]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'upstream' into for-next
authorJiri Kosina <jkosina@suse.cz>
Mon, 11 Jul 2011 12:37:32 +0000 (14:37 +0200)
committerJiri Kosina <jkosina@suse.cz>
Mon, 11 Jul 2011 12:37:32 +0000 (14:37 +0200)
3525 files changed:
.gitignore
.mailmap
CREDITS
Documentation/00-INDEX
Documentation/ABI/removed/o2cb [moved from Documentation/ABI/obsolete/o2cb with 65% similarity]
Documentation/ABI/testing/sysfs-block
Documentation/ABI/testing/sysfs-class-backlight-driver-adp8870 [new file with mode: 0644]
Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus
Documentation/ABI/testing/sysfs-driver-hid-wiimote [new file with mode: 0644]
Documentation/ABI/testing/sysfs-kernel-mm-cleancache [new file with mode: 0644]
Documentation/ABI/testing/sysfs-ptp [new file with mode: 0644]
Documentation/DocBook/Makefile
Documentation/DocBook/dvb/dvbproperty.xml
Documentation/DocBook/media-entities.tmpl
Documentation/DocBook/mtdnand.tmpl
Documentation/DocBook/v4l/media-controller.xml
Documentation/DocBook/v4l/pixfmt.xml
Documentation/DocBook/v4l/subdev-formats.xml
Documentation/IRQ-affinity.txt
Documentation/RCU/trace.txt
Documentation/accounting/cgroupstats.txt
Documentation/accounting/getdelays.c
Documentation/acpi/method-customizing.txt
Documentation/arm/Booting
Documentation/arm/Samsung/Overview.txt
Documentation/atomic_ops.txt
Documentation/blockdev/cciss.txt
Documentation/cachetlb.txt
Documentation/cgroups/blkio-controller.txt
Documentation/cgroups/cgroups.txt
Documentation/cgroups/cpuacct.txt
Documentation/cgroups/cpusets.txt
Documentation/cgroups/devices.txt
Documentation/cgroups/freezer-subsystem.txt
Documentation/cgroups/memory.txt
Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
Documentation/devicetree/booting-without-of.txt
Documentation/dmaengine.txt
Documentation/feature-removal-schedule.txt
Documentation/filesystems/9p.txt
Documentation/filesystems/Locking
Documentation/filesystems/configfs/configfs_example_explicit.c
Documentation/filesystems/configfs/configfs_example_macros.c
Documentation/filesystems/ext4.txt
Documentation/filesystems/nfs/idmapper.txt
Documentation/filesystems/ocfs2.txt
Documentation/filesystems/proc.txt
Documentation/filesystems/ubifs.txt
Documentation/filesystems/vfs.txt
Documentation/filesystems/xfs.txt
Documentation/hwmon/emc6w201 [new file with mode: 0644]
Documentation/hwmon/f71882fg
Documentation/hwmon/fam15h_power [new file with mode: 0644]
Documentation/hwmon/k10temp
Documentation/hwmon/max6650
Documentation/i2c/busses/i2c-i801
Documentation/i2c/writing-clients
Documentation/input/elantech.txt
Documentation/input/rotary-encoder.txt
Documentation/ioctl/ioctl-number.txt
Documentation/kbuild/kbuild.txt
Documentation/kbuild/kconfig-language.txt
Documentation/kbuild/kconfig.txt
Documentation/kbuild/makefiles.txt
Documentation/kernel-parameters.txt
Documentation/kmemleak.txt
Documentation/laptops/acer-wmi.txt [deleted file]
Documentation/lockstat.txt
Documentation/md.txt
Documentation/mmc/00-INDEX
Documentation/mmc/mmc-dev-attrs.txt
Documentation/mmc/mmc-dev-parts.txt [new file with mode: 0644]
Documentation/networking/bonding.txt
Documentation/networking/dns_resolver.txt
Documentation/power/devices.txt
Documentation/power/regulator/machine.txt
Documentation/power/runtime_pm.txt
Documentation/printk-formats.txt
Documentation/ptp/ptp.txt [new file with mode: 0644]
Documentation/ptp/testptp.c [new file with mode: 0644]
Documentation/ptp/testptp.mk [new file with mode: 0644]
Documentation/scheduler/sched-design-CFS.txt
Documentation/scheduler/sched-rt-group.txt
Documentation/scsi/ChangeLog.megaraid_sas
Documentation/security/00-INDEX [new file with mode: 0644]
Documentation/security/SELinux.txt [moved from Documentation/SELinux.txt with 100% similarity]
Documentation/security/Smack.txt [moved from Documentation/Smack.txt with 100% similarity]
Documentation/security/apparmor.txt [moved from Documentation/apparmor.txt with 100% similarity]
Documentation/security/credentials.txt [moved from Documentation/credentials.txt with 99% similarity]
Documentation/security/keys-request-key.txt [moved from Documentation/keys-request-key.txt with 98% similarity]
Documentation/security/keys-trusted-encrypted.txt [moved from Documentation/keys-trusted-encrypted.txt with 100% similarity]
Documentation/security/keys.txt [moved from Documentation/keys.txt with 99% similarity]
Documentation/security/tomoyo.txt [moved from Documentation/tomoyo.txt with 100% similarity]
Documentation/sysctl/kernel.txt
Documentation/virtual/lguest/Makefile
Documentation/virtual/lguest/lguest.c
Documentation/virtual/uml/UserModeLinux-HOWTO.txt
Documentation/vm/cleancache.txt [new file with mode: 0644]
Documentation/vm/hwpoison.txt
Documentation/vm/locking
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/Kconfig
arch/alpha/include/asm/gpio.h [new file with mode: 0644]
arch/alpha/include/asm/smp.h
arch/alpha/include/asm/unistd.h
arch/alpha/kernel/osf_sys.c
arch/alpha/kernel/process.c
arch/alpha/kernel/setup.c
arch/alpha/kernel/smp.c
arch/alpha/kernel/sys_dp264.c
arch/alpha/kernel/sys_titan.c
arch/alpha/kernel/systbls.S
arch/alpha/kernel/vmlinux.lds.S
arch/alpha/mm/init.c
arch/alpha/mm/numa.c
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/Makefile
arch/arm/boot/compressed/head.S
arch/arm/common/Kconfig
arch/arm/configs/at572d940hfek_defconfig [deleted file]
arch/arm/configs/at91sam9261_defconfig [moved from arch/arm/configs/at91sam9261ek_defconfig with 53% similarity]
arch/arm/configs/at91sam9263_defconfig [moved from arch/arm/configs/at91sam9263ek_defconfig with 57% similarity]
arch/arm/configs/davinci_all_defconfig
arch/arm/configs/exynos4_defconfig
arch/arm/configs/neocore926_defconfig [deleted file]
arch/arm/configs/netx_defconfig
arch/arm/configs/omap2plus_defconfig
arch/arm/configs/s5p6442_defconfig [deleted file]
arch/arm/configs/usb-a9263_defconfig [deleted file]
arch/arm/configs/viper_defconfig
arch/arm/configs/xcep_defconfig
arch/arm/configs/zeus_defconfig
arch/arm/include/asm/assembler.h
arch/arm/include/asm/bitops.h
arch/arm/include/asm/entry-macro-multi.S
arch/arm/include/asm/fiq.h
arch/arm/include/asm/mach/arch.h
arch/arm/include/asm/page.h
arch/arm/include/asm/prom.h [new file with mode: 0644]
arch/arm/include/asm/setup.h
arch/arm/include/asm/smp.h
arch/arm/include/asm/tlb.h
arch/arm/include/asm/unistd.h
arch/arm/kernel/Makefile
arch/arm/kernel/calls.S
arch/arm/kernel/devtree.c [new file with mode: 0644]
arch/arm/kernel/entry-armv.S
arch/arm/kernel/entry-common.S
arch/arm/kernel/fiq.c
arch/arm/kernel/fiqasm.S [new file with mode: 0644]
arch/arm/kernel/head-common.S
arch/arm/kernel/head.S
arch/arm/kernel/module.c
arch/arm/kernel/setup.c
arch/arm/kernel/smp.c
arch/arm/kernel/traps.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/lib/lib1funcs.S
arch/arm/mach-at91/Kconfig
arch/arm/mach-at91/Makefile
arch/arm/mach-at91/at572d940hf.c [deleted file]
arch/arm/mach-at91/at572d940hf_devices.c [deleted file]
arch/arm/mach-at91/at91cap9.c
arch/arm/mach-at91/at91cap9_devices.c
arch/arm/mach-at91/at91rm9200.c
arch/arm/mach-at91/at91rm9200_devices.c
arch/arm/mach-at91/at91sam9260.c
arch/arm/mach-at91/at91sam9260_devices.c
arch/arm/mach-at91/at91sam9261.c
arch/arm/mach-at91/at91sam9261_devices.c
arch/arm/mach-at91/at91sam9263.c
arch/arm/mach-at91/at91sam9263_devices.c
arch/arm/mach-at91/at91sam9g45.c
arch/arm/mach-at91/at91sam9g45_devices.c
arch/arm/mach-at91/at91sam9rl.c
arch/arm/mach-at91/at91sam9rl_devices.c
arch/arm/mach-at91/at91x40.c
arch/arm/mach-at91/board-1arm.c
arch/arm/mach-at91/board-afeb-9260v1.c
arch/arm/mach-at91/board-at572d940hf_ek.c [deleted file]
arch/arm/mach-at91/board-cam60.c
arch/arm/mach-at91/board-cap9adk.c
arch/arm/mach-at91/board-carmeva.c
arch/arm/mach-at91/board-cpu9krea.c
arch/arm/mach-at91/board-cpuat91.c
arch/arm/mach-at91/board-csb337.c
arch/arm/mach-at91/board-csb637.c
arch/arm/mach-at91/board-eb01.c
arch/arm/mach-at91/board-eb9200.c
arch/arm/mach-at91/board-ecbat91.c
arch/arm/mach-at91/board-eco920.c
arch/arm/mach-at91/board-flexibity.c
arch/arm/mach-at91/board-foxg20.c
arch/arm/mach-at91/board-gsia18s.c
arch/arm/mach-at91/board-kafa.c
arch/arm/mach-at91/board-kb9202.c
arch/arm/mach-at91/board-neocore926.c
arch/arm/mach-at91/board-pcontrol-g20.c
arch/arm/mach-at91/board-picotux200.c
arch/arm/mach-at91/board-qil-a9260.c
arch/arm/mach-at91/board-rm9200dk.c
arch/arm/mach-at91/board-rm9200ek.c
arch/arm/mach-at91/board-sam9-l9260.c
arch/arm/mach-at91/board-sam9260ek.c
arch/arm/mach-at91/board-sam9261ek.c
arch/arm/mach-at91/board-sam9263ek.c
arch/arm/mach-at91/board-sam9g20ek.c
arch/arm/mach-at91/board-sam9m10g45ek.c
arch/arm/mach-at91/board-sam9rlek.c
arch/arm/mach-at91/board-snapper9260.c
arch/arm/mach-at91/board-stamp9g20.c
arch/arm/mach-at91/board-usb-a9260.c
arch/arm/mach-at91/board-usb-a9263.c
arch/arm/mach-at91/board-yl-9200.c
arch/arm/mach-at91/clock.c
arch/arm/mach-at91/clock.h
arch/arm/mach-at91/generic.h
arch/arm/mach-at91/include/mach/at572d940hf.h [deleted file]
arch/arm/mach-at91/include/mach/at572d940hf_matrix.h [deleted file]
arch/arm/mach-at91/include/mach/at91cap9.h
arch/arm/mach-at91/include/mach/at91rm9200.h
arch/arm/mach-at91/include/mach/at91sam9260.h
arch/arm/mach-at91/include/mach/at91sam9261.h
arch/arm/mach-at91/include/mach/at91sam9263.h
arch/arm/mach-at91/include/mach/at91sam9g45.h
arch/arm/mach-at91/include/mach/at91sam9rl.h
arch/arm/mach-at91/include/mach/at91x40.h
arch/arm/mach-at91/include/mach/board.h
arch/arm/mach-at91/include/mach/clkdev.h [new file with mode: 0644]
arch/arm/mach-at91/include/mach/cpu.h
arch/arm/mach-at91/include/mach/hardware.h
arch/arm/mach-at91/include/mach/memory.h
arch/arm/mach-at91/include/mach/stamp9g20.h
arch/arm/mach-at91/include/mach/system_rev.h [new file with mode: 0644]
arch/arm/mach-at91/include/mach/timex.h
arch/arm/mach-davinci/da850.c
arch/arm/mach-davinci/devices-da8xx.c
arch/arm/mach-davinci/devices.c
arch/arm/mach-davinci/gpio.c
arch/arm/mach-davinci/include/mach/da8xx.h
arch/arm/mach-davinci/include/mach/hardware.h
arch/arm/mach-ep93xx/core.c
arch/arm/mach-exynos4/Kconfig
arch/arm/mach-exynos4/Makefile
arch/arm/mach-exynos4/cpu.c
arch/arm/mach-exynos4/cpuidle.c [new file with mode: 0644]
arch/arm/mach-exynos4/include/mach/regs-usb-phy.h
arch/arm/mach-exynos4/mach-nuri.c
arch/arm/mach-exynos4/setup-usb-phy.c [moved from arch/arm/mach-exynos4/usb-phy.c with 100% similarity]
arch/arm/mach-exynos4/time.c
arch/arm/mach-footbridge/dc21285-timer.c
arch/arm/mach-footbridge/include/mach/debug-macro.S
arch/arm/mach-gemini/board-wbd111.c
arch/arm/mach-gemini/board-wbd222.c
arch/arm/mach-h720x/Kconfig
arch/arm/mach-ixp4xx/include/mach/ixp46x_ts.h [new file with mode: 0644]
arch/arm/mach-ixp4xx/ixdp425-setup.c
arch/arm/mach-msm/timer.c
arch/arm/mach-mxs/ocotp.c
arch/arm/mach-netx/fb.c
arch/arm/mach-nomadik/Kconfig
arch/arm/mach-omap1/Makefile
arch/arm/mach-omap1/dma.c
arch/arm/mach-omap1/pm_bus.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-2430sdp.c
arch/arm/mach-omap2/board-3430sdp.c
arch/arm/mach-omap2/board-4430sdp.c
arch/arm/mach-omap2/board-am3517crane.c
arch/arm/mach-omap2/board-am3517evm.c
arch/arm/mach-omap2/board-apollon.c
arch/arm/mach-omap2/board-cm-t35.c
arch/arm/mach-omap2/board-cm-t3517.c
arch/arm/mach-omap2/board-devkit8000.c
arch/arm/mach-omap2/board-igep0020.c
arch/arm/mach-omap2/board-igep0030.c [deleted file]
arch/arm/mach-omap2/board-ldp.c
arch/arm/mach-omap2/board-n8x0.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/board-omap3logic.c
arch/arm/mach-omap2/board-omap3pandora.c
arch/arm/mach-omap2/board-omap3stalker.c
arch/arm/mach-omap2/board-omap3touchbook.c
arch/arm/mach-omap2/board-omap4panda.c
arch/arm/mach-omap2/board-overo.c
arch/arm/mach-omap2/board-rm680.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/board-rx51-video.c
arch/arm/mach-omap2/board-rx51.c
arch/arm/mach-omap2/board-zoom-debugboard.c
arch/arm/mach-omap2/board-zoom-display.c
arch/arm/mach-omap2/board-zoom-peripherals.c
arch/arm/mach-omap2/common-board-devices.c [new file with mode: 0644]
arch/arm/mach-omap2/common-board-devices.h [new file with mode: 0644]
arch/arm/mach-omap2/cpuidle34xx.c
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/display.c
arch/arm/mach-omap2/gpmc-smc91x.c
arch/arm/mach-omap2/gpmc-smsc911x.c
arch/arm/mach-omap2/hsmmc.c
arch/arm/mach-omap2/hsmmc.h
arch/arm/mach-omap2/include/mach/board-zoom.h
arch/arm/mach-omap2/mux.c
arch/arm/mach-omap2/mux.h
arch/arm/mach-omap2/mux44xx.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod_44xx_data.c
arch/arm/mach-omap2/omap_l3_noc.c
arch/arm/mach-omap2/omap_l3_smx.c
arch/arm/mach-omap2/omap_phy_internal.c
arch/arm/mach-omap2/pm-debug.c
arch/arm/mach-omap2/pm.h
arch/arm/mach-omap2/pm34xx.c
arch/arm/mach-omap2/pm44xx.c
arch/arm/mach-omap2/smartreflex.c
arch/arm/mach-omap2/usb-musb.c
arch/arm/mach-omap2/usb-tusb6010.c
arch/arm/mach-omap2/voltage.c
arch/arm/mach-pxa/Kconfig
arch/arm/mach-pxa/spitz_pm.c
arch/arm/mach-s3c2410/Makefile
arch/arm/mach-s3c2410/irq.c [deleted file]
arch/arm/mach-s3c2410/mach-amlm5900.c
arch/arm/mach-s3c2410/mach-tct_hammer.c
arch/arm/mach-s3c64xx/dev-spi.c
arch/arm/mach-s3c64xx/include/mach/gpio-bank-a.h [deleted file]
arch/arm/mach-s3c64xx/include/mach/gpio-bank-b.h [deleted file]
arch/arm/mach-s3c64xx/include/mach/gpio-bank-c.h [deleted file]
arch/arm/mach-s3c64xx/include/mach/gpio-bank-d.h [deleted file]
arch/arm/mach-s3c64xx/include/mach/gpio-bank-e.h [deleted file]
arch/arm/mach-s3c64xx/include/mach/gpio-bank-f.h [deleted file]
arch/arm/mach-s3c64xx/include/mach/gpio-bank-g.h [deleted file]
arch/arm/mach-s3c64xx/include/mach/gpio-bank-h.h [deleted file]
arch/arm/mach-s3c64xx/include/mach/gpio-bank-i.h [deleted file]
arch/arm/mach-s3c64xx/include/mach/gpio-bank-j.h [deleted file]
arch/arm/mach-s3c64xx/include/mach/gpio-bank-n.h [deleted file]
arch/arm/mach-s3c64xx/include/mach/gpio-bank-o.h [deleted file]
arch/arm/mach-s3c64xx/include/mach/gpio-bank-p.h [deleted file]
arch/arm/mach-s3c64xx/include/mach/gpio-bank-q.h [deleted file]
arch/arm/mach-s3c64xx/mach-smdk6410.c
arch/arm/mach-s3c64xx/pm.c
arch/arm/mach-s3c64xx/setup-i2c0.c
arch/arm/mach-s3c64xx/setup-i2c1.c
arch/arm/mach-s3c64xx/sleep.S
arch/arm/mach-s5p6442/Kconfig [deleted file]
arch/arm/mach-s5p6442/Makefile [deleted file]
arch/arm/mach-s5p6442/Makefile.boot [deleted file]
arch/arm/mach-s5p6442/clock.c [deleted file]
arch/arm/mach-s5p6442/cpu.c [deleted file]
arch/arm/mach-s5p6442/dev-audio.c [deleted file]
arch/arm/mach-s5p6442/dev-spi.c [deleted file]
arch/arm/mach-s5p6442/dma.c [deleted file]
arch/arm/mach-s5p6442/include/mach/debug-macro.S [deleted file]
arch/arm/mach-s5p6442/include/mach/entry-macro.S [deleted file]
arch/arm/mach-s5p6442/include/mach/gpio.h [deleted file]
arch/arm/mach-s5p6442/include/mach/hardware.h [deleted file]
arch/arm/mach-s5p6442/include/mach/io.h [deleted file]
arch/arm/mach-s5p6442/include/mach/irqs.h [deleted file]
arch/arm/mach-s5p6442/include/mach/map.h [deleted file]
arch/arm/mach-s5p6442/include/mach/memory.h [deleted file]
arch/arm/mach-s5p6442/include/mach/pwm-clock.h [deleted file]
arch/arm/mach-s5p6442/include/mach/regs-clock.h [deleted file]
arch/arm/mach-s5p6442/include/mach/regs-irq.h [deleted file]
arch/arm/mach-s5p6442/include/mach/spi-clocks.h [deleted file]
arch/arm/mach-s5p6442/include/mach/system.h [deleted file]
arch/arm/mach-s5p6442/include/mach/tick.h [deleted file]
arch/arm/mach-s5p6442/include/mach/timex.h [deleted file]
arch/arm/mach-s5p6442/include/mach/uncompress.h [deleted file]
arch/arm/mach-s5p6442/include/mach/vmalloc.h [deleted file]
arch/arm/mach-s5p6442/init.c [deleted file]
arch/arm/mach-s5p6442/mach-smdk6442.c [deleted file]
arch/arm/mach-s5p6442/setup-i2c0.c [deleted file]
arch/arm/mach-s5pc100/Makefile
arch/arm/mach-s5pv210/Makefile
arch/arm/mach-s5pv210/cpufreq.c
arch/arm/mach-shmobile/Makefile
arch/arm/mach-shmobile/board-ag5evm.c
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-g4evm.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-shmobile/clock-sh7372.c
arch/arm/mach-shmobile/clock-sh73a0.c
arch/arm/mach-shmobile/cpuidle.c [new file with mode: 0644]
arch/arm/mach-shmobile/headsmp.S
arch/arm/mach-shmobile/include/mach/common.h
arch/arm/mach-shmobile/include/mach/head-ap4evb.txt
arch/arm/mach-shmobile/include/mach/head-mackerel.txt
arch/arm/mach-shmobile/include/mach/sh7372.h
arch/arm/mach-shmobile/include/mach/sh73a0.h
arch/arm/mach-shmobile/intc-sh7372.c
arch/arm/mach-shmobile/intc-sh73a0.c
arch/arm/mach-shmobile/pm-sh7372.c [new file with mode: 0644]
arch/arm/mach-shmobile/setup-sh7367.c
arch/arm/mach-shmobile/setup-sh7372.c
arch/arm/mach-shmobile/setup-sh7377.c
arch/arm/mach-shmobile/setup-sh73a0.c
arch/arm/mach-shmobile/sleep-sh7372.S [new file with mode: 0644]
arch/arm/mach-shmobile/smp-sh73a0.c
arch/arm/mach-shmobile/suspend.c [new file with mode: 0644]
arch/arm/mach-tegra/board-harmony-power.c
arch/arm/mach-tegra/board-harmony.h
arch/arm/mach-tegra/include/mach/kbc.h
arch/arm/mach-tegra/include/mach/sdhci.h
arch/arm/mach-u300/Makefile
arch/arm/mach-u300/clock.h
arch/arm/mach-u300/include/mach/u300-regs.h
arch/arm/mach-u300/timer.c
arch/arm/mach-ux500/Kconfig
arch/arm/mach-ux500/Makefile
arch/arm/mach-ux500/board-mop500-sdi.c
arch/arm/mach-ux500/board-mop500.c
arch/arm/mach-ux500/cpu-db5500.c
arch/arm/mach-ux500/cpu-db8500.c
arch/arm/mach-ux500/cpu.c
arch/arm/mach-ux500/cpufreq.c [deleted file]
arch/arm/mach-ux500/devices-common.h
arch/arm/mach-ux500/devices-db5500.h
arch/arm/mach-ux500/devices-db8500.h
arch/arm/mach-ux500/include/mach/db5500-regs.h
arch/arm/mach-ux500/include/mach/db8500-regs.h
arch/arm/mach-ux500/include/mach/hardware.h
arch/arm/mach-ux500/include/mach/id.h
arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
arch/arm/mach-ux500/include/mach/irqs-board-u5500.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/irqs-db5500.h
arch/arm/mach-ux500/include/mach/irqs-db8500.h
arch/arm/mach-ux500/include/mach/irqs.h
arch/arm/mach-ux500/include/mach/prcmu-defs.h [deleted file]
arch/arm/mach-ux500/include/mach/prcmu.h [deleted file]
arch/arm/mach-ux500/prcmu.c [deleted file]
arch/arm/mach-vexpress/v2m.c
arch/arm/mm/cache-v6.S
arch/arm/mm/cache-v7.S
arch/arm/mm/init.c
arch/arm/mm/mm.h
arch/arm/mm/mmu.c
arch/arm/mm/proc-arm7tdmi.S
arch/arm/mm/proc-arm9tdmi.S
arch/arm/mm/proc-v6.S
arch/arm/mm/proc-v7.S
arch/arm/plat-iop/cp6.c
arch/arm/plat-mxc/devices/platform-imx-dma.c
arch/arm/plat-nomadik/Kconfig
arch/arm/plat-nomadik/Makefile
arch/arm/plat-nomadik/include/plat/gpio.h
arch/arm/plat-nomadik/include/plat/i2c.h
arch/arm/plat-omap/Makefile
arch/arm/plat-omap/include/plat/flash.h
arch/arm/plat-omap/include/plat/gpio.h
arch/arm/plat-omap/include/plat/gpmc-smsc911x.h
arch/arm/plat-omap/include/plat/iovmm.h
arch/arm/plat-omap/include/plat/mmc.h
arch/arm/plat-omap/include/plat/uncompress.h
arch/arm/plat-omap/include/plat/usb.h
arch/arm/plat-omap/iovmm.c
arch/arm/plat-omap/omap_device.c
arch/arm/plat-omap/sram.c
arch/arm/plat-s3c24xx/dma.c
arch/arm/plat-s3c24xx/irq.c
arch/arm/plat-s5p/Kconfig
arch/arm/plat-s5p/cpu.c
arch/arm/plat-s5p/dev-onenand.c
arch/arm/plat-s5p/include/plat/map-s5p.h
arch/arm/plat-s5p/include/plat/s5p6442.h [deleted file]
arch/arm/plat-samsung/Makefile
arch/arm/plat-samsung/dev-onenand.c
arch/arm/plat-samsung/include/plat/cpu.h
arch/arm/plat-samsung/include/plat/debug-macro.S
arch/arm/plat-samsung/include/plat/devs.h
arch/arm/plat-samsung/include/plat/regs-serial.h
arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
arch/avr32/configs/atngw100_defconfig
arch/avr32/configs/atngw100_evklcd100_defconfig
arch/avr32/configs/atngw100_evklcd101_defconfig
arch/avr32/configs/atngw100_mrmt_defconfig
arch/avr32/configs/atngw100mkii_defconfig
arch/avr32/configs/atngw100mkii_evklcd100_defconfig
arch/avr32/configs/atngw100mkii_evklcd101_defconfig
arch/avr32/configs/atstk1002_defconfig
arch/avr32/configs/atstk1003_defconfig
arch/avr32/configs/atstk1004_defconfig
arch/avr32/configs/atstk1006_defconfig
arch/avr32/configs/favr-32_defconfig
arch/avr32/configs/hammerhead_defconfig
arch/avr32/configs/merisc_defconfig
arch/avr32/configs/mimc200_defconfig
arch/avr32/include/asm/bitops.h
arch/avr32/include/asm/processor.h
arch/avr32/include/asm/unistd.h
arch/avr32/kernel/syscall_table.S
arch/avr32/mach-at32ap/at32ap700x.c
arch/avr32/mach-at32ap/include/mach/board.h
arch/avr32/mach-at32ap/include/mach/cpu.h
arch/avr32/mach-at32ap/intc.c
arch/avr32/mm/init.c
arch/blackfin/Kconfig
arch/blackfin/Kconfig.debug
arch/blackfin/configs/BF527-EZKIT-V2_defconfig
arch/blackfin/configs/BF527-EZKIT_defconfig
arch/blackfin/configs/BF533-STAMP_defconfig
arch/blackfin/configs/BF537-STAMP_defconfig
arch/blackfin/configs/CM-BF548_defconfig
arch/blackfin/include/asm/bfin-global.h
arch/blackfin/include/asm/bfin_pfmon.h [new file with mode: 0644]
arch/blackfin/include/asm/bfin_serial.h
arch/blackfin/include/asm/bfin_sport.h
arch/blackfin/include/asm/cacheflush.h
arch/blackfin/include/asm/cpu.h
arch/blackfin/include/asm/def_LPBlackfin.h
arch/blackfin/include/asm/gptimers.h
arch/blackfin/include/asm/irq_handler.h
arch/blackfin/include/asm/kgdb.h
arch/blackfin/include/asm/perf_event.h [new file with mode: 0644]
arch/blackfin/include/asm/ptrace.h
arch/blackfin/include/asm/unistd.h
arch/blackfin/include/mach-common/irq.h [new file with mode: 0644]
arch/blackfin/kernel/Makefile
arch/blackfin/kernel/bfin_dma_5xx.c
arch/blackfin/kernel/bfin_gpio.c
arch/blackfin/kernel/bfin_ksyms.c
arch/blackfin/kernel/debug-mmrs.c [new file with mode: 0644]
arch/blackfin/kernel/ipipe.c
arch/blackfin/kernel/irqchip.c
arch/blackfin/kernel/nmi.c
arch/blackfin/kernel/perf_event.c [new file with mode: 0644]
arch/blackfin/kernel/process.c
arch/blackfin/kernel/reboot.c
arch/blackfin/kernel/setup.c
arch/blackfin/kernel/vmlinux.lds.S
arch/blackfin/lib/strncpy.S
arch/blackfin/mach-bf518/include/mach/anomaly.h
arch/blackfin/mach-bf518/include/mach/bfin_serial_5xx.h [deleted file]
arch/blackfin/mach-bf518/include/mach/cdefBF512.h
arch/blackfin/mach-bf518/include/mach/defBF512.h
arch/blackfin/mach-bf518/include/mach/defBF514.h
arch/blackfin/mach-bf518/include/mach/irq.h
arch/blackfin/mach-bf527/boards/ezkit.c
arch/blackfin/mach-bf527/include/mach/anomaly.h
arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h [deleted file]
arch/blackfin/mach-bf527/include/mach/cdefBF522.h
arch/blackfin/mach-bf527/include/mach/defBF522.h
arch/blackfin/mach-bf527/include/mach/defBF525.h
arch/blackfin/mach-bf527/include/mach/irq.h
arch/blackfin/mach-bf533/include/mach/anomaly.h
arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h [deleted file]
arch/blackfin/mach-bf533/include/mach/irq.h
arch/blackfin/mach-bf537/boards/stamp.c
arch/blackfin/mach-bf537/include/mach/anomaly.h
arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h [deleted file]
arch/blackfin/mach-bf537/include/mach/irq.h
arch/blackfin/mach-bf537/ints-priority.c
arch/blackfin/mach-bf538/include/mach/anomaly.h
arch/blackfin/mach-bf538/include/mach/bfin_serial_5xx.h [deleted file]
arch/blackfin/mach-bf538/include/mach/irq.h
arch/blackfin/mach-bf548/boards/ezkit.c
arch/blackfin/mach-bf548/include/mach/anomaly.h
arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h [deleted file]
arch/blackfin/mach-bf548/include/mach/defBF547.h
arch/blackfin/mach-bf548/include/mach/irq.h
arch/blackfin/mach-bf561/boards/acvilon.c
arch/blackfin/mach-bf561/boards/ezkit.c
arch/blackfin/mach-bf561/include/mach/anomaly.h
arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h [deleted file]
arch/blackfin/mach-bf561/include/mach/irq.h
arch/blackfin/mach-bf561/smp.c
arch/blackfin/mach-common/dpmc.c
arch/blackfin/mach-common/entry.S
arch/blackfin/mach-common/ints-priority.c
arch/blackfin/mach-common/smp.c
arch/blackfin/mm/maccess.c
arch/blackfin/mm/sram-alloc.c
arch/cris/Kconfig
arch/cris/arch-v10/drivers/axisflashmap.c
arch/cris/arch-v10/kernel/entry.S
arch/cris/arch-v32/drivers/Kconfig
arch/cris/arch-v32/drivers/axisflashmap.c
arch/cris/arch-v32/kernel/entry.S
arch/cris/arch-v32/kernel/irq.c
arch/cris/arch-v32/kernel/smp.c
arch/cris/include/asm/unistd.h
arch/cris/kernel/vmlinux.lds.S
arch/cris/mm/init.c
arch/frv/Kconfig
arch/frv/include/asm/suspend.h [deleted file]
arch/frv/include/asm/unistd.h
arch/frv/kernel/entry.S
arch/frv/kernel/vmlinux.lds.S
arch/frv/mm/init.c
arch/h8300/Kconfig
arch/h8300/include/asm/unistd.h
arch/h8300/kernel/syscalls.S
arch/ia64/Kconfig
arch/ia64/include/asm/tlb.h
arch/ia64/include/asm/unistd.h
arch/ia64/kernel/entry.S
arch/ia64/kernel/time.c
arch/ia64/mm/contig.c
arch/ia64/mm/discontig.c
arch/ia64/mm/init.c
arch/m32r/Kconfig
arch/m32r/Kconfig.debug
arch/m32r/include/asm/smp.h
arch/m32r/include/asm/unistd.h
arch/m32r/kernel/smp.c
arch/m32r/kernel/smpboot.c
arch/m32r/kernel/syscall_table.S
arch/m32r/kernel/vmlinux.lds.S
arch/m32r/mm/discontig.c
arch/m32r/mm/init.c
arch/m68k/Kconfig
arch/m68k/Kconfig.nommu
arch/m68k/include/asm/bitops_mm.h
arch/m68k/include/asm/bitops_no.h
arch/m68k/include/asm/io_no.h
arch/m68k/include/asm/unistd.h
arch/m68k/kernel/asm-offsets.c
arch/m68k/kernel/asm-offsets_mm.c [deleted file]
arch/m68k/kernel/asm-offsets_no.c [deleted file]
arch/m68k/kernel/entry_no.S
arch/m68k/kernel/irq.c
arch/m68k/kernel/m68k_ksyms.c
arch/m68k/kernel/m68k_ksyms_mm.c [deleted file]
arch/m68k/kernel/m68k_ksyms_no.c [deleted file]
arch/m68k/kernel/process_no.c
arch/m68k/kernel/sys_m68k.c
arch/m68k/kernel/sys_m68k_mm.c [deleted file]
arch/m68k/kernel/sys_m68k_no.c [deleted file]
arch/m68k/kernel/syscalltable.S
arch/m68k/kernel/vmlinux.lds_no.S
arch/m68k/lib/Makefile
arch/m68k/lib/Makefile_mm [deleted file]
arch/m68k/lib/Makefile_no [deleted file]
arch/m68k/lib/checksum.c [deleted file]
arch/m68k/lib/checksum_no.c
arch/m68k/lib/memcpy.c
arch/m68k/lib/memmove.c
arch/m68k/lib/memset.c
arch/m68k/lib/muldi3.c
arch/m68k/lib/muldi3_mm.c [deleted file]
arch/m68k/lib/muldi3_no.c [deleted file]
arch/m68k/lib/string.c
arch/m68k/mm/Makefile
arch/m68k/mm/Makefile_mm [deleted file]
arch/m68k/mm/Makefile_no [deleted file]
arch/m68k/mm/init_mm.c
arch/m68k/mm/init_no.c
arch/m68k/mm/kmap.c
arch/m68k/mm/kmap_mm.c [deleted file]
arch/m68k/mm/kmap_no.c [deleted file]
arch/m68k/platform/68328/entry.S
arch/m68k/platform/68360/entry.S
arch/m68k/platform/coldfire/dma.c
arch/m68k/platform/coldfire/entry.S
arch/m68k/platform/coldfire/head.S
arch/microblaze/Kconfig
arch/microblaze/include/asm/unistd.h
arch/microblaze/kernel/prom.c
arch/microblaze/kernel/syscall_table.S
arch/microblaze/mm/init.c
arch/mips/Kconfig
arch/mips/Kconfig.debug
arch/mips/cavium-octeon/flash_setup.c
arch/mips/configs/bcm47xx_defconfig
arch/mips/configs/mtx1_defconfig
arch/mips/include/asm/prom.h
arch/mips/include/asm/suspend.h
arch/mips/include/asm/unistd.h
arch/mips/kernel/prom.c
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/vmlinux.lds.S
arch/mips/mm/init.c
arch/mips/txx9/generic/setup.c
arch/mn10300/Kconfig
arch/mn10300/configs/asb2364_defconfig
arch/mn10300/include/asm/uaccess.h
arch/mn10300/include/asm/unistd.h
arch/mn10300/kernel/entry.S
arch/mn10300/kernel/irq.c
arch/mn10300/kernel/smp.c
arch/mn10300/kernel/traps.c
arch/mn10300/kernel/vmlinux.lds.S
arch/mn10300/mm/cache-dbg-flush-by-reg.S
arch/mn10300/mm/cache-smp.c
arch/mn10300/mm/init.c
arch/mn10300/mm/tlb-smp.c
arch/parisc/Kconfig
arch/parisc/include/asm/smp.h
arch/parisc/include/asm/unistd.h
arch/parisc/kernel/syscall_table.S
arch/parisc/kernel/vmlinux.lds.S
arch/parisc/mm/init.c
arch/powerpc/Kconfig
arch/powerpc/Kconfig.debug
arch/powerpc/boot/.gitignore
arch/powerpc/boot/dtc-src/.gitignore [deleted file]
arch/powerpc/boot/dts/canyonlands.dts
arch/powerpc/boot/dts/katmai.dts
arch/powerpc/boot/dts/kilauea.dts
arch/powerpc/boot/dts/mpc8313erdb.dts
arch/powerpc/boot/dts/mpc8572ds.dts
arch/powerpc/boot/dts/p2020ds.dts
arch/powerpc/boot/dts/p2020rdb.dts
arch/powerpc/boot/dts/redwood.dts
arch/powerpc/configs/52xx/pcm030_defconfig
arch/powerpc/configs/ppc6xx_defconfig
arch/powerpc/configs/ps3_defconfig
arch/powerpc/configs/pseries_defconfig
arch/powerpc/include/asm/fsl_lbc.h
arch/powerpc/include/asm/ftrace.h
arch/powerpc/include/asm/hvcall.h
arch/powerpc/include/asm/pgalloc.h
arch/powerpc/include/asm/rio.h
arch/powerpc/include/asm/smp.h
arch/powerpc/include/asm/suspend.h [deleted file]
arch/powerpc/include/asm/syscall.h
arch/powerpc/include/asm/systbl.h
arch/powerpc/include/asm/thread_info.h
arch/powerpc/include/asm/unistd.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/ftrace.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/ptrace.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/swsusp.c
arch/powerpc/kernel/traps.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/mm/init_32.c
arch/powerpc/mm/init_64.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/pgtable.c
arch/powerpc/mm/tlb_hash32.c
arch/powerpc/mm/tlb_hash64.c
arch/powerpc/mm/tlb_nohash.c
arch/powerpc/oprofile/op_model_power4.c
arch/powerpc/platforms/40x/Kconfig
arch/powerpc/platforms/44x/Kconfig
arch/powerpc/platforms/cell/interrupt.c
arch/powerpc/platforms/cell/interrupt.h
arch/powerpc/platforms/cell/smp.c
arch/powerpc/platforms/powermac/pic.c
arch/powerpc/sysdev/Kconfig
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/fsl_lbc.c
arch/powerpc/sysdev/fsl_rio.c
arch/powerpc/sysdev/ppc4xx_msi.c [new file with mode: 0644]
arch/s390/Kconfig
arch/s390/appldata/appldata_base.c
arch/s390/appldata/appldata_mem.c
arch/s390/include/asm/bitops.h
arch/s390/include/asm/cmpxchg.h
arch/s390/include/asm/delay.h
arch/s390/include/asm/elf.h
arch/s390/include/asm/hugetlb.h
arch/s390/include/asm/irq.h
arch/s390/include/asm/lowcore.h
arch/s390/include/asm/mmu.h
arch/s390/include/asm/mmu_context.h
arch/s390/include/asm/page.h
arch/s390/include/asm/percpu.h
arch/s390/include/asm/pgalloc.h
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/qdio.h
arch/s390/include/asm/s390_ext.h [deleted file]
arch/s390/include/asm/suspend.h [deleted file]
arch/s390/include/asm/tlb.h
arch/s390/include/asm/tlbflush.h
arch/s390/include/asm/topology.h
arch/s390/include/asm/uaccess.h
arch/s390/include/asm/unistd.h
arch/s390/kernel/Makefile
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/compat_wrapper.S
arch/s390/kernel/dis.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/irq.c
arch/s390/kernel/process.c
arch/s390/kernel/s390_ext.c [deleted file]
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kernel/syscalls.S
arch/s390/kernel/time.c
arch/s390/kernel/topology.c
arch/s390/kernel/traps.c
arch/s390/kernel/vdso32/Makefile
arch/s390/kernel/vdso64/Makefile
arch/s390/kernel/vmlinux.lds.S
arch/s390/kernel/vtime.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/sie64a.S
arch/s390/lib/delay.c
arch/s390/mm/extmem.c
arch/s390/mm/fault.c
arch/s390/mm/hugetlbpage.c
arch/s390/mm/init.c
arch/s390/mm/maccess.c
arch/s390/mm/pageattr.c
arch/s390/mm/pgtable.c
arch/s390/mm/vmem.c
arch/s390/oprofile/hwsampler.c
arch/s390/oprofile/init.c
arch/score/Kconfig
arch/score/Kconfig.debug
arch/score/mm/init.c
arch/sh/Kconfig
arch/sh/Kconfig.debug
arch/sh/boards/mach-ap325rxa/setup.c
arch/sh/boards/mach-ecovec24/setup.c
arch/sh/boot/compressed/Makefile
arch/sh/configs/apsh4ad0a_defconfig
arch/sh/configs/sdk7786_defconfig
arch/sh/configs/se7206_defconfig
arch/sh/configs/shx3_defconfig
arch/sh/configs/titan_defconfig
arch/sh/configs/urquell_defconfig
arch/sh/include/asm/cmpxchg-grb.h
arch/sh/include/asm/kgdb.h
arch/sh/include/asm/pgtable.h
arch/sh/include/asm/processor_64.h
arch/sh/include/asm/ptrace.h
arch/sh/include/asm/suspend.h
arch/sh/include/asm/tlb.h
arch/sh/include/asm/unistd_32.h
arch/sh/include/asm/unistd_64.h
arch/sh/include/cpu-sh4/cpu/sh7722.h
arch/sh/include/cpu-sh4/cpu/sh7724.h
arch/sh/include/cpu-sh4/cpu/sh7757.h
arch/sh/kernel/cpu/sh4a/setup-sh7724.c
arch/sh/kernel/process_32.c
arch/sh/kernel/syscalls_32.S
arch/sh/kernel/syscalls_64.S
arch/sh/kernel/vmlinux.lds.S
arch/sh/mm/cache-debugfs.c
arch/sh/mm/consistent.c
arch/sh/mm/init.c
arch/sparc/Kconfig
arch/sparc/Kconfig.debug
arch/sparc/include/asm/floppy_32.h
arch/sparc/include/asm/floppy_64.h
arch/sparc/include/asm/leon.h
arch/sparc/include/asm/leon_pci.h [new file with mode: 0644]
arch/sparc/include/asm/pci_32.h
arch/sparc/include/asm/pcic.h
arch/sparc/include/asm/pgalloc_64.h
arch/sparc/include/asm/pgtable_64.h
arch/sparc/include/asm/system_32.h
arch/sparc/include/asm/system_64.h
arch/sparc/include/asm/tlb_64.h
arch/sparc/include/asm/tlbflush_64.h
arch/sparc/include/asm/unistd.h
arch/sparc/kernel/Makefile
arch/sparc/kernel/apc.c
arch/sparc/kernel/auxio_32.c
arch/sparc/kernel/chmc.c
arch/sparc/kernel/entry.S
arch/sparc/kernel/leon_kernel.c
arch/sparc/kernel/leon_pci.c [new file with mode: 0644]
arch/sparc/kernel/leon_pci_grpci2.c [new file with mode: 0644]
arch/sparc/kernel/module.c
arch/sparc/kernel/pci_common.c
arch/sparc/kernel/pci_schizo.c
arch/sparc/kernel/prom_irqtrans.c
arch/sparc/kernel/psycho_common.c
arch/sparc/kernel/sbus.c
arch/sparc/kernel/setup_32.c
arch/sparc/kernel/setup_64.c
arch/sparc/kernel/smp_32.c
arch/sparc/kernel/sun4d_irq.c
arch/sparc/kernel/sys_sparc32.c
arch/sparc/kernel/sys_sparc_64.c
arch/sparc/kernel/systbls_32.S
arch/sparc/kernel/systbls_64.S
arch/sparc/kernel/time_64.c
arch/sparc/kernel/traps_64.c
arch/sparc/kernel/unaligned_64.c
arch/sparc/kernel/us2e_cpufreq.c
arch/sparc/kernel/us3_cpufreq.c
arch/sparc/kernel/viohs.c
arch/sparc/kernel/visemul.c
arch/sparc/kernel/vmlinux.lds.S
arch/sparc/mm/fault_32.c
arch/sparc/mm/init_32.c
arch/sparc/mm/init_64.c
arch/sparc/mm/srmmu.c
arch/sparc/mm/sun4c.c
arch/sparc/mm/tlb.c
arch/sparc/mm/tsb.c
arch/sparc/prom/console_32.c
arch/sparc/prom/init_32.c
arch/sparc/prom/mp.c
arch/tile/Kconfig
arch/tile/Kconfig.debug
arch/tile/configs/tile_defconfig [deleted file]
arch/tile/configs/tilegx_defconfig [new file with mode: 0644]
arch/tile/configs/tilepro_defconfig [new file with mode: 0644]
arch/tile/include/arch/chip_tilegx.h [new file with mode: 0644]
arch/tile/include/arch/icache.h
arch/tile/include/arch/interrupts_64.h [new file with mode: 0644]
arch/tile/include/arch/spr_def.h
arch/tile/include/arch/spr_def_64.h [new file with mode: 0644]
arch/tile/include/asm/atomic.h
arch/tile/include/asm/atomic_32.h
arch/tile/include/asm/atomic_64.h [new file with mode: 0644]
arch/tile/include/asm/backtrace.h
arch/tile/include/asm/bitops.h
arch/tile/include/asm/bitops_32.h
arch/tile/include/asm/bitops_64.h [new file with mode: 0644]
arch/tile/include/asm/cacheflush.h
arch/tile/include/asm/compat.h
arch/tile/include/asm/dma-mapping.h
arch/tile/include/asm/fb.h [new file with mode: 0644]
arch/tile/include/asm/hardwall.h
arch/tile/include/asm/io.h
arch/tile/include/asm/irq.h
arch/tile/include/asm/mmu_context.h
arch/tile/include/asm/opcode-tile_32.h
arch/tile/include/asm/opcode-tile_64.h
arch/tile/include/asm/opcode_constants_64.h
arch/tile/include/asm/page.h
arch/tile/include/asm/parport.h [new file with mode: 0644]
arch/tile/include/asm/pci.h
arch/tile/include/asm/pgtable_64.h [new file with mode: 0644]
arch/tile/include/asm/processor.h
arch/tile/include/asm/serial.h [new file with mode: 0644]
arch/tile/include/asm/signal.h
arch/tile/include/asm/spinlock_64.h [new file with mode: 0644]
arch/tile/include/asm/stat.h
arch/tile/include/asm/swab.h
arch/tile/include/asm/thread_info.h
arch/tile/include/asm/topology.h
arch/tile/include/asm/traps.h
arch/tile/include/asm/unistd.h
arch/tile/include/asm/vga.h [moved from arch/tile/include/hv/pagesize.h with 52% similarity]
arch/tile/include/hv/hypervisor.h
arch/tile/kernel/Makefile
arch/tile/kernel/backtrace.c
arch/tile/kernel/compat.c
arch/tile/kernel/compat_signal.c
arch/tile/kernel/futex_64.S [new file with mode: 0644]
arch/tile/kernel/hardwall.c
arch/tile/kernel/head_64.S [new file with mode: 0644]
arch/tile/kernel/intvec_32.S
arch/tile/kernel/intvec_64.S [new file with mode: 0644]
arch/tile/kernel/module.c
arch/tile/kernel/pci-dma.c
arch/tile/kernel/pci.c
arch/tile/kernel/proc.c
arch/tile/kernel/process.c
arch/tile/kernel/regs_64.S [new file with mode: 0644]
arch/tile/kernel/setup.c
arch/tile/kernel/signal.c
arch/tile/kernel/single_step.c
arch/tile/kernel/stack.c
arch/tile/kernel/sys.c
arch/tile/kernel/sysfs.c [new file with mode: 0644]
arch/tile/kernel/tile-desc_32.c
arch/tile/kernel/tile-desc_64.c [new file with mode: 0644]
arch/tile/kernel/time.c
arch/tile/kernel/tlb.c
arch/tile/kernel/traps.c
arch/tile/kernel/vmlinux.lds.S
arch/tile/lib/atomic_asm_32.S
arch/tile/lib/cacheflush.c
arch/tile/lib/memchr_64.c [new file with mode: 0644]
arch/tile/lib/memcpy_64.c [new file with mode: 0644]
arch/tile/lib/memcpy_user_64.c [new file with mode: 0644]
arch/tile/lib/memset_64.c [new file with mode: 0644]
arch/tile/lib/spinlock_64.c [new file with mode: 0644]
arch/tile/lib/strchr_64.c [new file with mode: 0644]
arch/tile/lib/strlen_64.c [new file with mode: 0644]
arch/tile/lib/usercopy_64.S [new file with mode: 0644]
arch/tile/mm/fault.c
arch/tile/mm/init.c
arch/tile/mm/migrate_64.S [new file with mode: 0644]
arch/um/Kconfig.debug
arch/um/Kconfig.x86
arch/um/drivers/Makefile
arch/um/drivers/mcast.h [deleted file]
arch/um/drivers/mcast_kern.c [deleted file]
arch/um/drivers/mcast_user.c [deleted file]
arch/um/drivers/umcast.h [new file with mode: 0644]
arch/um/drivers/umcast_kern.c [new file with mode: 0644]
arch/um/drivers/umcast_user.c [new file with mode: 0644]
arch/um/drivers/xterm.c
arch/um/include/asm/common.lds.S
arch/um/include/asm/processor-generic.h
arch/um/include/asm/smp.h
arch/um/include/asm/tlb.h
arch/um/include/shared/os.h
arch/um/kernel/Makefile
arch/um/kernel/early_printk.c [new file with mode: 0644]
arch/um/kernel/smp.c
arch/um/kernel/trap.c
arch/um/os-Linux/main.c
arch/um/os-Linux/process.c
arch/um/os-Linux/util.c
arch/unicore32/Kconfig
arch/unicore32/Kconfig.debug
arch/unicore32/Makefile
arch/unicore32/boot/compressed/Makefile
arch/unicore32/configs/unicore32_defconfig [moved from arch/unicore32/configs/debug_defconfig with 97% similarity]
arch/unicore32/include/asm/Kbuild
arch/unicore32/include/asm/suspend.h
arch/unicore32/kernel/Makefile
arch/unicore32/kernel/vmlinux.lds.S
arch/unicore32/mm/init.c
arch/unicore32/mm/mmu.c
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/configs/i386_defconfig
arch/x86/configs/x86_64_defconfig
arch/x86/ia32/ia32entry.S
arch/x86/include/asm/acpi.h
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/desc.h
arch/x86/include/asm/idle.h
arch/x86/include/asm/io.h
arch/x86/include/asm/kgdb.h
arch/x86/include/asm/linkage.h
arch/x86/include/asm/memblock.h
arch/x86/include/asm/mmu.h
arch/x86/include/asm/percpu.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/ptrace.h
arch/x86/include/asm/pvclock.h
arch/x86/include/asm/suspend_32.h
arch/x86/include/asm/suspend_64.h
arch/x86/include/asm/tsc.h
arch/x86/include/asm/unistd_32.h
arch/x86/include/asm/unistd_64.h
arch/x86/include/asm/uv/uv_bau.h
arch/x86/include/asm/uv/uv_hub.h
arch/x86/include/asm/uv/uv_mmrs.h
arch/x86/include/asm/vdso.h
arch/x86/include/asm/vgtod.h
arch/x86/include/asm/vsyscall.h
arch/x86/include/asm/vvar.h [new file with mode: 0644]
arch/x86/include/asm/xen/hypercall.h
arch/x86/kernel/Makefile
arch/x86/kernel/amd_iommu.c
arch/x86/kernel/amd_iommu_init.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/apm_32.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/devicetree.c
arch/x86/kernel/ftrace.c
arch/x86/kernel/process.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/setup.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/syscall_table_32.S
arch/x86/kernel/tboot.c
arch/x86/kernel/time.c
arch/x86/kernel/tsc.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/kernel/vread_tsc_64.c [new file with mode: 0644]
arch/x86/kernel/vsyscall_64.c
arch/x86/kvm/emulate.c
arch/x86/kvm/mmu.c
arch/x86/kvm/paging_tmpl.h
arch/x86/kvm/vmx.c
arch/x86/lguest/boot.c
arch/x86/mm/fault.c
arch/x86/mm/hugetlbpage.c
arch/x86/mm/init.c
arch/x86/mm/memblock.c
arch/x86/oprofile/op_model_amd.c
arch/x86/pci/acpi.c
arch/x86/platform/efi/efi.c
arch/x86/platform/efi/efi_64.c
arch/x86/platform/uv/tlb_uv.c
arch/x86/platform/uv/uv_time.c
arch/x86/vdso/Makefile
arch/x86/vdso/vclock_gettime.c
arch/x86/vdso/vdso.lds.S
arch/x86/vdso/vextern.h [deleted file]
arch/x86/vdso/vgetcpu.c
arch/x86/vdso/vma.c
arch/x86/vdso/vvar.c [deleted file]
arch/x86/xen/enlighten.c
arch/x86/xen/mmu.c
arch/x86/xen/mmu.h
arch/x86/xen/multicalls.c
arch/x86/xen/setup.c
arch/x86/xen/smp.c
arch/xtensa/Kconfig
arch/xtensa/include/asm/page.h
arch/xtensa/include/asm/unistd.h
arch/xtensa/kernel/vmlinux.lds.S
arch/xtensa/mm/mmu.c
arch/xtensa/mm/pgtable.c [deleted file]
block/blk-cgroup.c
block/blk-cgroup.h
block/blk-core.c
block/blk-exec.c
block/blk-flush.c
block/blk-ioc.c
block/blk-lib.c
block/blk-settings.c
block/blk-sysfs.c
block/blk-throttle.c
block/blk.h
block/cfq-iosched.c
block/elevator.c
block/genhd.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/acpica/Makefile
drivers/acpi/acpica/acconfig.h
drivers/acpi/acpica/acevents.h
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/amlcode.h
drivers/acpi/acpica/dswload.c
drivers/acpi/acpica/dswload2.c
drivers/acpi/acpica/evglock.c [new file with mode: 0644]
drivers/acpi/acpica/evmisc.c
drivers/acpi/acpica/evregion.c
drivers/acpi/acpica/evrgnini.c
drivers/acpi/acpica/evxfregn.c
drivers/acpi/acpica/excreate.c
drivers/acpi/acpica/nsrepair.c
drivers/acpi/acpica/utdecode.c
drivers/acpi/acpica/utmutex.c
drivers/acpi/apei/einj.c
drivers/acpi/atomicio.c
drivers/acpi/bus.c
drivers/acpi/custom_method.c [new file with mode: 0644]
drivers/acpi/debugfs.c
drivers/acpi/ec.c
drivers/acpi/internal.h
drivers/acpi/osl.c
drivers/acpi/processor_core.c
drivers/acpi/processor_idle.c
drivers/acpi/sysfs.c
drivers/amba/bus.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/ata/pata_marvell.c
drivers/ata/pata_pcmcia.c
drivers/ata/sata_dwc_460ex.c
drivers/base/node.c
drivers/base/power/clock_ops.c
drivers/base/power/main.c
drivers/bcma/host_pci.c
drivers/block/Kconfig
drivers/block/Makefile
drivers/block/brd.c
drivers/block/cciss.c
drivers/block/cciss.h
drivers/block/cciss_cmd.h
drivers/block/cciss_scsi.c
drivers/block/cciss_scsi.h
drivers/block/drbd/drbd_actlog.c
drivers/block/drbd/drbd_bitmap.c
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_nl.c
drivers/block/drbd/drbd_receiver.c
drivers/block/drbd/drbd_req.c
drivers/block/drbd/drbd_req.h
drivers/block/drbd/drbd_worker.c
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/nbd.c
drivers/block/paride/pcd.c
drivers/block/rbd.c
drivers/block/virtio_blk.c
drivers/block/xen-blkback/Makefile [new file with mode: 0644]
drivers/block/xen-blkback/blkback.c [new file with mode: 0644]
drivers/block/xen-blkback/common.h [new file with mode: 0644]
drivers/block/xen-blkback/xenbus.c [new file with mode: 0644]
drivers/block/xen-blkfront.c
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btmrvl_debugfs.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/dtl1_cs.c
drivers/bluetooth/hci_ldisc.c
drivers/cdrom/viocd.c
drivers/char/agp/intel-agp.c
drivers/char/agp/intel-agp.h
drivers/char/agp/intel-gtt.c
drivers/char/agp/uninorth-agp.c
drivers/char/hpet.c
drivers/char/i8k.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/mspec.c
drivers/char/pcmcia/cm4000_cs.c
drivers/char/pcmcia/cm4040_cs.c
drivers/char/pcmcia/synclink_cs.c
drivers/char/ppdev.c
drivers/char/virtio_console.c
drivers/clocksource/sh_cmt.c
drivers/clocksource/sh_tmu.c
drivers/cpufreq/Makefile
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/db8500-cpufreq.c [new file with mode: 0644]
drivers/cpufreq/powernow-k8.c
drivers/cpuidle/governors/menu.c
drivers/crypto/Kconfig
drivers/dma/Kconfig
drivers/dma/TODO [new file with mode: 0644]
drivers/dma/at_hdmac.c
drivers/dma/at_hdmac_regs.h
drivers/dma/coh901318.c
drivers/dma/dw_dmac.c
drivers/dma/dw_dmac_regs.h
drivers/dma/intel_mid_dma.c
drivers/dma/ioat/dma_v2.c
drivers/dma/iop-adma.c
drivers/dma/mv_xor.c
drivers/dma/pch_dma.c
drivers/dma/ppc4xx/adma.c
drivers/dma/shdma.c
drivers/dma/shdma.h
drivers/dma/ste_dma40.c
drivers/dma/timb_dma.c
drivers/edac/amd76x_edac.c
drivers/edac/amd8111_edac.c
drivers/edac/amd8131_edac.c
drivers/edac/cpc925_edac.c
drivers/edac/e752x_edac.c
drivers/edac/e7xxx_edac.c
drivers/edac/edac_core.h
drivers/edac/edac_device.c
drivers/edac/edac_mc.c
drivers/edac/edac_module.c
drivers/edac/edac_pci.c
drivers/edac/i3200_edac.c
drivers/edac/i5000_edac.c
drivers/edac/i5400_edac.c
drivers/edac/i7300_edac.c
drivers/edac/i7core_edac.c
drivers/edac/i82860_edac.c
drivers/edac/i82875p_edac.c
drivers/edac/i82975x_edac.c
drivers/edac/mpc85xx_edac.h
drivers/edac/mv64x60_edac.h
drivers/edac/ppc4xx_edac.c
drivers/edac/r82600_edac.c
drivers/firmware/iscsi_ibft_find.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/basic_mmio_gpio.c
drivers/gpio/gpio-exynos4.c [moved from arch/arm/mach-exynos4/gpiolib.c with 92% similarity]
drivers/gpio/gpio-nomadik.c [moved from arch/arm/plat-nomadik/gpio.c with 89% similarity]
drivers/gpio/gpio-omap.c [moved from arch/arm/plat-omap/gpio.c with 92% similarity]
drivers/gpio/gpio-plat-samsung.c [moved from arch/arm/plat-samsung/gpiolib.c with 100% similarity]
drivers/gpio/gpio-s5pc100.c [moved from arch/arm/mach-s5pc100/gpiolib.c with 100% similarity]
drivers/gpio/gpio-s5pv210.c [moved from arch/arm/mach-s5pv210/gpiolib.c with 100% similarity]
drivers/gpio/gpio-u300.c [moved from arch/arm/mach-u300/gpio.c with 100% similarity]
drivers/gpio/gpiolib.c
drivers/gpio/janz-ttl.c
drivers/gpio/langwell_gpio.c
drivers/gpio/ml_ioh_gpio.c
drivers/gpio/pca953x.c
drivers/gpio/pch_gpio.c
drivers/gpio/rdc321x-gpio.c
drivers/gpio/timbgpio.c
drivers/gpio/tps65910-gpio.c [new file with mode: 0644]
drivers/gpio/vx855_gpio.c
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_ioc32.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_pci.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/drm_vm.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_i2c.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_modes.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/mga/mga_drv.h
drivers/gpu/drm/nouveau/Kconfig
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bios.h
drivers/gpu/drm/nouveau/nouveau_channel.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_drv.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/nouveau/nouveau_grctx.h
drivers/gpu/drm/nouveau/nouveau_hw.c
drivers/gpu/drm/nouveau/nouveau_mem.c
drivers/gpu/drm/nouveau/nouveau_object.c
drivers/gpu/drm/nouveau/nouveau_perf.c
drivers/gpu/drm/nouveau/nouveau_pm.c
drivers/gpu/drm/nouveau/nouveau_reg.h
drivers/gpu/drm/nouveau/nouveau_sgdma.c
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nouveau_vm.c
drivers/gpu/drm/nouveau/nouveau_vm.h
drivers/gpu/drm/nouveau/nouveau_volt.c
drivers/gpu/drm/nouveau/nv04_crtc.c
drivers/gpu/drm/nouveau/nv04_graph.c
drivers/gpu/drm/nouveau/nv04_instmem.c
drivers/gpu/drm/nouveau/nv10_graph.c
drivers/gpu/drm/nouveau/nv20_graph.c
drivers/gpu/drm/nouveau/nv40_fifo.c
drivers/gpu/drm/nouveau/nv40_graph.c
drivers/gpu/drm/nouveau/nv40_mpeg.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_calc.c
drivers/gpu/drm/nouveau/nv50_crtc.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_graph.c
drivers/gpu/drm/nouveau/nv50_grctx.c
drivers/gpu/drm/nouveau/nv50_mpeg.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_pm.c
drivers/gpu/drm/nouveau/nv50_vm.c
drivers/gpu/drm/nouveau/nv84_crypt.c
drivers/gpu/drm/nouveau/nva3_copy.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nva3_copy.fuc [new file with mode: 0644]
drivers/gpu/drm/nouveau/nva3_copy.fuc.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nva3_pm.c
drivers/gpu/drm/nouveau/nvc0_copy.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvc0_copy.fuc.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvc0_fifo.c
drivers/gpu/drm/nouveau/nvc0_graph.c
drivers/gpu/drm/nouveau/nvc0_graph.h
drivers/gpu/drm/nouveau/nvc0_grctx.c
drivers/gpu/drm/nouveau/nvreg.h
drivers/gpu/drm/radeon/Kconfig
drivers/gpu/drm/radeon/atom.c
drivers/gpu/drm/radeon/atombios.h
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/cayman_blit_shaders.c
drivers/gpu/drm/radeon/cayman_blit_shaders.h
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_blit_kms.c
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/nid.h
drivers/gpu/drm/radeon/r100_track.h
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_cs.c
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_clocks.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_family.h
drivers/gpu/drm/radeon/radeon_fence.c
drivers/gpu/drm/radeon/radeon_i2c.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/reg_srcs/r600
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/savage/savage_bci.c
drivers/gpu/drm/ttm/ttm_page_alloc.c
drivers/gpu/vga/vga_switcheroo.c
drivers/gpu/vga/vgaarb.c
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-magicmouse.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-roccat-arvo.c
drivers/hid/hid-roccat-arvo.h
drivers/hid/hid-roccat-common.c
drivers/hid/hid-roccat-common.h
drivers/hid/hid-roccat-kone.c
drivers/hid/hid-roccat-kone.h
drivers/hid/hid-roccat-koneplus.c
drivers/hid/hid-roccat-koneplus.h
drivers/hid/hid-roccat-kovaplus.c
drivers/hid/hid-roccat-kovaplus.h
drivers/hid/hid-roccat-pyra.c
drivers/hid/hid-roccat-pyra.h
drivers/hid/hid-wiimote.c [new file with mode: 0644]
drivers/hid/usbhid/hid-quirks.c
drivers/hid/usbhid/hiddev.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/abituguru.c
drivers/hwmon/abituguru3.c
drivers/hwmon/acpi_power_meter.c [moved from drivers/acpi/power_meter.c with 100% similarity]
drivers/hwmon/adcxx.c
drivers/hwmon/asus_atk0110.c
drivers/hwmon/coretemp.c
drivers/hwmon/emc6w201.c [new file with mode: 0644]
drivers/hwmon/f71882fg.c
drivers/hwmon/fam15h_power.c [new file with mode: 0644]
drivers/hwmon/ibmaem.c
drivers/hwmon/ibmpex.c
drivers/hwmon/it87.c
drivers/hwmon/jc42.c
drivers/hwmon/k10temp.c
drivers/hwmon/k8temp.c
drivers/hwmon/lm70.c
drivers/hwmon/max6642.c
drivers/hwmon/max6650.c
drivers/hwmon/pmbus_core.c
drivers/hwmon/s3c-hwmon.c
drivers/hwmon/sch5627.c
drivers/hwmon/ultra45_env.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-eg20t.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-nomadik.c
drivers/i2c/busses/i2c-ocores.c
drivers/i2c/busses/i2c-parport-light.c
drivers/i2c/busses/i2c-parport.c
drivers/i2c/busses/i2c-parport.h
drivers/i2c/busses/i2c-sh_mobile.c
drivers/i2c/busses/i2c-tegra.c
drivers/i2c/busses/i2c-xiic.c
drivers/ide/ide-cd.c
drivers/ide/ide-cs.c
drivers/infiniband/Kconfig
drivers/infiniband/core/Makefile
drivers/infiniband/core/cm.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/device.c
drivers/infiniband/core/mad.c
drivers/infiniband/core/netlink.c [new file with mode: 0644]
drivers/infiniband/core/ucma.c
drivers/infiniband/core/user_mad.c
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/hw/cxgb3/iwch_cm.c
drivers/infiniband/hw/cxgb3/iwch_provider.h
drivers/infiniband/hw/cxgb3/iwch_qp.c
drivers/infiniband/hw/cxgb4/cm.c
drivers/infiniband/hw/cxgb4/cq.c
drivers/infiniband/hw/cxgb4/iw_cxgb4.h
drivers/infiniband/hw/cxgb4/mem.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/nes/nes.c
drivers/infiniband/hw/qib/Kconfig
drivers/infiniband/hw/qib/qib_iba7322.c
drivers/infiniband/hw/qib/qib_intr.c
drivers/infiniband/ulp/iser/iser_verbs.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/input/evdev.c
drivers/input/input-compat.h
drivers/input/input-polldev.c
drivers/input/input.c
drivers/input/joydev.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/adp5589-keys.c [new file with mode: 0644]
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/mpr121_touchkey.c [new file with mode: 0644]
drivers/input/keyboard/omap-keypad.c
drivers/input/keyboard/pmic8xxx-keypad.c [new file with mode: 0644]
drivers/input/keyboard/qt1070.c
drivers/input/keyboard/sh_keysc.c
drivers/input/keyboard/tegra-kbc.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/ad714x.c
drivers/input/misc/ati_remote2.c
drivers/input/misc/pmic8xxx-pwrkey.c [new file with mode: 0644]
drivers/input/misc/rotary_encoder.c
drivers/input/misc/twl4030-pwrbutton.c
drivers/input/misc/twl4030-vibra.c
drivers/input/mouse/elantech.c
drivers/input/mouse/elantech.h
drivers/input/mousedev.c
drivers/input/serio/serport.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/atmel_tsadcc.c
drivers/input/touchscreen/h3600_ts_input.c
drivers/input/touchscreen/max11801_ts.c [new file with mode: 0644]
drivers/input/touchscreen/tsc2007.c
drivers/isdn/gigaset/interface.c
drivers/isdn/gigaset/ser-gigaset.c
drivers/isdn/hardware/avm/avm_cs.c
drivers/isdn/hardware/eicon/divasfunc.c
drivers/isdn/hardware/mISDN/hfcsusb.c
drivers/isdn/hardware/mISDN/netjet.c
drivers/isdn/hisax/avma1_cs.c
drivers/isdn/hisax/elsa_cs.c
drivers/isdn/hisax/sedlbauer_cs.c
drivers/isdn/hisax/teles_cs.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/led-class.c
drivers/leds/leds-88pm860x.c
drivers/leds/leds-asic3.c [new file with mode: 0644]
drivers/leds/leds-gpio-register.c [new file with mode: 0644]
drivers/leds/leds-h1940.c [deleted file]
drivers/leds/leds-lm3530.c
drivers/leds/leds-mc13783.c
drivers/leds/leds-pca9532.c
drivers/leds/leds.h
drivers/leds/ledtrig-timer.c
drivers/md/bitmap.c
drivers/md/bitmap.h
drivers/md/dm-io.c
drivers/md/dm-kcopyd.c
drivers/md/dm-log.c
drivers/md/dm-mpath.c
drivers/md/dm-raid1.c
drivers/md/dm-snap-persistent.c
drivers/md/dm-snap.c
drivers/md/dm-table.c
drivers/md/md.c
drivers/md/md.h
drivers/md/raid1.c
drivers/md/raid1.h
drivers/md/raid5.c
drivers/media/dvb/dm1105/dm1105.c
drivers/media/dvb/dvb-usb/anysee.c
drivers/media/dvb/dvb-usb/lmedm04.c
drivers/media/dvb/frontends/stb0899_algo.c
drivers/media/dvb/frontends/tda8261.c
drivers/media/media-devnode.c
drivers/media/radio/radio-maxiradio.c
drivers/media/radio/radio-timb.c
drivers/media/radio/radio-wl1273.c
drivers/media/radio/wl128x/fmdrv_v4l2.c
drivers/media/rc/Kconfig
drivers/media/rc/Makefile
drivers/media/rc/fintek-cir.c [new file with mode: 0644]
drivers/media/rc/fintek-cir.h [new file with mode: 0644]
drivers/media/rc/keymaps/rc-lme2510.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cx231xx/cx231xx-avcore.c
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/gspca/coarse_expo_autogain.h [deleted file]
drivers/media/video/gspca/kinect.c
drivers/media/video/gspca/ov519.c
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-firmware.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-ioctl.h
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/ivtv/ivtv-vbi.c
drivers/media/video/ivtv/ivtvfb.c
drivers/media/video/m5mols/Kconfig [new file with mode: 0644]
drivers/media/video/m5mols/Makefile [new file with mode: 0644]
drivers/media/video/m5mols/m5mols.h [new file with mode: 0644]
drivers/media/video/m5mols/m5mols_capture.c [new file with mode: 0644]
drivers/media/video/m5mols/m5mols_controls.c [new file with mode: 0644]
drivers/media/video/m5mols/m5mols_core.c [new file with mode: 0644]
drivers/media/video/m5mols/m5mols_reg.h [new file with mode: 0644]
drivers/media/video/omap/omap_vout.c
drivers/media/video/omap/omap_voutdef.h
drivers/media/video/omap3isp/isp.c
drivers/media/video/soc_camera.c
drivers/media/video/timblogiw.c
drivers/media/video/uvc/Makefile
drivers/media/video/uvc/uvc_driver.c
drivers/media/video/uvc/uvc_entity.c [new file with mode: 0644]
drivers/media/video/uvc/uvcvideo.h
drivers/mfd/88pm860x-core.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/ab3100-core.c
drivers/mfd/ab3550-core.c
drivers/mfd/ab8500-core.c
drivers/mfd/ab8500-gpadc.c
drivers/mfd/ab8500-i2c.c
drivers/mfd/asic3.c
drivers/mfd/davinci_voicecodec.c
drivers/mfd/db5500-prcmu-regs.h [moved from arch/arm/mach-ux500/include/mach/prcmu-regs.h with 80% similarity]
drivers/mfd/db5500-prcmu.c [new file with mode: 0644]
drivers/mfd/db8500-prcmu-regs.h [new file with mode: 0644]
drivers/mfd/db8500-prcmu.c [new file with mode: 0644]
drivers/mfd/htc-pasic3.c
drivers/mfd/janz-cmodio.c
drivers/mfd/max8925-core.c
drivers/mfd/mc13xxx-core.c
drivers/mfd/mfd-core.c
drivers/mfd/omap-usb-host.c
drivers/mfd/pm8921-core.c [new file with mode: 0644]
drivers/mfd/pm8xxx-irq.c [new file with mode: 0644]
drivers/mfd/rdc321x-southbridge.c
drivers/mfd/t7l66xb.c
drivers/mfd/tc6387xb.c
drivers/mfd/tc6393xb.c
drivers/mfd/timberdale.c
drivers/mfd/tps6105x.c
drivers/mfd/tps6586x.c
drivers/mfd/tps65910-irq.c [new file with mode: 0644]
drivers/mfd/tps65910.c [new file with mode: 0644]
drivers/mfd/tps65911-comparator.c [new file with mode: 0644]
drivers/mfd/twl-core.c
drivers/mfd/twl4030-codec.c
drivers/mfd/twl4030-power.c
drivers/mfd/twl6030-irq.c
drivers/mfd/wl1273-core.c
drivers/mfd/wm831x-core.c
drivers/mfd/wm831x-irq.c
drivers/mfd/wm8400-core.c
drivers/misc/apds990x.c
drivers/misc/cs5535-mfgpt.c
drivers/misc/kgdbts.c
drivers/misc/sgi-xp/xpnet.c
drivers/misc/spear13xx_pcie_gadget.c
drivers/misc/ti-st/st_core.c
drivers/mmc/card/block.c
drivers/mmc/card/mmc_test.c
drivers/mmc/card/queue.c
drivers/mmc/core/bus.c
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/mmc_ops.h
drivers/mmc/core/quirks.c
drivers/mmc/core/sd.c
drivers/mmc/core/sd.h
drivers/mmc/core/sd_ops.c
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_irq.c
drivers/mmc/core/sdio_ops.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/mmci.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pxa.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sdricoh_cs.c
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/sh_mobile_sdhi.c
drivers/mmc/host/tmio_mmc.c
drivers/mmc/host/tmio_mmc.h
drivers/mmc/host/tmio_mmc_dma.c
drivers/mmc/host/tmio_mmc_pio.c
drivers/mmc/host/vub300.c [new file with mode: 0644]
drivers/mtd/Kconfig
drivers/mtd/Makefile
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/chips/cfi_cmdset_0020.c
drivers/mtd/devices/block2mtd.c
drivers/mtd/devices/doc2000.c
drivers/mtd/devices/doc2001.c
drivers/mtd/devices/doc2001plus.c
drivers/mtd/devices/lart.c
drivers/mtd/devices/m25p80.c
drivers/mtd/devices/ms02-nv.c
drivers/mtd/devices/mtd_dataflash.c
drivers/mtd/devices/mtdram.c
drivers/mtd/devices/phram.c
drivers/mtd/devices/pmc551.c
drivers/mtd/devices/slram.c
drivers/mtd/devices/sst25l.c
drivers/mtd/lpddr/lpddr_cmds.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/amd76xrom.c
drivers/mtd/maps/autcpu12-nvram.c
drivers/mtd/maps/bcm963xx-flash.c
drivers/mtd/maps/bfin-async-flash.c
drivers/mtd/maps/cdb89712.c
drivers/mtd/maps/ceiva.c
drivers/mtd/maps/cfi_flagadm.c
drivers/mtd/maps/ck804xrom.c
drivers/mtd/maps/dbox2-flash.c
drivers/mtd/maps/dc21285.c
drivers/mtd/maps/dilnetpc.c
drivers/mtd/maps/dmv182.c
drivers/mtd/maps/edb7312.c
drivers/mtd/maps/esb2rom.c
drivers/mtd/maps/fortunet.c
drivers/mtd/maps/gpio-addr-flash.c
drivers/mtd/maps/h720x-flash.c
drivers/mtd/maps/ichxrom.c
drivers/mtd/maps/impa7.c
drivers/mtd/maps/intel_vr_nor.c
drivers/mtd/maps/ixp2000.c
drivers/mtd/maps/ixp4xx.c
drivers/mtd/maps/l440gx.c
drivers/mtd/maps/latch-addr-flash.c
drivers/mtd/maps/mbx860.c
drivers/mtd/maps/netsc520.c
drivers/mtd/maps/nettel.c
drivers/mtd/maps/octagon-5066.c
drivers/mtd/maps/pci.c
drivers/mtd/maps/pcmciamtd.c
drivers/mtd/maps/physmap.c
drivers/mtd/maps/physmap_of.c
drivers/mtd/maps/plat-ram.c
drivers/mtd/maps/pmcmsp-flash.c
drivers/mtd/maps/pxa2xx-flash.c
drivers/mtd/maps/rbtx4939-flash.c
drivers/mtd/maps/rpxlite.c
drivers/mtd/maps/sa1100-flash.c
drivers/mtd/maps/sbc_gxx.c
drivers/mtd/maps/sc520cdp.c
drivers/mtd/maps/scb2_flash.c
drivers/mtd/maps/scx200_docflash.c
drivers/mtd/maps/solutionengine.c
drivers/mtd/maps/sun_uflash.c
drivers/mtd/maps/tqm8xxl.c
drivers/mtd/maps/ts5500_flash.c
drivers/mtd/maps/tsunami_flash.c
drivers/mtd/maps/uclinux.c
drivers/mtd/maps/vmax301.c
drivers/mtd/maps/vmu-flash.c
drivers/mtd/maps/wr_sbc82xx_flash.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/mtdchar.c
drivers/mtd/mtdconcat.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdcore.h
drivers/mtd/mtdpart.c
drivers/mtd/mtdswap.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/alauda.c
drivers/mtd/nand/ams-delta.c
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/au1550nd.c
drivers/mtd/nand/autcpu12.c
drivers/mtd/nand/bcm_umi_nand.c
drivers/mtd/nand/bf5xx_nand.c
drivers/mtd/nand/cafe_nand.c
drivers/mtd/nand/cmx270_nand.c
drivers/mtd/nand/cs553x_nand.c
drivers/mtd/nand/davinci_nand.c
drivers/mtd/nand/denali.c
drivers/mtd/nand/denali.h
drivers/mtd/nand/diskonchip.c
drivers/mtd/nand/edb7312.c
drivers/mtd/nand/fsl_elbc_nand.c
drivers/mtd/nand/fsl_upm.c
drivers/mtd/nand/fsmc_nand.c
drivers/mtd/nand/gpio.c
drivers/mtd/nand/h1910.c
drivers/mtd/nand/jz4740_nand.c
drivers/mtd/nand/mpc5121_nfc.c
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_bbt.c
drivers/mtd/nand/nandsim.c
drivers/mtd/nand/ndfc.c
drivers/mtd/nand/nomadik_nand.c
drivers/mtd/nand/nuc900_nand.c
drivers/mtd/nand/omap2.c
drivers/mtd/nand/orion_nand.c
drivers/mtd/nand/pasemi_nand.c
drivers/mtd/nand/plat_nand.c
drivers/mtd/nand/ppchameleonevb.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/nand/rtc_from4.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/sh_flctl.c
drivers/mtd/nand/sharpsl.c
drivers/mtd/nand/sm_common.c
drivers/mtd/nand/socrates_nand.c
drivers/mtd/nand/spia.c
drivers/mtd/nand/tmio_nand.c
drivers/mtd/nand/txx9ndfmc.c
drivers/mtd/onenand/Kconfig
drivers/mtd/onenand/generic.c
drivers/mtd/onenand/omap2.c
drivers/mtd/onenand/onenand_base.c
drivers/mtd/onenand/onenand_sim.c
drivers/mtd/onenand/samsung.c
drivers/mtd/ubi/cdev.c
drivers/mtd/ubi/debug.c
drivers/mtd/ubi/debug.h
drivers/mtd/ubi/gluebi.c
drivers/mtd/ubi/io.c
drivers/mtd/ubi/scan.c
drivers/mtd/ubi/ubi-media.h
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/wl.c
drivers/net/3c503.c
drivers/net/3c509.c
drivers/net/3c59x.c
drivers/net/Makefile
drivers/net/arm/am79c961a.c
drivers/net/arm/ep93xx_eth.c
drivers/net/arm/ixp4xx_eth.c
drivers/net/benet/be_cmds.c
drivers/net/bfin_mac.c
drivers/net/bnx2x/bnx2x_cmn.c
drivers/net/bnx2x/bnx2x_main.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_sysfs.c
drivers/net/caif/caif_serial.c
drivers/net/can/flexcan.c
drivers/net/can/janz-ican3.c
drivers/net/can/slcan.c
drivers/net/can/softing/softing_cs.c
drivers/net/davinci_emac.c
drivers/net/depca.c
drivers/net/dl2k.c
drivers/net/dm9000.c
drivers/net/ehea/ehea_main.c
drivers/net/fs_enet/mac-fcc.c
drivers/net/gianfar.c
drivers/net/gianfar.h
drivers/net/gianfar_ethtool.c
drivers/net/gianfar_ptp.c [new file with mode: 0644]
drivers/net/hamradio/6pack.c
drivers/net/hamradio/baycom_epp.c
drivers/net/hamradio/baycom_par.c
drivers/net/hamradio/baycom_ser_fdx.c
drivers/net/hamradio/baycom_ser_hdx.c
drivers/net/hamradio/hdlcdrv.c
drivers/net/hamradio/mkiss.c
drivers/net/hp100.c
drivers/net/hplance.c
drivers/net/ibmlana.c
drivers/net/igb/igb_main.c
drivers/net/ioc3-eth.c
drivers/net/irda/bfin_sir.c
drivers/net/irda/bfin_sir.h
drivers/net/irda/irtty-sir.c
drivers/net/irda/smsc-ircc2.c
drivers/net/ks8842.c
drivers/net/ne3210.c
drivers/net/netxen/netxen_nic_main.c
drivers/net/pcmcia/3c574_cs.c
drivers/net/pcmcia/3c589_cs.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcmcia/com20020_cs.c
drivers/net/pcmcia/fmvj18x_cs.c
drivers/net/pcmcia/ibmtr_cs.c
drivers/net/pcmcia/nmclan_cs.c
drivers/net/pcmcia/pcnet_cs.c
drivers/net/pcmcia/smc91c92_cs.c
drivers/net/pcmcia/xirc2ps_cs.c
drivers/net/phy/Kconfig
drivers/net/phy/Makefile
drivers/net/phy/dp83640.c [new file with mode: 0644]
drivers/net/phy/dp83640_reg.h [new file with mode: 0644]
drivers/net/ppp_async.c
drivers/net/ppp_synctty.c
drivers/net/pxa168_eth.c
drivers/net/qlcnic/qlcnic_hw.c
drivers/net/qlcnic/qlcnic_main.c
drivers/net/r8169.c
drivers/net/sfc/mtd.c
drivers/net/slip.c
drivers/net/smc-mca.c
drivers/net/smc91x.c
drivers/net/tg3.c
drivers/net/tile/tilepro.c
drivers/net/tokenring/madgemc.c
drivers/net/tulip/de4x5.c
drivers/net/tun.c
drivers/net/usb/Kconfig
drivers/net/usb/Makefile
drivers/net/usb/catc.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/kalmia.c [new file with mode: 0644]
drivers/net/via-velocity.h
drivers/net/virtio_net.c
drivers/net/wan/farsync.c
drivers/net/wan/pc300_drv.c
drivers/net/wan/x25_asy.c
drivers/net/wireless/airo.c
drivers/net/wireless/airo_cs.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/reset.c
drivers/net/wireless/ath/ath9k/Kconfig
drivers/net/wireless/ath/ath9k/ahb.c
drivers/net/wireless/ath/ath9k/ani.c
drivers/net/wireless/ath/ath9k/ani.h
drivers/net/wireless/ath/ath9k/ar5008_initvals.h
drivers/net/wireless/ath/ath9k/ar5008_phy.c
drivers/net/wireless/ath/ath9k/ar9001_initvals.h
drivers/net/wireless/ath/ath9k/ar9002_calib.c
drivers/net/wireless/ath/ath9k/ar9002_hw.c
drivers/net/wireless/ath/ath9k/ar9002_initvals.h
drivers/net/wireless/ath/ath9k/ar9002_mac.c
drivers/net/wireless/ath/ath9k/ar9002_phy.c
drivers/net/wireless/ath/ath9k/ar9002_phy.h
drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ar9003_mac.c
drivers/net/wireless/ath/ath9k/ar9003_mac.h
drivers/net/wireless/ath/ath9k/ar9003_paprd.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ar9485_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/btcoex.c
drivers/net/wireless/ath/ath9k/btcoex.h
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/calib.h
drivers/net/wireless/ath/ath9k/common.c
drivers/net/wireless/ath/ath9k/common.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/eeprom.c
drivers/net/wireless/ath/ath9k/eeprom.h
drivers/net/wireless/ath/ath9k/eeprom_4k.c
drivers/net/wireless/ath/ath9k/eeprom_9287.c
drivers/net/wireless/ath/ath9k/eeprom_def.c
drivers/net/wireless/ath/ath9k/gpio.c
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/hif_usb.h
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
drivers/net/wireless/ath/ath9k/htc_hst.c
drivers/net/wireless/ath/ath9k/htc_hst.h
drivers/net/wireless/ath/ath9k/hw-ops.h
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/mac.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/phy.h
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/ath/ath9k/rc.h
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/wmi.c
drivers/net/wireless/ath/ath9k/wmi.h
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/carl9170.h
drivers/net/wireless/ath/carl9170/fw.c
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/hw.c
drivers/net/wireless/atmel_cs.c
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/dma.c
drivers/net/wireless/b43/leds.c
drivers/net/wireless/b43/lo.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/pcmcia.c
drivers/net/wireless/b43/phy_a.c
drivers/net/wireless/b43/phy_common.c
drivers/net/wireless/b43/phy_g.c
drivers/net/wireless/b43/phy_lp.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/b43/pio.c
drivers/net/wireless/b43/rfkill.c
drivers/net/wireless/b43/sdio.c
drivers/net/wireless/b43/sysfs.c
drivers/net/wireless/b43/tables_lpphy.c
drivers/net/wireless/b43/wa.c
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/iwlegacy/iwl-4965-lib.c
drivers/net/wireless/iwlegacy/iwl-4965.c
drivers/net/wireless/iwlegacy/iwl-core.c
drivers/net/wireless/iwlegacy/iwl-core.h
drivers/net/wireless/iwlegacy/iwl-dev.h
drivers/net/wireless/iwlegacy/iwl4965-base.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-2000.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-calib.c
drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
drivers/net/wireless/iwlwifi/iwl-agn-sta.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-devtrace.h
drivers/net/wireless/iwlwifi/iwl-eeprom.c
drivers/net/wireless/iwlwifi/iwl-hcmd.c
drivers/net/wireless/iwlwifi/iwl-led.c
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl-sv-open.c
drivers/net/wireless/iwlwifi/iwl-testmode.h
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwmc3200wifi/rx.c
drivers/net/wireless/libertas/cmd.c
drivers/net/wireless/libertas/if_cs.c
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/mwifiex/11n_aggr.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/sdio.h
drivers/net/wireless/mwifiex/txrx.c
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/orinoco/orinoco_cs.c
drivers/net/wireless/orinoco/spectrum_cs.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/ray_cs.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/Kconfig
drivers/net/wireless/rt2x00/rt2x00config.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/ps.c
drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
drivers/net/wireless/rtlwifi/rtl8192ce/phy.h
drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
drivers/net/wireless/wl12xx/conf.h
drivers/net/wireless/wl12xx/main.c
drivers/net/wireless/wl12xx/scan.c
drivers/net/wireless/wl12xx/scan.h
drivers/net/wireless/wl3501_cs.c
drivers/net/wireless/zd1211rw/zd_usb.c
drivers/net/xen-netfront.c
drivers/of/fdt.c
drivers/oprofile/buffer_sync.c
drivers/oprofile/event_buffer.h
drivers/oprofile/oprof.c
drivers/parport/parport_cs.c
drivers/parport/parport_ip32.c
drivers/pci/Makefile
drivers/pci/dmar.c
drivers/pci/intel-iommu.c
drivers/pci/iova.c
drivers/pci/pci-acpi.c
drivers/pci/pci-driver.c
drivers/pci/pci.c
drivers/pci/probe.c
drivers/pcmcia/ds.c
drivers/pcmcia/pxa2xx_vpac270.c
drivers/pcmcia/sa1100_generic.c
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/acerhdf.c
drivers/platform/x86/asus-laptop.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/asus_acpi.c
drivers/platform/x86/compal-laptop.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/dell-wmi-aio.c
drivers/platform/x86/dell-wmi.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/eeepc-wmi.c
drivers/platform/x86/fujitsu-laptop.c
drivers/platform/x86/hdaps.c
drivers/platform/x86/hp-wmi.c
drivers/platform/x86/ibm_rtl.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel_ips.c
drivers/platform/x86/intel_menlow.c
drivers/platform/x86/intel_mid_powerbtn.c
drivers/platform/x86/intel_mid_thermal.c
drivers/platform/x86/intel_oaktrail.c [new file with mode: 0644]
drivers/platform/x86/intel_pmic_gpio.c
drivers/platform/x86/msi-laptop.c
drivers/platform/x86/msi-wmi.c
drivers/platform/x86/mxm-wmi.c [new file with mode: 0644]
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/tc1100-wmi.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/topstar-laptop.c
drivers/platform/x86/toshiba_acpi.c
drivers/platform/x86/toshiba_bluetooth.c
drivers/platform/x86/wmi.c
drivers/platform/x86/xo15-ebook.c
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/bq27x00_battery.c
drivers/power/ds2760_battery.c
drivers/power/ds2780_battery.c [new file with mode: 0644]
drivers/power/gpio-charger.c
drivers/power/isp1704_charger.c
drivers/power/max8903_charger.c [new file with mode: 0644]
drivers/power/max8925_power.c
drivers/power/test_power.c
drivers/power/z2_battery.c
drivers/ptp/Kconfig [new file with mode: 0644]
drivers/ptp/Makefile [new file with mode: 0644]
drivers/ptp/ptp_chardev.c [new file with mode: 0644]
drivers/ptp/ptp_clock.c [new file with mode: 0644]
drivers/ptp/ptp_ixp46x.c [new file with mode: 0644]
drivers/ptp/ptp_private.h [new file with mode: 0644]
drivers/ptp/ptp_sysfs.c [new file with mode: 0644]
drivers/regulator/88pm8607.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/ab3100.c
drivers/regulator/core.c
drivers/regulator/db8500-prcmu.c [new file with mode: 0644]
drivers/regulator/max8925-regulator.c
drivers/regulator/max8997.c
drivers/regulator/max8998.c
drivers/regulator/mc13783-regulator.c
drivers/regulator/mc13892-regulator.c
drivers/regulator/mc13xxx-regulator-core.c
drivers/regulator/tps6105x-regulator.c
drivers/regulator/tps65023-regulator.c
drivers/regulator/tps6507x-regulator.c
drivers/regulator/tps65910-regulator.c [new file with mode: 0644]
drivers/regulator/twl-regulator.c
drivers/regulator/wm831x-dcdc.c
drivers/regulator/wm8400-regulator.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/interface.c
drivers/rtc/rtc-88pm860x.c [new file with mode: 0644]
drivers/rtc/rtc-dev.c
drivers/rtc/rtc-em3027.c [new file with mode: 0644]
drivers/rtc/rtc-m41t93.c [new file with mode: 0644]
drivers/rtc/rtc-mrst.c
drivers/rtc/rtc-mxc.c
drivers/rtc/rtc-pcf50633.c
drivers/rtc/rtc-puv3.c [moved from arch/unicore32/kernel/rtc.c with 98% similarity]
drivers/rtc/rtc-rv3029c2.c [new file with mode: 0644]
drivers/rtc/rtc-spear.c [new file with mode: 0644]
drivers/rtc/rtc-tile.c [new file with mode: 0644]
drivers/rtc/rtc-vt8500.c [new file with mode: 0644]
drivers/s390/block/dasd_alias.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/char/Kconfig
drivers/s390/char/Makefile
drivers/s390/char/monwriter.c
drivers/s390/char/raw3270.c
drivers/s390/char/sclp.c
drivers/s390/char/sclp.h
drivers/s390/char/sclp_config.c
drivers/s390/char/sclp_ocf.c [new file with mode: 0644]
drivers/s390/char/sclp_sdias.c
drivers/s390/char/sclp_tty.c
drivers/s390/char/tape_3590.c
drivers/s390/char/tape_block.c [deleted file]
drivers/s390/char/tape_std.c
drivers/s390/cio/chsc.c
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_ops.c
drivers/s390/cio/qdio_main.c
drivers/s390/crypto/ap_bus.c
drivers/s390/kvm/kvm_virtio.c
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_qdio.c
drivers/s390/scsi/zfcp_qdio.h
drivers/scsi/aacraid/linit.c
drivers/scsi/aic94xx/aic94xx_init.c
drivers/scsi/bfa/bfa_ioc.c
drivers/scsi/bfa/bfa_ioc.h
drivers/scsi/bfa/bfa_ioc_cb.c
drivers/scsi/bfa/bfa_ioc_ct.c
drivers/scsi/bnx2i/bnx2i.h
drivers/scsi/bnx2i/bnx2i_hwi.c
drivers/scsi/bnx2i/bnx2i_init.c
drivers/scsi/bnx2i/bnx2i_iscsi.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/fcoe/fcoe.h
drivers/scsi/fcoe/fcoe_ctlr.c
drivers/scsi/fcoe/fcoe_transport.c
drivers/scsi/in2000.c
drivers/scsi/ipr.c
drivers/scsi/libfc/fc_disc.c
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libfc/fc_fcp.c
drivers/scsi/libfc/fc_libfc.h
drivers/scsi/libsas/sas_ata.c
drivers/scsi/libsas/sas_internal.h
drivers/scsi/libsas/sas_phy.c
drivers/scsi/libsas/sas_port.c
drivers/scsi/libsas/sas_scsi_host.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_bsg.c
drivers/scsi/lpfc/lpfc_bsg.h
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_debugfs.c
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_hw4.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_mem.c
drivers/scsi/lpfc/lpfc_nportdisc.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h
drivers/scsi/lpfc/lpfc_sli4.h
drivers/scsi/lpfc/lpfc_vport.c
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_fusion.c
drivers/scsi/mpt2sas/mpt2sas_base.h
drivers/scsi/mpt2sas/mpt2sas_scsih.c
drivers/scsi/osst.c
drivers/scsi/pcmcia/aha152x_stub.c
drivers/scsi/pcmcia/fdomain_stub.c
drivers/scsi/pcmcia/nsp_cs.c
drivers/scsi/pcmcia/qlogic_stub.c
drivers/scsi/pcmcia/sym53c500_cs.c
drivers/scsi/pmcraid.c
drivers/scsi/pmcraid.h
drivers/scsi/qla4xxx/Makefile
drivers/scsi/qla4xxx/ql4_attr.c [new file with mode: 0644]
drivers/scsi/qla4xxx/ql4_def.h
drivers/scsi/qla4xxx/ql4_fw.h
drivers/scsi/qla4xxx/ql4_glbl.h
drivers/scsi/qla4xxx/ql4_init.c
drivers/scsi/qla4xxx/ql4_isr.c
drivers/scsi/qla4xxx/ql4_mbx.c
drivers/scsi/qla4xxx/ql4_nx.c
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/qla4xxx/ql4_version.h
drivers/scsi/scsi_error.c
drivers/scsi/scsi_proc.c
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_trace.c
drivers/scsi/sd.c
drivers/scsi/sr.c
drivers/scsi/ultrastor.c
drivers/scsi/wd33c93.c
drivers/sh/clk/core.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/amba-pl022.c
drivers/spi/coldfire_qspi.c
drivers/spi/dw_spi.c
drivers/spi/dw_spi.h
drivers/spi/omap2_mcspi.c
drivers/spi/spi.c
drivers/spi/spi_bfin5xx.c
drivers/spi/spi_bfin_sport.c [new file with mode: 0644]
drivers/spi/spi_nuc900.c
drivers/spi/spi_s3c24xx.c
drivers/spi/spi_sh.c
drivers/spi/spi_tegra.c
drivers/spi/tle62x0.c
drivers/spi/xilinx_spi.c
drivers/ssb/driver_pcicore.c
drivers/staging/Kconfig
drivers/staging/altera-stapl/altera-jtag.c
drivers/staging/altera-stapl/altera.c
drivers/staging/altera-stapl/altera.h [moved from include/staging/altera.h with 100% similarity]
drivers/staging/ath6kl/Kconfig
drivers/staging/ath6kl/os/linux/cfg80211.c
drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
drivers/staging/brcm80211/brcmfmac/wl_iw.c
drivers/staging/comedi/drivers/cb_das16_cs.c
drivers/staging/comedi/drivers/das08_cs.c
drivers/staging/comedi/drivers/ni_daq_700.c
drivers/staging/comedi/drivers/ni_daq_dio24.c
drivers/staging/comedi/drivers/ni_labpc_cs.c
drivers/staging/comedi/drivers/ni_mio_cs.c
drivers/staging/comedi/drivers/quatech_daqp_cs.c
drivers/staging/ft1000/ft1000-pcmcia/ft1000_cs.c
drivers/staging/generic_serial/rio/rioinit.c
drivers/staging/gma500/psb_drv.c
drivers/staging/gma500/psb_fb.c
drivers/staging/gma500/psb_intel_bios.c
drivers/staging/iio/accel/adis16201.h
drivers/staging/iio/accel/adis16203.h
drivers/staging/iio/dac/max517.c
drivers/staging/iio/imu/adis16400_ring.c
drivers/staging/iio/industrialio-trigger.c
drivers/staging/mei/init.c
drivers/staging/olpc_dcon/Kconfig
drivers/staging/rts_pstor/sd.c
drivers/staging/usbip/stub_dev.c
drivers/staging/usbip/stub_rx.c
drivers/staging/wlags49_h2/wl_cs.c
drivers/staging/wlan-ng/cfg80211.c
drivers/staging/zcache/zcache.c
drivers/target/loopback/tcm_loop.c
drivers/target/target_core_configfs.c
drivers/target/target_core_device.c
drivers/target/target_core_pr.c
drivers/target/target_core_pscsi.c
drivers/target/target_core_tmr.c
drivers/target/target_core_transport.c
drivers/target/tcm_fc/tcm_fc.h
drivers/target/tcm_fc/tfc_cmd.c
drivers/target/tcm_fc/tfc_conf.c
drivers/target/tcm_fc/tfc_io.c
drivers/target/tcm_fc/tfc_sess.c
drivers/telephony/ixj_pcmcia.c
drivers/thermal/thermal_sys.c
drivers/tty/cyclades.c
drivers/tty/ipwireless/main.c
drivers/tty/n_gsm.c
drivers/tty/n_hdlc.c
drivers/tty/n_r3964.c
drivers/tty/n_tty.c
drivers/tty/nozomi.c
drivers/tty/serial/68328serial.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/m32r_sio.c
drivers/tty/serial/mrst_max3110.c
drivers/tty/serial/pch_uart.c
drivers/tty/serial/serial_cs.c
drivers/tty/tty_buffer.c
drivers/tty/vt/selection.c
drivers/usb/class/cdc-acm.c
drivers/usb/core/driver.c
drivers/usb/core/hub.c
drivers/usb/core/inode.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/amd5536udc.c
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/dummy_hcd.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/mv_udc_core.c
drivers/usb/gadget/net2280.c
drivers/usb/gadget/pxa25x_udc.c
drivers/usb/gadget/s3c-hsotg.c
drivers/usb/gadget/s3c-hsudc.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ohci-pxa27x.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/pci-quirks.h
drivers/usb/host/sl811_cs.c
drivers/usb/host/xhci-dbg.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/musb/musb_core.c
drivers/usb/otg/twl6030-usb.c
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/option.c
drivers/usb/storage/transport.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
drivers/usb/storage/usb.h
drivers/vhost/net.c
drivers/vhost/test.c
drivers/vhost/vhost.c
drivers/vhost/vhost.h
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/amifb.c
drivers/video/arcfb.c
drivers/video/aty/atyfb_base.c
drivers/video/backlight/88pm860x_bl.c
drivers/video/backlight/Kconfig
drivers/video/backlight/Makefile
drivers/video/backlight/adp5520_bl.c
drivers/video/backlight/adp8870_bl.c [new file with mode: 0644]
drivers/video/bf537-lq035.c
drivers/video/broadsheetfb.c
drivers/video/da8xx-fb.c
drivers/video/efifb.c
drivers/video/hecubafb.c
drivers/video/imxfb.c
drivers/video/mb862xx/Makefile
drivers/video/mb862xx/mb862xx-i2c.c [new file with mode: 0644]
drivers/video/mb862xx/mb862xx_reg.h
drivers/video/mb862xx/mb862xxfb.h
drivers/video/mb862xx/mb862xxfbdrv.c [moved from drivers/video/mb862xx/mb862xxfb.c with 86% similarity]
drivers/video/metronomefb.c
drivers/video/modedb.c
drivers/video/omap/Makefile
drivers/video/omap/dispc.c
drivers/video/omap/lcd_omap2evm.c [deleted file]
drivers/video/omap/omapfb_main.c
drivers/video/omap/rfbi.c
drivers/video/omap2/Makefile
drivers/video/omap2/displays/Kconfig
drivers/video/omap2/displays/panel-acx565akm.c
drivers/video/omap2/displays/panel-generic-dpi.c
drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
drivers/video/omap2/displays/panel-taal.c
drivers/video/omap2/displays/panel-tpo-td043mtea1.c
drivers/video/omap2/dss/Kconfig
drivers/video/omap2/dss/core.c
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/dispc.h [new file with mode: 0644]
drivers/video/omap2/dss/display.c
drivers/video/omap2/dss/dpi.c
drivers/video/omap2/dss/dsi.c
drivers/video/omap2/dss/dss.c
drivers/video/omap2/dss/dss.h
drivers/video/omap2/dss/dss_features.c
drivers/video/omap2/dss/dss_features.h
drivers/video/omap2/dss/hdmi.c
drivers/video/omap2/dss/hdmi.h
drivers/video/omap2/dss/hdmi_omap4_panel.c
drivers/video/omap2/dss/manager.c
drivers/video/omap2/dss/overlay.c
drivers/video/omap2/dss/rfbi.c
drivers/video/omap2/dss/sdi.c
drivers/video/omap2/dss/venc.c
drivers/video/omap2/omapfb/omapfb-ioctl.c
drivers/video/omap2/omapfb/omapfb-main.c
drivers/video/omap2/omapfb/omapfb-sysfs.c
drivers/video/omap2/omapfb/omapfb.h
drivers/video/pxa168fb.c
drivers/video/s3c-fb.c
drivers/video/s3c2410fb.c
drivers/video/s3fb.c
drivers/video/savage/savagefb-i2c.c
drivers/video/savage/savagefb.h
drivers/video/savage/savagefb_driver.c
drivers/video/sh7760fb.c
drivers/video/sh_mobile_hdmi.c
drivers/video/sh_mobile_lcdcfb.c
drivers/video/sh_mobile_lcdcfb.h
drivers/video/sh_mobile_meram.c [new file with mode: 0644]
drivers/video/sh_mobile_meram.h [new file with mode: 0644]
drivers/video/sm501fb.c
drivers/video/tmiofb.c
drivers/video/udlfb.c
drivers/video/vga16fb.c
drivers/video/via/via-gpio.c
drivers/video/xen-fbfront.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_ring.c
drivers/w1/masters/Kconfig
drivers/w1/masters/ds1wm.c
drivers/w1/slaves/Kconfig
drivers/w1/slaves/Makefile
drivers/w1/slaves/w1_ds2408.c [new file with mode: 0644]
drivers/w1/slaves/w1_ds2780.c [new file with mode: 0644]
drivers/w1/slaves/w1_ds2780.h [new file with mode: 0644]
drivers/w1/w1.c
drivers/w1/w1.h
drivers/w1/w1_family.h
drivers/w1/w1_io.c
drivers/w1/w1_netlink.c
drivers/watchdog/rdc321x_wdt.c
drivers/xen/Makefile
drivers/xen/events.c
drivers/xen/swiotlb-xen.c
drivers/xen/tmem.c [new file with mode: 0644]
fs/9p/Kconfig
fs/9p/vfs_inode_dotl.c
fs/Kconfig
fs/afs/dir.c
fs/afs/fsclient.c
fs/afs/inode.c
fs/afs/super.c
fs/afs/write.c
fs/attr.c
fs/bad_inode.c
fs/binfmt_flat.c
fs/bio.c
fs/block_dev.c
fs/btrfs/Makefile
fs/btrfs/acl.c
fs/btrfs/btrfs_inode.h
fs/btrfs/compression.c
fs/btrfs/compression.h
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/delayed-inode.c [new file with mode: 0644]
fs/btrfs/delayed-inode.h [new file with mode: 0644]
fs/btrfs/delayed-ref.c
fs/btrfs/delayed-ref.h
fs/btrfs/dir-item.c
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/export.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/extent_map.c
fs/btrfs/extent_map.h
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/free-space-cache.h
fs/btrfs/inode-item.c
fs/btrfs/inode-map.c
fs/btrfs/inode-map.h [new file with mode: 0644]
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/ioctl.h
fs/btrfs/locking.c
fs/btrfs/locking.h
fs/btrfs/ref-cache.c
fs/btrfs/ref-cache.h
fs/btrfs/relocation.c
fs/btrfs/root-tree.c
fs/btrfs/scrub.c [new file with mode: 0644]
fs/btrfs/super.c
fs/btrfs/sysfs.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-defrag.c
fs/btrfs/tree-log.c
fs/btrfs/tree-log.h
fs/btrfs/version.sh [deleted file]
fs/btrfs/volumes.c
fs/btrfs/volumes.h
fs/btrfs/xattr.c
fs/buffer.c
fs/ceph/addr.c
fs/ceph/caps.c
fs/ceph/dir.c
fs/ceph/export.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/ioctl.c
fs/ceph/locks.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h
fs/ceph/snap.c
fs/ceph/xattr.c
fs/cifs/Kconfig
fs/cifs/README
fs/cifs/cache.c
fs/cifs/cifs_debug.c
fs/cifs/cifs_dfs_ref.c
fs/cifs/cifs_fs_sb.h
fs/cifs/cifs_spnego.c
fs/cifs/cifs_spnego.h
fs/cifs/cifsacl.c
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/fscache.c
fs/cifs/fscache.h
fs/cifs/inode.c
fs/cifs/ioctl.c
fs/cifs/link.c
fs/cifs/misc.c
fs/cifs/netmisc.c
fs/cifs/readdir.c
fs/cifs/sess.c
fs/cifs/smbencrypt.c
fs/cifs/transport.c
fs/cifs/xattr.c
fs/coda/pioctl.c
fs/dcache.c
fs/dcookies.c
fs/dlm/config.c
fs/dlm/config.h
fs/dlm/dlm_internal.h
fs/dlm/lock.c
fs/dlm/lock.h
fs/dlm/lockspace.c
fs/dlm/main.c
fs/dlm/plock.c
fs/dlm/user.c
fs/drop_caches.c
fs/ecryptfs/crypto.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/file.c
fs/ecryptfs/inode.c
fs/ecryptfs/keystore.c
fs/ecryptfs/main.c
fs/ecryptfs/super.c
fs/exec.c
fs/ext2/super.c
fs/ext3/inode.c
fs/ext3/namei.c
fs/ext3/super.c
fs/ext4/Makefile
fs/ext4/balloc.c
fs/ext4/ext4.h
fs/ext4/ext4_extents.h
fs/ext4/ext4_jbd2.c
fs/ext4/ext4_jbd2.h
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/fsync.c
fs/ext4/inode.c
fs/ext4/mballoc.c
fs/ext4/mballoc.h
fs/ext4/migrate.c
fs/ext4/mmp.c [new file with mode: 0644]
fs/ext4/move_extent.c
fs/ext4/namei.c
fs/ext4/page-io.c
fs/ext4/super.c
fs/ext4/xattr.c
fs/fat/file.c
fs/fs-writeback.c
fs/fscache/operation.c
fs/fscache/page.c
fs/fuse/dir.c
fs/fuse/inode.c
fs/gfs2/glock.c
fs/gfs2/main.c
fs/gfs2/quota.c
fs/gfs2/quota.h
fs/hpfs/namei.c
fs/hugetlbfs/inode.c
fs/inode.c
fs/isofs/inode.c
fs/jbd/commit.c
fs/jbd/journal.c
fs/jbd/transaction.c
fs/jbd2/checkpoint.c
fs/jbd2/commit.c
fs/jbd2/journal.c
fs/jbd2/transaction.c
fs/jffs2/dir.c
fs/jffs2/fs.c
fs/jffs2/os-linux.h
fs/jffs2/scan.c
fs/jfs/file.c
fs/jfs/inode.c
fs/jfs/jfs_imap.c
fs/jfs/jfs_incore.h
fs/jfs/jfs_inode.h
fs/jfs/jfs_logmgr.c
fs/jfs/resize.c
fs/lockd/clntproc.c
fs/logfs/dir.c
fs/mbcache.c
fs/mpage.c
fs/namei.c
fs/namespace.c
fs/ncpfs/dir.c
fs/ncpfs/inode.c
fs/ncpfs/mmap.c
fs/nfs/Kconfig
fs/nfs/Makefile
fs/nfs/callback.h
fs/nfs/callback_proc.c
fs/nfs/callback_xdr.c
fs/nfs/client.c
fs/nfs/delegation.c
fs/nfs/dir.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4filelayout.h
fs/nfs/nfs4filelayoutdev.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfs/nfsroot.c
fs/nfs/objlayout/Kbuild [new file with mode: 0644]
fs/nfs/objlayout/objio_osd.c [new file with mode: 0644]
fs/nfs/objlayout/objlayout.c [new file with mode: 0644]
fs/nfs/objlayout/objlayout.h [new file with mode: 0644]
fs/nfs/objlayout/pnfs_osd_xdr_cli.c [new file with mode: 0644]
fs/nfs/pagelist.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/nfs/pnfs_dev.c [new file with mode: 0644]
fs/nfs/read.c
fs/nfs/super.c
fs/nfs/write.c
fs/nfsd/Kconfig
fs/nfsd/export.c
fs/nfsd/nfs3proc.c
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/nfsfh.c
fs/nfsd/vfs.c
fs/nfsd/vfs.h
fs/nilfs2/btree.c
fs/nilfs2/inode.c
fs/nilfs2/nilfs.h
fs/nilfs2/segment.c
fs/ocfs2/Makefile
fs/ocfs2/alloc.c
fs/ocfs2/alloc.h
fs/ocfs2/cluster/sys.c
fs/ocfs2/dlm/dlmcommon.h
fs/ocfs2/dlm/dlmdebug.c
fs/ocfs2/dlm/dlmdomain.c
fs/ocfs2/dlm/dlmmaster.c
fs/ocfs2/dlm/dlmrecovery.c
fs/ocfs2/dlmfs/dlmfs.c
fs/ocfs2/file.c
fs/ocfs2/ioctl.c
fs/ocfs2/move_extents.c [new file with mode: 0644]
fs/ocfs2/move_extents.h [new file with mode: 0644]
fs/ocfs2/ocfs2_ioctl.h
fs/ocfs2/ocfs2_trace.h
fs/ocfs2/refcounttree.c
fs/ocfs2/refcounttree.h
fs/ocfs2/super.c
fs/omfs/dir.c
fs/omfs/file.c
fs/partitions/efi.c
fs/proc/Makefile
fs/proc/array.c
fs/proc/base.c
fs/proc/generic.c
fs/proc/inode.c
fs/proc/internal.h
fs/proc/namespaces.c [new file with mode: 0644]
fs/proc/proc_sysctl.c
fs/proc/root.c
fs/proc/stat.c
fs/proc/task_mmu.c
fs/proc/vmcore.c
fs/quota/dquot.c
fs/reiserfs/super.c
fs/reiserfs/xattr.c
fs/splice.c
fs/squashfs/block.c
fs/squashfs/cache.c
fs/squashfs/decompressor.c
fs/squashfs/decompressor.h
fs/squashfs/dir.c
fs/squashfs/export.c
fs/squashfs/file.c
fs/squashfs/fragment.c
fs/squashfs/id.c
fs/squashfs/inode.c
fs/squashfs/namei.c
fs/squashfs/squashfs.h
fs/squashfs/squashfs_fs.h
fs/squashfs/squashfs_fs_i.h
fs/squashfs/squashfs_fs_sb.h
fs/squashfs/super.c
fs/squashfs/symlink.c
fs/squashfs/xattr.c
fs/squashfs/xattr.h
fs/squashfs/xattr_id.c
fs/squashfs/xz_wrapper.c
fs/squashfs/zlib_wrapper.c
fs/super.c
fs/sysfs/mount.c
fs/sysfs/sysfs.h
fs/timerfd.c
fs/ubifs/budget.c
fs/ubifs/commit.c
fs/ubifs/debug.c
fs/ubifs/debug.h
fs/ubifs/dir.c
fs/ubifs/file.c
fs/ubifs/find.c
fs/ubifs/gc.c
fs/ubifs/io.c
fs/ubifs/journal.c
fs/ubifs/log.c
fs/ubifs/lprops.c
fs/ubifs/lpt_commit.c
fs/ubifs/master.c
fs/ubifs/misc.h
fs/ubifs/orphan.c
fs/ubifs/recovery.c
fs/ubifs/replay.c
fs/ubifs/sb.c
fs/ubifs/shrinker.c
fs/ubifs/super.c
fs/ubifs/tnc.c
fs/ubifs/tnc_commit.c
fs/ubifs/ubifs-media.h
fs/ubifs/ubifs.h
fs/ubifs/xattr.c
fs/ufs/balloc.c
fs/ufs/truncate.c
fs/xattr.c
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_discard.c
fs/xfs/linux-2.6/xfs_discard.h
fs/xfs/linux-2.6/xfs_file.c
fs/xfs/linux-2.6/xfs_iops.c
fs/xfs/linux-2.6/xfs_super.c
fs/xfs/linux-2.6/xfs_sync.c
fs/xfs/quota/xfs_qm.c
fs/xfs/xfs_ag.h
fs/xfs/xfs_alloc.c
fs/xfs/xfs_alloc.h
fs/xfs/xfs_alloc_btree.c
fs/xfs/xfs_attr.c
fs/xfs/xfs_bmap.c
fs/xfs/xfs_bmap.h
fs/xfs/xfs_iget.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_log.c
fs/xfs/xfs_log_cil.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_trans.c
fs/xfs/xfs_vnodeops.c
include/acpi/acpiosxf.h
include/acpi/acpixf.h
include/acpi/actypes.h
include/acpi/processor.h
include/asm-generic/audit_change_attr.h
include/asm-generic/audit_dir_write.h
include/asm-generic/audit_read.h
include/asm-generic/audit_write.h
include/asm-generic/bitops/find.h
include/asm-generic/bitops/le.h
include/asm-generic/bug.h
include/asm-generic/cacheflush.h
include/asm-generic/gpio.h
include/asm-generic/pgtable.h
include/asm-generic/ptrace.h [new file with mode: 0644]
include/asm-generic/resource.h
include/asm-generic/tlb.h
include/asm-generic/unistd.h
include/asm-generic/vmlinux.lds.h
include/drm/drmP.h
include/drm/drm_crtc.h
include/drm/drm_dp_helper.h
include/drm/drm_edid.h
include/drm/drm_fb_helper.h
include/drm/drm_pciids.h
include/linux/Kbuild
include/linux/acpi.h
include/linux/atomic.h
include/linux/basic_mmio_gpio.h
include/linux/bitmap.h
include/linux/bitops.h
include/linux/blk_types.h
include/linux/blkdev.h
include/linux/blktrace_api.h
include/linux/bootmem.h
include/linux/buffer_head.h
include/linux/c2port.h
include/linux/capability.h
include/linux/ceph/ceph_fs.h
include/linux/cgroup.h
include/linux/cgroup_subsys.h
include/linux/cleancache.h [new file with mode: 0644]
include/linux/clocksource.h
include/linux/compat.h
include/linux/compiler-gcc.h
include/linux/compiler-gcc4.h
include/linux/cpumask.h
include/linux/cpuset.h
include/linux/crash_dump.h
include/linux/cred.h
include/linux/device-mapper.h
include/linux/device.h
include/linux/device_cgroup.h
include/linux/dlm_plock.h
include/linux/dm-io.h
include/linux/dm-kcopyd.h
include/linux/dma_remapping.h
include/linux/drbd.h
include/linux/drbd_tag_magic.h
include/linux/dw_dmac.h
include/linux/efi.h
include/linux/ethtool.h
include/linux/ext3_fs.h
include/linux/flex_array.h
include/linux/fs.h
include/linux/fscache-cache.h
include/linux/ftrace_event.h
include/linux/genalloc.h
include/linux/genhd.h
include/linux/gfp.h
include/linux/gpio.h
include/linux/gpio_keys.h
include/linux/huge_mm.h
include/linux/hugetlb.h
include/linux/hugetlb_inline.h
include/linux/i2c.h
include/linux/i2c/adp8870.h [new file with mode: 0644]
include/linux/i2c/i2c-sh_mobile.h [new file with mode: 0644]
include/linux/i2c/mpr121_touchkey.h [new file with mode: 0644]
include/linux/i2c/tsc2007.h
include/linux/i2c/twl.h
include/linux/ieee80211.h
include/linux/if_ether.h
include/linux/if_link.h
include/linux/if_packet.h
include/linux/if_vlan.h
include/linux/init_task.h
include/linux/input/ad714x.h
include/linux/input/adp5589.h [new file with mode: 0644]
include/linux/input/pmic8xxx-keypad.h [new file with mode: 0644]
include/linux/input/pmic8xxx-pwrkey.h [new file with mode: 0644]
include/linux/input/sh_keysc.h
include/linux/interrupt.h
include/linux/ipmi_smi.h
include/linux/irqreturn.h
include/linux/jbd2.h
include/linux/kernel.h
include/linux/key.h
include/linux/kmod.h
include/linux/kmsg_dump.h
include/linux/kobject_ns.h
include/linux/leds-pca9532.h
include/linux/leds.h
include/linux/linkage.h
include/linux/lockdep.h
include/linux/lru_cache.h
include/linux/lsm_audit.h
include/linux/memblock.h
include/linux/memcontrol.h
include/linux/mempolicy.h
include/linux/mfd/88pm860x.h
include/linux/mfd/abx500.h
include/linux/mfd/asic3.h
include/linux/mfd/core.h
include/linux/mfd/db5500-prcmu.h [new file with mode: 0644]
include/linux/mfd/db8500-prcmu.h [new file with mode: 0644]
include/linux/mfd/max8997-private.h
include/linux/mfd/pm8xxx/core.h [new file with mode: 0644]
include/linux/mfd/pm8xxx/irq.h [new file with mode: 0644]
include/linux/mfd/pm8xxx/pm8921.h [new file with mode: 0644]
include/linux/mfd/tmio.h
include/linux/mfd/tps65910.h [new file with mode: 0644]
include/linux/mfd/twl4030-codec.h
include/linux/mfd/wm831x/core.h
include/linux/mfd/wm831x/pdata.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/mmc/Kbuild [new file with mode: 0644]
include/linux/mmc/card.h
include/linux/mmc/core.h
include/linux/mmc/host.h
include/linux/mmc/ioctl.h [new file with mode: 0644]
include/linux/mmc/mmc.h
include/linux/mmc/sd.h
include/linux/mmc/sdhci.h
include/linux/mmc/sh_mobile_sdhi.h
include/linux/mmu_notifier.h
include/linux/mmzone.h
include/linux/mtd/mtd.h
include/linux/mtd/nand.h
include/linux/mtd/partitions.h
include/linux/mtd/physmap.h
include/linux/mtd/ubi.h
include/linux/mutex.h
include/linux/mxm-wmi.h [new file with mode: 0644]
include/linux/net.h
include/linux/netdevice.h
include/linux/netfilter.h
include/linux/netfilter/ipset/ip_set_ahash.h
include/linux/netfilter/ipset/ip_set_timeout.h
include/linux/netfilter/nf_conntrack_common.h
include/linux/netlink.h
include/linux/nfs4.h
include/linux/nfs_page.h
include/linux/nfs_xdr.h
include/linux/nsproxy.h
include/linux/oom.h
include/linux/page-flags.h
include/linux/pagemap.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/percpu.h
include/linux/percpu_counter.h
include/linux/perf_event.h
include/linux/pid.h
include/linux/pm.h
include/linux/pm_qos_params.h
include/linux/pnfs_osd_xdr.h [new file with mode: 0644]
include/linux/posix-timers.h
include/linux/power/isp1704_charger.h [moved from arch/arm/mach-s5p6442/include/mach/dma.h with 67% similarity]
include/linux/power/max8903_charger.h [new file with mode: 0644]
include/linux/printk.h
include/linux/proc_fs.h
include/linux/ptp_classify.h
include/linux/ptp_clock.h [new file with mode: 0644]
include/linux/ptp_clock_kernel.h [new file with mode: 0644]
include/linux/ratelimit.h
include/linux/regulator/db8500-prcmu.h [new file with mode: 0644]
include/linux/regulator/machine.h
include/linux/rfkill-gpio.h [new file with mode: 0644]
include/linux/rmap.h
include/linux/rotary_encoder.h
include/linux/rtc.h
include/linux/sched.h
include/linux/seqlock.h
include/linux/shmem_fs.h
include/linux/skbuff.h
include/linux/smp.h
include/linux/spi/ads7846.h
include/linux/spi/spi.h
include/linux/sunrpc/gss_krb5_enctypes.h [new file with mode: 0644]
include/linux/sunrpc/msg_prot.h
include/linux/sunrpc/sched.h
include/linux/sunrpc/svcsock.h
include/linux/sunrpc/xdr.h
include/linux/sunrpc/xprt.h
include/linux/swap.h
include/linux/swiotlb.h
include/linux/syscalls.h
include/linux/sysfs.h
include/linux/topology.h
include/linux/tty_ldisc.h
include/linux/uaccess.h
include/linux/usb_usual.h
include/linux/uts.h
include/linux/virtio.h
include/linux/virtio_9p.h
include/linux/virtio_balloon.h
include/linux/virtio_blk.h
include/linux/virtio_config.h
include/linux/virtio_console.h
include/linux/virtio_ids.h
include/linux/virtio_net.h
include/linux/virtio_pci.h
include/linux/virtio_ring.h
include/linux/vm_event_item.h [new file with mode: 0644]
include/linux/vmstat.h
include/linux/xattr.h
include/media/m5mols.h [new file with mode: 0644]
include/media/v4l2-dev.h
include/media/videobuf-dvb.h
include/mtd/ubi-user.h
include/net/9p/9p.h
include/net/9p/client.h
include/net/9p/transport.h
include/net/cfg80211.h
include/net/dst.h
include/net/ip_vs.h
include/net/net_namespace.h
include/net/net_ratelimit.h [new file with mode: 0644]
include/net/netfilter/nf_conntrack.h
include/net/sctp/command.h
include/net/sctp/structs.h
include/pcmcia/ds.h
include/rdma/Kbuild
include/rdma/ib_user_cm.h
include/rdma/rdma_cm.h
include/rdma/rdma_netlink.h [new file with mode: 0644]
include/scsi/libsas.h
include/scsi/scsi_tcq.h
include/sound/soc.h
include/target/target_core_base.h
include/target/target_core_fabric_ops.h
include/target/target_core_transport.h
include/trace/events/btrfs.h
include/trace/events/ext4.h
include/trace/events/gpio.h [new file with mode: 0644]
include/trace/events/irq.h
include/trace/events/net.h
include/trace/events/vmscan.h
include/trace/ftrace.h
include/video/omap-panel-generic-dpi.h [moved from arch/arm/plat-omap/include/plat/panel-generic-dpi.h with 86% similarity]
include/video/omap-panel-nokia-dsi.h [moved from arch/arm/plat-omap/include/plat/nokia-dsi-panel.h with 65% similarity]
include/video/omapdss.h [moved from arch/arm/plat-omap/include/plat/display.h with 85% similarity]
include/video/sh_mobile_lcdc.h
include/video/sh_mobile_meram.h [new file with mode: 0644]
include/xen/interface/io/blkif.h
include/xen/interface/xen.h
init/Kconfig
init/calibrate.c
init/main.c
ipc/namespace.c
ipc/shm.c
kernel/Makefile
kernel/capability.c
kernel/cgroup.c
kernel/cgroup_freezer.c
kernel/compat.c
kernel/cpuset.c
kernel/cred.c
kernel/events/core.c
kernel/exit.c
kernel/fork.c
kernel/gcov/Kconfig
kernel/hrtimer.c
kernel/irq/handle.c
kernel/irq/irqdesc.c
kernel/irq/manage.c
kernel/irq/proc.c
kernel/irq/spurious.c
kernel/jump_label.c
kernel/kmod.c
kernel/kthread.c
kernel/lockdep.c
kernel/mutex.c
kernel/ns_cgroup.c [deleted file]
kernel/nsproxy.c
kernel/pm_qos_params.c
kernel/posix-timers.c
kernel/power/hibernate.c
kernel/power/user.c
kernel/printk.c
kernel/profile.c
kernel/ptrace.c
kernel/rcutree.c
kernel/rcutree.h
kernel/rcutree_plugin.h
kernel/rcutree_trace.c
kernel/sched.c
kernel/sched_fair.c
kernel/sched_rt.c
kernel/sched_stats.h
kernel/signal.c
kernel/smp.c
kernel/softirq.c
kernel/sysctl.c
kernel/time/alarmtimer.c
kernel/time/clockevents.c
kernel/time/clocksource.c
kernel/timer.c
kernel/trace/ftrace.c
kernel/trace/ring_buffer.c
kernel/trace/trace.h
kernel/trace/trace_events.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_output.c
kernel/trace/trace_printk.c
kernel/utsname.c
kernel/watchdog.c
kernel/workqueue.c
lib/Kconfig
lib/Kconfig.debug
lib/Makefile
lib/audit.c
lib/bitmap.c
lib/find_last_bit.c
lib/find_next_bit.c
lib/flex_array.c
lib/genalloc.c
lib/kobject.c
lib/kstrtox.c
lib/locking-selftest.c
lib/lru_cache.c
lib/show_mem.c
lib/swiotlb.c
lib/vsprintf.c
mm/Kconfig
mm/Makefile
mm/backing-dev.c
mm/cleancache.c [new file with mode: 0644]
mm/compaction.c
mm/filemap.c
mm/filemap_xip.c
mm/fremap.c
mm/huge_memory.c
mm/hugetlb.c
mm/init-mm.c
mm/internal.h
mm/ksm.c
mm/maccess.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/migrate.c
mm/mlock.c
mm/mmap.c
mm/mremap.c
mm/nobootmem.c
mm/nommu.c
mm/oom_kill.c
mm/page_alloc.c
mm/page_cgroup.c
mm/percpu.c
mm/readahead.c
mm/rmap.c
mm/shmem.c
mm/slab.c
mm/slub.c
mm/swap.c
mm/swapfile.c
mm/thrash.c
mm/truncate.c
mm/util.c
mm/vmalloc.c
mm/vmscan.c
mm/vmstat.c
net/802/psnap.c
net/8021q/vlan.c
net/8021q/vlan.h
net/8021q/vlan_core.c
net/8021q/vlan_dev.c
net/9p/Kconfig
net/9p/client.c
net/9p/mod.c
net/9p/trans_fd.c
net/9p/trans_rdma.c
net/9p/util.c
net/atm/atm_sysfs.c
net/atm/lec.c
net/atm/mpc.c
net/atm/proc.c
net/bluetooth/hci_event.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/sco.c
net/bridge/br_device.c
net/bridge/br_multicast.c
net/bridge/br_netfilter.c
net/bridge/netfilter/ebtables.c
net/caif/cfmuxl.c
net/caif/chnl_net.c
net/can/bcm.c
net/can/proc.c
net/ceph/messenger.c
net/ceph/osd_client.c
net/ceph/osdmap.c
net/core/dev.c
net/core/dst.c
net/core/ethtool.c
net/core/fib_rules.c
net/core/filter.c
net/core/net-sysfs.c
net/core/net_namespace.c
net/core/netpoll.c
net/core/rtnetlink.c
net/core/sysctl_net_core.c
net/core/utils.c
net/dns_resolver/dns_key.c
net/ieee802154/nl-phy.c
net/ipv4/af_inet.c
net/ipv4/igmp.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_diag.c
net/ipv4/inetpeer.c
net/ipv4/ip_options.c
net/ipv4/ip_output.c
net/ipv4/netfilter/ip_queue.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/ipt_CLUSTERIP.c
net/ipv4/netfilter/ipt_MASQUERADE.c
net/ipv4/netfilter/ipt_ecn.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
net/ipv4/netfilter/nf_conntrack_proto_icmp.c
net/ipv4/netfilter/nf_nat_core.c
net/ipv4/netfilter/nf_nat_helper.c
net/ipv4/netfilter/nf_nat_rule.c
net/ipv4/netfilter/nf_nat_standalone.c
net/ipv4/ping.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/tcp_ipv4.c
net/ipv4/udp.c
net/ipv6/af_inet6.c
net/ipv6/netfilter/ip6_queue.c
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
net/ipv6/raw.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/xfrm6_tunnel.c
net/irda/iriap.c
net/iucv/iucv.c
net/key/af_key.c
net/l2tp/l2tp_debugfs.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/main.c
net/mac80211/mesh.h
net/mac80211/mesh_pathtbl.c
net/mac80211/mlme.c
net/mac80211/scan.c
net/mac80211/tx.c
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipset/ip_set_hash_ipportnet.c
net/netfilter/ipset/ip_set_hash_net.c
net/netfilter/ipset/ip_set_hash_netport.c
net/netfilter/ipvs/ip_vs_conn.c
net/netfilter/ipvs/ip_vs_core.c
net/netfilter/ipvs/ip_vs_ftp.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_ftp.c
net/netfilter/nf_conntrack_h323_main.c
net/netfilter/nf_conntrack_irc.c
net/netfilter/nf_conntrack_pptp.c
net/netfilter/nf_conntrack_sane.c
net/netfilter/nf_conntrack_sip.c
net/netfilter/nfnetlink_log.c
net/netfilter/nfnetlink_queue.c
net/netfilter/xt_socket.c
net/netlink/af_netlink.c
net/packet/af_packet.c
net/phonet/socket.c
net/rds/ib.c
net/rds/ib_cm.c
net/rds/iw.c
net/rds/iw_cm.c
net/rds/rdma_transport.c
net/rfkill/Kconfig
net/rfkill/Makefile
net/rfkill/rfkill-gpio.c [new file with mode: 0644]
net/sched/sch_generic.c
net/sched/sch_sfq.c
net/sctp/associola.c
net/sctp/proc.c
net/sctp/sm_sideeffect.c
net/sctp/sm_statefuns.c
net/sunrpc/auth.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/auth_gss/gss_krb5_mech.c
net/sunrpc/clnt.c
net/sunrpc/rpcb_clnt.c
net/sunrpc/sched.c
net/sunrpc/svc.c
net/sunrpc/svcsock.c
net/sunrpc/xdr.c
net/sunrpc/xprtrdma/svc_rdma_transport.c
net/sunrpc/xprtrdma/verbs.c
net/sunrpc/xprtsock.c
net/unix/af_unix.c
net/wireless/core.h
net/wireless/nl80211.c
net/wireless/scan.c
net/wireless/sme.c
net/wireless/util.c
net/xfrm/xfrm_replay.c
scripts/.gitignore
scripts/Kbuild.include
scripts/Makefile
scripts/Makefile.asm-generic [new file with mode: 0644]
scripts/Makefile.build
scripts/Makefile.headersinst
scripts/Makefile.lib
scripts/basic/.gitignore
scripts/basic/Makefile
scripts/checkpatch.pl
scripts/checkversion.pl
scripts/depmod.sh [new file with mode: 0755]
scripts/docproc.c [moved from scripts/basic/docproc.c with 100% similarity]
scripts/export_report.pl
scripts/gen_initramfs_list.sh
scripts/kallsyms.c
scripts/kconfig/Makefile
scripts/kconfig/confdata.c
scripts/kconfig/expr.h
scripts/kconfig/gconf.c
scripts/kconfig/lex.zconf.c_shipped
scripts/kconfig/nconf.c
scripts/kconfig/qconf.cc
scripts/kconfig/zconf.l
scripts/mkcompile_h
scripts/package/Makefile
scripts/package/mkspec
scripts/patch-kernel
scripts/recordmcount.h
scripts/selinux/README
scripts/tags.sh
security/Kconfig
security/apparmor/lsm.c
security/apparmor/match.c
security/apparmor/policy_unpack.c
security/commoncap.c
security/device_cgroup.c
security/keys/encrypted.c
security/keys/internal.h
security/keys/keyctl.c
security/keys/keyring.c
security/keys/proc.c
security/keys/process_keys.c
security/keys/request_key.c
security/keys/request_key_auth.c
security/keys/trusted.c
security/keys/user_defined.c
security/lsm_audit.c
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/include/security.h
security/selinux/netnode.c
security/selinux/selinuxfs.c
security/selinux/ss/policydb.c
security/selinux/ss/policydb.h
security/selinux/ss/services.c
security/smack/smack.h
security/smack/smack_lsm.c
security/tomoyo/common.c
security/tomoyo/file.c
security/tomoyo/memory.c
security/tomoyo/mount.c
security/tomoyo/util.c
sound/core/control.c
sound/core/init.c
sound/core/misc.c
sound/core/oss/linear.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/core/seq/seq_queue.c
sound/firewire/isight.c
sound/pci/asihpi/asihpi.c
sound/pci/asihpi/hpidspcd.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/fm801.c
sound/pci/hda/hda_beep.h
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_eld.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_via.c
sound/pci/lola/lola.c
sound/pci/rme9652/hdspm.c
sound/pcmcia/pdaudiocf/pdaudiocf.c
sound/pcmcia/vx/vxpocket.c
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/blackfin/bf5xx-ad1836.c
sound/soc/codecs/ad1836.c
sound/soc/codecs/ad1836.h
sound/soc/codecs/cq93vc.c
sound/soc/codecs/cx20442.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/wl1273.c
sound/soc/codecs/wm1250-ev1.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8915.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8991.c
sound/soc/codecs/wm_hubs.c
sound/soc/davinci/davinci-vcif.c
sound/soc/fsl/fsl_dma.c
sound/soc/imx/Kconfig
sound/soc/imx/imx-pcm-dma-mx2.c
sound/soc/imx/imx-ssi.c
sound/soc/omap/Kconfig
sound/soc/omap/Makefile
sound/soc/omap/omap2evm.c [deleted file]
sound/soc/pxa/pxa2xx-pcm.c
sound/soc/pxa/raumfeld.c
sound/soc/samsung/Kconfig
sound/soc/samsung/i2s.c
sound/soc/samsung/smdk_wm8580.c
sound/soc/soc-cache.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/usb/6fire/firmware.c
sound/usb/6fire/pcm.c
sound/usb/card.c
sound/usb/mixer.c
sound/usb/mixer.h
sound/usb/mixer_quirks.c
sound/usb/quirks-table.h
sound/usb/quirks.c
sound/usb/usbaudio.h
tools/perf/Makefile
tools/perf/builtin-annotate.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-script.c
tools/perf/builtin-test.c
tools/perf/builtin-top.c
tools/perf/util/PERF-VERSION-GEN
tools/perf/util/event.c
tools/perf/util/event.h
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/header.c
tools/perf/util/include/linux/const.h [new file with mode: 0644]
tools/perf/util/python.c
tools/perf/util/session.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/trace-event-parse.c
tools/testing/ktest/ktest.pl
tools/virtio/virtio_test.c
usr/gen_init_cpio.c
virt/kvm/kvm_main.c

index 5d56a3fd0de6b9d4d8acc0a26495bd24c489d31f..9dacde0a4b2dcec4ce33013354b6c46738daaef7 100644 (file)
@@ -57,6 +57,7 @@ modules.builtin
 include/config
 include/linux/version.h
 include/generated
+arch/*/include/generated
 
 # stgit generated dirs
 patches-*
index 5a6dd592eedc888090d43bb8299b1ddc2143ce08..353ad5607156f0f2d4b5138f1b5d9db529933aa8 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -32,6 +32,7 @@ Brian Avery <b.avery@hp.com>
 Brian King <brking@us.ibm.com>
 Christoph Hellwig <hch@lst.de>
 Corey Minyard <minyard@acm.org>
+Damian Hobson-Garcia <dhobsong@igel.co.jp>
 David Brownell <david-b@pacbell.net>
 David Woodhouse <dwmw2@shinybook.infradead.org>
 Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
diff --git a/CREDITS b/CREDITS
index 95c469c610bc8a059b3bebac13fba37b98b544c1..d78359f5f64d7e581110166f9a2a7ecd410abc46 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -518,6 +518,14 @@ N: Zach Brown
 E: zab@zabbo.net
 D: maestro pci sound
 
+M: David Brownell
+D: Kernel engineer, mentor, and friend.  Maintained USB EHCI and
+D: gadget layers, SPI subsystem, GPIO subsystem, and more than a few
+D: device drivers.  His encouragement also helped many engineers get
+D: started working on the Linux kernel.  David passed away in early
+D: 2011, and will be greatly missed.
+W: https://lkml.org/lkml/2011/4/5/36
+
 N: Gary Brubaker
 E: xavyer@ix.netcom.com
 D: USB Serial Empeg Empeg-car Mark I/II Driver
@@ -2943,6 +2951,10 @@ S: Kasarmikatu 11 A4
 S: 70110 Kuopio
 S: Finland
 
+N: Tobias Ringström
+E: tori@unhappy.mine.nu
+D: Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver
+
 N: Luca Risolia
 E: luca.risolia@studio.unibo.it
 P: 1024D/FCE635A4 88E8 F32F 7244 68BA 3958  5D40 99DA 5D2A FCE6 35A4
@@ -3913,6 +3925,10 @@ S: Flandernstrasse 101
 S: D-73732 Esslingen
 S: Germany
 
+N: Roman Zippel
+E: zippel@linux-m68k.org
+D: AFFS and HFS filesystems, m68k maintainer, new kernel configuration in 2.5
+
 N: Leonard N. Zubkoff
 W: http://www.dandelion.com/Linux/
 D: BusLogic SCSI driver
index 1b777b9604921396c47497e4bf919adb3d51c0f4..1f89424c36a6036a9daecd3e0b2d0aca93bae3e9 100644 (file)
@@ -192,10 +192,6 @@ kernel-docs.txt
        - listing of various WWW + books that document kernel internals.
 kernel-parameters.txt
        - summary listing of command line / boot prompt args for the kernel.
-keys-request-key.txt
-       - description of the kernel key request service.
-keys.txt
-       - description of the kernel key retention service.
 kobject.txt
        - info of the kobject infrastructure of the Linux kernel.
 kprobes.txt
@@ -294,6 +290,8 @@ scheduler/
        - directory with info on the scheduler.
 scsi/
        - directory with info on Linux scsi support.
+security/
+       - directory that contains security-related info
 serial/
        - directory with info on the low level serial API.
 serial-console.txt
similarity index 65%
rename from Documentation/ABI/obsolete/o2cb
rename to Documentation/ABI/removed/o2cb
index 9c49d8e6c0ccbe5b49f222fd3f1eb98ce2b1b08e..7f5daa465093b898f123b67fb4bc8ab453ce9bc0 100644 (file)
@@ -1,11 +1,10 @@
 What:          /sys/o2cb symlink
-Date:          Dec 2005
-KernelVersion: 2.6.16
+Date:          May 2011
+KernelVersion: 2.6.40
 Contact:       ocfs2-devel@oss.oracle.com
-Description:   This is a symlink: /sys/o2cb to /sys/fs/o2cb. The symlink will
-               be removed when new versions of ocfs2-tools which know to look
+Description:   This is a symlink: /sys/o2cb to /sys/fs/o2cb. The symlink is
+               removed when new versions of ocfs2-tools which know to look
                in /sys/fs/o2cb are sufficiently prevalent. Don't code new
                software to look here, it should try /sys/fs/o2cb instead.
-               See Documentation/ABI/stable/o2cb for more information on usage.
 Users:         ocfs2-tools. It's sufficient to mail proposed changes to
                ocfs2-devel@oss.oracle.com.
index 4873c759d535a7549d5eecf62a7125b29d6c2dea..c1eb41cb9876083d3df79a6a995b692762acd21b 100644 (file)
@@ -142,3 +142,67 @@ Description:
                with the previous I/O request are enabled. When set to 2,
                all merge tries are disabled. The default value is 0 -
                which enables all types of merge tries.
+
+What:          /sys/block/<disk>/discard_alignment
+Date:          May 2011
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Devices that support discard functionality may
+               internally allocate space in units that are bigger than
+               the exported logical block size. The discard_alignment
+               parameter indicates how many bytes the beginning of the
+               device is offset from the internal allocation unit's
+               natural alignment.
+
+What:          /sys/block/<disk>/<partition>/discard_alignment
+Date:          May 2011
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Devices that support discard functionality may
+               internally allocate space in units that are bigger than
+               the exported logical block size. The discard_alignment
+               parameter indicates how many bytes the beginning of the
+               partition is offset from the internal allocation unit's
+               natural alignment.
+
+What:          /sys/block/<disk>/queue/discard_granularity
+Date:          May 2011
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Devices that support discard functionality may
+               internally allocate space using units that are bigger
+               than the logical block size. The discard_granularity
+               parameter indicates the size of the internal allocation
+               unit in bytes if reported by the device. Otherwise the
+               discard_granularity will be set to match the device's
+               physical block size. A discard_granularity of 0 means
+               that the device does not support discard functionality.
+
+What:          /sys/block/<disk>/queue/discard_max_bytes
+Date:          May 2011
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Devices that support discard functionality may have
+               internal limits on the number of bytes that can be
+               trimmed or unmapped in a single operation. Some storage
+               protocols also have inherent limits on the number of
+               blocks that can be described in a single command. The
+               discard_max_bytes parameter is set by the device driver
+               to the maximum number of bytes that can be discarded in
+               a single operation. Discard requests issued to the
+               device must not exceed this limit. A discard_max_bytes
+               value of 0 means that the device does not support
+               discard functionality.
+
+What:          /sys/block/<disk>/queue/discard_zeroes_data
+Date:          May 2011
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Devices that support discard functionality may return
+               stale or random data when a previously discarded block
+               is read back. This can cause problems if the filesystem
+               expects discarded blocks to be explicitly cleared. If a
+               device reports that it deterministically returns zeroes
+               when a discarded area is read the discard_zeroes_data
+               parameter will be set to one. Otherwise it will be 0 and
+               the result of reading a discarded area is undefined.
diff --git a/Documentation/ABI/testing/sysfs-class-backlight-driver-adp8870 b/Documentation/ABI/testing/sysfs-class-backlight-driver-adp8870
new file mode 100644 (file)
index 0000000..aa11dbd
--- /dev/null
@@ -0,0 +1,56 @@
+What:          /sys/class/backlight/<backlight>/<ambient light zone>_max
+What:          /sys/class/backlight/<backlight>/l1_daylight_max
+What:          /sys/class/backlight/<backlight>/l2_bright_max
+What:          /sys/class/backlight/<backlight>/l3_office_max
+What:          /sys/class/backlight/<backlight>/l4_indoor_max
+What:          /sys/class/backlight/<backlight>/l5_dark_max
+Date:          Mai 2011
+KernelVersion: 2.6.40
+Contact:       device-drivers-devel@blackfin.uclinux.org
+Description:
+               Control the maximum brightness for <ambient light zone>
+               on this <backlight>. Values are between 0 and 127. This file
+               will also show the brightness level stored for this
+               <ambient light zone>.
+
+What:          /sys/class/backlight/<backlight>/<ambient light zone>_dim
+What:          /sys/class/backlight/<backlight>/l2_bright_dim
+What:          /sys/class/backlight/<backlight>/l3_office_dim
+What:          /sys/class/backlight/<backlight>/l4_indoor_dim
+What:          /sys/class/backlight/<backlight>/l5_dark_dim
+Date:          Mai 2011
+KernelVersion: 2.6.40
+Contact:       device-drivers-devel@blackfin.uclinux.org
+Description:
+               Control the dim brightness for <ambient light zone>
+               on this <backlight>. Values are between 0 and 127, typically
+               set to 0. Full off when the backlight is disabled.
+               This file will also show the dim brightness level stored for
+               this <ambient light zone>.
+
+What:          /sys/class/backlight/<backlight>/ambient_light_level
+Date:          Mai 2011
+KernelVersion: 2.6.40
+Contact:       device-drivers-devel@blackfin.uclinux.org
+Description:
+               Get conversion value of the light sensor.
+               This value is updated every 80 ms (when the light sensor
+               is enabled). Returns integer between 0 (dark) and
+               8000 (max ambient brightness)
+
+What:          /sys/class/backlight/<backlight>/ambient_light_zone
+Date:          Mai 2011
+KernelVersion: 2.6.40
+Contact:       device-drivers-devel@blackfin.uclinux.org
+Description:
+               Get/Set current ambient light zone. Reading returns
+               integer between 1..5 (1 = daylight, 2 = bright, ..., 5 = dark).
+               Writing a value between 1..5 forces the backlight controller
+               to enter the corresponding ambient light zone.
+               Writing 0 returns to normal/automatic ambient light level
+               operation. The ambient light sensing feature on these devices
+               is an extension to the API documented in
+               Documentation/ABI/stable/sysfs-class-backlight.
+               It can be enabled by writing the value stored in
+               /sys/class/backlight/<backlight>/max_brightness to
+               /sys/class/backlight/<backlight>/brightness.
\ No newline at end of file
index c1b53b8bc2ae72703b4e3e72648c24e1ee92e2d0..65e6e5dd67e83a04cc0f8e93feffda8eb5c7be38 100644 (file)
@@ -92,6 +92,14 @@ Description: The mouse has a tracking- and a distance-control-unit. These
                This file is writeonly.
 Users:         http://roccat.sourceforge.net
 
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/talk
+Date:          May 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   Used to active some easy* functions of the mouse from outside.
+               The data has to be 16 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
 What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu
 Date:          October 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-wiimote b/Documentation/ABI/testing/sysfs-driver-hid-wiimote
new file mode 100644 (file)
index 0000000..5d5a16e
--- /dev/null
@@ -0,0 +1,10 @@
+What:          /sys/bus/hid/drivers/wiimote/<dev>/led1
+What:          /sys/bus/hid/drivers/wiimote/<dev>/led2
+What:          /sys/bus/hid/drivers/wiimote/<dev>/led3
+What:          /sys/bus/hid/drivers/wiimote/<dev>/led4
+Date:          July 2011
+KernelVersion: 3.1
+Contact:       David Herrmann <dh.herrmann@googlemail.com>
+Description:   Make it possible to set/get current led state. Reading from it
+               returns 0 if led is off and 1 if it is on. Writing 0 to it
+               disables the led, writing 1 enables it.
diff --git a/Documentation/ABI/testing/sysfs-kernel-mm-cleancache b/Documentation/ABI/testing/sysfs-kernel-mm-cleancache
new file mode 100644 (file)
index 0000000..662ae64
--- /dev/null
@@ -0,0 +1,11 @@
+What:          /sys/kernel/mm/cleancache/
+Date:          April 2011
+Contact:       Dan Magenheimer <dan.magenheimer@oracle.com>
+Description:
+               /sys/kernel/mm/cleancache/ contains a number of files which
+               record a count of various cleancache operations
+               (sum across all filesystems):
+                       succ_gets
+                       failed_gets
+                       puts
+                       flushes
diff --git a/Documentation/ABI/testing/sysfs-ptp b/Documentation/ABI/testing/sysfs-ptp
new file mode 100644 (file)
index 0000000..d40d2b5
--- /dev/null
@@ -0,0 +1,98 @@
+What:          /sys/class/ptp/
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This directory contains files and directories
+               providing a standardized interface to the ancillary
+               features of PTP hardware clocks.
+
+What:          /sys/class/ptp/ptpN/
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This directory contains the attributes of the Nth PTP
+               hardware clock registered into the PTP class driver
+               subsystem.
+
+What:          /sys/class/ptp/ptpN/clock_name
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This file contains the name of the PTP hardware clock
+               as a human readable string.
+
+What:          /sys/class/ptp/ptpN/max_adjustment
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This file contains the PTP hardware clock's maximum
+               frequency adjustment value (a positive integer) in
+               parts per billion.
+
+What:          /sys/class/ptp/ptpN/n_alarms
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This file contains the number of periodic or one shot
+               alarms offer by the PTP hardware clock.
+
+What:          /sys/class/ptp/ptpN/n_external_timestamps
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This file contains the number of external timestamp
+               channels offered by the PTP hardware clock.
+
+What:          /sys/class/ptp/ptpN/n_periodic_outputs
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This file contains the number of programmable periodic
+               output channels offered by the PTP hardware clock.
+
+What:          /sys/class/ptp/ptpN/pps_avaiable
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This file indicates whether the PTP hardware clock
+               supports a Pulse Per Second to the host CPU. Reading
+               "1" means that the PPS is supported, while "0" means
+               not supported.
+
+What:          /sys/class/ptp/ptpN/extts_enable
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This write-only file enables or disables external
+               timestamps. To enable external timestamps, write the
+               channel index followed by a "1" into the file.
+               To disable external timestamps, write the channel
+               index followed by a "0" into the file.
+
+What:          /sys/class/ptp/ptpN/fifo
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This file provides timestamps on external events, in
+               the form of three integers: channel index, seconds,
+               and nanoseconds.
+
+What:          /sys/class/ptp/ptpN/period
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This write-only file enables or disables periodic
+               outputs. To enable a periodic output, write five
+               integers into the file: channel index, start time
+               seconds, start time nanoseconds, period seconds, and
+               period nanoseconds. To disable a periodic output, set
+               all the seconds and nanoseconds values to zero.
+
+What:          /sys/class/ptp/ptpN/pps_enable
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This write-only file enables or disables delivery of
+               PPS events to the Linux PPS subsystem. To enable PPS
+               events, write a "1" into the file. To disable events,
+               write a "0" into the file.
index 8436b018c289cbc1c858dc8722d92a5f48389b5b..3cebfa0d161182bb562f349359b5676bb660dbd2 100644 (file)
@@ -73,7 +73,7 @@ installmandocs: mandocs
 ###
 #External programs used
 KERNELDOC = $(srctree)/scripts/kernel-doc
-DOCPROC   = $(objtree)/scripts/basic/docproc
+DOCPROC   = $(objtree)/scripts/docproc
 
 XMLTOFLAGS = -m $(srctree)/Documentation/DocBook/stylesheet.xsl
 XMLTOFLAGS += --skip-validation
index 52d5e3c7cf6c0dd96646b43c05aaa8d2dd97561b..b5365f61d69b05e8ee4b33e26857927d5fe6b6aa 100644 (file)
@@ -141,13 +141,15 @@ struct dtv_properties {
  </row></tbody></tgroup></informaltable>
 </section>
 
+<section>
+       <title>Property types</title>
 <para>
 On <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>/<link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
 the actual action is determined by the dtv_property cmd/data pairs. With one single ioctl, is possible to
 get/set up to 64 properties. The actual meaning of each property is described on the next sections.
 </para>
 
-<para>The Available frontend property types are:</para>
+<para>The available frontend property types are:</para>
 <programlisting>
 #define DTV_UNDEFINED          0
 #define DTV_TUNE               1
@@ -193,6 +195,7 @@ get/set up to 64 properties. The actual meaning of each property is described on
 #define DTV_ISDBT_LAYER_ENABLED        41
 #define DTV_ISDBS_TS_ID                42
 </programlisting>
+</section>
 
 <section id="fe_property_common">
        <title>Parameters that are common to all Digital TV standards</title>
index c8abb23ef1e7b063c8babd317e985fb0814db68c..e5fe09430fd905c19fa04f0d1d401f5f76bd9f2c 100644 (file)
 <!ENTITY sub-yuyv SYSTEM "v4l/pixfmt-yuyv.xml">
 <!ENTITY sub-yvyu SYSTEM "v4l/pixfmt-yvyu.xml">
 <!ENTITY sub-srggb10 SYSTEM "v4l/pixfmt-srggb10.xml">
+<!ENTITY sub-srggb12 SYSTEM "v4l/pixfmt-srggb12.xml">
 <!ENTITY sub-srggb8 SYSTEM "v4l/pixfmt-srggb8.xml">
 <!ENTITY sub-y10 SYSTEM "v4l/pixfmt-y10.xml">
 <!ENTITY sub-y12 SYSTEM "v4l/pixfmt-y12.xml">
 <!ENTITY sub-media-indices SYSTEM "media-indices.tmpl">
 
 <!ENTITY sub-media-controller SYSTEM "v4l/media-controller.xml">
-<!ENTITY sub-media-open SYSTEM "v4l/media-func-open.xml">
-<!ENTITY sub-media-close SYSTEM "v4l/media-func-close.xml">
-<!ENTITY sub-media-ioctl SYSTEM "v4l/media-func-ioctl.xml">
+<!ENTITY sub-media-func-open SYSTEM "v4l/media-func-open.xml">
+<!ENTITY sub-media-func-close SYSTEM "v4l/media-func-close.xml">
+<!ENTITY sub-media-func-ioctl SYSTEM "v4l/media-func-ioctl.xml">
 <!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
 <!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml">
 <!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml">
index 6f242d5dee9ad0942b26fc5f454b5be4e5a111fe..17910e2052addefcc2a581fa810991fde2545820 100644 (file)
@@ -189,8 +189,7 @@ static void __iomem *baseaddr;
                <title>Partition defines</title>
                <para>
                        If you want to divide your device into partitions, then
-                       enable the configuration switch CONFIG_MTD_PARTITIONS and define
-                       a partitioning scheme suitable to your board.
+                       define a partitioning scheme suitable to your board.
                </para>
                <programlisting>
 #define NUM_PARTITIONS 2
index 2dc25e1d4089f59aa1eedb061a2354ab06818d7b..873ac3a621f013a36148bcdf7f878e6a0bf419c2 100644 (file)
@@ -78,9 +78,9 @@
 <appendix id="media-user-func">
   <title>Function Reference</title>
   <!-- Keep this alphabetically sorted. -->
-  &sub-media-open;
-  &sub-media-close;
-  &sub-media-ioctl;
+  &sub-media-func-open;
+  &sub-media-func-close;
+  &sub-media-func-ioctl;
   <!-- All ioctls go here. -->
   &sub-media-ioc-device-info;
   &sub-media-ioc-enum-entities;
index dbfe3b08435f9a588c2de93a4e4fd4af202c7d82..deb660207f94700e04c1aa37106c8a567582b44d 100644 (file)
@@ -673,6 +673,7 @@ access the palette, this must be done with ioctls of the Linux framebuffer API.<
     &sub-srggb8;
     &sub-sbggr16;
     &sub-srggb10;
+    &sub-srggb12;
   </section>
 
   <section id="yuv-formats">
index a26b10c07857d215077b05d957633edcf1c034b6..8d3409d2c6320978186266c00518fc9e30dd888e 100644 (file)
        <constant>_JPEG</constant> prefix the format code is made of
        the following information.
        <itemizedlist>
-         <listitem>The number of bus samples per entropy encoded byte.</listitem>
-         <listitem>The bus width.</listitem>
+         <listitem><para>The number of bus samples per entropy encoded byte.</para></listitem>
+         <listitem><para>The bus width.</para></listitem>
        </itemizedlist>
+      </para>
 
-       <para>For instance, for a JPEG baseline process and an 8-bit bus width
-         the format will be named <constant>V4L2_MBUS_FMT_JPEG_1X8</constant>.
-       </para>
+      <para>For instance, for a JPEG baseline process and an 8-bit bus width
+        the format will be named <constant>V4L2_MBUS_FMT_JPEG_1X8</constant>.
       </para>
 
       <para>The following table lists existing JPEG compressed formats.</para>
index b4a615b78403a48f02252b90a41fabb1392fefe4..7890fae18529e3473700528a10f65d6ffd6f0533 100644 (file)
@@ -4,10 +4,11 @@ ChangeLog:
 
 SMP IRQ affinity
 
-/proc/irq/IRQ#/smp_affinity specifies which target CPUs are permitted
-for a given IRQ source. It's a bitmask of allowed CPUs. It's not allowed
-to turn off all CPUs, and if an IRQ controller does not support IRQ
-affinity then the value will not change from the default 0xffffffff.
+/proc/irq/IRQ#/smp_affinity and /proc/irq/IRQ#/smp_affinity_list specify
+which target CPUs are permitted for a given IRQ source.  It's a bitmask
+(smp_affinity) or cpu list (smp_affinity_list) of allowed CPUs.  It's not
+allowed to turn off all CPUs, and if an IRQ controller does not support
+IRQ affinity then the value will not change from the default of all cpus.
 
 /proc/irq/default_smp_affinity specifies default affinity mask that applies
 to all non-active IRQs. Once IRQ is allocated/activated its affinity bitmask
@@ -54,3 +55,11 @@ round-trip min/avg/max = 0.1/0.5/585.4 ms
 This time around IRQ44 was delivered only to the last four processors.
 i.e counters for the CPU0-3 did not change.
 
+Here is an example of limiting that same irq (44) to cpus 1024 to 1031:
+
+[root@moon 44]# echo 1024-1031 > smp_affinity
+[root@moon 44]# cat smp_affinity
+1024-1031
+
+Note that to do this with a bitmask would require 32 bitmasks of zero
+to follow the pertinent one.
index c078ad48f7a187aa8d76e9885d1776a46a4255e7..8173cec473aa0099a185d694bad1b1b6ee48743d 100644 (file)
@@ -99,18 +99,11 @@ o   "qp" indicates that RCU still expects a quiescent state from
 
 o      "dt" is the current value of the dyntick counter that is incremented
        when entering or leaving dynticks idle state, either by the
-       scheduler or by irq.  The number after the "/" is the interrupt
-       nesting depth when in dyntick-idle state, or one greater than
-       the interrupt-nesting depth otherwise.
-
-       This field is displayed only for CONFIG_NO_HZ kernels.
-
-o      "dn" is the current value of the dyntick counter that is incremented
-       when entering or leaving dynticks idle state via NMI.  If both
-       the "dt" and "dn" values are even, then this CPU is in dynticks
-       idle mode and may be ignored by RCU.  If either of these two
-       counters is odd, then RCU must be alert to the possibility of
-       an RCU read-side critical section running on this CPU.
+       scheduler or by irq.  This number is even if the CPU is in
+       dyntick idle mode and odd otherwise.  The number after the first
+       "/" is the interrupt nesting depth when in dyntick-idle state,
+       or one greater than the interrupt-nesting depth otherwise.
+       The number after the second "/" is the NMI nesting depth.
 
        This field is displayed only for CONFIG_NO_HZ kernels.
 
index eda40fd39cad9df7927e7409765007af38020219..d16a9849e60e127c2cd234cd02dcc9d6f16d35ec 100644 (file)
@@ -21,7 +21,7 @@ information will not be available.
 To extract cgroup statistics a utility very similar to getdelays.c
 has been developed, the sample output of the utility is shown below
 
-~/balbir/cgroupstats # ./getdelays  -C "/cgroup/a"
+~/balbir/cgroupstats # ./getdelays  -C "/sys/fs/cgroup/a"
 sleeping 1, blocked 0, running 1, stopped 0, uninterruptible 0
-~/balbir/cgroupstats # ./getdelays  -C "/cgroup"
+~/balbir/cgroupstats # ./getdelays  -C "/sys/fs/cgroup"
 sleeping 155, blocked 0, running 1, stopped 0, uninterruptible 2
index e9c77788a39d8f2c5c807b59295be6c3f1b3fea6..f6318f6d7bafcdbcceee0f6eb89edc4af26b287b 100644 (file)
@@ -177,6 +177,8 @@ static int get_family_id(int sd)
        rc = send_cmd(sd, GENL_ID_CTRL, getpid(), CTRL_CMD_GETFAMILY,
                        CTRL_ATTR_FAMILY_NAME, (void *)name,
                        strlen(TASKSTATS_GENL_NAME)+1);
+       if (rc < 0)
+               return 0;       /* sendto() failure? */
 
        rep_len = recv(sd, &ans, sizeof(ans), 0);
        if (ans.n.nlmsg_type == NLMSG_ERROR ||
@@ -191,30 +193,37 @@ static int get_family_id(int sd)
        return id;
 }
 
+#define average_ms(t, c) (t / 1000000ULL / (c ? c : 1))
+
 static void print_delayacct(struct taskstats *t)
 {
-       printf("\n\nCPU   %15s%15s%15s%15s\n"
-              "      %15llu%15llu%15llu%15llu\n"
-              "IO    %15s%15s\n"
-              "      %15llu%15llu\n"
-              "SWAP  %15s%15s\n"
-              "      %15llu%15llu\n"
-              "RECLAIM  %12s%15s\n"
-              "      %15llu%15llu\n",
-              "count", "real total", "virtual total", "delay total",
+       printf("\n\nCPU   %15s%15s%15s%15s%15s\n"
+              "      %15llu%15llu%15llu%15llu%15.3fms\n"
+              "IO    %15s%15s%15s\n"
+              "      %15llu%15llu%15llums\n"
+              "SWAP  %15s%15s%15s\n"
+              "      %15llu%15llu%15llums\n"
+              "RECLAIM  %12s%15s%15s\n"
+              "      %15llu%15llu%15llums\n",
+              "count", "real total", "virtual total",
+              "delay total", "delay average",
               (unsigned long long)t->cpu_count,
               (unsigned long long)t->cpu_run_real_total,
               (unsigned long long)t->cpu_run_virtual_total,
               (unsigned long long)t->cpu_delay_total,
-              "count", "delay total",
+              average_ms((double)t->cpu_delay_total, t->cpu_count),
+              "count", "delay total", "delay average",
               (unsigned long long)t->blkio_count,
               (unsigned long long)t->blkio_delay_total,
-              "count", "delay total",
+              average_ms(t->blkio_delay_total, t->blkio_count),
+              "count", "delay total", "delay average",
               (unsigned long long)t->swapin_count,
               (unsigned long long)t->swapin_delay_total,
-              "count", "delay total",
+              average_ms(t->swapin_delay_total, t->swapin_count),
+              "count", "delay total", "delay average",
               (unsigned long long)t->freepages_count,
-              (unsigned long long)t->freepages_delay_total);
+              (unsigned long long)t->freepages_delay_total,
+              average_ms(t->freepages_delay_total, t->freepages_count));
 }
 
 static void task_context_switch_counts(struct taskstats *t)
@@ -433,8 +442,6 @@ int main(int argc, char *argv[])
        }
 
        do {
-               int i;
-
                rep_len = recv(nl_sd, &msg, sizeof(msg), 0);
                PRINTF("received %d bytes\n", rep_len);
 
@@ -459,7 +466,6 @@ int main(int argc, char *argv[])
 
                na = (struct nlattr *) GENLMSG_DATA(&msg);
                len = 0;
-               i = 0;
                while (len < rep_len) {
                        len += NLA_ALIGN(na->nla_len);
                        switch (na->nla_type) {
index 3e1d25aee3fb2037b34af127214a1652691fa2f2..5f55373dd53bac20ec24554144fb81dd18e1d64d 100644 (file)
@@ -66,3 +66,8 @@ Note: We can use a kernel with multiple custom ACPI method running,
       But each individual write to debugfs can implement a SINGLE
       method override. i.e. if we want to insert/override multiple
       ACPI methods, we need to redo step c) ~ g) for multiple times.
+
+Note: Be aware that root can mis-use this driver to modify arbitrary
+      memory and gain additional rights, if root's privileges got
+      restricted (for example if root is not allowed to load additional
+      modules after boot).
index 76850295af8f93b0627f8a220f90ee8c6a677e92..4e686a2ed91e48b6f2e0d968f8f1352fe907b2cc 100644 (file)
@@ -65,13 +65,19 @@ looks at the connected hardware is beyond the scope of this document.
 The boot loader must ultimately be able to provide a MACH_TYPE_xxx
 value to the kernel. (see linux/arch/arm/tools/mach-types).
 
-
-4. Setup the kernel tagged list
--------------------------------
+4. Setup boot data
+------------------
 
 Existing boot loaders:         OPTIONAL, HIGHLY RECOMMENDED
 New boot loaders:              MANDATORY
 
+The boot loader must provide either a tagged list or a dtb image for
+passing configuration data to the kernel.  The physical address of the
+boot data is passed to the kernel in register r2.
+
+4a. Setup the kernel tagged list
+--------------------------------
+
 The boot loader must create and initialise the kernel tagged list.
 A valid tagged list starts with ATAG_CORE and ends with ATAG_NONE.
 The ATAG_CORE tag may or may not be empty.  An empty ATAG_CORE tag
@@ -101,6 +107,24 @@ The tagged list must be placed in a region of memory where neither
 the kernel decompressor nor initrd 'bootp' program will overwrite
 it.  The recommended placement is in the first 16KiB of RAM.
 
+4b. Setup the device tree
+-------------------------
+
+The boot loader must load a device tree image (dtb) into system ram
+at a 64bit aligned address and initialize it with the boot data.  The
+dtb format is documented in Documentation/devicetree/booting-without-of.txt.
+The kernel will look for the dtb magic value of 0xd00dfeed at the dtb
+physical address to determine if a dtb has been passed instead of a
+tagged list.
+
+The boot loader must pass at a minimum the size and location of the
+system memory, and the root filesystem location.  The dtb must be
+placed in a region of memory where the kernel decompressor will not
+overwrite it.  The recommended placement is in the first 16KiB of RAM
+with the caveat that it may not be located at physical address 0 since
+the kernel interprets a value of 0 in r2 to mean neither a tagged list
+nor a dtb were passed.
+
 5. Calling the kernel image
 ---------------------------
 
@@ -125,7 +149,8 @@ In either case, the following conditions must be met:
 - CPU register settings
   r0 = 0,
   r1 = machine type number discovered in (3) above.
-  r2 = physical address of tagged list in system RAM.
+  r2 = physical address of tagged list in system RAM, or
+       physical address of device tree block (dtb) in system RAM
 
 - CPU mode
   All forms of interrupts must be disabled (IRQs and FIQs)
index c3094ea51aa758745d7c9bcf9661164d0ecbac6f..658abb258cefab1e8d5a1e9f0003b904a69e8b7b 100644 (file)
@@ -14,7 +14,6 @@ Introduction
   - S3C24XX: See Documentation/arm/Samsung-S3C24XX/Overview.txt for full list
   - S3C64XX: S3C6400 and S3C6410
   - S5P6440
-  - S5P6442
   - S5PC100
   - S5PC110 / S5PV210
 
@@ -36,7 +35,6 @@ Configuration
   unifying all the SoCs into one kernel.
 
   s5p6440_defconfig - S5P6440 specific default configuration
-  s5p6442_defconfig - S5P6442 specific default configuration
   s5pc100_defconfig - S5PC100 specific default configuration
   s5pc110_defconfig - S5PC110 specific default configuration
   s5pv210_defconfig - S5PV210 specific default configuration
index ac4d47187122f93fc860db817a9d8970bbc80002..3bd585b449270afe15e8a439cef612a0a696ddef 100644 (file)
@@ -12,7 +12,7 @@ Also, it should be made opaque such that any kind of cast to a normal
 C integer type will fail.  Something like the following should
 suffice:
 
-       typedef struct { volatile int counter; } atomic_t;
+       typedef struct { int counter; } atomic_t;
 
 Historically, counter has been declared volatile.  This is now discouraged.
 See Documentation/volatile-considered-harmful.txt for the complete rationale.
index 89698e8df7d46deb7e2b5332dd8199606073b15c..c00c6a5ab21f6b0d253bf465eb6e1274d5994d18 100644 (file)
@@ -169,3 +169,18 @@ is issued which positions the tape to a known position.  Typically you
 must rewind the tape (by issuing "mt -f /dev/st0 rewind" for example)
 before i/o can proceed again to a tape drive which was reset.
 
+There is a cciss_tape_cmds module parameter which can be used to make cciss
+allocate more commands for use by tape drives.  Ordinarily only a few commands
+(6) are allocated for tape drives because tape drives are slow and
+infrequently used and the primary purpose of Smart Array controllers is to
+act as a RAID controller for disk drives, so the vast majority of commands
+are allocated for disk devices.  However, if you have more than a few tape
+drives attached to a smart array, the default number of commands may not be
+enought (for example, if you have 8 tape drives, you could only rewind 6
+at one time with the default number of commands.)  The cciss_tape_cmds module
+parameter allows more commands (up to 16 more) to be allocated for use by
+tape drives.  For example:
+
+        insmod cciss.ko cciss_tape_cmds=16
+
+Or, as a kernel boot parameter passed in via grub:  cciss.cciss_tape_cmds=8
index 9164ae3b83bcc6b466ffe25cf97093b72684a944..9b728dc17535f6f8c1630fe2e8f3a96e997feac9 100644 (file)
@@ -16,7 +16,7 @@ on all processors in the system.  Don't let this scare you into
 thinking SMP cache/tlb flushing must be so inefficient, this is in
 fact an area where many optimizations are possible.  For example,
 if it can be proven that a user address space has never executed
-on a cpu (see vma->cpu_vm_mask), one need not perform a flush
+on a cpu (see mm_cpumask()), one need not perform a flush
 for this address space on that cpu.
 
 First, the TLB flushing interfaces, since they are the simplest.  The
index 465351d4cf853e8a308c9c84abef789b3dcfa42c..cd45c8ea7463f71eccee9d82ce6a82b47bcee467 100644 (file)
@@ -28,16 +28,19 @@ cgroups. Here is what you can do.
 - Enable group scheduling in CFQ
        CONFIG_CFQ_GROUP_IOSCHED=y
 
-- Compile and boot into kernel and mount IO controller (blkio).
+- Compile and boot into kernel and mount IO controller (blkio); see
+  cgroups.txt, Why are cgroups needed?.
 
-       mount -t cgroup -o blkio none /cgroup
+       mount -t tmpfs cgroup_root /sys/fs/cgroup
+       mkdir /sys/fs/cgroup/blkio
+       mount -t cgroup -o blkio none /sys/fs/cgroup/blkio
 
 - Create two cgroups
-       mkdir -p /cgroup/test1/ /cgroup/test2
+       mkdir -p /sys/fs/cgroup/blkio/test1/ /sys/fs/cgroup/blkio/test2
 
 - Set weights of group test1 and test2
-       echo 1000 > /cgroup/test1/blkio.weight
-       echo 500 > /cgroup/test2/blkio.weight
+       echo 1000 > /sys/fs/cgroup/blkio/test1/blkio.weight
+       echo 500 > /sys/fs/cgroup/blkio/test2/blkio.weight
 
 - Create two same size files (say 512MB each) on same disk (file1, file2) and
   launch two dd threads in different cgroup to read those files.
@@ -46,12 +49,12 @@ cgroups. Here is what you can do.
        echo 3 > /proc/sys/vm/drop_caches
 
        dd if=/mnt/sdb/zerofile1 of=/dev/null &
-       echo $! > /cgroup/test1/tasks
-       cat /cgroup/test1/tasks
+       echo $! > /sys/fs/cgroup/blkio/test1/tasks
+       cat /sys/fs/cgroup/blkio/test1/tasks
 
        dd if=/mnt/sdb/zerofile2 of=/dev/null &
-       echo $! > /cgroup/test2/tasks
-       cat /cgroup/test2/tasks
+       echo $! > /sys/fs/cgroup/blkio/test2/tasks
+       cat /sys/fs/cgroup/blkio/test2/tasks
 
 - At macro level, first dd should finish first. To get more precise data, keep
   on looking at (with the help of script), at blkio.disk_time and
@@ -68,13 +71,13 @@ Throttling/Upper Limit policy
 - Enable throttling in block layer
        CONFIG_BLK_DEV_THROTTLING=y
 
-- Mount blkio controller
-        mount -t cgroup -o blkio none /cgroup/blkio
+- Mount blkio controller (see cgroups.txt, Why are cgroups needed?)
+        mount -t cgroup -o blkio none /sys/fs/cgroup/blkio
 
 - Specify a bandwidth rate on particular device for root group. The format
   for policy is "<major>:<minor>  <byes_per_second>".
 
-        echo "8:16  1048576" > /cgroup/blkio/blkio.read_bps_device
+        echo "8:16  1048576" > /sys/fs/cgroup/blkio/blkio.read_bps_device
 
   Above will put a limit of 1MB/second on reads happening for root group
   on device having major/minor number 8:16.
@@ -108,7 +111,7 @@ Hierarchical Cgroups
   CFQ and throttling will practically treat all groups at same level.
 
                                pivot
-                            /  |   \  \
+                            /  /   \  \
                        root  test1 test2  test3
 
   Down the line we can implement hierarchical accounting/control support
@@ -149,7 +152,7 @@ Proportional weight policy files
 
          Following is the format.
 
-         #echo dev_maj:dev_minor weight > /path/to/cgroup/blkio.weight_device
+         # echo dev_maj:dev_minor weight > blkio.weight_device
          Configure weight=300 on /dev/sdb (8:16) in this cgroup
          # echo 8:16 300 > blkio.weight_device
          # cat blkio.weight_device
index aedf1bd02fddd0a4427902e496949ba337423e3d..cd67e90003c0e547952de41086f01d59ecb9a493 100644 (file)
@@ -138,11 +138,11 @@ With the ability to classify tasks differently for different resources
 the admin can easily set up a script which receives exec notifications
 and depending on who is launching the browser he can
 
-       # echo browser_pid > /mnt/<restype>/<userclass>/tasks
+    # echo browser_pid > /sys/fs/cgroup/<restype>/<userclass>/tasks
 
 With only a single hierarchy, he now would potentially have to create
 a separate cgroup for every browser launched and associate it with
-approp network and other resource class.  This may lead to
+appropriate network and other resource class.  This may lead to
 proliferation of such cgroups.
 
 Also lets say that the administrator would like to give enhanced network
@@ -153,9 +153,9 @@ apps enhanced CPU power,
 With ability to write pids directly to resource classes, it's just a
 matter of :
 
-       # echo pid > /mnt/network/<new_class>/tasks
+       # echo pid > /sys/fs/cgroup/network/<new_class>/tasks
        (after some time)
-       # echo pid > /mnt/network/<orig_class>/tasks
+       # echo pid > /sys/fs/cgroup/network/<orig_class>/tasks
 
 Without this ability, he would have to split the cgroup into
 multiple separate ones and then associate the new cgroups with the
@@ -236,7 +236,8 @@ containing the following files describing that cgroup:
  - cgroup.procs: list of tgids in the cgroup.  This list is not
    guaranteed to be sorted or free of duplicate tgids, and userspace
    should sort/uniquify the list if this property is required.
-   This is a read-only file, for now.
+   Writing a thread group id into this file moves all threads in that
+   group into this cgroup.
  - notify_on_release flag: run the release agent on exit?
  - release_agent: the path to use for release notifications (this file
    exists in the top cgroup only)
@@ -309,21 +310,24 @@ subsystem, this is the case for the cpuset.
 To start a new job that is to be contained within a cgroup, using
 the "cpuset" cgroup subsystem, the steps are something like:
 
- 1) mkdir /dev/cgroup
- 2) mount -t cgroup -ocpuset cpuset /dev/cgroup
- 3) Create the new cgroup by doing mkdir's and write's (or echo's) in
-    the /dev/cgroup virtual file system.
- 4) Start a task that will be the "founding father" of the new job.
- 5) Attach that task to the new cgroup by writing its pid to the
-    /dev/cgroup tasks file for that cgroup.
- 6) fork, exec or clone the job tasks from this founding father task.
+ 1) mount -t tmpfs cgroup_root /sys/fs/cgroup
+ 2) mkdir /sys/fs/cgroup/cpuset
+ 3) mount -t cgroup -ocpuset cpuset /sys/fs/cgroup/cpuset
+ 4) Create the new cgroup by doing mkdir's and write's (or echo's) in
+    the /sys/fs/cgroup virtual file system.
+ 5) Start a task that will be the "founding father" of the new job.
+ 6) Attach that task to the new cgroup by writing its pid to the
+    /sys/fs/cgroup/cpuset/tasks file for that cgroup.
+ 7) fork, exec or clone the job tasks from this founding father task.
 
 For example, the following sequence of commands will setup a cgroup
 named "Charlie", containing just CPUs 2 and 3, and Memory Node 1,
 and then start a subshell 'sh' in that cgroup:
 
-  mount -t cgroup cpuset -ocpuset /dev/cgroup
-  cd /dev/cgroup
+  mount -t tmpfs cgroup_root /sys/fs/cgroup
+  mkdir /sys/fs/cgroup/cpuset
+  mount -t cgroup cpuset -ocpuset /sys/fs/cgroup/cpuset
+  cd /sys/fs/cgroup/cpuset
   mkdir Charlie
   cd Charlie
   /bin/echo 2-3 > cpuset.cpus
@@ -344,7 +348,7 @@ Creating, modifying, using the cgroups can be done through the cgroup
 virtual filesystem.
 
 To mount a cgroup hierarchy with all available subsystems, type:
-# mount -t cgroup xxx /dev/cgroup
+# mount -t cgroup xxx /sys/fs/cgroup
 
 The "xxx" is not interpreted by the cgroup code, but will appear in
 /proc/mounts so may be any useful identifying string that you like.
@@ -353,23 +357,32 @@ Note: Some subsystems do not work without some user input first.  For instance,
 if cpusets are enabled the user will have to populate the cpus and mems files
 for each new cgroup created before that group can be used.
 
+As explained in section `1.2 Why are cgroups needed?' you should create
+different hierarchies of cgroups for each single resource or group of
+resources you want to control. Therefore, you should mount a tmpfs on
+/sys/fs/cgroup and create directories for each cgroup resource or resource
+group.
+
+# mount -t tmpfs cgroup_root /sys/fs/cgroup
+# mkdir /sys/fs/cgroup/rg1
+
 To mount a cgroup hierarchy with just the cpuset and memory
 subsystems, type:
-# mount -t cgroup -o cpuset,memory hier1 /dev/cgroup
+# mount -t cgroup -o cpuset,memory hier1 /sys/fs/cgroup/rg1
 
 To change the set of subsystems bound to a mounted hierarchy, just
 remount with different options:
-# mount -o remount,cpuset,blkio hier1 /dev/cgroup
+# mount -o remount,cpuset,blkio hier1 /sys/fs/cgroup/rg1
 
 Now memory is removed from the hierarchy and blkio is added.
 
 Note this will add blkio to the hierarchy but won't remove memory or
 cpuset, because the new options are appended to the old ones:
-# mount -o remount,blkio /dev/cgroup
+# mount -o remount,blkio /sys/fs/cgroup/rg1
 
 To Specify a hierarchy's release_agent:
 # mount -t cgroup -o cpuset,release_agent="/sbin/cpuset_release_agent" \
-  xxx /dev/cgroup
+  xxx /sys/fs/cgroup/rg1
 
 Note that specifying 'release_agent' more than once will return failure.
 
@@ -378,17 +391,17 @@ when the hierarchy consists of a single (root) cgroup. Supporting
 the ability to arbitrarily bind/unbind subsystems from an existing
 cgroup hierarchy is intended to be implemented in the future.
 
-Then under /dev/cgroup you can find a tree that corresponds to the
-tree of the cgroups in the system. For instance, /dev/cgroup
+Then under /sys/fs/cgroup/rg1 you can find a tree that corresponds to the
+tree of the cgroups in the system. For instance, /sys/fs/cgroup/rg1
 is the cgroup that holds the whole system.
 
 If you want to change the value of release_agent:
-# echo "/sbin/new_release_agent" > /dev/cgroup/release_agent
+# echo "/sbin/new_release_agent" > /sys/fs/cgroup/rg1/release_agent
 
 It can also be changed via remount.
 
-If you want to create a new cgroup under /dev/cgroup:
-# cd /dev/cgroup
+If you want to create a new cgroup under /sys/fs/cgroup/rg1:
+# cd /sys/fs/cgroup/rg1
 # mkdir my_cgroup
 
 Now you want to do something with this cgroup.
@@ -430,6 +443,12 @@ You can attach the current shell task by echoing 0:
 
 # echo 0 > tasks
 
+You can use the cgroup.procs file instead of the tasks file to move all
+threads in a threadgroup at once. Echoing the pid of any task in a
+threadgroup to cgroup.procs causes all tasks in that threadgroup to be
+be attached to the cgroup. Writing 0 to cgroup.procs moves all tasks
+in the writing task's threadgroup.
+
 Note: Since every task is always a member of exactly one cgroup in each
 mounted hierarchy, to remove a task from its current cgroup you must
 move it into a new cgroup (possibly the root cgroup) by writing to the
@@ -575,7 +594,7 @@ rmdir() will fail with it. From this behavior, pre_destroy() can be
 called multiple times against a cgroup.
 
 int can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
-              struct task_struct *task, bool threadgroup)
+              struct task_struct *task)
 (cgroup_mutex held by caller)
 
 Called prior to moving a task into a cgroup; if the subsystem
@@ -584,9 +603,14 @@ task is passed, then a successful result indicates that *any*
 unspecified task can be moved into the cgroup. Note that this isn't
 called on a fork. If this method returns 0 (success) then this should
 remain valid while the caller holds cgroup_mutex and it is ensured that either
-attach() or cancel_attach() will be called in future. If threadgroup is
-true, then a successful result indicates that all threads in the given
-thread's threadgroup can be moved together.
+attach() or cancel_attach() will be called in future.
+
+int can_attach_task(struct cgroup *cgrp, struct task_struct *tsk);
+(cgroup_mutex held by caller)
+
+As can_attach, but for operations that must be run once per task to be
+attached (possibly many when using cgroup_attach_proc). Called after
+can_attach.
 
 void cancel_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
               struct task_struct *task, bool threadgroup)
@@ -598,15 +622,24 @@ function, so that the subsystem can implement a rollback. If not, not necessary.
 This will be called only about subsystems whose can_attach() operation have
 succeeded.
 
+void pre_attach(struct cgroup *cgrp);
+(cgroup_mutex held by caller)
+
+For any non-per-thread attachment work that needs to happen before
+attach_task. Needed by cpuset.
+
 void attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
-           struct cgroup *old_cgrp, struct task_struct *task,
-           bool threadgroup)
+           struct cgroup *old_cgrp, struct task_struct *task)
 (cgroup_mutex held by caller)
 
 Called after the task has been attached to the cgroup, to allow any
 post-attachment activity that requires memory allocations or blocking.
-If threadgroup is true, the subsystem should take care of all threads
-in the specified thread's threadgroup. Currently does not support any
+
+void attach_task(struct cgroup *cgrp, struct task_struct *tsk);
+(cgroup_mutex held by caller)
+
+As attach, but for operations that must be run once per task to be attached,
+like can_attach_task. Called before attach. Currently does not support any
 subsystem that might need the old_cgrp for every thread in the group.
 
 void fork(struct cgroup_subsy *ss, struct task_struct *task)
@@ -630,7 +663,7 @@ always handled well.
 void post_clone(struct cgroup_subsys *ss, struct cgroup *cgrp)
 (cgroup_mutex held by caller)
 
-Called at the end of cgroup_clone() to do any parameter
+Called during cgroup_create() to do any parameter
 initialization which might be required before a task could attach.  For
 example in cpusets, no task may attach before 'cpus' and 'mems' are set
 up.
index 8b930946c52a7dec05657470016946b1c3492123..9ad85df4b983e9da4ab967f098b39376c2ac0162 100644 (file)
@@ -10,26 +10,25 @@ directly present in its group.
 
 Accounting groups can be created by first mounting the cgroup filesystem.
 
-# mkdir /cgroups
-# mount -t cgroup -ocpuacct none /cgroups
-
-With the above step, the initial or the parent accounting group
-becomes visible at /cgroups. At bootup, this group includes all the
-tasks in the system. /cgroups/tasks lists the tasks in this cgroup.
-/cgroups/cpuacct.usage gives the CPU time (in nanoseconds) obtained by
-this group which is essentially the CPU time obtained by all the tasks
+# mount -t cgroup -ocpuacct none /sys/fs/cgroup
+
+With the above step, the initial or the parent accounting group becomes
+visible at /sys/fs/cgroup. At bootup, this group includes all the tasks in
+the system. /sys/fs/cgroup/tasks lists the tasks in this cgroup.
+/sys/fs/cgroup/cpuacct.usage gives the CPU time (in nanoseconds) obtained
+by this group which is essentially the CPU time obtained by all the tasks
 in the system.
 
-New accounting groups can be created under the parent group /cgroups.
+New accounting groups can be created under the parent group /sys/fs/cgroup.
 
-# cd /cgroups
+# cd /sys/fs/cgroup
 # mkdir g1
 # echo $$ > g1
 
 The above steps create a new group g1 and move the current shell
 process (bash) into it. CPU time consumed by this bash and its children
 can be obtained from g1/cpuacct.usage and the same is accumulated in
-/cgroups/cpuacct.usage also.
+/sys/fs/cgroup/cpuacct.usage also.
 
 cpuacct.stat file lists a few statistics which further divide the
 CPU time obtained by the cgroup into user and system times. Currently
index 98a30829af7a1bb1ce74015ef3fa7170a112af27..5b0d78e55cccc98b34989493e3bd40bda3f6fc41 100644 (file)
@@ -661,21 +661,21 @@ than stress the kernel.
 
 To start a new job that is to be contained within a cpuset, the steps are:
 
- 1) mkdir /dev/cpuset
- 2) mount -t cgroup -ocpuset cpuset /dev/cpuset
+ 1) mkdir /sys/fs/cgroup/cpuset
+ 2) mount -t cgroup -ocpuset cpuset /sys/fs/cgroup/cpuset
  3) Create the new cpuset by doing mkdir's and write's (or echo's) in
-    the /dev/cpuset virtual file system.
+    the /sys/fs/cgroup/cpuset virtual file system.
  4) Start a task that will be the "founding father" of the new job.
  5) Attach that task to the new cpuset by writing its pid to the
-    /dev/cpuset tasks file for that cpuset.
+    /sys/fs/cgroup/cpuset tasks file for that cpuset.
  6) fork, exec or clone the job tasks from this founding father task.
 
 For example, the following sequence of commands will setup a cpuset
 named "Charlie", containing just CPUs 2 and 3, and Memory Node 1,
 and then start a subshell 'sh' in that cpuset:
 
-  mount -t cgroup -ocpuset cpuset /dev/cpuset
-  cd /dev/cpuset
+  mount -t cgroup -ocpuset cpuset /sys/fs/cgroup/cpuset
+  cd /sys/fs/cgroup/cpuset
   mkdir Charlie
   cd Charlie
   /bin/echo 2-3 > cpuset.cpus
@@ -710,14 +710,14 @@ Creating, modifying, using the cpusets can be done through the cpuset
 virtual filesystem.
 
 To mount it, type:
-# mount -t cgroup -o cpuset cpuset /dev/cpuset
+# mount -t cgroup -o cpuset cpuset /sys/fs/cgroup/cpuset
 
-Then under /dev/cpuset you can find a tree that corresponds to the
-tree of the cpusets in the system. For instance, /dev/cpuset
+Then under /sys/fs/cgroup/cpuset you can find a tree that corresponds to the
+tree of the cpusets in the system. For instance, /sys/fs/cgroup/cpuset
 is the cpuset that holds the whole system.
 
-If you want to create a new cpuset under /dev/cpuset:
-# cd /dev/cpuset
+If you want to create a new cpuset under /sys/fs/cgroup/cpuset:
+# cd /sys/fs/cgroup/cpuset
 # mkdir my_cpuset
 
 Now you want to do something with this cpuset.
@@ -765,12 +765,12 @@ wrapper around the cgroup filesystem.
 
 The command
 
-mount -t cpuset X /dev/cpuset
+mount -t cpuset X /sys/fs/cgroup/cpuset
 
 is equivalent to
 
-mount -t cgroup -ocpuset,noprefix X /dev/cpuset
-echo "/sbin/cpuset_release_agent" > /dev/cpuset/release_agent
+mount -t cgroup -ocpuset,noprefix X /sys/fs/cgroup/cpuset
+echo "/sbin/cpuset_release_agent" > /sys/fs/cgroup/cpuset/release_agent
 
 2.2 Adding/removing cpus
 ------------------------
index 57ca4c89fe5c089aa6d8b9050fa5b2597e4f62b3..16624a7f82224d2f79d2a7aa2999ebe66c063baa 100644 (file)
@@ -22,16 +22,16 @@ removed from the child(ren).
 An entry is added using devices.allow, and removed using
 devices.deny.  For instance
 
-       echo 'c 1:3 mr' > /cgroups/1/devices.allow
+       echo 'c 1:3 mr' > /sys/fs/cgroup/1/devices.allow
 
 allows cgroup 1 to read and mknod the device usually known as
 /dev/null.  Doing
 
-       echo a > /cgroups/1/devices.deny
+       echo a > /sys/fs/cgroup/1/devices.deny
 
 will remove the default 'a *:* rwm' entry. Doing
 
-       echo a > /cgroups/1/devices.allow
+       echo a > /sys/fs/cgroup/1/devices.allow
 
 will add the 'a *:* rwm' entry to the whitelist.
 
index 41f37fea1276839b80cd4c220af27963f52c6a1d..c21d77742a0799424b09466857681ddcc7100f8b 100644 (file)
@@ -59,28 +59,28 @@ is non-freezable.
 
 * Examples of usage :
 
-   # mkdir /containers
-   # mount -t cgroup -ofreezer freezer  /containers
-   # mkdir /containers/0
-   # echo $some_pid > /containers/0/tasks
+   # mkdir /sys/fs/cgroup/freezer
+   # mount -t cgroup -ofreezer freezer /sys/fs/cgroup/freezer
+   # mkdir /sys/fs/cgroup/freezer/0
+   # echo $some_pid > /sys/fs/cgroup/freezer/0/tasks
 
 to get status of the freezer subsystem :
 
-   # cat /containers/0/freezer.state
+   # cat /sys/fs/cgroup/freezer/0/freezer.state
    THAWED
 
 to freeze all tasks in the container :
 
-   # echo FROZEN > /containers/0/freezer.state
-   # cat /containers/0/freezer.state
+   # echo FROZEN > /sys/fs/cgroup/freezer/0/freezer.state
+   # cat /sys/fs/cgroup/freezer/0/freezer.state
    FREEZING
-   # cat /containers/0/freezer.state
+   # cat /sys/fs/cgroup/freezer/0/freezer.state
    FROZEN
 
 to unfreeze all tasks in the container :
 
-   # echo THAWED > /containers/0/freezer.state
-   # cat /containers/0/freezer.state
+   # echo THAWED > /sys/fs/cgroup/freezer/0/freezer.state
+   # cat /sys/fs/cgroup/freezer/0/freezer.state
    THAWED
 
 This is the basic mechanism which should do the right thing for user space task
index 7c163477fcd8f001fb217cc66e4c67812af907a7..06eb6d957c83097b85fd15e87e94b8ed7edfe1cf 100644 (file)
@@ -1,8 +1,8 @@
 Memory Resource Controller
 
-NOTE: The Memory Resource Controller has been generically been referred
-      to as the memory controller in this document. Do not confuse memory
-      controller used here with the memory controller that is used in hardware.
+NOTE: The Memory Resource Controller has generically been referred to as the
+      memory controller in this document. Do not confuse memory controller
+      used here with the memory controller that is used in hardware.
 
 (For editors)
 In this document:
@@ -70,6 +70,7 @@ Brief summary of control files.
                                 (See sysctl's vm.swappiness)
  memory.move_charge_at_immigrate # set/show controls of moving charges
  memory.oom_control             # set/show oom controls.
+ memory.numa_stat               # show the number of memory usage per numa node
 
 1. History
 
@@ -181,7 +182,7 @@ 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).
 
-Exception: If CONFIG_CGROUP_CGROUP_MEM_RES_CTLR_SWAP is not used..
+Exception: If CONFIG_CGROUP_CGROUP_MEM_RES_CTLR_SWAP is not used.
 When you do swapoff and make swapped-out pages of shmem(tmpfs) to
 be backed into memory in force, charges for pages are accounted against the
 caller of swapoff rather than the users of shmem.
@@ -213,7 +214,7 @@ affecting global LRU, memory+swap limit is better than just limiting swap from
 OS point of view.
 
 * What happens when a cgroup hits memory.memsw.limit_in_bytes
-When a cgroup his memory.memsw.limit_in_bytes, it's useless to do swap-out
+When a cgroup hits memory.memsw.limit_in_bytes, it's useless to do swap-out
 in this cgroup. Then, swap-out will not be done by cgroup routine and file
 caches are dropped. But as mentioned above, global LRU can do swapout memory
 from it for sanity of the system's memory management state. You can't forbid
@@ -263,16 +264,17 @@ b. Enable CONFIG_RESOURCE_COUNTERS
 c. Enable CONFIG_CGROUP_MEM_RES_CTLR
 d. Enable CONFIG_CGROUP_MEM_RES_CTLR_SWAP (to use swap extension)
 
-1. Prepare the cgroups
-# mkdir -p /cgroups
-# mount -t cgroup none /cgroups -o memory
+1. Prepare the cgroups (see cgroups.txt, Why are cgroups needed?)
+# mount -t tmpfs none /sys/fs/cgroup
+# mkdir /sys/fs/cgroup/memory
+# mount -t cgroup none /sys/fs/cgroup/memory -o memory
 
 2. Make the new group and move bash into it
-# mkdir /cgroups/0
-# echo $$ > /cgroups/0/tasks
+# mkdir /sys/fs/cgroup/memory/0
+# echo $$ > /sys/fs/cgroup/memory/0/tasks
 
 Since now we're in the 0 cgroup, we can alter the memory limit:
-# echo 4M > /cgroups/0/memory.limit_in_bytes
+# echo 4M > /sys/fs/cgroup/memory/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. (Here, Kilo, Mega, Giga are Kibibytes, Mebibytes, Gibibytes.)
@@ -280,11 +282,11 @@ mega or gigabytes. (Here, Kilo, Mega, Giga are Kibibytes, Mebibytes, Gibibytes.)
 NOTE: We can write "-1" to reset the *.limit_in_bytes(unlimited).
 NOTE: We cannot set limits on the root cgroup any more.
 
-# cat /cgroups/0/memory.limit_in_bytes
+# cat /sys/fs/cgroup/memory/0/memory.limit_in_bytes
 4194304
 
 We can check the usage:
-# cat /cgroups/0/memory.usage_in_bytes
+# cat /sys/fs/cgroup/memory/0/memory.usage_in_bytes
 1216512
 
 A successful write to this file does not guarantee a successful set of
@@ -464,6 +466,24 @@ value for efficient access. (Of course, when necessary, it's synchronized.)
 If you want to know more exact memory usage, you should use RSS+CACHE(+SWAP)
 value in memory.stat(see 5.2).
 
+5.6 numa_stat
+
+This is similar to numa_maps but operates on a per-memcg basis.  This is
+useful for providing visibility into the numa locality information within
+an memcg since the pages are allowed to be allocated from any physical
+node.  One of the usecases is evaluating application performance by
+combining this information with the application's cpu allocation.
+
+We export "total", "file", "anon" and "unevictable" pages per-node for
+each memcg.  The ouput format of memory.numa_stat is:
+
+total=<total pages> N0=<node 0 pages> N1=<node 1 pages> ...
+file=<total file pages> N0=<node 0 pages> N1=<node 1 pages> ...
+anon=<total anon pages> N0=<node 0 pages> N1=<node 1 pages> ...
+unevictable=<total anon pages> N0=<node 0 pages> N1=<node 1 pages> ...
+
+And we have total = file + anon + unevictable.
+
 6. Hierarchy support
 
 The memory controller supports a deep hierarchy and hierarchical accounting.
@@ -471,13 +491,13 @@ The hierarchy is created by creating the appropriate cgroups in the
 cgroup filesystem. Consider for example, the following cgroup filesystem
 hierarchy
 
-               root
+              root
             /  |   \
-             |    \
-         a     b       c
-                       | \
-                       |  \
-                       d   e
+            /  |    \
+          a    b     c
+                     | \
+                     |  \
+                     d   e
 
 In the diagram above, with hierarchical accounting enabled, all memory
 usage of e, is accounted to its ancestors up until the root (i.e, c and root),
index edb7ae19e868a2166c8c93e977a0d4064e95dfc2..2c6be0377f55d0963970972c4d2b494e73f4507f 100644 (file)
@@ -74,3 +74,57 @@ Example:
                interrupt-parent = <&mpic>;
                phy-handle = <&phy0>
        };
+
+* Gianfar PTP clock nodes
+
+General Properties:
+
+  - compatible   Should be "fsl,etsec-ptp"
+  - reg          Offset and length of the register set for the device
+  - interrupts   There should be at least two interrupts. Some devices
+                 have as many as four PTP related interrupts.
+
+Clock Properties:
+
+  - fsl,tclk-period  Timer reference clock period in nanoseconds.
+  - fsl,tmr-prsc     Prescaler, divides the output clock.
+  - fsl,tmr-add      Frequency compensation value.
+  - fsl,tmr-fiper1   Fixed interval period pulse generator.
+  - fsl,tmr-fiper2   Fixed interval period pulse generator.
+  - fsl,max-adj      Maximum frequency adjustment in parts per billion.
+
+  These properties set the operational parameters for the PTP
+  clock. You must choose these carefully for the clock to work right.
+  Here is how to figure good values:
+
+  TimerOsc     = system clock               MHz
+  tclk_period  = desired clock period       nanoseconds
+  NominalFreq  = 1000 / tclk_period         MHz
+  FreqDivRatio = TimerOsc / NominalFreq     (must be greater that 1.0)
+  tmr_add      = ceil(2^32 / FreqDivRatio)
+  OutputClock  = NominalFreq / tmr_prsc     MHz
+  PulseWidth   = 1 / OutputClock            microseconds
+  FiperFreq1   = desired frequency in Hz
+  FiperDiv1    = 1000000 * OutputClock / FiperFreq1
+  tmr_fiper1   = tmr_prsc * tclk_period * FiperDiv1 - tclk_period
+  max_adj      = 1000000000 * (FreqDivRatio - 1.0) - 1
+
+  The calculation for tmr_fiper2 is the same as for tmr_fiper1. The
+  driver expects that tmr_fiper1 will be correctly set to produce a 1
+  Pulse Per Second (PPS) signal, since this will be offered to the PPS
+  subsystem to synchronize the Linux clock.
+
+Example:
+
+       ptp_clock@24E00 {
+               compatible = "fsl,etsec-ptp";
+               reg = <0x24E00 0xB0>;
+               interrupts = <12 0x8 13 0x8>;
+               interrupt-parent = < &ipic >;
+               fsl,tclk-period = <10>;
+               fsl,tmr-prsc    = <100>;
+               fsl,tmr-add     = <0x999999A4>;
+               fsl,tmr-fiper1  = <0x3B9AC9F6>;
+               fsl,tmr-fiper2  = <0x00018696>;
+               fsl,max-adj     = <659999998>;
+       };
index 50619a0720a8fd070b5f83cb1fc9ced9ff79a858..7c1329de0596a34ce81d60f214d46a43933f05c0 100644 (file)
@@ -12,8 +12,9 @@ Table of Contents
 =================
 
   I - Introduction
-    1) Entry point for arch/powerpc
-    2) Entry point for arch/x86
+    1) Entry point for arch/arm
+    2) Entry point for arch/powerpc
+    3) Entry point for arch/x86
 
   II - The DT block format
     1) Header
@@ -148,7 +149,46 @@ upgrades without significantly impacting the kernel code or cluttering
 it with special cases.
 
 
-1) Entry point for arch/powerpc
+1) Entry point for arch/arm
+---------------------------
+
+   There is one single entry point to the kernel, at the start
+   of the kernel image. That entry point supports two calling
+   conventions.  A summary of the interface is described here.  A full
+   description of the boot requirements is documented in
+   Documentation/arm/Booting
+
+        a) ATAGS interface.  Minimal information is passed from firmware
+        to the kernel with a tagged list of predefined parameters.
+
+                r0 : 0
+
+                r1 : Machine type number
+
+                r2 : Physical address of tagged list in system RAM
+
+        b) Entry with a flattened device-tree block.  Firmware loads the
+        physical address of the flattened device tree block (dtb) into r2,
+        r1 is not used, but it is considered good practise to use a valid
+        machine number as described in Documentation/arm/Booting.
+
+                r0 : 0
+
+                r1 : Valid machine type number.  When using a device tree,
+                a single machine type number will often be assigned to
+                represent a class or family of SoCs.
+
+                r2 : physical pointer to the device-tree block
+                (defined in chapter II) in RAM.  Device tree can be located
+                anywhere in system RAM, but it should be aligned on a 64 bit
+                boundary.
+
+   The kernel will differentiate between ATAGS and device tree booting by
+   reading the memory pointed to by r2 and looking for either the flattened
+   device tree block magic value (0xd00dfeed) or the ATAG_CORE value at
+   offset 0x4 from r2 (0x54410001).
+
+2) Entry point for arch/powerpc
 -------------------------------
 
    There is one single entry point to the kernel, at the start
@@ -226,7 +266,7 @@ it with special cases.
   cannot support both configurations with Book E and configurations
   with classic Powerpc architectures.
 
-2) Entry point for arch/x86
+3) Entry point for arch/x86
 -------------------------------
 
   There is one single 32bit entry point to the kernel at code32_start,
index 0c1c2f63c0a932fb735e9c914ddd7fc565efb964..5a0cb1ef6164d5c363f6f4b8de0007e7820ea5ef 100644 (file)
@@ -1 +1,96 @@
-See Documentation/crypto/async-tx-api.txt
+                       DMA Engine API Guide
+                       ====================
+
+                Vinod Koul <vinod dot koul at intel.com>
+
+NOTE: For DMA Engine usage in async_tx please see:
+       Documentation/crypto/async-tx-api.txt
+
+
+Below is a guide to device driver writers on how to use the Slave-DMA API of the
+DMA Engine. This is applicable only for slave DMA usage only.
+
+The slave DMA usage consists of following steps
+1. Allocate a DMA slave channel
+2. Set slave and controller specific parameters
+3. Get a descriptor for transaction
+4. Submit the transaction and wait for callback notification
+
+1. Allocate a DMA slave channel
+Channel allocation is slightly different in the slave DMA context, client
+drivers typically need a channel from a particular DMA controller only and even
+in some cases a specific channel is desired. To request a channel
+dma_request_channel() API is used.
+
+Interface:
+struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
+               dma_filter_fn filter_fn,
+               void *filter_param);
+where dma_filter_fn is defined as:
+typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
+
+When the optional 'filter_fn' parameter is set to NULL dma_request_channel
+simply returns the first channel that satisfies the capability mask.  Otherwise,
+when the mask parameter is insufficient for specifying the necessary channel,
+the filter_fn routine can be used to disposition the available channels in the
+system. The filter_fn routine is called once for each free channel in the
+system.  Upon seeing a suitable channel filter_fn returns DMA_ACK which flags
+that channel to be the return value from dma_request_channel.  A channel
+allocated via this interface is exclusive to the caller, until
+dma_release_channel() is called.
+
+2. Set slave and controller specific parameters
+Next step is always to pass some specific information to the DMA driver. Most of
+the generic information which a slave DMA can use is in struct dma_slave_config.
+It allows the clients to specify DMA direction, DMA addresses, bus widths, DMA
+burst lengths etc. If some DMA controllers have more parameters to be sent then
+they should try to embed struct dma_slave_config in their controller specific
+structure. That gives flexibility to client to pass more parameters, if
+required.
+
+Interface:
+int dmaengine_slave_config(struct dma_chan *chan,
+                                         struct dma_slave_config *config)
+
+3. Get a descriptor for transaction
+For slave usage the various modes of slave transfers supported by the
+DMA-engine are:
+slave_sg       - DMA a list of scatter gather buffers from/to a peripheral
+dma_cyclic     - Perform a cyclic DMA operation from/to a peripheral till the
+                 operation is explicitly stopped.
+The non NULL return of this transfer API represents a "descriptor" for the given
+transaction.
+
+Interface:
+struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_sg)(
+               struct dma_chan *chan,
+               struct scatterlist *dst_sg, unsigned int dst_nents,
+               struct scatterlist *src_sg, unsigned int src_nents,
+               unsigned long flags);
+struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_cyclic)(
+               struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+               size_t period_len, enum dma_data_direction direction);
+
+4. Submit the transaction and wait for callback notification
+To schedule the transaction to be scheduled by dma device, the "descriptor"
+returned in above (3) needs to be submitted.
+To tell the dma driver that a transaction is ready to be serviced, the
+descriptor->submit() callback needs to be invoked. This chains the descriptor to
+the pending queue.
+The transactions in the pending queue can be activated by calling the
+issue_pending API. If channel is idle then the first transaction in queue is
+started and subsequent ones queued up.
+On completion of the DMA operation the next in queue is submitted and a tasklet
+triggered. The tasklet would then call the client driver completion callback
+routine for notification, if set.
+Interface:
+void dma_async_issue_pending(struct dma_chan *chan);
+
+==============================================================================
+
+Additional usage notes for dma driver writers
+1/ Although DMA engine specifies that completion callback routines cannot submit
+any new operations, but typically for slave DMA subsequent transaction may not
+be available for submit prior to callback routine being called. This requirement
+is not a requirement for DMA-slave devices. But they should take care to drop
+the spin-lock they might be holding before calling the callback routine
index 95788ad2506c57575e1ead9af19f6fc3440e59d5..72e238465b0b6ca452ee4905dc097007b9ff3dc0 100644 (file)
@@ -6,6 +6,42 @@ be removed from this file.
 
 ---------------------------
 
+What:  x86 floppy disable_hlt
+When:  2012
+Why:   ancient workaround of dubious utility clutters the
+       code used by everybody else.
+Who:   Len Brown <len.brown@intel.com>
+
+---------------------------
+
+What:  CONFIG_APM_CPU_IDLE, and its ability to call APM BIOS in idle
+When:  2012
+Why:   This optional sub-feature of APM is of dubious reliability,
+       and ancient APM laptops are likely better served by calling HLT.
+       Deleting CONFIG_APM_CPU_IDLE allows x86 to stop exporting
+       the pm_idle function pointer to modules.
+Who:   Len Brown <len.brown@intel.com>
+
+----------------------------
+
+What:  x86_32 "no-hlt" cmdline param
+When:  2012
+Why:   remove a branch from idle path, simplify code used by everybody.
+       This option disabled the use of HLT in idle and machine_halt()
+       for hardware that was flakey 15-years ago.  Today we have
+       "idle=poll" that removed HLT from idle, and so if such a machine
+       is still running the upstream kernel, "idle=poll" is likely sufficient.
+Who:   Len Brown <len.brown@intel.com>
+
+----------------------------
+
+What:  x86 "idle=mwait" cmdline param
+When:  2012
+Why:   simplify x86 idle code
+Who:   Len Brown <len.brown@intel.com>
+
+----------------------------
+
 What:  PRISM54
 When:  2.6.34
 
@@ -262,16 +298,6 @@ Who:       Michael Buesch <mb@bu3sch.de>
 
 ---------------------------
 
-What:  /sys/o2cb symlink
-When:  January 2010
-Why:   /sys/fs/o2cb is the proper location for this information - /sys/o2cb
-       exists as a symlink for backwards compatibility for old versions of
-       ocfs2-tools. 2 years should be sufficient time to phase in new versions
-       which know to look in /sys/fs/o2cb.
-Who:   ocfs2-devel@oss.oracle.com
-
----------------------------
-
 What:  Ability for non root users to shm_get hugetlb pages based on mlock
        resource limits
 When:  2.6.31
@@ -455,23 +481,6 @@ Who:       FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
 
 ----------------------------
 
-What:   namespace cgroup (ns_cgroup)
-When:   2.6.38
-Why:    The ns_cgroup leads to some problems:
-       * cgroup creation is out-of-control
-       * cgroup name can conflict when pids are looping
-       * it is not possible to have a single process handling
-       a lot of namespaces without falling in a exponential creation time
-       * we may want to create a namespace without creating a cgroup
-
-       The ns_cgroup is replaced by a compatibility flag 'clone_children',
-       where a newly created cgroup will copy the parent cgroup values.
-       The userspace has to manually create a cgroup and add a task to
-       the 'tasks' file.
-Who:    Daniel Lezcano <daniel.lezcano@free.fr>
-
-----------------------------
-
 What:  iwlwifi disable_hw_scan module parameters
 When:  2.6.40
 Why:   Hareware scan is the prefer method for iwlwifi devices for
index b22abba78fede6049ab07b8167bce2dedc99fe90..13de64c7f0ab0bf7f347156573e187a0a72ac4a0 100644 (file)
@@ -25,6 +25,8 @@ Other applications are described in the following papers:
                http://xcpu.org/papers/cellfs-talk.pdf
        * PROSE I/O: Using 9p to enable Application Partitions
                http://plan9.escet.urjc.es/iwp9/cready/PROSE_iwp9_2006.pdf
+       * VirtFS: A Virtualization Aware File System pass-through
+               http://goo.gl/3WPDg
 
 USAGE
 =====
@@ -130,31 +132,20 @@ OPTIONS
 RESOURCES
 =========
 
-Our current recommendation is to use Inferno (http://www.vitanuova.com/nferno/index.html)
-as the 9p server.  You can start a 9p server under Inferno by issuing the
-following command:
-   ; styxlisten -A tcp!*!564 export '#U*'
+Protocol specifications are maintained on github:
+http://ericvh.github.com/9p-rfc/
 
-The -A specifies an unauthenticated export.  The 564 is the port # (you may
-have to choose a higher port number if running as a normal user).  The '#U*'
-specifies exporting the root of the Linux name space.  You may specify a
-subset of the namespace by extending the path: '#U*'/tmp would just export
-/tmp.  For more information, see the Inferno manual pages covering styxlisten
-and export.
+9p client and server implementations are listed on
+http://9p.cat-v.org/implementations
 
-A Linux version of the 9p server is now maintained under the npfs project
-on sourceforge (http://sourceforge.net/projects/npfs).  The currently
-maintained version is the single-threaded version of the server (named spfs)
-available from the same SVN repository.
+A 9p2000.L server is being developed by LLNL and can be found
+at http://code.google.com/p/diod/
 
 There are user and developer mailing lists available through the v9fs project
 on sourceforge (http://sourceforge.net/projects/v9fs).
 
-A stand-alone version of the module (which should build for any 2.6 kernel)
-is available via (http://github.com/ericvh/9p-sac/tree/master)
-
-News and other information is maintained on SWiK (http://swik.net/v9fs)
-and the Wiki (http://sf.net/apps/mediawiki/v9fs/index.php).
+News and other information is maintained on a Wiki.
+(http://sf.net/apps/mediawiki/v9fs/index.php).
 
 Bug reports may be issued through the kernel.org bugzilla 
 (http://bugzilla.kernel.org)
index 61b31acb9176b35bc77c914b2b3913abbcc9e78a..57d827d6071d6b77e18c2c984ae444ac43adbabb 100644 (file)
@@ -104,7 +104,7 @@ of the locking scheme for directory operations.
 prototypes:
        struct inode *(*alloc_inode)(struct super_block *sb);
        void (*destroy_inode)(struct inode *);
-       void (*dirty_inode) (struct inode *);
+       void (*dirty_inode) (struct inode *, int flags);
        int (*write_inode) (struct inode *, struct writeback_control *wbc);
        int (*drop_inode) (struct inode *);
        void (*evict_inode) (struct inode *);
@@ -126,7 +126,7 @@ locking rules:
                        s_umount
 alloc_inode:
 destroy_inode:
-dirty_inode:                           (must not sleep)
+dirty_inode:
 write_inode:
 drop_inode:                            !!!inode->i_lock!!!
 evict_inode:
index fd53869f5633f2994fe06365fe53c1754747dc6a..1420233dfa556906a503f32f2bd010da9ea3e92e 100644 (file)
@@ -464,9 +464,8 @@ static int __init configfs_example_init(void)
        return 0;
 
 out_unregister:
-       for (; i >= 0; i--) {
+       for (i--; i >= 0; i--)
                configfs_unregister_subsystem(example_subsys[i]);
-       }
 
        return ret;
 }
@@ -475,9 +474,8 @@ static void __exit configfs_example_exit(void)
 {
        int i;
 
-       for (i = 0; example_subsys[i]; i++) {
+       for (i = 0; example_subsys[i]; i++)
                configfs_unregister_subsystem(example_subsys[i]);
-       }
 }
 
 module_init(configfs_example_init);
index d8e30a0378aa2bf3540a79da4ff030d402943497..327dfbc640a9087302ce6ea5c6b30c77ad721acf 100644 (file)
@@ -427,9 +427,8 @@ static int __init configfs_example_init(void)
        return 0;
 
 out_unregister:
-       for (; i >= 0; i--) {
+       for (i--; i >= 0; i--)
                configfs_unregister_subsystem(example_subsys[i]);
-       }
 
        return ret;
 }
@@ -438,9 +437,8 @@ static void __exit configfs_example_exit(void)
 {
        int i;
 
-       for (i = 0; example_subsys[i]; i++) {
+       for (i = 0; example_subsys[i]; i++)
                configfs_unregister_subsystem(example_subsys[i]);
-       }
 }
 
 module_init(configfs_example_init);
index c79ec58fd7f6f3df8ee32d98448cf4acfe5d7705..3ae9bc94352a660f2d3ed9feccc0b3aa8955ffcc 100644 (file)
@@ -226,10 +226,6 @@ acl                        Enables POSIX Access Control Lists support.
 noacl                  This option disables POSIX Access Control List
                        support.
 
-reservation
-
-noreservation
-
 bsddf          (*)     Make 'df' act like BSD.
 minixdf                        Make 'df' act like Minix.
 
index b9b4192ea8b588ebd2d5be15767e69b93c8a7d0a..9c8fd614865642e7b9faf418de164c6088204b50 100644 (file)
@@ -47,8 +47,8 @@ request-key will find the first matching line and corresponding program.  In
 this case, /some/other/program will handle all uid lookups and
 /usr/sbin/nfs.idmap will handle gid, user, and group lookups.
 
-See <file:Documentation/keys-request-keys.txt> for more information about the
-request-key function.
+See <file:Documentation/security/keys-request-keys.txt> for more information
+about the request-key function.
 
 
 =========
index 9ed920a8cd79e92ef871e3fa29201b0777a8ce2a..7618a287aa41f085e8c166393b99ee31672c2a9e 100644 (file)
@@ -46,9 +46,15 @@ errors=panic         Panic and halt the machine if an error occurs.
 intr           (*)     Allow signals to interrupt cluster operations.
 nointr                 Do not allow signals to interrupt cluster
                        operations.
+noatime                        Do not update access time.
+relatime(*)            Update atime if the previous atime is older than
+                       mtime or ctime
+strictatime            Always update atime, but the minimum update interval
+                       is specified by atime_quantum.
 atime_quantum=60(*)    OCFS2 will not update atime unless this number
                        of seconds has passed since the last update.
-                       Set to zero to always update atime.
+                       Set to zero to always update atime. This option need
+                       work with strictatime.
 data=ordered   (*)     All data are forced directly out to the main file
                        system prior to its metadata being committed to the
                        journal.
index 60740e8ecb3779e7bb314dcde47d88f54183788b..db3b1aba32a3f9c0d80ce0cde2d8b6f1943f4dea 100644 (file)
@@ -574,6 +574,12 @@ The contents of each smp_affinity file is the same by default:
   > cat /proc/irq/0/smp_affinity
   ffffffff
 
+There is an alternate interface, smp_affinity_list which allows specifying
+a cpu range instead of a bitmask:
+
+  > cat /proc/irq/0/smp_affinity_list
+  1024-1031
+
 The default_smp_affinity mask applies to all non-active IRQs, which are the
 IRQs which have not yet been allocated/activated, and hence which lack a
 /proc/irq/[0-9]* directory.
@@ -583,12 +589,13 @@ reports itself as being attached. This hardware locality information does not
 include information about any possible driver locality preference.
 
 prof_cpu_mask specifies which CPUs are to be profiled by the system wide
-profiler. Default value is ffffffff (all cpus).
+profiler. Default value is ffffffff (all cpus if there are only 32 of them).
 
 The way IRQs are routed is handled by the IO-APIC, and it's Round Robin
 between all the CPUs which are allowed to handle it. As usual the kernel has
 more info than you and does a better job than you, so the defaults are the
-best choice for almost everyone.
+best choice for almost everyone.  [Note this applies only to those IO-APIC's
+that support "Round Robin" interrupt distribution.]
 
 There are  three  more  important subdirectories in /proc: net, scsi, and sys.
 The general  rule  is  that  the  contents,  or  even  the  existence of these
@@ -836,6 +843,7 @@ Provides counts of softirq handlers serviced since boot time, for each cpu.
  TASKLET:          0          0          0        290
    SCHED:      27035      26983      26971      26746
  HRTIMER:          0          0          0          0
+     RCU:       1678       1769       2178       2250
 
 
 1.3 IDE devices in /proc/ide
index d7b13b01e98054098ba8b94744173df1ed41126a..8e4fab639d9c322708c7e0ab01825697c3e4ccb7 100644 (file)
@@ -115,28 +115,8 @@ ubi.mtd=0 root=ubi0:rootfs rootfstype=ubifs
 Module Parameters for Debugging
 ===============================
 
-When UBIFS has been compiled with debugging enabled, there are 3 module
+When UBIFS has been compiled with debugging enabled, there are 2 module
 parameters that are available to control aspects of testing and debugging.
-The parameters are unsigned integers where each bit controls an option.
-The parameters are:
-
-debug_msgs     Selects which debug messages to display, as follows:
-
-               Message Type                            Flag value
-
-               General messages                        1
-               Journal messages                        2
-               Mount messages                          4
-               Commit messages                         8
-               LEB search messages                     16
-               Budgeting messages                      32
-               Garbage collection messages             64
-               Tree Node Cache (TNC) messages          128
-               LEB properties (lprops) messages        256
-               Input/output messages                   512
-               Log messages                            1024
-               Scan messages                           2048
-               Recovery messages                       4096
 
 debug_chks     Selects extra checks that UBIFS can do while running:
 
@@ -154,11 +134,9 @@ debug_tsts Selects a mode of testing, as follows:
 
                Test mode                               Flag value
 
-               Force in-the-gaps method                2
                Failure mode for recovery testing       4
 
-For example, set debug_msgs to 5 to display General messages and Mount
-messages.
+For example, set debug_chks to 3 to enable general and TNC checks.
 
 
 References
index 21a7dc467bba197758caceb4d18285f784da6bb2..88b9f5519af976e2cb2f472588cf43bd572b920e 100644 (file)
@@ -211,7 +211,7 @@ struct super_operations {
         struct inode *(*alloc_inode)(struct super_block *sb);
         void (*destroy_inode)(struct inode *);
 
-        void (*dirty_inode) (struct inode *);
+        void (*dirty_inode) (struct inode *, int flags);
         int (*write_inode) (struct inode *, int);
         void (*drop_inode) (struct inode *);
         void (*delete_inode) (struct inode *);
index 7bff3e4f35df84a9def7507badb42ccdeffef419..3fc0c31a6f5dc5f8ee1220d9bcf8062038297aa5 100644 (file)
@@ -39,6 +39,12 @@ When mounting an XFS filesystem, the following options are accepted.
        drive level write caching to be enabled, for devices that
        support write barriers.
 
+  discard
+       Issue command to let the block device reclaim space freed by the
+       filesystem.  This is useful for SSD devices, thinly provisioned
+       LUNs and virtual machine images, but may have a performance
+       impact.  This option is incompatible with the nodelaylog option.
+
   dmapi
        Enable the DMAPI (Data Management API) event callouts.
        Use with the "mtpt" option.
diff --git a/Documentation/hwmon/emc6w201 b/Documentation/hwmon/emc6w201
new file mode 100644 (file)
index 0000000..32f355a
--- /dev/null
@@ -0,0 +1,42 @@
+Kernel driver emc6w201
+======================
+
+Supported chips:
+  * SMSC EMC6W201
+    Prefix: 'emc6w201'
+    Addresses scanned: I2C 0x2c, 0x2d, 0x2e
+    Datasheet: Not public
+
+Author: Jean Delvare <khali@linux-fr.org>
+
+
+Description
+-----------
+
+From the datasheet:
+
+"The EMC6W201 is an environmental monitoring device with automatic fan
+control capability and enhanced system acoustics for noise suppression.
+This ACPI compliant device provides hardware monitoring for up to six
+voltages (including its own VCC) and five external thermal sensors,
+measures the speed of up to five fans, and controls the speed of
+multiple DC fans using three Pulse Width Modulator (PWM) outputs. Note
+that it is possible to control more than three fans by connecting two
+fans to one PWM output. The EMC6W201 will be available in a 36-pin
+QFN package."
+
+The device is functionally close to the EMC6D100 series, but is
+register-incompatible.
+
+The driver currently only supports the monitoring of the voltages,
+temperatures and fan speeds. Limits can be changed. Alarms are not
+supported, and neither is fan speed control.
+
+
+Known Systems With EMC6W201
+---------------------------
+
+The EMC6W201 is a rare device, only found on a few systems, made in
+2005 and 2006. Known systems with this device:
+* Dell Precision 670 workstation
+* Gigabyte 2CEWH mainboard
index df02245d1419d76a1962f3a879f5480c9cf02a5f..84d2623810f31ade6b45315297ee755c6985209d 100644 (file)
@@ -6,6 +6,10 @@ Supported chips:
     Prefix: 'f71808e'
     Addresses scanned: none, address read from Super I/O config space
     Datasheet: Not public
+  * Fintek F71808A
+    Prefix: 'f71808a'
+    Addresses scanned: none, address read from Super I/O config space
+    Datasheet: Not public
   * Fintek F71858FG
     Prefix: 'f71858fg'
     Addresses scanned: none, address read from Super I/O config space
diff --git a/Documentation/hwmon/fam15h_power b/Documentation/hwmon/fam15h_power
new file mode 100644 (file)
index 0000000..a92918e
--- /dev/null
@@ -0,0 +1,37 @@
+Kernel driver fam15h_power
+==========================
+
+Supported chips:
+* AMD Family 15h Processors
+
+  Prefix: 'fam15h_power'
+  Addresses scanned: PCI space
+  Datasheets:
+  BIOS and Kernel Developer's Guide (BKDG) For AMD Family 15h Processors
+    (not yet published)
+
+Author: Andreas Herrmann <andreas.herrmann3@amd.com>
+
+Description
+-----------
+
+This driver permits reading of registers providing power information
+of AMD Family 15h processors.
+
+For AMD Family 15h processors the following power values can be
+calculated using different processor northbridge function registers:
+
+* BasePwrWatts: Specifies in watts the maximum amount of power
+  consumed by the processor for NB and logic external to the core.
+* ProcessorPwrWatts: Specifies in watts the maximum amount of power
+  the processor can support.
+* CurrPwrWatts: Specifies in watts the current amount of power being
+  consumed by the processor.
+
+This driver provides ProcessorPwrWatts and CurrPwrWatts:
+* power1_crit (ProcessorPwrWatts)
+* power1_input (CurrPwrWatts)
+
+On multi-node processors the calculated value is for the entire
+package and not for a single node. Thus the driver creates sysfs
+attributes only for internal node0 of a multi-node processor.
index d2b56a4fd1f5a44566968e7b5faebe62b879ccaa..0393c89277c021b3e64921a7cda1007cb4f4d602 100644 (file)
@@ -11,6 +11,7 @@ Supported chips:
   Socket S1G2: Athlon (X2), Sempron (X2), Turion X2 (Ultra)
 * AMD Family 12h processors: "Llano"
 * AMD Family 14h processors: "Brazos" (C/E/G-Series)
+* AMD Family 15h processors: "Bulldozer"
 
   Prefix: 'k10temp'
   Addresses scanned: PCI space
@@ -40,7 +41,7 @@ Description
 -----------
 
 This driver permits reading of the internal temperature sensor of AMD
-Family 10h/11h/12h/14h processors.
+Family 10h/11h/12h/14h/15h processors.
 
 All these processors have a sensor, but on those for Socket F or AM2+,
 the sensor may return inconsistent values (erratum 319).  The driver
index c565650fcfc6f6949c8a24ae1bd2002ae9da86fa..58d9644a2bde87eb5931f92b0e1bfc936d9ed682 100644 (file)
@@ -2,9 +2,13 @@ Kernel driver max6650
 =====================
 
 Supported chips:
-  * Maxim 6650 / 6651
+  * Maxim MAX6650
     Prefix: 'max6650'
-    Addresses scanned: I2C 0x1b, 0x1f, 0x48, 0x4b
+    Addresses scanned: none
+    Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
+  * Maxim MAX6651
+    Prefix: 'max6651'
+    Addresses scanned: none
     Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
 
 Authors:
@@ -15,10 +19,10 @@ Authors:
 Description
 -----------
 
-This driver implements support for the Maxim 6650/6651
+This driver implements support for the Maxim MAX6650 and MAX6651.
 
-The 2 devices are very similar, but the Maxim 6550 has a reduced feature
-set, e.g. only one fan-input, instead of 4 for the 6651.
+The 2 devices are very similar, but the MAX6550 has a reduced feature
+set, e.g. only one fan-input, instead of 4 for the MAX6651.
 
 The driver is not able to distinguish between the 2 devices.
 
@@ -36,6 +40,13 @@ fan1_div     rw      sets the speed range the inputs can handle. Legal
                        values are 1, 2, 4, and 8. Use lower values for
                        faster fans.
 
+Usage notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
 Module parameters
 -----------------
 
index 6df69765ccb75045615dec13c3b564c550d18021..2871fd5003492b1d3ba266e2cd65aec8ebd58406 100644 (file)
@@ -19,6 +19,7 @@ Supported adapters:
   * Intel 6 Series (PCH)
   * Intel Patsburg (PCH)
   * Intel DH89xxCC (PCH)
+  * Intel Panther Point (PCH)
    Datasheets: Publicly available at the Intel website
 
 On Intel Patsburg and later chipsets, both the normal host SMBus controller
index 5ebf5af1d71606ae3d6d31557f97ce7f3077add7..5aa53374ea2a84d264f7875d69d39fd1b0526916 100644 (file)
@@ -38,7 +38,7 @@ static struct i2c_driver foo_driver = {
                .name   = "foo",
        },
 
-       .id_table       = foo_ids,
+       .id_table       = foo_idtable,
        .probe          = foo_probe,
        .remove         = foo_remove,
        /* if device autodetection is needed: */
index 56941ae1f5dbd2b161f7871ad3959f46ae227f89..db798af5ef98a434cbb8c8828857627953c932ec 100644 (file)
@@ -34,7 +34,8 @@ Contents
 Currently the Linux Elantech touchpad driver is aware of two different
 hardware versions unimaginatively called version 1 and version 2. Version 1
 is found in "older" laptops and uses 4 bytes per packet. Version 2 seems to
-be introduced with the EeePC and uses 6 bytes per packet.
+be introduced with the EeePC and uses 6 bytes per packet, and provides
+additional features such as position of two fingers, and width of the touch.
 
 The driver tries to support both hardware versions and should be compatible
 with the Xorg Synaptics touchpad driver and its graphical configuration
@@ -94,18 +95,44 @@ Currently the Linux Elantech touchpad driver provides two extra knobs under
    can check these bits and reject any packet that appears corrupted. Using
    this knob you can bypass that check.
 
-   It is not known yet whether hardware version 2 provides the same parity
-   bits. Hence checking is disabled by default. Currently even turning it on
-   will do nothing.
-
+   Hardware version 2 does not provide the same parity bits. Only some basic
+   data consistency checking can be done. For now checking is disabled by
+   default. Currently even turning it on will do nothing.
 
 /////////////////////////////////////////////////////////////////////////////
 
+3. Differentiating hardware versions
+   =================================
+
+To detect the hardware version, read the version number as param[0].param[1].param[2]
+
+ 4 bytes version: (after the arrow is the name given in the Dell-provided driver)
+ 02.00.22 => EF013
+ 02.06.00 => EF019
+In the wild, there appear to be more versions, such as 00.01.64, 01.00.21,
+02.00.00, 02.00.04, 02.00.06.
+
+ 6 bytes:
+ 02.00.30 => EF113
+ 02.08.00 => EF023
+ 02.08.XX => EF123
+ 02.0B.00 => EF215
+ 04.01.XX => Scroll_EF051
+ 04.02.XX => EF051
+In the wild, there appear to be more versions, such as 04.03.01, 04.04.11. There
+appears to be almost no difference, except for EF113, which does not report
+pressure/width and has different data consistency checks.
+
+Probably all the versions with param[0] <= 01 can be considered as
+4 bytes/firmware 1. The versions < 02.08.00, with the exception of 02.00.30, as
+4 bytes/firmware 2. Everything >= 02.08.00 can be considered as 6 bytes.
+
+/////////////////////////////////////////////////////////////////////////////
 
-3. Hardware version 1
+4. Hardware version 1
    ==================
 
-3.1 Registers
+4.1 Registers
     ~~~~~~~~~
 
 By echoing a hexadecimal value to a register it contents can be altered.
@@ -168,7 +195,7 @@ For example:
          smart edge activation area width?
 
 
-3.2 Native relative mode 4 byte packet format
+4.2 Native relative mode 4 byte packet format
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 byte 0:
@@ -226,9 +253,13 @@ byte 3:
                        positive = down
 
 
-3.3 Native absolute mode 4 byte packet format
+4.3 Native absolute mode 4 byte packet format
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+EF013 and EF019 have a special behaviour (due to a bug in the firmware?), and
+when 1 finger is touching, the first 2 position reports must be discarded.
+This counting is reset whenever a different number of fingers is reported.
+
 byte 0:
    firmware version 1.x:
 
@@ -279,11 +310,11 @@ byte 3:
 /////////////////////////////////////////////////////////////////////////////
 
 
-4. Hardware version 2
+5. Hardware version 2
    ==================
 
 
-4.1 Registers
+5.1 Registers
     ~~~~~~~~~
 
 By echoing a hexadecimal value to a register it contents can be altered.
@@ -316,16 +347,41 @@ For example:
                                    0x7f = never i.e. tap again to release)
 
 
-4.2 Native absolute mode 6 byte packet format
+5.2 Native absolute mode 6 byte packet format
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-4.2.1 One finger touch
+5.2.1 Parity checking and packet re-synchronization
+There is no parity checking, however some consistency checks can be performed.
+
+For instance for EF113:
+        SA1= packet[0];
+        A1 = packet[1];
+        B1 = packet[2];
+        SB1= packet[3];
+        C1 = packet[4];
+        D1 = packet[5];
+        if( (((SA1 & 0x3C) != 0x3C) && ((SA1 & 0xC0) != 0x80)) || // check Byte 1
+            (((SA1 & 0x0C) != 0x0C) && ((SA1 & 0xC0) == 0x80)) || // check Byte 1 (one finger pressed)
+            (((SA1 & 0xC0) != 0x80) && (( A1 & 0xF0) != 0x00)) || // check Byte 2
+            (((SB1 & 0x3E) != 0x38) && ((SA1 & 0xC0) != 0x80)) || // check Byte 4
+            (((SB1 & 0x0E) != 0x08) && ((SA1 & 0xC0) == 0x80)) || // check Byte 4 (one finger pressed)
+            (((SA1 & 0xC0) != 0x80) && (( C1 & 0xF0) != 0x00))  ) // check Byte 5
+               // error detected
+
+For all the other ones, there are just a few constant bits:
+        if( ((packet[0] & 0x0C) != 0x04) ||
+            ((packet[3] & 0x0f) != 0x02) )
+               // error detected
+
+
+In case an error is detected, all the packets are shifted by one (and packet[0] is discarded).
+
+5.2.1 One/Three finger touch
       ~~~~~~~~~~~~~~~~
 
 byte 0:
 
    bit   7   6   5   4   3   2   1   0
-        n1  n0   .   .   .   .   R   L
+        n1  n0  w3  w2   .   .   R   L
 
          L, R = 1 when Left, Right mouse button pressed
          n1..n0 = numbers of fingers on touchpad
@@ -333,24 +389,40 @@ byte 0:
 byte 1:
 
    bit   7   6   5   4   3   2   1   0
-         .   .   .   .   .  x10 x9  x8
+        p7  p6  p5  p4  .  x10 x9  x8
 
 byte 2:
 
    bit   7   6   5   4   3   2   1   0
-        x7  x6  x5  x4  x4  x2  x1  x0
+        x7  x6  x5  x4  x3  x2  x1  x0
 
          x10..x0 = absolute x value (horizontal)
 
 byte 3:
 
    bit   7   6   5   4   3   2   1   0
-         .   .   .   .   .   .   .   .
+        n4  vf  w1  w0   .   .   .  b2
+
+        n4 = set if more than 3 fingers (only in 3 fingers mode)
+        vf = a kind of flag ? (only on EF123, 0 when finger is over one
+             of the buttons, 1 otherwise)
+        w3..w0 = width of the finger touch (not EF113)
+        b2 (on EF113 only, 0 otherwise), b2.R.L indicates one button pressed:
+               0 = none
+               1 = Left
+               2 = Right
+               3 = Middle (Left and Right)
+               4 = Forward
+               5 = Back
+               6 = Another one
+               7 = Another one
 
 byte 4:
 
    bit   7   6   5   4   3   2   1   0
-         .   .   .   .   .   .  y9  y8
+        p3  p1  p2  p0   .   .  y9  y8
+
+        p7..p0 = pressure (not EF113)
 
 byte 5:
 
@@ -363,6 +435,11 @@ byte 5:
 4.2.2 Two finger touch
       ~~~~~~~~~~~~~~~~
 
+Note that the two pairs of coordinates are not exactly the coordinates of the
+two fingers, but only the pair of the lower-left and upper-right coordinates.
+So the actual fingers might be situated on the other diagonal of the square
+defined by these two points.
+
 byte 0:
 
    bit   7   6   5   4   3   2   1   0
@@ -376,14 +453,14 @@ byte 1:
    bit   7   6   5   4   3   2   1   0
         ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0
 
-         ax8..ax0 = first finger absolute x value
+        ax8..ax0 = lower-left finger absolute x value
 
 byte 2:
 
    bit   7   6   5   4   3   2   1   0
         ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0
 
-         ay8..ay0 = first finger absolute y value
+        ay8..ay0 = lower-left finger absolute y value
 
 byte 3:
 
@@ -395,11 +472,11 @@ byte 4:
    bit   7   6   5   4   3   2   1   0
         bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0
 
-         bx8..bx0 = second finger absolute x value
+         bx8..bx0 = upper-right finger absolute x value
 
 byte 5:
 
    bit   7   6   5   4   3   2   1   0
         by7 by8 by5 by4 by3 by2 by1 by0
 
-         by8..by0 = second finger absolute y value
+         by8..by0 = upper-right finger absolute y value
index 943e8f6f2b15fdcc491441d20e30854fd56f1803..92e68bce13a40ce2042326d287093c3ad41f7ad2 100644 (file)
@@ -9,6 +9,9 @@ peripherals with two wires. The outputs are phase-shifted by 90 degrees
 and by triggering on falling and rising edges, the turn direction can
 be determined.
 
+Some encoders have both outputs low in stable states, whereas others also have
+a stable state with both outputs high (half-period mode).
+
 The phase diagram of these two outputs look like this:
 
                   _____       _____       _____
@@ -26,6 +29,8 @@ The phase diagram of these two outputs look like this:
                 |<-------->|
                  one step
 
+                |<-->|
+                 one step (half-period mode)
 
 For more information, please see
        http://en.wikipedia.org/wiki/Rotary_encoder
@@ -34,6 +39,13 @@ For more information, please see
 1. Events / state machine
 -------------------------
 
+In half-period mode, state a) and c) above are used to determine the
+rotational direction based on the last stable state. Events are reported in
+states b) and d) given that the new stable state is different from the last
+(i.e. the rotation was not reversed half-way).
+
+Otherwise, the following apply:
+
 a) Rising edge on channel A, channel B in low state
        This state is used to recognize a clockwise turn
 
@@ -96,6 +108,7 @@ static struct rotary_encoder_platform_data my_rotary_encoder_info = {
        .gpio_b         = GPIO_ROTARY_B,
        .inverted_a     = 0,
        .inverted_b     = 0,
+       .half_period    = false,
 };
 
 static struct platform_device rotary_encoder_device = {
index 2d1ad12e2b3ec783c186a81b3763ea4d3f8ce3cb..3a46e360496dd6798fbcf9f1e59e4eec9728e5d5 100644 (file)
@@ -304,6 +304,7 @@ Code  Seq#(hex)     Include File            Comments
 0xB0   all     RATIO devices           in development:
                                        <mailto:vgo@ratio.de>
 0xB1   00-1F   PPPoX                   <mailto:mostrows@styx.uwaterloo.ca>
+0xB3   00      linux/mmc/ioctl.h
 0xC0   00-0F   linux/usb/iowarrior.h
 0xCB   00-1F   CBM serial IEC bus      in development:
                                        <mailto:michael.klein@puffin.lb.shuttle.de>
index 7c2a89ba674c3b6cd230f95d4327710acc652c72..68e32bb6bd807df797dd52204af2b973d021e0a6 100644 (file)
@@ -201,3 +201,16 @@ KBUILD_ENABLE_EXTRA_GCC_CHECKS
 --------------------------------------------------
 If enabled over the make command line with "W=1", it turns on additional
 gcc -W... options for more extensive build-time checking.
+
+KBUILD_BUILD_TIMESTAMP
+--------------------------------------------------
+Setting this to a date string overrides the timestamp used in the
+UTS_VERSION definition (uname -v in the running kernel). The value has to
+be a string that can be passed to date -d. The default value
+is the output of the date command at one point during build.
+
+KBUILD_BUILD_USER, KBUILD_BUILD_HOST
+--------------------------------------------------
+These two variables allow to override the user@host string displayed during
+boot and in /proc/version. The default value is the output of the commands
+whoami and host, respectively.
index b507d61fd41cd6a20157dca27f38a28b98f4fa1d..44e2649fbb295db936245c4c0de09109738bfc5e 100644 (file)
@@ -113,6 +113,13 @@ applicable everywhere (see syntax).
        That will limit the usefulness but on the other hand avoid
        the illegal configurations all over.
 
+- limiting menu display: "visible if" <expr>
+  This attribute is only applicable to menu blocks, if the condition is
+  false, the menu block is not displayed to the user (the symbols
+  contained there can still be selected by other symbols, though). It is
+  similar to a conditional "prompt" attribude for individual menu
+  entries. Default value of "visible" is true.
+
 - numerical ranges: "range" <symbol> <symbol> ["if" <expr>]
   This allows to limit the range of possible input values for int
   and hex symbols. The user can only input a value which is larger than
@@ -303,7 +310,8 @@ menu:
        "endmenu"
 
 This defines a menu block, see "Menu structure" above for more
-information. The only possible options are dependencies.
+information. The only possible options are dependencies and "visible"
+attributes.
 
 if:
 
@@ -381,3 +389,25 @@ config FOO
 
 limits FOO to module (=m) or disabled (=n).
 
+Kconfig symbol existence
+~~~~~~~~~~~~~~~~~~~~~~~~
+The following two methods produce the same kconfig symbol dependencies
+but differ greatly in kconfig symbol existence (production) in the
+generated config file.
+
+case 1:
+
+config FOO
+       tristate "about foo"
+       depends on BAR
+
+vs. case 2:
+
+if BAR
+config FOO
+       tristate "about foo"
+endif
+
+In case 1, the symbol FOO will always exist in the config file (given
+no other dependencies).  In case 2, the symbol FOO will only exist in
+the config file if BAR is enabled.
index cca46b1a0f6c2a33f4a39ea87f49a4ae91585c2c..c313d71324b4a83db6934114e86af7eed0f30be6 100644 (file)
@@ -48,11 +48,6 @@ KCONFIG_OVERWRITECONFIG
 If you set KCONFIG_OVERWRITECONFIG in the environment, Kconfig will not
 break symlinks when .config is a symlink to somewhere else.
 
-KCONFIG_NOTIMESTAMP
---------------------------------------------------
-If this environment variable exists and is non-null, the timestamp line
-in generated .config files is omitted.
-
 ______________________________________________________________________
 Environment variables for '{allyes/allmod/allno/rand}config'
 
index 5d145bb443c0a87957eb37cbb75c4ffb7543623f..47435e56c5dae3970468003034decf2698caa0e6 100644 (file)
@@ -40,11 +40,13 @@ This document describes the Linux kernel Makefiles.
           --- 6.6 Commands useful for building a boot image
           --- 6.7 Custom kbuild commands
           --- 6.8 Preprocessing linker scripts
+          --- 6.9 Generic header files
 
        === 7 Kbuild syntax for exported headers
                --- 7.1 header-y
                --- 7.2 objhdr-y
                --- 7.3 destination-y
+               --- 7.4 generic-y
 
        === 8 Kbuild Variables
        === 9 Makefile language
@@ -499,6 +501,18 @@ more details, with real examples.
        gcc >= 3.00. For gcc < 3.00, -malign-functions=4 is used.
        Note: cc-option-align uses KBUILD_CFLAGS for $(CC) options
 
+    cc-disable-warning
+       cc-disable-warning checks if gcc supports a given warning and returns
+       the commandline switch to disable it. This special function is needed,
+       because gcc 4.4 and later accept any unknown -Wno-* option and only
+       warn about it if there is another warning in the source file.
+
+       Example:
+               KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable)
+
+       In the above example, -Wno-unused-but-set-variable will be added to
+       KBUILD_CFLAGS only if gcc really accepts it.
+
     cc-version
        cc-version returns a numerical version of the $(CC) compiler version.
        The format is <major><minor> where both are two digits. So for example
@@ -955,6 +969,11 @@ When kbuild executes, the following steps are followed (roughly):
        used when linking modules. This is often a linker script.
        From commandline LDFLAGS_MODULE shall be used (see kbuild.txt).
 
+    KBUILD_ARFLAGS   Options for $(AR) when creating archives
+
+       $(KBUILD_ARFLAGS) set by the top level Makefile to "D" (deterministic
+       mode) if this option is supported by $(AR).
+
 --- 6.2 Add prerequisites to archprepare:
 
        The archprepare: rule is used to list prerequisites that need to be
@@ -1209,6 +1228,14 @@ When kbuild executes, the following steps are followed (roughly):
        The kbuild infrastructure for *lds file are used in several
        architecture-specific files.
 
+--- 6.9 Generic header files
+
+       The directory include/asm-generic contains the header files
+       that may be shared between individual architectures.
+       The recommended approach how to use a generic header file is
+       to list the file in the Kbuild file.
+       See "7.4 generic-y" for further info on syntax etc.
+
 === 7 Kbuild syntax for exported headers
 
 The kernel include a set of headers that is exported to userspace.
@@ -1265,6 +1292,32 @@ See subsequent chapter for the syntax of the Kbuild file.
        In the example above all exported headers in the Kbuild file
        will be located in the directory "include/linux" when exported.
 
+       --- 7.4 generic-y
+
+       If an architecture uses a verbatim copy of a header from
+       include/asm-generic then this is listed in the file
+       arch/$(ARCH)/include/asm/Kbuild like this:
+
+               Example:
+                       #arch/x86/include/asm/Kbuild
+                       generic-y += termios.h
+                       generic-y += rtc.h
+
+       During the prepare phase of the build a wrapper include
+       file is generated in the directory:
+
+               arch/$(ARCH)/include/generated/asm
+
+       When a header is exported where the architecture uses
+       the generic header a similar wrapper is generated as part
+       of the set of exported headers in the directory:
+
+               usr/include/asm
+
+       The generated wrapper will in both cases look like the following:
+
+               Example: termios.h
+                       #include <asm-generic/termios.h>
 
 === 8 Kbuild Variables
 
index 7c6624e7a5cb50f80bcc1d92e010d8896ec92956..fd248a318211a189163f2c42ba911a44284ea0bc 100644 (file)
@@ -999,7 +999,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        With this option on every unmap_single operation will
                        result in a hardware IOTLB flush operation as opposed
                        to batching them for performance.
-
+               sp_off [Default Off]
+                       By default, super page will be supported if Intel IOMMU
+                       has the capability. With this option, super page will
+                       not be supported.
        intremap=       [X86-64, Intel-IOMMU]
                        Format: { on (default) | off | nosid }
                        on      enable Interrupt Remapping (default)
@@ -1777,9 +1780,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        nosoftlockup    [KNL] Disable the soft-lockup detector.
 
-       noswapaccount   [KNL] Disable accounting of swap in memory resource
-                       controller. (See Documentation/cgroups/memory.txt)
-
        nosync          [HW,M68K] Disables sync negotiation for all devices.
 
        notsc           [BUGS=X86-32] Disable Time Stamp Counter
@@ -2598,6 +2598,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                                        unlock ejectable media);
                                m = MAX_SECTORS_64 (don't transfer more
                                        than 64 sectors = 32 KB at a time);
+                               n = INITIAL_READ10 (force a retry of the
+                                       initial READ(10) command);
                                o = CAPACITY_OK (accept the capacity
                                        reported by the device);
                                r = IGNORE_RESIDUE (the device reports
index 090e6ee04536285398a81257e1f9a1f9d34e398d..51063e681ca4f8cc0b628d2a46503ad1762aeaf5 100644 (file)
@@ -11,7 +11,9 @@ with the difference that the orphan objects are not freed but only
 reported via /sys/kernel/debug/kmemleak. A similar method is used by the
 Valgrind tool (memcheck --leak-check) to detect the memory leaks in
 user-space applications.
-Kmemleak is supported on x86, arm, powerpc, sparc, sh, microblaze and tile.
+
+Please check DEBUG_KMEMLEAK dependencies in lib/Kconfig.debug for supported
+architectures.
 
 Usage
 -----
diff --git a/Documentation/laptops/acer-wmi.txt b/Documentation/laptops/acer-wmi.txt
deleted file mode 100644 (file)
index 4beafa6..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-Acer Laptop WMI Extras Driver
-http://code.google.com/p/aceracpi
-Version 0.3
-4th April 2009
-
-Copyright 2007-2009 Carlos Corbacho <carlos@strangeworlds.co.uk>
-
-acer-wmi is a driver to allow you to control various parts of your Acer laptop
-hardware under Linux which are exposed via ACPI-WMI.
-
-This driver completely replaces the old out-of-tree acer_acpi, which I am
-currently maintaining for bug fixes only on pre-2.6.25 kernels. All development
-work is now focused solely on acer-wmi.
-
-Disclaimer
-**********
-
-Acer and Wistron have provided nothing towards the development acer_acpi or
-acer-wmi. All information we have has been through the efforts of the developers
-and the users to discover as much as possible about the hardware.
-
-As such, I do warn that this could break your hardware - this is extremely
-unlikely of course, but please bear this in mind.
-
-Background
-**********
-
-acer-wmi is derived from acer_acpi, originally developed by Mark
-Smith in 2005, then taken over by Carlos Corbacho in 2007, in order to activate
-the wireless LAN card under a 64-bit version of Linux, as acerhk[1] (the
-previous solution to the problem) relied on making 32 bit BIOS calls which are
-not possible in kernel space from a 64 bit OS.
-
-[1] acerhk: http://www.cakey.de/acerhk/
-
-Supported Hardware
-******************
-
-NOTE: The Acer Aspire One is not supported hardware. It cannot work with
-acer-wmi until Acer fix their ACPI-WMI implementation on them, so has been
-blacklisted until that happens.
-
-Please see the website for the current list of known working hardware:
-
-http://code.google.com/p/aceracpi/wiki/SupportedHardware
-
-If your laptop is not listed, or listed as unknown, and works with acer-wmi,
-please contact me with a copy of the DSDT.
-
-If your Acer laptop doesn't work with acer-wmi, I would also like to see the
-DSDT.
-
-To send me the DSDT, as root/sudo:
-
-cat /sys/firmware/acpi/tables/DSDT > dsdt
-
-And send me the resulting 'dsdt' file.
-
-Usage
-*****
-
-On Acer laptops, acer-wmi should already be autoloaded based on DMI matching.
-For non-Acer laptops, until WMI based autoloading support is added, you will
-need to manually load acer-wmi.
-
-acer-wmi creates /sys/devices/platform/acer-wmi, and fills it with various
-files whose usage is detailed below, which enables you to control some of the
-following (varies between models):
-
-* the wireless LAN card radio
-* inbuilt Bluetooth adapter
-* inbuilt 3G card
-* mail LED of your laptop
-* brightness of the LCD panel
-
-Wireless
-********
-
-With regards to wireless, all acer-wmi does is enable the radio on the card. It
-is not responsible for the wireless LED - once the radio is enabled, this is
-down to the wireless driver for your card. So the behaviour of the wireless LED,
-once you enable the radio, will depend on your hardware and driver combination.
-
-e.g. With the BCM4318 on the Acer Aspire 5020 series:
-
-ndiswrapper: Light blinks on when transmitting
-b43: Solid light, blinks off when transmitting
-
-Wireless radio control is unconditionally enabled - all Acer laptops that support
-acer-wmi come with built-in wireless. However, should you feel so inclined to
-ever wish to remove the card, or swap it out at some point, please get in touch
-with me, as we may well be able to gain some data on wireless card detection.
-
-The wireless radio is exposed through rfkill.
-
-Bluetooth
-*********
-
-For bluetooth, this is an internal USB dongle, so once enabled, you will get
-a USB device connection event, and a new USB device appears. When you disable
-bluetooth, you get the reverse - a USB device disconnect event, followed by the
-device disappearing again.
-
-Bluetooth is autodetected by acer-wmi, so if you do not have a bluetooth module
-installed in your laptop, this file won't exist (please be aware that it is
-quite common for Acer not to fit bluetooth to their laptops - so just because
-you have a bluetooth button on the laptop, doesn't mean that bluetooth is
-installed).
-
-For the adventurously minded - if you want to buy an internal bluetooth
-module off the internet that is compatible with your laptop and fit it, then
-it will work just fine with acer-wmi.
-
-Bluetooth is exposed through rfkill.
-
-3G
-**
-
-3G is currently not autodetected, so the 'threeg' file is always created under
-sysfs. So far, no-one in possession of an Acer laptop with 3G built-in appears to
-have tried Linux, or reported back, so we don't have any information on this.
-
-If you have an Acer laptop that does have a 3G card in, please contact me so we
-can properly detect these, and find out a bit more about them.
-
-To read the status of the 3G card (0=off, 1=on):
-cat /sys/devices/platform/acer-wmi/threeg
-
-To enable the 3G card:
-echo 1 > /sys/devices/platform/acer-wmi/threeg
-
-To disable the 3G card:
-echo 0 > /sys/devices/platform/acer-wmi/threeg
-
-To set the state of the 3G card when loading acer-wmi, pass:
-threeg=X (where X is 0 or 1)
-
-Mail LED
-********
-
-This can be found in most older Acer laptops supported by acer-wmi, and many
-newer ones - it is built into the 'mail' button, and blinks when active.
-
-On newer (WMID) laptops though, we have no way of detecting the mail LED. If
-your laptop identifies itself in dmesg as a WMID model, then please try loading
-acer_acpi with:
-
-force_series=2490
-
-This will use a known alternative method of reading/ writing the mail LED. If
-it works, please report back to me with the DMI data from your laptop so this
-can be added to acer-wmi.
-
-The LED is exposed through the LED subsystem, and can be found in:
-
-/sys/devices/platform/acer-wmi/leds/acer-wmi::mail/
-
-The mail LED is autodetected, so if you don't have one, the LED device won't
-be registered.
-
-Backlight
-*********
-
-The backlight brightness control is available on all acer-wmi supported
-hardware. The maximum brightness level is usually 15, but on some newer laptops
-it's 10 (this is again autodetected).
-
-The backlight is exposed through the backlight subsystem, and can be found in:
-
-/sys/devices/platform/acer-wmi/backlight/acer-wmi/
-
-Credits
-*******
-
-Olaf Tauber, who did the real hard work when he developed acerhk
-http://www.cakey.de/acerhk/
-All the authors of laptop ACPI modules in the kernel, whose work
-was an inspiration in the early days of acer_acpi
-Mathieu Segaud, who solved the problem with having to modprobe the driver
-twice in acer_acpi 0.2.
-Jim Ramsay, who added support for the WMID interface
-Mark Smith, who started the original acer_acpi
-
-And the many people who have used both acer_acpi and acer-wmi.
index 65f4c795015dead0cfde0f60381b7efcec67da9b..cef00d42ed5be272fdeffb89e1eede3c931ef25b 100644 (file)
@@ -12,8 +12,9 @@ Because things like lock contention can severely impact performance.
 - HOW
 
 Lockdep already has hooks in the lock functions and maps lock instances to
-lock classes. We build on that. The graph below shows the relation between
-the lock functions and the various hooks therein.
+lock classes. We build on that (see Documentation/lockdep-design.txt).
+The graph below shows the relation between the lock functions and the various
+hooks therein.
 
         __acquire
             |
@@ -128,6 +129,37 @@ points are the points we're contending with.
 
 The integer part of the time values is in us.
 
+Dealing with nested locks, subclasses may appear:
+
+32...............................................................................................................................................................................................
+33
+34                               &rq->lock:         13128          13128           0.43         190.53      103881.26          97454        3453404           0.00         401.11    13224683.11
+35                               ---------
+36                               &rq->lock            645          [<ffffffff8103bfc4>] task_rq_lock+0x43/0x75
+37                               &rq->lock            297          [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
+38                               &rq->lock            360          [<ffffffff8103c4c5>] select_task_rq_fair+0x1f0/0x74a
+39                               &rq->lock            428          [<ffffffff81045f98>] scheduler_tick+0x46/0x1fb
+40                               ---------
+41                               &rq->lock             77          [<ffffffff8103bfc4>] task_rq_lock+0x43/0x75
+42                               &rq->lock            174          [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
+43                               &rq->lock           4715          [<ffffffff8103ed4b>] double_rq_lock+0x42/0x54
+44                               &rq->lock            893          [<ffffffff81340524>] schedule+0x157/0x7b8
+45
+46...............................................................................................................................................................................................
+47
+48                             &rq->lock/1:         11526          11488           0.33         388.73      136294.31          21461          38404           0.00          37.93      109388.53
+49                             -----------
+50                             &rq->lock/1          11526          [<ffffffff8103ed58>] double_rq_lock+0x4f/0x54
+51                             -----------
+52                             &rq->lock/1           5645          [<ffffffff8103ed4b>] double_rq_lock+0x42/0x54
+53                             &rq->lock/1           1224          [<ffffffff81340524>] schedule+0x157/0x7b8
+54                             &rq->lock/1           4336          [<ffffffff8103ed58>] double_rq_lock+0x4f/0x54
+55                             &rq->lock/1            181          [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
+
+Line 48 shows statistics for the second subclass (/1) of &rq->lock class
+(subclass starts from 0), since in this case, as line 50 suggests,
+double_rq_lock actually acquires a nested lock of two spinlocks.
+
 View the top contending locks:
 
 # grep : /proc/lock_stat | head
@@ -136,7 +168,7 @@ View the top contending locks:
                              dcache_lock:          1037           1161           0.38          45.32         774.51           6611         243371           0.15         306.48       77387.24
                          &inode->i_mutex:           161            286 18446744073709       62882.54     1244614.55           3653          20598 18446744073709       62318.60     1693822.74
                          &zone->lru_lock:            94             94           0.53           7.33          92.10           4366          32690           0.29          59.81       16350.06
-              &inode->i_data.i_mmap_lock:            79             79           0.40           3.77          53.03          11779          87755           0.28         116.93       29898.44
+              &inode->i_data.i_mmap_mutex:            79             79           0.40           3.77          53.03          11779          87755           0.28         116.93       29898.44
                         &q->__queue_lock:            48             50           0.52          31.62          86.31            774          13131           0.17         113.08       12277.52
                         &rq->rq_lock_key:            43             47           0.74          68.50         170.63           3706          33929           0.22         107.99       17460.62
                       &rq->rq_lock_key#2:            39             46           0.75           6.68          49.03           2979          32292           0.17         125.17       17137.63
index 2366b1c8cf19492f52480669449ecd2b0a0d0f34..f0eee83ff78a61801e7d0cf293a2090180f208e8 100644 (file)
@@ -555,7 +555,7 @@ also have
    sync_min
    sync_max
      The two values, given as numbers of sectors, indicate a range
-     withing the array where 'check'/'repair' will operate. Must be
+     within the array where 'check'/'repair' will operate. Must be
      a multiple of chunk_size. When it reaches "sync_max" it will
      pause, rather than complete.
      You can use 'select' or 'poll' on "sync_completed" to wait for
index fca586f5b8539cb8dac5c22bfbbe0fa5f4987bb4..93dd7a714075bee668b0b425b81e9c133b8a8292 100644 (file)
@@ -2,3 +2,5 @@
         - this file
 mmc-dev-attrs.txt
         - info on SD and MMC device attributes
+mmc-dev-parts.txt
+        - info on SD and MMC device partitions
index ff2bd685bced95526ab79e66859cd2697b0f5d1f..8898a95b41e5ee1b277cd64697870726b11bc2fa 100644 (file)
@@ -1,3 +1,13 @@
+SD and MMC Block Device Attributes
+==================================
+
+These attributes are defined for the block devices associated with the
+SD or MMC device.
+
+The following attributes are read/write.
+
+       force_ro                Enforce read-only access even if write protect switch is off.
+
 SD and MMC Device Attributes
 ============================
 
diff --git a/Documentation/mmc/mmc-dev-parts.txt b/Documentation/mmc/mmc-dev-parts.txt
new file mode 100644 (file)
index 0000000..2db28b8
--- /dev/null
@@ -0,0 +1,27 @@
+SD and MMC Device Partitions
+============================
+
+Device partitions are additional logical block devices present on the
+SD/MMC device.
+
+As of this writing, MMC boot partitions as supported and exposed as
+/dev/mmcblkXboot0 and /dev/mmcblkXboot1, where X is the index of the
+parent /dev/mmcblkX.
+
+MMC Boot Partitions
+===================
+
+Read and write access is provided to the two MMC boot partitions. Due to
+the sensitive nature of the boot partition contents, which often store
+a bootloader or bootloader configuration tables crucial to booting the
+platform, write access is disabled by default to reduce the chance of
+accidental bricking.
+
+To enable write access to /dev/mmcblkXbootY, disable the forced read-only
+access with:
+
+echo 0 > /sys/block/mmcblkXbootY/force_ro
+
+To re-enable read-only access:
+
+echo 1 > /sys/block/mmcblkXbootY/force_ro
index 1f45bd887d65615621ac5443875dc81097166f10..675612ff41ae2b902d89ad93e6404515f2bdef19 100644 (file)
@@ -770,8 +770,17 @@ resend_igmp
        a failover event. One membership report is issued immediately after
        the failover, subsequent packets are sent in each 200ms interval.
 
-       The valid range is 0 - 255; the default value is 1. This option
-       was added for bonding version 3.7.0.
+       The valid range is 0 - 255; the default value is 1. A value of 0
+       prevents the IGMP membership report from being issued in response
+       to the failover event.
+
+       This option is useful for bonding modes balance-rr (0), active-backup
+       (1), balance-tlb (5) and balance-alb (6), in which a failover can
+       switch the IGMP traffic from one slave to another.  Therefore a fresh
+       IGMP report must be issued to cause the switch to forward the incoming
+       IGMP traffic over the newly selected slave.
+
+       This option was added for bonding version 3.7.0.
 
 3. Configuring Bonding Devices
 ==============================
index 04ca06325b087157b8f21afb3f571350b7e5ef3f..7f531ad83285ced1d2cc24d513d611e0c8156c47 100644 (file)
@@ -139,8 +139,8 @@ the key will be discarded and recreated when the data it holds has expired.
 dns_query() returns a copy of the value attached to the key, or an error if
 that is indicated instead.
 
-See <file:Documentation/keys-request-key.txt> for further information about
-request-key function.
+See <file:Documentation/security/keys-request-key.txt> for further
+information about request-key function.
 
 
 =========
index 88880839ece4e84f8101b4cfd50e3e22b8024515..64565aac6e4009b1bca8f963cf03f900e319d538 100644 (file)
@@ -520,59 +520,20 @@ Support for power domains is provided through the pwr_domain field of struct
 device.  This field is a pointer to an object of type struct dev_power_domain,
 defined in include/linux/pm.h, providing a set of power management callbacks
 analogous to the subsystem-level and device driver callbacks that are executed
-for the given device during all power transitions, in addition to the respective
-subsystem-level callbacks.  Specifically, the power domain "suspend" callbacks
-(i.e. ->runtime_suspend(), ->suspend(), ->freeze(), ->poweroff(), etc.) are
-executed after the analogous subsystem-level callbacks, while the power domain
-"resume" callbacks (i.e. ->runtime_resume(), ->resume(), ->thaw(), ->restore,
-etc.) are executed before the analogous subsystem-level callbacks.  Error codes
-returned by the "suspend" and "resume" power domain callbacks are ignored.
-
-Power domain ->runtime_idle() callback is executed before the subsystem-level
-->runtime_idle() callback and the result returned by it is not ignored.  Namely,
-if it returns error code, the subsystem-level ->runtime_idle() callback will not
-be called and the helper function rpm_idle() executing it will return error
-code.  This mechanism is intended to help platforms where saving device state
-is a time consuming operation and should only be carried out if all devices
-in the power domain are idle, before turning off the shared power resource(s).
-Namely, the power domain ->runtime_idle() callback may return error code until
-the pm_runtime_idle() helper (or its asychronous version) has been called for
-all devices in the power domain (it is recommended that the returned error code
-be -EBUSY in those cases), preventing the subsystem-level ->runtime_idle()
-callback from being run prematurely.
-
-The support for device power domains is only relevant to platforms needing to
-use the same subsystem-level (e.g. platform bus type) and device driver power
-management callbacks in many different power domain configurations and wanting
-to avoid incorporating the support for power domains into the subsystem-level
-callbacks.  The other platforms need not implement it or take it into account
-in any way.
-
-
-System Devices
---------------
-System devices (sysdevs) follow a slightly different API, which can be found in
-
-       include/linux/sysdev.h
-       drivers/base/sys.c
-
-System devices will be suspended with interrupts disabled, and after all other
-devices have been suspended.  On resume, they will be resumed before any other
-devices, and also with interrupts disabled.  These things occur in special
-"sysdev_driver" phases, which affect only system devices.
-
-Thus, after the suspend_noirq (or freeze_noirq or poweroff_noirq) phase, when
-the non-boot CPUs are all offline and IRQs are disabled on the remaining online
-CPU, then a sysdev_driver.suspend phase is carried out, and the system enters a
-sleep state (or a system image is created).  During resume (or after the image
-has been created or loaded) a sysdev_driver.resume phase is carried out, IRQs
-are enabled on the only online CPU, the non-boot CPUs are enabled, and the
-resume_noirq (or thaw_noirq or restore_noirq) phase begins.
-
-Code to actually enter and exit the system-wide low power state sometimes
-involves hardware details that are only known to the boot firmware, and
-may leave a CPU running software (from SRAM or flash memory) that monitors
-the system and manages its wakeup sequence.
+for the given device during all power transitions, instead of the respective
+subsystem-level callbacks.  Specifically, if a device's pm_domain pointer is
+not NULL, the ->suspend() callback from the object pointed to by it will be
+executed instead of its subsystem's (e.g. bus type's) ->suspend() callback and
+anlogously for all of the remaining callbacks.  In other words, power management
+domain callbacks, if defined for the given device, always take precedence over
+the callbacks provided by the device's subsystem (e.g. bus type).
+
+The support for device power management domains is only relevant to platforms
+needing to use the same device driver power management callbacks in many
+different power domain configurations and wanting to avoid incorporating the
+support for power domains into subsystem-level callbacks, for example by
+modifying the platform bus type.  Other platforms need not implement it or take
+it into account in any way.
 
 
 Device Low Power (suspend) States
index bdec39b9bd757612c937add6fc0fc9fe87322e27..b42419b52e444063841bcd6f0571ea0cde1eca84 100644 (file)
@@ -53,11 +53,11 @@ static struct regulator_init_data regulator1_data = {
 
 Regulator-1 supplies power to Regulator-2. This relationship must be registered
 with the core so that Regulator-1 is also enabled when Consumer A enables its
-supply (Regulator-2). The supply regulator is set by the supply_regulator_dev
+supply (Regulator-2). The supply regulator is set by the supply_regulator
 field below:-
 
 static struct regulator_init_data regulator2_data = {
-       .supply_regulator_dev = &platform_regulator1_device.dev,
+       .supply_regulator = "regulator_name",
        .constraints = {
                .min_uV = 1800000,
                .max_uV = 2000000,
index 654097b130b46175c4c5165ded5f535718266cc7..22accb3eb40e293c777d6898cb63cb2ce9f5bd91 100644 (file)
@@ -566,11 +566,6 @@ to do this is:
        pm_runtime_set_active(dev);
        pm_runtime_enable(dev);
 
-The PM core always increments the run-time usage counter before calling the
-->prepare() callback and decrements it after calling the ->complete() callback.
-Hence disabling run-time PM temporarily like this will not cause any run-time
-suspend callbacks to be lost.
-
 7. Generic subsystem callbacks
 
 Subsystems may wish to conserve code space by using the set of generic power
index 1b5a5ddbc3ef9a5211f3e7eeb487e524ac6ac0ac..5df176ed59b826e8cbeaca7c96d6ed6d06759fa8 100644 (file)
@@ -9,7 +9,121 @@ If variable is of Type,               use printk format specifier:
                size_t                  %zu or %zx
                ssize_t                 %zd or %zx
 
-Raw pointer value SHOULD be printed with %p.
+Raw pointer value SHOULD be printed with %p. The kernel supports
+the following extended format specifiers for pointer types:
+
+Symbols/Function Pointers:
+
+       %pF     versatile_init+0x0/0x110
+       %pf     versatile_init
+       %pS     versatile_init+0x0/0x110
+       %ps     versatile_init
+       %pB     prev_fn_of_versatile_init+0x88/0x88
+
+       For printing symbols and function pointers. The 'S' and 's' specifiers
+       result in the symbol name with ('S') or without ('s') offsets. Where
+       this is used on a kernel without KALLSYMS - the symbol address is
+       printed instead.
+
+       The 'B' specifier results in the symbol name with offsets and should be
+       used when printing stack backtraces. The specifier takes into
+       consideration the effect of compiler optimisations which may occur
+       when tail-call's are used and marked with the noreturn GCC attribute.
+
+       On ia64, ppc64 and parisc64 architectures function pointers are
+       actually function descriptors which must first be resolved. The 'F' and
+       'f' specifiers perform this resolution and then provide the same
+       functionality as the 'S' and 's' specifiers.
+
+Kernel Pointers:
+
+       %pK     0x01234567 or 0x0123456789abcdef
+
+       For printing kernel pointers which should be hidden from unprivileged
+       users. The behaviour of %pK depends on the kptr_restrict sysctl - see
+       Documentation/sysctl/kernel.txt for more details.
+
+Struct Resources:
+
+       %pr     [mem 0x60000000-0x6fffffff flags 0x2200] or
+               [mem 0x0000000060000000-0x000000006fffffff flags 0x2200]
+       %pR     [mem 0x60000000-0x6fffffff pref] or
+               [mem 0x0000000060000000-0x000000006fffffff pref]
+
+       For printing struct resources. The 'R' and 'r' specifiers result in a
+       printed resource with ('R') or without ('r') a decoded flags member.
+
+MAC/FDDI addresses:
+
+       %pM     00:01:02:03:04:05
+       %pMF    00-01-02-03-04-05
+       %pm     000102030405
+
+       For printing 6-byte MAC/FDDI addresses in hex notation. The 'M' and 'm'
+       specifiers result in a printed address with ('M') or without ('m') byte
+       separators. The default byte separator is the colon (':').
+
+       Where FDDI addresses are concerned the 'F' specifier can be used after
+       the 'M' specifier to use dash ('-') separators instead of the default
+       separator.
+
+IPv4 addresses:
+
+       %pI4    1.2.3.4
+       %pi4    001.002.003.004
+       %p[Ii][hnbl]
+
+       For printing IPv4 dot-separated decimal addresses. The 'I4' and 'i4'
+       specifiers result in a printed address with ('i4') or without ('I4')
+       leading zeros.
+
+       The additional 'h', 'n', 'b', and 'l' specifiers are used to specify
+       host, network, big or little endian order addresses respectively. Where
+       no specifier is provided the default network/big endian order is used.
+
+IPv6 addresses:
+
+       %pI6    0001:0002:0003:0004:0005:0006:0007:0008
+       %pi6    00010002000300040005000600070008
+       %pI6c   1:2:3:4:5:6:7:8
+
+       For printing IPv6 network-order 16-bit hex addresses. The 'I6' and 'i6'
+       specifiers result in a printed address with ('I6') or without ('i6')
+       colon-separators. Leading zeros are always used.
+
+       The additional 'c' specifier can be used with the 'I' specifier to
+       print a compressed IPv6 address as described by
+       http://tools.ietf.org/html/rfc5952
+
+UUID/GUID addresses:
+
+       %pUb    00010203-0405-0607-0809-0a0b0c0d0e0f
+       %pUB    00010203-0405-0607-0809-0A0B0C0D0E0F
+       %pUl    03020100-0504-0706-0809-0a0b0c0e0e0f
+       %pUL    03020100-0504-0706-0809-0A0B0C0E0E0F
+
+       For printing 16-byte UUID/GUIDs addresses. The additional 'l', 'L',
+       'b' and 'B' specifiers are used to specify a little endian order in
+       lower ('l') or upper case ('L') hex characters - and big endian order
+       in lower ('b') or upper case ('B') hex characters.
+
+       Where no additional specifiers are used the default little endian
+       order with lower case hex characters will be printed.
+
+struct va_format:
+
+       %pV
+
+       For printing struct va_format structures. These contain a format string
+       and va_list as follows:
+
+       struct va_format {
+               const char *fmt;
+               va_list *va;
+       };
+
+       Do not use this feature without some mechanism to verify the
+       correctness of the format string and va_list arguments.
 
 u64 SHOULD be printed with %llu/%llx, (unsigned long long):
 
@@ -32,4 +146,5 @@ Reminder: sizeof() result is of type size_t.
 Thank you for your cooperation and attention.
 
 
-By Randy Dunlap <rdunlap@xenotime.net>
+By Randy Dunlap <rdunlap@xenotime.net> and
+Andrew Murray <amurray@mpc-data.co.uk>
diff --git a/Documentation/ptp/ptp.txt b/Documentation/ptp/ptp.txt
new file mode 100644 (file)
index 0000000..ae8fef8
--- /dev/null
@@ -0,0 +1,89 @@
+
+* PTP hardware clock infrastructure for Linux
+
+  This patch set introduces support for IEEE 1588 PTP clocks in
+  Linux. Together with the SO_TIMESTAMPING socket options, this
+  presents a standardized method for developing PTP user space
+  programs, synchronizing Linux with external clocks, and using the
+  ancillary features of PTP hardware clocks.
+
+  A new class driver exports a kernel interface for specific clock
+  drivers and a user space interface. The infrastructure supports a
+  complete set of PTP hardware clock functionality.
+
+  + Basic clock operations
+    - Set time
+    - Get time
+    - Shift the clock by a given offset atomically
+    - Adjust clock frequency
+
+  + Ancillary clock features
+    - One short or periodic alarms, with signal delivery to user program
+    - Time stamp external events
+    - Period output signals configurable from user space
+    - Synchronization of the Linux system time via the PPS subsystem
+
+** PTP hardware clock kernel API
+
+   A PTP clock driver registers itself with the class driver. The
+   class driver handles all of the dealings with user space. The
+   author of a clock driver need only implement the details of
+   programming the clock hardware. The clock driver notifies the class
+   driver of asynchronous events (alarms and external time stamps) via
+   a simple message passing interface.
+
+   The class driver supports multiple PTP clock drivers. In normal use
+   cases, only one PTP clock is needed. However, for testing and
+   development, it can be useful to have more than one clock in a
+   single system, in order to allow performance comparisons.
+
+** PTP hardware clock user space API
+
+   The class driver also creates a character device for each
+   registered clock. User space can use an open file descriptor from
+   the character device as a POSIX clock id and may call
+   clock_gettime, clock_settime, and clock_adjtime.  These calls
+   implement the basic clock operations.
+
+   User space programs may control the clock using standardized
+   ioctls. A program may query, enable, configure, and disable the
+   ancillary clock features. User space can receive time stamped
+   events via blocking read() and poll(). One shot and periodic
+   signals may be configured via the POSIX timer_settime() system
+   call.
+
+** Writing clock drivers
+
+   Clock drivers include include/linux/ptp_clock_kernel.h and register
+   themselves by presenting a 'struct ptp_clock_info' to the
+   registration method. Clock drivers must implement all of the
+   functions in the interface. If a clock does not offer a particular
+   ancillary feature, then the driver should just return -EOPNOTSUPP
+   from those functions.
+
+   Drivers must ensure that all of the methods in interface are
+   reentrant. Since most hardware implementations treat the time value
+   as a 64 bit integer accessed as two 32 bit registers, drivers
+   should use spin_lock_irqsave/spin_unlock_irqrestore to protect
+   against concurrent access. This locking cannot be accomplished in
+   class driver, since the lock may also be needed by the clock
+   driver's interrupt service routine.
+
+** Supported hardware
+
+   + Freescale eTSEC gianfar
+     - 2 Time stamp external triggers, programmable polarity (opt. interrupt)
+     - 2 Alarm registers (optional interrupt)
+     - 3 Periodic signals (optional interrupt)
+
+   + National DP83640
+     - 6 GPIOs programmable as inputs or outputs
+     - 6 GPIOs with dedicated functions (LED/JTAG/clock) can also be
+       used as general inputs or outputs
+     - GPIO inputs can time stamp external triggers
+     - GPIO outputs can produce periodic signals
+     - 1 interrupt pin
+
+   + Intel IXP465
+     - Auxiliary Slave/Master Mode Snapshot (optional interrupt)
+     - Target Time (optional interrupt)
diff --git a/Documentation/ptp/testptp.c b/Documentation/ptp/testptp.c
new file mode 100644 (file)
index 0000000..f59ded0
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * PTP 1588 clock support - User space test program
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/timex.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/ptp_clock.h>
+
+#define DEVICE "/dev/ptp0"
+
+#ifndef ADJ_SETOFFSET
+#define ADJ_SETOFFSET 0x0100
+#endif
+
+#ifndef CLOCK_INVALID
+#define CLOCK_INVALID -1
+#endif
+
+/* When glibc offers the syscall, this will go away. */
+#include <sys/syscall.h>
+static int clock_adjtime(clockid_t id, struct timex *tx)
+{
+       return syscall(__NR_clock_adjtime, id, tx);
+}
+
+static clockid_t get_clockid(int fd)
+{
+#define CLOCKFD 3
+#define FD_TO_CLOCKID(fd)      ((~(clockid_t) (fd) << 3) | CLOCKFD)
+
+       return FD_TO_CLOCKID(fd);
+}
+
+static void handle_alarm(int s)
+{
+       printf("received signal %d\n", s);
+}
+
+static int install_handler(int signum, void (*handler)(int))
+{
+       struct sigaction action;
+       sigset_t mask;
+
+       /* Unblock the signal. */
+       sigemptyset(&mask);
+       sigaddset(&mask, signum);
+       sigprocmask(SIG_UNBLOCK, &mask, NULL);
+
+       /* Install the signal handler. */
+       action.sa_handler = handler;
+       action.sa_flags = 0;
+       sigemptyset(&action.sa_mask);
+       sigaction(signum, &action, NULL);
+
+       return 0;
+}
+
+static long ppb_to_scaled_ppm(int ppb)
+{
+       /*
+        * The 'freq' field in the 'struct timex' is in parts per
+        * million, but with a 16 bit binary fractional field.
+        * Instead of calculating either one of
+        *
+        *    scaled_ppm = (ppb / 1000) << 16  [1]
+        *    scaled_ppm = (ppb << 16) / 1000  [2]
+        *
+        * we simply use double precision math, in order to avoid the
+        * truncation in [1] and the possible overflow in [2].
+        */
+       return (long) (ppb * 65.536);
+}
+
+static void usage(char *progname)
+{
+       fprintf(stderr,
+               "usage: %s [options]\n"
+               " -a val     request a one-shot alarm after 'val' seconds\n"
+               " -A val     request a periodic alarm every 'val' seconds\n"
+               " -c         query the ptp clock's capabilities\n"
+               " -d name    device to open\n"
+               " -e val     read 'val' external time stamp events\n"
+               " -f val     adjust the ptp clock frequency by 'val' ppb\n"
+               " -g         get the ptp clock time\n"
+               " -h         prints this message\n"
+               " -p val     enable output with a period of 'val' nanoseconds\n"
+               " -P val     enable or disable (val=1|0) the system clock PPS\n"
+               " -s         set the ptp clock time from the system time\n"
+               " -S         set the system time from the ptp clock time\n"
+               " -t val     shift the ptp clock time by 'val' seconds\n",
+               progname);
+}
+
+int main(int argc, char *argv[])
+{
+       struct ptp_clock_caps caps;
+       struct ptp_extts_event event;
+       struct ptp_extts_request extts_request;
+       struct ptp_perout_request perout_request;
+       struct timespec ts;
+       struct timex tx;
+
+       static timer_t timerid;
+       struct itimerspec timeout;
+       struct sigevent sigevent;
+
+       char *progname;
+       int c, cnt, fd;
+
+       char *device = DEVICE;
+       clockid_t clkid;
+       int adjfreq = 0x7fffffff;
+       int adjtime = 0;
+       int capabilities = 0;
+       int extts = 0;
+       int gettime = 0;
+       int oneshot = 0;
+       int periodic = 0;
+       int perout = -1;
+       int pps = -1;
+       int settime = 0;
+
+       progname = strrchr(argv[0], '/');
+       progname = progname ? 1+progname : argv[0];
+       while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghp:P:sSt:v"))) {
+               switch (c) {
+               case 'a':
+                       oneshot = atoi(optarg);
+                       break;
+               case 'A':
+                       periodic = atoi(optarg);
+                       break;
+               case 'c':
+                       capabilities = 1;
+                       break;
+               case 'd':
+                       device = optarg;
+                       break;
+               case 'e':
+                       extts = atoi(optarg);
+                       break;
+               case 'f':
+                       adjfreq = atoi(optarg);
+                       break;
+               case 'g':
+                       gettime = 1;
+                       break;
+               case 'p':
+                       perout = atoi(optarg);
+                       break;
+               case 'P':
+                       pps = atoi(optarg);
+                       break;
+               case 's':
+                       settime = 1;
+                       break;
+               case 'S':
+                       settime = 2;
+                       break;
+               case 't':
+                       adjtime = atoi(optarg);
+                       break;
+               case 'h':
+                       usage(progname);
+                       return 0;
+               case '?':
+               default:
+                       usage(progname);
+                       return -1;
+               }
+       }
+
+       fd = open(device, O_RDWR);
+       if (fd < 0) {
+               fprintf(stderr, "opening %s: %s\n", device, strerror(errno));
+               return -1;
+       }
+
+       clkid = get_clockid(fd);
+       if (CLOCK_INVALID == clkid) {
+               fprintf(stderr, "failed to read clock id\n");
+               return -1;
+       }
+
+       if (capabilities) {
+               if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
+                       perror("PTP_CLOCK_GETCAPS");
+               } else {
+                       printf("capabilities:\n"
+                              "  %d maximum frequency adjustment (ppb)\n"
+                              "  %d programmable alarms\n"
+                              "  %d external time stamp channels\n"
+                              "  %d programmable periodic signals\n"
+                              "  %d pulse per second\n",
+                              caps.max_adj,
+                              caps.n_alarm,
+                              caps.n_ext_ts,
+                              caps.n_per_out,
+                              caps.pps);
+               }
+       }
+
+       if (0x7fffffff != adjfreq) {
+               memset(&tx, 0, sizeof(tx));
+               tx.modes = ADJ_FREQUENCY;
+               tx.freq = ppb_to_scaled_ppm(adjfreq);
+               if (clock_adjtime(clkid, &tx)) {
+                       perror("clock_adjtime");
+               } else {
+                       puts("frequency adjustment okay");
+               }
+       }
+
+       if (adjtime) {
+               memset(&tx, 0, sizeof(tx));
+               tx.modes = ADJ_SETOFFSET;
+               tx.time.tv_sec = adjtime;
+               tx.time.tv_usec = 0;
+               if (clock_adjtime(clkid, &tx) < 0) {
+                       perror("clock_adjtime");
+               } else {
+                       puts("time shift okay");
+               }
+       }
+
+       if (gettime) {
+               if (clock_gettime(clkid, &ts)) {
+                       perror("clock_gettime");
+               } else {
+                       printf("clock time: %ld.%09ld or %s",
+                              ts.tv_sec, ts.tv_nsec, ctime(&ts.tv_sec));
+               }
+       }
+
+       if (settime == 1) {
+               clock_gettime(CLOCK_REALTIME, &ts);
+               if (clock_settime(clkid, &ts)) {
+                       perror("clock_settime");
+               } else {
+                       puts("set time okay");
+               }
+       }
+
+       if (settime == 2) {
+               clock_gettime(clkid, &ts);
+               if (clock_settime(CLOCK_REALTIME, &ts)) {
+                       perror("clock_settime");
+               } else {
+                       puts("set time okay");
+               }
+       }
+
+       if (extts) {
+               memset(&extts_request, 0, sizeof(extts_request));
+               extts_request.index = 0;
+               extts_request.flags = PTP_ENABLE_FEATURE;
+               if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
+                       perror("PTP_EXTTS_REQUEST");
+                       extts = 0;
+               } else {
+                       puts("external time stamp request okay");
+               }
+               for (; extts; extts--) {
+                       cnt = read(fd, &event, sizeof(event));
+                       if (cnt != sizeof(event)) {
+                               perror("read");
+                               break;
+                       }
+                       printf("event index %u at %lld.%09u\n", event.index,
+                              event.t.sec, event.t.nsec);
+                       fflush(stdout);
+               }
+               /* Disable the feature again. */
+               extts_request.flags = 0;
+               if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
+                       perror("PTP_EXTTS_REQUEST");
+               }
+       }
+
+       if (oneshot) {
+               install_handler(SIGALRM, handle_alarm);
+               /* Create a timer. */
+               sigevent.sigev_notify = SIGEV_SIGNAL;
+               sigevent.sigev_signo = SIGALRM;
+               if (timer_create(clkid, &sigevent, &timerid)) {
+                       perror("timer_create");
+                       return -1;
+               }
+               /* Start the timer. */
+               memset(&timeout, 0, sizeof(timeout));
+               timeout.it_value.tv_sec = oneshot;
+               if (timer_settime(timerid, 0, &timeout, NULL)) {
+                       perror("timer_settime");
+                       return -1;
+               }
+               pause();
+               timer_delete(timerid);
+       }
+
+       if (periodic) {
+               install_handler(SIGALRM, handle_alarm);
+               /* Create a timer. */
+               sigevent.sigev_notify = SIGEV_SIGNAL;
+               sigevent.sigev_signo = SIGALRM;
+               if (timer_create(clkid, &sigevent, &timerid)) {
+                       perror("timer_create");
+                       return -1;
+               }
+               /* Start the timer. */
+               memset(&timeout, 0, sizeof(timeout));
+               timeout.it_interval.tv_sec = periodic;
+               timeout.it_value.tv_sec = periodic;
+               if (timer_settime(timerid, 0, &timeout, NULL)) {
+                       perror("timer_settime");
+                       return -1;
+               }
+               while (1) {
+                       pause();
+               }
+               timer_delete(timerid);
+       }
+
+       if (perout >= 0) {
+               if (clock_gettime(clkid, &ts)) {
+                       perror("clock_gettime");
+                       return -1;
+               }
+               memset(&perout_request, 0, sizeof(perout_request));
+               perout_request.index = 0;
+               perout_request.start.sec = ts.tv_sec + 2;
+               perout_request.start.nsec = 0;
+               perout_request.period.sec = 0;
+               perout_request.period.nsec = perout;
+               if (ioctl(fd, PTP_PEROUT_REQUEST, &perout_request)) {
+                       perror("PTP_PEROUT_REQUEST");
+               } else {
+                       puts("periodic output request okay");
+               }
+       }
+
+       if (pps != -1) {
+               int enable = pps ? 1 : 0;
+               if (ioctl(fd, PTP_ENABLE_PPS, enable)) {
+                       perror("PTP_ENABLE_PPS");
+               } else {
+                       puts("pps for system time request okay");
+               }
+       }
+
+       close(fd);
+       return 0;
+}
diff --git a/Documentation/ptp/testptp.mk b/Documentation/ptp/testptp.mk
new file mode 100644 (file)
index 0000000..4ef2d97
--- /dev/null
@@ -0,0 +1,33 @@
+# PTP 1588 clock support - User space test program
+#
+# Copyright (C) 2010 OMICRON electronics GmbH
+#
+#  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.
+
+CC        = $(CROSS_COMPILE)gcc
+INC       = -I$(KBUILD_OUTPUT)/usr/include
+CFLAGS    = -Wall $(INC)
+LDLIBS    = -lrt
+PROGS     = testptp
+
+all: $(PROGS)
+
+testptp: testptp.o
+
+clean:
+       rm -f testptp.o
+
+distclean: clean
+       rm -f $(PROGS)
index 99961993257a9f9cf358ca9641577e4b5b1699ff..91ecff07cede7dfbb4710273bd9824030a805258 100644 (file)
@@ -223,9 +223,10 @@ When CONFIG_FAIR_GROUP_SCHED is defined, a "cpu.shares" file is created for each
 group created using the pseudo filesystem.  See example steps below to create
 task groups and modify their CPU share using the "cgroups" pseudo filesystem.
 
-       # mkdir /dev/cpuctl
-       # mount -t cgroup -ocpu none /dev/cpuctl
-       # cd /dev/cpuctl
+       # mount -t tmpfs cgroup_root /sys/fs/cgroup
+       # mkdir /sys/fs/cgroup/cpu
+       # mount -t cgroup -ocpu none /sys/fs/cgroup/cpu
+       # cd /sys/fs/cgroup/cpu
 
        # mkdir multimedia      # create "multimedia" group of tasks
        # mkdir browser         # create "browser" group of tasks
index 605b0d40329d843f6c3b838cd4afa5e38438d31e..71b54d54998731ebcfe2c451c15066620b384aaa 100644 (file)
@@ -129,9 +129,8 @@ priority!
 Enabling CONFIG_RT_GROUP_SCHED lets you explicitly allocate real
 CPU bandwidth to task groups.
 
-This uses the /cgroup virtual file system and
-"/cgroup/<cgroup>/cpu.rt_runtime_us" to control the CPU time reserved for each
-control group.
+This uses the cgroup virtual file system and "<cgroup>/cpu.rt_runtime_us"
+to control the CPU time reserved for each control group.
 
 For more information on working with control groups, you should read
 Documentation/cgroups/cgroups.txt as well.
@@ -150,7 +149,7 @@ For now, this can be simplified to just the following (but see Future plans):
 ===============
 
 There is work in progress to make the scheduling period for each group
-("/cgroup/<cgroup>/cpu.rt_period_us") configurable as well.
+("<cgroup>/cpu.rt_period_us") configurable as well.
 
 The constraint on the period is that a subgroup must have a smaller or
 equal period to its parent. But realistically its not very useful _yet_
index 4d9ce73ff730c8eafa6ab4a6f032ba9e54c35d5d..9ed1d9d96783cbf8992b9a91f7f38221dc8f6dc1 100644 (file)
@@ -1,3 +1,17 @@
+Release Date    : Wed. May 11, 2011 17:00:00 PST 2010 -
+                       (emaild-id:megaraidlinux@lsi.com)
+                       Adam Radford
+Current Version : 00.00.05.38-rc1
+Old Version     : 00.00.05.34-rc1
+    1. Remove MSI-X black list, use MFI_REG_STATE.ready.msiEnable.
+    2. Remove un-used function megasas_return_cmd_for_smid().
+    3. Check MFI_REG_STATE.fault.resetAdapter in megasas_reset_fusion().
+    4. Disable interrupts/free_irq() in megasas_shutdown().
+    5. Fix bug where AENs could be lost in probe() and resume().
+    6. Convert 6,10,12 byte CDB's to 16 byte CDB for large LBA's for FastPath
+       IO.
+    7. Add 1078 OCR support.
+-------------------------------------------------------------------------------
 Release Date    : Thu. Feb 24, 2011 17:00:00 PST 2010 -
                        (emaild-id:megaraidlinux@lsi.com)
                        Adam Radford
diff --git a/Documentation/security/00-INDEX b/Documentation/security/00-INDEX
new file mode 100644 (file)
index 0000000..19bc494
--- /dev/null
@@ -0,0 +1,18 @@
+00-INDEX
+       - this file.
+SELinux.txt
+       - how to get started with the SELinux security enhancement.
+Smack.txt
+       - documentation on the Smack Linux Security Module.
+apparmor.txt
+       - documentation on the AppArmor security extension.
+credentials.txt
+       - documentation about credentials in Linux.
+keys-request-key.txt
+       - description of the kernel key request service.
+keys-trusted-encrypted.txt
+       - info on the Trusted and Encrypted keys in the kernel key ring service.
+keys.txt
+       - description of the kernel key retention service.
+tomoyo.txt
+       - documentation on the TOMOYO Linux Security Module.
similarity index 99%
rename from Documentation/credentials.txt
rename to Documentation/security/credentials.txt
index 995baf379c076770962a84268fde19b527caa0be..fc0366cbd7ce6af2392d8a124d6c6a9ab8d7b963 100644 (file)
@@ -216,7 +216,7 @@ The Linux kernel supports the following types of credentials:
      When a process accesses a key, if not already present, it will normally be
      cached on one of these keyrings for future accesses to find.
 
-     For more information on using keys, see Documentation/keys.txt.
+     For more information on using keys, see Documentation/security/keys.txt.
 
  (5) LSM
 
similarity index 98%
rename from Documentation/keys-request-key.txt
rename to Documentation/security/keys-request-key.txt
index 69686ad12c66e3a39de20fcf45b91dfcbee52cdf..51987bfecfedffa8e42ae64bc9aad54f4e4dd796 100644 (file)
@@ -3,8 +3,8 @@
                              ===================
 
 The key request service is part of the key retention service (refer to
-Documentation/keys.txt).  This document explains more fully how the requesting
-algorithm works.
+Documentation/security/keys.txt).  This document explains more fully how
+the requesting algorithm works.
 
 The process starts by either the kernel requesting a service by calling
 request_key*():
similarity index 99%
rename from Documentation/keys.txt
rename to Documentation/security/keys.txt
index 6523a9e6f293675a104ce77d78a896d0e9d190e5..4d75931d2d79e7febde59664b005798827df6d26 100644 (file)
@@ -434,7 +434,7 @@ The main syscalls are:
      /sbin/request-key will be invoked in an attempt to obtain a key. The
      callout_info string will be passed as an argument to the program.
 
-     See also Documentation/keys-request-key.txt.
+     See also Documentation/security/keys-request-key.txt.
 
 
 The keyctl syscall functions are:
@@ -864,7 +864,7 @@ payload contents" for more information.
     If successful, the key will have been attached to the default keyring for
     implicitly obtained request-key keys, as set by KEYCTL_SET_REQKEY_KEYRING.
 
-    See also Documentation/keys-request-key.txt.
+    See also Documentation/security/keys-request-key.txt.
 
 
 (*) To search for a key, passing auxiliary data to the upcaller, call:
index 36f007514db35f76cfb34a97c216c7a36a7dc8ff..5e7cb39ad195039dbb12ecacc3c0c2b7fd84da8a 100644 (file)
@@ -161,7 +161,8 @@ core_pattern is used to specify a core dumpfile pattern name.
        %s      signal number
        %t      UNIX time of dump
        %h      hostname
-       %e      executable filename
+       %e      executable filename (may be shortened)
+       %E      executable path
        %<OTHER> both are dropped
 . If the first character of the pattern is a '|', the kernel will treat
   the rest of the pattern as a command to run.  The core dump will be
index bebac6b4f332cc117287f58c0cf5df11bf5531f8..0ac34206f7a7c6fb44f92bd664f71487084580e3 100644 (file)
@@ -1,5 +1,5 @@
 # This creates the demonstration utility "lguest" which runs a Linux guest.
-# Missing headers?  Add "-I../../include -I../../arch/x86/include"
+# Missing headers?  Add "-I../../../include -I../../../arch/x86/include"
 CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -U_FORTIFY_SOURCE
 
 all: lguest
index d9da7e148538286d78d6f11236f3a4db89218f45..cd9d6af61d070bbf3633753a45444eab46193541 100644 (file)
@@ -49,7 +49,7 @@
 #include <linux/virtio_rng.h>
 #include <linux/virtio_ring.h>
 #include <asm/bootparam.h>
-#include "../../include/linux/lguest_launcher.h"
+#include "../../../include/linux/lguest_launcher.h"
 /*L:110
  * We can ignore the 42 include files we need for this program, but I do want
  * to draw attention to the use of kernel-style types.
@@ -135,9 +135,6 @@ struct device {
        /* Is it operational */
        bool running;
 
-       /* Does Guest want an intrrupt on empty? */
-       bool irq_on_empty;
-
        /* Device-specific data. */
        void *priv;
 };
@@ -637,10 +634,7 @@ static void trigger_irq(struct virtqueue *vq)
 
        /* If they don't want an interrupt, don't send one... */
        if (vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT) {
-               /* ... unless they've asked us to force one on empty. */
-               if (!vq->dev->irq_on_empty
-                   || lg_last_avail(vq) != vq->vring.avail->idx)
-                       return;
+               return;
        }
 
        /* Send the Guest an interrupt tell them we used something up. */
@@ -1057,15 +1051,6 @@ static void create_thread(struct virtqueue *vq)
        close(vq->eventfd);
 }
 
-static bool accepted_feature(struct device *dev, unsigned int bit)
-{
-       const u8 *features = get_feature_bits(dev) + dev->feature_len;
-
-       if (dev->feature_len < bit / CHAR_BIT)
-               return false;
-       return features[bit / CHAR_BIT] & (1 << (bit % CHAR_BIT));
-}
-
 static void start_device(struct device *dev)
 {
        unsigned int i;
@@ -1079,8 +1064,6 @@ static void start_device(struct device *dev)
                verbose(" %02x", get_feature_bits(dev)
                        [dev->feature_len+i]);
 
-       dev->irq_on_empty = accepted_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY);
-
        for (vq = dev->vq; vq; vq = vq->next) {
                if (vq->service)
                        create_thread(vq);
@@ -1564,7 +1547,6 @@ static void setup_tun_net(char *arg)
        /* Set up the tun device. */
        configure_device(ipfd, tapif, ip);
 
-       add_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY);
        /* Expect Guest to handle everything except UFO */
        add_feature(dev, VIRTIO_NET_F_CSUM);
        add_feature(dev, VIRTIO_NET_F_GUEST_CSUM);
index 9b7e1904db1c96230336f2799f0cb2501ab7588f..5d0fc8bfcdb9b608bccf03855c33a4d01386d270 100644 (file)
   forge.net/>  and explains these in detail, as well as
   some other issues.
 
+  There is also a related point-to-point only "ucast" transport.
+  This is useful when your network does not support multicast, and
+  all network connections are simple point to point links.
+
+  The full set of command line options for this transport are
+
+
+       ethn=ucast,ethernet address,remote address,listen port,remote port
+
+
 
 
   6\b6.\b.6\b6.\b.  T\bTU\bUN\bN/\b/T\bTA\bAP\bP w\bwi\bit\bth\bh t\bth\bhe\be u\bum\bml\bl_\b_n\bne\bet\bt h\bhe\bel\blp\bpe\ber\br
diff --git a/Documentation/vm/cleancache.txt b/Documentation/vm/cleancache.txt
new file mode 100644 (file)
index 0000000..36c367c
--- /dev/null
@@ -0,0 +1,278 @@
+MOTIVATION
+
+Cleancache is a new optional feature provided by the VFS layer that
+potentially dramatically increases page cache effectiveness for
+many workloads in many environments at a negligible cost.
+
+Cleancache can be thought of as a page-granularity victim cache for clean
+pages that the kernel's pageframe replacement algorithm (PFRA) would like
+to keep around, but can't since there isn't enough memory.  So when the
+PFRA "evicts" a page, it first attempts to use cleancache code to
+put the data contained in that page into "transcendent memory", memory
+that is not directly accessible or addressable by the kernel and is
+of unknown and possibly time-varying size.
+
+Later, when a cleancache-enabled filesystem wishes to access a page
+in a file on disk, it first checks cleancache to see if it already
+contains it; if it does, the page of data is copied into the kernel
+and a disk access is avoided.
+
+Transcendent memory "drivers" for cleancache are currently implemented
+in Xen (using hypervisor memory) and zcache (using in-kernel compressed
+memory) and other implementations are in development.
+
+FAQs are included below.
+
+IMPLEMENTATION OVERVIEW
+
+A cleancache "backend" that provides transcendent memory registers itself
+to the kernel's cleancache "frontend" by calling cleancache_register_ops,
+passing a pointer to a cleancache_ops structure with funcs set appropriately.
+Note that cleancache_register_ops returns the previous settings so that
+chaining can be performed if desired. The functions provided must conform to
+certain semantics as follows:
+
+Most important, cleancache is "ephemeral".  Pages which are copied into
+cleancache have an indefinite lifetime which is completely unknowable
+by the kernel and so may or may not still be in cleancache at any later time.
+Thus, as its name implies, cleancache is not suitable for dirty pages.
+Cleancache has complete discretion over what pages to preserve and what
+pages to discard and when.
+
+Mounting a cleancache-enabled filesystem should call "init_fs" to obtain a
+pool id which, if positive, must be saved in the filesystem's superblock;
+a negative return value indicates failure.  A "put_page" will copy a
+(presumably about-to-be-evicted) page into cleancache and associate it with
+the pool id, a file key, and a page index into the file.  (The combination
+of a pool id, a file key, and an index is sometimes called a "handle".)
+A "get_page" will copy the page, if found, from cleancache into kernel memory.
+A "flush_page" will ensure the page no longer is present in cleancache;
+a "flush_inode" will flush all pages associated with the specified file;
+and, when a filesystem is unmounted, a "flush_fs" will flush all pages in
+all files specified by the given pool id and also surrender the pool id.
+
+An "init_shared_fs", like init_fs, obtains a pool id but tells cleancache
+to treat the pool as shared using a 128-bit UUID as a key.  On systems
+that may run multiple kernels (such as hard partitioned or virtualized
+systems) that may share a clustered filesystem, and where cleancache
+may be shared among those kernels, calls to init_shared_fs that specify the
+same UUID will receive the same pool id, thus allowing the pages to
+be shared.  Note that any security requirements must be imposed outside
+of the kernel (e.g. by "tools" that control cleancache).  Or a
+cleancache implementation can simply disable shared_init by always
+returning a negative value.
+
+If a get_page is successful on a non-shared pool, the page is flushed (thus
+making cleancache an "exclusive" cache).  On a shared pool, the page
+is NOT flushed on a successful get_page so that it remains accessible to
+other sharers.  The kernel is responsible for ensuring coherency between
+cleancache (shared or not), the page cache, and the filesystem, using
+cleancache flush operations as required.
+
+Note that cleancache must enforce put-put-get coherency and get-get
+coherency.  For the former, if two puts are made to the same handle but
+with different data, say AAA by the first put and BBB by the second, a
+subsequent get can never return the stale data (AAA).  For get-get coherency,
+if a get for a given handle fails, subsequent gets for that handle will
+never succeed unless preceded by a successful put with that handle.
+
+Last, cleancache provides no SMP serialization guarantees; if two
+different Linux threads are simultaneously putting and flushing a page
+with the same handle, the results are indeterminate.  Callers must
+lock the page to ensure serial behavior.
+
+CLEANCACHE PERFORMANCE METRICS
+
+Cleancache monitoring is done by sysfs files in the
+/sys/kernel/mm/cleancache directory.  The effectiveness of cleancache
+can be measured (across all filesystems) with:
+
+succ_gets      - number of gets that were successful
+failed_gets    - number of gets that failed
+puts           - number of puts attempted (all "succeed")
+flushes                - number of flushes attempted
+
+A backend implementatation may provide additional metrics.
+
+FAQ
+
+1) Where's the value? (Andrew Morton)
+
+Cleancache provides a significant performance benefit to many workloads
+in many environments with negligible overhead by improving the
+effectiveness of the pagecache.  Clean pagecache pages are
+saved in transcendent memory (RAM that is otherwise not directly
+addressable to the kernel); fetching those pages later avoids "refaults"
+and thus disk reads.
+
+Cleancache (and its sister code "frontswap") provide interfaces for
+this transcendent memory (aka "tmem"), which conceptually lies between
+fast kernel-directly-addressable RAM and slower DMA/asynchronous devices.
+Disallowing direct kernel or userland reads/writes to tmem
+is ideal when data is transformed to a different form and size (such
+as with compression) or secretly moved (as might be useful for write-
+balancing for some RAM-like devices).  Evicted page-cache pages (and
+swap pages) are a great use for this kind of slower-than-RAM-but-much-
+faster-than-disk transcendent memory, and the cleancache (and frontswap)
+"page-object-oriented" specification provides a nice way to read and
+write -- and indirectly "name" -- the pages.
+
+In the virtual case, the whole point of virtualization is to statistically
+multiplex physical resources across the varying demands of multiple
+virtual machines.  This is really hard to do with RAM and efforts to
+do it well with no kernel change have essentially failed (except in some
+well-publicized special-case workloads).  Cleancache -- and frontswap --
+with a fairly small impact on the kernel, provide a huge amount
+of flexibility for more dynamic, flexible RAM multiplexing.
+Specifically, the Xen Transcendent Memory backend allows otherwise
+"fallow" hypervisor-owned RAM to not only be "time-shared" between multiple
+virtual machines, but the pages can be compressed and deduplicated to
+optimize RAM utilization.  And when guest OS's are induced to surrender
+underutilized RAM (e.g. with "self-ballooning"), page cache pages
+are the first to go, and cleancache allows those pages to be
+saved and reclaimed if overall host system memory conditions allow.
+
+And the identical interface used for cleancache can be used in
+physical systems as well.  The zcache driver acts as a memory-hungry
+device that stores pages of data in a compressed state.  And
+the proposed "RAMster" driver shares RAM across multiple physical
+systems.
+
+2) Why does cleancache have its sticky fingers so deep inside the
+   filesystems and VFS? (Andrew Morton and Christoph Hellwig)
+
+The core hooks for cleancache in VFS are in most cases a single line
+and the minimum set are placed precisely where needed to maintain
+coherency (via cleancache_flush operations) between cleancache,
+the page cache, and disk.  All hooks compile into nothingness if
+cleancache is config'ed off and turn into a function-pointer-
+compare-to-NULL if config'ed on but no backend claims the ops
+functions, or to a compare-struct-element-to-negative if a
+backend claims the ops functions but a filesystem doesn't enable
+cleancache.
+
+Some filesystems are built entirely on top of VFS and the hooks
+in VFS are sufficient, so don't require an "init_fs" hook; the
+initial implementation of cleancache didn't provide this hook.
+But for some filesystems (such as btrfs), the VFS hooks are
+incomplete and one or more hooks in fs-specific code are required.
+And for some other filesystems, such as tmpfs, cleancache may
+be counterproductive.  So it seemed prudent to require a filesystem
+to "opt in" to use cleancache, which requires adding a hook in
+each filesystem.  Not all filesystems are supported by cleancache
+only because they haven't been tested.  The existing set should
+be sufficient to validate the concept, the opt-in approach means
+that untested filesystems are not affected, and the hooks in the
+existing filesystems should make it very easy to add more
+filesystems in the future.
+
+The total impact of the hooks to existing fs and mm files is only
+about 40 lines added (not counting comments and blank lines).
+
+3) Why not make cleancache asynchronous and batched so it can
+   more easily interface with real devices with DMA instead
+   of copying each individual page? (Minchan Kim)
+
+The one-page-at-a-time copy semantics simplifies the implementation
+on both the frontend and backend and also allows the backend to
+do fancy things on-the-fly like page compression and
+page deduplication.  And since the data is "gone" (copied into/out
+of the pageframe) before the cleancache get/put call returns,
+a great deal of race conditions and potential coherency issues
+are avoided.  While the interface seems odd for a "real device"
+or for real kernel-addressable RAM, it makes perfect sense for
+transcendent memory.
+
+4) Why is non-shared cleancache "exclusive"?  And where is the
+   page "flushed" after a "get"? (Minchan Kim)
+
+The main reason is to free up space in transcendent memory and
+to avoid unnecessary cleancache_flush calls.  If you want inclusive,
+the page can be "put" immediately following the "get".  If
+put-after-get for inclusive becomes common, the interface could
+be easily extended to add a "get_no_flush" call.
+
+The flush is done by the cleancache backend implementation.
+
+5) What's the performance impact?
+
+Performance analysis has been presented at OLS'09 and LCA'10.
+Briefly, performance gains can be significant on most workloads,
+especially when memory pressure is high (e.g. when RAM is
+overcommitted in a virtual workload); and because the hooks are
+invoked primarily in place of or in addition to a disk read/write,
+overhead is negligible even in worst case workloads.  Basically
+cleancache replaces I/O with memory-copy-CPU-overhead; on older
+single-core systems with slow memory-copy speeds, cleancache
+has little value, but in newer multicore machines, especially
+consolidated/virtualized machines, it has great value.
+
+6) How do I add cleancache support for filesystem X? (Boaz Harrash)
+
+Filesystems that are well-behaved and conform to certain
+restrictions can utilize cleancache simply by making a call to
+cleancache_init_fs at mount time.  Unusual, misbehaving, or
+poorly layered filesystems must either add additional hooks
+and/or undergo extensive additional testing... or should just
+not enable the optional cleancache.
+
+Some points for a filesystem to consider:
+
+- The FS should be block-device-based (e.g. a ram-based FS such
+  as tmpfs should not enable cleancache)
+- To ensure coherency/correctness, the FS must ensure that all
+  file removal or truncation operations either go through VFS or
+  add hooks to do the equivalent cleancache "flush" operations
+- To ensure coherency/correctness, either inode numbers must
+  be unique across the lifetime of the on-disk file OR the
+  FS must provide an "encode_fh" function.
+- The FS must call the VFS superblock alloc and deactivate routines
+  or add hooks to do the equivalent cleancache calls done there.
+- To maximize performance, all pages fetched from the FS should
+  go through the do_mpag_readpage routine or the FS should add
+  hooks to do the equivalent (cf. btrfs)
+- Currently, the FS blocksize must be the same as PAGESIZE.  This
+  is not an architectural restriction, but no backends currently
+  support anything different.
+- A clustered FS should invoke the "shared_init_fs" cleancache
+  hook to get best performance for some backends.
+
+7) Why not use the KVA of the inode as the key? (Christoph Hellwig)
+
+If cleancache would use the inode virtual address instead of
+inode/filehandle, the pool id could be eliminated.  But, this
+won't work because cleancache retains pagecache data pages
+persistently even when the inode has been pruned from the
+inode unused list, and only flushes the data page if the file
+gets removed/truncated.  So if cleancache used the inode kva,
+there would be potential coherency issues if/when the inode
+kva is reused for a different file.  Alternately, if cleancache
+flushed the pages when the inode kva was freed, much of the value
+of cleancache would be lost because the cache of pages in cleanache
+is potentially much larger than the kernel pagecache and is most
+useful if the pages survive inode cache removal.
+
+8) Why is a global variable required?
+
+The cleancache_enabled flag is checked in all of the frequently-used
+cleancache hooks.  The alternative is a function call to check a static
+variable. Since cleancache is enabled dynamically at runtime, systems
+that don't enable cleancache would suffer thousands (possibly
+tens-of-thousands) of unnecessary function calls per second.  So the
+global variable allows cleancache to be enabled by default at compile
+time, but have insignificant performance impact when cleancache remains
+disabled at runtime.
+
+9) Does cleanache work with KVM?
+
+The memory model of KVM is sufficiently different that a cleancache
+backend may have less value for KVM.  This remains to be tested,
+especially in an overcommitted system.
+
+10) Does cleancache work in userspace?  It sounds useful for
+   memory hungry caches like web browsers.  (Jamie Lokier)
+
+No plans yet, though we agree it sounds useful, at least for
+apps that bypass the page cache (e.g. O_DIRECT).
+
+Last updated: Dan Magenheimer, April 13 2011
index 12f9ba20ccb7aebd72aab882f9b6d6d7d9b4a135..550068466605b99e8beecca7a1b4a03788f2829a 100644 (file)
@@ -129,12 +129,12 @@ Limit injection to pages owned by memgroup. Specified by inode number
 of the memcg.
 
 Example:
-        mkdir /cgroup/hwpoison
+        mkdir /sys/fs/cgroup/mem/hwpoison
 
         usemem -m 100 -s 1000 &
-        echo `jobs -p` > /cgroup/hwpoison/tasks
+        echo `jobs -p` > /sys/fs/cgroup/mem/hwpoison/tasks
 
-        memcg_ino=$(ls -id /cgroup/hwpoison | cut -f1 -d' ')
+        memcg_ino=$(ls -id /sys/fs/cgroup/mem/hwpoison | cut -f1 -d' ')
         echo $memcg_ino > /debug/hwpoison/corrupt-filter-memcg
 
         page-types -p `pidof init`   --hwpoison  # shall do nothing
index 25fadb448760008dc6408ed0cca2a72c66b2efd0..f61228bd639577195b4e5142d1388e33136b7ace 100644 (file)
@@ -66,7 +66,7 @@ in some cases it is not really needed. Eg, vm_start is modified by
 expand_stack(), it is hard to come up with a destructive scenario without 
 having the vmlist protection in this case.
 
-The page_table_lock nests with the inode i_mmap_lock and the kmem cache
+The page_table_lock nests with the inode i_mmap_mutex and the kmem cache
 c_spinlock spinlocks.  This is okay, since the kmem code asks for pages after
 dropping c_spinlock.  The page_table_lock also nests with pagecache_lock and
 pagemap_lru_lock spinlocks, and no code asks for memory with these locks
index 0b415248ae252b0706f16e3e5cb85e721e0b14d0..f0358cd91de3543a5418f536b1ec17a22a97cb2b 100644 (file)
@@ -223,10 +223,8 @@ S: Maintained
 F:     drivers/platform/x86/acerhdf.c
 
 ACER WMI LAPTOP EXTRAS
-M:     Carlos Corbacho <carlos@strangeworlds.co.uk>
-L:     aceracpi@googlegroups.com (subscribers-only)
+M:     Joey Lee <jlee@novell.com>
 L:     platform-driver-x86@vger.kernel.org
-W:     http://code.google.com/p/aceracpi
 S:     Maintained
 F:     drivers/platform/x86/acer-wmi.c
 
@@ -271,10 +269,8 @@ S: Supported
 F:     drivers/acpi/video.c
 
 ACPI WMI DRIVER
-M:     Carlos Corbacho <carlos@strangeworlds.co.uk>
 L:     platform-driver-x86@vger.kernel.org
-W:     http://www.lesswatts.org/projects/acpi/
-S:     Maintained
+S:     Orphan
 F:     drivers/platform/x86/wmi.c
 
 AD1889 ALSA SOUND DRIVER
@@ -287,35 +283,35 @@ F:        sound/pci/ad1889.*
 
 AD525X ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/AD5254
 S:     Supported
 F:     drivers/misc/ad525x_dpot.c
 
 AD5398 CURRENT REGULATOR DRIVER (AD5398/AD5821)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/AD5398
 S:     Supported
 F:     drivers/regulator/ad5398.c
 
 AD714X CAPACITANCE TOUCH SENSOR DRIVER (AD7142/3/7/8/7A)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/AD7142
 S:     Supported
 F:     drivers/input/misc/ad714x.c
 
 AD7877 TOUCHSCREEN DRIVER
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/AD7877
 S:     Supported
 F:     drivers/input/touchscreen/ad7877.c
 
 AD7879 TOUCHSCREEN DRIVER (AD7879/AD7889)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/AD7879
 S:     Supported
 F:     drivers/input/touchscreen/ad7879.c
@@ -341,7 +337,7 @@ F:  drivers/net/wireless/adm8211.*
 
 ADP5520 BACKLIGHT DRIVER WITH IO EXPANDER (ADP5520/ADP5501)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/ADP5520
 S:     Supported
 F:     drivers/mfd/adp5520.c
@@ -352,7 +348,7 @@ F:  drivers/input/keyboard/adp5520-keys.c
 
 ADP5588 QWERTY KEYPAD AND IO EXPANDER DRIVER (ADP5588/ADP5587)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/ADP5588
 S:     Supported
 F:     drivers/input/keyboard/adp5588-keys.c
@@ -360,7 +356,7 @@ F:  drivers/gpio/adp5588-gpio.c
 
 ADP8860 BACKLIGHT DRIVER (ADP8860/ADP8861/ADP8863)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/ADP8860
 S:     Supported
 F:     drivers/video/backlight/adp8860_bl.c
@@ -387,7 +383,7 @@ F:  drivers/hwmon/adt7475.c
 
 ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/ADXL345
 S:     Supported
 F:     drivers/input/misc/adxl34x.c
@@ -483,6 +479,13 @@ F: drivers/tty/serial/altera_jtaguart.c
 F:     include/linux/altera_uart.h
 F:     include/linux/altera_jtaguart.h
 
+AMD FAM15H PROCESSOR POWER MONITORING DRIVER
+M:     Andreas Herrmann <andreas.herrmann3@amd.com>
+L:     lm-sensors@lm-sensors.org
+S:     Maintained
+F:     Documentation/hwmon/fam15h_power
+F:     drivers/hwmon/fam15h_power.c
+
 AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER
 M:     Thomas Dahlmann <dahlmann.thomas@arcor.de>
 L:     linux-geode@lists.infradead.org (moderated for non-subscribers)
@@ -526,7 +529,7 @@ S:  Maintained
 F:     drivers/infiniband/hw/amso1100/
 
 ANALOG DEVICES INC ASOC CODEC DRIVERS
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 W:     http://wiki.analog.com/
 S:     Supported
@@ -924,6 +927,8 @@ F:  drivers/mmc/host/msm_sdcc.h
 F:     drivers/tty/serial/msm_serial.h
 F:     drivers/tty/serial/msm_serial.c
 F:     drivers/platform/msm/
+F:     drivers/*/pm8???-*
+F:     include/linux/mfd/pm8xxx/
 T:     git git://codeaurora.org/quic/kernel/davidb/linux-msm.git
 S:     Maintained
 
@@ -1734,7 +1739,7 @@ S:        Supported
 F:     drivers/net/enic/
 
 CIRRUS LOGIC EP93XX ETHERNET DRIVER
-M:     Lennert Buytenhek <kernel@wantstofly.org>
+M:     Hartley Sweeten <hsweeten@visionengravers.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/arm/ep93xx_eth.c
@@ -1884,7 +1889,6 @@ L:        cpufreq@vger.kernel.org
 W:     http://www.codemonkey.org.uk/projects/cpufreq/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq.git
 S:     Maintained
-F:     arch/x86/kernel/cpu/cpufreq/
 F:     drivers/cpufreq/
 F:     include/linux/cpufreq.h
 
@@ -2034,9 +2038,8 @@ F:        net/ax25/ax25_timer.c
 F:     net/ax25/sysctl_net_ax25.c
 
 DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
-M:     Tobias Ringstrom <tori@unhappy.mine.nu>
 L:     netdev@vger.kernel.org
-S:     Maintained
+S:     Orphan
 F:     Documentation/networking/dmfe.txt
 F:     drivers/net/tulip/dmfe.c
 
@@ -2170,6 +2173,8 @@ M:        Dan Williams <dan.j.williams@intel.com>
 S:     Supported
 F:     drivers/dma/
 F:     include/linux/dma*
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx.git
+T:     git git://git.infradead.org/users/vkoul/slave-dma.git (slave-dma)
 
 DME1737 HARDWARE MONITOR DRIVER
 M:     Juerg Haefliger <juergh@gmail.com>
@@ -2245,10 +2250,10 @@ F:      drivers/gpu/drm/
 F:     include/drm/
 
 INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
-M:     Chris Wilson <chris@chris-wilson.co.uk>
+M:     Keith Packard <keithp@keithp.com>
 L:     intel-gfx@lists.freedesktop.org (subscribers-only)
 L:     dri-devel@lists.freedesktop.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ickle/drm-intel.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/keithp/linux-2.6.git
 S:     Supported
 F:     drivers/gpu/drm/i915
 F:     include/drm/i915*
@@ -2286,8 +2291,7 @@ F:        drivers/scsi/eata_pio.*
 
 EBTABLES
 M:     Bart De Schuymer <bart.de.schuymer@pandora.be>
-L:     ebtables-user@lists.sourceforge.net
-L:     ebtables-devel@lists.sourceforge.net
+L:     netfilter-devel@vger.kernel.org
 W:     http://ebtables.sourceforge.net/
 S:     Maintained
 F:     include/linux/netfilter_bridge/ebt_*.h
@@ -2296,7 +2300,7 @@ F:        net/bridge/netfilter/ebt*.c
 ECRYPT FILE SYSTEM
 M:     Tyler Hicks <tyhicks@linux.vnet.ibm.com>
 M:     Dustin Kirkland <kirkland@canonical.com>
-L:     ecryptfs-devel@lists.launchpad.net
+L:     ecryptfs@vger.kernel.org
 W:     https://launchpad.net/ecryptfs
 S:     Supported
 F:     Documentation/filesystems/ecryptfs.txt
@@ -2576,6 +2580,13 @@ S:       Maintained
 F:     drivers/hwmon/f75375s.c
 F:     include/linux/f75375s.h
 
+FIREWIRE AUDIO DRIVERS
+M:     Clemens Ladisch <clemens@ladisch.de>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+T:     git git://git.alsa-project.org/alsa-kernel.git
+S:     Maintained
+F:     sound/firewire/
+
 FIREWIRE SUBSYSTEM
 M:     Stefan Richter <stefanr@s5r6.in-berlin.de>
 L:     linux1394-devel@lists.sourceforge.net
@@ -3016,9 +3027,8 @@ S:        Maintained
 F:     drivers/net/wireless/hostap/
 
 HP COMPAQ TC1100 TABLET WMI EXTRAS DRIVER
-M:     Carlos Corbacho <carlos@strangeworlds.co.uk>
 L:     platform-driver-x86@vger.kernel.org
-S:     Odd Fixes
+S:     Orphan
 F:     drivers/platform/x86/tc1100-wmi.c
 
 HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
@@ -3566,9 +3576,16 @@ M:       Andrew Morton <akpm@linux-foundation.org>
 M:     Jan Kara <jack@suse.cz>
 L:     linux-ext4@vger.kernel.org
 S:     Maintained
-F:     fs/jbd*/
-F:     include/linux/ext*jbd*.h
-F:     include/linux/jbd*.h
+F:     fs/jbd/
+F:     include/linux/ext3_jbd.h
+F:     include/linux/jbd.h
+
+JOURNALLING LAYER FOR BLOCK DEVICES (JBD2)
+M:     "Theodore Ts'o" <tytso@mit.edu>
+L:     linux-ext4@vger.kernel.org
+S:     Maintained
+F:     fs/jbd2/
+F:     include/linux/jbd2.h
 
 JSM Neo PCI based serial card
 M:     Breno Leitao <leitao@linux.vnet.ibm.com>
@@ -3591,10 +3608,9 @@ F:       Documentation/hwmon/k8temp
 F:     drivers/hwmon/k8temp.c
 
 KCONFIG
-M:     Roman Zippel <zippel@linux-m68k.org>
+M:     Michal Marek <mmarek@suse.cz>
 L:     linux-kbuild@vger.kernel.org
-Q:     http://patchwork.kernel.org/project/linux-kbuild/list/
-S:     Maintained
+S:     Odd Fixes
 F:     Documentation/kbuild/kconfig-language.txt
 F:     scripts/kconfig/
 
@@ -3705,7 +3721,7 @@ KEYS/KEYRINGS:
 M:     David Howells <dhowells@redhat.com>
 L:     keyrings@linux-nfs.org
 S:     Maintained
-F:     Documentation/keys.txt
+F:     Documentation/security/keys.txt
 F:     include/linux/key.h
 F:     include/linux/key-type.h
 F:     include/keys/
@@ -3717,7 +3733,7 @@ M:        Mimi Zohar <zohar@us.ibm.com>
 L:     linux-security-module@vger.kernel.org
 L:     keyrings@linux-nfs.org
 S:     Supported
-F:     Documentation/keys-trusted-encrypted.txt
+F:     Documentation/security/keys-trusted-encrypted.txt
 F:     include/keys/trusted-type.h
 F:     security/keys/trusted.c
 F:     security/keys/trusted.h
@@ -3728,7 +3744,7 @@ M:        David Safford <safford@watson.ibm.com>
 L:     linux-security-module@vger.kernel.org
 L:     keyrings@linux-nfs.org
 S:     Supported
-F:     Documentation/keys-trusted-encrypted.txt
+F:     Documentation/security/keys-trusted-encrypted.txt
 F:     include/keys/encrypted-type.h
 F:     security/keys/encrypted.c
 F:     security/keys/encrypted.h
@@ -3802,6 +3818,12 @@ S:       Maintained
 F:     drivers/leds/
 F:     include/linux/leds.h
 
+LEGACY EEPROM DRIVER
+M:     Jean Delvare <khali@linux-fr.org>
+S:     Maintained
+F:     Documentation/misc-devices/eeprom
+F:     drivers/misc/eeprom/eeprom.c
+
 LEGO USB Tower driver
 M:     Juergen Stuber <starblue@users.sourceforge.net>
 L:     legousb-devel@lists.sourceforge.net
@@ -3898,7 +3920,6 @@ F:        drivers/*/*/*pasemi*
 LINUX SECURITY MODULE (LSM) FRAMEWORK
 M:     Chris Wright <chrisw@sous-sol.org>
 L:     linux-security-module@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chrisw/lsm-2.6.git
 S:     Supported
 
 LIS3LV02D ACCELEROMETER DRIVER
@@ -4128,12 +4149,13 @@ F:      include/linux/mm.h
 F:     mm/
 
 MEMORY RESOURCE CONTROLLER
-M:     Balbir Singh <balbir@linux.vnet.ibm.com>
+M:     Balbir Singh <bsingharora@gmail.com>
 M:     Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
 M:     KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
 L:     linux-mm@kvack.org
 S:     Maintained
 F:     mm/memcontrol.c
+F:     mm/page_cgroup.c
 
 MEMORY TECHNOLOGY DEVICES (MTD)
 M:     David Woodhouse <dwmw2@infradead.org>
@@ -4234,8 +4256,7 @@ F:        drivers/mmc/
 F:     include/linux/mmc/
 
 MULTIMEDIA CARD (MMC) ETC. OVER SPI
-M:     David Brownell <dbrownell@users.sourceforge.net>
-S:     Odd Fixes
+S:     Orphan
 F:     drivers/mmc/host/mmc_spi.c
 F:     include/linux/spi/mmc_spi.h
 
@@ -4585,7 +4606,6 @@ F:        drivers/media/video/omap3isp/*
 
 OMAP USB SUPPORT
 M:     Felipe Balbi <balbi@ti.com>
-M:     David Brownell <dbrownell@users.sourceforge.net>
 L:     linux-usb@vger.kernel.org
 L:     linux-omap@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
@@ -4874,7 +4894,7 @@ F:        mm/percpu*.c
 F:     arch/*/include/asm/percpu.h
 
 PER-TASK DELAY ACCOUNTING
-M:     Balbir Singh <balbir@linux.vnet.ibm.com>
+M:     Balbir Singh <bsingharora@gmail.com>
 S:     Maintained
 F:     include/linux/delayacct.h
 F:     kernel/delayacct.c
@@ -4929,6 +4949,7 @@ T:        git git://git.kernel.org/pub/scm/linux/kernel/git/epip/linux-2.6-unicore32.gi
 F:     drivers/input/serio/i8042-unicore32io.h
 F:     drivers/i2c/busses/i2c-puv3.c
 F:     drivers/video/fb-puv3.c
+F:     drivers/rtc/rtc-puv3.c
 
 PMC SIERRA MaxRAID DRIVER
 M:     Anil Ravindranath <anil_ravindranath@pmc-sierra.com>
@@ -5430,6 +5451,13 @@ L:       linux-serial@vger.kernel.org
 S:     Maintained
 F:     drivers/tty/serial
 
+SYNOPSYS DESIGNWARE DMAC DRIVER
+M:     Viresh Kumar <viresh.kumar@st.com>
+S:     Maintained
+F:     include/linux/dw_dmac.h
+F:     drivers/dma/dw_dmac_regs.h
+F:     drivers/dma/dw_dmac.c
+
 TIMEKEEPING, NTP
 M:     John Stultz <johnstul@us.ibm.com>
 M:     Thomas Gleixner <tglx@linutronix.de>
@@ -5494,7 +5522,7 @@ F:        drivers/scsi/sg.c
 F:     include/scsi/sg.h
 
 SCSI SUBSYSTEM
-M:     "James E.J. Bottomley" <James.Bottomley@suse.de>
+M:     "James E.J. Bottomley" <JBottomley@parallels.com>
 L:     linux-scsi@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6.git
@@ -5592,10 +5620,11 @@ M:      James Morris <jmorris@namei.org>
 M:     Eric Paris <eparis@parisplace.org>
 L:     selinux@tycho.nsa.gov (subscribers-only, general discussion)
 W:     http://selinuxproject.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git
+T:     git git://git.infradead.org/users/eparis/selinux.git
 S:     Supported
 F:     include/linux/selinux*
 F:     security/selinux/
+F:     scripts/selinux/
 
 APPARMOR SECURITY MODULE
 M:     John Johansen <john.johansen@canonical.com>
@@ -5958,7 +5987,6 @@ F:        Documentation/serial/specialix.txt
 F:     drivers/staging/tty/specialix*
 
 SPI SUBSYSTEM
-M:     David Brownell <dbrownell@users.sourceforge.net>
 M:     Grant Likely <grant.likely@secretlab.ca>
 L:     spi-devel-general@lists.sourceforge.net
 Q:     http://patchwork.kernel.org/project/spi-devel-general/list/
@@ -5986,7 +6014,7 @@ F:        Documentation/filesystems/spufs.txt
 F:     arch/powerpc/platforms/cell/spufs/
 
 SQUASHFS FILE SYSTEM
-M:     Phillip Lougher <phillip@lougher.demon.co.uk>
+M:     Phillip Lougher <phillip@squashfs.org.uk>
 L:     squashfs-devel@lists.sourceforge.net (subscribers-only)
 W:     http://squashfs.org.uk
 S:     Maintained
@@ -6062,8 +6090,19 @@ F:       Documentation/filesystems/sysv-fs.txt
 F:     fs/sysv/
 F:     include/linux/sysv_fs.h
 
+TARGET SUBSYSTEM
+M:     Nicholas A. Bellinger <nab@linux-iscsi.org>
+L:     linux-scsi@vger.kernel.org
+L:     http://groups.google.com/group/linux-iscsi-target-dev
+W:     http://www.linux-iscsi.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master
+S:     Supported
+F:     drivers/target/
+F:     include/target/
+F:     Documentation/target/
+
 TASKSTATS STATISTICS INTERFACE
-M:     Balbir Singh <balbir@linux.vnet.ibm.com>
+M:     Balbir Singh <bsingharora@gmail.com>
 S:     Maintained
 F:     Documentation/accounting/taskstats*
 F:     include/linux/taskstats*
@@ -6395,9 +6434,8 @@ S:        Maintained
 F:     drivers/usb/misc/rio500*
 
 USB EHCI DRIVER
-M:     David Brownell <dbrownell@users.sourceforge.net>
 L:     linux-usb@vger.kernel.org
-S:     Odd Fixes
+S:     Orphan
 F:     Documentation/usb/ehci.txt
 F:     drivers/usb/host/ehci*
 
@@ -6411,9 +6449,10 @@ S:       Maintained
 F:     drivers/media/video/et61x251/
 
 USB GADGET/PERIPHERAL SUBSYSTEM
-M:     David Brownell <dbrownell@users.sourceforge.net>
+M:     Felipe Balbi <balbi@ti.com>
 L:     linux-usb@vger.kernel.org
 W:     http://www.linux-usb.org/gadget
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 S:     Maintained
 F:     drivers/usb/gadget/
 F:     include/linux/usb/gadget*
@@ -6423,7 +6462,7 @@ M:        Jiri Kosina <jkosina@suse.cz>
 L:     linux-usb@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git
 S:     Maintained
-F:     Documentation/usb/hiddev.txt
+F:     Documentation/hid/hiddev.txt
 F:     drivers/hid/usbhid/
 
 USB ISP116X DRIVER
@@ -6455,9 +6494,8 @@ S:        Maintained
 F:     sound/usb/midi.*
 
 USB OHCI DRIVER
-M:     David Brownell <dbrownell@users.sourceforge.net>
 L:     linux-usb@vger.kernel.org
-S:     Odd Fixes
+S:     Orphan
 F:     Documentation/usb/ohci.txt
 F:     drivers/usb/host/ohci*
 
@@ -6683,6 +6721,14 @@ S:       Maintained
 F:     Documentation/filesystems/vfat.txt
 F:     fs/fat/
 
+VIDEOBUF2 FRAMEWORK
+M:     Pawel Osciak <pawel@osciak.com>
+M:     Marek Szyprowski <m.szyprowski@samsung.com>
+L:     linux-media@vger.kernel.org
+S:     Maintained
+F:     drivers/media/video/videobuf2-*
+F:     include/media/videobuf2-*
+
 VIRTIO CONSOLE DRIVER
 M:     Amit Shah <amit.shah@redhat.com>
 L:     virtualization@lists.linux-foundation.org
@@ -6795,6 +6841,13 @@ L:       lm-sensors@lm-sensors.org
 S:     Maintained
 F:     drivers/hwmon/vt8231.c
 
+VUB300 USB to SDIO/SD/MMC bridge chip
+M:     Tony Olech <tony.olech@elandigitalsystems.com>
+L:     linux-mmc@vger.kernel.org
+L:     linux-usb@vger.kernel.org
+S:     Supported
+F:     drivers/mmc/host/vub300.c
+
 W1 DALLAS'S 1-WIRE BUS
 M:     Evgeniy Polyakov <johnpol@2ka.mipt.ru>
 S:     Maintained
@@ -6953,6 +7006,13 @@ T:       git git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86.
 S:     Maintained
 F:     drivers/platform/x86
 
+X86 MCE INFRASTRUCTURE
+M:     Tony Luck <tony.luck@intel.com>
+M:     Borislav Petkov <bp@amd64.org>
+L:     linux-edac@vger.kernel.org
+S:     Maintained
+F:     arch/x86/kernel/cpu/mcheck/*
+
 XEN HYPERVISOR INTERFACE
 M:     Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
 M:     Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
index a0344a81a893b1a6e8d35346c370db7574d656ff..41330a06e4ec99f6f7dde82b341dd52f67dd90b2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
-VERSION = 2
-PATCHLEVEL = 6
-SUBLEVEL = 39
-EXTRAVERSION =
-NAME = Flesh-Eating Bats with Fangs
+VERSION = 3
+PATCHLEVEL = 0
+SUBLEVEL = 0
+EXTRAVERSION = -rc4
+NAME = Sneaky Weasel
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
@@ -103,7 +103,7 @@ ifeq ("$(origin O)", "command line")
 endif
 
 ifeq ("$(origin W)", "command line")
-  export KBUILD_ENABLE_EXTRA_GCC_CHECKS := 1
+  export KBUILD_ENABLE_EXTRA_GCC_CHECKS := $(W)
 endif
 
 # That's our default target when none is given on the command line
@@ -220,6 +220,14 @@ ifeq ($(ARCH),sh64)
        SRCARCH := sh
 endif
 
+# Additional ARCH settings for tile
+ifeq ($(ARCH),tilepro)
+       SRCARCH := tile
+endif
+ifeq ($(ARCH),tilegx)
+       SRCARCH := tile
+endif
+
 # Where to locate arch specific headers
 hdr-arch  := $(SRCARCH)
 
@@ -349,7 +357,8 @@ CFLAGS_GCOV = -fprofile-arcs -ftest-coverage
 
 # Use LINUXINCLUDE when you must reference the include/ directory.
 # Needed to be compatible with the O= option
-LINUXINCLUDE    := -I$(srctree)/arch/$(hdr-arch)/include -Iinclude \
+LINUXINCLUDE    := -I$(srctree)/arch/$(hdr-arch)/include \
+                   -Iarch/$(hdr-arch)/include/generated -Iinclude \
                    $(if $(KBUILD_SRC), -I$(srctree)/include) \
                    -include include/generated/autoconf.h
 
@@ -369,7 +378,7 @@ KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds
 
 # Read KERNELRELEASE from include/config/kernel.release (if it exists)
 KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
-KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION)
 
 export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION
 export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC
@@ -382,6 +391,7 @@ export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV
 export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
 export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
 export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
+export KBUILD_ARFLAGS
 
 # When compiling out-of-tree modules, put MODVERDIR in the module
 # tree rather than in the kernel tree. The kernel tree might
@@ -416,6 +426,12 @@ ifneq ($(KBUILD_SRC),)
            $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
 endif
 
+# Support for using generic headers in asm-generic
+PHONY += asm-generic
+asm-generic:
+       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.asm-generic \
+                   obj=arch/$(SRCARCH)/include/generated/asm
+
 # To make sure we do not include .config for any of the *config targets
 # catch them early, and hand them over to scripts/kconfig/Makefile
 # It is allowed to specify more targets when calling make, including
@@ -559,6 +575,10 @@ ifndef CONFIG_CC_STACKPROTECTOR
 KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector)
 endif
 
+# This warning generated too much noise in a regular build.
+# Use make W=1 to enable this warning (see scripts/Makefile.build)
+KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable)
+
 ifdef CONFIG_FRAME_POINTER
 KBUILD_CFLAGS  += -fno-omit-frame-pointer -fno-optimize-sibling-calls
 else
@@ -604,7 +624,7 @@ CHECKFLAGS     += $(NOSTDINC_FLAGS)
 KBUILD_CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
 
 # disable pointer signed / unsigned warnings in gcc 4.0
-KBUILD_CFLAGS += $(call cc-option,-Wno-pointer-sign,)
+KBUILD_CFLAGS += $(call cc-disable-warning, pointer-sign)
 
 # disable invalid "can't wrap" optimizations for signed / pointers
 KBUILD_CFLAGS  += $(call cc-option,-fno-strict-overflow)
@@ -612,6 +632,9 @@ KBUILD_CFLAGS       += $(call cc-option,-fno-strict-overflow)
 # conserve stack if available
 KBUILD_CFLAGS   += $(call cc-option,-fconserve-stack)
 
+# use the deterministic mode of AR if available
+KBUILD_ARFLAGS := $(call ar-option,D)
+
 # check for 'asm goto'
 ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y)
        KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO
@@ -797,15 +820,17 @@ ifdef CONFIG_KALLSYMS
 # o The correct .tmp_kallsyms2.o is linked into the final vmlinux.
 # o Verify that the System.map from vmlinux matches the map from
 #   .tmp_vmlinux2, just in case we did not generate kallsyms correctly.
-# o If CONFIG_KALLSYMS_EXTRA_PASS is set, do an extra pass using
+# o If 'make KALLSYMS_EXTRA_PASS=1" was used, do an extra pass using
 #   .tmp_vmlinux3 and .tmp_kallsyms3.o.  This is only meant as a
 #   temporary bypass to allow the kernel to be built while the
 #   maintainers work out what went wrong with kallsyms.
 
-ifdef CONFIG_KALLSYMS_EXTRA_PASS
-last_kallsyms := 3
-else
 last_kallsyms := 2
+
+ifdef KALLSYMS_EXTRA_PASS
+ifneq ($(KALLSYMS_EXTRA_PASS),0)
+last_kallsyms := 3
+endif
 endif
 
 kallsyms.o := .tmp_kallsyms$(last_kallsyms).o
@@ -816,7 +841,8 @@ define verify_kallsyms
          $(cmd_sysmap) .tmp_vmlinux$(last_kallsyms) .tmp_System.map
        $(Q)cmp -s System.map .tmp_System.map ||                             \
                (echo Inconsistent kallsyms data;                            \
-                echo Try setting CONFIG_KALLSYMS_EXTRA_PASS;                \
+                echo This is a bug - please report about it;                \
+                echo Try "make KALLSYMS_EXTRA_PASS=1" as a workaround;      \
                 rm .tmp_kallsyms* ; /bin/false )
 endef
 
@@ -947,7 +973,7 @@ ifneq ($(KBUILD_SRC),)
 endif
 
 # prepare2 creates a makefile if using a separate output directory
-prepare2: prepare3 outputmakefile
+prepare2: prepare3 outputmakefile asm-generic
 
 prepare1: prepare2 include/linux/version.h include/generated/utsrelease.h \
                    include/config/auto.conf
@@ -979,7 +1005,7 @@ endef
 
 define filechk_version.h
        (echo \#define LINUX_VERSION_CODE $(shell                             \
-       expr $(VERSION) \* 65536 + $(PATCHLEVEL) \* 256 + $(SUBLEVEL));     \
+       expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL));    \
        echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';)
 endef
 
@@ -991,7 +1017,8 @@ include/generated/utsrelease.h: include/config/kernel.release FORCE
 
 PHONY += headerdep
 headerdep:
-       $(Q)find include/ -name '*.h' | xargs --max-args 1 scripts/headerdep.pl
+       $(Q)find $(srctree)/include/ -name '*.h' | xargs --max-args 1 \
+       $(srctree)/scripts/headerdep.pl -I$(srctree)/include
 
 # ---------------------------------------------------------------------------
 
@@ -1021,7 +1048,7 @@ hdr-inst := -rR -f $(srctree)/scripts/Makefile.headersinst obj
 hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm)
 
 PHONY += __headers
-__headers: include/linux/version.h scripts_basic FORCE
+__headers: include/linux/version.h scripts_basic asm-generic FORCE
        $(Q)$(MAKE) $(build)=scripts build_unifdef
 
 PHONY += headers_install_all
@@ -1083,11 +1110,6 @@ modules_install: _modinst_ _modinst_post
 
 PHONY += _modinst_
 _modinst_:
-       @if [ -z "`$(DEPMOD) -V 2>/dev/null | grep module-init-tools`" ]; then \
-               echo "Warning: you may need to install module-init-tools"; \
-               echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\
-               sleep 1; \
-       fi
        @rm -rf $(MODLIB)/kernel
        @rm -f $(MODLIB)/source
        @mkdir -p $(MODLIB)/kernel
@@ -1136,7 +1158,8 @@ CLEAN_FILES +=    vmlinux System.map \
                 .tmp_kallsyms* .tmp_version .tmp_vmlinux* .tmp_System.map
 
 # Directories & files removed with 'make mrproper'
-MRPROPER_DIRS  += include/config usr/include include/generated
+MRPROPER_DIRS  += include/config usr/include include/generated          \
+                  arch/*/include/generated
 MRPROPER_FILES += .config .config.old .version .old_version             \
                   include/linux/version.h                               \
                  Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS
@@ -1267,7 +1290,11 @@ help:
        @echo  '  make O=dir [targets] Locate all output files in "dir", including .config'
        @echo  '  make C=1   [targets] Check all c source with $$CHECK (sparse by default)'
        @echo  '  make C=2   [targets] Force check of all c source with $$CHECK'
-       @echo  '  make W=1   [targets] Enable extra gcc checks'
+       @echo  '  make W=n   [targets] Enable extra gcc checks, n=1,2,3 where'
+       @echo  '                1: warnings which may be relevant and do not occur too often'
+       @echo  '                2: warnings which occur quite often but may still be relevant'
+       @echo  '                3: more obscure warnings, can most likely be ignored'
+       @echo  '                Multiple levels can be combined with W=12 or W=123'
        @echo  '  make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections'
        @echo  ''
        @echo  'Execute "make" or "make all" to build all targets marked with [*] '
@@ -1291,6 +1318,7 @@ $(help-board-dirs): help-%:
 # Documentation targets
 # ---------------------------------------------------------------------------
 %docs: scripts_basic FORCE
+       $(Q)$(MAKE) $(build)=scripts build_docproc
        $(Q)$(MAKE) $(build)=Documentation/DocBook $@
 
 else # KBUILD_EXTMOD
@@ -1375,7 +1403,7 @@ endif # KBUILD_EXTMOD
 clean: $(clean-dirs)
        $(call cmd,rmdirs)
        $(call cmd,rmfiles)
-       @find $(or $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
+       @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
                \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
                -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
                -o -name '*.symtypes' -o -name 'modules.order' \
@@ -1393,13 +1421,15 @@ tags TAGS cscope gtags: FORCE
 # Scripts to check various things for consistency
 # ---------------------------------------------------------------------------
 
+PHONY += includecheck versioncheck coccicheck namespacecheck export_report
+
 includecheck:
-       find * $(RCS_FIND_IGNORE) \
+       find $(srctree)/* $(RCS_FIND_IGNORE) \
                -name '*.[hcS]' -type f -print | sort \
                | xargs $(PERL) -w $(srctree)/scripts/checkincludes.pl
 
 versioncheck:
-       find * $(RCS_FIND_IGNORE) \
+       find $(srctree)/* $(RCS_FIND_IGNORE) \
                -name '*.[hcS]' -type f -print | sort \
                | xargs $(PERL) -w $(srctree)/scripts/checkversion.pl
 
@@ -1496,12 +1526,8 @@ quiet_cmd_rmfiles = $(if $(wildcard $(rm-files)),CLEAN   $(wildcard $(rm-files))
 
 # Run depmod only if we have System.map and depmod is executable
 quiet_cmd_depmod = DEPMOD  $(KERNELRELEASE)
-      cmd_depmod = \
-       if [ -r System.map -a -x $(DEPMOD) ]; then                              \
-               $(DEPMOD) -ae -F System.map                                     \
-               $(if $(strip $(INSTALL_MOD_PATH)), -b $(INSTALL_MOD_PATH) )     \
-               $(KERNELRELEASE);                                               \
-       fi
+      cmd_depmod = $(CONFIG_SHELL) $(srctree)/scripts/depmod.sh $(DEPMOD) \
+                   $(KERNELRELEASE)
 
 # Create temporary dir for module support files
 # clean it up only when building all modules
index 8d24bacaa61ea5746e326133d32f019f9511b602..26b0e2397a5724140bc8683fedd6bbae67706fe5 100644 (file)
@@ -175,4 +175,7 @@ config HAVE_ARCH_JUMP_LABEL
 config HAVE_ARCH_MUTEX_CPU_RELAX
        bool
 
+config HAVE_RCU_TABLE_FREE
+       bool
+
 source "kernel/gcov/Kconfig"
index 9808998cc07321dd5f45f6f782b4eedf222446ec..60219bf9419884587ed0c6172a084cd5555bddbf 100644 (file)
@@ -12,6 +12,7 @@ config ALPHA
        select GENERIC_IRQ_PROBE
        select AUTO_IRQ_AFFINITY if SMP
        select GENERIC_IRQ_SHOW
+       select ARCH_WANT_OPTIONAL_GPIOLIB
        help
          The Alpha is a 64-bit general-purpose processor designed and
          marketed by the Digital Equipment Corporation of blessed memory,
@@ -40,10 +41,6 @@ config ARCH_HAS_ILOG2_U64
        bool
        default n
 
-config GENERIC_FIND_NEXT_BIT
-       bool
-       default y
-
 config GENERIC_CALIBRATE_DELAY
        bool
        default y
@@ -51,6 +48,9 @@ config GENERIC_CALIBRATE_DELAY
 config GENERIC_CMOS_UPDATE
         def_bool y
 
+config GENERIC_GPIO
+       def_bool y
+
 config ZONE_DMA
        bool
        default y
diff --git a/arch/alpha/include/asm/gpio.h b/arch/alpha/include/asm/gpio.h
new file mode 100644 (file)
index 0000000..7dc6a63
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Generic GPIO API implementation for Alpha.
+ *
+ * A stright copy of that for PowerPC which was:
+ *
+ * Copyright (c) 2007-2008  MontaVista Software, Inc.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.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.
+ */
+
+#ifndef _ASM_ALPHA_GPIO_H
+#define _ASM_ALPHA_GPIO_H
+
+#include <linux/errno.h>
+#include <asm-generic/gpio.h>
+
+#ifdef CONFIG_GPIOLIB
+
+/*
+ * We don't (yet) implement inlined/rapid versions for on-chip gpios.
+ * Just call gpiolib.
+ */
+static inline int gpio_get_value(unsigned int gpio)
+{
+       return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned int gpio, int value)
+{
+       __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned int gpio)
+{
+       return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+       return __gpio_to_irq(gpio);
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+       return -EINVAL;
+}
+
+#endif /* CONFIG_GPIOLIB */
+
+#endif /* _ASM_ALPHA_GPIO_H */
index 3f390e8cc0b33fdee5070297d99d30e102f90557..c46e714aa3e024ccd04ec7cf11207ba0a1243b13 100644 (file)
@@ -39,8 +39,6 @@ struct cpuinfo_alpha {
 
 extern struct cpuinfo_alpha cpu_data[NR_CPUS];
 
-#define PROC_CHANGE_PENALTY     20
-
 #define hard_smp_processor_id()        __hard_smp_processor_id()
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
index b1834166922dbb8260eb4457cf2c77a8c4616e59..4ac48a095f3ace676d7f4651dedf21a84da9249b 100644 (file)
 #define __NR_open_by_handle_at         498
 #define __NR_clock_adjtime             499
 #define __NR_syncfs                    500
+#define __NR_setns                     501
 
 #ifdef __KERNEL__
 
-#define NR_SYSCALLS                    501
+#define NR_SYSCALLS                    502
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 376f2213079190f65196b0e3f6554f0f55834183..326f0a2d56e52922920aad724dfec0e78487986a 100644 (file)
@@ -409,7 +409,7 @@ SYSCALL_DEFINE2(osf_getdomainname, char __user *, name, int, namelen)
                return -EFAULT;
 
        len = namelen;
-       if (namelen > 32)
+       if (len > 32)
                len = 32;
 
        down_read(&uts_sem);
@@ -594,7 +594,7 @@ SYSCALL_DEFINE3(osf_sysinfo, int, command, char __user *, buf, long, count)
        down_read(&uts_sem);
        res = sysinfo_table[offset];
        len = strlen(res)+1;
-       if (len > count)
+       if ((unsigned long)len > (unsigned long)count)
                len = count;
        if (copy_to_user(buf, res, len))
                err = -EFAULT;
@@ -649,7 +649,7 @@ SYSCALL_DEFINE5(osf_getsysinfo, unsigned long, op, void __user *, buffer,
                return 1;
 
        case GSI_GET_HWRPB:
-               if (nbytes < sizeof(*hwrpb))
+               if (nbytes > sizeof(*hwrpb))
                        return -EINVAL;
                if (copy_to_user(buffer, hwrpb, nbytes) != 0)
                        return -EFAULT;
@@ -1008,6 +1008,7 @@ SYSCALL_DEFINE4(osf_wait4, pid_t, pid, int __user *, ustatus, int, options,
 {
        struct rusage r;
        long ret, err;
+       unsigned int status = 0;
        mm_segment_t old_fs;
 
        if (!ur)
@@ -1016,13 +1017,15 @@ SYSCALL_DEFINE4(osf_wait4, pid_t, pid, int __user *, ustatus, int, options,
        old_fs = get_fs();
                
        set_fs (KERNEL_DS);
-       ret = sys_wait4(pid, ustatus, options, (struct rusage __user *) &r);
+       ret = sys_wait4(pid, (unsigned int __user *) &status, options,
+                       (struct rusage __user *) &r);
        set_fs (old_fs);
 
        if (!access_ok(VERIFY_WRITE, ur, sizeof(*ur)))
                return -EFAULT;
 
        err = 0;
+       err |= put_user(status, ustatus);
        err |= __put_user(r.ru_utime.tv_sec, &ur->ru_utime.tv_sec);
        err |= __put_user(r.ru_utime.tv_usec, &ur->ru_utime.tv_usec);
        err |= __put_user(r.ru_stime.tv_sec, &ur->ru_stime.tv_sec);
index 3ec35066f1dc51c09367c32bea106453a109953d..838eac128409e235b33080ca893847ebaa69b827 100644 (file)
@@ -121,7 +121,7 @@ common_shutdown_1(void *generic_ptr)
        /* Wait for the secondaries to halt. */
        set_cpu_present(boot_cpuid, false);
        set_cpu_possible(boot_cpuid, false);
-       while (cpus_weight(cpu_present_map))
+       while (cpumask_weight(cpu_present_mask))
                barrier();
 #endif
 
index edbddcbd5bc654692fbfc98572ed8277303d49db..cc0fd862cf26a9565580c9f137e0d67ac3119bab 100644 (file)
@@ -1257,7 +1257,7 @@ show_cpuinfo(struct seq_file *f, void *slot)
 #ifdef CONFIG_SMP
        seq_printf(f, "cpus active\t\t: %u\n"
                      "cpu active mask\t\t: %016lx\n",
-                      num_online_cpus(), cpus_addr(cpu_possible_map)[0]);
+                      num_online_cpus(), cpumask_bits(cpu_possible_mask)[0]);
 #endif
 
        show_cache_size (f, "L1 Icache", alpha_l1i_cacheshape);
index 5a621c6d22ab4e217b489376c82da5f3d5f94894..d739703608fcc6c29c0adaa2b2e065ee22b77a85 100644 (file)
@@ -451,7 +451,7 @@ setup_smp(void)
        }
 
        printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_map = %lx\n",
-              smp_num_probed, cpu_present_map.bits[0]);
+              smp_num_probed, cpumask_bits(cpu_present_mask)[0]);
 }
 
 /*
@@ -629,8 +629,9 @@ smp_send_reschedule(int cpu)
 void
 smp_send_stop(void)
 {
-       cpumask_t to_whom = cpu_possible_map;
-       cpu_clear(smp_processor_id(), to_whom);
+       cpumask_t to_whom;
+       cpumask_copy(&to_whom, cpu_possible_mask);
+       cpumask_clear_cpu(smp_processor_id(), &to_whom);
 #ifdef DEBUG_IPI_MSG
        if (hard_smp_processor_id() != boot_cpu_id)
                printk(KERN_WARNING "smp_send_stop: Not on boot cpu.\n");
index 5ac00fd4cd0cbd12ca4fe97208dbbe4809b99d7d..f8856829c22a96bdff7ce25eab5a4c012c07cae9 100644 (file)
@@ -140,7 +140,7 @@ cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity)
 
        for (cpu = 0; cpu < 4; cpu++) {
                unsigned long aff = cpu_irq_affinity[cpu];
-               if (cpu_isset(cpu, affinity))
+               if (cpumask_test_cpu(cpu, &affinity))
                        aff |= 1UL << irq;
                else
                        aff &= ~(1UL << irq);
index fea0e4620994455fd4a3d52471c5b89371571087..6994407e242aec27f243f08860c247b1162ddf70 100644 (file)
@@ -65,10 +65,11 @@ titan_update_irq_hw(unsigned long mask)
        register int bcpu = boot_cpuid;
 
 #ifdef CONFIG_SMP
-       cpumask_t cpm = cpu_present_map;
+       cpumask_t cpm;
        volatile unsigned long *dim0, *dim1, *dim2, *dim3;
        unsigned long mask0, mask1, mask2, mask3, dummy;
 
+       cpumask_copy(&cpm, cpu_present_mask);
        mask &= ~isa_enable;
        mask0 = mask & titan_cpu_irq_affinity[0];
        mask1 = mask & titan_cpu_irq_affinity[1];
@@ -84,10 +85,10 @@ titan_update_irq_hw(unsigned long mask)
        dim1 = &cchip->dim1.csr;
        dim2 = &cchip->dim2.csr;
        dim3 = &cchip->dim3.csr;
-       if (!cpu_isset(0, cpm)) dim0 = &dummy;
-       if (!cpu_isset(1, cpm)) dim1 = &dummy;
-       if (!cpu_isset(2, cpm)) dim2 = &dummy;
-       if (!cpu_isset(3, cpm)) dim3 = &dummy;
+       if (!cpumask_test_cpu(0, &cpm)) dim0 = &dummy;
+       if (!cpumask_test_cpu(1, &cpm)) dim1 = &dummy;
+       if (!cpumask_test_cpu(2, &cpm)) dim2 = &dummy;
+       if (!cpumask_test_cpu(3, &cpm)) dim3 = &dummy;
 
        *dim0 = mask0;
        *dim1 = mask1;
@@ -137,7 +138,7 @@ titan_cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity)
        int cpu;
 
        for (cpu = 0; cpu < 4; cpu++) {
-               if (cpu_isset(cpu, affinity))
+               if (cpumask_test_cpu(cpu, &affinity))
                        titan_cpu_irq_affinity[cpu] |= 1UL << irq;
                else
                        titan_cpu_irq_affinity[cpu] &= ~(1UL << irq);
index 15f999d41c75c820822fffb70a437ab0467d629e..b9c28f3f19560340fdbc343d5ca90875ffc82661 100644 (file)
@@ -519,6 +519,7 @@ sys_call_table:
        .quad sys_open_by_handle_at
        .quad sys_clock_adjtime
        .quad sys_syncfs                        /* 500 */
+       .quad sys_setns
 
        .size sys_call_table, . - sys_call_table
        .type sys_call_table, @object
index 3d890a98a08ba139f8d234755512fdb97f0fe51e..f937ad12385273ab0d97c49648fa30dad325d940 100644 (file)
@@ -39,7 +39,7 @@ SECTIONS
        __init_begin = ALIGN(PAGE_SIZE);
        INIT_TEXT_SECTION(PAGE_SIZE)
        INIT_DATA_SECTION(16)
-       PERCPU(L1_CACHE_BYTES, PAGE_SIZE)
+       PERCPU_SECTION(L1_CACHE_BYTES)
        /* Align to THREAD_SIZE rather than PAGE_SIZE here so any padding page
           needed for the THREAD_SIZE aligned init_task gets freed after init */
        . = ALIGN(THREAD_SIZE);
index 86425ab53bf5d1afa9bd0d4dddcb2e8543b621e4..69d0c5761e2f206d5de46da70703ca22e940ed08 100644 (file)
@@ -32,8 +32,6 @@
 #include <asm/console.h>
 #include <asm/tlb.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 extern void die_if_kernel(char *,struct pt_regs *,long);
 
 static struct pcb_struct original_pcb;
index 7b2c56d8f930b89fc6747ccdca550456f35f83b6..3973ae3957720dd68143cc0a21ecca2a76e8d48d 100644 (file)
@@ -313,6 +313,7 @@ void __init paging_init(void)
                        zones_size[ZONE_DMA] = dma_local_pfn;
                        zones_size[ZONE_NORMAL] = (end_pfn - start_pfn) - dma_local_pfn;
                }
+               node_set_state(nid, N_NORMAL_MEMORY);
                free_area_init_node(nid, zones_size, start_pfn, NULL);
        }
 
index 7275009686e64a9336ff6fb902d57c6363f1d4fd..9adc278a22abb36df1bdfdacd1db1fe240f8d0fb 100644 (file)
@@ -294,6 +294,8 @@ config ARCH_AT91
        bool "Atmel AT91"
        select ARCH_REQUIRE_GPIOLIB
        select HAVE_CLK
+       select CLKDEV_LOOKUP
+       select ARM_PATCH_PHYS_VIRT if MMU
        help
          This enables support for systems based on the Atmel AT91RM9200,
          AT91SAM9 and AT91CAP9 processors.
@@ -730,16 +732,6 @@ config ARCH_S5P64X0
          Samsung S5P64X0 CPU based systems, such as the Samsung SMDK6440,
          SMDK6450.
 
-config ARCH_S5P6442
-       bool "Samsung S5P6442"
-       select CPU_V6
-       select GENERIC_GPIO
-       select HAVE_CLK
-       select ARCH_USES_GETTIMEOFFSET
-       select HAVE_S3C2410_WATCHDOG if WATCHDOG
-       help
-         Samsung S5P6442 CPU based systems
-
 config ARCH_S5PC100
        bool "Samsung S5PC100"
        select GENERIC_GPIO
@@ -991,8 +983,6 @@ endif
 
 source "arch/arm/mach-s5p64x0/Kconfig"
 
-source "arch/arm/mach-s5p6442/Kconfig"
-
 source "arch/arm/mach-s5pc100/Kconfig"
 
 source "arch/arm/mach-s5pv210/Kconfig"
@@ -1399,7 +1389,6 @@ config NR_CPUS
 config HOTPLUG_CPU
        bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
        depends on SMP && HOTPLUG && EXPERIMENTAL
-       depends on !ARCH_MSM
        help
          Say Y here to experiment with turning CPUs off and on.  CPUs
          can be controlled through /sys/devices/system/cpu.
@@ -1420,7 +1409,7 @@ source kernel/Kconfig.preempt
 config HZ
        int
        default 200 if ARCH_EBSA110 || ARCH_S3C2410 || ARCH_S5P64X0 || \
-               ARCH_S5P6442 || ARCH_S5PV210 || ARCH_EXYNOS4
+               ARCH_S5PV210 || ARCH_EXYNOS4
        default OMAP_32K_TIMER_HZ if ARCH_OMAP && OMAP_32K_TIMER
        default AT91_TIMER_HZ if ARCH_AT91
        default SHMOBILE_TIMER_HZ if ARCH_SHMOBILE
@@ -1516,6 +1505,9 @@ config ARCH_SPARSEMEM_DEFAULT
 config ARCH_SELECT_MEMORY_MODEL
        def_bool ARCH_SPARSEMEM_ENABLE
 
+config HAVE_ARCH_PFN_VALID
+       def_bool ARCH_HAS_HOLES_MEMORYMODEL || !SPARSEMEM
+
 config HIGHMEM
        bool "High Memory Support"
        depends on MMU
@@ -1683,6 +1675,13 @@ endmenu
 
 menu "Boot options"
 
+config USE_OF
+       bool "Flattened Device Tree support"
+       select OF
+       select OF_EARLY_FLATTREE
+       help
+         Include support for flattened device tree machine descriptions.
+
 # Compressed boot loader in ROM.  Yes, we really want to ask about
 # TEXT and BSS so we preserve their values in the config files.
 config ZBOOT_ROM_TEXT
@@ -2021,7 +2020,7 @@ menu "Power management options"
 source "kernel/power/Kconfig"
 
 config ARCH_SUSPEND_POSSIBLE
-       depends on !ARCH_S5P64X0 && !ARCH_S5P6442 && !ARCH_S5PC100
+       depends on !ARCH_S5P64X0 && !ARCH_S5PC100
        depends on CPU_ARM920T || CPU_ARM926T || CPU_SA1100 || \
                CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE
        def_bool y
index 03d01d783e3bf95c72f28259aad1550b97c5cc68..81cbe40c159c63c20968d224f960d3d353509946 100644 (file)
@@ -63,13 +63,6 @@ config DEBUG_USER
              8 - SIGSEGV faults
             16 - SIGBUS faults
 
-config DEBUG_STACK_USAGE
-       bool "Enable stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T output.
-
 # These options are only for real kernel hackers who want to get their hands dirty.
 config DEBUG_LL
        bool "Kernel low-level debugging functions"
index 25750bcb3397ed85908b59529c1c2add7695be4d..f5b2b390c8f227353eb26ce233b4786a65229808 100644 (file)
@@ -176,7 +176,6 @@ machine-$(CONFIG_ARCH_S3C2410)              := s3c2410 s3c2400 s3c2412 s3c2416 s3c2440 s3c24
 machine-$(CONFIG_ARCH_S3C24A0)         := s3c24a0
 machine-$(CONFIG_ARCH_S3C64XX)         := s3c64xx
 machine-$(CONFIG_ARCH_S5P64X0)         := s5p64x0
-machine-$(CONFIG_ARCH_S5P6442)         := s5p6442
 machine-$(CONFIG_ARCH_S5PC100)         := s5pc100
 machine-$(CONFIG_ARCH_S5PV210)         := s5pv210
 machine-$(CONFIG_ARCH_EXYNOS4)         := exynos4
index f9da41921c521e216f07816eb5cab99c041f4845..940b20178107f656496645e3a4b38d85d7fb6eb3 100644 (file)
@@ -597,6 +597,8 @@ __common_mmu_cache_on:
                sub     pc, lr, r0, lsr #32     @ properly flush pipeline
 #endif
 
+#define PROC_ENTRY_SIZE (4*5)
+
 /*
  * Here follow the relocatable cache support functions for the
  * various processors.  This is a generic hook for locating an
@@ -624,7 +626,7 @@ call_cache_fn:      adr     r12, proc_types
  ARM(          addeq   pc, r12, r3             ) @ call cache function
  THUMB(                addeq   r12, r3                 )
  THUMB(                moveq   pc, r12                 ) @ call cache function
-               add     r12, r12, #4*5
+               add     r12, r12, #PROC_ENTRY_SIZE
                b       1b
 
 /*
@@ -691,9 +693,9 @@ proc_types:
 
                .word   0x41069260              @ ARM926EJ-S (v5TEJ)
                .word   0xff0ffff0
-               b       __arm926ejs_mmu_cache_on
-               b       __armv4_mmu_cache_off
-               b       __armv5tej_mmu_cache_flush
+               W(b)    __arm926ejs_mmu_cache_on
+               W(b)    __armv4_mmu_cache_off
+               W(b)    __armv5tej_mmu_cache_flush
 
                .word   0x00007000              @ ARM7 IDs
                .word   0x0000f000
@@ -794,6 +796,16 @@ proc_types:
 
                .size   proc_types, . - proc_types
 
+               /*
+                * If you get a "non-constant expression in ".if" statement"
+                * error from the assembler on this line, check that you have
+                * not accidentally written a "b" instruction where you should
+                * have written W(b).
+                */
+               .if (. - proc_types) % PROC_ENTRY_SIZE != 0
+               .error "The size of one or more proc_types entries is wrong."
+               .endif
+
 /*
  * Turn off the Cache and MMU.  ARMv3 does not support
  * reading the control register, but ARMv4 does.
index ea5ee4d067f34e99d40bc58a78e3a75c1e9e3df8..4b71766fb21ddf51e3764eab92ade6051ac6fe09 100644 (file)
@@ -7,7 +7,7 @@ config ARM_VIC
 config ARM_VIC_NR
        int
        default 4 if ARCH_S5PV210
-       default 3 if ARCH_S5P6442 || ARCH_S5PC100
+       default 3 if ARCH_S5PC100
        default 2
        depends on ARM_VIC
        help
diff --git a/arch/arm/configs/at572d940hfek_defconfig b/arch/arm/configs/at572d940hfek_defconfig
deleted file mode 100644 (file)
index 1b1158a..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCALVERSION="-AT572D940HF"
-# CONFIG_LOCALVERSION_AUTO is not set
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_BSD_PROCESS_ACCT_V3=y
-CONFIG_TASKSTATS=y
-CONFIG_TASK_XACCT=y
-CONFIG_TASK_IO_ACCOUNTING=y
-CONFIG_AUDIT=y
-CONFIG_CGROUPS=y
-CONFIG_CGROUP_CPUACCT=y
-CONFIG_CGROUP_SCHED=y
-CONFIG_RT_GROUP_SCHED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_RELAY=y
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EXPERT=y
-CONFIG_SLAB=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
-CONFIG_KPROBES=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_AT91=y
-CONFIG_ARCH_AT572D940HF=y
-CONFIG_MACH_AT572D940HFEB=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
-CONFIG_CMDLINE="mem=48M console=ttyS0 initrd=0x21100000,3145728 root=/dev/ram0 rw ip=172.16.1.181"
-CONFIG_KEXEC=y
-CONFIG_FPE_NWFPE=y
-CONFIG_FPE_NWFPE_XP=y
-CONFIG_NET=y
-CONFIG_PACKET=m
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-CONFIG_NET_PKTGEN=m
-CONFIG_NET_TCPPROBE=m
-CONFIG_CAN=m
-CONFIG_CAN_RAW=m
-CONFIG_CAN_BCM=m
-CONFIG_CAN_VCAN=m
-CONFIG_CAN_DEBUG_DEVICES=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_CONNECTOR=m
-CONFIG_MTD=m
-CONFIG_MTD_DEBUG=y
-CONFIG_MTD_DEBUG_VERBOSE=1
-CONFIG_MTD_CONCAT=m
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=m
-CONFIG_MTD_BLOCK=m
-CONFIG_MTD_BLOCK_RO=m
-CONFIG_FTL=m
-CONFIG_NFTL=m
-CONFIG_NFTL_RW=y
-CONFIG_INFTL=m
-CONFIG_RFD_FTL=m
-CONFIG_SSFDC=m
-CONFIG_MTD_OOPS=m
-CONFIG_MTD_CFI=m
-CONFIG_MTD_JEDECPROBE=m
-CONFIG_MTD_CFI_INTELEXT=m
-CONFIG_MTD_CFI_AMDSTD=m
-CONFIG_MTD_CFI_STAA=m
-CONFIG_MTD_ROM=m
-CONFIG_MTD_ABSENT=m
-CONFIG_MTD_COMPLEX_MAPPINGS=y
-CONFIG_MTD_PHYSMAP=m
-CONFIG_MTD_PLATRAM=m
-CONFIG_MTD_DATAFLASH=m
-CONFIG_MTD_M25P80=m
-CONFIG_MTD_SLRAM=m
-CONFIG_MTD_PHRAM=m
-CONFIG_MTD_MTDRAM=m
-CONFIG_MTD_BLOCK2MTD=m
-CONFIG_MTD_NAND=m
-CONFIG_MTD_NAND_VERIFY_WRITE=y
-CONFIG_MTD_NAND_DISKONCHIP=m
-CONFIG_MTD_NAND_NANDSIM=m
-CONFIG_MTD_NAND_PLATFORM=m
-CONFIG_MTD_ALAUDA=m
-CONFIG_MTD_UBI=m
-CONFIG_MTD_UBI_GLUEBI=m
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_BLK_DEV_NBD=m
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=65536
-CONFIG_ATMEL_TCLIB=y
-CONFIG_ATMEL_SSC=m
-CONFIG_SENSORS_TSL2550=m
-CONFIG_DS1682=m
-CONFIG_RAID_ATTRS=m
-CONFIG_SCSI=m
-CONFIG_SCSI_TGT=m
-# CONFIG_SCSI_PROC_FS is not set
-CONFIG_BLK_DEV_SD=m
-CONFIG_BLK_DEV_SR=m
-CONFIG_CHR_DEV_SG=m
-CONFIG_CHR_DEV_SCH=m
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_SCAN_ASYNC=y
-CONFIG_SCSI_ISCSI_ATTRS=m
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
-CONFIG_BONDING=m
-CONFIG_MACVLAN=m
-CONFIG_EQUALIZER=m
-CONFIG_TUN=m
-CONFIG_VETH=m
-CONFIG_PHYLIB=y
-CONFIG_MARVELL_PHY=m
-CONFIG_DAVICOM_PHY=m
-CONFIG_QSEMI_PHY=m
-CONFIG_LXT_PHY=m
-CONFIG_CICADA_PHY=m
-CONFIG_VITESSE_PHY=m
-CONFIG_SMSC_PHY=m
-CONFIG_BROADCOM_PHY=m
-CONFIG_ICPLUS_PHY=m
-CONFIG_MDIO_BITBANG=m
-CONFIG_NET_ETHERNET=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-CONFIG_USB_ZD1201=m
-CONFIG_HOSTAP=m
-CONFIG_HOSTAP_FIRMWARE=y
-CONFIG_HOSTAP_FIRMWARE_NVRAM=y
-CONFIG_USB_CATC=m
-CONFIG_USB_KAWETH=m
-CONFIG_USB_PEGASUS=m
-CONFIG_USB_RTL8150=m
-CONFIG_USB_USBNET=m
-CONFIG_USB_NET_DM9601=m
-CONFIG_USB_NET_GL620A=m
-CONFIG_USB_NET_PLUSB=m
-CONFIG_USB_NET_MCS7830=m
-CONFIG_USB_NET_RNDIS_HOST=m
-CONFIG_USB_ALI_M5632=y
-CONFIG_USB_AN2720=y
-CONFIG_USB_EPSON2888=y
-CONFIG_USB_KC2190=y
-# CONFIG_USB_NET_ZAURUS is not set
-CONFIG_INPUT_MOUSEDEV=m
-CONFIG_INPUT_EVDEV=m
-CONFIG_INPUT_EVBUG=m
-CONFIG_KEYBOARD_LKKBD=m
-CONFIG_KEYBOARD_GPIO=m
-CONFIG_KEYBOARD_NEWTON=m
-CONFIG_KEYBOARD_STOWAWAY=m
-CONFIG_KEYBOARD_SUNKBD=m
-CONFIG_KEYBOARD_XTKBD=m
-CONFIG_MOUSE_PS2=m
-CONFIG_MOUSE_SERIAL=m
-CONFIG_MOUSE_APPLETOUCH=m
-CONFIG_MOUSE_VSXXXAA=m
-CONFIG_MOUSE_GPIO=m
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_UINPUT=m
-CONFIG_SERIO_SERPORT=m
-CONFIG_SERIO_RAW=m
-CONFIG_VT_HW_CONSOLE_BINDING=y
-CONFIG_SERIAL_NONSTANDARD=y
-CONFIG_N_HDLC=m
-CONFIG_SPECIALIX=m
-CONFIG_STALDRV=y
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_IPMI_HANDLER=m
-CONFIG_IPMI_DEVICE_INTERFACE=m
-CONFIG_IPMI_SI=m
-CONFIG_IPMI_WATCHDOG=m
-CONFIG_IPMI_POWEROFF=m
-CONFIG_HW_RANDOM=y
-CONFIG_R3964=m
-CONFIG_RAW_DRIVER=m
-CONFIG_TCG_TPM=m
-CONFIG_TCG_NSC=m
-CONFIG_TCG_ATMEL=m
-CONFIG_I2C=m
-CONFIG_I2C_CHARDEV=m
-CONFIG_SPI=y
-CONFIG_SPI_ATMEL=y
-CONFIG_SPI_BITBANG=m
-CONFIG_SPI_SPIDEV=m
-# CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_SOUND=m
-CONFIG_SND=m
-CONFIG_SND_SEQUENCER=m
-CONFIG_SND_SEQ_DUMMY=m
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
-# CONFIG_SND_PCM_OSS_PLUGINS is not set
-CONFIG_SND_SEQUENCER_OSS=y
-CONFIG_SND_DYNAMIC_MINORS=y
-# CONFIG_SND_VERBOSE_PROCFS is not set
-CONFIG_SND_DUMMY=m
-CONFIG_SND_VIRMIDI=m
-CONFIG_SND_USB_AUDIO=m
-CONFIG_SND_USB_CAIAQ=m
-CONFIG_SND_USB_CAIAQ_INPUT=y
-CONFIG_HID=m
-CONFIG_HIDRAW=y
-CONFIG_USB_HID=m
-CONFIG_USB_HIDDEV=y
-CONFIG_USB_KBD=m
-CONFIG_USB_MOUSE=m
-CONFIG_HID_A4TECH=m
-CONFIG_HID_APPLE=m
-CONFIG_HID_BELKIN=m
-CONFIG_HID_CHERRY=m
-CONFIG_HID_CHICONY=m
-CONFIG_HID_CYPRESS=m
-CONFIG_HID_EZKEY=m
-CONFIG_HID_GYRATION=m
-CONFIG_HID_LOGITECH=m
-CONFIG_HID_MICROSOFT=m
-CONFIG_HID_MONTEREY=m
-CONFIG_HID_PANTHERLORD=m
-CONFIG_HID_PETALYNX=m
-CONFIG_HID_SAMSUNG=m
-CONFIG_HID_SONY=m
-CONFIG_HID_SUNPLUS=m
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_DEVICE_CLASS is not set
-CONFIG_USB_DYNAMIC_MINORS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=m
-CONFIG_USB_STORAGE_DATAFAB=m
-CONFIG_USB_STORAGE_FREECOM=m
-CONFIG_USB_STORAGE_ISD200=m
-CONFIG_USB_STORAGE_USBAT=m
-CONFIG_USB_STORAGE_SDDR09=m
-CONFIG_USB_STORAGE_SDDR55=m
-CONFIG_USB_STORAGE_JUMPSHOT=m
-CONFIG_USB_STORAGE_ALAUDA=m
-CONFIG_USB_STORAGE_KARMA=m
-CONFIG_USB_LIBUSUAL=y
-CONFIG_USB_SERIAL=m
-CONFIG_USB_EZUSB=y
-CONFIG_USB_SERIAL_GENERIC=y
-CONFIG_USB_SERIAL_PL2303=m
-CONFIG_USB_SERIAL_SPCP8X5=m
-CONFIG_USB_SERIAL_DEBUG=m
-CONFIG_USB_EMI62=m
-CONFIG_USB_EMI26=m
-CONFIG_USB_ADUTUX=m
-CONFIG_USB_TEST=m
-CONFIG_USB_GADGET=m
-CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_GADGET_DEBUG_FS=y
-CONFIG_USB_ZERO=m
-CONFIG_USB_ETH=m
-CONFIG_USB_GADGETFS=m
-CONFIG_USB_FILE_STORAGE=m
-CONFIG_USB_G_SERIAL=m
-CONFIG_USB_MIDI_GADGET=m
-CONFIG_MMC=y
-CONFIG_SDIO_UART=m
-CONFIG_MMC_AT91=m
-CONFIG_MMC_SPI=m
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=m
-CONFIG_LEDS_GPIO=m
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_TIMER=m
-CONFIG_LEDS_TRIGGER_HEARTBEAT=m
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_INTF_DEV_UIE_EMUL=y
-CONFIG_RTC_DRV_DS1307=m
-CONFIG_RTC_DRV_DS1305=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT2_FS_SECURITY=y
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT3_FS_SECURITY=y
-CONFIG_JBD_DEBUG=y
-CONFIG_REISERFS_FS=m
-CONFIG_REISERFS_CHECK=y
-CONFIG_REISERFS_PROC_INFO=y
-CONFIG_REISERFS_FS_XATTR=y
-CONFIG_REISERFS_FS_POSIX_ACL=y
-CONFIG_REISERFS_FS_SECURITY=y
-CONFIG_INOTIFY=y
-CONFIG_FUSE_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=y
-CONFIG_NTFS_FS=m
-CONFIG_NTFS_RW=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_JFFS2_FS=m
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_LZO=y
-CONFIG_JFFS2_CMODE_FAVOURLZO=y
-CONFIG_CRAMFS=m
-CONFIG_NFS_FS=m
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_NFSD=m
-CONFIG_NFSD_V3_ACL=y
-CONFIG_NFSD_V4=y
-CONFIG_CIFS=m
-CONFIG_CIFS_WEAK_PW_HASH=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_MAC_PARTITION=y
-CONFIG_BSD_DISKLABEL=y
-CONFIG_MINIX_SUBPARTITION=y
-CONFIG_SOLARIS_X86_PARTITION=y
-CONFIG_UNIXWARE_DISKLABEL=y
-CONFIG_LDM_PARTITION=y
-CONFIG_LDM_DEBUG=y
-CONFIG_SGI_PARTITION=y
-CONFIG_SUN_PARTITION=y
-CONFIG_NLS_DEFAULT="cp437"
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=m
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_UTF8=m
-CONFIG_DLM=m
-CONFIG_PRINTK_TIME=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_UNUSED_SYMBOLS=y
-CONFIG_DEBUG_FS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_GF128MUL=m
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MD5=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_CCITT=m
-CONFIG_CRC16=m
similarity index 53%
rename from arch/arm/configs/at91sam9261ek_defconfig
rename to arch/arm/configs/at91sam9261_defconfig
index b46025b66b64a1f92bc5639969ce50d84081bbd2..ade6b2f231164b00c1fc22ede4866e47d2aee485 100644 (file)
@@ -1,9 +1,13 @@
 CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
+CONFIG_NAMESPACES=y
+CONFIG_EMBEDDED=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
@@ -15,18 +19,27 @@ CONFIG_ARCH_AT91SAM9261=y
 CONFIG_MACH_AT91SAM9261EK=y
 CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
 # CONFIG_ARM_THUMB is not set
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="mem=64M console=ttyS0,115200 initrd=0x21100000,3145728 root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
+CONFIG_AUTO_ZRELADDR=y
+CONFIG_VFP=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
 CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
+CONFIG_CFG80211=y
+CONFIG_LIB80211=y
+CONFIG_MAC80211=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
@@ -34,8 +47,12 @@ CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_GLUEBI=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_MISC_DEVICES=y
+CONFIG_ATMEL_TCLIB=y
 CONFIG_ATMEL_SSC=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
@@ -45,12 +62,27 @@ CONFIG_NET_ETHERNET=y
 CONFIG_DM9000=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+CONFIG_USB_ZD1201=m
+CONFIG_RTL8187=m
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
+CONFIG_LIBERTAS_SPI=m
+CONFIG_RT2X00=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+CONFIG_ZD1211RW=m
+CONFIG_INPUT_POLLDEV=m
 # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=240
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
+CONFIG_INPUT_EVDEV=y
 # CONFIG_KEYBOARD_ATKBD is not set
 CONFIG_KEYBOARD_GPIO=y
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ADS7846=y
+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
 CONFIG_SERIAL_ATMEL=y
 CONFIG_SERIAL_ATMEL_CONSOLE=y
 CONFIG_HW_RANDOM=y
@@ -65,31 +97,62 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 CONFIG_AT91SAM9X_WATCHDOG=y
 CONFIG_FB=y
 CONFIG_FB_ATMEL=y
-# CONFIG_VGA_CONSOLE is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_ATMEL_LCDC=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SEQUENCER=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+CONFIG_SND_AT73C213=y
+CONFIG_SND_USB_AUDIO=m
 # CONFIG_USB_HID is not set
 CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DEBUG=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
 CONFIG_USB_GADGETFS=m
 CONFIG_USB_FILE_STORAGE=m
 CONFIG_USB_G_SERIAL=m
 CONFIG_MMC=y
 CONFIG_MMC_AT91=m
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_GPIO=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_AT91SAM9=y
-CONFIG_EXT2_FS=y
-CONFIG_INOTIFY=y
+CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_CODEPAGE_850=y
 CONFIG_NLS_ISO8859_1=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_UTF8=y
+CONFIG_FTRACE=y
+CONFIG_CRC_CCITT=m
similarity index 57%
rename from arch/arm/configs/at91sam9263ek_defconfig
rename to arch/arm/configs/at91sam9263_defconfig
index 8a04d6f4e065c613460ad9220bf955a00949c1d0..1cf96264cba1456ad4a7ae54daeb414479c3e684 100644 (file)
@@ -1,9 +1,13 @@
 CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
+CONFIG_NAMESPACES=y
+CONFIG_EMBEDDED=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
@@ -13,53 +17,81 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_ARCH_AT91=y
 CONFIG_ARCH_AT91SAM9263=y
 CONFIG_MACH_AT91SAM9263EK=y
+CONFIG_MACH_USB_A9263=y
+CONFIG_MACH_NEOCORE926=y
 CONFIG_MTD_AT91_DATAFLASH_CARD=y
 # CONFIG_ARM_THUMB is not set
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="mem=64M console=ttyS0,115200 initrd=0x21100000,3145728 root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
+CONFIG_AUTO_ZRELADDR=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
+CONFIG_NET_KEY=y
 CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_ROUTE_VERBOSE=y
 CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
+CONFIG_IPV6=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
+CONFIG_NFTL=y
+CONFIG_NFTL_RW=y
 CONFIG_MTD_DATAFLASH=y
+CONFIG_MTD_BLOCK2MTD=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
+CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_GLUEBI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_ATMEL_SSC=y
+CONFIG_MISC_DEVICES=y
+CONFIG_ATMEL_PWM=y
+CONFIG_ATMEL_TCLIB=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_SCSI_MULTI_LUN=y
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
+CONFIG_SMSC_PHY=y
+CONFIG_NET_ETHERNET=y
 CONFIG_MACB=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_USB_ZD1201=m
+CONFIG_INPUT_POLLDEV=m
 # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=240
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
 CONFIG_INPUT_EVDEV=y
 # CONFIG_KEYBOARD_ATKBD is not set
 CONFIG_KEYBOARD_GPIO=y
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ADS7846=y
-# CONFIG_SERIO is not set
+CONFIG_LEGACY_PTY_COUNT=4
 CONFIG_SERIAL_ATMEL=y
 CONFIG_SERIAL_ATMEL_CONSOLE=y
 CONFIG_HW_RANDOM=y
@@ -74,8 +106,25 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 CONFIG_AT91SAM9X_WATCHDOG=y
 CONFIG_FB=y
 CONFIG_FB_ATMEL=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_USB_HID is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_ATMEL_LCDC=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SEQUENCER=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+CONFIG_SND_ATMEL_AC97C=y
+# CONFIG_SND_SPI is not set
+CONFIG_SND_USB_AUDIO=m
 CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
 CONFIG_USB_MON=y
@@ -83,24 +132,37 @@ CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
 CONFIG_USB_GADGETFS=m
 CONFIG_USB_FILE_STORAGE=m
 CONFIG_USB_G_SERIAL=m
 CONFIG_MMC=y
+CONFIG_SDIO_UART=m
 CONFIG_MMC_AT91=m
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_ATMEL_PWM=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_AT91SAM9=y
 CONFIG_EXT2_FS=y
-CONFIG_INOTIFY=y
+CONFIG_FUSE_FS=m
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_JFFS2_FS=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
 CONFIG_CRAMFS=y
 CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_CODEPAGE_850=y
 CONFIG_NLS_ISO8859_1=y
-CONFIG_DEBUG_KERNEL=y
+CONFIG_FTRACE=y
 CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
+CONFIG_XZ_DEC=y
index 889922ad229c31e8419c7f211cb5ef481e4d612a..67b5abb6f8576e3fa47d248ecea51facf7f7b5dc 100644 (file)
@@ -157,7 +157,7 @@ CONFIG_LEDS_GPIO=m
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_TIMER=m
 CONFIG_LEDS_TRIGGER_HEARTBEAT=m
-CONFIG_RTC_CLASS=m
+CONFIG_RTC_CLASS=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 CONFIG_XFS_FS=m
index 2ffba24d2e2a3936eeb74f19c6872fe70ba01ab4..da53ff3b4d708122668cf2a910ae0f72ce9f4746 100644 (file)
@@ -8,7 +8,9 @@ CONFIG_ARCH_EXYNOS4=y
 CONFIG_S3C_LOWLEVEL_UART_PORT=1
 CONFIG_MACH_SMDKC210=y
 CONFIG_MACH_SMDKV310=y
+CONFIG_MACH_ARMLEX4210=y
 CONFIG_MACH_UNIVERSAL_C210=y
+CONFIG_MACH_NURI=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
diff --git a/arch/arm/configs/neocore926_defconfig b/arch/arm/configs/neocore926_defconfig
deleted file mode 100644 (file)
index 462dd18..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_COMPAT_BRK is not set
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_ARCH_AT91SAM9263=y
-CONFIG_MACH_NEOCORE926=y
-CONFIG_MTD_AT91_DATAFLASH_CARD=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_NET_KEY=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-CONFIG_NET_IPIP=y
-# CONFIG_INET_LRO is not set
-CONFIG_IPV6=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_NFTL=y
-CONFIG_NFTL_RW=y
-CONFIG_MTD_BLOCK2MTD=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ECC_SMC=y
-CONFIG_MTD_NAND_VERIFY_WRITE=y
-CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_NAND_PLATFORM=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_NBD=y
-CONFIG_ATMEL_PWM=y
-CONFIG_ATMEL_TCLIB=y
-CONFIG_SCSI=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_NETDEVICES=y
-CONFIG_SMSC_PHY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_MACB=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_ADS7846=y
-CONFIG_VT_HW_CONSOLE_BINDING=y
-# CONFIG_DEVKMEM is not set
-CONFIG_SERIAL_NONSTANDARD=y
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-# CONFIG_SERIAL_ATMEL_PDC is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_SPI=y
-CONFIG_SPI_ATMEL=y
-# CONFIG_HWMON is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=y
-CONFIG_FB=y
-CONFIG_FB_ATMEL=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_ATMEL_LCDC=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
-CONFIG_LOGO=y
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_MMC=y
-CONFIG_SDIO_UART=y
-CONFIG_MMC_AT91=m
-CONFIG_EXT2_FS=y
-# CONFIG_DNOTIFY is not set
-CONFIG_AUTOFS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_FS_WBUF_VERIFY=y
-CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-# CONFIG_ENABLE_WARN_DEPRECATED is not set
-# CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-# CONFIG_CRYPTO_HW is not set
index 316af5479d90b0cec88b479d70f5991155d5497e..9c0ad7993986f340952c2a74352e3d24e75c1a01 100644 (file)
@@ -60,7 +60,7 @@ CONFIG_FB_ARMCLCD=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
-CONFIG_RTC_CLASS=m
+CONFIG_RTC_CLASS=y
 CONFIG_INOTIFY=y
 CONFIG_TMPFS=y
 CONFIG_JFFS2_FS=y
index 076db52ff6723deacf4ec0c9485909b886be1484..d5f00d7eb075002f315aab9527c94cc80b4175f0 100644 (file)
@@ -21,58 +21,22 @@ CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_ARCH_OMAP=y
-CONFIG_ARCH_OMAP2=y
-CONFIG_ARCH_OMAP3=y
-CONFIG_ARCH_OMAP4=y
 CONFIG_OMAP_RESET_CLOCKS=y
 CONFIG_OMAP_MUX_DEBUG=y
-CONFIG_OMAP_32K_TIMER=y
-CONFIG_MACH_OMAP_GENERIC=y
-CONFIG_ARCH_OMAP2420=y
-CONFIG_ARCH_OMAP2430=y
-CONFIG_ARCH_OMAP3430=y
-CONFIG_MACH_OMAP_H4=y
-CONFIG_MACH_OMAP_APOLLON=y
-CONFIG_MACH_OMAP_2430SDP=y
-CONFIG_MACH_OMAP3_BEAGLE=y
-CONFIG_MACH_DEVKIT8000=y
-CONFIG_MACH_OMAP_LDP=y
-CONFIG_MACH_OVERO=y
-CONFIG_MACH_OMAP3EVM=y
-CONFIG_MACH_OMAP3517EVM=y
-CONFIG_MACH_OMAP3_PANDORA=y
-CONFIG_MACH_OMAP3_TOUCHBOOK=y
-CONFIG_MACH_OMAP_3430SDP=y
-CONFIG_MACH_NOKIA_N8X0=y
-CONFIG_MACH_NOKIA_RX51=y
-CONFIG_MACH_OMAP_ZOOM2=y
-CONFIG_MACH_OMAP_ZOOM3=y
-CONFIG_MACH_CM_T35=y
-CONFIG_MACH_IGEP0020=y
-CONFIG_MACH_SBC3530=y
-CONFIG_MACH_OMAP_3630SDP=y
-CONFIG_MACH_OMAP_4430SDP=y
 CONFIG_ARM_THUMBEE=y
-CONFIG_ARM_L1_CACHE_SHIFT=5
 CONFIG_ARM_ERRATA_411920=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=2
-# CONFIG_LOCAL_TIMERS is not set
-CONFIG_AEABI=y
 CONFIG_LEDS=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO2,115200"
 CONFIG_KEXEC=y
 CONFIG_FPE_NWFPE=y
-CONFIG_VFP=y
-CONFIG_NEON=y
 CONFIG_BINFMT_MISC=y
-CONFIG_PM=y
 CONFIG_PM_DEBUG=y
-CONFIG_PM_RUNTIME=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -89,14 +53,6 @@ CONFIG_IP_PNP_RARP=y
 # CONFIG_IPV6 is not set
 CONFIG_NETFILTER=y
 CONFIG_BT=m
-CONFIG_BT_L2CAP=m
-CONFIG_BT_SCO=m
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=m
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=m
 CONFIG_BT_HCIUART=m
 CONFIG_BT_HCIUART_H4=y
 CONFIG_BT_HCIUART_BCSP=y
@@ -107,11 +63,9 @@ CONFIG_CFG80211=m
 CONFIG_MAC80211=m
 CONFIG_MAC80211_RC_PID=y
 CONFIG_MAC80211_RC_DEFAULT_PID=y
-CONFIG_MAC80211_LEDS=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_CONNECTOR=y
 CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
@@ -127,7 +81,6 @@ CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_EEPROM_LEGACY=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_SCSI_MULTI_LUN=y
@@ -158,19 +111,15 @@ CONFIG_TOUCHSCREEN_ADS7846=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_TWL4030_PWRBUTTON=y
 CONFIG_VT_HW_CONSOLE_BINDING=y
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_8250_NR_UARTS=32
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
 CONFIG_SERIAL_8250_DETECT_IRQ=y
 CONFIG_SERIAL_8250_RSA=y
-# CONFIG_LEGACY_PTYS is not set
 CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_OMAP=y
 CONFIG_SPI=y
 CONFIG_SPI_OMAP24XX=y
 CONFIG_DEBUG_GPIO=y
@@ -181,10 +130,6 @@ CONFIG_POWER_SUPPLY=y
 CONFIG_WATCHDOG=y
 CONFIG_OMAP_WATCHDOG=y
 CONFIG_TWL4030_WATCHDOG=y
-CONFIG_MENELAUS=y
-CONFIG_TWL4030_CORE=y
-CONFIG_TWL4030_POWER=y
-CONFIG_REGULATOR=y
 CONFIG_REGULATOR_TWL4030=y
 CONFIG_REGULATOR_TPS65023=y
 CONFIG_REGULATOR_TPS6507X=y
@@ -208,7 +153,6 @@ CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_PLATFORM=y
 CONFIG_DISPLAY_SUPPORT=y
-# CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
 CONFIG_FONTS=y
@@ -217,25 +161,20 @@ CONFIG_FONT_8x16=y
 CONFIG_LOGO=y
 CONFIG_SOUND=m
 CONFIG_SND=m
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
 CONFIG_SND_VERBOSE_PRINTK=y
 CONFIG_SND_DEBUG=y
-CONFIG_SND_USB_AUDIO=y
-CONFIG_SND_SOC=y
-CONFIG_SND_OMAP_SOC=y
-CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=y
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_SOC=m
+CONFIG_SND_OMAP_SOC=m
+CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=m
 CONFIG_USB=y
 CONFIG_USB_DEBUG=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_DEVICEFS=y
 CONFIG_USB_SUSPEND=y
-# CONFIG_USB_OTG_WHITELIST is not set
 CONFIG_USB_MON=y
-# CONFIG_USB_MUSB_HDRC is not set
-# CONFIG_USB_MUSB_OTG is not set
-# CONFIG_USB_GADGET_MUSB_HDRC is not set
-CONFIG_USB_MUSB_DEBUG=y
 CONFIG_USB_WDM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_LIBUSUAL=y
@@ -250,18 +189,12 @@ CONFIG_MMC_UNSAFE_RESUME=y
 CONFIG_SDIO_UART=y
 CONFIG_MMC_OMAP=y
 CONFIG_MMC_OMAP_HS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_TRIGGER_TIMER=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_TWL92330=y
 CONFIG_RTC_DRV_TWL4030=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_FS_XATTR is not set
-CONFIG_INOTIFY=y
 CONFIG_QUOTA=y
 CONFIG_QFMT_V2=y
 CONFIG_MSDOS_FS=y
@@ -285,12 +218,10 @@ CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
 CONFIG_PROVE_LOCKING=y
-# CONFIG_LOCK_STAT is not set
 CONFIG_DEBUG_SPINLOCK_SLEEP=y
 # CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/s5p6442_defconfig b/arch/arm/configs/s5p6442_defconfig
deleted file mode 100644 (file)
index 0e92a78..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_KALLSYMS_ALL=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_S5P6442=y
-CONFIG_S3C_LOWLEVEL_UART_PORT=1
-CONFIG_MACH_SMDK6442=y
-CONFIG_CPU_32v6K=y
-CONFIG_AEABI=y
-CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x20800000,8M console=ttySAC1,115200 init=/linuxrc"
-CONFIG_FPE_NWFPE=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-# CONFIG_MISC_DEVICES is not set
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_NR_UARTS=3
-CONFIG_SERIAL_SAMSUNG=y
-CONFIG_SERIAL_SAMSUNG_CONSOLE=y
-CONFIG_HW_RANDOM=y
-# CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_EXT2_FS=y
-CONFIG_INOTIFY=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_CRAMFS=y
-CONFIG_ROMFS_FS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_BSD_DISKLABEL=y
-CONFIG_SOLARIS_X86_PARTITION=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_RT_MUTEXES=y
-CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_MUTEXES=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-# CONFIG_ARM_UNWIND is not set
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
-CONFIG_DEBUG_S3C_UART=1
-CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/usb-a9263_defconfig b/arch/arm/configs/usb-a9263_defconfig
deleted file mode 100644 (file)
index ee82d09..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_ARCH_AT91SAM9263=y
-CONFIG_MACH_USB_A9263=y
-CONFIG_AT91_SLOW_CLOCK=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=64M console=ttyS0,115200"
-CONFIG_FPE_NWFPE=y
-CONFIG_PM=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_ROUTE_VERBOSE=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-CONFIG_IP_MROUTE=y
-CONFIG_IP_PIMSM_V1=y
-CONFIG_IP_PIMSM_V2=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_DATAFLASH=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-CONFIG_MACB=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_EVBUG=y
-# CONFIG_KEYBOARD_ATKBD is not set
-CONFIG_KEYBOARD_GPIO=y
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_HW_RANDOM=y
-CONFIG_SPI=y
-CONFIG_SPI_ATMEL=y
-# CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_ETH=m
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_EXT2_FS=y
-CONFIG_INOTIFY=y
-CONFIG_FUSE_FS=m
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
-# CONFIG_CRYPTO_HW is not set
index 8b0c717378faa6c9596b9c4b22a4d9dea1b9da65..1d01ddd33122d76fa7db12e989ed0ac09e2293d7 100644 (file)
@@ -142,7 +142,7 @@ CONFIG_USB_GADGETFS=m
 CONFIG_USB_FILE_STORAGE=m
 CONFIG_USB_G_SERIAL=m
 CONFIG_USB_G_PRINTER=m
-CONFIG_RTC_CLASS=m
+CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_DS1307=m
 CONFIG_RTC_DRV_SA1100=m
 CONFIG_EXT2_FS=m
index 5b5504143647fe23fafb93e0a7df67b9b5b7f8c3..721832ffe2d728476ff5395333d23795efcfba8a 100644 (file)
@@ -73,7 +73,7 @@ CONFIG_SENSORS_MAX6650=m
 # CONFIG_VGA_CONSOLE is not set
 # CONFIG_HID_SUPPORT is not set
 # CONFIG_USB_SUPPORT is not set
-CONFIG_RTC_CLASS=m
+CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_SA1100=m
 CONFIG_DMADEVICES=y
 # CONFIG_DNOTIFY is not set
index 960f65514d88161389798236bb26ecd4c704b0cd..59577ad3f4efdfda65e65753054673a32614e80f 100644 (file)
@@ -158,7 +158,7 @@ CONFIG_LEDS_TRIGGER_HEARTBEAT=m
 CONFIG_LEDS_TRIGGER_BACKLIGHT=m
 CONFIG_LEDS_TRIGGER_GPIO=m
 CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
-CONFIG_RTC_CLASS=m
+CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_ISL1208=m
 CONFIG_RTC_DRV_PXA=m
 CONFIG_EXT2_FS=y
index bc2d2d75f7068998bb69a92b69c1216ec4dbd8fe..65c3f2474f5e3333142952b4dc7a1f445bcaedb4 100644 (file)
@@ -13,6 +13,9 @@
  *  Do not include any C declarations in this file - it is included by
  *  assembler source.
  */
+#ifndef __ASM_ASSEMBLER_H__
+#define __ASM_ASSEMBLER_H__
+
 #ifndef __ASSEMBLY__
 #error "Only include this from assembly code"
 #endif
        .macro  ldrusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
        usracc  ldr, \reg, \ptr, \inc, \cond, \rept, \abort
        .endm
+#endif /* __ASM_ASSEMBLER_H__ */
index 6b7403fd8f54f939e8827b29cc59d6c53a1f9f42..b4892a06442cea0a6b80ed1a99e465d0126db2d0 100644 (file)
@@ -203,8 +203,6 @@ extern int _find_next_bit_be(const unsigned long *p, int size, int offset);
 #define find_first_bit(p,sz)           _find_first_bit_le(p,sz)
 #define find_next_bit(p,sz,off)                _find_next_bit_le(p,sz,off)
 
-#define WORD_BITOFF_TO_LE(x)           ((x))
-
 #else
 /*
  * These are the big endian, atomic definitions.
@@ -214,8 +212,6 @@ extern int _find_next_bit_be(const unsigned long *p, int size, int offset);
 #define find_first_bit(p,sz)           _find_first_bit_be(p,sz)
 #define find_next_bit(p,sz,off)                _find_next_bit_be(p,sz,off)
 
-#define WORD_BITOFF_TO_LE(x)           ((x) ^ 0x18)
-
 #endif
 
 #if __LINUX_ARM_ARCH__ < 5
@@ -287,55 +283,29 @@ static inline int fls(int x)
 #include <asm-generic/bitops/hweight.h>
 #include <asm-generic/bitops/lock.h>
 
-static inline void __set_bit_le(int nr, void *addr)
-{
-       __set_bit(WORD_BITOFF_TO_LE(nr), addr);
-}
-
-static inline void __clear_bit_le(int nr, void *addr)
-{
-       __clear_bit(WORD_BITOFF_TO_LE(nr), addr);
-}
-
-static inline int __test_and_set_bit_le(int nr, void *addr)
-{
-       return __test_and_set_bit(WORD_BITOFF_TO_LE(nr), addr);
-}
-
-static inline int test_and_set_bit_le(int nr, void *addr)
-{
-       return test_and_set_bit(WORD_BITOFF_TO_LE(nr), addr);
-}
-
-static inline int __test_and_clear_bit_le(int nr, void *addr)
-{
-       return __test_and_clear_bit(WORD_BITOFF_TO_LE(nr), addr);
-}
-
-static inline int test_and_clear_bit_le(int nr, void *addr)
-{
-       return test_and_clear_bit(WORD_BITOFF_TO_LE(nr), addr);
-}
-
-static inline int test_bit_le(int nr, const void *addr)
-{
-       return test_bit(WORD_BITOFF_TO_LE(nr), addr);
-}
+#ifdef __ARMEB__
 
 static inline int find_first_zero_bit_le(const void *p, unsigned size)
 {
        return _find_first_zero_bit_le(p, size);
 }
+#define find_first_zero_bit_le find_first_zero_bit_le
 
 static inline int find_next_zero_bit_le(const void *p, int size, int offset)
 {
        return _find_next_zero_bit_le(p, size, offset);
 }
+#define find_next_zero_bit_le find_next_zero_bit_le
 
 static inline int find_next_bit_le(const void *p, int size, int offset)
 {
        return _find_next_bit_le(p, size, offset);
 }
+#define find_next_bit_le find_next_bit_le
+
+#endif
+
+#include <asm-generic/bitops/le.h>
 
 /*
  * Ext2 is defined to use little-endian byte ordering.
index ec0bbf79c71fd30d6c523773a4baf6bafffe5c6f..2da8547de6d6203c605759a9326f1b1a8d259d08 100644 (file)
@@ -1,3 +1,5 @@
+#include <asm/assembler.h>
+
 /*
  * Interrupt handling.  Preserves r7, r8, r9
  */
index 2242ce22ec6c866285391f94696149e3977dece3..d493d0b742a1383e716ab1b3c8f3286756e27689 100644 (file)
@@ -4,6 +4,13 @@
  * Support for FIQ on ARM architectures.
  * Written by Philip Blundell <philb@gnu.org>, 1998
  * Re-written by Russell King
+ *
+ * NOTE: The FIQ mode registers are not magically preserved across
+ * suspend/resume.
+ *
+ * Drivers which require these registers to be preserved across power
+ * management operations must implement appropriate suspend/resume handlers to
+ * save and restore them.
  */
 
 #ifndef __ASM_FIQ_H
@@ -29,9 +36,21 @@ struct fiq_handler {
 extern int claim_fiq(struct fiq_handler *f);
 extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
-extern void set_fiq_regs(struct pt_regs *regs);
-extern void get_fiq_regs(struct pt_regs *regs);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
 
+/* helpers defined in fiqasm.S: */
+extern void __set_fiq_regs(unsigned long const *regs);
+extern void __get_fiq_regs(unsigned long *regs);
+
+static inline void set_fiq_regs(struct pt_regs const *regs)
+{
+       __set_fiq_regs(&regs->ARM_r8);
+}
+
+static inline void get_fiq_regs(struct pt_regs *regs)
+{
+       __get_fiq_regs(&regs->ARM_r8);
+}
+
 #endif
index bf13b814c1b8c574256d5a383956f9b1a6d1f822..946f4d778f71648249e99588db97cbeb4c9ca941 100644 (file)
@@ -18,6 +18,8 @@ struct machine_desc {
        unsigned int            nr;             /* architecture number  */
        const char              *name;          /* architecture name    */
        unsigned long           boot_params;    /* tagged list          */
+       const char              **dt_compat;    /* array of device tree
+                                                * 'compatible' strings */
 
        unsigned int            nr_irqs;        /* number of IRQs */
 
@@ -47,6 +49,13 @@ struct machine_desc {
  */
 extern struct machine_desc *machine_desc;
 
+/*
+ * Machine type table - also only accessible during boot
+ */
+extern struct machine_desc __arch_info_begin[], __arch_info_end[];
+#define for_each_machine_desc(p)                       \
+       for (p = __arch_info_begin; p < __arch_info_end; p++)
+
 /*
  * Set of macros to define architecture features.  This is built into
  * a table by the linker.
index f51a69595f6ed53bc2d46d07a146f8b08ac6b83d..ac75d08488892f22dace530691de9a001d884f48 100644 (file)
@@ -197,7 +197,7 @@ typedef unsigned long pgprot_t;
 
 typedef struct page *pgtable_t;
 
-#ifndef CONFIG_SPARSEMEM
+#ifdef CONFIG_HAVE_ARCH_PFN_VALID
 extern int pfn_valid(unsigned long);
 #endif
 
diff --git a/arch/arm/include/asm/prom.h b/arch/arm/include/asm/prom.h
new file mode 100644 (file)
index 0000000..11b8708
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *  arch/arm/include/asm/prom.h
+ *
+ *  Copyright (C) 2009 Canonical Ltd. <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#ifndef __ASMARM_PROM_H
+#define __ASMARM_PROM_H
+
+#ifdef CONFIG_OF
+
+#include <asm/setup.h>
+#include <asm/irq.h>
+
+static inline void irq_dispose_mapping(unsigned int virq)
+{
+       return;
+}
+
+extern struct machine_desc *setup_machine_fdt(unsigned int dt_phys);
+extern void arm_dt_memblock_reserve(void);
+
+#else /* CONFIG_OF */
+
+static inline struct machine_desc *setup_machine_fdt(unsigned int dt_phys)
+{
+       return NULL;
+}
+
+static inline void arm_dt_memblock_reserve(void) { }
+
+#endif /* CONFIG_OF */
+#endif /* ASMARM_PROM_H */
index 95176af3df8cdd1a5df238b0d738da47db316bf6..ee2ad8ae07af7d4006d82a474cb2282654cb986a 100644 (file)
@@ -217,6 +217,10 @@ extern struct meminfo meminfo;
 #define bank_phys_end(bank)    ((bank)->start + (bank)->size)
 #define bank_phys_size(bank)   (bank)->size
 
+extern int arm_add_memory(phys_addr_t start, unsigned long size);
+extern void early_print(const char *str, ...);
+extern void dump_machine_table(void);
+
 #endif  /*  __KERNEL__  */
 
 #endif
index a87664f54f93480b702afe8c52d838052217bc58..e42d96a45d3e9267566cfa662a71235423c1e2f0 100644 (file)
 
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
-/*
- * at the moment, there's not a big penalty for changing CPUs
- * (the >big< penalty is running SMP in the first place)
- */
-#define PROC_CHANGE_PENALTY            15
-
 struct seq_file;
 
 /*
@@ -76,6 +70,7 @@ extern void platform_smp_prepare_cpus(unsigned int);
  */
 struct secondary_data {
        unsigned long pgdir;
+       unsigned long swapper_pg_dir;
        void *stack;
 };
 extern struct secondary_data secondary_data;
index 82dfe5d0c41e764b077acd0fca5b36c525586fc5..265f908c4a6e79b98e07d43b7614c5164e86da53 100644 (file)
  */
 #if defined(CONFIG_SMP) || defined(CONFIG_CPU_32v7)
 #define tlb_fast_mode(tlb)     0
-#define FREE_PTE_NR            500
 #else
 #define tlb_fast_mode(tlb)     1
-#define FREE_PTE_NR            0
 #endif
 
+#define MMU_GATHER_BUNDLE      8
+
 /*
  * TLB handling.  This allows us to remove pages from the page
  * tables, and efficiently handle the TLB issues.
@@ -58,7 +58,9 @@ struct mmu_gather {
        unsigned long           range_start;
        unsigned long           range_end;
        unsigned int            nr;
-       struct page             *pages[FREE_PTE_NR];
+       unsigned int            max;
+       struct page             **pages;
+       struct page             *local[MMU_GATHER_BUNDLE];
 };
 
 DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
@@ -97,26 +99,37 @@ static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr)
        }
 }
 
+static inline void __tlb_alloc_page(struct mmu_gather *tlb)
+{
+       unsigned long addr = __get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);
+
+       if (addr) {
+               tlb->pages = (void *)addr;
+               tlb->max = PAGE_SIZE / sizeof(struct page *);
+       }
+}
+
 static inline void tlb_flush_mmu(struct mmu_gather *tlb)
 {
        tlb_flush(tlb);
        if (!tlb_fast_mode(tlb)) {
                free_pages_and_swap_cache(tlb->pages, tlb->nr);
                tlb->nr = 0;
+               if (tlb->pages == tlb->local)
+                       __tlb_alloc_page(tlb);
        }
 }
 
-static inline struct mmu_gather *
-tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
+static inline void
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int fullmm)
 {
-       struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
-
        tlb->mm = mm;
-       tlb->fullmm = full_mm_flush;
+       tlb->fullmm = fullmm;
        tlb->vma = NULL;
+       tlb->max = ARRAY_SIZE(tlb->local);
+       tlb->pages = tlb->local;
        tlb->nr = 0;
-
-       return tlb;
+       __tlb_alloc_page(tlb);
 }
 
 static inline void
@@ -127,7 +140,8 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
        /* keep the page table cache within bounds */
        check_pgt_cache();
 
-       put_cpu_var(mmu_gathers);
+       if (tlb->pages != tlb->local)
+               free_pages((unsigned long)tlb->pages, 0);
 }
 
 /*
@@ -162,15 +176,22 @@ tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
                tlb_flush(tlb);
 }
 
-static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
 {
        if (tlb_fast_mode(tlb)) {
                free_page_and_swap_cache(page);
-       } else {
-               tlb->pages[tlb->nr++] = page;
-               if (tlb->nr >= FREE_PTE_NR)
-                       tlb_flush_mmu(tlb);
+               return 1; /* avoid calling tlb_flush_mmu */
        }
+
+       tlb->pages[tlb->nr++] = page;
+       VM_BUG_ON(tlb->nr > tlb->max);
+       return tlb->max - tlb->nr;
+}
+
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       if (!__tlb_remove_page(tlb, page))
+               tlb_flush_mmu(tlb);
 }
 
 static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
index 87dbe3e21970c224391e4f2e29e08c34157821f7..2c04ed5efeb50707ac3353958434d37691841839 100644 (file)
 #define __NR_open_by_handle_at         (__NR_SYSCALL_BASE+371)
 #define __NR_clock_adjtime             (__NR_SYSCALL_BASE+372)
 #define __NR_syncfs                    (__NR_SYSCALL_BASE+373)
+#define __NR_sendmmsg                  (__NR_SYSCALL_BASE+374)
+#define __NR_setns                     (__NR_SYSCALL_BASE+375)
 
 /*
  * The following SWIs are ARM private.
index 8d95446150a3e7ed0ad8fd5782f7f918529bc3d7..a5b31af5c2b81717bc98a6851a8daf2ec2b04d7a 100644 (file)
@@ -24,7 +24,7 @@ obj-$(CONFIG_OC_ETM)          += etm.o
 
 obj-$(CONFIG_ISA_DMA_API)      += dma.o
 obj-$(CONFIG_ARCH_ACORN)       += ecard.o 
-obj-$(CONFIG_FIQ)              += fiq.o
+obj-$(CONFIG_FIQ)              += fiq.o fiqasm.o
 obj-$(CONFIG_MODULES)          += armksyms.o module.o
 obj-$(CONFIG_ARTHUR)           += arthur.o
 obj-$(CONFIG_ISA_DMA)          += dma-isa.o
@@ -44,6 +44,7 @@ obj-$(CONFIG_ARM_THUMBEE)     += thumbee.o
 obj-$(CONFIG_KGDB)             += kgdb.o
 obj-$(CONFIG_ARM_UNWIND)       += unwind.o
 obj-$(CONFIG_HAVE_TCM)         += tcm.o
+obj-$(CONFIG_OF)               += devtree.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
 obj-$(CONFIG_SWP_EMULATE)      += swp_emulate.o
 CFLAGS_swp_emulate.o           := -Wa,-march=armv7-a
index 7fbf28c35bb2b438469894bb6bc80797fd8a3cf6..80f7896cc0164ad6f74469f1e777b90c1f306443 100644 (file)
                CALL(sys_open_by_handle_at)
                CALL(sys_clock_adjtime)
                CALL(sys_syncfs)
+               CALL(sys_sendmmsg)
+/* 375 */      CALL(sys_setns)
 #ifndef syscalls_counted
 .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
 #define syscalls_counted
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
new file mode 100644 (file)
index 0000000..0cdd7b4
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ *  linux/arch/arm/kernel/devtree.c
+ *
+ *  Copyright (C) 2009 Canonical Ltd. <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/bootmem.h>
+#include <linux/memblock.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+void __init early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+       arm_add_memory(base, size);
+}
+
+void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
+{
+       return alloc_bootmem_align(size, align);
+}
+
+void __init arm_dt_memblock_reserve(void)
+{
+       u64 *reserve_map, base, size;
+
+       if (!initial_boot_params)
+               return;
+
+       /* Reserve the dtb region */
+       memblock_reserve(virt_to_phys(initial_boot_params),
+                        be32_to_cpu(initial_boot_params->totalsize));
+
+       /*
+        * Process the reserve map.  This will probably overlap the initrd
+        * and dtb locations which are already reserved, but overlaping
+        * doesn't hurt anything
+        */
+       reserve_map = ((void*)initial_boot_params) +
+                       be32_to_cpu(initial_boot_params->off_mem_rsvmap);
+       while (1) {
+               base = be64_to_cpup(reserve_map++);
+               size = be64_to_cpup(reserve_map++);
+               if (!size)
+                       break;
+               memblock_reserve(base, size);
+       }
+}
+
+/**
+ * setup_machine_fdt - Machine setup when an dtb was passed to the kernel
+ * @dt_phys: physical address of dt blob
+ *
+ * If a dtb was passed to the kernel in r2, then use it to choose the
+ * correct machine_desc and to setup the system.
+ */
+struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
+{
+       struct boot_param_header *devtree;
+       struct machine_desc *mdesc, *mdesc_best = NULL;
+       unsigned int score, mdesc_score = ~1;
+       unsigned long dt_root;
+       const char *model;
+
+       if (!dt_phys)
+               return NULL;
+
+       devtree = phys_to_virt(dt_phys);
+
+       /* check device tree validity */
+       if (be32_to_cpu(devtree->magic) != OF_DT_HEADER)
+               return NULL;
+
+       /* Search the mdescs for the 'best' compatible value match */
+       initial_boot_params = devtree;
+       dt_root = of_get_flat_dt_root();
+       for_each_machine_desc(mdesc) {
+               score = of_flat_dt_match(dt_root, mdesc->dt_compat);
+               if (score > 0 && score < mdesc_score) {
+                       mdesc_best = mdesc;
+                       mdesc_score = score;
+               }
+       }
+       if (!mdesc_best) {
+               const char *prop;
+               long size;
+
+               early_print("\nError: unrecognized/unsupported "
+                           "device tree compatible list:\n[ ");
+
+               prop = of_get_flat_dt_prop(dt_root, "compatible", &size);
+               while (size > 0) {
+                       early_print("'%s' ", prop);
+                       size -= strlen(prop) + 1;
+                       prop += strlen(prop) + 1;
+               }
+               early_print("]\n\n");
+
+               dump_machine_table(); /* does not return */
+       }
+
+       model = of_get_flat_dt_prop(dt_root, "model", NULL);
+       if (!model)
+               model = of_get_flat_dt_prop(dt_root, "compatible", NULL);
+       if (!model)
+               model = "<unknown>";
+       pr_info("Machine: %s, model: %s\n", mdesc_best->name, model);
+
+       /* Retrieve various information from the /chosen node */
+       of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
+       /* Initialize {size,address}-cells info */
+       of_scan_flat_dt(early_init_dt_scan_root, NULL);
+       /* Setup memory, calling early_init_dt_add_memory_arch */
+       of_scan_flat_dt(early_init_dt_scan_memory, NULL);
+
+       /* Change machine number to match the mdesc we're using */
+       __machine_arch_type = mdesc_best->nr;
+
+       return mdesc_best;
+}
+
+/**
+ * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq#
+ *
+ * Currently the mapping mechanism is trivial; simple flat hwirq numbers are
+ * mapped 1:1 onto Linux irq numbers.  Cascaded irq controllers are not
+ * supported.
+ */
+unsigned int irq_create_of_mapping(struct device_node *controller,
+                                  const u32 *intspec, unsigned int intsize)
+{
+       return intspec[0];
+}
+EXPORT_SYMBOL_GPL(irq_create_of_mapping);
index e8d88567680718167cf2fe389dbe4af3e0155887..90c62cd51ca9ffc891f7c95336b1c2017097d512 100644 (file)
@@ -435,6 +435,10 @@ __irq_usr:
        usr_entry
        kuser_cmpxchg_check
 
+#ifdef CONFIG_IRQSOFF_TRACER
+       bl      trace_hardirqs_off
+#endif
+
        get_thread_info tsk
 #ifdef CONFIG_PREEMPT
        ldr     r8, [tsk, #TI_PREEMPT]          @ get preempt count
@@ -453,7 +457,7 @@ __irq_usr:
 #endif
 
        mov     why, #0
-       b       ret_to_user
+       b       ret_to_user_from_irq
  UNWIND(.fnend         )
 ENDPROC(__irq_usr)
 
index 1e7b04a40a3164f7226ce82907012acb231fec45..b2a27b6b0046ee6c1e0f0928c3269ab5f6c63cd2 100644 (file)
@@ -64,6 +64,7 @@ work_resched:
 ENTRY(ret_to_user)
 ret_slow_syscall:
        disable_irq                             @ disable interrupts
+ENTRY(ret_to_user_from_irq)
        ldr     r1, [tsk, #TI_FLAGS]
        tst     r1, #_TIF_WORK_MASK
        bne     work_pending
@@ -75,6 +76,7 @@ no_work_pending:
        arch_ret_to_user r1, lr
 
        restore_user_regs fast = 0, offset = 0
+ENDPROC(ret_to_user_from_irq)
 ENDPROC(ret_to_user)
 
 /*
index e72dc34eea1cfbd0f3202067c1a937c4a20821d2..4c164ece5891cfba0bd5e346a4fc51565f92d94b 100644 (file)
@@ -89,47 +89,6 @@ void set_fiq_handler(void *start, unsigned int length)
                flush_icache_range(0x1c, 0x1c + length);
 }
 
-/*
- * Taking an interrupt in FIQ mode is death, so both these functions
- * disable irqs for the duration.  Note - these functions are almost
- * entirely coded in assembly.
- */
-void __naked set_fiq_regs(struct pt_regs *regs)
-{
-       register unsigned long tmp;
-       asm volatile (
-       "mov    ip, sp\n\
-       stmfd   sp!, {fp, ip, lr, pc}\n\
-       sub     fp, ip, #4\n\
-       mrs     %0, cpsr\n\
-       msr     cpsr_c, %2      @ select FIQ mode\n\
-       mov     r0, r0\n\
-       ldmia   %1, {r8 - r14}\n\
-       msr     cpsr_c, %0      @ return to SVC mode\n\
-       mov     r0, r0\n\
-       ldmfd   sp, {fp, sp, pc}"
-       : "=&r" (tmp)
-       : "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE));
-}
-
-void __naked get_fiq_regs(struct pt_regs *regs)
-{
-       register unsigned long tmp;
-       asm volatile (
-       "mov    ip, sp\n\
-       stmfd   sp!, {fp, ip, lr, pc}\n\
-       sub     fp, ip, #4\n\
-       mrs     %0, cpsr\n\
-       msr     cpsr_c, %2      @ select FIQ mode\n\
-       mov     r0, r0\n\
-       stmia   %1, {r8 - r14}\n\
-       msr     cpsr_c, %0      @ return to SVC mode\n\
-       mov     r0, r0\n\
-       ldmfd   sp, {fp, sp, pc}"
-       : "=&r" (tmp)
-       : "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE));
-}
-
 int claim_fiq(struct fiq_handler *f)
 {
        int ret = 0;
@@ -174,8 +133,8 @@ void disable_fiq(int fiq)
 }
 
 EXPORT_SYMBOL(set_fiq_handler);
-EXPORT_SYMBOL(set_fiq_regs);
-EXPORT_SYMBOL(get_fiq_regs);
+EXPORT_SYMBOL(__set_fiq_regs); /* defined in fiqasm.S */
+EXPORT_SYMBOL(__get_fiq_regs); /* defined in fiqasm.S */
 EXPORT_SYMBOL(claim_fiq);
 EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
diff --git a/arch/arm/kernel/fiqasm.S b/arch/arm/kernel/fiqasm.S
new file mode 100644 (file)
index 0000000..207f9d6
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  linux/arch/arm/kernel/fiqasm.S
+ *
+ *  Derived from code originally in linux/arch/arm/kernel/fiq.c:
+ *
+ *  Copyright (C) 1998 Russell King
+ *  Copyright (C) 1998, 1999 Phil Blundell
+ *  Copyright (C) 2011, Linaro Limited
+ *
+ *  FIQ support written by Philip Blundell <philb@gnu.org>, 1998.
+ *
+ *  FIQ support re-written by Russell King to be more generic
+ *
+ *  v7/Thumb-2 compatibility modifications by Linaro Limited, 2011.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Taking an interrupt in FIQ mode is death, so both these functions
+ * disable irqs for the duration.
+ */
+
+ENTRY(__set_fiq_regs)
+       mov     r2, #PSR_I_BIT | PSR_F_BIT | FIQ_MODE
+       mrs     r1, cpsr
+       msr     cpsr_c, r2      @ select FIQ mode
+       mov     r0, r0          @ avoid hazard prior to ARMv4
+       ldmia   r0!, {r8 - r12}
+       ldr     sp, [r0], #4
+       ldr     lr, [r0]
+       msr     cpsr_c, r1      @ return to SVC mode
+       mov     r0, r0          @ avoid hazard prior to ARMv4
+       mov     pc, lr
+ENDPROC(__set_fiq_regs)
+
+ENTRY(__get_fiq_regs)
+       mov     r2, #PSR_I_BIT | PSR_F_BIT | FIQ_MODE
+       mrs     r1, cpsr
+       msr     cpsr_c, r2      @ select FIQ mode
+       mov     r0, r0          @ avoid hazard prior to ARMv4
+       stmia   r0!, {r8 - r12}
+       str     sp, [r0], #4
+       str     lr, [r0]
+       msr     cpsr_c, r1      @ return to SVC mode
+       mov     r0, r0          @ avoid hazard prior to ARMv4
+       mov     pc, lr
+ENDPROC(__get_fiq_regs)
index c84b57d27d07fec692e63c772a80540f90af0946..854bd22380d335dba0e6761c317ccf6f45d3b447 100644 (file)
 #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)
 #define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2)
 
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define OF_DT_MAGIC 0xd00dfeed
+#else
+#define OF_DT_MAGIC 0xedfe0dd0 /* 0xd00dfeed in big-endian */
+#endif
+
 /*
  * Exception handling.  Something went wrong and we can't proceed.  We
  * ought to tell the user, but since we don't have any guarantee that
 
 /* Determine validity of the r2 atags pointer.  The heuristic requires
  * that the pointer be aligned, in the first 16k of physical RAM and
- * that the ATAG_CORE marker is first and present.  Future revisions
+ * that the ATAG_CORE marker is first and present.  If CONFIG_OF_FLATTREE
+ * is selected, then it will also accept a dtb pointer.  Future revisions
  * of this function may be more lenient with the physical address and
  * may also be able to move the ATAGS block if necessary.
  *
  * Returns:
- *  r2 either valid atags pointer, or zero
+ *  r2 either valid atags pointer, valid dtb pointer, or zero
  *  r5, r6 corrupted
  */
 __vet_atags:
        tst     r2, #0x3                        @ aligned?
        bne     1f
 
-       ldr     r5, [r2, #0]                    @ is first tag ATAG_CORE?
-       cmp     r5, #ATAG_CORE_SIZE
+       ldr     r5, [r2, #0]
+#ifdef CONFIG_OF_FLATTREE
+       ldr     r6, =OF_DT_MAGIC                @ is it a DTB?
+       cmp     r5, r6
+       beq     2f
+#endif
+       cmp     r5, #ATAG_CORE_SIZE             @ is first tag ATAG_CORE?
        cmpne   r5, #ATAG_CORE_SIZE_EMPTY
        bne     1f
        ldr     r5, [r2, #4]
@@ -49,7 +61,7 @@ __vet_atags:
        cmp     r5, r6
        bne     1f
 
-       mov     pc, lr                          @ atag pointer is ok
+2:     mov     pc, lr                          @ atag/dtb pointer is ok
 
 1:     mov     r2, #0
        mov     pc, lr
@@ -61,7 +73,7 @@ ENDPROC(__vet_atags)
  *
  *  r0  = cp#15 control register
  *  r1  = machine ID
- *  r2  = atags pointer
+ *  r2  = atags/dtb pointer
  *  r9  = processor ID
  */
        __INIT
index c9173cfbbc74457da7bd726c8645a2d7703baba3..278c1b0ebb2ee340fcb0e4f4b010c80e535c9308 100644 (file)
@@ -59,7 +59,7 @@
  *
  * This is normally called from the decompressor code.  The requirements
  * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
- * r1 = machine nr, r2 = atags pointer.
+ * r1 = machine nr, r2 = atags or dtb pointer.
  *
  * This code is mostly position independent, so if you link the kernel at
  * 0xc0008000, you call this at __pa(0xc0008000).
@@ -91,7 +91,7 @@ ENTRY(stext)
 #endif
 
        /*
-        * r1 = machine no, r2 = atags,
+        * r1 = machine no, r2 = atags or dtb,
         * r8 = phys_offset, r9 = cpuid, r10 = procinfo
         */
        bl      __vet_atags
@@ -113,6 +113,7 @@ ENTRY(stext)
        ldr     r13, =__mmap_switched           @ address to jump to after
                                                @ mmu has been enabled
        adr     lr, BSYM(1f)                    @ return (PIC) address
+       mov     r8, r4                          @ set TTBR1 to swapper_pg_dir
  ARM(  add     pc, r10, #PROCINFO_INITFUNC     )
  THUMB(        add     r12, r10, #PROCINFO_INITFUNC    )
  THUMB(        mov     pc, r12                         )
@@ -302,8 +303,10 @@ ENTRY(secondary_startup)
         */
        adr     r4, __secondary_data
        ldmia   r4, {r5, r7, r12}               @ address to jump to after
-       sub     r4, r4, r5                      @ mmu has been enabled
-       ldr     r4, [r7, r4]                    @ get secondary_data.pgdir
+       sub     lr, r4, r5                      @ mmu has been enabled
+       ldr     r4, [r7, lr]                    @ get secondary_data.pgdir
+       add     r7, r7, #4
+       ldr     r8, [r7, lr]                    @ get secondary_data.swapper_pg_dir
        adr     lr, BSYM(__enable_mmu)          @ return address
        mov     r13, r12                        @ __secondary_switched address
  ARM(  add     pc, r10, #PROCINFO_INITFUNC     ) @ initialise processor
@@ -339,7 +342,7 @@ __secondary_data:
  *
  *  r0  = cp#15 control register
  *  r1  = machine ID
- *  r2  = atags pointer
+ *  r2  = atags or dtb pointer
  *  r4  = page table pointer
  *  r9  = processor ID
  *  r13 = *virtual* address to jump to upon completion
@@ -376,7 +379,7 @@ ENDPROC(__enable_mmu)
  *
  *  r0  = cp#15 control register
  *  r1  = machine ID
- *  r2  = atags pointer
+ *  r2  = atags or dtb pointer
  *  r9  = processor ID
  *  r13 = *virtual* address to jump to upon completion
  *
index fee7c36349eb6c137e7c578946968e20caf35910..016d6a0830a3e202bc42df7c40108a0875916d4b 100644 (file)
@@ -193,8 +193,17 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
                                offset -= 0x02000000;
                        offset += sym->st_value - loc;
 
-                       /* only Thumb addresses allowed (no interworking) */
-                       if (!(offset & 1) ||
+                       /*
+                        * For function symbols, only Thumb addresses are
+                        * allowed (no interworking).
+                        *
+                        * For non-function symbols, the destination
+                        * has no specific ARM/Thumb disposition, so
+                        * the branch is resolved under the assumption
+                        * that interworking is not required.
+                        */
+                       if ((ELF32_ST_TYPE(sym->st_info) == STT_FUNC &&
+                               !(offset & 1)) ||
                            offset <= (s32)0xff000000 ||
                            offset >= (s32)0x01000000) {
                                pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n",
index 6dce209a623b2a0bee4fc3665c1f1ca8dd559d5a..ed11fb08b05a5b2d3fd022d981970c01c9fdc088 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/screen_info.h>
 #include <linux/init.h>
 #include <linux/kexec.h>
+#include <linux/of_fdt.h>
 #include <linux/crash_dump.h>
 #include <linux/root_dev.h>
 #include <linux/cpu.h>
@@ -42,6 +43,7 @@
 #include <asm/cachetype.h>
 #include <asm/tlbflush.h>
 
+#include <asm/prom.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
@@ -309,7 +311,7 @@ static void __init cacheid_init(void)
  */
 extern struct proc_info_list *lookup_processor_type(unsigned int);
 
-static void __init early_print(const char *str, ...)
+void __init early_print(const char *str, ...)
 {
        extern void printascii(const char *);
        char buf[256];
@@ -439,25 +441,12 @@ void cpu_init(void)
            : "r14");
 }
 
-static struct machine_desc * __init setup_machine(unsigned int nr)
+void __init dump_machine_table(void)
 {
-       extern struct machine_desc __arch_info_begin[], __arch_info_end[];
        struct machine_desc *p;
 
-       /*
-        * locate machine in the list of supported machines.
-        */
-       for (p = __arch_info_begin; p < __arch_info_end; p++)
-               if (nr == p->nr) {
-                       printk("Machine: %s\n", p->name);
-                       return p;
-               }
-
-       early_print("\n"
-               "Error: unrecognized/unsupported machine ID (r1 = 0x%08x).\n\n"
-               "Available machine support:\n\nID (hex)\tNAME\n", nr);
-
-       for (p = __arch_info_begin; p < __arch_info_end; p++)
+       early_print("Available machine support:\n\nID (hex)\tNAME\n");
+       for_each_machine_desc(p)
                early_print("%08x\t%s\n", p->nr, p->name);
 
        early_print("\nPlease check your kernel config and/or bootloader.\n");
@@ -466,7 +455,7 @@ static struct machine_desc * __init setup_machine(unsigned int nr)
                /* can't use cpu_relax() here as it may require MMU setup */;
 }
 
-static int __init arm_add_memory(phys_addr_t start, unsigned long size)
+int __init arm_add_memory(phys_addr_t start, unsigned long size)
 {
        struct membank *bank = &meminfo.bank[meminfo.nr_banks];
 
@@ -801,23 +790,29 @@ static void __init squash_mem_tags(struct tag *tag)
                        tag->hdr.tag = ATAG_NONE;
 }
 
-void __init setup_arch(char **cmdline_p)
+static struct machine_desc * __init setup_machine_tags(unsigned int nr)
 {
        struct tag *tags = (struct tag *)&init_tags;
-       struct machine_desc *mdesc;
+       struct machine_desc *mdesc = NULL, *p;
        char *from = default_command_line;
 
        init_tags.mem.start = PHYS_OFFSET;
 
-       unwind_init();
-
-       setup_processor();
-       mdesc = setup_machine(machine_arch_type);
-       machine_desc = mdesc;
-       machine_name = mdesc->name;
+       /*
+        * locate machine in the list of supported machines.
+        */
+       for_each_machine_desc(p)
+               if (nr == p->nr) {
+                       printk("Machine: %s\n", p->name);
+                       mdesc = p;
+                       break;
+               }
 
-       if (mdesc->soft_reboot)
-               reboot_setup("s");
+       if (!mdesc) {
+               early_print("\nError: unrecognized/unsupported machine ID"
+                       " (r1 = 0x%08x).\n\n", nr);
+               dump_machine_table(); /* does not return */
+       }
 
        if (__atags_pointer)
                tags = phys_to_virt(__atags_pointer);
@@ -849,8 +844,17 @@ void __init setup_arch(char **cmdline_p)
        if (tags->hdr.tag != ATAG_CORE)
                convert_to_tag_list(tags);
 #endif
-       if (tags->hdr.tag != ATAG_CORE)
+
+       if (tags->hdr.tag != ATAG_CORE) {
+#if defined(CONFIG_OF)
+               /*
+                * If CONFIG_OF is set, then assume this is a reasonably
+                * modern system that should pass boot parameters
+                */
+               early_print("Warning: Neither atags nor dtb found\n");
+#endif
                tags = (struct tag *)&init_tags;
+       }
 
        if (mdesc->fixup)
                mdesc->fixup(mdesc, tags, &from, &meminfo);
@@ -862,14 +866,34 @@ void __init setup_arch(char **cmdline_p)
                parse_tags(tags);
        }
 
+       /* parse_early_param needs a boot_command_line */
+       strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
+
+       return mdesc;
+}
+
+
+void __init setup_arch(char **cmdline_p)
+{
+       struct machine_desc *mdesc;
+
+       unwind_init();
+
+       setup_processor();
+       mdesc = setup_machine_fdt(__atags_pointer);
+       if (!mdesc)
+               mdesc = setup_machine_tags(machine_arch_type);
+       machine_desc = mdesc;
+       machine_name = mdesc->name;
+
+       if (mdesc->soft_reboot)
+               reboot_setup("s");
+
        init_mm.start_code = (unsigned long) _text;
        init_mm.end_code   = (unsigned long) _etext;
        init_mm.end_data   = (unsigned long) _edata;
        init_mm.brk        = (unsigned long) _end;
 
-       /* parse_early_param needs a boot_command_line */
-       strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
-
        /* populate cmd_line too for later use, preserving boot_command_line */
        strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
        *cmdline_p = cmd_line;
@@ -881,6 +905,8 @@ void __init setup_arch(char **cmdline_p)
        paging_init(mdesc);
        request_standard_resources(mdesc);
 
+       unflatten_device_tree();
+
 #ifdef CONFIG_SMP
        if (is_smp())
                smp_init_cpus();
index d439a8f4c078fcef079a0adcb3844e69bf8d3cee..e7f92a4321f370d0c9e9f9dc73460a0be65c014a 100644 (file)
@@ -105,6 +105,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
         */
        secondary_data.stack = task_stack_page(idle) + THREAD_START_SP;
        secondary_data.pgdir = virt_to_phys(pgd);
+       secondary_data.swapper_pg_dir = virt_to_phys(swapper_pg_dir);
        __cpuc_flush_dcache_area(&secondary_data, sizeof(secondary_data));
        outer_clean_range(__pa(&secondary_data), __pa(&secondary_data + 1));
 
@@ -317,9 +318,13 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
        smp_store_cpu_info(cpu);
 
        /*
-        * OK, now it's safe to let the boot CPU continue
+        * OK, now it's safe to let the boot CPU continue.  Wait for
+        * the CPU migration code to notice that the CPU is online
+        * before we continue.
         */
        set_cpu_online(cpu, true);
+       while (!cpu_active(cpu))
+               cpu_relax();
 
        /*
         * OK, it's off to the idle thread for us
index d52eec268b4746a006ef3badf6805b8acae5d7e1..6807cb1e76ddb119f78100aa3ccc7d59b1184721 100644 (file)
@@ -139,7 +139,7 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
        fs = get_fs();
        set_fs(KERNEL_DS);
 
-       for (i = -4; i < 1; i++) {
+       for (i = -4; i < 1 + !!thumb; i++) {
                unsigned int val, bad;
 
                if (thumb)
@@ -563,7 +563,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
                if (!pmd_present(*pmd))
                        goto bad_access;
                pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
-               if (!pte_present(*pte) || !pte_dirty(*pte)) {
+               if (!pte_present(*pte) || !pte_write(*pte) || !pte_dirty(*pte)) {
                        pte_unmap_unlock(pte, ptl);
                        goto bad_access;
                }
index b4348e62ef06e7903d07561701dd78c462ff1aaf..e5287f21badc7e87c3c2e7a2d8953d5fb270ec86 100644 (file)
@@ -82,7 +82,7 @@ SECTIONS
 #endif
        }
 
-       PERCPU(32, PAGE_SIZE)
+       PERCPU_SECTION(32)
 
 #ifndef CONFIG_XIP_KERNEL
        . = ALIGN(PAGE_SIZE);
index 6dc06487f3c3e95359b2559163f24d8a8ca635cf..c562f649734cea40f813c3d6c50b9cffcd619ae9 100644 (file)
@@ -35,7 +35,7 @@ Boston, MA 02111-1307, USA.  */
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-
+#include <asm/unwind.h>
 
 .macro ARM_DIV_BODY dividend, divisor, result, curbit
 
@@ -207,6 +207,7 @@ Boston, MA 02111-1307, USA.  */
 
 ENTRY(__udivsi3)
 ENTRY(__aeabi_uidiv)
+UNWIND(.fnstart)
 
        subs    r2, r1, #1
        moveq   pc, lr
@@ -230,10 +231,12 @@ ENTRY(__aeabi_uidiv)
        mov     r0, r0, lsr r2
        mov     pc, lr
 
+UNWIND(.fnend)
 ENDPROC(__udivsi3)
 ENDPROC(__aeabi_uidiv)
 
 ENTRY(__umodsi3)
+UNWIND(.fnstart)
 
        subs    r2, r1, #1                      @ compare divisor with 1
        bcc     Ldiv0
@@ -247,10 +250,12 @@ ENTRY(__umodsi3)
 
        mov     pc, lr
 
+UNWIND(.fnend)
 ENDPROC(__umodsi3)
 
 ENTRY(__divsi3)
 ENTRY(__aeabi_idiv)
+UNWIND(.fnstart)
 
        cmp     r1, #0
        eor     ip, r0, r1                      @ save the sign of the result.
@@ -287,10 +292,12 @@ ENTRY(__aeabi_idiv)
        rsbmi   r0, r0, #0
        mov     pc, lr
 
+UNWIND(.fnend)
 ENDPROC(__divsi3)
 ENDPROC(__aeabi_idiv)
 
 ENTRY(__modsi3)
+UNWIND(.fnstart)
 
        cmp     r1, #0
        beq     Ldiv0
@@ -310,11 +317,14 @@ ENTRY(__modsi3)
        rsbmi   r0, r0, #0
        mov     pc, lr
 
+UNWIND(.fnend)
 ENDPROC(__modsi3)
 
 #ifdef CONFIG_AEABI
 
 ENTRY(__aeabi_uidivmod)
+UNWIND(.fnstart)
+UNWIND(.save {r0, r1, ip, lr}  )
 
        stmfd   sp!, {r0, r1, ip, lr}
        bl      __aeabi_uidiv
@@ -323,10 +333,12 @@ ENTRY(__aeabi_uidivmod)
        sub     r1, r1, r3
        mov     pc, lr
 
+UNWIND(.fnend)
 ENDPROC(__aeabi_uidivmod)
 
 ENTRY(__aeabi_idivmod)
-
+UNWIND(.fnstart)
+UNWIND(.save {r0, r1, ip, lr}  )
        stmfd   sp!, {r0, r1, ip, lr}
        bl      __aeabi_idiv
        ldmfd   sp!, {r1, r2, ip, lr}
@@ -334,15 +346,18 @@ ENTRY(__aeabi_idivmod)
        sub     r1, r1, r3
        mov     pc, lr
 
+UNWIND(.fnend)
 ENDPROC(__aeabi_idivmod)
 
 #endif
 
 Ldiv0:
-
+UNWIND(.fnstart)
+UNWIND(.pad #4)
+UNWIND(.save {lr})
        str     lr, [sp, #-8]!
        bl      __div0
        mov     r0, #0                  @ About as wrong as it could be.
        ldr     pc, [sp], #8
-
-
+UNWIND(.fnend)
+ENDPROC(Ldiv0)
index 2d299bf5d72fc05085dacf6ce5bcb20d9c02e1ea..22484670e7ba60948d75aeb3af23009795a2fe37 100644 (file)
@@ -3,9 +3,6 @@ if ARCH_AT91
 config HAVE_AT91_DATAFLASH_CARD
        bool
 
-config HAVE_NAND_ATMEL_BUSWIDTH_16
-       bool
-
 config HAVE_AT91_USART3
        bool
 
@@ -85,11 +82,6 @@ config ARCH_AT91CAP9
        select HAVE_FB_ATMEL
        select HAVE_NET_MACB
 
-config ARCH_AT572D940HF
-       bool "AT572D940HF"
-       select CPU_ARM926T
-       select GENERIC_CLOCKEVENTS
-
 config ARCH_AT91X40
        bool "AT91x40"
        select ARCH_USES_GETTIMEOFFSET
@@ -209,7 +201,6 @@ comment "AT91SAM9260 / AT91SAM9XE Board Type"
 config MACH_AT91SAM9260EK
        bool "Atmel AT91SAM9260-EK / AT91SAM9XE Evaluation Kit"
        select HAVE_AT91_DATAFLASH_CARD
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9260-EK or AT91SAM9XE Evaluation Kit
          <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3933>
@@ -270,7 +261,6 @@ comment "AT91SAM9261 Board Type"
 config MACH_AT91SAM9261EK
        bool "Atmel AT91SAM9261-EK Evaluation Kit"
        select HAVE_AT91_DATAFLASH_CARD
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9261-EK Evaluation Kit.
          <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3820>
@@ -286,7 +276,6 @@ comment "AT91SAM9G10 Board Type"
 config MACH_AT91SAM9G10EK
        bool "Atmel AT91SAM9G10-EK Evaluation Kit"
        select HAVE_AT91_DATAFLASH_CARD
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9G10-EK Evaluation Kit.
          <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4588>
@@ -302,7 +291,6 @@ comment "AT91SAM9263 Board Type"
 config MACH_AT91SAM9263EK
        bool "Atmel AT91SAM9263-EK Evaluation Kit"
        select HAVE_AT91_DATAFLASH_CARD
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9263-EK Evaluation Kit.
          <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4057>
@@ -343,7 +331,6 @@ comment "AT91SAM9G20 Board Type"
 config MACH_AT91SAM9G20EK
        bool "Atmel AT91SAM9G20-EK Evaluation Kit"
        select HAVE_AT91_DATAFLASH_CARD
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9G20-EK Evaluation Kit
          that embeds only one SD/MMC slot.
@@ -351,7 +338,6 @@ config MACH_AT91SAM9G20EK
 config MACH_AT91SAM9G20EK_2MMC
        depends on MACH_AT91SAM9G20EK
        bool "Atmel AT91SAM9G20-EK Evaluation Kit with 2 SD/MMC Slots"
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using an Atmel AT91SAM9G20-EK Evaluation Kit
          with 2 SD/MMC Slots. This is the case for AT91SAM9G20-EK rev. C and
@@ -416,7 +402,6 @@ comment "AT91SAM9G45 Board Type"
 
 config MACH_AT91SAM9M10G45EK
        bool "Atmel AT91SAM9M10G45-EK Evaluation Kits"
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9G45-EKES Evaluation Kit.
          "ES" at the end of the name means that this board is an
@@ -433,7 +418,6 @@ comment "AT91CAP9 Board Type"
 config MACH_AT91CAP9ADK
        bool "Atmel AT91CAP9A-DK Evaluation Kit"
        select HAVE_AT91_DATAFLASH_CARD
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91CAP9A-DK Evaluation Kit.
          <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4138>
@@ -442,23 +426,6 @@ endif
 
 # ----------------------------------------------------------
 
-if ARCH_AT572D940HF
-
-comment "AT572D940HF Board Type"
-
-config MACH_AT572D940HFEB
-       bool "AT572D940HF-EK"
-       depends on ARCH_AT572D940HF
-       select HAVE_AT91_DATAFLASH_CARD
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
-       help
-         Select this if you are using Atmel's AT572D940HF-EK evaluation kit.
-         <http://www.atmel.com/products/diopsis/default.asp>
-
-endif
-
-# ----------------------------------------------------------
-
 if ARCH_AT91X40
 
 comment "AT91X40 Board Type"
@@ -483,13 +450,6 @@ config MTD_AT91_DATAFLASH_CARD
        help
          Enable support for the DataFlash card.
 
-config MTD_NAND_ATMEL_BUSWIDTH_16
-       bool "Enable 16-bit data bus interface to NAND flash"
-       depends on HAVE_NAND_ATMEL_BUSWIDTH_16
-       help
-         On AT91SAM926x boards both types of NAND flash can be present
-         (8 and 16 bit data bus width).
-
 # ----------------------------------------------------------
 
 comment "AT91 Feature Selections"
index a83835e0c1859b359fd15f75f45125a81525a4d8..96966231920cb5af2b18a15677ef14494b2e39dd 100644 (file)
@@ -19,7 +19,6 @@ obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam926x_time.o at91sam9rl_devi
 obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o at91sam9_alt_reset.o
 obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT91CAP9)    += at91cap9.o at91sam926x_time.o at91cap9_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT572D940HF)  += at572d940hf.o at91sam926x_time.o at572d940hf_devices.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT91X40)     += at91x40.o at91x40_time.o
 
 # AT91RM9200 board-specific support
@@ -78,9 +77,6 @@ obj-$(CONFIG_MACH_AT91SAM9M10G45EK) += board-sam9m10g45ek.o
 # AT91CAP9 board-specific support
 obj-$(CONFIG_MACH_AT91CAP9ADK) += board-cap9adk.o
 
-# AT572D940HF board-specific support
-obj-$(CONFIG_MACH_AT572D940HFEB) += board-at572d940hf_ek.o
-
 # AT91X40 board-specific support
 obj-$(CONFIG_MACH_AT91EB01)    += board-eb01.o
 
diff --git a/arch/arm/mach-at91/at572d940hf.c b/arch/arm/mach-at91/at572d940hf.c
deleted file mode 100644 (file)
index a6b9c68..0000000
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * arch/arm/mach-at91/at572d940hf.c
- *
- * Antonio R. Costa <costa.antonior@gmail.com>
- * Copyright (C) 2008 Atmel
- *
- * Copyright (C) 2005 SAN People
- *
- * 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 <asm/mach/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <mach/at572d940hf.h>
-#include <mach/at91_pmc.h>
-#include <mach/at91_rstc.h>
-
-#include "generic.h"
-#include "clock.h"
-
-static struct map_desc at572d940hf_io_desc[] __initdata = {
-       {
-               .virtual        = AT91_VA_BASE_SYS,
-               .pfn            = __phys_to_pfn(AT91_BASE_SYS),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = AT91_IO_VIRT_BASE - AT572D940HF_SRAM_SIZE,
-               .pfn            = __phys_to_pfn(AT572D940HF_SRAM_BASE),
-               .length         = AT572D940HF_SRAM_SIZE,
-               .type           = MT_DEVICE,
-       },
-};
-
-/* --------------------------------------------------------------------
- *  Clocks
- * -------------------------------------------------------------------- */
-
-/*
- * The peripheral clocks.
- */
-static struct clk pioA_clk = {
-       .name           = "pioA_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_PIOA,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioB_clk = {
-       .name           = "pioB_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_PIOB,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioC_clk = {
-       .name           = "pioC_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_PIOC,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk macb_clk = {
-       .name           = "macb_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_EMAC,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart0_clk = {
-       .name           = "usart0_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_US0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart1_clk = {
-       .name           = "usart1_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_US1,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart2_clk = {
-       .name           = "usart2_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_US2,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc_clk = {
-       .name           = "mci_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_MCI,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk udc_clk = {
-       .name           = "udc_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_UDP,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi0_clk = {
-       .name           = "twi0_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_TWI0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi0_clk = {
-       .name           = "spi0_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_SPI0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi1_clk = {
-       .name           = "spi1_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_SPI1,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc0_clk = {
-       .name           = "ssc0_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_SSC0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc1_clk = {
-       .name           = "ssc1_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_SSC1,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc2_clk = {
-       .name           = "ssc2_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_SSC2,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc0_clk = {
-       .name           = "tc0_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_TC0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc1_clk = {
-       .name           = "tc1_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_TC1,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc2_clk = {
-       .name           = "tc2_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_TC2,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ohci_clk = {
-       .name           = "ohci_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_UHP,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc3_clk = {
-       .name           = "ssc3_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_SSC3,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi1_clk = {
-       .name           = "twi1_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_TWI1,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk can0_clk = {
-       .name           = "can0_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_CAN0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk can1_clk = {
-       .name           = "can1_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_CAN1,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mAgicV_clk = {
-       .name           = "mAgicV_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_MSIRQ0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-
-
-static struct clk *periph_clocks[] __initdata = {
-       &pioA_clk,
-       &pioB_clk,
-       &pioC_clk,
-       &macb_clk,
-       &usart0_clk,
-       &usart1_clk,
-       &usart2_clk,
-       &mmc_clk,
-       &udc_clk,
-       &twi0_clk,
-       &spi0_clk,
-       &spi1_clk,
-       &ssc0_clk,
-       &ssc1_clk,
-       &ssc2_clk,
-       &tc0_clk,
-       &tc1_clk,
-       &tc2_clk,
-       &ohci_clk,
-       &ssc3_clk,
-       &twi1_clk,
-       &can0_clk,
-       &can1_clk,
-       &mAgicV_clk,
-       /* irq0 .. irq2 */
-};
-
-/*
- * The five programmable clocks.
- * You must configure pin multiplexing to bring these signals out.
- */
-static struct clk pck0 = {
-       .name           = "pck0",
-       .pmc_mask       = AT91_PMC_PCK0,
-       .type           = CLK_TYPE_PROGRAMMABLE,
-       .id             = 0,
-};
-static struct clk pck1 = {
-       .name           = "pck1",
-       .pmc_mask       = AT91_PMC_PCK1,
-       .type           = CLK_TYPE_PROGRAMMABLE,
-       .id             = 1,
-};
-static struct clk pck2 = {
-       .name           = "pck2",
-       .pmc_mask       = AT91_PMC_PCK2,
-       .type           = CLK_TYPE_PROGRAMMABLE,
-       .id             = 2,
-};
-static struct clk pck3 = {
-       .name           = "pck3",
-       .pmc_mask       = AT91_PMC_PCK3,
-       .type           = CLK_TYPE_PROGRAMMABLE,
-       .id             = 3,
-};
-
-static struct clk mAgicV_mem_clk = {
-       .name           = "mAgicV_mem_clk",
-       .pmc_mask       = AT91_PMC_PCK4,
-       .type           = CLK_TYPE_PROGRAMMABLE,
-       .id             = 4,
-};
-
-/* HClocks */
-static struct clk hck0 = {
-       .name           = "hck0",
-       .pmc_mask       = AT91_PMC_HCK0,
-       .type           = CLK_TYPE_SYSTEM,
-       .id             = 0,
-};
-static struct clk hck1 = {
-       .name           = "hck1",
-       .pmc_mask       = AT91_PMC_HCK1,
-       .type           = CLK_TYPE_SYSTEM,
-       .id             = 1,
-};
-
-static void __init at572d940hf_register_clocks(void)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
-               clk_register(periph_clocks[i]);
-
-       clk_register(&pck0);
-       clk_register(&pck1);
-       clk_register(&pck2);
-       clk_register(&pck3);
-       clk_register(&mAgicV_mem_clk);
-
-       clk_register(&hck0);
-       clk_register(&hck1);
-}
-
-/* --------------------------------------------------------------------
- *  GPIO
- * -------------------------------------------------------------------- */
-
-static struct at91_gpio_bank at572d940hf_gpio[] = {
-       {
-               .id             = AT572D940HF_ID_PIOA,
-               .offset         = AT91_PIOA,
-               .clock          = &pioA_clk,
-       }, {
-               .id             = AT572D940HF_ID_PIOB,
-               .offset         = AT91_PIOB,
-               .clock          = &pioB_clk,
-       }, {
-               .id             = AT572D940HF_ID_PIOC,
-               .offset         = AT91_PIOC,
-               .clock          = &pioC_clk,
-       }
-};
-
-static void at572d940hf_reset(void)
-{
-       at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
-}
-
-
-/* --------------------------------------------------------------------
- *  AT572D940HF processor initialization
- * -------------------------------------------------------------------- */
-
-void __init at572d940hf_initialize(unsigned long main_clock)
-{
-       /* Map peripherals */
-       iotable_init(at572d940hf_io_desc, ARRAY_SIZE(at572d940hf_io_desc));
-
-       at91_arch_reset = at572d940hf_reset;
-       at91_extern_irq = (1 << AT572D940HF_ID_IRQ0) | (1 << AT572D940HF_ID_IRQ1)
-                       | (1 << AT572D940HF_ID_IRQ2);
-
-       /* Init clock subsystem */
-       at91_clock_init(main_clock);
-
-       /* Register the processor-specific clocks */
-       at572d940hf_register_clocks();
-
-       /* Register GPIO subsystem */
-       at91_gpio_init(at572d940hf_gpio, 3);
-}
-
-/* --------------------------------------------------------------------
- *  Interrupt initialization
- * -------------------------------------------------------------------- */
-
-/*
- * The default interrupt priority levels (0 = lowest, 7 = highest).
- */
-static unsigned int at572d940hf_default_irq_priority[NR_AIC_IRQS] __initdata = {
-       7,      /* Advanced Interrupt Controller */
-       7,      /* System Peripherals */
-       0,      /* Parallel IO Controller A */
-       0,      /* Parallel IO Controller B */
-       0,      /* Parallel IO Controller C */
-       3,      /* Ethernet */
-       6,      /* USART 0 */
-       6,      /* USART 1 */
-       6,      /* USART 2 */
-       0,      /* Multimedia Card Interface */
-       4,      /* USB Device Port */
-       0,      /* Two-Wire Interface 0 */
-       6,      /* Serial Peripheral Interface 0 */
-       6,      /* Serial Peripheral Interface 1 */
-       5,      /* Serial Synchronous Controller 0 */
-       5,      /* Serial Synchronous Controller 1 */
-       5,      /* Serial Synchronous Controller 2 */
-       0,      /* Timer Counter 0 */
-       0,      /* Timer Counter 1 */
-       0,      /* Timer Counter 2 */
-       3,      /* USB Host port */
-       3,      /* Serial Synchronous Controller 3 */
-       0,      /* Two-Wire Interface 1 */
-       0,      /* CAN Controller 0 */
-       0,      /* CAN Controller 1 */
-       0,      /* mAgicV HALT line */
-       0,      /* mAgicV SIRQ0 line */
-       0,      /* mAgicV exception line */
-       0,      /* mAgicV end of DMA line */
-       0,      /* Advanced Interrupt Controller */
-       0,      /* Advanced Interrupt Controller */
-       0,      /* Advanced Interrupt Controller */
-};
-
-void __init at572d940hf_init_interrupts(unsigned int priority[NR_AIC_IRQS])
-{
-       if (!priority)
-               priority = at572d940hf_default_irq_priority;
-
-       /* Initialize the AIC interrupt controller */
-       at91_aic_init(priority);
-
-       /* Enable GPIO interrupts */
-       at91_gpio_irq_setup();
-}
-
diff --git a/arch/arm/mach-at91/at572d940hf_devices.c b/arch/arm/mach-at91/at572d940hf_devices.c
deleted file mode 100644 (file)
index 0fc20a2..0000000
+++ /dev/null
@@ -1,970 +0,0 @@
-/*
- * arch/arm/mach-at91/at572d940hf_devices.c
- *
- * Copyright (C) 2008 Atmel Antonio R. Costa <costa.antonior@gmail.com>
- * Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org>
- * Copyright (C) 2005 David Brownell
- *
- * 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 <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-
-#include <mach/board.h>
-#include <mach/gpio.h>
-#include <mach/at572d940hf.h>
-#include <mach/at572d940hf_matrix.h>
-#include <mach/at91sam9_smc.h>
-
-#include "generic.h"
-#include "sam9_smc.h"
-
-
-/* --------------------------------------------------------------------
- *  USB Host
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
-static u64 ohci_dmamask = DMA_BIT_MASK(32);
-static struct at91_usbh_data usbh_data;
-
-static struct resource usbh_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_UHP_BASE,
-               .end    = AT572D940HF_UHP_BASE + SZ_1M - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_UHP,
-               .end    = AT572D940HF_ID_UHP,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_usbh_device = {
-       .name           = "at91_ohci",
-       .id             = -1,
-       .dev            = {
-                               .dma_mask               = &ohci_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &usbh_data,
-       },
-       .resource       = usbh_resources,
-       .num_resources  = ARRAY_SIZE(usbh_resources),
-};
-
-void __init at91_add_device_usbh(struct at91_usbh_data *data)
-{
-       if (!data)
-               return;
-
-       usbh_data = *data;
-       platform_device_register(&at572d940hf_usbh_device);
-
-}
-#else
-void __init at91_add_device_usbh(struct at91_usbh_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  USB Device (Gadget)
- * -------------------------------------------------------------------- */
-
-#ifdef CONFIG_USB_GADGET_AT91
-static struct at91_udc_data udc_data;
-
-static struct resource udc_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_UDP,
-               .end    = AT572D940HF_BASE_UDP + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_UDP,
-               .end    = AT572D940HF_ID_UDP,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_udc_device = {
-       .name           = "at91_udc",
-       .id             = -1,
-       .dev            = {
-                               .platform_data          = &udc_data,
-       },
-       .resource       = udc_resources,
-       .num_resources  = ARRAY_SIZE(udc_resources),
-};
-
-void __init at91_add_device_udc(struct at91_udc_data *data)
-{
-       if (!data)
-               return;
-
-       if (data->vbus_pin) {
-               at91_set_gpio_input(data->vbus_pin, 0);
-               at91_set_deglitch(data->vbus_pin, 1);
-       }
-
-       /* Pullup pin is handled internally */
-
-       udc_data = *data;
-       platform_device_register(&at572d940hf_udc_device);
-}
-#else
-void __init at91_add_device_udc(struct at91_udc_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  Ethernet
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
-static u64 eth_dmamask = DMA_BIT_MASK(32);
-static struct at91_eth_data eth_data;
-
-static struct resource eth_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_EMAC,
-               .end    = AT572D940HF_BASE_EMAC + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_EMAC,
-               .end    = AT572D940HF_ID_EMAC,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_eth_device = {
-       .name           = "macb",
-       .id             = -1,
-       .dev            = {
-                       .dma_mask               = &eth_dmamask,
-                       .coherent_dma_mask      = DMA_BIT_MASK(32),
-                       .platform_data          = &eth_data,
-       },
-       .resource       = eth_resources,
-       .num_resources  = ARRAY_SIZE(eth_resources),
-};
-
-void __init at91_add_device_eth(struct at91_eth_data *data)
-{
-       if (!data)
-               return;
-
-       if (data->phy_irq_pin) {
-               at91_set_gpio_input(data->phy_irq_pin, 0);
-               at91_set_deglitch(data->phy_irq_pin, 1);
-       }
-
-       /* Only RMII is supported */
-       data->is_rmii = 1;
-
-       /* Pins used for RMII */
-       at91_set_A_periph(AT91_PIN_PA16, 0);    /* ETXCK_EREFCK */
-       at91_set_A_periph(AT91_PIN_PA17, 0);    /* ERXDV */
-       at91_set_A_periph(AT91_PIN_PA18, 0);    /* ERX0 */
-       at91_set_A_periph(AT91_PIN_PA19, 0);    /* ERX1 */
-       at91_set_A_periph(AT91_PIN_PA20, 0);    /* ERXER */
-       at91_set_A_periph(AT91_PIN_PA23, 0);    /* ETXEN */
-       at91_set_A_periph(AT91_PIN_PA21, 0);    /* ETX0 */
-       at91_set_A_periph(AT91_PIN_PA22, 0);    /* ETX1 */
-       at91_set_A_periph(AT91_PIN_PA13, 0);    /* EMDIO */
-       at91_set_A_periph(AT91_PIN_PA14, 0);    /* EMDC */
-
-       eth_data = *data;
-       platform_device_register(&at572d940hf_eth_device);
-}
-#else
-void __init at91_add_device_eth(struct at91_eth_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  MMC / SD
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
-static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct at91_mmc_data mmc_data;
-
-static struct resource mmc_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_MCI,
-               .end    = AT572D940HF_BASE_MCI + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_MCI,
-               .end    = AT572D940HF_ID_MCI,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_mmc_device = {
-       .name           = "at91_mci",
-       .id             = -1,
-       .dev            = {
-                               .dma_mask               = &mmc_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &mmc_data,
-       },
-       .resource       = mmc_resources,
-       .num_resources  = ARRAY_SIZE(mmc_resources),
-};
-
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
-{
-       if (!data)
-               return;
-
-       /* input/irq */
-       if (data->det_pin) {
-               at91_set_gpio_input(data->det_pin, 1);
-               at91_set_deglitch(data->det_pin, 1);
-       }
-       if (data->wp_pin)
-               at91_set_gpio_input(data->wp_pin, 1);
-       if (data->vcc_pin)
-               at91_set_gpio_output(data->vcc_pin, 0);
-
-       /* CLK */
-       at91_set_A_periph(AT91_PIN_PC22, 0);
-
-       /* CMD */
-       at91_set_A_periph(AT91_PIN_PC23, 1);
-
-       /* DAT0, maybe DAT1..DAT3 */
-       at91_set_A_periph(AT91_PIN_PC24, 1);
-       if (data->wire4) {
-               at91_set_A_periph(AT91_PIN_PC25, 1);
-               at91_set_A_periph(AT91_PIN_PC26, 1);
-               at91_set_A_periph(AT91_PIN_PC27, 1);
-       }
-
-       mmc_data = *data;
-       platform_device_register(&at572d940hf_mmc_device);
-}
-#else
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  NAND / SmartMedia
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MTD_NAND_ATMEL) || defined(CONFIG_MTD_NAND_ATMEL_MODULE)
-static struct atmel_nand_data nand_data;
-
-#define NAND_BASE      AT91_CHIPSELECT_3
-
-static struct resource nand_resources[] = {
-       {
-               .start  = NAND_BASE,
-               .end    = NAND_BASE + SZ_256M - 1,
-               .flags  = IORESOURCE_MEM,
-       }
-};
-
-static struct platform_device at572d940hf_nand_device = {
-       .name           = "atmel_nand",
-       .id             = -1,
-       .dev            = {
-                               .platform_data  = &nand_data,
-       },
-       .resource       = nand_resources,
-       .num_resources  = ARRAY_SIZE(nand_resources),
-};
-
-void __init at91_add_device_nand(struct atmel_nand_data *data)
-{
-       unsigned long csa;
-
-       if (!data)
-               return;
-
-       csa = at91_sys_read(AT91_MATRIX_EBICSA);
-       at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
-
-       /* enable pin */
-       if (data->enable_pin)
-               at91_set_gpio_output(data->enable_pin, 1);
-
-       /* ready/busy pin */
-       if (data->rdy_pin)
-               at91_set_gpio_input(data->rdy_pin, 1);
-
-       /* card detect pin */
-       if (data->det_pin)
-               at91_set_gpio_input(data->det_pin, 1);
-
-       at91_set_A_periph(AT91_PIN_PB28, 0);            /* A[22] */
-       at91_set_B_periph(AT91_PIN_PA28, 0);            /* NANDOE */
-       at91_set_B_periph(AT91_PIN_PA29, 0);            /* NANDWE */
-
-       nand_data = *data;
-       platform_device_register(&at572d940hf_nand_device);
-}
-
-#else
-void __init at91_add_device_nand(struct atmel_nand_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  TWI (i2c)
- * -------------------------------------------------------------------- */
-
-/*
- * Prefer the GPIO code since the TWI controller isn't robust
- * (gets overruns and underruns under load) and can only issue
- * repeated STARTs in one scenario (the driver doesn't yet handle them).
- */
-
-#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
-
-static struct i2c_gpio_platform_data pdata = {
-       .sda_pin                = AT91_PIN_PC7,
-       .sda_is_open_drain      = 1,
-       .scl_pin                = AT91_PIN_PC8,
-       .scl_is_open_drain      = 1,
-       .udelay                 = 2,            /* ~100 kHz */
-};
-
-static struct platform_device at572d940hf_twi_device {
-       .name                   = "i2c-gpio",
-       .id                     = -1,
-       .dev.platform_data      = &pdata,
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
-       at91_set_GPIO_periph(AT91_PIN_PC7, 1);          /* TWD (SDA) */
-       at91_set_multi_drive(AT91_PIN_PC7, 1);
-
-       at91_set_GPIO_periph(AT91_PIN_PA8, 1);          /* TWCK (SCL) */
-       at91_set_multi_drive(AT91_PIN_PC8, 1);
-
-       i2c_register_board_info(0, devices, nr_devices);
-       platform_device_register(&at572d940hf_twi_device);
-}
-
-#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
-
-static struct resource twi0_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_TWI0,
-               .end    = AT572D940HF_BASE_TWI0 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_TWI0,
-               .end    = AT572D940HF_ID_TWI0,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_twi0_device = {
-       .name           = "at91_i2c",
-       .id             = 0,
-       .resource       = twi0_resources,
-       .num_resources  = ARRAY_SIZE(twi0_resources),
-};
-
-static struct resource twi1_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_TWI1,
-               .end    = AT572D940HF_BASE_TWI1 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_TWI1,
-               .end    = AT572D940HF_ID_TWI1,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_twi1_device = {
-       .name           = "at91_i2c",
-       .id             = 1,
-       .resource       = twi1_resources,
-       .num_resources  = ARRAY_SIZE(twi1_resources),
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
-       /* pins used for TWI0 interface */
-       at91_set_A_periph(AT91_PIN_PC7, 0);             /* TWD */
-       at91_set_multi_drive(AT91_PIN_PC7, 1);
-
-       at91_set_A_periph(AT91_PIN_PC8, 0);             /* TWCK */
-       at91_set_multi_drive(AT91_PIN_PC8, 1);
-
-       /* pins used for TWI1 interface */
-       at91_set_A_periph(AT91_PIN_PC20, 0);            /* TWD */
-       at91_set_multi_drive(AT91_PIN_PC20, 1);
-
-       at91_set_A_periph(AT91_PIN_PC21, 0);            /* TWCK */
-       at91_set_multi_drive(AT91_PIN_PC21, 1);
-
-       i2c_register_board_info(0, devices, nr_devices);
-       platform_device_register(&at572d940hf_twi0_device);
-       platform_device_register(&at572d940hf_twi1_device);
-}
-#else
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  SPI
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
-static u64 spi_dmamask = DMA_BIT_MASK(32);
-
-static struct resource spi0_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_SPI0,
-               .end    = AT572D940HF_BASE_SPI0 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_SPI0,
-               .end    = AT572D940HF_ID_SPI0,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_spi0_device = {
-       .name           = "atmel_spi",
-       .id             = 0,
-       .dev            = {
-                               .dma_mask               = &spi_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-       .resource       = spi0_resources,
-       .num_resources  = ARRAY_SIZE(spi0_resources),
-};
-
-static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA3, AT91_PIN_PA4, AT91_PIN_PA5, AT91_PIN_PA6 };
-
-static struct resource spi1_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_SPI1,
-               .end    = AT572D940HF_BASE_SPI1 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_SPI1,
-               .end    = AT572D940HF_ID_SPI1,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_spi1_device = {
-       .name           = "atmel_spi",
-       .id             = 1,
-       .dev            = {
-                               .dma_mask               = &spi_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-       .resource       = spi1_resources,
-       .num_resources  = ARRAY_SIZE(spi1_resources),
-};
-
-static const unsigned spi1_standard_cs[4] = { AT91_PIN_PC3, AT91_PIN_PC4, AT91_PIN_PC5, AT91_PIN_PC6 };
-
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
-{
-       int i;
-       unsigned long cs_pin;
-       short enable_spi0 = 0;
-       short enable_spi1 = 0;
-
-       /* Choose SPI chip-selects */
-       for (i = 0; i < nr_devices; i++) {
-               if (devices[i].controller_data)
-                       cs_pin = (unsigned long) devices[i].controller_data;
-               else if (devices[i].bus_num == 0)
-                       cs_pin = spi0_standard_cs[devices[i].chip_select];
-               else
-                       cs_pin = spi1_standard_cs[devices[i].chip_select];
-
-               if (devices[i].bus_num == 0)
-                       enable_spi0 = 1;
-               else
-                       enable_spi1 = 1;
-
-               /* enable chip-select pin */
-               at91_set_gpio_output(cs_pin, 1);
-
-               /* pass chip-select pin to driver */
-               devices[i].controller_data = (void *) cs_pin;
-       }
-
-       spi_register_board_info(devices, nr_devices);
-
-       /* Configure SPI bus(es) */
-       if (enable_spi0) {
-               at91_set_A_periph(AT91_PIN_PA0, 0);     /* SPI0_MISO */
-               at91_set_A_periph(AT91_PIN_PA1, 0);     /* SPI0_MOSI */
-               at91_set_A_periph(AT91_PIN_PA2, 0);     /* SPI0_SPCK */
-
-               at91_clock_associate("spi0_clk", &at572d940hf_spi0_device.dev, "spi_clk");
-               platform_device_register(&at572d940hf_spi0_device);
-       }
-       if (enable_spi1) {
-               at91_set_A_periph(AT91_PIN_PC0, 0);     /* SPI1_MISO */
-               at91_set_A_periph(AT91_PIN_PC1, 0);     /* SPI1_MOSI */
-               at91_set_A_periph(AT91_PIN_PC2, 0);     /* SPI1_SPCK */
-
-               at91_clock_associate("spi1_clk", &at572d940hf_spi1_device.dev, "spi_clk");
-               platform_device_register(&at572d940hf_spi1_device);
-       }
-}
-#else
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  Timer/Counter blocks
- * -------------------------------------------------------------------- */
-
-#ifdef CONFIG_ATMEL_TCLIB
-
-static struct resource tcb_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_TCB,
-               .end    = AT572D940HF_BASE_TCB + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_TC0,
-               .end    = AT572D940HF_ID_TC0,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = AT572D940HF_ID_TC1,
-               .end    = AT572D940HF_ID_TC1,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               .start  = AT572D940HF_ID_TC2,
-               .end    = AT572D940HF_ID_TC2,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_tcb_device = {
-       .name           = "atmel_tcb",
-       .id             = 0,
-       .resource       = tcb_resources,
-       .num_resources  = ARRAY_SIZE(tcb_resources),
-};
-
-static void __init at91_add_device_tc(void)
-{
-       /* this chip has a separate clock and irq for each TC channel */
-       at91_clock_associate("tc0_clk", &at572d940hf_tcb_device.dev, "t0_clk");
-       at91_clock_associate("tc1_clk", &at572d940hf_tcb_device.dev, "t1_clk");
-       at91_clock_associate("tc2_clk", &at572d940hf_tcb_device.dev, "t2_clk");
-       platform_device_register(&at572d940hf_tcb_device);
-}
-#else
-static void __init at91_add_device_tc(void) { }
-#endif
-
-
-/* --------------------------------------------------------------------
- *  RTT
- * -------------------------------------------------------------------- */
-
-static struct resource rtt_resources[] = {
-       {
-               .start  = AT91_BASE_SYS + AT91_RTT,
-               .end    = AT91_BASE_SYS + AT91_RTT + SZ_16 - 1,
-               .flags  = IORESOURCE_MEM,
-       }
-};
-
-static struct platform_device at572d940hf_rtt_device = {
-       .name           = "at91_rtt",
-       .id             = 0,
-       .resource       = rtt_resources,
-       .num_resources  = ARRAY_SIZE(rtt_resources),
-};
-
-static void __init at91_add_device_rtt(void)
-{
-       platform_device_register(&at572d940hf_rtt_device);
-}
-
-
-/* --------------------------------------------------------------------
- *  Watchdog
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE)
-static struct platform_device at572d940hf_wdt_device = {
-       .name           = "at91_wdt",
-       .id             = -1,
-       .num_resources  = 0,
-};
-
-static void __init at91_add_device_watchdog(void)
-{
-       platform_device_register(&at572d940hf_wdt_device);
-}
-#else
-static void __init at91_add_device_watchdog(void) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  UART
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SERIAL_ATMEL)
-static struct resource dbgu_resources[] = {
-       [0] = {
-               .start  = AT91_VA_BASE_SYS + AT91_DBGU,
-               .end    = AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91_ID_SYS,
-               .end    = AT91_ID_SYS,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct atmel_uart_data dbgu_data = {
-       .use_dma_tx     = 0,
-       .use_dma_rx     = 0,            /* DBGU not capable of receive DMA */
-       .regs           = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
-};
-
-static u64 dbgu_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at572d940hf_dbgu_device = {
-       .name           = "atmel_usart",
-       .id             = 0,
-       .dev            = {
-                               .dma_mask               = &dbgu_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &dbgu_data,
-       },
-       .resource       = dbgu_resources,
-       .num_resources  = ARRAY_SIZE(dbgu_resources),
-};
-
-static inline void configure_dbgu_pins(void)
-{
-       at91_set_A_periph(AT91_PIN_PC31, 1);            /* DTXD */
-       at91_set_A_periph(AT91_PIN_PC30, 0);            /* DRXD */
-}
-
-static struct resource uart0_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_US0,
-               .end    = AT572D940HF_BASE_US0 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_US0,
-               .end    = AT572D940HF_ID_US0,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct atmel_uart_data uart0_data = {
-       .use_dma_tx     = 1,
-       .use_dma_rx     = 1,
-};
-
-static u64 uart0_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at572d940hf_uart0_device = {
-       .name           = "atmel_usart",
-       .id             = 1,
-       .dev            = {
-                               .dma_mask               = &uart0_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &uart0_data,
-       },
-       .resource       = uart0_resources,
-       .num_resources  = ARRAY_SIZE(uart0_resources),
-};
-
-static inline void configure_usart0_pins(unsigned pins)
-{
-       at91_set_A_periph(AT91_PIN_PA8, 1);             /* TXD0 */
-       at91_set_A_periph(AT91_PIN_PA7, 0);             /* RXD0 */
-
-       if (pins & ATMEL_UART_RTS)
-               at91_set_A_periph(AT91_PIN_PA10, 0);    /* RTS0 */
-       if (pins & ATMEL_UART_CTS)
-               at91_set_A_periph(AT91_PIN_PA9, 0);     /* CTS0 */
-}
-
-static struct resource uart1_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_US1,
-               .end    = AT572D940HF_BASE_US1 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_US1,
-               .end    = AT572D940HF_ID_US1,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct atmel_uart_data uart1_data = {
-       .use_dma_tx     = 1,
-       .use_dma_rx     = 1,
-};
-
-static u64 uart1_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at572d940hf_uart1_device = {
-       .name           = "atmel_usart",
-       .id             = 2,
-       .dev            = {
-                               .dma_mask               = &uart1_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &uart1_data,
-       },
-       .resource       = uart1_resources,
-       .num_resources  = ARRAY_SIZE(uart1_resources),
-};
-
-static inline void configure_usart1_pins(unsigned pins)
-{
-       at91_set_A_periph(AT91_PIN_PC10, 1);            /* TXD1 */
-       at91_set_A_periph(AT91_PIN_PC9 , 0);            /* RXD1 */
-
-       if (pins & ATMEL_UART_RTS)
-               at91_set_A_periph(AT91_PIN_PC12, 0);    /* RTS1 */
-       if (pins & ATMEL_UART_CTS)
-               at91_set_A_periph(AT91_PIN_PC11, 0);    /* CTS1 */
-}
-
-static struct resource uart2_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_US2,
-               .end    = AT572D940HF_BASE_US2 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_US2,
-               .end    = AT572D940HF_ID_US2,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct atmel_uart_data uart2_data = {
-       .use_dma_tx     = 1,
-       .use_dma_rx     = 1,
-};
-
-static u64 uart2_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at572d940hf_uart2_device = {
-       .name           = "atmel_usart",
-       .id             = 3,
-       .dev            = {
-                               .dma_mask               = &uart2_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &uart2_data,
-       },
-       .resource       = uart2_resources,
-       .num_resources  = ARRAY_SIZE(uart2_resources),
-};
-
-static inline void configure_usart2_pins(unsigned pins)
-{
-       at91_set_A_periph(AT91_PIN_PC15, 1);            /* TXD2 */
-       at91_set_A_periph(AT91_PIN_PC14, 0);            /* RXD2 */
-
-       if (pins & ATMEL_UART_RTS)
-               at91_set_A_periph(AT91_PIN_PC17, 0);    /* RTS2 */
-       if (pins & ATMEL_UART_CTS)
-               at91_set_A_periph(AT91_PIN_PC16, 0);    /* CTS2 */
-}
-
-static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];  /* the UARTs to use */
-struct platform_device *atmel_default_console_device;  /* the serial console device */
-
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
-{
-       struct platform_device *pdev;
-
-       switch (id) {
-               case 0:         /* DBGU */
-                       pdev = &at572d940hf_dbgu_device;
-                       configure_dbgu_pins();
-                       at91_clock_associate("mck", &pdev->dev, "usart");
-                       break;
-               case AT572D940HF_ID_US0:
-                       pdev = &at572d940hf_uart0_device;
-                       configure_usart0_pins(pins);
-                       at91_clock_associate("usart0_clk", &pdev->dev, "usart");
-                       break;
-               case AT572D940HF_ID_US1:
-                       pdev = &at572d940hf_uart1_device;
-                       configure_usart1_pins(pins);
-                       at91_clock_associate("usart1_clk", &pdev->dev, "usart");
-                       break;
-               case AT572D940HF_ID_US2:
-                       pdev = &at572d940hf_uart2_device;
-                       configure_usart2_pins(pins);
-                       at91_clock_associate("usart2_clk", &pdev->dev, "usart");
-                       break;
-               default:
-                       return;
-       }
-       pdev->id = portnr;              /* update to mapped ID */
-
-       if (portnr < ATMEL_MAX_UART)
-               at91_uarts[portnr] = pdev;
-}
-
-void __init at91_set_serial_console(unsigned portnr)
-{
-       if (portnr < ATMEL_MAX_UART)
-               atmel_default_console_device = at91_uarts[portnr];
-}
-
-void __init at91_add_device_serial(void)
-{
-       int i;
-
-       for (i = 0; i < ATMEL_MAX_UART; i++) {
-               if (at91_uarts[i])
-                       platform_device_register(at91_uarts[i]);
-       }
-
-       if (!atmel_default_console_device)
-               printk(KERN_INFO "AT91: No default serial console defined.\n");
-}
-
-#else
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_set_serial_console(unsigned portnr) {}
-void __init at91_add_device_serial(void) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  mAgic
- * -------------------------------------------------------------------- */
-
-#ifdef CONFIG_MAGICV
-static struct resource mAgic_resources[] = {
-       {
-               .start = AT91_MAGIC_PM_BASE,
-               .end   = AT91_MAGIC_PM_BASE + AT91_MAGIC_PM_SIZE - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       {
-               .start = AT91_MAGIC_DM_I_BASE,
-               .end   = AT91_MAGIC_DM_I_BASE + AT91_MAGIC_DM_I_SIZE - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       {
-               .start = AT91_MAGIC_DM_F_BASE,
-               .end   = AT91_MAGIC_DM_F_BASE + AT91_MAGIC_DM_F_SIZE - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       {
-               .start = AT91_MAGIC_DM_DB_BASE,
-               .end   = AT91_MAGIC_DM_DB_BASE + AT91_MAGIC_DM_DB_SIZE - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       {
-               .start = AT91_MAGIC_REGS_BASE,
-               .end   = AT91_MAGIC_REGS_BASE + AT91_MAGIC_REGS_SIZE - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       {
-               .start = AT91_MAGIC_EXTPAGE_BASE,
-               .end   = AT91_MAGIC_EXTPAGE_BASE + AT91_MAGIC_EXTPAGE_SIZE - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       {
-               .start  = AT572D940HF_ID_MSIRQ0,
-               .end    = AT572D940HF_ID_MSIRQ0,
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = AT572D940HF_ID_MHALT,
-               .end    = AT572D940HF_ID_MHALT,
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = AT572D940HF_ID_MEXC,
-               .end    = AT572D940HF_ID_MEXC,
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = AT572D940HF_ID_MEDMA,
-               .end    = AT572D940HF_ID_MEDMA,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device mAgic_device = {
-       .name           = "mAgic",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(mAgic_resources),
-       .resource       = mAgic_resources,
-};
-
-void __init at91_add_device_mAgic(void)
-{
-       platform_device_register(&mAgic_device);
-}
-#else
-void __init at91_add_device_mAgic(void) {}
-#endif
-
-
-/* -------------------------------------------------------------------- */
-
-/*
- * These devices are always present and don't need any board-specific
- * setup.
- */
-static int __init at91_add_standard_devices(void)
-{
-       at91_add_device_rtt();
-       at91_add_device_watchdog();
-       at91_add_device_tc();
-       return 0;
-}
-
-arch_initcall(at91_add_standard_devices);
index 73376170fb914a692d04882a375d75b3a131de84..17fae4a42ab587f413025780f5228b7f0bfc7553 100644 (file)
@@ -222,6 +222,25 @@ static struct clk *periph_clocks[] __initdata = {
        // irq0 .. irq1
 };
 
+static struct clk_lookup periph_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk),
+       CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk),
+       CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
+       CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
+       CLKDEV_CON_DEV_ID("ssc", "ssc.0", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("ssc", "ssc.1", &ssc1_clk),
+};
+
+static struct clk_lookup usart_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
+};
+
 /*
  * The four programmable clocks.
  * You must configure pin multiplexing to bring these signals out.
@@ -258,12 +277,29 @@ static void __init at91cap9_register_clocks(void)
        for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
                clk_register(periph_clocks[i]);
 
+       clkdev_add_table(periph_clocks_lookups,
+                        ARRAY_SIZE(periph_clocks_lookups));
+       clkdev_add_table(usart_clocks_lookups,
+                        ARRAY_SIZE(usart_clocks_lookups));
+
        clk_register(&pck0);
        clk_register(&pck1);
        clk_register(&pck2);
        clk_register(&pck3);
 }
 
+static struct clk_lookup console_clock_lookup;
+
+void __init at91cap9_set_console_clock(int id)
+{
+       if (id >= ARRAY_SIZE(usart_clocks_lookups))
+               return;
+
+       console_clock_lookup.con_id = "usart";
+       console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+       clkdev_add(&console_clock_lookup);
+}
+
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
@@ -303,11 +339,14 @@ static void at91cap9_poweroff(void)
  *  AT91CAP9 processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91cap9_initialize(unsigned long main_clock)
+void __init at91cap9_map_io(void)
 {
        /* Map peripherals */
        iotable_init(at91cap9_io_desc, ARRAY_SIZE(at91cap9_io_desc));
+}
 
+void __init at91cap9_initialize(unsigned long main_clock)
+{
        at91_arch_reset = at91cap9_reset;
        pm_power_off = at91cap9_poweroff;
        at91_extern_irq = (1 << AT91CAP9_ID_IRQ0) | (1 << AT91CAP9_ID_IRQ1);
index 21020ceb2f3ac308064c52d5e5379c02c9d8ca73..cd850ed6f33542b5a70a7d7bfcbe0080f5d05619 100644 (file)
@@ -181,10 +181,6 @@ void __init at91_add_device_usba(struct usba_platform_data *data)
 
        /* Pullup pin is handled internally by USB device peripheral */
 
-       /* Clocks */
-       at91_clock_associate("utmi_clk", &at91_usba_udc_device.dev, "hclk");
-       at91_clock_associate("udphs_clk", &at91_usba_udc_device.dev, "pclk");
-
        platform_device_register(&at91_usba_udc_device);
 }
 #else
@@ -355,7 +351,6 @@ void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
                }
 
                mmc0_data = *data;
-               at91_clock_associate("mci0_clk", &at91cap9_mmc0_device.dev, "mci_clk");
                platform_device_register(&at91cap9_mmc0_device);
        } else {                        /* MCI1 */
                /* CLK */
@@ -373,7 +368,6 @@ void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
                }
 
                mmc1_data = *data;
-               at91_clock_associate("mci1_clk", &at91cap9_mmc1_device.dev, "mci_clk");
                platform_device_register(&at91cap9_mmc1_device);
        }
 }
@@ -614,7 +608,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_B_periph(AT91_PIN_PA1, 0);     /* SPI0_MOSI */
                at91_set_B_periph(AT91_PIN_PA2, 0);     /* SPI0_SPCK */
 
-               at91_clock_associate("spi0_clk", &at91cap9_spi0_device.dev, "spi_clk");
                platform_device_register(&at91cap9_spi0_device);
        }
        if (enable_spi1) {
@@ -622,7 +615,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_A_periph(AT91_PIN_PB13, 0);    /* SPI1_MOSI */
                at91_set_A_periph(AT91_PIN_PB14, 0);    /* SPI1_SPCK */
 
-               at91_clock_associate("spi1_clk", &at91cap9_spi1_device.dev, "spi_clk");
                platform_device_register(&at91cap9_spi1_device);
        }
 }
@@ -659,8 +651,6 @@ static struct platform_device at91cap9_tcb_device = {
 
 static void __init at91_add_device_tc(void)
 {
-       /* this chip has one clock and irq for all three TC channels */
-       at91_clock_associate("tcb_clk", &at91cap9_tcb_device.dev, "t0_clk");
        platform_device_register(&at91cap9_tcb_device);
 }
 #else
@@ -1001,12 +991,10 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins)
        case AT91CAP9_ID_SSC0:
                pdev = &at91cap9_ssc0_device;
                configure_ssc0_pins(pins);
-               at91_clock_associate("ssc0_clk", &pdev->dev, "ssc");
                break;
        case AT91CAP9_ID_SSC1:
                pdev = &at91cap9_ssc1_device;
                configure_ssc1_pins(pins);
-               at91_clock_associate("ssc1_clk", &pdev->dev, "ssc");
                break;
        default:
                return;
@@ -1199,32 +1187,30 @@ struct platform_device *atmel_default_console_device;   /* the serial console devi
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
        struct platform_device *pdev;
+       struct atmel_uart_data *pdata;
 
        switch (id) {
                case 0:         /* DBGU */
                        pdev = &at91cap9_dbgu_device;
                        configure_dbgu_pins();
-                       at91_clock_associate("mck", &pdev->dev, "usart");
                        break;
                case AT91CAP9_ID_US0:
                        pdev = &at91cap9_uart0_device;
                        configure_usart0_pins(pins);
-                       at91_clock_associate("usart0_clk", &pdev->dev, "usart");
                        break;
                case AT91CAP9_ID_US1:
                        pdev = &at91cap9_uart1_device;
                        configure_usart1_pins(pins);
-                       at91_clock_associate("usart1_clk", &pdev->dev, "usart");
                        break;
                case AT91CAP9_ID_US2:
                        pdev = &at91cap9_uart2_device;
                        configure_usart2_pins(pins);
-                       at91_clock_associate("usart2_clk", &pdev->dev, "usart");
                        break;
                default:
                        return;
        }
-       pdev->id = portnr;              /* update to mapped ID */
+       pdata = pdev->dev.platform_data;
+       pdata->num = portnr;            /* update to mapped ID */
 
        if (portnr < ATMEL_MAX_UART)
                at91_uarts[portnr] = pdev;
@@ -1232,8 +1218,10 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 
 void __init at91_set_serial_console(unsigned portnr)
 {
-       if (portnr < ATMEL_MAX_UART)
+       if (portnr < ATMEL_MAX_UART) {
                atmel_default_console_device = at91_uarts[portnr];
+               at91cap9_set_console_clock(portnr);
+       }
 }
 
 void __init at91_add_device_serial(void)
index 2e9ecad97f3dc76367a842eba110a046f7e20766..b228ce9e21a14b9e6c20c57e5b87d8bcc5b769bf 100644 (file)
@@ -18,6 +18,7 @@
 #include <mach/at91rm9200.h>
 #include <mach/at91_pmc.h>
 #include <mach/at91_st.h>
+#include <mach/cpu.h>
 
 #include "generic.h"
 #include "clock.h"
@@ -191,6 +192,26 @@ static struct clk *periph_clocks[] __initdata = {
        // irq0 .. irq6
 };
 
+static struct clk_lookup periph_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
+       CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
+       CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk),
+       CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
+       CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
+       CLKDEV_CON_DEV_ID("ssc", "ssc.0", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("ssc", "ssc.1", &ssc1_clk),
+       CLKDEV_CON_DEV_ID("ssc", "ssc.2", &ssc2_clk),
+};
+
+static struct clk_lookup usart_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.4", &usart3_clk),
+};
+
 /*
  * The four programmable clocks.
  * You must configure pin multiplexing to bring these signals out.
@@ -227,12 +248,29 @@ static void __init at91rm9200_register_clocks(void)
        for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
                clk_register(periph_clocks[i]);
 
+       clkdev_add_table(periph_clocks_lookups,
+                        ARRAY_SIZE(periph_clocks_lookups));
+       clkdev_add_table(usart_clocks_lookups,
+                        ARRAY_SIZE(usart_clocks_lookups));
+
        clk_register(&pck0);
        clk_register(&pck1);
        clk_register(&pck2);
        clk_register(&pck3);
 }
 
+static struct clk_lookup console_clock_lookup;
+
+void __init at91rm9200_set_console_clock(int id)
+{
+       if (id >= ARRAY_SIZE(usart_clocks_lookups))
+               return;
+
+       console_clock_lookup.con_id = "usart";
+       console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+       clkdev_add(&console_clock_lookup);
+}
+
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
@@ -266,15 +304,25 @@ static void at91rm9200_reset(void)
        at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
 }
 
+int rm9200_type;
+EXPORT_SYMBOL(rm9200_type);
+
+void __init at91rm9200_set_type(int type)
+{
+       rm9200_type = type;
+}
 
 /* --------------------------------------------------------------------
  *  AT91RM9200 processor initialization
  * -------------------------------------------------------------------- */
-void __init at91rm9200_initialize(unsigned long main_clock, unsigned short banks)
+void __init at91rm9200_map_io(void)
 {
        /* Map peripherals */
        iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc));
+}
 
+void __init at91rm9200_initialize(unsigned long main_clock)
+{
        at91_arch_reset = at91rm9200_reset;
        at91_extern_irq = (1 << AT91RM9200_ID_IRQ0) | (1 << AT91RM9200_ID_IRQ1)
                        | (1 << AT91RM9200_ID_IRQ2) | (1 << AT91RM9200_ID_IRQ3)
@@ -288,7 +336,8 @@ void __init at91rm9200_initialize(unsigned long main_clock, unsigned short banks
        at91rm9200_register_clocks();
 
        /* Initialize GPIO subsystem */
-       at91_gpio_init(at91rm9200_gpio, banks);
+       at91_gpio_init(at91rm9200_gpio,
+               cpu_is_at91rm9200_bga() ? AT91RM9200_BGA : AT91RM9200_PQFP);
 }
 
 
index 7b539228e0efb324b258d8e247c1e14c060fb30a..a0ba475be04cd23a7aeba30d933c8eead4fb3d1f 100644 (file)
@@ -644,15 +644,7 @@ static struct platform_device at91rm9200_tcb1_device = {
 
 static void __init at91_add_device_tc(void)
 {
-       /* this chip has a separate clock and irq for each TC channel */
-       at91_clock_associate("tc0_clk", &at91rm9200_tcb0_device.dev, "t0_clk");
-       at91_clock_associate("tc1_clk", &at91rm9200_tcb0_device.dev, "t1_clk");
-       at91_clock_associate("tc2_clk", &at91rm9200_tcb0_device.dev, "t2_clk");
        platform_device_register(&at91rm9200_tcb0_device);
-
-       at91_clock_associate("tc3_clk", &at91rm9200_tcb1_device.dev, "t0_clk");
-       at91_clock_associate("tc4_clk", &at91rm9200_tcb1_device.dev, "t1_clk");
-       at91_clock_associate("tc5_clk", &at91rm9200_tcb1_device.dev, "t2_clk");
        platform_device_register(&at91rm9200_tcb1_device);
 }
 #else
@@ -849,17 +841,14 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins)
        case AT91RM9200_ID_SSC0:
                pdev = &at91rm9200_ssc0_device;
                configure_ssc0_pins(pins);
-               at91_clock_associate("ssc0_clk", &pdev->dev, "ssc");
                break;
        case AT91RM9200_ID_SSC1:
                pdev = &at91rm9200_ssc1_device;
                configure_ssc1_pins(pins);
-               at91_clock_associate("ssc1_clk", &pdev->dev, "ssc");
                break;
        case AT91RM9200_ID_SSC2:
                pdev = &at91rm9200_ssc2_device;
                configure_ssc2_pins(pins);
-               at91_clock_associate("ssc2_clk", &pdev->dev, "ssc");
                break;
        default:
                return;
@@ -1109,37 +1098,34 @@ struct platform_device *atmel_default_console_device;   /* the serial console devi
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
        struct platform_device *pdev;
+       struct atmel_uart_data *pdata;
 
        switch (id) {
                case 0:         /* DBGU */
                        pdev = &at91rm9200_dbgu_device;
                        configure_dbgu_pins();
-                       at91_clock_associate("mck", &pdev->dev, "usart");
                        break;
                case AT91RM9200_ID_US0:
                        pdev = &at91rm9200_uart0_device;
                        configure_usart0_pins(pins);
-                       at91_clock_associate("usart0_clk", &pdev->dev, "usart");
                        break;
                case AT91RM9200_ID_US1:
                        pdev = &at91rm9200_uart1_device;
                        configure_usart1_pins(pins);
-                       at91_clock_associate("usart1_clk", &pdev->dev, "usart");
                        break;
                case AT91RM9200_ID_US2:
                        pdev = &at91rm9200_uart2_device;
                        configure_usart2_pins(pins);
-                       at91_clock_associate("usart2_clk", &pdev->dev, "usart");
                        break;
                case AT91RM9200_ID_US3:
                        pdev = &at91rm9200_uart3_device;
                        configure_usart3_pins(pins);
-                       at91_clock_associate("usart3_clk", &pdev->dev, "usart");
                        break;
                default:
                        return;
        }
-       pdev->id = portnr;              /* update to mapped ID */
+       pdata = pdev->dev.platform_data;
+       pdata->num = portnr;            /* update to mapped ID */
 
        if (portnr < ATMEL_MAX_UART)
                at91_uarts[portnr] = pdev;
@@ -1147,8 +1133,10 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 
 void __init at91_set_serial_console(unsigned portnr)
 {
-       if (portnr < ATMEL_MAX_UART)
+       if (portnr < ATMEL_MAX_UART) {
                atmel_default_console_device = at91_uarts[portnr];
+               at91rm9200_set_console_clock(portnr);
+       }
 }
 
 void __init at91_add_device_serial(void)
index 195208b30024cff807656304c1aef3bf833d8f83..7d606b04d313c5800359849ddff022a827655d87 100644 (file)
@@ -231,6 +231,28 @@ static struct clk *periph_clocks[] __initdata = {
        // irq0 .. irq2
 };
 
+static struct clk_lookup periph_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
+       CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
+       CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
+       CLKDEV_CON_DEV_ID("t3_clk", "atmel_tcb.1", &tc3_clk),
+       CLKDEV_CON_DEV_ID("t4_clk", "atmel_tcb.1", &tc4_clk),
+       CLKDEV_CON_DEV_ID("t5_clk", "atmel_tcb.1", &tc5_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk),
+};
+
+static struct clk_lookup usart_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.4", &usart3_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.5", &usart4_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.6", &usart5_clk),
+};
+
 /*
  * The two programmable clocks.
  * You must configure pin multiplexing to bring these signals out.
@@ -255,10 +277,27 @@ static void __init at91sam9260_register_clocks(void)
        for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
                clk_register(periph_clocks[i]);
 
+       clkdev_add_table(periph_clocks_lookups,
+                        ARRAY_SIZE(periph_clocks_lookups));
+       clkdev_add_table(usart_clocks_lookups,
+                        ARRAY_SIZE(usart_clocks_lookups));
+
        clk_register(&pck0);
        clk_register(&pck1);
 }
 
+static struct clk_lookup console_clock_lookup;
+
+void __init at91sam9260_set_console_clock(int id)
+{
+       if (id >= ARRAY_SIZE(usart_clocks_lookups))
+               return;
+
+       console_clock_lookup.con_id = "usart";
+       console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+       clkdev_add(&console_clock_lookup);
+}
+
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
@@ -289,7 +328,7 @@ static void at91sam9260_poweroff(void)
  *  AT91SAM9260 processor initialization
  * -------------------------------------------------------------------- */
 
-static void __init at91sam9xe_initialize(void)
+static void __init at91sam9xe_map_io(void)
 {
        unsigned long cidr, sram_size;
 
@@ -310,18 +349,21 @@ static void __init at91sam9xe_initialize(void)
        iotable_init(at91sam9xe_sram_desc, ARRAY_SIZE(at91sam9xe_sram_desc));
 }
 
-void __init at91sam9260_initialize(unsigned long main_clock)
+void __init at91sam9260_map_io(void)
 {
        /* Map peripherals */
        iotable_init(at91sam9260_io_desc, ARRAY_SIZE(at91sam9260_io_desc));
 
        if (cpu_is_at91sam9xe())
-               at91sam9xe_initialize();
+               at91sam9xe_map_io();
        else if (cpu_is_at91sam9g20())
                iotable_init(at91sam9g20_sram_desc, ARRAY_SIZE(at91sam9g20_sram_desc));
        else
                iotable_init(at91sam9260_sram_desc, ARRAY_SIZE(at91sam9260_sram_desc));
+}
 
+void __init at91sam9260_initialize(unsigned long main_clock)
+{
        at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9260_poweroff;
        at91_extern_irq = (1 << AT91SAM9260_ID_IRQ0) | (1 << AT91SAM9260_ID_IRQ1)
index 07eb7b07e442a69c9499b71cf49387f6ecd240e6..1fdeb9058a760a865ba0463d6fdbca89cd448bfb 100644 (file)
@@ -609,7 +609,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_A_periph(AT91_PIN_PA1, 0);     /* SPI0_MOSI */
                at91_set_A_periph(AT91_PIN_PA2, 0);     /* SPI1_SPCK */
 
-               at91_clock_associate("spi0_clk", &at91sam9260_spi0_device.dev, "spi_clk");
                platform_device_register(&at91sam9260_spi0_device);
        }
        if (enable_spi1) {
@@ -617,7 +616,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_A_periph(AT91_PIN_PB1, 0);     /* SPI1_MOSI */
                at91_set_A_periph(AT91_PIN_PB2, 0);     /* SPI1_SPCK */
 
-               at91_clock_associate("spi1_clk", &at91sam9260_spi1_device.dev, "spi_clk");
                platform_device_register(&at91sam9260_spi1_device);
        }
 }
@@ -694,15 +692,7 @@ static struct platform_device at91sam9260_tcb1_device = {
 
 static void __init at91_add_device_tc(void)
 {
-       /* this chip has a separate clock and irq for each TC channel */
-       at91_clock_associate("tc0_clk", &at91sam9260_tcb0_device.dev, "t0_clk");
-       at91_clock_associate("tc1_clk", &at91sam9260_tcb0_device.dev, "t1_clk");
-       at91_clock_associate("tc2_clk", &at91sam9260_tcb0_device.dev, "t2_clk");
        platform_device_register(&at91sam9260_tcb0_device);
-
-       at91_clock_associate("tc3_clk", &at91sam9260_tcb1_device.dev, "t0_clk");
-       at91_clock_associate("tc4_clk", &at91sam9260_tcb1_device.dev, "t1_clk");
-       at91_clock_associate("tc5_clk", &at91sam9260_tcb1_device.dev, "t2_clk");
        platform_device_register(&at91sam9260_tcb1_device);
 }
 #else
@@ -820,7 +810,6 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins)
        case AT91SAM9260_ID_SSC:
                pdev = &at91sam9260_ssc_device;
                configure_ssc_pins(pins);
-               at91_clock_associate("ssc_clk", &pdev->dev, "pclk");
                break;
        default:
                return;
@@ -1139,47 +1128,42 @@ struct platform_device *atmel_default_console_device;   /* the serial console devi
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
        struct platform_device *pdev;
+       struct atmel_uart_data *pdata;
 
        switch (id) {
                case 0:         /* DBGU */
                        pdev = &at91sam9260_dbgu_device;
                        configure_dbgu_pins();
-                       at91_clock_associate("mck", &pdev->dev, "usart");
                        break;
                case AT91SAM9260_ID_US0:
                        pdev = &at91sam9260_uart0_device;
                        configure_usart0_pins(pins);
-                       at91_clock_associate("usart0_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9260_ID_US1:
                        pdev = &at91sam9260_uart1_device;
                        configure_usart1_pins(pins);
-                       at91_clock_associate("usart1_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9260_ID_US2:
                        pdev = &at91sam9260_uart2_device;
                        configure_usart2_pins(pins);
-                       at91_clock_associate("usart2_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9260_ID_US3:
                        pdev = &at91sam9260_uart3_device;
                        configure_usart3_pins(pins);
-                       at91_clock_associate("usart3_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9260_ID_US4:
                        pdev = &at91sam9260_uart4_device;
                        configure_usart4_pins();
-                       at91_clock_associate("usart4_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9260_ID_US5:
                        pdev = &at91sam9260_uart5_device;
                        configure_usart5_pins();
-                       at91_clock_associate("usart5_clk", &pdev->dev, "usart");
                        break;
                default:
                        return;
        }
-       pdev->id = portnr;              /* update to mapped ID */
+       pdata = pdev->dev.platform_data;
+       pdata->num = portnr;            /* update to mapped ID */
 
        if (portnr < ATMEL_MAX_UART)
                at91_uarts[portnr] = pdev;
@@ -1187,8 +1171,10 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 
 void __init at91_set_serial_console(unsigned portnr)
 {
-       if (portnr < ATMEL_MAX_UART)
+       if (portnr < ATMEL_MAX_UART) {
                atmel_default_console_device = at91_uarts[portnr];
+               at91sam9260_set_console_clock(portnr);
+       }
 }
 
 void __init at91_add_device_serial(void)
index fcad88668504bde5331b764419b0676fa89edc68..c1483168c97a523569ff04676cf7f964e7282313 100644 (file)
@@ -178,6 +178,24 @@ static struct clk *periph_clocks[] __initdata = {
        // irq0 .. irq2
 };
 
+static struct clk_lookup periph_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
+       CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
+       CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc1_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
+};
+
+static struct clk_lookup usart_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
+};
+
 /*
  * The four programmable clocks.
  * You must configure pin multiplexing to bring these signals out.
@@ -228,6 +246,11 @@ static void __init at91sam9261_register_clocks(void)
        for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
                clk_register(periph_clocks[i]);
 
+       clkdev_add_table(periph_clocks_lookups,
+                        ARRAY_SIZE(periph_clocks_lookups));
+       clkdev_add_table(usart_clocks_lookups,
+                        ARRAY_SIZE(usart_clocks_lookups));
+
        clk_register(&pck0);
        clk_register(&pck1);
        clk_register(&pck2);
@@ -237,6 +260,18 @@ static void __init at91sam9261_register_clocks(void)
        clk_register(&hck1);
 }
 
+static struct clk_lookup console_clock_lookup;
+
+void __init at91sam9261_set_console_clock(int id)
+{
+       if (id >= ARRAY_SIZE(usart_clocks_lookups))
+               return;
+
+       console_clock_lookup.con_id = "usart";
+       console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+       clkdev_add(&console_clock_lookup);
+}
+
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
@@ -267,7 +302,7 @@ static void at91sam9261_poweroff(void)
  *  AT91SAM9261 processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91sam9261_initialize(unsigned long main_clock)
+void __init at91sam9261_map_io(void)
 {
        /* Map peripherals */
        iotable_init(at91sam9261_io_desc, ARRAY_SIZE(at91sam9261_io_desc));
@@ -276,8 +311,10 @@ void __init at91sam9261_initialize(unsigned long main_clock)
                iotable_init(at91sam9g10_sram_desc, ARRAY_SIZE(at91sam9g10_sram_desc));
        else
                iotable_init(at91sam9261_sram_desc, ARRAY_SIZE(at91sam9261_sram_desc));
+}
 
-
+void __init at91sam9261_initialize(unsigned long main_clock)
+{
        at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9261_poweroff;
        at91_extern_irq = (1 << AT91SAM9261_ID_IRQ0) | (1 << AT91SAM9261_ID_IRQ1)
index 59fc48311fb07d11760382e85e5ff386986a93f6..3eb4538fceebeb243aba31185861d3639d05c9c3 100644 (file)
@@ -426,7 +426,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_A_periph(AT91_PIN_PA1, 0);     /* SPI0_MOSI */
                at91_set_A_periph(AT91_PIN_PA2, 0);     /* SPI0_SPCK */
 
-               at91_clock_associate("spi0_clk", &at91sam9261_spi0_device.dev, "spi_clk");
                platform_device_register(&at91sam9261_spi0_device);
        }
        if (enable_spi1) {
@@ -434,7 +433,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_A_periph(AT91_PIN_PB31, 0);    /* SPI1_MOSI */
                at91_set_A_periph(AT91_PIN_PB29, 0);    /* SPI1_SPCK */
 
-               at91_clock_associate("spi1_clk", &at91sam9261_spi1_device.dev, "spi_clk");
                platform_device_register(&at91sam9261_spi1_device);
        }
 }
@@ -581,10 +579,6 @@ static struct platform_device at91sam9261_tcb_device = {
 
 static void __init at91_add_device_tc(void)
 {
-       /* this chip has a separate clock and irq for each TC channel */
-       at91_clock_associate("tc0_clk", &at91sam9261_tcb_device.dev, "t0_clk");
-       at91_clock_associate("tc1_clk", &at91sam9261_tcb_device.dev, "t1_clk");
-       at91_clock_associate("tc2_clk", &at91sam9261_tcb_device.dev, "t2_clk");
        platform_device_register(&at91sam9261_tcb_device);
 }
 #else
@@ -786,17 +780,14 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins)
        case AT91SAM9261_ID_SSC0:
                pdev = &at91sam9261_ssc0_device;
                configure_ssc0_pins(pins);
-               at91_clock_associate("ssc0_clk", &pdev->dev, "pclk");
                break;
        case AT91SAM9261_ID_SSC1:
                pdev = &at91sam9261_ssc1_device;
                configure_ssc1_pins(pins);
-               at91_clock_associate("ssc1_clk", &pdev->dev, "pclk");
                break;
        case AT91SAM9261_ID_SSC2:
                pdev = &at91sam9261_ssc2_device;
                configure_ssc2_pins(pins);
-               at91_clock_associate("ssc2_clk", &pdev->dev, "pclk");
                break;
        default:
                return;
@@ -989,32 +980,30 @@ struct platform_device *atmel_default_console_device;     /* the serial console devi
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
        struct platform_device *pdev;
+       struct atmel_uart_data *pdata;
 
        switch (id) {
                case 0:         /* DBGU */
                        pdev = &at91sam9261_dbgu_device;
                        configure_dbgu_pins();
-                       at91_clock_associate("mck", &pdev->dev, "usart");
                        break;
                case AT91SAM9261_ID_US0:
                        pdev = &at91sam9261_uart0_device;
                        configure_usart0_pins(pins);
-                       at91_clock_associate("usart0_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9261_ID_US1:
                        pdev = &at91sam9261_uart1_device;
                        configure_usart1_pins(pins);
-                       at91_clock_associate("usart1_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9261_ID_US2:
                        pdev = &at91sam9261_uart2_device;
                        configure_usart2_pins(pins);
-                       at91_clock_associate("usart2_clk", &pdev->dev, "usart");
                        break;
                default:
                        return;
        }
-       pdev->id = portnr;              /* update to mapped ID */
+       pdata = pdev->dev.platform_data;
+       pdata->num = portnr;            /* update to mapped ID */
 
        if (portnr < ATMEL_MAX_UART)
                at91_uarts[portnr] = pdev;
@@ -1022,8 +1011,10 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 
 void __init at91_set_serial_console(unsigned portnr)
 {
-       if (portnr < ATMEL_MAX_UART)
+       if (portnr < ATMEL_MAX_UART) {
                atmel_default_console_device = at91_uarts[portnr];
+               at91sam9261_set_console_clock(portnr);
+       }
 }
 
 void __init at91_add_device_serial(void)
index 249f900954d8b08c05078c5a7ed0cf57d53255d6..dc28477d14ffa158e0e0ae8031815ada848b9c51 100644 (file)
@@ -199,6 +199,23 @@ static struct clk *periph_clocks[] __initdata = {
        // irq0 .. irq1
 };
 
+static struct clk_lookup periph_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+       CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
+       CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
+};
+
+static struct clk_lookup usart_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
+};
+
 /*
  * The four programmable clocks.
  * You must configure pin multiplexing to bring these signals out.
@@ -235,12 +252,29 @@ static void __init at91sam9263_register_clocks(void)
        for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
                clk_register(periph_clocks[i]);
 
+       clkdev_add_table(periph_clocks_lookups,
+                        ARRAY_SIZE(periph_clocks_lookups));
+       clkdev_add_table(usart_clocks_lookups,
+                        ARRAY_SIZE(usart_clocks_lookups));
+
        clk_register(&pck0);
        clk_register(&pck1);
        clk_register(&pck2);
        clk_register(&pck3);
 }
 
+static struct clk_lookup console_clock_lookup;
+
+void __init at91sam9263_set_console_clock(int id)
+{
+       if (id >= ARRAY_SIZE(usart_clocks_lookups))
+               return;
+
+       console_clock_lookup.con_id = "usart";
+       console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+       clkdev_add(&console_clock_lookup);
+}
+
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
@@ -279,11 +313,14 @@ static void at91sam9263_poweroff(void)
  *  AT91SAM9263 processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91sam9263_initialize(unsigned long main_clock)
+void __init at91sam9263_map_io(void)
 {
        /* Map peripherals */
        iotable_init(at91sam9263_io_desc, ARRAY_SIZE(at91sam9263_io_desc));
+}
 
+void __init at91sam9263_initialize(unsigned long main_clock)
+{
        at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9263_poweroff;
        at91_extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1);
index fb5c23af1017ed13c480ae324bf90b6b7d566bf1..ffe081b77ed0f5bfafc97116919f0c381b06be98 100644 (file)
@@ -308,7 +308,6 @@ void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
                }
 
                mmc0_data = *data;
-               at91_clock_associate("mci0_clk", &at91sam9263_mmc0_device.dev, "mci_clk");
                platform_device_register(&at91sam9263_mmc0_device);
        } else {                        /* MCI1 */
                /* CLK */
@@ -339,7 +338,6 @@ void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
                }
 
                mmc1_data = *data;
-               at91_clock_associate("mci1_clk", &at91sam9263_mmc1_device.dev, "mci_clk");
                platform_device_register(&at91sam9263_mmc1_device);
        }
 }
@@ -686,7 +684,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_B_periph(AT91_PIN_PA1, 0);     /* SPI0_MOSI */
                at91_set_B_periph(AT91_PIN_PA2, 0);     /* SPI0_SPCK */
 
-               at91_clock_associate("spi0_clk", &at91sam9263_spi0_device.dev, "spi_clk");
                platform_device_register(&at91sam9263_spi0_device);
        }
        if (enable_spi1) {
@@ -694,7 +691,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_A_periph(AT91_PIN_PB13, 0);    /* SPI1_MOSI */
                at91_set_A_periph(AT91_PIN_PB14, 0);    /* SPI1_SPCK */
 
-               at91_clock_associate("spi1_clk", &at91sam9263_spi1_device.dev, "spi_clk");
                platform_device_register(&at91sam9263_spi1_device);
        }
 }
@@ -941,8 +937,6 @@ static struct platform_device at91sam9263_tcb_device = {
 
 static void __init at91_add_device_tc(void)
 {
-       /* this chip has one clock and irq for all three TC channels */
-       at91_clock_associate("tcb_clk", &at91sam9263_tcb_device.dev, "t0_clk");
        platform_device_register(&at91sam9263_tcb_device);
 }
 #else
@@ -1171,12 +1165,10 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins)
        case AT91SAM9263_ID_SSC0:
                pdev = &at91sam9263_ssc0_device;
                configure_ssc0_pins(pins);
-               at91_clock_associate("ssc0_clk", &pdev->dev, "pclk");
                break;
        case AT91SAM9263_ID_SSC1:
                pdev = &at91sam9263_ssc1_device;
                configure_ssc1_pins(pins);
-               at91_clock_associate("ssc1_clk", &pdev->dev, "pclk");
                break;
        default:
                return;
@@ -1370,32 +1362,30 @@ struct platform_device *atmel_default_console_device;   /* the serial console devi
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
        struct platform_device *pdev;
+       struct atmel_uart_data *pdata;
 
        switch (id) {
                case 0:         /* DBGU */
                        pdev = &at91sam9263_dbgu_device;
                        configure_dbgu_pins();
-                       at91_clock_associate("mck", &pdev->dev, "usart");
                        break;
                case AT91SAM9263_ID_US0:
                        pdev = &at91sam9263_uart0_device;
                        configure_usart0_pins(pins);
-                       at91_clock_associate("usart0_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9263_ID_US1:
                        pdev = &at91sam9263_uart1_device;
                        configure_usart1_pins(pins);
-                       at91_clock_associate("usart1_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9263_ID_US2:
                        pdev = &at91sam9263_uart2_device;
                        configure_usart2_pins(pins);
-                       at91_clock_associate("usart2_clk", &pdev->dev, "usart");
                        break;
                default:
                        return;
        }
-       pdev->id = portnr;              /* update to mapped ID */
+       pdata = pdev->dev.platform_data;
+       pdata->num = portnr;            /* update to mapped ID */
 
        if (portnr < ATMEL_MAX_UART)
                at91_uarts[portnr] = pdev;
@@ -1403,8 +1393,10 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 
 void __init at91_set_serial_console(unsigned portnr)
 {
-       if (portnr < ATMEL_MAX_UART)
+       if (portnr < ATMEL_MAX_UART) {
                atmel_default_console_device = at91_uarts[portnr];
+               at91sam9263_set_console_clock(portnr);
+       }
 }
 
 void __init at91_add_device_serial(void)
index c67b47f1c0fd805751cf226a65315337a2507942..2bb6ff9af1c7fede95a7879c3381dc0a1c424d8c 100644 (file)
@@ -184,22 +184,6 @@ static struct clk vdec_clk = {
        .type           = CLK_TYPE_PERIPHERAL,
 };
 
-/* One additional fake clock for ohci */
-static struct clk ohci_clk = {
-       .name           = "ohci_clk",
-       .pmc_mask       = 0,
-       .type           = CLK_TYPE_PERIPHERAL,
-       .parent         = &uhphs_clk,
-};
-
-/* One additional fake clock for second TC block */
-static struct clk tcb1_clk = {
-       .name           = "tcb1_clk",
-       .pmc_mask       = 0,
-       .type           = CLK_TYPE_PERIPHERAL,
-       .parent         = &tcb0_clk,
-};
-
 static struct clk *periph_clocks[] __initdata = {
        &pioA_clk,
        &pioB_clk,
@@ -228,8 +212,30 @@ static struct clk *periph_clocks[] __initdata = {
        &udphs_clk,
        &mmc1_clk,
        // irq0
-       &ohci_clk,
-       &tcb1_clk,
+};
+
+static struct clk_lookup periph_clocks_lookups[] = {
+       /* One additional fake clock for ohci */
+       CLKDEV_CON_ID("ohci_clk", &uhphs_clk),
+       CLKDEV_CON_DEV_ID("ehci_clk", "atmel-ehci.0", &uhphs_clk),
+       CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk),
+       CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk),
+       CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
+       CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb0_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+};
+
+static struct clk_lookup usart_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.4", &usart3_clk),
 };
 
 /*
@@ -256,6 +262,11 @@ static void __init at91sam9g45_register_clocks(void)
        for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
                clk_register(periph_clocks[i]);
 
+       clkdev_add_table(periph_clocks_lookups,
+                        ARRAY_SIZE(periph_clocks_lookups));
+       clkdev_add_table(usart_clocks_lookups,
+                        ARRAY_SIZE(usart_clocks_lookups));
+
        if (cpu_is_at91sam9m10() || cpu_is_at91sam9m11())
                clk_register(&vdec_clk);
 
@@ -263,6 +274,18 @@ static void __init at91sam9g45_register_clocks(void)
        clk_register(&pck1);
 }
 
+static struct clk_lookup console_clock_lookup;
+
+void __init at91sam9g45_set_console_clock(int id)
+{
+       if (id >= ARRAY_SIZE(usart_clocks_lookups))
+               return;
+
+       console_clock_lookup.con_id = "usart";
+       console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+       clkdev_add(&console_clock_lookup);
+}
+
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
@@ -306,11 +329,14 @@ static void at91sam9g45_poweroff(void)
  *  AT91SAM9G45 processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91sam9g45_initialize(unsigned long main_clock)
+void __init at91sam9g45_map_io(void)
 {
        /* Map peripherals */
        iotable_init(at91sam9g45_io_desc, ARRAY_SIZE(at91sam9g45_io_desc));
+}
 
+void __init at91sam9g45_initialize(unsigned long main_clock)
+{
        at91_arch_reset = at91sam9g45_reset;
        pm_power_off = at91sam9g45_poweroff;
        at91_extern_irq = (1 << AT91SAM9G45_ID_IRQ0);
index 5e9f8a4c38df0d900c326287debd0ea8ce57f604..05674865bc214d5642885038c514b5c4b067e7a5 100644 (file)
@@ -180,7 +180,6 @@ void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data)
        }
 
        usbh_ehci_data = *data;
-       at91_clock_associate("uhphs_clk", &at91_usbh_ehci_device.dev, "ehci_clk");
        platform_device_register(&at91_usbh_ehci_device);
 }
 #else
@@ -266,10 +265,6 @@ void __init at91_add_device_usba(struct usba_platform_data *data)
 
        /* Pullup pin is handled internally by USB device peripheral */
 
-       /* Clocks */
-       at91_clock_associate("utmi_clk", &at91_usba_udc_device.dev, "hclk");
-       at91_clock_associate("udphs_clk", &at91_usba_udc_device.dev, "pclk");
-
        platform_device_register(&at91_usba_udc_device);
 }
 #else
@@ -478,7 +473,6 @@ void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
                }
 
                mmc0_data = *data;
-               at91_clock_associate("mci0_clk", &at91sam9g45_mmc0_device.dev, "mci_clk");
                platform_device_register(&at91sam9g45_mmc0_device);
 
        } else {                        /* MCI1 */
@@ -504,7 +498,6 @@ void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
                }
 
                mmc1_data = *data;
-               at91_clock_associate("mci1_clk", &at91sam9g45_mmc1_device.dev, "mci_clk");
                platform_device_register(&at91sam9g45_mmc1_device);
 
        }
@@ -801,7 +794,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_A_periph(AT91_PIN_PB1, 0);     /* SPI0_MOSI */
                at91_set_A_periph(AT91_PIN_PB2, 0);     /* SPI0_SPCK */
 
-               at91_clock_associate("spi0_clk", &at91sam9g45_spi0_device.dev, "spi_clk");
                platform_device_register(&at91sam9g45_spi0_device);
        }
        if (enable_spi1) {
@@ -809,7 +801,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_A_periph(AT91_PIN_PB15, 0);    /* SPI1_MOSI */
                at91_set_A_periph(AT91_PIN_PB16, 0);    /* SPI1_SPCK */
 
-               at91_clock_associate("spi1_clk", &at91sam9g45_spi1_device.dev, "spi_clk");
                platform_device_register(&at91sam9g45_spi1_device);
        }
 }
@@ -999,10 +990,7 @@ static struct platform_device at91sam9g45_tcb1_device = {
 
 static void __init at91_add_device_tc(void)
 {
-       /* this chip has one clock and irq for all six TC channels */
-       at91_clock_associate("tcb0_clk", &at91sam9g45_tcb0_device.dev, "t0_clk");
        platform_device_register(&at91sam9g45_tcb0_device);
-       at91_clock_associate("tcb1_clk", &at91sam9g45_tcb1_device.dev, "t0_clk");
        platform_device_register(&at91sam9g45_tcb1_device);
 }
 #else
@@ -1286,12 +1274,10 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins)
        case AT91SAM9G45_ID_SSC0:
                pdev = &at91sam9g45_ssc0_device;
                configure_ssc0_pins(pins);
-               at91_clock_associate("ssc0_clk", &pdev->dev, "pclk");
                break;
        case AT91SAM9G45_ID_SSC1:
                pdev = &at91sam9g45_ssc1_device;
                configure_ssc1_pins(pins);
-               at91_clock_associate("ssc1_clk", &pdev->dev, "pclk");
                break;
        default:
                return;
@@ -1527,37 +1513,34 @@ struct platform_device *atmel_default_console_device;   /* the serial console devi
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
        struct platform_device *pdev;
+       struct atmel_uart_data *pdata;
 
        switch (id) {
                case 0:         /* DBGU */
                        pdev = &at91sam9g45_dbgu_device;
                        configure_dbgu_pins();
-                       at91_clock_associate("mck", &pdev->dev, "usart");
                        break;
                case AT91SAM9G45_ID_US0:
                        pdev = &at91sam9g45_uart0_device;
                        configure_usart0_pins(pins);
-                       at91_clock_associate("usart0_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9G45_ID_US1:
                        pdev = &at91sam9g45_uart1_device;
                        configure_usart1_pins(pins);
-                       at91_clock_associate("usart1_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9G45_ID_US2:
                        pdev = &at91sam9g45_uart2_device;
                        configure_usart2_pins(pins);
-                       at91_clock_associate("usart2_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9G45_ID_US3:
                        pdev = &at91sam9g45_uart3_device;
                        configure_usart3_pins(pins);
-                       at91_clock_associate("usart3_clk", &pdev->dev, "usart");
                        break;
                default:
                        return;
        }
-       pdev->id = portnr;              /* update to mapped ID */
+       pdata = pdev->dev.platform_data;
+       pdata->num = portnr;            /* update to mapped ID */
 
        if (portnr < ATMEL_MAX_UART)
                at91_uarts[portnr] = pdev;
@@ -1565,8 +1548,10 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 
 void __init at91_set_serial_console(unsigned portnr)
 {
-       if (portnr < ATMEL_MAX_UART)
+       if (portnr < ATMEL_MAX_UART) {
                atmel_default_console_device = at91_uarts[portnr];
+               at91sam9g45_set_console_clock(portnr);
+       }
 }
 
 void __init at91_add_device_serial(void)
index 6a9d24e5ed8e412680c2364208c46b820959f236..1a40f16b66c849dd71a14dd238e8df60df284876 100644 (file)
@@ -190,6 +190,24 @@ static struct clk *periph_clocks[] __initdata = {
        // irq0
 };
 
+static struct clk_lookup periph_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk),
+       CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
+       CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
+       CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+};
+
+static struct clk_lookup usart_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.4", &usart3_clk),
+};
+
 /*
  * The two programmable clocks.
  * You must configure pin multiplexing to bring these signals out.
@@ -214,10 +232,27 @@ static void __init at91sam9rl_register_clocks(void)
        for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
                clk_register(periph_clocks[i]);
 
+       clkdev_add_table(periph_clocks_lookups,
+                        ARRAY_SIZE(periph_clocks_lookups));
+       clkdev_add_table(usart_clocks_lookups,
+                        ARRAY_SIZE(usart_clocks_lookups));
+
        clk_register(&pck0);
        clk_register(&pck1);
 }
 
+static struct clk_lookup console_clock_lookup;
+
+void __init at91sam9rl_set_console_clock(int id)
+{
+       if (id >= ARRAY_SIZE(usart_clocks_lookups))
+               return;
+
+       console_clock_lookup.con_id = "usart";
+       console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+       clkdev_add(&console_clock_lookup);
+}
+
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
@@ -252,7 +287,7 @@ static void at91sam9rl_poweroff(void)
  *  AT91SAM9RL processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91sam9rl_initialize(unsigned long main_clock)
+void __init at91sam9rl_map_io(void)
 {
        unsigned long cidr, sram_size;
 
@@ -275,7 +310,10 @@ void __init at91sam9rl_initialize(unsigned long main_clock)
 
        /* Map SRAM */
        iotable_init(at91sam9rl_sram_desc, ARRAY_SIZE(at91sam9rl_sram_desc));
+}
 
+void __init at91sam9rl_initialize(unsigned long main_clock)
+{
        at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9rl_poweroff;
        at91_extern_irq = (1 << AT91SAM9RL_ID_IRQ0);
index c49262bddd851db28d12415c73203a532ae3d431..c296045f2b6aa2099cca149b520192dc0ab89034 100644 (file)
@@ -155,10 +155,6 @@ void __init at91_add_device_usba(struct usba_platform_data *data)
 
        /* Pullup pin is handled internally by USB device peripheral */
 
-       /* Clocks */
-       at91_clock_associate("utmi_clk", &at91_usba_udc_device.dev, "hclk");
-       at91_clock_associate("udphs_clk", &at91_usba_udc_device.dev, "pclk");
-
        platform_device_register(&at91_usba_udc_device);
 }
 #else
@@ -605,10 +601,6 @@ static struct platform_device at91sam9rl_tcb_device = {
 
 static void __init at91_add_device_tc(void)
 {
-       /* this chip has a separate clock and irq for each TC channel */
-       at91_clock_associate("tc0_clk", &at91sam9rl_tcb_device.dev, "t0_clk");
-       at91_clock_associate("tc1_clk", &at91sam9rl_tcb_device.dev, "t1_clk");
-       at91_clock_associate("tc2_clk", &at91sam9rl_tcb_device.dev, "t2_clk");
        platform_device_register(&at91sam9rl_tcb_device);
 }
 #else
@@ -892,12 +884,10 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins)
        case AT91SAM9RL_ID_SSC0:
                pdev = &at91sam9rl_ssc0_device;
                configure_ssc0_pins(pins);
-               at91_clock_associate("ssc0_clk", &pdev->dev, "pclk");
                break;
        case AT91SAM9RL_ID_SSC1:
                pdev = &at91sam9rl_ssc1_device;
                configure_ssc1_pins(pins);
-               at91_clock_associate("ssc1_clk", &pdev->dev, "pclk");
                break;
        default:
                return;
@@ -1141,37 +1131,34 @@ struct platform_device *atmel_default_console_device;   /* the serial console devi
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
        struct platform_device *pdev;
+       struct atmel_uart_data *pdata;
 
        switch (id) {
                case 0:         /* DBGU */
                        pdev = &at91sam9rl_dbgu_device;
                        configure_dbgu_pins();
-                       at91_clock_associate("mck", &pdev->dev, "usart");
                        break;
                case AT91SAM9RL_ID_US0:
                        pdev = &at91sam9rl_uart0_device;
                        configure_usart0_pins(pins);
-                       at91_clock_associate("usart0_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9RL_ID_US1:
                        pdev = &at91sam9rl_uart1_device;
                        configure_usart1_pins(pins);
-                       at91_clock_associate("usart1_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9RL_ID_US2:
                        pdev = &at91sam9rl_uart2_device;
                        configure_usart2_pins(pins);
-                       at91_clock_associate("usart2_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9RL_ID_US3:
                        pdev = &at91sam9rl_uart3_device;
                        configure_usart3_pins(pins);
-                       at91_clock_associate("usart3_clk", &pdev->dev, "usart");
                        break;
                default:
                        return;
        }
-       pdev->id = portnr;              /* update to mapped ID */
+       pdata = pdev->dev.platform_data;
+       pdata->num = portnr;            /* update to mapped ID */
 
        if (portnr < ATMEL_MAX_UART)
                at91_uarts[portnr] = pdev;
@@ -1179,8 +1166,10 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 
 void __init at91_set_serial_console(unsigned portnr)
 {
-       if (portnr < ATMEL_MAX_UART)
+       if (portnr < ATMEL_MAX_UART) {
                atmel_default_console_device = at91_uarts[portnr];
+               at91sam9rl_set_console_clock(portnr);
+       }
 }
 
 void __init at91_add_device_serial(void)
index ad3ec85b27906c5ac38c3d8f11432f0e87d61985..56ba3bd035aeff76f6bc0db6459c20d47ab9d09f 100644 (file)
@@ -37,11 +37,6 @@ unsigned long clk_get_rate(struct clk *clk)
        return AT91X40_MASTER_CLOCK;
 }
 
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       return NULL;
-}
-
 void __init at91x40_initialize(unsigned long main_clock)
 {
        at91_extern_irq = (1 << AT91X40_ID_IRQ0) | (1 << AT91X40_ID_IRQ1)
index 8a3fc84847c120b42980298067f74d8b3abc00fc..ab1d463aa47d4c3c72d6df44f590bec8a767d24e 100644 (file)
 
 #include <mach/board.h>
 #include <mach/gpio.h>
+#include <mach/cpu.h>
 
 #include "generic.h"
 
 
-static void __init onearm_map_io(void)
+static void __init onearm_init_early(void)
 {
+       /* Set cpu type: PQFP */
+       at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
+
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_PQFP);
+       at91rm9200_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -92,9 +96,9 @@ static void __init onearm_board_init(void)
 
 MACHINE_START(ONEARM, "Ajeco 1ARM single board computer")
        /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = onearm_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = onearm_init_early,
        .init_irq       = onearm_init_irq,
        .init_machine   = onearm_board_init,
 MACHINE_END
index cba7f7771feed1b6fc2286b76a8b63ffbdc9f398..a4924de48c36300e0121371ef0435e1ff4a8e43d 100644 (file)
@@ -48,7 +48,7 @@
 #include "generic.h"
 
 
-static void __init afeb9260_map_io(void)
+static void __init afeb9260_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9260_initialize(18432000);
@@ -218,9 +218,9 @@ static void __init afeb9260_board_init(void)
 
 MACHINE_START(AFEB9260, "Custom afeb9260 board")
        /* Maintainer: Sergey Lapin <slapin@ossfans.org> */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = afeb9260_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = afeb9260_init_early,
        .init_irq       = afeb9260_init_irq,
        .init_machine   = afeb9260_board_init,
 MACHINE_END
diff --git a/arch/arm/mach-at91/board-at572d940hf_ek.c b/arch/arm/mach-at91/board-at572d940hf_ek.c
deleted file mode 100644 (file)
index 3929f1c..0000000
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-at572d940hf_ek.c
- *
- * Copyright (C) 2008 Atmel Antonio R. Costa <costa.antonior@gmail.com>
- * Copyright (C) 2005 SAN People
- *
- * 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/types.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/ds1305.h>
-#include <linux/irq.h>
-#include <linux/mtd/physmap.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/board.h>
-#include <mach/gpio.h>
-#include <mach/at91sam9_smc.h>
-
-#include "sam9_smc.h"
-#include "generic.h"
-
-
-static void __init eb_map_io(void)
-{
-       /* Initialize processor: 12.500 MHz crystal */
-       at572d940hf_initialize(12000000);
-
-       /* DBGU on ttyS0. (Rx & Tx only) */
-       at91_register_uart(0, 0, 0);
-
-       /* USART0 on ttyS1. (Rx & Tx only) */
-       at91_register_uart(AT572D940HF_ID_US0, 1, 0);
-
-       /* USART1 on ttyS2. (Rx & Tx only) */
-       at91_register_uart(AT572D940HF_ID_US1, 2, 0);
-
-       /* USART2 on ttyS3. (Tx & Rx only */
-       at91_register_uart(AT572D940HF_ID_US2, 3, 0);
-
-       /* set serial console to ttyS0 (ie, DBGU) */
-       at91_set_serial_console(0);
-}
-
-static void __init eb_init_irq(void)
-{
-       at572d940hf_init_interrupts(NULL);
-}
-
-
-/*
- * USB Host Port
- */
-static struct at91_usbh_data __initdata eb_usbh_data = {
-       .ports          = 2,
-};
-
-
-/*
- * USB Device Port
- */
-static struct at91_udc_data __initdata eb_udc_data = {
-       .vbus_pin       = 0,            /* no VBUS detection,UDC always on */
-       .pullup_pin     = 0,            /* pull-up driven by UDC */
-};
-
-
-/*
- * MCI (SD/MMC)
- */
-static struct at91_mmc_data __initdata eb_mmc_data = {
-       .wire4          = 1,
-/*     .det_pin        = ... not connected */
-/*     .wp_pin         = ... not connected */
-/*     .vcc_pin        = ... not connected */
-};
-
-
-/*
- * MACB Ethernet device
- */
-static struct at91_eth_data __initdata eb_eth_data = {
-       .phy_irq_pin    = AT91_PIN_PB25,
-       .is_rmii        = 1,
-};
-
-/*
- * NOR flash
- */
-
-static struct mtd_partition eb_nor_partitions[] = {
-       {
-               .name           = "Raw Environment",
-               .offset         = 0,
-               .size           = SZ_4M,
-               .mask_flags     = 0,
-       },
-       {
-               .name           = "OS FS",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = 3 * SZ_1M,
-               .mask_flags     = 0,
-       },
-       {
-               .name           = "APP FS",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = MTDPART_SIZ_FULL,
-               .mask_flags     = 0,
-       },
-};
-
-static void nor_flash_set_vpp(struct map_info* mi, int i) {
-};
-
-static struct physmap_flash_data nor_flash_data = {
-       .width          = 4,
-       .parts          = eb_nor_partitions,
-       .nr_parts       = ARRAY_SIZE(eb_nor_partitions),
-       .set_vpp        = nor_flash_set_vpp,
-};
-
-static struct resource nor_flash_resources[] = {
-       {
-               .start  = AT91_CHIPSELECT_0,
-               .end    = AT91_CHIPSELECT_0 + SZ_16M - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device nor_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-                               .platform_data = &nor_flash_data,
-                       },
-       .resource       = nor_flash_resources,
-       .num_resources  = ARRAY_SIZE(nor_flash_resources),
-};
-
-static struct sam9_smc_config __initdata eb_nor_smc_config = {
-       .ncs_read_setup         = 1,
-       .nrd_setup              = 1,
-       .ncs_write_setup        = 1,
-       .nwe_setup              = 1,
-
-       .ncs_read_pulse         = 7,
-       .nrd_pulse              = 7,
-       .ncs_write_pulse        = 7,
-       .nwe_pulse              = 7,
-
-       .read_cycle             = 9,
-       .write_cycle            = 9,
-
-       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_WRITE | AT91_SMC_DBW_32,
-       .tdf_cycles             = 1,
-};
-
-static void __init eb_add_device_nor(void)
-{
-       /* configure chip-select 0 (NOR) */
-       sam9_smc_configure(0, &eb_nor_smc_config);
-       platform_device_register(&nor_flash);
-}
-
-/*
- * NAND flash
- */
-static struct mtd_partition __initdata eb_nand_partition[] = {
-       {
-               .name   = "Partition 1",
-               .offset = 0,
-               .size   = SZ_16M,
-       },
-       {
-               .name   = "Partition 2",
-               .offset = MTDPART_OFS_NXTBLK,
-               .size   = MTDPART_SIZ_FULL,
-       }
-};
-
-static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
-{
-       *num_partitions = ARRAY_SIZE(eb_nand_partition);
-       return eb_nand_partition;
-}
-
-static struct atmel_nand_data __initdata eb_nand_data = {
-       .ale            = 22,
-       .cle            = 21,
-/*     .det_pin        = ... not connected */
-/*     .rdy_pin        = AT91_PIN_PC16, */
-       .enable_pin     = AT91_PIN_PA15,
-       .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
-};
-
-static struct sam9_smc_config __initdata eb_nand_smc_config = {
-       .ncs_read_setup         = 0,
-       .nrd_setup              = 0,
-       .ncs_write_setup        = 1,
-       .nwe_setup              = 1,
-
-       .ncs_read_pulse         = 3,
-       .nrd_pulse              = 3,
-       .ncs_write_pulse        = 3,
-       .nwe_pulse              = 3,
-
-       .read_cycle             = 5,
-       .write_cycle            = 5,
-
-       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
-       .tdf_cycles             = 12,
-};
-
-static void __init eb_add_device_nand(void)
-{
-       /* setup bus-width (8 or 16) */
-       if (eb_nand_data.bus_width_16)
-               eb_nand_smc_config.mode |= AT91_SMC_DBW_16;
-       else
-               eb_nand_smc_config.mode |= AT91_SMC_DBW_8;
-
-       /* configure chip-select 3 (NAND) */
-       sam9_smc_configure(3, &eb_nand_smc_config);
-
-       at91_add_device_nand(&eb_nand_data);
-}
-
-
-/*
- * SPI devices
- */
-static struct resource rtc_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_ID_IRQ1,
-               .end    = AT572D940HF_ID_IRQ1,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct ds1305_platform_data ds1306_data = {
-       .is_ds1306      = true,
-       .en_1hz         = false,
-};
-
-static struct spi_board_info eb_spi_devices[] = {
-       {       /* RTC Dallas DS1306 */
-               .modalias       = "rtc-ds1305",
-               .chip_select    = 3,
-               .mode           = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA,
-               .max_speed_hz   = 500000,
-               .bus_num        = 0,
-               .irq            = AT572D940HF_ID_IRQ1,
-               .platform_data  = (void *) &ds1306_data,
-       },
-#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
-       {       /* Dataflash card */
-               .modalias       = "mtd_dataflash",
-               .chip_select    = 0,
-               .max_speed_hz   = 15 * 1000 * 1000,
-               .bus_num        = 0,
-       },
-#endif
-};
-
-static void __init eb_board_init(void)
-{
-       /* Serial */
-       at91_add_device_serial();
-       /* USB Host */
-       at91_add_device_usbh(&eb_usbh_data);
-       /* USB Device */
-       at91_add_device_udc(&eb_udc_data);
-       /* I2C */
-       at91_add_device_i2c(NULL, 0);
-       /* NOR */
-       eb_add_device_nor();
-       /* NAND */
-       eb_add_device_nand();
-       /* SPI */
-       at91_add_device_spi(eb_spi_devices, ARRAY_SIZE(eb_spi_devices));
-       /* MMC */
-       at91_add_device_mmc(0, &eb_mmc_data);
-       /* Ethernet */
-       at91_add_device_eth(&eb_eth_data);
-       /* mAgic */
-       at91_add_device_mAgic();
-}
-
-MACHINE_START(AT572D940HFEB, "Atmel AT91D940HF-EB")
-       /* Maintainer: Atmel <costa.antonior@gmail.com> */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
-       .timer          = &at91sam926x_timer,
-       .map_io         = eb_map_io,
-       .init_irq       = eb_init_irq,
-       .init_machine   = eb_board_init,
-MACHINE_END
index b54e3e6fceb6774df2318b663131625800b25b0a..148fccb9a25a4e9c5d10ec2740bd4e3a48195af0 100644 (file)
@@ -45,7 +45,7 @@
 #include "generic.h"
 
 
-static void __init cam60_map_io(void)
+static void __init cam60_init_early(void)
 {
        /* Initialize processor: 10 MHz crystal */
        at91sam9260_initialize(10000000);
@@ -198,9 +198,9 @@ static void __init cam60_board_init(void)
 
 MACHINE_START(CAM60, "KwikByte CAM60")
        /* Maintainer: KwikByte */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = cam60_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = cam60_init_early,
        .init_irq       = cam60_init_irq,
        .init_machine   = cam60_board_init,
 MACHINE_END
index e7274440ead99f8970e2abc801d2d752dced6d90..1904fdf87613d9803ffcae12cfd1618111f4aee5 100644 (file)
 #include <mach/gpio.h>
 #include <mach/at91cap9_matrix.h>
 #include <mach/at91sam9_smc.h>
+#include <mach/system_rev.h>
 
 #include "sam9_smc.h"
 #include "generic.h"
 
 
-static void __init cap9adk_map_io(void)
+static void __init cap9adk_init_early(void)
 {
        /* Initialize processor: 12 MHz crystal */
        at91cap9_initialize(12000000);
@@ -187,11 +188,6 @@ static struct atmel_nand_data __initdata cap9adk_nand_data = {
 //     .rdy_pin        = ... not connected
        .enable_pin     = AT91_PIN_PD15,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
 };
 
 static struct sam9_smc_config __initdata cap9adk_nand_smc_config = {
@@ -219,6 +215,7 @@ static void __init cap9adk_add_device_nand(void)
        csa = at91_sys_read(AT91_MATRIX_EBICSA);
        at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_VDDIOMSEL_3_3V);
 
+       cap9adk_nand_data.bus_width_16 = !board_have_nand_8bit();
        /* setup bus-width (8 or 16) */
        if (cap9adk_nand_data.bus_width_16)
                cap9adk_nand_smc_config.mode |= AT91_SMC_DBW_16;
@@ -399,9 +396,9 @@ static void __init cap9adk_board_init(void)
 
 MACHINE_START(AT91CAP9ADK, "Atmel AT91CAP9A-DK")
        /* Maintainer: Stelian Pop <stelian.pop@leadtechdesign.com> */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = cap9adk_map_io,
+       .map_io         = at91cap9_map_io,
+       .init_early     = cap9adk_init_early,
        .init_irq       = cap9adk_init_irq,
        .init_machine   = cap9adk_board_init,
 MACHINE_END
index 295e1e77fa60cc3106a17b685df37be064428f81..f36b18687494a5548ace1b4a534cee7cb284aa1d 100644 (file)
 #include "generic.h"
 
 
-static void __init carmeva_map_io(void)
+static void __init carmeva_init_early(void)
 {
        /* Initialize processor: 20.000 MHz crystal */
-       at91rm9200_initialize(20000000, AT91RM9200_BGA);
+       at91rm9200_initialize(20000000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -162,9 +162,9 @@ static void __init carmeva_board_init(void)
 
 MACHINE_START(CARMEVA, "Carmeva")
        /* Maintainer: Conitec Datasystems */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = carmeva_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = carmeva_init_early,
        .init_irq       = carmeva_init_irq,
        .init_machine   = carmeva_board_init,
 MACHINE_END
index 3838594578f3539d395cfd74bd4f9a90f9c21940..980511084fe4179e9965568f26cb9a6d174380e9 100644 (file)
@@ -47,7 +47,7 @@
 #include "sam9_smc.h"
 #include "generic.h"
 
-static void __init cpu9krea_map_io(void)
+static void __init cpu9krea_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9260_initialize(18432000);
@@ -375,9 +375,9 @@ MACHINE_START(CPUAT9260, "Eukrea CPU9260")
 MACHINE_START(CPUAT9G20, "Eukrea CPU9G20")
 #endif
        /* Maintainer: Eric Benard - EUKREA Electromatique */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = cpu9krea_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = cpu9krea_init_early,
        .init_irq       = cpu9krea_init_irq,
        .init_machine   = cpu9krea_board_init,
 MACHINE_END
index 2f4dd8cdd484a50c1276fd48dcc61b68b3519c24..6daabe3907a1d7cdaa033147de021114ce6727d2 100644 (file)
@@ -38,6 +38,7 @@
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/cpu.h>
 
 #include "generic.h"
 
@@ -50,10 +51,13 @@ static struct gpio_led cpuat91_leds[] = {
        },
 };
 
-static void __init cpuat91_map_io(void)
+static void __init cpuat91_init_early(void)
 {
+       /* Set cpu type: PQFP */
+       at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
+
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_PQFP);
+       at91rm9200_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -175,9 +179,9 @@ static void __init cpuat91_board_init(void)
 
 MACHINE_START(CPUAT91, "Eukrea")
        /* Maintainer: Eric Benard - EUKREA Electromatique */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = cpuat91_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = cpuat91_init_early,
        .init_irq       = cpuat91_init_irq,
        .init_machine   = cpuat91_board_init,
 MACHINE_END
index 464839dc39bd4d1c9acc0d38d17559d84a897e32..d98bcec1dfe000d6dc667081f36655a6206bf5fa 100644 (file)
 #include "generic.h"
 
 
-static void __init csb337_map_io(void)
+static void __init csb337_init_early(void)
 {
        /* Initialize processor: 3.6864 MHz crystal */
-       at91rm9200_initialize(3686400, AT91RM9200_BGA);
+       at91rm9200_initialize(3686400);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
@@ -257,9 +257,9 @@ static void __init csb337_board_init(void)
 
 MACHINE_START(CSB337, "Cogent CSB337")
        /* Maintainer: Bill Gatliff */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = csb337_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = csb337_init_early,
        .init_irq       = csb337_init_irq,
        .init_machine   = csb337_board_init,
 MACHINE_END
index 431688c6141267f3227f034baa9c9dab2bd9d9d3..019aab4e20b01394aba18eb89580e2ed729b08a6 100644 (file)
 #include "generic.h"
 
 
-static void __init csb637_map_io(void)
+static void __init csb637_init_early(void)
 {
        /* Initialize processor: 3.6864 MHz crystal */
-       at91rm9200_initialize(3686400, AT91RM9200_BGA);
+       at91rm9200_initialize(3686400);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -138,9 +138,9 @@ static void __init csb637_board_init(void)
 
 MACHINE_START(CSB637, "Cogent CSB637")
        /* Maintainer: Bill Gatliff */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = csb637_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = csb637_init_early,
        .init_irq       = csb637_init_irq,
        .init_machine   = csb637_board_init,
 MACHINE_END
index d8df59a3426d82a75de3255bf586292659072616..d2023f27c65254f83113588a105d221ccfabf705 100644 (file)
@@ -35,7 +35,7 @@ static void __init at91eb01_init_irq(void)
        at91x40_init_interrupts(NULL);
 }
 
-static void __init at91eb01_map_io(void)
+static void __init at91eb01_init_early(void)
 {
        at91x40_initialize(40000000);
 }
@@ -43,7 +43,7 @@ static void __init at91eb01_map_io(void)
 MACHINE_START(AT91EB01, "Atmel AT91 EB01")
        /* Maintainer: Greg Ungerer <gerg@snapgear.com> */
        .timer          = &at91x40_timer,
+       .init_early     = at91eb01_init_early,
        .init_irq       = at91eb01_init_irq,
-       .map_io         = at91eb01_map_io,
 MACHINE_END
 
index 6cf6566ae346610a78f29f7de0f0f698f7d16e09..e9484535cbc81f213b77bf617068721a037a3b9a 100644 (file)
 #include "generic.h"
 
 
-static void __init eb9200_map_io(void)
+static void __init eb9200_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_BGA);
+       at91rm9200_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -120,9 +120,9 @@ static void __init eb9200_board_init(void)
 }
 
 MACHINE_START(ATEB9200, "Embest ATEB9200")
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = eb9200_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = eb9200_init_early,
        .init_irq       = eb9200_init_irq,
        .init_machine   = eb9200_board_init,
 MACHINE_END
index de2fd04e7c8ae355940829879b0dcf008b3da999..a6f57faa10a7f1dbc202c6d320c03854fff54982 100644 (file)
 
 #include <mach/board.h>
 #include <mach/gpio.h>
+#include <mach/cpu.h>
 
 #include "generic.h"
 
 
-static void __init ecb_at91map_io(void)
+static void __init ecb_at91init_early(void)
 {
+       /* Set cpu type: PQFP */
+       at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
+
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_PQFP);
+       at91rm9200_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7);
@@ -168,9 +172,9 @@ static void __init ecb_at91board_init(void)
 
 MACHINE_START(ECBAT91, "emQbit's ECB_AT91")
        /* Maintainer: emQbit.com */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = ecb_at91map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = ecb_at91init_early,
        .init_irq       = ecb_at91init_irq,
        .init_machine   = ecb_at91board_init,
 MACHINE_END
index a158a0ce458fb36d09a4afe58f184c0e428ed057..bfc0062d1483f61e0a1d7026ca9a859a41253840 100644 (file)
 
 #include <mach/board.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/cpu.h>
+
 #include "generic.h"
 
-static void __init eco920_map_io(void)
+static void __init eco920_init_early(void)
 {
-       at91rm9200_initialize(18432000, AT91RM9200_PQFP);
+       /* Set cpu type: PQFP */
+       at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
+
+       at91rm9200_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
@@ -86,21 +91,6 @@ static struct platform_device eco920_flash = {
        .num_resources  = 1,
 };
 
-static struct resource at91_beeper_resources[] = {
-       [0] = {
-               .start          = AT91RM9200_BASE_TC3,
-               .end            = AT91RM9200_BASE_TC3 + 0x39,
-               .flags          = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device at91_beeper = {
-       .name           = "at91_beeper",
-       .id             = 0,
-       .resource       = at91_beeper_resources,
-       .num_resources  = ARRAY_SIZE(at91_beeper_resources),
-};
-
 static struct spi_board_info eco920_spi_devices[] = {
        {       /* CAN controller */
                .modalias       = "tlv5638",
@@ -139,18 +129,14 @@ static void __init eco920_board_init(void)
                AT91_SMC_TDF_(1)        /* float time */
        );
 
-       at91_clock_associate("tc3_clk", &at91_beeper.dev, "at91_beeper");
-       at91_set_B_periph(AT91_PIN_PB6, 0);
-       platform_device_register(&at91_beeper);
-
        at91_add_device_spi(eco920_spi_devices, ARRAY_SIZE(eco920_spi_devices));
 }
 
 MACHINE_START(ECO920, "eco920")
        /* Maintainer: Sascha Hauer */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = eco920_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = eco920_init_early,
        .init_irq       = eco920_init_irq,
        .init_machine   = eco920_board_init,
 MACHINE_END
index c8a62dc8fa65965f7672673e58201ff00ed9bebd..466c063b8d218257eae472407a24c5b58773b9b9 100644 (file)
@@ -37,7 +37,7 @@
 
 #include "generic.h"
 
-static void __init flexibity_map_io(void)
+static void __init flexibity_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9260_initialize(18432000);
@@ -154,9 +154,9 @@ static void __init flexibity_board_init(void)
 
 MACHINE_START(FLEXIBITY, "Flexibity Connect")
        /* Maintainer: Maxim Osipov */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = flexibity_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = flexibity_init_early,
        .init_irq       = flexibity_init_irq,
        .init_machine   = flexibity_board_init,
 MACHINE_END
index dfc7dfe738e4a5260ff64c2013010c19a81b4b04..e2d1dc9eff452f09d0459b3191ebaaac387709c0 100644 (file)
@@ -57,7 +57,7 @@
  */
 
 
-static void __init foxg20_map_io(void)
+static void __init foxg20_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9260_initialize(18432000);
@@ -266,9 +266,9 @@ static void __init foxg20_board_init(void)
 
 MACHINE_START(ACMENETUSFOXG20, "Acme Systems srl FOX Board G20")
        /* Maintainer: Sergio Tanzilli */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = foxg20_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = foxg20_init_early,
        .init_irq       = foxg20_init_irq,
        .init_machine   = foxg20_board_init,
 MACHINE_END
index bc28136ee24966e19e6d8a3a271f04f7ed32ea92..1d4f36b3cb275d0b27ce83e8a187201efc36402b 100644 (file)
@@ -38,9 +38,9 @@
 #include "sam9_smc.h"
 #include "generic.h"
 
-static void __init gsia18s_map_io(void)
+static void __init gsia18s_init_early(void)
 {
-       stamp9g20_map_io();
+       stamp9g20_init_early();
 
        /*
         * USART0 on ttyS1 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI).
@@ -576,9 +576,9 @@ static void __init gsia18s_board_init(void)
 }
 
 MACHINE_START(GSIA18S, "GS_IA18_S")
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = gsia18s_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = gsia18s_init_early,
        .init_irq       = init_irq,
        .init_machine   = gsia18s_board_init,
 MACHINE_END
index d2e1f4ec1fcc87dcc6aca97d6a664af6ed637d36..9b003ff744ba4c87d3746001de09125a36fe7657 100644 (file)
 
 #include <mach/board.h>
 #include <mach/gpio.h>
+#include <mach/cpu.h>
 
 #include "generic.h"
 
 
-static void __init kafa_map_io(void)
+static void __init kafa_init_early(void)
 {
+       /* Set cpu type: PQFP */
+       at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
+
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_PQFP);
+       at91rm9200_initialize(18432000);
 
        /* Set up the LEDs */
        at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
@@ -94,9 +98,9 @@ static void __init kafa_board_init(void)
 
 MACHINE_START(KAFA, "Sperry-Sun KAFA")
        /* Maintainer: Sergei Sharonov */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = kafa_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = kafa_init_early,
        .init_irq       = kafa_init_irq,
        .init_machine   = kafa_board_init,
 MACHINE_END
index a13d2063faff8e43dfeedab3531010e0118887b2..a813a74b65f9e296aba3d4d31af7f48913dd87e2 100644 (file)
 
 #include <mach/board.h>
 #include <mach/gpio.h>
-
+#include <mach/cpu.h>
 #include <mach/at91rm9200_mc.h>
 
 #include "generic.h"
 
 
-static void __init kb9202_map_io(void)
+static void __init kb9202_init_early(void)
 {
+       /* Set cpu type: PQFP */
+       at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
+
        /* Initialize processor: 10 MHz crystal */
-       at91rm9200_initialize(10000000, AT91RM9200_PQFP);
+       at91rm9200_initialize(10000000);
 
        /* Set up the LEDs */
        at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18);
@@ -136,9 +139,9 @@ static void __init kb9202_board_init(void)
 
 MACHINE_START(KB9200, "KB920x")
        /* Maintainer: KwikByte, Inc. */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = kb9202_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = kb9202_init_early,
        .init_irq       = kb9202_init_irq,
        .init_machine   = kb9202_board_init,
 MACHINE_END
index fe5f1d47e6e23884eb2ac6d3ab00d36aa264aba0..961e805db68c21f7bde7db486d43126e57e31cd5 100644 (file)
@@ -51,7 +51,7 @@
 #include "generic.h"
 
 
-static void __init neocore926_map_io(void)
+static void __init neocore926_init_early(void)
 {
        /* Initialize processor: 20 MHz crystal */
        at91sam9263_initialize(20000000);
@@ -387,9 +387,9 @@ static void __init neocore926_board_init(void)
 
 MACHINE_START(NEOCORE926, "ADENEO NEOCORE 926")
        /* Maintainer: ADENEO */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = neocore926_map_io,
+       .map_io         = at91sam9263_map_io,
+       .init_early     = neocore926_init_early,
        .init_irq       = neocore926_init_irq,
        .init_machine   = neocore926_board_init,
 MACHINE_END
index feb65787c30be5502985a112e4b200d0f7de8ac0..21a21af258784336c94a7b374b883a26f6652d82 100644 (file)
@@ -37,9 +37,9 @@
 #include "generic.h"
 
 
-static void __init pcontrol_g20_map_io(void)
+static void __init pcontrol_g20_init_early(void)
 {
-       stamp9g20_map_io();
+       stamp9g20_init_early();
 
        /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) piggyback  A2 */
        at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS
@@ -222,9 +222,9 @@ static void __init pcontrol_g20_board_init(void)
 
 MACHINE_START(PCONTROL_G20, "PControl G20")
        /* Maintainer: pgsellmann@portner-elektronik.at */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = pcontrol_g20_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = pcontrol_g20_init_early,
        .init_irq       = init_irq,
        .init_machine   = pcontrol_g20_board_init,
 MACHINE_END
index 55dad3a46547288cba52ed6debc5d384f55bc8e1..756cc2a745ddd16c5ac5f1f3a23cc10aac4fe158 100644 (file)
 #include "generic.h"
 
 
-static void __init picotux200_map_io(void)
+static void __init picotux200_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_BGA);
+       at91rm9200_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -123,9 +123,9 @@ static void __init picotux200_board_init(void)
 
 MACHINE_START(PICOTUX2XX, "picotux 200")
        /* Maintainer: Kleinhenz Elektronik GmbH */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = picotux200_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = picotux200_init_early,
        .init_irq       = picotux200_init_irq,
        .init_machine   = picotux200_board_init,
 MACHINE_END
index 69d15a875b667f34a68ba4332db47c5a4f6bef4c..d1a6001b0bd86b7a931ff0c8f86e710a85ae67eb 100644 (file)
@@ -48,7 +48,7 @@
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.000 MHz crystal */
        at91sam9260_initialize(12000000);
@@ -268,9 +268,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(QIL_A9260, "CALAO QIL_A9260")
        /* Maintainer: calao-systems */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index 4c1047c8200df94466a81337779a4cfcfb1c7d7a..aef9627710b0cee79ce885abb8b6e1be60df1bf5 100644 (file)
 #include "generic.h"
 
 
-static void __init dk_map_io(void)
+static void __init dk_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_BGA);
+       at91rm9200_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
@@ -227,9 +227,9 @@ static void __init dk_board_init(void)
 
 MACHINE_START(AT91RM9200DK, "Atmel AT91RM9200-DK")
        /* Maintainer: SAN People/Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = dk_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = dk_init_early,
        .init_irq       = dk_init_irq,
        .init_machine   = dk_board_init,
 MACHINE_END
index 9df1be8818c0bdf8eb9ff47086e0a68ee7c21294..015a02183080973619b389bf406c98ee87ba91af 100644 (file)
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_BGA);
+       at91rm9200_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
@@ -193,9 +193,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91RM9200EK, "Atmel AT91RM9200-EK")
        /* Maintainer: SAN People/Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index 25a26beaa728bbee99a15174925a73532ddad949..aaf1bf0989b3c1635e40e6314456cd7189594d77 100644 (file)
@@ -44,7 +44,7 @@
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9260_initialize(18432000);
@@ -212,9 +212,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
        /* Maintainer: Olimex */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index de1816e0e1d967c87825bf6c4de11c8370aaf057..d600dc123227f04dad183eb1606f798258eb2ba1 100644 (file)
 #include <mach/gpio.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
+#include <mach/system_rev.h>
 
 #include "sam9_smc.h"
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9260_initialize(18432000);
@@ -191,11 +192,6 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PC13,
        .enable_pin     = AT91_PIN_PC14,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
 };
 
 static struct sam9_smc_config __initdata ek_nand_smc_config = {
@@ -218,6 +214,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
 
 static void __init ek_add_device_nand(void)
 {
+       ek_nand_data.bus_width_16 = !board_have_nand_8bit();
        /* setup bus-width (8 or 16) */
        if (ek_nand_data.bus_width_16)
                ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
@@ -356,9 +353,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
        /* Maintainer: Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index 14acc901e24cdd97ca4c939f5ae3bcfba189feff..f897f84d43dc490d393768c3c9ed6296687e5f44 100644 (file)
 #include <mach/gpio.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
+#include <mach/system_rev.h>
 
 #include "sam9_smc.h"
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9261_initialize(18432000);
@@ -197,11 +198,6 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PC15,
        .enable_pin     = AT91_PIN_PC14,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
 };
 
 static struct sam9_smc_config __initdata ek_nand_smc_config = {
@@ -224,6 +220,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
 
 static void __init ek_add_device_nand(void)
 {
+       ek_nand_data.bus_width_16 = !board_have_nand_8bit();
        /* setup bus-width (8 or 16) */
        if (ek_nand_data.bus_width_16)
                ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
@@ -623,9 +620,9 @@ MACHINE_START(AT91SAM9261EK, "Atmel AT91SAM9261-EK")
 MACHINE_START(AT91SAM9G10EK, "Atmel AT91SAM9G10-EK")
 #endif
        /* Maintainer: Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9261_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index bfe490df58be9edf63ab20b001ccaf94c368ccd1..605b26f40a4ce6e947f0a322c2597e88cf3514de 100644 (file)
 #include <mach/gpio.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
+#include <mach/system_rev.h>
 
 #include "sam9_smc.h"
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 16.367 MHz crystal */
        at91sam9263_initialize(16367660);
@@ -198,11 +199,6 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PA22,
        .enable_pin     = AT91_PIN_PD15,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
 };
 
 static struct sam9_smc_config __initdata ek_nand_smc_config = {
@@ -225,6 +221,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
 
 static void __init ek_add_device_nand(void)
 {
+       ek_nand_data.bus_width_16 = !board_have_nand_8bit();
        /* setup bus-width (8 or 16) */
        if (ek_nand_data.bus_width_16)
                ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
@@ -454,9 +451,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
        /* Maintainer: Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9263_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index ca8198b3c168bb8a333dc3d08102b082a73e66c4..7624cf0d006b9030639d1a7d2a84d9a3b8f5893a 100644 (file)
@@ -43,6 +43,7 @@
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91sam9_smc.h>
+#include <mach/system_rev.h>
 
 #include "sam9_smc.h"
 #include "generic.h"
@@ -60,7 +61,7 @@ static int inline ek_have_2mmc(void)
 }
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9260_initialize(18432000);
@@ -175,11 +176,6 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PC13,
        .enable_pin     = AT91_PIN_PC14,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
 };
 
 static struct sam9_smc_config __initdata ek_nand_smc_config = {
@@ -202,6 +198,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
 
 static void __init ek_add_device_nand(void)
 {
+       ek_nand_data.bus_width_16 = !board_have_nand_8bit();
        /* setup bus-width (8 or 16) */
        if (ek_nand_data.bus_width_16)
                ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
@@ -406,18 +403,18 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9G20EK, "Atmel AT91SAM9G20-EK")
        /* Maintainer: Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
 
 MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
        /* Maintainer: Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index 6c999dbd2bcfb20427387767dc5bdb623c48a489..063c95d0e8f02879c35792b548da42452056e183 100644 (file)
 #include <mach/gpio.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
+#include <mach/system_rev.h>
 
 #include "sam9_smc.h"
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.000 MHz crystal */
        at91sam9g45_initialize(12000000);
@@ -155,11 +156,6 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PC8,
        .enable_pin     = AT91_PIN_PC14,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
 };
 
 static struct sam9_smc_config __initdata ek_nand_smc_config = {
@@ -182,6 +178,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
 
 static void __init ek_add_device_nand(void)
 {
+       ek_nand_data.bus_width_16 = !board_have_nand_8bit();
        /* setup bus-width (8 or 16) */
        if (ek_nand_data.bus_width_16)
                ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
@@ -424,9 +421,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK")
        /* Maintainer: Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9g45_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index 3bf3408e94c18f370d5edb3991f7a8ff6dd0b208..effb399a80a689ce5993e7526715ebb875b0d4a3 100644 (file)
@@ -38,7 +38,7 @@
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.000 MHz crystal */
        at91sam9rl_initialize(12000000);
@@ -329,9 +329,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK")
        /* Maintainer: Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9rl_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index 17f7d9b32142d73984f60cc554c874865a385e17..3eb0a1153cc8f2ee50c5f5e2f6afd1947173de78 100644 (file)
@@ -40,7 +40,7 @@
 
 #define SNAPPER9260_IO_EXP_GPIO(x)     (NR_BUILTIN_GPIO + (x))
 
-static void __init snapper9260_map_io(void)
+static void __init snapper9260_init_early(void)
 {
        at91sam9260_initialize(18432000);
 
@@ -178,9 +178,9 @@ static void __init snapper9260_board_init(void)
 }
 
 MACHINE_START(SNAPPER_9260, "Bluewater Systems Snapper 9260/9G20 module")
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = snapper9260_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = snapper9260_init_early,
        .init_irq       = snapper9260_init_irq,
        .init_machine   = snapper9260_board_init,
 MACHINE_END
index f8902b118960d84f4d9bf6c57d3a28e9c302df64..5e5c85688f5f5a59ade095ec246952ef4750419e 100644 (file)
@@ -32,7 +32,7 @@
 #include "generic.h"
 
 
-void __init stamp9g20_map_io(void)
+void __init stamp9g20_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9260_initialize(18432000);
@@ -44,9 +44,9 @@ void __init stamp9g20_map_io(void)
        at91_set_serial_console(0);
 }
 
-static void __init stamp9g20evb_map_io(void)
+static void __init stamp9g20evb_init_early(void)
 {
-       stamp9g20_map_io();
+       stamp9g20_init_early();
 
        /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
        at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
@@ -54,9 +54,9 @@ static void __init stamp9g20evb_map_io(void)
                                                | ATMEL_UART_DCD | ATMEL_UART_RI);
 }
 
-static void __init portuxg20_map_io(void)
+static void __init portuxg20_init_early(void)
 {
-       stamp9g20_map_io();
+       stamp9g20_init_early();
 
        /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
        at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
@@ -298,18 +298,18 @@ static void __init stamp9g20evb_board_init(void)
 
 MACHINE_START(PORTUXG20, "taskit PortuxG20")
        /* Maintainer: taskit GmbH */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = portuxg20_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = portuxg20_init_early,
        .init_irq       = init_irq,
        .init_machine   = portuxg20_board_init,
 MACHINE_END
 
 MACHINE_START(STAMP9G20, "taskit Stamp9G20")
        /* Maintainer: taskit GmbH */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = stamp9g20evb_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = stamp9g20evb_init_early,
        .init_irq       = init_irq,
        .init_machine   = stamp9g20evb_board_init,
 MACHINE_END
index 07784baeae841f2d98709b71cc1fe45917b820f1..0e784e6fedec3641acf2b2ebf502b4d682fe91dc 100644 (file)
@@ -48,7 +48,7 @@
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.000 MHz crystal */
        at91sam9260_initialize(12000000);
@@ -228,9 +228,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(USB_A9260, "CALAO USB_A9260")
        /* Maintainer: calao-systems */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index b614508931fd92cc1b7b95a4da438d246cf5f86e..cf626dd14b2ccc6c914790641e523989cfe66413 100644 (file)
@@ -47,7 +47,7 @@
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.00 MHz crystal */
        at91sam9263_initialize(12000000);
@@ -244,9 +244,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(USB_A9263, "CALAO USB_A9263")
        /* Maintainer: calao-systems */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9263_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index e0f0080eb639f30137d8aca6631271ad82dc639e..c208cc334d7df8421e34ea004b8380c374159791 100644 (file)
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/cpu.h>
 
 #include "generic.h"
 
 
-static void __init yl9200_map_io(void)
+static void __init yl9200_init_early(void)
 {
+       /* Set cpu type: PQFP */
+       at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
+
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_PQFP);
+       at91rm9200_initialize(18432000);
 
        /* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */
        at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17);
@@ -594,9 +598,9 @@ static void __init yl9200_board_init(void)
 
 MACHINE_START(YL9200, "uCdragon YL-9200")
        /* Maintainer: S.Birtles */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = yl9200_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = yl9200_init_early,
        .init_irq       = yl9200_init_irq,
        .init_machine   = yl9200_board_init,
 MACHINE_END
index 9113da6845f17482437ed984bd978b9b28378dfe..61873f3aa92d74f2aaa327a4f0e7d0021f502d02 100644 (file)
@@ -163,7 +163,7 @@ static struct clk udpck = {
        .parent         = &pllb,
        .mode           = pmc_sys_mode,
 };
-static struct clk utmi_clk = {
+struct clk utmi_clk = {
        .name           = "utmi_clk",
        .parent         = &main_clk,
        .pmc_mask       = AT91_PMC_UPLLEN,      /* in CKGR_UCKR */
@@ -182,7 +182,7 @@ static struct clk uhpck = {
  * memory, interfaces to on-chip peripherals, the AIC, and sometimes more
  * (e.g baud rate generation).  It's sourced from one of the primary clocks.
  */
-static struct clk mck = {
+struct clk mck = {
        .name           = "mck",
        .pmc_mask       = AT91_PMC_MCKRDY,      /* in PMC_SR */
 };
@@ -215,43 +215,6 @@ static struct clk __init *at91_css_to_clk(unsigned long css)
        return NULL;
 }
 
-/*
- * Associate a particular clock with a function (eg, "uart") and device.
- * The drivers can then request the same 'function' with several different
- * devices and not care about which clock name to use.
- */
-void __init at91_clock_associate(const char *id, struct device *dev, const char *func)
-{
-       struct clk *clk = clk_get(NULL, id);
-
-       if (!dev || !clk || !IS_ERR(clk_get(dev, func)))
-               return;
-
-       clk->function = func;
-       clk->dev = dev;
-}
-
-/* clocks cannot be de-registered no refcounting necessary */
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       struct clk *clk;
-
-       list_for_each_entry(clk, &clocks, node) {
-               if (strcmp(id, clk->name) == 0)
-                       return clk;
-               if (clk->function && (dev == clk->dev) && strcmp(id, clk->function) == 0)
-                       return clk;
-       }
-
-       return ERR_PTR(-ENOENT);
-}
-EXPORT_SYMBOL(clk_get);
-
-void clk_put(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_put);
-
 static void __clk_enable(struct clk *clk)
 {
        if (clk->parent)
@@ -498,32 +461,38 @@ postcore_initcall(at91_clk_debugfs_init);
 /*------------------------------------------------------------------------*/
 
 /* Register a new clock */
+static void __init at91_clk_add(struct clk *clk)
+{
+       list_add_tail(&clk->node, &clocks);
+
+       clk->cl.con_id = clk->name;
+       clk->cl.clk = clk;
+       clkdev_add(&clk->cl);
+}
+
 int __init clk_register(struct clk *clk)
 {
        if (clk_is_peripheral(clk)) {
                if (!clk->parent)
                        clk->parent = &mck;
                clk->mode = pmc_periph_mode;
-               list_add_tail(&clk->node, &clocks);
        }
        else if (clk_is_sys(clk)) {
                clk->parent = &mck;
                clk->mode = pmc_sys_mode;
-
-               list_add_tail(&clk->node, &clocks);
        }
 #ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
        else if (clk_is_programmable(clk)) {
                clk->mode = pmc_sys_mode;
                init_programmable_clock(clk);
-               list_add_tail(&clk->node, &clocks);
        }
 #endif
 
+       at91_clk_add(clk);
+
        return 0;
 }
 
-
 /*------------------------------------------------------------------------*/
 
 static u32 __init at91_pll_rate(struct clk *pll, u32 freq, u32 reg)
@@ -630,7 +599,7 @@ static void __init at91_pllb_usbfs_clock_init(unsigned long main_clock)
                at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP);
        } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() ||
                   cpu_is_at91sam9263() || cpu_is_at91sam9g20() ||
-                  cpu_is_at91sam9g10() || cpu_is_at572d940hf()) {
+                  cpu_is_at91sam9g10()) {
                uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
                udpck.pmc_mask = AT91SAM926x_PMC_UDP;
        } else if (cpu_is_at91cap9()) {
@@ -754,19 +723,19 @@ int __init at91_clock_init(unsigned long main_clock)
 
        /* Register the PMC's standard clocks */
        for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++)
-               list_add_tail(&standard_pmc_clocks[i]->node, &clocks);
+               at91_clk_add(standard_pmc_clocks[i]);
 
        if (cpu_has_pllb())
-               list_add_tail(&pllb.node, &clocks);
+               at91_clk_add(&pllb);
 
        if (cpu_has_uhp())
-               list_add_tail(&uhpck.node, &clocks);
+               at91_clk_add(&uhpck);
 
        if (cpu_has_udpfs())
-               list_add_tail(&udpck.node, &clocks);
+               at91_clk_add(&udpck);
 
        if (cpu_has_utmi())
-               list_add_tail(&utmi_clk.node, &clocks);
+               at91_clk_add(&utmi_clk);
 
        /* MCK and CPU clock are "always on" */
        clk_enable(&mck);
index 6cf4b78e175d7a47775463d03f4f6c7146a2910e..c2e63e47dcbece02cf2c9ea296b52476b59ef938 100644 (file)
@@ -6,6 +6,8 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/clkdev.h>
+
 #define CLK_TYPE_PRIMARY       0x1
 #define CLK_TYPE_PLL           0x2
 #define CLK_TYPE_PROGRAMMABLE  0x4
@@ -16,8 +18,7 @@
 struct clk {
        struct list_head node;
        const char      *name;          /* unique clock name */
-       const char      *function;      /* function of the clock */
-       struct device   *dev;           /* device associated with function */
+       struct clk_lookup cl;
        unsigned long   rate_hz;
        struct clk      *parent;
        u32             pmc_mask;
@@ -29,3 +30,18 @@ struct clk {
 
 
 extern int __init clk_register(struct clk *clk);
+extern struct clk mck;
+extern struct clk utmi_clk;
+
+#define CLKDEV_CON_ID(_id, _clk)                       \
+       {                                               \
+               .con_id = _id,                          \
+               .clk = _clk,                            \
+       }
+
+#define CLKDEV_CON_DEV_ID(_con_id, _dev_id, _clk)      \
+       {                                               \
+               .con_id = _con_id,                      \
+               .dev_id = _dev_id,                      \
+               .clk = _clk,                            \
+       }
index 0c66deb2db39a990646d833da4c751e7fc28e81c..8ff3418f3430d91e8b5ab765e8beff54db127be9 100644 (file)
@@ -8,8 +8,21 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/clkdev.h>
+
+ /* Map io */
+extern void __init at91rm9200_map_io(void);
+extern void __init at91sam9260_map_io(void);
+extern void __init at91sam9261_map_io(void);
+extern void __init at91sam9263_map_io(void);
+extern void __init at91sam9rl_map_io(void);
+extern void __init at91sam9g45_map_io(void);
+extern void __init at91x40_map_io(void);
+extern void __init at91cap9_map_io(void);
+
  /* Processors */
-extern void __init at91rm9200_initialize(unsigned long main_clock, unsigned short banks);
+extern void __init at91rm9200_set_type(int type);
+extern void __init at91rm9200_initialize(unsigned long main_clock);
 extern void __init at91sam9260_initialize(unsigned long main_clock);
 extern void __init at91sam9261_initialize(unsigned long main_clock);
 extern void __init at91sam9263_initialize(unsigned long main_clock);
@@ -17,7 +30,6 @@ extern void __init at91sam9rl_initialize(unsigned long main_clock);
 extern void __init at91sam9g45_initialize(unsigned long main_clock);
 extern void __init at91x40_initialize(unsigned long main_clock);
 extern void __init at91cap9_initialize(unsigned long main_clock);
-extern void __init at572d940hf_initialize(unsigned long main_clock);
 
  /* Interrupts */
 extern void __init at91rm9200_init_interrupts(unsigned int priority[]);
@@ -28,7 +40,6 @@ extern void __init at91sam9rl_init_interrupts(unsigned int priority[]);
 extern void __init at91sam9g45_init_interrupts(unsigned int priority[]);
 extern void __init at91x40_init_interrupts(unsigned int priority[]);
 extern void __init at91cap9_init_interrupts(unsigned int priority[]);
-extern void __init at572d940hf_init_interrupts(unsigned int priority[]);
 extern void __init at91_aic_init(unsigned int priority[]);
 
  /* Timer */
@@ -39,8 +50,19 @@ extern struct sys_timer at91x40_timer;
 
  /* Clocks */
 extern int __init at91_clock_init(unsigned long main_clock);
+/*
+ * function to specify the clock of the default console. As we do not
+ * use the device/driver bus, the dev_name is not intialize. So we need
+ * to link the clock to a specific con_id only "usart"
+ */
+extern void __init at91rm9200_set_console_clock(int id);
+extern void __init at91sam9260_set_console_clock(int id);
+extern void __init at91sam9261_set_console_clock(int id);
+extern void __init at91sam9263_set_console_clock(int id);
+extern void __init at91sam9rl_set_console_clock(int id);
+extern void __init at91sam9g45_set_console_clock(int id);
+extern void __init at91cap9_set_console_clock(int id);
 struct device;
-extern void __init at91_clock_associate(const char *id, struct device *dev, const char *func);
 
  /* Power Management */
 extern void at91_irq_suspend(void);
diff --git a/arch/arm/mach-at91/include/mach/at572d940hf.h b/arch/arm/mach-at91/include/mach/at572d940hf.h
deleted file mode 100644 (file)
index be510cf..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * include/mach/at572d940hf.h
- *
- * Antonio R. Costa <costa.antonior@gmail.com>
- * Copyright (C) 2008 Atmel
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-#ifndef AT572D940HF_H
-#define AT572D940HF_H
-
-/*
- * Peripheral identifiers/interrupts.
- */
-#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
-#define AT91_ID_SYS            1       /* System Peripherals */
-#define AT572D940HF_ID_PIOA    2       /* Parallel IO Controller A */
-#define AT572D940HF_ID_PIOB    3       /* Parallel IO Controller B */
-#define AT572D940HF_ID_PIOC    4       /* Parallel IO Controller C */
-#define AT572D940HF_ID_EMAC    5       /* MACB ethernet controller */
-#define AT572D940HF_ID_US0     6       /* USART 0 */
-#define AT572D940HF_ID_US1     7       /* USART 1 */
-#define AT572D940HF_ID_US2     8       /* USART 2 */
-#define AT572D940HF_ID_MCI     9       /* Multimedia Card Interface */
-#define AT572D940HF_ID_UDP     10      /* USB Device Port */
-#define AT572D940HF_ID_TWI0    11      /* Two-Wire Interface 0 */
-#define AT572D940HF_ID_SPI0    12      /* Serial Peripheral Interface 0 */
-#define AT572D940HF_ID_SPI1    13      /* Serial Peripheral Interface 1 */
-#define AT572D940HF_ID_SSC0    14      /* Serial Synchronous Controller 0 */
-#define AT572D940HF_ID_SSC1    15      /* Serial Synchronous Controller 1 */
-#define AT572D940HF_ID_SSC2    16      /* Serial Synchronous Controller 2 */
-#define AT572D940HF_ID_TC0     17      /* Timer Counter 0 */
-#define AT572D940HF_ID_TC1     18      /* Timer Counter 1 */
-#define AT572D940HF_ID_TC2     19      /* Timer Counter 2 */
-#define AT572D940HF_ID_UHP     20      /* USB Host port */
-#define AT572D940HF_ID_SSC3    21      /* Serial Synchronous Controller 3 */
-#define AT572D940HF_ID_TWI1    22      /* Two-Wire Interface 1 */
-#define AT572D940HF_ID_CAN0    23      /* CAN Controller 0 */
-#define AT572D940HF_ID_CAN1    24      /* CAN Controller 1 */
-#define AT572D940HF_ID_MHALT   25      /* mAgicV HALT line */
-#define AT572D940HF_ID_MSIRQ0  26      /* mAgicV SIRQ0 line */
-#define AT572D940HF_ID_MEXC    27      /* mAgicV exception line */
-#define AT572D940HF_ID_MEDMA   28      /* mAgicV end of DMA line */
-#define AT572D940HF_ID_IRQ0    29      /* External Interrupt Source (IRQ0) */
-#define AT572D940HF_ID_IRQ1    30      /* External Interrupt Source (IRQ1) */
-#define AT572D940HF_ID_IRQ2    31      /* External Interrupt Source (IRQ2) */
-
-
-/*
- * User Peripheral physical base addresses.
- */
-#define AT572D940HF_BASE_TCB   0xfffa0000
-#define AT572D940HF_BASE_TC0   0xfffa0000
-#define AT572D940HF_BASE_TC1   0xfffa0040
-#define AT572D940HF_BASE_TC2   0xfffa0080
-#define AT572D940HF_BASE_UDP   0xfffa4000
-#define AT572D940HF_BASE_MCI   0xfffa8000
-#define AT572D940HF_BASE_TWI0  0xfffac000
-#define AT572D940HF_BASE_US0   0xfffb0000
-#define AT572D940HF_BASE_US1   0xfffb4000
-#define AT572D940HF_BASE_US2   0xfffb8000
-#define AT572D940HF_BASE_SSC0  0xfffbc000
-#define AT572D940HF_BASE_SSC1  0xfffc0000
-#define AT572D940HF_BASE_SSC2  0xfffc4000
-#define AT572D940HF_BASE_SPI0  0xfffc8000
-#define AT572D940HF_BASE_SPI1  0xfffcc000
-#define AT572D940HF_BASE_SSC3  0xfffd0000
-#define AT572D940HF_BASE_TWI1  0xfffd4000
-#define AT572D940HF_BASE_EMAC  0xfffd8000
-#define AT572D940HF_BASE_CAN0  0xfffdc000
-#define AT572D940HF_BASE_CAN1  0xfffe0000
-#define AT91_BASE_SYS          0xffffea00
-
-
-/*
- * System Peripherals (offset from AT91_BASE_SYS)
- */
-#define AT91_SDRAMC0   (0xffffea00 - AT91_BASE_SYS)
-#define AT91_SMC       (0xffffec00 - AT91_BASE_SYS)
-#define AT91_MATRIX    (0xffffee00 - AT91_BASE_SYS)
-#define AT91_AIC       (0xfffff000 - AT91_BASE_SYS)
-#define AT91_DBGU      (0xfffff200 - AT91_BASE_SYS)
-#define AT91_PIOA      (0xfffff400 - AT91_BASE_SYS)
-#define AT91_PIOB      (0xfffff600 - AT91_BASE_SYS)
-#define AT91_PIOC      (0xfffff800 - AT91_BASE_SYS)
-#define AT91_PMC       (0xfffffc00 - AT91_BASE_SYS)
-#define AT91_RSTC      (0xfffffd00 - AT91_BASE_SYS)
-#define AT91_RTT       (0xfffffd20 - AT91_BASE_SYS)
-#define AT91_PIT       (0xfffffd30 - AT91_BASE_SYS)
-#define AT91_WDT       (0xfffffd40 - AT91_BASE_SYS)
-
-#define AT91_USART0    AT572D940HF_ID_US0
-#define AT91_USART1    AT572D940HF_ID_US1
-#define AT91_USART2    AT572D940HF_ID_US2
-
-
-/*
- * Internal Memory.
- */
-#define AT572D940HF_SRAM_BASE  0x00300000      /* Internal SRAM base address */
-#define AT572D940HF_SRAM_SIZE  (48 * SZ_1K)    /* Internal SRAM size (48Kb) */
-
-#define AT572D940HF_ROM_BASE   0x00400000      /* Internal ROM base address */
-#define AT572D940HF_ROM_SIZE   SZ_32K          /* Internal ROM size (32Kb) */
-
-#define AT572D940HF_UHP_BASE   0x00500000      /* USB Host controller */
-
-
-#endif
diff --git a/arch/arm/mach-at91/include/mach/at572d940hf_matrix.h b/arch/arm/mach-at91/include/mach/at572d940hf_matrix.h
deleted file mode 100644 (file)
index b6751df..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * include/mach//at572d940hf_matrix.h
- *
- * Antonio R. Costa <costa.antonior@gmail.com>
- * Copyright (C) 2008 Atmel
- *
- * Copyright (C) 2005 SAN People
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#ifndef AT572D940HF_MATRIX_H
-#define AT572D940HF_MATRIX_H
-
-#define AT91_MATRIX_MCFG0      (AT91_MATRIX + 0x00)    /* Master Configuration Register 0 */
-#define AT91_MATRIX_MCFG1      (AT91_MATRIX + 0x04)    /* Master Configuration Register 1 */
-#define AT91_MATRIX_MCFG2      (AT91_MATRIX + 0x08)    /* Master Configuration Register 2 */
-#define AT91_MATRIX_MCFG3      (AT91_MATRIX + 0x0C)    /* Master Configuration Register 3 */
-#define AT91_MATRIX_MCFG4      (AT91_MATRIX + 0x10)    /* Master Configuration Register 4 */
-#define AT91_MATRIX_MCFG5      (AT91_MATRIX + 0x14)    /* Master Configuration Register 5 */
-
-#define                AT91_MATRIX_ULBT        (7 << 0)        /* Undefined Length Burst Type */
-#define                        AT91_MATRIX_ULBT_INFINITE       (0 << 0)
-#define                        AT91_MATRIX_ULBT_SINGLE         (1 << 0)
-#define                        AT91_MATRIX_ULBT_FOUR           (2 << 0)
-#define                        AT91_MATRIX_ULBT_EIGHT          (3 << 0)
-#define                        AT91_MATRIX_ULBT_SIXTEEN        (4 << 0)
-
-#define AT91_MATRIX_SCFG0      (AT91_MATRIX + 0x40)    /* Slave Configuration Register 0 */
-#define AT91_MATRIX_SCFG1      (AT91_MATRIX + 0x44)    /* Slave Configuration Register 1 */
-#define AT91_MATRIX_SCFG2      (AT91_MATRIX + 0x48)    /* Slave Configuration Register 2 */
-#define AT91_MATRIX_SCFG3      (AT91_MATRIX + 0x4C)    /* Slave Configuration Register 3 */
-#define AT91_MATRIX_SCFG4      (AT91_MATRIX + 0x50)    /* Slave Configuration Register 4 */
-#define                AT91_MATRIX_SLOT_CYCLE          (0xff << 0)     /* Maximum Number of Allowed Cycles for a Burst */
-#define                AT91_MATRIX_DEFMSTR_TYPE        (3    << 16)    /* Default Master Type */
-#define                        AT91_MATRIX_DEFMSTR_TYPE_NONE   (0 << 16)
-#define                        AT91_MATRIX_DEFMSTR_TYPE_LAST   (1 << 16)
-#define                        AT91_MATRIX_DEFMSTR_TYPE_FIXED  (2 << 16)
-#define                AT91_MATRIX_FIXED_DEFMSTR       (0x7  << 18)    /* Fixed Index of Default Master */
-#define                AT91_MATRIX_ARBT                (3    << 24)    /* Arbitration Type */
-#define                        AT91_MATRIX_ARBT_ROUND_ROBIN    (0 << 24)
-#define                        AT91_MATRIX_ARBT_FIXED_PRIORITY (1 << 24)
-
-#define AT91_MATRIX_PRAS0      (AT91_MATRIX + 0x80)    /* Priority Register A for Slave 0 */
-#define AT91_MATRIX_PRAS1      (AT91_MATRIX + 0x88)    /* Priority Register A for Slave 1 */
-#define AT91_MATRIX_PRAS2      (AT91_MATRIX + 0x90)    /* Priority Register A for Slave 2 */
-#define AT91_MATRIX_PRAS3      (AT91_MATRIX + 0x98)    /* Priority Register A for Slave 3 */
-#define AT91_MATRIX_PRAS4      (AT91_MATRIX + 0xA0)    /* Priority Register A for Slave 4 */
-
-#define                AT91_MATRIX_M0PR                (3 << 0)        /* Master 0 Priority */
-#define                AT91_MATRIX_M1PR                (3 << 4)        /* Master 1 Priority */
-#define                AT91_MATRIX_M2PR                (3 << 8)        /* Master 2 Priority */
-#define                AT91_MATRIX_M3PR                (3 << 12)       /* Master 3 Priority */
-#define                AT91_MATRIX_M4PR                (3 << 16)       /* Master 4 Priority */
-#define                AT91_MATRIX_M5PR                (3 << 20)       /* Master 5 Priority */
-#define                AT91_MATRIX_M6PR                (3 << 24)       /* Master 6 Priority */
-
-#define AT91_MATRIX_MRCR       (AT91_MATRIX + 0x100)   /* Master Remap Control Register */
-#define                AT91_MATRIX_RCB0                (1 << 0)        /* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
-#define                AT91_MATRIX_RCB1                (1 << 1)        /* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
-
-#define AT91_MATRIX_SFR0       (AT91_MATRIX + 0x110)   /* Special Function Register 0 */
-#define AT91_MATRIX_SFR1       (AT91_MATRIX + 0x114)   /* Special Function Register 1 */
-#define AT91_MATRIX_SFR2       (AT91_MATRIX + 0x118)   /* Special Function Register 2 */
-#define AT91_MATRIX_SFR3       (AT91_MATRIX + 0x11C)   /* Special Function Register 3 */
-#define AT91_MATRIX_SFR4       (AT91_MATRIX + 0x120)   /* Special Function Register 4 */
-#define AT91_MATRIX_SFR5       (AT91_MATRIX + 0x124)   /* Special Function Register 5 */
-#define AT91_MATRIX_SFR6       (AT91_MATRIX + 0x128)   /* Special Function Register 6 */
-#define AT91_MATRIX_SFR7       (AT91_MATRIX + 0x12C)   /* Special Function Register 7 */
-#define AT91_MATRIX_SFR8       (AT91_MATRIX + 0x130)   /* Special Function Register 8 */
-#define AT91_MATRIX_SFR9       (AT91_MATRIX + 0x134)   /* Special Function Register 9 */
-#define AT91_MATRIX_SFR10      (AT91_MATRIX + 0x138)   /* Special Function Register 10 */
-#define AT91_MATRIX_SFR11      (AT91_MATRIX + 0x13C)   /* Special Function Register 11 */
-#define AT91_MATRIX_SFR12      (AT91_MATRIX + 0x140)   /* Special Function Register 12 */
-#define AT91_MATRIX_SFR13      (AT91_MATRIX + 0x144)   /* Special Function Register 13 */
-#define AT91_MATRIX_SFR14      (AT91_MATRIX + 0x148)   /* Special Function Register 14 */
-#define AT91_MATRIX_SFR15      (AT91_MATRIX + 0x14C)   /* Special Function Register 15 */
-
-
-/*
- * The following registers / bits are not defined in the Datasheet (Revision A)
- */
-
-#define AT91_MATRIX_TCR                (AT91_MATRIX + 0x100)   /* TCM Configuration Register */
-#define                AT91_MATRIX_ITCM_SIZE           (0xf << 0)      /* Size of ITCM enabled memory block */
-#define                        AT91_MATRIX_ITCM_0              (0 << 0)
-#define                        AT91_MATRIX_ITCM_16             (5 << 0)
-#define                        AT91_MATRIX_ITCM_32             (6 << 0)
-#define                        AT91_MATRIX_ITCM_64             (7 << 0)
-#define                AT91_MATRIX_DTCM_SIZE           (0xf << 4)      /* Size of DTCM enabled memory block */
-#define                        AT91_MATRIX_DTCM_0              (0 << 4)
-#define                        AT91_MATRIX_DTCM_16             (5 << 4)
-#define                        AT91_MATRIX_DTCM_32             (6 << 4)
-#define                        AT91_MATRIX_DTCM_64             (7 << 4)
-
-#define AT91_MATRIX_EBICSA     (AT91_MATRIX + 0x11C)   /* EBI Chip Select Assignment Register */
-#define                AT91_MATRIX_CS1A                (1 << 1)        /* Chip Select 1 Assignment */
-#define                        AT91_MATRIX_CS1A_SMC            (0 << 1)
-#define                        AT91_MATRIX_CS1A_SDRAMC         (1 << 1)
-#define                AT91_MATRIX_CS3A                (1 << 3)        /* Chip Select 3 Assignment */
-#define                        AT91_MATRIX_CS3A_SMC            (0 << 3)
-#define                        AT91_MATRIX_CS3A_SMC_SMARTMEDIA (1 << 3)
-#define                AT91_MATRIX_CS4A                (1 << 4)        /* Chip Select 4 Assignment */
-#define                        AT91_MATRIX_CS4A_SMC            (0 << 4)
-#define                        AT91_MATRIX_CS4A_SMC_CF1        (1 << 4)
-#define                AT91_MATRIX_CS5A                (1 << 5)        /* Chip Select 5 Assignment */
-#define                        AT91_MATRIX_CS5A_SMC            (0 << 5)
-#define                        AT91_MATRIX_CS5A_SMC_CF2        (1 << 5)
-#define                AT91_MATRIX_DBPUC               (1 << 8)        /* Data Bus Pull-up Configuration */
-
-#endif
index 9c6af97374851a72d2481a0fc4b03ba64781eff8..665993849a7b99f44fc97a8d06578b0578971ecc 100644 (file)
@@ -20,8 +20,6 @@
 /*
  * Peripheral identifiers/interrupts.
  */
-#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
-#define AT91_ID_SYS            1       /* System Peripherals */
 #define AT91CAP9_ID_PIOABCD    2       /* Parallel IO Controller A, B, C and D */
 #define AT91CAP9_ID_MPB0       3       /* MP Block Peripheral 0 */
 #define AT91CAP9_ID_MPB1       4       /* MP Block Peripheral 1 */
 #define AT91CAP9_UDPHS_FIFO    0x00600000      /* USB High Speed Device Port */
 #define AT91CAP9_UHP_BASE      0x00700000      /* USB Host controller */
 
-#define CONFIG_DRAM_BASE       AT91_CHIPSELECT_6
-
 #endif
index 78983155a074c74b18873deaa3d736b65f4a831e..99e0f8d02d7bc492727def41a71dfbe8e11e2536 100644 (file)
@@ -19,8 +19,6 @@
 /*
  * Peripheral identifiers/interrupts.
  */
-#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
-#define AT91_ID_SYS            1       /* System Peripheral */
 #define AT91RM9200_ID_PIOA     2       /* Parallel IO Controller A */
 #define AT91RM9200_ID_PIOB     3       /* Parallel IO Controller B */
 #define AT91RM9200_ID_PIOC     4       /* Parallel IO Controller C */
index 4e79036d3b801849ea8f547e6dd6fdf8b16d894e..8b6bf835cd733cf88ebc9fab564381d125b2a40a 100644 (file)
@@ -20,8 +20,6 @@
 /*
  * Peripheral identifiers/interrupts.
  */
-#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
-#define AT91_ID_SYS            1       /* System Peripherals */
 #define AT91SAM9260_ID_PIOA    2       /* Parallel IO Controller A */
 #define AT91SAM9260_ID_PIOB    3       /* Parallel IO Controller B */
 #define AT91SAM9260_ID_PIOC    4       /* Parallel IO Controller C */
index 2b561851812952fe60e8b44fa1d44641fcdd81bc..eafbddaf523c9e702d2316f66b62bd07e01f2df6 100644 (file)
@@ -18,8 +18,6 @@
 /*
  * Peripheral identifiers/interrupts.
  */
-#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
-#define AT91_ID_SYS            1       /* System Peripherals */
 #define AT91SAM9261_ID_PIOA    2       /* Parallel IO Controller A */
 #define AT91SAM9261_ID_PIOB    3       /* Parallel IO Controller B */
 #define AT91SAM9261_ID_PIOC    4       /* Parallel IO Controller C */
index 2091f1e42d43c32931f7f6b327f4a056a8f54bbf..e2d348213a7be7ca8796aa3dff77efda48e56f06 100644 (file)
@@ -18,8 +18,6 @@
 /*
  * Peripheral identifiers/interrupts.
  */
-#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
-#define AT91_ID_SYS            1       /* System Peripherals */
 #define AT91SAM9263_ID_PIOA    2       /* Parallel IO Controller A */
 #define AT91SAM9263_ID_PIOB    3       /* Parallel IO Controller B */
 #define AT91SAM9263_ID_PIOCDE  4       /* Parallel IO Controller C, D and E */
index a526869aee377a198d439d639091b3856f705f50..659304aa73d939176d6197acd548e50370e0e821 100644 (file)
@@ -18,8 +18,6 @@
 /*
  * Peripheral identifiers/interrupts.
  */
-#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
-#define AT91_ID_SYS            1       /* System Controller Interrupt */
 #define AT91SAM9G45_ID_PIOA    2       /* Parallel I/O Controller A */
 #define AT91SAM9G45_ID_PIOB    3       /* Parallel I/O Controller B */
 #define AT91SAM9G45_ID_PIOC    4       /* Parallel I/O Controller C */
 #define AT91SAM9G45_EHCI_BASE  0x00800000      /* USB Host controller (EHCI) */
 #define AT91SAM9G45_VDEC_BASE  0x00900000      /* Video Decoder Controller */
 
-#define CONFIG_DRAM_BASE       AT91_CHIPSELECT_6
-
 #define CONSISTENT_DMA_SIZE    SZ_4M
 
 /*
index 87ba8517ad98291a12749853cfc7379e021c4997..41dbbe61055c5c5ad50d1d66c1e7e0f08805af5c 100644 (file)
@@ -17,8 +17,6 @@
 /*
  * Peripheral identifiers/interrupts.
  */
-#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
-#define AT91_ID_SYS            1       /* System Controller */
 #define AT91SAM9RL_ID_PIOA     2       /* Parallel IO Controller A */
 #define AT91SAM9RL_ID_PIOB     3       /* Parallel IO Controller B */
 #define AT91SAM9RL_ID_PIOC     4       /* Parallel IO Controller C */
index 063ac44a020423119b52749dc3c866b6dd7eb965..a152ff87e688ea48792be4733643b1b9fb2c5c89 100644 (file)
@@ -15,8 +15,6 @@
 /*
  *     IRQ list.
  */
-#define AT91_ID_FIQ            0       /* FIQ */
-#define AT91_ID_SYS            1       /* System Peripheral */
 #define AT91X40_ID_USART0      2       /* USART port 0 */
 #define AT91X40_ID_USART1      3       /* USART port 1 */
 #define AT91X40_ID_TC0         4       /* Timer/Counter 0 */
index 2b499eb343a12a082ad5d0a862c0fb3fb9e722a5..ed544a0d5a1d8b5ce5bc4681ed7e83ef704ab41d 100644 (file)
@@ -90,7 +90,7 @@ struct at91_eth_data {
 extern void __init at91_add_device_eth(struct at91_eth_data *data);
 
 #if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91SAM9G20) || defined(CONFIG_ARCH_AT91CAP9) \
-       || defined(CONFIG_ARCH_AT91SAM9G45) || defined(CONFIG_ARCH_AT572D940HF)
+       || defined(CONFIG_ARCH_AT91SAM9G45)
 #define eth_platform_data      at91_eth_data
 #endif
 
@@ -140,6 +140,7 @@ extern void __init at91_set_serial_console(unsigned portnr);
 extern struct platform_device *atmel_default_console_device;
 
 struct atmel_uart_data {
+       int                     num;            /* port num */
        short                   use_dma_tx;     /* use transmit DMA? */
        short                   use_dma_rx;     /* use receive DMA? */
        void __iomem            *regs;          /* virt. base address, if any */
@@ -203,9 +204,6 @@ extern void __init at91_init_leds(u8 cpu_led, u8 timer_led);
 extern void __init at91_gpio_leds(struct gpio_led *leds, int nr);
 extern void __init at91_pwm_leds(struct gpio_led *leds, int nr);
 
- /* AT572D940HF DSP */
-extern void __init at91_add_device_mAgic(void);
-
 /* FIXME: this needs a better location, but gets stuff building again */
 extern int at91_suspend_entering_slow_clock(void);
 
diff --git a/arch/arm/mach-at91/include/mach/clkdev.h b/arch/arm/mach-at91/include/mach/clkdev.h
new file mode 100644 (file)
index 0000000..04b37a8
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASM_MACH_CLKDEV_H
+#define __ASM_MACH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
index 0700f2125305d99fd769f46726fe1e09afaa3dcc..df966c2bc2d448e032333ac566a5a2adbe3ee034 100644 (file)
@@ -34,8 +34,6 @@
 #define ARCH_ID_AT91SAM9XE256  0x329a93a0
 #define ARCH_ID_AT91SAM9XE512  0x329aa3a0
 
-#define ARCH_ID_AT572D940HF    0x0e0303e0
-
 #define ARCH_ID_AT91M40800     0x14080044
 #define ARCH_ID_AT91R40807     0x44080746
 #define ARCH_ID_AT91M40807     0x14080745
@@ -90,9 +88,16 @@ static inline unsigned long at91cap9_rev_identify(void)
 #endif
 
 #ifdef CONFIG_ARCH_AT91RM9200
+extern int rm9200_type;
+#define ARCH_REVISON_9200_BGA  (0 << 0)
+#define ARCH_REVISON_9200_PQFP (1 << 0)
 #define cpu_is_at91rm9200()    (at91_cpu_identify() == ARCH_ID_AT91RM9200)
+#define cpu_is_at91rm9200_bga()        (!cpu_is_at91rm9200_pqfp())
+#define cpu_is_at91rm9200_pqfp() (cpu_is_at91rm9200() && rm9200_type & ARCH_REVISON_9200_PQFP)
 #else
 #define cpu_is_at91rm9200()    (0)
+#define cpu_is_at91rm9200_bga()        (0)
+#define cpu_is_at91rm9200_pqfp() (0)
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9260
@@ -181,12 +186,6 @@ static inline unsigned long at91cap9_rev_identify(void)
 #define cpu_is_at91cap9_revC() (0)
 #endif
 
-#ifdef CONFIG_ARCH_AT572D940HF
-#define cpu_is_at572d940hf() (at91_cpu_identify() == ARCH_ID_AT572D940HF)
-#else
-#define cpu_is_at572d940hf() (0)
-#endif
-
 /*
  * Since this is ARM, we will never run on any AVR32 CPU. But these
  * definitions may reduce clutter in common drivers.
index 3d64a75e3ed5be8a0566b343653b3af965a47c6f..1008b9fb50741ecf77a979ff2fc239f78f781632 100644 (file)
 #include <mach/at91cap9.h>
 #elif defined(CONFIG_ARCH_AT91X40)
 #include <mach/at91x40.h>
-#elif defined(CONFIG_ARCH_AT572D940HF)
-#include <mach/at572d940hf.h>
 #else
 #error "Unsupported AT91 processor"
 #endif
 
 
+/*
+ * Peripheral identifiers/interrupts.
+ */
+#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
+#define AT91_ID_SYS            1       /* System Peripherals */
+
 #ifdef CONFIG_MMU
 /*
  * Remap the peripherals from address 0xFFF78000 .. 0xFFFFFFFF
 #define AT91_CHIPSELECT_6      0x70000000
 #define AT91_CHIPSELECT_7      0x80000000
 
-/* SDRAM */
-#ifdef CONFIG_DRAM_BASE
-#define AT91_SDRAM_BASE                CONFIG_DRAM_BASE
-#else
-#define AT91_SDRAM_BASE                AT91_CHIPSELECT_1
-#endif
-
 /* Clocks */
 #define AT91_SLOW_CLOCK                32768           /* slow clock */
 
index c2cfe5040642982891cfc6a0ea2d684ab33dd037..401c207f2f39c8e3af445183794d70e14c518e49 100644 (file)
@@ -23,6 +23,4 @@
 
 #include <mach/hardware.h>
 
-#define PLAT_PHYS_OFFSET       (AT91_SDRAM_BASE)
-
 #endif
index 6120f9c46d59aad836994464989a5aaa9ce2efc4..f62c0abca4b4fffa60a1c7fe25454f37b32795ec 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __MACH_STAMP9G20_H
 #define __MACH_STAMP9G20_H
 
-void stamp9g20_map_io(void);
+void stamp9g20_init_early(void);
 void stamp9g20_board_init(void);
 
 #endif
diff --git a/arch/arm/mach-at91/include/mach/system_rev.h b/arch/arm/mach-at91/include/mach/system_rev.h
new file mode 100644 (file)
index 0000000..b855ee7
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2 only
+ */
+
+#ifndef __ARCH_SYSTEM_REV_H__
+#define __ARCH_SYSTEM_REV_H__
+
+/*
+ * board revision encoding
+ * mach specific
+ * the 16-31 bit are reserved for at91 generic information
+ *
+ * bit 31:
+ *     0 => nand 16 bit
+ *     1 => nand 8 bit
+ */
+#define BOARD_HAVE_NAND_8BIT   (1 << 31)
+static int inline board_have_nand_8bit(void)
+{
+       return system_rev & BOARD_HAVE_NAND_8BIT;
+}
+
+#endif /* __ARCH_SYSTEM_REV_H__ */
index 05a6e8af80c4e1f3c4b4983c88821c1e1bd0ad26..31ac2d97f14cb24b85371b259a2c70b27fc6a461 100644 (file)
 #define AT91X40_MASTER_CLOCK   40000000
 #define CLOCK_TICK_RATE                (AT91X40_MASTER_CLOCK)
 
-#elif defined(CONFIG_ARCH_AT572D940HF)
-
-#define AT572D940HF_MASTER_CLOCK       80000000
-#define CLOCK_TICK_RATE                (AT572D940HF_MASTER_CLOCK/16)
-
 #endif
 
 #endif
index b95b9196deed9edc99605cdf6768a761f94dd967..133aac40585374299ef9d55f651dd8f85fcf4e71 100644 (file)
@@ -1055,7 +1055,7 @@ int da850_register_pm(struct platform_device *pdev)
        if (!pdata->cpupll_reg_base)
                return -ENOMEM;
 
-       pdata->ddrpll_reg_base = ioremap(DA8XX_PLL1_BASE, SZ_4K);
+       pdata->ddrpll_reg_base = ioremap(DA850_PLL1_BASE, SZ_4K);
        if (!pdata->ddrpll_reg_base) {
                ret = -ENOMEM;
                goto no_ddrpll_mem;
index 58a02dc7b15a5b76f8deb2f540e55f030d484d55..fc4e98ea7543a397e4ece003b3ff9f9d498fd42f 100644 (file)
 #include "clock.h"
 
 #define DA8XX_TPCC_BASE                        0x01c00000
-#define DA850_MMCSD1_BASE              0x01e1b000
-#define DA850_TPCC1_BASE               0x01e30000
 #define DA8XX_TPTC0_BASE               0x01c08000
 #define DA8XX_TPTC1_BASE               0x01c08400
-#define DA850_TPTC2_BASE               0x01e38000
 #define DA8XX_WDOG_BASE                        0x01c21000 /* DA8XX_TIMER64P1_BASE */
 #define DA8XX_I2C0_BASE                        0x01c22000
-#define DA8XX_RTC_BASE                 0x01C23000
+#define DA8XX_RTC_BASE                 0x01c23000
+#define DA8XX_MMCSD0_BASE              0x01c40000
+#define DA8XX_SPI0_BASE                        0x01c41000
+#define DA830_SPI1_BASE                        0x01e12000
+#define DA8XX_LCD_CNTRL_BASE           0x01e13000
+#define DA850_MMCSD1_BASE              0x01e1b000
 #define DA8XX_EMAC_CPPI_PORT_BASE      0x01e20000
 #define DA8XX_EMAC_CPGMACSS_BASE       0x01e22000
 #define DA8XX_EMAC_CPGMAC_BASE         0x01e23000
 #define DA8XX_EMAC_MDIO_BASE           0x01e24000
-#define DA8XX_GPIO_BASE                        0x01e26000
 #define DA8XX_I2C1_BASE                        0x01e28000
-#define DA8XX_SPI0_BASE                        0x01c41000
-#define DA830_SPI1_BASE                        0x01e12000
+#define DA850_TPCC1_BASE               0x01e30000
+#define DA850_TPTC2_BASE               0x01e38000
 #define DA850_SPI1_BASE                        0x01f0e000
+#define DA8XX_DDR2_CTL_BASE            0xb0000000
 
 #define DA8XX_EMAC_CTRL_REG_OFFSET     0x3000
 #define DA8XX_EMAC_MOD_REG_OFFSET      0x2000
@@ -492,7 +494,7 @@ static struct platform_device da850_mcasp_device = {
        .resource       = da850_mcasp_resources,
 };
 
-struct platform_device davinci_pcm_device = {
+static struct platform_device davinci_pcm_device = {
        .name   = "davinci-pcm-audio",
        .id     = -1,
 };
index 22ebc64bc9d99a5bd71a52f801f3903a6f5b04d9..806a2f02b9808abf870ac9b9b0e1c77d99e60bb4 100644 (file)
@@ -33,6 +33,9 @@
 #define DM365_MMCSD0_BASE           0x01D11000
 #define DM365_MMCSD1_BASE           0x01D00000
 
+/* System control register offsets */
+#define DM64XX_VDD3P3V_PWDN    0x48
+
 static struct resource i2c_resources[] = {
        {
                .start          = DAVINCI_I2C_BASE,
@@ -295,7 +298,7 @@ static void davinci_init_wdt(void)
 
 /*-------------------------------------------------------------------------*/
 
-struct platform_device davinci_pcm_device = {
+static struct platform_device davinci_pcm_device = {
        .name           = "davinci-pcm-audio",
        .id             = -1,
 };
index a0b838894ac99b27daaf413fbfbd8f78ae842066..e7221398e5af9c751d1dc8f85c1d294b2afb0f9b 100644 (file)
@@ -252,9 +252,11 @@ static struct irq_chip gpio_irqchip = {
 static void
 gpio_irq_handler(unsigned irq, struct irq_desc *desc)
 {
-       struct davinci_gpio_regs __iomem *g = irq2regs(irq);
+       struct davinci_gpio_regs __iomem *g;
        u32 mask = 0xffff;
 
+       g = (__force struct davinci_gpio_regs __iomem *) irq_desc_get_handler_data(desc);
+
        /* we only care about one bank */
        if (irq & 1)
                mask <<= 16;
@@ -422,8 +424,7 @@ static int __init davinci_gpio_irq_setup(void)
 
                /* set up all irqs in this bank */
                irq_set_chained_handler(bank_irq, gpio_irq_handler);
-               irq_set_chip_data(bank_irq, (__force void *)g);
-               irq_set_handler_data(bank_irq, (void *)irq);
+               irq_set_handler_data(bank_irq, (__force void *)g);
 
                for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) {
                        irq_set_chip(irq, &gpio_irqchip);
index e4fc1af8500e7ca78d08fd13f7482b0247d114d6..ad64da713fc83fdec2006a9aa78cb56c0561409a 100644 (file)
@@ -64,13 +64,9 @@ extern unsigned int da850_max_speed;
 #define DA8XX_TIMER64P1_BASE   0x01c21000
 #define DA8XX_GPIO_BASE                0x01e26000
 #define DA8XX_PSC1_BASE                0x01e27000
-#define DA8XX_LCD_CNTRL_BASE   0x01e13000
-#define DA8XX_PLL1_BASE                0x01e1a000
-#define DA8XX_MMCSD0_BASE      0x01c40000
 #define DA8XX_AEMIF_CS2_BASE   0x60000000
 #define DA8XX_AEMIF_CS3_BASE   0x62000000
 #define DA8XX_AEMIF_CTL_BASE   0x68000000
-#define DA8XX_DDR2_CTL_BASE    0xb0000000
 #define DA8XX_ARM_RAM_BASE     0xffff0000
 
 void __init da830_init(void);
index c45ba1f62a11a3b32d70b44e291a1f0bc8b98764..414e0b93e741f5a8bd1ce8c76b88ebf5ca8a6bcd 100644 (file)
@@ -21,9 +21,6 @@
  */
 #define DAVINCI_SYSTEM_MODULE_BASE        0x01C40000
 
-/* System control register offsets */
-#define DM64XX_VDD3P3V_PWDN    0x48
-
 /*
  * I/O mapping
  */
index 82079545adc4e8b788e98509cc8e77c7a5e95508..1d4b65fd673eb23e9d2ac2fd9dbded0f2e8ba6d9 100644 (file)
@@ -402,11 +402,15 @@ static struct resource ep93xx_eth_resource[] = {
        }
 };
 
+static u64 ep93xx_eth_dma_mask = DMA_BIT_MASK(32);
+
 static struct platform_device ep93xx_eth_device = {
        .name           = "ep93xx-eth",
        .id             = -1,
        .dev            = {
-               .platform_data  = &ep93xx_eth_data,
+               .platform_data          = &ep93xx_eth_data,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .dma_mask               = &ep93xx_eth_dma_mask,
        },
        .num_resources  = ARRAY_SIZE(ep93xx_eth_resource),
        .resource       = ep93xx_eth_resource,
index 805196207ce8745196461acefdc37b5d90fb64d4..1435fc31c4b29e55e2209050f0f51eab21fbb390 100644 (file)
@@ -91,6 +91,11 @@ config EXYNOS4_SETUP_FIMC
        help
          Common setup code for the camera interfaces.
 
+config EXYNOS4_SETUP_USB_PHY
+       bool
+       help
+         Common setup code for USB PHY controller
+
 # machine support
 
 menu "EXYNOS4 Machines"
@@ -169,11 +174,14 @@ config MACH_NURI
        select S3C_DEV_HSMMC2
        select S3C_DEV_HSMMC3
        select S3C_DEV_I2C1
+       select S3C_DEV_I2C3
        select S3C_DEV_I2C5
        select S5P_DEV_USB_EHCI
        select EXYNOS4_SETUP_I2C1
+       select EXYNOS4_SETUP_I2C3
        select EXYNOS4_SETUP_I2C5
        select EXYNOS4_SETUP_SDHCI
+       select EXYNOS4_SETUP_USB_PHY
        select SAMSUNG_DEV_PWM
        help
          Machine support for Samsung Mobile NURI Board.
index 777897551e428bc258c599ee1415841e35dff564..60fe5ecf359963ec365abb7f06b4a160b65cd2cb 100644 (file)
@@ -13,9 +13,10 @@ obj-                         :=
 # Core support for EXYNOS4 system
 
 obj-$(CONFIG_CPU_EXYNOS4210)   += cpu.o init.o clock.o irq-combiner.o
-obj-$(CONFIG_CPU_EXYNOS4210)   += setup-i2c0.o gpiolib.o irq-eint.o dma.o
+obj-$(CONFIG_CPU_EXYNOS4210)   += setup-i2c0.o irq-eint.o dma.o
 obj-$(CONFIG_PM)               += pm.o sleep.o
 obj-$(CONFIG_CPU_FREQ)         += cpufreq.o
+obj-$(CONFIG_CPU_IDLE)         += cpuidle.o
 
 obj-$(CONFIG_SMP)              += platsmp.o headsmp.o
 
@@ -55,4 +56,4 @@ obj-$(CONFIG_EXYNOS4_SETUP_KEYPAD)    += setup-keypad.o
 obj-$(CONFIG_EXYNOS4_SETUP_SDHCI)      += setup-sdhci.o
 obj-$(CONFIG_EXYNOS4_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
 
-obj-$(CONFIG_USB_SUPPORT)              += usb-phy.o
+obj-$(CONFIG_EXYNOS4_SETUP_USB_PHY)    += setup-usb-phy.o
index 08813a6f66b13f9df62f570524f3de592c19a022..9babe4473e8893614e2cddef1ebfd1855f9e94c2 100644 (file)
@@ -98,7 +98,7 @@ static struct map_desc exynos4_iodesc[] __initdata = {
                .length         = SZ_4K,
                .type           = MT_DEVICE,
        }, {
-               .virtual        = (unsigned long)S5P_VA_USB_HSPHY,
+               .virtual        = (unsigned long)S3C_VA_USB_HSPHY,
                .pfn            = __phys_to_pfn(EXYNOS4_PA_HSPHY),
                .length         = SZ_4K,
                .type           = MT_DEVICE,
diff --git a/arch/arm/mach-exynos4/cpuidle.c b/arch/arm/mach-exynos4/cpuidle.c
new file mode 100644 (file)
index 0000000..bf7e96f
--- /dev/null
@@ -0,0 +1,86 @@
+/* linux/arch/arm/mach-exynos4/cpuidle.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cpuidle.h>
+#include <linux/io.h>
+
+#include <asm/proc-fns.h>
+
+static int exynos4_enter_idle(struct cpuidle_device *dev,
+                             struct cpuidle_state *state);
+
+static struct cpuidle_state exynos4_cpuidle_set[] = {
+       [0] = {
+               .enter                  = exynos4_enter_idle,
+               .exit_latency           = 1,
+               .target_residency       = 100000,
+               .flags                  = CPUIDLE_FLAG_TIME_VALID,
+               .name                   = "IDLE",
+               .desc                   = "ARM clock gating(WFI)",
+       },
+};
+
+static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device);
+
+static struct cpuidle_driver exynos4_idle_driver = {
+       .name           = "exynos4_idle",
+       .owner          = THIS_MODULE,
+};
+
+static int exynos4_enter_idle(struct cpuidle_device *dev,
+                             struct cpuidle_state *state)
+{
+       struct timeval before, after;
+       int idle_time;
+
+       local_irq_disable();
+       do_gettimeofday(&before);
+
+       cpu_do_idle();
+
+       do_gettimeofday(&after);
+       local_irq_enable();
+       idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
+                   (after.tv_usec - before.tv_usec);
+
+       return idle_time;
+}
+
+static int __init exynos4_init_cpuidle(void)
+{
+       int i, max_cpuidle_state, cpu_id;
+       struct cpuidle_device *device;
+
+       cpuidle_register_driver(&exynos4_idle_driver);
+
+       for_each_cpu(cpu_id, cpu_online_mask) {
+               device = &per_cpu(exynos4_cpuidle_device, cpu_id);
+               device->cpu = cpu_id;
+
+               device->state_count = (sizeof(exynos4_cpuidle_set) /
+                                              sizeof(struct cpuidle_state));
+
+               max_cpuidle_state = device->state_count;
+
+               for (i = 0; i < max_cpuidle_state; i++) {
+                       memcpy(&device->states[i], &exynos4_cpuidle_set[i],
+                                       sizeof(struct cpuidle_state));
+               }
+
+               if (cpuidle_register_device(device)) {
+                       printk(KERN_ERR "CPUidle register device failed\n,");
+                       return -EIO;
+               }
+       }
+       return 0;
+}
+device_initcall(exynos4_init_cpuidle);
index 703118d5173c0e4125f47305d946f2603474add5..c337cf3a71bf35e39bf4780f481a36a1c54db9aa 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef __PLAT_S5P_REGS_USB_PHY_H
 #define __PLAT_S5P_REGS_USB_PHY_H
 
-#define EXYNOS4_HSOTG_PHYREG(x)                ((x) + S5P_VA_USB_HSPHY)
+#define EXYNOS4_HSOTG_PHYREG(x)                ((x) + S3C_VA_USB_HSPHY)
 
 #define EXYNOS4_PHYPWR                 EXYNOS4_HSOTG_PHYREG(0x00)
 #define PHY1_HSIC_NORMAL_MASK          (0xf << 9)
index bb5d12f43af87e9ffd0a91c749fd56b348735a8e..642702bb5b127172142a468839a8be4af1d651c1 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/serial_core.h>
 #include <linux/input.h>
 #include <linux/i2c.h>
+#include <linux/i2c/atmel_mxt_ts.h>
 #include <linux/gpio_keys.h>
 #include <linux/gpio.h>
 #include <linux/regulator/machine.h>
@@ -32,6 +33,8 @@
 #include <plat/sdhci.h>
 #include <plat/ehci.h>
 #include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <plat/iic.h>
 
 #include <mach/map.h>
 
@@ -259,6 +262,88 @@ static struct i2c_board_info i2c1_devs[] __initdata = {
        /* Gyro, To be updated */
 };
 
+/* TSP */
+static u8 mxt_init_vals[] = {
+       /* MXT_GEN_COMMAND(6) */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* MXT_GEN_POWER(7) */
+       0x20, 0xff, 0x32,
+       /* MXT_GEN_ACQUIRE(8) */
+       0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23,
+       /* MXT_TOUCH_MULTI(9) */
+       0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00,
+       0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00,
+       /* MXT_TOUCH_KEYARRAY(15) */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+       0x00,
+       /* MXT_SPT_GPIOPWM(19) */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* MXT_PROCI_GRIPFACE(20) */
+       0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04,
+       0x0f, 0x0a,
+       /* MXT_PROCG_NOISE(22) */
+       0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00,
+       0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03,
+       /* MXT_TOUCH_PROXIMITY(23) */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00,
+       /* MXT_PROCI_ONETOUCH(24) */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* MXT_SPT_SELFTEST(25) */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       /* MXT_PROCI_TWOTOUCH(27) */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* MXT_SPT_CTECONFIG(28) */
+       0x00, 0x00, 0x02, 0x08, 0x10, 0x00,
+};
+
+static struct mxt_platform_data mxt_platform_data = {
+       .config                 = mxt_init_vals,
+       .config_length          = ARRAY_SIZE(mxt_init_vals),
+
+       .x_line                 = 18,
+       .y_line                 = 11,
+       .x_size                 = 1024,
+       .y_size                 = 600,
+       .blen                   = 0x1,
+       .threshold              = 0x28,
+       .voltage                = 2800000,              /* 2.8V */
+       .orient                 = MXT_DIAGONAL_COUNTER,
+       .irqflags               = IRQF_TRIGGER_FALLING,
+};
+
+static struct s3c2410_platform_i2c i2c3_data __initdata = {
+       .flags          = 0,
+       .bus_num        = 3,
+       .slave_addr     = 0x10,
+       .frequency      = 400 * 1000,
+       .sda_delay      = 100,
+};
+
+static struct i2c_board_info i2c3_devs[] __initdata = {
+       {
+               I2C_BOARD_INFO("atmel_mxt_ts", 0x4a),
+               .platform_data  = &mxt_platform_data,
+               .irq            = IRQ_EINT(4),
+       },
+};
+
+static void __init nuri_tsp_init(void)
+{
+       int gpio;
+
+       /* TOUCH_INT: XEINT_4 */
+       gpio = EXYNOS4_GPX0(4);
+       gpio_request(gpio, "TOUCH_INT");
+       s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0xf));
+       s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
+}
+
 /* GPIO I2C 5 (PMIC) */
 static struct i2c_board_info i2c5_devs[] __initdata = {
        /* max8997, To be updated */
@@ -283,6 +368,7 @@ static struct platform_device *nuri_devices[] __initdata = {
        &s3c_device_wdt,
        &s3c_device_timer[0],
        &s5p_device_ehci,
+       &s3c_device_i2c3,
 
        /* NURI Devices */
        &nuri_gpio_keys,
@@ -300,8 +386,11 @@ static void __init nuri_map_io(void)
 static void __init nuri_machine_init(void)
 {
        nuri_sdhci_init();
+       nuri_tsp_init();
 
        i2c_register_board_info(1, i2c1_devs, ARRAY_SIZE(i2c1_devs));
+       s3c_i2c3_set_platdata(&i2c3_data);
+       i2c_register_board_info(3, i2c3_devs, ARRAY_SIZE(i2c3_devs));
        i2c_register_board_info(5, i2c5_devs, ARRAY_SIZE(i2c5_devs));
 
        nuri_ehci_init();
index 86b9fa0d3639e1d69278e22a72ee3d188718a14a..ebb8f38d54059dbadb2cc32679d91fce3dbd348c 100644 (file)
@@ -206,6 +206,7 @@ static cycle_t exynos4_pwm4_read(struct clocksource *cs)
        return (cycle_t) ~__raw_readl(S3C_TIMERREG(0x40));
 }
 
+#ifdef CONFIG_PM
 static void exynos4_pwm4_resume(struct clocksource *cs)
 {
        unsigned long pclk;
@@ -218,6 +219,7 @@ static void exynos4_pwm4_resume(struct clocksource *cs)
        exynos4_pwm_init(4, ~0);
        exynos4_pwm_start(4, 1);
 }
+#endif
 
 struct clocksource pwm_clocksource = {
        .name           = "pwm_timer4",
index 5f1f9867fc70eedff4620119fead758eb7c0e2b2..121ad1d4fa39f9a0d4f70c6cbd23021f4e62617f 100644 (file)
@@ -103,6 +103,7 @@ static void __init footbridge_timer_init(void)
        clockevents_calc_mult_shift(ce, mem_fclk_21285, 5);
        ce->max_delta_ns = clockevent_delta2ns(0xffffff, ce);
        ce->min_delta_ns = clockevent_delta2ns(0x000004, ce);
+       ce->cpumask = cpumask_of(smp_processor_id());
 
        clockevents_register_device(ce);
 }
index 30b971d65815f342069719afca2052769ac99ba9..1be2eeb7a0a042198a73ec78a3b33278c25e533b 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/hardware/debug-8250.S>
 
 #else
+#include <mach/hardware.h>
        /* For EBSA285 debugging */
                .equ    dc21285_high, ARMCSR_BASE & 0xff000000
                .equ    dc21285_low,  ARMCSR_BASE & 0x00ffffff
@@ -36,8 +37,8 @@
                .else
                mov     \rp, #0
                .endif
-               orr     \rv, \rp, #0x42000000
-               orr     \rp, \rp, #dc21285_high
+               orr     \rv, \rp, #dc21285_high
+               orr     \rp, \rp, #0x42000000
                .endm
 
                .macro  senduart,rd,rx
index af7b68a6b2589385ae2996afb7f5da7645278608..88cc422ee444341f0cb813dd48e4acff54a33d16 100644 (file)
@@ -84,7 +84,6 @@ static struct sys_timer wbd111_timer = {
        .init   = gemini_timer_init,
 };
 
-#ifdef CONFIG_MTD_PARTITIONS
 static struct mtd_partition wbd111_partitions[] = {
        {
                .name           = "RedBoot",
@@ -116,11 +115,7 @@ static struct mtd_partition wbd111_partitions[] = {
                .mask_flags     = MTD_WRITEABLE,
        }
 };
-#define wbd111_num_partitions  ARRAY_SIZE(wbd111_partitions)
-#else
-#define wbd111_partitions      NULL
-#define wbd111_num_partitions  0
-#endif /* CONFIG_MTD_PARTITIONS */
+#define wbd111_num_partitions  ARRAY_SIZE(wbd111_partitions)
 
 static void __init wbd111_init(void)
 {
index 99e5bbecf923afd6a1c173308cfd6f6a6741e09a..3a220347bc88c70b4b0ade20f159476876b20ac5 100644 (file)
@@ -84,7 +84,6 @@ static struct sys_timer wbd222_timer = {
        .init   = gemini_timer_init,
 };
 
-#ifdef CONFIG_MTD_PARTITIONS
 static struct mtd_partition wbd222_partitions[] = {
        {
                .name           = "RedBoot",
@@ -116,11 +115,7 @@ static struct mtd_partition wbd222_partitions[] = {
                .mask_flags     = MTD_WRITEABLE,
        }
 };
-#define wbd222_num_partitions  ARRAY_SIZE(wbd222_partitions)
-#else
-#define wbd222_partitions      NULL
-#define wbd222_num_partitions  0
-#endif /* CONFIG_MTD_PARTITIONS */
+#define wbd222_num_partitions  ARRAY_SIZE(wbd222_partitions)
 
 static void __init wbd222_init(void)
 {
index 9b6982efbd22014e59b56e33b7c46bd3c20ccd56..abf356c02343fd144fc305f1c2c7f45af38b3a60 100644 (file)
@@ -6,12 +6,14 @@ config ARCH_H7201
        bool "gms30c7201"
        depends on ARCH_H720X
        select CPU_H7201
+       select ZONE_DMA
        help
          Say Y here if you are using the Hynix GMS30C7201 Reference Board
 
 config ARCH_H7202
        bool "hms30c7202"
        select CPU_H7202
+       select ZONE_DMA
        depends on ARCH_H720X
        help
          Say Y here if you are using the Hynix HMS30C7202 Reference Board
diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp46x_ts.h b/arch/arm/mach-ixp4xx/include/mach/ixp46x_ts.h
new file mode 100644 (file)
index 0000000..292d55e
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * PTP 1588 clock using the IXP46X
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  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.
+ */
+
+#ifndef _IXP46X_TS_H_
+#define _IXP46X_TS_H_
+
+#define DEFAULT_ADDEND 0xF0000029
+#define TICKS_NS_SHIFT 4
+
+struct ixp46x_channel_ctl {
+       u32 ch_control;  /* 0x40 Time Synchronization Channel Control */
+       u32 ch_event;    /* 0x44 Time Synchronization Channel Event */
+       u32 tx_snap_lo;  /* 0x48 Transmit Snapshot Low Register */
+       u32 tx_snap_hi;  /* 0x4C Transmit Snapshot High Register */
+       u32 rx_snap_lo;  /* 0x50 Receive Snapshot Low Register */
+       u32 rx_snap_hi;  /* 0x54 Receive Snapshot High Register */
+       u32 src_uuid_lo; /* 0x58 Source UUID0 Low Register */
+       u32 src_uuid_hi; /* 0x5C Sequence Identifier/Source UUID0 High */
+};
+
+struct ixp46x_ts_regs {
+       u32 control;     /* 0x00 Time Sync Control Register */
+       u32 event;       /* 0x04 Time Sync Event Register */
+       u32 addend;      /* 0x08 Time Sync Addend Register */
+       u32 accum;       /* 0x0C Time Sync Accumulator Register */
+       u32 test;        /* 0x10 Time Sync Test Register */
+       u32 unused;      /* 0x14 */
+       u32 rsystime_lo; /* 0x18 RawSystemTime_Low Register */
+       u32 rsystime_hi; /* 0x1C RawSystemTime_High Register */
+       u32 systime_lo;  /* 0x20 SystemTime_Low Register */
+       u32 systime_hi;  /* 0x24 SystemTime_High Register */
+       u32 trgt_lo;     /* 0x28 TargetTime_Low Register */
+       u32 trgt_hi;     /* 0x2C TargetTime_High Register */
+       u32 asms_lo;     /* 0x30 Auxiliary Slave Mode Snapshot Low  */
+       u32 asms_hi;     /* 0x34 Auxiliary Slave Mode Snapshot High */
+       u32 amms_lo;     /* 0x38 Auxiliary Master Mode Snapshot Low */
+       u32 amms_hi;     /* 0x3C Auxiliary Master Mode Snapshot High */
+
+       struct ixp46x_channel_ctl channel[3];
+};
+
+/* 0x00 Time Sync Control Register Bits */
+#define TSCR_AMM (1<<3)
+#define TSCR_ASM (1<<2)
+#define TSCR_TTM (1<<1)
+#define TSCR_RST (1<<0)
+
+/* 0x04 Time Sync Event Register Bits */
+#define TSER_SNM (1<<3)
+#define TSER_SNS (1<<2)
+#define TTIPEND  (1<<1)
+
+/* 0x40 Time Synchronization Channel Control Register Bits */
+#define MASTER_MODE   (1<<0)
+#define TIMESTAMP_ALL (1<<1)
+
+/* 0x44 Time Synchronization Channel Event Register Bits */
+#define TX_SNAPSHOT_LOCKED (1<<0)
+#define RX_SNAPSHOT_LOCKED (1<<1)
+
+#endif
index 140783386785511a8997a8926a20a9d353bd8091..dca4f7f9f4f7bc3c2e12babc52d4443e537ab87d 100644 (file)
@@ -60,7 +60,6 @@ static struct platform_device ixdp425_flash = {
 #if defined(CONFIG_MTD_NAND_PLATFORM) || \
     defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
 
-#ifdef CONFIG_MTD_PARTITIONS
 const char *part_probes[] = { "cmdlinepart", NULL };
 
 static struct mtd_partition ixdp425_partitions[] = {
@@ -74,7 +73,6 @@ static struct mtd_partition ixdp425_partitions[] = {
                .size   = MTDPART_SIZ_FULL
        },
 };
-#endif
 
 static void
 ixdp425_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
@@ -103,11 +101,9 @@ static struct platform_nand_data ixdp425_flash_nand_data = {
                .nr_chips               = 1,
                .chip_delay             = 30,
                .options                = NAND_NO_AUTOINCR,
-#ifdef CONFIG_MTD_PARTITIONS
                .part_probe_types       = part_probes,
                .partitions             = ixdp425_partitions,
                .nr_partitions          = ARRAY_SIZE(ixdp425_partitions),
-#endif
        },
        .ctrl = {
                .cmd_ctrl               = ixdp425_flash_nand_cmd_ctrl
index 38b95e949d13b0a87d83a3274b0369e98c8321ed..63621f152c989c0a2041208cf7ff1ab58bb9ee52 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/io.h>
 
 #include <asm/mach/time.h>
+#include <asm/hardware/gic.h>
+
 #include <mach/msm_iomap.h>
 #include <mach/cpu.h>
 
@@ -55,10 +57,12 @@ enum timer_location {
 #if defined(CONFIG_ARCH_QSD8X50)
 #define DGT_HZ (19200000 / 4) /* 19.2 MHz / 4 by default */
 #define MSM_DGT_SHIFT (0)
-#elif defined(CONFIG_ARCH_MSM7X30) || defined(CONFIG_ARCH_MSM8X60) || \
-                                     defined(CONFIG_ARCH_MSM8960)
+#elif defined(CONFIG_ARCH_MSM7X30)
 #define DGT_HZ (24576000 / 4) /* 24.576 MHz (LPXO) / 4 by default */
 #define MSM_DGT_SHIFT (0)
+#elif defined(CONFIG_ARCH_MSM8X60) || defined(CONFIG_ARCH_MSM8960)
+#define DGT_HZ (27000000 / 4) /* 27 MHz (PXO) / 4 by default */
+#define MSM_DGT_SHIFT (0)
 #else
 #define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */
 #define MSM_DGT_SHIFT (5)
@@ -100,7 +104,11 @@ static cycle_t msm_read_timer_count(struct clocksource *cs)
 {
        struct msm_clock *clk = container_of(cs, struct msm_clock, clocksource);
 
-       return readl(clk->global_counter);
+       /*
+        * Shift timer count down by a constant due to unreliable lower bits
+        * on some targets.
+        */
+       return readl(clk->global_counter) >> clk->shift;
 }
 
 static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt)
index 65157a35dbba351d6751bdcb4ee483e37b25ee88..54add60f94c98c5d8d15c119e996395a13b6fc86 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/err.h>
 #include <linux/mutex.h>
 
+#include <asm/processor.h>     /* for cpu_relax() */
+
 #include <mach/mxs.h>
 
 #define OCOTP_WORD_OFFSET              0x20
index 5b84bcd30271321a17a38c7e0d2a2f51d4f286c2..b9913234bbf66458e93740aa1fd1e9c2004d42a1 100644 (file)
@@ -103,7 +103,6 @@ static struct amba_device fb_device = {
                .flags  = IORESOURCE_MEM,
        },
        .irq            = { NETX_IRQ_LCD, NO_IRQ },
-       .periphid       = 0x10112400,
 };
 
 int netx_fb_init(struct clcd_board *board, struct clcd_panel *panel)
index 71f3ea623974b487d8bd44cb3dd6edbf24d21fb8..3c5e0f522e9ce507f6ceb95fcd605ef3bd734334 100644 (file)
@@ -6,7 +6,6 @@ config MACH_NOMADIK_8815NHK
        bool "ST 8815 Nomadik Hardware Kit (evaluation board)"
        select NOMADIK_8815
        select HAS_MTU
-       select NOMADIK_GPIO
 
 endmenu
 
index af98117043d214f8e088e8fd1429656410300a14..5b114d1558c83f41fe8acc524b1aa86f2ffa4a54 100644 (file)
@@ -4,14 +4,14 @@
 
 # Common support
 obj-y := io.o id.o sram.o time.o irq.o mux.o flash.o serial.o devices.o dma.o
-obj-y += clock.o clock_data.o opp_data.o reset.o
+obj-y += clock.o clock_data.o opp_data.o reset.o pm_bus.o
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 
 obj-$(CONFIG_OMAP_32K_TIMER)   += timer32k.o
 
 # Power Management
-obj-$(CONFIG_PM) += pm.o sleep.o pm_bus.o
+obj-$(CONFIG_PM) += pm.o sleep.o
 
 # DSP
 obj-$(CONFIG_OMAP_MBOX_FWK)    += mailbox_mach.o
index d8559344c6e2927581d19663de05e0b23c10c849..f5a52204b89fa8e85908ab8f2566594575324027 100644 (file)
@@ -284,14 +284,15 @@ static int __init omap1_system_dma_init(void)
        dma_base = ioremap(res[0].start, resource_size(&res[0]));
        if (!dma_base) {
                pr_err("%s: Unable to ioremap\n", __func__);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto exit_device_put;
        }
 
        ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
        if (ret) {
                dev_err(&pdev->dev, "%s: Unable to add resources for %s%d\n",
                        __func__, pdev->name, pdev->id);
-               goto exit_device_del;
+               goto exit_device_put;
        }
 
        p = kzalloc(sizeof(struct omap_system_dma_plat_info), GFP_KERNEL);
@@ -299,7 +300,7 @@ static int __init omap1_system_dma_init(void)
                dev_err(&pdev->dev, "%s: Unable to allocate 'p' for %s\n",
                        __func__, pdev->name);
                ret = -ENOMEM;
-               goto exit_device_put;
+               goto exit_device_del;
        }
 
        d = kzalloc(sizeof(struct omap_dma_dev_attr), GFP_KERNEL);
@@ -380,10 +381,10 @@ exit_release_d:
        kfree(d);
 exit_release_p:
        kfree(p);
-exit_device_put:
-       platform_device_put(pdev);
 exit_device_del:
        platform_device_del(pdev);
+exit_device_put:
+       platform_device_put(pdev);
 
        return ret;
 }
index fe31d933f0edee78106d52d0c82fb95ef70a3a58..334fb8871bc319348f9edb152e5d611fb539aa6f 100644 (file)
@@ -56,9 +56,13 @@ static struct dev_power_domain default_power_domain = {
                USE_PLATFORM_PM_SLEEP_OPS
        },
 };
+#define OMAP1_PWR_DOMAIN (&default_power_domain)
+#else
+#define OMAP1_PWR_DOMAIN NULL
+#endif /* CONFIG_PM_RUNTIME */
 
 static struct pm_clk_notifier_block platform_bus_notifier = {
-       .pwr_domain = &default_power_domain,
+       .pwr_domain = OMAP1_PWR_DOMAIN,
        .con_ids = { "ick", "fck", NULL, },
 };
 
@@ -72,4 +76,4 @@ static int __init omap1_pm_runtime_init(void)
        return 0;
 }
 core_initcall(omap1_pm_runtime_init);
-#endif /* CONFIG_PM_RUNTIME */
+
index b997a35830fce5e36f1624773916a90159a02865..19d5891c48e325f6afe8e1a101dfdfbca3ad0a68 100644 (file)
@@ -288,6 +288,7 @@ config MACH_IGEP0030
        depends on ARCH_OMAP3
        default y
        select OMAP_PACKAGE_CBB
+       select MACH_IGEP0020
 
 config MACH_SBC3530
        bool "OMAP3 SBC STALKER board"
index 66dfbccacd25e0cabfdbbbf802f8cb59526d8fc7..b14807794401243fac61205cfcafdb925398dfbd 100644 (file)
@@ -229,8 +229,6 @@ obj-$(CONFIG_MACH_CM_T35)           += board-cm-t35.o \
 obj-$(CONFIG_MACH_CM_T3517)            += board-cm-t3517.o
 obj-$(CONFIG_MACH_IGEP0020)            += board-igep0020.o \
                                           hsmmc.o
-obj-$(CONFIG_MACH_IGEP0030)            += board-igep0030.o \
-                                          hsmmc.o
 obj-$(CONFIG_MACH_OMAP3_TOUCHBOOK)     += board-omap3touchbook.o \
                                           hsmmc.o
 obj-$(CONFIG_MACH_OMAP_4430SDP)                += board-4430sdp.o \
@@ -270,3 +268,5 @@ obj-$(CONFIG_ARCH_OMAP4)            += hwspinlock.o
 
 disp-$(CONFIG_OMAP2_DSS)               := display.o
 obj-y                                  += $(disp-m) $(disp-y)
+
+obj-y                                  += common-board-devices.o
index 1fa6bb896f419d9fccbdca8f6638a4c426673be2..5de6eac0a72520a8b37e7a9d5cde73c3de40b1c5 100644 (file)
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/gpio.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <mach/gpio.h>
 #include <plat/board.h>
 #include <plat/common.h>
 #include <plat/gpmc.h>
@@ -41,6 +41,7 @@
 
 #include "mux.h"
 #include "hsmmc.h"
+#include "common-board-devices.h"
 
 #define SDP2430_CS0_BASE       0x04000000
 #define SECONDARY_LCD_GPIO             147
@@ -180,15 +181,6 @@ static struct twl4030_platform_data sdp2430_twldata = {
        .vmmc1          = &sdp2430_vmmc1,
 };
 
-static struct i2c_board_info __initdata sdp2430_i2c_boardinfo[] = {
-       {
-               I2C_BOARD_INFO("twl4030", 0x48),
-               .flags = I2C_CLIENT_WAKE,
-               .irq = INT_24XX_SYS_NIRQ,
-               .platform_data = &sdp2430_twldata,
-       },
-};
-
 static struct i2c_board_info __initdata sdp2430_i2c1_boardinfo[] = {
        {
                I2C_BOARD_INFO("isp1301_omap", 0x2D),
@@ -201,8 +193,7 @@ static int __init omap2430_i2c_init(void)
 {
        omap_register_i2c_bus(1, 100, sdp2430_i2c1_boardinfo,
                        ARRAY_SIZE(sdp2430_i2c1_boardinfo));
-       omap_register_i2c_bus(2, 2600, sdp2430_i2c_boardinfo,
-                       ARRAY_SIZE(sdp2430_i2c_boardinfo));
+       omap2_pmic_init("twl4030", &sdp2430_twldata);
        return 0;
 }
 
@@ -217,11 +208,6 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
        {}      /* Terminator */
 };
 
-static struct omap_musb_board_data musb_board_data = {
-       .interface_type         = MUSB_INTERFACE_ULPI,
-       .mode                   = MUSB_OTG,
-       .power                  = 100,
-};
 static struct omap_usb_config sdp2430_usb_config __initdata = {
        .otg            = 1,
 #ifdef  CONFIG_USB_GADGET_OMAP
@@ -240,8 +226,6 @@ static struct omap_board_mux board_mux[] __initdata = {
 
 static void __init omap_2430sdp_init(void)
 {
-       int ret;
-
        omap2430_mux_init(board_mux, OMAP_PACKAGE_ZAC);
 
        omap_board_config = sdp2430_config;
@@ -255,14 +239,13 @@ static void __init omap_2430sdp_init(void)
        omap2_usbfs_init(&sdp2430_usb_config);
 
        omap_mux_init_signal("usb0hs_stp", OMAP_PULL_ENA | OMAP_PULL_UP);
-       usb_musb_init(&musb_board_data);
+       usb_musb_init(NULL);
 
        board_smc91x_init();
 
        /* Turn off secondary LCD backlight */
-       ret = gpio_request(SECONDARY_LCD_GPIO, "Secondary LCD backlight");
-       if (ret == 0)
-               gpio_direction_output(SECONDARY_LCD_GPIO, 0);
+       gpio_request_one(SECONDARY_LCD_GPIO, GPIOF_OUT_INIT_LOW,
+                        "Secondary LCD backlight");
 }
 
 static void __init omap_2430sdp_map_io(void)
index 9afd087cc29c9b1346cde3b161236e6d01b37524..5dac974be6256bd4a22a4fc570142d56bee90efa 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/input.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
 #include <linux/i2c/twl.h>
 #include <linux/regulator/machine.h>
 #include <linux/io.h>
@@ -37,8 +36,8 @@
 #include <plat/common.h>
 #include <plat/dma.h>
 #include <plat/gpmc.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 
 #include <plat/gpmc-smc91x.h>
 
@@ -48,6 +47,7 @@
 #include "hsmmc.h"
 #include "pm.h"
 #include "control.h"
+#include "common-board-devices.h"
 
 #define CONFIG_DISABLE_HFCLK 1
 
 
 #define TWL4030_MSECURE_GPIO 22
 
-/* FIXME: These values need to be updated based on more profiling on 3430sdp*/
-static struct cpuidle_params omap3_cpuidle_params_table[] = {
-       /* C1 */
-       {1, 2, 2, 5},
-       /* C2 */
-       {1, 10, 10, 30},
-       /* C3 */
-       {1, 50, 50, 300},
-       /* C4 */
-       {1, 1500, 1800, 4000},
-       /* C5 */
-       {1, 2500, 7500, 12000},
-       /* C6 */
-       {1, 3000, 8500, 15000},
-       /* C7 */
-       {1, 10000, 30000, 300000},
-};
-
 static uint32_t board_keymap[] = {
        KEY(0, 0, KEY_LEFT),
        KEY(0, 1, KEY_RIGHT),
@@ -123,63 +105,14 @@ static struct twl4030_keypad_data sdp3430_kp_data = {
        .rep            = 1,
 };
 
-static int ts_gpio;    /* Needed for ads7846_get_pendown_state */
-
-/**
- * @brief ads7846_dev_init : Requests & sets GPIO line for pen-irq
- *
- * @return - void. If request gpio fails then Flag KERN_ERR.
- */
-static void ads7846_dev_init(void)
-{
-       if (gpio_request(ts_gpio, "ADS7846 pendown") < 0) {
-               printk(KERN_ERR "can't get ads746 pen down GPIO\n");
-               return;
-       }
-
-       gpio_direction_input(ts_gpio);
-       gpio_set_debounce(ts_gpio, 310);
-}
-
-static int ads7846_get_pendown_state(void)
-{
-       return !gpio_get_value(ts_gpio);
-}
-
-static struct ads7846_platform_data tsc2046_config __initdata = {
-       .get_pendown_state      = ads7846_get_pendown_state,
-       .keep_vref_on           = 1,
-       .wakeup                         = true,
-};
-
-
-static struct omap2_mcspi_device_config tsc2046_mcspi_config = {
-       .turbo_mode     = 0,
-       .single_channel = 1,    /* 0: slave, 1: master */
-};
-
-static struct spi_board_info sdp3430_spi_board_info[] __initdata = {
-       [0] = {
-               /*
-                * TSC2046 operates at a max freqency of 2MHz, so
-                * operate slightly below at 1.5MHz
-                */
-               .modalias               = "ads7846",
-               .bus_num                = 1,
-               .chip_select            = 0,
-               .max_speed_hz           = 1500000,
-               .controller_data        = &tsc2046_mcspi_config,
-               .irq                    = 0,
-               .platform_data          = &tsc2046_config,
-       },
-};
-
-
 #define SDP3430_LCD_PANEL_BACKLIGHT_GPIO       8
 #define SDP3430_LCD_PANEL_ENABLE_GPIO          5
 
-static unsigned backlight_gpio;
-static unsigned enable_gpio;
+static struct gpio sdp3430_dss_gpios[] __initdata = {
+       {SDP3430_LCD_PANEL_ENABLE_GPIO,    GPIOF_OUT_INIT_LOW, "LCD reset"    },
+       {SDP3430_LCD_PANEL_BACKLIGHT_GPIO, GPIOF_OUT_INIT_LOW, "LCD Backlight"},
+};
+
 static int lcd_enabled;
 static int dvi_enabled;
 
@@ -187,29 +120,11 @@ static void __init sdp3430_display_init(void)
 {
        int r;
 
-       enable_gpio    = SDP3430_LCD_PANEL_ENABLE_GPIO;
-       backlight_gpio = SDP3430_LCD_PANEL_BACKLIGHT_GPIO;
-
-       r = gpio_request(enable_gpio, "LCD reset");
-       if (r) {
-               printk(KERN_ERR "failed to get LCD reset GPIO\n");
-               goto err0;
-       }
-
-       r = gpio_request(backlight_gpio, "LCD Backlight");
-       if (r) {
-               printk(KERN_ERR "failed to get LCD backlight GPIO\n");
-               goto err1;
-       }
-
-       gpio_direction_output(enable_gpio, 0);
-       gpio_direction_output(backlight_gpio, 0);
+       r = gpio_request_array(sdp3430_dss_gpios,
+                              ARRAY_SIZE(sdp3430_dss_gpios));
+       if (r)
+               printk(KERN_ERR "failed to get LCD control GPIOs\n");
 
-       return;
-err1:
-       gpio_free(enable_gpio);
-err0:
-       return;
 }
 
 static int sdp3430_panel_enable_lcd(struct omap_dss_device *dssdev)
@@ -219,8 +134,8 @@ static int sdp3430_panel_enable_lcd(struct omap_dss_device *dssdev)
                return -EINVAL;
        }
 
-       gpio_direction_output(enable_gpio, 1);
-       gpio_direction_output(backlight_gpio, 1);
+       gpio_direction_output(SDP3430_LCD_PANEL_ENABLE_GPIO, 1);
+       gpio_direction_output(SDP3430_LCD_PANEL_BACKLIGHT_GPIO, 1);
 
        lcd_enabled = 1;
 
@@ -231,8 +146,8 @@ static void sdp3430_panel_disable_lcd(struct omap_dss_device *dssdev)
 {
        lcd_enabled = 0;
 
-       gpio_direction_output(enable_gpio, 0);
-       gpio_direction_output(backlight_gpio, 0);
+       gpio_direction_output(SDP3430_LCD_PANEL_ENABLE_GPIO, 0);
+       gpio_direction_output(SDP3430_LCD_PANEL_BACKLIGHT_GPIO, 0);
 }
 
 static int sdp3430_panel_enable_dvi(struct omap_dss_device *dssdev)
@@ -360,12 +275,10 @@ static int sdp3430_twl_gpio_setup(struct device *dev,
        omap2_hsmmc_init(mmc);
 
        /* gpio + 7 is "sub_lcd_en_bkl" (output/PWM1) */
-       gpio_request(gpio + 7, "sub_lcd_en_bkl");
-       gpio_direction_output(gpio + 7, 0);
+       gpio_request_one(gpio + 7, GPIOF_OUT_INIT_LOW, "sub_lcd_en_bkl");
 
        /* gpio + 15 is "sub_lcd_nRST" (output) */
-       gpio_request(gpio + 15, "sub_lcd_nRST");
-       gpio_direction_output(gpio + 15, 0);
+       gpio_request_one(gpio + 15, GPIOF_OUT_INIT_LOW, "sub_lcd_nRST");
 
        return 0;
 }
@@ -580,20 +493,10 @@ static struct twl4030_platform_data sdp3430_twldata = {
        .vpll2          = &sdp3430_vpll2,
 };
 
-static struct i2c_board_info __initdata sdp3430_i2c_boardinfo[] = {
-       {
-               I2C_BOARD_INFO("twl4030", 0x48),
-               .flags = I2C_CLIENT_WAKE,
-               .irq = INT_34XX_SYS_NIRQ,
-               .platform_data = &sdp3430_twldata,
-       },
-};
-
 static int __init omap3430_i2c_init(void)
 {
        /* i2c1 for PMIC only */
-       omap_register_i2c_bus(1, 2600, sdp3430_i2c_boardinfo,
-                       ARRAY_SIZE(sdp3430_i2c_boardinfo));
+       omap3_pmic_init("twl4030", &sdp3430_twldata);
        /* i2c2 on camera connector (for sensor control) and optional isp1301 */
        omap_register_i2c_bus(2, 400, NULL, 0);
        /* i2c3 on display connector (for DVI, tfp410) */
@@ -719,19 +622,19 @@ static struct omap_device_pad serial3_pads[] __initdata = {
                         OMAP_MUX_MODE0),
 };
 
-static struct omap_board_data serial1_data = {
+static struct omap_board_data serial1_data __initdata = {
        .id             = 0,
        .pads           = serial1_pads,
        .pads_cnt       = ARRAY_SIZE(serial1_pads),
 };
 
-static struct omap_board_data serial2_data = {
+static struct omap_board_data serial2_data __initdata = {
        .id             = 1,
        .pads           = serial2_pads,
        .pads_cnt       = ARRAY_SIZE(serial2_pads),
 };
 
-static struct omap_board_data serial3_data = {
+static struct omap_board_data serial3_data __initdata = {
        .id             = 2,
        .pads           = serial3_pads,
        .pads_cnt       = ARRAY_SIZE(serial3_pads),
@@ -872,30 +775,22 @@ static struct flash_partitions sdp_flash_partitions[] = {
        },
 };
 
-static struct omap_musb_board_data musb_board_data = {
-       .interface_type         = MUSB_INTERFACE_ULPI,
-       .mode                   = MUSB_OTG,
-       .power                  = 100,
-};
-
 static void __init omap_3430sdp_init(void)
 {
+       int gpio_pendown;
+
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
        omap_board_config = sdp3430_config;
        omap_board_config_size = ARRAY_SIZE(sdp3430_config);
-       omap3_pm_init_cpuidle(omap3_cpuidle_params_table);
        omap3430_i2c_init();
        omap_display_init(&sdp3430_dss_data);
        if (omap_rev() > OMAP3430_REV_ES1_0)
-               ts_gpio = SDP3430_TS_GPIO_IRQ_SDPV2;
+               gpio_pendown = SDP3430_TS_GPIO_IRQ_SDPV2;
        else
-               ts_gpio = SDP3430_TS_GPIO_IRQ_SDPV1;
-       sdp3430_spi_board_info[0].irq = gpio_to_irq(ts_gpio);
-       spi_register_board_info(sdp3430_spi_board_info,
-                               ARRAY_SIZE(sdp3430_spi_board_info));
-       ads7846_dev_init();
+               gpio_pendown = SDP3430_TS_GPIO_IRQ_SDPV1;
+       omap_ads7846_init(1, gpio_pendown, 310, NULL);
        board_serial_init();
-       usb_musb_init(&musb_board_data);
+       usb_musb_init(NULL);
        board_smc91x_init();
        board_flash_init(sdp_flash_partitions, chip_sel_3430, 0);
        sdp3430_display_init();
index 56702c5e577fe3365cab09b56c32d5b4913020a0..63de2d396e2dddf84eaec2b6035aad64aba49385 100644 (file)
 #include <plat/usb.h>
 #include <plat/mmc.h>
 #include <plat/omap4-keypad.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #include "mux.h"
 #include "hsmmc.h"
 #include "timer-gp.h"
 #include "control.h"
+#include "common-board-devices.h"
 
 #define ETH_KS8851_IRQ                 34
 #define ETH_KS8851_POWER_ON            48
@@ -251,58 +252,22 @@ static struct spi_board_info sdp4430_spi_board_info[] __initdata = {
        },
 };
 
-static int omap_ethernet_init(void)
+static struct gpio sdp4430_eth_gpios[] __initdata = {
+       { ETH_KS8851_POWER_ON,  GPIOF_OUT_INIT_HIGH,    "eth_power"     },
+       { ETH_KS8851_QUART,     GPIOF_OUT_INIT_HIGH,    "quart"         },
+       { ETH_KS8851_IRQ,       GPIOF_IN,               "eth_irq"       },
+};
+
+static int __init omap_ethernet_init(void)
 {
        int status;
 
        /* Request of GPIO lines */
+       status = gpio_request_array(sdp4430_eth_gpios,
+                                   ARRAY_SIZE(sdp4430_eth_gpios));
+       if (status)
+               pr_err("Cannot request ETH GPIOs\n");
 
-       status = gpio_request(ETH_KS8851_POWER_ON, "eth_power");
-       if (status) {
-               pr_err("Cannot request GPIO %d\n", ETH_KS8851_POWER_ON);
-               return status;
-       }
-
-       status = gpio_request(ETH_KS8851_QUART, "quart");
-       if (status) {
-               pr_err("Cannot request GPIO %d\n", ETH_KS8851_QUART);
-               goto error1;
-       }
-
-       status = gpio_request(ETH_KS8851_IRQ, "eth_irq");
-       if (status) {
-               pr_err("Cannot request GPIO %d\n", ETH_KS8851_IRQ);
-               goto error2;
-       }
-
-       /* Configuration of requested GPIO lines */
-
-       status = gpio_direction_output(ETH_KS8851_POWER_ON, 1);
-       if (status) {
-               pr_err("Cannot set output GPIO %d\n", ETH_KS8851_IRQ);
-               goto error3;
-       }
-
-       status = gpio_direction_output(ETH_KS8851_QUART, 1);
-       if (status) {
-               pr_err("Cannot set output GPIO %d\n", ETH_KS8851_QUART);
-               goto error3;
-       }
-
-       status = gpio_direction_input(ETH_KS8851_IRQ);
-       if (status) {
-               pr_err("Cannot set input GPIO %d\n", ETH_KS8851_IRQ);
-               goto error3;
-       }
-
-       return 0;
-
-error3:
-       gpio_free(ETH_KS8851_IRQ);
-error2:
-       gpio_free(ETH_KS8851_QUART);
-error1:
-       gpio_free(ETH_KS8851_POWER_ON);
        return status;
 }
 
@@ -357,6 +322,7 @@ static struct omap2_hsmmc_info mmc[] = {
                .gpio_wp        = -EINVAL,
                .nonremovable   = true,
                .ocr_mask       = MMC_VDD_29_30,
+               .no_off_init    = true,
        },
        {
                .mmc            = 1,
@@ -575,14 +541,6 @@ static struct twl4030_platform_data sdp4430_twldata = {
        .usb            = &omap4_usbphy_data
 };
 
-static struct i2c_board_info __initdata sdp4430_i2c_boardinfo[] = {
-       {
-               I2C_BOARD_INFO("twl6030", 0x48),
-               .flags = I2C_CLIENT_WAKE,
-               .irq = OMAP44XX_IRQ_SYS_1N,
-               .platform_data = &sdp4430_twldata,
-       },
-};
 static struct i2c_board_info __initdata sdp4430_i2c_3_boardinfo[] = {
        {
                I2C_BOARD_INFO("tmp105", 0x48),
@@ -598,12 +556,7 @@ static struct i2c_board_info __initdata sdp4430_i2c_4_boardinfo[] = {
 };
 static int __init omap4_i2c_init(void)
 {
-       /*
-        * Phoenix Audio IC needs I2C1 to
-        * start with 400 KHz or less
-        */
-       omap_register_i2c_bus(1, 400, sdp4430_i2c_boardinfo,
-                       ARRAY_SIZE(sdp4430_i2c_boardinfo));
+       omap4_pmic_init("twl6030", &sdp4430_twldata);
        omap_register_i2c_bus(2, 400, NULL, 0);
        omap_register_i2c_bus(3, 400, sdp4430_i2c_3_boardinfo,
                                ARRAY_SIZE(sdp4430_i2c_3_boardinfo));
@@ -614,21 +567,13 @@ static int __init omap4_i2c_init(void)
 
 static void __init omap_sfh7741prox_init(void)
 {
-       int  error;
+       int error;
 
-       error = gpio_request(OMAP4_SFH7741_ENABLE_GPIO, "sfh7741");
-       if (error < 0) {
+       error = gpio_request_one(OMAP4_SFH7741_ENABLE_GPIO,
+                                GPIOF_OUT_INIT_LOW, "sfh7741");
+       if (error < 0)
                pr_err("%s:failed to request GPIO %d, error %d\n",
                        __func__, OMAP4_SFH7741_ENABLE_GPIO, error);
-               return;
-       }
-
-       error = gpio_direction_output(OMAP4_SFH7741_ENABLE_GPIO , 0);
-       if (error < 0) {
-               pr_err("%s: GPIO configuration failed: GPIO %d,error %d\n",
-                        __func__, OMAP4_SFH7741_ENABLE_GPIO, error);
-               gpio_free(OMAP4_SFH7741_ENABLE_GPIO);
-       }
 }
 
 static void sdp4430_hdmi_mux_init(void)
@@ -645,27 +590,19 @@ static void sdp4430_hdmi_mux_init(void)
                        OMAP_PIN_INPUT_PULLUP);
 }
 
+static struct gpio sdp4430_hdmi_gpios[] = {
+       { HDMI_GPIO_HPD,        GPIOF_OUT_INIT_HIGH,    "hdmi_gpio_hpd"   },
+       { HDMI_GPIO_LS_OE,      GPIOF_OUT_INIT_HIGH,    "hdmi_gpio_ls_oe" },
+};
+
 static int sdp4430_panel_enable_hdmi(struct omap_dss_device *dssdev)
 {
        int status;
 
-       status = gpio_request_one(HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH,
-                                                       "hdmi_gpio_hpd");
-       if (status) {
-               pr_err("Cannot request GPIO %d\n", HDMI_GPIO_HPD);
-               return status;
-       }
-       status = gpio_request_one(HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH,
-                                                       "hdmi_gpio_ls_oe");
-       if (status) {
-               pr_err("Cannot request GPIO %d\n", HDMI_GPIO_LS_OE);
-               goto error1;
-       }
-
-       return 0;
-
-error1:
-       gpio_free(HDMI_GPIO_HPD);
+       status = gpio_request_array(sdp4430_hdmi_gpios,
+                                   ARRAY_SIZE(sdp4430_hdmi_gpios));
+       if (status)
+               pr_err("%s: Cannot request HDMI GPIOs\n", __func__);
 
        return status;
 }
@@ -680,6 +617,15 @@ static struct omap_dss_device sdp4430_hdmi_device = {
        .name = "hdmi",
        .driver_name = "hdmi_panel",
        .type = OMAP_DISPLAY_TYPE_HDMI,
+       .clocks = {
+               .dispc  = {
+                       .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK,
+               },
+               .hdmi   = {
+                       .regn   = 15,
+                       .regm2  = 1,
+               },
+       },
        .platform_enable = sdp4430_panel_enable_hdmi,
        .platform_disable = sdp4430_panel_disable_hdmi,
        .channel = OMAP_DSS_CHANNEL_DIGIT,
@@ -736,19 +682,19 @@ static struct omap_device_pad serial4_pads[] __initdata = {
                         OMAP_PIN_OUTPUT | OMAP_MUX_MODE0),
 };
 
-static struct omap_board_data serial2_data = {
+static struct omap_board_data serial2_data __initdata = {
        .id             = 1,
        .pads           = serial2_pads,
        .pads_cnt       = ARRAY_SIZE(serial2_pads),
 };
 
-static struct omap_board_data serial3_data = {
+static struct omap_board_data serial3_data __initdata = {
        .id             = 2,
        .pads           = serial3_pads,
        .pads_cnt       = ARRAY_SIZE(serial3_pads),
 };
 
-static struct omap_board_data serial4_data = {
+static struct omap_board_data serial4_data __initdata = {
        .id             = 3,
        .pads           = serial4_pads,
        .pads_cnt       = ARRAY_SIZE(serial4_pads),
@@ -784,7 +730,7 @@ static void __init omap_4430sdp_init(void)
 
        if (omap_rev() == OMAP4430_REV_ES1_0)
                package = OMAP_PACKAGE_CBL;
-       omap4_mux_init(board_mux, package);
+       omap4_mux_init(board_mux, NULL, package);
 
        omap_board_config = sdp4430_config;
        omap_board_config_size = ARRAY_SIZE(sdp4430_config);
index a890d244fec688fdb93b1e44a7d8e51b35b2a373..5e438a77cd726f35e5df2ea43df0788f8e34d16b 100644 (file)
@@ -89,19 +89,13 @@ static void __init am3517_crane_init(void)
                return;
        }
 
-       ret = gpio_request(GPIO_USB_POWER, "usb_ehci_enable");
+       ret = gpio_request_one(GPIO_USB_POWER, GPIOF_OUT_INIT_HIGH,
+                              "usb_ehci_enable");
        if (ret < 0) {
                pr_err("Can not request GPIO %d\n", GPIO_USB_POWER);
                return;
        }
 
-       ret = gpio_direction_output(GPIO_USB_POWER, 1);
-       if (ret < 0) {
-               gpio_free(GPIO_USB_POWER);
-               pr_err("Unable to initialize EHCI power\n");
-               return;
-       }
-
        usbhs_init(&usbhs_bdata);
 }
 
index ce7d5e6e41508c3708a64b9680566dce6933b9dc..63af4171c0436d85c3d7ea35d6a21679380414fa 100644 (file)
@@ -34,8 +34,8 @@
 #include <plat/board.h>
 #include <plat/common.h>
 #include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 
 #include "mux.h"
 #include "control.h"
@@ -174,19 +174,14 @@ static void __init am3517_evm_rtc_init(void)
        int r;
 
        omap_mux_init_gpio(GPIO_RTCS35390A_IRQ, OMAP_PIN_INPUT_PULLUP);
-       r = gpio_request(GPIO_RTCS35390A_IRQ, "rtcs35390a-irq");
+
+       r = gpio_request_one(GPIO_RTCS35390A_IRQ, GPIOF_IN, "rtcs35390a-irq");
        if (r < 0) {
                printk(KERN_WARNING "failed to request GPIO#%d\n",
                                GPIO_RTCS35390A_IRQ);
                return;
        }
-       r = gpio_direction_input(GPIO_RTCS35390A_IRQ);
-       if (r < 0) {
-               printk(KERN_WARNING "GPIO#%d cannot be configured as input\n",
-                               GPIO_RTCS35390A_IRQ);
-               gpio_free(GPIO_RTCS35390A_IRQ);
-               return;
-       }
+
        am3517evm_i2c1_boardinfo[0].irq = gpio_to_irq(GPIO_RTCS35390A_IRQ);
 }
 
@@ -242,6 +237,15 @@ static int dvi_enabled;
 
 #if defined(CONFIG_PANEL_SHARP_LQ043T1DG01) || \
                defined(CONFIG_PANEL_SHARP_LQ043T1DG01_MODULE)
+static struct gpio am3517_evm_dss_gpios[] __initdata = {
+       /* GPIO 182 = LCD Backlight Power */
+       { LCD_PANEL_BKLIGHT_PWR, GPIOF_OUT_INIT_HIGH, "lcd_backlight_pwr" },
+       /* GPIO 181 = LCD Panel PWM */
+       { LCD_PANEL_PWM,         GPIOF_OUT_INIT_HIGH, "lcd bl enable"     },
+       /* GPIO 176 = LCD Panel Power enable pin */
+       { LCD_PANEL_PWR,         GPIOF_OUT_INIT_HIGH, "dvi enable"        },
+};
+
 static void __init am3517_evm_display_init(void)
 {
        int r;
@@ -249,41 +253,15 @@ static void __init am3517_evm_display_init(void)
        omap_mux_init_gpio(LCD_PANEL_PWR, OMAP_PIN_INPUT_PULLUP);
        omap_mux_init_gpio(LCD_PANEL_BKLIGHT_PWR, OMAP_PIN_INPUT_PULLDOWN);
        omap_mux_init_gpio(LCD_PANEL_PWM, OMAP_PIN_INPUT_PULLDOWN);
-       /*
-        * Enable GPIO 182 = LCD Backlight Power
-        */
-       r = gpio_request(LCD_PANEL_BKLIGHT_PWR, "lcd_backlight_pwr");
+
+       r = gpio_request_array(am3517_evm_dss_gpios,
+                              ARRAY_SIZE(am3517_evm_dss_gpios));
        if (r) {
-               printk(KERN_ERR "failed to get lcd_backlight_pwr\n");
+               printk(KERN_ERR "failed to get DSS panel control GPIOs\n");
                return;
        }
-       gpio_direction_output(LCD_PANEL_BKLIGHT_PWR, 1);
-       /*
-        * Enable GPIO 181 = LCD Panel PWM
-        */
-       r = gpio_request(LCD_PANEL_PWM, "lcd_pwm");
-       if (r) {
-               printk(KERN_ERR "failed to get lcd_pwm\n");
-               goto err_1;
-       }
-       gpio_direction_output(LCD_PANEL_PWM, 1);
-       /*
-        * Enable GPIO 176 = LCD Panel Power enable pin
-        */
-       r = gpio_request(LCD_PANEL_PWR, "lcd_panel_pwr");
-       if (r) {
-               printk(KERN_ERR "failed to get lcd_panel_pwr\n");
-               goto err_2;
-       }
-       gpio_direction_output(LCD_PANEL_PWR, 1);
 
        printk(KERN_INFO "Display initialized successfully\n");
-       return;
-
-err_2:
-       gpio_free(LCD_PANEL_PWM);
-err_1:
-       gpio_free(LCD_PANEL_BKLIGHT_PWR);
 }
 #else
 static void __init am3517_evm_display_init(void) {}
@@ -396,7 +374,7 @@ static struct omap_musb_board_data musb_board_data = {
        .power                  = 500,
        .set_phy_power          = am35x_musb_phy_power,
        .clear_irq              = am35x_musb_clear_irq,
-       .set_mode               = am35x_musb_set_mode,
+       .set_mode               = am35x_set_mode,
        .reset                  = am35x_musb_reset,
 };
 
index f4f8374a02982d59b3bf4f1527834e15eabbc23b..b124bdfb4239ebfcf42c8ca5ab011322cdec3182 100644 (file)
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/smc91x.h>
+#include <linux/gpio.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 
-#include <mach/gpio.h>
 #include <plat/led.h>
 #include <plat/usb.h>
 #include <plat/board.h>
@@ -202,6 +202,7 @@ static inline void __init apollon_init_smc91x(void)
        unsigned int rate;
        struct clk *gpmc_fck;
        int eth_cs;
+       int err;
 
        gpmc_fck = clk_get(NULL, "gpmc_fck");   /* Always on ENABLE_ON_INIT */
        if (IS_ERR(gpmc_fck)) {
@@ -245,15 +246,13 @@ static inline void __init apollon_init_smc91x(void)
        apollon_smc91x_resources[0].end   = base + 0x30f;
        udelay(100);
 
-       omap_mux_init_gpio(74, 0);
-       if (gpio_request(APOLLON_ETHR_GPIO_IRQ, "SMC91x irq") < 0) {
+       omap_mux_init_gpio(APOLLON_ETHR_GPIO_IRQ, 0);
+       err = gpio_request_one(APOLLON_ETHR_GPIO_IRQ, GPIOF_IN, "SMC91x irq");
+       if (err) {
                printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
                        APOLLON_ETHR_GPIO_IRQ);
                gpmc_cs_free(APOLLON_ETH_CS);
-               goto out;
        }
-       gpio_direction_input(APOLLON_ETHR_GPIO_IRQ);
-
 out:
        clk_disable(gpmc_fck);
        clk_put(gpmc_fck);
@@ -280,20 +279,19 @@ static void __init omap_apollon_init_early(void)
        omap2_init_common_devices(NULL, NULL);
 }
 
+static struct gpio apollon_gpio_leds[] __initdata = {
+       { LED0_GPIO13, GPIOF_OUT_INIT_LOW, "LED0" }, /* LED0 - AA10 */
+       { LED1_GPIO14, GPIOF_OUT_INIT_LOW, "LED1" }, /* LED1 - AA6  */
+       { LED2_GPIO15, GPIOF_OUT_INIT_LOW, "LED2" }, /* LED2 - AA4  */
+};
+
 static void __init apollon_led_init(void)
 {
-       /* LED0 - AA10 */
        omap_mux_init_signal("vlynq_clk.gpio_13", 0);
-       gpio_request(LED0_GPIO13, "LED0");
-       gpio_direction_output(LED0_GPIO13, 0);
-       /* LED1  - AA6 */
        omap_mux_init_signal("vlynq_rx1.gpio_14", 0);
-       gpio_request(LED1_GPIO14, "LED1");
-       gpio_direction_output(LED1_GPIO14, 0);
-       /* LED2  - AA4 */
        omap_mux_init_signal("vlynq_rx0.gpio_15", 0);
-       gpio_request(LED2_GPIO15, "LED2");
-       gpio_direction_output(LED2_GPIO15, 0);
+
+       gpio_request_array(apollon_gpio_leds, ARRAY_SIZE(apollon_gpio_leds));
 }
 
 static void __init apollon_usb_init(void)
@@ -301,8 +299,7 @@ static void __init apollon_usb_init(void)
        /* USB device */
        /* DEVICE_SUSPEND */
        omap_mux_init_signal("mcbsp2_clkx.gpio_12", 0);
-       gpio_request(12, "USB suspend");
-       gpio_direction_output(12, 0);
+       gpio_request_one(12, GPIOF_OUT_INIT_LOW, "USB suspend");
        omap2_usbfs_init(&apollon_usb_config);
 }
 
index 02a12b41c0ff0b178e3493706e24c54d68a2bf70..77456dec93ea9640c60a7b48f7dcf3db4b68e568 100644 (file)
@@ -45,8 +45,8 @@
 #include <plat/nand.h>
 #include <plat/gpmc.h>
 #include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 #include <plat/mcspi.h>
 
 #include <mach/hardware.h>
@@ -54,6 +54,7 @@
 #include "mux.h"
 #include "sdram-micron-mt46h32m32lf-6.h"
 #include "hsmmc.h"
+#include "common-board-devices.h"
 
 #define CM_T35_GPIO_PENDOWN    57
 
 #define SB_T35_SMSC911X_CS     4
 #define SB_T35_SMSC911X_GPIO   65
 
-#define NAND_BLOCK_SIZE                SZ_128K
-
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
 #include <linux/smsc911x.h>
+#include <plat/gpmc-smsc911x.h>
 
-static struct smsc911x_platform_config cm_t35_smsc911x_config = {
-       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
-       .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
-       .flags          = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
-       .phy_interface  = PHY_INTERFACE_MODE_MII,
-};
-
-static struct resource cm_t35_smsc911x_resources[] = {
-       {
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .start  = OMAP_GPIO_IRQ(CM_T35_SMSC911X_GPIO),
-               .end    = OMAP_GPIO_IRQ(CM_T35_SMSC911X_GPIO),
-               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
-       },
-};
-
-static struct platform_device cm_t35_smsc911x_device = {
-       .name           = "smsc911x",
+static struct omap_smsc911x_platform_data cm_t35_smsc911x_cfg = {
        .id             = 0,
-       .num_resources  = ARRAY_SIZE(cm_t35_smsc911x_resources),
-       .resource       = cm_t35_smsc911x_resources,
-       .dev            = {
-               .platform_data = &cm_t35_smsc911x_config,
-       },
-};
-
-static struct resource sb_t35_smsc911x_resources[] = {
-       {
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .start  = OMAP_GPIO_IRQ(SB_T35_SMSC911X_GPIO),
-               .end    = OMAP_GPIO_IRQ(SB_T35_SMSC911X_GPIO),
-               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
-       },
+       .cs             = CM_T35_SMSC911X_CS,
+       .gpio_irq       = CM_T35_SMSC911X_GPIO,
+       .gpio_reset     = -EINVAL,
+       .flags          = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
 };
 
-static struct platform_device sb_t35_smsc911x_device = {
-       .name           = "smsc911x",
+static struct omap_smsc911x_platform_data sb_t35_smsc911x_cfg = {
        .id             = 1,
-       .num_resources  = ARRAY_SIZE(sb_t35_smsc911x_resources),
-       .resource       = sb_t35_smsc911x_resources,
-       .dev            = {
-               .platform_data = &cm_t35_smsc911x_config,
-       },
+       .cs             = SB_T35_SMSC911X_CS,
+       .gpio_irq       = SB_T35_SMSC911X_GPIO,
+       .gpio_reset     = -EINVAL,
+       .flags          = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
 };
 
-static void __init cm_t35_init_smsc911x(struct platform_device *dev,
-                                       int cs, int irq_gpio)
-{
-       unsigned long cs_mem_base;
-
-       if (gpmc_cs_request(cs, SZ_16M, &cs_mem_base) < 0) {
-               pr_err("CM-T35: Failed request for GPMC mem for smsc911x\n");
-               return;
-       }
-
-       dev->resource[0].start = cs_mem_base + 0x0;
-       dev->resource[0].end   = cs_mem_base + 0xff;
-
-       if ((gpio_request(irq_gpio, "ETH IRQ") == 0) &&
-           (gpio_direction_input(irq_gpio) == 0)) {
-               gpio_export(irq_gpio, 0);
-       } else {
-               pr_err("CM-T35: could not obtain gpio for SMSC911X IRQ\n");
-               return;
-       }
-
-       platform_device_register(dev);
-}
-
 static void __init cm_t35_init_ethernet(void)
 {
-       cm_t35_init_smsc911x(&cm_t35_smsc911x_device,
-                            CM_T35_SMSC911X_CS, CM_T35_SMSC911X_GPIO);
-       cm_t35_init_smsc911x(&sb_t35_smsc911x_device,
-                            SB_T35_SMSC911X_CS, SB_T35_SMSC911X_GPIO);
+       gpmc_smsc911x_init(&cm_t35_smsc911x_cfg);
+       gpmc_smsc911x_init(&sb_t35_smsc911x_cfg);
 }
 #else
 static inline void __init cm_t35_init_ethernet(void) { return; }
@@ -235,69 +176,10 @@ static void __init cm_t35_init_nand(void)
 static inline void cm_t35_init_nand(void) {}
 #endif
 
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
-       defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
-#include <linux/spi/ads7846.h>
-
-static struct omap2_mcspi_device_config ads7846_mcspi_config = {
-       .turbo_mode     = 0,
-       .single_channel = 1,    /* 0: slave, 1: master */
-};
-
-static int ads7846_get_pendown_state(void)
-{
-       return !gpio_get_value(CM_T35_GPIO_PENDOWN);
-}
-
-static struct ads7846_platform_data ads7846_config = {
-       .x_max                  = 0x0fff,
-       .y_max                  = 0x0fff,
-       .x_plate_ohms           = 180,
-       .pressure_max           = 255,
-       .debounce_max           = 10,
-       .debounce_tol           = 3,
-       .debounce_rep           = 1,
-       .get_pendown_state      = ads7846_get_pendown_state,
-       .keep_vref_on           = 1,
-};
-
-static struct spi_board_info cm_t35_spi_board_info[] __initdata = {
-       {
-               .modalias               = "ads7846",
-               .bus_num                = 1,
-               .chip_select            = 0,
-               .max_speed_hz           = 1500000,
-               .controller_data        = &ads7846_mcspi_config,
-               .irq                    = OMAP_GPIO_IRQ(CM_T35_GPIO_PENDOWN),
-               .platform_data          = &ads7846_config,
-       },
-};
-
-static void __init cm_t35_init_ads7846(void)
-{
-       if ((gpio_request(CM_T35_GPIO_PENDOWN, "ADS7846_PENDOWN") == 0) &&
-           (gpio_direction_input(CM_T35_GPIO_PENDOWN) == 0)) {
-               gpio_export(CM_T35_GPIO_PENDOWN, 0);
-       } else {
-               pr_err("CM-T35: could not obtain gpio for ADS7846_PENDOWN\n");
-               return;
-       }
-
-       spi_register_board_info(cm_t35_spi_board_info,
-                               ARRAY_SIZE(cm_t35_spi_board_info));
-}
-#else
-static inline void cm_t35_init_ads7846(void) {}
-#endif
-
 #define CM_T35_LCD_EN_GPIO 157
 #define CM_T35_LCD_BL_GPIO 58
 #define CM_T35_DVI_EN_GPIO 54
 
-static int lcd_bl_gpio;
-static int lcd_en_gpio;
-static int dvi_en_gpio;
-
 static int lcd_enabled;
 static int dvi_enabled;
 
@@ -308,8 +190,8 @@ static int cm_t35_panel_enable_lcd(struct omap_dss_device *dssdev)
                return -EINVAL;
        }
 
-       gpio_set_value(lcd_en_gpio, 1);
-       gpio_set_value(lcd_bl_gpio, 1);
+       gpio_set_value(CM_T35_LCD_EN_GPIO, 1);
+       gpio_set_value(CM_T35_LCD_BL_GPIO, 1);
 
        lcd_enabled = 1;
 
@@ -320,8 +202,8 @@ static void cm_t35_panel_disable_lcd(struct omap_dss_device *dssdev)
 {
        lcd_enabled = 0;
 
-       gpio_set_value(lcd_bl_gpio, 0);
-       gpio_set_value(lcd_en_gpio, 0);
+       gpio_set_value(CM_T35_LCD_BL_GPIO, 0);
+       gpio_set_value(CM_T35_LCD_EN_GPIO, 0);
 }
 
 static int cm_t35_panel_enable_dvi(struct omap_dss_device *dssdev)
@@ -331,7 +213,7 @@ static int cm_t35_panel_enable_dvi(struct omap_dss_device *dssdev)
                return -EINVAL;
        }
 
-       gpio_set_value(dvi_en_gpio, 0);
+       gpio_set_value(CM_T35_DVI_EN_GPIO, 0);
        dvi_enabled = 1;
 
        return 0;
@@ -339,7 +221,7 @@ static int cm_t35_panel_enable_dvi(struct omap_dss_device *dssdev)
 
 static void cm_t35_panel_disable_dvi(struct omap_dss_device *dssdev)
 {
-       gpio_set_value(dvi_en_gpio, 1);
+       gpio_set_value(CM_T35_DVI_EN_GPIO, 1);
        dvi_enabled = 0;
 }
 
@@ -421,62 +303,38 @@ static struct spi_board_info cm_t35_lcd_spi_board_info[] __initdata = {
        },
 };
 
+static struct gpio cm_t35_dss_gpios[] __initdata = {
+       { CM_T35_LCD_EN_GPIO, GPIOF_OUT_INIT_LOW,  "lcd enable"    },
+       { CM_T35_LCD_BL_GPIO, GPIOF_OUT_INIT_LOW,  "lcd bl enable" },
+       { CM_T35_DVI_EN_GPIO, GPIOF_OUT_INIT_HIGH, "dvi enable"    },
+};
+
 static void __init cm_t35_init_display(void)
 {
        int err;
 
-       lcd_en_gpio = CM_T35_LCD_EN_GPIO;
-       lcd_bl_gpio = CM_T35_LCD_BL_GPIO;
-       dvi_en_gpio = CM_T35_DVI_EN_GPIO;
-
        spi_register_board_info(cm_t35_lcd_spi_board_info,
                                ARRAY_SIZE(cm_t35_lcd_spi_board_info));
 
-       err = gpio_request(lcd_en_gpio, "LCD RST");
-       if (err) {
-               pr_err("CM-T35: failed to get LCD reset GPIO\n");
-               goto out;
-       }
-
-       err = gpio_request(lcd_bl_gpio, "LCD BL");
+       err = gpio_request_array(cm_t35_dss_gpios,
+                                ARRAY_SIZE(cm_t35_dss_gpios));
        if (err) {
-               pr_err("CM-T35: failed to get LCD backlight control GPIO\n");
-               goto err_lcd_bl;
-       }
-
-       err = gpio_request(dvi_en_gpio, "DVI EN");
-       if (err) {
-               pr_err("CM-T35: failed to get DVI reset GPIO\n");
-               goto err_dvi_en;
+               pr_err("CM-T35: failed to request DSS control GPIOs\n");
+               return;
        }
 
-       gpio_export(lcd_en_gpio, 0);
-       gpio_export(lcd_bl_gpio, 0);
-       gpio_export(dvi_en_gpio, 0);
-       gpio_direction_output(lcd_en_gpio, 0);
-       gpio_direction_output(lcd_bl_gpio, 0);
-       gpio_direction_output(dvi_en_gpio, 1);
+       gpio_export(CM_T35_LCD_EN_GPIO, 0);
+       gpio_export(CM_T35_LCD_BL_GPIO, 0);
+       gpio_export(CM_T35_DVI_EN_GPIO, 0);
 
        msleep(50);
-       gpio_set_value(lcd_en_gpio, 1);
+       gpio_set_value(CM_T35_LCD_EN_GPIO, 1);
 
        err = omap_display_init(&cm_t35_dss_data);
        if (err) {
                pr_err("CM-T35: failed to register DSS device\n");
-               goto err_dev_reg;
+               gpio_free_array(cm_t35_dss_gpios, ARRAY_SIZE(cm_t35_dss_gpios));
        }
-
-       return;
-
-err_dev_reg:
-       gpio_free(dvi_en_gpio);
-err_dvi_en:
-       gpio_free(lcd_bl_gpio);
-err_lcd_bl:
-       gpio_free(lcd_en_gpio);
-out:
-
-       return;
 }
 
 static struct regulator_consumer_supply cm_t35_vmmc1_supply = {
@@ -609,10 +467,8 @@ static int cm_t35_twl_gpio_setup(struct device *dev, unsigned gpio,
 {
        int wlan_rst = gpio + 2;
 
-       if ((gpio_request(wlan_rst, "WLAN RST") == 0) &&
-           (gpio_direction_output(wlan_rst, 1) == 0)) {
+       if (gpio_request_one(wlan_rst, GPIOF_OUT_INIT_HIGH, "WLAN RST") == 0) {
                gpio_export(wlan_rst, 0);
-
                udelay(10);
                gpio_set_value(wlan_rst, 0);
                udelay(10);
@@ -653,19 +509,9 @@ static struct twl4030_platform_data cm_t35_twldata = {
        .vpll2          = &cm_t35_vpll2,
 };
 
-static struct i2c_board_info __initdata cm_t35_i2c_boardinfo[] = {
-       {
-               I2C_BOARD_INFO("tps65930", 0x48),
-               .flags          = I2C_CLIENT_WAKE,
-               .irq            = INT_34XX_SYS_NIRQ,
-               .platform_data  = &cm_t35_twldata,
-       },
-};
-
 static void __init cm_t35_init_i2c(void)
 {
-       omap_register_i2c_bus(1, 2600, cm_t35_i2c_boardinfo,
-                             ARRAY_SIZE(cm_t35_i2c_boardinfo));
+       omap3_pmic_init("tps65930", &cm_t35_twldata);
 }
 
 static void __init cm_t35_init_early(void)
@@ -775,12 +621,6 @@ static struct omap_board_mux board_mux[] __initdata = {
 };
 #endif
 
-static struct omap_musb_board_data musb_board_data = {
-       .interface_type         = MUSB_INTERFACE_ULPI,
-       .mode                   = MUSB_OTG,
-       .power                  = 100,
-};
-
 static struct omap_board_config_kernel cm_t35_config[] __initdata = {
 };
 
@@ -792,12 +632,12 @@ static void __init cm_t35_init(void)
        omap_serial_init();
        cm_t35_init_i2c();
        cm_t35_init_nand();
-       cm_t35_init_ads7846();
+       omap_ads7846_init(1, CM_T35_GPIO_PENDOWN, 0, NULL);
        cm_t35_init_ethernet();
        cm_t35_init_led();
        cm_t35_init_display();
 
-       usb_musb_init(&musb_board_data);
+       usb_musb_init(NULL);
        usbhs_init(&usbhs_bdata);
 }
 
index a27e3eee829259e7c7f608200f593a0d1400f385..c3a9fd35034a3b40ad33df50e2573c7f5a000cbb 100644 (file)
@@ -48,6 +48,7 @@
 
 #include "mux.h"
 #include "control.h"
+#include "common-board-devices.h"
 
 #if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
 static struct gpio_led cm_t3517_leds[] = {
@@ -148,14 +149,13 @@ static void __init cm_t3517_init_rtc(void)
 {
        int err;
 
-       err = gpio_request(RTC_CS_EN_GPIO, "rtc cs en");
+       err = gpio_request_one(RTC_CS_EN_GPIO, GPIOF_OUT_INIT_HIGH,
+                              "rtc cs en");
        if (err) {
                pr_err("CM-T3517: rtc cs en gpio request failed: %d\n", err);
                return;
        }
 
-       gpio_direction_output(RTC_CS_EN_GPIO, 1);
-
        platform_device_register(&cm_t3517_rtc_device);
 }
 #else
@@ -178,15 +178,15 @@ static struct usbhs_omap_board_data cm_t3517_ehci_pdata __initdata = {
        .reset_gpio_port[2]  = -EINVAL,
 };
 
-static int cm_t3517_init_usbh(void)
+static int __init cm_t3517_init_usbh(void)
 {
        int err;
 
-       err = gpio_request(USB_HUB_RESET_GPIO, "usb hub rst");
+       err = gpio_request_one(USB_HUB_RESET_GPIO, GPIOF_OUT_INIT_LOW,
+                              "usb hub rst");
        if (err) {
                pr_err("CM-T3517: usb hub rst gpio request failed: %d\n", err);
        } else {
-               gpio_direction_output(USB_HUB_RESET_GPIO, 0);
                udelay(10);
                gpio_set_value(USB_HUB_RESET_GPIO, 1);
                msleep(1);
@@ -204,8 +204,6 @@ static inline int cm_t3517_init_usbh(void)
 #endif
 
 #if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE)
-#define NAND_BLOCK_SIZE                SZ_128K
-
 static struct mtd_partition cm_t3517_nand_partitions[] = {
        {
                .name           = "xloader",
index 65f9fde2c567253a5f2e5cf8f73f32c624dc721d..34956ec832960f1e215241f196ef2d89b3006d91 100644 (file)
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 
 #include <plat/mcspi.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
 #include <linux/dm9000.h>
 #include <linux/interrupt.h>
 
@@ -60,8 +59,7 @@
 #include "mux.h"
 #include "hsmmc.h"
 #include "timer-gp.h"
-
-#define NAND_BLOCK_SIZE                SZ_128K
+#include "common-board-devices.h"
 
 #define OMAP_DM9000_GPIO_IRQ   25
 #define OMAP3_DEVKIT_TS_GPIO   27
@@ -97,13 +95,6 @@ static struct mtd_partition devkit8000_nand_partitions[] = {
        },
 };
 
-static struct omap_nand_platform_data devkit8000_nand_data = {
-       .options        = NAND_BUSWIDTH_16,
-       .parts          = devkit8000_nand_partitions,
-       .nr_parts       = ARRAY_SIZE(devkit8000_nand_partitions),
-       .dma_channel    = -1,           /* disable DMA in OMAP NAND driver */
-};
-
 static struct omap2_hsmmc_info mmc[] = {
        {
                .mmc            = 1,
@@ -249,7 +240,7 @@ static int devkit8000_twl_gpio_setup(struct device *dev,
        /* TWL4030_GPIO_MAX + 0 is "LCD_PWREN" (out, active high) */
        devkit8000_lcd_device.reset_gpio = gpio + TWL4030_GPIO_MAX + 0;
        ret = gpio_request_one(devkit8000_lcd_device.reset_gpio,
-                       GPIOF_DIR_OUT | GPIOF_INIT_LOW, "LCD_PWREN");
+                              GPIOF_OUT_INIT_LOW, "LCD_PWREN");
        if (ret < 0) {
                devkit8000_lcd_device.reset_gpio = -EINVAL;
                printk(KERN_ERR "Failed to request GPIO for LCD_PWRN\n");
@@ -258,7 +249,7 @@ static int devkit8000_twl_gpio_setup(struct device *dev,
        /* gpio + 7 is "DVI_PD" (out, active low) */
        devkit8000_dvi_device.reset_gpio = gpio + 7;
        ret = gpio_request_one(devkit8000_dvi_device.reset_gpio,
-                       GPIOF_DIR_OUT | GPIOF_INIT_LOW, "DVI PowerDown");
+                              GPIOF_OUT_INIT_LOW, "DVI PowerDown");
        if (ret < 0) {
                devkit8000_dvi_device.reset_gpio = -EINVAL;
                printk(KERN_ERR "Failed to request GPIO for DVI PowerDown\n");
@@ -366,19 +357,9 @@ static struct twl4030_platform_data devkit8000_twldata = {
        .keypad         = &devkit8000_kp_data,
 };
 
-static struct i2c_board_info __initdata devkit8000_i2c_boardinfo[] = {
-       {
-               I2C_BOARD_INFO("tps65930", 0x48),
-               .flags = I2C_CLIENT_WAKE,
-               .irq = INT_34XX_SYS_NIRQ,
-               .platform_data = &devkit8000_twldata,
-       },
-};
-
 static int __init devkit8000_i2c_init(void)
 {
-       omap_register_i2c_bus(1, 2600, devkit8000_i2c_boardinfo,
-                       ARRAY_SIZE(devkit8000_i2c_boardinfo));
+       omap3_pmic_init("tps65930", &devkit8000_twldata);
        /* Bus 3 is attached to the DVI port where devices like the pico DLP
         * projector don't work reliably with 400kHz */
        omap_register_i2c_bus(3, 400, NULL, 0);
@@ -463,56 +444,6 @@ static void __init devkit8000_init_irq(void)
 #endif
 }
 
-static void __init devkit8000_ads7846_init(void)
-{
-       int gpio = OMAP3_DEVKIT_TS_GPIO;
-       int ret;
-
-       ret = gpio_request(gpio, "ads7846_pen_down");
-       if (ret < 0) {
-               printk(KERN_ERR "Failed to request GPIO %d for "
-                               "ads7846 pen down IRQ\n", gpio);
-               return;
-       }
-
-       gpio_direction_input(gpio);
-}
-
-static int ads7846_get_pendown_state(void)
-{
-       return !gpio_get_value(OMAP3_DEVKIT_TS_GPIO);
-}
-
-static struct ads7846_platform_data ads7846_config = {
-       .x_max                  = 0x0fff,
-       .y_max                  = 0x0fff,
-       .x_plate_ohms           = 180,
-       .pressure_max           = 255,
-       .debounce_max           = 10,
-       .debounce_tol           = 5,
-       .debounce_rep           = 1,
-       .get_pendown_state      = ads7846_get_pendown_state,
-       .keep_vref_on           = 1,
-       .settle_delay_usecs     = 150,
-};
-
-static struct omap2_mcspi_device_config ads7846_mcspi_config = {
-       .turbo_mode     = 0,
-       .single_channel = 1,    /* 0: slave, 1: master */
-};
-
-static struct spi_board_info devkit8000_spi_board_info[] __initdata = {
-       {
-               .modalias               = "ads7846",
-               .bus_num                = 2,
-               .chip_select            = 0,
-               .max_speed_hz           = 1500000,
-               .controller_data        = &ads7846_mcspi_config,
-               .irq                    = OMAP_GPIO_IRQ(OMAP3_DEVKIT_TS_GPIO),
-               .platform_data          = &ads7846_config,
-       }
-};
-
 #define OMAP_DM9000_BASE       0x2c000000
 
 static struct resource omap_dm9000_resources[] = {
@@ -550,14 +481,14 @@ static void __init omap_dm9000_init(void)
 {
        unsigned char *eth_addr = omap_dm9000_platdata.dev_addr;
        struct omap_die_id odi;
+       int ret;
 
-       if (gpio_request(OMAP_DM9000_GPIO_IRQ, "dm9000 irq") < 0) {
+       ret = gpio_request_one(OMAP_DM9000_GPIO_IRQ, GPIOF_IN, "dm9000 irq");
+       if (ret < 0) {
                printk(KERN_ERR "Failed to request GPIO%d for dm9000 IRQ\n",
                        OMAP_DM9000_GPIO_IRQ);
                return;
-               }
-
-       gpio_direction_input(OMAP_DM9000_GPIO_IRQ);
+       }
 
        /* init the mac address using DIE id */
        omap_get_die_id(&odi);
@@ -576,45 +507,6 @@ static struct platform_device *devkit8000_devices[] __initdata = {
        &omap_dm9000_dev,
 };
 
-static void __init devkit8000_flash_init(void)
-{
-       u8 cs = 0;
-       u8 nandcs = GPMC_CS_NUM + 1;
-
-       /* find out the chip-select on which NAND exists */
-       while (cs < GPMC_CS_NUM) {
-               u32 ret = 0;
-               ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-
-               if ((ret & 0xC00) == 0x800) {
-                       printk(KERN_INFO "Found NAND on CS%d\n", cs);
-                       if (nandcs > GPMC_CS_NUM)
-                               nandcs = cs;
-               }
-               cs++;
-       }
-
-       if (nandcs > GPMC_CS_NUM) {
-               printk(KERN_INFO "NAND: Unable to find configuration "
-                                "in GPMC\n ");
-               return;
-       }
-
-       if (nandcs < GPMC_CS_NUM) {
-               devkit8000_nand_data.cs = nandcs;
-
-               printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-               if (gpmc_nand_init(&devkit8000_nand_data) < 0)
-                       printk(KERN_ERR "Unable to register NAND device\n");
-       }
-}
-
-static struct omap_musb_board_data musb_board_data = {
-       .interface_type         = MUSB_INTERFACE_ULPI,
-       .mode                   = MUSB_OTG,
-       .power                  = 100,
-};
-
 static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
 
        .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
@@ -795,14 +687,13 @@ static void __init devkit8000_init(void)
                        ARRAY_SIZE(devkit8000_devices));
 
        omap_display_init(&devkit8000_dss_data);
-       spi_register_board_info(devkit8000_spi_board_info,
-       ARRAY_SIZE(devkit8000_spi_board_info));
 
-       devkit8000_ads7846_init();
+       omap_ads7846_init(2, OMAP3_DEVKIT_TS_GPIO, 0, NULL);
 
-       usb_musb_init(&musb_board_data);
+       usb_musb_init(NULL);
        usbhs_init(&usbhs_bdata);
-       devkit8000_flash_init();
+       omap_nand_flash_init(NAND_BUSWIDTH_16, devkit8000_nand_partitions,
+                            ARRAY_SIZE(devkit8000_nand_partitions));
 
        /* Ensure SDRC pins are mux'd for self-refresh */
        omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
index 34cf982b96798edf3e24fd3816d0248b034c75e4..0c1bfca3f731cfdd4b8a9fa7aaa0793cca01e18b 100644 (file)
 #include <plat/common.h>
 #include <plat/gpmc.h>
 #include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 #include <plat/onenand.h>
 
 #include "mux.h"
 #include "hsmmc.h"
 #include "sdram-numonyx-m65kxxxxam.h"
+#include "common-board-devices.h"
 
 #define IGEP2_SMSC911X_CS       5
 #define IGEP2_SMSC911X_GPIO     176
 #define IGEP2_RC_GPIO_WIFI_NRESET  139
 #define IGEP2_RC_GPIO_BT_NRESET    137
 
+#define IGEP3_GPIO_LED0_GREEN  54
+#define IGEP3_GPIO_LED0_RED    53
+#define IGEP3_GPIO_LED1_RED    16
+#define IGEP3_GPIO_USBH_NRESET  183
+
 /*
  * IGEP2 Hardware Revision Table
  *
@@ -68,6 +74,7 @@
 
 #define IGEP2_BOARD_HWREV_B    0
 #define IGEP2_BOARD_HWREV_C    1
+#define IGEP3_BOARD_HWREV      2
 
 static u8 hwrev;
 
@@ -75,24 +82,29 @@ static void __init igep2_get_revision(void)
 {
        u8 ret;
 
+       if (machine_is_igep0030()) {
+               hwrev = IGEP3_BOARD_HWREV;
+               return;
+       }
+
        omap_mux_init_gpio(IGEP2_GPIO_LED1_RED, OMAP_PIN_INPUT);
 
-       if ((gpio_request(IGEP2_GPIO_LED1_RED, "GPIO_HW0_REV") == 0) &&
-           (gpio_direction_input(IGEP2_GPIO_LED1_RED) == 0)) {
-               ret = gpio_get_value(IGEP2_GPIO_LED1_RED);
-               if (ret == 0) {
-                       pr_info("IGEP2: Hardware Revision C (B-NON compatible)\n");
-                       hwrev = IGEP2_BOARD_HWREV_C;
-               } else if (ret ==  1) {
-                       pr_info("IGEP2: Hardware Revision B/C (B compatible)\n");
-                       hwrev = IGEP2_BOARD_HWREV_B;
-               } else {
-                       pr_err("IGEP2: Unknown Hardware Revision\n");
-                       hwrev = -1;
-               }
-       } else {
+       if (gpio_request_one(IGEP2_GPIO_LED1_RED, GPIOF_IN, "GPIO_HW0_REV")) {
                pr_warning("IGEP2: Could not obtain gpio GPIO_HW0_REV\n");
                pr_err("IGEP2: Unknown Hardware Revision\n");
+               return;
+       }
+
+       ret = gpio_get_value(IGEP2_GPIO_LED1_RED);
+       if (ret == 0) {
+               pr_info("IGEP2: Hardware Revision C (B-NON compatible)\n");
+               hwrev = IGEP2_BOARD_HWREV_C;
+       } else if (ret ==  1) {
+               pr_info("IGEP2: Hardware Revision B/C (B compatible)\n");
+               hwrev = IGEP2_BOARD_HWREV_B;
+       } else {
+               pr_err("IGEP2: Unknown Hardware Revision\n");
+               hwrev = -1;
        }
 
        gpio_free(IGEP2_GPIO_LED1_RED);
@@ -111,7 +123,7 @@ static void __init igep2_get_revision(void)
  * So MTD regards it as 4KiB page size and 256KiB block size 64*(2*2048)
  */
 
-static struct mtd_partition igep2_onenand_partitions[] = {
+static struct mtd_partition igep_onenand_partitions[] = {
        {
                .name           = "X-Loader",
                .offset         = 0,
@@ -139,21 +151,21 @@ static struct mtd_partition igep2_onenand_partitions[] = {
        },
 };
 
-static struct omap_onenand_platform_data igep2_onenand_data = {
-       .parts = igep2_onenand_partitions,
-       .nr_parts = ARRAY_SIZE(igep2_onenand_partitions),
+static struct omap_onenand_platform_data igep_onenand_data = {
+       .parts = igep_onenand_partitions,
+       .nr_parts = ARRAY_SIZE(igep_onenand_partitions),
        .dma_channel    = -1,   /* disable DMA in OMAP OneNAND driver */
 };
 
-static struct platform_device igep2_onenand_device = {
+static struct platform_device igep_onenand_device = {
        .name           = "omap2-onenand",
        .id             = -1,
        .dev = {
-               .platform_data = &igep2_onenand_data,
+               .platform_data = &igep_onenand_data,
        },
 };
 
-static void __init igep2_flash_init(void)
+static void __init igep_flash_init(void)
 {
        u8 cs = 0;
        u8 onenandcs = GPMC_CS_NUM + 1;
@@ -165,7 +177,7 @@ static void __init igep2_flash_init(void)
                /* Check if NAND/oneNAND is configured */
                if ((ret & 0xC00) == 0x800)
                        /* NAND found */
-                       pr_err("IGEP2: Unsupported NAND found\n");
+                       pr_err("IGEP: Unsupported NAND found\n");
                else {
                        ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
                        if ((ret & 0x3F) == (ONENAND_MAP >> 24))
@@ -175,85 +187,46 @@ static void __init igep2_flash_init(void)
        }
 
        if (onenandcs > GPMC_CS_NUM) {
-               pr_err("IGEP2: Unable to find configuration in GPMC\n");
+               pr_err("IGEP: Unable to find configuration in GPMC\n");
                return;
        }
 
-       igep2_onenand_data.cs = onenandcs;
+       igep_onenand_data.cs = onenandcs;
 
-       if (platform_device_register(&igep2_onenand_device) < 0)
-               pr_err("IGEP2: Unable to register OneNAND device\n");
+       if (platform_device_register(&igep_onenand_device) < 0)
+               pr_err("IGEP: Unable to register OneNAND device\n");
 }
 
 #else
-static void __init igep2_flash_init(void) {}
+static void __init igep_flash_init(void) {}
 #endif
 
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
 
 #include <linux/smsc911x.h>
+#include <plat/gpmc-smsc911x.h>
 
-static struct smsc911x_platform_config igep2_smsc911x_config = {
-       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
-       .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
-       .flags          = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS  ,
-       .phy_interface  = PHY_INTERFACE_MODE_MII,
-};
-
-static struct resource igep2_smsc911x_resources[] = {
-       {
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .start  = OMAP_GPIO_IRQ(IGEP2_SMSC911X_GPIO),
-               .end    = OMAP_GPIO_IRQ(IGEP2_SMSC911X_GPIO),
-               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
-       },
-};
-
-static struct platform_device igep2_smsc911x_device = {
-       .name           = "smsc911x",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(igep2_smsc911x_resources),
-       .resource       = igep2_smsc911x_resources,
-       .dev            = {
-               .platform_data = &igep2_smsc911x_config,
-       },
+static struct omap_smsc911x_platform_data smsc911x_cfg = {
+       .cs             = IGEP2_SMSC911X_CS,
+       .gpio_irq       = IGEP2_SMSC911X_GPIO,
+       .gpio_reset     = -EINVAL,
+       .flags          = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
 };
 
 static inline void __init igep2_init_smsc911x(void)
 {
-       unsigned long cs_mem_base;
-
-       if (gpmc_cs_request(IGEP2_SMSC911X_CS, SZ_16M, &cs_mem_base) < 0) {
-               pr_err("IGEP v2: Failed request for GPMC mem for smsc911x\n");
-               gpmc_cs_free(IGEP2_SMSC911X_CS);
-               return;
-       }
-
-       igep2_smsc911x_resources[0].start = cs_mem_base + 0x0;
-       igep2_smsc911x_resources[0].end   = cs_mem_base + 0xff;
-
-       if ((gpio_request(IGEP2_SMSC911X_GPIO, "SMSC911X IRQ") == 0) &&
-           (gpio_direction_input(IGEP2_SMSC911X_GPIO) == 0)) {
-               gpio_export(IGEP2_SMSC911X_GPIO, 0);
-       } else {
-               pr_err("IGEP v2: Could not obtain gpio for for SMSC911X IRQ\n");
-               return;
-       }
-
-       platform_device_register(&igep2_smsc911x_device);
+       gpmc_smsc911x_init(&smsc911x_cfg);
 }
 
 #else
 static inline void __init igep2_init_smsc911x(void) { }
 #endif
 
-static struct regulator_consumer_supply igep2_vmmc1_supply =
+static struct regulator_consumer_supply igep_vmmc1_supply =
        REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0");
 
 /* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
-static struct regulator_init_data igep2_vmmc1 = {
+static struct regulator_init_data igep_vmmc1 = {
        .constraints = {
                .min_uV                 = 1850000,
                .max_uV                 = 3150000,
@@ -264,13 +237,13 @@ static struct regulator_init_data igep2_vmmc1 = {
                                        | REGULATOR_CHANGE_STATUS,
        },
        .num_consumer_supplies  = 1,
-       .consumer_supplies      = &igep2_vmmc1_supply,
+       .consumer_supplies      = &igep_vmmc1_supply,
 };
 
-static struct regulator_consumer_supply igep2_vio_supply =
+static struct regulator_consumer_supply igep_vio_supply =
        REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.1");
 
-static struct regulator_init_data igep2_vio = {
+static struct regulator_init_data igep_vio = {
        .constraints = {
                .min_uV                 = 1800000,
                .max_uV                 = 1800000,
@@ -282,34 +255,34 @@ static struct regulator_init_data igep2_vio = {
                                        | REGULATOR_CHANGE_STATUS,
        },
        .num_consumer_supplies  = 1,
-       .consumer_supplies      = &igep2_vio_supply,
+       .consumer_supplies      = &igep_vio_supply,
 };
 
-static struct regulator_consumer_supply igep2_vmmc2_supply =
+static struct regulator_consumer_supply igep_vmmc2_supply =
        REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1");
 
-static struct regulator_init_data igep2_vmmc2 = {
+static struct regulator_init_data igep_vmmc2 = {
        .constraints            = {
                .valid_modes_mask       = REGULATOR_MODE_NORMAL,
                .always_on              = 1,
        },
        .num_consumer_supplies  = 1,
-       .consumer_supplies      = &igep2_vmmc2_supply,
+       .consumer_supplies      = &igep_vmmc2_supply,
 };
 
-static struct fixed_voltage_config igep2_vwlan = {
+static struct fixed_voltage_config igep_vwlan = {
        .supply_name            = "vwlan",
        .microvolts             = 3300000,
        .gpio                   = -EINVAL,
        .enabled_at_boot        = 1,
-       .init_data              = &igep2_vmmc2,
+       .init_data              = &igep_vmmc2,
 };
 
-static struct platform_device igep2_vwlan_device = {
+static struct platform_device igep_vwlan_device = {
        .name           = "reg-fixed-voltage",
        .id             = 0,
        .dev = {
-               .platform_data  = &igep2_vwlan,
+               .platform_data  = &igep_vwlan,
        },
 };
 
@@ -334,20 +307,17 @@ static struct omap2_hsmmc_info mmc[] = {
 #if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
 #include <linux/leds.h>
 
-static struct gpio_led igep2_gpio_leds[] = {
+static struct gpio_led igep_gpio_leds[] = {
        [0] = {
                .name                   = "gpio-led:red:d0",
-               .gpio                   = IGEP2_GPIO_LED0_RED,
                .default_trigger        = "default-off"
        },
        [1] = {
                .name                   = "gpio-led:green:d0",
-               .gpio                   = IGEP2_GPIO_LED0_GREEN,
                .default_trigger        = "default-off",
        },
        [2] = {
                .name                   = "gpio-led:red:d1",
-               .gpio                   = IGEP2_GPIO_LED1_RED,
                .default_trigger        = "default-off",
        },
        [3] = {
@@ -358,94 +328,119 @@ static struct gpio_led igep2_gpio_leds[] = {
        },
 };
 
-static struct gpio_led_platform_data igep2_led_pdata = {
-       .leds           = igep2_gpio_leds,
-       .num_leds       = ARRAY_SIZE(igep2_gpio_leds),
+static struct gpio_led_platform_data igep_led_pdata = {
+       .leds           = igep_gpio_leds,
+       .num_leds       = ARRAY_SIZE(igep_gpio_leds),
 };
 
-static struct platform_device igep2_led_device = {
+static struct platform_device igep_led_device = {
         .name   = "leds-gpio",
         .id     = -1,
         .dev    = {
-                .platform_data  =  &igep2_led_pdata,
+                .platform_data  =  &igep_led_pdata,
        },
 };
 
-static void __init igep2_leds_init(void)
+static void __init igep_leds_init(void)
 {
-       platform_device_register(&igep2_led_device);
+       if (machine_is_igep0020()) {
+               igep_gpio_leds[0].gpio = IGEP2_GPIO_LED0_RED;
+               igep_gpio_leds[1].gpio = IGEP2_GPIO_LED0_GREEN;
+               igep_gpio_leds[2].gpio = IGEP2_GPIO_LED1_RED;
+       } else {
+               igep_gpio_leds[0].gpio = IGEP3_GPIO_LED0_RED;
+               igep_gpio_leds[1].gpio = IGEP3_GPIO_LED0_GREEN;
+               igep_gpio_leds[2].gpio = IGEP3_GPIO_LED1_RED;
+       }
+
+       platform_device_register(&igep_led_device);
 }
 
 #else
-static inline void igep2_leds_init(void)
+static struct gpio igep_gpio_leds[] __initdata = {
+       { -EINVAL,      GPIOF_OUT_INIT_LOW, "gpio-led:red:d0"   },
+       { -EINVAL,      GPIOF_OUT_INIT_LOW, "gpio-led:green:d0" },
+       { -EINVAL,      GPIOF_OUT_INIT_LOW, "gpio-led:red:d1"   },
+};
+
+static inline void igep_leds_init(void)
 {
-       if ((gpio_request(IGEP2_GPIO_LED0_RED, "gpio-led:red:d0") == 0) &&
-           (gpio_direction_output(IGEP2_GPIO_LED0_RED, 0) == 0))
-               gpio_export(IGEP2_GPIO_LED0_RED, 0);
-       else
-               pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_RED\n");
+       int i;
 
-       if ((gpio_request(IGEP2_GPIO_LED0_GREEN, "gpio-led:green:d0") == 0) &&
-           (gpio_direction_output(IGEP2_GPIO_LED0_GREEN, 0) == 0))
-               gpio_export(IGEP2_GPIO_LED0_GREEN, 0);
-       else
-               pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_GREEN\n");
+       if (machine_is_igep0020()) {
+               igep_gpio_leds[0].gpio = IGEP2_GPIO_LED0_RED;
+               igep_gpio_leds[1].gpio = IGEP2_GPIO_LED0_GREEN;
+               igep_gpio_leds[2].gpio = IGEP2_GPIO_LED1_RED;
+       } else {
+               igep_gpio_leds[0].gpio = IGEP3_GPIO_LED0_RED;
+               igep_gpio_leds[1].gpio = IGEP3_GPIO_LED0_GREEN;
+               igep_gpio_leds[2].gpio = IGEP3_GPIO_LED1_RED;
+       }
 
-       if ((gpio_request(IGEP2_GPIO_LED1_RED, "gpio-led:red:d1") == 0) &&
-           (gpio_direction_output(IGEP2_GPIO_LED1_RED, 0) == 0))
-               gpio_export(IGEP2_GPIO_LED1_RED, 0);
-       else
-               pr_warning("IGEP v2: Could not obtain gpio GPIO_LED1_RED\n");
+       if (gpio_request_array(igep_gpio_leds, ARRAY_SIZE(igep_gpio_leds))) {
+               pr_warning("IGEP v2: Could not obtain leds gpios\n");
+               return;
+       }
 
+       for (i = 0; i < ARRAY_SIZE(igep_gpio_leds); i++)
+               gpio_export(igep_gpio_leds[i].gpio, 0);
 }
 #endif
 
-static int igep2_twl_gpio_setup(struct device *dev,
+static struct gpio igep2_twl_gpios[] = {
+       { -EINVAL, GPIOF_IN,            "GPIO_EHCI_NOC"  },
+       { -EINVAL, GPIOF_OUT_INIT_LOW,  "GPIO_USBH_CPEN" },
+};
+
+static int igep_twl_gpio_setup(struct device *dev,
                unsigned gpio, unsigned ngpio)
 {
+       int ret;
+
        /* gpio + 0 is "mmc0_cd" (input/IRQ) */
        mmc[0].gpio_cd = gpio + 0;
        omap2_hsmmc_init(mmc);
 
-       /*
-        * REVISIT: need ehci-omap hooks for external VBUS
-        * power switch and overcurrent detect
-        */
-       if ((gpio_request(gpio + 1, "GPIO_EHCI_NOC") < 0) ||
-           (gpio_direction_input(gpio + 1) < 0))
-               pr_err("IGEP2: Could not obtain gpio for EHCI NOC");
-
-       /*
-        * TWL4030_GPIO_MAX + 0 == ledA, GPIO_USBH_CPEN
-        * (out, active low)
-        */
-       if ((gpio_request(gpio + TWL4030_GPIO_MAX, "GPIO_USBH_CPEN") < 0) ||
-           (gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0) < 0))
-               pr_err("IGEP2: Could not obtain gpio for USBH_CPEN");
-
        /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
 #if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
-       if ((gpio_request(gpio+TWL4030_GPIO_MAX+1, "gpio-led:green:d1") == 0)
-           && (gpio_direction_output(gpio + TWL4030_GPIO_MAX + 1, 1) == 0))
+       ret = gpio_request_one(gpio + TWL4030_GPIO_MAX + 1, GPIOF_OUT_INIT_HIGH,
+                              "gpio-led:green:d1");
+       if (ret == 0)
                gpio_export(gpio + TWL4030_GPIO_MAX + 1, 0);
        else
-               pr_warning("IGEP v2: Could not obtain gpio GPIO_LED1_GREEN\n");
+               pr_warning("IGEP: Could not obtain gpio GPIO_LED1_GREEN\n");
 #else
-       igep2_gpio_leds[3].gpio = gpio + TWL4030_GPIO_MAX + 1;
+       igep_gpio_leds[3].gpio = gpio + TWL4030_GPIO_MAX + 1;
 #endif
 
+       if (machine_is_igep0030())
+               return 0;
+
+       /*
+        * REVISIT: need ehci-omap hooks for external VBUS
+        * power switch and overcurrent detect
+        */
+       igep2_twl_gpios[0].gpio = gpio + 1;
+
+       /* TWL4030_GPIO_MAX + 0 == ledA, GPIO_USBH_CPEN (out, active low) */
+       igep2_twl_gpios[1].gpio = gpio + TWL4030_GPIO_MAX;
+
+       ret = gpio_request_array(igep2_twl_gpios, ARRAY_SIZE(igep2_twl_gpios));
+       if (ret < 0)
+               pr_err("IGEP2: Could not obtain gpio for USBH_CPEN");
+
        return 0;
 };
 
-static struct twl4030_gpio_platform_data igep2_twl4030_gpio_pdata = {
+static struct twl4030_gpio_platform_data igep_twl4030_gpio_pdata = {
        .gpio_base      = OMAP_MAX_GPIO_LINES,
        .irq_base       = TWL4030_GPIO_IRQ_BASE,
        .irq_end        = TWL4030_GPIO_IRQ_END,
        .use_leds       = true,
-       .setup          = igep2_twl_gpio_setup,
+       .setup          = igep_twl_gpio_setup,
 };
 
-static struct twl4030_usb_data igep2_usb_data = {
+static struct twl4030_usb_data igep_usb_data = {
        .usb_mode       = T2_USB_MODE_ULPI,
 };
 
@@ -507,16 +502,17 @@ static struct regulator_init_data igep2_vpll2 = {
 
 static void __init igep2_display_init(void)
 {
-       if (gpio_request(IGEP2_GPIO_DVI_PUP, "GPIO_DVI_PUP") &&
-           gpio_direction_output(IGEP2_GPIO_DVI_PUP, 1))
+       int err = gpio_request_one(IGEP2_GPIO_DVI_PUP, GPIOF_OUT_INIT_HIGH,
+                                  "GPIO_DVI_PUP");
+       if (err)
                pr_err("IGEP v2: Could not obtain gpio GPIO_DVI_PUP\n");
 }
 
-static struct platform_device *igep2_devices[] __initdata = {
-       &igep2_vwlan_device,
+static struct platform_device *igep_devices[] __initdata = {
+       &igep_vwlan_device,
 };
 
-static void __init igep2_init_early(void)
+static void __init igep_init_early(void)
 {
        omap2_init_common_infrastructure();
        omap2_init_common_devices(m65kxxxxam_sdrc_params,
@@ -561,27 +557,15 @@ static struct twl4030_keypad_data igep2_keypad_pdata = {
        .rep            = 1,
 };
 
-static struct twl4030_platform_data igep2_twldata = {
+static struct twl4030_platform_data igep_twldata = {
        .irq_base       = TWL4030_IRQ_BASE,
        .irq_end        = TWL4030_IRQ_END,
 
        /* platform_data for children goes here */
-       .usb            = &igep2_usb_data,
-       .codec          = &igep2_codec_data,
-       .gpio           = &igep2_twl4030_gpio_pdata,
-       .keypad         = &igep2_keypad_pdata,
-       .vmmc1          = &igep2_vmmc1,
-       .vpll2          = &igep2_vpll2,
-       .vio            = &igep2_vio,
-};
-
-static struct i2c_board_info __initdata igep2_i2c1_boardinfo[] = {
-       {
-               I2C_BOARD_INFO("twl4030", 0x48),
-               .flags          = I2C_CLIENT_WAKE,
-               .irq            = INT_34XX_SYS_NIRQ,
-               .platform_data  = &igep2_twldata,
-       },
+       .usb            = &igep_usb_data,
+       .gpio           = &igep_twl4030_gpio_pdata,
+       .vmmc1          = &igep_vmmc1,
+       .vio            = &igep_vio,
 };
 
 static struct i2c_board_info __initdata igep2_i2c3_boardinfo[] = {
@@ -590,32 +574,29 @@ static struct i2c_board_info __initdata igep2_i2c3_boardinfo[] = {
        },
 };
 
-static void __init igep2_i2c_init(void)
+static void __init igep_i2c_init(void)
 {
        int ret;
 
-       ret = omap_register_i2c_bus(1, 2600, igep2_i2c1_boardinfo,
-               ARRAY_SIZE(igep2_i2c1_boardinfo));
-       if (ret)
-               pr_warning("IGEP2: Could not register I2C1 bus (%d)\n", ret);
+       if (machine_is_igep0020()) {
+               /*
+                * Bus 3 is attached to the DVI port where devices like the
+                * pico DLP projector don't work reliably with 400kHz
+                */
+               ret = omap_register_i2c_bus(3, 100, igep2_i2c3_boardinfo,
+                                           ARRAY_SIZE(igep2_i2c3_boardinfo));
+               if (ret)
+                       pr_warning("IGEP2: Could not register I2C3 bus (%d)\n", ret);
+
+               igep_twldata.codec      = &igep2_codec_data;
+               igep_twldata.keypad     = &igep2_keypad_pdata;
+               igep_twldata.vpll2      = &igep2_vpll2;
+       }
 
-       /*
-        * Bus 3 is attached to the DVI port where devices like the pico DLP
-        * projector don't work reliably with 400kHz
-        */
-       ret = omap_register_i2c_bus(3, 100, igep2_i2c3_boardinfo,
-               ARRAY_SIZE(igep2_i2c3_boardinfo));
-       if (ret)
-               pr_warning("IGEP2: Could not register I2C3 bus (%d)\n", ret);
+       omap3_pmic_init("twl4030", &igep_twldata);
 }
 
-static struct omap_musb_board_data musb_board_data = {
-       .interface_type         = MUSB_INTERFACE_ULPI,
-       .mode                   = MUSB_OTG,
-       .power                  = 100,
-};
-
-static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
+static const struct usbhs_omap_board_data igep2_usbhs_bdata __initconst = {
        .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
        .port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
        .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
@@ -626,6 +607,17 @@ static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
        .reset_gpio_port[2] = -EINVAL,
 };
 
+static const struct usbhs_omap_board_data igep3_usbhs_bdata __initconst = {
+       .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
+       .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
+       .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
+
+       .phy_reset = true,
+       .reset_gpio_port[0] = -EINVAL,
+       .reset_gpio_port[1] = IGEP3_GPIO_USBH_NRESET,
+       .reset_gpio_port[2] = -EINVAL,
+};
+
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
        { .reg_offset = OMAP_MUX_TERMINATOR },
@@ -633,82 +625,95 @@ static struct omap_board_mux board_mux[] __initdata = {
 #endif
 
 #if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
+static struct gpio igep_wlan_bt_gpios[] __initdata = {
+       { -EINVAL, GPIOF_OUT_INIT_HIGH, "GPIO_WIFI_NPD"    },
+       { -EINVAL, GPIOF_OUT_INIT_HIGH, "GPIO_WIFI_NRESET" },
+       { -EINVAL, GPIOF_OUT_INIT_HIGH, "GPIO_BT_NRESET"   },
+};
 
-static void __init igep2_wlan_bt_init(void)
+static void __init igep_wlan_bt_init(void)
 {
-       unsigned npd, wreset, btreset;
+       int err;
 
        /* GPIO's for WLAN-BT combo depends on hardware revision */
        if (hwrev == IGEP2_BOARD_HWREV_B) {
-               npd = IGEP2_RB_GPIO_WIFI_NPD;
-               wreset = IGEP2_RB_GPIO_WIFI_NRESET;
-               btreset = IGEP2_RB_GPIO_BT_NRESET;
-       } else if (hwrev == IGEP2_BOARD_HWREV_C) {
-               npd = IGEP2_RC_GPIO_WIFI_NPD;
-               wreset = IGEP2_RC_GPIO_WIFI_NRESET;
-               btreset = IGEP2_RC_GPIO_BT_NRESET;
+               igep_wlan_bt_gpios[0].gpio = IGEP2_RB_GPIO_WIFI_NPD;
+               igep_wlan_bt_gpios[1].gpio = IGEP2_RB_GPIO_WIFI_NRESET;
+               igep_wlan_bt_gpios[2].gpio = IGEP2_RB_GPIO_BT_NRESET;
+       } else if (hwrev == IGEP2_BOARD_HWREV_C || machine_is_igep0030()) {
+               igep_wlan_bt_gpios[0].gpio = IGEP2_RC_GPIO_WIFI_NPD;
+               igep_wlan_bt_gpios[1].gpio = IGEP2_RC_GPIO_WIFI_NRESET;
+               igep_wlan_bt_gpios[2].gpio = IGEP2_RC_GPIO_BT_NRESET;
        } else
                return;
 
-       /* Set GPIO's for  WLAN-BT combo module */
-       if ((gpio_request(npd, "GPIO_WIFI_NPD") == 0) &&
-           (gpio_direction_output(npd, 1) == 0)) {
-               gpio_export(npd, 0);
-       } else
-               pr_warning("IGEP2: Could not obtain gpio GPIO_WIFI_NPD\n");
-
-       if ((gpio_request(wreset, "GPIO_WIFI_NRESET") == 0) &&
-           (gpio_direction_output(wreset, 1) == 0)) {
-               gpio_export(wreset, 0);
-               gpio_set_value(wreset, 0);
-               udelay(10);
-               gpio_set_value(wreset, 1);
-       } else
-               pr_warning("IGEP2: Could not obtain gpio GPIO_WIFI_NRESET\n");
+       err = gpio_request_array(igep_wlan_bt_gpios,
+                                ARRAY_SIZE(igep_wlan_bt_gpios));
+       if (err) {
+               pr_warning("IGEP2: Could not obtain WIFI/BT gpios\n");
+               return;
+       }
+
+       gpio_export(igep_wlan_bt_gpios[0].gpio, 0);
+       gpio_export(igep_wlan_bt_gpios[1].gpio, 0);
+       gpio_export(igep_wlan_bt_gpios[2].gpio, 0);
+
+       gpio_set_value(igep_wlan_bt_gpios[1].gpio, 0);
+       udelay(10);
+       gpio_set_value(igep_wlan_bt_gpios[1].gpio, 1);
 
-       if ((gpio_request(btreset, "GPIO_BT_NRESET") == 0) &&
-           (gpio_direction_output(btreset, 1) == 0)) {
-               gpio_export(btreset, 0);
-       } else
-               pr_warning("IGEP2: Could not obtain gpio GPIO_BT_NRESET\n");
 }
 #else
-static inline void __init igep2_wlan_bt_init(void) { }
+static inline void __init igep_wlan_bt_init(void) { }
 #endif
 
-static void __init igep2_init(void)
+static void __init igep_init(void)
 {
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
 
        /* Get IGEP2 hardware revision */
        igep2_get_revision();
        /* Register I2C busses and drivers */
-       igep2_i2c_init();
-       platform_add_devices(igep2_devices, ARRAY_SIZE(igep2_devices));
-       omap_display_init(&igep2_dss_data);
+       igep_i2c_init();
+       platform_add_devices(igep_devices, ARRAY_SIZE(igep_devices));
        omap_serial_init();
-       usb_musb_init(&musb_board_data);
-       usbhs_init(&usbhs_bdata);
+       usb_musb_init(NULL);
 
-       igep2_flash_init();
-       igep2_leds_init();
-       igep2_display_init();
-       igep2_init_smsc911x();
+       igep_flash_init();
+       igep_leds_init();
 
        /*
         * WLAN-BT combo module from MuRata which has a Marvell WLAN
         * (88W8686) + CSR Bluetooth chipset. Uses SDIO interface.
         */
-       igep2_wlan_bt_init();
+       igep_wlan_bt_init();
 
+       if (machine_is_igep0020()) {
+               omap_display_init(&igep2_dss_data);
+               igep2_display_init();
+               igep2_init_smsc911x();
+               usbhs_init(&igep2_usbhs_bdata);
+       } else {
+               usbhs_init(&igep3_usbhs_bdata);
+       }
 }
 
 MACHINE_START(IGEP0020, "IGEP v2 board")
        .boot_params    = 0x80000100,
        .reserve        = omap_reserve,
        .map_io         = omap3_map_io,
-       .init_early     = igep2_init_early,
+       .init_early     = igep_init_early,
+       .init_irq       = omap_init_irq,
+       .init_machine   = igep_init,
+       .timer          = &omap_timer,
+MACHINE_END
+
+MACHINE_START(IGEP0030, "IGEP OMAP3 module")
+       .boot_params    = 0x80000100,
+       .reserve        = omap_reserve,
+       .map_io         = omap3_map_io,
+       .init_early     = igep_init_early,
        .init_irq       = omap_init_irq,
-       .init_machine   = igep2_init,
+       .init_machine   = igep_init,
        .timer          = &omap_timer,
 MACHINE_END
diff --git a/arch/arm/mach-omap2/board-igep0030.c b/arch/arm/mach-omap2/board-igep0030.c
deleted file mode 100644 (file)
index 2cf86c3..0000000
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * Copyright (C) 2010 - ISEE 2007 SL
- *
- * Modified from mach-omap2/board-generic.c
- *
- * 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/delay.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-
-#include <linux/regulator/machine.h>
-#include <linux/regulator/fixed.h>
-#include <linux/i2c/twl.h>
-#include <linux/mmc/host.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-#include <plat/board.h>
-#include <plat/common.h>
-#include <plat/gpmc.h>
-#include <plat/usb.h>
-#include <plat/onenand.h>
-
-#include "mux.h"
-#include "hsmmc.h"
-#include "sdram-numonyx-m65kxxxxam.h"
-
-#define IGEP3_GPIO_LED0_GREEN  54
-#define IGEP3_GPIO_LED0_RED    53
-#define IGEP3_GPIO_LED1_RED    16
-
-#define IGEP3_GPIO_WIFI_NPD    138
-#define IGEP3_GPIO_WIFI_NRESET 139
-#define IGEP3_GPIO_BT_NRESET   137
-
-#define IGEP3_GPIO_USBH_NRESET  183
-
-
-#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
-       defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
-
-#define ONENAND_MAP             0x20000000
-
-/*
- * x2 Flash built-in COMBO POP MEMORY
- * Since the device is equipped with two DataRAMs, and two-plane NAND
- * Flash memory array, these two component enables simultaneous program
- * of 4KiB. Plane1 has only even blocks such as block0, block2, block4
- * while Plane2 has only odd blocks such as block1, block3, block5.
- * So MTD regards it as 4KiB page size and 256KiB block size 64*(2*2048)
- */
-
-static struct mtd_partition igep3_onenand_partitions[] = {
-       {
-               .name           = "X-Loader",
-               .offset         = 0,
-               .size           = 2 * (64*(2*2048))
-       },
-       {
-               .name           = "U-Boot",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = 6 * (64*(2*2048)),
-       },
-       {
-               .name           = "Environment",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = 2 * (64*(2*2048)),
-       },
-       {
-               .name           = "Kernel",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = 12 * (64*(2*2048)),
-       },
-       {
-               .name           = "File System",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = MTDPART_SIZ_FULL,
-       },
-};
-
-static struct omap_onenand_platform_data igep3_onenand_pdata = {
-       .parts = igep3_onenand_partitions,
-       .nr_parts = ARRAY_SIZE(igep3_onenand_partitions),
-       .onenand_setup = NULL,
-       .dma_channel    = -1,   /* disable DMA in OMAP OneNAND driver */
-};
-
-static struct platform_device igep3_onenand_device = {
-       .name           = "omap2-onenand",
-       .id             = -1,
-       .dev = {
-               .platform_data = &igep3_onenand_pdata,
-       },
-};
-
-static void __init igep3_flash_init(void)
-{
-       u8 cs = 0;
-       u8 onenandcs = GPMC_CS_NUM + 1;
-
-       for (cs = 0; cs < GPMC_CS_NUM; cs++) {
-               u32 ret;
-               ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-
-               /* Check if NAND/oneNAND is configured */
-               if ((ret & 0xC00) == 0x800)
-                       /* NAND found */
-                       pr_err("IGEP3: Unsupported NAND found\n");
-               else {
-                       ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
-
-                       if ((ret & 0x3F) == (ONENAND_MAP >> 24))
-                               /* OneNAND found */
-                               onenandcs = cs;
-               }
-       }
-
-       if (onenandcs > GPMC_CS_NUM) {
-               pr_err("IGEP3: Unable to find configuration in GPMC\n");
-               return;
-       }
-
-       igep3_onenand_pdata.cs = onenandcs;
-
-       if (platform_device_register(&igep3_onenand_device) < 0)
-               pr_err("IGEP3: Unable to register OneNAND device\n");
-}
-
-#else
-static void __init igep3_flash_init(void) {}
-#endif
-
-static struct regulator_consumer_supply igep3_vmmc1_supply =
-       REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0");
-
-/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
-static struct regulator_init_data igep3_vmmc1 = {
-       .constraints = {
-               .min_uV                 = 1850000,
-               .max_uV                 = 3150000,
-               .valid_modes_mask       = REGULATOR_MODE_NORMAL
-                                       | REGULATOR_MODE_STANDBY,
-               .valid_ops_mask         = REGULATOR_CHANGE_VOLTAGE
-                                       | REGULATOR_CHANGE_MODE
-                                       | REGULATOR_CHANGE_STATUS,
-       },
-       .num_consumer_supplies  = 1,
-       .consumer_supplies      = &igep3_vmmc1_supply,
-};
-
-static struct regulator_consumer_supply igep3_vio_supply =
-       REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.1");
-
-static struct regulator_init_data igep3_vio = {
-       .constraints = {
-               .min_uV                 = 1800000,
-               .max_uV                 = 1800000,
-               .apply_uV               = 1,
-               .valid_modes_mask       = REGULATOR_MODE_NORMAL
-                                       | REGULATOR_MODE_STANDBY,
-               .valid_ops_mask         = REGULATOR_CHANGE_VOLTAGE
-                                       | REGULATOR_CHANGE_MODE
-                                       | REGULATOR_CHANGE_STATUS,
-       },
-       .num_consumer_supplies  = 1,
-       .consumer_supplies      = &igep3_vio_supply,
-};
-
-static struct regulator_consumer_supply igep3_vmmc2_supply =
-       REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1");
-
-static struct regulator_init_data igep3_vmmc2 = {
-       .constraints    = {
-               .valid_modes_mask       = REGULATOR_MODE_NORMAL,
-               .always_on              = 1,
-       },
-       .num_consumer_supplies  = 1,
-       .consumer_supplies      = &igep3_vmmc2_supply,
-};
-
-static struct fixed_voltage_config igep3_vwlan = {
-       .supply_name            = "vwlan",
-       .microvolts             = 3300000,
-       .gpio                   = -EINVAL,
-       .enabled_at_boot        = 1,
-       .init_data              = &igep3_vmmc2,
-};
-
-static struct platform_device igep3_vwlan_device = {
-       .name   = "reg-fixed-voltage",
-       .id     = 0,
-       .dev    = {
-               .platform_data = &igep3_vwlan,
-       },
-};
-
-static struct omap2_hsmmc_info mmc[] = {
-       [0] = {
-               .mmc            = 1,
-               .caps           = MMC_CAP_4_BIT_DATA,
-               .gpio_cd        = -EINVAL,
-               .gpio_wp        = -EINVAL,
-       },
-#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
-       [1] = {
-               .mmc            = 2,
-               .caps           = MMC_CAP_4_BIT_DATA,
-               .gpio_cd        = -EINVAL,
-               .gpio_wp        = -EINVAL,
-       },
-#endif
-       {}      /* Terminator */
-};
-
-#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
-#include <linux/leds.h>
-
-static struct gpio_led igep3_gpio_leds[] = {
-       [0] = {
-               .name                   = "gpio-led:red:d0",
-               .gpio                   = IGEP3_GPIO_LED0_RED,
-               .default_trigger        = "default-off"
-       },
-       [1] = {
-               .name                   = "gpio-led:green:d0",
-               .gpio                   = IGEP3_GPIO_LED0_GREEN,
-               .default_trigger        = "default-off",
-       },
-       [2] = {
-               .name                   = "gpio-led:red:d1",
-               .gpio                   = IGEP3_GPIO_LED1_RED,
-               .default_trigger        = "default-off",
-       },
-       [3] = {
-               .name                   = "gpio-led:green:d1",
-               .default_trigger        = "heartbeat",
-               .gpio                   = -EINVAL, /* gets replaced */
-       },
-};
-
-static struct gpio_led_platform_data igep3_led_pdata = {
-       .leds           = igep3_gpio_leds,
-       .num_leds       = ARRAY_SIZE(igep3_gpio_leds),
-};
-
-static struct platform_device igep3_led_device = {
-        .name   = "leds-gpio",
-        .id     = -1,
-        .dev    = {
-                .platform_data = &igep3_led_pdata,
-       },
-};
-
-static void __init igep3_leds_init(void)
-{
-       platform_device_register(&igep3_led_device);
-}
-
-#else
-static inline void igep3_leds_init(void)
-{
-       if ((gpio_request(IGEP3_GPIO_LED0_RED, "gpio-led:red:d0") == 0) &&
-           (gpio_direction_output(IGEP3_GPIO_LED0_RED, 1) == 0)) {
-               gpio_export(IGEP3_GPIO_LED0_RED, 0);
-               gpio_set_value(IGEP3_GPIO_LED0_RED, 1);
-       } else
-               pr_warning("IGEP3: Could not obtain gpio GPIO_LED0_RED\n");
-
-       if ((gpio_request(IGEP3_GPIO_LED0_GREEN, "gpio-led:green:d0") == 0) &&
-           (gpio_direction_output(IGEP3_GPIO_LED0_GREEN, 1) == 0)) {
-               gpio_export(IGEP3_GPIO_LED0_GREEN, 0);
-               gpio_set_value(IGEP3_GPIO_LED0_GREEN, 1);
-       } else
-               pr_warning("IGEP3: Could not obtain gpio GPIO_LED0_GREEN\n");
-
-       if ((gpio_request(IGEP3_GPIO_LED1_RED, "gpio-led:red:d1") == 0) &&
-               (gpio_direction_output(IGEP3_GPIO_LED1_RED, 1) == 0)) {
-               gpio_export(IGEP3_GPIO_LED1_RED, 0);
-               gpio_set_value(IGEP3_GPIO_LED1_RED, 1);
-       } else
-               pr_warning("IGEP3: Could not obtain gpio GPIO_LED1_RED\n");
-}
-#endif
-
-static int igep3_twl4030_gpio_setup(struct device *dev,
-               unsigned gpio, unsigned ngpio)
-{
-       /* gpio + 0 is "mmc0_cd" (input/IRQ) */
-       mmc[0].gpio_cd = gpio + 0;
-       omap2_hsmmc_init(mmc);
-
-       /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
-#if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
-       if ((gpio_request(gpio+TWL4030_GPIO_MAX+1, "gpio-led:green:d1") == 0)
-           && (gpio_direction_output(gpio + TWL4030_GPIO_MAX + 1, 1) == 0)) {
-               gpio_export(gpio + TWL4030_GPIO_MAX + 1, 0);
-               gpio_set_value(gpio + TWL4030_GPIO_MAX + 1, 0);
-       } else
-               pr_warning("IGEP3: Could not obtain gpio GPIO_LED1_GREEN\n");
-#else
-       igep3_gpio_leds[3].gpio = gpio + TWL4030_GPIO_MAX + 1;
-#endif
-
-       return 0;
-};
-
-static struct twl4030_gpio_platform_data igep3_twl4030_gpio_pdata = {
-       .gpio_base      = OMAP_MAX_GPIO_LINES,
-       .irq_base       = TWL4030_GPIO_IRQ_BASE,
-       .irq_end        = TWL4030_GPIO_IRQ_END,
-       .use_leds       = true,
-       .setup          = igep3_twl4030_gpio_setup,
-};
-
-static struct twl4030_usb_data igep3_twl4030_usb_data = {
-       .usb_mode       = T2_USB_MODE_ULPI,
-};
-
-static struct platform_device *igep3_devices[] __initdata = {
-       &igep3_vwlan_device,
-};
-
-static void __init igep3_init_early(void)
-{
-       omap2_init_common_infrastructure();
-       omap2_init_common_devices(m65kxxxxam_sdrc_params,
-                                 m65kxxxxam_sdrc_params);
-}
-
-static struct twl4030_platform_data igep3_twl4030_pdata = {
-       .irq_base       = TWL4030_IRQ_BASE,
-       .irq_end        = TWL4030_IRQ_END,
-
-       /* platform_data for children goes here */
-       .usb            = &igep3_twl4030_usb_data,
-       .gpio           = &igep3_twl4030_gpio_pdata,
-       .vmmc1          = &igep3_vmmc1,
-       .vio            = &igep3_vio,
-};
-
-static struct i2c_board_info __initdata igep3_i2c_boardinfo[] = {
-       {
-               I2C_BOARD_INFO("twl4030", 0x48),
-               .flags          = I2C_CLIENT_WAKE,
-               .irq            = INT_34XX_SYS_NIRQ,
-               .platform_data  = &igep3_twl4030_pdata,
-       },
-};
-
-static int __init igep3_i2c_init(void)
-{
-       omap_register_i2c_bus(1, 2600, igep3_i2c_boardinfo,
-                       ARRAY_SIZE(igep3_i2c_boardinfo));
-
-       return 0;
-}
-
-static struct omap_musb_board_data musb_board_data = {
-       .interface_type = MUSB_INTERFACE_ULPI,
-       .mode           = MUSB_OTG,
-       .power          = 100,
-};
-
-#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
-
-static void __init igep3_wifi_bt_init(void)
-{
-       /* Configure MUX values for W-LAN + Bluetooth GPIO's */
-       omap_mux_init_gpio(IGEP3_GPIO_WIFI_NPD, OMAP_PIN_OUTPUT);
-       omap_mux_init_gpio(IGEP3_GPIO_WIFI_NRESET, OMAP_PIN_OUTPUT);
-       omap_mux_init_gpio(IGEP3_GPIO_BT_NRESET, OMAP_PIN_OUTPUT);
-
-       /* Set GPIO's for  W-LAN + Bluetooth combo module */
-       if ((gpio_request(IGEP3_GPIO_WIFI_NPD, "GPIO_WIFI_NPD") == 0) &&
-           (gpio_direction_output(IGEP3_GPIO_WIFI_NPD, 1) == 0)) {
-               gpio_export(IGEP3_GPIO_WIFI_NPD, 0);
-       } else
-               pr_warning("IGEP3: Could not obtain gpio GPIO_WIFI_NPD\n");
-
-       if ((gpio_request(IGEP3_GPIO_WIFI_NRESET, "GPIO_WIFI_NRESET") == 0) &&
-           (gpio_direction_output(IGEP3_GPIO_WIFI_NRESET, 1) == 0)) {
-               gpio_export(IGEP3_GPIO_WIFI_NRESET, 0);
-               gpio_set_value(IGEP3_GPIO_WIFI_NRESET, 0);
-               udelay(10);
-               gpio_set_value(IGEP3_GPIO_WIFI_NRESET, 1);
-       } else
-               pr_warning("IGEP3: Could not obtain gpio GPIO_WIFI_NRESET\n");
-
-       if ((gpio_request(IGEP3_GPIO_BT_NRESET, "GPIO_BT_NRESET") == 0) &&
-           (gpio_direction_output(IGEP3_GPIO_BT_NRESET, 1) == 0)) {
-               gpio_export(IGEP3_GPIO_BT_NRESET, 0);
-       } else
-               pr_warning("IGEP3: Could not obtain gpio GPIO_BT_NRESET\n");
-}
-#else
-void __init igep3_wifi_bt_init(void) {}
-#endif
-
-static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
-       .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
-       .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
-       .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
-
-       .phy_reset = true,
-       .reset_gpio_port[0] = -EINVAL,
-       .reset_gpio_port[1] = IGEP3_GPIO_USBH_NRESET,
-       .reset_gpio_port[2] = -EINVAL,
-};
-
-#ifdef CONFIG_OMAP_MUX
-static struct omap_board_mux board_mux[] __initdata = {
-       OMAP3_MUX(I2C2_SDA, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
-       { .reg_offset = OMAP_MUX_TERMINATOR },
-};
-#endif
-
-static void __init igep3_init(void)
-{
-       omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
-
-       /* Register I2C busses and drivers */
-       igep3_i2c_init();
-       platform_add_devices(igep3_devices, ARRAY_SIZE(igep3_devices));
-       omap_serial_init();
-       usb_musb_init(&musb_board_data);
-       usbhs_init(&usbhs_bdata);
-
-       igep3_flash_init();
-       igep3_leds_init();
-
-       /*
-        * WLAN-BT combo module from MuRata which has a Marvell WLAN
-        * (88W8686) + CSR Bluetooth chipset. Uses SDIO interface.
-        */
-       igep3_wifi_bt_init();
-
-}
-
-MACHINE_START(IGEP0030, "IGEP OMAP3 module")
-       .boot_params    = 0x80000100,
-       .reserve        = omap_reserve,
-       .map_io         = omap3_map_io,
-       .init_early     = igep3_init_early,
-       .init_irq       = omap_init_irq,
-       .init_machine   = igep3_init,
-       .timer          = &omap_timer,
-MACHINE_END
index e2ba77957a8c305196a25956633724932cff2d11..f7d6038075f0721be241eff8a6b08859c1a86daa 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
 #include <linux/io.h>
 
 #include <asm/delay.h>
 #include <plat/usb.h>
+#include <plat/gpmc-smsc911x.h>
 
 #include "board-flash.h"
 #include "mux.h"
 #include "hsmmc.h"
 #include "control.h"
+#include "common-board-devices.h"
 
 #define LDP_SMSC911X_CS                1
 #define LDP_SMSC911X_GPIO      152
 #define DEBUG_BASE             0x08000000
 #define LDP_ETHR_START         DEBUG_BASE
 
-static struct resource ldp_smsc911x_resources[] = {
-       [0] = {
-               .start  = LDP_ETHR_START,
-               .end    = LDP_ETHR_START + SZ_4K,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = 0,
-               .end    = 0,
-               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
-       },
-};
-
-static struct smsc911x_platform_config ldp_smsc911x_config = {
-       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
-       .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
-       .flags          = SMSC911X_USE_32BIT,
-       .phy_interface  = PHY_INTERFACE_MODE_MII,
-};
-
-static struct platform_device ldp_smsc911x_device = {
-       .name           = "smsc911x",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(ldp_smsc911x_resources),
-       .resource       = ldp_smsc911x_resources,
-       .dev            = {
-               .platform_data = &ldp_smsc911x_config,
-       },
-};
-
 static uint32_t board_keymap[] = {
        KEY(0, 0, KEY_1),
        KEY(1, 0, KEY_2),
@@ -197,82 +168,16 @@ static struct platform_device ldp_gpio_keys_device = {
        },
 };
 
-static int ts_gpio;
-
-/**
- * @brief ads7846_dev_init : Requests & sets GPIO line for pen-irq
- *
- * @return - void. If request gpio fails then Flag KERN_ERR.
- */
-static void ads7846_dev_init(void)
-{
-       if (gpio_request(ts_gpio, "ads7846 irq") < 0) {
-               printk(KERN_ERR "can't get ads746 pen down GPIO\n");
-               return;
-       }
-
-       gpio_direction_input(ts_gpio);
-       gpio_set_debounce(ts_gpio, 310);
-}
-
-static int ads7846_get_pendown_state(void)
-{
-       return !gpio_get_value(ts_gpio);
-}
-
-static struct ads7846_platform_data tsc2046_config __initdata = {
-       .get_pendown_state      = ads7846_get_pendown_state,
-       .keep_vref_on           = 1,
-};
-
-static struct omap2_mcspi_device_config tsc2046_mcspi_config = {
-       .turbo_mode     = 0,
-       .single_channel = 1,    /* 0: slave, 1: master */
-};
-
-static struct spi_board_info ldp_spi_board_info[] __initdata = {
-       [0] = {
-               /*
-                * TSC2046 operates at a max freqency of 2MHz, so
-                * operate slightly below at 1.5MHz
-                */
-               .modalias               = "ads7846",
-               .bus_num                = 1,
-               .chip_select            = 0,
-               .max_speed_hz           = 1500000,
-               .controller_data        = &tsc2046_mcspi_config,
-               .irq                    = 0,
-               .platform_data          = &tsc2046_config,
-       },
+static struct omap_smsc911x_platform_data smsc911x_cfg = {
+       .cs             = LDP_SMSC911X_CS,
+       .gpio_irq       = LDP_SMSC911X_GPIO,
+       .gpio_reset     = -EINVAL,
+       .flags          = SMSC911X_USE_32BIT,
 };
 
 static inline void __init ldp_init_smsc911x(void)
 {
-       int eth_cs;
-       unsigned long cs_mem_base;
-       int eth_gpio = 0;
-
-       eth_cs = LDP_SMSC911X_CS;
-
-       if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
-               printk(KERN_ERR "Failed to request GPMC mem for smsc911x\n");
-               return;
-       }
-
-       ldp_smsc911x_resources[0].start = cs_mem_base + 0x0;
-       ldp_smsc911x_resources[0].end   = cs_mem_base + 0xff;
-       udelay(100);
-
-       eth_gpio = LDP_SMSC911X_GPIO;
-
-       ldp_smsc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
-
-       if (gpio_request(eth_gpio, "smsc911x irq") < 0) {
-               printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n",
-                               eth_gpio);
-               return;
-       }
-       gpio_direction_input(eth_gpio);
+       gpmc_smsc911x_init(&smsc911x_cfg);
 }
 
 static struct platform_device ldp_lcd_device = {
@@ -360,19 +265,9 @@ static struct twl4030_platform_data ldp_twldata = {
        .keypad         = &ldp_kp_twl4030_data,
 };
 
-static struct i2c_board_info __initdata ldp_i2c_boardinfo[] = {
-       {
-               I2C_BOARD_INFO("twl4030", 0x48),
-               .flags = I2C_CLIENT_WAKE,
-               .irq = INT_34XX_SYS_NIRQ,
-               .platform_data = &ldp_twldata,
-       },
-};
-
 static int __init omap_i2c_init(void)
 {
-       omap_register_i2c_bus(1, 2600, ldp_i2c_boardinfo,
-                       ARRAY_SIZE(ldp_i2c_boardinfo));
+       omap3_pmic_init("twl4030", &ldp_twldata);
        omap_register_i2c_bus(2, 400, NULL, 0);
        omap_register_i2c_bus(3, 400, NULL, 0);
        return 0;
@@ -389,7 +284,6 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
 };
 
 static struct platform_device *ldp_devices[] __initdata = {
-       &ldp_smsc911x_device,
        &ldp_lcd_device,
        &ldp_gpio_keys_device,
 };
@@ -400,12 +294,6 @@ static struct omap_board_mux board_mux[] __initdata = {
 };
 #endif
 
-static struct omap_musb_board_data musb_board_data = {
-       .interface_type         = MUSB_INTERFACE_ULPI,
-       .mode                   = MUSB_OTG,
-       .power                  = 100,
-};
-
 static struct mtd_partition ldp_nand_partitions[] = {
        /* All the partition sizes are listed in terms of NAND block size */
        {
@@ -446,13 +334,9 @@ static void __init omap_ldp_init(void)
        ldp_init_smsc911x();
        omap_i2c_init();
        platform_add_devices(ldp_devices, ARRAY_SIZE(ldp_devices));
-       ts_gpio = 54;
-       ldp_spi_board_info[0].irq = gpio_to_irq(ts_gpio);
-       spi_register_board_info(ldp_spi_board_info,
-                               ARRAY_SIZE(ldp_spi_board_info));
-       ads7846_dev_init();
+       omap_ads7846_init(1, 54, 310, NULL);
        omap_serial_init();
-       usb_musb_init(&musb_board_data);
+       usb_musb_init(NULL);
        board_nand_init(ldp_nand_partitions,
                ARRAY_SIZE(ldp_nand_partitions), ZOOM_NAND_CS, 0);
 
index e710cd9e079ba59d528a8ecf7a80d2d481c593be..8d74318ed495efcf2522c30e00035463cb0abb67 100644 (file)
@@ -106,14 +106,13 @@ static void __init n8x0_usb_init(void)
        static char     announce[] __initdata = KERN_INFO "TUSB 6010\n";
 
        /* PM companion chip power control pin */
-       ret = gpio_request(TUSB6010_GPIO_ENABLE, "TUSB6010 enable");
+       ret = gpio_request_one(TUSB6010_GPIO_ENABLE, GPIOF_OUT_INIT_LOW,
+                              "TUSB6010 enable");
        if (ret != 0) {
                printk(KERN_ERR "Could not get TUSB power GPIO%i\n",
                       TUSB6010_GPIO_ENABLE);
                return;
        }
-       gpio_direction_output(TUSB6010_GPIO_ENABLE, 0);
-
        tusb_set_power(0);
 
        ret = tusb6010_setup_interface(&tusb_data, TUSB6010_REFCLK_19, 2,
@@ -494,8 +493,12 @@ static struct omap_mmc_platform_data mmc1_data = {
 
 static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC];
 
-static void __init n8x0_mmc_init(void)
+static struct gpio n810_emmc_gpios[] __initdata = {
+       { N810_EMMC_VSD_GPIO, GPIOF_OUT_INIT_LOW,  "MMC slot 2 Vddf" },
+       { N810_EMMC_VIO_GPIO, GPIOF_OUT_INIT_LOW,  "MMC slot 2 Vdd"  },
+};
 
+static void __init n8x0_mmc_init(void)
 {
        int err;
 
@@ -512,27 +515,18 @@ static void __init n8x0_mmc_init(void)
                mmc1_data.slots[1].ban_openended = 1;
        }
 
-       err = gpio_request(N8X0_SLOT_SWITCH_GPIO, "MMC slot switch");
+       err = gpio_request_one(N8X0_SLOT_SWITCH_GPIO, GPIOF_OUT_INIT_LOW,
+                              "MMC slot switch");
        if (err)
                return;
 
-       gpio_direction_output(N8X0_SLOT_SWITCH_GPIO, 0);
-
        if (machine_is_nokia_n810()) {
-               err = gpio_request(N810_EMMC_VSD_GPIO, "MMC slot 2 Vddf");
-               if (err) {
-                       gpio_free(N8X0_SLOT_SWITCH_GPIO);
-                       return;
-               }
-               gpio_direction_output(N810_EMMC_VSD_GPIO, 0);
-
-               err = gpio_request(N810_EMMC_VIO_GPIO, "MMC slot 2 Vdd");
+               err = gpio_request_array(n810_emmc_gpios,
+                                        ARRAY_SIZE(n810_emmc_gpios));
                if (err) {
                        gpio_free(N8X0_SLOT_SWITCH_GPIO);
-                       gpio_free(N810_EMMC_VSD_GPIO);
                        return;
                }
-               gpio_direction_output(N810_EMMC_VIO_GPIO, 0);
        }
 
        mmc_data[0] = &mmc1_data;
index 33007fd4a0835fd298129c9fda30b844707cc08b..7f21d24bd437732724a45af9302c50a514f56482 100644 (file)
@@ -41,8 +41,8 @@
 
 #include <plat/board.h>
 #include <plat/common.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
@@ -52,8 +52,7 @@
 #include "hsmmc.h"
 #include "timer-gp.h"
 #include "pm.h"
-
-#define NAND_BLOCK_SIZE                SZ_128K
+#include "common-board-devices.h"
 
 /*
  * OMAP3 Beagle revision
@@ -79,6 +78,12 @@ static u8 omap3_beagle_get_rev(void)
        return omap3_beagle_version;
 }
 
+static struct gpio omap3_beagle_rev_gpios[] __initdata = {
+       { 171, GPIOF_IN, "rev_id_0"    },
+       { 172, GPIOF_IN, "rev_id_1" },
+       { 173, GPIOF_IN, "rev_id_2"    },
+};
+
 static void __init omap3_beagle_init_rev(void)
 {
        int ret;
@@ -88,25 +93,20 @@ static void __init omap3_beagle_init_rev(void)
        omap_mux_init_gpio(172, OMAP_PIN_INPUT_PULLUP);
        omap_mux_init_gpio(173, OMAP_PIN_INPUT_PULLUP);
 
-       ret = gpio_request(171, "rev_id_0");
-       if (ret < 0)
-               goto fail0;
-
-       ret = gpio_request(172, "rev_id_1");
-       if (ret < 0)
-               goto fail1;
-
-       ret = gpio_request(173, "rev_id_2");
-       if (ret < 0)
-               goto fail2;
-
-       gpio_direction_input(171);
-       gpio_direction_input(172);
-       gpio_direction_input(173);
+       ret = gpio_request_array(omap3_beagle_rev_gpios,
+                                ARRAY_SIZE(omap3_beagle_rev_gpios));
+       if (ret < 0) {
+               printk(KERN_ERR "Unable to get revision detection GPIO pins\n");
+               omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
+               return;
+       }
 
        beagle_rev = gpio_get_value(171) | (gpio_get_value(172) << 1)
                        | (gpio_get_value(173) << 2);
 
+       gpio_free_array(omap3_beagle_rev_gpios,
+                       ARRAY_SIZE(omap3_beagle_rev_gpios));
+
        switch (beagle_rev) {
        case 7:
                printk(KERN_INFO "OMAP3 Beagle Rev: Ax/Bx\n");
@@ -128,18 +128,6 @@ static void __init omap3_beagle_init_rev(void)
                printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd\n", beagle_rev);
                omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
        }
-
-       return;
-
-fail2:
-       gpio_free(172);
-fail1:
-       gpio_free(171);
-fail0:
-       printk(KERN_ERR "Unable to get revision detection GPIO pins\n");
-       omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
-
-       return;
 }
 
 static struct mtd_partition omap3beagle_nand_partitions[] = {
@@ -173,15 +161,6 @@ static struct mtd_partition omap3beagle_nand_partitions[] = {
        },
 };
 
-static struct omap_nand_platform_data omap3beagle_nand_data = {
-       .options        = NAND_BUSWIDTH_16,
-       .parts          = omap3beagle_nand_partitions,
-       .nr_parts       = ARRAY_SIZE(omap3beagle_nand_partitions),
-       .dma_channel    = -1,           /* disable DMA in OMAP NAND driver */
-       .nand_setup     = NULL,
-       .dev_ready      = NULL,
-};
-
 /* DSS */
 
 static int beagle_enable_dvi(struct omap_dss_device *dssdev)
@@ -243,13 +222,10 @@ static void __init beagle_display_init(void)
 {
        int r;
 
-       r = gpio_request(beagle_dvi_device.reset_gpio, "DVI reset");
-       if (r < 0) {
+       r = gpio_request_one(beagle_dvi_device.reset_gpio, GPIOF_OUT_INIT_LOW,
+                            "DVI reset");
+       if (r < 0)
                printk(KERN_ERR "Unable to get DVI reset GPIO\n");
-               return;
-       }
-
-       gpio_direction_output(beagle_dvi_device.reset_gpio, 0);
 }
 
 #include "sdram-micron-mt46h32m32lf-6.h"
@@ -276,7 +252,7 @@ static struct gpio_led gpio_leds[];
 static int beagle_twl_gpio_setup(struct device *dev,
                unsigned gpio, unsigned ngpio)
 {
-       int r;
+       int r, usb_pwr_level;
 
        if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
                mmc[0].gpio_wp = -EINVAL;
@@ -295,66 +271,46 @@ static int beagle_twl_gpio_setup(struct device *dev,
        beagle_vmmc1_supply.dev = mmc[0].dev;
        beagle_vsim_supply.dev = mmc[0].dev;
 
-       /* REVISIT: need ehci-omap hooks for external VBUS
-        * power switch and overcurrent detect
-        */
-       if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM) {
-               r = gpio_request(gpio + 1, "EHCI_nOC");
-               if (!r) {
-                       r = gpio_direction_input(gpio + 1);
-                       if (r)
-                               gpio_free(gpio + 1);
-               }
-               if (r)
-                       pr_err("%s: unable to configure EHCI_nOC\n", __func__);
-       }
-
        /*
         * TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, XM active
         * high / others active low)
-        */
-       gpio_request(gpio + TWL4030_GPIO_MAX, "nEN_USB_PWR");
-       if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM)
-               gpio_direction_output(gpio + TWL4030_GPIO_MAX, 1);
-       else
-               gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
-
-       /* DVI reset GPIO is different between beagle revisions */
-       if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM)
-               beagle_dvi_device.reset_gpio = 129;
-       else
-               beagle_dvi_device.reset_gpio = 170;
-
-       /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
-       gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
-
-       /*
-        * gpio + 1 on Xm controls the TFP410's enable line (active low)
-        * gpio + 2 control varies depending on the board rev as follows:
-        * P7/P8 revisions(prototype): Camera EN
-        * A2+ revisions (production): LDO (supplies DVI, serial, led blocks)
+        * DVI reset GPIO is different between beagle revisions
         */
        if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
-               r = gpio_request(gpio + 1, "nDVI_PWR_EN");
-               if (!r) {
-                       r = gpio_direction_output(gpio + 1, 0);
-                       if (r)
-                               gpio_free(gpio + 1);
-               }
+               usb_pwr_level = GPIOF_OUT_INIT_HIGH;
+               beagle_dvi_device.reset_gpio = 129;
+               /*
+                * gpio + 1 on Xm controls the TFP410's enable line (active low)
+                * gpio + 2 control varies depending on the board rev as below:
+                * P7/P8 revisions(prototype): Camera EN
+                * A2+ revisions (production): LDO (DVI, serial, led blocks)
+                */
+               r = gpio_request_one(gpio + 1, GPIOF_OUT_INIT_LOW,
+                                    "nDVI_PWR_EN");
                if (r)
                        pr_err("%s: unable to configure nDVI_PWR_EN\n",
                                __func__);
-               r = gpio_request(gpio + 2, "DVI_LDO_EN");
-               if (!r) {
-                       r = gpio_direction_output(gpio + 2, 1);
-                       if (r)
-                               gpio_free(gpio + 2);
-               }
+               r = gpio_request_one(gpio + 2, GPIOF_OUT_INIT_HIGH,
+                                    "DVI_LDO_EN");
                if (r)
                        pr_err("%s: unable to configure DVI_LDO_EN\n",
                                __func__);
+       } else {
+               usb_pwr_level = GPIOF_OUT_INIT_LOW;
+               beagle_dvi_device.reset_gpio = 170;
+               /*
+                * REVISIT: need ehci-omap hooks for external VBUS
+                * power switch and overcurrent detect
+                */
+               if (gpio_request_one(gpio + 1, GPIOF_IN, "EHCI_nOC"))
+                       pr_err("%s: unable to configure EHCI_nOC\n", __func__);
        }
 
+       gpio_request_one(gpio + TWL4030_GPIO_MAX, usb_pwr_level, "nEN_USB_PWR");
+
+       /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
+       gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
+
        return 0;
 }
 
@@ -453,15 +409,6 @@ static struct twl4030_platform_data beagle_twldata = {
        .vpll2          = &beagle_vpll2,
 };
 
-static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
-       {
-               I2C_BOARD_INFO("twl4030", 0x48),
-               .flags = I2C_CLIENT_WAKE,
-               .irq = INT_34XX_SYS_NIRQ,
-               .platform_data = &beagle_twldata,
-       },
-};
-
 static struct i2c_board_info __initdata beagle_i2c_eeprom[] = {
        {
                I2C_BOARD_INFO("eeprom", 0x50),
@@ -470,8 +417,7 @@ static struct i2c_board_info __initdata beagle_i2c_eeprom[] = {
 
 static int __init omap3_beagle_i2c_init(void)
 {
-       omap_register_i2c_bus(1, 2600, beagle_i2c_boardinfo,
-                       ARRAY_SIZE(beagle_i2c_boardinfo));
+       omap3_pmic_init("twl4030", &beagle_twldata);
        /* Bus 3 is attached to the DVI port where devices like the pico DLP
         * projector don't work reliably with 400kHz */
        omap_register_i2c_bus(3, 100, beagle_i2c_eeprom, ARRAY_SIZE(beagle_i2c_eeprom));
@@ -551,39 +497,6 @@ static struct platform_device *omap3_beagle_devices[] __initdata = {
        &keys_gpio,
 };
 
-static void __init omap3beagle_flash_init(void)
-{
-       u8 cs = 0;
-       u8 nandcs = GPMC_CS_NUM + 1;
-
-       /* find out the chip-select on which NAND exists */
-       while (cs < GPMC_CS_NUM) {
-               u32 ret = 0;
-               ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-
-               if ((ret & 0xC00) == 0x800) {
-                       printk(KERN_INFO "Found NAND on CS%d\n", cs);
-                       if (nandcs > GPMC_CS_NUM)
-                               nandcs = cs;
-               }
-               cs++;
-       }
-
-       if (nandcs > GPMC_CS_NUM) {
-               printk(KERN_INFO "NAND: Unable to find configuration "
-                                "in GPMC\n ");
-               return;
-       }
-
-       if (nandcs < GPMC_CS_NUM) {
-               omap3beagle_nand_data.cs = nandcs;
-
-               printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-               if (gpmc_nand_init(&omap3beagle_nand_data) < 0)
-                       printk(KERN_ERR "Unable to register NAND device\n");
-       }
-}
-
 static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
 
        .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
@@ -602,12 +515,6 @@ static struct omap_board_mux board_mux[] __initdata = {
 };
 #endif
 
-static struct omap_musb_board_data musb_board_data = {
-       .interface_type         = MUSB_INTERFACE_ULPI,
-       .mode                   = MUSB_OTG,
-       .power                  = 100,
-};
-
 static void __init beagle_opp_init(void)
 {
        int r = 0;
@@ -665,13 +572,16 @@ static void __init omap3_beagle_init(void)
        omap_serial_init();
 
        omap_mux_init_gpio(170, OMAP_PIN_INPUT);
-       gpio_request(170, "DVI_nPD");
        /* REVISIT leave DVI powered down until it's needed ... */
-       gpio_direction_output(170, true);
+       gpio_request_one(170, GPIOF_OUT_INIT_HIGH, "DVI_nPD");
 
-       usb_musb_init(&musb_board_data);
+       usb_musb_init(NULL);
        usbhs_init(&usbhs_bdata);
-       omap3beagle_flash_init();
+       omap_nand_flash_init(NAND_BUSWIDTH_16, omap3beagle_nand_partitions,
+                            ARRAY_SIZE(omap3beagle_nand_partitions));
+
+       /* Ensure msecure is mux'd to be able to set the RTC. */
+       omap_mux_init_signal("sys_drm_msecure", OMAP_PIN_OFF_OUTPUT_HIGH);
 
        /* Ensure SDRC pins are mux'd for self-refresh */
        omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
index 5a1a916e5cc8a1989959d807731d94719eb39513..b4d43464a303f43e5a6283c61dd09b55f657d624 100644 (file)
 #include <plat/usb.h>
 #include <plat/common.h>
 #include <plat/mcspi.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 
 #include "mux.h"
 #include "sdram-micron-mt46h32m32lf-6.h"
 #include "hsmmc.h"
+#include "common-board-devices.h"
 
 #define OMAP3_EVM_TS_GPIO      175
 #define OMAP3_EVM_EHCI_VBUS    22
@@ -101,49 +102,20 @@ static void __init omap3_evm_get_revision(void)
 }
 
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
-static struct resource omap3evm_smsc911x_resources[] = {
-       [0] =   {
-               .start  = OMAP3EVM_ETHR_START,
-               .end    = (OMAP3EVM_ETHR_START + OMAP3EVM_ETHR_SIZE - 1),
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] =   {
-               .start  = OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ),
-               .end    = OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ),
-               .flags  = (IORESOURCE_IRQ | IRQF_TRIGGER_LOW),
-       },
-};
+#include <plat/gpmc-smsc911x.h>
 
-static struct smsc911x_platform_config smsc911x_config = {
-       .phy_interface  = PHY_INTERFACE_MODE_MII,
-       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
-       .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
-       .flags          = (SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS),
-};
-
-static struct platform_device omap3evm_smsc911x_device = {
-       .name           = "smsc911x",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(omap3evm_smsc911x_resources),
-       .resource       = &omap3evm_smsc911x_resources[0],
-       .dev            = {
-               .platform_data = &smsc911x_config,
-       },
+static struct omap_smsc911x_platform_data smsc911x_cfg = {
+       .cs             = OMAP3EVM_SMSC911X_CS,
+       .gpio_irq       = OMAP3EVM_ETHR_GPIO_IRQ,
+       .gpio_reset     = -EINVAL,
+       .flags          = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
 };
 
 static inline void __init omap3evm_init_smsc911x(void)
 {
-       int eth_cs, eth_rst;
        struct clk *l3ck;
        unsigned int rate;
 
-       if (get_omap3_evm_rev() == OMAP3EVM_BOARD_GEN_1)
-               eth_rst = OMAP3EVM_GEN1_ETHR_GPIO_RST;
-       else
-               eth_rst = OMAP3EVM_GEN2_ETHR_GPIO_RST;
-
-       eth_cs = OMAP3EVM_SMSC911X_CS;
-
        l3ck = clk_get(NULL, "l3_ck");
        if (IS_ERR(l3ck))
                rate = 100000000;
@@ -152,33 +124,13 @@ static inline void __init omap3evm_init_smsc911x(void)
 
        /* Configure ethernet controller reset gpio */
        if (cpu_is_omap3430()) {
-               if (gpio_request(eth_rst, "SMSC911x gpio") < 0) {
-                       pr_err(KERN_ERR "Failed to request %d for smsc911x\n",
-                                       eth_rst);
-                       return;
-               }
-
-               if (gpio_direction_output(eth_rst, 1) < 0) {
-                       pr_err(KERN_ERR "Failed to set direction of %d for" \
-                                       " smsc911x\n", eth_rst);
-                       return;
-               }
-               /* reset pulse to ethernet controller*/
-               usleep_range(150, 220);
-               gpio_set_value(eth_rst, 0);
-               usleep_range(150, 220);
-               gpio_set_value(eth_rst, 1);
-               usleep_range(1, 2);
-       }
-
-       if (gpio_request(OMAP3EVM_ETHR_GPIO_IRQ, "SMSC911x irq") < 0) {
-               printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n",
-                       OMAP3EVM_ETHR_GPIO_IRQ);
-               return;
+               if (get_omap3_evm_rev() == OMAP3EVM_BOARD_GEN_1)
+                       smsc911x_cfg.gpio_reset = OMAP3EVM_GEN1_ETHR_GPIO_RST;
+               else
+                       smsc911x_cfg.gpio_reset = OMAP3EVM_GEN2_ETHR_GPIO_RST;
        }
 
-       gpio_direction_input(OMAP3EVM_ETHR_GPIO_IRQ);
-       platform_device_register(&omap3evm_smsc911x_device);
+       gpmc_smsc911x_init(&smsc911x_cfg);
 }
 
 #else
@@ -197,6 +149,15 @@ static inline void __init omap3evm_init_smsc911x(void) { return; }
 #define OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO        210
 #define OMAP3EVM_DVI_PANEL_EN_GPIO     199
 
+static struct gpio omap3_evm_dss_gpios[] __initdata = {
+       { OMAP3EVM_LCD_PANEL_RESB,  GPIOF_OUT_INIT_HIGH, "lcd_panel_resb"  },
+       { OMAP3EVM_LCD_PANEL_INI,   GPIOF_OUT_INIT_HIGH, "lcd_panel_ini"   },
+       { OMAP3EVM_LCD_PANEL_QVGA,  GPIOF_OUT_INIT_LOW,  "lcd_panel_qvga"  },
+       { OMAP3EVM_LCD_PANEL_LR,    GPIOF_OUT_INIT_HIGH, "lcd_panel_lr"    },
+       { OMAP3EVM_LCD_PANEL_UD,    GPIOF_OUT_INIT_HIGH, "lcd_panel_ud"    },
+       { OMAP3EVM_LCD_PANEL_ENVDD, GPIOF_OUT_INIT_LOW,  "lcd_panel_envdd" },
+};
+
 static int lcd_enabled;
 static int dvi_enabled;
 
@@ -204,61 +165,10 @@ static void __init omap3_evm_display_init(void)
 {
        int r;
 
-       r = gpio_request(OMAP3EVM_LCD_PANEL_RESB, "lcd_panel_resb");
-       if (r) {
-               printk(KERN_ERR "failed to get lcd_panel_resb\n");
-               return;
-       }
-       gpio_direction_output(OMAP3EVM_LCD_PANEL_RESB, 1);
-
-       r = gpio_request(OMAP3EVM_LCD_PANEL_INI, "lcd_panel_ini");
-       if (r) {
-               printk(KERN_ERR "failed to get lcd_panel_ini\n");
-               goto err_1;
-       }
-       gpio_direction_output(OMAP3EVM_LCD_PANEL_INI, 1);
-
-       r = gpio_request(OMAP3EVM_LCD_PANEL_QVGA, "lcd_panel_qvga");
-       if (r) {
-               printk(KERN_ERR "failed to get lcd_panel_qvga\n");
-               goto err_2;
-       }
-       gpio_direction_output(OMAP3EVM_LCD_PANEL_QVGA, 0);
-
-       r = gpio_request(OMAP3EVM_LCD_PANEL_LR, "lcd_panel_lr");
-       if (r) {
-               printk(KERN_ERR "failed to get lcd_panel_lr\n");
-               goto err_3;
-       }
-       gpio_direction_output(OMAP3EVM_LCD_PANEL_LR, 1);
-
-       r = gpio_request(OMAP3EVM_LCD_PANEL_UD, "lcd_panel_ud");
-       if (r) {
-               printk(KERN_ERR "failed to get lcd_panel_ud\n");
-               goto err_4;
-       }
-       gpio_direction_output(OMAP3EVM_LCD_PANEL_UD, 1);
-
-       r = gpio_request(OMAP3EVM_LCD_PANEL_ENVDD, "lcd_panel_envdd");
-       if (r) {
-               printk(KERN_ERR "failed to get lcd_panel_envdd\n");
-               goto err_5;
-       }
-       gpio_direction_output(OMAP3EVM_LCD_PANEL_ENVDD, 0);
-
-       return;
-
-err_5:
-       gpio_free(OMAP3EVM_LCD_PANEL_UD);
-err_4:
-       gpio_free(OMAP3EVM_LCD_PANEL_LR);
-err_3:
-       gpio_free(OMAP3EVM_LCD_PANEL_QVGA);
-err_2:
-       gpio_free(OMAP3EVM_LCD_PANEL_INI);
-err_1:
-       gpio_free(OMAP3EVM_LCD_PANEL_RESB);
-
+       r = gpio_request_array(omap3_evm_dss_gpios,
+                              ARRAY_SIZE(omap3_evm_dss_gpios));
+       if (r)
+               printk(KERN_ERR "failed to get lcd_panel_* gpios\n");
 }
 
 static int omap3_evm_enable_lcd(struct omap_dss_device *dssdev)
@@ -448,7 +358,7 @@ static struct platform_device leds_gpio = {
 static int omap3evm_twl_gpio_setup(struct device *dev,
                unsigned gpio, unsigned ngpio)
 {
-       int r;
+       int r, lcd_bl_en;
 
        /* gpio + 0 is "mmc0_cd" (input/IRQ) */
        omap_mux_init_gpio(63, OMAP_PIN_INPUT);
@@ -465,16 +375,14 @@ static int omap3evm_twl_gpio_setup(struct device *dev,
         */
 
        /* TWL4030_GPIO_MAX + 0 == ledA, LCD Backlight control */
-       r = gpio_request(gpio + TWL4030_GPIO_MAX, "EN_LCD_BKL");
-       if (!r)
-               r = gpio_direction_output(gpio + TWL4030_GPIO_MAX,
-                       (get_omap3_evm_rev() >= OMAP3EVM_BOARD_GEN_2) ? 1 : 0);
+       lcd_bl_en = get_omap3_evm_rev() >= OMAP3EVM_BOARD_GEN_2 ?
+               GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+       r = gpio_request_one(gpio + TWL4030_GPIO_MAX, lcd_bl_en, "EN_LCD_BKL");
        if (r)
                printk(KERN_ERR "failed to get/set lcd_bkl gpio\n");
 
        /* gpio + 7 == DVI Enable */
-       gpio_request(gpio + 7, "EN_DVI");
-       gpio_direction_output(gpio + 7, 0);
+       gpio_request_one(gpio + 7, GPIOF_OUT_INIT_LOW, "EN_DVI");
 
        /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
        gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
@@ -652,78 +560,18 @@ static struct twl4030_platform_data omap3evm_twldata = {
        .vdac           = &omap3_evm_vdac,
        .vpll2          = &omap3_evm_vpll2,
        .vio            = &omap3evm_vio,
-};
-
-static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
-       {
-               I2C_BOARD_INFO("twl4030", 0x48),
-               .flags = I2C_CLIENT_WAKE,
-               .irq = INT_34XX_SYS_NIRQ,
-               .platform_data = &omap3evm_twldata,
-       },
+       .vmmc1          = &omap3evm_vmmc1,
+       .vsim           = &omap3evm_vsim,
 };
 
 static int __init omap3_evm_i2c_init(void)
 {
-       /*
-        * REVISIT: These entries can be set in omap3evm_twl_data
-        * after a merge with MFD tree
-        */
-       omap3evm_twldata.vmmc1 = &omap3evm_vmmc1;
-       omap3evm_twldata.vsim = &omap3evm_vsim;
-
-       omap_register_i2c_bus(1, 2600, omap3evm_i2c_boardinfo,
-                       ARRAY_SIZE(omap3evm_i2c_boardinfo));
+       omap3_pmic_init("twl4030", &omap3evm_twldata);
        omap_register_i2c_bus(2, 400, NULL, 0);
        omap_register_i2c_bus(3, 400, NULL, 0);
        return 0;
 }
 
-static void ads7846_dev_init(void)
-{
-       if (gpio_request(OMAP3_EVM_TS_GPIO, "ADS7846 pendown") < 0)
-               printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
-
-       gpio_direction_input(OMAP3_EVM_TS_GPIO);
-       gpio_set_debounce(OMAP3_EVM_TS_GPIO, 310);
-}
-
-static int ads7846_get_pendown_state(void)
-{
-       return !gpio_get_value(OMAP3_EVM_TS_GPIO);
-}
-
-static struct ads7846_platform_data ads7846_config = {
-       .x_max                  = 0x0fff,
-       .y_max                  = 0x0fff,
-       .x_plate_ohms           = 180,
-       .pressure_max           = 255,
-       .debounce_max           = 10,
-       .debounce_tol           = 3,
-       .debounce_rep           = 1,
-       .get_pendown_state      = ads7846_get_pendown_state,
-       .keep_vref_on           = 1,
-       .settle_delay_usecs     = 150,
-       .wakeup                         = true,
-};
-
-static struct omap2_mcspi_device_config ads7846_mcspi_config = {
-       .turbo_mode     = 0,
-       .single_channel = 1,    /* 0: slave, 1: master */
-};
-
-static struct spi_board_info omap3evm_spi_board_info[] = {
-       [0] = {
-               .modalias               = "ads7846",
-               .bus_num                = 1,
-               .chip_select            = 0,
-               .max_speed_hz           = 1500000,
-               .controller_data        = &ads7846_mcspi_config,
-               .irq                    = OMAP_GPIO_IRQ(OMAP3_EVM_TS_GPIO),
-               .platform_data          = &ads7846_config,
-       },
-};
-
 static struct omap_board_config_kernel omap3_evm_config[] __initdata = {
 };
 
@@ -825,6 +673,11 @@ static struct omap_musb_board_data musb_board_data = {
        .power                  = 100,
 };
 
+static struct gpio omap3_evm_ehci_gpios[] __initdata = {
+       { OMAP3_EVM_EHCI_VBUS,   GPIOF_OUT_INIT_HIGH,  "enable EHCI VBUS" },
+       { OMAP3_EVM_EHCI_SELECT, GPIOF_OUT_INIT_LOW,   "select EHCI port" },
+};
+
 static void __init omap3_evm_init(void)
 {
        omap3_evm_get_revision();
@@ -841,9 +694,6 @@ static void __init omap3_evm_init(void)
 
        omap_display_init(&omap3_evm_dss_data);
 
-       spi_register_board_info(omap3evm_spi_board_info,
-                               ARRAY_SIZE(omap3evm_spi_board_info));
-
        omap_serial_init();
 
        /* OMAP3EVM uses ISP1504 phy and so register nop transceiver */
@@ -851,16 +701,12 @@ static void __init omap3_evm_init(void)
 
        if (get_omap3_evm_rev() >= OMAP3EVM_BOARD_GEN_2) {
                /* enable EHCI VBUS using GPIO22 */
-               omap_mux_init_gpio(22, OMAP_PIN_INPUT_PULLUP);
-               gpio_request(OMAP3_EVM_EHCI_VBUS, "enable EHCI VBUS");
-               gpio_direction_output(OMAP3_EVM_EHCI_VBUS, 0);
-               gpio_set_value(OMAP3_EVM_EHCI_VBUS, 1);
-
+               omap_mux_init_gpio(OMAP3_EVM_EHCI_VBUS, OMAP_PIN_INPUT_PULLUP);
                /* Select EHCI port on main board */
-               omap_mux_init_gpio(61, OMAP_PIN_INPUT_PULLUP);
-               gpio_request(OMAP3_EVM_EHCI_SELECT, "select EHCI port");
-               gpio_direction_output(OMAP3_EVM_EHCI_SELECT, 0);
-               gpio_set_value(OMAP3_EVM_EHCI_SELECT, 0);
+               omap_mux_init_gpio(OMAP3_EVM_EHCI_SELECT,
+                                  OMAP_PIN_INPUT_PULLUP);
+               gpio_request_array(omap3_evm_ehci_gpios,
+                                  ARRAY_SIZE(omap3_evm_ehci_gpios));
 
                /* setup EHCI phy reset config */
                omap_mux_init_gpio(21, OMAP_PIN_INPUT_PULLUP);
@@ -876,7 +722,7 @@ static void __init omap3_evm_init(void)
        }
        usb_musb_init(&musb_board_data);
        usbhs_init(&usbhs_bdata);
-       ads7846_dev_init();
+       omap_ads7846_init(1, OMAP3_EVM_TS_GPIO, 310, NULL);
        omap3evm_init_smsc911x();
        omap3_evm_display_init();
 
index b726943d7c93da3b92b79c71d10e790f51cb1539..60d9be49dbab1a3595b12291a65abe36d6724bc4 100644 (file)
@@ -37,6 +37,7 @@
 #include "hsmmc.h"
 #include "timer-gp.h"
 #include "control.h"
+#include "common-board-devices.h"
 
 #include <plat/mux.h>
 #include <plat/board.h>
@@ -93,19 +94,9 @@ static struct twl4030_platform_data omap3logic_twldata = {
        .vmmc1          = &omap3logic_vmmc1,
 };
 
-static struct i2c_board_info __initdata omap3logic_i2c_boardinfo[] = {
-       {
-               I2C_BOARD_INFO("twl4030", 0x48),
-               .flags = I2C_CLIENT_WAKE,
-               .irq = INT_34XX_SYS_NIRQ,
-               .platform_data = &omap3logic_twldata,
-       },
-};
-
 static int __init omap3logic_i2c_init(void)
 {
-       omap_register_i2c_bus(1, 2600, omap3logic_i2c_boardinfo,
-                               ARRAY_SIZE(omap3logic_i2c_boardinfo));
+       omap3_pmic_init("twl4030", &omap3logic_twldata);
        return 0;
 }
 
@@ -147,7 +138,6 @@ static struct omap_smsc911x_platform_data __initdata board_smsc911x_data = {
        .cs             = OMAP3LOGIC_SMSC911X_CS,
        .gpio_irq       = -EINVAL,
        .gpio_reset     = -EINVAL,
-       .flags          = IORESOURCE_IRQ_LOWLEVEL,
 };
 
 /* TODO/FIXME (comment by Peter Barada, LogicPD):
index 07dba888f4502b4a4beb18389c56034439633e0f..23f71d40883ea1fafbd2fd331d33fd9c581731dd 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/platform_device.h>
 
 #include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
 #include <linux/wl12xx.h>
@@ -31,6 +30,7 @@
 #include <linux/leds.h>
 #include <linux/input.h>
 #include <linux/input/matrix_keypad.h>
+#include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
 
 #include <plat/board.h>
 #include <plat/common.h>
-#include <mach/gpio.h>
 #include <mach/hardware.h>
 #include <plat/mcspi.h>
 #include <plat/usb.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/nand.h>
 
 #include "mux.h"
 #include "sdram-micron-mt46h32m32lf-6.h"
 #include "hsmmc.h"
+#include "common-board-devices.h"
 
 #define PANDORA_WIFI_IRQ_GPIO          21
 #define PANDORA_WIFI_NRESET_GPIO       23
 #define OMAP3_PANDORA_TS_GPIO          94
 
-#define NAND_BLOCK_SIZE                        SZ_128K
-
 static struct mtd_partition omap3pandora_nand_partitions[] = {
        {
                .name           = "xloader",
@@ -86,7 +84,8 @@ static struct mtd_partition omap3pandora_nand_partitions[] = {
 
 static struct omap_nand_platform_data pandora_nand_data = {
        .cs             = 0,
-       .devsize        = 1,    /* '0' for 8-bit, '1' for 16-bit device */
+       .devsize        = NAND_BUSWIDTH_16,
+       .xfer_type      = NAND_OMAP_PREFETCH_DMA,
        .parts          = omap3pandora_nand_partitions,
        .nr_parts       = ARRAY_SIZE(omap3pandora_nand_partitions),
 };
@@ -305,24 +304,13 @@ static int omap3pandora_twl_gpio_setup(struct device *dev,
 
        /* gpio + 13 drives 32kHz buffer for wifi module */
        gpio_32khz = gpio + 13;
-       ret = gpio_request(gpio_32khz, "wifi 32kHz");
+       ret = gpio_request_one(gpio_32khz, GPIOF_OUT_INIT_HIGH, "wifi 32kHz");
        if (ret < 0) {
                pr_err("Cannot get GPIO line %d, ret=%d\n", gpio_32khz, ret);
-               goto fail;
-       }
-
-       ret = gpio_direction_output(gpio_32khz, 1);
-       if (ret < 0) {
-               pr_err("Cannot set GPIO line %d, ret=%d\n", gpio_32khz, ret);
-               goto fail_direction;
+               return -ENODEV;
        }
 
        return 0;
-
-fail_direction:
-       gpio_free(gpio_32khz);
-fail:
-       return -ENODEV;
 }
 
 static struct twl4030_gpio_platform_data omap3pandora_gpio_data = {
@@ -544,15 +532,6 @@ static struct twl4030_platform_data omap3pandora_twldata = {
        .bci            = &pandora_bci_data,
 };
 
-static struct i2c_board_info __initdata omap3pandora_i2c_boardinfo[] = {
-       {
-               I2C_BOARD_INFO("tps65950", 0x48),
-               .flags = I2C_CLIENT_WAKE,
-               .irq = INT_34XX_SYS_NIRQ,
-               .platform_data = &omap3pandora_twldata,
-       },
-};
-
 static struct i2c_board_info __initdata omap3pandora_i2c3_boardinfo[] = {
        {
                I2C_BOARD_INFO("bq27500", 0x55),
@@ -562,61 +541,15 @@ static struct i2c_board_info __initdata omap3pandora_i2c3_boardinfo[] = {
 
 static int __init omap3pandora_i2c_init(void)
 {
-       omap_register_i2c_bus(1, 2600, omap3pandora_i2c_boardinfo,
-                       ARRAY_SIZE(omap3pandora_i2c_boardinfo));
+       omap3_pmic_init("tps65950", &omap3pandora_twldata);
        /* i2c2 pins are not connected */
        omap_register_i2c_bus(3, 100, omap3pandora_i2c3_boardinfo,
                        ARRAY_SIZE(omap3pandora_i2c3_boardinfo));
        return 0;
 }
 
-static void __init omap3pandora_ads7846_init(void)
-{
-       int gpio = OMAP3_PANDORA_TS_GPIO;
-       int ret;
-
-       ret = gpio_request(gpio, "ads7846_pen_down");
-       if (ret < 0) {
-               printk(KERN_ERR "Failed to request GPIO %d for "
-                               "ads7846 pen down IRQ\n", gpio);
-               return;
-       }
-
-       gpio_direction_input(gpio);
-}
-
-static int ads7846_get_pendown_state(void)
-{
-       return !gpio_get_value(OMAP3_PANDORA_TS_GPIO);
-}
-
-static struct ads7846_platform_data ads7846_config = {
-       .x_max                  = 0x0fff,
-       .y_max                  = 0x0fff,
-       .x_plate_ohms           = 180,
-       .pressure_max           = 255,
-       .debounce_max           = 10,
-       .debounce_tol           = 3,
-       .debounce_rep           = 1,
-       .get_pendown_state      = ads7846_get_pendown_state,
-       .keep_vref_on           = 1,
-};
-
-static struct omap2_mcspi_device_config ads7846_mcspi_config = {
-       .turbo_mode     = 0,
-       .single_channel = 1,    /* 0: slave, 1: master */
-};
-
 static struct spi_board_info omap3pandora_spi_board_info[] __initdata = {
        {
-               .modalias               = "ads7846",
-               .bus_num                = 1,
-               .chip_select            = 0,
-               .max_speed_hz           = 1500000,
-               .controller_data        = &ads7846_mcspi_config,
-               .irq                    = OMAP_GPIO_IRQ(OMAP3_PANDORA_TS_GPIO),
-               .platform_data          = &ads7846_config,
-       }, {
                .modalias               = "tpo_td043mtea1_panel_spi",
                .bus_num                = 1,
                .chip_select            = 1,
@@ -639,14 +572,10 @@ static void __init pandora_wl1251_init(void)
 
        memset(&pandora_wl1251_pdata, 0, sizeof(pandora_wl1251_pdata));
 
-       ret = gpio_request(PANDORA_WIFI_IRQ_GPIO, "wl1251 irq");
+       ret = gpio_request_one(PANDORA_WIFI_IRQ_GPIO, GPIOF_IN, "wl1251 irq");
        if (ret < 0)
                goto fail;
 
-       ret = gpio_direction_input(PANDORA_WIFI_IRQ_GPIO);
-       if (ret < 0)
-               goto fail_irq;
-
        pandora_wl1251_pdata.irq = gpio_to_irq(PANDORA_WIFI_IRQ_GPIO);
        if (pandora_wl1251_pdata.irq < 0)
                goto fail_irq;
@@ -688,12 +617,6 @@ static struct omap_board_mux board_mux[] __initdata = {
 };
 #endif
 
-static struct omap_musb_board_data musb_board_data = {
-       .interface_type         = MUSB_INTERFACE_ULPI,
-       .mode                   = MUSB_OTG,
-       .power                  = 100,
-};
-
 static void __init omap3pandora_init(void)
 {
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
@@ -705,9 +628,9 @@ static void __init omap3pandora_init(void)
        omap_serial_init();
        spi_register_board_info(omap3pandora_spi_board_info,
                        ARRAY_SIZE(omap3pandora_spi_board_info));
-       omap3pandora_ads7846_init();
+       omap_ads7846_init(1, OMAP3_PANDORA_TS_GPIO, 0, NULL);
        usbhs_init(&usbhs_bdata);
-       usb_musb_init(&musb_board_data);
+       usb_musb_init(NULL);
        gpmc_nand_init(&pandora_nand_data);
 
        /* Ensure SDRC pins are mux'd for self-refresh */
index a6e0b9161c99ceac2b98122f7a5f78955bbf4c53..0c108a212ea2190904bb6e66ee11aad696f40c15 100644 (file)
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 
 #include <plat/mcspi.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
 #include <linux/interrupt.h>
 #include <linux/smsc911x.h>
 #include <linux/i2c/at24.h>
 #include "mux.h"
 #include "hsmmc.h"
 #include "timer-gp.h"
+#include "common-board-devices.h"
 
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
+#include <plat/gpmc-smsc911x.h>
+
 #define OMAP3STALKER_ETHR_START        0x2c000000
 #define OMAP3STALKER_ETHR_SIZE 1024
 #define OMAP3STALKER_ETHR_GPIO_IRQ     19
 #define OMAP3STALKER_SMC911X_CS        5
 
-static struct resource omap3stalker_smsc911x_resources[] = {
-       [0] = {
-              .start   = OMAP3STALKER_ETHR_START,
-              .end     =
-              (OMAP3STALKER_ETHR_START + OMAP3STALKER_ETHR_SIZE - 1),
-              .flags   = IORESOURCE_MEM,
-       },
-       [1] = {
-              .start   = OMAP_GPIO_IRQ(OMAP3STALKER_ETHR_GPIO_IRQ),
-              .end     = OMAP_GPIO_IRQ(OMAP3STALKER_ETHR_GPIO_IRQ),
-              .flags   = (IORESOURCE_IRQ | IRQF_TRIGGER_LOW),
-       },
-};
-
-static struct smsc911x_platform_config smsc911x_config = {
-       .phy_interface  = PHY_INTERFACE_MODE_MII,
-       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
-       .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+static struct omap_smsc911x_platform_data smsc911x_cfg = {
+       .cs             = OMAP3STALKER_SMC911X_CS,
+       .gpio_irq       = OMAP3STALKER_ETHR_GPIO_IRQ,
+       .gpio_reset     = -EINVAL,
        .flags          = (SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS),
 };
 
-static struct platform_device omap3stalker_smsc911x_device = {
-       .name           = "smsc911x",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(omap3stalker_smsc911x_resources),
-       .resource       = &omap3stalker_smsc911x_resources[0],
-       .dev            = {
-               .platform_data  = &smsc911x_config,
-       },
-};
-
 static inline void __init omap3stalker_init_eth(void)
 {
-       int eth_cs;
        struct clk *l3ck;
        unsigned int rate;
 
-       eth_cs = OMAP3STALKER_SMC911X_CS;
-
        l3ck = clk_get(NULL, "l3_ck");
        if (IS_ERR(l3ck))
                rate = 100000000;
@@ -107,16 +82,7 @@ static inline void __init omap3stalker_init_eth(void)
                rate = clk_get_rate(l3ck);
 
        omap_mux_init_gpio(19, OMAP_PIN_INPUT_PULLUP);
-       if (gpio_request(OMAP3STALKER_ETHR_GPIO_IRQ, "SMC911x irq") < 0) {
-               printk(KERN_ERR
-                      "Failed to request GPIO%d for smc911x IRQ\n",
-                      OMAP3STALKER_ETHR_GPIO_IRQ);
-               return;
-       }
-
-       gpio_direction_input(OMAP3STALKER_ETHR_GPIO_IRQ);
-
-       platform_device_register(&omap3stalker_smsc911x_device);
+       gpmc_smsc911x_init(&smsc911x_cfg);
 }
 
 #else
@@ -365,12 +331,11 @@ omap3stalker_twl_gpio_setup(struct device *dev,
         */
 
        /* TWL4030_GPIO_MAX + 0 == ledA, LCD Backlight control */
-       gpio_request(gpio + TWL4030_GPIO_MAX, "EN_LCD_BKL");
-       gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
+       gpio_request_one(gpio + TWL4030_GPIO_MAX, GPIOF_OUT_INIT_LOW,
+                        "EN_LCD_BKL");
 
        /* gpio + 7 == DVI Enable */
-       gpio_request(gpio + 7, "EN_DVI");
-       gpio_direction_output(gpio + 7, 0);
+       gpio_request_one(gpio + 7, GPIOF_OUT_INIT_LOW, "EN_DVI");
 
        /* TWL4030_GPIO_MAX + 1 == ledB (out, mmc0) */
        gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
@@ -489,15 +454,8 @@ static struct twl4030_platform_data omap3stalker_twldata = {
        .codec          = &omap3stalker_codec_data,
        .vdac           = &omap3_stalker_vdac,
        .vpll2          = &omap3_stalker_vpll2,
-};
-
-static struct i2c_board_info __initdata omap3stalker_i2c_boardinfo[] = {
-       {
-        I2C_BOARD_INFO("twl4030", 0x48),
-        .flags         = I2C_CLIENT_WAKE,
-        .irq           = INT_34XX_SYS_NIRQ,
-        .platform_data = &omap3stalker_twldata,
-        },
+       .vmmc1          = &omap3stalker_vmmc1,
+       .vsim           = &omap3stalker_vsim,
 };
 
 static struct at24_platform_data fram_info = {
@@ -516,15 +474,7 @@ static struct i2c_board_info __initdata omap3stalker_i2c_boardinfo3[] = {
 
 static int __init omap3_stalker_i2c_init(void)
 {
-       /*
-        * REVISIT: These entries can be set in omap3evm_twl_data
-        * after a merge with MFD tree
-        */
-       omap3stalker_twldata.vmmc1 = &omap3stalker_vmmc1;
-       omap3stalker_twldata.vsim = &omap3stalker_vsim;
-
-       omap_register_i2c_bus(1, 2600, omap3stalker_i2c_boardinfo,
-                             ARRAY_SIZE(omap3stalker_i2c_boardinfo));
+       omap3_pmic_init("twl4030", &omap3stalker_twldata);
        omap_register_i2c_bus(2, 400, NULL, 0);
        omap_register_i2c_bus(3, 400, omap3stalker_i2c_boardinfo3,
                              ARRAY_SIZE(omap3stalker_i2c_boardinfo3));
@@ -532,49 +482,6 @@ static int __init omap3_stalker_i2c_init(void)
 }
 
 #define OMAP3_STALKER_TS_GPIO  175
-static void ads7846_dev_init(void)
-{
-       if (gpio_request(OMAP3_STALKER_TS_GPIO, "ADS7846 pendown") < 0)
-               printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
-
-       gpio_direction_input(OMAP3_STALKER_TS_GPIO);
-       gpio_set_debounce(OMAP3_STALKER_TS_GPIO, 310);
-}
-
-static int ads7846_get_pendown_state(void)
-{
-       return !gpio_get_value(OMAP3_STALKER_TS_GPIO);
-}
-
-static struct ads7846_platform_data ads7846_config = {
-       .x_max                  = 0x0fff,
-       .y_max                  = 0x0fff,
-       .x_plate_ohms           = 180,
-       .pressure_max           = 255,
-       .debounce_max           = 10,
-       .debounce_tol           = 3,
-       .debounce_rep           = 1,
-       .get_pendown_state      = ads7846_get_pendown_state,
-       .keep_vref_on           = 1,
-       .settle_delay_usecs     = 150,
-};
-
-static struct omap2_mcspi_device_config ads7846_mcspi_config = {
-       .turbo_mode             = 0,
-       .single_channel         = 1,    /* 0: slave, 1: master */
-};
-
-static struct spi_board_info omap3stalker_spi_board_info[] = {
-       [0] = {
-              .modalias        = "ads7846",
-              .bus_num         = 1,
-              .chip_select     = 0,
-              .max_speed_hz    = 1500000,
-              .controller_data = &ads7846_mcspi_config,
-              .irq             = OMAP_GPIO_IRQ(OMAP3_STALKER_TS_GPIO),
-              .platform_data   = &ads7846_config,
-       },
-};
 
 static struct omap_board_config_kernel omap3_stalker_config[] __initdata = {
 };
@@ -618,12 +525,6 @@ static struct omap_board_mux board_mux[] __initdata = {
 };
 #endif
 
-static struct omap_musb_board_data musb_board_data = {
-       .interface_type = MUSB_INTERFACE_ULPI,
-       .mode           = MUSB_OTG,
-       .power          = 100,
-};
-
 static void __init omap3_stalker_init(void)
 {
        omap3_mux_init(board_mux, OMAP_PACKAGE_CUS);
@@ -636,13 +537,11 @@ static void __init omap3_stalker_init(void)
                             ARRAY_SIZE(omap3_stalker_devices));
 
        omap_display_init(&omap3_stalker_dss_data);
-       spi_register_board_info(omap3stalker_spi_board_info,
-                               ARRAY_SIZE(omap3stalker_spi_board_info));
 
        omap_serial_init();
-       usb_musb_init(&musb_board_data);
+       usb_musb_init(NULL);
        usbhs_init(&usbhs_bdata);
-       ads7846_dev_init();
+       omap_ads7846_init(1, OMAP3_STALKER_TS_GPIO, 310, NULL);
 
        omap_mux_init_gpio(21, OMAP_PIN_OUTPUT);
        omap_mux_init_gpio(18, OMAP_PIN_INPUT_PULLUP);
index 127cb1752bddea97edff181a4a3dc3022c306480..5f649faf7377ecb757c49c73e9430d91adf2940f 100644 (file)
 #include "mux.h"
 #include "hsmmc.h"
 #include "timer-gp.h"
+#include "common-board-devices.h"
 
 #include <asm/setup.h>
 
-#define NAND_BLOCK_SIZE                SZ_128K
-
 #define OMAP3_AC_GPIO          136
 #define OMAP3_TS_GPIO          162
 #define TB_BL_PWM_TIMER                9
@@ -95,15 +94,6 @@ static struct mtd_partition omap3touchbook_nand_partitions[] = {
        },
 };
 
-static struct omap_nand_platform_data omap3touchbook_nand_data = {
-       .options        = NAND_BUSWIDTH_16,
-       .parts          = omap3touchbook_nand_partitions,
-       .nr_parts       = ARRAY_SIZE(omap3touchbook_nand_partitions),
-       .dma_channel    = -1,           /* disable DMA in OMAP NAND driver */
-       .nand_setup     = NULL,
-       .dev_ready      = NULL,
-};
-
 #include "sdram-micron-mt46h32m32lf-6.h"
 
 static struct omap2_hsmmc_info mmc[] = {
@@ -154,13 +144,11 @@ static int touchbook_twl_gpio_setup(struct device *dev,
        /* REVISIT: need ehci-omap hooks for external VBUS
         * power switch and overcurrent detect
         */
-
-       gpio_request(gpio + 1, "EHCI_nOC");
-       gpio_direction_input(gpio + 1);
+       gpio_request_one(gpio + 1, GPIOF_IN, "EHCI_nOC");
 
        /* TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, active low) */
-       gpio_request(gpio + TWL4030_GPIO_MAX, "nEN_USB_PWR");
-       gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
+       gpio_request_one(gpio + TWL4030_GPIO_MAX, GPIOF_OUT_INIT_LOW,
+                        "nEN_USB_PWR");
 
        /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
        gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
@@ -273,15 +261,6 @@ static struct twl4030_platform_data touchbook_twldata = {
        .vpll2          = &touchbook_vpll2,
 };
 
-static struct i2c_board_info __initdata touchbook_i2c_boardinfo[] = {
-       {
-               I2C_BOARD_INFO("twl4030", 0x48),
-               .flags = I2C_CLIENT_WAKE,
-               .irq = INT_34XX_SYS_NIRQ,
-               .platform_data = &touchbook_twldata,
-       },
-};
-
 static struct i2c_board_info __initdata touchBook_i2c_boardinfo[] = {
        {
                I2C_BOARD_INFO("bq27200", 0x55),
@@ -291,8 +270,7 @@ static struct i2c_board_info __initdata touchBook_i2c_boardinfo[] = {
 static int __init omap3_touchbook_i2c_init(void)
 {
        /* Standard TouchBook bus */
-       omap_register_i2c_bus(1, 2600, touchbook_i2c_boardinfo,
-                       ARRAY_SIZE(touchbook_i2c_boardinfo));
+       omap3_pmic_init("twl4030", &touchbook_twldata);
 
        /* Additional TouchBook bus */
        omap_register_i2c_bus(3, 100, touchBook_i2c_boardinfo,
@@ -301,19 +279,7 @@ static int __init omap3_touchbook_i2c_init(void)
        return 0;
 }
 
-static void __init omap3_ads7846_init(void)
-{
-       if (gpio_request(OMAP3_TS_GPIO, "ads7846_pen_down")) {
-               printk(KERN_ERR "Failed to request GPIO %d for "
-                               "ads7846 pen down IRQ\n", OMAP3_TS_GPIO);
-               return;
-       }
-
-       gpio_direction_input(OMAP3_TS_GPIO);
-       gpio_set_debounce(OMAP3_TS_GPIO, 310);
-}
-
-static struct ads7846_platform_data ads7846_config = {
+static struct ads7846_platform_data ads7846_pdata = {
        .x_min                  = 100,
        .y_min                  = 265,
        .x_max                  = 3950,
@@ -327,23 +293,6 @@ static struct ads7846_platform_data ads7846_config = {
        .keep_vref_on           = 1,
 };
 
-static struct omap2_mcspi_device_config ads7846_mcspi_config = {
-       .turbo_mode     = 0,
-       .single_channel = 1,    /* 0: slave, 1: master */
-};
-
-static struct spi_board_info omap3_ads7846_spi_board_info[] __initdata = {
-       {
-               .modalias               = "ads7846",
-               .bus_num                = 4,
-               .chip_select            = 0,
-               .max_speed_hz           = 1500000,
-               .controller_data        = &ads7846_mcspi_config,
-               .irq                    = OMAP_GPIO_IRQ(OMAP3_TS_GPIO),
-               .platform_data          = &ads7846_config,
-       }
-};
-
 static struct gpio_led gpio_leds[] = {
        {
                .name                   = "touchbook::usr0",
@@ -434,39 +383,6 @@ static struct platform_device *omap3_touchbook_devices[] __initdata = {
        &keys_gpio,
 };
 
-static void __init omap3touchbook_flash_init(void)
-{
-       u8 cs = 0;
-       u8 nandcs = GPMC_CS_NUM + 1;
-
-       /* find out the chip-select on which NAND exists */
-       while (cs < GPMC_CS_NUM) {
-               u32 ret = 0;
-               ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-
-               if ((ret & 0xC00) == 0x800) {
-                       printk(KERN_INFO "Found NAND on CS%d\n", cs);
-                       if (nandcs > GPMC_CS_NUM)
-                               nandcs = cs;
-               }
-               cs++;
-       }
-
-       if (nandcs > GPMC_CS_NUM) {
-               printk(KERN_INFO "NAND: Unable to find configuration "
-                                "in GPMC\n ");
-               return;
-       }
-
-       if (nandcs < GPMC_CS_NUM) {
-               omap3touchbook_nand_data.cs = nandcs;
-
-               printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-               if (gpmc_nand_init(&omap3touchbook_nand_data) < 0)
-                       printk(KERN_ERR "Unable to register NAND device\n");
-       }
-}
-
 static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
 
        .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
@@ -481,15 +397,10 @@ static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
 
 static void omap3_touchbook_poweroff(void)
 {
-       int r;
+       int pwr_off = TB_KILL_POWER_GPIO;
 
-       r = gpio_request(TB_KILL_POWER_GPIO, "DVI reset");
-       if (r < 0) {
+       if (gpio_request_one(pwr_off, GPIOF_OUT_INIT_LOW, "DVI reset") < 0)
                printk(KERN_ERR "Unable to get kill power GPIO\n");
-               return;
-       }
-
-       gpio_direction_output(TB_KILL_POWER_GPIO, 0);
 }
 
 static int __init early_touchbook_revision(char *p)
@@ -501,12 +412,6 @@ static int __init early_touchbook_revision(char *p)
 }
 early_param("tbr", early_touchbook_revision);
 
-static struct omap_musb_board_data musb_board_data = {
-       .interface_type         = MUSB_INTERFACE_ULPI,
-       .mode                   = MUSB_OTG,
-       .power                  = 100,
-};
-
 static void __init omap3_touchbook_init(void)
 {
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
@@ -521,17 +426,15 @@ static void __init omap3_touchbook_init(void)
        omap_serial_init();
 
        omap_mux_init_gpio(170, OMAP_PIN_INPUT);
-       gpio_request(176, "DVI_nPD");
        /* REVISIT leave DVI powered down until it's needed ... */
-       gpio_direction_output(176, true);
+       gpio_request_one(176, GPIOF_OUT_INIT_HIGH, "DVI_nPD");
 
        /* Touchscreen and accelerometer */
-       spi_register_board_info(omap3_ads7846_spi_board_info,
-                               ARRAY_SIZE(omap3_ads7846_spi_board_info));
-       omap3_ads7846_init();
-       usb_musb_init(&musb_board_data);
+       omap_ads7846_init(4, OMAP3_TS_GPIO, 310, &ads7846_pdata);
+       usb_musb_init(NULL);
        usbhs_init(&usbhs_bdata);
-       omap3touchbook_flash_init();
+       omap_nand_flash_init(NAND_BUSWIDTH_16, omap3touchbook_nand_partitions,
+                            ARRAY_SIZE(omap3touchbook_nand_partitions));
 
        /* Ensure SDRC pins are mux'd for self-refresh */
        omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
index f3a7b1011914c7958e5fdd5ce51b2790c74702ea..0cfe2005cb506a32c79d96f9864bb7e24bd35a0f 100644 (file)
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #include <plat/board.h>
 #include <plat/common.h>
 #include <plat/usb.h>
 #include <plat/mmc.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omap-panel-generic-dpi.h>
 #include "timer-gp.h"
 
 #include "hsmmc.h"
 #include "control.h"
 #include "mux.h"
+#include "common-board-devices.h"
 
 #define GPIO_HUB_POWER         1
 #define GPIO_HUB_NRESET                62
@@ -111,6 +112,11 @@ static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
        .reset_gpio_port[2]  = -EINVAL
 };
 
+static struct gpio panda_ehci_gpios[] __initdata = {
+       { GPIO_HUB_POWER,       GPIOF_OUT_INIT_LOW,  "hub_power"  },
+       { GPIO_HUB_NRESET,      GPIOF_OUT_INIT_LOW,  "hub_nreset" },
+};
+
 static void __init omap4_ehci_init(void)
 {
        int ret;
@@ -120,44 +126,27 @@ static void __init omap4_ehci_init(void)
        phy_ref_clk = clk_get(NULL, "auxclk3_ck");
        if (IS_ERR(phy_ref_clk)) {
                pr_err("Cannot request auxclk3\n");
-               goto error1;
+               return;
        }
        clk_set_rate(phy_ref_clk, 19200000);
        clk_enable(phy_ref_clk);
 
-       /* disable the power to the usb hub prior to init */
-       ret = gpio_request(GPIO_HUB_POWER, "hub_power");
+       /* disable the power to the usb hub prior to init and reset phy+hub */
+       ret = gpio_request_array(panda_ehci_gpios,
+                                ARRAY_SIZE(panda_ehci_gpios));
        if (ret) {
-               pr_err("Cannot request GPIO %d\n", GPIO_HUB_POWER);
-               goto error1;
+               pr_err("Unable to initialize EHCI power/reset\n");
+               return;
        }
-       gpio_export(GPIO_HUB_POWER, 0);
-       gpio_direction_output(GPIO_HUB_POWER, 0);
-       gpio_set_value(GPIO_HUB_POWER, 0);
 
-       /* reset phy+hub */
-       ret = gpio_request(GPIO_HUB_NRESET, "hub_nreset");
-       if (ret) {
-               pr_err("Cannot request GPIO %d\n", GPIO_HUB_NRESET);
-               goto error2;
-       }
+       gpio_export(GPIO_HUB_POWER, 0);
        gpio_export(GPIO_HUB_NRESET, 0);
-       gpio_direction_output(GPIO_HUB_NRESET, 0);
-       gpio_set_value(GPIO_HUB_NRESET, 0);
        gpio_set_value(GPIO_HUB_NRESET, 1);
 
        usbhs_init(&usbhs_bdata);
 
        /* enable power to hub */
        gpio_set_value(GPIO_HUB_POWER, 1);
-       return;
-
-error2:
-       gpio_free(GPIO_HUB_POWER);
-error1:
-       pr_err("Unable to initialize EHCI power/reset\n");
-       return;
-
 }
 
 static struct omap_musb_board_data musb_board_data = {
@@ -408,15 +397,6 @@ static struct twl4030_platform_data omap4_panda_twldata = {
        .usb            = &omap4_usbphy_data,
 };
 
-static struct i2c_board_info __initdata omap4_panda_i2c_boardinfo[] = {
-       {
-               I2C_BOARD_INFO("twl6030", 0x48),
-               .flags = I2C_CLIENT_WAKE,
-               .irq = OMAP44XX_IRQ_SYS_1N,
-               .platform_data = &omap4_panda_twldata,
-       },
-};
-
 /*
  * Display monitor features are burnt in their EEPROM as EDID data. The EEPROM
  * is connected as I2C slave device, and can be accessed at address 0x50
@@ -429,12 +409,7 @@ static struct i2c_board_info __initdata panda_i2c_eeprom[] = {
 
 static int __init omap4_panda_i2c_init(void)
 {
-       /*
-        * Phoenix Audio IC needs I2C1 to
-        * start with 400 KHz or less
-        */
-       omap_register_i2c_bus(1, 400, omap4_panda_i2c_boardinfo,
-                       ARRAY_SIZE(omap4_panda_i2c_boardinfo));
+       omap4_pmic_init("twl6030", &omap4_panda_twldata);
        omap_register_i2c_bus(2, 400, NULL, 0);
        /*
         * Bus 3 is attached to the DVI port where devices like the pico DLP
@@ -551,19 +526,19 @@ static struct omap_device_pad serial4_pads[] __initdata = {
                         OMAP_PIN_OUTPUT | OMAP_MUX_MODE0),
 };
 
-static struct omap_board_data serial2_data = {
+static struct omap_board_data serial2_data __initdata = {
        .id             = 1,
        .pads           = serial2_pads,
        .pads_cnt       = ARRAY_SIZE(serial2_pads),
 };
 
-static struct omap_board_data serial3_data = {
+static struct omap_board_data serial3_data __initdata = {
        .id             = 2,
        .pads           = serial3_pads,
        .pads_cnt       = ARRAY_SIZE(serial3_pads),
 };
 
-static struct omap_board_data serial4_data = {
+static struct omap_board_data serial4_data __initdata = {
        .id             = 3,
        .pads           = serial4_pads,
        .pads_cnt       = ARRAY_SIZE(serial4_pads),
@@ -651,27 +626,19 @@ static void omap4_panda_hdmi_mux_init(void)
                        OMAP_PIN_INPUT_PULLUP);
 }
 
+static struct gpio panda_hdmi_gpios[] = {
+       { HDMI_GPIO_HPD,        GPIOF_OUT_INIT_HIGH, "hdmi_gpio_hpd"   },
+       { HDMI_GPIO_LS_OE,      GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" },
+};
+
 static int omap4_panda_panel_enable_hdmi(struct omap_dss_device *dssdev)
 {
        int status;
 
-       status = gpio_request_one(HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH,
-                                                       "hdmi_gpio_hpd");
-       if (status) {
-               pr_err("Cannot request GPIO %d\n", HDMI_GPIO_HPD);
-               return status;
-       }
-       status = gpio_request_one(HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH,
-                                                       "hdmi_gpio_ls_oe");
-       if (status) {
-               pr_err("Cannot request GPIO %d\n", HDMI_GPIO_LS_OE);
-               goto error1;
-       }
-
-       return 0;
-
-error1:
-       gpio_free(HDMI_GPIO_HPD);
+       status = gpio_request_array(panda_hdmi_gpios,
+                                   ARRAY_SIZE(panda_hdmi_gpios));
+       if (status)
+               pr_err("Cannot request HDMI GPIOs\n");
 
        return status;
 }
@@ -720,7 +687,7 @@ static void __init omap4_panda_init(void)
 
        if (omap_rev() == OMAP4430_REV_ES1_0)
                package = OMAP_PACKAGE_CBL;
-       omap4_mux_init(board_mux, package);
+       omap4_mux_init(board_mux, NULL, package);
 
        if (wl12xx_set_platform_data(&omap_panda_wlan_data))
                pr_err("error setting wl12xx data\n");
index 59ca33326b8c630ff789bf3f003c1b6e4ecadd68..175e1ab2b04d7225a0a13485e12e239e9692030d 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/gpio.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/i2c/twl.h>
@@ -43,9 +44,8 @@
 
 #include <plat/board.h>
 #include <plat/common.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
-#include <mach/gpio.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 #include <plat/gpmc.h>
 #include <mach/hardware.h>
 #include <plat/nand.h>
@@ -56,6 +56,7 @@
 #include "mux.h"
 #include "sdram-micron-mt46h32m32lf-6.h"
 #include "hsmmc.h"
+#include "common-board-devices.h"
 
 #define OVERO_GPIO_BT_XGATE    15
 #define OVERO_GPIO_W2W_NRESET  16
@@ -64,8 +65,6 @@
 #define OVERO_GPIO_USBH_CPEN   168
 #define OVERO_GPIO_USBH_NRESET 183
 
-#define NAND_BLOCK_SIZE SZ_128K
-
 #define OVERO_SMSC911X_CS      5
 #define OVERO_SMSC911X_GPIO    176
 #define OVERO_SMSC911X2_CS     4
 #if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
        defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
 
-#include <linux/spi/ads7846.h>
-
-static struct omap2_mcspi_device_config ads7846_mcspi_config = {
-       .turbo_mode     = 0,
-       .single_channel = 1,    /* 0: slave, 1: master */
-};
-
-static int ads7846_get_pendown_state(void)
-{
-       return !gpio_get_value(OVERO_GPIO_PENDOWN);
-}
-
-static struct ads7846_platform_data ads7846_config = {
-       .x_max                  = 0x0fff,
-       .y_max                  = 0x0fff,
-       .x_plate_ohms           = 180,
-       .pressure_max           = 255,
-       .debounce_max           = 10,
-       .debounce_tol           = 3,
-       .debounce_rep           = 1,
-       .get_pendown_state      = ads7846_get_pendown_state,
-       .keep_vref_on           = 1,
-};
-
 /* fixed regulator for ads7846 */
 static struct regulator_consumer_supply ads7846_supply =
        REGULATOR_SUPPLY("vcc", "spi1.0");
@@ -128,14 +103,7 @@ static struct platform_device vads7846_device = {
 
 static void __init overo_ads7846_init(void)
 {
-       if ((gpio_request(OVERO_GPIO_PENDOWN, "ADS7846_PENDOWN") == 0) &&
-           (gpio_direction_input(OVERO_GPIO_PENDOWN) == 0)) {
-               gpio_export(OVERO_GPIO_PENDOWN, 0);
-       } else {
-               printk(KERN_ERR "could not obtain gpio for ADS7846_PENDOWN\n");
-               return;
-       }
-
+       omap_ads7846_init(1, OVERO_GPIO_PENDOWN, 0, NULL);
        platform_device_register(&vads7846_device);
 }
 
@@ -146,106 +114,28 @@ static inline void __init overo_ads7846_init(void) { return; }
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
 
 #include <linux/smsc911x.h>
+#include <plat/gpmc-smsc911x.h>
 
-static struct resource overo_smsc911x_resources[] = {
-       {
-               .name   = "smsc911x-memory",
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
-       },
-};
-
-static struct resource overo_smsc911x2_resources[] = {
-       {
-               .name   = "smsc911x2-memory",
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
-       },
-};
-
-static struct smsc911x_platform_config overo_smsc911x_config = {
-       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
-       .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
-       .flags          = SMSC911X_USE_32BIT ,
-       .phy_interface  = PHY_INTERFACE_MODE_MII,
-};
-
-static struct platform_device overo_smsc911x_device = {
-       .name           = "smsc911x",
+static struct omap_smsc911x_platform_data smsc911x_cfg = {
        .id             = 0,
-       .num_resources  = ARRAY_SIZE(overo_smsc911x_resources),
-       .resource       = overo_smsc911x_resources,
-       .dev            = {
-               .platform_data = &overo_smsc911x_config,
-       },
+       .cs             = OVERO_SMSC911X_CS,
+       .gpio_irq       = OVERO_SMSC911X_GPIO,
+       .gpio_reset     = -EINVAL,
+       .flags          = SMSC911X_USE_32BIT,
 };
 
-static struct platform_device overo_smsc911x2_device = {
-       .name           = "smsc911x",
+static struct omap_smsc911x_platform_data smsc911x2_cfg = {
        .id             = 1,
-       .num_resources  = ARRAY_SIZE(overo_smsc911x2_resources),
-       .resource       = overo_smsc911x2_resources,
-       .dev            = {
-               .platform_data = &overo_smsc911x_config,
-       },
-};
-
-static struct platform_device *smsc911x_devices[] = {
-       &overo_smsc911x_device,
-       &overo_smsc911x2_device,
+       .cs             = OVERO_SMSC911X2_CS,
+       .gpio_irq       = OVERO_SMSC911X2_GPIO,
+       .gpio_reset     = -EINVAL,
+       .flags          = SMSC911X_USE_32BIT,
 };
 
-static inline void __init overo_init_smsc911x(void)
+static void __init overo_init_smsc911x(void)
 {
-       unsigned long cs_mem_base, cs_mem_base2;
-
-       /* set up first smsc911x chip */
-
-       if (gpmc_cs_request(OVERO_SMSC911X_CS, SZ_16M, &cs_mem_base) < 0) {
-               printk(KERN_ERR "Failed request for GPMC mem for smsc911x\n");
-               return;
-       }
-
-       overo_smsc911x_resources[0].start = cs_mem_base + 0x0;
-       overo_smsc911x_resources[0].end   = cs_mem_base + 0xff;
-
-       if ((gpio_request(OVERO_SMSC911X_GPIO, "SMSC911X IRQ") == 0) &&
-           (gpio_direction_input(OVERO_SMSC911X_GPIO) == 0)) {
-               gpio_export(OVERO_SMSC911X_GPIO, 0);
-       } else {
-               printk(KERN_ERR "could not obtain gpio for SMSC911X IRQ\n");
-               return;
-       }
-
-       overo_smsc911x_resources[1].start = OMAP_GPIO_IRQ(OVERO_SMSC911X_GPIO);
-       overo_smsc911x_resources[1].end   = 0;
-
-       /* set up second smsc911x chip */
-
-       if (gpmc_cs_request(OVERO_SMSC911X2_CS, SZ_16M, &cs_mem_base2) < 0) {
-               printk(KERN_ERR "Failed request for GPMC mem for smsc911x2\n");
-               return;
-       }
-
-       overo_smsc911x2_resources[0].start = cs_mem_base2 + 0x0;
-       overo_smsc911x2_resources[0].end   = cs_mem_base2 + 0xff;
-
-       if ((gpio_request(OVERO_SMSC911X2_GPIO, "SMSC911X2 IRQ") == 0) &&
-           (gpio_direction_input(OVERO_SMSC911X2_GPIO) == 0)) {
-               gpio_export(OVERO_SMSC911X2_GPIO, 0);
-       } else {
-               printk(KERN_ERR "could not obtain gpio for SMSC911X2 IRQ\n");
-               return;
-       }
-
-       overo_smsc911x2_resources[1].start = OMAP_GPIO_IRQ(OVERO_SMSC911X2_GPIO);
-       overo_smsc911x2_resources[1].end   = 0;
-
-       platform_add_devices(smsc911x_devices, ARRAY_SIZE(smsc911x_devices));
+       gpmc_smsc911x_init(&smsc911x_cfg);
+       gpmc_smsc911x_init(&smsc911x2_cfg);
 }
 
 #else
@@ -259,21 +149,20 @@ static int dvi_enabled;
 #define OVERO_GPIO_LCD_EN 144
 #define OVERO_GPIO_LCD_BL 145
 
+static struct gpio overo_dss_gpios[] __initdata = {
+       { OVERO_GPIO_LCD_EN, GPIOF_OUT_INIT_HIGH, "OVERO_GPIO_LCD_EN" },
+       { OVERO_GPIO_LCD_BL, GPIOF_OUT_INIT_HIGH, "OVERO_GPIO_LCD_BL" },
+};
+
 static void __init overo_display_init(void)
 {
-       if ((gpio_request(OVERO_GPIO_LCD_EN, "OVERO_GPIO_LCD_EN") == 0) &&
-           (gpio_direction_output(OVERO_GPIO_LCD_EN, 1) == 0))
-               gpio_export(OVERO_GPIO_LCD_EN, 0);
-       else
-               printk(KERN_ERR "could not obtain gpio for "
-                                       "OVERO_GPIO_LCD_EN\n");
+       if (gpio_request_array(overo_dss_gpios, ARRAY_SIZE(overo_dss_gpios))) {
+               printk(KERN_ERR "could not obtain DSS control GPIOs\n");
+               return;
+       }
 
-       if ((gpio_request(OVERO_GPIO_LCD_BL, "OVERO_GPIO_LCD_BL") == 0) &&
-           (gpio_direction_output(OVERO_GPIO_LCD_BL, 1) == 0))
-               gpio_export(OVERO_GPIO_LCD_BL, 0);
-       else
-               printk(KERN_ERR "could not obtain gpio for "
-                                       "OVERO_GPIO_LCD_BL\n");
+       gpio_export(OVERO_GPIO_LCD_EN, 0);
+       gpio_export(OVERO_GPIO_LCD_BL, 0);
 }
 
 static int overo_panel_enable_dvi(struct omap_dss_device *dssdev)
@@ -412,45 +301,6 @@ static struct mtd_partition overo_nand_partitions[] = {
        },
 };
 
-static struct omap_nand_platform_data overo_nand_data = {
-       .parts = overo_nand_partitions,
-       .nr_parts = ARRAY_SIZE(overo_nand_partitions),
-       .dma_channel = -1,      /* disable DMA in OMAP NAND driver */
-};
-
-static void __init overo_flash_init(void)
-{
-       u8 cs = 0;
-       u8 nandcs = GPMC_CS_NUM + 1;
-
-       /* find out the chip-select on which NAND exists */
-       while (cs < GPMC_CS_NUM) {
-               u32 ret = 0;
-               ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-
-               if ((ret & 0xC00) == 0x800) {
-                       printk(KERN_INFO "Found NAND on CS%d\n", cs);
-                       if (nandcs > GPMC_CS_NUM)
-                               nandcs = cs;
-               }
-               cs++;
-       }
-
-       if (nandcs > GPMC_CS_NUM) {
-               printk(KERN_INFO "NAND: Unable to find configuration "
-                                "in GPMC\n ");
-               return;
-       }
-
-       if (nandcs < GPMC_CS_NUM) {
-               overo_nand_data.cs = nandcs;
-
-               printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-               if (gpmc_nand_init(&overo_nand_data) < 0)
-                       printk(KERN_ERR "Unable to register NAND device\n");
-       }
-}
-
 static struct omap2_hsmmc_info mmc[] = {
        {
                .mmc            = 1,
@@ -648,37 +498,15 @@ static struct twl4030_platform_data overo_twldata = {
        .vpll2          = &overo_vpll2,
 };
 
-static struct i2c_board_info __initdata overo_i2c_boardinfo[] = {
-       {
-               I2C_BOARD_INFO("tps65950", 0x48),
-               .flags = I2C_CLIENT_WAKE,
-               .irq = INT_34XX_SYS_NIRQ,
-               .platform_data = &overo_twldata,
-       },
-};
-
 static int __init overo_i2c_init(void)
 {
-       omap_register_i2c_bus(1, 2600, overo_i2c_boardinfo,
-                       ARRAY_SIZE(overo_i2c_boardinfo));
+       omap3_pmic_init("tps65950", &overo_twldata);
        /* i2c2 pins are used for gpio */
        omap_register_i2c_bus(3, 400, NULL, 0);
        return 0;
 }
 
 static struct spi_board_info overo_spi_board_info[] __initdata = {
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
-       defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
-       {
-               .modalias               = "ads7846",
-               .bus_num                = 1,
-               .chip_select            = 0,
-               .max_speed_hz           = 1500000,
-               .controller_data        = &ads7846_mcspi_config,
-               .irq                    = OMAP_GPIO_IRQ(OVERO_GPIO_PENDOWN),
-               .platform_data          = &ads7846_config,
-       },
-#endif
 #if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \
        defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE)
        {
@@ -722,20 +550,22 @@ static struct omap_board_mux board_mux[] __initdata = {
 };
 #endif
 
-static struct omap_musb_board_data musb_board_data = {
-       .interface_type         = MUSB_INTERFACE_ULPI,
-       .mode                   = MUSB_OTG,
-       .power                  = 100,
+static struct gpio overo_bt_gpios[] __initdata = {
+       { OVERO_GPIO_BT_XGATE,  GPIOF_OUT_INIT_LOW,     "lcd enable"    },
+       { OVERO_GPIO_BT_NRESET, GPIOF_OUT_INIT_HIGH,    "lcd bl enable" },
 };
 
 static void __init overo_init(void)
 {
+       int ret;
+
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
        overo_i2c_init();
        omap_display_init(&overo_dss_data);
        omap_serial_init();
-       overo_flash_init();
-       usb_musb_init(&musb_board_data);
+       omap_nand_flash_init(0, overo_nand_partitions,
+                            ARRAY_SIZE(overo_nand_partitions));
+       usb_musb_init(NULL);
        usbhs_init(&usbhs_bdata);
        overo_spi_init();
        overo_ads7846_init();
@@ -748,9 +578,9 @@ static void __init overo_init(void)
        omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
        omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
 
-       if ((gpio_request(OVERO_GPIO_W2W_NRESET,
-                         "OVERO_GPIO_W2W_NRESET") == 0) &&
-           (gpio_direction_output(OVERO_GPIO_W2W_NRESET, 1) == 0)) {
+       ret = gpio_request_one(OVERO_GPIO_W2W_NRESET, GPIOF_OUT_INIT_HIGH,
+                              "OVERO_GPIO_W2W_NRESET");
+       if (ret == 0) {
                gpio_export(OVERO_GPIO_W2W_NRESET, 0);
                gpio_set_value(OVERO_GPIO_W2W_NRESET, 0);
                udelay(10);
@@ -760,25 +590,20 @@ static void __init overo_init(void)
                                        "OVERO_GPIO_W2W_NRESET\n");
        }
 
-       if ((gpio_request(OVERO_GPIO_BT_XGATE, "OVERO_GPIO_BT_XGATE") == 0) &&
-           (gpio_direction_output(OVERO_GPIO_BT_XGATE, 0) == 0))
+       ret = gpio_request_array(overo_bt_gpios, ARRAY_SIZE(overo_bt_gpios));
+       if (ret) {
+               pr_err("%s: could not obtain BT gpios\n", __func__);
+       } else {
                gpio_export(OVERO_GPIO_BT_XGATE, 0);
-       else
-               printk(KERN_ERR "could not obtain gpio for OVERO_GPIO_BT_XGATE\n");
-
-       if ((gpio_request(OVERO_GPIO_BT_NRESET, "OVERO_GPIO_BT_NRESET") == 0) &&
-           (gpio_direction_output(OVERO_GPIO_BT_NRESET, 1) == 0)) {
                gpio_export(OVERO_GPIO_BT_NRESET, 0);
                gpio_set_value(OVERO_GPIO_BT_NRESET, 0);
                mdelay(6);
                gpio_set_value(OVERO_GPIO_BT_NRESET, 1);
-       } else {
-               printk(KERN_ERR "could not obtain gpio for "
-                                       "OVERO_GPIO_BT_NRESET\n");
        }
 
-       if ((gpio_request(OVERO_GPIO_USBH_CPEN, "OVERO_GPIO_USBH_CPEN") == 0) &&
-           (gpio_direction_output(OVERO_GPIO_USBH_CPEN, 1) == 0))
+       ret = gpio_request_one(OVERO_GPIO_USBH_CPEN, GPIOF_OUT_INIT_HIGH,
+                              "OVERO_GPIO_USBH_CPEN");
+       if (ret == 0)
                gpio_export(OVERO_GPIO_USBH_CPEN, 0);
        else
                printk(KERN_ERR "could not obtain gpio for "
index 2af8b05e786d58e5a57fd8f13897804cf7a4d69c..42d10b12da3ccedadacf35f05be4273b37214964 100644 (file)
@@ -31,6 +31,7 @@
 #include "mux.h"
 #include "hsmmc.h"
 #include "sdram-nokia.h"
+#include "common-board-devices.h"
 
 static struct regulator_consumer_supply rm680_vemmc_consumers[] = {
        REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"),
@@ -90,19 +91,9 @@ static struct twl4030_platform_data rm680_twl_data = {
        /* add rest of the children here */
 };
 
-static struct i2c_board_info __initdata rm680_twl_i2c_board_info[] = {
-       {
-               I2C_BOARD_INFO("twl5031", 0x48),
-               .flags          = I2C_CLIENT_WAKE,
-               .irq            = INT_34XX_SYS_NIRQ,
-               .platform_data  = &rm680_twl_data,
-       },
-};
-
 static void __init rm680_i2c_init(void)
 {
-       omap_register_i2c_bus(1, 2900, rm680_twl_i2c_board_info,
-                               ARRAY_SIZE(rm680_twl_i2c_board_info));
+       omap_pmic_init(1, 2900, "twl5031", INT_34XX_SYS_NIRQ, &rm680_twl_data);
        omap_register_i2c_bus(2, 400, NULL, 0);
        omap_register_i2c_bus(3, 400, NULL, 0);
 }
@@ -153,17 +144,11 @@ static struct omap_board_mux board_mux[] __initdata = {
 };
 #endif
 
-static struct omap_musb_board_data rm680_musb_data = {
-       .interface_type = MUSB_INTERFACE_ULPI,
-       .mode           = MUSB_PERIPHERAL,
-       .power          = 100,
-};
-
 static void __init rm680_init(void)
 {
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
        omap_serial_init();
-       usb_musb_init(&rm680_musb_data);
+       usb_musb_init(NULL);
        rm680_peripherals_init();
 }
 
index bbcb6775a6a3006486b5d64890aca629e66e3ab3..990366726c58f2c2614e43536dc28c5f36b70cbf 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/mmc/host.h>
+#include <linux/power/isp1704_charger.h>
 
 #include <plat/mcspi.h>
 #include <plat/board.h>
@@ -43,6 +44,7 @@
 
 #include "mux.h"
 #include "hsmmc.h"
+#include "common-board-devices.h"
 
 #define SYSTEM_REV_B_USES_VAUX3        0x1699
 #define SYSTEM_REV_S_USES_VAUX3 0x8
@@ -52,6 +54,8 @@
 #define RX51_FMTX_RESET_GPIO           163
 #define RX51_FMTX_IRQ                  53
 
+#define RX51_USB_TRANSCEIVER_RST_GPIO  67
+
 /* list all spi devices here */
 enum {
        RX51_SPI_WL1251,
@@ -110,10 +114,30 @@ static struct spi_board_info rx51_peripherals_spi_board_info[] __initdata = {
        },
 };
 
+static void rx51_charger_set_power(bool on)
+{
+       gpio_set_value(RX51_USB_TRANSCEIVER_RST_GPIO, on);
+}
+
+static struct isp1704_charger_data rx51_charger_data = {
+       .set_power      = rx51_charger_set_power,
+};
+
 static struct platform_device rx51_charger_device = {
-       .name = "isp1704_charger",
+       .name   = "isp1704_charger",
+       .dev    = {
+               .platform_data = &rx51_charger_data,
+       },
 };
 
+static void __init rx51_charger_init(void)
+{
+       WARN_ON(gpio_request_one(RX51_USB_TRANSCEIVER_RST_GPIO,
+               GPIOF_OUT_INIT_LOW, "isp1704_reset"));
+
+       platform_device_register(&rx51_charger_device);
+}
+
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
 
 #define RX51_GPIO_CAMERA_LENS_COVER    110
@@ -464,6 +488,7 @@ static struct regulator_init_data rx51_vmmc2 = {
                .name                   = "V28_A",
                .min_uV                 = 2800000,
                .max_uV                 = 3000000,
+               .always_on              = true, /* due VIO leak to AIC34 VDDs */
                .apply_uV               = true,
                .valid_modes_mask       = REGULATOR_MODE_NORMAL
                                        | REGULATOR_MODE_STANDBY,
@@ -557,10 +582,8 @@ static __init void rx51_init_si4713(void)
 static int rx51_twlgpio_setup(struct device *dev, unsigned gpio, unsigned n)
 {
        /* FIXME this gpio setup is just a placeholder for now */
-       gpio_request(gpio + 6, "backlight_pwm");
-       gpio_direction_output(gpio + 6, 0);
-       gpio_request(gpio + 7, "speaker_en");
-       gpio_direction_output(gpio + 7, 1);
+       gpio_request_one(gpio + 6, GPIOF_OUT_INIT_LOW, "backlight_pwm");
+       gpio_request_one(gpio + 7, GPIOF_OUT_INIT_LOW, "speaker_en");
 
        return 0;
 }
@@ -730,7 +753,7 @@ static struct twl4030_resconfig twl4030_rconfig[] __initdata = {
        { .resource = RES_RESET, .devgroup = -1,
          .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
        },
-       { .resource = RES_Main_Ref, .devgroup = -1,
+       { .resource = RES_MAIN_REF, .devgroup = -1,
          .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
        },
        { 0, 0},
@@ -777,15 +800,6 @@ static struct tpa6130a2_platform_data rx51_tpa6130a2_data __initdata_or_module =
        .power_gpio             = 98,
 };
 
-static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_1[] = {
-       {
-               I2C_BOARD_INFO("twl5030", 0x48),
-               .flags = I2C_CLIENT_WAKE,
-               .irq = INT_34XX_SYS_NIRQ,
-               .platform_data = &rx51_twldata,
-       },
-};
-
 /* Audio setup data */
 static struct aic3x_setup_data rx51_aic34_setup = {
        .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
@@ -833,8 +847,7 @@ static int __init rx51_i2c_init(void)
                rx51_twldata.vaux3 = &rx51_vaux3_cam;
        }
        rx51_twldata.vmmc2 = &rx51_vmmc2;
-       omap_register_i2c_bus(1, 2200, rx51_peripherals_i2c_board_info_1,
-                             ARRAY_SIZE(rx51_peripherals_i2c_board_info_1));
+       omap_pmic_init(1, 2200, "twl5030", INT_34XX_SYS_NIRQ, &rx51_twldata);
        omap_register_i2c_bus(2, 100, rx51_peripherals_i2c_board_info_2,
                              ARRAY_SIZE(rx51_peripherals_i2c_board_info_2));
        omap_register_i2c_bus(3, 400, NULL, 0);
@@ -921,26 +934,20 @@ static void rx51_wl1251_set_power(bool enable)
        gpio_set_value(RX51_WL1251_POWER_GPIO, enable);
 }
 
+static struct gpio rx51_wl1251_gpios[] __initdata = {
+       { RX51_WL1251_POWER_GPIO, GPIOF_OUT_INIT_LOW,   "wl1251 power"  },
+       { RX51_WL1251_IRQ_GPIO,   GPIOF_IN,             "wl1251 irq"    },
+};
+
 static void __init rx51_init_wl1251(void)
 {
        int irq, ret;
 
-       ret = gpio_request(RX51_WL1251_POWER_GPIO, "wl1251 power");
+       ret = gpio_request_array(rx51_wl1251_gpios,
+                                ARRAY_SIZE(rx51_wl1251_gpios));
        if (ret < 0)
                goto error;
 
-       ret = gpio_direction_output(RX51_WL1251_POWER_GPIO, 0);
-       if (ret < 0)
-               goto err_power;
-
-       ret = gpio_request(RX51_WL1251_IRQ_GPIO, "wl1251 irq");
-       if (ret < 0)
-               goto err_power;
-
-       ret = gpio_direction_input(RX51_WL1251_IRQ_GPIO);
-       if (ret < 0)
-               goto err_irq;
-
        irq = gpio_to_irq(RX51_WL1251_IRQ_GPIO);
        if (irq < 0)
                goto err_irq;
@@ -952,10 +959,7 @@ static void __init rx51_init_wl1251(void)
 
 err_irq:
        gpio_free(RX51_WL1251_IRQ_GPIO);
-
-err_power:
        gpio_free(RX51_WL1251_POWER_GPIO);
-
 error:
        printk(KERN_ERR "wl1251 board initialisation failed\n");
        wl1251_pdata.set_power = NULL;
@@ -981,6 +985,6 @@ void __init rx51_peripherals_init(void)
        if (partition)
                omap2_hsmmc_init(mmc);
 
-       platform_device_register(&rx51_charger_device);
+       rx51_charger_init();
 }
 
index 89a66db8b77d513c76abe85a522c6c70394021f5..2c1289bd5e6ad7a2ee30d736d5bb3a14bf6591f0 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/spi/spi.h>
 #include <linux/mm.h>
 #include <asm/mach-types.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/vram.h>
 #include <plat/mcspi.h>
 
@@ -76,13 +76,12 @@ static int __init rx51_video_init(void)
                return 0;
        }
 
-       if (gpio_request(RX51_LCD_RESET_GPIO, "LCD ACX565AKM reset")) {
+       if (gpio_request_one(RX51_LCD_RESET_GPIO, GPIOF_OUT_INIT_HIGH,
+                            "LCD ACX565AKM reset")) {
                pr_err("%s failed to get LCD Reset GPIO\n", __func__);
                return 0;
        }
 
-       gpio_direction_output(RX51_LCD_RESET_GPIO, 1);
-
        omap_display_init(&rx51_dss_board_info);
        return 0;
 }
index f8ba20a14e625554f95fded51abc2177e7326b96..fec4cac8fa0ab858fd6c09f55af0b08ce8e0ad1a 100644 (file)
@@ -58,21 +58,25 @@ static struct platform_device leds_gpio = {
        },
 };
 
+/*
+ * cpuidle C-states definition override from the default values.
+ * The 'exit_latency' field is the sum of sleep and wake-up latencies.
+ */
 static struct cpuidle_params rx51_cpuidle_params[] = {
        /* C1 */
-       {1, 110, 162, 5},
+       {110 + 162, 5 , 1},
        /* C2 */
-       {1, 106, 180, 309},
+       {106 + 180, 309, 1},
        /* C3 */
-       {0, 107, 410, 46057},
+       {107 + 410, 46057, 0},
        /* C4 */
-       {0, 121, 3374, 46057},
+       {121 + 3374, 46057, 0},
        /* C5 */
-       {1, 855, 1146, 46057},
+       {855 + 1146, 46057, 1},
        /* C6 */
-       {0, 7580, 4134, 484329},
+       {7580 + 4134, 484329, 0},
        /* C7 */
-       {1, 7505, 15274, 484329},
+       {7505 + 15274, 484329, 1},
 };
 
 static struct omap_lcd_config rx51_lcd_config = {
index 007ebdc6c993eec5a8d73243a18a6be382557501..6402e781c458c7ebbdd48017acc9527e038f6ef4 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/interrupt.h>
 
 #include <plat/gpmc.h>
+#include <plat/gpmc-smsc911x.h>
 
 #include <mach/board-zoom.h>
 
 #define DEBUG_BASE             0x08000000
 #define ZOOM_ETHR_START        DEBUG_BASE
 
-static struct resource zoom_smsc911x_resources[] = {
-       [0] = {
-               .start  = ZOOM_ETHR_START,
-               .end    = ZOOM_ETHR_START + SZ_4K,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
-       },
-};
-
-static struct smsc911x_platform_config zoom_smsc911x_config = {
-       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
-       .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+static struct omap_smsc911x_platform_data zoom_smsc911x_cfg = {
+       .cs             = ZOOM_SMSC911X_CS,
+       .gpio_irq       = ZOOM_SMSC911X_GPIO,
+       .gpio_reset     = -EINVAL,
        .flags          = SMSC911X_USE_32BIT,
-       .phy_interface  = PHY_INTERFACE_MODE_MII,
-};
-
-static struct platform_device zoom_smsc911x_device = {
-       .name           = "smsc911x",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(zoom_smsc911x_resources),
-       .resource       = zoom_smsc911x_resources,
-       .dev            = {
-               .platform_data = &zoom_smsc911x_config,
-       },
 };
 
 static inline void __init zoom_init_smsc911x(void)
 {
-       int eth_cs;
-       unsigned long cs_mem_base;
-       int eth_gpio = 0;
-
-       eth_cs = ZOOM_SMSC911X_CS;
-
-       if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
-               printk(KERN_ERR "Failed to request GPMC mem for smsc911x\n");
-               return;
-       }
-
-       zoom_smsc911x_resources[0].start = cs_mem_base + 0x0;
-       zoom_smsc911x_resources[0].end   = cs_mem_base + 0xff;
-
-       eth_gpio = ZOOM_SMSC911X_GPIO;
-
-       zoom_smsc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
-
-       if (gpio_request(eth_gpio, "smsc911x irq") < 0) {
-               printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n",
-                               eth_gpio);
-               return;
-       }
-       gpio_direction_input(eth_gpio);
+       gpmc_smsc911x_init(&zoom_smsc911x_cfg);
 }
 
 static struct plat_serial8250_port serial_platform_data[] = {
@@ -120,12 +77,9 @@ static inline void __init zoom_init_quaduart(void)
 
        quart_gpio = ZOOM_QUADUART_GPIO;
 
-       if (gpio_request(quart_gpio, "TL16CP754C GPIO") < 0) {
+       if (gpio_request_one(quart_gpio, GPIOF_IN, "TL16CP754C GPIO") < 0)
                printk(KERN_ERR "Failed to request GPIO%d for TL16CP754C\n",
                                                                quart_gpio);
-               return;
-       }
-       gpio_direction_input(quart_gpio);
 }
 
 static inline int omap_zoom_debugboard_detect(void)
@@ -135,12 +89,12 @@ static inline int omap_zoom_debugboard_detect(void)
 
        debug_board_detect = ZOOM_SMSC911X_GPIO;
 
-       if (gpio_request(debug_board_detect, "Zoom debug board detect") < 0) {
+       if (gpio_request_one(debug_board_detect, GPIOF_IN,
+                            "Zoom debug board detect") < 0) {
                printk(KERN_ERR "Failed to request GPIO%d for Zoom debug"
                "board detect\n", debug_board_detect);
                return 0;
        }
-       gpio_direction_input(debug_board_detect);
 
        if (!gpio_get_value(debug_board_detect)) {
                ret = 0;
@@ -150,7 +104,6 @@ static inline int omap_zoom_debugboard_detect(void)
 }
 
 static struct platform_device *zoom_devices[] __initdata = {
-       &zoom_smsc911x_device,
        &zoom_debugboard_serial_device,
 };
 
index 37b84c2b850fd813b0e40ceccec6e2b19152de40..d4683ba5f72182aa47ef94267ff9dc97c446b043 100644 (file)
 #include <linux/i2c/twl.h>
 #include <linux/spi/spi.h>
 #include <plat/mcspi.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define LCD_PANEL_RESET_GPIO_PROD      96
 #define LCD_PANEL_RESET_GPIO_PILOT     55
 #define LCD_PANEL_QVGA_GPIO            56
 
-static void zoom_lcd_panel_init(void)
-{
-       int ret;
-       unsigned char lcd_panel_reset_gpio;
+static struct gpio zoom_lcd_gpios[] __initdata = {
+       { -EINVAL,              GPIOF_OUT_INIT_HIGH, "lcd reset" },
+       { LCD_PANEL_QVGA_GPIO,  GPIOF_OUT_INIT_HIGH, "lcd qvga"  },
+};
 
-       lcd_panel_reset_gpio = (omap_rev() > OMAP3430_REV_ES3_0) ?
+static void __init zoom_lcd_panel_init(void)
+{
+       zoom_lcd_gpios[0].gpio = (omap_rev() > OMAP3430_REV_ES3_0) ?
                        LCD_PANEL_RESET_GPIO_PROD :
                        LCD_PANEL_RESET_GPIO_PILOT;
 
-       ret = gpio_request(lcd_panel_reset_gpio, "lcd reset");
-       if (ret) {
-               pr_err("Failed to get LCD reset GPIO (gpio%d).\n",
-                       lcd_panel_reset_gpio);
-               return;
-       }
-       gpio_direction_output(lcd_panel_reset_gpio, 1);
-
-       ret = gpio_request(LCD_PANEL_QVGA_GPIO, "lcd qvga");
-       if (ret) {
-               pr_err("Failed to get LCD_PANEL_QVGA_GPIO (gpio%d).\n",
-                       LCD_PANEL_QVGA_GPIO);
-               goto err0;
-       }
-       gpio_direction_output(LCD_PANEL_QVGA_GPIO, 1);
-
-       return;
-err0:
-       gpio_free(lcd_panel_reset_gpio);
+       if (gpio_request_array(zoom_lcd_gpios, ARRAY_SIZE(zoom_lcd_gpios)))
+               pr_err("%s: Failed to get LCD GPIOs.\n", __func__);
 }
 
 static int zoom_panel_enable_lcd(struct omap_dss_device *dssdev)
index 8dee7549fbdf5330553859c0df43bfed335fcf66..118c6f53c5eb00f3815ba3f21d72623aacdcc828 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "mux.h"
 #include "hsmmc.h"
+#include "common-board-devices.h"
 
 #define OMAP_ZOOM_WLAN_PMENA_GPIO      (101)
 #define OMAP_ZOOM_WLAN_IRQ_GPIO                (162)
@@ -276,13 +277,11 @@ static int zoom_twl_gpio_setup(struct device *dev,
        zoom_vsim_supply.dev = mmc[0].dev;
        zoom_vmmc2_supply.dev = mmc[1].dev;
 
-       ret = gpio_request(LCD_PANEL_ENABLE_GPIO, "lcd enable");
-       if (ret) {
+       ret = gpio_request_one(LCD_PANEL_ENABLE_GPIO, GPIOF_OUT_INIT_LOW,
+                              "lcd enable");
+       if (ret)
                pr_err("Failed to get LCD_PANEL_ENABLE_GPIO (gpio%d).\n",
                                LCD_PANEL_ENABLE_GPIO);
-               return ret;
-       }
-       gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 0);
 
        return ret;
 }
@@ -349,15 +348,6 @@ static struct twl4030_platform_data zoom_twldata = {
        .vdac           = &zoom_vdac,
 };
 
-static struct i2c_board_info __initdata zoom_i2c_boardinfo[] = {
-       {
-               I2C_BOARD_INFO("twl5030", 0x48),
-               .flags          = I2C_CLIENT_WAKE,
-               .irq            = INT_34XX_SYS_NIRQ,
-               .platform_data  = &zoom_twldata,
-       },
-};
-
 static int __init omap_i2c_init(void)
 {
        if (machine_is_omap_zoom2()) {
@@ -365,19 +355,12 @@ static int __init omap_i2c_init(void)
                zoom_audio_data.hs_extmute = 1;
                zoom_audio_data.set_hs_extmute = zoom2_set_hs_extmute;
        }
-       omap_register_i2c_bus(1, 2400, zoom_i2c_boardinfo,
-                       ARRAY_SIZE(zoom_i2c_boardinfo));
+       omap_pmic_init(1, 2400, "twl5030", INT_34XX_SYS_NIRQ, &zoom_twldata);
        omap_register_i2c_bus(2, 400, NULL, 0);
        omap_register_i2c_bus(3, 400, NULL, 0);
        return 0;
 }
 
-static struct omap_musb_board_data musb_board_data = {
-       .interface_type         = MUSB_INTERFACE_ULPI,
-       .mode                   = MUSB_OTG,
-       .power                  = 100,
-};
-
 static void enable_board_wakeup_source(void)
 {
        /* T2 interrupt line (keypad) */
@@ -392,7 +375,7 @@ void __init zoom_peripherals_init(void)
 
        omap_i2c_init();
        platform_device_register(&omap_vwlan_device);
-       usb_musb_init(&musb_board_data);
+       usb_musb_init(NULL);
        enable_board_wakeup_source();
        omap_serial_init();
 }
diff --git a/arch/arm/mach-omap2/common-board-devices.c b/arch/arm/mach-omap2/common-board-devices.c
new file mode 100644 (file)
index 0000000..94ccf46
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * common-board-devices.c
+ *
+ * Copyright (C) 2011 CompuLab, Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/i2c/twl.h>
+
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+
+#include <plat/i2c.h>
+#include <plat/mcspi.h>
+#include <plat/nand.h>
+
+#include "common-board-devices.h"
+
+static struct i2c_board_info __initdata pmic_i2c_board_info = {
+       .addr           = 0x48,
+       .flags          = I2C_CLIENT_WAKE,
+};
+
+void __init omap_pmic_init(int bus, u32 clkrate,
+                          const char *pmic_type, int pmic_irq,
+                          struct twl4030_platform_data *pmic_data)
+{
+       strncpy(pmic_i2c_board_info.type, pmic_type,
+               sizeof(pmic_i2c_board_info.type));
+       pmic_i2c_board_info.irq = pmic_irq;
+       pmic_i2c_board_info.platform_data = pmic_data;
+
+       omap_register_i2c_bus(bus, clkrate, &pmic_i2c_board_info, 1);
+}
+
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
+       defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+static struct omap2_mcspi_device_config ads7846_mcspi_config = {
+       .turbo_mode     = 0,
+       .single_channel = 1,    /* 0: slave, 1: master */
+};
+
+static struct ads7846_platform_data ads7846_config = {
+       .x_max                  = 0x0fff,
+       .y_max                  = 0x0fff,
+       .x_plate_ohms           = 180,
+       .pressure_max           = 255,
+       .debounce_max           = 10,
+       .debounce_tol           = 3,
+       .debounce_rep           = 1,
+       .gpio_pendown           = -EINVAL,
+       .keep_vref_on           = 1,
+};
+
+static struct spi_board_info ads7846_spi_board_info __initdata = {
+       .modalias               = "ads7846",
+       .bus_num                = -EINVAL,
+       .chip_select            = 0,
+       .max_speed_hz           = 1500000,
+       .controller_data        = &ads7846_mcspi_config,
+       .irq                    = -EINVAL,
+       .platform_data          = &ads7846_config,
+};
+
+void __init omap_ads7846_init(int bus_num, int gpio_pendown, int gpio_debounce,
+                             struct ads7846_platform_data *board_pdata)
+{
+       struct spi_board_info *spi_bi = &ads7846_spi_board_info;
+       int err;
+
+       if (board_pdata && board_pdata->get_pendown_state) {
+               err = gpio_request_one(gpio_pendown, GPIOF_IN, "TSPenDown");
+               if (err) {
+                       pr_err("Couldn't obtain gpio for TSPenDown: %d\n", err);
+                       return;
+               }
+               gpio_export(gpio_pendown, 0);
+
+               if (gpio_debounce)
+                       gpio_set_debounce(gpio_pendown, gpio_debounce);
+       }
+
+       ads7846_config.gpio_pendown = gpio_pendown;
+
+       spi_bi->bus_num = bus_num;
+       spi_bi->irq     = OMAP_GPIO_IRQ(gpio_pendown);
+
+       if (board_pdata)
+               spi_bi->platform_data = board_pdata;
+
+       spi_register_board_info(&ads7846_spi_board_info, 1);
+}
+#else
+void __init omap_ads7846_init(int bus_num, int gpio_pendown, int gpio_debounce,
+                             struct ads7846_platform_data *board_pdata)
+{
+}
+#endif
+
+#if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE)
+static struct omap_nand_platform_data nand_data = {
+       .dma_channel    = -1,           /* disable DMA in OMAP NAND driver */
+};
+
+void __init omap_nand_flash_init(int options, struct mtd_partition *parts,
+                                int nr_parts)
+{
+       u8 cs = 0;
+       u8 nandcs = GPMC_CS_NUM + 1;
+
+       /* find out the chip-select on which NAND exists */
+       while (cs < GPMC_CS_NUM) {
+               u32 ret = 0;
+               ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+               if ((ret & 0xC00) == 0x800) {
+                       printk(KERN_INFO "Found NAND on CS%d\n", cs);
+                       if (nandcs > GPMC_CS_NUM)
+                               nandcs = cs;
+               }
+               cs++;
+       }
+
+       if (nandcs > GPMC_CS_NUM) {
+               printk(KERN_INFO "NAND: Unable to find configuration "
+                                "in GPMC\n ");
+               return;
+       }
+
+       if (nandcs < GPMC_CS_NUM) {
+               nand_data.cs = nandcs;
+               nand_data.parts = parts;
+               nand_data.nr_parts = nr_parts;
+               nand_data.options = options;
+
+               printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
+               if (gpmc_nand_init(&nand_data) < 0)
+                       printk(KERN_ERR "Unable to register NAND device\n");
+       }
+}
+#else
+void __init omap_nand_flash_init(int options, struct mtd_partition *parts,
+                                int nr_parts)
+{
+}
+#endif
diff --git a/arch/arm/mach-omap2/common-board-devices.h b/arch/arm/mach-omap2/common-board-devices.h
new file mode 100644 (file)
index 0000000..6797190
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __OMAP_COMMON_BOARD_DEVICES__
+#define __OMAP_COMMON_BOARD_DEVICES__
+
+#define NAND_BLOCK_SIZE        SZ_128K
+
+struct twl4030_platform_data;
+struct mtd_partition;
+
+void omap_pmic_init(int bus, u32 clkrate, const char *pmic_type, int pmic_irq,
+                   struct twl4030_platform_data *pmic_data);
+
+static inline void omap2_pmic_init(const char *pmic_type,
+                                  struct twl4030_platform_data *pmic_data)
+{
+       omap_pmic_init(2, 2600, pmic_type, INT_24XX_SYS_NIRQ, pmic_data);
+}
+
+static inline void omap3_pmic_init(const char *pmic_type,
+                                  struct twl4030_platform_data *pmic_data)
+{
+       omap_pmic_init(1, 2600, pmic_type, INT_34XX_SYS_NIRQ, pmic_data);
+}
+
+static inline void omap4_pmic_init(const char *pmic_type,
+                                  struct twl4030_platform_data *pmic_data)
+{
+       /* Phoenix Audio IC needs I2C1 to start with 400 KHz or less */
+       omap_pmic_init(1, 400, pmic_type, OMAP44XX_IRQ_SYS_1N, pmic_data);
+}
+
+struct ads7846_platform_data;
+
+void omap_ads7846_init(int bus_num, int gpio_pendown, int gpio_debounce,
+                      struct ads7846_platform_data *board_pdata);
+void omap_nand_flash_init(int opts, struct mtd_partition *parts, int n_parts);
+
+#endif /* __OMAP_COMMON_BOARD_DEVICES__ */
index 1c240eff3918c08161243279e62206b4eed5caa4..4bf6e6e8b1001ae5b14ab0e86c44dec7c8b1043d 100644 (file)
 
 #ifdef CONFIG_CPU_IDLE
 
-#define OMAP3_MAX_STATES 7
-#define OMAP3_STATE_C1 0 /* C1 - MPU WFI + Core active */
-#define OMAP3_STATE_C2 1 /* C2 - MPU WFI + Core inactive */
-#define OMAP3_STATE_C3 2 /* C3 - MPU CSWR + Core inactive */
-#define OMAP3_STATE_C4 3 /* C4 - MPU OFF + Core iactive */
-#define OMAP3_STATE_C5 4 /* C5 - MPU RET + Core RET */
-#define OMAP3_STATE_C6 5 /* C6 - MPU OFF + Core RET */
-#define OMAP3_STATE_C7 6 /* C7 - MPU OFF + Core OFF */
-
-#define OMAP3_STATE_MAX OMAP3_STATE_C7
-
-#define CPUIDLE_FLAG_CHECK_BM  0x10000 /* use omap3_enter_idle_bm() */
-
-struct omap3_processor_cx {
-       u8 valid;
-       u8 type;
-       u32 sleep_latency;
-       u32 wakeup_latency;
-       u32 mpu_state;
-       u32 core_state;
-       u32 threshold;
-       u32 flags;
-       const char *desc;
-};
-
-struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES];
-struct omap3_processor_cx current_cx_state;
-struct powerdomain *mpu_pd, *core_pd, *per_pd;
-struct powerdomain *cam_pd;
-
 /*
  * The latencies/thresholds for various C states have
  * to be configured from the respective board files.
@@ -75,27 +45,31 @@ struct powerdomain *cam_pd;
  */
 static struct cpuidle_params cpuidle_params_table[] = {
        /* C1 */
-       {1, 2, 2, 5},
+       {2 + 2, 5, 1},
        /* C2 */
-       {1, 10, 10, 30},
+       {10 + 10, 30, 1},
        /* C3 */
-       {1, 50, 50, 300},
+       {50 + 50, 300, 1},
        /* C4 */
-       {1, 1500, 1800, 4000},
+       {1500 + 1800, 4000, 1},
        /* C5 */
-       {1, 2500, 7500, 12000},
+       {2500 + 7500, 12000, 1},
        /* C6 */
-       {1, 3000, 8500, 15000},
+       {3000 + 8500, 15000, 1},
        /* C7 */
-       {1, 10000, 30000, 300000},
+       {10000 + 30000, 300000, 1},
 };
+#define OMAP3_NUM_STATES ARRAY_SIZE(cpuidle_params_table)
 
-static int omap3_idle_bm_check(void)
-{
-       if (!omap3_can_sleep())
-               return 1;
-       return 0;
-}
+/* Mach specific information to be recorded in the C-state driver_data */
+struct omap3_idle_statedata {
+       u32 mpu_state;
+       u32 core_state;
+       u8 valid;
+};
+struct omap3_idle_statedata omap3_idle_data[OMAP3_NUM_STATES];
+
+struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;
 
 static int _cpuidle_allow_idle(struct powerdomain *pwrdm,
                                struct clockdomain *clkdm)
@@ -122,12 +96,10 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
 static int omap3_enter_idle(struct cpuidle_device *dev,
                        struct cpuidle_state *state)
 {
-       struct omap3_processor_cx *cx = cpuidle_get_statedata(state);
+       struct omap3_idle_statedata *cx = cpuidle_get_statedata(state);
        struct timespec ts_preidle, ts_postidle, ts_idle;
        u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
 
-       current_cx_state = *cx;
-
        /* Used to keep track of the total time in idle */
        getnstimeofday(&ts_preidle);
 
@@ -140,7 +112,8 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
        if (omap_irq_pending() || need_resched())
                goto return_sleep_time;
 
-       if (cx->type == OMAP3_STATE_C1) {
+       /* Deny idle for C1 */
+       if (state == &dev->states[0]) {
                pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle);
                pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle);
        }
@@ -148,7 +121,8 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
        /* Execute ARM wfi */
        omap_sram_idle();
 
-       if (cx->type == OMAP3_STATE_C1) {
+       /* Re-allow idle for C1 */
+       if (state == &dev->states[0]) {
                pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle);
                pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle);
        }
@@ -164,41 +138,53 @@ return_sleep_time:
 }
 
 /**
- * next_valid_state - Find next valid c-state
+ * next_valid_state - Find next valid C-state
  * @dev: cpuidle device
- * @state: Currently selected c-state
+ * @state: Currently selected C-state
  *
  * If the current state is valid, it is returned back to the caller.
  * Else, this function searches for a lower c-state which is still
- * valid (as defined in omap3_power_states[]).
+ * valid.
+ *
+ * A state is valid if the 'valid' field is enabled and
+ * if it satisfies the enable_off_mode condition.
  */
 static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
-                                               struct cpuidle_state *curr)
+                                             struct cpuidle_state *curr)
 {
        struct cpuidle_state *next = NULL;
-       struct omap3_processor_cx *cx;
+       struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr);
+       u32 mpu_deepest_state = PWRDM_POWER_RET;
+       u32 core_deepest_state = PWRDM_POWER_RET;
 
-       cx = (struct omap3_processor_cx *)cpuidle_get_statedata(curr);
+       if (enable_off_mode) {
+               mpu_deepest_state = PWRDM_POWER_OFF;
+               /*
+                * Erratum i583: valable for ES rev < Es1.2 on 3630.
+                * CORE OFF mode is not supported in a stable form, restrict
+                * instead the CORE state to RET.
+                */
+               if (!IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583))
+                       core_deepest_state = PWRDM_POWER_OFF;
+       }
 
        /* Check if current state is valid */
-       if (cx->valid) {
+       if ((cx->valid) &&
+           (cx->mpu_state >= mpu_deepest_state) &&
+           (cx->core_state >= core_deepest_state)) {
                return curr;
        } else {
-               u8 idx = OMAP3_STATE_MAX;
+               int idx = OMAP3_NUM_STATES - 1;
 
-               /*
-                * Reach the current state starting at highest C-state
-                */
-               for (; idx >= OMAP3_STATE_C1; idx--) {
+               /* Reach the current state starting at highest C-state */
+               for (; idx >= 0; idx--) {
                        if (&dev->states[idx] == curr) {
                                next = &dev->states[idx];
                                break;
                        }
                }
 
-               /*
-                * Should never hit this condition.
-                */
+               /* Should never hit this condition */
                WARN_ON(next == NULL);
 
                /*
@@ -206,17 +192,17 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
                 * Start search from the next (lower) state.
                 */
                idx--;
-               for (; idx >= OMAP3_STATE_C1; idx--) {
-                       struct omap3_processor_cx *cx;
-
+               for (; idx >= 0; idx--) {
                        cx = cpuidle_get_statedata(&dev->states[idx]);
-                       if (cx->valid) {
+                       if ((cx->valid) &&
+                           (cx->mpu_state >= mpu_deepest_state) &&
+                           (cx->core_state >= core_deepest_state)) {
                                next = &dev->states[idx];
                                break;
                        }
                }
                /*
-                * C1 and C2 are always valid.
+                * C1 is always valid.
                 * So, no need to check for 'next==NULL' outside this loop.
                 */
        }
@@ -229,36 +215,22 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
  * @dev: cpuidle device
  * @state: The target state to be programmed
  *
- * Used for C states with CPUIDLE_FLAG_CHECK_BM flag set. This
- * function checks for any pending activity and then programs the
- * device to the specified or a safer state.
+ * This function checks for any pending activity and then programs
+ * the device to the specified or a safer state.
  */
 static int omap3_enter_idle_bm(struct cpuidle_device *dev,
                               struct cpuidle_state *state)
 {
-       struct cpuidle_state *new_state = next_valid_state(dev, state);
-       u32 core_next_state, per_next_state = 0, per_saved_state = 0;
-       u32 cam_state;
-       struct omap3_processor_cx *cx;
+       struct cpuidle_state *new_state;
+       u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state;
+       struct omap3_idle_statedata *cx;
        int ret;
 
-       if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) {
-               BUG_ON(!dev->safe_state);
+       if (!omap3_can_sleep()) {
                new_state = dev->safe_state;
                goto select_state;
        }
 
-       cx = cpuidle_get_statedata(state);
-       core_next_state = cx->core_state;
-
-       /*
-        * FIXME: we currently manage device-specific idle states
-        *        for PER and CORE in combination with CPU-specific
-        *        idle states.  This is wrong, and device-specific
-        *        idle management needs to be separated out into 
-        *        its own code.
-        */
-
        /*
         * Prevent idle completely if CAM is active.
         * CAM does not have wakeup capability in OMAP3.
@@ -269,10 +241,20 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
                goto select_state;
        }
 
+       /*
+        * FIXME: we currently manage device-specific idle states
+        *        for PER and CORE in combination with CPU-specific
+        *        idle states.  This is wrong, and device-specific
+        *        idle management needs to be separated out into
+        *        its own code.
+        */
+
        /*
         * Prevent PER off if CORE is not in retention or off as this
         * would disable PER wakeups completely.
         */
+       cx = cpuidle_get_statedata(state);
+       core_next_state = cx->core_state;
        per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
        if ((per_next_state == PWRDM_POWER_OFF) &&
            (core_next_state > PWRDM_POWER_RET))
@@ -282,6 +264,8 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
        if (per_next_state != per_saved_state)
                pwrdm_set_next_pwrst(per_pd, per_next_state);
 
+       new_state = next_valid_state(dev, state);
+
 select_state:
        dev->last_state = new_state;
        ret = omap3_enter_idle(dev, new_state);
@@ -295,31 +279,6 @@ select_state:
 
 DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev);
 
-/**
- * omap3_cpuidle_update_states() - Update the cpuidle states
- * @mpu_deepest_state: Enable states up to and including this for mpu domain
- * @core_deepest_state:        Enable states up to and including this for core domain
- *
- * This goes through the list of states available and enables and disables the
- * validity of C states based on deepest state that can be achieved for the
- * variable domain
- */
-void omap3_cpuidle_update_states(u32 mpu_deepest_state, u32 core_deepest_state)
-{
-       int i;
-
-       for (i = OMAP3_STATE_C1; i < OMAP3_MAX_STATES; i++) {
-               struct omap3_processor_cx *cx = &omap3_power_states[i];
-
-               if ((cx->mpu_state >= mpu_deepest_state) &&
-                   (cx->core_state >= core_deepest_state)) {
-                       cx->valid = 1;
-               } else {
-                       cx->valid = 0;
-               }
-       }
-}
-
 void omap3_pm_init_cpuidle(struct cpuidle_params *cpuidle_board_params)
 {
        int i;
@@ -327,212 +286,109 @@ void omap3_pm_init_cpuidle(struct cpuidle_params *cpuidle_board_params)
        if (!cpuidle_board_params)
                return;
 
-       for (i = OMAP3_STATE_C1; i < OMAP3_MAX_STATES; i++) {
-               cpuidle_params_table[i].valid =
-                       cpuidle_board_params[i].valid;
-               cpuidle_params_table[i].sleep_latency =
-                       cpuidle_board_params[i].sleep_latency;
-               cpuidle_params_table[i].wake_latency =
-                       cpuidle_board_params[i].wake_latency;
-               cpuidle_params_table[i].threshold =
-                       cpuidle_board_params[i].threshold;
+       for (i = 0; i < OMAP3_NUM_STATES; i++) {
+               cpuidle_params_table[i].valid = cpuidle_board_params[i].valid;
+               cpuidle_params_table[i].exit_latency =
+                       cpuidle_board_params[i].exit_latency;
+               cpuidle_params_table[i].target_residency =
+                       cpuidle_board_params[i].target_residency;
        }
        return;
 }
 
-/* omap3_init_power_states - Initialises the OMAP3 specific C states.
- *
- * Below is the desciption of each C state.
- *     C1 . MPU WFI + Core active
- *     C2 . MPU WFI + Core inactive
- *     C3 . MPU CSWR + Core inactive
- *     C4 . MPU OFF + Core inactive
- *     C5 . MPU CSWR + Core CSWR
- *     C6 . MPU OFF + Core CSWR
- *     C7 . MPU OFF + Core OFF
- */
-void omap_init_power_states(void)
-{
-       /* C1 . MPU WFI + Core active */
-       omap3_power_states[OMAP3_STATE_C1].valid =
-                       cpuidle_params_table[OMAP3_STATE_C1].valid;
-       omap3_power_states[OMAP3_STATE_C1].type = OMAP3_STATE_C1;
-       omap3_power_states[OMAP3_STATE_C1].sleep_latency =
-                       cpuidle_params_table[OMAP3_STATE_C1].sleep_latency;
-       omap3_power_states[OMAP3_STATE_C1].wakeup_latency =
-                       cpuidle_params_table[OMAP3_STATE_C1].wake_latency;
-       omap3_power_states[OMAP3_STATE_C1].threshold =
-                       cpuidle_params_table[OMAP3_STATE_C1].threshold;
-       omap3_power_states[OMAP3_STATE_C1].mpu_state = PWRDM_POWER_ON;
-       omap3_power_states[OMAP3_STATE_C1].core_state = PWRDM_POWER_ON;
-       omap3_power_states[OMAP3_STATE_C1].flags = CPUIDLE_FLAG_TIME_VALID;
-       omap3_power_states[OMAP3_STATE_C1].desc = "MPU ON + CORE ON";
-
-       /* C2 . MPU WFI + Core inactive */
-       omap3_power_states[OMAP3_STATE_C2].valid =
-                       cpuidle_params_table[OMAP3_STATE_C2].valid;
-       omap3_power_states[OMAP3_STATE_C2].type = OMAP3_STATE_C2;
-       omap3_power_states[OMAP3_STATE_C2].sleep_latency =
-                       cpuidle_params_table[OMAP3_STATE_C2].sleep_latency;
-       omap3_power_states[OMAP3_STATE_C2].wakeup_latency =
-                       cpuidle_params_table[OMAP3_STATE_C2].wake_latency;
-       omap3_power_states[OMAP3_STATE_C2].threshold =
-                       cpuidle_params_table[OMAP3_STATE_C2].threshold;
-       omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON;
-       omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON;
-       omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID |
-                               CPUIDLE_FLAG_CHECK_BM;
-       omap3_power_states[OMAP3_STATE_C2].desc = "MPU ON + CORE ON";
-
-       /* C3 . MPU CSWR + Core inactive */
-       omap3_power_states[OMAP3_STATE_C3].valid =
-                       cpuidle_params_table[OMAP3_STATE_C3].valid;
-       omap3_power_states[OMAP3_STATE_C3].type = OMAP3_STATE_C3;
-       omap3_power_states[OMAP3_STATE_C3].sleep_latency =
-                       cpuidle_params_table[OMAP3_STATE_C3].sleep_latency;
-       omap3_power_states[OMAP3_STATE_C3].wakeup_latency =
-                       cpuidle_params_table[OMAP3_STATE_C3].wake_latency;
-       omap3_power_states[OMAP3_STATE_C3].threshold =
-                       cpuidle_params_table[OMAP3_STATE_C3].threshold;
-       omap3_power_states[OMAP3_STATE_C3].mpu_state = PWRDM_POWER_RET;
-       omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_ON;
-       omap3_power_states[OMAP3_STATE_C3].flags = CPUIDLE_FLAG_TIME_VALID |
-                               CPUIDLE_FLAG_CHECK_BM;
-       omap3_power_states[OMAP3_STATE_C3].desc = "MPU RET + CORE ON";
-
-       /* C4 . MPU OFF + Core inactive */
-       omap3_power_states[OMAP3_STATE_C4].valid =
-                       cpuidle_params_table[OMAP3_STATE_C4].valid;
-       omap3_power_states[OMAP3_STATE_C4].type = OMAP3_STATE_C4;
-       omap3_power_states[OMAP3_STATE_C4].sleep_latency =
-                       cpuidle_params_table[OMAP3_STATE_C4].sleep_latency;
-       omap3_power_states[OMAP3_STATE_C4].wakeup_latency =
-                       cpuidle_params_table[OMAP3_STATE_C4].wake_latency;
-       omap3_power_states[OMAP3_STATE_C4].threshold =
-                       cpuidle_params_table[OMAP3_STATE_C4].threshold;
-       omap3_power_states[OMAP3_STATE_C4].mpu_state = PWRDM_POWER_OFF;
-       omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_ON;
-       omap3_power_states[OMAP3_STATE_C4].flags = CPUIDLE_FLAG_TIME_VALID |
-                               CPUIDLE_FLAG_CHECK_BM;
-       omap3_power_states[OMAP3_STATE_C4].desc = "MPU OFF + CORE ON";
-
-       /* C5 . MPU CSWR + Core CSWR*/
-       omap3_power_states[OMAP3_STATE_C5].valid =
-                       cpuidle_params_table[OMAP3_STATE_C5].valid;
-       omap3_power_states[OMAP3_STATE_C5].type = OMAP3_STATE_C5;
-       omap3_power_states[OMAP3_STATE_C5].sleep_latency =
-                       cpuidle_params_table[OMAP3_STATE_C5].sleep_latency;
-       omap3_power_states[OMAP3_STATE_C5].wakeup_latency =
-                       cpuidle_params_table[OMAP3_STATE_C5].wake_latency;
-       omap3_power_states[OMAP3_STATE_C5].threshold =
-                       cpuidle_params_table[OMAP3_STATE_C5].threshold;
-       omap3_power_states[OMAP3_STATE_C5].mpu_state = PWRDM_POWER_RET;
-       omap3_power_states[OMAP3_STATE_C5].core_state = PWRDM_POWER_RET;
-       omap3_power_states[OMAP3_STATE_C5].flags = CPUIDLE_FLAG_TIME_VALID |
-                               CPUIDLE_FLAG_CHECK_BM;
-       omap3_power_states[OMAP3_STATE_C5].desc = "MPU RET + CORE RET";
-
-       /* C6 . MPU OFF + Core CSWR */
-       omap3_power_states[OMAP3_STATE_C6].valid =
-                       cpuidle_params_table[OMAP3_STATE_C6].valid;
-       omap3_power_states[OMAP3_STATE_C6].type = OMAP3_STATE_C6;
-       omap3_power_states[OMAP3_STATE_C6].sleep_latency =
-                       cpuidle_params_table[OMAP3_STATE_C6].sleep_latency;
-       omap3_power_states[OMAP3_STATE_C6].wakeup_latency =
-                       cpuidle_params_table[OMAP3_STATE_C6].wake_latency;
-       omap3_power_states[OMAP3_STATE_C6].threshold =
-                       cpuidle_params_table[OMAP3_STATE_C6].threshold;
-       omap3_power_states[OMAP3_STATE_C6].mpu_state = PWRDM_POWER_OFF;
-       omap3_power_states[OMAP3_STATE_C6].core_state = PWRDM_POWER_RET;
-       omap3_power_states[OMAP3_STATE_C6].flags = CPUIDLE_FLAG_TIME_VALID |
-                               CPUIDLE_FLAG_CHECK_BM;
-       omap3_power_states[OMAP3_STATE_C6].desc = "MPU OFF + CORE RET";
-
-       /* C7 . MPU OFF + Core OFF */
-       omap3_power_states[OMAP3_STATE_C7].valid =
-                       cpuidle_params_table[OMAP3_STATE_C7].valid;
-       omap3_power_states[OMAP3_STATE_C7].type = OMAP3_STATE_C7;
-       omap3_power_states[OMAP3_STATE_C7].sleep_latency =
-                       cpuidle_params_table[OMAP3_STATE_C7].sleep_latency;
-       omap3_power_states[OMAP3_STATE_C7].wakeup_latency =
-                       cpuidle_params_table[OMAP3_STATE_C7].wake_latency;
-       omap3_power_states[OMAP3_STATE_C7].threshold =
-                       cpuidle_params_table[OMAP3_STATE_C7].threshold;
-       omap3_power_states[OMAP3_STATE_C7].mpu_state = PWRDM_POWER_OFF;
-       omap3_power_states[OMAP3_STATE_C7].core_state = PWRDM_POWER_OFF;
-       omap3_power_states[OMAP3_STATE_C7].flags = CPUIDLE_FLAG_TIME_VALID |
-                               CPUIDLE_FLAG_CHECK_BM;
-       omap3_power_states[OMAP3_STATE_C7].desc = "MPU OFF + CORE OFF";
-
-       /*
-        * Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot
-        * enable OFF mode in a stable form for previous revisions.
-        * we disable C7 state as a result.
-        */
-       if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583)) {
-               omap3_power_states[OMAP3_STATE_C7].valid = 0;
-               cpuidle_params_table[OMAP3_STATE_C7].valid = 0;
-               pr_warn("%s: core off state C7 disabled due to i583\n",
-                               __func__);
-       }
-}
-
 struct cpuidle_driver omap3_idle_driver = {
        .name =         "omap3_idle",
        .owner =        THIS_MODULE,
 };
 
+/* Helper to fill the C-state common data and register the driver_data */
+static inline struct omap3_idle_statedata *_fill_cstate(
+                                       struct cpuidle_device *dev,
+                                       int idx, const char *descr)
+{
+       struct omap3_idle_statedata *cx = &omap3_idle_data[idx];
+       struct cpuidle_state *state = &dev->states[idx];
+
+       state->exit_latency     = cpuidle_params_table[idx].exit_latency;
+       state->target_residency = cpuidle_params_table[idx].target_residency;
+       state->flags            = CPUIDLE_FLAG_TIME_VALID;
+       state->enter            = omap3_enter_idle_bm;
+       cx->valid               = cpuidle_params_table[idx].valid;
+       sprintf(state->name, "C%d", idx + 1);
+       strncpy(state->desc, descr, CPUIDLE_DESC_LEN);
+       cpuidle_set_statedata(state, cx);
+
+       return cx;
+}
+
 /**
  * omap3_idle_init - Init routine for OMAP3 idle
  *
- * Registers the OMAP3 specific cpuidle driver with the cpuidle
+ * Registers the OMAP3 specific cpuidle driver to the cpuidle
  * framework with the valid set of states.
  */
 int __init omap3_idle_init(void)
 {
-       int i, count = 0;
-       struct omap3_processor_cx *cx;
-       struct cpuidle_state *state;
        struct cpuidle_device *dev;
+       struct omap3_idle_statedata *cx;
 
        mpu_pd = pwrdm_lookup("mpu_pwrdm");
        core_pd = pwrdm_lookup("core_pwrdm");
        per_pd = pwrdm_lookup("per_pwrdm");
        cam_pd = pwrdm_lookup("cam_pwrdm");
 
-       omap_init_power_states();
        cpuidle_register_driver(&omap3_idle_driver);
-
        dev = &per_cpu(omap3_idle_dev, smp_processor_id());
 
-       for (i = OMAP3_STATE_C1; i < OMAP3_MAX_STATES; i++) {
-               cx = &omap3_power_states[i];
-               state = &dev->states[count];
-
-               if (!cx->valid)
-                       continue;
-               cpuidle_set_statedata(state, cx);
-               state->exit_latency = cx->sleep_latency + cx->wakeup_latency;
-               state->target_residency = cx->threshold;
-               state->flags = cx->flags;
-               state->enter = (state->flags & CPUIDLE_FLAG_CHECK_BM) ?
-                       omap3_enter_idle_bm : omap3_enter_idle;
-               if (cx->type == OMAP3_STATE_C1)
-                       dev->safe_state = state;
-               sprintf(state->name, "C%d", count+1);
-               strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
-               count++;
-       }
+       /* C1 . MPU WFI + Core active */
+       cx = _fill_cstate(dev, 0, "MPU ON + CORE ON");
+       (&dev->states[0])->enter = omap3_enter_idle;
+       dev->safe_state = &dev->states[0];
+       cx->valid = 1;  /* C1 is always valid */
+       cx->mpu_state = PWRDM_POWER_ON;
+       cx->core_state = PWRDM_POWER_ON;
 
-       if (!count)
-               return -EINVAL;
-       dev->state_count = count;
+       /* C2 . MPU WFI + Core inactive */
+       cx = _fill_cstate(dev, 1, "MPU ON + CORE ON");
+       cx->mpu_state = PWRDM_POWER_ON;
+       cx->core_state = PWRDM_POWER_ON;
+
+       /* C3 . MPU CSWR + Core inactive */
+       cx = _fill_cstate(dev, 2, "MPU RET + CORE ON");
+       cx->mpu_state = PWRDM_POWER_RET;
+       cx->core_state = PWRDM_POWER_ON;
 
-       if (enable_off_mode)
-               omap3_cpuidle_update_states(PWRDM_POWER_OFF, PWRDM_POWER_OFF);
-       else
-               omap3_cpuidle_update_states(PWRDM_POWER_RET, PWRDM_POWER_RET);
+       /* C4 . MPU OFF + Core inactive */
+       cx = _fill_cstate(dev, 3, "MPU OFF + CORE ON");
+       cx->mpu_state = PWRDM_POWER_OFF;
+       cx->core_state = PWRDM_POWER_ON;
+
+       /* C5 . MPU RET + Core RET */
+       cx = _fill_cstate(dev, 4, "MPU RET + CORE RET");
+       cx->mpu_state = PWRDM_POWER_RET;
+       cx->core_state = PWRDM_POWER_RET;
+
+       /* C6 . MPU OFF + Core RET */
+       cx = _fill_cstate(dev, 5, "MPU OFF + CORE RET");
+       cx->mpu_state = PWRDM_POWER_OFF;
+       cx->core_state = PWRDM_POWER_RET;
+
+       /* C7 . MPU OFF + Core OFF */
+       cx = _fill_cstate(dev, 6, "MPU OFF + CORE OFF");
+       /*
+        * Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot
+        * enable OFF mode in a stable form for previous revisions.
+        * We disable C7 state as a result.
+        */
+       if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583)) {
+               cx->valid = 0;
+               pr_warn("%s: core off state C7 disabled due to i583\n",
+                       __func__);
+       }
+       cx->mpu_state = PWRDM_POWER_OFF;
+       cx->core_state = PWRDM_POWER_OFF;
 
+       dev->state_count = OMAP3_NUM_STATES;
        if (cpuidle_register_device(dev)) {
                printk(KERN_ERR "%s: CPUidle register device failed\n",
                       __func__);
index 7b855856459143a6cfaa8c20ab597d661c5213a5..5b8ca680ed93d2e9f919548cca05cb656f4ee787 100644 (file)
@@ -97,7 +97,7 @@ static int __init omap4_l3_init(void)
 
        WARN(IS_ERR(od), "could not build omap_device for %s\n", oh_name);
 
-       return PTR_ERR(od);
+       return IS_ERR(od) ? PTR_ERR(od) : 0;
 }
 postcore_initcall(omap4_l3_init);
 
index 256d23fb79abad7a3c40f15ea7905972e780ea7b..543fcb8b518cb227d967f32a03a0ed8d68b63400 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
 
@@ -56,37 +56,58 @@ static bool opt_clock_available(const char *clk_role)
        return false;
 }
 
+struct omap_dss_hwmod_data {
+       const char *oh_name;
+       const char *dev_name;
+       const int id;
+};
+
+static const struct omap_dss_hwmod_data omap2_dss_hwmod_data[] __initdata = {
+       { "dss_core", "omapdss_dss", -1 },
+       { "dss_dispc", "omapdss_dispc", -1 },
+       { "dss_rfbi", "omapdss_rfbi", -1 },
+       { "dss_venc", "omapdss_venc", -1 },
+};
+
+static const struct omap_dss_hwmod_data omap3_dss_hwmod_data[] __initdata = {
+       { "dss_core", "omapdss_dss", -1 },
+       { "dss_dispc", "omapdss_dispc", -1 },
+       { "dss_rfbi", "omapdss_rfbi", -1 },
+       { "dss_venc", "omapdss_venc", -1 },
+       { "dss_dsi1", "omapdss_dsi1", -1 },
+};
+
+static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initdata = {
+       { "dss_core", "omapdss_dss", -1 },
+       { "dss_dispc", "omapdss_dispc", -1 },
+       { "dss_rfbi", "omapdss_rfbi", -1 },
+       { "dss_venc", "omapdss_venc", -1 },
+       { "dss_dsi1", "omapdss_dsi1", -1 },
+       { "dss_dsi2", "omapdss_dsi2", -1 },
+       { "dss_hdmi", "omapdss_hdmi", -1 },
+};
+
 int __init omap_display_init(struct omap_dss_board_info *board_data)
 {
        int r = 0;
        struct omap_hwmod *oh;
        struct omap_device *od;
-       int i;
+       int i, oh_count;
        struct omap_display_platform_data pdata;
-
-       /*
-        * omap: valid DSS hwmod names
-        * omap2,3,4: dss_core, dss_dispc, dss_rfbi, dss_venc
-        * omap3,4: dss_dsi1
-        * omap4: dss_dsi2, dss_hdmi
-        */
-       char *oh_name[] = { "dss_core", "dss_dispc", "dss_rfbi", "dss_venc",
-               "dss_dsi1", "dss_dsi2", "dss_hdmi" };
-       char *dev_name[] = { "omapdss_dss", "omapdss_dispc", "omapdss_rfbi",
-               "omapdss_venc", "omapdss_dsi1", "omapdss_dsi2",
-               "omapdss_hdmi" };
-       int oh_count;
+       const struct omap_dss_hwmod_data *curr_dss_hwmod;
 
        memset(&pdata, 0, sizeof(pdata));
 
-       if (cpu_is_omap24xx())
-               oh_count = ARRAY_SIZE(oh_name) - 3;
-               /* last 3 hwmod dev in oh_name are not available for omap2 */
-       else if (cpu_is_omap44xx())
-               oh_count = ARRAY_SIZE(oh_name);
-       else
-               oh_count = ARRAY_SIZE(oh_name) - 2;
-               /* last 2 hwmod dev in oh_name are not available for omap3 */
+       if (cpu_is_omap24xx()) {
+               curr_dss_hwmod = omap2_dss_hwmod_data;
+               oh_count = ARRAY_SIZE(omap2_dss_hwmod_data);
+       } else if (cpu_is_omap34xx()) {
+               curr_dss_hwmod = omap3_dss_hwmod_data;
+               oh_count = ARRAY_SIZE(omap3_dss_hwmod_data);
+       } else {
+               curr_dss_hwmod = omap4_dss_hwmod_data;
+               oh_count = ARRAY_SIZE(omap4_dss_hwmod_data);
+       }
 
        /* opt_clks are always associated with dss hwmod */
        oh_core = omap_hwmod_lookup("dss_core");
@@ -100,19 +121,21 @@ int __init omap_display_init(struct omap_dss_board_info *board_data)
        pdata.opt_clock_available = opt_clock_available;
 
        for (i = 0; i < oh_count; i++) {
-               oh = omap_hwmod_lookup(oh_name[i]);
+               oh = omap_hwmod_lookup(curr_dss_hwmod[i].oh_name);
                if (!oh) {
-                       pr_err("Could not look up %s\n", oh_name[i]);
+                       pr_err("Could not look up %s\n",
+                               curr_dss_hwmod[i].oh_name);
                        return -ENODEV;
                }
 
-               od = omap_device_build(dev_name[i], -1, oh, &pdata,
+               od = omap_device_build(curr_dss_hwmod[i].dev_name,
+                               curr_dss_hwmod[i].id, oh, &pdata,
                                sizeof(struct omap_display_platform_data),
                                omap_dss_latency,
                                ARRAY_SIZE(omap_dss_latency), 0);
 
                if (WARN((IS_ERR(od)), "Could not build omap_device for %s\n",
-                               oh_name[i]))
+                               curr_dss_hwmod[i].oh_name))
                        return -ENODEV;
        }
        omap_display_device.dev.platform_data = board_data;
index 877c6f5807b7b1d5e68a623715bfa78711286dfd..ba10c24f3d8dcef3378490a9f615c74b471e22a2 100644 (file)
@@ -147,25 +147,24 @@ void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
                        goto free1;
        }
 
-       if (gpio_request(gpmc_cfg->gpio_irq, "SMC91X irq") < 0)
+       if (gpio_request_one(gpmc_cfg->gpio_irq, GPIOF_IN, "SMC91X irq") < 0)
                goto free1;
 
-       gpio_direction_input(gpmc_cfg->gpio_irq);
        gpmc_smc91x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
 
        if (gpmc_cfg->gpio_pwrdwn) {
-               ret = gpio_request(gpmc_cfg->gpio_pwrdwn, "SMC91X powerdown");
+               ret = gpio_request_one(gpmc_cfg->gpio_pwrdwn,
+                                      GPIOF_OUT_INIT_LOW, "SMC91X powerdown");
                if (ret)
                        goto free2;
-               gpio_direction_output(gpmc_cfg->gpio_pwrdwn, 0);
        }
 
        if (gpmc_cfg->gpio_reset) {
-               ret = gpio_request(gpmc_cfg->gpio_reset, "SMC91X reset");
+               ret = gpio_request_one(gpmc_cfg->gpio_reset,
+                                      GPIOF_OUT_INIT_LOW, "SMC91X reset");
                if (ret)
                        goto free3;
 
-               gpio_direction_output(gpmc_cfg->gpio_reset, 0);
                gpio_set_value(gpmc_cfg->gpio_reset, 1);
                msleep(100);
                gpio_set_value(gpmc_cfg->gpio_reset, 0);
index 703f150dd01dbd7b86f54e279ddb116d48fe6316..997033129d2642fc022702c316c71e4376679fb1 100644 (file)
@@ -10,6 +10,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#define pr_fmt(fmt) "%s: " fmt, __func__
 
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
@@ -30,7 +31,7 @@ static struct resource gpmc_smsc911x_resources[] = {
                .flags          = IORESOURCE_MEM,
        },
        [1] = {
-               .flags          = IORESOURCE_IRQ,
+               .flags          = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
        },
 };
 
@@ -41,16 +42,6 @@ static struct smsc911x_platform_config gpmc_smsc911x_config = {
        .flags          = SMSC911X_USE_16BIT,
 };
 
-static struct platform_device gpmc_smsc911x_device = {
-       .name           = "smsc911x",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(gpmc_smsc911x_resources),
-       .resource       = gpmc_smsc911x_resources,
-       .dev            = {
-               .platform_data = &gpmc_smsc911x_config,
-       },
-};
-
 /*
  * Initialize smsc911x device connected to the GPMC. Note that we
  * assume that pin multiplexing is done in the board-*.c file,
@@ -58,46 +49,49 @@ static struct platform_device gpmc_smsc911x_device = {
  */
 void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *board_data)
 {
+       struct platform_device *pdev;
        unsigned long cs_mem_base;
        int ret;
 
        gpmc_cfg = board_data;
 
        if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
-               printk(KERN_ERR "Failed to request GPMC mem for smsc911x\n");
+               pr_err("Failed to request GPMC mem region\n");
                return;
        }
 
        gpmc_smsc911x_resources[0].start = cs_mem_base + 0x0;
        gpmc_smsc911x_resources[0].end = cs_mem_base + 0xff;
 
-       if (gpio_request(gpmc_cfg->gpio_irq, "smsc911x irq") < 0) {
-               printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n",
-                               gpmc_cfg->gpio_irq);
+       if (gpio_request_one(gpmc_cfg->gpio_irq, GPIOF_IN, "smsc911x irq")) {
+               pr_err("Failed to request IRQ GPIO%d\n", gpmc_cfg->gpio_irq);
                goto free1;
        }
 
-       gpio_direction_input(gpmc_cfg->gpio_irq);
        gpmc_smsc911x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
-       gpmc_smsc911x_resources[1].flags |=
-                                       (gpmc_cfg->flags & IRQF_TRIGGER_MASK);
 
        if (gpio_is_valid(gpmc_cfg->gpio_reset)) {
-               ret = gpio_request(gpmc_cfg->gpio_reset, "smsc911x reset");
+               ret = gpio_request_one(gpmc_cfg->gpio_reset,
+                                      GPIOF_OUT_INIT_HIGH, "smsc911x reset");
                if (ret) {
-                       printk(KERN_ERR "Failed to request GPIO%d for smsc911x reset\n",
-                                       gpmc_cfg->gpio_reset);
+                       pr_err("Failed to request reset GPIO%d\n",
+                              gpmc_cfg->gpio_reset);
                        goto free2;
                }
 
-               gpio_direction_output(gpmc_cfg->gpio_reset, 1);
                gpio_set_value(gpmc_cfg->gpio_reset, 0);
                msleep(100);
                gpio_set_value(gpmc_cfg->gpio_reset, 1);
        }
 
-       if (platform_device_register(&gpmc_smsc911x_device) < 0) {
-               printk(KERN_ERR "Unable to register smsc911x device\n");
+       if (gpmc_cfg->flags)
+               gpmc_smsc911x_config.flags = gpmc_cfg->flags;
+
+       pdev = platform_device_register_resndata(NULL, "smsc911x", gpmc_cfg->id,
+                gpmc_smsc911x_resources, ARRAY_SIZE(gpmc_smsc911x_resources),
+                &gpmc_smsc911x_config, sizeof(gpmc_smsc911x_config));
+       if (!pdev) {
+               pr_err("Unable to register platform device\n");
                gpio_free(gpmc_cfg->gpio_reset);
                goto free2;
        }
@@ -109,5 +103,5 @@ free2:
 free1:
        gpmc_cs_free(gpmc_cfg->cs);
 
-       printk(KERN_ERR "Could not initialize smsc911x\n");
+       pr_err("Could not initialize smsc911x device\n");
 }
index b2f30bed5a2041d5e27a7b3ce24a172eb8d966e1..66868c5d5a29b8207da355ef7163e941296f615c 100644 (file)
@@ -145,6 +145,7 @@ static void omap4_hsmmc1_after_set_reg(struct device *dev, int slot,
                                 int power_on, int vdd)
 {
        u32 reg;
+       unsigned long timeout;
 
        if (power_on) {
                reg = omap4_ctrl_pad_readl(control_pbias_offset);
@@ -157,9 +158,15 @@ static void omap4_hsmmc1_after_set_reg(struct device *dev, int slot,
                        OMAP4_MMC1_PWRDNZ_MASK |
                        OMAP4_USBC1_ICUSB_PWRDNZ_MASK);
                omap4_ctrl_pad_writel(reg, control_pbias_offset);
-               /* 4 microsec delay for comparator to generate an error*/
-               udelay(4);
-               reg = omap4_ctrl_pad_readl(control_pbias_offset);
+
+               timeout = jiffies + msecs_to_jiffies(5);
+               do {
+                       reg = omap4_ctrl_pad_readl(control_pbias_offset);
+                       if (!(reg & OMAP4_MMC1_PBIASLITE_VMODE_ERROR_MASK))
+                               break;
+                       usleep_range(100, 200);
+               } while (!time_after(jiffies, timeout));
+
                if (reg & OMAP4_MMC1_PBIASLITE_VMODE_ERROR_MASK) {
                        pr_err("Pbias Voltage is not same as LDO\n");
                        /* Caution : On VMODE_ERROR Power Down MMC IO */
@@ -331,6 +338,9 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
        if (c->no_off)
                mmc->slots[0].no_off = 1;
 
+       if (c->no_off_init)
+               mmc->slots[0].no_regulator_off_init = c->no_off_init;
+
        if (c->vcc_aux_disable_is_sleep)
                mmc->slots[0].vcc_aux_disable_is_sleep = 1;
 
index f119348827d46d029c3cc7544ca1293420b7156c..f757e78d4d4f5759f73bdc27acc502c1ef8f497f 100644 (file)
@@ -18,6 +18,7 @@ struct omap2_hsmmc_info {
        bool    nonremovable;   /* Nonremovable e.g. eMMC */
        bool    power_saving;   /* Try to sleep or power off when possible */
        bool    no_off;         /* power_saving and power is not to go off */
+       bool    no_off_init;    /* no power off when not in MMC sleep state */
        bool    vcc_aux_disable_is_sleep; /* Regulator off remapped to sleep */
        int     gpio_cd;        /* or -EINVAL */
        int     gpio_wp;        /* or -EINVAL */
index d20bd9c1a1061cfde9b547073b354fb23e8d0321..775fdc3b000b686d20e09ab21d4a5c756c8c9542 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Defines for zoom boards
  */
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define ZOOM_NAND_CS    0
 
index a4ab1e364313693dcdef6292e3310a8afa9fe6be..c7fb22abc219db3756758275e0aa30c90fcdd5e6 100644 (file)
@@ -83,6 +83,9 @@ void omap_mux_write(struct omap_mux_partition *partition, u16 val,
 void omap_mux_write_array(struct omap_mux_partition *partition,
                                 struct omap_board_mux *board_mux)
 {
+       if (!board_mux)
+               return;
+
        while (board_mux->reg_offset != OMAP_MUX_TERMINATOR) {
                omap_mux_write(partition, board_mux->value,
                               board_mux->reg_offset);
@@ -906,7 +909,7 @@ static struct omap_mux *omap_mux_get_by_gpio(
 u16 omap_mux_get_gpio(int gpio)
 {
        struct omap_mux_partition *partition;
-       struct omap_mux *m;
+       struct omap_mux *m = NULL;
 
        list_for_each_entry(partition, &mux_partitions, node) {
                m = omap_mux_get_by_gpio(partition, gpio);
index 137f321c029f59a240fd885cfd7c8538c59bf9d8..2132308ad1e41fffc14856b48294ffd42e748c8b 100644 (file)
@@ -323,10 +323,12 @@ int omap3_mux_init(struct omap_board_mux *board_mux, int flags);
 
 /**
  * omap4_mux_init() - initialize mux system with board specific set
- * @board_mux:         Board specific mux table
+ * @board_subset:      Board specific mux table
+ * @board_wkup_subset: Board specific mux table for wakeup instance
  * @flags:             OMAP package type used for the board
  */
-int omap4_mux_init(struct omap_board_mux *board_mux, int flags);
+int omap4_mux_init(struct omap_board_mux *board_subset,
+       struct omap_board_mux *board_wkup_subset, int flags);
 
 /**
  * omap_mux_init - private mux init function, do not call
index 9a66445112ae8ca37a7ad8b1c136c04d7cebaa4f..f5a74daab2ff679ecfc7717d1b8dd3b1295d8606 100644 (file)
@@ -1309,7 +1309,8 @@ static struct omap_ball __initdata omap4_wkup_cbl_cbs_ball[] = {
 #define omap4_wkup_cbl_cbs_ball  NULL
 #endif
 
-int __init omap4_mux_init(struct omap_board_mux *board_subset, int flags)
+int __init omap4_mux_init(struct omap_board_mux *board_subset,
+       struct omap_board_mux *board_wkup_subset, int flags)
 {
        struct omap_ball *package_balls_core;
        struct omap_ball *package_balls_wkup = omap4_wkup_cbl_cbs_ball;
@@ -1347,7 +1348,7 @@ int __init omap4_mux_init(struct omap_board_mux *board_subset, int flags)
                            OMAP_MUX_GPIO_IN_MODE3,
                            OMAP4_CTRL_MODULE_PAD_WKUP_MUX_PBASE,
                            OMAP4_CTRL_MODULE_PAD_WKUP_MUX_SIZE,
-                           omap4_wkup_muxmodes, NULL, board_subset,
+                           omap4_wkup_muxmodes, NULL, board_wkup_subset,
                            package_balls_wkup);
 
        return ret;
index e03429453ce7aa8b20eee7fe0b1026a66fec8c5b..293fa6cd50e14192cf075e1b9f9937c307b7c2e4 100644 (file)
@@ -1628,7 +1628,7 @@ int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data),
                        void *data)
 {
        struct omap_hwmod *temp_oh;
-       int ret;
+       int ret = 0;
 
        if (!fn)
                return -EINVAL;
index abc548a0c98dacae4bd6c5fc7d8eb615dde9b4c5..e1c69ffe0f69db181b9dd6245be9e72ffbaf63f0 100644 (file)
@@ -5109,7 +5109,7 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
        &omap44xx_iva_seq1_hwmod,
 
        /* kbd class */
-/*     &omap44xx_kbd_hwmod, */
+       &omap44xx_kbd_hwmod,
 
        /* mailbox class */
        &omap44xx_mailbox_hwmod,
index 82632c24076f443f80bbc88f78e12a6c15ad0c76..7b9f1909ddb2a3bc110d83b721a2466ec574f01a 100644 (file)
@@ -63,10 +63,7 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3)
        char *source_name;
 
        /* Get the Type of interrupt */
-       if (irq == l3->app_irq)
-               inttype = L3_APPLICATION_ERROR;
-       else
-               inttype = L3_DEBUG_ERROR;
+       inttype = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR;
 
        for (i = 0; i < L3_MODULES; i++) {
                /*
@@ -84,10 +81,10 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3)
 
                        err_src = j;
                        /* Read the stderrlog_main_source from clk domain */
-                       std_err_main_addr = base + (*(l3_targ[i] + err_src));
-                       std_err_main =  readl(std_err_main_addr);
+                       std_err_main_addr = base + *(l3_targ[i] + err_src);
+                       std_err_main = readl(std_err_main_addr);
 
-                       switch ((std_err_main & CUSTOM_ERROR)) {
+                       switch (std_err_main & CUSTOM_ERROR) {
                        case STANDARD_ERROR:
                                source_name =
                                l3_targ_stderrlog_main_name[i][err_src];
@@ -132,49 +129,49 @@ static int __init omap4_l3_probe(struct platform_device *pdev)
 
        l3 = kzalloc(sizeof(*l3), GFP_KERNEL);
        if (!l3)
-               ret = -ENOMEM;
+               return -ENOMEM;
 
        platform_set_drvdata(pdev, l3);
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(&pdev->dev, "couldn't find resource 0\n");
                ret = -ENODEV;
-               goto err1;
+               goto err0;
        }
 
        l3->l3_base[0] = ioremap(res->start, resource_size(res));
-       if (!(l3->l3_base[0])) {
+       if (!l3->l3_base[0]) {
                dev_err(&pdev->dev, "ioremap failed\n");
                ret = -ENOMEM;
-               goto err2;
+               goto err0;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        if (!res) {
                dev_err(&pdev->dev, "couldn't find resource 1\n");
                ret = -ENODEV;
-               goto err3;
+               goto err1;
        }
 
        l3->l3_base[1] = ioremap(res->start, resource_size(res));
-       if (!(l3->l3_base[1])) {
+       if (!l3->l3_base[1]) {
                dev_err(&pdev->dev, "ioremap failed\n");
                ret = -ENOMEM;
-               goto err4;
+               goto err1;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
        if (!res) {
                dev_err(&pdev->dev, "couldn't find resource 2\n");
                ret = -ENODEV;
-               goto err5;
+               goto err2;
        }
 
        l3->l3_base[2] = ioremap(res->start, resource_size(res));
-       if (!(l3->l3_base[2])) {
+       if (!l3->l3_base[2]) {
                dev_err(&pdev->dev, "ioremap failed\n");
                ret = -ENOMEM;
-               goto err6;
+               goto err2;
        }
 
        /*
@@ -187,7 +184,7 @@ static int __init omap4_l3_probe(struct platform_device *pdev)
        if (ret) {
                pr_crit("L3: request_irq failed to register for 0x%x\n",
                                         OMAP44XX_IRQ_L3_DBG);
-               goto err7;
+               goto err3;
        }
        l3->debug_irq = irq;
 
@@ -198,24 +195,22 @@ static int __init omap4_l3_probe(struct platform_device *pdev)
        if (ret) {
                pr_crit("L3: request_irq failed to register for 0x%x\n",
                                         OMAP44XX_IRQ_L3_APP);
-               goto err8;
+               goto err4;
        }
        l3->app_irq = irq;
 
-       goto err0;
-err8:
-err7:
-       iounmap(l3->l3_base[2]);
-err6:
-err5:
-       iounmap(l3->l3_base[1]);
+       return 0;
+
 err4:
+       free_irq(l3->debug_irq, l3);
 err3:
-       iounmap(l3->l3_base[0]);
+       iounmap(l3->l3_base[2]);
 err2:
+       iounmap(l3->l3_base[1]);
 err1:
-       kfree(l3);
+       iounmap(l3->l3_base[0]);
 err0:
+       kfree(l3);
        return ret;
 }
 
index 4321e79389291c9695e4695d91132f64b48cc803..873c0e33b512e1da521e2277a8122b60aa84a779 100644 (file)
@@ -155,7 +155,7 @@ static irqreturn_t omap3_l3_block_irq(struct omap3_l3 *l3,
        u8                      multi = error & L3_ERROR_LOG_MULTI;
        u32                     address = omap3_l3_decode_addr(error_addr);
 
-       WARN(true, "%s Error seen by %s %s at address %x\n",
+       WARN(true, "%s seen by %s %s at address %x\n",
                                 omap3_l3_code_string(code),
                          omap3_l3_initiator_string(initid),
                             multi ? "Multiple Errors" : "",
@@ -167,21 +167,15 @@ static irqreturn_t omap3_l3_block_irq(struct omap3_l3 *l3,
 static irqreturn_t omap3_l3_app_irq(int irq, void *_l3)
 {
        struct omap3_l3         *l3 = _l3;
-
        u64                     status, clear;
        u64                     error;
        u64                     error_addr;
        u64                     err_source = 0;
        void                    __iomem *base;
        int                     int_type;
-
        irqreturn_t             ret = IRQ_NONE;
 
-       if (irq == l3->app_irq)
-               int_type = L3_APPLICATION_ERROR;
-       else
-               int_type = L3_DEBUG_ERROR;
-
+       int_type = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR;
        if (!int_type) {
                status = omap3_l3_readll(l3->rt, L3_SI_FLAG_STATUS_0);
                /*
@@ -202,7 +196,6 @@ static irqreturn_t omap3_l3_app_irq(int irq, void *_l3)
 
        base = l3->rt + *(omap3_l3_bases[int_type] + err_source);
        error = omap3_l3_readll(base, L3_ERROR_LOG);
-
        if (error) {
                error_addr = omap3_l3_readll(base, L3_ERROR_LOG_ADDR);
 
@@ -210,9 +203,8 @@ static irqreturn_t omap3_l3_app_irq(int irq, void *_l3)
        }
 
        /* Clear the status register */
-       clear = ((L3_AGENT_STATUS_CLEAR_IA << int_type) |
-                (L3_AGENT_STATUS_CLEAR_TA));
-
+       clear = (L3_AGENT_STATUS_CLEAR_IA << int_type) |
+               L3_AGENT_STATUS_CLEAR_TA;
        omap3_l3_writell(base, L3_AGENT_STATUS, clear);
 
        /* clear the error log register */
@@ -228,10 +220,8 @@ static int __init omap3_l3_probe(struct platform_device *pdev)
        int                     ret;
 
        l3 = kzalloc(sizeof(*l3), GFP_KERNEL);
-       if (!l3) {
-               ret = -ENOMEM;
-               goto err0;
-       }
+       if (!l3)
+               return -ENOMEM;
 
        platform_set_drvdata(pdev, l3);
 
@@ -239,13 +229,13 @@ static int __init omap3_l3_probe(struct platform_device *pdev)
        if (!res) {
                dev_err(&pdev->dev, "couldn't find resource\n");
                ret = -ENODEV;
-               goto err1;
+               goto err0;
        }
        l3->rt = ioremap(res->start, resource_size(res));
-       if (!(l3->rt)) {
+       if (!l3->rt) {
                dev_err(&pdev->dev, "ioremap failed\n");
                ret = -ENOMEM;
-               goto err2;
+               goto err0;
        }
 
        l3->debug_irq = platform_get_irq(pdev, 0);
@@ -254,28 +244,26 @@ static int __init omap3_l3_probe(struct platform_device *pdev)
                "l3-debug-irq", l3);
        if (ret) {
                dev_err(&pdev->dev, "couldn't request debug irq\n");
-               goto err3;
+               goto err1;
        }
 
        l3->app_irq = platform_get_irq(pdev, 1);
        ret = request_irq(l3->app_irq, omap3_l3_app_irq,
                IRQF_DISABLED | IRQF_TRIGGER_RISING,
                "l3-app-irq", l3);
-
        if (ret) {
                dev_err(&pdev->dev, "couldn't request app irq\n");
-               goto err4;
+               goto err2;
        }
 
-       goto err0;
+       return 0;
 
-err4:
-err3:
-       iounmap(l3->rt);
 err2:
+       free_irq(l3->debug_irq, l3);
 err1:
-       kfree(l3);
+       iounmap(l3->rt);
 err0:
+       kfree(l3);
        return ret;
 }
 
index 05f6abc96b0d6032edfb3e2b21f85bc90099ba5d..58775e3c84762e59b9cbe3c82a5d4022638f15ae 100644 (file)
@@ -50,13 +50,18 @@ int omap4430_phy_init(struct device *dev)
 {
        ctrl_base = ioremap(OMAP443X_SCM_BASE, SZ_1K);
        if (!ctrl_base) {
-               dev_err(dev, "control module ioremap failed\n");
+               pr_err("control module ioremap failed\n");
                return -ENOMEM;
        }
        /* Power down the phy */
        __raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF);
-       phyclk = clk_get(dev, "ocp2scp_usb_phy_ick");
 
+       if (!dev) {
+               iounmap(ctrl_base);
+               return 0;
+       }
+
+       phyclk = clk_get(dev, "ocp2scp_usb_phy_ick");
        if (IS_ERR(phyclk)) {
                dev_err(dev, "cannot clk_get ocp2scp_usb_phy_ick\n");
                iounmap(ctrl_base);
@@ -228,7 +233,7 @@ void am35x_musb_clear_irq(void)
        regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
 }
 
-void am35x_musb_set_mode(u8 musb_mode)
+void am35x_set_mode(u8 musb_mode)
 {
        u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
 
index a5a83b358ddd89724de71eace26e11d8289c8e65..e01da45c053756f62ac08956620dc16dd09d3407 100644 (file)
@@ -189,7 +189,7 @@ static struct dentry *pm_dbg_dir;
 
 static int pm_dbg_init_done;
 
-static int __init pm_dbg_init(void);
+static int pm_dbg_init(void);
 
 enum {
        DEBUG_FILE_COUNTERS = 0,
@@ -595,7 +595,7 @@ static int option_set(void *data, u64 val)
 
 DEFINE_SIMPLE_ATTRIBUTE(pm_dbg_option_fops, option_get, option_set, "%llu\n");
 
-static int __init pm_dbg_init(void)
+static int pm_dbg_init(void)
 {
        int i;
        struct dentry *d;
index 797bfd12b643fe3cc697bf2b7a7b09be522accc7..45bcfce7735248732a609f647870cee35d19f8a9 100644 (file)
@@ -36,11 +36,16 @@ static inline int omap4_opp_init(void)
 }
 #endif
 
+/*
+ * cpuidle mach specific parameters
+ *
+ * The board code can override the default C-states definition using
+ * omap3_pm_init_cpuidle
+ */
 struct cpuidle_params {
-       u8  valid;
-       u32 sleep_latency;
-       u32 wake_latency;
-       u32 threshold;
+       u32 exit_latency;       /* exit_latency = sleep + wake-up latencies */
+       u32 target_residency;
+       u8 valid;               /* validates the C-state */
 };
 
 #if defined(CONFIG_PM) && defined(CONFIG_CPU_IDLE)
@@ -73,10 +78,6 @@ extern u32 sleep_while_idle;
 #define sleep_while_idle 0
 #endif
 
-#if defined(CONFIG_CPU_IDLE)
-extern void omap3_cpuidle_update_states(u32, u32);
-#endif
-
 #if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
 extern void pm_dbg_update_time(struct powerdomain *pwrdm, int prev);
 extern int pm_dbg_regset_save(int reg_set);
index 0c5e3a46a3ada0a51403f1770542923e273fad8a..c155c9d1c82cbe3b7868e545b02033e530f0afca 100644 (file)
@@ -779,18 +779,6 @@ void omap3_pm_off_mode_enable(int enable)
        else
                state = PWRDM_POWER_RET;
 
-#ifdef CONFIG_CPU_IDLE
-       /*
-        * Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot
-        * enable OFF mode in a stable form for previous revisions, restrict
-        * instead to RET
-        */
-       if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583))
-               omap3_cpuidle_update_states(state, PWRDM_POWER_RET);
-       else
-               omap3_cpuidle_update_states(state, state);
-#endif
-
        list_for_each_entry(pwrst, &pwrst_list, node) {
                if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583) &&
                                pwrst->pwrdm == core_pwrdm &&
@@ -895,8 +883,6 @@ static int __init omap3_pm_init(void)
 
        pm_errata_configure();
 
-       printk(KERN_ERR "Power Management for TI OMAP3.\n");
-
        /* XXX prcm_setup_regs needs to be before enabling hw
         * supervised mode for powerdomains */
        prcm_setup_regs();
index 76cfff2db5141e26b2b0b7a0396abb37f342ec92..59a870be8390289931bde435d0499952ec9ecb00 100644 (file)
@@ -105,13 +105,11 @@ static int __init omap4_pm_init(void)
 
        pr_err("Power Management for TI OMAP4.\n");
 
-#ifdef CONFIG_PM
        ret = pwrdm_for_each(pwrdms_setup, NULL);
        if (ret) {
                pr_err("Failed to setup powerdomains\n");
                goto err2;
        }
-#endif
 
 #ifdef CONFIG_SUSPEND
        suspend_set_ops(&omap_pm_ops);
index 13e24f913dd4044199faebbfcb9bd462ad6fc22d..fb7dc52394a8fd8a872fb0e1f22d0cc867a3df9b 100644 (file)
@@ -847,6 +847,14 @@ static int __init omap_sr_probe(struct platform_device *pdev)
                goto err_free_devinfo;
        }
 
+       mem = request_mem_region(mem->start, resource_size(mem),
+                                       dev_name(&pdev->dev));
+       if (!mem) {
+               dev_err(&pdev->dev, "%s: no mem region\n", __func__);
+               ret = -EBUSY;
+               goto err_free_devinfo;
+       }
+
        irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 
        pm_runtime_enable(&pdev->dev);
@@ -883,7 +891,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
                ret = sr_late_init(sr_info);
                if (ret) {
                        pr_warning("%s: Error in SR late init\n", __func__);
-                       goto err_release_region;
+                       return ret;
                }
        }
 
@@ -896,7 +904,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
        vdd_dbg_dir = omap_voltage_get_dbgdir(sr_info->voltdm);
        if (!vdd_dbg_dir) {
                ret = -EINVAL;
-               goto err_release_region;
+               goto err_iounmap;
        }
 
        sr_info->dbg_dir = debugfs_create_dir("smartreflex", vdd_dbg_dir);
@@ -904,7 +912,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n",
                        __func__);
                ret = PTR_ERR(sr_info->dbg_dir);
-               goto err_release_region;
+               goto err_iounmap;
        }
 
        (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR,
@@ -921,7 +929,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "%s: Unable to create debugfs directory"
                        "for n-values\n", __func__);
                ret = PTR_ERR(nvalue_dir);
-               goto err_release_region;
+               goto err_debugfs;
        }
 
        omap_voltage_get_volttable(sr_info->voltdm, &volt_data);
@@ -931,7 +939,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
                        "entries for n-values\n",
                        __func__, sr_info->voltdm->name);
                ret = -ENODATA;
-               goto err_release_region;
+               goto err_debugfs;
        }
 
        for (i = 0; i < sr_info->nvalue_count; i++) {
@@ -945,6 +953,11 @@ static int __init omap_sr_probe(struct platform_device *pdev)
 
        return ret;
 
+err_debugfs:
+       debugfs_remove_recursive(sr_info->dbg_dir);
+err_iounmap:
+       list_del(&sr_info->node);
+       iounmap(sr_info->base);
 err_release_region:
        release_mem_region(mem->start, resource_size(mem));
 err_free_devinfo:
index 35559f77e2deb8e47fa7e2d84caffebdf0740bf1..c7ed540d868d218a56a1b4c07db3b417a2f91845 100644 (file)
@@ -108,7 +108,13 @@ static void usb_musb_mux_init(struct omap_musb_board_data *board_data)
        }
 }
 
-void __init usb_musb_init(struct omap_musb_board_data *board_data)
+static struct omap_musb_board_data musb_default_board_data = {
+       .interface_type         = MUSB_INTERFACE_ULPI,
+       .mode                   = MUSB_OTG,
+       .power                  = 100,
+};
+
+void __init usb_musb_init(struct omap_musb_board_data *musb_board_data)
 {
        struct omap_hwmod               *oh;
        struct omap_device              *od;
@@ -116,11 +122,12 @@ void __init usb_musb_init(struct omap_musb_board_data *board_data)
        struct device                   *dev;
        int                             bus_id = -1;
        const char                      *oh_name, *name;
+       struct omap_musb_board_data     *board_data;
 
-       if (cpu_is_omap3517() || cpu_is_omap3505()) {
-       } else if (cpu_is_omap44xx()) {
-               usb_musb_mux_init(board_data);
-       }
+       if (musb_board_data)
+               board_data = musb_board_data;
+       else
+               board_data = &musb_default_board_data;
 
        /*
         * REVISIT: This line can be removed once all the platforms using
@@ -164,10 +171,15 @@ void __init usb_musb_init(struct omap_musb_board_data *board_data)
        dev->dma_mask = &musb_dmamask;
        dev->coherent_dma_mask = musb_dmamask;
        put_device(dev);
+
+       if (cpu_is_omap44xx())
+               omap4430_phy_init(dev);
 }
 
 #else
 void __init usb_musb_init(struct omap_musb_board_data *board_data)
 {
+       if (cpu_is_omap44xx())
+               omap4430_phy_init(NULL);
 }
 #endif /* CONFIG_USB_MUSB_SOC */
index 8a3c05f3c1d6eff4db8b10e9d2ee3ffe0fc5d10a..8dd26b765b7d3f3aa976d8907f6eb8d0b631b1d1 100644 (file)
@@ -293,12 +293,11 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
                        );
 
        /* IRQ */
-       status = gpio_request(irq, "TUSB6010 irq");
+       status = gpio_request_one(irq, GPIOF_IN, "TUSB6010 irq");
        if (status < 0) {
                printk(error, 3, status);
                return status;
        }
-       gpio_direction_input(irq);
        tusb_resources[2].start = irq + IH_GPIO_BASE;
 
        /* set up memory timings ... can speed them up later */
index 0c1552d9d99508c3bc0d2a3aaf4ae5038becc089..9ef3789ded4b0f1c5e48d1782c7004067a03d8cd 100644 (file)
@@ -148,7 +148,6 @@ static int vp_volt_debug_get(void *data, u64 *val)
        }
 
        vsel = vdd->read_reg(prm_mod_offs, vdd->vp_data->voltage);
-       pr_notice("curr_vsel = %x\n", vsel);
 
        if (!vdd->pmic_info->vsel_to_uv) {
                pr_warning("PMIC function to convert vsel to voltage"
index 2fc9f94cdd29af9abd575dbf30c92acd379a1a24..cd19309fd3b846ce571c4c1e6eb14bf3f5450585 100644 (file)
@@ -153,7 +153,6 @@ config MACH_XCEP
        bool "Iskratel Electronics XCEP"
        select PXA25x
        select MTD
-       select MTD_PARTITIONS
        select MTD_PHYSMAP
        select MTD_CFI_INTELEXT
        select MTD_CFI
index 7fe74067d85fc7e2aeb1469878f28c8cd73b3456..094279aefe9c6fd5d6a86dd88fbbc44b6d55c07b 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
+#include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/apm-emulation.h>
index 0d468e96e83ef399b40f094f8304a1735e84957f..81695353d8f497d52d848a3637ac2b133003e841 100644 (file)
@@ -10,7 +10,6 @@ obj-n                         :=
 obj-                           :=
 
 obj-$(CONFIG_CPU_S3C2410)      += s3c2410.o
-obj-$(CONFIG_CPU_S3C2410)      += irq.o
 obj-$(CONFIG_CPU_S3C2410_DMA)  += dma.o
 obj-$(CONFIG_CPU_S3C2410_DMA)  += dma.o
 obj-$(CONFIG_S3C2410_PM)       += pm.o sleep.o
diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c
deleted file mode 100644 (file)
index 2854129..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/irq.c
- *
- * Copyright (c) 2006 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/syscore_ops.h>
-
-#include <plat/cpu.h>
-#include <plat/pm.h>
-
-struct syscore_ops s3c24xx_irq_syscore_ops = {
-       .suspend        = s3c24xx_irq_suspend,
-       .resume         = s3c24xx_irq_resume,
-};
index 44440cbd76204f7212d97f87228ae4d8394ae4b0..dabc141243f397b234c00b19293fccdd05a5d027 100644 (file)
@@ -58,8 +58,6 @@
 #include <plat/cpu.h>
 #include <plat/gpio-cfg.h>
 
-#ifdef CONFIG_MTD_PARTITIONS
-
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/map.h>
@@ -113,7 +111,6 @@ static struct platform_device amlm5900_device_nor = {
        .num_resources  = 1,
        .resource       = &amlm5900_nor_resource,
 };
-#endif
 
 static struct map_desc amlm5900_iodesc[] __initdata = {
 };
@@ -158,9 +155,7 @@ static struct platform_device *amlm5900_devices[] __initdata = {
        &s3c_device_rtc,
        &s3c_device_usbgadget,
         &s3c_device_sdi,
-#ifdef CONFIG_MTD_PARTITIONS
        &amlm5900_device_nor,
-#endif
 };
 
 static void __init amlm5900_map_io(void)
index a15d0621c22f2e4bbb4f7786d0435b575d3217ba..43c2b831b9e85164a5f9465216145e6973015f88 100644 (file)
@@ -49,8 +49,6 @@
 #include <plat/devs.h>
 #include <plat/cpu.h>
 
-#ifdef CONFIG_MTD_PARTITIONS
-
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/map.h>
@@ -91,8 +89,6 @@ static struct platform_device tct_hammer_device_nor = {
        .resource       = &tct_hammer_nor_resource,
 };
 
-#endif
-
 static struct map_desc tct_hammer_iodesc[] __initdata = {
 };
 
@@ -133,9 +129,7 @@ static struct platform_device *tct_hammer_devices[] __initdata = {
        &s3c_device_rtc,
        &s3c_device_usbgadget,
        &s3c_device_sdi,
-#ifdef CONFIG_MTD_PARTITIONS
        &tct_hammer_device_nor,
-#endif
 };
 
 static void __init tct_hammer_map_io(void)
index 405e621289172512bbf01527d9061717a95d55d6..82db072cb836b78899e917f4691bacdc3857557b 100644 (file)
@@ -16,7 +16,6 @@
 
 #include <mach/dma.h>
 #include <mach/map.h>
-#include <mach/gpio-bank-c.h>
 #include <mach/spi-clocks.h>
 #include <mach/irqs.h>
 
@@ -40,23 +39,15 @@ static char *spi_src_clks[] = {
  */
 static int s3c64xx_spi_cfg_gpio(struct platform_device *pdev)
 {
+       unsigned int base;
+
        switch (pdev->id) {
        case 0:
-               s3c_gpio_cfgpin(S3C64XX_GPC(0), S3C64XX_GPC0_SPI_MISO0);
-               s3c_gpio_cfgpin(S3C64XX_GPC(1), S3C64XX_GPC1_SPI_CLKO);
-               s3c_gpio_cfgpin(S3C64XX_GPC(2), S3C64XX_GPC2_SPI_MOSIO);
-               s3c_gpio_setpull(S3C64XX_GPC(0), S3C_GPIO_PULL_UP);
-               s3c_gpio_setpull(S3C64XX_GPC(1), S3C_GPIO_PULL_UP);
-               s3c_gpio_setpull(S3C64XX_GPC(2), S3C_GPIO_PULL_UP);
+               base = S3C64XX_GPC(0);
                break;
 
        case 1:
-               s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C64XX_GPC4_SPI_MISO1);
-               s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C64XX_GPC5_SPI_CLK1);
-               s3c_gpio_cfgpin(S3C64XX_GPC(6), S3C64XX_GPC6_SPI_MOSI1);
-               s3c_gpio_setpull(S3C64XX_GPC(4), S3C_GPIO_PULL_UP);
-               s3c_gpio_setpull(S3C64XX_GPC(5), S3C_GPIO_PULL_UP);
-               s3c_gpio_setpull(S3C64XX_GPC(6), S3C_GPIO_PULL_UP);
+               base = S3C64XX_GPC(4);
                break;
 
        default:
@@ -64,6 +55,9 @@ static int s3c64xx_spi_cfg_gpio(struct platform_device *pdev)
                return -EINVAL;
        }
 
+       s3c_gpio_cfgall_range(base, 3,
+                             S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
+
        return 0;
 }
 
diff --git a/arch/arm/mach-s3c64xx/include/mach/gpio-bank-a.h b/arch/arm/mach-s3c64xx/include/mach/gpio-bank-a.h
deleted file mode 100644 (file)
index 34212e1..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* linux/arch/arm/mach-s3c64xx/include/mach/gpio-bank-a.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * GPIO Bank A register and configuration definitions
- *
- * 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.
-*/
-
-#define S3C64XX_GPACON                 (S3C64XX_GPA_BASE + 0x00)
-#define S3C64XX_GPADAT                 (S3C64XX_GPA_BASE + 0x04)
-#define S3C64XX_GPAPUD                 (S3C64XX_GPA_BASE + 0x08)
-#define S3C64XX_GPACONSLP              (S3C64XX_GPA_BASE + 0x0c)
-#define S3C64XX_GPAPUDSLP              (S3C64XX_GPA_BASE + 0x10)
-
-#define S3C64XX_GPA_CONMASK(__gpio)    (0xf << ((__gpio) * 4))
-#define S3C64XX_GPA_INPUT(__gpio)      (0x0 << ((__gpio) * 4))
-#define S3C64XX_GPA_OUTPUT(__gpio)     (0x1 << ((__gpio) * 4))
-
-#define S3C64XX_GPA0_UART_RXD0         (0x02 << 0)
-#define S3C64XX_GPA0_EINT_G1_0         (0x07 << 0)
-
-#define S3C64XX_GPA1_UART_TXD0         (0x02 << 4)
-#define S3C64XX_GPA1_EINT_G1_1         (0x07 << 4)
-
-#define S3C64XX_GPA2_UART_nCTS0                (0x02 << 8)
-#define S3C64XX_GPA2_EINT_G1_2         (0x07 << 8)
-
-#define S3C64XX_GPA3_UART_nRTS0                (0x02 << 12)
-#define S3C64XX_GPA3_EINT_G1_3         (0x07 << 12)
-
-#define S3C64XX_GPA4_UART_RXD1         (0x02 << 16)
-#define S3C64XX_GPA4_EINT_G1_4         (0x07 << 16)
-
-#define S3C64XX_GPA5_UART_TXD1         (0x02 << 20)
-#define S3C64XX_GPA5_EINT_G1_5         (0x07 << 20)
-
-#define S3C64XX_GPA6_UART_nCTS1                (0x02 << 24)
-#define S3C64XX_GPA6_EINT_G1_6         (0x07 << 24)
-
-#define S3C64XX_GPA7_UART_nRTS1                (0x02 << 28)
-#define S3C64XX_GPA7_EINT_G1_7         (0x07 << 28)
-
diff --git a/arch/arm/mach-s3c64xx/include/mach/gpio-bank-b.h b/arch/arm/mach-s3c64xx/include/mach/gpio-bank-b.h
deleted file mode 100644 (file)
index 7232c03..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/* linux/arch/arm/mach-s3c64xx/include/mach/gpio-bank-b.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * GPIO Bank B register and configuration definitions
- *
- * 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.
-*/
-
-#define S3C64XX_GPBCON                 (S3C64XX_GPB_BASE + 0x00)
-#define S3C64XX_GPBDAT                 (S3C64XX_GPB_BASE + 0x04)
-#define S3C64XX_GPBPUD                 (S3C64XX_GPB_BASE + 0x08)
-#define S3C64XX_GPBCONSLP              (S3C64XX_GPB_BASE + 0x0c)
-#define S3C64XX_GPBPUDSLP              (S3C64XX_GPB_BASE + 0x10)
-
-#define S3C64XX_GPB_CONMASK(__gpio)    (0xf << ((__gpio) * 4))
-#define S3C64XX_GPB_INPUT(__gpio)      (0x0 << ((__gpio) * 4))
-#define S3C64XX_GPB_OUTPUT(__gpio)     (0x1 << ((__gpio) * 4))
-
-#define S3C64XX_GPB0_UART_RXD2         (0x02 << 0)
-#define S3C64XX_GPB0_EXTDMA_REQ                (0x03 << 0)
-#define S3C64XX_GPB0_IrDA_RXD          (0x04 << 0)
-#define S3C64XX_GPB0_ADDR_CF0          (0x05 << 0)
-#define S3C64XX_GPB0_EINT_G1_8         (0x07 << 0)
-
-#define S3C64XX_GPB1_UART_TXD2         (0x02 << 4)
-#define S3C64XX_GPB1_EXTDMA_ACK                (0x03 << 4)
-#define S3C64XX_GPB1_IrDA_TXD          (0x04 << 4)
-#define S3C64XX_GPB1_ADDR_CF1          (0x05 << 4)
-#define S3C64XX_GPB1_EINT_G1_9         (0x07 << 4)
-
-#define S3C64XX_GPB2_UART_RXD3         (0x02 << 8)
-#define S3C64XX_GPB2_IrDA_RXD          (0x03 << 8)
-#define S3C64XX_GPB2_EXTDMA_REQ                (0x04 << 8)
-#define S3C64XX_GPB2_ADDR_CF2          (0x05 << 8)
-#define S3C64XX_GPB2_I2C_SCL1          (0x06 << 8)
-#define S3C64XX_GPB2_EINT_G1_10                (0x07 << 8)
-
-#define S3C64XX_GPB3_UART_TXD3         (0x02 << 12)
-#define S3C64XX_GPB3_IrDA_TXD          (0x03 << 12)
-#define S3C64XX_GPB3_EXTDMA_ACK                (0x04 << 12)
-#define S3C64XX_GPB3_I2C_SDA1          (0x06 << 12)
-#define S3C64XX_GPB3_EINT_G1_11                (0x07 << 12)
-
-#define S3C64XX_GPB4_IrDA_SDBW         (0x02 << 16)
-#define S3C64XX_GPB4_CAM_FIELD         (0x03 << 16)
-#define S3C64XX_GPB4_CF_DATA_DIR       (0x04 << 16)
-#define S3C64XX_GPB4_EINT_G1_12                (0x07 << 16)
-
-#define S3C64XX_GPB5_I2C_SCL0          (0x02 << 20)
-#define S3C64XX_GPB5_EINT_G1_13                (0x07 << 20)
-
-#define S3C64XX_GPB6_I2C_SDA0          (0x02 << 24)
-#define S3C64XX_GPB6_EINT_G1_14                (0x07 << 24)
-
diff --git a/arch/arm/mach-s3c64xx/include/mach/gpio-bank-c.h b/arch/arm/mach-s3c64xx/include/mach/gpio-bank-c.h
deleted file mode 100644 (file)
index db189ab..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* linux/arch/arm/mach-s3c64xx/include/mach/gpio-bank-c.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * GPIO Bank C register and configuration definitions
- *
- * 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.
-*/
-
-#define S3C64XX_GPCCON                 (S3C64XX_GPC_BASE + 0x00)
-#define S3C64XX_GPCDAT                 (S3C64XX_GPC_BASE + 0x04)
-#define S3C64XX_GPCPUD                 (S3C64XX_GPC_BASE + 0x08)
-#define S3C64XX_GPCCONSLP              (S3C64XX_GPC_BASE + 0x0c)
-#define S3C64XX_GPCPUDSLP              (S3C64XX_GPC_BASE + 0x10)
-
-#define S3C64XX_GPC_CONMASK(__gpio)    (0xf << ((__gpio) * 4))
-#define S3C64XX_GPC_INPUT(__gpio)      (0x0 << ((__gpio) * 4))
-#define S3C64XX_GPC_OUTPUT(__gpio)     (0x1 << ((__gpio) * 4))
-
-#define S3C64XX_GPC0_SPI_MISO0         (0x02 << 0)
-#define S3C64XX_GPC0_EINT_G2_0         (0x07 << 0)
-
-#define S3C64XX_GPC1_SPI_CLKO          (0x02 << 4)
-#define S3C64XX_GPC1_EINT_G2_1         (0x07 << 4)
-
-#define S3C64XX_GPC2_SPI_MOSIO         (0x02 << 8)
-#define S3C64XX_GPC2_EINT_G2_2         (0x07 << 8)
-
-#define S3C64XX_GPC3_SPI_nCSO          (0x02 << 12)
-#define S3C64XX_GPC3_EINT_G2_3         (0x07 << 12)
-
-#define S3C64XX_GPC4_SPI_MISO1         (0x02 << 16)
-#define S3C64XX_GPC4_MMC2_CMD          (0x03 << 16)
-#define S3C64XX_GPC4_I2S_V40_DO0       (0x05 << 16)
-#define S3C64XX_GPC4_EINT_G2_4         (0x07 << 16)
-
-#define S3C64XX_GPC5_SPI_CLK1          (0x02 << 20)
-#define S3C64XX_GPC5_MMC2_CLK          (0x03 << 20)
-#define S3C64XX_GPC5_I2S_V40_DO1       (0x05 << 20)
-#define S3C64XX_GPC5_EINT_G2_5         (0x07 << 20)
-
-#define S3C64XX_GPC6_SPI_MOSI1         (0x02 << 24)
-#define S3C64XX_GPC6_EINT_G2_6         (0x07 << 24)
-
-#define S3C64XX_GPC7_SPI_nCS1          (0x02 << 28)
-#define S3C64XX_GPC7_I2S_V40_DO2       (0x05 << 28)
-#define S3C64XX_GPC7_EINT_G2_7         (0x07 << 28)
-
diff --git a/arch/arm/mach-s3c64xx/include/mach/gpio-bank-d.h b/arch/arm/mach-s3c64xx/include/mach/gpio-bank-d.h
deleted file mode 100644 (file)
index 1a01cee..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* linux/arch/arm/mach-s3c64xx/include/mach/gpio-bank-d.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * GPIO Bank D register and configuration definitions
- *
- * 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.
-*/
-
-#define S3C64XX_GPDCON                 (S3C64XX_GPD_BASE + 0x00)
-#define S3C64XX_GPDDAT                 (S3C64XX_GPD_BASE + 0x04)
-#define S3C64XX_GPDPUD                 (S3C64XX_GPD_BASE + 0x08)
-#define S3C64XX_GPDCONSLP              (S3C64XX_GPD_BASE + 0x0c)
-#define S3C64XX_GPDPUDSLP              (S3C64XX_GPD_BASE + 0x10)
-
-#define S3C64XX_GPD_CONMASK(__gpio)    (0xf << ((__gpio) * 4))
-#define S3C64XX_GPD_INPUT(__gpio)      (0x0 << ((__gpio) * 4))
-#define S3C64XX_GPD_OUTPUT(__gpio)     (0x1 << ((__gpio) * 4))
-
-#define S3C64XX_GPD0_PCM0_SCLK         (0x02 << 0)
-#define S3C64XX_GPD0_I2S0_CLK          (0x03 << 0)
-#define S3C64XX_GPD0_AC97_BITCLK       (0x04 << 0)
-#define S3C64XX_GPD0_EINT_G3_0         (0x07 << 0)
-
-#define S3C64XX_GPD1_PCM0_EXTCLK       (0x02 << 4)
-#define S3C64XX_GPD1_I2S0_CDCLK                (0x03 << 4)
-#define S3C64XX_GPD1_AC97_nRESET       (0x04 << 4)
-#define S3C64XX_GPD1_EINT_G3_1         (0x07 << 4)
-
-#define S3C64XX_GPD2_PCM0_FSYNC                (0x02 << 8)
-#define S3C64XX_GPD2_I2S0_LRCLK                (0x03 << 8)
-#define S3C64XX_GPD2_AC97_SYNC         (0x04 << 8)
-#define S3C64XX_GPD2_EINT_G3_2         (0x07 << 8)
-
-#define S3C64XX_GPD3_PCM0_SIN          (0x02 << 12)
-#define S3C64XX_GPD3_I2S0_DI           (0x03 << 12)
-#define S3C64XX_GPD3_AC97_SDI          (0x04 << 12)
-#define S3C64XX_GPD3_EINT_G3_3         (0x07 << 12)
-
-#define S3C64XX_GPD4_PCM0_SOUT         (0x02 << 16)
-#define S3C64XX_GPD4_I2S0_D0           (0x03 << 16)
-#define S3C64XX_GPD4_AC97_SDO          (0x04 << 16)
-#define S3C64XX_GPD4_EINT_G3_4         (0x07 << 16)
-
diff --git a/arch/arm/mach-s3c64xx/include/mach/gpio-bank-e.h b/arch/arm/mach-s3c64xx/include/mach/gpio-bank-e.h
deleted file mode 100644 (file)
index f057adb..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* linux/arch/arm/mach-s3c64xx/include/mach/gpio-bank-e.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * GPIO Bank E register and configuration definitions
- *
- * 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.
-*/
-
-#define S3C64XX_GPECON                 (S3C64XX_GPE_BASE + 0x00)
-#define S3C64XX_GPEDAT                 (S3C64XX_GPE_BASE + 0x04)
-#define S3C64XX_GPEPUD                 (S3C64XX_GPE_BASE + 0x08)
-#define S3C64XX_GPECONSLP              (S3C64XX_GPE_BASE + 0x0c)
-#define S3C64XX_GPEPUDSLP              (S3C64XX_GPE_BASE + 0x10)
-
-#define S3C64XX_GPE_CONMASK(__gpio)    (0xf << ((__gpio) * 4))
-#define S3C64XX_GPE_INPUT(__gpio)      (0x0 << ((__gpio) * 4))
-#define S3C64XX_GPE_OUTPUT(__gpio)     (0x1 << ((__gpio) * 4))
-
-#define S3C64XX_GPE0_PCM1_SCLK         (0x02 << 0)
-#define S3C64XX_GPE0_I2S1_CLK          (0x03 << 0)
-#define S3C64XX_GPE0_AC97_BITCLK       (0x04 << 0)
-
-#define S3C64XX_GPE1_PCM1_EXTCLK       (0x02 << 4)
-#define S3C64XX_GPE1_I2S1_CDCLK                (0x03 << 4)
-#define S3C64XX_GPE1_AC97_nRESET       (0x04 << 4)
-
-#define S3C64XX_GPE2_PCM1_FSYNC                (0x02 << 8)
-#define S3C64XX_GPE2_I2S1_LRCLK                (0x03 << 8)
-#define S3C64XX_GPE2_AC97_SYNC         (0x04 << 8)
-
-#define S3C64XX_GPE3_PCM1_SIN          (0x02 << 12)
-#define S3C64XX_GPE3_I2S1_DI           (0x03 << 12)
-#define S3C64XX_GPE3_AC97_SDI          (0x04 << 12)
-
-#define S3C64XX_GPE4_PCM1_SOUT         (0x02 << 16)
-#define S3C64XX_GPE4_I2S1_D0           (0x03 << 16)
-#define S3C64XX_GPE4_AC97_SDO          (0x04 << 16)
-
diff --git a/arch/arm/mach-s3c64xx/include/mach/gpio-bank-f.h b/arch/arm/mach-s3c64xx/include/mach/gpio-bank-f.h
deleted file mode 100644 (file)
index 62ab8f5..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/* linux/arch/arm/mach-s3c64xx/include/mach/gpio-bank-f.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * GPIO Bank F register and configuration definitions
- *
- * 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.
-*/
-
-#define S3C64XX_GPFCON                 (S3C64XX_GPF_BASE + 0x00)
-#define S3C64XX_GPFDAT                 (S3C64XX_GPF_BASE + 0x04)
-#define S3C64XX_GPFPUD                 (S3C64XX_GPF_BASE + 0x08)
-#define S3C64XX_GPFCONSLP              (S3C64XX_GPF_BASE + 0x0c)
-#define S3C64XX_GPFPUDSLP              (S3C64XX_GPF_BASE + 0x10)
-
-#define S3C64XX_GPF_CONMASK(__gpio)    (0x3 << ((__gpio) * 2))
-#define S3C64XX_GPF_INPUT(__gpio)      (0x0 << ((__gpio) * 2))
-#define S3C64XX_GPF_OUTPUT(__gpio)     (0x1 << ((__gpio) * 2))
-
-#define S3C64XX_GPF0_CAMIF_CLK         (0x02 << 0)
-#define S3C64XX_GPF0_EINT_G4_0         (0x03 << 0)
-
-#define S3C64XX_GPF1_CAMIF_HREF                (0x02 << 2)
-#define S3C64XX_GPF1_EINT_G4_1         (0x03 << 2)
-
-#define S3C64XX_GPF2_CAMIF_PCLK                (0x02 << 4)
-#define S3C64XX_GPF2_EINT_G4_2         (0x03 << 4)
-
-#define S3C64XX_GPF3_CAMIF_nRST                (0x02 << 6)
-#define S3C64XX_GPF3_EINT_G4_3         (0x03 << 6)
-
-#define S3C64XX_GPF4_CAMIF_VSYNC       (0x02 << 8)
-#define S3C64XX_GPF4_EINT_G4_4         (0x03 << 8)
-
-#define S3C64XX_GPF5_CAMIF_YDATA0      (0x02 << 10)
-#define S3C64XX_GPF5_EINT_G4_5         (0x03 << 10)
-
-#define S3C64XX_GPF6_CAMIF_YDATA1      (0x02 << 12)
-#define S3C64XX_GPF6_EINT_G4_6         (0x03 << 12)
-
-#define S3C64XX_GPF7_CAMIF_YDATA2      (0x02 << 14)
-#define S3C64XX_GPF7_EINT_G4_7         (0x03 << 14)
-
-#define S3C64XX_GPF8_CAMIF_YDATA3      (0x02 << 16)
-#define S3C64XX_GPF8_EINT_G4_8         (0x03 << 16)
-
-#define S3C64XX_GPF9_CAMIF_YDATA4      (0x02 << 18)
-#define S3C64XX_GPF9_EINT_G4_9         (0x03 << 18)
-
-#define S3C64XX_GPF10_CAMIF_YDATA5     (0x02 << 20)
-#define S3C64XX_GPF10_EINT_G4_10       (0x03 << 20)
-
-#define S3C64XX_GPF11_CAMIF_YDATA6     (0x02 << 22)
-#define S3C64XX_GPF11_EINT_G4_11       (0x03 << 22)
-
-#define S3C64XX_GPF12_CAMIF_YDATA7     (0x02 << 24)
-#define S3C64XX_GPF12_EINT_G4_12       (0x03 << 24)
-
-#define S3C64XX_GPF13_PWM_ECLK         (0x02 << 26)
-#define S3C64XX_GPF13_EINT_G4_13       (0x03 << 26)
-
-#define S3C64XX_GPF14_PWM_TOUT0                (0x02 << 28)
-#define S3C64XX_GPF14_CLKOUT0          (0x03 << 28)
-
-#define S3C64XX_GPF15_PWM_TOUT1                (0x02 << 30)
-
diff --git a/arch/arm/mach-s3c64xx/include/mach/gpio-bank-g.h b/arch/arm/mach-s3c64xx/include/mach/gpio-bank-g.h
deleted file mode 100644 (file)
index b94954a..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/* linux/arch/arm/mach-s3c64xx/include/mach/gpio-bank-g.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * GPIO Bank G register and configuration definitions
- *
- * 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.
-*/
-
-#define S3C64XX_GPGCON                 (S3C64XX_GPG_BASE + 0x00)
-#define S3C64XX_GPGDAT                 (S3C64XX_GPG_BASE + 0x04)
-#define S3C64XX_GPGPUD                 (S3C64XX_GPG_BASE + 0x08)
-#define S3C64XX_GPGCONSLP              (S3C64XX_GPG_BASE + 0x0c)
-#define S3C64XX_GPGPUDSLP              (S3C64XX_GPG_BASE + 0x10)
-
-#define S3C64XX_GPG_CONMASK(__gpio)    (0xf << ((__gpio) * 4))
-#define S3C64XX_GPG_INPUT(__gpio)      (0x0 << ((__gpio) * 4))
-#define S3C64XX_GPG_OUTPUT(__gpio)     (0x1 << ((__gpio) * 4))
-
-#define S3C64XX_GPG0_MMC0_CLK          (0x02 << 0)
-#define S3C64XX_GPG0_EINT_G5_0         (0x07 << 0)
-
-#define S3C64XX_GPG1_MMC0_CMD          (0x02 << 4)
-#define S3C64XX_GPG1_EINT_G5_1         (0x07 << 4)
-
-#define S3C64XX_GPG2_MMC0_DATA0                (0x02 << 8)
-#define S3C64XX_GPG2_EINT_G5_2         (0x07 << 8)
-
-#define S3C64XX_GPG3_MMC0_DATA1                (0x02 << 12)
-#define S3C64XX_GPG3_EINT_G5_3         (0x07 << 12)
-
-#define S3C64XX_GPG4_MMC0_DATA2                (0x02 << 16)
-#define S3C64XX_GPG4_EINT_G5_4         (0x07 << 16)
-
-#define S3C64XX_GPG5_MMC0_DATA3                (0x02 << 20)
-#define S3C64XX_GPG5_EINT_G5_5         (0x07 << 20)
-
diff --git a/arch/arm/mach-s3c64xx/include/mach/gpio-bank-h.h b/arch/arm/mach-s3c64xx/include/mach/gpio-bank-h.h
deleted file mode 100644 (file)
index 5d75aaa..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/* linux/arch/arm/mach-s3c64xx/include/mach/gpio-bank-h.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * GPIO Bank H register and configuration definitions
- *
- * 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.
-*/
-
-#define S3C64XX_GPHCON0                        (S3C64XX_GPH_BASE + 0x00)
-#define S3C64XX_GPHCON1                        (S3C64XX_GPH_BASE + 0x04)
-#define S3C64XX_GPHDAT                 (S3C64XX_GPH_BASE + 0x08)
-#define S3C64XX_GPHPUD                 (S3C64XX_GPH_BASE + 0x0c)
-#define S3C64XX_GPHCONSLP              (S3C64XX_GPH_BASE + 0x10)
-#define S3C64XX_GPHPUDSLP              (S3C64XX_GPH_BASE + 0x14)
-
-#define S3C64XX_GPH_CONMASK(__gpio)    (0xf << ((__gpio) * 4))
-#define S3C64XX_GPH_INPUT(__gpio)      (0x0 << ((__gpio) * 4))
-#define S3C64XX_GPH_OUTPUT(__gpio)     (0x1 << ((__gpio) * 4))
-
-#define S3C64XX_GPH0_MMC1_CLK          (0x02 << 0)
-#define S3C64XX_GPH0_KP_COL0           (0x04 << 0)
-#define S3C64XX_GPH0_EINT_G6_0         (0x07 << 0)
-
-#define S3C64XX_GPH1_MMC1_CMD          (0x02 << 4)
-#define S3C64XX_GPH1_KP_COL1           (0x04 << 4)
-#define S3C64XX_GPH1_EINT_G6_1         (0x07 << 4)
-
-#define S3C64XX_GPH2_MMC1_DATA0                (0x02 << 8)
-#define S3C64XX_GPH2_KP_COL2           (0x04 << 8)
-#define S3C64XX_GPH2_EINT_G6_2         (0x07 << 8)
-
-#define S3C64XX_GPH3_MMC1_DATA1                (0x02 << 12)
-#define S3C64XX_GPH3_KP_COL3           (0x04 << 12)
-#define S3C64XX_GPH3_EINT_G6_3         (0x07 << 12)
-
-#define S3C64XX_GPH4_MMC1_DATA2                (0x02 << 16)
-#define S3C64XX_GPH4_KP_COL4           (0x04 << 16)
-#define S3C64XX_GPH4_EINT_G6_4         (0x07 << 16)
-
-#define S3C64XX_GPH5_MMC1_DATA3                (0x02 << 20)
-#define S3C64XX_GPH5_KP_COL5           (0x04 << 20)
-#define S3C64XX_GPH5_EINT_G6_5         (0x07 << 20)
-
-#define S3C64XX_GPH6_MMC1_DATA4                (0x02 << 24)
-#define S3C64XX_GPH6_MMC2_DATA0                (0x03 << 24)
-#define S3C64XX_GPH6_KP_COL6           (0x04 << 24)
-#define S3C64XX_GPH6_I2S_V40_BCLK      (0x05 << 24)
-#define S3C64XX_GPH6_ADDR_CF0          (0x06 << 24)
-#define S3C64XX_GPH6_EINT_G6_6         (0x07 << 24)
-
-#define S3C64XX_GPH7_MMC1_DATA5                (0x02 << 28)
-#define S3C64XX_GPH7_MMC2_DATA1                (0x03 << 28)
-#define S3C64XX_GPH7_KP_COL7           (0x04 << 28)
-#define S3C64XX_GPH7_I2S_V40_CDCLK     (0x05 << 28)
-#define S3C64XX_GPH7_ADDR_CF1          (0x06 << 28)
-#define S3C64XX_GPH7_EINT_G6_7         (0x07 << 28)
-
-#define S3C64XX_GPH8_MMC1_DATA6                (0x02 <<  0)
-#define S3C64XX_GPH8_MMC2_DATA2                (0x03 <<  0)
-#define S3C64XX_GPH8_I2S_V40_LRCLK     (0x05 <<  0)
-#define S3C64XX_GPH8_ADDR_CF2          (0x06 <<  0)
-#define S3C64XX_GPH8_EINT_G6_8         (0x07 <<  0)
-
-#define S3C64XX_GPH9_OUTPUT            (0x01 <<  4)
-#define S3C64XX_GPH9_MMC1_DATA7                (0x02 <<  4)
-#define S3C64XX_GPH9_MMC2_DATA3                (0x03 <<  4)
-#define S3C64XX_GPH9_I2S_V40_DI                (0x05 <<  4)
-#define S3C64XX_GPH9_EINT_G6_9         (0x07 <<  4)
diff --git a/arch/arm/mach-s3c64xx/include/mach/gpio-bank-i.h b/arch/arm/mach-s3c64xx/include/mach/gpio-bank-i.h
deleted file mode 100644 (file)
index 4ceaa60..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* linux/arch/arm/mach-s3c64xx/include/mach/gpio-bank-i.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * GPIO Bank I register and configuration definitions
- *
- * 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.
-*/
-
-#define S3C64XX_GPICON                 (S3C64XX_GPI_BASE + 0x00)
-#define S3C64XX_GPIDAT                 (S3C64XX_GPI_BASE + 0x04)
-#define S3C64XX_GPIPUD                 (S3C64XX_GPI_BASE + 0x08)
-#define S3C64XX_GPICONSLP              (S3C64XX_GPI_BASE + 0x0c)
-#define S3C64XX_GPIPUDSLP              (S3C64XX_GPI_BASE + 0x10)
-
-#define S3C64XX_GPI_CONMASK(__gpio)    (0x3 << ((__gpio) * 2))
-#define S3C64XX_GPI_INPUT(__gpio)      (0x0 << ((__gpio) * 2))
-#define S3C64XX_GPI_OUTPUT(__gpio)     (0x1 << ((__gpio) * 2))
-
-#define S3C64XX_GPI0_VD0               (0x02 << 0)
-#define S3C64XX_GPI1_VD1               (0x02 << 2)
-#define S3C64XX_GPI2_VD2               (0x02 << 4)
-#define S3C64XX_GPI3_VD3               (0x02 << 6)
-#define S3C64XX_GPI4_VD4               (0x02 << 8)
-#define S3C64XX_GPI5_VD5               (0x02 << 10)
-#define S3C64XX_GPI6_VD6               (0x02 << 12)
-#define S3C64XX_GPI7_VD7               (0x02 << 14)
-#define S3C64XX_GPI8_VD8               (0x02 << 16)
-#define S3C64XX_GPI9_VD9               (0x02 << 18)
-#define S3C64XX_GPI10_VD10             (0x02 << 20)
-#define S3C64XX_GPI11_VD11             (0x02 << 22)
-#define S3C64XX_GPI12_VD12             (0x02 << 24)
-#define S3C64XX_GPI13_VD13             (0x02 << 26)
-#define S3C64XX_GPI14_VD14             (0x02 << 28)
-#define S3C64XX_GPI15_VD15             (0x02 << 30)
diff --git a/arch/arm/mach-s3c64xx/include/mach/gpio-bank-j.h b/arch/arm/mach-s3c64xx/include/mach/gpio-bank-j.h
deleted file mode 100644 (file)
index 6f25cd0..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* linux/arch/arm/mach-s3c64xx/include/mach/gpio-bank-j.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * GPIO Bank J register and configuration definitions
- *
- * 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.
-*/
-
-#define S3C64XX_GPJCON                 (S3C64XX_GPJ_BASE + 0x00)
-#define S3C64XX_GPJDAT                 (S3C64XX_GPJ_BASE + 0x04)
-#define S3C64XX_GPJPUD                 (S3C64XX_GPJ_BASE + 0x08)
-#define S3C64XX_GPJCONSLP              (S3C64XX_GPJ_BASE + 0x0c)
-#define S3C64XX_GPJPUDSLP              (S3C64XX_GPJ_BASE + 0x10)
-
-#define S3C64XX_GPJ_CONMASK(__gpio)    (0x3 << ((__gpio) * 2))
-#define S3C64XX_GPJ_INPUT(__gpio)      (0x0 << ((__gpio) * 2))
-#define S3C64XX_GPJ_OUTPUT(__gpio)     (0x1 << ((__gpio) * 2))
-
-#define S3C64XX_GPJ0_VD16              (0x02 << 0)
-#define S3C64XX_GPJ1_VD17              (0x02 << 2)
-#define S3C64XX_GPJ2_VD18              (0x02 << 4)
-#define S3C64XX_GPJ3_VD19              (0x02 << 6)
-#define S3C64XX_GPJ4_VD20              (0x02 << 8)
-#define S3C64XX_GPJ5_VD21              (0x02 << 10)
-#define S3C64XX_GPJ6_VD22              (0x02 << 12)
-#define S3C64XX_GPJ7_VD23              (0x02 << 14)
-#define S3C64XX_GPJ8_LCD_HSYNC         (0x02 << 16)
-#define S3C64XX_GPJ9_LCD_VSYNC         (0x02 << 18)
-#define S3C64XX_GPJ10_LCD_VDEN         (0x02 << 20)
-#define S3C64XX_GPJ11_LCD_VCLK         (0x02 << 22)
diff --git a/arch/arm/mach-s3c64xx/include/mach/gpio-bank-n.h b/arch/arm/mach-s3c64xx/include/mach/gpio-bank-n.h
deleted file mode 100644 (file)
index d0aeda1..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/* linux/arch/arm/mach-s3c64xx/include/mach/gpio-bank-n.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * GPIO Bank N register and configuration definitions
- *
- * 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.
-*/
-
-#define S3C64XX_GPNCON                 (S3C64XX_GPN_BASE + 0x00)
-#define S3C64XX_GPNDAT                 (S3C64XX_GPN_BASE + 0x04)
-#define S3C64XX_GPNPUD                 (S3C64XX_GPN_BASE + 0x08)
-
-#define S3C64XX_GPN_CONMASK(__gpio)    (0x3 << ((__gpio) * 2))
-#define S3C64XX_GPN_INPUT(__gpio)      (0x0 << ((__gpio) * 2))
-#define S3C64XX_GPN_OUTPUT(__gpio)     (0x1 << ((__gpio) * 2))
-
-#define S3C64XX_GPN0_EINT0             (0x02 << 0)
-#define S3C64XX_GPN0_KP_ROW0           (0x03 << 0)
-
-#define S3C64XX_GPN1_EINT1             (0x02 << 2)
-#define S3C64XX_GPN1_KP_ROW1           (0x03 << 2)
-
-#define S3C64XX_GPN2_EINT2             (0x02 << 4)
-#define S3C64XX_GPN2_KP_ROW2           (0x03 << 4)
-
-#define S3C64XX_GPN3_EINT3             (0x02 << 6)
-#define S3C64XX_GPN3_KP_ROW3           (0x03 << 6)
-
-#define S3C64XX_GPN4_EINT4             (0x02 << 8)
-#define S3C64XX_GPN4_KP_ROW4           (0x03 << 8)
-
-#define S3C64XX_GPN5_EINT5             (0x02 << 10)
-#define S3C64XX_GPN5_KP_ROW5           (0x03 << 10)
-
-#define S3C64XX_GPN6_EINT6             (0x02 << 12)
-#define S3C64XX_GPN6_KP_ROW6           (0x03 << 12)
-
-#define S3C64XX_GPN7_EINT7             (0x02 << 14)
-#define S3C64XX_GPN7_KP_ROW7           (0x03 << 14)
-
-#define S3C64XX_GPN8_EINT8             (0x02 << 16)
-#define S3C64XX_GPN9_EINT9             (0x02 << 18)
-#define S3C64XX_GPN10_EINT10           (0x02 << 20)
-#define S3C64XX_GPN11_EINT11           (0x02 << 22)
-#define S3C64XX_GPN12_EINT12           (0x02 << 24)
-#define S3C64XX_GPN13_EINT13           (0x02 << 26)
-#define S3C64XX_GPN14_EINT14           (0x02 << 28)
-#define S3C64XX_GPN15_EINT15           (0x02 << 30)
diff --git a/arch/arm/mach-s3c64xx/include/mach/gpio-bank-o.h b/arch/arm/mach-s3c64xx/include/mach/gpio-bank-o.h
deleted file mode 100644 (file)
index 21868fa..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* linux/arch/arm/mach-s3c64xx/include/mach/gpio-bank-o.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * GPIO Bank O register and configuration definitions
- *
- * 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.
-*/
-
-#define S3C64XX_GPOCON                 (S3C64XX_GPO_BASE + 0x00)
-#define S3C64XX_GPODAT                 (S3C64XX_GPO_BASE + 0x04)
-#define S3C64XX_GPOPUD                 (S3C64XX_GPO_BASE + 0x08)
-#define S3C64XX_GPOCONSLP              (S3C64XX_GPO_BASE + 0x0c)
-#define S3C64XX_GPOPUDSLP              (S3C64XX_GPO_BASE + 0x10)
-
-#define S3C64XX_GPO_CONMASK(__gpio)    (0x3 << ((__gpio) * 2))
-#define S3C64XX_GPO_INPUT(__gpio)      (0x0 << ((__gpio) * 2))
-#define S3C64XX_GPO_OUTPUT(__gpio)     (0x1 << ((__gpio) * 2))
-
-#define S3C64XX_GPO0_MEM0_nCS2         (0x02 << 0)
-#define S3C64XX_GPO0_EINT_G7_0         (0x03 << 0)
-
-#define S3C64XX_GPO1_MEM0_nCS3         (0x02 << 2)
-#define S3C64XX_GPO1_EINT_G7_1         (0x03 << 2)
-
-#define S3C64XX_GPO2_MEM0_nCS4         (0x02 << 4)
-#define S3C64XX_GPO2_EINT_G7_2         (0x03 << 4)
-
-#define S3C64XX_GPO3_MEM0_nCS5         (0x02 << 6)
-#define S3C64XX_GPO3_EINT_G7_3         (0x03 << 6)
-
-#define S3C64XX_GPO4_EINT_G7_4         (0x03 << 8)
-
-#define S3C64XX_GPO5_EINT_G7_5         (0x03 << 10)
-
-#define S3C64XX_GPO6_MEM0_ADDR6                (0x02 << 12)
-#define S3C64XX_GPO6_EINT_G7_6         (0x03 << 12)
-
-#define S3C64XX_GPO7_MEM0_ADDR7                (0x02 << 14)
-#define S3C64XX_GPO7_EINT_G7_7         (0x03 << 14)
-
-#define S3C64XX_GPO8_MEM0_ADDR8                (0x02 << 16)
-#define S3C64XX_GPO8_EINT_G7_8         (0x03 << 16)
-
-#define S3C64XX_GPO9_MEM0_ADDR9                (0x02 << 18)
-#define S3C64XX_GPO9_EINT_G7_9         (0x03 << 18)
-
-#define S3C64XX_GPO10_MEM0_ADDR10      (0x02 << 20)
-#define S3C64XX_GPO10_EINT_G7_10       (0x03 << 20)
-
-#define S3C64XX_GPO11_MEM0_ADDR11      (0x02 << 22)
-#define S3C64XX_GPO11_EINT_G7_11       (0x03 << 22)
-
-#define S3C64XX_GPO12_MEM0_ADDR12      (0x02 << 24)
-#define S3C64XX_GPO12_EINT_G7_12       (0x03 << 24)
-
-#define S3C64XX_GPO13_MEM0_ADDR13      (0x02 << 26)
-#define S3C64XX_GPO13_EINT_G7_13       (0x03 << 26)
-
-#define S3C64XX_GPO14_MEM0_ADDR14      (0x02 << 28)
-#define S3C64XX_GPO14_EINT_G7_14       (0x03 << 28)
-
-#define S3C64XX_GPO15_MEM0_ADDR15      (0x02 << 30)
-#define S3C64XX_GPO15_EINT_G7_15       (0x03 << 30)
-
diff --git a/arch/arm/mach-s3c64xx/include/mach/gpio-bank-p.h b/arch/arm/mach-s3c64xx/include/mach/gpio-bank-p.h
deleted file mode 100644 (file)
index 46bcfb6..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/* linux/arch/arm/mach-s3c64xx/include/mach/gpio-bank-p.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * GPIO Bank P register and configuration definitions
- *
- * 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.
-*/
-
-#define S3C64XX_GPPCON                 (S3C64XX_GPP_BASE + 0x00)
-#define S3C64XX_GPPDAT                 (S3C64XX_GPP_BASE + 0x04)
-#define S3C64XX_GPPPUD                 (S3C64XX_GPP_BASE + 0x08)
-#define S3C64XX_GPPCONSLP              (S3C64XX_GPP_BASE + 0x0c)
-#define S3C64XX_GPPPUDSLP              (S3C64XX_GPP_BASE + 0x10)
-
-#define S3C64XX_GPP_CONMASK(__gpio)    (0x3 << ((__gpio) * 2))
-#define S3C64XX_GPP_INPUT(__gpio)      (0x0 << ((__gpio) * 2))
-#define S3C64XX_GPP_OUTPUT(__gpio)     (0x1 << ((__gpio) * 2))
-
-#define S3C64XX_GPP0_MEM0_ADDRV                (0x02 << 0)
-#define S3C64XX_GPP0_EINT_G8_0         (0x03 << 0)
-
-#define S3C64XX_GPP1_MEM0_SMCLK                (0x02 << 2)
-#define S3C64XX_GPP1_EINT_G8_1         (0x03 << 2)
-
-#define S3C64XX_GPP2_MEM0_nWAIT                (0x02 << 4)
-#define S3C64XX_GPP2_EINT_G8_2         (0x03 << 4)
-
-#define S3C64XX_GPP3_MEM0_RDY0_ALE     (0x02 << 6)
-#define S3C64XX_GPP3_EINT_G8_3         (0x03 << 6)
-
-#define S3C64XX_GPP4_MEM0_RDY1_CLE     (0x02 << 8)
-#define S3C64XX_GPP4_EINT_G8_4         (0x03 << 8)
-
-#define S3C64XX_GPP5_MEM0_INTsm0_FWE   (0x02 << 10)
-#define S3C64XX_GPP5_EINT_G8_5         (0x03 << 10)
-
-#define S3C64XX_GPP6_MEM0_(null)       (0x02 << 12)
-#define S3C64XX_GPP6_EINT_G8_6         (0x03 << 12)
-
-#define S3C64XX_GPP7_MEM0_INTsm1_FRE   (0x02 << 14)
-#define S3C64XX_GPP7_EINT_G8_7         (0x03 << 14)
-
-#define S3C64XX_GPP8_MEM0_RPn_RnB      (0x02 << 16)
-#define S3C64XX_GPP8_EINT_G8_8         (0x03 << 16)
-
-#define S3C64XX_GPP9_MEM0_ATA_RESET    (0x02 << 18)
-#define S3C64XX_GPP9_EINT_G8_9         (0x03 << 18)
-
-#define S3C64XX_GPP10_MEM0_ATA_INPACK  (0x02 << 20)
-#define S3C64XX_GPP10_EINT_G8_10       (0x03 << 20)
-
-#define S3C64XX_GPP11_MEM0_ATA_REG     (0x02 << 22)
-#define S3C64XX_GPP11_EINT_G8_11       (0x03 << 22)
-
-#define S3C64XX_GPP12_MEM0_ATA_WE      (0x02 << 24)
-#define S3C64XX_GPP12_EINT_G8_12       (0x03 << 24)
-
-#define S3C64XX_GPP13_MEM0_ATA_OE      (0x02 << 26)
-#define S3C64XX_GPP13_EINT_G8_13       (0x03 << 26)
-
-#define S3C64XX_GPP14_MEM0_ATA_CD      (0x02 << 28)
-#define S3C64XX_GPP14_EINT_G8_14       (0x03 << 28)
-
diff --git a/arch/arm/mach-s3c64xx/include/mach/gpio-bank-q.h b/arch/arm/mach-s3c64xx/include/mach/gpio-bank-q.h
deleted file mode 100644 (file)
index 1712223..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/* linux/arch/arm/mach-s3c64xx/include/mach/gpio-bank-q.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * GPIO Bank Q register and configuration definitions
- *
- * 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.
-*/
-
-#define S3C64XX_GPQCON                 (S3C64XX_GPQ_BASE + 0x00)
-#define S3C64XX_GPQDAT                 (S3C64XX_GPQ_BASE + 0x04)
-#define S3C64XX_GPQPUD                 (S3C64XX_GPQ_BASE + 0x08)
-#define S3C64XX_GPQCONSLP              (S3C64XX_GPQ_BASE + 0x0c)
-#define S3C64XX_GPQPUDSLP              (S3C64XX_GPQ_BASE + 0x10)
-
-#define S3C64XX_GPQ_CONMASK(__gpio)    (0x3 << ((__gpio) * 2))
-#define S3C64XX_GPQ_INPUT(__gpio)      (0x0 << ((__gpio) * 2))
-#define S3C64XX_GPQ_OUTPUT(__gpio)     (0x1 << ((__gpio) * 2))
-
-#define S3C64XX_GPQ0_MEM0_ADDR18_RAS   (0x02 << 0)
-#define S3C64XX_GPQ0_EINT_G9_0         (0x03 << 0)
-
-#define S3C64XX_GPQ1_MEM0_ADDR19_CAS   (0x02 << 2)
-#define S3C64XX_GPQ1_EINT_G9_1         (0x03 << 2)
-
-#define S3C64XX_GPQ2_EINT_G9_2         (0x03 << 4)
-
-#define S3C64XX_GPQ3_EINT_G9_3         (0x03 << 6)
-
-#define S3C64XX_GPQ4_EINT_G9_4         (0x03 << 8)
-
-#define S3C64XX_GPQ5_EINT_G9_5         (0x03 << 10)
-
-#define S3C64XX_GPQ6_EINT_G9_6         (0x03 << 12)
-
-#define S3C64XX_GPQ7_MEM0_ADDR17_WENDMC        (0x02 << 14)
-#define S3C64XX_GPQ7_EINT_G9_7         (0x03 << 14)
-
-#define S3C64XX_GPQ8_MEM0_ADDR16_APDMC (0x02 << 16)
-#define S3C64XX_GPQ8_EINT_G9_8         (0x03 << 16)
-
index 686a4f270b123d6d1d2372298cfde9e8f69b248f..2c0353a809061115b046244719d9aeb3f71e6e95 100644 (file)
@@ -50,7 +50,6 @@
 #include <mach/hardware.h>
 #include <mach/regs-fb.h>
 #include <mach/map.h>
-#include <mach/gpio-bank-f.h>
 
 #include <asm/irq.h>
 #include <asm/mach-types.h>
index 79412f735a8da99aecd222574cd6cae0c9799f65..bc1c470b7de69becd4a096e4551b3c2f74e374cd 100644 (file)
 #include <mach/regs-gpio-memport.h>
 
 #ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
-#include <mach/gpio-bank-n.h>
-
 void s3c_pm_debug_smdkled(u32 set, u32 clear)
 {
        unsigned long flags;
-       u32 reg;
+       int i;
 
        local_irq_save(flags);
-       reg = __raw_readl(S3C64XX_GPNCON);
-       reg &= ~(S3C64XX_GPN_CONMASK(12) | S3C64XX_GPN_CONMASK(13) |
-                S3C64XX_GPN_CONMASK(14) | S3C64XX_GPN_CONMASK(15));
-       reg |= S3C64XX_GPN_OUTPUT(12) | S3C64XX_GPN_OUTPUT(13) |
-              S3C64XX_GPN_OUTPUT(14) | S3C64XX_GPN_OUTPUT(15);
-       __raw_writel(reg, S3C64XX_GPNCON);
-
-       reg = __raw_readl(S3C64XX_GPNDAT);
-       reg &= ~(clear << 12);
-       reg |= set << 12;
-       __raw_writel(reg, S3C64XX_GPNDAT);
-
+       for (i = 0; i < 4; i++) {
+               if (clear & (1 << i))
+                       gpio_set_value(S3C64XX_GPN(12 + i), 0);
+               if (set & (1 << i))
+                       gpio_set_value(S3C64XX_GPN(12 + i), 1);
+       }
        local_irq_restore(flags);
 }
 #endif
@@ -187,6 +179,18 @@ static int s3c64xx_pm_init(void)
        pm_cpu_prep = s3c64xx_pm_prepare;
        pm_cpu_sleep = s3c64xx_cpu_suspend;
        pm_uart_udivslot = 1;
+
+#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
+       gpio_request(S3C64XX_GPN(12), "DEBUG_LED0");
+       gpio_request(S3C64XX_GPN(13), "DEBUG_LED1");
+       gpio_request(S3C64XX_GPN(14), "DEBUG_LED2");
+       gpio_request(S3C64XX_GPN(15), "DEBUG_LED3");
+       gpio_direction_output(S3C64XX_GPN(12), 0);
+       gpio_direction_output(S3C64XX_GPN(13), 0);
+       gpio_direction_output(S3C64XX_GPN(14), 0);
+       gpio_direction_output(S3C64XX_GPN(15), 0);
+#endif
+
        return 0;
 }
 
index 406192a43c6e6fc711e6db1294bfb9a24c875489..241af94a9e7012dfb213cf6bec7de2f64bbc0d4f 100644 (file)
 
 struct platform_device; /* don't need the contents */
 
-#include <mach/gpio-bank-b.h>
 #include <plat/iic.h>
 #include <plat/gpio-cfg.h>
 
 void s3c_i2c0_cfg_gpio(struct platform_device *dev)
 {
-       s3c_gpio_cfgpin(S3C64XX_GPB(5), S3C64XX_GPB5_I2C_SCL0);
-       s3c_gpio_cfgpin(S3C64XX_GPB(6), S3C64XX_GPB6_I2C_SDA0);
-       s3c_gpio_setpull(S3C64XX_GPB(5), S3C_GPIO_PULL_UP);
-       s3c_gpio_setpull(S3C64XX_GPB(6), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgall_range(S3C64XX_GPB(5), 2,
+                             S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
 }
index 1ee62c97cd7fc098f8908d56e18236910127ed6c..3d13a961986d2b9a5131586c462d7dda48f8940c 100644 (file)
 
 struct platform_device; /* don't need the contents */
 
-#include <mach/gpio-bank-b.h>
 #include <plat/iic.h>
 #include <plat/gpio-cfg.h>
 
 void s3c_i2c1_cfg_gpio(struct platform_device *dev)
 {
-       s3c_gpio_cfgpin(S3C64XX_GPB(2), S3C64XX_GPB2_I2C_SCL1);
-       s3c_gpio_cfgpin(S3C64XX_GPB(3), S3C64XX_GPB3_I2C_SDA1);
-       s3c_gpio_setpull(S3C64XX_GPB(2), S3C_GPIO_PULL_UP);
-       s3c_gpio_setpull(S3C64XX_GPB(3), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgall_range(S3C64XX_GPB(2), 2,
+                             S3C_GPIO_SFN(6), S3C_GPIO_PULL_UP);
 }
index afe5a762f46e7cc48e4d5b704bf07c8cc04ca514..1f87732b23206daa964f4af30eaf62c94dd73617 100644 (file)
@@ -20,7 +20,6 @@
 #define S3C64XX_VA_GPIO (0x0)
 
 #include <mach/regs-gpio.h>
-#include <mach/gpio-bank-n.h>
 
 #define LL_UART (S3C_PA_UART + (0x400 * CONFIG_S3C_LOWLEVEL_UART_PORT))
 
@@ -68,6 +67,13 @@ ENTRY(s3c_cpu_resume)
        ldr     r2, =LL_UART            /* for debug */
 
 #ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
+
+#define S3C64XX_GPNCON                 (S3C64XX_GPN_BASE + 0x00)
+#define S3C64XX_GPNDAT                 (S3C64XX_GPN_BASE + 0x04)
+
+#define S3C64XX_GPN_CONMASK(__gpio)    (0x3 << ((__gpio) * 2))
+#define S3C64XX_GPN_OUTPUT(__gpio)     (0x1 << ((__gpio) * 2))
+
        /* Initialise the GPIO state if we are debugging via the SMDK LEDs,
         * as the uboot version supplied resets these to inputs during the
         * resume checks.
diff --git a/arch/arm/mach-s5p6442/Kconfig b/arch/arm/mach-s5p6442/Kconfig
deleted file mode 100644 (file)
index 33569e4..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# arch/arm/mach-s5p6442/Kconfig
-#
-# Copyright (c) 2010 Samsung Electronics Co., Ltd.
-#              http://www.samsung.com/
-#
-# Licensed under GPLv2
-
-# Configuration options for the S5P6442
-
-if ARCH_S5P6442
-
-config CPU_S5P6442
-       bool
-       select S3C_PL330_DMA
-       help
-         Enable S5P6442 CPU support
-
-config MACH_SMDK6442
-       bool "SMDK6442"
-       select CPU_S5P6442
-       select S3C_DEV_WDT
-       help
-         Machine support for Samsung SMDK6442
-
-endif
diff --git a/arch/arm/mach-s5p6442/Makefile b/arch/arm/mach-s5p6442/Makefile
deleted file mode 100644 (file)
index 90a3d83..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-# arch/arm/mach-s5p6442/Makefile
-#
-# Copyright (c) 2010 Samsung Electronics Co., Ltd.
-#              http://www.samsung.com/
-#
-# Licensed under GPLv2
-
-obj-y                          :=
-obj-m                          :=
-obj-n                          :=
-obj-                           :=
-
-# Core support for S5P6442 system
-
-obj-$(CONFIG_CPU_S5P6442)      += cpu.o init.o clock.o dma.o
-obj-$(CONFIG_CPU_S5P6442)      += setup-i2c0.o
-
-# machine support
-
-obj-$(CONFIG_MACH_SMDK6442)    += mach-smdk6442.o
-
-# device support
-obj-y                          += dev-audio.o
-obj-$(CONFIG_S3C64XX_DEV_SPI)  += dev-spi.o
diff --git a/arch/arm/mach-s5p6442/Makefile.boot b/arch/arm/mach-s5p6442/Makefile.boot
deleted file mode 100644 (file)
index ff90aa1..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-   zreladdr-y  := 0x20008000
-params_phys-y  := 0x20000100
diff --git a/arch/arm/mach-s5p6442/clock.c b/arch/arm/mach-s5p6442/clock.c
deleted file mode 100644 (file)
index fbbc7be..0000000
+++ /dev/null
@@ -1,420 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/clock.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5P6442 - Clock 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.
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <mach/map.h>
-
-#include <plat/cpu-freq.h>
-#include <mach/regs-clock.h>
-#include <plat/clock.h>
-#include <plat/cpu.h>
-#include <plat/pll.h>
-#include <plat/s5p-clock.h>
-#include <plat/clock-clksrc.h>
-#include <plat/s5p6442.h>
-
-static struct clksrc_clk clk_mout_apll = {
-       .clk    = {
-               .name           = "mout_apll",
-               .id             = -1,
-       },
-       .sources        = &clk_src_apll,
-       .reg_src        = { .reg = S5P_CLK_SRC0, .shift = 0, .size = 1 },
-};
-
-static struct clksrc_clk clk_mout_mpll = {
-       .clk = {
-               .name           = "mout_mpll",
-               .id             = -1,
-       },
-       .sources        = &clk_src_mpll,
-       .reg_src        = { .reg = S5P_CLK_SRC0, .shift = 4, .size = 1 },
-};
-
-static struct clksrc_clk clk_mout_epll = {
-       .clk    = {
-               .name           = "mout_epll",
-               .id             = -1,
-       },
-       .sources        = &clk_src_epll,
-       .reg_src        = { .reg = S5P_CLK_SRC0, .shift = 8, .size = 1 },
-};
-
-/* Possible clock sources for ARM Mux */
-static struct clk *clk_src_arm_list[] = {
-       [1] = &clk_mout_apll.clk,
-       [2] = &clk_mout_mpll.clk,
-};
-
-static struct clksrc_sources clk_src_arm = {
-       .sources        = clk_src_arm_list,
-       .nr_sources     = ARRAY_SIZE(clk_src_arm_list),
-};
-
-static struct clksrc_clk clk_mout_arm = {
-       .clk    = {
-               .name           = "mout_arm",
-               .id             = -1,
-       },
-       .sources        = &clk_src_arm,
-       .reg_src        = { .reg = S5P_CLK_MUX_STAT0, .shift = 16, .size = 3 },
-};
-
-static struct clk clk_dout_a2m = {
-       .name           = "dout_a2m",
-       .id             = -1,
-       .parent         = &clk_mout_apll.clk,
-};
-
-/* Possible clock sources for D0 Mux */
-static struct clk *clk_src_d0_list[] = {
-       [1] = &clk_mout_mpll.clk,
-       [2] = &clk_dout_a2m,
-};
-
-static struct clksrc_sources clk_src_d0 = {
-       .sources        = clk_src_d0_list,
-       .nr_sources     = ARRAY_SIZE(clk_src_d0_list),
-};
-
-static struct clksrc_clk clk_mout_d0 = {
-       .clk = {
-               .name           = "mout_d0",
-               .id             = -1,
-       },
-       .sources        = &clk_src_d0,
-       .reg_src        = { .reg = S5P_CLK_MUX_STAT0, .shift = 20, .size = 3 },
-};
-
-static struct clk clk_dout_apll = {
-       .name           = "dout_apll",
-       .id             = -1,
-       .parent         = &clk_mout_arm.clk,
-};
-
-/* Possible clock sources for D0SYNC Mux */
-static struct clk *clk_src_d0sync_list[] = {
-       [1] = &clk_mout_d0.clk,
-       [2] = &clk_dout_apll,
-};
-
-static struct clksrc_sources clk_src_d0sync = {
-       .sources        = clk_src_d0sync_list,
-       .nr_sources     = ARRAY_SIZE(clk_src_d0sync_list),
-};
-
-static struct clksrc_clk clk_mout_d0sync = {
-       .clk    = {
-               .name           = "mout_d0sync",
-               .id             = -1,
-       },
-       .sources        = &clk_src_d0sync,
-       .reg_src        = { .reg = S5P_CLK_MUX_STAT1, .shift = 28, .size = 3 },
-};
-
-/* Possible clock sources for D1 Mux */
-static struct clk *clk_src_d1_list[] = {
-       [1] = &clk_mout_mpll.clk,
-       [2] = &clk_dout_a2m,
-};
-
-static struct clksrc_sources clk_src_d1 = {
-       .sources        = clk_src_d1_list,
-       .nr_sources     = ARRAY_SIZE(clk_src_d1_list),
-};
-
-static struct clksrc_clk clk_mout_d1 = {
-       .clk    = {
-               .name           = "mout_d1",
-               .id             = -1,
-       },
-       .sources        = &clk_src_d1,
-       .reg_src        = { .reg = S5P_CLK_MUX_STAT0, .shift = 24, .size = 3 },
-};
-
-/* Possible clock sources for D1SYNC Mux */
-static struct clk *clk_src_d1sync_list[] = {
-       [1] = &clk_mout_d1.clk,
-       [2] = &clk_dout_apll,
-};
-
-static struct clksrc_sources clk_src_d1sync = {
-       .sources        = clk_src_d1sync_list,
-       .nr_sources     = ARRAY_SIZE(clk_src_d1sync_list),
-};
-
-static struct clksrc_clk clk_mout_d1sync = {
-       .clk    = {
-               .name           = "mout_d1sync",
-               .id             = -1,
-       },
-       .sources        = &clk_src_d1sync,
-       .reg_src        = { .reg = S5P_CLK_MUX_STAT1, .shift = 24, .size = 3 },
-};
-
-static struct clk clk_hclkd0 = {
-       .name           = "hclkd0",
-       .id             = -1,
-       .parent         = &clk_mout_d0sync.clk,
-};
-
-static struct clk clk_hclkd1 = {
-       .name           = "hclkd1",
-       .id             = -1,
-       .parent         = &clk_mout_d1sync.clk,
-};
-
-static struct clk clk_pclkd0 = {
-       .name           = "pclkd0",
-       .id             = -1,
-       .parent         = &clk_hclkd0,
-};
-
-static struct clk clk_pclkd1 = {
-       .name           = "pclkd1",
-       .id             = -1,
-       .parent         = &clk_hclkd1,
-};
-
-int s5p6442_clk_ip0_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKGATE_IP0, clk, enable);
-}
-
-int s5p6442_clk_ip3_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKGATE_IP3, clk, enable);
-}
-
-static struct clksrc_clk clksrcs[] = {
-       {
-               .clk    = {
-                       .name           = "dout_a2m",
-                       .id             = -1,
-                       .parent         = &clk_mout_apll.clk,
-               },
-               .sources = &clk_src_apll,
-               .reg_src = { .reg = S5P_CLK_SRC0, .shift = 0, .size = 1 },
-               .reg_div = { .reg = S5P_CLK_DIV0, .shift = 4, .size = 3 },
-       }, {
-               .clk    = {
-                       .name           = "dout_apll",
-                       .id             = -1,
-                       .parent         = &clk_mout_arm.clk,
-               },
-               .sources = &clk_src_arm,
-               .reg_src = { .reg = S5P_CLK_MUX_STAT0, .shift = 16, .size = 3 },
-               .reg_div = { .reg = S5P_CLK_DIV0, .shift = 0, .size = 3 },
-       }, {
-               .clk    = {
-                       .name           = "hclkd1",
-                       .id             = -1,
-                       .parent         = &clk_mout_d1sync.clk,
-               },
-               .sources = &clk_src_d1sync,
-               .reg_src = { .reg = S5P_CLK_MUX_STAT1, .shift = 24, .size = 3 },
-               .reg_div = { .reg = S5P_CLK_DIV0, .shift = 24, .size = 4 },
-       }, {
-               .clk    = {
-                       .name           = "hclkd0",
-                       .id             = -1,
-                       .parent         = &clk_mout_d0sync.clk,
-               },
-               .sources = &clk_src_d0sync,
-               .reg_src = { .reg = S5P_CLK_MUX_STAT1, .shift = 28, .size = 3 },
-               .reg_div = { .reg = S5P_CLK_DIV0, .shift = 16, .size = 4 },
-       }, {
-               .clk    = {
-                       .name           = "pclkd0",
-                       .id             = -1,
-                       .parent         = &clk_hclkd0,
-               },
-               .sources = &clk_src_d0sync,
-               .reg_src = { .reg = S5P_CLK_MUX_STAT1, .shift = 28, .size = 3 },
-               .reg_div = { .reg = S5P_CLK_DIV0, .shift = 20, .size = 3 },
-       }, {
-               .clk    = {
-                       .name           = "pclkd1",
-                       .id             = -1,
-                       .parent         = &clk_hclkd1,
-               },
-               .sources = &clk_src_d1sync,
-               .reg_src = { .reg = S5P_CLK_MUX_STAT1, .shift = 24, .size = 3 },
-               .reg_div = { .reg = S5P_CLK_DIV0, .shift = 28, .size = 3 },
-       }
-};
-
-/* Clock initialisation code */
-static struct clksrc_clk *init_parents[] = {
-       &clk_mout_apll,
-       &clk_mout_mpll,
-       &clk_mout_epll,
-       &clk_mout_arm,
-       &clk_mout_d0,
-       &clk_mout_d0sync,
-       &clk_mout_d1,
-       &clk_mout_d1sync,
-};
-
-void __init_or_cpufreq s5p6442_setup_clocks(void)
-{
-       struct clk *pclkd0_clk;
-       struct clk *pclkd1_clk;
-
-       unsigned long xtal;
-       unsigned long arm;
-       unsigned long hclkd0 = 0;
-       unsigned long hclkd1 = 0;
-       unsigned long pclkd0 = 0;
-       unsigned long pclkd1 = 0;
-
-       unsigned long apll;
-       unsigned long mpll;
-       unsigned long epll;
-       unsigned int ptr;
-
-       printk(KERN_DEBUG "%s: registering clocks\n", __func__);
-
-       xtal = clk_get_rate(&clk_xtal);
-
-       printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
-
-       apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4508);
-       mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON), pll_4502);
-       epll = s5p_get_pll45xx(xtal, __raw_readl(S5P_EPLL_CON), pll_4500);
-
-       printk(KERN_INFO "S5P6442: PLL settings, A=%ld, M=%ld, E=%ld",
-                       apll, mpll, epll);
-
-       clk_fout_apll.rate = apll;
-       clk_fout_mpll.rate = mpll;
-       clk_fout_epll.rate = epll;
-
-       for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
-               s3c_set_clksrc(init_parents[ptr], true);
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
-               s3c_set_clksrc(&clksrcs[ptr], true);
-
-       arm = clk_get_rate(&clk_dout_apll);
-       hclkd0 = clk_get_rate(&clk_hclkd0);
-       hclkd1 = clk_get_rate(&clk_hclkd1);
-
-       pclkd0_clk = clk_get(NULL, "pclkd0");
-       BUG_ON(IS_ERR(pclkd0_clk));
-
-       pclkd0 = clk_get_rate(pclkd0_clk);
-       clk_put(pclkd0_clk);
-
-       pclkd1_clk = clk_get(NULL, "pclkd1");
-       BUG_ON(IS_ERR(pclkd1_clk));
-
-       pclkd1 = clk_get_rate(pclkd1_clk);
-       clk_put(pclkd1_clk);
-
-       printk(KERN_INFO "S5P6442: HCLKD0=%ld, HCLKD1=%ld, PCLKD0=%ld, PCLKD1=%ld\n",
-                       hclkd0, hclkd1, pclkd0, pclkd1);
-
-       /* For backward compatibility */
-       clk_f.rate = arm;
-       clk_h.rate = hclkd1;
-       clk_p.rate = pclkd1;
-
-       clk_pclkd0.rate = pclkd0;
-       clk_pclkd1.rate = pclkd1;
-}
-
-static struct clk init_clocks_off[] = {
-       {
-               .name           = "pdma",
-               .id             = -1,
-               .parent         = &clk_pclkd1,
-               .enable         = s5p6442_clk_ip0_ctrl,
-               .ctrlbit        = (1 << 3),
-       },
-};
-
-static struct clk init_clocks[] = {
-       {
-               .name           = "systimer",
-               .id             = -1,
-               .parent         = &clk_pclkd1,
-               .enable         = s5p6442_clk_ip3_ctrl,
-               .ctrlbit        = (1<<16),
-       }, {
-               .name           = "uart",
-               .id             = 0,
-               .parent         = &clk_pclkd1,
-               .enable         = s5p6442_clk_ip3_ctrl,
-               .ctrlbit        = (1<<17),
-       }, {
-               .name           = "uart",
-               .id             = 1,
-               .parent         = &clk_pclkd1,
-               .enable         = s5p6442_clk_ip3_ctrl,
-               .ctrlbit        = (1<<18),
-       }, {
-               .name           = "uart",
-               .id             = 2,
-               .parent         = &clk_pclkd1,
-               .enable         = s5p6442_clk_ip3_ctrl,
-               .ctrlbit        = (1<<19),
-       }, {
-               .name           = "watchdog",
-               .id             = -1,
-               .parent         = &clk_pclkd1,
-               .enable         = s5p6442_clk_ip3_ctrl,
-               .ctrlbit        = (1 << 22),
-       }, {
-               .name           = "timers",
-               .id             = -1,
-               .parent         = &clk_pclkd1,
-               .enable         = s5p6442_clk_ip3_ctrl,
-               .ctrlbit        = (1<<23),
-       },
-};
-
-static struct clk *clks[] __initdata = {
-       &clk_ext,
-       &clk_epll,
-       &clk_mout_apll.clk,
-       &clk_mout_mpll.clk,
-       &clk_mout_epll.clk,
-       &clk_mout_d0.clk,
-       &clk_mout_d0sync.clk,
-       &clk_mout_d1.clk,
-       &clk_mout_d1sync.clk,
-       &clk_hclkd0,
-       &clk_pclkd0,
-       &clk_hclkd1,
-       &clk_pclkd1,
-};
-
-void __init s5p6442_register_clocks(void)
-{
-       s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
-
-       s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
-       s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
-
-       s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-       s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-
-       s3c_pwmclk_init();
-}
diff --git a/arch/arm/mach-s5p6442/cpu.c b/arch/arm/mach-s5p6442/cpu.c
deleted file mode 100644 (file)
index 842af86..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/cpu.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/sysdev.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/sched.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <asm/proc-fns.h>
-
-#include <mach/hardware.h>
-#include <mach/map.h>
-#include <asm/irq.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-clock.h>
-
-#include <plat/cpu.h>
-#include <plat/devs.h>
-#include <plat/clock.h>
-#include <plat/s5p6442.h>
-
-/* Initial IO mappings */
-
-static struct map_desc s5p6442_iodesc[] __initdata = {
-       {
-               .virtual        = (unsigned long)S5P_VA_SYSTIMER,
-               .pfn            = __phys_to_pfn(S5P6442_PA_SYSTIMER),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)S5P_VA_GPIO,
-               .pfn            = __phys_to_pfn(S5P6442_PA_GPIO),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)VA_VIC0,
-               .pfn            = __phys_to_pfn(S5P6442_PA_VIC0),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)VA_VIC1,
-               .pfn            = __phys_to_pfn(S5P6442_PA_VIC1),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)VA_VIC2,
-               .pfn            = __phys_to_pfn(S5P6442_PA_VIC2),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)S3C_VA_UART,
-               .pfn            = __phys_to_pfn(S3C_PA_UART),
-               .length         = SZ_512K,
-               .type           = MT_DEVICE,
-       }
-};
-
-static void s5p6442_idle(void)
-{
-       if (!need_resched())
-               cpu_do_idle();
-
-       local_irq_enable();
-}
-
-/*
- * s5p6442_map_io
- *
- * register the standard cpu IO areas
- */
-
-void __init s5p6442_map_io(void)
-{
-       iotable_init(s5p6442_iodesc, ARRAY_SIZE(s5p6442_iodesc));
-}
-
-void __init s5p6442_init_clocks(int xtal)
-{
-       printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
-
-       s3c24xx_register_baseclocks(xtal);
-       s5p_register_clocks(xtal);
-       s5p6442_register_clocks();
-       s5p6442_setup_clocks();
-}
-
-void __init s5p6442_init_irq(void)
-{
-       /* S5P6442 supports 3 VIC */
-       u32 vic[3];
-
-       /* VIC0, VIC1, and VIC2: some interrupt reserved */
-       vic[0] = 0x7fefffff;
-       vic[1] = 0X7f389c81;
-       vic[2] = 0X1bbbcfff;
-
-       s5p_init_irq(vic, ARRAY_SIZE(vic));
-}
-
-struct sysdev_class s5p6442_sysclass = {
-       .name   = "s5p6442-core",
-};
-
-static struct sys_device s5p6442_sysdev = {
-       .cls    = &s5p6442_sysclass,
-};
-
-static int __init s5p6442_core_init(void)
-{
-       return sysdev_class_register(&s5p6442_sysclass);
-}
-
-core_initcall(s5p6442_core_init);
-
-int __init s5p6442_init(void)
-{
-       printk(KERN_INFO "S5P6442: Initializing architecture\n");
-
-       /* set idle function */
-       pm_idle = s5p6442_idle;
-
-       return sysdev_register(&s5p6442_sysdev);
-}
diff --git a/arch/arm/mach-s5p6442/dev-audio.c b/arch/arm/mach-s5p6442/dev-audio.c
deleted file mode 100644 (file)
index 8719dc4..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/dev-audio.c
- *
- * Copyright (c) 2010 Samsung Electronics Co. Ltd
- *     Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/gpio.h>
-
-#include <plat/gpio-cfg.h>
-#include <plat/audio.h>
-
-#include <mach/map.h>
-#include <mach/dma.h>
-#include <mach/irqs.h>
-
-static int s5p6442_cfg_i2s(struct platform_device *pdev)
-{
-       unsigned int base;
-
-       /* configure GPIO for i2s port */
-       switch (pdev->id) {
-       case 1:
-               base = S5P6442_GPC1(0);
-               break;
-
-       case 0:
-               base = S5P6442_GPC0(0);
-               break;
-
-       default:
-               printk(KERN_ERR "Invalid Device %d\n", pdev->id);
-               return -EINVAL;
-       }
-
-       s3c_gpio_cfgpin_range(base, 5, S3C_GPIO_SFN(2));
-       return 0;
-}
-
-static const char *rclksrc_v35[] = {
-       [0] = "busclk",
-       [1] = "i2sclk",
-};
-
-static struct s3c_audio_pdata i2sv35_pdata = {
-       .cfg_gpio = s5p6442_cfg_i2s,
-       .type = {
-               .i2s = {
-                       .quirks = QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR,
-                       .src_clk = rclksrc_v35,
-               },
-       },
-};
-
-static struct resource s5p6442_iis0_resource[] = {
-       [0] = {
-               .start = S5P6442_PA_I2S0,
-               .end   = S5P6442_PA_I2S0 + 0x100 - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start = DMACH_I2S0_TX,
-               .end   = DMACH_I2S0_TX,
-               .flags = IORESOURCE_DMA,
-       },
-       [2] = {
-               .start = DMACH_I2S0_RX,
-               .end   = DMACH_I2S0_RX,
-               .flags = IORESOURCE_DMA,
-       },
-       [3] = {
-               .start = DMACH_I2S0S_TX,
-               .end = DMACH_I2S0S_TX,
-               .flags = IORESOURCE_DMA,
-       },
-};
-
-struct platform_device s5p6442_device_iis0 = {
-       .name = "samsung-i2s",
-       .id = 0,
-       .num_resources    = ARRAY_SIZE(s5p6442_iis0_resource),
-       .resource         = s5p6442_iis0_resource,
-       .dev = {
-               .platform_data = &i2sv35_pdata,
-       },
-};
-
-static const char *rclksrc_v3[] = {
-       [0] = "iis",
-       [1] = "sclk_audio",
-};
-
-static struct s3c_audio_pdata i2sv3_pdata = {
-       .cfg_gpio = s5p6442_cfg_i2s,
-       .type = {
-               .i2s = {
-                       .src_clk = rclksrc_v3,
-               },
-       },
-};
-
-static struct resource s5p6442_iis1_resource[] = {
-       [0] = {
-               .start = S5P6442_PA_I2S1,
-               .end   = S5P6442_PA_I2S1 + 0x100 - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start = DMACH_I2S1_TX,
-               .end   = DMACH_I2S1_TX,
-               .flags = IORESOURCE_DMA,
-       },
-       [2] = {
-               .start = DMACH_I2S1_RX,
-               .end   = DMACH_I2S1_RX,
-               .flags = IORESOURCE_DMA,
-       },
-};
-
-struct platform_device s5p6442_device_iis1 = {
-       .name             = "samsung-i2s",
-       .id               = 1,
-       .num_resources    = ARRAY_SIZE(s5p6442_iis1_resource),
-       .resource         = s5p6442_iis1_resource,
-       .dev = {
-               .platform_data = &i2sv3_pdata,
-       },
-};
-
-/* PCM Controller platform_devices */
-
-static int s5p6442_pcm_cfg_gpio(struct platform_device *pdev)
-{
-       unsigned int base;
-
-       switch (pdev->id) {
-       case 0:
-               base = S5P6442_GPC0(0);
-               break;
-
-       case 1:
-               base = S5P6442_GPC1(0);
-               break;
-
-       default:
-               printk(KERN_DEBUG "Invalid PCM Controller number!");
-               return -EINVAL;
-       }
-
-       s3c_gpio_cfgpin_range(base, 5, S3C_GPIO_SFN(3));
-       return 0;
-}
-
-static struct s3c_audio_pdata s3c_pcm_pdata = {
-       .cfg_gpio = s5p6442_pcm_cfg_gpio,
-};
-
-static struct resource s5p6442_pcm0_resource[] = {
-       [0] = {
-               .start = S5P6442_PA_PCM0,
-               .end   = S5P6442_PA_PCM0 + 0x100 - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start = DMACH_PCM0_TX,
-               .end   = DMACH_PCM0_TX,
-               .flags = IORESOURCE_DMA,
-       },
-       [2] = {
-               .start = DMACH_PCM0_RX,
-               .end   = DMACH_PCM0_RX,
-               .flags = IORESOURCE_DMA,
-       },
-};
-
-struct platform_device s5p6442_device_pcm0 = {
-       .name             = "samsung-pcm",
-       .id               = 0,
-       .num_resources    = ARRAY_SIZE(s5p6442_pcm0_resource),
-       .resource         = s5p6442_pcm0_resource,
-       .dev = {
-               .platform_data = &s3c_pcm_pdata,
-       },
-};
-
-static struct resource s5p6442_pcm1_resource[] = {
-       [0] = {
-               .start = S5P6442_PA_PCM1,
-               .end   = S5P6442_PA_PCM1 + 0x100 - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start = DMACH_PCM1_TX,
-               .end   = DMACH_PCM1_TX,
-               .flags = IORESOURCE_DMA,
-       },
-       [2] = {
-               .start = DMACH_PCM1_RX,
-               .end   = DMACH_PCM1_RX,
-               .flags = IORESOURCE_DMA,
-       },
-};
-
-struct platform_device s5p6442_device_pcm1 = {
-       .name             = "samsung-pcm",
-       .id               = 1,
-       .num_resources    = ARRAY_SIZE(s5p6442_pcm1_resource),
-       .resource         = s5p6442_pcm1_resource,
-       .dev = {
-               .platform_data = &s3c_pcm_pdata,
-       },
-};
diff --git a/arch/arm/mach-s5p6442/dev-spi.c b/arch/arm/mach-s5p6442/dev-spi.c
deleted file mode 100644 (file)
index cce8c24..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/dev-spi.c
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *     Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/gpio.h>
-
-#include <mach/dma.h>
-#include <mach/map.h>
-#include <mach/irqs.h>
-#include <mach/spi-clocks.h>
-
-#include <plat/s3c64xx-spi.h>
-#include <plat/gpio-cfg.h>
-
-static char *spi_src_clks[] = {
-       [S5P6442_SPI_SRCCLK_PCLK] = "pclk",
-       [S5P6442_SPI_SRCCLK_SCLK] = "spi_epll",
-};
-
-/* SPI Controller platform_devices */
-
-/* Since we emulate multi-cs capability, we do not touch the CS.
- * The emulated CS is toggled by board specific mechanism, as it can
- * be either some immediate GPIO or some signal out of some other
- * chip in between ... or some yet another way.
- * We simply do not assume anything about CS.
- */
-static int s5p6442_spi_cfg_gpio(struct platform_device *pdev)
-{
-       switch (pdev->id) {
-       case 0:
-               s3c_gpio_cfgpin(S5P6442_GPB(0), S3C_GPIO_SFN(2));
-               s3c_gpio_setpull(S5P6442_GPB(0), S3C_GPIO_PULL_UP);
-               s3c_gpio_cfgall_range(S5P6442_GPB(2), 2,
-                                     S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
-               break;
-
-       default:
-               dev_err(&pdev->dev, "Invalid SPI Controller number!");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static struct resource s5p6442_spi0_resource[] = {
-       [0] = {
-               .start = S5P6442_PA_SPI,
-               .end   = S5P6442_PA_SPI + 0x100 - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start = DMACH_SPI0_TX,
-               .end   = DMACH_SPI0_TX,
-               .flags = IORESOURCE_DMA,
-       },
-       [2] = {
-               .start = DMACH_SPI0_RX,
-               .end   = DMACH_SPI0_RX,
-               .flags = IORESOURCE_DMA,
-       },
-       [3] = {
-               .start = IRQ_SPI0,
-               .end   = IRQ_SPI0,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-static struct s3c64xx_spi_info s5p6442_spi0_pdata = {
-       .cfg_gpio = s5p6442_spi_cfg_gpio,
-       .fifo_lvl_mask = 0x1ff,
-       .rx_lvl_offset = 15,
-};
-
-static u64 spi_dmamask = DMA_BIT_MASK(32);
-
-struct platform_device s5p6442_device_spi = {
-       .name             = "s3c64xx-spi",
-       .id               = 0,
-       .num_resources    = ARRAY_SIZE(s5p6442_spi0_resource),
-       .resource         = s5p6442_spi0_resource,
-       .dev = {
-               .dma_mask               = &spi_dmamask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-               .platform_data = &s5p6442_spi0_pdata,
-       },
-};
-
-void __init s5p6442_spi_set_info(int cntrlr, int src_clk_nr, int num_cs)
-{
-       struct s3c64xx_spi_info *pd;
-
-       /* Reject invalid configuration */
-       if (!num_cs || src_clk_nr < 0
-                       || src_clk_nr > S5P6442_SPI_SRCCLK_SCLK) {
-               printk(KERN_ERR "%s: Invalid SPI configuration\n", __func__);
-               return;
-       }
-
-       switch (cntrlr) {
-       case 0:
-               pd = &s5p6442_spi0_pdata;
-               break;
-       default:
-               printk(KERN_ERR "%s: Invalid SPI controller(%d)\n",
-                                                       __func__, cntrlr);
-               return;
-       }
-
-       pd->num_cs = num_cs;
-       pd->src_clk_nr = src_clk_nr;
-       pd->src_clk_name = spi_src_clks[src_clk_nr];
-}
diff --git a/arch/arm/mach-s5p6442/dma.c b/arch/arm/mach-s5p6442/dma.c
deleted file mode 100644 (file)
index 7dfb136..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *     Jaswinder Singh <jassi.brar@samsung.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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-
-#include <plat/devs.h>
-#include <plat/irqs.h>
-
-#include <mach/map.h>
-#include <mach/irqs.h>
-
-#include <plat/s3c-pl330-pdata.h>
-
-static u64 dma_dmamask = DMA_BIT_MASK(32);
-
-static struct resource s5p6442_pdma_resource[] = {
-       [0] = {
-               .start  = S5P6442_PA_PDMA,
-               .end    = S5P6442_PA_PDMA + SZ_4K,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_PDMA,
-               .end    = IRQ_PDMA,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct s3c_pl330_platdata s5p6442_pdma_pdata = {
-       .peri = {
-               [0] = DMACH_UART0_RX,
-               [1] = DMACH_UART0_TX,
-               [2] = DMACH_UART1_RX,
-               [3] = DMACH_UART1_TX,
-               [4] = DMACH_UART2_RX,
-               [5] = DMACH_UART2_TX,
-               [6] = DMACH_MAX,
-               [7] = DMACH_MAX,
-               [8] = DMACH_MAX,
-               [9] = DMACH_I2S0_RX,
-               [10] = DMACH_I2S0_TX,
-               [11] = DMACH_I2S0S_TX,
-               [12] = DMACH_I2S1_RX,
-               [13] = DMACH_I2S1_TX,
-               [14] = DMACH_MAX,
-               [15] = DMACH_MAX,
-               [16] = DMACH_SPI0_RX,
-               [17] = DMACH_SPI0_TX,
-               [18] = DMACH_MAX,
-               [19] = DMACH_MAX,
-               [20] = DMACH_PCM0_RX,
-               [21] = DMACH_PCM0_TX,
-               [22] = DMACH_PCM1_RX,
-               [23] = DMACH_PCM1_TX,
-               [24] = DMACH_MAX,
-               [25] = DMACH_MAX,
-               [26] = DMACH_MAX,
-               [27] = DMACH_MSM_REQ0,
-               [28] = DMACH_MSM_REQ1,
-               [29] = DMACH_MSM_REQ2,
-               [30] = DMACH_MSM_REQ3,
-               [31] = DMACH_MAX,
-       },
-};
-
-static struct platform_device s5p6442_device_pdma = {
-       .name           = "s3c-pl330",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(s5p6442_pdma_resource),
-       .resource       = s5p6442_pdma_resource,
-       .dev            = {
-               .dma_mask = &dma_dmamask,
-               .coherent_dma_mask = DMA_BIT_MASK(32),
-               .platform_data = &s5p6442_pdma_pdata,
-       },
-};
-
-static struct platform_device *s5p6442_dmacs[] __initdata = {
-       &s5p6442_device_pdma,
-};
-
-static int __init s5p6442_dma_init(void)
-{
-       platform_add_devices(s5p6442_dmacs, ARRAY_SIZE(s5p6442_dmacs));
-
-       return 0;
-}
-arch_initcall(s5p6442_dma_init);
diff --git a/arch/arm/mach-s5p6442/include/mach/debug-macro.S b/arch/arm/mach-s5p6442/include/mach/debug-macro.S
deleted file mode 100644 (file)
index e221320..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/include/mach/debug-macro.S
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * Based on arch/arm/mach-s3c6400/include/mach/debug-macro.S
- *
- * 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.
-*/
-
-/* pull in the relevant register and map files. */
-
-#include <mach/map.h>
-#include <plat/regs-serial.h>
-
-       .macro addruart, rp, rv
-               ldr     \rp, = S3C_PA_UART
-               ldr     \rv, = S3C_VA_UART
-#if CONFIG_DEBUG_S3C_UART != 0
-               add     \rp, \rp, #(0x400 * CONFIG_DEBUG_S3C_UART)
-               add     \rv, \rv, #(0x400 * CONFIG_DEBUG_S3C_UART)
-#endif
-       .endm
-
-#define fifo_full fifo_full_s5pv210
-#define fifo_level fifo_level_s5pv210
-
-/* include the reset of the code which will do the work, we're only
- * compiling for a single cpu processor type so the default of s3c2440
- * will be fine with us.
- */
-
-#include <plat/debug-macro.S>
diff --git a/arch/arm/mach-s5p6442/include/mach/entry-macro.S b/arch/arm/mach-s5p6442/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 6d574ed..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/include/mach/entry-macro.S
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * Low-level IRQ helper macros for the Samsung S5P6442
- *
- * 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 <asm/hardware/vic.h>
-#include <mach/map.h>
-#include <plat/irqs.h>
-
-       .macro  disable_fiq
-       .endm
-
-       .macro  get_irqnr_preamble, base, tmp
-       ldr     \base, =VA_VIC0
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
-       .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
-
-       @ check the vic0
-       mov     \irqnr, # S5P_IRQ_OFFSET + 31
-       ldr     \irqstat, [ \base, # VIC_IRQ_STATUS ]
-       teq     \irqstat, #0
-
-       @ otherwise try vic1
-       addeq   \tmp, \base, #(VA_VIC1 - VA_VIC0)
-       addeq   \irqnr, \irqnr, #32
-       ldreq   \irqstat, [ \tmp, # VIC_IRQ_STATUS ]
-       teqeq   \irqstat, #0
-
-       @ otherwise try vic2
-       addeq   \tmp, \base, #(VA_VIC2 - VA_VIC0)
-       addeq   \irqnr, \irqnr, #32
-       ldreq   \irqstat, [ \tmp, # VIC_IRQ_STATUS ]
-       teqeq   \irqstat, #0
-
-       clzne   \irqstat, \irqstat
-       subne   \irqnr, \irqnr, \irqstat
-       .endm
diff --git a/arch/arm/mach-s5p6442/include/mach/gpio.h b/arch/arm/mach-s5p6442/include/mach/gpio.h
deleted file mode 100644 (file)
index b8715df..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/include/mach/gpio.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5P6442 - GPIO lib 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.
-*/
-
-#ifndef __ASM_ARCH_GPIO_H
-#define __ASM_ARCH_GPIO_H __FILE__
-
-#define gpio_get_value __gpio_get_value
-#define gpio_set_value __gpio_set_value
-#define gpio_cansleep  __gpio_cansleep
-#define gpio_to_irq    __gpio_to_irq
-
-/* GPIO bank sizes */
-#define S5P6442_GPIO_A0_NR     (8)
-#define S5P6442_GPIO_A1_NR     (2)
-#define S5P6442_GPIO_B_NR      (4)
-#define S5P6442_GPIO_C0_NR     (5)
-#define S5P6442_GPIO_C1_NR     (5)
-#define S5P6442_GPIO_D0_NR     (2)
-#define S5P6442_GPIO_D1_NR     (6)
-#define S5P6442_GPIO_E0_NR     (8)
-#define S5P6442_GPIO_E1_NR     (5)
-#define S5P6442_GPIO_F0_NR     (8)
-#define S5P6442_GPIO_F1_NR     (8)
-#define S5P6442_GPIO_F2_NR     (8)
-#define S5P6442_GPIO_F3_NR     (6)
-#define S5P6442_GPIO_G0_NR     (7)
-#define S5P6442_GPIO_G1_NR     (7)
-#define S5P6442_GPIO_G2_NR     (7)
-#define S5P6442_GPIO_H0_NR     (8)
-#define S5P6442_GPIO_H1_NR     (8)
-#define S5P6442_GPIO_H2_NR     (8)
-#define S5P6442_GPIO_H3_NR     (8)
-#define S5P6442_GPIO_J0_NR     (8)
-#define S5P6442_GPIO_J1_NR     (6)
-#define S5P6442_GPIO_J2_NR     (8)
-#define S5P6442_GPIO_J3_NR     (8)
-#define S5P6442_GPIO_J4_NR     (5)
-
-/* GPIO bank numbers */
-
-/* CONFIG_S3C_GPIO_SPACE allows the user to select extra
- * space for debugging purposes so that any accidental
- * change from one gpio bank to another can be caught.
-*/
-
-#define S5P6442_GPIO_NEXT(__gpio) \
-       ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
-
-enum s5p_gpio_number {
-       S5P6442_GPIO_A0_START   = 0,
-       S5P6442_GPIO_A1_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_A0),
-       S5P6442_GPIO_B_START    = S5P6442_GPIO_NEXT(S5P6442_GPIO_A1),
-       S5P6442_GPIO_C0_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_B),
-       S5P6442_GPIO_C1_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_C0),
-       S5P6442_GPIO_D0_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_C1),
-       S5P6442_GPIO_D1_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_D0),
-       S5P6442_GPIO_E0_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_D1),
-       S5P6442_GPIO_E1_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_E0),
-       S5P6442_GPIO_F0_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_E1),
-       S5P6442_GPIO_F1_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_F0),
-       S5P6442_GPIO_F2_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_F1),
-       S5P6442_GPIO_F3_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_F2),
-       S5P6442_GPIO_G0_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_F3),
-       S5P6442_GPIO_G1_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_G0),
-       S5P6442_GPIO_G2_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_G1),
-       S5P6442_GPIO_H0_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_G2),
-       S5P6442_GPIO_H1_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_H0),
-       S5P6442_GPIO_H2_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_H1),
-       S5P6442_GPIO_H3_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_H2),
-       S5P6442_GPIO_J0_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_H3),
-       S5P6442_GPIO_J1_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_J0),
-       S5P6442_GPIO_J2_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_J1),
-       S5P6442_GPIO_J3_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_J2),
-       S5P6442_GPIO_J4_START   = S5P6442_GPIO_NEXT(S5P6442_GPIO_J3),
-};
-
-/* S5P6442 GPIO number definitions. */
-#define S5P6442_GPA0(_nr)      (S5P6442_GPIO_A0_START + (_nr))
-#define S5P6442_GPA1(_nr)      (S5P6442_GPIO_A1_START + (_nr))
-#define S5P6442_GPB(_nr)       (S5P6442_GPIO_B_START + (_nr))
-#define S5P6442_GPC0(_nr)      (S5P6442_GPIO_C0_START + (_nr))
-#define S5P6442_GPC1(_nr)      (S5P6442_GPIO_C1_START + (_nr))
-#define S5P6442_GPD0(_nr)      (S5P6442_GPIO_D0_START + (_nr))
-#define S5P6442_GPD1(_nr)      (S5P6442_GPIO_D1_START + (_nr))
-#define S5P6442_GPE0(_nr)      (S5P6442_GPIO_E0_START + (_nr))
-#define S5P6442_GPE1(_nr)      (S5P6442_GPIO_E1_START + (_nr))
-#define S5P6442_GPF0(_nr)      (S5P6442_GPIO_F0_START + (_nr))
-#define S5P6442_GPF1(_nr)      (S5P6442_GPIO_F1_START + (_nr))
-#define S5P6442_GPF2(_nr)      (S5P6442_GPIO_F2_START + (_nr))
-#define S5P6442_GPF3(_nr)      (S5P6442_GPIO_F3_START + (_nr))
-#define S5P6442_GPG0(_nr)      (S5P6442_GPIO_G0_START + (_nr))
-#define S5P6442_GPG1(_nr)      (S5P6442_GPIO_G1_START + (_nr))
-#define S5P6442_GPG2(_nr)      (S5P6442_GPIO_G2_START + (_nr))
-#define S5P6442_GPH0(_nr)      (S5P6442_GPIO_H0_START + (_nr))
-#define S5P6442_GPH1(_nr)      (S5P6442_GPIO_H1_START + (_nr))
-#define S5P6442_GPH2(_nr)      (S5P6442_GPIO_H2_START + (_nr))
-#define S5P6442_GPH3(_nr)      (S5P6442_GPIO_H3_START + (_nr))
-#define S5P6442_GPJ0(_nr)      (S5P6442_GPIO_J0_START + (_nr))
-#define S5P6442_GPJ1(_nr)      (S5P6442_GPIO_J1_START + (_nr))
-#define S5P6442_GPJ2(_nr)      (S5P6442_GPIO_J2_START + (_nr))
-#define S5P6442_GPJ3(_nr)      (S5P6442_GPIO_J3_START + (_nr))
-#define S5P6442_GPJ4(_nr)      (S5P6442_GPIO_J4_START + (_nr))
-
-/* the end of the S5P6442 specific gpios */
-#define S5P6442_GPIO_END       (S5P6442_GPJ4(S5P6442_GPIO_J4_NR) + 1)
-#define S3C_GPIO_END           S5P6442_GPIO_END
-
-/* define the number of gpios we need to the one after the GPJ4() range */
-#define ARCH_NR_GPIOS          (S5P6442_GPJ4(S5P6442_GPIO_J4_NR) +     \
-                                CONFIG_SAMSUNG_GPIO_EXTRA + 1)
-
-#include <asm-generic/gpio.h>
-
-#endif /* __ASM_ARCH_GPIO_H */
diff --git a/arch/arm/mach-s5p6442/include/mach/hardware.h b/arch/arm/mach-s5p6442/include/mach/hardware.h
deleted file mode 100644 (file)
index 8cd7b67..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/include/mach/hardware.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5P6442 - Hardware 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.
-*/
-
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H __FILE__
-
-/* currently nothing here, placeholder */
-
-#endif /* __ASM_ARCH_HARDWARE_H */
diff --git a/arch/arm/mach-s5p6442/include/mach/io.h b/arch/arm/mach-s5p6442/include/mach/io.h
deleted file mode 100644 (file)
index 5d2195a..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* arch/arm/mach-s5p6442/include/mach/io.h
- *
- * Copyright 2008-2010 Ben Dooks <ben-linux@fluff.org>
- *
- * Default IO routines for S5P6442
- */
-
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/* No current ISA/PCI bus support. */
-#define __io(a)                __typesafe_io(a)
-#define __mem_pci(a)   (a)
-
-#define IO_SPACE_LIMIT (0xFFFFFFFF)
-
-#endif
diff --git a/arch/arm/mach-s5p6442/include/mach/irqs.h b/arch/arm/mach-s5p6442/include/mach/irqs.h
deleted file mode 100644 (file)
index 3fbc6c3..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/include/mach/irqs.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5P6442 - IRQ definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_IRQS_H
-#define __ASM_ARCH_IRQS_H __FILE__
-
-#include <plat/irqs.h>
-
-/* VIC0 */
-#define IRQ_EINT16_31          S5P_IRQ_VIC0(16)
-#define IRQ_BATF               S5P_IRQ_VIC0(17)
-#define IRQ_MDMA               S5P_IRQ_VIC0(18)
-#define IRQ_PDMA               S5P_IRQ_VIC0(19)
-#define IRQ_TIMER0_VIC         S5P_IRQ_VIC0(21)
-#define IRQ_TIMER1_VIC         S5P_IRQ_VIC0(22)
-#define IRQ_TIMER2_VIC         S5P_IRQ_VIC0(23)
-#define IRQ_TIMER3_VIC         S5P_IRQ_VIC0(24)
-#define IRQ_TIMER4_VIC         S5P_IRQ_VIC0(25)
-#define IRQ_SYSTIMER           S5P_IRQ_VIC0(26)
-#define IRQ_WDT                        S5P_IRQ_VIC0(27)
-#define IRQ_RTC_ALARM          S5P_IRQ_VIC0(28)
-#define IRQ_RTC_TIC            S5P_IRQ_VIC0(29)
-#define IRQ_GPIOINT            S5P_IRQ_VIC0(30)
-
-/* VIC1 */
-#define IRQ_PMU                        S5P_IRQ_VIC1(0)
-#define IRQ_ONENAND            S5P_IRQ_VIC1(7)
-#define IRQ_UART0              S5P_IRQ_VIC1(10)
-#define IRQ_UART1              S5P_IRQ_VIC1(11)
-#define IRQ_UART2              S5P_IRQ_VIC1(12)
-#define IRQ_SPI0               S5P_IRQ_VIC1(15)
-#define IRQ_IIC                S5P_IRQ_VIC1(19)
-#define IRQ_IIC1               S5P_IRQ_VIC1(20)
-#define IRQ_IIC2               S5P_IRQ_VIC1(21)
-#define IRQ_OTG                S5P_IRQ_VIC1(24)
-#define IRQ_MSM                S5P_IRQ_VIC1(25)
-#define IRQ_HSMMC0             S5P_IRQ_VIC1(26)
-#define IRQ_HSMMC1             S5P_IRQ_VIC1(27)
-#define IRQ_HSMMC2             S5P_IRQ_VIC1(28)
-#define IRQ_COMMRX             S5P_IRQ_VIC1(29)
-#define IRQ_COMMTX             S5P_IRQ_VIC1(30)
-
-/* VIC2 */
-#define IRQ_LCD0               S5P_IRQ_VIC2(0)
-#define IRQ_LCD1               S5P_IRQ_VIC2(1)
-#define IRQ_LCD2               S5P_IRQ_VIC2(2)
-#define IRQ_LCD3               S5P_IRQ_VIC2(3)
-#define IRQ_ROTATOR            S5P_IRQ_VIC2(4)
-#define IRQ_FIMC0              S5P_IRQ_VIC2(5)
-#define IRQ_FIMC1              S5P_IRQ_VIC2(6)
-#define IRQ_FIMC2              S5P_IRQ_VIC2(7)
-#define IRQ_JPEG               S5P_IRQ_VIC2(8)
-#define IRQ_3D                         S5P_IRQ_VIC2(10)
-#define IRQ_Mixer              S5P_IRQ_VIC2(11)
-#define IRQ_MFC                S5P_IRQ_VIC2(14)
-#define IRQ_TVENC              S5P_IRQ_VIC2(15)
-#define IRQ_I2S0               S5P_IRQ_VIC2(16)
-#define IRQ_I2S1               S5P_IRQ_VIC2(17)
-#define IRQ_RP                         S5P_IRQ_VIC2(19)
-#define IRQ_PCM0               S5P_IRQ_VIC2(20)
-#define IRQ_PCM1               S5P_IRQ_VIC2(21)
-#define IRQ_ADC                S5P_IRQ_VIC2(23)
-#define IRQ_PENDN              S5P_IRQ_VIC2(24)
-#define IRQ_KEYPAD             S5P_IRQ_VIC2(25)
-#define IRQ_SSS_INT            S5P_IRQ_VIC2(27)
-#define IRQ_SSS_HASH           S5P_IRQ_VIC2(28)
-#define IRQ_VIC_END            S5P_IRQ_VIC2(31)
-
-#define S5P_IRQ_EINT_BASE      (IRQ_VIC_END + 1)
-
-#define S5P_EINT_BASE1         (S5P_IRQ_VIC0(0))
-#define S5P_EINT_BASE2         (S5P_IRQ_EINT_BASE)
-
-/* Set the default NR_IRQS */
-
-#define NR_IRQS                (IRQ_EINT(31) + 1)
-
-#endif /* __ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-s5p6442/include/mach/map.h b/arch/arm/mach-s5p6442/include/mach/map.h
deleted file mode 100644 (file)
index 058dab4..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/include/mach/map.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5P6442 - Memory map definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_MAP_H
-#define __ASM_ARCH_MAP_H __FILE__
-
-#include <plat/map-base.h>
-#include <plat/map-s5p.h>
-
-#define S5P6442_PA_SDRAM       0x20000000
-
-#define S5P6442_PA_I2S0                0xC0B00000
-#define S5P6442_PA_I2S1                0xF2200000
-
-#define S5P6442_PA_CHIPID      0xE0000000
-
-#define S5P6442_PA_SYSCON      0xE0100000
-
-#define S5P6442_PA_GPIO                0xE0200000
-
-#define S5P6442_PA_VIC0                0xE4000000
-#define S5P6442_PA_VIC1                0xE4100000
-#define S5P6442_PA_VIC2                0xE4200000
-
-#define S5P6442_PA_SROMC       0xE7000000
-
-#define S5P6442_PA_MDMA                0xE8000000
-#define S5P6442_PA_PDMA                0xE9000000
-
-#define S5P6442_PA_TIMER       0xEA000000
-
-#define S5P6442_PA_SYSTIMER    0xEA100000
-
-#define S5P6442_PA_WATCHDOG    0xEA200000
-
-#define S5P6442_PA_UART                0xEC000000
-
-#define S5P6442_PA_IIC0                0xEC100000
-
-#define S5P6442_PA_SPI         0xEC300000
-
-#define S5P6442_PA_PCM0                0xF2400000
-#define S5P6442_PA_PCM1                0xF2500000
-
-/* Compatibiltiy Defines */
-
-#define S3C_PA_IIC             S5P6442_PA_IIC0
-#define S3C_PA_WDT             S5P6442_PA_WATCHDOG
-
-#define S5P_PA_CHIPID          S5P6442_PA_CHIPID
-#define S5P_PA_SDRAM           S5P6442_PA_SDRAM
-#define S5P_PA_SROMC           S5P6442_PA_SROMC
-#define S5P_PA_SYSCON          S5P6442_PA_SYSCON
-#define S5P_PA_TIMER           S5P6442_PA_TIMER
-
-/* UART */
-
-#define S3C_PA_UART            S5P6442_PA_UART
-
-#define S5P_PA_UART(x)         (S3C_PA_UART + ((x) * S3C_UART_OFFSET))
-#define S5P_PA_UART0           S5P_PA_UART(0)
-#define S5P_PA_UART1           S5P_PA_UART(1)
-#define S5P_PA_UART2           S5P_PA_UART(2)
-
-#define S5P_SZ_UART            SZ_256
-
-#endif /* __ASM_ARCH_MAP_H */
diff --git a/arch/arm/mach-s5p6442/include/mach/memory.h b/arch/arm/mach-s5p6442/include/mach/memory.h
deleted file mode 100644 (file)
index cfe259d..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/include/mach/memory.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5P6442 - Memory definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_MEMORY_H
-#define __ASM_ARCH_MEMORY_H
-
-#define PLAT_PHYS_OFFSET               UL(0x20000000)
-#define CONSISTENT_DMA_SIZE    SZ_8M
-
-#endif /* __ASM_ARCH_MEMORY_H */
diff --git a/arch/arm/mach-s5p6442/include/mach/pwm-clock.h b/arch/arm/mach-s5p6442/include/mach/pwm-clock.h
deleted file mode 100644 (file)
index 2724b37..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/include/mach/pwm-clock.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *      Ben Dooks <ben@simtec.co.uk>
- *      http://armlinux.simtec.co.uk/
- *
- * Based on arch/arm/mach-s3c64xx/include/mach/pwm-clock.h
- *
- * S5P6442 - pwm clock and timer 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.
-*/
-
-#ifndef __ASM_ARCH_PWMCLK_H
-#define __ASM_ARCH_PWMCLK_H __FILE__
-
-/**
- * pwm_cfg_src_is_tclk() - return whether the given mux config is a tclk
- * @tcfg: The timer TCFG1 register bits shifted down to 0.
- *
- * Return true if the given configuration from TCFG1 is a TCLK instead
- * any of the TDIV clocks.
- */
-static inline int pwm_cfg_src_is_tclk(unsigned long tcfg)
-{
-       return tcfg == S3C64XX_TCFG1_MUX_TCLK;
-}
-
-/**
- * tcfg_to_divisor() - convert tcfg1 setting to a divisor
- * @tcfg1: The tcfg1 setting, shifted down.
- *
- * Get the divisor value for the given tcfg1 setting. We assume the
- * caller has already checked to see if this is not a TCLK source.
- */
-static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
-{
-       return 1 << tcfg1;
-}
-
-/**
- * pwm_tdiv_has_div1() - does the tdiv setting have a /1
- *
- * Return true if we have a /1 in the tdiv setting.
- */
-static inline unsigned int pwm_tdiv_has_div1(void)
-{
-       return 1;
-}
-
-/**
- * pwm_tdiv_div_bits() - calculate TCFG1 divisor value.
- * @div: The divisor to calculate the bit information for.
- *
- * Turn a divisor into the necessary bit field for TCFG1.
- */
-static inline unsigned long pwm_tdiv_div_bits(unsigned int div)
-{
-       return ilog2(div);
-}
-
-#define S3C_TCFG1_MUX_TCLK S3C64XX_TCFG1_MUX_TCLK
-
-#endif /* __ASM_ARCH_PWMCLK_H */
diff --git a/arch/arm/mach-s5p6442/include/mach/regs-clock.h b/arch/arm/mach-s5p6442/include/mach/regs-clock.h
deleted file mode 100644 (file)
index 00828a3..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/include/mach/regs-clock.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5P6442 - Clock register definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_REGS_CLOCK_H
-#define __ASM_ARCH_REGS_CLOCK_H __FILE__
-
-#include <mach/map.h>
-
-#define S5P_CLKREG(x)          (S3C_VA_SYS + (x))
-
-#define S5P_APLL_LOCK          S5P_CLKREG(0x00)
-#define S5P_MPLL_LOCK          S5P_CLKREG(0x08)
-#define S5P_EPLL_LOCK          S5P_CLKREG(0x10)
-#define S5P_VPLL_LOCK          S5P_CLKREG(0x20)
-
-#define S5P_APLL_CON           S5P_CLKREG(0x100)
-#define S5P_MPLL_CON           S5P_CLKREG(0x108)
-#define S5P_EPLL_CON           S5P_CLKREG(0x110)
-#define S5P_VPLL_CON           S5P_CLKREG(0x120)
-
-#define S5P_CLK_SRC0           S5P_CLKREG(0x200)
-#define S5P_CLK_SRC1           S5P_CLKREG(0x204)
-#define S5P_CLK_SRC2           S5P_CLKREG(0x208)
-#define S5P_CLK_SRC3           S5P_CLKREG(0x20C)
-#define S5P_CLK_SRC4           S5P_CLKREG(0x210)
-#define S5P_CLK_SRC5           S5P_CLKREG(0x214)
-#define S5P_CLK_SRC6           S5P_CLKREG(0x218)
-
-#define S5P_CLK_SRC_MASK0      S5P_CLKREG(0x280)
-#define S5P_CLK_SRC_MASK1      S5P_CLKREG(0x284)
-
-#define S5P_CLK_DIV0           S5P_CLKREG(0x300)
-#define S5P_CLK_DIV1           S5P_CLKREG(0x304)
-#define S5P_CLK_DIV2           S5P_CLKREG(0x308)
-#define S5P_CLK_DIV3           S5P_CLKREG(0x30C)
-#define S5P_CLK_DIV4           S5P_CLKREG(0x310)
-#define S5P_CLK_DIV5           S5P_CLKREG(0x314)
-#define S5P_CLK_DIV6           S5P_CLKREG(0x318)
-
-#define S5P_CLKGATE_IP0                S5P_CLKREG(0x460)
-#define S5P_CLKGATE_IP3                S5P_CLKREG(0x46C)
-
-/* CLK_OUT */
-#define S5P_CLK_OUT_SHIFT      (12)
-#define S5P_CLK_OUT_MASK       (0x1F << S5P_CLK_OUT_SHIFT)
-#define S5P_CLK_OUT            S5P_CLKREG(0x500)
-
-#define S5P_CLK_DIV_STAT0      S5P_CLKREG(0x1000)
-#define S5P_CLK_DIV_STAT1      S5P_CLKREG(0x1004)
-
-#define S5P_CLK_MUX_STAT0      S5P_CLKREG(0x1100)
-#define S5P_CLK_MUX_STAT1      S5P_CLKREG(0x1104)
-
-#define S5P_MDNIE_SEL          S5P_CLKREG(0x7008)
-
-/* Register Bit definition */
-#define S5P_EPLL_EN                    (1<<31)
-#define S5P_EPLL_MASK                  0xffffffff
-#define S5P_EPLLVAL(_m, _p, _s)        ((_m) << 16 | ((_p) << 8) | ((_s)))
-
-/* CLKDIV0 */
-#define S5P_CLKDIV0_APLL_SHIFT         (0)
-#define S5P_CLKDIV0_APLL_MASK          (0x7 << S5P_CLKDIV0_APLL_SHIFT)
-#define S5P_CLKDIV0_A2M_SHIFT          (4)
-#define S5P_CLKDIV0_A2M_MASK           (0x7 << S5P_CLKDIV0_A2M_SHIFT)
-#define S5P_CLKDIV0_D0CLK_SHIFT                (16)
-#define S5P_CLKDIV0_D0CLK_MASK         (0xF << S5P_CLKDIV0_D0CLK_SHIFT)
-#define S5P_CLKDIV0_P0CLK_SHIFT                (20)
-#define S5P_CLKDIV0_P0CLK_MASK         (0x7 << S5P_CLKDIV0_P0CLK_SHIFT)
-#define S5P_CLKDIV0_D1CLK_SHIFT                (24)
-#define S5P_CLKDIV0_D1CLK_MASK         (0xF << S5P_CLKDIV0_D1CLK_SHIFT)
-#define S5P_CLKDIV0_P1CLK_SHIFT                (28)
-#define S5P_CLKDIV0_P1CLK_MASK         (0x7 << S5P_CLKDIV0_P1CLK_SHIFT)
-
-/* Clock MUX status Registers */
-#define S5P_CLK_MUX_STAT0_APLL_SHIFT   (0)
-#define S5P_CLK_MUX_STAT0_APLL_MASK    (0x7 << S5P_CLK_MUX_STAT0_APLL_SHIFT)
-#define S5P_CLK_MUX_STAT0_MPLL_SHIFT   (4)
-#define S5P_CLK_MUX_STAT0_MPLL_MASK    (0x7 << S5P_CLK_MUX_STAT0_MPLL_SHIFT)
-#define S5P_CLK_MUX_STAT0_EPLL_SHIFT   (8)
-#define S5P_CLK_MUX_STAT0_EPLL_MASK    (0x7 << S5P_CLK_MUX_STAT0_EPLL_SHIFT)
-#define S5P_CLK_MUX_STAT0_VPLL_SHIFT   (12)
-#define S5P_CLK_MUX_STAT0_VPLL_MASK    (0x7 << S5P_CLK_MUX_STAT0_VPLL_SHIFT)
-#define S5P_CLK_MUX_STAT0_MUXARM_SHIFT (16)
-#define S5P_CLK_MUX_STAT0_MUXARM_MASK  (0x7 << S5P_CLK_MUX_STAT0_MUXARM_SHIFT)
-#define S5P_CLK_MUX_STAT0_MUXD0_SHIFT  (20)
-#define S5P_CLK_MUX_STAT0_MUXD0_MASK   (0x7 << S5P_CLK_MUX_STAT0_MUXD0_SHIFT)
-#define S5P_CLK_MUX_STAT0_MUXD1_SHIFT  (24)
-#define S5P_CLK_MUX_STAT0_MUXD1_MASK   (0x7 << S5P_CLK_MUX_STAT0_MUXD1_SHIFT)
-#define S5P_CLK_MUX_STAT1_D1SYNC_SHIFT (24)
-#define S5P_CLK_MUX_STAT1_D1SYNC_MASK  (0x7 << S5P_CLK_MUX_STAT1_D1SYNC_SHIFT)
-#define S5P_CLK_MUX_STAT1_D0SYNC_SHIFT (28)
-#define S5P_CLK_MUX_STAT1_D0SYNC_MASK  (0x7 << S5P_CLK_MUX_STAT1_D0SYNC_SHIFT)
-
-#endif /* __ASM_ARCH_REGS_CLOCK_H */
diff --git a/arch/arm/mach-s5p6442/include/mach/regs-irq.h b/arch/arm/mach-s5p6442/include/mach/regs-irq.h
deleted file mode 100644 (file)
index 73782b5..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/include/mach/regs-irq.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5P6442 - IRQ register definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_REGS_IRQ_H
-#define __ASM_ARCH_REGS_IRQ_H __FILE__
-
-#include <asm/hardware/vic.h>
-#include <mach/map.h>
-
-#endif /* __ASM_ARCH_REGS_IRQ_H */
diff --git a/arch/arm/mach-s5p6442/include/mach/spi-clocks.h b/arch/arm/mach-s5p6442/include/mach/spi-clocks.h
deleted file mode 100644 (file)
index 7fd8820..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/include/mach/spi-clocks.h
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *     Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __S5P6442_PLAT_SPI_CLKS_H
-#define __S5P6442_PLAT_SPI_CLKS_H __FILE__
-
-#define S5P6442_SPI_SRCCLK_PCLK                0
-#define S5P6442_SPI_SRCCLK_SCLK                1
-
-#endif /* __S5P6442_PLAT_SPI_CLKS_H */
diff --git a/arch/arm/mach-s5p6442/include/mach/system.h b/arch/arm/mach-s5p6442/include/mach/system.h
deleted file mode 100644 (file)
index c30c1cc..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/include/mach/system.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5P6442 - system support header
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H __FILE__
-
-#include <plat/system-reset.h>
-
-static void arch_idle(void)
-{
-       /* nothing here yet */
-}
-
-#endif /* __ASM_ARCH_SYSTEM_H */
diff --git a/arch/arm/mach-s5p6442/include/mach/tick.h b/arch/arm/mach-s5p6442/include/mach/tick.h
deleted file mode 100644 (file)
index e1d4cab..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/include/mach/tick.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * Based on arch/arm/mach-s3c6400/include/mach/tick.h
- *
- * S5P6442 - Timer tick support definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_TICK_H
-#define __ASM_ARCH_TICK_H __FILE__
-
-static inline u32 s3c24xx_ostimer_pending(void)
-{
-       u32 pend = __raw_readl(VA_VIC0 + VIC_RAW_STATUS);
-       return pend & (1 << (IRQ_TIMER4_VIC - S5P_IRQ_VIC0(0)));
-}
-
-#define TICK_MAX       (0xffffffff)
-
-#endif /* __ASM_ARCH_TICK_H */
diff --git a/arch/arm/mach-s5p6442/include/mach/timex.h b/arch/arm/mach-s5p6442/include/mach/timex.h
deleted file mode 100644 (file)
index ff8f2fc..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* arch/arm/mach-s5p6442/include/mach/timex.h
- *
- * Copyright (c) 2003-2010 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S5P6442 - time parameters
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_TIMEX_H
-#define __ASM_ARCH_TIMEX_H
-
-/* CLOCK_TICK_RATE needs to be evaluatable by the cpp, so making it
- * a variable is useless. It seems as long as we make our timers an
- * exact multiple of HZ, any value that makes a 1->1 correspondence
- * for the time conversion functions to/from jiffies is acceptable.
-*/
-
-#define CLOCK_TICK_RATE 12000000
-
-#endif /* __ASM_ARCH_TIMEX_H */
diff --git a/arch/arm/mach-s5p6442/include/mach/uncompress.h b/arch/arm/mach-s5p6442/include/mach/uncompress.h
deleted file mode 100644 (file)
index 5ac7cbe..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/include/mach/uncompress.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5P6442 - uncompress code
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_UNCOMPRESS_H
-#define __ASM_ARCH_UNCOMPRESS_H
-
-#include <mach/map.h>
-#include <plat/uncompress.h>
-
-static void arch_detect_cpu(void)
-{
-       /* we do not need to do any cpu detection here at the moment. */
-}
-
-#endif /* __ASM_ARCH_UNCOMPRESS_H */
diff --git a/arch/arm/mach-s5p6442/include/mach/vmalloc.h b/arch/arm/mach-s5p6442/include/mach/vmalloc.h
deleted file mode 100644 (file)
index 4aa55e5..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* arch/arm/mach-s5p6442/include/mach/vmalloc.h
- *
- * Copyright 2010 Ben Dooks <ben-linux@fluff.org>
- *
- * 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.
- *
- * S5P6442 vmalloc definition
-*/
-
-#ifndef __ASM_ARCH_VMALLOC_H
-#define __ASM_ARCH_VMALLOC_H
-
-#define VMALLOC_END    0xF6000000UL
-
-#endif /* __ASM_ARCH_VMALLOC_H */
diff --git a/arch/arm/mach-s5p6442/init.c b/arch/arm/mach-s5p6442/init.c
deleted file mode 100644 (file)
index 1874bdb..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/s5p6442-init.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-
-#include <plat/cpu.h>
-#include <plat/devs.h>
-#include <plat/s5p6442.h>
-#include <plat/regs-serial.h>
-
-static struct s3c24xx_uart_clksrc s5p6442_serial_clocks[] = {
-       [0] = {
-               .name           = "pclk",
-               .divisor        = 1,
-               .min_baud       = 0,
-               .max_baud       = 0,
-       },
-};
-
-/* uart registration process */
-void __init s5p6442_common_init_uarts(struct s3c2410_uartcfg *cfg, int no)
-{
-       struct s3c2410_uartcfg *tcfg = cfg;
-       u32 ucnt;
-
-       for (ucnt = 0; ucnt < no; ucnt++, tcfg++) {
-               if (!tcfg->clocks) {
-                       tcfg->clocks = s5p6442_serial_clocks;
-                       tcfg->clocks_size = ARRAY_SIZE(s5p6442_serial_clocks);
-               }
-       }
-
-       s3c24xx_init_uartdevs("s5pv210-uart", s5p_uart_resources, cfg, no);
-}
diff --git a/arch/arm/mach-s5p6442/mach-smdk6442.c b/arch/arm/mach-s5p6442/mach-smdk6442.c
deleted file mode 100644 (file)
index eaf6b9c..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/mach-smdk6442.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/i2c.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-
-#include <mach/map.h>
-#include <mach/regs-clock.h>
-
-#include <plat/regs-serial.h>
-#include <plat/s5p6442.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/iic.h>
-
-/* Following are default values for UCON, ULCON and UFCON UART registers */
-#define SMDK6442_UCON_DEFAULT  (S3C2410_UCON_TXILEVEL |        \
-                                S3C2410_UCON_RXILEVEL |        \
-                                S3C2410_UCON_TXIRQMODE |       \
-                                S3C2410_UCON_RXIRQMODE |       \
-                                S3C2410_UCON_RXFIFO_TOI |      \
-                                S3C2443_UCON_RXERR_IRQEN)
-
-#define SMDK6442_ULCON_DEFAULT S3C2410_LCON_CS8
-
-#define SMDK6442_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE |       \
-                                S5PV210_UFCON_TXTRIG4 |        \
-                                S5PV210_UFCON_RXTRIG4)
-
-static struct s3c2410_uartcfg smdk6442_uartcfgs[] __initdata = {
-       [0] = {
-               .hwport         = 0,
-               .flags          = 0,
-               .ucon           = SMDK6442_UCON_DEFAULT,
-               .ulcon          = SMDK6442_ULCON_DEFAULT,
-               .ufcon          = SMDK6442_UFCON_DEFAULT,
-       },
-       [1] = {
-               .hwport         = 1,
-               .flags          = 0,
-               .ucon           = SMDK6442_UCON_DEFAULT,
-               .ulcon          = SMDK6442_ULCON_DEFAULT,
-               .ufcon          = SMDK6442_UFCON_DEFAULT,
-       },
-       [2] = {
-               .hwport         = 2,
-               .flags          = 0,
-               .ucon           = SMDK6442_UCON_DEFAULT,
-               .ulcon          = SMDK6442_ULCON_DEFAULT,
-               .ufcon          = SMDK6442_UFCON_DEFAULT,
-       },
-};
-
-static struct platform_device *smdk6442_devices[] __initdata = {
-       &s3c_device_i2c0,
-       &samsung_asoc_dma,
-       &s5p6442_device_iis0,
-       &s3c_device_wdt,
-};
-
-static struct i2c_board_info smdk6442_i2c_devs0[] __initdata = {
-       { I2C_BOARD_INFO("wm8580", 0x1b), },
-};
-
-static void __init smdk6442_map_io(void)
-{
-       s5p_init_io(NULL, 0, S5P_VA_CHIPID);
-       s3c24xx_init_clocks(12000000);
-       s3c24xx_init_uarts(smdk6442_uartcfgs, ARRAY_SIZE(smdk6442_uartcfgs));
-}
-
-static void __init smdk6442_machine_init(void)
-{
-       s3c_i2c0_set_platdata(NULL);
-       i2c_register_board_info(0, smdk6442_i2c_devs0,
-                       ARRAY_SIZE(smdk6442_i2c_devs0));
-       platform_add_devices(smdk6442_devices, ARRAY_SIZE(smdk6442_devices));
-}
-
-MACHINE_START(SMDK6442, "SMDK6442")
-       /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
-       .boot_params    = S5P_PA_SDRAM + 0x100,
-       .init_irq       = s5p6442_init_irq,
-       .map_io         = smdk6442_map_io,
-       .init_machine   = smdk6442_machine_init,
-       .timer          = &s3c24xx_timer,
-MACHINE_END
diff --git a/arch/arm/mach-s5p6442/setup-i2c0.c b/arch/arm/mach-s5p6442/setup-i2c0.c
deleted file mode 100644 (file)
index aad8565..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/* linux/arch/arm/mach-s5p6442/setup-i2c0.c
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * I2C0 GPIO configuration.
- *
- * Based on plat-s3c64xx/setup-i2c0.c
- *
- * 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/types.h>
-#include <linux/gpio.h>
-
-struct platform_device; /* don't need the contents */
-
-#include <plat/gpio-cfg.h>
-#include <plat/iic.h>
-
-void s3c_i2c0_cfg_gpio(struct platform_device *dev)
-{
-       s3c_gpio_cfgall_range(S5P6442_GPD1(0), 2,
-                             S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
-}
index eecab57d2e5d4f4727b43d51818d59c5968df51d..a5e6e608b498ccd1b285123550dc13ad5a5e9d1e 100644 (file)
@@ -11,7 +11,7 @@ obj-                          :=
 
 # Core support for S5PC100 system
 
-obj-$(CONFIG_CPU_S5PC100)      += cpu.o init.o clock.o gpiolib.o
+obj-$(CONFIG_CPU_S5PC100)      += cpu.o init.o clock.o
 obj-$(CONFIG_CPU_S5PC100)      += setup-i2c0.o
 obj-$(CONFIG_CPU_S5PC100)      += dma.o
 
index 11f17907b4e8ff7024400975851f74fc04f5617b..50907aca006c4d49d70432cca4fe09e69310158a 100644 (file)
@@ -12,7 +12,7 @@ obj-                          :=
 
 # Core support for S5PV210 system
 
-obj-$(CONFIG_CPU_S5PV210)      += cpu.o init.o clock.o dma.o gpiolib.o
+obj-$(CONFIG_CPU_S5PV210)      += cpu.o init.o clock.o dma.o
 obj-$(CONFIG_CPU_S5PV210)      += setup-i2c0.o
 obj-$(CONFIG_S5PV210_PM)       += pm.o sleep.o
 obj-$(CONFIG_CPU_FREQ)         += cpufreq.o
index 22046e2f53c2a17d1a064f7257696551ff325677..153af8b359ec00994994dc3abf9c052ddd39b3cb 100644 (file)
@@ -101,12 +101,14 @@ static void s5pv210_set_refresh(enum s5pv210_dmc_port ch, unsigned long freq)
        unsigned long tmp, tmp1;
        void __iomem *reg = NULL;
 
-       if (ch == DMC0)
+       if (ch == DMC0) {
                reg = (S5P_VA_DMC0 + 0x30);
-       else if (ch == DMC1)
+       } else if (ch == DMC1) {
                reg = (S5P_VA_DMC1 + 0x30);
-       else
+       } else {
                printk(KERN_ERR "Cannot find DMC port\n");
+               return;
+       }
 
        /* Find current DRAM frequency */
        tmp = s5pv210_dram_conf[ch].freq;
index e2507f66f9d5b8f68c9beab25c738e3891c43f3c..612b27000c3e3863cd50e5aa3b4b15fc1bfc2586 100644 (file)
@@ -30,6 +30,11 @@ obj-$(CONFIG_ARCH_SH7377)    += entry-intc.o
 obj-$(CONFIG_ARCH_SH7372)      += entry-intc.o
 obj-$(CONFIG_ARCH_SH73A0)      += entry-gic.o
 
+# PM objects
+obj-$(CONFIG_SUSPEND)          += suspend.o
+obj-$(CONFIG_CPU_IDLE)         += cpuidle.o
+obj-$(CONFIG_ARCH_SH7372)      += pm-sh7372.o sleep-sh7372.o
+
 # Board objects
 obj-$(CONFIG_MACH_G3EVM)       += board-g3evm.o
 obj-$(CONFIG_MACH_G4EVM)       += board-g4evm.o
index 3e6f0aab460bd2382552a5723c738a739fbc4610..1e2aba23e0d6d56ea6ddcd696937344027493e8b 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/input/sh_keysc.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/sh_mmcif.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
+#include <linux/mfd/tmio.h>
 #include <linux/sh_clk.h>
 #include <video/sh_mobile_lcdc.h>
 #include <video/sh_mipi_dsi.h>
@@ -156,10 +158,19 @@ static struct resource sh_mmcif_resources[] = {
        },
 };
 
+static struct sh_mmcif_dma sh_mmcif_dma = {
+       .chan_priv_rx   = {
+               .slave_id       = SHDMA_SLAVE_MMCIF_RX,
+       },
+       .chan_priv_tx   = {
+               .slave_id       = SHDMA_SLAVE_MMCIF_TX,
+       },
+};
 static struct sh_mmcif_plat_data sh_mmcif_platdata = {
        .sup_pclk       = 0,
        .ocr            = MMC_VDD_165_195,
        .caps           = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE,
+       .dma            = &sh_mmcif_dma,
 };
 
 static struct platform_device mmc_device = {
@@ -296,11 +307,13 @@ static struct platform_device lcdc0_device = {
 /* MIPI-DSI */
 static struct resource mipidsi0_resources[] = {
        [0] = {
+               .name   = "DSI0",
                .start  = 0xfeab0000,
                .end    = 0xfeab3fff,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
+               .name   = "DSI0",
                .start  = 0xfeab4000,
                .end    = 0xfeab7fff,
                .flags  = IORESOURCE_MEM,
@@ -325,6 +338,87 @@ static struct platform_device mipidsi0_device = {
        },
 };
 
+static struct sh_mobile_sdhi_info sdhi0_info = {
+       .dma_slave_tx   = SHDMA_SLAVE_SDHI0_TX,
+       .dma_slave_rx   = SHDMA_SLAVE_SDHI0_RX,
+       .tmio_caps      = MMC_CAP_SD_HIGHSPEED,
+       .tmio_ocr_mask  = MMC_VDD_27_28 | MMC_VDD_28_29,
+};
+
+static struct resource sdhi0_resources[] = {
+       [0] = {
+               .name   = "SDHI0",
+               .start  = 0xee100000,
+               .end    = 0xee1000ff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = gic_spi(83),
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = gic_spi(84),
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = gic_spi(85),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device sdhi0_device = {
+       .name           = "sh_mobile_sdhi",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(sdhi0_resources),
+       .resource       = sdhi0_resources,
+       .dev    = {
+               .platform_data  = &sdhi0_info,
+       },
+};
+
+void ag5evm_sdhi1_set_pwr(struct platform_device *pdev, int state)
+{
+       gpio_set_value(GPIO_PORT114, state);
+}
+
+static struct sh_mobile_sdhi_info sh_sdhi1_platdata = {
+       .tmio_flags     = TMIO_MMC_WRPROTECT_DISABLE,
+       .tmio_caps      = MMC_CAP_NONREMOVABLE | MMC_CAP_SDIO_IRQ,
+       .tmio_ocr_mask  = MMC_VDD_32_33 | MMC_VDD_33_34,
+       .set_pwr        = ag5evm_sdhi1_set_pwr,
+};
+
+static struct resource sdhi1_resources[] = {
+       [0] = {
+               .name   = "SDHI1",
+               .start  = 0xee120000,
+               .end    = 0xee1200ff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = gic_spi(87),
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = gic_spi(88),
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = gic_spi(89),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device sdhi1_device = {
+       .name           = "sh_mobile_sdhi",
+       .id             = 1,
+       .dev            = {
+               .platform_data  = &sh_sdhi1_platdata,
+       },
+       .num_resources  = ARRAY_SIZE(sdhi1_resources),
+       .resource       = sdhi1_resources,
+};
+
 static struct platform_device *ag5evm_devices[] __initdata = {
        &eth_device,
        &keysc_device,
@@ -333,6 +427,8 @@ static struct platform_device *ag5evm_devices[] __initdata = {
        &irda_device,
        &lcdc0_device,
        &mipidsi0_device,
+       &sdhi0_device,
+       &sdhi1_device,
 };
 
 static struct map_desc ag5evm_io_desc[] __initdata = {
@@ -454,6 +550,26 @@ static void __init ag5evm_init(void)
        /* MIPI-DSI clock setup */
        __raw_writel(0x2a809010, DSI0PHYCR);
 
+       /* enable SDHI0 on CN15 [SD I/F] */
+       gpio_request(GPIO_FN_SDHICD0, NULL);
+       gpio_request(GPIO_FN_SDHIWP0, NULL);
+       gpio_request(GPIO_FN_SDHICMD0, NULL);
+       gpio_request(GPIO_FN_SDHICLK0, NULL);
+       gpio_request(GPIO_FN_SDHID0_3, NULL);
+       gpio_request(GPIO_FN_SDHID0_2, NULL);
+       gpio_request(GPIO_FN_SDHID0_1, NULL);
+       gpio_request(GPIO_FN_SDHID0_0, NULL);
+
+       /* enable SDHI1 on CN4 [WLAN I/F] */
+       gpio_request(GPIO_FN_SDHICLK1, NULL);
+       gpio_request(GPIO_FN_SDHICMD1_PU, NULL);
+       gpio_request(GPIO_FN_SDHID1_3_PU, NULL);
+       gpio_request(GPIO_FN_SDHID1_2_PU, NULL);
+       gpio_request(GPIO_FN_SDHID1_1_PU, NULL);
+       gpio_request(GPIO_FN_SDHID1_0_PU, NULL);
+       gpio_request(GPIO_PORT114, "sdhi1_power");
+       gpio_direction_output(GPIO_PORT114, 0);
+
 #ifdef CONFIG_CACHE_L2X0
        /* Shared attribute override enable, 64K*8way */
        l2x0_init(__io(0xf0100000), 0x00460000, 0xc2000fff);
index 1e35fa976d6450064e6a6b616d95864a7e73103b..f6b687f61c28ebe4def01c748e0a576a53a362d9 100644 (file)
@@ -249,6 +249,29 @@ static int slot_cn7_get_cd(struct platform_device *pdev)
 {
        return !gpio_get_value(GPIO_PORT41);
 }
+/* MERAM */
+static struct sh_mobile_meram_info meram_info = {
+       .addr_mode      = SH_MOBILE_MERAM_MODE1,
+};
+
+static struct resource meram_resources[] = {
+       [0] = {
+               .name   = "MERAM",
+               .start  = 0xe8000000,
+               .end    = 0xe81fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device meram_device = {
+       .name           = "sh_mobile_meram",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(meram_resources),
+       .resource       = meram_resources,
+       .dev            = {
+               .platform_data = &meram_info,
+       },
+};
 
 /* SH_MMCIF */
 static struct resource sh_mmcif_resources[] = {
@@ -316,8 +339,16 @@ static struct resource sdhi0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = evt2irq(0x0e00) /* SDHI0 */,
-               .flags  = IORESOURCE_IRQ,
+               .start  = evt2irq(0x0e00) /* SDHI0_SDHI0I0 */,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = evt2irq(0x0e20) /* SDHI0_SDHI0I1 */,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = evt2irq(0x0e40) /* SDHI0_SDHI0I2 */,
+               .flags  = IORESOURCE_IRQ,
        },
 };
 
@@ -349,8 +380,16 @@ static struct resource sdhi1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = evt2irq(0x0e80),
-               .flags  = IORESOURCE_IRQ,
+               .start  = evt2irq(0x0e80), /* SDHI1_SDHI1I0 */
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = evt2irq(0x0ea0), /* SDHI1_SDHI1I1 */
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = evt2irq(0x0ec0), /* SDHI1_SDHI1I2 */
+               .flags  = IORESOURCE_IRQ,
        },
 };
 
@@ -431,13 +470,29 @@ const static struct fb_videomode ap4evb_lcdc_modes[] = {
 #endif
        },
 };
+static struct sh_mobile_meram_cfg lcd_meram_cfg = {
+       .icb[0] = {
+               .marker_icb     = 28,
+               .cache_icb      = 24,
+               .meram_offset   = 0x0,
+               .meram_size     = 0x40,
+       },
+       .icb[1] = {
+               .marker_icb     = 29,
+               .cache_icb      = 25,
+               .meram_offset   = 0x40,
+               .meram_size     = 0x40,
+       },
+};
 
 static struct sh_mobile_lcdc_info lcdc_info = {
+       .meram_dev = &meram_info,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
                .bpp = 16,
                .lcd_cfg = ap4evb_lcdc_modes,
                .num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes),
+               .meram_cfg = &lcd_meram_cfg,
        }
 };
 
@@ -708,15 +763,31 @@ static struct platform_device fsi_device = {
 static struct platform_device fsi_ak4643_device = {
        .name           = "sh_fsi2_a_ak4643",
 };
+static struct sh_mobile_meram_cfg hdmi_meram_cfg = {
+       .icb[0] = {
+               .marker_icb     = 30,
+               .cache_icb      = 26,
+               .meram_offset   = 0x80,
+               .meram_size     = 0x100,
+       },
+       .icb[1] = {
+               .marker_icb     = 31,
+               .cache_icb      = 27,
+               .meram_offset   = 0x180,
+               .meram_size     = 0x100,
+       },
+};
 
 static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = {
        .clock_source = LCDC_CLK_EXTERNAL,
+       .meram_dev = &meram_info,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
                .bpp = 16,
                .interface_type = RGB24,
                .clock_divider = 1,
                .flags = LCDC_FLAGS_DWPOL,
+               .meram_cfg = &hdmi_meram_cfg,
        }
 };
 
@@ -945,6 +1016,7 @@ static struct platform_device *ap4evb_devices[] __initdata = {
        &csi2_device,
        &ceu_device,
        &ap4evb_camera,
+       &meram_device,
 };
 
 static void __init hdmi_init_pm_clock(void)
@@ -980,11 +1052,6 @@ static void __init hdmi_init_pm_clock(void)
                goto out;
        }
 
-       ret = clk_enable(&sh7372_pllc2_clk);
-       if (ret < 0) {
-               pr_err("Cannot enable pllc2 clock\n");
-               goto out;
-       }
        pr_debug("PLLC2 set frequency %lu\n", rate);
 
        ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk);
@@ -1343,6 +1410,7 @@ static void __init ap4evb_init(void)
 
        hdmi_init_pm_clock();
        fsi_init_pm_clock();
+       sh7372_pm_init();
 }
 
 static void __init ap4evb_timer_init(void)
index c87a7b7c583278f2f43bbf964c74c02f8b7f84d0..8e3c5559f27f937c68f059c1c89a525945a498b4 100644 (file)
@@ -205,7 +205,7 @@ static struct resource sdhi0_resources[] = {
        [0] = {
                .name   = "SDHI0",
                .start  = 0xe6d50000,
-               .end    = 0xe6d50nff,
+               .end    = 0xe6d500ff,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
index 7da2ca24229dc296f41795cd788c5f989451abb1..7e1d375843211e52944720a562a5c580dbe20149 100644 (file)
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
+#include <linux/pm_runtime.h>
 #include <linux/smsc911x.h>
 #include <linux/sh_intc.h>
 #include <linux/tca6416_keypad.h>
 #include <linux/usb/r8a66597.h>
+#include <linux/usb/renesas_usbhs.h>
 
 #include <video/sh_mobile_hdmi.h>
 #include <video/sh_mobile_lcdc.h>
  * ------+--------------------+--------------------+-------
  * IRQ0  | ICR1A.IRQ0SA=0010  | SDHI2 card detect  | Low
  * IRQ6  | ICR1A.IRQ6SA=0011  | Ether(LAN9220)     | High
- * IRQ7  | ICR1A.IRQ7SA=0010  | LCD Tuch Panel     | Low
+ * IRQ7  | ICR1A.IRQ7SA=0010  | LCD Touch Panel    | Low
  * IRQ8  | ICR2A.IRQ8SA=0010  | MMC/SD card detect | Low
  * IRQ9  | ICR2A.IRQ9SA=0010  | KEY(TCA6408)       | Low
  * IRQ21 | ICR4A.IRQ21SA=0011 | Sensor(ADXL345)    | High
  * open      | external VBUS | Function
  *
  * *1
- * CN31 is used as Host in Linux.
+ * CN31 is used as
+ * CONFIG_USB_R8A66597_HCD     Host
+ * CONFIG_USB_RENESAS_USBHS    Function
+ *
+ * CAUTION
+ *
+ * renesas_usbhs driver can use external interrupt mode
+ * (which come from USB-PHY) or autonomy mode (it use own interrupt)
+ * for detecting connection/disconnection when Function.
+ * USB will be power OFF while it has been disconnecting
+ * if external interrupt mode, and it is always power ON if autonomy mode,
+ *
+ * mackerel can not use external interrupt (IRQ7-PORT167) mode on "USB0",
+ * because Touchscreen is using IRQ7-PORT40.
+ * It is impossible to use IRQ7 demux on this board.
+ *
+ * We can use external interrupt mode USB-Function on "USB1".
+ * USB1 can become Host by r8a66597, and become Function by renesas_usbhs.
+ * But don't select both drivers in same time.
+ * These uses same IRQ number for request_irq(), and aren't supporting
+ * IRQF_SHARED / IORESOURCE_IRQ_SHAREABLE.
+ *
+ * Actually these are old/new version of USB driver.
+ * This mean its register will be broken if it supports shared IRQ,
  */
 
 /*
  * FIXME !!
  *
  * gpio_no_direction
+ * gpio_pull_down
  * are quick_hack.
  *
  * current gpio frame work doesn't have
@@ -196,6 +222,16 @@ static void __init gpio_no_direction(u32 addr)
        __raw_writeb(0x00, addr);
 }
 
+static void __init gpio_pull_down(u32 addr)
+{
+       u8 data = __raw_readb(addr);
+
+       data &= 0x0F;
+       data |= 0xA0;
+
+       __raw_writeb(data, addr);
+}
+
 /* MTD */
 static struct mtd_partition nor_flash_partitions[] = {
        {
@@ -279,6 +315,30 @@ static struct platform_device smc911x_device = {
        },
 };
 
+/* MERAM */
+static struct sh_mobile_meram_info mackerel_meram_info = {
+       .addr_mode      = SH_MOBILE_MERAM_MODE1,
+};
+
+static struct resource meram_resources[] = {
+       [0] = {
+               .name   = "MERAM",
+               .start  = 0xe8000000,
+               .end    = 0xe81fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device meram_device = {
+       .name           = "sh_mobile_meram",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(meram_resources),
+       .resource       = meram_resources,
+       .dev            = {
+               .platform_data = &mackerel_meram_info,
+       },
+};
+
 /* LCDC */
 static struct fb_videomode mackerel_lcdc_modes[] = {
        {
@@ -307,7 +367,23 @@ static int mackerel_get_brightness(void *board_data)
        return gpio_get_value(GPIO_PORT31);
 }
 
+static struct sh_mobile_meram_cfg lcd_meram_cfg = {
+       .icb[0] = {
+               .marker_icb     = 28,
+               .cache_icb      = 24,
+               .meram_offset   = 0x0,
+               .meram_size     = 0x40,
+       },
+       .icb[1] = {
+               .marker_icb     = 29,
+               .cache_icb      = 25,
+               .meram_offset   = 0x40,
+               .meram_size     = 0x40,
+       },
+};
+
 static struct sh_mobile_lcdc_info lcdc_info = {
+       .meram_dev = &mackerel_meram_info,
        .clock_source = LCDC_CLK_BUS,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
@@ -327,6 +403,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
                        .name = "sh_mobile_lcdc_bl",
                        .max_brightness = 1,
                },
+               .meram_cfg = &lcd_meram_cfg,
        }
 };
 
@@ -353,8 +430,23 @@ static struct platform_device lcdc_device = {
        },
 };
 
+static struct sh_mobile_meram_cfg hdmi_meram_cfg = {
+       .icb[0] = {
+               .marker_icb     = 30,
+               .cache_icb      = 26,
+               .meram_offset   = 0x80,
+               .meram_size     = 0x100,
+       },
+       .icb[1] = {
+               .marker_icb     = 31,
+               .cache_icb      = 27,
+               .meram_offset   = 0x180,
+               .meram_size     = 0x100,
+       },
+};
 /* HDMI */
 static struct sh_mobile_lcdc_info hdmi_lcdc_info = {
+       .meram_dev = &mackerel_meram_info,
        .clock_source = LCDC_CLK_EXTERNAL,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
@@ -362,6 +454,7 @@ static struct sh_mobile_lcdc_info hdmi_lcdc_info = {
                .interface_type = RGB24,
                .clock_divider = 1,
                .flags = LCDC_FLAGS_DWPOL,
+               .meram_cfg = &hdmi_meram_cfg,
        }
 };
 
@@ -458,12 +551,6 @@ static void __init hdmi_init_pm_clock(void)
                goto out;
        }
 
-       ret = clk_enable(&sh7372_pllc2_clk);
-       if (ret < 0) {
-               pr_err("Cannot enable pllc2 clock\n");
-               goto out;
-       }
-
        pr_debug("PLLC2 set frequency %lu\n", rate);
 
        ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk);
@@ -475,7 +562,121 @@ out:
                clk_put(hdmi_ick);
 }
 
-/* USB1 (Host) */
+/* USBHS0 is connected to CN22 which takes a USB Mini-B plug
+ *
+ * The sh7372 SoC has IRQ7 set aside for USBHS0 hotplug,
+ * but on this particular board IRQ7 is already used by
+ * the touch screen. This leaves us with software polling.
+ */
+#define USBHS0_POLL_INTERVAL (HZ * 5)
+
+struct usbhs_private {
+       unsigned int usbphyaddr;
+       unsigned int usbcrcaddr;
+       struct renesas_usbhs_platform_info info;
+       struct delayed_work work;
+       struct platform_device *pdev;
+};
+
+#define usbhs_get_priv(pdev)                           \
+       container_of(renesas_usbhs_get_info(pdev),      \
+                    struct usbhs_private, info)
+
+#define usbhs_is_connected(priv)                       \
+       (!((1 << 7) & __raw_readw(priv->usbcrcaddr)))
+
+static int usbhs_get_vbus(struct platform_device *pdev)
+{
+       return usbhs_is_connected(usbhs_get_priv(pdev));
+}
+
+static void usbhs_phy_reset(struct platform_device *pdev)
+{
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+       /* init phy */
+       __raw_writew(0x8a0a, priv->usbcrcaddr);
+}
+
+static int usbhs0_get_id(struct platform_device *pdev)
+{
+       return USBHS_GADGET;
+}
+
+static void usbhs0_work_function(struct work_struct *work)
+{
+       struct usbhs_private *priv = container_of(work, struct usbhs_private,
+                                                 work.work);
+
+       renesas_usbhs_call_notify_hotplug(priv->pdev);
+       schedule_delayed_work(&priv->work, USBHS0_POLL_INTERVAL);
+}
+
+static int usbhs0_hardware_init(struct platform_device *pdev)
+{
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+       priv->pdev = pdev;
+       INIT_DELAYED_WORK(&priv->work, usbhs0_work_function);
+       schedule_delayed_work(&priv->work, USBHS0_POLL_INTERVAL);
+       return 0;
+}
+
+static void usbhs0_hardware_exit(struct platform_device *pdev)
+{
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+       cancel_delayed_work_sync(&priv->work);
+}
+
+static struct usbhs_private usbhs0_private = {
+       .usbcrcaddr     = 0xe605810c,           /* USBCR2 */
+       .info = {
+               .platform_callback = {
+                       .hardware_init  = usbhs0_hardware_init,
+                       .hardware_exit  = usbhs0_hardware_exit,
+                       .phy_reset      = usbhs_phy_reset,
+                       .get_id         = usbhs0_get_id,
+                       .get_vbus       = usbhs_get_vbus,
+               },
+               .driver_param = {
+                       .buswait_bwait  = 4,
+               },
+       },
+};
+
+static struct resource usbhs0_resources[] = {
+       [0] = {
+               .name   = "USBHS0",
+               .start  = 0xe6890000,
+               .end    = 0xe68900e6 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x1ca0) /* USB0_USB0I0 */,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device usbhs0_device = {
+       .name   = "renesas_usbhs",
+       .id     = 0,
+       .dev = {
+               .platform_data          = &usbhs0_private.info,
+       },
+       .num_resources  = ARRAY_SIZE(usbhs0_resources),
+       .resource       = usbhs0_resources,
+};
+
+/* USBHS1 is connected to CN31 which takes a USB Mini-AB plug
+ *
+ * Use J30 to select between Host and Function. This setting
+ * can however not be detected by software. Hotplug of USBHS1
+ * is provided via IRQ8.
+ */
+#define IRQ8 evt2irq(0x0300)
+
+/* USBHS1 USB Host support via r8a66597_hcd */
 static void usb1_host_port_power(int port, int power)
 {
        if (!power) /* only power-on is supported for now */
@@ -492,9 +693,9 @@ static struct r8a66597_platdata usb1_host_data = {
 
 static struct resource usb1_host_resources[] = {
        [0] = {
-               .name   = "USBHS",
-               .start  = 0xE68B0000,
-               .end    = 0xE68B00E6 - 1,
+               .name   = "USBHS1",
+               .start  = 0xe68b0000,
+               .end    = 0xe68b00e6 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -515,6 +716,127 @@ static struct platform_device usb1_host_device = {
        .resource       = usb1_host_resources,
 };
 
+/* USBHS1 USB Function support via renesas_usbhs */
+
+#define USB_PHY_MODE           (1 << 4)
+#define USB_PHY_INT_EN         ((1 << 3) | (1 << 2))
+#define USB_PHY_ON             (1 << 1)
+#define USB_PHY_OFF            (1 << 0)
+#define USB_PHY_INT_CLR                (USB_PHY_ON | USB_PHY_OFF)
+
+static irqreturn_t usbhs1_interrupt(int irq, void *data)
+{
+       struct platform_device *pdev = data;
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+       dev_dbg(&pdev->dev, "%s\n", __func__);
+
+       renesas_usbhs_call_notify_hotplug(pdev);
+
+       /* clear status */
+       __raw_writew(__raw_readw(priv->usbphyaddr) | USB_PHY_INT_CLR,
+                    priv->usbphyaddr);
+
+       return IRQ_HANDLED;
+}
+
+static int usbhs1_hardware_init(struct platform_device *pdev)
+{
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+       int ret;
+
+       /* clear interrupt status */
+       __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->usbphyaddr);
+
+       ret = request_irq(IRQ8, usbhs1_interrupt, IRQF_TRIGGER_HIGH,
+                         dev_name(&pdev->dev), pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "request_irq err\n");
+               return ret;
+       }
+
+       /* enable USB phy interrupt */
+       __raw_writew(USB_PHY_MODE | USB_PHY_INT_EN, priv->usbphyaddr);
+
+       return 0;
+}
+
+static void usbhs1_hardware_exit(struct platform_device *pdev)
+{
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+       /* clear interrupt status */
+       __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->usbphyaddr);
+
+       free_irq(IRQ8, pdev);
+}
+
+static int usbhs1_get_id(struct platform_device *pdev)
+{
+       return USBHS_GADGET;
+}
+
+static u32 usbhs1_pipe_cfg[] = {
+       USB_ENDPOINT_XFER_CONTROL,
+       USB_ENDPOINT_XFER_ISOC,
+       USB_ENDPOINT_XFER_ISOC,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_INT,
+       USB_ENDPOINT_XFER_INT,
+       USB_ENDPOINT_XFER_INT,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usbhs_private usbhs1_private = {
+       .usbphyaddr     = 0xe60581e2,           /* USBPHY1INTAP */
+       .usbcrcaddr     = 0xe6058130,           /* USBCR4 */
+       .info = {
+               .platform_callback = {
+                       .hardware_init  = usbhs1_hardware_init,
+                       .hardware_exit  = usbhs1_hardware_exit,
+                       .get_id         = usbhs1_get_id,
+                       .phy_reset      = usbhs_phy_reset,
+                       .get_vbus       = usbhs_get_vbus,
+               },
+               .driver_param = {
+                       .buswait_bwait  = 4,
+                       .pipe_type      = usbhs1_pipe_cfg,
+                       .pipe_size      = ARRAY_SIZE(usbhs1_pipe_cfg),
+               },
+       },
+};
+
+static struct resource usbhs1_resources[] = {
+       [0] = {
+               .name   = "USBHS1",
+               .start  = 0xe68b0000,
+               .end    = 0xe68b00e6 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x1ce0) /* USB1_USB1I0 */,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device usbhs1_device = {
+       .name   = "renesas_usbhs",
+       .id     = 1,
+       .dev = {
+               .platform_data          = &usbhs1_private.info,
+       },
+       .num_resources  = ARRAY_SIZE(usbhs1_resources),
+       .resource       = usbhs1_resources,
+};
+
 /* LED */
 static struct gpio_led mackerel_leds[] = {
        {
@@ -676,6 +998,17 @@ static int slot_cn7_get_cd(struct platform_device *pdev)
 }
 
 /* SDHI0 */
+static irqreturn_t mackerel_sdhi0_gpio_cd(int irq, void *arg)
+{
+       struct device *dev = arg;
+       struct sh_mobile_sdhi_info *info = dev->platform_data;
+       struct tmio_mmc_data *pdata = info->pdata;
+
+       tmio_mmc_cd_wakeup(pdata);
+
+       return IRQ_HANDLED;
+}
+
 static struct sh_mobile_sdhi_info sdhi0_info = {
        .dma_slave_tx   = SHDMA_SLAVE_SDHI0_TX,
        .dma_slave_rx   = SHDMA_SLAVE_SDHI0_RX,
@@ -690,7 +1023,15 @@ static struct resource sdhi0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = evt2irq(0x0e00) /* SDHI0 */,
+               .start  = evt2irq(0x0e00) /* SDHI0_SDHI0I0 */,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = evt2irq(0x0e20) /* SDHI0_SDHI0I1 */,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = evt2irq(0x0e40) /* SDHI0_SDHI0I2 */,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -705,7 +1046,7 @@ static struct platform_device sdhi0_device = {
        },
 };
 
-#if !defined(CONFIG_MMC_SH_MMCIF)
+#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
 /* SDHI1 */
 static struct sh_mobile_sdhi_info sdhi1_info = {
        .dma_slave_tx   = SHDMA_SLAVE_SDHI1_TX,
@@ -725,7 +1066,15 @@ static struct resource sdhi1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = evt2irq(0x0e80),
+               .start  = evt2irq(0x0e80), /* SDHI1_SDHI1I0 */
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = evt2irq(0x0ea0), /* SDHI1_SDHI1I1 */
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = evt2irq(0x0ec0), /* SDHI1_SDHI1I2 */
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -768,7 +1117,15 @@ static struct resource sdhi2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = evt2irq(0x1200),
+               .start  = evt2irq(0x1200), /* SDHI2_SDHI2I0 */
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = evt2irq(0x1220), /* SDHI2_SDHI2I1 */
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = evt2irq(0x1240), /* SDHI2_SDHI2I2 */
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -803,6 +1160,15 @@ static struct resource sh_mmcif_resources[] = {
        },
 };
 
+static struct sh_mmcif_dma sh_mmcif_dma = {
+       .chan_priv_rx   = {
+               .slave_id       = SHDMA_SLAVE_MMCIF_RX,
+       },
+       .chan_priv_tx   = {
+               .slave_id       = SHDMA_SLAVE_MMCIF_TX,
+       },
+};
+
 static struct sh_mmcif_plat_data sh_mmcif_plat = {
        .sup_pclk       = 0,
        .ocr            = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
@@ -810,6 +1176,7 @@ static struct sh_mmcif_plat_data sh_mmcif_plat = {
                          MMC_CAP_8_BIT_DATA |
                          MMC_CAP_NEEDS_POLL,
        .get_cd         = slot_cn7_get_cd,
+       .dma            = &sh_mmcif_dma,
 };
 
 static struct platform_device sh_mmcif_device = {
@@ -858,37 +1225,23 @@ static struct soc_camera_link camera_link = {
        .priv           = &camera_info,
 };
 
-static void dummy_release(struct device *dev)
+static struct platform_device *camera_device;
+
+static void mackerel_camera_release(struct device *dev)
 {
+       soc_camera_platform_release(&camera_device);
 }
 
-static struct platform_device camera_device = {
-       .name           = "soc_camera_platform",
-       .dev            = {
-               .platform_data  = &camera_info,
-               .release        = dummy_release,
-       },
-};
-
 static int mackerel_camera_add(struct soc_camera_link *icl,
                               struct device *dev)
 {
-       if (icl != &camera_link)
-               return -ENODEV;
-
-       camera_info.dev = dev;
-
-       return platform_device_register(&camera_device);
+       return soc_camera_platform_add(icl, dev, &camera_device, &camera_link,
+                                      mackerel_camera_release, 0);
 }
 
 static void mackerel_camera_del(struct soc_camera_link *icl)
 {
-       if (icl != &camera_link)
-               return;
-
-       platform_device_unregister(&camera_device);
-       memset(&camera_device.dev.kobj, 0,
-              sizeof(camera_device.dev.kobj));
+       soc_camera_platform_del(icl, camera_device, &camera_link);
 }
 
 static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
@@ -934,13 +1287,15 @@ static struct platform_device *mackerel_devices[] __initdata = {
        &nor_flash_device,
        &smc911x_device,
        &lcdc_device,
+       &usbhs0_device,
        &usb1_host_device,
+       &usbhs1_device,
        &leds_device,
        &fsi_device,
        &fsi_ak4643_device,
        &fsi_hdmi_device,
        &sdhi0_device,
-#if !defined(CONFIG_MMC_SH_MMCIF)
+#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
        &sdhi1_device,
 #endif
        &sdhi2_device,
@@ -949,6 +1304,7 @@ static struct platform_device *mackerel_devices[] __initdata = {
        &mackerel_camera,
        &hdmi_lcdc_device,
        &hdmi_device,
+       &meram_device,
 };
 
 /* Keypad Initialization */
@@ -1030,12 +1386,15 @@ static void __init mackerel_map_io(void)
 
 #define GPIO_PORT9CR   0xE6051009
 #define GPIO_PORT10CR  0xE605100A
+#define GPIO_PORT167CR 0xE60520A7
+#define GPIO_PORT168CR 0xE60520A8
 #define SRCR4          0xe61580bc
 #define USCCR1         0xE6058144
 static void __init mackerel_init(void)
 {
        u32 srcr4;
        struct clk *clk;
+       int ret;
 
        sh7372_pinmux_init();
 
@@ -1081,16 +1440,17 @@ static void __init mackerel_init(void)
        gpio_request(GPIO_PORT151, NULL); /* LCDDON */
        gpio_direction_output(GPIO_PORT151, 1);
 
-       /* USB enable */
-       gpio_request(GPIO_FN_VBUS0_1,    NULL);
-       gpio_request(GPIO_FN_IDIN_1_18,  NULL);
-       gpio_request(GPIO_FN_PWEN_1_115, NULL);
-       gpio_request(GPIO_FN_OVCN_1_114, NULL);
-       gpio_request(GPIO_FN_EXTLP_1,    NULL);
-       gpio_request(GPIO_FN_OVCN2_1,    NULL);
+       /* USBHS0 */
+       gpio_request(GPIO_FN_VBUS0_0, NULL);
+       gpio_pull_down(GPIO_PORT168CR); /* VBUS0_0 pull down */
 
-       /* setup USB phy */
-       __raw_writew(0x8a0a, 0xE6058130);       /* USBCR4 */
+       /* USBHS1 */
+       gpio_request(GPIO_FN_VBUS0_1, NULL);
+       gpio_pull_down(GPIO_PORT167CR); /* VBUS0_1 pull down */
+       gpio_request(GPIO_FN_IDIN_1_113, NULL);
+
+       /* USB phy tweak to make the r8a66597_hcd host driver work */
+       __raw_writew(0x8a0a, 0xe6058130);       /* USBCR4 */
 
        /* enable FSI2 port A (ak4643) */
        gpio_request(GPIO_FN_FSIAIBT,   NULL);
@@ -1140,7 +1500,14 @@ static void __init mackerel_init(void)
        gpio_request(GPIO_FN_SDHID0_1, NULL);
        gpio_request(GPIO_FN_SDHID0_0, NULL);
 
-#if !defined(CONFIG_MMC_SH_MMCIF)
+       ret = request_irq(evt2irq(0x3340), mackerel_sdhi0_gpio_cd,
+                         IRQF_TRIGGER_FALLING, "sdhi0 cd", &sdhi0_device.dev);
+       if (!ret)
+               sdhi0_info.tmio_flags |= TMIO_MMC_HAS_COLD_CD;
+       else
+               pr_err("Cannot get IRQ #%d: %d\n", evt2irq(0x3340), ret);
+
+#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
        /* enable SDHI1 */
        gpio_request(GPIO_FN_SDHICMD1, NULL);
        gpio_request(GPIO_FN_SDHICLK1, NULL);
@@ -1216,6 +1583,7 @@ static void __init mackerel_init(void)
        platform_add_devices(mackerel_devices, ARRAY_SIZE(mackerel_devices));
 
        hdmi_init_pm_clock();
+       sh7372_pm_init();
 }
 
 static void __init mackerel_timer_init(void)
index e9731b5a73edacc54f2d0a9340ca455e84a063e5..c0800d83971e62c591993cce8ad77c87a5d3b6dd 100644 (file)
 #define DSI1PCKCR      0xe6150098
 #define PLLC01CR       0xe6150028
 #define PLLC2CR                0xe615002c
+#define RMSTPCR0       0xe6150110
+#define RMSTPCR1       0xe6150114
+#define RMSTPCR2       0xe6150118
+#define RMSTPCR3       0xe615011c
+#define RMSTPCR4       0xe6150120
 #define SMSTPCR0       0xe6150130
 #define SMSTPCR1       0xe6150134
 #define SMSTPCR2       0xe6150138
@@ -421,9 +426,6 @@ static unsigned long fsidiv_recalc(struct clk *clk)
 
        value = __raw_readl(clk->mapping->base);
 
-       if ((value & 0x3) != 0x3)
-               return 0;
-
        value >>= 16;
        if (value < 2)
                return 0;
@@ -504,9 +506,10 @@ static struct clk *late_main_clks[] = {
 enum { MSTP001,
        MSTP131, MSTP130,
        MSTP129, MSTP128, MSTP127, MSTP126, MSTP125,
-       MSTP118, MSTP117, MSTP116,
+       MSTP118, MSTP117, MSTP116, MSTP113,
        MSTP106, MSTP101, MSTP100,
        MSTP223,
+       MSTP218, MSTP217, MSTP216,
        MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
        MSTP329, MSTP328, MSTP323, MSTP322, MSTP314, MSTP313, MSTP312,
        MSTP423, MSTP415, MSTP413, MSTP411, MSTP410, MSTP406, MSTP403,
@@ -527,10 +530,14 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP118] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 18, 0), /* DSITX */
        [MSTP117] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 17, 0), /* LCDC1 */
        [MSTP116] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */
+       [MSTP113] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 13, 0), /* MERAM */
        [MSTP106] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 6, 0), /* JPU */
        [MSTP101] = MSTP(&div4_clks[DIV4_M1], SMSTPCR1, 1, 0), /* VPU */
        [MSTP100] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 0, 0), /* LCDC0 */
        [MSTP223] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR2, 23, 0), /* SPU2 */
+       [MSTP218] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 18, 0), /* DMAC1 */
+       [MSTP217] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 17, 0), /* DMAC2 */
+       [MSTP216] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 16, 0), /* DMAC3 */
        [MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */
        [MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */
        [MSTP204] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 4, 0), /* SCIFA0 */
@@ -617,11 +624,15 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("sh-mipi-dsi.0", &mstp_clks[MSTP118]), /* DSITX0 */
        CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1", &mstp_clks[MSTP117]), /* LCDC1 */
        CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */
+       CLKDEV_DEV_ID("sh_mobile_meram.0", &mstp_clks[MSTP113]), /* MERAM */
        CLKDEV_DEV_ID("uio_pdrv_genirq.5", &mstp_clks[MSTP106]), /* JPU */
        CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[MSTP101]), /* VPU */
        CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[MSTP100]), /* LCDC0 */
        CLKDEV_DEV_ID("uio_pdrv_genirq.6", &mstp_clks[MSTP223]), /* SPU2DSP0 */
        CLKDEV_DEV_ID("uio_pdrv_genirq.7", &mstp_clks[MSTP223]), /* SPU2DSP1 */
+       CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP218]), /* DMAC1 */
+       CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[MSTP217]), /* DMAC2 */
+       CLKDEV_DEV_ID("sh-dma-engine.2", &mstp_clks[MSTP216]), /* DMAC3 */
        CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */
        CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP206]), /* SCIFB */
        CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */
@@ -634,6 +645,7 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */
        CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USB0 */
        CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP322]), /* USB0 */
+       CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[MSTP322]), /* USB0 */
        CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
        CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
        CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */
@@ -644,6 +656,7 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* IIC4 */
        CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */
        CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */
+       CLKDEV_DEV_ID("renesas_usbhs.1", &mstp_clks[MSTP406]), /* USB1 */
        CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
 
        CLKDEV_ICK_ID("ick", "sh-mobile-hdmi", &div6_reparent_clks[DIV6_HDMI]),
@@ -655,6 +668,13 @@ void __init sh7372_clock_init(void)
 {
        int k, ret = 0;
 
+       /* make sure MSTP bits on the RT/SH4AL-DSP side are off */
+       __raw_writel(0xe4ef8087, RMSTPCR0);
+       __raw_writel(0xffffffff, RMSTPCR1);
+       __raw_writel(0x37c7f7ff, RMSTPCR2);
+       __raw_writel(0xffffffff, RMSTPCR3);
+       __raw_writel(0xffe0fffd, RMSTPCR4);
+
        for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
                ret = clk_register(main_clks[k]);
 
index 7e58904c1c8c506aa63789d80cf52674b209afd8..bcacb1e8cf85148e79d75b423de47d0f8e61ccbc 100644 (file)
@@ -266,7 +266,8 @@ enum { MSTP001,
        MSTP129, MSTP128, MSTP127, MSTP126, MSTP125, MSTP118, MSTP116, MSTP100,
        MSTP219,
        MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
-       MSTP331, MSTP329, MSTP325, MSTP323, MSTP312,
+       MSTP331, MSTP329, MSTP325, MSTP323, MSTP318,
+       MSTP314, MSTP313, MSTP312, MSTP311,
        MSTP411, MSTP410, MSTP403,
        MSTP_NR };
 
@@ -295,7 +296,11 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */
        [MSTP325] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 25, 0), /* IrDA */
        [MSTP323] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 23, 0), /* IIC1 */
+       [MSTP318] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 18, 0), /* SY-DMAC */
+       [MSTP314] = MSTP(&div6_clks[DIV6_SDHI0], SMSTPCR3, 14, 0), /* SDHI0 */
+       [MSTP313] = MSTP(&div6_clks[DIV6_SDHI1], SMSTPCR3, 13, 0), /* SDHI1 */
        [MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMCIF0 */
+       [MSTP311] = MSTP(&div6_clks[DIV6_SDHI2], SMSTPCR3, 11, 0), /* SDHI2 */
        [MSTP411] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 11, 0), /* IIC3 */
        [MSTP410] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 10, 0), /* IIC4 */
        [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
@@ -313,6 +318,9 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("vck1_clk", &div6_clks[DIV6_VCK1]),
        CLKDEV_CON_ID("vck2_clk", &div6_clks[DIV6_VCK2]),
        CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]),
+       CLKDEV_CON_ID("sdhi0_clk", &div6_clks[DIV6_SDHI0]),
+       CLKDEV_CON_ID("sdhi1_clk", &div6_clks[DIV6_SDHI1]),
+       CLKDEV_CON_ID("sdhi2_clk", &div6_clks[DIV6_SDHI2]),
        CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]),
        CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]),
        CLKDEV_ICK_ID("dsi0p_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]),
@@ -341,7 +349,11 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */
        CLKDEV_DEV_ID("sh_irda.0", &mstp_clks[MSTP325]), /* IrDA */
        CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* I2C1 */
+       CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP318]), /* SY-DMAC */
+       CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
+       CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
        CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMCIF0 */
+       CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP311]), /* SDHI2 */
        CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* I2C3 */
        CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* I2C4 */
        CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
@@ -351,6 +363,11 @@ void __init sh73a0_clock_init(void)
 {
        int k, ret = 0;
 
+       /* Set SDHI clocks to a known state */
+       __raw_writel(0x108, SD0CKCR);
+       __raw_writel(0x108, SD1CKCR);
+       __raw_writel(0x108, SD2CKCR);
+
        /* detect main clock parent */
        switch ((__raw_readl(CKSCR) >> 24) & 0x03) {
        case 0:
diff --git a/arch/arm/mach-shmobile/cpuidle.c b/arch/arm/mach-shmobile/cpuidle.c
new file mode 100644 (file)
index 0000000..2e44f11
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * CPUIdle support code for SH-Mobile ARM
+ *
+ *  Copyright (C) 2011 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/pm.h>
+#include <linux/cpuidle.h>
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+static void shmobile_enter_wfi(void)
+{
+       cpu_do_idle();
+}
+
+void (*shmobile_cpuidle_modes[CPUIDLE_STATE_MAX])(void) = {
+       shmobile_enter_wfi, /* regular sleep mode */
+};
+
+static int shmobile_cpuidle_enter(struct cpuidle_device *dev,
+                                 struct cpuidle_state *state)
+{
+       ktime_t before, after;
+       int requested_state = state - &dev->states[0];
+
+       dev->last_state = &dev->states[requested_state];
+       before = ktime_get();
+
+       local_irq_disable();
+       local_fiq_disable();
+
+       shmobile_cpuidle_modes[requested_state]();
+
+       local_irq_enable();
+       local_fiq_enable();
+
+       after = ktime_get();
+       return ktime_to_ns(ktime_sub(after, before)) >> 10;
+}
+
+static struct cpuidle_device shmobile_cpuidle_dev;
+static struct cpuidle_driver shmobile_cpuidle_driver = {
+       .name =         "shmobile_cpuidle",
+       .owner =        THIS_MODULE,
+};
+
+void (*shmobile_cpuidle_setup)(struct cpuidle_device *dev);
+
+static int shmobile_cpuidle_init(void)
+{
+       struct cpuidle_device *dev = &shmobile_cpuidle_dev;
+       struct cpuidle_state *state;
+       int i;
+
+       cpuidle_register_driver(&shmobile_cpuidle_driver);
+
+       for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
+               dev->states[i].name[0] = '\0';
+               dev->states[i].desc[0] = '\0';
+               dev->states[i].enter = shmobile_cpuidle_enter;
+       }
+
+       i = CPUIDLE_DRIVER_STATE_START;
+
+       state = &dev->states[i++];
+       snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
+       strncpy(state->desc, "WFI", CPUIDLE_DESC_LEN);
+       state->exit_latency = 1;
+       state->target_residency = 1 * 2;
+       state->power_usage = 3;
+       state->flags = 0;
+       state->flags |= CPUIDLE_FLAG_TIME_VALID;
+
+       dev->safe_state = state;
+       dev->state_count = i;
+
+       if (shmobile_cpuidle_setup)
+               shmobile_cpuidle_setup(dev);
+
+       cpuidle_register_device(dev);
+
+       return 0;
+}
+late_initcall(shmobile_cpuidle_init);
index d4cec6b4c7d93cab2a22385efcae773f411bc018..26079d933d913e1bf4f04e68d6a23e1eb3225e3d 100644 (file)
@@ -24,4 +24,4 @@
        .align  12
 ENTRY(shmobile_secondary_vector)
        ldr     pc, 1f
-1:     .long   secondary_startup - PAGE_OFFSET + PHYS_OFFSET
+1:     .long   secondary_startup - PAGE_OFFSET + PLAT_PHYS_OFFSET
index 013ac0ee8256acd4dfd8eda35f770860ef289cdc..06aecb31d9c7ececc9784ced7086ccc9ed83418f 100644 (file)
@@ -8,6 +8,10 @@ struct clk;
 extern int clk_init(void);
 extern void shmobile_handle_irq_intc(struct pt_regs *);
 extern void shmobile_handle_irq_gic(struct pt_regs *);
+extern struct platform_suspend_ops shmobile_suspend_ops;
+struct cpuidle_device;
+extern void (*shmobile_cpuidle_modes[])(void);
+extern void (*shmobile_cpuidle_setup)(struct cpuidle_device *dev);
 
 extern void sh7367_init_irq(void);
 extern void sh7367_add_early_devices(void);
@@ -30,6 +34,9 @@ extern void sh7372_add_early_devices(void);
 extern void sh7372_add_standard_devices(void);
 extern void sh7372_clock_init(void);
 extern void sh7372_pinmux_init(void);
+extern void sh7372_pm_init(void);
+extern void sh7372_cpu_suspend(void);
+extern void sh7372_cpu_resume(void);
 extern struct clk sh7372_extal1_clk;
 extern struct clk sh7372_extal2_clk;
 
index 3029aba38688e846ade96eefda7ecbceeb4f6732..9f134dfeffdcf6b5761914aa646ff6e878887223 100644 (file)
@@ -87,8 +87,7 @@ WAIT 1, 0xFE40009C
 ED 0xFE400354, 0x01AD8002
 
 LIST "SCIF0 - Serial port for earlyprintk"
-EB 0xE6053098, 0x11
 EB 0xE6053098, 0xe1
 EW 0xE6C40000, 0x0000
 EB 0xE6C40004, 0x19
-EW 0xE6C40008, 0x3000
+EW 0xE6C40008, 0x0030
index 3029aba38688e846ade96eefda7ecbceeb4f6732..9f134dfeffdcf6b5761914aa646ff6e878887223 100644 (file)
@@ -87,8 +87,7 @@ WAIT 1, 0xFE40009C
 ED 0xFE400354, 0x01AD8002
 
 LIST "SCIF0 - Serial port for earlyprintk"
-EB 0xE6053098, 0x11
 EB 0xE6053098, 0xe1
 EW 0xE6C40000, 0x0000
 EB 0xE6C40004, 0x19
-EW 0xE6C40008, 0x3000
+EW 0xE6C40008, 0x0030
index 5736efcca60c484d7762e346a16cee2d18ad7759..df20d7670172d402e156a54b5639d8d5ab840328 100644 (file)
@@ -435,6 +435,7 @@ enum {
 
 /* DMA slave IDs */
 enum {
+       SHDMA_SLAVE_INVALID,
        SHDMA_SLAVE_SCIF0_TX,
        SHDMA_SLAVE_SCIF0_RX,
        SHDMA_SLAVE_SCIF1_TX,
index ceb2cdc92bf9f38a51b0f1c193d0c8ed4b5a03c3..216c3d695ef177f36f131f47bbee51be3b9be877 100644 (file)
@@ -463,5 +463,35 @@ enum {
        GPIO_FN_FSIAIBT_PU,
        GPIO_FN_FSIAISLD_PU,
 };
+/* DMA slave IDs */
+enum {
+       SHDMA_SLAVE_INVALID,
+       SHDMA_SLAVE_SCIF0_TX,
+       SHDMA_SLAVE_SCIF0_RX,
+       SHDMA_SLAVE_SCIF1_TX,
+       SHDMA_SLAVE_SCIF1_RX,
+       SHDMA_SLAVE_SCIF2_TX,
+       SHDMA_SLAVE_SCIF2_RX,
+       SHDMA_SLAVE_SCIF3_TX,
+       SHDMA_SLAVE_SCIF3_RX,
+       SHDMA_SLAVE_SCIF4_TX,
+       SHDMA_SLAVE_SCIF4_RX,
+       SHDMA_SLAVE_SCIF5_TX,
+       SHDMA_SLAVE_SCIF5_RX,
+       SHDMA_SLAVE_SCIF6_TX,
+       SHDMA_SLAVE_SCIF6_RX,
+       SHDMA_SLAVE_SCIF7_TX,
+       SHDMA_SLAVE_SCIF7_RX,
+       SHDMA_SLAVE_SCIF8_TX,
+       SHDMA_SLAVE_SCIF8_RX,
+       SHDMA_SLAVE_SDHI0_TX,
+       SHDMA_SLAVE_SDHI0_RX,
+       SHDMA_SLAVE_SDHI1_TX,
+       SHDMA_SLAVE_SDHI1_RX,
+       SHDMA_SLAVE_SDHI2_TX,
+       SHDMA_SLAVE_SDHI2_RX,
+       SHDMA_SLAVE_MMCIF_TX,
+       SHDMA_SLAVE_MMCIF_RX,
+};
 
 #endif /* __ASM_SH73A0_H__ */
index 7a4960f9c1e3fcb313cf103fcacd3ccbfe3fab71..3b28743c77eb738f502737f434f0aee4c0f7cdf3 100644 (file)
@@ -27,8 +27,6 @@
 
 enum {
        UNUSED_INTCA = 0,
-       ENABLED,
-       DISABLED,
 
        /* interrupt sources INTCA */
        IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A,
@@ -49,14 +47,14 @@ enum {
        MSIOF2, MSIOF1,
        SCIFA4, SCIFA5, SCIFB,
        FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
-       SDHI0,
-       SDHI1,
+       SDHI0_SDHI0I0, SDHI0_SDHI0I1, SDHI0_SDHI0I2, SDHI0_SDHI0I3,
+       SDHI1_SDHI1I0, SDHI1_SDHI1I1, SDHI1_SDHI1I2,
        IRREM,
        IRDA,
        TPU0,
        TTI20,
        DDM,
-       SDHI2,
+       SDHI2_SDHI2I0, SDHI2_SDHI2I1, SDHI2_SDHI2I2, SDHI2_SDHI2I3,
        RWDT0,
        DMAC1_1_DEI0, DMAC1_1_DEI1, DMAC1_1_DEI2, DMAC1_1_DEI3,
        DMAC1_2_DEI4, DMAC1_2_DEI5, DMAC1_2_DADERR,
@@ -84,7 +82,7 @@ enum {
 
        /* interrupt groups INTCA */
        DMAC1_1, DMAC1_2, DMAC2_1, DMAC2_2, DMAC3_1, DMAC3_2, SHWYSTAT,
-       AP_ARM1, AP_ARM2, SPU2, FLCTL, IIC1
+       AP_ARM1, AP_ARM2, SPU2, FLCTL, IIC1, SDHI0, SDHI1, SDHI2
 };
 
 static struct intc_vect intca_vectors[] __initdata = {
@@ -125,17 +123,17 @@ static struct intc_vect intca_vectors[] __initdata = {
        INTC_VECT(SCIFB, 0x0d60),
        INTC_VECT(FLCTL_FLSTEI, 0x0d80), INTC_VECT(FLCTL_FLTENDI, 0x0da0),
        INTC_VECT(FLCTL_FLTREQ0I, 0x0dc0), INTC_VECT(FLCTL_FLTREQ1I, 0x0de0),
-       INTC_VECT(SDHI0, 0x0e00), INTC_VECT(SDHI0, 0x0e20),
-       INTC_VECT(SDHI0, 0x0e40), INTC_VECT(SDHI0, 0x0e60),
-       INTC_VECT(SDHI1, 0x0e80), INTC_VECT(SDHI1, 0x0ea0),
-       INTC_VECT(SDHI1, 0x0ec0),
+       INTC_VECT(SDHI0_SDHI0I0, 0x0e00), INTC_VECT(SDHI0_SDHI0I1, 0x0e20),
+       INTC_VECT(SDHI0_SDHI0I2, 0x0e40), INTC_VECT(SDHI0_SDHI0I3, 0x0e60),
+       INTC_VECT(SDHI1_SDHI1I0, 0x0e80), INTC_VECT(SDHI1_SDHI1I1, 0x0ea0),
+       INTC_VECT(SDHI1_SDHI1I2, 0x0ec0),
        INTC_VECT(IRREM, 0x0f60),
        INTC_VECT(IRDA, 0x0480),
        INTC_VECT(TPU0, 0x04a0),
        INTC_VECT(TTI20, 0x1100),
        INTC_VECT(DDM, 0x1140),
-       INTC_VECT(SDHI2, 0x1200), INTC_VECT(SDHI2, 0x1220),
-       INTC_VECT(SDHI2, 0x1240), INTC_VECT(SDHI2, 0x1260),
+       INTC_VECT(SDHI2_SDHI2I0, 0x1200), INTC_VECT(SDHI2_SDHI2I1, 0x1220),
+       INTC_VECT(SDHI2_SDHI2I2, 0x1240), INTC_VECT(SDHI2_SDHI2I3, 0x1260),
        INTC_VECT(RWDT0, 0x1280),
        INTC_VECT(DMAC1_1_DEI0, 0x2000), INTC_VECT(DMAC1_1_DEI1, 0x2020),
        INTC_VECT(DMAC1_1_DEI2, 0x2040), INTC_VECT(DMAC1_1_DEI3, 0x2060),
@@ -195,6 +193,12 @@ static struct intc_group intca_groups[] __initdata = {
        INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLTENDI,
                   FLCTL_FLTREQ0I, FLCTL_FLTREQ1I),
        INTC_GROUP(IIC1, IIC1_ALI1, IIC1_TACKI1, IIC1_WAITI1, IIC1_DTEI1),
+       INTC_GROUP(SDHI0, SDHI0_SDHI0I0, SDHI0_SDHI0I1,
+                  SDHI0_SDHI0I2, SDHI0_SDHI0I3),
+       INTC_GROUP(SDHI1, SDHI1_SDHI1I0, SDHI1_SDHI1I1,
+                  SDHI1_SDHI1I2),
+       INTC_GROUP(SDHI2, SDHI2_SDHI2I0, SDHI2_SDHI2I1,
+                  SDHI2_SDHI2I2, SDHI2_SDHI2I3),
        INTC_GROUP(SHWYSTAT, SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM),
 };
 
@@ -230,10 +234,10 @@ static struct intc_mask_reg intca_mask_registers[] __initdata = {
          { SCIFB, SCIFA5, SCIFA4, MSIOF1,
            0, 0, MSIOF2, 0 } },
        { 0xe694009c, 0xe69400dc, 8, /* IMR7A / IMCR7A */
-         { DISABLED, ENABLED, ENABLED, ENABLED,
+         { SDHI0_SDHI0I3, SDHI0_SDHI0I2, SDHI0_SDHI0I1, SDHI0_SDHI0I0,
            FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLTENDI, FLCTL_FLSTEI } },
        { 0xe69400a0, 0xe69400e0, 8, /* IMR8A / IMCR8A */
-         { 0, ENABLED, ENABLED, ENABLED,
+         { 0, SDHI1_SDHI1I2, SDHI1_SDHI1I1, SDHI1_SDHI1I0,
            TTI20, USBHSDMAC0_USHDMI, 0, 0 } },
        { 0xe69400a4, 0xe69400e4, 8, /* IMR9A / IMCR9A */
          { CMT1_CMT13, CMT1_CMT12, CMT1_CMT11, CMT1_CMT10,
@@ -248,7 +252,7 @@ static struct intc_mask_reg intca_mask_registers[] __initdata = {
          { 0, 0, TPU0, 0,
            0, 0, 0, 0 } },
        { 0xe69400b4, 0xe69400f4, 8, /* IMR13A / IMCR13A */
-         { DISABLED, DISABLED, ENABLED, ENABLED,
+         { SDHI2_SDHI2I3, SDHI2_SDHI2I2, SDHI2_SDHI2I1, SDHI2_SDHI2I0,
            0, CMT3, 0, RWDT0 } },
        { 0xe6950080, 0xe69500c0, 8, /* IMR0A3 / IMCR0A3 */
          { SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM, 0,
@@ -354,14 +358,10 @@ static struct intc_mask_reg intca_ack_registers[] __initdata = {
          { IRQ24A, IRQ25A, IRQ26A, IRQ27A, IRQ28A, IRQ29A, IRQ30A, IRQ31A } },
 };
 
-static struct intc_desc intca_desc __initdata = {
-       .name = "sh7372-intca",
-       .force_enable = ENABLED,
-       .force_disable = DISABLED,
-       .hw = INTC_HW_DESC(intca_vectors, intca_groups,
-                          intca_mask_registers, intca_prio_registers,
-                          intca_sense_registers, intca_ack_registers),
-};
+static DECLARE_INTC_DESC_ACK(intca_desc, "sh7372-intca",
+                            intca_vectors, intca_groups,
+                            intca_mask_registers, intca_prio_registers,
+                            intca_sense_registers, intca_ack_registers);
 
 enum {
        UNUSED_INTCS = 0,
index 5d0e1503ece66fb9385f3ffc80abb88e60d2ed27..a911a60e7719a1e0fa040f5798b0e7174b060fa1 100644 (file)
@@ -250,6 +250,11 @@ static irqreturn_t sh73a0_intcs_demux(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static int sh73a0_set_wake(struct irq_data *data, unsigned int on)
+{
+       return 0; /* always allow wakeup */
+}
+
 void __init sh73a0_init_irq(void)
 {
        void __iomem *gic_dist_base = __io(0xf0001000);
@@ -257,6 +262,7 @@ void __init sh73a0_init_irq(void)
        void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE);
 
        gic_init(0, 29, gic_dist_base, gic_cpu_base);
+       gic_arch_extn.irq_set_wake = sh73a0_set_wake;
 
        register_intc_controller(&intcs_desc);
 
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c
new file mode 100644 (file)
index 0000000..8e4aadf
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * sh7372 Power management support
+ *
+ *  Copyright (C) 2011 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/pm.h>
+#include <linux/suspend.h>
+#include <linux/cpuidle.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/tlbflush.h>
+#include <mach/common.h>
+
+#define SMFRAM 0xe6a70000
+#define SYSTBCR 0xe6150024
+#define SBAR 0xe6180020
+#define APARMBAREA 0xe6f10020
+
+static void sh7372_enter_core_standby(void)
+{
+       void __iomem *smfram = (void __iomem *)SMFRAM;
+
+       __raw_writel(0, APARMBAREA); /* translate 4k */
+       __raw_writel(__pa(sh7372_cpu_resume), SBAR); /* set reset vector */
+       __raw_writel(0x10, SYSTBCR); /* enable core standby */
+
+       __raw_writel(0, smfram + 0x3c); /* clear page table address */
+
+       sh7372_cpu_suspend();
+       cpu_init();
+
+       /* if page table address is non-NULL then we have been powered down */
+       if (__raw_readl(smfram + 0x3c)) {
+               __raw_writel(__raw_readl(smfram + 0x40),
+                            __va(__raw_readl(smfram + 0x3c)));
+
+               flush_tlb_all();
+               set_cr(__raw_readl(smfram + 0x38));
+       }
+
+       __raw_writel(0, SYSTBCR); /* disable core standby */
+       __raw_writel(0, SBAR); /* disable reset vector translation */
+}
+
+#ifdef CONFIG_CPU_IDLE
+static void sh7372_cpuidle_setup(struct cpuidle_device *dev)
+{
+       struct cpuidle_state *state;
+       int i = dev->state_count;
+
+       state = &dev->states[i];
+       snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
+       strncpy(state->desc, "Core Standby Mode", CPUIDLE_DESC_LEN);
+       state->exit_latency = 10;
+       state->target_residency = 20 + 10;
+       state->power_usage = 1; /* perhaps not */
+       state->flags = 0;
+       state->flags |= CPUIDLE_FLAG_TIME_VALID;
+       shmobile_cpuidle_modes[i] = sh7372_enter_core_standby;
+
+       dev->state_count = i + 1;
+}
+
+static void sh7372_cpuidle_init(void)
+{
+       shmobile_cpuidle_setup = sh7372_cpuidle_setup;
+}
+#else
+static void sh7372_cpuidle_init(void) {}
+#endif
+
+#ifdef CONFIG_SUSPEND
+static int sh7372_enter_suspend(suspend_state_t suspend_state)
+{
+       sh7372_enter_core_standby();
+       return 0;
+}
+
+static void sh7372_suspend_init(void)
+{
+       shmobile_suspend_ops.enter = sh7372_enter_suspend;
+}
+#else
+static void sh7372_suspend_init(void) {}
+#endif
+
+#define DBGREG1 0xe6100020
+#define DBGREG9 0xe6100040
+
+void __init sh7372_pm_init(void)
+{
+       /* enable DBG hardware block to kick SYSC */
+       __raw_writel(0x0000a500, DBGREG9);
+       __raw_writel(0x0000a501, DBGREG9);
+       __raw_writel(0x00000000, DBGREG1);
+
+       sh7372_suspend_init();
+       sh7372_cpuidle_init();
+}
index ce28141662da72c9812ba12edad47537f3f371a9..e546017f15dea1202df2be20fa6303b69d70f1f4 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
+#include <linux/uio_driver.h>
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/io.h>
@@ -37,7 +38,7 @@ static struct plat_sci_port scif0_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xc00), evt2irq(0xc00),
                            evt2irq(0xc00), evt2irq(0xc00) },
 };
@@ -56,7 +57,7 @@ static struct plat_sci_port scif1_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xc20), evt2irq(0xc20),
                            evt2irq(0xc20), evt2irq(0xc20) },
 };
@@ -75,7 +76,7 @@ static struct plat_sci_port scif2_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xc40), evt2irq(0xc40),
                            evt2irq(0xc40), evt2irq(0xc40) },
 };
@@ -94,7 +95,7 @@ static struct plat_sci_port scif3_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xc60), evt2irq(0xc60),
                            evt2irq(0xc60), evt2irq(0xc60) },
 };
@@ -113,7 +114,7 @@ static struct plat_sci_port scif4_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xd20), evt2irq(0xd20),
                            evt2irq(0xd20), evt2irq(0xd20) },
 };
@@ -132,7 +133,7 @@ static struct plat_sci_port scif5_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xd40), evt2irq(0xd40),
                            evt2irq(0xd40), evt2irq(0xd40) },
 };
@@ -151,7 +152,7 @@ static struct plat_sci_port scif6_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFB,
        .irqs           = { evt2irq(0xd60), evt2irq(0xd60),
                            evt2irq(0xd60), evt2irq(0xd60) },
 };
@@ -195,6 +196,214 @@ static struct platform_device cmt10_device = {
        .num_resources  = ARRAY_SIZE(cmt10_resources),
 };
 
+/* VPU */
+static struct uio_info vpu_platform_data = {
+       .name = "VPU5",
+       .version = "0",
+       .irq = intcs_evt2irq(0x980),
+};
+
+static struct resource vpu_resources[] = {
+       [0] = {
+               .name   = "VPU",
+               .start  = 0xfe900000,
+               .end    = 0xfe902807,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device vpu_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &vpu_platform_data,
+       },
+       .resource       = vpu_resources,
+       .num_resources  = ARRAY_SIZE(vpu_resources),
+};
+
+/* VEU0 */
+static struct uio_info veu0_platform_data = {
+       .name = "VEU0",
+       .version = "0",
+       .irq = intcs_evt2irq(0x700),
+};
+
+static struct resource veu0_resources[] = {
+       [0] = {
+               .name   = "VEU0",
+               .start  = 0xfe920000,
+               .end    = 0xfe9200b7,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu0_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &veu0_platform_data,
+       },
+       .resource       = veu0_resources,
+       .num_resources  = ARRAY_SIZE(veu0_resources),
+};
+
+/* VEU1 */
+static struct uio_info veu1_platform_data = {
+       .name = "VEU1",
+       .version = "0",
+       .irq = intcs_evt2irq(0x720),
+};
+
+static struct resource veu1_resources[] = {
+       [0] = {
+               .name   = "VEU1",
+               .start  = 0xfe924000,
+               .end    = 0xfe9240b7,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu1_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &veu1_platform_data,
+       },
+       .resource       = veu1_resources,
+       .num_resources  = ARRAY_SIZE(veu1_resources),
+};
+
+/* VEU2 */
+static struct uio_info veu2_platform_data = {
+       .name = "VEU2",
+       .version = "0",
+       .irq = intcs_evt2irq(0x740),
+};
+
+static struct resource veu2_resources[] = {
+       [0] = {
+               .name   = "VEU2",
+               .start  = 0xfe928000,
+               .end    = 0xfe9280b7,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu2_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 3,
+       .dev = {
+               .platform_data  = &veu2_platform_data,
+       },
+       .resource       = veu2_resources,
+       .num_resources  = ARRAY_SIZE(veu2_resources),
+};
+
+/* VEU3 */
+static struct uio_info veu3_platform_data = {
+       .name = "VEU3",
+       .version = "0",
+       .irq = intcs_evt2irq(0x760),
+};
+
+static struct resource veu3_resources[] = {
+       [0] = {
+               .name   = "VEU3",
+               .start  = 0xfe92c000,
+               .end    = 0xfe92c0b7,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu3_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 4,
+       .dev = {
+               .platform_data  = &veu3_platform_data,
+       },
+       .resource       = veu3_resources,
+       .num_resources  = ARRAY_SIZE(veu3_resources),
+};
+
+/* VEU2H */
+static struct uio_info veu2h_platform_data = {
+       .name = "VEU2H",
+       .version = "0",
+       .irq = intcs_evt2irq(0x520),
+};
+
+static struct resource veu2h_resources[] = {
+       [0] = {
+               .name   = "VEU2H",
+               .start  = 0xfe93c000,
+               .end    = 0xfe93c27b,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu2h_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 5,
+       .dev = {
+               .platform_data  = &veu2h_platform_data,
+       },
+       .resource       = veu2h_resources,
+       .num_resources  = ARRAY_SIZE(veu2h_resources),
+};
+
+/* JPU */
+static struct uio_info jpu_platform_data = {
+       .name = "JPU",
+       .version = "0",
+       .irq = intcs_evt2irq(0x560),
+};
+
+static struct resource jpu_resources[] = {
+       [0] = {
+               .name   = "JPU",
+               .start  = 0xfe980000,
+               .end    = 0xfe9902d3,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device jpu_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 6,
+       .dev = {
+               .platform_data  = &jpu_platform_data,
+       },
+       .resource       = jpu_resources,
+       .num_resources  = ARRAY_SIZE(jpu_resources),
+};
+
+/* SPU1 */
+static struct uio_info spu1_platform_data = {
+       .name = "SPU1",
+       .version = "0",
+       .irq = evt2irq(0xfc0),
+};
+
+static struct resource spu1_resources[] = {
+       [0] = {
+               .name   = "SPU1",
+               .start  = 0xfe300000,
+               .end    = 0xfe3fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device spu1_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 7,
+       .dev = {
+               .platform_data  = &spu1_platform_data,
+       },
+       .resource       = spu1_resources,
+       .num_resources  = ARRAY_SIZE(spu1_resources),
+};
+
 static struct platform_device *sh7367_early_devices[] __initdata = {
        &scif0_device,
        &scif1_device,
@@ -206,10 +415,24 @@ static struct platform_device *sh7367_early_devices[] __initdata = {
        &cmt10_device,
 };
 
+static struct platform_device *sh7367_devices[] __initdata = {
+       &vpu_device,
+       &veu0_device,
+       &veu1_device,
+       &veu2_device,
+       &veu3_device,
+       &veu2h_device,
+       &jpu_device,
+       &spu1_device,
+};
+
 void __init sh7367_add_standard_devices(void)
 {
        platform_add_devices(sh7367_early_devices,
                             ARRAY_SIZE(sh7367_early_devices));
+
+       platform_add_devices(sh7367_devices,
+                           ARRAY_SIZE(sh7367_devices));
 }
 
 #define SYMSTPCR2 0xe6158048
index ff0494f3d00cb5816a1c90041226823585482721..cd807eea69e2e720bf2554dfb6c7c233cab31958 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
+#include <linux/uio_driver.h>
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/io.h>
@@ -601,6 +602,214 @@ static struct platform_device dma2_device = {
        },
 };
 
+/* VPU */
+static struct uio_info vpu_platform_data = {
+       .name = "VPU5HG",
+       .version = "0",
+       .irq = intcs_evt2irq(0x980),
+};
+
+static struct resource vpu_resources[] = {
+       [0] = {
+               .name   = "VPU",
+               .start  = 0xfe900000,
+               .end    = 0xfe900157,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device vpu_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &vpu_platform_data,
+       },
+       .resource       = vpu_resources,
+       .num_resources  = ARRAY_SIZE(vpu_resources),
+};
+
+/* VEU0 */
+static struct uio_info veu0_platform_data = {
+       .name = "VEU0",
+       .version = "0",
+       .irq = intcs_evt2irq(0x700),
+};
+
+static struct resource veu0_resources[] = {
+       [0] = {
+               .name   = "VEU0",
+               .start  = 0xfe920000,
+               .end    = 0xfe9200cb,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu0_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &veu0_platform_data,
+       },
+       .resource       = veu0_resources,
+       .num_resources  = ARRAY_SIZE(veu0_resources),
+};
+
+/* VEU1 */
+static struct uio_info veu1_platform_data = {
+       .name = "VEU1",
+       .version = "0",
+       .irq = intcs_evt2irq(0x720),
+};
+
+static struct resource veu1_resources[] = {
+       [0] = {
+               .name   = "VEU1",
+               .start  = 0xfe924000,
+               .end    = 0xfe9240cb,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu1_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &veu1_platform_data,
+       },
+       .resource       = veu1_resources,
+       .num_resources  = ARRAY_SIZE(veu1_resources),
+};
+
+/* VEU2 */
+static struct uio_info veu2_platform_data = {
+       .name = "VEU2",
+       .version = "0",
+       .irq = intcs_evt2irq(0x740),
+};
+
+static struct resource veu2_resources[] = {
+       [0] = {
+               .name   = "VEU2",
+               .start  = 0xfe928000,
+               .end    = 0xfe928307,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu2_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 3,
+       .dev = {
+               .platform_data  = &veu2_platform_data,
+       },
+       .resource       = veu2_resources,
+       .num_resources  = ARRAY_SIZE(veu2_resources),
+};
+
+/* VEU3 */
+static struct uio_info veu3_platform_data = {
+       .name = "VEU3",
+       .version = "0",
+       .irq = intcs_evt2irq(0x760),
+};
+
+static struct resource veu3_resources[] = {
+       [0] = {
+               .name   = "VEU3",
+               .start  = 0xfe92c000,
+               .end    = 0xfe92c307,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu3_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 4,
+       .dev = {
+               .platform_data  = &veu3_platform_data,
+       },
+       .resource       = veu3_resources,
+       .num_resources  = ARRAY_SIZE(veu3_resources),
+};
+
+/* JPU */
+static struct uio_info jpu_platform_data = {
+       .name = "JPU",
+       .version = "0",
+       .irq = intcs_evt2irq(0x560),
+};
+
+static struct resource jpu_resources[] = {
+       [0] = {
+               .name   = "JPU",
+               .start  = 0xfe980000,
+               .end    = 0xfe9902d3,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device jpu_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 5,
+       .dev = {
+               .platform_data  = &jpu_platform_data,
+       },
+       .resource       = jpu_resources,
+       .num_resources  = ARRAY_SIZE(jpu_resources),
+};
+
+/* SPU2DSP0 */
+static struct uio_info spu0_platform_data = {
+       .name = "SPU2DSP0",
+       .version = "0",
+       .irq = evt2irq(0x1800),
+};
+
+static struct resource spu0_resources[] = {
+       [0] = {
+               .name   = "SPU2DSP0",
+               .start  = 0xfe200000,
+               .end    = 0xfe2fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device spu0_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 6,
+       .dev = {
+               .platform_data  = &spu0_platform_data,
+       },
+       .resource       = spu0_resources,
+       .num_resources  = ARRAY_SIZE(spu0_resources),
+};
+
+/* SPU2DSP1 */
+static struct uio_info spu1_platform_data = {
+       .name = "SPU2DSP1",
+       .version = "0",
+       .irq = evt2irq(0x1820),
+};
+
+static struct resource spu1_resources[] = {
+       [0] = {
+               .name   = "SPU2DSP1",
+               .start  = 0xfe300000,
+               .end    = 0xfe3fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device spu1_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 7,
+       .dev = {
+               .platform_data  = &spu1_platform_data,
+       },
+       .resource       = spu1_resources,
+       .num_resources  = ARRAY_SIZE(spu1_resources),
+};
+
 static struct platform_device *sh7372_early_devices[] __initdata = {
        &scif0_device,
        &scif1_device,
@@ -620,6 +829,14 @@ static struct platform_device *sh7372_late_devices[] __initdata = {
        &dma0_device,
        &dma1_device,
        &dma2_device,
+       &vpu_device,
+       &veu0_device,
+       &veu1_device,
+       &veu2_device,
+       &veu3_device,
+       &jpu_device,
+       &spu0_device,
+       &spu1_device,
 };
 
 void __init sh7372_add_standard_devices(void)
index 8099b0b8a9346dcb76a17c2902dec2a1dba01c8b..bb405b8e459be00c11ce956c0e67bf9e181557f2 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
+#include <linux/uio_driver.h>
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/io.h>
@@ -38,7 +39,7 @@ static struct plat_sci_port scif0_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xc00), evt2irq(0xc00),
                            evt2irq(0xc00), evt2irq(0xc00) },
 };
@@ -57,7 +58,7 @@ static struct plat_sci_port scif1_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xc20), evt2irq(0xc20),
                            evt2irq(0xc20), evt2irq(0xc20) },
 };
@@ -76,7 +77,7 @@ static struct plat_sci_port scif2_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xc40), evt2irq(0xc40),
                            evt2irq(0xc40), evt2irq(0xc40) },
 };
@@ -95,7 +96,7 @@ static struct plat_sci_port scif3_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xc60), evt2irq(0xc60),
                            evt2irq(0xc60), evt2irq(0xc60) },
 };
@@ -114,7 +115,7 @@ static struct plat_sci_port scif4_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xd20), evt2irq(0xd20),
                            evt2irq(0xd20), evt2irq(0xd20) },
 };
@@ -133,7 +134,7 @@ static struct plat_sci_port scif5_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xd40), evt2irq(0xd40),
                            evt2irq(0xd40), evt2irq(0xd40) },
 };
@@ -152,7 +153,7 @@ static struct plat_sci_port scif6_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { intcs_evt2irq(0x1a80), intcs_evt2irq(0x1a80),
                            intcs_evt2irq(0x1a80), intcs_evt2irq(0x1a80) },
 };
@@ -171,7 +172,7 @@ static struct plat_sci_port scif7_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFB,
        .irqs           = { evt2irq(0xd60), evt2irq(0xd60),
                            evt2irq(0xd60), evt2irq(0xd60) },
 };
@@ -215,6 +216,214 @@ static struct platform_device cmt10_device = {
        .num_resources  = ARRAY_SIZE(cmt10_resources),
 };
 
+/* VPU */
+static struct uio_info vpu_platform_data = {
+       .name = "VPU5HG",
+       .version = "0",
+       .irq = intcs_evt2irq(0x980),
+};
+
+static struct resource vpu_resources[] = {
+       [0] = {
+               .name   = "VPU",
+               .start  = 0xfe900000,
+               .end    = 0xfe900157,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device vpu_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &vpu_platform_data,
+       },
+       .resource       = vpu_resources,
+       .num_resources  = ARRAY_SIZE(vpu_resources),
+};
+
+/* VEU0 */
+static struct uio_info veu0_platform_data = {
+       .name = "VEU0",
+       .version = "0",
+       .irq = intcs_evt2irq(0x700),
+};
+
+static struct resource veu0_resources[] = {
+       [0] = {
+               .name   = "VEU0",
+               .start  = 0xfe920000,
+               .end    = 0xfe9200cb,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu0_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &veu0_platform_data,
+       },
+       .resource       = veu0_resources,
+       .num_resources  = ARRAY_SIZE(veu0_resources),
+};
+
+/* VEU1 */
+static struct uio_info veu1_platform_data = {
+       .name = "VEU1",
+       .version = "0",
+       .irq = intcs_evt2irq(0x720),
+};
+
+static struct resource veu1_resources[] = {
+       [0] = {
+               .name   = "VEU1",
+               .start  = 0xfe924000,
+               .end    = 0xfe9240cb,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu1_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &veu1_platform_data,
+       },
+       .resource       = veu1_resources,
+       .num_resources  = ARRAY_SIZE(veu1_resources),
+};
+
+/* VEU2 */
+static struct uio_info veu2_platform_data = {
+       .name = "VEU2",
+       .version = "0",
+       .irq = intcs_evt2irq(0x740),
+};
+
+static struct resource veu2_resources[] = {
+       [0] = {
+               .name   = "VEU2",
+               .start  = 0xfe928000,
+               .end    = 0xfe928307,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu2_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 3,
+       .dev = {
+               .platform_data  = &veu2_platform_data,
+       },
+       .resource       = veu2_resources,
+       .num_resources  = ARRAY_SIZE(veu2_resources),
+};
+
+/* VEU3 */
+static struct uio_info veu3_platform_data = {
+       .name = "VEU3",
+       .version = "0",
+       .irq = intcs_evt2irq(0x760),
+};
+
+static struct resource veu3_resources[] = {
+       [0] = {
+               .name   = "VEU3",
+               .start  = 0xfe92c000,
+               .end    = 0xfe92c307,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu3_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 4,
+       .dev = {
+               .platform_data  = &veu3_platform_data,
+       },
+       .resource       = veu3_resources,
+       .num_resources  = ARRAY_SIZE(veu3_resources),
+};
+
+/* JPU */
+static struct uio_info jpu_platform_data = {
+       .name = "JPU",
+       .version = "0",
+       .irq = intcs_evt2irq(0x560),
+};
+
+static struct resource jpu_resources[] = {
+       [0] = {
+               .name   = "JPU",
+               .start  = 0xfe980000,
+               .end    = 0xfe9902d3,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device jpu_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 5,
+       .dev = {
+               .platform_data  = &jpu_platform_data,
+       },
+       .resource       = jpu_resources,
+       .num_resources  = ARRAY_SIZE(jpu_resources),
+};
+
+/* SPU2DSP0 */
+static struct uio_info spu0_platform_data = {
+       .name = "SPU2DSP0",
+       .version = "0",
+       .irq = evt2irq(0x1800),
+};
+
+static struct resource spu0_resources[] = {
+       [0] = {
+               .name   = "SPU2DSP0",
+               .start  = 0xfe200000,
+               .end    = 0xfe2fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device spu0_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 6,
+       .dev = {
+               .platform_data  = &spu0_platform_data,
+       },
+       .resource       = spu0_resources,
+       .num_resources  = ARRAY_SIZE(spu0_resources),
+};
+
+/* SPU2DSP1 */
+static struct uio_info spu1_platform_data = {
+       .name = "SPU2DSP1",
+       .version = "0",
+       .irq = evt2irq(0x1820),
+};
+
+static struct resource spu1_resources[] = {
+       [0] = {
+               .name   = "SPU2DSP1",
+               .start  = 0xfe300000,
+               .end    = 0xfe3fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device spu1_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 7,
+       .dev = {
+               .platform_data  = &spu1_platform_data,
+       },
+       .resource       = spu1_resources,
+       .num_resources  = ARRAY_SIZE(spu1_resources),
+};
+
 static struct platform_device *sh7377_early_devices[] __initdata = {
        &scif0_device,
        &scif1_device,
@@ -227,10 +436,24 @@ static struct platform_device *sh7377_early_devices[] __initdata = {
        &cmt10_device,
 };
 
+static struct platform_device *sh7377_devices[] __initdata = {
+       &vpu_device,
+       &veu0_device,
+       &veu1_device,
+       &veu2_device,
+       &veu3_device,
+       &jpu_device,
+       &spu0_device,
+       &spu1_device,
+};
+
 void __init sh7377_add_standard_devices(void)
 {
        platform_add_devices(sh7377_early_devices,
                            ARRAY_SIZE(sh7377_early_devices));
+
+       platform_add_devices(sh7377_devices,
+                           ARRAY_SIZE(sh7377_devices));
 }
 
 #define SMSTPCR3 0xe615013c
index 685c40a2f5e65139e24a8a36d74e55ecc2b9e916..e46821c0a62ef6a08aa06d6a390a9db884276861 100644 (file)
 #include <linux/input.h>
 #include <linux/io.h>
 #include <linux/serial_sci.h>
+#include <linux/sh_dma.h>
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
 #include <mach/hardware.h>
+#include <mach/sh73a0.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
@@ -392,6 +394,242 @@ static struct platform_device i2c4_device = {
        .num_resources  = ARRAY_SIZE(i2c4_resources),
 };
 
+/* Transmit sizes and respective CHCR register values */
+enum {
+       XMIT_SZ_8BIT            = 0,
+       XMIT_SZ_16BIT           = 1,
+       XMIT_SZ_32BIT           = 2,
+       XMIT_SZ_64BIT           = 7,
+       XMIT_SZ_128BIT          = 3,
+       XMIT_SZ_256BIT          = 4,
+       XMIT_SZ_512BIT          = 5,
+};
+
+/* log2(size / 8) - used to calculate number of transfers */
+#define TS_SHIFT {                     \
+       [XMIT_SZ_8BIT]          = 0,    \
+       [XMIT_SZ_16BIT]         = 1,    \
+       [XMIT_SZ_32BIT]         = 2,    \
+       [XMIT_SZ_64BIT]         = 3,    \
+       [XMIT_SZ_128BIT]        = 4,    \
+       [XMIT_SZ_256BIT]        = 5,    \
+       [XMIT_SZ_512BIT]        = 6,    \
+}
+
+#define TS_INDEX2VAL(i) ((((i) & 3) << 3) | (((i) & 0xc) << (20 - 2)))
+#define CHCR_TX(xmit_sz) (DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL((xmit_sz)))
+#define CHCR_RX(xmit_sz) (DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL((xmit_sz)))
+
+static const struct sh_dmae_slave_config sh73a0_dmae_slaves[] = {
+       {
+               .slave_id       = SHDMA_SLAVE_SCIF0_TX,
+               .addr           = 0xe6c40020,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x21,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF0_RX,
+               .addr           = 0xe6c40024,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x22,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF1_TX,
+               .addr           = 0xe6c50020,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x25,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF1_RX,
+               .addr           = 0xe6c50024,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x26,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF2_TX,
+               .addr           = 0xe6c60020,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x29,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF2_RX,
+               .addr           = 0xe6c60024,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x2a,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF3_TX,
+               .addr           = 0xe6c70020,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x2d,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF3_RX,
+               .addr           = 0xe6c70024,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x2e,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF4_TX,
+               .addr           = 0xe6c80020,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x39,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF4_RX,
+               .addr           = 0xe6c80024,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x3a,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF5_TX,
+               .addr           = 0xe6cb0020,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x35,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF5_RX,
+               .addr           = 0xe6cb0024,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x36,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF6_TX,
+               .addr           = 0xe6cc0020,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x1d,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF6_RX,
+               .addr           = 0xe6cc0024,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x1e,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF7_TX,
+               .addr           = 0xe6cd0020,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x19,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF7_RX,
+               .addr           = 0xe6cd0024,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x1a,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF8_TX,
+               .addr           = 0xe6c30040,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x3d,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF8_RX,
+               .addr           = 0xe6c30060,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x3e,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI0_TX,
+               .addr           = 0xee100030,
+               .chcr           = CHCR_TX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xc1,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI0_RX,
+               .addr           = 0xee100030,
+               .chcr           = CHCR_RX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xc2,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI1_TX,
+               .addr           = 0xee120030,
+               .chcr           = CHCR_TX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xc9,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI1_RX,
+               .addr           = 0xee120030,
+               .chcr           = CHCR_RX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xca,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI2_TX,
+               .addr           = 0xee140030,
+               .chcr           = CHCR_TX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xcd,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI2_RX,
+               .addr           = 0xee140030,
+               .chcr           = CHCR_RX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xce,
+       }, {
+               .slave_id       = SHDMA_SLAVE_MMCIF_TX,
+               .addr           = 0xe6bd0034,
+               .chcr           = CHCR_TX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xd1,
+       }, {
+               .slave_id       = SHDMA_SLAVE_MMCIF_RX,
+               .addr           = 0xe6bd0034,
+               .chcr           = CHCR_RX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xd2,
+       },
+};
+
+#define DMAE_CHANNEL(_offset)                                  \
+       {                                                       \
+               .offset         = _offset - 0x20,               \
+               .dmars          = _offset - 0x20 + 0x40,        \
+       }
+
+static const struct sh_dmae_channel sh73a0_dmae_channels[] = {
+       DMAE_CHANNEL(0x8000),
+       DMAE_CHANNEL(0x8080),
+       DMAE_CHANNEL(0x8100),
+       DMAE_CHANNEL(0x8180),
+       DMAE_CHANNEL(0x8200),
+       DMAE_CHANNEL(0x8280),
+       DMAE_CHANNEL(0x8300),
+       DMAE_CHANNEL(0x8380),
+       DMAE_CHANNEL(0x8400),
+       DMAE_CHANNEL(0x8480),
+       DMAE_CHANNEL(0x8500),
+       DMAE_CHANNEL(0x8580),
+       DMAE_CHANNEL(0x8600),
+       DMAE_CHANNEL(0x8680),
+       DMAE_CHANNEL(0x8700),
+       DMAE_CHANNEL(0x8780),
+       DMAE_CHANNEL(0x8800),
+       DMAE_CHANNEL(0x8880),
+       DMAE_CHANNEL(0x8900),
+       DMAE_CHANNEL(0x8980),
+};
+
+static const unsigned int ts_shift[] = TS_SHIFT;
+
+static struct sh_dmae_pdata sh73a0_dmae_platform_data = {
+       .slave          = sh73a0_dmae_slaves,
+       .slave_num      = ARRAY_SIZE(sh73a0_dmae_slaves),
+       .channel        = sh73a0_dmae_channels,
+       .channel_num    = ARRAY_SIZE(sh73a0_dmae_channels),
+       .ts_low_shift   = 3,
+       .ts_low_mask    = 0x18,
+       .ts_high_shift  = (20 - 2),     /* 2 bits for shifted low TS */
+       .ts_high_mask   = 0x00300000,
+       .ts_shift       = ts_shift,
+       .ts_shift_num   = ARRAY_SIZE(ts_shift),
+       .dmaor_init     = DMAOR_DME,
+};
+
+static struct resource sh73a0_dmae_resources[] = {
+       {
+               /* Registers including DMAOR and channels including DMARSx */
+               .start  = 0xfe000020,
+               .end    = 0xfe008a00 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               /* DMA error IRQ */
+               .start  = gic_spi(129),
+               .end    = gic_spi(129),
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               /* IRQ for channels 0-19 */
+               .start  = gic_spi(109),
+               .end    = gic_spi(128),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dma0_device = {
+       .name           = "sh-dma-engine",
+       .id             = 0,
+       .resource       = sh73a0_dmae_resources,
+       .num_resources  = ARRAY_SIZE(sh73a0_dmae_resources),
+       .dev            = {
+               .platform_data  = &sh73a0_dmae_platform_data,
+       },
+};
+
 static struct platform_device *sh73a0_early_devices[] __initdata = {
        &scif0_device,
        &scif1_device,
@@ -413,10 +651,16 @@ static struct platform_device *sh73a0_late_devices[] __initdata = {
        &i2c2_device,
        &i2c3_device,
        &i2c4_device,
+       &dma0_device,
 };
 
+#define SRCR2          0xe61580b0
+
 void __init sh73a0_add_standard_devices(void)
 {
+       /* Clear software reset bit on SY-DMAC module */
+       __raw_writel(__raw_readl(SRCR2) & ~(1 << 18), SRCR2);
+
        platform_add_devices(sh73a0_early_devices,
                            ARRAY_SIZE(sh73a0_early_devices));
        platform_add_devices(sh73a0_late_devices,
diff --git a/arch/arm/mach-shmobile/sleep-sh7372.S b/arch/arm/mach-shmobile/sleep-sh7372.S
new file mode 100644 (file)
index 0000000..d37d3ca
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * sh7372 lowlevel sleep code for "Core Standby Mode"
+ *
+ * Copyright (C) 2011 Magnus Damm
+ *
+ * In "Core Standby Mode" the ARM core is off, but L2 cache is still on
+ *
+ * Based on mach-omap2/sleep34xx.S
+ *
+ * (C) Copyright 2007 Texas Instruments
+ * Karthik Dasu <karthik-dp@ti.com>
+ *
+ * (C) Copyright 2004 Texas Instruments, <www.ti.com>
+ * Richard Woodruff <r-woodruff2@ti.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/linkage.h>
+#include <asm/assembler.h>
+
+#define SMFRAM 0xe6a70000
+
+       .align
+kernel_flush:
+       .word   v7_flush_dcache_all
+
+       .align  3
+ENTRY(sh7372_cpu_suspend)
+       stmfd   sp!, {r0-r12, lr}       @ save registers on stack
+
+       ldr     r8, =SMFRAM
+
+       mov     r4, sp                  @ Store sp
+       mrs     r5, spsr                @ Store spsr
+       mov     r6, lr                  @ Store lr
+       stmia   r8!, {r4-r6}
+
+       mrc     p15, 0, r4, c1, c0, 2   @ Coprocessor access control register
+       mrc     p15, 0, r5, c2, c0, 0   @ TTBR0
+       mrc     p15, 0, r6, c2, c0, 1   @ TTBR1
+       mrc     p15, 0, r7, c2, c0, 2   @ TTBCR
+       stmia   r8!, {r4-r7}
+
+       mrc     p15, 0, r4, c3, c0, 0   @ Domain access Control Register
+       mrc     p15, 0, r5, c10, c2, 0  @ PRRR
+       mrc     p15, 0, r6, c10, c2, 1  @ NMRR
+       stmia   r8!,{r4-r6}
+
+       mrc     p15, 0, r4, c13, c0, 1  @ Context ID
+       mrc     p15, 0, r5, c13, c0, 2  @ User r/w thread and process ID
+       mrc     p15, 0, r6, c12, c0, 0  @ Secure or NS vector base address
+       mrs     r7, cpsr                @ Store current cpsr
+       stmia   r8!, {r4-r7}
+
+       mrc     p15, 0, r4, c1, c0, 0   @ save control register
+       stmia   r8!, {r4}
+
+       /*
+        * jump out to kernel flush routine
+        *  - reuse that code is better
+        *  - it executes in a cached space so is faster than refetch per-block
+        *  - should be faster and will change with kernel
+        *  - 'might' have to copy address, load and jump to it
+        * Flush all data from the L1 data cache before disabling
+        * SCTLR.C bit.
+        */
+       ldr     r1, kernel_flush
+       mov     lr, pc
+       bx      r1
+
+       /*
+        * Clear the SCTLR.C bit to prevent further data cache
+        * allocation. Clearing SCTLR.C would make all the data accesses
+        * strongly ordered and would not hit the cache.
+        */
+       mrc     p15, 0, r0, c1, c0, 0
+       bic     r0, r0, #(1 << 2)       @ Disable the C bit
+       mcr     p15, 0, r0, c1, c0, 0
+       isb
+
+       /*
+        * Invalidate L1 data cache. Even though only invalidate is
+        * necessary exported flush API is used here. Doing clean
+        * on already clean cache would be almost NOP.
+        */
+       ldr     r1, kernel_flush
+       blx     r1
+       /*
+        * The kernel doesn't interwork: v7_flush_dcache_all in particluar will
+        * always return in Thumb state when CONFIG_THUMB2_KERNEL is enabled.
+        * This sequence switches back to ARM.  Note that .align may insert a
+        * nop: bx pc needs to be word-aligned in order to work.
+        */
+ THUMB(        .thumb          )
+ THUMB(        .align          )
+ THUMB(        bx      pc      )
+ THUMB(        nop             )
+       .arm
+
+       /* Data memory barrier and Data sync barrier */
+       dsb
+       dmb
+
+/*
+ * ===================================
+ * == WFI instruction => Enter idle ==
+ * ===================================
+ */
+       wfi                             @ wait for interrupt
+
+/*
+ * ===================================
+ * == Resume path for non-OFF modes ==
+ * ===================================
+ */
+       mrc     p15, 0, r0, c1, c0, 0
+       tst     r0, #(1 << 2)           @ Check C bit enabled?
+       orreq   r0, r0, #(1 << 2)       @ Enable the C bit if cleared
+       mcreq   p15, 0, r0, c1, c0, 0
+       isb
+
+/*
+ * ===================================
+ * == Exit point from non-OFF modes ==
+ * ===================================
+ */
+       ldmfd   sp!, {r0-r12, pc}       @ restore regs and return
+
+       .pool
+
+       .align  12
+       .text
+       .global sh7372_cpu_resume
+sh7372_cpu_resume:
+
+       mov     r1, #0
+       /*
+        * Invalidate all instruction caches to PoU
+        * and flush branch target cache
+        */
+       mcr     p15, 0, r1, c7, c5, 0
+
+       ldr     r3, =SMFRAM
+
+       ldmia   r3!, {r4-r6}
+       mov     sp, r4                  @ Restore sp
+       msr     spsr_cxsf, r5           @ Restore spsr
+       mov     lr, r6                  @ Restore lr
+
+       ldmia   r3!, {r4-r7}
+       mcr     p15, 0, r4, c1, c0, 2   @ Coprocessor access Control Register
+       mcr     p15, 0, r5, c2, c0, 0   @ TTBR0
+       mcr     p15, 0, r6, c2, c0, 1   @ TTBR1
+       mcr     p15, 0, r7, c2, c0, 2   @ TTBCR
+
+       ldmia   r3!,{r4-r6}
+       mcr     p15, 0, r4, c3, c0, 0   @ Domain access Control Register
+       mcr     p15, 0, r5, c10, c2, 0  @ PRRR
+       mcr     p15, 0, r6, c10, c2, 1  @ NMRR
+
+       ldmia   r3!,{r4-r7}
+       mcr     p15, 0, r4, c13, c0, 1  @ Context ID
+       mcr     p15, 0, r5, c13, c0, 2  @ User r/w thread and process ID
+       mrc     p15, 0, r6, c12, c0, 0  @ Secure or NS vector base address
+       msr     cpsr, r7                @ store cpsr
+
+       /* Starting to enable MMU here */
+       mrc     p15, 0, r7, c2, c0, 2   @ Read TTBRControl
+       /* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1 */
+       and     r7, #0x7
+       cmp     r7, #0x0
+       beq     usettbr0
+ttbr_error:
+       /*
+        * More work needs to be done to support N[0:2] value other than 0
+        * So looping here so that the error can be detected
+        */
+       b       ttbr_error
+
+       .align
+cache_pred_disable_mask:
+       .word   0xFFFFE7FB
+ttbrbit_mask:
+       .word   0xFFFFC000
+table_index_mask:
+       .word   0xFFF00000
+table_entry:
+       .word   0x00000C02
+usettbr0:
+
+       mrc     p15, 0, r2, c2, c0, 0
+       ldr     r5, ttbrbit_mask
+       and     r2, r5
+       mov     r4, pc
+       ldr     r5, table_index_mask
+       and     r4, r5                  @ r4 = 31 to 20 bits of pc
+       /* Extract the value to be written to table entry */
+       ldr     r6, table_entry
+       /* r6 has the value to be written to table entry */
+       add     r6, r6, r4
+       /* Getting the address of table entry to modify */
+       lsr     r4, #18
+       /* r2 has the location which needs to be modified */
+       add     r2, r4
+       ldr     r4, [r2]
+       str     r6, [r2] /* modify the table entry */
+
+       mov     r7, r6
+       mov     r5, r2
+       mov     r6, r4
+       /* r5 = original page table address */
+       /* r6 = original page table data */
+
+       mov     r0, #0
+       mcr     p15, 0, r0, c7, c5, 4   @ Flush prefetch buffer
+       mcr     p15, 0, r0, c7, c5, 6   @ Invalidate branch predictor array
+       mcr     p15, 0, r0, c8, c5, 0   @ Invalidate instruction TLB
+       mcr     p15, 0, r0, c8, c6, 0   @ Invalidate data TLB
+
+       /*
+        * Restore control register. This enables the MMU.
+        * The caches and prediction are not enabled here, they
+        * will be enabled after restoring the MMU table entry.
+        */
+       ldmia   r3!, {r4}
+       stmia   r3!, {r5} /* save original page table address */
+       stmia   r3!, {r6} /* save original page table data */
+       stmia   r3!, {r7} /* save modified page table data */
+
+       ldr     r2, cache_pred_disable_mask
+       and     r4, r2
+       mcr     p15, 0, r4, c1, c0, 0
+       dsb
+       isb
+
+       ldr     r0, =restoremmu_on
+       bx      r0
+
+/*
+ * ==============================
+ * == Exit point from OFF mode ==
+ * ==============================
+ */
+restoremmu_on:
+
+       ldmfd   sp!, {r0-r12, pc}       @ restore regs and return
index a156d2108df1a9cf582340155557a7a7caf3615e..3ffdbc92ba828ddd0755ecc73648edc48539021a 100644 (file)
@@ -59,6 +59,11 @@ unsigned int __init sh73a0_get_core_count(void)
 {
        void __iomem *scu_base = scu_base_addr();
 
+#ifdef CONFIG_HAVE_ARM_TWD
+       /* twd_base needs to be initialized before percpu_timer_setup() */
+       twd_base = (void __iomem *)0xf0000600;
+#endif
+
        return scu_get_core_count(scu_base);
 }
 
@@ -82,10 +87,6 @@ int __cpuinit sh73a0_boot_secondary(unsigned int cpu)
 
 void __init sh73a0_smp_prepare_cpus(void)
 {
-#ifdef CONFIG_HAVE_ARM_TWD
-       twd_base = (void __iomem *)0xf0000600;
-#endif
-
        scu_enable(scu_base_addr());
 
        /* Map the reset vector (in headsmp.S) */
diff --git a/arch/arm/mach-shmobile/suspend.c b/arch/arm/mach-shmobile/suspend.c
new file mode 100644 (file)
index 0000000..c1febe1
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Suspend-to-RAM support code for SH-Mobile ARM
+ *
+ *  Copyright (C) 2011 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/pm.h>
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+static int shmobile_suspend_default_enter(suspend_state_t suspend_state)
+{
+       cpu_do_idle();
+       return 0;
+}
+
+static int shmobile_suspend_begin(suspend_state_t state)
+{
+       disable_hlt();
+       return 0;
+}
+
+static void shmobile_suspend_end(void)
+{
+       enable_hlt();
+}
+
+struct platform_suspend_ops shmobile_suspend_ops = {
+       .begin          = shmobile_suspend_begin,
+       .end            = shmobile_suspend_end,
+       .enter          = shmobile_suspend_default_enter,
+       .valid          = suspend_valid_only_mem,
+};
+
+static int __init shmobile_suspend_init(void)
+{
+       suspend_set_ops(&shmobile_suspend_ops);
+       return 0;
+}
+late_initcall(shmobile_suspend_init);
index c84442cabe077b3fad50b110641cbbd95f96afd8..5ad8b2f94f8dbbbaa374c2c6ab307c307591ce72 100644 (file)
@@ -24,6 +24,8 @@
 
 #include <mach/irqs.h>
 
+#include "board-harmony.h"
+
 #define PMC_CTRL               0x0
 #define PMC_CTRL_INTR_LOW      (1 << 17)
 
@@ -98,7 +100,7 @@ static struct tps6586x_platform_data tps_platform = {
        .irq_base       = TEGRA_NR_IRQS,
        .num_subdevs    = ARRAY_SIZE(tps_devs),
        .subdevs        = tps_devs,
-       .gpio_base      = TEGRA_NR_GPIOS,
+       .gpio_base      = HARMONY_GPIO_TPS6586X(0),
 };
 
 static struct i2c_board_info __initdata harmony_regulators[] = {
index 1e57b071f52de9c6d37178bca02f0d6a563db1e8..d85142edaf6bc0eebc7d66b385e457d91fc5a100 100644 (file)
@@ -17,7 +17,8 @@
 #ifndef _MACH_TEGRA_BOARD_HARMONY_H
 #define _MACH_TEGRA_BOARD_HARMONY_H
 
-#define HARMONY_GPIO_WM8903(_x_)       (TEGRA_NR_GPIOS + (_x_))
+#define HARMONY_GPIO_TPS6586X(_x_)     (TEGRA_NR_GPIOS + (_x_))
+#define HARMONY_GPIO_WM8903(_x_)       (HARMONY_GPIO_TPS6586X(4) + (_x_))
 
 #define TEGRA_GPIO_SD2_CD              TEGRA_GPIO_PI5
 #define TEGRA_GPIO_SD2_WP              TEGRA_GPIO_PH1
index 04c779832c78efb86eb590cd063171925af91a25..4f3572a1c684422bbf00e4c2990d472285c7fba8 100644 (file)
@@ -50,13 +50,11 @@ struct tegra_kbc_platform_data {
        unsigned int debounce_cnt;
        unsigned int repeat_cnt;
 
-       unsigned int wake_cnt; /* 0:wake on any key >1:wake on wake_cfg */
-       const struct tegra_kbc_wake_key *wake_cfg;
-
        struct tegra_kbc_pin_cfg pin_cfg[KBC_MAX_GPIO];
        const struct matrix_keymap_data *keymap_data;
 
        bool wakeup;
        bool use_fn_map;
+       bool use_ghost_filter;
 };
 #endif
index 3ad086e859c38f91696e832e4a51358afb40bcd2..4231bc7b865206a7fa4f21a8ae02b227374a7ec9 100644 (file)
@@ -24,6 +24,7 @@ struct tegra_sdhci_platform_data {
        int wp_gpio;
        int power_gpio;
        int is_8bit;
+       int pm_flags;
 };
 
 #endif
index fab46fe9a71f7b7061d2aa9e8f485f1449b625f1..8fd354aaf0a7f5c9aa309ee69b490e604868fc65 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the linux kernel, U300 machine.
 #
 
-obj-y          := core.o clock.o timer.o gpio.o padmux.o
+obj-y          := core.o clock.o timer.o padmux.o
 obj-m          :=
 obj-n          :=
 obj-           :=
index c34f3ea3017c4db1b4da624b12c1f800e24a91b0..4f50ca8f901e2bebd5de51defd425ba9e83f9ff4 100644 (file)
@@ -31,7 +31,7 @@ struct clk {
        bool reset;
        __u16 clk_val;
        __s8 usecount;
-       __u32 res_reg;
+       void __iomem * res_reg;
        __u16 res_mask;
 
        bool hw_ctrld;
index 8b85df4c8d8fcce5530535ffb2d91e15f25b636d..035fdc9dbdb03ebb50e88873a67232707d4fbc50 100644 (file)
  * the defines are used for setting up the I/O memory mapping.
  */
 
+#ifdef __ASSEMBLER__
+#define IOMEM(a) (a)
+#else
+#define IOMEM(a) (void __iomem *) a
+#endif
+
 /* NAND Flash CS0 */
 #define U300_NAND_CS0_PHYS_BASE                0x80000000
 
 #define U300_SEMI_CONFIG_BASE          0x30000000
 #endif
 
-/*
- * All the following peripherals are specified at their PHYSICAL address,
- * so if you need to access them (in the kernel), you MUST use the macros
- * defined in <asm/io.h> to map to the IO_ADDRESS_AHB() IO_ADDRESS_FAST()
- * etc.
- */
-
 /*
  * AHB peripherals
  */
 
 /* Vectored Interrupt Controller 0, servicing 32 interrupts */
 #define U300_INTCON0_BASE              (U300_AHB_PER_PHYS_BASE+0x1000)
-#define U300_INTCON0_VBASE             (U300_AHB_PER_VIRT_BASE+0x1000)
+#define U300_INTCON0_VBASE             IOMEM(U300_AHB_PER_VIRT_BASE+0x1000)
 
 /* Vectored Interrupt Controller 1, servicing 32 interrupts */
 #define U300_INTCON1_BASE              (U300_AHB_PER_PHYS_BASE+0x2000)
-#define U300_INTCON1_VBASE             (U300_AHB_PER_VIRT_BASE+0x2000)
+#define U300_INTCON1_VBASE             IOMEM(U300_AHB_PER_VIRT_BASE+0x2000)
 
 /* Memory Stick Pro (MSPRO) controller */
 #define U300_MSPRO_BASE                        (U300_AHB_PER_PHYS_BASE+0x3000)
 
 /* SYSCON */
 #define U300_SYSCON_BASE               (U300_SLOW_PER_PHYS_BASE+0x1000)
-#define U300_SYSCON_VBASE              (U300_SLOW_PER_VIRT_BASE+0x1000)
+#define U300_SYSCON_VBASE              IOMEM(U300_SLOW_PER_VIRT_BASE+0x1000)
 
 /* Watchdog */
 #define U300_WDOG_BASE                 (U300_SLOW_PER_PHYS_BASE+0x2000)
 
 /* APP side special timer */
 #define U300_TIMER_APP_BASE            (U300_SLOW_PER_PHYS_BASE+0x4000)
-#define U300_TIMER_APP_VBASE           (U300_SLOW_PER_VIRT_BASE+0x4000)
+#define U300_TIMER_APP_VBASE           IOMEM(U300_SLOW_PER_VIRT_BASE+0x4000)
 
 /* Keypad */
 #define U300_KEYPAD_BASE               (U300_SLOW_PER_PHYS_BASE+0x5000)
  * Virtual accessor macros for static devices
  */
 
-
 #endif
index 891cf44591e073ea4de84968d33f598595a8263c..18d7fa0603c230259ff96d3f9dc910b4a53a3b04 100644 (file)
@@ -411,8 +411,7 @@ static void __init u300_timer_init(void)
        /* Use general purpose timer 2 as clock source */
        if (clocksource_mmio_init(U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2CC,
                        "GPT2", rate, 300, 32, clocksource_mmio_readl_up))
-               printk(KERN_ERR "timer: failed to initialize clock "
-                      "source %s\n", clocksource_u300_1mhz.name);
+               pr_err("timer: failed to initialize U300 clock source\n");
 
        clockevents_calc_mult_shift(&clockevent_u300_1mhz,
                                    rate, APPTIMER_MIN_RANGE);
index 58626013aa322874bd0ebd33eb5ce22f2bb3ab1f..f8b9392ee3471b7628a7f8fcfd7ce50d7d52f269 100644 (file)
@@ -5,16 +5,18 @@ config UX500_SOC_COMMON
        default y
        select ARM_GIC
        select HAS_MTU
-       select NOMADIK_GPIO
        select ARM_ERRATA_753970
 
 menu "Ux500 SoC"
 
 config UX500_SOC_DB5500
        bool "DB5500"
+       select MFD_DB5500_PRCMU
 
 config UX500_SOC_DB8500
        bool "DB8500"
+       select MFD_DB8500_PRCMU
+       select REGULATOR_DB8500_PRCMU
 
 endmenu
 
index b549a8fb4231a6b8d30e4860e83f45460323bb1f..1694916e68229f543609a6a5c68dfa7c8216b790 100644 (file)
@@ -5,7 +5,7 @@
 obj-y                          := clock.o cpu.o devices.o devices-common.o \
                                   id.o usb.o
 obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o dma-db5500.o
-obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o prcmu.o
+obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o
 obj-$(CONFIG_MACH_U8500)       += board-mop500.o board-mop500-sdi.o \
                                board-mop500-regulators.o \
                                board-mop500-uib.o board-mop500-stuib.o \
@@ -17,4 +17,4 @@ obj-$(CONFIG_HOTPLUG_CPU)     += hotplug.o
 obj-$(CONFIG_LOCAL_TIMERS)     += localtimer.o
 obj-$(CONFIG_U5500_MODEM_IRQ)  += modem-irq-db5500.o
 obj-$(CONFIG_U5500_MBOX)       += mbox-db5500.o
-obj-$(CONFIG_CPU_FREQ)         += cpufreq.o
+
index bf0b02414e5bfeed31f61c3db596714bab8aeb64..7c6cb4fa47a937211b16917cd63d5ac008bd574c 100644 (file)
@@ -99,8 +99,11 @@ static void sdi0_configure(void)
        gpio_direction_output(sdi0_vsel, 0);
        gpio_direction_output(sdi0_en, 1);
 
-       /* Add the device */
-       db8500_add_sdi0(&mop500_sdi0_data);
+       /* Add the device, force v2 to subrevision 1 */
+       if (cpu_is_u8500v2())
+               db8500_add_sdi0(&mop500_sdi0_data, 0x10480180);
+       else
+               db8500_add_sdi0(&mop500_sdi0_data, 0);
 }
 
 void mop500_sdi_tc35892_init(void)
@@ -188,13 +191,18 @@ static struct mmci_platform_data mop500_sdi4_data = {
 
 void __init mop500_sdi_init(void)
 {
+       u32 periphid = 0;
+
+       /* v2 has a new version of this block that need to be forced */
+       if (cpu_is_u8500v2())
+               periphid = 0x10480180;
        /* PoP:ed eMMC on top of DB8500 v1.0 has problems with high speed */
        if (!cpu_is_u8500v10())
                mop500_sdi2_data.capabilities |= MMC_CAP_MMC_HIGHSPEED;
-       db8500_add_sdi2(&mop500_sdi2_data);
+       db8500_add_sdi2(&mop500_sdi2_data, periphid);
 
        /* On-board eMMC */
-       db8500_add_sdi4(&mop500_sdi4_data);
+       db8500_add_sdi4(&mop500_sdi4_data, periphid);
 
        if (machine_is_hrefv60()) {
                mop500_sdi0_data.gpio_cd = HREFV60_SDMMC_CD_GPIO;
index 6e1907fa94f0405a788acd8896b9202a8a4c67c0..bb26f40493e697ffe9a6805ae65acd896b9e12e5 100644 (file)
@@ -204,7 +204,7 @@ static struct i2c_board_info __initdata mop500_i2c2_devices[] = {
        },
 };
 
-#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \
+#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, t_out, _sm)   \
 static struct nmk_i2c_controller u8500_i2c##id##_data = { \
        /*                              \
         * slave data setup time, which is      \
@@ -219,19 +219,21 @@ static struct nmk_i2c_controller u8500_i2c##id##_data = { \
        .rft            = _rft,         \
        /* std. mode operation */       \
        .clk_freq       = clk,          \
+       /* Slave response timeout(ms) */\
+       .timeout        = t_out,        \
        .sm             = _sm,          \
 }
 
 /*
  * The board uses 4 i2c controllers, initialize all of
  * them with slave data setup time of 250 ns,
- * Tx & Rx FIFO threshold values as 1 and standard
+ * Tx & Rx FIFO threshold values as 8 and standard
  * mode of operation
  */
-U8500_I2C_CONTROLLER(0, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
-U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
-U8500_I2C_CONTROLLER(2,        0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
-U8500_I2C_CONTROLLER(3,        0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
+U8500_I2C_CONTROLLER(0, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
+U8500_I2C_CONTROLLER(1, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
+U8500_I2C_CONTROLLER(2,        0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
+U8500_I2C_CONTROLLER(3,        0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
 
 static void __init mop500_i2c_init(void)
 {
index c9dc2eff3cb2d5a8677c16ee7e43ec6d992c47b9..c01bc19e3c5eac6c51d3adf1cffb13333a29047b 100644 (file)
@@ -188,6 +188,8 @@ void __init u5500_map_io(void)
        ux500_map_io();
 
        iotable_init(u5500_io_desc, ARRAY_SIZE(u5500_io_desc));
+
+       _PRCMU_BASE = __io_address(U5500_PRCMU_BASE);
 }
 
 static int usb_db5500_rx_dma_cfg[] = {
index 516126cb357dfeb52d918e57d4af4598669773d1..4598b06c8c554383a711b205f103ebfae29b87e7 100644 (file)
@@ -87,6 +87,8 @@ void __init u8500_map_io(void)
                iotable_init(u8500_v1_io_desc, ARRAY_SIZE(u8500_v1_io_desc));
        else if (cpu_is_u8500v2())
                iotable_init(u8500_v2_io_desc, ARRAY_SIZE(u8500_v2_io_desc));
+
+       _PRCMU_BASE = __io_address(U8500_PRCMU_BASE);
 }
 
 static struct resource db8500_pmu_resources[] = {
@@ -129,9 +131,14 @@ static struct platform_device db8500_pmu_device = {
        .dev.platform_data      = &db8500_pmu_platdata,
 };
 
+static struct platform_device db8500_prcmu_device = {
+       .name                   = "db8500-prcmu",
+};
+
 static struct platform_device *platform_devs[] __initdata = {
        &u8500_dma40_device,
        &db8500_pmu_device,
+       &db8500_prcmu_device,
 };
 
 static resource_size_t __initdata db8500_gpio_base[] = {
@@ -152,6 +159,9 @@ static void __init db8500_add_gpios(void)
                /* No custom data yet */
        };
 
+       if (cpu_is_u8500v2())
+               pdata.supports_sleepmode = true;
+
        dbx500_add_gpios(ARRAY_AND_SIZE(db8500_gpio_base),
                         IRQ_DB8500_GPIO0, &pdata);
 }
index 5a43107c62325fc8a3f533053777ca0385cdc436..1da23bb87c16bcec2047d9ac8e08e474d2f505ce 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/clk.h>
+#include <linux/mfd/db8500-prcmu.h>
+#include <linux/mfd/db5500-prcmu.h>
 
 #include <asm/cacheflush.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <mach/hardware.h>
 #include <mach/setup.h>
 #include <mach/devices.h>
-#include <mach/prcmu.h>
 
 #include "clock.h"
 
+void __iomem *_PRCMU_BASE;
+
 #ifdef CONFIG_CACHE_L2X0
 static void __iomem *l2x0_base;
 #endif
@@ -47,6 +50,8 @@ void __init ux500_init_irq(void)
         * Init clocks here so that they are available for system timer
         * initialization.
         */
+       if (cpu_is_u5500())
+               db5500_prcmu_early_init();
        if (cpu_is_u8500())
                prcmu_early_init();
        clk_init();
diff --git a/arch/arm/mach-ux500/cpufreq.c b/arch/arm/mach-ux500/cpufreq.c
deleted file mode 100644 (file)
index 5c5b747..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * CPU frequency scaling for u8500
- * Inspired by linux/arch/arm/mach-davinci/cpufreq.c
- *
- * Copyright (C) STMicroelectronics 2009
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- *
- * Author: Sundar Iyer <sundar.iyer@stericsson.com>
- * Author: Martin Persson <martin.persson@stericsson.com>
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
- *
- */
-
-#include <linux/platform_device.h>
-#include <linux/kernel.h>
-#include <linux/cpufreq.h>
-#include <linux/delay.h>
-
-#include <mach/hardware.h>
-#include <mach/prcmu.h>
-#include <mach/prcmu-defs.h>
-
-#define DRIVER_NAME "cpufreq-u8500"
-#define CPUFREQ_NAME "u8500"
-
-static struct device *dev;
-
-static struct cpufreq_frequency_table freq_table[] = {
-       [0] = {
-               .index = 0,
-               .frequency = 200000,
-       },
-       [1] = {
-               .index = 1,
-               .frequency = 300000,
-       },
-       [2] = {
-               .index = 2,
-               .frequency = 600000,
-       },
-       [3] = {
-               /* Used for CPU_OPP_MAX, if available */
-               .index = 3,
-               .frequency = CPUFREQ_TABLE_END,
-       },
-       [4] = {
-               .index = 4,
-               .frequency = CPUFREQ_TABLE_END,
-       },
-};
-
-static enum prcmu_cpu_opp index2opp[] = {
-       CPU_OPP_EXT_CLK,
-       CPU_OPP_50,
-       CPU_OPP_100,
-       CPU_OPP_MAX
-};
-
-static int u8500_cpufreq_verify_speed(struct cpufreq_policy *policy)
-{
-       return cpufreq_frequency_table_verify(policy, freq_table);
-}
-
-static int u8500_cpufreq_target(struct cpufreq_policy *policy,
-                               unsigned int target_freq,
-                               unsigned int relation)
-{
-       struct cpufreq_freqs freqs;
-       unsigned int index;
-       int ret = 0;
-
-       /*
-        * Ensure desired rate is within allowed range.  Some govenors
-        * (ondemand) will just pass target_freq=0 to get the minimum.
-        */
-       if (target_freq < policy->cpuinfo.min_freq)
-               target_freq = policy->cpuinfo.min_freq;
-       if (target_freq > policy->cpuinfo.max_freq)
-               target_freq = policy->cpuinfo.max_freq;
-
-       ret = cpufreq_frequency_table_target(policy, freq_table,
-                                            target_freq, relation, &index);
-       if (ret < 0) {
-               dev_err(dev, "Could not look up next frequency\n");
-               return ret;
-       }
-
-       freqs.old = policy->cur;
-       freqs.new = freq_table[index].frequency;
-       freqs.cpu = policy->cpu;
-
-       if (freqs.old == freqs.new) {
-               dev_dbg(dev, "Current and target frequencies are equal\n");
-               return 0;
-       }
-
-       dev_dbg(dev, "transition: %u --> %u\n", freqs.old, freqs.new);
-       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-
-       ret = prcmu_set_cpu_opp(index2opp[index]);
-       if (ret < 0) {
-               dev_err(dev, "Failed to set OPP level\n");
-               return ret;
-       }
-
-       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
-       return ret;
-}
-
-static unsigned int u8500_cpufreq_getspeed(unsigned int cpu)
-{
-       int i;
-
-       for (i = 0; prcmu_get_cpu_opp() != index2opp[i]; i++)
-               ;
-       return freq_table[i].frequency;
-}
-
-static int __cpuinit u8500_cpu_init(struct cpufreq_policy *policy)
-{
-       int res;
-
-       BUILD_BUG_ON(ARRAY_SIZE(index2opp) + 1 != ARRAY_SIZE(freq_table));
-
-       if (cpu_is_u8500v2()) {
-               freq_table[1].frequency = 400000;
-               freq_table[2].frequency = 800000;
-               if (prcmu_has_arm_maxopp())
-                       freq_table[3].frequency = 1000000;
-       }
-
-       /* get policy fields based on the table */
-       res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
-       if (!res)
-               cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
-       else {
-               dev_err(dev, "u8500-cpufreq : Failed to read policy table\n");
-               return res;
-       }
-
-       policy->min = policy->cpuinfo.min_freq;
-       policy->max = policy->cpuinfo.max_freq;
-       policy->cur = u8500_cpufreq_getspeed(policy->cpu);
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
-       /*
-        * FIXME : Need to take time measurement across the target()
-        *         function with no/some/all drivers in the notification
-        *         list.
-        */
-       policy->cpuinfo.transition_latency = 200 * 1000; /* in ns */
-
-       /* policy sharing between dual CPUs */
-       cpumask_copy(policy->cpus, &cpu_present_map);
-
-       policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
-
-       return res;
-}
-
-static struct freq_attr *u8500_cpufreq_attr[] = {
-       &cpufreq_freq_attr_scaling_available_freqs,
-       NULL,
-};
-static int u8500_cpu_exit(struct cpufreq_policy *policy)
-{
-       cpufreq_frequency_table_put_attr(policy->cpu);
-       return 0;
-}
-
-static struct cpufreq_driver u8500_driver = {
-       .owner = THIS_MODULE,
-       .flags = CPUFREQ_STICKY,
-       .verify = u8500_cpufreq_verify_speed,
-       .target = u8500_cpufreq_target,
-       .get = u8500_cpufreq_getspeed,
-       .init = u8500_cpu_init,
-       .exit = u8500_cpu_exit,
-       .name = CPUFREQ_NAME,
-       .attr = u8500_cpufreq_attr,
-};
-
-static int __init u8500_cpufreq_probe(struct platform_device *pdev)
-{
-       dev = &pdev->dev;
-       return cpufreq_register_driver(&u8500_driver);
-}
-
-static int __exit u8500_cpufreq_remove(struct platform_device *pdev)
-{
-       return cpufreq_unregister_driver(&u8500_driver);
-}
-
-static struct platform_driver u8500_cpufreq_driver = {
-       .driver = {
-               .name    = DRIVER_NAME,
-               .owner   = THIS_MODULE,
-       },
-       .remove = __exit_p(u8500_cpufreq_remove),
-};
-
-static int __init u8500_cpufreq_init(void)
-{
-       return platform_driver_probe(&u8500_cpufreq_driver,
-                                    &u8500_cpufreq_probe);
-}
-
-device_initcall(u8500_cpufreq_init);
index c719b5a1d9130ee47f36e97889686ee7c7038ad0..7825705033bfe6e18881e6e8fa15aaa2d8c4d82f 100644 (file)
@@ -28,18 +28,20 @@ dbx500_add_msp_spi(const char *name, resource_size_t base, int irq,
 
 static inline struct amba_device *
 dbx500_add_spi(const char *name, resource_size_t base, int irq,
-                                  struct spi_master_cntlr *pdata)
+              struct spi_master_cntlr *pdata,
+              u32 periphid)
 {
-       return dbx500_add_amba_device(name, base, irq, pdata, 0);
+       return dbx500_add_amba_device(name, base, irq, pdata, periphid);
 }
 
 struct mmci_platform_data;
 
 static inline struct amba_device *
 dbx500_add_sdi(const char *name, resource_size_t base, int irq,
-              struct mmci_platform_data *pdata)
+              struct mmci_platform_data *pdata,
+              u32 periphid)
 {
-       return dbx500_add_amba_device(name, base, irq, pdata, 0);
+       return dbx500_add_amba_device(name, base, irq, pdata, periphid);
 }
 
 struct amba_pl011_data;
index 94627f7783b033458b98eb401aae9ccdfd7eeb6a..0c4bccd02b90fe2836c4b8954235bf88d5eac270 100644 (file)
        ux500_add_usb(U5500_USBOTG_BASE, IRQ_DB5500_USBOTG, rx_cfg, tx_cfg)
 
 #define db5500_add_sdi0(pdata) \
-       dbx500_add_sdi("sdi0", U5500_SDI0_BASE, IRQ_DB5500_SDMMC0, pdata)
+       dbx500_add_sdi("sdi0", U5500_SDI0_BASE, IRQ_DB5500_SDMMC0, pdata, \
+                      0x10480180)
 #define db5500_add_sdi1(pdata) \
-       dbx500_add_sdi("sdi1", U5500_SDI1_BASE, IRQ_DB5500_SDMMC1, pdata)
+       dbx500_add_sdi("sdi1", U5500_SDI1_BASE, IRQ_DB5500_SDMMC1, pdata, \
+                      0x10480180)
 #define db5500_add_sdi2(pdata) \
-       dbx500_add_sdi("sdi2", U5500_SDI2_BASE, IRQ_DB5500_SDMMC2, pdata)
+       dbx500_add_sdi("sdi2", U5500_SDI2_BASE, IRQ_DB5500_SDMMC2, pdata \
+                      0x10480180)
 #define db5500_add_sdi3(pdata) \
-       dbx500_add_sdi("sdi3", U5500_SDI3_BASE, IRQ_DB5500_SDMMC3, pdata)
+       dbx500_add_sdi("sdi3", U5500_SDI3_BASE, IRQ_DB5500_SDMMC3, pdata \
+                      0x10480180)
 #define db5500_add_sdi4(pdata) \
-       dbx500_add_sdi("sdi4", U5500_SDI4_BASE, IRQ_DB5500_SDMMC4, pdata)
+       dbx500_add_sdi("sdi4", U5500_SDI4_BASE, IRQ_DB5500_SDMMC4, pdata \
+                      0x10480180)
 
+/* This one has a bad peripheral ID in the U5500 silicon */
 #define db5500_add_spi0(pdata) \
-       dbx500_add_spi("spi0", U5500_SPI0_BASE, IRQ_DB5500_SPI0, pdata)
+       dbx500_add_spi("spi0", U5500_SPI0_BASE, IRQ_DB5500_SPI0, pdata, \
+                      0x10080023)
 #define db5500_add_spi1(pdata) \
-       dbx500_add_spi("spi1", U5500_SPI1_BASE, IRQ_DB5500_SPI1, pdata)
+       dbx500_add_spi("spi1", U5500_SPI1_BASE, IRQ_DB5500_SPI1, pdata, \
+                      0x10080023)
 #define db5500_add_spi2(pdata) \
-       dbx500_add_spi("spi2", U5500_SPI2_BASE, IRQ_DB5500_SPI2, pdata)
+       dbx500_add_spi("spi2", U5500_SPI2_BASE, IRQ_DB5500_SPI2, pdata \
+                      0x10080023)
 #define db5500_add_spi3(pdata) \
-       dbx500_add_spi("spi3", U5500_SPI3_BASE, IRQ_DB5500_SPI3, pdata)
+       dbx500_add_spi("spi3", U5500_SPI3_BASE, IRQ_DB5500_SPI3, pdata \
+                      0x10080023)
 
 #define db5500_add_uart0(plat) \
        dbx500_add_uart("uart0", U5500_UART0_BASE, IRQ_DB5500_UART0, plat)
index 9cc6f8f5d3e621c9008c1006ef6c59bda65cd8b4..cbd4a9ae81093a14e7ca73c67cadc0869c6d579d 100644 (file)
@@ -25,7 +25,7 @@ static inline struct amba_device *
 db8500_add_ssp(const char *name, resource_size_t base, int irq,
               struct pl022_ssp_controller *pdata)
 {
-       return dbx500_add_amba_device(name, base, irq, pdata, SSP_PER_ID);
+       return dbx500_add_amba_device(name, base, irq, pdata, 0);
 }
 
 
@@ -64,18 +64,18 @@ db8500_add_ssp(const char *name, resource_size_t base, int irq,
 #define db8500_add_usb(rx_cfg, tx_cfg) \
        ux500_add_usb(U8500_USBOTG_BASE, IRQ_DB8500_USBOTG, rx_cfg, tx_cfg)
 
-#define db8500_add_sdi0(pdata) \
-       dbx500_add_sdi("sdi0", U8500_SDI0_BASE, IRQ_DB8500_SDMMC0, pdata)
-#define db8500_add_sdi1(pdata) \
-       dbx500_add_sdi("sdi1", U8500_SDI1_BASE, IRQ_DB8500_SDMMC1, pdata)
-#define db8500_add_sdi2(pdata) \
-       dbx500_add_sdi("sdi2", U8500_SDI2_BASE, IRQ_DB8500_SDMMC2, pdata)
-#define db8500_add_sdi3(pdata) \
-       dbx500_add_sdi("sdi3", U8500_SDI3_BASE, IRQ_DB8500_SDMMC3, pdata)
-#define db8500_add_sdi4(pdata) \
-       dbx500_add_sdi("sdi4", U8500_SDI4_BASE, IRQ_DB8500_SDMMC4, pdata)
-#define db8500_add_sdi5(pdata) \
-       dbx500_add_sdi("sdi5", U8500_SDI5_BASE, IRQ_DB8500_SDMMC5, pdata)
+#define db8500_add_sdi0(pdata, pid) \
+       dbx500_add_sdi("sdi0", U8500_SDI0_BASE, IRQ_DB8500_SDMMC0, pdata, pid)
+#define db8500_add_sdi1(pdata, pid) \
+       dbx500_add_sdi("sdi1", U8500_SDI1_BASE, IRQ_DB8500_SDMMC1, pdata, pid)
+#define db8500_add_sdi2(pdata, pid) \
+       dbx500_add_sdi("sdi2", U8500_SDI2_BASE, IRQ_DB8500_SDMMC2, pdata, pid)
+#define db8500_add_sdi3(pdata, pid) \
+       dbx500_add_sdi("sdi3", U8500_SDI3_BASE, IRQ_DB8500_SDMMC3, pdata, pid)
+#define db8500_add_sdi4(pdata, pid) \
+       dbx500_add_sdi("sdi4", U8500_SDI4_BASE, IRQ_DB8500_SDMMC4, pdata, pid)
+#define db8500_add_sdi5(pdata, pid) \
+       dbx500_add_sdi("sdi5", U8500_SDI5_BASE, IRQ_DB8500_SDMMC5, pdata, pid)
 
 #define db8500_add_ssp0(pdata) \
        db8500_add_ssp("ssp0", U8500_SSP0_BASE, IRQ_DB8500_SSP0, pdata)
@@ -83,13 +83,13 @@ db8500_add_ssp(const char *name, resource_size_t base, int irq,
        db8500_add_ssp("ssp1", U8500_SSP1_BASE, IRQ_DB8500_SSP1, pdata)
 
 #define db8500_add_spi0(pdata) \
-       dbx500_add_spi("spi0", U8500_SPI0_BASE, IRQ_DB8500_SPI0, pdata)
+       dbx500_add_spi("spi0", U8500_SPI0_BASE, IRQ_DB8500_SPI0, pdata, 0)
 #define db8500_add_spi1(pdata) \
-       dbx500_add_spi("spi1", U8500_SPI1_BASE, IRQ_DB8500_SPI1, pdata)
+       dbx500_add_spi("spi1", U8500_SPI1_BASE, IRQ_DB8500_SPI1, pdata, 0)
 #define db8500_add_spi2(pdata) \
-       dbx500_add_spi("spi2", U8500_SPI2_BASE, IRQ_DB8500_SPI2, pdata)
+       dbx500_add_spi("spi2", U8500_SPI2_BASE, IRQ_DB8500_SPI2, pdata, 0)
 #define db8500_add_spi3(pdata) \
-       dbx500_add_spi("spi3", U8500_SPI3_BASE, IRQ_DB8500_SPI3, pdata)
+       dbx500_add_spi("spi3", U8500_SPI3_BASE, IRQ_DB8500_SPI3, pdata, 0)
 
 #define db8500_add_uart0(pdata) \
        dbx500_add_uart("uart0", U8500_UART0_BASE, IRQ_DB8500_UART0, pdata)
index bd88c1e74060740158c95ab0c427d40265717694..6ad983294103f83c7eea6e96a9df0f6e3741cc47 100644 (file)
@@ -17,6 +17,8 @@
 #define U5500_GIC_DIST_BASE    0xA0411000
 #define U5500_GIC_CPU_BASE     0xA0410100
 #define U5500_DMA_BASE         0x90030000
+#define U5500_STM_BASE         0x90020000
+#define U5500_STM_REG_BASE     (U5500_STM_BASE + 0xF000)
 #define U5500_MCDE_BASE                0xA0400000
 #define U5500_MODEM_BASE       0xB0000000
 #define U5500_L2CC_BASE                0xA0412000
@@ -29,7 +31,9 @@
 #define U5500_NAND0_BASE       0x60000000
 #define U5500_NAND1_BASE       0x70000000
 #define U5500_TWD_BASE         0xa0410600
+#define U5500_ICN_BASE         0xA0040000
 #define U5500_B2R2_BASE                0xa0200000
+#define U5500_BOOT_ROM_BASE    0x90000000
 
 #define U5500_FSMC_BASE                (U5500_PER1_BASE + 0x0000)
 #define U5500_SDI0_BASE                (U5500_PER1_BASE + 0x1000)
@@ -60,6 +64,7 @@
 #define U5500_MSP1_BASE                (U5500_PER4_BASE + 0x9000)
 #define U5500_GPIO2_BASE       (U5500_PER4_BASE + 0xA000)
 #define U5500_CDETECT_BASE     (U5500_PER4_BASE + 0xF000)
+#define U5500_PRCMU_TCDM_BASE  (U5500_PER4_BASE + 0x18000)
 
 #define U5500_SPI0_BASE                (U5500_PER5_BASE + 0x0000)
 #define U5500_SPI1_BASE                (U5500_PER5_BASE + 0x1000)
@@ -83,7 +88,7 @@
 #define U5500_HASH0_BASE       (U5500_PER6_BASE + 0x1000)
 #define U5500_HASH1_BASE       (U5500_PER6_BASE + 0x2000)
 #define U5500_PKA_BASE         (U5500_PER6_BASE + 0x4000)
-#define U5500_PKAM_BASE                (U5500_PER6_BASE + 0x5000)
+#define U5500_PKAM_BASE                (U5500_PER6_BASE + 0x5100)
 #define U5500_MTU0_BASE                (U5500_PER6_BASE + 0x6000)
 #define U5500_MTU1_BASE                (U5500_PER6_BASE + 0x7000)
 #define U5500_CR_BASE          (U5500_PER6_BASE + 0x8000)
 #define U5500_MBOX2_LOCAL_START        (U5500_MBOX_BASE + 0x20)
 #define U5500_MBOX2_LOCAL_END  (U5500_MBOX_BASE + 0x3F)
 
-#define U5500_ESRAM_BASE               0x40000000
+#define U5500_ACCCON_BASE_SEC  (0xBFFF0000)
+#define U5500_ACCCON_BASE              (0xBFFF1000)
+#define U5500_ACCCON_CPUVEC_RESET_ADDR_OFFSET (0x00000020)
+#define U5500_ACCCON_ACC_CPU_CTRL_OFFSET (0x000000BC)
+
+#define U5500_ESRAM_BASE               0x40000000
 #define U5500_ESRAM_DMA_LCPA_OFFSET    0x10000
 #define U5500_DMA_LCPA_BASE    (U5500_ESRAM_BASE + U5500_ESRAM_DMA_LCPA_OFFSET)
 
+#define U5500_MCDE_SIZE                0x1000
+#define U5500_DSI_LINK_SIZE    0x1000
+#define U5500_DSI_LINK_COUNT   0x2
+#define U5500_DSI_LINK1_BASE   (U5500_MCDE_BASE + U5500_MCDE_SIZE)
+#define U5500_DSI_LINK2_BASE   (U5500_DSI_LINK1_BASE + U5500_DSI_LINK_SIZE)
+
 #endif
index 16647b2553786d11b17654e336dd5df6cefa54cb..049997109cf951d1d960bb2ac38fd1779fd1539b 100644 (file)
 #define U8500_ESRAM_BANK2      (U8500_ESRAM_BANK1 + U8500_ESRAM_BANK_SIZE)
 #define U8500_ESRAM_BANK3      (U8500_ESRAM_BANK2 + U8500_ESRAM_BANK_SIZE)
 #define U8500_ESRAM_BANK4      (U8500_ESRAM_BANK3 + U8500_ESRAM_BANK_SIZE)
-/* Use bank 4 for DMA LCPA */
-#define U8500_DMA_LCPA_BASE    U8500_ESRAM_BANK4
+/*
+ * on V1 DMA uses 4KB for logical parameters position is right after the 64KB
+ * reserved for security
+ */
+#define U8500_ESRAM_DMA_LCPA_OFFSET     0x10000
+
+#define U8500_DMA_LCPA_BASE    (U8500_ESRAM_BANK0 + U8500_ESRAM_DMA_LCPA_OFFSET)
 #define U8500_DMA_LCPA_BASE_ED (U8500_ESRAM_BANK4 + 0x4000)
 
 #define U8500_PER3_BASE                0x80000000
 #define U8500_B2R2_BASE                0x80130000
 #define U8500_HSEM_BASE                0x80140000
 #define U8500_PER4_BASE                0x80150000
+#define U8500_TPIU_BASE                0x80190000
 #define U8500_ICN_BASE         0x81000000
 
 #define U8500_BOOT_ROM_BASE    0x90000000
+/* ASIC ID is at 0xbf4 offset within this region */
+#define U8500_ASIC_ID_BASE     0x9001D000
 
 #define U8500_PER6_BASE                0xa03c0000
 #define U8500_PER5_BASE                0xa03e0000
 
 /* per6 base addresses */
 #define U8500_RNG_BASE         (U8500_PER6_BASE + 0x0000)
-#define U8500_PKA_BASE         (U8500_PER6_BASE + 0x1000)
-#define U8500_PKAM_BASE                (U8500_PER6_BASE + 0x2000)
+#define U8500_HASH0_BASE        (U8500_PER6_BASE + 0x1000)
+#define U8500_HASH1_BASE        (U8500_PER6_BASE + 0x2000)
+#define U8500_PKA_BASE         (U8500_PER6_BASE + 0x4000)
+#define U8500_PKAM_BASE                (U8500_PER6_BASE + 0x5100)
 #define U8500_MTU0_BASE                (U8500_PER6_BASE + 0x6000) /* v1 */
 #define U8500_MTU1_BASE                (U8500_PER6_BASE + 0x7000) /* v1 */
 #define U8500_CR_BASE          (U8500_PER6_BASE + 0x8000) /* v1 */
-#define U8500_CRYPTO0_BASE     (U8500_PER6_BASE + 0xa000)
-#define U8500_CRYPTO1_BASE     (U8500_PER6_BASE + 0xb000)
+#define U8500_CRYP0_BASE       (U8500_PER6_BASE + 0xa000)
+#define U8500_CRYP1_BASE       (U8500_PER6_BASE + 0xb000)
 #define U8500_CLKRST6_BASE     (U8500_PER6_BASE + 0xf000)
 
 /* per5 base addresses */
 #define U8500_DMC_BASE         (U8500_PER4_BASE + 0x06000)
 #define U8500_PRCMU_BASE       (U8500_PER4_BASE + 0x07000)
 #define U8500_PRCMU_TCDM_BASE_V1 (U8500_PER4_BASE + 0x0f000)
-#define U8500_PRCMU_TCDM_BASE   (U8500_PER4_BASE + 0x68000)
+#define U8500_PRCMU_TCDM_BASE  (U8500_PER4_BASE + 0x68000)
+#define U8500_PRCMU_TCPM_BASE   (U8500_PER4_BASE + 0x60000)
 
 /* per3 base addresses */
 #define U8500_FSMC_BASE                (U8500_PER3_BASE + 0x0000)
 #define U8500_I2C1_BASE                (U8500_PER1_BASE + 0x2000)
 #define U8500_MSP0_BASE                (U8500_PER1_BASE + 0x3000)
 #define U8500_MSP1_BASE                (U8500_PER1_BASE + 0x4000)
+#define U8500_MSP3_BASE                (U8500_PER1_BASE + 0x5000)
 #define U8500_SDI0_BASE                (U8500_PER1_BASE + 0x6000)
 #define U8500_I2C2_BASE                (U8500_PER1_BASE + 0x8000)
 #define U8500_SPI3_BASE                (U8500_PER1_BASE + 0x9000)
 #define U8500_GPIOBANK7_BASE   (U8500_GPIO2_BASE + 0x80)
 #define U8500_GPIOBANK8_BASE   U8500_GPIO3_BASE
 
+#define U8500_MCDE_SIZE                0x1000
+#define U8500_DSI_LINK_SIZE    0x1000
+#define U8500_DSI_LINK1_BASE   (U8500_MCDE_BASE + U8500_MCDE_SIZE)
+#define U8500_DSI_LINK2_BASE   (U8500_DSI_LINK1_BASE + U8500_DSI_LINK_SIZE)
+#define U8500_DSI_LINK3_BASE   (U8500_DSI_LINK2_BASE + U8500_DSI_LINK_SIZE)
+#define U8500_DSI_LINK_COUNT   0x3
+
+/* Modem and APE physical addresses */
+#define U8500_MODEM_BASE       0xe000000
+#define U8500_APE_BASE         0x6000000
+
 #endif
index bf63f2631ba0519234ef6f1d0c94d0af92d2b548..470ac52663d61e7021586c29de997a78205fdba9 100644 (file)
 #include <mach/db8500-regs.h>
 #include <mach/db5500-regs.h>
 
-/* ST-Ericsson modified pl022 id */
-#define SSP_PER_ID             0x01080022
-
 #ifndef __ASSEMBLY__
 
 #include <mach/id.h>
+extern void __iomem *_PRCMU_BASE;
 
 #define ARRAY_AND_SIZE(x)      (x), ARRAY_SIZE(x)
 
index f1288d10b6ab7eb537040e950d65a16828747b4b..02b541a37ee5ebca1f28dac8a03e6d248f42a41b 100644 (file)
@@ -75,6 +75,26 @@ static inline bool __attribute_const__ cpu_is_u8500v2(void)
        return cpu_is_u8500() && ((dbx500_revision() & 0xf0) == 0xB0);
 }
 
+static inline bool cpu_is_u8500v20(void)
+{
+       return cpu_is_u8500() && (dbx500_revision() == 0xB0);
+}
+
+static inline bool cpu_is_u8500v21(void)
+{
+       return cpu_is_u8500() && (dbx500_revision() == 0xB1);
+}
+
+static inline bool cpu_is_u8500v20_or_later(void)
+{
+       return cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11();
+}
+
+static inline bool ux500_is_svp(void)
+{
+       return false;
+}
+
 #define ux500_unknown_soc()    BUG()
 
 #endif
index 97ef55f8493496486723c8fb4fa4ada65717e785..47969909836c9bb1441b7143dc5c4e156915267f 100644 (file)
 
 #define MOP500_IRQ_END         MOP500_NR_IRQS
 
+/*
+ * We may have several boards, but only one will run at a
+ * time, so the one with most IRQs will bump this ahead,
+ * but the IRQ_BOARD_START remains the same for either board.
+ */
 #if MOP500_IRQ_END > IRQ_BOARD_END
 #undef IRQ_BOARD_END
 #define IRQ_BOARD_END  MOP500_IRQ_END
diff --git a/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h b/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h
new file mode 100644 (file)
index 0000000..29d972c
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __MACH_IRQS_BOARD_U5500_H
+#define __MACH_IRQS_BOARD_U5500_H
+
+#define AB5500_NR_IRQS         5
+#define IRQ_AB5500_BASE                IRQ_BOARD_START
+#define IRQ_AB5500_END         (IRQ_AB5500_BASE + AB5500_NR_IRQS)
+
+#define U5500_IRQ_END          IRQ_AB5500_END
+
+#if IRQ_BOARD_END < U5500_IRQ_END
+#undef IRQ_BOARD_END
+#define IRQ_BOARD_END          U5500_IRQ_END
+#endif
+
+#endif
index bfa123dbec3b15d993d76f24509773c7e9777141..77239776a6f2358d9b8eb53b2d5e7c25331cef87 100644 (file)
 #define IRQ_DB5500_GPIO6               (IRQ_SHPI_START + 125)
 #define IRQ_DB5500_GPIO7               (IRQ_SHPI_START + 126)
 
+#ifdef CONFIG_UX500_SOC_DB5500
+
+/*
+ * After the GPIO ones we reserve a range of IRQ:s in which virtual
+ * IRQ:s representing modem IRQ:s can be allocated
+ */
+#define IRQ_MODEM_EVENTS_BASE  IRQ_SOC_START
+#define IRQ_MODEM_EVENTS_NBR   72
+#define IRQ_MODEM_EVENTS_END   (IRQ_MODEM_EVENTS_BASE + IRQ_MODEM_EVENTS_NBR)
+
+/* List of virtual IRQ:s that are allocated from the range above */
+#define MBOX_PAIR0_VIRT_IRQ    (IRQ_MODEM_EVENTS_BASE + 43)
+#define MBOX_PAIR1_VIRT_IRQ    (IRQ_MODEM_EVENTS_BASE + 45)
+#define MBOX_PAIR2_VIRT_IRQ    (IRQ_MODEM_EVENTS_BASE + 41)
+
+/*
+ * We may have several SoCs, but only one will run at a
+ * time, so the one with most IRQs will bump this ahead,
+ * but the IRQ_SOC_START remains the same for either SoC.
+ */
+#if IRQ_SOC_END < IRQ_MODEM_EVENTS_END
+#undef IRQ_SOC_END
+#define IRQ_SOC_END            IRQ_MODEM_EVENTS_END
+#endif
+
+#endif /* CONFIG_UX500_SOC_DB5500 */
+
 #endif
index 8b5d9f0a1633a4cb0edc501a915b9144a98734d9..68bc149746080863b67bbfdcdd81a43ab9206bd8 100644 (file)
 #define IRQ_DB8500_GPIO7               (IRQ_SHPI_START + 126)
 #define IRQ_DB8500_GPIO8               (IRQ_SHPI_START + 127)
 
+#define IRQ_CA_WAKE_REQ_ED                     (IRQ_SHPI_START + 71)
+#define IRQ_AC_READ_NOTIFICATION_0_ED          (IRQ_SHPI_START + 66)
+#define IRQ_AC_READ_NOTIFICATION_1_ED          (IRQ_SHPI_START + 64)
+#define IRQ_CA_MSG_PEND_NOTIFICATION_0_ED      (IRQ_SHPI_START + 67)
+#define IRQ_CA_MSG_PEND_NOTIFICATION_1_ED      (IRQ_SHPI_START + 65)
+
+#define IRQ_CA_WAKE_REQ_V1                     (IRQ_SHPI_START + 83)
+#define IRQ_AC_READ_NOTIFICATION_0_V1          (IRQ_SHPI_START + 78)
+#define IRQ_AC_READ_NOTIFICATION_1_V1          (IRQ_SHPI_START + 76)
+#define IRQ_CA_MSG_PEND_NOTIFICATION_0_V1      (IRQ_SHPI_START + 79)
+#define IRQ_CA_MSG_PEND_NOTIFICATION_1_V1      (IRQ_SHPI_START + 77)
+
+#ifdef CONFIG_UX500_SOC_DB8500
+
+/* Virtual interrupts corresponding to the PRCMU wakeups.  */
+#define IRQ_PRCMU_BASE IRQ_SOC_START
+#define NUM_PRCMU_WAKEUPS (IRQ_PRCMU_END - IRQ_PRCMU_BASE)
+
+#define IRQ_PRCMU_RTC (IRQ_PRCMU_BASE)
+#define IRQ_PRCMU_RTT0 (IRQ_PRCMU_BASE + 1)
+#define IRQ_PRCMU_RTT1 (IRQ_PRCMU_BASE + 2)
+#define IRQ_PRCMU_HSI0 (IRQ_PRCMU_BASE + 3)
+#define IRQ_PRCMU_HSI1 (IRQ_PRCMU_BASE + 4)
+#define IRQ_PRCMU_CA_WAKE (IRQ_PRCMU_BASE + 5)
+#define IRQ_PRCMU_USB (IRQ_PRCMU_BASE + 6)
+#define IRQ_PRCMU_ABB (IRQ_PRCMU_BASE + 7)
+#define IRQ_PRCMU_ABB_FIFO (IRQ_PRCMU_BASE + 8)
+#define IRQ_PRCMU_ARM (IRQ_PRCMU_BASE + 9)
+#define IRQ_PRCMU_MODEM_SW_RESET_REQ (IRQ_PRCMU_BASE + 10)
+#define IRQ_PRCMU_GPIO0 (IRQ_PRCMU_BASE + 11)
+#define IRQ_PRCMU_GPIO1 (IRQ_PRCMU_BASE + 12)
+#define IRQ_PRCMU_GPIO2 (IRQ_PRCMU_BASE + 13)
+#define IRQ_PRCMU_GPIO3 (IRQ_PRCMU_BASE + 14)
+#define IRQ_PRCMU_GPIO4 (IRQ_PRCMU_BASE + 15)
+#define IRQ_PRCMU_GPIO5 (IRQ_PRCMU_BASE + 16)
+#define IRQ_PRCMU_GPIO6 (IRQ_PRCMU_BASE + 17)
+#define IRQ_PRCMU_GPIO7 (IRQ_PRCMU_BASE + 18)
+#define IRQ_PRCMU_GPIO8 (IRQ_PRCMU_BASE + 19)
+#define IRQ_PRCMU_CA_SLEEP (IRQ_PRCMU_BASE + 20)
+#define IRQ_PRCMU_HOTMON_LOW (IRQ_PRCMU_BASE + 21)
+#define IRQ_PRCMU_HOTMON_HIGH (IRQ_PRCMU_BASE + 22)
+#define IRQ_PRCMU_END (IRQ_PRCMU_BASE + 23)
+
+/*
+ * We may have several SoCs, but only one will run at a
+ * time, so the one with most IRQs will bump this ahead,
+ * but the IRQ_SOC_START remains the same for either SoC.
+ */
+#if IRQ_SOC_END < IRQ_PRCMU_END
+#undef IRQ_SOC_END
+#define IRQ_SOC_END IRQ_PRCMU_END
+#endif
+
+#endif /* CONFIG_UX500_SOC_DB8500 */
 #endif
index ba1294c13c4dc56939ff7d02ce108980c12d41fd..9db68d264c5f727c1fffc15f5a563d4b2a9d9a65 100644 (file)
 #ifndef ASM_ARCH_IRQS_H
 #define ASM_ARCH_IRQS_H
 
-#include <mach/irqs-db5500.h>
-#include <mach/irqs-db8500.h>
+#include <mach/hardware.h>
 
-#define IRQ_LOCALTIMER                  29
-#define IRQ_LOCALWDOG                   30
+#define IRQ_LOCALTIMER                 29
+#define IRQ_LOCALWDOG                  30
 
 /* Shared Peripheral Interrupt (SHPI) */
 #define IRQ_SHPI_START                 32
 
-/* Interrupt numbers generic for shared peripheral */
+/*
+ * MTU0 preserved for now until plat-nomadik is taught not to use it.  Don't
+ * add any other IRQs here, use the irqs-dbx500.h files.
+ */
 #define IRQ_MTU0               (IRQ_SHPI_START + 4)
 
-/* There are 128 shared peripheral interrupts assigned to
- * INTID[160:32]. The first 32 interrupts are reserved.
- */
-#define DBX500_NR_INTERNAL_IRQS                161
+#define DBX500_NR_INTERNAL_IRQS                160
 
 /* After chip-specific IRQ numbers we have the GPIO ones */
 #define NOMADIK_NR_GPIO                        288
 #define NOMADIK_GPIO_TO_IRQ(gpio)      ((gpio) + DBX500_NR_INTERNAL_IRQS)
 #define NOMADIK_IRQ_TO_GPIO(irq)       ((irq) - DBX500_NR_INTERNAL_IRQS)
-#define IRQ_BOARD_START                        NOMADIK_GPIO_TO_IRQ(NOMADIK_NR_GPIO)
+#define IRQ_GPIO_END                   NOMADIK_GPIO_TO_IRQ(NOMADIK_NR_GPIO)
+
+#define IRQ_SOC_START          IRQ_GPIO_END
+/* This will be overridden by SoC-specific irq headers */
+#define IRQ_SOC_END            IRQ_SOC_START
 
+#include <mach/irqs-db5500.h>
+#include <mach/irqs-db8500.h>
+
+#define IRQ_BOARD_START                IRQ_SOC_END
 /* This will be overridden by board-specific irq headers */
-#define IRQ_BOARD_END                  IRQ_BOARD_START
+#define IRQ_BOARD_END          IRQ_BOARD_START
 
 #ifdef CONFIG_MACH_U8500
 #include <mach/irqs-board-mop500.h>
 #endif
 
-/*
- * After the board specific IRQ:s we reserve a range of IRQ:s in which virtual
- * IRQ:s representing modem IRQ:s can be allocated
- */
-#define IRQ_MODEM_EVENTS_BASE (IRQ_BOARD_END + 1)
-#define IRQ_MODEM_EVENTS_NBR 72
-#define IRQ_MODEM_EVENTS_END (IRQ_MODEM_EVENTS_BASE + IRQ_MODEM_EVENTS_NBR)
-
-/* List of virtual IRQ:s that are allocated from the range above */
-#define MBOX_PAIR0_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 43)
-#define MBOX_PAIR1_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 45)
-#define MBOX_PAIR2_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 41)
+#ifdef CONFIG_MACH_U5500
+#include <mach/irqs-board-u5500.h>
+#endif
 
-#define NR_IRQS                                IRQ_MODEM_EVENTS_END
+#define NR_IRQS                        IRQ_BOARD_END
 
 #endif /* ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-ux500/include/mach/prcmu-defs.h b/arch/arm/mach-ux500/include/mach/prcmu-defs.h
deleted file mode 100644 (file)
index 848ba64..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics 2009
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Sundar Iyer <sundar.iyer@stericsson.com>
- * Author: Martin Persson <martin.persson@stericsson.com>
- *
- * License Terms: GNU General Public License v2
- *
- * PRCM Unit definitions
- */
-
-#ifndef __MACH_PRCMU_DEFS_H
-#define __MACH_PRCMU_DEFS_H
-
-enum prcmu_cpu_opp {
-       CPU_OPP_INIT      = 0x00,
-       CPU_OPP_NO_CHANGE = 0x01,
-       CPU_OPP_100       = 0x02,
-       CPU_OPP_50        = 0x03,
-       CPU_OPP_MAX       = 0x04,
-       CPU_OPP_EXT_CLK   = 0x07
-};
-enum prcmu_ape_opp {
-       APE_OPP_NO_CHANGE = 0x00,
-       APE_OPP_100       = 0x02,
-       APE_OPP_50        = 0x03,
-};
-
-#endif /* __MACH_PRCMU_DEFS_H */
diff --git a/arch/arm/mach-ux500/include/mach/prcmu.h b/arch/arm/mach-ux500/include/mach/prcmu.h
deleted file mode 100644 (file)
index c49e456..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics 2009
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
- * Author: Sundar Iyer <sundar.iyer@stericsson.com>
- * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
- *
- * License Terms: GNU General Public License v2
- *
- * PRCM Unit f/w API
- */
-#ifndef __MACH_PRCMU_H
-#define __MACH_PRCMU_H
-#include <mach/prcmu-defs.h>
-
-void __init prcmu_early_init(void);
-int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
-int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
-int prcmu_set_ape_opp(enum prcmu_ape_opp opp);
-int prcmu_set_cpu_opp(enum prcmu_cpu_opp opp);
-int prcmu_set_ape_cpu_opps(enum prcmu_ape_opp ape_opp,
-                          enum prcmu_cpu_opp cpu_opp);
-int prcmu_get_ape_opp(void);
-int prcmu_get_cpu_opp(void);
-bool prcmu_has_arm_maxopp(void);
-
-#endif /* __MACH_PRCMU_H */
diff --git a/arch/arm/mach-ux500/prcmu.c b/arch/arm/mach-ux500/prcmu.c
deleted file mode 100644 (file)
index c522d26..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics 2009
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
- * Author: Sundar Iyer <sundar.iyer@stericsson.com>
- * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
- *
- * U8500 PRCM Unit interface driver
- *
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/mutex.h>
-#include <linux/completion.h>
-#include <linux/jiffies.h>
-#include <linux/bitops.h>
-#include <linux/interrupt.h>
-
-#include <mach/hardware.h>
-#include <mach/prcmu-regs.h>
-#include <mach/prcmu-defs.h>
-
-/* Global var to runtime determine TCDM base for v2 or v1 */
-static __iomem void *tcdm_base;
-
-#define _MBOX_HEADER           (tcdm_base + 0xFE8)
-#define MBOX_HEADER_REQ_MB0    (_MBOX_HEADER + 0x0)
-
-#define REQ_MB1 (tcdm_base + 0xFD0)
-#define REQ_MB5 (tcdm_base + 0xE44)
-
-#define REQ_MB1_ARMOPP         (REQ_MB1 + 0x0)
-#define REQ_MB1_APEOPP         (REQ_MB1 + 0x1)
-#define REQ_MB1_BOOSTOPP       (REQ_MB1 + 0x2)
-
-#define ACK_MB1 (tcdm_base + 0xE04)
-#define ACK_MB5 (tcdm_base + 0xDF4)
-
-#define ACK_MB1_CURR_ARMOPP            (ACK_MB1 + 0x0)
-#define ACK_MB1_CURR_APEOPP            (ACK_MB1 + 0x1)
-
-#define REQ_MB5_I2C_SLAVE_OP (REQ_MB5)
-#define REQ_MB5_I2C_HW_BITS (REQ_MB5 + 1)
-#define REQ_MB5_I2C_REG (REQ_MB5 + 2)
-#define REQ_MB5_I2C_VAL (REQ_MB5 + 3)
-
-#define ACK_MB5_I2C_STATUS (ACK_MB5 + 1)
-#define ACK_MB5_I2C_VAL (ACK_MB5 + 3)
-
-#define PRCM_AVS_VARM_MAX_OPP          (tcdm_base + 0x2E4)
-#define PRCM_AVS_ISMODEENABLE          7
-#define PRCM_AVS_ISMODEENABLE_MASK     (1 << PRCM_AVS_ISMODEENABLE)
-
-#define I2C_WRITE(slave) \
-       (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0))
-#define I2C_READ(slave) \
-       (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0) | BIT(0))
-#define I2C_STOP_EN BIT(3)
-
-enum mb1_h {
-       MB1H_ARM_OPP = 1,
-       MB1H_APE_OPP,
-       MB1H_ARM_APE_OPP,
-};
-
-static struct {
-       struct mutex lock;
-       struct completion work;
-       struct {
-               u8 arm_opp;
-               u8 ape_opp;
-               u8 arm_status;
-               u8 ape_status;
-       } ack;
-} mb1_transfer;
-
-enum ack_mb5_status {
-       I2C_WR_OK = 0x01,
-       I2C_RD_OK = 0x02,
-};
-
-#define MBOX_BIT BIT
-#define NUM_MBOX 8
-
-static struct {
-       struct mutex lock;
-       struct completion work;
-       bool failed;
-       struct {
-               u8 status;
-               u8 value;
-       } ack;
-} mb5_transfer;
-
-/**
- * prcmu_abb_read() - Read register value(s) from the ABB.
- * @slave:     The I2C slave address.
- * @reg:       The (start) register address.
- * @value:     The read out value(s).
- * @size:      The number of registers to read.
- *
- * Reads register value(s) from the ABB.
- * @size has to be 1 for the current firmware version.
- */
-int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
-{
-       int r;
-
-       if (size != 1)
-               return -EINVAL;
-
-       r = mutex_lock_interruptible(&mb5_transfer.lock);
-       if (r)
-               return r;
-
-       while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
-               cpu_relax();
-
-       writeb(I2C_READ(slave), REQ_MB5_I2C_SLAVE_OP);
-       writeb(I2C_STOP_EN, REQ_MB5_I2C_HW_BITS);
-       writeb(reg, REQ_MB5_I2C_REG);
-
-       writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
-       if (!wait_for_completion_timeout(&mb5_transfer.work,
-                       msecs_to_jiffies(500))) {
-               pr_err("prcmu: prcmu_abb_read timed out.\n");
-               r = -EIO;
-               goto unlock_and_return;
-       }
-       r = ((mb5_transfer.ack.status == I2C_RD_OK) ? 0 : -EIO);
-       if (!r)
-               *value = mb5_transfer.ack.value;
-
-unlock_and_return:
-       mutex_unlock(&mb5_transfer.lock);
-       return r;
-}
-EXPORT_SYMBOL(prcmu_abb_read);
-
-/**
- * prcmu_abb_write() - Write register value(s) to the ABB.
- * @slave:     The I2C slave address.
- * @reg:       The (start) register address.
- * @value:     The value(s) to write.
- * @size:      The number of registers to write.
- *
- * Reads register value(s) from the ABB.
- * @size has to be 1 for the current firmware version.
- */
-int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
-{
-       int r;
-
-       if (size != 1)
-               return -EINVAL;
-
-       r = mutex_lock_interruptible(&mb5_transfer.lock);
-       if (r)
-               return r;
-
-
-       while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
-               cpu_relax();
-
-       writeb(I2C_WRITE(slave), REQ_MB5_I2C_SLAVE_OP);
-       writeb(I2C_STOP_EN, REQ_MB5_I2C_HW_BITS);
-       writeb(reg, REQ_MB5_I2C_REG);
-       writeb(*value, REQ_MB5_I2C_VAL);
-
-       writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
-       if (!wait_for_completion_timeout(&mb5_transfer.work,
-                       msecs_to_jiffies(500))) {
-               pr_err("prcmu: prcmu_abb_write timed out.\n");
-               r = -EIO;
-               goto unlock_and_return;
-       }
-       r = ((mb5_transfer.ack.status == I2C_WR_OK) ? 0 : -EIO);
-
-unlock_and_return:
-       mutex_unlock(&mb5_transfer.lock);
-       return r;
-}
-EXPORT_SYMBOL(prcmu_abb_write);
-
-static int set_ape_cpu_opps(u8 header, enum prcmu_ape_opp ape_opp,
-                           enum prcmu_cpu_opp cpu_opp)
-{
-       bool do_ape;
-       bool do_arm;
-       int err = 0;
-
-       do_ape = ((header == MB1H_APE_OPP) || (header == MB1H_ARM_APE_OPP));
-       do_arm = ((header == MB1H_ARM_OPP) || (header == MB1H_ARM_APE_OPP));
-
-       mutex_lock(&mb1_transfer.lock);
-
-       while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
-               cpu_relax();
-
-       writeb(0, MBOX_HEADER_REQ_MB0);
-       writeb(cpu_opp, REQ_MB1_ARMOPP);
-       writeb(ape_opp, REQ_MB1_APEOPP);
-       writeb(0, REQ_MB1_BOOSTOPP);
-       writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
-       wait_for_completion(&mb1_transfer.work);
-       if ((do_ape) && (mb1_transfer.ack.ape_status != 0))
-               err = -EIO;
-       if ((do_arm) && (mb1_transfer.ack.arm_status != 0))
-               err = -EIO;
-
-       mutex_unlock(&mb1_transfer.lock);
-
-       return err;
-}
-
-/**
- * prcmu_set_ape_opp() - Set the OPP of the APE.
- * @opp:       The OPP to set.
- *
- * This function sets the OPP of the APE.
- */
-int prcmu_set_ape_opp(enum prcmu_ape_opp opp)
-{
-       return set_ape_cpu_opps(MB1H_APE_OPP, opp, APE_OPP_NO_CHANGE);
-}
-EXPORT_SYMBOL(prcmu_set_ape_opp);
-
-/**
- * prcmu_set_cpu_opp() - Set the OPP of the CPU.
- * @opp:       The OPP to set.
- *
- * This function sets the OPP of the CPU.
- */
-int prcmu_set_cpu_opp(enum prcmu_cpu_opp opp)
-{
-       return set_ape_cpu_opps(MB1H_ARM_OPP, CPU_OPP_NO_CHANGE, opp);
-}
-EXPORT_SYMBOL(prcmu_set_cpu_opp);
-
-/**
- * prcmu_set_ape_cpu_opps() - Set the OPPs of the APE and the CPU.
- * @ape_opp:   The APE OPP to set.
- * @cpu_opp:   The CPU OPP to set.
- *
- * This function sets the OPPs of the APE and the CPU.
- */
-int prcmu_set_ape_cpu_opps(enum prcmu_ape_opp ape_opp,
-                          enum prcmu_cpu_opp cpu_opp)
-{
-       return set_ape_cpu_opps(MB1H_ARM_APE_OPP, ape_opp, cpu_opp);
-}
-EXPORT_SYMBOL(prcmu_set_ape_cpu_opps);
-
-/**
- * prcmu_get_ape_opp() - Get the OPP of the APE.
- *
- * This function gets the OPP of the APE.
- */
-enum prcmu_ape_opp prcmu_get_ape_opp(void)
-{
-       return readb(ACK_MB1_CURR_APEOPP);
-}
-EXPORT_SYMBOL(prcmu_get_ape_opp);
-
-/**
- * prcmu_get_cpu_opp() - Get the OPP of the CPU.
- *
- * This function gets the OPP of the CPU. The OPP is specified in %%.
- * PRCMU_OPP_EXT is a special OPP value, not specified in %%.
- */
-int prcmu_get_cpu_opp(void)
-{
-       return readb(ACK_MB1_CURR_ARMOPP);
-}
-EXPORT_SYMBOL(prcmu_get_cpu_opp);
-
-bool prcmu_has_arm_maxopp(void)
-{
-       return (readb(PRCM_AVS_VARM_MAX_OPP) & PRCM_AVS_ISMODEENABLE_MASK)
-               == PRCM_AVS_ISMODEENABLE_MASK;
-}
-
-static void read_mailbox_0(void)
-{
-       writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_1(void)
-{
-       mb1_transfer.ack.arm_opp = readb(ACK_MB1_CURR_ARMOPP);
-       mb1_transfer.ack.ape_opp = readb(ACK_MB1_CURR_APEOPP);
-       complete(&mb1_transfer.work);
-       writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_2(void)
-{
-       writel(MBOX_BIT(2), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_3(void)
-{
-       writel(MBOX_BIT(3), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_4(void)
-{
-       writel(MBOX_BIT(4), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_5(void)
-{
-       mb5_transfer.ack.status = readb(ACK_MB5_I2C_STATUS);
-       mb5_transfer.ack.value = readb(ACK_MB5_I2C_VAL);
-       complete(&mb5_transfer.work);
-       writel(MBOX_BIT(5), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_6(void)
-{
-       writel(MBOX_BIT(6), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_7(void)
-{
-       writel(MBOX_BIT(7), PRCM_ARM_IT1_CLEAR);
-}
-
-static void (* const read_mailbox[NUM_MBOX])(void) = {
-       read_mailbox_0,
-       read_mailbox_1,
-       read_mailbox_2,
-       read_mailbox_3,
-       read_mailbox_4,
-       read_mailbox_5,
-       read_mailbox_6,
-       read_mailbox_7
-};
-
-static irqreturn_t prcmu_irq_handler(int irq, void *data)
-{
-       u32 bits;
-       u8 n;
-
-       bits = (readl(PRCM_ARM_IT1_VAL) & (MBOX_BIT(NUM_MBOX) - 1));
-       if (unlikely(!bits))
-               return IRQ_NONE;
-
-       for (n = 0; bits; n++) {
-               if (bits & MBOX_BIT(n)) {
-                       bits -= MBOX_BIT(n);
-                       read_mailbox[n]();
-               }
-       }
-       return IRQ_HANDLED;
-}
-
-void __init prcmu_early_init(void)
-{
-       if (cpu_is_u8500v11() || cpu_is_u8500ed()) {
-               tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE_V1);
-       } else if (cpu_is_u8500v2()) {
-               tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE);
-       } else {
-               pr_err("prcmu: Unsupported chip version\n");
-               BUG();
-       }
-}
-
-static int __init prcmu_init(void)
-{
-       if (cpu_is_u8500ed()) {
-               pr_err("prcmu: Unsupported chip version\n");
-               return 0;
-       }
-
-       mutex_init(&mb1_transfer.lock);
-       init_completion(&mb1_transfer.work);
-       mutex_init(&mb5_transfer.lock);
-       init_completion(&mb5_transfer.work);
-
-       /* Clean up the mailbox interrupts after pre-kernel code. */
-       writel((MBOX_BIT(NUM_MBOX) - 1), PRCM_ARM_IT1_CLEAR);
-
-       return request_irq(IRQ_DB8500_PRCMU1, prcmu_irq_handler, 0,
-                          "prcmu", NULL);
-}
-
-arch_initcall(prcmu_init);
index 285edcd2da2aa9a9d6186a6c17cf053918b0b66e..9e6b93b1a04342e7883aa241ddecb02856818a0e 100644 (file)
@@ -46,12 +46,6 @@ static struct map_desc v2m_io_desc[] __initdata = {
        },
 };
 
-static void __init v2m_init_early(void)
-{
-       ct_desc->init_early();
-       versatile_sched_clock_init(MMIO_P2V(V2M_SYS_24MHZ), 24000000);
-}
-
 static void __init v2m_timer_init(void)
 {
        u32 scctrl;
@@ -365,6 +359,13 @@ static struct clk_lookup v2m_lookups[] = {
        },
 };
 
+static void __init v2m_init_early(void)
+{
+       ct_desc->init_early();
+       clkdev_add_table(v2m_lookups, ARRAY_SIZE(v2m_lookups));
+       versatile_sched_clock_init(MMIO_P2V(V2M_SYS_24MHZ), 24000000);
+}
+
 static void v2m_power_off(void)
 {
        if (v2m_cfg_write(SYS_CFG_SHUTDOWN | SYS_CFG_SITE_MB, 0))
@@ -418,8 +419,6 @@ static void __init v2m_init(void)
 {
        int i;
 
-       clkdev_add_table(v2m_lookups, ARRAY_SIZE(v2m_lookups));
-
        platform_device_register(&v2m_pcie_i2c_device);
        platform_device_register(&v2m_ddc_i2c_device);
        platform_device_register(&v2m_flash_device);
index c96fa1b3f49f5d78b670289a1d8fc8ccf3b38b30..73b4a8b66a575cabbbac35cf3611b2991777e640 100644 (file)
@@ -176,6 +176,7 @@ ENDPROC(v6_coherent_kern_range)
  */
 ENTRY(v6_flush_kern_dcache_area)
        add     r1, r0, r1
+       bic     r0, r0, #D_CACHE_LINE_SIZE - 1
 1:
 #ifdef HARVARD_CACHE
        mcr     p15, 0, r0, c7, c14, 1          @ clean & invalidate D line
index dc18d81ef8ce5d94e8f7e9c62515bf8624cd79c8..d32f02b618663d985b90b61d9a91996997c85433 100644 (file)
@@ -221,6 +221,8 @@ ENDPROC(v7_coherent_user_range)
 ENTRY(v7_flush_kern_dcache_area)
        dcache_line_size r2, r3
        add     r1, r0, r1
+       sub     r3, r2, #1
+       bic     r0, r0, r3
 1:
        mcr     p15, 0, r0, c7, c14, 1          @ clean & invalidate D line / unified line
        add     r0, r0, r2
index 76f82ae44efb177ae925cc998b9c3ce2c8470bb3..c19571c40a21ca62902d65cd01dcb8db9ea4f178 100644 (file)
 #include <linux/mman.h>
 #include <linux/nodemask.h>
 #include <linux/initrd.h>
+#include <linux/of_fdt.h>
 #include <linux/highmem.h>
 #include <linux/gfp.h>
 #include <linux/memblock.h>
 #include <linux/sort.h>
 
 #include <asm/mach-types.h>
+#include <asm/prom.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
 #include <asm/sizes.h>
@@ -71,6 +73,14 @@ static int __init parse_tag_initrd2(const struct tag *tag)
 
 __tagtable(ATAG_INITRD2, parse_tag_initrd2);
 
+#ifdef CONFIG_OF_FLATTREE
+void __init early_init_dt_setup_initrd_arch(unsigned long start, unsigned long end)
+{
+       phys_initrd_start = start;
+       phys_initrd_size = end - start;
+}
+#endif /* CONFIG_OF_FLATTREE */
+
 /*
  * This keeps memory configuration data used by a couple memory
  * initialization functions, as well as show_mem() for the skipping
@@ -85,7 +95,7 @@ void show_mem(unsigned int filter)
        struct meminfo * mi = &meminfo;
 
        printk("Mem-info:\n");
-       show_free_areas();
+       show_free_areas(filter);
 
        for_each_bank (i, mi) {
                struct membank *bank = &mi->bank[i];
@@ -273,13 +283,15 @@ static void __init arm_bootmem_free(unsigned long min, unsigned long max_low,
        free_area_init_node(0, zone_size, min, zhole_size);
 }
 
-#ifndef CONFIG_SPARSEMEM
+#ifdef CONFIG_HAVE_ARCH_PFN_VALID
 int pfn_valid(unsigned long pfn)
 {
        return memblock_is_memory(pfn << PAGE_SHIFT);
 }
 EXPORT_SYMBOL(pfn_valid);
+#endif
 
+#ifndef CONFIG_SPARSEMEM
 static void arm_memory_present(void)
 {
 }
@@ -318,6 +330,12 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
        memblock_reserve(__pa(_stext), _end - _stext);
 #endif
 #ifdef CONFIG_BLK_DEV_INITRD
+       if (phys_initrd_size &&
+           !memblock_is_region_memory(phys_initrd_start, phys_initrd_size)) {
+               pr_err("INITRD: 0x%08lx+0x%08lx is not a memory region - disabling initrd\n",
+                      phys_initrd_start, phys_initrd_size);
+               phys_initrd_start = phys_initrd_size = 0;
+       }
        if (phys_initrd_size &&
            memblock_is_region_reserved(phys_initrd_start, phys_initrd_size)) {
                pr_err("INITRD: 0x%08lx+0x%08lx overlaps in-use memory region - disabling initrd\n",
@@ -334,6 +352,7 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
 #endif
 
        arm_mm_memblock_reserve();
+       arm_dt_memblock_reserve();
 
        /* reserve any platform specific memblock areas */
        if (mdesc->reserve)
@@ -622,7 +641,8 @@ void __init mem_init(void)
                        "    modules : 0x%08lx - 0x%08lx   (%4ld MB)\n"
                        "      .init : 0x%p" " - 0x%p" "   (%4d kB)\n"
                        "      .text : 0x%p" " - 0x%p" "   (%4d kB)\n"
-                       "      .data : 0x%p" " - 0x%p" "   (%4d kB)\n",
+                       "      .data : 0x%p" " - 0x%p" "   (%4d kB)\n"
+                       "       .bss : 0x%p" " - 0x%p" "   (%4d kB)\n",
 
                        MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
                                (PAGE_SIZE)),
@@ -644,7 +664,8 @@ void __init mem_init(void)
 
                        MLK_ROUNDUP(__init_begin, __init_end),
                        MLK_ROUNDUP(_text, _etext),
-                       MLK_ROUNDUP(_sdata, _edata));
+                       MLK_ROUNDUP(_sdata, _edata),
+                       MLK_ROUNDUP(__bss_start, __bss_stop));
 
 #undef MLK
 #undef MLM
index d2384106af9cbb32f96a61d54570ef39d391c5b7..5b3d7d543659154b36d3a568be429ebc096819e0 100644 (file)
@@ -5,14 +5,9 @@ extern pmd_t *top_pmd;
 
 #define TOP_PTE(x)     pte_offset_kernel(top_pmd, x)
 
-static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt)
-{
-       return pmd_offset(pud_offset(pgd, virt), virt);
-}
-
 static inline pmd_t *pmd_off_k(unsigned long virt)
 {
-       return pmd_off(pgd_offset_k(virt), virt);
+       return pmd_offset(pud_offset(pgd_offset_k(virt), virt), virt);
 }
 
 struct mem_type {
index 6cf76b3b68d1f374fcbc6be0c38224161f7db477..9d9e736c2b4f4afe2a90190d8b583c8e1f0c656a 100644 (file)
@@ -31,8 +31,6 @@
 
 #include "mm.h"
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 /*
  * empty_zero_page is a special page that is used for
  * zero-initialized data and COW.
@@ -765,15 +763,12 @@ static void __init sanity_check_meminfo(void)
 {
        int i, j, highmem = 0;
 
-       lowmem_limit = __pa(vmalloc_min - 1) + 1;
-       memblock_set_current_limit(lowmem_limit);
-
        for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
                struct membank *bank = &meminfo.bank[j];
                *bank = meminfo.bank[i];
 
 #ifdef CONFIG_HIGHMEM
-               if (__va(bank->start) > vmalloc_min ||
+               if (__va(bank->start) >= vmalloc_min ||
                    __va(bank->start) < (void *)PAGE_OFFSET)
                        highmem = 1;
 
@@ -831,6 +826,9 @@ static void __init sanity_check_meminfo(void)
                        bank->size = newsize;
                }
 #endif
+               if (!bank->highmem && bank->start + bank->size > lowmem_limit)
+                       lowmem_limit = bank->start + bank->size;
+
                j++;
        }
 #ifdef CONFIG_HIGHMEM
@@ -854,6 +852,7 @@ static void __init sanity_check_meminfo(void)
        }
 #endif
        meminfo.nr_banks = j;
+       memblock_set_current_limit(lowmem_limit);
 }
 
 static inline void prepare_page_table(void)
index e4c165ca669680eb6d74ce8e3d5822de50bbe44f..537ffcb0646d5e0c77ef8a336f4b39b07937beab 100644 (file)
@@ -146,7 +146,7 @@ __arm7tdmi_proc_info:
                .long   0
                .long   0
                .long   v4_cache_fns
-               .size   __arm7tdmi_proc_info, . - __arm7dmi_proc_info
+               .size   __arm7tdmi_proc_info, . - __arm7tdmi_proc_info
 
                .type   __triscenda7_proc_info, #object
 __triscenda7_proc_info:
index 7b7ebd4d096d9cb3939bed7a059be8514486d463..546b54da10059752195476dc6bd9fc0b1b243775 100644 (file)
@@ -116,7 +116,7 @@ __arm9tdmi_proc_info:
                .long   0
                .long   0
                .long   v4_cache_fns
-               .size   __arm9tdmi_proc_info, . - __arm9dmi_proc_info
+               .size   __arm9tdmi_proc_info, . - __arm9tdmi_proc_info
 
                .type   __p2001_proc_info, #object
 __p2001_proc_info:
index ab17cc0d3fa7cd5f2d0a97b7c5539789b2f20c09..1d2b8451bf25c24f9e66ac10f83faf54ebcdc401 100644 (file)
@@ -213,7 +213,9 @@ __v6_setup:
        mcr     p15, 0, r0, c2, c0, 2           @ TTB control register
        ALT_SMP(orr     r4, r4, #TTB_FLAGS_SMP)
        ALT_UP(orr      r4, r4, #TTB_FLAGS_UP)
-       mcr     p15, 0, r4, c2, c0, 1           @ load TTB1
+       ALT_SMP(orr     r8, r8, #TTB_FLAGS_SMP)
+       ALT_UP(orr      r8, r8, #TTB_FLAGS_UP)
+       mcr     p15, 0, r8, c2, c0, 1           @ load TTB1
 #endif /* CONFIG_MMU */
        adr     r5, v6_crval
        ldmia   r5, {r5, r6}
index babfba09c89ff390deb7ddfd0496e813f442e047..089c0b5e454fccbdbc63a4d4e9d72d15baa7075a 100644 (file)
@@ -210,19 +210,21 @@ cpu_v7_name:
 
 /* Suspend/resume support: derived from arch/arm/mach-s5pv210/sleep.S */
 .globl cpu_v7_suspend_size
-.equ   cpu_v7_suspend_size, 4 * 8
+.equ   cpu_v7_suspend_size, 4 * 9
 #ifdef CONFIG_PM_SLEEP
 ENTRY(cpu_v7_do_suspend)
        stmfd   sp!, {r4 - r11, lr}
        mrc     p15, 0, r4, c13, c0, 0  @ FCSE/PID
        mrc     p15, 0, r5, c13, c0, 1  @ Context ID
+       mrc     p15, 0, r6, c13, c0, 3  @ User r/o thread ID
+       stmia   r0!, {r4 - r6}
        mrc     p15, 0, r6, c3, c0, 0   @ Domain ID
        mrc     p15, 0, r7, c2, c0, 0   @ TTB 0
        mrc     p15, 0, r8, c2, c0, 1   @ TTB 1
        mrc     p15, 0, r9, c1, c0, 0   @ Control register
        mrc     p15, 0, r10, c1, c0, 1  @ Auxiliary control register
        mrc     p15, 0, r11, c1, c0, 2  @ Co-processor access control
-       stmia   r0, {r4 - r11}
+       stmia   r0, {r6 - r11}
        ldmfd   sp!, {r4 - r11, pc}
 ENDPROC(cpu_v7_do_suspend)
 
@@ -230,9 +232,11 @@ ENTRY(cpu_v7_do_resume)
        mov     ip, #0
        mcr     p15, 0, ip, c8, c7, 0   @ invalidate TLBs
        mcr     p15, 0, ip, c7, c5, 0   @ invalidate I cache
-       ldmia   r0, {r4 - r11}
+       ldmia   r0!, {r4 - r6}
        mcr     p15, 0, r4, c13, c0, 0  @ FCSE/PID
        mcr     p15, 0, r5, c13, c0, 1  @ Context ID
+       mcr     p15, 0, r6, c13, c0, 3  @ User r/o thread ID
+       ldmia   r0, {r6 - r11}
        mcr     p15, 0, r6, c3, c0, 0   @ Domain ID
        mcr     p15, 0, r7, c2, c0, 0   @ TTB 0
        mcr     p15, 0, r8, c2, c0, 1   @ TTB 1
@@ -368,7 +372,9 @@ __v7_setup:
        mcr     p15, 0, r10, c2, c0, 2          @ TTB control register
        ALT_SMP(orr     r4, r4, #TTB_FLAGS_SMP)
        ALT_UP(orr      r4, r4, #TTB_FLAGS_UP)
-       mcr     p15, 0, r4, c2, c0, 1           @ load TTB1
+       ALT_SMP(orr     r8, r8, #TTB_FLAGS_SMP)
+       ALT_UP(orr      r8, r8, #TTB_FLAGS_UP)
+       mcr     p15, 0, r8, c2, c0, 1           @ load TTB1
        ldr     r5, =PRRR                       @ PRRR
        ldr     r6, =NMRR                       @ NMRR
        mcr     p15, 0, r5, c10, c2, 0          @ write PRRR
@@ -416,9 +422,9 @@ ENTRY(v7_processor_functions)
        .word   cpu_v7_dcache_clean_area
        .word   cpu_v7_switch_mm
        .word   cpu_v7_set_pte_ext
-       .word   0
-       .word   0
-       .word   0
+       .word   cpu_v7_suspend_size
+       .word   cpu_v7_do_suspend
+       .word   cpu_v7_do_resume
        .size   v7_processor_functions, . - v7_processor_functions
 
        .section ".rodata"
index 9612a87e2a881df2f49126e02ed0b6ed60982977..bab73e2c79db9653701e32a1babc63f770fff3d7 100644 (file)
@@ -18,6 +18,7 @@
  */
 #include <linux/init.h>
 #include <asm/traps.h>
+#include <asm/ptrace.h>
 
 static int cp6_trap(struct pt_regs *regs, unsigned int instr)
 {
index 3538b85ede910a4bc32c8e85b604789809cef21d..b130f60ca6b73e9b7b8435dcc52633bb1761078c 100644 (file)
@@ -139,7 +139,7 @@ static struct sdma_script_start_addrs addr_imx35_to2 = {
 #endif
 
 #ifdef CONFIG_SOC_IMX51
-static struct sdma_script_start_addrs addr_imx51_to1 = {
+static struct sdma_script_start_addrs addr_imx51 = {
        .ap_2_ap_addr = 642,
        .uart_2_mcu_addr = 817,
        .mcu_2_app_addr = 747,
@@ -196,7 +196,9 @@ static int __init imxXX_add_imx_dma(void)
 
 #if defined(CONFIG_SOC_IMX51)
        if (cpu_is_mx51()) {
-               imx51_imx_sdma_data.pdata.script_addrs = &addr_imx51_to1;
+               int to_version = mx51_revision() >> 4;
+               imx51_imx_sdma_data.pdata.to_version = to_version;
+               imx51_imx_sdma_data.pdata.script_addrs = &addr_imx51;
                ret = imx_add_imx_sdma(&imx51_imx_sdma_data);
        } else
 #endif
index 18296ee68802708b876ec68b3f2b23c2b9d65599..ce659015535e4a86bc6e708fa3abcc2e59742ec0 100644 (file)
@@ -21,9 +21,4 @@ config HAS_MTU
          to multiple interrupt generating programmable
          32-bit free running decrementing counters.
 
-config NOMADIK_GPIO
-       bool
-       help
-         Support for the Nomadik GPIO controller.
-
 endif
index c33547361bd75b9e54306d867d212a4ac49f3e11..37c7cdd0f8f017979e64f80b00f09736f74d2c21 100644 (file)
@@ -3,4 +3,3 @@
 # Licensed under GPLv2
 
 obj-$(CONFIG_HAS_MTU)  += timer.o
-obj-$(CONFIG_NOMADIK_GPIO)     += gpio.o
index 1b9f6f0843d1227cf67f896511ac43467f62d617..d5d7e651269c3b434c5f500c5a491b9f7e3437c1 100644 (file)
@@ -78,6 +78,8 @@ extern int nmk_gpio_get_mode(int gpio);
 extern void nmk_gpio_wakeups_suspend(void);
 extern void nmk_gpio_wakeups_resume(void);
 
+extern void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up);
+
 /*
  * Platform data to register a block: only the initial gpio/irq number.
  */
@@ -88,6 +90,7 @@ struct nmk_gpio_platform_data {
        int num_gpio;
        u32 (*get_secondary_status)(unsigned int bank);
        void (*set_ioforce)(bool enable);
+       bool supports_sleepmode;
 };
 
 #endif /* __ASM_PLAT_GPIO_H */
index 1621db67a53dedec35b848a8230c6e276100fca6..8ba70ffc31ecaceb2adaf7d421eea9c900fe2b6a 100644 (file)
@@ -11,8 +11,8 @@
 enum i2c_freq_mode {
        I2C_FREQ_MODE_STANDARD,         /* up to 100 Kb/s */
        I2C_FREQ_MODE_FAST,             /* up to 400 Kb/s */
+       I2C_FREQ_MODE_HIGH_SPEED,       /* up to 3.4 Mb/s */
        I2C_FREQ_MODE_FAST_PLUS,        /* up to 1 Mb/s */
-       I2C_FREQ_MODE_HIGH_SPEED        /* up to 3.4 Mb/s */
 };
 
 /**
@@ -24,13 +24,15 @@ enum i2c_freq_mode {
  *             to the values of 14, 6, 2 for a 48 MHz i2c clk
  * @tft:       Tx FIFO Threshold in bytes
  * @rft:       Rx FIFO Threshold in bytes
+ * @timeout    Slave response timeout(ms)
  * @sm:                speed mode
  */
 struct nmk_i2c_controller {
        unsigned long   clk_freq;
        unsigned short  slsu;
-       unsigned char   tft;
-       unsigned char   rft;
+       unsigned char   tft;
+       unsigned char   rft;
+       int timeout;
        enum i2c_freq_mode      sm;
 };
 
index a4a12859fdd57c6bc4a65870ac57682c6f92f28d..f0233e6abcdff0e9d72fe4967df9be6a36e8e4e6 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 # Common support
-obj-y := common.o sram.o clock.o devices.o dma.o mux.o gpio.o \
+obj-y := common.o sram.o clock.o devices.o dma.o mux.o \
         usb.o fb.o io.o counter_32k.o
 obj-m :=
 obj-n :=
index 3083195123ea2c1f9c46ea840d56a83ceda838b0..0d88499b79e903b1f7cf9ef4d2afe5c31d61c086 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/mtd/map.h>
 
+struct platform_device;
 extern void omap1_set_vpp(struct platform_device *pdev, int enable);
 
 #endif
index cac2e8ac696821f3c3d30304f41796a8a58dfd47..ec97e00cb5810a7709eecd679a324bdda4ae41c8 100644 (file)
 
 #define OMAP34XX_NR_GPIOS              6
 
+/*
+ * OMAP1510 GPIO registers
+ */
+#define OMAP1510_GPIO_DATA_INPUT       0x00
+#define OMAP1510_GPIO_DATA_OUTPUT      0x04
+#define OMAP1510_GPIO_DIR_CONTROL      0x08
+#define OMAP1510_GPIO_INT_CONTROL      0x0c
+#define OMAP1510_GPIO_INT_MASK         0x10
+#define OMAP1510_GPIO_INT_STATUS       0x14
+#define OMAP1510_GPIO_PIN_CONTROL      0x18
+
+#define OMAP1510_IH_GPIO_BASE          64
+
+/*
+ * OMAP1610 specific GPIO registers
+ */
+#define OMAP1610_GPIO_REVISION         0x0000
+#define OMAP1610_GPIO_SYSCONFIG                0x0010
+#define OMAP1610_GPIO_SYSSTATUS                0x0014
+#define OMAP1610_GPIO_IRQSTATUS1       0x0018
+#define OMAP1610_GPIO_IRQENABLE1       0x001c
+#define OMAP1610_GPIO_WAKEUPENABLE     0x0028
+#define OMAP1610_GPIO_DATAIN           0x002c
+#define OMAP1610_GPIO_DATAOUT          0x0030
+#define OMAP1610_GPIO_DIRECTION                0x0034
+#define OMAP1610_GPIO_EDGE_CTRL1       0x0038
+#define OMAP1610_GPIO_EDGE_CTRL2       0x003c
+#define OMAP1610_GPIO_CLEAR_IRQENABLE1 0x009c
+#define OMAP1610_GPIO_CLEAR_WAKEUPENA  0x00a8
+#define OMAP1610_GPIO_CLEAR_DATAOUT    0x00b0
+#define OMAP1610_GPIO_SET_IRQENABLE1   0x00dc
+#define OMAP1610_GPIO_SET_WAKEUPENA    0x00e8
+#define OMAP1610_GPIO_SET_DATAOUT      0x00f0
+
+/*
+ * OMAP7XX specific GPIO registers
+ */
+#define OMAP7XX_GPIO_DATA_INPUT                0x00
+#define OMAP7XX_GPIO_DATA_OUTPUT       0x04
+#define OMAP7XX_GPIO_DIR_CONTROL       0x08
+#define OMAP7XX_GPIO_INT_CONTROL       0x0c
+#define OMAP7XX_GPIO_INT_MASK          0x10
+#define OMAP7XX_GPIO_INT_STATUS                0x14
+
+/*
+ * omap2+ specific GPIO registers
+ */
+#define OMAP24XX_GPIO_REVISION         0x0000
+#define OMAP24XX_GPIO_IRQSTATUS1       0x0018
+#define OMAP24XX_GPIO_IRQSTATUS2       0x0028
+#define OMAP24XX_GPIO_IRQENABLE2       0x002c
+#define OMAP24XX_GPIO_IRQENABLE1       0x001c
+#define OMAP24XX_GPIO_WAKE_EN          0x0020
+#define OMAP24XX_GPIO_CTRL             0x0030
+#define OMAP24XX_GPIO_OE               0x0034
+#define OMAP24XX_GPIO_DATAIN           0x0038
+#define OMAP24XX_GPIO_DATAOUT          0x003c
+#define OMAP24XX_GPIO_LEVELDETECT0     0x0040
+#define OMAP24XX_GPIO_LEVELDETECT1     0x0044
+#define OMAP24XX_GPIO_RISINGDETECT     0x0048
+#define OMAP24XX_GPIO_FALLINGDETECT    0x004c
+#define OMAP24XX_GPIO_DEBOUNCE_EN      0x0050
+#define OMAP24XX_GPIO_DEBOUNCE_VAL     0x0054
+#define OMAP24XX_GPIO_CLEARIRQENABLE1  0x0060
+#define OMAP24XX_GPIO_SETIRQENABLE1    0x0064
+#define OMAP24XX_GPIO_CLEARWKUENA      0x0080
+#define OMAP24XX_GPIO_SETWKUENA                0x0084
+#define OMAP24XX_GPIO_CLEARDATAOUT     0x0090
+#define OMAP24XX_GPIO_SETDATAOUT       0x0094
+
+#define OMAP4_GPIO_REVISION            0x0000
+#define OMAP4_GPIO_EOI                 0x0020
+#define OMAP4_GPIO_IRQSTATUSRAW0       0x0024
+#define OMAP4_GPIO_IRQSTATUSRAW1       0x0028
+#define OMAP4_GPIO_IRQSTATUS0          0x002c
+#define OMAP4_GPIO_IRQSTATUS1          0x0030
+#define OMAP4_GPIO_IRQSTATUSSET0       0x0034
+#define OMAP4_GPIO_IRQSTATUSSET1       0x0038
+#define OMAP4_GPIO_IRQSTATUSCLR0       0x003c
+#define OMAP4_GPIO_IRQSTATUSCLR1       0x0040
+#define OMAP4_GPIO_IRQWAKEN0           0x0044
+#define OMAP4_GPIO_IRQWAKEN1           0x0048
+#define OMAP4_GPIO_IRQENABLE1          0x011c
+#define OMAP4_GPIO_WAKE_EN             0x0120
+#define OMAP4_GPIO_IRQSTATUS2          0x0128
+#define OMAP4_GPIO_IRQENABLE2          0x012c
+#define OMAP4_GPIO_CTRL                        0x0130
+#define OMAP4_GPIO_OE                  0x0134
+#define OMAP4_GPIO_DATAIN              0x0138
+#define OMAP4_GPIO_DATAOUT             0x013c
+#define OMAP4_GPIO_LEVELDETECT0                0x0140
+#define OMAP4_GPIO_LEVELDETECT1                0x0144
+#define OMAP4_GPIO_RISINGDETECT                0x0148
+#define OMAP4_GPIO_FALLINGDETECT       0x014c
+#define OMAP4_GPIO_DEBOUNCENABLE       0x0150
+#define OMAP4_GPIO_DEBOUNCINGTIME      0x0154
+#define OMAP4_GPIO_CLEARIRQENABLE1     0x0160
+#define OMAP4_GPIO_SETIRQENABLE1       0x0164
+#define OMAP4_GPIO_CLEARWKUENA         0x0180
+#define OMAP4_GPIO_SETWKUENA           0x0184
+#define OMAP4_GPIO_CLEARDATAOUT                0x0190
+#define OMAP4_GPIO_SETDATAOUT          0x0194
+
 #define OMAP_MPUIO(nr)         (OMAP_MAX_GPIO_LINES + (nr))
 #define OMAP_GPIO_IS_MPUIO(nr) ((nr) >= OMAP_MAX_GPIO_LINES)
 
index 872de0bf1e6bb777368b1b1d61eb6d564dc3d473..ea6c9c88c725d1eee7e77390bdf2a6d4f68bf3b2 100644 (file)
 #ifndef __ASM_ARCH_OMAP_GPMC_SMSC911X_H__
 
 struct omap_smsc911x_platform_data {
+       int     id;
        int     cs;
        int     gpio_irq;
        int     gpio_reset;
        u32     flags;
 };
 
-#if defined(CONFIG_SMSC911X) || \
-       defined(CONFIG_SMSC911X_MODULE)
+#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
 
 extern void gpmc_smsc911x_init(struct omap_smsc911x_platform_data *d);
 
index 32a2f6c4d39e3b37437f9e9c60b792a84297ed6e..e992b9655fbc4fb873d489846ce82e8644ea5ea6 100644 (file)
@@ -29,9 +29,6 @@ struct iovm_struct {
  * lower 16 bit is used for h/w and upper 16 bit is for s/w.
  */
 #define IOVMF_SW_SHIFT         16
-#define IOVMF_HW_SIZE          (1 << IOVMF_SW_SHIFT)
-#define IOVMF_HW_MASK          (IOVMF_HW_SIZE - 1)
-#define IOVMF_SW_MASK          (~IOVMF_HW_MASK)UL
 
 /*
  * iovma: h/w flags derived from cam and ram attribute
index f38fef9f1310ca56fdf73fb3a3816ec674ba06a9..c7b874186c27017d58a38bc4209e1c225752d3f5 100644 (file)
@@ -101,6 +101,9 @@ struct omap_mmc_platform_data {
                /* If using power_saving and the MMC power is not to go off */
                unsigned no_off:1;
 
+               /* eMMC does not handle power off when not in sleep state */
+               unsigned no_regulator_off_init:1;
+
                /* Regulator off remapped to sleep */
                unsigned vcc_aux_disable_is_sleep:1;
 
index 565d2664f5a739adc503bca1d86751b4e997d2c7..ac4b60d9aa299c86208e66cdbe00df1432b6a650 100644 (file)
@@ -129,7 +129,6 @@ static inline void __arch_decomp_setup(unsigned long arch_id)
                DEBUG_LL_OMAP1(3, sx1);
 
                /* omap2 based boards using UART1 */
-               DEBUG_LL_OMAP2(1, omap2evm);
                DEBUG_LL_OMAP2(1, omap_2430sdp);
                DEBUG_LL_OMAP2(1, omap_apollon);
                DEBUG_LL_OMAP2(1, omap_h4);
index 02b96c8f6a17cd687f63a5e439d44ba57f621339..17d3c939775c7164e2c246f8a150bb212bbb0647 100644 (file)
@@ -113,7 +113,7 @@ extern int omap4430_phy_suspend(struct device *dev, int suspend);
 extern void am35x_musb_reset(void);
 extern void am35x_musb_phy_power(u8 on);
 extern void am35x_musb_clear_irq(void);
-extern void am35x_musb_set_mode(u8 musb_mode);
+extern void am35x_set_mode(u8 musb_mode);
 
 /*
  * FIXME correct answer depends on hmc_mode,
index 51ef43e8def6194e5d7bacfc361f093c3f89c79e..83a37c54342f414573d942c2c28f5bb9459b4ec7 100644 (file)
@@ -648,7 +648,6 @@ u32 iommu_vmap(struct iommu *obj, u32 da, const struct sg_table *sgt,
                        return PTR_ERR(va);
        }
 
-       flags &= IOVMF_HW_MASK;
        flags |= IOVMF_DISCONT;
        flags |= IOVMF_MMIO;
 
@@ -706,7 +705,6 @@ u32 iommu_vmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags)
        if (!va)
                return -ENOMEM;
 
-       flags &= IOVMF_HW_MASK;
        flags |= IOVMF_DISCONT;
        flags |= IOVMF_ALLOC;
 
@@ -795,7 +793,6 @@ u32 iommu_kmap(struct iommu *obj, u32 da, u32 pa, size_t bytes,
        if (!va)
                return -ENOMEM;
 
-       flags &= IOVMF_HW_MASK;
        flags |= IOVMF_LINEAR;
        flags |= IOVMF_MMIO;
 
@@ -853,7 +850,6 @@ u32 iommu_kmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags)
                return -ENOMEM;
        pa = virt_to_phys(va);
 
-       flags &= IOVMF_HW_MASK;
        flags |= IOVMF_LINEAR;
        flags |= IOVMF_ALLOC;
 
index a37b8eb65b76a6c2b13a019545852b3c9b48a7cc..49fc0df0c21f58be364d6da00e14d73eb8c32344 100644 (file)
@@ -84,6 +84,7 @@
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/pm_runtime.h>
 
 #include <plat/omap_device.h>
 #include <plat/omap_hwmod.h>
@@ -539,20 +540,34 @@ int omap_early_device_register(struct omap_device *od)
 static int _od_runtime_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
+       int ret;
+
+       ret = pm_generic_runtime_suspend(dev);
+
+       if (!ret)
+               omap_device_idle(pdev);
+
+       return ret;
+}
 
-       return omap_device_idle(pdev);
+static int _od_runtime_idle(struct device *dev)
+{
+       return pm_generic_runtime_idle(dev);
 }
 
 static int _od_runtime_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
 
-       return omap_device_enable(pdev);
+       omap_device_enable(pdev);
+
+       return pm_generic_runtime_resume(dev);
 }
 
 static struct dev_power_domain omap_device_power_domain = {
        .ops = {
                .runtime_suspend = _od_runtime_suspend,
+               .runtime_idle = _od_runtime_idle,
                .runtime_resume = _od_runtime_resume,
                USE_PLATFORM_PM_SLEEP_OPS
        }
index a3f50b34a90d3ffed85c0fcd4bc6baad080df7cd..6af3d0b1f8d058e8387697b3c560bce32f7e31ef 100644 (file)
@@ -166,7 +166,7 @@ static void __init omap_detect_sram(void)
                else if (cpu_is_omap1611())
                        omap_sram_size = SZ_256K;
                else {
-                       printk(KERN_ERR "Could not detect SRAM size\n");
+                       pr_err("Could not detect SRAM size\n");
                        omap_sram_size = 0x4000;
                }
        }
@@ -221,10 +221,10 @@ static void __init omap_map_sram(void)
        omap_sram_io_desc[0].length = ROUND_DOWN(omap_sram_size, PAGE_SIZE);
        iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc));
 
-       printk(KERN_INFO "SRAM: Mapped pa 0x%08lx to va 0x%08lx size: 0x%lx\n",
-       __pfn_to_phys(omap_sram_io_desc[0].pfn),
-       omap_sram_io_desc[0].virtual,
-              omap_sram_io_desc[0].length);
+       pr_info("SRAM: Mapped pa 0x%08llx to va 0x%08lx size: 0x%lx\n",
+               (long long) __pfn_to_phys(omap_sram_io_desc[0].pfn),
+               omap_sram_io_desc[0].virtual,
+               omap_sram_io_desc[0].length);
 
        /*
         * Normally devicemaps_init() would flush caches and tlb after
@@ -252,7 +252,7 @@ static void __init omap_map_sram(void)
 void *omap_sram_push_address(unsigned long size)
 {
        if (size > (omap_sram_ceil - (omap_sram_base + SRAM_BOOTLOADER_SZ))) {
-               printk(KERN_ERR "Not enough space in SRAM\n");
+               pr_err("Not enough space in SRAM\n");
                return NULL;
        }
 
index c10d10c56e2e71a632877a9576efe62a1a8a717e..2abf9660bc6cc6eaa9879b82281bf79d3c83225d 100644 (file)
@@ -1199,7 +1199,7 @@ EXPORT_SYMBOL(s3c2410_dma_getposition);
 
 #ifdef CONFIG_PM
 
-static void s3c2410_dma_suspend_chan(s3c2410_dma_chan *cp)
+static void s3c2410_dma_suspend_chan(struct s3c2410_dma_chan *cp)
 {
        printk(KERN_DEBUG "suspending dma channel %d\n", cp->number);
 
index 9aee7e1668b1e464a908af6243ea62f6b5f9e76b..fc8c5f89954d453c29fcdd45d3a385af63ca0a41 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
@@ -668,3 +669,8 @@ void __init s3c24xx_init_irq(void)
 
        irqdbf("s3c2410: registered interrupt handlers\n");
 }
+
+struct syscore_ops s3c24xx_irq_syscore_ops = {
+       .suspend        = s3c24xx_irq_suspend,
+       .resume         = s3c24xx_irq_resume,
+};
index 6751bcf7b8888fe3360f3f9551b328d1636f4181..e98f5c5c787961d57ab88d4a618ec19152a84011 100644 (file)
@@ -7,7 +7,7 @@
 
 config PLAT_S5P
        bool
-       depends on (ARCH_S5P64X0 || ARCH_S5P6442 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS4)
+       depends on (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS4)
        default y
        select ARM_VIC if !ARCH_EXYNOS4
        select ARM_GIC if ARCH_EXYNOS4
index 5cf5e721e6caf83234bd556936286a632961ff48..bbc2aa7449ca0242dcc8655c8cd0dde3bc90ef76 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <plat/cpu.h>
 #include <plat/s5p6440.h>
-#include <plat/s5p6442.h>
 #include <plat/s5p6450.h>
 #include <plat/s5pc100.h>
 #include <plat/s5pv210.h>
@@ -30,7 +29,6 @@
 /* table of supported CPUs */
 
 static const char name_s5p6440[] = "S5P6440";
-static const char name_s5p6442[] = "S5P6442";
 static const char name_s5p6450[] = "S5P6450";
 static const char name_s5pc100[] = "S5PC100";
 static const char name_s5pv210[] = "S5PV210/S5PC110";
@@ -45,14 +43,6 @@ static struct cpu_table cpu_ids[] __initdata = {
                .init_uarts     = s5p6440_init_uarts,
                .init           = s5p64x0_init,
                .name           = name_s5p6440,
-       }, {
-               .idcode         = 0x36442000,
-               .idmask         = 0xfffff000,
-               .map_io         = s5p6442_map_io,
-               .init_clocks    = s5p6442_init_clocks,
-               .init_uarts     = s5p6442_init_uarts,
-               .init           = s5p6442_init,
-               .name           = name_s5p6442,
        }, {
                .idcode         = 0x36450000,
                .idmask         = 0xfffff000,
index 6db926202caa6adcb193b899e21eb78584c28ff0..20336c8f247919f359bb22107cb8eadce842e55c 100644 (file)
@@ -15,8 +15,6 @@
 
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/onenand.h>
 
 #include <mach/irqs.h>
 #include <mach/map.h>
@@ -45,13 +43,3 @@ struct platform_device s5p_device_onenand = {
        .num_resources  = ARRAY_SIZE(s5p_onenand_resources),
        .resource       = s5p_onenand_resources,
 };
-
-void s5p_onenand_set_platdata(struct onenand_platform_data *pdata)
-{
-       struct onenand_platform_data *pd;
-
-       pd = kmemdup(pdata, sizeof(struct onenand_platform_data), GFP_KERNEL);
-       if (!pd)
-               printk(KERN_ERR "%s: no memory for platform data\n", __func__);
-       s5p_device_onenand.dev.platform_data = pd;
-}
index a6c3d327ce72d1306a8b9308501f60e7c8879efb..d973d39666a3f9e83adc79964810c6a2d8b85da3 100644 (file)
@@ -39,7 +39,7 @@
 #define S5P_VA_TWD             S5P_VA_COREPERI(0x600)
 #define S5P_VA_GIC_DIST                S5P_VA_COREPERI(0x1000)
 
-#define S5P_VA_USB_HSPHY       S3C_ADDR(0x02900000)
+#define S3C_VA_USB_HSPHY       S3C_ADDR(0x02900000)
 
 #define VA_VIC(x)              (S3C_VA_IRQ + ((x) * 0x10000))
 #define VA_VIC0                        VA_VIC(0)
diff --git a/arch/arm/plat-s5p/include/plat/s5p6442.h b/arch/arm/plat-s5p/include/plat/s5p6442.h
deleted file mode 100644 (file)
index 7b88013..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/* arch/arm/plat-s5p/include/plat/s5p6442.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * Header file for s5p6442 cpu 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.
-*/
-
-/* Common init code for S5P6442 related SoCs */
-
-extern void s5p6442_common_init_uarts(struct s3c2410_uartcfg *cfg, int no);
-extern void s5p6442_register_clocks(void);
-extern void s5p6442_setup_clocks(void);
-
-#ifdef CONFIG_CPU_S5P6442
-
-extern  int s5p6442_init(void);
-extern void s5p6442_init_irq(void);
-extern void s5p6442_map_io(void);
-extern void s5p6442_init_clocks(int xtal);
-
-#define s5p6442_init_uarts s5p6442_common_init_uarts
-
-#else
-#define s5p6442_init_clocks NULL
-#define s5p6442_init_uarts NULL
-#define s5p6442_map_io NULL
-#define s5p6442_init NULL
-#endif
index e9de58a2e2944eddba6a1b4df0fe27ee7684d825..53eb15b0a07d6efe6d1c26eb01d7c306eaff6f07 100644 (file)
@@ -19,7 +19,6 @@ obj-y                         += gpio.o
 obj-y                          += gpio-config.o
 obj-y                          += dev-asocdma.o
 
-obj-$(CONFIG_SAMSUNG_GPIOLIB_4BIT)     += gpiolib.o
 obj-$(CONFIG_SAMSUNG_CLKSRC)   += clock-clksrc.o
 
 obj-$(CONFIG_SAMSUNG_IRQ_UART) += irq-uart.o
index 45ec73287d8c89aeb0d0cde81d3ed95661d798ad..f54ae71f0cd2d461d296c4a5b9053ece80765a68 100644 (file)
@@ -13,8 +13,6 @@
 
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/onenand.h>
 
 #include <mach/irqs.h>
 #include <mach/map.h>
@@ -43,13 +41,3 @@ struct platform_device s3c_device_onenand = {
        .num_resources  = ARRAY_SIZE(s3c_onenand_resources),
        .resource       = s3c_onenand_resources,
 };
-
-void s3c_onenand_set_platdata(struct onenand_platform_data *pdata)
-{
-       struct onenand_platform_data *pd;
-
-       pd = kmemdup(pdata, sizeof(struct onenand_platform_data), GFP_KERNEL);
-       if (!pd)
-               printk(KERN_ERR "%s: no memory for platform data\n", __func__);
-       s3c_device_onenand.dev.platform_data = pd;
-}
index 3aedac0034bac2bcaa849a44aab852b634cd1597..c0a5741b23e6019817f8c6001714a3e9a3cde6ea 100644 (file)
@@ -86,7 +86,6 @@ extern struct sysdev_class s3c2443_sysclass;
 extern struct sysdev_class s3c6410_sysclass;
 extern struct sysdev_class s3c64xx_sysclass;
 extern struct sysdev_class s5p64x0_sysclass;
-extern struct sysdev_class s5p6442_sysclass;
 extern struct sysdev_class s5pv210_sysclass;
 extern struct sysdev_class exynos4_sysclass;
 
index dc6efd90e8ffaf51701532566b716c9f2953e282..207e275362a82f94844d58afccd725caada2a77f 100644 (file)
@@ -11,7 +11,7 @@
 
 #include <plat/regs-serial.h>
 
-/* The S5PV210/S5PC110 and S5P6442 implementations are as belows. */
+/* The S5PV210/S5PC110 implementations are as belows. */
 
        .macro fifo_level_s5pv210 rd, rx
                ldr     \rd, [ \rx, # S3C2410_UFSTAT ]
index 39818d8da4201539bf19537a16a83bc4e2e670e0..4af108ff41121da579b41e0717802daf6c56285b 100644 (file)
@@ -75,10 +75,8 @@ extern struct platform_device s5pc100_device_spi1;
 extern struct platform_device s5pc100_device_spi2;
 extern struct platform_device s5pv210_device_spi0;
 extern struct platform_device s5pv210_device_spi1;
-extern struct platform_device s5p6440_device_spi0;
-extern struct platform_device s5p6440_device_spi1;
-extern struct platform_device s5p6450_device_spi0;
-extern struct platform_device s5p6450_device_spi1;
+extern struct platform_device s5p64x0_device_spi0;
+extern struct platform_device s5p64x0_device_spi1;
 
 extern struct platform_device s3c_device_hwmon;
 
@@ -111,12 +109,6 @@ extern struct platform_device exynos4_device_spdif;
 extern struct platform_device exynos4_device_pd[];
 extern struct platform_device exynos4_device_ahci;
 
-extern struct platform_device s5p6442_device_pcm0;
-extern struct platform_device s5p6442_device_pcm1;
-extern struct platform_device s5p6442_device_iis0;
-extern struct platform_device s5p6442_device_iis1;
-extern struct platform_device s5p6442_device_spi;
-
 extern struct platform_device s5p6440_device_pcm;
 extern struct platform_device s5p6440_device_iis;
 
index 788837e99cb3da172159c35770dfbf1d47b86400..c151c5f94a87b0e647863b5bb48016a6f27f55a8 100644 (file)
 #define S3C64XX_UINTSP         0x34
 #define S3C64XX_UINTM          0x38
 
-/* Following are specific to S5PV210 and S5P6442 */
+/* Following are specific to S5PV210 */
 #define S5PV210_UCON_CLKMASK   (1<<10)
 #define S5PV210_UCON_PCLK      (0<<10)
 #define S5PV210_UCON_UCLK      (1<<10)
index ff1a561b326ee028aa66467e758e12ac03a63b25..0ffe34a215544b1008dc0d0ff6dbf0bc852da0cf 100644 (file)
@@ -69,6 +69,5 @@ extern void s3c64xx_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
 extern void s5pc100_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
 extern void s5pv210_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
 extern void s5p64x0_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
-extern void s5p6442_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
 
 #endif /* __S3C64XX_PLAT_SPI_H */
index 6f9ca56de1f6b19ee52cca2b98e8a07411700109..a06bfccc2840e5204c5519203a6c343837ebac3c 100644 (file)
@@ -5,6 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_BASE_FULL is not set
 # CONFIG_COMPAT_BRK is not set
index 7eece0af34c92ee46992b0a4d315110a2d254620..d8f1fe80d210daea5b764c50b0977a09d58c6a9f 100644 (file)
@@ -5,6 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_BASE_FULL is not set
 # CONFIG_COMPAT_BRK is not set
index 387eb9d6e423321297fa1959741a9ff93812777c..d4c5b19ec950a2eddc4b6399e8d0286626aeb0c9 100644 (file)
@@ -5,6 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_BASE_FULL is not set
 # CONFIG_COMPAT_BRK is not set
index 19f6ceeeff7b4710d5ccf916b231e0b469f9478f..77ca4f905d2cf9da872e12cb1efb4536a728a8f4 100644 (file)
@@ -7,6 +7,7 @@ CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_BASE_FULL is not set
 # CONFIG_SLUB_DEBUG is not set
@@ -109,7 +110,7 @@ CONFIG_LEDS_GPIO=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_RTC_CLASS=m
+CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_S35390A=m
 CONFIG_RTC_DRV_AT32AP700X=m
 CONFIG_DMADEVICES=y
index f0fe237133a93f1a2d0984ab10e57d403f83cd71..6e0dca4d3131ff920a7580408ab48b45cd92b916 100644 (file)
@@ -5,6 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_BASE_FULL is not set
 # CONFIG_COMPAT_BRK is not set
index e4a7c1dc8380f4aefbd17b055ef66b4a42acd4cb..7f2a344a5fa8334594929bcae48ec4fee4b5242c 100644 (file)
@@ -5,6 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_BASE_FULL is not set
 # CONFIG_COMPAT_BRK is not set
index 6f37f70c2c37a83d4126162b4910705a1693dd10..085eeba88f67e5b94efefe4284c57b69ca1c60c7 100644 (file)
@@ -5,6 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_BASE_FULL is not set
 # CONFIG_COMPAT_BRK is not set
index 4fb01f5ab42f1db7f20e653564946ca1443dc03f..d1a887e6405595010c7181c6a928c5fc35a3cb7b 100644 (file)
@@ -5,6 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_BASE_FULL is not set
 # CONFIG_COMPAT_BRK is not set
index 9faaf9b900f242358032ea65279d61575ffe6ec7..956f2819ad45495a96c9244a53781028b48c4d91 100644 (file)
@@ -5,6 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_BASE_FULL is not set
 # CONFIG_COMPAT_BRK is not set
index 3d2a5d85f970f46985096290085a1fe19e1006e1..40c69f38c61a2ab2b9a409dc1304cf495d0606b5 100644 (file)
@@ -5,6 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_BASE_FULL is not set
 # CONFIG_COMPAT_BRK is not set
index 1ed8f22d4fe2cd8ff5f8b9f3bfc04805fd19b3d6..511eb8af356dab0a3681ee274aade2a988c89096 100644 (file)
@@ -5,6 +5,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_BASE_FULL is not set
 # CONFIG_COMPAT_BRK is not set
index aeadc955db323b9da70dbb0b8b675243bcdcfee6..19973b06170c94a5518619a4fb07869c08c1727d 100644 (file)
@@ -6,6 +6,7 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_BASE_FULL is not set
 # CONFIG_COMPAT_BRK is not set
index 1692beeb7ed3beeb321a1de732448dc0f886b12e..6f45681196d135a1290c2a5d7ae8be2b7b180d99 100644 (file)
@@ -7,6 +7,7 @@ CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_BASE_FULL is not set
 # CONFIG_COMPAT_BRK is not set
index 8b670a6530bf163304e48fe383e66bfc03123e15..3befab966827bacb4339247637e27d39333a7b1b 100644 (file)
@@ -7,6 +7,7 @@ CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_BASE_FULL is not set
 CONFIG_MODULES=y
index 5a51f2e7ffb9f9390294145d0332b936187ee536..1bee51f2215475e5f4bdbbaf00b49e84daf6719a 100644 (file)
@@ -7,6 +7,7 @@ CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_BASE_FULL is not set
 # CONFIG_COMPAT_BRK is not set
index 72444d97f80cd759551256591bc1b9d8ff733b15..b70c19bab63af141d8815e1ec76fb96f3b06b63b 100644 (file)
@@ -270,14 +270,21 @@ static inline int __fls(unsigned long word)
 
 unsigned long find_first_zero_bit(const unsigned long *addr,
                                  unsigned long size);
+#define find_first_zero_bit find_first_zero_bit
+
 unsigned long find_next_zero_bit(const unsigned long *addr,
                                 unsigned long size,
                                 unsigned long offset);
+#define find_next_zero_bit find_next_zero_bit
+
 unsigned long find_first_bit(const unsigned long *addr,
                             unsigned long size);
+#define find_first_bit find_first_bit
+
 unsigned long find_next_bit(const unsigned long *addr,
                                 unsigned long size,
                                 unsigned long offset);
+#define find_next_bit find_next_bit
 
 /*
  * ffs: find first bit set. This is defined the same way as
@@ -299,6 +306,14 @@ static inline int ffs(unsigned long word)
 #include <asm-generic/bitops/hweight.h>
 #include <asm-generic/bitops/lock.h>
 
+extern unsigned long find_next_zero_bit_le(const void *addr,
+               unsigned long size, unsigned long offset);
+#define find_next_zero_bit_le find_next_zero_bit_le
+
+extern unsigned long find_next_bit_le(const void *addr,
+               unsigned long size, unsigned long offset);
+#define find_next_bit_le find_next_bit_le
+
 #include <asm-generic/bitops/le.h>
 #include <asm-generic/bitops/ext2-atomic.h>
 
index 49a88f5a9d2feda1c7b033cfd19c71453c6dd6bf..108502bc67706786d3125dff42be43f6a1d9b7d2 100644 (file)
@@ -131,7 +131,6 @@ struct thread_struct {
  */
 #define start_thread(regs, new_pc, new_sp)      \
        do {                                     \
-               set_fs(USER_DS);                 \
                memset(regs, 0, sizeof(*regs));  \
                regs->sr = MODE_USER;            \
                regs->pc = new_pc & ~1;          \
index 89861a27543ec58554f9ad957b84801a80885595..f714544e5560ce2fd0033f63b22480a0eef440d1 100644 (file)
 #define __NR_signalfd          279
 /* 280 was __NR_timerfd */
 #define __NR_eventfd           281
+#define __NR_setns             283
 
 #ifdef __KERNEL__
-#define NR_syscalls            282
+#define NR_syscalls            284
 
 /* Old stuff */
 #define __IGNORE_uselib
index e76bad16b0f08570f548934a78238bf54910d4c0..c7fd394d28a4d4e968addf61f659e0e781d21b60 100644 (file)
@@ -296,4 +296,5 @@ sys_call_table:
        .long   sys_ni_syscall          /* 280, was sys_timerfd */
        .long   sys_eventfd
        .long   sys_recvmmsg
+       .long   sys_setns
        .long   sys_ni_syscall          /* r8 is saturated at nr_syscalls */
index bfc9d071db9bce219985b62a5c80446ff7a1f3e5..7fbf0dcb9afe5f88e9e307f3530cdbd875cf20f1 100644 (file)
@@ -1014,6 +1014,7 @@ static struct platform_device *__initdata at32_usarts[4];
 void __init at32_map_usart(unsigned int hw_id, unsigned int line, int flags)
 {
        struct platform_device *pdev;
+       struct atmel_uart_data *pdata;
 
        switch (hw_id) {
        case 0:
@@ -1043,6 +1044,8 @@ void __init at32_map_usart(unsigned int hw_id, unsigned int line, int flags)
        }
 
        pdev->id = line;
+       pdata = pdev->dev.platform_data;
+       pdata->num = line;
        at32_usarts[line] = pdev;
 }
 
index 61740201b3115eb7988ff3eca6728195f5d90d8b..679458d9a622365afd30fe371c229567dedc83cb 100644 (file)
@@ -33,6 +33,7 @@ extern struct platform_device *atmel_default_console_device;
 #define        ATMEL_USART_CLK         0x04
 
 struct atmel_uart_data {
+       int             num;            /* port num */
        short           use_dma_tx;     /* use transmit DMA? */
        short           use_dma_rx;     /* use receive DMA? */
        void __iomem    *regs;          /* virtual base address, if any */
index 9c96a130f3a858b02b33a3d66f1347623a2ba1ea..8181293115e427b1087c95a3b56f041437fa1ced 100644 (file)
 #define cpu_is_at91sam9263()   (0)
 #define cpu_is_at91sam9rl()    (0)
 #define cpu_is_at91cap9()      (0)
+#define cpu_is_at91cap9_revB() (0)
+#define cpu_is_at91cap9_revC() (0)
 #define cpu_is_at91sam9g10()   (0)
+#define cpu_is_at91sam9g20()   (0)
 #define cpu_is_at91sam9g45()   (0)
 #define cpu_is_at91sam9g45es() (0)
+#define cpu_is_at91sam9m10()   (0)
+#define cpu_is_at91sam9g46()   (0)
+#define cpu_is_at91sam9m11()   (0)
+#define cpu_is_at91sam9x5()    (0)
+#define cpu_is_at91sam9g15()   (0)
+#define cpu_is_at91sam9g35()   (0)
+#define cpu_is_at91sam9x35()   (0)
+#define cpu_is_at91sam9g25()   (0)
+#define cpu_is_at91sam9x25()   (0)
 
 #endif /* __ASM_ARCH_CPU_H */
index 3e3646186c9ffa686aa01ff86821fe1cc7639ebe..c9ac2f8e8f648af54f08407c7f31fb85a4807d06 100644 (file)
@@ -167,14 +167,12 @@ static int intc_suspend(void)
        return 0;
 }
 
-static int intc_resume(void)
+static void intc_resume(void)
 {
        int i;
 
        for (i = 0; i < 64; i++)
                intc_writel(&intc0, INTPR0 + 4 * i, intc0.saved_ipr[i]);
-
-       return 0;
 }
 #else
 #define intc_suspend   NULL
index a7314d44b17ba5a2afd1bd83b3edaf8cea222c33..2798c2d4a1cf9c79e43df9df28378394d0cdd60a 100644 (file)
@@ -25,8 +25,6 @@
 #include <asm/setup.h>
 #include <asm/sections.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned_data;
 
 struct page *empty_zero_page;
index 8addb1220b4f290c5ec23eefa1f6f245b5753267..d619b17c4413009a5baaf89a3af21e2dc556a798 100644 (file)
@@ -24,11 +24,13 @@ config BLACKFIN
        select HAVE_FUNCTION_TRACER
        select HAVE_FUNCTION_TRACE_MCOUNT_TEST
        select HAVE_IDE
+       select HAVE_IRQ_WORK
        select HAVE_KERNEL_GZIP if RAMKERNEL
        select HAVE_KERNEL_BZIP2 if RAMKERNEL
        select HAVE_KERNEL_LZMA if RAMKERNEL
        select HAVE_KERNEL_LZO if RAMKERNEL
        select HAVE_OPROFILE
+       select HAVE_PERF_EVENTS
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_ATOMIC64
@@ -45,9 +47,6 @@ config GENERIC_BUG
 config ZONE_DMA
        def_bool y
 
-config GENERIC_FIND_NEXT_BIT
-       def_bool y
-
 config GENERIC_GPIO
        def_bool y
 
index 2641731f24cd12835e92da4dec18d0f61dee9f68..e2a3d4c8ab9aca33059de9475941007a595a9113 100644 (file)
@@ -9,15 +9,6 @@ config DEBUG_STACKOVERFLOW
          This option will cause messages to be printed if free stack space
          drops below a certain limit.
 
-config DEBUG_STACK_USAGE
-       bool "Enable stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T output.
-
-         This option will slow down process creation somewhat.
-
 config DEBUG_VERBOSE
        bool "Verbose fault messages"
        default y
@@ -32,7 +23,7 @@ config DEBUG_VERBOSE
          Most people should say N here.
 
 config DEBUG_MMRS
-       bool "Generate Blackfin MMR tree"
+       tristate "Generate Blackfin MMR tree"
        select DEBUG_FS
        help
          Create a tree of Blackfin MMRs via the debugfs tree.  If
index 95cf2ba9de17ba2e95337efc8de0d14f3a21e754..8465b3e6b8628a23b5961471c46de0adf617d1db 100644 (file)
@@ -121,13 +121,11 @@ CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_VGA16 is not set
 # CONFIG_LOGO_LINUX_CLUT224 is not set
 # CONFIG_LOGO_BLACKFIN_VGA16 is not set
-CONFIG_SOUND=m
-CONFIG_SND=m
-CONFIG_SND_SOC=m
-CONFIG_SND_BF5XX_I2S=m
-CONFIG_SND_BF5XX_SOC_SSM2602=m
-CONFIG_SND_BF5XX_AC97=m
-CONFIG_SND_BF5XX_SOC_AD1980=m
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_BF5XX_I2S=y
+CONFIG_SND_BF5XX_SOC_SSM2602=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
index 8be8e33fac526c7eb6526f39ce9f44c7a1521ab9..5e7321b26040665fb4a6a3b74db5c82208af2107 100644 (file)
@@ -96,7 +96,7 @@ CONFIG_SERIAL_BFIN_UART1=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=m
-CONFIG_I2C_BLACKFIN_TWI=m
+CONFIG_I2C_BLACKFIN_TWI=y
 CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 CONFIG_SPI=y
 CONFIG_SPI_BFIN=y
@@ -115,13 +115,11 @@ CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_VGA16 is not set
 # CONFIG_LOGO_LINUX_CLUT224 is not set
 # CONFIG_LOGO_BLACKFIN_VGA16 is not set
-CONFIG_SOUND=m
-CONFIG_SND=m
-CONFIG_SND_SOC=m
-CONFIG_SND_BF5XX_I2S=m
-CONFIG_SND_BF5XX_SOC_SSM2602=m
-CONFIG_SND_BF5XX_AC97=m
-CONFIG_SND_BF5XX_SOC_AD1980=m
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_BF5XX_I2S=y
+CONFIG_SND_BF5XX_SOC_SSM2602=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
index 0aafde6c8c2d00fd079c62999fb60cf7023dcc87..b90d3792ed5209a46b2cd4342398d18e28bf531f 100644 (file)
@@ -99,8 +99,6 @@ CONFIG_SND_PCM_OSS=m
 CONFIG_SND_SOC=m
 CONFIG_SND_BF5XX_I2S=m
 CONFIG_SND_BF5XX_SOC_AD73311=m
-CONFIG_SND_BF5XX_AC97=m
-CONFIG_SND_BF5XX_SOC_AD1980=m
 # CONFIG_USB_SUPPORT is not set
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_BFIN=y
index c9077fb581354bc621fe5e1ee152e9ae1933a56a..005362537a7b4c3f4d70dc46f864bd78feafcbf3 100644 (file)
@@ -110,8 +110,6 @@ CONFIG_SND_PCM_OSS=m
 CONFIG_SND_SOC=m
 CONFIG_SND_BF5XX_I2S=m
 CONFIG_SND_BF5XX_SOC_AD73311=m
-CONFIG_SND_BF5XX_AC97=m
-CONFIG_SND_BF5XX_SOC_AD1980=m
 # CONFIG_USB_SUPPORT is not set
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_BFIN=y
index 31d954216c054ec37748ffb942d6d3f463d8ba8b..9f1d08401fcaacdf6d53f661da44e2cee641b66e 100644 (file)
@@ -112,7 +112,7 @@ CONFIG_USB_G_SERIAL=m
 CONFIG_USB_G_PRINTER=m
 CONFIG_MMC=m
 CONFIG_SDH_BFIN=m
-CONFIG_RTC_CLASS=m
+CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_BFIN=m
 CONFIG_EXT2_FS=m
 # CONFIG_DNOTIFY is not set
index 121cc04d877d891c1e4594a9ade1795abf5991e4..17bcbf60bcae15641097aed9234ceae16a92e061 100644 (file)
@@ -49,16 +49,6 @@ extern void dump_bfin_trace_buffer(void);
 #define dump_bfin_trace_buffer()
 #endif
 
-/* init functions only */
-extern int init_arch_irq(void);
-extern void init_exception_vectors(void);
-extern void program_IAR(void);
-
-extern asmlinkage void lower_to_irq14(void);
-extern asmlinkage void bfin_return_from_exception(void);
-extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs);
-extern int bfin_internal_set_wake(unsigned int irq, unsigned int state);
-
 extern void *l1_data_A_sram_alloc(size_t);
 extern void *l1_data_B_sram_alloc(size_t);
 extern void *l1_inst_sram_alloc(size_t);
diff --git a/arch/blackfin/include/asm/bfin_pfmon.h b/arch/blackfin/include/asm/bfin_pfmon.h
new file mode 100644 (file)
index 0000000..accd47e
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Blackfin Performance Monitor definitions
+ *
+ * Copyright 2005-2011 Analog Devices Inc.
+ *
+ * Licensed under the ADI BSD license or GPL-2 (or later).
+ */
+
+#ifndef __ASM_BFIN_PFMON_H__
+#define __ASM_BFIN_PFMON_H__
+
+/* PFCTL Masks */
+#define PFMON_MASK     0xff
+#define PFCEN_MASK     0x3
+#define PFCEN_DISABLE  0x0
+#define PFCEN_ENABLE_USER      0x1
+#define PFCEN_ENABLE_SUPV      0x2
+#define PFCEN_ENABLE_ALL       (PFCEN_ENABLE_USER | PFCEN_ENABLE_SUPV)
+
+#define PFPWR_P        0
+#define PEMUSW0_P      2
+#define PFCEN0_P       3
+#define PFMON0_P       5
+#define PEMUSW1_P      13
+#define PFCEN1_P       14
+#define PFMON1_P       16
+#define PFCNT0_P       24
+#define PFCNT1_P       25
+
+#define PFPWR  (1 << PFPWR_P)
+#define PEMUSW(n, x)   ((x) << ((n) ? PEMUSW1_P : PEMUSW0_P))
+#define PEMUSW0        PEMUSW(0, 1)
+#define PEMUSW1        PEMUSW(1, 1)
+#define PFCEN(n, x)    ((x) << ((n) ? PFCEN1_P : PFCEN0_P))
+#define PFCEN0 PFCEN(0, PFCEN_MASK)
+#define PFCEN1 PFCEN(1, PFCEN_MASK)
+#define PFCNT(n, x)    ((x) << ((n) ? PFCNT1_P : PFCNT0_P))
+#define PFCNT0 PFCNT(0, 1)
+#define PFCNT1 PFCNT(1, 1)
+#define PFMON(n, x)    ((x) << ((n) ? PFMON1_P : PFMON0_P))
+#define PFMON0 PFMON(0, PFMON_MASK)
+#define PFMON1 PFMON(1, PFMON_MASK)
+
+#endif
index 7dbc664eab1e2925baf95b8cc949cff65b4a4091..7fd0ec7b5b0f2c9326d0cd4deb0f788b6fadea34 100644 (file)
@@ -184,7 +184,7 @@ struct bfin_uart_regs {
 #undef __BFP
 
 #ifndef port_membase
-# define port_membase(p) (((struct bfin_serial_port *)(p))->port.membase)
+# define port_membase(p) 0
 #endif
 
 #define UART_GET_CHAR(p)      bfin_read16(port_membase(p) + OFFSET_RBR)
@@ -235,10 +235,10 @@ struct bfin_uart_regs {
 #define UART_SET_DLAB(p)      do { UART_PUT_LCR(p, UART_GET_LCR(p) | DLAB); SSYNC(); } while (0)
 
 #ifndef put_lsr_cache
-# define put_lsr_cache(p, v) (((struct bfin_serial_port *)(p))->lsr = (v))
+# define put_lsr_cache(p, v)
 #endif
 #ifndef get_lsr_cache
-# define get_lsr_cache(p)    (((struct bfin_serial_port *)(p))->lsr)
+# define get_lsr_cache(p) 0
 #endif
 
 /* The hardware clears the LSR bits upon read, so we need to cache
index d27600c262c2b18427b0d28feed430440cbd6452..f8568a31d0ab5fb0c8e0893176fcbf348df8b2d6 100644 (file)
@@ -100,6 +100,10 @@ struct sport_register {
 };
 #undef __BFP
 
+struct bfin_snd_platform_data {
+       const unsigned short *pin_req;
+};
+
 #define bfin_read_sport_rx32(base) \
 ({ \
        struct sport_register *__mmrs = (void *)base; \
index 77135b62818e16794db3d441debbec3c0cfb7254..9a5b2c572ebfb6b55fbe5f36add07ec3d4ed3903 100644 (file)
@@ -39,8 +39,13 @@ extern void blackfin_invalidate_entire_icache(void);
 
 static inline void flush_icache_range(unsigned start, unsigned end)
 {
-#if defined(CONFIG_BFIN_EXTMEM_WRITEBACK) || defined(CONFIG_BFIN_L2_WRITEBACK)
-       blackfin_dcache_flush_range(start, end);
+#if defined(CONFIG_BFIN_EXTMEM_WRITEBACK)
+       if (end <= physical_mem_end)
+               blackfin_dcache_flush_range(start, end);
+#endif
+#if defined(CONFIG_BFIN_L2_WRITEBACK)
+       if (start >= L2_START && end <= L2_START + L2_LENGTH)
+               blackfin_dcache_flush_range(start, end);
 #endif
 
        /* Make sure all write buffers in the data side of the core
@@ -52,9 +57,17 @@ static inline void flush_icache_range(unsigned start, unsigned end)
         * the pipeline.
         */
        SSYNC();
-#if defined(CONFIG_BFIN_ICACHE)
-       blackfin_icache_flush_range(start, end);
-       flush_icache_range_others(start, end);
+#if defined(CONFIG_BFIN_EXTMEM_ICACHEABLE)
+       if (end <= physical_mem_end) {
+               blackfin_icache_flush_range(start, end);
+               flush_icache_range_others(start, end);
+       }
+#endif
+#if defined(CONFIG_BFIN_L2_ICACHEABLE)
+       if (start >= L2_START && end <= L2_START + L2_LENGTH) {
+               blackfin_icache_flush_range(start, end);
+               flush_icache_range_others(start, end);
+       }
 #endif
 }
 
index 16883e582e3cd96ce9a914242837f877e3a77f16..05043786da2199cbb302563a0c1e3e62295852c2 100644 (file)
 
 #include <linux/percpu.h>
 
-struct task_struct;
-
 struct blackfin_cpudata {
        struct cpu cpu;
-       struct task_struct *idle;
        unsigned int imemctl;
        unsigned int dmemctl;
 };
index 7600fe0696af1c9cda33471b1bf8a963e43df303..8236790114575eb9e2dc4df8e21c3cbf0413376c 100644 (file)
 
 #define bfin_read(addr) \
 ({ \
-    sizeof(*(addr)) == 1 ? bfin_read8(addr)  : \
-    sizeof(*(addr)) == 2 ? bfin_read16(addr) : \
-    sizeof(*(addr)) == 4 ? bfin_read32(addr) : \
-    ({ BUG(); 0; }); \
+       sizeof(*(addr)) == 1 ? bfin_read8(addr)  : \
+       sizeof(*(addr)) == 2 ? bfin_read16(addr) : \
+       sizeof(*(addr)) == 4 ? bfin_read32(addr) : \
+       ({ BUG(); 0; }); \
 })
 #define bfin_write(addr, val) \
 do { \
@@ -69,13 +69,13 @@ do { \
 
 #define bfin_write_or(addr, bits) \
 do { \
-       void *__addr = (void *)(addr); \
+       typeof(addr) __addr = (addr); \
        bfin_write(__addr, bfin_read(__addr) | (bits)); \
 } while (0)
 
 #define bfin_write_and(addr, bits) \
 do { \
-       void *__addr = (void *)(addr); \
+       typeof(addr) __addr = (addr); \
        bfin_write(__addr, bfin_read(__addr) & (bits)); \
 } while (0)
 
index c722acdda0d396cc3835001ebdc55c1da5435493..38657dac1235d4d4d8e2a3d8b66b364aa931ed79 100644 (file)
@@ -193,4 +193,22 @@ uint16_t get_enabled_gptimers(void);
 uint32_t get_gptimer_status(unsigned int group);
 void     set_gptimer_status(unsigned int group, uint32_t value);
 
+/*
+ * All Blackfin system MMRs are padded to 32bits even if the register
+ * itself is only 16bits.  So use a helper macro to streamline this.
+ */
+#define __BFP(m) u16 m; u16 __pad_##m
+
+/*
+ * bfin timer registers layout
+ */
+struct bfin_gptimer_regs {
+       __BFP(config);
+       u32 counter;
+       u32 period;
+       u32 width;
+};
+
+#undef __BFP
+
 #endif
index 7fbe42307b9a4ce176be29458fba04b2769a20d6..ee73f79aef1025759a27c9a27ed1f0d89120fdcf 100644 (file)
 #include <linux/types.h>
 #include <linux/linkage.h>
 
+/* init functions only */
+extern int __init init_arch_irq(void);
+extern void init_exception_vectors(void);
+extern void __init program_IAR(void);
+#ifdef init_mach_irq
+extern void __init init_mach_irq(void);
+#else
+# define init_mach_irq()
+#endif
+
 /* BASE LEVEL interrupt handler routines */
 asmlinkage void evt_exception(void);
 asmlinkage void trap(void);
@@ -37,4 +47,19 @@ extern void return_from_exception(void);
 extern int bfin_request_exception(unsigned int exception, void (*handler)(void));
 extern int bfin_free_exception(unsigned int exception, void (*handler)(void));
 
+extern asmlinkage void lower_to_irq14(void);
+extern asmlinkage void bfin_return_from_exception(void);
+extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs);
+extern int bfin_internal_set_wake(unsigned int irq, unsigned int state);
+
+struct irq_data;
+extern void bfin_handle_irq(unsigned irq);
+extern void bfin_ack_noop(struct irq_data *);
+extern void bfin_internal_mask_irq(unsigned int irq);
+extern void bfin_internal_unmask_irq(unsigned int irq);
+
+struct irq_desc;
+extern void bfin_demux_mac_status_irq(unsigned int, struct irq_desc *);
+extern void bfin_demux_gpio_irq(unsigned int, struct irq_desc *);
+
 #endif
index 8651afe1299027502afd3700b4394ae3dfcf0b85..aaf884591b070cfa6246804f3491efac713afcab 100644 (file)
@@ -103,7 +103,12 @@ static inline void arch_kgdb_breakpoint(void)
        asm("EXCPT 2;");
 }
 #define BREAK_INSTR_SIZE       2
-#define CACHE_FLUSH_IS_SAFE    1
+#ifdef CONFIG_SMP
+# define CACHE_FLUSH_IS_SAFE   0
+#else
+# define CACHE_FLUSH_IS_SAFE   1
+#endif
+#define GDB_ADJUSTS_BREAK_OFFSET
 #define HW_INST_WATCHPOINT_NUM 6
 #define HW_WATCHPOINT_NUM      8
 #define TYPE_INST_WATCHPOINT   0
diff --git a/arch/blackfin/include/asm/perf_event.h b/arch/blackfin/include/asm/perf_event.h
new file mode 100644 (file)
index 0000000..3d2b171
--- /dev/null
@@ -0,0 +1 @@
+#define MAX_HWEVENTS 2
index 832d7c009a2cf5ed890a5e54a33074444b4d0e84..7854d4367c15c2247c70ef0a07af9ee933df0887 100644 (file)
@@ -102,14 +102,9 @@ struct pt_regs {
 /* user_mode returns true if only one bit is set in IPEND, other than the
    master interrupt enable.  */
 #define user_mode(regs) (!(((regs)->ipend & ~0x10) & (((regs)->ipend & ~0x10) - 1)))
-#define instruction_pointer(regs) ((regs)->pc)
-#define user_stack_pointer(regs)  ((regs)->usp)
-#define profile_pc(regs) instruction_pointer(regs)
 extern void show_regs(struct pt_regs *);
 
 #define arch_has_single_step() (1)
-extern void user_enable_single_step(struct task_struct *child);
-extern void user_disable_single_step(struct task_struct *child);
 /* common code demands this function */
 #define ptrace_disable(child) user_disable_single_step(child)
 
@@ -130,6 +125,8 @@ extern int is_user_addr_valid(struct task_struct *child,
            ((unsigned long)task_stack_page(task) + \
             (THREAD_SIZE - sizeof(struct pt_regs)))
 
+#include <asm-generic/ptrace.h>
+
 #endif  /*  __KERNEL__  */
 
 #endif                         /* __ASSEMBLY__ */
index ff9a9f35d50b0d53c09fda181041050f01224962..0ccba60b9ccfde4ec58f1efab7be1fbddee2a24c 100644 (file)
 #define __NR_open_by_handle_at 376
 #define __NR_clock_adjtime     377
 #define __NR_syncfs            378
+#define __NR_setns             379
+#define __NR_sendmmsg          380
 
-#define __NR_syscall           379
+#define __NR_syscall           381
 #define NR_syscalls            __NR_syscall
 
 /* Old optional stuff no one actually uses */
diff --git a/arch/blackfin/include/mach-common/irq.h b/arch/blackfin/include/mach-common/irq.h
new file mode 100644 (file)
index 0000000..cab14e9
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Common Blackfin IRQ definitions (i.e. the CEC)
+ *
+ * Copyright 2005-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#ifndef _MACH_COMMON_IRQ_H_
+#define _MACH_COMMON_IRQ_H_
+
+/*
+ * Core events interrupt source definitions
+ *
+ *  Event Source       Event Name
+ *  Emulation          EMU            0  (highest priority)
+ *  Reset              RST            1
+ *  NMI                NMI            2
+ *  Exception          EVX            3
+ *  Reserved           --             4
+ *  Hardware Error     IVHW           5
+ *  Core Timer         IVTMR          6
+ *  Peripherals        IVG7           7
+ *  Peripherals        IVG8           8
+ *  Peripherals        IVG9           9
+ *  Peripherals        IVG10         10
+ *  Peripherals        IVG11         11
+ *  Peripherals        IVG12         12
+ *  Peripherals        IVG13         13
+ *  Softirq            IVG14         14
+ *  System Call        IVG15         15  (lowest priority)
+ */
+
+/* The ABSTRACT IRQ definitions */
+#define IRQ_EMU                        0       /* Emulation */
+#define IRQ_RST                        1       /* reset */
+#define IRQ_NMI                        2       /* Non Maskable */
+#define IRQ_EVX                        3       /* Exception */
+#define IRQ_UNUSED             4       /* - unused interrupt */
+#define IRQ_HWERR              5       /* Hardware Error */
+#define IRQ_CORETMR            6       /* Core timer */
+
+#define BFIN_IRQ(x)            ((x) + 7)
+
+#define IVG7                   7
+#define IVG8                   8
+#define IVG9                   9
+#define IVG10                  10
+#define IVG11                  11
+#define IVG12                  12
+#define IVG13                  13
+#define IVG14                  14
+#define IVG15                  15
+
+#define NR_IRQS                        (NR_MACH_IRQS + NR_SPARE_IRQS)
+
+#endif
index ca5ccc777772097ee66854c18e0fa4e6cb07dbfb..d550b24d9e9b2a9fa6a78bbb3783b1031845a57e 100644 (file)
@@ -33,7 +33,10 @@ obj-$(CONFIG_EARLY_PRINTK)           += shadow_console.o
 obj-$(CONFIG_STACKTRACE)             += stacktrace.o
 obj-$(CONFIG_DEBUG_VERBOSE)          += trace.o
 obj-$(CONFIG_BFIN_PSEUDODBG_INSNS)   += pseudodbg.o
+obj-$(CONFIG_PERF_EVENTS)            += perf_event.o
 
 # the kgdb test puts code into L2 and without linker
 # relaxation, we need to force long calls to/from it
 CFLAGS_kgdb_test.o := -mlong-calls -O0
+
+obj-$(CONFIG_DEBUG_MMRS)             += debug-mmrs.o
index 6ce8dce753c9a49039a615e56cf8e83fbb8097bf..71dbaa4a48afc1263b23af017702ea82aedb2557 100644 (file)
@@ -36,6 +36,11 @@ static int __init blackfin_dma_init(void)
 
        printk(KERN_INFO "Blackfin DMA Controller\n");
 
+
+#if ANOMALY_05000480
+       bfin_write_DMAC_TC_PER(0x0111);
+#endif
+
        for (i = 0; i < MAX_DMA_CHANNELS; i++) {
                atomic_set(&dma_ch[i].chan_status, 0);
                dma_ch[i].regs = dma_io_base_addr[i];
index 170cf90735ba6cb806ee002b7041313760ebae2a..bcf8cf6fe4126d6608a560b39e2b92ade8b89a7a 100644 (file)
 #include <linux/module.h>
 #include <linux/err.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <asm/blackfin.h>
 #include <asm/gpio.h>
 #include <asm/portmux.h>
 #include <linux/irq.h>
+#include <asm/irq_handler.h>
 
 #if ANOMALY_05000311 || ANOMALY_05000323
 enum {
@@ -534,7 +536,7 @@ static const unsigned int sic_iwr_irqs[] = {
 #if defined(BF533_FAMILY)
        IRQ_PROG_INTB
 #elif defined(BF537_FAMILY)
-       IRQ_PROG_INTB, IRQ_PORTG_INTB, IRQ_MAC_TX
+       IRQ_PF_INTB_WATCH, IRQ_PORTG_INTB, IRQ_PH_INTB_MAC_TX
 #elif defined(BF538_FAMILY)
        IRQ_PORTF_INTB
 #elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
@@ -1203,35 +1205,43 @@ void bfin_reset_boot_spi_cs(unsigned short pin)
 }
 
 #if defined(CONFIG_PROC_FS)
-static int gpio_proc_read(char *buf, char **start, off_t offset,
-                         int len, int *unused_i, void *unused_v)
+static int gpio_proc_show(struct seq_file *m, void *v)
 {
-       int c, irq, gpio, outlen = 0;
+       int c, irq, gpio;
 
        for (c = 0; c < MAX_RESOURCES; c++) {
                irq = is_reserved(gpio_irq, c, 1);
                gpio = is_reserved(gpio, c, 1);
                if (!check_gpio(c) && (gpio || irq))
-                       len = sprintf(buf, "GPIO_%d: \t%s%s \t\tGPIO %s\n", c,
+                       seq_printf(m, "GPIO_%d: \t%s%s \t\tGPIO %s\n", c,
                                 get_label(c), (gpio && irq) ? " *" : "",
                                 get_gpio_dir(c) ? "OUTPUT" : "INPUT");
                else if (is_reserved(peri, c, 1))
-                       len = sprintf(buf, "GPIO_%d: \t%s \t\tPeripheral\n", c, get_label(c));
+                       seq_printf(m, "GPIO_%d: \t%s \t\tPeripheral\n", c, get_label(c));
                else
                        continue;
-               buf += len;
-               outlen += len;
        }
-       return outlen;
+
+       return 0;
 }
 
+static int gpio_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, gpio_proc_show, NULL);
+}
+
+static const struct file_operations gpio_proc_ops = {
+       .open           = gpio_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static __init int gpio_register_proc(void)
 {
        struct proc_dir_entry *proc_gpio;
 
-       proc_gpio = create_proc_entry("gpio", S_IRUGO, NULL);
-       if (proc_gpio)
-               proc_gpio->read_proc = gpio_proc_read;
+       proc_gpio = proc_create("gpio", S_IRUGO, NULL, &gpio_proc_ops);
        return proc_gpio != NULL;
 }
 __initcall(gpio_register_proc);
index 2c264b51566afa2d7ca45b8ad129fcc8384e89c0..c446591b961ddc7d922ead4be15e58ae94158687 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <asm/cacheflush.h>
 #include <asm/io.h>
+#include <asm/irq_handler.h>
 
 /* Allow people to have their own Blackfin exception handler in a module */
 EXPORT_SYMBOL(bfin_return_from_exception);
diff --git a/arch/blackfin/kernel/debug-mmrs.c b/arch/blackfin/kernel/debug-mmrs.c
new file mode 100644 (file)
index 0000000..fce4807
--- /dev/null
@@ -0,0 +1,1860 @@
+/*
+ * debugfs interface to core/system MMRs
+ *
+ * Copyright 2007-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <asm/blackfin.h>
+#include <asm/gpio.h>
+#include <asm/gptimers.h>
+#include <asm/bfin_can.h>
+#include <asm/bfin_dma.h>
+#include <asm/bfin_ppi.h>
+#include <asm/bfin_serial.h>
+#include <asm/bfin5xx_spi.h>
+#include <asm/bfin_twi.h>
+
+/* Common code defines PORT_MUX on us, so redirect the MMR back locally */
+#ifdef BFIN_PORT_MUX
+#undef PORT_MUX
+#define PORT_MUX BFIN_PORT_MUX
+#endif
+
+#define _d(name, bits, addr, perms) debugfs_create_x##bits(name, perms, parent, (u##bits *)addr)
+#define d(name, bits, addr)         _d(name, bits, addr, S_IRUSR|S_IWUSR)
+#define d_RO(name, bits, addr)      _d(name, bits, addr, S_IRUSR)
+#define d_WO(name, bits, addr)      _d(name, bits, addr, S_IWUSR)
+
+#define D_RO(name, bits) d_RO(#name, bits, name)
+#define D_WO(name, bits) d_WO(#name, bits, name)
+#define D32(name)        d(#name, 32, name)
+#define D16(name)        d(#name, 16, name)
+
+#define REGS_OFF(peri, mmr) offsetof(struct bfin_##peri##_regs, mmr)
+#define __REGS(peri, sname, rname) \
+       do { \
+               struct bfin_##peri##_regs r; \
+               void *addr = (void *)(base + REGS_OFF(peri, rname)); \
+               strcpy(_buf, sname); \
+               if (sizeof(r.rname) == 2) \
+                       debugfs_create_x16(buf, S_IRUSR|S_IWUSR, parent, addr); \
+               else \
+                       debugfs_create_x32(buf, S_IRUSR|S_IWUSR, parent, addr); \
+       } while (0)
+#define REGS_STR_PFX(buf, pfx, num) \
+       ({ \
+               buf + (num >= 0 ? \
+                       sprintf(buf, #pfx "%i_", num) : \
+                       sprintf(buf, #pfx "_")); \
+       })
+#define REGS_STR_PFX_C(buf, pfx, num) \
+       ({ \
+               buf + (num >= 0 ? \
+                       sprintf(buf, #pfx "%c_", 'A' + num) : \
+                       sprintf(buf, #pfx "_")); \
+       })
+
+/*
+ * Core registers (not memory mapped)
+ */
+extern u32 last_seqstat;
+
+static int debug_cclk_get(void *data, u64 *val)
+{
+       *val = get_cclk();
+       return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_debug_cclk, debug_cclk_get, NULL, "0x%08llx\n");
+
+static int debug_sclk_get(void *data, u64 *val)
+{
+       *val = get_sclk();
+       return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_debug_sclk, debug_sclk_get, NULL, "0x%08llx\n");
+
+#define DEFINE_SYSREG(sr, pre, post) \
+static int sysreg_##sr##_get(void *data, u64 *val) \
+{ \
+       unsigned long tmp; \
+       pre; \
+       __asm__ __volatile__("%0 = " #sr ";" : "=d"(tmp)); \
+       *val = tmp; \
+       return 0; \
+} \
+static int sysreg_##sr##_set(void *data, u64 val) \
+{ \
+       unsigned long tmp = val; \
+       __asm__ __volatile__(#sr " = %0;" : : "d"(tmp)); \
+       post; \
+       return 0; \
+} \
+DEFINE_SIMPLE_ATTRIBUTE(fops_sysreg_##sr, sysreg_##sr##_get, sysreg_##sr##_set, "0x%08llx\n")
+
+DEFINE_SYSREG(cycles, , );
+DEFINE_SYSREG(cycles2, __asm__ __volatile__("%0 = cycles;" : "=d"(tmp)), );
+DEFINE_SYSREG(emudat, , );
+DEFINE_SYSREG(seqstat, , );
+DEFINE_SYSREG(syscfg, , CSYNC());
+#define D_SYSREG(sr) debugfs_create_file(#sr, S_IRUSR|S_IWUSR, parent, NULL, &fops_sysreg_##sr)
+
+/*
+ * CAN
+ */
+#define CAN_OFF(mmr)  REGS_OFF(can, mmr)
+#define __CAN(uname, lname) __REGS(can, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_can(struct dentry *parent, unsigned long base, int num)
+{
+       static struct dentry *am, *mb;
+       int i, j;
+       char buf[32], *_buf = REGS_STR_PFX(buf, CAN, num);
+
+       if (!am) {
+               am = debugfs_create_dir("am", parent);
+               mb = debugfs_create_dir("mb", parent);
+       }
+
+       __CAN(MC1, mc1);
+       __CAN(MD1, md1);
+       __CAN(TRS1, trs1);
+       __CAN(TRR1, trr1);
+       __CAN(TA1, ta1);
+       __CAN(AA1, aa1);
+       __CAN(RMP1, rmp1);
+       __CAN(RML1, rml1);
+       __CAN(MBTIF1, mbtif1);
+       __CAN(MBRIF1, mbrif1);
+       __CAN(MBIM1, mbim1);
+       __CAN(RFH1, rfh1);
+       __CAN(OPSS1, opss1);
+
+       __CAN(MC2, mc2);
+       __CAN(MD2, md2);
+       __CAN(TRS2, trs2);
+       __CAN(TRR2, trr2);
+       __CAN(TA2, ta2);
+       __CAN(AA2, aa2);
+       __CAN(RMP2, rmp2);
+       __CAN(RML2, rml2);
+       __CAN(MBTIF2, mbtif2);
+       __CAN(MBRIF2, mbrif2);
+       __CAN(MBIM2, mbim2);
+       __CAN(RFH2, rfh2);
+       __CAN(OPSS2, opss2);
+
+       __CAN(CLOCK, clock);
+       __CAN(TIMING, timing);
+       __CAN(DEBUG, debug);
+       __CAN(STATUS, status);
+       __CAN(CEC, cec);
+       __CAN(GIS, gis);
+       __CAN(GIM, gim);
+       __CAN(GIF, gif);
+       __CAN(CONTROL, control);
+       __CAN(INTR, intr);
+       __CAN(VERSION, version);
+       __CAN(MBTD, mbtd);
+       __CAN(EWR, ewr);
+       __CAN(ESR, esr);
+       /*__CAN(UCREG, ucreg); no longer exists */
+       __CAN(UCCNT, uccnt);
+       __CAN(UCRC, ucrc);
+       __CAN(UCCNF, uccnf);
+       __CAN(VERSION2, version2);
+
+       for (i = 0; i < 32; ++i) {
+               sprintf(_buf, "AM%02iL", i);
+               debugfs_create_x16(buf, S_IRUSR|S_IWUSR, am,
+                       (u16 *)(base + CAN_OFF(msk[i].aml)));
+               sprintf(_buf, "AM%02iH", i);
+               debugfs_create_x16(buf, S_IRUSR|S_IWUSR, am,
+                       (u16 *)(base + CAN_OFF(msk[i].amh)));
+
+               for (j = 0; j < 3; ++j) {
+                       sprintf(_buf, "MB%02i_DATA%i", i, j);
+                       debugfs_create_x16(buf, S_IRUSR|S_IWUSR, mb,
+                               (u16 *)(base + CAN_OFF(chl[i].data[j*2])));
+               }
+               sprintf(_buf, "MB%02i_LENGTH", i);
+               debugfs_create_x16(buf, S_IRUSR|S_IWUSR, mb,
+                       (u16 *)(base + CAN_OFF(chl[i].dlc)));
+               sprintf(_buf, "MB%02i_TIMESTAMP", i);
+               debugfs_create_x16(buf, S_IRUSR|S_IWUSR, mb,
+                       (u16 *)(base + CAN_OFF(chl[i].tsv)));
+               sprintf(_buf, "MB%02i_ID0", i);
+               debugfs_create_x16(buf, S_IRUSR|S_IWUSR, mb,
+                       (u16 *)(base + CAN_OFF(chl[i].id0)));
+               sprintf(_buf, "MB%02i_ID1", i);
+               debugfs_create_x16(buf, S_IRUSR|S_IWUSR, mb,
+                       (u16 *)(base + CAN_OFF(chl[i].id1)));
+       }
+}
+#define CAN(num) bfin_debug_mmrs_can(parent, CAN##num##_MC1, num)
+
+/*
+ * DMA
+ */
+#define __DMA(uname, lname) __REGS(dma, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_dma(struct dentry *parent, unsigned long base, int num, char mdma, const char *pfx)
+{
+       char buf[32], *_buf;
+
+       if (mdma)
+               _buf = buf + sprintf(buf, "%s_%c%i_", pfx, mdma, num);
+       else
+               _buf = buf + sprintf(buf, "%s%i_", pfx, num);
+
+       __DMA(NEXT_DESC_PTR, next_desc_ptr);
+       __DMA(START_ADDR, start_addr);
+       __DMA(CONFIG, config);
+       __DMA(X_COUNT, x_count);
+       __DMA(X_MODIFY, x_modify);
+       __DMA(Y_COUNT, y_count);
+       __DMA(Y_MODIFY, y_modify);
+       __DMA(CURR_DESC_PTR, curr_desc_ptr);
+       __DMA(CURR_ADDR, curr_addr);
+       __DMA(IRQ_STATUS, irq_status);
+       __DMA(PERIPHERAL_MAP, peripheral_map);
+       __DMA(CURR_X_COUNT, curr_x_count);
+       __DMA(CURR_Y_COUNT, curr_y_count);
+}
+#define _DMA(num, base, mdma, pfx) bfin_debug_mmrs_dma(parent, base, num, mdma, pfx "DMA")
+#define DMA(num)  _DMA(num, DMA##num##_NEXT_DESC_PTR, 0, "")
+#define _MDMA(num, x) \
+       do { \
+               _DMA(num, x##DMA_D##num##_NEXT_DESC_PTR, 'D', #x); \
+               _DMA(num, x##DMA_S##num##_NEXT_DESC_PTR, 'S', #x); \
+       } while (0)
+#define MDMA(num) _MDMA(num, M)
+#define IMDMA(num) _MDMA(num, IM)
+
+/*
+ * EPPI
+ */
+#define __EPPI(uname, lname) __REGS(eppi, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_eppi(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf = REGS_STR_PFX(buf, EPPI, num);
+       __EPPI(STATUS, status);
+       __EPPI(HCOUNT, hcount);
+       __EPPI(HDELAY, hdelay);
+       __EPPI(VCOUNT, vcount);
+       __EPPI(VDELAY, vdelay);
+       __EPPI(FRAME, frame);
+       __EPPI(LINE, line);
+       __EPPI(CLKDIV, clkdiv);
+       __EPPI(CONTROL, control);
+       __EPPI(FS1W_HBL, fs1w_hbl);
+       __EPPI(FS1P_AVPL, fs1p_avpl);
+       __EPPI(FS2W_LVB, fs2w_lvb);
+       __EPPI(FS2P_LAVF, fs2p_lavf);
+       __EPPI(CLIP, clip);
+}
+#define EPPI(num) bfin_debug_mmrs_eppi(parent, EPPI##num##_STATUS, num)
+
+/*
+ * General Purpose Timers
+ */
+#define __GPTIMER(uname, lname) __REGS(gptimer, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_gptimer(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf = REGS_STR_PFX(buf, TIMER, num);
+       __GPTIMER(CONFIG, config);
+       __GPTIMER(COUNTER, counter);
+       __GPTIMER(PERIOD, period);
+       __GPTIMER(WIDTH, width);
+}
+#define GPTIMER(num) bfin_debug_mmrs_gptimer(parent, TIMER##num##_CONFIG, num)
+
+/*
+ * Handshake MDMA
+ */
+#define __HMDMA(uname, lname) __REGS(hmdma, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_hmdma(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf = REGS_STR_PFX(buf, HMDMA, num);
+       __HMDMA(CONTROL, control);
+       __HMDMA(ECINIT, ecinit);
+       __HMDMA(BCINIT, bcinit);
+       __HMDMA(ECURGENT, ecurgent);
+       __HMDMA(ECOVERFLOW, ecoverflow);
+       __HMDMA(ECOUNT, ecount);
+       __HMDMA(BCOUNT, bcount);
+}
+#define HMDMA(num) bfin_debug_mmrs_hmdma(parent, HMDMA##num##_CONTROL, num)
+
+/*
+ * Port/GPIO
+ */
+#define bfin_gpio_regs gpio_port_t
+#define __PORT(uname, lname) __REGS(gpio, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_port(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf;
+#ifdef __ADSPBF54x__
+       _buf = REGS_STR_PFX_C(buf, PORT, num);
+       __PORT(FER, port_fer);
+       __PORT(SET, data_set);
+       __PORT(CLEAR, data_clear);
+       __PORT(DIR_SET, dir_set);
+       __PORT(DIR_CLEAR, dir_clear);
+       __PORT(INEN, inen);
+       __PORT(MUX, port_mux);
+#else
+       _buf = buf + sprintf(buf, "PORT%cIO_", num);
+       __PORT(CLEAR, data_clear);
+       __PORT(SET, data_set);
+       __PORT(TOGGLE, toggle);
+       __PORT(MASKA, maska);
+       __PORT(MASKA_CLEAR, maska_clear);
+       __PORT(MASKA_SET, maska_set);
+       __PORT(MASKA_TOGGLE, maska_toggle);
+       __PORT(MASKB, maskb);
+       __PORT(MASKB_CLEAR, maskb_clear);
+       __PORT(MASKB_SET, maskb_set);
+       __PORT(MASKB_TOGGLE, maskb_toggle);
+       __PORT(DIR, dir);
+       __PORT(POLAR, polar);
+       __PORT(EDGE, edge);
+       __PORT(BOTH, both);
+       __PORT(INEN, inen);
+#endif
+       _buf[-1] = '\0';
+       d(buf, 16, base + REGS_OFF(gpio, data));
+}
+#define PORT(base, num) bfin_debug_mmrs_port(parent, base, num)
+
+/*
+ * PPI
+ */
+#define __PPI(uname, lname) __REGS(ppi, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_ppi(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf = REGS_STR_PFX(buf, PPI, num);
+       __PPI(CONTROL, control);
+       __PPI(STATUS, status);
+       __PPI(COUNT, count);
+       __PPI(DELAY, delay);
+       __PPI(FRAME, frame);
+}
+#define PPI(num) bfin_debug_mmrs_ppi(parent, PPI##num##_CONTROL, num)
+
+/*
+ * SPI
+ */
+#define __SPI(uname, lname) __REGS(spi, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_spi(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf = REGS_STR_PFX(buf, SPI, num);
+       __SPI(CTL, ctl);
+       __SPI(FLG, flg);
+       __SPI(STAT, stat);
+       __SPI(TDBR, tdbr);
+       __SPI(RDBR, rdbr);
+       __SPI(BAUD, baud);
+       __SPI(SHADOW, shadow);
+}
+#define SPI(num) bfin_debug_mmrs_spi(parent, SPI##num##_REGBASE, num)
+
+/*
+ * SPORT
+ */
+static inline int sport_width(void *mmr)
+{
+       unsigned long lmmr = (unsigned long)mmr;
+       if ((lmmr & 0xff) == 0x10)
+               /* SPORT#_TX has 0x10 offset -> SPORT#_TCR2 has 0x04 offset */
+               lmmr -= 0xc;
+       else
+               /* SPORT#_RX has 0x18 offset -> SPORT#_RCR2 has 0x24 offset */
+               lmmr += 0xc;
+       /* extract SLEN field from control register 2 and add 1 */
+       return (bfin_read16(lmmr) & 0x1f) + 1;
+}
+static int sport_set(void *mmr, u64 val)
+{
+       unsigned long flags;
+       local_irq_save(flags);
+       if (sport_width(mmr) <= 16)
+               bfin_write16(mmr, val);
+       else
+               bfin_write32(mmr, val);
+       local_irq_restore(flags);
+       return 0;
+}
+static int sport_get(void *mmr, u64 *val)
+{
+       unsigned long flags;
+       local_irq_save(flags);
+       if (sport_width(mmr) <= 16)
+               *val = bfin_read16(mmr);
+       else
+               *val = bfin_read32(mmr);
+       local_irq_restore(flags);
+       return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_sport, sport_get, sport_set, "0x%08llx\n");
+/*DEFINE_SIMPLE_ATTRIBUTE(fops_sport_ro, sport_get, NULL, "0x%08llx\n");*/
+DEFINE_SIMPLE_ATTRIBUTE(fops_sport_wo, NULL, sport_set, "0x%08llx\n");
+#define SPORT_OFF(mmr) (SPORT0_##mmr - SPORT0_TCR1)
+#define _D_SPORT(name, perms, fops) \
+       do { \
+               strcpy(_buf, #name); \
+               debugfs_create_file(buf, perms, parent, (void *)(base + SPORT_OFF(name)), fops); \
+       } while (0)
+#define __SPORT_RW(name) _D_SPORT(name, S_IRUSR|S_IWUSR, &fops_sport)
+#define __SPORT_RO(name) _D_SPORT(name, S_IRUSR, &fops_sport_ro)
+#define __SPORT_WO(name) _D_SPORT(name, S_IWUSR, &fops_sport_wo)
+#define __SPORT(name, bits) \
+       do { \
+               strcpy(_buf, #name); \
+               debugfs_create_x##bits(buf, S_IRUSR|S_IWUSR, parent, (u##bits *)(base + SPORT_OFF(name))); \
+       } while (0)
+static void __init __maybe_unused
+bfin_debug_mmrs_sport(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf = REGS_STR_PFX(buf, SPORT, num);
+       __SPORT(CHNL, 16);
+       __SPORT(MCMC1, 16);
+       __SPORT(MCMC2, 16);
+       __SPORT(MRCS0, 32);
+       __SPORT(MRCS1, 32);
+       __SPORT(MRCS2, 32);
+       __SPORT(MRCS3, 32);
+       __SPORT(MTCS0, 32);
+       __SPORT(MTCS1, 32);
+       __SPORT(MTCS2, 32);
+       __SPORT(MTCS3, 32);
+       __SPORT(RCLKDIV, 16);
+       __SPORT(RCR1, 16);
+       __SPORT(RCR2, 16);
+       __SPORT(RFSDIV, 16);
+       __SPORT_RW(RX);
+       __SPORT(STAT, 16);
+       __SPORT(TCLKDIV, 16);
+       __SPORT(TCR1, 16);
+       __SPORT(TCR2, 16);
+       __SPORT(TFSDIV, 16);
+       __SPORT_WO(TX);
+}
+#define SPORT(num) bfin_debug_mmrs_sport(parent, SPORT##num##_TCR1, num)
+
+/*
+ * TWI
+ */
+#define __TWI(uname, lname) __REGS(twi, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_twi(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf = REGS_STR_PFX(buf, TWI, num);
+       __TWI(CLKDIV, clkdiv);
+       __TWI(CONTROL, control);
+       __TWI(SLAVE_CTL, slave_ctl);
+       __TWI(SLAVE_STAT, slave_stat);
+       __TWI(SLAVE_ADDR, slave_addr);
+       __TWI(MASTER_CTL, master_ctl);
+       __TWI(MASTER_STAT, master_stat);
+       __TWI(MASTER_ADDR, master_addr);
+       __TWI(INT_STAT, int_stat);
+       __TWI(INT_MASK, int_mask);
+       __TWI(FIFO_CTL, fifo_ctl);
+       __TWI(FIFO_STAT, fifo_stat);
+       __TWI(XMT_DATA8, xmt_data8);
+       __TWI(XMT_DATA16, xmt_data16);
+       __TWI(RCV_DATA8, rcv_data8);
+       __TWI(RCV_DATA16, rcv_data16);
+}
+#define TWI(num) bfin_debug_mmrs_twi(parent, TWI##num##_CLKDIV, num)
+
+/*
+ * UART
+ */
+#define __UART(uname, lname) __REGS(uart, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_uart(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf = REGS_STR_PFX(buf, UART, num);
+#ifdef BFIN_UART_BF54X_STYLE
+       __UART(DLL, dll);
+       __UART(DLH, dlh);
+       __UART(GCTL, gctl);
+       __UART(LCR, lcr);
+       __UART(MCR, mcr);
+       __UART(LSR, lsr);
+       __UART(MSR, msr);
+       __UART(SCR, scr);
+       __UART(IER_SET, ier_set);
+       __UART(IER_CLEAR, ier_clear);
+       __UART(THR, thr);
+       __UART(RBR, rbr);
+#else
+       __UART(DLL, dll);
+       __UART(THR, thr);
+       __UART(RBR, rbr);
+       __UART(DLH, dlh);
+       __UART(IER, ier);
+       __UART(IIR, iir);
+       __UART(LCR, lcr);
+       __UART(MCR, mcr);
+       __UART(LSR, lsr);
+       __UART(MSR, msr);
+       __UART(SCR, scr);
+       __UART(GCTL, gctl);
+#endif
+}
+#define UART(num) bfin_debug_mmrs_uart(parent, UART##num##_DLL, num)
+
+/*
+ * The actual debugfs generation
+ */
+static struct dentry *debug_mmrs_dentry;
+
+static int __init bfin_debug_mmrs_init(void)
+{
+       struct dentry *top, *parent;
+
+       pr_info("debug-mmrs: setting up Blackfin MMR debugfs\n");
+
+       top = debugfs_create_dir("blackfin", NULL);
+       if (top == NULL)
+               return -1;
+
+       parent = debugfs_create_dir("core_regs", top);
+       debugfs_create_file("cclk", S_IRUSR, parent, NULL, &fops_debug_cclk);
+       debugfs_create_file("sclk", S_IRUSR, parent, NULL, &fops_debug_sclk);
+       debugfs_create_x32("last_seqstat", S_IRUSR, parent, &last_seqstat);
+       D_SYSREG(cycles);
+       D_SYSREG(cycles2);
+       D_SYSREG(emudat);
+       D_SYSREG(seqstat);
+       D_SYSREG(syscfg);
+
+       /* Core MMRs */
+       parent = debugfs_create_dir("ctimer", top);
+       D32(TCNTL);
+       D32(TCOUNT);
+       D32(TPERIOD);
+       D32(TSCALE);
+
+       parent = debugfs_create_dir("cec", top);
+       D32(EVT0);
+       D32(EVT1);
+       D32(EVT2);
+       D32(EVT3);
+       D32(EVT4);
+       D32(EVT5);
+       D32(EVT6);
+       D32(EVT7);
+       D32(EVT8);
+       D32(EVT9);
+       D32(EVT10);
+       D32(EVT11);
+       D32(EVT12);
+       D32(EVT13);
+       D32(EVT14);
+       D32(EVT15);
+       D32(EVT_OVERRIDE);
+       D32(IMASK);
+       D32(IPEND);
+       D32(ILAT);
+       D32(IPRIO);
+
+       parent = debugfs_create_dir("debug", top);
+       D32(DBGSTAT);
+       D32(DSPID);
+
+       parent = debugfs_create_dir("mmu", top);
+       D32(SRAM_BASE_ADDRESS);
+       D32(DCPLB_ADDR0);
+       D32(DCPLB_ADDR10);
+       D32(DCPLB_ADDR11);
+       D32(DCPLB_ADDR12);
+       D32(DCPLB_ADDR13);
+       D32(DCPLB_ADDR14);
+       D32(DCPLB_ADDR15);
+       D32(DCPLB_ADDR1);
+       D32(DCPLB_ADDR2);
+       D32(DCPLB_ADDR3);
+       D32(DCPLB_ADDR4);
+       D32(DCPLB_ADDR5);
+       D32(DCPLB_ADDR6);
+       D32(DCPLB_ADDR7);
+       D32(DCPLB_ADDR8);
+       D32(DCPLB_ADDR9);
+       D32(DCPLB_DATA0);
+       D32(DCPLB_DATA10);
+       D32(DCPLB_DATA11);
+       D32(DCPLB_DATA12);
+       D32(DCPLB_DATA13);
+       D32(DCPLB_DATA14);
+       D32(DCPLB_DATA15);
+       D32(DCPLB_DATA1);
+       D32(DCPLB_DATA2);
+       D32(DCPLB_DATA3);
+       D32(DCPLB_DATA4);
+       D32(DCPLB_DATA5);
+       D32(DCPLB_DATA6);
+       D32(DCPLB_DATA7);
+       D32(DCPLB_DATA8);
+       D32(DCPLB_DATA9);
+       D32(DCPLB_FAULT_ADDR);
+       D32(DCPLB_STATUS);
+       D32(DMEM_CONTROL);
+       D32(DTEST_COMMAND);
+       D32(DTEST_DATA0);
+       D32(DTEST_DATA1);
+
+       D32(ICPLB_ADDR0);
+       D32(ICPLB_ADDR1);
+       D32(ICPLB_ADDR2);
+       D32(ICPLB_ADDR3);
+       D32(ICPLB_ADDR4);
+       D32(ICPLB_ADDR5);
+       D32(ICPLB_ADDR6);
+       D32(ICPLB_ADDR7);
+       D32(ICPLB_ADDR8);
+       D32(ICPLB_ADDR9);
+       D32(ICPLB_ADDR10);
+       D32(ICPLB_ADDR11);
+       D32(ICPLB_ADDR12);
+       D32(ICPLB_ADDR13);
+       D32(ICPLB_ADDR14);
+       D32(ICPLB_ADDR15);
+       D32(ICPLB_DATA0);
+       D32(ICPLB_DATA1);
+       D32(ICPLB_DATA2);
+       D32(ICPLB_DATA3);
+       D32(ICPLB_DATA4);
+       D32(ICPLB_DATA5);
+       D32(ICPLB_DATA6);
+       D32(ICPLB_DATA7);
+       D32(ICPLB_DATA8);
+       D32(ICPLB_DATA9);
+       D32(ICPLB_DATA10);
+       D32(ICPLB_DATA11);
+       D32(ICPLB_DATA12);
+       D32(ICPLB_DATA13);
+       D32(ICPLB_DATA14);
+       D32(ICPLB_DATA15);
+       D32(ICPLB_FAULT_ADDR);
+       D32(ICPLB_STATUS);
+       D32(IMEM_CONTROL);
+       if (!ANOMALY_05000481) {
+               D32(ITEST_COMMAND);
+               D32(ITEST_DATA0);
+               D32(ITEST_DATA1);
+       }
+
+       parent = debugfs_create_dir("perf", top);
+       D32(PFCNTR0);
+       D32(PFCNTR1);
+       D32(PFCTL);
+
+       parent = debugfs_create_dir("trace", top);
+       D32(TBUF);
+       D32(TBUFCTL);
+       D32(TBUFSTAT);
+
+       parent = debugfs_create_dir("watchpoint", top);
+       D32(WPIACTL);
+       D32(WPIA0);
+       D32(WPIA1);
+       D32(WPIA2);
+       D32(WPIA3);
+       D32(WPIA4);
+       D32(WPIA5);
+       D32(WPIACNT0);
+       D32(WPIACNT1);
+       D32(WPIACNT2);
+       D32(WPIACNT3);
+       D32(WPIACNT4);
+       D32(WPIACNT5);
+       D32(WPDACTL);
+       D32(WPDA0);
+       D32(WPDA1);
+       D32(WPDACNT0);
+       D32(WPDACNT1);
+       D32(WPSTAT);
+
+       /* System MMRs */
+#ifdef ATAPI_CONTROL
+       parent = debugfs_create_dir("atapi", top);
+       D16(ATAPI_CONTROL);
+       D16(ATAPI_DEV_ADDR);
+       D16(ATAPI_DEV_RXBUF);
+       D16(ATAPI_DEV_TXBUF);
+       D16(ATAPI_DMA_TFRCNT);
+       D16(ATAPI_INT_MASK);
+       D16(ATAPI_INT_STATUS);
+       D16(ATAPI_LINE_STATUS);
+       D16(ATAPI_MULTI_TIM_0);
+       D16(ATAPI_MULTI_TIM_1);
+       D16(ATAPI_MULTI_TIM_2);
+       D16(ATAPI_PIO_TFRCNT);
+       D16(ATAPI_PIO_TIM_0);
+       D16(ATAPI_PIO_TIM_1);
+       D16(ATAPI_REG_TIM_0);
+       D16(ATAPI_SM_STATE);
+       D16(ATAPI_STATUS);
+       D16(ATAPI_TERMINATE);
+       D16(ATAPI_UDMAOUT_TFRCNT);
+       D16(ATAPI_ULTRA_TIM_0);
+       D16(ATAPI_ULTRA_TIM_1);
+       D16(ATAPI_ULTRA_TIM_2);
+       D16(ATAPI_ULTRA_TIM_3);
+       D16(ATAPI_UMAIN_TFRCNT);
+       D16(ATAPI_XFER_LEN);
+#endif
+
+#if defined(CAN_MC1) || defined(CAN0_MC1) || defined(CAN1_MC1)
+       parent = debugfs_create_dir("can", top);
+# ifdef CAN_MC1
+       bfin_debug_mmrs_can(parent, CAN_MC1, -1);
+# endif
+# ifdef CAN0_MC1
+       CAN(0);
+# endif
+# ifdef CAN1_MC1
+       CAN(1);
+# endif
+#endif
+
+#ifdef CNT_COMMAND
+       parent = debugfs_create_dir("counter", top);
+       D16(CNT_COMMAND);
+       D16(CNT_CONFIG);
+       D32(CNT_COUNTER);
+       D16(CNT_DEBOUNCE);
+       D16(CNT_IMASK);
+       D32(CNT_MAX);
+       D32(CNT_MIN);
+       D16(CNT_STATUS);
+#endif
+
+       parent = debugfs_create_dir("dmac", top);
+#ifdef DMA_TC_CNT
+       D16(DMAC_TC_CNT);
+       D16(DMAC_TC_PER);
+#endif
+#ifdef DMAC0_TC_CNT
+       D16(DMAC0_TC_CNT);
+       D16(DMAC0_TC_PER);
+#endif
+#ifdef DMAC1_TC_CNT
+       D16(DMAC1_TC_CNT);
+       D16(DMAC1_TC_PER);
+#endif
+#ifdef DMAC1_PERIMUX
+       D16(DMAC1_PERIMUX);
+#endif
+
+#ifdef __ADSPBF561__
+       /* XXX: should rewrite the MMR map */
+# define DMA0_NEXT_DESC_PTR DMA2_0_NEXT_DESC_PTR
+# define DMA1_NEXT_DESC_PTR DMA2_1_NEXT_DESC_PTR
+# define DMA2_NEXT_DESC_PTR DMA2_2_NEXT_DESC_PTR
+# define DMA3_NEXT_DESC_PTR DMA2_3_NEXT_DESC_PTR
+# define DMA4_NEXT_DESC_PTR DMA2_4_NEXT_DESC_PTR
+# define DMA5_NEXT_DESC_PTR DMA2_5_NEXT_DESC_PTR
+# define DMA6_NEXT_DESC_PTR DMA2_6_NEXT_DESC_PTR
+# define DMA7_NEXT_DESC_PTR DMA2_7_NEXT_DESC_PTR
+# define DMA8_NEXT_DESC_PTR DMA2_8_NEXT_DESC_PTR
+# define DMA9_NEXT_DESC_PTR DMA2_9_NEXT_DESC_PTR
+# define DMA10_NEXT_DESC_PTR DMA2_10_NEXT_DESC_PTR
+# define DMA11_NEXT_DESC_PTR DMA2_11_NEXT_DESC_PTR
+# define DMA12_NEXT_DESC_PTR DMA1_0_NEXT_DESC_PTR
+# define DMA13_NEXT_DESC_PTR DMA1_1_NEXT_DESC_PTR
+# define DMA14_NEXT_DESC_PTR DMA1_2_NEXT_DESC_PTR
+# define DMA15_NEXT_DESC_PTR DMA1_3_NEXT_DESC_PTR
+# define DMA16_NEXT_DESC_PTR DMA1_4_NEXT_DESC_PTR
+# define DMA17_NEXT_DESC_PTR DMA1_5_NEXT_DESC_PTR
+# define DMA18_NEXT_DESC_PTR DMA1_6_NEXT_DESC_PTR
+# define DMA19_NEXT_DESC_PTR DMA1_7_NEXT_DESC_PTR
+# define DMA20_NEXT_DESC_PTR DMA1_8_NEXT_DESC_PTR
+# define DMA21_NEXT_DESC_PTR DMA1_9_NEXT_DESC_PTR
+# define DMA22_NEXT_DESC_PTR DMA1_10_NEXT_DESC_PTR
+# define DMA23_NEXT_DESC_PTR DMA1_11_NEXT_DESC_PTR
+#endif
+       parent = debugfs_create_dir("dma", top);
+       DMA(0);
+       DMA(1);
+       DMA(1);
+       DMA(2);
+       DMA(3);
+       DMA(4);
+       DMA(5);
+       DMA(6);
+       DMA(7);
+#ifdef DMA8_NEXT_DESC_PTR
+       DMA(8);
+       DMA(9);
+       DMA(10);
+       DMA(11);
+#endif
+#ifdef DMA12_NEXT_DESC_PTR
+       DMA(12);
+       DMA(13);
+       DMA(14);
+       DMA(15);
+       DMA(16);
+       DMA(17);
+       DMA(18);
+       DMA(19);
+#endif
+#ifdef DMA20_NEXT_DESC_PTR
+       DMA(20);
+       DMA(21);
+       DMA(22);
+       DMA(23);
+#endif
+
+       parent = debugfs_create_dir("ebiu_amc", top);
+       D32(EBIU_AMBCTL0);
+       D32(EBIU_AMBCTL1);
+       D16(EBIU_AMGCTL);
+#ifdef EBIU_MBSCTL
+       D16(EBIU_MBSCTL);
+       D32(EBIU_ARBSTAT);
+       D32(EBIU_MODE);
+       D16(EBIU_FCTL);
+#endif
+
+#ifdef EBIU_SDGCTL
+       parent = debugfs_create_dir("ebiu_sdram", top);
+# ifdef __ADSPBF561__
+       D32(EBIU_SDBCTL);
+# else
+       D16(EBIU_SDBCTL);
+# endif
+       D32(EBIU_SDGCTL);
+       D16(EBIU_SDRRC);
+       D16(EBIU_SDSTAT);
+#endif
+
+#ifdef EBIU_DDRACCT
+       parent = debugfs_create_dir("ebiu_ddr", top);
+       D32(EBIU_DDRACCT);
+       D32(EBIU_DDRARCT);
+       D32(EBIU_DDRBRC0);
+       D32(EBIU_DDRBRC1);
+       D32(EBIU_DDRBRC2);
+       D32(EBIU_DDRBRC3);
+       D32(EBIU_DDRBRC4);
+       D32(EBIU_DDRBRC5);
+       D32(EBIU_DDRBRC6);
+       D32(EBIU_DDRBRC7);
+       D32(EBIU_DDRBWC0);
+       D32(EBIU_DDRBWC1);
+       D32(EBIU_DDRBWC2);
+       D32(EBIU_DDRBWC3);
+       D32(EBIU_DDRBWC4);
+       D32(EBIU_DDRBWC5);
+       D32(EBIU_DDRBWC6);
+       D32(EBIU_DDRBWC7);
+       D32(EBIU_DDRCTL0);
+       D32(EBIU_DDRCTL1);
+       D32(EBIU_DDRCTL2);
+       D32(EBIU_DDRCTL3);
+       D32(EBIU_DDRGC0);
+       D32(EBIU_DDRGC1);
+       D32(EBIU_DDRGC2);
+       D32(EBIU_DDRGC3);
+       D32(EBIU_DDRMCCL);
+       D32(EBIU_DDRMCEN);
+       D32(EBIU_DDRQUE);
+       D32(EBIU_DDRTACT);
+       D32(EBIU_ERRADD);
+       D16(EBIU_ERRMST);
+       D16(EBIU_RSTCTL);
+#endif
+
+#ifdef EMAC_ADDRHI
+       parent = debugfs_create_dir("emac", top);
+       D32(EMAC_ADDRHI);
+       D32(EMAC_ADDRLO);
+       D32(EMAC_FLC);
+       D32(EMAC_HASHHI);
+       D32(EMAC_HASHLO);
+       D32(EMAC_MMC_CTL);
+       D32(EMAC_MMC_RIRQE);
+       D32(EMAC_MMC_RIRQS);
+       D32(EMAC_MMC_TIRQE);
+       D32(EMAC_MMC_TIRQS);
+       D32(EMAC_OPMODE);
+       D32(EMAC_RXC_ALIGN);
+       D32(EMAC_RXC_ALLFRM);
+       D32(EMAC_RXC_ALLOCT);
+       D32(EMAC_RXC_BROAD);
+       D32(EMAC_RXC_DMAOVF);
+       D32(EMAC_RXC_EQ64);
+       D32(EMAC_RXC_FCS);
+       D32(EMAC_RXC_GE1024);
+       D32(EMAC_RXC_LNERRI);
+       D32(EMAC_RXC_LNERRO);
+       D32(EMAC_RXC_LONG);
+       D32(EMAC_RXC_LT1024);
+       D32(EMAC_RXC_LT128);
+       D32(EMAC_RXC_LT256);
+       D32(EMAC_RXC_LT512);
+       D32(EMAC_RXC_MACCTL);
+       D32(EMAC_RXC_MULTI);
+       D32(EMAC_RXC_OCTET);
+       D32(EMAC_RXC_OK);
+       D32(EMAC_RXC_OPCODE);
+       D32(EMAC_RXC_PAUSE);
+       D32(EMAC_RXC_SHORT);
+       D32(EMAC_RXC_TYPED);
+       D32(EMAC_RXC_UNICST);
+       D32(EMAC_RX_IRQE);
+       D32(EMAC_RX_STAT);
+       D32(EMAC_RX_STKY);
+       D32(EMAC_STAADD);
+       D32(EMAC_STADAT);
+       D32(EMAC_SYSCTL);
+       D32(EMAC_SYSTAT);
+       D32(EMAC_TXC_1COL);
+       D32(EMAC_TXC_ABORT);
+       D32(EMAC_TXC_ALLFRM);
+       D32(EMAC_TXC_ALLOCT);
+       D32(EMAC_TXC_BROAD);
+       D32(EMAC_TXC_CRSERR);
+       D32(EMAC_TXC_DEFER);
+       D32(EMAC_TXC_DMAUND);
+       D32(EMAC_TXC_EQ64);
+       D32(EMAC_TXC_GE1024);
+       D32(EMAC_TXC_GT1COL);
+       D32(EMAC_TXC_LATECL);
+       D32(EMAC_TXC_LT1024);
+       D32(EMAC_TXC_LT128);
+       D32(EMAC_TXC_LT256);
+       D32(EMAC_TXC_LT512);
+       D32(EMAC_TXC_MACCTL);
+       D32(EMAC_TXC_MULTI);
+       D32(EMAC_TXC_OCTET);
+       D32(EMAC_TXC_OK);
+       D32(EMAC_TXC_UNICST);
+       D32(EMAC_TXC_XS_COL);
+       D32(EMAC_TXC_XS_DFR);
+       D32(EMAC_TX_IRQE);
+       D32(EMAC_TX_STAT);
+       D32(EMAC_TX_STKY);
+       D32(EMAC_VLAN1);
+       D32(EMAC_VLAN2);
+       D32(EMAC_WKUP_CTL);
+       D32(EMAC_WKUP_FFCMD);
+       D32(EMAC_WKUP_FFCRC0);
+       D32(EMAC_WKUP_FFCRC1);
+       D32(EMAC_WKUP_FFMSK0);
+       D32(EMAC_WKUP_FFMSK1);
+       D32(EMAC_WKUP_FFMSK2);
+       D32(EMAC_WKUP_FFMSK3);
+       D32(EMAC_WKUP_FFOFF);
+# ifdef EMAC_PTP_ACCR
+       D32(EMAC_PTP_ACCR);
+       D32(EMAC_PTP_ADDEND);
+       D32(EMAC_PTP_ALARMHI);
+       D32(EMAC_PTP_ALARMLO);
+       D16(EMAC_PTP_CTL);
+       D32(EMAC_PTP_FOFF);
+       D32(EMAC_PTP_FV1);
+       D32(EMAC_PTP_FV2);
+       D32(EMAC_PTP_FV3);
+       D16(EMAC_PTP_ID_OFF);
+       D32(EMAC_PTP_ID_SNAP);
+       D16(EMAC_PTP_IE);
+       D16(EMAC_PTP_ISTAT);
+       D32(EMAC_PTP_OFFSET);
+       D32(EMAC_PTP_PPS_PERIOD);
+       D32(EMAC_PTP_PPS_STARTHI);
+       D32(EMAC_PTP_PPS_STARTLO);
+       D32(EMAC_PTP_RXSNAPHI);
+       D32(EMAC_PTP_RXSNAPLO);
+       D32(EMAC_PTP_TIMEHI);
+       D32(EMAC_PTP_TIMELO);
+       D32(EMAC_PTP_TXSNAPHI);
+       D32(EMAC_PTP_TXSNAPLO);
+# endif
+#endif
+
+#if defined(EPPI0_STATUS) || defined(EPPI1_STATUS) || defined(EPPI2_STATUS)
+       parent = debugfs_create_dir("eppi", top);
+# ifdef EPPI0_STATUS
+       EPPI(0);
+# endif
+# ifdef EPPI1_STATUS
+       EPPI(1);
+# endif
+# ifdef EPPI2_STATUS
+       EPPI(2);
+# endif
+#endif
+
+       parent = debugfs_create_dir("gptimer", top);
+#ifdef TIMER_DISABLE
+       D16(TIMER_DISABLE);
+       D16(TIMER_ENABLE);
+       D32(TIMER_STATUS);
+#endif
+#ifdef TIMER_DISABLE0
+       D16(TIMER_DISABLE0);
+       D16(TIMER_ENABLE0);
+       D32(TIMER_STATUS0);
+#endif
+#ifdef TIMER_DISABLE1
+       D16(TIMER_DISABLE1);
+       D16(TIMER_ENABLE1);
+       D32(TIMER_STATUS1);
+#endif
+       /* XXX: Should convert BF561 MMR names */
+#ifdef TMRS4_DISABLE
+       D16(TMRS4_DISABLE);
+       D16(TMRS4_ENABLE);
+       D32(TMRS4_STATUS);
+       D16(TMRS8_DISABLE);
+       D16(TMRS8_ENABLE);
+       D32(TMRS8_STATUS);
+#endif
+       GPTIMER(0);
+       GPTIMER(1);
+       GPTIMER(2);
+#ifdef TIMER3_CONFIG
+       GPTIMER(3);
+       GPTIMER(4);
+       GPTIMER(5);
+       GPTIMER(6);
+       GPTIMER(7);
+#endif
+#ifdef TIMER8_CONFIG
+       GPTIMER(8);
+       GPTIMER(9);
+       GPTIMER(10);
+#endif
+#ifdef TIMER11_CONFIG
+       GPTIMER(11);
+#endif
+
+#ifdef HMDMA0_CONTROL
+       parent = debugfs_create_dir("hmdma", top);
+       HMDMA(0);
+       HMDMA(1);
+#endif
+
+#ifdef HOST_CONTROL
+       parent = debugfs_create_dir("hostdp", top);
+       D16(HOST_CONTROL);
+       D16(HOST_STATUS);
+       D16(HOST_TIMEOUT);
+#endif
+
+#ifdef IMDMA_S0_CONFIG
+       parent = debugfs_create_dir("imdma", top);
+       IMDMA(0);
+       IMDMA(1);
+#endif
+
+#ifdef KPAD_CTL
+       parent = debugfs_create_dir("keypad", top);
+       D16(KPAD_CTL);
+       D16(KPAD_PRESCALE);
+       D16(KPAD_MSEL);
+       D16(KPAD_ROWCOL);
+       D16(KPAD_STAT);
+       D16(KPAD_SOFTEVAL);
+#endif
+
+       parent = debugfs_create_dir("mdma", top);
+       MDMA(0);
+       MDMA(1);
+#ifdef MDMA_D2_CONFIG
+       MDMA(2);
+       MDMA(3);
+#endif
+
+#ifdef MXVR_CONFIG
+       parent = debugfs_create_dir("mxvr", top);
+       D16(MXVR_CONFIG);
+# ifdef MXVR_PLL_CTL_0
+       D32(MXVR_PLL_CTL_0);
+# endif
+       D32(MXVR_STATE_0);
+       D32(MXVR_STATE_1);
+       D32(MXVR_INT_STAT_0);
+       D32(MXVR_INT_STAT_1);
+       D32(MXVR_INT_EN_0);
+       D32(MXVR_INT_EN_1);
+       D16(MXVR_POSITION);
+       D16(MXVR_MAX_POSITION);
+       D16(MXVR_DELAY);
+       D16(MXVR_MAX_DELAY);
+       D32(MXVR_LADDR);
+       D16(MXVR_GADDR);
+       D32(MXVR_AADDR);
+       D32(MXVR_ALLOC_0);
+       D32(MXVR_ALLOC_1);
+       D32(MXVR_ALLOC_2);
+       D32(MXVR_ALLOC_3);
+       D32(MXVR_ALLOC_4);
+       D32(MXVR_ALLOC_5);
+       D32(MXVR_ALLOC_6);
+       D32(MXVR_ALLOC_7);
+       D32(MXVR_ALLOC_8);
+       D32(MXVR_ALLOC_9);
+       D32(MXVR_ALLOC_10);
+       D32(MXVR_ALLOC_11);
+       D32(MXVR_ALLOC_12);
+       D32(MXVR_ALLOC_13);
+       D32(MXVR_ALLOC_14);
+       D32(MXVR_SYNC_LCHAN_0);
+       D32(MXVR_SYNC_LCHAN_1);
+       D32(MXVR_SYNC_LCHAN_2);
+       D32(MXVR_SYNC_LCHAN_3);
+       D32(MXVR_SYNC_LCHAN_4);
+       D32(MXVR_SYNC_LCHAN_5);
+       D32(MXVR_SYNC_LCHAN_6);
+       D32(MXVR_SYNC_LCHAN_7);
+       D32(MXVR_DMA0_CONFIG);
+       D32(MXVR_DMA0_START_ADDR);
+       D16(MXVR_DMA0_COUNT);
+       D32(MXVR_DMA0_CURR_ADDR);
+       D16(MXVR_DMA0_CURR_COUNT);
+       D32(MXVR_DMA1_CONFIG);
+       D32(MXVR_DMA1_START_ADDR);
+       D16(MXVR_DMA1_COUNT);
+       D32(MXVR_DMA1_CURR_ADDR);
+       D16(MXVR_DMA1_CURR_COUNT);
+       D32(MXVR_DMA2_CONFIG);
+       D32(MXVR_DMA2_START_ADDR);
+       D16(MXVR_DMA2_COUNT);
+       D32(MXVR_DMA2_CURR_ADDR);
+       D16(MXVR_DMA2_CURR_COUNT);
+       D32(MXVR_DMA3_CONFIG);
+       D32(MXVR_DMA3_START_ADDR);
+       D16(MXVR_DMA3_COUNT);
+       D32(MXVR_DMA3_CURR_ADDR);
+       D16(MXVR_DMA3_CURR_COUNT);
+       D32(MXVR_DMA4_CONFIG);
+       D32(MXVR_DMA4_START_ADDR);
+       D16(MXVR_DMA4_COUNT);
+       D32(MXVR_DMA4_CURR_ADDR);
+       D16(MXVR_DMA4_CURR_COUNT);
+       D32(MXVR_DMA5_CONFIG);
+       D32(MXVR_DMA5_START_ADDR);
+       D16(MXVR_DMA5_COUNT);
+       D32(MXVR_DMA5_CURR_ADDR);
+       D16(MXVR_DMA5_CURR_COUNT);
+       D32(MXVR_DMA6_CONFIG);
+       D32(MXVR_DMA6_START_ADDR);
+       D16(MXVR_DMA6_COUNT);
+       D32(MXVR_DMA6_CURR_ADDR);
+       D16(MXVR_DMA6_CURR_COUNT);
+       D32(MXVR_DMA7_CONFIG);
+       D32(MXVR_DMA7_START_ADDR);
+       D16(MXVR_DMA7_COUNT);
+       D32(MXVR_DMA7_CURR_ADDR);
+       D16(MXVR_DMA7_CURR_COUNT);
+       D16(MXVR_AP_CTL);
+       D32(MXVR_APRB_START_ADDR);
+       D32(MXVR_APRB_CURR_ADDR);
+       D32(MXVR_APTB_START_ADDR);
+       D32(MXVR_APTB_CURR_ADDR);
+       D32(MXVR_CM_CTL);
+       D32(MXVR_CMRB_START_ADDR);
+       D32(MXVR_CMRB_CURR_ADDR);
+       D32(MXVR_CMTB_START_ADDR);
+       D32(MXVR_CMTB_CURR_ADDR);
+       D32(MXVR_RRDB_START_ADDR);
+       D32(MXVR_RRDB_CURR_ADDR);
+       D32(MXVR_PAT_DATA_0);
+       D32(MXVR_PAT_EN_0);
+       D32(MXVR_PAT_DATA_1);
+       D32(MXVR_PAT_EN_1);
+       D16(MXVR_FRAME_CNT_0);
+       D16(MXVR_FRAME_CNT_1);
+       D32(MXVR_ROUTING_0);
+       D32(MXVR_ROUTING_1);
+       D32(MXVR_ROUTING_2);
+       D32(MXVR_ROUTING_3);
+       D32(MXVR_ROUTING_4);
+       D32(MXVR_ROUTING_5);
+       D32(MXVR_ROUTING_6);
+       D32(MXVR_ROUTING_7);
+       D32(MXVR_ROUTING_8);
+       D32(MXVR_ROUTING_9);
+       D32(MXVR_ROUTING_10);
+       D32(MXVR_ROUTING_11);
+       D32(MXVR_ROUTING_12);
+       D32(MXVR_ROUTING_13);
+       D32(MXVR_ROUTING_14);
+# ifdef MXVR_PLL_CTL_1
+       D32(MXVR_PLL_CTL_1);
+# endif
+       D16(MXVR_BLOCK_CNT);
+# ifdef MXVR_CLK_CTL
+       D32(MXVR_CLK_CTL);
+# endif
+# ifdef MXVR_CDRPLL_CTL
+       D32(MXVR_CDRPLL_CTL);
+# endif
+# ifdef MXVR_FMPLL_CTL
+       D32(MXVR_FMPLL_CTL);
+# endif
+# ifdef MXVR_PIN_CTL
+       D16(MXVR_PIN_CTL);
+# endif
+# ifdef MXVR_SCLK_CNT
+       D16(MXVR_SCLK_CNT);
+# endif
+#endif
+
+#ifdef NFC_ADDR
+       parent = debugfs_create_dir("nfc", top);
+       D_WO(NFC_ADDR, 16);
+       D_WO(NFC_CMD, 16);
+       D_RO(NFC_COUNT, 16);
+       D16(NFC_CTL);
+       D_WO(NFC_DATA_RD, 16);
+       D_WO(NFC_DATA_WR, 16);
+       D_RO(NFC_ECC0, 16);
+       D_RO(NFC_ECC1, 16);
+       D_RO(NFC_ECC2, 16);
+       D_RO(NFC_ECC3, 16);
+       D16(NFC_IRQMASK);
+       D16(NFC_IRQSTAT);
+       D_WO(NFC_PGCTL, 16);
+       D_RO(NFC_READ, 16);
+       D16(NFC_RST);
+       D_RO(NFC_STAT, 16);
+#endif
+
+#ifdef OTP_CONTROL
+       parent = debugfs_create_dir("otp", top);
+       D16(OTP_CONTROL);
+       D16(OTP_BEN);
+       D16(OTP_STATUS);
+       D32(OTP_TIMING);
+       D32(OTP_DATA0);
+       D32(OTP_DATA1);
+       D32(OTP_DATA2);
+       D32(OTP_DATA3);
+#endif
+
+#ifdef PIXC_CTL
+       parent = debugfs_create_dir("pixc", top);
+       D16(PIXC_CTL);
+       D16(PIXC_PPL);
+       D16(PIXC_LPF);
+       D16(PIXC_AHSTART);
+       D16(PIXC_AHEND);
+       D16(PIXC_AVSTART);
+       D16(PIXC_AVEND);
+       D16(PIXC_ATRANSP);
+       D16(PIXC_BHSTART);
+       D16(PIXC_BHEND);
+       D16(PIXC_BVSTART);
+       D16(PIXC_BVEND);
+       D16(PIXC_BTRANSP);
+       D16(PIXC_INTRSTAT);
+       D32(PIXC_RYCON);
+       D32(PIXC_GUCON);
+       D32(PIXC_BVCON);
+       D32(PIXC_CCBIAS);
+       D32(PIXC_TC);
+#endif
+
+       parent = debugfs_create_dir("pll", top);
+       D16(PLL_CTL);
+       D16(PLL_DIV);
+       D16(PLL_LOCKCNT);
+       D16(PLL_STAT);
+       D16(VR_CTL);
+       D32(CHIPID);    /* it's part of this hardware block */
+
+#if defined(PPI_CONTROL) || defined(PPI0_CONTROL) || defined(PPI1_CONTROL)
+       parent = debugfs_create_dir("ppi", top);
+# ifdef PPI_CONTROL
+       bfin_debug_mmrs_ppi(parent, PPI_CONTROL, -1);
+# endif
+# ifdef PPI0_CONTROL
+       PPI(0);
+# endif
+# ifdef PPI1_CONTROL
+       PPI(1);
+# endif
+#endif
+
+#ifdef PWM_CTRL
+       parent = debugfs_create_dir("pwm", top);
+       D16(PWM_CTRL);
+       D16(PWM_STAT);
+       D16(PWM_TM);
+       D16(PWM_DT);
+       D16(PWM_GATE);
+       D16(PWM_CHA);
+       D16(PWM_CHB);
+       D16(PWM_CHC);
+       D16(PWM_SEG);
+       D16(PWM_SYNCWT);
+       D16(PWM_CHAL);
+       D16(PWM_CHBL);
+       D16(PWM_CHCL);
+       D16(PWM_LSI);
+       D16(PWM_STAT2);
+#endif
+
+#ifdef RSI_CONFIG
+       parent = debugfs_create_dir("rsi", top);
+       D32(RSI_ARGUMENT);
+       D16(RSI_CEATA_CONTROL);
+       D16(RSI_CLK_CONTROL);
+       D16(RSI_COMMAND);
+       D16(RSI_CONFIG);
+       D16(RSI_DATA_CNT);
+       D16(RSI_DATA_CONTROL);
+       D16(RSI_DATA_LGTH);
+       D32(RSI_DATA_TIMER);
+       D16(RSI_EMASK);
+       D16(RSI_ESTAT);
+       D32(RSI_FIFO);
+       D16(RSI_FIFO_CNT);
+       D32(RSI_MASK0);
+       D32(RSI_MASK1);
+       D16(RSI_PID0);
+       D16(RSI_PID1);
+       D16(RSI_PID2);
+       D16(RSI_PID3);
+       D16(RSI_PID4);
+       D16(RSI_PID5);
+       D16(RSI_PID6);
+       D16(RSI_PID7);
+       D16(RSI_PWR_CONTROL);
+       D16(RSI_RD_WAIT_EN);
+       D32(RSI_RESPONSE0);
+       D32(RSI_RESPONSE1);
+       D32(RSI_RESPONSE2);
+       D32(RSI_RESPONSE3);
+       D16(RSI_RESP_CMD);
+       D32(RSI_STATUS);
+       D_WO(RSI_STATUSCL, 16);
+#endif
+
+#ifdef RTC_ALARM
+       parent = debugfs_create_dir("rtc", top);
+       D32(RTC_ALARM);
+       D16(RTC_ICTL);
+       D16(RTC_ISTAT);
+       D16(RTC_PREN);
+       D32(RTC_STAT);
+       D16(RTC_SWCNT);
+#endif
+
+#ifdef SDH_CFG
+       parent = debugfs_create_dir("sdh", top);
+       D32(SDH_ARGUMENT);
+       D16(SDH_CFG);
+       D16(SDH_CLK_CTL);
+       D16(SDH_COMMAND);
+       D_RO(SDH_DATA_CNT, 16);
+       D16(SDH_DATA_CTL);
+       D16(SDH_DATA_LGTH);
+       D32(SDH_DATA_TIMER);
+       D16(SDH_E_MASK);
+       D16(SDH_E_STATUS);
+       D32(SDH_FIFO);
+       D_RO(SDH_FIFO_CNT, 16);
+       D32(SDH_MASK0);
+       D32(SDH_MASK1);
+       D_RO(SDH_PID0, 16);
+       D_RO(SDH_PID1, 16);
+       D_RO(SDH_PID2, 16);
+       D_RO(SDH_PID3, 16);
+       D_RO(SDH_PID4, 16);
+       D_RO(SDH_PID5, 16);
+       D_RO(SDH_PID6, 16);
+       D_RO(SDH_PID7, 16);
+       D16(SDH_PWR_CTL);
+       D16(SDH_RD_WAIT_EN);
+       D_RO(SDH_RESPONSE0, 32);
+       D_RO(SDH_RESPONSE1, 32);
+       D_RO(SDH_RESPONSE2, 32);
+       D_RO(SDH_RESPONSE3, 32);
+       D_RO(SDH_RESP_CMD, 16);
+       D_RO(SDH_STATUS, 32);
+       D_WO(SDH_STATUS_CLR, 16);
+#endif
+
+#ifdef SECURE_CONTROL
+       parent = debugfs_create_dir("security", top);
+       D16(SECURE_CONTROL);
+       D16(SECURE_STATUS);
+       D32(SECURE_SYSSWT);
+#endif
+
+       parent = debugfs_create_dir("sic", top);
+       D16(SWRST);
+       D16(SYSCR);
+       D16(SIC_RVECT);
+       D32(SIC_IAR0);
+       D32(SIC_IAR1);
+       D32(SIC_IAR2);
+#ifdef SIC_IAR3
+       D32(SIC_IAR3);
+#endif
+#ifdef SIC_IAR4
+       D32(SIC_IAR4);
+       D32(SIC_IAR5);
+       D32(SIC_IAR6);
+#endif
+#ifdef SIC_IAR7
+       D32(SIC_IAR7);
+#endif
+#ifdef SIC_IAR8
+       D32(SIC_IAR8);
+       D32(SIC_IAR9);
+       D32(SIC_IAR10);
+       D32(SIC_IAR11);
+#endif
+#ifdef SIC_IMASK
+       D32(SIC_IMASK);
+       D32(SIC_ISR);
+       D32(SIC_IWR);
+#endif
+#ifdef SIC_IMASK0
+       D32(SIC_IMASK0);
+       D32(SIC_IMASK1);
+       D32(SIC_ISR0);
+       D32(SIC_ISR1);
+       D32(SIC_IWR0);
+       D32(SIC_IWR1);
+#endif
+#ifdef SIC_IMASK2
+       D32(SIC_IMASK2);
+       D32(SIC_ISR2);
+       D32(SIC_IWR2);
+#endif
+#ifdef SICB_RVECT
+       D16(SICB_SWRST);
+       D16(SICB_SYSCR);
+       D16(SICB_RVECT);
+       D32(SICB_IAR0);
+       D32(SICB_IAR1);
+       D32(SICB_IAR2);
+       D32(SICB_IAR3);
+       D32(SICB_IAR4);
+       D32(SICB_IAR5);
+       D32(SICB_IAR6);
+       D32(SICB_IAR7);
+       D32(SICB_IMASK0);
+       D32(SICB_IMASK1);
+       D32(SICB_ISR0);
+       D32(SICB_ISR1);
+       D32(SICB_IWR0);
+       D32(SICB_IWR1);
+#endif
+
+       parent = debugfs_create_dir("spi", top);
+#ifdef SPI0_REGBASE
+       SPI(0);
+#endif
+#ifdef SPI1_REGBASE
+       SPI(1);
+#endif
+#ifdef SPI2_REGBASE
+       SPI(2);
+#endif
+
+       parent = debugfs_create_dir("sport", top);
+#ifdef SPORT0_STAT
+       SPORT(0);
+#endif
+#ifdef SPORT1_STAT
+       SPORT(1);
+#endif
+#ifdef SPORT2_STAT
+       SPORT(2);
+#endif
+#ifdef SPORT3_STAT
+       SPORT(3);
+#endif
+
+#if defined(TWI_CLKDIV) || defined(TWI0_CLKDIV) || defined(TWI1_CLKDIV)
+       parent = debugfs_create_dir("twi", top);
+# ifdef TWI_CLKDIV
+       bfin_debug_mmrs_twi(parent, TWI_CLKDIV, -1);
+# endif
+# ifdef TWI0_CLKDIV
+       TWI(0);
+# endif
+# ifdef TWI1_CLKDIV
+       TWI(1);
+# endif
+#endif
+
+       parent = debugfs_create_dir("uart", top);
+#ifdef BFIN_UART_DLL
+       bfin_debug_mmrs_uart(parent, BFIN_UART_DLL, -1);
+#endif
+#ifdef UART0_DLL
+       UART(0);
+#endif
+#ifdef UART1_DLL
+       UART(1);
+#endif
+#ifdef UART2_DLL
+       UART(2);
+#endif
+#ifdef UART3_DLL
+       UART(3);
+#endif
+
+#ifdef USB_FADDR
+       parent = debugfs_create_dir("usb", top);
+       D16(USB_FADDR);
+       D16(USB_POWER);
+       D16(USB_INTRTX);
+       D16(USB_INTRRX);
+       D16(USB_INTRTXE);
+       D16(USB_INTRRXE);
+       D16(USB_INTRUSB);
+       D16(USB_INTRUSBE);
+       D16(USB_FRAME);
+       D16(USB_INDEX);
+       D16(USB_TESTMODE);
+       D16(USB_GLOBINTR);
+       D16(USB_GLOBAL_CTL);
+       D16(USB_TX_MAX_PACKET);
+       D16(USB_CSR0);
+       D16(USB_TXCSR);
+       D16(USB_RX_MAX_PACKET);
+       D16(USB_RXCSR);
+       D16(USB_COUNT0);
+       D16(USB_RXCOUNT);
+       D16(USB_TXTYPE);
+       D16(USB_NAKLIMIT0);
+       D16(USB_TXINTERVAL);
+       D16(USB_RXTYPE);
+       D16(USB_RXINTERVAL);
+       D16(USB_TXCOUNT);
+       D16(USB_EP0_FIFO);
+       D16(USB_EP1_FIFO);
+       D16(USB_EP2_FIFO);
+       D16(USB_EP3_FIFO);
+       D16(USB_EP4_FIFO);
+       D16(USB_EP5_FIFO);
+       D16(USB_EP6_FIFO);
+       D16(USB_EP7_FIFO);
+       D16(USB_OTG_DEV_CTL);
+       D16(USB_OTG_VBUS_IRQ);
+       D16(USB_OTG_VBUS_MASK);
+       D16(USB_LINKINFO);
+       D16(USB_VPLEN);
+       D16(USB_HS_EOF1);
+       D16(USB_FS_EOF1);
+       D16(USB_LS_EOF1);
+       D16(USB_APHY_CNTRL);
+       D16(USB_APHY_CALIB);
+       D16(USB_APHY_CNTRL2);
+       D16(USB_PHY_TEST);
+       D16(USB_PLLOSC_CTRL);
+       D16(USB_SRP_CLKDIV);
+       D16(USB_EP_NI0_TXMAXP);
+       D16(USB_EP_NI0_TXCSR);
+       D16(USB_EP_NI0_RXMAXP);
+       D16(USB_EP_NI0_RXCSR);
+       D16(USB_EP_NI0_RXCOUNT);
+       D16(USB_EP_NI0_TXTYPE);
+       D16(USB_EP_NI0_TXINTERVAL);
+       D16(USB_EP_NI0_RXTYPE);
+       D16(USB_EP_NI0_RXINTERVAL);
+       D16(USB_EP_NI0_TXCOUNT);
+       D16(USB_EP_NI1_TXMAXP);
+       D16(USB_EP_NI1_TXCSR);
+       D16(USB_EP_NI1_RXMAXP);
+       D16(USB_EP_NI1_RXCSR);
+       D16(USB_EP_NI1_RXCOUNT);
+       D16(USB_EP_NI1_TXTYPE);
+       D16(USB_EP_NI1_TXINTERVAL);
+       D16(USB_EP_NI1_RXTYPE);
+       D16(USB_EP_NI1_RXINTERVAL);
+       D16(USB_EP_NI1_TXCOUNT);
+       D16(USB_EP_NI2_TXMAXP);
+       D16(USB_EP_NI2_TXCSR);
+       D16(USB_EP_NI2_RXMAXP);
+       D16(USB_EP_NI2_RXCSR);
+       D16(USB_EP_NI2_RXCOUNT);
+       D16(USB_EP_NI2_TXTYPE);
+       D16(USB_EP_NI2_TXINTERVAL);
+       D16(USB_EP_NI2_RXTYPE);
+       D16(USB_EP_NI2_RXINTERVAL);
+       D16(USB_EP_NI2_TXCOUNT);
+       D16(USB_EP_NI3_TXMAXP);
+       D16(USB_EP_NI3_TXCSR);
+       D16(USB_EP_NI3_RXMAXP);
+       D16(USB_EP_NI3_RXCSR);
+       D16(USB_EP_NI3_RXCOUNT);
+       D16(USB_EP_NI3_TXTYPE);
+       D16(USB_EP_NI3_TXINTERVAL);
+       D16(USB_EP_NI3_RXTYPE);
+       D16(USB_EP_NI3_RXINTERVAL);
+       D16(USB_EP_NI3_TXCOUNT);
+       D16(USB_EP_NI4_TXMAXP);
+       D16(USB_EP_NI4_TXCSR);
+       D16(USB_EP_NI4_RXMAXP);
+       D16(USB_EP_NI4_RXCSR);
+       D16(USB_EP_NI4_RXCOUNT);
+       D16(USB_EP_NI4_TXTYPE);
+       D16(USB_EP_NI4_TXINTERVAL);
+       D16(USB_EP_NI4_RXTYPE);
+       D16(USB_EP_NI4_RXINTERVAL);
+       D16(USB_EP_NI4_TXCOUNT);
+       D16(USB_EP_NI5_TXMAXP);
+       D16(USB_EP_NI5_TXCSR);
+       D16(USB_EP_NI5_RXMAXP);
+       D16(USB_EP_NI5_RXCSR);
+       D16(USB_EP_NI5_RXCOUNT);
+       D16(USB_EP_NI5_TXTYPE);
+       D16(USB_EP_NI5_TXINTERVAL);
+       D16(USB_EP_NI5_RXTYPE);
+       D16(USB_EP_NI5_RXINTERVAL);
+       D16(USB_EP_NI5_TXCOUNT);
+       D16(USB_EP_NI6_TXMAXP);
+       D16(USB_EP_NI6_TXCSR);
+       D16(USB_EP_NI6_RXMAXP);
+       D16(USB_EP_NI6_RXCSR);
+       D16(USB_EP_NI6_RXCOUNT);
+       D16(USB_EP_NI6_TXTYPE);
+       D16(USB_EP_NI6_TXINTERVAL);
+       D16(USB_EP_NI6_RXTYPE);
+       D16(USB_EP_NI6_RXINTERVAL);
+       D16(USB_EP_NI6_TXCOUNT);
+       D16(USB_EP_NI7_TXMAXP);
+       D16(USB_EP_NI7_TXCSR);
+       D16(USB_EP_NI7_RXMAXP);
+       D16(USB_EP_NI7_RXCSR);
+       D16(USB_EP_NI7_RXCOUNT);
+       D16(USB_EP_NI7_TXTYPE);
+       D16(USB_EP_NI7_TXINTERVAL);
+       D16(USB_EP_NI7_RXTYPE);
+       D16(USB_EP_NI7_RXINTERVAL);
+       D16(USB_EP_NI7_TXCOUNT);
+       D16(USB_DMA_INTERRUPT);
+       D16(USB_DMA0CONTROL);
+       D16(USB_DMA0ADDRLOW);
+       D16(USB_DMA0ADDRHIGH);
+       D16(USB_DMA0COUNTLOW);
+       D16(USB_DMA0COUNTHIGH);
+       D16(USB_DMA1CONTROL);
+       D16(USB_DMA1ADDRLOW);
+       D16(USB_DMA1ADDRHIGH);
+       D16(USB_DMA1COUNTLOW);
+       D16(USB_DMA1COUNTHIGH);
+       D16(USB_DMA2CONTROL);
+       D16(USB_DMA2ADDRLOW);
+       D16(USB_DMA2ADDRHIGH);
+       D16(USB_DMA2COUNTLOW);
+       D16(USB_DMA2COUNTHIGH);
+       D16(USB_DMA3CONTROL);
+       D16(USB_DMA3ADDRLOW);
+       D16(USB_DMA3ADDRHIGH);
+       D16(USB_DMA3COUNTLOW);
+       D16(USB_DMA3COUNTHIGH);
+       D16(USB_DMA4CONTROL);
+       D16(USB_DMA4ADDRLOW);
+       D16(USB_DMA4ADDRHIGH);
+       D16(USB_DMA4COUNTLOW);
+       D16(USB_DMA4COUNTHIGH);
+       D16(USB_DMA5CONTROL);
+       D16(USB_DMA5ADDRLOW);
+       D16(USB_DMA5ADDRHIGH);
+       D16(USB_DMA5COUNTLOW);
+       D16(USB_DMA5COUNTHIGH);
+       D16(USB_DMA6CONTROL);
+       D16(USB_DMA6ADDRLOW);
+       D16(USB_DMA6ADDRHIGH);
+       D16(USB_DMA6COUNTLOW);
+       D16(USB_DMA6COUNTHIGH);
+       D16(USB_DMA7CONTROL);
+       D16(USB_DMA7ADDRLOW);
+       D16(USB_DMA7ADDRHIGH);
+       D16(USB_DMA7COUNTLOW);
+       D16(USB_DMA7COUNTHIGH);
+#endif
+
+#ifdef WDOG_CNT
+       parent = debugfs_create_dir("watchdog", top);
+       D32(WDOG_CNT);
+       D16(WDOG_CTL);
+       D32(WDOG_STAT);
+#endif
+#ifdef WDOGA_CNT
+       parent = debugfs_create_dir("watchdog", top);
+       D32(WDOGA_CNT);
+       D16(WDOGA_CTL);
+       D32(WDOGA_STAT);
+       D32(WDOGB_CNT);
+       D16(WDOGB_CTL);
+       D32(WDOGB_STAT);
+#endif
+
+       /* BF533 glue */
+#ifdef FIO_FLAG_D
+#define PORTFIO FIO_FLAG_D
+#endif
+       /* BF561 glue */
+#ifdef FIO0_FLAG_D
+#define PORTFIO FIO0_FLAG_D
+#endif
+#ifdef FIO1_FLAG_D
+#define PORTGIO FIO1_FLAG_D
+#endif
+#ifdef FIO2_FLAG_D
+#define PORTHIO FIO2_FLAG_D
+#endif
+       parent = debugfs_create_dir("port", top);
+#ifdef PORTFIO
+       PORT(PORTFIO, 'F');
+#endif
+#ifdef PORTGIO
+       PORT(PORTGIO, 'G');
+#endif
+#ifdef PORTHIO
+       PORT(PORTHIO, 'H');
+#endif
+
+#ifdef __ADSPBF51x__
+       D16(PORTF_FER);
+       D16(PORTF_DRIVE);
+       D16(PORTF_HYSTERESIS);
+       D16(PORTF_MUX);
+
+       D16(PORTG_FER);
+       D16(PORTG_DRIVE);
+       D16(PORTG_HYSTERESIS);
+       D16(PORTG_MUX);
+
+       D16(PORTH_FER);
+       D16(PORTH_DRIVE);
+       D16(PORTH_HYSTERESIS);
+       D16(PORTH_MUX);
+
+       D16(MISCPORT_DRIVE);
+       D16(MISCPORT_HYSTERESIS);
+#endif /* BF51x */
+
+#ifdef __ADSPBF52x__
+       D16(PORTF_FER);
+       D16(PORTF_DRIVE);
+       D16(PORTF_HYSTERESIS);
+       D16(PORTF_MUX);
+       D16(PORTF_SLEW);
+
+       D16(PORTG_FER);
+       D16(PORTG_DRIVE);
+       D16(PORTG_HYSTERESIS);
+       D16(PORTG_MUX);
+       D16(PORTG_SLEW);
+
+       D16(PORTH_FER);
+       D16(PORTH_DRIVE);
+       D16(PORTH_HYSTERESIS);
+       D16(PORTH_MUX);
+       D16(PORTH_SLEW);
+
+       D16(MISCPORT_DRIVE);
+       D16(MISCPORT_HYSTERESIS);
+       D16(MISCPORT_SLEW);
+#endif /* BF52x */
+
+#ifdef BF537_FAMILY
+       D16(PORTF_FER);
+       D16(PORTG_FER);
+       D16(PORTH_FER);
+       D16(PORT_MUX);
+#endif /* BF534 BF536 BF537 */
+
+#ifdef BF538_FAMILY
+       D16(PORTCIO_FER);
+       D16(PORTCIO);
+       D16(PORTCIO_CLEAR);
+       D16(PORTCIO_SET);
+       D16(PORTCIO_TOGGLE);
+       D16(PORTCIO_DIR);
+       D16(PORTCIO_INEN);
+
+       D16(PORTDIO);
+       D16(PORTDIO_CLEAR);
+       D16(PORTDIO_DIR);
+       D16(PORTDIO_FER);
+       D16(PORTDIO_INEN);
+       D16(PORTDIO_SET);
+       D16(PORTDIO_TOGGLE);
+
+       D16(PORTEIO);
+       D16(PORTEIO_CLEAR);
+       D16(PORTEIO_DIR);
+       D16(PORTEIO_FER);
+       D16(PORTEIO_INEN);
+       D16(PORTEIO_SET);
+       D16(PORTEIO_TOGGLE);
+#endif /* BF538 BF539 */
+
+#ifdef __ADSPBF54x__
+       {
+               int num;
+               unsigned long base;
+               char *_buf, buf[32];
+
+               base = PORTA_FER;
+               for (num = 0; num < 10; ++num) {
+                       PORT(base, num);
+                       base += sizeof(struct bfin_gpio_regs);
+               }
+
+#define __PINT(uname, lname) __REGS(pint, #uname, lname)
+               parent = debugfs_create_dir("pint", top);
+               base = PINT0_MASK_SET;
+               for (num = 0; num < 4; ++num) {
+                       _buf = REGS_STR_PFX(buf, PINT, num);
+                       __PINT(MASK_SET, mask_set);
+                       __PINT(MASK_CLEAR, mask_clear);
+                       __PINT(IRQ, irq);
+                       __PINT(ASSIGN, assign);
+                       __PINT(EDGE_SET, edge_set);
+                       __PINT(EDGE_CLEAR, edge_clear);
+                       __PINT(INVERT_SET, invert_set);
+                       __PINT(INVERT_CLEAR, invert_clear);
+                       __PINT(PINSTATE, pinstate);
+                       __PINT(LATCH, latch);
+                       base += sizeof(struct bfin_pint_regs);
+               }
+
+       }
+#endif /* BF54x */
+
+       debug_mmrs_dentry = top;
+
+       return 0;
+}
+module_init(bfin_debug_mmrs_init);
+
+static void __exit bfin_debug_mmrs_exit(void)
+{
+       debugfs_remove_recursive(debug_mmrs_dentry);
+}
+module_exit(bfin_debug_mmrs_exit);
+
+MODULE_LICENSE("GPL");
index f37019c847c9b643c04676d0a2423f870286f16c..486426f8a0d79c203d591569e298b33e7040bfdb 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/io.h>
 #include <asm/system.h>
 #include <asm/atomic.h>
+#include <asm/irq_handler.h>
 
 DEFINE_PER_CPU(struct pt_regs, __ipipe_tick_regs);
 
index 1696d34f51c2ab369e54b2b319da1c2663e74358..ff3d747154ac6ecb5f97fb8027f8f7dfcb587988 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kallsyms.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <asm/irq_handler.h>
 #include <asm/trace.h>
 #include <asm/pda.h>
 
index 401eb1d8e3b43be33a2d6fb653d9e26fa754ae2c..679d0db352564584bc2a699adfee03c04c4a4d07 100644 (file)
@@ -145,16 +145,16 @@ int check_nmi_wdt_touched(void)
 {
        unsigned int this_cpu = smp_processor_id();
        unsigned int cpu;
+       cpumask_t mask;
 
-       cpumask_t mask = cpu_online_map;
-
+       cpumask_copy(&mask, cpu_online_mask);
        if (!atomic_read(&nmi_touched[this_cpu]))
                return 0;
 
        atomic_set(&nmi_touched[this_cpu], 0);
 
-       cpu_clear(this_cpu, mask);
-       for_each_cpu_mask(cpu, mask) {
+       cpumask_clear_cpu(this_cpu, &mask);
+       for_each_cpu(cpu, &mask) {
                invalidate_dcache_range((unsigned long)(&nmi_touched[cpu]),
                                (unsigned long)(&nmi_touched[cpu]));
                if (!atomic_read(&nmi_touched[cpu]))
diff --git a/arch/blackfin/kernel/perf_event.c b/arch/blackfin/kernel/perf_event.c
new file mode 100644 (file)
index 0000000..04300f2
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * Blackfin performance counters
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Ripped from SuperH version:
+ *
+ *  Copyright (C) 2009  Paul Mundt
+ *
+ * Heavily based on the x86 and PowerPC implementations.
+ *
+ * x86:
+ *  Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
+ *  Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
+ *  Copyright (C) 2009 Jaswinder Singh Rajput
+ *  Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
+ *  Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
+ *
+ * ppc:
+ *  Copyright 2008-2009 Paul Mackerras, IBM Corporation.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/perf_event.h>
+#include <asm/bfin_pfmon.h>
+
+/*
+ * We have two counters, and each counter can support an event type.
+ * The 'o' is PFCNTx=1 and 's' is PFCNTx=0
+ *
+ * 0x04 o pc invariant branches
+ * 0x06 o mispredicted branches
+ * 0x09 o predicted branches taken
+ * 0x0B o EXCPT insn
+ * 0x0C o CSYNC/SSYNC insn
+ * 0x0D o Insns committed
+ * 0x0E o Interrupts taken
+ * 0x0F o Misaligned address exceptions
+ * 0x80 o Code memory fetches stalled due to DMA
+ * 0x83 o 64bit insn fetches delivered
+ * 0x9A o data cache fills (bank a)
+ * 0x9B o data cache fills (bank b)
+ * 0x9C o data cache lines evicted (bank a)
+ * 0x9D o data cache lines evicted (bank b)
+ * 0x9E o data cache high priority fills
+ * 0x9F o data cache low priority fills
+ * 0x00 s loop 0 iterations
+ * 0x01 s loop 1 iterations
+ * 0x0A s CSYNC/SSYNC stalls
+ * 0x10 s DAG read/after write hazards
+ * 0x13 s RAW data hazards
+ * 0x81 s code TAG stalls
+ * 0x82 s code fill stalls
+ * 0x90 s processor to memory stalls
+ * 0x91 s data memory stalls not hidden by 0x90
+ * 0x92 s data store buffer full stalls
+ * 0x93 s data memory write buffer full stalls due to high->low priority
+ * 0x95 s data memory fill buffer stalls
+ * 0x96 s data TAG collision stalls
+ * 0x97 s data collision stalls
+ * 0x98 s data stalls
+ * 0x99 s data stalls sent to processor
+ */
+
+static const int event_map[] = {
+       /* use CYCLES cpu register */
+       [PERF_COUNT_HW_CPU_CYCLES]          = -1,
+       [PERF_COUNT_HW_INSTRUCTIONS]        = 0x0D,
+       [PERF_COUNT_HW_CACHE_REFERENCES]    = -1,
+       [PERF_COUNT_HW_CACHE_MISSES]        = 0x83,
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x09,
+       [PERF_COUNT_HW_BRANCH_MISSES]       = 0x06,
+       [PERF_COUNT_HW_BUS_CYCLES]          = -1,
+};
+
+#define C(x)   PERF_COUNT_HW_CACHE_##x
+
+static const int cache_events[PERF_COUNT_HW_CACHE_MAX]
+                             [PERF_COUNT_HW_CACHE_OP_MAX]
+                             [PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+       [C(L1D)] = {    /* Data bank A */
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = 0,
+                       [C(RESULT_MISS)  ] = 0x9A,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = 0,
+                       [C(RESULT_MISS)  ] = 0,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = 0,
+                       [C(RESULT_MISS)  ] = 0,
+               },
+       },
+
+       [C(L1I)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = 0,
+                       [C(RESULT_MISS)  ] = 0x83,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = 0,
+                       [C(RESULT_MISS)  ] = 0,
+               },
+       },
+
+       [C(LL)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+       },
+
+       [C(DTLB)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+       },
+
+       [C(ITLB)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+       },
+
+       [C(BPU)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+       },
+};
+
+const char *perf_pmu_name(void)
+{
+       return "bfin";
+}
+EXPORT_SYMBOL(perf_pmu_name);
+
+int perf_num_counters(void)
+{
+       return ARRAY_SIZE(event_map);
+}
+EXPORT_SYMBOL(perf_num_counters);
+
+static u64 bfin_pfmon_read(int idx)
+{
+       return bfin_read32(PFCNTR0 + (idx * 4));
+}
+
+static void bfin_pfmon_disable(struct hw_perf_event *hwc, int idx)
+{
+       bfin_write_PFCTL(bfin_read_PFCTL() & ~PFCEN(idx, PFCEN_MASK));
+}
+
+static void bfin_pfmon_enable(struct hw_perf_event *hwc, int idx)
+{
+       u32 val, mask;
+
+       val = PFPWR;
+       if (idx) {
+               mask = ~(PFCNT1 | PFMON1 | PFCEN1 | PEMUSW1);
+               /* The packed config is for event0, so shift it to event1 slots */
+               val |= (hwc->config << (PFMON1_P - PFMON0_P));
+               val |= (hwc->config & PFCNT0) << (PFCNT1_P - PFCNT0_P);
+               bfin_write_PFCNTR1(0);
+       } else {
+               mask = ~(PFCNT0 | PFMON0 | PFCEN0 | PEMUSW0);
+               val |= hwc->config;
+               bfin_write_PFCNTR0(0);
+       }
+
+       bfin_write_PFCTL((bfin_read_PFCTL() & mask) | val);
+}
+
+static void bfin_pfmon_disable_all(void)
+{
+       bfin_write_PFCTL(bfin_read_PFCTL() & ~PFPWR);
+}
+
+static void bfin_pfmon_enable_all(void)
+{
+       bfin_write_PFCTL(bfin_read_PFCTL() | PFPWR);
+}
+
+struct cpu_hw_events {
+       struct perf_event *events[MAX_HWEVENTS];
+       unsigned long used_mask[BITS_TO_LONGS(MAX_HWEVENTS)];
+};
+DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
+
+static int hw_perf_cache_event(int config, int *evp)
+{
+       unsigned long type, op, result;
+       int ev;
+
+       /* unpack config */
+       type = config & 0xff;
+       op = (config >> 8) & 0xff;
+       result = (config >> 16) & 0xff;
+
+       if (type >= PERF_COUNT_HW_CACHE_MAX ||
+           op >= PERF_COUNT_HW_CACHE_OP_MAX ||
+           result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+               return -EINVAL;
+
+       ev = cache_events[type][op][result];
+       if (ev == 0)
+               return -EOPNOTSUPP;
+       if (ev == -1)
+               return -EINVAL;
+       *evp = ev;
+       return 0;
+}
+
+static void bfin_perf_event_update(struct perf_event *event,
+                                  struct hw_perf_event *hwc, int idx)
+{
+       u64 prev_raw_count, new_raw_count;
+       s64 delta;
+       int shift = 0;
+
+       /*
+        * Depending on the counter configuration, they may or may not
+        * be chained, in which case the previous counter value can be
+        * updated underneath us if the lower-half overflows.
+        *
+        * Our tactic to handle this is to first atomically read and
+        * exchange a new raw count - then add that new-prev delta
+        * count to the generic counter atomically.
+        *
+        * As there is no interrupt associated with the overflow events,
+        * this is the simplest approach for maintaining consistency.
+        */
+again:
+       prev_raw_count = local64_read(&hwc->prev_count);
+       new_raw_count = bfin_pfmon_read(idx);
+
+       if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+                            new_raw_count) != prev_raw_count)
+               goto again;
+
+       /*
+        * Now we have the new raw value and have updated the prev
+        * timestamp already. We can now calculate the elapsed delta
+        * (counter-)time and add that to the generic counter.
+        *
+        * Careful, not all hw sign-extends above the physical width
+        * of the count.
+        */
+       delta = (new_raw_count << shift) - (prev_raw_count << shift);
+       delta >>= shift;
+
+       local64_add(delta, &event->count);
+}
+
+static void bfin_pmu_stop(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+       int idx = hwc->idx;
+
+       if (!(event->hw.state & PERF_HES_STOPPED)) {
+               bfin_pfmon_disable(hwc, idx);
+               cpuc->events[idx] = NULL;
+               event->hw.state |= PERF_HES_STOPPED;
+       }
+
+       if ((flags & PERF_EF_UPDATE) && !(event->hw.state & PERF_HES_UPTODATE)) {
+               bfin_perf_event_update(event, &event->hw, idx);
+               event->hw.state |= PERF_HES_UPTODATE;
+       }
+}
+
+static void bfin_pmu_start(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+       int idx = hwc->idx;
+
+       if (WARN_ON_ONCE(idx == -1))
+               return;
+
+       if (flags & PERF_EF_RELOAD)
+               WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+
+       cpuc->events[idx] = event;
+       event->hw.state = 0;
+       bfin_pfmon_enable(hwc, idx);
+}
+
+static void bfin_pmu_del(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+
+       bfin_pmu_stop(event, PERF_EF_UPDATE);
+       __clear_bit(event->hw.idx, cpuc->used_mask);
+
+       perf_event_update_userpage(event);
+}
+
+static int bfin_pmu_add(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+       int idx = hwc->idx;
+       int ret = -EAGAIN;
+
+       perf_pmu_disable(event->pmu);
+
+       if (__test_and_set_bit(idx, cpuc->used_mask)) {
+               idx = find_first_zero_bit(cpuc->used_mask, MAX_HWEVENTS);
+               if (idx == MAX_HWEVENTS)
+                       goto out;
+
+               __set_bit(idx, cpuc->used_mask);
+               hwc->idx = idx;
+       }
+
+       bfin_pfmon_disable(hwc, idx);
+
+       event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+       if (flags & PERF_EF_START)
+               bfin_pmu_start(event, PERF_EF_RELOAD);
+
+       perf_event_update_userpage(event);
+       ret = 0;
+out:
+       perf_pmu_enable(event->pmu);
+       return ret;
+}
+
+static void bfin_pmu_read(struct perf_event *event)
+{
+       bfin_perf_event_update(event, &event->hw, event->hw.idx);
+}
+
+static int bfin_pmu_event_init(struct perf_event *event)
+{
+       struct perf_event_attr *attr = &event->attr;
+       struct hw_perf_event *hwc = &event->hw;
+       int config = -1;
+       int ret;
+
+       if (attr->exclude_hv || attr->exclude_idle)
+               return -EPERM;
+
+       /*
+        * All of the on-chip counters are "limited", in that they have
+        * no interrupts, and are therefore unable to do sampling without
+        * further work and timer assistance.
+        */
+       if (hwc->sample_period)
+               return -EINVAL;
+
+       ret = 0;
+       switch (attr->type) {
+       case PERF_TYPE_RAW:
+               config = PFMON(0, attr->config & PFMON_MASK) |
+                       PFCNT(0, !(attr->config & 0x100));
+               break;
+       case PERF_TYPE_HW_CACHE:
+               ret = hw_perf_cache_event(attr->config, &config);
+               break;
+       case PERF_TYPE_HARDWARE:
+               if (attr->config >= ARRAY_SIZE(event_map))
+                       return -EINVAL;
+
+               config = event_map[attr->config];
+               break;
+       }
+
+       if (config == -1)
+               return -EINVAL;
+
+       if (!attr->exclude_kernel)
+               config |= PFCEN(0, PFCEN_ENABLE_SUPV);
+       if (!attr->exclude_user)
+               config |= PFCEN(0, PFCEN_ENABLE_USER);
+
+       hwc->config |= config;
+
+       return ret;
+}
+
+static void bfin_pmu_enable(struct pmu *pmu)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct perf_event *event;
+       struct hw_perf_event *hwc;
+       int i;
+
+       for (i = 0; i < MAX_HWEVENTS; ++i) {
+               event = cpuc->events[i];
+               if (!event)
+                       continue;
+               hwc = &event->hw;
+               bfin_pfmon_enable(hwc, hwc->idx);
+       }
+
+       bfin_pfmon_enable_all();
+}
+
+static void bfin_pmu_disable(struct pmu *pmu)
+{
+       bfin_pfmon_disable_all();
+}
+
+static struct pmu pmu = {
+       .pmu_enable  = bfin_pmu_enable,
+       .pmu_disable = bfin_pmu_disable,
+       .event_init  = bfin_pmu_event_init,
+       .add         = bfin_pmu_add,
+       .del         = bfin_pmu_del,
+       .start       = bfin_pmu_start,
+       .stop        = bfin_pmu_stop,
+       .read        = bfin_pmu_read,
+};
+
+static void bfin_pmu_setup(int cpu)
+{
+       struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
+
+       memset(cpuhw, 0, sizeof(struct cpu_hw_events));
+}
+
+static int __cpuinit
+bfin_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
+{
+       unsigned int cpu = (long)hcpu;
+
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_UP_PREPARE:
+               bfin_write_PFCTL(0);
+               bfin_pmu_setup(cpu);
+               break;
+
+       default:
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+static int __init bfin_pmu_init(void)
+{
+       int ret;
+
+       ret = perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
+       if (!ret)
+               perf_cpu_notifier(bfin_pmu_notifier);
+
+       return ret;
+}
+early_initcall(bfin_pmu_init);
index b407bc8ad9186f05fee0f657ffec48e7aab87efe..6a660fa921b59aba0c22d0ece7747ec5abcf0eca 100644 (file)
@@ -171,10 +171,8 @@ asmlinkage int bfin_clone(struct pt_regs *regs)
        unsigned long newsp;
 
 #ifdef __ARCH_SYNC_CORE_DCACHE
-       if (current->rt.nr_cpus_allowed == num_possible_cpus()) {
-               current->cpus_allowed = cpumask_of_cpu(smp_processor_id());
-               current->rt.nr_cpus_allowed = 1;
-       }
+       if (current->rt.nr_cpus_allowed == num_possible_cpus())
+               set_cpus_allowed_ptr(current, cpumask_of(smp_processor_id()));
 #endif
 
        /* syscall2 puts clone_flags in r0 and usp in r1 */
index 53d08dee8531b1ba588fcef55a97b288a89c0054..488bdc51aaa5fd9efa71bc4e6e75dba45fc1521d 100644 (file)
@@ -23,6 +23,9 @@
 __attribute__ ((__l1_text__, __noreturn__))
 static void bfin_reset(void)
 {
+       if (!ANOMALY_05000353 && !ANOMALY_05000386)
+               bfrom_SoftReset((void *)(L1_SCRATCH_START + L1_SCRATCH_LENGTH - 20));
+
        /* Wait for completion of "system" events such as cache line
         * line fills so that we avoid infinite stalls later on as
         * much as possible.  This code is in L1, so it won't trigger
@@ -30,46 +33,40 @@ static void bfin_reset(void)
         */
        __builtin_bfin_ssync();
 
-       /* The bootrom checks to see how it was reset and will
-        * automatically perform a software reset for us when
-        * it starts executing after the core reset.
-        */
-       if (ANOMALY_05000353 || ANOMALY_05000386) {
-               /* Initiate System software reset. */
-               bfin_write_SWRST(0x7);
+       /* Initiate System software reset. */
+       bfin_write_SWRST(0x7);
 
-               /* Due to the way reset is handled in the hardware, we need
-                * to delay for 10 SCLKS.  The only reliable way to do this is
-                * to calculate the CCLK/SCLK ratio and multiply 10.  For now,
-                * we'll assume worse case which is a 1:15 ratio.
-                */
-               asm(
-                       "LSETUP (1f, 1f) LC0 = %0\n"
-                       "1: nop;"
-                       :
-                       : "a" (15 * 10)
-                       : "LC0", "LB0", "LT0"
-               );
+       /* Due to the way reset is handled in the hardware, we need
+        * to delay for 10 SCLKS.  The only reliable way to do this is
+        * to calculate the CCLK/SCLK ratio and multiply 10.  For now,
+        * we'll assume worse case which is a 1:15 ratio.
+        */
+       asm(
+               "LSETUP (1f, 1f) LC0 = %0\n"
+               "1: nop;"
+               :
+               : "a" (15 * 10)
+               : "LC0", "LB0", "LT0"
+       );
 
-               /* Clear System software reset */
-               bfin_write_SWRST(0);
+       /* Clear System software reset */
+       bfin_write_SWRST(0);
 
-               /* The BF526 ROM will crash during reset */
+       /* The BF526 ROM will crash during reset */
 #if defined(__ADSPBF522__) || defined(__ADSPBF524__) || defined(__ADSPBF526__)
-               bfin_read_SWRST();
+       bfin_read_SWRST();
 #endif
 
-               /* Wait for the SWRST write to complete.  Cannot rely on SSYNC
-                * though as the System state is all reset now.
-                */
-               asm(
-                       "LSETUP (1f, 1f) LC1 = %0\n"
-                       "1: nop;"
-                       :
-                       : "a" (15 * 1)
-                       : "LC1", "LB1", "LT1"
-               );
-       }
+       /* Wait for the SWRST write to complete.  Cannot rely on SSYNC
+        * though as the System state is all reset now.
+        */
+       asm(
+               "LSETUP (1f, 1f) LC1 = %0\n"
+               "1: nop;"
+               :
+               : "a" (15 * 1)
+               : "LC1", "LB1", "LT1"
+       );
 
        while (1)
                /* Issue core reset */
index 805c6132c7796b26a632c85df14b8a58d508e1de..536bd9d7e0cfb80392e3ed43b8ac8f6fb106fce0 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/cpu.h>
 #include <asm/fixed_code.h>
 #include <asm/early_printk.h>
+#include <asm/irq_handler.h>
 
 u16 _bfin_swrst;
 EXPORT_SYMBOL(_bfin_swrst);
@@ -105,6 +106,8 @@ void __cpuinit bfin_setup_caches(unsigned int cpu)
        bfin_dcache_init(dcplb_tbl[cpu]);
 #endif
 
+       bfin_setup_cpudata(cpu);
+
        /*
         * In cache coherence emulation mode, we need to have the
         * D-cache enabled before running any atomic operation which
@@ -163,7 +166,6 @@ void __cpuinit bfin_setup_cpudata(unsigned int cpu)
 {
        struct blackfin_cpudata *cpudata = &per_cpu(cpu_data, cpu);
 
-       cpudata->idle = current;
        cpudata->imemctl = bfin_read_IMEM_CONTROL();
        cpudata->dmemctl = bfin_read_DMEM_CONTROL();
 }
@@ -851,6 +853,7 @@ void __init native_machine_early_platform_add_devices(void)
 
 void __init setup_arch(char **cmdline_p)
 {
+       u32 mmr;
        unsigned long sclk, cclk;
 
        native_machine_early_platform_add_devices();
@@ -902,10 +905,10 @@ void __init setup_arch(char **cmdline_p)
        bfin_write_EBIU_FCTL(CONFIG_EBIU_FCTLVAL);
 #endif
 #ifdef CONFIG_BFIN_HYSTERESIS_CONTROL
-       bfin_write_PORTF_HYSTERISIS(HYST_PORTF_0_15);
-       bfin_write_PORTG_HYSTERISIS(HYST_PORTG_0_15);
-       bfin_write_PORTH_HYSTERISIS(HYST_PORTH_0_15);
-       bfin_write_MISCPORT_HYSTERISIS((bfin_read_MISCPORT_HYSTERISIS() &
+       bfin_write_PORTF_HYSTERESIS(HYST_PORTF_0_15);
+       bfin_write_PORTG_HYSTERESIS(HYST_PORTG_0_15);
+       bfin_write_PORTH_HYSTERESIS(HYST_PORTH_0_15);
+       bfin_write_MISCPORT_HYSTERESIS((bfin_read_MISCPORT_HYSTERESIS() &
                                        ~HYST_NONEGPIO_MASK) | HYST_NONEGPIO);
 #endif
 
@@ -921,17 +924,14 @@ void __init setup_arch(char **cmdline_p)
                bfin_read_IMDMA_D1_IRQ_STATUS();
        }
 #endif
-       printk(KERN_INFO "Hardware Trace ");
-       if (bfin_read_TBUFCTL() & 0x1)
-               printk(KERN_CONT "Active ");
-       else
-               printk(KERN_CONT "Off ");
-       if (bfin_read_TBUFCTL() & 0x2)
-               printk(KERN_CONT "and Enabled\n");
-       else
-               printk(KERN_CONT "and Disabled\n");
 
-       printk(KERN_INFO "Boot Mode: %i\n", bfin_read_SYSCR() & 0xF);
+       mmr = bfin_read_TBUFCTL();
+       printk(KERN_INFO "Hardware Trace %s and %sabled\n",
+               (mmr & 0x1) ? "active" : "off",
+               (mmr & 0x2) ? "en" : "dis");
+
+       mmr = bfin_read_SYSCR();
+       printk(KERN_INFO "Boot Mode: %i\n", mmr & 0xF);
 
        /* Newer parts mirror SWRST bits in SYSCR */
 #if defined(CONFIG_BF53x) || defined(CONFIG_BF561) || \
@@ -939,7 +939,7 @@ void __init setup_arch(char **cmdline_p)
        _bfin_swrst = bfin_read_SWRST();
 #else
        /* Clear boot mode field */
-       _bfin_swrst = bfin_read_SYSCR() & ~0xf;
+       _bfin_swrst = mmr & ~0xf;
 #endif
 
 #ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
@@ -1036,8 +1036,6 @@ void __init setup_arch(char **cmdline_p)
 static int __init topology_init(void)
 {
        unsigned int cpu;
-       /* Record CPU-private information for the boot processor. */
-       bfin_setup_cpudata(0);
 
        for_each_possible_cpu(cpu) {
                register_cpu(&per_cpu(cpu_data, cpu).cpu, cpu);
@@ -1283,12 +1281,14 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                   dsup_banks, BFIN_DSUBBANKS, BFIN_DWAYS,
                   BFIN_DLINES);
 #ifdef __ARCH_SYNC_CORE_DCACHE
-       seq_printf(m, "SMP Dcache Flushes\t: %lu\n\n", dcache_invld_count[cpu_num]);
+       seq_printf(m, "dcache flushes\t: %lu\n", dcache_invld_count[cpu_num]);
 #endif
 #ifdef __ARCH_SYNC_CORE_ICACHE
-       seq_printf(m, "SMP Icache Flushes\t: %lu\n\n", icache_invld_count[cpu_num]);
+       seq_printf(m, "icache flushes\t: %lu\n", icache_invld_count[cpu_num]);
 #endif
 
+       seq_printf(m, "\n");
+
        if (cpu_num != num_possible_cpus() - 1)
                return 0;
 
@@ -1312,13 +1312,11 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                              " in data cache\n");
        }
        seq_printf(m, "board name\t: %s\n", bfin_board_name);
-       seq_printf(m, "board memory\t: %ld kB (0x%p -> 0x%p)\n",
-                physical_mem_end >> 10, (void *)0, (void *)physical_mem_end);
-       seq_printf(m, "kernel memory\t: %d kB (0x%p -> 0x%p)\n",
+       seq_printf(m, "board memory\t: %ld kB (0x%08lx -> 0x%08lx)\n",
+               physical_mem_end >> 10, 0ul, physical_mem_end);
+       seq_printf(m, "kernel memory\t: %d kB (0x%08lx -> 0x%08lx)\n",
                ((int)memory_end - (int)_rambase) >> 10,
-               (void *)_rambase,
-               (void *)memory_end);
-       seq_printf(m, "\n");
+               _rambase, memory_end);
 
        return 0;
 }
@@ -1326,7 +1324,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
 static void *c_start(struct seq_file *m, loff_t *pos)
 {
        if (*pos == 0)
-               *pos = first_cpu(cpu_online_map);
+               *pos = cpumask_first(cpu_online_mask);
        if (*pos >= num_online_cpus())
                return NULL;
 
@@ -1335,7 +1333,7 @@ static void *c_start(struct seq_file *m, loff_t *pos)
 
 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
 {
-       *pos = next_cpu(*pos, cpu_online_map);
+       *pos = cpumask_next(*pos, cpu_online_mask);
 
        return c_start(m, pos);
 }
index 854fa49f1c3ec964f7f105fd9c0019d133cca420..3ac5b66d14aa72de5234801dbcc47e61c3a5f67d 100644 (file)
@@ -136,7 +136,7 @@ SECTIONS
 
        . = ALIGN(16);
        INIT_DATA_SECTION(16)
-       PERCPU(32, PAGE_SIZE)
+       PERCPU_SECTION(32)
 
        .exit.data :
        {
@@ -155,14 +155,8 @@ SECTIONS
                SECURITY_INITCALL
                INIT_RAM_FS
 
-               . = ALIGN(4);
                ___per_cpu_load = .;
-               ___per_cpu_start = .;
-               *(.data.percpu.first)
-               *(.data.percpu.page_aligned)
-               *(.data.percpu)
-               *(.data.percpu.shared_aligned)
-               ___per_cpu_end = .;
+               PERCPU_INPUT(32)
 
                EXIT_DATA
                __einitdata = .;
index f3931d50b4a715a50878363a43bd14e9c63b9dd1..2c07dddac9956bd24da0603910c9a7d35957f42b 100644 (file)
@@ -25,7 +25,7 @@
 
 ENTRY(_strncpy)
        CC = R2 == 0;
-       if CC JUMP 4f;
+       if CC JUMP 6f;
 
        P2 = R2 ;       /* size */
        P0 = R0 ;       /* dst*/
index 24918c5f7ea1d9c30379c3a219c90830f87ec763..d2f076fbbc9ee001d4cf1310f1a61559c560145e 100644 (file)
@@ -5,7 +5,7 @@
  * and can be replaced with that version at any time
  * DO NOT EDIT THIS FILE
  *
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
  * Licensed under the ADI BSD license.
  *   https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
  */
 #define ANOMALY_05000364 (0)
 #define ANOMALY_05000371 (0)
 #define ANOMALY_05000380 (0)
+#define ANOMALY_05000383 (0)
 #define ANOMALY_05000386 (0)
 #define ANOMALY_05000389 (0)
 #define ANOMALY_05000400 (0)
 #define ANOMALY_05000467 (0)
 #define ANOMALY_05000474 (0)
 #define ANOMALY_05000475 (0)
+#define ANOMALY_05000480 (0)
 #define ANOMALY_05000485 (0)
 
 #endif
diff --git a/arch/blackfin/mach-bf518/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf518/include/mach/bfin_serial_5xx.h
deleted file mode 100644 (file)
index f6d924a..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2008-2009 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later
- */
-
-#include <asm/dma.h>
-#include <asm/portmux.h>
-
-#if defined(CONFIG_BFIN_UART0_CTSRTS) || defined(CONFIG_BFIN_UART1_CTSRTS)
-# define CONFIG_SERIAL_BFIN_CTSRTS
-
-# ifndef CONFIG_UART0_CTS_PIN
-#  define CONFIG_UART0_CTS_PIN -1
-# endif
-
-# ifndef CONFIG_UART0_RTS_PIN
-#  define CONFIG_UART0_RTS_PIN -1
-# endif
-
-# ifndef CONFIG_UART1_CTS_PIN
-#  define CONFIG_UART1_CTS_PIN -1
-# endif
-
-# ifndef CONFIG_UART1_RTS_PIN
-#  define CONFIG_UART1_RTS_PIN -1
-# endif
-#endif
-
-struct bfin_serial_res {
-       unsigned long uart_base_addr;
-       int uart_irq;
-       int uart_status_irq;
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       unsigned int uart_tx_dma_channel;
-       unsigned int uart_rx_dma_channel;
-#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       int uart_cts_pin;
-       int uart_rts_pin;
-#endif
-};
-
-struct bfin_serial_res bfin_serial_resource[] = {
-#ifdef CONFIG_SERIAL_BFIN_UART0
-       {
-        0xFFC00400,
-        IRQ_UART0_RX,
-        IRQ_UART0_ERROR,
-#ifdef CONFIG_SERIAL_BFIN_DMA
-        CH_UART0_TX,
-        CH_UART0_RX,
-#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-        CONFIG_UART0_CTS_PIN,
-        CONFIG_UART0_RTS_PIN,
-#endif
-        },
-#endif
-#ifdef CONFIG_SERIAL_BFIN_UART1
-       {
-        0xFFC02000,
-        IRQ_UART1_RX,
-        IRQ_UART1_ERROR,
-#ifdef CONFIG_SERIAL_BFIN_DMA
-        CH_UART1_TX,
-        CH_UART1_RX,
-#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-        CONFIG_UART1_CTS_PIN,
-        CONFIG_UART1_RTS_PIN,
-#endif
-        },
-#endif
-};
-
-#define DRIVER_NAME "bfin-uart"
-
-#include <asm/bfin_serial.h>
index b657d37a3402d094b3191c5a1e4bba1a0f65a6c7..bb79627f0929532ec763516063007b45907498b9 100644 (file)
 #define bfin_write_PORTG_SLEW(val)             bfin_write16(PORTG_SLEW, val)
 #define bfin_read_PORTH_SLEW()                 bfin_read16(PORTH_SLEW)
 #define bfin_write_PORTH_SLEW(val)             bfin_write16(PORTH_SLEW, val)
-#define bfin_read_PORTF_HYSTERISIS()           bfin_read16(PORTF_HYSTERISIS)
-#define bfin_write_PORTF_HYSTERISIS(val)       bfin_write16(PORTF_HYSTERISIS, val)
-#define bfin_read_PORTG_HYSTERISIS()           bfin_read16(PORTG_HYSTERISIS)
-#define bfin_write_PORTG_HYSTERISIS(val)       bfin_write16(PORTG_HYSTERISIS, val)
-#define bfin_read_PORTH_HYSTERISIS()           bfin_read16(PORTH_HYSTERISIS)
-#define bfin_write_PORTH_HYSTERISIS(val)       bfin_write16(PORTH_HYSTERISIS, val)
+#define bfin_read_PORTF_HYSTERESIS()           bfin_read16(PORTF_HYSTERESIS)
+#define bfin_write_PORTF_HYSTERESIS(val)       bfin_write16(PORTF_HYSTERESIS, val)
+#define bfin_read_PORTG_HYSTERESIS()           bfin_read16(PORTG_HYSTERESIS)
+#define bfin_write_PORTG_HYSTERESIS(val)       bfin_write16(PORTG_HYSTERESIS, val)
+#define bfin_read_PORTH_HYSTERESIS()           bfin_read16(PORTH_HYSTERESIS)
+#define bfin_write_PORTH_HYSTERESIS(val)       bfin_write16(PORTH_HYSTERESIS, val)
 #define bfin_read_MISCPORT_DRIVE()             bfin_read16(MISCPORT_DRIVE)
 #define bfin_write_MISCPORT_DRIVE(val)         bfin_write16(MISCPORT_DRIVE, val)
 #define bfin_read_MISCPORT_SLEW()              bfin_read16(MISCPORT_SLEW)
 #define bfin_write_MISCPORT_SLEW(val)          bfin_write16(MISCPORT_SLEW, val)
-#define bfin_read_MISCPORT_HYSTERISIS()                bfin_read16(MISCPORT_HYSTERISIS)
-#define bfin_write_MISCPORT_HYSTERISIS(val)    bfin_write16(MISCPORT_HYSTERISIS, val)
+#define bfin_read_MISCPORT_HYSTERESIS()                bfin_read16(MISCPORT_HYSTERESIS)
+#define bfin_write_MISCPORT_HYSTERESIS(val)    bfin_write16(MISCPORT_HYSTERESIS, val)
 
 /* HOST Port Registers */
 
index cb1172f5075729994a12c27680b881fba226cffe..729704078cd720350c1d9388cd4e69bd07cdc536 100644 (file)
 #define PORTF_SLEW              0xFFC03230      /* Port F slew control */
 #define PORTG_SLEW              0xFFC03234      /* Port G slew control */
 #define PORTH_SLEW              0xFFC03238      /* Port H slew control */
-#define PORTF_HYSTERISIS        0xFFC03240      /* Port F Schmitt trigger control */
-#define PORTG_HYSTERISIS        0xFFC03244      /* Port G Schmitt trigger control */
-#define PORTH_HYSTERISIS        0xFFC03248      /* Port H Schmitt trigger control */
+#define PORTF_HYSTERESIS        0xFFC03240      /* Port F Schmitt trigger control */
+#define PORTG_HYSTERESIS        0xFFC03244      /* Port G Schmitt trigger control */
+#define PORTH_HYSTERESIS        0xFFC03248      /* Port H Schmitt trigger control */
 #define MISCPORT_DRIVE          0xFFC03280      /* Misc Port drive strength control */
 #define MISCPORT_SLEW           0xFFC03284      /* Misc Port slew control */
-#define MISCPORT_HYSTERISIS     0xFFC03288      /* Misc Port Schmitt trigger control */
+#define MISCPORT_HYSTERESIS     0xFFC03288      /* Misc Port Schmitt trigger control */
 
 
 /***********************************************************************************
index 98a51c479290dae44812cf2dd325be875bd561e3..cfab428e577cc6ac10c6e48835199ee3b20c8fd2 100644 (file)
 #define RSI_EMASK                      0xFFC038C4 /* RSI Exception Mask Register */
 #define RSI_CONFIG                     0xFFC038C8 /* RSI Configuration Register */
 #define RSI_RD_WAIT_EN                 0xFFC038CC /* RSI Read Wait Enable Register */
-#define RSI_PID0                       0xFFC03FE0 /* RSI Peripheral ID Register 0 */
-#define RSI_PID1                       0xFFC03FE4 /* RSI Peripheral ID Register 1 */
-#define RSI_PID2                       0xFFC03FE8 /* RSI Peripheral ID Register 2 */
-#define RSI_PID3                       0xFFC03FEC /* RSI Peripheral ID Register 3 */
-#define RSI_PID4                       0xFFC03FF0 /* RSI Peripheral ID Register 4 */
-#define RSI_PID5                       0xFFC03FF4 /* RSI Peripheral ID Register 5 */
-#define RSI_PID6                       0xFFC03FF8 /* RSI Peripheral ID Register 6 */
-#define RSI_PID7                       0xFFC03FFC /* RSI Peripheral ID Register 7 */
+#define RSI_PID0                       0xFFC038D0 /* RSI Peripheral ID Register 0 */
+#define RSI_PID1                       0xFFC038D4 /* RSI Peripheral ID Register 1 */
+#define RSI_PID2                       0xFFC038D8 /* RSI Peripheral ID Register 2 */
+#define RSI_PID3                       0xFFC038DC /* RSI Peripheral ID Register 3 */
+#define RSI_PID4                       0xFFC038E0 /* RSI Peripheral ID Register 0 */
+#define RSI_PID5                       0xFFC038E4 /* RSI Peripheral ID Register 1 */
+#define RSI_PID6                       0xFFC038E8 /* RSI Peripheral ID Register 2 */
+#define RSI_PID7                       0xFFC038EC /* RSI Peripheral ID Register 3 */
 
 #endif /* _DEF_BF514_H */
index 435e76e31aaabd6c91145a1f3f6531e466841c16..edf8efd457dcb8c912448f583e2d23b2e02e0f00 100644 (file)
@@ -7,38 +7,9 @@
 #ifndef _BF518_IRQ_H_
 #define _BF518_IRQ_H_
 
-/*
- * Interrupt source definitions
-       Event Source    Core Event Name
-       Core        Emulation               **
-       Events         (highest priority)  EMU         0
-       Reset                   RST         1
-       NMI                     NMI         2
-       Exception               EVX         3
-       Reserved                --          4
-       Hardware Error          IVHW        5
-       Core Timer              IVTMR       6 *
-
-       .....
-
-        Software Interrupt 1    IVG14       31
-        Software Interrupt 2    --
-        (lowest priority)  IVG15       32 *
-*/
-
-#define NR_PERI_INTS    (2 * 32)
-
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define IRQ_EMU                        0       /* Emulation */
-#define IRQ_RST                        1       /* reset */
-#define IRQ_NMI                        2       /* Non Maskable */
-#define IRQ_EVX                        3       /* Exception */
-#define IRQ_UNUSED             4       /* - unused interrupt */
-#define IRQ_HWERR              5       /* Hardware Error */
-#define IRQ_CORETMR            6       /* Core timer */
-
-#define BFIN_IRQ(x)            ((x) + 7)
+#include <mach-common/irq.h>
+
+#define NR_PERI_INTS           (2 * 32)
 
 #define IRQ_PLL_WAKEUP         BFIN_IRQ(0)     /* PLL Wakeup Interrupt */
 #define IRQ_DMA0_ERROR         BFIN_IRQ(1)     /* DMA Error 0 (generic) */
 #define IRQ_UART0_ERROR                BFIN_IRQ(12)    /* UART0 Status */
 #define IRQ_UART1_ERROR                BFIN_IRQ(13)    /* UART1 Status */
 #define IRQ_RTC                        BFIN_IRQ(14)    /* RTC */
-#define IRQ_PPI                BFIN_IRQ(15)    /* DMA Channel 0 (PPI) */
+#define IRQ_PPI                        BFIN_IRQ(15)    /* DMA Channel 0 (PPI) */
 #define IRQ_SPORT0_RX          BFIN_IRQ(16)    /* DMA 3 Channel (SPORT0 RX) */
 #define IRQ_SPORT0_TX          BFIN_IRQ(17)    /* DMA 4 Channel (SPORT0 TX) */
 #define IRQ_RSI                        BFIN_IRQ(17)    /* DMA 4 Channel (RSI) */
 #define IRQ_SPORT1_RX          BFIN_IRQ(18)    /* DMA 5 Channel (SPORT1 RX/SPI) */
 #define IRQ_SPI1               BFIN_IRQ(18)    /* DMA 5 Channel (SPI1) */
 #define IRQ_SPORT1_TX          BFIN_IRQ(19)    /* DMA 6 Channel (SPORT1 TX) */
-#define IRQ_TWI                BFIN_IRQ(20)    /* TWI */
-#define IRQ_SPI0               BFIN_IRQ(21)    /* DMA 7 Channel (SPI0) */
-#define IRQ_UART0_RX           BFIN_IRQ(22)    /* DMA8 Channel (UART0 RX) */
-#define IRQ_UART0_TX           BFIN_IRQ(23)    /* DMA9 Channel (UART0 TX) */
-#define IRQ_UART1_RX           BFIN_IRQ(24)    /* DMA10 Channel (UART1 RX) */
-#define IRQ_UART1_TX           BFIN_IRQ(25)    /* DMA11 Channel (UART1 TX) */
-#define IRQ_OPTSEC             BFIN_IRQ(26)    /* OTPSEC Interrupt */
-#define IRQ_CNT                BFIN_IRQ(27)    /* GP Counter */
-#define IRQ_MAC_RX             BFIN_IRQ(28)    /* DMA1 Channel (MAC RX) */
-#define IRQ_PORTH_INTA         BFIN_IRQ(29)    /* Port H Interrupt A */
+#define IRQ_TWI                        BFIN_IRQ(20)    /* TWI */
+#define IRQ_SPI0               BFIN_IRQ(21)    /* DMA 7 Channel (SPI0) */
+#define IRQ_UART0_RX           BFIN_IRQ(22)    /* DMA8 Channel (UART0 RX) */
+#define IRQ_UART0_TX           BFIN_IRQ(23)    /* DMA9 Channel (UART0 TX) */
+#define IRQ_UART1_RX           BFIN_IRQ(24)    /* DMA10 Channel (UART1 RX) */
+#define IRQ_UART1_TX           BFIN_IRQ(25)    /* DMA11 Channel (UART1 TX) */
+#define IRQ_OPTSEC             BFIN_IRQ(26)    /* OTPSEC Interrupt */
+#define IRQ_CNT                        BFIN_IRQ(27)    /* GP Counter */
+#define IRQ_MAC_RX             BFIN_IRQ(28)    /* DMA1 Channel (MAC RX) */
+#define IRQ_PORTH_INTA         BFIN_IRQ(29)    /* Port H Interrupt A */
 #define IRQ_MAC_TX             BFIN_IRQ(30)    /* DMA2 Channel (MAC TX) */
 #define IRQ_PORTH_INTB         BFIN_IRQ(31)    /* Port H Interrupt B */
 #define IRQ_TIMER0             BFIN_IRQ(32)    /* Timer 0 */
 #define IRQ_PWM_SYNC           BFIN_IRQ(54)    /* PWM Sync Interrupt */
 #define IRQ_PTP_STAT           BFIN_IRQ(55)    /* PTP Stat Interrupt */
 
-#define SYS_IRQS               BFIN_IRQ(63)    /* 70 */
-
-#define IRQ_PF0         71
-#define IRQ_PF1         72
-#define IRQ_PF2         73
-#define IRQ_PF3         74
-#define IRQ_PF4         75
-#define IRQ_PF5         76
-#define IRQ_PF6         77
-#define IRQ_PF7         78
-#define IRQ_PF8         79
-#define IRQ_PF9         80
-#define IRQ_PF10        81
-#define IRQ_PF11        82
-#define IRQ_PF12        83
-#define IRQ_PF13        84
-#define IRQ_PF14        85
-#define IRQ_PF15        86
-
-#define IRQ_PG0         87
-#define IRQ_PG1         88
-#define IRQ_PG2         89
-#define IRQ_PG3         90
-#define IRQ_PG4         91
-#define IRQ_PG5         92
-#define IRQ_PG6         93
-#define IRQ_PG7         94
-#define IRQ_PG8         95
-#define IRQ_PG9         96
-#define IRQ_PG10        97
-#define IRQ_PG11        98
-#define IRQ_PG12        99
-#define IRQ_PG13        100
-#define IRQ_PG14        101
-#define IRQ_PG15        102
-
-#define IRQ_PH0         103
-#define IRQ_PH1         104
-#define IRQ_PH2         105
-#define IRQ_PH3         106
-#define IRQ_PH4         107
-#define IRQ_PH5         108
-#define IRQ_PH6         109
-#define IRQ_PH7         110
-#define IRQ_PH8         111
-#define IRQ_PH9         112
-#define IRQ_PH10        113
-#define IRQ_PH11        114
-#define IRQ_PH12        115
-#define IRQ_PH13        116
-#define IRQ_PH14        117
-#define IRQ_PH15        118
-
-#define GPIO_IRQ_BASE  IRQ_PF0
-
-#define IRQ_MAC_PHYINT         119 /* PHY_INT Interrupt */
-#define IRQ_MAC_MMCINT         120 /* MMC Counter Interrupt */
-#define IRQ_MAC_RXFSINT                121 /* RX Frame-Status Interrupt */
-#define IRQ_MAC_TXFSINT                122 /* TX Frame-Status Interrupt */
-#define IRQ_MAC_WAKEDET                123 /* Wake-Up Interrupt */
-#define IRQ_MAC_RXDMAERR       124 /* RX DMA Direction Error Interrupt */
-#define IRQ_MAC_TXDMAERR       125 /* TX DMA Direction Error Interrupt */
-#define IRQ_MAC_STMDONE                126 /* Station Mgt. Transfer Done Interrupt */
-
-#define NR_MACH_IRQS   (IRQ_MAC_STMDONE + 1)
-#define NR_IRQS                (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7            7
-#define IVG8            8
-#define IVG9            9
-#define IVG10           10
-#define IVG11           11
-#define IVG12           12
-#define IVG13           13
-#define IVG14           14
-#define IVG15           15
+#define SYS_IRQS               BFIN_IRQ(63)    /* 70 */
+
+#define IRQ_PF0                        71
+#define IRQ_PF1                        72
+#define IRQ_PF2                        73
+#define IRQ_PF3                        74
+#define IRQ_PF4                        75
+#define IRQ_PF5                        76
+#define IRQ_PF6                        77
+#define IRQ_PF7                        78
+#define IRQ_PF8                        79
+#define IRQ_PF9                        80
+#define IRQ_PF10               81
+#define IRQ_PF11               82
+#define IRQ_PF12               83
+#define IRQ_PF13               84
+#define IRQ_PF14               85
+#define IRQ_PF15               86
+
+#define IRQ_PG0                        87
+#define IRQ_PG1                        88
+#define IRQ_PG2                        89
+#define IRQ_PG3                        90
+#define IRQ_PG4                        91
+#define IRQ_PG5                        92
+#define IRQ_PG6                        93
+#define IRQ_PG7                        94
+#define IRQ_PG8                        95
+#define IRQ_PG9                        96
+#define IRQ_PG10               97
+#define IRQ_PG11               98
+#define IRQ_PG12               99
+#define IRQ_PG13               100
+#define IRQ_PG14               101
+#define IRQ_PG15               102
+
+#define IRQ_PH0                        103
+#define IRQ_PH1                        104
+#define IRQ_PH2                        105
+#define IRQ_PH3                        106
+#define IRQ_PH4                        107
+#define IRQ_PH5                        108
+#define IRQ_PH6                        109
+#define IRQ_PH7                        110
+#define IRQ_PH8                        111
+#define IRQ_PH9                        112
+#define IRQ_PH10               113
+#define IRQ_PH11               114
+#define IRQ_PH12               115
+#define IRQ_PH13               116
+#define IRQ_PH14               117
+#define IRQ_PH15               118
+
+#define GPIO_IRQ_BASE          IRQ_PF0
+
+#define IRQ_MAC_PHYINT         119     /* PHY_INT Interrupt */
+#define IRQ_MAC_MMCINT         120     /* MMC Counter Interrupt */
+#define IRQ_MAC_RXFSINT                121     /* RX Frame-Status Interrupt */
+#define IRQ_MAC_TXFSINT                122     /* TX Frame-Status Interrupt */
+#define IRQ_MAC_WAKEDET                123     /* Wake-Up Interrupt */
+#define IRQ_MAC_RXDMAERR       124     /* RX DMA Direction Error Interrupt */
+#define IRQ_MAC_TXDMAERR       125     /* TX DMA Direction Error Interrupt */
+#define IRQ_MAC_STMDONE                126     /* Station Mgt. Transfer Done Interrupt */
+
+#define NR_MACH_IRQS           (IRQ_MAC_STMDONE + 1)
 
 /* IAR0 BIT FIELDS */
 #define IRQ_PLL_WAKEUP_POS     0
 #define IRQ_DMA0_ERROR_POS     4
-#define IRQ_DMAR0_BLK_POS      8
-#define IRQ_DMAR1_BLK_POS      12
-#define IRQ_DMAR0_OVR_POS      16
-#define IRQ_DMAR1_OVR_POS      20
-#define IRQ_PPI_ERROR_POS      24
-#define IRQ_MAC_ERROR_POS      28
+#define IRQ_DMAR0_BLK_POS      8
+#define IRQ_DMAR1_BLK_POS      12
+#define IRQ_DMAR0_OVR_POS      16
+#define IRQ_DMAR1_OVR_POS      20
+#define IRQ_PPI_ERROR_POS      24
+#define IRQ_MAC_ERROR_POS      28
 
 /* IAR1 BIT FIELDS */
 #define IRQ_SPORT0_ERROR_POS   0
 #define IRQ_SPORT1_ERROR_POS   4
 #define IRQ_PTP_ERROR_POS      8
-#define IRQ_UART0_ERROR_POS    16
-#define IRQ_UART1_ERROR_POS    20
-#define IRQ_RTC_POS            24
-#define IRQ_PPI_POS            28
+#define IRQ_UART0_ERROR_POS    16
+#define IRQ_UART1_ERROR_POS    20
+#define IRQ_RTC_POS            24
+#define IRQ_PPI_POS            28
 
 /* IAR2 BIT FIELDS */
 #define IRQ_SPORT0_RX_POS      0
 #define IRQ_SPORT1_RX_POS      8
 #define IRQ_SPI1_POS           8
 #define IRQ_SPORT1_TX_POS      12
-#define IRQ_TWI_POS            16
-#define IRQ_SPI0_POS           20
-#define IRQ_UART0_RX_POS       24
-#define IRQ_UART0_TX_POS       28
+#define IRQ_TWI_POS            16
+#define IRQ_SPI0_POS           20
+#define IRQ_UART0_RX_POS       24
+#define IRQ_UART0_TX_POS       28
 
 /* IAR3 BIT FIELDS */
-#define IRQ_UART1_RX_POS       0
-#define IRQ_UART1_TX_POS       4
-#define IRQ_OPTSEC_POS         8
-#define IRQ_CNT_POS            12
-#define IRQ_MAC_RX_POS         16
+#define IRQ_UART1_RX_POS       0
+#define IRQ_UART1_TX_POS       4
+#define IRQ_OPTSEC_POS         8
+#define IRQ_CNT_POS            12
+#define IRQ_MAC_RX_POS         16
 #define IRQ_PORTH_INTA_POS     20
-#define IRQ_MAC_TX_POS         24
+#define IRQ_MAC_TX_POS         24
 #define IRQ_PORTH_INTB_POS     28
 
 /* IAR4 BIT FIELDS */
 /* IAR5 BIT FIELDS */
 #define IRQ_PORTG_INTA_POS     0
 #define IRQ_PORTG_INTB_POS     4
-#define IRQ_MEM_DMA0_POS       8
-#define IRQ_MEM_DMA1_POS       12
-#define IRQ_WATCH_POS          16
+#define IRQ_MEM_DMA0_POS       8
+#define IRQ_MEM_DMA1_POS       12
+#define IRQ_WATCH_POS          16
 #define IRQ_PORTF_INTA_POS     20
 #define IRQ_PORTF_INTB_POS     24
-#define IRQ_SPI0_ERROR_POS     28
+#define IRQ_SPI0_ERROR_POS     28
 
 /* IAR6 BIT FIELDS */
-#define IRQ_SPI1_ERROR_POS     0
-#define IRQ_RSI_INT0_POS       12
-#define IRQ_RSI_INT1_POS       16
-#define IRQ_PWM_TRIP_POS       20
-#define IRQ_PWM_SYNC_POS       24
-#define IRQ_PTP_STAT_POS       28
-
-#endif                         /* _BF518_IRQ_H_ */
+#define IRQ_SPI1_ERROR_POS     0
+#define IRQ_RSI_INT0_POS       12
+#define IRQ_RSI_INT1_POS       16
+#define IRQ_PWM_TRIP_POS       20
+#define IRQ_PWM_SYNC_POS       24
+#define IRQ_PTP_STAT_POS       28
+
+#endif
index 2cd2ff6f304374d3e5c4427879f5d48e273d39f8..e67ac772066894e18a8acd8512e188f56fba6812 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/portmux.h>
 #include <asm/dpmc.h>
 #include <linux/spi/ad7877.h>
+#include <asm/bfin_sport.h>
 
 /*
  * Name the Board for the /proc/cpuinfo
@@ -526,11 +527,69 @@ static struct bfin5xx_spi_chip spidev_chip_info = {
 };
 #endif
 
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+
+static const u16 bfin_snd_pin[][7] = {
+       {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+               P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0, 0},
+       {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+               P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_TFS, 0},
+};
+
+static struct bfin_snd_platform_data bfin_snd_data[] = {
+       {
+               .pin_req = &bfin_snd_pin[0][0],
+       },
+       {
+               .pin_req = &bfin_snd_pin[1][0],
+       },
+};
+
+#define BFIN_SND_RES(x) \
+       [x] = { \
+               { \
+                       .start = SPORT##x##_TCR1, \
+                       .end = SPORT##x##_TCR1, \
+                       .flags = IORESOURCE_MEM \
+               }, \
+               { \
+                       .start = CH_SPORT##x##_RX, \
+                       .end = CH_SPORT##x##_RX, \
+                       .flags = IORESOURCE_DMA, \
+               }, \
+               { \
+                       .start = CH_SPORT##x##_TX, \
+                       .end = CH_SPORT##x##_TX, \
+                       .flags = IORESOURCE_DMA, \
+               }, \
+               { \
+                       .start = IRQ_SPORT##x##_ERROR, \
+                       .end = IRQ_SPORT##x##_ERROR, \
+                       .flags = IORESOURCE_IRQ, \
+               } \
+       }
+
+static struct resource bfin_snd_resources[][4] = {
+       BFIN_SND_RES(0),
+       BFIN_SND_RES(1),
+};
+
+static struct platform_device bfin_pcm = {
+       .name = "bfin-pcm-audio",
+       .id = -1,
+};
+#endif
+
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
 static struct platform_device bfin_i2s = {
        .name = "bfin-i2s",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
@@ -538,7 +597,11 @@ static struct platform_device bfin_i2s = {
 static struct platform_device bfin_tdm = {
        .name = "bfin-tdm",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
@@ -583,7 +646,9 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
                .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
                .bus_num = 0,
                .chip_select = 4,
+               .platform_data = "ad1836",
                .controller_data = &ad1836_spi_chip_info,
+               .mode = SPI_MODE_3,
        },
 #endif
 #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
@@ -1211,6 +1276,11 @@ static struct platform_device *stamp_devices[] __initdata = {
        &ezkit_flash_device,
 #endif
 
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+       &bfin_pcm,
+#endif
+
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
        &bfin_i2s,
 #endif
index 9358afa05c90f47058f6cc522ee0a5edbbce5e21..e66a7e89cd3c621b0b7c928a153b1f57917d7b32 100644 (file)
@@ -5,14 +5,14 @@
  * and can be replaced with that version at any time
  * DO NOT EDIT THIS FILE
  *
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
  * Licensed under the ADI BSD license.
  *   https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
  */
 
 /* This file should be up to date with:
  *  - Revision E, 03/15/2010; ADSP-BF526 Blackfin Processor Anomaly List
- *  - Revision G, 08/25/2009; ADSP-BF527 Blackfin Processor Anomaly List
+ *  - Revision H, 04/29/2010; ADSP-BF527 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define ANOMALY_05000483 (1)
 /* PLL_CTL Change Using bfrom_SysControl() Can Result in Processor Overclocking */
 #define ANOMALY_05000485 (_ANOMALY_BF526_BF527(< 2, < 3))
+/* The CODEC Zero-Cross Detect Feature is not Functional */
+#define ANOMALY_05000487 (1)
 /* IFLUSH sucks at life */
 #define ANOMALY_05000491 (1)
 
 #define ANOMALY_05000323 (0)
 #define ANOMALY_05000362 (1)
 #define ANOMALY_05000363 (0)
+#define ANOMALY_05000383 (0)
 #define ANOMALY_05000400 (0)
 #define ANOMALY_05000402 (0)
 #define ANOMALY_05000412 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
 #define ANOMALY_05000474 (0)
+#define ANOMALY_05000480 (0)
 
 #endif
diff --git a/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h
deleted file mode 100644 (file)
index 960e089..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2007-2009 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later
- */
-
-#include <asm/dma.h>
-#include <asm/portmux.h>
-
-#if defined(CONFIG_BFIN_UART0_CTSRTS) || defined(CONFIG_BFIN_UART1_CTSRTS)
-# define CONFIG_SERIAL_BFIN_CTSRTS
-
-# ifndef CONFIG_UART0_CTS_PIN
-#  define CONFIG_UART0_CTS_PIN -1
-# endif
-
-# ifndef CONFIG_UART0_RTS_PIN
-#  define CONFIG_UART0_RTS_PIN -1
-# endif
-
-# ifndef CONFIG_UART1_CTS_PIN
-#  define CONFIG_UART1_CTS_PIN -1
-# endif
-
-# ifndef CONFIG_UART1_RTS_PIN
-#  define CONFIG_UART1_RTS_PIN -1
-# endif
-#endif
-
-struct bfin_serial_res {
-       unsigned long uart_base_addr;
-       int uart_irq;
-       int uart_status_irq;
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       unsigned int uart_tx_dma_channel;
-       unsigned int uart_rx_dma_channel;
-#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       int uart_cts_pin;
-       int uart_rts_pin;
-#endif
-};
-
-struct bfin_serial_res bfin_serial_resource[] = {
-#ifdef CONFIG_SERIAL_BFIN_UART0
-       {
-        0xFFC00400,
-        IRQ_UART0_RX,
-        IRQ_UART0_ERROR,
-#ifdef CONFIG_SERIAL_BFIN_DMA
-        CH_UART0_TX,
-        CH_UART0_RX,
-#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-        CONFIG_UART0_CTS_PIN,
-        CONFIG_UART0_RTS_PIN,
-#endif
-        },
-#endif
-#ifdef CONFIG_SERIAL_BFIN_UART1
-       {
-        0xFFC02000,
-        IRQ_UART1_RX,
-        IRQ_UART1_ERROR,
-#ifdef CONFIG_SERIAL_BFIN_DMA
-        CH_UART1_TX,
-        CH_UART1_RX,
-#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-        CONFIG_UART1_CTS_PIN,
-        CONFIG_UART1_RTS_PIN,
-#endif
-        },
-#endif
-};
-
-#define DRIVER_NAME "bfin-uart"
-
-#include <asm/bfin_serial.h>
index 618dfcdfa91ab1055e3af4ef962d132b45e8237c..2c12e879aa4ed48682f7063c4859b31a09fddfe5 100644 (file)
 #define bfin_write_PORTG_SLEW(val)             bfin_write16(PORTG_SLEW, val)
 #define bfin_read_PORTH_SLEW()                 bfin_read16(PORTH_SLEW)
 #define bfin_write_PORTH_SLEW(val)             bfin_write16(PORTH_SLEW, val)
-#define bfin_read_PORTF_HYSTERISIS()           bfin_read16(PORTF_HYSTERISIS)
-#define bfin_write_PORTF_HYSTERISIS(val)       bfin_write16(PORTF_HYSTERISIS, val)
-#define bfin_read_PORTG_HYSTERISIS()           bfin_read16(PORTG_HYSTERISIS)
-#define bfin_write_PORTG_HYSTERISIS(val)       bfin_write16(PORTG_HYSTERISIS, val)
-#define bfin_read_PORTH_HYSTERISIS()           bfin_read16(PORTH_HYSTERISIS)
-#define bfin_write_PORTH_HYSTERISIS(val)       bfin_write16(PORTH_HYSTERISIS, val)
+#define bfin_read_PORTF_HYSTERESIS()           bfin_read16(PORTF_HYSTERESIS)
+#define bfin_write_PORTF_HYSTERESIS(val)       bfin_write16(PORTF_HYSTERESIS, val)
+#define bfin_read_PORTG_HYSTERESIS()           bfin_read16(PORTG_HYSTERESIS)
+#define bfin_write_PORTG_HYSTERESIS(val)       bfin_write16(PORTG_HYSTERESIS, val)
+#define bfin_read_PORTH_HYSTERESIS()           bfin_read16(PORTH_HYSTERESIS)
+#define bfin_write_PORTH_HYSTERESIS(val)       bfin_write16(PORTH_HYSTERESIS, val)
 #define bfin_read_MISCPORT_DRIVE()             bfin_read16(MISCPORT_DRIVE)
 #define bfin_write_MISCPORT_DRIVE(val)         bfin_write16(MISCPORT_DRIVE, val)
 #define bfin_read_MISCPORT_SLEW()              bfin_read16(MISCPORT_SLEW)
 #define bfin_write_MISCPORT_SLEW(val)          bfin_write16(MISCPORT_SLEW, val)
-#define bfin_read_MISCPORT_HYSTERISIS()                bfin_read16(MISCPORT_HYSTERISIS)
-#define bfin_write_MISCPORT_HYSTERISIS(val)    bfin_write16(MISCPORT_HYSTERISIS, val)
+#define bfin_read_MISCPORT_HYSTERESIS()                bfin_read16(MISCPORT_HYSTERESIS)
+#define bfin_write_MISCPORT_HYSTERESIS(val)    bfin_write16(MISCPORT_HYSTERESIS, val)
 
 /* HOST Port Registers */
 
index 84ef11e52644cea94f70ca235a8b2888cdf0859d..37d353a19722f3242c70ccdd3776570581dab744 100644 (file)
 #define PORTF_SLEW              0xFFC03230      /* Port F slew control */
 #define PORTG_SLEW              0xFFC03234      /* Port G slew control */
 #define PORTH_SLEW              0xFFC03238      /* Port H slew control */
-#define PORTF_HYSTERISIS        0xFFC03240      /* Port F Schmitt trigger control */
-#define PORTG_HYSTERISIS        0xFFC03244      /* Port G Schmitt trigger control */
-#define PORTH_HYSTERISIS        0xFFC03248      /* Port H Schmitt trigger control */
+#define PORTF_HYSTERESIS        0xFFC03240      /* Port F Schmitt trigger control */
+#define PORTG_HYSTERESIS        0xFFC03244      /* Port G Schmitt trigger control */
+#define PORTH_HYSTERESIS        0xFFC03248      /* Port H Schmitt trigger control */
 #define MISCPORT_DRIVE          0xFFC03280      /* Misc Port drive strength control */
 #define MISCPORT_SLEW           0xFFC03284      /* Misc Port slew control */
-#define MISCPORT_HYSTERISIS     0xFFC03288      /* Misc Port Schmitt trigger control */
+#define MISCPORT_HYSTERESIS     0xFFC03288      /* Misc Port Schmitt trigger control */
 
 
 /***********************************************************************************
index cc383adfdffa0752097a55dbfe6fb9936df717cd..aab80bb1a683e45fca36f02144efc4a44c4fd3f6 100644 (file)
 #define                USB_EP_NI7_TXTYPE  0xffc03bd4   /* Sets the transaction protocol and peripheral endpoint number for the Host Tx endpoint7 */
 #define            USB_EP_NI7_TXINTERVAL  0xffc03bd8   /* Sets the NAK response timeout on Endpoint7 */
 #define                USB_EP_NI7_RXTYPE  0xffc03bdc   /* Sets the transaction protocol and peripheral endpoint number for the Host Rx endpoint7 */
-#define            USB_EP_NI7_RXINTERVAL  0xffc03bf0   /* Sets the polling interval for Interrupt/Isochronous transfers or the NAK response timeout on Bulk transfers for Host Rx endpoint7 */
-#define               USB_EP_NI7_TXCOUNT  0xffc03bf8   /* Number of bytes to be written to the endpoint7 Tx FIFO */
+#define            USB_EP_NI7_RXINTERVAL  0xffc03be0   /* Sets the polling interval for Interrupt/Isochronous transfers or the NAK response timeout on Bulk transfers for Host Rx endpoint7 */
+#define               USB_EP_NI7_TXCOUNT  0xffc03be8   /* Number of bytes to be written to the endpoint7 Tx FIFO */
 
 #define                USB_DMA_INTERRUPT  0xffc03c00   /* Indicates pending interrupts for the DMA channels */
 
index 704d9253e41d35373e48643557d48dbdd05efc7d..ed7310ff819b5a2e49b23bdcc2a1983f1ef669e2 100644 (file)
@@ -7,38 +7,9 @@
 #ifndef _BF527_IRQ_H_
 #define _BF527_IRQ_H_
 
-/*
- * Interrupt source definitions
-       Event Source    Core Event Name
-       Core        Emulation               **
-       Events         (highest priority)  EMU         0
-       Reset                   RST         1
-       NMI                     NMI         2
-       Exception               EVX         3
-       Reserved                --          4
-       Hardware Error          IVHW        5
-       Core Timer              IVTMR       6 *
-
-       .....
-
-        Software Interrupt 1    IVG14       31
-        Software Interrupt 2    --
-        (lowest priority)  IVG15       32 *
-*/
-
-#define NR_PERI_INTS    (2 * 32)
-
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define IRQ_EMU                        0       /* Emulation */
-#define IRQ_RST                        1       /* reset */
-#define IRQ_NMI                        2       /* Non Maskable */
-#define IRQ_EVX                        3       /* Exception */
-#define IRQ_UNUSED             4       /* - unused interrupt */
-#define IRQ_HWERR              5       /* Hardware Error */
-#define IRQ_CORETMR            6       /* Core timer */
-
-#define BFIN_IRQ(x)            ((x) + 7)
+#include <mach-common/irq.h>
+
+#define NR_PERI_INTS           (2 * 32)
 
 #define IRQ_PLL_WAKEUP         BFIN_IRQ(0)     /* PLL Wakeup Interrupt */
 #define IRQ_DMA0_ERROR         BFIN_IRQ(1)     /* DMA Error 0 (generic) */
 #define IRQ_UART0_ERROR                BFIN_IRQ(12)    /* UART0 Status */
 #define IRQ_UART1_ERROR                BFIN_IRQ(13)    /* UART1 Status */
 #define IRQ_RTC                        BFIN_IRQ(14)    /* RTC */
-#define IRQ_PPI                BFIN_IRQ(15)    /* DMA Channel 0 (PPI/NAND) */
+#define IRQ_PPI                        BFIN_IRQ(15)    /* DMA Channel 0 (PPI/NAND) */
 #define IRQ_SPORT0_RX          BFIN_IRQ(16)    /* DMA 3 Channel (SPORT0 RX) */
 #define IRQ_SPORT0_TX          BFIN_IRQ(17)    /* DMA 4 Channel (SPORT0 TX) */
 #define IRQ_SPORT1_RX          BFIN_IRQ(18)    /* DMA 5 Channel (SPORT1 RX) */
 #define IRQ_SPORT1_TX          BFIN_IRQ(19)    /* DMA 6 Channel (SPORT1 TX) */
-#define IRQ_TWI                BFIN_IRQ(20)    /* TWI */
-#define IRQ_SPI                BFIN_IRQ(21)    /* DMA 7 Channel (SPI) */
-#define IRQ_UART0_RX           BFIN_IRQ(22)    /* DMA8 Channel (UART0 RX) */
-#define IRQ_UART0_TX           BFIN_IRQ(23)    /* DMA9 Channel (UART0 TX) */
-#define IRQ_UART1_RX           BFIN_IRQ(24)    /* DMA10 Channel (UART1 RX) */
-#define IRQ_UART1_TX           BFIN_IRQ(25)    /* DMA11 Channel (UART1 TX) */
-#define IRQ_OPTSEC             BFIN_IRQ(26)    /* OTPSEC Interrupt */
-#define IRQ_CNT                BFIN_IRQ(27)    /* GP Counter */
-#define IRQ_MAC_RX             BFIN_IRQ(28)    /* DMA1 Channel (MAC RX/HDMA) */
-#define IRQ_PORTH_INTA         BFIN_IRQ(29)    /* Port H Interrupt A */
+#define IRQ_TWI                        BFIN_IRQ(20)    /* TWI */
+#define IRQ_SPI                        BFIN_IRQ(21)    /* DMA 7 Channel (SPI) */
+#define IRQ_UART0_RX           BFIN_IRQ(22)    /* DMA8 Channel (UART0 RX) */
+#define IRQ_UART0_TX           BFIN_IRQ(23)    /* DMA9 Channel (UART0 TX) */
+#define IRQ_UART1_RX           BFIN_IRQ(24)    /* DMA10 Channel (UART1 RX) */
+#define IRQ_UART1_TX           BFIN_IRQ(25)    /* DMA11 Channel (UART1 TX) */
+#define IRQ_OPTSEC             BFIN_IRQ(26)    /* OTPSEC Interrupt */
+#define IRQ_CNT                        BFIN_IRQ(27)    /* GP Counter */
+#define IRQ_MAC_RX             BFIN_IRQ(28)    /* DMA1 Channel (MAC RX/HDMA) */
+#define IRQ_PORTH_INTA         BFIN_IRQ(29)    /* Port H Interrupt A */
 #define IRQ_MAC_TX             BFIN_IRQ(30)    /* DMA2 Channel (MAC TX/NAND) */
 #define IRQ_NFC                        BFIN_IRQ(30)    /* DMA2 Channel (MAC TX/NAND) */
 #define IRQ_PORTH_INTB         BFIN_IRQ(31)    /* Port H Interrupt B */
 #define IRQ_USB_INT2           BFIN_IRQ(54)    /* USB_INT2 Interrupt */
 #define IRQ_USB_DMA            BFIN_IRQ(55)    /* USB_DMAINT Interrupt */
 
-#define SYS_IRQS               BFIN_IRQ(63)    /* 70 */
-
-#define IRQ_PF0         71
-#define IRQ_PF1         72
-#define IRQ_PF2         73
-#define IRQ_PF3         74
-#define IRQ_PF4         75
-#define IRQ_PF5         76
-#define IRQ_PF6         77
-#define IRQ_PF7         78
-#define IRQ_PF8         79
-#define IRQ_PF9         80
-#define IRQ_PF10        81
-#define IRQ_PF11        82
-#define IRQ_PF12        83
-#define IRQ_PF13        84
-#define IRQ_PF14        85
-#define IRQ_PF15        86
-
-#define IRQ_PG0         87
-#define IRQ_PG1         88
-#define IRQ_PG2         89
-#define IRQ_PG3         90
-#define IRQ_PG4         91
-#define IRQ_PG5         92
-#define IRQ_PG6         93
-#define IRQ_PG7         94
-#define IRQ_PG8         95
-#define IRQ_PG9         96
-#define IRQ_PG10        97
-#define IRQ_PG11        98
-#define IRQ_PG12        99
-#define IRQ_PG13        100
-#define IRQ_PG14        101
-#define IRQ_PG15        102
-
-#define IRQ_PH0         103
-#define IRQ_PH1         104
-#define IRQ_PH2         105
-#define IRQ_PH3         106
-#define IRQ_PH4         107
-#define IRQ_PH5         108
-#define IRQ_PH6         109
-#define IRQ_PH7         110
-#define IRQ_PH8         111
-#define IRQ_PH9         112
-#define IRQ_PH10        113
-#define IRQ_PH11        114
-#define IRQ_PH12        115
-#define IRQ_PH13        116
-#define IRQ_PH14        117
-#define IRQ_PH15        118
-
-#define GPIO_IRQ_BASE  IRQ_PF0
-
-#define IRQ_MAC_PHYINT         119 /* PHY_INT Interrupt */
-#define IRQ_MAC_MMCINT         120 /* MMC Counter Interrupt */
-#define IRQ_MAC_RXFSINT                121 /* RX Frame-Status Interrupt */
-#define IRQ_MAC_TXFSINT                122 /* TX Frame-Status Interrupt */
-#define IRQ_MAC_WAKEDET                123 /* Wake-Up Interrupt */
-#define IRQ_MAC_RXDMAERR       124 /* RX DMA Direction Error Interrupt */
-#define IRQ_MAC_TXDMAERR       125 /* TX DMA Direction Error Interrupt */
-#define IRQ_MAC_STMDONE                126 /* Station Mgt. Transfer Done Interrupt */
-
-#define NR_MACH_IRQS   (IRQ_MAC_STMDONE + 1)
-#define NR_IRQS                (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7            7
-#define IVG8            8
-#define IVG9            9
-#define IVG10           10
-#define IVG11           11
-#define IVG12           12
-#define IVG13           13
-#define IVG14           14
-#define IVG15           15
+#define SYS_IRQS               BFIN_IRQ(63)    /* 70 */
+
+#define IRQ_PF0                        71
+#define IRQ_PF1                        72
+#define IRQ_PF2                        73
+#define IRQ_PF3                        74
+#define IRQ_PF4                        75
+#define IRQ_PF5                        76
+#define IRQ_PF6                        77
+#define IRQ_PF7                        78
+#define IRQ_PF8                        79
+#define IRQ_PF9                        80
+#define IRQ_PF10               81
+#define IRQ_PF11               82
+#define IRQ_PF12               83
+#define IRQ_PF13               84
+#define IRQ_PF14               85
+#define IRQ_PF15               86
+
+#define IRQ_PG0                        87
+#define IRQ_PG1                        88
+#define IRQ_PG2                        89
+#define IRQ_PG3                        90
+#define IRQ_PG4                        91
+#define IRQ_PG5                        92
+#define IRQ_PG6                        93
+#define IRQ_PG7                        94
+#define IRQ_PG8                        95
+#define IRQ_PG9                        96
+#define IRQ_PG10               97
+#define IRQ_PG11               98
+#define IRQ_PG12               99
+#define IRQ_PG13               100
+#define IRQ_PG14               101
+#define IRQ_PG15               102
+
+#define IRQ_PH0                        103
+#define IRQ_PH1                        104
+#define IRQ_PH2                        105
+#define IRQ_PH3                        106
+#define IRQ_PH4                        107
+#define IRQ_PH5                        108
+#define IRQ_PH6                        109
+#define IRQ_PH7                        110
+#define IRQ_PH8                        111
+#define IRQ_PH9                        112
+#define IRQ_PH10               113
+#define IRQ_PH11               114
+#define IRQ_PH12               115
+#define IRQ_PH13               116
+#define IRQ_PH14               117
+#define IRQ_PH15               118
+
+#define GPIO_IRQ_BASE          IRQ_PF0
+
+#define IRQ_MAC_PHYINT         119     /* PHY_INT Interrupt */
+#define IRQ_MAC_MMCINT         120     /* MMC Counter Interrupt */
+#define IRQ_MAC_RXFSINT                121     /* RX Frame-Status Interrupt */
+#define IRQ_MAC_TXFSINT                122     /* TX Frame-Status Interrupt */
+#define IRQ_MAC_WAKEDET                123     /* Wake-Up Interrupt */
+#define IRQ_MAC_RXDMAERR       124     /* RX DMA Direction Error Interrupt */
+#define IRQ_MAC_TXDMAERR       125     /* TX DMA Direction Error Interrupt */
+#define IRQ_MAC_STMDONE                126     /* Station Mgt. Transfer Done Interrupt */
+
+#define NR_MACH_IRQS           (IRQ_MAC_STMDONE + 1)
 
 /* IAR0 BIT FIELDS */
 #define IRQ_PLL_WAKEUP_POS     0
 #define IRQ_DMA0_ERROR_POS     4
-#define IRQ_DMAR0_BLK_POS      8
-#define IRQ_DMAR1_BLK_POS      12
-#define IRQ_DMAR0_OVR_POS      16
-#define IRQ_DMAR1_OVR_POS      20
-#define IRQ_PPI_ERROR_POS      24
-#define IRQ_MAC_ERROR_POS      28
+#define IRQ_DMAR0_BLK_POS      8
+#define IRQ_DMAR1_BLK_POS      12
+#define IRQ_DMAR0_OVR_POS      16
+#define IRQ_DMAR1_OVR_POS      20
+#define IRQ_PPI_ERROR_POS      24
+#define IRQ_MAC_ERROR_POS      28
 
 /* IAR1 BIT FIELDS */
 #define IRQ_SPORT0_ERROR_POS   0
 #define IRQ_SPORT1_ERROR_POS   4
-#define IRQ_UART0_ERROR_POS    16
-#define IRQ_UART1_ERROR_POS    20
-#define IRQ_RTC_POS            24
-#define IRQ_PPI_POS            28
+#define IRQ_UART0_ERROR_POS    16
+#define IRQ_UART1_ERROR_POS    20
+#define IRQ_RTC_POS            24
+#define IRQ_PPI_POS            28
 
 /* IAR2 BIT FIELDS */
 #define IRQ_SPORT0_RX_POS      0
 #define IRQ_SPORT0_TX_POS      4
 #define IRQ_SPORT1_RX_POS      8
 #define IRQ_SPORT1_TX_POS      12
-#define IRQ_TWI_POS            16
-#define IRQ_SPI_POS            20
-#define IRQ_UART0_RX_POS       24
-#define IRQ_UART0_TX_POS       28
+#define IRQ_TWI_POS            16
+#define IRQ_SPI_POS            20
+#define IRQ_UART0_RX_POS       24
+#define IRQ_UART0_TX_POS       28
 
 /* IAR3 BIT FIELDS */
-#define IRQ_UART1_RX_POS       0
-#define IRQ_UART1_TX_POS       4
-#define IRQ_OPTSEC_POS         8
-#define IRQ_CNT_POS            12
-#define IRQ_MAC_RX_POS         16
+#define IRQ_UART1_RX_POS       0
+#define IRQ_UART1_TX_POS       4
+#define IRQ_OPTSEC_POS         8
+#define IRQ_CNT_POS            12
+#define IRQ_MAC_RX_POS         16
 #define IRQ_PORTH_INTA_POS     20
-#define IRQ_MAC_TX_POS         24
+#define IRQ_MAC_TX_POS         24
 #define IRQ_PORTH_INTB_POS     28
 
 /* IAR4 BIT FIELDS */
 /* IAR5 BIT FIELDS */
 #define IRQ_PORTG_INTA_POS     0
 #define IRQ_PORTG_INTB_POS     4
-#define IRQ_MEM_DMA0_POS       8
-#define IRQ_MEM_DMA1_POS       12
-#define IRQ_WATCH_POS          16
+#define IRQ_MEM_DMA0_POS       8
+#define IRQ_MEM_DMA1_POS       12
+#define IRQ_WATCH_POS          16
 #define IRQ_PORTF_INTA_POS     20
 #define IRQ_PORTF_INTB_POS     24
-#define IRQ_SPI_ERROR_POS      28
+#define IRQ_SPI_ERROR_POS      28
 
 /* IAR6 BIT FIELDS */
-#define IRQ_NFC_ERROR_POS      0
-#define IRQ_HDMA_ERROR_POS     4
-#define IRQ_HDMA_POS           8
-#define IRQ_USB_EINT_POS       12
-#define IRQ_USB_INT0_POS       16
-#define IRQ_USB_INT1_POS       20
-#define IRQ_USB_INT2_POS       24
-#define IRQ_USB_DMA_POS        28
-
-#endif                         /* _BF527_IRQ_H_ */
+#define IRQ_NFC_ERROR_POS      0
+#define IRQ_HDMA_ERROR_POS     4
+#define IRQ_HDMA_POS           8
+#define IRQ_USB_EINT_POS       12
+#define IRQ_USB_INT0_POS       16
+#define IRQ_USB_INT1_POS       20
+#define IRQ_USB_INT2_POS       24
+#define IRQ_USB_DMA_POS                28
+
+#endif
index 78f8721879180f72c630755455573be016dca955..72aa59440f825f7145874cb090865a489881a7ac 100644 (file)
@@ -5,13 +5,13 @@
  * and can be replaced with that version at any time
  * DO NOT EDIT THIS FILE
  *
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
  * Licensed under the ADI BSD license.
  *   https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
  */
 
 /* This file should be up to date with:
- *  - Revision E, 09/18/2008; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
+ *  - Revision F, 05/25/2010; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define ANOMALY_05000443 (1)
 /* False Hardware Error when RETI Points to Invalid Memory */
 #define ANOMALY_05000461 (1)
+/* Synchronization Problem at Startup May Cause SPORT Transmit Channels to Misalign */
+#define ANOMALY_05000462 (1)
+/* Boot Failure When SDRAM Control Signals Toggle Coming Out Of Reset */
+#define ANOMALY_05000471 (1)
 /* Interrupted 32-Bit SPORT Data Register Access Results In Underflow */
 #define ANOMALY_05000473 (1)
 /* Possible Lockup Condition whem Modifying PLL from External Memory */
 #define ANOMALY_05000362 (1)
 #define ANOMALY_05000364 (0)
 #define ANOMALY_05000380 (0)
+#define ANOMALY_05000383 (0)
 #define ANOMALY_05000386 (1)
 #define ANOMALY_05000389 (0)
 #define ANOMALY_05000412 (0)
 #define ANOMALY_05000430 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
+#define ANOMALY_05000440 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
 #define ANOMALY_05000456 (0)
 #define ANOMALY_05000465 (0)
 #define ANOMALY_05000467 (0)
 #define ANOMALY_05000474 (0)
+#define ANOMALY_05000480 (0)
 #define ANOMALY_05000485 (0)
 
 #endif
diff --git a/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h
deleted file mode 100644 (file)
index 45dcaa4..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2006-2009 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later
- */
-
-#include <asm/dma.h>
-#include <asm/portmux.h>
-
-#ifdef CONFIG_BFIN_UART0_CTSRTS
-# define CONFIG_SERIAL_BFIN_CTSRTS
-# ifndef CONFIG_UART0_CTS_PIN
-#  define CONFIG_UART0_CTS_PIN -1
-# endif
-# ifndef CONFIG_UART0_RTS_PIN
-#  define CONFIG_UART0_RTS_PIN -1
-# endif
-#endif
-
-struct bfin_serial_res {
-       unsigned long   uart_base_addr;
-       int             uart_irq;
-       int             uart_status_irq;
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       unsigned int    uart_tx_dma_channel;
-       unsigned int    uart_rx_dma_channel;
-#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       int             uart_cts_pin;
-       int             uart_rts_pin;
-#endif
-};
-
-struct bfin_serial_res bfin_serial_resource[] = {
-       {
-       0xFFC00400,
-       IRQ_UART0_RX,
-       IRQ_UART0_ERROR,
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       CH_UART0_TX,
-       CH_UART0_RX,
-#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       CONFIG_UART0_CTS_PIN,
-       CONFIG_UART0_RTS_PIN,
-#endif
-       }
-};
-
-#define DRIVER_NAME "bfin-uart"
-
-#include <asm/bfin_serial.h>
index 1f7e9765d954b9bbcd20d9d0d376dbd383d64848..709733754142b93f70f13acbf0d95b19a7e69940 100644 (file)
@@ -7,83 +7,36 @@
 #ifndef _BF533_IRQ_H_
 #define _BF533_IRQ_H_
 
-/*
- * Interrupt source definitions
-             Event Source    Core Event Name
-Core        Emulation               **
- Events         (highest priority)  EMU         0
-            Reset                   RST         1
-            NMI                     NMI         2
-            Exception               EVX         3
-            Reserved                --          4
-            Hardware Error          IVHW        5
-            Core Timer              IVTMR       6 *
-           PLL Wakeup Interrupt    IVG7        7
-           DMA Error (generic)     IVG7        8
-           PPI Error Interrupt     IVG7        9
-           SPORT0 Error Interrupt  IVG7        10
-           SPORT1 Error Interrupt  IVG7        11
-           SPI Error Interrupt     IVG7        12
-           UART Error Interrupt    IVG7        13
-           RTC Interrupt           IVG8        14
-           DMA0 Interrupt (PPI)    IVG8        15
-           DMA1 (SPORT0 RX)        IVG9        16
-           DMA2 (SPORT0 TX)        IVG9        17
-           DMA3 (SPORT1 RX)        IVG9        18
-           DMA4 (SPORT1 TX)        IVG9        19
-           DMA5 (PPI)              IVG10       20
-           DMA6 (UART RX)          IVG10       21
-           DMA7 (UART TX)          IVG10       22
-           Timer0                  IVG11       23
-           Timer1                  IVG11       24
-           Timer2                  IVG11       25
-           PF Interrupt A          IVG12       26
-           PF Interrupt B          IVG12       27
-           DMA8/9 Interrupt        IVG13       28
-           DMA10/11 Interrupt      IVG13       29
-           Watchdog Timer          IVG13       30
+#include <mach-common/irq.h>
 
-            Softirq                IVG14       31
-            System Call    --
-                 (lowest priority)  IVG15       32 *
- */
-#define SYS_IRQS       31
-#define NR_PERI_INTS   24
+#define NR_PERI_INTS           24
 
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define        IRQ_EMU                 0       /*Emulation */
-#define        IRQ_RST                 1       /*reset */
-#define        IRQ_NMI                 2       /*Non Maskable */
-#define        IRQ_EVX                 3       /*Exception */
-#define        IRQ_UNUSED              4       /*- unused interrupt*/
-#define        IRQ_HWERR               5       /*Hardware Error */
-#define        IRQ_CORETMR             6       /*Core timer */
+#define IRQ_PLL_WAKEUP         BFIN_IRQ(0)     /* PLL Wakeup Interrupt */
+#define IRQ_DMA_ERROR          BFIN_IRQ(1)     /* DMA Error (general) */
+#define IRQ_PPI_ERROR          BFIN_IRQ(2)     /* PPI Error Interrupt */
+#define IRQ_SPORT0_ERROR       BFIN_IRQ(3)     /* SPORT0 Error Interrupt */
+#define IRQ_SPORT1_ERROR       BFIN_IRQ(4)     /* SPORT1 Error Interrupt */
+#define IRQ_SPI_ERROR          BFIN_IRQ(5)     /* SPI Error Interrupt */
+#define IRQ_UART0_ERROR                BFIN_IRQ(6)     /* UART Error Interrupt */
+#define IRQ_RTC                        BFIN_IRQ(7)     /* RTC Interrupt */
+#define IRQ_PPI                        BFIN_IRQ(8)     /* DMA0 Interrupt (PPI) */
+#define IRQ_SPORT0_RX          BFIN_IRQ(9)     /* DMA1 Interrupt (SPORT0 RX) */
+#define IRQ_SPORT0_TX          BFIN_IRQ(10)    /* DMA2 Interrupt (SPORT0 TX) */
+#define IRQ_SPORT1_RX          BFIN_IRQ(11)    /* DMA3 Interrupt (SPORT1 RX) */
+#define IRQ_SPORT1_TX          BFIN_IRQ(12)    /* DMA4 Interrupt (SPORT1 TX) */
+#define IRQ_SPI                        BFIN_IRQ(13)    /* DMA5 Interrupt (SPI) */
+#define IRQ_UART0_RX           BFIN_IRQ(14)    /* DMA6 Interrupt (UART RX) */
+#define IRQ_UART0_TX           BFIN_IRQ(15)    /* DMA7 Interrupt (UART TX) */
+#define IRQ_TIMER0             BFIN_IRQ(16)    /* Timer 0 */
+#define IRQ_TIMER1             BFIN_IRQ(17)    /* Timer 1 */
+#define IRQ_TIMER2             BFIN_IRQ(18)    /* Timer 2 */
+#define IRQ_PROG_INTA          BFIN_IRQ(19)    /* Programmable Flags A (8) */
+#define IRQ_PROG_INTB          BFIN_IRQ(20)    /* Programmable Flags B (8) */
+#define IRQ_MEM_DMA0           BFIN_IRQ(21)    /* DMA8/9 Interrupt (Memory DMA Stream 0) */
+#define IRQ_MEM_DMA1           BFIN_IRQ(22)    /* DMA10/11 Interrupt (Memory DMA Stream 1) */
+#define IRQ_WATCH              BFIN_IRQ(23)    /* Watch Dog Timer */
 
-#define        IRQ_PLL_WAKEUP          7       /*PLL Wakeup Interrupt */
-#define        IRQ_DMA_ERROR           8       /*DMA Error (general) */
-#define        IRQ_PPI_ERROR           9       /*PPI Error Interrupt */
-#define        IRQ_SPORT0_ERROR        10      /*SPORT0 Error Interrupt */
-#define        IRQ_SPORT1_ERROR        11      /*SPORT1 Error Interrupt */
-#define        IRQ_SPI_ERROR           12      /*SPI Error Interrupt */
-#define        IRQ_UART0_ERROR         13      /*UART Error Interrupt */
-#define        IRQ_RTC                 14      /*RTC Interrupt */
-#define        IRQ_PPI                 15      /*DMA0 Interrupt (PPI) */
-#define        IRQ_SPORT0_RX           16      /*DMA1 Interrupt (SPORT0 RX) */
-#define        IRQ_SPORT0_TX           17      /*DMA2 Interrupt (SPORT0 TX) */
-#define        IRQ_SPORT1_RX           18      /*DMA3 Interrupt (SPORT1 RX) */
-#define        IRQ_SPORT1_TX           19      /*DMA4 Interrupt (SPORT1 TX) */
-#define        IRQ_SPI                 20      /*DMA5 Interrupt (SPI) */
-#define        IRQ_UART0_RX            21      /*DMA6 Interrupt (UART RX) */
-#define        IRQ_UART0_TX            22      /*DMA7 Interrupt (UART TX) */
-#define        IRQ_TIMER0              23      /*Timer 0 */
-#define        IRQ_TIMER1              24      /*Timer 1 */
-#define        IRQ_TIMER2              25      /*Timer 2 */
-#define        IRQ_PROG_INTA           26      /*Programmable Flags A (8) */
-#define        IRQ_PROG_INTB           27      /*Programmable Flags B (8) */
-#define        IRQ_MEM_DMA0            28      /*DMA8/9 Interrupt (Memory DMA Stream 0) */
-#define        IRQ_MEM_DMA1            29      /*DMA10/11 Interrupt (Memory DMA Stream 1) */
-#define        IRQ_WATCH               30      /*Watch Dog Timer */
+#define SYS_IRQS               31
 
 #define IRQ_PF0                        33
 #define IRQ_PF1                        34
@@ -105,46 +58,35 @@ Core        Emulation               **
 #define GPIO_IRQ_BASE          IRQ_PF0
 
 #define NR_MACH_IRQS           (IRQ_PF15 + 1)
-#define NR_IRQS                        (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7                   7
-#define IVG8                   8
-#define IVG9                   9
-#define IVG10                  10
-#define IVG11                  11
-#define IVG12                  12
-#define IVG13                  13
-#define IVG14                  14
-#define IVG15                  15
 
-/* IAR0 BIT FIELDS*/
-#define RTC_ERROR_POS                  28
-#define UART_ERROR_POS                 24
-#define SPORT1_ERROR_POS               20
-#define SPI_ERROR_POS                  16
-#define SPORT0_ERROR_POS               12
-#define PPI_ERROR_POS                  8
-#define DMA_ERROR_POS                  4
-#define PLLWAKE_ERROR_POS              0
+/* IAR0 BIT FIELDS */
+#define RTC_ERROR_POS          28
+#define UART_ERROR_POS         24
+#define SPORT1_ERROR_POS       20
+#define SPI_ERROR_POS          16
+#define SPORT0_ERROR_POS       12
+#define PPI_ERROR_POS          8
+#define DMA_ERROR_POS          4
+#define PLLWAKE_ERROR_POS      0
 
-/* IAR1 BIT FIELDS*/
-#define DMA7_UARTTX_POS                        28
-#define DMA6_UARTRX_POS                        24
-#define DMA5_SPI_POS                   20
-#define DMA4_SPORT1TX_POS              16
-#define DMA3_SPORT1RX_POS              12
-#define DMA2_SPORT0TX_POS              8
-#define DMA1_SPORT0RX_POS              4
-#define DMA0_PPI_POS                   0
+/* IAR1 BIT FIELDS */
+#define DMA7_UARTTX_POS                28
+#define DMA6_UARTRX_POS                24
+#define DMA5_SPI_POS           20
+#define DMA4_SPORT1TX_POS      16
+#define DMA3_SPORT1RX_POS      12
+#define DMA2_SPORT0TX_POS      8
+#define DMA1_SPORT0RX_POS      4
+#define DMA0_PPI_POS           0
 
-/* IAR2 BIT FIELDS*/
-#define WDTIMER_POS                    28
-#define MEMDMA1_POS                    24
-#define MEMDMA0_POS                    20
-#define PFB_POS                                16
-#define PFA_POS                                12
-#define TIMER2_POS                     8
-#define TIMER1_POS                     4
-#define TIMER0_POS                     0
+/* IAR2 BIT FIELDS */
+#define WDTIMER_POS            28
+#define MEMDMA1_POS            24
+#define MEMDMA0_POS            20
+#define PFB_POS                        16
+#define PFA_POS                        12
+#define TIMER2_POS             8
+#define TIMER1_POS             4
+#define TIMER0_POS             0
 
-#endif                         /* _BF533_IRQ_H_ */
+#endif
index 3fa335405b317c9926c6bfe5fac4c6a16ffcbfdb..76db1d4831739027e32b38c4e8f5fc7762672b7f 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/reboot.h>
 #include <asm/portmux.h>
 #include <asm/dpmc.h>
+#include <asm/bfin_sport.h>
 #ifdef CONFIG_REGULATOR_FIXED_VOLTAGE
 #include <linux/regulator/fixed.h>
 #endif
@@ -381,7 +382,6 @@ static struct platform_device net2272_bfin_device = {
 #endif
 
 #if defined(CONFIG_MTD_NAND_PLATFORM) || defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
-#ifdef CONFIG_MTD_PARTITIONS
 const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
 
 static struct mtd_partition bfin_plat_nand_partitions[] = {
@@ -395,7 +395,6 @@ static struct mtd_partition bfin_plat_nand_partitions[] = {
                .offset = MTDPART_OFS_APPEND,
        },
 };
-#endif
 
 #define BFIN_NAND_PLAT_CLE 2
 #define BFIN_NAND_PLAT_ALE 1
@@ -422,11 +421,9 @@ static struct platform_nand_data bfin_plat_nand_data = {
        .chip = {
                .nr_chips = 1,
                .chip_delay = 30,
-#ifdef CONFIG_MTD_PARTITIONS
                .part_probe_types = part_probes,
                .partitions = bfin_plat_nand_partitions,
                .nr_partitions = ARRAY_SIZE(bfin_plat_nand_partitions),
-#endif
        },
        .ctrl = {
                .cmd_ctrl  = bfin_plat_nand_cmd_ctrl,
@@ -2585,27 +2582,103 @@ static struct platform_device bfin_dpmc = {
        },
 };
 
-#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
+       defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+
+#define SPORT_REQ(x) \
+       [x] = {P_SPORT##x##_TFS, P_SPORT##x##_DTPRI, P_SPORT##x##_TSCLK, \
+               P_SPORT##x##_RFS, P_SPORT##x##_DRPRI, P_SPORT##x##_RSCLK, 0}
+
+static const u16 bfin_snd_pin[][7] = {
+       SPORT_REQ(0),
+       SPORT_REQ(1),
+};
+
+static struct bfin_snd_platform_data bfin_snd_data[] = {
+       {
+               .pin_req = &bfin_snd_pin[0][0],
+       },
+       {
+               .pin_req = &bfin_snd_pin[1][0],
+       },
+};
+
+#define BFIN_SND_RES(x) \
+       [x] = { \
+               { \
+                       .start = SPORT##x##_TCR1, \
+                       .end = SPORT##x##_TCR1, \
+                       .flags = IORESOURCE_MEM \
+               }, \
+               { \
+                       .start = CH_SPORT##x##_RX, \
+                       .end = CH_SPORT##x##_RX, \
+                       .flags = IORESOURCE_DMA, \
+               }, \
+               { \
+                       .start = CH_SPORT##x##_TX, \
+                       .end = CH_SPORT##x##_TX, \
+                       .flags = IORESOURCE_DMA, \
+               }, \
+               { \
+                       .start = IRQ_SPORT##x##_ERROR, \
+                       .end = IRQ_SPORT##x##_ERROR, \
+                       .flags = IORESOURCE_IRQ, \
+               } \
+       }
+
+static struct resource bfin_snd_resources[][4] = {
+       BFIN_SND_RES(0),
+       BFIN_SND_RES(1),
+};
+
+static struct platform_device bfin_pcm = {
+       .name = "bfin-pcm-audio",
+       .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD73311) || defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
+static struct platform_device bfin_ad73311_codec_device = {
+       .name = "ad73311",
+       .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_I2S) || defined(CONFIG_SND_BF5XX_SOC_I2S_MODULE)
 static struct platform_device bfin_i2s = {
        .name = "bfin-i2s",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
 static struct platform_device bfin_tdm = {
        .name = "bfin-tdm",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
 static struct platform_device bfin_ac97 = {
        .name = "bfin-ac97",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
@@ -2796,17 +2869,28 @@ static struct platform_device *stamp_devices[] __initdata = {
        &stamp_flash_device,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
+       defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+       &bfin_pcm,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD73311) || defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
+       &bfin_ad73311_codec_device,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_I2S) || defined(CONFIG_SND_BF5XX_SOC_I2S_MODULE)
        &bfin_i2s,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
        &bfin_tdm,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
        &bfin_ac97,
 #endif
+
 #if defined(CONFIG_REGULATOR_AD5398) || defined(CONFIG_REGULATOR_AD5398_MODULE)
 #if defined(CONFIG_REGULATOR_VIRTUAL_CONSUMER) || \
        defined(CONFIG_REGULATOR_VIRTUAL_CONSUMER_MODULE)
index 43df6afd22ad71c2fca56d00e708f7493204605b..7f8e5a9f5db63ef455e38108d166d3655f3b211a 100644 (file)
@@ -5,13 +5,13 @@
  * and can be replaced with that version at any time
  * DO NOT EDIT THIS FILE
  *
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
  * Licensed under the ADI BSD license.
  *   https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
  */
 
 /* This file should be up to date with:
- *  - Revision D, 09/18/2008; ADSP-BF534/ADSP-BF536/ADSP-BF537 Blackfin Processor Anomaly List
+ *  - Revision E, 05/25/2010; ADSP-BF534/ADSP-BF536/ADSP-BF537 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define ANOMALY_05000443 (1)
 /* False Hardware Error when RETI Points to Invalid Memory */
 #define ANOMALY_05000461 (1)
+/* Synchronization Problem at Startup May Cause SPORT Transmit Channels to Misalign */
+#define ANOMALY_05000462 (1)
 /* Interrupted 32-Bit SPORT Data Register Access Results In Underflow */
 #define ANOMALY_05000473 (1)
 /* Possible Lockup Condition whem Modifying PLL from External Memory */
 #define ANOMALY_05000475 (1)
 /* TESTSET Instruction Cannot Be Interrupted */
 #define ANOMALY_05000477 (1)
+/* Multiple Simultaneous Urgent DMA Requests May Cause DMA System Instability */
+#define ANOMALY_05000480 (__SILICON_REVISION__ < 3)
 /* Reads of ITEST_COMMAND and ITEST_DATA Registers Cause Cache Corruption */
 #define ANOMALY_05000481 (1)
 /* IFLUSH sucks at life */
 #define ANOMALY_05000363 (0)
 #define ANOMALY_05000364 (0)
 #define ANOMALY_05000380 (0)
+#define ANOMALY_05000383 (0)
 #define ANOMALY_05000386 (1)
 #define ANOMALY_05000389 (0)
 #define ANOMALY_05000400 (0)
 #define ANOMALY_05000430 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
+#define ANOMALY_05000440 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
 #define ANOMALY_05000456 (0)
diff --git a/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h
deleted file mode 100644 (file)
index 3e955db..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2006-2009 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later
- */
-
-#include <asm/dma.h>
-#include <asm/portmux.h>
-
-#if defined(CONFIG_BFIN_UART0_CTSRTS) || defined(CONFIG_BFIN_UART1_CTSRTS)
-# define CONFIG_SERIAL_BFIN_CTSRTS
-
-# ifndef CONFIG_UART0_CTS_PIN
-#  define CONFIG_UART0_CTS_PIN -1
-# endif
-
-# ifndef CONFIG_UART0_RTS_PIN
-#  define CONFIG_UART0_RTS_PIN -1
-# endif
-
-# ifndef CONFIG_UART1_CTS_PIN
-#  define CONFIG_UART1_CTS_PIN -1
-# endif
-
-# ifndef CONFIG_UART1_RTS_PIN
-#  define CONFIG_UART1_RTS_PIN -1
-# endif
-#endif
-
-struct bfin_serial_res {
-       unsigned long   uart_base_addr;
-       int             uart_irq;
-       int             uart_status_irq;
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       unsigned int    uart_tx_dma_channel;
-       unsigned int    uart_rx_dma_channel;
-#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       int     uart_cts_pin;
-       int     uart_rts_pin;
-#endif
-};
-
-struct bfin_serial_res bfin_serial_resource[] = {
-#ifdef CONFIG_SERIAL_BFIN_UART0
-       {
-       0xFFC00400,
-       IRQ_UART0_RX,
-       IRQ_UART0_ERROR,
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       CH_UART0_TX,
-       CH_UART0_RX,
-#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       CONFIG_UART0_CTS_PIN,
-       CONFIG_UART0_RTS_PIN,
-#endif
-       },
-#endif
-#ifdef CONFIG_SERIAL_BFIN_UART1
-       {
-       0xFFC02000,
-       IRQ_UART1_RX,
-       IRQ_UART1_ERROR,
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       CH_UART1_TX,
-       CH_UART1_RX,
-#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       CONFIG_UART1_CTS_PIN,
-       CONFIG_UART1_RTS_PIN,
-#endif
-       },
-#endif
-};
-
-#define DRIVER_NAME "bfin-uart"
-
-#include <asm/bfin_serial.h>
index 1a6d617c5fcf8680597f0b5b4143be15b5590201..b6ed8235bda4cfa811810076ee2d5255660622b8 100644 (file)
 #ifndef _BF537_IRQ_H_
 #define _BF537_IRQ_H_
 
-/*
- * Interrupt source definitions
- *            Event Source    Core Event Name
- * Core       Emulation               **
- * Events         (highest priority)  EMU         0
- *            Reset                   RST         1
- *            NMI                     NMI         2
- *            Exception               EVX         3
- *            Reserved                --          4
- *            Hardware Error          IVHW        5
- *            Core Timer              IVTMR       6
- *  .....
- *
- *            Softirq                IVG14
- *            System Call    --
- *               (lowest priority)    IVG15
- */
-
-#define SYS_IRQS        39
-#define NR_PERI_INTS    32
-
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define IRQ_EMU             0  /*Emulation */
-#define IRQ_RST             1  /*reset */
-#define IRQ_NMI             2  /*Non Maskable */
-#define IRQ_EVX             3  /*Exception */
-#define IRQ_UNUSED          4  /*- unused interrupt*/
-#define IRQ_HWERR           5  /*Hardware Error */
-#define IRQ_CORETMR         6  /*Core timer */
-
-#define IRQ_PLL_WAKEUP      7  /*PLL Wakeup Interrupt */
-#define IRQ_DMA_ERROR       8  /*DMA Error (general) */
-#define IRQ_GENERIC_ERROR   9  /*GENERIC Error Interrupt */
-#define IRQ_RTC             10 /*RTC Interrupt */
-#define IRQ_PPI             11 /*DMA0 Interrupt (PPI) */
-#define IRQ_SPORT0_RX       12 /*DMA3 Interrupt (SPORT0 RX) */
-#define IRQ_SPORT0_TX       13 /*DMA4 Interrupt (SPORT0 TX) */
-#define IRQ_SPORT1_RX       14 /*DMA5 Interrupt (SPORT1 RX) */
-#define IRQ_SPORT1_TX       15 /*DMA6 Interrupt (SPORT1 TX) */
-#define IRQ_TWI             16 /*TWI Interrupt */
-#define IRQ_SPI             17 /*DMA7 Interrupt (SPI) */
-#define IRQ_UART0_RX        18 /*DMA8 Interrupt (UART0 RX) */
-#define IRQ_UART0_TX        19 /*DMA9 Interrupt (UART0 TX) */
-#define IRQ_UART1_RX        20 /*DMA10 Interrupt (UART1 RX) */
-#define IRQ_UART1_TX        21 /*DMA11 Interrupt (UART1 TX) */
-#define IRQ_CAN_RX          22 /*CAN Receive Interrupt */
-#define IRQ_CAN_TX          23 /*CAN Transmit Interrupt */
-#define IRQ_MAC_RX          24 /*DMA1 (Ethernet RX) Interrupt */
-#define IRQ_MAC_TX          25 /*DMA2 (Ethernet TX) Interrupt */
-#define IRQ_TIMER0            26       /*Timer 0 */
-#define IRQ_TIMER1            27       /*Timer 1 */
-#define IRQ_TIMER2            28       /*Timer 2 */
-#define IRQ_TIMER3            29       /*Timer 3 */
-#define IRQ_TIMER4            30       /*Timer 4 */
-#define IRQ_TIMER5            31       /*Timer 5 */
-#define IRQ_TIMER6            32       /*Timer 6 */
-#define IRQ_TIMER7            33       /*Timer 7 */
-#define IRQ_PROG_INTA       34 /* PF Ports F&G (PF15:0) Interrupt A */
-#define IRQ_PORTG_INTB      35 /* PF Port G (PF15:0) Interrupt B */
-#define IRQ_MEM_DMA0        36 /*(Memory DMA Stream 0) */
-#define IRQ_MEM_DMA1        37 /*(Memory DMA Stream 1) */
-#define IRQ_PROG_INTB        38        /* PF Ports F (PF15:0) Interrupt B */
-#define IRQ_WATCH           38 /*Watch Dog Timer */
-
-#define IRQ_PPI_ERROR       42 /*PPI Error Interrupt */
-#define IRQ_CAN_ERROR       43 /*CAN Error Interrupt */
-#define IRQ_MAC_ERROR       44 /*MAC Status/Error Interrupt */
-#define IRQ_SPORT0_ERROR    45 /*SPORT0 Error Interrupt */
-#define IRQ_SPORT1_ERROR    46 /*SPORT1 Error Interrupt */
-#define IRQ_SPI_ERROR       47 /*SPI Error Interrupt */
-#define IRQ_UART0_ERROR     48 /*UART Error Interrupt */
-#define IRQ_UART1_ERROR     49 /*UART Error Interrupt */
-
-#define IRQ_PF0         50
-#define IRQ_PF1         51
-#define IRQ_PF2         52
-#define IRQ_PF3         53
-#define IRQ_PF4         54
-#define IRQ_PF5         55
-#define IRQ_PF6         56
-#define IRQ_PF7         57
-#define IRQ_PF8         58
-#define IRQ_PF9         59
-#define IRQ_PF10        60
-#define IRQ_PF11        61
-#define IRQ_PF12        62
-#define IRQ_PF13        63
-#define IRQ_PF14        64
-#define IRQ_PF15        65
-
-#define IRQ_PG0         66
-#define IRQ_PG1         67
-#define IRQ_PG2         68
-#define IRQ_PG3         69
-#define IRQ_PG4         70
-#define IRQ_PG5         71
-#define IRQ_PG6         72
-#define IRQ_PG7         73
-#define IRQ_PG8         74
-#define IRQ_PG9         75
-#define IRQ_PG10        76
-#define IRQ_PG11        77
-#define IRQ_PG12        78
-#define IRQ_PG13        79
-#define IRQ_PG14        80
-#define IRQ_PG15        81
-
-#define IRQ_PH0         82
-#define IRQ_PH1         83
-#define IRQ_PH2         84
-#define IRQ_PH3         85
-#define IRQ_PH4         86
-#define IRQ_PH5         87
-#define IRQ_PH6         88
-#define IRQ_PH7         89
-#define IRQ_PH8         90
-#define IRQ_PH9         91
-#define IRQ_PH10        92
-#define IRQ_PH11        93
-#define IRQ_PH12        94
-#define IRQ_PH13        95
-#define IRQ_PH14        96
-#define IRQ_PH15        97
-
-#define GPIO_IRQ_BASE  IRQ_PF0
-
-#define IRQ_MAC_PHYINT         98 /* PHY_INT Interrupt */
-#define IRQ_MAC_MMCINT         99 /* MMC Counter Interrupt */
-#define IRQ_MAC_RXFSINT                100 /* RX Frame-Status Interrupt */
-#define IRQ_MAC_TXFSINT                101 /* TX Frame-Status Interrupt */
-#define IRQ_MAC_WAKEDET                102 /* Wake-Up Interrupt */
-#define IRQ_MAC_RXDMAERR       103 /* RX DMA Direction Error Interrupt */
-#define IRQ_MAC_TXDMAERR       104 /* TX DMA Direction Error Interrupt */
-#define IRQ_MAC_STMDONE                105 /* Station Mgt. Transfer Done Interrupt */
-
-#define NR_MACH_IRQS   (IRQ_MAC_STMDONE + 1)
-#define NR_IRQS                (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7            7
-#define IVG8            8
-#define IVG9            9
-#define IVG10           10
-#define IVG11           11
-#define IVG12           12
-#define IVG13           13
-#define IVG14           14
-#define IVG15           15
-
-/* IAR0 BIT FIELDS*/
-#define IRQ_PLL_WAKEUP_POS  0
-#define IRQ_DMA_ERROR_POS   4
-#define IRQ_ERROR_POS       8
-#define IRQ_RTC_POS         12
-#define IRQ_PPI_POS         16
-#define IRQ_SPORT0_RX_POS   20
-#define IRQ_SPORT0_TX_POS   24
-#define IRQ_SPORT1_RX_POS   28
-
-/* IAR1 BIT FIELDS*/
-#define IRQ_SPORT1_TX_POS   0
-#define IRQ_TWI_POS         4
-#define IRQ_SPI_POS         8
-#define IRQ_UART0_RX_POS    12
-#define IRQ_UART0_TX_POS    16
-#define IRQ_UART1_RX_POS    20
-#define IRQ_UART1_TX_POS    24
-#define IRQ_CAN_RX_POS      28
-
-/* IAR2 BIT FIELDS*/
-#define IRQ_CAN_TX_POS      0
-#define IRQ_MAC_RX_POS      4
-#define IRQ_MAC_TX_POS      8
-#define IRQ_TIMER0_POS        12
-#define IRQ_TIMER1_POS        16
-#define IRQ_TIMER2_POS        20
-#define IRQ_TIMER3_POS        24
-#define IRQ_TIMER4_POS        28
-
-/* IAR3 BIT FIELDS*/
-#define IRQ_TIMER5_POS        0
-#define IRQ_TIMER6_POS        4
-#define IRQ_TIMER7_POS        8
-#define IRQ_PROG_INTA_POS   12
-#define IRQ_PORTG_INTB_POS   16
-#define IRQ_MEM_DMA0_POS    20
-#define IRQ_MEM_DMA1_POS    24
-#define IRQ_WATCH_POS       28
-
-#endif                         /* _BF537_IRQ_H_ */
+#include <mach-common/irq.h>
+
+#define NR_PERI_INTS           32
+
+#define IRQ_PLL_WAKEUP         BFIN_IRQ(0)     /* PLL Wakeup Interrupt */
+#define IRQ_DMA_ERROR          BFIN_IRQ(1)     /* DMA Error (general) */
+#define IRQ_GENERIC_ERROR      BFIN_IRQ(2)     /* GENERIC Error Interrupt */
+#define IRQ_RTC                        BFIN_IRQ(3)     /* RTC Interrupt */
+#define IRQ_PPI                        BFIN_IRQ(4)     /* DMA0 Interrupt (PPI) */
+#define IRQ_SPORT0_RX          BFIN_IRQ(5)     /* DMA3 Interrupt (SPORT0 RX) */
+#define IRQ_SPORT0_TX          BFIN_IRQ(6)     /* DMA4 Interrupt (SPORT0 TX) */
+#define IRQ_SPORT1_RX          BFIN_IRQ(7)     /* DMA5 Interrupt (SPORT1 RX) */
+#define IRQ_SPORT1_TX          BFIN_IRQ(8)     /* DMA6 Interrupt (SPORT1 TX) */
+#define IRQ_TWI                        BFIN_IRQ(9)     /* TWI Interrupt */
+#define IRQ_SPI                        BFIN_IRQ(10)    /* DMA7 Interrupt (SPI) */
+#define IRQ_UART0_RX           BFIN_IRQ(11)    /* DMA8 Interrupt (UART0 RX) */
+#define IRQ_UART0_TX           BFIN_IRQ(12)    /* DMA9 Interrupt (UART0 TX) */
+#define IRQ_UART1_RX           BFIN_IRQ(13)    /* DMA10 Interrupt (UART1 RX) */
+#define IRQ_UART1_TX           BFIN_IRQ(14)    /* DMA11 Interrupt (UART1 TX) */
+#define IRQ_CAN_RX             BFIN_IRQ(15)    /* CAN Receive Interrupt */
+#define IRQ_CAN_TX             BFIN_IRQ(16)    /* CAN Transmit Interrupt */
+#define IRQ_PH_INTA_MAC_RX     BFIN_IRQ(17)    /* Port H Interrupt A & DMA1 Interrupt (Ethernet RX) */
+#define IRQ_PH_INTB_MAC_TX     BFIN_IRQ(18)    /* Port H Interrupt B & DMA2 Interrupt (Ethernet TX) */
+#define IRQ_TIMER0             BFIN_IRQ(19)    /* Timer 0 */
+#define IRQ_TIMER1             BFIN_IRQ(20)    /* Timer 1 */
+#define IRQ_TIMER2             BFIN_IRQ(21)    /* Timer 2 */
+#define IRQ_TIMER3             BFIN_IRQ(22)    /* Timer 3 */
+#define IRQ_TIMER4             BFIN_IRQ(23)    /* Timer 4 */
+#define IRQ_TIMER5             BFIN_IRQ(24)    /* Timer 5 */
+#define IRQ_TIMER6             BFIN_IRQ(25)    /* Timer 6 */
+#define IRQ_TIMER7             BFIN_IRQ(26)    /* Timer 7 */
+#define IRQ_PF_INTA_PG_INTA    BFIN_IRQ(27)    /* Ports F&G Interrupt A */
+#define IRQ_PORTG_INTB         BFIN_IRQ(28)    /* Port G Interrupt B */
+#define IRQ_MEM_DMA0           BFIN_IRQ(29)    /* (Memory DMA Stream 0) */
+#define IRQ_MEM_DMA1           BFIN_IRQ(30)    /* (Memory DMA Stream 1) */
+#define IRQ_PF_INTB_WATCH      BFIN_IRQ(31)    /* Watchdog & Port F Interrupt B */
+
+#define SYS_IRQS               39
+
+#define IRQ_PPI_ERROR          42      /* PPI Error Interrupt */
+#define IRQ_CAN_ERROR          43      /* CAN Error Interrupt */
+#define IRQ_MAC_ERROR          44      /* MAC Status/Error Interrupt */
+#define IRQ_SPORT0_ERROR       45      /* SPORT0 Error Interrupt */
+#define IRQ_SPORT1_ERROR       46      /* SPORT1 Error Interrupt */
+#define IRQ_SPI_ERROR          47      /* SPI Error Interrupt */
+#define IRQ_UART0_ERROR                48      /* UART Error Interrupt */
+#define IRQ_UART1_ERROR                49      /* UART Error Interrupt */
+
+#define IRQ_PF0                        50
+#define IRQ_PF1                        51
+#define IRQ_PF2                        52
+#define IRQ_PF3                        53
+#define IRQ_PF4                        54
+#define IRQ_PF5                        55
+#define IRQ_PF6                        56
+#define IRQ_PF7                        57
+#define IRQ_PF8                        58
+#define IRQ_PF9                        59
+#define IRQ_PF10               60
+#define IRQ_PF11               61
+#define IRQ_PF12               62
+#define IRQ_PF13               63
+#define IRQ_PF14               64
+#define IRQ_PF15               65
+
+#define IRQ_PG0                        66
+#define IRQ_PG1                        67
+#define IRQ_PG2                        68
+#define IRQ_PG3                        69
+#define IRQ_PG4                        70
+#define IRQ_PG5                        71
+#define IRQ_PG6                        72
+#define IRQ_PG7                        73
+#define IRQ_PG8                        74
+#define IRQ_PG9                        75
+#define IRQ_PG10               76
+#define IRQ_PG11               77
+#define IRQ_PG12               78
+#define IRQ_PG13               79
+#define IRQ_PG14               80
+#define IRQ_PG15               81
+
+#define IRQ_PH0                        82
+#define IRQ_PH1                        83
+#define IRQ_PH2                        84
+#define IRQ_PH3                        85
+#define IRQ_PH4                        86
+#define IRQ_PH5                        87
+#define IRQ_PH6                        88
+#define IRQ_PH7                        89
+#define IRQ_PH8                        90
+#define IRQ_PH9                        91
+#define IRQ_PH10               92
+#define IRQ_PH11               93
+#define IRQ_PH12               94
+#define IRQ_PH13               95
+#define IRQ_PH14               96
+#define IRQ_PH15               97
+
+#define GPIO_IRQ_BASE          IRQ_PF0
+
+#define IRQ_MAC_PHYINT         98      /* PHY_INT Interrupt */
+#define IRQ_MAC_MMCINT         99      /* MMC Counter Interrupt */
+#define IRQ_MAC_RXFSINT                100     /* RX Frame-Status Interrupt */
+#define IRQ_MAC_TXFSINT                101     /* TX Frame-Status Interrupt */
+#define IRQ_MAC_WAKEDET                102     /* Wake-Up Interrupt */
+#define IRQ_MAC_RXDMAERR       103     /* RX DMA Direction Error Interrupt */
+#define IRQ_MAC_TXDMAERR       104     /* TX DMA Direction Error Interrupt */
+#define IRQ_MAC_STMDONE                105     /* Station Mgt. Transfer Done Interrupt */
+
+#define IRQ_MAC_RX             106     /* DMA1 Interrupt (Ethernet RX) */
+#define IRQ_PORTH_INTA         107     /* Port H Interrupt A */
+
+#if 0 /* No Interrupt B support (yet) */
+#define IRQ_MAC_TX             108     /* DMA2 Interrupt (Ethernet TX) */
+#define IRQ_PORTH_INTB         109     /* Port H Interrupt B */
+#else
+#define IRQ_MAC_TX             IRQ_PH_INTB_MAC_TX
+#endif
+
+#define IRQ_PORTF_INTA         110     /* Port F Interrupt A */
+#define IRQ_PORTG_INTA         111     /* Port G Interrupt A */
+
+#if 0 /* No Interrupt B support (yet) */
+#define IRQ_WATCH              112     /* Watchdog Timer */
+#define IRQ_PORTF_INTB         113     /* Port F Interrupt B */
+#else
+#define IRQ_WATCH              IRQ_PF_INTB_WATCH
+#endif
+
+#define NR_MACH_IRQS           (113 + 1)
+
+/* IAR0 BIT FIELDS */
+#define IRQ_PLL_WAKEUP_POS     0
+#define IRQ_DMA_ERROR_POS      4
+#define IRQ_ERROR_POS          8
+#define IRQ_RTC_POS            12
+#define IRQ_PPI_POS            16
+#define IRQ_SPORT0_RX_POS      20
+#define IRQ_SPORT0_TX_POS      24
+#define IRQ_SPORT1_RX_POS      28
+
+/* IAR1 BIT FIELDS */
+#define IRQ_SPORT1_TX_POS      0
+#define IRQ_TWI_POS            4
+#define IRQ_SPI_POS            8
+#define IRQ_UART0_RX_POS       12
+#define IRQ_UART0_TX_POS       16
+#define IRQ_UART1_RX_POS       20
+#define IRQ_UART1_TX_POS       24
+#define IRQ_CAN_RX_POS         28
+
+/* IAR2 BIT FIELDS */
+#define IRQ_CAN_TX_POS         0
+#define IRQ_MAC_RX_POS         4
+#define IRQ_MAC_TX_POS         8
+#define IRQ_TIMER0_POS         12
+#define IRQ_TIMER1_POS         16
+#define IRQ_TIMER2_POS         20
+#define IRQ_TIMER3_POS         24
+#define IRQ_TIMER4_POS         28
+
+/* IAR3 BIT FIELDS */
+#define IRQ_TIMER5_POS         0
+#define IRQ_TIMER6_POS         4
+#define IRQ_TIMER7_POS         8
+#define IRQ_PROG_INTA_POS      12
+#define IRQ_PORTG_INTB_POS     16
+#define IRQ_MEM_DMA0_POS       20
+#define IRQ_MEM_DMA1_POS       24
+#define IRQ_WATCH_POS          28
+
+#define init_mach_irq init_mach_irq
+
+#endif
index f6500622b35d0eb85eb5e788cb7696deb4911889..2137a209a22bdc8f427c1e29c46cc42c97448e28 100644 (file)
 #include <linux/irq.h>
 #include <asm/blackfin.h>
 
+#include <asm/irq_handler.h>
+#include <asm/bfin5xx_spi.h>
+#include <asm/bfin_sport.h>
+#include <asm/bfin_can.h>
+#include <asm/bfin_dma.h>
+#include <asm/dpmc.h>
+
 void __init program_IAR(void)
 {
        /* Program the IAR0 Register with the configured priority */
@@ -51,3 +58,159 @@ void __init program_IAR(void)
 
        SSYNC();
 }
+
+#define SPI_ERR_MASK   (BIT_STAT_TXCOL | BIT_STAT_RBSY | BIT_STAT_MODF | BIT_STAT_TXE) /* SPI_STAT */
+#define SPORT_ERR_MASK (ROVF | RUVF | TOVF | TUVF)     /* SPORT_STAT */
+#define PPI_ERR_MASK   (0xFFFF & ~FLD) /* PPI_STATUS */
+#define EMAC_ERR_MASK  (PHYINT | MMCINT | RXFSINT | TXFSINT | WAKEDET | RXDMAERR | TXDMAERR | STMDONE) /* EMAC_SYSTAT */
+#define UART_ERR_MASK  (0x6)   /* UART_IIR */
+#define CAN_ERR_MASK   (EWTIF | EWRIF | EPIF | BOIF | WUIF | UIAIF | AAIF | RMLIF | UCEIF | EXTIF | ADIF)      /* CAN_GIF */
+
+static int error_int_mask;
+
+static void bf537_generic_error_mask_irq(struct irq_data *d)
+{
+       error_int_mask &= ~(1L << (d->irq - IRQ_PPI_ERROR));
+       if (!error_int_mask)
+               bfin_internal_mask_irq(IRQ_GENERIC_ERROR);
+}
+
+static void bf537_generic_error_unmask_irq(struct irq_data *d)
+{
+       bfin_internal_unmask_irq(IRQ_GENERIC_ERROR);
+       error_int_mask |= 1L << (d->irq - IRQ_PPI_ERROR);
+}
+
+static struct irq_chip bf537_generic_error_irqchip = {
+       .name = "ERROR",
+       .irq_ack = bfin_ack_noop,
+       .irq_mask_ack = bf537_generic_error_mask_irq,
+       .irq_mask = bf537_generic_error_mask_irq,
+       .irq_unmask = bf537_generic_error_unmask_irq,
+};
+
+static void bf537_demux_error_irq(unsigned int int_err_irq,
+                                 struct irq_desc *inta_desc)
+{
+       int irq = 0;
+
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+       if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK)
+               irq = IRQ_MAC_ERROR;
+       else
+#endif
+       if (bfin_read_SPORT0_STAT() & SPORT_ERR_MASK)
+               irq = IRQ_SPORT0_ERROR;
+       else if (bfin_read_SPORT1_STAT() & SPORT_ERR_MASK)
+               irq = IRQ_SPORT1_ERROR;
+       else if (bfin_read_PPI_STATUS() & PPI_ERR_MASK)
+               irq = IRQ_PPI_ERROR;
+       else if (bfin_read_CAN_GIF() & CAN_ERR_MASK)
+               irq = IRQ_CAN_ERROR;
+       else if (bfin_read_SPI_STAT() & SPI_ERR_MASK)
+               irq = IRQ_SPI_ERROR;
+       else if ((bfin_read_UART0_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
+               irq = IRQ_UART0_ERROR;
+       else if ((bfin_read_UART1_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
+               irq = IRQ_UART1_ERROR;
+
+       if (irq) {
+               if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR)))
+                       bfin_handle_irq(irq);
+               else {
+
+                       switch (irq) {
+                       case IRQ_PPI_ERROR:
+                               bfin_write_PPI_STATUS(PPI_ERR_MASK);
+                               break;
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+                       case IRQ_MAC_ERROR:
+                               bfin_write_EMAC_SYSTAT(EMAC_ERR_MASK);
+                               break;
+#endif
+                       case IRQ_SPORT0_ERROR:
+                               bfin_write_SPORT0_STAT(SPORT_ERR_MASK);
+                               break;
+
+                       case IRQ_SPORT1_ERROR:
+                               bfin_write_SPORT1_STAT(SPORT_ERR_MASK);
+                               break;
+
+                       case IRQ_CAN_ERROR:
+                               bfin_write_CAN_GIS(CAN_ERR_MASK);
+                               break;
+
+                       case IRQ_SPI_ERROR:
+                               bfin_write_SPI_STAT(SPI_ERR_MASK);
+                               break;
+
+                       default:
+                               break;
+                       }
+
+                       pr_debug("IRQ %d:"
+                                " MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n",
+                                irq);
+               }
+       } else
+               pr_err("%s: IRQ ?: PERIPHERAL ERROR INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
+                      __func__);
+
+}
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static int mac_rx_int_mask;
+
+static void bf537_mac_rx_mask_irq(struct irq_data *d)
+{
+       mac_rx_int_mask &= ~(1L << (d->irq - IRQ_MAC_RX));
+       if (!mac_rx_int_mask)
+               bfin_internal_mask_irq(IRQ_PH_INTA_MAC_RX);
+}
+
+static void bf537_mac_rx_unmask_irq(struct irq_data *d)
+{
+       bfin_internal_unmask_irq(IRQ_PH_INTA_MAC_RX);
+       mac_rx_int_mask |= 1L << (d->irq - IRQ_MAC_RX);
+}
+
+static struct irq_chip bf537_mac_rx_irqchip = {
+       .name = "ERROR",
+       .irq_ack = bfin_ack_noop,
+       .irq_mask_ack = bf537_mac_rx_mask_irq,
+       .irq_mask = bf537_mac_rx_mask_irq,
+       .irq_unmask = bf537_mac_rx_unmask_irq,
+};
+
+static void bf537_demux_mac_rx_irq(unsigned int int_irq,
+                                  struct irq_desc *desc)
+{
+       if (bfin_read_DMA1_IRQ_STATUS() & (DMA_DONE | DMA_ERR))
+               bfin_handle_irq(IRQ_MAC_RX);
+       else
+               bfin_demux_gpio_irq(int_irq, desc);
+}
+#endif
+
+void __init init_mach_irq(void)
+{
+       int irq;
+
+#if defined(CONFIG_BF537) || defined(CONFIG_BF536)
+       /* Clear EMAC Interrupt Status bits so we can demux it later */
+       bfin_write_EMAC_SYSTAT(-1);
+#endif
+
+       irq_set_chained_handler(IRQ_GENERIC_ERROR, bf537_demux_error_irq);
+       for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++)
+               irq_set_chip_and_handler(irq, &bf537_generic_error_irqchip,
+                                        handle_level_irq);
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+       irq_set_chained_handler(IRQ_PH_INTA_MAC_RX, bf537_demux_mac_rx_irq);
+       irq_set_chip_and_handler(IRQ_MAC_RX, &bf537_mac_rx_irqchip, handle_level_irq);
+       irq_set_chip_and_handler(IRQ_PORTH_INTA, &bf537_mac_rx_irqchip, handle_level_irq);
+
+       irq_set_chained_handler(IRQ_MAC_ERROR, bfin_demux_mac_status_irq);
+#endif
+}
index 8774b481c78e826e45a3ee971742015434985fdf..55e7d0712a942f04e027dec473636062c1e8a5f0 100644 (file)
@@ -5,14 +5,14 @@
  * and can be replaced with that version at any time
  * DO NOT EDIT THIS FILE
  *
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
  * Licensed under the ADI BSD license.
  *   https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
  */
 
 /* This file should be up to date with:
- *  - Revision H, 07/10/2009; ADSP-BF538/BF538F Blackfin Processor Anomaly List
- *  - Revision M, 07/10/2009; ADSP-BF539/BF539F Blackfin Processor Anomaly List
+ *  - Revision I, 05/25/2010; ADSP-BF538/BF538F Blackfin Processor Anomaly List
+ *  - Revision N, 05/25/2010; ADSP-BF539/BF539F Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define ANOMALY_05000363 (0)
 #define ANOMALY_05000364 (0)
 #define ANOMALY_05000380 (0)
+#define ANOMALY_05000383 (0)
 #define ANOMALY_05000386 (1)
 #define ANOMALY_05000389 (0)
 #define ANOMALY_05000400 (0)
 #define ANOMALY_05000430 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
+#define ANOMALY_05000440 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
 #define ANOMALY_05000456 (0)
 #define ANOMALY_05000465 (0)
 #define ANOMALY_05000467 (0)
 #define ANOMALY_05000474 (0)
+#define ANOMALY_05000480 (0)
 #define ANOMALY_05000485 (0)
 
 #endif
diff --git a/arch/blackfin/mach-bf538/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf538/include/mach/bfin_serial_5xx.h
deleted file mode 100644 (file)
index beb502e..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2008-2009 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <asm/dma.h>
-#include <asm/portmux.h>
-
-#if defined(CONFIG_BFIN_UART0_CTSRTS) || defined(CONFIG_BFIN_UART1_CTSRTS)
-# define CONFIG_SERIAL_BFIN_CTSRTS
-
-# ifndef CONFIG_UART0_CTS_PIN
-#  define CONFIG_UART0_CTS_PIN -1
-# endif
-
-# ifndef CONFIG_UART0_RTS_PIN
-#  define CONFIG_UART0_RTS_PIN -1
-# endif
-
-# ifndef CONFIG_UART1_CTS_PIN
-#  define CONFIG_UART1_CTS_PIN -1
-# endif
-
-# ifndef CONFIG_UART1_RTS_PIN
-#  define CONFIG_UART1_RTS_PIN -1
-# endif
-#endif
-
-struct bfin_serial_res {
-       unsigned long   uart_base_addr;
-       int             uart_irq;
-       int             uart_status_irq;
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       unsigned int    uart_tx_dma_channel;
-       unsigned int    uart_rx_dma_channel;
-#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       int     uart_cts_pin;
-       int     uart_rts_pin;
-#endif
-};
-
-struct bfin_serial_res bfin_serial_resource[] = {
-#ifdef CONFIG_SERIAL_BFIN_UART0
-       {
-       0xFFC00400,
-       IRQ_UART0_RX,
-       IRQ_UART0_ERROR,
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       CH_UART0_TX,
-       CH_UART0_RX,
-#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       CONFIG_UART0_CTS_PIN,
-       CONFIG_UART0_RTS_PIN,
-#endif
-       },
-#endif
-#ifdef CONFIG_SERIAL_BFIN_UART1
-       {
-       0xFFC02000,
-       IRQ_UART1_RX,
-       IRQ_UART1_ERROR,
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       CH_UART1_TX,
-       CH_UART1_RX,
-#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       CONFIG_UART1_CTS_PIN,
-       CONFIG_UART1_RTS_PIN,
-#endif
-       },
-#endif
-#ifdef CONFIG_SERIAL_BFIN_UART2
-       {
-       0xFFC02100,
-       IRQ_UART2_RX,
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       CH_UART2_TX,
-       CH_UART2_RX,
-#endif
-#ifdef CONFIG_BFIN_UART2_CTSRTS
-       CONFIG_UART2_CTS_PIN,
-       CONFIG_UART2_RTS_PIN,
-#endif
-       },
-#endif
-};
-
-#define DRIVER_NAME "bfin-uart"
-
-#include <asm/bfin_serial.h>
index 7a479d224dc79da2c1d371469110e40158d870be..07ca069d37cd29bb97a584ff3dd728161470524c 100644 (file)
@@ -7,38 +7,9 @@
 #ifndef _BF538_IRQ_H_
 #define _BF538_IRQ_H_
 
-/*
- * Interrupt source definitions
-       Event Source    Core Event Name
-       Core        Emulation               **
-       Events         (highest priority)  EMU         0
-       Reset                   RST         1
-       NMI                     NMI         2
-       Exception               EVX         3
-       Reserved                --          4
-       Hardware Error          IVHW        5
-       Core Timer              IVTMR       6 *
-
-       .....
-
-        Software Interrupt 1    IVG14       31
-        Software Interrupt 2    --
-        (lowest priority)  IVG15       32 *
-*/
-
-#define NR_PERI_INTS    (2 * 32)
-
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define IRQ_EMU                        0       /* Emulation */
-#define IRQ_RST                        1       /* reset */
-#define IRQ_NMI                        2       /* Non Maskable */
-#define IRQ_EVX                        3       /* Exception */
-#define IRQ_UNUSED             4       /* - unused interrupt */
-#define IRQ_HWERR              5       /* Hardware Error */
-#define IRQ_CORETMR            6       /* Core timer */
-
-#define BFIN_IRQ(x)            ((x) + 7)
+#include <mach-common/irq.h>
+
+#define NR_PERI_INTS           (2 * 32)
 
 #define IRQ_PLL_WAKEUP         BFIN_IRQ(0)     /* PLL Wakeup Interrupt */
 #define IRQ_DMA0_ERROR         BFIN_IRQ(1)     /* DMA Error 0 (generic) */
 
 #define SYS_IRQS               BFIN_IRQ(63)    /* 70 */
 
-#define IRQ_PF0         71
-#define IRQ_PF1         72
-#define IRQ_PF2         73
-#define IRQ_PF3         74
-#define IRQ_PF4         75
-#define IRQ_PF5         76
-#define IRQ_PF6         77
-#define IRQ_PF7         78
-#define IRQ_PF8         79
-#define IRQ_PF9         80
-#define IRQ_PF10        81
-#define IRQ_PF11        82
-#define IRQ_PF12        83
-#define IRQ_PF13        84
-#define IRQ_PF14        85
-#define IRQ_PF15        86
-
-#define GPIO_IRQ_BASE  IRQ_PF0
-
-#define NR_MACH_IRQS   (IRQ_PF15 + 1)
-#define NR_IRQS                (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7            7
-#define IVG8            8
-#define IVG9            9
-#define IVG10           10
-#define IVG11           11
-#define IVG12           12
-#define IVG13           13
-#define IVG14           14
-#define IVG15           15
+#define IRQ_PF0                        71
+#define IRQ_PF1                        72
+#define IRQ_PF2                        73
+#define IRQ_PF3                        74
+#define IRQ_PF4                        75
+#define IRQ_PF5                        76
+#define IRQ_PF6                        77
+#define IRQ_PF7                        78
+#define IRQ_PF8                        79
+#define IRQ_PF9                        80
+#define IRQ_PF10               81
+#define IRQ_PF11               82
+#define IRQ_PF12               83
+#define IRQ_PF13               84
+#define IRQ_PF14               85
+#define IRQ_PF15               86
+
+#define GPIO_IRQ_BASE          IRQ_PF0
+
+#define NR_MACH_IRQS           (IRQ_PF15 + 1)
 
 /* IAR0 BIT FIELDS */
 #define IRQ_PLL_WAKEUP_POS     0
 #define IRQ_CAN_TX_POS         0
 #define IRQ_MEM1_DMA0_POS      4
 #define IRQ_MEM1_DMA1_POS      8
-#endif                         /* _BF538_IRQ_H_ */
+
+#endif
index 93e19a54a8803d639fd5586a155954610861dbc7..311bf9970fe716e97278611b8c7879ffabc5c0b1 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/gpio.h>
 #include <asm/nand.h>
 #include <asm/dpmc.h>
+#include <asm/bfin_sport.h>
 #include <asm/portmux.h>
 #include <asm/bfin_sdh.h>
 #include <mach/bf54x_keys.h>
@@ -956,7 +957,15 @@ static struct mtd_partition ezkit_partitions[] = {
                .offset     = MTDPART_OFS_APPEND,
        }, {
                .name       = "file system(nor)",
-               .size       = MTDPART_SIZ_FULL,
+               .size       = 0x1000000 - 0x80000 - 0x400000 - 0x8000 * 4,
+               .offset     = MTDPART_OFS_APPEND,
+       }, {
+               .name       = "config(nor)",
+               .size       = 0x8000 * 3,
+               .offset     = MTDPART_OFS_APPEND,
+       }, {
+               .name       = "u-boot env(nor)",
+               .size       = 0x8000,
                .offset     = MTDPART_OFS_APPEND,
        }
 };
@@ -1312,27 +1321,110 @@ static struct platform_device bfin_dpmc = {
        },
 };
 
-#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
+       defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+
+#define SPORT_REQ(x) \
+       [x] = {P_SPORT##x##_TFS, P_SPORT##x##_DTPRI, P_SPORT##x##_TSCLK, \
+               P_SPORT##x##_RFS, P_SPORT##x##_DRPRI, P_SPORT##x##_RSCLK, 0}
+
+static const u16 bfin_snd_pin[][7] = {
+       SPORT_REQ(0),
+       SPORT_REQ(1),
+};
+
+static struct bfin_snd_platform_data bfin_snd_data[] = {
+       {
+               .pin_req = &bfin_snd_pin[0][0],
+       },
+       {
+               .pin_req = &bfin_snd_pin[1][0],
+       },
+};
+
+#define BFIN_SND_RES(x) \
+       [x] = { \
+               { \
+                       .start = SPORT##x##_TCR1, \
+                       .end = SPORT##x##_TCR1, \
+                       .flags = IORESOURCE_MEM \
+               }, \
+               { \
+                       .start = CH_SPORT##x##_RX, \
+                       .end = CH_SPORT##x##_RX, \
+                       .flags = IORESOURCE_DMA, \
+               }, \
+               { \
+                       .start = CH_SPORT##x##_TX, \
+                       .end = CH_SPORT##x##_TX, \
+                       .flags = IORESOURCE_DMA, \
+               }, \
+               { \
+                       .start = IRQ_SPORT##x##_ERROR, \
+                       .end = IRQ_SPORT##x##_ERROR, \
+                       .flags = IORESOURCE_IRQ, \
+               } \
+       }
+
+static struct resource bfin_snd_resources[][4] = {
+       BFIN_SND_RES(0),
+       BFIN_SND_RES(1),
+};
+
+static struct platform_device bfin_pcm = {
+       .name = "bfin-pcm-audio",
+       .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD73311) || defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
+static struct platform_device bfin_ad73311_codec_device = {
+       .name = "ad73311",
+       .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD1980) || defined(CONFIG_SND_BF5XX_SOC_AD1980_MODULE)
+static struct platform_device bfin_ad1980_codec_device = {
+       .name = "ad1980",
+       .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_I2S) || defined(CONFIG_SND_BF5XX_SOC_I2S_MODULE)
 static struct platform_device bfin_i2s = {
        .name = "bfin-i2s",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
 static struct platform_device bfin_tdm = {
        .name = "bfin-tdm",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
 static struct platform_device bfin_ac97 = {
        .name = "bfin-ac97",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
@@ -1450,6 +1542,16 @@ static struct platform_device *ezkit_devices[] __initdata = {
        &ezkit_flash_device,
 #endif
 
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
+       defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+       &bfin_pcm,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD1980) || defined(CONFIG_SND_BF5XX_SOC_AD1980_MODULE)
+       &bfin_ad1980_codec_device,
+#endif
+
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
        &bfin_i2s,
 #endif
index ffd0537295ac4d5c348bdf1e747b1f48caafc92f..9e70785bdde3434b388c7a4f0fe6ca20ab61aee3 100644 (file)
@@ -5,13 +5,13 @@
  * and can be replaced with that version at any time
  * DO NOT EDIT THIS FILE
  *
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
  * Licensed under the ADI BSD license.
  *   https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
  */
 
 /* This file should be up to date with:
- *  - Revision I, 07/23/2009; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List
+ *  - Revision J, 06/03/2010; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define ANOMALY_05000481 (1)
 /* Possible USB Data Corruption When Multiple Endpoints Are Accessed by the Core */
 #define ANOMALY_05000483 (1)
+/* DDR Trim May Not Be Performed for Certain VLEV Values in OTP Page PBS00L */
+#define ANOMALY_05000484 (__SILICON_REVISION__ < 3)
 /* PLL_CTL Change Using bfrom_SysControl() Can Result in Processor Overclocking */
 #define ANOMALY_05000485 (__SILICON_REVISION__ >= 2)
 /* IFLUSH sucks at life */
 #define ANOMALY_05000412 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
+#define ANOMALY_05000440 (0)
 #define ANOMALY_05000475 (0)
+#define ANOMALY_05000480 (0)
 
 #endif
diff --git a/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h
deleted file mode 100644 (file)
index 0d94eda..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2007-2009 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <asm/dma.h>
-#include <asm/portmux.h>
-
-#if defined(CONFIG_BFIN_UART0_CTSRTS) || defined(CONFIG_BFIN_UART1_CTSRTS) || \
-       defined(CONFIG_BFIN_UART2_CTSRTS) || defined(CONFIG_BFIN_UART3_CTSRTS)
-# define CONFIG_SERIAL_BFIN_HARD_CTSRTS
-#endif
-
-struct bfin_serial_res {
-       unsigned long   uart_base_addr;
-       int             uart_irq;
-       int             uart_status_irq;
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       unsigned int    uart_tx_dma_channel;
-       unsigned int    uart_rx_dma_channel;
-#endif
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       int             uart_cts_pin;
-       int             uart_rts_pin;
-#endif
-};
-
-struct bfin_serial_res bfin_serial_resource[] = {
-#ifdef CONFIG_SERIAL_BFIN_UART0
-       {
-       0xFFC00400,
-       IRQ_UART0_RX,
-       IRQ_UART0_ERROR,
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       CH_UART0_TX,
-       CH_UART0_RX,
-#endif
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       0,
-       0,
-#endif
-       },
-#endif
-#ifdef CONFIG_SERIAL_BFIN_UART1
-       {
-       0xFFC02000,
-       IRQ_UART1_RX,
-       IRQ_UART1_ERROR,
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       CH_UART1_TX,
-       CH_UART1_RX,
-#endif
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       GPIO_PE10,
-       GPIO_PE9,
-#endif
-       },
-#endif
-#ifdef CONFIG_SERIAL_BFIN_UART2
-       {
-       0xFFC02100,
-       IRQ_UART2_RX,
-       IRQ_UART2_ERROR,
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       CH_UART2_TX,
-       CH_UART2_RX,
-#endif
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       0,
-       0,
-#endif
-       },
-#endif
-#ifdef CONFIG_SERIAL_BFIN_UART3
-       {
-       0xFFC03100,
-       IRQ_UART3_RX,
-       IRQ_UART3_ERROR,
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       CH_UART3_TX,
-       CH_UART3_RX,
-#endif
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       GPIO_PB3,
-       GPIO_PB2,
-#endif
-       },
-#endif
-};
-
-#define DRIVER_NAME "bfin-uart"
-
-#include <asm/bfin_serial.h>
index 1cbba115f96f3d518eead9457913bcd8ca39ab7f..1fa41ec03f317f067fbdd73b5a33ecbc495d086b 100644 (file)
 #define            USB_EP_NI0_TXINTERVAL  0xffc03e18   /* Sets the NAK response timeout on Endpoint 0 */
 #define                USB_EP_NI0_RXTYPE  0xffc03e1c   /* Sets the transaction protocol and peripheral endpoint number for the Host Rx endpoint0 */
 #define            USB_EP_NI0_RXINTERVAL  0xffc03e20   /* Sets the polling interval for Interrupt/Isochronous transfers or the NAK response timeout on Bulk transfers for Host Rx endpoint0 */
+#define               USB_EP_NI0_TXCOUNT  0xffc03e28   /* Number of bytes to be written to the endpoint0 Tx FIFO */
 
 /* USB Endpoint 1 Control Registers */
 
-#define               USB_EP_NI0_TXCOUNT  0xffc03e28   /* Number of bytes to be written to the endpoint0 Tx FIFO */
 #define                USB_EP_NI1_TXMAXP  0xffc03e40   /* Maximum packet size for Host Tx endpoint1 */
 #define                 USB_EP_NI1_TXCSR  0xffc03e44   /* Control Status register for endpoint1 */
 #define                USB_EP_NI1_RXMAXP  0xffc03e48   /* Maximum packet size for Host Rx endpoint1 */
 #define            USB_EP_NI1_TXINTERVAL  0xffc03e58   /* Sets the NAK response timeout on Endpoint1 */
 #define                USB_EP_NI1_RXTYPE  0xffc03e5c   /* Sets the transaction protocol and peripheral endpoint number for the Host Rx endpoint1 */
 #define            USB_EP_NI1_RXINTERVAL  0xffc03e60   /* Sets the polling interval for Interrupt/Isochronous transfers or the NAK response timeout on Bulk transfers for Host Rx endpoint1 */
+#define               USB_EP_NI1_TXCOUNT  0xffc03e68   /* Number of bytes to be written to the+H102 endpoint1 Tx FIFO */
 
 /* USB Endpoint 2 Control Registers */
 
-#define               USB_EP_NI1_TXCOUNT  0xffc03e68   /* Number of bytes to be written to the+H102 endpoint1 Tx FIFO */
 #define                USB_EP_NI2_TXMAXP  0xffc03e80   /* Maximum packet size for Host Tx endpoint2 */
 #define                 USB_EP_NI2_TXCSR  0xffc03e84   /* Control Status register for endpoint2 */
 #define                USB_EP_NI2_RXMAXP  0xffc03e88   /* Maximum packet size for Host Rx endpoint2 */
 #define            USB_EP_NI2_TXINTERVAL  0xffc03e98   /* Sets the NAK response timeout on Endpoint2 */
 #define                USB_EP_NI2_RXTYPE  0xffc03e9c   /* Sets the transaction protocol and peripheral endpoint number for the Host Rx endpoint2 */
 #define            USB_EP_NI2_RXINTERVAL  0xffc03ea0   /* Sets the polling interval for Interrupt/Isochronous transfers or the NAK response timeout on Bulk transfers for Host Rx endpoint2 */
+#define               USB_EP_NI2_TXCOUNT  0xffc03ea8   /* Number of bytes to be written to the endpoint2 Tx FIFO */
 
 /* USB Endpoint 3 Control Registers */
 
-#define               USB_EP_NI2_TXCOUNT  0xffc03ea8   /* Number of bytes to be written to the endpoint2 Tx FIFO */
 #define                USB_EP_NI3_TXMAXP  0xffc03ec0   /* Maximum packet size for Host Tx endpoint3 */
 #define                 USB_EP_NI3_TXCSR  0xffc03ec4   /* Control Status register for endpoint3 */
 #define                USB_EP_NI3_RXMAXP  0xffc03ec8   /* Maximum packet size for Host Rx endpoint3 */
 #define            USB_EP_NI3_TXINTERVAL  0xffc03ed8   /* Sets the NAK response timeout on Endpoint3 */
 #define                USB_EP_NI3_RXTYPE  0xffc03edc   /* Sets the transaction protocol and peripheral endpoint number for the Host Rx endpoint3 */
 #define            USB_EP_NI3_RXINTERVAL  0xffc03ee0   /* Sets the polling interval for Interrupt/Isochronous transfers or the NAK response timeout on Bulk transfers for Host Rx endpoint3 */
+#define               USB_EP_NI3_TXCOUNT  0xffc03ee8   /* Number of bytes to be written to the H124endpoint3 Tx FIFO */
 
 /* USB Endpoint 4 Control Registers */
 
-#define               USB_EP_NI3_TXCOUNT  0xffc03ee8   /* Number of bytes to be written to the H124endpoint3 Tx FIFO */
 #define                USB_EP_NI4_TXMAXP  0xffc03f00   /* Maximum packet size for Host Tx endpoint4 */
 #define                 USB_EP_NI4_TXCSR  0xffc03f04   /* Control Status register for endpoint4 */
 #define                USB_EP_NI4_RXMAXP  0xffc03f08   /* Maximum packet size for Host Rx endpoint4 */
 #define            USB_EP_NI4_TXINTERVAL  0xffc03f18   /* Sets the NAK response timeout on Endpoint4 */
 #define                USB_EP_NI4_RXTYPE  0xffc03f1c   /* Sets the transaction protocol and peripheral endpoint number for the Host Rx endpoint4 */
 #define            USB_EP_NI4_RXINTERVAL  0xffc03f20   /* Sets the polling interval for Interrupt/Isochronous transfers or the NAK response timeout on Bulk transfers for Host Rx endpoint4 */
+#define               USB_EP_NI4_TXCOUNT  0xffc03f28   /* Number of bytes to be written to the endpoint4 Tx FIFO */
 
 /* USB Endpoint 5 Control Registers */
 
-#define               USB_EP_NI4_TXCOUNT  0xffc03f28   /* Number of bytes to be written to the endpoint4 Tx FIFO */
 #define                USB_EP_NI5_TXMAXP  0xffc03f40   /* Maximum packet size for Host Tx endpoint5 */
 #define                 USB_EP_NI5_TXCSR  0xffc03f44   /* Control Status register for endpoint5 */
 #define                USB_EP_NI5_RXMAXP  0xffc03f48   /* Maximum packet size for Host Rx endpoint5 */
 #define            USB_EP_NI5_TXINTERVAL  0xffc03f58   /* Sets the NAK response timeout on Endpoint5 */
 #define                USB_EP_NI5_RXTYPE  0xffc03f5c   /* Sets the transaction protocol and peripheral endpoint number for the Host Rx endpoint5 */
 #define            USB_EP_NI5_RXINTERVAL  0xffc03f60   /* Sets the polling interval for Interrupt/Isochronous transfers or the NAK response timeout on Bulk transfers for Host Rx endpoint5 */
+#define               USB_EP_NI5_TXCOUNT  0xffc03f68   /* Number of bytes to be written to the H145endpoint5 Tx FIFO */
 
 /* USB Endpoint 6 Control Registers */
 
-#define               USB_EP_NI5_TXCOUNT  0xffc03f68   /* Number of bytes to be written to the H145endpoint5 Tx FIFO */
 #define                USB_EP_NI6_TXMAXP  0xffc03f80   /* Maximum packet size for Host Tx endpoint6 */
 #define                 USB_EP_NI6_TXCSR  0xffc03f84   /* Control Status register for endpoint6 */
 #define                USB_EP_NI6_RXMAXP  0xffc03f88   /* Maximum packet size for Host Rx endpoint6 */
 #define            USB_EP_NI6_TXINTERVAL  0xffc03f98   /* Sets the NAK response timeout on Endpoint6 */
 #define                USB_EP_NI6_RXTYPE  0xffc03f9c   /* Sets the transaction protocol and peripheral endpoint number for the Host Rx endpoint6 */
 #define            USB_EP_NI6_RXINTERVAL  0xffc03fa0   /* Sets the polling interval for Interrupt/Isochronous transfers or the NAK response timeout on Bulk transfers for Host Rx endpoint6 */
+#define               USB_EP_NI6_TXCOUNT  0xffc03fa8   /* Number of bytes to be written to the endpoint6 Tx FIFO */
 
 /* USB Endpoint 7 Control Registers */
 
-#define               USB_EP_NI6_TXCOUNT  0xffc03fa8   /* Number of bytes to be written to the endpoint6 Tx FIFO */
 #define                USB_EP_NI7_TXMAXP  0xffc03fc0   /* Maximum packet size for Host Tx endpoint7 */
 #define                 USB_EP_NI7_TXCSR  0xffc03fc4   /* Control Status register for endpoint7 */
 #define                USB_EP_NI7_RXMAXP  0xffc03fc8   /* Maximum packet size for Host Rx endpoint7 */
 #define                USB_EP_NI7_TXTYPE  0xffc03fd4   /* Sets the transaction protocol and peripheral endpoint number for the Host Tx endpoint7 */
 #define            USB_EP_NI7_TXINTERVAL  0xffc03fd8   /* Sets the NAK response timeout on Endpoint7 */
 #define                USB_EP_NI7_RXTYPE  0xffc03fdc   /* Sets the transaction protocol and peripheral endpoint number for the Host Rx endpoint7 */
-#define            USB_EP_NI7_RXINTERVAL  0xffc03ff0   /* Sets the polling interval for Interrupt/Isochronous transfers or the NAK response timeout on Bulk transfers for Host Rx endpoint7 */
-#define               USB_EP_NI7_TXCOUNT  0xffc03ff8   /* Number of bytes to be written to the endpoint7 Tx FIFO */
+#define            USB_EP_NI7_RXINTERVAL  0xffc03fe0   /* Sets the polling interval for Interrupt/Isochronous transfers or the NAK response timeout on Bulk transfers for Host Rx endpoint7 */
+#define               USB_EP_NI7_TXCOUNT  0xffc03fe8   /* Number of bytes to be written to the endpoint7 Tx FIFO */
+
 #define                USB_DMA_INTERRUPT  0xffc04000   /* Indicates pending interrupts for the DMA channels */
 
 /* USB Channel 0 Config Registers */
index 7f87787e77382279a35a75b0f65a1ea3bbbdf505..533b8095b540aec5950f3d44df16914c71a2b2ad 100644 (file)
@@ -7,38 +7,9 @@
 #ifndef _BF548_IRQ_H_
 #define _BF548_IRQ_H_
 
-/*
- * Interrupt source definitions
-            Event Source    Core Event Name
-Core        Emulation               **
-Events         (highest priority)  EMU         0
-            Reset                   RST         1
-            NMI                     NMI         2
-            Exception               EVX         3
-            Reserved                --          4
-            Hardware Error          IVHW        5
-            Core Timer              IVTMR       6 *
-
-.....
-
-            Software Interrupt 1    IVG14       31
-            Software Interrupt 2    --
-                 (lowest priority)  IVG15       32 *
- */
-
-#define NR_PERI_INTS    (32 * 3)
-
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define IRQ_EMU                        0       /* Emulation */
-#define IRQ_RST                        1       /* reset */
-#define IRQ_NMI                        2       /* Non Maskable */
-#define IRQ_EVX                        3       /* Exception */
-#define IRQ_UNUSED             4       /* - unused interrupt*/
-#define IRQ_HWERR              5       /* Hardware Error */
-#define IRQ_CORETMR            6       /* Core timer */
+#include <mach-common/irq.h>
 
-#define BFIN_IRQ(x)            ((x) + 7)
+#define NR_PERI_INTS           (3 * 32)
 
 #define IRQ_PLL_WAKEUP         BFIN_IRQ(0)     /* PLL Wakeup Interrupt */
 #define IRQ_DMAC0_ERROR                BFIN_IRQ(1)     /* DMAC0 Status Interrupt */
@@ -311,49 +282,37 @@ Events         (highest priority)  EMU         0
 #define IRQ_PJ14               BFIN_PJ_IRQ(14)         /* N/A */
 #define IRQ_PJ15               BFIN_PJ_IRQ(15)         /* N/A */
 
-#define GPIO_IRQ_BASE  IRQ_PA0
+#define GPIO_IRQ_BASE          IRQ_PA0
 
-#define NR_MACH_IRQS   (IRQ_PJ15 + 1)
-#define NR_IRQS                (NR_MACH_IRQS + NR_SPARE_IRQS)
+#define NR_MACH_IRQS           (IRQ_PJ15 + 1)
 
 /* For compatibility reasons with existing code */
 
-#define IRQ_DMAC0_ERR          IRQ_DMAC0_ERROR
-#define IRQ_EPPI0_ERR          IRQ_EPPI0_ERROR
+#define IRQ_DMAC0_ERR          IRQ_DMAC0_ERROR
+#define IRQ_EPPI0_ERR          IRQ_EPPI0_ERROR
 #define IRQ_SPORT0_ERR         IRQ_SPORT0_ERROR
 #define IRQ_SPORT1_ERR         IRQ_SPORT1_ERROR
-#define IRQ_SPI0_ERR           IRQ_SPI0_ERROR
-#define IRQ_UART0_ERR          IRQ_UART0_ERROR
-#define IRQ_DMAC1_ERR          IRQ_DMAC1_ERROR
+#define IRQ_SPI0_ERR           IRQ_SPI0_ERROR
+#define IRQ_UART0_ERR          IRQ_UART0_ERROR
+#define IRQ_DMAC1_ERR          IRQ_DMAC1_ERROR
 #define IRQ_SPORT2_ERR         IRQ_SPORT2_ERROR
 #define IRQ_SPORT3_ERR         IRQ_SPORT3_ERROR
-#define IRQ_SPI1_ERR           IRQ_SPI1_ERROR
-#define IRQ_SPI2_ERR           IRQ_SPI2_ERROR
-#define IRQ_UART1_ERR          IRQ_UART1_ERROR
-#define IRQ_UART2_ERR          IRQ_UART2_ERROR
-#define IRQ_CAN0_ERR           IRQ_CAN0_ERROR
-#define IRQ_MXVR_ERR           IRQ_MXVR_ERROR
-#define IRQ_EPPI1_ERR                  IRQ_EPPI1_ERROR
-#define IRQ_EPPI2_ERR                  IRQ_EPPI2_ERROR
-#define IRQ_UART3_ERR          IRQ_UART3_ERROR
-#define IRQ_HOST_ERR           IRQ_HOST_ERROR
-#define IRQ_PIXC_ERR           IRQ_PIXC_ERROR
-#define IRQ_NFC_ERR            IRQ_NFC_ERROR
-#define IRQ_ATAPI_ERR          IRQ_ATAPI_ERROR
-#define IRQ_CAN1_ERR           IRQ_CAN1_ERROR
+#define IRQ_SPI1_ERR           IRQ_SPI1_ERROR
+#define IRQ_SPI2_ERR           IRQ_SPI2_ERROR
+#define IRQ_UART1_ERR          IRQ_UART1_ERROR
+#define IRQ_UART2_ERR          IRQ_UART2_ERROR
+#define IRQ_CAN0_ERR           IRQ_CAN0_ERROR
+#define IRQ_MXVR_ERR           IRQ_MXVR_ERROR
+#define IRQ_EPPI1_ERR          IRQ_EPPI1_ERROR
+#define IRQ_EPPI2_ERR          IRQ_EPPI2_ERROR
+#define IRQ_UART3_ERR          IRQ_UART3_ERROR
+#define IRQ_HOST_ERR           IRQ_HOST_ERROR
+#define IRQ_PIXC_ERR           IRQ_PIXC_ERROR
+#define IRQ_NFC_ERR            IRQ_NFC_ERROR
+#define IRQ_ATAPI_ERR          IRQ_ATAPI_ERROR
+#define IRQ_CAN1_ERR           IRQ_CAN1_ERROR
 #define IRQ_HS_DMA_ERR         IRQ_HS_DMA_ERROR
 
-
-#define IVG7            7
-#define IVG8            8
-#define IVG9            9
-#define IVG10           10
-#define IVG11           11
-#define IVG12           12
-#define IVG13           13
-#define IVG14           14
-#define IVG15           15
-
 /* IAR0 BIT FIELDS */
 #define IRQ_PLL_WAKEUP_POS     0
 #define IRQ_DMAC0_ERR_POS      4
@@ -492,4 +451,4 @@ struct bfin_pint_regs {
 
 #endif
 
-#endif /* _BF548_IRQ_H_ */
+#endif
index 3926cd909b66bff4b2033f49c831b544f30c9686..9231a942892b75b9afdce6936dbdf41e6a0adb8b 100644 (file)
@@ -243,7 +243,6 @@ static struct platform_device bfin_uart0_device = {
 
 #if defined(CONFIG_MTD_NAND_PLATFORM) || defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
 
-#ifdef CONFIG_MTD_PARTITIONS
 const char *part_probes[] = { "cmdlinepart", NULL };
 
 static struct mtd_partition bfin_plat_nand_partitions[] = {
@@ -257,7 +256,6 @@ static struct mtd_partition bfin_plat_nand_partitions[] = {
             .offset = MTDPART_OFS_APPEND,
             },
 };
-#endif
 
 #define BFIN_NAND_PLAT_CLE 2
 #define BFIN_NAND_PLAT_ALE 3
@@ -286,11 +284,9 @@ static struct platform_nand_data bfin_plat_nand_data = {
        .chip = {
                 .nr_chips = 1,
                 .chip_delay = 30,
-#ifdef CONFIG_MTD_PARTITIONS
                 .part_probe_types = part_probes,
                 .partitions = bfin_plat_nand_partitions,
                 .nr_partitions = ARRAY_SIZE(bfin_plat_nand_partitions),
-#endif
                 },
        .ctrl = {
                 .cmd_ctrl = bfin_plat_nand_cmd_ctrl,
index f667e7704197995ce186a61400d7ee19334fb491..5067984a62e78f669d4fbe99cc5eb0d62f251b4a 100644 (file)
@@ -247,7 +247,15 @@ static struct mtd_partition ezkit_partitions[] = {
                .offset     = MTDPART_OFS_APPEND,
        }, {
                .name       = "file system(nor)",
-               .size       = MTDPART_SIZ_FULL,
+               .size       = 0x800000 - 0x40000 - 0x1C0000 - 0x2000 * 8,
+               .offset     = MTDPART_OFS_APPEND,
+       }, {
+               .name       = "config(nor)",
+               .size       = 0x2000 * 7,
+               .offset     = MTDPART_OFS_APPEND,
+       }, {
+               .name       = "u-boot env(nor)",
+               .size       = 0x2000,
                .offset     = MTDPART_OFS_APPEND,
        }
 };
index 6a3499b02097af3e94b020ac0b5ebe7b731585ec..22b5ab7730271de0d52217a2e281ae7593bf7a06 100644 (file)
@@ -5,13 +5,13 @@
  * and can be replaced with that version at any time
  * DO NOT EDIT THIS FILE
  *
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
  * Licensed under the ADI BSD license.
  *   https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
  */
 
 /* This file should be up to date with:
- *  - Revision Q, 11/07/2008; ADSP-BF561 Blackfin Processor Anomaly List
+ *  - Revision R, 05/25/2010; ADSP-BF561 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define ANOMALY_05000428 (__SILICON_REVISION__ > 3)
 /* IFLUSH Instruction at End of Hardware Loop Causes Infinite Stall */
 #define ANOMALY_05000443 (1)
+/* SCKELOW Feature Is Not Functional */
+#define ANOMALY_05000458 (1)
 /* False Hardware Error when RETI Points to Invalid Memory */
 #define ANOMALY_05000461 (1)
+/* Synchronization Problem at Startup May Cause SPORT Transmit Channels to Misalign */
+#define ANOMALY_05000462 (1)
+/* Boot Failure When SDRAM Control Signals Toggle Coming Out Of Reset */
+#define ANOMALY_05000471 (1)
 /* Interrupted 32-Bit SPORT Data Register Access Results In Underflow */
 #define ANOMALY_05000473 (1)
 /* Possible Lockup Condition whem Modifying PLL from External Memory */
-#define ANOMALY_05000475 (__SILICON_REVISION__ < 4)
+#define ANOMALY_05000475 (1)
 /* TESTSET Instruction Cannot Be Interrupted */
 #define ANOMALY_05000477 (1)
 /* Reads of ITEST_COMMAND and ITEST_DATA Registers Cause Cache Corruption */
 #define ANOMALY_05000353 (1)
 #define ANOMALY_05000364 (0)
 #define ANOMALY_05000380 (0)
+#define ANOMALY_05000383 (0)
 #define ANOMALY_05000386 (1)
 #define ANOMALY_05000389 (0)
 #define ANOMALY_05000400 (0)
 #define ANOMALY_05000430 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
+#define ANOMALY_05000440 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
 #define ANOMALY_05000456 (0)
 #define ANOMALY_05000465 (0)
 #define ANOMALY_05000467 (0)
 #define ANOMALY_05000474 (0)
+#define ANOMALY_05000480 (0)
 #define ANOMALY_05000485 (0)
 
 #endif
diff --git a/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h
deleted file mode 100644 (file)
index 3a69474..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2006-2009 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <asm/dma.h>
-#include <asm/portmux.h>
-
-#ifdef CONFIG_BFIN_UART0_CTSRTS
-# define CONFIG_SERIAL_BFIN_CTSRTS
-# ifndef CONFIG_UART0_CTS_PIN
-#  define CONFIG_UART0_CTS_PIN -1
-# endif
-# ifndef CONFIG_UART0_RTS_PIN
-#  define CONFIG_UART0_RTS_PIN -1
-# endif
-#endif
-
-struct bfin_serial_res {
-       unsigned long   uart_base_addr;
-       int             uart_irq;
-       int             uart_status_irq;
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       unsigned int    uart_tx_dma_channel;
-       unsigned int    uart_rx_dma_channel;
-#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       int             uart_cts_pin;
-       int             uart_rts_pin;
-#endif
-};
-
-struct bfin_serial_res bfin_serial_resource[] = {
-       {
-       0xFFC00400,
-       IRQ_UART_RX,
-       IRQ_UART_ERROR,
-#ifdef CONFIG_SERIAL_BFIN_DMA
-       CH_UART_TX,
-       CH_UART_RX,
-#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       CONFIG_UART0_CTS_PIN,
-       CONFIG_UART0_RTS_PIN,
-#endif
-       }
-};
-
-#define DRIVER_NAME "bfin-uart"
-
-#include <asm/bfin_serial.h>
index c95566ade51b0b0cd6794a861cf71995c000364c..d6998520f70f77c4cefc5dd28a5e6546aeb88333 100644 (file)
 #ifndef _BF561_IRQ_H_
 #define _BF561_IRQ_H_
 
-/***********************************************************************
- * Interrupt source definitions:
-             Event Source              Core Event Name     IRQ No
-                                               (highest priority)
-           Emulation Events                    EMU         0
-            Reset                              RST         1
-            NMI                                        NMI         2
-            Exception                          EVX         3
-            Reserved                           --          4
-            Hardware Error                     IVHW        5
-            Core Timer                         IVTMR       6 *
-
-           PLL Wakeup Interrupt                IVG7        7
-           DMA1 Error (generic)                IVG7        8
-           DMA2 Error (generic)                IVG7        9
-           IMDMA Error (generic)               IVG7        10
-           PPI1 Error Interrupt                IVG7        11
-           PPI2 Error Interrupt                IVG7        12
-           SPORT0 Error Interrupt              IVG7        13
-           SPORT1 Error Interrupt              IVG7        14
-           SPI Error Interrupt                 IVG7        15
-           UART Error Interrupt                IVG7        16
-           Reserved Interrupt                  IVG7        17
-
-           DMA1 0  Interrupt(PPI1)             IVG8        18
-           DMA1 1  Interrupt(PPI2)             IVG8        19
-           DMA1 2  Interrupt                   IVG8        20
-           DMA1 3  Interrupt                   IVG8        21
-           DMA1 4  Interrupt                   IVG8        22
-           DMA1 5  Interrupt                   IVG8        23
-           DMA1 6  Interrupt                   IVG8        24
-           DMA1 7  Interrupt                   IVG8        25
-           DMA1 8  Interrupt                   IVG8        26
-           DMA1 9  Interrupt                   IVG8        27
-           DMA1 10 Interrupt                   IVG8        28
-           DMA1 11 Interrupt                   IVG8        29
-
-           DMA2 0  (SPORT0 RX)                 IVG9        30
-           DMA2 1  (SPORT0 TX)                 IVG9        31
-           DMA2 2  (SPORT1 RX)                 IVG9        32
-           DMA2 3  (SPORT2 TX)                 IVG9        33
-           DMA2 4  (SPI)                       IVG9        34
-           DMA2 5  (UART RX)                   IVG9        35
-           DMA2 6  (UART TX)                   IVG9        36
-           DMA2 7  Interrupt                   IVG9        37
-           DMA2 8  Interrupt                   IVG9        38
-           DMA2 9  Interrupt                   IVG9        39
-           DMA2 10 Interrupt                   IVG9        40
-           DMA2 11 Interrupt                   IVG9        41
-
-           TIMER 0  Interrupt                  IVG10       42
-           TIMER 1  Interrupt                  IVG10       43
-           TIMER 2  Interrupt                  IVG10       44
-           TIMER 3  Interrupt                  IVG10       45
-           TIMER 4  Interrupt                  IVG10       46
-           TIMER 5  Interrupt                  IVG10       47
-           TIMER 6  Interrupt                  IVG10       48
-           TIMER 7  Interrupt                  IVG10       49
-           TIMER 8  Interrupt                  IVG10       50
-           TIMER 9  Interrupt                  IVG10       51
-           TIMER 10 Interrupt                  IVG10       52
-           TIMER 11 Interrupt                  IVG10       53
-
-           Programmable Flags0 A (8)           IVG11       54
-           Programmable Flags0 B (8)           IVG11       55
-           Programmable Flags1 A (8)           IVG11       56
-           Programmable Flags1 B (8)           IVG11       57
-           Programmable Flags2 A (8)           IVG11       58
-           Programmable Flags2 B (8)           IVG11       59
-
-           MDMA1 0 write/read INT              IVG8        60
-           MDMA1 1 write/read INT              IVG8        61
-
-           MDMA2 0 write/read INT              IVG9        62
-           MDMA2 1 write/read INT              IVG9        63
-
-           IMDMA 0 write/read INT              IVG12       64
-           IMDMA 1 write/read INT              IVG12       65
-
-           Watch Dog Timer                     IVG13       66
-
-           Reserved interrupt                  IVG7        67
-           Reserved interrupt                  IVG7        68
-           Supplemental interrupt 0            IVG7        69
-           supplemental interrupt 1            IVG7        70
-
-            Softirq                            IVG14
-            System Call    --
-                 (lowest priority)             IVG15
-
- **********************************************************************/
-
-#define SYS_IRQS               71
-#define NR_PERI_INTS           64
-
-/*
- * The ABSTRACT IRQ definitions
- *  the first seven of the following are fixed,
- *  the rest you change if you need to.
- */
-/* IVG 0-6*/
-#define        IRQ_EMU                 0       /* Emulation                */
-#define        IRQ_RST                 1       /* Reset                    */
-#define        IRQ_NMI                 2       /* Non Maskable Interrupt   */
-#define        IRQ_EVX                 3       /* Exception                */
-#define        IRQ_UNUSED              4       /* Reserved interrupt       */
-#define        IRQ_HWERR               5       /* Hardware Error           */
-#define        IRQ_CORETMR             6       /* Core timer               */
-
-#define IVG_BASE               7
-/* IVG 7  */
-#define        IRQ_PLL_WAKEUP          (IVG_BASE + 0)  /* PLL Wakeup Interrupt     */
-#define        IRQ_DMA1_ERROR          (IVG_BASE + 1)  /* DMA1   Error (general)   */
-#define        IRQ_DMA_ERROR           IRQ_DMA1_ERROR  /* DMA1   Error (general)   */
-#define        IRQ_DMA2_ERROR          (IVG_BASE + 2)  /* DMA2   Error (general)   */
-#define IRQ_IMDMA_ERROR                (IVG_BASE + 3)  /* IMDMA  Error Interrupt   */
-#define        IRQ_PPI1_ERROR          (IVG_BASE + 4)  /* PPI1   Error Interrupt   */
-#define        IRQ_PPI_ERROR           IRQ_PPI1_ERROR  /* PPI1   Error Interrupt   */
-#define        IRQ_PPI2_ERROR          (IVG_BASE + 5)  /* PPI2   Error Interrupt   */
-#define        IRQ_SPORT0_ERROR        (IVG_BASE + 6)  /* SPORT0 Error Interrupt   */
-#define        IRQ_SPORT1_ERROR        (IVG_BASE + 7)  /* SPORT1 Error Interrupt   */
-#define        IRQ_SPI_ERROR           (IVG_BASE + 8)  /* SPI    Error Interrupt   */
-#define        IRQ_UART_ERROR          (IVG_BASE + 9)  /* UART   Error Interrupt   */
-#define IRQ_RESERVED_ERROR     (IVG_BASE + 10) /* Reversed     Interrupt   */
-/* IVG 8  */
-#define        IRQ_DMA1_0              (IVG_BASE + 11) /* DMA1 0  Interrupt(PPI1)  */
-#define        IRQ_PPI                 IRQ_DMA1_0      /* DMA1 0  Interrupt(PPI1)  */
-#define        IRQ_PPI0                IRQ_DMA1_0      /* DMA1 0  Interrupt(PPI1)  */
-#define        IRQ_DMA1_1              (IVG_BASE + 12) /* DMA1 1  Interrupt(PPI2)  */
-#define        IRQ_PPI1                IRQ_DMA1_1      /* DMA1 1  Interrupt(PPI2)  */
-#define        IRQ_DMA1_2              (IVG_BASE + 13) /* DMA1 2  Interrupt        */
-#define        IRQ_DMA1_3              (IVG_BASE + 14) /* DMA1 3  Interrupt        */
-#define        IRQ_DMA1_4              (IVG_BASE + 15) /* DMA1 4  Interrupt        */
-#define        IRQ_DMA1_5              (IVG_BASE + 16) /* DMA1 5  Interrupt        */
-#define        IRQ_DMA1_6              (IVG_BASE + 17) /* DMA1 6  Interrupt        */
-#define        IRQ_DMA1_7              (IVG_BASE + 18) /* DMA1 7  Interrupt        */
-#define        IRQ_DMA1_8              (IVG_BASE + 19) /* DMA1 8  Interrupt        */
-#define        IRQ_DMA1_9              (IVG_BASE + 20) /* DMA1 9  Interrupt        */
-#define        IRQ_DMA1_10             (IVG_BASE + 21) /* DMA1 10 Interrupt        */
-#define        IRQ_DMA1_11             (IVG_BASE + 22) /* DMA1 11 Interrupt        */
-/* IVG 9  */
-#define        IRQ_DMA2_0              (IVG_BASE + 23) /* DMA2 0  (SPORT0 RX)      */
-#define        IRQ_SPORT0_RX           IRQ_DMA2_0      /* DMA2 0  (SPORT0 RX)      */
-#define        IRQ_DMA2_1              (IVG_BASE + 24) /* DMA2 1  (SPORT0 TX)      */
-#define        IRQ_SPORT0_TX           IRQ_DMA2_1      /* DMA2 1  (SPORT0 TX)      */
-#define        IRQ_DMA2_2              (IVG_BASE + 25) /* DMA2 2  (SPORT1 RX)      */
-#define        IRQ_SPORT1_RX           IRQ_DMA2_2      /* DMA2 2  (SPORT1 RX)      */
-#define        IRQ_DMA2_3              (IVG_BASE + 26) /* DMA2 3  (SPORT2 TX)      */
-#define        IRQ_SPORT1_TX           IRQ_DMA2_3      /* DMA2 3  (SPORT2 TX)      */
-#define        IRQ_DMA2_4              (IVG_BASE + 27) /* DMA2 4  (SPI)            */
-#define        IRQ_SPI                 IRQ_DMA2_4      /* DMA2 4  (SPI)            */
-#define        IRQ_DMA2_5              (IVG_BASE + 28) /* DMA2 5  (UART RX)        */
-#define        IRQ_UART_RX             IRQ_DMA2_5      /* DMA2 5  (UART RX)        */
-#define        IRQ_DMA2_6              (IVG_BASE + 29) /* DMA2 6  (UART TX)        */
-#define        IRQ_UART_TX             IRQ_DMA2_6      /* DMA2 6  (UART TX)        */
-#define        IRQ_DMA2_7              (IVG_BASE + 30) /* DMA2 7  Interrupt        */
-#define        IRQ_DMA2_8              (IVG_BASE + 31) /* DMA2 8  Interrupt        */
-#define        IRQ_DMA2_9              (IVG_BASE + 32) /* DMA2 9  Interrupt        */
-#define        IRQ_DMA2_10             (IVG_BASE + 33) /* DMA2 10 Interrupt        */
-#define        IRQ_DMA2_11             (IVG_BASE + 34) /* DMA2 11 Interrupt        */
-/* IVG 10 */
-#define IRQ_TIMER0             (IVG_BASE + 35) /* TIMER 0  Interrupt       */
-#define IRQ_TIMER1             (IVG_BASE + 36) /* TIMER 1  Interrupt       */
-#define IRQ_TIMER2             (IVG_BASE + 37) /* TIMER 2  Interrupt       */
-#define IRQ_TIMER3             (IVG_BASE + 38) /* TIMER 3  Interrupt       */
-#define IRQ_TIMER4             (IVG_BASE + 39) /* TIMER 4  Interrupt       */
-#define IRQ_TIMER5             (IVG_BASE + 40) /* TIMER 5  Interrupt       */
-#define IRQ_TIMER6             (IVG_BASE + 41) /* TIMER 6  Interrupt       */
-#define IRQ_TIMER7             (IVG_BASE + 42) /* TIMER 7  Interrupt       */
-#define IRQ_TIMER8             (IVG_BASE + 43) /* TIMER 8  Interrupt       */
-#define IRQ_TIMER9             (IVG_BASE + 44) /* TIMER 9  Interrupt       */
-#define IRQ_TIMER10            (IVG_BASE + 45) /* TIMER 10 Interrupt       */
-#define IRQ_TIMER11            (IVG_BASE + 46) /* TIMER 11 Interrupt       */
-/* IVG 11 */
-#define        IRQ_PROG0_INTA          (IVG_BASE + 47) /* Programmable Flags0 A (8) */
-#define        IRQ_PROG_INTA           IRQ_PROG0_INTA  /* Programmable Flags0 A (8) */
-#define        IRQ_PROG0_INTB          (IVG_BASE + 48) /* Programmable Flags0 B (8) */
-#define        IRQ_PROG_INTB           IRQ_PROG0_INTB  /* Programmable Flags0 B (8) */
-#define        IRQ_PROG1_INTA          (IVG_BASE + 49) /* Programmable Flags1 A (8) */
-#define        IRQ_PROG1_INTB          (IVG_BASE + 50) /* Programmable Flags1 B (8) */
-#define        IRQ_PROG2_INTA          (IVG_BASE + 51) /* Programmable Flags2 A (8) */
-#define        IRQ_PROG2_INTB          (IVG_BASE + 52) /* Programmable Flags2 B (8) */
-/* IVG 8  */
-#define IRQ_DMA1_WRRD0         (IVG_BASE + 53) /* MDMA1 0 write/read INT   */
-#define IRQ_DMA_WRRD0          IRQ_DMA1_WRRD0  /* MDMA1 0 write/read INT   */
+#include <mach-common/irq.h>
+
+#define NR_PERI_INTS           (2 * 32)
+
+#define IRQ_PLL_WAKEUP         BFIN_IRQ(0)     /* PLL Wakeup Interrupt */
+#define IRQ_DMA1_ERROR         BFIN_IRQ(1)     /* DMA1   Error (general) */
+#define IRQ_DMA_ERROR          IRQ_DMA1_ERROR  /* DMA1   Error (general) */
+#define IRQ_DMA2_ERROR         BFIN_IRQ(2)     /* DMA2   Error (general) */
+#define IRQ_IMDMA_ERROR                BFIN_IRQ(3)     /* IMDMA  Error Interrupt */
+#define IRQ_PPI1_ERROR         BFIN_IRQ(4)     /* PPI1   Error Interrupt */
+#define IRQ_PPI_ERROR          IRQ_PPI1_ERROR  /* PPI1   Error Interrupt */
+#define IRQ_PPI2_ERROR         BFIN_IRQ(5)     /* PPI2   Error Interrupt */
+#define IRQ_SPORT0_ERROR       BFIN_IRQ(6)     /* SPORT0 Error Interrupt */
+#define IRQ_SPORT1_ERROR       BFIN_IRQ(7)     /* SPORT1 Error Interrupt */
+#define IRQ_SPI_ERROR          BFIN_IRQ(8)     /* SPI    Error Interrupt */
+#define IRQ_UART_ERROR         BFIN_IRQ(9)     /* UART   Error Interrupt */
+#define IRQ_RESERVED_ERROR     BFIN_IRQ(10)    /* Reversed */
+#define IRQ_DMA1_0             BFIN_IRQ(11)    /* DMA1 0  Interrupt(PPI1) */
+#define IRQ_PPI                        IRQ_DMA1_0      /* DMA1 0  Interrupt(PPI1) */
+#define IRQ_PPI0               IRQ_DMA1_0      /* DMA1 0  Interrupt(PPI1) */
+#define IRQ_DMA1_1             BFIN_IRQ(12)    /* DMA1 1  Interrupt(PPI2) */
+#define IRQ_PPI1               IRQ_DMA1_1      /* DMA1 1  Interrupt(PPI2) */
+#define IRQ_DMA1_2             BFIN_IRQ(13)    /* DMA1 2  Interrupt */
+#define IRQ_DMA1_3             BFIN_IRQ(14)    /* DMA1 3  Interrupt */
+#define IRQ_DMA1_4             BFIN_IRQ(15)    /* DMA1 4  Interrupt */
+#define IRQ_DMA1_5             BFIN_IRQ(16)    /* DMA1 5  Interrupt */
+#define IRQ_DMA1_6             BFIN_IRQ(17)    /* DMA1 6  Interrupt */
+#define IRQ_DMA1_7             BFIN_IRQ(18)    /* DMA1 7  Interrupt */
+#define IRQ_DMA1_8             BFIN_IRQ(19)    /* DMA1 8  Interrupt */
+#define IRQ_DMA1_9             BFIN_IRQ(20)    /* DMA1 9  Interrupt */
+#define IRQ_DMA1_10            BFIN_IRQ(21)    /* DMA1 10 Interrupt */
+#define IRQ_DMA1_11            BFIN_IRQ(22)    /* DMA1 11 Interrupt */
+#define IRQ_DMA2_0             BFIN_IRQ(23)    /* DMA2 0  (SPORT0 RX) */
+#define IRQ_SPORT0_RX          IRQ_DMA2_0      /* DMA2 0  (SPORT0 RX) */
+#define IRQ_DMA2_1             BFIN_IRQ(24)    /* DMA2 1  (SPORT0 TX) */
+#define IRQ_SPORT0_TX          IRQ_DMA2_1      /* DMA2 1  (SPORT0 TX) */
+#define IRQ_DMA2_2             BFIN_IRQ(25)    /* DMA2 2  (SPORT1 RX) */
+#define IRQ_SPORT1_RX          IRQ_DMA2_2      /* DMA2 2  (SPORT1 RX) */
+#define IRQ_DMA2_3             BFIN_IRQ(26)    /* DMA2 3  (SPORT2 TX) */
+#define IRQ_SPORT1_TX          IRQ_DMA2_3      /* DMA2 3  (SPORT2 TX) */
+#define IRQ_DMA2_4             BFIN_IRQ(27)    /* DMA2 4  (SPI) */
+#define IRQ_SPI                        IRQ_DMA2_4      /* DMA2 4  (SPI) */
+#define IRQ_DMA2_5             BFIN_IRQ(28)    /* DMA2 5  (UART RX) */
+#define IRQ_UART_RX            IRQ_DMA2_5      /* DMA2 5  (UART RX) */
+#define IRQ_DMA2_6             BFIN_IRQ(29)    /* DMA2 6  (UART TX) */
+#define IRQ_UART_TX            IRQ_DMA2_6      /* DMA2 6  (UART TX) */
+#define IRQ_DMA2_7             BFIN_IRQ(30)    /* DMA2 7  Interrupt */
+#define IRQ_DMA2_8             BFIN_IRQ(31)    /* DMA2 8  Interrupt */
+#define IRQ_DMA2_9             BFIN_IRQ(32)    /* DMA2 9  Interrupt */
+#define IRQ_DMA2_10            BFIN_IRQ(33)    /* DMA2 10 Interrupt */
+#define IRQ_DMA2_11            BFIN_IRQ(34)    /* DMA2 11 Interrupt */
+#define IRQ_TIMER0             BFIN_IRQ(35)    /* TIMER 0  Interrupt */
+#define IRQ_TIMER1             BFIN_IRQ(36)    /* TIMER 1  Interrupt */
+#define IRQ_TIMER2             BFIN_IRQ(37)    /* TIMER 2  Interrupt */
+#define IRQ_TIMER3             BFIN_IRQ(38)    /* TIMER 3  Interrupt */
+#define IRQ_TIMER4             BFIN_IRQ(39)    /* TIMER 4  Interrupt */
+#define IRQ_TIMER5             BFIN_IRQ(40)    /* TIMER 5  Interrupt */
+#define IRQ_TIMER6             BFIN_IRQ(41)    /* TIMER 6  Interrupt */
+#define IRQ_TIMER7             BFIN_IRQ(42)    /* TIMER 7  Interrupt */
+#define IRQ_TIMER8             BFIN_IRQ(43)    /* TIMER 8  Interrupt */
+#define IRQ_TIMER9             BFIN_IRQ(44)    /* TIMER 9  Interrupt */
+#define IRQ_TIMER10            BFIN_IRQ(45)    /* TIMER 10 Interrupt */
+#define IRQ_TIMER11            BFIN_IRQ(46)    /* TIMER 11 Interrupt */
+#define IRQ_PROG0_INTA         BFIN_IRQ(47)    /* Programmable Flags0 A (8) */
+#define IRQ_PROG_INTA          IRQ_PROG0_INTA  /* Programmable Flags0 A (8) */
+#define IRQ_PROG0_INTB         BFIN_IRQ(48)    /* Programmable Flags0 B (8) */
+#define IRQ_PROG_INTB          IRQ_PROG0_INTB  /* Programmable Flags0 B (8) */
+#define IRQ_PROG1_INTA         BFIN_IRQ(49)    /* Programmable Flags1 A (8) */
+#define IRQ_PROG1_INTB         BFIN_IRQ(50)    /* Programmable Flags1 B (8) */
+#define IRQ_PROG2_INTA         BFIN_IRQ(51)    /* Programmable Flags2 A (8) */
+#define IRQ_PROG2_INTB         BFIN_IRQ(52)    /* Programmable Flags2 B (8) */
+#define IRQ_DMA1_WRRD0         BFIN_IRQ(53)    /* MDMA1 0 write/read INT */
+#define IRQ_DMA_WRRD0          IRQ_DMA1_WRRD0  /* MDMA1 0 write/read INT */
 #define IRQ_MEM_DMA0           IRQ_DMA1_WRRD0
-#define IRQ_DMA1_WRRD1         (IVG_BASE + 54) /* MDMA1 1 write/read INT   */
-#define IRQ_DMA_WRRD1          IRQ_DMA1_WRRD1  /* MDMA1 1 write/read INT   */
+#define IRQ_DMA1_WRRD1         BFIN_IRQ(54)    /* MDMA1 1 write/read INT */
+#define IRQ_DMA_WRRD1          IRQ_DMA1_WRRD1  /* MDMA1 1 write/read INT */
 #define IRQ_MEM_DMA1           IRQ_DMA1_WRRD1
-/* IVG 9  */
-#define IRQ_DMA2_WRRD0         (IVG_BASE + 55) /* MDMA2 0 write/read INT   */
+#define IRQ_DMA2_WRRD0         BFIN_IRQ(55)    /* MDMA2 0 write/read INT */
 #define IRQ_MEM_DMA2           IRQ_DMA2_WRRD0
-#define IRQ_DMA2_WRRD1         (IVG_BASE + 56) /* MDMA2 1 write/read INT   */
+#define IRQ_DMA2_WRRD1         BFIN_IRQ(56)    /* MDMA2 1 write/read INT */
 #define IRQ_MEM_DMA3           IRQ_DMA2_WRRD1
-/* IVG 12 */
-#define IRQ_IMDMA_WRRD0                (IVG_BASE + 57) /* IMDMA 0 write/read INT   */
+#define IRQ_IMDMA_WRRD0                BFIN_IRQ(57)    /* IMDMA 0 write/read INT */
 #define IRQ_IMEM_DMA0          IRQ_IMDMA_WRRD0
-#define IRQ_IMDMA_WRRD1                (IVG_BASE + 58) /* IMDMA 1 write/read INT   */
+#define IRQ_IMDMA_WRRD1                BFIN_IRQ(58)    /* IMDMA 1 write/read INT */
 #define IRQ_IMEM_DMA1          IRQ_IMDMA_WRRD1
-/* IVG 13 */
-#define        IRQ_WATCH               (IVG_BASE + 59) /* Watch Dog Timer          */
-/* IVG 7  */
-#define IRQ_RESERVED_1         (IVG_BASE + 60) /* Reserved interrupt       */
-#define IRQ_RESERVED_2         (IVG_BASE + 61) /* Reserved interrupt       */
-#define IRQ_SUPPLE_0           (IVG_BASE + 62) /* Supplemental interrupt 0 */
-#define IRQ_SUPPLE_1           (IVG_BASE + 63) /* supplemental interrupt 1 */
+#define IRQ_WATCH              BFIN_IRQ(59)    /* Watch Dog Timer */
+#define IRQ_RESERVED_1         BFIN_IRQ(60)    /* Reserved interrupt */
+#define IRQ_RESERVED_2         BFIN_IRQ(61)    /* Reserved interrupt */
+#define IRQ_SUPPLE_0           BFIN_IRQ(62)    /* Supplemental interrupt 0 */
+#define IRQ_SUPPLE_1           BFIN_IRQ(63)    /* supplemental interrupt 1 */
+
+#define SYS_IRQS               71
 
 #define IRQ_PF0                        73
 #define IRQ_PF1                        74
 #define GPIO_IRQ_BASE          IRQ_PF0
 
 #define NR_MACH_IRQS           (IRQ_PF47 + 1)
-#define NR_IRQS                        (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7                   7
-#define IVG8                   8
-#define IVG9                   9
-#define IVG10                  10
-#define IVG11                  11
-#define IVG12                  12
-#define IVG13                  13
-#define IVG14                  14
-#define IVG15                  15
-
-/*
- * DEFAULT PRIORITIES:
- */
-
-#define        CONFIG_DEF_PLL_WAKEUP           7
-#define        CONFIG_DEF_DMA1_ERROR           7
-#define        CONFIG_DEF_DMA2_ERROR           7
-#define CONFIG_DEF_IMDMA_ERROR         7
-#define        CONFIG_DEF_PPI1_ERROR           7
-#define        CONFIG_DEF_PPI2_ERROR           7
-#define        CONFIG_DEF_SPORT0_ERROR         7
-#define        CONFIG_DEF_SPORT1_ERROR         7
-#define        CONFIG_DEF_SPI_ERROR            7
-#define        CONFIG_DEF_UART_ERROR           7
-#define CONFIG_DEF_RESERVED_ERROR      7
-#define        CONFIG_DEF_DMA1_0               8
-#define        CONFIG_DEF_DMA1_1               8
-#define        CONFIG_DEF_DMA1_2               8
-#define        CONFIG_DEF_DMA1_3               8
-#define        CONFIG_DEF_DMA1_4               8
-#define        CONFIG_DEF_DMA1_5               8
-#define        CONFIG_DEF_DMA1_6               8
-#define        CONFIG_DEF_DMA1_7               8
-#define        CONFIG_DEF_DMA1_8               8
-#define        CONFIG_DEF_DMA1_9               8
-#define        CONFIG_DEF_DMA1_10              8
-#define        CONFIG_DEF_DMA1_11              8
-#define        CONFIG_DEF_DMA2_0               9
-#define        CONFIG_DEF_DMA2_1               9
-#define        CONFIG_DEF_DMA2_2               9
-#define        CONFIG_DEF_DMA2_3               9
-#define        CONFIG_DEF_DMA2_4               9
-#define        CONFIG_DEF_DMA2_5               9
-#define        CONFIG_DEF_DMA2_6               9
-#define        CONFIG_DEF_DMA2_7               9
-#define        CONFIG_DEF_DMA2_8               9
-#define        CONFIG_DEF_DMA2_9               9
-#define        CONFIG_DEF_DMA2_10              9
-#define        CONFIG_DEF_DMA2_11              9
-#define CONFIG_DEF_TIMER0              10
-#define CONFIG_DEF_TIMER1              10
-#define CONFIG_DEF_TIMER2              10
-#define CONFIG_DEF_TIMER3              10
-#define CONFIG_DEF_TIMER4              10
-#define CONFIG_DEF_TIMER5              10
-#define CONFIG_DEF_TIMER6              10
-#define CONFIG_DEF_TIMER7              10
-#define CONFIG_DEF_TIMER8              10
-#define CONFIG_DEF_TIMER9              10
-#define CONFIG_DEF_TIMER10             10
-#define CONFIG_DEF_TIMER11             10
-#define        CONFIG_DEF_PROG0_INTA           11
-#define        CONFIG_DEF_PROG0_INTB           11
-#define        CONFIG_DEF_PROG1_INTA           11
-#define        CONFIG_DEF_PROG1_INTB           11
-#define        CONFIG_DEF_PROG2_INTA           11
-#define        CONFIG_DEF_PROG2_INTB           11
-#define CONFIG_DEF_DMA1_WRRD0          8
-#define CONFIG_DEF_DMA1_WRRD1          8
-#define CONFIG_DEF_DMA2_WRRD0          9
-#define CONFIG_DEF_DMA2_WRRD1          9
-#define CONFIG_DEF_IMDMA_WRRD0         12
-#define CONFIG_DEF_IMDMA_WRRD1         12
-#define        CONFIG_DEF_WATCH                13
-#define CONFIG_DEF_RESERVED_1          7
-#define CONFIG_DEF_RESERVED_2          7
-#define CONFIG_DEF_SUPPLE_0            7
-#define CONFIG_DEF_SUPPLE_1            7
 
 /* IAR0 BIT FIELDS */
-#define        IRQ_PLL_WAKEUP_POS                      0
-#define        IRQ_DMA1_ERROR_POS                      4
-#define        IRQ_DMA2_ERROR_POS                      8
-#define IRQ_IMDMA_ERROR_POS                    12
-#define        IRQ_PPI0_ERROR_POS                      16
-#define        IRQ_PPI1_ERROR_POS                      20
-#define        IRQ_SPORT0_ERROR_POS            24
-#define        IRQ_SPORT1_ERROR_POS            28
+#define IRQ_PLL_WAKEUP_POS     0
+#define IRQ_DMA1_ERROR_POS     4
+#define IRQ_DMA2_ERROR_POS     8
+#define IRQ_IMDMA_ERROR_POS    12
+#define IRQ_PPI0_ERROR_POS     16
+#define IRQ_PPI1_ERROR_POS     20
+#define IRQ_SPORT0_ERROR_POS   24
+#define IRQ_SPORT1_ERROR_POS   28
+
 /* IAR1 BIT FIELDS */
-#define        IRQ_SPI_ERROR_POS                       0
-#define        IRQ_UART_ERROR_POS                      4
-#define IRQ_RESERVED_ERROR_POS         8
-#define        IRQ_DMA1_0_POS                  12
-#define        IRQ_DMA1_1_POS                  16
-#define IRQ_DMA1_2_POS                 20
-#define IRQ_DMA1_3_POS                 24
-#define IRQ_DMA1_4_POS                 28
+#define IRQ_SPI_ERROR_POS      0
+#define IRQ_UART_ERROR_POS     4
+#define IRQ_RESERVED_ERROR_POS 8
+#define IRQ_DMA1_0_POS         12
+#define IRQ_DMA1_1_POS         16
+#define IRQ_DMA1_2_POS         20
+#define IRQ_DMA1_3_POS         24
+#define IRQ_DMA1_4_POS         28
+
 /* IAR2 BIT FIELDS */
-#define IRQ_DMA1_5_POS                 0
-#define IRQ_DMA1_6_POS                 4
-#define IRQ_DMA1_7_POS                 8
-#define IRQ_DMA1_8_POS                 12
-#define IRQ_DMA1_9_POS                 16
-#define IRQ_DMA1_10_POS                        20
-#define IRQ_DMA1_11_POS                        24
-#define IRQ_DMA2_0_POS                 28
+#define IRQ_DMA1_5_POS         0
+#define IRQ_DMA1_6_POS         4
+#define IRQ_DMA1_7_POS         8
+#define IRQ_DMA1_8_POS         12
+#define IRQ_DMA1_9_POS         16
+#define IRQ_DMA1_10_POS                20
+#define IRQ_DMA1_11_POS                24
+#define IRQ_DMA2_0_POS         28
+
 /* IAR3 BIT FIELDS */
-#define IRQ_DMA2_1_POS                 0
-#define IRQ_DMA2_2_POS                 4
-#define IRQ_DMA2_3_POS                 8
-#define IRQ_DMA2_4_POS                 12
-#define IRQ_DMA2_5_POS                 16
-#define IRQ_DMA2_6_POS                 20
-#define IRQ_DMA2_7_POS                 24
-#define IRQ_DMA2_8_POS                 28
+#define IRQ_DMA2_1_POS         0
+#define IRQ_DMA2_2_POS         4
+#define IRQ_DMA2_3_POS         8
+#define IRQ_DMA2_4_POS         12
+#define IRQ_DMA2_5_POS         16
+#define IRQ_DMA2_6_POS         20
+#define IRQ_DMA2_7_POS         24
+#define IRQ_DMA2_8_POS         28
+
 /* IAR4 BIT FIELDS */
-#define IRQ_DMA2_9_POS                 0
-#define IRQ_DMA2_10_POS                        4
-#define IRQ_DMA2_11_POS                        8
-#define IRQ_TIMER0_POS                 12
-#define IRQ_TIMER1_POS                 16
-#define IRQ_TIMER2_POS                 20
-#define IRQ_TIMER3_POS                 24
-#define IRQ_TIMER4_POS                 28
+#define IRQ_DMA2_9_POS         0
+#define IRQ_DMA2_10_POS                4
+#define IRQ_DMA2_11_POS                8
+#define IRQ_TIMER0_POS         12
+#define IRQ_TIMER1_POS         16
+#define IRQ_TIMER2_POS         20
+#define IRQ_TIMER3_POS         24
+#define IRQ_TIMER4_POS         28
+
 /* IAR5 BIT FIELDS */
-#define IRQ_TIMER5_POS                 0
-#define IRQ_TIMER6_POS                 4
-#define IRQ_TIMER7_POS                 8
-#define IRQ_TIMER8_POS                 12
-#define IRQ_TIMER9_POS                 16
-#define IRQ_TIMER10_POS                        20
-#define IRQ_TIMER11_POS                        24
-#define IRQ_PROG0_INTA_POS                     28
+#define IRQ_TIMER5_POS         0
+#define IRQ_TIMER6_POS         4
+#define IRQ_TIMER7_POS         8
+#define IRQ_TIMER8_POS         12
+#define IRQ_TIMER9_POS         16
+#define IRQ_TIMER10_POS                20
+#define IRQ_TIMER11_POS                24
+#define IRQ_PROG0_INTA_POS     28
+
 /* IAR6 BIT FIELDS */
-#define IRQ_PROG0_INTB_POS                     0
-#define IRQ_PROG1_INTA_POS                     4
-#define IRQ_PROG1_INTB_POS                     8
-#define IRQ_PROG2_INTA_POS                     12
-#define IRQ_PROG2_INTB_POS                     16
-#define IRQ_DMA1_WRRD0_POS                     20
-#define IRQ_DMA1_WRRD1_POS                     24
-#define IRQ_DMA2_WRRD0_POS                     28
-/* IAR7 BIT FIELDS */
-#define IRQ_DMA2_WRRD1_POS                     0
-#define IRQ_IMDMA_WRRD0_POS                    4
-#define IRQ_IMDMA_WRRD1_POS                    8
-#define        IRQ_WDTIMER_POS                 12
-#define IRQ_RESERVED_1_POS                     16
-#define IRQ_RESERVED_2_POS                     20
-#define IRQ_SUPPLE_0_POS                       24
-#define IRQ_SUPPLE_1_POS                       28
+#define IRQ_PROG0_INTB_POS     0
+#define IRQ_PROG1_INTA_POS     4
+#define IRQ_PROG1_INTB_POS     8
+#define IRQ_PROG2_INTA_POS     12
+#define IRQ_PROG2_INTB_POS     16
+#define IRQ_DMA1_WRRD0_POS     20
+#define IRQ_DMA1_WRRD1_POS     24
+#define IRQ_DMA2_WRRD0_POS     28
 
-#endif                         /* _BF561_IRQ_H_ */
+/* IAR7 BIT FIELDS */
+#define IRQ_DMA2_WRRD1_POS     0
+#define IRQ_IMDMA_WRRD0_POS    4
+#define IRQ_IMDMA_WRRD1_POS    8
+#define IRQ_WDTIMER_POS                12
+#define IRQ_RESERVED_1_POS     16
+#define IRQ_RESERVED_2_POS     20
+#define IRQ_SUPPLE_0_POS       24
+#define IRQ_SUPPLE_1_POS       28
+
+#endif
index 7b07740cf68cdf828c101cced2e99bfe68e59613..85abd8be134382821e60af23d57c9117e875b93e 100644 (file)
@@ -24,17 +24,23 @@ static DEFINE_SPINLOCK(boot_lock);
 
 void __init platform_init_cpus(void)
 {
-       cpu_set(0, cpu_possible_map); /* CoreA */
-       cpu_set(1, cpu_possible_map); /* CoreB */
+       struct cpumask mask;
+
+       cpumask_set_cpu(0, &mask); /* CoreA */
+       cpumask_set_cpu(1, &mask); /* CoreB */
+       init_cpu_possible(&mask);
 }
 
 void __init platform_prepare_cpus(unsigned int max_cpus)
 {
+       struct cpumask mask;
+
        bfin_relocate_coreb_l1_mem();
 
        /* Both cores ought to be present on a bf561! */
-       cpu_set(0, cpu_present_map); /* CoreA */
-       cpu_set(1, cpu_present_map); /* CoreB */
+       cpumask_set_cpu(0, &mask); /* CoreA */
+       cpumask_set_cpu(1, &mask); /* CoreB */
+       init_cpu_present(&mask);
 }
 
 int __init setup_profiling_timer(unsigned int multiplier) /* not supported */
@@ -62,9 +68,6 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
        bfin_write_SICB_IWR1(IWR_DISABLE_ALL);
        SSYNC();
 
-       /* Store CPU-private information to the cpu_data array. */
-       bfin_setup_cpudata(cpu);
-
        /* We are done with local CPU inits, unblock the boot CPU. */
        set_cpu_online(cpu, true);
        spin_lock(&boot_lock);
index 5e4112e518a992c2566c14b893f5d17f05481076..f5685a496c58d648e387f4fb03c56efe9bf6cbcc 100644 (file)
@@ -85,10 +85,11 @@ static void bfin_wakeup_cpu(void)
 {
        unsigned int cpu;
        unsigned int this_cpu = smp_processor_id();
-       cpumask_t mask = cpu_online_map;
+       cpumask_t mask;
 
-       cpu_clear(this_cpu, mask);
-       for_each_cpu_mask(cpu, mask)
+       cpumask_copy(&mask, cpu_online_mask);
+       cpumask_clear_cpu(this_cpu, &mask);
+       for_each_cpu(cpu, &mask)
                platform_send_ipi_cpu(cpu, IRQ_SUPPLE_0);
 }
 
index f96933f48a7fd933c9fce9df72ef182cf66c5cce..225d311c97013048a6920b578b1956c57f6d57a2 100644 (file)
@@ -1753,6 +1753,8 @@ ENTRY(_sys_call_table)
        .long _sys_open_by_handle_at
        .long _sys_clock_adjtime
        .long _sys_syncfs
+       .long _sys_setns
+       .long _sys_sendmmsg             /* 380 */
 
        .rept NR_syscalls-(.-_sys_call_table)/4
        .long _sys_ni_syscall
index 43d9fb195c1ee7a82a548e34e08fba4802e128bc..1177369f9922533f839b5a02091506384a8addd4 100644 (file)
 #ifdef CONFIG_IPIPE
 #include <linux/ipipe.h>
 #endif
-#ifdef CONFIG_KGDB
-#include <linux/kgdb.h>
-#endif
 #include <asm/traps.h>
 #include <asm/blackfin.h>
 #include <asm/gpio.h>
 #include <asm/irq_handler.h>
 #include <asm/dpmc.h>
-#include <asm/bfin5xx_spi.h>
-#include <asm/bfin_sport.h>
-#include <asm/bfin_can.h>
 
 #define SIC_SYSIRQ(irq)        (irq - (IRQ_CORETMR + 1))
 
-#ifdef BF537_FAMILY
-# define BF537_GENERIC_ERROR_INT_DEMUX
-# define SPI_ERR_MASK   (BIT_STAT_TXCOL | BIT_STAT_RBSY | BIT_STAT_MODF | BIT_STAT_TXE)        /* SPI_STAT */
-# define SPORT_ERR_MASK (ROVF | RUVF | TOVF | TUVF)    /* SPORT_STAT */
-# define PPI_ERR_MASK   (0xFFFF & ~FLD)        /* PPI_STATUS */
-# define EMAC_ERR_MASK  (PHYINT | MMCINT | RXFSINT | TXFSINT | WAKEDET | RXDMAERR | TXDMAERR | STMDONE)        /* EMAC_SYSTAT */
-# define UART_ERR_MASK  (0x6)  /* UART_IIR */
-# define CAN_ERR_MASK   (EWTIF | EWRIF | EPIF | BOIF | WUIF | UIAIF | AAIF | RMLIF | UCEIF | EXTIF | ADIF)     /* CAN_GIF */
-#else
-# undef BF537_GENERIC_ERROR_INT_DEMUX
-#endif
-
 /*
  * NOTES:
  * - we have separated the physical Hardware interrupt from the
@@ -63,22 +45,19 @@ unsigned long bfin_irq_flags = 0x1f;
 EXPORT_SYMBOL(bfin_irq_flags);
 #endif
 
-/* The number of spurious interrupts */
-atomic_t num_spurious;
-
 #ifdef CONFIG_PM
 unsigned long bfin_sic_iwr[3]; /* Up to 3 SIC_IWRx registers */
 unsigned vr_wakeup;
 #endif
 
-struct ivgx {
+static struct ivgx {
        /* irq number for request_irq, available in mach-bf5xx/irq.h */
        unsigned int irqno;
        /* corresponding bit in the SIC_ISR register */
        unsigned int isrflag;
 } ivg_table[NR_PERI_INTS];
 
-struct ivg_slice {
+static struct ivg_slice {
        /* position of first irq in ivg_table for given ivg */
        struct ivgx *ifirst;
        struct ivgx *istop;
@@ -125,7 +104,7 @@ static void __init search_IAR(void)
  * This is for core internal IRQs
  */
 
-static void bfin_ack_noop(struct irq_data *d)
+void bfin_ack_noop(struct irq_data *d)
 {
        /* Dummy function.  */
 }
@@ -154,26 +133,24 @@ static void bfin_core_unmask_irq(struct irq_data *d)
        return;
 }
 
-static void bfin_internal_mask_irq(unsigned int irq)
+void bfin_internal_mask_irq(unsigned int irq)
 {
-       unsigned long flags;
+       unsigned long flags = hard_local_irq_save();
 
-#ifdef CONFIG_BF53x
-       flags = hard_local_irq_save();
-       bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
-                            ~(1 << SIC_SYSIRQ(irq)));
-#else
-       unsigned mask_bank, mask_bit;
-       flags = hard_local_irq_save();
-       mask_bank = SIC_SYSIRQ(irq) / 32;
-       mask_bit = SIC_SYSIRQ(irq) % 32;
+#ifdef SIC_IMASK0
+       unsigned mask_bank = SIC_SYSIRQ(irq) / 32;
+       unsigned mask_bit = SIC_SYSIRQ(irq) % 32;
        bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) &
                             ~(1 << mask_bit));
-#ifdef CONFIG_SMP
+# ifdef CONFIG_SMP
        bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) &
                             ~(1 << mask_bit));
+# endif
+#else
+       bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
+                            ~(1 << SIC_SYSIRQ(irq)));
 #endif
-#endif
+
        hard_local_irq_restore(flags);
 }
 
@@ -186,33 +163,31 @@ static void bfin_internal_mask_irq_chip(struct irq_data *d)
 static void bfin_internal_unmask_irq_affinity(unsigned int irq,
                const struct cpumask *affinity)
 #else
-static void bfin_internal_unmask_irq(unsigned int irq)
+void bfin_internal_unmask_irq(unsigned int irq)
 #endif
 {
-       unsigned long flags;
+       unsigned long flags = hard_local_irq_save();
 
-#ifdef CONFIG_BF53x
-       flags = hard_local_irq_save();
-       bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
-                            (1 << SIC_SYSIRQ(irq)));
-#else
-       unsigned mask_bank, mask_bit;
-       flags = hard_local_irq_save();
-       mask_bank = SIC_SYSIRQ(irq) / 32;
-       mask_bit = SIC_SYSIRQ(irq) % 32;
-#ifdef CONFIG_SMP
+#ifdef SIC_IMASK0
+       unsigned mask_bank = SIC_SYSIRQ(irq) / 32;
+       unsigned mask_bit = SIC_SYSIRQ(irq) % 32;
+# ifdef CONFIG_SMP
        if (cpumask_test_cpu(0, affinity))
-#endif
+# endif
                bfin_write_SIC_IMASK(mask_bank,
                        bfin_read_SIC_IMASK(mask_bank) |
                        (1 << mask_bit));
-#ifdef CONFIG_SMP
+# ifdef CONFIG_SMP
        if (cpumask_test_cpu(1, affinity))
                bfin_write_SICB_IMASK(mask_bank,
                        bfin_read_SICB_IMASK(mask_bank) |
                        (1 << mask_bit));
+# endif
+#else
+       bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
+                            (1 << SIC_SYSIRQ(irq)));
 #endif
-#endif
+
        hard_local_irq_restore(flags);
 }
 
@@ -295,6 +270,8 @@ static int bfin_internal_set_wake_chip(struct irq_data *d, unsigned int state)
 {
        return bfin_internal_set_wake(d->irq, state);
 }
+#else
+# define bfin_internal_set_wake_chip NULL
 #endif
 
 static struct irq_chip bfin_core_irqchip = {
@@ -315,12 +292,10 @@ static struct irq_chip bfin_internal_irqchip = {
 #ifdef CONFIG_SMP
        .irq_set_affinity = bfin_internal_set_affinity,
 #endif
-#ifdef CONFIG_PM
        .irq_set_wake = bfin_internal_set_wake_chip,
-#endif
 };
 
-static void bfin_handle_irq(unsigned irq)
+void bfin_handle_irq(unsigned irq)
 {
 #ifdef CONFIG_IPIPE
        struct pt_regs regs;    /* Contents not used. */
@@ -332,102 +307,6 @@ static void bfin_handle_irq(unsigned irq)
 #endif  /* !CONFIG_IPIPE */
 }
 
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
-static int error_int_mask;
-
-static void bfin_generic_error_mask_irq(struct irq_data *d)
-{
-       error_int_mask &= ~(1L << (d->irq - IRQ_PPI_ERROR));
-       if (!error_int_mask)
-               bfin_internal_mask_irq(IRQ_GENERIC_ERROR);
-}
-
-static void bfin_generic_error_unmask_irq(struct irq_data *d)
-{
-       bfin_internal_unmask_irq(IRQ_GENERIC_ERROR);
-       error_int_mask |= 1L << (d->irq - IRQ_PPI_ERROR);
-}
-
-static struct irq_chip bfin_generic_error_irqchip = {
-       .name = "ERROR",
-       .irq_ack = bfin_ack_noop,
-       .irq_mask_ack = bfin_generic_error_mask_irq,
-       .irq_mask = bfin_generic_error_mask_irq,
-       .irq_unmask = bfin_generic_error_unmask_irq,
-};
-
-static void bfin_demux_error_irq(unsigned int int_err_irq,
-                                struct irq_desc *inta_desc)
-{
-       int irq = 0;
-
-#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
-       if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK)
-               irq = IRQ_MAC_ERROR;
-       else
-#endif
-       if (bfin_read_SPORT0_STAT() & SPORT_ERR_MASK)
-               irq = IRQ_SPORT0_ERROR;
-       else if (bfin_read_SPORT1_STAT() & SPORT_ERR_MASK)
-               irq = IRQ_SPORT1_ERROR;
-       else if (bfin_read_PPI_STATUS() & PPI_ERR_MASK)
-               irq = IRQ_PPI_ERROR;
-       else if (bfin_read_CAN_GIF() & CAN_ERR_MASK)
-               irq = IRQ_CAN_ERROR;
-       else if (bfin_read_SPI_STAT() & SPI_ERR_MASK)
-               irq = IRQ_SPI_ERROR;
-       else if ((bfin_read_UART0_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
-               irq = IRQ_UART0_ERROR;
-       else if ((bfin_read_UART1_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
-               irq = IRQ_UART1_ERROR;
-
-       if (irq) {
-               if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR)))
-                       bfin_handle_irq(irq);
-               else {
-
-                       switch (irq) {
-                       case IRQ_PPI_ERROR:
-                               bfin_write_PPI_STATUS(PPI_ERR_MASK);
-                               break;
-#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
-                       case IRQ_MAC_ERROR:
-                               bfin_write_EMAC_SYSTAT(EMAC_ERR_MASK);
-                               break;
-#endif
-                       case IRQ_SPORT0_ERROR:
-                               bfin_write_SPORT0_STAT(SPORT_ERR_MASK);
-                               break;
-
-                       case IRQ_SPORT1_ERROR:
-                               bfin_write_SPORT1_STAT(SPORT_ERR_MASK);
-                               break;
-
-                       case IRQ_CAN_ERROR:
-                               bfin_write_CAN_GIS(CAN_ERR_MASK);
-                               break;
-
-                       case IRQ_SPI_ERROR:
-                               bfin_write_SPI_STAT(SPI_ERR_MASK);
-                               break;
-
-                       default:
-                               break;
-                       }
-
-                       pr_debug("IRQ %d:"
-                                " MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n",
-                                irq);
-               }
-       } else
-               printk(KERN_ERR
-                      "%s : %s : LINE %d :\nIRQ ?: PERIPHERAL ERROR"
-                      " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
-                      __func__, __FILE__, __LINE__);
-
-}
-#endif                         /* BF537_GENERIC_ERROR_INT_DEMUX */
-
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
 static int mac_stat_int_mask;
 
@@ -468,7 +347,7 @@ static void bfin_mac_status_mask_irq(struct irq_data *d)
        unsigned int irq = d->irq;
 
        mac_stat_int_mask &= ~(1L << (irq - IRQ_MAC_PHYINT));
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+#ifdef BF537_FAMILY
        switch (irq) {
        case IRQ_MAC_PHYINT:
                bfin_write_EMAC_SYSCTL(bfin_read_EMAC_SYSCTL() & ~PHYIE);
@@ -487,7 +366,7 @@ static void bfin_mac_status_unmask_irq(struct irq_data *d)
 {
        unsigned int irq = d->irq;
 
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+#ifdef BF537_FAMILY
        switch (irq) {
        case IRQ_MAC_PHYINT:
                bfin_write_EMAC_SYSCTL(bfin_read_EMAC_SYSCTL() | PHYIE);
@@ -505,12 +384,14 @@ static void bfin_mac_status_unmask_irq(struct irq_data *d)
 #ifdef CONFIG_PM
 int bfin_mac_status_set_wake(struct irq_data *d, unsigned int state)
 {
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+#ifdef BF537_FAMILY
        return bfin_internal_set_wake(IRQ_GENERIC_ERROR, state);
 #else
        return bfin_internal_set_wake(IRQ_MAC_ERROR, state);
 #endif
 }
+#else
+# define bfin_mac_status_set_wake NULL
 #endif
 
 static struct irq_chip bfin_mac_status_irqchip = {
@@ -519,13 +400,11 @@ static struct irq_chip bfin_mac_status_irqchip = {
        .irq_mask_ack = bfin_mac_status_mask_irq,
        .irq_mask = bfin_mac_status_mask_irq,
        .irq_unmask = bfin_mac_status_unmask_irq,
-#ifdef CONFIG_PM
        .irq_set_wake = bfin_mac_status_set_wake,
-#endif
 };
 
-static void bfin_demux_mac_status_irq(unsigned int int_err_irq,
-                                struct irq_desc *inta_desc)
+void bfin_demux_mac_status_irq(unsigned int int_err_irq,
+                              struct irq_desc *inta_desc)
 {
        int i, irq = 0;
        u32 status = bfin_read_EMAC_SYSTAT();
@@ -680,29 +559,48 @@ static int bfin_gpio_irq_type(struct irq_data *d, unsigned int type)
 }
 
 #ifdef CONFIG_PM
-int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
+static int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
 {
        return gpio_pm_wakeup_ctrl(irq_to_gpio(d->irq), state);
 }
+#else
+# define bfin_gpio_set_wake NULL
 #endif
 
-static void bfin_demux_gpio_irq(unsigned int inta_irq,
-                               struct irq_desc *desc)
+static void bfin_demux_gpio_block(unsigned int irq)
 {
-       unsigned int i, gpio, mask, irq, search = 0;
+       unsigned int gpio, mask;
+
+       gpio = irq_to_gpio(irq);
+       mask = get_gpiop_data(gpio) & get_gpiop_maska(gpio);
+
+       while (mask) {
+               if (mask & 1)
+                       bfin_handle_irq(irq);
+               irq++;
+               mask >>= 1;
+       }
+}
+
+void bfin_demux_gpio_irq(unsigned int inta_irq,
+                        struct irq_desc *desc)
+{
+       unsigned int irq;
 
        switch (inta_irq) {
-#if defined(CONFIG_BF53x)
-       case IRQ_PROG_INTA:
-               irq = IRQ_PF0;
-               search = 1;
+#if defined(BF537_FAMILY)
+       case IRQ_PF_INTA_PG_INTA:
+               bfin_demux_gpio_block(IRQ_PF0);
+               irq = IRQ_PG0;
                break;
-# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
-       case IRQ_MAC_RX:
+       case IRQ_PH_INTA_MAC_RX:
                irq = IRQ_PH0;
                break;
-# endif
-#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
+#elif defined(BF533_FAMILY)
+       case IRQ_PROG_INTA:
+               irq = IRQ_PF0;
+               break;
+#elif defined(BF538_FAMILY)
        case IRQ_PORTF_INTA:
                irq = IRQ_PF0;
                break;
@@ -732,31 +630,7 @@ static void bfin_demux_gpio_irq(unsigned int inta_irq,
                return;
        }
 
-       if (search) {
-               for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
-                       irq += i;
-
-                       mask = get_gpiop_data(i) & get_gpiop_maska(i);
-
-                       while (mask) {
-                               if (mask & 1)
-                                       bfin_handle_irq(irq);
-                               irq++;
-                               mask >>= 1;
-                       }
-               }
-       } else {
-                       gpio = irq_to_gpio(irq);
-                       mask = get_gpiop_data(gpio) & get_gpiop_maska(gpio);
-
-                       do {
-                               if (mask & 1)
-                                       bfin_handle_irq(irq);
-                               irq++;
-                               mask >>= 1;
-                       } while (mask);
-       }
-
+       bfin_demux_gpio_block(irq);
 }
 
 #else                          /* CONFIG_BF54x */
@@ -974,15 +848,11 @@ static int bfin_gpio_irq_type(struct irq_data *d, unsigned int type)
 }
 
 #ifdef CONFIG_PM
-u32 pint_saved_masks[NR_PINT_SYS_IRQS];
-u32 pint_wakeup_masks[NR_PINT_SYS_IRQS];
-
-int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
+static int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
 {
        u32 pint_irq;
        u32 pint_val = irq2pint_lut[d->irq - SYS_IRQS];
        u32 bank = PINT_2_BANK(pint_val);
-       u32 pintbit = PINT_BIT(pint_val);
 
        switch (bank) {
        case 0:
@@ -1003,46 +873,14 @@ int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
 
        bfin_internal_set_wake(pint_irq, state);
 
-       if (state)
-               pint_wakeup_masks[bank] |= pintbit;
-       else
-               pint_wakeup_masks[bank] &= ~pintbit;
-
        return 0;
 }
-
-u32 bfin_pm_setup(void)
-{
-       u32 val, i;
-
-       for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
-               val = pint[i]->mask_clear;
-               pint_saved_masks[i] = val;
-               if (val ^ pint_wakeup_masks[i]) {
-                       pint[i]->mask_clear = val;
-                       pint[i]->mask_set = pint_wakeup_masks[i];
-               }
-       }
-
-       return 0;
-}
-
-void bfin_pm_restore(void)
-{
-       u32 i, val;
-
-       for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
-               val = pint_saved_masks[i];
-               if (val ^ pint_wakeup_masks[i]) {
-                       pint[i]->mask_clear = pint[i]->mask_clear;
-                       pint[i]->mask_set = val;
-               }
-       }
-}
+#else
+# define bfin_gpio_set_wake NULL
 #endif
 
-static void bfin_demux_gpio_irq(unsigned int inta_irq,
-                               struct irq_desc *desc)
+void bfin_demux_gpio_irq(unsigned int inta_irq,
+                        struct irq_desc *desc)
 {
        u32 bank, pint_val;
        u32 request, irq;
@@ -1091,9 +929,7 @@ static struct irq_chip bfin_gpio_irqchip = {
        .irq_set_type = bfin_gpio_irq_type,
        .irq_startup = bfin_gpio_irq_startup,
        .irq_shutdown = bfin_gpio_irq_shutdown,
-#ifdef CONFIG_PM
        .irq_set_wake = bfin_gpio_set_wake,
-#endif
 };
 
 void __cpuinit init_exception_vectors(void)
@@ -1127,12 +963,12 @@ int __init init_arch_irq(void)
 {
        int irq;
        unsigned long ilat = 0;
+
        /*  Disable all the peripheral intrs  - page 4-29 HW Ref manual */
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) \
-       || defined(BF538_FAMILY) || defined(CONFIG_BF51x)
+#ifdef SIC_IMASK0
        bfin_write_SIC_IMASK0(SIC_UNMASK_ALL);
        bfin_write_SIC_IMASK1(SIC_UNMASK_ALL);
-# ifdef CONFIG_BF54x
+# ifdef SIC_IMASK2
        bfin_write_SIC_IMASK2(SIC_UNMASK_ALL);
 # endif
 # ifdef CONFIG_SMP
@@ -1145,11 +981,6 @@ int __init init_arch_irq(void)
 
        local_irq_disable();
 
-#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
-       /* Clear EMAC Interrupt Status bits so we can demux it later */
-       bfin_write_EMAC_SYSTAT(-1);
-#endif
-
 #ifdef CONFIG_BF54x
 # ifdef CONFIG_PINTx_REASSIGN
        pint[0]->assign = CONFIG_PINT0_ASSIGN;
@@ -1168,11 +999,11 @@ int __init init_arch_irq(void)
                        irq_set_chip(irq, &bfin_internal_irqchip);
 
                switch (irq) {
-#if defined(CONFIG_BF53x)
+#if defined(BF537_FAMILY)
+               case IRQ_PH_INTA_MAC_RX:
+               case IRQ_PF_INTA_PG_INTA:
+#elif defined(BF533_FAMILY)
                case IRQ_PROG_INTA:
-# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
-               case IRQ_MAC_RX:
-# endif
 #elif defined(CONFIG_BF54x)
                case IRQ_PINT0:
                case IRQ_PINT1:
@@ -1186,16 +1017,11 @@ int __init init_arch_irq(void)
                case IRQ_PROG0_INTA:
                case IRQ_PROG1_INTA:
                case IRQ_PROG2_INTA:
-#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
+#elif defined(BF538_FAMILY)
                case IRQ_PORTF_INTA:
 #endif
                        irq_set_chained_handler(irq, bfin_demux_gpio_irq);
                        break;
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
-               case IRQ_GENERIC_ERROR:
-                       irq_set_chained_handler(irq, bfin_demux_error_irq);
-                       break;
-#endif
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
                case IRQ_MAC_ERROR:
                        irq_set_chained_handler(irq,
@@ -1213,11 +1039,10 @@ int __init init_arch_irq(void)
                case IRQ_CORETMR:
 # ifdef CONFIG_SMP
                        irq_set_handler(irq, handle_percpu_irq);
-                       break;
 # else
                        irq_set_handler(irq, handle_simple_irq);
-                       break;
 # endif
+                       break;
 #endif
 
 #ifdef CONFIG_TICKSOURCE_GPTMR0
@@ -1226,26 +1051,17 @@ int __init init_arch_irq(void)
                        break;
 #endif
 
-#ifdef CONFIG_IPIPE
                default:
+#ifdef CONFIG_IPIPE
                        irq_set_handler(irq, handle_level_irq);
-                       break;
-#else /* !CONFIG_IPIPE */
-               default:
+#else
                        irq_set_handler(irq, handle_simple_irq);
+#endif
                        break;
-#endif /* !CONFIG_IPIPE */
                }
        }
 
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
-       for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++)
-               irq_set_chip_and_handler(irq, &bfin_generic_error_irqchip,
-                                        handle_level_irq);
-#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
-       irq_set_chained_handler(IRQ_MAC_ERROR, bfin_demux_mac_status_irq);
-#endif
-#endif
+       init_mach_irq();
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
        for (irq = IRQ_MAC_PHYINT; irq <= IRQ_MAC_STMDONE; irq++)
@@ -1307,53 +1123,54 @@ int __init init_arch_irq(void)
 #ifdef CONFIG_DO_IRQ_L1
 __attribute__((l1_text))
 #endif
-void do_irq(int vec, struct pt_regs *fp)
+static int vec_to_irq(int vec)
 {
-       if (vec == EVT_IVTMR_P) {
-               vec = IRQ_CORETMR;
-       } else {
-               struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
-               struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
-#if defined(SIC_ISR0)
-               unsigned long sic_status[3];
+       struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
+       struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
+       unsigned long sic_status[3];
+
+       if (likely(vec == EVT_IVTMR_P))
+               return IRQ_CORETMR;
 
-               if (smp_processor_id()) {
+#ifdef SIC_ISR
+       sic_status[0] = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
+#else
+       if (smp_processor_id()) {
 # ifdef SICB_ISR0
-                       /* This will be optimized out in UP mode. */
-                       sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0();
-                       sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1();
-# endif
-               } else {
-                       sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
-                       sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
-               }
-# ifdef SIC_ISR2
-               sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
+               /* This will be optimized out in UP mode. */
+               sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0();
+               sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1();
 # endif
-               for (;; ivg++) {
-                       if (ivg >= ivg_stop) {
-                               atomic_inc(&num_spurious);
-                               return;
-                       }
-                       if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
-                               break;
-               }
-#else
-               unsigned long sic_status;
-
-               sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
+       } else {
+               sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
+               sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
+       }
+#endif
+#ifdef SIC_ISR2
+       sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
+#endif
 
-               for (;; ivg++) {
-                       if (ivg >= ivg_stop) {
-                               atomic_inc(&num_spurious);
-                               return;
-                       } else if (sic_status & ivg->isrflag)
-                               break;
-               }
+       for (;; ivg++) {
+               if (ivg >= ivg_stop)
+                       return -1;
+#ifdef SIC_ISR
+               if (sic_status[0] & ivg->isrflag)
+#else
+               if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
 #endif
-               vec = ivg->irqno;
+                       return ivg->irqno;
        }
-       asm_do_IRQ(vec, fp);
+}
+
+#ifdef CONFIG_DO_IRQ_L1
+__attribute__((l1_text))
+#endif
+void do_irq(int vec, struct pt_regs *fp)
+{
+       int irq = vec_to_irq(vec);
+       if (irq == -1)
+               return;
+       asm_do_IRQ(irq, fp);
 }
 
 #ifdef CONFIG_IPIPE
@@ -1391,40 +1208,9 @@ asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
        struct ivgx *ivg = ivg7_13[vec-IVG7].ifirst;
        int irq, s = 0;
 
-       if (likely(vec == EVT_IVTMR_P))
-               irq = IRQ_CORETMR;
-       else {
-#if defined(SIC_ISR0)
-               unsigned long sic_status[3];
-
-               sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
-               sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
-# ifdef SIC_ISR2
-               sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
-# endif
-               for (;; ivg++) {
-                       if (ivg >= ivg_stop) {
-                               atomic_inc(&num_spurious);
-                               return 0;
-                       }
-                       if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
-                               break;
-               }
-#else
-               unsigned long sic_status;
-
-               sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
-
-               for (;; ivg++) {
-                       if (ivg >= ivg_stop) {
-                               atomic_inc(&num_spurious);
-                               return 0;
-                       } else if (sic_status & ivg->isrflag)
-                               break;
-               }
-#endif
-               irq = ivg->irqno;
-       }
+       irq = vec_to_irq(vec);
+       if (irq == -1)
+               return 0;
 
        if (irq == IRQ_SYSTMR) {
 #if !defined(CONFIG_GENERIC_CLOCKEVENTS) || defined(CONFIG_TICKSOURCE_GPTMR0)
index 1fbd94c4445700d24ac882cd7515dac3c159db4f..35e7e1eb0188f58de9fe39ed50af1538b5802e69 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <asm/atomic.h>
 #include <asm/cacheflush.h>
+#include <asm/irq_handler.h>
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -96,7 +97,7 @@ static void ipi_cpu_stop(unsigned int cpu)
        dump_stack();
        spin_unlock(&stop_lock);
 
-       cpu_clear(cpu, cpu_online_map);
+       set_cpu_online(cpu, false);
 
        local_irq_disable();
 
@@ -146,7 +147,7 @@ static void ipi_call_function(unsigned int cpu, struct ipi_message *msg)
                 */
                resync_core_dcache();
 #endif
-               cpu_clear(cpu, *msg->call_struct.waitmask);
+               cpumask_clear_cpu(cpu, msg->call_struct.waitmask);
        }
 }
 
@@ -222,9 +223,10 @@ static inline void smp_send_message(cpumask_t callmap, unsigned long type,
        struct ipi_message_queue *msg_queue;
        struct ipi_message *msg;
        unsigned long flags, next_msg;
-       cpumask_t waitmask = callmap; /* waitmask is shared by all cpus */
+       cpumask_t waitmask; /* waitmask is shared by all cpus */
 
-       for_each_cpu_mask(cpu, callmap) {
+       cpumask_copy(&waitmask, &callmap);
+       for_each_cpu(cpu, &callmap) {
                msg_queue = &per_cpu(ipi_msg_queue, cpu);
                spin_lock_irqsave(&msg_queue->lock, flags);
                if (msg_queue->count < BFIN_IPI_MSGQ_LEN) {
@@ -246,7 +248,7 @@ static inline void smp_send_message(cpumask_t callmap, unsigned long type,
        }
 
        if (wait) {
-               while (!cpus_empty(waitmask))
+               while (!cpumask_empty(&waitmask))
                        blackfin_dcache_invalidate_range(
                                (unsigned long)(&waitmask),
                                (unsigned long)(&waitmask));
@@ -265,9 +267,9 @@ int smp_call_function(void (*func)(void *info), void *info, int wait)
        cpumask_t callmap;
 
        preempt_disable();
-       callmap = cpu_online_map;
-       cpu_clear(smp_processor_id(), callmap);
-       if (!cpus_empty(callmap))
+       cpumask_copy(&callmap, cpu_online_mask);
+       cpumask_clear_cpu(smp_processor_id(), &callmap);
+       if (!cpumask_empty(&callmap))
                smp_send_message(callmap, BFIN_IPI_CALL_FUNC, func, info, wait);
 
        preempt_enable();
@@ -284,8 +286,8 @@ int smp_call_function_single(int cpuid, void (*func) (void *info), void *info,
 
        if (cpu_is_offline(cpu))
                return 0;
-       cpus_clear(callmap);
-       cpu_set(cpu, callmap);
+       cpumask_clear(&callmap);
+       cpumask_set_cpu(cpu, &callmap);
 
        smp_send_message(callmap, BFIN_IPI_CALL_FUNC, func, info, wait);
 
@@ -308,9 +310,9 @@ void smp_send_stop(void)
        cpumask_t callmap;
 
        preempt_disable();
-       callmap = cpu_online_map;
-       cpu_clear(smp_processor_id(), callmap);
-       if (!cpus_empty(callmap))
+       cpumask_copy(&callmap, cpu_online_mask);
+       cpumask_clear_cpu(smp_processor_id(), &callmap);
+       if (!cpumask_empty(&callmap))
                smp_send_message(callmap, BFIN_IPI_CPU_STOP, NULL, NULL, 0);
 
        preempt_enable();
index b71cebc1f8a3850d843c1c470fc9016ef0ef3b10..e2532114c5fd75bde75e31038012b6eefa93c80d 100644 (file)
@@ -16,7 +16,7 @@ static int validate_memory_access_address(unsigned long addr, int size)
        return bfin_mem_access_type(addr, size);
 }
 
-long probe_kernel_read(void *dst, void *src, size_t size)
+long probe_kernel_read(void *dst, const void *src, size_t size)
 {
        unsigned long lsrc = (unsigned long)src;
        int mem_type;
@@ -55,7 +55,7 @@ long probe_kernel_read(void *dst, void *src, size_t size)
        return -EFAULT;
 }
 
-long probe_kernel_write(void *dst, void *src, size_t size)
+long probe_kernel_write(void *dst, const void *src, size_t size)
 {
        unsigned long ldst = (unsigned long)dst;
        int mem_type;
index dfd304a4a3ea113a25f23befd8ba8f0078b4bc79..29d98faa1efdacd4a9cf93723fb268ab91dcbc85 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/spinlock.h>
 #include <linux/rtc.h>
 #include <linux/slab.h>
@@ -764,7 +765,7 @@ EXPORT_SYMBOL(sram_alloc_with_lsl);
 /* Need to keep line of output the same.  Currently, that is 44 bytes
  * (including newline).
  */
-static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
+static int _sram_proc_show(struct seq_file *m, const char *desc,
                struct sram_piece *pfree_head,
                struct sram_piece *pused_head)
 {
@@ -773,13 +774,13 @@ static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
        if (!pfree_head || !pused_head)
                return -1;
 
-       *len += sprintf(&buf[*len], "--- SRAM %-14s Size   PID State     \n", desc);
+       seq_printf(m, "--- SRAM %-14s Size   PID State     \n", desc);
 
        /* search the relevant memory slot */
        pslot = pused_head->next;
 
        while (pslot != NULL) {
-               *len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
+               seq_printf(m, "%p-%p %10i %5i %-10s\n",
                        pslot->paddr, pslot->paddr + pslot->size,
                        pslot->size, pslot->pid, "ALLOCATED");
 
@@ -789,7 +790,7 @@ static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
        pslot = pfree_head->next;
 
        while (pslot != NULL) {
-               *len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
+               seq_printf(m, "%p-%p %10i %5i %-10s\n",
                        pslot->paddr, pslot->paddr + pslot->size,
                        pslot->size, pslot->pid, "FREE");
 
@@ -798,54 +799,62 @@ static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
 
        return 0;
 }
-static int sram_proc_read(char *buf, char **start, off_t offset, int count,
-               int *eof, void *data)
+static int sram_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0;
        unsigned int cpu;
 
        for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
-               if (_sram_proc_read(buf, &len, count, "Scratchpad",
+               if (_sram_proc_show(m, "Scratchpad",
                        &per_cpu(free_l1_ssram_head, cpu), &per_cpu(used_l1_ssram_head, cpu)))
                        goto not_done;
 #if L1_DATA_A_LENGTH != 0
-               if (_sram_proc_read(buf, &len, count, "L1 Data A",
+               if (_sram_proc_show(m, "L1 Data A",
                        &per_cpu(free_l1_data_A_sram_head, cpu),
                        &per_cpu(used_l1_data_A_sram_head, cpu)))
                        goto not_done;
 #endif
 #if L1_DATA_B_LENGTH != 0
-               if (_sram_proc_read(buf, &len, count, "L1 Data B",
+               if (_sram_proc_show(m, "L1 Data B",
                        &per_cpu(free_l1_data_B_sram_head, cpu),
                        &per_cpu(used_l1_data_B_sram_head, cpu)))
                        goto not_done;
 #endif
 #if L1_CODE_LENGTH != 0
-               if (_sram_proc_read(buf, &len, count, "L1 Instruction",
+               if (_sram_proc_show(m, "L1 Instruction",
                        &per_cpu(free_l1_inst_sram_head, cpu),
                        &per_cpu(used_l1_inst_sram_head, cpu)))
                        goto not_done;
 #endif
        }
 #if L2_LENGTH != 0
-       if (_sram_proc_read(buf, &len, count, "L2", &free_l2_sram_head,
-               &used_l2_sram_head))
+       if (_sram_proc_show(m, "L2", &free_l2_sram_head, &used_l2_sram_head))
                goto not_done;
 #endif
-       *eof = 1;
  not_done:
-       return len;
+       return 0;
+}
+
+static int sram_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, sram_proc_show, NULL);
 }
 
+static const struct file_operations sram_proc_ops = {
+       .open           = sram_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static int __init sram_proc_init(void)
 {
        struct proc_dir_entry *ptr;
-       ptr = create_proc_entry("sram", S_IFREG | S_IRUGO, NULL);
+
+       ptr = proc_create("sram", S_IRUGO, NULL, &sram_proc_ops);
        if (!ptr) {
                printk(KERN_WARNING "unable to create /proc/sram\n");
                return -1;
        }
-       ptr->read_proc = sram_proc_read;
        return 0;
 }
 late_initcall(sram_proc_init);
index a6d03069d0fff21a51bff6c94ec11e7a18be2f9f..17addacb169eb4a6e0c5ca16e3f39d849b3035f4 100644 (file)
@@ -31,10 +31,6 @@ config ARCH_HAS_ILOG2_U64
        bool
        default n
 
-config GENERIC_FIND_NEXT_BIT
-       bool
-       default y
-
 config GENERIC_HWEIGHT
        bool
        default y
@@ -274,7 +270,6 @@ config ETRAX_AXISFLASHMAP
        select MTD_JEDECPROBE if ETRAX_ARCH_V32
        select MTD_CHAR
        select MTD_BLOCK
-       select MTD_PARTITIONS
        select MTD_COMPLEX_MAPPINGS
        help
          This option enables MTD mapping of flash devices.  Needed to use
index ed708e19d09eb3575c50c05f4c6cf06ee55c854d..a4bbdfd37bd8f74f9255d2617e8bc8375d75c8ad 100644 (file)
@@ -372,7 +372,7 @@ static int __init init_axis_flash(void)
 #ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE
        if (mymtd) {
                main_partition.size = mymtd->size;
-               err = add_mtd_partitions(mymtd, &main_partition, 1);
+               err = mtd_device_register(mymtd, &main_partition, 1);
                if (err)
                        panic("axisflashmap: Could not initialize "
                              "partition for whole main mtd device!\n");
@@ -382,10 +382,12 @@ static int __init init_axis_flash(void)
         if (mymtd) {
                if (use_default_ptable) {
                        printk(KERN_INFO " Using default partition table.\n");
-                       err = add_mtd_partitions(mymtd, axis_default_partitions,
-                                                NUM_DEFAULT_PARTITIONS);
+                       err = mtd_device_register(mymtd,
+                                                 axis_default_partitions,
+                                                 NUM_DEFAULT_PARTITIONS);
                } else {
-                       err = add_mtd_partitions(mymtd, axis_partitions, pidx);
+                       err = mtd_device_register(mymtd, axis_partitions,
+                                                 pidx);
                }
 
                if (err)
index 0d6420d087fd01d8e588315b3dec2d2d76791495..1161883eb582964fb5ad583e20b5bf327dd83097 100644 (file)
@@ -937,6 +937,7 @@ sys_call_table:
        .long sys_inotify_init1
        .long sys_preadv
        .long sys_pwritev
+       .long sys_setns                 /* 335 */
 
         /*
          * NOTE!! This doesn't have to be exact - we just have
index 1633b120aa81a413b00422629cdbc61a4310ce4a..41a2732e8b9c406f664d93ce065eff6e646d2487 100644 (file)
@@ -405,7 +405,6 @@ config ETRAX_AXISFLASHMAP
        select MTD_JEDECPROBE
        select MTD_CHAR
        select MTD_BLOCK
-       select MTD_PARTITIONS
        select MTD_COMPLEX_MAPPINGS
        help
          This option enables MTD mapping of flash devices.  Needed to use
index 7b155f8203b8d0d179022733825a504667cd4da8..a2bde3744622fec40df210616e6aef82c76b3cc4 100644 (file)
@@ -561,7 +561,7 @@ static int __init init_axis_flash(void)
 #ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE
        if (main_mtd) {
                main_partition.size = main_mtd->size;
-               err = add_mtd_partitions(main_mtd, &main_partition, 1);
+               err = mtd_device_register(main_mtd, &main_partition, 1);
                if (err)
                        panic("axisflashmap: Could not initialize "
                              "partition for whole main mtd device!\n");
@@ -597,7 +597,8 @@ static int __init init_axis_flash(void)
                        mtd_ram->erasesize = (main_mtd ? main_mtd->erasesize :
                                CONFIG_ETRAX_PTABLE_SECTOR);
                } else {
-                       err = add_mtd_partitions(main_mtd, &partition[part], 1);
+                       err = mtd_device_register(main_mtd, &partition[part],
+                                                 1);
                        if (err)
                                panic("axisflashmap: Could not add mtd "
                                        "partition %d\n", part);
@@ -633,7 +634,7 @@ static int __init init_axis_flash(void)
 #ifndef CONFIG_ETRAX_VCS_SIM
        if (aux_mtd) {
                aux_partition.size = aux_mtd->size;
-               err = add_mtd_partitions(aux_mtd, &aux_partition, 1);
+               err = mtd_device_register(aux_mtd, &aux_partition, 1);
                if (err)
                        panic("axisflashmap: Could not initialize "
                              "aux mtd device!\n");
index 3abf12c23e5f6ef329f3fca151402cec97643946..84fed7e91ada221772f5afa8f3e4d9707a899116 100644 (file)
@@ -880,6 +880,7 @@ sys_call_table:
        .long sys_inotify_init1
        .long sys_preadv
        .long sys_pwritev
+       .long sys_setns                 /* 335 */
 
         /*
          * NOTE!! This doesn't have to be exact - we just have
index 68a1a5901ca5acd59dedeb64ec7f7f588c16070c..5ebe6e841820ec45a5a653d66993b7b2b5952bef 100644 (file)
@@ -266,11 +266,11 @@ static int irq_cpu(int irq)
 
 
        /* Let the interrupt stay if possible */
-       if (cpu_isset(cpu, irq_allocations[irq - FIRST_IRQ].mask))
+       if (cpumask_test_cpu(cpu, &irq_allocations[irq - FIRST_IRQ].mask))
                goto out;
 
        /* IRQ must be moved to another CPU. */
-       cpu = first_cpu(irq_allocations[irq - FIRST_IRQ].mask);
+       cpu = cpumask_first(&irq_allocations[irq - FIRST_IRQ].mask);
        irq_allocations[irq - FIRST_IRQ].cpu = cpu;
 out:
        spin_unlock_irqrestore(&irq_lock, flags);
index 66cc75657e2f3782e6431b249fdf6f9fe5dc30fb..a0843a71aaeed9eb47ed62b121f7e997bfc0c85d 100644 (file)
@@ -81,7 +81,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
 
        /* Mark all possible CPUs as present */
        for (i = 0; i < max_cpus; i++)
-           cpu_set(i, phys_cpu_present_map);
+               cpumask_set_cpu(i, &phys_cpu_present_map);
 }
 
 void __devinit smp_prepare_boot_cpu(void)
@@ -98,7 +98,7 @@ void __devinit smp_prepare_boot_cpu(void)
        SUPP_REG_WR(RW_MM_TLB_PGD, pgd);
 
        set_cpu_online(0, true);
-       cpu_set(0, phys_cpu_present_map);
+       cpumask_set_cpu(0, &phys_cpu_present_map);
        set_cpu_possible(0, true);
 }
 
@@ -112,8 +112,9 @@ smp_boot_one_cpu(int cpuid)
 {
        unsigned timeout;
        struct task_struct *idle;
-       cpumask_t cpu_mask = CPU_MASK_NONE;
+       cpumask_t cpu_mask;
 
+       cpumask_clear(&cpu_mask);
        idle = fork_idle(cpuid);
        if (IS_ERR(idle))
                panic("SMP: fork failed for CPU:%d", cpuid);
@@ -125,10 +126,10 @@ smp_boot_one_cpu(int cpuid)
        cpu_now_booting = cpuid;
 
        /* Kick it */
-       cpu_set(cpuid, cpu_online_map);
-       cpu_set(cpuid, cpu_mask);
+       set_cpu_online(cpuid, true);
+       cpumask_set_cpu(cpuid, &cpu_mask);
        send_ipi(IPI_BOOT, 0, cpu_mask);
-       cpu_clear(cpuid, cpu_online_map);
+       set_cpu_online(cpuid, false);
 
        /* Wait for CPU to come online */
        for (timeout = 0; timeout < 10000; timeout++) {
@@ -176,7 +177,7 @@ void __init smp_callin(void)
        notify_cpu_starting(cpu);
        local_irq_enable();
 
-       cpu_set(cpu, cpu_online_map);
+       set_cpu_online(cpu, true);
        cpu_idle();
 }
 
@@ -214,8 +215,9 @@ int __cpuinit __cpu_up(unsigned int cpu)
 
 void smp_send_reschedule(int cpu)
 {
-       cpumask_t cpu_mask = CPU_MASK_NONE;
-       cpu_set(cpu, cpu_mask);
+       cpumask_t cpu_mask;
+       cpumask_clear(&cpu_mask);
+       cpumask_set_cpu(cpu, &cpu_mask);
        send_ipi(IPI_SCHEDULE, 0, cpu_mask);
 }
 
@@ -232,7 +234,7 @@ void flush_tlb_common(struct mm_struct* mm, struct vm_area_struct* vma, unsigned
 
        spin_lock_irqsave(&tlbstate_lock, flags);
        cpu_mask = (mm == FLUSH_ALL ? cpu_all_mask : *mm_cpumask(mm));
-       cpu_clear(smp_processor_id(), cpu_mask);
+       cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
        flush_mm = mm;
        flush_vma = vma;
        flush_addr = addr;
@@ -277,10 +279,10 @@ int send_ipi(int vector, int wait, cpumask_t cpu_mask)
        int ret = 0;
 
        /* Calculate CPUs to send to. */
-       cpus_and(cpu_mask, cpu_mask, cpu_online_map);
+       cpumask_and(&cpu_mask, &cpu_mask, cpu_online_mask);
 
        /* Send the IPI. */
-       for_each_cpu_mask(i, cpu_mask)
+       for_each_cpu(i, &cpu_mask)
        {
                ipi.vector |= vector;
                REG_WR(intr_vect, irq_regs[i], rw_ipi, ipi);
@@ -288,7 +290,7 @@ int send_ipi(int vector, int wait, cpumask_t cpu_mask)
 
        /* Wait for IPI to finish on other CPUS */
        if (wait) {
-               for_each_cpu_mask(i, cpu_mask) {
+               for_each_cpu(i, &cpu_mask) {
                         int j;
                         for (j = 0 ; j < 1000; j++) {
                                ipi = REG_RD(intr_vect, irq_regs[i], rw_ipi);
@@ -314,11 +316,12 @@ int send_ipi(int vector, int wait, cpumask_t cpu_mask)
  */
 int smp_call_function(void (*func)(void *info), void *info, int wait)
 {
-       cpumask_t cpu_mask = CPU_MASK_ALL;
+       cpumask_t cpu_mask;
        struct call_data_struct data;
        int ret;
 
-       cpu_clear(smp_processor_id(), cpu_mask);
+       cpumask_setall(&cpu_mask);
+       cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
 
        WARN_ON(irqs_disabled());
 
index f6fad83b3a8c58c9bc0f88f8c60575783394db28..f921b8b0f97e6699cca03f3cd90af305dc647508 100644 (file)
 #define __NR_inotify_init1     332
 #define __NR_preadv            333
 #define __NR_pwritev           334
+#define __NR_setns             335
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 335
+#define NR_syscalls 336
 
 #include <arch/unistd.h>
 
index 728bbd9e7d4c1105b802cbc53558e54c350db93a..a6990cb0f098772c8739b8e7e738789414af7dc8 100644 (file)
@@ -102,7 +102,7 @@ SECTIONS
 #endif
        __vmlinux_end = .;              /* Last address of the physical file. */
 #ifdef CONFIG_ETRAX_ARCH_V32
-       PERCPU(32, PAGE_SIZE)
+       PERCPU_SECTION(32)
 
        .init.ramfs : {
                INIT_RAM_FS
index df33ab89d70f0083c99380db30faaa8114d7512e..d72ab58fd83e743cdeba8cac08e02634cc8f552b 100644 (file)
@@ -13,8 +13,6 @@
 #include <linux/bootmem.h>
 #include <asm/tlb.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 unsigned long empty_zero_page;
 
 extern char _stext, _edata, _etext; /* From linkerscript */
index 064f62196745d0bbd5d0ddadec022754a2659c79..cb884e48942560f23eb9de40c24cb62d9b7eb1e9 100644 (file)
@@ -19,14 +19,6 @@ config RWSEM_GENERIC_SPINLOCK
 config RWSEM_XCHGADD_ALGORITHM
        bool
 
-config GENERIC_FIND_NEXT_BIT
-       bool
-       default y
-
-config GENERIC_FIND_BIT_LE
-       bool
-       default y
-
 config GENERIC_HWEIGHT
        bool
        default y
diff --git a/arch/frv/include/asm/suspend.h b/arch/frv/include/asm/suspend.h
deleted file mode 100644 (file)
index 5fa7b5a..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* suspend.h: suspension stuff
- *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.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.
- */
-
-#ifndef _ASM_SUSPEND_H
-#define _ASM_SUSPEND_H
-
-static inline int arch_prepare_suspend(void)
-{
-       return 0;
-}
-
-#endif /* _ASM_SUSPEND_H */
index b28da499e22a16d29c68c6dbccfa02475ce3a807..a569dff7cd590f0936fce6a4b5e03e99325b8674 100644 (file)
 #define __NR_pwritev           334
 #define __NR_rt_tgsigqueueinfo 335
 #define __NR_perf_event_open   336
+#define __NR_setns             337
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 337
+#define NR_syscalls 338
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 /* #define __ARCH_WANT_OLD_READDIR */
index 63d579bf1c2974d6cec4972af17ee1db812519c5..017d6d7b784fa5324f78dd5b4c11d431e8127278 100644 (file)
@@ -1526,5 +1526,6 @@ sys_call_table:
        .long sys_pwritev
        .long sys_rt_tgsigqueueinfo     /* 335 */
        .long sys_perf_event_open
+       .long sys_setns
 
 syscall_table_size = (. - sys_call_table)
index 0daae8af5787bfd44fe467689b2fdbd2e7b73289..7e958d829ec9810020c75eca7beef1cbfd44a3c2 100644 (file)
@@ -37,7 +37,7 @@ SECTIONS
   _einittext = .;
 
   INIT_DATA_SECTION(8)
-  PERCPU(L1_CACHE_BYTES, 4096)
+  PERCPU_SECTION(L1_CACHE_BYTES)
 
   . = ALIGN(PAGE_SIZE);
   __init_end = .;
index ed64588ac3a76662935dc1fddd1b9e015ebaa475..fbe5f0dbae06eb588d3d6be5106e5ffeeaebdf9b 100644 (file)
@@ -41,8 +41,6 @@
 
 #undef DEBUG
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 /*
  * BAD_PAGE is the page that is used for page faults when linux
  * is out-of-memory. Older versions of linux just did a
index e20322ffcaf839d2e9fabb4ecfafdbc997a8c221..091ed6192ae831f7f2a96ecb663c1528b6c29632 100644 (file)
@@ -41,14 +41,6 @@ config ARCH_HAS_ILOG2_U64
        bool
        default n
 
-config GENERIC_FIND_NEXT_BIT
-       bool
-       default y
-
-config GENERIC_FIND_BIT_LE
-       bool
-       default y
-
 config GENERIC_HWEIGHT
        bool
        default y
index 50f2c5a365915a8d3e6487502ecd02055ec56088..2c3f8e60b1e09269e71dd5c57817c2d8bc8aa2ff 100644 (file)
 #define __NR_move_pages                317
 #define __NR_getcpu            318
 #define __NR_epoll_pwait       319
+#define __NR_setns             320
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 320
+#define NR_syscalls 321
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index faefaff7d43de491cb99df880047f9d637c788fe..f4b2e67bcc34dcd93340baf8bfcf4cdb35176be7 100644 (file)
@@ -333,6 +333,7 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_ni_syscall)       /* sys_move_pages */
        .long SYMBOL_NAME(sys_getcpu)
        .long SYMBOL_NAME(sys_ni_syscall)       /* sys_epoll_pwait */
+       .long SYMBOL_NAME(sys_setns)            /* 320 */
 
        .macro  call_sp addr
        mov.l   #SYMBOL_NAME(\addr),er6
index e5cc56ae6ce3089129624b26ef24445592586348..38280ef4a2af219c8a2aba4fef0a43830acc8515 100644 (file)
@@ -78,10 +78,6 @@ config HUGETLB_PAGE_SIZE_VARIABLE
        depends on HUGETLB_PAGE
        default y
 
-config GENERIC_FIND_NEXT_BIT
-       bool
-       default y
-
 config GENERIC_CALIBRATE_DELAY
        bool
        default y
index 23cce999eb1cadaef129afa9d342ca3bc87c2d54..c3ffe3e54edc1a0457359b2c198d555330d09bf7 100644 (file)
 #include <asm/machvec.h>
 
 #ifdef CONFIG_SMP
-# define FREE_PTE_NR           2048
 # define tlb_fast_mode(tlb)    ((tlb)->nr == ~0U)
 #else
-# define FREE_PTE_NR           0
 # define tlb_fast_mode(tlb)    (1)
 #endif
 
+/*
+ * If we can't allocate a page to make a big batch of page pointers
+ * to work on, then just handle a few from the on-stack structure.
+ */
+#define        IA64_GATHER_BUNDLE      8
+
 struct mmu_gather {
        struct mm_struct        *mm;
        unsigned int            nr;             /* == ~0U => fast mode */
+       unsigned int            max;
        unsigned char           fullmm;         /* non-zero means full mm flush */
        unsigned char           need_flush;     /* really unmapped some PTEs? */
        unsigned long           start_addr;
        unsigned long           end_addr;
-       struct page             *pages[FREE_PTE_NR];
+       struct page             **pages;
+       struct page             *local[IA64_GATHER_BUNDLE];
 };
 
 struct ia64_tr_entry {
@@ -90,9 +96,6 @@ extern struct ia64_tr_entry *ia64_idtrs[NR_CPUS];
 #define RR_RID_MASK    0x00000000ffffff00L
 #define RR_TO_RID(val)         ((val >> 8) & 0xffffff)
 
-/* Users of the generic TLB shootdown code must declare this storage space. */
-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 /*
  * Flush the TLB for address range START to END and, if not in fast mode, release the
  * freed pages that where gathered up to this point.
@@ -147,15 +150,23 @@ ia64_tlb_flush_mmu (struct mmu_gather *tlb, unsigned long start, unsigned long e
        }
 }
 
-/*
- * Return a pointer to an initialized struct mmu_gather.
- */
-static inline struct mmu_gather *
-tlb_gather_mmu (struct mm_struct *mm, unsigned int full_mm_flush)
+static inline void __tlb_alloc_page(struct mmu_gather *tlb)
 {
-       struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
+       unsigned long addr = __get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);
 
+       if (addr) {
+               tlb->pages = (void *)addr;
+               tlb->max = PAGE_SIZE / sizeof(void *);
+       }
+}
+
+
+static inline void
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int full_mm_flush)
+{
        tlb->mm = mm;
+       tlb->max = ARRAY_SIZE(tlb->local);
+       tlb->pages = tlb->local;
        /*
         * Use fast mode if only 1 CPU is online.
         *
@@ -172,7 +183,6 @@ tlb_gather_mmu (struct mm_struct *mm, unsigned int full_mm_flush)
        tlb->nr = (num_online_cpus() == 1) ? ~0U : 0;
        tlb->fullmm = full_mm_flush;
        tlb->start_addr = ~0UL;
-       return tlb;
 }
 
 /*
@@ -180,7 +190,7 @@ tlb_gather_mmu (struct mm_struct *mm, unsigned int full_mm_flush)
  * collected.
  */
 static inline void
-tlb_finish_mmu (struct mmu_gather *tlb, unsigned long start, unsigned long end)
+tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
 {
        /*
         * Note: tlb->nr may be 0 at this point, so we can't rely on tlb->start_addr and
@@ -191,7 +201,8 @@ tlb_finish_mmu (struct mmu_gather *tlb, unsigned long start, unsigned long end)
        /* keep the page table cache within bounds */
        check_pgt_cache();
 
-       put_cpu_var(mmu_gathers);
+       if (tlb->pages != tlb->local)
+               free_pages((unsigned long)tlb->pages, 0);
 }
 
 /*
@@ -199,18 +210,33 @@ tlb_finish_mmu (struct mmu_gather *tlb, unsigned long start, unsigned long end)
  * must be delayed until after the TLB has been flushed (see comments at the beginning of
  * this file).
  */
-static inline void
-tlb_remove_page (struct mmu_gather *tlb, struct page *page)
+static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
 {
        tlb->need_flush = 1;
 
        if (tlb_fast_mode(tlb)) {
                free_page_and_swap_cache(page);
-               return;
+               return 1; /* avoid calling tlb_flush_mmu */
        }
+
+       if (!tlb->nr && tlb->pages == tlb->local)
+               __tlb_alloc_page(tlb);
+
        tlb->pages[tlb->nr++] = page;
-       if (tlb->nr >= FREE_PTE_NR)
-               ia64_tlb_flush_mmu(tlb, tlb->start_addr, tlb->end_addr);
+       VM_BUG_ON(tlb->nr > tlb->max);
+
+       return tlb->max - tlb->nr;
+}
+
+static inline void tlb_flush_mmu(struct mmu_gather *tlb)
+{
+       ia64_tlb_flush_mmu(tlb, tlb->start_addr, tlb->end_addr);
+}
+
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       if (!__tlb_remove_page(tlb, page))
+               tlb_flush_mmu(tlb);
 }
 
 /*
index 404d037c5e10e4460ac04373051986fae9f874d5..7c928da35b173732cc01d9a8d6f749ef4310d691 100644 (file)
 #define __NR_open_by_handle_at         1327
 #define __NR_clock_adjtime             1328
 #define __NR_syncfs                    1329
+#define __NR_setns                     1330
+#define __NR_sendmmsg                  1331
 
 #ifdef __KERNEL__
 
 
-#define NR_syscalls                    306 /* length of syscall table */
+#define NR_syscalls                    308 /* length of syscall table */
 
 /*
  * The following defines stop scripts/checksyscalls.sh from complaining about
index 6de2e23b3636e422e6e3e7ca09f69decb6b9a310..97dd2abdeb1a3b2cd66a409d1dc4bf8ec0345b55 100644 (file)
@@ -1775,6 +1775,8 @@ sys_call_table:
        data8 sys_open_by_handle_at
        data8 sys_clock_adjtime
        data8 sys_syncfs
+       data8 sys_setns                         // 1330
+       data8 sys_sendmmsg
 
        .org sys_call_table + 8*NR_syscalls     // guard against failures to increase NR_syscalls
 #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
index 04440cc09b40cbd2a124b78474f6bba30a26d0b2..85118dfe9bb5ac3548296848efbd2ff0d1d7890b 100644 (file)
@@ -36,7 +36,7 @@
 static cycle_t itc_get_cycles(struct clocksource *cs);
 
 struct fsyscall_gtod_data_t fsyscall_gtod_data = {
-       .lock = SEQLOCK_UNLOCKED,
+       .lock = __SEQLOCK_UNLOCKED(fsyscall_gtod_data.lock),
 };
 
 struct itc_jitter_data_t itc_jitter_data;
index 9a018cde5d84d5c3718c3fef41d6557aa392d14b..f114a3b14c6ad73c7fa6afbe950375f46d98b876 100644 (file)
@@ -44,13 +44,16 @@ void show_mem(unsigned int filter)
        pg_data_t *pgdat;
 
        printk(KERN_INFO "Mem-info:\n");
-       show_free_areas();
+       show_free_areas(filter);
        printk(KERN_INFO "Node memory in pages:\n");
        for_each_online_pgdat(pgdat) {
                unsigned long present;
                unsigned long flags;
                int shared = 0, cached = 0, reserved = 0;
+               int nid = pgdat->node_id;
 
+               if (skip_free_areas_node(filter, nid))
+                       continue;
                pgdat_resize_lock(pgdat, &flags);
                present = pgdat->node_present_pages;
                for(i = 0; i < pgdat->node_spanned_pages; i++) {
@@ -64,8 +67,7 @@ void show_mem(unsigned int filter)
                                if (max_gap < LARGE_GAP)
                                        continue;
 #endif
-                               i = vmemmap_find_next_valid_pfn(pgdat->node_id,
-                                        i) - 1;
+                               i = vmemmap_find_next_valid_pfn(nid, i) - 1;
                                continue;
                        }
                        if (PageReserved(page))
@@ -81,7 +83,7 @@ void show_mem(unsigned int filter)
                total_cached += cached;
                total_shared += shared;
                printk(KERN_INFO "Node %4d:  RAM: %11ld, rsvd: %8d, "
-                      "shrd: %10d, swpd: %10d\n", pgdat->node_id,
+                      "shrd: %10d, swpd: %10d\n", nid,
                       present, reserved, shared, cached);
        }
        printk(KERN_INFO "%ld pages of RAM\n", total_present);
index 82ab1bc6afb1236460c0e380a2a5fbf61a5b8e1b..c641333cd997635f1c885d12d895459111168e4a 100644 (file)
@@ -622,13 +622,16 @@ void show_mem(unsigned int filter)
        pg_data_t *pgdat;
 
        printk(KERN_INFO "Mem-info:\n");
-       show_free_areas();
+       show_free_areas(filter);
        printk(KERN_INFO "Node memory in pages:\n");
        for_each_online_pgdat(pgdat) {
                unsigned long present;
                unsigned long flags;
                int shared = 0, cached = 0, reserved = 0;
+               int nid = pgdat->node_id;
 
+               if (skip_free_areas_node(filter, nid))
+                       continue;
                pgdat_resize_lock(pgdat, &flags);
                present = pgdat->node_present_pages;
                for(i = 0; i < pgdat->node_spanned_pages; i++) {
@@ -638,8 +641,7 @@ void show_mem(unsigned int filter)
                        if (pfn_valid(pgdat->node_start_pfn + i))
                                page = pfn_to_page(pgdat->node_start_pfn + i);
                        else {
-                               i = vmemmap_find_next_valid_pfn(pgdat->node_id,
-                                        i) - 1;
+                               i = vmemmap_find_next_valid_pfn(nid, i) - 1;
                                continue;
                        }
                        if (PageReserved(page))
@@ -655,7 +657,7 @@ void show_mem(unsigned int filter)
                total_cached += cached;
                total_shared += shared;
                printk(KERN_INFO "Node %4d:  RAM: %11ld, rsvd: %8d, "
-                      "shrd: %10d, swpd: %10d\n", pgdat->node_id,
+                      "shrd: %10d, swpd: %10d\n", nid,
                       present, reserved, shared, cached);
        }
        printk(KERN_INFO "%ld pages of RAM\n", total_present);
index ed41759efcac3b76e44d9a6b87c0c379448b4c5c..00cb0e26c64e02cd9663c381fa359e22f6c8104a 100644 (file)
@@ -36,8 +36,6 @@
 #include <asm/mca.h>
 #include <asm/paravirt.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 extern void ia64_tlb_init (void);
 
 unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL;
index 736b808d2291bc149c7801cceb73876d50e0f46b..85b44e8582254a5f154ecc2c49455e5f7b0f3157 100644 (file)
@@ -256,14 +256,6 @@ config ARCH_HAS_ILOG2_U64
        bool
        default n
 
-config GENERIC_FIND_NEXT_BIT
-       bool
-       default y
-
-config GENERIC_FIND_BIT_LE
-       bool
-       default y
-
 config GENERIC_HWEIGHT
        bool
        default y
index 2e1019ddbb2233667604f312b0597a32a1206a4d..bb1afc1a31ccb8de1f748949b79c1d6c962a5c35 100644 (file)
@@ -9,15 +9,6 @@ config DEBUG_STACKOVERFLOW
          This option will cause messages to be printed if free stack space
          drops below a certain limit.
 
-config DEBUG_STACK_USAGE
-       bool "Stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T and sysrq-P debug output.
-
-         This option will slow down process creation somewhat.
-
 config DEBUG_PAGEALLOC
        bool "Debug page memory allocations"
        depends on DEBUG_KERNEL && BROKEN
index e67ded1aab9100df5d478573945166b70a7b4105..cf7829a615513e1597d903c6398348d8e0d5ac1e 100644 (file)
@@ -81,11 +81,11 @@ static __inline__ int cpu_number_map(int cpu)
 
 static __inline__ unsigned int num_booting_cpus(void)
 {
-       return cpus_weight(cpu_callout_map);
+       return cpumask_weight(&cpu_callout_map);
 }
 
 extern void smp_send_timer(void);
-extern unsigned long send_IPI_mask_phys(cpumask_t, int, int);
+extern unsigned long send_IPI_mask_phys(const cpumask_t*, int, int);
 
 extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
@@ -94,8 +94,6 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 
 #define NO_PROC_ID (0xff)      /* No processor magic marker */
 
-#define PROC_CHANGE_PENALTY    (15)    /* Schedule penalty */
-
 /*
  * M32R-mp IPI
  */
index c70545689da83ef2ffaef987b2c3374fadca04fc..3e1db561aacc0c5923f0f14f455887f421b8bc71 100644 (file)
 /* #define __NR_timerfd                322 removed */
 #define __NR_eventfd           323
 #define __NR_fallocate         324
+#define __NR_setns             325
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 325
+#define NR_syscalls 326
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_STAT64
index fc10b39893d42ee0cd4ed8a3e1102a79d7d51273..092d40a6708e4a35ffec5e6f4f966791551d50c6 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/io.h>
 #include <asm/mmu_context.h>
 #include <asm/m32r.h>
+#include <asm/tlbflush.h>
 
 /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
 /* Data structures and variables                                             */
@@ -61,33 +62,22 @@ extern spinlock_t ipi_lock[];
 /* Function Prototypes                                                       */
 /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
 
-void smp_send_reschedule(int);
 void smp_reschedule_interrupt(void);
-
-void smp_flush_cache_all(void);
 void smp_flush_cache_all_interrupt(void);
 
-void smp_flush_tlb_all(void);
 static void flush_tlb_all_ipi(void *);
-
-void smp_flush_tlb_mm(struct mm_struct *);
-void smp_flush_tlb_range(struct vm_area_struct *, unsigned long, \
-       unsigned long);
-void smp_flush_tlb_page(struct vm_area_struct *, unsigned long);
 static void flush_tlb_others(cpumask_t, struct mm_struct *,
        struct vm_area_struct *, unsigned long);
+
 void smp_invalidate_interrupt(void);
 
-void smp_send_stop(void);
 static void stop_this_cpu(void *);
 
-void smp_send_timer(void);
 void smp_ipi_timer_interrupt(struct pt_regs *);
 void smp_local_timer_interrupt(void);
 
 static void send_IPI_allbutself(int, int);
 static void send_IPI_mask(const struct cpumask *, int, int);
-unsigned long send_IPI_mask_phys(cpumask_t, int, int);
 
 /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
 /* Rescheduling request Routines                                             */
@@ -162,10 +152,10 @@ void smp_flush_cache_all(void)
        unsigned long *mask;
 
        preempt_disable();
-       cpumask = cpu_online_map;
-       cpu_clear(smp_processor_id(), cpumask);
+       cpumask_copy(&cpumask, cpu_online_mask);
+       cpumask_clear_cpu(smp_processor_id(), &cpumask);
        spin_lock(&flushcache_lock);
-       mask=cpus_addr(cpumask);
+       mask=cpumask_bits(&cpumask);
        atomic_set_mask(*mask, (atomic_t *)&flushcache_cpumask);
        send_IPI_mask(&cpumask, INVALIDATE_CACHE_IPI, 0);
        _flush_cache_copyback_all();
@@ -263,8 +253,8 @@ void smp_flush_tlb_mm(struct mm_struct *mm)
        preempt_disable();
        cpu_id = smp_processor_id();
        mmc = &mm->context[cpu_id];
-       cpu_mask = *mm_cpumask(mm);
-       cpu_clear(cpu_id, cpu_mask);
+       cpumask_copy(&cpu_mask, mm_cpumask(mm));
+       cpumask_clear_cpu(cpu_id, &cpu_mask);
 
        if (*mmc != NO_CONTEXT) {
                local_irq_save(flags);
@@ -275,7 +265,7 @@ void smp_flush_tlb_mm(struct mm_struct *mm)
                        cpumask_clear_cpu(cpu_id, mm_cpumask(mm));
                local_irq_restore(flags);
        }
-       if (!cpus_empty(cpu_mask))
+       if (!cpumask_empty(&cpu_mask))
                flush_tlb_others(cpu_mask, mm, NULL, FLUSH_ALL);
 
        preempt_enable();
@@ -333,8 +323,8 @@ void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
        preempt_disable();
        cpu_id = smp_processor_id();
        mmc = &mm->context[cpu_id];
-       cpu_mask = *mm_cpumask(mm);
-       cpu_clear(cpu_id, cpu_mask);
+       cpumask_copy(&cpu_mask, mm_cpumask(mm));
+       cpumask_clear_cpu(cpu_id, &cpu_mask);
 
 #ifdef DEBUG_SMP
        if (!mm)
@@ -348,7 +338,7 @@ void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
                __flush_tlb_page(va);
                local_irq_restore(flags);
        }
-       if (!cpus_empty(cpu_mask))
+       if (!cpumask_empty(&cpu_mask))
                flush_tlb_others(cpu_mask, mm, vma, va);
 
        preempt_enable();
@@ -395,14 +385,14 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
         * - current CPU must not be in mask
         * - mask must exist :)
         */
-       BUG_ON(cpus_empty(cpumask));
+       BUG_ON(cpumask_empty(&cpumask));
 
-       BUG_ON(cpu_isset(smp_processor_id(), cpumask));
+       BUG_ON(cpumask_test_cpu(smp_processor_id(), &cpumask));
        BUG_ON(!mm);
 
        /* If a CPU which we ran on has gone down, OK. */
-       cpus_and(cpumask, cpumask, cpu_online_map);
-       if (cpus_empty(cpumask))
+       cpumask_and(&cpumask, &cpumask, cpu_online_mask);
+       if (cpumask_empty(&cpumask))
                return;
 
        /*
@@ -416,7 +406,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
        flush_mm = mm;
        flush_vma = vma;
        flush_va = va;
-       mask=cpus_addr(cpumask);
+       mask=cpumask_bits(&cpumask);
        atomic_set_mask(*mask, (atomic_t *)&flush_cpumask);
 
        /*
@@ -425,7 +415,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
         */
        send_IPI_mask(&cpumask, INVALIDATE_TLB_IPI, 0);
 
-       while (!cpus_empty(flush_cpumask)) {
+       while (!cpumask_empty((cpumask_t*)&flush_cpumask)) {
                /* nothing. lockup detection does not belong here */
                mb();
        }
@@ -460,7 +450,7 @@ void smp_invalidate_interrupt(void)
        int cpu_id = smp_processor_id();
        unsigned long *mmc = &flush_mm->context[cpu_id];
 
-       if (!cpu_isset(cpu_id, flush_cpumask))
+       if (!cpumask_test_cpu(cpu_id, &flush_cpumask))
                return;
 
        if (flush_va == FLUSH_ALL) {
@@ -478,7 +468,7 @@ void smp_invalidate_interrupt(void)
                        __flush_tlb_page(va);
                }
        }
-       cpu_clear(cpu_id, flush_cpumask);
+       cpumask_clear_cpu(cpu_id, (cpumask_t*)&flush_cpumask);
 }
 
 /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
@@ -530,7 +520,7 @@ static void stop_this_cpu(void *dummy)
        /*
         * Remove this CPU:
         */
-       cpu_clear(cpu_id, cpu_online_map);
+       set_cpu_online(cpu_id, false);
 
        /*
         * PSW IE = 1;
@@ -725,8 +715,8 @@ static void send_IPI_allbutself(int ipi_num, int try)
 {
        cpumask_t cpumask;
 
-       cpumask = cpu_online_map;
-       cpu_clear(smp_processor_id(), cpumask);
+       cpumask_copy(&cpumask, cpu_online_mask);
+       cpumask_clear_cpu(smp_processor_id(), &cpumask);
 
        send_IPI_mask(&cpumask, ipi_num, try);
 }
@@ -763,13 +753,13 @@ static void send_IPI_mask(const struct cpumask *cpumask, int ipi_num, int try)
        cpumask_and(&tmp, cpumask, cpu_online_mask);
        BUG_ON(!cpumask_equal(cpumask, &tmp));
 
-       physid_mask = CPU_MASK_NONE;
+       cpumask_clear(&physid_mask);
        for_each_cpu(cpu_id, cpumask) {
                if ((phys_id = cpu_to_physid(cpu_id)) != -1)
-                       cpu_set(phys_id, physid_mask);
+                       cpumask_set_cpu(phys_id, &physid_mask);
        }
 
-       send_IPI_mask_phys(physid_mask, ipi_num, try);
+       send_IPI_mask_phys(&physid_mask, ipi_num, try);
 }
 
 /*==========================================================================*
@@ -792,14 +782,14 @@ static void send_IPI_mask(const struct cpumask *cpumask, int ipi_num, int try)
  * ---------- --- --------------------------------------------------------
  *
  *==========================================================================*/
-unsigned long send_IPI_mask_phys(cpumask_t physid_mask, int ipi_num,
+unsigned long send_IPI_mask_phys(const cpumask_t *physid_mask, int ipi_num,
        int try)
 {
        spinlock_t *ipilock;
        volatile unsigned long *ipicr_addr;
        unsigned long ipicr_val;
        unsigned long my_physid_mask;
-       unsigned long mask = cpus_addr(physid_mask)[0];
+       unsigned long mask = cpumask_bits(physid_mask)[0];
 
 
        if (mask & ~physids_coerce(phys_cpu_present_map))
index e034844cfc0d948095104ca874d8a9ca02135184..cfdbe5d15002070d1b9f84e3a26656184be5c16d 100644 (file)
@@ -135,9 +135,9 @@ void __devinit smp_prepare_boot_cpu(void)
 {
        bsp_phys_id = hard_smp_processor_id();
        physid_set(bsp_phys_id, phys_cpu_present_map);
-       cpu_set(0, cpu_online_map);     /* BSP's cpu_id == 0 */
-       cpu_set(0, cpu_callout_map);
-       cpu_set(0, cpu_callin_map);
+       set_cpu_online(0, true);        /* BSP's cpu_id == 0 */
+       cpumask_set_cpu(0, &cpu_callout_map);
+       cpumask_set_cpu(0, &cpu_callin_map);
 
        /*
         * Initialize the logical to physical CPU number mapping
@@ -178,7 +178,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        for (phys_id = 0 ; phys_id < nr_cpu ; phys_id++)
                physid_set(phys_id, phys_cpu_present_map);
 #ifndef CONFIG_HOTPLUG_CPU
-       init_cpu_present(&cpu_possible_map);
+       init_cpu_present(cpu_possible_mask);
 #endif
 
        show_mp_info(nr_cpu);
@@ -294,10 +294,10 @@ static void __init do_boot_cpu(int phys_id)
        send_status = 0;
        boot_status = 0;
 
-       cpu_set(phys_id, cpu_bootout_map);
+       cpumask_set_cpu(phys_id, &cpu_bootout_map);
 
        /* Send Startup IPI */
-       send_IPI_mask_phys(cpumask_of_cpu(phys_id), CPU_BOOT_IPI, 0);
+       send_IPI_mask_phys(cpumask_of(phys_id), CPU_BOOT_IPI, 0);
 
        Dprintk("Waiting for send to finish...\n");
        timeout = 0;
@@ -306,7 +306,7 @@ static void __init do_boot_cpu(int phys_id)
        do {
                Dprintk("+");
                udelay(1000);
-               send_status = !cpu_isset(phys_id, cpu_bootin_map);
+               send_status = !cpumask_test_cpu(phys_id, &cpu_bootin_map);
        } while (send_status && (timeout++ < 100));
 
        Dprintk("After Startup.\n");
@@ -316,19 +316,19 @@ static void __init do_boot_cpu(int phys_id)
                 * allow APs to start initializing.
                 */
                Dprintk("Before Callout %d.\n", cpu_id);
-               cpu_set(cpu_id, cpu_callout_map);
+               cpumask_set_cpu(cpu_id, &cpu_callout_map);
                Dprintk("After Callout %d.\n", cpu_id);
 
                /*
                 * Wait 5s total for a response
                 */
                for (timeout = 0; timeout < 5000; timeout++) {
-                       if (cpu_isset(cpu_id, cpu_callin_map))
+                       if (cpumask_test_cpu(cpu_id, &cpu_callin_map))
                                break;  /* It has booted */
                        udelay(1000);
                }
 
-               if (cpu_isset(cpu_id, cpu_callin_map)) {
+               if (cpumask_test_cpu(cpu_id, &cpu_callin_map)) {
                        /* number CPUs logically, starting from 1 (BSP is 0) */
                        Dprintk("OK.\n");
                } else {
@@ -340,9 +340,9 @@ static void __init do_boot_cpu(int phys_id)
 
        if (send_status || boot_status) {
                unmap_cpu_to_physid(cpu_id, phys_id);
-               cpu_clear(cpu_id, cpu_callout_map);
-               cpu_clear(cpu_id, cpu_callin_map);
-               cpu_clear(cpu_id, cpu_initialized);
+               cpumask_clear_cpu(cpu_id, &cpu_callout_map);
+               cpumask_clear_cpu(cpu_id, &cpu_callin_map);
+               cpumask_clear_cpu(cpu_id, &cpu_initialized);
                cpucount--;
        }
 }
@@ -351,17 +351,17 @@ int __cpuinit __cpu_up(unsigned int cpu_id)
 {
        int timeout;
 
-       cpu_set(cpu_id, smp_commenced_mask);
+       cpumask_set_cpu(cpu_id, &smp_commenced_mask);
 
        /*
         * Wait 5s total for a response
         */
        for (timeout = 0; timeout < 5000; timeout++) {
-               if (cpu_isset(cpu_id, cpu_online_map))
+               if (cpu_online(cpu_id))
                        break;
                udelay(1000);
        }
-       if (!cpu_isset(cpu_id, cpu_online_map))
+       if (!cpu_online(cpu_id))
                BUG();
 
        return 0;
@@ -373,11 +373,11 @@ void __init smp_cpus_done(unsigned int max_cpus)
        unsigned long bogosum = 0;
 
        for (timeout = 0; timeout < 5000; timeout++) {
-               if (cpus_equal(cpu_callin_map, cpu_online_map))
+               if (cpumask_equal(&cpu_callin_map, cpu_online_mask))
                        break;
                udelay(1000);
        }
-       if (!cpus_equal(cpu_callin_map, cpu_online_map))
+       if (!cpumask_equal(&cpu_callin_map, cpu_online_mask))
                BUG();
 
        for (cpu_id = 0 ; cpu_id < num_online_cpus() ; cpu_id++)
@@ -388,7 +388,7 @@ void __init smp_cpus_done(unsigned int max_cpus)
         */
        Dprintk("Before bogomips.\n");
        if (cpucount) {
-               for_each_cpu_mask(cpu_id, cpu_online_map)
+               for_each_cpu(cpu_id,cpu_online_mask)
                        bogosum += cpu_data[cpu_id].loops_per_jiffy;
 
                printk(KERN_INFO "Total of %d processors activated " \
@@ -425,7 +425,7 @@ int __init start_secondary(void *unused)
        cpu_init();
        preempt_disable();
        smp_callin();
-       while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
+       while (!cpumask_test_cpu(smp_processor_id(), &smp_commenced_mask))
                cpu_relax();
 
        smp_online();
@@ -463,7 +463,7 @@ static void __init smp_callin(void)
        int cpu_id = smp_processor_id();
        unsigned long timeout;
 
-       if (cpu_isset(cpu_id, cpu_callin_map)) {
+       if (cpumask_test_cpu(cpu_id, &cpu_callin_map)) {
                printk("huh, phys CPU#%d, CPU#%d already present??\n",
                        phys_id, cpu_id);
                BUG();
@@ -474,7 +474,7 @@ static void __init smp_callin(void)
        timeout = jiffies + (2 * HZ);
        while (time_before(jiffies, timeout)) {
                /* Has the boot CPU finished it's STARTUP sequence ? */
-               if (cpu_isset(cpu_id, cpu_callout_map))
+               if (cpumask_test_cpu(cpu_id, &cpu_callout_map))
                        break;
                cpu_relax();
        }
@@ -486,7 +486,7 @@ static void __init smp_callin(void)
        }
 
        /* Allow the master to continue. */
-       cpu_set(cpu_id, cpu_callin_map);
+       cpumask_set_cpu(cpu_id, &cpu_callin_map);
 }
 
 static void __init smp_online(void)
@@ -503,7 +503,7 @@ static void __init smp_online(void)
        /* Save our processor parameters */
        smp_store_cpu_info(cpu_id);
 
-       cpu_set(cpu_id, cpu_online_map);
+       set_cpu_online(cpu_id, true);
 }
 
 /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
index 60536e271233c20a1401dc7ee09a70e9251f0d48..528f2e6ad06421e20d9c6f8d30e5d1c24f726350 100644 (file)
@@ -324,3 +324,4 @@ ENTRY(sys_call_table)
        .long sys_ni_syscall
        .long sys_eventfd
        .long sys_fallocate
+       .long sys_setns                 /* 325 */
index cf95aec77460687134d40c0185cd86b95d7aceac..018e4a711d7927cef577e347dac93fb3a22afd75 100644 (file)
@@ -54,7 +54,7 @@ SECTIONS
   __init_begin = .;
   INIT_TEXT_SECTION(PAGE_SIZE)
   INIT_DATA_SECTION(16)
-  PERCPU(32, PAGE_SIZE)
+  PERCPU_SECTION(32)
   . = ALIGN(PAGE_SIZE);
   __init_end = .;
   /* freed after init ends here */
index 5d2858f6eede4283bbb7c61717d021e3cf60797c..2c468e8b5853203099f2125c081d81fd9b6b665e 100644 (file)
@@ -149,6 +149,7 @@ unsigned long __init zone_sizes_init(void)
                zholes_size[ZONE_DMA] = mp->holes;
                holes += zholes_size[ZONE_DMA];
 
+               node_set_state(nid, N_NORMAL_MEMORY);
                free_area_init_node(nid, zones_size, start_pfn, zholes_size);
        }
 
index 73e2205ebf5afba2c17ca848701c0ae026f52fab..78b660e903da0d38ffba80724271b56dc9f1e3f7 100644 (file)
@@ -35,8 +35,6 @@ extern char __init_begin, __init_end;
 
 pgd_t swapper_pg_dir[1024];
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 /*
  * Cache of MMU context last used.
  */
index 75531da02a40a602cd3cabd5a11f041f7786b4a0..d66e34c718d0927a6eba9daa9a023b7e3bcd228a 100644 (file)
@@ -5,6 +5,7 @@ config M68K
        select HAVE_AOUT if MMU
        select GENERIC_ATOMIC64 if MMU
        select HAVE_GENERIC_HARDIRQS if !MMU
+       select GENERIC_IRQ_SHOW if !MMU
 
 config RWSEM_GENERIC_SPINLOCK
        bool
index 273bccab9517c719fa893d58c5f6631ba9f1f15e..b004dc1b1710bc3f8bfceddf7695266249b5bbdb 100644 (file)
@@ -2,10 +2,6 @@ config FPU
        bool
        default n
 
-config GENERIC_FIND_NEXT_BIT
-       bool
-       default y
-
 config GENERIC_GPIO
        bool
        default n
@@ -18,6 +14,33 @@ config GENERIC_CLOCKEVENTS
        bool
        default n
 
+config M68000
+       bool
+       help
+         The Freescale (was Motorola) 68000 CPU is the first generation of
+         the well known M68K family of processors. The CPU core as well as
+         being available as a stand alone CPU was also used in many
+         System-On-Chip devices (eg 68328, 68302, etc). It does not contain
+         a paging MMU.
+
+config MCPU32
+       bool
+       help
+         The Freescale (was then Motorola) CPU32 is a CPU core that is
+         based on the 68020 processor. For the most part it is used in
+         System-On-Chip parts, and does not contain a paging MMU.
+
+config COLDFIRE
+       bool
+       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       help
+         The Freescale ColdFire family of processors is a modern derivitive
+         of the 68000 processor family. They are mainly targeted at embedded
+         applications, and are all System-On-Chip (SOC) devices, as opposed
+         to stand alone CPUs. They implement a subset of the original 68000
+         processor instruction set.
+
 config COLDFIRE_SW_A7
        bool
        default n
@@ -40,26 +63,31 @@ choice
 
 config M68328
        bool "MC68328"
+       select M68000
        help
          Motorola 68328 processor support.
 
 config M68EZ328
        bool "MC68EZ328"
+       select M68000
        help
          Motorola 68EX328 processor support.
 
 config M68VZ328
        bool "MC68VZ328"
+       select M68000
        help
          Motorola 68VZ328 processor support.
 
 config M68360
        bool "MC68360"
+       select MCPU32
        help
          Motorola 68360 processor support.
 
 config M5206
        bool "MCF5206"
+       select COLDFIRE
        select COLDFIRE_SW_A7
        select HAVE_MBAR
        help
@@ -67,6 +95,7 @@ config M5206
 
 config M5206e
        bool "MCF5206e"
+       select COLDFIRE
        select COLDFIRE_SW_A7
        select HAVE_MBAR
        help
@@ -74,6 +103,7 @@ config M5206e
 
 config M520x
        bool "MCF520x"
+       select COLDFIRE
        select GENERIC_CLOCKEVENTS
        select HAVE_CACHE_SPLIT
        help
@@ -81,6 +111,7 @@ config M520x
 
 config M523x
        bool "MCF523x"
+       select COLDFIRE
        select GENERIC_CLOCKEVENTS
        select HAVE_CACHE_SPLIT
        select HAVE_IPSBAR
@@ -89,6 +120,7 @@ config M523x
 
 config M5249
        bool "MCF5249"
+       select COLDFIRE
        select COLDFIRE_SW_A7
        select HAVE_MBAR
        help
@@ -96,6 +128,7 @@ config M5249
 
 config M5271
        bool "MCF5271"
+       select COLDFIRE
        select HAVE_CACHE_SPLIT
        select HAVE_IPSBAR
        help
@@ -103,6 +136,7 @@ config M5271
 
 config M5272
        bool "MCF5272"
+       select COLDFIRE
        select COLDFIRE_SW_A7
        select HAVE_MBAR
        help
@@ -110,6 +144,7 @@ config M5272
 
 config M5275
        bool "MCF5275"
+       select COLDFIRE
        select HAVE_CACHE_SPLIT
        select HAVE_IPSBAR
        help
@@ -117,6 +152,7 @@ config M5275
 
 config M528x
        bool "MCF528x"
+       select COLDFIRE
        select GENERIC_CLOCKEVENTS
        select HAVE_CACHE_SPLIT
        select HAVE_IPSBAR
@@ -125,6 +161,7 @@ config M528x
 
 config M5307
        bool "MCF5307"
+       select COLDFIRE
        select COLDFIRE_SW_A7
        select HAVE_CACHE_CB
        select HAVE_MBAR
@@ -133,12 +170,14 @@ config M5307
 
 config M532x
        bool "MCF532x"
+       select COLDFIRE
        select HAVE_CACHE_CB
        help
          Freescale (Motorola) ColdFire 532x processor support.
 
 config M5407
        bool "MCF5407"
+       select COLDFIRE
        select COLDFIRE_SW_A7
        select HAVE_CACHE_CB
        select HAVE_MBAR
@@ -147,6 +186,7 @@ config M5407
 
 config M547x
        bool "MCF547x"
+       select COLDFIRE
        select HAVE_CACHE_CB
        select HAVE_MBAR
        help
@@ -154,6 +194,7 @@ config M547x
 
 config M548x
        bool "MCF548x"
+       select COLDFIRE
        select HAVE_CACHE_CB
        select HAVE_MBAR
        help
@@ -172,13 +213,6 @@ config M54xx
        depends on (M548x || M547x)
        default y
 
-config COLDFIRE
-       bool
-       depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407 || M54xx)
-       select GENERIC_GPIO
-       select ARCH_REQUIRE_GPIOLIB
-       default y
-
 config CLOCK_SET
        bool "Enable setting the CPU clock frequency"
        default n
index e9020f88a748f4ae5905015eaa300e793a447732..89cf5b814a4d77ced1629524cc7e1a6d5ea481d6 100644 (file)
@@ -200,6 +200,7 @@ out:
        res += ((long)p - (long)vaddr - 4) * 8;
        return res < size ? res : size;
 }
+#define find_first_zero_bit find_first_zero_bit
 
 static inline int find_next_zero_bit(const unsigned long *vaddr, int size,
                                     int offset)
@@ -229,6 +230,7 @@ static inline int find_next_zero_bit(const unsigned long *vaddr, int size,
        /* No zero yet, search remaining full bytes for a zero */
        return offset + find_first_zero_bit(p, size - offset);
 }
+#define find_next_zero_bit find_next_zero_bit
 
 static inline int find_first_bit(const unsigned long *vaddr, unsigned size)
 {
@@ -253,6 +255,7 @@ out:
        res += ((long)p - (long)vaddr - 4) * 8;
        return res < size ? res : size;
 }
+#define find_first_bit find_first_bit
 
 static inline int find_next_bit(const unsigned long *vaddr, int size,
                                int offset)
@@ -282,6 +285,7 @@ static inline int find_next_bit(const unsigned long *vaddr, int size,
        /* No one yet, search remaining full bytes for a one */
        return offset + find_first_bit(p, size - offset);
 }
+#define find_next_bit find_next_bit
 
 /*
  * ffz = Find First Zero in word. Undefined if no zero exists,
@@ -398,6 +402,7 @@ out:
        res += (p - addr) * 32;
        return res < size ? res : size;
 }
+#define find_first_zero_bit_le find_first_zero_bit_le
 
 static inline unsigned long find_next_zero_bit_le(const void *addr,
                unsigned long size, unsigned long offset)
@@ -427,6 +432,7 @@ static inline unsigned long find_next_zero_bit_le(const void *addr,
        /* No zero yet, search remaining full bytes for a zero */
        return offset + find_first_zero_bit_le(p, size - offset);
 }
+#define find_next_zero_bit_le find_next_zero_bit_le
 
 static inline int find_first_bit_le(const void *vaddr, unsigned size)
 {
@@ -451,6 +457,7 @@ out:
        res += (p - addr) * 32;
        return res < size ? res : size;
 }
+#define find_first_bit_le find_first_bit_le
 
 static inline unsigned long find_next_bit_le(const void *addr,
                unsigned long size, unsigned long offset)
@@ -480,6 +487,7 @@ static inline unsigned long find_next_bit_le(const void *addr,
        /* No set bit yet, search remaining full bytes for a set bit */
        return offset + find_first_bit_le(p, size - offset);
 }
+#define find_next_bit_le find_next_bit_le
 
 /* Bitmap functions for the ext2 filesystem. */
 
index 7d3779fdc5b6ffa68c6b7374fa106cbb50fd4bb8..72e85acdd7bd5f6f61f9a071d909a347ea2a5a56 100644 (file)
@@ -246,23 +246,7 @@ static inline int __test_and_clear_bit_le(int nr, volatile void *addr)
        return retval;
 }
 
-#define ext2_set_bit_atomic(lock, nr, addr)            \
-       ({                                              \
-               int ret;                                \
-               spin_lock(lock);                        \
-               ret = __test_and_set_bit_le((nr), (addr));      \
-               spin_unlock(lock);                      \
-               ret;                                    \
-       })
-
-#define ext2_clear_bit_atomic(lock, nr, addr)          \
-       ({                                              \
-               int ret;                                \
-               spin_lock(lock);                        \
-               ret = __test_and_clear_bit_le((nr), (addr));    \
-               spin_unlock(lock);                      \
-               ret;                                    \
-       })
+#include <asm-generic/bitops/ext2-atomic.h>
 
 static inline int test_bit_le(int nr, const volatile void *addr)
 {
@@ -335,6 +319,10 @@ found_first:
 found_middle:
        return result + ffz(__swab32(tmp));
 }
+#define find_next_zero_bit_le find_next_zero_bit_le
+
+extern unsigned long find_next_bit_le(const void *addr,
+               unsigned long size, unsigned long offset);
 
 #endif /* __KERNEL__ */
 
index cf20f3097af6f3e31c7c6ab76b7363b9dcc99615..353bf754a9725a490e12eb9528555d256fd797fd 100644 (file)
@@ -144,8 +144,10 @@ static inline void io_insl(unsigned int addr, void *buf, int len)
 #define IOMAP_NOCACHE_NONSER           2
 #define IOMAP_WRITETHROUGH             3
 
-extern void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag);
-
+static inline void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
+{
+       return (void *) physaddr;
+}
 static inline void *ioremap(unsigned long physaddr, unsigned long size)
 {
        return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
@@ -163,7 +165,7 @@ static inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size
        return __ioremap(physaddr, size, IOMAP_FULL_CACHING);
 }
 
-extern void iounmap(void *addr);
+#define        iounmap(addr)   do { } while(0)
 
 /*
  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
index f3b649de2a1bf812d78dc360c828360cd3591675..43f984e93970b8acbabbfd6554920a4b4fb265f4 100644 (file)
 #define __NR_open_by_handle_at 341
 #define __NR_clock_adjtime     342
 #define __NR_syncfs            343
+#define __NR_setns             344
 
 #ifdef __KERNEL__
 
-#define NR_syscalls            344
+#define NR_syscalls            345
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 59a69a5c62f25243bb9ddbb3195ee1b3d1469bf8..983fed9d469b3979ed8f5e251631434e6ad1f61b 100644 (file)
@@ -1,5 +1,105 @@
-#ifdef CONFIG_MMU
-#include "asm-offsets_mm.c"
+/*
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
+ */
+
+#define ASM_OFFSETS_C
+
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/kbuild.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/amigahw.h>
+#include <linux/font.h>
+
+int main(void)
+{
+       /* offsets into the task struct */
+       DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
+       DEFINE(TASK_MM, offsetof(struct task_struct, mm));
+       DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));
+       DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info));
+
+       /* offsets into the thread struct */
+       DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
+       DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
+       DEFINE(THREAD_SR, offsetof(struct thread_struct, sr));
+       DEFINE(THREAD_FS, offsetof(struct thread_struct, fs));
+       DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp));
+       DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
+       DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp));
+       DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
+       DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
+
+       /* offsets into the thread_info struct */
+       DEFINE(TINFO_PREEMPT, offsetof(struct thread_info, preempt_count));
+       DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags));
+
+       /* offsets into the pt_regs */
+       DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0));
+       DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0));
+       DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1));
+       DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2));
+       DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3));
+       DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4));
+       DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5));
+       DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0));
+       DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1));
+       DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2));
+       DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc));
+       DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr));
+
+       /* bitfields are a bit difficult */
+#ifdef CONFIG_COLDFIRE
+       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
 #else
-#include "asm-offsets_no.c"
+       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
+#endif
+
+       /* offsets into the irq_cpustat_t struct */
+       DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
+
+       /* signal defines */
+       DEFINE(LSIGSEGV, SIGSEGV);
+       DEFINE(LSEGV_MAPERR, SEGV_MAPERR);
+       DEFINE(LSIGTRAP, SIGTRAP);
+       DEFINE(LTRAP_TRACE, TRAP_TRACE);
+
+#ifdef CONFIG_MMU
+       /* offsets into the bi_record struct */
+       DEFINE(BIR_TAG, offsetof(struct bi_record, tag));
+       DEFINE(BIR_SIZE, offsetof(struct bi_record, size));
+       DEFINE(BIR_DATA, offsetof(struct bi_record, data));
+
+       /* offsets into font_desc (drivers/video/console/font.h) */
+       DEFINE(FONT_DESC_IDX, offsetof(struct font_desc, idx));
+       DEFINE(FONT_DESC_NAME, offsetof(struct font_desc, name));
+       DEFINE(FONT_DESC_WIDTH, offsetof(struct font_desc, width));
+       DEFINE(FONT_DESC_HEIGHT, offsetof(struct font_desc, height));
+       DEFINE(FONT_DESC_DATA, offsetof(struct font_desc, data));
+       DEFINE(FONT_DESC_PREF, offsetof(struct font_desc, pref));
+
+       /* offsets into the custom struct */
+       DEFINE(CUSTOMBASE, &amiga_custom);
+       DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar));
+       DEFINE(C_INTREQR, offsetof(struct CUSTOM, intreqr));
+       DEFINE(C_INTENA, offsetof(struct CUSTOM, intena));
+       DEFINE(C_INTREQ, offsetof(struct CUSTOM, intreq));
+       DEFINE(C_SERDATR, offsetof(struct CUSTOM, serdatr));
+       DEFINE(C_SERDAT, offsetof(struct CUSTOM, serdat));
+       DEFINE(C_SERPER, offsetof(struct CUSTOM, serper));
+       DEFINE(CIAABASE, &ciaa);
+       DEFINE(CIABBASE, &ciab);
+       DEFINE(C_PRA, offsetof(struct CIA, pra));
+       DEFINE(ZTWOBASE, zTwoBase);
 #endif
+
+       return 0;
+}
diff --git a/arch/m68k/kernel/asm-offsets_mm.c b/arch/m68k/kernel/asm-offsets_mm.c
deleted file mode 100644 (file)
index 78e59b8..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * This program is used to generate definitions needed by
- * assembly language modules.
- *
- * We use the technique used in the OSF Mach kernel code:
- * generate asm statements containing #defines,
- * compile this file to assembler, and then extract the
- * #defines from the assembly-language output.
- */
-
-#define ASM_OFFSETS_C
-
-#include <linux/stddef.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/kbuild.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/amigahw.h>
-#include <linux/font.h>
-
-int main(void)
-{
-       /* offsets into the task struct */
-       DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
-       DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));
-       DEFINE(TASK_MM, offsetof(struct task_struct, mm));
-#ifdef CONFIG_MMU
-       DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info));
-#endif
-
-       /* offsets into the thread struct */
-       DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
-       DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
-       DEFINE(THREAD_SR, offsetof(struct thread_struct, sr));
-       DEFINE(THREAD_FS, offsetof(struct thread_struct, fs));
-       DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp));
-       DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
-       DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp));
-       DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
-       DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
-
-       /* offsets into the thread_info struct */
-       DEFINE(TINFO_PREEMPT, offsetof(struct thread_info, preempt_count));
-       DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags));
-
-       /* offsets into the pt_regs */
-       DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0));
-       DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0));
-       DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1));
-       DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2));
-       DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3));
-       DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4));
-       DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5));
-       DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0));
-       DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1));
-       DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2));
-       DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc));
-       DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr));
-       /* bitfields are a bit difficult */
-       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
-
-       /* offsets into the irq_cpustat_t struct */
-       DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
-
-       /* offsets into the bi_record struct */
-       DEFINE(BIR_TAG, offsetof(struct bi_record, tag));
-       DEFINE(BIR_SIZE, offsetof(struct bi_record, size));
-       DEFINE(BIR_DATA, offsetof(struct bi_record, data));
-
-       /* offsets into font_desc (drivers/video/console/font.h) */
-       DEFINE(FONT_DESC_IDX, offsetof(struct font_desc, idx));
-       DEFINE(FONT_DESC_NAME, offsetof(struct font_desc, name));
-       DEFINE(FONT_DESC_WIDTH, offsetof(struct font_desc, width));
-       DEFINE(FONT_DESC_HEIGHT, offsetof(struct font_desc, height));
-       DEFINE(FONT_DESC_DATA, offsetof(struct font_desc, data));
-       DEFINE(FONT_DESC_PREF, offsetof(struct font_desc, pref));
-
-       /* signal defines */
-       DEFINE(LSIGSEGV, SIGSEGV);
-       DEFINE(LSEGV_MAPERR, SEGV_MAPERR);
-       DEFINE(LSIGTRAP, SIGTRAP);
-       DEFINE(LTRAP_TRACE, TRAP_TRACE);
-
-       /* offsets into the custom struct */
-       DEFINE(CUSTOMBASE, &amiga_custom);
-       DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar));
-       DEFINE(C_INTREQR, offsetof(struct CUSTOM, intreqr));
-       DEFINE(C_INTENA, offsetof(struct CUSTOM, intena));
-       DEFINE(C_INTREQ, offsetof(struct CUSTOM, intreq));
-       DEFINE(C_SERDATR, offsetof(struct CUSTOM, serdatr));
-       DEFINE(C_SERDAT, offsetof(struct CUSTOM, serdat));
-       DEFINE(C_SERPER, offsetof(struct CUSTOM, serper));
-       DEFINE(CIAABASE, &ciaa);
-       DEFINE(CIABBASE, &ciab);
-       DEFINE(C_PRA, offsetof(struct CIA, pra));
-       DEFINE(ZTWOBASE, zTwoBase);
-
-       return 0;
-}
diff --git a/arch/m68k/kernel/asm-offsets_no.c b/arch/m68k/kernel/asm-offsets_no.c
deleted file mode 100644 (file)
index ffe02f4..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * This program is used to generate definitions needed by
- * assembly language modules.
- *
- * We use the technique used in the OSF Mach kernel code:
- * generate asm statements containing #defines,
- * compile this file to assembler, and then extract the
- * #defines from the assembly-language output.
- */
-
-#include <linux/stddef.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/ptrace.h>
-#include <linux/hardirq.h>
-#include <linux/kbuild.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/thread_info.h>
-
-int main(void)
-{
-       /* offsets into the task struct */
-       DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
-       DEFINE(TASK_MM, offsetof(struct task_struct, mm));
-
-       /* offsets into the irq_cpustat_t struct */
-       DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
-
-       /* offsets into the thread struct */
-       DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
-       DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
-       DEFINE(THREAD_SR, offsetof(struct thread_struct, sr));
-       DEFINE(THREAD_FS, offsetof(struct thread_struct, fs));
-       DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp));
-       DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
-       DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp));
-       DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
-       DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
-
-       /* offsets into the pt_regs */
-       DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0));
-       DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0));
-       DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1));
-       DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2));
-       DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3));
-       DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4));
-       DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5));
-       DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0));
-       DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1));
-       DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2));
-       DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc));
-       DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr));
-
-#ifdef CONFIG_COLDFIRE
-       /* bitfields are a bit difficult */
-       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
-#else
-       /* bitfields are a bit difficult */
-       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
-#endif
-
-       /* signal defines */
-       DEFINE(SIGSEGV, SIGSEGV);
-       DEFINE(SEGV_MAPERR, SEGV_MAPERR);
-       DEFINE(SIGTRAP, SIGTRAP);
-       DEFINE(TRAP_TRACE, TRAP_TRACE);
-
-       DEFINE(PT_PTRACED, PT_PTRACED);
-
-       /* Offsets in thread_info structure */
-       DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
-       DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count));
-
-       return 0;
-}
index 2783f25e38bda453345bfc4994cc0853bb071965..5f0f6b598b5a6d1ee347436f6f7232491ca9ae36 100644 (file)
@@ -24,7 +24,6 @@
  * linux 2.4 support David McCullough <davidm@snapgear.com>
  */
 
-#include <linux/sys.h>
 #include <linux/linkage.h>
 #include <asm/errno.h>
 #include <asm/setup.h>
index 15dbc3e9d20c5594cdf96d9655898ef7ad378285..544b8717d49913bff339695db2d25f255d4734a1 100644 (file)
@@ -28,31 +28,3 @@ asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
 
        set_irq_regs(oldregs);
 }
-
-int show_interrupts(struct seq_file *p, void *v)
-{
-       struct irqaction *ap;
-       int irq = *((loff_t *) v);
-
-       if (irq == 0)
-               seq_puts(p, "           CPU0\n");
-
-       if (irq < NR_IRQS) {
-               struct irq_desc *desc = irq_to_desc(irq);
-
-               ap = desc->action;
-               if (ap) {
-                       seq_printf(p, "%3d: ", irq);
-                       seq_printf(p, "%10u ", kstat_irqs(irq));
-                       seq_printf(p, "%14s  ", irq_desc_get_chip(desc)->name);
-
-                       seq_printf(p, "%s", ap->name);
-                       for (ap = ap->next; ap; ap = ap->next)
-                               seq_printf(p, ", %s", ap->name);
-                       seq_putc(p, '\n');
-               }
-       }
-
-       return 0;
-}
-
index 4752c28ce0acefbb42a3f374db1636d425fcda07..1b7a14d1a00070af31fe62299f6dbe3b8e03d4be 100644 (file)
@@ -1,5 +1,32 @@
-#ifdef CONFIG_MMU
-#include "m68k_ksyms_mm.c"
-#else
-#include "m68k_ksyms_no.c"
+#include <linux/module.h>
+
+asmlinkage long long __ashldi3 (long long, int);
+asmlinkage long long __ashrdi3 (long long, int);
+asmlinkage long long __lshrdi3 (long long, int);
+asmlinkage long long __muldi3 (long long, long long);
+
+/* The following are special because they're not called
+   explicitly (the C compiler generates them).  Fortunately,
+   their interface isn't gonna change any time soon now, so
+   it's OK to leave it out of version control.  */
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__muldi3);
+
+#if defined(CONFIG_M68000) || defined(CONFIG_COLDFIRE)
+/*
+ * Simpler 68k and ColdFire parts also need a few other gcc functions.
+ */
+extern long long __divsi3(long long, long long);
+extern long long __modsi3(long long, long long);
+extern long long __mulsi3(long long, long long);
+extern long long __udivsi3(long long, long long);
+extern long long __umodsi3(long long, long long);
+
+EXPORT_SYMBOL(__divsi3);
+EXPORT_SYMBOL(__modsi3);
+EXPORT_SYMBOL(__mulsi3);
+EXPORT_SYMBOL(__udivsi3);
+EXPORT_SYMBOL(__umodsi3);
 #endif
diff --git a/arch/m68k/kernel/m68k_ksyms_mm.c b/arch/m68k/kernel/m68k_ksyms_mm.c
deleted file mode 100644 (file)
index d900e77..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <linux/module.h>
-
-asmlinkage long long __ashldi3 (long long, int);
-asmlinkage long long __ashrdi3 (long long, int);
-asmlinkage long long __lshrdi3 (long long, int);
-asmlinkage long long __muldi3 (long long, long long);
-
-/* The following are special because they're not called
-   explicitly (the C compiler generates them).  Fortunately,
-   their interface isn't gonna change any time soon now, so
-   it's OK to leave it out of version control.  */
-EXPORT_SYMBOL(__ashldi3);
-EXPORT_SYMBOL(__ashrdi3);
-EXPORT_SYMBOL(__lshrdi3);
-EXPORT_SYMBOL(__muldi3);
-
diff --git a/arch/m68k/kernel/m68k_ksyms_no.c b/arch/m68k/kernel/m68k_ksyms_no.c
deleted file mode 100644 (file)
index 39fe0a7..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#include <linux/module.h>
-#include <linux/linkage.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/user.h>
-#include <linux/elfcore.h>
-#include <linux/in6.h>
-#include <linux/interrupt.h>
-
-#include <asm/setup.h>
-#include <asm/machdep.h>
-#include <asm/pgalloc.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/checksum.h>
-#include <asm/current.h>
-
-extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
-
-/* platform dependent support */
-
-EXPORT_SYMBOL(__ioremap);
-EXPORT_SYMBOL(iounmap);
-EXPORT_SYMBOL(dump_fpu);
-
-EXPORT_SYMBOL(ip_fast_csum);
-
-EXPORT_SYMBOL(kernel_thread);
-
-/* Networking helper routines. */
-EXPORT_SYMBOL(csum_partial_copy_nocheck);
-
-/* The following are special because they're not called
-   explicitly (the C compiler generates them).  Fortunately,
-   their interface isn't gonna change any time soon now, so
-   it's OK to leave it out of version control.  */
-EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(memset);
-
-/*
- * libgcc functions - functions that are used internally by the
- * compiler...  (prototypes are not correct though, but that
- * doesn't really matter since they're not versioned).
- */
-extern void __ashldi3(void);
-extern void __ashrdi3(void);
-extern void __divsi3(void);
-extern void __lshrdi3(void);
-extern void __modsi3(void);
-extern void __muldi3(void);
-extern void __mulsi3(void);
-extern void __udivsi3(void);
-extern void __umodsi3(void);
-
-        /* gcc lib functions */
-EXPORT_SYMBOL(__ashldi3);
-EXPORT_SYMBOL(__ashrdi3);
-EXPORT_SYMBOL(__divsi3);
-EXPORT_SYMBOL(__lshrdi3);
-EXPORT_SYMBOL(__modsi3);
-EXPORT_SYMBOL(__muldi3);
-EXPORT_SYMBOL(__mulsi3);
-EXPORT_SYMBOL(__udivsi3);
-EXPORT_SYMBOL(__umodsi3);
-
-#ifdef CONFIG_COLDFIRE
-extern unsigned int *dma_device_address;
-extern unsigned long dma_base_addr, _ramend;
-EXPORT_SYMBOL(dma_base_addr);
-EXPORT_SYMBOL(dma_device_address);
-EXPORT_SYMBOL(_ramend);
-
-extern asmlinkage void trap(void);
-extern void    *_ramvec;
-EXPORT_SYMBOL(trap);
-EXPORT_SYMBOL(_ramvec);
-#endif /* CONFIG_COLDFIRE */
index e2a63af5d517510820cfa9085d46b08bcd403f46..9b86ad11c68e38bca9566ca3911ffff471c2cc5a 100644 (file)
@@ -151,6 +151,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
        set_fs(fs);
        return retval;
 }
+EXPORT_SYMBOL(kernel_thread);
 
 void flush_thread(void)
 {
@@ -283,6 +284,7 @@ int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu)
 #endif
        return 1;
 }
+EXPORT_SYMBOL(dump_fpu);
 
 /*
  *     Generic dumping code. Used for panic and debug.
index 63013df33584d79a8047f623d7f93814b1a31626..8623f8dc16f8a03c9da88910537ae93fc47bc510 100644 (file)
@@ -1,5 +1,580 @@
+/*
+ * linux/arch/m68k/kernel/sys_m68k.c
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/m68k
+ * platform.
+ */
+
+#include <linux/capability.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/smp.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/syscalls.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+#include <linux/ipc.h>
+
+#include <asm/setup.h>
+#include <asm/uaccess.h>
+#include <asm/cachectl.h>
+#include <asm/traps.h>
+#include <asm/page.h>
+#include <asm/unistd.h>
+#include <asm/cacheflush.h>
+
 #ifdef CONFIG_MMU
-#include "sys_m68k_mm.c"
+
+#include <asm/tlb.h>
+
+asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
+                            unsigned long error_code);
+
+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+       unsigned long prot, unsigned long flags,
+       unsigned long fd, unsigned long pgoff)
+{
+       /*
+        * This is wrong for sun3 - there PAGE_SIZE is 8Kb,
+        * so we need to shift the argument down by 1; m68k mmap64(3)
+        * (in libc) expects the last argument of mmap2 in 4Kb units.
+        */
+       return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
+}
+
+/* Convert virtual (user) address VADDR to physical address PADDR */
+#define virt_to_phys_040(vaddr)                                                \
+({                                                                     \
+  unsigned long _mmusr, _paddr;                                                \
+                                                                       \
+  __asm__ __volatile__ (".chip 68040\n\t"                              \
+                       "ptestr (%1)\n\t"                               \
+                       "movec %%mmusr,%0\n\t"                          \
+                       ".chip 68k"                                     \
+                       : "=r" (_mmusr)                                 \
+                       : "a" (vaddr));                                 \
+  _paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0;            \
+  _paddr;                                                              \
+})
+
+static inline int
+cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
+{
+  unsigned long paddr, i;
+
+  switch (scope)
+    {
+    case FLUSH_SCOPE_ALL:
+      switch (cache)
+       {
+       case FLUSH_CACHE_DATA:
+         /* This nop is needed for some broken versions of the 68040.  */
+         __asm__ __volatile__ ("nop\n\t"
+                               ".chip 68040\n\t"
+                               "cpusha %dc\n\t"
+                               ".chip 68k");
+         break;
+       case FLUSH_CACHE_INSN:
+         __asm__ __volatile__ ("nop\n\t"
+                               ".chip 68040\n\t"
+                               "cpusha %ic\n\t"
+                               ".chip 68k");
+         break;
+       default:
+       case FLUSH_CACHE_BOTH:
+         __asm__ __volatile__ ("nop\n\t"
+                               ".chip 68040\n\t"
+                               "cpusha %bc\n\t"
+                               ".chip 68k");
+         break;
+       }
+      break;
+
+    case FLUSH_SCOPE_LINE:
+      /* Find the physical address of the first mapped page in the
+        address range.  */
+      if ((paddr = virt_to_phys_040(addr))) {
+        paddr += addr & ~(PAGE_MASK | 15);
+        len = (len + (addr & 15) + 15) >> 4;
+      } else {
+       unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
+
+       if (len <= tmp)
+         return 0;
+       addr += tmp;
+       len -= tmp;
+       tmp = PAGE_SIZE;
+       for (;;)
+         {
+           if ((paddr = virt_to_phys_040(addr)))
+             break;
+           if (len <= tmp)
+             return 0;
+           addr += tmp;
+           len -= tmp;
+         }
+       len = (len + 15) >> 4;
+      }
+      i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
+      while (len--)
+       {
+         switch (cache)
+           {
+           case FLUSH_CACHE_DATA:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushl %%dc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           case FLUSH_CACHE_INSN:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushl %%ic,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           default:
+           case FLUSH_CACHE_BOTH:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushl %%bc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           }
+         if (!--i && len)
+           {
+             /*
+              * No need to page align here since it is done by
+              * virt_to_phys_040().
+              */
+             addr += PAGE_SIZE;
+             i = PAGE_SIZE / 16;
+             /* Recompute physical address when crossing a page
+                boundary. */
+             for (;;)
+               {
+                 if ((paddr = virt_to_phys_040(addr)))
+                   break;
+                 if (len <= i)
+                   return 0;
+                 len -= i;
+                 addr += PAGE_SIZE;
+               }
+           }
+         else
+           paddr += 16;
+       }
+      break;
+
+    default:
+    case FLUSH_SCOPE_PAGE:
+      len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
+      for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
+       {
+         if (!(paddr = virt_to_phys_040(addr)))
+           continue;
+         switch (cache)
+           {
+           case FLUSH_CACHE_DATA:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushp %%dc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           case FLUSH_CACHE_INSN:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushp %%ic,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           default:
+           case FLUSH_CACHE_BOTH:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushp %%bc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           }
+       }
+      break;
+    }
+  return 0;
+}
+
+#define virt_to_phys_060(vaddr)                                \
+({                                                     \
+  unsigned long paddr;                                 \
+  __asm__ __volatile__ (".chip 68060\n\t"              \
+                       "plpar (%0)\n\t"                \
+                       ".chip 68k"                     \
+                       : "=a" (paddr)                  \
+                       : "0" (vaddr));                 \
+  (paddr); /* XXX */                                   \
+})
+
+static inline int
+cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
+{
+  unsigned long paddr, i;
+
+  /*
+   * 68060 manual says:
+   *  cpush %dc : flush DC, remains valid (with our %cacr setup)
+   *  cpush %ic : invalidate IC
+   *  cpush %bc : flush DC + invalidate IC
+   */
+  switch (scope)
+    {
+    case FLUSH_SCOPE_ALL:
+      switch (cache)
+       {
+       case FLUSH_CACHE_DATA:
+         __asm__ __volatile__ (".chip 68060\n\t"
+                               "cpusha %dc\n\t"
+                               ".chip 68k");
+         break;
+       case FLUSH_CACHE_INSN:
+         __asm__ __volatile__ (".chip 68060\n\t"
+                               "cpusha %ic\n\t"
+                               ".chip 68k");
+         break;
+       default:
+       case FLUSH_CACHE_BOTH:
+         __asm__ __volatile__ (".chip 68060\n\t"
+                               "cpusha %bc\n\t"
+                               ".chip 68k");
+         break;
+       }
+      break;
+
+    case FLUSH_SCOPE_LINE:
+      /* Find the physical address of the first mapped page in the
+        address range.  */
+      len += addr & 15;
+      addr &= -16;
+      if (!(paddr = virt_to_phys_060(addr))) {
+       unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
+
+       if (len <= tmp)
+         return 0;
+       addr += tmp;
+       len -= tmp;
+       tmp = PAGE_SIZE;
+       for (;;)
+         {
+           if ((paddr = virt_to_phys_060(addr)))
+             break;
+           if (len <= tmp)
+             return 0;
+           addr += tmp;
+           len -= tmp;
+         }
+      }
+      len = (len + 15) >> 4;
+      i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
+      while (len--)
+       {
+         switch (cache)
+           {
+           case FLUSH_CACHE_DATA:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushl %%dc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           case FLUSH_CACHE_INSN:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushl %%ic,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           default:
+           case FLUSH_CACHE_BOTH:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushl %%bc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           }
+         if (!--i && len)
+           {
+
+             /*
+              * We just want to jump to the first cache line
+              * in the next page.
+              */
+             addr += PAGE_SIZE;
+             addr &= PAGE_MASK;
+
+             i = PAGE_SIZE / 16;
+             /* Recompute physical address when crossing a page
+                boundary. */
+             for (;;)
+               {
+                 if ((paddr = virt_to_phys_060(addr)))
+                   break;
+                 if (len <= i)
+                   return 0;
+                 len -= i;
+                 addr += PAGE_SIZE;
+               }
+           }
+         else
+           paddr += 16;
+       }
+      break;
+
+    default:
+    case FLUSH_SCOPE_PAGE:
+      len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
+      addr &= PAGE_MASK;       /* Workaround for bug in some
+                                  revisions of the 68060 */
+      for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
+       {
+         if (!(paddr = virt_to_phys_060(addr)))
+           continue;
+         switch (cache)
+           {
+           case FLUSH_CACHE_DATA:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushp %%dc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           case FLUSH_CACHE_INSN:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushp %%ic,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           default:
+           case FLUSH_CACHE_BOTH:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushp %%bc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           }
+       }
+      break;
+    }
+  return 0;
+}
+
+/* sys_cacheflush -- flush (part of) the processor cache.  */
+asmlinkage int
+sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
+{
+       struct vm_area_struct *vma;
+       int ret = -EINVAL;
+
+       if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
+           cache & ~FLUSH_CACHE_BOTH)
+               goto out;
+
+       if (scope == FLUSH_SCOPE_ALL) {
+               /* Only the superuser may explicitly flush the whole cache. */
+               ret = -EPERM;
+               if (!capable(CAP_SYS_ADMIN))
+                       goto out;
+       } else {
+               /*
+                * Verify that the specified address region actually belongs
+                * to this process.
+                */
+               vma = find_vma (current->mm, addr);
+               ret = -EINVAL;
+               /* Check for overflow.  */
+               if (addr + len < addr)
+                       goto out;
+               if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
+                       goto out;
+       }
+
+       if (CPU_IS_020_OR_030) {
+               if (scope == FLUSH_SCOPE_LINE && len < 256) {
+                       unsigned long cacr;
+                       __asm__ ("movec %%cacr, %0" : "=r" (cacr));
+                       if (cache & FLUSH_CACHE_INSN)
+                               cacr |= 4;
+                       if (cache & FLUSH_CACHE_DATA)
+                               cacr |= 0x400;
+                       len >>= 2;
+                       while (len--) {
+                               __asm__ __volatile__ ("movec %1, %%caar\n\t"
+                                                     "movec %0, %%cacr"
+                                                     : /* no outputs */
+                                                     : "r" (cacr), "r" (addr));
+                               addr += 4;
+                       }
+               } else {
+                       /* Flush the whole cache, even if page granularity requested. */
+                       unsigned long cacr;
+                       __asm__ ("movec %%cacr, %0" : "=r" (cacr));
+                       if (cache & FLUSH_CACHE_INSN)
+                               cacr |= 8;
+                       if (cache & FLUSH_CACHE_DATA)
+                               cacr |= 0x800;
+                       __asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr));
+               }
+               ret = 0;
+               goto out;
+       } else {
+           /*
+            * 040 or 060: don't blindly trust 'scope', someone could
+            * try to flush a few megs of memory.
+            */
+
+           if (len>=3*PAGE_SIZE && scope<FLUSH_SCOPE_PAGE)
+               scope=FLUSH_SCOPE_PAGE;
+           if (len>=10*PAGE_SIZE && scope<FLUSH_SCOPE_ALL)
+               scope=FLUSH_SCOPE_ALL;
+           if (CPU_IS_040) {
+               ret = cache_flush_040 (addr, scope, cache, len);
+           } else if (CPU_IS_060) {
+               ret = cache_flush_060 (addr, scope, cache, len);
+           }
+       }
+out:
+       return ret;
+}
+
+/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
+   D1 (newval).  */
+asmlinkage int
+sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
+                     unsigned long __user * mem)
+{
+       /* This was borrowed from ARM's implementation.  */
+       for (;;) {
+               struct mm_struct *mm = current->mm;
+               pgd_t *pgd;
+               pmd_t *pmd;
+               pte_t *pte;
+               spinlock_t *ptl;
+               unsigned long mem_value;
+
+               down_read(&mm->mmap_sem);
+               pgd = pgd_offset(mm, (unsigned long)mem);
+               if (!pgd_present(*pgd))
+                       goto bad_access;
+               pmd = pmd_offset(pgd, (unsigned long)mem);
+               if (!pmd_present(*pmd))
+                       goto bad_access;
+               pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl);
+               if (!pte_present(*pte) || !pte_dirty(*pte)
+                   || !pte_write(*pte)) {
+                       pte_unmap_unlock(pte, ptl);
+                       goto bad_access;
+               }
+
+               mem_value = *mem;
+               if (mem_value == oldval)
+                       *mem = newval;
+
+               pte_unmap_unlock(pte, ptl);
+               up_read(&mm->mmap_sem);
+               return mem_value;
+
+             bad_access:
+               up_read(&mm->mmap_sem);
+               /* This is not necessarily a bad access, we can get here if
+                  a memory we're trying to write to should be copied-on-write.
+                  Make the kernel do the necessary page stuff, then re-iterate.
+                  Simulate a write access fault to do that.  */
+               {
+                       /* The first argument of the function corresponds to
+                          D1, which is the first field of struct pt_regs.  */
+                       struct pt_regs *fp = (struct pt_regs *)&newval;
+
+                       /* '3' is an RMW flag.  */
+                       if (do_page_fault(fp, (unsigned long)mem, 3))
+                               /* If the do_page_fault() failed, we don't
+                                  have anything meaningful to return.
+                                  There should be a SIGSEGV pending for
+                                  the process.  */
+                               return 0xdeadbeef;
+               }
+       }
+}
+
 #else
-#include "sys_m68k_no.c"
-#endif
+
+/* sys_cacheflush -- flush (part of) the processor cache.  */
+asmlinkage int
+sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
+{
+       flush_cache_all();
+       return 0;
+}
+
+/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
+   D1 (newval).  */
+asmlinkage int
+sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
+                     unsigned long __user * mem)
+{
+       struct mm_struct *mm = current->mm;
+       unsigned long mem_value;
+
+       down_read(&mm->mmap_sem);
+
+       mem_value = *mem;
+       if (mem_value == oldval)
+               *mem = newval;
+
+       up_read(&mm->mmap_sem);
+       return mem_value;
+}
+
+#endif /* CONFIG_MMU */
+
+asmlinkage int sys_getpagesize(void)
+{
+       return PAGE_SIZE;
+}
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename,
+                 const char *const argv[],
+                 const char *const envp[])
+{
+       register long __res asm ("%d0") = __NR_execve;
+       register long __a asm ("%d1") = (long)(filename);
+       register long __b asm ("%d2") = (long)(argv);
+       register long __c asm ("%d3") = (long)(envp);
+       asm volatile ("trap  #0" : "+d" (__res)
+                       : "d" (__a), "d" (__b), "d" (__c));
+       return __res;
+}
+
+asmlinkage unsigned long sys_get_thread_area(void)
+{
+       return current_thread_info()->tp_value;
+}
+
+asmlinkage int sys_set_thread_area(unsigned long tp)
+{
+       current_thread_info()->tp_value = tp;
+       return 0;
+}
+
+asmlinkage int sys_atomic_barrier(void)
+{
+       /* no code needed for uniprocs */
+       return 0;
+}
diff --git a/arch/m68k/kernel/sys_m68k_mm.c b/arch/m68k/kernel/sys_m68k_mm.c
deleted file mode 100644 (file)
index 3db2e7f..0000000
+++ /dev/null
@@ -1,546 +0,0 @@
-/*
- * linux/arch/m68k/kernel/sys_m68k.c
- *
- * This file contains various random system calls that
- * have a non-standard calling sequence on the Linux/m68k
- * platform.
- */
-
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/smp.h>
-#include <linux/sem.h>
-#include <linux/msg.h>
-#include <linux/shm.h>
-#include <linux/stat.h>
-#include <linux/syscalls.h>
-#include <linux/mman.h>
-#include <linux/file.h>
-#include <linux/ipc.h>
-
-#include <asm/setup.h>
-#include <asm/uaccess.h>
-#include <asm/cachectl.h>
-#include <asm/traps.h>
-#include <asm/page.h>
-#include <asm/unistd.h>
-#include <linux/elf.h>
-#include <asm/tlb.h>
-
-asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
-                            unsigned long error_code);
-
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags,
-       unsigned long fd, unsigned long pgoff)
-{
-       /*
-        * This is wrong for sun3 - there PAGE_SIZE is 8Kb,
-        * so we need to shift the argument down by 1; m68k mmap64(3)
-        * (in libc) expects the last argument of mmap2 in 4Kb units.
-        */
-       return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
-}
-
-/* Convert virtual (user) address VADDR to physical address PADDR */
-#define virt_to_phys_040(vaddr)                                                \
-({                                                                     \
-  unsigned long _mmusr, _paddr;                                                \
-                                                                       \
-  __asm__ __volatile__ (".chip 68040\n\t"                              \
-                       "ptestr (%1)\n\t"                               \
-                       "movec %%mmusr,%0\n\t"                          \
-                       ".chip 68k"                                     \
-                       : "=r" (_mmusr)                                 \
-                       : "a" (vaddr));                                 \
-  _paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0;            \
-  _paddr;                                                              \
-})
-
-static inline int
-cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
-{
-  unsigned long paddr, i;
-
-  switch (scope)
-    {
-    case FLUSH_SCOPE_ALL:
-      switch (cache)
-       {
-       case FLUSH_CACHE_DATA:
-         /* This nop is needed for some broken versions of the 68040.  */
-         __asm__ __volatile__ ("nop\n\t"
-                               ".chip 68040\n\t"
-                               "cpusha %dc\n\t"
-                               ".chip 68k");
-         break;
-       case FLUSH_CACHE_INSN:
-         __asm__ __volatile__ ("nop\n\t"
-                               ".chip 68040\n\t"
-                               "cpusha %ic\n\t"
-                               ".chip 68k");
-         break;
-       default:
-       case FLUSH_CACHE_BOTH:
-         __asm__ __volatile__ ("nop\n\t"
-                               ".chip 68040\n\t"
-                               "cpusha %bc\n\t"
-                               ".chip 68k");
-         break;
-       }
-      break;
-
-    case FLUSH_SCOPE_LINE:
-      /* Find the physical address of the first mapped page in the
-        address range.  */
-      if ((paddr = virt_to_phys_040(addr))) {
-        paddr += addr & ~(PAGE_MASK | 15);
-        len = (len + (addr & 15) + 15) >> 4;
-      } else {
-       unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
-
-       if (len <= tmp)
-         return 0;
-       addr += tmp;
-       len -= tmp;
-       tmp = PAGE_SIZE;
-       for (;;)
-         {
-           if ((paddr = virt_to_phys_040(addr)))
-             break;
-           if (len <= tmp)
-             return 0;
-           addr += tmp;
-           len -= tmp;
-         }
-       len = (len + 15) >> 4;
-      }
-      i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
-      while (len--)
-       {
-         switch (cache)
-           {
-           case FLUSH_CACHE_DATA:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushl %%dc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           case FLUSH_CACHE_INSN:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushl %%ic,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           default:
-           case FLUSH_CACHE_BOTH:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushl %%bc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           }
-         if (!--i && len)
-           {
-             /*
-              * No need to page align here since it is done by
-              * virt_to_phys_040().
-              */
-             addr += PAGE_SIZE;
-             i = PAGE_SIZE / 16;
-             /* Recompute physical address when crossing a page
-                boundary. */
-             for (;;)
-               {
-                 if ((paddr = virt_to_phys_040(addr)))
-                   break;
-                 if (len <= i)
-                   return 0;
-                 len -= i;
-                 addr += PAGE_SIZE;
-               }
-           }
-         else
-           paddr += 16;
-       }
-      break;
-
-    default:
-    case FLUSH_SCOPE_PAGE:
-      len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
-      for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
-       {
-         if (!(paddr = virt_to_phys_040(addr)))
-           continue;
-         switch (cache)
-           {
-           case FLUSH_CACHE_DATA:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushp %%dc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           case FLUSH_CACHE_INSN:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushp %%ic,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           default:
-           case FLUSH_CACHE_BOTH:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushp %%bc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           }
-       }
-      break;
-    }
-  return 0;
-}
-
-#define virt_to_phys_060(vaddr)                                \
-({                                                     \
-  unsigned long paddr;                                 \
-  __asm__ __volatile__ (".chip 68060\n\t"              \
-                       "plpar (%0)\n\t"                \
-                       ".chip 68k"                     \
-                       : "=a" (paddr)                  \
-                       : "0" (vaddr));                 \
-  (paddr); /* XXX */                                   \
-})
-
-static inline int
-cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
-{
-  unsigned long paddr, i;
-
-  /*
-   * 68060 manual says:
-   *  cpush %dc : flush DC, remains valid (with our %cacr setup)
-   *  cpush %ic : invalidate IC
-   *  cpush %bc : flush DC + invalidate IC
-   */
-  switch (scope)
-    {
-    case FLUSH_SCOPE_ALL:
-      switch (cache)
-       {
-       case FLUSH_CACHE_DATA:
-         __asm__ __volatile__ (".chip 68060\n\t"
-                               "cpusha %dc\n\t"
-                               ".chip 68k");
-         break;
-       case FLUSH_CACHE_INSN:
-         __asm__ __volatile__ (".chip 68060\n\t"
-                               "cpusha %ic\n\t"
-                               ".chip 68k");
-         break;
-       default:
-       case FLUSH_CACHE_BOTH:
-         __asm__ __volatile__ (".chip 68060\n\t"
-                               "cpusha %bc\n\t"
-                               ".chip 68k");
-         break;
-       }
-      break;
-
-    case FLUSH_SCOPE_LINE:
-      /* Find the physical address of the first mapped page in the
-        address range.  */
-      len += addr & 15;
-      addr &= -16;
-      if (!(paddr = virt_to_phys_060(addr))) {
-       unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
-
-       if (len <= tmp)
-         return 0;
-       addr += tmp;
-       len -= tmp;
-       tmp = PAGE_SIZE;
-       for (;;)
-         {
-           if ((paddr = virt_to_phys_060(addr)))
-             break;
-           if (len <= tmp)
-             return 0;
-           addr += tmp;
-           len -= tmp;
-         }
-      }
-      len = (len + 15) >> 4;
-      i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
-      while (len--)
-       {
-         switch (cache)
-           {
-           case FLUSH_CACHE_DATA:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushl %%dc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           case FLUSH_CACHE_INSN:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushl %%ic,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           default:
-           case FLUSH_CACHE_BOTH:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushl %%bc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           }
-         if (!--i && len)
-           {
-
-             /*
-              * We just want to jump to the first cache line
-              * in the next page.
-              */
-             addr += PAGE_SIZE;
-             addr &= PAGE_MASK;
-
-             i = PAGE_SIZE / 16;
-             /* Recompute physical address when crossing a page
-                boundary. */
-             for (;;)
-               {
-                 if ((paddr = virt_to_phys_060(addr)))
-                   break;
-                 if (len <= i)
-                   return 0;
-                 len -= i;
-                 addr += PAGE_SIZE;
-               }
-           }
-         else
-           paddr += 16;
-       }
-      break;
-
-    default:
-    case FLUSH_SCOPE_PAGE:
-      len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
-      addr &= PAGE_MASK;       /* Workaround for bug in some
-                                  revisions of the 68060 */
-      for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
-       {
-         if (!(paddr = virt_to_phys_060(addr)))
-           continue;
-         switch (cache)
-           {
-           case FLUSH_CACHE_DATA:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushp %%dc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           case FLUSH_CACHE_INSN:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushp %%ic,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           default:
-           case FLUSH_CACHE_BOTH:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushp %%bc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           }
-       }
-      break;
-    }
-  return 0;
-}
-
-/* sys_cacheflush -- flush (part of) the processor cache.  */
-asmlinkage int
-sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
-{
-       struct vm_area_struct *vma;
-       int ret = -EINVAL;
-
-       if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
-           cache & ~FLUSH_CACHE_BOTH)
-               goto out;
-
-       if (scope == FLUSH_SCOPE_ALL) {
-               /* Only the superuser may explicitly flush the whole cache. */
-               ret = -EPERM;
-               if (!capable(CAP_SYS_ADMIN))
-                       goto out;
-       } else {
-               /*
-                * Verify that the specified address region actually belongs
-                * to this process.
-                */
-               vma = find_vma (current->mm, addr);
-               ret = -EINVAL;
-               /* Check for overflow.  */
-               if (addr + len < addr)
-                       goto out;
-               if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
-                       goto out;
-       }
-
-       if (CPU_IS_020_OR_030) {
-               if (scope == FLUSH_SCOPE_LINE && len < 256) {
-                       unsigned long cacr;
-                       __asm__ ("movec %%cacr, %0" : "=r" (cacr));
-                       if (cache & FLUSH_CACHE_INSN)
-                               cacr |= 4;
-                       if (cache & FLUSH_CACHE_DATA)
-                               cacr |= 0x400;
-                       len >>= 2;
-                       while (len--) {
-                               __asm__ __volatile__ ("movec %1, %%caar\n\t"
-                                                     "movec %0, %%cacr"
-                                                     : /* no outputs */
-                                                     : "r" (cacr), "r" (addr));
-                               addr += 4;
-                       }
-               } else {
-                       /* Flush the whole cache, even if page granularity requested. */
-                       unsigned long cacr;
-                       __asm__ ("movec %%cacr, %0" : "=r" (cacr));
-                       if (cache & FLUSH_CACHE_INSN)
-                               cacr |= 8;
-                       if (cache & FLUSH_CACHE_DATA)
-                               cacr |= 0x800;
-                       __asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr));
-               }
-               ret = 0;
-               goto out;
-       } else {
-           /*
-            * 040 or 060: don't blindly trust 'scope', someone could
-            * try to flush a few megs of memory.
-            */
-
-           if (len>=3*PAGE_SIZE && scope<FLUSH_SCOPE_PAGE)
-               scope=FLUSH_SCOPE_PAGE;
-           if (len>=10*PAGE_SIZE && scope<FLUSH_SCOPE_ALL)
-               scope=FLUSH_SCOPE_ALL;
-           if (CPU_IS_040) {
-               ret = cache_flush_040 (addr, scope, cache, len);
-           } else if (CPU_IS_060) {
-               ret = cache_flush_060 (addr, scope, cache, len);
-           }
-       }
-out:
-       return ret;
-}
-
-asmlinkage int sys_getpagesize(void)
-{
-       return PAGE_SIZE;
-}
-
-/*
- * Do a system call from kernel instead of calling sys_execve so we
- * end up with proper pt_regs.
- */
-int kernel_execve(const char *filename,
-                 const char *const argv[],
-                 const char *const envp[])
-{
-       register long __res asm ("%d0") = __NR_execve;
-       register long __a asm ("%d1") = (long)(filename);
-       register long __b asm ("%d2") = (long)(argv);
-       register long __c asm ("%d3") = (long)(envp);
-       asm volatile ("trap  #0" : "+d" (__res)
-                       : "d" (__a), "d" (__b), "d" (__c));
-       return __res;
-}
-
-asmlinkage unsigned long sys_get_thread_area(void)
-{
-       return current_thread_info()->tp_value;
-}
-
-asmlinkage int sys_set_thread_area(unsigned long tp)
-{
-       current_thread_info()->tp_value = tp;
-       return 0;
-}
-
-/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
-   D1 (newval).  */
-asmlinkage int
-sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
-                     unsigned long __user * mem)
-{
-       /* This was borrowed from ARM's implementation.  */
-       for (;;) {
-               struct mm_struct *mm = current->mm;
-               pgd_t *pgd;
-               pmd_t *pmd;
-               pte_t *pte;
-               spinlock_t *ptl;
-               unsigned long mem_value;
-
-               down_read(&mm->mmap_sem);
-               pgd = pgd_offset(mm, (unsigned long)mem);
-               if (!pgd_present(*pgd))
-                       goto bad_access;
-               pmd = pmd_offset(pgd, (unsigned long)mem);
-               if (!pmd_present(*pmd))
-                       goto bad_access;
-               pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl);
-               if (!pte_present(*pte) || !pte_dirty(*pte)
-                   || !pte_write(*pte)) {
-                       pte_unmap_unlock(pte, ptl);
-                       goto bad_access;
-               }
-
-               mem_value = *mem;
-               if (mem_value == oldval)
-                       *mem = newval;
-
-               pte_unmap_unlock(pte, ptl);
-               up_read(&mm->mmap_sem);
-               return mem_value;
-
-             bad_access:
-               up_read(&mm->mmap_sem);
-               /* This is not necessarily a bad access, we can get here if
-                  a memory we're trying to write to should be copied-on-write.
-                  Make the kernel do the necessary page stuff, then re-iterate.
-                  Simulate a write access fault to do that.  */
-               {
-                       /* The first argument of the function corresponds to
-                          D1, which is the first field of struct pt_regs.  */
-                       struct pt_regs *fp = (struct pt_regs *)&newval;
-
-                       /* '3' is an RMW flag.  */
-                       if (do_page_fault(fp, (unsigned long)mem, 3))
-                               /* If the do_page_fault() failed, we don't
-                                  have anything meaningful to return.
-                                  There should be a SIGSEGV pending for
-                                  the process.  */
-                               return 0xdeadbeef;
-               }
-       }
-}
-
-asmlinkage int sys_atomic_barrier(void)
-{
-       /* no code needed for uniprocs */
-       return 0;
-}
diff --git a/arch/m68k/kernel/sys_m68k_no.c b/arch/m68k/kernel/sys_m68k_no.c
deleted file mode 100644 (file)
index 68488ae..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * linux/arch/m68knommu/kernel/sys_m68k.c
- *
- * This file contains various random system calls that
- * have a non-standard calling sequence on the Linux/m68k
- * platform.
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/sem.h>
-#include <linux/msg.h>
-#include <linux/shm.h>
-#include <linux/stat.h>
-#include <linux/syscalls.h>
-#include <linux/mman.h>
-#include <linux/file.h>
-#include <linux/ipc.h>
-#include <linux/fs.h>
-
-#include <asm/setup.h>
-#include <asm/uaccess.h>
-#include <asm/cachectl.h>
-#include <asm/traps.h>
-#include <asm/cacheflush.h>
-#include <asm/unistd.h>
-
-/* sys_cacheflush -- flush (part of) the processor cache.  */
-asmlinkage int
-sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
-{
-       flush_cache_all();
-       return(0);
-}
-
-asmlinkage int sys_getpagesize(void)
-{
-       return PAGE_SIZE;
-}
-
-/*
- * Do a system call from kernel instead of calling sys_execve so we
- * end up with proper pt_regs.
- */
-int kernel_execve(const char *filename,
-                 const char *const argv[],
-                 const char *const envp[])
-{
-       register long __res asm ("%d0") = __NR_execve;
-       register long __a asm ("%d1") = (long)(filename);
-       register long __b asm ("%d2") = (long)(argv);
-       register long __c asm ("%d3") = (long)(envp);
-       asm volatile ("trap  #0" : "+d" (__res)
-                       : "d" (__a), "d" (__b), "d" (__c));
-       return __res;
-}
-
-asmlinkage unsigned long sys_get_thread_area(void)
-{
-       return current_thread_info()->tp_value;
-}
-
-asmlinkage int sys_set_thread_area(unsigned long tp)
-{
-       current_thread_info()->tp_value = tp;
-       return 0;
-}
-
-/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
-   D1 (newval).  */
-asmlinkage int
-sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
-                     unsigned long __user * mem)
-{
-       struct mm_struct *mm = current->mm;
-       unsigned long mem_value;
-
-       down_read(&mm->mmap_sem);
-
-       mem_value = *mem;
-       if (mem_value == oldval)
-               *mem = newval;
-
-       up_read(&mm->mmap_sem);
-       return mem_value;
-}
-
-asmlinkage int sys_atomic_barrier(void)
-{
-       /* no code needed for uniprocs */
-       return 0;
-}
index 5909e392cb1e7e46e0f791ecbbe39e39c1e2f470..00d1452f9571073f98d4c5968fdb870f35daeb03 100644 (file)
@@ -11,7 +11,6 @@
  *  Linux/m68k support by Hamish Macdonald
  */
 
-#include <linux/sys.h>
 #include <linux/linkage.h>
 
 #ifndef CONFIG_MMU
@@ -365,4 +364,5 @@ ENTRY(sys_call_table)
        .long sys_open_by_handle_at
        .long sys_clock_adjtime
        .long sys_syncfs
+       .long sys_setns
 
index f4d715cdca0e7d5dca002943d88a8aeafa255ea3..7dc4087a9545aaa9df48b92a18ab80bbead41469 100644 (file)
@@ -84,52 +84,52 @@ SECTIONS {
                /* Kernel symbol table: Normal symbols */
                . = ALIGN(4);
                __start___ksymtab = .;
-               *(__ksymtab)
+               *(SORT(___ksymtab+*))
                __stop___ksymtab = .;
 
                /* Kernel symbol table: GPL-only symbols */
                __start___ksymtab_gpl = .;
-               *(__ksymtab_gpl)
+               *(SORT(___ksymtab_gpl+*))
                __stop___ksymtab_gpl = .;
 
                /* Kernel symbol table: Normal unused symbols */
                __start___ksymtab_unused = .;
-               *(__ksymtab_unused)
+               *(SORT(___ksymtab_unused+*))
                __stop___ksymtab_unused = .;
 
                /* Kernel symbol table: GPL-only unused symbols */
                __start___ksymtab_unused_gpl = .;
-               *(__ksymtab_unused_gpl)
+               *(SORT(___ksymtab_unused_gpl+*))
                __stop___ksymtab_unused_gpl = .;
 
                /* Kernel symbol table: GPL-future symbols */
                __start___ksymtab_gpl_future = .;
-               *(__ksymtab_gpl_future)
+               *(SORT(___ksymtab_gpl_future+*))
                __stop___ksymtab_gpl_future = .;
 
                /* Kernel symbol table: Normal symbols */
                __start___kcrctab = .;
-               *(__kcrctab)
+               *(SORT(___kcrctab+*))
                __stop___kcrctab = .;
 
                /* Kernel symbol table: GPL-only symbols */
                __start___kcrctab_gpl = .;
-               *(__kcrctab_gpl)
+               *(SORT(___kcrctab_gpl+*))
                __stop___kcrctab_gpl = .;
 
                /* Kernel symbol table: Normal unused symbols */
                __start___kcrctab_unused = .;
-               *(__kcrctab_unused)
+               *(SORT(___kcrctab_unused+*))
                __stop___kcrctab_unused = .;
 
                /* Kernel symbol table: GPL-only unused symbols */
                __start___kcrctab_unused_gpl = .;
-               *(__kcrctab_unused_gpl)
+               *(SORT(___kcrctab_unused_gpl+*))
                __stop___kcrctab_unused_gpl = .;
 
                /* Kernel symbol table: GPL-future symbols */
                __start___kcrctab_gpl_future = .;
-               *(__kcrctab_gpl_future)
+               *(SORT(___kcrctab_gpl_future+*))
                __stop___kcrctab_gpl_future = .;
 
                /* Kernel symbol table: strings */
index 1f95881d843732f1abed9b0186687d793e59ecdc..df421e5014363243d887cee75fb7d4b71902152c 100644 (file)
@@ -1,5 +1,14 @@
+
+#
+# Makefile for m68k-specific library files..
+#
+
+lib-y  := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
+          memcpy.o memset.o memmove.o
+
 ifdef CONFIG_MMU
-include arch/m68k/lib/Makefile_mm
+lib-y  += string.o uaccess.o checksum_mm.o
 else
-include arch/m68k/lib/Makefile_no
+lib-y  += mulsi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o delay.o checksum_no.o
 endif
+
diff --git a/arch/m68k/lib/Makefile_mm b/arch/m68k/lib/Makefile_mm
deleted file mode 100644 (file)
index af9abf8..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Makefile for m68k-specific library files..
-#
-
-lib-y  := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
-          checksum.o string.o uaccess.o
diff --git a/arch/m68k/lib/Makefile_no b/arch/m68k/lib/Makefile_no
deleted file mode 100644 (file)
index 32d852e..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for m68knommu specific library files..
-#
-
-lib-y  := ashldi3.o ashrdi3.o lshrdi3.o \
-          muldi3.o mulsi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \
-          checksum.o memcpy.o memmove.o memset.o delay.o
diff --git a/arch/m68k/lib/checksum.c b/arch/m68k/lib/checksum.c
deleted file mode 100644 (file)
index 1297536..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef CONFIG_MMU
-#include "checksum_mm.c"
-#else
-#include "checksum_no.c"
-#endif
index eccf25d3d73ec3c5c1e84f3a7d9f9383eab157f5..e4c6354da76520a96062eb2bb9a4e25ce59092a6 100644 (file)
@@ -101,6 +101,7 @@ __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
 {
        return (__force __sum16)~do_csum(iph,ihl*4);
 }
+EXPORT_SYMBOL(ip_fast_csum);
 #endif
 
 /*
@@ -140,6 +141,7 @@ csum_partial_copy_from_user(const void __user *src, void *dst,
        memcpy(dst, (__force const void *)src, len);
        return csum_partial(dst, len, sum);
 }
+EXPORT_SYMBOL(csum_partial_copy_from_user);
 
 /*
  * copy from ds while checksumming, otherwise like csum_partial
@@ -151,3 +153,4 @@ csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
        memcpy(dst, src, len);
        return csum_partial(dst, len, sum);
 }
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
index b50dbcad47464534688b7414997d488e4ba721bd..064889316974756878ff3a5f969068ab71b5cc2a 100644 (file)
@@ -1,62 +1,79 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
 
-#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/string.h>
 
-void * memcpy(void * to, const void * from, size_t n)
+void *memcpy(void *to, const void *from, size_t n)
 {
-#ifdef CONFIG_COLDFIRE
-  void *xto = to;
-  size_t temp;
+       void *xto = to;
+       size_t temp, temp1;
 
-  if (!n)
-    return xto;
-  if ((long) to & 1)
-    {
-      char *cto = to;
-      const char *cfrom = from;
-      *cto++ = *cfrom++;
-      to = cto;
-      from = cfrom;
-      n--;
-    }
-  if (n > 2 && (long) to & 2)
-    {
-      short *sto = to;
-      const short *sfrom = from;
-      *sto++ = *sfrom++;
-      to = sto;
-      from = sfrom;
-      n -= 2;
-    }
-  temp = n >> 2;
-  if (temp)
-    {
-      long *lto = to;
-      const long *lfrom = from;
-      for (; temp; temp--)
-       *lto++ = *lfrom++;
-      to = lto;
-      from = lfrom;
-    }
-  if (n & 2)
-    {
-      short *sto = to;
-      const short *sfrom = from;
-      *sto++ = *sfrom++;
-      to = sto;
-      from = sfrom;
-    }
-  if (n & 1)
-    {
-      char *cto = to;
-      const char *cfrom = from;
-      *cto = *cfrom;
-    }
-  return xto;
+       if (!n)
+               return xto;
+       if ((long)to & 1) {
+               char *cto = to;
+               const char *cfrom = from;
+               *cto++ = *cfrom++;
+               to = cto;
+               from = cfrom;
+               n--;
+       }
+       if (n > 2 && (long)to & 2) {
+               short *sto = to;
+               const short *sfrom = from;
+               *sto++ = *sfrom++;
+               to = sto;
+               from = sfrom;
+               n -= 2;
+       }
+       temp = n >> 2;
+       if (temp) {
+               long *lto = to;
+               const long *lfrom = from;
+#if defined(CONFIG_M68000) || defined(CONFIG_COLDFIRE)
+               for (; temp; temp--)
+                       *lto++ = *lfrom++;
 #else
-  const char *c_from = from;
-  char *c_to = to;
-  while (n-- > 0)
-    *c_to++ = *c_from++;
-  return((void *) to);
+               asm volatile (
+                       "       movel %2,%3\n"
+                       "       andw  #7,%3\n"
+                       "       lsrl  #3,%2\n"
+                       "       negw  %3\n"
+                       "       jmp   %%pc@(1f,%3:w:2)\n"
+                       "4:     movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "1:     dbra  %2,4b\n"
+                       "       clrw  %2\n"
+                       "       subql #1,%2\n"
+                       "       jpl   4b"
+                       : "=a" (lfrom), "=a" (lto), "=d" (temp), "=&d" (temp1)
+                       : "0" (lfrom), "1" (lto), "2" (temp));
 #endif
+               to = lto;
+               from = lfrom;
+       }
+       if (n & 2) {
+               short *sto = to;
+               const short *sfrom = from;
+               *sto++ = *sfrom++;
+               to = sto;
+               from = sfrom;
+       }
+       if (n & 1) {
+               char *cto = to;
+               const char *cfrom = from;
+               *cto = *cfrom;
+       }
+       return xto;
 }
+EXPORT_SYMBOL(memcpy);
index b3dcfe9dab7e63bd277c841ed1ca87ef65248e56..6519f7f349f665d9f2321b6c87beee45f8d15645 100644 (file)
@@ -4,8 +4,6 @@
  * for more details.
  */
 
-#define __IN_STRING_C
-
 #include <linux/module.h>
 #include <linux/string.h>
 
index 1389bf455633a2ed0b752ce04d61bcb3a58c4a54..8a7639f0a2fe5c05d1ecc70065e15da88961db99 100644 (file)
@@ -1,47 +1,74 @@
-#include <linux/types.h>
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
 
-void * memset(void * s, int c, size_t count)
+#include <linux/module.h>
+#include <linux/string.h>
+
+void *memset(void *s, int c, size_t count)
 {
-  void *xs = s;
-  size_t temp;
+       void *xs = s;
+       size_t temp;
 
-  if (!count)
-    return xs;
-  c &= 0xff;
-  c |= c << 8;
-  c |= c << 16;
-  if ((long) s & 1)
-    {
-      char *cs = s;
-      *cs++ = c;
-      s = cs;
-      count--;
-    }
-  if (count > 2 && (long) s & 2)
-    {
-      short *ss = s;
-      *ss++ = c;
-      s = ss;
-      count -= 2;
-    }
-  temp = count >> 2;
-  if (temp)
-    {
-      long *ls = s;
-      for (; temp; temp--)
-       *ls++ = c;
-      s = ls;
-    }
-  if (count & 2)
-    {
-      short *ss = s;
-      *ss++ = c;
-      s = ss;
-    }
-  if (count & 1)
-    {
-      char *cs = s;
-      *cs = c;
-    }
-  return xs;
+       if (!count)
+               return xs;
+       c &= 0xff;
+       c |= c << 8;
+       c |= c << 16;
+       if ((long)s & 1) {
+               char *cs = s;
+               *cs++ = c;
+               s = cs;
+               count--;
+       }
+       if (count > 2 && (long)s & 2) {
+               short *ss = s;
+               *ss++ = c;
+               s = ss;
+               count -= 2;
+       }
+       temp = count >> 2;
+       if (temp) {
+               long *ls = s;
+#if defined(CONFIG_M68000) || defined(CONFIG_COLDFIRE)
+               for (; temp; temp--)
+                       *ls++ = c;
+#else
+               size_t temp1;
+               asm volatile (
+                       "       movel %1,%2\n"
+                       "       andw  #7,%2\n"
+                       "       lsrl  #3,%1\n"
+                       "       negw  %2\n"
+                       "       jmp   %%pc@(2f,%2:w:2)\n"
+                       "1:     movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "2:     dbra  %1,1b\n"
+                       "       clrw  %1\n"
+                       "       subql #1,%1\n"
+                       "       jpl   1b"
+                       : "=a" (ls), "=d" (temp), "=&d" (temp1)
+                       : "d" (c), "0" (ls), "1" (temp));
+#endif
+               s = ls;
+       }
+       if (count & 2) {
+               short *ss = s;
+               *ss++ = c;
+               s = ss;
+       }
+       if (count & 1) {
+               char *cs = s;
+               *cs = c;
+       }
+       return xs;
 }
+EXPORT_SYMBOL(memset);
index 16e0eb338ee0e5303a44fa3180f0bcdcd08e3d0d..79e928a525d078169e0617270e1fcea9da08b5f2 100644 (file)
@@ -1,5 +1,97 @@
-#ifdef CONFIG_MMU
-#include "muldi3_mm.c"
+/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and 
+                          gcc-2.7.2.3/longlong.h which is: */
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#if defined(CONFIG_M68000) || defined(CONFIG_COLDFIRE)
+
+#define SI_TYPE_SIZE 32
+#define __BITS4 (SI_TYPE_SIZE / 4)
+#define __ll_B (1L << (SI_TYPE_SIZE / 2))
+#define __ll_lowpart(t) ((USItype) (t) % __ll_B)
+#define __ll_highpart(t) ((USItype) (t) / __ll_B)
+
+#define umul_ppmm(w1, w0, u, v)                                                \
+  do {                                                                 \
+    USItype __x0, __x1, __x2, __x3;                                    \
+    USItype __ul, __vl, __uh, __vh;                                    \
+                                                                       \
+    __ul = __ll_lowpart (u);                                           \
+    __uh = __ll_highpart (u);                                          \
+    __vl = __ll_lowpart (v);                                           \
+    __vh = __ll_highpart (v);                                          \
+                                                                       \
+    __x0 = (USItype) __ul * __vl;                                      \
+    __x1 = (USItype) __ul * __vh;                                      \
+    __x2 = (USItype) __uh * __vl;                                      \
+    __x3 = (USItype) __uh * __vh;                                      \
+                                                                       \
+    __x1 += __ll_highpart (__x0);/* this can't give carry */           \
+    __x1 += __x2;              /* but this indeed can */               \
+    if (__x1 < __x2)           /* did we get it? */                    \
+      __x3 += __ll_B;          /* yes, add it in the proper pos. */    \
+                                                                       \
+    (w1) = __x3 + __ll_highpart (__x1);                                        \
+    (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0);         \
+  } while (0)
+
 #else
-#include "muldi3_no.c"
+
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("mulu%.l %3,%1:%0"                                          \
+           : "=d" ((USItype)(w0)),                                     \
+             "=d" ((USItype)(w1))                                      \
+           : "%0" ((USItype)(u)),                                      \
+             "dmi" ((USItype)(v)))
+
 #endif
+
+#define __umulsidi3(u, v) \
+  ({DIunion __w;                                                       \
+    umul_ppmm (__w.s.high, __w.s.low, u, v);                           \
+    __w.ll; })
+
+typedef         int SItype     __attribute__ ((mode (SI)));
+typedef unsigned int USItype   __attribute__ ((mode (SI)));
+typedef                 int DItype     __attribute__ ((mode (DI)));
+typedef int word_type __attribute__ ((mode (__word__)));
+
+struct DIstruct {SItype high, low;};
+
+typedef union
+{
+  struct DIstruct s;
+  DItype ll;
+} DIunion;
+
+DItype
+__muldi3 (DItype u, DItype v)
+{
+  DIunion w;
+  DIunion uu, vv;
+
+  uu.ll = u,
+  vv.ll = v;
+
+  w.ll = __umulsidi3 (uu.s.low, vv.s.low);
+  w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
+              + (USItype) uu.s.high * (USItype) vv.s.low);
+
+  return w.ll;
+}
diff --git a/arch/m68k/lib/muldi3_mm.c b/arch/m68k/lib/muldi3_mm.c
deleted file mode 100644 (file)
index be4f275..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and
-                          gcc-2.7.2.3/longlong.h which is: */
-/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU CC 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 GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-#define BITS_PER_UNIT 8
-
-#define umul_ppmm(w1, w0, u, v) \
-  __asm__ ("mulu%.l %3,%1:%0"                                          \
-           : "=d" ((USItype)(w0)),                                     \
-             "=d" ((USItype)(w1))                                      \
-           : "%0" ((USItype)(u)),                                      \
-             "dmi" ((USItype)(v)))
-
-#define __umulsidi3(u, v) \
-  ({DIunion __w;                                                       \
-    umul_ppmm (__w.s.high, __w.s.low, u, v);                           \
-    __w.ll; })
-
-typedef                 int SItype     __attribute__ ((mode (SI)));
-typedef unsigned int USItype   __attribute__ ((mode (SI)));
-typedef                 int DItype     __attribute__ ((mode (DI)));
-typedef int word_type __attribute__ ((mode (__word__)));
-
-struct DIstruct {SItype high, low;};
-
-typedef union
-{
-  struct DIstruct s;
-  DItype ll;
-} DIunion;
-
-DItype
-__muldi3 (DItype u, DItype v)
-{
-  DIunion w;
-  DIunion uu, vv;
-
-  uu.ll = u,
-  vv.ll = v;
-
-  w.ll = __umulsidi3 (uu.s.low, vv.s.low);
-  w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
-              + (USItype) uu.s.high * (USItype) vv.s.low);
-
-  return w.ll;
-}
diff --git a/arch/m68k/lib/muldi3_no.c b/arch/m68k/lib/muldi3_no.c
deleted file mode 100644 (file)
index 34af72c..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and 
-                          gcc-2.7.2.3/longlong.h which is: */
-/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU CC 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 GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-#define BITS_PER_UNIT 8
-#define SI_TYPE_SIZE 32
-
-#define __BITS4 (SI_TYPE_SIZE / 4)
-#define __ll_B (1L << (SI_TYPE_SIZE / 2))
-#define __ll_lowpart(t) ((USItype) (t) % __ll_B)
-#define __ll_highpart(t) ((USItype) (t) / __ll_B)
-
-#define umul_ppmm(w1, w0, u, v)                                                \
-  do {                                                                 \
-    USItype __x0, __x1, __x2, __x3;                                    \
-    USItype __ul, __vl, __uh, __vh;                                    \
-                                                                       \
-    __ul = __ll_lowpart (u);                                           \
-    __uh = __ll_highpart (u);                                          \
-    __vl = __ll_lowpart (v);                                           \
-    __vh = __ll_highpart (v);                                          \
-                                                                       \
-    __x0 = (USItype) __ul * __vl;                                      \
-    __x1 = (USItype) __ul * __vh;                                      \
-    __x2 = (USItype) __uh * __vl;                                      \
-    __x3 = (USItype) __uh * __vh;                                      \
-                                                                       \
-    __x1 += __ll_highpart (__x0);/* this can't give carry */           \
-    __x1 += __x2;              /* but this indeed can */               \
-    if (__x1 < __x2)           /* did we get it? */                    \
-      __x3 += __ll_B;          /* yes, add it in the proper pos. */    \
-                                                                       \
-    (w1) = __x3 + __ll_highpart (__x1);                                        \
-    (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0);         \
-  } while (0)
-
-#define __umulsidi3(u, v) \
-  ({DIunion __w;                                                       \
-    umul_ppmm (__w.s.high, __w.s.low, u, v);                           \
-    __w.ll; })
-
-typedef         int SItype     __attribute__ ((mode (SI)));
-typedef unsigned int USItype   __attribute__ ((mode (SI)));
-typedef                 int DItype     __attribute__ ((mode (DI)));
-typedef int word_type __attribute__ ((mode (__word__)));
-
-struct DIstruct {SItype high, low;};
-
-typedef union
-{
-  struct DIstruct s;
-  DItype ll;
-} DIunion;
-
-DItype
-__muldi3 (DItype u, DItype v)
-{
-  DIunion w;
-  DIunion uu, vv;
-
-  uu.ll = u,
-  vv.ll = v;
-
-  w.ll = __umulsidi3 (uu.s.low, vv.s.low);
-  w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
-              + (USItype) uu.s.high * (USItype) vv.s.low);
-
-  return w.ll;
-}
index d399c5f25636f46473ea06a3ee796ec3bd2888cd..b9a57abfad08dc545f703b16f3cb2241727dccf9 100644 (file)
@@ -20,226 +20,3 @@ char *strcat(char *dest, const char *src)
        return __kernel_strcpy(dest + __kernel_strlen(dest), src);
 }
 EXPORT_SYMBOL(strcat);
-
-void *memset(void *s, int c, size_t count)
-{
-       void *xs = s;
-       size_t temp, temp1;
-
-       if (!count)
-               return xs;
-       c &= 0xff;
-       c |= c << 8;
-       c |= c << 16;
-       if ((long)s & 1) {
-               char *cs = s;
-               *cs++ = c;
-               s = cs;
-               count--;
-       }
-       if (count > 2 && (long)s & 2) {
-               short *ss = s;
-               *ss++ = c;
-               s = ss;
-               count -= 2;
-       }
-       temp = count >> 2;
-       if (temp) {
-               long *ls = s;
-
-               asm volatile (
-                       "       movel %1,%2\n"
-                       "       andw  #7,%2\n"
-                       "       lsrl  #3,%1\n"
-                       "       negw  %2\n"
-                       "       jmp   %%pc@(2f,%2:w:2)\n"
-                       "1:     movel %3,%0@+\n"
-                       "       movel %3,%0@+\n"
-                       "       movel %3,%0@+\n"
-                       "       movel %3,%0@+\n"
-                       "       movel %3,%0@+\n"
-                       "       movel %3,%0@+\n"
-                       "       movel %3,%0@+\n"
-                       "       movel %3,%0@+\n"
-                       "2:     dbra  %1,1b\n"
-                       "       clrw  %1\n"
-                       "       subql #1,%1\n"
-                       "       jpl   1b"
-                       : "=a" (ls), "=d" (temp), "=&d" (temp1)
-                       : "d" (c), "0" (ls), "1" (temp));
-               s = ls;
-       }
-       if (count & 2) {
-               short *ss = s;
-               *ss++ = c;
-               s = ss;
-       }
-       if (count & 1) {
-               char *cs = s;
-               *cs = c;
-       }
-       return xs;
-}
-EXPORT_SYMBOL(memset);
-
-void *memcpy(void *to, const void *from, size_t n)
-{
-       void *xto = to;
-       size_t temp, temp1;
-
-       if (!n)
-               return xto;
-       if ((long)to & 1) {
-               char *cto = to;
-               const char *cfrom = from;
-               *cto++ = *cfrom++;
-               to = cto;
-               from = cfrom;
-               n--;
-       }
-       if (n > 2 && (long)to & 2) {
-               short *sto = to;
-               const short *sfrom = from;
-               *sto++ = *sfrom++;
-               to = sto;
-               from = sfrom;
-               n -= 2;
-       }
-       temp = n >> 2;
-       if (temp) {
-               long *lto = to;
-               const long *lfrom = from;
-
-               asm volatile (
-                       "       movel %2,%3\n"
-                       "       andw  #7,%3\n"
-                       "       lsrl  #3,%2\n"
-                       "       negw  %3\n"
-                       "       jmp   %%pc@(1f,%3:w:2)\n"
-                       "4:     movel %0@+,%1@+\n"
-                       "       movel %0@+,%1@+\n"
-                       "       movel %0@+,%1@+\n"
-                       "       movel %0@+,%1@+\n"
-                       "       movel %0@+,%1@+\n"
-                       "       movel %0@+,%1@+\n"
-                       "       movel %0@+,%1@+\n"
-                       "       movel %0@+,%1@+\n"
-                       "1:     dbra  %2,4b\n"
-                       "       clrw  %2\n"
-                       "       subql #1,%2\n"
-                       "       jpl   4b"
-                       : "=a" (lfrom), "=a" (lto), "=d" (temp), "=&d" (temp1)
-                       : "0" (lfrom), "1" (lto), "2" (temp));
-               to = lto;
-               from = lfrom;
-       }
-       if (n & 2) {
-               short *sto = to;
-               const short *sfrom = from;
-               *sto++ = *sfrom++;
-               to = sto;
-               from = sfrom;
-       }
-       if (n & 1) {
-               char *cto = to;
-               const char *cfrom = from;
-               *cto = *cfrom;
-       }
-       return xto;
-}
-EXPORT_SYMBOL(memcpy);
-
-void *memmove(void *dest, const void *src, size_t n)
-{
-       void *xdest = dest;
-       size_t temp;
-
-       if (!n)
-               return xdest;
-
-       if (dest < src) {
-               if ((long)dest & 1) {
-                       char *cdest = dest;
-                       const char *csrc = src;
-                       *cdest++ = *csrc++;
-                       dest = cdest;
-                       src = csrc;
-                       n--;
-               }
-               if (n > 2 && (long)dest & 2) {
-                       short *sdest = dest;
-                       const short *ssrc = src;
-                       *sdest++ = *ssrc++;
-                       dest = sdest;
-                       src = ssrc;
-                       n -= 2;
-               }
-               temp = n >> 2;
-               if (temp) {
-                       long *ldest = dest;
-                       const long *lsrc = src;
-                       temp--;
-                       do
-                               *ldest++ = *lsrc++;
-                       while (temp--);
-                       dest = ldest;
-                       src = lsrc;
-               }
-               if (n & 2) {
-                       short *sdest = dest;
-                       const short *ssrc = src;
-                       *sdest++ = *ssrc++;
-                       dest = sdest;
-                       src = ssrc;
-               }
-               if (n & 1) {
-                       char *cdest = dest;
-                       const char *csrc = src;
-                       *cdest = *csrc;
-               }
-       } else {
-               dest = (char *)dest + n;
-               src = (const char *)src + n;
-               if ((long)dest & 1) {
-                       char *cdest = dest;
-                       const char *csrc = src;
-                       *--cdest = *--csrc;
-                       dest = cdest;
-                       src = csrc;
-                       n--;
-               }
-               if (n > 2 && (long)dest & 2) {
-                       short *sdest = dest;
-                       const short *ssrc = src;
-                       *--sdest = *--ssrc;
-                       dest = sdest;
-                       src = ssrc;
-                       n -= 2;
-               }
-               temp = n >> 2;
-               if (temp) {
-                       long *ldest = dest;
-                       const long *lsrc = src;
-                       temp--;
-                       do
-                               *--ldest = *--lsrc;
-                       while (temp--);
-                       dest = ldest;
-                       src = lsrc;
-               }
-               if (n & 2) {
-                       short *sdest = dest;
-                       const short *ssrc = src;
-                       *--sdest = *--ssrc;
-                       dest = sdest;
-                       src = ssrc;
-               }
-               if (n & 1) {
-                       char *cdest = dest;
-                       const char *csrc = src;
-                       *--cdest = *--csrc;
-               }
-       }
-       return xdest;
-}
-EXPORT_SYMBOL(memmove);
index b60270e4954bb256e17ca0af97341d3d1766efec..09cadf1058d5c6b948a8dd3b1016c6f6bc79068f 100644 (file)
@@ -1,5 +1,9 @@
-ifdef CONFIG_MMU
-include arch/m68k/mm/Makefile_mm
-else
-include arch/m68k/mm/Makefile_no
-endif
+#
+# Makefile for the linux m68k-specific parts of the memory manager.
+#
+
+obj-y  := init.o
+
+obj-$(CONFIG_MMU)              += cache.o fault.o hwtest.o
+obj-$(CONFIG_MMU_MOTOROLA)     += kmap.o memory.o motorola.o
+obj-$(CONFIG_MMU_SUN3)         += sun3kmap.o sun3mmu.o
diff --git a/arch/m68k/mm/Makefile_mm b/arch/m68k/mm/Makefile_mm
deleted file mode 100644 (file)
index 5eaa43c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for the linux m68k-specific parts of the memory manager.
-#
-
-obj-y          := cache.o init.o fault.o hwtest.o
-
-obj-$(CONFIG_MMU_MOTOROLA)     += kmap.o memory.o motorola.o
-obj-$(CONFIG_MMU_SUN3)         += sun3kmap.o sun3mmu.o
diff --git a/arch/m68k/mm/Makefile_no b/arch/m68k/mm/Makefile_no
deleted file mode 100644 (file)
index b54ab6b..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the linux m68knommu specific parts of the memory manager.
-#
-
-obj-y += init.o kmap.o
index 8bc842554e5b4618ad3e77208dc5872cd184fef2..9113c2f1760735f8134aee0ab0e6ff7a8aea9b7a 100644 (file)
@@ -32,8 +32,6 @@
 #include <asm/sections.h>
 #include <asm/tlb.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 pg_data_t pg_data_map[MAX_NUMNODES];
 EXPORT_SYMBOL(pg_data_map);
 
index 8a6653f56bd8b29c286b3f973191d53557721e78..7cbd7bd1f8bcd74352fda4c1db5c3f928d230936 100644 (file)
 #include <asm/system.h>
 #include <asm/machdep.h>
 
-#undef DEBUG
-
-extern void die_if_kernel(char *,struct pt_regs *,long);
-extern void free_initmem(void);
-
 /*
- * BAD_PAGE is the page that is used for page faults when linux
- * is out-of-memory. Older versions of linux just did a
- * do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving a inode
- * unused etc..
- *
- * BAD_PAGETABLE is the accompanying page-table: it is initialized
- * to point to BAD_PAGE entries.
- *
  * ZERO_PAGE is a special page that is used for zero-initialized
  * data and COW.
  */
-static unsigned long empty_bad_page_table;
-
-static unsigned long empty_bad_page;
-
 unsigned long empty_zero_page;
 
 extern unsigned long memory_start;
@@ -77,22 +59,9 @@ void __init paging_init(void)
         * Make sure start_mem is page aligned, otherwise bootmem and
         * page_alloc get different views of the world.
         */
-#ifdef DEBUG
-       unsigned long start_mem = PAGE_ALIGN(memory_start);
-#endif
        unsigned long end_mem   = memory_end & PAGE_MASK;
+       unsigned long zones_size[MAX_NR_ZONES] = {0, };
 
-#ifdef DEBUG
-       printk (KERN_DEBUG "start_mem is %#lx\nvirtual_end is %#lx\n",
-               start_mem, end_mem);
-#endif
-
-       /*
-        * Initialize the bad page table and bad page to point
-        * to a couple of allocated pages.
-        */
-       empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
-       empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
        empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
        memset((void *)empty_zero_page, 0, PAGE_SIZE);
 
@@ -101,19 +70,8 @@ void __init paging_init(void)
         */
        set_fs (USER_DS);
 
-#ifdef DEBUG
-       printk (KERN_DEBUG "before free_area_init\n");
-
-       printk (KERN_DEBUG "free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n",
-               start_mem, end_mem);
-#endif
-
-       {
-               unsigned long zones_size[MAX_NR_ZONES] = {0, };
-
-               zones_size[ZONE_DMA] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
-               free_area_init(zones_size);
-       }
+       zones_size[ZONE_DMA] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
+       free_area_init(zones_size);
 }
 
 void __init mem_init(void)
@@ -166,8 +124,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
 }
 #endif
 
-void
-free_initmem()
+void free_initmem(void)
 {
 #ifdef CONFIG_RAMKERNEL
        unsigned long addr;
index a373d136b2b28547421a276b2789bc0d1f93b97d..69345849454b9c03991258aa1eff409472896e2b 100644 (file)
@@ -1,5 +1,367 @@
-#ifdef CONFIG_MMU
-#include "kmap_mm.c"
+/*
+ *  linux/arch/m68k/mm/kmap.c
+ *
+ *  Copyright (C) 1997 Roman Hodek
+ *
+ *  10/01/99 cleaned up the code and changing to the same interface
+ *          used by other architectures                /Roman Zippel
+ */
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#undef DEBUG
+
+#define PTRTREESIZE    (256*1024)
+
+/*
+ * For 040/060 we can use the virtual memory area like other architectures,
+ * but for 020/030 we want to use early termination page descriptor and we
+ * can't mix this with normal page descriptors, so we have to copy that code
+ * (mm/vmalloc.c) and return appriorate aligned addresses.
+ */
+
+#ifdef CPU_M68040_OR_M68060_ONLY
+
+#define IO_SIZE                PAGE_SIZE
+
+static inline struct vm_struct *get_io_area(unsigned long size)
+{
+       return get_vm_area(size, VM_IOREMAP);
+}
+
+
+static inline void free_io_area(void *addr)
+{
+       vfree((void *)(PAGE_MASK & (unsigned long)addr));
+}
+
 #else
-#include "kmap_no.c"
+
+#define IO_SIZE                (256*1024)
+
+static struct vm_struct *iolist;
+
+static struct vm_struct *get_io_area(unsigned long size)
+{
+       unsigned long addr;
+       struct vm_struct **p, *tmp, *area;
+
+       area = kmalloc(sizeof(*area), GFP_KERNEL);
+       if (!area)
+               return NULL;
+       addr = KMAP_START;
+       for (p = &iolist; (tmp = *p) ; p = &tmp->next) {
+               if (size + addr < (unsigned long)tmp->addr)
+                       break;
+               if (addr > KMAP_END-size) {
+                       kfree(area);
+                       return NULL;
+               }
+               addr = tmp->size + (unsigned long)tmp->addr;
+       }
+       area->addr = (void *)addr;
+       area->size = size + IO_SIZE;
+       area->next = *p;
+       *p = area;
+       return area;
+}
+
+static inline void free_io_area(void *addr)
+{
+       struct vm_struct **p, *tmp;
+
+       if (!addr)
+               return;
+       addr = (void *)((unsigned long)addr & -IO_SIZE);
+       for (p = &iolist ; (tmp = *p) ; p = &tmp->next) {
+               if (tmp->addr == addr) {
+                       *p = tmp->next;
+                       __iounmap(tmp->addr, tmp->size);
+                       kfree(tmp);
+                       return;
+               }
+       }
+}
+
 #endif
+
+/*
+ * Map some physical address range into the kernel address space.
+ */
+/* Rewritten by Andreas Schwab to remove all races. */
+
+void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
+{
+       struct vm_struct *area;
+       unsigned long virtaddr, retaddr;
+       long offset;
+       pgd_t *pgd_dir;
+       pmd_t *pmd_dir;
+       pte_t *pte_dir;
+
+       /*
+        * Don't allow mappings that wrap..
+        */
+       if (!size || physaddr > (unsigned long)(-size))
+               return NULL;
+
+#ifdef CONFIG_AMIGA
+       if (MACH_IS_AMIGA) {
+               if ((physaddr >= 0x40000000) && (physaddr + size < 0x60000000)
+                   && (cacheflag == IOMAP_NOCACHE_SER))
+                       return (void __iomem *)physaddr;
+       }
+#endif
+
+#ifdef DEBUG
+       printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag);
+#endif
+       /*
+        * Mappings have to be aligned
+        */
+       offset = physaddr & (IO_SIZE - 1);
+       physaddr &= -IO_SIZE;
+       size = (size + offset + IO_SIZE - 1) & -IO_SIZE;
+
+       /*
+        * Ok, go for it..
+        */
+       area = get_io_area(size);
+       if (!area)
+               return NULL;
+
+       virtaddr = (unsigned long)area->addr;
+       retaddr = virtaddr + offset;
+#ifdef DEBUG
+       printk("0x%lx,0x%lx,0x%lx", physaddr, virtaddr, retaddr);
+#endif
+
+       /*
+        * add cache and table flags to physical address
+        */
+       if (CPU_IS_040_OR_060) {
+               physaddr |= (_PAGE_PRESENT | _PAGE_GLOBAL040 |
+                            _PAGE_ACCESSED | _PAGE_DIRTY);
+               switch (cacheflag) {
+               case IOMAP_FULL_CACHING:
+                       physaddr |= _PAGE_CACHE040;
+                       break;
+               case IOMAP_NOCACHE_SER:
+               default:
+                       physaddr |= _PAGE_NOCACHE_S;
+                       break;
+               case IOMAP_NOCACHE_NONSER:
+                       physaddr |= _PAGE_NOCACHE;
+                       break;
+               case IOMAP_WRITETHROUGH:
+                       physaddr |= _PAGE_CACHE040W;
+                       break;
+               }
+       } else {
+               physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
+               switch (cacheflag) {
+               case IOMAP_NOCACHE_SER:
+               case IOMAP_NOCACHE_NONSER:
+               default:
+                       physaddr |= _PAGE_NOCACHE030;
+                       break;
+               case IOMAP_FULL_CACHING:
+               case IOMAP_WRITETHROUGH:
+                       break;
+               }
+       }
+
+       while ((long)size > 0) {
+#ifdef DEBUG
+               if (!(virtaddr & (PTRTREESIZE-1)))
+                       printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr);
+#endif
+               pgd_dir = pgd_offset_k(virtaddr);
+               pmd_dir = pmd_alloc(&init_mm, pgd_dir, virtaddr);
+               if (!pmd_dir) {
+                       printk("ioremap: no mem for pmd_dir\n");
+                       return NULL;
+               }
+
+               if (CPU_IS_020_OR_030) {
+                       pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
+                       physaddr += PTRTREESIZE;
+                       virtaddr += PTRTREESIZE;
+                       size -= PTRTREESIZE;
+               } else {
+                       pte_dir = pte_alloc_kernel(pmd_dir, virtaddr);
+                       if (!pte_dir) {
+                               printk("ioremap: no mem for pte_dir\n");
+                               return NULL;
+                       }
+
+                       pte_val(*pte_dir) = physaddr;
+                       virtaddr += PAGE_SIZE;
+                       physaddr += PAGE_SIZE;
+                       size -= PAGE_SIZE;
+               }
+       }
+#ifdef DEBUG
+       printk("\n");
+#endif
+       flush_tlb_all();
+
+       return (void __iomem *)retaddr;
+}
+EXPORT_SYMBOL(__ioremap);
+
+/*
+ * Unmap a ioremap()ed region again
+ */
+void iounmap(void __iomem *addr)
+{
+#ifdef CONFIG_AMIGA
+       if ((!MACH_IS_AMIGA) ||
+           (((unsigned long)addr < 0x40000000) ||
+            ((unsigned long)addr > 0x60000000)))
+                       free_io_area((__force void *)addr);
+#else
+       free_io_area((__force void *)addr);
+#endif
+}
+EXPORT_SYMBOL(iounmap);
+
+/*
+ * __iounmap unmaps nearly everything, so be careful
+ * it doesn't free currently pointer/page tables anymore but it
+ * wans't used anyway and might be added later.
+ */
+void __iounmap(void *addr, unsigned long size)
+{
+       unsigned long virtaddr = (unsigned long)addr;
+       pgd_t *pgd_dir;
+       pmd_t *pmd_dir;
+       pte_t *pte_dir;
+
+       while ((long)size > 0) {
+               pgd_dir = pgd_offset_k(virtaddr);
+               if (pgd_bad(*pgd_dir)) {
+                       printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
+                       pgd_clear(pgd_dir);
+                       return;
+               }
+               pmd_dir = pmd_offset(pgd_dir, virtaddr);
+
+               if (CPU_IS_020_OR_030) {
+                       int pmd_off = (virtaddr/PTRTREESIZE) & 15;
+                       int pmd_type = pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK;
+
+                       if (pmd_type == _PAGE_PRESENT) {
+                               pmd_dir->pmd[pmd_off] = 0;
+                               virtaddr += PTRTREESIZE;
+                               size -= PTRTREESIZE;
+                               continue;
+                       } else if (pmd_type == 0)
+                               continue;
+               }
+
+               if (pmd_bad(*pmd_dir)) {
+                       printk("iounmap: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
+                       pmd_clear(pmd_dir);
+                       return;
+               }
+               pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
+
+               pte_val(*pte_dir) = 0;
+               virtaddr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       flush_tlb_all();
+}
+
+/*
+ * Set new cache mode for some kernel address space.
+ * The caller must push data for that range itself, if such data may already
+ * be in the cache.
+ */
+void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
+{
+       unsigned long virtaddr = (unsigned long)addr;
+       pgd_t *pgd_dir;
+       pmd_t *pmd_dir;
+       pte_t *pte_dir;
+
+       if (CPU_IS_040_OR_060) {
+               switch (cmode) {
+               case IOMAP_FULL_CACHING:
+                       cmode = _PAGE_CACHE040;
+                       break;
+               case IOMAP_NOCACHE_SER:
+               default:
+                       cmode = _PAGE_NOCACHE_S;
+                       break;
+               case IOMAP_NOCACHE_NONSER:
+                       cmode = _PAGE_NOCACHE;
+                       break;
+               case IOMAP_WRITETHROUGH:
+                       cmode = _PAGE_CACHE040W;
+                       break;
+               }
+       } else {
+               switch (cmode) {
+               case IOMAP_NOCACHE_SER:
+               case IOMAP_NOCACHE_NONSER:
+               default:
+                       cmode = _PAGE_NOCACHE030;
+                       break;
+               case IOMAP_FULL_CACHING:
+               case IOMAP_WRITETHROUGH:
+                       cmode = 0;
+               }
+       }
+
+       while ((long)size > 0) {
+               pgd_dir = pgd_offset_k(virtaddr);
+               if (pgd_bad(*pgd_dir)) {
+                       printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
+                       pgd_clear(pgd_dir);
+                       return;
+               }
+               pmd_dir = pmd_offset(pgd_dir, virtaddr);
+
+               if (CPU_IS_020_OR_030) {
+                       int pmd_off = (virtaddr/PTRTREESIZE) & 15;
+
+                       if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
+                               pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] &
+                                                        _CACHEMASK040) | cmode;
+                               virtaddr += PTRTREESIZE;
+                               size -= PTRTREESIZE;
+                               continue;
+                       }
+               }
+
+               if (pmd_bad(*pmd_dir)) {
+                       printk("iocachemode: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
+                       pmd_clear(pmd_dir);
+                       return;
+               }
+               pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
+
+               pte_val(*pte_dir) = (pte_val(*pte_dir) & _CACHEMASK040) | cmode;
+               virtaddr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       flush_tlb_all();
+}
+EXPORT_SYMBOL(kernel_set_cachemode);
diff --git a/arch/m68k/mm/kmap_mm.c b/arch/m68k/mm/kmap_mm.c
deleted file mode 100644 (file)
index 6934584..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- *  linux/arch/m68k/mm/kmap.c
- *
- *  Copyright (C) 1997 Roman Hodek
- *
- *  10/01/99 cleaned up the code and changing to the same interface
- *          used by other architectures                /Roman Zippel
- */
-
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/page.h>
-#include <asm/pgalloc.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
-#undef DEBUG
-
-#define PTRTREESIZE    (256*1024)
-
-/*
- * For 040/060 we can use the virtual memory area like other architectures,
- * but for 020/030 we want to use early termination page descriptor and we
- * can't mix this with normal page descriptors, so we have to copy that code
- * (mm/vmalloc.c) and return appriorate aligned addresses.
- */
-
-#ifdef CPU_M68040_OR_M68060_ONLY
-
-#define IO_SIZE                PAGE_SIZE
-
-static inline struct vm_struct *get_io_area(unsigned long size)
-{
-       return get_vm_area(size, VM_IOREMAP);
-}
-
-
-static inline void free_io_area(void *addr)
-{
-       vfree((void *)(PAGE_MASK & (unsigned long)addr));
-}
-
-#else
-
-#define IO_SIZE                (256*1024)
-
-static struct vm_struct *iolist;
-
-static struct vm_struct *get_io_area(unsigned long size)
-{
-       unsigned long addr;
-       struct vm_struct **p, *tmp, *area;
-
-       area = kmalloc(sizeof(*area), GFP_KERNEL);
-       if (!area)
-               return NULL;
-       addr = KMAP_START;
-       for (p = &iolist; (tmp = *p) ; p = &tmp->next) {
-               if (size + addr < (unsigned long)tmp->addr)
-                       break;
-               if (addr > KMAP_END-size) {
-                       kfree(area);
-                       return NULL;
-               }
-               addr = tmp->size + (unsigned long)tmp->addr;
-       }
-       area->addr = (void *)addr;
-       area->size = size + IO_SIZE;
-       area->next = *p;
-       *p = area;
-       return area;
-}
-
-static inline void free_io_area(void *addr)
-{
-       struct vm_struct **p, *tmp;
-
-       if (!addr)
-               return;
-       addr = (void *)((unsigned long)addr & -IO_SIZE);
-       for (p = &iolist ; (tmp = *p) ; p = &tmp->next) {
-               if (tmp->addr == addr) {
-                       *p = tmp->next;
-                       __iounmap(tmp->addr, tmp->size);
-                       kfree(tmp);
-                       return;
-               }
-       }
-}
-
-#endif
-
-/*
- * Map some physical address range into the kernel address space.
- */
-/* Rewritten by Andreas Schwab to remove all races. */
-
-void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
-{
-       struct vm_struct *area;
-       unsigned long virtaddr, retaddr;
-       long offset;
-       pgd_t *pgd_dir;
-       pmd_t *pmd_dir;
-       pte_t *pte_dir;
-
-       /*
-        * Don't allow mappings that wrap..
-        */
-       if (!size || physaddr > (unsigned long)(-size))
-               return NULL;
-
-#ifdef CONFIG_AMIGA
-       if (MACH_IS_AMIGA) {
-               if ((physaddr >= 0x40000000) && (physaddr + size < 0x60000000)
-                   && (cacheflag == IOMAP_NOCACHE_SER))
-                       return (void __iomem *)physaddr;
-       }
-#endif
-
-#ifdef DEBUG
-       printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag);
-#endif
-       /*
-        * Mappings have to be aligned
-        */
-       offset = physaddr & (IO_SIZE - 1);
-       physaddr &= -IO_SIZE;
-       size = (size + offset + IO_SIZE - 1) & -IO_SIZE;
-
-       /*
-        * Ok, go for it..
-        */
-       area = get_io_area(size);
-       if (!area)
-               return NULL;
-
-       virtaddr = (unsigned long)area->addr;
-       retaddr = virtaddr + offset;
-#ifdef DEBUG
-       printk("0x%lx,0x%lx,0x%lx", physaddr, virtaddr, retaddr);
-#endif
-
-       /*
-        * add cache and table flags to physical address
-        */
-       if (CPU_IS_040_OR_060) {
-               physaddr |= (_PAGE_PRESENT | _PAGE_GLOBAL040 |
-                            _PAGE_ACCESSED | _PAGE_DIRTY);
-               switch (cacheflag) {
-               case IOMAP_FULL_CACHING:
-                       physaddr |= _PAGE_CACHE040;
-                       break;
-               case IOMAP_NOCACHE_SER:
-               default:
-                       physaddr |= _PAGE_NOCACHE_S;
-                       break;
-               case IOMAP_NOCACHE_NONSER:
-                       physaddr |= _PAGE_NOCACHE;
-                       break;
-               case IOMAP_WRITETHROUGH:
-                       physaddr |= _PAGE_CACHE040W;
-                       break;
-               }
-       } else {
-               physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
-               switch (cacheflag) {
-               case IOMAP_NOCACHE_SER:
-               case IOMAP_NOCACHE_NONSER:
-               default:
-                       physaddr |= _PAGE_NOCACHE030;
-                       break;
-               case IOMAP_FULL_CACHING:
-               case IOMAP_WRITETHROUGH:
-                       break;
-               }
-       }
-
-       while ((long)size > 0) {
-#ifdef DEBUG
-               if (!(virtaddr & (PTRTREESIZE-1)))
-                       printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr);
-#endif
-               pgd_dir = pgd_offset_k(virtaddr);
-               pmd_dir = pmd_alloc(&init_mm, pgd_dir, virtaddr);
-               if (!pmd_dir) {
-                       printk("ioremap: no mem for pmd_dir\n");
-                       return NULL;
-               }
-
-               if (CPU_IS_020_OR_030) {
-                       pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
-                       physaddr += PTRTREESIZE;
-                       virtaddr += PTRTREESIZE;
-                       size -= PTRTREESIZE;
-               } else {
-                       pte_dir = pte_alloc_kernel(pmd_dir, virtaddr);
-                       if (!pte_dir) {
-                               printk("ioremap: no mem for pte_dir\n");
-                               return NULL;
-                       }
-
-                       pte_val(*pte_dir) = physaddr;
-                       virtaddr += PAGE_SIZE;
-                       physaddr += PAGE_SIZE;
-                       size -= PAGE_SIZE;
-               }
-       }
-#ifdef DEBUG
-       printk("\n");
-#endif
-       flush_tlb_all();
-
-       return (void __iomem *)retaddr;
-}
-EXPORT_SYMBOL(__ioremap);
-
-/*
- * Unmap a ioremap()ed region again
- */
-void iounmap(void __iomem *addr)
-{
-#ifdef CONFIG_AMIGA
-       if ((!MACH_IS_AMIGA) ||
-           (((unsigned long)addr < 0x40000000) ||
-            ((unsigned long)addr > 0x60000000)))
-                       free_io_area((__force void *)addr);
-#else
-       free_io_area((__force void *)addr);
-#endif
-}
-EXPORT_SYMBOL(iounmap);
-
-/*
- * __iounmap unmaps nearly everything, so be careful
- * it doesn't free currently pointer/page tables anymore but it
- * wans't used anyway and might be added later.
- */
-void __iounmap(void *addr, unsigned long size)
-{
-       unsigned long virtaddr = (unsigned long)addr;
-       pgd_t *pgd_dir;
-       pmd_t *pmd_dir;
-       pte_t *pte_dir;
-
-       while ((long)size > 0) {
-               pgd_dir = pgd_offset_k(virtaddr);
-               if (pgd_bad(*pgd_dir)) {
-                       printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
-                       pgd_clear(pgd_dir);
-                       return;
-               }
-               pmd_dir = pmd_offset(pgd_dir, virtaddr);
-
-               if (CPU_IS_020_OR_030) {
-                       int pmd_off = (virtaddr/PTRTREESIZE) & 15;
-                       int pmd_type = pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK;
-
-                       if (pmd_type == _PAGE_PRESENT) {
-                               pmd_dir->pmd[pmd_off] = 0;
-                               virtaddr += PTRTREESIZE;
-                               size -= PTRTREESIZE;
-                               continue;
-                       } else if (pmd_type == 0)
-                               continue;
-               }
-
-               if (pmd_bad(*pmd_dir)) {
-                       printk("iounmap: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
-                       pmd_clear(pmd_dir);
-                       return;
-               }
-               pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
-
-               pte_val(*pte_dir) = 0;
-               virtaddr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       flush_tlb_all();
-}
-
-/*
- * Set new cache mode for some kernel address space.
- * The caller must push data for that range itself, if such data may already
- * be in the cache.
- */
-void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
-{
-       unsigned long virtaddr = (unsigned long)addr;
-       pgd_t *pgd_dir;
-       pmd_t *pmd_dir;
-       pte_t *pte_dir;
-
-       if (CPU_IS_040_OR_060) {
-               switch (cmode) {
-               case IOMAP_FULL_CACHING:
-                       cmode = _PAGE_CACHE040;
-                       break;
-               case IOMAP_NOCACHE_SER:
-               default:
-                       cmode = _PAGE_NOCACHE_S;
-                       break;
-               case IOMAP_NOCACHE_NONSER:
-                       cmode = _PAGE_NOCACHE;
-                       break;
-               case IOMAP_WRITETHROUGH:
-                       cmode = _PAGE_CACHE040W;
-                       break;
-               }
-       } else {
-               switch (cmode) {
-               case IOMAP_NOCACHE_SER:
-               case IOMAP_NOCACHE_NONSER:
-               default:
-                       cmode = _PAGE_NOCACHE030;
-                       break;
-               case IOMAP_FULL_CACHING:
-               case IOMAP_WRITETHROUGH:
-                       cmode = 0;
-               }
-       }
-
-       while ((long)size > 0) {
-               pgd_dir = pgd_offset_k(virtaddr);
-               if (pgd_bad(*pgd_dir)) {
-                       printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
-                       pgd_clear(pgd_dir);
-                       return;
-               }
-               pmd_dir = pmd_offset(pgd_dir, virtaddr);
-
-               if (CPU_IS_020_OR_030) {
-                       int pmd_off = (virtaddr/PTRTREESIZE) & 15;
-
-                       if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
-                               pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] &
-                                                        _CACHEMASK040) | cmode;
-                               virtaddr += PTRTREESIZE;
-                               size -= PTRTREESIZE;
-                               continue;
-                       }
-               }
-
-               if (pmd_bad(*pmd_dir)) {
-                       printk("iocachemode: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
-                       pmd_clear(pmd_dir);
-                       return;
-               }
-               pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
-
-               pte_val(*pte_dir) = (pte_val(*pte_dir) & _CACHEMASK040) | cmode;
-               virtaddr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       flush_tlb_all();
-}
-EXPORT_SYMBOL(kernel_set_cachemode);
diff --git a/arch/m68k/mm/kmap_no.c b/arch/m68k/mm/kmap_no.c
deleted file mode 100644 (file)
index ece8d5a..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- *  linux/arch/m68knommu/mm/kmap.c
- *
- *  Copyright (C) 2000 Lineo, <davidm@snapgear.com>
- *  Copyright (C) 2000-2002 David McCullough <davidm@snapgear.com>
- */
-
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/page.h>
-#include <asm/pgalloc.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
-#undef DEBUG
-
-/*
- * Map some physical address range into the kernel address space.
- */
-void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
-{
-       return (void *)physaddr;
-}
-
-/*
- * Unmap a ioremap()ed region again.
- */
-void iounmap(void *addr)
-{
-}
-
-/*
- * Set new cache mode for some kernel address space.
- * The caller must push data for that range itself, if such data may already
- * be in the cache.
- */
-void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
-{
-}
index 676960cf022aa46d14dc62093d6825c3f4a15a14..f68dce766c0a34ca4fd54ea8185724e49394c22b 100644 (file)
@@ -10,7 +10,6 @@
  * Linux/m68k support by Hamish Macdonald
  */
 
-#include <linux/sys.h>
 #include <linux/linkage.h>
 #include <asm/thread_info.h>
 #include <asm/unistd.h>
@@ -80,7 +79,7 @@ ENTRY(system_call)
        movel   %sp,%d1                 /* get thread_info pointer */
        andl    #-THREAD_SIZE,%d1
        movel   %d1,%a2
-       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
+       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
        jne     do_trace
        cmpl    #NR_syscalls,%d0
        jcc     badsys
@@ -107,12 +106,12 @@ Luser_return:
        andl    #-THREAD_SIZE,%d1
        movel   %d1,%a2
 1:
-       move    %a2@(TI_FLAGS),%d1      /* thread_info->flags */
+       move    %a2@(TINFO_FLAGS),%d1   /* thread_info->flags */
        jne     Lwork_to_do
        RESTORE_ALL
 
 Lwork_to_do:
-       movel   %a2@(TI_FLAGS),%d1      /* thread_info->flags */
+       movel   %a2@(TINFO_FLAGS),%d1   /* thread_info->flags */
        btst    #TIF_NEED_RESCHED,%d1
        jne     reschedule
 
index 46c1b18c9dcbfc80d9a16a2126b468c3f9cfea46..a07b14feed9245398cc3f57e928a7d2140324426 100644 (file)
@@ -12,7 +12,6 @@
  * M68360 Port by SED Systems, and Lineo.
  */
 
-#include <linux/sys.h>
 #include <linux/linkage.h>
 #include <asm/thread_info.h>
 #include <asm/unistd.h>
@@ -76,7 +75,7 @@ ENTRY(system_call)
        movel   %sp,%d1                 /* get thread_info pointer */
        andl    #-THREAD_SIZE,%d1
        movel   %d1,%a2
-       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
+       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
        jne     do_trace
        cmpl    #NR_syscalls,%d0
        jcc     badsys
@@ -103,12 +102,12 @@ Luser_return:
        andl    #-THREAD_SIZE,%d1
        movel   %d1,%a2
 1:
-       move    %a2@(TI_FLAGS),%d1      /* thread_info->flags */
+       move    %a2@(TINFO_FLAGS),%d1   /* thread_info->flags */
        jne     Lwork_to_do
        RESTORE_ALL
 
 Lwork_to_do:
-       movel   %a2@(TI_FLAGS),%d1      /* thread_info->flags */
+       movel   %a2@(TINFO_FLAGS),%d1   /* thread_info->flags */
        btst    #TIF_NEED_RESCHED,%d1
        jne     reschedule
 
index e88b95e2cc6227475934938ede809416793cc05c..df5ce20d181ce8c8b5e8eedf79a7cd4b1f8242ca 100644 (file)
@@ -9,6 +9,7 @@
 /***************************************************************************/
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <asm/dma.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
@@ -33,7 +34,9 @@ unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
        MCFDMA_BASE3,
 #endif
 };
+EXPORT_SYMBOL(dma_base_addr);
 
 unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+EXPORT_SYMBOL(dma_device_address);
 
 /***************************************************************************/
index eab63f09965b0593db1bfb67a08dbd12db21562b..27c2b001161e1d31b43bc7a2ba6640ba4ceb4139 100644 (file)
@@ -26,7 +26,6 @@
  * Bug, speed and maintainability fixes by Philippe De Muyter <phdm@macqel.be>
  */
 
-#include <linux/sys.h>
 #include <linux/linkage.h>
 #include <asm/unistd.h>
 #include <asm/thread_info.h>
@@ -78,7 +77,7 @@ ENTRY(system_call)
        movel   %d2,%a0
        movel   %a0@,%a1                /* save top of frame */
        movel   %sp,%a1@(TASK_THREAD+THREAD_ESP0)
-       btst    #(TIF_SYSCALL_TRACE%8),%a0@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
+       btst    #(TIF_SYSCALL_TRACE%8),%a0@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
        bnes    1f
 
        movel   %d3,%a0
@@ -113,11 +112,11 @@ ret_from_exception:
        movel   %sp,%d1                 /* get thread_info pointer */
        andl    #-THREAD_SIZE,%d1       /* at base of kernel stack */
        movel   %d1,%a0
-       movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
+       movel   %a0@(TINFO_FLAGS),%d1   /* get thread_info->flags */
        andl    #(1<<TIF_NEED_RESCHED),%d1
        jeq     Lkernel_return
 
-       movel   %a0@(TI_PREEMPTCOUNT),%d1
+       movel   %a0@(TINFO_PREEMPT),%d1
        cmpl    #0,%d1
        jne     Lkernel_return
 
@@ -137,14 +136,14 @@ Luser_return:
        movel   %sp,%d1                 /* get thread_info pointer */
        andl    #-THREAD_SIZE,%d1       /* at base of kernel stack */
        movel   %d1,%a0
-       movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
+       movel   %a0@(TINFO_FLAGS),%d1   /* get thread_info->flags */
        jne     Lwork_to_do             /* still work to do */
 
 Lreturn:
        RESTORE_USER
 
 Lwork_to_do:
-       movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
+       movel   %a0@(TINFO_FLAGS),%d1   /* get thread_info->flags */
        move    #0x2000,%sr             /* enable intrs again */
        btst    #TIF_NEED_RESCHED,%d1
        jne     reschedule
index 6ae91a4991842466a3d86ae47cde14b6c2d31db1..c33483824a2eed3573c6d1c8b1c07545b136a800 100644 (file)
@@ -8,7 +8,6 @@
 
 /*****************************************************************************/
 
-#include <linux/sys.h>
 #include <linux/linkage.h>
 #include <linux/init.h>
 #include <asm/asm-offsets.h>
index eccdefe70d4e4ba1b4874df00228faff583e948b..e446bab2427bc7c69982190f3e89c0f442752780 100644 (file)
@@ -33,12 +33,6 @@ config ARCH_HAS_ILOG2_U32
 config ARCH_HAS_ILOG2_U64
        def_bool n
 
-config GENERIC_FIND_NEXT_BIT
-       def_bool y
-
-config GENERIC_FIND_BIT_LE
-       def_bool y
-
 config GENERIC_HWEIGHT
        def_bool y
 
index 30edd61a6b8fe4d5bbd0a52c9dc687e1f5901896..7d7092b917ac5ddb61664075aca7879ca95d6717 100644 (file)
 #define __NR_open_by_handle_at 372
 #define __NR_clock_adjtime     373
 #define __NR_syncfs            374
+#define __NR_setns             375
 
-#define __NR_syscalls          375
+#define __NR_syscalls          376
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
index 00ee90f083438340ca174710c3c8a91ef92cb612..b15cc219b1d98ed86eeb6375b596bb3caaa789dd 100644 (file)
@@ -130,7 +130,7 @@ void __init early_init_devtree(void *params)
         * device-tree, including the platform type, initrd location and
         * size, TCE reserve, and more ...
         */
-       of_scan_flat_dt(early_init_dt_scan_chosen, NULL);
+       of_scan_flat_dt(early_init_dt_scan_chosen, cmd_line);
 
        /* Scan memory nodes and rebuild MEMBLOCKs */
        memblock_init();
index 85cea81d1ca15c35cab526a104d71c5fa65b16d1..d915a122c86592fa29b8ebf395c4902881be5539 100644 (file)
@@ -379,3 +379,4 @@ ENTRY(sys_call_table)
        .long sys_open_by_handle_at
        .long sys_clock_adjtime
        .long sys_syncfs
+       .long sys_setns                 /* 375 */
index c8437866d3b75f3bde5d7c5fad00f9d624e9d58e..213f2d67166960de3a966e7443136c0b934faaa6 100644 (file)
@@ -32,8 +32,6 @@ unsigned int __page_offset;
 EXPORT_SYMBOL(__page_offset);
 
 #else
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 static int init_bootmem_done;
 #endif /* CONFIG_MMU */
 
index cef1a854487d1fff86c9154aabb86027e5eba2f5..653da62d0682b06bc0df0cf489dc1059a554faec 100644 (file)
@@ -821,14 +821,6 @@ config ARCH_SUPPORTS_OPROFILE
        bool
        default y if !MIPS_MT_SMTC
 
-config GENERIC_FIND_NEXT_BIT
-       bool
-       default y
-
-config GENERIC_FIND_BIT_LE
-       bool
-       default y
-
 config GENERIC_HWEIGHT
        bool
        default y
index 5358f90b4dd2ccee0c6767a01ebbc4f238f77976..83ed00a5644ac1b72286adbf81a95b40219462ba 100644 (file)
@@ -76,15 +76,6 @@ config DEBUG_STACKOVERFLOW
          provides another way to check stack overflow happened on kernel mode
          stack usually caused by nested interruption.
 
-config DEBUG_STACK_USAGE
-       bool "Enable stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T and sysrq-P debug output.
-
-         This option will slow down process creation somewhat.
-
 config SMTC_IDLE_HOOK_DEBUG
        bool "Enable additional debug checks before going into CPU idle loop"
        depends on DEBUG_KERNEL && MIPS_MT_SMTC
index 008f657116eb4a61822a711fe8f0c845b157a500..0ee02f5e51cce7e6bb1bfb10304539059f211169 100644 (file)
@@ -16,7 +16,6 @@
 
 static struct map_info flash_map;
 static struct mtd_info *mymtd;
-#ifdef CONFIG_MTD_PARTITIONS
 static int nr_parts;
 static struct mtd_partition *parts;
 static const char *part_probe_types[] = {
@@ -26,7 +25,6 @@ static const char *part_probe_types[] = {
 #endif
        NULL
 };
-#endif
 
 /**
  * Module/ driver initialization.
@@ -63,17 +61,10 @@ static int __init flash_init(void)
                if (mymtd) {
                        mymtd->owner = THIS_MODULE;
 
-#ifdef CONFIG_MTD_PARTITIONS
                        nr_parts = parse_mtd_partitions(mymtd,
                                                        part_probe_types,
                                                        &parts, 0);
-                       if (nr_parts > 0)
-                               add_mtd_partitions(mymtd, parts, nr_parts);
-                       else
-                               add_mtd_device(mymtd);
-#else
-                       add_mtd_device(mymtd);
-#endif
+                       mtd_device_register(mymtd, parts, nr_parts);
                } else {
                        pr_err("Failed to register MTD device for flash\n");
                }
index 22fdf2f0cc236922976f26a2281b9940589576c8..ad15fb10322b28f8ccf0fbc8d29427ef0606ab93 100644 (file)
@@ -16,7 +16,6 @@ CONFIG_TASK_IO_ACCOUNTING=y
 CONFIG_AUDIT=y
 CONFIG_TINY_RCU=y
 CONFIG_CGROUPS=y
-CONFIG_CGROUP_NS=y
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
index 37862b2ce3633a3f87f3aeb0ce3f8e119688a143..807c97eed8a8ed48a5957c144e907894c8d8c397 100644 (file)
@@ -678,7 +678,7 @@ CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
-CONFIG_RTC_CLASS=m
+CONFIG_RTC_CLASS=y
 CONFIG_RTC_INTF_DEV_UIE_EMUL=y
 CONFIG_RTC_DRV_TEST=m
 CONFIG_RTC_DRV_DS1307=m
index f29b862d9db31b45476e6dfcaccd427f17800eb4..857d9b7858ad6265a6406d355c71eb68e7a45a3e 100644 (file)
@@ -14,9 +14,6 @@
 #ifdef CONFIG_OF
 #include <asm/bootinfo.h>
 
-/* which is compatible with the flattened device tree (FDT) */
-#define cmd_line arcs_cmdline
-
 extern int early_init_dt_scan_memory_arch(unsigned long node,
        const char *uname, int depth, void *data);
 
index 294cdb66c5fcb4b6d49ea338fa7ac4b45c1b27cd..3adac3b53d1930172595b7e3b5dbdfc9dd4cf42d 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef __ASM_SUSPEND_H
 #define __ASM_SUSPEND_H
 
-static inline int arch_prepare_suspend(void) { return 0; }
-
 /* References to section boundaries */
 extern const void __nosave_begin, __nosave_end;
 
index fa2e37ea2be17220a958a7dfaefbd121ee5e6bb8..6fcfc480e9d017bdadafec7042819b0a607547bf 100644 (file)
 #define __NR_open_by_handle_at         (__NR_Linux + 340)
 #define __NR_clock_adjtime             (__NR_Linux + 341)
 #define __NR_syncfs                    (__NR_Linux + 342)
+#define __NR_setns                     (__NR_Linux + 343)
 
 /*
  * Offset of the last Linux o32 flavoured syscall
  */
-#define __NR_Linux_syscalls            342
+#define __NR_Linux_syscalls            343
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
 
 #define __NR_O32_Linux                 4000
-#define __NR_O32_Linux_syscalls                342
+#define __NR_O32_Linux_syscalls                343
 
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 
 #define __NR_open_by_handle_at         (__NR_Linux + 299)
 #define __NR_clock_adjtime             (__NR_Linux + 300)
 #define __NR_syncfs                    (__NR_Linux + 301)
+#define __NR_setns                     (__NR_Linux + 302)
 
 /*
  * Offset of the last Linux 64-bit flavoured syscall
  */
-#define __NR_Linux_syscalls            301
+#define __NR_Linux_syscalls            302
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
 
 #define __NR_64_Linux                  5000
-#define __NR_64_Linux_syscalls         301
+#define __NR_64_Linux_syscalls         302
 
 #if _MIPS_SIM == _MIPS_SIM_NABI32
 
 #define __NR_open_by_handle_at         (__NR_Linux + 304)
 #define __NR_clock_adjtime             (__NR_Linux + 305)
 #define __NR_syncfs                    (__NR_Linux + 306)
+#define __NR_setns                     (__NR_Linux + 307)
 
 /*
  * Offset of the last N32 flavoured syscall
  */
-#define __NR_Linux_syscalls            306
+#define __NR_Linux_syscalls            307
 
 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
 
 #define __NR_N32_Linux                 6000
-#define __NR_N32_Linux_syscalls                306
+#define __NR_N32_Linux_syscalls                307
 
 #ifdef __KERNEL__
 
index a19811e98a411cb2b99386d74627205316070233..5b7eade41fa3866e5adc4d029688db5b0beb8570 100644 (file)
@@ -83,7 +83,8 @@ void __init early_init_devtree(void *params)
         * device-tree, including the platform type, initrd location and
         * size, and more ...
         */
-       of_scan_flat_dt(early_init_dt_scan_chosen, NULL);
+       of_scan_flat_dt(early_init_dt_scan_chosen, arcs_cmdline);
+
 
        /* Scan memory nodes */
        of_scan_flat_dt(early_init_dt_scan_root, NULL);
index 7a8e1dd7f6f2188af20aaf4bfff978bf4a39f59d..99e656e425f31c929ce448f15646837386090b09 100644 (file)
@@ -589,6 +589,7 @@ einval:     li      v0, -ENOSYS
        sys     sys_open_by_handle_at   3       /* 4340 */
        sys     sys_clock_adjtime       2
        sys     sys_syncfs              1
+       sys     sys_setns               2
        .endm
 
        /* We pre-compute the number of _instruction_ bytes needed to
index 2d31c83224f988fc240a8b9ba6a7fcbd68750740..fb0575f47f3d1b8696873327c18676cb676a97a5 100644 (file)
@@ -428,4 +428,5 @@ sys_call_table:
        PTR     sys_open_by_handle_at
        PTR     sys_clock_adjtime               /* 5300 */
        PTR     sys_syncfs
+       PTR     sys_setns
        .size   sys_call_table,.-sys_call_table
index 38a0503b9a4a5c062ed9ff3b3baf6a72fd09f2d7..4de0c5534e73e04e9ca162c9de6844a773bbb0e6 100644 (file)
@@ -428,4 +428,5 @@ EXPORT(sysn32_call_table)
        PTR     sys_open_by_handle_at
        PTR     compat_sys_clock_adjtime        /* 6305 */
        PTR     sys_syncfs
+       PTR     sys_setns
        .size   sysn32_call_table,.-sysn32_call_table
index 91ea5e4041ddd5683e7c1e63bd2d63ec0835d633..4a387de08bfa1d48954ea9296d72d22024dad448 100644 (file)
@@ -546,4 +546,5 @@ sys_call_table:
        PTR     compat_sys_open_by_handle_at    /* 4340 */
        PTR     compat_sys_clock_adjtime
        PTR     sys_syncfs
+       PTR     sys_setns
        .size   sys_call_table,.-sys_call_table
index 01af3876cf90f2e73f684b37a794f8501c800beb..a81176f44c74d4e39be2eaf8d939ccdf1aa5157b 100644 (file)
@@ -118,7 +118,7 @@ SECTIONS
                EXIT_DATA
        }
 
-       PERCPU(1 << CONFIG_MIPS_L1_CACHE_SHIFT, PAGE_SIZE)
+       PERCPU_SECTION(1 << CONFIG_MIPS_L1_CACHE_SHIFT)
        . = ALIGN(PAGE_SIZE);
        __init_end = .;
        /* freed after init ends here */
index 279599e9a779fa80fe4e237d353aa5fe916dedab..1aadeb42c5a59ebd3f696478f29252e77adeea42 100644 (file)
@@ -64,8 +64,6 @@
 
 #endif /* CONFIG_MIPS_MT_SMTC */
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 /*
  * We have up to 8 empty zeroed pages so we can map one of the right colour
  * when needed.  This is necessary only on R4000 / R4400 SC and MC versions
index 812816c456620f86fce6ba670d2f6352df7f9b6d..ec38e00b25592dccd0cbf51f7ed3ec3c10584e12 100644 (file)
@@ -639,7 +639,6 @@ void __init txx9_physmap_flash_init(int no, unsigned long addr,
                .flags = IORESOURCE_MEM,
        };
        struct platform_device *pdev;
-#ifdef CONFIG_MTD_PARTITIONS
        static struct mtd_partition parts[2];
        struct physmap_flash_data pdata_part;
 
@@ -658,7 +657,7 @@ void __init txx9_physmap_flash_init(int no, unsigned long addr,
                pdata_part.parts = parts;
                pdata = &pdata_part;
        }
-#endif
+
        pdev = platform_device_alloc("physmap-flash", no);
        if (!pdev ||
            platform_device_add_resources(pdev, &res, 1) ||
index feaf09cc86325b2f49ac423e9e9aafff5cf37744..1f870340ebdd9a1dcd0b559d8004dc2165a9eb32 100644 (file)
@@ -44,9 +44,6 @@ config GENERIC_CALIBRATE_DELAY
 config GENERIC_CMOS_UPDATE
         def_bool n
 
-config GENERIC_FIND_NEXT_BIT
-       def_bool y
-
 config GENERIC_HWEIGHT
        def_bool y
 
index 31d76261a3d5b4851066ac3059391c4760a92b9e..fbb96ae3122a6b91323897906f88f1843f850fbf 100644 (file)
@@ -8,7 +8,6 @@ CONFIG_TASK_XACCT=y
 CONFIG_TASK_IO_ACCOUNTING=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CGROUPS=y
-CONFIG_CGROUP_NS=y
 CONFIG_CGROUP_FREEZER=y
 CONFIG_CGROUP_DEVICE=y
 CONFIG_CGROUP_CPUACCT=y
index 3d6e60dad9d98a2b99a44029658638c48f300d50..780560b330d9ef9109a76b0210185f3bc178ca8e 100644 (file)
@@ -15,6 +15,7 @@
  * User space memory access functions
  */
 #include <linux/thread_info.h>
+#include <linux/kernel.h>
 #include <asm/page.h>
 #include <asm/errno.h>
 
index 9d056f5159292cceb0729f93df7022b2e2e31edd..9051f921cbc7a94252212b625f1161759d054965 100644 (file)
 #define __NR_rt_tgsigqueueinfo 336
 #define __NR_perf_event_open   337
 #define __NR_recvmmsg          338
+#define __NR_setns             339
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 339
+#define NR_syscalls 340
 
 /*
  * specify the deprecated syscalls we want to support on this arch
index fb93ad720b82665cb5abbf1add396fdfd2e53ec4..ae435e1d56694f71d5471b4000c130d7ea4c30d2 100644 (file)
@@ -759,6 +759,7 @@ ENTRY(sys_call_table)
        .long sys_rt_tgsigqueueinfo
        .long sys_perf_event_open
        .long sys_recvmmsg
+       .long sys_setns
 
 
 nr_syscalls=(.-sys_call_table)/4
index 86af0d7d07719aab1c3435b71adb44ded4fee730..2623d19f4f4c5bfebfa79f0cc6c3be60b1352081 100644 (file)
@@ -87,7 +87,7 @@ static void mn10300_cpupic_mask_ack(struct irq_data *d)
                tmp2 = GxICR(irq);
 
                irq_affinity_online[irq] =
-                       any_online_cpu(*d->affinity);
+                       cpumask_any_and(d->affinity, cpu_online_mask);
                CROSS_GxICR(irq, irq_affinity_online[irq]) =
                        (tmp & (GxICR_LEVEL | GxICR_ENABLE)) | GxICR_DETECT;
                tmp = CROSS_GxICR(irq, irq_affinity_online[irq]);
@@ -124,7 +124,8 @@ static void mn10300_cpupic_unmask_clear(struct irq_data *d)
        } else {
                tmp = GxICR(irq);
 
-               irq_affinity_online[irq] = any_online_cpu(*d->affinity);
+               irq_affinity_online[irq] = cpumask_any_and(d->affinity,
+                                                          cpu_online_mask);
                CROSS_GxICR(irq, irq_affinity_online[irq]) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT;
                tmp = CROSS_GxICR(irq, irq_affinity_online[irq]);
        }
@@ -366,11 +367,11 @@ void migrate_irqs(void)
                if (irqd_is_per_cpu(data))
                        continue;
 
-               if (cpu_isset(self, data->affinity) &&
-                   !cpus_intersects(irq_affinity[irq], cpu_online_map)) {
+               if (cpumask_test_cpu(self, &data->affinity) &&
+                   !cpumask_intersects(&irq_affinity[irq], cpu_online_mask)) {
                        int cpu_id;
-                       cpu_id = first_cpu(cpu_online_map);
-                       cpu_set(cpu_id, data->affinity);
+                       cpu_id = cpumask_first(cpu_online_mask);
+                       cpumask_set_cpu(cpu_id, &data->affinity);
                }
                /* We need to operate irq_affinity_online atomically. */
                arch_local_cli_save(flags);
@@ -381,7 +382,8 @@ void migrate_irqs(void)
                        GxICR(irq) = x & GxICR_LEVEL;
                        tmp = GxICR(irq);
 
-                       new = any_online_cpu(data->affinity);
+                       new = cpumask_any_and(&data->affinity,
+                                             cpu_online_mask);
                        irq_affinity_online[irq] = new;
 
                        CROSS_GxICR(irq, new) =
index 83fb2791223134aece3c8d29587dc810aed87d31..9242e9fcc56487d41a4c37c2019d7a4ed2614eec 100644 (file)
@@ -309,7 +309,7 @@ static void send_IPI_mask(const cpumask_t *cpumask, int irq)
        u16 tmp;
 
        for (i = 0; i < NR_CPUS; i++) {
-               if (cpu_isset(i, *cpumask)) {
+               if (cpumask_test_cpu(i, cpumask)) {
                        /* send IPI */
                        tmp = CROSS_GxICR(irq, i);
                        CROSS_GxICR(irq, i) =
@@ -342,8 +342,8 @@ void send_IPI_allbutself(int irq)
 {
        cpumask_t cpumask;
 
-       cpumask = cpu_online_map;
-       cpu_clear(smp_processor_id(), cpumask);
+       cpumask_copy(&cpumask, cpu_online_mask);
+       cpumask_clear_cpu(smp_processor_id(), &cpumask);
        send_IPI_mask(&cpumask, irq);
 }
 
@@ -393,8 +393,8 @@ int smp_nmi_call_function(smp_call_func_t func, void *info, int wait)
 
        data.func = func;
        data.info = info;
-       data.started = cpu_online_map;
-       cpu_clear(smp_processor_id(), data.started);
+       cpumask_copy(&data.started, cpu_online_mask);
+       cpumask_clear_cpu(smp_processor_id(), &data.started);
        data.wait = wait;
        if (wait)
                data.finished = data.started;
@@ -410,14 +410,14 @@ int smp_nmi_call_function(smp_call_func_t func, void *info, int wait)
        if (CALL_FUNCTION_NMI_IPI_TIMEOUT > 0) {
                for (cnt = 0;
                     cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT &&
-                            !cpus_empty(data.started);
+                            !cpumask_empty(&data.started);
                     cnt++)
                        mdelay(1);
 
                if (wait && cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT) {
                        for (cnt = 0;
                             cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT &&
-                                    !cpus_empty(data.finished);
+                                    !cpumask_empty(&data.finished);
                             cnt++)
                                mdelay(1);
                }
@@ -428,10 +428,10 @@ int smp_nmi_call_function(smp_call_func_t func, void *info, int wait)
        } else {
                /* If timeout value is zero, wait until cpumask has been
                 * cleared */
-               while (!cpus_empty(data.started))
+               while (!cpumask_empty(&data.started))
                        barrier();
                if (wait)
-                       while (!cpus_empty(data.finished))
+                       while (!cpumask_empty(&data.finished))
                                barrier();
        }
 
@@ -472,12 +472,12 @@ void stop_this_cpu(void *unused)
 #endif /* CONFIG_GDBSTUB */
 
        flags = arch_local_cli_save();
-       cpu_clear(smp_processor_id(), cpu_online_map);
+       set_cpu_online(smp_processor_id(), false);
 
        while (!stopflag)
                cpu_relax();
 
-       cpu_set(smp_processor_id(), cpu_online_map);
+       set_cpu_online(smp_processor_id(), true);
        arch_local_irq_restore(flags);
 }
 
@@ -529,12 +529,13 @@ void smp_nmi_call_function_interrupt(void)
         * execute the function
         */
        smp_mb();
-       cpu_clear(smp_processor_id(), nmi_call_data->started);
+       cpumask_clear_cpu(smp_processor_id(), &nmi_call_data->started);
        (*func)(info);
 
        if (wait) {
                smp_mb();
-               cpu_clear(smp_processor_id(), nmi_call_data->finished);
+               cpumask_clear_cpu(smp_processor_id(),
+                                 &nmi_call_data->finished);
        }
 }
 
@@ -657,7 +658,7 @@ int __init start_secondary(void *unused)
 {
        smp_cpu_init();
        smp_callin();
-       while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
+       while (!cpumask_test_cpu(smp_processor_id(), &smp_commenced_mask))
                cpu_relax();
 
        local_flush_tlb();
@@ -780,13 +781,14 @@ static int __init do_boot_cpu(int phy_id)
 
        if (send_status == 0) {
                /* Allow AP to start initializing */
-               cpu_set(cpu_id, cpu_callout_map);
+               cpumask_set_cpu(cpu_id, &cpu_callout_map);
 
                /* Wait for setting cpu_callin_map */
                timeout = 0;
                do {
                        udelay(1000);
-                       callin_status = cpu_isset(cpu_id, cpu_callin_map);
+                       callin_status = cpumask_test_cpu(cpu_id,
+                                                        &cpu_callin_map);
                } while (callin_status == 0 && timeout++ < 5000);
 
                if (callin_status == 0)
@@ -796,9 +798,9 @@ static int __init do_boot_cpu(int phy_id)
        }
 
        if (send_status == GxICR_REQUEST || callin_status == 0) {
-               cpu_clear(cpu_id, cpu_callout_map);
-               cpu_clear(cpu_id, cpu_callin_map);
-               cpu_clear(cpu_id, cpu_initialized);
+               cpumask_clear_cpu(cpu_id, &cpu_callout_map);
+               cpumask_clear_cpu(cpu_id, &cpu_callin_map);
+               cpumask_clear_cpu(cpu_id, &cpu_initialized);
                cpucount--;
                return 1;
        }
@@ -833,7 +835,7 @@ static void __init smp_callin(void)
        cpu = smp_processor_id();
        timeout = jiffies + (2 * HZ);
 
-       if (cpu_isset(cpu, cpu_callin_map)) {
+       if (cpumask_test_cpu(cpu, &cpu_callin_map)) {
                printk(KERN_ERR "CPU#%d already present.\n", cpu);
                BUG();
        }
@@ -841,7 +843,7 @@ static void __init smp_callin(void)
 
        /* Wait for AP startup 2s total */
        while (time_before(jiffies, timeout)) {
-               if (cpu_isset(cpu, cpu_callout_map))
+               if (cpumask_test_cpu(cpu, &cpu_callout_map))
                        break;
                cpu_relax();
        }
@@ -861,11 +863,11 @@ static void __init smp_callin(void)
        smp_store_cpu_info(cpu);
 
        /* Allow the boot processor to continue */
-       cpu_set(cpu, cpu_callin_map);
+       cpumask_set_cpu(cpu, &cpu_callin_map);
 }
 
 /**
- * smp_online - Set cpu_online_map
+ * smp_online - Set cpu_online_mask
  */
 static void __init smp_online(void)
 {
@@ -875,7 +877,7 @@ static void __init smp_online(void)
 
        local_irq_enable();
 
-       cpu_set(cpu, cpu_online_map);
+       set_cpu_online(cpu, true);
        smp_wmb();
 }
 
@@ -892,13 +894,13 @@ void __init smp_cpus_done(unsigned int max_cpus)
 /*
  * smp_prepare_boot_cpu - Set up stuff for the boot processor.
  *
- * Set up the cpu_online_map, cpu_callout_map and cpu_callin_map of the boot
+ * Set up the cpu_online_mask, cpu_callout_map and cpu_callin_map of the boot
  * processor (CPU 0).
  */
 void __devinit smp_prepare_boot_cpu(void)
 {
-       cpu_set(0, cpu_callout_map);
-       cpu_set(0, cpu_callin_map);
+       cpumask_set_cpu(0, &cpu_callout_map);
+       cpumask_set_cpu(0, &cpu_callin_map);
        current_thread_info()->cpu = 0;
 }
 
@@ -931,16 +933,16 @@ int __devinit __cpu_up(unsigned int cpu)
                run_wakeup_cpu(cpu);
 #endif /* CONFIG_HOTPLUG_CPU */
 
-       cpu_set(cpu, smp_commenced_mask);
+       cpumask_set_cpu(cpu, &smp_commenced_mask);
 
        /* Wait 5s total for a response */
        for (timeout = 0 ; timeout < 5000 ; timeout++) {
-               if (cpu_isset(cpu, cpu_online_map))
+               if (cpu_online(cpu))
                        break;
                udelay(1000);
        }
 
-       BUG_ON(!cpu_isset(cpu, cpu_online_map));
+       BUG_ON(!cpu_online(cpu));
        return 0;
 }
 
@@ -986,7 +988,7 @@ int __cpu_disable(void)
                return -EBUSY;
 
        migrate_irqs();
-       cpu_clear(cpu, current->active_mm->cpu_vm_mask);
+       cpumask_clear_cpu(cpu, &mm_cpumask(current->active_mm));
        return 0;
 }
 
@@ -1091,13 +1093,13 @@ static int hotplug_cpu_nmi_call_function(cpumask_t cpumask,
        do {
                mn10300_local_dcache_inv_range(start, end);
                barrier();
-       } while (!cpus_empty(nmi_call_func_mask_data.started));
+       } while (!cpumask_empty(&nmi_call_func_mask_data.started));
 
        if (wait) {
                do {
                        mn10300_local_dcache_inv_range(start, end);
                        barrier();
-               } while (!cpus_empty(nmi_call_func_mask_data.finished));
+               } while (!cpumask_empty(&nmi_call_func_mask_data.finished));
        }
 
        spin_unlock(&smp_nmi_call_lock);
@@ -1108,9 +1110,9 @@ static void restart_wakeup_cpu(void)
 {
        unsigned int cpu = smp_processor_id();
 
-       cpu_set(cpu, cpu_callin_map);
+       cpumask_set_cpu(cpu, &cpu_callin_map);
        local_flush_tlb();
-       cpu_set(cpu, cpu_online_map);
+       set_cpu_online(cpu, true);
        smp_wmb();
 }
 
@@ -1141,8 +1143,9 @@ static void sleep_cpu(void *unused)
 static void run_sleep_cpu(unsigned int cpu)
 {
        unsigned long flags;
-       cpumask_t cpumask = cpumask_of(cpu);
+       cpumask_t cpumask;
 
+       cpumask_copy(&cpumask, &cpumask_of(cpu));
        flags = arch_local_cli_save();
        hotplug_cpu_nmi_call_function(cpumask, prepare_sleep_cpu, NULL, 1);
        hotplug_cpu_nmi_call_function(cpumask, sleep_cpu, NULL, 0);
index f03cb278828f400c1e66580be491c30da507e9b3..bd3e5e73826e1839b307d5ae7a279a3e93f6afbc 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/irq.h>
 #include <asm/processor.h>
 #include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <asm/io.h>
 #include <asm/atomic.h>
 #include <asm/smp.h>
@@ -156,7 +156,7 @@ int die_if_no_fixup(const char *str, struct pt_regs *regs,
 
        case EXCEP_TRAP:
        case EXCEP_UNIMPINS:
-               if (get_user(opcode, (uint8_t __user *)regs->pc) != 0)
+               if (probe_kernel_read(&opcode, (u8 *)regs->pc, 1) < 0)
                        break;
                if (opcode == 0xff) {
                        if (notify_die(DIE_BREAKPOINT, str, regs, code, 0, 0))
index 968bcd2cb0226c325cc37837518e25dafe4ed6b9..13c4814c29f840dd4ecb95e4e7206da7127aef49 100644 (file)
@@ -44,6 +44,7 @@ SECTIONS
   RO_DATA(PAGE_SIZE)
 
   /* writeable */
+  _sdata = .;     /* Start of rw data section */
   RW_DATA_SECTION(32, PAGE_SIZE, THREAD_SIZE)
   _edata = .;
 
@@ -70,7 +71,7 @@ SECTIONS
        .exit.text : { EXIT_TEXT; }
        .exit.data : { EXIT_DATA; }
 
-  PERCPU(32, PAGE_SIZE)
+  PERCPU_SECTION(32)
   . = ALIGN(PAGE_SIZE);
   __init_end = .;
   /* freed after init ends here */
index 665919f2ab62ef3e8f43c4466f6f72fdd69988e9..a775ea5d7cee077cf37c5ceb90c8bfe773e4fd99 100644 (file)
@@ -120,14 +120,14 @@ debugger_local_cache_flushinv_one:
        # conditionally purge this line in all ways
        mov     d1,(L1_CACHE_WAYDISP*0,a0)
 
-debugger_local_cache_flushinv_no_dcache:
+debugger_local_cache_flushinv_one_no_dcache:
        #
        # now try to flush the icache
        #
        mov     CHCTR,a0
        movhu   (a0),d0
        btst    CHCTR_ICEN,d0
-       beq     mn10300_local_icache_inv_range_reg_end
+       beq     debugger_local_cache_flushinv_one_end
 
        LOCAL_CLI_SAVE(d1)
 
index 4a6e9a4b5b27d866048d99270ed6a030f8d4dd57..2d23b9eeee62eef7d1164c54b17a2f3c463c6b9e 100644 (file)
@@ -74,7 +74,7 @@ void smp_cache_interrupt(void)
                break;
        }
 
-       cpu_clear(smp_processor_id(), smp_cache_ipi_map);
+       cpumask_clear_cpu(smp_processor_id(), &smp_cache_ipi_map);
 }
 
 /**
@@ -94,12 +94,12 @@ void smp_cache_call(unsigned long opr_mask,
        smp_cache_mask = opr_mask;
        smp_cache_start = start;
        smp_cache_end = end;
-       smp_cache_ipi_map = cpu_online_map;
-       cpu_clear(smp_processor_id(), smp_cache_ipi_map);
+       cpumask_copy(&smp_cache_ipi_map, cpu_online_mask);
+       cpumask_clear_cpu(smp_processor_id(), &smp_cache_ipi_map);
 
        send_IPI_allbutself(FLUSH_CACHE_IPI);
 
-       while (!cpus_empty(smp_cache_ipi_map))
+       while (!cpumask_empty(&smp_cache_ipi_map))
                /* nothing. lockup detection does not belong here */
                mb();
 }
index 48907cc3bdb77311526c1b1ca173b20983091f8d..13801824e3ee298afda7db2ee5d0613266ed6ccd 100644 (file)
@@ -37,8 +37,6 @@
 #include <asm/tlb.h>
 #include <asm/sections.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 unsigned long highstart_pfn, highend_pfn;
 
 #ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
index 0b6a5ad1960e6dad2e665a489b7bccf2d61f9034..9a777498a916a3c8042dee0a3abf9ba960a122ba 100644 (file)
@@ -64,7 +64,7 @@ void smp_flush_tlb(void *unused)
 
        cpu_id = get_cpu();
 
-       if (!cpu_isset(cpu_id, flush_cpumask))
+       if (!cpumask_test_cpu(cpu_id, &flush_cpumask))
                /* This was a BUG() but until someone can quote me the line
                 * from the intel manual that guarantees an IPI to multiple
                 * CPUs is retried _only_ on the erroring CPUs its staying as a
@@ -80,7 +80,7 @@ void smp_flush_tlb(void *unused)
                local_flush_tlb_page(flush_mm, flush_va);
 
        smp_mb__before_clear_bit();
-       cpu_clear(cpu_id, flush_cpumask);
+       cpumask_clear_cpu(cpu_id, &flush_cpumask);
        smp_mb__after_clear_bit();
 out:
        put_cpu();
@@ -103,11 +103,11 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
         * - we do not send IPIs to as-yet unbooted CPUs.
         */
        BUG_ON(!mm);
-       BUG_ON(cpus_empty(cpumask));
-       BUG_ON(cpu_isset(smp_processor_id(), cpumask));
+       BUG_ON(cpumask_empty(&cpumask));
+       BUG_ON(cpumask_test_cpu(smp_processor_id(), &cpumask));
 
-       cpus_and(tmp, cpumask, cpu_online_map);
-       BUG_ON(!cpus_equal(cpumask, tmp));
+       cpumask_and(&tmp, &cpumask, cpu_online_mask);
+       BUG_ON(!cpumask_equal(&cpumask, &tmp));
 
        /* I'm not happy about this global shared spinlock in the MM hot path,
         * but we'll see how contended it is.
@@ -128,7 +128,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
        /* FIXME: if NR_CPUS>=3, change send_IPI_mask */
        smp_call_function(smp_flush_tlb, NULL, 1);
 
-       while (!cpus_empty(flush_cpumask))
+       while (!cpumask_empty(&flush_cpumask))
                /* Lockup detection does not belong here */
                smp_mb();
 
@@ -146,11 +146,11 @@ void flush_tlb_mm(struct mm_struct *mm)
        cpumask_t cpu_mask;
 
        preempt_disable();
-       cpu_mask = mm->cpu_vm_mask;
-       cpu_clear(smp_processor_id(), cpu_mask);
+       cpumask_copy(&cpu_mask, mm_cpumask(mm));
+       cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
 
        local_flush_tlb();
-       if (!cpus_empty(cpu_mask))
+       if (!cpumask_empty(&cpu_mask))
                flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
 
        preempt_enable();
@@ -165,11 +165,11 @@ void flush_tlb_current_task(void)
        cpumask_t cpu_mask;
 
        preempt_disable();
-       cpu_mask = mm->cpu_vm_mask;
-       cpu_clear(smp_processor_id(), cpu_mask);
+       cpumask_copy(&cpu_mask, mm_cpumask(mm));
+       cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
 
        local_flush_tlb();
-       if (!cpus_empty(cpu_mask))
+       if (!cpumask_empty(&cpu_mask))
                flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
 
        preempt_enable();
@@ -186,11 +186,11 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
        cpumask_t cpu_mask;
 
        preempt_disable();
-       cpu_mask = mm->cpu_vm_mask;
-       cpu_clear(smp_processor_id(), cpu_mask);
+       cpumask_copy(&cpu_mask, mm_cpumask(mm));
+       cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
 
        local_flush_tlb_page(mm, va);
-       if (!cpus_empty(cpu_mask))
+       if (!cpumask_empty(&cpu_mask))
                flush_tlb_others(cpu_mask, mm, va);
 
        preempt_enable();
index 69ff049c857127537a89cc1b5c0339bdedea8dd0..65adc86a230e705d64b41b1c69a886268f9a6eb6 100644 (file)
@@ -47,14 +47,6 @@ config ARCH_HAS_ILOG2_U64
        bool
        default n
 
-config GENERIC_FIND_NEXT_BIT
-       bool
-       default y
-
-config GENERIC_FIND_BIT_LE
-       bool
-       default y
-
 config GENERIC_BUG
        bool
        default y
index 2e73623feb6ba28d4590eafc02b573f8acb7c2c4..e8f8037d872bc91c794f50ba5fd7a0f8eb996232 100644 (file)
@@ -33,15 +33,6 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 
 #endif /* !ASSEMBLY */
 
-/*
- *     This magic constant controls our willingness to transfer
- *      a process across CPUs. Such a transfer incurs cache and tlb
- *      misses. The current value is inherited from i386. Still needs
- *      to be tuned for parisc.
- */
-#define PROC_CHANGE_PENALTY    15              /* Schedule penalty */
-
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
 #else /* CONFIG_SMP */
index 9cbc2c3bf630bea422fcafb546e419d7d88b8b44..3392de3e7be08eef3e60e377fbd7fe5039fb9ac9 100644 (file)
 #define __NR_name_to_handle_at (__NR_Linux + 325)
 #define __NR_open_by_handle_at (__NR_Linux + 326)
 #define __NR_syncfs            (__NR_Linux + 327)
+#define __NR_setns             (__NR_Linux + 328)
 
-#define __NR_Linux_syscalls    (__NR_syncfs + 1)
+#define __NR_Linux_syscalls    (__NR_setns + 1)
 
 
 #define __IGNORE_select                /* newselect */
index a5b02ce4d41eea6797b1c4ce5c24476f6764e0bd..34a4f5a2fffbdc9cf36ea2a5ebc19a6ffe1dc9d7 100644 (file)
        ENTRY_SAME(name_to_handle_at)   /* 325 */
        ENTRY_COMP(open_by_handle_at)
        ENTRY_SAME(syncfs)
+       ENTRY_SAME(setns)
 
        /* Nothing yet */
 
index e1a55849bfa7832d8b58fac498012cd8cc44a438..fa6f2b8163e03cc1bdc953bbb1e2b8282b826c7a 100644 (file)
@@ -149,7 +149,7 @@ SECTIONS
                EXIT_DATA
        }
 
-       PERCPU(L1_CACHE_BYTES, PAGE_SIZE)
+       PERCPU_SECTION(L1_CACHE_BYTES)
        . = ALIGN(PAGE_SIZE);
        __init_end = .;
        /* freed after init ends here */
index 5fa1e273006e2a673ed62aecdb62127a7a5e1a6b..82f364e209fc5a059f1be77fd5563e7c4a70c122 100644 (file)
@@ -31,8 +31,6 @@
 #include <asm/mmzone.h>
 #include <asm/sections.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 extern int  data_start;
 
 #ifdef CONFIG_DISCONTIGMEM
@@ -686,7 +684,7 @@ void show_mem(unsigned int filter)
        int shared = 0, cached = 0;
 
        printk(KERN_INFO "Mem-info:\n");
-       show_free_areas();
+       show_free_areas(filter);
 #ifndef CONFIG_DISCONTIGMEM
        i = max_mapnr;
        while (i-- > 0) {
index a3128ca0fe11c18edec56c175eaf39656ff4ebc8..2729c6663d8a79c42705b9f81828e6ee6d6f5dd0 100644 (file)
@@ -91,14 +91,6 @@ config GENERIC_HWEIGHT
        bool
        default y
 
-config GENERIC_FIND_NEXT_BIT
-       bool
-       default y
-
-config GENERIC_FIND_BIT_LE
-       bool
-       default y
-
 config GENERIC_GPIO
        bool
        help
@@ -140,6 +132,8 @@ config PPC
        select IRQ_PER_CPU
        select GENERIC_IRQ_SHOW
        select GENERIC_IRQ_SHOW_LEVEL
+       select HAVE_RCU_TABLE_FREE if SMP
+       select HAVE_SYSCALL_TRACEPOINTS
 
 config EARLY_PRINTK
        bool
index a597dd77b9035ba9b2eda6766b98b47a0e9770f4..e72dcf6a421d8581cc0e3b7fd231b2b3ebcf644c 100644 (file)
@@ -35,27 +35,6 @@ config DEBUG_STACKOVERFLOW
          This option will cause messages to be printed if free stack space
          drops below a certain limit.
 
-config DEBUG_STACK_USAGE
-       bool "Stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T and sysrq-P debug output.
-
-         This option will slow down process creation somewhat.
-
-config DEBUG_PER_CPU_MAPS
-       bool "Debug access to per_cpu maps"
-       depends on DEBUG_KERNEL
-       depends on SMP
-       default n
-       ---help---
-         Say Y to verify that the per_cpu map being accessed has
-         been setup.  Adds a fair amount of code to kernel memory
-         and decreases performance.
-
-         Say N if unsure.
-
 config HCALL_STATS
        bool "Hypervisor call instrumentation"
        depends on PPC_PSERIES && DEBUG_FS && TRACEPOINTS
index 3d80c3e9cf6003b2fe9bfe512c660a2961d81a32..12da77ec0228c419b8611675a6ddfce282cede81 100644 (file)
@@ -1,5 +1,4 @@
 addnote
-dtc
 empty.c
 hack-coff
 infblock.c
diff --git a/arch/powerpc/boot/dtc-src/.gitignore b/arch/powerpc/boot/dtc-src/.gitignore
deleted file mode 100644 (file)
index a7c3f94..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-dtc-lexer.lex.c
-dtc-parser.tab.c
-dtc-parser.tab.h
index 2779f08313a5b0c0400a2457e72dc39a6eba1cb0..22dd6ae84da0b08de2cefd98856d1ee4da308edb 100644 (file)
                                0x0 0x0 0x0 0x3 &UIC3 0x12 0x4 /* swizzled int C */
                                0x0 0x0 0x0 0x4 &UIC3 0x13 0x4 /* swizzled int D */>;
                };
+
+               MSI: ppc4xx-msi@C10000000 {
+                       compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+                       reg = < 0xC 0x10000000 0x100>;
+                       sdr-base = <0x36C>;
+                       msi-data = <0x00000000>;
+                       msi-mask = <0x44440000>;
+                       interrupt-count = <3>;
+                       interrupts = <0 1 2 3>;
+                       interrupt-parent = <&UIC3>;
+                       #interrupt-cells = <1>;
+                       #address-cells = <0>;
+                       #size-cells = <0>;
+                       interrupt-map = <0 &UIC3 0x18 1
+                                       1 &UIC3 0x19 1
+                                       2 &UIC3 0x1A 1
+                                       3 &UIC3 0x1B 1>;
+               };
        };
 };
index 7c3be5e45748e4abdaa2605b70c68fe851c50b21..f913dbe25d35a29dab9391ccbd2e96f203bf8672 100644 (file)
                                0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /* swizzled int D */>;
                };
 
+               MSI: ppc4xx-msi@400300000 {
+                               compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+                               reg = < 0x4 0x00300000 0x100>;
+                               sdr-base = <0x3B0>;
+                               msi-data = <0x00000000>;
+                               msi-mask = <0x44440000>;
+                               interrupt-count = <3>;
+                               interrupts =<0 1 2 3>;
+                               interrupt-parent = <&UIC0>;
+                               #interrupt-cells = <1>;
+                               #address-cells = <0>;
+                               #size-cells = <0>;
+                               interrupt-map = <0 &UIC0 0xC 1
+                                       1 &UIC0 0x0D 1
+                                       2 &UIC0 0x0E 1
+                                       3 &UIC0 0x0F 1>;
+               };
+
                I2O: i2o@400100000 {
                        compatible = "ibm,i2o-440spe";
                        reg = <0x00000004 0x00100000 0x100>;
index 89edb16649c36609aa2481e97fdf97786ea9872e..1613d6e4049eb2ba22aeceef97e8e57110620713 100644 (file)
                                0x0 0x0 0x0 0x3 &UIC2 0xd 0x4 /* swizzled int C */
                                0x0 0x0 0x0 0x4 &UIC2 0xe 0x4 /* swizzled int D */>;
                };
+
+               MSI: ppc4xx-msi@C10000000 {
+                       compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+                       reg = < 0x0 0xEF620000 0x100>;
+                       sdr-base = <0x4B0>;
+                       msi-data = <0x00000000>;
+                       msi-mask = <0x44440000>;
+                       interrupt-count = <12>;
+                       interrupts = <0 1 2 3 4 5 6 7 8 9 0xA 0xB 0xC 0xD>;
+                       interrupt-parent = <&UIC2>;
+                       #interrupt-cells = <1>;
+                       #address-cells = <0>;
+                       #size-cells = <0>;
+                       interrupt-map = <0 &UIC2 0x10 1
+                                       1 &UIC2 0x11 1
+                                       2 &UIC2 0x12 1
+                                       2 &UIC2 0x13 1
+                                       2 &UIC2 0x14 1
+                                       2 &UIC2 0x15 1
+                                       2 &UIC2 0x16 1
+                                       2 &UIC2 0x17 1
+                                       2 &UIC2 0x18 1
+                                       2 &UIC2 0x19 1
+                                       2 &UIC2 0x1A 1
+                                       2 &UIC2 0x1B 1
+                                       2 &UIC2 0x1C 1
+                                       3 &UIC2 0x1D 1>;
+               };
        };
 };
index 761faa7b6964e3dd6601e2acca95796f84fcfe44..ac1eb320c7b4a9925d5071584333ac35c97ea679 100644 (file)
                        sleep = <&pmc 0x00300000>;
                };
 
+               ptp_clock@24E00 {
+                       compatible = "fsl,etsec-ptp";
+                       reg = <0x24E00 0xB0>;
+                       interrupts = <12 0x8 13 0x8>;
+                       interrupt-parent = < &ipic >;
+                       fsl,tclk-period = <10>;
+                       fsl,tmr-prsc    = <100>;
+                       fsl,tmr-add     = <0x999999A4>;
+                       fsl,tmr-fiper1  = <0x3B9AC9F6>;
+                       fsl,tmr-fiper2  = <0x00018696>;
+                       fsl,max-adj     = <659999998>;
+               };
+
                enet0: ethernet@24000 {
                        #address-cells = <1>;
                        #size-cells = <1>;
index cafc1285c140778990d04e3096f81bcc032f0ffd..f6c04d25e91681c06628ecc5eda09afd153ab81d 100644 (file)
                        };
                };
 
+               ptp_clock@24E00 {
+                       compatible = "fsl,etsec-ptp";
+                       reg = <0x24E00 0xB0>;
+                       interrupts = <68 2 69 2 70 2 71 2>;
+                       interrupt-parent = < &mpic >;
+                       fsl,tclk-period = <5>;
+                       fsl,tmr-prsc = <200>;
+                       fsl,tmr-add = <0xAAAAAAAB>;
+                       fsl,tmr-fiper1 = <0x3B9AC9FB>;
+                       fsl,tmr-fiper2 = <0x3B9AC9FB>;
+                       fsl,max-adj = <499999999>;
+               };
+
                enet0: ethernet@24000 {
                        #address-cells = <1>;
                        #size-cells = <1>;
index 2bcf3683d223510ef2b7988c494af466c5dc8297..dae403100f2f8f798c2e81f02e4355d494efe57c 100644 (file)
 
                };
 
+               ptp_clock@24E00 {
+                       compatible = "fsl,etsec-ptp";
+                       reg = <0x24E00 0xB0>;
+                       interrupts = <68 2 69 2 70 2>;
+                       interrupt-parent = < &mpic >;
+                       fsl,tclk-period = <5>;
+                       fsl,tmr-prsc = <200>;
+                       fsl,tmr-add = <0xCCCCCCCD>;
+                       fsl,tmr-fiper1 = <0x3B9AC9FB>;
+                       fsl,tmr-fiper2 = <0x0001869B>;
+                       fsl,max-adj = <249999999>;
+               };
+
                enet0: ethernet@24000 {
                        tbi-handle = <&tbi0>;
                        phy-handle = <&phy0>;
index 3782a58f13beab7ac6adc4c0f80c0f844e8d4060..1d7a05f3021e058bd59eabb6fd049446accf7073 100644 (file)
                        status = "disabled";
                };
 
+               ptp_clock@24E00 {
+                       compatible = "fsl,etsec-ptp";
+                       reg = <0x24E00 0xB0>;
+                       interrupts = <68 2 69 2 70 2>;
+                       interrupt-parent = < &mpic >;
+                       fsl,tclk-period = <5>;
+                       fsl,tmr-prsc = <200>;
+                       fsl,tmr-add = <0xCCCCCCCD>;
+                       fsl,tmr-fiper1 = <0x3B9AC9FB>;
+                       fsl,tmr-fiper2 = <0x0001869B>;
+                       fsl,max-adj = <249999999>;
+               };
+
                enet0: ethernet@24000 {
                        fixed-link = <1 1 1000 0 0>;
                        phy-connection-type = "rgmii-id";
index 81636c01d90652d2bc9082a872c4ba1594a0ac5d..d86a3a4981182b5534f30e029c1b8824f3817792 100644 (file)
                                0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /* swizzled int D */>;
                };
 
+               MSI: ppc4xx-msi@400300000 {
+                               compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+                               reg = < 0x4 0x00300000 0x100
+                                       0x4 0x00300000 0x100>;
+                               sdr-base = <0x3B0>;
+                               msi-data = <0x00000000>;
+                               msi-mask = <0x44440000>;
+                               interrupt-count = <3>;
+                               interrupts =<0 1 2 3>;
+                               interrupt-parent = <&UIC0>;
+                               #interrupt-cells = <1>;
+                               #address-cells = <0>;
+                               #size-cells = <0>;
+                               interrupt-map = <0 &UIC0 0xC 1
+                                       1 &UIC0 0x0D 1
+                                       2 &UIC0 0x0E 1
+                                       3 &UIC0 0x0F 1>;
+               };
+
        };
 
+
        chosen {
                linux,stdout-path = "/plb/opb/serial@ef600200";
        };
index 7f7e4a8786029897df66ca0e49c64b2c6aa5065d..22e719575c60b33cb64cee5fcb840c2507f942c8 100644 (file)
@@ -85,7 +85,7 @@ CONFIG_USB_OHCI_HCD=m
 CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
 # CONFIG_USB_OHCI_HCD_PCI is not set
 CONFIG_USB_STORAGE=m
-CONFIG_RTC_CLASS=m
+CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_PCF8563=m
 CONFIG_EXT2_FS=m
 CONFIG_EXT3_FS=m
index 214208924a9c55be2a010471174461ea4d9aa3ee..04360f9b010939686b142791b7a24607d79e91c4 100644 (file)
@@ -10,7 +10,6 @@ CONFIG_TASK_XACCT=y
 CONFIG_TASK_IO_ACCOUNTING=y
 CONFIG_AUDIT=y
 CONFIG_CGROUPS=y
-CONFIG_CGROUP_NS=y
 CONFIG_CGROUP_DEVICE=y
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_RESOURCE_COUNTERS=y
index 6472322bf13b6820af3c364c1a994baebe914fbe..185c292b0f1c8cab6968420212c9690bc895e6b3 100644 (file)
@@ -141,7 +141,7 @@ CONFIG_USB_EHCI_TT_NEWSCHED=y
 # CONFIG_USB_EHCI_HCD_PPC_OF is not set
 CONFIG_USB_OHCI_HCD=m
 CONFIG_USB_STORAGE=m
-CONFIG_RTC_CLASS=m
+CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_PS3=m
 CONFIG_EXT2_FS=m
 CONFIG_EXT3_FS=m
index 7de13865508c689a76047ccedee63653330aa79d..c9f212b5f3ded98122423e13754ad40fe202e839 100644 (file)
@@ -15,7 +15,6 @@ CONFIG_AUDITSYSCALL=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_CGROUPS=y
-CONFIG_CGROUP_NS=y
 CONFIG_CGROUP_FREEZER=y
 CONFIG_CGROUP_DEVICE=y
 CONFIG_CPUSETS=y
index 5c1bf3466749563d2ee683b1a7c4dfef0903e0ea..8a0b5ece8f76f8e6152bfe0a7be812426c06ce95 100644 (file)
@@ -157,6 +157,8 @@ struct fsl_lbc_regs {
 #define LBCR_EPAR_SHIFT    16
 #define LBCR_BMT   0x0000FF00
 #define LBCR_BMT_SHIFT      8
+#define LBCR_BMTPS 0x0000000F
+#define LBCR_BMTPS_SHIFT    0
 #define LBCR_INIT  0x00040000
        __be32 lcrr;            /**< Clock Ratio Register */
 #define LCRR_DBYP    0x80000000
index dde1296b8b41a903dd2707f0d9465162efd36fbc..169d039ed402080720aef97c33e20952d28dad12 100644 (file)
@@ -60,4 +60,18 @@ struct dyn_arch_ftrace {
 
 #endif
 
+#if defined(CONFIG_FTRACE_SYSCALLS) && defined(CONFIG_PPC64) && !defined(__ASSEMBLY__)
+#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
+static inline bool arch_syscall_match_sym_name(const char *sym, const char *name)
+{
+       /*
+        * Compare the symbol name with the system call name. Skip the .sys or .SyS
+        * prefix from the symbol name and the sys prefix from the system call name and
+        * just match the rest. This is only needed on ppc64 since symbol names on
+        * 32bit do not start with a period so the generic function will work.
+        */
+       return !strcmp(sym + 4, name + 3);
+}
+#endif /* CONFIG_FTRACE_SYSCALLS && CONFIG_PPC64 && !__ASSEMBLY__ */
+
 #endif /* _ASM_POWERPC_FTRACE */
index 852b8c1c09db72672136347c19f181d194cb8e47..fd8201dddd4b738666b3f6efe7c785b5b50f4632 100644 (file)
 #define H_HOME_NODE_ASSOCIATIVITY 0x2EC
 #define H_BEST_ENERGY          0x2F4
 #define H_GET_MPP_X            0x314
-#define MAX_HCALL_OPCODE       H_BEST_ENERGY
+#define MAX_HCALL_OPCODE       H_GET_MPP_X
 
 #ifndef __ASSEMBLY__
 
index abe8532bd14e4dfc27693cfadce3d49a78380881..bf301ac62f35a0c1da1ed7b9cae0de43c95d0df0 100644 (file)
@@ -31,14 +31,29 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage)
 #endif
 
 #ifdef CONFIG_SMP
-extern void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift);
-extern void pte_free_finish(void);
+struct mmu_gather;
+extern void tlb_remove_table(struct mmu_gather *, void *);
+
+static inline void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int shift)
+{
+       unsigned long pgf = (unsigned long)table;
+       BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
+       pgf |= shift;
+       tlb_remove_table(tlb, (void *)pgf);
+}
+
+static inline void __tlb_remove_table(void *_table)
+{
+       void *table = (void *)((unsigned long)_table & ~MAX_PGTABLE_INDEX_SIZE);
+       unsigned shift = (unsigned long)_table & MAX_PGTABLE_INDEX_SIZE;
+
+       pgtable_free(table, shift);
+}
 #else /* CONFIG_SMP */
 static inline void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift)
 {
        pgtable_free(table, shift);
 }
-static inline void pte_free_finish(void) { }
 #endif /* !CONFIG_SMP */
 
 static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage,
index 0018bf80cb25d523562a6754cbec75a7eee63688..b1d2deceeedbc1f24030a302e2f190ff8929084b 100644 (file)
 #define ASM_PPC_RIO_H
 
 extern void platform_rio_init(void);
+#ifdef CONFIG_FSL_RIO
+extern int fsl_rio_mcheck_exception(struct pt_regs *);
+#else
+static inline int fsl_rio_mcheck_exception(struct pt_regs *regs) {return 0; }
+#endif
 
 #endif                         /* ASM_PPC_RIO_H */
index 880b8c1e6e537d0ee451d253894e96a123bd4a57..11eb404b5606c03c94b68189e3f32cb1859cd3dc 100644 (file)
@@ -191,8 +191,6 @@ extern unsigned long __secondary_hold_spinloop;
 extern unsigned long __secondary_hold_acknowledge;
 extern char __secondary_hold;
 
-extern irqreturn_t debug_ipi_action(int irq, void *data);
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/suspend.h b/arch/powerpc/include/asm/suspend.h
deleted file mode 100644 (file)
index c6efc34..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_POWERPC_SUSPEND_H
-#define __ASM_POWERPC_SUSPEND_H
-
-static inline int arch_prepare_suspend(void) { return 0; }
-
-#endif /* __ASM_POWERPC_SUSPEND_H */
index 23913e902fc3c50c4307514c159c53db9e7d004d..b54b2add07be99eb67a2a662231443063c8a996e 100644 (file)
 
 #include <linux/sched.h>
 
+/* ftrace syscalls requires exporting the sys_call_table */
+#ifdef CONFIG_FTRACE_SYSCALLS
+extern const unsigned long *sys_call_table;
+#endif /* CONFIG_FTRACE_SYSCALLS */
+
 static inline long syscall_get_nr(struct task_struct *task,
                                  struct pt_regs *regs)
 {
index 8489d372077fa4efebaaf0c1dae0b9730a37b8e6..f6736b7da463508e2b9777e851d2bdd2c597fec8 100644 (file)
@@ -353,3 +353,4 @@ COMPAT_SYS_SPU(open_by_handle_at)
 COMPAT_SYS_SPU(clock_adjtime)
 SYSCALL_SPU(syncfs)
 COMPAT_SYS_SPU(sendmmsg)
+SYSCALL_SPU(setns)
index d8529ef13b2329352a6b85a92adb2574ed768607..836f231ec1f0b2ed1301f383b75113ab352ba363 100644 (file)
@@ -110,7 +110,8 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_NOERROR            12      /* Force successful syscall return */
 #define TIF_NOTIFY_RESUME      13      /* callback before returning to user */
 #define TIF_FREEZE             14      /* Freezing for suspend */
-#define TIF_RUNLATCH           15      /* Is the runlatch enabled? */
+#define TIF_SYSCALL_TRACEPOINT 15      /* syscall tracepoint instrumentation */
+#define TIF_RUNLATCH           16      /* Is the runlatch enabled? */
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE     (1<<TIF_SYSCALL_TRACE)
@@ -127,8 +128,10 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_NOERROR           (1<<TIF_NOERROR)
 #define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
 #define _TIF_FREEZE            (1<<TIF_FREEZE)
+#define _TIF_SYSCALL_TRACEPOINT        (1<<TIF_SYSCALL_TRACEPOINT)
 #define _TIF_RUNLATCH          (1<<TIF_RUNLATCH)
-#define _TIF_SYSCALL_T_OR_A    (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP)
+#define _TIF_SYSCALL_T_OR_A    (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
+                                _TIF_SECCOMP | _TIF_SYSCALL_TRACEPOINT)
 
 #define _TIF_USER_WORK_MASK    (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
                                 _TIF_NOTIFY_RESUME)
@@ -139,10 +142,12 @@ static inline struct thread_info *current_thread_info(void)
 #define TLF_NAPPING            0       /* idle thread enabled NAP mode */
 #define TLF_SLEEPING           1       /* suspend code enabled SLEEP mode */
 #define TLF_RESTORE_SIGMASK    2       /* Restore signal mask in do_signal */
+#define TLF_LAZY_MMU           3       /* tlb_batch is active */
 
 #define _TLF_NAPPING           (1 << TLF_NAPPING)
 #define _TLF_SLEEPING          (1 << TLF_SLEEPING)
 #define _TLF_RESTORE_SIGMASK   (1 << TLF_RESTORE_SIGMASK)
+#define _TLF_LAZY_MMU          (1 << TLF_LAZY_MMU)
 
 #ifndef __ASSEMBLY__
 #define HAVE_SET_RESTORE_SIGMASK       1
index 6d23c8193caa246a39b2285240d0727fa7d19980..b8b3f599362b70167ab8db7c49038ad08f2b02f2 100644 (file)
 #define __NR_clock_adjtime     347
 #define __NR_syncfs            348
 #define __NR_sendmmsg          349
+#define __NR_setns             350
 
 #ifdef __KERNEL__
 
-#define __NR_syscalls          350
+#define __NR_syscalls          351
 
 #define __NR__exit __NR_exit
 #define NR_syscalls    __NR_syscalls
index 9aab363125724721e94a339413d1c6a5135b70e1..e8b981897d44a268041cc07d7368b1952cd62cfe 100644 (file)
@@ -109,6 +109,7 @@ obj-$(CONFIG_PPC_IO_WORKAROUNDS)    += io-workarounds.o
 
 obj-$(CONFIG_DYNAMIC_FTRACE)   += ftrace.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)    += ftrace.o
+obj-$(CONFIG_FTRACE_SYSCALLS)  += ftrace.o
 obj-$(CONFIG_PERF_EVENTS)      += perf_callchain.o
 
 obj-$(CONFIG_PPC_PERF_CTRS)    += perf_event.o
index 34d2722b9451f816b08405549a691d421ae7d81a..9fb933248ab69fe2272f447d1b286407dee5d195 100644 (file)
@@ -1979,7 +1979,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .pvr_value              = 0x80240000,
                .cpu_name               = "e5500",
                .cpu_features           = CPU_FTRS_E5500,
-               .cpu_user_features      = COMMON_USER_BOOKE,
+               .cpu_user_features      = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
                .mmu_features           = MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS |
                        MMU_FTR_USE_TLBILX,
                .icache_bsize           = 64,
index ce1f3e44c24fabf07408fd3e0ed70919a3828cb3..bf99cfa6bbfe3a29240094eb5fe2db695ed78e66 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/cacheflush.h>
 #include <asm/code-patching.h>
 #include <asm/ftrace.h>
+#include <asm/syscall.h>
 
 
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -600,3 +601,10 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
        }
 }
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+#if defined(CONFIG_FTRACE_SYSCALLS) && defined(CONFIG_PPC64)
+unsigned long __init arch_syscall_addr(int nr)
+{
+       return sys_call_table[nr*2];
+}
+#endif /* CONFIG_FTRACE_SYSCALLS && CONFIG_PPC64 */
index a24d37d4cf5158e17ad85421a1bee6d1af14e299..5b428e3086662bcc802f9ce5049ada0c92aefa63 100644 (file)
@@ -295,17 +295,20 @@ static inline void handle_one_irq(unsigned int irq)
        unsigned long saved_sp_limit;
        struct irq_desc *desc;
 
+       desc = irq_to_desc(irq);
+       if (!desc)
+               return;
+
        /* Switch to the irq stack to handle this */
        curtp = current_thread_info();
        irqtp = hardirq_ctx[smp_processor_id()];
 
        if (curtp == irqtp) {
                /* We're already on the irq stack, just handle it */
-               generic_handle_irq(irq);
+               desc->handle_irq(irq, desc);
                return;
        }
 
-       desc = irq_to_desc(irq);
        saved_sp_limit = current->thread.ksp_limit;
 
        irqtp->task = curtp->task;
@@ -557,15 +560,8 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
        if (revmap_type == IRQ_HOST_MAP_LEGACY) {
                if (irq_map[0].host != NULL) {
                        raw_spin_unlock_irqrestore(&irq_big_lock, flags);
-                       /* If we are early boot, we can't free the structure,
-                        * too bad...
-                        * this will be fixed once slab is made available early
-                        * instead of the current cruft
-                        */
-                       if (mem_init_done) {
-                               of_node_put(host->of_node);
-                               kfree(host);
-                       }
+                       of_node_put(host->of_node);
+                       kfree(host);
                        return NULL;
                }
                irq_map[0].host = host;
@@ -727,9 +723,7 @@ unsigned int irq_create_mapping(struct irq_host *host,
        }
        pr_debug("irq: -> using host @%p\n", host);
 
-       /* Check if mapping already exist, if it does, call
-        * host->ops->map() to update the flags
-        */
+       /* Check if mapping already exists */
        virq = irq_find_mapping(host, hwirq);
        if (virq != NO_IRQ) {
                pr_debug("irq: -> existing mapping on virq %d\n", virq);
@@ -899,10 +893,13 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host,
                return irq_find_mapping(host, hwirq);
 
        /*
-        * No rcu_read_lock(ing) needed, the ptr returned can't go under us
-        * as it's referencing an entry in the static irq_map table.
+        * The ptr returned references the static global irq_map.
+        * but freeing an irq can delete nodes along the path to
+        * do the lookup via call_rcu.
         */
+       rcu_read_lock();
        ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq);
+       rcu_read_unlock();
 
        /*
         * If found in radix tree, then fine.
@@ -1010,14 +1007,23 @@ void irq_free_virt(unsigned int virq, unsigned int count)
        WARN_ON (virq < NUM_ISA_INTERRUPTS);
        WARN_ON (count == 0 || (virq + count) > irq_virq_count);
 
+       if (virq < NUM_ISA_INTERRUPTS) {
+               if (virq + count < NUM_ISA_INTERRUPTS)
+                       return;
+               count  =- NUM_ISA_INTERRUPTS - virq;
+               virq = NUM_ISA_INTERRUPTS;
+       }
+
+       if (count > irq_virq_count || virq > irq_virq_count - count) {
+               if (virq > irq_virq_count)
+                       return;
+               count = irq_virq_count - virq;
+       }
+
        raw_spin_lock_irqsave(&irq_big_lock, flags);
        for (i = virq; i < (virq + count); i++) {
                struct irq_host *host;
 
-               if (i < NUM_ISA_INTERRUPTS ||
-                   (virq + count) > irq_virq_count)
-                       continue;
-
                host = irq_map[i].host;
                irq_map[i].hwirq = host->inval_irq;
                smp_wmb();
index 095043d79946cfbfd8c9f15e56584ef393192456..91e52df3d81d19ec7a22bba96fee3ea2d12b4002 100644 (file)
@@ -395,6 +395,9 @@ struct task_struct *__switch_to(struct task_struct *prev,
        struct thread_struct *new_thread, *old_thread;
        unsigned long flags;
        struct task_struct *last;
+#ifdef CONFIG_PPC_BOOK3S_64
+       struct ppc64_tlb_batch *batch;
+#endif
 
 #ifdef CONFIG_SMP
        /* avoid complexity of lazy save/restore of fpu
@@ -513,7 +516,17 @@ struct task_struct *__switch_to(struct task_struct *prev,
                old_thread->accum_tb += (current_tb - start_tb);
                new_thread->start_tb = current_tb;
        }
-#endif
+#endif /* CONFIG_PPC64 */
+
+#ifdef CONFIG_PPC_BOOK3S_64
+       batch = &__get_cpu_var(ppc64_tlb_batch);
+       if (batch->active) {
+               current_thread_info()->local_flags |= _TLF_LAZY_MMU;
+               if (batch->index)
+                       __flush_tlb_pending(batch);
+               batch->active = 0;
+       }
+#endif /* CONFIG_PPC_BOOK3S_64 */
 
        local_irq_save(flags);
 
@@ -528,6 +541,14 @@ struct task_struct *__switch_to(struct task_struct *prev,
        hard_irq_disable();
        last = _switch(old_thread, new_thread);
 
+#ifdef CONFIG_PPC_BOOK3S_64
+       if (current_thread_info()->local_flags & _TLF_LAZY_MMU) {
+               current_thread_info()->local_flags &= ~_TLF_LAZY_MMU;
+               batch = &__get_cpu_var(ppc64_tlb_batch);
+               batch->active = 1;
+       }
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
        local_irq_restore(flags);
 
        return last;
index 48aeb55faae9b806363317493800521ad8e2ec57..8c3112a57cf25ec751a118d8550bc95ed4c92575 100644 (file)
@@ -82,11 +82,29 @@ static int __init early_parse_mem(char *p)
 }
 early_param("mem", early_parse_mem);
 
+/*
+ * overlaps_initrd - check for overlap with page aligned extension of
+ * initrd.
+ */
+static inline int overlaps_initrd(unsigned long start, unsigned long size)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (!initrd_start)
+               return 0;
+
+       return  (start + size) > _ALIGN_DOWN(initrd_start, PAGE_SIZE) &&
+                       start <= _ALIGN_UP(initrd_end, PAGE_SIZE);
+#else
+       return 0;
+#endif
+}
+
 /**
  * move_device_tree - move tree to an unused area, if needed.
  *
  * The device tree may be allocated beyond our memory limit, or inside the
- * crash kernel region for kdump. If so, move it out of the way.
+ * crash kernel region for kdump, or within the page aligned range of initrd.
+ * If so, move it out of the way.
  */
 static void __init move_device_tree(void)
 {
@@ -99,7 +117,8 @@ static void __init move_device_tree(void)
        size = be32_to_cpu(initial_boot_params->totalsize);
 
        if ((memory_limit && (start + size) > PHYSICAL_START + memory_limit) ||
-                       overlaps_crashkernel(start, size)) {
+                       overlaps_crashkernel(start, size) ||
+                       overlaps_initrd(start, size)) {
                p = __va(memblock_alloc(size, PAGE_SIZE));
                memcpy(p, initial_boot_params, size);
                initial_boot_params = (struct boot_param_header *)p;
@@ -555,7 +574,9 @@ static void __init early_reserve_mem(void)
 #ifdef CONFIG_BLK_DEV_INITRD
        /* then reserve the initrd, if any */
        if (initrd_start && (initrd_end > initrd_start))
-               memblock_reserve(__pa(initrd_start), initrd_end - initrd_start);
+               memblock_reserve(_ALIGN_DOWN(__pa(initrd_start), PAGE_SIZE),
+                       _ALIGN_UP(initrd_end, PAGE_SIZE) -
+                       _ALIGN_DOWN(initrd_start, PAGE_SIZE));
 #endif /* CONFIG_BLK_DEV_INITRD */
 
 #ifdef CONFIG_PPC32
@@ -694,7 +715,7 @@ void __init early_init_devtree(void *params)
         * device-tree, including the platform type, initrd location and
         * size, TCE reserve, and more ...
         */
-       of_scan_flat_dt(early_init_dt_scan_chosen_ppc, NULL);
+       of_scan_flat_dt(early_init_dt_scan_chosen_ppc, cmd_line);
 
        /* Scan memory nodes and rebuild MEMBLOCKs */
        memblock_init();
index a6ae1cfad86ce86040553fa94346ad2043c3a0bb..cb22024f2b42a189d9848978ac3dafd1c611f19f 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/signal.h>
 #include <linux/seccomp.h>
 #include <linux/audit.h>
+#include <trace/syscall.h>
 #ifdef CONFIG_PPC32
 #include <linux/module.h>
 #endif
@@ -40,6 +41,9 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/syscalls.h>
+
 /*
  * The parameter save area on the stack is used to store arguments being passed
  * to callee function and is located at fixed offset from stack pointer.
@@ -1710,6 +1714,9 @@ long do_syscall_trace_enter(struct pt_regs *regs)
                 */
                ret = -1L;
 
+       if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
+               trace_sys_enter(regs, regs->gpr[0]);
+
        if (unlikely(current->audit_context)) {
 #ifdef CONFIG_PPC64
                if (!is_32bit_task())
@@ -1738,6 +1745,9 @@ void do_syscall_trace_leave(struct pt_regs *regs)
                audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
                                   regs->result);
 
+       if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
+               trace_sys_exit(regs, regs->result);
+
        step = test_thread_flag(TIF_SINGLESTEP);
        if (step || test_thread_flag(TIF_SYSCALL_TRACE))
                tracehook_report_syscall_exit(regs, step);
index 4a6f2ec7e761d89e07bc73967eef323fa77788de..8ebc6700b98d18769f6e8afd1eb54f9f0363ec58 100644 (file)
@@ -129,7 +129,7 @@ static irqreturn_t call_function_single_action(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-irqreturn_t debug_ipi_action(int irq, void *data)
+static irqreturn_t debug_ipi_action(int irq, void *data)
 {
        if (crash_ipi_function_ptr) {
                crash_ipi_function_ptr(get_irq_regs());
index 560c961195015d39b0f62296f48413f27f394f0f..aa17b76dd42799375ce954490526b00e5262de06 100644 (file)
@@ -10,7 +10,6 @@
  */
 
 #include <linux/sched.h>
-#include <asm/suspend.h>
 #include <asm/system.h>
 #include <asm/current.h>
 #include <asm/mmu_context.h>
index b13306b0d9259ffa27b5d9d906e9ece0e9a42de9..0ff4ab98d50ca713f1c8a983349aa2369fcad22e 100644 (file)
@@ -55,6 +55,7 @@
 #endif
 #include <asm/kexec.h>
 #include <asm/ppc-opcode.h>
+#include <asm/rio.h>
 
 #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
 int (*__debugger)(struct pt_regs *regs) __read_mostly;
@@ -424,6 +425,12 @@ int machine_check_e500mc(struct pt_regs *regs)
        unsigned long reason = mcsr;
        int recoverable = 1;
 
+       if (reason & MCSR_BUS_RBERR) {
+               recoverable = fsl_rio_mcheck_exception(regs);
+               if (recoverable == 1)
+                       goto silent_out;
+       }
+
        printk("Machine check in kernel mode.\n");
        printk("Caused by (from MCSR=%lx): ", reason);
 
@@ -499,6 +506,7 @@ int machine_check_e500mc(struct pt_regs *regs)
                       reason & MCSR_MEA ? "Effective" : "Physical", addr);
        }
 
+silent_out:
        mtspr(SPRN_MCSR, mcsr);
        return mfspr(SPRN_MCSR) == 0 && recoverable;
 }
@@ -507,6 +515,11 @@ int machine_check_e500(struct pt_regs *regs)
 {
        unsigned long reason = get_mc_reason(regs);
 
+       if (reason & MCSR_BUS_RBERR) {
+               if (fsl_rio_mcheck_exception(regs))
+                       return 1;
+       }
+
        printk("Machine check in kernel mode.\n");
        printk("Caused by (from MCSR=%lx): ", reason);
 
index b9150f07d2664a9a763ebeda3564b1c08f18fb17..920276c0f6a1d47396451a5a3e9ac0d71d8b3c4c 100644 (file)
@@ -160,7 +160,7 @@ SECTIONS
                INIT_RAM_FS
        }
 
-       PERCPU(L1_CACHE_BYTES, PAGE_SIZE)
+       PERCPU_SECTION(L1_CACHE_BYTES)
 
        . = ALIGN(8);
        .machine.desc : AT(ADDR(.machine.desc) - LOAD_OFFSET) {
index d65b591e5556bd01a4ee4bb7b5238b43ee389f6a..5de0f254dbb5cb38fc39b2879fd2f6c40e36c3c6 100644 (file)
@@ -223,21 +223,6 @@ void free_initmem(void)
 #undef FREESEC
 }
 
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       if (start < end)
-               printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
-       for (; start < end; start += PAGE_SIZE) {
-               ClearPageReserved(virt_to_page(start));
-               init_page_count(virt_to_page(start));
-               free_page(start);
-               totalram_pages++;
-       }
-}
-#endif
-
-
 #ifdef CONFIG_8xx /* No 8xx specific .c file to put that in ... */
 void setup_initial_memory_limit(phys_addr_t first_memblock_base,
                                phys_addr_t first_memblock_size)
index 6374b2196a17a33b97589fb8097fc0c00a1f176b..f6dbb4c20e645ad071d87e6f5244c214e565e667 100644 (file)
@@ -99,20 +99,6 @@ void free_initmem(void)
                ((unsigned long)__init_end - (unsigned long)__init_begin) >> 10);
 }
 
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       if (start < end)
-               printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
-       for (; start < end; start += PAGE_SIZE) {
-               ClearPageReserved(virt_to_page(start));
-               init_page_count(virt_to_page(start));
-               free_page(start);
-               totalram_pages++;
-       }
-}
-#endif
-
 static void pgd_ctor(void *addr)
 {
        memset(addr, 0, PGD_TABLE_SIZE);
index 57e545b84bf199cb8db2b2fbefa0d4755a419394..29d4dde65c45f9b6f075d2d575fac1d05e2bbdc7 100644 (file)
@@ -382,6 +382,25 @@ void __init mem_init(void)
        mem_init_done = 1;
 }
 
+#ifdef CONFIG_BLK_DEV_INITRD
+void __init free_initrd_mem(unsigned long start, unsigned long end)
+{
+       if (start >= end)
+               return;
+
+       start = _ALIGN_DOWN(start, PAGE_SIZE);
+       end = _ALIGN_UP(end, PAGE_SIZE);
+       pr_info("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+
+       for (; start < end; start += PAGE_SIZE) {
+               ClearPageReserved(virt_to_page(start));
+               init_page_count(virt_to_page(start));
+               free_page(start);
+               totalram_pages++;
+       }
+}
+#endif
+
 /*
  * This is called when a page has been modified by the kernel.
  * It just marks the page as not i-cache clean.  We do the i-cache
index 6a3997f98dfb90a2f3d01da4b53156c2098a38f8..af40c8768a7824095878c475791053987ed57c4d 100644 (file)
 
 #include "mmu_decl.h"
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
-#ifdef CONFIG_SMP
-
-/*
- * Handle batching of page table freeing on SMP. Page tables are
- * queued up and send to be freed later by RCU in order to avoid
- * freeing a page table page that is being walked without locks
- */
-
-static DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
-static unsigned long pte_freelist_forced_free;
-
-struct pte_freelist_batch
-{
-       struct rcu_head rcu;
-       unsigned int    index;
-       unsigned long   tables[0];
-};
-
-#define PTE_FREELIST_SIZE \
-       ((PAGE_SIZE - sizeof(struct pte_freelist_batch)) \
-         / sizeof(unsigned long))
-
-static void pte_free_smp_sync(void *arg)
-{
-       /* Do nothing, just ensure we sync with all CPUs */
-}
-
-/* This is only called when we are critically out of memory
- * (and fail to get a page in pte_free_tlb).
- */
-static void pgtable_free_now(void *table, unsigned shift)
-{
-       pte_freelist_forced_free++;
-
-       smp_call_function(pte_free_smp_sync, NULL, 1);
-
-       pgtable_free(table, shift);
-}
-
-static void pte_free_rcu_callback(struct rcu_head *head)
-{
-       struct pte_freelist_batch *batch =
-               container_of(head, struct pte_freelist_batch, rcu);
-       unsigned int i;
-
-       for (i = 0; i < batch->index; i++) {
-               void *table = (void *)(batch->tables[i] & ~MAX_PGTABLE_INDEX_SIZE);
-               unsigned shift = batch->tables[i] & MAX_PGTABLE_INDEX_SIZE;
-
-               pgtable_free(table, shift);
-       }
-
-       free_page((unsigned long)batch);
-}
-
-static void pte_free_submit(struct pte_freelist_batch *batch)
-{
-       call_rcu_sched(&batch->rcu, pte_free_rcu_callback);
-}
-
-void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift)
-{
-       /* This is safe since tlb_gather_mmu has disabled preemption */
-       struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
-       unsigned long pgf;
-
-       if (atomic_read(&tlb->mm->mm_users) < 2 ||
-           cpumask_equal(mm_cpumask(tlb->mm), cpumask_of(smp_processor_id()))){
-               pgtable_free(table, shift);
-               return;
-       }
-
-       if (*batchp == NULL) {
-               *batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC);
-               if (*batchp == NULL) {
-                       pgtable_free_now(table, shift);
-                       return;
-               }
-               (*batchp)->index = 0;
-       }
-       BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
-       pgf = (unsigned long)table | shift;
-       (*batchp)->tables[(*batchp)->index++] = pgf;
-       if ((*batchp)->index == PTE_FREELIST_SIZE) {
-               pte_free_submit(*batchp);
-               *batchp = NULL;
-       }
-}
-
-void pte_free_finish(void)
-{
-       /* This is safe since tlb_gather_mmu has disabled preemption */
-       struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
-
-       if (*batchp == NULL)
-               return;
-       pte_free_submit(*batchp);
-       *batchp = NULL;
-}
-
-#endif /* CONFIG_SMP */
-
 static inline int is_exec_fault(void)
 {
        return current->thread.regs && TRAP(current->thread.regs) == 0x400;
index 690566b66e8ea233cd0f40f4850d6ad8f1bc307d..27b863c14941a9406ced93e2f534825171d2bf85 100644 (file)
@@ -71,9 +71,6 @@ void tlb_flush(struct mmu_gather *tlb)
                 */
                _tlbia();
        }
-
-       /* Push out batch of freed page tables */
-       pte_free_finish();
 }
 
 /*
index c14d09f614f362ef67e04744bc5db8f62b8947cc..31f18207970ba6aa01d7370784bf2d810465f413 100644 (file)
@@ -155,7 +155,7 @@ void __flush_tlb_pending(struct ppc64_tlb_batch *batch)
 
 void tlb_flush(struct mmu_gather *tlb)
 {
-       struct ppc64_tlb_batch *tlbbatch = &__get_cpu_var(ppc64_tlb_batch);
+       struct ppc64_tlb_batch *tlbbatch = &get_cpu_var(ppc64_tlb_batch);
 
        /* If there's a TLB batch pending, then we must flush it because the
         * pages are going to be freed and we really don't want to have a CPU
@@ -164,8 +164,7 @@ void tlb_flush(struct mmu_gather *tlb)
        if (tlbbatch->index)
                __flush_tlb_pending(tlbbatch);
 
-       /* Push out batch of freed page tables */
-       pte_free_finish();
+       put_cpu_var(ppc64_tlb_batch);
 }
 
 /**
index 2a030d89bbc6e65a847a29f6c4bf012f2e6188b0..0bdad3aecc670aa6379adc093cdb49054322a1a0 100644 (file)
@@ -299,9 +299,6 @@ EXPORT_SYMBOL(flush_tlb_range);
 void tlb_flush(struct mmu_gather *tlb)
 {
        flush_tlb_mm(tlb->mm);
-
-       /* Push out batch of freed page tables */
-       pte_free_finish();
 }
 
 /*
index 8ee51a252cf1b28bb11c1f023b395067e0b90db4..e6bec74be131246b5ee3d1bce119d9a01c97f51d 100644 (file)
@@ -261,6 +261,28 @@ static int get_kernel(unsigned long pc, unsigned long mmcra)
        return is_kernel;
 }
 
+static bool pmc_overflow(unsigned long val)
+{
+       if ((int)val < 0)
+               return true;
+
+       /*
+        * Events on POWER7 can roll back if a speculative event doesn't
+        * eventually complete. Unfortunately in some rare cases they will
+        * raise a performance monitor exception. We need to catch this to
+        * ensure we reset the PMC. In all cases the PMC will be 256 or less
+        * cycles from overflow.
+        *
+        * We only do this if the first pass fails to find any overflowing
+        * PMCs because a user might set a period of less than 256 and we
+        * don't want to mistakenly reset them.
+        */
+       if (__is_processor(PV_POWER7) && ((0x80000000 - val) <= 256))
+               return true;
+
+       return false;
+}
+
 static void power4_handle_interrupt(struct pt_regs *regs,
                                    struct op_counter_config *ctr)
 {
@@ -281,7 +303,7 @@ static void power4_handle_interrupt(struct pt_regs *regs,
 
        for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) {
                val = classic_ctr_read(i);
-               if (val < 0) {
+               if (pmc_overflow(val)) {
                        if (oprofile_running && ctr[i].enabled) {
                                oprofile_add_ext_sample(pc, regs, i, is_kernel);
                                classic_ctr_write(i, reset_value[i]);
index b72176434ebe1aa62f7246bf1661ecb84e89f1fd..d733d7ca939c476e69be1994277460b216138175 100644 (file)
@@ -57,6 +57,8 @@ config KILAUEA
        select 405EX
        select PPC40x_SIMPLE
        select PPC4xx_PCI_EXPRESS
+       select PCI_MSI
+       select PPC4xx_MSI
        help
          This option enables support for the AMCC PPC405EX evaluation board.
 
index f485fc5f6d5e64a37913592701ca51d37381d6f7..e958b6f48ec283073e678bb8fdf815ae3bdcdea0 100644 (file)
@@ -74,6 +74,8 @@ config KATMAI
        select 440SPe
        select PCI
        select PPC4xx_PCI_EXPRESS
+       select PCI_MSI
+       select PCC4xx_MSI
        help
          This option enables support for the AMCC PPC440SPe evaluation board.
 
@@ -118,6 +120,8 @@ config CANYONLANDS
        select 460EX
        select PCI
        select PPC4xx_PCI_EXPRESS
+       select PCI_MSI
+       select PPC4xx_MSI
        select IBM_NEW_EMAC_RGMII
        select IBM_NEW_EMAC_ZMII
        help
@@ -144,6 +148,8 @@ config REDWOOD
        select 460SX
        select PCI
        select PPC4xx_PCI_EXPRESS
+       select PCI_MSI
+       select PPC4xx_MSI
        help
          This option enables support for the AMCC PPC460SX Redwood board.
 
index 449c08c1586231b958b968128e5707125440163c..3e4eba603e6b6162fbbdb71679f2f37656dbd40a 100644 (file)
@@ -176,14 +176,14 @@ EXPORT_SYMBOL_GPL(iic_get_target_id);
 #ifdef CONFIG_SMP
 
 /* Use the highest interrupt priorities for IPI */
-static inline int iic_ipi_to_irq(int ipi)
+static inline int iic_msg_to_irq(int msg)
 {
-       return IIC_IRQ_TYPE_IPI + 0xf - ipi;
+       return IIC_IRQ_TYPE_IPI + 0xf - msg;
 }
 
-void iic_cause_IPI(int cpu, int mesg)
+void iic_message_pass(int cpu, int msg)
 {
-       out_be64(&per_cpu(cpu_iic, cpu).regs->generate, (0xf - mesg) << 4);
+       out_be64(&per_cpu(cpu_iic, cpu).regs->generate, (0xf - msg) << 4);
 }
 
 struct irq_host *iic_get_irq_host(int node)
@@ -192,50 +192,31 @@ struct irq_host *iic_get_irq_host(int node)
 }
 EXPORT_SYMBOL_GPL(iic_get_irq_host);
 
-static irqreturn_t iic_ipi_action(int irq, void *dev_id)
-{
-       int ipi = (int)(long)dev_id;
-
-       switch(ipi) {
-       case PPC_MSG_CALL_FUNCTION:
-               generic_smp_call_function_interrupt();
-               break;
-       case PPC_MSG_RESCHEDULE:
-               scheduler_ipi();
-               break;
-       case PPC_MSG_CALL_FUNC_SINGLE:
-               generic_smp_call_function_single_interrupt();
-               break;
-       case PPC_MSG_DEBUGGER_BREAK:
-               debug_ipi_action(0, NULL);
-               break;
-       }
-       return IRQ_HANDLED;
-}
-static void iic_request_ipi(int ipi, const char *name)
+static void iic_request_ipi(int msg)
 {
        int virq;
 
-       virq = irq_create_mapping(iic_host, iic_ipi_to_irq(ipi));
+       virq = irq_create_mapping(iic_host, iic_msg_to_irq(msg));
        if (virq == NO_IRQ) {
                printk(KERN_ERR
-                      "iic: failed to map IPI %s\n", name);
+                      "iic: failed to map IPI %s\n", smp_ipi_name[msg]);
                return;
        }
-       if (request_irq(virq, iic_ipi_action, IRQF_DISABLED, name,
-                       (void *)(long)ipi))
-               printk(KERN_ERR
-                      "iic: failed to request IPI %s\n", name);
+
+       /*
+        * If smp_request_message_ipi encounters an error it will notify
+        * the error.  If a message is not needed it will return non-zero.
+        */
+       if (smp_request_message_ipi(virq, msg))
+               irq_dispose_mapping(virq);
 }
 
 void iic_request_IPIs(void)
 {
-       iic_request_ipi(PPC_MSG_CALL_FUNCTION, "IPI-call");
-       iic_request_ipi(PPC_MSG_RESCHEDULE, "IPI-resched");
-       iic_request_ipi(PPC_MSG_CALL_FUNC_SINGLE, "IPI-call-single");
-#ifdef CONFIG_DEBUGGER
-       iic_request_ipi(PPC_MSG_DEBUGGER_BREAK, "IPI-debug");
-#endif /* CONFIG_DEBUGGER */
+       iic_request_ipi(PPC_MSG_CALL_FUNCTION);
+       iic_request_ipi(PPC_MSG_RESCHEDULE);
+       iic_request_ipi(PPC_MSG_CALL_FUNC_SINGLE);
+       iic_request_ipi(PPC_MSG_DEBUGGER_BREAK);
 }
 
 #endif /* CONFIG_SMP */
index 942dc39d604559f4d1d58da68759a280dad968e7..4f60ae6ca358aa769fdd1976960d126a51a4ba9c 100644 (file)
@@ -75,7 +75,7 @@ enum {
 };
 
 extern void iic_init_IRQ(void);
-extern void iic_cause_IPI(int cpu, int mesg);
+extern void iic_message_pass(int cpu, int msg);
 extern void iic_request_IPIs(void);
 extern void iic_setup_cpu(void);
 
index d176e6148e3f2597a872ee572cf9512226a10c07..dbb641ea90dd6105324ad53844cee8b800c594ce 100644 (file)
@@ -152,7 +152,7 @@ static int smp_cell_cpu_bootable(unsigned int nr)
        return 1;
 }
 static struct smp_ops_t bpa_iic_smp_ops = {
-       .message_pass   = iic_cause_IPI,
+       .message_pass   = iic_message_pass,
        .probe          = smp_iic_probe,
        .kick_cpu       = smp_cell_kick_cpu,
        .setup_cpu      = smp_cell_setup_cpu,
index 9089b04211919506cb1a443025d0f058d5deff3c..7667db448aa73cc58aacaf72e74fa0c5a2339fc6 100644 (file)
@@ -715,7 +715,8 @@ static struct syscore_ops pmacpic_syscore_ops = {
 
 static int __init init_pmacpic_syscore(void)
 {
-       register_syscore_ops(&pmacpic_syscore_ops);
+       if (pmac_irq_hw[0])
+               register_syscore_ops(&pmacpic_syscore_ops);
        return 0;
 }
 
index d775fd148d13760b9b3a9f97a31049a0734c00af..7b4df37ac381edab99725c0ad9a4037d229d369f 100644 (file)
@@ -7,11 +7,18 @@ config PPC4xx_PCI_EXPRESS
        depends on PCI && 4xx
        default n
 
+config PPC4xx_MSI
+       bool
+       depends on PCI_MSI
+       depends on PCI && 4xx
+       default n
+
 config PPC_MSI_BITMAP
        bool
        depends on PCI_MSI
        default y if MPIC
        default y if FSL_PCI
+       default y if PPC4xx_MSI
 
 source "arch/powerpc/sysdev/xics/Kconfig"
 
index 6076e0074a870497ae138e7674958f605d3fc11b..0efa990e3344947d74df4c2806187fd1a0d2b7b7 100644 (file)
@@ -41,6 +41,7 @@ obj-$(CONFIG_OF_RTC)          += of_rtc.o
 ifeq ($(CONFIG_PCI),y)
 obj-$(CONFIG_4xx)              += ppc4xx_pci.o
 endif
+obj-$(CONFIG_PPC4xx_MSI)       += ppc4xx_msi.o
 obj-$(CONFIG_PPC4xx_CPM)       += ppc4xx_cpm.o
 obj-$(CONFIG_PPC4xx_GPIO)      += ppc4xx_gpio.o
 
index 4fcb5a4e60dddaeca9143a79c2ebb61a581d3be6..d917573cf1a854183d425053b479ed6423ae0c3c 100644 (file)
@@ -184,7 +184,8 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
 }
 EXPORT_SYMBOL(fsl_upm_run_pattern);
 
-static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl)
+static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl,
+                                      struct device_node *node)
 {
        struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
 
@@ -195,8 +196,9 @@ static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl)
        out_be32(&lbc->lteccr, LTECCR_CLEAR);
        out_be32(&lbc->ltedr, LTEDR_ENABLE);
 
-       /* Enable interrupts for any detected events */
-       out_be32(&lbc->lteir, LTEIR_ENABLE);
+       /* Set the monitor timeout value to the maximum for erratum A001 */
+       if (of_device_is_compatible(node, "fsl,elbc"))
+               clrsetbits_be32(&lbc->lbcr, LBCR_BMT, LBCR_BMTPS);
 
        return 0;
 }
@@ -304,7 +306,7 @@ static int __devinit fsl_lbc_ctrl_probe(struct platform_device *dev)
 
        fsl_lbc_ctrl_dev->dev = &dev->dev;
 
-       ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev);
+       ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev, dev->dev.of_node);
        if (ret < 0)
                goto err;
 
@@ -317,6 +319,9 @@ static int __devinit fsl_lbc_ctrl_probe(struct platform_device *dev)
                goto err;
        }
 
+       /* Enable interrupts for any detected events */
+       out_be32(&fsl_lbc_ctrl_dev->regs->lteir, LTEIR_ENABLE);
+
        return 0;
 
 err:
index 49798532b477b8630c77a203dfb76c62ad3caf46..5b206a2fe17c47653632e516051984746ad2d587 100644 (file)
@@ -10,7 +10,7 @@
  * - Added Port-Write message handling
  * - Added Machine Check exception handling
  *
- * Copyright (C) 2007, 2008 Freescale Semiconductor, Inc.
+ * Copyright (C) 2007, 2008, 2010 Freescale Semiconductor, Inc.
  * Zhang Wei <wei.zhang@freescale.com>
  *
  * Copyright 2005 MontaVista Software, Inc.
 #define IRQ_RIO_RX(m)          (((struct rio_priv *)(m->priv))->rxirq)
 #define IRQ_RIO_PW(m)          (((struct rio_priv *)(m->priv))->pwirq)
 
+#define IPWSR_CLEAR            0x98
+#define OMSR_CLEAR             0x1cb3
+#define IMSR_CLEAR             0x491
+#define IDSR_CLEAR             0x91
+#define ODSR_CLEAR             0x1c00
+#define LTLEECSR_ENABLE_ALL    0xFFC000FC
+#define ESCSR_CLEAR            0x07120204
+
+#define RIO_PORT1_EDCSR                0x0640
+#define RIO_PORT2_EDCSR                0x0680
+#define RIO_PORT1_IECSR                0x10130
+#define RIO_PORT2_IECSR                0x101B0
+#define RIO_IM0SR              0x13064
+#define RIO_IM1SR              0x13164
+#define RIO_OM0SR              0x13004
+#define RIO_OM1SR              0x13104
+
 #define RIO_ATMU_REGS_OFFSET   0x10c00
 #define RIO_P_MSG_REGS_OFFSET  0x11000
 #define RIO_S_MSG_REGS_OFFSET  0x13000
 #define RIO_GCCSR              0x13c
 #define RIO_ESCSR              0x158
+#define RIO_PORT2_ESCSR                0x178
 #define RIO_CCSR               0x15c
 #define RIO_LTLEDCSR           0x0608
-#define  RIO_LTLEDCSR_IER      0x80000000
-#define  RIO_LTLEDCSR_PRT      0x01000000
+#define RIO_LTLEDCSR_IER       0x80000000
+#define RIO_LTLEDCSR_PRT       0x01000000
 #define RIO_LTLEECSR           0x060c
 #define RIO_EPWISR             0x10010
 #define RIO_ISR_AACR           0x10120
 #define RIO_IPWSR_PWD          0x00000008
 #define RIO_IPWSR_PWB          0x00000004
 
-#define RIO_EPWISR_PINT                0x80000000
+/* EPWISR Error match value */
+#define RIO_EPWISR_PINT1       0x80000000
+#define RIO_EPWISR_PINT2       0x40000000
+#define RIO_EPWISR_MU          0x00000002
 #define RIO_EPWISR_PW          0x00000001
 
 #define RIO_MSG_DESC_SIZE      32
@@ -260,9 +281,7 @@ struct rio_priv {
 static void __iomem *rio_regs_win;
 
 #ifdef CONFIG_E500
-static int (*saved_mcheck_exception)(struct pt_regs *regs);
-
-static int fsl_rio_mcheck_exception(struct pt_regs *regs)
+int fsl_rio_mcheck_exception(struct pt_regs *regs)
 {
        const struct exception_table_entry *entry = NULL;
        unsigned long reason = mfspr(SPRN_MCSR);
@@ -284,11 +303,9 @@ static int fsl_rio_mcheck_exception(struct pt_regs *regs)
                }
        }
 
-       if (saved_mcheck_exception)
-               return saved_mcheck_exception(regs);
-       else
-               return cur_cpu_spec->machine_check(regs);
+       return 0;
 }
+EXPORT_SYMBOL_GPL(fsl_rio_mcheck_exception);
 #endif
 
 /**
@@ -1064,6 +1081,40 @@ static int fsl_rio_doorbell_init(struct rio_mport *mport)
        return rc;
 }
 
+static void port_error_handler(struct rio_mport *port, int offset)
+{
+       /*XXX: Error recovery is not implemented, we just clear errors */
+       out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0);
+
+       if (offset == 0) {
+               out_be32((u32 *)(rio_regs_win + RIO_PORT1_EDCSR), 0);
+               out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), 0);
+               out_be32((u32 *)(rio_regs_win + RIO_ESCSR), ESCSR_CLEAR);
+       } else {
+               out_be32((u32 *)(rio_regs_win + RIO_PORT2_EDCSR), 0);
+               out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), 0);
+               out_be32((u32 *)(rio_regs_win + RIO_PORT2_ESCSR), ESCSR_CLEAR);
+       }
+}
+
+static void msg_unit_error_handler(struct rio_mport *port)
+{
+       struct rio_priv *priv = port->priv;
+
+       /*XXX: Error recovery is not implemented, we just clear errors */
+       out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0);
+
+       out_be32((u32 *)(rio_regs_win + RIO_IM0SR), IMSR_CLEAR);
+       out_be32((u32 *)(rio_regs_win + RIO_IM1SR), IMSR_CLEAR);
+       out_be32((u32 *)(rio_regs_win + RIO_OM0SR), OMSR_CLEAR);
+       out_be32((u32 *)(rio_regs_win + RIO_OM1SR), OMSR_CLEAR);
+
+       out_be32(&priv->msg_regs->odsr, ODSR_CLEAR);
+       out_be32(&priv->msg_regs->dsr, IDSR_CLEAR);
+
+       out_be32(&priv->msg_regs->pwsr, IPWSR_CLEAR);
+}
+
 /**
  * fsl_rio_port_write_handler - MPC85xx port write interrupt handler
  * @irq: Linux interrupt number
@@ -1144,10 +1195,22 @@ fsl_rio_port_write_handler(int irq, void *dev_instance)
        }
 
 pw_done:
-       if (epwisr & RIO_EPWISR_PINT) {
+       if (epwisr & RIO_EPWISR_PINT1) {
+               tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+               pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
+               port_error_handler(port, 0);
+       }
+
+       if (epwisr & RIO_EPWISR_PINT2) {
                tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
                pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
-               out_be32(priv->regs_win + RIO_LTLEDCSR, 0);
+               port_error_handler(port, 1);
+       }
+
+       if (epwisr & RIO_EPWISR_MU) {
+               tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+               pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
+               msg_unit_error_handler(port);
        }
 
        return IRQ_HANDLED;
@@ -1258,12 +1321,14 @@ static int fsl_rio_port_write_init(struct rio_mport *mport)
 
 
        /* Hook up port-write handler */
-       rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler, 0,
-                        "port-write", (void *)mport);
+       rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler,
+                       IRQF_SHARED, "port-write", (void *)mport);
        if (rc < 0) {
                pr_err("MPC85xx RIO: unable to request inbound doorbell irq");
                goto err_out;
        }
+       /* Enable Error Interrupt */
+       out_be32((u32 *)(rio_regs_win + RIO_LTLEECSR), LTLEECSR_ENABLE_ALL);
 
        INIT_WORK(&priv->pw_work, fsl_pw_dpc);
        spin_lock_init(&priv->pw_fifo_lock);
@@ -1538,11 +1603,6 @@ int fsl_rio_setup(struct platform_device *dev)
        fsl_rio_doorbell_init(port);
        fsl_rio_port_write_init(port);
 
-#ifdef CONFIG_E500
-       saved_mcheck_exception = ppc_md.machine_check_exception;
-       ppc_md.machine_check_exception = fsl_rio_mcheck_exception;
-#endif
-
        return 0;
 err:
        iounmap(priv->regs_win);
diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c
new file mode 100644 (file)
index 0000000..367af02
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * Adding PCI-E MSI support for PPC4XX SoCs.
+ *
+ * Copyright (c) 2010, Applied Micro Circuits Corporation
+ * Authors:    Tirumala R Marri <tmarri@apm.com>
+ *             Feng Kan <fkan@apm.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/irq.h>
+#include <linux/bootmem.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
+#include <linux/of_platform.h>
+#include <linux/interrupt.h>
+#include <asm/prom.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+#include <boot/dcr.h>
+#include <asm/dcr-regs.h>
+#include <asm/msi_bitmap.h>
+
+#define PEIH_TERMADH   0x00
+#define PEIH_TERMADL   0x08
+#define PEIH_MSIED     0x10
+#define PEIH_MSIMK     0x18
+#define PEIH_MSIASS    0x20
+#define PEIH_FLUSH0    0x30
+#define PEIH_FLUSH1    0x38
+#define PEIH_CNTRST    0x48
+#define NR_MSI_IRQS    4
+
+struct ppc4xx_msi {
+       u32 msi_addr_lo;
+       u32 msi_addr_hi;
+       void __iomem *msi_regs;
+       int msi_virqs[NR_MSI_IRQS];
+       struct msi_bitmap bitmap;
+       struct device_node *msi_dev;
+};
+
+static struct ppc4xx_msi ppc4xx_msi;
+
+static int ppc4xx_msi_init_allocator(struct platform_device *dev,
+               struct ppc4xx_msi *msi_data)
+{
+       int err;
+
+       err = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
+                             dev->dev.of_node);
+       if (err)
+               return err;
+
+       err = msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap);
+       if (err < 0) {
+               msi_bitmap_free(&msi_data->bitmap);
+               return err;
+       }
+
+       return 0;
+}
+
+static int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+       int int_no = -ENOMEM;
+       unsigned int virq;
+       struct msi_msg msg;
+       struct msi_desc *entry;
+       struct ppc4xx_msi *msi_data = &ppc4xx_msi;
+
+       list_for_each_entry(entry, &dev->msi_list, list) {
+               int_no = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
+               if (int_no >= 0)
+                       break;
+               if (int_no < 0) {
+                       pr_debug("%s: fail allocating msi interrupt\n",
+                                       __func__);
+               }
+               virq = irq_of_parse_and_map(msi_data->msi_dev, int_no);
+               if (virq == NO_IRQ) {
+                       dev_err(&dev->dev, "%s: fail mapping irq\n", __func__);
+                       msi_bitmap_free_hwirqs(&msi_data->bitmap, int_no, 1);
+                       return -ENOSPC;
+               }
+               dev_dbg(&dev->dev, "%s: virq = %d\n", __func__, virq);
+
+               /* Setup msi address space */
+               msg.address_hi = msi_data->msi_addr_hi;
+               msg.address_lo = msi_data->msi_addr_lo;
+
+               irq_set_msi_desc(virq, entry);
+               msg.data = int_no;
+               write_msi_msg(virq, &msg);
+       }
+       return 0;
+}
+
+void ppc4xx_teardown_msi_irqs(struct pci_dev *dev)
+{
+       struct msi_desc *entry;
+       struct ppc4xx_msi *msi_data = &ppc4xx_msi;
+
+       dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n");
+
+       list_for_each_entry(entry, &dev->msi_list, list) {
+               if (entry->irq == NO_IRQ)
+                       continue;
+               irq_set_msi_desc(entry->irq, NULL);
+               msi_bitmap_free_hwirqs(&msi_data->bitmap,
+                               virq_to_hw(entry->irq), 1);
+               irq_dispose_mapping(entry->irq);
+       }
+}
+
+static int ppc4xx_msi_check_device(struct pci_dev *pdev, int nvec, int type)
+{
+       dev_dbg(&pdev->dev, "PCIE-MSI:%s called. vec %x type %d\n",
+               __func__, nvec, type);
+       if (type == PCI_CAP_ID_MSIX)
+               pr_debug("ppc4xx msi: MSI-X untested, trying anyway.\n");
+
+       return 0;
+}
+
+static int ppc4xx_setup_pcieh_hw(struct platform_device *dev,
+                                struct resource res, struct ppc4xx_msi *msi)
+{
+       const u32 *msi_data;
+       const u32 *msi_mask;
+       const u32 *sdr_addr;
+       dma_addr_t msi_phys;
+       void *msi_virt;
+
+       sdr_addr = of_get_property(dev->dev.of_node, "sdr-base", NULL);
+       if (!sdr_addr)
+               return -1;
+
+       SDR0_WRITE(sdr_addr, (u64)res.start >> 32);      /*HIGH addr */
+       SDR0_WRITE(sdr_addr + 1, res.start & 0xFFFFFFFF); /* Low addr */
+
+
+       msi->msi_dev = of_find_node_by_name(NULL, "ppc4xx-msi");
+       if (msi->msi_dev)
+               return -ENODEV;
+
+       msi->msi_regs = of_iomap(msi->msi_dev, 0);
+       if (!msi->msi_regs) {
+               dev_err(&dev->dev, "of_iomap problem failed\n");
+               return -ENOMEM;
+       }
+       dev_dbg(&dev->dev, "PCIE-MSI: msi register mapped 0x%x 0x%x\n",
+               (u32) (msi->msi_regs + PEIH_TERMADH), (u32) (msi->msi_regs));
+
+       msi_virt = dma_alloc_coherent(&dev->dev, 64, &msi_phys, GFP_KERNEL);
+       msi->msi_addr_hi = 0x0;
+       msi->msi_addr_lo = (u32) msi_phys;
+       dev_dbg(&dev->dev, "PCIE-MSI: msi address 0x%x\n", msi->msi_addr_lo);
+
+       /* Progam the Interrupt handler Termination addr registers */
+       out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi);
+       out_be32(msi->msi_regs + PEIH_TERMADL, msi->msi_addr_lo);
+
+       msi_data = of_get_property(dev->dev.of_node, "msi-data", NULL);
+       if (!msi_data)
+               return -1;
+       msi_mask = of_get_property(dev->dev.of_node, "msi-mask", NULL);
+       if (!msi_mask)
+               return -1;
+       /* Program MSI Expected data and Mask bits */
+       out_be32(msi->msi_regs + PEIH_MSIED, *msi_data);
+       out_be32(msi->msi_regs + PEIH_MSIMK, *msi_mask);
+
+       return 0;
+}
+
+static int ppc4xx_of_msi_remove(struct platform_device *dev)
+{
+       struct ppc4xx_msi *msi = dev->dev.platform_data;
+       int i;
+       int virq;
+
+       for (i = 0; i < NR_MSI_IRQS; i++) {
+               virq = msi->msi_virqs[i];
+               if (virq != NO_IRQ)
+                       irq_dispose_mapping(virq);
+       }
+
+       if (msi->bitmap.bitmap)
+               msi_bitmap_free(&msi->bitmap);
+       iounmap(msi->msi_regs);
+       of_node_put(msi->msi_dev);
+       kfree(msi);
+
+       return 0;
+}
+
+static int __devinit ppc4xx_msi_probe(struct platform_device *dev)
+{
+       struct ppc4xx_msi *msi;
+       struct resource res;
+       int err = 0;
+
+       msi = &ppc4xx_msi;/*keep the msi data for further use*/
+
+       dev_dbg(&dev->dev, "PCIE-MSI: Setting up MSI support...\n");
+
+       msi = kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL);
+       if (!msi) {
+               dev_err(&dev->dev, "No memory for MSI structure\n");
+               return -ENOMEM;
+       }
+       dev->dev.platform_data = msi;
+
+       /* Get MSI ranges */
+       err = of_address_to_resource(dev->dev.of_node, 0, &res);
+       if (err) {
+               dev_err(&dev->dev, "%s resource error!\n",
+                       dev->dev.of_node->full_name);
+               goto error_out;
+       }
+
+       if (ppc4xx_setup_pcieh_hw(dev, res, msi))
+               goto error_out;
+
+       err = ppc4xx_msi_init_allocator(dev, msi);
+       if (err) {
+               dev_err(&dev->dev, "Error allocating MSI bitmap\n");
+               goto error_out;
+       }
+
+       ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs;
+       ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs;
+       ppc_md.msi_check_device = ppc4xx_msi_check_device;
+       return err;
+
+error_out:
+       ppc4xx_of_msi_remove(dev);
+       return err;
+}
+static const struct of_device_id ppc4xx_msi_ids[] = {
+       {
+               .compatible = "amcc,ppc4xx-msi",
+       },
+       {}
+};
+static struct platform_driver ppc4xx_msi_driver = {
+       .probe = ppc4xx_msi_probe,
+       .remove = ppc4xx_of_msi_remove,
+       .driver = {
+                  .name = "ppc4xx-msi",
+                  .owner = THIS_MODULE,
+                  .of_match_table = ppc4xx_msi_ids,
+                  },
+
+};
+
+static __init int ppc4xx_msi_init(void)
+{
+       return platform_driver_register(&ppc4xx_msi_driver);
+}
+
+subsys_initcall(ppc4xx_msi_init);
index 4a7f14079e03b989bd4cd4b1a012b082e07447b3..c03fef7a9c2220c45ca1584ad8f65191bb5c9e76 100644 (file)
@@ -2,7 +2,7 @@ config MMU
        def_bool y
 
 config ZONE_DMA
-       def_bool y if 64BIT
+       def_bool y
 
 config LOCKDEP_SUPPORT
        def_bool y
@@ -89,6 +89,7 @@ config S390
        select HAVE_GET_USER_PAGES_FAST
        select HAVE_ARCH_MUTEX_CPU_RELAX
        select HAVE_ARCH_JUMP_LABEL if !MARCH_G5
+       select HAVE_RCU_TABLE_FREE if SMP
        select ARCH_INLINE_SPIN_TRYLOCK
        select ARCH_INLINE_SPIN_TRYLOCK_BH
        select ARCH_INLINE_SPIN_LOCK
@@ -230,17 +231,6 @@ config SYSVIPC_COMPAT
 config AUDIT_ARCH
        def_bool y
 
-config S390_EXEC_PROTECT
-       def_bool y
-       prompt "Data execute protection"
-       help
-         This option allows to enable a buffer overflow protection for user
-         space programs and it also selects the addressing mode option above.
-         The kernel parameter noexec=on will enable this feature and also
-         switch the addressing modes, default is disabled. Enabling this (via
-         kernel parameter) on machines earlier than IBM System z9 this will
-         reduce system performance.
-
 comment "Code generation options"
 
 choice
@@ -589,6 +579,7 @@ config S390_GUEST
        def_bool y
        prompt "s390 guest support for KVM (EXPERIMENTAL)"
        depends on 64BIT && EXPERIMENTAL
+       select VIRTUALIZATION
        select VIRTIO
        select VIRTIO_RING
        select VIRTIO_CONSOLE
index 5c91995b74e4b598e7eb5e974492ecb13087ff6a..24bff4f1cc52ba906a9a6432af6f4e1ebf16c818 100644 (file)
@@ -130,9 +130,7 @@ static void appldata_work_fn(struct work_struct *work)
 {
        struct list_head *lh;
        struct appldata_ops *ops;
-       int i;
 
-       i = 0;
        get_online_cpus();
        mutex_lock(&appldata_ops_mutex);
        list_for_each(lh, &appldata_ops_list) {
index e43fe753703114890aaff48dec708aec64f32999..f7d3dc555bdbd5c44b45f7f2feeb75560d38887d 100644 (file)
@@ -92,9 +92,7 @@ static void appldata_get_mem_data(void *data)
        mem_data->pswpin     = ev[PSWPIN];
        mem_data->pswpout    = ev[PSWPOUT];
        mem_data->pgalloc    = ev[PGALLOC_NORMAL];
-#ifdef CONFIG_ZONE_DMA
        mem_data->pgalloc    += ev[PGALLOC_DMA];
-#endif
        mem_data->pgfault    = ev[PGFAULT];
        mem_data->pgmajfault = ev[PGMAJFAULT];
 
index e1c8f3a49884bcf73f5a04ad2e6fe613bc13cd45..667c6e9f6a34bf569d1d1441af55eec2d02d3e37 100644 (file)
@@ -621,6 +621,7 @@ static inline unsigned long find_first_zero_bit(const unsigned long *addr,
        bits = __ffz_word(bytes*8, __load_ulong_be(addr, bytes));
        return (bits < size) ? bits : size;
 }
+#define find_first_zero_bit find_first_zero_bit
 
 /**
  * find_first_bit - find the first set bit in a memory region
@@ -641,6 +642,7 @@ static inline unsigned long find_first_bit(const unsigned long * addr,
        bits = __ffs_word(bytes*8, __load_ulong_be(addr, bytes));
        return (bits < size) ? bits : size;
 }
+#define find_first_bit find_first_bit
 
 /**
  * find_next_zero_bit - find the first zero bit in a memory region
@@ -677,6 +679,7 @@ static inline int find_next_zero_bit (const unsigned long * addr,
        }
        return offset + find_first_zero_bit(p, size);
 }
+#define find_next_zero_bit find_next_zero_bit
 
 /**
  * find_next_bit - find the first set bit in a memory region
@@ -713,6 +716,7 @@ static inline int find_next_bit (const unsigned long * addr,
        }
        return offset + find_first_bit(p, size);
 }
+#define find_next_bit find_next_bit
 
 /*
  * Every architecture must define this function. It's the fastest
@@ -742,41 +746,6 @@ static inline int sched_find_first_bit(unsigned long *b)
  *    23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24
  */
 
-static inline void __set_bit_le(unsigned long nr, void *addr)
-{
-       __set_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
-}
-
-static inline void __clear_bit_le(unsigned long nr, void *addr)
-{
-       __clear_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
-}
-
-static inline int __test_and_set_bit_le(unsigned long nr, void *addr)
-{
-       return __test_and_set_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
-}
-
-static inline int test_and_set_bit_le(unsigned long nr, void *addr)
-{
-       return test_and_set_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
-}
-
-static inline int __test_and_clear_bit_le(unsigned long nr, void *addr)
-{
-       return __test_and_clear_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
-}
-
-static inline int test_and_clear_bit_le(unsigned long nr, void *addr)
-{
-       return test_and_clear_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
-}
-
-static inline int test_bit_le(unsigned long nr, const void *addr)
-{
-       return test_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
-}
-
 static inline int find_first_zero_bit_le(void *vaddr, unsigned int size)
 {
        unsigned long bytes, bits;
@@ -787,6 +756,7 @@ static inline int find_first_zero_bit_le(void *vaddr, unsigned int size)
        bits = __ffz_word(bytes*8, __load_ulong_le(vaddr, bytes));
        return (bits < size) ? bits : size;
 }
+#define find_first_zero_bit_le find_first_zero_bit_le
 
 static inline int find_next_zero_bit_le(void *vaddr, unsigned long size,
                                          unsigned long offset)
@@ -816,6 +786,7 @@ static inline int find_next_zero_bit_le(void *vaddr, unsigned long size,
         }
        return offset + find_first_zero_bit_le(p, size);
 }
+#define find_next_zero_bit_le find_next_zero_bit_le
 
 static inline unsigned long find_first_bit_le(void *vaddr, unsigned long size)
 {
@@ -827,6 +798,7 @@ static inline unsigned long find_first_bit_le(void *vaddr, unsigned long size)
        bits = __ffs_word(bytes*8, __load_ulong_le(vaddr, bytes));
        return (bits < size) ? bits : size;
 }
+#define find_first_bit_le find_first_bit_le
 
 static inline int find_next_bit_le(void *vaddr, unsigned long size,
                                     unsigned long offset)
@@ -856,6 +828,9 @@ static inline int find_next_bit_le(void *vaddr, unsigned long size,
        }
        return offset + find_first_bit_le(p, size);
 }
+#define find_next_bit_le find_next_bit_le
+
+#include <asm-generic/bitops/le.h>
 
 #define ext2_set_bit_atomic(lock, nr, addr)    \
        test_and_set_bit_le(nr, addr)
index 7488e52efa97628481e95d6c0dca90e8ed30cd0a..81d7908416cf769202a40541d6a1779560712df5 100644 (file)
@@ -167,7 +167,6 @@ static inline unsigned long __cmpxchg(void *ptr, unsigned long old,
 #ifdef CONFIG_64BIT
 #define cmpxchg64(ptr, o, n)                                           \
 ({                                                                     \
-       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
        cmpxchg((ptr), (o), (n));                                       \
 })
 #else /* CONFIG_64BIT */
index 8a096b83f51f634623217fc3b5da8f61520a81e7..0e3b35f96be174c12df5d93e33acee36532bcb61 100644 (file)
 #ifndef _S390_DELAY_H
 #define _S390_DELAY_H
 
-extern void __udelay(unsigned long long usecs);
-extern void udelay_simple(unsigned long long usecs);
-extern void __delay(unsigned long loops);
+void __ndelay(unsigned long long nsecs);
+void __udelay(unsigned long long usecs);
+void udelay_simple(unsigned long long usecs);
+void __delay(unsigned long loops);
 
+#define ndelay(n) __ndelay((unsigned long long) (n))
 #define udelay(n) __udelay((unsigned long long) (n))
 #define mdelay(n) __udelay((unsigned long long) (n) * 1000)
 
index 10c029cfcc7d3c7d8e8feda790c6c3e885fa34a9..64b61bf72e936ff6839a975162c47483a417328d 100644 (file)
@@ -196,18 +196,6 @@ do {                                                               \
 } while (0)
 #endif /* __s390x__ */
 
-/*
- * An executable for which elf_read_implies_exec() returns TRUE will
- * have the READ_IMPLIES_EXEC personality flag set automatically.
- */
-#define elf_read_implies_exec(ex, executable_stack)    \
-({                                                     \
-       if (current->mm->context.noexec &&              \
-           executable_stack != EXSTACK_DISABLE_X)      \
-               disable_noexec(current->mm, current);   \
-       current->mm->context.noexec == 0;               \
-})
-
 #define STACK_RND_MASK 0x7ffUL
 
 #define ARCH_DLINFO                                                        \
index b56403c2df281d098aa67dc89d3ca9511b6ea5ea..799ed0f1643d135c843f3a1cdc41204063289f0f 100644 (file)
@@ -111,21 +111,10 @@ static inline void huge_ptep_invalidate(struct mm_struct *mm,
 {
        pmd_t *pmdp = (pmd_t *) ptep;
 
-       if (!MACHINE_HAS_IDTE) {
-               __pmd_csp(pmdp);
-               if (mm->context.noexec) {
-                       pmdp = get_shadow_table(pmdp);
-                       __pmd_csp(pmdp);
-               }
-               return;
-       }
-
-       __pmd_idte(address, pmdp);
-       if (mm->context.noexec) {
-               pmdp = get_shadow_table(pmdp);
+       if (MACHINE_HAS_IDTE)
                __pmd_idte(address, pmdp);
-       }
-       return;
+       else
+               __pmd_csp(pmdp);
 }
 
 #define huge_ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \
index db14a311f1d21d2c03c8d093c5c55220c71c18b2..ba7b01c726a37eb024900e69db673542cc86db02 100644 (file)
@@ -2,6 +2,7 @@
 #define _ASM_IRQ_H
 
 #include <linux/hardirq.h>
+#include <linux/types.h>
 
 enum interruption_class {
        EXTERNAL_INTERRUPT,
@@ -15,6 +16,7 @@ enum interruption_class {
        EXTINT_VRT,
        EXTINT_SCP,
        EXTINT_IUC,
+       EXTINT_CPM,
        IOINT_QAI,
        IOINT_QDI,
        IOINT_DAS,
@@ -30,4 +32,11 @@ enum interruption_class {
        NR_IRQS,
 };
 
+typedef void (*ext_int_handler_t)(unsigned int, unsigned int, unsigned long);
+
+int register_external_interrupt(u16 code, ext_int_handler_t handler);
+int unregister_external_interrupt(u16 code, ext_int_handler_t handler);
+void service_subclass_irq_register(void);
+void service_subclass_irq_unregister(void);
+
 #endif /* _ASM_IRQ_H */
index 65e172f8209d902798e05a884bc3c5ce8ef7f80c..228cf0b295dbbffd445068e08bd64a13cf9b9cda 100644 (file)
@@ -124,7 +124,7 @@ struct _lowcore {
        /* Address space pointer. */
        __u32   kernel_asce;                    /* 0x02ac */
        __u32   user_asce;                      /* 0x02b0 */
-       __u32   user_exec_asce;                 /* 0x02b4 */
+       __u32   current_pid;                    /* 0x02b4 */
 
        /* SMP info area */
        __u32   cpu_nr;                         /* 0x02b8 */
@@ -255,7 +255,7 @@ struct _lowcore {
        /* Address space pointer. */
        __u64   kernel_asce;                    /* 0x0310 */
        __u64   user_asce;                      /* 0x0318 */
-       __u64   user_exec_asce;                 /* 0x0320 */
+       __u64   current_pid;                    /* 0x0320 */
 
        /* SMP info area */
        __u32   cpu_nr;                         /* 0x0328 */
index 78522cdefdd42334c7b4f72be1180a6a2ed2f327..82d0847896a0cc096f38331e83cb9bd3b3dfbae4 100644 (file)
@@ -5,19 +5,18 @@ typedef struct {
        atomic_t attach_count;
        unsigned int flush_mm;
        spinlock_t list_lock;
-       struct list_head crst_list;
        struct list_head pgtable_list;
        unsigned long asce_bits;
        unsigned long asce_limit;
        unsigned long vdso_base;
-       int noexec;
-       int has_pgste;   /* The mmu context has extended page tables */
-       int alloc_pgste; /* cloned contexts will have extended page tables */
+       /* Cloned contexts will be created with extended page tables. */
+       unsigned int alloc_pgste:1;
+       /* The mmu context has extended page tables. */
+       unsigned int has_pgste:1;
 } mm_context_t;
 
 #define INIT_MM_CONTEXT(name)                                                \
        .context.list_lock    = __SPIN_LOCK_UNLOCKED(name.context.list_lock), \
-       .context.crst_list    = LIST_HEAD_INIT(name.context.crst_list),       \
        .context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list),
 
 #endif
index 8c277caa8d3aa81d0d8f14c28b2e71f12ec3e791..5682f160ff82caa965a9bd1e3c3aa0b28d403021 100644 (file)
@@ -35,11 +35,9 @@ static inline int init_new_context(struct task_struct *tsk,
                 * and if has_pgste is set, it will create extended page
                 * tables.
                 */
-               mm->context.noexec = 0;
                mm->context.has_pgste = 1;
                mm->context.alloc_pgste = 1;
        } else {
-               mm->context.noexec = (user_mode == SECONDARY_SPACE_MODE);
                mm->context.has_pgste = 0;
                mm->context.alloc_pgste = 0;
        }
@@ -63,10 +61,8 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)
        S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd);
        if (user_mode != HOME_SPACE_MODE) {
                /* Load primary space page table origin. */
-               pgd = mm->context.noexec ? get_shadow_table(pgd) : pgd;
-               S390_lowcore.user_exec_asce = mm->context.asce_bits | __pa(pgd);
                asm volatile(LCTL_OPCODE" 1,1,%0\n"
-                            : : "m" (S390_lowcore.user_exec_asce) );
+                            : : "m" (S390_lowcore.user_asce) );
        } else
                /* Load home space page table origin. */
                asm volatile(LCTL_OPCODE" 13,13,%0"
index 3c987e9ec8d69e61d4eaaa5f21e409613662324c..accb372ddc7e4095e768a3756b6fafeb418ee4ac 100644 (file)
@@ -90,6 +90,7 @@ static inline void copy_page(void *to, void *from)
  */
 
 typedef struct { unsigned long pgprot; } pgprot_t;
+typedef struct { unsigned long pgste; } pgste_t;
 typedef struct { unsigned long pte; } pte_t;
 typedef struct { unsigned long pmd; } pmd_t;
 typedef struct { unsigned long pud; } pud_t;
@@ -97,18 +98,21 @@ typedef struct { unsigned long pgd; } pgd_t;
 typedef pte_t *pgtable_t;
 
 #define pgprot_val(x)  ((x).pgprot)
+#define pgste_val(x)   ((x).pgste)
 #define pte_val(x)     ((x).pte)
 #define pmd_val(x)     ((x).pmd)
 #define pud_val(x)     ((x).pud)
 #define pgd_val(x)      ((x).pgd)
 
+#define __pgste(x)     ((pgste_t) { (x) } )
 #define __pte(x)        ((pte_t) { (x) } )
 #define __pmd(x)        ((pmd_t) { (x) } )
+#define __pud(x)       ((pud_t) { (x) } )
 #define __pgd(x)        ((pgd_t) { (x) } )
 #define __pgprot(x)     ((pgprot_t) { (x) } )
 
-static inline void
-page_set_storage_key(unsigned long addr, unsigned int skey, int mapped)
+static inline void page_set_storage_key(unsigned long addr,
+                                       unsigned char skey, int mapped)
 {
        if (!mapped)
                asm volatile(".insn rrf,0xb22b0000,%0,%1,8,0"
@@ -117,15 +121,59 @@ page_set_storage_key(unsigned long addr, unsigned int skey, int mapped)
                asm volatile("sske %0,%1" : : "d" (skey), "a" (addr));
 }
 
-static inline unsigned int
-page_get_storage_key(unsigned long addr)
+static inline unsigned char page_get_storage_key(unsigned long addr)
 {
-       unsigned int skey;
+       unsigned char skey;
 
-       asm volatile("iske %0,%1" : "=d" (skey) : "a" (addr), "0" (0));
+       asm volatile("iske %0,%1" : "=d" (skey) : "a" (addr));
        return skey;
 }
 
+static inline int page_reset_referenced(unsigned long addr)
+{
+       unsigned int ipm;
+
+       asm volatile(
+               "       rrbe    0,%1\n"
+               "       ipm     %0\n"
+               : "=d" (ipm) : "a" (addr) : "cc");
+       return !!(ipm & 0x20000000);
+}
+
+/* Bits int the storage key */
+#define _PAGE_CHANGED          0x02    /* HW changed bit               */
+#define _PAGE_REFERENCED       0x04    /* HW referenced bit            */
+#define _PAGE_FP_BIT           0x08    /* HW fetch protection bit      */
+#define _PAGE_ACC_BITS         0xf0    /* HW access control bits       */
+
+/*
+ * Test and clear dirty bit in storage key.
+ * We can't clear the changed bit atomically. This is a potential
+ * race against modification of the referenced bit. This function
+ * should therefore only be called if it is not mapped in any
+ * address space.
+ */
+#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY
+static inline int page_test_and_clear_dirty(unsigned long pfn, int mapped)
+{
+       unsigned char skey;
+
+       skey = page_get_storage_key(pfn << PAGE_SHIFT);
+       if (!(skey & _PAGE_CHANGED))
+               return 0;
+       page_set_storage_key(pfn << PAGE_SHIFT, skey & ~_PAGE_CHANGED, mapped);
+       return 1;
+}
+
+/*
+ * Test and clear referenced bit in storage key.
+ */
+#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
+static inline int page_test_and_clear_young(unsigned long pfn)
+{
+       return page_reset_referenced(pfn << PAGE_SHIFT);
+}
+
 struct page;
 void arch_free_page(struct page *page, int order);
 void arch_alloc_page(struct page *page, int order);
index f7ad8719d02dcd211bc18c39806d86a5dceb985a..5325c89a5843b52c73cd0ef36dd6cc67c1a10928 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef __ARCH_S390_PERCPU__
 #define __ARCH_S390_PERCPU__
 
+#include <linux/preempt.h>
+#include <asm/cmpxchg.h>
+
 /*
  * s390 uses its own implementation for per cpu data, the offset of
  * the cpu local data area is cached in the cpu's lowcore memory.
 #define ARCH_NEEDS_WEAK_PER_CPU
 #endif
 
+#define arch_irqsafe_cpu_to_op(pcp, val, op)                           \
+do {                                                                   \
+       typedef typeof(pcp) pcp_op_T__;                                 \
+       pcp_op_T__ old__, new__, prev__;                                \
+       pcp_op_T__ *ptr__;                                              \
+       preempt_disable();                                              \
+       ptr__ = __this_cpu_ptr(&(pcp));                                 \
+       prev__ = *ptr__;                                                \
+       do {                                                            \
+               old__ = prev__;                                         \
+               new__ = old__ op (val);                                 \
+               switch (sizeof(*ptr__)) {                               \
+               case 8:                                                 \
+                       prev__ = cmpxchg64(ptr__, old__, new__);        \
+                       break;                                          \
+               default:                                                \
+                       prev__ = cmpxchg(ptr__, old__, new__);          \
+               }                                                       \
+       } while (prev__ != old__);                                      \
+       preempt_enable();                                               \
+} while (0)
+
+#define irqsafe_cpu_add_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +)
+#define irqsafe_cpu_add_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +)
+#define irqsafe_cpu_add_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +)
+#define irqsafe_cpu_add_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +)
+
+#define irqsafe_cpu_and_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &)
+#define irqsafe_cpu_and_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &)
+#define irqsafe_cpu_and_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &)
+#define irqsafe_cpu_and_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &)
+
+#define irqsafe_cpu_or_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |)
+#define irqsafe_cpu_or_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |)
+#define irqsafe_cpu_or_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |)
+#define irqsafe_cpu_or_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |)
+
+#define irqsafe_cpu_xor_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^)
+#define irqsafe_cpu_xor_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^)
+#define irqsafe_cpu_xor_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^)
+#define irqsafe_cpu_xor_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^)
+
+#define arch_irqsafe_cpu_cmpxchg(pcp, oval, nval)                      \
+({                                                                     \
+       typedef typeof(pcp) pcp_op_T__;                                 \
+       pcp_op_T__ ret__;                                               \
+       pcp_op_T__ *ptr__;                                              \
+       preempt_disable();                                              \
+       ptr__ = __this_cpu_ptr(&(pcp));                                 \
+       switch (sizeof(*ptr__)) {                                       \
+       case 8:                                                         \
+               ret__ = cmpxchg64(ptr__, oval, nval);                   \
+               break;                                                  \
+       default:                                                        \
+               ret__ = cmpxchg(ptr__, oval, nval);                     \
+       }                                                               \
+       preempt_enable();                                               \
+       ret__;                                                          \
+})
+
+#define irqsafe_cpu_cmpxchg_1(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval)
+#define irqsafe_cpu_cmpxchg_2(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval)
+#define irqsafe_cpu_cmpxchg_4(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval)
+#define irqsafe_cpu_cmpxchg_8(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval)
+
 #include <asm-generic/percpu.h>
 
 #endif /* __ARCH_S390_PERCPU__ */
index 082eb4e50e8b3f53a59cc8343e619bfc6a60b6cc..38e71ebcd3c276c2483d5e378f4cc63f189c20a2 100644 (file)
 #include <linux/gfp.h>
 #include <linux/mm.h>
 
-#define check_pgt_cache()      do {} while (0)
-
-unsigned long *crst_table_alloc(struct mm_struct *, int);
+unsigned long *crst_table_alloc(struct mm_struct *);
 void crst_table_free(struct mm_struct *, unsigned long *);
-void crst_table_free_rcu(struct mm_struct *, unsigned long *);
 
 unsigned long *page_table_alloc(struct mm_struct *);
 void page_table_free(struct mm_struct *, unsigned long *);
-void page_table_free_rcu(struct mm_struct *, unsigned long *);
-void disable_noexec(struct mm_struct *, struct task_struct *);
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+void page_table_free_rcu(struct mmu_gather *, unsigned long *);
+void __tlb_remove_table(void *_table);
+#endif
 
 static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
 {
@@ -50,9 +49,6 @@ static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
 static inline void crst_table_init(unsigned long *crst, unsigned long entry)
 {
        clear_table(crst, entry, sizeof(unsigned long)*2048);
-       crst = get_shadow_table(crst);
-       if (crst)
-               clear_table(crst, entry, sizeof(unsigned long)*2048);
 }
 
 #ifndef __s390x__
@@ -69,10 +65,7 @@ static inline unsigned long pgd_entry_type(struct mm_struct *mm)
 #define pmd_free(mm, x)                                do { } while (0)
 
 #define pgd_populate(mm, pgd, pud)             BUG()
-#define pgd_populate_kernel(mm, pgd, pud)      BUG()
-
 #define pud_populate(mm, pud, pmd)             BUG()
-#define pud_populate_kernel(mm, pud, pmd)      BUG()
 
 #else /* __s390x__ */
 
@@ -90,7 +83,7 @@ void crst_table_downgrade(struct mm_struct *, unsigned long limit);
 
 static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
 {
-       unsigned long *table = crst_table_alloc(mm, mm->context.noexec);
+       unsigned long *table = crst_table_alloc(mm);
        if (table)
                crst_table_init(table, _REGION3_ENTRY_EMPTY);
        return (pud_t *) table;
@@ -99,43 +92,21 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
 
 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
 {
-       unsigned long *table = crst_table_alloc(mm, mm->context.noexec);
+       unsigned long *table = crst_table_alloc(mm);
        if (table)
                crst_table_init(table, _SEGMENT_ENTRY_EMPTY);
        return (pmd_t *) table;
 }
 #define pmd_free(mm, pmd) crst_table_free(mm, (unsigned long *) pmd)
 
-static inline void pgd_populate_kernel(struct mm_struct *mm,
-                                      pgd_t *pgd, pud_t *pud)
-{
-       pgd_val(*pgd) = _REGION2_ENTRY | __pa(pud);
-}
-
 static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
 {
-       pgd_populate_kernel(mm, pgd, pud);
-       if (mm->context.noexec) {
-               pgd = get_shadow_table(pgd);
-               pud = get_shadow_table(pud);
-               pgd_populate_kernel(mm, pgd, pud);
-       }
-}
-
-static inline void pud_populate_kernel(struct mm_struct *mm,
-                                      pud_t *pud, pmd_t *pmd)
-{
-       pud_val(*pud) = _REGION3_ENTRY | __pa(pmd);
+       pgd_val(*pgd) = _REGION2_ENTRY | __pa(pud);
 }
 
 static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
 {
-       pud_populate_kernel(mm, pud, pmd);
-       if (mm->context.noexec) {
-               pud = get_shadow_table(pud);
-               pmd = get_shadow_table(pmd);
-               pud_populate_kernel(mm, pud, pmd);
-       }
+       pud_val(*pud) = _REGION3_ENTRY | __pa(pmd);
 }
 
 #endif /* __s390x__ */
@@ -143,29 +114,19 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
 static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
        spin_lock_init(&mm->context.list_lock);
-       INIT_LIST_HEAD(&mm->context.crst_list);
        INIT_LIST_HEAD(&mm->context.pgtable_list);
-       return (pgd_t *)
-               crst_table_alloc(mm, user_mode == SECONDARY_SPACE_MODE);
+       return (pgd_t *) crst_table_alloc(mm);
 }
 #define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd)
 
-static inline void pmd_populate_kernel(struct mm_struct *mm,
-                                      pmd_t *pmd, pte_t *pte)
-{
-       pmd_val(*pmd) = _SEGMENT_ENTRY + __pa(pte);
-}
-
 static inline void pmd_populate(struct mm_struct *mm,
                                pmd_t *pmd, pgtable_t pte)
 {
-       pmd_populate_kernel(mm, pmd, pte);
-       if (mm->context.noexec) {
-               pmd = get_shadow_table(pmd);
-               pmd_populate_kernel(mm, pmd, pte + PTRS_PER_PTE);
-       }
+       pmd_val(*pmd) = _SEGMENT_ENTRY + __pa(pte);
 }
 
+#define pmd_populate_kernel(mm, pmd, pte) pmd_populate(mm, pmd, pte)
+
 #define pmd_pgtable(pmd) \
        (pgtable_t)(pmd_val(pmd) & -sizeof(pte_t)*PTRS_PER_PTE)
 
index 02ace3491c51cca92625f2a39f30fe9aa9741ddb..801fbe1d837d32f04e4c3106da6cb85dae2c6ec9 100644 (file)
@@ -31,9 +31,8 @@
 #ifndef __ASSEMBLY__
 #include <linux/sched.h>
 #include <linux/mm_types.h>
-#include <asm/bitops.h>
 #include <asm/bug.h>
-#include <asm/processor.h>
+#include <asm/page.h>
 
 extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096)));
 extern void paging_init(void);
@@ -243,11 +242,13 @@ extern unsigned long VMALLOC_START;
 /* Software bits in the page table entry */
 #define _PAGE_SWT      0x001           /* SW pte type bit t */
 #define _PAGE_SWX      0x002           /* SW pte type bit x */
-#define _PAGE_SPECIAL  0x004           /* SW associated with special page */
+#define _PAGE_SWC      0x004           /* SW pte changed bit (for KVM) */
+#define _PAGE_SWR      0x008           /* SW pte referenced bit (for KVM) */
+#define _PAGE_SPECIAL  0x010           /* SW associated with special page */
 #define __HAVE_ARCH_PTE_SPECIAL
 
 /* Set of bits not changed in pte_modify */
-#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_SPECIAL)
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_SPECIAL | _PAGE_SWC | _PAGE_SWR)
 
 /* Six different types of pages. */
 #define _PAGE_TYPE_EMPTY       0x400
@@ -256,8 +257,6 @@ extern unsigned long VMALLOC_START;
 #define _PAGE_TYPE_FILE                0x601   /* bit 0x002 is used for offset !! */
 #define _PAGE_TYPE_RO          0x200
 #define _PAGE_TYPE_RW          0x000
-#define _PAGE_TYPE_EX_RO       0x202
-#define _PAGE_TYPE_EX_RW       0x002
 
 /*
  * Only four types for huge pages, using the invalid bit and protection bit
@@ -287,8 +286,6 @@ extern unsigned long VMALLOC_START;
  * _PAGE_TYPE_FILE     11?1   ->   11?1
  * _PAGE_TYPE_RO       0100   ->   1100
  * _PAGE_TYPE_RW       0000   ->   1000
- * _PAGE_TYPE_EX_RO    0110   ->   1110
- * _PAGE_TYPE_EX_RW    0010   ->   1010
  *
  * pte_none is true for bits combinations 1000, 1010, 1100, 1110
  * pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001
@@ -296,16 +293,6 @@ extern unsigned long VMALLOC_START;
  * swap pte is 1011 and 0001, 0011, 0101, 0111 are invalid.
  */
 
-/* Page status table bits for virtualization */
-#define RCP_PCL_BIT    55
-#define RCP_HR_BIT     54
-#define RCP_HC_BIT     53
-#define RCP_GR_BIT     50
-#define RCP_GC_BIT     49
-
-/* User dirty bit for KVM's migration feature */
-#define KVM_UD_BIT     47
-
 #ifndef __s390x__
 
 /* Bits in the segment table address-space-control-element */
@@ -325,6 +312,19 @@ extern unsigned long VMALLOC_START;
 #define _SEGMENT_ENTRY         (_SEGMENT_ENTRY_PTL)
 #define _SEGMENT_ENTRY_EMPTY   (_SEGMENT_ENTRY_INV)
 
+/* Page status table bits for virtualization */
+#define RCP_ACC_BITS   0xf0000000UL
+#define RCP_FP_BIT     0x08000000UL
+#define RCP_PCL_BIT    0x00800000UL
+#define RCP_HR_BIT     0x00400000UL
+#define RCP_HC_BIT     0x00200000UL
+#define RCP_GR_BIT     0x00040000UL
+#define RCP_GC_BIT     0x00020000UL
+
+/* User dirty / referenced bit for KVM's migration feature */
+#define KVM_UR_BIT     0x00008000UL
+#define KVM_UC_BIT     0x00004000UL
+
 #else /* __s390x__ */
 
 /* Bits in the segment/region table address-space-control-element */
@@ -367,6 +367,19 @@ extern unsigned long VMALLOC_START;
 #define _SEGMENT_ENTRY_LARGE   0x400   /* STE-format control, large page   */
 #define _SEGMENT_ENTRY_CO      0x100   /* change-recording override   */
 
+/* Page status table bits for virtualization */
+#define RCP_ACC_BITS   0xf000000000000000UL
+#define RCP_FP_BIT     0x0800000000000000UL
+#define RCP_PCL_BIT    0x0080000000000000UL
+#define RCP_HR_BIT     0x0040000000000000UL
+#define RCP_HC_BIT     0x0020000000000000UL
+#define RCP_GR_BIT     0x0004000000000000UL
+#define RCP_GC_BIT     0x0002000000000000UL
+
+/* User dirty / referenced bit for KVM's migration feature */
+#define KVM_UR_BIT     0x0000800000000000UL
+#define KVM_UC_BIT     0x0000400000000000UL
+
 #endif /* __s390x__ */
 
 /*
@@ -377,85 +390,54 @@ extern unsigned long VMALLOC_START;
 #define _ASCE_USER_BITS                (_ASCE_SPACE_SWITCH | _ASCE_PRIVATE_SPACE | \
                                 _ASCE_ALT_EVENT)
 
-/* Bits int the storage key */
-#define _PAGE_CHANGED    0x02          /* HW changed bit                   */
-#define _PAGE_REFERENCED 0x04          /* HW referenced bit                */
-
 /*
  * Page protection definitions.
  */
 #define PAGE_NONE      __pgprot(_PAGE_TYPE_NONE)
 #define PAGE_RO                __pgprot(_PAGE_TYPE_RO)
 #define PAGE_RW                __pgprot(_PAGE_TYPE_RW)
-#define PAGE_EX_RO     __pgprot(_PAGE_TYPE_EX_RO)
-#define PAGE_EX_RW     __pgprot(_PAGE_TYPE_EX_RW)
 
 #define PAGE_KERNEL    PAGE_RW
 #define PAGE_COPY      PAGE_RO
 
 /*
- * Dependent on the EXEC_PROTECT option s390 can do execute protection.
- * Write permission always implies read permission. In theory with a
- * primary/secondary page table execute only can be implemented but
- * it would cost an additional bit in the pte to distinguish all the
- * different pte types. To avoid that execute permission currently
- * implies read permission as well.
+ * On s390 the page table entry has an invalid bit and a read-only bit.
+ * Read permission implies execute permission and write permission
+ * implies read permission.
  */
          /*xwr*/
 #define __P000 PAGE_NONE
 #define __P001 PAGE_RO
 #define __P010 PAGE_RO
 #define __P011 PAGE_RO
-#define __P100 PAGE_EX_RO
-#define __P101 PAGE_EX_RO
-#define __P110 PAGE_EX_RO
-#define __P111 PAGE_EX_RO
+#define __P100 PAGE_RO
+#define __P101 PAGE_RO
+#define __P110 PAGE_RO
+#define __P111 PAGE_RO
 
 #define __S000 PAGE_NONE
 #define __S001 PAGE_RO
 #define __S010 PAGE_RW
 #define __S011 PAGE_RW
-#define __S100 PAGE_EX_RO
-#define __S101 PAGE_EX_RO
-#define __S110 PAGE_EX_RW
-#define __S111 PAGE_EX_RW
-
-#ifndef __s390x__
-# define PxD_SHADOW_SHIFT      1
-#else /* __s390x__ */
-# define PxD_SHADOW_SHIFT      2
-#endif /* __s390x__ */
+#define __S100 PAGE_RO
+#define __S101 PAGE_RO
+#define __S110 PAGE_RW
+#define __S111 PAGE_RW
 
-static inline void *get_shadow_table(void *table)
+static inline int mm_exclusive(struct mm_struct *mm)
 {
-       unsigned long addr, offset;
-       struct page *page;
-
-       addr = (unsigned long) table;
-       offset = addr & ((PAGE_SIZE << PxD_SHADOW_SHIFT) - 1);
-       page = virt_to_page((void *)(addr ^ offset));
-       return (void *)(addr_t)(page->index ? (page->index | offset) : 0UL);
+       return likely(mm == current->active_mm &&
+                     atomic_read(&mm->context.attach_count) <= 1);
 }
 
-/*
- * Certain architectures need to do special things when PTEs
- * within a page table are directly modified.  Thus, the following
- * hook is made available.
- */
-static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
-                             pte_t *ptep, pte_t entry)
+static inline int mm_has_pgste(struct mm_struct *mm)
 {
-       *ptep = entry;
-       if (mm->context.noexec) {
-               if (!(pte_val(entry) & _PAGE_INVALID) &&
-                   (pte_val(entry) & _PAGE_SWX))
-                       pte_val(entry) |= _PAGE_RO;
-               else
-                       pte_val(entry) = _PAGE_TYPE_EMPTY;
-               ptep[PTRS_PER_PTE] = entry;
-       }
+#ifdef CONFIG_PGSTE
+       if (unlikely(mm->context.has_pgste))
+               return 1;
+#endif
+       return 0;
 }
-
 /*
  * pgd/pmd/pte query functions
  */
@@ -568,52 +550,127 @@ static inline int pte_special(pte_t pte)
 }
 
 #define __HAVE_ARCH_PTE_SAME
-#define pte_same(a,b)  (pte_val(a) == pte_val(b))
+static inline int pte_same(pte_t a, pte_t b)
+{
+       return pte_val(a) == pte_val(b);
+}
 
-static inline void rcp_lock(pte_t *ptep)
+static inline pgste_t pgste_get_lock(pte_t *ptep)
 {
+       unsigned long new = 0;
 #ifdef CONFIG_PGSTE
-       unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
+       unsigned long old;
+
        preempt_disable();
-       while (test_and_set_bit(RCP_PCL_BIT, pgste))
-               ;
+       asm(
+               "       lg      %0,%2\n"
+               "0:     lgr     %1,%0\n"
+               "       nihh    %0,0xff7f\n"    /* clear RCP_PCL_BIT in old */
+               "       oihh    %1,0x0080\n"    /* set RCP_PCL_BIT in new */
+               "       csg     %0,%1,%2\n"
+               "       jl      0b\n"
+               : "=&d" (old), "=&d" (new), "=Q" (ptep[PTRS_PER_PTE])
+               : "Q" (ptep[PTRS_PER_PTE]) : "cc");
 #endif
+       return __pgste(new);
 }
 
-static inline void rcp_unlock(pte_t *ptep)
+static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste)
 {
 #ifdef CONFIG_PGSTE
-       unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
-       clear_bit(RCP_PCL_BIT, pgste);
+       asm(
+               "       nihh    %1,0xff7f\n"    /* clear RCP_PCL_BIT */
+               "       stg     %1,%0\n"
+               : "=Q" (ptep[PTRS_PER_PTE])
+               : "d" (pgste_val(pgste)), "Q" (ptep[PTRS_PER_PTE]) : "cc");
        preempt_enable();
 #endif
 }
 
-/* forward declaration for SetPageUptodate in page-flags.h*/
-static inline void page_clear_dirty(struct page *page, int mapped);
-#include <linux/page-flags.h>
-
-static inline void ptep_rcp_copy(pte_t *ptep)
+static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste)
 {
 #ifdef CONFIG_PGSTE
-       struct page *page = virt_to_page(pte_val(*ptep));
-       unsigned int skey;
-       unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
-
-       skey = page_get_storage_key(page_to_phys(page));
-       if (skey & _PAGE_CHANGED) {
-               set_bit_simple(RCP_GC_BIT, pgste);
-               set_bit_simple(KVM_UD_BIT, pgste);
-       }
-       if (skey & _PAGE_REFERENCED)
-               set_bit_simple(RCP_GR_BIT, pgste);
-       if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) {
-               SetPageDirty(page);
-               set_bit_simple(KVM_UD_BIT, pgste);
+       unsigned long address, bits;
+       unsigned char skey;
+
+       address = pte_val(*ptep) & PAGE_MASK;
+       skey = page_get_storage_key(address);
+       bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED);
+       /* Clear page changed & referenced bit in the storage key */
+       if (bits) {
+               skey ^= bits;
+               page_set_storage_key(address, skey, 1);
        }
-       if (test_and_clear_bit_simple(RCP_HR_BIT, pgste))
-               SetPageReferenced(page);
+       /* Transfer page changed & referenced bit to guest bits in pgste */
+       pgste_val(pgste) |= bits << 48;         /* RCP_GR_BIT & RCP_GC_BIT */
+       /* Get host changed & referenced bits from pgste */
+       bits |= (pgste_val(pgste) & (RCP_HR_BIT | RCP_HC_BIT)) >> 52;
+       /* Clear host bits in pgste. */
+       pgste_val(pgste) &= ~(RCP_HR_BIT | RCP_HC_BIT);
+       pgste_val(pgste) &= ~(RCP_ACC_BITS | RCP_FP_BIT);
+       /* Copy page access key and fetch protection bit to pgste */
+       pgste_val(pgste) |=
+               (unsigned long) (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56;
+       /* Transfer changed and referenced to kvm user bits */
+       pgste_val(pgste) |= bits << 45;         /* KVM_UR_BIT & KVM_UC_BIT */
+       /* Transfer changed & referenced to pte sofware bits */
+       pte_val(*ptep) |= bits << 1;            /* _PAGE_SWR & _PAGE_SWC */
+#endif
+       return pgste;
+
+}
+
+static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
+{
+#ifdef CONFIG_PGSTE
+       int young;
+
+       young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK);
+       /* Transfer page referenced bit to pte software bit (host view) */
+       if (young || (pgste_val(pgste) & RCP_HR_BIT))
+               pte_val(*ptep) |= _PAGE_SWR;
+       /* Clear host referenced bit in pgste. */
+       pgste_val(pgste) &= ~RCP_HR_BIT;
+       /* Transfer page referenced bit to guest bit in pgste */
+       pgste_val(pgste) |= (unsigned long) young << 50; /* set RCP_GR_BIT */
 #endif
+       return pgste;
+
+}
+
+static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste)
+{
+#ifdef CONFIG_PGSTE
+       unsigned long address;
+       unsigned long okey, nkey;
+
+       address = pte_val(*ptep) & PAGE_MASK;
+       okey = nkey = page_get_storage_key(address);
+       nkey &= ~(_PAGE_ACC_BITS | _PAGE_FP_BIT);
+       /* Set page access key and fetch protection bit from pgste */
+       nkey |= (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56;
+       if (okey != nkey)
+               page_set_storage_key(address, nkey, 1);
+#endif
+}
+
+/*
+ * Certain architectures need to do special things when PTEs
+ * within a page table are directly modified.  Thus, the following
+ * hook is made available.
+ */
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+                             pte_t *ptep, pte_t entry)
+{
+       pgste_t pgste;
+
+       if (mm_has_pgste(mm)) {
+               pgste = pgste_get_lock(ptep);
+               pgste_set_pte(ptep, pgste);
+               *ptep = entry;
+               pgste_set_unlock(ptep, pgste);
+       } else
+               *ptep = entry;
 }
 
 /*
@@ -627,19 +684,19 @@ static inline int pte_write(pte_t pte)
 
 static inline int pte_dirty(pte_t pte)
 {
-       /* A pte is neither clean nor dirty on s/390. The dirty bit
-        * is in the storage key. See page_test_and_clear_dirty for
-        * details.
-        */
+#ifdef CONFIG_PGSTE
+       if (pte_val(pte) & _PAGE_SWC)
+               return 1;
+#endif
        return 0;
 }
 
 static inline int pte_young(pte_t pte)
 {
-       /* A pte is neither young nor old on s/390. The young bit
-        * is in the storage key. See page_test_and_clear_young for
-        * details.
-        */
+#ifdef CONFIG_PGSTE
+       if (pte_val(pte) & _PAGE_SWR)
+               return 1;
+#endif
        return 0;
 }
 
@@ -647,64 +704,30 @@ static inline int pte_young(pte_t pte)
  * pgd/pmd/pte modification functions
  */
 
-#ifndef __s390x__
-
-#define pgd_clear(pgd)         do { } while (0)
-#define pud_clear(pud)         do { } while (0)
-
-#else /* __s390x__ */
-
-static inline void pgd_clear_kernel(pgd_t * pgd)
+static inline void pgd_clear(pgd_t *pgd)
 {
+#ifdef __s390x__
        if ((pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R2)
                pgd_val(*pgd) = _REGION2_ENTRY_EMPTY;
+#endif
 }
 
-static inline void pgd_clear(pgd_t * pgd)
-{
-       pgd_t *shadow = get_shadow_table(pgd);
-
-       pgd_clear_kernel(pgd);
-       if (shadow)
-               pgd_clear_kernel(shadow);
-}
-
-static inline void pud_clear_kernel(pud_t *pud)
+static inline void pud_clear(pud_t *pud)
 {
+#ifdef __s390x__
        if ((pud_val(*pud) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3)
                pud_val(*pud) = _REGION3_ENTRY_EMPTY;
+#endif
 }
 
-static inline void pud_clear(pud_t *pud)
-{
-       pud_t *shadow = get_shadow_table(pud);
-
-       pud_clear_kernel(pud);
-       if (shadow)
-               pud_clear_kernel(shadow);
-}
-
-#endif /* __s390x__ */
-
-static inline void pmd_clear_kernel(pmd_t * pmdp)
+static inline void pmd_clear(pmd_t *pmdp)
 {
        pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY;
 }
 
-static inline void pmd_clear(pmd_t *pmd)
-{
-       pmd_t *shadow = get_shadow_table(pmd);
-
-       pmd_clear_kernel(pmd);
-       if (shadow)
-               pmd_clear_kernel(shadow);
-}
-
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
        pte_val(*ptep) = _PAGE_TYPE_EMPTY;
-       if (mm->context.noexec)
-               pte_val(ptep[PTRS_PER_PTE]) = _PAGE_TYPE_EMPTY;
 }
 
 /*
@@ -734,35 +757,27 @@ static inline pte_t pte_mkwrite(pte_t pte)
 
 static inline pte_t pte_mkclean(pte_t pte)
 {
-       /* The only user of pte_mkclean is the fork() code.
-          We must *not* clear the *physical* page dirty bit
-          just because fork() wants to clear the dirty bit in
-          *one* of the page's mappings.  So we just do nothing. */
+#ifdef CONFIG_PGSTE
+       pte_val(pte) &= ~_PAGE_SWC;
+#endif
        return pte;
 }
 
 static inline pte_t pte_mkdirty(pte_t pte)
 {
-       /* We do not explicitly set the dirty bit because the
-        * sske instruction is slow. It is faster to let the
-        * next instruction set the dirty bit.
-        */
        return pte;
 }
 
 static inline pte_t pte_mkold(pte_t pte)
 {
-       /* S/390 doesn't keep its dirty/referenced bit in the pte.
-        * There is no point in clearing the real referenced bit.
-        */
+#ifdef CONFIG_PGSTE
+       pte_val(pte) &= ~_PAGE_SWR;
+#endif
        return pte;
 }
 
 static inline pte_t pte_mkyoung(pte_t pte)
 {
-       /* S/390 doesn't keep its dirty/referenced bit in the pte.
-        * There is no point in setting the real referenced bit.
-        */
        return pte;
 }
 
@@ -800,62 +815,60 @@ static inline pte_t pte_mkhuge(pte_t pte)
 }
 #endif
 
-#ifdef CONFIG_PGSTE
 /*
- * Get (and clear) the user dirty bit for a PTE.
+ * Get (and clear) the user dirty bit for a pte.
  */
-static inline int kvm_s390_test_and_clear_page_dirty(struct mm_struct *mm,
-                                                    pte_t *ptep)
+static inline int ptep_test_and_clear_user_dirty(struct mm_struct *mm,
+                                                pte_t *ptep)
 {
-       int dirty;
-       unsigned long *pgste;
-       struct page *page;
-       unsigned int skey;
-
-       if (!mm->context.has_pgste)
-               return -EINVAL;
-       rcp_lock(ptep);
-       pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
-       page = virt_to_page(pte_val(*ptep));
-       skey = page_get_storage_key(page_to_phys(page));
-       if (skey & _PAGE_CHANGED) {
-               set_bit_simple(RCP_GC_BIT, pgste);
-               set_bit_simple(KVM_UD_BIT, pgste);
+       pgste_t pgste;
+       int dirty = 0;
+
+       if (mm_has_pgste(mm)) {
+               pgste = pgste_get_lock(ptep);
+               pgste = pgste_update_all(ptep, pgste);
+               dirty = !!(pgste_val(pgste) & KVM_UC_BIT);
+               pgste_val(pgste) &= ~KVM_UC_BIT;
+               pgste_set_unlock(ptep, pgste);
+               return dirty;
        }
-       if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) {
-               SetPageDirty(page);
-               set_bit_simple(KVM_UD_BIT, pgste);
-       }
-       dirty = test_and_clear_bit_simple(KVM_UD_BIT, pgste);
-       if (skey & _PAGE_CHANGED)
-               page_clear_dirty(page, 1);
-       rcp_unlock(ptep);
        return dirty;
 }
-#endif
+
+/*
+ * Get (and clear) the user referenced bit for a pte.
+ */
+static inline int ptep_test_and_clear_user_young(struct mm_struct *mm,
+                                                pte_t *ptep)
+{
+       pgste_t pgste;
+       int young = 0;
+
+       if (mm_has_pgste(mm)) {
+               pgste = pgste_get_lock(ptep);
+               pgste = pgste_update_young(ptep, pgste);
+               young = !!(pgste_val(pgste) & KVM_UR_BIT);
+               pgste_val(pgste) &= ~KVM_UR_BIT;
+               pgste_set_unlock(ptep, pgste);
+       }
+       return young;
+}
 
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
                                            unsigned long addr, pte_t *ptep)
 {
-#ifdef CONFIG_PGSTE
-       unsigned long physpage;
-       int young;
-       unsigned long *pgste;
+       pgste_t pgste;
+       pte_t pte;
 
-       if (!vma->vm_mm->context.has_pgste)
-               return 0;
-       physpage = pte_val(*ptep) & PAGE_MASK;
-       pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
-
-       young = ((page_get_storage_key(physpage) & _PAGE_REFERENCED) != 0);
-       rcp_lock(ptep);
-       if (young)
-               set_bit_simple(RCP_GR_BIT, pgste);
-       young |= test_and_clear_bit_simple(RCP_HR_BIT, pgste);
-       rcp_unlock(ptep);
-       return young;
-#endif
+       if (mm_has_pgste(vma->vm_mm)) {
+               pgste = pgste_get_lock(ptep);
+               pgste = pgste_update_young(ptep, pgste);
+               pte = *ptep;
+               *ptep = pte_mkold(pte);
+               pgste_set_unlock(ptep, pgste);
+               return pte_young(pte);
+       }
        return 0;
 }
 
@@ -867,10 +880,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
         * On s390 reference bits are in storage key and never in TLB
         * With virtualization we handle the reference bit, without we
         * we can simply return */
-#ifdef CONFIG_PGSTE
        return ptep_test_and_clear_young(vma, address, ptep);
-#endif
-       return 0;
 }
 
 static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
@@ -890,25 +900,6 @@ static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
        }
 }
 
-static inline void ptep_invalidate(struct mm_struct *mm,
-                                  unsigned long address, pte_t *ptep)
-{
-       if (mm->context.has_pgste) {
-               rcp_lock(ptep);
-               __ptep_ipte(address, ptep);
-               ptep_rcp_copy(ptep);
-               pte_val(*ptep) = _PAGE_TYPE_EMPTY;
-               rcp_unlock(ptep);
-               return;
-       }
-       __ptep_ipte(address, ptep);
-       pte_val(*ptep) = _PAGE_TYPE_EMPTY;
-       if (mm->context.noexec) {
-               __ptep_ipte(address, ptep + PTRS_PER_PTE);
-               pte_val(*(ptep + PTRS_PER_PTE)) = _PAGE_TYPE_EMPTY;
-       }
-}
-
 /*
  * This is hard to understand. ptep_get_and_clear and ptep_clear_flush
  * both clear the TLB for the unmapped pte. The reason is that
@@ -923,24 +914,72 @@ static inline void ptep_invalidate(struct mm_struct *mm,
  * is a nop.
  */
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
-#define ptep_get_and_clear(__mm, __address, __ptep)                    \
-({                                                                     \
-       pte_t __pte = *(__ptep);                                        \
-       (__mm)->context.flush_mm = 1;                                   \
-       if (atomic_read(&(__mm)->context.attach_count) > 1 ||           \
-           (__mm) != current->active_mm)                               \
-               ptep_invalidate(__mm, __address, __ptep);               \
-       else                                                            \
-               pte_clear((__mm), (__address), (__ptep));               \
-       __pte;                                                          \
-})
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
+                                      unsigned long address, pte_t *ptep)
+{
+       pgste_t pgste;
+       pte_t pte;
+
+       mm->context.flush_mm = 1;
+       if (mm_has_pgste(mm))
+               pgste = pgste_get_lock(ptep);
+
+       pte = *ptep;
+       if (!mm_exclusive(mm))
+               __ptep_ipte(address, ptep);
+       pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+
+       if (mm_has_pgste(mm)) {
+               pgste = pgste_update_all(&pte, pgste);
+               pgste_set_unlock(ptep, pgste);
+       }
+       return pte;
+}
+
+#define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION
+static inline pte_t ptep_modify_prot_start(struct mm_struct *mm,
+                                          unsigned long address,
+                                          pte_t *ptep)
+{
+       pte_t pte;
+
+       mm->context.flush_mm = 1;
+       if (mm_has_pgste(mm))
+               pgste_get_lock(ptep);
+
+       pte = *ptep;
+       if (!mm_exclusive(mm))
+               __ptep_ipte(address, ptep);
+       return pte;
+}
+
+static inline void ptep_modify_prot_commit(struct mm_struct *mm,
+                                          unsigned long address,
+                                          pte_t *ptep, pte_t pte)
+{
+       *ptep = pte;
+       if (mm_has_pgste(mm))
+               pgste_set_unlock(ptep, *(pgste_t *)(ptep + PTRS_PER_PTE));
+}
 
 #define __HAVE_ARCH_PTEP_CLEAR_FLUSH
 static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
                                     unsigned long address, pte_t *ptep)
 {
-       pte_t pte = *ptep;
-       ptep_invalidate(vma->vm_mm, address, ptep);
+       pgste_t pgste;
+       pte_t pte;
+
+       if (mm_has_pgste(vma->vm_mm))
+               pgste = pgste_get_lock(ptep);
+
+       pte = *ptep;
+       __ptep_ipte(address, ptep);
+       pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+
+       if (mm_has_pgste(vma->vm_mm)) {
+               pgste = pgste_update_all(&pte, pgste);
+               pgste_set_unlock(ptep, pgste);
+       }
        return pte;
 }
 
@@ -953,76 +992,67 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
  */
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
 static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
-                                           unsigned long addr,
+                                           unsigned long address,
                                            pte_t *ptep, int full)
 {
-       pte_t pte = *ptep;
+       pgste_t pgste;
+       pte_t pte;
+
+       if (mm_has_pgste(mm))
+               pgste = pgste_get_lock(ptep);
+
+       pte = *ptep;
+       if (!full)
+               __ptep_ipte(address, ptep);
+       pte_val(*ptep) = _PAGE_TYPE_EMPTY;
 
-       if (full)
-               pte_clear(mm, addr, ptep);
-       else
-               ptep_invalidate(mm, addr, ptep);
+       if (mm_has_pgste(mm)) {
+               pgste = pgste_update_all(&pte, pgste);
+               pgste_set_unlock(ptep, pgste);
+       }
        return pte;
 }
 
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
-#define ptep_set_wrprotect(__mm, __addr, __ptep)                       \
-({                                                                     \
-       pte_t __pte = *(__ptep);                                        \
-       if (pte_write(__pte)) {                                         \
-               (__mm)->context.flush_mm = 1;                           \
-               if (atomic_read(&(__mm)->context.attach_count) > 1 ||   \
-                   (__mm) != current->active_mm)                       \
-                       ptep_invalidate(__mm, __addr, __ptep);          \
-               set_pte_at(__mm, __addr, __ptep, pte_wrprotect(__pte)); \
-       }                                                               \
-})
+static inline pte_t ptep_set_wrprotect(struct mm_struct *mm,
+                                      unsigned long address, pte_t *ptep)
+{
+       pgste_t pgste;
+       pte_t pte = *ptep;
 
-#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
-#define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \
-({                                                                     \
-       int __changed = !pte_same(*(__ptep), __entry);                  \
-       if (__changed) {                                                \
-               ptep_invalidate((__vma)->vm_mm, __addr, __ptep);        \
-               set_pte_at((__vma)->vm_mm, __addr, __ptep, __entry);    \
-       }                                                               \
-       __changed;                                                      \
-})
+       if (pte_write(pte)) {
+               mm->context.flush_mm = 1;
+               if (mm_has_pgste(mm))
+                       pgste = pgste_get_lock(ptep);
 
-/*
- * Test and clear dirty bit in storage key.
- * We can't clear the changed bit atomically. This is a potential
- * race against modification of the referenced bit. This function
- * should therefore only be called if it is not mapped in any
- * address space.
- */
-#define __HAVE_ARCH_PAGE_TEST_DIRTY
-static inline int page_test_dirty(struct page *page)
-{
-       return (page_get_storage_key(page_to_phys(page)) & _PAGE_CHANGED) != 0;
-}
+               if (!mm_exclusive(mm))
+                       __ptep_ipte(address, ptep);
+               *ptep = pte_wrprotect(pte);
 
-#define __HAVE_ARCH_PAGE_CLEAR_DIRTY
-static inline void page_clear_dirty(struct page *page, int mapped)
-{
-       page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY, mapped);
+               if (mm_has_pgste(mm))
+                       pgste_set_unlock(ptep, pgste);
+       }
+       return pte;
 }
 
-/*
- * Test and clear referenced bit in storage key.
- */
-#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
-static inline int page_test_and_clear_young(struct page *page)
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+static inline int ptep_set_access_flags(struct vm_area_struct *vma,
+                                       unsigned long address, pte_t *ptep,
+                                       pte_t entry, int dirty)
 {
-       unsigned long physpage = page_to_phys(page);
-       int ccode;
-
-       asm volatile(
-               "       rrbe    0,%1\n"
-               "       ipm     %0\n"
-               "       srl     %0,28\n"
-               : "=d" (ccode) : "a" (physpage) : "cc" );
-       return ccode & 2;
+       pgste_t pgste;
+
+       if (pte_same(*ptep, entry))
+               return 0;
+       if (mm_has_pgste(vma->vm_mm))
+               pgste = pgste_get_lock(ptep);
+
+       __ptep_ipte(address, ptep);
+       *ptep = entry;
+
+       if (mm_has_pgste(vma->vm_mm))
+               pgste_set_unlock(ptep, pgste);
+       return 1;
 }
 
 /*
index 2c79b64162713b63e95b7a80b825e29660813d91..1300c30253349bdc03bc7273441790209ff3c61c 100644 (file)
@@ -84,6 +84,7 @@ struct thread_struct {
        struct per_event per_event;     /* Cause of the last PER trap */
         /* pfault_wait is used to block the process on a pfault event */
        unsigned long pfault_wait;
+       struct list_head list;
 };
 
 typedef struct thread_struct thread_struct;
index 350e7ee5952daaa025ed239189a1df2f78f9142d..15c97625df8d3f0411c17a44c999b117ef1ff49d 100644 (file)
@@ -139,110 +139,47 @@ struct slib {
        struct slibe slibe[QDIO_MAX_BUFFERS_PER_Q];
 } __attribute__ ((packed, aligned(2048)));
 
-/**
- * struct sbal_flags - storage block address list flags
- * @last: last entry
- * @cont: contiguous storage
- * @frag: fragmentation
- */
-struct sbal_flags {
-       u8      : 1;
-       u8 last : 1;
-       u8 cont : 1;
-       u8      : 1;
-       u8 frag : 2;
-       u8      : 2;
-} __attribute__ ((packed));
-
-#define SBAL_FLAGS_FIRST_FRAG          0x04000000UL
-#define SBAL_FLAGS_MIDDLE_FRAG         0x08000000UL
-#define SBAL_FLAGS_LAST_FRAG           0x0c000000UL
-#define SBAL_FLAGS_LAST_ENTRY          0x40000000UL
-#define SBAL_FLAGS_CONTIGUOUS          0x20000000UL
+#define SBAL_EFLAGS_LAST_ENTRY         0x40
+#define SBAL_EFLAGS_CONTIGUOUS         0x20
+#define SBAL_EFLAGS_FIRST_FRAG         0x04
+#define SBAL_EFLAGS_MIDDLE_FRAG                0x08
+#define SBAL_EFLAGS_LAST_FRAG          0x0c
+#define SBAL_EFLAGS_MASK               0x6f
 
-#define SBAL_FLAGS0_DATA_CONTINUATION  0x20UL
+#define SBAL_SFLAGS0_PCI_REQ           0x40
+#define SBAL_SFLAGS0_DATA_CONTINUATION 0x20
 
 /* Awesome OpenFCP extensions */
-#define SBAL_FLAGS0_TYPE_STATUS                0x00UL
-#define SBAL_FLAGS0_TYPE_WRITE         0x08UL
-#define SBAL_FLAGS0_TYPE_READ          0x10UL
-#define SBAL_FLAGS0_TYPE_WRITE_READ    0x18UL
-#define SBAL_FLAGS0_MORE_SBALS         0x04UL
-#define SBAL_FLAGS0_COMMAND            0x02UL
-#define SBAL_FLAGS0_LAST_SBAL          0x00UL
-#define SBAL_FLAGS0_ONLY_SBAL          SBAL_FLAGS0_COMMAND
-#define SBAL_FLAGS0_MIDDLE_SBAL                SBAL_FLAGS0_MORE_SBALS
-#define SBAL_FLAGS0_FIRST_SBAL SBAL_FLAGS0_MORE_SBALS | SBAL_FLAGS0_COMMAND
-#define SBAL_FLAGS0_PCI                        0x40
-
-/**
- * struct sbal_sbalf_0 - sbal flags for sbale 0
- * @pci: PCI indicator
- * @cont: data continuation
- * @sbtype: storage-block type (FCP)
- */
-struct sbal_sbalf_0 {
-       u8        : 1;
-       u8 pci    : 1;
-       u8 cont   : 1;
-       u8 sbtype : 2;
-       u8        : 3;
-} __attribute__ ((packed));
-
-/**
- * struct sbal_sbalf_1 - sbal flags for sbale 1
- * @key: storage key
- */
-struct sbal_sbalf_1 {
-       u8     : 4;
-       u8 key : 4;
-} __attribute__ ((packed));
-
-/**
- * struct sbal_sbalf_14 - sbal flags for sbale 14
- * @erridx: error index
- */
-struct sbal_sbalf_14 {
-       u8        : 4;
-       u8 erridx : 4;
-} __attribute__ ((packed));
-
-/**
- * struct sbal_sbalf_15 - sbal flags for sbale 15
- * @reason: reason for error state
- */
-struct sbal_sbalf_15 {
-       u8 reason;
-} __attribute__ ((packed));
-
-/**
- * union sbal_sbalf - storage block address list flags
- * @i0: sbalf0
- * @i1: sbalf1
- * @i14: sbalf14
- * @i15: sblaf15
- * @value: raw value
- */
-union sbal_sbalf {
-       struct sbal_sbalf_0  i0;
-       struct sbal_sbalf_1  i1;
-       struct sbal_sbalf_14 i14;
-       struct sbal_sbalf_15 i15;
-       u8 value;
-};
+#define SBAL_SFLAGS0_TYPE_STATUS       0x00
+#define SBAL_SFLAGS0_TYPE_WRITE                0x08
+#define SBAL_SFLAGS0_TYPE_READ         0x10
+#define SBAL_SFLAGS0_TYPE_WRITE_READ   0x18
+#define SBAL_SFLAGS0_MORE_SBALS                0x04
+#define SBAL_SFLAGS0_COMMAND           0x02
+#define SBAL_SFLAGS0_LAST_SBAL         0x00
+#define SBAL_SFLAGS0_ONLY_SBAL         SBAL_SFLAGS0_COMMAND
+#define SBAL_SFLAGS0_MIDDLE_SBAL       SBAL_SFLAGS0_MORE_SBALS
+#define SBAL_SFLAGS0_FIRST_SBAL (SBAL_SFLAGS0_MORE_SBALS | SBAL_SFLAGS0_COMMAND)
 
 /**
  * struct qdio_buffer_element - SBAL entry
- * @flags: flags
+ * @eflags: SBAL entry flags
+ * @scount: SBAL count
+ * @sflags: whole SBAL flags
  * @length: length
  * @addr: address
 */
 struct qdio_buffer_element {
-       u32 flags;
+       u8 eflags;
+       /* private: */
+       u8 res1;
+       /* public: */
+       u8 scount;
+       u8 sflags;
        u32 length;
 #ifdef CONFIG_32BIT
        /* private: */
-       void *reserved;
+       void *res2;
        /* public: */
 #endif
        void *addr;
diff --git a/arch/s390/include/asm/s390_ext.h b/arch/s390/include/asm/s390_ext.h
deleted file mode 100644 (file)
index 080876d..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- *    Copyright IBM Corp. 1999,2010
- *    Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>,
- *              Martin Schwidefsky <schwidefsky@de.ibm.com>,
- */
-
-#ifndef _S390_EXTINT_H
-#define _S390_EXTINT_H
-
-#include <linux/types.h>
-
-typedef void (*ext_int_handler_t)(unsigned int, unsigned int, unsigned long);
-
-int register_external_interrupt(__u16 code, ext_int_handler_t handler);
-int unregister_external_interrupt(__u16 code, ext_int_handler_t handler);
-
-#endif /* _S390_EXTINT_H */
diff --git a/arch/s390/include/asm/suspend.h b/arch/s390/include/asm/suspend.h
deleted file mode 100644 (file)
index dc75c61..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __ASM_S390_SUSPEND_H
-#define __ASM_S390_SUSPEND_H
-
-static inline int arch_prepare_suspend(void)
-{
-       return 0;
-}
-
-#endif
-
index 9074a54c4d10f843320ae85819895024dbf5d67f..c687a2c834626adb1f01cc24ae4f62713d83adaa 100644 (file)
 #include <linux/swap.h>
 #include <asm/processor.h>
 #include <asm/pgalloc.h>
-#include <asm/smp.h>
 #include <asm/tlbflush.h>
 
-#ifndef CONFIG_SMP
-#define TLB_NR_PTRS    1
-#else
-#define TLB_NR_PTRS    508
-#endif
-
 struct mmu_gather {
        struct mm_struct *mm;
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+       struct mmu_table_batch *batch;
+#endif
        unsigned int fullmm;
-       unsigned int nr_ptes;
-       unsigned int nr_pxds;
-       void *array[TLB_NR_PTRS];
+       unsigned int need_flush;
 };
 
-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+struct mmu_table_batch {
+       struct rcu_head         rcu;
+       unsigned int            nr;
+       void                    *tables[0];
+};
 
-static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm,
-                                               unsigned int full_mm_flush)
-{
-       struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
+#define MAX_TABLE_BATCH                \
+       ((PAGE_SIZE - sizeof(struct mmu_table_batch)) / sizeof(void *))
 
+extern void tlb_table_flush(struct mmu_gather *tlb);
+extern void tlb_remove_table(struct mmu_gather *tlb, void *table);
+#endif
+
+static inline void tlb_gather_mmu(struct mmu_gather *tlb,
+                                 struct mm_struct *mm,
+                                 unsigned int full_mm_flush)
+{
        tlb->mm = mm;
        tlb->fullmm = full_mm_flush;
-       tlb->nr_ptes = 0;
-       tlb->nr_pxds = TLB_NR_PTRS;
+       tlb->need_flush = 0;
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+       tlb->batch = NULL;
+#endif
        if (tlb->fullmm)
                __tlb_flush_mm(mm);
-       return tlb;
 }
 
-static inline void tlb_flush_mmu(struct mmu_gather *tlb,
-                                unsigned long start, unsigned long end)
+static inline void tlb_flush_mmu(struct mmu_gather *tlb)
 {
-       if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < TLB_NR_PTRS))
-               __tlb_flush_mm(tlb->mm);
-       while (tlb->nr_ptes > 0)
-               page_table_free_rcu(tlb->mm, tlb->array[--tlb->nr_ptes]);
-       while (tlb->nr_pxds < TLB_NR_PTRS)
-               crst_table_free_rcu(tlb->mm, tlb->array[tlb->nr_pxds++]);
+       if (!tlb->need_flush)
+               return;
+       tlb->need_flush = 0;
+       __tlb_flush_mm(tlb->mm);
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+       tlb_table_flush(tlb);
+#endif
 }
 
 static inline void tlb_finish_mmu(struct mmu_gather *tlb,
                                  unsigned long start, unsigned long end)
 {
-       tlb_flush_mmu(tlb, start, end);
-
-       rcu_table_freelist_finish();
-
-       /* keep the page table cache within bounds */
-       check_pgt_cache();
-
-       put_cpu_var(mmu_gathers);
+       tlb_flush_mmu(tlb);
 }
 
 /*
  * Release the page cache reference for a pte removed by
- * tlb_ptep_clear_flush. In both flush modes the tlb fo a page cache page
+ * tlb_ptep_clear_flush. In both flush modes the tlb for a page cache page
  * has already been freed, so just do free_page_and_swap_cache.
  */
+static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       free_page_and_swap_cache(page);
+       return 1; /* avoid calling tlb_flush_mmu */
+}
+
 static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
 {
        free_page_and_swap_cache(page);
@@ -100,12 +105,11 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
 static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
                                unsigned long address)
 {
-       if (!tlb->fullmm) {
-               tlb->array[tlb->nr_ptes++] = pte;
-               if (tlb->nr_ptes >= tlb->nr_pxds)
-                       tlb_flush_mmu(tlb, 0, 0);
-       } else
-               page_table_free(tlb->mm, (unsigned long *) pte);
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+       if (!tlb->fullmm)
+               return page_table_free_rcu(tlb, (unsigned long *) pte);
+#endif
+       page_table_free(tlb->mm, (unsigned long *) pte);
 }
 
 /*
@@ -121,12 +125,11 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
 #ifdef __s390x__
        if (tlb->mm->context.asce_limit <= (1UL << 31))
                return;
-       if (!tlb->fullmm) {
-               tlb->array[--tlb->nr_pxds] = pmd;
-               if (tlb->nr_ptes >= tlb->nr_pxds)
-                       tlb_flush_mmu(tlb, 0, 0);
-       } else
-               crst_table_free(tlb->mm, (unsigned long *) pmd);
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+       if (!tlb->fullmm)
+               return tlb_remove_table(tlb, pmd);
+#endif
+       crst_table_free(tlb->mm, (unsigned long *) pmd);
 #endif
 }
 
@@ -143,12 +146,11 @@ static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud,
 #ifdef __s390x__
        if (tlb->mm->context.asce_limit <= (1UL << 42))
                return;
-       if (!tlb->fullmm) {
-               tlb->array[--tlb->nr_pxds] = pud;
-               if (tlb->nr_ptes >= tlb->nr_pxds)
-                       tlb_flush_mmu(tlb, 0, 0);
-       } else
-               crst_table_free(tlb->mm, (unsigned long *) pud);
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+       if (!tlb->fullmm)
+               return tlb_remove_table(tlb, pud);
+#endif
+       crst_table_free(tlb->mm, (unsigned long *) pud);
 #endif
 }
 
index 29d5d6d4becc7e12a4a5a0b9801a0de554c44b68..b7a4f2eb00573388070f1dda84d6014b638103f8 100644 (file)
@@ -50,7 +50,7 @@ static inline void __tlb_flush_full(struct mm_struct *mm)
        /*
         * If the process only ran on the local cpu, do a local flush.
         */
-       local_cpumask = cpumask_of_cpu(smp_processor_id());
+       cpumask_copy(&local_cpumask, cpumask_of(smp_processor_id()));
        if (cpumask_equal(mm_cpumask(mm), &local_cpumask))
                __tlb_flush_local();
        else
@@ -80,16 +80,11 @@ static inline void __tlb_flush_mm(struct mm_struct * mm)
         * on all cpus instead of doing a local flush if the mm
         * only ran on the local cpu.
         */
-       if (MACHINE_HAS_IDTE) {
-               if (mm->context.noexec)
-                       __tlb_flush_idte((unsigned long)
-                                        get_shadow_table(mm->pgd) |
-                                        mm->context.asce_bits);
+       if (MACHINE_HAS_IDTE)
                __tlb_flush_idte((unsigned long) mm->pgd |
                                 mm->context.asce_bits);
-               return;
-       }
-       __tlb_flush_full(mm);
+       else
+               __tlb_flush_full(mm);
 }
 
 static inline void __tlb_flush_mm_cond(struct mm_struct * mm)
index c5338834ddbdfb6614be4d8079afcef4deda1ca2..005d77d8ae2ab04c56f10d6f931e8aac3dddcff7 100644 (file)
@@ -7,7 +7,7 @@
 extern unsigned char cpu_core_id[NR_CPUS];
 extern cpumask_t cpu_core_map[NR_CPUS];
 
-static inline const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
+static inline const struct cpumask *cpu_coregroup_mask(int cpu)
 {
        return &cpu_core_map[cpu];
 }
@@ -21,7 +21,7 @@ static inline const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
 extern unsigned char cpu_book_id[NR_CPUS];
 extern cpumask_t cpu_book_map[NR_CPUS];
 
-static inline const struct cpumask *cpu_book_mask(unsigned int cpu)
+static inline const struct cpumask *cpu_book_mask(int cpu)
 {
        return &cpu_book_map[cpu];
 }
index 2d9ea11f919ad2a1565091d3b861da2d2da09de5..2b23885e81e9a40019cc0d0e03748f3d4bbf670e 100644 (file)
 
 #define segment_eq(a,b) ((a).ar4 == (b).ar4)
 
+#define __access_ok(addr, size)        \
+({                             \
+       __chk_user_ptr(addr);   \
+       1;                      \
+})
 
-static inline int __access_ok(const void __user *addr, unsigned long size)
-{
-       return 1;
-}
-#define access_ok(type,addr,size) __access_ok(addr,size)
+#define access_ok(type, addr, size) __access_ok(addr, size)
 
 /*
  * The exception table consists of pairs of addresses: the first is the
index e821525723775c8f2ca745daffddd21f91f62d41..404bdb9671b4f5c8d03d2391e93abf26e5b38a59 100644 (file)
 #define __NR_open_by_handle_at 336
 #define __NR_clock_adjtime     337
 #define __NR_syncfs            338
-#define NR_syscalls 339
+#define __NR_setns             339
+#define NR_syscalls 340
 
 /* 
  * There are some system calls that are not present on 64 bit, some
 
 /* Ignore system calls that are also reachable via sys_socket */
 #define __IGNORE_recvmmsg
+#define __IGNORE_sendmmsg
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 5ff15dacb5718c04973d4660c9a18478afd1c8f8..df3732249baafa3f0c30474d26da5243412890d1 100644 (file)
@@ -20,10 +20,10 @@ CFLAGS_ptrace.o             += -DUTS_MACHINE='"$(UTS_MACHINE)"'
 
 CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
 
-obj-y  :=  bitmap.o traps.o time.o process.o base.o early.o setup.o \
-           processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
-           s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o \
-           vdso.o vtime.o sysinfo.o nmi.o sclp.o jump_label.o
+obj-y  :=  bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o \
+           processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o \
+           debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o \
+           sysinfo.o jump_label.o
 
 obj-y  += $(if $(CONFIG_64BIT),entry64.o,entry.o)
 obj-y  += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
index fe03c140002a56ea8643ee17ab481381a749ce2b..edfbd17d70826b3c761b0cd8f2e46d7c24a58781 100644 (file)
@@ -124,13 +124,11 @@ int main(void)
        DEFINE(__LC_LAST_UPDATE_TIMER, offsetof(struct _lowcore, last_update_timer));
        DEFINE(__LC_LAST_UPDATE_CLOCK, offsetof(struct _lowcore, last_update_clock));
        DEFINE(__LC_CURRENT, offsetof(struct _lowcore, current_task));
+       DEFINE(__LC_CURRENT_PID, offsetof(struct _lowcore, current_pid));
        DEFINE(__LC_THREAD_INFO, offsetof(struct _lowcore, thread_info));
        DEFINE(__LC_KERNEL_STACK, offsetof(struct _lowcore, kernel_stack));
        DEFINE(__LC_ASYNC_STACK, offsetof(struct _lowcore, async_stack));
        DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack));
-       DEFINE(__LC_KERNEL_ASCE, offsetof(struct _lowcore, kernel_asce));
-       DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce));
-       DEFINE(__LC_USER_EXEC_ASCE, offsetof(struct _lowcore, user_exec_asce));
        DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock));
        DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));
        DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags));
index 1dc96ea08fa89283c12e4c2240af06efa9d0239a..1f5eb789c3a78e061c0f957e0f31089b01765342 100644 (file)
@@ -1904,3 +1904,9 @@ compat_sys_clock_adjtime_wrapper:
 sys_syncfs_wrapper:
        lgfr    %r2,%r2                 # int
        jg      sys_syncfs
+
+       .globl  sys_setns_wrapper
+sys_setns_wrapper:
+       lgfr    %r2,%r2                 # int
+       lgfr    %r3,%r3                 # int
+       jg      sys_setns
index 3d4a78fc1adc3f6403eaf4ebc93f03211c5e1f86..1ca3d1d6a86ce5e4f3e15309f41cf6fe03300660 100644 (file)
@@ -30,9 +30,9 @@
 #include <asm/atomic.h>
 #include <asm/mathemu.h>
 #include <asm/cpcmd.h>
-#include <asm/s390_ext.h>
 #include <asm/lowcore.h>
 #include <asm/debug.h>
+#include <asm/irq.h>
 
 #ifndef CONFIG_64BIT
 #define ONELONG "%08lx: "
index 1b67fc6ebdc25f1407e569f3114bc3cb4827fd72..0476174dfff59695ee00f9985e6ebadb6da05b9a 100644 (file)
@@ -212,6 +212,7 @@ __switch_to:
        lctl    %c4,%c4,__TASK_pid(%r3)         # load pid to control reg. 4
        lm      %r6,%r15,__SF_GPRS(%r15)        # load gprs of next task
        st      %r3,__LC_CURRENT                # store task struct of next
+       mvc     __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next
        st      %r5,__LC_THREAD_INFO            # store thread info of next
        ahi     %r5,STACK_SIZE                  # end of kernel stack of next
        st      %r5,__LC_KERNEL_STACK           # store end of kernel stack
index 9fd864563499bb7e46f0cd85d4a03550b32a15ac..d61967e2eab01582b9509db83ebeba935ec16a3a 100644 (file)
@@ -220,6 +220,7 @@ __switch_to:
        lctl    %c4,%c4,__TASK_pid(%r3)         # load pid to control reg. 4
        lmg     %r6,%r15,__SF_GPRS(%r15)        # load gprs of next task
        stg     %r3,__LC_CURRENT                # store task struct of next
+       mvc     __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next
        stg     %r5,__LC_THREAD_INFO            # store thread info of next
        aghi    %r5,STACK_SIZE                  # end of kernel stack of next
        stg     %r5,__LC_KERNEL_STACK           # store end of kernel stack
index ea5099c9709c1213cc16f7b5ab2fc8a74372de09..e3264f6a9720515cc65df5784731d4452d32eca1 100644 (file)
@@ -1,19 +1,28 @@
 /*
- *    Copyright IBM Corp. 2004,2010
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
- *              Thomas Spatzier (tspat@de.ibm.com)
+ *    Copyright IBM Corp. 2004,2011
+ *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
+ *              Holger Smolinski <Holger.Smolinski@de.ibm.com>,
+ *              Thomas Spatzier <tspat@de.ibm.com>,
  *
  * This file contains interrupt related functions.
  */
 
-#include <linux/module.h>
-#include <linux/kernel.h>
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
-#include <linux/cpu.h>
 #include <linux/proc_fs.h>
 #include <linux/profile.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ftrace.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <asm/irq_regs.h>
+#include <asm/cputime.h>
+#include <asm/lowcore.h>
+#include <asm/irq.h>
+#include "entry.h"
 
 struct irq_class {
        char *name;
@@ -32,6 +41,7 @@ static const struct irq_class intrclass_names[] = {
        {.name = "VRT", .desc = "[EXT] Virtio" },
        {.name = "SCP", .desc = "[EXT] Service Call" },
        {.name = "IUC", .desc = "[EXT] IUCV" },
+       {.name = "CPM", .desc = "[EXT] CPU Measurement" },
        {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt" },
        {.name = "QDI", .desc = "[I/O] QDIO Interrupt" },
        {.name = "DAS", .desc = "[I/O] DASD" },
@@ -81,8 +91,7 @@ int show_interrupts(struct seq_file *p, void *v)
  * For compatibilty only. S/390 specific setup of interrupts et al. is done
  * much later in init_channel_subsystem().
  */
-void __init
-init_IRQ(void)
+void __init init_IRQ(void)
 {
        /* nothing... */
 }
@@ -133,3 +142,116 @@ void init_irq_proc(void)
        create_prof_cpu_mask(root_irq_dir);
 }
 #endif
+
+/*
+ * ext_int_hash[index] is the start of the list for all external interrupts
+ * that hash to this index. With the current set of external interrupts
+ * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console, 0x4000
+ * iucv and 0x2603 pfault) this is always the first element.
+ */
+
+struct ext_int_info {
+       struct ext_int_info *next;
+       ext_int_handler_t handler;
+       u16 code;
+};
+
+static struct ext_int_info *ext_int_hash[256];
+
+static inline int ext_hash(u16 code)
+{
+       return (code + (code >> 9)) & 0xff;
+}
+
+int register_external_interrupt(u16 code, ext_int_handler_t handler)
+{
+       struct ext_int_info *p;
+       int index;
+
+       p = kmalloc(sizeof(*p), GFP_ATOMIC);
+       if (!p)
+               return -ENOMEM;
+       p->code = code;
+       p->handler = handler;
+       index = ext_hash(code);
+       p->next = ext_int_hash[index];
+       ext_int_hash[index] = p;
+       return 0;
+}
+EXPORT_SYMBOL(register_external_interrupt);
+
+int unregister_external_interrupt(u16 code, ext_int_handler_t handler)
+{
+       struct ext_int_info *p, *q;
+       int index;
+
+       index = ext_hash(code);
+       q = NULL;
+       p = ext_int_hash[index];
+       while (p) {
+               if (p->code == code && p->handler == handler)
+                       break;
+               q = p;
+               p = p->next;
+       }
+       if (!p)
+               return -ENOENT;
+       if (q)
+               q->next = p->next;
+       else
+               ext_int_hash[index] = p->next;
+       kfree(p);
+       return 0;
+}
+EXPORT_SYMBOL(unregister_external_interrupt);
+
+void __irq_entry do_extint(struct pt_regs *regs, unsigned int ext_int_code,
+                          unsigned int param32, unsigned long param64)
+{
+       struct pt_regs *old_regs;
+       unsigned short code;
+       struct ext_int_info *p;
+       int index;
+
+       code = (unsigned short) ext_int_code;
+       old_regs = set_irq_regs(regs);
+       s390_idle_check(regs, S390_lowcore.int_clock,
+                       S390_lowcore.async_enter_timer);
+       irq_enter();
+       if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
+               /* Serve timer interrupts first. */
+               clock_comparator_work();
+       kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
+       if (code != 0x1004)
+               __get_cpu_var(s390_idle).nohz_delay = 1;
+       index = ext_hash(code);
+       for (p = ext_int_hash[index]; p; p = p->next) {
+               if (likely(p->code == code))
+                       p->handler(ext_int_code, param32, param64);
+       }
+       irq_exit();
+       set_irq_regs(old_regs);
+}
+
+static DEFINE_SPINLOCK(sc_irq_lock);
+static int sc_irq_refcount;
+
+void service_subclass_irq_register(void)
+{
+       spin_lock(&sc_irq_lock);
+       if (!sc_irq_refcount)
+               ctl_set_bit(0, 9);
+       sc_irq_refcount++;
+       spin_unlock(&sc_irq_lock);
+}
+EXPORT_SYMBOL(service_subclass_irq_register);
+
+void service_subclass_irq_unregister(void)
+{
+       spin_lock(&sc_irq_lock);
+       sc_irq_refcount--;
+       if (!sc_irq_refcount)
+               ctl_clear_bit(0, 9);
+       spin_unlock(&sc_irq_lock);
+}
+EXPORT_SYMBOL(service_subclass_irq_unregister);
index a895e69379f75233a84ab98681fbd9dc6421fbe1..541a7509faebd47f7b9d5a72a1f779c3efa2e1f4 100644 (file)
@@ -9,41 +9,26 @@
 
 #include <linux/compiler.h>
 #include <linux/cpu.h>
-#include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/fs.h>
 #include <linux/smp.h>
-#include <linux/stddef.h>
 #include <linux/slab.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/vmalloc.h>
-#include <linux/user.h>
 #include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/notifier.h>
 #include <linux/tick.h>
-#include <linux/elfcore.h>
-#include <linux/kernel_stat.h>
 #include <linux/personality.h>
 #include <linux/syscalls.h>
 #include <linux/compat.h>
 #include <linux/kprobes.h>
 #include <linux/random.h>
-#include <asm/compat.h>
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
+#include <linux/module.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/irq.h>
 #include <asm/timer.h>
 #include <asm/nmi.h>
+#include <asm/compat.h>
 #include <asm/smp.h>
 #include "entry.h"
 
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c
deleted file mode 100644 (file)
index 1850299..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- *    Copyright IBM Corp. 1999,2010
- *    Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>,
- *              Martin Schwidefsky <schwidefsky@de.ibm.com>,
- */
-
-#include <linux/kernel_stat.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/ftrace.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <asm/s390_ext.h>
-#include <asm/irq_regs.h>
-#include <asm/cputime.h>
-#include <asm/lowcore.h>
-#include <asm/irq.h>
-#include "entry.h"
-
-struct ext_int_info {
-       struct ext_int_info *next;
-       ext_int_handler_t handler;
-       __u16 code;
-};
-
-/*
- * ext_int_hash[index] is the start of the list for all external interrupts
- * that hash to this index. With the current set of external interrupts 
- * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console, 0x4000
- * iucv and 0x2603 pfault) this is always the first element. 
- */
-static struct ext_int_info *ext_int_hash[256];
-
-static inline int ext_hash(__u16 code)
-{
-       return (code + (code >> 9)) & 0xff;
-}
-
-int register_external_interrupt(__u16 code, ext_int_handler_t handler)
-{
-       struct ext_int_info *p;
-       int index;
-
-       p = kmalloc(sizeof(*p), GFP_ATOMIC);
-       if (!p)
-               return -ENOMEM;
-       p->code = code;
-       p->handler = handler;
-       index = ext_hash(code);
-       p->next = ext_int_hash[index];
-       ext_int_hash[index] = p;
-       return 0;
-}
-EXPORT_SYMBOL(register_external_interrupt);
-
-int unregister_external_interrupt(__u16 code, ext_int_handler_t handler)
-{
-       struct ext_int_info *p, *q;
-       int index;
-
-       index = ext_hash(code);
-       q = NULL;
-       p = ext_int_hash[index];
-       while (p) {
-               if (p->code == code && p->handler == handler)
-                       break;
-               q = p;
-               p = p->next;
-       }
-       if (!p)
-               return -ENOENT;
-       if (q)
-               q->next = p->next;
-       else
-               ext_int_hash[index] = p->next;
-       kfree(p);
-       return 0;
-}
-EXPORT_SYMBOL(unregister_external_interrupt);
-
-void __irq_entry do_extint(struct pt_regs *regs, unsigned int ext_int_code,
-                          unsigned int param32, unsigned long param64)
-{
-       struct pt_regs *old_regs;
-       unsigned short code;
-       struct ext_int_info *p;
-       int index;
-
-       code = (unsigned short) ext_int_code;
-       old_regs = set_irq_regs(regs);
-       s390_idle_check(regs, S390_lowcore.int_clock,
-                       S390_lowcore.async_enter_timer);
-       irq_enter();
-       if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
-               /* Serve timer interrupts first. */
-               clock_comparator_work();
-       kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
-       if (code != 0x1004)
-               __get_cpu_var(s390_idle).nohz_delay = 1;
-       index = ext_hash(code);
-       for (p = ext_int_hash[index]; p; p = p->next) {
-               if (likely(p->code == code))
-                       p->handler(ext_int_code, param32, param64);
-       }
-       irq_exit();
-       set_irq_regs(old_regs);
-}
index f5434d1ecb3166136eaf77e509d04e327b39165b..0c35dee10b00e93b005114c7b0d031531b7fc253 100644 (file)
@@ -305,8 +305,7 @@ static int set_amode_and_uaccess(unsigned long user_amode,
  */
 static int __init early_parse_switch_amode(char *p)
 {
-       if (user_mode != SECONDARY_SPACE_MODE)
-               user_mode = PRIMARY_SPACE_MODE;
+       user_mode = PRIMARY_SPACE_MODE;
        return 0;
 }
 early_param("switch_amode", early_parse_switch_amode);
@@ -315,10 +314,6 @@ static int __init early_parse_user_mode(char *p)
 {
        if (p && strcmp(p, "primary") == 0)
                user_mode = PRIMARY_SPACE_MODE;
-#ifdef CONFIG_S390_EXEC_PROTECT
-       else if (p && strcmp(p, "secondary") == 0)
-               user_mode = SECONDARY_SPACE_MODE;
-#endif
        else if (!p || strcmp(p, "home") == 0)
                user_mode = HOME_SPACE_MODE;
        else
@@ -327,31 +322,9 @@ static int __init early_parse_user_mode(char *p)
 }
 early_param("user_mode", early_parse_user_mode);
 
-#ifdef CONFIG_S390_EXEC_PROTECT
-/*
- * Enable execute protection?
- */
-static int __init early_parse_noexec(char *p)
-{
-       if (!strncmp(p, "off", 3))
-               return 0;
-       user_mode = SECONDARY_SPACE_MODE;
-       return 0;
-}
-early_param("noexec", early_parse_noexec);
-#endif /* CONFIG_S390_EXEC_PROTECT */
-
 static void setup_addressing_mode(void)
 {
-       if (user_mode == SECONDARY_SPACE_MODE) {
-               if (set_amode_and_uaccess(PSW_ASC_SECONDARY,
-                                         PSW32_ASC_SECONDARY))
-                       pr_info("Execute protection active, "
-                               "mvcos available\n");
-               else
-                       pr_info("Execute protection active, "
-                               "mvcos not available\n");
-       } else if (user_mode == PRIMARY_SPACE_MODE) {
+       if (user_mode == PRIMARY_SPACE_MODE) {
                if (set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY))
                        pr_info("Address spaces switched, "
                                "mvcos available\n");
index 63c7d9ff220d1545dea5d3cded8e96a3216af3aa..1d55c95f617c76d3f86784d34750395fb7573391 100644 (file)
@@ -44,7 +44,6 @@
 #include <asm/sigp.h>
 #include <asm/pgalloc.h>
 #include <asm/irq.h>
-#include <asm/s390_ext.h>
 #include <asm/cpcmd.h>
 #include <asm/tlbflush.h>
 #include <asm/timer.h>
@@ -263,7 +262,7 @@ void smp_ctl_set_bit(int cr, int bit)
 
        memset(&parms.orvals, 0, sizeof(parms.orvals));
        memset(&parms.andvals, 0xff, sizeof(parms.andvals));
-       parms.orvals[cr] = 1 << bit;
+       parms.orvals[cr] = 1UL << bit;
        on_each_cpu(smp_ctl_bit_callback, &parms, 1);
 }
 EXPORT_SYMBOL(smp_ctl_set_bit);
@@ -277,7 +276,7 @@ void smp_ctl_clear_bit(int cr, int bit)
 
        memset(&parms.orvals, 0, sizeof(parms.orvals));
        memset(&parms.andvals, 0xff, sizeof(parms.andvals));
-       parms.andvals[cr] = ~(1L << bit);
+       parms.andvals[cr] = ~(1UL << bit);
        on_each_cpu(smp_ctl_bit_callback, &parms, 1);
 }
 EXPORT_SYMBOL(smp_ctl_clear_bit);
@@ -335,7 +334,7 @@ static int smp_rescan_cpus_sigp(cpumask_t avail)
                smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN;
                if (!cpu_stopped(logical_cpu))
                        continue;
-               cpu_set(logical_cpu, cpu_present_map);
+               set_cpu_present(logical_cpu, true);
                smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED;
                logical_cpu = cpumask_next(logical_cpu, &avail);
                if (logical_cpu >= nr_cpu_ids)
@@ -367,7 +366,7 @@ static int smp_rescan_cpus_sclp(cpumask_t avail)
                        continue;
                __cpu_logical_map[logical_cpu] = cpu_id;
                smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN;
-               cpu_set(logical_cpu, cpu_present_map);
+               set_cpu_present(logical_cpu, true);
                if (cpu >= info->configured)
                        smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY;
                else
@@ -385,7 +384,7 @@ static int __smp_rescan_cpus(void)
 {
        cpumask_t avail;
 
-       cpus_xor(avail, cpu_possible_map, cpu_present_map);
+       cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask);
        if (smp_use_sigp_detection)
                return smp_rescan_cpus_sigp(avail);
        else
@@ -467,7 +466,7 @@ int __cpuinit start_secondary(void *cpuvoid)
        notify_cpu_starting(smp_processor_id());
        /* Mark this cpu as online */
        ipi_call_lock();
-       cpu_set(smp_processor_id(), cpu_online_map);
+       set_cpu_online(smp_processor_id(), true);
        ipi_call_unlock();
        /* Switch on interrupts */
        local_irq_enable();
@@ -644,7 +643,7 @@ int __cpu_disable(void)
        struct ec_creg_mask_parms cr_parms;
        int cpu = smp_processor_id();
 
-       cpu_clear(cpu, cpu_online_map);
+       set_cpu_online(cpu, false);
 
        /* Disable pfault pseudo page faults on this cpu. */
        pfault_fini();
@@ -654,8 +653,8 @@ int __cpu_disable(void)
 
        /* disable all external interrupts */
        cr_parms.orvals[0] = 0;
-       cr_parms.andvals[0] = ~(1 << 15 | 1 << 14 | 1 << 13 | 1 << 12 |
-                               1 << 11 | 1 << 10 | 1 <<  6 | 1 <<  4);
+       cr_parms.andvals[0] = ~(1 << 15 | 1 << 14 | 1 << 13 | 1 << 11 |
+                               1 << 10 | 1 <<  9 | 1 <<  6 | 1 <<  4);
        /* disable all I/O interrupts */
        cr_parms.orvals[6] = 0;
        cr_parms.andvals[6] = ~(1 << 31 | 1 << 30 | 1 << 29 | 1 << 28 |
@@ -681,7 +680,7 @@ void __cpu_die(unsigned int cpu)
        atomic_dec(&init_mm.context.attach_count);
 }
 
-void cpu_die(void)
+void __noreturn cpu_die(void)
 {
        idle_task_exit();
        while (sigp(smp_processor_id(), sigp_stop) == sigp_busy)
@@ -738,8 +737,8 @@ void __init smp_prepare_boot_cpu(void)
        BUG_ON(smp_processor_id() != 0);
 
        current_thread_info()->cpu = 0;
-       cpu_set(0, cpu_present_map);
-       cpu_set(0, cpu_online_map);
+       set_cpu_present(0, true);
+       set_cpu_online(0, true);
        S390_lowcore.percpu_offset = __per_cpu_offset[0];
        current_set[0] = current;
        smp_cpu_state[0] = CPU_STATE_CONFIGURED;
@@ -1016,21 +1015,21 @@ int __ref smp_rescan_cpus(void)
 
        get_online_cpus();
        mutex_lock(&smp_cpu_state_mutex);
-       newcpus = cpu_present_map;
+       cpumask_copy(&newcpus, cpu_present_mask);
        rc = __smp_rescan_cpus();
        if (rc)
                goto out;
-       cpus_andnot(newcpus, cpu_present_map, newcpus);
-       for_each_cpu_mask(cpu, newcpus) {
+       cpumask_andnot(&newcpus, cpu_present_mask, &newcpus);
+       for_each_cpu(cpu, &newcpus) {
                rc = smp_add_present_cpu(cpu);
                if (rc)
-                       cpu_clear(cpu, cpu_present_map);
+                       set_cpu_present(cpu, false);
        }
        rc = 0;
 out:
        mutex_unlock(&smp_cpu_state_mutex);
        put_online_cpus();
-       if (!cpus_empty(newcpus))
+       if (!cpumask_empty(&newcpus))
                topology_schedule_update();
        return rc;
 }
index 9c65fd4ddce0b56e4cffa97ecef4730ed42f78e4..6ee39ef8fe4add9f0c47dd33ba52aa3050842ead 100644 (file)
@@ -347,3 +347,4 @@ SYSCALL(sys_name_to_handle_at,sys_name_to_handle_at,sys_name_to_handle_at_wrappe
 SYSCALL(sys_open_by_handle_at,sys_open_by_handle_at,compat_sys_open_by_handle_at_wrapper)
 SYSCALL(sys_clock_adjtime,sys_clock_adjtime,compat_sys_clock_adjtime_wrapper)
 SYSCALL(sys_syncfs,sys_syncfs,sys_syncfs_wrapper)
+SYSCALL(sys_setns,sys_setns,sys_setns_wrapper)
index 87be655557aa48d4e0a0237e245977ffde9b0620..dff933065ab6ab688d9a3cc652f54d55b60dc79a 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/kprobes.h>
 #include <asm/uaccess.h>
 #include <asm/delay.h>
-#include <asm/s390_ext.h>
 #include <asm/div64.h>
 #include <asm/vdso.h>
 #include <asm/irq.h>
@@ -810,7 +809,7 @@ static int etr_sync_clock_stop(struct etr_aib *aib, int port)
        etr_sync.etr_port = port;
        get_online_cpus();
        atomic_set(&etr_sync.cpus, num_online_cpus() - 1);
-       rc = stop_machine(etr_sync_clock, &etr_sync, &cpu_online_map);
+       rc = stop_machine(etr_sync_clock, &etr_sync, cpu_online_mask);
        put_online_cpus();
        return rc;
 }
@@ -1579,7 +1578,7 @@ static void stp_work_fn(struct work_struct *work)
        memset(&stp_sync, 0, sizeof(stp_sync));
        get_online_cpus();
        atomic_set(&stp_sync.cpus, num_online_cpus() - 1);
-       stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map);
+       stop_machine(stp_sync_clock, &stp_sync, cpu_online_mask);
        put_online_cpus();
 
        if (!check_sync_clock())
index 94b06c31fc8a389c752bcefe843d237ed1871a1a..0cd340b72632c4a42fc19d43615e66f76a0c3a7e 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/smp.h>
 #include <linux/cpuset.h>
 #include <asm/delay.h>
-#include <asm/s390_ext.h>
 
 #define PTF_HORIZONTAL (0UL)
 #define PTF_VERTICAL   (1UL)
@@ -52,20 +51,20 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
 {
        cpumask_t mask;
 
-       cpus_clear(mask);
+       cpumask_clear(&mask);
        if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) {
                cpumask_copy(&mask, cpumask_of(cpu));
                return mask;
        }
        while (info) {
-               if (cpu_isset(cpu, info->mask)) {
+               if (cpumask_test_cpu(cpu, &info->mask)) {
                        mask = info->mask;
                        break;
                }
                info = info->next;
        }
-       if (cpus_empty(mask))
-               mask = cpumask_of_cpu(cpu);
+       if (cpumask_empty(&mask))
+               cpumask_copy(&mask, cpumask_of(cpu));
        return mask;
 }
 
@@ -85,10 +84,10 @@ static void add_cpus_to_mask(struct topology_cpu *tl_cpu,
                        if (cpu_logical_map(lcpu) != rcpu)
                                continue;
 #ifdef CONFIG_SCHED_BOOK
-                       cpu_set(lcpu, book->mask);
+                       cpumask_set_cpu(lcpu, &book->mask);
                        cpu_book_id[lcpu] = book->id;
 #endif
-                       cpu_set(lcpu, core->mask);
+                       cpumask_set_cpu(lcpu, &core->mask);
                        cpu_core_id[lcpu] = core->id;
                        smp_cpu_polarization[lcpu] = tl_cpu->pp;
                }
@@ -101,13 +100,13 @@ static void clear_masks(void)
 
        info = &core_info;
        while (info) {
-               cpus_clear(info->mask);
+               cpumask_clear(&info->mask);
                info = info->next;
        }
 #ifdef CONFIG_SCHED_BOOK
        info = &book_info;
        while (info) {
-               cpus_clear(info->mask);
+               cpumask_clear(&info->mask);
                info = info->next;
        }
 #endif
index b5a4a739b477424d4c9217ebd3bcaf4ba56ddbf8..a65d2e82f61d56813851d293436c697309515cda 100644 (file)
@@ -39,7 +39,6 @@
 #include <asm/atomic.h>
 #include <asm/mathemu.h>
 #include <asm/cpcmd.h>
-#include <asm/s390_ext.h>
 #include <asm/lowcore.h>
 #include <asm/debug.h>
 #include "entry.h"
index d13e8755a8cce46e1a97a260893aaa6fd10c8767..8ad2b34ad151324346a07fdefa5e3682c5a33e35 100644 (file)
@@ -22,6 +22,9 @@ obj-y += vdso32_wrapper.o
 extra-y += vdso32.lds
 CPPFLAGS_vdso32.lds += -P -C -U$(ARCH)
 
+# Disable gcov profiling for VDSO code
+GCOV_PROFILE := n
+
 # Force dependency (incbin is bad)
 $(obj)/vdso32_wrapper.o : $(obj)/vdso32.so
 
index 449352dda9cdb9a81209d3ff3f49cf61c0356a82..2a8ddfd12a5b97c6273b171f55da81b1fbdee940 100644 (file)
@@ -22,6 +22,9 @@ obj-y += vdso64_wrapper.o
 extra-y += vdso64.lds
 CPPFLAGS_vdso64.lds += -P -C -U$(ARCH)
 
+# Disable gcov profiling for VDSO code
+GCOV_PROFILE := n
+
 # Force dependency (incbin is bad)
 $(obj)/vdso64_wrapper.o : $(obj)/vdso64.so
 
index 1bc18cdb525b3d838d9b47f7b98fc3474101355f..56fe6bc81fee45804a61c37fb189ccf73a0b72e8 100644 (file)
@@ -77,7 +77,7 @@ SECTIONS
        . = ALIGN(PAGE_SIZE);
        INIT_DATA_SECTION(0x100)
 
-       PERCPU(0x100, PAGE_SIZE)
+       PERCPU_SECTION(0x100)
        . = ALIGN(PAGE_SIZE);
        __init_end = .;         /* freed after init ends here */
 
index 5e8ead4b4aba0d8604d2eaafcacd9b18d34468be..2d6228f60cd69ec9d5e6ee2f670cbf93cc608c42 100644 (file)
 #include <linux/cpu.h>
 #include <linux/kprobes.h>
 
-#include <asm/s390_ext.h>
 #include <asm/timer.h>
 #include <asm/irq_regs.h>
 #include <asm/cputime.h>
+#include <asm/irq.h>
 
 static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
 
index 30ca85cce3147f89b70cb2ba991c20e1275a1a5a..67345ae7ce8d967a6e952070e2969d10ad7dcd5e 100644 (file)
@@ -731,6 +731,7 @@ static int __init kvm_s390_init(void)
        }
        memcpy(facilities, S390_lowcore.stfle_fac_list, 16);
        facilities[0] &= 0xff00fff3f47c0000ULL;
+       facilities[1] &= 0x201c000000000000ULL;
        return 0;
 }
 
index ab0e041ac54cf2b17fc0b631bf0ed6cd4f59fd53..5faa1b1b23fa78f19d8f399f7681e3573ade6ee7 100644 (file)
@@ -93,4 +93,6 @@ sie_err:
 
        .section __ex_table,"a"
        .quad   sie_inst,sie_err
+       .quad   sie_exit,sie_err
+       .quad   sie_reenter,sie_err
        .previous
index 0f53110e1d09a36eb5ab794285d30854abe82a27..a65229d91c92be055931de197528c67d3403837c 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/irqflags.h>
 #include <linux/interrupt.h>
+#include <asm/div64.h>
 
 void __delay(unsigned long loops)
 {
@@ -116,3 +117,17 @@ void udelay_simple(unsigned long long usecs)
        while (get_clock() < end)
                cpu_relax();
 }
+
+void __ndelay(unsigned long long nsecs)
+{
+       u64 end;
+
+       nsecs <<= 9;
+       do_div(nsecs, 125);
+       end = get_clock() + nsecs;
+       if (nsecs & ~0xfffUL)
+               __udelay(nsecs >> 12);
+       while (get_clock() < end)
+               barrier();
+}
+EXPORT_SYMBOL(__ndelay);
index 3cc95dd0a3a6a1cb7bc133f0890786bf2324e4bf..075ddada4911bd05369d292d3e04d4b95eb56771 100644 (file)
@@ -412,6 +412,7 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
        struct dcss_segment *seg;
        int rc, diag_cc;
 
+       start_addr = end_addr = 0;
        seg = kmalloc(sizeof(*seg), GFP_KERNEL | GFP_DMA);
        if (seg == NULL) {
                rc = -ENOMEM;
@@ -573,6 +574,7 @@ segment_modify_shared (char *name, int do_nonshared)
        unsigned long start_addr, end_addr, dummy;
        int rc, diag_cc;
 
+       start_addr = end_addr = 0;
        mutex_lock(&dcss_lock);
        seg = segment_by_name (name);
        if (seg == NULL) {
@@ -681,8 +683,6 @@ void
 segment_save(char *name)
 {
        struct dcss_segment *seg;
-       int startpfn = 0;
-       int endpfn = 0;
        char cmd1[160];
        char cmd2[80];
        int i, response;
@@ -698,8 +698,6 @@ segment_save(char *name)
                goto out;
        }
 
-       startpfn = seg->start_addr >> PAGE_SHIFT;
-       endpfn = (seg->end) >> PAGE_SHIFT;
        sprintf(cmd1, "DEFSEG %s", name);
        for (i=0; i<seg->segcnt; i++) {
                sprintf(cmd1+strlen(cmd1), " %lX-%lX %s",
index ab988135e5c682a90370f998d5d72956fd40961c..fe103e891e7a0eb32dc7c67fc0cea3217bd4b6e3 100644 (file)
@@ -34,7 +34,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
-#include <asm/s390_ext.h>
+#include <asm/irq.h>
 #include <asm/mmu_context.h>
 #include <asm/compat.h>
 #include "../kernel/entry.h"
@@ -225,33 +225,6 @@ static noinline void do_sigbus(struct pt_regs *regs, long int_code,
        force_sig_info(SIGBUS, &si, tsk);
 }
 
-#ifdef CONFIG_S390_EXEC_PROTECT
-static noinline int signal_return(struct pt_regs *regs, long int_code,
-                                 unsigned long trans_exc_code)
-{
-       u16 instruction;
-       int rc;
-
-       rc = __get_user(instruction, (u16 __user *) regs->psw.addr);
-
-       if (!rc && instruction == 0x0a77) {
-               clear_tsk_thread_flag(current, TIF_PER_TRAP);
-               if (is_compat_task())
-                       sys32_sigreturn();
-               else
-                       sys_sigreturn();
-       } else if (!rc && instruction == 0x0aad) {
-               clear_tsk_thread_flag(current, TIF_PER_TRAP);
-               if (is_compat_task())
-                       sys32_rt_sigreturn();
-               else
-                       sys_rt_sigreturn();
-       } else
-               do_sigsegv(regs, int_code, SEGV_MAPERR, trans_exc_code);
-       return 0;
-}
-#endif /* CONFIG_S390_EXEC_PROTECT */
-
 static noinline void do_fault_error(struct pt_regs *regs, long int_code,
                                    unsigned long trans_exc_code, int fault)
 {
@@ -259,13 +232,6 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code,
 
        switch (fault) {
        case VM_FAULT_BADACCESS:
-#ifdef CONFIG_S390_EXEC_PROTECT
-               if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY &&
-                   (trans_exc_code & 3) == 0) {
-                       signal_return(regs, int_code, trans_exc_code);
-                       break;
-               }
-#endif /* CONFIG_S390_EXEC_PROTECT */
        case VM_FAULT_BADMAP:
                /* Bad memory access. Check if it is kernel or user space. */
                if (regs->psw.mask & PSW_MASK_PSTATE) {
@@ -279,9 +245,12 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code,
                do_no_context(regs, int_code, trans_exc_code);
                break;
        default: /* fault & VM_FAULT_ERROR */
-               if (fault & VM_FAULT_OOM)
-                       pagefault_out_of_memory();
-               else if (fault & VM_FAULT_SIGBUS) {
+               if (fault & VM_FAULT_OOM) {
+                       if (!(regs->psw.mask & PSW_MASK_PSTATE))
+                               do_no_context(regs, int_code, trans_exc_code);
+                       else
+                               pagefault_out_of_memory();
+               } else if (fault & VM_FAULT_SIGBUS) {
                        /* Kernel mode? Handle exceptions or die */
                        if (!(regs->psw.mask & PSW_MASK_PSTATE))
                                do_no_context(regs, int_code, trans_exc_code);
@@ -311,7 +280,8 @@ static inline int do_exception(struct pt_regs *regs, int access,
        struct mm_struct *mm;
        struct vm_area_struct *vma;
        unsigned long address;
-       int fault, write;
+       unsigned int flags;
+       int fault;
 
        if (notify_page_fault(regs))
                return 0;
@@ -330,6 +300,10 @@ static inline int do_exception(struct pt_regs *regs, int access,
 
        address = trans_exc_code & __FAIL_ADDR_MASK;
        perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
+       flags = FAULT_FLAG_ALLOW_RETRY;
+       if (access == VM_WRITE || (trans_exc_code & store_indication) == 0x400)
+               flags |= FAULT_FLAG_WRITE;
+retry:
        down_read(&mm->mmap_sem);
 
        fault = VM_FAULT_BADMAP;
@@ -359,21 +333,31 @@ static inline int do_exception(struct pt_regs *regs, int access,
         * make sure we exit gracefully rather than endlessly redo
         * the fault.
         */
-       write = (access == VM_WRITE ||
-                (trans_exc_code & store_indication) == 0x400) ?
-               FAULT_FLAG_WRITE : 0;
-       fault = handle_mm_fault(mm, vma, address, write);
+       fault = handle_mm_fault(mm, vma, address, flags);
        if (unlikely(fault & VM_FAULT_ERROR))
                goto out_up;
 
-       if (fault & VM_FAULT_MAJOR) {
-               tsk->maj_flt++;
-               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
-                                    regs, address);
-       } else {
-               tsk->min_flt++;
-               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
-                                    regs, address);
+       /*
+        * Major/minor page fault accounting is only done on the
+        * initial attempt. If we go through a retry, it is extremely
+        * likely that the page will be found in page cache at that point.
+        */
+       if (flags & FAULT_FLAG_ALLOW_RETRY) {
+               if (fault & VM_FAULT_MAJOR) {
+                       tsk->maj_flt++;
+                       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
+                                     regs, address);
+               } else {
+                       tsk->min_flt++;
+                       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
+                                     regs, address);
+               }
+               if (fault & VM_FAULT_RETRY) {
+                       /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
+                        * of starvation. */
+                       flags &= ~FAULT_FLAG_ALLOW_RETRY;
+                       goto retry;
+               }
        }
        /*
         * The instruction that caused the program check will
@@ -414,11 +398,6 @@ void __kprobes do_dat_exception(struct pt_regs *regs, long pgm_int_code,
        int access, fault;
 
        access = VM_READ | VM_EXEC | VM_WRITE;
-#ifdef CONFIG_S390_EXEC_PROTECT
-       if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY &&
-           (trans_exc_code & 3) == 0)
-               access = VM_EXEC;
-#endif
        fault = do_exception(regs, access, trans_exc_code);
        if (unlikely(fault))
                do_fault_error(regs, pgm_int_code & 255, trans_exc_code, fault);
@@ -468,10 +447,9 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
        access = write ? VM_WRITE : VM_READ;
        fault = do_exception(&regs, access, uaddr | 2);
        if (unlikely(fault)) {
-               if (fault & VM_FAULT_OOM) {
-                       pagefault_out_of_memory();
-                       fault = 0;
-               } else if (fault & VM_FAULT_SIGBUS)
+               if (fault & VM_FAULT_OOM)
+                       return -EFAULT;
+               else if (fault & VM_FAULT_SIGBUS)
                        do_sigbus(&regs, pgm_int_code, uaddr);
        }
        return fault ? -EFAULT : 0;
@@ -491,22 +469,28 @@ static int __init nopfault(char *str)
 
 __setup("nopfault", nopfault);
 
-typedef struct {
-       __u16 refdiagc;
-       __u16 reffcode;
-       __u16 refdwlen;
-       __u16 refversn;
-       __u64 refgaddr;
-       __u64 refselmk;
-       __u64 refcmpmk;
-       __u64 reserved;
-} __attribute__ ((packed, aligned(8))) pfault_refbk_t;
+struct pfault_refbk {
+       u16 refdiagc;
+       u16 reffcode;
+       u16 refdwlen;
+       u16 refversn;
+       u64 refgaddr;
+       u64 refselmk;
+       u64 refcmpmk;
+       u64 reserved;
+} __attribute__ ((packed, aligned(8)));
 
 int pfault_init(void)
 {
-       pfault_refbk_t refbk =
-               { 0x258, 0, 5, 2, __LC_CURRENT, 1ULL << 48, 1ULL << 48,
-                 __PF_RES_FIELD };
+       struct pfault_refbk refbk = {
+               .refdiagc = 0x258,
+               .reffcode = 0,
+               .refdwlen = 5,
+               .refversn = 2,
+               .refgaddr = __LC_CURRENT_PID,
+               .refselmk = 1ULL << 48,
+               .refcmpmk = 1ULL << 48,
+               .reserved = __PF_RES_FIELD };
         int rc;
 
        if (!MACHINE_IS_VM || pfault_disable)
@@ -518,18 +502,20 @@ int pfault_init(void)
                "2:\n"
                EX_TABLE(0b,1b)
                : "=d" (rc) : "a" (&refbk), "m" (refbk) : "cc");
-        __ctl_set_bit(0, 9);
         return rc;
 }
 
 void pfault_fini(void)
 {
-       pfault_refbk_t refbk =
-       { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL };
+       struct pfault_refbk refbk = {
+               .refdiagc = 0x258,
+               .reffcode = 1,
+               .refdwlen = 5,
+               .refversn = 2,
+       };
 
        if (!MACHINE_IS_VM || pfault_disable)
                return;
-       __ctl_clear_bit(0,9);
        asm volatile(
                "       diag    %0,0,0x258\n"
                "0:\n"
@@ -537,11 +523,15 @@ void pfault_fini(void)
                : : "a" (&refbk), "m" (refbk) : "cc");
 }
 
+static DEFINE_SPINLOCK(pfault_lock);
+static LIST_HEAD(pfault_list);
+
 static void pfault_interrupt(unsigned int ext_int_code,
                             unsigned int param32, unsigned long param64)
 {
        struct task_struct *tsk;
        __u16 subcode;
+       pid_t pid;
 
        /*
         * Get the external interruption subcode & pfault
@@ -553,44 +543,79 @@ static void pfault_interrupt(unsigned int ext_int_code,
        if ((subcode & 0xff00) != __SUBCODE_MASK)
                return;
        kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++;
-
-       /*
-        * Get the token (= address of the task structure of the affected task).
-        */
-#ifdef CONFIG_64BIT
-       tsk = (struct task_struct *) param64;
-#else
-       tsk = (struct task_struct *) param32;
-#endif
-
+       if (subcode & 0x0080) {
+               /* Get the token (= pid of the affected task). */
+               pid = sizeof(void *) == 4 ? param32 : param64;
+               rcu_read_lock();
+               tsk = find_task_by_pid_ns(pid, &init_pid_ns);
+               if (tsk)
+                       get_task_struct(tsk);
+               rcu_read_unlock();
+               if (!tsk)
+                       return;
+       } else {
+               tsk = current;
+       }
+       spin_lock(&pfault_lock);
        if (subcode & 0x0080) {
                /* signal bit is set -> a page has been swapped in by VM */
-               if (xchg(&tsk->thread.pfault_wait, -1) != 0) {
+               if (tsk->thread.pfault_wait == 1) {
                        /* Initial interrupt was faster than the completion
                         * interrupt. pfault_wait is valid. Set pfault_wait
                         * back to zero and wake up the process. This can
                         * safely be done because the task is still sleeping
                         * and can't produce new pfaults. */
                        tsk->thread.pfault_wait = 0;
+                       list_del(&tsk->thread.list);
                        wake_up_process(tsk);
-                       put_task_struct(tsk);
+               } else {
+                       /* Completion interrupt was faster than initial
+                        * interrupt. Set pfault_wait to -1 so the initial
+                        * interrupt doesn't put the task to sleep. */
+                       tsk->thread.pfault_wait = -1;
                }
+               put_task_struct(tsk);
        } else {
                /* signal bit not set -> a real page is missing. */
-               get_task_struct(tsk);
-               set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-               if (xchg(&tsk->thread.pfault_wait, 1) != 0) {
+               if (tsk->thread.pfault_wait == -1) {
                        /* Completion interrupt was faster than the initial
-                        * interrupt (swapped in a -1 for pfault_wait). Set
-                        * pfault_wait back to zero and exit. This can be
-                        * done safely because tsk is running in kernel 
-                        * mode and can't produce new pfaults. */
+                        * interrupt (pfault_wait == -1). Set pfault_wait
+                        * back to zero and exit. */
                        tsk->thread.pfault_wait = 0;
-                       set_task_state(tsk, TASK_RUNNING);
-                       put_task_struct(tsk);
-               } else
+               } else {
+                       /* Initial interrupt arrived before completion
+                        * interrupt. Let the task sleep. */
+                       tsk->thread.pfault_wait = 1;
+                       list_add(&tsk->thread.list, &pfault_list);
+                       set_task_state(tsk, TASK_UNINTERRUPTIBLE);
                        set_tsk_need_resched(tsk);
+               }
+       }
+       spin_unlock(&pfault_lock);
+}
+
+static int __cpuinit pfault_cpu_notify(struct notifier_block *self,
+                                      unsigned long action, void *hcpu)
+{
+       struct thread_struct *thread, *next;
+       struct task_struct *tsk;
+
+       switch (action) {
+       case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
+               spin_lock_irq(&pfault_lock);
+               list_for_each_entry_safe(thread, next, &pfault_list, list) {
+                       thread->pfault_wait = 0;
+                       list_del(&thread->list);
+                       tsk = container_of(thread, struct task_struct, thread);
+                       wake_up_process(tsk);
+               }
+               spin_unlock_irq(&pfault_lock);
+               break;
+       default:
+               break;
        }
+       return NOTIFY_OK;
 }
 
 static int __init pfault_irq_init(void)
@@ -599,22 +624,22 @@ static int __init pfault_irq_init(void)
 
        if (!MACHINE_IS_VM)
                return 0;
-       /*
-        * Try to get pfault pseudo page faults going.
-        */
        rc = register_external_interrupt(0x2603, pfault_interrupt);
-       if (rc) {
-               pfault_disable = 1;
-               return rc;
-       }
-       if (pfault_init() == 0)
-               return 0;
+       if (rc)
+               goto out_extint;
+       rc = pfault_init() == 0 ? 0 : -EOPNOTSUPP;
+       if (rc)
+               goto out_pfault;
+       service_subclass_irq_register();
+       hotcpu_notifier(pfault_cpu_notify, 0);
+       return 0;
 
-       /* Tough luck, no pfault. */
-       pfault_disable = 1;
+out_pfault:
        unregister_external_interrupt(0x2603, pfault_interrupt);
-       return 0;
+out_extint:
+       pfault_disable = 1;
+       return rc;
 }
 early_initcall(pfault_irq_init);
 
-#endif
+#endif /* CONFIG_PFAULT */
index 639cd21f2218d6431030472a03509acb2ba8a41b..a4d856db9154fb6654115a10f6f2c39c8962e5ae 100644 (file)
@@ -13,7 +13,6 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
                                   pte_t *pteptr, pte_t pteval)
 {
        pmd_t *pmdp = (pmd_t *) pteptr;
-       pte_t shadow_pteval = pteval;
        unsigned long mask;
 
        if (!MACHINE_HAS_HPAGE) {
@@ -21,18 +20,9 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
                mask = pte_val(pteval) &
                                (_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO);
                pte_val(pteval) = (_SEGMENT_ENTRY + __pa(pteptr)) | mask;
-               if (mm->context.noexec) {
-                       pteptr += PTRS_PER_PTE;
-                       pte_val(shadow_pteval) =
-                                       (_SEGMENT_ENTRY + __pa(pteptr)) | mask;
-               }
        }
 
        pmd_val(*pmdp) = pte_val(pteval);
-       if (mm->context.noexec) {
-               pmdp = get_shadow_table(pmdp);
-               pmd_val(*pmdp) = pte_val(shadow_pteval);
-       }
 }
 
 int arch_prepare_hugepage(struct page *page)
index bb409332a484add0f68a1c20734d81968273f0e6..59b663109d9024af9728547208b74a56d5d2d6a2 100644 (file)
@@ -119,9 +119,7 @@ void __init paging_init(void)
        sparse_memory_present_with_active_regions(MAX_NUMNODES);
        sparse_init();
        memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
-#ifdef CONFIG_ZONE_DMA
        max_zone_pfns[ZONE_DMA] = PFN_DOWN(MAX_DMA_ADDRESS);
-#endif
        max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
        free_area_init_nodes(max_zone_pfns);
        fault_init();
@@ -175,7 +173,8 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
                pmd = pmd_offset(pud, address);
                pte = pte_offset_kernel(pmd, address);
                if (!enable) {
-                       ptep_invalidate(&init_mm, address, pte);
+                       __ptep_ipte(address, pte);
+                       pte_val(*pte) = _PAGE_TYPE_EMPTY;
                        continue;
                }
                *pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW));
index 71a4b0d34be09625c2fecfd28a23d61b47e29019..51e5cd9b906a7887d69e2eee825ecbf38ce29d9e 100644 (file)
@@ -19,7 +19,7 @@
  * using the stura instruction.
  * Returns the number of bytes copied or -EFAULT.
  */
-static long probe_kernel_write_odd(void *dst, void *src, size_t size)
+static long probe_kernel_write_odd(void *dst, const void *src, size_t size)
 {
        unsigned long count, aligned;
        int offset, mask;
@@ -45,7 +45,7 @@ static long probe_kernel_write_odd(void *dst, void *src, size_t size)
        return rc ? rc : count;
 }
 
-long probe_kernel_write(void *dst, void *src, size_t size)
+long probe_kernel_write(void *dst, const void *src, size_t size)
 {
        long copied = 0;
 
index f05edcc3beff42c53cae96eb1850001915ff5bbc..d013ed39743b1bfe57faaa31f51c933f31d5639a 100644 (file)
@@ -28,7 +28,7 @@ static void change_page_attr(unsigned long addr, int numpages,
 
                pte = *ptep;
                pte = set(pte);
-               ptep_invalidate(&init_mm, addr, ptep);
+               __ptep_ipte(addr, ptep);
                *ptep = pte;
                addr += PAGE_SIZE;
        }
index e1850c28cd68453b2bde08189269e21702b3aa42..37a23c22370576415441e7542728b79a233f2f58 100644 (file)
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
 
-struct rcu_table_freelist {
-       struct rcu_head rcu;
-       struct mm_struct *mm;
-       unsigned int pgt_index;
-       unsigned int crst_index;
-       unsigned long *table[0];
-};
-
-#define RCU_FREELIST_SIZE \
-       ((PAGE_SIZE - sizeof(struct rcu_table_freelist)) \
-         / sizeof(unsigned long))
-
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-static DEFINE_PER_CPU(struct rcu_table_freelist *, rcu_table_freelist);
-
-static void __page_table_free(struct mm_struct *mm, unsigned long *table);
-static void __crst_table_free(struct mm_struct *mm, unsigned long *table);
-
-static struct rcu_table_freelist *rcu_table_freelist_get(struct mm_struct *mm)
-{
-       struct rcu_table_freelist **batchp = &__get_cpu_var(rcu_table_freelist);
-       struct rcu_table_freelist *batch = *batchp;
-
-       if (batch)
-               return batch;
-       batch = (struct rcu_table_freelist *) __get_free_page(GFP_ATOMIC);
-       if (batch) {
-               batch->mm = mm;
-               batch->pgt_index = 0;
-               batch->crst_index = RCU_FREELIST_SIZE;
-               *batchp = batch;
-       }
-       return batch;
-}
-
-static void rcu_table_freelist_callback(struct rcu_head *head)
-{
-       struct rcu_table_freelist *batch =
-               container_of(head, struct rcu_table_freelist, rcu);
-
-       while (batch->pgt_index > 0)
-               __page_table_free(batch->mm, batch->table[--batch->pgt_index]);
-       while (batch->crst_index < RCU_FREELIST_SIZE)
-               __crst_table_free(batch->mm, batch->table[batch->crst_index++]);
-       free_page((unsigned long) batch);
-}
-
-void rcu_table_freelist_finish(void)
-{
-       struct rcu_table_freelist *batch = __get_cpu_var(rcu_table_freelist);
-
-       if (!batch)
-               return;
-       call_rcu(&batch->rcu, rcu_table_freelist_callback);
-       __get_cpu_var(rcu_table_freelist) = NULL;
-}
-
-static void smp_sync(void *arg)
-{
-}
-
 #ifndef CONFIG_64BIT
 #define ALLOC_ORDER    1
-#define TABLES_PER_PAGE        4
-#define FRAG_MASK      15UL
-#define SECOND_HALVES  10UL
-
-void clear_table_pgstes(unsigned long *table)
-{
-       clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE/4);
-       memset(table + 256, 0, PAGE_SIZE/4);
-       clear_table(table + 512, _PAGE_TYPE_EMPTY, PAGE_SIZE/4);
-       memset(table + 768, 0, PAGE_SIZE/4);
-}
-
+#define FRAG_MASK      0x0f
 #else
 #define ALLOC_ORDER    2
-#define TABLES_PER_PAGE        2
-#define FRAG_MASK      3UL
-#define SECOND_HALVES  2UL
-
-void clear_table_pgstes(unsigned long *table)
-{
-       clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE/2);
-       memset(table + 256, 0, PAGE_SIZE/2);
-}
-
+#define FRAG_MASK      0x03
 #endif
 
 unsigned long VMALLOC_START = VMALLOC_END - VMALLOC_SIZE;
@@ -125,68 +44,18 @@ static int __init parse_vmalloc(char *arg)
 }
 early_param("vmalloc", parse_vmalloc);
 
-unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec)
+unsigned long *crst_table_alloc(struct mm_struct *mm)
 {
        struct page *page = alloc_pages(GFP_KERNEL, ALLOC_ORDER);
 
        if (!page)
                return NULL;
-       page->index = 0;
-       if (noexec) {
-               struct page *shadow = alloc_pages(GFP_KERNEL, ALLOC_ORDER);
-               if (!shadow) {
-                       __free_pages(page, ALLOC_ORDER);
-                       return NULL;
-               }
-               page->index = page_to_phys(shadow);
-       }
-       spin_lock_bh(&mm->context.list_lock);
-       list_add(&page->lru, &mm->context.crst_list);
-       spin_unlock_bh(&mm->context.list_lock);
        return (unsigned long *) page_to_phys(page);
 }
 
-static void __crst_table_free(struct mm_struct *mm, unsigned long *table)
-{
-       unsigned long *shadow = get_shadow_table(table);
-
-       if (shadow)
-               free_pages((unsigned long) shadow, ALLOC_ORDER);
-       free_pages((unsigned long) table, ALLOC_ORDER);
-}
-
 void crst_table_free(struct mm_struct *mm, unsigned long *table)
 {
-       struct page *page = virt_to_page(table);
-
-       spin_lock_bh(&mm->context.list_lock);
-       list_del(&page->lru);
-       spin_unlock_bh(&mm->context.list_lock);
-       __crst_table_free(mm, table);
-}
-
-void crst_table_free_rcu(struct mm_struct *mm, unsigned long *table)
-{
-       struct rcu_table_freelist *batch;
-       struct page *page = virt_to_page(table);
-
-       spin_lock_bh(&mm->context.list_lock);
-       list_del(&page->lru);
-       spin_unlock_bh(&mm->context.list_lock);
-       if (atomic_read(&mm->mm_users) < 2 &&
-           cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
-               __crst_table_free(mm, table);
-               return;
-       }
-       batch = rcu_table_freelist_get(mm);
-       if (!batch) {
-               smp_call_function(smp_sync, NULL, 1);
-               __crst_table_free(mm, table);
-               return;
-       }
-       batch->table[--batch->crst_index] = table;
-       if (batch->pgt_index >= batch->crst_index)
-               rcu_table_freelist_finish();
+       free_pages((unsigned long) table, ALLOC_ORDER);
 }
 
 #ifdef CONFIG_64BIT
@@ -197,7 +66,7 @@ int crst_table_upgrade(struct mm_struct *mm, unsigned long limit)
 
        BUG_ON(limit > (1UL << 53));
 repeat:
-       table = crst_table_alloc(mm, mm->context.noexec);
+       table = crst_table_alloc(mm);
        if (!table)
                return -ENOMEM;
        spin_lock_bh(&mm->page_table_lock);
@@ -264,140 +133,175 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit)
 }
 #endif
 
+static inline unsigned int atomic_xor_bits(atomic_t *v, unsigned int bits)
+{
+       unsigned int old, new;
+
+       do {
+               old = atomic_read(v);
+               new = old ^ bits;
+       } while (atomic_cmpxchg(v, old, new) != old);
+       return new;
+}
+
 /*
  * page table entry allocation/free routines.
  */
+#ifdef CONFIG_PGSTE
+static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm)
+{
+       struct page *page;
+       unsigned long *table;
+
+       page = alloc_page(GFP_KERNEL|__GFP_REPEAT);
+       if (!page)
+               return NULL;
+       pgtable_page_ctor(page);
+       atomic_set(&page->_mapcount, 3);
+       table = (unsigned long *) page_to_phys(page);
+       clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE/2);
+       clear_table(table + PTRS_PER_PTE, 0, PAGE_SIZE/2);
+       return table;
+}
+
+static inline void page_table_free_pgste(unsigned long *table)
+{
+       struct page *page;
+
+       page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
+       pgtable_page_ctor(page);
+       atomic_set(&page->_mapcount, -1);
+       __free_page(page);
+}
+#endif
+
 unsigned long *page_table_alloc(struct mm_struct *mm)
 {
        struct page *page;
        unsigned long *table;
-       unsigned long bits;
+       unsigned int mask, bit;
 
-       bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
+#ifdef CONFIG_PGSTE
+       if (mm_has_pgste(mm))
+               return page_table_alloc_pgste(mm);
+#endif
+       /* Allocate fragments of a 4K page as 1K/2K page table */
        spin_lock_bh(&mm->context.list_lock);
-       page = NULL;
+       mask = FRAG_MASK;
        if (!list_empty(&mm->context.pgtable_list)) {
                page = list_first_entry(&mm->context.pgtable_list,
                                        struct page, lru);
-               if ((page->flags & FRAG_MASK) == ((1UL << TABLES_PER_PAGE) - 1))
-                       page = NULL;
+               table = (unsigned long *) page_to_phys(page);
+               mask = atomic_read(&page->_mapcount);
+               mask = mask | (mask >> 4);
        }
-       if (!page) {
+       if ((mask & FRAG_MASK) == FRAG_MASK) {
                spin_unlock_bh(&mm->context.list_lock);
                page = alloc_page(GFP_KERNEL|__GFP_REPEAT);
                if (!page)
                        return NULL;
                pgtable_page_ctor(page);
-               page->flags &= ~FRAG_MASK;
+               atomic_set(&page->_mapcount, 1);
                table = (unsigned long *) page_to_phys(page);
-               if (mm->context.has_pgste)
-                       clear_table_pgstes(table);
-               else
-                       clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE);
+               clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE);
                spin_lock_bh(&mm->context.list_lock);
                list_add(&page->lru, &mm->context.pgtable_list);
+       } else {
+               for (bit = 1; mask & bit; bit <<= 1)
+                       table += PTRS_PER_PTE;
+               mask = atomic_xor_bits(&page->_mapcount, bit);
+               if ((mask & FRAG_MASK) == FRAG_MASK)
+                       list_del(&page->lru);
        }
-       table = (unsigned long *) page_to_phys(page);
-       while (page->flags & bits) {
-               table += 256;
-               bits <<= 1;
-       }
-       page->flags |= bits;
-       if ((page->flags & FRAG_MASK) == ((1UL << TABLES_PER_PAGE) - 1))
-               list_move_tail(&page->lru, &mm->context.pgtable_list);
        spin_unlock_bh(&mm->context.list_lock);
        return table;
 }
 
-static void __page_table_free(struct mm_struct *mm, unsigned long *table)
+void page_table_free(struct mm_struct *mm, unsigned long *table)
 {
        struct page *page;
-       unsigned long bits;
+       unsigned int bit, mask;
 
-       bits = ((unsigned long) table) & 15;
-       table = (unsigned long *)(((unsigned long) table) ^ bits);
+#ifdef CONFIG_PGSTE
+       if (mm_has_pgste(mm))
+               return page_table_free_pgste(table);
+#endif
+       /* Free 1K/2K page table fragment of a 4K page */
        page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
-       page->flags ^= bits;
-       if (!(page->flags & FRAG_MASK)) {
+       bit = 1 << ((__pa(table) & ~PAGE_MASK)/(PTRS_PER_PTE*sizeof(pte_t)));
+       spin_lock_bh(&mm->context.list_lock);
+       if ((atomic_read(&page->_mapcount) & FRAG_MASK) != FRAG_MASK)
+               list_del(&page->lru);
+       mask = atomic_xor_bits(&page->_mapcount, bit);
+       if (mask & FRAG_MASK)
+               list_add(&page->lru, &mm->context.pgtable_list);
+       spin_unlock_bh(&mm->context.list_lock);
+       if (mask == 0) {
                pgtable_page_dtor(page);
+               atomic_set(&page->_mapcount, -1);
                __free_page(page);
        }
 }
 
-void page_table_free(struct mm_struct *mm, unsigned long *table)
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+
+static void __page_table_free_rcu(void *table, unsigned bit)
 {
        struct page *page;
-       unsigned long bits;
 
-       bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
-       bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long);
+#ifdef CONFIG_PGSTE
+       if (bit == FRAG_MASK)
+               return page_table_free_pgste(table);
+#endif
+       /* Free 1K/2K page table fragment of a 4K page */
        page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
-       spin_lock_bh(&mm->context.list_lock);
-       page->flags ^= bits;
-       if (page->flags & FRAG_MASK) {
-               /* Page now has some free pgtable fragments. */
-               if (!list_empty(&page->lru))
-                       list_move(&page->lru, &mm->context.pgtable_list);
-               page = NULL;
-       } else
-               /* All fragments of the 4K page have been freed. */
-               list_del(&page->lru);
-       spin_unlock_bh(&mm->context.list_lock);
-       if (page) {
+       if (atomic_xor_bits(&page->_mapcount, bit) == 0) {
                pgtable_page_dtor(page);
+               atomic_set(&page->_mapcount, -1);
                __free_page(page);
        }
 }
 
-void page_table_free_rcu(struct mm_struct *mm, unsigned long *table)
+void page_table_free_rcu(struct mmu_gather *tlb, unsigned long *table)
 {
-       struct rcu_table_freelist *batch;
+       struct mm_struct *mm;
        struct page *page;
-       unsigned long bits;
+       unsigned int bit, mask;
 
-       if (atomic_read(&mm->mm_users) < 2 &&
-           cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
-               page_table_free(mm, table);
-               return;
-       }
-       batch = rcu_table_freelist_get(mm);
-       if (!batch) {
-               smp_call_function(smp_sync, NULL, 1);
-               page_table_free(mm, table);
+       mm = tlb->mm;
+#ifdef CONFIG_PGSTE
+       if (mm_has_pgste(mm)) {
+               table = (unsigned long *) (__pa(table) | FRAG_MASK);
+               tlb_remove_table(tlb, table);
                return;
        }
-       bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
-       bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long);
+#endif
+       bit = 1 << ((__pa(table) & ~PAGE_MASK) / (PTRS_PER_PTE*sizeof(pte_t)));
        page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
        spin_lock_bh(&mm->context.list_lock);
-       /* Delayed freeing with rcu prevents reuse of pgtable fragments */
-       list_del_init(&page->lru);
+       if ((atomic_read(&page->_mapcount) & FRAG_MASK) != FRAG_MASK)
+               list_del(&page->lru);
+       mask = atomic_xor_bits(&page->_mapcount, bit | (bit << 4));
+       if (mask & FRAG_MASK)
+               list_add_tail(&page->lru, &mm->context.pgtable_list);
        spin_unlock_bh(&mm->context.list_lock);
-       table = (unsigned long *)(((unsigned long) table) | bits);
-       batch->table[batch->pgt_index++] = table;
-       if (batch->pgt_index >= batch->crst_index)
-               rcu_table_freelist_finish();
+       table = (unsigned long *) (__pa(table) | (bit << 4));
+       tlb_remove_table(tlb, table);
 }
 
-void disable_noexec(struct mm_struct *mm, struct task_struct *tsk)
+void __tlb_remove_table(void *_table)
 {
-       struct page *page;
+       void *table = (void *)((unsigned long) _table & PAGE_MASK);
+       unsigned type = (unsigned long) _table & ~PAGE_MASK;
 
-       spin_lock_bh(&mm->context.list_lock);
-       /* Free shadow region and segment tables. */
-       list_for_each_entry(page, &mm->context.crst_list, lru)
-               if (page->index) {
-                       free_pages((unsigned long) page->index, ALLOC_ORDER);
-                       page->index = 0;
-               }
-       /* "Free" second halves of page tables. */
-       list_for_each_entry(page, &mm->context.pgtable_list, lru)
-               page->flags &= ~SECOND_HALVES;
-       spin_unlock_bh(&mm->context.list_lock);
-       mm->context.noexec = 0;
-       update_mm(mm, tsk);
+       if (type)
+               __page_table_free_rcu(table, type);
+       else
+               free_pages((unsigned long) table, ALLOC_ORDER);
 }
 
+#endif
+
 /*
  * switch on pgstes for its userspace process (for kvm)
  */
@@ -411,7 +315,7 @@ int s390_enable_sie(void)
                return -EINVAL;
 
        /* Do we have pgstes? if yes, we are done */
-       if (tsk->mm->context.has_pgste)
+       if (mm_has_pgste(tsk->mm))
                return 0;
 
        /* lets check if we are allowed to replace the mm */
index 34c43f23b28cedbb88ba405466a00144f32379fe..8c1970d1dd912231f9215c3455c9e4de9200809d 100644 (file)
@@ -95,7 +95,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
                        pu_dir = vmem_pud_alloc();
                        if (!pu_dir)
                                goto out;
-                       pgd_populate_kernel(&init_mm, pg_dir, pu_dir);
+                       pgd_populate(&init_mm, pg_dir, pu_dir);
                }
 
                pu_dir = pud_offset(pg_dir, address);
@@ -103,7 +103,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
                        pm_dir = vmem_pmd_alloc();
                        if (!pm_dir)
                                goto out;
-                       pud_populate_kernel(&init_mm, pu_dir, pm_dir);
+                       pud_populate(&init_mm, pu_dir, pm_dir);
                }
 
                pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0));
@@ -123,7 +123,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
                        pt_dir = vmem_pte_alloc();
                        if (!pt_dir)
                                goto out;
-                       pmd_populate_kernel(&init_mm, pm_dir, pt_dir);
+                       pmd_populate(&init_mm, pm_dir, pt_dir);
                }
 
                pt_dir = pte_offset_kernel(pm_dir, address);
@@ -159,7 +159,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
                        continue;
 
                if (pmd_huge(*pm_dir)) {
-                       pmd_clear_kernel(pm_dir);
+                       pmd_clear(pm_dir);
                        address += HPAGE_SIZE - PAGE_SIZE;
                        continue;
                }
@@ -192,7 +192,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
                        pu_dir = vmem_pud_alloc();
                        if (!pu_dir)
                                goto out;
-                       pgd_populate_kernel(&init_mm, pg_dir, pu_dir);
+                       pgd_populate(&init_mm, pg_dir, pu_dir);
                }
 
                pu_dir = pud_offset(pg_dir, address);
@@ -200,7 +200,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
                        pm_dir = vmem_pmd_alloc();
                        if (!pm_dir)
                                goto out;
-                       pud_populate_kernel(&init_mm, pu_dir, pm_dir);
+                       pud_populate(&init_mm, pu_dir, pm_dir);
                }
 
                pm_dir = pmd_offset(pu_dir, address);
@@ -208,7 +208,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
                        pt_dir = vmem_pte_alloc();
                        if (!pt_dir)
                                goto out;
-                       pmd_populate_kernel(&init_mm, pm_dir, pt_dir);
+                       pmd_populate(&init_mm, pm_dir, pt_dir);
                }
 
                pt_dir = pte_offset_kernel(pm_dir, address);
index 33cbd373cce4f39e1181299b9098c2334fc231ec..4552ce40c81a5086ad550e21092c78b36ad3b7c3 100644 (file)
@@ -5,6 +5,7 @@
  * Author: Heinz Graalfs <graalfs@de.ibm.com>
  */
 
+#include <linux/kernel_stat.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/smp.h>
@@ -18,7 +19,7 @@
 #include <linux/oprofile.h>
 
 #include <asm/lowcore.h>
-#include <asm/s390_ext.h>
+#include <asm/irq.h>
 
 #include "hwsampler.h"
 
@@ -579,7 +580,7 @@ static int hws_cpu_callback(struct notifier_block *nfb,
 {
        /* We do not have sampler space available for all possible CPUs.
           All CPUs should be online when hw sampling is activated. */
-       return NOTIFY_BAD;
+       return (hws_state <= HWS_DEALLOCATED) ? NOTIFY_OK : NOTIFY_BAD;
 }
 
 static struct notifier_block hws_cpu_notifier = {
@@ -674,17 +675,11 @@ int hwsampler_activate(unsigned int cpu)
 static void hws_ext_handler(unsigned int ext_int_code,
                            unsigned int param32, unsigned long param64)
 {
-       int cpu;
        struct hws_cpu_buffer *cb;
 
-       cpu = smp_processor_id();
-       cb = &per_cpu(sampler_cpu_buffer, cpu);
-
-       atomic_xchg(
-                       &cb->ext_params,
-                       atomic_read(&cb->ext_params)
-                               | S390_lowcore.ext_params);
-
+       kstat_cpu(smp_processor_id()).irqs[EXTINT_CPM]++;
+       cb = &__get_cpu_var(sampler_cpu_buffer);
+       atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32);
        if (hws_wq)
                queue_work(hws_wq, &cb->worker);
 }
@@ -764,7 +759,7 @@ static int worker_check_error(unsigned int cpu, int ext_params)
        if (!sdbt || !*sdbt)
                return -EINVAL;
 
-       if (ext_params & EI_IEA)
+       if (ext_params & EI_PRA)
                cb->req_alert++;
 
        if (ext_params & EI_LSDA)
@@ -1009,7 +1004,7 @@ int hwsampler_deallocate()
        if (hws_state != HWS_STOPPED)
                goto deallocate_exit;
 
-       smp_ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
+       ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
        deallocate_sdbt();
 
        hws_state = HWS_DEALLOCATED;
@@ -1123,7 +1118,7 @@ int hwsampler_shutdown()
                mutex_lock(&hws_sem);
 
                if (hws_state == HWS_STOPPED) {
-                       smp_ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
+                       ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
                        deallocate_sdbt();
                }
                if (hws_wq) {
@@ -1198,7 +1193,7 @@ start_all_exit:
        hws_oom = 1;
        hws_flush_all = 0;
        /* now let them in, 1407 CPUMF external interrupts */
-       smp_ctl_set_bit(0, 5); /* set CR0 bit 58 */
+       ctl_set_bit(0, 5); /* set CR0 bit 58 */
 
        return 0;
 }
index 5995e9bc72d9c291d57df38ab66c0a1929f43dd6..0e358c2cffeb5e6bf1955ba6ca2c3de7092e03b3 100644 (file)
@@ -25,7 +25,7 @@ extern void s390_backtrace(struct pt_regs * const regs, unsigned int depth);
 
 #include "hwsampler.h"
 
-#define DEFAULT_INTERVAL       4096
+#define DEFAULT_INTERVAL       4127518
 
 #define DEFAULT_SDBT_BLOCKS    1
 #define DEFAULT_SDB_BLOCKS     511
@@ -151,6 +151,12 @@ static int oprofile_hwsampler_init(struct oprofile_operations *ops)
        if (oprofile_max_interval == 0)
                return -ENODEV;
 
+       /* The initial value should be sane */
+       if (oprofile_hw_interval < oprofile_min_interval)
+               oprofile_hw_interval = oprofile_min_interval;
+       if (oprofile_hw_interval > oprofile_max_interval)
+               oprofile_hw_interval = oprofile_max_interval;
+
        if (oprofile_timer_init(ops))
                return -ENODEV;
 
index e73bc781cc1465cb51f5c23a2c61f168b5279129..288add8d168f05f8181f3a7d0eee61ecda89ce82 100644 (file)
@@ -43,9 +43,6 @@ config NO_DMA
 config RWSEM_GENERIC_SPINLOCK
        def_bool y
 
-config GENERIC_FIND_NEXT_BIT
-       def_bool y
-
 config GENERIC_HWEIGHT
        def_bool y
 
index 451ed54ce64609c0875a0d4db8503c2222ed7263..a1f346df0a710bd5441fbf6ceb46a8fe47927c2e 100644 (file)
@@ -16,15 +16,6 @@ config CMDLINE
          other cases you can specify kernel args so that you don't have
          to set them up in board prom initialization routines.
 
-config DEBUG_STACK_USAGE
-       bool "Enable stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T and sysrq-P debug output.
-
-         This option will slow down process creation somewhat.
-
 config RUNTIME_DEBUG
        bool "Enable run-time debugging"
        depends on DEBUG_KERNEL
index 50fdec54c70a75c6aabd281263139f4dca54a6ef..cee6bce1e30c3663490e05d66725f89c907e62a9 100644 (file)
@@ -38,8 +38,6 @@
 #include <asm/sections.h>
 #include <asm/tlb.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 unsigned long empty_zero_page;
 EXPORT_SYMBOL_GPL(empty_zero_page);
 
index b44e37753b9a59f30d448ebca1da13814ef33ba5..f03338c2f0886bbb830973f15e4a929d19981e6d 100644 (file)
@@ -71,12 +71,6 @@ config GENERIC_CSUM
        def_bool y
        depends on SUPERH64
 
-config GENERIC_FIND_NEXT_BIT
-       def_bool y
-
-config GENERIC_FIND_BIT_LE
-       def_bool y
-
 config GENERIC_HWEIGHT
        def_bool y
 
@@ -167,7 +161,7 @@ config ARCH_HAS_CPU_IDLE_WAIT
 
 config NO_IOPORT
        def_bool !PCI
-       depends on !SH_CAYMAN && !SH_SH4202_MICRODEV
+       depends on !SH_CAYMAN && !SH_SH4202_MICRODEV && !SH_SHMIN
 
 config IO_TRAPPED
        bool
index 1553d56cf4e08f30e2454c4a20e85307059af331..c1d5a820b1aa3f64e72475203515b6a4303c1c0f 100644 (file)
@@ -28,15 +28,6 @@ config STACK_DEBUG
          every function call and will therefore incur a major
          performance hit. Most users should say N.
 
-config DEBUG_STACK_USAGE
-       bool "Stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T and sysrq-P debug output.
-
-         This option will slow down process creation somewhat.
-
 config 4KSTACKS
        bool "Use 4Kb for kernel stacks instead of 8Kb"
        depends on DEBUG_KERNEL && (MMU || BROKEN) && !PAGE_SIZE_64KB
index 618bd566cf53bfe70b85b825072e0e7fa2b8aab5..969421f64a150a777b6a7f97e1d7b69aff4e1534 100644 (file)
@@ -359,37 +359,31 @@ static struct soc_camera_link camera_link = {
        .priv           = &camera_info,
 };
 
-static void dummy_release(struct device *dev)
+static struct platform_device *camera_device;
+
+static void ap325rxa_camera_release(struct device *dev)
 {
+       soc_camera_platform_release(&camera_device);
 }
 
-static struct platform_device camera_device = {
-       .name           = "soc_camera_platform",
-       .dev            = {
-               .platform_data  = &camera_info,
-               .release        = dummy_release,
-       },
-};
-
 static int ap325rxa_camera_add(struct soc_camera_link *icl,
                               struct device *dev)
 {
-       if (icl != &camera_link || camera_probe() <= 0)
-               return -ENODEV;
+       int ret = soc_camera_platform_add(icl, dev, &camera_device, &camera_link,
+                                         ap325rxa_camera_release, 0);
+       if (ret < 0)
+               return ret;
 
-       camera_info.dev = dev;
+       ret = camera_probe();
+       if (ret < 0)
+               soc_camera_platform_del(icl, camera_device, &camera_link);
 
-       return platform_device_register(&camera_device);
+       return ret;
 }
 
 static void ap325rxa_camera_del(struct soc_camera_link *icl)
 {
-       if (icl != &camera_link)
-               return;
-
-       platform_device_unregister(&camera_device);
-       memset(&camera_device.dev.kobj, 0,
-              sizeof(camera_device.dev.kobj));
+       soc_camera_platform_del(icl, camera_device, &camera_link);
 }
 #endif /* CONFIG_I2C */
 
index bb13d0e1b964cc912de97ff9579cd26ca72de3f2..513cb1a2e6c830bc2d25cf27cf485ff8b37c37f8 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/usb/r8a66597.h>
+#include <linux/usb/renesas_usbhs.h>
 #include <linux/i2c.h>
 #include <linux/i2c/tsc2007.h>
 #include <linux/spi/spi.h>
@@ -232,6 +233,52 @@ static struct platform_device usb1_common_device = {
        .resource       = usb1_common_resources,
 };
 
+/*
+ * USBHS
+ */
+static int usbhs_get_id(struct platform_device *pdev)
+{
+       return gpio_get_value(GPIO_PTB3);
+}
+
+static struct renesas_usbhs_platform_info usbhs_info = {
+       .platform_callback = {
+               .get_id         = usbhs_get_id,
+       },
+       .driver_param = {
+               .buswait_bwait          = 4,
+               .detection_delay        = 5,
+       },
+};
+
+static struct resource usbhs_resources[] = {
+       [0] = {
+               .start  = 0xa4d90000,
+               .end    = 0xa4d90124 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 66,
+               .end    = 66,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device usbhs_device = {
+       .name   = "renesas_usbhs",
+       .id     = 1,
+       .dev = {
+               .dma_mask               = NULL,         /*  not use dma */
+               .coherent_dma_mask      = 0xffffffff,
+               .platform_data          = &usbhs_info,
+       },
+       .num_resources  = ARRAY_SIZE(usbhs_resources),
+       .resource       = usbhs_resources,
+       .archdata = {
+               .hwblk_id = HWBLK_USB1,
+       },
+};
+
 /* LCDC */
 const static struct fb_videomode ecovec_lcd_modes[] = {
        {
@@ -885,6 +932,9 @@ static struct platform_device sh_mmcif_device = {
        },
        .num_resources  = ARRAY_SIZE(sh_mmcif_resources),
        .resource       = sh_mmcif_resources,
+       .archdata = {
+               .hwblk_id = HWBLK_MMC,
+       },
 };
 #endif
 
@@ -894,6 +944,7 @@ static struct platform_device *ecovec_devices[] __initdata = {
        &sh_eth_device,
        &usb0_host_device,
        &usb1_common_device,
+       &usbhs_device,
        &lcdc_device,
        &ceu0_device,
        &ceu1_device,
index 780e083e4d17fe6e2f55edf7793d24d57cb1559b..23bc849d9c64a2274924cbab5f29462c22402103 100644 (file)
@@ -27,8 +27,6 @@ IMAGE_OFFSET  := $(shell /bin/bash -c 'printf "0x%08x" \
                        $(CONFIG_BOOT_LINK_OFFSET)]')
 endif
 
-LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
-
 ifeq ($(CONFIG_MCOUNT),y)
 ORIG_CFLAGS := $(KBUILD_CFLAGS)
 KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
@@ -37,7 +35,25 @@ endif
 LDFLAGS_vmlinux := --oformat $(ld-bfd) -Ttext $(IMAGE_OFFSET) -e startup \
                   -T $(obj)/../../kernel/vmlinux.lds
 
-$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o $(LIBGCC) FORCE
+#
+# Pull in the necessary libgcc bits from the in-kernel implementation.
+#
+lib1funcs-$(CONFIG_SUPERH32)   := ashiftrt.S ashldi3.c ashrsi3.S ashlsi3.S \
+                                  lshrsi3.S
+lib1funcs-obj                  := \
+       $(addsuffix .o, $(basename $(addprefix $(obj)/, $(lib1funcs-y))))
+
+lib1funcs-dir          := $(srctree)/arch/$(SRCARCH)/lib
+ifeq ($(BITS),64)
+       lib1funcs-dir   := $(addsuffix $(BITS), $(lib1funcs-dir))
+endif
+
+KBUILD_CFLAGS += -I$(lib1funcs-dir)
+
+$(addprefix $(obj)/,$(lib1funcs-y)): $(obj)/%: $(lib1funcs-dir)/% FORCE
+       $(call cmd,shipped)
+
+$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o $(lib1funcs-obj) FORCE
        $(call if_changed,ld)
        @:
 
index 77ec0e7b8ddf6c68b5fa2ad6226a6a03dc57845b..e7583484cc07dd3d9ab257d094f769b94446397a 100644 (file)
@@ -7,7 +7,6 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CGROUPS=y
-CONFIG_CGROUP_NS=y
 CONFIG_CGROUP_FREEZER=y
 CONFIG_CGROUP_DEVICE=y
 CONFIG_CGROUP_CPUACCT=y
index c41650572d7957584804e4b5a3f9c03403176113..8a7dd7b59c5c01f9a0adf539e87ad569f6dd678e 100644 (file)
@@ -12,7 +12,6 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_CGROUPS=y
 CONFIG_CGROUP_DEBUG=y
-CONFIG_CGROUP_NS=y
 CONFIG_CGROUP_FREEZER=y
 CONFIG_CGROUP_DEVICE=y
 CONFIG_CPUSETS=y
index a468ff227fc6503c13fec6e3ab8e310aace0b876..72c3fad7383f5fc254d90fe3d499eb4a61ce1a47 100644 (file)
@@ -8,7 +8,6 @@ CONFIG_RCU_TRACE=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CGROUPS=y
 CONFIG_CGROUP_DEBUG=y
-CONFIG_CGROUP_NS=y
 CONFIG_CGROUP_DEVICE=y
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_RESOURCE_COUNTERS=y
index 3f92d37c6374e7dfde027bc5933eb40c07115d5d..6bb413036892cb2f50af2db94649584557703b91 100644 (file)
@@ -9,7 +9,6 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CGROUPS=y
-CONFIG_CGROUP_NS=y
 CONFIG_CGROUP_FREEZER=y
 CONFIG_CGROUP_DEVICE=y
 CONFIG_CGROUP_CPUACCT=y
index 0f558914e7604cc56a6822eeb2a2dec09c510abc..e2cbd92d520b347ca8e695cb2a8392dc72ac2794 100644 (file)
@@ -227,7 +227,7 @@ CONFIG_USB_SERIAL=m
 CONFIG_USB_SERIAL_GENERIC=y
 CONFIG_USB_SERIAL_ARK3116=m
 CONFIG_USB_SERIAL_PL2303=m
-CONFIG_RTC_CLASS=m
+CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_SH=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
index 7b3daec6fefe6cb7fe1a54a6c9bb4284cbe11bd5..8bfa4d056d7a6574e4ac7f4fa6d6b49a90001d7c 100644 (file)
@@ -9,7 +9,6 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CGROUPS=y
 CONFIG_CGROUP_DEBUG=y
-CONFIG_CGROUP_NS=y
 CONFIG_CGROUP_FREEZER=y
 CONFIG_CGROUP_DEVICE=y
 CONFIG_CPUSETS=y
index 4676bf57693a0ec3daf573d885731cfe7ed21963..f848dec9e483de8ed72cf3240c733d52f0da38e5 100644 (file)
@@ -15,8 +15,9 @@ static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val)
                "   mov.l   %2,   @%1     \n\t" /* store new value */
                "1: mov     r1,   r15     \n\t" /* LOGOUT */
                : "=&r" (retval),
-                 "+r"  (m)
-               : "r"   (val)
+                 "+r"  (m),
+                 "+r"  (val)           /* inhibit r15 overloading */
+               :
                : "memory", "r0", "r1");
 
        return retval;
@@ -36,8 +37,9 @@ static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val)
                "   mov.b   %2,   @%1     \n\t" /* store new value */
                "1: mov     r1,   r15     \n\t" /* LOGOUT */
                : "=&r" (retval),
-                 "+r"  (m)
-               : "r"   (val)
+                 "+r"  (m),
+                 "+r"  (val)           /* inhibit r15 overloading */
+               :
                : "memory" , "r0", "r1");
 
        return retval;
@@ -54,13 +56,14 @@ static inline unsigned long __cmpxchg_u32(volatile int *m, unsigned long old,
                "   nop                   \n\t"
                "   mov    r15,   r1      \n\t" /* r1 = saved sp */
                "   mov    #-8,   r15     \n\t" /* LOGIN */
-               "   mov.l  @%1,   %0      \n\t" /* load  old value */
-               "   cmp/eq  %0,   %2      \n\t"
+               "   mov.l  @%3,   %0      \n\t" /* load  old value */
+               "   cmp/eq  %0,   %1      \n\t"
                "   bf            1f      \n\t" /* if not equal */
-               "   mov.l   %3,   @%1     \n\t" /* store new value */
+               "   mov.l   %2,   @%3     \n\t" /* store new value */
                "1: mov     r1,   r15     \n\t" /* LOGOUT */
-               : "=&r" (retval)
-               :  "r"  (m), "r"  (old), "r"  (new)
+               : "=&r" (retval),
+                 "+r"  (old), "+r"  (new) /* old or new can be r15 */
+               :  "r"  (m)
                : "memory" , "r0", "r1", "t");
 
        return retval;
index 4235e228d921057c4e801e2ed2535b5f084132ff..f3613952d1aeb8469a0581b91fcd35c3c80ca3d0 100644 (file)
@@ -34,5 +34,6 @@ static inline void arch_kgdb_breakpoint(void)
 
 #define CACHE_FLUSH_IS_SAFE    1
 #define BREAK_INSTR_SIZE       2
+#define GDB_ADJUSTS_BREAK_OFFSET
 
 #endif /* __ASM_SH_KGDB_H */
index db85916b9e95aa8def960feff9b7b9ca1a5549f4..9210e93a92c337f18c94fd962bbeb5e23cfbb739 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/pgtable-2level.h>
 #endif
 #include <asm/page.h>
+#include <asm/mmu.h>
 
 #ifndef __ASSEMBLY__
 #include <asm/addrspace.h>
index 2a541ddb5a1b2f907a00b6e4764a6f2ecc3bfafa..e25c4c7d6b63171221e247cea5f6ee45136efaf7 100644 (file)
@@ -150,7 +150,6 @@ struct thread_struct {
 #define SR_USER (SR_MMU | SR_FD)
 
 #define start_thread(_regs, new_pc, new_sp)                    \
-       set_fs(USER_DS);                                        \
        _regs->sr = SR_USER;    /* User mode. */                \
        _regs->pc = new_pc - 4; /* Compensate syscall exit */   \
        _regs->pc |= 1;         /* Set SHmedia ! */             \
index de167d3a1a8023423cd9ed83f42e2038aa01bbee..88bd6be168a9c3c4ceb1c2494930a858958473f1 100644 (file)
 #include <asm/system.h>
 
 #define user_mode(regs)                        (((regs)->sr & 0x40000000)==0)
-#define user_stack_pointer(_regs)      ((unsigned long)(_regs)->regs[15])
 #define kernel_stack_pointer(_regs)    ((unsigned long)(_regs)->regs[15])
-#define instruction_pointer(regs)      ((unsigned long)(regs)->pc)
+
+#define GET_FP(regs)   ((regs)->regs[14])
+#define GET_USP(regs)  ((regs)->regs[15])
 
 extern void show_regs(struct pt_regs *);
 
@@ -132,13 +133,16 @@ extern void ptrace_triggered(struct perf_event *bp, int nmi,
 
 static inline unsigned long profile_pc(struct pt_regs *regs)
 {
-       unsigned long pc = instruction_pointer(regs);
+       unsigned long pc = regs->pc;
 
        if (virt_addr_uncached(pc))
                return CAC_ADDR(pc);
 
        return pc;
 }
+#define profile_pc profile_pc
+
+#include <asm-generic/ptrace.h>
 #endif /* __KERNEL__ */
 
 #endif /* __ASM_SH_PTRACE_H */
index 64eb41a063e8162c7bde64bdcf0cd8ce3e4c45b1..e14567a7e9a14814353fcf9c645d456c4bc5873f 100644 (file)
@@ -3,7 +3,6 @@
 
 #ifndef __ASSEMBLY__
 #include <linux/notifier.h>
-static inline int arch_prepare_suspend(void) { return 0; }
 
 #include <asm/ptrace.h>
 
index 75abb38dffd5d479e0b848615b7df115b72abad5..ec88bfcdf7ce57202e1402a03e491c01ef97af28 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/pagemap.h>
 
 #ifdef CONFIG_MMU
+#include <linux/swap.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
@@ -23,8 +24,6 @@ struct mmu_gather {
        unsigned long           start, end;
 };
 
-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 static inline void init_tlb_gather(struct mmu_gather *tlb)
 {
        tlb->start = TASK_SIZE;
@@ -36,17 +35,13 @@ static inline void init_tlb_gather(struct mmu_gather *tlb)
        }
 }
 
-static inline struct mmu_gather *
-tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
+static inline void
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int full_mm_flush)
 {
-       struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
-
        tlb->mm = mm;
        tlb->fullmm = full_mm_flush;
 
        init_tlb_gather(tlb);
-
-       return tlb;
 }
 
 static inline void
@@ -57,8 +52,6 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
 
        /* keep the page table cache within bounds */
        check_pgt_cache();
-
-       put_cpu_var(mmu_gathers);
 }
 
 static inline void
@@ -91,7 +84,21 @@ tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
        }
 }
 
-#define tlb_remove_page(tlb,page)      free_page_and_swap_cache(page)
+static inline void tlb_flush_mmu(struct mmu_gather *tlb)
+{
+}
+
+static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       free_page_and_swap_cache(page);
+       return 1; /* avoid calling tlb_flush_mmu */
+}
+
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       __tlb_remove_page(tlb, page);
+}
+
 #define pte_free_tlb(tlb, ptep, addr)  pte_free((tlb)->mm, ptep)
 #define pmd_free_tlb(tlb, pmdp, addr)  pmd_free((tlb)->mm, pmdp)
 #define pud_free_tlb(tlb, pudp, addr)  pud_free((tlb)->mm, pudp)
index bb7d2702c2c912b011a8c592362c2214414449aa..3432008d28880d360d6764a04fb257c86f291505 100644 (file)
 #define __NR_clock_adjtime     361
 #define __NR_syncfs            362
 #define __NR_sendmmsg          363
+#define __NR_setns             364
 
-#define NR_syscalls 364
+#define NR_syscalls 365
 
 #ifdef __KERNEL__
 
index 46327cea1e5c53e42ae9939d52985a647bc2d624..ec9898665f23fbbb2f1da713a5f875dd677ee5c2 100644 (file)
 #define __NR_clock_adjtime     372
 #define __NR_syncfs            373
 #define __NR_sendmmsg          374
+#define __NR_setns             375
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 375
+#define NR_syscalls 376
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 7a5b8a331b4aa55f6d7141486fd6153491c4a4a6..bd0622788d64a83ccb7f57799cb16c3143360cc9 100644 (file)
@@ -236,6 +236,7 @@ enum {
 };
 
 enum {
+       SHDMA_SLAVE_INVALID,
        SHDMA_SLAVE_SCIF0_TX,
        SHDMA_SLAVE_SCIF0_RX,
        SHDMA_SLAVE_SCIF1_TX,
index 7eb435999426e1979a5127942a4686114626e724..cbc47e6bcab5474b4c675af5600da0c66da1883e 100644 (file)
@@ -285,6 +285,7 @@ enum {
 };
 
 enum {
+       SHDMA_SLAVE_INVALID,
        SHDMA_SLAVE_SCIF0_TX,
        SHDMA_SLAVE_SCIF0_RX,
        SHDMA_SLAVE_SCIF1_TX,
@@ -297,6 +298,14 @@ enum {
        SHDMA_SLAVE_SCIF4_RX,
        SHDMA_SLAVE_SCIF5_TX,
        SHDMA_SLAVE_SCIF5_RX,
+       SHDMA_SLAVE_USB0D0_TX,
+       SHDMA_SLAVE_USB0D0_RX,
+       SHDMA_SLAVE_USB0D1_TX,
+       SHDMA_SLAVE_USB0D1_RX,
+       SHDMA_SLAVE_USB1D0_TX,
+       SHDMA_SLAVE_USB1D0_RX,
+       SHDMA_SLAVE_USB1D1_TX,
+       SHDMA_SLAVE_USB1D1_RX,
        SHDMA_SLAVE_SDHI0_TX,
        SHDMA_SLAVE_SDHI0_RX,
        SHDMA_SLAVE_SDHI1_TX,
index 05b8196c77539a647650311d9006a2d3e04b7c9e..41f9f8b9db735164fb9755d874f10576229968a5 100644 (file)
@@ -252,6 +252,7 @@ enum {
 };
 
 enum {
+       SHDMA_SLAVE_INVALID,
        SHDMA_SLAVE_SDHI_TX,
        SHDMA_SLAVE_SDHI_RX,
        SHDMA_SLAVE_MMCIF_TX,
index 0333fe9e3881913e82c5458b45e4f6aef5d867dd..134a397b1918e0898c6f839503fe0d9a4411c08c 100644 (file)
@@ -92,6 +92,46 @@ static const struct sh_dmae_slave_config sh7724_dmae_slaves[] = {
                .addr           = 0xa4e50024,
                .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
                .mid_rid        = 0x36,
+       }, {
+               .slave_id       = SHDMA_SLAVE_USB0D0_TX,
+               .addr           = 0xA4D80100,
+               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
+               .mid_rid        = 0x73,
+       }, {
+               .slave_id       = SHDMA_SLAVE_USB0D0_RX,
+               .addr           = 0xA4D80100,
+               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
+               .mid_rid        = 0x73,
+       }, {
+               .slave_id       = SHDMA_SLAVE_USB0D1_TX,
+               .addr           = 0xA4D80120,
+               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
+               .mid_rid        = 0x77,
+       }, {
+               .slave_id       = SHDMA_SLAVE_USB0D1_RX,
+               .addr           = 0xA4D80120,
+               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
+               .mid_rid        = 0x77,
+       }, {
+               .slave_id       = SHDMA_SLAVE_USB1D0_TX,
+               .addr           = 0xA4D90100,
+               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
+               .mid_rid        = 0xab,
+       }, {
+               .slave_id       = SHDMA_SLAVE_USB1D0_RX,
+               .addr           = 0xA4D90100,
+               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
+               .mid_rid        = 0xab,
+       }, {
+               .slave_id       = SHDMA_SLAVE_USB1D1_TX,
+               .addr           = 0xA4D90120,
+               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
+               .mid_rid        = 0xaf,
+       }, {
+               .slave_id       = SHDMA_SLAVE_USB1D1_RX,
+               .addr           = 0xA4D90120,
+               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
+               .mid_rid        = 0xaf,
        }, {
                .slave_id       = SHDMA_SLAVE_SDHI0_TX,
                .addr           = 0x04ce0030,
index 762a13984bbd76c897963c10f6513809d0cc345f..aaf6d59c201227b52c431e6be891868d756a5fda 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/fs.h>
 #include <linux/ftrace.h>
 #include <linux/hw_breakpoint.h>
+#include <linux/prefetch.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/system.h>
@@ -101,8 +102,6 @@ EXPORT_SYMBOL(kernel_thread);
 void start_thread(struct pt_regs *regs, unsigned long new_pc,
                  unsigned long new_sp)
 {
-       set_fs(USER_DS);
-
        regs->pr = 0;
        regs->sr = SR_FD;
        regs->pc = new_pc;
index 7c486f3e3a3c1d969a1af787520034a6441172e2..39b051de4c7ca4d6c7d13fb983232bf2be1f26f6 100644 (file)
@@ -381,3 +381,4 @@ ENTRY(sys_call_table)
        .long sys_clock_adjtime
        .long sys_syncfs
        .long sys_sendmmsg
+       .long sys_setns
index ba1a737afe80723bf4e5fcad513f09f339087acb..089c4d825d087a27585a295ee7509d409a76b786 100644 (file)
@@ -401,3 +401,4 @@ sys_call_table:
        .long sys_clock_adjtime
        .long sys_syncfs
        .long sys_sendmmsg
+       .long sys_setns                 /* 375 */
index af4d46187a79f18bb8ae350294ccb5923f5410fb..731c10ce67b56dd482e95c2ecdb239de023ea831 100644 (file)
@@ -66,7 +66,7 @@ SECTIONS
                __machvec_end = .;
        }
 
-       PERCPU(L1_CACHE_BYTES, PAGE_SIZE)
+       PERCPU_SECTION(L1_CACHE_BYTES)
 
        /*
         * .exit.text is discarded at runtime, not link time, to deal with
index 52411462c4096f973243e5c05acc9ebfc357819a..115725198038da862a19ef634a0ec38adf23b76f 100644 (file)
@@ -26,9 +26,9 @@ static int cache_seq_show(struct seq_file *file, void *iter)
 {
        unsigned int cache_type = (unsigned int)file->private;
        struct cache_info *cache;
-       unsigned int waysize, way, cache_size;
-       unsigned long ccr, base;
-       static unsigned long addrstart = 0;
+       unsigned int waysize, way;
+       unsigned long ccr;
+       unsigned long addrstart = 0;
 
        /*
         * Go uncached immediately so we don't skew the results any
@@ -45,28 +45,13 @@ static int cache_seq_show(struct seq_file *file, void *iter)
        }
 
        if (cache_type == CACHE_TYPE_DCACHE) {
-               base = CACHE_OC_ADDRESS_ARRAY;
+               addrstart = CACHE_OC_ADDRESS_ARRAY;
                cache = &current_cpu_data.dcache;
        } else {
-               base = CACHE_IC_ADDRESS_ARRAY;
+               addrstart = CACHE_IC_ADDRESS_ARRAY;
                cache = &current_cpu_data.icache;
        }
 
-       /*
-        * Due to the amount of data written out (depending on the cache size),
-        * we may be iterated over multiple times. In this case, keep track of
-        * the entry position in addrstart, and rewind it when we've hit the
-        * end of the cache.
-        *
-        * Likewise, the same code is used for multiple caches, so care must
-        * be taken for bouncing addrstart back and forth so the appropriate
-        * cache is hit.
-        */
-       cache_size = cache->ways * cache->sets * cache->linesz;
-       if (((addrstart & 0xff000000) != base) ||
-            (addrstart & 0x00ffffff) > cache_size)
-               addrstart = base;
-
        waysize = cache->sets;
 
        /*
index 40733a9524021d42d42ddc5a8d7e08ef77a1c155..f251b5f27652f3aa278c3789d198e88c841c3938 100644 (file)
@@ -82,7 +82,7 @@ void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
        void *addr;
 
        addr = __in_29bit_mode() ?
-              (void *)P1SEGADDR((unsigned long)vaddr) : vaddr;
+              (void *)CAC_ADDR((unsigned long)vaddr) : vaddr;
 
        switch (direction) {
        case DMA_FROM_DEVICE:           /* invalidate only */
index 0d3f912e3334b1ecd07e5ec7c34b9ee84326bb56..58a93fb3d965055739e8484f0a1045bf338e0194 100644 (file)
@@ -28,7 +28,6 @@
 #include <asm/cache.h>
 #include <asm/sizes.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
 void __init generic_mem_init(void)
index 63a027c9ada5aabf99fdea93c2f355e431076cce..253986bd6bb625a270ae1f27b99d967650b178c4 100644 (file)
@@ -26,7 +26,6 @@ config SPARC
        select HAVE_DMA_API_DEBUG
        select HAVE_ARCH_JUMP_LABEL
        select HAVE_GENERIC_HARDIRQS
-       select GENERIC_HARDIRQS_NO_DEPRECATED
        select GENERIC_IRQ_SHOW
        select USE_GENERIC_SMP_HELPERS if SMP
 
@@ -190,14 +189,6 @@ config RWSEM_XCHGADD_ALGORITHM
        bool
        default y if SPARC64
 
-config GENERIC_FIND_NEXT_BIT
-       bool
-       default y
-
-config GENERIC_FIND_BIT_LE
-       bool
-       default y
-
 config GENERIC_HWEIGHT
        bool
        default y if !ULTRA_HAS_POPULATION_COUNT
@@ -536,6 +527,23 @@ config PCI_DOMAINS
 config PCI_SYSCALL
        def_bool PCI
 
+config PCIC_PCI
+       bool
+       depends on PCI && SPARC32 && !SPARC_LEON
+       default y
+
+config LEON_PCI
+       bool
+       depends on PCI && SPARC_LEON
+       default y
+
+config GRPCI2
+       bool "GRPCI2 Host Bridge Support"
+       depends on LEON_PCI
+       default y
+       help
+         Say Y here to include the GRPCI2 Host Bridge Driver.
+
 source "drivers/pci/Kconfig"
 
 source "drivers/pcmcia/Kconfig"
index d9a795efbc045ea548f1fc60adf1d59cbe1437c3..6db35fba79fd2fe77977cbf47b053d2608b0e98a 100644 (file)
@@ -6,15 +6,6 @@ config TRACE_IRQFLAGS_SUPPORT
 
 source "lib/Kconfig.debug"
 
-config DEBUG_STACK_USAGE
-       bool "Enable stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T and sysrq-P debug output.
-
-         This option will slow down process creation somewhat.
-
 config DEBUG_DCFLUSH
        bool "D-cache flush debugging"
        depends on SPARC64 && DEBUG_KERNEL
index 482c79e2a41685343025cb9514eef7e205b2f637..7440915e86d8d970216a944b32765b1499a59192 100644 (file)
@@ -138,7 +138,7 @@ static unsigned char sun_82072_fd_inb(int port)
                return sun_fdc->data_82072;
        case 7: /* FD_DIR */
                return sun_read_dir();
-       };
+       }
        panic("sun_82072_fd_inb: How did I get here?");
 }
 
@@ -161,7 +161,7 @@ static void sun_82072_fd_outb(unsigned char value, int port)
        case 4: /* FD_STATUS */
                sun_fdc->status_82072 = value;
                break;
-       };
+       }
        return;
 }
 
@@ -186,7 +186,7 @@ static unsigned char sun_82077_fd_inb(int port)
                return sun_fdc->data_82077;
        case 7: /* FD_DIR */
                return sun_read_dir();
-       };
+       }
        panic("sun_82077_fd_inb: How did I get here?");
 }
 
@@ -212,7 +212,7 @@ static void sun_82077_fd_outb(unsigned char value, int port)
        case 3: /* FD_TDR */
                sun_fdc->tapectl_82077 = value;
                break;
-       };
+       }
        return;
 }
 
index 6597ce874d78761147e7ae206bca34c444c3ad87..bcef1f5a2a6d16945022494cb7d5fd3c1122fc44 100644 (file)
@@ -111,7 +111,7 @@ static unsigned char sun_82077_fd_inb(unsigned long port)
        case 7: /* FD_DIR */
                /* XXX: Is DCL on 0x80 in sun4m? */
                return sbus_readb(&sun_fdc->dir_82077);
-       };
+       }
        panic("sun_82072_fd_inb: How did I get here?");
 }
 
@@ -135,7 +135,7 @@ static void sun_82077_fd_outb(unsigned char value, unsigned long port)
        case 4: /* FD_STATUS */
                sbus_writeb(value, &sun_fdc->status_82077);
                break;
-       };
+       }
        return;
 }
 
index 6bdaf1e43d2aef8eba06e01da9f963706d54c2d2..a4e457f003ed07a1b3a47e60d4781e8739ecbef2 100644 (file)
@@ -318,6 +318,9 @@ struct device_node;
 extern unsigned int leon_build_device_irq(unsigned int real_irq,
                                           irq_flow_handler_t flow_handler,
                                           const char *name, int do_ack);
+extern void leon_update_virq_handling(unsigned int virq,
+                             irq_flow_handler_t flow_handler,
+                             const char *name, int do_ack);
 extern void leon_clear_clock_irq(void);
 extern void leon_load_profile_irq(int cpu, unsigned int limit);
 extern void leon_init_timers(irq_handler_t counter_fn);
diff --git a/arch/sparc/include/asm/leon_pci.h b/arch/sparc/include/asm/leon_pci.h
new file mode 100644 (file)
index 0000000..42b4b31
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * asm/leon_pci.h
+ *
+ * Copyright (C) 2011 Aeroflex Gaisler AB, Daniel Hellstrom
+ */
+
+#ifndef _ASM_LEON_PCI_H_
+#define _ASM_LEON_PCI_H_
+
+/* PCI related definitions */
+struct leon_pci_info {
+       struct pci_ops *ops;
+       struct resource io_space;
+       struct resource mem_space;
+       int (*map_irq)(struct pci_dev *dev, u8 slot, u8 pin);
+};
+
+extern void leon_pci_init(struct platform_device *ofdev,
+                               struct leon_pci_info *info);
+
+#endif /* _ASM_LEON_PCI_H_ */
index 332ac9ab36bc61c486e787d4cf962ae39c067d29..862e3ce92b15d45659c1ca343a3ad317c9dfb7b3 100644 (file)
@@ -47,7 +47,31 @@ extern struct device_node *pci_device_to_OF_node(struct pci_dev *pdev);
 
 #endif /* __KERNEL__ */
 
+#ifndef CONFIG_LEON_PCI
 /* generic pci stuff */
 #include <asm-generic/pci.h>
+#else
+/*
+ * On LEON PCI Memory space is mapped 1:1 with physical address space.
+ *
+ * I/O space is located at low 64Kbytes in PCI I/O space. The I/O addresses
+ * are converted into CPU addresses to virtual addresses that are mapped with
+ * MMU to the PCI Host PCI I/O space window which are translated to the low
+ * 64Kbytes by the Host controller.
+ */
+
+extern void
+pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+                       struct resource *res);
+
+extern void
+pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+                       struct pci_bus_region *region);
+
+static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
+{
+       return PCI_IRQ_NONE;
+}
+#endif
 
 #endif /* __SPARC_PCI_H */
index 7eb5d78f5211d04782430eeb8c71b8083522f22f..6676cbcc8b6a37799633e2850fbc72540e825c24 100644 (file)
@@ -29,7 +29,7 @@ struct linux_pcic {
        int                     pcic_imdim;
 };
 
-#ifdef CONFIG_PCI
+#ifdef CONFIG_PCIC_PCI
 extern int pcic_present(void);
 extern int pcic_probe(void);
 extern void pci_time_init(void);
index 5bdfa2c6e4006eb315e50a30c7df82c12b147d73..4e5e0878144f3331835f8327e334db1dc97872cf 100644 (file)
@@ -78,4 +78,7 @@ static inline void check_pgt_cache(void)
        quicklist_trim(0, NULL, 25, 16);
 }
 
+#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte)
+#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd)
+
 #endif /* _SPARC64_PGALLOC_H */
index b77128c80524fb7166a83d7411bd0c1a66acc5fb..1e03c5a6b4f73b30775f763ec014a61f409cf400 100644 (file)
@@ -655,9 +655,11 @@ static inline int pte_special(pte_t pte)
 #define pte_unmap(pte)                 do { } while (0)
 
 /* Actual page table PTE updates.  */
-extern void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t orig);
+extern void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr,
+                         pte_t *ptep, pte_t orig, int fullmm);
 
-static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
+static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
+                            pte_t *ptep, pte_t pte, int fullmm)
 {
        pte_t orig = *ptep;
 
@@ -670,12 +672,19 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *p
         *             and SUN4V pte layout, so this inline test is fine.
         */
        if (likely(mm != &init_mm) && (pte_val(orig) & _PAGE_VALID))
-               tlb_batch_add(mm, addr, ptep, orig);
+               tlb_batch_add(mm, addr, ptep, orig, fullmm);
 }
 
+#define set_pte_at(mm,addr,ptep,pte)   \
+       __set_pte_at((mm), (addr), (ptep), (pte), 0)
+
 #define pte_clear(mm,addr,ptep)                \
        set_pte_at((mm), (addr), (ptep), __pte(0UL))
 
+#define __HAVE_ARCH_PTE_CLEAR_NOT_PRESENT_FULL
+#define pte_clear_not_present_full(mm,addr,ptep,fullmm)        \
+       __set_pte_at((mm), (addr), (ptep), __pte(0UL), (fullmm))
+
 #ifdef DCACHE_ALIASING_POSSIBLE
 #define __HAVE_ARCH_MOVE_PTE
 #define move_pte(pte, prot, old_addr, new_addr)                                \
index 47a7e862474efa94247d0192945ae23af8fcb78e..aba16092a81b68063138594cf45aa9b4e79f7a7e 100644 (file)
@@ -220,7 +220,7 @@ static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int
        switch (size) {
        case 4:
                return xchg_u32(ptr, x);
-       };
+       }
        __xchg_called_with_bad_pointer();
        return x;
 }
index 3c96d3bb9f151d0112c922dedea653bc3acafe4d..10bcabce97b2d94a1487a1572756a73c4993dd18 100644 (file)
@@ -234,7 +234,7 @@ static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr,
                return xchg32(ptr, x);
        case 8:
                return xchg64(ptr, x);
-       };
+       }
        __xchg_called_with_bad_pointer();
        return x;
 }
index dca406b9b6fc5b9b6400732d6abe3a9f1e9e528d..190e18913cc6968213cb468b07963db26f965ebd 100644 (file)
@@ -7,66 +7,11 @@
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
 
-#define TLB_BATCH_NR   192
-
-/*
- * For UP we don't need to worry about TLB flush
- * and page free order so much..
- */
-#ifdef CONFIG_SMP
-  #define FREE_PTE_NR  506
-  #define tlb_fast_mode(bp) ((bp)->pages_nr == ~0U)
-#else
-  #define FREE_PTE_NR  1
-  #define tlb_fast_mode(bp) 1
-#endif
-
-struct mmu_gather {
-       struct mm_struct *mm;
-       unsigned int pages_nr;
-       unsigned int need_flush;
-       unsigned int fullmm;
-       unsigned int tlb_nr;
-       unsigned long vaddrs[TLB_BATCH_NR];
-       struct page *pages[FREE_PTE_NR];
-};
-
-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 #ifdef CONFIG_SMP
 extern void smp_flush_tlb_pending(struct mm_struct *,
                                  unsigned long, unsigned long *);
 #endif
 
-extern void __flush_tlb_pending(unsigned long, unsigned long, unsigned long *);
-extern void flush_tlb_pending(void);
-
-static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
-{
-       struct mmu_gather *mp = &get_cpu_var(mmu_gathers);
-
-       BUG_ON(mp->tlb_nr);
-
-       mp->mm = mm;
-       mp->pages_nr = num_online_cpus() > 1 ? 0U : ~0U;
-       mp->fullmm = full_mm_flush;
-
-       return mp;
-}
-
-
-static inline void tlb_flush_mmu(struct mmu_gather *mp)
-{
-       if (!mp->fullmm)
-               flush_tlb_pending();
-       if (mp->need_flush) {
-               free_pages_and_swap_cache(mp->pages, mp->pages_nr);
-               mp->pages_nr = 0;
-               mp->need_flush = 0;
-       }
-
-}
-
 #ifdef CONFIG_SMP
 extern void smp_flush_tlb_mm(struct mm_struct *mm);
 #define do_flush_tlb_mm(mm) smp_flush_tlb_mm(mm)
@@ -74,38 +19,14 @@ extern void smp_flush_tlb_mm(struct mm_struct *mm);
 #define do_flush_tlb_mm(mm) __flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT)
 #endif
 
-static inline void tlb_finish_mmu(struct mmu_gather *mp, unsigned long start, unsigned long end)
-{
-       tlb_flush_mmu(mp);
-
-       if (mp->fullmm)
-               mp->fullmm = 0;
-
-       /* keep the page table cache within bounds */
-       check_pgt_cache();
-
-       put_cpu_var(mmu_gathers);
-}
-
-static inline void tlb_remove_page(struct mmu_gather *mp, struct page *page)
-{
-       if (tlb_fast_mode(mp)) {
-               free_page_and_swap_cache(page);
-               return;
-       }
-       mp->need_flush = 1;
-       mp->pages[mp->pages_nr++] = page;
-       if (mp->pages_nr >= FREE_PTE_NR)
-               tlb_flush_mmu(mp);
-}
-
-#define tlb_remove_tlb_entry(mp,ptep,addr) do { } while (0)
-#define pte_free_tlb(mp, ptepage, addr) pte_free((mp)->mm, ptepage)
-#define pmd_free_tlb(mp, pmdp, addr) pmd_free((mp)->mm, pmdp)
-#define pud_free_tlb(tlb,pudp, addr) __pud_free_tlb(tlb,pudp,addr)
+extern void __flush_tlb_pending(unsigned long, unsigned long, unsigned long *);
+extern void flush_tlb_pending(void);
 
-#define tlb_migrate_finish(mm) do { } while (0)
 #define tlb_start_vma(tlb, vma) do { } while (0)
 #define tlb_end_vma(tlb, vma)  do { } while (0)
+#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0)
+#define tlb_flush(tlb) flush_tlb_pending()
+
+#include <asm-generic/tlb.h>
 
 #endif /* _SPARC64_TLB_H */
index fbb675dbe0c92abe8bead2c0a46c58451fa4d0e1..2ef463494153a65adec7c7a59a37c0095fda2649 100644 (file)
@@ -5,9 +5,17 @@
 #include <asm/mmu_context.h>
 
 /* TSB flush operations. */
-struct mmu_gather;
+
+#define TLB_BATCH_NR   192
+
+struct tlb_batch {
+       struct mm_struct *mm;
+       unsigned long tlb_nr;
+       unsigned long vaddrs[TLB_BATCH_NR];
+};
+
 extern void flush_tsb_kernel_range(unsigned long start, unsigned long end);
-extern void flush_tsb_user(struct mmu_gather *mp);
+extern void flush_tsb_user(struct tlb_batch *tb);
 
 /* TLB flush operations. */
 
index c5387ed0add8f87e9c98d165055484a05e60931c..6260d5deeabca0a009526078a87d1628d960f905 100644 (file)
 #define __NR_clock_adjtime     334
 #define __NR_syncfs            335
 #define __NR_sendmmsg          336
+#define __NR_setns             337
 
-#define NR_syscalls            337
+#define NR_syscalls            338
 
 #ifdef __32bit_syscall_numbers__
 /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
index 9cff2709a96df89576b460d1138199c79c4eb5c2..b90b4a1d070ad3e33b6b2ba6e3de59327c59677d 100644 (file)
@@ -73,7 +73,9 @@ obj-$(CONFIG_SPARC64_SMP) += cpumap.o
 
 obj-y                     += dma.o
 
-obj-$(CONFIG_SPARC32_PCI) += pcic.o
+obj-$(CONFIG_PCIC_PCI)    += pcic.o
+obj-$(CONFIG_LEON_PCI)    += leon_pci.o
+obj-$(CONFIG_GRPCI2)      += leon_pci_grpci2.o
 
 obj-$(CONFIG_SMP)         += trampoline_$(BITS).o smp_$(BITS).o
 obj-$(CONFIG_SPARC32_SMP) += sun4m_smp.o sun4d_smp.o leon_smp.o
index 1e34f29e58bb723537429dd0aacb9e0fe7df11b9..caef9deb5866f6d87a6fd3d72cb0bc4b25719080 100644 (file)
@@ -123,7 +123,7 @@ static long apc_ioctl(struct file *f, unsigned int cmd, unsigned long __arg)
 
        default:
                return -EINVAL;
-       };
+       }
 
        return 0;
 }
index 8505e0ac78baaf27331681302961f1bb7e173154..acf5151f3c1d7b9ffe24012bbe0d0047107dec1f 100644 (file)
@@ -101,7 +101,7 @@ void set_auxio(unsigned char bits_on, unsigned char bits_off)
                break;
        default:
                panic("Can't set AUXIO register on this machine.");
-       };
+       }
        spin_unlock_irqrestore(&auxio_lock, flags);
 }
 EXPORT_SYMBOL(set_auxio);
index 668c7be5d365265b8f3ea4a645c196d528a772d6..5f450260981dd3f564db36387b8e80b817b36986 100644 (file)
@@ -664,7 +664,7 @@ static void chmc_interpret_one_decode_reg(struct chmc *p, int which_bank, u64 va
        case 0x0:
                bp->interleave = 16;
                break;
-       };
+       }
 
        /* UK[10] is reserved, and UK[11] is not set for the SDRAM
         * bank size definition.
index 8341963f4c84c10f5974edfa6f10af7db42754bd..9fe08a1ea6c6ea226f9cb4a91bf1f183067d98da 100644 (file)
@@ -229,7 +229,7 @@ real_irq_entry:
 #ifdef CONFIG_SMP
        .globl  patchme_maybe_smp_msg
 
-       cmp     %l7, 12
+       cmp     %l7, 11
 patchme_maybe_smp_msg:
        bgu     maybe_smp4m_msg
         nop
@@ -293,7 +293,7 @@ maybe_smp4m_msg:
        WRITE_PAUSE
        wr      %l4, PSR_ET, %psr
        WRITE_PAUSE
-       sll     %o2, 28, %o2            ! shift for simpler checks below
+       sll     %o3, 28, %o2            ! shift for simpler checks below
 maybe_smp4m_msg_check_single:
        andcc   %o2, 0x1, %g0
        beq,a   maybe_smp4m_msg_check_mask
@@ -1604,7 +1604,7 @@ restore_current:
        retl
         nop
 
-#ifdef CONFIG_PCI
+#ifdef CONFIG_PCIC_PCI
 #include <asm/pcic.h>
 
        .align  4
@@ -1650,7 +1650,7 @@ pcic_nmi_trap_patch:
         rd     %psr, %l0
        .word   0
 
-#endif /* CONFIG_PCI */
+#endif /* CONFIG_PCIC_PCI */
 
        .globl  flushw_all
 flushw_all:
index 2f538ac2e139b68c5ffea31b12520c0672b83a88..d17255a2bbac142be0f3fe3b1e5e4a60d49a363e 100644 (file)
@@ -236,6 +236,21 @@ static unsigned int _leon_build_device_irq(struct platform_device *op,
        return leon_build_device_irq(real_irq, handle_simple_irq, "edge", 0);
 }
 
+void leon_update_virq_handling(unsigned int virq,
+                             irq_flow_handler_t flow_handler,
+                             const char *name, int do_ack)
+{
+       unsigned long mask = (unsigned long)irq_get_chip_data(virq);
+
+       mask &= ~LEON_DO_ACK_HW;
+       if (do_ack)
+               mask |= LEON_DO_ACK_HW;
+
+       irq_set_chip_and_handler_name(virq, &leon_irq,
+                                     flow_handler, name);
+       irq_set_chip_data(virq, (void *)mask);
+}
+
 void __init leon_init_timers(irq_handler_t counter_fn)
 {
        int irq, eirq;
@@ -361,6 +376,22 @@ void __init leon_init_timers(irq_handler_t counter_fn)
                prom_halt();
        }
 
+#ifdef CONFIG_SMP
+       {
+               unsigned long flags;
+
+               /*
+                * In SMP, sun4m adds a IPI handler to IRQ trap handler that
+                * LEON never must take, sun4d and LEON overwrites the branch
+                * with a NOP.
+                */
+               local_irq_save(flags);
+               patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
+               local_flush_cache_all();
+               local_irq_restore(flags);
+       }
+#endif
+
        LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl,
                              LEON3_GPTIMER_EN |
                              LEON3_GPTIMER_RL |
diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c
new file mode 100644 (file)
index 0000000..a8a9a27
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * leon_pci.c: LEON Host PCI support
+ *
+ * Copyright (C) 2011 Aeroflex Gaisler AB, Daniel Hellstrom
+ *
+ * Code is partially derived from pcic.c
+ */
+
+#include <linux/of_device.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <asm/leon.h>
+#include <asm/leon_pci.h>
+
+/* The LEON architecture does not rely on a BIOS or bootloader to setup
+ * PCI for us. The Linux generic routines are used to setup resources,
+ * reset values of confuration-space registers settings ae preseved.
+ */
+void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
+{
+       struct pci_bus *root_bus;
+
+       root_bus = pci_scan_bus_parented(&ofdev->dev, 0, info->ops, info);
+       if (root_bus) {
+               root_bus->resource[0] = &info->io_space;
+               root_bus->resource[1] = &info->mem_space;
+               root_bus->resource[2] = NULL;
+
+               /* Init all PCI devices into PCI tree */
+               pci_bus_add_devices(root_bus);
+
+               /* Setup IRQs of all devices using custom routines */
+               pci_fixup_irqs(pci_common_swizzle, info->map_irq);
+
+               /* Assign devices with resources */
+               pci_assign_unassigned_resources();
+       }
+}
+
+/* PCI Memory and Prefetchable Memory is direct-mapped. However I/O Space is
+ * accessed through a Window which is translated to low 64KB in PCI space, the
+ * first 4KB is not used so 60KB is available.
+ *
+ * This function is used by generic code to translate resource addresses into
+ * PCI addresses.
+ */
+void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+                            struct resource *res)
+{
+       struct leon_pci_info *info = dev->bus->sysdata;
+
+       region->start = res->start;
+       region->end = res->end;
+
+       if (res->flags & IORESOURCE_IO) {
+               region->start -= (info->io_space.start - 0x1000);
+               region->end -= (info->io_space.start - 0x1000);
+       }
+}
+EXPORT_SYMBOL(pcibios_resource_to_bus);
+
+/* see pcibios_resource_to_bus() comment */
+void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+                            struct pci_bus_region *region)
+{
+       struct leon_pci_info *info = dev->bus->sysdata;
+
+       res->start = region->start;
+       res->end = region->end;
+
+       if (res->flags & IORESOURCE_IO) {
+               res->start += (info->io_space.start - 0x1000);
+               res->end += (info->io_space.start - 0x1000);
+       }
+}
+EXPORT_SYMBOL(pcibios_bus_to_resource);
+
+void __devinit pcibios_fixup_bus(struct pci_bus *pbus)
+{
+       struct leon_pci_info *info = pbus->sysdata;
+       struct pci_dev *dev;
+       int i, has_io, has_mem;
+       u16 cmd;
+
+       /* Generic PCI bus probing sets these to point at
+        * &io{port,mem}_resouce which is wrong for us.
+        */
+       if (pbus->self == NULL) {
+               pbus->resource[0] = &info->io_space;
+               pbus->resource[1] = &info->mem_space;
+               pbus->resource[2] = NULL;
+       }
+
+       list_for_each_entry(dev, &pbus->devices, bus_list) {
+               /*
+                * We can not rely on that the bootloader has enabled I/O
+                * or memory access to PCI devices. Instead we enable it here
+                * if the device has BARs of respective type.
+                */
+               has_io = has_mem = 0;
+               for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+                       unsigned long f = dev->resource[i].flags;
+                       if (f & IORESOURCE_IO)
+                               has_io = 1;
+                       else if (f & IORESOURCE_MEM)
+                               has_mem = 1;
+               }
+               /* ROM BARs are mapped into 32-bit memory space */
+               if (dev->resource[PCI_ROM_RESOURCE].end != 0) {
+                       dev->resource[PCI_ROM_RESOURCE].flags |=
+                                                       IORESOURCE_ROM_ENABLE;
+                       has_mem = 1;
+               }
+               pci_bus_read_config_word(pbus, dev->devfn, PCI_COMMAND, &cmd);
+               if (has_io && !(cmd & PCI_COMMAND_IO)) {
+#ifdef CONFIG_PCI_DEBUG
+                       printk(KERN_INFO "LEONPCI: Enabling I/O for dev %s\n",
+                                        pci_name(dev));
+#endif
+                       cmd |= PCI_COMMAND_IO;
+                       pci_bus_write_config_word(pbus, dev->devfn, PCI_COMMAND,
+                                                                       cmd);
+               }
+               if (has_mem && !(cmd & PCI_COMMAND_MEMORY)) {
+#ifdef CONFIG_PCI_DEBUG
+                       printk(KERN_INFO "LEONPCI: Enabling MEMORY for dev"
+                                        "%s\n", pci_name(dev));
+#endif
+                       cmd |= PCI_COMMAND_MEMORY;
+                       pci_bus_write_config_word(pbus, dev->devfn, PCI_COMMAND,
+                                                                       cmd);
+               }
+       }
+}
+
+/*
+ * Other archs parse arguments here.
+ */
+char * __devinit pcibios_setup(char *str)
+{
+       return str;
+}
+
+resource_size_t pcibios_align_resource(void *data, const struct resource *res,
+                               resource_size_t size, resource_size_t align)
+{
+       return res->start;
+}
+
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+       return pci_enable_resources(dev, mask);
+}
+
+struct device_node *pci_device_to_OF_node(struct pci_dev *pdev)
+{
+       /*
+        * Currently the OpenBoot nodes are not connected with the PCI device,
+        * this is because the LEON PROM does not create PCI nodes. Eventually
+        * this will change and the same approach as pcic.c can be used to
+        * match PROM nodes with pci devices.
+        */
+       return NULL;
+}
+EXPORT_SYMBOL(pci_device_to_OF_node);
+
+void __devinit pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+#ifdef CONFIG_PCI_DEBUG
+       printk(KERN_DEBUG "LEONPCI: Assigning IRQ %02d to %s\n", irq,
+               pci_name(dev));
+#endif
+       pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+/* in/out routines taken from pcic.c
+ *
+ * This probably belongs here rather than ioport.c because
+ * we do not want this crud linked into SBus kernels.
+ * Also, think for a moment about likes of floppy.c that
+ * include architecture specific parts. They may want to redefine ins/outs.
+ *
+ * We do not use horrible macros here because we want to
+ * advance pointer by sizeof(size).
+ */
+void outsb(unsigned long addr, const void *src, unsigned long count)
+{
+       while (count) {
+               count -= 1;
+               outb(*(const char *)src, addr);
+               src += 1;
+               /* addr += 1; */
+       }
+}
+EXPORT_SYMBOL(outsb);
+
+void outsw(unsigned long addr, const void *src, unsigned long count)
+{
+       while (count) {
+               count -= 2;
+               outw(*(const short *)src, addr);
+               src += 2;
+               /* addr += 2; */
+       }
+}
+EXPORT_SYMBOL(outsw);
+
+void outsl(unsigned long addr, const void *src, unsigned long count)
+{
+       while (count) {
+               count -= 4;
+               outl(*(const long *)src, addr);
+               src += 4;
+               /* addr += 4; */
+       }
+}
+EXPORT_SYMBOL(outsl);
+
+void insb(unsigned long addr, void *dst, unsigned long count)
+{
+       while (count) {
+               count -= 1;
+               *(unsigned char *)dst = inb(addr);
+               dst += 1;
+               /* addr += 1; */
+       }
+}
+EXPORT_SYMBOL(insb);
+
+void insw(unsigned long addr, void *dst, unsigned long count)
+{
+       while (count) {
+               count -= 2;
+               *(unsigned short *)dst = inw(addr);
+               dst += 2;
+               /* addr += 2; */
+       }
+}
+EXPORT_SYMBOL(insw);
+
+void insl(unsigned long addr, void *dst, unsigned long count)
+{
+       while (count) {
+               count -= 4;
+               /*
+                * XXX I am sure we are in for an unaligned trap here.
+                */
+               *(unsigned long *)dst = inl(addr);
+               dst += 4;
+               /* addr += 4; */
+       }
+}
+EXPORT_SYMBOL(insl);
diff --git a/arch/sparc/kernel/leon_pci_grpci2.c b/arch/sparc/kernel/leon_pci_grpci2.c
new file mode 100644 (file)
index 0000000..44dc093
--- /dev/null
@@ -0,0 +1,897 @@
+/*
+ * leon_pci_grpci2.c: GRPCI2 Host PCI driver
+ *
+ * Copyright (C) 2011 Aeroflex Gaisler AB, Daniel Hellstrom
+ *
+ */
+
+#include <linux/of_device.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/leon.h>
+#include <asm/vaddrs.h>
+#include <asm/sections.h>
+#include <asm/leon_pci.h>
+
+#include "irq.h"
+
+struct grpci2_barcfg {
+       unsigned long pciadr;   /* PCI Space Address */
+       unsigned long ahbadr;   /* PCI Base address mapped to this AHB addr */
+};
+
+/* Device Node Configuration options:
+ *  - barcfgs    : Custom Configuration of Host's 6 target BARs
+ *  - irq_mask   : Limit which PCI interrupts are enabled
+ *  - do_reset   : Force PCI Reset on startup
+ *
+ * barcfgs
+ * =======
+ *
+ * Optional custom Target BAR configuration (see struct grpci2_barcfg). All
+ * addresses are physical. Array always contains 6 elements (len=2*4*6 bytes)
+ *
+ * -1 means not configured (let host driver do default setup).
+ *
+ * [i*2+0] = PCI Address of BAR[i] on target interface
+ * [i*2+1] = Accessing PCI address of BAR[i] result in this AMBA address
+ *
+ *
+ * irq_mask
+ * ========
+ *
+ * Limit which PCI interrupts are enabled. 0=Disable, 1=Enable. By default
+ * all are enabled. Use this when PCI interrupt pins are floating on PCB.
+ * int, len=4.
+ *  bit0 = PCI INTA#
+ *  bit1 = PCI INTB#
+ *  bit2 = PCI INTC#
+ *  bit3 = PCI INTD#
+ *
+ *
+ * reset
+ * =====
+ *
+ * Force PCI reset on startup. int, len=4
+ */
+
+/* Enable Debugging Configuration Space Access */
+#undef GRPCI2_DEBUG_CFGACCESS
+
+/*
+ * GRPCI2 APB Register MAP
+ */
+struct grpci2_regs {
+       unsigned int ctrl;              /* 0x00 Control */
+       unsigned int sts_cap;           /* 0x04 Status / Capabilities */
+       int res1;                       /* 0x08 */
+       unsigned int io_map;            /* 0x0C I/O Map address */
+       unsigned int dma_ctrl;          /* 0x10 DMA */
+       unsigned int dma_bdbase;        /* 0x14 DMA */
+       int res2[2];                    /* 0x18 */
+       unsigned int bars[6];           /* 0x20 read-only PCI BARs */
+       int res3[2];                    /* 0x38 */
+       unsigned int ahbmst_map[16];    /* 0x40 AHB->PCI Map per AHB Master */
+
+       /* PCI Trace Buffer Registers (OPTIONAL) */
+       unsigned int t_ctrl;            /* 0x80 */
+       unsigned int t_cnt;             /* 0x84 */
+       unsigned int t_adpat;           /* 0x88 */
+       unsigned int t_admask;          /* 0x8C */
+       unsigned int t_sigpat;          /* 0x90 */
+       unsigned int t_sigmask;         /* 0x94 */
+       unsigned int t_adstate;         /* 0x98 */
+       unsigned int t_sigstate;        /* 0x9C */
+};
+
+#define REGLOAD(a)     (be32_to_cpu(__raw_readl(&(a))))
+#define REGSTORE(a, v) (__raw_writel(cpu_to_be32(v), &(a)))
+
+#define CTRL_BUS_BIT 16
+
+#define CTRL_RESET (1<<31)
+#define CTRL_SI (1<<27)
+#define CTRL_PE (1<<26)
+#define CTRL_EI (1<<25)
+#define CTRL_ER (1<<24)
+#define CTRL_BUS (0xff<<CTRL_BUS_BIT)
+#define CTRL_HOSTINT 0xf
+
+#define STS_HOST_BIT   31
+#define STS_MST_BIT    30
+#define STS_TAR_BIT    29
+#define STS_DMA_BIT    28
+#define STS_DI_BIT     27
+#define STS_HI_BIT     26
+#define STS_IRQMODE_BIT        24
+#define STS_TRACE_BIT  23
+#define STS_CFGERRVALID_BIT 20
+#define STS_CFGERR_BIT 19
+#define STS_INTTYPE_BIT        12
+#define STS_INTSTS_BIT 8
+#define STS_FDEPTH_BIT 2
+#define STS_FNUM_BIT   0
+
+#define STS_HOST       (1<<STS_HOST_BIT)
+#define STS_MST                (1<<STS_MST_BIT)
+#define STS_TAR                (1<<STS_TAR_BIT)
+#define STS_DMA                (1<<STS_DMA_BIT)
+#define STS_DI         (1<<STS_DI_BIT)
+#define STS_HI         (1<<STS_HI_BIT)
+#define STS_IRQMODE    (0x3<<STS_IRQMODE_BIT)
+#define STS_TRACE      (1<<STS_TRACE_BIT)
+#define STS_CFGERRVALID        (1<<STS_CFGERRVALID_BIT)
+#define STS_CFGERR     (1<<STS_CFGERR_BIT)
+#define STS_INTTYPE    (0x3f<<STS_INTTYPE_BIT)
+#define STS_INTSTS     (0xf<<STS_INTSTS_BIT)
+#define STS_FDEPTH     (0x7<<STS_FDEPTH_BIT)
+#define STS_FNUM       (0x3<<STS_FNUM_BIT)
+
+#define STS_ISYSERR    (1<<17)
+#define STS_IDMA       (1<<16)
+#define STS_IDMAERR    (1<<15)
+#define STS_IMSTABRT   (1<<14)
+#define STS_ITGTABRT   (1<<13)
+#define STS_IPARERR    (1<<12)
+
+#define STS_ERR_IRQ (STS_ISYSERR | STS_IMSTABRT | STS_ITGTABRT | STS_IPARERR)
+
+struct grpci2_bd_chan {
+       unsigned int ctrl;      /* 0x00 DMA Control */
+       unsigned int nchan;     /* 0x04 Next DMA Channel Address */
+       unsigned int nbd;       /* 0x08 Next Data Descriptor in chan */
+       unsigned int res;       /* 0x0C Reserved */
+};
+
+#define BD_CHAN_EN             0x80000000
+#define BD_CHAN_TYPE           0x00300000
+#define BD_CHAN_BDCNT          0x0000ffff
+#define BD_CHAN_EN_BIT         31
+#define BD_CHAN_TYPE_BIT       20
+#define BD_CHAN_BDCNT_BIT      0
+
+struct grpci2_bd_data {
+       unsigned int ctrl;      /* 0x00 DMA Data Control */
+       unsigned int pci_adr;   /* 0x04 PCI Start Address */
+       unsigned int ahb_adr;   /* 0x08 AHB Start address */
+       unsigned int next;      /* 0x0C Next Data Descriptor in chan */
+};
+
+#define BD_DATA_EN             0x80000000
+#define BD_DATA_IE             0x40000000
+#define BD_DATA_DR             0x20000000
+#define BD_DATA_TYPE           0x00300000
+#define BD_DATA_ER             0x00080000
+#define BD_DATA_LEN            0x0000ffff
+#define BD_DATA_EN_BIT         31
+#define BD_DATA_IE_BIT         30
+#define BD_DATA_DR_BIT         29
+#define BD_DATA_TYPE_BIT       20
+#define BD_DATA_ER_BIT         19
+#define BD_DATA_LEN_BIT                0
+
+/* GRPCI2 Capability */
+struct grpci2_cap_first {
+       unsigned int ctrl;
+       unsigned int pci2ahb_map[6];
+       unsigned int ext2ahb_map;
+       unsigned int io_map;
+       unsigned int pcibar_size[6];
+};
+#define CAP9_CTRL_OFS 0
+#define CAP9_BAR_OFS 0x4
+#define CAP9_IOMAP_OFS 0x20
+#define CAP9_BARSIZE_OFS 0x24
+
+struct grpci2_priv {
+       struct leon_pci_info    info; /* must be on top of this structure */
+       struct grpci2_regs      *regs;
+       char                    irq;
+       char                    irq_mode; /* IRQ Mode from CAPSTS REG */
+       char                    bt_enabled;
+       char                    do_reset;
+       char                    irq_mask;
+       u32                     pciid; /* PCI ID of Host */
+       unsigned char           irq_map[4];
+
+       /* Virtual IRQ numbers */
+       unsigned int            virq_err;
+       unsigned int            virq_dma;
+
+       /* AHB PCI Windows */
+       unsigned long           pci_area;       /* MEMORY */
+       unsigned long           pci_area_end;
+       unsigned long           pci_io;         /* I/O */
+       unsigned long           pci_conf;       /* CONFIGURATION */
+       unsigned long           pci_conf_end;
+       unsigned long           pci_io_va;
+
+       struct grpci2_barcfg    tgtbars[6];
+};
+
+DEFINE_SPINLOCK(grpci2_dev_lock);
+struct grpci2_priv *grpci2priv;
+
+int grpci2_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       struct grpci2_priv *priv = dev->bus->sysdata;
+       int irq_group;
+
+       /* Use default IRQ decoding on PCI BUS0 according slot numbering */
+       irq_group = slot & 0x3;
+       pin = ((pin - 1) + irq_group) & 0x3;
+
+       return priv->irq_map[pin];
+}
+
+static int grpci2_cfg_r32(struct grpci2_priv *priv, unsigned int bus,
+                               unsigned int devfn, int where, u32 *val)
+{
+       unsigned int *pci_conf;
+       unsigned long flags;
+       u32 tmp;
+
+       if (where & 0x3)
+               return -EINVAL;
+
+       if (bus == 0 && PCI_SLOT(devfn) != 0)
+               devfn += (0x8 * 6);
+
+       /* Select bus */
+       spin_lock_irqsave(&grpci2_dev_lock, flags);
+       REGSTORE(priv->regs->ctrl, (REGLOAD(priv->regs->ctrl) & ~(0xff << 16)) |
+                                  (bus << 16));
+       spin_unlock_irqrestore(&grpci2_dev_lock, flags);
+
+       /* clear old status */
+       REGSTORE(priv->regs->sts_cap, (STS_CFGERR | STS_CFGERRVALID));
+
+       pci_conf = (unsigned int *) (priv->pci_conf |
+                                               (devfn << 8) | (where & 0xfc));
+       tmp = LEON3_BYPASS_LOAD_PA(pci_conf);
+
+       /* Wait until GRPCI2 signals that CFG access is done, it should be
+        * done instantaneously unless a DMA operation is ongoing...
+        */
+       while ((REGLOAD(priv->regs->sts_cap) & STS_CFGERRVALID) == 0)
+               ;
+
+       if (REGLOAD(priv->regs->sts_cap) & STS_CFGERR) {
+               *val = 0xffffffff;
+       } else {
+               /* Bus always little endian (unaffected by byte-swapping) */
+               *val = flip_dword(tmp);
+       }
+
+       return 0;
+}
+
+static int grpci2_cfg_r16(struct grpci2_priv *priv, unsigned int bus,
+                               unsigned int devfn, int where, u32 *val)
+{
+       u32 v;
+       int ret;
+
+       if (where & 0x1)
+               return -EINVAL;
+       ret = grpci2_cfg_r32(priv, bus, devfn, where & ~0x3, &v);
+       *val = 0xffff & (v >> (8 * (where & 0x3)));
+       return ret;
+}
+
+static int grpci2_cfg_r8(struct grpci2_priv *priv, unsigned int bus,
+                               unsigned int devfn, int where, u32 *val)
+{
+       u32 v;
+       int ret;
+
+       ret = grpci2_cfg_r32(priv, bus, devfn, where & ~0x3, &v);
+       *val = 0xff & (v >> (8 * (where & 3)));
+
+       return ret;
+}
+
+static int grpci2_cfg_w32(struct grpci2_priv *priv, unsigned int bus,
+                               unsigned int devfn, int where, u32 val)
+{
+       unsigned int *pci_conf;
+       unsigned long flags;
+
+       if (where & 0x3)
+               return -EINVAL;
+
+       if (bus == 0 && PCI_SLOT(devfn) != 0)
+               devfn += (0x8 * 6);
+
+       /* Select bus */
+       spin_lock_irqsave(&grpci2_dev_lock, flags);
+       REGSTORE(priv->regs->ctrl, (REGLOAD(priv->regs->ctrl) & ~(0xff << 16)) |
+                                  (bus << 16));
+       spin_unlock_irqrestore(&grpci2_dev_lock, flags);
+
+       /* clear old status */
+       REGSTORE(priv->regs->sts_cap, (STS_CFGERR | STS_CFGERRVALID));
+
+       pci_conf = (unsigned int *) (priv->pci_conf |
+                                               (devfn << 8) | (where & 0xfc));
+       LEON3_BYPASS_STORE_PA(pci_conf, flip_dword(val));
+
+       /* Wait until GRPCI2 signals that CFG access is done, it should be
+        * done instantaneously unless a DMA operation is ongoing...
+        */
+       while ((REGLOAD(priv->regs->sts_cap) & STS_CFGERRVALID) == 0)
+               ;
+
+       return 0;
+}
+
+static int grpci2_cfg_w16(struct grpci2_priv *priv, unsigned int bus,
+                               unsigned int devfn, int where, u32 val)
+{
+       int ret;
+       u32 v;
+
+       if (where & 0x1)
+               return -EINVAL;
+       ret = grpci2_cfg_r32(priv, bus, devfn, where&~3, &v);
+       if (ret)
+               return ret;
+       v = (v & ~(0xffff << (8 * (where & 0x3)))) |
+           ((0xffff & val) << (8 * (where & 0x3)));
+       return grpci2_cfg_w32(priv, bus, devfn, where & ~0x3, v);
+}
+
+static int grpci2_cfg_w8(struct grpci2_priv *priv, unsigned int bus,
+                               unsigned int devfn, int where, u32 val)
+{
+       int ret;
+       u32 v;
+
+       ret = grpci2_cfg_r32(priv, bus, devfn, where & ~0x3, &v);
+       if (ret != 0)
+               return ret;
+       v = (v & ~(0xff << (8 * (where & 0x3)))) |
+           ((0xff & val) << (8 * (where & 0x3)));
+       return grpci2_cfg_w32(priv, bus, devfn, where & ~0x3, v);
+}
+
+/* Read from Configuration Space. When entering here the PCI layer has taken
+ * the pci_lock spinlock and IRQ is off.
+ */
+static int grpci2_read_config(struct pci_bus *bus, unsigned int devfn,
+                             int where, int size, u32 *val)
+{
+       struct grpci2_priv *priv = grpci2priv;
+       unsigned int busno = bus->number;
+       int ret;
+
+       if (PCI_SLOT(devfn) > 15 || (PCI_SLOT(devfn) == 0 && busno == 0)) {
+               *val = ~0;
+               return 0;
+       }
+
+       switch (size) {
+       case 1:
+               ret = grpci2_cfg_r8(priv, busno, devfn, where, val);
+               break;
+       case 2:
+               ret = grpci2_cfg_r16(priv, busno, devfn, where, val);
+               break;
+       case 4:
+               ret = grpci2_cfg_r32(priv, busno, devfn, where, val);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+#ifdef GRPCI2_DEBUG_CFGACCESS
+       printk(KERN_INFO "grpci2_read_config: [%02x:%02x:%x] ofs=%d val=%x "
+               "size=%d\n", busno, PCI_SLOT(devfn), PCI_FUNC(devfn), where,
+               *val, size);
+#endif
+
+       return ret;
+}
+
+/* Write to Configuration Space. When entering here the PCI layer has taken
+ * the pci_lock spinlock and IRQ is off.
+ */
+static int grpci2_write_config(struct pci_bus *bus, unsigned int devfn,
+                              int where, int size, u32 val)
+{
+       struct grpci2_priv *priv = grpci2priv;
+       unsigned int busno = bus->number;
+
+       if (PCI_SLOT(devfn) > 15 || (PCI_SLOT(devfn) == 0 && busno == 0))
+               return 0;
+
+#ifdef GRPCI2_DEBUG_CFGACCESS
+       printk(KERN_INFO "grpci2_write_config: [%02x:%02x:%x] ofs=%d size=%d "
+               "val=%x\n", busno, PCI_SLOT(devfn), PCI_FUNC(devfn),
+               where, size, val);
+#endif
+
+       switch (size) {
+       default:
+               return -EINVAL;
+       case 1:
+               return grpci2_cfg_w8(priv, busno, devfn, where, val);
+       case 2:
+               return grpci2_cfg_w16(priv, busno, devfn, where, val);
+       case 4:
+               return grpci2_cfg_w32(priv, busno, devfn, where, val);
+       }
+}
+
+static struct pci_ops grpci2_ops = {
+       .read =         grpci2_read_config,
+       .write =        grpci2_write_config,
+};
+
+/* GENIRQ IRQ chip implementation for GRPCI2 irqmode=0..2. In configuration
+ * 3 where all PCI Interrupts has a separate IRQ on the system IRQ controller
+ * this is not needed and the standard IRQ controller can be used.
+ */
+
+static void grpci2_mask_irq(struct irq_data *data)
+{
+       unsigned long flags;
+       unsigned int irqidx;
+       struct grpci2_priv *priv = grpci2priv;
+
+       irqidx = (unsigned int)data->chip_data - 1;
+       if (irqidx > 3) /* only mask PCI interrupts here */
+               return;
+
+       spin_lock_irqsave(&grpci2_dev_lock, flags);
+       REGSTORE(priv->regs->ctrl, REGLOAD(priv->regs->ctrl) & ~(1 << irqidx));
+       spin_unlock_irqrestore(&grpci2_dev_lock, flags);
+}
+
+static void grpci2_unmask_irq(struct irq_data *data)
+{
+       unsigned long flags;
+       unsigned int irqidx;
+       struct grpci2_priv *priv = grpci2priv;
+
+       irqidx = (unsigned int)data->chip_data - 1;
+       if (irqidx > 3) /* only unmask PCI interrupts here */
+               return;
+
+       spin_lock_irqsave(&grpci2_dev_lock, flags);
+       REGSTORE(priv->regs->ctrl, REGLOAD(priv->regs->ctrl) | (1 << irqidx));
+       spin_unlock_irqrestore(&grpci2_dev_lock, flags);
+}
+
+static unsigned int grpci2_startup_irq(struct irq_data *data)
+{
+       grpci2_unmask_irq(data);
+       return 0;
+}
+
+static void grpci2_shutdown_irq(struct irq_data *data)
+{
+       grpci2_mask_irq(data);
+}
+
+static struct irq_chip grpci2_irq = {
+       .name           = "grpci2",
+       .irq_startup    = grpci2_startup_irq,
+       .irq_shutdown   = grpci2_shutdown_irq,
+       .irq_mask       = grpci2_mask_irq,
+       .irq_unmask     = grpci2_unmask_irq,
+};
+
+/* Handle one or multiple IRQs from the PCI core */
+static void grpci2_pci_flow_irq(unsigned int irq, struct irq_desc *desc)
+{
+       struct grpci2_priv *priv = grpci2priv;
+       int i, ack = 0;
+       unsigned int ctrl, sts_cap, pci_ints;
+
+       ctrl = REGLOAD(priv->regs->ctrl);
+       sts_cap = REGLOAD(priv->regs->sts_cap);
+
+       /* Error Interrupt? */
+       if (sts_cap & STS_ERR_IRQ) {
+               generic_handle_irq(priv->virq_err);
+               ack = 1;
+       }
+
+       /* PCI Interrupt? */
+       pci_ints = ((~sts_cap) >> STS_INTSTS_BIT) & ctrl & CTRL_HOSTINT;
+       if (pci_ints) {
+               /* Call respective PCI Interrupt handler */
+               for (i = 0; i < 4; i++) {
+                       if (pci_ints & (1 << i))
+                               generic_handle_irq(priv->irq_map[i]);
+               }
+               ack = 1;
+       }
+
+       /*
+        * Decode DMA Interrupt only when shared with Err and PCI INTX#, when
+        * the DMA is a unique IRQ the DMA interrupts doesn't end up here, they
+        * goes directly to DMA ISR.
+        */
+       if ((priv->irq_mode == 0) && (sts_cap & (STS_IDMA | STS_IDMAERR))) {
+               generic_handle_irq(priv->virq_dma);
+               ack = 1;
+       }
+
+       /*
+        * Call "first level" IRQ chip end-of-irq handler. It will ACK LEON IRQ
+        * Controller, this must be done after IRQ sources have been handled to
+        * avoid double IRQ generation
+        */
+       if (ack)
+               desc->irq_data.chip->irq_eoi(&desc->irq_data);
+}
+
+/* Create a virtual IRQ */
+static unsigned int grpci2_build_device_irq(unsigned int irq)
+{
+       unsigned int virq = 0, pil;
+
+       pil = 1 << 8;
+       virq = irq_alloc(irq, pil);
+       if (virq == 0)
+               goto out;
+
+       irq_set_chip_and_handler_name(virq, &grpci2_irq, handle_simple_irq,
+                                     "pcilvl");
+       irq_set_chip_data(virq, (void *)irq);
+
+out:
+       return virq;
+}
+
+void grpci2_hw_init(struct grpci2_priv *priv)
+{
+       u32 ahbadr, pciadr, bar_sz, capptr, io_map, data;
+       struct grpci2_regs *regs = priv->regs;
+       int i;
+       struct grpci2_barcfg *barcfg = priv->tgtbars;
+
+       /* Reset any earlier setup */
+       if (priv->do_reset) {
+               printk(KERN_INFO "GRPCI2: Resetting PCI bus\n");
+               REGSTORE(regs->ctrl, CTRL_RESET);
+               ssleep(1); /* Wait for boards to settle */
+       }
+       REGSTORE(regs->ctrl, 0);
+       REGSTORE(regs->sts_cap, ~0); /* Clear Status */
+       REGSTORE(regs->dma_ctrl, 0);
+       REGSTORE(regs->dma_bdbase, 0);
+
+       /* Translate I/O accesses to 0, I/O Space always @ PCI low 64Kbytes */
+       REGSTORE(regs->io_map, REGLOAD(regs->io_map) & 0x0000ffff);
+
+       /* set 1:1 mapping between AHB -> PCI memory space, for all Masters
+        * Each AHB master has it's own mapping registers. Max 16 AHB masters.
+        */
+       for (i = 0; i < 16; i++)
+               REGSTORE(regs->ahbmst_map[i], priv->pci_area);
+
+       /* Get the GRPCI2 Host PCI ID */
+       grpci2_cfg_r32(priv, 0, 0, PCI_VENDOR_ID, &priv->pciid);
+
+       /* Get address to first (always defined) capability structure */
+       grpci2_cfg_r8(priv, 0, 0, PCI_CAPABILITY_LIST, &capptr);
+
+       /* Enable/Disable Byte twisting */
+       grpci2_cfg_r32(priv, 0, 0, capptr+CAP9_IOMAP_OFS, &io_map);
+       io_map = (io_map & ~0x1) | (priv->bt_enabled ? 1 : 0);
+       grpci2_cfg_w32(priv, 0, 0, capptr+CAP9_IOMAP_OFS, io_map);
+
+       /* Setup the Host's PCI Target BARs for other peripherals to access,
+        * and do DMA to the host's memory. The target BARs can be sized and
+        * enabled individually.
+        *
+        * User may set custom target BARs, but default is:
+        * The first BARs is used to map kernel low (DMA is part of normal
+        * region on sparc which is SRMMU_MAXMEM big) main memory 1:1 to the
+        * PCI bus, the other BARs are disabled. We assume that the first BAR
+        * is always available.
+        */
+       for (i = 0; i < 6; i++) {
+               if (barcfg[i].pciadr != ~0 && barcfg[i].ahbadr != ~0) {
+                       /* Target BARs must have the proper alignment */
+                       ahbadr = barcfg[i].ahbadr;
+                       pciadr = barcfg[i].pciadr;
+                       bar_sz = ((pciadr - 1) & ~pciadr) + 1;
+               } else {
+                       if (i == 0) {
+                               /* Map main memory */
+                               bar_sz = 0xf0000008; /* 256MB prefetchable */
+                               ahbadr = 0xf0000000 & (u32)__pa(PAGE_ALIGN(
+                                       (unsigned long) &_end));
+                               pciadr = ahbadr;
+                       } else {
+                               bar_sz = 0;
+                               ahbadr = 0;
+                               pciadr = 0;
+                       }
+               }
+               grpci2_cfg_w32(priv, 0, 0, capptr+CAP9_BARSIZE_OFS+i*4, bar_sz);
+               grpci2_cfg_w32(priv, 0, 0, PCI_BASE_ADDRESS_0+i*4, pciadr);
+               grpci2_cfg_w32(priv, 0, 0, capptr+CAP9_BAR_OFS+i*4, ahbadr);
+               printk(KERN_INFO "        TGT BAR[%d]: 0x%08x (PCI)-> 0x%08x\n",
+                       i, pciadr, ahbadr);
+       }
+
+       /* set as bus master and enable pci memory responses */
+       grpci2_cfg_r32(priv, 0, 0, PCI_COMMAND, &data);
+       data |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+       grpci2_cfg_w32(priv, 0, 0, PCI_COMMAND, data);
+
+       /* Enable Error respone (CPU-TRAP) on illegal memory access. */
+       REGSTORE(regs->ctrl, CTRL_ER | CTRL_PE);
+}
+
+static irqreturn_t grpci2_jump_interrupt(int irq, void *arg)
+{
+       printk(KERN_ERR "GRPCI2: Jump IRQ happened\n");
+       return IRQ_NONE;
+}
+
+/* Handle GRPCI2 Error Interrupt */
+static irqreturn_t grpci2_err_interrupt(int irq, void *arg)
+{
+       struct grpci2_priv *priv = arg;
+       struct grpci2_regs *regs = priv->regs;
+       unsigned int status;
+
+       status = REGLOAD(regs->sts_cap);
+       if ((status & STS_ERR_IRQ) == 0)
+               return IRQ_NONE;
+
+       if (status & STS_IPARERR)
+               printk(KERN_ERR "GRPCI2: Parity Error\n");
+
+       if (status & STS_ITGTABRT)
+               printk(KERN_ERR "GRPCI2: Target Abort\n");
+
+       if (status & STS_IMSTABRT)
+               printk(KERN_ERR "GRPCI2: Master Abort\n");
+
+       if (status & STS_ISYSERR)
+               printk(KERN_ERR "GRPCI2: System Error\n");
+
+       /* Clear handled INT TYPE IRQs */
+       REGSTORE(regs->sts_cap, status & STS_ERR_IRQ);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit grpci2_of_probe(struct platform_device *ofdev)
+{
+       struct grpci2_regs *regs;
+       struct grpci2_priv *priv;
+       int err, i, len;
+       const int *tmp;
+       unsigned int capability;
+
+       if (grpci2priv) {
+               printk(KERN_ERR "GRPCI2: only one GRPCI2 core supported\n");
+               return -ENODEV;
+       }
+
+       if (ofdev->num_resources < 3) {
+               printk(KERN_ERR "GRPCI2: not enough APB/AHB resources\n");
+               return -EIO;
+       }
+
+       /* Find Device Address */
+       regs = of_ioremap(&ofdev->resource[0], 0,
+                         resource_size(&ofdev->resource[0]),
+                         "grlib-grpci2 regs");
+       if (regs == NULL) {
+               printk(KERN_ERR "GRPCI2: ioremap failed\n");
+               return -EIO;
+       }
+
+       /*
+        * Check that we're in Host Slot and that we can act as a Host Bridge
+        * and not only as target.
+        */
+       capability = REGLOAD(regs->sts_cap);
+       if ((capability & STS_HOST) || !(capability & STS_MST)) {
+               printk(KERN_INFO "GRPCI2: not in host system slot\n");
+               err = -EIO;
+               goto err1;
+       }
+
+       priv = grpci2priv = kzalloc(sizeof(struct grpci2_priv), GFP_KERNEL);
+       if (grpci2priv == NULL) {
+               err = -ENOMEM;
+               goto err1;
+       }
+       memset(grpci2priv, 0, sizeof(*grpci2priv));
+       priv->regs = regs;
+       priv->irq = ofdev->archdata.irqs[0]; /* BASE IRQ */
+       priv->irq_mode = (capability & STS_IRQMODE) >> STS_IRQMODE_BIT;
+
+       printk(KERN_INFO "GRPCI2: host found at %p, irq%d\n", regs, priv->irq);
+
+       /* Byte twisting should be made configurable from kernel command line */
+       priv->bt_enabled = 1;
+
+       /* Let user do custom Target BAR assignment */
+       tmp = of_get_property(ofdev->dev.of_node, "barcfg", &len);
+       if (tmp && (len == 2*4*6))
+               memcpy(priv->tgtbars, tmp, 2*4*6);
+       else
+               memset(priv->tgtbars, -1, 2*4*6);
+
+       /* Limit IRQ unmasking in irq_mode 2 and 3 */
+       tmp = of_get_property(ofdev->dev.of_node, "irq_mask", &len);
+       if (tmp && (len == 4))
+               priv->do_reset = *tmp;
+       else
+               priv->irq_mask = 0xf;
+
+       /* Optional PCI reset. Force PCI reset on startup */
+       tmp = of_get_property(ofdev->dev.of_node, "reset", &len);
+       if (tmp && (len == 4))
+               priv->do_reset = *tmp;
+       else
+               priv->do_reset = 0;
+
+       /* Find PCI Memory, I/O and Configuration Space Windows */
+       priv->pci_area = ofdev->resource[1].start;
+       priv->pci_area_end = ofdev->resource[1].end+1;
+       priv->pci_io = ofdev->resource[2].start;
+       priv->pci_conf = ofdev->resource[2].start + 0x10000;
+       priv->pci_conf_end = priv->pci_conf + 0x10000;
+       priv->pci_io_va = (unsigned long)ioremap(priv->pci_io, 0x10000);
+       if (!priv->pci_io_va) {
+               err = -EIO;
+               goto err2;
+       }
+
+       printk(KERN_INFO
+               "GRPCI2: MEMORY SPACE [0x%08lx - 0x%08lx]\n"
+               "        I/O    SPACE [0x%08lx - 0x%08lx]\n"
+               "        CONFIG SPACE [0x%08lx - 0x%08lx]\n",
+               priv->pci_area, priv->pci_area_end-1,
+               priv->pci_io, priv->pci_conf-1,
+               priv->pci_conf, priv->pci_conf_end-1);
+
+       /*
+        * I/O Space resources in I/O Window mapped into Virtual Adr Space
+        * We never use low 4KB because some devices seem have problems using
+        * address 0.
+        */
+       memset(&priv->info.io_space, 0, sizeof(struct resource));
+       priv->info.io_space.name = "GRPCI2 PCI I/O Space";
+       priv->info.io_space.start = priv->pci_io_va + 0x1000;
+       priv->info.io_space.end = priv->pci_io_va + 0x10000 - 1;
+       priv->info.io_space.flags = IORESOURCE_IO;
+
+       /*
+        * GRPCI2 has no prefetchable memory, map everything as
+        * non-prefetchable memory
+        */
+       memset(&priv->info.mem_space, 0, sizeof(struct resource));
+       priv->info.mem_space.name = "GRPCI2 PCI MEM Space";
+       priv->info.mem_space.start = priv->pci_area;
+       priv->info.mem_space.end = priv->pci_area_end - 1;
+       priv->info.mem_space.flags = IORESOURCE_MEM;
+
+       if (request_resource(&iomem_resource, &priv->info.mem_space) < 0)
+               goto err3;
+       if (request_resource(&ioport_resource, &priv->info.io_space) < 0)
+               goto err4;
+
+       grpci2_hw_init(priv);
+
+       /*
+        * Get PCI Interrupt to System IRQ mapping and setup IRQ handling
+        * Error IRQ always on PCI INTA.
+        */
+       if (priv->irq_mode < 2) {
+               /* All PCI interrupts are shared using the same system IRQ */
+               leon_update_virq_handling(priv->irq, grpci2_pci_flow_irq,
+                                        "pcilvl", 0);
+
+               priv->irq_map[0] = grpci2_build_device_irq(1);
+               priv->irq_map[1] = grpci2_build_device_irq(2);
+               priv->irq_map[2] = grpci2_build_device_irq(3);
+               priv->irq_map[3] = grpci2_build_device_irq(4);
+
+               priv->virq_err = grpci2_build_device_irq(5);
+               if (priv->irq_mode & 1)
+                       priv->virq_dma = ofdev->archdata.irqs[1];
+               else
+                       priv->virq_dma = grpci2_build_device_irq(6);
+
+               /* Enable IRQs on LEON IRQ controller */
+               err = request_irq(priv->irq, grpci2_jump_interrupt, 0,
+                                       "GRPCI2_JUMP", priv);
+               if (err)
+                       printk(KERN_ERR "GRPCI2: ERR IRQ request failed\n");
+       } else {
+               /* All PCI interrupts have an unique IRQ interrupt */
+               for (i = 0; i < 4; i++) {
+                       /* Make LEON IRQ layer handle level IRQ by acking */
+                       leon_update_virq_handling(ofdev->archdata.irqs[i],
+                                                handle_fasteoi_irq, "pcilvl",
+                                                1);
+                       priv->irq_map[i] = ofdev->archdata.irqs[i];
+               }
+               priv->virq_err = priv->irq_map[0];
+               if (priv->irq_mode & 1)
+                       priv->virq_dma = ofdev->archdata.irqs[4];
+               else
+                       priv->virq_dma = priv->irq_map[0];
+
+               /* Unmask all PCI interrupts, request_irq will not do that */
+               REGSTORE(regs->ctrl, REGLOAD(regs->ctrl)|(priv->irq_mask&0xf));
+       }
+
+       /* Setup IRQ handler for non-configuration space access errors */
+       err = request_irq(priv->virq_err, grpci2_err_interrupt, IRQF_SHARED,
+                               "GRPCI2_ERR", priv);
+       if (err) {
+               printk(KERN_DEBUG "GRPCI2: ERR VIRQ request failed: %d\n", err);
+               goto err5;
+       }
+
+       /*
+        * Enable Error Interrupts. PCI interrupts are unmasked once request_irq
+        * is called by the PCI Device drivers
+        */
+       REGSTORE(regs->ctrl, REGLOAD(regs->ctrl) | CTRL_EI | CTRL_SI);
+
+       /* Init common layer and scan buses */
+       priv->info.ops = &grpci2_ops;
+       priv->info.map_irq = grpci2_map_irq;
+       leon_pci_init(ofdev, &priv->info);
+
+       return 0;
+
+err5:
+       release_resource(&priv->info.io_space);
+err4:
+       release_resource(&priv->info.mem_space);
+err3:
+       err = -ENOMEM;
+       iounmap((void *)priv->pci_io_va);
+err2:
+       kfree(priv);
+err1:
+       of_iounmap(&ofdev->resource[0], regs,
+               resource_size(&ofdev->resource[0]));
+       return err;
+}
+
+static struct of_device_id grpci2_of_match[] = {
+       {
+        .name = "GAISLER_GRPCI2",
+        },
+       {
+        .name = "01_07c",
+        },
+       {},
+};
+
+static struct platform_driver grpci2_of_driver = {
+       .driver = {
+               .name = "grpci2",
+               .owner = THIS_MODULE,
+               .of_match_table = grpci2_of_match,
+       },
+       .probe = grpci2_of_probe,
+};
+
+static int __init grpci2_init(void)
+{
+       return platform_driver_register(&grpci2_of_driver);
+}
+
+subsys_initcall(grpci2_init);
index 8d348c474a2f3b7ffde344246c0e41856f3988fe..99ba5baa9497da77a773a2fc9da7600b2ee16816 100644 (file)
@@ -214,7 +214,7 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
                               me->name,
                               (int) (ELF_R_TYPE(rel[i].r_info) & 0xff));
                        return -ENOEXEC;
-               };
+               }
        }
        return 0;
 }
index 6e3874b64488056ba060e21a57b5796863cd66b3..a6895987fb70254b7db258c2eff6fd65262aba46 100644 (file)
@@ -281,7 +281,7 @@ static int sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
        case 4:
                *value = ret & 0xffffffff;
                break;
-       };
+       }
 
 
        return PCIBIOS_SUCCESSFUL;
@@ -456,7 +456,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
 
                default:
                        break;
-               };
+               }
        }
 
        if (!saw_io || !saw_mem) {
index 283fbc329a4397c9d8ff9b159611fe1bf62d4e8b..f030b02eddddd18f04db1c268735c37f040ca0e2 100644 (file)
@@ -264,7 +264,7 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
                default:
                        type_string = "ECC Error";
                        break;
-               };
+               }
                printk("%s: IOMMU Error, type[%s]\n",
                       pbm->name, type_string);
 
@@ -319,7 +319,7 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
                        default:
                                type_string = "ECC Error";
                                break;
-                       };
+                       }
                        printk("%s: IOMMU TAG(%d)[error(%s) ctx(%x) wr(%d) str(%d) "
                               "sz(%dK) vpg(%08lx)]\n",
                               pbm->name, i, type_string,
@@ -1328,7 +1328,7 @@ static int __devinit schizo_pbm_init(struct pci_pbm_info *pbm,
        default:
                chipset_name = "SCHIZO";
                break;
-       };
+       }
 
        /* For SCHIZO, three OBP regs:
         * 1) PBM controller regs
index 570b98f6e89794b9ae21ab5bf2fafc9209c03f34..40e4936bd47995486039d256463cc514f23d8350 100644 (file)
@@ -694,7 +694,7 @@ static unsigned int sbus_of_build_irq(struct device_node *dp,
                case 3:
                        iclr = reg_base + SYSIO_ICLR_SLOT3;
                        break;
-               };
+               }
 
                iclr += ((unsigned long)sbus_level - 1UL) * 8UL;
        }
index fe2af66bb1988ee3eff896223b5f131e06ca06e6..8db48e808ed42a969e45dec6c92d1c92b05930df 100644 (file)
@@ -228,7 +228,7 @@ void psycho_check_iommu_error(struct pci_pbm_info *pbm,
                default:
                        type_str = "ECC Error";
                        break;
-               };
+               }
                printk(KERN_ERR "%s: IOMMU Error, type[%s]\n",
                       pbm->name, type_str);
 
index 2ca32d13abcfdbbfbe0a81de61e706d292248b0f..a161b9c77f055617553fb32a2e25fdac279922f0 100644 (file)
@@ -97,7 +97,7 @@ void sbus_set_sbus64(struct device *dev, int bursts)
 
        default:
                return;
-       };
+       }
 
        val = upa_readq(cfg_reg);
        if (val & (1UL << 14UL)) {
@@ -244,7 +244,7 @@ static unsigned int sbus_build_irq(struct platform_device *op, unsigned int ino)
                case 3:
                        iclr = reg_base + SYSIO_ICLR_SLOT3;
                        break;
-               };
+               }
 
                iclr += ((unsigned long)sbus_level - 1UL) * 8UL;
        }
index 3609bdee9ed294d1d6b88cea15fbc92a7ac2297a..d26e1f6c717aa1f5fd3dffe2689594e1bce3b29a 100644 (file)
@@ -82,7 +82,7 @@ static void prom_sync_me(void)
                             "nop\n\t" : : "r" (&trapbase));
 
        prom_printf("PROM SYNC COMMAND...\n");
-       show_free_areas();
+       show_free_areas(0);
        if(current->pid != 0) {
                local_irq_enable();
                sys_sync();
@@ -267,7 +267,7 @@ void __init setup_arch(char **cmdline_p)
        default:
                printk("UNKNOWN!\n");
                break;
-       };
+       }
 
 #ifdef CONFIG_DUMMY_CONSOLE
        conswitchp = &dummy_con;
index f3b6850cc8db4e4e59e5b975fcd6184af2c2d70c..c4dd0999da86b633568f278cada4420593b55940 100644 (file)
@@ -209,7 +209,7 @@ void __init per_cpu_patch(void)
                default:
                        prom_printf("Unknown cpu type, halting.\n");
                        prom_halt();
-               };
+               }
 
                *(unsigned int *) (addr +  0) = insns[0];
                wmb();
index d5b3958be0b40ac25fdcb7d209d10d950c7df80e..21b125341bf79a5dbe8282d22751c4f805ab5d11 100644 (file)
@@ -114,7 +114,7 @@ void __init smp_cpus_done(unsigned int max_cpus)
                printk("UNKNOWN!\n");
                BUG();
                break;
-       };
+       }
 }
 
 void cpu_panic(void)
@@ -374,7 +374,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
                printk("UNKNOWN!\n");
                BUG();
                break;
-       };
+       }
 }
 
 /* Set this up early so that things like the scheduler can init
@@ -447,7 +447,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
                printk("UNKNOWN!\n");
                BUG();
                break;
-       };
+       }
 
        if (!ret) {
                cpumask_set_cpu(cpu, &smp_commenced_mask);
index a9ea60eb2c10f21e01cf007143e47942b6a768ad..1d13c5bda0b15c3042ce69e406311a449e93e4df 100644 (file)
@@ -103,10 +103,9 @@ static void sun4d_sbus_handler_irq(int sbusl)
 
        sbil = (sbusl << 2);
        /* Loop for each pending SBI */
-       for (sbino = 0; bus_mask; sbino++) {
+       for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1) {
                unsigned int idx, mask;
 
-               bus_mask >>= 1;
                if (!(bus_mask & 1))
                        continue;
                /* XXX This seems to ACK the irq twice.  acquire_sbi()
@@ -118,19 +117,16 @@ static void sun4d_sbus_handler_irq(int sbusl)
                mask &= (0xf << sbil);
 
                /* Loop for each pending SBI slot */
-               idx = 0;
                slot = (1 << sbil);
-               while (mask != 0) {
+               for (idx = 0; mask != 0; idx++, slot <<= 1) {
                        unsigned int pil;
                        struct irq_bucket *p;
 
-                       idx++;
-                       slot <<= 1;
                        if (!(mask & slot))
                                continue;
 
                        mask &= ~slot;
-                       pil = sun4d_encode_irq(sbino, sbil, idx);
+                       pil = sun4d_encode_irq(sbino, sbusl, idx);
 
                        p = irq_map[pil];
                        while (p) {
@@ -218,10 +214,10 @@ static void sun4d_unmask_irq(struct irq_data *data)
 
 #ifdef CONFIG_SMP
        spin_lock_irqsave(&sun4d_imsk_lock, flags);
-       cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | ~(1 << real_irq));
+       cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) & ~(1 << real_irq));
        spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
 #else
-       cc_set_imsk(cc_get_imsk() | ~(1 << real_irq));
+       cc_set_imsk(cc_get_imsk() & ~(1 << real_irq));
 #endif
 }
 
@@ -299,26 +295,68 @@ static void __init sun4d_load_profile_irqs(void)
        }
 }
 
+unsigned int _sun4d_build_device_irq(unsigned int real_irq,
+                                     unsigned int pil,
+                                     unsigned int board)
+{
+       struct sun4d_handler_data *handler_data;
+       unsigned int irq;
+
+       irq = irq_alloc(real_irq, pil);
+       if (irq == 0) {
+               prom_printf("IRQ: allocate for %d %d %d failed\n",
+                       real_irq, pil, board);
+               goto err_out;
+       }
+
+       handler_data = irq_get_handler_data(irq);
+       if (unlikely(handler_data))
+               goto err_out;
+
+       handler_data = kzalloc(sizeof(struct sun4d_handler_data), GFP_ATOMIC);
+       if (unlikely(!handler_data)) {
+               prom_printf("IRQ: kzalloc(sun4d_handler_data) failed.\n");
+               prom_halt();
+       }
+       handler_data->cpuid    = board_to_cpu[board];
+       handler_data->real_irq = real_irq;
+       irq_set_chip_and_handler_name(irq, &sun4d_irq,
+                                     handle_level_irq, "level");
+       irq_set_handler_data(irq, handler_data);
+
+err_out:
+       return irq;
+}
+
+
+
 unsigned int sun4d_build_device_irq(struct platform_device *op,
                                     unsigned int real_irq)
 {
        struct device_node *dp = op->dev.of_node;
-       struct device_node *io_unit, *sbi = dp->parent;
+       struct device_node *board_parent, *bus = dp->parent;
+       char *bus_connection;
        const struct linux_prom_registers *regs;
-       struct sun4d_handler_data *handler_data;
        unsigned int pil;
        unsigned int irq;
        int board, slot;
        int sbusl;
 
-       irq = 0;
-       while (sbi) {
-               if (!strcmp(sbi->name, "sbi"))
+       irq = real_irq;
+       while (bus) {
+               if (!strcmp(bus->name, "sbi")) {
+                       bus_connection = "io-unit";
+                       break;
+               }
+
+               if (!strcmp(bus->name, "bootbus")) {
+                       bus_connection = "cpu-unit";
                        break;
+               }
 
-               sbi = sbi->parent;
+               bus = bus->parent;
        }
-       if (!sbi)
+       if (!bus)
                goto err_out;
 
        regs = of_get_property(dp, "reg", NULL);
@@ -328,17 +366,19 @@ unsigned int sun4d_build_device_irq(struct platform_device *op,
        slot = regs->which_io;
 
        /*
-        *  If SBI's parent is not io-unit or the io-unit lacks
-        * a "board#" property, something is very wrong.
+        * If Bus nodes parent is not io-unit/cpu-unit or the io-unit/cpu-unit
+        * lacks a "board#" property, something is very wrong.
         */
-       if (!sbi->parent || strcmp(sbi->parent->name, "io-unit")) {
-               printk("%s: Error, parent is not io-unit.\n", sbi->full_name);
+       if (!bus->parent || strcmp(bus->parent->name, bus_connection)) {
+               printk(KERN_ERR "%s: Error, parent is not %s.\n",
+                       bus->full_name, bus_connection);
                goto err_out;
        }
-       io_unit = sbi->parent;
-       board = of_getintprop_default(io_unit, "board#", -1);
+       board_parent = bus->parent;
+       board = of_getintprop_default(board_parent, "board#", -1);
        if (board == -1) {
-               printk("%s: Error, lacks board# property.\n", io_unit->full_name);
+               printk(KERN_ERR "%s: Error, lacks board# property.\n",
+                       board_parent->full_name);
                goto err_out;
        }
 
@@ -348,29 +388,17 @@ unsigned int sun4d_build_device_irq(struct platform_device *op,
        else
                pil = real_irq;
 
-       irq = irq_alloc(real_irq, pil);
-       if (irq == 0)
-               goto err_out;
-
-       handler_data = irq_get_handler_data(irq);
-       if (unlikely(handler_data))
-               goto err_out;
-
-       handler_data = kzalloc(sizeof(struct sun4d_handler_data), GFP_ATOMIC);
-       if (unlikely(!handler_data)) {
-               prom_printf("IRQ: kzalloc(sun4d_handler_data) failed.\n");
-               prom_halt();
-       }
-       handler_data->cpuid    = board_to_cpu[board];
-       handler_data->real_irq = real_irq;
-       irq_set_chip_and_handler_name(irq, &sun4d_irq,
-                                     handle_level_irq, "level");
-       irq_set_handler_data(irq, handler_data);
-
+       irq = _sun4d_build_device_irq(real_irq, pil, board);
 err_out:
-       return real_irq;
+       return irq;
 }
 
+unsigned int sun4d_build_timer_irq(unsigned int board, unsigned int real_irq)
+{
+       return _sun4d_build_device_irq(real_irq, real_irq, board);
+}
+
+
 static void __init sun4d_fixup_trap_table(void)
 {
 #ifdef CONFIG_SMP
@@ -402,6 +430,7 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn)
        unsigned int irq;
        const u32 *reg;
        int err;
+       int board;
 
        dp = of_find_node_by_name(NULL, "cpu-unit");
        if (!dp) {
@@ -414,12 +443,19 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn)
         * bootbus.
         */
        reg = of_get_property(dp, "reg", NULL);
-       of_node_put(dp);
        if (!reg) {
                prom_printf("sun4d_init_timers: No reg property\n");
                prom_halt();
        }
 
+       board = of_getintprop_default(dp, "board#", -1);
+       if (board == -1) {
+               prom_printf("sun4d_init_timers: No board# property on cpu-unit\n");
+               prom_halt();
+       }
+
+       of_node_put(dp);
+
        res.start = reg[1];
        res.end = reg[2] - 1;
        res.flags = reg[0] & 0xff;
@@ -434,7 +470,7 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn)
 
        master_l10_counter = &sun4d_timers->l10_cur_count;
 
-       irq = sun4d_build_device_irq(NULL, SUN4D_TIMER_IRQ);
+       irq = sun4d_build_timer_irq(board, SUN4D_TIMER_IRQ);
        err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL);
        if (err) {
                prom_printf("sun4d_init_timers: request_irq() failed with %d\n",
index 6db18c6927fbee68a20125e1eb31e486798eeac0..170cd8e8eb2a25d178d0b949380ebf56c640ed86 100644 (file)
@@ -109,7 +109,7 @@ asmlinkage long compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compa
 
        default:
                return -ENOSYS;
-       };
+       }
 
        return -ENOSYS;
 }
index 96082d30def094021b75754981e05c511d098935..908b47a5ee2431cca7294ae1b81b961586838964 100644 (file)
@@ -460,7 +460,7 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second
                default:
                        err = -ENOSYS;
                        goto out;
-               };
+               }
        }
        if (call <= MSGCTL) {
                switch (call) {
@@ -481,7 +481,7 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second
                default:
                        err = -ENOSYS;
                        goto out;
-               };
+               }
        }
        if (call <= SHMCTL) {
                switch (call) {
@@ -507,7 +507,7 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second
                default:
                        err = -ENOSYS;
                        goto out;
-               };
+               }
        } else {
                err = -ENOSYS;
        }
index 332c83ff7701799f30538cb891c016337bd1c749..6e492d59f6b1d7fa2d9f7974527ad56b5d7cc967 100644 (file)
@@ -84,4 +84,4 @@ sys_call_table:
 /*320*/        .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv
 /*325*/        .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init
 /*330*/        .long sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime
-/*335*/        .long sys_syncfs, sys_sendmmsg
+/*335*/        .long sys_syncfs, sys_sendmmsg, sys_setns
index 43887ca0be0e263562e33f03d19fd202a8b2bf13..f566518483b5bcda9998d635adabc18a18354373 100644 (file)
@@ -85,7 +85,7 @@ sys_call_table32:
 /*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv
        .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init
 /*330*/        .word sys32_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime
-       .word sys_syncfs, compat_sys_sendmmsg
+       .word sys_syncfs, compat_sys_sendmmsg, sys_setns
 
 #endif /* CONFIG_COMPAT */
 
@@ -162,4 +162,4 @@ sys_call_table:
 /*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv
        .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init
 /*330*/        .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime
-       .word sys_syncfs, sys_sendmmsg
+       .word sys_syncfs, sys_sendmmsg, sys_setns
index 2b8d54b2d850b18a3eb8b4756bbcda3eb3a8dbc3..1db6b18964d22cef79a22330fec92e22b3df7c98 100644 (file)
@@ -708,7 +708,7 @@ static void sparc64_timer_setup(enum clock_event_mode mode,
        case CLOCK_EVT_MODE_UNUSED:
                WARN_ON(1);
                break;
-       };
+       }
 }
 
 static struct clock_event_device sparc64_clockevent = {
index 1ed547bd850f8abd937529b0752c60ddcd8027ac..0cbdaa41cd1eb8fa19f4597b834da3c9a489b4ee 100644 (file)
@@ -1804,7 +1804,7 @@ static const char *sun4v_err_type_to_str(u32 type)
                return "warning resumable";
        default:
                return "unknown";
-       };
+       }
 }
 
 static void sun4v_log_error(struct pt_regs *regs, struct sun4v_error_entry *ent, int cpu, const char *pfx, atomic_t *ocnt)
index c752c4c479bd8457da289b3da9797980d8dec7da..b2b019ea8caab36b346cd6a0ed766bfe075eb264 100644 (file)
@@ -211,7 +211,7 @@ static inline int do_int_store(int reg_num, int size, unsigned long *dst_addr,
                default:
                        BUG();
                        break;
-               };
+               }
        }
        return __do_int_store(dst_addr, size, src_val, asi);
 }
@@ -328,7 +328,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
                case ASI_SNFL:
                        asi &= ~0x08;
                        break;
-               };
+               }
                switch (dir) {
                case load:
                        reg_addr = fetch_reg_addr(((insn>>25)&0x1f), regs);
@@ -351,7 +351,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
                                default:
                                        BUG();
                                        break;
-                               };
+                               }
                                *reg_addr = val_in;
                        }
                        break;
index 531d54fc9829271efb36c572a9b32129fddded59..489fc15f3194b4e74f21541cf72523cf7ee3d85e 100644 (file)
@@ -176,7 +176,7 @@ static unsigned long index_to_estar_mode(unsigned int index)
 
        default:
                BUG();
-       };
+       }
 }
 
 static unsigned long index_to_divisor(unsigned int index)
@@ -199,7 +199,7 @@ static unsigned long index_to_divisor(unsigned int index)
 
        default:
                BUG();
-       };
+       }
 }
 
 static unsigned long estar_to_divisor(unsigned long estar)
@@ -224,7 +224,7 @@ static unsigned long estar_to_divisor(unsigned long estar)
                break;
        default:
                BUG();
-       };
+       }
 
        return ret;
 }
index 9a8ceb7008330a9fb695c1ddb2d2377cb15bb68f..eb1624b931d903fa4ea8955a270c111d2ba7b3d4 100644 (file)
@@ -71,7 +71,7 @@ static unsigned long get_current_freq(unsigned int cpu, unsigned long safari_cfg
                break;
        default:
                BUG();
-       };
+       }
 
        return ret;
 }
@@ -125,7 +125,7 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index)
 
        default:
                BUG();
-       };
+       }
 
        reg = read_safari_cfg();
 
index aa6ac70d4fd501099aa8082fd3da0f877e435291..29348ea139c33a7b1221bd0ce484a99ca3255f9d 100644 (file)
@@ -363,7 +363,7 @@ static int process_ver(struct vio_driver_state *vio, struct vio_ver_info *pkt)
 
        default:
                return handshake_failure(vio);
-       };
+       }
 }
 
 static int process_attr(struct vio_driver_state *vio, void *pkt)
index 9dfd2ebcb157143bb69fe988dd1ced391ab8e874..36357717d691019ff4772c7a4aa2993c68f13c35 100644 (file)
@@ -334,7 +334,7 @@ static void edge(struct pt_regs *regs, unsigned int insn, unsigned int opf)
                left = edge32_tab_l[(rs1 >> 2) & 0x1].left;
                right = edge32_tab_l[(rs2 >> 2) & 0x1].right;
                break;
-       };
+       }
 
        if ((rs1 & ~0x7UL) == (rs2 & ~0x7UL))
                rd_val = right & left;
@@ -360,7 +360,7 @@ static void edge(struct pt_regs *regs, unsigned int insn, unsigned int opf)
                tstate = regs->tstate & ~(TSTATE_XCC | TSTATE_ICC);
                regs->tstate = tstate | (ccr << 32UL);
        }
-       };
+       }
 }
 
 static void array(struct pt_regs *regs, unsigned int insn, unsigned int opf)
@@ -392,7 +392,7 @@ static void array(struct pt_regs *regs, unsigned int insn, unsigned int opf)
 
        case ARRAY32_OPF:
                rd_val <<= 2;
-       };
+       }
 
        store_reg(regs, rd_val, RD(insn));
 }
@@ -577,7 +577,7 @@ static void pformat(struct pt_regs *regs, unsigned int insn, unsigned int opf)
                *fpd_regaddr(f, RD(insn)) = rd_val;
                break;
        }
-       };
+       }
 }
 
 static void pmul(struct pt_regs *regs, unsigned int insn, unsigned int opf)
@@ -693,7 +693,7 @@ static void pmul(struct pt_regs *regs, unsigned int insn, unsigned int opf)
                *fpd_regaddr(f, RD(insn)) = rd_val;
                break;
        }
-       };
+       }
 }
 
 static void pcmp(struct pt_regs *regs, unsigned int insn, unsigned int opf)
@@ -786,7 +786,7 @@ static void pcmp(struct pt_regs *regs, unsigned int insn, unsigned int opf)
                                rd_val |= 1 << i;
                }
                break;
-       };
+       }
 
        maybe_flush_windows(0, 0, RD(insn), 0);
        store_reg(regs, rd_val, RD(insn));
@@ -885,7 +885,7 @@ int vis_emul(struct pt_regs *regs, unsigned int insn)
        case BSHUFFLE_OPF:
                bshuffle(regs, insn);
                break;
-       };
+       }
 
        regs->tpc = regs->tnpc;
        regs->tnpc += 4;
index 92b557afe535a59e95d8ab185d5d51c254d4d081..c0220759003e13d302a52ebd1ec5e75dd641c531 100644 (file)
@@ -108,7 +108,7 @@ SECTIONS
                __sun4v_2insn_patch_end = .;
        }
 
-       PERCPU(SMP_CACHE_BYTES, PAGE_SIZE)
+       PERCPU_SECTION(SMP_CACHE_BYTES)
 
        . = ALIGN(PAGE_SIZE);
        __init_end = .;
index b10ac4d62378a3705e52a010feb5e326f41b2d2f..7543ddbdadb271b18e79ccbaf126ed3ba3650991 100644 (file)
@@ -135,7 +135,7 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
 
        default:
                break;
-       };
+       }
 
        memset(&regs, 0, sizeof (regs));
        regs.pc = pc;
index 4c31e2b6e71b8bd49451ab2d6f4381e82bfbd9ae..7b00de61c5f1f73cf2e8c18c3cf07dfc1e190c50 100644 (file)
@@ -37,8 +37,6 @@
 #include <asm/prom.h>
 #include <asm/leon.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 unsigned long *sparc_valid_addr_bitmap;
 EXPORT_SYMBOL(sparc_valid_addr_bitmap);
 
@@ -78,7 +76,7 @@ void __init kmap_init(void)
 void show_mem(unsigned int filter)
 {
        printk("Mem-info:\n");
-       show_free_areas();
+       show_free_areas(filter);
        printk("Free swap:       %6ldkB\n",
               nr_swap_pages << (PAGE_SHIFT-10));
        printk("%ld pages of RAM\n", totalram_pages);
@@ -342,7 +340,7 @@ void __init paging_init(void)
                prom_printf("paging_init: sparc_cpu_model = %d\n", sparc_cpu_model);
                prom_printf("paging_init: Halting...\n");
                prom_halt();
-       };
+       }
 
        /* Initialize the protection map with non-constant, MMU dependent values. */
        protection_map[0] = PAGE_NONE;
index e10cd03fab801648ef2e5da6361a0a23867560aa..3fd8e18bed80a4ea06b960572b664bfed1d23a23 100644 (file)
@@ -1625,7 +1625,7 @@ static void __init sun4v_ktsb_init(void)
                ktsb_descr[0].pgsz_idx = HV_PGSZ_IDX_4MB;
                ktsb_descr[0].pgsz_mask = HV_PGSZ_MASK_4MB;
                break;
-       };
+       }
 
        ktsb_descr[0].assoc = 1;
        ktsb_descr[0].num_ttes = KERNEL_TSB_NENTRIES;
@@ -2266,7 +2266,7 @@ unsigned long pte_sz_bits(unsigned long sz)
                        return _PAGE_SZ512K_4V;
                case 4 * 1024 * 1024:
                        return _PAGE_SZ4MB_4V;
-               };
+               }
        } else {
                switch (sz) {
                case 8 * 1024:
@@ -2278,7 +2278,7 @@ unsigned long pte_sz_bits(unsigned long sz)
                        return _PAGE_SZ512K_4U;
                case 4 * 1024 * 1024:
                        return _PAGE_SZ4MB_4U;
-               };
+               }
        }
 }
 
index fe09fd8be6956e5f00fe0fddc5c9bbf6a11882c5..cbef74e793b8df9c9f3b7dc474f7a64feb082b3d 100644 (file)
@@ -1665,7 +1665,7 @@ static void __init init_swift(void)
        default:
                srmmu_modtype = Swift_ok;
                break;
-       };
+       }
 
        BTFIXUPSET_CALL(flush_cache_all, swift_flush_cache_all, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(flush_cache_mm, swift_flush_cache_mm, BTFIXUPCALL_NORM);
@@ -2069,7 +2069,7 @@ static void __init get_srmmu_type(void)
                        /* Some other Cypress revision, assume a 605. */
                        init_cypress_605(mod_rev);
                        break;
-               };
+               }
                return;
        }
        
index a2350b5e68aa66c237999dca7790a7e7e0282c48..1cf4f198709a2d798679b39f3e64629d4f24ac9a 100644 (file)
@@ -318,7 +318,7 @@ void __init sun4c_probe_vac(void)
                prom_printf("probe_vac: Didn't expect vac-linesize of %d, halting\n",
                            sun4c_vacinfo.linesize);
                prom_halt();
-       };
+       }
 
        sun4c_flush_all();
        sun4c_enable_vac();
@@ -364,7 +364,7 @@ static void __init patch_kernel_fault_handler(void)
                        prom_printf("Unhandled number of segmaps: %d\n",
                                    num_segmaps);
                        prom_halt();
-       };
+       }
        switch (num_contexts) {
                case 8:
                        /* Default, nothing to do. */
@@ -377,7 +377,7 @@ static void __init patch_kernel_fault_handler(void)
                        prom_printf("Unhandled number of contexts: %d\n",
                                    num_contexts);
                        prom_halt();
-       };
+       }
 
        if (sun4c_vacinfo.do_hwflushes != 0) {
                PATCH_INSN(vac_hwflush_patch1_on, vac_hwflush_patch1);
@@ -394,7 +394,7 @@ static void __init patch_kernel_fault_handler(void)
                        prom_printf("Impossible VAC linesize %d, halting...\n",
                                    sun4c_vacinfo.linesize);
                        prom_halt();
-               };
+               }
        }
 }
 
index d8f21e24a82f8c98f0a708bd1a493058a51b49bb..b1f279cd00bfd96afb039e917a0692ce440beaeb 100644 (file)
 
 /* Heavily inspired by the ppc64 code.  */
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+static DEFINE_PER_CPU(struct tlb_batch, tlb_batch);
 
 void flush_tlb_pending(void)
 {
-       struct mmu_gather *mp = &get_cpu_var(mmu_gathers);
+       struct tlb_batch *tb = &get_cpu_var(tlb_batch);
 
-       if (mp->tlb_nr) {
-               flush_tsb_user(mp);
+       if (tb->tlb_nr) {
+               flush_tsb_user(tb);
 
-               if (CTX_VALID(mp->mm->context)) {
+               if (CTX_VALID(tb->mm->context)) {
 #ifdef CONFIG_SMP
-                       smp_flush_tlb_pending(mp->mm, mp->tlb_nr,
-                                             &mp->vaddrs[0]);
+                       smp_flush_tlb_pending(tb->mm, tb->tlb_nr,
+                                             &tb->vaddrs[0]);
 #else
-                       __flush_tlb_pending(CTX_HWBITS(mp->mm->context),
-                                           mp->tlb_nr, &mp->vaddrs[0]);
+                       __flush_tlb_pending(CTX_HWBITS(tb->mm->context),
+                                           tb->tlb_nr, &tb->vaddrs[0]);
 #endif
                }
-               mp->tlb_nr = 0;
+               tb->tlb_nr = 0;
        }
 
-       put_cpu_var(mmu_gathers);
+       put_cpu_var(tlb_batch);
 }
 
-void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t orig)
+void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr,
+                  pte_t *ptep, pte_t orig, int fullmm)
 {
-       struct mmu_gather *mp = &__get_cpu_var(mmu_gathers);
+       struct tlb_batch *tb = &get_cpu_var(tlb_batch);
        unsigned long nr;
 
        vaddr &= PAGE_MASK;
@@ -77,21 +78,25 @@ void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t
 
 no_cache_flush:
 
-       if (mp->fullmm)
+       if (fullmm) {
+               put_cpu_var(tlb_batch);
                return;
+       }
 
-       nr = mp->tlb_nr;
+       nr = tb->tlb_nr;
 
-       if (unlikely(nr != 0 && mm != mp->mm)) {
+       if (unlikely(nr != 0 && mm != tb->mm)) {
                flush_tlb_pending();
                nr = 0;
        }
 
        if (nr == 0)
-               mp->mm = mm;
+               tb->mm = mm;
 
-       mp->vaddrs[nr] = vaddr;
-       mp->tlb_nr = ++nr;
+       tb->vaddrs[nr] = vaddr;
+       tb->tlb_nr = ++nr;
        if (nr >= TLB_BATCH_NR)
                flush_tlb_pending();
+
+       put_cpu_var(tlb_batch);
 }
index 101d7c82870be8a704a2ab84f07d97a2d890f37a..a5f51b22fcbe9eb4654a5d33d38054c886d75761 100644 (file)
@@ -47,12 +47,13 @@ void flush_tsb_kernel_range(unsigned long start, unsigned long end)
        }
 }
 
-static void __flush_tsb_one(struct mmu_gather *mp, unsigned long hash_shift, unsigned long tsb, unsigned long nentries)
+static void __flush_tsb_one(struct tlb_batch *tb, unsigned long hash_shift,
+                           unsigned long tsb, unsigned long nentries)
 {
        unsigned long i;
 
-       for (i = 0; i < mp->tlb_nr; i++) {
-               unsigned long v = mp->vaddrs[i];
+       for (i = 0; i < tb->tlb_nr; i++) {
+               unsigned long v = tb->vaddrs[i];
                unsigned long tag, ent, hash;
 
                v &= ~0x1UL;
@@ -65,9 +66,9 @@ static void __flush_tsb_one(struct mmu_gather *mp, unsigned long hash_shift, uns
        }
 }
 
-void flush_tsb_user(struct mmu_gather *mp)
+void flush_tsb_user(struct tlb_batch *tb)
 {
-       struct mm_struct *mm = mp->mm;
+       struct mm_struct *mm = tb->mm;
        unsigned long nentries, base, flags;
 
        spin_lock_irqsave(&mm->context.lock, flags);
@@ -76,7 +77,7 @@ void flush_tsb_user(struct mmu_gather *mp)
        nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries;
        if (tlb_type == cheetah_plus || tlb_type == hypervisor)
                base = __pa(base);
-       __flush_tsb_one(mp, PAGE_SHIFT, base, nentries);
+       __flush_tsb_one(tb, PAGE_SHIFT, base, nentries);
 
 #ifdef CONFIG_HUGETLB_PAGE
        if (mm->context.tsb_block[MM_TSB_HUGE].tsb) {
@@ -84,7 +85,7 @@ void flush_tsb_user(struct mmu_gather *mp)
                nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries;
                if (tlb_type == cheetah_plus || tlb_type == hypervisor)
                        base = __pa(base);
-               __flush_tsb_one(mp, HPAGE_SHIFT, base, nentries);
+               __flush_tsb_one(tb, HPAGE_SHIFT, base, nentries);
        }
 #endif
        spin_unlock_irqrestore(&mm->context.lock, flags);
@@ -179,7 +180,7 @@ static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_idx, unsign
                printk(KERN_ERR "TSB[%s:%d]: Impossible TSB size %lu, killing process.\n",
                       current->comm, current->pid, tsb_bytes);
                do_exit(SIGSEGV);
-       };
+       }
        tte |= pte_sz_bits(page_sz);
 
        if (tlb_type == cheetah_plus || tlb_type == hypervisor) {
@@ -214,7 +215,7 @@ static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_idx, unsign
 #endif
                default:
                        BUG();
-               };
+               }
                hp->assoc = 1;
                hp->num_ttes = tsb_bytes / 16;
                hp->ctx_idx = 0;
@@ -229,7 +230,7 @@ static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_idx, unsign
 #endif
                default:
                        BUG();
-               };
+               }
                hp->tsb_base = tsb_paddr;
                hp->resv = 0;
        }
index b05e3db5fa63c766718c79578d200d6ad99967b6..a00f47b16c10a7ca15190e41f47c28489916ecc3 100644 (file)
@@ -38,7 +38,7 @@ static int prom_nbputchar(const char *buf)
                break;
        default:
                break;
-       };
+       }
        restore_current();
        spin_unlock_irqrestore(&prom_lock, flags);
        return i; /* Ugh, we could spin forever on unsupported proms ;( */
index 0a601b300639ff6ce7a0909c7b3a2ff544dbd8c3..26c64cea3c9c082e701f672e299a50ff2f70ad09 100644 (file)
@@ -53,7 +53,7 @@ void __init prom_init(struct linux_romvec *rp)
                            romvec->pv_romvers);
                prom_halt();
                break;
-       };
+       }
 
        prom_rev = romvec->pv_plugin_revision;
        prom_prev = romvec->pv_printrev;
index 97c44c9ddbc85bd87a400a9560170f1313656635..0da8256cf76f286a6e2aa2d4c60e219e18a1e911 100644 (file)
@@ -35,7 +35,7 @@ prom_startcpu(int cpunode, struct linux_prom_registers *ctable_reg, int ctx, cha
        case PROM_V3:
                ret = (*(romvec->v3_cpustart))(cpunode, (int) ctable_reg, ctx, pc);
                break;
-       };
+       }
        restore_current();
        spin_unlock_irqrestore(&prom_lock, flags);
 
index e32b0c23c4c815870ac0dac9358ea97af1e8cd05..0249b8b4db545bdb26334d05d3e105a387b6f1d0 100644 (file)
@@ -5,13 +5,13 @@ config TILE
        def_bool y
        select HAVE_KVM if !TILEGX
        select GENERIC_FIND_FIRST_BIT
-       select GENERIC_FIND_NEXT_BIT
        select USE_GENERIC_SMP_HELPERS
        select CC_OPTIMIZE_FOR_SIZE
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_PROBE
        select GENERIC_PENDING_IRQ if SMP
        select GENERIC_IRQ_SHOW
+       select SYS_HYPERVISOR
 
 # FIXME: investigate whether we need/want these options.
 #      select HAVE_IOREMAP_PROT
@@ -339,6 +339,14 @@ config NO_IOPORT
 
 source "drivers/pci/Kconfig"
 
+config HOTPLUG
+       bool "Support for hot-pluggable devices"
+       ---help---
+         Say Y here if you want to plug devices into your computer while
+         the system is running, and be able to use them quickly.  In many
+         cases, the devices can likewise be unplugged at any time too.
+         One well-known example of this is USB.
+
 source "drivers/pci/hotplug/Kconfig"
 
 endmenu
index 9bc161a02c71ba65ef8e1394cb1617738533bd9e..ddbfc3322d7f461e693614405ac5ce2aee930148 100644 (file)
@@ -21,15 +21,6 @@ config DEBUG_STACKOVERFLOW
          This option will cause messages to be printed if free stack space
          drops below a certain limit.
 
-config DEBUG_STACK_USAGE
-       bool "Stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T and sysrq-P debug output.
-
-         This option will slow down process creation somewhat.
-
 config DEBUG_EXTRA_FLAGS
        string "Additional compiler arguments when building with '-g'"
        depends on DEBUG_INFO
diff --git a/arch/tile/configs/tile_defconfig b/arch/tile/configs/tile_defconfig
deleted file mode 100644 (file)
index 0fe5444..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="usr/contents.txt"
-CONFIG_EXPERT=y
-# CONFIG_COMPAT_BRK is not set
-CONFIG_PROFILING=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_HZ_100=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-CONFIG_IPV6=y
-# CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_NETDEVICES=y
-CONFIG_TUN=y
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_WLAN is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-# CONFIG_HID_SUPPORT is not set
-CONFIG_RTC_CLASS=y
-# CONFIG_RTC_INTF_SYSFS is not set
-# CONFIG_RTC_INTF_PROC is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_FUSE_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=m
-CONFIG_TMPFS=y
-CONFIG_HUGETLBFS=y
-CONFIG_NFS_FS=m
-CONFIG_NFS_V3=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_FRAME_WARN=2048
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DETECT_HUNG_TASK=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_VM=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_DEBUG_STACKOVERFLOW=y
-CONFIG_DEBUG_EXTRA_FLAGS="-femit-struct-debug-baseonly"
diff --git a/arch/tile/configs/tilegx_defconfig b/arch/tile/configs/tilegx_defconfig
new file mode 100644 (file)
index 0000000..09f1c7f
--- /dev/null
@@ -0,0 +1,1833 @@
+#
+# Automatically generated make config: don't edit
+# Linux/tilegx 2.6.39-rc5 Kernel Configuration
+# Wed May  4 11:08:04 2011
+#
+CONFIG_TILE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_HAVE_ARCH_ALLOC_REMAP=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
+CONFIG_SYS_SUPPORTS_HUGETLBFS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_DEFAULT_MIGRATION_COST=10000000
+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
+CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_SMP=y
+# CONFIG_DEBUG_COPY_FROM_USER is not set
+CONFIG_HVC_TILE=y
+CONFIG_TILEGX=y
+CONFIG_64BIT=y
+CONFIG_ARCH_DEFCONFIG="arch/tile/configs/tilegx_defconfig"
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_FHANDLE is not set
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_AUDIT=y
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_PENDING_IRQ=y
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=64
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=19
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_NS=y
+# CONFIG_CGROUP_FREEZER is not set
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_MEM_RES_CTLR=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
+# CONFIG_DEBUG_BLK_CGROUP is not set
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+# CONFIG_SCHED_AUTOGROUP is not set
+CONFIG_MM_OWNER=y
+# CONFIG_SYSFS_DEPRECATED is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="usr/contents.txt"
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+CONFIG_INITRAMFS_COMPRESSION_NONE=y
+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EXPERT=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_EMBEDDED=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_BLK_DEV_BSG=y
+CONFIG_BLK_DEV_INTEGRITY=y
+# CONFIG_BLK_DEV_THROTTLING is not set
+CONFIG_BLOCK_COMPAT=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CFQ_GROUP_IOSCHED=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_PADATA=y
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+
+#
+# Tilera-specific configuration
+#
+CONFIG_NR_CPUS=100
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+CONFIG_SCHED_HRTICK=y
+# CONFIG_KEXEC is not set
+CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=y
+# CONFIG_HIGHMEM is not set
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=2
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_DISCONTIGMEM_MANUAL=y
+CONFIG_DISCONTIGMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_COMPACTION is not set
+CONFIG_MIGRATION=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_VMALLOC_RESERVE=0x1000000
+CONFIG_HARDWALL=y
+CONFIG_KERNEL_PL=1
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_NO_IOMEM is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_PCI_DEBUG=y
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_COMPAT_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+CONFIG_BINFMT_MISC=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_MIGRATE=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_XFRM_IPCOMP=m
+CONFIG_NET_KEY=m
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_FIB_TRIE_STATS is not set
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_ROUTE_CLASSID=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+# CONFIG_NET_IPGRE_DEMUX is not set
+CONFIG_IP_MROUTE=y
+# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BIC=m
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_CONG_ILLINOIS=m
+CONFIG_DEFAULT_CUBIC=y
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_TCP_MD5SIG=y
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_SIT=m
+# CONFIG_IPV6_SIT_6RD is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+# CONFIG_IPV6_SUBTREES is not set
+CONFIG_IPV6_MROUTE=y
+# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_NETLABEL=y
+CONFIG_NETWORK_SECMARK=y
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+# CONFIG_NF_CONNTRACK_TIMESTAMP is not set
+CONFIG_NF_CT_PROTO_DCCP=m
+CONFIG_NF_CT_PROTO_GRE=m
+CONFIG_NF_CT_PROTO_SCTP=m
+CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_BROADCAST=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+# CONFIG_NF_CONNTRACK_SNMP is not set
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+# CONFIG_NF_CT_NETLINK is not set
+CONFIG_NETFILTER_TPROXY=m
+CONFIG_NETFILTER_XTABLES=y
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=m
+CONFIG_NETFILTER_XT_CONNMARK=m
+
+#
+# Xtables targets
+#
+# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set
+# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
+CONFIG_NETFILTER_XT_TARGET_CT=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HL=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_RATEEST=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+
+#
+# Xtables matches
+#
+# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+# CONFIG_NETFILTER_XT_MATCH_CPU is not set
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_HL=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+# CONFIG_IP_SET is not set
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_AH_ESP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_PROTO_SCTP=y
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+# CONFIG_IP_VS_DH is not set
+# CONFIG_IP_VS_SH is not set
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+# CONFIG_IP_VS_NFCT is not set
+# CONFIG_IP_VS_PE_SIP is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_CONNTRACK_IPV4=y
+# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+# CONFIG_NF_NAT is not set
+CONFIG_IP_NF_MANGLE=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_SECURITY=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV6=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+# CONFIG_IP_DCCP is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+CONFIG_RDS=m
+CONFIG_RDS_TCP=m
+# CONFIG_RDS_DEBUG is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+CONFIG_STP=m
+CONFIG_GARP=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+CONFIG_NET_DSA=y
+CONFIG_NET_DSA_TAG_DSA=y
+CONFIG_NET_DSA_TAG_EDSA=y
+CONFIG_NET_DSA_TAG_TRAILER=y
+CONFIG_NET_DSA_MV88E6XXX=y
+CONFIG_NET_DSA_MV88E6060=y
+CONFIG_NET_DSA_MV88E6XXX_NEED_PPU=y
+CONFIG_NET_DSA_MV88E6131=y
+CONFIG_NET_DSA_MV88E6123_61_65=y
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_PHONET=m
+# CONFIG_IEEE802154 is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+# CONFIG_NET_SCH_SFB is not set
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+# CONFIG_NET_SCH_MQPRIO is not set
+# CONFIG_NET_SCH_CHOKE is not set
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+# CONFIG_NET_ACT_CSUM is not set
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_SCH_FIFO=y
+CONFIG_DCB=y
+CONFIG_DNS_RESOLVER=y
+# CONFIG_BATMAN_ADV is not set
+CONFIG_RPS=y
+CONFIG_RFS_ACCEL=y
+CONFIG_XPS=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+# CONFIG_BLK_DEV_DRBD is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+CONFIG_ATA_OVER_ETH=y
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_BMP085 is not set
+# CONFIG_PCH_PHUB is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+# CONFIG_SENSORS_LIS3_I2C is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=m
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+CONFIG_SCSI_TGT=m
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+CONFIG_SCSI_SAS_ATTRS=m
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_CXGB4_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_SCSI_BNX2X_FCOE is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_FCOE is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_PMCRAID is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_ATA=m
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_SATA_PMP=y
+
+#
+# Controllers with non-SFF native interface
+#
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_AHCI_PLATFORM is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_SATA_ACARD_AHCI is not set
+CONFIG_SATA_SIL24=m
+CONFIG_ATA_SFF=y
+
+#
+# SFF controllers with custom DMA interface
+#
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_ATA_BMDMA=y
+
+#
+# SATA SFF controllers with BMDMA
+#
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+
+#
+# PATA SFF controllers with BMDMA
+#
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARASAN_CF is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CS5536 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_TOSHIBA is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+
+#
+# PIO-only SFF controllers
+#
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_RZ1000 is not set
+
+#
+# Generic fallback / legacy drivers
+#
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_LEGACY is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_AUTODETECT=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_MULTICORE_RAID456=y
+# CONFIG_MD_MULTIPATH is not set
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+# CONFIG_DM_RAID is not set
+CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_QL=m
+CONFIG_DM_MULTIPATH_ST=m
+CONFIG_DM_DELAY=m
+CONFIG_DM_UEVENT=y
+# CONFIG_DM_FLAKEY is not set
+# CONFIG_TARGET_CORE is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+CONFIG_IFB=m
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+CONFIG_VETH=m
+# CONFIG_ARCNET is not set
+# CONFIG_MII is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# 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_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_BCM63XX_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_MICREL_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+# CONFIG_NET_ETHERNET is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+CONFIG_E1000E=m
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_STMMAC_ETH is not set
+# CONFIG_PCH_GBE is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+# CONFIG_WLAN is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+# CONFIG_TILE_NET is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+# CONFIG_N_GSM is not set
+CONFIG_DEVKMEM=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MFD_HSU is not set
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_PCH_UART is not set
+# CONFIG_TTY_PRINTK is not set
+CONFIG_HVC_DRIVER=y
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_RAMOOPS is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MUX is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_INTEL_MID is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_PXA_PCI is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+# CONFIG_I2C_EG20T is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGA_ARB is not set
+# CONFIG_DRM is not set
+# CONFIG_STUB_POULSBO is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_NFC_DEVICES is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_ISL12022 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_TILE=y
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT2_FS_XIP=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_DEFAULTS_TO_ORDERED=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_XATTR=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_FS_XIP=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_JBD2=y
+CONFIG_JBD2_DEBUG=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_XFS_FS=m
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_DEBUG is not set
+CONFIG_GFS2_FS=m
+CONFIG_GFS2_FS_LOCKING_DLM=y
+# CONFIG_OCFS2_FS is not set
+CONFIG_BTRFS_FS=m
+CONFIG_BTRFS_FS_POSIX_ACL=y
+# CONFIG_NILFS2_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_EXPORTFS=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+# CONFIG_QUOTA_DEBUG is not set
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=m
+CONFIG_GENERIC_ACL=y
+
+#
+# Caches
+#
+CONFIG_FSCACHE=m
+CONFIG_FSCACHE_STATS=y
+# CONFIG_FSCACHE_HISTOGRAM is not set
+# CONFIG_FSCACHE_DEBUG is not set
+# CONFIG_FSCACHE_OBJECT_LIST is not set
+CONFIG_CACHEFILES=m
+# CONFIG_CACHEFILES_DEBUG is not set
+# CONFIG_CACHEFILES_HISTOGRAM is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_CONFIGFS_FS=m
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_ECRYPT_FS=m
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_LOGFS is not set
+CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=m
+# CONFIG_SQUASHFS_XATTR is not set
+# CONFIG_SQUASHFS_LZO is not set
+# CONFIG_SQUASHFS_XZ is not set
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_PSTORE is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_PNFS_FILE_LAYOUT=m
+CONFIG_NFS_FSCACHE=y
+# CONFIG_NFS_USE_LEGACY_DNS is not set
+CONFIG_NFS_USE_KERNEL_DNS=y
+# CONFIG_NFS_USE_NEW_IDMAPPER is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_DEPRECATED=y
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_CEPH_FS is not set
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+# CONFIG_CIFS_STATS2 is not set
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_DEBUG2 is not set
+CONFIG_CIFS_DFS_UPCALL=y
+CONFIG_CIFS_FSCACHE=y
+# CONFIG_CIFS_ACL is not set
+CONFIG_CIFS_EXPERIMENTAL=y
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+CONFIG_DLM=m
+CONFIG_DLM_DEBUG=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+CONFIG_HEADERS_CHECK=y
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_LOCK_STAT is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_REDUCED=y
+CONFIG_DEBUG_VM=y
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+CONFIG_DEBUG_CREDENTIALS=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BUILD_DOCSRC is not set
+CONFIG_DYNAMIC_DEBUG=y
+# CONFIG_ATOMIC64_SELFTEST is not set
+CONFIG_ASYNC_RAID6_TEST=m
+# CONFIG_SAMPLES is not set
+# CONFIG_TEST_KSTRTOX is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_EXTRA_FLAGS=""
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITYFS=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+# CONFIG_SECURITY_PATH is not set
+CONFIG_LSM_MMAP_MIN_ADDR=65536
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=1
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set
+# CONFIG_SECURITY_SMACK is not set
+# CONFIG_SECURITY_TOMOYO is not set
+# CONFIG_SECURITY_APPARMOR is not set
+# CONFIG_IMA is not set
+CONFIG_DEFAULT_SECURITY_SELINUX=y
+# CONFIG_DEFAULT_SECURITY_DAC is not set
+CONFIG_DEFAULT_SECURITY="selinux"
+CONFIG_XOR_BLOCKS=m
+CONFIG_ASYNC_CORE=m
+CONFIG_ASYNC_MEMCPY=m
+CONFIG_ASYNC_XOR=m
+CONFIG_ASYNC_PQ=m
+CONFIG_ASYNC_RAID6_RECOV=m
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_PCRYPT=m
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_SEQIV=m
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_CTR=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_VMAC=m
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_GHASH=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_SALSA20 is not set
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_ZLIB=m
+CONFIG_CRYPTO_LZO=m
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_DEV_HIFN_795X=m
+CONFIG_CRYPTO_DEV_HIFN_795X_RNG=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_RAID6_PQ=m
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=m
+CONFIG_AUDIT_GENERIC=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_LZO_COMPRESS=m
+CONFIG_LZO_DECOMPRESS=m
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_CPU_RMAP=y
+CONFIG_NLATTR=y
+# CONFIG_AVERAGE is not set
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/tile/configs/tilepro_defconfig b/arch/tile/configs/tilepro_defconfig
new file mode 100644 (file)
index 0000000..f58dc36
--- /dev/null
@@ -0,0 +1,1163 @@
+#
+# Automatically generated make config: don't edit
+# Linux/tile 2.6.39-rc5 Kernel Configuration
+# Tue May  3 09:15:02 2011
+#
+CONFIG_TILE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_HAVE_ARCH_ALLOC_REMAP=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
+CONFIG_SYS_SUPPORTS_HUGETLBFS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_DEFAULT_MIGRATION_COST=10000000
+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
+CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_SMP=y
+# CONFIG_DEBUG_COPY_FROM_USER is not set
+CONFIG_HVC_TILE=y
+# CONFIG_TILEGX is not set
+CONFIG_ARCH_DEFCONFIG="arch/tile/configs/tile_defconfig"
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_FHANDLE=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_PENDING_IRQ=y
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_CGROUPS is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_SCHED_AUTOGROUP is not set
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="usr/contents.txt"
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+CONFIG_INITRAMFS_COMPRESSION_NONE=y
+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EXPERT=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_EMBEDDED=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+
+#
+# Tilera-specific configuration
+#
+CONFIG_NR_CPUS=64
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+CONFIG_SCHED_HRTICK=y
+# CONFIG_KEXEC is not set
+CONFIG_HIGHMEM=y
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=2
+# CONFIG_VMSPLIT_3_75G is not set
+# CONFIG_VMSPLIT_3_5G is not set
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2_75G is not set
+# CONFIG_VMSPLIT_2_5G is not set
+# CONFIG_VMSPLIT_2_25G is not set
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_DISCONTIGMEM_MANUAL=y
+CONFIG_DISCONTIGMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_COMPACTION is not set
+CONFIG_MIGRATION=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_VMALLOC_RESERVE=0x1000000
+CONFIG_HARDWALL=y
+CONFIG_KERNEL_PL=1
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_NO_IOMEM is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+# CONFIG_IPV6_SIT_6RD is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+# CONFIG_BATMAN_ADV is not set
+CONFIG_RPS=y
+CONFIG_RFS_ACCEL=y
+CONFIG_XPS=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_PCH_PHUB is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_CXGB4_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_SCSI_BNX2X_FCOE is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_FCOE is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_PMCRAID is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_TARGET_CORE is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+# CONFIG_MII is not set
+# CONFIG_PHYLIB is not set
+# CONFIG_NET_ETHERNET is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_STMMAC_ETH is not set
+# CONFIG_PCH_GBE is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+# CONFIG_WLAN is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+CONFIG_TILE_NET=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+# CONFIG_N_GSM is not set
+CONFIG_DEVKMEM=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MFD_HSU is not set
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_PCH_UART is not set
+# CONFIG_TTY_PRINTK is not set
+CONFIG_HVC_DRIVER=y
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_RAMOOPS is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SCH5627 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_ALIM7101_WDT is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
+# CONFIG_DRM is not set
+# CONFIG_STUB_POULSBO is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_NFC_DEVICES is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_EDAC=y
+
+#
+# Reporting subsystems
+#
+# CONFIG_EDAC_DEBUG is not set
+CONFIG_EDAC_MM_EDAC=y
+CONFIG_EDAC_TILE=y
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+# CONFIG_RTC_INTF_SYSFS is not set
+# CONFIG_RTC_INTF_PROC is not set
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_TILE=y
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_EXPORTFS=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=y
+# CONFIG_CUSE is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_LOGFS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_PSTORE is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_LOCK_STAT is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_INFO_REDUCED is not set
+CONFIG_DEBUG_VM=y
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_TEST_KSTRTOX is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_EXTRA_FLAGS="-femit-struct-debug-baseonly"
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=m
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCRYPT is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_CPU_RMAP=y
+CONFIG_NLATTR=y
+# CONFIG_AVERAGE is not set
+CONFIG_HAVE_KVM=y
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/tile/include/arch/chip_tilegx.h b/arch/tile/include/arch/chip_tilegx.h
new file mode 100644 (file)
index 0000000..ea8e4f2
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/*
+ * @file
+ * Global header file.
+ * This header file specifies defines for TILE-Gx.
+ */
+
+#ifndef __ARCH_CHIP_H__
+#define __ARCH_CHIP_H__
+
+/** Specify chip version.
+ * When possible, prefer the CHIP_xxx symbols below for future-proofing.
+ * This is intended for cross-compiling; native compilation should
+ * use the predefined __tile_chip__ symbol.
+ */
+#define TILE_CHIP 10
+
+/** Specify chip revision.
+ * This provides for the case of a respin of a particular chip type;
+ * the normal value for this symbol is "0".
+ * This is intended for cross-compiling; native compilation should
+ * use the predefined __tile_chip_rev__ symbol.
+ */
+#define TILE_CHIP_REV 0
+
+/** The name of this architecture. */
+#define CHIP_ARCH_NAME "tilegx"
+
+/** The ELF e_machine type for binaries for this chip. */
+#define CHIP_ELF_TYPE() EM_TILEGX
+
+/** The alternate ELF e_machine type for binaries for this chip. */
+#define CHIP_COMPAT_ELF_TYPE() 0x2597
+
+/** What is the native word size of the machine? */
+#define CHIP_WORD_SIZE() 64
+
+/** How many bits of a virtual address are used. Extra bits must be
+ * the sign extension of the low bits.
+ */
+#define CHIP_VA_WIDTH() 42
+
+/** How many bits are in a physical address? */
+#define CHIP_PA_WIDTH() 40
+
+/** Size of the L2 cache, in bytes. */
+#define CHIP_L2_CACHE_SIZE() 262144
+
+/** Log size of an L2 cache line in bytes. */
+#define CHIP_L2_LOG_LINE_SIZE() 6
+
+/** Size of an L2 cache line, in bytes. */
+#define CHIP_L2_LINE_SIZE() (1 << CHIP_L2_LOG_LINE_SIZE())
+
+/** Associativity of the L2 cache. */
+#define CHIP_L2_ASSOC() 8
+
+/** Size of the L1 data cache, in bytes. */
+#define CHIP_L1D_CACHE_SIZE() 32768
+
+/** Log size of an L1 data cache line in bytes. */
+#define CHIP_L1D_LOG_LINE_SIZE() 6
+
+/** Size of an L1 data cache line, in bytes. */
+#define CHIP_L1D_LINE_SIZE() (1 << CHIP_L1D_LOG_LINE_SIZE())
+
+/** Associativity of the L1 data cache. */
+#define CHIP_L1D_ASSOC() 2
+
+/** Size of the L1 instruction cache, in bytes. */
+#define CHIP_L1I_CACHE_SIZE() 32768
+
+/** Log size of an L1 instruction cache line in bytes. */
+#define CHIP_L1I_LOG_LINE_SIZE() 6
+
+/** Size of an L1 instruction cache line, in bytes. */
+#define CHIP_L1I_LINE_SIZE() (1 << CHIP_L1I_LOG_LINE_SIZE())
+
+/** Associativity of the L1 instruction cache. */
+#define CHIP_L1I_ASSOC() 2
+
+/** Stride with which flush instructions must be issued. */
+#define CHIP_FLUSH_STRIDE() CHIP_L2_LINE_SIZE()
+
+/** Stride with which inv instructions must be issued. */
+#define CHIP_INV_STRIDE() CHIP_L2_LINE_SIZE()
+
+/** Stride with which finv instructions must be issued. */
+#define CHIP_FINV_STRIDE() CHIP_L2_LINE_SIZE()
+
+/** Can the local cache coherently cache data that is homed elsewhere? */
+#define CHIP_HAS_COHERENT_LOCAL_CACHE() 1
+
+/** How many simultaneous outstanding victims can the L2 cache have? */
+#define CHIP_MAX_OUTSTANDING_VICTIMS() 128
+
+/** Does the TLB support the NC and NOALLOC bits? */
+#define CHIP_HAS_NC_AND_NOALLOC_BITS() 1
+
+/** Does the chip support hash-for-home caching? */
+#define CHIP_HAS_CBOX_HOME_MAP() 1
+
+/** Number of entries in the chip's home map tables. */
+#define CHIP_CBOX_HOME_MAP_SIZE() 128
+
+/** Do uncacheable requests miss in the cache regardless of whether
+ * there is matching data? */
+#define CHIP_HAS_ENFORCED_UNCACHEABLE_REQUESTS() 1
+
+/** Does the mf instruction wait for victims? */
+#define CHIP_HAS_MF_WAITS_FOR_VICTIMS() 0
+
+/** Does the chip have an "inv" instruction that doesn't also flush? */
+#define CHIP_HAS_INV() 1
+
+/** Does the chip have a "wh64" instruction? */
+#define CHIP_HAS_WH64() 1
+
+/** Does this chip have a 'dword_align' instruction? */
+#define CHIP_HAS_DWORD_ALIGN() 0
+
+/** Number of performance counters. */
+#define CHIP_PERFORMANCE_COUNTERS() 4
+
+/** Does this chip have auxiliary performance counters? */
+#define CHIP_HAS_AUX_PERF_COUNTERS() 1
+
+/** Is the CBOX_MSR1 SPR supported? */
+#define CHIP_HAS_CBOX_MSR1() 0
+
+/** Is the TILE_RTF_HWM SPR supported? */
+#define CHIP_HAS_TILE_RTF_HWM() 1
+
+/** Is the TILE_WRITE_PENDING SPR supported? */
+#define CHIP_HAS_TILE_WRITE_PENDING() 0
+
+/** Is the PROC_STATUS SPR supported? */
+#define CHIP_HAS_PROC_STATUS_SPR() 1
+
+/** Is the DSTREAM_PF SPR supported? */
+#define CHIP_HAS_DSTREAM_PF() 1
+
+/** Log of the number of mshims we have. */
+#define CHIP_LOG_NUM_MSHIMS() 2
+
+/** Are the bases of the interrupt vector areas fixed? */
+#define CHIP_HAS_FIXED_INTVEC_BASE() 0
+
+/** Are the interrupt masks split up into 2 SPRs? */
+#define CHIP_HAS_SPLIT_INTR_MASK() 0
+
+/** Is the cycle count split up into 2 SPRs? */
+#define CHIP_HAS_SPLIT_CYCLE() 0
+
+/** Does the chip have a static network? */
+#define CHIP_HAS_SN() 0
+
+/** Does the chip have a static network processor? */
+#define CHIP_HAS_SN_PROC() 0
+
+/** Size of the L1 static network processor instruction cache, in bytes. */
+/* #define CHIP_L1SNI_CACHE_SIZE() -- does not apply to chip 10 */
+
+/** Does the chip have DMA support in each tile? */
+#define CHIP_HAS_TILE_DMA() 0
+
+/** Does the chip have the second revision of the directly accessible
+ *  dynamic networks?  This encapsulates a number of characteristics,
+ *  including the absence of the catch-all, the absence of inline message
+ *  tags, the absence of support for network context-switching, and so on.
+ */
+#define CHIP_HAS_REV1_XDN() 1
+
+/** Does the chip have cmpexch and similar (fetchadd, exch, etc.)? */
+#define CHIP_HAS_CMPEXCH() 1
+
+/** Does the chip have memory-mapped I/O support? */
+#define CHIP_HAS_MMIO() 1
+
+/** Does the chip have post-completion interrupts? */
+#define CHIP_HAS_POST_COMPLETION_INTERRUPTS() 1
+
+/** Does the chip have native single step support? */
+#define CHIP_HAS_SINGLE_STEP() 1
+
+#ifndef __OPEN_SOURCE__  /* features only relevant to hypervisor-level code */
+
+/** How many entries are present in the instruction TLB? */
+#define CHIP_ITLB_ENTRIES() 16
+
+/** How many entries are present in the data TLB? */
+#define CHIP_DTLB_ENTRIES() 32
+
+/** How many MAF entries does the XAUI shim have? */
+#define CHIP_XAUI_MAF_ENTRIES() 32
+
+/** Does the memory shim have a source-id table? */
+#define CHIP_HAS_MSHIM_SRCID_TABLE() 0
+
+/** Does the L1 instruction cache clear on reset? */
+#define CHIP_HAS_L1I_CLEAR_ON_RESET() 1
+
+/** Does the chip come out of reset with valid coordinates on all tiles?
+ * Note that if defined, this also implies that the upper left is 1,1.
+ */
+#define CHIP_HAS_VALID_TILE_COORD_RESET() 1
+
+/** Does the chip have unified packet formats? */
+#define CHIP_HAS_UNIFIED_PACKET_FORMATS() 1
+
+/** Does the chip support write reordering? */
+#define CHIP_HAS_WRITE_REORDERING() 1
+
+/** Does the chip support Y-X routing as well as X-Y? */
+#define CHIP_HAS_Y_X_ROUTING() 1
+
+/** Is INTCTRL_3 managed with the correct MPL? */
+#define CHIP_HAS_INTCTRL_3_STATUS_FIX() 1
+
+/** Is it possible to configure the chip to be big-endian? */
+#define CHIP_HAS_BIG_ENDIAN_CONFIG() 1
+
+/** Is the CACHE_RED_WAY_OVERRIDDEN SPR supported? */
+#define CHIP_HAS_CACHE_RED_WAY_OVERRIDDEN() 0
+
+/** Is the DIAG_TRACE_WAY SPR supported? */
+#define CHIP_HAS_DIAG_TRACE_WAY() 0
+
+/** Is the MEM_STRIPE_CONFIG SPR supported? */
+#define CHIP_HAS_MEM_STRIPE_CONFIG() 1
+
+/** Are the TLB_PERF SPRs supported? */
+#define CHIP_HAS_TLB_PERF() 1
+
+/** Is the VDN_SNOOP_SHIM_CTL SPR supported? */
+#define CHIP_HAS_VDN_SNOOP_SHIM_CTL() 0
+
+/** Does the chip support rev1 DMA packets? */
+#define CHIP_HAS_REV1_DMA_PACKETS() 1
+
+/** Does the chip have an IPI shim? */
+#define CHIP_HAS_IPI() 1
+
+#endif /* !__OPEN_SOURCE__ */
+#endif /* __ARCH_CHIP_H__ */
index 5c87c90163389bc3b6a9a265a4fbc1dea6256cc6..762eafa8a11ec95af2928e9c045549ff59c4604e 100644 (file)
@@ -16,7 +16,7 @@
 /**
  * @file
  *
- * Support for invalidating bytes in the instruction
+ * Support for invalidating bytes in the instruction cache.
  */
 
 #ifndef __ARCH_ICACHE_H__
  *
  * @param addr The start of memory to be invalidated.
  * @param size The number of bytes to be invalidated.
- * @param page_size The system's page size, typically the PAGE_SIZE constant
- * in sys/page.h.  This value must be a power of two no larger
- * than the page containing the code to be invalidated. If the value
- * is smaller than the actual page size, this function will still
- * work, but may run slower than necessary.
+ * @param page_size The system's page size, e.g. getpagesize() in userspace.
+ * This value must be a power of two no larger than the page containing
+ * the code to be invalidated. If the value is smaller than the actual page
+ * size, this function will still work, but may run slower than necessary.
  */
 static __inline void
 invalidate_icache(const void* addr, unsigned long size,
diff --git a/arch/tile/include/arch/interrupts_64.h b/arch/tile/include/arch/interrupts_64.h
new file mode 100644 (file)
index 0000000..5bb58b2
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#ifndef __ARCH_INTERRUPTS_H__
+#define __ARCH_INTERRUPTS_H__
+
+/** Mask for an interrupt. */
+#ifdef __ASSEMBLER__
+/* Note: must handle breaking interrupts into high and low words manually. */
+#define INT_MASK(intno) (1 << (intno))
+#else
+#define INT_MASK(intno) (1ULL << (intno))
+#endif
+
+
+/** Where a given interrupt executes */
+#define INTERRUPT_VECTOR(i, pl) (0xFC000000 + ((pl) << 24) + ((i) << 8))
+
+/** Where to store a vector for a given interrupt. */
+#define USER_INTERRUPT_VECTOR(i) INTERRUPT_VECTOR(i, 0)
+
+/** The base address of user-level interrupts. */
+#define USER_INTERRUPT_VECTOR_BASE INTERRUPT_VECTOR(0, 0)
+
+
+/** Additional synthetic interrupt. */
+#define INT_BREAKPOINT (63)
+
+#define INT_MEM_ERROR    0
+#define INT_SINGLE_STEP_3    1
+#define INT_SINGLE_STEP_2    2
+#define INT_SINGLE_STEP_1    3
+#define INT_SINGLE_STEP_0    4
+#define INT_IDN_COMPLETE    5
+#define INT_UDN_COMPLETE    6
+#define INT_ITLB_MISS    7
+#define INT_ILL    8
+#define INT_GPV    9
+#define INT_IDN_ACCESS   10
+#define INT_UDN_ACCESS   11
+#define INT_SWINT_3   12
+#define INT_SWINT_2   13
+#define INT_SWINT_1   14
+#define INT_SWINT_0   15
+#define INT_ILL_TRANS   16
+#define INT_UNALIGN_DATA   17
+#define INT_DTLB_MISS   18
+#define INT_DTLB_ACCESS   19
+#define INT_IDN_FIREWALL   20
+#define INT_UDN_FIREWALL   21
+#define INT_TILE_TIMER   22
+#define INT_AUX_TILE_TIMER   23
+#define INT_IDN_TIMER   24
+#define INT_UDN_TIMER   25
+#define INT_IDN_AVAIL   26
+#define INT_UDN_AVAIL   27
+#define INT_IPI_3   28
+#define INT_IPI_2   29
+#define INT_IPI_1   30
+#define INT_IPI_0   31
+#define INT_PERF_COUNT   32
+#define INT_AUX_PERF_COUNT   33
+#define INT_INTCTRL_3   34
+#define INT_INTCTRL_2   35
+#define INT_INTCTRL_1   36
+#define INT_INTCTRL_0   37
+#define INT_BOOT_ACCESS   38
+#define INT_WORLD_ACCESS   39
+#define INT_I_ASID   40
+#define INT_D_ASID   41
+#define INT_DOUBLE_FAULT   42
+
+#define NUM_INTERRUPTS 43
+
+#ifndef __ASSEMBLER__
+#define QUEUED_INTERRUPTS ( \
+    INT_MASK(INT_MEM_ERROR) | \
+    INT_MASK(INT_IDN_COMPLETE) | \
+    INT_MASK(INT_UDN_COMPLETE) | \
+    INT_MASK(INT_IDN_FIREWALL) | \
+    INT_MASK(INT_UDN_FIREWALL) | \
+    INT_MASK(INT_TILE_TIMER) | \
+    INT_MASK(INT_AUX_TILE_TIMER) | \
+    INT_MASK(INT_IDN_TIMER) | \
+    INT_MASK(INT_UDN_TIMER) | \
+    INT_MASK(INT_IDN_AVAIL) | \
+    INT_MASK(INT_UDN_AVAIL) | \
+    INT_MASK(INT_IPI_3) | \
+    INT_MASK(INT_IPI_2) | \
+    INT_MASK(INT_IPI_1) | \
+    INT_MASK(INT_IPI_0) | \
+    INT_MASK(INT_PERF_COUNT) | \
+    INT_MASK(INT_AUX_PERF_COUNT) | \
+    INT_MASK(INT_INTCTRL_3) | \
+    INT_MASK(INT_INTCTRL_2) | \
+    INT_MASK(INT_INTCTRL_1) | \
+    INT_MASK(INT_INTCTRL_0) | \
+    INT_MASK(INT_BOOT_ACCESS) | \
+    INT_MASK(INT_WORLD_ACCESS) | \
+    INT_MASK(INT_I_ASID) | \
+    INT_MASK(INT_D_ASID) | \
+    INT_MASK(INT_DOUBLE_FAULT) | \
+    0)
+#define NONQUEUED_INTERRUPTS ( \
+    INT_MASK(INT_SINGLE_STEP_3) | \
+    INT_MASK(INT_SINGLE_STEP_2) | \
+    INT_MASK(INT_SINGLE_STEP_1) | \
+    INT_MASK(INT_SINGLE_STEP_0) | \
+    INT_MASK(INT_ITLB_MISS) | \
+    INT_MASK(INT_ILL) | \
+    INT_MASK(INT_GPV) | \
+    INT_MASK(INT_IDN_ACCESS) | \
+    INT_MASK(INT_UDN_ACCESS) | \
+    INT_MASK(INT_SWINT_3) | \
+    INT_MASK(INT_SWINT_2) | \
+    INT_MASK(INT_SWINT_1) | \
+    INT_MASK(INT_SWINT_0) | \
+    INT_MASK(INT_ILL_TRANS) | \
+    INT_MASK(INT_UNALIGN_DATA) | \
+    INT_MASK(INT_DTLB_MISS) | \
+    INT_MASK(INT_DTLB_ACCESS) | \
+    0)
+#define CRITICAL_MASKED_INTERRUPTS ( \
+    INT_MASK(INT_MEM_ERROR) | \
+    INT_MASK(INT_SINGLE_STEP_3) | \
+    INT_MASK(INT_SINGLE_STEP_2) | \
+    INT_MASK(INT_SINGLE_STEP_1) | \
+    INT_MASK(INT_SINGLE_STEP_0) | \
+    INT_MASK(INT_IDN_COMPLETE) | \
+    INT_MASK(INT_UDN_COMPLETE) | \
+    INT_MASK(INT_IDN_FIREWALL) | \
+    INT_MASK(INT_UDN_FIREWALL) | \
+    INT_MASK(INT_TILE_TIMER) | \
+    INT_MASK(INT_AUX_TILE_TIMER) | \
+    INT_MASK(INT_IDN_TIMER) | \
+    INT_MASK(INT_UDN_TIMER) | \
+    INT_MASK(INT_IDN_AVAIL) | \
+    INT_MASK(INT_UDN_AVAIL) | \
+    INT_MASK(INT_IPI_3) | \
+    INT_MASK(INT_IPI_2) | \
+    INT_MASK(INT_IPI_1) | \
+    INT_MASK(INT_IPI_0) | \
+    INT_MASK(INT_PERF_COUNT) | \
+    INT_MASK(INT_AUX_PERF_COUNT) | \
+    INT_MASK(INT_INTCTRL_3) | \
+    INT_MASK(INT_INTCTRL_2) | \
+    INT_MASK(INT_INTCTRL_1) | \
+    INT_MASK(INT_INTCTRL_0) | \
+    0)
+#define CRITICAL_UNMASKED_INTERRUPTS ( \
+    INT_MASK(INT_ITLB_MISS) | \
+    INT_MASK(INT_ILL) | \
+    INT_MASK(INT_GPV) | \
+    INT_MASK(INT_IDN_ACCESS) | \
+    INT_MASK(INT_UDN_ACCESS) | \
+    INT_MASK(INT_SWINT_3) | \
+    INT_MASK(INT_SWINT_2) | \
+    INT_MASK(INT_SWINT_1) | \
+    INT_MASK(INT_SWINT_0) | \
+    INT_MASK(INT_ILL_TRANS) | \
+    INT_MASK(INT_UNALIGN_DATA) | \
+    INT_MASK(INT_DTLB_MISS) | \
+    INT_MASK(INT_DTLB_ACCESS) | \
+    INT_MASK(INT_BOOT_ACCESS) | \
+    INT_MASK(INT_WORLD_ACCESS) | \
+    INT_MASK(INT_I_ASID) | \
+    INT_MASK(INT_D_ASID) | \
+    INT_MASK(INT_DOUBLE_FAULT) | \
+    0)
+#define MASKABLE_INTERRUPTS ( \
+    INT_MASK(INT_MEM_ERROR) | \
+    INT_MASK(INT_SINGLE_STEP_3) | \
+    INT_MASK(INT_SINGLE_STEP_2) | \
+    INT_MASK(INT_SINGLE_STEP_1) | \
+    INT_MASK(INT_SINGLE_STEP_0) | \
+    INT_MASK(INT_IDN_COMPLETE) | \
+    INT_MASK(INT_UDN_COMPLETE) | \
+    INT_MASK(INT_IDN_FIREWALL) | \
+    INT_MASK(INT_UDN_FIREWALL) | \
+    INT_MASK(INT_TILE_TIMER) | \
+    INT_MASK(INT_AUX_TILE_TIMER) | \
+    INT_MASK(INT_IDN_TIMER) | \
+    INT_MASK(INT_UDN_TIMER) | \
+    INT_MASK(INT_IDN_AVAIL) | \
+    INT_MASK(INT_UDN_AVAIL) | \
+    INT_MASK(INT_IPI_3) | \
+    INT_MASK(INT_IPI_2) | \
+    INT_MASK(INT_IPI_1) | \
+    INT_MASK(INT_IPI_0) | \
+    INT_MASK(INT_PERF_COUNT) | \
+    INT_MASK(INT_AUX_PERF_COUNT) | \
+    INT_MASK(INT_INTCTRL_3) | \
+    INT_MASK(INT_INTCTRL_2) | \
+    INT_MASK(INT_INTCTRL_1) | \
+    INT_MASK(INT_INTCTRL_0) | \
+    0)
+#define UNMASKABLE_INTERRUPTS ( \
+    INT_MASK(INT_ITLB_MISS) | \
+    INT_MASK(INT_ILL) | \
+    INT_MASK(INT_GPV) | \
+    INT_MASK(INT_IDN_ACCESS) | \
+    INT_MASK(INT_UDN_ACCESS) | \
+    INT_MASK(INT_SWINT_3) | \
+    INT_MASK(INT_SWINT_2) | \
+    INT_MASK(INT_SWINT_1) | \
+    INT_MASK(INT_SWINT_0) | \
+    INT_MASK(INT_ILL_TRANS) | \
+    INT_MASK(INT_UNALIGN_DATA) | \
+    INT_MASK(INT_DTLB_MISS) | \
+    INT_MASK(INT_DTLB_ACCESS) | \
+    INT_MASK(INT_BOOT_ACCESS) | \
+    INT_MASK(INT_WORLD_ACCESS) | \
+    INT_MASK(INT_I_ASID) | \
+    INT_MASK(INT_D_ASID) | \
+    INT_MASK(INT_DOUBLE_FAULT) | \
+    0)
+#define SYNC_INTERRUPTS ( \
+    INT_MASK(INT_SINGLE_STEP_3) | \
+    INT_MASK(INT_SINGLE_STEP_2) | \
+    INT_MASK(INT_SINGLE_STEP_1) | \
+    INT_MASK(INT_SINGLE_STEP_0) | \
+    INT_MASK(INT_IDN_COMPLETE) | \
+    INT_MASK(INT_UDN_COMPLETE) | \
+    INT_MASK(INT_ITLB_MISS) | \
+    INT_MASK(INT_ILL) | \
+    INT_MASK(INT_GPV) | \
+    INT_MASK(INT_IDN_ACCESS) | \
+    INT_MASK(INT_UDN_ACCESS) | \
+    INT_MASK(INT_SWINT_3) | \
+    INT_MASK(INT_SWINT_2) | \
+    INT_MASK(INT_SWINT_1) | \
+    INT_MASK(INT_SWINT_0) | \
+    INT_MASK(INT_ILL_TRANS) | \
+    INT_MASK(INT_UNALIGN_DATA) | \
+    INT_MASK(INT_DTLB_MISS) | \
+    INT_MASK(INT_DTLB_ACCESS) | \
+    0)
+#define NON_SYNC_INTERRUPTS ( \
+    INT_MASK(INT_MEM_ERROR) | \
+    INT_MASK(INT_IDN_FIREWALL) | \
+    INT_MASK(INT_UDN_FIREWALL) | \
+    INT_MASK(INT_TILE_TIMER) | \
+    INT_MASK(INT_AUX_TILE_TIMER) | \
+    INT_MASK(INT_IDN_TIMER) | \
+    INT_MASK(INT_UDN_TIMER) | \
+    INT_MASK(INT_IDN_AVAIL) | \
+    INT_MASK(INT_UDN_AVAIL) | \
+    INT_MASK(INT_IPI_3) | \
+    INT_MASK(INT_IPI_2) | \
+    INT_MASK(INT_IPI_1) | \
+    INT_MASK(INT_IPI_0) | \
+    INT_MASK(INT_PERF_COUNT) | \
+    INT_MASK(INT_AUX_PERF_COUNT) | \
+    INT_MASK(INT_INTCTRL_3) | \
+    INT_MASK(INT_INTCTRL_2) | \
+    INT_MASK(INT_INTCTRL_1) | \
+    INT_MASK(INT_INTCTRL_0) | \
+    INT_MASK(INT_BOOT_ACCESS) | \
+    INT_MASK(INT_WORLD_ACCESS) | \
+    INT_MASK(INT_I_ASID) | \
+    INT_MASK(INT_D_ASID) | \
+    INT_MASK(INT_DOUBLE_FAULT) | \
+    0)
+#endif /* !__ASSEMBLER__ */
+#endif /* !__ARCH_INTERRUPTS_H__ */
index 442fcba0d12266db8ed8febd68c62a101a7b3ab6..f548efeb2de3f7fc005f90854a80d1b4941e3a98 100644 (file)
  *   more details.
  */
 
+/* Include the proper base SPR definition file. */
+#ifdef __tilegx__
+#include <arch/spr_def_64.h>
+#else
+#include <arch/spr_def_32.h>
+#endif
+
+#ifdef __KERNEL__
+
 /*
  * In addition to including the proper base SPR definition file, depending
  * on machine architecture, this file defines several macros which allow
@@ -29,7 +38,6 @@
 #define _concat4(a, b, c, d)  __concat4(a, b, c, d)
 
 #ifdef __tilegx__
-#include <arch/spr_def_64.h>
 
 /* TILE-Gx dependent, protection-level dependent SPRs. */
 
@@ -65,7 +73,6 @@
        _concat4(INT_SINGLE_STEP_, CONFIG_KERNEL_PL,,)
 
 #else
-#include <arch/spr_def_32.h>
 
 /* TILEPro dependent, protection-level dependent SPRs. */
 
        _concat4(SPR_INTCTRL_, CONFIG_KERNEL_PL, _STATUS,)
 #define INT_INTCTRL_K \
        _concat4(INT_INTCTRL_, CONFIG_KERNEL_PL,,)
+
+#endif /* __KERNEL__ */
diff --git a/arch/tile/include/arch/spr_def_64.h b/arch/tile/include/arch/spr_def_64.h
new file mode 100644 (file)
index 0000000..cd3e5f9
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#ifndef __DOXYGEN__
+
+#ifndef __ARCH_SPR_DEF_H__
+#define __ARCH_SPR_DEF_H__
+
+#define SPR_AUX_PERF_COUNT_0 0x2105
+#define SPR_AUX_PERF_COUNT_1 0x2106
+#define SPR_AUX_PERF_COUNT_CTL 0x2107
+#define SPR_AUX_PERF_COUNT_STS 0x2108
+#define SPR_CMPEXCH_VALUE 0x2780
+#define SPR_CYCLE 0x2781
+#define SPR_DONE 0x2705
+#define SPR_DSTREAM_PF 0x2706
+#define SPR_EVENT_BEGIN 0x2782
+#define SPR_EVENT_END 0x2783
+#define SPR_EX_CONTEXT_0_0 0x2580
+#define SPR_EX_CONTEXT_0_1 0x2581
+#define SPR_EX_CONTEXT_0_1__PL_SHIFT 0
+#define SPR_EX_CONTEXT_0_1__PL_RMASK 0x3
+#define SPR_EX_CONTEXT_0_1__PL_MASK  0x3
+#define SPR_EX_CONTEXT_0_1__ICS_SHIFT 2
+#define SPR_EX_CONTEXT_0_1__ICS_RMASK 0x1
+#define SPR_EX_CONTEXT_0_1__ICS_MASK  0x4
+#define SPR_EX_CONTEXT_1_0 0x2480
+#define SPR_EX_CONTEXT_1_1 0x2481
+#define SPR_EX_CONTEXT_1_1__PL_SHIFT 0
+#define SPR_EX_CONTEXT_1_1__PL_RMASK 0x3
+#define SPR_EX_CONTEXT_1_1__PL_MASK  0x3
+#define SPR_EX_CONTEXT_1_1__ICS_SHIFT 2
+#define SPR_EX_CONTEXT_1_1__ICS_RMASK 0x1
+#define SPR_EX_CONTEXT_1_1__ICS_MASK  0x4
+#define SPR_EX_CONTEXT_2_0 0x2380
+#define SPR_EX_CONTEXT_2_1 0x2381
+#define SPR_EX_CONTEXT_2_1__PL_SHIFT 0
+#define SPR_EX_CONTEXT_2_1__PL_RMASK 0x3
+#define SPR_EX_CONTEXT_2_1__PL_MASK  0x3
+#define SPR_EX_CONTEXT_2_1__ICS_SHIFT 2
+#define SPR_EX_CONTEXT_2_1__ICS_RMASK 0x1
+#define SPR_EX_CONTEXT_2_1__ICS_MASK  0x4
+#define SPR_FAIL 0x2707
+#define SPR_ILL_TRANS_REASON__I_STREAM_VA_RMASK 0x1
+#define SPR_INTCTRL_0_STATUS 0x2505
+#define SPR_INTCTRL_1_STATUS 0x2405
+#define SPR_INTCTRL_2_STATUS 0x2305
+#define SPR_INTERRUPT_CRITICAL_SECTION 0x2708
+#define SPR_INTERRUPT_MASK_0 0x2506
+#define SPR_INTERRUPT_MASK_1 0x2406
+#define SPR_INTERRUPT_MASK_2 0x2306
+#define SPR_INTERRUPT_MASK_RESET_0 0x2507
+#define SPR_INTERRUPT_MASK_RESET_1 0x2407
+#define SPR_INTERRUPT_MASK_RESET_2 0x2307
+#define SPR_INTERRUPT_MASK_SET_0 0x2508
+#define SPR_INTERRUPT_MASK_SET_1 0x2408
+#define SPR_INTERRUPT_MASK_SET_2 0x2308
+#define SPR_INTERRUPT_VECTOR_BASE_0 0x2509
+#define SPR_INTERRUPT_VECTOR_BASE_1 0x2409
+#define SPR_INTERRUPT_VECTOR_BASE_2 0x2309
+#define SPR_INTERRUPT_VECTOR_BASE_3 0x2209
+#define SPR_IPI_EVENT_0 0x1f05
+#define SPR_IPI_EVENT_1 0x1e05
+#define SPR_IPI_EVENT_2 0x1d05
+#define SPR_IPI_EVENT_RESET_0 0x1f06
+#define SPR_IPI_EVENT_RESET_1 0x1e06
+#define SPR_IPI_EVENT_RESET_2 0x1d06
+#define SPR_IPI_EVENT_SET_0 0x1f07
+#define SPR_IPI_EVENT_SET_1 0x1e07
+#define SPR_IPI_EVENT_SET_2 0x1d07
+#define SPR_IPI_MASK_0 0x1f08
+#define SPR_IPI_MASK_1 0x1e08
+#define SPR_IPI_MASK_2 0x1d08
+#define SPR_IPI_MASK_RESET_0 0x1f09
+#define SPR_IPI_MASK_RESET_1 0x1e09
+#define SPR_IPI_MASK_RESET_2 0x1d09
+#define SPR_IPI_MASK_SET_0 0x1f0a
+#define SPR_IPI_MASK_SET_1 0x1e0a
+#define SPR_IPI_MASK_SET_2 0x1d0a
+#define SPR_MPL_AUX_TILE_TIMER_SET_0 0x1700
+#define SPR_MPL_AUX_TILE_TIMER_SET_1 0x1701
+#define SPR_MPL_AUX_TILE_TIMER_SET_2 0x1702
+#define SPR_MPL_INTCTRL_0_SET_0 0x2500
+#define SPR_MPL_INTCTRL_0_SET_1 0x2501
+#define SPR_MPL_INTCTRL_0_SET_2 0x2502
+#define SPR_MPL_INTCTRL_1_SET_0 0x2400
+#define SPR_MPL_INTCTRL_1_SET_1 0x2401
+#define SPR_MPL_INTCTRL_1_SET_2 0x2402
+#define SPR_MPL_INTCTRL_2_SET_0 0x2300
+#define SPR_MPL_INTCTRL_2_SET_1 0x2301
+#define SPR_MPL_INTCTRL_2_SET_2 0x2302
+#define SPR_MPL_UDN_ACCESS_SET_0 0x0b00
+#define SPR_MPL_UDN_ACCESS_SET_1 0x0b01
+#define SPR_MPL_UDN_ACCESS_SET_2 0x0b02
+#define SPR_MPL_UDN_AVAIL_SET_0 0x1b00
+#define SPR_MPL_UDN_AVAIL_SET_1 0x1b01
+#define SPR_MPL_UDN_AVAIL_SET_2 0x1b02
+#define SPR_MPL_UDN_COMPLETE_SET_0 0x0600
+#define SPR_MPL_UDN_COMPLETE_SET_1 0x0601
+#define SPR_MPL_UDN_COMPLETE_SET_2 0x0602
+#define SPR_MPL_UDN_FIREWALL_SET_0 0x1500
+#define SPR_MPL_UDN_FIREWALL_SET_1 0x1501
+#define SPR_MPL_UDN_FIREWALL_SET_2 0x1502
+#define SPR_MPL_UDN_TIMER_SET_0 0x1900
+#define SPR_MPL_UDN_TIMER_SET_1 0x1901
+#define SPR_MPL_UDN_TIMER_SET_2 0x1902
+#define SPR_MPL_WORLD_ACCESS_SET_0 0x2700
+#define SPR_MPL_WORLD_ACCESS_SET_1 0x2701
+#define SPR_MPL_WORLD_ACCESS_SET_2 0x2702
+#define SPR_PASS 0x2709
+#define SPR_PERF_COUNT_0 0x2005
+#define SPR_PERF_COUNT_1 0x2006
+#define SPR_PERF_COUNT_CTL 0x2007
+#define SPR_PERF_COUNT_DN_CTL 0x2008
+#define SPR_PERF_COUNT_STS 0x2009
+#define SPR_PROC_STATUS 0x2784
+#define SPR_SIM_CONTROL 0x2785
+#define SPR_SINGLE_STEP_CONTROL_0 0x0405
+#define SPR_SINGLE_STEP_CONTROL_0__CANCELED_MASK  0x1
+#define SPR_SINGLE_STEP_CONTROL_0__INHIBIT_MASK  0x2
+#define SPR_SINGLE_STEP_CONTROL_1 0x0305
+#define SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK  0x1
+#define SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK  0x2
+#define SPR_SINGLE_STEP_CONTROL_2 0x0205
+#define SPR_SINGLE_STEP_CONTROL_2__CANCELED_MASK  0x1
+#define SPR_SINGLE_STEP_CONTROL_2__INHIBIT_MASK  0x2
+#define SPR_SINGLE_STEP_EN_0_0 0x250a
+#define SPR_SINGLE_STEP_EN_0_1 0x240a
+#define SPR_SINGLE_STEP_EN_0_2 0x230a
+#define SPR_SINGLE_STEP_EN_1_0 0x250b
+#define SPR_SINGLE_STEP_EN_1_1 0x240b
+#define SPR_SINGLE_STEP_EN_1_2 0x230b
+#define SPR_SINGLE_STEP_EN_2_0 0x250c
+#define SPR_SINGLE_STEP_EN_2_1 0x240c
+#define SPR_SINGLE_STEP_EN_2_2 0x230c
+#define SPR_SYSTEM_SAVE_0_0 0x2582
+#define SPR_SYSTEM_SAVE_0_1 0x2583
+#define SPR_SYSTEM_SAVE_0_2 0x2584
+#define SPR_SYSTEM_SAVE_0_3 0x2585
+#define SPR_SYSTEM_SAVE_1_0 0x2482
+#define SPR_SYSTEM_SAVE_1_1 0x2483
+#define SPR_SYSTEM_SAVE_1_2 0x2484
+#define SPR_SYSTEM_SAVE_1_3 0x2485
+#define SPR_SYSTEM_SAVE_2_0 0x2382
+#define SPR_SYSTEM_SAVE_2_1 0x2383
+#define SPR_SYSTEM_SAVE_2_2 0x2384
+#define SPR_SYSTEM_SAVE_2_3 0x2385
+#define SPR_TILE_COORD 0x270b
+#define SPR_TILE_RTF_HWM 0x270c
+#define SPR_TILE_TIMER_CONTROL 0x1605
+#define SPR_UDN_AVAIL_EN 0x1b05
+#define SPR_UDN_DATA_AVAIL 0x0b80
+#define SPR_UDN_DEADLOCK_TIMEOUT 0x1906
+#define SPR_UDN_DEMUX_COUNT_0 0x0b05
+#define SPR_UDN_DEMUX_COUNT_1 0x0b06
+#define SPR_UDN_DEMUX_COUNT_2 0x0b07
+#define SPR_UDN_DEMUX_COUNT_3 0x0b08
+#define SPR_UDN_DIRECTION_PROTECT 0x1505
+
+#endif /* !defined(__ARCH_SPR_DEF_H__) */
+
+#endif /* !defined(__DOXYGEN__) */
index 75a16028a95294ebfb67fbcca5e3c0b404a57bcb..739cfe0499d1da5e682f342e0c2ade78d8905e00 100644 (file)
@@ -130,17 +130,52 @@ static inline int atomic_read(const atomic_t *v)
  */
 #define atomic_inc_not_zero(v)         atomic_add_unless((v), 1, 0)
 
-
-/*
- * We define xchg() and cmpxchg() in the included headers.
- * Note that we do not define __HAVE_ARCH_CMPXCHG, since that would imply
- * that cmpxchg() is an efficient operation, which is not particularly true.
- */
-
 /* Nonexistent functions intended to cause link errors. */
 extern unsigned long __xchg_called_with_bad_pointer(void);
 extern unsigned long __cmpxchg_called_with_bad_pointer(void);
 
+#define xchg(ptr, x)                                                   \
+       ({                                                              \
+               typeof(*(ptr)) __x;                                     \
+               switch (sizeof(*(ptr))) {                               \
+               case 4:                                                 \
+                       __x = (typeof(__x))(typeof(__x-__x))atomic_xchg( \
+                               (atomic_t *)(ptr),                      \
+                               (u32)(typeof((x)-(x)))(x));             \
+                       break;                                          \
+               case 8:                                                 \
+                       __x = (typeof(__x))(typeof(__x-__x))atomic64_xchg( \
+                               (atomic64_t *)(ptr),                    \
+                               (u64)(typeof((x)-(x)))(x));             \
+                       break;                                          \
+               default:                                                \
+                       __xchg_called_with_bad_pointer();               \
+               }                                                       \
+               __x;                                                    \
+       })
+
+#define cmpxchg(ptr, o, n)                                             \
+       ({                                                              \
+               typeof(*(ptr)) __x;                                     \
+               switch (sizeof(*(ptr))) {                               \
+               case 4:                                                 \
+                       __x = (typeof(__x))(typeof(__x-__x))atomic_cmpxchg( \
+                               (atomic_t *)(ptr),                      \
+                               (u32)(typeof((o)-(o)))(o),              \
+                               (u32)(typeof((n)-(n)))(n));             \
+                       break;                                          \
+               case 8:                                                 \
+                       __x = (typeof(__x))(typeof(__x-__x))atomic64_cmpxchg( \
+                               (atomic64_t *)(ptr),                    \
+                               (u64)(typeof((o)-(o)))(o),              \
+                               (u64)(typeof((n)-(n)))(n));             \
+                       break;                                          \
+               default:                                                \
+                       __cmpxchg_called_with_bad_pointer();            \
+               }                                                       \
+               __x;                                                    \
+       })
+
 #define tas(ptr) (xchg((ptr), 1))
 
 #endif /* __ASSEMBLY__ */
index ed359aee88375f1d5257ac6d21fbebe84d7a350c..92a8bee323113520374d917155c7be3dcc358726 100644 (file)
@@ -110,16 +110,6 @@ static inline void atomic_set(atomic_t *v, int n)
        _atomic_xchg(v, n);
 }
 
-#define xchg(ptr, x) ((typeof(*(ptr))) \
-  ((sizeof(*(ptr)) == sizeof(atomic_t)) ? \
-   atomic_xchg((atomic_t *)(ptr), (long)(x)) : \
-   __xchg_called_with_bad_pointer()))
-
-#define cmpxchg(ptr, o, n) ((typeof(*(ptr))) \
-  ((sizeof(*(ptr)) == sizeof(atomic_t)) ? \
-   atomic_cmpxchg((atomic_t *)(ptr), (long)(o), (long)(n)) : \
-   __cmpxchg_called_with_bad_pointer()))
-
 /* A 64bit atomic type */
 
 typedef struct {
diff --git a/arch/tile/include/asm/atomic_64.h b/arch/tile/include/asm/atomic_64.h
new file mode 100644 (file)
index 0000000..1c1e60d
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * Do not include directly; use <asm/atomic.h>.
+ */
+
+#ifndef _ASM_TILE_ATOMIC_64_H
+#define _ASM_TILE_ATOMIC_64_H
+
+#ifndef __ASSEMBLY__
+
+#include <arch/spr_def.h>
+
+/* First, the 32-bit atomic ops that are "real" on our 64-bit platform. */
+
+#define atomic_set(v, i) ((v)->counter = (i))
+
+/*
+ * The smp_mb() operations throughout are to support the fact that
+ * Linux requires memory barriers before and after the operation,
+ * on any routine which updates memory and returns a value.
+ */
+
+static inline int atomic_cmpxchg(atomic_t *v, int o, int n)
+{
+       int val;
+       __insn_mtspr(SPR_CMPEXCH_VALUE, o);
+       smp_mb();  /* barrier for proper semantics */
+       val = __insn_cmpexch4((void *)&v->counter, n);
+       smp_mb();  /* barrier for proper semantics */
+       return val;
+}
+
+static inline int atomic_xchg(atomic_t *v, int n)
+{
+       int val;
+       smp_mb();  /* barrier for proper semantics */
+       val = __insn_exch4((void *)&v->counter, n);
+       smp_mb();  /* barrier for proper semantics */
+       return val;
+}
+
+static inline void atomic_add(int i, atomic_t *v)
+{
+       __insn_fetchadd4((void *)&v->counter, i);
+}
+
+static inline int atomic_add_return(int i, atomic_t *v)
+{
+       int val;
+       smp_mb();  /* barrier for proper semantics */
+       val = __insn_fetchadd4((void *)&v->counter, i) + i;
+       barrier();  /* the "+ i" above will wait on memory */
+       return val;
+}
+
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+       int guess, oldval = v->counter;
+       do {
+               if (oldval == u)
+                       break;
+               guess = oldval;
+               oldval = atomic_cmpxchg(v, guess, guess + a);
+       } while (guess != oldval);
+       return oldval != u;
+}
+
+/* Now the true 64-bit operations. */
+
+#define ATOMIC64_INIT(i)       { (i) }
+
+#define atomic64_read(v)               ((v)->counter)
+#define atomic64_set(v, i) ((v)->counter = (i))
+
+static inline long atomic64_cmpxchg(atomic64_t *v, long o, long n)
+{
+       long val;
+       smp_mb();  /* barrier for proper semantics */
+       __insn_mtspr(SPR_CMPEXCH_VALUE, o);
+       val = __insn_cmpexch((void *)&v->counter, n);
+       smp_mb();  /* barrier for proper semantics */
+       return val;
+}
+
+static inline long atomic64_xchg(atomic64_t *v, long n)
+{
+       long val;
+       smp_mb();  /* barrier for proper semantics */
+       val = __insn_exch((void *)&v->counter, n);
+       smp_mb();  /* barrier for proper semantics */
+       return val;
+}
+
+static inline void atomic64_add(long i, atomic64_t *v)
+{
+       __insn_fetchadd((void *)&v->counter, i);
+}
+
+static inline long atomic64_add_return(long i, atomic64_t *v)
+{
+       int val;
+       smp_mb();  /* barrier for proper semantics */
+       val = __insn_fetchadd((void *)&v->counter, i) + i;
+       barrier();  /* the "+ i" above will wait on memory */
+       return val;
+}
+
+static inline long atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+       long guess, oldval = v->counter;
+       do {
+               if (oldval == u)
+                       break;
+               guess = oldval;
+               oldval = atomic64_cmpxchg(v, guess, guess + a);
+       } while (guess != oldval);
+       return oldval != u;
+}
+
+#define atomic64_sub_return(i, v)      atomic64_add_return(-(i), (v))
+#define atomic64_sub(i, v)             atomic64_add(-(i), (v))
+#define atomic64_inc_return(v)         atomic64_add_return(1, (v))
+#define atomic64_dec_return(v)         atomic64_sub_return(1, (v))
+#define atomic64_inc(v)                        atomic64_add(1, (v))
+#define atomic64_dec(v)                        atomic64_sub(1, (v))
+
+#define atomic64_inc_and_test(v)       (atomic64_inc_return(v) == 0)
+#define atomic64_dec_and_test(v)       (atomic64_dec_return(v) == 0)
+#define atomic64_sub_and_test(i, v)    (atomic64_sub_return((i), (v)) == 0)
+#define atomic64_add_negative(i, v)    (atomic64_add_return((i), (v)) < 0)
+
+#define atomic64_inc_not_zero(v)       atomic64_add_unless((v), 1, 0)
+
+/* Atomic dec and inc don't implement barrier, so provide them if needed. */
+#define smp_mb__before_atomic_dec()    smp_mb()
+#define smp_mb__after_atomic_dec()     smp_mb()
+#define smp_mb__before_atomic_inc()    smp_mb()
+#define smp_mb__after_atomic_inc()     smp_mb()
+
+/* Define this to indicate that cmpxchg is an efficient operation. */
+#define __HAVE_ARCH_CMPXCHG
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_TILE_ATOMIC_64_H */
index f18887d823999f8a7778defa2196ab10b586b81d..bd5399a69edf011bf23b4e51a9828b772f8de3cd 100644 (file)
  *   more details.
  */
 
-#ifndef _TILE_BACKTRACE_H
-#define _TILE_BACKTRACE_H
-
-
+#ifndef _ASM_TILE_BACKTRACE_H
+#define _ASM_TILE_BACKTRACE_H
 
 #include <linux/types.h>
 
-#include <arch/chip.h>
-
-#if defined(__tile__)
-typedef unsigned long VirtualAddress;
-#elif CHIP_VA_WIDTH() > 32
-typedef unsigned long long VirtualAddress;
-#else
-typedef unsigned int VirtualAddress;
-#endif
-
-
-/** Reads 'size' bytes from 'address' and writes the data to 'result'.
+/* Reads 'size' bytes from 'address' and writes the data to 'result'.
  * Returns true if successful, else false (e.g. memory not readable).
  */
 typedef bool (*BacktraceMemoryReader)(void *result,
-                                     VirtualAddress address,
+                                     unsigned long address,
                                      unsigned int size,
                                      void *extra);
 
 typedef struct {
-       /** Current PC. */
-       VirtualAddress pc;
+       /* Current PC. */
+       unsigned long pc;
 
-       /** Current stack pointer value. */
-       VirtualAddress sp;
+       /* Current stack pointer value. */
+       unsigned long sp;
 
-       /** Current frame pointer value (i.e. caller's stack pointer) */
-       VirtualAddress fp;
+       /* Current frame pointer value (i.e. caller's stack pointer) */
+       unsigned long fp;
 
-       /** Internal use only: caller's PC for first frame. */
-       VirtualAddress initial_frame_caller_pc;
+       /* Internal use only: caller's PC for first frame. */
+       unsigned long initial_frame_caller_pc;
 
-       /** Internal use only: callback to read memory. */
+       /* Internal use only: callback to read memory. */
        BacktraceMemoryReader read_memory_func;
 
-       /** Internal use only: arbitrary argument to read_memory_func. */
+       /* Internal use only: arbitrary argument to read_memory_func. */
        void *read_memory_func_extra;
 
 } BacktraceIterator;
 
 
-/** Initializes a backtracer to start from the given location.
- *
- * If the frame pointer cannot be determined it is set to -1.
- *
- * @param state The state to be filled in.
- * @param read_memory_func A callback that reads memory. If NULL, a default
- *        value is provided.
- * @param read_memory_func_extra An arbitrary argument to read_memory_func.
- * @param pc The current PC.
- * @param lr The current value of the 'lr' register.
- * @param sp The current value of the 'sp' register.
- * @param r52 The current value of the 'r52' register.
- */
-extern void backtrace_init(BacktraceIterator *state,
-                          BacktraceMemoryReader read_memory_func,
-                          void *read_memory_func_extra,
-                          VirtualAddress pc, VirtualAddress lr,
-                          VirtualAddress sp, VirtualAddress r52);
-
-
-/** Advances the backtracing state to the calling frame, returning
- * true iff successful.
- */
-extern bool backtrace_next(BacktraceIterator *state);
-
-
 typedef enum {
 
        /* We have no idea what the caller's pc is. */
@@ -138,7 +99,7 @@ enum {
 };
 
 
-/** Internal constants used to define 'info' operands. */
+/* Internal constants used to define 'info' operands. */
 enum {
        /* 0 and 1 are reserved, as are all negative numbers. */
 
@@ -147,13 +108,10 @@ enum {
        CALLER_SP_IN_R52_BASE = 4,
 
        CALLER_SP_OFFSET_BASE = 8,
-
-       /* Marks the entry point of certain functions. */
-       ENTRY_POINT_INFO_OP = 16
 };
 
 
-/** Current backtracer state describing where it thinks the caller is. */
+/* Current backtracer state describing where it thinks the caller is. */
 typedef struct {
        /*
         * Public fields
@@ -192,7 +150,13 @@ typedef struct {
 
 } CallerLocation;
 
+extern void backtrace_init(BacktraceIterator *state,
+                          BacktraceMemoryReader read_memory_func,
+                          void *read_memory_func_extra,
+                          unsigned long pc, unsigned long lr,
+                          unsigned long sp, unsigned long r52);
 
 
+extern bool backtrace_next(BacktraceIterator *state);
 
-#endif /* _TILE_BACKTRACE_H */
+#endif /* _ASM_TILE_BACKTRACE_H */
index 132e6bbd07e911e02f6abba5586db0c6d7d9456a..16f1fa51fea13de4139c5a18c2d10088b8e395c1 100644 (file)
@@ -122,6 +122,7 @@ static inline unsigned long __arch_hweight64(__u64 w)
 #include <asm-generic/bitops/lock.h>
 #include <asm-generic/bitops/find.h>
 #include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/non-atomic.h>
 #include <asm-generic/bitops/le.h>
 
 #endif /* _ASM_TILE_BITOPS_H */
index 2638be51a16438989987a20146584879bd06ae76..d31ab905cfa7105b4ba32bcc03db55c8e0a74be1 100644 (file)
@@ -126,7 +126,6 @@ static inline int test_and_change_bit(unsigned nr,
 #define smp_mb__before_clear_bit()     smp_mb()
 #define smp_mb__after_clear_bit()      do {} while (0)
 
-#include <asm-generic/bitops/non-atomic.h>
 #include <asm-generic/bitops/ext2-atomic.h>
 
 #endif /* _ASM_TILE_BITOPS_32_H */
diff --git a/arch/tile/include/asm/bitops_64.h b/arch/tile/include/asm/bitops_64.h
new file mode 100644 (file)
index 0000000..99615e8
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#ifndef _ASM_TILE_BITOPS_64_H
+#define _ASM_TILE_BITOPS_64_H
+
+#include <linux/compiler.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+
+/* See <asm/bitops.h> for API comments. */
+
+static inline void set_bit(unsigned nr, volatile unsigned long *addr)
+{
+       unsigned long mask = (1UL << (nr % BITS_PER_LONG));
+       __insn_fetchor((void *)(addr + nr / BITS_PER_LONG), mask);
+}
+
+static inline void clear_bit(unsigned nr, volatile unsigned long *addr)
+{
+       unsigned long mask = (1UL << (nr % BITS_PER_LONG));
+       __insn_fetchand((void *)(addr + nr / BITS_PER_LONG), ~mask);
+}
+
+#define smp_mb__before_clear_bit()     smp_mb()
+#define smp_mb__after_clear_bit()      smp_mb()
+
+
+static inline void change_bit(unsigned nr, volatile unsigned long *addr)
+{
+       unsigned long old, mask = (1UL << (nr % BITS_PER_LONG));
+       long guess, oldval;
+       addr += nr / BITS_PER_LONG;
+       old = *addr;
+       do {
+               guess = oldval;
+               oldval = atomic64_cmpxchg((atomic64_t *)addr,
+                                         guess, guess ^ mask);
+       } while (guess != oldval);
+}
+
+
+/*
+ * The test_and_xxx_bit() routines require a memory fence before we
+ * start the operation, and after the operation completes.  We use
+ * smp_mb() before, and rely on the "!= 0" comparison, plus a compiler
+ * barrier(), to block until the atomic op is complete.
+ */
+
+static inline int test_and_set_bit(unsigned nr, volatile unsigned long *addr)
+{
+       int val;
+       unsigned long mask = (1UL << (nr % BITS_PER_LONG));
+       smp_mb();  /* barrier for proper semantics */
+       val = (__insn_fetchor((void *)(addr + nr / BITS_PER_LONG), mask)
+              & mask) != 0;
+       barrier();
+       return val;
+}
+
+
+static inline int test_and_clear_bit(unsigned nr, volatile unsigned long *addr)
+{
+       int val;
+       unsigned long mask = (1UL << (nr % BITS_PER_LONG));
+       smp_mb();  /* barrier for proper semantics */
+       val = (__insn_fetchand((void *)(addr + nr / BITS_PER_LONG), ~mask)
+              & mask) != 0;
+       barrier();
+       return val;
+}
+
+
+static inline int test_and_change_bit(unsigned nr,
+                                     volatile unsigned long *addr)
+{
+       unsigned long mask = (1UL << (nr % BITS_PER_LONG));
+       long guess, oldval = *addr;
+       addr += nr / BITS_PER_LONG;
+       oldval = *addr;
+       do {
+               guess = oldval;
+               oldval = atomic64_cmpxchg((atomic64_t *)addr,
+                                         guess, guess ^ mask);
+       } while (guess != oldval);
+       return (oldval & mask) != 0;
+}
+
+#define ext2_set_bit_atomic(lock, nr, addr)                    \
+       test_and_set_bit((nr), (unsigned long *)(addr))
+#define ext2_clear_bit_atomic(lock, nr, addr)                  \
+       test_and_clear_bit((nr), (unsigned long *)(addr))
+
+#endif /* _ASM_TILE_BITOPS_64_H */
index 12fb0fb330ee95895360a5ddc4287e3efc0917d2..e925f4bb498f40f93b1ffe6a04390f9732c2ffdb 100644 (file)
@@ -116,22 +116,28 @@ static inline void __finv_buffer(void *buffer, size_t size)
 }
 
 
-/* Invalidate a VA range, then memory fence. */
+/* Invalidate a VA range and wait for it to be complete. */
 static inline void inv_buffer(void *buffer, size_t size)
 {
        __inv_buffer(buffer, size);
-       mb_incoherent();
+       mb();
 }
 
-/* Flush a VA range, then memory fence. */
-static inline void flush_buffer(void *buffer, size_t size)
+/*
+ * Flush a locally-homecached VA range and wait for the evicted
+ * cachelines to hit memory.
+ */
+static inline void flush_buffer_local(void *buffer, size_t size)
 {
        __flush_buffer(buffer, size);
        mb_incoherent();
 }
 
-/* Flush & invalidate a VA range, then memory fence. */
-static inline void finv_buffer(void *buffer, size_t size)
+/*
+ * Flush and invalidate a locally-homecached VA range and wait for the
+ * evicted cachelines to hit memory.
+ */
+static inline void finv_buffer_local(void *buffer, size_t size)
 {
        __finv_buffer(buffer, size);
        mb_incoherent();
index c3ae570c0a5d9ef209970d6d00a388a3128e550a..bf95f55b82b04e77c0e93ac8e28391c820ecaa08 100644 (file)
@@ -215,8 +215,8 @@ struct compat_sigaction;
 struct compat_siginfo;
 struct compat_sigaltstack;
 long compat_sys_execve(const char __user *path,
-                      const compat_uptr_t __user *argv,
-                      const compat_uptr_t __user *envp, struct pt_regs *);
+                      compat_uptr_t __user *argv,
+                      compat_uptr_t __user *envp, struct pt_regs *);
 long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act,
                             struct compat_sigaction __user *oact,
                             size_t sigsetsize);
index 15e1dceecc646186d21a95eebf372ab5cc9f42cb..eaa06d175b39d3af86d91f2761058ffb6fc1fc27 100644 (file)
@@ -65,7 +65,8 @@ extern void dma_sync_single_range_for_cpu(struct device *, dma_addr_t,
 extern void dma_sync_single_range_for_device(struct device *, dma_addr_t,
                                             unsigned long offset, size_t,
                                             enum dma_data_direction);
-extern void dma_cache_sync(void *vaddr, size_t, enum dma_data_direction);
+extern void dma_cache_sync(struct device *dev, void *vaddr, size_t,
+                          enum dma_data_direction);
 
 static inline int
 dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
diff --git a/arch/tile/include/asm/fb.h b/arch/tile/include/asm/fb.h
new file mode 100644 (file)
index 0000000..3a4988e
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/fb.h>
index 0bed3ec7b42ccd7ba5f6f0b212bc278b37c568d7..2ac422848c7d2ee8b0125c60f2848799f53bf57c 100644 (file)
 #define HARDWALL_DEACTIVATE \
  _IO(HARDWALL_IOCTL_BASE, _HARDWALL_DEACTIVATE)
 
+#define _HARDWALL_GET_ID 4
+#define HARDWALL_GET_ID \
+ _IO(HARDWALL_IOCTL_BASE, _HARDWALL_GET_ID)
+
 #ifndef __KERNEL__
 
 /* This is the canonical name expected by userspace. */
 
 #else
 
-/* Hook for /proc/tile/hardwall. */
-struct seq_file;
-int proc_tile_hardwall_show(struct seq_file *sf, void *v);
+/* /proc hooks for hardwall. */
+struct proc_dir_entry;
+#ifdef CONFIG_HARDWALL
+void proc_tile_hardwall_init(struct proc_dir_entry *root);
+int proc_pid_hardwall(struct task_struct *task, char *buffer);
+#else
+static inline void proc_tile_hardwall_init(struct proc_dir_entry *root) {}
+#endif
 
 #endif
 
index d3cbb9b14cbe4b7950575c46b6f8b34312f42a78..c9ea1652af03c609f355ec12c456a45e0dd826f3 100644 (file)
@@ -52,6 +52,7 @@ extern void iounmap(volatile void __iomem *addr);
 #endif
 
 #define ioremap_nocache(physaddr, size)                ioremap(physaddr, size)
+#define ioremap_wc(physaddr, size)             ioremap(physaddr, size)
 #define ioremap_writethrough(physaddr, size)   ioremap(physaddr, size)
 #define ioremap_fullcache(physaddr, size)      ioremap(physaddr, size)
 
@@ -161,6 +162,15 @@ static inline void _tile_writeq(u64 val, unsigned long addr)
 #define iowrite32 writel
 #define iowrite64 writeq
 
+static inline void memset_io(void *dst, int val, size_t len)
+{
+       int x;
+       BUG_ON((unsigned long)dst & 0x3);
+       val = (val & 0xff) * 0x01010101;
+       for (x = 0; x < len; x += 4)
+               writel(val, dst + x);
+}
+
 static inline void memcpy_fromio(void *dst, const volatile void __iomem *src,
                                 size_t len)
 {
@@ -269,6 +279,11 @@ static inline void outsl(unsigned long addr, const void *buffer, int count)
        ioport_panic();
 }
 
+#define ioread16be(addr)       be16_to_cpu(ioread16(addr))
+#define ioread32be(addr)       be32_to_cpu(ioread32(addr))
+#define iowrite16be(v, addr)   iowrite16(be16_to_cpu(v), (addr))
+#define iowrite32be(v, addr)   iowrite32(be32_to_cpu(v), (addr))
+
 #define ioread8_rep(p, dst, count) \
        insb((unsigned long) (p), (dst), (count))
 #define ioread16_rep(p, dst, count) \
@@ -283,4 +298,7 @@ static inline void outsl(unsigned long addr, const void *buffer, int count)
 #define iowrite32_rep(p, src, count) \
        outsl((unsigned long) (p), (src), (count))
 
+#define virt_to_bus     virt_to_phys
+#define bus_to_virt     phys_to_virt
+
 #endif /* _ASM_TILE_IO_H */
index 572fd3ef1d7314daf51ee058376b75446649c076..94e9a511de849c925bcf28841368ce278feade0c 100644 (file)
@@ -23,6 +23,8 @@
 /* IRQ numbers used for linux IPIs. */
 #define IRQ_RESCHEDULE 1
 
+#define irq_canonicalize(irq)   (irq)
+
 void ack_bad_irq(unsigned int irq);
 
 /*
index 9bc0d0725c28da6ce73f026784dea406609adb88..15fb246411202d1ba1547a07132ff6bf2198f8fd 100644 (file)
@@ -100,8 +100,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                __get_cpu_var(current_asid) = asid;
 
                /* Clear cpu from the old mm, and set it in the new one. */
-               cpumask_clear_cpu(cpu, &prev->cpu_vm_mask);
-               cpumask_set_cpu(cpu, &next->cpu_vm_mask);
+               cpumask_clear_cpu(cpu, mm_cpumask(prev));
+               cpumask_set_cpu(cpu, mm_cpumask(next));
 
                /* Re-load page tables */
                install_page_table(next->pgd, asid);
index eda60ecbae3d5f924e42a56dea5bcbfc51ff4252..03df7b1e77bfef861fee0171c4d205bada39a414 100644 (file)
@@ -1502,5 +1502,12 @@ extern int parse_insn_tile(tile_bundle_bits bits,
                            decoded[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]);
 
 
+/* Given a set of bundle bits and a specific pipe, returns which
+ * instruction the bundle contains in that pipe.
+ */
+extern const struct tile_opcode *
+find_opcode(tile_bundle_bits bits, tile_pipeline pipe);
+
+
 
 #endif /* opcode_tile_h */
index eda60ecbae3d5f924e42a56dea5bcbfc51ff4252..c0633466cd5ce49c9739c953268fea79ffcee559 100644 (file)
 #ifndef opcode_tile_h
 #define opcode_tile_h
 
-typedef unsigned long long tile_bundle_bits;
+typedef unsigned long long tilegx_bundle_bits;
 
 
 enum
 {
-  TILE_MAX_OPERANDS = 5 /* mm */
+  TILEGX_MAX_OPERANDS = 4 /* bfexts */
 };
 
 typedef enum
 {
-  TILE_OPC_BPT,
-  TILE_OPC_INFO,
-  TILE_OPC_INFOL,
-  TILE_OPC_J,
-  TILE_OPC_JAL,
-  TILE_OPC_MOVE,
-  TILE_OPC_MOVE_SN,
-  TILE_OPC_MOVEI,
-  TILE_OPC_MOVEI_SN,
-  TILE_OPC_MOVELI,
-  TILE_OPC_MOVELI_SN,
-  TILE_OPC_MOVELIS,
-  TILE_OPC_PREFETCH,
-  TILE_OPC_RAISE,
-  TILE_OPC_ADD,
-  TILE_OPC_ADD_SN,
-  TILE_OPC_ADDB,
-  TILE_OPC_ADDB_SN,
-  TILE_OPC_ADDBS_U,
-  TILE_OPC_ADDBS_U_SN,
-  TILE_OPC_ADDH,
-  TILE_OPC_ADDH_SN,
-  TILE_OPC_ADDHS,
-  TILE_OPC_ADDHS_SN,
-  TILE_OPC_ADDI,
-  TILE_OPC_ADDI_SN,
-  TILE_OPC_ADDIB,
-  TILE_OPC_ADDIB_SN,
-  TILE_OPC_ADDIH,
-  TILE_OPC_ADDIH_SN,
-  TILE_OPC_ADDLI,
-  TILE_OPC_ADDLI_SN,
-  TILE_OPC_ADDLIS,
-  TILE_OPC_ADDS,
-  TILE_OPC_ADDS_SN,
-  TILE_OPC_ADIFFB_U,
-  TILE_OPC_ADIFFB_U_SN,
-  TILE_OPC_ADIFFH,
-  TILE_OPC_ADIFFH_SN,
-  TILE_OPC_AND,
-  TILE_OPC_AND_SN,
-  TILE_OPC_ANDI,
-  TILE_OPC_ANDI_SN,
-  TILE_OPC_AULI,
-  TILE_OPC_AVGB_U,
-  TILE_OPC_AVGB_U_SN,
-  TILE_OPC_AVGH,
-  TILE_OPC_AVGH_SN,
-  TILE_OPC_BBNS,
-  TILE_OPC_BBNS_SN,
-  TILE_OPC_BBNST,
-  TILE_OPC_BBNST_SN,
-  TILE_OPC_BBS,
-  TILE_OPC_BBS_SN,
-  TILE_OPC_BBST,
-  TILE_OPC_BBST_SN,
-  TILE_OPC_BGEZ,
-  TILE_OPC_BGEZ_SN,
-  TILE_OPC_BGEZT,
-  TILE_OPC_BGEZT_SN,
-  TILE_OPC_BGZ,
-  TILE_OPC_BGZ_SN,
-  TILE_OPC_BGZT,
-  TILE_OPC_BGZT_SN,
-  TILE_OPC_BITX,
-  TILE_OPC_BITX_SN,
-  TILE_OPC_BLEZ,
-  TILE_OPC_BLEZ_SN,
-  TILE_OPC_BLEZT,
-  TILE_OPC_BLEZT_SN,
-  TILE_OPC_BLZ,
-  TILE_OPC_BLZ_SN,
-  TILE_OPC_BLZT,
-  TILE_OPC_BLZT_SN,
-  TILE_OPC_BNZ,
-  TILE_OPC_BNZ_SN,
-  TILE_OPC_BNZT,
-  TILE_OPC_BNZT_SN,
-  TILE_OPC_BYTEX,
-  TILE_OPC_BYTEX_SN,
-  TILE_OPC_BZ,
-  TILE_OPC_BZ_SN,
-  TILE_OPC_BZT,
-  TILE_OPC_BZT_SN,
-  TILE_OPC_CLZ,
-  TILE_OPC_CLZ_SN,
-  TILE_OPC_CRC32_32,
-  TILE_OPC_CRC32_32_SN,
-  TILE_OPC_CRC32_8,
-  TILE_OPC_CRC32_8_SN,
-  TILE_OPC_CTZ,
-  TILE_OPC_CTZ_SN,
-  TILE_OPC_DRAIN,
-  TILE_OPC_DTLBPR,
-  TILE_OPC_DWORD_ALIGN,
-  TILE_OPC_DWORD_ALIGN_SN,
-  TILE_OPC_FINV,
-  TILE_OPC_FLUSH,
-  TILE_OPC_FNOP,
-  TILE_OPC_ICOH,
-  TILE_OPC_ILL,
-  TILE_OPC_INTHB,
-  TILE_OPC_INTHB_SN,
-  TILE_OPC_INTHH,
-  TILE_OPC_INTHH_SN,
-  TILE_OPC_INTLB,
-  TILE_OPC_INTLB_SN,
-  TILE_OPC_INTLH,
-  TILE_OPC_INTLH_SN,
-  TILE_OPC_INV,
-  TILE_OPC_IRET,
-  TILE_OPC_JALB,
-  TILE_OPC_JALF,
-  TILE_OPC_JALR,
-  TILE_OPC_JALRP,
-  TILE_OPC_JB,
-  TILE_OPC_JF,
-  TILE_OPC_JR,
-  TILE_OPC_JRP,
-  TILE_OPC_LB,
-  TILE_OPC_LB_SN,
-  TILE_OPC_LB_U,
-  TILE_OPC_LB_U_SN,
-  TILE_OPC_LBADD,
-  TILE_OPC_LBADD_SN,
-  TILE_OPC_LBADD_U,
-  TILE_OPC_LBADD_U_SN,
-  TILE_OPC_LH,
-  TILE_OPC_LH_SN,
-  TILE_OPC_LH_U,
-  TILE_OPC_LH_U_SN,
-  TILE_OPC_LHADD,
-  TILE_OPC_LHADD_SN,
-  TILE_OPC_LHADD_U,
-  TILE_OPC_LHADD_U_SN,
-  TILE_OPC_LNK,
-  TILE_OPC_LNK_SN,
-  TILE_OPC_LW,
-  TILE_OPC_LW_SN,
-  TILE_OPC_LW_NA,
-  TILE_OPC_LW_NA_SN,
-  TILE_OPC_LWADD,
-  TILE_OPC_LWADD_SN,
-  TILE_OPC_LWADD_NA,
-  TILE_OPC_LWADD_NA_SN,
-  TILE_OPC_MAXB_U,
-  TILE_OPC_MAXB_U_SN,
-  TILE_OPC_MAXH,
-  TILE_OPC_MAXH_SN,
-  TILE_OPC_MAXIB_U,
-  TILE_OPC_MAXIB_U_SN,
-  TILE_OPC_MAXIH,
-  TILE_OPC_MAXIH_SN,
-  TILE_OPC_MF,
-  TILE_OPC_MFSPR,
-  TILE_OPC_MINB_U,
-  TILE_OPC_MINB_U_SN,
-  TILE_OPC_MINH,
-  TILE_OPC_MINH_SN,
-  TILE_OPC_MINIB_U,
-  TILE_OPC_MINIB_U_SN,
-  TILE_OPC_MINIH,
-  TILE_OPC_MINIH_SN,
-  TILE_OPC_MM,
-  TILE_OPC_MNZ,
-  TILE_OPC_MNZ_SN,
-  TILE_OPC_MNZB,
-  TILE_OPC_MNZB_SN,
-  TILE_OPC_MNZH,
-  TILE_OPC_MNZH_SN,
-  TILE_OPC_MTSPR,
-  TILE_OPC_MULHH_SS,
-  TILE_OPC_MULHH_SS_SN,
-  TILE_OPC_MULHH_SU,
-  TILE_OPC_MULHH_SU_SN,
-  TILE_OPC_MULHH_UU,
-  TILE_OPC_MULHH_UU_SN,
-  TILE_OPC_MULHHA_SS,
-  TILE_OPC_MULHHA_SS_SN,
-  TILE_OPC_MULHHA_SU,
-  TILE_OPC_MULHHA_SU_SN,
-  TILE_OPC_MULHHA_UU,
-  TILE_OPC_MULHHA_UU_SN,
-  TILE_OPC_MULHHSA_UU,
-  TILE_OPC_MULHHSA_UU_SN,
-  TILE_OPC_MULHL_SS,
-  TILE_OPC_MULHL_SS_SN,
-  TILE_OPC_MULHL_SU,
-  TILE_OPC_MULHL_SU_SN,
-  TILE_OPC_MULHL_US,
-  TILE_OPC_MULHL_US_SN,
-  TILE_OPC_MULHL_UU,
-  TILE_OPC_MULHL_UU_SN,
-  TILE_OPC_MULHLA_SS,
-  TILE_OPC_MULHLA_SS_SN,
-  TILE_OPC_MULHLA_SU,
-  TILE_OPC_MULHLA_SU_SN,
-  TILE_OPC_MULHLA_US,
-  TILE_OPC_MULHLA_US_SN,
-  TILE_OPC_MULHLA_UU,
-  TILE_OPC_MULHLA_UU_SN,
-  TILE_OPC_MULHLSA_UU,
-  TILE_OPC_MULHLSA_UU_SN,
-  TILE_OPC_MULLL_SS,
-  TILE_OPC_MULLL_SS_SN,
-  TILE_OPC_MULLL_SU,
-  TILE_OPC_MULLL_SU_SN,
-  TILE_OPC_MULLL_UU,
-  TILE_OPC_MULLL_UU_SN,
-  TILE_OPC_MULLLA_SS,
-  TILE_OPC_MULLLA_SS_SN,
-  TILE_OPC_MULLLA_SU,
-  TILE_OPC_MULLLA_SU_SN,
-  TILE_OPC_MULLLA_UU,
-  TILE_OPC_MULLLA_UU_SN,
-  TILE_OPC_MULLLSA_UU,
-  TILE_OPC_MULLLSA_UU_SN,
-  TILE_OPC_MVNZ,
-  TILE_OPC_MVNZ_SN,
-  TILE_OPC_MVZ,
-  TILE_OPC_MVZ_SN,
-  TILE_OPC_MZ,
-  TILE_OPC_MZ_SN,
-  TILE_OPC_MZB,
-  TILE_OPC_MZB_SN,
-  TILE_OPC_MZH,
-  TILE_OPC_MZH_SN,
-  TILE_OPC_NAP,
-  TILE_OPC_NOP,
-  TILE_OPC_NOR,
-  TILE_OPC_NOR_SN,
-  TILE_OPC_OR,
-  TILE_OPC_OR_SN,
-  TILE_OPC_ORI,
-  TILE_OPC_ORI_SN,
-  TILE_OPC_PACKBS_U,
-  TILE_OPC_PACKBS_U_SN,
-  TILE_OPC_PACKHB,
-  TILE_OPC_PACKHB_SN,
-  TILE_OPC_PACKHS,
-  TILE_OPC_PACKHS_SN,
-  TILE_OPC_PACKLB,
-  TILE_OPC_PACKLB_SN,
-  TILE_OPC_PCNT,
-  TILE_OPC_PCNT_SN,
-  TILE_OPC_RL,
-  TILE_OPC_RL_SN,
-  TILE_OPC_RLI,
-  TILE_OPC_RLI_SN,
-  TILE_OPC_S1A,
-  TILE_OPC_S1A_SN,
-  TILE_OPC_S2A,
-  TILE_OPC_S2A_SN,
-  TILE_OPC_S3A,
-  TILE_OPC_S3A_SN,
-  TILE_OPC_SADAB_U,
-  TILE_OPC_SADAB_U_SN,
-  TILE_OPC_SADAH,
-  TILE_OPC_SADAH_SN,
-  TILE_OPC_SADAH_U,
-  TILE_OPC_SADAH_U_SN,
-  TILE_OPC_SADB_U,
-  TILE_OPC_SADB_U_SN,
-  TILE_OPC_SADH,
-  TILE_OPC_SADH_SN,
-  TILE_OPC_SADH_U,
-  TILE_OPC_SADH_U_SN,
-  TILE_OPC_SB,
-  TILE_OPC_SBADD,
-  TILE_OPC_SEQ,
-  TILE_OPC_SEQ_SN,
-  TILE_OPC_SEQB,
-  TILE_OPC_SEQB_SN,
-  TILE_OPC_SEQH,
-  TILE_OPC_SEQH_SN,
-  TILE_OPC_SEQI,
-  TILE_OPC_SEQI_SN,
-  TILE_OPC_SEQIB,
-  TILE_OPC_SEQIB_SN,
-  TILE_OPC_SEQIH,
-  TILE_OPC_SEQIH_SN,
-  TILE_OPC_SH,
-  TILE_OPC_SHADD,
-  TILE_OPC_SHL,
-  TILE_OPC_SHL_SN,
-  TILE_OPC_SHLB,
-  TILE_OPC_SHLB_SN,
-  TILE_OPC_SHLH,
-  TILE_OPC_SHLH_SN,
-  TILE_OPC_SHLI,
-  TILE_OPC_SHLI_SN,
-  TILE_OPC_SHLIB,
-  TILE_OPC_SHLIB_SN,
-  TILE_OPC_SHLIH,
-  TILE_OPC_SHLIH_SN,
-  TILE_OPC_SHR,
-  TILE_OPC_SHR_SN,
-  TILE_OPC_SHRB,
-  TILE_OPC_SHRB_SN,
-  TILE_OPC_SHRH,
-  TILE_OPC_SHRH_SN,
-  TILE_OPC_SHRI,
-  TILE_OPC_SHRI_SN,
-  TILE_OPC_SHRIB,
-  TILE_OPC_SHRIB_SN,
-  TILE_OPC_SHRIH,
-  TILE_OPC_SHRIH_SN,
-  TILE_OPC_SLT,
-  TILE_OPC_SLT_SN,
-  TILE_OPC_SLT_U,
-  TILE_OPC_SLT_U_SN,
-  TILE_OPC_SLTB,
-  TILE_OPC_SLTB_SN,
-  TILE_OPC_SLTB_U,
-  TILE_OPC_SLTB_U_SN,
-  TILE_OPC_SLTE,
-  TILE_OPC_SLTE_SN,
-  TILE_OPC_SLTE_U,
-  TILE_OPC_SLTE_U_SN,
-  TILE_OPC_SLTEB,
-  TILE_OPC_SLTEB_SN,
-  TILE_OPC_SLTEB_U,
-  TILE_OPC_SLTEB_U_SN,
-  TILE_OPC_SLTEH,
-  TILE_OPC_SLTEH_SN,
-  TILE_OPC_SLTEH_U,
-  TILE_OPC_SLTEH_U_SN,
-  TILE_OPC_SLTH,
-  TILE_OPC_SLTH_SN,
-  TILE_OPC_SLTH_U,
-  TILE_OPC_SLTH_U_SN,
-  TILE_OPC_SLTI,
-  TILE_OPC_SLTI_SN,
-  TILE_OPC_SLTI_U,
-  TILE_OPC_SLTI_U_SN,
-  TILE_OPC_SLTIB,
-  TILE_OPC_SLTIB_SN,
-  TILE_OPC_SLTIB_U,
-  TILE_OPC_SLTIB_U_SN,
-  TILE_OPC_SLTIH,
-  TILE_OPC_SLTIH_SN,
-  TILE_OPC_SLTIH_U,
-  TILE_OPC_SLTIH_U_SN,
-  TILE_OPC_SNE,
-  TILE_OPC_SNE_SN,
-  TILE_OPC_SNEB,
-  TILE_OPC_SNEB_SN,
-  TILE_OPC_SNEH,
-  TILE_OPC_SNEH_SN,
-  TILE_OPC_SRA,
-  TILE_OPC_SRA_SN,
-  TILE_OPC_SRAB,
-  TILE_OPC_SRAB_SN,
-  TILE_OPC_SRAH,
-  TILE_OPC_SRAH_SN,
-  TILE_OPC_SRAI,
-  TILE_OPC_SRAI_SN,
-  TILE_OPC_SRAIB,
-  TILE_OPC_SRAIB_SN,
-  TILE_OPC_SRAIH,
-  TILE_OPC_SRAIH_SN,
-  TILE_OPC_SUB,
-  TILE_OPC_SUB_SN,
-  TILE_OPC_SUBB,
-  TILE_OPC_SUBB_SN,
-  TILE_OPC_SUBBS_U,
-  TILE_OPC_SUBBS_U_SN,
-  TILE_OPC_SUBH,
-  TILE_OPC_SUBH_SN,
-  TILE_OPC_SUBHS,
-  TILE_OPC_SUBHS_SN,
-  TILE_OPC_SUBS,
-  TILE_OPC_SUBS_SN,
-  TILE_OPC_SW,
-  TILE_OPC_SWADD,
-  TILE_OPC_SWINT0,
-  TILE_OPC_SWINT1,
-  TILE_OPC_SWINT2,
-  TILE_OPC_SWINT3,
-  TILE_OPC_TBLIDXB0,
-  TILE_OPC_TBLIDXB0_SN,
-  TILE_OPC_TBLIDXB1,
-  TILE_OPC_TBLIDXB1_SN,
-  TILE_OPC_TBLIDXB2,
-  TILE_OPC_TBLIDXB2_SN,
-  TILE_OPC_TBLIDXB3,
-  TILE_OPC_TBLIDXB3_SN,
-  TILE_OPC_TNS,
-  TILE_OPC_TNS_SN,
-  TILE_OPC_WH64,
-  TILE_OPC_XOR,
-  TILE_OPC_XOR_SN,
-  TILE_OPC_XORI,
-  TILE_OPC_XORI_SN,
-  TILE_OPC_NONE
-} tile_mnemonic;
+  TILEGX_OPC_BPT,
+  TILEGX_OPC_INFO,
+  TILEGX_OPC_INFOL,
+  TILEGX_OPC_MOVE,
+  TILEGX_OPC_MOVEI,
+  TILEGX_OPC_MOVELI,
+  TILEGX_OPC_PREFETCH,
+  TILEGX_OPC_PREFETCH_ADD_L1,
+  TILEGX_OPC_PREFETCH_ADD_L1_FAULT,
+  TILEGX_OPC_PREFETCH_ADD_L2,
+  TILEGX_OPC_PREFETCH_ADD_L2_FAULT,
+  TILEGX_OPC_PREFETCH_ADD_L3,
+  TILEGX_OPC_PREFETCH_ADD_L3_FAULT,
+  TILEGX_OPC_PREFETCH_L1,
+  TILEGX_OPC_PREFETCH_L1_FAULT,
+  TILEGX_OPC_PREFETCH_L2,
+  TILEGX_OPC_PREFETCH_L2_FAULT,
+  TILEGX_OPC_PREFETCH_L3,
+  TILEGX_OPC_PREFETCH_L3_FAULT,
+  TILEGX_OPC_RAISE,
+  TILEGX_OPC_ADD,
+  TILEGX_OPC_ADDI,
+  TILEGX_OPC_ADDLI,
+  TILEGX_OPC_ADDX,
+  TILEGX_OPC_ADDXI,
+  TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXSC,
+  TILEGX_OPC_AND,
+  TILEGX_OPC_ANDI,
+  TILEGX_OPC_BEQZ,
+  TILEGX_OPC_BEQZT,
+  TILEGX_OPC_BFEXTS,
+  TILEGX_OPC_BFEXTU,
+  TILEGX_OPC_BFINS,
+  TILEGX_OPC_BGEZ,
+  TILEGX_OPC_BGEZT,
+  TILEGX_OPC_BGTZ,
+  TILEGX_OPC_BGTZT,
+  TILEGX_OPC_BLBC,
+  TILEGX_OPC_BLBCT,
+  TILEGX_OPC_BLBS,
+  TILEGX_OPC_BLBST,
+  TILEGX_OPC_BLEZ,
+  TILEGX_OPC_BLEZT,
+  TILEGX_OPC_BLTZ,
+  TILEGX_OPC_BLTZT,
+  TILEGX_OPC_BNEZ,
+  TILEGX_OPC_BNEZT,
+  TILEGX_OPC_CLZ,
+  TILEGX_OPC_CMOVEQZ,
+  TILEGX_OPC_CMOVNEZ,
+  TILEGX_OPC_CMPEQ,
+  TILEGX_OPC_CMPEQI,
+  TILEGX_OPC_CMPEXCH,
+  TILEGX_OPC_CMPEXCH4,
+  TILEGX_OPC_CMPLES,
+  TILEGX_OPC_CMPLEU,
+  TILEGX_OPC_CMPLTS,
+  TILEGX_OPC_CMPLTSI,
+  TILEGX_OPC_CMPLTU,
+  TILEGX_OPC_CMPLTUI,
+  TILEGX_OPC_CMPNE,
+  TILEGX_OPC_CMUL,
+  TILEGX_OPC_CMULA,
+  TILEGX_OPC_CMULAF,
+  TILEGX_OPC_CMULF,
+  TILEGX_OPC_CMULFR,
+  TILEGX_OPC_CMULH,
+  TILEGX_OPC_CMULHR,
+  TILEGX_OPC_CRC32_32,
+  TILEGX_OPC_CRC32_8,
+  TILEGX_OPC_CTZ,
+  TILEGX_OPC_DBLALIGN,
+  TILEGX_OPC_DBLALIGN2,
+  TILEGX_OPC_DBLALIGN4,
+  TILEGX_OPC_DBLALIGN6,
+  TILEGX_OPC_DRAIN,
+  TILEGX_OPC_DTLBPR,
+  TILEGX_OPC_EXCH,
+  TILEGX_OPC_EXCH4,
+  TILEGX_OPC_FDOUBLE_ADD_FLAGS,
+  TILEGX_OPC_FDOUBLE_ADDSUB,
+  TILEGX_OPC_FDOUBLE_MUL_FLAGS,
+  TILEGX_OPC_FDOUBLE_PACK1,
+  TILEGX_OPC_FDOUBLE_PACK2,
+  TILEGX_OPC_FDOUBLE_SUB_FLAGS,
+  TILEGX_OPC_FDOUBLE_UNPACK_MAX,
+  TILEGX_OPC_FDOUBLE_UNPACK_MIN,
+  TILEGX_OPC_FETCHADD,
+  TILEGX_OPC_FETCHADD4,
+  TILEGX_OPC_FETCHADDGEZ,
+  TILEGX_OPC_FETCHADDGEZ4,
+  TILEGX_OPC_FETCHAND,
+  TILEGX_OPC_FETCHAND4,
+  TILEGX_OPC_FETCHOR,
+  TILEGX_OPC_FETCHOR4,
+  TILEGX_OPC_FINV,
+  TILEGX_OPC_FLUSH,
+  TILEGX_OPC_FLUSHWB,
+  TILEGX_OPC_FNOP,
+  TILEGX_OPC_FSINGLE_ADD1,
+  TILEGX_OPC_FSINGLE_ADDSUB2,
+  TILEGX_OPC_FSINGLE_MUL1,
+  TILEGX_OPC_FSINGLE_MUL2,
+  TILEGX_OPC_FSINGLE_PACK1,
+  TILEGX_OPC_FSINGLE_PACK2,
+  TILEGX_OPC_FSINGLE_SUB1,
+  TILEGX_OPC_ICOH,
+  TILEGX_OPC_ILL,
+  TILEGX_OPC_INV,
+  TILEGX_OPC_IRET,
+  TILEGX_OPC_J,
+  TILEGX_OPC_JAL,
+  TILEGX_OPC_JALR,
+  TILEGX_OPC_JALRP,
+  TILEGX_OPC_JR,
+  TILEGX_OPC_JRP,
+  TILEGX_OPC_LD,
+  TILEGX_OPC_LD1S,
+  TILEGX_OPC_LD1S_ADD,
+  TILEGX_OPC_LD1U,
+  TILEGX_OPC_LD1U_ADD,
+  TILEGX_OPC_LD2S,
+  TILEGX_OPC_LD2S_ADD,
+  TILEGX_OPC_LD2U,
+  TILEGX_OPC_LD2U_ADD,
+  TILEGX_OPC_LD4S,
+  TILEGX_OPC_LD4S_ADD,
+  TILEGX_OPC_LD4U,
+  TILEGX_OPC_LD4U_ADD,
+  TILEGX_OPC_LD_ADD,
+  TILEGX_OPC_LDNA,
+  TILEGX_OPC_LDNA_ADD,
+  TILEGX_OPC_LDNT,
+  TILEGX_OPC_LDNT1S,
+  TILEGX_OPC_LDNT1S_ADD,
+  TILEGX_OPC_LDNT1U,
+  TILEGX_OPC_LDNT1U_ADD,
+  TILEGX_OPC_LDNT2S,
+  TILEGX_OPC_LDNT2S_ADD,
+  TILEGX_OPC_LDNT2U,
+  TILEGX_OPC_LDNT2U_ADD,
+  TILEGX_OPC_LDNT4S,
+  TILEGX_OPC_LDNT4S_ADD,
+  TILEGX_OPC_LDNT4U,
+  TILEGX_OPC_LDNT4U_ADD,
+  TILEGX_OPC_LDNT_ADD,
+  TILEGX_OPC_LNK,
+  TILEGX_OPC_MF,
+  TILEGX_OPC_MFSPR,
+  TILEGX_OPC_MM,
+  TILEGX_OPC_MNZ,
+  TILEGX_OPC_MTSPR,
+  TILEGX_OPC_MUL_HS_HS,
+  TILEGX_OPC_MUL_HS_HU,
+  TILEGX_OPC_MUL_HS_LS,
+  TILEGX_OPC_MUL_HS_LU,
+  TILEGX_OPC_MUL_HU_HU,
+  TILEGX_OPC_MUL_HU_LS,
+  TILEGX_OPC_MUL_HU_LU,
+  TILEGX_OPC_MUL_LS_LS,
+  TILEGX_OPC_MUL_LS_LU,
+  TILEGX_OPC_MUL_LU_LU,
+  TILEGX_OPC_MULA_HS_HS,
+  TILEGX_OPC_MULA_HS_HU,
+  TILEGX_OPC_MULA_HS_LS,
+  TILEGX_OPC_MULA_HS_LU,
+  TILEGX_OPC_MULA_HU_HU,
+  TILEGX_OPC_MULA_HU_LS,
+  TILEGX_OPC_MULA_HU_LU,
+  TILEGX_OPC_MULA_LS_LS,
+  TILEGX_OPC_MULA_LS_LU,
+  TILEGX_OPC_MULA_LU_LU,
+  TILEGX_OPC_MULAX,
+  TILEGX_OPC_MULX,
+  TILEGX_OPC_MZ,
+  TILEGX_OPC_NAP,
+  TILEGX_OPC_NOP,
+  TILEGX_OPC_NOR,
+  TILEGX_OPC_OR,
+  TILEGX_OPC_ORI,
+  TILEGX_OPC_PCNT,
+  TILEGX_OPC_REVBITS,
+  TILEGX_OPC_REVBYTES,
+  TILEGX_OPC_ROTL,
+  TILEGX_OPC_ROTLI,
+  TILEGX_OPC_SHL,
+  TILEGX_OPC_SHL16INSLI,
+  TILEGX_OPC_SHL1ADD,
+  TILEGX_OPC_SHL1ADDX,
+  TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL2ADDX,
+  TILEGX_OPC_SHL3ADD,
+  TILEGX_OPC_SHL3ADDX,
+  TILEGX_OPC_SHLI,
+  TILEGX_OPC_SHLX,
+  TILEGX_OPC_SHLXI,
+  TILEGX_OPC_SHRS,
+  TILEGX_OPC_SHRSI,
+  TILEGX_OPC_SHRU,
+  TILEGX_OPC_SHRUI,
+  TILEGX_OPC_SHRUX,
+  TILEGX_OPC_SHRUXI,
+  TILEGX_OPC_SHUFFLEBYTES,
+  TILEGX_OPC_ST,
+  TILEGX_OPC_ST1,
+  TILEGX_OPC_ST1_ADD,
+  TILEGX_OPC_ST2,
+  TILEGX_OPC_ST2_ADD,
+  TILEGX_OPC_ST4,
+  TILEGX_OPC_ST4_ADD,
+  TILEGX_OPC_ST_ADD,
+  TILEGX_OPC_STNT,
+  TILEGX_OPC_STNT1,
+  TILEGX_OPC_STNT1_ADD,
+  TILEGX_OPC_STNT2,
+  TILEGX_OPC_STNT2_ADD,
+  TILEGX_OPC_STNT4,
+  TILEGX_OPC_STNT4_ADD,
+  TILEGX_OPC_STNT_ADD,
+  TILEGX_OPC_SUB,
+  TILEGX_OPC_SUBX,
+  TILEGX_OPC_SUBXSC,
+  TILEGX_OPC_SWINT0,
+  TILEGX_OPC_SWINT1,
+  TILEGX_OPC_SWINT2,
+  TILEGX_OPC_SWINT3,
+  TILEGX_OPC_TBLIDXB0,
+  TILEGX_OPC_TBLIDXB1,
+  TILEGX_OPC_TBLIDXB2,
+  TILEGX_OPC_TBLIDXB3,
+  TILEGX_OPC_V1ADD,
+  TILEGX_OPC_V1ADDI,
+  TILEGX_OPC_V1ADDUC,
+  TILEGX_OPC_V1ADIFFU,
+  TILEGX_OPC_V1AVGU,
+  TILEGX_OPC_V1CMPEQ,
+  TILEGX_OPC_V1CMPEQI,
+  TILEGX_OPC_V1CMPLES,
+  TILEGX_OPC_V1CMPLEU,
+  TILEGX_OPC_V1CMPLTS,
+  TILEGX_OPC_V1CMPLTSI,
+  TILEGX_OPC_V1CMPLTU,
+  TILEGX_OPC_V1CMPLTUI,
+  TILEGX_OPC_V1CMPNE,
+  TILEGX_OPC_V1DDOTPU,
+  TILEGX_OPC_V1DDOTPUA,
+  TILEGX_OPC_V1DDOTPUS,
+  TILEGX_OPC_V1DDOTPUSA,
+  TILEGX_OPC_V1DOTP,
+  TILEGX_OPC_V1DOTPA,
+  TILEGX_OPC_V1DOTPU,
+  TILEGX_OPC_V1DOTPUA,
+  TILEGX_OPC_V1DOTPUS,
+  TILEGX_OPC_V1DOTPUSA,
+  TILEGX_OPC_V1INT_H,
+  TILEGX_OPC_V1INT_L,
+  TILEGX_OPC_V1MAXU,
+  TILEGX_OPC_V1MAXUI,
+  TILEGX_OPC_V1MINU,
+  TILEGX_OPC_V1MINUI,
+  TILEGX_OPC_V1MNZ,
+  TILEGX_OPC_V1MULTU,
+  TILEGX_OPC_V1MULU,
+  TILEGX_OPC_V1MULUS,
+  TILEGX_OPC_V1MZ,
+  TILEGX_OPC_V1SADAU,
+  TILEGX_OPC_V1SADU,
+  TILEGX_OPC_V1SHL,
+  TILEGX_OPC_V1SHLI,
+  TILEGX_OPC_V1SHRS,
+  TILEGX_OPC_V1SHRSI,
+  TILEGX_OPC_V1SHRU,
+  TILEGX_OPC_V1SHRUI,
+  TILEGX_OPC_V1SUB,
+  TILEGX_OPC_V1SUBUC,
+  TILEGX_OPC_V2ADD,
+  TILEGX_OPC_V2ADDI,
+  TILEGX_OPC_V2ADDSC,
+  TILEGX_OPC_V2ADIFFS,
+  TILEGX_OPC_V2AVGS,
+  TILEGX_OPC_V2CMPEQ,
+  TILEGX_OPC_V2CMPEQI,
+  TILEGX_OPC_V2CMPLES,
+  TILEGX_OPC_V2CMPLEU,
+  TILEGX_OPC_V2CMPLTS,
+  TILEGX_OPC_V2CMPLTSI,
+  TILEGX_OPC_V2CMPLTU,
+  TILEGX_OPC_V2CMPLTUI,
+  TILEGX_OPC_V2CMPNE,
+  TILEGX_OPC_V2DOTP,
+  TILEGX_OPC_V2DOTPA,
+  TILEGX_OPC_V2INT_H,
+  TILEGX_OPC_V2INT_L,
+  TILEGX_OPC_V2MAXS,
+  TILEGX_OPC_V2MAXSI,
+  TILEGX_OPC_V2MINS,
+  TILEGX_OPC_V2MINSI,
+  TILEGX_OPC_V2MNZ,
+  TILEGX_OPC_V2MULFSC,
+  TILEGX_OPC_V2MULS,
+  TILEGX_OPC_V2MULTS,
+  TILEGX_OPC_V2MZ,
+  TILEGX_OPC_V2PACKH,
+  TILEGX_OPC_V2PACKL,
+  TILEGX_OPC_V2PACKUC,
+  TILEGX_OPC_V2SADAS,
+  TILEGX_OPC_V2SADAU,
+  TILEGX_OPC_V2SADS,
+  TILEGX_OPC_V2SADU,
+  TILEGX_OPC_V2SHL,
+  TILEGX_OPC_V2SHLI,
+  TILEGX_OPC_V2SHLSC,
+  TILEGX_OPC_V2SHRS,
+  TILEGX_OPC_V2SHRSI,
+  TILEGX_OPC_V2SHRU,
+  TILEGX_OPC_V2SHRUI,
+  TILEGX_OPC_V2SUB,
+  TILEGX_OPC_V2SUBSC,
+  TILEGX_OPC_V4ADD,
+  TILEGX_OPC_V4ADDSC,
+  TILEGX_OPC_V4INT_H,
+  TILEGX_OPC_V4INT_L,
+  TILEGX_OPC_V4PACKSC,
+  TILEGX_OPC_V4SHL,
+  TILEGX_OPC_V4SHLSC,
+  TILEGX_OPC_V4SHRS,
+  TILEGX_OPC_V4SHRU,
+  TILEGX_OPC_V4SUB,
+  TILEGX_OPC_V4SUBSC,
+  TILEGX_OPC_WH64,
+  TILEGX_OPC_XOR,
+  TILEGX_OPC_XORI,
+  TILEGX_OPC_NONE
+} tilegx_mnemonic;
 
 /* 64-bit pattern for a { bpt ; nop } bundle. */
-#define TILE_BPT_BUNDLE 0x400b3cae70166000ULL
+#define TILEGX_BPT_BUNDLE 0x286a44ae51485000ULL
 
 
-#define TILE_ELF_MACHINE_CODE EM_TILEPRO
+#define TILE_ELF_MACHINE_CODE EM_TILE64
 
-#define TILE_ELF_NAME "elf32-tilepro"
+#define TILE_ELF_NAME "elf32-tile64"
 
 
 static __inline unsigned int
-get_BrOff_SN(tile_bundle_bits num)
+get_BFEnd_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 0)) & 0x3ff);
+  return (((n >> 12)) & 0x3f);
 }
 
 static __inline unsigned int
-get_BrOff_X1(tile_bundle_bits n)
+get_BFOpcodeExtension_X0(tilegx_bundle_bits num)
 {
-  return (((unsigned int)(n >> 43)) & 0x00007fff) |
-         (((unsigned int)(n >> 20)) & 0x00018000);
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 24)) & 0xf);
 }
 
 static __inline unsigned int
-get_BrType_X1(tile_bundle_bits n)
+get_BFStart_X0(tilegx_bundle_bits num)
 {
-  return (((unsigned int)(n >> 31)) & 0xf);
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 18)) & 0x3f);
 }
 
 static __inline unsigned int
-get_Dest_Imm8_X1(tile_bundle_bits n)
+get_BrOff_X1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 31)) & 0x0000003f) |
-         (((unsigned int)(n >> 43)) & 0x000000c0);
+         (((unsigned int)(n >> 37)) & 0x0001ffc0);
 }
 
 static __inline unsigned int
-get_Dest_SN(tile_bundle_bits num)
+get_BrType_X1(tilegx_bundle_bits n)
 {
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 2)) & 0x3);
+  return (((unsigned int)(n >> 54)) & 0x1f);
 }
 
 static __inline unsigned int
-get_Dest_X0(tile_bundle_bits num)
+get_Dest_Imm8_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 31)) & 0x0000003f) |
+         (((unsigned int)(n >> 43)) & 0x000000c0);
+}
+
+static __inline unsigned int
+get_Dest_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 0)) & 0x3f);
 }
 
 static __inline unsigned int
-get_Dest_X1(tile_bundle_bits n)
+get_Dest_X1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 31)) & 0x3f);
 }
 
 static __inline unsigned int
-get_Dest_Y0(tile_bundle_bits num)
+get_Dest_Y0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 0)) & 0x3f);
 }
 
 static __inline unsigned int
-get_Dest_Y1(tile_bundle_bits n)
+get_Dest_Y1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 31)) & 0x3f);
 }
 
 static __inline unsigned int
-get_Imm16_X0(tile_bundle_bits num)
+get_Imm16_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 12)) & 0xffff);
 }
 
 static __inline unsigned int
-get_Imm16_X1(tile_bundle_bits n)
+get_Imm16_X1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 43)) & 0xffff);
 }
 
 static __inline unsigned int
-get_Imm8_SN(tile_bundle_bits num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 0)) & 0xff);
-}
-
-static __inline unsigned int
-get_Imm8_X0(tile_bundle_bits num)
+get_Imm8OpcodeExtension_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 12)) & 0xff);
+  return (((n >> 20)) & 0xff);
 }
 
 static __inline unsigned int
-get_Imm8_X1(tile_bundle_bits n)
+get_Imm8OpcodeExtension_X1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 43)) & 0xff);
+  return (((unsigned int)(n >> 51)) & 0xff);
 }
 
 static __inline unsigned int
-get_Imm8_Y0(tile_bundle_bits num)
+get_Imm8_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 12)) & 0xff);
 }
 
 static __inline unsigned int
-get_Imm8_Y1(tile_bundle_bits n)
+get_Imm8_X1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 43)) & 0xff);
 }
 
 static __inline unsigned int
-get_ImmOpcodeExtension_X0(tile_bundle_bits num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 20)) & 0x7f);
-}
-
-static __inline unsigned int
-get_ImmOpcodeExtension_X1(tile_bundle_bits n)
-{
-  return (((unsigned int)(n >> 51)) & 0x7f);
-}
-
-static __inline unsigned int
-get_ImmRROpcodeExtension_SN(tile_bundle_bits num)
+get_Imm8_Y0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 8)) & 0x3);
-}
-
-static __inline unsigned int
-get_JOffLong_X1(tile_bundle_bits n)
-{
-  return (((unsigned int)(n >> 43)) & 0x00007fff) |
-         (((unsigned int)(n >> 20)) & 0x00018000) |
-         (((unsigned int)(n >> 14)) & 0x001e0000) |
-         (((unsigned int)(n >> 16)) & 0x07e00000) |
-         (((unsigned int)(n >> 31)) & 0x18000000);
-}
-
-static __inline unsigned int
-get_JOff_X1(tile_bundle_bits n)
-{
-  return (((unsigned int)(n >> 43)) & 0x00007fff) |
-         (((unsigned int)(n >> 20)) & 0x00018000) |
-         (((unsigned int)(n >> 14)) & 0x001e0000) |
-         (((unsigned int)(n >> 16)) & 0x07e00000) |
-         (((unsigned int)(n >> 31)) & 0x08000000);
-}
-
-static __inline unsigned int
-get_MF_Imm15_X1(tile_bundle_bits n)
-{
-  return (((unsigned int)(n >> 37)) & 0x00003fff) |
-         (((unsigned int)(n >> 44)) & 0x00004000);
+  return (((n >> 12)) & 0xff);
 }
 
 static __inline unsigned int
-get_MMEnd_X0(tile_bundle_bits num)
+get_Imm8_Y1(tilegx_bundle_bits n)
 {
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 18)) & 0x1f);
+  return (((unsigned int)(n >> 43)) & 0xff);
 }
 
 static __inline unsigned int
-get_MMEnd_X1(tile_bundle_bits n)
+get_JumpOff_X1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 49)) & 0x1f);
+  return (((unsigned int)(n >> 31)) & 0x7ffffff);
 }
 
 static __inline unsigned int
-get_MMStart_X0(tile_bundle_bits num)
+get_JumpOpcodeExtension_X1(tilegx_bundle_bits n)
 {
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 23)) & 0x1f);
+  return (((unsigned int)(n >> 58)) & 0x1);
 }
 
 static __inline unsigned int
-get_MMStart_X1(tile_bundle_bits n)
+get_MF_Imm14_X1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 54)) & 0x1f);
+  return (((unsigned int)(n >> 37)) & 0x3fff);
 }
 
 static __inline unsigned int
-get_MT_Imm15_X1(tile_bundle_bits n)
+get_MT_Imm14_X1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 31)) & 0x0000003f) |
-         (((unsigned int)(n >> 37)) & 0x00003fc0) |
-         (((unsigned int)(n >> 44)) & 0x00004000);
+         (((unsigned int)(n >> 37)) & 0x00003fc0);
 }
 
 static __inline unsigned int
-get_Mode(tile_bundle_bits n)
+get_Mode(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 63)) & 0x1);
+  return (((unsigned int)(n >> 62)) & 0x3);
 }
 
 static __inline unsigned int
-get_NoRegOpcodeExtension_SN(tile_bundle_bits num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 0)) & 0xf);
-}
-
-static __inline unsigned int
-get_Opcode_SN(tile_bundle_bits num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 10)) & 0x3f);
-}
-
-static __inline unsigned int
-get_Opcode_X0(tile_bundle_bits num)
+get_Opcode_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 28)) & 0x7);
 }
 
 static __inline unsigned int
-get_Opcode_X1(tile_bundle_bits n)
+get_Opcode_X1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 59)) & 0xf);
+  return (((unsigned int)(n >> 59)) & 0x7);
 }
 
 static __inline unsigned int
-get_Opcode_Y0(tile_bundle_bits num)
+get_Opcode_Y0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 27)) & 0xf);
 }
 
 static __inline unsigned int
-get_Opcode_Y1(tile_bundle_bits n)
+get_Opcode_Y1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 59)) & 0xf);
+  return (((unsigned int)(n >> 58)) & 0xf);
 }
 
 static __inline unsigned int
-get_Opcode_Y2(tile_bundle_bits n)
+get_Opcode_Y2(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 56)) & 0x7);
-}
-
-static __inline unsigned int
-get_RROpcodeExtension_SN(tile_bundle_bits num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 4)) & 0xf);
+  return (((n >> 26)) & 0x00000001) |
+         (((unsigned int)(n >> 56)) & 0x00000002);
 }
 
 static __inline unsigned int
-get_RRROpcodeExtension_X0(tile_bundle_bits num)
+get_RRROpcodeExtension_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 18)) & 0x1ff);
+  return (((n >> 18)) & 0x3ff);
 }
 
 static __inline unsigned int
-get_RRROpcodeExtension_X1(tile_bundle_bits n)
+get_RRROpcodeExtension_X1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 49)) & 0x1ff);
+  return (((unsigned int)(n >> 49)) & 0x3ff);
 }
 
 static __inline unsigned int
-get_RRROpcodeExtension_Y0(tile_bundle_bits num)
+get_RRROpcodeExtension_Y0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 18)) & 0x3);
 }
 
 static __inline unsigned int
-get_RRROpcodeExtension_Y1(tile_bundle_bits n)
+get_RRROpcodeExtension_Y1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 49)) & 0x3);
 }
 
 static __inline unsigned int
-get_RouteOpcodeExtension_SN(tile_bundle_bits num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 0)) & 0x3ff);
-}
-
-static __inline unsigned int
-get_S_X0(tile_bundle_bits num)
+get_ShAmt_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 27)) & 0x1);
+  return (((n >> 12)) & 0x3f);
 }
 
 static __inline unsigned int
-get_S_X1(tile_bundle_bits n)
+get_ShAmt_X1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 58)) & 0x1);
+  return (((unsigned int)(n >> 43)) & 0x3f);
 }
 
 static __inline unsigned int
-get_ShAmt_X0(tile_bundle_bits num)
+get_ShAmt_Y0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 12)) & 0x1f);
+  return (((n >> 12)) & 0x3f);
 }
 
 static __inline unsigned int
-get_ShAmt_X1(tile_bundle_bits n)
+get_ShAmt_Y1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 43)) & 0x1f);
+  return (((unsigned int)(n >> 43)) & 0x3f);
 }
 
 static __inline unsigned int
-get_ShAmt_Y0(tile_bundle_bits num)
+get_ShiftOpcodeExtension_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 12)) & 0x1f);
+  return (((n >> 18)) & 0x3ff);
 }
 
 static __inline unsigned int
-get_ShAmt_Y1(tile_bundle_bits n)
+get_ShiftOpcodeExtension_X1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 43)) & 0x1f);
+  return (((unsigned int)(n >> 49)) & 0x3ff);
 }
 
 static __inline unsigned int
-get_SrcA_X0(tile_bundle_bits num)
+get_ShiftOpcodeExtension_Y0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 6)) & 0x3f);
+  return (((n >> 18)) & 0x3);
 }
 
 static __inline unsigned int
-get_SrcA_X1(tile_bundle_bits n)
+get_ShiftOpcodeExtension_Y1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 37)) & 0x3f);
+  return (((unsigned int)(n >> 49)) & 0x3);
 }
 
 static __inline unsigned int
-get_SrcA_Y0(tile_bundle_bits num)
+get_SrcA_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 6)) & 0x3f);
 }
 
 static __inline unsigned int
-get_SrcA_Y1(tile_bundle_bits n)
+get_SrcA_X1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 37)) & 0x3f);
 }
 
 static __inline unsigned int
-get_SrcA_Y2(tile_bundle_bits n)
+get_SrcA_Y0(tilegx_bundle_bits num)
 {
-  return (((n >> 26)) & 0x00000001) |
-         (((unsigned int)(n >> 50)) & 0x0000003e);
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 6)) & 0x3f);
 }
 
 static __inline unsigned int
-get_SrcBDest_Y2(tile_bundle_bits num)
+get_SrcA_Y1(tilegx_bundle_bits n)
 {
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 20)) & 0x3f);
+  return (((unsigned int)(n >> 37)) & 0x3f);
 }
 
 static __inline unsigned int
-get_SrcB_X0(tile_bundle_bits num)
+get_SrcA_Y2(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 12)) & 0x3f);
+  return (((n >> 20)) & 0x3f);
 }
 
 static __inline unsigned int
-get_SrcB_X1(tile_bundle_bits n)
+get_SrcBDest_Y2(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 43)) & 0x3f);
+  return (((unsigned int)(n >> 51)) & 0x3f);
 }
 
 static __inline unsigned int
-get_SrcB_Y0(tile_bundle_bits num)
+get_SrcB_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 12)) & 0x3f);
 }
 
 static __inline unsigned int
-get_SrcB_Y1(tile_bundle_bits n)
+get_SrcB_X1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 43)) & 0x3f);
 }
 
 static __inline unsigned int
-get_Src_SN(tile_bundle_bits num)
+get_SrcB_Y0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 0)) & 0x3);
-}
-
-static __inline unsigned int
-get_UnOpcodeExtension_X0(tile_bundle_bits num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 12)) & 0x1f);
-}
-
-static __inline unsigned int
-get_UnOpcodeExtension_X1(tile_bundle_bits n)
-{
-  return (((unsigned int)(n >> 43)) & 0x1f);
-}
-
-static __inline unsigned int
-get_UnOpcodeExtension_Y0(tile_bundle_bits num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 12)) & 0x1f);
+  return (((n >> 12)) & 0x3f);
 }
 
 static __inline unsigned int
-get_UnOpcodeExtension_Y1(tile_bundle_bits n)
+get_SrcB_Y1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 43)) & 0x1f);
+  return (((unsigned int)(n >> 43)) & 0x3f);
 }
 
 static __inline unsigned int
-get_UnShOpcodeExtension_X0(tile_bundle_bits num)
+get_UnaryOpcodeExtension_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 17)) & 0x3ff);
+  return (((n >> 12)) & 0x3f);
 }
 
 static __inline unsigned int
-get_UnShOpcodeExtension_X1(tile_bundle_bits n)
+get_UnaryOpcodeExtension_X1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 48)) & 0x3ff);
+  return (((unsigned int)(n >> 43)) & 0x3f);
 }
 
 static __inline unsigned int
-get_UnShOpcodeExtension_Y0(tile_bundle_bits num)
+get_UnaryOpcodeExtension_Y0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 17)) & 0x7);
+  return (((n >> 12)) & 0x3f);
 }
 
 static __inline unsigned int
-get_UnShOpcodeExtension_Y1(tile_bundle_bits n)
+get_UnaryOpcodeExtension_Y1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 48)) & 0x7);
+  return (((unsigned int)(n >> 43)) & 0x3f);
 }
 
 
@@ -874,546 +722,441 @@ sign_extend(int n, int num_bits)
 
 
 
-static __inline tile_bundle_bits
-create_BrOff_SN(int num)
+static __inline tilegx_bundle_bits
+create_BFEnd_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x3ff) << 0);
+  return ((n & 0x3f) << 12);
 }
 
-static __inline tile_bundle_bits
-create_BrOff_X1(int num)
+static __inline tilegx_bundle_bits
+create_BFOpcodeExtension_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x00007fff)) << 43) |
-         (((tile_bundle_bits)(n & 0x00018000)) << 20);
+  return ((n & 0xf) << 24);
 }
 
-static __inline tile_bundle_bits
-create_BrType_X1(int num)
+static __inline tilegx_bundle_bits
+create_BFStart_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0xf)) << 31);
+  return ((n & 0x3f) << 18);
 }
 
-static __inline tile_bundle_bits
-create_Dest_Imm8_X1(int num)
+static __inline tilegx_bundle_bits
+create_BrOff_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x0000003f)) << 31) |
-         (((tile_bundle_bits)(n & 0x000000c0)) << 43);
+  return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) |
+         (((tilegx_bundle_bits)(n & 0x0001ffc0)) << 37);
 }
 
-static __inline tile_bundle_bits
-create_Dest_SN(int num)
+static __inline tilegx_bundle_bits
+create_BrType_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x1f)) << 54);
+}
+
+static __inline tilegx_bundle_bits
+create_Dest_Imm8_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x3) << 2);
+  return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) |
+         (((tilegx_bundle_bits)(n & 0x000000c0)) << 43);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Dest_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0x3f) << 0);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Dest_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x3f)) << 31);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 31);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Dest_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0x3f) << 0);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Dest_Y1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x3f)) << 31);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 31);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Imm16_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0xffff) << 12);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Imm16_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0xffff)) << 43);
+  return (((tilegx_bundle_bits)(n & 0xffff)) << 43);
 }
 
-static __inline tile_bundle_bits
-create_Imm8_SN(int num)
+static __inline tilegx_bundle_bits
+create_Imm8OpcodeExtension_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0xff) << 0);
+  return ((n & 0xff) << 20);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
+create_Imm8OpcodeExtension_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0xff)) << 51);
+}
+
+static __inline tilegx_bundle_bits
 create_Imm8_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0xff) << 12);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Imm8_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0xff)) << 43);
+  return (((tilegx_bundle_bits)(n & 0xff)) << 43);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Imm8_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0xff) << 12);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Imm8_Y1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0xff)) << 43);
-}
-
-static __inline tile_bundle_bits
-create_ImmOpcodeExtension_X0(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return ((n & 0x7f) << 20);
-}
-
-static __inline tile_bundle_bits
-create_ImmOpcodeExtension_X1(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x7f)) << 51);
-}
-
-static __inline tile_bundle_bits
-create_ImmRROpcodeExtension_SN(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return ((n & 0x3) << 8);
-}
-
-static __inline tile_bundle_bits
-create_JOffLong_X1(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x00007fff)) << 43) |
-         (((tile_bundle_bits)(n & 0x00018000)) << 20) |
-         (((tile_bundle_bits)(n & 0x001e0000)) << 14) |
-         (((tile_bundle_bits)(n & 0x07e00000)) << 16) |
-         (((tile_bundle_bits)(n & 0x18000000)) << 31);
-}
-
-static __inline tile_bundle_bits
-create_JOff_X1(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x00007fff)) << 43) |
-         (((tile_bundle_bits)(n & 0x00018000)) << 20) |
-         (((tile_bundle_bits)(n & 0x001e0000)) << 14) |
-         (((tile_bundle_bits)(n & 0x07e00000)) << 16) |
-         (((tile_bundle_bits)(n & 0x08000000)) << 31);
-}
-
-static __inline tile_bundle_bits
-create_MF_Imm15_X1(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x00003fff)) << 37) |
-         (((tile_bundle_bits)(n & 0x00004000)) << 44);
+  return (((tilegx_bundle_bits)(n & 0xff)) << 43);
 }
 
-static __inline tile_bundle_bits
-create_MMEnd_X0(int num)
+static __inline tilegx_bundle_bits
+create_JumpOff_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x1f) << 18);
+  return (((tilegx_bundle_bits)(n & 0x7ffffff)) << 31);
 }
 
-static __inline tile_bundle_bits
-create_MMEnd_X1(int num)
+static __inline tilegx_bundle_bits
+create_JumpOpcodeExtension_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1f)) << 49);
+  return (((tilegx_bundle_bits)(n & 0x1)) << 58);
 }
 
-static __inline tile_bundle_bits
-create_MMStart_X0(int num)
+static __inline tilegx_bundle_bits
+create_MF_Imm14_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x1f) << 23);
+  return (((tilegx_bundle_bits)(n & 0x3fff)) << 37);
 }
 
-static __inline tile_bundle_bits
-create_MMStart_X1(int num)
+static __inline tilegx_bundle_bits
+create_MT_Imm14_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1f)) << 54);
+  return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) |
+         (((tilegx_bundle_bits)(n & 0x00003fc0)) << 37);
 }
 
-static __inline tile_bundle_bits
-create_MT_Imm15_X1(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x0000003f)) << 31) |
-         (((tile_bundle_bits)(n & 0x00003fc0)) << 37) |
-         (((tile_bundle_bits)(n & 0x00004000)) << 44);
-}
-
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Mode(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1)) << 63);
+  return (((tilegx_bundle_bits)(n & 0x3)) << 62);
 }
 
-static __inline tile_bundle_bits
-create_NoRegOpcodeExtension_SN(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return ((n & 0xf) << 0);
-}
-
-static __inline tile_bundle_bits
-create_Opcode_SN(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return ((n & 0x3f) << 10);
-}
-
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Opcode_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0x7) << 28);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Opcode_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0xf)) << 59);
+  return (((tilegx_bundle_bits)(n & 0x7)) << 59);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Opcode_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0xf) << 27);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Opcode_Y1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0xf)) << 59);
+  return (((tilegx_bundle_bits)(n & 0xf)) << 58);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Opcode_Y2(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x7)) << 56);
-}
-
-static __inline tile_bundle_bits
-create_RROpcodeExtension_SN(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return ((n & 0xf) << 4);
+  return ((n & 0x00000001) << 26) |
+         (((tilegx_bundle_bits)(n & 0x00000002)) << 56);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_RRROpcodeExtension_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x1ff) << 18);
+  return ((n & 0x3ff) << 18);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_RRROpcodeExtension_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1ff)) << 49);
+  return (((tilegx_bundle_bits)(n & 0x3ff)) << 49);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_RRROpcodeExtension_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0x3) << 18);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_RRROpcodeExtension_Y1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x3)) << 49);
+  return (((tilegx_bundle_bits)(n & 0x3)) << 49);
 }
 
-static __inline tile_bundle_bits
-create_RouteOpcodeExtension_SN(int num)
+static __inline tilegx_bundle_bits
+create_ShAmt_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x3ff) << 0);
+  return ((n & 0x3f) << 12);
 }
 
-static __inline tile_bundle_bits
-create_S_X0(int num)
+static __inline tilegx_bundle_bits
+create_ShAmt_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x1) << 27);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
 }
 
-static __inline tile_bundle_bits
-create_S_X1(int num)
+static __inline tilegx_bundle_bits
+create_ShAmt_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1)) << 58);
+  return ((n & 0x3f) << 12);
 }
 
-static __inline tile_bundle_bits
-create_ShAmt_X0(int num)
+static __inline tilegx_bundle_bits
+create_ShAmt_Y1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x1f) << 12);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
 }
 
-static __inline tile_bundle_bits
-create_ShAmt_X1(int num)
+static __inline tilegx_bundle_bits
+create_ShiftOpcodeExtension_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1f)) << 43);
+  return ((n & 0x3ff) << 18);
 }
 
-static __inline tile_bundle_bits
-create_ShAmt_Y0(int num)
+static __inline tilegx_bundle_bits
+create_ShiftOpcodeExtension_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x1f) << 12);
+  return (((tilegx_bundle_bits)(n & 0x3ff)) << 49);
 }
 
-static __inline tile_bundle_bits
-create_ShAmt_Y1(int num)
+static __inline tilegx_bundle_bits
+create_ShiftOpcodeExtension_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1f)) << 43);
+  return ((n & 0x3) << 18);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
+create_ShiftOpcodeExtension_Y1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3)) << 49);
+}
+
+static __inline tilegx_bundle_bits
 create_SrcA_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0x3f) << 6);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcA_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x3f)) << 37);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 37);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcA_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0x3f) << 6);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcA_Y1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x3f)) << 37);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 37);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcA_Y2(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x00000001) << 26) |
-         (((tile_bundle_bits)(n & 0x0000003e)) << 50);
+  return ((n & 0x3f) << 20);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcBDest_Y2(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x3f) << 20);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 51);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcB_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0x3f) << 12);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcB_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x3f)) << 43);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcB_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0x3f) << 12);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcB_Y1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x3f)) << 43);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
 }
 
-static __inline tile_bundle_bits
-create_Src_SN(int num)
+static __inline tilegx_bundle_bits
+create_UnaryOpcodeExtension_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x3) << 0);
-}
-
-static __inline tile_bundle_bits
-create_UnOpcodeExtension_X0(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return ((n & 0x1f) << 12);
-}
-
-static __inline tile_bundle_bits
-create_UnOpcodeExtension_X1(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1f)) << 43);
-}
-
-static __inline tile_bundle_bits
-create_UnOpcodeExtension_Y0(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return ((n & 0x1f) << 12);
-}
-
-static __inline tile_bundle_bits
-create_UnOpcodeExtension_Y1(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1f)) << 43);
-}
-
-static __inline tile_bundle_bits
-create_UnShOpcodeExtension_X0(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return ((n & 0x3ff) << 17);
+  return ((n & 0x3f) << 12);
 }
 
-static __inline tile_bundle_bits
-create_UnShOpcodeExtension_X1(int num)
+static __inline tilegx_bundle_bits
+create_UnaryOpcodeExtension_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x3ff)) << 48);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
 }
 
-static __inline tile_bundle_bits
-create_UnShOpcodeExtension_Y0(int num)
+static __inline tilegx_bundle_bits
+create_UnaryOpcodeExtension_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x7) << 17);
+  return ((n & 0x3f) << 12);
 }
 
-static __inline tile_bundle_bits
-create_UnShOpcodeExtension_Y1(int num)
+static __inline tilegx_bundle_bits
+create_UnaryOpcodeExtension_Y1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x7)) << 48);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
 }
 
 
-
 typedef enum
 {
-  TILE_PIPELINE_X0,
-  TILE_PIPELINE_X1,
-  TILE_PIPELINE_Y0,
-  TILE_PIPELINE_Y1,
-  TILE_PIPELINE_Y2,
-} tile_pipeline;
+  TILEGX_PIPELINE_X0,
+  TILEGX_PIPELINE_X1,
+  TILEGX_PIPELINE_Y0,
+  TILEGX_PIPELINE_Y1,
+  TILEGX_PIPELINE_Y2,
+} tilegx_pipeline;
 
-#define tile_is_x_pipeline(p) ((int)(p) <= (int)TILE_PIPELINE_X1)
+#define tilegx_is_x_pipeline(p) ((int)(p) <= (int)TILEGX_PIPELINE_X1)
 
 typedef enum
 {
-  TILE_OP_TYPE_REGISTER,
-  TILE_OP_TYPE_IMMEDIATE,
-  TILE_OP_TYPE_ADDRESS,
-  TILE_OP_TYPE_SPR
-} tile_operand_type;
+  TILEGX_OP_TYPE_REGISTER,
+  TILEGX_OP_TYPE_IMMEDIATE,
+  TILEGX_OP_TYPE_ADDRESS,
+  TILEGX_OP_TYPE_SPR
+} tilegx_operand_type;
 
-/* This is the bit that determines if a bundle is in the Y encoding. */
-#define TILE_BUNDLE_Y_ENCODING_MASK ((tile_bundle_bits)1 << 63)
+/* These are the bits that determine if a bundle is in the X encoding. */
+#define TILEGX_BUNDLE_MODE_MASK ((tilegx_bundle_bits)3 << 62)
 
 enum
 {
   /* Maximum number of instructions in a bundle (2 for X, 3 for Y). */
-  TILE_MAX_INSTRUCTIONS_PER_BUNDLE = 3,
+  TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE = 3,
 
   /* How many different pipeline encodings are there? X0, X1, Y0, Y1, Y2. */
-  TILE_NUM_PIPELINE_ENCODINGS = 5,
+  TILEGX_NUM_PIPELINE_ENCODINGS = 5,
 
-  /* Log base 2 of TILE_BUNDLE_SIZE_IN_BYTES. */
-  TILE_LOG2_BUNDLE_SIZE_IN_BYTES = 3,
+  /* Log base 2 of TILEGX_BUNDLE_SIZE_IN_BYTES. */
+  TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES = 3,
 
   /* Instructions take this many bytes. */
-  TILE_BUNDLE_SIZE_IN_BYTES = 1 << TILE_LOG2_BUNDLE_SIZE_IN_BYTES,
+  TILEGX_BUNDLE_SIZE_IN_BYTES = 1 << TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES,
 
-  /* Log base 2 of TILE_BUNDLE_ALIGNMENT_IN_BYTES. */
-  TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES = 3,
+  /* Log base 2 of TILEGX_BUNDLE_ALIGNMENT_IN_BYTES. */
+  TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES = 3,
 
   /* Bundles should be aligned modulo this number of bytes. */
-  TILE_BUNDLE_ALIGNMENT_IN_BYTES =
-    (1 << TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES),
-
-  /* Log base 2 of TILE_SN_INSTRUCTION_SIZE_IN_BYTES. */
-  TILE_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES = 1,
-
-  /* Static network instructions take this many bytes. */
-  TILE_SN_INSTRUCTION_SIZE_IN_BYTES =
-    (1 << TILE_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES),
+  TILEGX_BUNDLE_ALIGNMENT_IN_BYTES =
+    (1 << TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES),
 
   /* Number of registers (some are magic, such as network I/O). */
-  TILE_NUM_REGISTERS = 64,
-
-  /* Number of static network registers. */
-  TILE_NUM_SN_REGISTERS = 4
+  TILEGX_NUM_REGISTERS = 64,
 };
 
 
-struct tile_operand
+struct tilegx_operand
 {
   /* Is this operand a register, immediate or address? */
-  tile_operand_type type;
+  tilegx_operand_type type;
 
   /* The default relocation type for this operand.  */
   signed int default_reloc : 16;
@@ -1437,27 +1180,27 @@ struct tile_operand
   unsigned int rightshift : 2;
 
   /* Return the bits for this operand to be ORed into an existing bundle. */
-  tile_bundle_bits (*insert) (int op);
+  tilegx_bundle_bits (*insert) (int op);
 
   /* Extract this operand and return it. */
-  unsigned int (*extract) (tile_bundle_bits bundle);
+  unsigned int (*extract) (tilegx_bundle_bits bundle);
 };
 
 
-extern const struct tile_operand tile_operands[];
+extern const struct tilegx_operand tilegx_operands[];
 
 /* One finite-state machine per pipe for rapid instruction decoding. */
 extern const unsigned short * const
-tile_bundle_decoder_fsms[TILE_NUM_PIPELINE_ENCODINGS];
+tilegx_bundle_decoder_fsms[TILEGX_NUM_PIPELINE_ENCODINGS];
 
 
-struct tile_opcode
+struct tilegx_opcode
 {
   /* The opcode mnemonic, e.g. "add" */
   const char *name;
 
   /* The enum value for this mnemonic. */
-  tile_mnemonic mnemonic;
+  tilegx_mnemonic mnemonic;
 
   /* A bit mask of which of the five pipes this instruction
      is compatible with:
@@ -1478,29 +1221,28 @@ struct tile_opcode
   unsigned char can_bundle;
 
   /* The description of the operands. Each of these is an
-   * index into the tile_operands[] table. */
-  unsigned char operands[TILE_NUM_PIPELINE_ENCODINGS][TILE_MAX_OPERANDS];
+   * index into the tilegx_operands[] table. */
+  unsigned char operands[TILEGX_NUM_PIPELINE_ENCODINGS][TILEGX_MAX_OPERANDS];
 
 };
 
-extern const struct tile_opcode tile_opcodes[];
-
+extern const struct tilegx_opcode tilegx_opcodes[];
 
 /* Used for non-textual disassembly into structs. */
-struct tile_decoded_instruction
+struct tilegx_decoded_instruction
 {
-  const struct tile_opcode *opcode;
-  const struct tile_operand *operands[TILE_MAX_OPERANDS];
-  int operand_values[TILE_MAX_OPERANDS];
+  const struct tilegx_opcode *opcode;
+  const struct tilegx_operand *operands[TILEGX_MAX_OPERANDS];
+  long long operand_values[TILEGX_MAX_OPERANDS];
 };
 
 
 /* Disassemble a bundle into a struct for machine processing. */
-extern int parse_insn_tile(tile_bundle_bits bits,
-                           unsigned int pc,
-                           struct tile_decoded_instruction
-                           decoded[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]);
+extern int parse_insn_tilegx(tilegx_bundle_bits bits,
+                             unsigned long long pc,
+                             struct tilegx_decoded_instruction
+                             decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]);
 
 
 
-#endif /* opcode_tile_h */
+#endif /* opcode_tilegx_h */
index 227d033b180c16d04297fc17297cee0c8e4c0728..710192869476a5b1fb40fa2a61a4ce2623410d9d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
  *
  *   This program is free software; you can redistribute it and/or
  *   modify it under the terms of the GNU General Public License
 #define _TILE_OPCODE_CONSTANTS_H
 enum
 {
-  ADDBS_U_SPECIAL_0_OPCODE_X0 = 98,
-  ADDBS_U_SPECIAL_0_OPCODE_X1 = 68,
-  ADDB_SPECIAL_0_OPCODE_X0 = 1,
-  ADDB_SPECIAL_0_OPCODE_X1 = 1,
-  ADDHS_SPECIAL_0_OPCODE_X0 = 99,
-  ADDHS_SPECIAL_0_OPCODE_X1 = 69,
-  ADDH_SPECIAL_0_OPCODE_X0 = 2,
-  ADDH_SPECIAL_0_OPCODE_X1 = 2,
-  ADDIB_IMM_0_OPCODE_X0 = 1,
-  ADDIB_IMM_0_OPCODE_X1 = 1,
-  ADDIH_IMM_0_OPCODE_X0 = 2,
-  ADDIH_IMM_0_OPCODE_X1 = 2,
-  ADDI_IMM_0_OPCODE_X0 = 3,
-  ADDI_IMM_0_OPCODE_X1 = 3,
-  ADDI_IMM_1_OPCODE_SN = 1,
-  ADDI_OPCODE_Y0 = 9,
-  ADDI_OPCODE_Y1 = 7,
-  ADDLIS_OPCODE_X0 = 1,
-  ADDLIS_OPCODE_X1 = 2,
-  ADDLI_OPCODE_X0 = 2,
-  ADDLI_OPCODE_X1 = 3,
-  ADDS_SPECIAL_0_OPCODE_X0 = 96,
-  ADDS_SPECIAL_0_OPCODE_X1 = 66,
-  ADD_SPECIAL_0_OPCODE_X0 = 3,
-  ADD_SPECIAL_0_OPCODE_X1 = 3,
-  ADD_SPECIAL_0_OPCODE_Y0 = 0,
-  ADD_SPECIAL_0_OPCODE_Y1 = 0,
-  ADIFFB_U_SPECIAL_0_OPCODE_X0 = 4,
-  ADIFFH_SPECIAL_0_OPCODE_X0 = 5,
-  ANDI_IMM_0_OPCODE_X0 = 1,
-  ANDI_IMM_0_OPCODE_X1 = 4,
-  ANDI_OPCODE_Y0 = 10,
-  ANDI_OPCODE_Y1 = 8,
-  AND_SPECIAL_0_OPCODE_X0 = 6,
-  AND_SPECIAL_0_OPCODE_X1 = 4,
-  AND_SPECIAL_2_OPCODE_Y0 = 0,
-  AND_SPECIAL_2_OPCODE_Y1 = 0,
-  AULI_OPCODE_X0 = 3,
-  AULI_OPCODE_X1 = 4,
-  AVGB_U_SPECIAL_0_OPCODE_X0 = 7,
-  AVGH_SPECIAL_0_OPCODE_X0 = 8,
-  BBNST_BRANCH_OPCODE_X1 = 15,
-  BBNS_BRANCH_OPCODE_X1 = 14,
-  BBNS_OPCODE_SN = 63,
-  BBST_BRANCH_OPCODE_X1 = 13,
-  BBS_BRANCH_OPCODE_X1 = 12,
-  BBS_OPCODE_SN = 62,
-  BGEZT_BRANCH_OPCODE_X1 = 7,
-  BGEZ_BRANCH_OPCODE_X1 = 6,
-  BGEZ_OPCODE_SN = 61,
-  BGZT_BRANCH_OPCODE_X1 = 5,
-  BGZ_BRANCH_OPCODE_X1 = 4,
-  BGZ_OPCODE_SN = 58,
-  BITX_UN_0_SHUN_0_OPCODE_X0 = 1,
-  BITX_UN_0_SHUN_0_OPCODE_Y0 = 1,
-  BLEZT_BRANCH_OPCODE_X1 = 11,
-  BLEZ_BRANCH_OPCODE_X1 = 10,
-  BLEZ_OPCODE_SN = 59,
-  BLZT_BRANCH_OPCODE_X1 = 9,
-  BLZ_BRANCH_OPCODE_X1 = 8,
-  BLZ_OPCODE_SN = 60,
-  BNZT_BRANCH_OPCODE_X1 = 3,
-  BNZ_BRANCH_OPCODE_X1 = 2,
-  BNZ_OPCODE_SN = 57,
-  BPT_NOREG_RR_IMM_0_OPCODE_SN = 1,
-  BRANCH_OPCODE_X1 = 5,
-  BYTEX_UN_0_SHUN_0_OPCODE_X0 = 2,
-  BYTEX_UN_0_SHUN_0_OPCODE_Y0 = 2,
-  BZT_BRANCH_OPCODE_X1 = 1,
-  BZ_BRANCH_OPCODE_X1 = 0,
-  BZ_OPCODE_SN = 56,
-  CLZ_UN_0_SHUN_0_OPCODE_X0 = 3,
-  CLZ_UN_0_SHUN_0_OPCODE_Y0 = 3,
-  CRC32_32_SPECIAL_0_OPCODE_X0 = 9,
-  CRC32_8_SPECIAL_0_OPCODE_X0 = 10,
-  CTZ_UN_0_SHUN_0_OPCODE_X0 = 4,
-  CTZ_UN_0_SHUN_0_OPCODE_Y0 = 4,
-  DRAIN_UN_0_SHUN_0_OPCODE_X1 = 1,
-  DTLBPR_UN_0_SHUN_0_OPCODE_X1 = 2,
-  DWORD_ALIGN_SPECIAL_0_OPCODE_X0 = 95,
-  FINV_UN_0_SHUN_0_OPCODE_X1 = 3,
-  FLUSH_UN_0_SHUN_0_OPCODE_X1 = 4,
-  FNOP_NOREG_RR_IMM_0_OPCODE_SN = 3,
-  FNOP_UN_0_SHUN_0_OPCODE_X0 = 5,
-  FNOP_UN_0_SHUN_0_OPCODE_X1 = 5,
-  FNOP_UN_0_SHUN_0_OPCODE_Y0 = 5,
-  FNOP_UN_0_SHUN_0_OPCODE_Y1 = 1,
-  HALT_NOREG_RR_IMM_0_OPCODE_SN = 0,
-  ICOH_UN_0_SHUN_0_OPCODE_X1 = 6,
-  ILL_UN_0_SHUN_0_OPCODE_X1 = 7,
-  ILL_UN_0_SHUN_0_OPCODE_Y1 = 2,
-  IMM_0_OPCODE_SN = 0,
-  IMM_0_OPCODE_X0 = 4,
-  IMM_0_OPCODE_X1 = 6,
-  IMM_1_OPCODE_SN = 1,
-  IMM_OPCODE_0_X0 = 5,
-  INTHB_SPECIAL_0_OPCODE_X0 = 11,
-  INTHB_SPECIAL_0_OPCODE_X1 = 5,
-  INTHH_SPECIAL_0_OPCODE_X0 = 12,
-  INTHH_SPECIAL_0_OPCODE_X1 = 6,
-  INTLB_SPECIAL_0_OPCODE_X0 = 13,
-  INTLB_SPECIAL_0_OPCODE_X1 = 7,
-  INTLH_SPECIAL_0_OPCODE_X0 = 14,
-  INTLH_SPECIAL_0_OPCODE_X1 = 8,
-  INV_UN_0_SHUN_0_OPCODE_X1 = 8,
-  IRET_UN_0_SHUN_0_OPCODE_X1 = 9,
-  JALB_OPCODE_X1 = 13,
-  JALF_OPCODE_X1 = 12,
-  JALRP_SPECIAL_0_OPCODE_X1 = 9,
-  JALRR_IMM_1_OPCODE_SN = 3,
-  JALR_RR_IMM_0_OPCODE_SN = 5,
-  JALR_SPECIAL_0_OPCODE_X1 = 10,
-  JB_OPCODE_X1 = 11,
-  JF_OPCODE_X1 = 10,
-  JRP_SPECIAL_0_OPCODE_X1 = 11,
-  JRR_IMM_1_OPCODE_SN = 2,
-  JR_RR_IMM_0_OPCODE_SN = 4,
-  JR_SPECIAL_0_OPCODE_X1 = 12,
-  LBADD_IMM_0_OPCODE_X1 = 22,
-  LBADD_U_IMM_0_OPCODE_X1 = 23,
-  LB_OPCODE_Y2 = 0,
-  LB_UN_0_SHUN_0_OPCODE_X1 = 10,
-  LB_U_OPCODE_Y2 = 1,
-  LB_U_UN_0_SHUN_0_OPCODE_X1 = 11,
-  LHADD_IMM_0_OPCODE_X1 = 24,
-  LHADD_U_IMM_0_OPCODE_X1 = 25,
-  LH_OPCODE_Y2 = 2,
-  LH_UN_0_SHUN_0_OPCODE_X1 = 12,
-  LH_U_OPCODE_Y2 = 3,
-  LH_U_UN_0_SHUN_0_OPCODE_X1 = 13,
-  LNK_SPECIAL_0_OPCODE_X1 = 13,
-  LWADD_IMM_0_OPCODE_X1 = 26,
-  LWADD_NA_IMM_0_OPCODE_X1 = 27,
-  LW_NA_UN_0_SHUN_0_OPCODE_X1 = 24,
-  LW_OPCODE_Y2 = 4,
-  LW_UN_0_SHUN_0_OPCODE_X1 = 14,
-  MAXB_U_SPECIAL_0_OPCODE_X0 = 15,
-  MAXB_U_SPECIAL_0_OPCODE_X1 = 14,
-  MAXH_SPECIAL_0_OPCODE_X0 = 16,
-  MAXH_SPECIAL_0_OPCODE_X1 = 15,
-  MAXIB_U_IMM_0_OPCODE_X0 = 4,
-  MAXIB_U_IMM_0_OPCODE_X1 = 5,
-  MAXIH_IMM_0_OPCODE_X0 = 5,
-  MAXIH_IMM_0_OPCODE_X1 = 6,
-  MFSPR_IMM_0_OPCODE_X1 = 7,
-  MF_UN_0_SHUN_0_OPCODE_X1 = 15,
-  MINB_U_SPECIAL_0_OPCODE_X0 = 17,
-  MINB_U_SPECIAL_0_OPCODE_X1 = 16,
-  MINH_SPECIAL_0_OPCODE_X0 = 18,
-  MINH_SPECIAL_0_OPCODE_X1 = 17,
-  MINIB_U_IMM_0_OPCODE_X0 = 6,
-  MINIB_U_IMM_0_OPCODE_X1 = 8,
-  MINIH_IMM_0_OPCODE_X0 = 7,
-  MINIH_IMM_0_OPCODE_X1 = 9,
-  MM_OPCODE_X0 = 6,
-  MM_OPCODE_X1 = 7,
-  MNZB_SPECIAL_0_OPCODE_X0 = 19,
-  MNZB_SPECIAL_0_OPCODE_X1 = 18,
-  MNZH_SPECIAL_0_OPCODE_X0 = 20,
-  MNZH_SPECIAL_0_OPCODE_X1 = 19,
-  MNZ_SPECIAL_0_OPCODE_X0 = 21,
-  MNZ_SPECIAL_0_OPCODE_X1 = 20,
-  MNZ_SPECIAL_1_OPCODE_Y0 = 0,
-  MNZ_SPECIAL_1_OPCODE_Y1 = 1,
-  MOVEI_IMM_1_OPCODE_SN = 0,
-  MOVE_RR_IMM_0_OPCODE_SN = 8,
-  MTSPR_IMM_0_OPCODE_X1 = 10,
-  MULHHA_SS_SPECIAL_0_OPCODE_X0 = 22,
-  MULHHA_SS_SPECIAL_7_OPCODE_Y0 = 0,
-  MULHHA_SU_SPECIAL_0_OPCODE_X0 = 23,
-  MULHHA_UU_SPECIAL_0_OPCODE_X0 = 24,
-  MULHHA_UU_SPECIAL_7_OPCODE_Y0 = 1,
-  MULHHSA_UU_SPECIAL_0_OPCODE_X0 = 25,
-  MULHH_SS_SPECIAL_0_OPCODE_X0 = 26,
-  MULHH_SS_SPECIAL_6_OPCODE_Y0 = 0,
-  MULHH_SU_SPECIAL_0_OPCODE_X0 = 27,
-  MULHH_UU_SPECIAL_0_OPCODE_X0 = 28,
-  MULHH_UU_SPECIAL_6_OPCODE_Y0 = 1,
-  MULHLA_SS_SPECIAL_0_OPCODE_X0 = 29,
-  MULHLA_SU_SPECIAL_0_OPCODE_X0 = 30,
-  MULHLA_US_SPECIAL_0_OPCODE_X0 = 31,
-  MULHLA_UU_SPECIAL_0_OPCODE_X0 = 32,
-  MULHLSA_UU_SPECIAL_0_OPCODE_X0 = 33,
-  MULHLSA_UU_SPECIAL_5_OPCODE_Y0 = 0,
-  MULHL_SS_SPECIAL_0_OPCODE_X0 = 34,
-  MULHL_SU_SPECIAL_0_OPCODE_X0 = 35,
-  MULHL_US_SPECIAL_0_OPCODE_X0 = 36,
-  MULHL_UU_SPECIAL_0_OPCODE_X0 = 37,
-  MULLLA_SS_SPECIAL_0_OPCODE_X0 = 38,
-  MULLLA_SS_SPECIAL_7_OPCODE_Y0 = 2,
-  MULLLA_SU_SPECIAL_0_OPCODE_X0 = 39,
-  MULLLA_UU_SPECIAL_0_OPCODE_X0 = 40,
-  MULLLA_UU_SPECIAL_7_OPCODE_Y0 = 3,
-  MULLLSA_UU_SPECIAL_0_OPCODE_X0 = 41,
-  MULLL_SS_SPECIAL_0_OPCODE_X0 = 42,
-  MULLL_SS_SPECIAL_6_OPCODE_Y0 = 2,
-  MULLL_SU_SPECIAL_0_OPCODE_X0 = 43,
-  MULLL_UU_SPECIAL_0_OPCODE_X0 = 44,
-  MULLL_UU_SPECIAL_6_OPCODE_Y0 = 3,
-  MVNZ_SPECIAL_0_OPCODE_X0 = 45,
-  MVNZ_SPECIAL_1_OPCODE_Y0 = 1,
-  MVZ_SPECIAL_0_OPCODE_X0 = 46,
-  MVZ_SPECIAL_1_OPCODE_Y0 = 2,
-  MZB_SPECIAL_0_OPCODE_X0 = 47,
-  MZB_SPECIAL_0_OPCODE_X1 = 21,
-  MZH_SPECIAL_0_OPCODE_X0 = 48,
-  MZH_SPECIAL_0_OPCODE_X1 = 22,
-  MZ_SPECIAL_0_OPCODE_X0 = 49,
-  MZ_SPECIAL_0_OPCODE_X1 = 23,
-  MZ_SPECIAL_1_OPCODE_Y0 = 3,
-  MZ_SPECIAL_1_OPCODE_Y1 = 2,
-  NAP_UN_0_SHUN_0_OPCODE_X1 = 16,
-  NOP_NOREG_RR_IMM_0_OPCODE_SN = 2,
-  NOP_UN_0_SHUN_0_OPCODE_X0 = 6,
-  NOP_UN_0_SHUN_0_OPCODE_X1 = 17,
-  NOP_UN_0_SHUN_0_OPCODE_Y0 = 6,
-  NOP_UN_0_SHUN_0_OPCODE_Y1 = 3,
-  NOREG_RR_IMM_0_OPCODE_SN = 0,
-  NOR_SPECIAL_0_OPCODE_X0 = 50,
-  NOR_SPECIAL_0_OPCODE_X1 = 24,
-  NOR_SPECIAL_2_OPCODE_Y0 = 1,
-  NOR_SPECIAL_2_OPCODE_Y1 = 1,
-  ORI_IMM_0_OPCODE_X0 = 8,
-  ORI_IMM_0_OPCODE_X1 = 11,
-  ORI_OPCODE_Y0 = 11,
-  ORI_OPCODE_Y1 = 9,
-  OR_SPECIAL_0_OPCODE_X0 = 51,
-  OR_SPECIAL_0_OPCODE_X1 = 25,
-  OR_SPECIAL_2_OPCODE_Y0 = 2,
-  OR_SPECIAL_2_OPCODE_Y1 = 2,
-  PACKBS_U_SPECIAL_0_OPCODE_X0 = 103,
-  PACKBS_U_SPECIAL_0_OPCODE_X1 = 73,
-  PACKHB_SPECIAL_0_OPCODE_X0 = 52,
-  PACKHB_SPECIAL_0_OPCODE_X1 = 26,
-  PACKHS_SPECIAL_0_OPCODE_X0 = 102,
-  PACKHS_SPECIAL_0_OPCODE_X1 = 72,
-  PACKLB_SPECIAL_0_OPCODE_X0 = 53,
-  PACKLB_SPECIAL_0_OPCODE_X1 = 27,
-  PCNT_UN_0_SHUN_0_OPCODE_X0 = 7,
-  PCNT_UN_0_SHUN_0_OPCODE_Y0 = 7,
-  RLI_SHUN_0_OPCODE_X0 = 1,
-  RLI_SHUN_0_OPCODE_X1 = 1,
-  RLI_SHUN_0_OPCODE_Y0 = 1,
-  RLI_SHUN_0_OPCODE_Y1 = 1,
-  RL_SPECIAL_0_OPCODE_X0 = 54,
-  RL_SPECIAL_0_OPCODE_X1 = 28,
-  RL_SPECIAL_3_OPCODE_Y0 = 0,
-  RL_SPECIAL_3_OPCODE_Y1 = 0,
-  RR_IMM_0_OPCODE_SN = 0,
-  S1A_SPECIAL_0_OPCODE_X0 = 55,
-  S1A_SPECIAL_0_OPCODE_X1 = 29,
-  S1A_SPECIAL_0_OPCODE_Y0 = 1,
-  S1A_SPECIAL_0_OPCODE_Y1 = 1,
-  S2A_SPECIAL_0_OPCODE_X0 = 56,
-  S2A_SPECIAL_0_OPCODE_X1 = 30,
-  S2A_SPECIAL_0_OPCODE_Y0 = 2,
-  S2A_SPECIAL_0_OPCODE_Y1 = 2,
-  S3A_SPECIAL_0_OPCODE_X0 = 57,
-  S3A_SPECIAL_0_OPCODE_X1 = 31,
-  S3A_SPECIAL_5_OPCODE_Y0 = 1,
-  S3A_SPECIAL_5_OPCODE_Y1 = 1,
-  SADAB_U_SPECIAL_0_OPCODE_X0 = 58,
-  SADAH_SPECIAL_0_OPCODE_X0 = 59,
-  SADAH_U_SPECIAL_0_OPCODE_X0 = 60,
-  SADB_U_SPECIAL_0_OPCODE_X0 = 61,
-  SADH_SPECIAL_0_OPCODE_X0 = 62,
-  SADH_U_SPECIAL_0_OPCODE_X0 = 63,
-  SBADD_IMM_0_OPCODE_X1 = 28,
-  SB_OPCODE_Y2 = 5,
-  SB_SPECIAL_0_OPCODE_X1 = 32,
-  SEQB_SPECIAL_0_OPCODE_X0 = 64,
-  SEQB_SPECIAL_0_OPCODE_X1 = 33,
-  SEQH_SPECIAL_0_OPCODE_X0 = 65,
-  SEQH_SPECIAL_0_OPCODE_X1 = 34,
-  SEQIB_IMM_0_OPCODE_X0 = 9,
-  SEQIB_IMM_0_OPCODE_X1 = 12,
-  SEQIH_IMM_0_OPCODE_X0 = 10,
-  SEQIH_IMM_0_OPCODE_X1 = 13,
-  SEQI_IMM_0_OPCODE_X0 = 11,
-  SEQI_IMM_0_OPCODE_X1 = 14,
-  SEQI_OPCODE_Y0 = 12,
-  SEQI_OPCODE_Y1 = 10,
-  SEQ_SPECIAL_0_OPCODE_X0 = 66,
-  SEQ_SPECIAL_0_OPCODE_X1 = 35,
-  SEQ_SPECIAL_5_OPCODE_Y0 = 2,
-  SEQ_SPECIAL_5_OPCODE_Y1 = 2,
-  SHADD_IMM_0_OPCODE_X1 = 29,
-  SHL8II_IMM_0_OPCODE_SN = 3,
-  SHLB_SPECIAL_0_OPCODE_X0 = 67,
-  SHLB_SPECIAL_0_OPCODE_X1 = 36,
-  SHLH_SPECIAL_0_OPCODE_X0 = 68,
-  SHLH_SPECIAL_0_OPCODE_X1 = 37,
-  SHLIB_SHUN_0_OPCODE_X0 = 2,
-  SHLIB_SHUN_0_OPCODE_X1 = 2,
-  SHLIH_SHUN_0_OPCODE_X0 = 3,
-  SHLIH_SHUN_0_OPCODE_X1 = 3,
-  SHLI_SHUN_0_OPCODE_X0 = 4,
-  SHLI_SHUN_0_OPCODE_X1 = 4,
-  SHLI_SHUN_0_OPCODE_Y0 = 2,
-  SHLI_SHUN_0_OPCODE_Y1 = 2,
-  SHL_SPECIAL_0_OPCODE_X0 = 69,
-  SHL_SPECIAL_0_OPCODE_X1 = 38,
-  SHL_SPECIAL_3_OPCODE_Y0 = 1,
-  SHL_SPECIAL_3_OPCODE_Y1 = 1,
-  SHR1_RR_IMM_0_OPCODE_SN = 9,
-  SHRB_SPECIAL_0_OPCODE_X0 = 70,
-  SHRB_SPECIAL_0_OPCODE_X1 = 39,
-  SHRH_SPECIAL_0_OPCODE_X0 = 71,
-  SHRH_SPECIAL_0_OPCODE_X1 = 40,
-  SHRIB_SHUN_0_OPCODE_X0 = 5,
-  SHRIB_SHUN_0_OPCODE_X1 = 5,
-  SHRIH_SHUN_0_OPCODE_X0 = 6,
-  SHRIH_SHUN_0_OPCODE_X1 = 6,
-  SHRI_SHUN_0_OPCODE_X0 = 7,
-  SHRI_SHUN_0_OPCODE_X1 = 7,
-  SHRI_SHUN_0_OPCODE_Y0 = 3,
-  SHRI_SHUN_0_OPCODE_Y1 = 3,
-  SHR_SPECIAL_0_OPCODE_X0 = 72,
-  SHR_SPECIAL_0_OPCODE_X1 = 41,
-  SHR_SPECIAL_3_OPCODE_Y0 = 2,
-  SHR_SPECIAL_3_OPCODE_Y1 = 2,
-  SHUN_0_OPCODE_X0 = 7,
-  SHUN_0_OPCODE_X1 = 8,
-  SHUN_0_OPCODE_Y0 = 13,
-  SHUN_0_OPCODE_Y1 = 11,
-  SH_OPCODE_Y2 = 6,
-  SH_SPECIAL_0_OPCODE_X1 = 42,
-  SLTB_SPECIAL_0_OPCODE_X0 = 73,
-  SLTB_SPECIAL_0_OPCODE_X1 = 43,
-  SLTB_U_SPECIAL_0_OPCODE_X0 = 74,
-  SLTB_U_SPECIAL_0_OPCODE_X1 = 44,
-  SLTEB_SPECIAL_0_OPCODE_X0 = 75,
-  SLTEB_SPECIAL_0_OPCODE_X1 = 45,
-  SLTEB_U_SPECIAL_0_OPCODE_X0 = 76,
-  SLTEB_U_SPECIAL_0_OPCODE_X1 = 46,
-  SLTEH_SPECIAL_0_OPCODE_X0 = 77,
-  SLTEH_SPECIAL_0_OPCODE_X1 = 47,
-  SLTEH_U_SPECIAL_0_OPCODE_X0 = 78,
-  SLTEH_U_SPECIAL_0_OPCODE_X1 = 48,
-  SLTE_SPECIAL_0_OPCODE_X0 = 79,
-  SLTE_SPECIAL_0_OPCODE_X1 = 49,
-  SLTE_SPECIAL_4_OPCODE_Y0 = 0,
-  SLTE_SPECIAL_4_OPCODE_Y1 = 0,
-  SLTE_U_SPECIAL_0_OPCODE_X0 = 80,
-  SLTE_U_SPECIAL_0_OPCODE_X1 = 50,
-  SLTE_U_SPECIAL_4_OPCODE_Y0 = 1,
-  SLTE_U_SPECIAL_4_OPCODE_Y1 = 1,
-  SLTH_SPECIAL_0_OPCODE_X0 = 81,
-  SLTH_SPECIAL_0_OPCODE_X1 = 51,
-  SLTH_U_SPECIAL_0_OPCODE_X0 = 82,
-  SLTH_U_SPECIAL_0_OPCODE_X1 = 52,
-  SLTIB_IMM_0_OPCODE_X0 = 12,
-  SLTIB_IMM_0_OPCODE_X1 = 15,
-  SLTIB_U_IMM_0_OPCODE_X0 = 13,
-  SLTIB_U_IMM_0_OPCODE_X1 = 16,
-  SLTIH_IMM_0_OPCODE_X0 = 14,
-  SLTIH_IMM_0_OPCODE_X1 = 17,
-  SLTIH_U_IMM_0_OPCODE_X0 = 15,
-  SLTIH_U_IMM_0_OPCODE_X1 = 18,
-  SLTI_IMM_0_OPCODE_X0 = 16,
-  SLTI_IMM_0_OPCODE_X1 = 19,
-  SLTI_OPCODE_Y0 = 14,
-  SLTI_OPCODE_Y1 = 12,
-  SLTI_U_IMM_0_OPCODE_X0 = 17,
-  SLTI_U_IMM_0_OPCODE_X1 = 20,
-  SLTI_U_OPCODE_Y0 = 15,
-  SLTI_U_OPCODE_Y1 = 13,
-  SLT_SPECIAL_0_OPCODE_X0 = 83,
-  SLT_SPECIAL_0_OPCODE_X1 = 53,
-  SLT_SPECIAL_4_OPCODE_Y0 = 2,
-  SLT_SPECIAL_4_OPCODE_Y1 = 2,
-  SLT_U_SPECIAL_0_OPCODE_X0 = 84,
-  SLT_U_SPECIAL_0_OPCODE_X1 = 54,
-  SLT_U_SPECIAL_4_OPCODE_Y0 = 3,
-  SLT_U_SPECIAL_4_OPCODE_Y1 = 3,
-  SNEB_SPECIAL_0_OPCODE_X0 = 85,
-  SNEB_SPECIAL_0_OPCODE_X1 = 55,
-  SNEH_SPECIAL_0_OPCODE_X0 = 86,
-  SNEH_SPECIAL_0_OPCODE_X1 = 56,
-  SNE_SPECIAL_0_OPCODE_X0 = 87,
-  SNE_SPECIAL_0_OPCODE_X1 = 57,
-  SNE_SPECIAL_5_OPCODE_Y0 = 3,
-  SNE_SPECIAL_5_OPCODE_Y1 = 3,
-  SPECIAL_0_OPCODE_X0 = 0,
-  SPECIAL_0_OPCODE_X1 = 1,
-  SPECIAL_0_OPCODE_Y0 = 1,
-  SPECIAL_0_OPCODE_Y1 = 1,
-  SPECIAL_1_OPCODE_Y0 = 2,
-  SPECIAL_1_OPCODE_Y1 = 2,
-  SPECIAL_2_OPCODE_Y0 = 3,
-  SPECIAL_2_OPCODE_Y1 = 3,
-  SPECIAL_3_OPCODE_Y0 = 4,
-  SPECIAL_3_OPCODE_Y1 = 4,
-  SPECIAL_4_OPCODE_Y0 = 5,
-  SPECIAL_4_OPCODE_Y1 = 5,
-  SPECIAL_5_OPCODE_Y0 = 6,
-  SPECIAL_5_OPCODE_Y1 = 6,
-  SPECIAL_6_OPCODE_Y0 = 7,
-  SPECIAL_7_OPCODE_Y0 = 8,
-  SRAB_SPECIAL_0_OPCODE_X0 = 88,
-  SRAB_SPECIAL_0_OPCODE_X1 = 58,
-  SRAH_SPECIAL_0_OPCODE_X0 = 89,
-  SRAH_SPECIAL_0_OPCODE_X1 = 59,
-  SRAIB_SHUN_0_OPCODE_X0 = 8,
-  SRAIB_SHUN_0_OPCODE_X1 = 8,
-  SRAIH_SHUN_0_OPCODE_X0 = 9,
-  SRAIH_SHUN_0_OPCODE_X1 = 9,
-  SRAI_SHUN_0_OPCODE_X0 = 10,
-  SRAI_SHUN_0_OPCODE_X1 = 10,
-  SRAI_SHUN_0_OPCODE_Y0 = 4,
-  SRAI_SHUN_0_OPCODE_Y1 = 4,
-  SRA_SPECIAL_0_OPCODE_X0 = 90,
-  SRA_SPECIAL_0_OPCODE_X1 = 60,
-  SRA_SPECIAL_3_OPCODE_Y0 = 3,
-  SRA_SPECIAL_3_OPCODE_Y1 = 3,
-  SUBBS_U_SPECIAL_0_OPCODE_X0 = 100,
-  SUBBS_U_SPECIAL_0_OPCODE_X1 = 70,
-  SUBB_SPECIAL_0_OPCODE_X0 = 91,
-  SUBB_SPECIAL_0_OPCODE_X1 = 61,
-  SUBHS_SPECIAL_0_OPCODE_X0 = 101,
-  SUBHS_SPECIAL_0_OPCODE_X1 = 71,
-  SUBH_SPECIAL_0_OPCODE_X0 = 92,
-  SUBH_SPECIAL_0_OPCODE_X1 = 62,
-  SUBS_SPECIAL_0_OPCODE_X0 = 97,
-  SUBS_SPECIAL_0_OPCODE_X1 = 67,
-  SUB_SPECIAL_0_OPCODE_X0 = 93,
-  SUB_SPECIAL_0_OPCODE_X1 = 63,
-  SUB_SPECIAL_0_OPCODE_Y0 = 3,
-  SUB_SPECIAL_0_OPCODE_Y1 = 3,
-  SWADD_IMM_0_OPCODE_X1 = 30,
-  SWINT0_UN_0_SHUN_0_OPCODE_X1 = 18,
-  SWINT1_UN_0_SHUN_0_OPCODE_X1 = 19,
-  SWINT2_UN_0_SHUN_0_OPCODE_X1 = 20,
-  SWINT3_UN_0_SHUN_0_OPCODE_X1 = 21,
-  SW_OPCODE_Y2 = 7,
-  SW_SPECIAL_0_OPCODE_X1 = 64,
-  TBLIDXB0_UN_0_SHUN_0_OPCODE_X0 = 8,
-  TBLIDXB0_UN_0_SHUN_0_OPCODE_Y0 = 8,
-  TBLIDXB1_UN_0_SHUN_0_OPCODE_X0 = 9,
-  TBLIDXB1_UN_0_SHUN_0_OPCODE_Y0 = 9,
-  TBLIDXB2_UN_0_SHUN_0_OPCODE_X0 = 10,
-  TBLIDXB2_UN_0_SHUN_0_OPCODE_Y0 = 10,
-  TBLIDXB3_UN_0_SHUN_0_OPCODE_X0 = 11,
-  TBLIDXB3_UN_0_SHUN_0_OPCODE_Y0 = 11,
-  TNS_UN_0_SHUN_0_OPCODE_X1 = 22,
-  UN_0_SHUN_0_OPCODE_X0 = 11,
-  UN_0_SHUN_0_OPCODE_X1 = 11,
-  UN_0_SHUN_0_OPCODE_Y0 = 5,
-  UN_0_SHUN_0_OPCODE_Y1 = 5,
-  WH64_UN_0_SHUN_0_OPCODE_X1 = 23,
-  XORI_IMM_0_OPCODE_X0 = 2,
-  XORI_IMM_0_OPCODE_X1 = 21,
-  XOR_SPECIAL_0_OPCODE_X0 = 94,
-  XOR_SPECIAL_0_OPCODE_X1 = 65,
-  XOR_SPECIAL_2_OPCODE_Y0 = 3,
-  XOR_SPECIAL_2_OPCODE_Y1 = 3
+  ADDI_IMM8_OPCODE_X0 = 1,
+  ADDI_IMM8_OPCODE_X1 = 1,
+  ADDI_OPCODE_Y0 = 0,
+  ADDI_OPCODE_Y1 = 1,
+  ADDLI_OPCODE_X0 = 1,
+  ADDLI_OPCODE_X1 = 0,
+  ADDXI_IMM8_OPCODE_X0 = 2,
+  ADDXI_IMM8_OPCODE_X1 = 2,
+  ADDXI_OPCODE_Y0 = 1,
+  ADDXI_OPCODE_Y1 = 2,
+  ADDXLI_OPCODE_X0 = 2,
+  ADDXLI_OPCODE_X1 = 1,
+  ADDXSC_RRR_0_OPCODE_X0 = 1,
+  ADDXSC_RRR_0_OPCODE_X1 = 1,
+  ADDX_RRR_0_OPCODE_X0 = 2,
+  ADDX_RRR_0_OPCODE_X1 = 2,
+  ADDX_RRR_0_OPCODE_Y0 = 0,
+  ADDX_SPECIAL_0_OPCODE_Y1 = 0,
+  ADD_RRR_0_OPCODE_X0 = 3,
+  ADD_RRR_0_OPCODE_X1 = 3,
+  ADD_RRR_0_OPCODE_Y0 = 1,
+  ADD_SPECIAL_0_OPCODE_Y1 = 1,
+  ANDI_IMM8_OPCODE_X0 = 3,
+  ANDI_IMM8_OPCODE_X1 = 3,
+  ANDI_OPCODE_Y0 = 2,
+  ANDI_OPCODE_Y1 = 3,
+  AND_RRR_0_OPCODE_X0 = 4,
+  AND_RRR_0_OPCODE_X1 = 4,
+  AND_RRR_5_OPCODE_Y0 = 0,
+  AND_RRR_5_OPCODE_Y1 = 0,
+  BEQZT_BRANCH_OPCODE_X1 = 16,
+  BEQZ_BRANCH_OPCODE_X1 = 17,
+  BFEXTS_BF_OPCODE_X0 = 4,
+  BFEXTU_BF_OPCODE_X0 = 5,
+  BFINS_BF_OPCODE_X0 = 6,
+  BF_OPCODE_X0 = 3,
+  BGEZT_BRANCH_OPCODE_X1 = 18,
+  BGEZ_BRANCH_OPCODE_X1 = 19,
+  BGTZT_BRANCH_OPCODE_X1 = 20,
+  BGTZ_BRANCH_OPCODE_X1 = 21,
+  BLBCT_BRANCH_OPCODE_X1 = 22,
+  BLBC_BRANCH_OPCODE_X1 = 23,
+  BLBST_BRANCH_OPCODE_X1 = 24,
+  BLBS_BRANCH_OPCODE_X1 = 25,
+  BLEZT_BRANCH_OPCODE_X1 = 26,
+  BLEZ_BRANCH_OPCODE_X1 = 27,
+  BLTZT_BRANCH_OPCODE_X1 = 28,
+  BLTZ_BRANCH_OPCODE_X1 = 29,
+  BNEZT_BRANCH_OPCODE_X1 = 30,
+  BNEZ_BRANCH_OPCODE_X1 = 31,
+  BRANCH_OPCODE_X1 = 2,
+  CMOVEQZ_RRR_0_OPCODE_X0 = 5,
+  CMOVEQZ_RRR_4_OPCODE_Y0 = 0,
+  CMOVNEZ_RRR_0_OPCODE_X0 = 6,
+  CMOVNEZ_RRR_4_OPCODE_Y0 = 1,
+  CMPEQI_IMM8_OPCODE_X0 = 4,
+  CMPEQI_IMM8_OPCODE_X1 = 4,
+  CMPEQI_OPCODE_Y0 = 3,
+  CMPEQI_OPCODE_Y1 = 4,
+  CMPEQ_RRR_0_OPCODE_X0 = 7,
+  CMPEQ_RRR_0_OPCODE_X1 = 5,
+  CMPEQ_RRR_3_OPCODE_Y0 = 0,
+  CMPEQ_RRR_3_OPCODE_Y1 = 2,
+  CMPEXCH4_RRR_0_OPCODE_X1 = 6,
+  CMPEXCH_RRR_0_OPCODE_X1 = 7,
+  CMPLES_RRR_0_OPCODE_X0 = 8,
+  CMPLES_RRR_0_OPCODE_X1 = 8,
+  CMPLES_RRR_2_OPCODE_Y0 = 0,
+  CMPLES_RRR_2_OPCODE_Y1 = 0,
+  CMPLEU_RRR_0_OPCODE_X0 = 9,
+  CMPLEU_RRR_0_OPCODE_X1 = 9,
+  CMPLEU_RRR_2_OPCODE_Y0 = 1,
+  CMPLEU_RRR_2_OPCODE_Y1 = 1,
+  CMPLTSI_IMM8_OPCODE_X0 = 5,
+  CMPLTSI_IMM8_OPCODE_X1 = 5,
+  CMPLTSI_OPCODE_Y0 = 4,
+  CMPLTSI_OPCODE_Y1 = 5,
+  CMPLTS_RRR_0_OPCODE_X0 = 10,
+  CMPLTS_RRR_0_OPCODE_X1 = 10,
+  CMPLTS_RRR_2_OPCODE_Y0 = 2,
+  CMPLTS_RRR_2_OPCODE_Y1 = 2,
+  CMPLTUI_IMM8_OPCODE_X0 = 6,
+  CMPLTUI_IMM8_OPCODE_X1 = 6,
+  CMPLTU_RRR_0_OPCODE_X0 = 11,
+  CMPLTU_RRR_0_OPCODE_X1 = 11,
+  CMPLTU_RRR_2_OPCODE_Y0 = 3,
+  CMPLTU_RRR_2_OPCODE_Y1 = 3,
+  CMPNE_RRR_0_OPCODE_X0 = 12,
+  CMPNE_RRR_0_OPCODE_X1 = 12,
+  CMPNE_RRR_3_OPCODE_Y0 = 1,
+  CMPNE_RRR_3_OPCODE_Y1 = 3,
+  CMULAF_RRR_0_OPCODE_X0 = 13,
+  CMULA_RRR_0_OPCODE_X0 = 14,
+  CMULFR_RRR_0_OPCODE_X0 = 15,
+  CMULF_RRR_0_OPCODE_X0 = 16,
+  CMULHR_RRR_0_OPCODE_X0 = 17,
+  CMULH_RRR_0_OPCODE_X0 = 18,
+  CMUL_RRR_0_OPCODE_X0 = 19,
+  CNTLZ_UNARY_OPCODE_X0 = 1,
+  CNTLZ_UNARY_OPCODE_Y0 = 1,
+  CNTTZ_UNARY_OPCODE_X0 = 2,
+  CNTTZ_UNARY_OPCODE_Y0 = 2,
+  CRC32_32_RRR_0_OPCODE_X0 = 20,
+  CRC32_8_RRR_0_OPCODE_X0 = 21,
+  DBLALIGN2_RRR_0_OPCODE_X0 = 22,
+  DBLALIGN2_RRR_0_OPCODE_X1 = 13,
+  DBLALIGN4_RRR_0_OPCODE_X0 = 23,
+  DBLALIGN4_RRR_0_OPCODE_X1 = 14,
+  DBLALIGN6_RRR_0_OPCODE_X0 = 24,
+  DBLALIGN6_RRR_0_OPCODE_X1 = 15,
+  DBLALIGN_RRR_0_OPCODE_X0 = 25,
+  DRAIN_UNARY_OPCODE_X1 = 1,
+  DTLBPR_UNARY_OPCODE_X1 = 2,
+  EXCH4_RRR_0_OPCODE_X1 = 16,
+  EXCH_RRR_0_OPCODE_X1 = 17,
+  FDOUBLE_ADDSUB_RRR_0_OPCODE_X0 = 26,
+  FDOUBLE_ADD_FLAGS_RRR_0_OPCODE_X0 = 27,
+  FDOUBLE_MUL_FLAGS_RRR_0_OPCODE_X0 = 28,
+  FDOUBLE_PACK1_RRR_0_OPCODE_X0 = 29,
+  FDOUBLE_PACK2_RRR_0_OPCODE_X0 = 30,
+  FDOUBLE_SUB_FLAGS_RRR_0_OPCODE_X0 = 31,
+  FDOUBLE_UNPACK_MAX_RRR_0_OPCODE_X0 = 32,
+  FDOUBLE_UNPACK_MIN_RRR_0_OPCODE_X0 = 33,
+  FETCHADD4_RRR_0_OPCODE_X1 = 18,
+  FETCHADDGEZ4_RRR_0_OPCODE_X1 = 19,
+  FETCHADDGEZ_RRR_0_OPCODE_X1 = 20,
+  FETCHADD_RRR_0_OPCODE_X1 = 21,
+  FETCHAND4_RRR_0_OPCODE_X1 = 22,
+  FETCHAND_RRR_0_OPCODE_X1 = 23,
+  FETCHOR4_RRR_0_OPCODE_X1 = 24,
+  FETCHOR_RRR_0_OPCODE_X1 = 25,
+  FINV_UNARY_OPCODE_X1 = 3,
+  FLUSHWB_UNARY_OPCODE_X1 = 4,
+  FLUSH_UNARY_OPCODE_X1 = 5,
+  FNOP_UNARY_OPCODE_X0 = 3,
+  FNOP_UNARY_OPCODE_X1 = 6,
+  FNOP_UNARY_OPCODE_Y0 = 3,
+  FNOP_UNARY_OPCODE_Y1 = 8,
+  FSINGLE_ADD1_RRR_0_OPCODE_X0 = 34,
+  FSINGLE_ADDSUB2_RRR_0_OPCODE_X0 = 35,
+  FSINGLE_MUL1_RRR_0_OPCODE_X0 = 36,
+  FSINGLE_MUL2_RRR_0_OPCODE_X0 = 37,
+  FSINGLE_PACK1_UNARY_OPCODE_X0 = 4,
+  FSINGLE_PACK1_UNARY_OPCODE_Y0 = 4,
+  FSINGLE_PACK2_RRR_0_OPCODE_X0 = 38,
+  FSINGLE_SUB1_RRR_0_OPCODE_X0 = 39,
+  ICOH_UNARY_OPCODE_X1 = 7,
+  ILL_UNARY_OPCODE_X1 = 8,
+  ILL_UNARY_OPCODE_Y1 = 9,
+  IMM8_OPCODE_X0 = 4,
+  IMM8_OPCODE_X1 = 3,
+  INV_UNARY_OPCODE_X1 = 9,
+  IRET_UNARY_OPCODE_X1 = 10,
+  JALRP_UNARY_OPCODE_X1 = 11,
+  JALRP_UNARY_OPCODE_Y1 = 10,
+  JALR_UNARY_OPCODE_X1 = 12,
+  JALR_UNARY_OPCODE_Y1 = 11,
+  JAL_JUMP_OPCODE_X1 = 0,
+  JRP_UNARY_OPCODE_X1 = 13,
+  JRP_UNARY_OPCODE_Y1 = 12,
+  JR_UNARY_OPCODE_X1 = 14,
+  JR_UNARY_OPCODE_Y1 = 13,
+  JUMP_OPCODE_X1 = 4,
+  J_JUMP_OPCODE_X1 = 1,
+  LD1S_ADD_IMM8_OPCODE_X1 = 7,
+  LD1S_OPCODE_Y2 = 0,
+  LD1S_UNARY_OPCODE_X1 = 15,
+  LD1U_ADD_IMM8_OPCODE_X1 = 8,
+  LD1U_OPCODE_Y2 = 1,
+  LD1U_UNARY_OPCODE_X1 = 16,
+  LD2S_ADD_IMM8_OPCODE_X1 = 9,
+  LD2S_OPCODE_Y2 = 2,
+  LD2S_UNARY_OPCODE_X1 = 17,
+  LD2U_ADD_IMM8_OPCODE_X1 = 10,
+  LD2U_OPCODE_Y2 = 3,
+  LD2U_UNARY_OPCODE_X1 = 18,
+  LD4S_ADD_IMM8_OPCODE_X1 = 11,
+  LD4S_OPCODE_Y2 = 1,
+  LD4S_UNARY_OPCODE_X1 = 19,
+  LD4U_ADD_IMM8_OPCODE_X1 = 12,
+  LD4U_OPCODE_Y2 = 2,
+  LD4U_UNARY_OPCODE_X1 = 20,
+  LDNA_UNARY_OPCODE_X1 = 21,
+  LDNT1S_ADD_IMM8_OPCODE_X1 = 13,
+  LDNT1S_UNARY_OPCODE_X1 = 22,
+  LDNT1U_ADD_IMM8_OPCODE_X1 = 14,
+  LDNT1U_UNARY_OPCODE_X1 = 23,
+  LDNT2S_ADD_IMM8_OPCODE_X1 = 15,
+  LDNT2S_UNARY_OPCODE_X1 = 24,
+  LDNT2U_ADD_IMM8_OPCODE_X1 = 16,
+  LDNT2U_UNARY_OPCODE_X1 = 25,
+  LDNT4S_ADD_IMM8_OPCODE_X1 = 17,
+  LDNT4S_UNARY_OPCODE_X1 = 26,
+  LDNT4U_ADD_IMM8_OPCODE_X1 = 18,
+  LDNT4U_UNARY_OPCODE_X1 = 27,
+  LDNT_ADD_IMM8_OPCODE_X1 = 19,
+  LDNT_UNARY_OPCODE_X1 = 28,
+  LD_ADD_IMM8_OPCODE_X1 = 20,
+  LD_OPCODE_Y2 = 3,
+  LD_UNARY_OPCODE_X1 = 29,
+  LNK_UNARY_OPCODE_X1 = 30,
+  LNK_UNARY_OPCODE_Y1 = 14,
+  LWNA_ADD_IMM8_OPCODE_X1 = 21,
+  MFSPR_IMM8_OPCODE_X1 = 22,
+  MF_UNARY_OPCODE_X1 = 31,
+  MM_BF_OPCODE_X0 = 7,
+  MNZ_RRR_0_OPCODE_X0 = 40,
+  MNZ_RRR_0_OPCODE_X1 = 26,
+  MNZ_RRR_4_OPCODE_Y0 = 2,
+  MNZ_RRR_4_OPCODE_Y1 = 2,
+  MODE_OPCODE_YA2 = 1,
+  MODE_OPCODE_YB2 = 2,
+  MODE_OPCODE_YC2 = 3,
+  MTSPR_IMM8_OPCODE_X1 = 23,
+  MULAX_RRR_0_OPCODE_X0 = 41,
+  MULAX_RRR_3_OPCODE_Y0 = 2,
+  MULA_HS_HS_RRR_0_OPCODE_X0 = 42,
+  MULA_HS_HS_RRR_9_OPCODE_Y0 = 0,
+  MULA_HS_HU_RRR_0_OPCODE_X0 = 43,
+  MULA_HS_LS_RRR_0_OPCODE_X0 = 44,
+  MULA_HS_LU_RRR_0_OPCODE_X0 = 45,
+  MULA_HU_HU_RRR_0_OPCODE_X0 = 46,
+  MULA_HU_HU_RRR_9_OPCODE_Y0 = 1,
+  MULA_HU_LS_RRR_0_OPCODE_X0 = 47,
+  MULA_HU_LU_RRR_0_OPCODE_X0 = 48,
+  MULA_LS_LS_RRR_0_OPCODE_X0 = 49,
+  MULA_LS_LS_RRR_9_OPCODE_Y0 = 2,
+  MULA_LS_LU_RRR_0_OPCODE_X0 = 50,
+  MULA_LU_LU_RRR_0_OPCODE_X0 = 51,
+  MULA_LU_LU_RRR_9_OPCODE_Y0 = 3,
+  MULX_RRR_0_OPCODE_X0 = 52,
+  MULX_RRR_3_OPCODE_Y0 = 3,
+  MUL_HS_HS_RRR_0_OPCODE_X0 = 53,
+  MUL_HS_HS_RRR_8_OPCODE_Y0 = 0,
+  MUL_HS_HU_RRR_0_OPCODE_X0 = 54,
+  MUL_HS_LS_RRR_0_OPCODE_X0 = 55,
+  MUL_HS_LU_RRR_0_OPCODE_X0 = 56,
+  MUL_HU_HU_RRR_0_OPCODE_X0 = 57,
+  MUL_HU_HU_RRR_8_OPCODE_Y0 = 1,
+  MUL_HU_LS_RRR_0_OPCODE_X0 = 58,
+  MUL_HU_LU_RRR_0_OPCODE_X0 = 59,
+  MUL_LS_LS_RRR_0_OPCODE_X0 = 60,
+  MUL_LS_LS_RRR_8_OPCODE_Y0 = 2,
+  MUL_LS_LU_RRR_0_OPCODE_X0 = 61,
+  MUL_LU_LU_RRR_0_OPCODE_X0 = 62,
+  MUL_LU_LU_RRR_8_OPCODE_Y0 = 3,
+  MZ_RRR_0_OPCODE_X0 = 63,
+  MZ_RRR_0_OPCODE_X1 = 27,
+  MZ_RRR_4_OPCODE_Y0 = 3,
+  MZ_RRR_4_OPCODE_Y1 = 3,
+  NAP_UNARY_OPCODE_X1 = 32,
+  NOP_UNARY_OPCODE_X0 = 5,
+  NOP_UNARY_OPCODE_X1 = 33,
+  NOP_UNARY_OPCODE_Y0 = 5,
+  NOP_UNARY_OPCODE_Y1 = 15,
+  NOR_RRR_0_OPCODE_X0 = 64,
+  NOR_RRR_0_OPCODE_X1 = 28,
+  NOR_RRR_5_OPCODE_Y0 = 1,
+  NOR_RRR_5_OPCODE_Y1 = 1,
+  ORI_IMM8_OPCODE_X0 = 7,
+  ORI_IMM8_OPCODE_X1 = 24,
+  OR_RRR_0_OPCODE_X0 = 65,
+  OR_RRR_0_OPCODE_X1 = 29,
+  OR_RRR_5_OPCODE_Y0 = 2,
+  OR_RRR_5_OPCODE_Y1 = 2,
+  PCNT_UNARY_OPCODE_X0 = 6,
+  PCNT_UNARY_OPCODE_Y0 = 6,
+  REVBITS_UNARY_OPCODE_X0 = 7,
+  REVBITS_UNARY_OPCODE_Y0 = 7,
+  REVBYTES_UNARY_OPCODE_X0 = 8,
+  REVBYTES_UNARY_OPCODE_Y0 = 8,
+  ROTLI_SHIFT_OPCODE_X0 = 1,
+  ROTLI_SHIFT_OPCODE_X1 = 1,
+  ROTLI_SHIFT_OPCODE_Y0 = 0,
+  ROTLI_SHIFT_OPCODE_Y1 = 0,
+  ROTL_RRR_0_OPCODE_X0 = 66,
+  ROTL_RRR_0_OPCODE_X1 = 30,
+  ROTL_RRR_6_OPCODE_Y0 = 0,
+  ROTL_RRR_6_OPCODE_Y1 = 0,
+  RRR_0_OPCODE_X0 = 5,
+  RRR_0_OPCODE_X1 = 5,
+  RRR_0_OPCODE_Y0 = 5,
+  RRR_0_OPCODE_Y1 = 6,
+  RRR_1_OPCODE_Y0 = 6,
+  RRR_1_OPCODE_Y1 = 7,
+  RRR_2_OPCODE_Y0 = 7,
+  RRR_2_OPCODE_Y1 = 8,
+  RRR_3_OPCODE_Y0 = 8,
+  RRR_3_OPCODE_Y1 = 9,
+  RRR_4_OPCODE_Y0 = 9,
+  RRR_4_OPCODE_Y1 = 10,
+  RRR_5_OPCODE_Y0 = 10,
+  RRR_5_OPCODE_Y1 = 11,
+  RRR_6_OPCODE_Y0 = 11,
+  RRR_6_OPCODE_Y1 = 12,
+  RRR_7_OPCODE_Y0 = 12,
+  RRR_7_OPCODE_Y1 = 13,
+  RRR_8_OPCODE_Y0 = 13,
+  RRR_9_OPCODE_Y0 = 14,
+  SHIFT_OPCODE_X0 = 6,
+  SHIFT_OPCODE_X1 = 6,
+  SHIFT_OPCODE_Y0 = 15,
+  SHIFT_OPCODE_Y1 = 14,
+  SHL16INSLI_OPCODE_X0 = 7,
+  SHL16INSLI_OPCODE_X1 = 7,
+  SHL1ADDX_RRR_0_OPCODE_X0 = 67,
+  SHL1ADDX_RRR_0_OPCODE_X1 = 31,
+  SHL1ADDX_RRR_7_OPCODE_Y0 = 1,
+  SHL1ADDX_RRR_7_OPCODE_Y1 = 1,
+  SHL1ADD_RRR_0_OPCODE_X0 = 68,
+  SHL1ADD_RRR_0_OPCODE_X1 = 32,
+  SHL1ADD_RRR_1_OPCODE_Y0 = 0,
+  SHL1ADD_RRR_1_OPCODE_Y1 = 0,
+  SHL2ADDX_RRR_0_OPCODE_X0 = 69,
+  SHL2ADDX_RRR_0_OPCODE_X1 = 33,
+  SHL2ADDX_RRR_7_OPCODE_Y0 = 2,
+  SHL2ADDX_RRR_7_OPCODE_Y1 = 2,
+  SHL2ADD_RRR_0_OPCODE_X0 = 70,
+  SHL2ADD_RRR_0_OPCODE_X1 = 34,
+  SHL2ADD_RRR_1_OPCODE_Y0 = 1,
+  SHL2ADD_RRR_1_OPCODE_Y1 = 1,
+  SHL3ADDX_RRR_0_OPCODE_X0 = 71,
+  SHL3ADDX_RRR_0_OPCODE_X1 = 35,
+  SHL3ADDX_RRR_7_OPCODE_Y0 = 3,
+  SHL3ADDX_RRR_7_OPCODE_Y1 = 3,
+  SHL3ADD_RRR_0_OPCODE_X0 = 72,
+  SHL3ADD_RRR_0_OPCODE_X1 = 36,
+  SHL3ADD_RRR_1_OPCODE_Y0 = 2,
+  SHL3ADD_RRR_1_OPCODE_Y1 = 2,
+  SHLI_SHIFT_OPCODE_X0 = 2,
+  SHLI_SHIFT_OPCODE_X1 = 2,
+  SHLI_SHIFT_OPCODE_Y0 = 1,
+  SHLI_SHIFT_OPCODE_Y1 = 1,
+  SHLXI_SHIFT_OPCODE_X0 = 3,
+  SHLXI_SHIFT_OPCODE_X1 = 3,
+  SHLX_RRR_0_OPCODE_X0 = 73,
+  SHLX_RRR_0_OPCODE_X1 = 37,
+  SHL_RRR_0_OPCODE_X0 = 74,
+  SHL_RRR_0_OPCODE_X1 = 38,
+  SHL_RRR_6_OPCODE_Y0 = 1,
+  SHL_RRR_6_OPCODE_Y1 = 1,
+  SHRSI_SHIFT_OPCODE_X0 = 4,
+  SHRSI_SHIFT_OPCODE_X1 = 4,
+  SHRSI_SHIFT_OPCODE_Y0 = 2,
+  SHRSI_SHIFT_OPCODE_Y1 = 2,
+  SHRS_RRR_0_OPCODE_X0 = 75,
+  SHRS_RRR_0_OPCODE_X1 = 39,
+  SHRS_RRR_6_OPCODE_Y0 = 2,
+  SHRS_RRR_6_OPCODE_Y1 = 2,
+  SHRUI_SHIFT_OPCODE_X0 = 5,
+  SHRUI_SHIFT_OPCODE_X1 = 5,
+  SHRUI_SHIFT_OPCODE_Y0 = 3,
+  SHRUI_SHIFT_OPCODE_Y1 = 3,
+  SHRUXI_SHIFT_OPCODE_X0 = 6,
+  SHRUXI_SHIFT_OPCODE_X1 = 6,
+  SHRUX_RRR_0_OPCODE_X0 = 76,
+  SHRUX_RRR_0_OPCODE_X1 = 40,
+  SHRU_RRR_0_OPCODE_X0 = 77,
+  SHRU_RRR_0_OPCODE_X1 = 41,
+  SHRU_RRR_6_OPCODE_Y0 = 3,
+  SHRU_RRR_6_OPCODE_Y1 = 3,
+  SHUFFLEBYTES_RRR_0_OPCODE_X0 = 78,
+  ST1_ADD_IMM8_OPCODE_X1 = 25,
+  ST1_OPCODE_Y2 = 0,
+  ST1_RRR_0_OPCODE_X1 = 42,
+  ST2_ADD_IMM8_OPCODE_X1 = 26,
+  ST2_OPCODE_Y2 = 1,
+  ST2_RRR_0_OPCODE_X1 = 43,
+  ST4_ADD_IMM8_OPCODE_X1 = 27,
+  ST4_OPCODE_Y2 = 2,
+  ST4_RRR_0_OPCODE_X1 = 44,
+  STNT1_ADD_IMM8_OPCODE_X1 = 28,
+  STNT1_RRR_0_OPCODE_X1 = 45,
+  STNT2_ADD_IMM8_OPCODE_X1 = 29,
+  STNT2_RRR_0_OPCODE_X1 = 46,
+  STNT4_ADD_IMM8_OPCODE_X1 = 30,
+  STNT4_RRR_0_OPCODE_X1 = 47,
+  STNT_ADD_IMM8_OPCODE_X1 = 31,
+  STNT_RRR_0_OPCODE_X1 = 48,
+  ST_ADD_IMM8_OPCODE_X1 = 32,
+  ST_OPCODE_Y2 = 3,
+  ST_RRR_0_OPCODE_X1 = 49,
+  SUBXSC_RRR_0_OPCODE_X0 = 79,
+  SUBXSC_RRR_0_OPCODE_X1 = 50,
+  SUBX_RRR_0_OPCODE_X0 = 80,
+  SUBX_RRR_0_OPCODE_X1 = 51,
+  SUBX_RRR_0_OPCODE_Y0 = 2,
+  SUBX_RRR_0_OPCODE_Y1 = 2,
+  SUB_RRR_0_OPCODE_X0 = 81,
+  SUB_RRR_0_OPCODE_X1 = 52,
+  SUB_RRR_0_OPCODE_Y0 = 3,
+  SUB_RRR_0_OPCODE_Y1 = 3,
+  SWINT0_UNARY_OPCODE_X1 = 34,
+  SWINT1_UNARY_OPCODE_X1 = 35,
+  SWINT2_UNARY_OPCODE_X1 = 36,
+  SWINT3_UNARY_OPCODE_X1 = 37,
+  TBLIDXB0_UNARY_OPCODE_X0 = 9,
+  TBLIDXB0_UNARY_OPCODE_Y0 = 9,
+  TBLIDXB1_UNARY_OPCODE_X0 = 10,
+  TBLIDXB1_UNARY_OPCODE_Y0 = 10,
+  TBLIDXB2_UNARY_OPCODE_X0 = 11,
+  TBLIDXB2_UNARY_OPCODE_Y0 = 11,
+  TBLIDXB3_UNARY_OPCODE_X0 = 12,
+  TBLIDXB3_UNARY_OPCODE_Y0 = 12,
+  UNARY_RRR_0_OPCODE_X0 = 82,
+  UNARY_RRR_0_OPCODE_X1 = 53,
+  UNARY_RRR_1_OPCODE_Y0 = 3,
+  UNARY_RRR_1_OPCODE_Y1 = 3,
+  V1ADDI_IMM8_OPCODE_X0 = 8,
+  V1ADDI_IMM8_OPCODE_X1 = 33,
+  V1ADDUC_RRR_0_OPCODE_X0 = 83,
+  V1ADDUC_RRR_0_OPCODE_X1 = 54,
+  V1ADD_RRR_0_OPCODE_X0 = 84,
+  V1ADD_RRR_0_OPCODE_X1 = 55,
+  V1ADIFFU_RRR_0_OPCODE_X0 = 85,
+  V1AVGU_RRR_0_OPCODE_X0 = 86,
+  V1CMPEQI_IMM8_OPCODE_X0 = 9,
+  V1CMPEQI_IMM8_OPCODE_X1 = 34,
+  V1CMPEQ_RRR_0_OPCODE_X0 = 87,
+  V1CMPEQ_RRR_0_OPCODE_X1 = 56,
+  V1CMPLES_RRR_0_OPCODE_X0 = 88,
+  V1CMPLES_RRR_0_OPCODE_X1 = 57,
+  V1CMPLEU_RRR_0_OPCODE_X0 = 89,
+  V1CMPLEU_RRR_0_OPCODE_X1 = 58,
+  V1CMPLTSI_IMM8_OPCODE_X0 = 10,
+  V1CMPLTSI_IMM8_OPCODE_X1 = 35,
+  V1CMPLTS_RRR_0_OPCODE_X0 = 90,
+  V1CMPLTS_RRR_0_OPCODE_X1 = 59,
+  V1CMPLTUI_IMM8_OPCODE_X0 = 11,
+  V1CMPLTUI_IMM8_OPCODE_X1 = 36,
+  V1CMPLTU_RRR_0_OPCODE_X0 = 91,
+  V1CMPLTU_RRR_0_OPCODE_X1 = 60,
+  V1CMPNE_RRR_0_OPCODE_X0 = 92,
+  V1CMPNE_RRR_0_OPCODE_X1 = 61,
+  V1DDOTPUA_RRR_0_OPCODE_X0 = 161,
+  V1DDOTPUSA_RRR_0_OPCODE_X0 = 93,
+  V1DDOTPUS_RRR_0_OPCODE_X0 = 94,
+  V1DDOTPU_RRR_0_OPCODE_X0 = 162,
+  V1DOTPA_RRR_0_OPCODE_X0 = 95,
+  V1DOTPUA_RRR_0_OPCODE_X0 = 163,
+  V1DOTPUSA_RRR_0_OPCODE_X0 = 96,
+  V1DOTPUS_RRR_0_OPCODE_X0 = 97,
+  V1DOTPU_RRR_0_OPCODE_X0 = 164,
+  V1DOTP_RRR_0_OPCODE_X0 = 98,
+  V1INT_H_RRR_0_OPCODE_X0 = 99,
+  V1INT_H_RRR_0_OPCODE_X1 = 62,
+  V1INT_L_RRR_0_OPCODE_X0 = 100,
+  V1INT_L_RRR_0_OPCODE_X1 = 63,
+  V1MAXUI_IMM8_OPCODE_X0 = 12,
+  V1MAXUI_IMM8_OPCODE_X1 = 37,
+  V1MAXU_RRR_0_OPCODE_X0 = 101,
+  V1MAXU_RRR_0_OPCODE_X1 = 64,
+  V1MINUI_IMM8_OPCODE_X0 = 13,
+  V1MINUI_IMM8_OPCODE_X1 = 38,
+  V1MINU_RRR_0_OPCODE_X0 = 102,
+  V1MINU_RRR_0_OPCODE_X1 = 65,
+  V1MNZ_RRR_0_OPCODE_X0 = 103,
+  V1MNZ_RRR_0_OPCODE_X1 = 66,
+  V1MULTU_RRR_0_OPCODE_X0 = 104,
+  V1MULUS_RRR_0_OPCODE_X0 = 105,
+  V1MULU_RRR_0_OPCODE_X0 = 106,
+  V1MZ_RRR_0_OPCODE_X0 = 107,
+  V1MZ_RRR_0_OPCODE_X1 = 67,
+  V1SADAU_RRR_0_OPCODE_X0 = 108,
+  V1SADU_RRR_0_OPCODE_X0 = 109,
+  V1SHLI_SHIFT_OPCODE_X0 = 7,
+  V1SHLI_SHIFT_OPCODE_X1 = 7,
+  V1SHL_RRR_0_OPCODE_X0 = 110,
+  V1SHL_RRR_0_OPCODE_X1 = 68,
+  V1SHRSI_SHIFT_OPCODE_X0 = 8,
+  V1SHRSI_SHIFT_OPCODE_X1 = 8,
+  V1SHRS_RRR_0_OPCODE_X0 = 111,
+  V1SHRS_RRR_0_OPCODE_X1 = 69,
+  V1SHRUI_SHIFT_OPCODE_X0 = 9,
+  V1SHRUI_SHIFT_OPCODE_X1 = 9,
+  V1SHRU_RRR_0_OPCODE_X0 = 112,
+  V1SHRU_RRR_0_OPCODE_X1 = 70,
+  V1SUBUC_RRR_0_OPCODE_X0 = 113,
+  V1SUBUC_RRR_0_OPCODE_X1 = 71,
+  V1SUB_RRR_0_OPCODE_X0 = 114,
+  V1SUB_RRR_0_OPCODE_X1 = 72,
+  V2ADDI_IMM8_OPCODE_X0 = 14,
+  V2ADDI_IMM8_OPCODE_X1 = 39,
+  V2ADDSC_RRR_0_OPCODE_X0 = 115,
+  V2ADDSC_RRR_0_OPCODE_X1 = 73,
+  V2ADD_RRR_0_OPCODE_X0 = 116,
+  V2ADD_RRR_0_OPCODE_X1 = 74,
+  V2ADIFFS_RRR_0_OPCODE_X0 = 117,
+  V2AVGS_RRR_0_OPCODE_X0 = 118,
+  V2CMPEQI_IMM8_OPCODE_X0 = 15,
+  V2CMPEQI_IMM8_OPCODE_X1 = 40,
+  V2CMPEQ_RRR_0_OPCODE_X0 = 119,
+  V2CMPEQ_RRR_0_OPCODE_X1 = 75,
+  V2CMPLES_RRR_0_OPCODE_X0 = 120,
+  V2CMPLES_RRR_0_OPCODE_X1 = 76,
+  V2CMPLEU_RRR_0_OPCODE_X0 = 121,
+  V2CMPLEU_RRR_0_OPCODE_X1 = 77,
+  V2CMPLTSI_IMM8_OPCODE_X0 = 16,
+  V2CMPLTSI_IMM8_OPCODE_X1 = 41,
+  V2CMPLTS_RRR_0_OPCODE_X0 = 122,
+  V2CMPLTS_RRR_0_OPCODE_X1 = 78,
+  V2CMPLTUI_IMM8_OPCODE_X0 = 17,
+  V2CMPLTUI_IMM8_OPCODE_X1 = 42,
+  V2CMPLTU_RRR_0_OPCODE_X0 = 123,
+  V2CMPLTU_RRR_0_OPCODE_X1 = 79,
+  V2CMPNE_RRR_0_OPCODE_X0 = 124,
+  V2CMPNE_RRR_0_OPCODE_X1 = 80,
+  V2DOTPA_RRR_0_OPCODE_X0 = 125,
+  V2DOTP_RRR_0_OPCODE_X0 = 126,
+  V2INT_H_RRR_0_OPCODE_X0 = 127,
+  V2INT_H_RRR_0_OPCODE_X1 = 81,
+  V2INT_L_RRR_0_OPCODE_X0 = 128,
+  V2INT_L_RRR_0_OPCODE_X1 = 82,
+  V2MAXSI_IMM8_OPCODE_X0 = 18,
+  V2MAXSI_IMM8_OPCODE_X1 = 43,
+  V2MAXS_RRR_0_OPCODE_X0 = 129,
+  V2MAXS_RRR_0_OPCODE_X1 = 83,
+  V2MINSI_IMM8_OPCODE_X0 = 19,
+  V2MINSI_IMM8_OPCODE_X1 = 44,
+  V2MINS_RRR_0_OPCODE_X0 = 130,
+  V2MINS_RRR_0_OPCODE_X1 = 84,
+  V2MNZ_RRR_0_OPCODE_X0 = 131,
+  V2MNZ_RRR_0_OPCODE_X1 = 85,
+  V2MULFSC_RRR_0_OPCODE_X0 = 132,
+  V2MULS_RRR_0_OPCODE_X0 = 133,
+  V2MULTS_RRR_0_OPCODE_X0 = 134,
+  V2MZ_RRR_0_OPCODE_X0 = 135,
+  V2MZ_RRR_0_OPCODE_X1 = 86,
+  V2PACKH_RRR_0_OPCODE_X0 = 136,
+  V2PACKH_RRR_0_OPCODE_X1 = 87,
+  V2PACKL_RRR_0_OPCODE_X0 = 137,
+  V2PACKL_RRR_0_OPCODE_X1 = 88,
+  V2PACKUC_RRR_0_OPCODE_X0 = 138,
+  V2PACKUC_RRR_0_OPCODE_X1 = 89,
+  V2SADAS_RRR_0_OPCODE_X0 = 139,
+  V2SADAU_RRR_0_OPCODE_X0 = 140,
+  V2SADS_RRR_0_OPCODE_X0 = 141,
+  V2SADU_RRR_0_OPCODE_X0 = 142,
+  V2SHLI_SHIFT_OPCODE_X0 = 10,
+  V2SHLI_SHIFT_OPCODE_X1 = 10,
+  V2SHLSC_RRR_0_OPCODE_X0 = 143,
+  V2SHLSC_RRR_0_OPCODE_X1 = 90,
+  V2SHL_RRR_0_OPCODE_X0 = 144,
+  V2SHL_RRR_0_OPCODE_X1 = 91,
+  V2SHRSI_SHIFT_OPCODE_X0 = 11,
+  V2SHRSI_SHIFT_OPCODE_X1 = 11,
+  V2SHRS_RRR_0_OPCODE_X0 = 145,
+  V2SHRS_RRR_0_OPCODE_X1 = 92,
+  V2SHRUI_SHIFT_OPCODE_X0 = 12,
+  V2SHRUI_SHIFT_OPCODE_X1 = 12,
+  V2SHRU_RRR_0_OPCODE_X0 = 146,
+  V2SHRU_RRR_0_OPCODE_X1 = 93,
+  V2SUBSC_RRR_0_OPCODE_X0 = 147,
+  V2SUBSC_RRR_0_OPCODE_X1 = 94,
+  V2SUB_RRR_0_OPCODE_X0 = 148,
+  V2SUB_RRR_0_OPCODE_X1 = 95,
+  V4ADDSC_RRR_0_OPCODE_X0 = 149,
+  V4ADDSC_RRR_0_OPCODE_X1 = 96,
+  V4ADD_RRR_0_OPCODE_X0 = 150,
+  V4ADD_RRR_0_OPCODE_X1 = 97,
+  V4INT_H_RRR_0_OPCODE_X0 = 151,
+  V4INT_H_RRR_0_OPCODE_X1 = 98,
+  V4INT_L_RRR_0_OPCODE_X0 = 152,
+  V4INT_L_RRR_0_OPCODE_X1 = 99,
+  V4PACKSC_RRR_0_OPCODE_X0 = 153,
+  V4PACKSC_RRR_0_OPCODE_X1 = 100,
+  V4SHLSC_RRR_0_OPCODE_X0 = 154,
+  V4SHLSC_RRR_0_OPCODE_X1 = 101,
+  V4SHL_RRR_0_OPCODE_X0 = 155,
+  V4SHL_RRR_0_OPCODE_X1 = 102,
+  V4SHRS_RRR_0_OPCODE_X0 = 156,
+  V4SHRS_RRR_0_OPCODE_X1 = 103,
+  V4SHRU_RRR_0_OPCODE_X0 = 157,
+  V4SHRU_RRR_0_OPCODE_X1 = 104,
+  V4SUBSC_RRR_0_OPCODE_X0 = 158,
+  V4SUBSC_RRR_0_OPCODE_X1 = 105,
+  V4SUB_RRR_0_OPCODE_X0 = 159,
+  V4SUB_RRR_0_OPCODE_X1 = 106,
+  WH64_UNARY_OPCODE_X1 = 38,
+  XORI_IMM8_OPCODE_X0 = 20,
+  XORI_IMM8_OPCODE_X1 = 45,
+  XOR_RRR_0_OPCODE_X0 = 160,
+  XOR_RRR_0_OPCODE_X1 = 107,
+  XOR_RRR_5_OPCODE_Y0 = 3,
+  XOR_RRR_5_OPCODE_Y1 = 3
 };
 
 #endif /* !_TILE_OPCODE_CONSTANTS_H */
index 3eb53525bf9d380d8b4d54db5c063abe694b527e..db93518fac033ff373671549ed7c7da23688ce80 100644 (file)
@@ -16,7 +16,8 @@
 #define _ASM_TILE_PAGE_H
 
 #include <linux/const.h>
-#include <hv/pagesize.h>
+#include <hv/hypervisor.h>
+#include <arch/chip.h>
 
 /* PAGE_SHIFT and HPAGE_SHIFT determine the page sizes. */
 #define PAGE_SHIFT     HV_LOG2_PAGE_SIZE_SMALL
@@ -28,8 +29,6 @@
 #define PAGE_MASK      (~(PAGE_SIZE - 1))
 #define HPAGE_MASK     (~(HPAGE_SIZE - 1))
 
-#ifdef __KERNEL__
-
 /*
  * If the Kconfig doesn't specify, set a maximum zone order that
  * is enough so that we can create huge pages from small pages given
@@ -39,9 +38,6 @@
 #define CONFIG_FORCE_MAX_ZONEORDER (HPAGE_SHIFT - PAGE_SHIFT + 1)
 #endif
 
-#include <hv/hypervisor.h>
-#include <arch/chip.h>
-
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
@@ -91,6 +87,10 @@ typedef struct page *pgtable_t;
 /* Must be a macro since it is used to create constants. */
 #define __pgprot(val) hv_pte(val)
 
+/* Rarely-used initializers, typically with a "zero" value. */
+#define __pte(x) hv_pte(x)
+#define __pgd(x) hv_pte(x)
+
 static inline u64 pgprot_val(pgprot_t pgprot)
 {
        return hv_pte_val(pgprot);
@@ -110,6 +110,8 @@ static inline u64 pgd_val(pgd_t pgd)
 
 typedef HV_PTE pmd_t;
 
+#define __pmd(x) hv_pte(x)
+
 static inline u64 pmd_val(pmd_t pmd)
 {
        return hv_pte_val(pmd);
@@ -318,7 +320,7 @@ static inline int pfn_valid(unsigned long pfn)
 
 /* Provide as macros since these require some other headers included. */
 #define page_to_pa(page) ((phys_addr_t)(page_to_pfn(page)) << PAGE_SHIFT)
-#define virt_to_page(kaddr) pfn_to_page(kaddr_to_pfn(kaddr))
+#define virt_to_page(kaddr) pfn_to_page(kaddr_to_pfn((void *)(kaddr)))
 #define page_to_virt(page) pfn_to_kaddr(page_to_pfn(page))
 
 struct mm_struct;
@@ -331,6 +333,4 @@ extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr);
 
 #include <asm-generic/memory_model.h>
 
-#endif /* __KERNEL__ */
-
 #endif /* _ASM_TILE_PAGE_H */
diff --git a/arch/tile/include/asm/parport.h b/arch/tile/include/asm/parport.h
new file mode 100644 (file)
index 0000000..cf252af
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/parport.h>
index c3fc458a0d323485557c1b6a97db662534fd9c3f..7f03cefed1b92079687a2ca838cd9d700a600a58 100644 (file)
@@ -46,7 +46,8 @@ struct pci_controller {
  */
 #define PCI_DMA_BUS_IS_PHYS     1
 
-int __init tile_pci_init(void);
+int __devinit tile_pci_init(void);
+int __devinit pcibios_init(void);
 
 void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
 static inline void pci_iounmap(struct pci_dev *dev, void __iomem *addr) {}
diff --git a/arch/tile/include/asm/pgtable_64.h b/arch/tile/include/asm/pgtable_64.h
new file mode 100644 (file)
index 0000000..fd80328
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ */
+
+#ifndef _ASM_TILE_PGTABLE_64_H
+#define _ASM_TILE_PGTABLE_64_H
+
+/* The level-0 page table breaks the address space into 32-bit chunks. */
+#define PGDIR_SHIFT    HV_LOG2_L1_SPAN
+#define PGDIR_SIZE     HV_L1_SPAN
+#define PGDIR_MASK     (~(PGDIR_SIZE-1))
+#define PTRS_PER_PGD   HV_L0_ENTRIES
+#define SIZEOF_PGD     (PTRS_PER_PGD * sizeof(pgd_t))
+
+/*
+ * The level-1 index is defined by the huge page size.  A PMD is composed
+ * of PTRS_PER_PMD pgd_t's and is the middle level of the page table.
+ */
+#define PMD_SHIFT      HV_LOG2_PAGE_SIZE_LARGE
+#define PMD_SIZE       HV_PAGE_SIZE_LARGE
+#define PMD_MASK       (~(PMD_SIZE-1))
+#define PTRS_PER_PMD   (1 << (PGDIR_SHIFT - PMD_SHIFT))
+#define SIZEOF_PMD     (PTRS_PER_PMD * sizeof(pmd_t))
+
+/*
+ * The level-2 index is defined by the difference between the huge
+ * page size and the normal page size.  A PTE is composed of
+ * PTRS_PER_PTE pte_t's and is the bottom level of the page table.
+ * Note that the hypervisor docs use PTE for what we call pte_t, so
+ * this nomenclature is somewhat confusing.
+ */
+#define PTRS_PER_PTE (1 << (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL))
+#define SIZEOF_PTE     (PTRS_PER_PTE * sizeof(pte_t))
+
+/*
+ * Align the vmalloc area to an L2 page table, and leave a guard page
+ * at the beginning and end.  The vmalloc code also puts in an internal
+ * guard page between each allocation.
+ */
+#define _VMALLOC_END   HUGE_VMAP_BASE
+#define VMALLOC_END    (_VMALLOC_END - PAGE_SIZE)
+#define VMALLOC_START  (_VMALLOC_START + PAGE_SIZE)
+
+#define HUGE_VMAP_END  (HUGE_VMAP_BASE + PGDIR_SIZE)
+
+#ifndef __ASSEMBLY__
+
+/* We have no pud since we are a three-level page table. */
+#include <asm-generic/pgtable-nopud.h>
+
+static inline int pud_none(pud_t pud)
+{
+       return pud_val(pud) == 0;
+}
+
+static inline int pud_present(pud_t pud)
+{
+       return pud_val(pud) & _PAGE_PRESENT;
+}
+
+#define pmd_ERROR(e) \
+       pr_err("%s:%d: bad pmd 0x%016llx.\n", __FILE__, __LINE__, pmd_val(e))
+
+static inline void pud_clear(pud_t *pudp)
+{
+       __pte_clear(&pudp->pgd);
+}
+
+static inline int pud_bad(pud_t pud)
+{
+       return ((pud_val(pud) & _PAGE_ALL) != _PAGE_TABLE);
+}
+
+/* Return the page-table frame number (ptfn) that a pud_t points at. */
+#define pud_ptfn(pud) hv_pte_get_ptfn((pud).pgd)
+
+/*
+ * A given kernel pud_t maps to a kernel pmd_t table at a specific
+ * virtual address.  Since kernel pmd_t tables can be aligned at
+ * sub-page granularity, this macro can return non-page-aligned
+ * pointers, despite its name.
+ */
+#define pud_page_vaddr(pud) \
+       (__va((phys_addr_t)pud_ptfn(pud) << HV_LOG2_PAGE_TABLE_ALIGN))
+
+/*
+ * A pud_t points to a pmd_t array.  Since we can have multiple per
+ * page, we don't have a one-to-one mapping of pud_t's to pages.
+ */
+#define pud_page(pud) pfn_to_page(HV_PTFN_TO_PFN(pud_ptfn(pud)))
+
+static inline unsigned long pud_index(unsigned long address)
+{
+       return (address >> PUD_SHIFT) & (PTRS_PER_PUD - 1);
+}
+
+#define pmd_offset(pud, address) \
+       ((pmd_t *)pud_page_vaddr(*(pud)) + pmd_index(address))
+
+static inline void __set_pmd(pmd_t *pmdp, pmd_t pmdval)
+{
+       set_pte(pmdp, pmdval);
+}
+
+/* Create a pmd from a PTFN and pgprot. */
+static inline pmd_t ptfn_pmd(unsigned long ptfn, pgprot_t prot)
+{
+       return hv_pte_set_ptfn(prot, ptfn);
+}
+
+/* Return the page-table frame number (ptfn) that a pmd_t points at. */
+static inline unsigned long pmd_ptfn(pmd_t pmd)
+{
+       return hv_pte_get_ptfn(pmd);
+}
+
+static inline void pmd_clear(pmd_t *pmdp)
+{
+       __pte_clear(pmdp);
+}
+
+/* Normalize an address to having the correct high bits set. */
+#define pgd_addr_normalize pgd_addr_normalize
+static inline unsigned long pgd_addr_normalize(unsigned long addr)
+{
+       return ((long)addr << (CHIP_WORD_SIZE() - CHIP_VA_WIDTH())) >>
+               (CHIP_WORD_SIZE() - CHIP_VA_WIDTH());
+}
+
+/* We don't define any pgds for these addresses. */
+static inline int pgd_addr_invalid(unsigned long addr)
+{
+       return addr >= MEM_HV_START ||
+               (addr > MEM_LOW_END && addr < MEM_HIGH_START);
+}
+
+/*
+ * Use atomic instructions to provide atomicity against the hypervisor.
+ */
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
+                                           unsigned long addr, pte_t *ptep)
+{
+       return (__insn_fetchand(&ptep->val, ~HV_PTE_ACCESSED) >>
+               HV_PTE_INDEX_ACCESSED) & 0x1;
+}
+
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+static inline void ptep_set_wrprotect(struct mm_struct *mm,
+                                     unsigned long addr, pte_t *ptep)
+{
+       __insn_fetchand(&ptep->val, ~HV_PTE_WRITABLE);
+}
+
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
+                                      unsigned long addr, pte_t *ptep)
+{
+       return hv_pte(__insn_exch(&ptep->val, 0UL));
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_TILE_PGTABLE_64_H */
index e6889474038a056e43ba19c5928b334ddca5a741..34c1e01ffb5e24648c4171fccedcd3257ef5e0da 100644 (file)
@@ -215,6 +215,8 @@ static inline void release_thread(struct task_struct *dead_task)
 
 extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
+extern int do_work_pending(struct pt_regs *regs, u32 flags);
+
 
 /*
  * Return saved (kernel) PC of a blocked thread.
@@ -255,10 +257,6 @@ static inline void cpu_relax(void)
        barrier();
 }
 
-struct siginfo;
-extern void arch_coredump_signal(struct siginfo *, struct pt_regs *);
-#define arch_coredump_signal arch_coredump_signal
-
 /* Info on this processor (see fs/proc/cpuinfo.c) */
 struct seq_operations;
 extern const struct seq_operations cpuinfo_op;
@@ -269,9 +267,6 @@ extern char chip_model[64];
 /* Data on which physical memory controller corresponds to which NUMA node. */
 extern int node_controller[];
 
-/* Do we dump information to the console when a user application crashes? */
-extern int show_crashinfo;
-
 #if CHIP_HAS_CBOX_HOME_MAP()
 /* Does the heap allocator return hash-for-home pages by default? */
 extern int hash_default;
diff --git a/arch/tile/include/asm/serial.h b/arch/tile/include/asm/serial.h
new file mode 100644 (file)
index 0000000..a0cb0ca
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/serial.h>
index 81d92a45cd4b613e2c18add9afe153e43a5d703e..1e1e616783ebfdd50ba937df77391816026ecaff 100644 (file)
@@ -28,6 +28,10 @@ struct pt_regs;
 int restore_sigcontext(struct pt_regs *, struct sigcontext __user *);
 int setup_sigcontext(struct sigcontext __user *, struct pt_regs *);
 void do_signal(struct pt_regs *regs);
+void signal_fault(const char *type, struct pt_regs *,
+                 void __user *frame, int sig);
+void trace_unhandled_signal(const char *type, struct pt_regs *regs,
+                           unsigned long address, int signo);
 #endif
 
 #endif /* _ASM_TILE_SIGNAL_H */
diff --git a/arch/tile/include/asm/spinlock_64.h b/arch/tile/include/asm/spinlock_64.h
new file mode 100644 (file)
index 0000000..72be590
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * 64-bit SMP ticket spinlocks, allowing only a single CPU anywhere
+ * (the type definitions are in asm/spinlock_types.h)
+ */
+
+#ifndef _ASM_TILE_SPINLOCK_64_H
+#define _ASM_TILE_SPINLOCK_64_H
+
+/* Shifts and masks for the various fields in "lock". */
+#define __ARCH_SPIN_CURRENT_SHIFT      17
+#define __ARCH_SPIN_NEXT_MASK          0x7fff
+#define __ARCH_SPIN_NEXT_OVERFLOW      0x8000
+
+/*
+ * Return the "current" portion of a ticket lock value,
+ * i.e. the number that currently owns the lock.
+ */
+static inline int arch_spin_current(u32 val)
+{
+       return val >> __ARCH_SPIN_CURRENT_SHIFT;
+}
+
+/*
+ * Return the "next" portion of a ticket lock value,
+ * i.e. the number that the next task to try to acquire the lock will get.
+ */
+static inline int arch_spin_next(u32 val)
+{
+       return val & __ARCH_SPIN_NEXT_MASK;
+}
+
+/* The lock is locked if a task would have to wait to get it. */
+static inline int arch_spin_is_locked(arch_spinlock_t *lock)
+{
+       u32 val = lock->lock;
+       return arch_spin_current(val) != arch_spin_next(val);
+}
+
+/* Bump the current ticket so the next task owns the lock. */
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+       wmb();  /* guarantee anything modified under the lock is visible */
+       __insn_fetchadd4(&lock->lock, 1U << __ARCH_SPIN_CURRENT_SHIFT);
+}
+
+void arch_spin_unlock_wait(arch_spinlock_t *lock);
+
+void arch_spin_lock_slow(arch_spinlock_t *lock, u32 val);
+
+/* Grab the "next" ticket number and bump it atomically.
+ * If the current ticket is not ours, go to the slow path.
+ * We also take the slow path if the "next" value overflows.
+ */
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+       u32 val = __insn_fetchadd4(&lock->lock, 1);
+       u32 ticket = val & (__ARCH_SPIN_NEXT_MASK | __ARCH_SPIN_NEXT_OVERFLOW);
+       if (unlikely(arch_spin_current(val) != ticket))
+               arch_spin_lock_slow(lock, ticket);
+}
+
+/* Try to get the lock, and return whether we succeeded. */
+int arch_spin_trylock(arch_spinlock_t *lock);
+
+/* We cannot take an interrupt after getting a ticket, so don't enable them. */
+#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ *
+ * We use fetchadd() for readers, and fetchor() with the sign bit
+ * for writers.
+ */
+
+#define __WRITE_LOCK_BIT (1 << 31)
+
+static inline int arch_write_val_locked(int val)
+{
+       return val < 0;  /* Optimize "val & __WRITE_LOCK_BIT". */
+}
+
+/**
+ * read_can_lock - would read_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+static inline int arch_read_can_lock(arch_rwlock_t *rw)
+{
+       return !arch_write_val_locked(rw->lock);
+}
+
+/**
+ * write_can_lock - would write_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+static inline int arch_write_can_lock(arch_rwlock_t *rw)
+{
+       return rw->lock == 0;
+}
+
+extern void __read_lock_failed(arch_rwlock_t *rw);
+
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+       u32 val = __insn_fetchaddgez4(&rw->lock, 1);
+       if (unlikely(arch_write_val_locked(val)))
+               __read_lock_failed(rw);
+}
+
+extern void __write_lock_failed(arch_rwlock_t *rw, u32 val);
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+       u32 val = __insn_fetchor4(&rw->lock, __WRITE_LOCK_BIT);
+       if (unlikely(val != 0))
+               __write_lock_failed(rw, val);
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+       __insn_mf();
+       __insn_fetchadd4(&rw->lock, -1);
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+       __insn_mf();
+       rw->lock = 0;
+}
+
+static inline int arch_read_trylock(arch_rwlock_t *rw)
+{
+       return !arch_write_val_locked(__insn_fetchaddgez4(&rw->lock, 1));
+}
+
+static inline int arch_write_trylock(arch_rwlock_t *rw)
+{
+       u32 val = __insn_fetchor4(&rw->lock, __WRITE_LOCK_BIT);
+       if (likely(val == 0))
+               return 1;
+       if (!arch_write_val_locked(val))
+               __insn_fetchand4(&rw->lock, ~__WRITE_LOCK_BIT);
+       return 0;
+}
+
+#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
+#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
+
+#endif /* _ASM_TILE_SPINLOCK_64_H */
index b16e5db8f0e7225f9e8789a747f9295d341d947d..c0db34d56be367f24a29b9e4249a98d9ad356961 100644 (file)
@@ -1,4 +1,4 @@
-#ifdef CONFIG_COMPAT
+#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
 #define __ARCH_WANT_STAT64     /* Used for compat_sys_stat64() etc. */
 #endif
 #include <asm-generic/stat.h>
index 25c686a00f1d2ed460e4c14330e414a10e587d4a..7c37b38f6c8d78f36c2215e6387e71c25c0e29ab 100644 (file)
 /* Tile gcc is always >= 4.3.0, so we use __builtin_bswap. */
 #define __arch_swab32(x) __builtin_bswap32(x)
 #define __arch_swab64(x) __builtin_bswap64(x)
-
-/* Use the variant that is natural for the wordsize. */
-#ifdef CONFIG_64BIT
-#define __arch_swab16(x) (__builtin_bswap64(x) >> 48)
-#else
 #define __arch_swab16(x) (__builtin_bswap32(x) >> 16)
-#endif
 
 #endif /* _ASM_TILE_SWAB_H */
index 3405b52853b869ba7bae0fcd7e091051fdaa30a7..bc4f562bd4594762a04dc7a845be8b0fcfa6b763 100644 (file)
@@ -125,6 +125,7 @@ extern void cpu_idle_on_new_stack(struct thread_info *old_ti,
 #define TIF_SYSCALL_AUDIT      5       /* syscall auditing active */
 #define TIF_SECCOMP            6       /* secure computing */
 #define TIF_MEMDIE             7       /* OOM killer at work */
+#define TIF_NOTIFY_RESUME      8       /* callback before returning to user */
 
 #define _TIF_SIGPENDING                (1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
@@ -134,10 +135,12 @@ extern void cpu_idle_on_new_stack(struct thread_info *old_ti,
 #define _TIF_SYSCALL_AUDIT     (1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP           (1<<TIF_SECCOMP)
 #define _TIF_MEMDIE            (1<<TIF_MEMDIE)
+#define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
 
 /* Work to do on any return to user space. */
 #define _TIF_ALLWORK_MASK \
-  (_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SINGLESTEP|_TIF_ASYNC_TLB)
+  (_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SINGLESTEP|\
+   _TIF_ASYNC_TLB|_TIF_NOTIFY_RESUME)
 
 /*
  * Thread-synchronous status.
index 343172d422a95fe3652de7038bf42a9b36b7a0e5..6fdd0c860193a9b3b3279d881a4d368706de7f9a 100644 (file)
@@ -44,25 +44,64 @@ static inline const struct cpumask *cpumask_of_node(int node)
 /* For now, use numa node -1 for global allocation. */
 #define pcibus_to_node(bus)            ((void)(bus), -1)
 
+/*
+ * TILE architecture has many cores integrated in one processor, so we need
+ * setup bigger balance_interval for both CPU/NODE scheduling domains to
+ * reduce process scheduling costs.
+ */
+
+/* sched_domains SD_CPU_INIT for TILE architecture */
+#define SD_CPU_INIT (struct sched_domain) {                            \
+       .min_interval           = 4,                                    \
+       .max_interval           = 128,                                  \
+       .busy_factor            = 64,                                   \
+       .imbalance_pct          = 125,                                  \
+       .cache_nice_tries       = 1,                                    \
+       .busy_idx               = 2,                                    \
+       .idle_idx               = 1,                                    \
+       .newidle_idx            = 0,                                    \
+       .wake_idx               = 0,                                    \
+       .forkexec_idx           = 0,                                    \
+                                                                       \
+       .flags                  = 1*SD_LOAD_BALANCE                     \
+                               | 1*SD_BALANCE_NEWIDLE                  \
+                               | 1*SD_BALANCE_EXEC                     \
+                               | 1*SD_BALANCE_FORK                     \
+                               | 0*SD_BALANCE_WAKE                     \
+                               | 0*SD_WAKE_AFFINE                      \
+                               | 0*SD_PREFER_LOCAL                     \
+                               | 0*SD_SHARE_CPUPOWER                   \
+                               | 0*SD_SHARE_PKG_RESOURCES              \
+                               | 0*SD_SERIALIZE                        \
+                               ,                                       \
+       .last_balance           = jiffies,                              \
+       .balance_interval       = 32,                                   \
+}
+
 /* sched_domains SD_NODE_INIT for TILE architecture */
-#define SD_NODE_INIT (struct sched_domain) {           \
-       .min_interval           = 8,                    \
-       .max_interval           = 32,                   \
-       .busy_factor            = 32,                   \
-       .imbalance_pct          = 125,                  \
-       .cache_nice_tries       = 1,                    \
-       .busy_idx               = 3,                    \
-       .idle_idx               = 1,                    \
-       .newidle_idx            = 2,                    \
-       .wake_idx               = 1,                    \
-       .flags                  = SD_LOAD_BALANCE       \
-                               | SD_BALANCE_NEWIDLE    \
-                               | SD_BALANCE_EXEC       \
-                               | SD_BALANCE_FORK       \
-                               | SD_WAKE_AFFINE        \
-                               | SD_SERIALIZE,         \
-       .last_balance           = jiffies,              \
-       .balance_interval       = 1,                    \
+#define SD_NODE_INIT (struct sched_domain) {                           \
+       .min_interval           = 16,                                   \
+       .max_interval           = 512,                                  \
+       .busy_factor            = 32,                                   \
+       .imbalance_pct          = 125,                                  \
+       .cache_nice_tries       = 1,                                    \
+       .busy_idx               = 3,                                    \
+       .idle_idx               = 1,                                    \
+       .newidle_idx            = 2,                                    \
+       .wake_idx               = 1,                                    \
+       .flags                  = 1*SD_LOAD_BALANCE                     \
+                               | 1*SD_BALANCE_NEWIDLE                  \
+                               | 1*SD_BALANCE_EXEC                     \
+                               | 1*SD_BALANCE_FORK                     \
+                               | 0*SD_BALANCE_WAKE                     \
+                               | 0*SD_WAKE_AFFINE                      \
+                               | 0*SD_PREFER_LOCAL                     \
+                               | 0*SD_SHARE_CPUPOWER                   \
+                               | 0*SD_SHARE_PKG_RESOURCES              \
+                               | 1*SD_SERIALIZE                        \
+                               ,                                       \
+       .last_balance           = jiffies,                              \
+       .balance_interval       = 128,                                  \
 }
 
 /* By definition, we create nodes based on online memory. */
index d06e35f572010cc1a5f4de4e78740039b785f89d..5f20f920f932b6c38e0a8971d1cedfb012dd729c 100644 (file)
 #ifndef _ASM_TILE_TRAPS_H
 #define _ASM_TILE_TRAPS_H
 
+#include <arch/chip.h>
+
 /* mm/fault.c */
 void do_page_fault(struct pt_regs *, int fault_num,
                   unsigned long address, unsigned long write);
+#if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC()
 void do_async_page_fault(struct pt_regs *);
+#endif
 
 #ifndef __tilegx__
 /*
index b35c2db71199ae3d70fc2b1e29687dc350514a77..f70bf1c541f1e2b8f4572223c1b1ee34893269f1 100644 (file)
@@ -15,7 +15,7 @@
 #if !defined(_ASM_TILE_UNISTD_H) || defined(__SYSCALL)
 #define _ASM_TILE_UNISTD_H
 
-#ifndef __LP64__
+#if !defined(__LP64__) || defined(__SYSCALL_COMPAT)
 /* Use the flavor of this syscall that matches the 32-bit API better. */
 #define __ARCH_WANT_SYNC_FILE_RANGE2
 #endif
similarity index 52%
rename from arch/tile/include/hv/pagesize.h
rename to arch/tile/include/asm/vga.h
index 58bed114fedd7212f3a9793fe41a8e6b52c49b36..7b46e754d611c8852b03a920ad7531f65bab6a58 100644 (file)
  *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  *   NON INFRINGEMENT.  See the GNU General Public License for
  *   more details.
+ *
+ * Access to VGA videoram.
  */
 
-/**
- * @file pagesize.h
- */
+#ifndef _ASM_TILE_VGA_H
+#define _ASM_TILE_VGA_H
 
-#ifndef _HV_PAGESIZE_H
-#define _HV_PAGESIZE_H
+#include <asm/io.h>
 
-/** The log2 of the size of small pages, in bytes. This value should
- * be verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL).
- */
-#define HV_LOG2_PAGE_SIZE_SMALL 16
+#define VT_BUF_HAVE_RW
 
-/** The log2 of the size of large pages, in bytes. This value should be
- * verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE).
- */
-#define HV_LOG2_PAGE_SIZE_LARGE 24
+static inline void scr_writew(u16 val, volatile u16 *addr)
+{
+       __raw_writew(val, (volatile u16 __iomem *) addr);
+}
+
+static inline u16 scr_readw(volatile const u16 *addr)
+{
+       return __raw_readw((volatile const u16 __iomem *) addr);
+}
+
+#define vga_readb(a)   readb((u8 __iomem *)(a))
+#define vga_writeb(v,a)        writeb(v, (u8 __iomem *)(a))
+
+#define VGA_MAP_MEM(x,s)       ((unsigned long) ioremap(x, s))
 
-#endif /* _HV_PAGESIZE_H */
+#endif
index ee41bca4c8c40f8b4f34bf574a188b0ab838f0d3..72ec1e972f15afb84746da32594e8d3b8bccdf6e 100644 (file)
@@ -22,8 +22,6 @@
 
 #include <arch/chip.h>
 
-#include <hv/pagesize.h>
-
 /* Linux builds want unsigned long constants, but assembler wants numbers */
 #ifdef __ASSEMBLER__
 /** One, for assembler */
  */
 #define HV_L1_SPAN (__HV_SIZE_ONE << HV_LOG2_L1_SPAN)
 
+/** The log2 of the size of small pages, in bytes. This value should
+ * be verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL).
+ */
+#define HV_LOG2_PAGE_SIZE_SMALL 16
+
 /** The size of small pages, in bytes. This value should be verified
  * at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL).
  */
 #define HV_PAGE_SIZE_SMALL (__HV_SIZE_ONE << HV_LOG2_PAGE_SIZE_SMALL)
 
+/** The log2 of the size of large pages, in bytes. This value should be
+ * verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE).
+ */
+#define HV_LOG2_PAGE_SIZE_LARGE 24
+
 /** The size of large pages, in bytes. This value should be verified
  * at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE).
  */
index b4c8e8ec45dc7fa041befe4d12e56c4d94236f8f..b4dbc057baada67ccd549902591664680e2ac6f2 100644 (file)
@@ -5,7 +5,7 @@
 extra-y := vmlinux.lds head_$(BITS).o
 obj-y := backtrace.o entry.o init_task.o irq.o messaging.o \
        pci-dma.o proc.o process.o ptrace.o reboot.o \
-       setup.o signal.o single_step.o stack.o sys.o time.o traps.o \
+       setup.o signal.o single_step.o stack.o sys.o sysfs.o time.o traps.o \
        intvec_$(BITS).o regs_$(BITS).o tile-desc_$(BITS).o
 
 obj-$(CONFIG_HARDWALL)         += hardwall.o
index 55a6a74974b4dad8c973484bcf2dc1934c34b309..1dc71eabfc5ad8aa49c9fceb6d4fb9423233fd2c 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/string.h>
-
 #include <asm/backtrace.h>
-
-#include <arch/chip.h>
-
 #include <asm/opcode-tile.h>
+#include <arch/abi.h>
 
-
-#define TREG_SP 54
-#define TREG_LR 55
-
-
-#if TILE_CHIP >= 10
+#ifdef __tilegx__
 #define tile_bundle_bits tilegx_bundle_bits
 #define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE
 #define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES
@@ -47,7 +39,7 @@ typedef long long bt_int_reg_t;
 typedef int bt_int_reg_t;
 #endif
 
-/** A decoded bundle used for backtracer analysis. */
+/* A decoded bundle used for backtracer analysis. */
 struct BacktraceBundle {
        tile_bundle_bits bits;
        int num_insns;
@@ -56,23 +48,7 @@ struct BacktraceBundle {
 };
 
 
-/* This implementation only makes sense for native tools. */
-/** Default function to read memory. */
-static bool bt_read_memory(void *result, VirtualAddress addr,
-                          unsigned int size, void *extra)
-{
-       /* FIXME: this should do some horrible signal stuff to catch
-        * SEGV cleanly and fail.
-        *
-        * Or else the caller should do the setjmp for efficiency.
-        */
-
-       memcpy(result, (const void *)addr, size);
-       return true;
-}
-
-
-/** Locates an instruction inside the given bundle that
+/* Locates an instruction inside the given bundle that
  * has the specified mnemonic, and whose first 'num_operands_to_match'
  * operands exactly match those in 'operand_values'.
  */
@@ -107,13 +83,13 @@ static const struct tile_decoded_instruction *find_matching_insn(
        return NULL;
 }
 
-/** Does this bundle contain an 'iret' instruction? */
+/* Does this bundle contain an 'iret' instruction? */
 static inline bool bt_has_iret(const struct BacktraceBundle *bundle)
 {
        return find_matching_insn(bundle, TILE_OPC_IRET, NULL, 0) != NULL;
 }
 
-/** Does this bundle contain an 'addi sp, sp, OFFSET' or
+/* Does this bundle contain an 'addi sp, sp, OFFSET' or
  * 'addli sp, sp, OFFSET' instruction, and if so, what is OFFSET?
  */
 static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)
@@ -124,7 +100,7 @@ static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)
                find_matching_insn(bundle, TILE_OPC_ADDI, vals, 2);
        if (insn == NULL)
                insn = find_matching_insn(bundle, TILE_OPC_ADDLI, vals, 2);
-#if TILE_CHIP >= 10
+#ifdef __tilegx__
        if (insn == NULL)
                insn = find_matching_insn(bundle, TILEGX_OPC_ADDXLI, vals, 2);
        if (insn == NULL)
@@ -137,7 +113,7 @@ static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)
        return true;
 }
 
-/** Does this bundle contain any 'info OP' or 'infol OP'
+/* Does this bundle contain any 'info OP' or 'infol OP'
  * instruction, and if so, what are their OP?  Note that OP is interpreted
  * as an unsigned value by this code since that's what the caller wants.
  * Returns the number of info ops found.
@@ -161,7 +137,7 @@ static int bt_get_info_ops(const struct BacktraceBundle *bundle,
        return num_ops;
 }
 
-/** Does this bundle contain a jrp instruction, and if so, to which
+/* Does this bundle contain a jrp instruction, and if so, to which
  * register is it jumping?
  */
 static bool bt_has_jrp(const struct BacktraceBundle *bundle, int *target_reg)
@@ -175,7 +151,7 @@ static bool bt_has_jrp(const struct BacktraceBundle *bundle, int *target_reg)
        return true;
 }
 
-/** Does this bundle modify the specified register in any way? */
+/* Does this bundle modify the specified register in any way? */
 static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg)
 {
        int i, j;
@@ -195,34 +171,34 @@ static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg)
        return false;
 }
 
-/** Does this bundle modify sp? */
+/* Does this bundle modify sp? */
 static inline bool bt_modifies_sp(const struct BacktraceBundle *bundle)
 {
        return bt_modifies_reg(bundle, TREG_SP);
 }
 
-/** Does this bundle modify lr? */
+/* Does this bundle modify lr? */
 static inline bool bt_modifies_lr(const struct BacktraceBundle *bundle)
 {
        return bt_modifies_reg(bundle, TREG_LR);
 }
 
-/** Does this bundle contain the instruction 'move fp, sp'? */
+/* Does this bundle contain the instruction 'move fp, sp'? */
 static inline bool bt_has_move_r52_sp(const struct BacktraceBundle *bundle)
 {
        static const int vals[2] = { 52, TREG_SP };
        return find_matching_insn(bundle, TILE_OPC_MOVE, vals, 2) != NULL;
 }
 
-/** Does this bundle contain a store of lr to sp? */
+/* Does this bundle contain a store of lr to sp? */
 static inline bool bt_has_sw_sp_lr(const struct BacktraceBundle *bundle)
 {
        static const int vals[2] = { TREG_SP, TREG_LR };
        return find_matching_insn(bundle, OPCODE_STORE, vals, 2) != NULL;
 }
 
-#if TILE_CHIP >= 10
-/** Track moveli values placed into registers. */
+#ifdef __tilegx__
+/* Track moveli values placed into registers. */
 static inline void bt_update_moveli(const struct BacktraceBundle *bundle,
                                    int moveli_args[])
 {
@@ -238,7 +214,7 @@ static inline void bt_update_moveli(const struct BacktraceBundle *bundle,
        }
 }
 
-/** Does this bundle contain an 'add sp, sp, reg' instruction
+/* Does this bundle contain an 'add sp, sp, reg' instruction
  * from a register that we saw a moveli into, and if so, what
  * is the value in the register?
  */
@@ -260,11 +236,11 @@ static bool bt_has_add_sp(const struct BacktraceBundle *bundle, int *adjust,
 }
 #endif
 
-/** Locates the caller's PC and SP for a program starting at the
+/* Locates the caller's PC and SP for a program starting at the
  * given address.
  */
 static void find_caller_pc_and_caller_sp(CallerLocation *location,
-                                        const VirtualAddress start_pc,
+                                        const unsigned long start_pc,
                                         BacktraceMemoryReader read_memory_func,
                                         void *read_memory_func_extra)
 {
@@ -288,9 +264,9 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
        tile_bundle_bits prefetched_bundles[32];
        int num_bundles_prefetched = 0;
        int next_bundle = 0;
-       VirtualAddress pc;
+       unsigned long pc;
 
-#if TILE_CHIP >= 10
+#ifdef __tilegx__
        /* Naively try to track moveli values to support addx for -m32. */
        int moveli_args[TILEGX_NUM_REGISTERS] = { 0 };
 #endif
@@ -369,10 +345,6 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
                                        /* Weird; reserved value, ignore it. */
                                        continue;
                                }
-                               if (info_operand & ENTRY_POINT_INFO_OP) {
-                                       /* This info op is ignored by the backtracer. */
-                                       continue;
-                               }
 
                                /* Skip info ops which are not in the
                                 * "one_ago" mode we want right now.
@@ -453,7 +425,7 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
                if (!sp_determined) {
                        int adjust;
                        if (bt_has_addi_sp(&bundle, &adjust)
-#if TILE_CHIP >= 10
+#ifdef __tilegx__
                            || bt_has_add_sp(&bundle, &adjust, moveli_args)
 #endif
                                ) {
@@ -504,7 +476,7 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
                                }
                        }
 
-#if TILE_CHIP >= 10
+#ifdef __tilegx__
                        /* Track moveli arguments for -m32 mode. */
                        bt_update_moveli(&bundle, moveli_args);
 #endif
@@ -546,18 +518,26 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
        }
 }
 
+/* Initializes a backtracer to start from the given location.
+ *
+ * If the frame pointer cannot be determined it is set to -1.
+ *
+ * state: The state to be filled in.
+ * read_memory_func: A callback that reads memory.
+ * read_memory_func_extra: An arbitrary argument to read_memory_func.
+ * pc: The current PC.
+ * lr: The current value of the 'lr' register.
+ * sp: The current value of the 'sp' register.
+ * r52: The current value of the 'r52' register.
+ */
 void backtrace_init(BacktraceIterator *state,
                    BacktraceMemoryReader read_memory_func,
                    void *read_memory_func_extra,
-                   VirtualAddress pc, VirtualAddress lr,
-                   VirtualAddress sp, VirtualAddress r52)
+                   unsigned long pc, unsigned long lr,
+                   unsigned long sp, unsigned long r52)
 {
        CallerLocation location;
-       VirtualAddress fp, initial_frame_caller_pc;
-
-       if (read_memory_func == NULL) {
-               read_memory_func = bt_read_memory;
-       }
+       unsigned long fp, initial_frame_caller_pc;
 
        /* Find out where we are in the initial frame. */
        find_caller_pc_and_caller_sp(&location, pc,
@@ -630,12 +610,15 @@ void backtrace_init(BacktraceIterator *state,
 /* Handle the case where the register holds more bits than the VA. */
 static bool valid_addr_reg(bt_int_reg_t reg)
 {
-       return ((VirtualAddress)reg == reg);
+       return ((unsigned long)reg == reg);
 }
 
+/* Advances the backtracing state to the calling frame, returning
+ * true iff successful.
+ */
 bool backtrace_next(BacktraceIterator *state)
 {
-       VirtualAddress next_fp, next_pc;
+       unsigned long next_fp, next_pc;
        bt_int_reg_t next_frame[2];
 
        if (state->fp == -1) {
index dbc213adf5e1dac8557e38647266c730ecb7e6eb..bf5e9d70266c72fe9ef45e30cdade23ef0f2e374 100644 (file)
@@ -135,26 +135,15 @@ long tile_compat_sys_msgrcv(int msqid,
 
 /* Provide the compat syscall number to call mapping. */
 #undef __SYSCALL
-#define __SYSCALL(nr, call) [nr] = (compat_##call),
+#define __SYSCALL(nr, call) [nr] = (call),
 
 /* The generic versions of these don't work for Tile. */
 #define compat_sys_msgrcv tile_compat_sys_msgrcv
 #define compat_sys_msgsnd tile_compat_sys_msgsnd
 
 /* See comments in sys.c */
-#define compat_sys_fadvise64 sys32_fadvise64
 #define compat_sys_fadvise64_64 sys32_fadvise64_64
 #define compat_sys_readahead sys32_readahead
-#define compat_sys_sync_file_range compat_sys_sync_file_range2
-
-/* We leverage the "struct stat64" type for 32-bit time_t/nsec. */
-#define compat_sys_stat64 sys_stat64
-#define compat_sys_lstat64 sys_lstat64
-#define compat_sys_fstat64 sys_fstat64
-#define compat_sys_fstatat64 sys_fstatat64
-
-/* The native sys_ptrace dynamically handles compat binaries. */
-#define compat_sys_ptrace sys_ptrace
 
 /* Call the trampolines to manage pt_regs where necessary. */
 #define compat_sys_execve _compat_sys_execve
index dbb0dfc7beceb10eaa25fd4b73579cdc620334c5..a7869ad627760e1315ca1fd3096233910ab56df3 100644 (file)
@@ -317,7 +317,7 @@ long compat_sys_rt_sigreturn(struct pt_regs *regs)
        return 0;
 
 badframe:
-       force_sig(SIGSEGV, current);
+       signal_fault("bad sigreturn frame", regs, frame, 0);
        return 0;
 }
 
@@ -431,6 +431,6 @@ int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        return 0;
 
 give_sigsegv:
-       force_sigsegv(sig, current);
+       signal_fault("bad setup frame", regs, frame, sig);
        return -EFAULT;
 }
diff --git a/arch/tile/kernel/futex_64.S b/arch/tile/kernel/futex_64.S
new file mode 100644 (file)
index 0000000..f465d1e
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * Atomically access user memory, but use MMU to avoid propagating
+ * kernel exceptions.
+ */
+
+#include <linux/linkage.h>
+#include <asm/errno.h>
+#include <asm/futex.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+
+/*
+ * Provide a set of atomic memory operations supporting <asm/futex.h>.
+ *
+ * r0: user address to manipulate
+ * r1: new value to write, or for cmpxchg, old value to compare against
+ * r2: (cmpxchg only) new value to write
+ *
+ * Return __get_user struct, r0 with value, r1 with error.
+ */
+#define FUTEX_OP(name, ...) \
+STD_ENTRY(futex_##name)                        \
+       __VA_ARGS__;                    \
+       {                               \
+        move   r1, zero;               \
+        jrp    lr                      \
+       };                              \
+       STD_ENDPROC(futex_##name);      \
+       .pushsection __ex_table,"a";    \
+       .quad 1b, get_user_fault;       \
+       .popsection
+
+       .pushsection .fixup,"ax"
+get_user_fault:
+       { movei r1, -EFAULT; jrp lr }
+       ENDPROC(get_user_fault)
+       .popsection
+
+FUTEX_OP(cmpxchg, mtspr CMPEXCH_VALUE, r1; 1: cmpexch4 r0, r0, r2)
+FUTEX_OP(set, 1: exch4 r0, r0, r1)
+FUTEX_OP(add, 1: fetchadd4 r0, r0, r1)
+FUTEX_OP(or, 1: fetchor4 r0, r0, r1)
+FUTEX_OP(andn, nor r1, r1, zero; 1: fetchand4 r0, r0, r1)
index e910530436e64a4079ba65e22bdca13e6ad01bfa..8c41891aab3413c8fa44549baad4a013a992407b 100644 (file)
 struct hardwall_info {
        struct list_head list;             /* "rectangles" list */
        struct list_head task_head;        /* head of tasks in this hardwall */
+       struct cpumask cpumask;            /* cpus in the rectangle */
        int ulhc_x;                        /* upper left hand corner x coord */
        int ulhc_y;                        /* upper left hand corner y coord */
        int width;                         /* rectangle width */
        int height;                        /* rectangle height */
+       int id;                            /* integer id for this hardwall */
        int teardown_in_progress;          /* are we tearing this one down? */
 };
 
 /* Currently allocated hardwall rectangles */
 static LIST_HEAD(rectangles);
 
+/* /proc/tile/hardwall */
+static struct proc_dir_entry *hardwall_proc_dir;
+
+/* Functions to manage files in /proc/tile/hardwall. */
+static void hardwall_add_proc(struct hardwall_info *rect);
+static void hardwall_remove_proc(struct hardwall_info *rect);
+
 /*
  * Guard changes to the hardwall data structures.
  * This could be finer grained (e.g. one lock for the list of hardwall
@@ -105,6 +114,8 @@ static int setup_rectangle(struct hardwall_info *r, struct cpumask *mask)
        r->ulhc_y = cpu_y(ulhc);
        r->width = cpu_x(lrhc) - r->ulhc_x + 1;
        r->height = cpu_y(lrhc) - r->ulhc_y + 1;
+       cpumask_copy(&r->cpumask, mask);
+       r->id = ulhc;   /* The ulhc cpu id can be the hardwall id. */
 
        /* Width and height must be positive */
        if (r->width <= 0 || r->height <= 0)
@@ -268,12 +279,10 @@ void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num)
        found_processes = 0;
        list_for_each_entry(p, &rect->task_head, thread.hardwall_list) {
                BUG_ON(p->thread.hardwall != rect);
-               if (p->sighand) {
+               if (!(p->flags & PF_EXITING)) {
                        found_processes = 1;
                        pr_notice("hardwall: killing %d\n", p->pid);
-                       spin_lock(&p->sighand->siglock);
-                       __group_send_sig_info(info.si_signo, &info, p);
-                       spin_unlock(&p->sighand->siglock);
+                       do_send_sig_info(info.si_signo, &info, p, false);
                }
        }
        if (!found_processes)
@@ -390,6 +399,9 @@ static struct hardwall_info *hardwall_create(
        /* Set up appropriate hardwalling on all affected cpus. */
        hardwall_setup(rect);
 
+       /* Create a /proc/tile/hardwall entry. */
+       hardwall_add_proc(rect);
+
        return rect;
 }
 
@@ -647,6 +659,9 @@ static void hardwall_destroy(struct hardwall_info *rect)
        /* Restart switch and disable firewall. */
        on_each_cpu_mask(&mask, restart_udn_switch, NULL, 1);
 
+       /* Remove the /proc/tile/hardwall entry. */
+       hardwall_remove_proc(rect);
+
        /* Now free the rectangle from the list. */
        spin_lock_irqsave(&hardwall_lock, flags);
        BUG_ON(!list_empty(&rect->task_head));
@@ -656,35 +671,57 @@ static void hardwall_destroy(struct hardwall_info *rect)
 }
 
 
-/*
- * Dump hardwall state via /proc; initialized in arch/tile/sys/proc.c.
- */
-int proc_tile_hardwall_show(struct seq_file *sf, void *v)
+static int hardwall_proc_show(struct seq_file *sf, void *v)
 {
-       struct hardwall_info *r;
+       struct hardwall_info *rect = sf->private;
+       char buf[256];
 
-       if (udn_disabled) {
-               seq_printf(sf, "%dx%d 0,0 pids:\n", smp_width, smp_height);
-               return 0;
-       }
-
-       spin_lock_irq(&hardwall_lock);
-       list_for_each_entry(r, &rectangles, list) {
-               struct task_struct *p;
-               seq_printf(sf, "%dx%d %d,%d pids:",
-                          r->width, r->height, r->ulhc_x, r->ulhc_y);
-               list_for_each_entry(p, &r->task_head, thread.hardwall_list) {
-                       unsigned int cpu = cpumask_first(&p->cpus_allowed);
-                       unsigned int x = cpu % smp_width;
-                       unsigned int y = cpu / smp_width;
-                       seq_printf(sf, " %d@%d,%d", p->pid, x, y);
-               }
-               seq_printf(sf, "\n");
-       }
-       spin_unlock_irq(&hardwall_lock);
+       int rc = cpulist_scnprintf(buf, sizeof(buf), &rect->cpumask);
+       buf[rc++] = '\n';
+       seq_write(sf, buf, rc);
        return 0;
 }
 
+static int hardwall_proc_open(struct inode *inode,
+                             struct file *file)
+{
+       return single_open(file, hardwall_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations hardwall_proc_fops = {
+       .open           = hardwall_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void hardwall_add_proc(struct hardwall_info *rect)
+{
+       char buf[64];
+       snprintf(buf, sizeof(buf), "%d", rect->id);
+       proc_create_data(buf, 0444, hardwall_proc_dir,
+                        &hardwall_proc_fops, rect);
+}
+
+static void hardwall_remove_proc(struct hardwall_info *rect)
+{
+       char buf[64];
+       snprintf(buf, sizeof(buf), "%d", rect->id);
+       remove_proc_entry(buf, hardwall_proc_dir);
+}
+
+int proc_pid_hardwall(struct task_struct *task, char *buffer)
+{
+       struct hardwall_info *rect = task->thread.hardwall;
+       return rect ? sprintf(buffer, "%d\n", rect->id) : 0;
+}
+
+void proc_tile_hardwall_init(struct proc_dir_entry *root)
+{
+       if (!udn_disabled)
+               hardwall_proc_dir = proc_mkdir("hardwall", root);
+}
+
 
 /*
  * Character device support via ioctl/close.
@@ -718,6 +755,9 @@ static long hardwall_ioctl(struct file *file, unsigned int a, unsigned long b)
                        return -EINVAL;
                return hardwall_deactivate(current);
 
+       case _HARDWALL_GET_ID:
+               return rect ? rect->id : -EINVAL;
+
        default:
                return -EINVAL;
        }
diff --git a/arch/tile/kernel/head_64.S b/arch/tile/kernel/head_64.S
new file mode 100644 (file)
index 0000000..6bc3a93
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * TILE startup code.
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/thread_info.h>
+#include <asm/processor.h>
+#include <asm/asm-offsets.h>
+#include <hv/hypervisor.h>
+#include <arch/chip.h>
+#include <arch/spr_def.h>
+
+/*
+ * This module contains the entry code for kernel images. It performs the
+ * minimal setup needed to call the generic C routines.
+ */
+
+       __HEAD
+ENTRY(_start)
+       /* Notify the hypervisor of what version of the API we want */
+       {
+         movei r1, TILE_CHIP
+         movei r2, TILE_CHIP_REV
+       }
+       {
+         moveli r0, _HV_VERSION
+         jal hv_init
+       }
+       /* Get a reasonable default ASID in r0 */
+       {
+         move r0, zero
+         jal hv_inquire_asid
+       }
+
+       /*
+        * Install the default page table.  The relocation required to
+        * statically define the table is a bit too complex, so we have
+        * to plug in the pointer from the L0 to the L1 table by hand.
+        * We only do this on the first cpu to boot, though, since the
+        * other CPUs should see a properly-constructed page table.
+        */
+       {
+         v4int_l r2, zero, r0    /* ASID for hv_install_context */
+         moveli r4, hw1_last(swapper_pgprot - PAGE_OFFSET)
+       }
+       {
+         shl16insli r4, r4, hw0(swapper_pgprot - PAGE_OFFSET)
+       }
+       {
+         ld r1, r4               /* access_pte for hv_install_context */
+       }
+       {
+         moveli r0, hw1_last(.Lsv_data_pmd - PAGE_OFFSET)
+         moveli r6, hw1_last(temp_data_pmd - PAGE_OFFSET)
+       }
+       {
+         /* After initializing swapper_pgprot, HV_PTE_GLOBAL is set. */
+         bfextu r7, r1, HV_PTE_INDEX_GLOBAL, HV_PTE_INDEX_GLOBAL
+         inv r4
+       }
+       bnez r7, .Lno_write
+       {
+         shl16insli r0, r0, hw0(.Lsv_data_pmd - PAGE_OFFSET)
+         shl16insli r6, r6, hw0(temp_data_pmd - PAGE_OFFSET)
+       }
+       {
+         /* Cut off the low bits of the PT address. */
+         shrui r6, r6, HV_LOG2_PAGE_TABLE_ALIGN
+         /* Start with our access pte. */
+         move r5, r1
+       }
+       {
+         /* Stuff the address into the page table pointer slot of the PTE. */
+         bfins r5, r6, HV_PTE_INDEX_PTFN, \
+                       HV_PTE_INDEX_PTFN + HV_PTE_PTFN_BITS - 1
+       }
+       {
+         /* Store the L0 data PTE. */
+         st r0, r5
+         addli r6, r6, (temp_code_pmd - temp_data_pmd) >> \
+                       HV_LOG2_PAGE_TABLE_ALIGN
+       }
+       {
+         addli r0, r0, .Lsv_code_pmd - .Lsv_data_pmd
+         bfins r5, r6, HV_PTE_INDEX_PTFN, \
+                       HV_PTE_INDEX_PTFN + HV_PTE_PTFN_BITS - 1
+       }
+       /* Store the L0 code PTE. */
+       st r0, r5
+
+.Lno_write:
+       moveli lr, hw2_last(1f)
+       {
+         shl16insli lr, lr, hw1(1f)
+         moveli r0, hw1_last(swapper_pg_dir - PAGE_OFFSET)
+       }
+       {
+         shl16insli lr, lr, hw0(1f)
+         shl16insli r0, r0, hw0(swapper_pg_dir - PAGE_OFFSET)
+       }
+       {
+         move r3, zero
+         j hv_install_context
+       }
+1:
+
+       /* Install the interrupt base. */
+       moveli r0, hw2_last(MEM_SV_START)
+       shl16insli r0, r0, hw1(MEM_SV_START)
+       shl16insli r0, r0, hw0(MEM_SV_START)
+       mtspr SPR_INTERRUPT_VECTOR_BASE_K, r0
+
+       /*
+        * Get our processor number and save it away in SAVE_K_0.
+        * Extract stuff from the topology structure: r4 = y, r6 = x,
+        * r5 = width.  FIXME: consider whether we want to just make these
+        * 64-bit values (and if so fix smp_topology write below, too).
+        */
+       jal hv_inquire_topology
+       {
+         v4int_l r5, zero, r1    /* r5 = width */
+         shrui r4, r0, 32        /* r4 = y */
+       }
+       {
+         v4int_l r6, zero, r0    /* r6 = x */
+         mul_lu_lu r4, r4, r5
+       }
+       {
+         add r4, r4, r6          /* r4 == cpu == y*width + x */
+       }
+
+#ifdef CONFIG_SMP
+       /*
+        * Load up our per-cpu offset.  When the first (master) tile
+        * boots, this value is still zero, so we will load boot_pc
+        * with start_kernel, and boot_sp with init_stack + THREAD_SIZE.
+        * The master tile initializes the per-cpu offset array, so that
+        * when subsequent (secondary) tiles boot, they will instead load
+        * from their per-cpu versions of boot_sp and boot_pc.
+        */
+       moveli r5, hw2_last(__per_cpu_offset)
+       shl16insli r5, r5, hw1(__per_cpu_offset)
+       shl16insli r5, r5, hw0(__per_cpu_offset)
+       shl3add r5, r4, r5
+       ld r5, r5
+       bnez r5, 1f
+
+       /*
+        * Save the width and height to the smp_topology variable
+        * for later use.
+        */
+       moveli r0, hw2_last(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET)
+       shl16insli r0, r0, hw1(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET)
+       shl16insli r0, r0, hw0(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET)
+       st r0, r1
+1:
+#else
+       move r5, zero
+#endif
+
+       /* Load and go with the correct pc and sp. */
+       {
+         moveli r1, hw2_last(boot_sp)
+         moveli r0, hw2_last(boot_pc)
+       }
+       {
+         shl16insli r1, r1, hw1(boot_sp)
+         shl16insli r0, r0, hw1(boot_pc)
+       }
+       {
+         shl16insli r1, r1, hw0(boot_sp)
+         shl16insli r0, r0, hw0(boot_pc)
+       }
+       {
+         add r1, r1, r5
+         add r0, r0, r5
+       }
+       ld r0, r0
+       ld sp, r1
+       or r4, sp, r4
+       mtspr SPR_SYSTEM_SAVE_K_0, r4  /* save ksp0 + cpu */
+       addi sp, sp, -STACK_TOP_DELTA
+       {
+         move lr, zero   /* stop backtraces in the called function */
+         jr r0
+       }
+       ENDPROC(_start)
+
+__PAGE_ALIGNED_BSS
+       .align PAGE_SIZE
+ENTRY(empty_zero_page)
+       .fill PAGE_SIZE,1,0
+       END(empty_zero_page)
+
+       .macro PTE cpa, bits1
+       .quad HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED |\
+             HV_PTE_GLOBAL | (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE) |\
+             (\bits1) | (HV_CPA_TO_PFN(\cpa) << HV_PTE_INDEX_PFN)
+       .endm
+
+__PAGE_ALIGNED_DATA
+       .align PAGE_SIZE
+ENTRY(swapper_pg_dir)
+       .org swapper_pg_dir + HV_L0_INDEX(PAGE_OFFSET) * HV_PTE_SIZE
+.Lsv_data_pmd:
+       .quad 0  /* PTE temp_data_pmd - PAGE_OFFSET, 0 */
+       .org swapper_pg_dir + HV_L0_INDEX(MEM_SV_START) * HV_PTE_SIZE
+.Lsv_code_pmd:
+       .quad 0  /* PTE temp_code_pmd - PAGE_OFFSET, 0 */
+       .org swapper_pg_dir + HV_L0_SIZE
+       END(swapper_pg_dir)
+
+       .align HV_PAGE_TABLE_ALIGN
+ENTRY(temp_data_pmd)
+       /*
+        * We fill the PAGE_OFFSET pmd with huge pages with
+        * VA = PA + PAGE_OFFSET.  We remap things with more precise access
+        * permissions later.
+        */
+       .set addr, 0
+       .rept HV_L1_ENTRIES
+       PTE addr, HV_PTE_READABLE | HV_PTE_WRITABLE
+       .set addr, addr + HV_PAGE_SIZE_LARGE
+       .endr
+       .org temp_data_pmd + HV_L1_SIZE
+       END(temp_data_pmd)
+
+       .align HV_PAGE_TABLE_ALIGN
+ENTRY(temp_code_pmd)
+       /*
+        * We fill the MEM_SV_START pmd with huge pages with
+        * VA = PA + PAGE_OFFSET.  We remap things with more precise access
+        * permissions later.
+        */
+       .set addr, 0
+       .rept HV_L1_ENTRIES
+       PTE addr, HV_PTE_READABLE | HV_PTE_EXECUTABLE
+       .set addr, addr + HV_PAGE_SIZE_LARGE
+       .endr
+       .org temp_code_pmd + HV_L1_SIZE
+       END(temp_code_pmd)
+
+       /*
+        * Isolate swapper_pgprot to its own cache line, since each cpu
+        * starting up will read it using VA-is-PA and local homing.
+        * This would otherwise likely conflict with other data on the cache
+        * line, once we have set its permanent home in the page tables.
+        */
+       __INITDATA
+       .align CHIP_L2_LINE_SIZE()
+ENTRY(swapper_pgprot)
+       .quad HV_PTE_PRESENT | (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE)
+       .align CHIP_L2_LINE_SIZE()
+       END(swapper_pgprot)
index fffcfa6b3a62e11c2d4a34590b5ba8d57798ca9e..72ade79b621bcd8b23ec44650e3d4af4fdbf0b66 100644 (file)
@@ -851,14 +851,27 @@ STD_ENTRY(interrupt_return)
        /* Check to see if there is any work to do before returning to user. */
        {
         addi   r29, r32, THREAD_INFO_FLAGS_OFFSET
-        moveli r28, lo16(_TIF_ALLWORK_MASK)
+        moveli r1, lo16(_TIF_ALLWORK_MASK)
        }
        {
         lw     r29, r29
-        auli   r28, r28, ha16(_TIF_ALLWORK_MASK)
+        auli   r1, r1, ha16(_TIF_ALLWORK_MASK)
        }
-       and     r28, r29, r28
-       bnz     r28, .Lwork_pending
+       and     r1, r29, r1
+       bzt     r1, .Lrestore_all
+
+       /*
+        * Make sure we have all the registers saved for signal
+        * handling or single-step.  Call out to C code to figure out
+        * exactly what we need to do for each flag bit, then if
+        * necessary, reload the flags and recheck.
+        */
+       push_extra_callee_saves r0
+       {
+        PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+        jal    do_work_pending
+       }
+       bnz     r0, .Lresume_userspace
 
        /*
         * In the NMI case we
@@ -1099,99 +1112,6 @@ STD_ENTRY(interrupt_return)
        pop_reg r50
        pop_reg r51, sp, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(51)
        j .Lcontinue_restore_regs
-
-.Lwork_pending:
-       /* Mask the reschedule flag */
-       andi    r28, r29, _TIF_NEED_RESCHED
-
-       {
-        /*
-         * If the NEED_RESCHED flag is called, we call schedule(), which
-         * may drop this context right here and go do something else.
-         * On return, jump back to .Lresume_userspace and recheck.
-         */
-        bz     r28, .Lasync_tlb
-
-        /* Mask the async-tlb flag */
-        andi   r28, r29, _TIF_ASYNC_TLB
-       }
-
-       jal     schedule
-       FEEDBACK_REENTER(interrupt_return)
-
-       /* Reload the flags and check again */
-       j       .Lresume_userspace
-
-.Lasync_tlb:
-       {
-        bz     r28, .Lneed_sigpending
-
-        /* Mask the sigpending flag */
-        andi   r28, r29, _TIF_SIGPENDING
-       }
-
-       PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
-       jal     do_async_page_fault
-       FEEDBACK_REENTER(interrupt_return)
-
-       /*
-        * Go restart the "resume userspace" process.  We may have
-        * fired a signal, and we need to disable interrupts again.
-        */
-       j       .Lresume_userspace
-
-.Lneed_sigpending:
-       /*
-        * At this point we are either doing signal handling or single-step,
-        * so either way make sure we have all the registers saved.
-        */
-       push_extra_callee_saves r0
-
-       {
-        /* If no signal pending, skip to singlestep check */
-        bz     r28, .Lneed_singlestep
-
-        /* Mask the singlestep flag */
-        andi   r28, r29, _TIF_SINGLESTEP
-       }
-
-       jal     do_signal
-       FEEDBACK_REENTER(interrupt_return)
-
-       /* Reload the flags and check again */
-       j       .Lresume_userspace
-
-.Lneed_singlestep:
-       {
-        /* Get a pointer to the EX1 field */
-        PTREGS_PTR(r29, PTREGS_OFFSET_EX1)
-
-        /* If we get here, our bit must be set. */
-        bz     r28, .Lwork_confusion
-       }
-       /* If we are in priv mode, don't single step */
-       lw      r28, r29
-       andi    r28, r28, SPR_EX_CONTEXT_1_1__PL_MASK  /* mask off ICS */
-       bnz     r28, .Lrestore_all
-
-       /* Allow interrupts within the single step code */
-       TRACE_IRQS_ON  /* Note: clobbers registers r0-r29 */
-       IRQ_ENABLE(r20, r21)
-
-       /* try to single-step the current instruction */
-       PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
-       jal     single_step_once
-       FEEDBACK_REENTER(interrupt_return)
-
-       /* Re-disable interrupts.  TRACE_IRQS_OFF in .Lrestore_all. */
-       IRQ_DISABLE(r20,r21)
-
-       j       .Lrestore_all
-
-.Lwork_confusion:
-       move    r0, r28
-       panic   "thread_info allwork flags unhandled on userspace resume: %#x"
-
        STD_ENDPROC(interrupt_return)
 
        /*
@@ -1550,7 +1470,10 @@ STD_ENTRY(_sys_clone)
  * We place it in the __HEAD section to ensure it is relatively
  * near to the intvec_SWINT_1 code (reachable by a conditional branch).
  *
- * Must match register usage in do_page_fault().
+ * Our use of ATOMIC_LOCK_REG here must match do_page_fault_ics().
+ *
+ * As we do in lib/atomic_asm_32.S, we bypass a store if the value we
+ * would store is the same as the value we just loaded.
  */
        __HEAD
        .align 64
@@ -1611,17 +1534,7 @@ ENTRY(sys_cmpxchg)
        {
         shri   r20, r25, 32 - ATOMIC_HASH_L1_SHIFT
         slt_u  r23, r0, r23
-
-        /*
-         * Ensure that the TLB is loaded before we take out the lock.
-         * On TILEPro, this will start fetching the value all the way
-         * into our L1 as well (and if it gets modified before we
-         * grab the lock, it will be invalidated from our cache
-         * before we reload it).  On tile64, we'll start fetching it
-         * into our L1 if we're the home, and if we're not, we'll
-         * still at least start fetching it into the home's L2.
-         */
-        lw     r26, r0
+        lw     r26, r0  /* see comment in the "#else" for the "lw r26". */
        }
        {
         s2a    r21, r20, r21
@@ -1637,18 +1550,9 @@ ENTRY(sys_cmpxchg)
         bbs    r23, .Lcmpxchg64
         andi   r23, r0, 7       /* Precompute alignment for cmpxchg64. */
        }
-
        {
-        /*
-         * We very carefully align the code that actually runs with
-         * the lock held (nine bundles) so that we know it is all in
-         * the icache when we start.  This instruction (the jump) is
-         * at the start of the first cache line, address zero mod 64;
-         * we jump to somewhere in the second cache line to issue the
-         * tns, then jump back to finish up.
-         */
         s2a    ATOMIC_LOCK_REG_NAME, r25, r21
-        j      .Lcmpxchg32_tns
+        j      .Lcmpxchg32_tns   /* see comment in the #else for the jump. */
        }
 
 #else /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
@@ -1713,24 +1617,25 @@ ENTRY(sys_cmpxchg)
        {
         /*
          * We very carefully align the code that actually runs with
-         * the lock held (nine bundles) so that we know it is all in
+         * the lock held (twelve bundles) so that we know it is all in
          * the icache when we start.  This instruction (the jump) is
          * at the start of the first cache line, address zero mod 64;
-         * we jump to somewhere in the second cache line to issue the
-         * tns, then jump back to finish up.
+         * we jump to the very end of the second cache line to get that
+         * line loaded in the icache, then fall through to issue the tns
+         * in the third cache line, at which point it's all cached.
+         * Note that is for performance, not correctness.
          */
         j      .Lcmpxchg32_tns
        }
 
 #endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
 
-       ENTRY(__sys_cmpxchg_grab_lock)
+/* Symbol for do_page_fault_ics() to use to compare against the PC. */
+.global __sys_cmpxchg_grab_lock
+__sys_cmpxchg_grab_lock:
 
        /*
         * Perform the actual cmpxchg or atomic_update.
-        * Note that the system <arch/atomic.h> header relies on
-        * atomic_update() to always perform an "mf", so don't make
-        * it optional or conditional without modifying that code.
         */
 .Ldo_cmpxchg32:
        {
@@ -1748,10 +1653,13 @@ ENTRY(sys_cmpxchg)
        }
        {
         mvnz   r24, r23, r25    /* Use atomic_update value if appropriate. */
-        bbns   r22, .Lcmpxchg32_mismatch
+        bbns   r22, .Lcmpxchg32_nostore
        }
+       seq     r22, r24, r21    /* Are we storing the value we loaded? */
+       bbs     r22, .Lcmpxchg32_nostore
        sw      r0, r24
 
+       /* The following instruction is the start of the second cache line. */
        /* Do slow mtspr here so the following "mf" waits less. */
        {
         move   sp, r27
@@ -1759,7 +1667,6 @@ ENTRY(sys_cmpxchg)
        }
        mf
 
-       /* The following instruction is the start of the second cache line. */
        {
         move   r0, r21
         sw     ATOMIC_LOCK_REG_NAME, zero
@@ -1767,7 +1674,7 @@ ENTRY(sys_cmpxchg)
        iret
 
        /* Duplicated code here in the case where we don't overlap "mf" */
-.Lcmpxchg32_mismatch:
+.Lcmpxchg32_nostore:
        {
         move   r0, r21
         sw     ATOMIC_LOCK_REG_NAME, zero
@@ -1783,8 +1690,6 @@ ENTRY(sys_cmpxchg)
         * and for 64-bit cmpxchg.  We provide it as a macro and put
         * it into both versions.  We can't share the code literally
         * since it depends on having the right branch-back address.
-        * Note that the first few instructions should share the cache
-        * line with the second half of the actual locked code.
         */
        .macro  cmpxchg_lock, bitwidth
 
@@ -1810,7 +1715,7 @@ ENTRY(sys_cmpxchg)
        }
        /*
         * The preceding instruction is the last thing that must be
-        * on the second cache line.
+        * hot in the icache before we do the "tns" above.
         */
 
 #ifdef CONFIG_SMP
@@ -1841,6 +1746,12 @@ ENTRY(sys_cmpxchg)
        .endm
 
 .Lcmpxchg32_tns:
+       /*
+        * This is the last instruction on the second cache line.
+        * The nop here loads the second line, then we fall through
+        * to the tns to load the third line before we take the lock.
+        */
+       nop
        cmpxchg_lock 32
 
        /*
diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S
new file mode 100644 (file)
index 0000000..79c93e1
--- /dev/null
@@ -0,0 +1,1231 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * Linux interrupt vectors.
+ */
+
+#include <linux/linkage.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <asm/ptrace.h>
+#include <asm/thread_info.h>
+#include <asm/irqflags.h>
+#include <asm/asm-offsets.h>
+#include <asm/types.h>
+#include <hv/hypervisor.h>
+#include <arch/abi.h>
+#include <arch/interrupts.h>
+#include <arch/spr_def.h>
+
+#ifdef CONFIG_PREEMPT
+# error "No support for kernel preemption currently"
+#endif
+
+#define PTREGS_PTR(reg, ptreg) addli reg, sp, C_ABI_SAVE_AREA_SIZE + (ptreg)
+
+#define PTREGS_OFFSET_SYSCALL PTREGS_OFFSET_REG(TREG_SYSCALL_NR)
+
+
+       .macro  push_reg reg, ptr=sp, delta=-8
+       {
+        st     \ptr, \reg
+        addli  \ptr, \ptr, \delta
+       }
+       .endm
+
+       .macro  pop_reg reg, ptr=sp, delta=8
+       {
+        ld     \reg, \ptr
+        addli  \ptr, \ptr, \delta
+       }
+       .endm
+
+       .macro  pop_reg_zero reg, zreg, ptr=sp, delta=8
+       {
+        move   \zreg, zero
+        ld     \reg, \ptr
+        addi   \ptr, \ptr, \delta
+       }
+       .endm
+
+       .macro  push_extra_callee_saves reg
+       PTREGS_PTR(\reg, PTREGS_OFFSET_REG(51))
+       push_reg r51, \reg
+       push_reg r50, \reg
+       push_reg r49, \reg
+       push_reg r48, \reg
+       push_reg r47, \reg
+       push_reg r46, \reg
+       push_reg r45, \reg
+       push_reg r44, \reg
+       push_reg r43, \reg
+       push_reg r42, \reg
+       push_reg r41, \reg
+       push_reg r40, \reg
+       push_reg r39, \reg
+       push_reg r38, \reg
+       push_reg r37, \reg
+       push_reg r36, \reg
+       push_reg r35, \reg
+       push_reg r34, \reg, PTREGS_OFFSET_BASE - PTREGS_OFFSET_REG(34)
+       .endm
+
+       .macro  panic str
+       .pushsection .rodata, "a"
+1:
+       .asciz  "\str"
+       .popsection
+       {
+        moveli r0, hw2_last(1b)
+       }
+       {
+        shl16insli r0, r0, hw1(1b)
+       }
+       {
+        shl16insli r0, r0, hw0(1b)
+        jal    panic
+       }
+       .endm
+
+
+#ifdef __COLLECT_LINKER_FEEDBACK__
+       .pushsection .text.intvec_feedback,"ax"
+intvec_feedback:
+       .popsection
+#endif
+
+       /*
+        * Default interrupt handler.
+        *
+        * vecnum is where we'll put this code.
+        * c_routine is the C routine we'll call.
+        *
+        * The C routine is passed two arguments:
+        * - A pointer to the pt_regs state.
+        * - The interrupt vector number.
+        *
+        * The "processing" argument specifies the code for processing
+        * the interrupt. Defaults to "handle_interrupt".
+        */
+       .macro  int_hand vecnum, vecname, c_routine, processing=handle_interrupt
+       .org    (\vecnum << 8)
+intvec_\vecname:
+       /* Temporarily save a register so we have somewhere to work. */
+
+       mtspr   SPR_SYSTEM_SAVE_K_1, r0
+       mfspr   r0, SPR_EX_CONTEXT_K_1
+
+       andi    r0, r0, SPR_EX_CONTEXT_1_1__PL_MASK  /* mask off ICS */
+
+       .ifc    \vecnum, INT_DOUBLE_FAULT
+       /*
+        * For double-faults from user-space, fall through to the normal
+        * register save and stack setup path.  Otherwise, it's the
+        * hypervisor giving us one last chance to dump diagnostics, and we
+        * branch to the kernel_double_fault routine to do so.
+        */
+       beqz    r0, 1f
+       j       _kernel_double_fault
+1:
+       .else
+       /*
+        * If we're coming from user-space, then set sp to the top of
+        * the kernel stack.  Otherwise, assume sp is already valid.
+        */
+       {
+        bnez   r0, 0f
+        move   r0, sp
+       }
+       .endif
+
+       .ifc    \c_routine, do_page_fault
+       /*
+        * The page_fault handler may be downcalled directly by the
+        * hypervisor even when Linux is running and has ICS set.
+        *
+        * In this case the contents of EX_CONTEXT_K_1 reflect the
+        * previous fault and can't be relied on to choose whether or
+        * not to reinitialize the stack pointer.  So we add a test
+        * to see whether SYSTEM_SAVE_K_2 has the high bit set,
+        * and if so we don't reinitialize sp, since we must be coming
+        * from Linux.  (In fact the precise case is !(val & ~1),
+        * but any Linux PC has to have the high bit set.)
+        *
+        * Note that the hypervisor *always* sets SYSTEM_SAVE_K_2 for
+        * any path that turns into a downcall to one of our TLB handlers.
+        *
+        * FIXME: if we end up never using this path, perhaps we should
+        * prevent the hypervisor from generating downcalls in this case.
+        * The advantage of getting a downcall is we can panic in Linux.
+        */
+       mfspr   r0, SPR_SYSTEM_SAVE_K_2
+       {
+        bltz   r0, 0f    /* high bit in S_S_1_2 is for a PC to use */
+        move   r0, sp
+       }
+       .endif
+
+
+       /*
+        * SYSTEM_SAVE_K_0 holds the cpu number in the low bits, and
+        * the current stack top in the higher bits.  So we recover
+        * our stack top by just masking off the low bits, then
+        * point sp at the top aligned address on the actual stack page.
+        */
+       mfspr   r0, SPR_SYSTEM_SAVE_K_0
+       mm      r0, zero, LOG2_THREAD_SIZE, 63
+
+0:
+       /*
+        * Align the stack mod 64 so we can properly predict what
+        * cache lines we need to write-hint to reduce memory fetch
+        * latency as we enter the kernel.  The layout of memory is
+        * as follows, with cache line 0 at the lowest VA, and cache
+        * line 8 just below the r0 value this "andi" computes.
+        * Note that we never write to cache line 8, and we skip
+        * cache lines 1-3 for syscalls.
+        *
+        *    cache line 8: ptregs padding (two words)
+        *    cache line 7: sp, lr, pc, ex1, faultnum, orig_r0, flags, cmpexch
+        *    cache line 6: r46...r53 (tp)
+        *    cache line 5: r38...r45
+        *    cache line 4: r30...r37
+        *    cache line 3: r22...r29
+        *    cache line 2: r14...r21
+        *    cache line 1: r6...r13
+        *    cache line 0: 2 x frame, r0..r5
+        */
+       andi    r0, r0, -64
+
+       /*
+        * Push the first four registers on the stack, so that we can set
+        * them to vector-unique values before we jump to the common code.
+        *
+        * Registers are pushed on the stack as a struct pt_regs,
+        * with the sp initially just above the struct, and when we're
+        * done, sp points to the base of the struct, minus
+        * C_ABI_SAVE_AREA_SIZE, so we can directly jal to C code.
+        *
+        * This routine saves just the first four registers, plus the
+        * stack context so we can do proper backtracing right away,
+        * and defers to handle_interrupt to save the rest.
+        * The backtracer needs pc, ex1, lr, sp, r52, and faultnum.
+        */
+       addli   r0, r0, PTREGS_OFFSET_LR - (PTREGS_SIZE + KSTK_PTREGS_GAP)
+       wh64    r0   /* cache line 7 */
+       {
+        st     r0, lr
+        addli  r0, r0, PTREGS_OFFSET_SP - PTREGS_OFFSET_LR
+       }
+       {
+        st     r0, sp
+        addli  sp, r0, PTREGS_OFFSET_REG(52) - PTREGS_OFFSET_SP
+       }
+       wh64    sp   /* cache line 6 */
+       {
+        st     sp, r52
+        addli  sp, sp, PTREGS_OFFSET_REG(1) - PTREGS_OFFSET_REG(52)
+       }
+       wh64    sp   /* cache line 0 */
+       {
+        st     sp, r1
+        addli  sp, sp, PTREGS_OFFSET_REG(2) - PTREGS_OFFSET_REG(1)
+       }
+       {
+        st     sp, r2
+        addli  sp, sp, PTREGS_OFFSET_REG(3) - PTREGS_OFFSET_REG(2)
+       }
+       {
+        st     sp, r3
+        addli  sp, sp, PTREGS_OFFSET_PC - PTREGS_OFFSET_REG(3)
+       }
+       mfspr   r0, SPR_EX_CONTEXT_K_0
+       .ifc \processing,handle_syscall
+       /*
+        * Bump the saved PC by one bundle so that when we return, we won't
+        * execute the same swint instruction again.  We need to do this while
+        * we're in the critical section.
+        */
+       addi    r0, r0, 8
+       .endif
+       {
+        st     sp, r0
+        addli  sp, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC
+       }
+       mfspr   r0, SPR_EX_CONTEXT_K_1
+       {
+        st     sp, r0
+        addi   sp, sp, PTREGS_OFFSET_FAULTNUM - PTREGS_OFFSET_EX1
+       /*
+        * Use r0 for syscalls so it's a temporary; use r1 for interrupts
+        * so that it gets passed through unchanged to the handler routine.
+        * Note that the .if conditional confusingly spans bundles.
+        */
+        .ifc \processing,handle_syscall
+        movei  r0, \vecnum
+       }
+       {
+        st     sp, r0
+        .else
+        movei  r1, \vecnum
+       }
+       {
+        st     sp, r1
+        .endif
+        addli  sp, sp, PTREGS_OFFSET_REG(0) - PTREGS_OFFSET_FAULTNUM
+       }
+       mfspr   r0, SPR_SYSTEM_SAVE_K_1    /* Original r0 */
+       {
+        st     sp, r0
+        addi   sp, sp, -PTREGS_OFFSET_REG(0) - 8
+       }
+       {
+        st     sp, zero        /* write zero into "Next SP" frame pointer */
+        addi   sp, sp, -8      /* leave SP pointing at bottom of frame */
+       }
+       .ifc \processing,handle_syscall
+       j       handle_syscall
+       .else
+       /* Capture per-interrupt SPR context to registers. */
+       .ifc \c_routine, do_page_fault
+       mfspr   r2, SPR_SYSTEM_SAVE_K_3   /* address of page fault */
+       mfspr   r3, SPR_SYSTEM_SAVE_K_2   /* info about page fault */
+       .else
+       .ifc \vecnum, INT_ILL_TRANS
+       mfspr   r2, ILL_TRANS_REASON
+       .else
+       .ifc \vecnum, INT_DOUBLE_FAULT
+       mfspr   r2, SPR_SYSTEM_SAVE_K_2   /* double fault info from HV */
+       .else
+       .ifc \c_routine, do_trap
+       mfspr   r2, GPV_REASON
+       .else
+       .ifc \c_routine, op_handle_perf_interrupt
+       mfspr   r2, PERF_COUNT_STS
+#if CHIP_HAS_AUX_PERF_COUNTERS()
+       .else
+       .ifc \c_routine, op_handle_aux_perf_interrupt
+       mfspr   r2, AUX_PERF_COUNT_STS
+       .endif
+#endif
+       .endif
+       .endif
+       .endif
+       .endif
+       .endif
+       /* Put function pointer in r0 */
+       moveli  r0, hw2_last(\c_routine)
+       shl16insli r0, r0, hw1(\c_routine)
+       {
+        shl16insli r0, r0, hw0(\c_routine)
+        j       \processing
+       }
+       .endif
+       ENDPROC(intvec_\vecname)
+
+#ifdef __COLLECT_LINKER_FEEDBACK__
+       .pushsection .text.intvec_feedback,"ax"
+       .org    (\vecnum << 5)
+       FEEDBACK_ENTER_EXPLICIT(intvec_\vecname, .intrpt1, 1 << 8)
+       jrp     lr
+       .popsection
+#endif
+
+       .endm
+
+
+       /*
+        * Save the rest of the registers that we didn't save in the actual
+        * vector itself.  We can't use r0-r10 inclusive here.
+        */
+       .macro  finish_interrupt_save, function
+
+       /* If it's a syscall, save a proper orig_r0, otherwise just zero. */
+       PTREGS_PTR(r52, PTREGS_OFFSET_ORIG_R0)
+       {
+        .ifc \function,handle_syscall
+        st     r52, r0
+        .else
+        st     r52, zero
+        .endif
+        PTREGS_PTR(r52, PTREGS_OFFSET_TP)
+       }
+       st      r52, tp
+       {
+        mfspr  tp, CMPEXCH_VALUE
+        PTREGS_PTR(r52, PTREGS_OFFSET_CMPEXCH)
+       }
+
+       /*
+        * For ordinary syscalls, we save neither caller- nor callee-
+        * save registers, since the syscall invoker doesn't expect the
+        * caller-saves to be saved, and the called kernel functions will
+        * take care of saving the callee-saves for us.
+        *
+        * For interrupts we save just the caller-save registers.  Saving
+        * them is required (since the "caller" can't save them).  Again,
+        * the called kernel functions will restore the callee-save
+        * registers for us appropriately.
+        *
+        * On return, we normally restore nothing special for syscalls,
+        * and just the caller-save registers for interrupts.
+        *
+        * However, there are some important caveats to all this:
+        *
+        * - We always save a few callee-save registers to give us
+        *   some scratchpad registers to carry across function calls.
+        *
+        * - fork/vfork/etc require us to save all the callee-save
+        *   registers, which we do in PTREGS_SYSCALL_ALL_REGS, below.
+        *
+        * - We always save r0..r5 and r10 for syscalls, since we need
+        *   to reload them a bit later for the actual kernel call, and
+        *   since we might need them for -ERESTARTNOINTR, etc.
+        *
+        * - Before invoking a signal handler, we save the unsaved
+        *   callee-save registers so they are visible to the
+        *   signal handler or any ptracer.
+        *
+        * - If the unsaved callee-save registers are modified, we set
+        *   a bit in pt_regs so we know to reload them from pt_regs
+        *   and not just rely on the kernel function unwinding.
+        *   (Done for ptrace register writes and SA_SIGINFO handler.)
+        */
+       {
+        st     r52, tp
+        PTREGS_PTR(r52, PTREGS_OFFSET_REG(33))
+       }
+       wh64    r52    /* cache line 4 */
+       push_reg r33, r52
+       push_reg r32, r52
+       push_reg r31, r52
+       .ifc \function,handle_syscall
+       push_reg r30, r52, PTREGS_OFFSET_SYSCALL - PTREGS_OFFSET_REG(30)
+       push_reg TREG_SYSCALL_NR_NAME, r52, \
+         PTREGS_OFFSET_REG(5) - PTREGS_OFFSET_SYSCALL
+       .else
+
+       push_reg r30, r52, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(30)
+       wh64    r52   /* cache line 3 */
+       push_reg r29, r52
+       push_reg r28, r52
+       push_reg r27, r52
+       push_reg r26, r52
+       push_reg r25, r52
+       push_reg r24, r52
+       push_reg r23, r52
+       push_reg r22, r52
+       wh64    r52   /* cache line 2 */
+       push_reg r21, r52
+       push_reg r20, r52
+       push_reg r19, r52
+       push_reg r18, r52
+       push_reg r17, r52
+       push_reg r16, r52
+       push_reg r15, r52
+       push_reg r14, r52
+       wh64    r52   /* cache line 1 */
+       push_reg r13, r52
+       push_reg r12, r52
+       push_reg r11, r52
+       push_reg r10, r52
+       push_reg r9, r52
+       push_reg r8, r52
+       push_reg r7, r52
+       push_reg r6, r52
+
+       .endif
+
+       push_reg r5, r52
+       st      r52, r4
+
+       /* Load tp with our per-cpu offset. */
+#ifdef CONFIG_SMP
+       {
+        mfspr  r20, SPR_SYSTEM_SAVE_K_0
+        moveli r21, hw2_last(__per_cpu_offset)
+       }
+       {
+        shl16insli r21, r21, hw1(__per_cpu_offset)
+        bfextu r20, r20, 0, LOG2_THREAD_SIZE-1
+       }
+       shl16insli r21, r21, hw0(__per_cpu_offset)
+       shl3add r20, r20, r21
+       ld      tp, r20
+#else
+       move    tp, zero
+#endif
+
+       /*
+        * If we will be returning to the kernel, we will need to
+        * reset the interrupt masks to the state they had before.
+        * Set DISABLE_IRQ in flags iff we came from PL1 with irqs disabled.
+        */
+       mfspr   r32, SPR_EX_CONTEXT_K_1
+       {
+        andi   r32, r32, SPR_EX_CONTEXT_1_1__PL_MASK  /* mask off ICS */
+        PTREGS_PTR(r21, PTREGS_OFFSET_FLAGS)
+       }
+       beqzt   r32, 1f       /* zero if from user space */
+       IRQS_DISABLED(r32)    /* zero if irqs enabled */
+#if PT_FLAGS_DISABLE_IRQ != 1
+# error Value of IRQS_DISABLED used to set PT_FLAGS_DISABLE_IRQ; fix
+#endif
+1:
+       .ifnc \function,handle_syscall
+       /* Record the fact that we saved the caller-save registers above. */
+       ori     r32, r32, PT_FLAGS_CALLER_SAVES
+       .endif
+       st      r21, r32
+
+#ifdef __COLLECT_LINKER_FEEDBACK__
+       /*
+        * Notify the feedback routines that we were in the
+        * appropriate fixed interrupt vector area.  Note that we
+        * still have ICS set at this point, so we can't invoke any
+        * atomic operations or we will panic.  The feedback
+        * routines internally preserve r0..r10 and r30 up.
+        */
+       .ifnc \function,handle_syscall
+       shli    r20, r1, 5
+       .else
+       moveli  r20, INT_SWINT_1 << 5
+       .endif
+       moveli  r21, hw2_last(intvec_feedback)
+       shl16insli r21, r21, hw1(intvec_feedback)
+       shl16insli r21, r21, hw0(intvec_feedback)
+       add     r20, r20, r21
+       jalr    r20
+
+       /* And now notify the feedback routines that we are here. */
+       FEEDBACK_ENTER(\function)
+#endif
+
+       /*
+        * we've captured enough state to the stack (including in
+        * particular our EX_CONTEXT state) that we can now release
+        * the interrupt critical section and replace it with our
+        * standard "interrupts disabled" mask value.  This allows
+        * synchronous interrupts (and profile interrupts) to punch
+        * through from this point onwards.
+        */
+       .ifc \function,handle_nmi
+       IRQ_DISABLE_ALL(r20)
+       .else
+       IRQ_DISABLE(r20, r21)
+       .endif
+       mtspr   INTERRUPT_CRITICAL_SECTION, zero
+
+       /*
+        * Prepare the first 256 stack bytes to be rapidly accessible
+        * without having to fetch the background data.
+        */
+       addi    r52, sp, -64
+       {
+        wh64   r52
+        addi   r52, r52, -64
+       }
+       {
+        wh64   r52
+        addi   r52, r52, -64
+       }
+       {
+        wh64   r52
+        addi   r52, r52, -64
+       }
+       wh64    r52
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+       .ifnc \function,handle_nmi
+       /*
+        * We finally have enough state set up to notify the irq
+        * tracing code that irqs were disabled on entry to the handler.
+        * The TRACE_IRQS_OFF call clobbers registers r0-r29.
+        * For syscalls, we already have the register state saved away
+        * on the stack, so we don't bother to do any register saves here,
+        * and later we pop the registers back off the kernel stack.
+        * For interrupt handlers, save r0-r3 in callee-saved registers.
+        */
+       .ifnc \function,handle_syscall
+       { move r30, r0; move r31, r1 }
+       { move r32, r2; move r33, r3 }
+       .endif
+       TRACE_IRQS_OFF
+       .ifnc \function,handle_syscall
+       { move r0, r30; move r1, r31 }
+       { move r2, r32; move r3, r33 }
+       .endif
+       .endif
+#endif
+
+       .endm
+
+       /*
+        * Redispatch a downcall.
+        */
+       .macro  dc_dispatch vecnum, vecname
+       .org    (\vecnum << 8)
+intvec_\vecname:
+       j       hv_downcall_dispatch
+       ENDPROC(intvec_\vecname)
+       .endm
+
+       /*
+        * Common code for most interrupts.  The C function we're eventually
+        * going to is in r0, and the faultnum is in r1; the original
+        * values for those registers are on the stack.
+        */
+       .pushsection .text.handle_interrupt,"ax"
+handle_interrupt:
+       finish_interrupt_save handle_interrupt
+
+       /* Jump to the C routine; it should enable irqs as soon as possible. */
+       {
+        jalr   r0
+        PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+       }
+       FEEDBACK_REENTER(handle_interrupt)
+       {
+        movei  r30, 0   /* not an NMI */
+        j      interrupt_return
+       }
+       STD_ENDPROC(handle_interrupt)
+
+/*
+ * This routine takes a boolean in r30 indicating if this is an NMI.
+ * If so, we also expect a boolean in r31 indicating whether to
+ * re-enable the oprofile interrupts.
+ */
+STD_ENTRY(interrupt_return)
+       /* If we're resuming to kernel space, don't check thread flags. */
+       {
+        bnez   r30, .Lrestore_all  /* NMIs don't special-case user-space */
+        PTREGS_PTR(r29, PTREGS_OFFSET_EX1)
+       }
+       ld      r29, r29
+       andi    r29, r29, SPR_EX_CONTEXT_1_1__PL_MASK  /* mask off ICS */
+       {
+        beqzt  r29, .Lresume_userspace
+        PTREGS_PTR(r29, PTREGS_OFFSET_PC)
+       }
+
+       /* If we're resuming to _cpu_idle_nap, bump PC forward by 8. */
+       moveli  r27, hw2_last(_cpu_idle_nap)
+       {
+        ld     r28, r29
+        shl16insli r27, r27, hw1(_cpu_idle_nap)
+       }
+       {
+        shl16insli r27, r27, hw0(_cpu_idle_nap)
+       }
+       {
+        cmpeq  r27, r27, r28
+       }
+       {
+        blbc   r27, .Lrestore_all
+        addi   r28, r28, 8
+       }
+       st      r29, r28
+       j       .Lrestore_all
+
+.Lresume_userspace:
+       FEEDBACK_REENTER(interrupt_return)
+
+       /*
+        * Disable interrupts so as to make sure we don't
+        * miss an interrupt that sets any of the thread flags (like
+        * need_resched or sigpending) between sampling and the iret.
+        * Routines like schedule() or do_signal() may re-enable
+        * interrupts before returning.
+        */
+       IRQ_DISABLE(r20, r21)
+       TRACE_IRQS_OFF  /* Note: clobbers registers r0-r29 */
+
+       /* Get base of stack in r32; note r30/31 are used as arguments here. */
+       GET_THREAD_INFO(r32)
+
+
+       /* Check to see if there is any work to do before returning to user. */
+       {
+        addi   r29, r32, THREAD_INFO_FLAGS_OFFSET
+        moveli r1, hw1_last(_TIF_ALLWORK_MASK)
+       }
+       {
+        ld     r29, r29
+        shl16insli r1, r1, hw0(_TIF_ALLWORK_MASK)
+       }
+       and     r1, r29, r1
+       beqzt   r1, .Lrestore_all
+
+       /*
+        * Make sure we have all the registers saved for signal
+        * handling or single-step.  Call out to C code to figure out
+        * exactly what we need to do for each flag bit, then if
+        * necessary, reload the flags and recheck.
+        */
+       push_extra_callee_saves r0
+       {
+        PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+        jal    do_work_pending
+       }
+       bnez    r0, .Lresume_userspace
+
+       /*
+        * In the NMI case we
+        * omit the call to single_process_check_nohz, which normally checks
+        * to see if we should start or stop the scheduler tick, because
+        * we can't call arbitrary Linux code from an NMI context.
+        * We always call the homecache TLB deferral code to re-trigger
+        * the deferral mechanism.
+        *
+        * The other chunk of responsibility this code has is to reset the
+        * interrupt masks appropriately to reset irqs and NMIs.  We have
+        * to call TRACE_IRQS_OFF and TRACE_IRQS_ON to support all the
+        * lockdep-type stuff, but we can't set ICS until afterwards, since
+        * ICS can only be used in very tight chunks of code to avoid
+        * tripping over various assertions that it is off.
+        */
+.Lrestore_all:
+       PTREGS_PTR(r0, PTREGS_OFFSET_EX1)
+       {
+        ld      r0, r0
+        PTREGS_PTR(r32, PTREGS_OFFSET_FLAGS)
+       }
+       {
+        andi   r0, r0, SPR_EX_CONTEXT_1_1__PL_MASK
+        ld     r32, r32
+       }
+       bnez    r0, 1f
+       j       2f
+#if PT_FLAGS_DISABLE_IRQ != 1
+# error Assuming PT_FLAGS_DISABLE_IRQ == 1 so we can use blbct below
+#endif
+1:     blbct   r32, 2f
+       IRQ_DISABLE(r20,r21)
+       TRACE_IRQS_OFF
+       movei   r0, 1
+       mtspr   INTERRUPT_CRITICAL_SECTION, r0
+       beqzt   r30, .Lrestore_regs
+       j       3f
+2:     TRACE_IRQS_ON
+       movei   r0, 1
+       mtspr   INTERRUPT_CRITICAL_SECTION, r0
+       IRQ_ENABLE(r20, r21)
+       beqzt   r30, .Lrestore_regs
+3:
+
+
+       /*
+        * We now commit to returning from this interrupt, since we will be
+        * doing things like setting EX_CONTEXT SPRs and unwinding the stack
+        * frame.  No calls should be made to any other code after this point.
+        * This code should only be entered with ICS set.
+        * r32 must still be set to ptregs.flags.
+        * We launch loads to each cache line separately first, so we can
+        * get some parallelism out of the memory subsystem.
+        * We start zeroing caller-saved registers throughout, since
+        * that will save some cycles if this turns out to be a syscall.
+        */
+.Lrestore_regs:
+       FEEDBACK_REENTER(interrupt_return)   /* called from elsewhere */
+
+       /*
+        * Rotate so we have one high bit and one low bit to test.
+        * - low bit says whether to restore all the callee-saved registers,
+        *   or just r30-r33, and r52 up.
+        * - high bit (i.e. sign bit) says whether to restore all the
+        *   caller-saved registers, or just r0.
+        */
+#if PT_FLAGS_CALLER_SAVES != 2 || PT_FLAGS_RESTORE_REGS != 4
+# error Rotate trick does not work :-)
+#endif
+       {
+        rotli  r20, r32, 62
+        PTREGS_PTR(sp, PTREGS_OFFSET_REG(0))
+       }
+
+       /*
+        * Load cache lines 0, 4, 6 and 7, in that order, then use
+        * the last loaded value, which makes it likely that the other
+        * cache lines have also loaded, at which point we should be
+        * able to safely read all the remaining words on those cache
+        * lines without waiting for the memory subsystem.
+        */
+       pop_reg r0, sp, PTREGS_OFFSET_REG(30) - PTREGS_OFFSET_REG(0)
+       pop_reg r30, sp, PTREGS_OFFSET_REG(52) - PTREGS_OFFSET_REG(30)
+       pop_reg_zero r52, r3, sp, PTREGS_OFFSET_CMPEXCH - PTREGS_OFFSET_REG(52)
+       pop_reg_zero r21, r27, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_CMPEXCH
+       pop_reg_zero lr, r2, sp, PTREGS_OFFSET_PC - PTREGS_OFFSET_EX1
+       {
+        mtspr  CMPEXCH_VALUE, r21
+        move   r4, zero
+       }
+       pop_reg r21, sp, PTREGS_OFFSET_REG(31) - PTREGS_OFFSET_PC
+       {
+        mtspr  SPR_EX_CONTEXT_K_1, lr
+        andi   lr, lr, SPR_EX_CONTEXT_1_1__PL_MASK  /* mask off ICS */
+       }
+       {
+        mtspr  SPR_EX_CONTEXT_K_0, r21
+        move   r5, zero
+       }
+
+       /* Restore callee-saveds that we actually use. */
+       pop_reg_zero r31, r6
+       pop_reg_zero r32, r7
+       pop_reg_zero r33, r8, sp, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(33)
+
+       /*
+        * If we modified other callee-saveds, restore them now.
+        * This is rare, but could be via ptrace or signal handler.
+        */
+       {
+        move   r9, zero
+        blbs   r20, .Lrestore_callees
+       }
+.Lcontinue_restore_regs:
+
+       /* Check if we're returning from a syscall. */
+       {
+        move   r10, zero
+        bltzt  r20, 1f  /* no, so go restore callee-save registers */
+       }
+
+       /*
+        * Check if we're returning to userspace.
+        * Note that if we're not, we don't worry about zeroing everything.
+        */
+       {
+        addli  sp, sp, PTREGS_OFFSET_LR - PTREGS_OFFSET_REG(29)
+        bnez   lr, .Lkernel_return
+       }
+
+       /*
+        * On return from syscall, we've restored r0 from pt_regs, but we
+        * clear the remainder of the caller-saved registers.  We could
+        * restore the syscall arguments, but there's not much point,
+        * and it ensures user programs aren't trying to use the
+        * caller-saves if we clear them, as well as avoiding leaking
+        * kernel pointers into userspace.
+        */
+       pop_reg_zero lr, r11, sp, PTREGS_OFFSET_TP - PTREGS_OFFSET_LR
+       pop_reg_zero tp, r12, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_TP
+       {
+        ld     sp, sp
+        move   r13, zero
+        move   r14, zero
+       }
+       { move r15, zero; move r16, zero }
+       { move r17, zero; move r18, zero }
+       { move r19, zero; move r20, zero }
+       { move r21, zero; move r22, zero }
+       { move r23, zero; move r24, zero }
+       { move r25, zero; move r26, zero }
+
+       /* Set r1 to errno if we are returning an error, otherwise zero. */
+       {
+        moveli r29, 4096
+        sub    r1, zero, r0
+       }
+       {
+        move   r28, zero
+        cmpltu r29, r1, r29
+       }
+       {
+        mnz    r1, r29, r1
+        move   r29, zero
+       }
+       iret
+
+       /*
+        * Not a syscall, so restore caller-saved registers.
+        * First kick off loads for cache lines 1-3, which we're touching
+        * for the first time here.
+        */
+       .align 64
+1:     pop_reg r29, sp, PTREGS_OFFSET_REG(21) - PTREGS_OFFSET_REG(29)
+       pop_reg r21, sp, PTREGS_OFFSET_REG(13) - PTREGS_OFFSET_REG(21)
+       pop_reg r13, sp, PTREGS_OFFSET_REG(1) - PTREGS_OFFSET_REG(13)
+       pop_reg r1
+       pop_reg r2
+       pop_reg r3
+       pop_reg r4
+       pop_reg r5
+       pop_reg r6
+       pop_reg r7
+       pop_reg r8
+       pop_reg r9
+       pop_reg r10
+       pop_reg r11
+       pop_reg r12, sp, 16
+       /* r13 already restored above */
+       pop_reg r14
+       pop_reg r15
+       pop_reg r16
+       pop_reg r17
+       pop_reg r18
+       pop_reg r19
+       pop_reg r20, sp, 16
+       /* r21 already restored above */
+       pop_reg r22
+       pop_reg r23
+       pop_reg r24
+       pop_reg r25
+       pop_reg r26
+       pop_reg r27
+       pop_reg r28, sp, PTREGS_OFFSET_LR - PTREGS_OFFSET_REG(28)
+       /* r29 already restored above */
+       bnez    lr, .Lkernel_return
+       pop_reg lr, sp, PTREGS_OFFSET_TP - PTREGS_OFFSET_LR
+       pop_reg tp, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_TP
+       ld      sp, sp
+       iret
+
+       /*
+        * We can't restore tp when in kernel mode, since a thread might
+        * have migrated from another cpu and brought a stale tp value.
+        */
+.Lkernel_return:
+       pop_reg lr, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_LR
+       ld      sp, sp
+       iret
+
+       /* Restore callee-saved registers from r34 to r51. */
+.Lrestore_callees:
+       addli  sp, sp, PTREGS_OFFSET_REG(34) - PTREGS_OFFSET_REG(29)
+       pop_reg r34
+       pop_reg r35
+       pop_reg r36
+       pop_reg r37
+       pop_reg r38
+       pop_reg r39
+       pop_reg r40
+       pop_reg r41
+       pop_reg r42
+       pop_reg r43
+       pop_reg r44
+       pop_reg r45
+       pop_reg r46
+       pop_reg r47
+       pop_reg r48
+       pop_reg r49
+       pop_reg r50
+       pop_reg r51, sp, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(51)
+       j .Lcontinue_restore_regs
+       STD_ENDPROC(interrupt_return)
+
+       /*
+        * "NMI" interrupts mask ALL interrupts before calling the
+        * handler, and don't check thread flags, etc., on the way
+        * back out.  In general, the only things we do here for NMIs
+        * are register save/restore and dataplane kernel-TLB management.
+        * We don't (for example) deal with start/stop of the sched tick.
+        */
+       .pushsection .text.handle_nmi,"ax"
+handle_nmi:
+       finish_interrupt_save handle_nmi
+       {
+        jalr   r0
+        PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+       }
+       FEEDBACK_REENTER(handle_nmi)
+       {
+        movei  r30, 1
+        move   r31, r0
+       }
+       j       interrupt_return
+       STD_ENDPROC(handle_nmi)
+
+       /*
+        * Parallel code for syscalls to handle_interrupt.
+        */
+       .pushsection .text.handle_syscall,"ax"
+handle_syscall:
+       finish_interrupt_save handle_syscall
+
+       /* Enable irqs. */
+       TRACE_IRQS_ON
+       IRQ_ENABLE(r20, r21)
+
+       /* Bump the counter for syscalls made on this tile. */
+       moveli r20, hw2_last(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET)
+       shl16insli r20, r20, hw1(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET)
+       shl16insli r20, r20, hw0(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET)
+       add     r20, r20, tp
+       ld4s    r21, r20
+       addi    r21, r21, 1
+       st4     r20, r21
+
+       /* Trace syscalls, if requested. */
+       GET_THREAD_INFO(r31)
+       addi    r31, r31, THREAD_INFO_FLAGS_OFFSET
+       ld      r30, r31
+       andi    r30, r30, _TIF_SYSCALL_TRACE
+       {
+        addi   r30, r31, THREAD_INFO_STATUS_OFFSET - THREAD_INFO_FLAGS_OFFSET
+        beqzt  r30, .Lrestore_syscall_regs
+       }
+       jal     do_syscall_trace
+       FEEDBACK_REENTER(handle_syscall)
+
+       /*
+        * We always reload our registers from the stack at this
+        * point.  They might be valid, if we didn't build with
+        * TRACE_IRQFLAGS, and this isn't a dataplane tile, and we're not
+        * doing syscall tracing, but there are enough cases now that it
+        * seems simplest just to do the reload unconditionally.
+        */
+.Lrestore_syscall_regs:
+       {
+        ld     r30, r30
+        PTREGS_PTR(r11, PTREGS_OFFSET_REG(0))
+       }
+       pop_reg r0,  r11
+       pop_reg r1,  r11
+       pop_reg r2,  r11
+       pop_reg r3,  r11
+       pop_reg r4,  r11
+       pop_reg r5,  r11, PTREGS_OFFSET_SYSCALL - PTREGS_OFFSET_REG(5)
+       {
+        ld     TREG_SYSCALL_NR_NAME, r11
+        moveli r21, __NR_syscalls
+       }
+
+       /* Ensure that the syscall number is within the legal range. */
+       {
+        moveli r20, hw2(sys_call_table)
+        blbs   r30, .Lcompat_syscall
+       }
+       {
+        cmpltu r21, TREG_SYSCALL_NR_NAME, r21
+        shl16insli r20, r20, hw1(sys_call_table)
+       }
+       {
+        blbc   r21, .Linvalid_syscall
+        shl16insli r20, r20, hw0(sys_call_table)
+       }
+.Lload_syscall_pointer:
+       shl3add r20, TREG_SYSCALL_NR_NAME, r20
+       ld      r20, r20
+
+       /* Jump to syscall handler. */
+       jalr    r20
+.Lhandle_syscall_link: /* value of "lr" after "jalr r20" above */
+
+       /*
+        * Write our r0 onto the stack so it gets restored instead
+        * of whatever the user had there before.
+        * In compat mode, sign-extend r0 before storing it.
+        */
+       {
+        PTREGS_PTR(r29, PTREGS_OFFSET_REG(0))
+        blbct  r30, 1f
+       }
+       addxi   r0, r0, 0
+1:     st      r29, r0
+
+.Lsyscall_sigreturn_skip:
+       FEEDBACK_REENTER(handle_syscall)
+
+       /* Do syscall trace again, if requested. */
+       ld      r30, r31
+       andi    r30, r30, _TIF_SYSCALL_TRACE
+       beqzt   r30, 1f
+       jal     do_syscall_trace
+       FEEDBACK_REENTER(handle_syscall)
+1:     j       .Lresume_userspace   /* jump into middle of interrupt_return */
+
+.Lcompat_syscall:
+       /*
+        * Load the base of the compat syscall table in r20, and
+        * range-check the syscall number (duplicated from 64-bit path).
+        * Sign-extend all the user's passed arguments to make them consistent.
+        * Also save the original "r(n)" values away in "r(11+n)" in
+        * case the syscall table entry wants to validate them.
+        */
+       moveli  r20, hw2(compat_sys_call_table)
+       {
+        cmpltu r21, TREG_SYSCALL_NR_NAME, r21
+        shl16insli r20, r20, hw1(compat_sys_call_table)
+       }
+       {
+        blbc   r21, .Linvalid_syscall
+        shl16insli r20, r20, hw0(compat_sys_call_table)
+       }
+       { move r11, r0; addxi r0, r0, 0 }
+       { move r12, r1; addxi r1, r1, 0 }
+       { move r13, r2; addxi r2, r2, 0 }
+       { move r14, r3; addxi r3, r3, 0 }
+       { move r15, r4; addxi r4, r4, 0 }
+       { move r16, r5; addxi r5, r5, 0 }
+       j .Lload_syscall_pointer
+
+.Linvalid_syscall:
+       /* Report an invalid syscall back to the user program */
+       {
+        PTREGS_PTR(r29, PTREGS_OFFSET_REG(0))
+        movei  r28, -ENOSYS
+       }
+       st      r29, r28
+       j       .Lresume_userspace   /* jump into middle of interrupt_return */
+       STD_ENDPROC(handle_syscall)
+
+       /* Return the address for oprofile to suppress in backtraces. */
+STD_ENTRY_SECTION(handle_syscall_link_address, .text.handle_syscall)
+       lnk     r0
+       {
+        addli  r0, r0, .Lhandle_syscall_link - .
+        jrp    lr
+       }
+       STD_ENDPROC(handle_syscall_link_address)
+
+STD_ENTRY(ret_from_fork)
+       jal     sim_notify_fork
+       jal     schedule_tail
+       FEEDBACK_REENTER(ret_from_fork)
+       j       .Lresume_userspace
+       STD_ENDPROC(ret_from_fork)
+
+/* Various stub interrupt handlers and syscall handlers */
+
+STD_ENTRY_LOCAL(_kernel_double_fault)
+       mfspr   r1, SPR_EX_CONTEXT_K_0
+       move    r2, lr
+       move    r3, sp
+       move    r4, r52
+       addi    sp, sp, -C_ABI_SAVE_AREA_SIZE
+       j       kernel_double_fault
+       STD_ENDPROC(_kernel_double_fault)
+
+STD_ENTRY_LOCAL(bad_intr)
+       mfspr   r2, SPR_EX_CONTEXT_K_0
+       panic   "Unhandled interrupt %#x: PC %#lx"
+       STD_ENDPROC(bad_intr)
+
+/* Put address of pt_regs in reg and jump. */
+#define PTREGS_SYSCALL(x, reg)                          \
+       STD_ENTRY(_##x);                                \
+       {                                               \
+        PTREGS_PTR(reg, PTREGS_OFFSET_BASE);           \
+        j      x                                       \
+       };                                              \
+       STD_ENDPROC(_##x)
+
+/*
+ * Special-case sigreturn to not write r0 to the stack on return.
+ * This is technically more efficient, but it also avoids difficulties
+ * in the 64-bit OS when handling 32-bit compat code, since we must not
+ * sign-extend r0 for the sigreturn return-value case.
+ */
+#define PTREGS_SYSCALL_SIGRETURN(x, reg)                \
+       STD_ENTRY(_##x);                                \
+       addli   lr, lr, .Lsyscall_sigreturn_skip - .Lhandle_syscall_link; \
+       {                                               \
+        PTREGS_PTR(reg, PTREGS_OFFSET_BASE);           \
+        j      x                                       \
+       };                                              \
+       STD_ENDPROC(_##x)
+
+PTREGS_SYSCALL(sys_execve, r3)
+PTREGS_SYSCALL(sys_sigaltstack, r2)
+PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0)
+#ifdef CONFIG_COMPAT
+PTREGS_SYSCALL(compat_sys_execve, r3)
+PTREGS_SYSCALL(compat_sys_sigaltstack, r2)
+PTREGS_SYSCALL_SIGRETURN(compat_sys_rt_sigreturn, r0)
+#endif
+
+/* Save additional callee-saves to pt_regs, put address in r4 and jump. */
+STD_ENTRY(_sys_clone)
+       push_extra_callee_saves r4
+       j       sys_clone
+       STD_ENDPROC(_sys_clone)
+
+/* The single-step support may need to read all the registers. */
+int_unalign:
+       push_extra_callee_saves r0
+       j       do_trap
+
+/* Include .intrpt1 array of interrupt vectors */
+       .section ".intrpt1", "ax"
+
+#define op_handle_perf_interrupt bad_intr
+#define op_handle_aux_perf_interrupt bad_intr
+
+#ifndef CONFIG_HARDWALL
+#define do_hardwall_trap bad_intr
+#endif
+
+       int_hand     INT_MEM_ERROR, MEM_ERROR, bad_intr
+       int_hand     INT_SINGLE_STEP_3, SINGLE_STEP_3, bad_intr
+#if CONFIG_KERNEL_PL == 2
+       int_hand     INT_SINGLE_STEP_2, SINGLE_STEP_2, gx_singlestep_handle
+       int_hand     INT_SINGLE_STEP_1, SINGLE_STEP_1, bad_intr
+#else
+       int_hand     INT_SINGLE_STEP_2, SINGLE_STEP_2, bad_intr
+       int_hand     INT_SINGLE_STEP_1, SINGLE_STEP_1, gx_singlestep_handle
+#endif
+       int_hand     INT_SINGLE_STEP_0, SINGLE_STEP_0, bad_intr
+       int_hand     INT_IDN_COMPLETE, IDN_COMPLETE, bad_intr
+       int_hand     INT_UDN_COMPLETE, UDN_COMPLETE, bad_intr
+       int_hand     INT_ITLB_MISS, ITLB_MISS, do_page_fault
+       int_hand     INT_ILL, ILL, do_trap
+       int_hand     INT_GPV, GPV, do_trap
+       int_hand     INT_IDN_ACCESS, IDN_ACCESS, do_trap
+       int_hand     INT_UDN_ACCESS, UDN_ACCESS, do_trap
+       int_hand     INT_SWINT_3, SWINT_3, do_trap
+       int_hand     INT_SWINT_2, SWINT_2, do_trap
+       int_hand     INT_SWINT_1, SWINT_1, SYSCALL, handle_syscall
+       int_hand     INT_SWINT_0, SWINT_0, do_trap
+       int_hand     INT_ILL_TRANS, ILL_TRANS, do_trap
+       int_hand     INT_UNALIGN_DATA, UNALIGN_DATA, int_unalign
+       int_hand     INT_DTLB_MISS, DTLB_MISS, do_page_fault
+       int_hand     INT_DTLB_ACCESS, DTLB_ACCESS, do_page_fault
+       int_hand     INT_IDN_FIREWALL, IDN_FIREWALL, bad_intr
+       int_hand     INT_UDN_FIREWALL, UDN_FIREWALL, do_hardwall_trap
+       int_hand     INT_TILE_TIMER, TILE_TIMER, do_timer_interrupt
+       int_hand     INT_IDN_TIMER, IDN_TIMER, bad_intr
+       int_hand     INT_UDN_TIMER, UDN_TIMER, bad_intr
+       int_hand     INT_IDN_AVAIL, IDN_AVAIL, bad_intr
+       int_hand     INT_UDN_AVAIL, UDN_AVAIL, bad_intr
+       int_hand     INT_IPI_3, IPI_3, bad_intr
+#if CONFIG_KERNEL_PL == 2
+       int_hand     INT_IPI_2, IPI_2, tile_dev_intr
+       int_hand     INT_IPI_1, IPI_1, bad_intr
+#else
+       int_hand     INT_IPI_2, IPI_2, bad_intr
+       int_hand     INT_IPI_1, IPI_1, tile_dev_intr
+#endif
+       int_hand     INT_IPI_0, IPI_0, bad_intr
+       int_hand     INT_PERF_COUNT, PERF_COUNT, \
+                    op_handle_perf_interrupt, handle_nmi
+       int_hand     INT_AUX_PERF_COUNT, AUX_PERF_COUNT, \
+                    op_handle_perf_interrupt, handle_nmi
+       int_hand     INT_INTCTRL_3, INTCTRL_3, bad_intr
+#if CONFIG_KERNEL_PL == 2
+       dc_dispatch  INT_INTCTRL_2, INTCTRL_2
+       int_hand     INT_INTCTRL_1, INTCTRL_1, bad_intr
+#else
+       int_hand     INT_INTCTRL_2, INTCTRL_2, bad_intr
+       dc_dispatch  INT_INTCTRL_1, INTCTRL_1
+#endif
+       int_hand     INT_INTCTRL_0, INTCTRL_0, bad_intr
+       int_hand     INT_MESSAGE_RCV_DWNCL, MESSAGE_RCV_DWNCL, \
+                    hv_message_intr
+       int_hand     INT_DEV_INTR_DWNCL, DEV_INTR_DWNCL, bad_intr
+       int_hand     INT_I_ASID, I_ASID, bad_intr
+       int_hand     INT_D_ASID, D_ASID, bad_intr
+       int_hand     INT_DOUBLE_FAULT, DOUBLE_FAULT, do_trap
+
+       /* Synthetic interrupt delivered only by the simulator */
+       int_hand     INT_BREAKPOINT, BREAKPOINT, do_breakpoint
index e2ab82b7c7e7122fcc2c8d48cd1ac0f2f7fa61c3..f68df69f1f67bcc20ab6e90708014240887a7c50 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/kernel.h>
 #include <asm/opcode-tile.h>
 #include <asm/pgtable.h>
+#include <asm/homecache.h>
 
 #ifdef __tilegx__
 # define Elf_Rela Elf64_Rela
@@ -86,8 +87,13 @@ error:
 void module_free(struct module *mod, void *module_region)
 {
        vfree(module_region);
+
+       /* Globally flush the L1 icache. */
+       flush_remote(0, HV_FLUSH_EVICT_L1I, cpu_online_mask,
+                    0, 0, 0, NULL, NULL, 0);
+
        /*
-        * FIXME: If module_region == mod->init_region, trim exception
+        * FIXME: If module_region == mod->module_init, trim exception
         * table entries.
         */
 }
index 658752b2835e37fa7472f2ef52e93045d1674645..658f2ce426a44ef5fefab5852cfbe05dc796953b 100644 (file)
@@ -244,7 +244,7 @@ EXPORT_SYMBOL(dma_sync_single_range_for_device);
  * dma_alloc_noncoherent() returns non-cacheable memory, so there's no
  * need to do any flushing here.
  */
-void dma_cache_sync(void *vaddr, size_t size,
+void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
                    enum dma_data_direction direction)
 {
 }
index ea38f0c9ec7cc776f4bdeddfd7e8371e224166e4..6d4cb5d7a9fd0da47f0f78235c44072c310e57ba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
  *
  *   This program is free software; you can redistribute it and/or
  *   modify it under the terms of the GNU General Public License
@@ -59,6 +59,7 @@ int __write_once tile_plx_gen1;
 
 static struct pci_controller controllers[TILE_NUM_PCIE];
 static int num_controllers;
+static int pci_scan_flags[TILE_NUM_PCIE];
 
 static struct pci_ops tile_cfg_ops;
 
@@ -79,7 +80,7 @@ EXPORT_SYMBOL(pcibios_align_resource);
  * controller_id is the controller number, config type is 0 or 1 for
  * config0 or config1 operations.
  */
-static int __init tile_pcie_open(int controller_id, int config_type)
+static int __devinit tile_pcie_open(int controller_id, int config_type)
 {
        char filename[32];
        int fd;
@@ -95,7 +96,7 @@ static int __init tile_pcie_open(int controller_id, int config_type)
 /*
  * Get the IRQ numbers from the HV and set up the handlers for them.
  */
-static int __init tile_init_irqs(int controller_id,
+static int __devinit tile_init_irqs(int controller_id,
                                 struct pci_controller *controller)
 {
        char filename[32];
@@ -139,71 +140,74 @@ static int __init tile_init_irqs(int controller_id,
  *
  * Returns the number of controllers discovered.
  */
-int __init tile_pci_init(void)
+int __devinit tile_pci_init(void)
 {
        int i;
 
        pr_info("PCI: Searching for controllers...\n");
 
+       /* Re-init number of PCIe controllers to support hot-plug feature. */
+       num_controllers = 0;
+
        /* Do any configuration we need before using the PCIe */
 
        for (i = 0; i < TILE_NUM_PCIE; i++) {
-               int hv_cfg_fd0 = -1;
-               int hv_cfg_fd1 = -1;
-               int hv_mem_fd = -1;
-               char name[32];
-               struct pci_controller *controller;
-
                /*
-                * Open the fd to the HV.  If it fails then this
-                * device doesn't exist.
+                * To see whether we need a real config op based on
+                * the results of pcibios_init(), to support PCIe hot-plug.
                 */
-               hv_cfg_fd0 = tile_pcie_open(i, 0);
-               if (hv_cfg_fd0 < 0)
-                       continue;
-               hv_cfg_fd1 = tile_pcie_open(i, 1);
-               if (hv_cfg_fd1 < 0) {
-                       pr_err("PCI: Couldn't open config fd to HV "
-                           "for controller %d\n", i);
-                       goto err_cont;
-               }
-
-               sprintf(name, "pcie/%d/mem", i);
-               hv_mem_fd = hv_dev_open((HV_VirtAddr)name, 0);
-               if (hv_mem_fd < 0) {
-                       pr_err("PCI: Could not open mem fd to HV!\n");
-                       goto err_cont;
-               }
+               if (pci_scan_flags[i] == 0) {
+                       int hv_cfg_fd0 = -1;
+                       int hv_cfg_fd1 = -1;
+                       int hv_mem_fd = -1;
+                       char name[32];
+                       struct pci_controller *controller;
+
+                       /*
+                        * Open the fd to the HV.  If it fails then this
+                        * device doesn't exist.
+                        */
+                       hv_cfg_fd0 = tile_pcie_open(i, 0);
+                       if (hv_cfg_fd0 < 0)
+                               continue;
+                       hv_cfg_fd1 = tile_pcie_open(i, 1);
+                       if (hv_cfg_fd1 < 0) {
+                               pr_err("PCI: Couldn't open config fd to HV "
+                                   "for controller %d\n", i);
+                               goto err_cont;
+                       }
 
-               pr_info("PCI: Found PCI controller #%d\n", i);
+                       sprintf(name, "pcie/%d/mem", i);
+                       hv_mem_fd = hv_dev_open((HV_VirtAddr)name, 0);
+                       if (hv_mem_fd < 0) {
+                               pr_err("PCI: Could not open mem fd to HV!\n");
+                               goto err_cont;
+                       }
 
-               controller = &controllers[num_controllers];
+                       pr_info("PCI: Found PCI controller #%d\n", i);
 
-               if (tile_init_irqs(i, controller)) {
-                       pr_err("PCI: Could not initialize "
-                              "IRQs, aborting.\n");
-                       goto err_cont;
-               }
+                       controller = &controllers[i];
 
-               controller->index = num_controllers;
-               controller->hv_cfg_fd[0] = hv_cfg_fd0;
-               controller->hv_cfg_fd[1] = hv_cfg_fd1;
-               controller->hv_mem_fd = hv_mem_fd;
-               controller->first_busno = 0;
-               controller->last_busno = 0xff;
-               controller->ops = &tile_cfg_ops;
+                       controller->index = i;
+                       controller->hv_cfg_fd[0] = hv_cfg_fd0;
+                       controller->hv_cfg_fd[1] = hv_cfg_fd1;
+                       controller->hv_mem_fd = hv_mem_fd;
+                       controller->first_busno = 0;
+                       controller->last_busno = 0xff;
+                       controller->ops = &tile_cfg_ops;
 
-               num_controllers++;
-               continue;
+                       num_controllers++;
+                       continue;
 
 err_cont:
-               if (hv_cfg_fd0 >= 0)
-                       hv_dev_close(hv_cfg_fd0);
-               if (hv_cfg_fd1 >= 0)
-                       hv_dev_close(hv_cfg_fd1);
-               if (hv_mem_fd >= 0)
-                       hv_dev_close(hv_mem_fd);
-               continue;
+                       if (hv_cfg_fd0 >= 0)
+                               hv_dev_close(hv_cfg_fd0);
+                       if (hv_cfg_fd1 >= 0)
+                               hv_dev_close(hv_cfg_fd1);
+                       if (hv_mem_fd >= 0)
+                               hv_dev_close(hv_mem_fd);
+                       continue;
+               }
        }
 
        /*
@@ -232,7 +236,7 @@ static int tile_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 }
 
 
-static void __init fixup_read_and_payload_sizes(void)
+static void __devinit fixup_read_and_payload_sizes(void)
 {
        struct pci_dev *dev = NULL;
        int smallest_max_payload = 0x1; /* Tile maxes out at 256 bytes. */
@@ -282,7 +286,7 @@ static void __init fixup_read_and_payload_sizes(void)
  * The controllers have been set up by the time we get here, by a call to
  * tile_pci_init.
  */
-static int __init pcibios_init(void)
+int __devinit pcibios_init(void)
 {
        int i;
 
@@ -296,25 +300,36 @@ static int __init pcibios_init(void)
        mdelay(250);
 
        /* Scan all of the recorded PCI controllers.  */
-       for (i = 0; i < num_controllers; i++) {
-               struct pci_controller *controller = &controllers[i];
-               struct pci_bus *bus;
-
-               pr_info("PCI: initializing controller #%d\n", i);
-
+       for (i = 0; i < TILE_NUM_PCIE; i++) {
                /*
-                * This comes from the generic Linux PCI driver.
-                *
-                * It reads the PCI tree for this bus into the Linux
-                * data structures.
-                *
-                * This is inlined in linux/pci.h and calls into
-                * pci_scan_bus_parented() in probe.c.
+                * Do real pcibios init ops if the controller is initialized
+                * by tile_pci_init() successfully and not initialized by
+                * pcibios_init() yet to support PCIe hot-plug.
                 */
-               bus = pci_scan_bus(0, controller->ops, controller);
-               controller->root_bus = bus;
-               controller->last_busno = bus->subordinate;
+               if (pci_scan_flags[i] == 0 && controllers[i].ops != NULL) {
+                       struct pci_controller *controller = &controllers[i];
+                       struct pci_bus *bus;
 
+                       if (tile_init_irqs(i, controller)) {
+                               pr_err("PCI: Could not initialize IRQs\n");
+                               continue;
+                       }
+
+                       pr_info("PCI: initializing controller #%d\n", i);
+
+                       /*
+                        * This comes from the generic Linux PCI driver.
+                        *
+                        * It reads the PCI tree for this bus into the Linux
+                        * data structures.
+                        *
+                        * This is inlined in linux/pci.h and calls into
+                        * pci_scan_bus_parented() in probe.c.
+                        */
+                       bus = pci_scan_bus(0, controller->ops, controller);
+                       controller->root_bus = bus;
+                       controller->last_busno = bus->subordinate;
+               }
        }
 
        /* Do machine dependent PCI interrupt routing */
@@ -326,34 +341,45 @@ static int __init pcibios_init(void)
         * It allocates all of the resources (I/O memory, etc)
         * associated with the devices read in above.
         */
-
        pci_assign_unassigned_resources();
 
        /* Configure the max_read_size and max_payload_size values. */
        fixup_read_and_payload_sizes();
 
        /* Record the I/O resources in the PCI controller structure. */
-       for (i = 0; i < num_controllers; i++) {
-               struct pci_bus *root_bus = controllers[i].root_bus;
-               struct pci_bus *next_bus;
-               struct pci_dev *dev;
-
-               list_for_each_entry(dev, &root_bus->devices, bus_list) {
-                       /* Find the PCI host controller, ie. the 1st bridge. */
-                       if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
-                               (PCI_SLOT(dev->devfn) == 0)) {
-                               next_bus = dev->subordinate;
-                               controllers[i].mem_resources[0] =
-                                       *next_bus->resource[0];
-                               controllers[i].mem_resources[1] =
-                                        *next_bus->resource[1];
-                               controllers[i].mem_resources[2] =
-                                        *next_bus->resource[2];
-
-                               break;
+       for (i = 0; i < TILE_NUM_PCIE; i++) {
+               /*
+                * Do real pcibios init ops if the controller is initialized
+                * by tile_pci_init() successfully and not initialized by
+                * pcibios_init() yet to support PCIe hot-plug.
+                */
+               if (pci_scan_flags[i] == 0 && controllers[i].ops != NULL) {
+                       struct pci_bus *root_bus = controllers[i].root_bus;
+                       struct pci_bus *next_bus;
+                       struct pci_dev *dev;
+
+                       list_for_each_entry(dev, &root_bus->devices, bus_list) {
+                               /*
+                                * Find the PCI host controller, ie. the 1st
+                                * bridge.
+                                */
+                               if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
+                                       (PCI_SLOT(dev->devfn) == 0)) {
+                                       next_bus = dev->subordinate;
+                                       controllers[i].mem_resources[0] =
+                                               *next_bus->resource[0];
+                                       controllers[i].mem_resources[1] =
+                                                *next_bus->resource[1];
+                                       controllers[i].mem_resources[2] =
+                                                *next_bus->resource[2];
+
+                                       /* Setup flags. */
+                                       pci_scan_flags[i] = 1;
+
+                                       break;
+                               }
                        }
                }
-
        }
 
        return 0;
@@ -381,7 +407,7 @@ char __devinit *pcibios_setup(char *str)
 /*
  * This is called from the generic Linux layer.
  */
-void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+void __devinit pcibios_update_irq(struct pci_dev *dev, int irq)
 {
        pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
index 2e02c41ddf3bb54420e350b2890a7446da4cbd72..62d820833c68bc2ee34185f3ad3f4f6c080bff15 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/processor.h>
 #include <asm/sections.h>
 #include <asm/homecache.h>
+#include <asm/hardwall.h>
 #include <arch/chip.h>
 
 
@@ -88,3 +89,75 @@ const struct seq_operations cpuinfo_op = {
        .stop   = c_stop,
        .show   = show_cpuinfo,
 };
+
+/*
+ * Support /proc/tile directory
+ */
+
+static int __init proc_tile_init(void)
+{
+       struct proc_dir_entry *root = proc_mkdir("tile", NULL);
+       if (root == NULL)
+               return 0;
+
+       proc_tile_hardwall_init(root);
+
+       return 0;
+}
+
+arch_initcall(proc_tile_init);
+
+/*
+ * Support /proc/sys/tile directory
+ */
+
+#ifndef __tilegx__  /* FIXME: GX: no support for unaligned access yet */
+static ctl_table unaligned_subtable[] = {
+       {
+               .procname       = "enabled",
+               .data           = &unaligned_fixup,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec
+       },
+       {
+               .procname       = "printk",
+               .data           = &unaligned_printk,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec
+       },
+       {
+               .procname       = "count",
+               .data           = &unaligned_fixup_count,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec
+       },
+       {}
+};
+
+static ctl_table unaligned_table[] = {
+       {
+               .procname       = "unaligned_fixup",
+               .mode           = 0555,
+               .child          = unaligned_subtable
+       },
+       {}
+};
+#endif
+
+static struct ctl_path tile_path[] = {
+       { .procname = "tile" },
+       { }
+};
+
+static int __init proc_sys_tile_init(void)
+{
+#ifndef __tilegx__  /* FIXME: GX: no support for unaligned access yet */
+       register_sysctl_paths(tile_path, unaligned_table);
+#endif
+       return 0;
+}
+
+arch_initcall(proc_sys_tile_init);
index d0065103eb7bd48e98003e2d594c7c8b2572f0c4..9c45d8bbdf57a7d6b7e9b8eb99da20138e16116e 100644 (file)
 #include <linux/hardirq.h>
 #include <linux/syscalls.h>
 #include <linux/kernel.h>
+#include <linux/tracehook.h>
+#include <linux/signal.h>
 #include <asm/system.h>
 #include <asm/stack.h>
 #include <asm/homecache.h>
 #include <asm/syscalls.h>
+#include <asm/traps.h>
 #ifdef CONFIG_HARDWALL
 #include <asm/hardwall.h>
 #endif
@@ -546,6 +549,51 @@ struct task_struct *__sched _switch_to(struct task_struct *prev,
        return __switch_to(prev, next, next_current_ksp0(next));
 }
 
+/*
+ * This routine is called on return from interrupt if any of the
+ * TIF_WORK_MASK flags are set in thread_info->flags.  It is
+ * entered with interrupts disabled so we don't miss an event
+ * that modified the thread_info flags.  If any flag is set, we
+ * handle it and return, and the calling assembly code will
+ * re-disable interrupts, reload the thread flags, and call back
+ * if more flags need to be handled.
+ *
+ * We return whether we need to check the thread_info flags again
+ * or not.  Note that we don't clear TIF_SINGLESTEP here, so it's
+ * important that it be tested last, and then claim that we don't
+ * need to recheck the flags.
+ */
+int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
+{
+       if (thread_info_flags & _TIF_NEED_RESCHED) {
+               schedule();
+               return 1;
+       }
+#if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC()
+       if (thread_info_flags & _TIF_ASYNC_TLB) {
+               do_async_page_fault(regs);
+               return 1;
+       }
+#endif
+       if (thread_info_flags & _TIF_SIGPENDING) {
+               do_signal(regs);
+               return 1;
+       }
+       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
+               return 1;
+       }
+       if (thread_info_flags & _TIF_SINGLESTEP) {
+               if ((regs->ex1 & SPR_EX_CONTEXT_1_1__PL_MASK) == 0)
+                       single_step_once(regs);
+               return 0;
+       }
+       panic("work_pending: bad flags %#x\n", thread_info_flags);
+}
+
 /* Note there is an implicit fifth argument if (clone_flags & CLONE_SETTLS). */
 SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
                void __user *, parent_tidptr, void __user *, child_tidptr,
@@ -582,8 +630,8 @@ out:
 
 #ifdef CONFIG_COMPAT
 long compat_sys_execve(const char __user *path,
-                      const compat_uptr_t __user *argv,
-                      const compat_uptr_t __user *envp,
+                      compat_uptr_t __user *argv,
+                      compat_uptr_t __user *envp,
                       struct pt_regs *regs)
 {
        long error;
diff --git a/arch/tile/kernel/regs_64.S b/arch/tile/kernel/regs_64.S
new file mode 100644 (file)
index 0000000..f748c1e
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/linkage.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/asm-offsets.h>
+#include <arch/spr_def.h>
+#include <asm/processor.h>
+
+/*
+ * See <asm/system.h>; called with prev and next task_struct pointers.
+ * "prev" is returned in r0 for _switch_to and also for ret_from_fork.
+ *
+ * We want to save pc/sp in "prev", and get the new pc/sp from "next".
+ * We also need to save all the callee-saved registers on the stack.
+ *
+ * Intel enables/disables access to the hardware cycle counter in
+ * seccomp (secure computing) environments if necessary, based on
+ * has_secure_computing().  We might want to do this at some point,
+ * though it would require virtualizing the other SPRs under WORLD_ACCESS.
+ *
+ * Since we're saving to the stack, we omit sp from this list.
+ * And for parallels with other architectures, we save lr separately,
+ * in the thread_struct itself (as the "pc" field).
+ *
+ * This code also needs to be aligned with process.c copy_thread()
+ */
+
+#if CALLEE_SAVED_REGS_COUNT != 24
+# error Mismatch between <asm/system.h> and kernel/entry.S
+#endif
+#define FRAME_SIZE ((2 + CALLEE_SAVED_REGS_COUNT) * 8)
+
+#define SAVE_REG(r) { st r12, r; addi r12, r12, 8 }
+#define LOAD_REG(r) { ld r, r12; addi r12, r12, 8 }
+#define FOR_EACH_CALLEE_SAVED_REG(f)                                   \
+                                                       f(r30); f(r31); \
+       f(r32); f(r33); f(r34); f(r35); f(r36); f(r37); f(r38); f(r39); \
+       f(r40); f(r41); f(r42); f(r43); f(r44); f(r45); f(r46); f(r47); \
+       f(r48); f(r49); f(r50); f(r51); f(r52);
+
+STD_ENTRY_SECTION(__switch_to, .sched.text)
+       {
+         move r10, sp
+         st sp, lr
+       }
+       {
+         addli r11, sp, -FRAME_SIZE + 8
+         addli sp, sp, -FRAME_SIZE
+       }
+       {
+         st r11, r10
+         addli r4, r1, TASK_STRUCT_THREAD_KSP_OFFSET
+       }
+       {
+         ld r13, r4   /* Load new sp to a temp register early. */
+         addi r12, sp, 16
+       }
+       FOR_EACH_CALLEE_SAVED_REG(SAVE_REG)
+       addli r3, r0, TASK_STRUCT_THREAD_KSP_OFFSET
+       {
+         st r3, sp
+         addli r3, r0, TASK_STRUCT_THREAD_PC_OFFSET
+       }
+       {
+         st r3, lr
+         addli r4, r1, TASK_STRUCT_THREAD_PC_OFFSET
+       }
+       {
+         ld lr, r4
+         addi r12, r13, 16
+       }
+       {
+         /* Update sp and ksp0 simultaneously to avoid backtracer warnings. */
+         move sp, r13
+         mtspr SPR_SYSTEM_SAVE_K_0, r2
+       }
+       FOR_EACH_CALLEE_SAVED_REG(LOAD_REG)
+.L__switch_to_pc:
+       {
+         addli sp, sp, FRAME_SIZE
+         jrp lr   /* r0 is still valid here, so return it */
+       }
+       STD_ENDPROC(__switch_to)
+
+/* Return a suitable address for the backtracer for suspended threads */
+STD_ENTRY_SECTION(get_switch_to_pc, .sched.text)
+       lnk r0
+       {
+         addli r0, r0, .L__switch_to_pc - .
+         jrp lr
+       }
+       STD_ENDPROC(get_switch_to_pc)
+
+STD_ENTRY(get_pt_regs)
+       .irp reg, r0, r1, r2, r3, r4, r5, r6, r7, \
+                r8, r9, r10, r11, r12, r13, r14, r15, \
+                r16, r17, r18, r19, r20, r21, r22, r23, \
+                r24, r25, r26, r27, r28, r29, r30, r31, \
+                r32, r33, r34, r35, r36, r37, r38, r39, \
+                r40, r41, r42, r43, r44, r45, r46, r47, \
+                r48, r49, r50, r51, r52, tp, sp
+       {
+        st r0, \reg
+        addi r0, r0, 8
+       }
+       .endr
+       {
+        st r0, lr
+        addi r0, r0, PTREGS_OFFSET_PC - PTREGS_OFFSET_LR
+       }
+       lnk r1
+       {
+        st r0, r1
+        addi r0, r0, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC
+       }
+       mfspr r1, INTERRUPT_CRITICAL_SECTION
+       shli r1, r1, SPR_EX_CONTEXT_1_1__ICS_SHIFT
+       ori r1, r1, KERNEL_PL
+       {
+        st r0, r1
+        addi r0, r0, PTREGS_OFFSET_FAULTNUM - PTREGS_OFFSET_EX1
+       }
+       {
+        st r0, zero       /* clear faultnum */
+        addi r0, r0, PTREGS_OFFSET_ORIG_R0 - PTREGS_OFFSET_FAULTNUM
+       }
+       {
+        st r0, zero       /* clear orig_r0 */
+        addli r0, r0, -PTREGS_OFFSET_ORIG_R0    /* restore r0 to base */
+       }
+       jrp lr
+       STD_ENDPROC(get_pt_regs)
index 3696b18325665784156689aac1325e725a200b74..6cdc9ba55fe0443dd8906fd60056d1ad9e6e783f 100644 (file)
@@ -912,6 +912,8 @@ void __cpuinit setup_cpu(int boot)
 #endif
 }
 
+#ifdef CONFIG_BLK_DEV_INITRD
+
 static int __initdata set_initramfs_file;
 static char __initdata initramfs_file[128] = "initramfs.cpio.gz";
 
@@ -969,6 +971,10 @@ void __init free_initrd_mem(unsigned long begin, unsigned long end)
        free_bootmem(__pa(begin), end - begin);
 }
 
+#else
+static inline void load_hv_initrd(void) {}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
 static void __init validate_hv(void)
 {
        /*
index 1260321155f1d591b85131f44d9c72ad31122626..bedaf4e9f3a77ff57ee62b3ccc3bc70bb0e202c2 100644 (file)
@@ -39,7 +39,6 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-
 SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss,
                stack_t __user *, uoss, struct pt_regs *, regs)
 {
@@ -78,6 +77,13 @@ int restore_sigcontext(struct pt_regs *regs,
        return err;
 }
 
+void signal_fault(const char *type, struct pt_regs *regs,
+                 void __user *frame, int sig)
+{
+       trace_unhandled_signal(type, regs, (unsigned long)frame, SIGSEGV);
+       force_sigsegv(sig, current);
+}
+
 /* The assembly shim for this function arranges to ignore the return value. */
 SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
 {
@@ -105,7 +111,7 @@ SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
        return 0;
 
 badframe:
-       force_sig(SIGSEGV, current);
+       signal_fault("bad sigreturn frame", regs, frame, 0);
        return 0;
 }
 
@@ -231,7 +237,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        return 0;
 
 give_sigsegv:
-       force_sigsegv(sig, current);
+       signal_fault("bad setup frame", regs, frame, sig);
        return -EFAULT;
 }
 
@@ -245,7 +251,6 @@ static int handle_signal(unsigned long sig, siginfo_t *info,
 {
        int ret;
 
-
        /* Are we from a system call? */
        if (regs->faultnum == INT_SWINT_1) {
                /* If so, check system call restarting.. */
@@ -363,3 +368,118 @@ done:
        /* Avoid double syscall restart if there are nested signals. */
        regs->faultnum = INT_SWINT_1_SIGRETURN;
 }
+
+int show_unhandled_signals = 1;
+
+static int __init crashinfo(char *str)
+{
+       unsigned long val;
+       const char *word;
+
+       if (*str == '\0')
+               val = 2;
+       else if (*str != '=' || strict_strtoul(++str, 0, &val) != 0)
+               return 0;
+       show_unhandled_signals = val;
+       switch (show_unhandled_signals) {
+       case 0:
+               word = "No";
+               break;
+       case 1:
+               word = "One-line";
+               break;
+       default:
+               word = "Detailed";
+               break;
+       }
+       pr_info("%s crash reports will be generated on the console\n", word);
+       return 1;
+}
+__setup("crashinfo", crashinfo);
+
+static void dump_mem(void __user *address)
+{
+       void __user *addr;
+       enum { region_size = 256, bytes_per_line = 16 };
+       int i, j, k;
+       int found_readable_mem = 0;
+
+       pr_err("\n");
+       if (!access_ok(VERIFY_READ, address, 1)) {
+               pr_err("Not dumping at address 0x%lx (kernel address)\n",
+                      (unsigned long)address);
+               return;
+       }
+
+       addr = (void __user *)
+               (((unsigned long)address & -bytes_per_line) - region_size/2);
+       if (addr > address)
+               addr = NULL;
+       for (i = 0; i < region_size;
+            addr += bytes_per_line, i += bytes_per_line) {
+               unsigned char buf[bytes_per_line];
+               char line[100];
+               if (copy_from_user(buf, addr, bytes_per_line))
+                       continue;
+               if (!found_readable_mem) {
+                       pr_err("Dumping memory around address 0x%lx:\n",
+                              (unsigned long)address);
+                       found_readable_mem = 1;
+               }
+               j = sprintf(line, REGFMT":", (unsigned long)addr);
+               for (k = 0; k < bytes_per_line; ++k)
+                       j += sprintf(&line[j], " %02x", buf[k]);
+               pr_err("%s\n", line);
+       }
+       if (!found_readable_mem)
+               pr_err("No readable memory around address 0x%lx\n",
+                      (unsigned long)address);
+}
+
+void trace_unhandled_signal(const char *type, struct pt_regs *regs,
+                           unsigned long address, int sig)
+{
+       struct task_struct *tsk = current;
+
+       if (show_unhandled_signals == 0)
+               return;
+
+       /* If the signal is handled, don't show it here. */
+       if (!is_global_init(tsk)) {
+               void __user *handler =
+                       tsk->sighand->action[sig-1].sa.sa_handler;
+               if (handler != SIG_IGN && handler != SIG_DFL)
+                       return;
+       }
+
+       /* Rate-limit the one-line output, not the detailed output. */
+       if (show_unhandled_signals <= 1 && !printk_ratelimit())
+               return;
+
+       printk("%s%s[%d]: %s at %lx pc "REGFMT" signal %d",
+              task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
+              tsk->comm, task_pid_nr(tsk), type, address, regs->pc, sig);
+
+       print_vma_addr(KERN_CONT " in ", regs->pc);
+
+       printk(KERN_CONT "\n");
+
+       if (show_unhandled_signals > 1) {
+               switch (sig) {
+               case SIGILL:
+               case SIGFPE:
+               case SIGSEGV:
+               case SIGBUS:
+                       pr_err("User crash: signal %d,"
+                              " trap %ld, address 0x%lx\n",
+                              sig, regs->faultnum, address);
+                       show_regs(regs);
+                       dump_mem((void __user *)address);
+                       break;
+               default:
+                       pr_err("User crash: signal %d, trap %ld\n",
+                              sig, regs->faultnum);
+                       break;
+               }
+       }
+}
index 84a729e06ec44b448110ddf78cef5852ef87fa23..4032ca8e51b613b894bee171f1afa8468ffddb1d 100644 (file)
@@ -186,6 +186,8 @@ static tile_bundle_bits rewrite_load_store_unaligned(
                        .si_code = SEGV_MAPERR,
                        .si_addr = addr
                };
+               trace_unhandled_signal("segfault", regs,
+                                      (unsigned long)addr, SIGSEGV);
                force_sig_info(info.si_signo, &info, current);
                return (tile_bundle_bits) 0;
        }
@@ -196,6 +198,8 @@ static tile_bundle_bits rewrite_load_store_unaligned(
                        .si_code = BUS_ADRALN,
                        .si_addr = addr
                };
+               trace_unhandled_signal("unaligned trap", regs,
+                                      (unsigned long)addr, SIGBUS);
                force_sig_info(info.si_signo, &info, current);
                return (tile_bundle_bits) 0;
        }
@@ -318,6 +322,14 @@ void single_step_once(struct pt_regs *regs)
 "    .popsection\n"
        );
 
+       /*
+        * Enable interrupts here to allow touching userspace and the like.
+        * The callers expect this: do_trap() already has interrupts
+        * enabled, and do_work_pending() handles functions that enable
+        * interrupts internally.
+        */
+       local_irq_enable();
+
        if (state == NULL) {
                /* allocate a page of writable, executable memory */
                state = kmalloc(sizeof(struct single_step_state), GFP_KERNEL);
index dd81713a90dc5991a077fbfde30c3d65cb91489c..37ee4d037e0bae6788762e23e28fd3f518f38175 100644 (file)
@@ -36,7 +36,7 @@
 #define KBT_LOOP       3  /* Backtrace entered a loop */
 
 /* Is address on the specified kernel stack? */
-static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp)
+static int in_kernel_stack(struct KBacktraceIterator *kbt, unsigned long sp)
 {
        ulong kstack_base = (ulong) kbt->task->stack;
        if (kstack_base == 0)  /* corrupt task pointer; just follow stack... */
@@ -45,7 +45,7 @@ static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp)
 }
 
 /* Is address valid for reading? */
-static int valid_address(struct KBacktraceIterator *kbt, VirtualAddress address)
+static int valid_address(struct KBacktraceIterator *kbt, unsigned long address)
 {
        HV_PTE *l1_pgtable = kbt->pgtable;
        HV_PTE *l2_pgtable;
@@ -97,7 +97,7 @@ static int valid_address(struct KBacktraceIterator *kbt, VirtualAddress address)
 }
 
 /* Callback for backtracer; basically a glorified memcpy */
-static bool read_memory_func(void *result, VirtualAddress address,
+static bool read_memory_func(void *result, unsigned long address,
                             unsigned int size, void *vkbt)
 {
        int retval;
@@ -124,7 +124,7 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
 {
        const char *fault = NULL;  /* happy compiler */
        char fault_buf[64];
-       VirtualAddress sp = kbt->it.sp;
+       unsigned long sp = kbt->it.sp;
        struct pt_regs *p;
 
        if (!in_kernel_stack(kbt, sp))
@@ -163,7 +163,7 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
 }
 
 /* Is the pc pointing to a sigreturn trampoline? */
-static int is_sigreturn(VirtualAddress pc)
+static int is_sigreturn(unsigned long pc)
 {
        return (pc == VDSO_BASE);
 }
@@ -260,7 +260,7 @@ static void validate_stack(struct pt_regs *regs)
 void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
                             struct task_struct *t, struct pt_regs *regs)
 {
-       VirtualAddress pc, lr, sp, r52;
+       unsigned long pc, lr, sp, r52;
        int is_current;
 
        /*
@@ -331,7 +331,7 @@ EXPORT_SYMBOL(KBacktraceIterator_end);
 
 void KBacktraceIterator_next(struct KBacktraceIterator *kbt)
 {
-       VirtualAddress old_pc = kbt->it.pc, old_sp = kbt->it.sp;
+       unsigned long old_pc = kbt->it.pc, old_sp = kbt->it.sp;
        kbt->new_context = 0;
        if (!backtrace_next(&kbt->it) && !KBacktraceIterator_restart(kbt)) {
                kbt->end = KBT_DONE;
index e2187d24a9b41d8ad765f1a383347525dc728a5f..cb44ba7ccd2d1e61622a761c90259c3b257a9c1f 100644 (file)
@@ -56,13 +56,6 @@ ssize_t sys32_readahead(int fd, u32 offset_lo, u32 offset_hi, u32 count)
        return sys_readahead(fd, ((loff_t)offset_hi << 32) | offset_lo, count);
 }
 
-long sys32_fadvise64(int fd, u32 offset_lo, u32 offset_hi,
-                    u32 len, int advice)
-{
-       return sys_fadvise64_64(fd, ((loff_t)offset_hi << 32) | offset_lo,
-                               len, advice);
-}
-
 int sys32_fadvise64_64(int fd, u32 offset_lo, u32 offset_hi,
                       u32 len_lo, u32 len_hi, int advice)
 {
@@ -103,10 +96,8 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
 
 #ifndef __tilegx__
 /* See comments at the top of the file. */
-#define sys_fadvise64 sys32_fadvise64
 #define sys_fadvise64_64 sys32_fadvise64_64
 #define sys_readahead sys32_readahead
-#define sys_sync_file_range sys_sync_file_range2
 #endif
 
 /* Call the trampolines to manage pt_regs where necessary. */
diff --git a/arch/tile/kernel/sysfs.c b/arch/tile/kernel/sysfs.c
new file mode 100644 (file)
index 0000000..b671a86
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * /sys entry support.
+ */
+
+#include <linux/sysdev.h>
+#include <linux/cpu.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <hv/hypervisor.h>
+
+/* Return a string queried from the hypervisor, truncated to page size. */
+static ssize_t get_hv_confstr(char *page, int query)
+{
+       ssize_t n = hv_confstr(query, (unsigned long)page, PAGE_SIZE - 1);
+       n = n < 0 ? 0 : min(n, (ssize_t)PAGE_SIZE - 1) - 1;
+       if (n)
+               page[n++] = '\n';
+       page[n] = '\0';
+       return n;
+}
+
+static ssize_t chip_width_show(struct sysdev_class *dev,
+                              struct sysdev_class_attribute *attr,
+                              char *page)
+{
+       return sprintf(page, "%u\n", smp_width);
+}
+static SYSDEV_CLASS_ATTR(chip_width, 0444, chip_width_show, NULL);
+
+static ssize_t chip_height_show(struct sysdev_class *dev,
+                               struct sysdev_class_attribute *attr,
+                               char *page)
+{
+       return sprintf(page, "%u\n", smp_height);
+}
+static SYSDEV_CLASS_ATTR(chip_height, 0444, chip_height_show, NULL);
+
+static ssize_t chip_serial_show(struct sysdev_class *dev,
+                               struct sysdev_class_attribute *attr,
+                               char *page)
+{
+       return get_hv_confstr(page, HV_CONFSTR_CHIP_SERIAL_NUM);
+}
+static SYSDEV_CLASS_ATTR(chip_serial, 0444, chip_serial_show, NULL);
+
+static ssize_t chip_revision_show(struct sysdev_class *dev,
+                                 struct sysdev_class_attribute *attr,
+                                 char *page)
+{
+       return get_hv_confstr(page, HV_CONFSTR_CHIP_REV);
+}
+static SYSDEV_CLASS_ATTR(chip_revision, 0444, chip_revision_show, NULL);
+
+
+static ssize_t type_show(struct sysdev_class *dev,
+                           struct sysdev_class_attribute *attr,
+                           char *page)
+{
+       return sprintf(page, "tilera\n");
+}
+static SYSDEV_CLASS_ATTR(type, 0444, type_show, NULL);
+
+#define HV_CONF_ATTR(name, conf)                                       \
+       static ssize_t name ## _show(struct sysdev_class *dev,          \
+                                    struct sysdev_class_attribute *attr, \
+                                    char *page)                        \
+       {                                                               \
+               return get_hv_confstr(page, conf);                      \
+       }                                                               \
+       static SYSDEV_CLASS_ATTR(name, 0444, name ## _show, NULL);
+
+HV_CONF_ATTR(version,          HV_CONFSTR_HV_SW_VER)
+HV_CONF_ATTR(config_version,   HV_CONFSTR_HV_CONFIG_VER)
+
+HV_CONF_ATTR(board_part,       HV_CONFSTR_BOARD_PART_NUM)
+HV_CONF_ATTR(board_serial,     HV_CONFSTR_BOARD_SERIAL_NUM)
+HV_CONF_ATTR(board_revision,   HV_CONFSTR_BOARD_REV)
+HV_CONF_ATTR(board_description,        HV_CONFSTR_BOARD_DESC)
+HV_CONF_ATTR(mezz_part,                HV_CONFSTR_MEZZ_PART_NUM)
+HV_CONF_ATTR(mezz_serial,      HV_CONFSTR_MEZZ_SERIAL_NUM)
+HV_CONF_ATTR(mezz_revision,    HV_CONFSTR_MEZZ_REV)
+HV_CONF_ATTR(mezz_description, HV_CONFSTR_MEZZ_DESC)
+HV_CONF_ATTR(switch_control,   HV_CONFSTR_SWITCH_CONTROL)
+
+static struct attribute *board_attrs[] = {
+       &attr_board_part.attr,
+       &attr_board_serial.attr,
+       &attr_board_revision.attr,
+       &attr_board_description.attr,
+       &attr_mezz_part.attr,
+       &attr_mezz_serial.attr,
+       &attr_mezz_revision.attr,
+       &attr_mezz_description.attr,
+       &attr_switch_control.attr,
+       NULL
+};
+
+static struct attribute_group board_attr_group = {
+       .name   = "board",
+       .attrs  = board_attrs,
+};
+
+
+static struct bin_attribute hvconfig_bin;
+
+static ssize_t
+hvconfig_bin_read(struct file *filp, struct kobject *kobj,
+                 struct bin_attribute *bin_attr,
+                 char *buf, loff_t off, size_t count)
+{
+       static size_t size;
+
+       /* Lazily learn the true size (minus the trailing NUL). */
+       if (size == 0)
+               size = hv_confstr(HV_CONFSTR_HV_CONFIG, 0, 0) - 1;
+
+       /* Check and adjust input parameters. */
+       if (off > size)
+               return -EINVAL;
+       if (count > size - off)
+               count = size - off;
+
+       if (count) {
+               /* Get a copy of the hvc and copy out the relevant portion. */
+               char *hvc;
+
+               size = off + count;
+               hvc = kmalloc(size, GFP_KERNEL);
+               if (hvc == NULL)
+                       return -ENOMEM;
+               hv_confstr(HV_CONFSTR_HV_CONFIG, (unsigned long)hvc, size);
+               memcpy(buf, hvc + off, count);
+               kfree(hvc);
+       }
+
+       return count;
+}
+
+static int __init create_sysfs_entries(void)
+{
+       struct sysdev_class *cls = &cpu_sysdev_class;
+       int err = 0;
+
+#define create_cpu_attr(name)                                          \
+       if (!err)                                                       \
+               err = sysfs_create_file(&cls->kset.kobj, &attr_##name.attr);
+       create_cpu_attr(chip_width);
+       create_cpu_attr(chip_height);
+       create_cpu_attr(chip_serial);
+       create_cpu_attr(chip_revision);
+
+#define create_hv_attr(name)                                           \
+       if (!err)                                                       \
+               err = sysfs_create_file(hypervisor_kobj, &attr_##name.attr);
+       create_hv_attr(type);
+       create_hv_attr(version);
+       create_hv_attr(config_version);
+
+       if (!err)
+               err = sysfs_create_group(hypervisor_kobj, &board_attr_group);
+
+       if (!err) {
+               sysfs_bin_attr_init(&hvconfig_bin);
+               hvconfig_bin.attr.name = "hvconfig";
+               hvconfig_bin.attr.mode = S_IRUGO;
+               hvconfig_bin.read = hvconfig_bin_read;
+               hvconfig_bin.size = PAGE_SIZE;
+               err = sysfs_create_bin_file(hypervisor_kobj, &hvconfig_bin);
+       }
+
+       return err;
+}
+subsys_initcall(create_sysfs_entries);
index 69af0e150f785b974fbcbbbc0aa532f3685c5de6..7e31a12857885c13affbcbd53ad916b2006bf15c 100644 (file)
@@ -2413,12 +2413,13 @@ const struct tile_operand tile_operands[43] =
 
 
 
-/* Given a set of bundle bits and the lookup FSM for a specific pipe,
- * returns which instruction the bundle contains in that pipe.
+/* Given a set of bundle bits and a specific pipe, returns which
+ * instruction the bundle contains in that pipe.
  */
-static const struct tile_opcode *
-find_opcode(tile_bundle_bits bits, const unsigned short *table)
+const struct tile_opcode *
+find_opcode(tile_bundle_bits bits, tile_pipeline pipe)
 {
+  const unsigned short *table = tile_bundle_decoder_fsms[pipe];
   int index = 0;
 
   while (1)
@@ -2465,7 +2466,7 @@ parse_insn_tile(tile_bundle_bits bits,
     int i;
 
     d = &decoded[num_instructions++];
-    opc = find_opcode (bits, tile_bundle_decoder_fsms[pipe]);
+    opc = find_opcode (bits, (tile_pipeline)pipe);
     d->opcode = opc;
 
     /* Decode each operand, sign extending, etc. as appropriate. */
diff --git a/arch/tile/kernel/tile-desc_64.c b/arch/tile/kernel/tile-desc_64.c
new file mode 100644 (file)
index 0000000..d57007b
--- /dev/null
@@ -0,0 +1,2200 @@
+/* This define is BFD_RELOC_##x for real bfd, or -1 for everyone else. */
+#define BFD_RELOC(x) -1
+
+/* Special registers. */
+#define TREG_LR 55
+#define TREG_SN 56
+#define TREG_ZERO 63
+
+/* FIXME: Rename this. */
+#include <asm/opcode-tile_64.h>
+
+#include <linux/stddef.h>
+
+const struct tilegx_opcode tilegx_opcodes[334] =
+{
+ { "bpt", TILEGX_OPC_BPT, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "info", TILEGX_OPC_INFO, 0xf, 1, TREG_ZERO, 1,
+    { { 0 }, { 1 }, { 2 }, { 3 }, { 0, } },
+  },
+  { "infol", TILEGX_OPC_INFOL, 0x3, 1, TREG_ZERO, 1,
+    { { 4 }, { 5 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "move", TILEGX_OPC_MOVE, 0xf, 2, TREG_ZERO, 1,
+    { { 6, 7 }, { 8, 9 }, { 10, 11 }, { 12, 13 }, { 0, } },
+  },
+  { "movei", TILEGX_OPC_MOVEI, 0xf, 2, TREG_ZERO, 1,
+    { { 6, 0 }, { 8, 1 }, { 10, 2 }, { 12, 3 }, { 0, } },
+  },
+  { "moveli", TILEGX_OPC_MOVELI, 0x3, 2, TREG_ZERO, 1,
+    { { 6, 4 }, { 8, 5 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "prefetch", TILEGX_OPC_PREFETCH, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+  },
+  { "prefetch_add_l1", TILEGX_OPC_PREFETCH_ADD_L1, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "prefetch_add_l1_fault", TILEGX_OPC_PREFETCH_ADD_L1_FAULT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "prefetch_add_l2", TILEGX_OPC_PREFETCH_ADD_L2, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "prefetch_add_l2_fault", TILEGX_OPC_PREFETCH_ADD_L2_FAULT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "prefetch_add_l3", TILEGX_OPC_PREFETCH_ADD_L3, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "prefetch_add_l3_fault", TILEGX_OPC_PREFETCH_ADD_L3_FAULT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "prefetch_l1", TILEGX_OPC_PREFETCH_L1, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+  },
+  { "prefetch_l1_fault", TILEGX_OPC_PREFETCH_L1_FAULT, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+  },
+  { "prefetch_l2", TILEGX_OPC_PREFETCH_L2, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+  },
+  { "prefetch_l2_fault", TILEGX_OPC_PREFETCH_L2_FAULT, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+  },
+  { "prefetch_l3", TILEGX_OPC_PREFETCH_L3, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+  },
+  { "prefetch_l3_fault", TILEGX_OPC_PREFETCH_L3_FAULT, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+  },
+  { "raise", TILEGX_OPC_RAISE, 0x2, 0, TREG_ZERO, 1,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "add", TILEGX_OPC_ADD, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "addi", TILEGX_OPC_ADDI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+  },
+  { "addli", TILEGX_OPC_ADDLI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 4 }, { 8, 9, 5 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "addx", TILEGX_OPC_ADDX, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "addxi", TILEGX_OPC_ADDXI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+  },
+  { "addxli", TILEGX_OPC_ADDXLI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 4 }, { 8, 9, 5 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "addxsc", TILEGX_OPC_ADDXSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "and", TILEGX_OPC_AND, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "andi", TILEGX_OPC_ANDI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+  },
+  { "beqz", TILEGX_OPC_BEQZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "beqzt", TILEGX_OPC_BEQZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bfexts", TILEGX_OPC_BFEXTS, 0x1, 4, TREG_ZERO, 1,
+    { { 6, 7, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bfextu", TILEGX_OPC_BFEXTU, 0x1, 4, TREG_ZERO, 1,
+    { { 6, 7, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bfins", TILEGX_OPC_BFINS, 0x1, 4, TREG_ZERO, 1,
+    { { 23, 7, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bgez", TILEGX_OPC_BGEZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bgezt", TILEGX_OPC_BGEZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bgtz", TILEGX_OPC_BGTZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bgtzt", TILEGX_OPC_BGTZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "blbc", TILEGX_OPC_BLBC, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "blbct", TILEGX_OPC_BLBCT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "blbs", TILEGX_OPC_BLBS, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "blbst", TILEGX_OPC_BLBST, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "blez", TILEGX_OPC_BLEZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "blezt", TILEGX_OPC_BLEZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bltz", TILEGX_OPC_BLTZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bltzt", TILEGX_OPC_BLTZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bnez", TILEGX_OPC_BNEZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bnezt", TILEGX_OPC_BNEZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "clz", TILEGX_OPC_CLZ, 0x5, 2, TREG_ZERO, 1,
+    { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+  },
+  { "cmoveqz", TILEGX_OPC_CMOVEQZ, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "cmovnez", TILEGX_OPC_CMOVNEZ, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "cmpeq", TILEGX_OPC_CMPEQ, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "cmpeqi", TILEGX_OPC_CMPEQI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+  },
+  { "cmpexch", TILEGX_OPC_CMPEXCH, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmpexch4", TILEGX_OPC_CMPEXCH4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmples", TILEGX_OPC_CMPLES, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "cmpleu", TILEGX_OPC_CMPLEU, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "cmplts", TILEGX_OPC_CMPLTS, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "cmpltsi", TILEGX_OPC_CMPLTSI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+  },
+  { "cmpltu", TILEGX_OPC_CMPLTU, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "cmpltui", TILEGX_OPC_CMPLTUI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmpne", TILEGX_OPC_CMPNE, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "cmul", TILEGX_OPC_CMUL, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmula", TILEGX_OPC_CMULA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmulaf", TILEGX_OPC_CMULAF, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmulf", TILEGX_OPC_CMULF, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmulfr", TILEGX_OPC_CMULFR, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmulh", TILEGX_OPC_CMULH, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmulhr", TILEGX_OPC_CMULHR, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "crc32_32", TILEGX_OPC_CRC32_32, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "crc32_8", TILEGX_OPC_CRC32_8, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ctz", TILEGX_OPC_CTZ, 0x5, 2, TREG_ZERO, 1,
+    { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+  },
+  { "dblalign", TILEGX_OPC_DBLALIGN, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "dblalign2", TILEGX_OPC_DBLALIGN2, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "dblalign4", TILEGX_OPC_DBLALIGN4, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "dblalign6", TILEGX_OPC_DBLALIGN6, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "drain", TILEGX_OPC_DRAIN, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "dtlbpr", TILEGX_OPC_DTLBPR, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "exch", TILEGX_OPC_EXCH, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "exch4", TILEGX_OPC_EXCH4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fdouble_add_flags", TILEGX_OPC_FDOUBLE_ADD_FLAGS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fdouble_addsub", TILEGX_OPC_FDOUBLE_ADDSUB, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fdouble_mul_flags", TILEGX_OPC_FDOUBLE_MUL_FLAGS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fdouble_pack1", TILEGX_OPC_FDOUBLE_PACK1, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fdouble_pack2", TILEGX_OPC_FDOUBLE_PACK2, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fdouble_sub_flags", TILEGX_OPC_FDOUBLE_SUB_FLAGS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fdouble_unpack_max", TILEGX_OPC_FDOUBLE_UNPACK_MAX, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fdouble_unpack_min", TILEGX_OPC_FDOUBLE_UNPACK_MIN, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fetchadd", TILEGX_OPC_FETCHADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fetchadd4", TILEGX_OPC_FETCHADD4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fetchaddgez", TILEGX_OPC_FETCHADDGEZ, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fetchaddgez4", TILEGX_OPC_FETCHADDGEZ4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fetchand", TILEGX_OPC_FETCHAND, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fetchand4", TILEGX_OPC_FETCHAND4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fetchor", TILEGX_OPC_FETCHOR, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fetchor4", TILEGX_OPC_FETCHOR4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "finv", TILEGX_OPC_FINV, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "flush", TILEGX_OPC_FLUSH, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "flushwb", TILEGX_OPC_FLUSHWB, 0x2, 0, TREG_ZERO, 1,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fnop", TILEGX_OPC_FNOP, 0xf, 0, TREG_ZERO, 1,
+    { {  }, {  }, {  }, {  }, { 0, } },
+  },
+  { "fsingle_add1", TILEGX_OPC_FSINGLE_ADD1, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fsingle_addsub2", TILEGX_OPC_FSINGLE_ADDSUB2, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fsingle_mul1", TILEGX_OPC_FSINGLE_MUL1, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fsingle_mul2", TILEGX_OPC_FSINGLE_MUL2, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fsingle_pack1", TILEGX_OPC_FSINGLE_PACK1, 0x5, 2, TREG_ZERO, 1,
+    { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+  },
+  { "fsingle_pack2", TILEGX_OPC_FSINGLE_PACK2, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fsingle_sub1", TILEGX_OPC_FSINGLE_SUB1, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "icoh", TILEGX_OPC_ICOH, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ill", TILEGX_OPC_ILL, 0xa, 0, TREG_ZERO, 1,
+    { { 0, }, {  }, { 0, }, {  }, { 0, } },
+  },
+  { "inv", TILEGX_OPC_INV, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "iret", TILEGX_OPC_IRET, 0x2, 0, TREG_ZERO, 1,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "j", TILEGX_OPC_J, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 25 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "jal", TILEGX_OPC_JAL, 0x2, 1, TREG_LR, 1,
+    { { 0, }, { 25 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "jalr", TILEGX_OPC_JALR, 0xa, 1, TREG_LR, 1,
+    { { 0, }, { 9 }, { 0, }, { 13 }, { 0, } },
+  },
+  { "jalrp", TILEGX_OPC_JALRP, 0xa, 1, TREG_LR, 1,
+    { { 0, }, { 9 }, { 0, }, { 13 }, { 0, } },
+  },
+  { "jr", TILEGX_OPC_JR, 0xa, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 13 }, { 0, } },
+  },
+  { "jrp", TILEGX_OPC_JRP, 0xa, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 13 }, { 0, } },
+  },
+  { "ld", TILEGX_OPC_LD, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+  },
+  { "ld1s", TILEGX_OPC_LD1S, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+  },
+  { "ld1s_add", TILEGX_OPC_LD1S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ld1u", TILEGX_OPC_LD1U, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+  },
+  { "ld1u_add", TILEGX_OPC_LD1U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ld2s", TILEGX_OPC_LD2S, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+  },
+  { "ld2s_add", TILEGX_OPC_LD2S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ld2u", TILEGX_OPC_LD2U, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+  },
+  { "ld2u_add", TILEGX_OPC_LD2U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ld4s", TILEGX_OPC_LD4S, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+  },
+  { "ld4s_add", TILEGX_OPC_LD4S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ld4u", TILEGX_OPC_LD4U, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+  },
+  { "ld4u_add", TILEGX_OPC_LD4U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ld_add", TILEGX_OPC_LD_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldna", TILEGX_OPC_LDNA, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldna_add", TILEGX_OPC_LDNA_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt", TILEGX_OPC_LDNT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt1s", TILEGX_OPC_LDNT1S, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt1s_add", TILEGX_OPC_LDNT1S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt1u", TILEGX_OPC_LDNT1U, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt1u_add", TILEGX_OPC_LDNT1U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt2s", TILEGX_OPC_LDNT2S, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt2s_add", TILEGX_OPC_LDNT2S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt2u", TILEGX_OPC_LDNT2U, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt2u_add", TILEGX_OPC_LDNT2U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt4s", TILEGX_OPC_LDNT4S, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt4s_add", TILEGX_OPC_LDNT4S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt4u", TILEGX_OPC_LDNT4U, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt4u_add", TILEGX_OPC_LDNT4U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt_add", TILEGX_OPC_LDNT_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "lnk", TILEGX_OPC_LNK, 0xa, 1, TREG_ZERO, 1,
+    { { 0, }, { 8 }, { 0, }, { 12 }, { 0, } },
+  },
+  { "mf", TILEGX_OPC_MF, 0x2, 0, TREG_ZERO, 1,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mfspr", TILEGX_OPC_MFSPR, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 27 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mm", TILEGX_OPC_MM, 0x1, 4, TREG_ZERO, 1,
+    { { 23, 7, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mnz", TILEGX_OPC_MNZ, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "mtspr", TILEGX_OPC_MTSPR, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 28, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mul_hs_hs", TILEGX_OPC_MUL_HS_HS, 0x5, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mul_hs_hu", TILEGX_OPC_MUL_HS_HU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mul_hs_ls", TILEGX_OPC_MUL_HS_LS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mul_hs_lu", TILEGX_OPC_MUL_HS_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mul_hu_hu", TILEGX_OPC_MUL_HU_HU, 0x5, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mul_hu_ls", TILEGX_OPC_MUL_HU_LS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mul_hu_lu", TILEGX_OPC_MUL_HU_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mul_ls_ls", TILEGX_OPC_MUL_LS_LS, 0x5, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mul_ls_lu", TILEGX_OPC_MUL_LS_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mul_lu_lu", TILEGX_OPC_MUL_LU_LU, 0x5, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mula_hs_hs", TILEGX_OPC_MULA_HS_HS, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mula_hs_hu", TILEGX_OPC_MULA_HS_HU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mula_hs_ls", TILEGX_OPC_MULA_HS_LS, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mula_hs_lu", TILEGX_OPC_MULA_HS_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mula_hu_hu", TILEGX_OPC_MULA_HU_HU, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mula_hu_ls", TILEGX_OPC_MULA_HU_LS, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mula_hu_lu", TILEGX_OPC_MULA_HU_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mula_ls_ls", TILEGX_OPC_MULA_LS_LS, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mula_ls_lu", TILEGX_OPC_MULA_LS_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mula_lu_lu", TILEGX_OPC_MULA_LU_LU, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mulax", TILEGX_OPC_MULAX, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mulx", TILEGX_OPC_MULX, 0x5, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mz", TILEGX_OPC_MZ, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "nap", TILEGX_OPC_NAP, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "nop", TILEGX_OPC_NOP, 0xf, 0, TREG_ZERO, 1,
+    { {  }, {  }, {  }, {  }, { 0, } },
+  },
+  { "nor", TILEGX_OPC_NOR, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "or", TILEGX_OPC_OR, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "ori", TILEGX_OPC_ORI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "pcnt", TILEGX_OPC_PCNT, 0x5, 2, TREG_ZERO, 1,
+    { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+  },
+  { "revbits", TILEGX_OPC_REVBITS, 0x5, 2, TREG_ZERO, 1,
+    { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+  },
+  { "revbytes", TILEGX_OPC_REVBYTES, 0x5, 2, TREG_ZERO, 1,
+    { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+  },
+  { "rotl", TILEGX_OPC_ROTL, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "rotli", TILEGX_OPC_ROTLI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } },
+  },
+  { "shl", TILEGX_OPC_SHL, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shl16insli", TILEGX_OPC_SHL16INSLI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 4 }, { 8, 9, 5 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "shl1add", TILEGX_OPC_SHL1ADD, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shl1addx", TILEGX_OPC_SHL1ADDX, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shl2add", TILEGX_OPC_SHL2ADD, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shl2addx", TILEGX_OPC_SHL2ADDX, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shl3add", TILEGX_OPC_SHL3ADD, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shl3addx", TILEGX_OPC_SHL3ADDX, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shli", TILEGX_OPC_SHLI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } },
+  },
+  { "shlx", TILEGX_OPC_SHLX, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "shlxi", TILEGX_OPC_SHLXI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "shrs", TILEGX_OPC_SHRS, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shrsi", TILEGX_OPC_SHRSI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } },
+  },
+  { "shru", TILEGX_OPC_SHRU, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shrui", TILEGX_OPC_SHRUI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } },
+  },
+  { "shrux", TILEGX_OPC_SHRUX, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "shruxi", TILEGX_OPC_SHRUXI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "shufflebytes", TILEGX_OPC_SHUFFLEBYTES, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "st", TILEGX_OPC_ST, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 14, 33 } },
+  },
+  { "st1", TILEGX_OPC_ST1, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 14, 33 } },
+  },
+  { "st1_add", TILEGX_OPC_ST1_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "st2", TILEGX_OPC_ST2, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 14, 33 } },
+  },
+  { "st2_add", TILEGX_OPC_ST2_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "st4", TILEGX_OPC_ST4, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 14, 33 } },
+  },
+  { "st4_add", TILEGX_OPC_ST4_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "st_add", TILEGX_OPC_ST_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "stnt", TILEGX_OPC_STNT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "stnt1", TILEGX_OPC_STNT1, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "stnt1_add", TILEGX_OPC_STNT1_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "stnt2", TILEGX_OPC_STNT2, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "stnt2_add", TILEGX_OPC_STNT2_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "stnt4", TILEGX_OPC_STNT4, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "stnt4_add", TILEGX_OPC_STNT4_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "stnt_add", TILEGX_OPC_STNT_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "sub", TILEGX_OPC_SUB, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "subx", TILEGX_OPC_SUBX, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "subxsc", TILEGX_OPC_SUBXSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "swint0", TILEGX_OPC_SWINT0, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "swint1", TILEGX_OPC_SWINT1, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "swint2", TILEGX_OPC_SWINT2, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "swint3", TILEGX_OPC_SWINT3, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "tblidxb0", TILEGX_OPC_TBLIDXB0, 0x5, 2, TREG_ZERO, 1,
+    { { 23, 7 }, { 0, }, { 24, 11 }, { 0, }, { 0, } },
+  },
+  { "tblidxb1", TILEGX_OPC_TBLIDXB1, 0x5, 2, TREG_ZERO, 1,
+    { { 23, 7 }, { 0, }, { 24, 11 }, { 0, }, { 0, } },
+  },
+  { "tblidxb2", TILEGX_OPC_TBLIDXB2, 0x5, 2, TREG_ZERO, 1,
+    { { 23, 7 }, { 0, }, { 24, 11 }, { 0, }, { 0, } },
+  },
+  { "tblidxb3", TILEGX_OPC_TBLIDXB3, 0x5, 2, TREG_ZERO, 1,
+    { { 23, 7 }, { 0, }, { 24, 11 }, { 0, }, { 0, } },
+  },
+  { "v1add", TILEGX_OPC_V1ADD, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1addi", TILEGX_OPC_V1ADDI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1adduc", TILEGX_OPC_V1ADDUC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1adiffu", TILEGX_OPC_V1ADIFFU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1avgu", TILEGX_OPC_V1AVGU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmpeq", TILEGX_OPC_V1CMPEQ, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmpeqi", TILEGX_OPC_V1CMPEQI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmples", TILEGX_OPC_V1CMPLES, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmpleu", TILEGX_OPC_V1CMPLEU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmplts", TILEGX_OPC_V1CMPLTS, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmpltsi", TILEGX_OPC_V1CMPLTSI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmpltu", TILEGX_OPC_V1CMPLTU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmpltui", TILEGX_OPC_V1CMPLTUI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmpne", TILEGX_OPC_V1CMPNE, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1ddotpu", TILEGX_OPC_V1DDOTPU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1ddotpua", TILEGX_OPC_V1DDOTPUA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1ddotpus", TILEGX_OPC_V1DDOTPUS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1ddotpusa", TILEGX_OPC_V1DDOTPUSA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1dotp", TILEGX_OPC_V1DOTP, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1dotpa", TILEGX_OPC_V1DOTPA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1dotpu", TILEGX_OPC_V1DOTPU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1dotpua", TILEGX_OPC_V1DOTPUA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1dotpus", TILEGX_OPC_V1DOTPUS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1dotpusa", TILEGX_OPC_V1DOTPUSA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1int_h", TILEGX_OPC_V1INT_H, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1int_l", TILEGX_OPC_V1INT_L, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1maxu", TILEGX_OPC_V1MAXU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1maxui", TILEGX_OPC_V1MAXUI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1minu", TILEGX_OPC_V1MINU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1minui", TILEGX_OPC_V1MINUI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1mnz", TILEGX_OPC_V1MNZ, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1multu", TILEGX_OPC_V1MULTU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1mulu", TILEGX_OPC_V1MULU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1mulus", TILEGX_OPC_V1MULUS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1mz", TILEGX_OPC_V1MZ, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1sadau", TILEGX_OPC_V1SADAU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1sadu", TILEGX_OPC_V1SADU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1shl", TILEGX_OPC_V1SHL, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1shli", TILEGX_OPC_V1SHLI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1shrs", TILEGX_OPC_V1SHRS, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1shrsi", TILEGX_OPC_V1SHRSI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1shru", TILEGX_OPC_V1SHRU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1shrui", TILEGX_OPC_V1SHRUI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1sub", TILEGX_OPC_V1SUB, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1subuc", TILEGX_OPC_V1SUBUC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2add", TILEGX_OPC_V2ADD, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2addi", TILEGX_OPC_V2ADDI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2addsc", TILEGX_OPC_V2ADDSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2adiffs", TILEGX_OPC_V2ADIFFS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2avgs", TILEGX_OPC_V2AVGS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmpeq", TILEGX_OPC_V2CMPEQ, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmpeqi", TILEGX_OPC_V2CMPEQI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmples", TILEGX_OPC_V2CMPLES, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmpleu", TILEGX_OPC_V2CMPLEU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmplts", TILEGX_OPC_V2CMPLTS, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmpltsi", TILEGX_OPC_V2CMPLTSI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmpltu", TILEGX_OPC_V2CMPLTU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmpltui", TILEGX_OPC_V2CMPLTUI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmpne", TILEGX_OPC_V2CMPNE, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2dotp", TILEGX_OPC_V2DOTP, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2dotpa", TILEGX_OPC_V2DOTPA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2int_h", TILEGX_OPC_V2INT_H, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2int_l", TILEGX_OPC_V2INT_L, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2maxs", TILEGX_OPC_V2MAXS, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2maxsi", TILEGX_OPC_V2MAXSI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2mins", TILEGX_OPC_V2MINS, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2minsi", TILEGX_OPC_V2MINSI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2mnz", TILEGX_OPC_V2MNZ, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2mulfsc", TILEGX_OPC_V2MULFSC, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2muls", TILEGX_OPC_V2MULS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2mults", TILEGX_OPC_V2MULTS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2mz", TILEGX_OPC_V2MZ, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2packh", TILEGX_OPC_V2PACKH, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2packl", TILEGX_OPC_V2PACKL, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2packuc", TILEGX_OPC_V2PACKUC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2sadas", TILEGX_OPC_V2SADAS, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2sadau", TILEGX_OPC_V2SADAU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2sads", TILEGX_OPC_V2SADS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2sadu", TILEGX_OPC_V2SADU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2shl", TILEGX_OPC_V2SHL, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2shli", TILEGX_OPC_V2SHLI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2shlsc", TILEGX_OPC_V2SHLSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2shrs", TILEGX_OPC_V2SHRS, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2shrsi", TILEGX_OPC_V2SHRSI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2shru", TILEGX_OPC_V2SHRU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2shrui", TILEGX_OPC_V2SHRUI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2sub", TILEGX_OPC_V2SUB, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2subsc", TILEGX_OPC_V2SUBSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4add", TILEGX_OPC_V4ADD, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4addsc", TILEGX_OPC_V4ADDSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4int_h", TILEGX_OPC_V4INT_H, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4int_l", TILEGX_OPC_V4INT_L, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4packsc", TILEGX_OPC_V4PACKSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4shl", TILEGX_OPC_V4SHL, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4shlsc", TILEGX_OPC_V4SHLSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4shrs", TILEGX_OPC_V4SHRS, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4shru", TILEGX_OPC_V4SHRU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4sub", TILEGX_OPC_V4SUB, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4subsc", TILEGX_OPC_V4SUBSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "wh64", TILEGX_OPC_WH64, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "xor", TILEGX_OPC_XOR, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "xori", TILEGX_OPC_XORI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { NULL, TILEGX_OPC_NONE, 0, 0, TREG_ZERO, 0, { { 0, } },
+  }
+};
+#define BITFIELD(start, size) ((start) | (((1 << (size)) - 1) << 6))
+#define CHILD(array_index) (TILEGX_OPC_NONE + (array_index))
+
+static const unsigned short decode_X0_fsm[936] =
+{
+  BITFIELD(22, 9) /* index 0 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_BFEXTS,
+  TILEGX_OPC_BFEXTS, TILEGX_OPC_BFEXTS, TILEGX_OPC_BFEXTS, TILEGX_OPC_BFEXTU,
+  TILEGX_OPC_BFEXTU, TILEGX_OPC_BFEXTU, TILEGX_OPC_BFEXTU, TILEGX_OPC_BFINS,
+  TILEGX_OPC_BFINS, TILEGX_OPC_BFINS, TILEGX_OPC_BFINS, TILEGX_OPC_MM,
+  TILEGX_OPC_MM, TILEGX_OPC_MM, TILEGX_OPC_MM, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, CHILD(528), CHILD(578),
+  CHILD(583), CHILD(588), CHILD(593), CHILD(598), TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, CHILD(603), CHILD(620), CHILD(637), CHILD(654), CHILD(671),
+  CHILD(703), CHILD(797), CHILD(814), CHILD(831), CHILD(848), CHILD(865),
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, CHILD(889), TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  BITFIELD(6, 2) /* index 513 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(518),
+  BITFIELD(8, 2) /* index 518 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(523),
+  BITFIELD(10, 2) /* index 523 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_MOVELI,
+  BITFIELD(20, 2) /* index 528 */,
+  TILEGX_OPC_NONE, CHILD(533), TILEGX_OPC_ADDXI, CHILD(548),
+  BITFIELD(6, 2) /* index 533 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(538),
+  BITFIELD(8, 2) /* index 538 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(543),
+  BITFIELD(10, 2) /* index 543 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI,
+  BITFIELD(0, 2) /* index 548 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(553),
+  BITFIELD(2, 2) /* index 553 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(558),
+  BITFIELD(4, 2) /* index 558 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(563),
+  BITFIELD(6, 2) /* index 563 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(568),
+  BITFIELD(8, 2) /* index 568 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(573),
+  BITFIELD(10, 2) /* index 573 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO,
+  BITFIELD(20, 2) /* index 578 */,
+  TILEGX_OPC_CMPEQI, TILEGX_OPC_CMPLTSI, TILEGX_OPC_CMPLTUI, TILEGX_OPC_ORI,
+  BITFIELD(20, 2) /* index 583 */,
+  TILEGX_OPC_V1ADDI, TILEGX_OPC_V1CMPEQI, TILEGX_OPC_V1CMPLTSI,
+  TILEGX_OPC_V1CMPLTUI,
+  BITFIELD(20, 2) /* index 588 */,
+  TILEGX_OPC_V1MAXUI, TILEGX_OPC_V1MINUI, TILEGX_OPC_V2ADDI,
+  TILEGX_OPC_V2CMPEQI,
+  BITFIELD(20, 2) /* index 593 */,
+  TILEGX_OPC_V2CMPLTSI, TILEGX_OPC_V2CMPLTUI, TILEGX_OPC_V2MAXSI,
+  TILEGX_OPC_V2MINSI,
+  BITFIELD(20, 2) /* index 598 */,
+  TILEGX_OPC_XORI, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(18, 4) /* index 603 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_ADDXSC, TILEGX_OPC_ADDX, TILEGX_OPC_ADD,
+  TILEGX_OPC_AND, TILEGX_OPC_CMOVEQZ, TILEGX_OPC_CMOVNEZ, TILEGX_OPC_CMPEQ,
+  TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU,
+  TILEGX_OPC_CMPNE, TILEGX_OPC_CMULAF, TILEGX_OPC_CMULA, TILEGX_OPC_CMULFR,
+  BITFIELD(18, 4) /* index 620 */,
+  TILEGX_OPC_CMULF, TILEGX_OPC_CMULHR, TILEGX_OPC_CMULH, TILEGX_OPC_CMUL,
+  TILEGX_OPC_CRC32_32, TILEGX_OPC_CRC32_8, TILEGX_OPC_DBLALIGN2,
+  TILEGX_OPC_DBLALIGN4, TILEGX_OPC_DBLALIGN6, TILEGX_OPC_DBLALIGN,
+  TILEGX_OPC_FDOUBLE_ADDSUB, TILEGX_OPC_FDOUBLE_ADD_FLAGS,
+  TILEGX_OPC_FDOUBLE_MUL_FLAGS, TILEGX_OPC_FDOUBLE_PACK1,
+  TILEGX_OPC_FDOUBLE_PACK2, TILEGX_OPC_FDOUBLE_SUB_FLAGS,
+  BITFIELD(18, 4) /* index 637 */,
+  TILEGX_OPC_FDOUBLE_UNPACK_MAX, TILEGX_OPC_FDOUBLE_UNPACK_MIN,
+  TILEGX_OPC_FSINGLE_ADD1, TILEGX_OPC_FSINGLE_ADDSUB2,
+  TILEGX_OPC_FSINGLE_MUL1, TILEGX_OPC_FSINGLE_MUL2, TILEGX_OPC_FSINGLE_PACK2,
+  TILEGX_OPC_FSINGLE_SUB1, TILEGX_OPC_MNZ, TILEGX_OPC_MULAX,
+  TILEGX_OPC_MULA_HS_HS, TILEGX_OPC_MULA_HS_HU, TILEGX_OPC_MULA_HS_LS,
+  TILEGX_OPC_MULA_HS_LU, TILEGX_OPC_MULA_HU_HU, TILEGX_OPC_MULA_HU_LS,
+  BITFIELD(18, 4) /* index 654 */,
+  TILEGX_OPC_MULA_HU_LU, TILEGX_OPC_MULA_LS_LS, TILEGX_OPC_MULA_LS_LU,
+  TILEGX_OPC_MULA_LU_LU, TILEGX_OPC_MULX, TILEGX_OPC_MUL_HS_HS,
+  TILEGX_OPC_MUL_HS_HU, TILEGX_OPC_MUL_HS_LS, TILEGX_OPC_MUL_HS_LU,
+  TILEGX_OPC_MUL_HU_HU, TILEGX_OPC_MUL_HU_LS, TILEGX_OPC_MUL_HU_LU,
+  TILEGX_OPC_MUL_LS_LS, TILEGX_OPC_MUL_LS_LU, TILEGX_OPC_MUL_LU_LU,
+  TILEGX_OPC_MZ,
+  BITFIELD(18, 4) /* index 671 */,
+  TILEGX_OPC_NOR, CHILD(688), TILEGX_OPC_ROTL, TILEGX_OPC_SHL1ADDX,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADDX, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL3ADDX, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHLX, TILEGX_OPC_SHL,
+  TILEGX_OPC_SHRS, TILEGX_OPC_SHRUX, TILEGX_OPC_SHRU, TILEGX_OPC_SHUFFLEBYTES,
+  TILEGX_OPC_SUBXSC,
+  BITFIELD(12, 2) /* index 688 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(693),
+  BITFIELD(14, 2) /* index 693 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(698),
+  BITFIELD(16, 2) /* index 698 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE,
+  BITFIELD(18, 4) /* index 703 */,
+  TILEGX_OPC_SUBX, TILEGX_OPC_SUB, CHILD(720), TILEGX_OPC_V1ADDUC,
+  TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADIFFU, TILEGX_OPC_V1AVGU,
+  TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLEU,
+  TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPNE,
+  TILEGX_OPC_V1DDOTPUSA, TILEGX_OPC_V1DDOTPUS, TILEGX_OPC_V1DOTPA,
+  BITFIELD(12, 4) /* index 720 */,
+  TILEGX_OPC_NONE, CHILD(737), CHILD(742), CHILD(747), CHILD(752), CHILD(757),
+  CHILD(762), CHILD(767), CHILD(772), CHILD(777), CHILD(782), CHILD(787),
+  CHILD(792), TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 737 */,
+  TILEGX_OPC_CLZ, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 742 */,
+  TILEGX_OPC_CTZ, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 747 */,
+  TILEGX_OPC_FNOP, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 752 */,
+  TILEGX_OPC_FSINGLE_PACK1, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 757 */,
+  TILEGX_OPC_NOP, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 762 */,
+  TILEGX_OPC_PCNT, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 767 */,
+  TILEGX_OPC_REVBITS, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 772 */,
+  TILEGX_OPC_REVBYTES, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 777 */,
+  TILEGX_OPC_TBLIDXB0, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 782 */,
+  TILEGX_OPC_TBLIDXB1, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 787 */,
+  TILEGX_OPC_TBLIDXB2, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 792 */,
+  TILEGX_OPC_TBLIDXB3, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(18, 4) /* index 797 */,
+  TILEGX_OPC_V1DOTPUSA, TILEGX_OPC_V1DOTPUS, TILEGX_OPC_V1DOTP,
+  TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_L, TILEGX_OPC_V1MAXU,
+  TILEGX_OPC_V1MINU, TILEGX_OPC_V1MNZ, TILEGX_OPC_V1MULTU, TILEGX_OPC_V1MULUS,
+  TILEGX_OPC_V1MULU, TILEGX_OPC_V1MZ, TILEGX_OPC_V1SADAU, TILEGX_OPC_V1SADU,
+  TILEGX_OPC_V1SHL, TILEGX_OPC_V1SHRS,
+  BITFIELD(18, 4) /* index 814 */,
+  TILEGX_OPC_V1SHRU, TILEGX_OPC_V1SUBUC, TILEGX_OPC_V1SUB, TILEGX_OPC_V2ADDSC,
+  TILEGX_OPC_V2ADD, TILEGX_OPC_V2ADIFFS, TILEGX_OPC_V2AVGS,
+  TILEGX_OPC_V2CMPEQ, TILEGX_OPC_V2CMPLES, TILEGX_OPC_V2CMPLEU,
+  TILEGX_OPC_V2CMPLTS, TILEGX_OPC_V2CMPLTU, TILEGX_OPC_V2CMPNE,
+  TILEGX_OPC_V2DOTPA, TILEGX_OPC_V2DOTP, TILEGX_OPC_V2INT_H,
+  BITFIELD(18, 4) /* index 831 */,
+  TILEGX_OPC_V2INT_L, TILEGX_OPC_V2MAXS, TILEGX_OPC_V2MINS, TILEGX_OPC_V2MNZ,
+  TILEGX_OPC_V2MULFSC, TILEGX_OPC_V2MULS, TILEGX_OPC_V2MULTS, TILEGX_OPC_V2MZ,
+  TILEGX_OPC_V2PACKH, TILEGX_OPC_V2PACKL, TILEGX_OPC_V2PACKUC,
+  TILEGX_OPC_V2SADAS, TILEGX_OPC_V2SADAU, TILEGX_OPC_V2SADS,
+  TILEGX_OPC_V2SADU, TILEGX_OPC_V2SHLSC,
+  BITFIELD(18, 4) /* index 848 */,
+  TILEGX_OPC_V2SHL, TILEGX_OPC_V2SHRS, TILEGX_OPC_V2SHRU, TILEGX_OPC_V2SUBSC,
+  TILEGX_OPC_V2SUB, TILEGX_OPC_V4ADDSC, TILEGX_OPC_V4ADD, TILEGX_OPC_V4INT_H,
+  TILEGX_OPC_V4INT_L, TILEGX_OPC_V4PACKSC, TILEGX_OPC_V4SHLSC,
+  TILEGX_OPC_V4SHL, TILEGX_OPC_V4SHRS, TILEGX_OPC_V4SHRU, TILEGX_OPC_V4SUBSC,
+  TILEGX_OPC_V4SUB,
+  BITFIELD(18, 3) /* index 865 */,
+  CHILD(874), CHILD(877), CHILD(880), CHILD(883), CHILD(886), TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(21, 1) /* index 874 */,
+  TILEGX_OPC_XOR, TILEGX_OPC_NONE,
+  BITFIELD(21, 1) /* index 877 */,
+  TILEGX_OPC_V1DDOTPUA, TILEGX_OPC_NONE,
+  BITFIELD(21, 1) /* index 880 */,
+  TILEGX_OPC_V1DDOTPU, TILEGX_OPC_NONE,
+  BITFIELD(21, 1) /* index 883 */,
+  TILEGX_OPC_V1DOTPUA, TILEGX_OPC_NONE,
+  BITFIELD(21, 1) /* index 886 */,
+  TILEGX_OPC_V1DOTPU, TILEGX_OPC_NONE,
+  BITFIELD(18, 4) /* index 889 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHLXI,
+  TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI, TILEGX_OPC_SHRUXI, TILEGX_OPC_V1SHLI,
+  TILEGX_OPC_V1SHRSI, TILEGX_OPC_V1SHRUI, TILEGX_OPC_V2SHLI,
+  TILEGX_OPC_V2SHRSI, TILEGX_OPC_V2SHRUI, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE,
+  BITFIELD(0, 2) /* index 906 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(911),
+  BITFIELD(2, 2) /* index 911 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(916),
+  BITFIELD(4, 2) /* index 916 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(921),
+  BITFIELD(6, 2) /* index 921 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(926),
+  BITFIELD(8, 2) /* index 926 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(931),
+  BITFIELD(10, 2) /* index 931 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  TILEGX_OPC_INFOL,
+};
+
+static const unsigned short decode_X1_fsm[1206] =
+{
+  BITFIELD(53, 9) /* index 0 */,
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_BEQZT,
+  TILEGX_OPC_BEQZT, TILEGX_OPC_BEQZ, TILEGX_OPC_BEQZ, TILEGX_OPC_BGEZT,
+  TILEGX_OPC_BGEZT, TILEGX_OPC_BGEZ, TILEGX_OPC_BGEZ, TILEGX_OPC_BGTZT,
+  TILEGX_OPC_BGTZT, TILEGX_OPC_BGTZ, TILEGX_OPC_BGTZ, TILEGX_OPC_BLBCT,
+  TILEGX_OPC_BLBCT, TILEGX_OPC_BLBC, TILEGX_OPC_BLBC, TILEGX_OPC_BLBST,
+  TILEGX_OPC_BLBST, TILEGX_OPC_BLBS, TILEGX_OPC_BLBS, TILEGX_OPC_BLEZT,
+  TILEGX_OPC_BLEZT, TILEGX_OPC_BLEZ, TILEGX_OPC_BLEZ, TILEGX_OPC_BLTZT,
+  TILEGX_OPC_BLTZT, TILEGX_OPC_BLTZ, TILEGX_OPC_BLTZ, TILEGX_OPC_BNEZT,
+  TILEGX_OPC_BNEZT, TILEGX_OPC_BNEZ, TILEGX_OPC_BNEZ, CHILD(528), CHILD(578),
+  CHILD(598), CHILD(663), CHILD(683), CHILD(688), CHILD(693), CHILD(698),
+  CHILD(703), CHILD(708), CHILD(713), CHILD(718), TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  CHILD(723), CHILD(740), CHILD(772), CHILD(789), CHILD(1108), CHILD(1125),
+  CHILD(1142), TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, CHILD(1159), TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176),
+  BITFIELD(37, 2) /* index 513 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(518),
+  BITFIELD(39, 2) /* index 518 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(523),
+  BITFIELD(41, 2) /* index 523 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_MOVELI,
+  BITFIELD(51, 2) /* index 528 */,
+  TILEGX_OPC_NONE, CHILD(533), TILEGX_OPC_ADDXI, CHILD(548),
+  BITFIELD(37, 2) /* index 533 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(538),
+  BITFIELD(39, 2) /* index 538 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(543),
+  BITFIELD(41, 2) /* index 543 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI,
+  BITFIELD(31, 2) /* index 548 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(553),
+  BITFIELD(33, 2) /* index 553 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(558),
+  BITFIELD(35, 2) /* index 558 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(563),
+  BITFIELD(37, 2) /* index 563 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(568),
+  BITFIELD(39, 2) /* index 568 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(573),
+  BITFIELD(41, 2) /* index 573 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO,
+  BITFIELD(51, 2) /* index 578 */,
+  TILEGX_OPC_CMPEQI, TILEGX_OPC_CMPLTSI, TILEGX_OPC_CMPLTUI, CHILD(583),
+  BITFIELD(31, 2) /* index 583 */,
+  TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, CHILD(588),
+  BITFIELD(33, 2) /* index 588 */,
+  TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, CHILD(593),
+  BITFIELD(35, 2) /* index 593 */,
+  TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD,
+  TILEGX_OPC_PREFETCH_ADD_L1_FAULT,
+  BITFIELD(51, 2) /* index 598 */,
+  CHILD(603), CHILD(618), CHILD(633), CHILD(648),
+  BITFIELD(31, 2) /* index 603 */,
+  TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, CHILD(608),
+  BITFIELD(33, 2) /* index 608 */,
+  TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, CHILD(613),
+  BITFIELD(35, 2) /* index 613 */,
+  TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD,
+  TILEGX_OPC_PREFETCH_ADD_L1,
+  BITFIELD(31, 2) /* index 618 */,
+  TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, CHILD(623),
+  BITFIELD(33, 2) /* index 623 */,
+  TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, CHILD(628),
+  BITFIELD(35, 2) /* index 628 */,
+  TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD,
+  TILEGX_OPC_PREFETCH_ADD_L2_FAULT,
+  BITFIELD(31, 2) /* index 633 */,
+  TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, CHILD(638),
+  BITFIELD(33, 2) /* index 638 */,
+  TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, CHILD(643),
+  BITFIELD(35, 2) /* index 643 */,
+  TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD,
+  TILEGX_OPC_PREFETCH_ADD_L2,
+  BITFIELD(31, 2) /* index 648 */,
+  TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, CHILD(653),
+  BITFIELD(33, 2) /* index 653 */,
+  TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, CHILD(658),
+  BITFIELD(35, 2) /* index 658 */,
+  TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD,
+  TILEGX_OPC_PREFETCH_ADD_L3_FAULT,
+  BITFIELD(51, 2) /* index 663 */,
+  CHILD(668), TILEGX_OPC_LDNT1S_ADD, TILEGX_OPC_LDNT1U_ADD,
+  TILEGX_OPC_LDNT2S_ADD,
+  BITFIELD(31, 2) /* index 668 */,
+  TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, CHILD(673),
+  BITFIELD(33, 2) /* index 673 */,
+  TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, CHILD(678),
+  BITFIELD(35, 2) /* index 678 */,
+  TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD,
+  TILEGX_OPC_PREFETCH_ADD_L3,
+  BITFIELD(51, 2) /* index 683 */,
+  TILEGX_OPC_LDNT2U_ADD, TILEGX_OPC_LDNT4S_ADD, TILEGX_OPC_LDNT4U_ADD,
+  TILEGX_OPC_LDNT_ADD,
+  BITFIELD(51, 2) /* index 688 */,
+  TILEGX_OPC_LD_ADD, TILEGX_OPC_LDNA_ADD, TILEGX_OPC_MFSPR, TILEGX_OPC_MTSPR,
+  BITFIELD(51, 2) /* index 693 */,
+  TILEGX_OPC_ORI, TILEGX_OPC_ST1_ADD, TILEGX_OPC_ST2_ADD, TILEGX_OPC_ST4_ADD,
+  BITFIELD(51, 2) /* index 698 */,
+  TILEGX_OPC_STNT1_ADD, TILEGX_OPC_STNT2_ADD, TILEGX_OPC_STNT4_ADD,
+  TILEGX_OPC_STNT_ADD,
+  BITFIELD(51, 2) /* index 703 */,
+  TILEGX_OPC_ST_ADD, TILEGX_OPC_V1ADDI, TILEGX_OPC_V1CMPEQI,
+  TILEGX_OPC_V1CMPLTSI,
+  BITFIELD(51, 2) /* index 708 */,
+  TILEGX_OPC_V1CMPLTUI, TILEGX_OPC_V1MAXUI, TILEGX_OPC_V1MINUI,
+  TILEGX_OPC_V2ADDI,
+  BITFIELD(51, 2) /* index 713 */,
+  TILEGX_OPC_V2CMPEQI, TILEGX_OPC_V2CMPLTSI, TILEGX_OPC_V2CMPLTUI,
+  TILEGX_OPC_V2MAXSI,
+  BITFIELD(51, 2) /* index 718 */,
+  TILEGX_OPC_V2MINSI, TILEGX_OPC_XORI, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(49, 4) /* index 723 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_ADDXSC, TILEGX_OPC_ADDX, TILEGX_OPC_ADD,
+  TILEGX_OPC_AND, TILEGX_OPC_CMPEQ, TILEGX_OPC_CMPEXCH4, TILEGX_OPC_CMPEXCH,
+  TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU,
+  TILEGX_OPC_CMPNE, TILEGX_OPC_DBLALIGN2, TILEGX_OPC_DBLALIGN4,
+  TILEGX_OPC_DBLALIGN6,
+  BITFIELD(49, 4) /* index 740 */,
+  TILEGX_OPC_EXCH4, TILEGX_OPC_EXCH, TILEGX_OPC_FETCHADD4,
+  TILEGX_OPC_FETCHADDGEZ4, TILEGX_OPC_FETCHADDGEZ, TILEGX_OPC_FETCHADD,
+  TILEGX_OPC_FETCHAND4, TILEGX_OPC_FETCHAND, TILEGX_OPC_FETCHOR4,
+  TILEGX_OPC_FETCHOR, TILEGX_OPC_MNZ, TILEGX_OPC_MZ, TILEGX_OPC_NOR,
+  CHILD(757), TILEGX_OPC_ROTL, TILEGX_OPC_SHL1ADDX,
+  BITFIELD(43, 2) /* index 757 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(762),
+  BITFIELD(45, 2) /* index 762 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(767),
+  BITFIELD(47, 2) /* index 767 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE,
+  BITFIELD(49, 4) /* index 772 */,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADDX, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL3ADDX, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHLX, TILEGX_OPC_SHL,
+  TILEGX_OPC_SHRS, TILEGX_OPC_SHRUX, TILEGX_OPC_SHRU, TILEGX_OPC_ST1,
+  TILEGX_OPC_ST2, TILEGX_OPC_ST4, TILEGX_OPC_STNT1, TILEGX_OPC_STNT2,
+  TILEGX_OPC_STNT4,
+  BITFIELD(46, 7) /* index 789 */,
+  TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT,
+  TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT,
+  TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST,
+  TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_SUBXSC,
+  TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC,
+  TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBX,
+  TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUBX,
+  TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUB,
+  TILEGX_OPC_SUB, TILEGX_OPC_SUB, TILEGX_OPC_SUB, TILEGX_OPC_SUB,
+  TILEGX_OPC_SUB, TILEGX_OPC_SUB, TILEGX_OPC_SUB, CHILD(918), CHILD(927),
+  CHILD(1006), CHILD(1090), CHILD(1099), TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC,
+  TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC,
+  TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD,
+  TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD,
+  TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD, TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ,
+  TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ,
+  TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ,
+  TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES,
+  TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES,
+  TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLEU,
+  TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU,
+  TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU,
+  TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS,
+  TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS,
+  TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS,
+  TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU,
+  TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU,
+  TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPNE,
+  TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE,
+  TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE,
+  TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H,
+  TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H,
+  TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H,
+  TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L,
+  TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L,
+  TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L,
+  BITFIELD(43, 3) /* index 918 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_DRAIN, TILEGX_OPC_DTLBPR, TILEGX_OPC_FINV,
+  TILEGX_OPC_FLUSHWB, TILEGX_OPC_FLUSH, TILEGX_OPC_FNOP, TILEGX_OPC_ICOH,
+  BITFIELD(43, 3) /* index 927 */,
+  CHILD(936), TILEGX_OPC_INV, TILEGX_OPC_IRET, TILEGX_OPC_JALRP,
+  TILEGX_OPC_JALR, TILEGX_OPC_JRP, TILEGX_OPC_JR, CHILD(991),
+  BITFIELD(31, 2) /* index 936 */,
+  CHILD(941), CHILD(966), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(33, 2) /* index 941 */,
+  TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_ILL, CHILD(946),
+  BITFIELD(35, 2) /* index 946 */,
+  TILEGX_OPC_ILL, CHILD(951), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(37, 2) /* index 951 */,
+  TILEGX_OPC_ILL, CHILD(956), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(39, 2) /* index 956 */,
+  TILEGX_OPC_ILL, CHILD(961), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(41, 2) /* index 961 */,
+  TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_BPT, TILEGX_OPC_ILL,
+  BITFIELD(33, 2) /* index 966 */,
+  TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_ILL, CHILD(971),
+  BITFIELD(35, 2) /* index 971 */,
+  TILEGX_OPC_ILL, CHILD(976), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(37, 2) /* index 976 */,
+  TILEGX_OPC_ILL, CHILD(981), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(39, 2) /* index 981 */,
+  TILEGX_OPC_ILL, CHILD(986), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(41, 2) /* index 986 */,
+  TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_RAISE, TILEGX_OPC_ILL,
+  BITFIELD(31, 2) /* index 991 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, CHILD(996),
+  BITFIELD(33, 2) /* index 996 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, CHILD(1001),
+  BITFIELD(35, 2) /* index 1001 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S,
+  TILEGX_OPC_PREFETCH_L1_FAULT,
+  BITFIELD(43, 3) /* index 1006 */,
+  CHILD(1015), CHILD(1030), CHILD(1045), CHILD(1060), CHILD(1075),
+  TILEGX_OPC_LDNA, TILEGX_OPC_LDNT1S, TILEGX_OPC_LDNT1U,
+  BITFIELD(31, 2) /* index 1015 */,
+  TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, CHILD(1020),
+  BITFIELD(33, 2) /* index 1020 */,
+  TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, CHILD(1025),
+  BITFIELD(35, 2) /* index 1025 */,
+  TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_PREFETCH,
+  BITFIELD(31, 2) /* index 1030 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, CHILD(1035),
+  BITFIELD(33, 2) /* index 1035 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, CHILD(1040),
+  BITFIELD(35, 2) /* index 1040 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S,
+  TILEGX_OPC_PREFETCH_L2_FAULT,
+  BITFIELD(31, 2) /* index 1045 */,
+  TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, CHILD(1050),
+  BITFIELD(33, 2) /* index 1050 */,
+  TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, CHILD(1055),
+  BITFIELD(35, 2) /* index 1055 */,
+  TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_PREFETCH_L2,
+  BITFIELD(31, 2) /* index 1060 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(1065),
+  BITFIELD(33, 2) /* index 1065 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(1070),
+  BITFIELD(35, 2) /* index 1070 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S,
+  TILEGX_OPC_PREFETCH_L3_FAULT,
+  BITFIELD(31, 2) /* index 1075 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(1080),
+  BITFIELD(33, 2) /* index 1080 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(1085),
+  BITFIELD(35, 2) /* index 1085 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_PREFETCH_L3,
+  BITFIELD(43, 3) /* index 1090 */,
+  TILEGX_OPC_LDNT2S, TILEGX_OPC_LDNT2U, TILEGX_OPC_LDNT4S, TILEGX_OPC_LDNT4U,
+  TILEGX_OPC_LDNT, TILEGX_OPC_LD, TILEGX_OPC_LNK, TILEGX_OPC_MF,
+  BITFIELD(43, 3) /* index 1099 */,
+  TILEGX_OPC_NAP, TILEGX_OPC_NOP, TILEGX_OPC_SWINT0, TILEGX_OPC_SWINT1,
+  TILEGX_OPC_SWINT2, TILEGX_OPC_SWINT3, TILEGX_OPC_WH64, TILEGX_OPC_NONE,
+  BITFIELD(49, 4) /* index 1108 */,
+  TILEGX_OPC_V1MAXU, TILEGX_OPC_V1MINU, TILEGX_OPC_V1MNZ, TILEGX_OPC_V1MZ,
+  TILEGX_OPC_V1SHL, TILEGX_OPC_V1SHRS, TILEGX_OPC_V1SHRU, TILEGX_OPC_V1SUBUC,
+  TILEGX_OPC_V1SUB, TILEGX_OPC_V2ADDSC, TILEGX_OPC_V2ADD, TILEGX_OPC_V2CMPEQ,
+  TILEGX_OPC_V2CMPLES, TILEGX_OPC_V2CMPLEU, TILEGX_OPC_V2CMPLTS,
+  TILEGX_OPC_V2CMPLTU,
+  BITFIELD(49, 4) /* index 1125 */,
+  TILEGX_OPC_V2CMPNE, TILEGX_OPC_V2INT_H, TILEGX_OPC_V2INT_L,
+  TILEGX_OPC_V2MAXS, TILEGX_OPC_V2MINS, TILEGX_OPC_V2MNZ, TILEGX_OPC_V2MZ,
+  TILEGX_OPC_V2PACKH, TILEGX_OPC_V2PACKL, TILEGX_OPC_V2PACKUC,
+  TILEGX_OPC_V2SHLSC, TILEGX_OPC_V2SHL, TILEGX_OPC_V2SHRS, TILEGX_OPC_V2SHRU,
+  TILEGX_OPC_V2SUBSC, TILEGX_OPC_V2SUB,
+  BITFIELD(49, 4) /* index 1142 */,
+  TILEGX_OPC_V4ADDSC, TILEGX_OPC_V4ADD, TILEGX_OPC_V4INT_H,
+  TILEGX_OPC_V4INT_L, TILEGX_OPC_V4PACKSC, TILEGX_OPC_V4SHLSC,
+  TILEGX_OPC_V4SHL, TILEGX_OPC_V4SHRS, TILEGX_OPC_V4SHRU, TILEGX_OPC_V4SUBSC,
+  TILEGX_OPC_V4SUB, TILEGX_OPC_XOR, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(49, 4) /* index 1159 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHLXI,
+  TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI, TILEGX_OPC_SHRUXI, TILEGX_OPC_V1SHLI,
+  TILEGX_OPC_V1SHRSI, TILEGX_OPC_V1SHRUI, TILEGX_OPC_V2SHLI,
+  TILEGX_OPC_V2SHRSI, TILEGX_OPC_V2SHRUI, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE,
+  BITFIELD(31, 2) /* index 1176 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(1181),
+  BITFIELD(33, 2) /* index 1181 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(1186),
+  BITFIELD(35, 2) /* index 1186 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(1191),
+  BITFIELD(37, 2) /* index 1191 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(1196),
+  BITFIELD(39, 2) /* index 1196 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(1201),
+  BITFIELD(41, 2) /* index 1201 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  TILEGX_OPC_INFOL,
+};
+
+static const unsigned short decode_Y0_fsm[178] =
+{
+  BITFIELD(27, 4) /* index 0 */,
+  CHILD(17), TILEGX_OPC_ADDXI, CHILD(32), TILEGX_OPC_CMPEQI,
+  TILEGX_OPC_CMPLTSI, CHILD(62), CHILD(67), CHILD(118), CHILD(123),
+  CHILD(128), CHILD(133), CHILD(153), CHILD(158), CHILD(163), CHILD(168),
+  CHILD(173),
+  BITFIELD(6, 2) /* index 17 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(22),
+  BITFIELD(8, 2) /* index 22 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(27),
+  BITFIELD(10, 2) /* index 27 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI,
+  BITFIELD(0, 2) /* index 32 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(37),
+  BITFIELD(2, 2) /* index 37 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(42),
+  BITFIELD(4, 2) /* index 42 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(47),
+  BITFIELD(6, 2) /* index 47 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(52),
+  BITFIELD(8, 2) /* index 52 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(57),
+  BITFIELD(10, 2) /* index 57 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO,
+  BITFIELD(18, 2) /* index 62 */,
+  TILEGX_OPC_ADDX, TILEGX_OPC_ADD, TILEGX_OPC_SUBX, TILEGX_OPC_SUB,
+  BITFIELD(15, 5) /* index 67 */,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD,
+  TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD,
+  TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, CHILD(100),
+  CHILD(109), TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(12, 3) /* index 100 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_CLZ, TILEGX_OPC_CTZ, TILEGX_OPC_FNOP,
+  TILEGX_OPC_FSINGLE_PACK1, TILEGX_OPC_NOP, TILEGX_OPC_PCNT,
+  TILEGX_OPC_REVBITS,
+  BITFIELD(12, 3) /* index 109 */,
+  TILEGX_OPC_REVBYTES, TILEGX_OPC_TBLIDXB0, TILEGX_OPC_TBLIDXB1,
+  TILEGX_OPC_TBLIDXB2, TILEGX_OPC_TBLIDXB3, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE,
+  BITFIELD(18, 2) /* index 118 */,
+  TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU,
+  BITFIELD(18, 2) /* index 123 */,
+  TILEGX_OPC_CMPEQ, TILEGX_OPC_CMPNE, TILEGX_OPC_MULAX, TILEGX_OPC_MULX,
+  BITFIELD(18, 2) /* index 128 */,
+  TILEGX_OPC_CMOVEQZ, TILEGX_OPC_CMOVNEZ, TILEGX_OPC_MNZ, TILEGX_OPC_MZ,
+  BITFIELD(18, 2) /* index 133 */,
+  TILEGX_OPC_AND, TILEGX_OPC_NOR, CHILD(138), TILEGX_OPC_XOR,
+  BITFIELD(12, 2) /* index 138 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(143),
+  BITFIELD(14, 2) /* index 143 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(148),
+  BITFIELD(16, 2) /* index 148 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE,
+  BITFIELD(18, 2) /* index 153 */,
+  TILEGX_OPC_ROTL, TILEGX_OPC_SHL, TILEGX_OPC_SHRS, TILEGX_OPC_SHRU,
+  BITFIELD(18, 2) /* index 158 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_SHL1ADDX, TILEGX_OPC_SHL2ADDX,
+  TILEGX_OPC_SHL3ADDX,
+  BITFIELD(18, 2) /* index 163 */,
+  TILEGX_OPC_MUL_HS_HS, TILEGX_OPC_MUL_HU_HU, TILEGX_OPC_MUL_LS_LS,
+  TILEGX_OPC_MUL_LU_LU,
+  BITFIELD(18, 2) /* index 168 */,
+  TILEGX_OPC_MULA_HS_HS, TILEGX_OPC_MULA_HU_HU, TILEGX_OPC_MULA_LS_LS,
+  TILEGX_OPC_MULA_LU_LU,
+  BITFIELD(18, 2) /* index 173 */,
+  TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI,
+};
+
+static const unsigned short decode_Y1_fsm[167] =
+{
+  BITFIELD(58, 4) /* index 0 */,
+  TILEGX_OPC_NONE, CHILD(17), TILEGX_OPC_ADDXI, CHILD(32), TILEGX_OPC_CMPEQI,
+  TILEGX_OPC_CMPLTSI, CHILD(62), CHILD(67), CHILD(117), CHILD(122),
+  CHILD(127), CHILD(132), CHILD(152), CHILD(157), CHILD(162), TILEGX_OPC_NONE,
+  BITFIELD(37, 2) /* index 17 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(22),
+  BITFIELD(39, 2) /* index 22 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(27),
+  BITFIELD(41, 2) /* index 27 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI,
+  BITFIELD(31, 2) /* index 32 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(37),
+  BITFIELD(33, 2) /* index 37 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(42),
+  BITFIELD(35, 2) /* index 42 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(47),
+  BITFIELD(37, 2) /* index 47 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(52),
+  BITFIELD(39, 2) /* index 52 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(57),
+  BITFIELD(41, 2) /* index 57 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO,
+  BITFIELD(49, 2) /* index 62 */,
+  TILEGX_OPC_ADDX, TILEGX_OPC_ADD, TILEGX_OPC_SUBX, TILEGX_OPC_SUB,
+  BITFIELD(47, 4) /* index 67 */,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL3ADD,
+  TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, CHILD(84),
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(43, 3) /* index 84 */,
+  CHILD(93), CHILD(96), CHILD(99), CHILD(102), CHILD(105), CHILD(108),
+  CHILD(111), CHILD(114),
+  BITFIELD(46, 1) /* index 93 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_FNOP,
+  BITFIELD(46, 1) /* index 96 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_ILL,
+  BITFIELD(46, 1) /* index 99 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_JALRP,
+  BITFIELD(46, 1) /* index 102 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_JALR,
+  BITFIELD(46, 1) /* index 105 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_JRP,
+  BITFIELD(46, 1) /* index 108 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_JR,
+  BITFIELD(46, 1) /* index 111 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_LNK,
+  BITFIELD(46, 1) /* index 114 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_NOP,
+  BITFIELD(49, 2) /* index 117 */,
+  TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU,
+  BITFIELD(49, 2) /* index 122 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_CMPEQ, TILEGX_OPC_CMPNE,
+  BITFIELD(49, 2) /* index 127 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_MNZ, TILEGX_OPC_MZ,
+  BITFIELD(49, 2) /* index 132 */,
+  TILEGX_OPC_AND, TILEGX_OPC_NOR, CHILD(137), TILEGX_OPC_XOR,
+  BITFIELD(43, 2) /* index 137 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(142),
+  BITFIELD(45, 2) /* index 142 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(147),
+  BITFIELD(47, 2) /* index 147 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE,
+  BITFIELD(49, 2) /* index 152 */,
+  TILEGX_OPC_ROTL, TILEGX_OPC_SHL, TILEGX_OPC_SHRS, TILEGX_OPC_SHRU,
+  BITFIELD(49, 2) /* index 157 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_SHL1ADDX, TILEGX_OPC_SHL2ADDX,
+  TILEGX_OPC_SHL3ADDX,
+  BITFIELD(49, 2) /* index 162 */,
+  TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI,
+};
+
+static const unsigned short decode_Y2_fsm[118] =
+{
+  BITFIELD(62, 2) /* index 0 */,
+  TILEGX_OPC_NONE, CHILD(5), CHILD(66), CHILD(109),
+  BITFIELD(55, 3) /* index 5 */,
+  CHILD(14), CHILD(14), CHILD(14), CHILD(17), CHILD(40), CHILD(40), CHILD(40),
+  CHILD(43),
+  BITFIELD(26, 1) /* index 14 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1U,
+  BITFIELD(26, 1) /* index 17 */,
+  CHILD(20), CHILD(30),
+  BITFIELD(51, 2) /* index 20 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, CHILD(25),
+  BITFIELD(53, 2) /* index 25 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S,
+  TILEGX_OPC_PREFETCH_L1_FAULT,
+  BITFIELD(51, 2) /* index 30 */,
+  TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, CHILD(35),
+  BITFIELD(53, 2) /* index 35 */,
+  TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_PREFETCH,
+  BITFIELD(26, 1) /* index 40 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2U,
+  BITFIELD(26, 1) /* index 43 */,
+  CHILD(46), CHILD(56),
+  BITFIELD(51, 2) /* index 46 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, CHILD(51),
+  BITFIELD(53, 2) /* index 51 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S,
+  TILEGX_OPC_PREFETCH_L2_FAULT,
+  BITFIELD(51, 2) /* index 56 */,
+  TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, CHILD(61),
+  BITFIELD(53, 2) /* index 61 */,
+  TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_PREFETCH_L2,
+  BITFIELD(56, 2) /* index 66 */,
+  CHILD(71), CHILD(74), CHILD(90), CHILD(93),
+  BITFIELD(26, 1) /* index 71 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_LD4S,
+  BITFIELD(26, 1) /* index 74 */,
+  TILEGX_OPC_NONE, CHILD(77),
+  BITFIELD(51, 2) /* index 77 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(82),
+  BITFIELD(53, 2) /* index 82 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(87),
+  BITFIELD(55, 1) /* index 87 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_PREFETCH_L3_FAULT,
+  BITFIELD(26, 1) /* index 90 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD,
+  BITFIELD(26, 1) /* index 93 */,
+  CHILD(96), TILEGX_OPC_LD,
+  BITFIELD(51, 2) /* index 96 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(101),
+  BITFIELD(53, 2) /* index 101 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(106),
+  BITFIELD(55, 1) /* index 106 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_PREFETCH_L3,
+  BITFIELD(26, 1) /* index 109 */,
+  CHILD(112), CHILD(115),
+  BITFIELD(57, 1) /* index 112 */,
+  TILEGX_OPC_ST1, TILEGX_OPC_ST4,
+  BITFIELD(57, 1) /* index 115 */,
+  TILEGX_OPC_ST2, TILEGX_OPC_ST,
+};
+
+#undef BITFIELD
+#undef CHILD
+const unsigned short * const
+tilegx_bundle_decoder_fsms[TILEGX_NUM_PIPELINE_ENCODINGS] =
+{
+  decode_X0_fsm,
+  decode_X1_fsm,
+  decode_Y0_fsm,
+  decode_Y1_fsm,
+  decode_Y2_fsm
+};
+const struct tilegx_operand tilegx_operands[35] =
+{
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_X0),
+    8, 1, 0, 0, 0, 0,
+    create_Imm8_X0, get_Imm8_X0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_X1),
+    8, 1, 0, 0, 0, 0,
+    create_Imm8_X1, get_Imm8_X1
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_Y0),
+    8, 1, 0, 0, 0, 0,
+    create_Imm8_Y0, get_Imm8_Y0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_Y1),
+    8, 1, 0, 0, 0, 0,
+    create_Imm8_Y1, get_Imm8_Y1
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM16_X0_HW0_LAST),
+    16, 1, 0, 0, 0, 0,
+    create_Imm16_X0, get_Imm16_X0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM16_X1_HW0_LAST),
+    16, 1, 0, 0, 0, 0,
+    create_Imm16_X1, get_Imm16_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 0, 1, 0, 0,
+    create_Dest_X0, get_Dest_X0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcA_X0, get_SrcA_X0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 0, 1, 0, 0,
+    create_Dest_X1, get_Dest_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcA_X1, get_SrcA_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 0, 1, 0, 0,
+    create_Dest_Y0, get_Dest_Y0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcA_Y0, get_SrcA_Y0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 0, 1, 0, 0,
+    create_Dest_Y1, get_Dest_Y1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcA_Y1, get_SrcA_Y1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcA_Y2, get_SrcA_Y2
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 1, 0, 0,
+    create_SrcA_X1, get_SrcA_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcB_X0, get_SrcB_X0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcB_X1, get_SrcB_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcB_Y0, get_SrcB_Y0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcB_Y1, get_SrcB_Y1
+  },
+  {
+    TILEGX_OP_TYPE_ADDRESS, BFD_RELOC(TILEGX_BROFF_X1),
+    17, 1, 0, 0, 1, TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES,
+    create_BrOff_X1, get_BrOff_X1
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(NONE),
+    6, 0, 0, 0, 0, 0,
+    create_BFStart_X0, get_BFStart_X0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(NONE),
+    6, 0, 0, 0, 0, 0,
+    create_BFEnd_X0, get_BFEnd_X0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 1, 0, 0,
+    create_Dest_X0, get_Dest_X0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 1, 0, 0,
+    create_Dest_Y0, get_Dest_Y0
+  },
+  {
+    TILEGX_OP_TYPE_ADDRESS, BFD_RELOC(TILEGX_JUMPOFF_X1),
+    27, 1, 0, 0, 1, TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES,
+    create_JumpOff_X1, get_JumpOff_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 0, 1, 0, 0,
+    create_SrcBDest_Y2, get_SrcBDest_Y2
+  },
+  {
+    TILEGX_OP_TYPE_SPR, BFD_RELOC(TILEGX_MF_IMM14_X1),
+    14, 0, 0, 0, 0, 0,
+    create_MF_Imm14_X1, get_MF_Imm14_X1
+  },
+  {
+    TILEGX_OP_TYPE_SPR, BFD_RELOC(TILEGX_MT_IMM14_X1),
+    14, 0, 0, 0, 0, 0,
+    create_MT_Imm14_X1, get_MT_Imm14_X1
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_X0),
+    6, 0, 0, 0, 0, 0,
+    create_ShAmt_X0, get_ShAmt_X0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_X1),
+    6, 0, 0, 0, 0, 0,
+    create_ShAmt_X1, get_ShAmt_X1
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_Y0),
+    6, 0, 0, 0, 0, 0,
+    create_ShAmt_Y0, get_ShAmt_Y0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_Y1),
+    6, 0, 0, 0, 0, 0,
+    create_ShAmt_Y1, get_ShAmt_Y1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcBDest_Y2, get_SrcBDest_Y2
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_DEST_IMM8_X1),
+    8, 1, 0, 0, 0, 0,
+    create_Dest_Imm8_X1, get_Dest_Imm8_X1
+  }
+};
+
+
+
+
+/* Given a set of bundle bits and the lookup FSM for a specific pipe,
+ * returns which instruction the bundle contains in that pipe.
+ */
+static const struct tilegx_opcode *
+find_opcode(tilegx_bundle_bits bits, const unsigned short *table)
+{
+  int index = 0;
+
+  while (1)
+  {
+    unsigned short bitspec = table[index];
+    unsigned int bitfield =
+      ((unsigned int)(bits >> (bitspec & 63))) & (bitspec >> 6);
+
+    unsigned short next = table[index + 1 + bitfield];
+    if (next <= TILEGX_OPC_NONE)
+      return &tilegx_opcodes[next];
+
+    index = next - TILEGX_OPC_NONE;
+  }
+}
+
+
+int
+parse_insn_tilegx(tilegx_bundle_bits bits,
+                  unsigned long long pc,
+                  struct tilegx_decoded_instruction
+                  decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE])
+{
+  int num_instructions = 0;
+  int pipe;
+
+  int min_pipe, max_pipe;
+  if ((bits & TILEGX_BUNDLE_MODE_MASK) == 0)
+  {
+    min_pipe = TILEGX_PIPELINE_X0;
+    max_pipe = TILEGX_PIPELINE_X1;
+  }
+  else
+  {
+    min_pipe = TILEGX_PIPELINE_Y0;
+    max_pipe = TILEGX_PIPELINE_Y2;
+  }
+
+  /* For each pipe, find an instruction that fits. */
+  for (pipe = min_pipe; pipe <= max_pipe; pipe++)
+  {
+    const struct tilegx_opcode *opc;
+    struct tilegx_decoded_instruction *d;
+    int i;
+
+    d = &decoded[num_instructions++];
+    opc = find_opcode (bits, tilegx_bundle_decoder_fsms[pipe]);
+    d->opcode = opc;
+
+    /* Decode each operand, sign extending, etc. as appropriate. */
+    for (i = 0; i < opc->num_operands; i++)
+    {
+      const struct tilegx_operand *op =
+        &tilegx_operands[opc->operands[pipe][i]];
+      int raw_opval = op->extract (bits);
+      long long opval;
+
+      if (op->is_signed)
+      {
+        /* Sign-extend the operand. */
+        int shift = (int)((sizeof(int) * 8) - op->num_bits);
+        raw_opval = (raw_opval << shift) >> shift;
+      }
+
+      /* Adjust PC-relative scaled branch offsets. */
+      if (op->type == TILEGX_OP_TYPE_ADDRESS)
+        opval = (raw_opval * TILEGX_BUNDLE_SIZE_IN_BYTES) + pc;
+      else
+        opval = raw_opval;
+
+      /* Record the final value. */
+      d->operands[i] = op;
+      d->operand_values[i] = opval;
+    }
+  }
+
+  return num_instructions;
+}
index 49a605be94c56bb3712dabfa988969261eb446bb..c4be58cc5d5083fe213c9994b236c272f13c992a 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/delay.h>
+#include <linux/module.h>
 #include <asm/irq_regs.h>
 #include <asm/traps.h>
 #include <hv/hypervisor.h>
@@ -56,6 +57,7 @@ cycles_t get_cycles(void)
 
        return (((cycles_t)high) << 32) | low;
 }
+EXPORT_SYMBOL(get_cycles);
 #endif
 
 /*
index 2dffc1044d8314041a6566a2d93634f979e1775e..a5f241c24cac9ec3cdc6fc6d5e8099fe152921d6 100644 (file)
@@ -34,13 +34,13 @@ void flush_tlb_mm(struct mm_struct *mm)
 {
        HV_Remote_ASID asids[NR_CPUS];
        int i = 0, cpu;
-       for_each_cpu(cpu, &mm->cpu_vm_mask) {
+       for_each_cpu(cpu, mm_cpumask(mm)) {
                HV_Remote_ASID *asid = &asids[i++];
                asid->y = cpu / smp_topology.width;
                asid->x = cpu % smp_topology.width;
                asid->asid = per_cpu(current_asid, cpu);
        }
-       flush_remote(0, HV_FLUSH_EVICT_L1I, &mm->cpu_vm_mask,
+       flush_remote(0, HV_FLUSH_EVICT_L1I, mm_cpumask(mm),
                     0, 0, 0, NULL, asids, i);
 }
 
@@ -54,8 +54,8 @@ void flush_tlb_page_mm(const struct vm_area_struct *vma, struct mm_struct *mm,
 {
        unsigned long size = hv_page_size(vma);
        int cache = (vma->vm_flags & VM_EXEC) ? HV_FLUSH_EVICT_L1I : 0;
-       flush_remote(0, cache, &mm->cpu_vm_mask,
-                    va, size, size, &mm->cpu_vm_mask, NULL, 0);
+       flush_remote(0, cache, mm_cpumask(mm),
+                    va, size, size, mm_cpumask(mm), NULL, 0);
 }
 
 void flush_tlb_page(const struct vm_area_struct *vma, unsigned long va)
@@ -70,8 +70,8 @@ void flush_tlb_range(const struct vm_area_struct *vma,
        unsigned long size = hv_page_size(vma);
        struct mm_struct *mm = vma->vm_mm;
        int cache = (vma->vm_flags & VM_EXEC) ? HV_FLUSH_EVICT_L1I : 0;
-       flush_remote(0, cache, &mm->cpu_vm_mask, start, end - start, size,
-                    &mm->cpu_vm_mask, NULL, 0);
+       flush_remote(0, cache, mm_cpumask(mm), start, end - start, size,
+                    mm_cpumask(mm), NULL, 0);
 }
 
 void flush_tlb_all(void)
index 5474fc2e77e8456b3d6e745b8defc3129e08eb85..f9803dfa73573deed9f98349c212aeb45bc8dc6a 100644 (file)
@@ -308,6 +308,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
        info.si_addr = (void __user *)address;
        if (signo == SIGILL)
                info.si_trapno = fault_num;
+       trace_unhandled_signal("trap", regs, address, signo);
        force_sig_info(signo, &info, current);
 }
 
index 38f64fafdc10a9d8a3271a50d333b9787074ce19..631f10de12feee423e5c3376f56813cc35fb6053 100644 (file)
@@ -60,7 +60,7 @@ SECTIONS
   . = ALIGN(PAGE_SIZE);
   VMLINUX_SYMBOL(_sinitdata) = .;
   INIT_DATA_SECTION(16) :data =0
-  PERCPU(L2_CACHE_BYTES, PAGE_SIZE)
+  PERCPU_SECTION(L2_CACHE_BYTES)
   . = ALIGN(PAGE_SIZE);
   VMLINUX_SYMBOL(_einitdata) = .;
 
index 82f64cc636589ed9c1ae1ec9aaf743949edeb2da..24448734f6f17c3f70f95f4252afbf98c5dcce00 100644 (file)
@@ -59,7 +59,7 @@
  * bad kernel addresses).
  *
  * Note that if the value we would store is the same as what we
- * loaded, we bypass the load.  Other platforms with true atomics can
+ * loaded, we bypass the store.  Other platforms with true atomics can
  * make the guarantee that a non-atomic __clear_bit(), for example,
  * can safely race with an atomic test_and_set_bit(); this example is
  * from bit_spinlock.h in slub_lock() / slub_unlock().  We can't do
index 35c1d8ca5f38132e9428db0297f22062dbbb68e4..8928aace7a641d8a2b7be866f88deefb4f5f9a1e 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/page.h>
 #include <asm/cacheflush.h>
 #include <arch/icache.h>
+#include <arch/spr_def.h>
 
 
 void __flush_icache_range(unsigned long start, unsigned long end)
@@ -39,6 +40,18 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh)
        char *p, *base;
        size_t step_size, load_count;
        const unsigned long STRIPE_WIDTH = 8192;
+#ifdef __tilegx__
+       /*
+        * On TILE-Gx, we must disable the dstream prefetcher before doing
+        * a cache flush; otherwise, we could end up with data in the cache
+        * that we don't want there.  Note that normally we'd do an mf
+        * after the SPR write to disabling the prefetcher, but we do one
+        * below, before any further loads, so there's no need to do it
+        * here.
+        */
+       uint_reg_t old_dstream_pf = __insn_mfspr(SPR_DSTREAM_PF);
+       __insn_mtspr(SPR_DSTREAM_PF, 0);
+#endif
 
        /*
         * Flush and invalidate the buffer out of the local L1/L2
@@ -122,4 +135,9 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh)
 
        /* Wait for the load+inv's (and thus finvs) to have completed. */
        __insn_mf();
+
+#ifdef __tilegx__
+       /* Reenable the prefetcher. */
+       __insn_mtspr(SPR_DSTREAM_PF, old_dstream_pf);
+#endif
 }
diff --git a/arch/tile/lib/memchr_64.c b/arch/tile/lib/memchr_64.c
new file mode 100644 (file)
index 0000000..84fdc8d
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+void *memchr(const void *s, int c, size_t n)
+{
+       const uint64_t *last_word_ptr;
+       const uint64_t *p;
+       const char *last_byte_ptr;
+       uintptr_t s_int;
+       uint64_t goal, before_mask, v, bits;
+       char *ret;
+
+       if (__builtin_expect(n == 0, 0)) {
+               /* Don't dereference any memory if the array is empty. */
+               return NULL;
+       }
+
+       /* Get an aligned pointer. */
+       s_int = (uintptr_t) s;
+       p = (const uint64_t *)(s_int & -8);
+
+       /* Create eight copies of the byte for which we are looking. */
+       goal = 0x0101010101010101ULL * (uint8_t) c;
+
+       /* Read the first word, but munge it so that bytes before the array
+        * will not match goal.
+        *
+        * Note that this shift count expression works because we know
+        * shift counts are taken mod 64.
+        */
+       before_mask = (1ULL << (s_int << 3)) - 1;
+       v = (*p | before_mask) ^ (goal & before_mask);
+
+       /* Compute the address of the last byte. */
+       last_byte_ptr = (const char *)s + n - 1;
+
+       /* Compute the address of the word containing the last byte. */
+       last_word_ptr = (const uint64_t *)((uintptr_t) last_byte_ptr & -8);
+
+       while ((bits = __insn_v1cmpeq(v, goal)) == 0) {
+               if (__builtin_expect(p == last_word_ptr, 0)) {
+                       /* We already read the last word in the array,
+                        * so give up.
+                        */
+                       return NULL;
+               }
+               v = *++p;
+       }
+
+       /* We found a match, but it might be in a byte past the end
+        * of the array.
+        */
+       ret = ((char *)p) + (__insn_ctz(bits) >> 3);
+       return (ret <= last_byte_ptr) ? ret : NULL;
+}
+EXPORT_SYMBOL(memchr);
diff --git a/arch/tile/lib/memcpy_64.c b/arch/tile/lib/memcpy_64.c
new file mode 100644 (file)
index 0000000..3fab9a6
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#define __memcpy memcpy
+/* EXPORT_SYMBOL() is in arch/tile/lib/exports.c since this should be asm. */
+
+/* Must be 8 bytes in size. */
+#define word_t uint64_t
+
+#if CHIP_L2_LINE_SIZE() != 64 && CHIP_L2_LINE_SIZE() != 128
+#error "Assumes 64 or 128 byte line size"
+#endif
+
+/* How many cache lines ahead should we prefetch? */
+#define PREFETCH_LINES_AHEAD 3
+
+/*
+ * Provide "base versions" of load and store for the normal code path.
+ * The kernel provides other versions for userspace copies.
+ */
+#define ST(p, v) (*(p) = (v))
+#define LD(p) (*(p))
+
+#ifndef USERCOPY_FUNC
+#define ST1 ST
+#define ST2 ST
+#define ST4 ST
+#define ST8 ST
+#define LD1 LD
+#define LD2 LD
+#define LD4 LD
+#define LD8 LD
+#define RETVAL dstv
+void *memcpy(void *__restrict dstv, const void *__restrict srcv, size_t n)
+#else
+/*
+ * Special kernel version will provide implementation of the LDn/STn
+ * macros to return a count of uncopied bytes due to mm fault.
+ */
+#define RETVAL 0
+int USERCOPY_FUNC(void *__restrict dstv, const void *__restrict srcv, size_t n)
+#endif
+{
+       char *__restrict dst1 = (char *)dstv;
+       const char *__restrict src1 = (const char *)srcv;
+       const char *__restrict src1_end;
+       const char *__restrict prefetch;
+       word_t *__restrict dst8;    /* 8-byte pointer to destination memory. */
+       word_t final; /* Final bytes to write to trailing word, if any */
+       long i;
+
+       if (n < 16) {
+               for (; n; n--)
+                       ST1(dst1++, LD1(src1++));
+               return RETVAL;
+       }
+
+       /*
+        * Locate the end of source memory we will copy.  Don't
+        * prefetch past this.
+        */
+       src1_end = src1 + n - 1;
+
+       /* Prefetch ahead a few cache lines, but not past the end. */
+       prefetch = src1;
+       for (i = 0; i < PREFETCH_LINES_AHEAD; i++) {
+               __insn_prefetch(prefetch);
+               prefetch += CHIP_L2_LINE_SIZE();
+               prefetch = (prefetch > src1_end) ? prefetch : src1;
+       }
+
+       /* Copy bytes until dst is word-aligned. */
+       for (; (uintptr_t)dst1 & (sizeof(word_t) - 1); n--)
+               ST1(dst1++, LD1(src1++));
+
+       /* 8-byte pointer to destination memory. */
+       dst8 = (word_t *)dst1;
+
+       if (__builtin_expect((uintptr_t)src1 & (sizeof(word_t) - 1), 0)) {
+               /*
+                * Misaligned copy.  Copy 8 bytes at a time, but don't
+                * bother with other fanciness.
+                *
+                * TODO: Consider prefetching and using wh64 as well.
+                */
+
+               /* Create an aligned src8. */
+               const word_t *__restrict src8 =
+                       (const word_t *)((uintptr_t)src1 & -sizeof(word_t));
+               word_t b;
+
+               word_t a = LD8(src8++);
+               for (; n >= sizeof(word_t); n -= sizeof(word_t)) {
+                       b = LD8(src8++);
+                       a = __insn_dblalign(a, b, src1);
+                       ST8(dst8++, a);
+                       a = b;
+               }
+
+               if (n == 0)
+                       return RETVAL;
+
+               b = ((const char *)src8 <= src1_end) ? *src8 : 0;
+
+               /*
+                * Final source bytes to write to trailing partial
+                * word, if any.
+                */
+               final = __insn_dblalign(a, b, src1);
+       } else {
+               /* Aligned copy. */
+
+               const word_t* __restrict src8 = (const word_t *)src1;
+
+               /* src8 and dst8 are both word-aligned. */
+               if (n >= CHIP_L2_LINE_SIZE()) {
+                       /* Copy until 'dst' is cache-line-aligned. */
+                       for (; (uintptr_t)dst8 & (CHIP_L2_LINE_SIZE() - 1);
+                            n -= sizeof(word_t))
+                               ST8(dst8++, LD8(src8++));
+
+                       for (; n >= CHIP_L2_LINE_SIZE(); ) {
+                               __insn_wh64(dst8);
+
+                               /*
+                                * Prefetch and advance to next line
+                                * to prefetch, but don't go past the end
+                                */
+                               __insn_prefetch(prefetch);
+                               prefetch += CHIP_L2_LINE_SIZE();
+                               prefetch = (prefetch > src1_end) ? prefetch :
+                                       (const char *)src8;
+
+                               /*
+                                * Copy an entire cache line.  Manually
+                                * unrolled to avoid idiosyncracies of
+                                * compiler unrolling.
+                                */
+#define COPY_WORD(offset) ({ ST8(dst8+offset, LD8(src8+offset)); n -= 8; })
+                               COPY_WORD(0);
+                               COPY_WORD(1);
+                               COPY_WORD(2);
+                               COPY_WORD(3);
+                               COPY_WORD(4);
+                               COPY_WORD(5);
+                               COPY_WORD(6);
+                               COPY_WORD(7);
+#if CHIP_L2_LINE_SIZE() == 128
+                               COPY_WORD(8);
+                               COPY_WORD(9);
+                               COPY_WORD(10);
+                               COPY_WORD(11);
+                               COPY_WORD(12);
+                               COPY_WORD(13);
+                               COPY_WORD(14);
+                               COPY_WORD(15);
+#elif CHIP_L2_LINE_SIZE() != 64
+# error Fix code that assumes particular L2 cache line sizes
+#endif
+
+                               dst8 += CHIP_L2_LINE_SIZE() / sizeof(word_t);
+                               src8 += CHIP_L2_LINE_SIZE() / sizeof(word_t);
+                       }
+               }
+
+               for (; n >= sizeof(word_t); n -= sizeof(word_t))
+                       ST8(dst8++, LD8(src8++));
+
+               if (__builtin_expect(n == 0, 1))
+                       return RETVAL;
+
+               final = LD8(src8);
+       }
+
+       /* n != 0 if we get here.  Write out any trailing bytes. */
+       dst1 = (char *)dst8;
+       if (n & 4) {
+               ST4((uint32_t *)dst1, final);
+               dst1 += 4;
+               final >>= 32;
+               n &= 3;
+       }
+       if (n & 2) {
+               ST2((uint16_t *)dst1, final);
+               dst1 += 2;
+               final >>= 16;
+               n &= 1;
+       }
+       if (n)
+               ST1((uint8_t *)dst1, final);
+
+       return RETVAL;
+}
+
+
+#ifdef USERCOPY_FUNC
+#undef ST1
+#undef ST2
+#undef ST4
+#undef ST8
+#undef LD1
+#undef LD2
+#undef LD4
+#undef LD8
+#undef USERCOPY_FUNC
+#endif
diff --git a/arch/tile/lib/memcpy_user_64.c b/arch/tile/lib/memcpy_user_64.c
new file mode 100644 (file)
index 0000000..4763b3a
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * Do memcpy(), but trap and return "n" when a load or store faults.
+ *
+ * Note: this idiom only works when memcpy() compiles to a leaf function.
+ * If "sp" is updated during memcpy, the "jrp lr" will be incorrect.
+ *
+ * Also note that we are capturing "n" from the containing scope here.
+ */
+
+#define _ST(p, inst, v)                                                \
+       ({                                                      \
+               asm("1: " #inst " %0, %1;"                      \
+                   ".pushsection .coldtext.memcpy,\"ax\";"     \
+                   "2: { move r0, %2; jrp lr };"               \
+                   ".section __ex_table,\"a\";"                \
+                   ".quad 1b, 2b;"                             \
+                   ".popsection"                               \
+                   : "=m" (*(p)) : "r" (v), "r" (n));          \
+       })
+
+#define _LD(p, inst)                                           \
+       ({                                                      \
+               unsigned long __v;                              \
+               asm("1: " #inst " %0, %1;"                      \
+                   ".pushsection .coldtext.memcpy,\"ax\";"     \
+                   "2: { move r0, %2; jrp lr };"               \
+                   ".section __ex_table,\"a\";"                \
+                   ".quad 1b, 2b;"                             \
+                   ".popsection"                               \
+                   : "=r" (__v) : "m" (*(p)), "r" (n));        \
+               __v;                                            \
+       })
+
+#define USERCOPY_FUNC __copy_to_user_inatomic
+#define ST1(p, v) _ST((p), st1, (v))
+#define ST2(p, v) _ST((p), st2, (v))
+#define ST4(p, v) _ST((p), st4, (v))
+#define ST8(p, v) _ST((p), st, (v))
+#define LD1 LD
+#define LD2 LD
+#define LD4 LD
+#define LD8 LD
+#include "memcpy_64.c"
+
+#define USERCOPY_FUNC __copy_from_user_inatomic
+#define ST1 ST
+#define ST2 ST
+#define ST4 ST
+#define ST8 ST
+#define LD1(p) _LD((p), ld1u)
+#define LD2(p) _LD((p), ld2u)
+#define LD4(p) _LD((p), ld4u)
+#define LD8(p) _LD((p), ld)
+#include "memcpy_64.c"
+
+#define USERCOPY_FUNC __copy_in_user_inatomic
+#define ST1(p, v) _ST((p), st1, (v))
+#define ST2(p, v) _ST((p), st2, (v))
+#define ST4(p, v) _ST((p), st4, (v))
+#define ST8(p, v) _ST((p), st, (v))
+#define LD1(p) _LD((p), ld1u)
+#define LD2(p) _LD((p), ld2u)
+#define LD4(p) _LD((p), ld4u)
+#define LD8(p) _LD((p), ld)
+#include "memcpy_64.c"
+
+unsigned long __copy_from_user_zeroing(void *to, const void __user *from,
+                                      unsigned long n)
+{
+       unsigned long rc = __copy_from_user_inatomic(to, from, n);
+       if (unlikely(rc))
+               memset(to + n - rc, 0, rc);
+       return rc;
+}
diff --git a/arch/tile/lib/memset_64.c b/arch/tile/lib/memset_64.c
new file mode 100644 (file)
index 0000000..3873085
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <arch/chip.h>
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+#undef memset
+
+void *memset(void *s, int c, size_t n)
+{
+       uint64_t *out64;
+       int n64, to_align64;
+       uint64_t v64;
+       uint8_t *out8 = s;
+
+       /* Experimentation shows that a trivial tight loop is a win up until
+        * around a size of 20, where writing a word at a time starts to win.
+        */
+#define BYTE_CUTOFF 20
+
+#if BYTE_CUTOFF < 7
+       /* This must be at least at least this big, or some code later
+        * on doesn't work.
+        */
+#error "BYTE_CUTOFF is too small"
+#endif
+
+       if (n < BYTE_CUTOFF) {
+               /* Strangely, this turns out to be the tightest way to
+                * write this loop.
+                */
+               if (n != 0) {
+                       do {
+                               /* Strangely, combining these into one line
+                                * performs worse.
+                                */
+                               *out8 = c;
+                               out8++;
+                       } while (--n != 0);
+               }
+
+               return s;
+       }
+
+       /* Align 'out8'. We know n >= 7 so this won't write past the end. */
+       while (((uintptr_t) out8 & 7) != 0) {
+               *out8++ = c;
+               --n;
+       }
+
+       /* Align 'n'. */
+       while (n & 7)
+               out8[--n] = c;
+
+       out64 = (uint64_t *) out8;
+       n64 = n >> 3;
+
+       /* Tile input byte out to 64 bits. */
+       /* KLUDGE */
+       v64 = 0x0101010101010101ULL * (uint8_t)c;
+
+       /* This must be at least 8 or the following loop doesn't work. */
+#define CACHE_LINE_SIZE_IN_DOUBLEWORDS (CHIP_L2_LINE_SIZE() / 8)
+
+       /* Determine how many words we need to emit before the 'out32'
+        * pointer becomes aligned modulo the cache line size.
+        */
+       to_align64 = (-((uintptr_t)out64 >> 3)) &
+               (CACHE_LINE_SIZE_IN_DOUBLEWORDS - 1);
+
+       /* Only bother aligning and using wh64 if there is at least
+        * one full cache line to process.  This check also prevents
+        * overrunning the end of the buffer with alignment words.
+        */
+       if (to_align64 <= n64 - CACHE_LINE_SIZE_IN_DOUBLEWORDS) {
+               int lines_left;
+
+               /* Align out64 mod the cache line size so we can use wh64. */
+               n64 -= to_align64;
+               for (; to_align64 != 0; to_align64--) {
+                       *out64 = v64;
+                       out64++;
+               }
+
+               /* Use unsigned divide to turn this into a right shift. */
+               lines_left = (unsigned)n64 / CACHE_LINE_SIZE_IN_DOUBLEWORDS;
+
+               do {
+                       /* Only wh64 a few lines at a time, so we don't
+                        * exceed the maximum number of victim lines.
+                        */
+                       int x = ((lines_left < CHIP_MAX_OUTSTANDING_VICTIMS())
+                                 ? lines_left
+                                 : CHIP_MAX_OUTSTANDING_VICTIMS());
+                       uint64_t *wh = out64;
+                       int i = x;
+                       int j;
+
+                       lines_left -= x;
+
+                       do {
+                               __insn_wh64(wh);
+                               wh += CACHE_LINE_SIZE_IN_DOUBLEWORDS;
+                       } while (--i);
+
+                       for (j = x * (CACHE_LINE_SIZE_IN_DOUBLEWORDS / 4);
+                            j != 0; j--) {
+                               *out64++ = v64;
+                               *out64++ = v64;
+                               *out64++ = v64;
+                               *out64++ = v64;
+                       }
+               } while (lines_left != 0);
+
+               /* We processed all full lines above, so only this many
+                * words remain to be processed.
+                */
+               n64 &= CACHE_LINE_SIZE_IN_DOUBLEWORDS - 1;
+       }
+
+       /* Now handle any leftover values. */
+       if (n64 != 0) {
+               do {
+                       *out64 = v64;
+                       out64++;
+               } while (--n64 != 0);
+       }
+
+       return s;
+}
+EXPORT_SYMBOL(memset);
diff --git a/arch/tile/lib/spinlock_64.c b/arch/tile/lib/spinlock_64.c
new file mode 100644 (file)
index 0000000..d6fb958
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <asm/processor.h>
+
+#include "spinlock_common.h"
+
+/*
+ * Read the spinlock value without allocating in our cache and without
+ * causing an invalidation to another cpu with a copy of the cacheline.
+ * This is important when we are spinning waiting for the lock.
+ */
+static inline u32 arch_spin_read_noalloc(void *lock)
+{
+       return atomic_cmpxchg((atomic_t *)lock, -1, -1);
+}
+
+/*
+ * Wait until the high bits (current) match my ticket.
+ * If we notice the overflow bit set on entry, we clear it.
+ */
+void arch_spin_lock_slow(arch_spinlock_t *lock, u32 my_ticket)
+{
+       if (unlikely(my_ticket & __ARCH_SPIN_NEXT_OVERFLOW)) {
+               __insn_fetchand4(&lock->lock, ~__ARCH_SPIN_NEXT_OVERFLOW);
+               my_ticket &= ~__ARCH_SPIN_NEXT_OVERFLOW;
+       }
+
+       for (;;) {
+               u32 val = arch_spin_read_noalloc(lock);
+               u32 delta = my_ticket - arch_spin_current(val);
+               if (delta == 0)
+                       return;
+               relax((128 / CYCLES_PER_RELAX_LOOP) * delta);
+       }
+}
+EXPORT_SYMBOL(arch_spin_lock_slow);
+
+/*
+ * Check the lock to see if it is plausible, and try to get it with cmpxchg().
+ */
+int arch_spin_trylock(arch_spinlock_t *lock)
+{
+       u32 val = arch_spin_read_noalloc(lock);
+       if (unlikely(arch_spin_current(val) != arch_spin_next(val)))
+               return 0;
+       return cmpxchg(&lock->lock, val, (val + 1) & ~__ARCH_SPIN_NEXT_OVERFLOW)
+               == val;
+}
+EXPORT_SYMBOL(arch_spin_trylock);
+
+void arch_spin_unlock_wait(arch_spinlock_t *lock)
+{
+       u32 iterations = 0;
+       while (arch_spin_is_locked(lock))
+               delay_backoff(iterations++);
+}
+EXPORT_SYMBOL(arch_spin_unlock_wait);
+
+/*
+ * If the read lock fails due to a writer, we retry periodically
+ * until the value is positive and we write our incremented reader count.
+ */
+void __read_lock_failed(arch_rwlock_t *rw)
+{
+       u32 val;
+       int iterations = 0;
+       do {
+               delay_backoff(iterations++);
+               val = __insn_fetchaddgez4(&rw->lock, 1);
+       } while (unlikely(arch_write_val_locked(val)));
+}
+EXPORT_SYMBOL(__read_lock_failed);
+
+/*
+ * If we failed because there were readers, clear the "writer" bit
+ * so we don't block additional readers.  Otherwise, there was another
+ * writer anyway, so our "fetchor" made no difference.  Then wait,
+ * issuing periodic fetchor instructions, till we get the lock.
+ */
+void __write_lock_failed(arch_rwlock_t *rw, u32 val)
+{
+       int iterations = 0;
+       do {
+               if (!arch_write_val_locked(val))
+                       val = __insn_fetchand4(&rw->lock, ~__WRITE_LOCK_BIT);
+               delay_backoff(iterations++);
+               val = __insn_fetchor4(&rw->lock, __WRITE_LOCK_BIT);
+       } while (val != 0);
+}
+EXPORT_SYMBOL(__write_lock_failed);
diff --git a/arch/tile/lib/strchr_64.c b/arch/tile/lib/strchr_64.c
new file mode 100644 (file)
index 0000000..617a927
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+#undef strchr
+
+char *strchr(const char *s, int c)
+{
+       int z, g;
+
+       /* Get an aligned pointer. */
+       const uintptr_t s_int = (uintptr_t) s;
+       const uint64_t *p = (const uint64_t *)(s_int & -8);
+
+       /* Create eight copies of the byte for which we are looking. */
+       const uint64_t goal = 0x0101010101010101ULL * (uint8_t) c;
+
+       /* Read the first aligned word, but force bytes before the string to
+        * match neither zero nor goal (we make sure the high bit of each
+        * byte is 1, and the low 7 bits are all the opposite of the goal
+        * byte).
+        *
+        * Note that this shift count expression works because we know shift
+        * counts are taken mod 64.
+        */
+       const uint64_t before_mask = (1ULL << (s_int << 3)) - 1;
+       uint64_t v = (*p | before_mask) ^
+               (goal & __insn_v1shrsi(before_mask, 1));
+
+       uint64_t zero_matches, goal_matches;
+       while (1) {
+               /* Look for a terminating '\0'. */
+               zero_matches = __insn_v1cmpeqi(v, 0);
+
+               /* Look for the goal byte. */
+               goal_matches = __insn_v1cmpeq(v, goal);
+
+               if (__builtin_expect((zero_matches | goal_matches) != 0, 0))
+                       break;
+
+               v = *++p;
+       }
+
+       z = __insn_ctz(zero_matches);
+       g = __insn_ctz(goal_matches);
+
+       /* If we found c before '\0' we got a match. Note that if c == '\0'
+        * then g == z, and we correctly return the address of the '\0'
+        * rather than NULL.
+        */
+       return (g <= z) ? ((char *)p) + (g >> 3) : NULL;
+}
+EXPORT_SYMBOL(strchr);
diff --git a/arch/tile/lib/strlen_64.c b/arch/tile/lib/strlen_64.c
new file mode 100644 (file)
index 0000000..1c92d46
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+#undef strlen
+
+size_t strlen(const char *s)
+{
+       /* Get an aligned pointer. */
+       const uintptr_t s_int = (uintptr_t) s;
+       const uint64_t *p = (const uint64_t *)(s_int & -8);
+
+       /* Read the first word, but force bytes before the string to be nonzero.
+        * This expression works because we know shift counts are taken mod 64.
+        */
+       uint64_t v = *p | ((1ULL << (s_int << 3)) - 1);
+
+       uint64_t bits;
+       while ((bits = __insn_v1cmpeqi(v, 0)) == 0)
+               v = *++p;
+
+       return ((const char *)p) + (__insn_ctz(bits) >> 3) - s;
+}
+EXPORT_SYMBOL(strlen);
diff --git a/arch/tile/lib/usercopy_64.S b/arch/tile/lib/usercopy_64.S
new file mode 100644 (file)
index 0000000..2ff44f8
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/linkage.h>
+#include <asm/errno.h>
+#include <asm/cache.h>
+#include <arch/chip.h>
+
+/* Access user memory, but use MMU to avoid propagating kernel exceptions. */
+
+       .pushsection .fixup,"ax"
+
+get_user_fault:
+       { movei r1, -EFAULT; move r0, zero }
+       jrp lr
+       ENDPROC(get_user_fault)
+
+put_user_fault:
+       { movei r0, -EFAULT; jrp lr }
+       ENDPROC(put_user_fault)
+
+       .popsection
+
+/*
+ * __get_user_N functions take a pointer in r0, and return 0 in r1
+ * on success, with the value in r0; or else -EFAULT in r1.
+ */
+#define __get_user_N(bytes, LOAD) \
+       STD_ENTRY(__get_user_##bytes); \
+1:     { LOAD r0, r0; move r1, zero }; \
+       jrp lr; \
+       STD_ENDPROC(__get_user_##bytes); \
+       .pushsection __ex_table,"a"; \
+       .quad 1b, get_user_fault; \
+       .popsection
+
+__get_user_N(1, ld1u)
+__get_user_N(2, ld2u)
+__get_user_N(4, ld4u)
+__get_user_N(8, ld)
+
+/*
+ * __put_user_N functions take a value in r0 and a pointer in r1,
+ * and return 0 in r0 on success or -EFAULT on failure.
+ */
+#define __put_user_N(bytes, STORE) \
+       STD_ENTRY(__put_user_##bytes); \
+1:     { STORE r1, r0; move r0, zero }; \
+       jrp lr; \
+       STD_ENDPROC(__put_user_##bytes); \
+       .pushsection __ex_table,"a"; \
+       .quad 1b, put_user_fault; \
+       .popsection
+
+__put_user_N(1, st1)
+__put_user_N(2, st2)
+__put_user_N(4, st4)
+__put_user_N(8, st)
+
+/*
+ * strnlen_user_asm takes the pointer in r0, and the length bound in r1.
+ * It returns the length, including the terminating NUL, or zero on exception.
+ * If length is greater than the bound, returns one plus the bound.
+ */
+STD_ENTRY(strnlen_user_asm)
+       { beqz r1, 2f; addi r3, r0, -1 }  /* bias down to include NUL */
+1:      { ld1u r4, r0; addi r1, r1, -1 }
+       beqz r4, 2f
+       { bnezt r1, 1b; addi r0, r0, 1 }
+2:      { sub r0, r0, r3; jrp lr }
+       STD_ENDPROC(strnlen_user_asm)
+       .pushsection .fixup,"ax"
+strnlen_user_fault:
+       { move r0, zero; jrp lr }
+       ENDPROC(strnlen_user_fault)
+       .section __ex_table,"a"
+       .quad 1b, strnlen_user_fault
+       .popsection
+
+/*
+ * strncpy_from_user_asm takes the kernel target pointer in r0,
+ * the userspace source pointer in r1, and the length bound (including
+ * the trailing NUL) in r2.  On success, it returns the string length
+ * (not including the trailing NUL), or -EFAULT on failure.
+ */
+STD_ENTRY(strncpy_from_user_asm)
+       { beqz r2, 2f; move r3, r0 }
+1:      { ld1u r4, r1; addi r1, r1, 1; addi r2, r2, -1 }
+       { st1 r0, r4; addi r0, r0, 1 }
+       beqz r2, 2f
+       bnezt r4, 1b
+       addi r0, r0, -1   /* don't count the trailing NUL */
+2:      { sub r0, r0, r3; jrp lr }
+       STD_ENDPROC(strncpy_from_user_asm)
+       .pushsection .fixup,"ax"
+strncpy_from_user_fault:
+       { movei r0, -EFAULT; jrp lr }
+       ENDPROC(strncpy_from_user_fault)
+       .section __ex_table,"a"
+       .quad 1b, strncpy_from_user_fault
+       .popsection
+
+/*
+ * clear_user_asm takes the user target address in r0 and the
+ * number of bytes to zero in r1.
+ * It returns the number of uncopiable bytes (hopefully zero) in r0.
+ * Note that we don't use a separate .fixup section here since we fall
+ * through into the "fixup" code as the last straight-line bundle anyway.
+ */
+STD_ENTRY(clear_user_asm)
+       { beqz r1, 2f; or r2, r0, r1 }
+       andi r2, r2, 7
+       beqzt r2, .Lclear_aligned_user_asm
+1:      { st1 r0, zero; addi r0, r0, 1; addi r1, r1, -1 }
+       bnezt r1, 1b
+2:      { move r0, r1; jrp lr }
+       .pushsection __ex_table,"a"
+       .quad 1b, 2b
+       .popsection
+
+.Lclear_aligned_user_asm:
+1:      { st r0, zero; addi r0, r0, 8; addi r1, r1, -8 }
+       bnezt r1, 1b
+2:      { move r0, r1; jrp lr }
+       STD_ENDPROC(clear_user_asm)
+       .pushsection __ex_table,"a"
+       .quad 1b, 2b
+       .popsection
+
+/*
+ * flush_user_asm takes the user target address in r0 and the
+ * number of bytes to flush in r1.
+ * It returns the number of unflushable bytes (hopefully zero) in r0.
+ */
+STD_ENTRY(flush_user_asm)
+       beqz r1, 2f
+       { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
+       { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
+       { and r0, r0, r2; and r1, r1, r2 }
+       { sub r1, r1, r0 }
+1:      { flush r0; addi r1, r1, -CHIP_FLUSH_STRIDE() }
+       { addi r0, r0, CHIP_FLUSH_STRIDE(); bnezt r1, 1b }
+2:      { move r0, r1; jrp lr }
+       STD_ENDPROC(flush_user_asm)
+       .pushsection __ex_table,"a"
+       .quad 1b, 2b
+       .popsection
+
+/*
+ * inv_user_asm takes the user target address in r0 and the
+ * number of bytes to invalidate in r1.
+ * It returns the number of not inv'able bytes (hopefully zero) in r0.
+ */
+STD_ENTRY(inv_user_asm)
+       beqz r1, 2f
+       { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
+       { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
+       { and r0, r0, r2; and r1, r1, r2 }
+       { sub r1, r1, r0 }
+1:      { inv r0; addi r1, r1, -CHIP_INV_STRIDE() }
+       { addi r0, r0, CHIP_INV_STRIDE(); bnezt r1, 1b }
+2:      { move r0, r1; jrp lr }
+       STD_ENDPROC(inv_user_asm)
+       .pushsection __ex_table,"a"
+       .quad 1b, 2b
+       .popsection
+
+/*
+ * finv_user_asm takes the user target address in r0 and the
+ * number of bytes to flush-invalidate in r1.
+ * It returns the number of not finv'able bytes (hopefully zero) in r0.
+ */
+STD_ENTRY(finv_user_asm)
+       beqz r1, 2f
+       { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
+       { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
+       { and r0, r0, r2; and r1, r1, r2 }
+       { sub r1, r1, r0 }
+1:      { finv r0; addi r1, r1, -CHIP_FINV_STRIDE() }
+       { addi r0, r0, CHIP_FINV_STRIDE(); bnezt r1, 1b }
+2:      { move r0, r1; jrp lr }
+       STD_ENDPROC(finv_user_asm)
+       .pushsection __ex_table,"a"
+       .quad 1b, 2b
+       .popsection
index 51f8663bf0743e57765041fbedf3c6f1927e8a86..25b7b90fd62064b46cf6faf0204a7cbc78b28cc1 100644 (file)
 
 #include <arch/interrupts.h>
 
-static noinline void force_sig_info_fault(int si_signo, int si_code,
-       unsigned long address, int fault_num, struct task_struct *tsk)
+static noinline void force_sig_info_fault(const char *type, int si_signo,
+                                         int si_code, unsigned long address,
+                                         int fault_num,
+                                         struct task_struct *tsk,
+                                         struct pt_regs *regs)
 {
        siginfo_t info;
 
@@ -59,6 +62,7 @@ static noinline void force_sig_info_fault(int si_signo, int si_code,
        info.si_code = si_code;
        info.si_addr = (void __user *)address;
        info.si_trapno = fault_num;
+       trace_unhandled_signal(type, regs, address, si_signo);
        force_sig_info(si_signo, &info, tsk);
 }
 
@@ -71,11 +75,12 @@ SYSCALL_DEFINE2(cmpxchg_badaddr, unsigned long, address,
                struct pt_regs *, regs)
 {
        if (address >= PAGE_OFFSET)
-               force_sig_info_fault(SIGSEGV, SEGV_MAPERR, address,
-                                    INT_DTLB_MISS, current);
+               force_sig_info_fault("atomic segfault", SIGSEGV, SEGV_MAPERR,
+                                    address, INT_DTLB_MISS, current, regs);
        else
-               force_sig_info_fault(SIGBUS, BUS_ADRALN, address,
-                                    INT_UNALIGN_DATA, current);
+               force_sig_info_fault("atomic alignment fault", SIGBUS,
+                                    BUS_ADRALN, address,
+                                    INT_UNALIGN_DATA, current, regs);
 
        /*
         * Adjust pc to point at the actual instruction, which is unusual
@@ -471,8 +476,8 @@ bad_area_nosemaphore:
                 */
                local_irq_enable();
 
-               force_sig_info_fault(SIGSEGV, si_code, address,
-                                    fault_num, tsk);
+               force_sig_info_fault("segfault", SIGSEGV, si_code, address,
+                                    fault_num, tsk, regs);
                return 0;
        }
 
@@ -547,7 +552,8 @@ do_sigbus:
        if (is_kernel_mode)
                goto no_context;
 
-       force_sig_info_fault(SIGBUS, BUS_ADRERR, address, fault_num, tsk);
+       force_sig_info_fault("bus error", SIGBUS, BUS_ADRERR, address,
+                            fault_num, tsk, regs);
        return 0;
 }
 
@@ -732,6 +738,7 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
                panic("Bad fault number %d in do_page_fault", fault_num);
        }
 
+#if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC()
        if (EX1_PL(regs->ex1) != USER_PL) {
                struct async_tlb *async;
                switch (fault_num) {
@@ -775,6 +782,7 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
                        return;
                }
        }
+#endif
 
        handle_page_fault(regs, fault_num, is_page_fault, address, write);
 }
@@ -801,8 +809,6 @@ static void handle_async_page_fault(struct pt_regs *regs,
                                  async->address, async->is_write);
        }
 }
-#endif /* CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC() */
-
 
 /*
  * This routine effectively re-issues asynchronous page faults
@@ -824,6 +830,8 @@ void do_async_page_fault(struct pt_regs *regs)
        handle_async_page_fault(regs, &current->thread.sn_async_tlb);
 #endif
 }
+#endif /* CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC() */
+
 
 void vmalloc_sync_all(void)
 {
index d6e87fda2fb25d65449553253522f611a41d86bf..4e10c4023028181f9700143ab29738b8e0a10a84 100644 (file)
@@ -60,8 +60,6 @@ unsigned long VMALLOC_RESERVE = CONFIG_VMALLOC_RESERVE;
 EXPORT_SYMBOL(VMALLOC_RESERVE);
 #endif
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 /* Create an L2 page table */
 static pte_t * __init alloc_pte(void)
 {
diff --git a/arch/tile/mm/migrate_64.S b/arch/tile/mm/migrate_64.S
new file mode 100644 (file)
index 0000000..e76fea6
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * This routine is a helper for migrating the home of a set of pages to
+ * a new cpu.  See the documentation in homecache.c for more information.
+ */
+
+#include <linux/linkage.h>
+#include <linux/threads.h>
+#include <asm/page.h>
+#include <asm/thread_info.h>
+#include <asm/types.h>
+#include <asm/asm-offsets.h>
+#include <hv/hypervisor.h>
+
+       .text
+
+/*
+ * First, some definitions that apply to all the code in the file.
+ */
+
+/* Locals (caller-save) */
+#define r_tmp          r10
+#define r_save_sp      r11
+
+/* What we save where in the stack frame; must include all callee-saves. */
+#define FRAME_SP       8
+#define FRAME_R30      16
+#define FRAME_R31      24
+#define FRAME_R32      32
+#define FRAME_R33      40
+#define FRAME_SIZE     48
+
+
+
+
+/*
+ * On entry:
+ *
+ *   r0 the new context PA to install (moved to r_context)
+ *   r1 PTE to use for context access (moved to r_access)
+ *   r2 ASID to use for new context (moved to r_asid)
+ *   r3 pointer to cpumask with just this cpu set in it (r_my_cpumask)
+ */
+
+/* Arguments (caller-save) */
+#define r_context_in   r0
+#define r_access_in    r1
+#define r_asid_in      r2
+#define r_my_cpumask   r3
+
+/* Locals (callee-save); must not be more than FRAME_xxx above. */
+#define r_save_ics     r30
+#define r_context      r31
+#define r_access       r32
+#define r_asid         r33
+
+/*
+ * Caller-save locals and frame constants are the same as
+ * for homecache_migrate_stack_and_flush.
+ */
+
+STD_ENTRY(flush_and_install_context)
+       /*
+        * Create a stack frame; we can't touch it once we flush the
+        * cache until we install the new page table and flush the TLB.
+        */
+       {
+        move r_save_sp, sp
+        st sp, lr
+        addi sp, sp, -FRAME_SIZE
+       }
+       addi r_tmp, sp, FRAME_SP
+       {
+        st r_tmp, r_save_sp
+        addi r_tmp, sp, FRAME_R30
+       }
+       {
+        st r_tmp, r30
+        addi r_tmp, sp, FRAME_R31
+       }
+       {
+        st r_tmp, r31
+        addi r_tmp, sp, FRAME_R32
+       }
+       {
+        st r_tmp, r32
+        addi r_tmp, sp, FRAME_R33
+       }
+       st r_tmp, r33
+
+       /* Move some arguments to callee-save registers. */
+       {
+        move r_context, r_context_in
+        move r_access, r_access_in
+       }
+       move r_asid, r_asid_in
+
+       /* Disable interrupts, since we can't use our stack. */
+       {
+        mfspr r_save_ics, INTERRUPT_CRITICAL_SECTION
+        movei r_tmp, 1
+       }
+       mtspr INTERRUPT_CRITICAL_SECTION, r_tmp
+
+       /* First, flush our L2 cache. */
+       {
+        move r0, zero  /* cache_pa */
+        moveli r1, hw2_last(HV_FLUSH_EVICT_L2)  /* cache_control */
+       }
+       {
+        shl16insli r1, r1, hw1(HV_FLUSH_EVICT_L2)
+        move r2, r_my_cpumask  /* cache_cpumask */
+       }
+       {
+        shl16insli r1, r1, hw0(HV_FLUSH_EVICT_L2)
+        move r3, zero  /* tlb_va */
+       }
+       {
+        move r4, zero  /* tlb_length */
+        move r5, zero  /* tlb_pgsize */
+       }
+       {
+        move r6, zero  /* tlb_cpumask */
+        move r7, zero  /* asids */
+       }
+       {
+        move r8, zero  /* asidcount */
+        jal hv_flush_remote
+       }
+       bnez r0, 1f
+
+       /* Now install the new page table. */
+       {
+        move r0, r_context
+        move r1, r_access
+       }
+       {
+        move r2, r_asid
+        movei r3, HV_CTX_DIRECTIO
+       }
+       jal hv_install_context
+       bnez r0, 1f
+
+       /* Finally, flush the TLB. */
+       {
+        movei r0, 0   /* preserve_global */
+        jal hv_flush_all
+       }
+
+1:      /* Reset interrupts back how they were before. */
+       mtspr INTERRUPT_CRITICAL_SECTION, r_save_ics
+
+       /* Restore the callee-saved registers and return. */
+       addli lr, sp, FRAME_SIZE
+       {
+        ld lr, lr
+        addli r_tmp, sp, FRAME_R30
+       }
+       {
+        ld r30, r_tmp
+        addli r_tmp, sp, FRAME_R31
+       }
+       {
+        ld r31, r_tmp
+        addli r_tmp, sp, FRAME_R32
+       }
+       {
+        ld r32, r_tmp
+        addli r_tmp, sp, FRAME_R33
+       }
+       {
+        ld r33, r_tmp
+        addi sp, sp, FRAME_SIZE
+       }
+       jrp lr
+       STD_ENDPROC(flush_and_install_context)
index 8fce5e536b0fa7a268fb59657c7ddc3f99e5d568..68205fd3b08c844e0db9d182c54f9e718032780f 100644 (file)
@@ -28,13 +28,13 @@ config GCOV
          If you're involved in UML kernel development and want to use gcov,
          say Y.  If you're unsure, say N.
 
-config DEBUG_STACK_USAGE
-       bool "Stack utilization instrumentation"
-       default N
-       help
-         Track the maximum kernel stack usage - this will look at each
-         kernel stack at process exit and log it if it's the deepest
-         stack seen so far.
+config EARLY_PRINTK
+       bool "Early printk"
+       default y
+       ---help---
+         Write kernel log output directly to stdout.
+
+         This is useful for kernel debugging when your machine crashes very
+         early before the console code is initialized.
 
-         This option will slow down process creation and destruction somewhat.
 endmenu
index a9da516a527416e12cfdc887939e2eb8cbd5020f..8aae429a56e2d34690c24253fb1c3825fe1cf52a 100644 (file)
@@ -15,7 +15,6 @@ endmenu
 config UML_X86
        def_bool y
        select GENERIC_FIND_FIRST_BIT
-       select GENERIC_FIND_NEXT_BIT
 
 config 64BIT
        bool
@@ -29,10 +28,10 @@ config X86_64
        def_bool 64BIT
 
 config RWSEM_XCHGADD_ALGORITHM
-       def_bool X86_XADD
+       def_bool X86_XADD && 64BIT
 
 config RWSEM_GENERIC_SPINLOCK
-       def_bool !X86_XADD
+       def_bool !RWSEM_XCHGADD_ALGORITHM
 
 config 3_LEVEL_PGTABLES
        bool "Three-level pagetables (EXPERIMENTAL)" if !64BIT
index 1d9b6ae967b089c780afd713932af0bf42900468..e7582e1d248cc91796d94e2fcaa9a6f7b4ef62fc 100644 (file)
@@ -9,7 +9,7 @@
 slip-objs := slip_kern.o slip_user.o
 slirp-objs := slirp_kern.o slirp_user.o
 daemon-objs := daemon_kern.o daemon_user.o
-mcast-objs := mcast_kern.o mcast_user.o
+umcast-objs := umcast_kern.o umcast_user.o
 net-objs := net_kern.o net_user.o
 mconsole-objs := mconsole_kern.o mconsole_user.o
 hostaudio-objs := hostaudio_kern.o
@@ -44,7 +44,7 @@ obj-$(CONFIG_UML_NET_SLIP) += slip.o slip_common.o
 obj-$(CONFIG_UML_NET_SLIRP) += slirp.o slip_common.o
 obj-$(CONFIG_UML_NET_DAEMON) += daemon.o 
 obj-$(CONFIG_UML_NET_VDE) += vde.o
-obj-$(CONFIG_UML_NET_MCAST) += mcast.o 
+obj-$(CONFIG_UML_NET_MCAST) += umcast.o
 obj-$(CONFIG_UML_NET_PCAP) += pcap.o
 obj-$(CONFIG_UML_NET) += net.o 
 obj-$(CONFIG_MCONSOLE) += mconsole.o
diff --git a/arch/um/drivers/mcast.h b/arch/um/drivers/mcast.h
deleted file mode 100644 (file)
index 6fa282e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* 
- * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
- * Licensed under the GPL
- */
-
-#ifndef __DRIVERS_MCAST_H
-#define __DRIVERS_MCAST_H
-
-#include "net_user.h"
-
-struct mcast_data {
-       char *addr;
-       unsigned short port;
-       void *mcast_addr;
-       int ttl;
-       void *dev;
-};
-
-extern const struct net_user_info mcast_user_info;
-
-extern int mcast_user_write(int fd, void *buf, int len, 
-                           struct mcast_data *pri);
-
-#endif
diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c
deleted file mode 100644 (file)
index ffc6416..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * user-mode-linux networking multicast transport
- * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
- * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
- *
- * based on the existing uml-networking code, which is
- * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
- * James Leu (jleu@mindspring.net).
- * Copyright (C) 2001 by various other people who didn't put their name here.
- *
- * Licensed under the GPL.
- */
-
-#include "linux/init.h"
-#include <linux/netdevice.h>
-#include "mcast.h"
-#include "net_kern.h"
-
-struct mcast_init {
-       char *addr;
-       int port;
-       int ttl;
-};
-
-static void mcast_init(struct net_device *dev, void *data)
-{
-       struct uml_net_private *pri;
-       struct mcast_data *dpri;
-       struct mcast_init *init = data;
-
-       pri = netdev_priv(dev);
-       dpri = (struct mcast_data *) pri->user;
-       dpri->addr = init->addr;
-       dpri->port = init->port;
-       dpri->ttl = init->ttl;
-       dpri->dev = dev;
-
-       printk("mcast backend multicast address: %s:%u, TTL:%u\n",
-              dpri->addr, dpri->port, dpri->ttl);
-}
-
-static int mcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp)
-{
-       return net_recvfrom(fd, skb_mac_header(skb),
-                           skb->dev->mtu + ETH_HEADER_OTHER);
-}
-
-static int mcast_write(int fd, struct sk_buff *skb, struct uml_net_private *lp)
-{
-       return mcast_user_write(fd, skb->data, skb->len,
-                               (struct mcast_data *) &lp->user);
-}
-
-static const struct net_kern_info mcast_kern_info = {
-       .init                   = mcast_init,
-       .protocol               = eth_protocol,
-       .read                   = mcast_read,
-       .write                  = mcast_write,
-};
-
-static int mcast_setup(char *str, char **mac_out, void *data)
-{
-       struct mcast_init *init = data;
-       char *port_str = NULL, *ttl_str = NULL, *remain;
-       char *last;
-
-       *init = ((struct mcast_init)
-               { .addr         = "239.192.168.1",
-                 .port         = 1102,
-                 .ttl          = 1 });
-
-       remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str,
-                              NULL);
-       if (remain != NULL) {
-               printk(KERN_ERR "mcast_setup - Extra garbage on "
-                      "specification : '%s'\n", remain);
-               return 0;
-       }
-
-       if (port_str != NULL) {
-               init->port = simple_strtoul(port_str, &last, 10);
-               if ((*last != '\0') || (last == port_str)) {
-                       printk(KERN_ERR "mcast_setup - Bad port : '%s'\n",
-                              port_str);
-                       return 0;
-               }
-       }
-
-       if (ttl_str != NULL) {
-               init->ttl = simple_strtoul(ttl_str, &last, 10);
-               if ((*last != '\0') || (last == ttl_str)) {
-                       printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n",
-                              ttl_str);
-                       return 0;
-               }
-       }
-
-       printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr,
-              init->port, init->ttl);
-
-       return 1;
-}
-
-static struct transport mcast_transport = {
-       .list           = LIST_HEAD_INIT(mcast_transport.list),
-       .name           = "mcast",
-       .setup          = mcast_setup,
-       .user           = &mcast_user_info,
-       .kern           = &mcast_kern_info,
-       .private_size   = sizeof(struct mcast_data),
-       .setup_size     = sizeof(struct mcast_init),
-};
-
-static int register_mcast(void)
-{
-       register_transport(&mcast_transport);
-       return 0;
-}
-
-late_initcall(register_mcast);
diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
deleted file mode 100644 (file)
index ee19e91..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * user-mode-linux networking multicast transport
- * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
- * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
- *
- * based on the existing uml-networking code, which is
- * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
- * James Leu (jleu@mindspring.net).
- * Copyright (C) 2001 by various other people who didn't put their name here.
- *
- * Licensed under the GPL.
- *
- */
-
-#include <unistd.h>
-#include <errno.h>
-#include <netinet/in.h>
-#include "kern_constants.h"
-#include "mcast.h"
-#include "net_user.h"
-#include "um_malloc.h"
-#include "user.h"
-
-static struct sockaddr_in *new_addr(char *addr, unsigned short port)
-{
-       struct sockaddr_in *sin;
-
-       sin = uml_kmalloc(sizeof(struct sockaddr_in), UM_GFP_KERNEL);
-       if (sin == NULL) {
-               printk(UM_KERN_ERR "new_addr: allocation of sockaddr_in "
-                      "failed\n");
-               return NULL;
-       }
-       sin->sin_family = AF_INET;
-       sin->sin_addr.s_addr = in_aton(addr);
-       sin->sin_port = htons(port);
-       return sin;
-}
-
-static int mcast_user_init(void *data, void *dev)
-{
-       struct mcast_data *pri = data;
-
-       pri->mcast_addr = new_addr(pri->addr, pri->port);
-       pri->dev = dev;
-       return 0;
-}
-
-static void mcast_remove(void *data)
-{
-       struct mcast_data *pri = data;
-
-       kfree(pri->mcast_addr);
-       pri->mcast_addr = NULL;
-}
-
-static int mcast_open(void *data)
-{
-       struct mcast_data *pri = data;
-       struct sockaddr_in *sin = pri->mcast_addr;
-       struct ip_mreq mreq;
-       int fd, yes = 1, err = -EINVAL;
-
-
-       if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0))
-               goto out;
-
-       fd = socket(AF_INET, SOCK_DGRAM, 0);
-
-       if (fd < 0) {
-               err = -errno;
-               printk(UM_KERN_ERR "mcast_open : data socket failed, "
-                      "errno = %d\n", errno);
-               goto out;
-       }
-
-       if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
-               err = -errno;
-               printk(UM_KERN_ERR "mcast_open: SO_REUSEADDR failed, "
-                      "errno = %d\n", errno);
-               goto out_close;
-       }
-
-       /* set ttl according to config */
-       if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
-                      sizeof(pri->ttl)) < 0) {
-               err = -errno;
-               printk(UM_KERN_ERR "mcast_open: IP_MULTICAST_TTL failed, "
-                      "error = %d\n", errno);
-               goto out_close;
-       }
-
-       /* set LOOP, so data does get fed back to local sockets */
-       if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
-               err = -errno;
-               printk(UM_KERN_ERR "mcast_open: IP_MULTICAST_LOOP failed, "
-                      "error = %d\n", errno);
-               goto out_close;
-       }
-
-       /* bind socket to mcast address */
-       if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
-               err = -errno;
-               printk(UM_KERN_ERR "mcast_open : data bind failed, "
-                      "errno = %d\n", errno);
-               goto out_close;
-       }
-
-       /* subscribe to the multicast group */
-       mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
-       mreq.imr_interface.s_addr = 0;
-       if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP,
-                      &mreq, sizeof(mreq)) < 0) {
-               err = -errno;
-               printk(UM_KERN_ERR "mcast_open: IP_ADD_MEMBERSHIP failed, "
-                      "error = %d\n", errno);
-               printk(UM_KERN_ERR "There appears not to be a multicast-"
-                      "capable network interface on the host.\n");
-               printk(UM_KERN_ERR "eth0 should be configured in order to use "
-                      "the multicast transport.\n");
-               goto out_close;
-       }
-
-       return fd;
-
- out_close:
-       close(fd);
- out:
-       return err;
-}
-
-static void mcast_close(int fd, void *data)
-{
-       struct ip_mreq mreq;
-       struct mcast_data *pri = data;
-       struct sockaddr_in *sin = pri->mcast_addr;
-
-       mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
-       mreq.imr_interface.s_addr = 0;
-       if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP,
-                      &mreq, sizeof(mreq)) < 0) {
-               printk(UM_KERN_ERR "mcast_open: IP_DROP_MEMBERSHIP failed, "
-                      "error = %d\n", errno);
-       }
-
-       close(fd);
-}
-
-int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri)
-{
-       struct sockaddr_in *data_addr = pri->mcast_addr;
-
-       return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr));
-}
-
-const struct net_user_info mcast_user_info = {
-       .init           = mcast_user_init,
-       .open           = mcast_open,
-       .close          = mcast_close,
-       .remove         = mcast_remove,
-       .add_address    = NULL,
-       .delete_address = NULL,
-       .mtu            = ETH_MAX_PACKET,
-       .max_packet     = ETH_MAX_PACKET + ETH_HEADER_OTHER,
-};
diff --git a/arch/um/drivers/umcast.h b/arch/um/drivers/umcast.h
new file mode 100644 (file)
index 0000000..6f8c0fe
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __DRIVERS_UMCAST_H
+#define __DRIVERS_UMCAST_H
+
+#include "net_user.h"
+
+struct umcast_data {
+       char *addr;
+       unsigned short lport;
+       unsigned short rport;
+       void *listen_addr;
+       void *remote_addr;
+       int ttl;
+       int unicast;
+       void *dev;
+};
+
+extern const struct net_user_info umcast_user_info;
+
+extern int umcast_user_write(int fd, void *buf, int len,
+                            struct umcast_data *pri);
+
+#endif
diff --git a/arch/um/drivers/umcast_kern.c b/arch/um/drivers/umcast_kern.c
new file mode 100644 (file)
index 0000000..42dab11
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * user-mode-linux networking multicast transport
+ * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ *
+ * based on the existing uml-networking code, which is
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ *
+ * Licensed under the GPL.
+ */
+
+#include "linux/init.h"
+#include <linux/netdevice.h>
+#include "umcast.h"
+#include "net_kern.h"
+
+struct umcast_init {
+       char *addr;
+       int lport;
+       int rport;
+       int ttl;
+       bool unicast;
+};
+
+static void umcast_init(struct net_device *dev, void *data)
+{
+       struct uml_net_private *pri;
+       struct umcast_data *dpri;
+       struct umcast_init *init = data;
+
+       pri = netdev_priv(dev);
+       dpri = (struct umcast_data *) pri->user;
+       dpri->addr = init->addr;
+       dpri->lport = init->lport;
+       dpri->rport = init->rport;
+       dpri->unicast = init->unicast;
+       dpri->ttl = init->ttl;
+       dpri->dev = dev;
+
+       if (dpri->unicast) {
+               printk(KERN_INFO "ucast backend address: %s:%u listen port: "
+                      "%u\n", dpri->addr, dpri->rport, dpri->lport);
+       } else {
+               printk(KERN_INFO "mcast backend multicast address: %s:%u, "
+                      "TTL:%u\n", dpri->addr, dpri->lport, dpri->ttl);
+       }
+}
+
+static int umcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp)
+{
+       return net_recvfrom(fd, skb_mac_header(skb),
+                           skb->dev->mtu + ETH_HEADER_OTHER);
+}
+
+static int umcast_write(int fd, struct sk_buff *skb, struct uml_net_private *lp)
+{
+       return umcast_user_write(fd, skb->data, skb->len,
+                               (struct umcast_data *) &lp->user);
+}
+
+static const struct net_kern_info umcast_kern_info = {
+       .init                   = umcast_init,
+       .protocol               = eth_protocol,
+       .read                   = umcast_read,
+       .write                  = umcast_write,
+};
+
+static int mcast_setup(char *str, char **mac_out, void *data)
+{
+       struct umcast_init *init = data;
+       char *port_str = NULL, *ttl_str = NULL, *remain;
+       char *last;
+
+       *init = ((struct umcast_init)
+               { .addr = "239.192.168.1",
+                 .lport        = 1102,
+                 .ttl  = 1 });
+
+       remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str,
+                              NULL);
+       if (remain != NULL) {
+               printk(KERN_ERR "mcast_setup - Extra garbage on "
+                      "specification : '%s'\n", remain);
+               return 0;
+       }
+
+       if (port_str != NULL) {
+               init->lport = simple_strtoul(port_str, &last, 10);
+               if ((*last != '\0') || (last == port_str)) {
+                       printk(KERN_ERR "mcast_setup - Bad port : '%s'\n",
+                              port_str);
+                       return 0;
+               }
+       }
+
+       if (ttl_str != NULL) {
+               init->ttl = simple_strtoul(ttl_str, &last, 10);
+               if ((*last != '\0') || (last == ttl_str)) {
+                       printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n",
+                              ttl_str);
+                       return 0;
+               }
+       }
+
+       init->unicast = false;
+       init->rport = init->lport;
+
+       printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr,
+              init->lport, init->ttl);
+
+       return 1;
+}
+
+static int ucast_setup(char *str, char **mac_out, void *data)
+{
+       struct umcast_init *init = data;
+       char *lport_str = NULL, *rport_str = NULL, *remain;
+       char *last;
+
+       *init = ((struct umcast_init)
+               { .addr         = "",
+                 .lport        = 1102,
+                 .rport        = 1102 });
+
+       remain = split_if_spec(str, mac_out, &init->addr,
+                              &lport_str, &rport_str, NULL);
+       if (remain != NULL) {
+               printk(KERN_ERR "ucast_setup - Extra garbage on "
+                      "specification : '%s'\n", remain);
+               return 0;
+       }
+
+       if (lport_str != NULL) {
+               init->lport = simple_strtoul(lport_str, &last, 10);
+               if ((*last != '\0') || (last == lport_str)) {
+                       printk(KERN_ERR "ucast_setup - Bad listen port : "
+                              "'%s'\n", lport_str);
+                       return 0;
+               }
+       }
+
+       if (rport_str != NULL) {
+               init->rport = simple_strtoul(rport_str, &last, 10);
+               if ((*last != '\0') || (last == rport_str)) {
+                       printk(KERN_ERR "ucast_setup - Bad remote port : "
+                              "'%s'\n", rport_str);
+                       return 0;
+               }
+       }
+
+       init->unicast = true;
+
+       printk(KERN_INFO "Configured ucast device: :%u -> %s:%u\n",
+              init->lport, init->addr, init->rport);
+
+       return 1;
+}
+
+static struct transport mcast_transport = {
+       .list   = LIST_HEAD_INIT(mcast_transport.list),
+       .name   = "mcast",
+       .setup  = mcast_setup,
+       .user   = &umcast_user_info,
+       .kern   = &umcast_kern_info,
+       .private_size   = sizeof(struct umcast_data),
+       .setup_size     = sizeof(struct umcast_init),
+};
+
+static struct transport ucast_transport = {
+       .list   = LIST_HEAD_INIT(ucast_transport.list),
+       .name   = "ucast",
+       .setup  = ucast_setup,
+       .user   = &umcast_user_info,
+       .kern   = &umcast_kern_info,
+       .private_size   = sizeof(struct umcast_data),
+       .setup_size     = sizeof(struct umcast_init),
+};
+
+static int register_umcast(void)
+{
+       register_transport(&mcast_transport);
+       register_transport(&ucast_transport);
+       return 0;
+}
+
+late_initcall(register_umcast);
diff --git a/arch/um/drivers/umcast_user.c b/arch/um/drivers/umcast_user.c
new file mode 100644 (file)
index 0000000..59c56fd
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * user-mode-linux networking multicast transport
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
+ *
+ * based on the existing uml-networking code, which is
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ *
+ * Licensed under the GPL.
+ *
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include "kern_constants.h"
+#include "umcast.h"
+#include "net_user.h"
+#include "um_malloc.h"
+#include "user.h"
+
+static struct sockaddr_in *new_addr(char *addr, unsigned short port)
+{
+       struct sockaddr_in *sin;
+
+       sin = uml_kmalloc(sizeof(struct sockaddr_in), UM_GFP_KERNEL);
+       if (sin == NULL) {
+               printk(UM_KERN_ERR "new_addr: allocation of sockaddr_in "
+                      "failed\n");
+               return NULL;
+       }
+       sin->sin_family = AF_INET;
+       if (addr)
+               sin->sin_addr.s_addr = in_aton(addr);
+       else
+               sin->sin_addr.s_addr = INADDR_ANY;
+       sin->sin_port = htons(port);
+       return sin;
+}
+
+static int umcast_user_init(void *data, void *dev)
+{
+       struct umcast_data *pri = data;
+
+       pri->remote_addr = new_addr(pri->addr, pri->rport);
+       if (pri->unicast)
+               pri->listen_addr = new_addr(NULL, pri->lport);
+       else
+               pri->listen_addr = pri->remote_addr;
+       pri->dev = dev;
+       return 0;
+}
+
+static void umcast_remove(void *data)
+{
+       struct umcast_data *pri = data;
+
+       kfree(pri->listen_addr);
+       if (pri->unicast)
+               kfree(pri->remote_addr);
+       pri->listen_addr = pri->remote_addr = NULL;
+}
+
+static int umcast_open(void *data)
+{
+       struct umcast_data *pri = data;
+       struct sockaddr_in *lsin = pri->listen_addr;
+       struct sockaddr_in *rsin = pri->remote_addr;
+       struct ip_mreq mreq;
+       int fd, yes = 1, err = -EINVAL;
+
+
+       if ((!pri->unicast && lsin->sin_addr.s_addr == 0) ||
+           (rsin->sin_addr.s_addr == 0) ||
+           (lsin->sin_port == 0) || (rsin->sin_port == 0))
+               goto out;
+
+       fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+       if (fd < 0) {
+               err = -errno;
+               printk(UM_KERN_ERR "umcast_open : data socket failed, "
+                      "errno = %d\n", errno);
+               goto out;
+       }
+
+       if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
+               err = -errno;
+               printk(UM_KERN_ERR "umcast_open: SO_REUSEADDR failed, "
+                      "errno = %d\n", errno);
+               goto out_close;
+       }
+
+       if (!pri->unicast) {
+               /* set ttl according to config */
+               if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
+                              sizeof(pri->ttl)) < 0) {
+                       err = -errno;
+                       printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_TTL "
+                              "failed, error = %d\n", errno);
+                       goto out_close;
+               }
+
+               /* set LOOP, so data does get fed back to local sockets */
+               if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP,
+                              &yes, sizeof(yes)) < 0) {
+                       err = -errno;
+                       printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_LOOP "
+                              "failed, error = %d\n", errno);
+                       goto out_close;
+               }
+       }
+
+       /* bind socket to the address */
+       if (bind(fd, (struct sockaddr *) lsin, sizeof(*lsin)) < 0) {
+               err = -errno;
+               printk(UM_KERN_ERR "umcast_open : data bind failed, "
+                      "errno = %d\n", errno);
+               goto out_close;
+       }
+
+       if (!pri->unicast) {
+               /* subscribe to the multicast group */
+               mreq.imr_multiaddr.s_addr = lsin->sin_addr.s_addr;
+               mreq.imr_interface.s_addr = 0;
+               if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP,
+                              &mreq, sizeof(mreq)) < 0) {
+                       err = -errno;
+                       printk(UM_KERN_ERR "umcast_open: IP_ADD_MEMBERSHIP "
+                              "failed, error = %d\n", errno);
+                       printk(UM_KERN_ERR "There appears not to be a "
+                              "multicast-capable network interface on the "
+                              "host.\n");
+                       printk(UM_KERN_ERR "eth0 should be configured in order "
+                              "to use the multicast transport.\n");
+                       goto out_close;
+               }
+       }
+
+       return fd;
+
+ out_close:
+       close(fd);
+ out:
+       return err;
+}
+
+static void umcast_close(int fd, void *data)
+{
+       struct umcast_data *pri = data;
+
+       if (!pri->unicast) {
+               struct ip_mreq mreq;
+               struct sockaddr_in *lsin = pri->listen_addr;
+
+               mreq.imr_multiaddr.s_addr = lsin->sin_addr.s_addr;
+               mreq.imr_interface.s_addr = 0;
+               if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP,
+                              &mreq, sizeof(mreq)) < 0) {
+                       printk(UM_KERN_ERR "umcast_close: IP_DROP_MEMBERSHIP "
+                              "failed, error = %d\n", errno);
+               }
+       }
+
+       close(fd);
+}
+
+int umcast_user_write(int fd, void *buf, int len, struct umcast_data *pri)
+{
+       struct sockaddr_in *data_addr = pri->remote_addr;
+
+       return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr));
+}
+
+const struct net_user_info umcast_user_info = {
+       .init   = umcast_user_init,
+       .open   = umcast_open,
+       .close  = umcast_close,
+       .remove = umcast_remove,
+       .add_address    = NULL,
+       .delete_address = NULL,
+       .mtu    = ETH_MAX_PACKET,
+       .max_packet     = ETH_MAX_PACKET + ETH_HEADER_OTHER,
+};
index da2caa5a21efa91333ffd44c9c7743b467ec3f26..8ac7146c237f69ae9052397767c23140055512f3 100644 (file)
@@ -90,7 +90,7 @@ static int xterm_open(int input, int output, int primary, void *d,
        int pid, fd, new, err;
        char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
        char *argv[] = { terminal_emulator, title_switch, title, exec_switch,
-                        "/usr/lib/uml/port-helper", "-uml-socket",
+                        OS_LIB_PATH "/uml/port-helper", "-uml-socket",
                         file, NULL };
 
        if (access(argv[4], X_OK) < 0)
index 34bede8aad4a9ca9c23df9261be3a7c3d8ac20ec..4938de5512d20add327d2865e9c60ce6fb21181a 100644 (file)
@@ -42,7 +42,7 @@
        INIT_SETUP(0)
   }
 
-  PERCPU(32, 32)
+  PERCPU_SECTION(32)
        
   .initcall.init : {
        INIT_CALLS
index d1d1b0d8a0cd9c66d754243f636425e4c942ee46..98d01bc4fa92f1267062645e31c9b632f74e2339 100644 (file)
@@ -14,6 +14,8 @@ struct task_struct;
 #include "registers.h"
 #include "sysdep/archsetjmp.h"
 
+#include <linux/prefetch.h>
+
 struct mm_struct;
 
 struct thread_struct {
index f27a963131741ba935f80ec424c9b4c413ae63d4..4a4b09d4f36648c0bf85724aa9533d9890403a07 100644 (file)
@@ -11,7 +11,6 @@
 
 #define cpu_logical_map(n) (n)
 #define cpu_number_map(n) (n)
-#define PROC_CHANGE_PENALTY    15 /* Pick a number, any number */
 extern int hard_smp_processor_id(void);
 #define NO_PROC_ID -1
 
index 660caedac9eb70bb3314beb5b1e87a3d3e876bef..4febacd1a8a1a3dee2c24e3b3447081e7ca94ebb 100644 (file)
@@ -22,9 +22,6 @@ struct mmu_gather {
        unsigned int            fullmm; /* non-zero means full mm flush */
 };
 
-/* Users of the generic TLB shootdown code must declare this storage space. */
-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep,
                                          unsigned long address)
 {
@@ -47,27 +44,20 @@ static inline void init_tlb_gather(struct mmu_gather *tlb)
        }
 }
 
-/* tlb_gather_mmu
- *     Return a pointer to an initialized struct mmu_gather.
- */
-static inline struct mmu_gather *
-tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
+static inline void
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int full_mm_flush)
 {
-       struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
-
        tlb->mm = mm;
        tlb->fullmm = full_mm_flush;
 
        init_tlb_gather(tlb);
-
-       return tlb;
 }
 
 extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
                               unsigned long end);
 
 static inline void
-tlb_flush_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
+tlb_flush_mmu(struct mmu_gather *tlb)
 {
        if (!tlb->need_flush)
                return;
@@ -83,12 +73,10 @@ tlb_flush_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
 static inline void
 tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
 {
-       tlb_flush_mmu(tlb, start, end);
+       tlb_flush_mmu(tlb);
 
        /* keep the page table cache within bounds */
        check_pgt_cache();
-
-       put_cpu_var(mmu_gathers);
 }
 
 /* tlb_remove_page
@@ -96,11 +84,16 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
  *     while handling the additional races in SMP caused by other CPUs
  *     caching valid mappings in their TLBs.
  */
-static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
 {
        tlb->need_flush = 1;
        free_page_and_swap_cache(page);
-       return;
+       return 1; /* avoid calling tlb_flush_mmu */
+}
+
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       __tlb_remove_page(tlb, page);
 }
 
 /**
index c4617baaa4f2752a84a3cb20fa517e326e5ebaa7..83c7c2ecd61422b7fccd054e79597bad10d4f9a7 100644 (file)
 #define OS_ACC_R_OK    4       /* Test for read permission.  */
 #define OS_ACC_RW_OK   (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */
 
+#ifdef CONFIG_64BIT
+#define OS_LIB_PATH    "/usr/lib64/"
+#else
+#define OS_LIB_PATH    "/usr/lib/"
+#endif
+
 /*
  * types taken from stat_file() in hostfs_user.c
  * (if they are wrong here, they are wrong there...).
@@ -238,6 +244,7 @@ extern int raw(int fd);
 extern void setup_machinename(char *machine_out);
 extern void setup_hostinfo(char *buf, int len);
 extern void os_dump_core(void) __attribute__ ((noreturn));
+extern void um_early_printk(const char *s, unsigned int n);
 
 /* time.c */
 extern void idle_sleep(unsigned long long nsecs);
index 1119233597a1eb2f3ac26a22bb4a05183f32b9d9..c4491c15afb213064995f3aa490d2a749a39f8d3 100644 (file)
@@ -17,6 +17,7 @@ obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \
 obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
 obj-$(CONFIG_GPROF)    += gprof_syms.o
 obj-$(CONFIG_GCOV)     += gmon_syms.o
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
 
 USER_OBJS := config.o
 
diff --git a/arch/um/kernel/early_printk.c b/arch/um/kernel/early_printk.c
new file mode 100644 (file)
index 0000000..ec649bf
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 Richard Weinberger <richrd@nod.at>
+ *
+ * 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/console.h>
+#include <linux/init.h>
+#include "os.h"
+
+static void early_console_write(struct console *con, const char *s, unsigned int n)
+{
+       um_early_printk(s, n);
+}
+
+static struct console early_console = {
+       .name = "earlycon",
+       .write = early_console_write,
+       .flags = CON_BOOT,
+       .index = -1,
+};
+
+static int __init setup_early_printk(char *buf)
+{
+       register_console(&early_console);
+
+       return 0;
+}
+
+early_param("earlyprintk", setup_early_printk);
index eefb107d2d734856c376f973913a29ddf18acae7..155206a6690879da2e6521c7604d74ad8f9e52a0 100644 (file)
@@ -7,9 +7,6 @@
 #include "asm/pgalloc.h"
 #include "asm/tlb.h"
 
-/* For some reason, mmu_gathers are referenced when CONFIG_SMP is off. */
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 #ifdef CONFIG_SMP
 
 #include "linux/sched.h"
index 637c6505dc00de1ce482335023bff8227aedaaa1..8c7b8823d1f0e1257f3a410620048bbd3556d95b 100644 (file)
@@ -113,6 +113,27 @@ out_of_memory:
        return 0;
 }
 
+static void show_segv_info(struct uml_pt_regs *regs)
+{
+       struct task_struct *tsk = current;
+       struct faultinfo *fi = UPT_FAULTINFO(regs);
+
+       if (!unhandled_signal(tsk, SIGSEGV))
+               return;
+
+       if (!printk_ratelimit())
+               return;
+
+       printk("%s%s[%d]: segfault at %lx ip %p sp %p error %x",
+               task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
+               tsk->comm, task_pid_nr(tsk), FAULT_ADDRESS(*fi),
+               (void *)UPT_IP(regs), (void *)UPT_SP(regs),
+               fi->error_code);
+
+       print_vma_addr(KERN_CONT " in ", UPT_IP(regs));
+       printk(KERN_CONT "\n");
+}
+
 static void bad_segv(struct faultinfo fi, unsigned long ip)
 {
        struct siginfo si;
@@ -141,6 +162,7 @@ void segv_handler(int sig, struct uml_pt_regs *regs)
        struct faultinfo * fi = UPT_FAULTINFO(regs);
 
        if (UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)) {
+               show_segv_info(regs);
                bad_segv(*fi, UPT_IP(regs));
                return;
        }
@@ -202,6 +224,8 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
                      address, ip);
        }
 
+       show_segv_info(regs);
+
        if (err == -EACCES) {
                si.si_signo = SIGBUS;
                si.si_errno = 0;
index eee69b9f52c92bfd355303fd72b5afbf70502d7e..fb2a97a75fb1b799966785ad8694d08b9f13508b 100644 (file)
@@ -78,7 +78,7 @@ static void install_fatal_handler(int sig)
        }
 }
 
-#define UML_LIB_PATH   ":/usr/lib/uml"
+#define UML_LIB_PATH   ":" OS_LIB_PATH "/uml"
 
 static void setup_env_path(void)
 {
@@ -142,7 +142,6 @@ int __init main(int argc, char **argv, char **envp)
         */
        install_fatal_handler(SIGINT);
        install_fatal_handler(SIGTERM);
-       install_fatal_handler(SIGHUP);
 
        scan_elf_aux(envp);
 
index e0477c3ee89448f72320b01a493a97cb280ecad6..0c45dc8efb055243d9259da46f702760b773ce11 100644 (file)
@@ -253,6 +253,7 @@ void init_new_thread_signals(void)
                    SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGALRM,
                    SIGVTALRM, -1);
        signal(SIGWINCH, SIG_IGN);
+       signal(SIGTERM, SIG_DFL);
 }
 
 int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr)
index 42827cafa6af3ac72f4c57d62e08968b81360faa..5803b188767213eb1a60399c594677a661547287 100644 (file)
@@ -139,3 +139,8 @@ void os_dump_core(void)
 
        uml_abort();
 }
+
+void um_early_printk(const char *s, unsigned int n)
+{
+       printf("%.*s", n, s);
+}
index d3a303246c9f0967ff1ac86e9359eded8fae15da..e57dcce9bfda4da6ea6be362a542bf891289f0c0 100644 (file)
@@ -231,10 +231,6 @@ config PUV3_PWM
        help
          Enable support for NB0916 PWM controllers
 
-config PUV3_RTC
-       tristate "PKUnity v3 RTC Support"
-       depends on !ARCH_FPGA
-
 if PUV3_NB0916
 
 menu "PKUnity NetBook-0916 Features"
index 3140151ede4502f537bd39ed37b99d2767a945f8..ae2ec334c3c61473ffa6b7b5cf8695c8d64c322b 100644 (file)
@@ -27,13 +27,6 @@ config EARLY_PRINTK
          with klogd/syslogd or the X server. You should normally N here,
          unless you want to debug such a crash.
 
-config DEBUG_STACK_USAGE
-       bool "Enable stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T output.
-
 # These options are only for real kernel hackers who want to get their hands dirty.
 config DEBUG_LL
        bool "Kernel low-level debugging functions"
index 76a8beec7d03e454d49e9da70a6c6dbc734566ef..6af4bc415f2b34ec19fc024c1242a470a4feef73 100644 (file)
@@ -40,42 +40,10 @@ core-y                      += arch/unicore32/mm/
 
 libs-y                 += arch/unicore32/lib/
 
-ASM_GENERATED_DIR      := $(srctree)/arch/unicore32/include/generated
-LINUXINCLUDE           += -I$(ASM_GENERATED_DIR)
-
-ASM_GENERIC_HEADERS    := atomic.h auxvec.h
-ASM_GENERIC_HEADERS    += bitsperlong.h bug.h bugs.h
-ASM_GENERIC_HEADERS    += cputime.h current.h
-ASM_GENERIC_HEADERS    += device.h div64.h
-ASM_GENERIC_HEADERS    += emergency-restart.h errno.h
-ASM_GENERIC_HEADERS    += fb.h fcntl.h ftrace.h futex.h
-ASM_GENERIC_HEADERS    += hardirq.h hw_irq.h
-ASM_GENERIC_HEADERS    += ioctl.h ioctls.h ipcbuf.h irq_regs.h
-ASM_GENERIC_HEADERS    += kdebug.h kmap_types.h
-ASM_GENERIC_HEADERS    += local.h
-ASM_GENERIC_HEADERS    += mman.h module.h msgbuf.h
-ASM_GENERIC_HEADERS    += param.h parport.h percpu.h poll.h posix_types.h
-ASM_GENERIC_HEADERS    += resource.h
-ASM_GENERIC_HEADERS    += scatterlist.h sections.h segment.h sembuf.h serial.h
-ASM_GENERIC_HEADERS    += setup.h shmbuf.h shmparam.h
-ASM_GENERIC_HEADERS    += siginfo.h signal.h sizes.h
-ASM_GENERIC_HEADERS    += socket.h sockios.h stat.h statfs.h swab.h syscalls.h
-ASM_GENERIC_HEADERS    += termbits.h termios.h topology.h types.h
-ASM_GENERIC_HEADERS    += ucontext.h unaligned.h user.h
-ASM_GENERIC_HEADERS    += vga.h
-ASM_GENERIC_HEADERS    += xor.h
-
-archprepare:
-ifneq ($(ASM_GENERATED_DIR), $(wildcard $(ASM_GENERATED_DIR)))
-       $(Q)mkdir -p $(ASM_GENERATED_DIR)/asm
-       $(Q)$(foreach a, $(ASM_GENERIC_HEADERS),        \
-               echo '#include <asm-generic/$a>'        \
-                       > $(ASM_GENERATED_DIR)/asm/$a; )
-endif
-
 boot                   := arch/unicore32/boot
 
-# Default target when executing plain make
+# Default defconfig and target when executing plain make
+KBUILD_DEFCONFIG       := $(ARCH)_defconfig
 KBUILD_IMAGE           := zImage
 
 all:   $(KBUILD_IMAGE)
@@ -83,8 +51,6 @@ all:  $(KBUILD_IMAGE)
 zImage Image uImage: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
 
-MRPROPER_DIRS          += $(ASM_GENERATED_DIR)
-
 archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
 
index 95373428cb3d846029312a737669c5a522895c8e..b0954a2d23cfaf5b4db0bbe1b6e95493d75ebc03 100644 (file)
@@ -59,7 +59,7 @@ $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/head.o $(obj)/piggy.o \
 # We now have a PIC decompressor implementation.  Decompressors running
 # from RAM should not define ZTEXTADDR.  Decompressors running directly
 # from ROM or Flash must define ZTEXTADDR (preferably via the config)
-ZTEXTADDR      := 0
+ZTEXTADDR      := 0x03000000
 ZBSSADDR       := ALIGN(4)
 
 SEDFLAGS_lds   = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/
similarity index 97%
rename from arch/unicore32/configs/debug_defconfig
rename to arch/unicore32/configs/unicore32_defconfig
index b5fbde9f1cb2cf8623e911178916e7595b6acbde..c9dd3198b6f701d3e07b50c81528fb240da7b9ca 100644 (file)
@@ -1,6 +1,6 @@
 ### General setup
 CONFIG_EXPERIMENTAL=y
-CONFIG_LOCALVERSION="-debug"
+CONFIG_LOCALVERSION="-unicore32"
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
@@ -64,7 +64,6 @@ CONFIG_I2C_BATTERY_BQ27200=n
 CONFIG_I2C_EEPROM_AT24=n
 CONFIG_LCD_BACKLIGHT=n
 
-CONFIG_PUV3_RTC=y
 CONFIG_PUV3_UMAL=y
 CONFIG_PUV3_MUSB=n
 CONFIG_PUV3_AC97=n
@@ -167,8 +166,9 @@ CONFIG_LEDS_TRIGGER_IDE_DISK=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 
 #      Real Time Clock
-CONFIG_RTC_LIB=m
-CONFIG_RTC_CLASS=m
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_PUV3=y
 
 ### File systems
 CONFIG_EXT2_FS=m
index b200fdaca44de8061175e02d95c47c58489abc0b..ca113d6999c5279df35ad1d47a275ace8fd18463 100644 (file)
@@ -1,2 +1,61 @@
 include include/asm-generic/Kbuild.asm
 
+generic-y += atomic.h
+generic-y += auxvec.h
+generic-y += bitsperlong.h
+generic-y += bug.h
+generic-y += bugs.h
+generic-y += cputime.h
+generic-y += current.h
+generic-y += device.h
+generic-y += div64.h
+generic-y += emergency-restart.h
+generic-y += errno.h
+generic-y += fb.h
+generic-y += fcntl.h
+generic-y += ftrace.h
+generic-y += futex.h
+generic-y += hardirq.h
+generic-y += hw_irq.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += irq_regs.h
+generic-y += kdebug.h
+generic-y += kmap_types.h
+generic-y += local.h
+generic-y += mman.h
+generic-y += module.h
+generic-y += msgbuf.h
+generic-y += param.h
+generic-y += parport.h
+generic-y += percpu.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += resource.h
+generic-y += scatterlist.h
+generic-y += sections.h
+generic-y += segment.h
+generic-y += sembuf.h
+generic-y += serial.h
+generic-y += setup.h
+generic-y += shmbuf.h
+generic-y += shmparam.h
+generic-y += siginfo.h
+generic-y += signal.h
+generic-y += sizes.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += stat.h
+generic-y += statfs.h
+generic-y += swab.h
+generic-y += syscalls.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += topology.h
+generic-y += types.h
+generic-y += ucontext.h
+generic-y += unaligned.h
+generic-y += user.h
+generic-y += vga.h
+generic-y += xor.h
index 88a9c0f32b219677e38eb1eb6b817861ec8edc37..65bad75c7e96d0706f51bb16fcdcb9615e86b435 100644 (file)
@@ -14,7 +14,6 @@
 #define __UNICORE_SUSPEND_H__
 
 #ifndef __ASSEMBLY__
-static inline int arch_prepare_suspend(void) { return 0; }
 
 #include <asm/ptrace.h>
 
index ec23a2fb2f508646d38c76ce7bbd89ed20bc8168..aeb0f181568e39f5537f70d7078163c09f29c2cb 100644 (file)
@@ -16,7 +16,6 @@ obj-$(CONFIG_UNICORE_FPU_F64) += fpu-ucf64.o
 obj-$(CONFIG_ARCH_PUV3)                += clock.o irq.o time.o
 
 obj-$(CONFIG_PUV3_GPIO)                += gpio.o
-obj-$(CONFIG_PUV3_RTC)         += rtc.o
 obj-$(CONFIG_PUV3_PWM)         += pwm.o
 obj-$(CONFIG_PUV3_PM)          += pm.o sleep.o
 obj-$(CONFIG_HIBERNATION)      += hibernate.o hibernate_asm.o
index 9bf7f7af52c529f10566dbf8a9a816ecf0b65567..77e407e49a632c84cfb4957580c13dfbbebd1df4 100644 (file)
@@ -30,7 +30,7 @@ SECTIONS
        HEAD_TEXT_SECTION
        INIT_TEXT_SECTION(PAGE_SIZE)
        INIT_DATA_SECTION(16)
-       PERCPU(L1_CACHE_BYTES, PAGE_SIZE)
+       PERCPU_SECTION(L1_CACHE_BYTES)
        __init_end = .;
 
        _stext = .;
index 1fc02633f700a18af47db8e61a85cd55c0210d80..2d3e7112d2a3cbce8d778770e35754ac5a34e753 100644 (file)
@@ -62,7 +62,7 @@ void show_mem(unsigned int filter)
        struct meminfo *mi = &meminfo;
 
        printk(KERN_DEFAULT "Mem-info:\n");
-       show_free_areas();
+       show_free_areas(filter);
 
        for_each_bank(i, mi) {
                struct membank *bank = &mi->bank[i];
index db2d334941b41dd7d1527107ab08bf6e03e98e1a..3e5c3e5a0b4542a99cb1e6bda573ab3dfc002dcc 100644 (file)
@@ -30,8 +30,6 @@
 
 #include "mm.h"
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 /*
  * empty_zero_page is a special page that is used for
  * zero-initialized data and COW.
index 880fcb6c86f484c602afa6bbcfb436d48647f8c9..da349723d4115cef7d75aac4680ba2284deaf0d0 100644 (file)
@@ -17,8 +17,6 @@ config X86_64
 config X86
        def_bool y
        select HAVE_AOUT if X86_32
-       select HAVE_READQ
-       select HAVE_WRITEQ
        select HAVE_UNSTABLE_SCHED_CLOCK
        select HAVE_IDE
        select HAVE_OPROFILE
@@ -66,7 +64,6 @@ config X86
        select HAVE_GENERIC_HARDIRQS
        select HAVE_SPARSE_IRQ
        select GENERIC_FIND_FIRST_BIT
-       select GENERIC_FIND_NEXT_BIT
        select GENERIC_IRQ_PROBE
        select GENERIC_PENDING_IRQ if SMP
        select GENERIC_IRQ_SHOW
@@ -917,6 +914,7 @@ config TOSHIBA
 
 config I8K
        tristate "Dell laptop support"
+       select HWMON
        ---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 615e18810f4856e500b7964ffbfe82c78a843b20..c0f8a5c889107bf80ab45eaf33468e5120ee6a56 100644 (file)
@@ -66,26 +66,6 @@ config DEBUG_STACKOVERFLOW
          This option will cause messages to be printed if free stack space
          drops below a certain limit.
 
-config DEBUG_STACK_USAGE
-       bool "Stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       ---help---
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T and sysrq-P debug output.
-
-         This option will slow down process creation somewhat.
-
-config DEBUG_PER_CPU_MAPS
-       bool "Debug access to per_cpu maps"
-       depends on DEBUG_KERNEL
-       depends on SMP
-       ---help---
-         Say Y to verify that the per_cpu map being accessed has
-         been setup.  Adds a fair amount of code to kernel memory
-         and decreases performance.
-
-         Say N if unsure.
-
 config X86_PTDUMP
        bool "Export kernel pagetable layout to userspace via debugfs"
        depends on DEBUG_KERNEL
index 6f9872658dd2d66e80d8025eb7f8c40ee86b958f..2bf18059fbea710667d4636477b41a21a1fb1571 100644 (file)
@@ -10,7 +10,6 @@ CONFIG_TASK_IO_ACCOUNTING=y
 CONFIG_AUDIT=y
 CONFIG_LOG_BUF_SHIFT=18
 CONFIG_CGROUPS=y
-CONFIG_CGROUP_NS=y
 CONFIG_CGROUP_FREEZER=y
 CONFIG_CPUSETS=y
 CONFIG_CGROUP_CPUACCT=y
index ee01a9d5d4f0a7b8e3bd9f6e4f86fb28e7fe2b68..22a0dc8e51dd4196e43acdab23d9a3e32513e167 100644 (file)
@@ -11,7 +11,6 @@ CONFIG_TASK_IO_ACCOUNTING=y
 CONFIG_AUDIT=y
 CONFIG_LOG_BUF_SHIFT=18
 CONFIG_CGROUPS=y
-CONFIG_CGROUP_NS=y
 CONFIG_CGROUP_FREEZER=y
 CONFIG_CPUSETS=y
 CONFIG_CGROUP_CPUACCT=y
index 95f5826be458a4a1368d45bc1cd6c81342d660b9..c1870dddd3223ee39b344ebb6d385a96236aa00e 100644 (file)
@@ -849,4 +849,5 @@ ia32_sys_call_table:
        .quad compat_sys_clock_adjtime
        .quad sys_syncfs
        .quad compat_sys_sendmmsg       /* 345 */
+       .quad sys_setns
 ia32_syscall_end:
index 416d865eae39bdb5eecb670aeaeffdc2a3f2bd21..610001d385dd466c48394873c972e3430b7789ba 100644 (file)
@@ -139,7 +139,7 @@ static inline unsigned int acpi_processor_cstate_check(unsigned int max_cstate)
            boot_cpu_data.x86_model <= 0x05 &&
            boot_cpu_data.x86_mask < 0x0A)
                return 1;
-       else if (c1e_detected)
+       else if (amd_e400_c1e_detected)
                return 1;
        else
                return max_cstate;
index 5dc6acc98dbde7a1bed021ead6386644d47f3ff3..71cc3800712ca09caba33cd508e457ee017280e2 100644 (file)
 #define X86_FEATURE_OSXSAVE    (4*32+27) /* "" XSAVE enabled in the OS */
 #define X86_FEATURE_AVX                (4*32+28) /* Advanced Vector Extensions */
 #define X86_FEATURE_F16C       (4*32+29) /* 16-bit fp conversions */
-#define X86_FEATURE_RDRND      (4*32+30) /* The RDRAND instruction */
+#define X86_FEATURE_RDRAND     (4*32+30) /* The RDRAND instruction */
 #define X86_FEATURE_HYPERVISOR (4*32+31) /* Running on a hypervisor */
 
 /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
index 617bd56b3070d0ac570b752c73f52311e2fb68d1..7b439d9aea2a5c30a22f1f3b8ba17db7f4011a39 100644 (file)
@@ -4,30 +4,33 @@
 #include <asm/desc_defs.h>
 #include <asm/ldt.h>
 #include <asm/mmu.h>
+
 #include <linux/smp.h>
 
-static inline void fill_ldt(struct desc_struct *desc,
-                           const struct user_desc *info)
-{
-       desc->limit0 = info->limit & 0x0ffff;
-       desc->base0 = info->base_addr & 0x0000ffff;
-
-       desc->base1 = (info->base_addr & 0x00ff0000) >> 16;
-       desc->type = (info->read_exec_only ^ 1) << 1;
-       desc->type |= info->contents << 2;
-       desc->s = 1;
-       desc->dpl = 0x3;
-       desc->p = info->seg_not_present ^ 1;
-       desc->limit = (info->limit & 0xf0000) >> 16;
-       desc->avl = info->useable;
-       desc->d = info->seg_32bit;
-       desc->g = info->limit_in_pages;
-       desc->base2 = (info->base_addr & 0xff000000) >> 24;
+static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *info)
+{
+       desc->limit0            = info->limit & 0x0ffff;
+
+       desc->base0             = (info->base_addr & 0x0000ffff);
+       desc->base1             = (info->base_addr & 0x00ff0000) >> 16;
+
+       desc->type              = (info->read_exec_only ^ 1) << 1;
+       desc->type             |= info->contents << 2;
+
+       desc->s                 = 1;
+       desc->dpl               = 0x3;
+       desc->p                 = info->seg_not_present ^ 1;
+       desc->limit             = (info->limit & 0xf0000) >> 16;
+       desc->avl               = info->useable;
+       desc->d                 = info->seg_32bit;
+       desc->g                 = info->limit_in_pages;
+
+       desc->base2             = (info->base_addr & 0xff000000) >> 24;
        /*
         * Don't allow setting of the lm bit. It is useless anyway
         * because 64bit system calls require __USER_CS:
         */
-       desc->l = 0;
+       desc->l                 = 0;
 }
 
 extern struct desc_ptr idt_descr;
@@ -36,6 +39,7 @@ extern gate_desc idt_table[];
 struct gdt_page {
        struct desc_struct gdt[GDT_ENTRIES];
 } __attribute__((aligned(PAGE_SIZE)));
+
 DECLARE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page);
 
 static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu)
@@ -48,16 +52,16 @@ static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu)
 static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func,
                             unsigned dpl, unsigned ist, unsigned seg)
 {
-       gate->offset_low = PTR_LOW(func);
-       gate->segment = __KERNEL_CS;
-       gate->ist = ist;
-       gate->p = 1;
-       gate->dpl = dpl;
-       gate->zero0 = 0;
-       gate->zero1 = 0;
-       gate->type = type;
-       gate->offset_middle = PTR_MIDDLE(func);
-       gate->offset_high = PTR_HIGH(func);
+       gate->offset_low        = PTR_LOW(func);
+       gate->segment           = __KERNEL_CS;
+       gate->ist               = ist;
+       gate->p                 = 1;
+       gate->dpl               = dpl;
+       gate->zero0             = 0;
+       gate->zero1             = 0;
+       gate->type              = type;
+       gate->offset_middle     = PTR_MIDDLE(func);
+       gate->offset_high       = PTR_HIGH(func);
 }
 
 #else
@@ -66,8 +70,7 @@ static inline void pack_gate(gate_desc *gate, unsigned char type,
                             unsigned short seg)
 {
        gate->a = (seg << 16) | (base & 0xffff);
-       gate->b = (base & 0xffff0000) |
-                 (((0x80 | type | (dpl << 5)) & 0xff) << 8);
+       gate->b = (base & 0xffff0000) | (((0x80 | type | (dpl << 5)) & 0xff) << 8);
 }
 
 #endif
@@ -75,31 +78,29 @@ static inline void pack_gate(gate_desc *gate, unsigned char type,
 static inline int desc_empty(const void *ptr)
 {
        const u32 *desc = ptr;
+
        return !(desc[0] | desc[1]);
 }
 
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else
-#define load_TR_desc() native_load_tr_desc()
-#define load_gdt(dtr) native_load_gdt(dtr)
-#define load_idt(dtr) native_load_idt(dtr)
-#define load_tr(tr) asm volatile("ltr %0"::"m" (tr))
-#define load_ldt(ldt) asm volatile("lldt %0"::"m" (ldt))
-
-#define store_gdt(dtr) native_store_gdt(dtr)
-#define store_idt(dtr) native_store_idt(dtr)
-#define store_tr(tr) (tr = native_store_tr())
-
-#define load_TLS(t, cpu) native_load_tls(t, cpu)
-#define set_ldt native_set_ldt
-
-#define write_ldt_entry(dt, entry, desc)       \
-       native_write_ldt_entry(dt, entry, desc)
-#define write_gdt_entry(dt, entry, desc, type)         \
-       native_write_gdt_entry(dt, entry, desc, type)
-#define write_idt_entry(dt, entry, g)          \
-       native_write_idt_entry(dt, entry, g)
+#define load_TR_desc()                         native_load_tr_desc()
+#define load_gdt(dtr)                          native_load_gdt(dtr)
+#define load_idt(dtr)                          native_load_idt(dtr)
+#define load_tr(tr)                            asm volatile("ltr %0"::"m" (tr))
+#define load_ldt(ldt)                          asm volatile("lldt %0"::"m" (ldt))
+
+#define store_gdt(dtr)                         native_store_gdt(dtr)
+#define store_idt(dtr)                         native_store_idt(dtr)
+#define store_tr(tr)                           (tr = native_store_tr())
+
+#define load_TLS(t, cpu)                       native_load_tls(t, cpu)
+#define set_ldt                                        native_set_ldt
+
+#define write_ldt_entry(dt, entry, desc)       native_write_ldt_entry(dt, entry, desc)
+#define write_gdt_entry(dt, entry, desc, type) native_write_gdt_entry(dt, entry, desc, type)
+#define write_idt_entry(dt, entry, g)          native_write_idt_entry(dt, entry, g)
 
 static inline void paravirt_alloc_ldt(struct desc_struct *ldt, unsigned entries)
 {
@@ -112,33 +113,27 @@ static inline void paravirt_free_ldt(struct desc_struct *ldt, unsigned entries)
 
 #define store_ldt(ldt) asm("sldt %0" : "=m"(ldt))
 
-static inline void native_write_idt_entry(gate_desc *idt, int entry,
-                                         const gate_desc *gate)
+static inline void native_write_idt_entry(gate_desc *idt, int entry, const gate_desc *gate)
 {
        memcpy(&idt[entry], gate, sizeof(*gate));
 }
 
-static inline void native_write_ldt_entry(struct desc_struct *ldt, int entry,
-                                         const void *desc)
+static inline void native_write_ldt_entry(struct desc_struct *ldt, int entry, const void *desc)
 {
        memcpy(&ldt[entry], desc, 8);
 }
 
-static inline void native_write_gdt_entry(struct desc_struct *gdt, int entry,
-                                         const void *desc, int type)
+static inline void
+native_write_gdt_entry(struct desc_struct *gdt, int entry, const void *desc, int type)
 {
        unsigned int size;
+
        switch (type) {
-       case DESC_TSS:
-               size = sizeof(tss_desc);
-               break;
-       case DESC_LDT:
-               size = sizeof(ldt_desc);
-               break;
-       default:
-               size = sizeof(struct desc_struct);
-               break;
+       case DESC_TSS:  size = sizeof(tss_desc);        break;
+       case DESC_LDT:  size = sizeof(ldt_desc);        break;
+       default:        size = sizeof(*gdt);            break;
        }
+
        memcpy(&gdt[entry], desc, size);
 }
 
@@ -154,20 +149,21 @@ static inline void pack_descriptor(struct desc_struct *desc, unsigned long base,
 }
 
 
-static inline void set_tssldt_descriptor(void *d, unsigned long addr,
-                                        unsigned type, unsigned size)
+static inline void set_tssldt_descriptor(void *d, unsigned long addr, unsigned type, unsigned size)
 {
 #ifdef CONFIG_X86_64
        struct ldttss_desc64 *desc = d;
+
        memset(desc, 0, sizeof(*desc));
-       desc->limit0 = size & 0xFFFF;
-       desc->base0 = PTR_LOW(addr);
-       desc->base1 = PTR_MIDDLE(addr) & 0xFF;
-       desc->type = type;
-       desc->p = 1;
-       desc->limit1 = (size >> 16) & 0xF;
-       desc->base2 = (PTR_MIDDLE(addr) >> 8) & 0xFF;
-       desc->base3 = PTR_HIGH(addr);
+
+       desc->limit0            = size & 0xFFFF;
+       desc->base0             = PTR_LOW(addr);
+       desc->base1             = PTR_MIDDLE(addr) & 0xFF;
+       desc->type              = type;
+       desc->p                 = 1;
+       desc->limit1            = (size >> 16) & 0xF;
+       desc->base2             = (PTR_MIDDLE(addr) >> 8) & 0xFF;
+       desc->base3             = PTR_HIGH(addr);
 #else
        pack_descriptor((struct desc_struct *)d, addr, size, 0x80 | type, 0);
 #endif
@@ -237,14 +233,16 @@ static inline void native_store_idt(struct desc_ptr *dtr)
 static inline unsigned long native_store_tr(void)
 {
        unsigned long tr;
+
        asm volatile("str %0":"=r" (tr));
+
        return tr;
 }
 
 static inline void native_load_tls(struct thread_struct *t, unsigned int cpu)
 {
-       unsigned int i;
        struct desc_struct *gdt = get_cpu_gdt_table(cpu);
+       unsigned int i;
 
        for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++)
                gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i];
@@ -313,6 +311,7 @@ static inline void _set_gate(int gate, unsigned type, void *addr,
                             unsigned dpl, unsigned ist, unsigned seg)
 {
        gate_desc s;
+
        pack_gate(&s, type, (unsigned long)addr, dpl, ist, seg);
        /*
         * does not need to be atomic because it is only done once at
@@ -343,8 +342,9 @@ static inline void alloc_system_vector(int vector)
                set_bit(vector, used_vectors);
                if (first_system_vector > vector)
                        first_system_vector = vector;
-       } else
+       } else {
                BUG();
+       }
 }
 
 static inline void alloc_intr_gate(unsigned int n, void *addr)
index 38d87379e270596635ff569242c54ff71ad3ce69..f49253d75710e90bd31a86956d941b0cfb289940 100644 (file)
@@ -16,6 +16,6 @@ static inline void enter_idle(void) { }
 static inline void exit_idle(void) { }
 #endif /* CONFIG_X86_64 */
 
-void c1e_remove_cpu(int cpu);
+void amd_e400_remove_cpu(int cpu);
 
 #endif /* _ASM_X86_IDLE_H */
index 072273082528c3bcff89ca88d9d98e26567c38df..d02804d650c4596aa4644a8fccb75ba72d387548 100644 (file)
@@ -38,7 +38,6 @@
 
 #include <linux/string.h>
 #include <linux/compiler.h>
-#include <asm-generic/int-ll64.h>
 #include <asm/page.h>
 
 #include <xen/xen.h>
@@ -87,27 +86,6 @@ build_mmio_write(__writel, "l", unsigned int, "r", )
 build_mmio_read(readq, "q", unsigned long, "=r", :"memory")
 build_mmio_write(writeq, "q", unsigned long, "r", :"memory")
 
-#else
-
-static inline __u64 readq(const volatile void __iomem *addr)
-{
-       const volatile u32 __iomem *p = addr;
-       u32 low, high;
-
-       low = readl(p);
-       high = readl(p + 1);
-
-       return low + ((u64)high << 32);
-}
-
-static inline void writeq(__u64 val, volatile void __iomem *addr)
-{
-       writel(val, addr);
-       writel(val >> 32, addr+4);
-}
-
-#endif
-
 #define readq_relaxed(a)       readq(a)
 
 #define __raw_readq(a)         readq(a)
@@ -117,6 +95,8 @@ static inline void writeq(__u64 val, volatile void __iomem *addr)
 #define readq                  readq
 #define writeq                 writeq
 
+#endif
+
 /**
  *     virt_to_phys    -       map virtual addresses to physical
  *     @address: address to remap
index 396f5b5fc4d714e4babdb916565731264a312ec8..77e95f54570a9728816055df2e6c562e1a608ccc 100644 (file)
@@ -77,6 +77,7 @@ static inline void arch_kgdb_breakpoint(void)
 }
 #define BREAK_INSTR_SIZE       1
 #define CACHE_FLUSH_IS_SAFE    1
+#define GDB_ADJUSTS_BREAK_OFFSET
 
 extern int kgdb_ll_trap(int cmd, const char *str,
                        struct pt_regs *regs, long err, int trap, int sig);
index 12d55e773eb605ff85c67c8cbf8d453697e01871..48142971b25d095b9724a06a6eff47b2cf302532 100644 (file)
@@ -8,11 +8,6 @@
 
 #ifdef CONFIG_X86_32
 #define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
-/*
- * For 32-bit UML - mark functions implemented in assembly that use
- * regparm input parameters:
- */
-#define asmregparm __attribute__((regparm(3)))
 
 /*
  * Make sure the compiler doesn't do anything stupid with the
index 19ae14ba69780c38defd3fbcfe7fdcb05859f9c0..0cd3800f33b9dcf68e39a1288ebf7ccd442f3a97 100644 (file)
@@ -4,7 +4,6 @@
 #define ARCH_DISCARD_MEMBLOCK
 
 u64 memblock_x86_find_in_range_size(u64 start, u64 *sizep, u64 align);
-void memblock_x86_to_bootmem(u64 start, u64 end);
 
 void memblock_x86_reserve_range(u64 start, u64 end, char *name);
 void memblock_x86_free_range(u64 start, u64 end);
@@ -19,5 +18,6 @@ u64 memblock_x86_hole_size(u64 start, u64 end);
 u64 memblock_x86_find_in_range_node(int nid, u64 start, u64 end, u64 size, u64 align);
 u64 memblock_x86_free_memory_in_range(u64 addr, u64 limit);
 u64 memblock_x86_memory_in_range(u64 addr, u64 limit);
+bool memblock_x86_check_reserved_size(u64 *addrp, u64 *sizep, u64 align);
 
 #endif
index aeff3e89b222edc08d31f122dc7008a0cc8466a9..5f55e69627692f9a353355bbb426ef8bf73fc44c 100644 (file)
 typedef struct {
        void *ldt;
        int size;
-       struct mutex lock;
-       void *vdso;
 
 #ifdef CONFIG_X86_64
        /* True if mm supports a task running in 32 bit compatibility mode. */
        unsigned short ia32_compat;
 #endif
 
+       struct mutex lock;
+       void *vdso;
 } mm_context_t;
 
 #ifdef CONFIG_SMP
index 53278b0dfdf660103f8f9c234b0d97691ae48611..a0a9779084d16ec7b9e11b03d6435026428817dc 100644 (file)
@@ -509,6 +509,11 @@ do {                                                                       \
  * it in software.  The address used in the cmpxchg16 instruction must be
  * aligned to a 16 byte boundary.
  */
+#ifdef CONFIG_SMP
+#define CMPXCHG16B_EMU_CALL "call this_cpu_cmpxchg16b_emu\n\t" ASM_NOP3
+#else
+#define CMPXCHG16B_EMU_CALL "call this_cpu_cmpxchg16b_emu\n\t" ASM_NOP2
+#endif
 #define percpu_cmpxchg16b_double(pcp1, o1, o2, n1, n2)                 \
 ({                                                                     \
        char __ret;                                                     \
@@ -517,7 +522,7 @@ do {                                                                        \
        typeof(o2) __o2 = o2;                                           \
        typeof(o2) __n2 = n2;                                           \
        typeof(o2) __dummy;                                             \
-       alternative_io("call this_cpu_cmpxchg16b_emu\n\t" ASM_NOP4,     \
+       alternative_io(CMPXCHG16B_EMU_CALL,                             \
                       "cmpxchg16b " __percpu_prefix "(%%rsi)\n\tsetz %0\n\t",  \
                       X86_FEATURE_CX16,                                \
                       ASM_OUTPUT2("=a"(__ret), "=d"(__dummy)),         \
index 4c25ab48257bf8043639d87cc557f04ab2ad263a..219371546afd343ddeb39a1f3018ce0e5c6cfc31 100644 (file)
@@ -754,10 +754,10 @@ static inline void __sti_mwait(unsigned long eax, unsigned long ecx)
 extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx);
 
 extern void select_idle_routine(const struct cpuinfo_x86 *c);
-extern void init_c1e_mask(void);
+extern void init_amd_e400_c1e_mask(void);
 
 extern unsigned long           boot_option_idle_override;
-extern bool                    c1e_detected;
+extern bool                    amd_e400_c1e_detected;
 
 enum idle_boot_override {IDLE_NO_OVERRIDE=0, IDLE_HALT, IDLE_NOMWAIT,
                         IDLE_POLL, IDLE_FORCE_MWAIT};
index 1babf8adecdf624840f60915f19169754e9967f0..94e7618fcac8d6fb8bd61c1b356b522187b1218a 100644 (file)
@@ -136,6 +136,7 @@ struct cpuinfo_x86;
 struct task_struct;
 
 extern unsigned long profile_pc(struct pt_regs *regs);
+#define profile_pc profile_pc
 
 extern unsigned long
 convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs);
@@ -202,20 +203,11 @@ static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
 #endif
 }
 
-static inline unsigned long instruction_pointer(struct pt_regs *regs)
-{
-       return regs->ip;
-}
-
-static inline unsigned long frame_pointer(struct pt_regs *regs)
-{
-       return regs->bp;
-}
+#define GET_IP(regs) ((regs)->ip)
+#define GET_FP(regs) ((regs)->bp)
+#define GET_USP(regs) ((regs)->sp)
 
-static inline unsigned long user_stack_pointer(struct pt_regs *regs)
-{
-       return regs->sp;
-}
+#include <asm-generic/ptrace.h>
 
 /* Query offset/name of register from its name/offset */
 extern int regs_query_register_offset(const char *name);
index 31d84acc15125646018914b51a758821ec796590..a518c0a4504465e6ac46068ba6d34a68d66a6fd3 100644 (file)
@@ -22,6 +22,8 @@ static inline u64 pvclock_scale_delta(u64 delta, u32 mul_frac, int shift)
        u64 product;
 #ifdef __i386__
        u32 tmp1, tmp2;
+#else
+       ulong tmp;
 #endif
 
        if (shift < 0)
@@ -42,8 +44,11 @@ static inline u64 pvclock_scale_delta(u64 delta, u32 mul_frac, int shift)
                : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
 #elif defined(__x86_64__)
        __asm__ (
-               "mul %%rdx ; shrd $32,%%rdx,%%rax"
-               : "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
+               "mul %[mul_frac] ; shrd $32, %[hi], %[lo]"
+               : [lo]"=a"(product),
+                 [hi]"=d"(tmp)
+               : "0"(delta),
+                 [mul_frac]"rm"((u64)mul_frac));
 #else
 #error implement me!
 #endif
index fd921c3a68414e341fe8fffa8b1df1326eba2ba7..487055c8c1aaf2d63bbf2b0d8bcfcdd5d616c721 100644 (file)
@@ -9,8 +9,6 @@
 #include <asm/desc.h>
 #include <asm/i387.h>
 
-static inline int arch_prepare_suspend(void) { return 0; }
-
 /* image of the saved processor state */
 struct saved_context {
        u16 es, fs, gs, ss;
index 8d942afae681bec8fe2c47a9bf57955dbc4317b0..09b0bf104156579ae49f72b17c603befcf2db5a6 100644 (file)
@@ -9,11 +9,6 @@
 #include <asm/desc.h>
 #include <asm/i387.h>
 
-static inline int arch_prepare_suspend(void)
-{
-       return 0;
-}
-
 /*
  * Image of the saved processor state, used by the low level ACPI suspend to
  * RAM code and by the low level hibernation code.
index 83e2efd181e27c8d5e9430fe8e52a30c022faf5c..9db5583b6d38ff781611c5b20b812115de28cba2 100644 (file)
@@ -51,6 +51,10 @@ extern int unsynchronized_tsc(void);
 extern int check_tsc_unstable(void);
 extern unsigned long native_calibrate_tsc(void);
 
+#ifdef CONFIG_X86_64
+extern cycles_t vread_tsc(void);
+#endif
+
 /*
  * Boot-time check whether the TSCs are synchronized across
  * all CPUs/cores:
index fb6a625c99bf622449d2378f3815d1d363453029..593485b38ab38cc501e3f975209aabfb3f710106 100644 (file)
 #define __NR_clock_adjtime     343
 #define __NR_syncfs             344
 #define __NR_sendmmsg          345
+#define __NR_setns             346
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 346
+#define NR_syscalls 347
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 79f90eb15aad0f6c882f136b359506f9bcbc93e6..705bf139288c1f8014b3b9d9389d01f606740153 100644 (file)
@@ -679,6 +679,8 @@ __SYSCALL(__NR_clock_adjtime, sys_clock_adjtime)
 __SYSCALL(__NR_syncfs, sys_syncfs)
 #define __NR_sendmmsg                          307
 __SYSCALL(__NR_sendmmsg, sys_sendmmsg)
+#define __NR_setns                             308
+__SYSCALL(__NR_setns, sys_setns)
 
 #ifndef __NO_STUBS
 #define __ARCH_WANT_OLD_READDIR
index 130f1eeee5fed416bb41ed4fa54a97bdcc31a601..a291c40efd4360ec47150d7b9874d5965b97ad7f 100644 (file)
@@ -5,7 +5,7 @@
  *
  * SGI UV Broadcast Assist Unit definitions
  *
- * Copyright (C) 2008 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2008-2011 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_X86_UV_UV_BAU_H
 
 #define MAX_CPUS_PER_UVHUB             64
 #define MAX_CPUS_PER_SOCKET            32
-#define UV_ADP_SIZE                    64 /* hardware-provided max. */
-#define UV_CPUS_PER_ACT_STATUS         32 /* hardware-provided max. */
-#define UV_ITEMS_PER_DESCRIPTOR                8
+#define ADP_SZ                         64 /* hardware-provided max. */
+#define UV_CPUS_PER_AS                 32 /* hardware-provided max. */
+#define ITEMS_PER_DESC                 8
 /* the 'throttle' to prevent the hardware stay-busy bug */
 #define MAX_BAU_CONCURRENT             3
 #define UV_ACT_STATUS_MASK             0x3
 #define UV_ACT_STATUS_SIZE             2
 #define UV_DISTRIBUTION_SIZE           256
 #define UV_SW_ACK_NPENDING             8
-#define UV_NET_ENDPOINT_INTD           0x38
-#define UV_DESC_BASE_PNODE_SHIFT       49
+#define UV1_NET_ENDPOINT_INTD          0x38
+#define UV2_NET_ENDPOINT_INTD          0x28
+#define UV_NET_ENDPOINT_INTD           (is_uv1_hub() ?                 \
+                       UV1_NET_ENDPOINT_INTD : UV2_NET_ENDPOINT_INTD)
+#define UV_DESC_PSHIFT                 49
 #define UV_PAYLOADQ_PNODE_SHIFT                49
 #define UV_PTC_BASENAME                        "sgi_uv/ptc_statistics"
 #define UV_BAU_BASENAME                        "sgi_uv/bau_tunables"
 #define UV_BAU_TUNABLES_FILE           "bau_tunables"
 #define WHITESPACE                     " \t\n"
 #define uv_physnodeaddr(x)             ((__pa((unsigned long)(x)) & uv_mmask))
-#define UV_ENABLE_INTD_SOFT_ACK_MODE_SHIFT 15
-#define UV_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHIFT 16
-#define UV_INTD_SOFT_ACK_TIMEOUT_PERIOD 0x0000000009UL
+#define cpubit_isset(cpu, bau_local_cpumask) \
+       test_bit((cpu), (bau_local_cpumask).bits)
+
 /* [19:16] SOFT_ACK timeout period  19: 1 is urgency 7  17:16 1 is multiplier */
-#define BAU_MISC_CONTROL_MULT_MASK 3
+/*
+ * UV2: Bit 19 selects between
+ *  (0): 10 microsecond timebase and
+ *  (1): 80 microseconds
+ *  we're using 655us, similar to UV1: 65 units of 10us
+ */
+#define UV1_INTD_SOFT_ACK_TIMEOUT_PERIOD (9UL)
+#define UV2_INTD_SOFT_ACK_TIMEOUT_PERIOD (65*10UL)
+
+#define UV_INTD_SOFT_ACK_TIMEOUT_PERIOD        (is_uv1_hub() ?                 \
+               UV1_INTD_SOFT_ACK_TIMEOUT_PERIOD :                      \
+               UV2_INTD_SOFT_ACK_TIMEOUT_PERIOD)
 
-#define UVH_AGING_PRESCALE_SEL 0x000000b000UL
+#define BAU_MISC_CONTROL_MULT_MASK     3
+
+#define UVH_AGING_PRESCALE_SEL         0x000000b000UL
 /* [30:28] URGENCY_7  an index into a table of times */
-#define BAU_URGENCY_7_SHIFT 28
-#define BAU_URGENCY_7_MASK 7
+#define BAU_URGENCY_7_SHIFT            28
+#define BAU_URGENCY_7_MASK             7
 
-#define UVH_TRANSACTION_TIMEOUT 0x000000b200UL
+#define UVH_TRANSACTION_TIMEOUT                0x000000b200UL
 /* [45:40] BAU - BAU transaction timeout select - a multiplier */
-#define BAU_TRANS_SHIFT 40
-#define BAU_TRANS_MASK 0x3f
+#define BAU_TRANS_SHIFT                        40
+#define BAU_TRANS_MASK                 0x3f
+
+/*
+ * shorten some awkward names
+ */
+#define AS_PUSH_SHIFT UVH_LB_BAU_SB_ACTIVATION_CONTROL_PUSH_SHFT
+#define SOFTACK_MSHIFT UVH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT
+#define SOFTACK_PSHIFT UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT
+#define SOFTACK_TIMEOUT_PERIOD UV_INTD_SOFT_ACK_TIMEOUT_PERIOD
+#define write_gmmr     uv_write_global_mmr64
+#define write_lmmr     uv_write_local_mmr
+#define read_lmmr      uv_read_local_mmr
+#define read_gmmr      uv_read_global_mmr64
 
 /*
  * bits in UVH_LB_BAU_SB_ACTIVATION_STATUS_0/1
  */
-#define DESC_STATUS_IDLE               0
-#define DESC_STATUS_ACTIVE             1
-#define DESC_STATUS_DESTINATION_TIMEOUT        2
-#define DESC_STATUS_SOURCE_TIMEOUT     3
+#define DS_IDLE                                0
+#define DS_ACTIVE                      1
+#define DS_DESTINATION_TIMEOUT         2
+#define DS_SOURCE_TIMEOUT              3
+/*
+ * bits put together from HRP_LB_BAU_SB_ACTIVATION_STATUS_0/1/2
+ * values 1 and 5 will not occur
+ */
+#define UV2H_DESC_IDLE                 0
+#define UV2H_DESC_DEST_TIMEOUT         2
+#define UV2H_DESC_DEST_STRONG_NACK     3
+#define UV2H_DESC_BUSY                 4
+#define UV2H_DESC_SOURCE_TIMEOUT       6
+#define UV2H_DESC_DEST_PUT_ERR         7
 
 /*
  * delay for 'plugged' timeout retries, in microseconds
  * threshholds at which to use IPI to free resources
  */
 /* after this # consecutive 'plugged' timeouts, use IPI to release resources */
-#define PLUGSB4RESET 100
+#define PLUGSB4RESET                   100
 /* after this many consecutive timeouts, use IPI to release resources */
-#define TIMEOUTSB4RESET 1
+#define TIMEOUTSB4RESET                        1
 /* at this number uses of IPI to release resources, giveup the request */
-#define IPI_RESET_LIMIT 1
+#define IPI_RESET_LIMIT                        1
 /* after this # consecutive successes, bump up the throttle if it was lowered */
-#define COMPLETE_THRESHOLD 5
+#define COMPLETE_THRESHOLD             5
+
+#define UV_LB_SUBNODEID                        0x10
 
-#define UV_LB_SUBNODEID 0x10
+/* these two are the same for UV1 and UV2: */
+#define UV_SA_SHFT UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT
+#define UV_SA_MASK UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK
+/* 4 bits of software ack period */
+#define UV2_ACK_MASK                   0x7UL
+#define UV2_ACK_UNITS_SHFT             3
+#define UV2_LEG_SHFT UV2H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_SHFT
+#define UV2_EXT_SHFT UV2H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_SHFT
 
 /*
  * number of entries in the destination side payload queue
 /*
  * tuning the action when the numalink network is extremely delayed
  */
-#define CONGESTED_RESPONSE_US 1000 /* 'long' response time, in microseconds */
-#define CONGESTED_REPS 10 /* long delays averaged over this many broadcasts */
-#define CONGESTED_PERIOD 30 /* time for the bau to be disabled, in seconds */
+#define CONGESTED_RESPONSE_US          1000    /* 'long' response time, in
+                                                  microseconds */
+#define CONGESTED_REPS                 10      /* long delays averaged over
+                                                  this many broadcasts */
+#define CONGESTED_PERIOD               30      /* time for the bau to be
+                                                  disabled, in seconds */
+/* see msg_type: */
+#define MSG_NOOP                       0
+#define MSG_REGULAR                    1
+#define MSG_RETRY                      2
 
 /*
  * Distribution: 32 bytes (256 bits) (bytes 0-0x1f of descriptor)
  * 'base_dest_nasid' field of the header corresponds to the
  * destination nodeID associated with that specified bit.
  */
-struct bau_target_uvhubmask {
-       unsigned long bits[BITS_TO_LONGS(UV_DISTRIBUTION_SIZE)];
+struct bau_targ_hubmask {
+       unsigned long           bits[BITS_TO_LONGS(UV_DISTRIBUTION_SIZE)];
 };
 
 /*
@@ -139,7 +193,7 @@ struct bau_target_uvhubmask {
  *  enough bits for max. cpu's per uvhub)
  */
 struct bau_local_cpumask {
-       unsigned long bits;
+       unsigned long           bits;
 };
 
 /*
@@ -160,14 +214,14 @@ struct bau_local_cpumask {
  * The payload is software-defined for INTD transactions
  */
 struct bau_msg_payload {
-       unsigned long address;          /* signifies a page or all TLB's
-                                               of the cpu */
+       unsigned long   address;                /* signifies a page or all
+                                                  TLB's of the cpu */
        /* 64 bits */
-       unsigned short sending_cpu;     /* filled in by sender */
+       unsigned short  sending_cpu;            /* filled in by sender */
        /* 16 bits */
-       unsigned short acknowledge_count;/* filled in by destination */
+       unsigned short  acknowledge_count;      /* filled in by destination */
        /* 16 bits */
-       unsigned int reserved1:32;      /* not usable */
+       unsigned int    reserved1:32;           /* not usable */
 };
 
 
@@ -176,93 +230,96 @@ struct bau_msg_payload {
  * see table 4.2.3.0.1 in broacast_assist spec.
  */
 struct bau_msg_header {
-       unsigned int dest_subnodeid:6;  /* must be 0x10, for the LB */
+       unsigned int    dest_subnodeid:6;       /* must be 0x10, for the LB */
        /* bits 5:0 */
-       unsigned int base_dest_nasid:15; /* nasid of the */
-       /* bits 20:6 */                   /* first bit in uvhub map */
-       unsigned int command:8; /* message type */
+       unsigned int    base_dest_nasid:15;     /* nasid of the first bit */
+       /* bits 20:6 */                         /* in uvhub map */
+       unsigned int    command:8;              /* message type */
        /* bits 28:21 */
-                               /* 0x38: SN3net EndPoint Message */
-       unsigned int rsvd_1:3;  /* must be zero */
+       /* 0x38: SN3net EndPoint Message */
+       unsigned int    rsvd_1:3;               /* must be zero */
        /* bits 31:29 */
-                               /* int will align on 32 bits */
-       unsigned int rsvd_2:9;  /* must be zero */
+       /* int will align on 32 bits */
+       unsigned int    rsvd_2:9;               /* must be zero */
        /* bits 40:32 */
-                               /* Suppl_A is 56-41 */
-       unsigned int sequence:16;/* message sequence number */
-       /* bits 56:41 */        /* becomes bytes 16-17 of msg */
-                               /* Address field (96:57) is never used as an
-                                  address (these are address bits 42:3) */
-
-       unsigned int rsvd_3:1;  /* must be zero */
+       /* Suppl_A is 56-41 */
+       unsigned int    sequence:16;            /* message sequence number */
+       /* bits 56:41 */                        /* becomes bytes 16-17 of msg */
+                                               /* Address field (96:57) is
+                                                  never used as an address
+                                                  (these are address bits
+                                                  42:3) */
+
+       unsigned int    rsvd_3:1;               /* must be zero */
        /* bit 57 */
-                               /* address bits 27:4 are payload */
+       /* address bits 27:4 are payload */
        /* these next 24  (58-81) bits become bytes 12-14 of msg */
-
        /* bits 65:58 land in byte 12 */
-       unsigned int replied_to:1;/* sent as 0 by the source to byte 12 */
+       unsigned int    replied_to:1;           /* sent as 0 by the source to
+                                                  byte 12 */
        /* bit 58 */
-       unsigned int msg_type:3; /* software type of the message*/
+       unsigned int    msg_type:3;             /* software type of the
+                                                  message */
        /* bits 61:59 */
-       unsigned int canceled:1; /* message canceled, resource to be freed*/
+       unsigned int    canceled:1;             /* message canceled, resource
+                                                  is to be freed*/
        /* bit 62 */
-       unsigned int payload_1a:1;/* not currently used */
+       unsigned int    payload_1a:1;           /* not currently used */
        /* bit 63 */
-       unsigned int payload_1b:2;/* not currently used */
+       unsigned int    payload_1b:2;           /* not currently used */
        /* bits 65:64 */
 
        /* bits 73:66 land in byte 13 */
-       unsigned int payload_1ca:6;/* not currently used */
+       unsigned int    payload_1ca:6;          /* not currently used */
        /* bits 71:66 */
-       unsigned int payload_1c:2;/* not currently used */
+       unsigned int    payload_1c:2;           /* not currently used */
        /* bits 73:72 */
 
        /* bits 81:74 land in byte 14 */
-       unsigned int payload_1d:6;/* not currently used */
+       unsigned int    payload_1d:6;           /* not currently used */
        /* bits 79:74 */
-       unsigned int payload_1e:2;/* not currently used */
+       unsigned int    payload_1e:2;           /* not currently used */
        /* bits 81:80 */
 
-       unsigned int rsvd_4:7;  /* must be zero */
+       unsigned int    rsvd_4:7;               /* must be zero */
        /* bits 88:82 */
-       unsigned int sw_ack_flag:1;/* software acknowledge flag */
+       unsigned int    swack_flag:1;           /* software acknowledge flag */
        /* bit 89 */
-                               /* INTD trasactions at destination are to
-                                  wait for software acknowledge */
-       unsigned int rsvd_5:6;  /* must be zero */
+                                               /* INTD trasactions at
+                                                  destination are to wait for
+                                                  software acknowledge */
+       unsigned int    rsvd_5:6;               /* must be zero */
        /* bits 95:90 */
-       unsigned int rsvd_6:5;  /* must be zero */
+       unsigned int    rsvd_6:5;               /* must be zero */
        /* bits 100:96 */
-       unsigned int int_both:1;/* if 1, interrupt both sockets on the uvhub */
+       unsigned int    int_both:1;             /* if 1, interrupt both sockets
+                                                  on the uvhub */
        /* bit 101*/
-       unsigned int fairness:3;/* usually zero */
+       unsigned int    fairness:3;             /* usually zero */
        /* bits 104:102 */
-       unsigned int multilevel:1;      /* multi-level multicast format */
+       unsigned int    multilevel:1;           /* multi-level multicast
+                                                  format */
        /* bit 105 */
-                               /* 0 for TLB: endpoint multi-unicast messages */
-       unsigned int chaining:1;/* next descriptor is part of this activation*/
+       /* 0 for TLB: endpoint multi-unicast messages */
+       unsigned int    chaining:1;             /* next descriptor is part of
+                                                  this activation*/
        /* bit 106 */
-       unsigned int rsvd_7:21; /* must be zero */
+       unsigned int    rsvd_7:21;              /* must be zero */
        /* bits 127:107 */
 };
 
-/* see msg_type: */
-#define MSG_NOOP 0
-#define MSG_REGULAR 1
-#define MSG_RETRY 2
-
 /*
  * The activation descriptor:
  * The format of the message to send, plus all accompanying control
  * Should be 64 bytes
  */
 struct bau_desc {
-       struct bau_target_uvhubmask distribution;
+       struct bau_targ_hubmask distribution;
        /*
         * message template, consisting of header and payload:
         */
-       struct bau_msg_header header;
-       struct bau_msg_payload payload;
+       struct bau_msg_header           header;
+       struct bau_msg_payload          payload;
 };
 /*
  *   -payload--    ---------header------
@@ -281,59 +338,51 @@ struct bau_desc {
  * are 32 bytes (2 micropackets) (256 bits) in length, but contain only 17
  * bytes of usable data, including the sw ack vector in byte 15 (bits 127:120)
  * (12 bytes come from bau_msg_payload, 3 from payload_1, 2 from
- *  sw_ack_vector and payload_2)
+ *  swack_vec and payload_2)
  * "Enabling Software Acknowledgment mode (see Section 4.3.3 Software
  *  Acknowledge Processing) also selects 32 byte (17 bytes usable) payload
  *  operation."
  */
-struct bau_payload_queue_entry {
-       unsigned long address;          /* signifies a page or all TLB's
-                                               of the cpu */
+struct bau_pq_entry {
+       unsigned long   address;        /* signifies a page or all TLB's
+                                          of the cpu */
        /* 64 bits, bytes 0-7 */
-
-       unsigned short sending_cpu;     /* cpu that sent the message */
+       unsigned short  sending_cpu;    /* cpu that sent the message */
        /* 16 bits, bytes 8-9 */
-
-       unsigned short acknowledge_count; /* filled in by destination */
+       unsigned short  acknowledge_count; /* filled in by destination */
        /* 16 bits, bytes 10-11 */
-
        /* these next 3 bytes come from bits 58-81 of the message header */
-       unsigned short replied_to:1;    /* sent as 0 by the source */
-       unsigned short msg_type:3;      /* software message type */
-       unsigned short canceled:1;      /* sent as 0 by the source */
-       unsigned short unused1:3;       /* not currently using */
+       unsigned short  replied_to:1;   /* sent as 0 by the source */
+       unsigned short  msg_type:3;     /* software message type */
+       unsigned short  canceled:1;     /* sent as 0 by the source */
+       unsigned short  unused1:3;      /* not currently using */
        /* byte 12 */
-
-       unsigned char unused2a;         /* not currently using */
+       unsigned char   unused2a;       /* not currently using */
        /* byte 13 */
-       unsigned char unused2;          /* not currently using */
+       unsigned char   unused2;        /* not currently using */
        /* byte 14 */
-
-       unsigned char sw_ack_vector;    /* filled in by the hardware */
+       unsigned char   swack_vec;      /* filled in by the hardware */
        /* byte 15 (bits 127:120) */
-
-       unsigned short sequence;        /* message sequence number */
+       unsigned short  sequence;       /* message sequence number */
        /* bytes 16-17 */
-       unsigned char unused4[2];       /* not currently using bytes 18-19 */
+       unsigned char   unused4[2];     /* not currently using bytes 18-19 */
        /* bytes 18-19 */
-
-       int number_of_cpus;             /* filled in at destination */
+       int             number_of_cpus; /* filled in at destination */
        /* 32 bits, bytes 20-23 (aligned) */
-
-       unsigned char unused5[8];       /* not using */
+       unsigned char   unused5[8];     /* not using */
        /* bytes 24-31 */
 };
 
 struct msg_desc {
-       struct bau_payload_queue_entry *msg;
-       int msg_slot;
-       int sw_ack_slot;
-       struct bau_payload_queue_entry *va_queue_first;
-       struct bau_payload_queue_entry *va_queue_last;
+       struct bau_pq_entry     *msg;
+       int                     msg_slot;
+       int                     swack_slot;
+       struct bau_pq_entry     *queue_first;
+       struct bau_pq_entry     *queue_last;
 };
 
 struct reset_args {
-       int sender;
+       int                     sender;
 };
 
 /*
@@ -341,112 +390,226 @@ struct reset_args {
  */
 struct ptc_stats {
        /* sender statistics */
-       unsigned long s_giveup; /* number of fall backs to IPI-style flushes */
-       unsigned long s_requestor; /* number of shootdown requests */
-       unsigned long s_stimeout; /* source side timeouts */
-       unsigned long s_dtimeout; /* destination side timeouts */
-       unsigned long s_time; /* time spent in sending side */
-       unsigned long s_retriesok; /* successful retries */
-       unsigned long s_ntargcpu; /* total number of cpu's targeted */
-       unsigned long s_ntargself; /* times the sending cpu was targeted */
-       unsigned long s_ntarglocals; /* targets of cpus on the local blade */
-       unsigned long s_ntargremotes; /* targets of cpus on remote blades */
-       unsigned long s_ntarglocaluvhub; /* targets of the local hub */
-       unsigned long s_ntargremoteuvhub; /* remotes hubs targeted */
-       unsigned long s_ntarguvhub; /* total number of uvhubs targeted */
-       unsigned long s_ntarguvhub16; /* number of times target hubs >= 16*/
-       unsigned long s_ntarguvhub8; /* number of times target hubs >= 8 */
-       unsigned long s_ntarguvhub4; /* number of times target hubs >= 4 */
-       unsigned long s_ntarguvhub2; /* number of times target hubs >= 2 */
-       unsigned long s_ntarguvhub1; /* number of times target hubs == 1 */
-       unsigned long s_resets_plug; /* ipi-style resets from plug state */
-       unsigned long s_resets_timeout; /* ipi-style resets from timeouts */
-       unsigned long s_busy; /* status stayed busy past s/w timer */
-       unsigned long s_throttles; /* waits in throttle */
-       unsigned long s_retry_messages; /* retry broadcasts */
-       unsigned long s_bau_reenabled; /* for bau enable/disable */
-       unsigned long s_bau_disabled; /* for bau enable/disable */
+       unsigned long   s_giveup;               /* number of fall backs to
+                                                  IPI-style flushes */
+       unsigned long   s_requestor;            /* number of shootdown
+                                                  requests */
+       unsigned long   s_stimeout;             /* source side timeouts */
+       unsigned long   s_dtimeout;             /* destination side timeouts */
+       unsigned long   s_time;                 /* time spent in sending side */
+       unsigned long   s_retriesok;            /* successful retries */
+       unsigned long   s_ntargcpu;             /* total number of cpu's
+                                                  targeted */
+       unsigned long   s_ntargself;            /* times the sending cpu was
+                                                  targeted */
+       unsigned long   s_ntarglocals;          /* targets of cpus on the local
+                                                  blade */
+       unsigned long   s_ntargremotes;         /* targets of cpus on remote
+                                                  blades */
+       unsigned long   s_ntarglocaluvhub;      /* targets of the local hub */
+       unsigned long   s_ntargremoteuvhub;     /* remotes hubs targeted */
+       unsigned long   s_ntarguvhub;           /* total number of uvhubs
+                                                  targeted */
+       unsigned long   s_ntarguvhub16;         /* number of times target
+                                                  hubs >= 16*/
+       unsigned long   s_ntarguvhub8;          /* number of times target
+                                                  hubs >= 8 */
+       unsigned long   s_ntarguvhub4;          /* number of times target
+                                                  hubs >= 4 */
+       unsigned long   s_ntarguvhub2;          /* number of times target
+                                                  hubs >= 2 */
+       unsigned long   s_ntarguvhub1;          /* number of times target
+                                                  hubs == 1 */
+       unsigned long   s_resets_plug;          /* ipi-style resets from plug
+                                                  state */
+       unsigned long   s_resets_timeout;       /* ipi-style resets from
+                                                  timeouts */
+       unsigned long   s_busy;                 /* status stayed busy past
+                                                  s/w timer */
+       unsigned long   s_throttles;            /* waits in throttle */
+       unsigned long   s_retry_messages;       /* retry broadcasts */
+       unsigned long   s_bau_reenabled;        /* for bau enable/disable */
+       unsigned long   s_bau_disabled;         /* for bau enable/disable */
        /* destination statistics */
-       unsigned long d_alltlb; /* times all tlb's on this cpu were flushed */
-       unsigned long d_onetlb; /* times just one tlb on this cpu was flushed */
-       unsigned long d_multmsg; /* interrupts with multiple messages */
-       unsigned long d_nomsg; /* interrupts with no message */
-       unsigned long d_time; /* time spent on destination side */
-       unsigned long d_requestee; /* number of messages processed */
-       unsigned long d_retries; /* number of retry messages processed */
-       unsigned long d_canceled; /* number of messages canceled by retries */
-       unsigned long d_nocanceled; /* retries that found nothing to cancel */
-       unsigned long d_resets; /* number of ipi-style requests processed */
-       unsigned long d_rcanceled; /* number of messages canceled by resets */
+       unsigned long   d_alltlb;               /* times all tlb's on this
+                                                  cpu were flushed */
+       unsigned long   d_onetlb;               /* times just one tlb on this
+                                                  cpu was flushed */
+       unsigned long   d_multmsg;              /* interrupts with multiple
+                                                  messages */
+       unsigned long   d_nomsg;                /* interrupts with no message */
+       unsigned long   d_time;                 /* time spent on destination
+                                                  side */
+       unsigned long   d_requestee;            /* number of messages
+                                                  processed */
+       unsigned long   d_retries;              /* number of retry messages
+                                                  processed */
+       unsigned long   d_canceled;             /* number of messages canceled
+                                                  by retries */
+       unsigned long   d_nocanceled;           /* retries that found nothing
+                                                  to cancel */
+       unsigned long   d_resets;               /* number of ipi-style requests
+                                                  processed */
+       unsigned long   d_rcanceled;            /* number of messages canceled
+                                                  by resets */
+};
+
+struct tunables {
+       int                     *tunp;
+       int                     deflt;
 };
 
 struct hub_and_pnode {
-       short uvhub;
-       short pnode;
+       short                   uvhub;
+       short                   pnode;
 };
+
+struct socket_desc {
+       short                   num_cpus;
+       short                   cpu_number[MAX_CPUS_PER_SOCKET];
+};
+
+struct uvhub_desc {
+       unsigned short          socket_mask;
+       short                   num_cpus;
+       short                   uvhub;
+       short                   pnode;
+       struct socket_desc      socket[2];
+};
+
 /*
  * one per-cpu; to locate the software tables
  */
 struct bau_control {
-       struct bau_desc *descriptor_base;
-       struct bau_payload_queue_entry *va_queue_first;
-       struct bau_payload_queue_entry *va_queue_last;
-       struct bau_payload_queue_entry *bau_msg_head;
-       struct bau_control *uvhub_master;
-       struct bau_control *socket_master;
-       struct ptc_stats *statp;
-       unsigned long timeout_interval;
-       unsigned long set_bau_on_time;
-       atomic_t active_descriptor_count;
-       int plugged_tries;
-       int timeout_tries;
-       int ipi_attempts;
-       int conseccompletes;
-       int baudisabled;
-       int set_bau_off;
-       short cpu;
-       short osnode;
-       short uvhub_cpu;
-       short uvhub;
-       short cpus_in_socket;
-       short cpus_in_uvhub;
-       short partition_base_pnode;
-       unsigned short message_number;
-       unsigned short uvhub_quiesce;
-       short socket_acknowledge_count[DEST_Q_SIZE];
-       cycles_t send_message;
-       spinlock_t uvhub_lock;
-       spinlock_t queue_lock;
+       struct bau_desc         *descriptor_base;
+       struct bau_pq_entry     *queue_first;
+       struct bau_pq_entry     *queue_last;
+       struct bau_pq_entry     *bau_msg_head;
+       struct bau_control      *uvhub_master;
+       struct bau_control      *socket_master;
+       struct ptc_stats        *statp;
+       unsigned long           timeout_interval;
+       unsigned long           set_bau_on_time;
+       atomic_t                active_descriptor_count;
+       int                     plugged_tries;
+       int                     timeout_tries;
+       int                     ipi_attempts;
+       int                     conseccompletes;
+       int                     baudisabled;
+       int                     set_bau_off;
+       short                   cpu;
+       short                   osnode;
+       short                   uvhub_cpu;
+       short                   uvhub;
+       short                   cpus_in_socket;
+       short                   cpus_in_uvhub;
+       short                   partition_base_pnode;
+       unsigned short          message_number;
+       unsigned short          uvhub_quiesce;
+       short                   socket_acknowledge_count[DEST_Q_SIZE];
+       cycles_t                send_message;
+       spinlock_t              uvhub_lock;
+       spinlock_t              queue_lock;
        /* tunables */
-       int max_bau_concurrent;
-       int max_bau_concurrent_constant;
-       int plugged_delay;
-       int plugsb4reset;
-       int timeoutsb4reset;
-       int ipi_reset_limit;
-       int complete_threshold;
-       int congested_response_us;
-       int congested_reps;
-       int congested_period;
-       cycles_t period_time;
-       long period_requests;
-       struct hub_and_pnode *target_hub_and_pnode;
+       int                     max_concurr;
+       int                     max_concurr_const;
+       int                     plugged_delay;
+       int                     plugsb4reset;
+       int                     timeoutsb4reset;
+       int                     ipi_reset_limit;
+       int                     complete_threshold;
+       int                     cong_response_us;
+       int                     cong_reps;
+       int                     cong_period;
+       cycles_t                period_time;
+       long                    period_requests;
+       struct hub_and_pnode    *thp;
 };
 
-static inline int bau_uvhub_isset(int uvhub, struct bau_target_uvhubmask *dstp)
+static unsigned long read_mmr_uv2_status(void)
+{
+       return read_lmmr(UV2H_LB_BAU_SB_ACTIVATION_STATUS_2);
+}
+
+static void write_mmr_data_broadcast(int pnode, unsigned long mmr_image)
+{
+       write_gmmr(pnode, UVH_BAU_DATA_BROADCAST, mmr_image);
+}
+
+static void write_mmr_descriptor_base(int pnode, unsigned long mmr_image)
+{
+       write_gmmr(pnode, UVH_LB_BAU_SB_DESCRIPTOR_BASE, mmr_image);
+}
+
+static void write_mmr_activation(unsigned long index)
+{
+       write_lmmr(UVH_LB_BAU_SB_ACTIVATION_CONTROL, index);
+}
+
+static void write_gmmr_activation(int pnode, unsigned long mmr_image)
+{
+       write_gmmr(pnode, UVH_LB_BAU_SB_ACTIVATION_CONTROL, mmr_image);
+}
+
+static void write_mmr_payload_first(int pnode, unsigned long mmr_image)
+{
+       write_gmmr(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST, mmr_image);
+}
+
+static void write_mmr_payload_tail(int pnode, unsigned long mmr_image)
+{
+       write_gmmr(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL, mmr_image);
+}
+
+static void write_mmr_payload_last(int pnode, unsigned long mmr_image)
+{
+       write_gmmr(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST, mmr_image);
+}
+
+static void write_mmr_misc_control(int pnode, unsigned long mmr_image)
+{
+       write_gmmr(pnode, UVH_LB_BAU_MISC_CONTROL, mmr_image);
+}
+
+static unsigned long read_mmr_misc_control(int pnode)
+{
+       return read_gmmr(pnode, UVH_LB_BAU_MISC_CONTROL);
+}
+
+static void write_mmr_sw_ack(unsigned long mr)
+{
+       uv_write_local_mmr(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS, mr);
+}
+
+static unsigned long read_mmr_sw_ack(void)
+{
+       return read_lmmr(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE);
+}
+
+static unsigned long read_gmmr_sw_ack(int pnode)
+{
+       return read_gmmr(pnode, UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE);
+}
+
+static void write_mmr_data_config(int pnode, unsigned long mr)
+{
+       uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG, mr);
+}
+
+static inline int bau_uvhub_isset(int uvhub, struct bau_targ_hubmask *dstp)
 {
        return constant_test_bit(uvhub, &dstp->bits[0]);
 }
-static inline void bau_uvhub_set(int pnode, struct bau_target_uvhubmask *dstp)
+static inline void bau_uvhub_set(int pnode, struct bau_targ_hubmask *dstp)
 {
        __set_bit(pnode, &dstp->bits[0]);
 }
-static inline void bau_uvhubs_clear(struct bau_target_uvhubmask *dstp,
+static inline void bau_uvhubs_clear(struct bau_targ_hubmask *dstp,
                                    int nbits)
 {
        bitmap_zero(&dstp->bits[0], nbits);
 }
-static inline int bau_uvhub_weight(struct bau_target_uvhubmask *dstp)
+static inline int bau_uvhub_weight(struct bau_targ_hubmask *dstp)
 {
        return bitmap_weight((unsigned long *)&dstp->bits[0],
                                UV_DISTRIBUTION_SIZE);
@@ -457,9 +620,6 @@ static inline void bau_cpubits_clear(struct bau_local_cpumask *dstp, int nbits)
        bitmap_zero(&dstp->bits, nbits);
 }
 
-#define cpubit_isset(cpu, bau_local_cpumask) \
-       test_bit((cpu), (bau_local_cpumask).bits)
-
 extern void uv_bau_message_intr1(void);
 extern void uv_bau_timeout_intr1(void);
 
@@ -467,7 +627,7 @@ struct atomic_short {
        short counter;
 };
 
-/**
+/*
  * atomic_read_short - read a short atomic variable
  * @v: pointer of type atomic_short
  *
@@ -478,14 +638,14 @@ static inline int atomic_read_short(const struct atomic_short *v)
        return v->counter;
 }
 
-/**
- * atomic_add_short_return - add and return a short int
+/*
+ * atom_asr - add and return a short int
  * @i: short value to add
  * @v: pointer of type atomic_short
  *
  * Atomically adds @i to @v and returns @i + @v
  */
-static inline int atomic_add_short_return(short i, struct atomic_short *v)
+static inline int atom_asr(short i, struct atomic_short *v)
 {
        short __i = i;
        asm volatile(LOCK_PREFIX "xaddw %0, %1"
@@ -494,4 +654,26 @@ static inline int atomic_add_short_return(short i, struct atomic_short *v)
        return i + __i;
 }
 
+/*
+ * conditionally add 1 to *v, unless *v is >= u
+ * return 0 if we cannot add 1 to *v because it is >= u
+ * return 1 if we can add 1 to *v because it is < u
+ * the add is atomic
+ *
+ * This is close to atomic_add_unless(), but this allows the 'u' value
+ * to be lowered below the current 'v'.  atomic_add_unless can only stop
+ * on equal.
+ */
+static inline int atomic_inc_unless_ge(spinlock_t *lock, atomic_t *v, int u)
+{
+       spin_lock(lock);
+       if (atomic_read(v) >= u) {
+               spin_unlock(lock);
+               return 0;
+       }
+       atomic_inc(v);
+       spin_unlock(lock);
+       return 1;
+}
+
 #endif /* _ASM_X86_UV_UV_BAU_H */
index 4298002d0c83a9c09c19c725c22a33e43921d128..f26544a15214e41f418b0554c52581ce23f9aacb 100644 (file)
@@ -77,8 +77,9 @@
  *
  *             1111110000000000
  *             5432109876543210
- *             pppppppppplc0cch        Nehalem-EX
- *             ppppppppplcc0cch        Westmere-EX
+ *             pppppppppplc0cch        Nehalem-EX (12 bits in hdw reg)
+ *             ppppppppplcc0cch        Westmere-EX (12 bits in hdw reg)
+ *             pppppppppppcccch        SandyBridge (15 bits in hdw reg)
  *             sssssssssss
  *
  *                     p  = pnode bits
@@ -87,7 +88,7 @@
  *                     h  = hyperthread
  *                     s  = bits that are in the SOCKET_ID CSR
  *
- *     Note: Processor only supports 12 bits in the APICID register. The ACPI
+ *     Note: Processor may support fewer bits in the APICID register. The ACPI
  *           tables hold all 16 bits. Software needs to be aware of this.
  *
  *           Unless otherwise specified, all references to APICID refer to
@@ -138,6 +139,8 @@ struct uv_hub_info_s {
        unsigned long           global_mmr_base;
        unsigned long           gpa_mask;
        unsigned int            gnode_extra;
+       unsigned char           hub_revision;
+       unsigned char           apic_pnode_shift;
        unsigned long           gnode_upper;
        unsigned long           lowmem_remap_top;
        unsigned long           lowmem_remap_base;
@@ -149,13 +152,31 @@ struct uv_hub_info_s {
        unsigned char           m_val;
        unsigned char           n_val;
        struct uv_scir_s        scir;
-       unsigned char           apic_pnode_shift;
 };
 
 DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
 #define uv_hub_info            (&__get_cpu_var(__uv_hub_info))
 #define uv_cpu_hub_info(cpu)   (&per_cpu(__uv_hub_info, cpu))
 
+/*
+ * Hub revisions less than UV2_HUB_REVISION_BASE are UV1 hubs. All UV2
+ * hubs have revision numbers greater than or equal to UV2_HUB_REVISION_BASE.
+ * This is a software convention - NOT the hardware revision numbers in
+ * the hub chip.
+ */
+#define UV1_HUB_REVISION_BASE          1
+#define UV2_HUB_REVISION_BASE          3
+
+static inline int is_uv1_hub(void)
+{
+       return uv_hub_info->hub_revision < UV2_HUB_REVISION_BASE;
+}
+
+static inline int is_uv2_hub(void)
+{
+       return uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE;
+}
+
 union uvh_apicid {
     unsigned long       v;
     struct uvh_apicid_s {
@@ -180,11 +201,25 @@ union uvh_apicid {
 #define UV_PNODE_TO_GNODE(p)           ((p) |uv_hub_info->gnode_extra)
 #define UV_PNODE_TO_NASID(p)           (UV_PNODE_TO_GNODE(p) << 1)
 
-#define UV_LOCAL_MMR_BASE              0xf4000000UL
-#define UV_GLOBAL_MMR32_BASE           0xf8000000UL
+#define UV1_LOCAL_MMR_BASE             0xf4000000UL
+#define UV1_GLOBAL_MMR32_BASE          0xf8000000UL
+#define UV1_LOCAL_MMR_SIZE             (64UL * 1024 * 1024)
+#define UV1_GLOBAL_MMR32_SIZE          (64UL * 1024 * 1024)
+
+#define UV2_LOCAL_MMR_BASE             0xfa000000UL
+#define UV2_GLOBAL_MMR32_BASE          0xfc000000UL
+#define UV2_LOCAL_MMR_SIZE             (32UL * 1024 * 1024)
+#define UV2_GLOBAL_MMR32_SIZE          (32UL * 1024 * 1024)
+
+#define UV_LOCAL_MMR_BASE              (is_uv1_hub() ? UV1_LOCAL_MMR_BASE     \
+                                               : UV2_LOCAL_MMR_BASE)
+#define UV_GLOBAL_MMR32_BASE           (is_uv1_hub() ? UV1_GLOBAL_MMR32_BASE  \
+                                               : UV2_GLOBAL_MMR32_BASE)
+#define UV_LOCAL_MMR_SIZE              (is_uv1_hub() ? UV1_LOCAL_MMR_SIZE :   \
+                                               UV2_LOCAL_MMR_SIZE)
+#define UV_GLOBAL_MMR32_SIZE           (is_uv1_hub() ? UV1_GLOBAL_MMR32_SIZE :\
+                                               UV2_GLOBAL_MMR32_SIZE)
 #define UV_GLOBAL_MMR64_BASE           (uv_hub_info->global_mmr_base)
-#define UV_LOCAL_MMR_SIZE              (64UL * 1024 * 1024)
-#define UV_GLOBAL_MMR32_SIZE           (64UL * 1024 * 1024)
 
 #define UV_GLOBAL_GRU_MMR_BASE         0x4000000
 
@@ -300,6 +335,17 @@ static inline int uv_apicid_to_pnode(int apicid)
        return (apicid >> uv_hub_info->apic_pnode_shift);
 }
 
+/*
+ * Convert an apicid to the socket number on the blade
+ */
+static inline int uv_apicid_to_socket(int apicid)
+{
+       if (is_uv1_hub())
+               return (apicid >> (uv_hub_info->apic_pnode_shift - 1)) & 1;
+       else
+               return 0;
+}
+
 /*
  * Access global MMRs using the low memory MMR32 space. This region supports
  * faster MMR access but not all MMRs are accessible in this space.
@@ -519,14 +565,13 @@ static inline void uv_hub_send_ipi(int pnode, int apicid, int vector)
 
 /*
  * Get the minimum revision number of the hub chips within the partition.
- *     1 - initial rev 1.0 silicon
- *     2 - rev 2.0 production silicon
+ *     1 - UV1 rev 1.0 initial silicon
+ *     2 - UV1 rev 2.0 production silicon
+ *     3 - UV2 rev 1.0 initial silicon
  */
 static inline int uv_get_min_hub_revision_id(void)
 {
-       extern int uv_min_hub_revision_id;
-
-       return uv_min_hub_revision_id;
+       return uv_hub_info->hub_revision;
 }
 
 #endif /* CONFIG_X86_64 */
index f5bb64a823d77a1d3ebf97d40e80e913c83e0d31..4be52c863448ae6f745492c93df6978704857b94 100644 (file)
 #ifndef _ASM_X86_UV_UV_MMRS_H
 #define _ASM_X86_UV_UV_MMRS_H
 
+/*
+ * This file contains MMR definitions for both UV1 & UV2 hubs.
+ *
+ * In general, MMR addresses and structures are identical on both hubs.
+ * These MMRs are identified as:
+ *     #define UVH_xxx         <address>
+ *     union uvh_xxx {
+ *             unsigned long       v;
+ *             struct uvh_int_cmpd_s {
+ *             } s;
+ *     };
+ *
+ * If the MMR exists on both hub type but has different addresses or
+ * contents, the MMR definition is similar to:
+ *     #define UV1H_xxx        <uv1 address>
+ *     #define UV2H_xxx        <uv2address>
+ *     #define UVH_xxx         (is_uv1_hub() ? UV1H_xxx : UV2H_xxx)
+ *     union uvh_xxx {
+ *             unsigned long       v;
+ *             struct uv1h_int_cmpd_s {         (Common fields only)
+ *             } s;
+ *             struct uv1h_int_cmpd_s {         (Full UV1 definition)
+ *             } s1;
+ *             struct uv2h_int_cmpd_s {         (Full UV2 definition)
+ *             } s2;
+ *     };
+ *
+ * Only essential difference are enumerated. For example, if the address is
+ * the same for both UV1 & UV2, only a single #define is generated. Likewise,
+ * if the contents is the same for both hubs, only the "s" structure is
+ * generated.
+ *
+ * If the MMR exists on ONLY 1 type of hub, no generic definition is
+ * generated:
+ *     #define UVnH_xxx        <uvn address>
+ *     union uvnh_xxx {
+ *             unsigned long       v;
+ *             struct uvh_int_cmpd_s {
+ *             } sn;
+ *     };
+ */
+
 #define UV_MMR_ENABLE          (1UL << 63)
 
+#define UV1_HUB_PART_NUMBER    0x88a5
+#define UV2_HUB_PART_NUMBER    0x8eb8
+
+/* Compat: if this #define is present, UV headers support UV2 */
+#define UV2_HUB_IS_SUPPORTED   1
+
+/* KABI compat: if this #define is present, KABI hacks are present */
+#define UV2_HUB_KABI_HACKS     1
+
 /* ========================================================================= */
 /*                          UVH_BAU_DATA_BROADCAST                           */
 /* ========================================================================= */
 #define UVH_BAU_DATA_BROADCAST 0x61688UL
-#define UVH_BAU_DATA_BROADCAST_32 0x0440
+#define UVH_BAU_DATA_BROADCAST_32 0x440
 
 #define UVH_BAU_DATA_BROADCAST_ENABLE_SHFT 0
 #define UVH_BAU_DATA_BROADCAST_ENABLE_MASK 0x0000000000000001UL
@@ -34,7 +85,7 @@ union uvh_bau_data_broadcast_u {
 /*                           UVH_BAU_DATA_CONFIG                             */
 /* ========================================================================= */
 #define UVH_BAU_DATA_CONFIG 0x61680UL
-#define UVH_BAU_DATA_CONFIG_32 0x0438
+#define UVH_BAU_DATA_CONFIG_32 0x438
 
 #define UVH_BAU_DATA_CONFIG_VECTOR_SHFT 0
 #define UVH_BAU_DATA_CONFIG_VECTOR_MASK 0x00000000000000ffUL
@@ -73,125 +124,245 @@ union uvh_bau_data_config_u {
 /*                           UVH_EVENT_OCCURRED0                             */
 /* ========================================================================= */
 #define UVH_EVENT_OCCURRED0 0x70000UL
-#define UVH_EVENT_OCCURRED0_32 0x005e8
-
-#define UVH_EVENT_OCCURRED0_LB_HCERR_SHFT 0
-#define UVH_EVENT_OCCURRED0_LB_HCERR_MASK 0x0000000000000001UL
-#define UVH_EVENT_OCCURRED0_GR0_HCERR_SHFT 1
-#define UVH_EVENT_OCCURRED0_GR0_HCERR_MASK 0x0000000000000002UL
-#define UVH_EVENT_OCCURRED0_GR1_HCERR_SHFT 2
-#define UVH_EVENT_OCCURRED0_GR1_HCERR_MASK 0x0000000000000004UL
-#define UVH_EVENT_OCCURRED0_LH_HCERR_SHFT 3
-#define UVH_EVENT_OCCURRED0_LH_HCERR_MASK 0x0000000000000008UL
-#define UVH_EVENT_OCCURRED0_RH_HCERR_SHFT 4
-#define UVH_EVENT_OCCURRED0_RH_HCERR_MASK 0x0000000000000010UL
-#define UVH_EVENT_OCCURRED0_XN_HCERR_SHFT 5
-#define UVH_EVENT_OCCURRED0_XN_HCERR_MASK 0x0000000000000020UL
-#define UVH_EVENT_OCCURRED0_SI_HCERR_SHFT 6
-#define UVH_EVENT_OCCURRED0_SI_HCERR_MASK 0x0000000000000040UL
-#define UVH_EVENT_OCCURRED0_LB_AOERR0_SHFT 7
-#define UVH_EVENT_OCCURRED0_LB_AOERR0_MASK 0x0000000000000080UL
-#define UVH_EVENT_OCCURRED0_GR0_AOERR0_SHFT 8
-#define UVH_EVENT_OCCURRED0_GR0_AOERR0_MASK 0x0000000000000100UL
-#define UVH_EVENT_OCCURRED0_GR1_AOERR0_SHFT 9
-#define UVH_EVENT_OCCURRED0_GR1_AOERR0_MASK 0x0000000000000200UL
-#define UVH_EVENT_OCCURRED0_LH_AOERR0_SHFT 10
-#define UVH_EVENT_OCCURRED0_LH_AOERR0_MASK 0x0000000000000400UL
-#define UVH_EVENT_OCCURRED0_RH_AOERR0_SHFT 11
-#define UVH_EVENT_OCCURRED0_RH_AOERR0_MASK 0x0000000000000800UL
-#define UVH_EVENT_OCCURRED0_XN_AOERR0_SHFT 12
-#define UVH_EVENT_OCCURRED0_XN_AOERR0_MASK 0x0000000000001000UL
-#define UVH_EVENT_OCCURRED0_SI_AOERR0_SHFT 13
-#define UVH_EVENT_OCCURRED0_SI_AOERR0_MASK 0x0000000000002000UL
-#define UVH_EVENT_OCCURRED0_LB_AOERR1_SHFT 14
-#define UVH_EVENT_OCCURRED0_LB_AOERR1_MASK 0x0000000000004000UL
-#define UVH_EVENT_OCCURRED0_GR0_AOERR1_SHFT 15
-#define UVH_EVENT_OCCURRED0_GR0_AOERR1_MASK 0x0000000000008000UL
-#define UVH_EVENT_OCCURRED0_GR1_AOERR1_SHFT 16
-#define UVH_EVENT_OCCURRED0_GR1_AOERR1_MASK 0x0000000000010000UL
-#define UVH_EVENT_OCCURRED0_LH_AOERR1_SHFT 17
-#define UVH_EVENT_OCCURRED0_LH_AOERR1_MASK 0x0000000000020000UL
-#define UVH_EVENT_OCCURRED0_RH_AOERR1_SHFT 18
-#define UVH_EVENT_OCCURRED0_RH_AOERR1_MASK 0x0000000000040000UL
-#define UVH_EVENT_OCCURRED0_XN_AOERR1_SHFT 19
-#define UVH_EVENT_OCCURRED0_XN_AOERR1_MASK 0x0000000000080000UL
-#define UVH_EVENT_OCCURRED0_SI_AOERR1_SHFT 20
-#define UVH_EVENT_OCCURRED0_SI_AOERR1_MASK 0x0000000000100000UL
-#define UVH_EVENT_OCCURRED0_RH_VPI_INT_SHFT 21
-#define UVH_EVENT_OCCURRED0_RH_VPI_INT_MASK 0x0000000000200000UL
-#define UVH_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT 22
-#define UVH_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK 0x0000000000400000UL
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT 23
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK 0x0000000000800000UL
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT 24
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK 0x0000000001000000UL
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT 25
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK 0x0000000002000000UL
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT 26
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK 0x0000000004000000UL
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT 27
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK 0x0000000008000000UL
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT 28
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK 0x0000000010000000UL
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT 29
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK 0x0000000020000000UL
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT 30
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK 0x0000000040000000UL
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT 31
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK 0x0000000080000000UL
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT 32
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK 0x0000000100000000UL
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT 33
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK 0x0000000200000000UL
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT 34
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK 0x0000000400000000UL
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT 35
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK 0x0000000800000000UL
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT 36
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK 0x0000001000000000UL
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT 37
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK 0x0000002000000000UL
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT 38
-#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK 0x0000004000000000UL
-#define UVH_EVENT_OCCURRED0_L1_NMI_INT_SHFT 39
-#define UVH_EVENT_OCCURRED0_L1_NMI_INT_MASK 0x0000008000000000UL
-#define UVH_EVENT_OCCURRED0_STOP_CLOCK_SHFT 40
-#define UVH_EVENT_OCCURRED0_STOP_CLOCK_MASK 0x0000010000000000UL
-#define UVH_EVENT_OCCURRED0_ASIC_TO_L1_SHFT 41
-#define UVH_EVENT_OCCURRED0_ASIC_TO_L1_MASK 0x0000020000000000UL
-#define UVH_EVENT_OCCURRED0_L1_TO_ASIC_SHFT 42
-#define UVH_EVENT_OCCURRED0_L1_TO_ASIC_MASK 0x0000040000000000UL
-#define UVH_EVENT_OCCURRED0_LTC_INT_SHFT 43
-#define UVH_EVENT_OCCURRED0_LTC_INT_MASK 0x0000080000000000UL
-#define UVH_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT 44
-#define UVH_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK 0x0000100000000000UL
-#define UVH_EVENT_OCCURRED0_IPI_INT_SHFT 45
-#define UVH_EVENT_OCCURRED0_IPI_INT_MASK 0x0000200000000000UL
-#define UVH_EVENT_OCCURRED0_EXTIO_INT0_SHFT 46
-#define UVH_EVENT_OCCURRED0_EXTIO_INT0_MASK 0x0000400000000000UL
-#define UVH_EVENT_OCCURRED0_EXTIO_INT1_SHFT 47
-#define UVH_EVENT_OCCURRED0_EXTIO_INT1_MASK 0x0000800000000000UL
-#define UVH_EVENT_OCCURRED0_EXTIO_INT2_SHFT 48
-#define UVH_EVENT_OCCURRED0_EXTIO_INT2_MASK 0x0001000000000000UL
-#define UVH_EVENT_OCCURRED0_EXTIO_INT3_SHFT 49
-#define UVH_EVENT_OCCURRED0_EXTIO_INT3_MASK 0x0002000000000000UL
-#define UVH_EVENT_OCCURRED0_PROFILE_INT_SHFT 50
-#define UVH_EVENT_OCCURRED0_PROFILE_INT_MASK 0x0004000000000000UL
-#define UVH_EVENT_OCCURRED0_RTC0_SHFT 51
-#define UVH_EVENT_OCCURRED0_RTC0_MASK 0x0008000000000000UL
-#define UVH_EVENT_OCCURRED0_RTC1_SHFT 52
-#define UVH_EVENT_OCCURRED0_RTC1_MASK 0x0010000000000000UL
-#define UVH_EVENT_OCCURRED0_RTC2_SHFT 53
-#define UVH_EVENT_OCCURRED0_RTC2_MASK 0x0020000000000000UL
-#define UVH_EVENT_OCCURRED0_RTC3_SHFT 54
-#define UVH_EVENT_OCCURRED0_RTC3_MASK 0x0040000000000000UL
-#define UVH_EVENT_OCCURRED0_BAU_DATA_SHFT 55
-#define UVH_EVENT_OCCURRED0_BAU_DATA_MASK 0x0080000000000000UL
-#define UVH_EVENT_OCCURRED0_POWER_MANAGEMENT_REQ_SHFT 56
-#define UVH_EVENT_OCCURRED0_POWER_MANAGEMENT_REQ_MASK 0x0100000000000000UL
+#define UVH_EVENT_OCCURRED0_32 0x5e8
+
+#define UV1H_EVENT_OCCURRED0_LB_HCERR_SHFT 0
+#define UV1H_EVENT_OCCURRED0_LB_HCERR_MASK 0x0000000000000001UL
+#define UV1H_EVENT_OCCURRED0_GR0_HCERR_SHFT 1
+#define UV1H_EVENT_OCCURRED0_GR0_HCERR_MASK 0x0000000000000002UL
+#define UV1H_EVENT_OCCURRED0_GR1_HCERR_SHFT 2
+#define UV1H_EVENT_OCCURRED0_GR1_HCERR_MASK 0x0000000000000004UL
+#define UV1H_EVENT_OCCURRED0_LH_HCERR_SHFT 3
+#define UV1H_EVENT_OCCURRED0_LH_HCERR_MASK 0x0000000000000008UL
+#define UV1H_EVENT_OCCURRED0_RH_HCERR_SHFT 4
+#define UV1H_EVENT_OCCURRED0_RH_HCERR_MASK 0x0000000000000010UL
+#define UV1H_EVENT_OCCURRED0_XN_HCERR_SHFT 5
+#define UV1H_EVENT_OCCURRED0_XN_HCERR_MASK 0x0000000000000020UL
+#define UV1H_EVENT_OCCURRED0_SI_HCERR_SHFT 6
+#define UV1H_EVENT_OCCURRED0_SI_HCERR_MASK 0x0000000000000040UL
+#define UV1H_EVENT_OCCURRED0_LB_AOERR0_SHFT 7
+#define UV1H_EVENT_OCCURRED0_LB_AOERR0_MASK 0x0000000000000080UL
+#define UV1H_EVENT_OCCURRED0_GR0_AOERR0_SHFT 8
+#define UV1H_EVENT_OCCURRED0_GR0_AOERR0_MASK 0x0000000000000100UL
+#define UV1H_EVENT_OCCURRED0_GR1_AOERR0_SHFT 9
+#define UV1H_EVENT_OCCURRED0_GR1_AOERR0_MASK 0x0000000000000200UL
+#define UV1H_EVENT_OCCURRED0_LH_AOERR0_SHFT 10
+#define UV1H_EVENT_OCCURRED0_LH_AOERR0_MASK 0x0000000000000400UL
+#define UV1H_EVENT_OCCURRED0_RH_AOERR0_SHFT 11
+#define UV1H_EVENT_OCCURRED0_RH_AOERR0_MASK 0x0000000000000800UL
+#define UV1H_EVENT_OCCURRED0_XN_AOERR0_SHFT 12
+#define UV1H_EVENT_OCCURRED0_XN_AOERR0_MASK 0x0000000000001000UL
+#define UV1H_EVENT_OCCURRED0_SI_AOERR0_SHFT 13
+#define UV1H_EVENT_OCCURRED0_SI_AOERR0_MASK 0x0000000000002000UL
+#define UV1H_EVENT_OCCURRED0_LB_AOERR1_SHFT 14
+#define UV1H_EVENT_OCCURRED0_LB_AOERR1_MASK 0x0000000000004000UL
+#define UV1H_EVENT_OCCURRED0_GR0_AOERR1_SHFT 15
+#define UV1H_EVENT_OCCURRED0_GR0_AOERR1_MASK 0x0000000000008000UL
+#define UV1H_EVENT_OCCURRED0_GR1_AOERR1_SHFT 16
+#define UV1H_EVENT_OCCURRED0_GR1_AOERR1_MASK 0x0000000000010000UL
+#define UV1H_EVENT_OCCURRED0_LH_AOERR1_SHFT 17
+#define UV1H_EVENT_OCCURRED0_LH_AOERR1_MASK 0x0000000000020000UL
+#define UV1H_EVENT_OCCURRED0_RH_AOERR1_SHFT 18
+#define UV1H_EVENT_OCCURRED0_RH_AOERR1_MASK 0x0000000000040000UL
+#define UV1H_EVENT_OCCURRED0_XN_AOERR1_SHFT 19
+#define UV1H_EVENT_OCCURRED0_XN_AOERR1_MASK 0x0000000000080000UL
+#define UV1H_EVENT_OCCURRED0_SI_AOERR1_SHFT 20
+#define UV1H_EVENT_OCCURRED0_SI_AOERR1_MASK 0x0000000000100000UL
+#define UV1H_EVENT_OCCURRED0_RH_VPI_INT_SHFT 21
+#define UV1H_EVENT_OCCURRED0_RH_VPI_INT_MASK 0x0000000000200000UL
+#define UV1H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT 22
+#define UV1H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK 0x0000000000400000UL
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT 23
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK 0x0000000000800000UL
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT 24
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK 0x0000000001000000UL
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT 25
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK 0x0000000002000000UL
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT 26
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK 0x0000000004000000UL
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT 27
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK 0x0000000008000000UL
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT 28
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK 0x0000000010000000UL
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT 29
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK 0x0000000020000000UL
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT 30
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK 0x0000000040000000UL
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT 31
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK 0x0000000080000000UL
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT 32
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK 0x0000000100000000UL
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT 33
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK 0x0000000200000000UL
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT 34
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK 0x0000000400000000UL
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT 35
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK 0x0000000800000000UL
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT 36
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK 0x0000001000000000UL
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT 37
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK 0x0000002000000000UL
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT 38
+#define UV1H_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK 0x0000004000000000UL
+#define UV1H_EVENT_OCCURRED0_L1_NMI_INT_SHFT 39
+#define UV1H_EVENT_OCCURRED0_L1_NMI_INT_MASK 0x0000008000000000UL
+#define UV1H_EVENT_OCCURRED0_STOP_CLOCK_SHFT 40
+#define UV1H_EVENT_OCCURRED0_STOP_CLOCK_MASK 0x0000010000000000UL
+#define UV1H_EVENT_OCCURRED0_ASIC_TO_L1_SHFT 41
+#define UV1H_EVENT_OCCURRED0_ASIC_TO_L1_MASK 0x0000020000000000UL
+#define UV1H_EVENT_OCCURRED0_L1_TO_ASIC_SHFT 42
+#define UV1H_EVENT_OCCURRED0_L1_TO_ASIC_MASK 0x0000040000000000UL
+#define UV1H_EVENT_OCCURRED0_LTC_INT_SHFT 43
+#define UV1H_EVENT_OCCURRED0_LTC_INT_MASK 0x0000080000000000UL
+#define UV1H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT 44
+#define UV1H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK 0x0000100000000000UL
+#define UV1H_EVENT_OCCURRED0_IPI_INT_SHFT 45
+#define UV1H_EVENT_OCCURRED0_IPI_INT_MASK 0x0000200000000000UL
+#define UV1H_EVENT_OCCURRED0_EXTIO_INT0_SHFT 46
+#define UV1H_EVENT_OCCURRED0_EXTIO_INT0_MASK 0x0000400000000000UL
+#define UV1H_EVENT_OCCURRED0_EXTIO_INT1_SHFT 47
+#define UV1H_EVENT_OCCURRED0_EXTIO_INT1_MASK 0x0000800000000000UL
+#define UV1H_EVENT_OCCURRED0_EXTIO_INT2_SHFT 48
+#define UV1H_EVENT_OCCURRED0_EXTIO_INT2_MASK 0x0001000000000000UL
+#define UV1H_EVENT_OCCURRED0_EXTIO_INT3_SHFT 49
+#define UV1H_EVENT_OCCURRED0_EXTIO_INT3_MASK 0x0002000000000000UL
+#define UV1H_EVENT_OCCURRED0_PROFILE_INT_SHFT 50
+#define UV1H_EVENT_OCCURRED0_PROFILE_INT_MASK 0x0004000000000000UL
+#define UV1H_EVENT_OCCURRED0_RTC0_SHFT 51
+#define UV1H_EVENT_OCCURRED0_RTC0_MASK 0x0008000000000000UL
+#define UV1H_EVENT_OCCURRED0_RTC1_SHFT 52
+#define UV1H_EVENT_OCCURRED0_RTC1_MASK 0x0010000000000000UL
+#define UV1H_EVENT_OCCURRED0_RTC2_SHFT 53
+#define UV1H_EVENT_OCCURRED0_RTC2_MASK 0x0020000000000000UL
+#define UV1H_EVENT_OCCURRED0_RTC3_SHFT 54
+#define UV1H_EVENT_OCCURRED0_RTC3_MASK 0x0040000000000000UL
+#define UV1H_EVENT_OCCURRED0_BAU_DATA_SHFT 55
+#define UV1H_EVENT_OCCURRED0_BAU_DATA_MASK 0x0080000000000000UL
+#define UV1H_EVENT_OCCURRED0_POWER_MANAGEMENT_REQ_SHFT 56
+#define UV1H_EVENT_OCCURRED0_POWER_MANAGEMENT_REQ_MASK 0x0100000000000000UL
+
+#define UV2H_EVENT_OCCURRED0_LB_HCERR_SHFT 0
+#define UV2H_EVENT_OCCURRED0_LB_HCERR_MASK 0x0000000000000001UL
+#define UV2H_EVENT_OCCURRED0_QP_HCERR_SHFT 1
+#define UV2H_EVENT_OCCURRED0_QP_HCERR_MASK 0x0000000000000002UL
+#define UV2H_EVENT_OCCURRED0_RH_HCERR_SHFT 2
+#define UV2H_EVENT_OCCURRED0_RH_HCERR_MASK 0x0000000000000004UL
+#define UV2H_EVENT_OCCURRED0_LH0_HCERR_SHFT 3
+#define UV2H_EVENT_OCCURRED0_LH0_HCERR_MASK 0x0000000000000008UL
+#define UV2H_EVENT_OCCURRED0_LH1_HCERR_SHFT 4
+#define UV2H_EVENT_OCCURRED0_LH1_HCERR_MASK 0x0000000000000010UL
+#define UV2H_EVENT_OCCURRED0_GR0_HCERR_SHFT 5
+#define UV2H_EVENT_OCCURRED0_GR0_HCERR_MASK 0x0000000000000020UL
+#define UV2H_EVENT_OCCURRED0_GR1_HCERR_SHFT 6
+#define UV2H_EVENT_OCCURRED0_GR1_HCERR_MASK 0x0000000000000040UL
+#define UV2H_EVENT_OCCURRED0_NI0_HCERR_SHFT 7
+#define UV2H_EVENT_OCCURRED0_NI0_HCERR_MASK 0x0000000000000080UL
+#define UV2H_EVENT_OCCURRED0_NI1_HCERR_SHFT 8
+#define UV2H_EVENT_OCCURRED0_NI1_HCERR_MASK 0x0000000000000100UL
+#define UV2H_EVENT_OCCURRED0_LB_AOERR0_SHFT 9
+#define UV2H_EVENT_OCCURRED0_LB_AOERR0_MASK 0x0000000000000200UL
+#define UV2H_EVENT_OCCURRED0_QP_AOERR0_SHFT 10
+#define UV2H_EVENT_OCCURRED0_QP_AOERR0_MASK 0x0000000000000400UL
+#define UV2H_EVENT_OCCURRED0_RH_AOERR0_SHFT 11
+#define UV2H_EVENT_OCCURRED0_RH_AOERR0_MASK 0x0000000000000800UL
+#define UV2H_EVENT_OCCURRED0_LH0_AOERR0_SHFT 12
+#define UV2H_EVENT_OCCURRED0_LH0_AOERR0_MASK 0x0000000000001000UL
+#define UV2H_EVENT_OCCURRED0_LH1_AOERR0_SHFT 13
+#define UV2H_EVENT_OCCURRED0_LH1_AOERR0_MASK 0x0000000000002000UL
+#define UV2H_EVENT_OCCURRED0_GR0_AOERR0_SHFT 14
+#define UV2H_EVENT_OCCURRED0_GR0_AOERR0_MASK 0x0000000000004000UL
+#define UV2H_EVENT_OCCURRED0_GR1_AOERR0_SHFT 15
+#define UV2H_EVENT_OCCURRED0_GR1_AOERR0_MASK 0x0000000000008000UL
+#define UV2H_EVENT_OCCURRED0_XB_AOERR0_SHFT 16
+#define UV2H_EVENT_OCCURRED0_XB_AOERR0_MASK 0x0000000000010000UL
+#define UV2H_EVENT_OCCURRED0_RT_AOERR0_SHFT 17
+#define UV2H_EVENT_OCCURRED0_RT_AOERR0_MASK 0x0000000000020000UL
+#define UV2H_EVENT_OCCURRED0_NI0_AOERR0_SHFT 18
+#define UV2H_EVENT_OCCURRED0_NI0_AOERR0_MASK 0x0000000000040000UL
+#define UV2H_EVENT_OCCURRED0_NI1_AOERR0_SHFT 19
+#define UV2H_EVENT_OCCURRED0_NI1_AOERR0_MASK 0x0000000000080000UL
+#define UV2H_EVENT_OCCURRED0_LB_AOERR1_SHFT 20
+#define UV2H_EVENT_OCCURRED0_LB_AOERR1_MASK 0x0000000000100000UL
+#define UV2H_EVENT_OCCURRED0_QP_AOERR1_SHFT 21
+#define UV2H_EVENT_OCCURRED0_QP_AOERR1_MASK 0x0000000000200000UL
+#define UV2H_EVENT_OCCURRED0_RH_AOERR1_SHFT 22
+#define UV2H_EVENT_OCCURRED0_RH_AOERR1_MASK 0x0000000000400000UL
+#define UV2H_EVENT_OCCURRED0_LH0_AOERR1_SHFT 23
+#define UV2H_EVENT_OCCURRED0_LH0_AOERR1_MASK 0x0000000000800000UL
+#define UV2H_EVENT_OCCURRED0_LH1_AOERR1_SHFT 24
+#define UV2H_EVENT_OCCURRED0_LH1_AOERR1_MASK 0x0000000001000000UL
+#define UV2H_EVENT_OCCURRED0_GR0_AOERR1_SHFT 25
+#define UV2H_EVENT_OCCURRED0_GR0_AOERR1_MASK 0x0000000002000000UL
+#define UV2H_EVENT_OCCURRED0_GR1_AOERR1_SHFT 26
+#define UV2H_EVENT_OCCURRED0_GR1_AOERR1_MASK 0x0000000004000000UL
+#define UV2H_EVENT_OCCURRED0_XB_AOERR1_SHFT 27
+#define UV2H_EVENT_OCCURRED0_XB_AOERR1_MASK 0x0000000008000000UL
+#define UV2H_EVENT_OCCURRED0_RT_AOERR1_SHFT 28
+#define UV2H_EVENT_OCCURRED0_RT_AOERR1_MASK 0x0000000010000000UL
+#define UV2H_EVENT_OCCURRED0_NI0_AOERR1_SHFT 29
+#define UV2H_EVENT_OCCURRED0_NI0_AOERR1_MASK 0x0000000020000000UL
+#define UV2H_EVENT_OCCURRED0_NI1_AOERR1_SHFT 30
+#define UV2H_EVENT_OCCURRED0_NI1_AOERR1_MASK 0x0000000040000000UL
+#define UV2H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT 31
+#define UV2H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK 0x0000000080000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT 32
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK 0x0000000100000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT 33
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK 0x0000000200000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT 34
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK 0x0000000400000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT 35
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK 0x0000000800000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT 36
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK 0x0000001000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT 37
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK 0x0000002000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT 38
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK 0x0000004000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT 39
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK 0x0000008000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT 40
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK 0x0000010000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT 41
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK 0x0000020000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT 42
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK 0x0000040000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT 43
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK 0x0000080000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT 44
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK 0x0000100000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT 45
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK 0x0000200000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT 46
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK 0x0000400000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT 47
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK 0x0000800000000000UL
+#define UV2H_EVENT_OCCURRED0_L1_NMI_INT_SHFT 48
+#define UV2H_EVENT_OCCURRED0_L1_NMI_INT_MASK 0x0001000000000000UL
+#define UV2H_EVENT_OCCURRED0_STOP_CLOCK_SHFT 49
+#define UV2H_EVENT_OCCURRED0_STOP_CLOCK_MASK 0x0002000000000000UL
+#define UV2H_EVENT_OCCURRED0_ASIC_TO_L1_SHFT 50
+#define UV2H_EVENT_OCCURRED0_ASIC_TO_L1_MASK 0x0004000000000000UL
+#define UV2H_EVENT_OCCURRED0_L1_TO_ASIC_SHFT 51
+#define UV2H_EVENT_OCCURRED0_L1_TO_ASIC_MASK 0x0008000000000000UL
+#define UV2H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT 52
+#define UV2H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK 0x0010000000000000UL
+#define UV2H_EVENT_OCCURRED0_IPI_INT_SHFT 53
+#define UV2H_EVENT_OCCURRED0_IPI_INT_MASK 0x0020000000000000UL
+#define UV2H_EVENT_OCCURRED0_EXTIO_INT0_SHFT 54
+#define UV2H_EVENT_OCCURRED0_EXTIO_INT0_MASK 0x0040000000000000UL
+#define UV2H_EVENT_OCCURRED0_EXTIO_INT1_SHFT 55
+#define UV2H_EVENT_OCCURRED0_EXTIO_INT1_MASK 0x0080000000000000UL
+#define UV2H_EVENT_OCCURRED0_EXTIO_INT2_SHFT 56
+#define UV2H_EVENT_OCCURRED0_EXTIO_INT2_MASK 0x0100000000000000UL
+#define UV2H_EVENT_OCCURRED0_EXTIO_INT3_SHFT 57
+#define UV2H_EVENT_OCCURRED0_EXTIO_INT3_MASK 0x0200000000000000UL
+#define UV2H_EVENT_OCCURRED0_PROFILE_INT_SHFT 58
+#define UV2H_EVENT_OCCURRED0_PROFILE_INT_MASK 0x0400000000000000UL
+
 union uvh_event_occurred0_u {
     unsigned long      v;
-    struct uvh_event_occurred0_s {
+    struct uv1h_event_occurred0_s {
        unsigned long   lb_hcerr             :  1;  /* RW, W1C */
        unsigned long   gr0_hcerr            :  1;  /* RW, W1C */
        unsigned long   gr1_hcerr            :  1;  /* RW, W1C */
@@ -250,14 +421,76 @@ union uvh_event_occurred0_u {
        unsigned long   bau_data             :  1;  /* RW, W1C */
        unsigned long   power_management_req :  1;  /* RW, W1C */
        unsigned long   rsvd_57_63           :  7;  /*    */
-    } s;
+    } s1;
+    struct uv2h_event_occurred0_s {
+       unsigned long   lb_hcerr            :  1;  /* RW */
+       unsigned long   qp_hcerr            :  1;  /* RW */
+       unsigned long   rh_hcerr            :  1;  /* RW */
+       unsigned long   lh0_hcerr           :  1;  /* RW */
+       unsigned long   lh1_hcerr           :  1;  /* RW */
+       unsigned long   gr0_hcerr           :  1;  /* RW */
+       unsigned long   gr1_hcerr           :  1;  /* RW */
+       unsigned long   ni0_hcerr           :  1;  /* RW */
+       unsigned long   ni1_hcerr           :  1;  /* RW */
+       unsigned long   lb_aoerr0           :  1;  /* RW */
+       unsigned long   qp_aoerr0           :  1;  /* RW */
+       unsigned long   rh_aoerr0           :  1;  /* RW */
+       unsigned long   lh0_aoerr0          :  1;  /* RW */
+       unsigned long   lh1_aoerr0          :  1;  /* RW */
+       unsigned long   gr0_aoerr0          :  1;  /* RW */
+       unsigned long   gr1_aoerr0          :  1;  /* RW */
+       unsigned long   xb_aoerr0           :  1;  /* RW */
+       unsigned long   rt_aoerr0           :  1;  /* RW */
+       unsigned long   ni0_aoerr0          :  1;  /* RW */
+       unsigned long   ni1_aoerr0          :  1;  /* RW */
+       unsigned long   lb_aoerr1           :  1;  /* RW */
+       unsigned long   qp_aoerr1           :  1;  /* RW */
+       unsigned long   rh_aoerr1           :  1;  /* RW */
+       unsigned long   lh0_aoerr1          :  1;  /* RW */
+       unsigned long   lh1_aoerr1          :  1;  /* RW */
+       unsigned long   gr0_aoerr1          :  1;  /* RW */
+       unsigned long   gr1_aoerr1          :  1;  /* RW */
+       unsigned long   xb_aoerr1           :  1;  /* RW */
+       unsigned long   rt_aoerr1           :  1;  /* RW */
+       unsigned long   ni0_aoerr1          :  1;  /* RW */
+       unsigned long   ni1_aoerr1          :  1;  /* RW */
+       unsigned long   system_shutdown_int :  1;  /* RW */
+       unsigned long   lb_irq_int_0        :  1;  /* RW */
+       unsigned long   lb_irq_int_1        :  1;  /* RW */
+       unsigned long   lb_irq_int_2        :  1;  /* RW */
+       unsigned long   lb_irq_int_3        :  1;  /* RW */
+       unsigned long   lb_irq_int_4        :  1;  /* RW */
+       unsigned long   lb_irq_int_5        :  1;  /* RW */
+       unsigned long   lb_irq_int_6        :  1;  /* RW */
+       unsigned long   lb_irq_int_7        :  1;  /* RW */
+       unsigned long   lb_irq_int_8        :  1;  /* RW */
+       unsigned long   lb_irq_int_9        :  1;  /* RW */
+       unsigned long   lb_irq_int_10       :  1;  /* RW */
+       unsigned long   lb_irq_int_11       :  1;  /* RW */
+       unsigned long   lb_irq_int_12       :  1;  /* RW */
+       unsigned long   lb_irq_int_13       :  1;  /* RW */
+       unsigned long   lb_irq_int_14       :  1;  /* RW */
+       unsigned long   lb_irq_int_15       :  1;  /* RW */
+       unsigned long   l1_nmi_int          :  1;  /* RW */
+       unsigned long   stop_clock          :  1;  /* RW */
+       unsigned long   asic_to_l1          :  1;  /* RW */
+       unsigned long   l1_to_asic          :  1;  /* RW */
+       unsigned long   la_seq_trigger      :  1;  /* RW */
+       unsigned long   ipi_int             :  1;  /* RW */
+       unsigned long   extio_int0          :  1;  /* RW */
+       unsigned long   extio_int1          :  1;  /* RW */
+       unsigned long   extio_int2          :  1;  /* RW */
+       unsigned long   extio_int3          :  1;  /* RW */
+       unsigned long   profile_int         :  1;  /* RW */
+       unsigned long   rsvd_59_63          :  5;  /*    */
+    } s2;
 };
 
 /* ========================================================================= */
 /*                        UVH_EVENT_OCCURRED0_ALIAS                          */
 /* ========================================================================= */
 #define UVH_EVENT_OCCURRED0_ALIAS 0x0000000000070008UL
-#define UVH_EVENT_OCCURRED0_ALIAS_32 0x005f0
+#define UVH_EVENT_OCCURRED0_ALIAS_32 0x5f0
 
 /* ========================================================================= */
 /*                         UVH_GR0_TLB_INT0_CONFIG                           */
@@ -432,8 +665,16 @@ union uvh_int_cmpb_u {
 /* ========================================================================= */
 #define UVH_INT_CMPC 0x22100UL
 
-#define UVH_INT_CMPC_REAL_TIME_CMPC_SHFT 0
-#define UVH_INT_CMPC_REAL_TIME_CMPC_MASK 0x00ffffffffffffffUL
+#define UV1H_INT_CMPC_REAL_TIME_CMPC_SHFT      0
+#define UV2H_INT_CMPC_REAL_TIME_CMPC_SHFT      0
+#define UVH_INT_CMPC_REAL_TIME_CMPC_SHFT       (is_uv1_hub() ?         \
+                       UV1H_INT_CMPC_REAL_TIME_CMPC_SHFT :     \
+                       UV2H_INT_CMPC_REAL_TIME_CMPC_SHFT)
+#define UV1H_INT_CMPC_REAL_TIME_CMPC_MASK      0xffffffffffffffUL
+#define UV2H_INT_CMPC_REAL_TIME_CMPC_MASK      0xffffffffffffffUL
+#define UVH_INT_CMPC_REAL_TIME_CMPC_MASK       (is_uv1_hub() ?         \
+                       UV1H_INT_CMPC_REAL_TIME_CMPC_MASK :     \
+                       UV2H_INT_CMPC_REAL_TIME_CMPC_MASK)
 
 union uvh_int_cmpc_u {
     unsigned long      v;
@@ -448,8 +689,16 @@ union uvh_int_cmpc_u {
 /* ========================================================================= */
 #define UVH_INT_CMPD 0x22180UL
 
-#define UVH_INT_CMPD_REAL_TIME_CMPD_SHFT 0
-#define UVH_INT_CMPD_REAL_TIME_CMPD_MASK 0x00ffffffffffffffUL
+#define UV1H_INT_CMPD_REAL_TIME_CMPD_SHFT      0
+#define UV2H_INT_CMPD_REAL_TIME_CMPD_SHFT      0
+#define UVH_INT_CMPD_REAL_TIME_CMPD_SHFT       (is_uv1_hub() ?         \
+                       UV1H_INT_CMPD_REAL_TIME_CMPD_SHFT :     \
+                       UV2H_INT_CMPD_REAL_TIME_CMPD_SHFT)
+#define UV1H_INT_CMPD_REAL_TIME_CMPD_MASK      0xffffffffffffffUL
+#define UV2H_INT_CMPD_REAL_TIME_CMPD_MASK      0xffffffffffffffUL
+#define UVH_INT_CMPD_REAL_TIME_CMPD_MASK       (is_uv1_hub() ?         \
+                       UV1H_INT_CMPD_REAL_TIME_CMPD_MASK :     \
+                       UV2H_INT_CMPD_REAL_TIME_CMPD_MASK)
 
 union uvh_int_cmpd_u {
     unsigned long      v;
@@ -463,7 +712,7 @@ union uvh_int_cmpd_u {
 /*                               UVH_IPI_INT                                 */
 /* ========================================================================= */
 #define UVH_IPI_INT 0x60500UL
-#define UVH_IPI_INT_32 0x0348
+#define UVH_IPI_INT_32 0x348
 
 #define UVH_IPI_INT_VECTOR_SHFT 0
 #define UVH_IPI_INT_VECTOR_MASK 0x00000000000000ffUL
@@ -493,7 +742,7 @@ union uvh_ipi_int_u {
 /*                   UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST                     */
 /* ========================================================================= */
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST 0x320050UL
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_32 0x009c0
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_32 0x9c0
 
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_ADDRESS_SHFT 4
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_ADDRESS_MASK 0x000007fffffffff0UL
@@ -515,7 +764,7 @@ union uvh_lb_bau_intd_payload_queue_first_u {
 /*                    UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST                     */
 /* ========================================================================= */
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST 0x320060UL
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_32 0x009c8
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_32 0x9c8
 
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_ADDRESS_SHFT 4
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_ADDRESS_MASK 0x000007fffffffff0UL
@@ -533,7 +782,7 @@ union uvh_lb_bau_intd_payload_queue_last_u {
 /*                    UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL                     */
 /* ========================================================================= */
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL 0x320070UL
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_32 0x009d0
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_32 0x9d0
 
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_ADDRESS_SHFT 4
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_ADDRESS_MASK 0x000007fffffffff0UL
@@ -551,7 +800,7 @@ union uvh_lb_bau_intd_payload_queue_tail_u {
 /*                   UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE                    */
 /* ========================================================================= */
 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE 0x320080UL
-#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_32 0x0a68
+#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_32 0xa68
 
 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_0_SHFT 0
 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_0_MASK 0x0000000000000001UL
@@ -585,6 +834,7 @@ union uvh_lb_bau_intd_payload_queue_tail_u {
 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_6_MASK 0x0000000000004000UL
 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_7_SHFT 15
 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_7_MASK 0x0000000000008000UL
+
 union uvh_lb_bau_intd_software_acknowledge_u {
     unsigned long      v;
     struct uvh_lb_bau_intd_software_acknowledge_s {
@@ -612,13 +862,13 @@ union uvh_lb_bau_intd_software_acknowledge_u {
 /*                UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS                 */
 /* ========================================================================= */
 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS 0x0000000000320088UL
-#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS_32 0x0a70
+#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS_32 0xa70
 
 /* ========================================================================= */
 /*                         UVH_LB_BAU_MISC_CONTROL                           */
 /* ========================================================================= */
 #define UVH_LB_BAU_MISC_CONTROL 0x320170UL
-#define UVH_LB_BAU_MISC_CONTROL_32 0x00a10
+#define UVH_LB_BAU_MISC_CONTROL_32 0xa10
 
 #define UVH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT 0
 #define UVH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK 0x00000000000000ffUL
@@ -628,8 +878,8 @@ union uvh_lb_bau_intd_software_acknowledge_u {
 #define UVH_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK 0x0000000000000200UL
 #define UVH_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT 10
 #define UVH_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK 0x0000000000000400UL
-#define UVH_LB_BAU_MISC_CONTROL_CSI_AGENT_PRESENCE_VECTOR_SHFT 11
-#define UVH_LB_BAU_MISC_CONTROL_CSI_AGENT_PRESENCE_VECTOR_MASK 0x0000000000003800UL
+#define UVH_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_SHFT 11
+#define UVH_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_MASK 0x0000000000003800UL
 #define UVH_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14
 #define UVH_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_MASK 0x0000000000004000UL
 #define UVH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT 15
@@ -650,8 +900,86 @@ union uvh_lb_bau_intd_software_acknowledge_u {
 #define UVH_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_MASK 0x0000000008000000UL
 #define UVH_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28
 #define UVH_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL
-#define UVH_LB_BAU_MISC_CONTROL_FUN_SHFT 48
-#define UVH_LB_BAU_MISC_CONTROL_FUN_MASK 0xffff000000000000UL
+
+#define UV1H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT 0
+#define UV1H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK 0x00000000000000ffUL
+#define UV1H_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT 8
+#define UV1H_LB_BAU_MISC_CONTROL_APIC_MODE_MASK 0x0000000000000100UL
+#define UV1H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT 9
+#define UV1H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK 0x0000000000000200UL
+#define UV1H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT 10
+#define UV1H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK 0x0000000000000400UL
+#define UV1H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_SHFT 11
+#define UV1H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_MASK 0x0000000000003800UL
+#define UV1H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14
+#define UV1H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_MASK 0x0000000000004000UL
+#define UV1H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT 15
+#define UV1H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_MASK 0x0000000000008000UL
+#define UV1H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT 16
+#define UV1H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK 0x00000000000f0000UL
+#define UV1H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_SHFT 20
+#define UV1H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_MASK 0x0000000000100000UL
+#define UV1H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_SHFT 21
+#define UV1H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_MASK 0x0000000000200000UL
+#define UV1H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_SHFT 22
+#define UV1H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_MASK 0x0000000000400000UL
+#define UV1H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_SHFT 23
+#define UV1H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_MASK 0x0000000000800000UL
+#define UV1H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24
+#define UV1H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000007000000UL
+#define UV1H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27
+#define UV1H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_MASK 0x0000000008000000UL
+#define UV1H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28
+#define UV1H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL
+#define UV1H_LB_BAU_MISC_CONTROL_FUN_SHFT 48
+#define UV1H_LB_BAU_MISC_CONTROL_FUN_MASK 0xffff000000000000UL
+
+#define UV2H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT 0
+#define UV2H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK 0x00000000000000ffUL
+#define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT 8
+#define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_MASK 0x0000000000000100UL
+#define UV2H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT 9
+#define UV2H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK 0x0000000000000200UL
+#define UV2H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT 10
+#define UV2H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK 0x0000000000000400UL
+#define UV2H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_SHFT 11
+#define UV2H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_MASK 0x0000000000003800UL
+#define UV2H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14
+#define UV2H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_MASK 0x0000000000004000UL
+#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT 15
+#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_MASK 0x0000000000008000UL
+#define UV2H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT 16
+#define UV2H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK 0x00000000000f0000UL
+#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_SHFT 20
+#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_MASK 0x0000000000100000UL
+#define UV2H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_SHFT 21
+#define UV2H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_MASK 0x0000000000200000UL
+#define UV2H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_SHFT 22
+#define UV2H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_MASK 0x0000000000400000UL
+#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_SHFT 23
+#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_MASK 0x0000000000800000UL
+#define UV2H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24
+#define UV2H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000007000000UL
+#define UV2H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27
+#define UV2H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_MASK 0x0000000008000000UL
+#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28
+#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL
+#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_SHFT 29
+#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_MASK 0x0000000020000000UL
+#define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_SHFT 30
+#define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_MASK 0x0000000040000000UL
+#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_SHFT 31
+#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_MASK 0x0000000080000000UL
+#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_SHFT 32
+#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_MASK 0x0000000100000000UL
+#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_SHFT 33
+#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_MASK 0x0000000200000000UL
+#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_SHFT 34
+#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_MASK 0x0000000400000000UL
+#define UV2H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_SHFT 35
+#define UV2H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_MASK 0x0000000800000000UL
+#define UV2H_LB_BAU_MISC_CONTROL_FUN_SHFT 48
+#define UV2H_LB_BAU_MISC_CONTROL_FUN_MASK 0xffff000000000000UL
 
 union uvh_lb_bau_misc_control_u {
     unsigned long      v;
@@ -660,7 +988,25 @@ union uvh_lb_bau_misc_control_u {
        unsigned long   apic_mode                          :  1;  /* RW */
        unsigned long   force_broadcast                    :  1;  /* RW */
        unsigned long   force_lock_nop                     :  1;  /* RW */
-       unsigned long   csi_agent_presence_vector          :  3;  /* RW */
+       unsigned long   qpi_agent_presence_vector          :  3;  /* RW */
+       unsigned long   descriptor_fetch_mode              :  1;  /* RW */
+       unsigned long   enable_intd_soft_ack_mode          :  1;  /* RW */
+       unsigned long   intd_soft_ack_timeout_period       :  4;  /* RW */
+       unsigned long   enable_dual_mapping_mode           :  1;  /* RW */
+       unsigned long   vga_io_port_decode_enable          :  1;  /* RW */
+       unsigned long   vga_io_port_16_bit_decode          :  1;  /* RW */
+       unsigned long   suppress_dest_registration         :  1;  /* RW */
+       unsigned long   programmed_initial_priority        :  3;  /* RW */
+       unsigned long   use_incoming_priority              :  1;  /* RW */
+       unsigned long   enable_programmed_initial_priority :  1;  /* RW */
+       unsigned long   rsvd_29_63    : 35;
+    } s;
+    struct uv1h_lb_bau_misc_control_s {
+       unsigned long   rejection_delay                    :  8;  /* RW */
+       unsigned long   apic_mode                          :  1;  /* RW */
+       unsigned long   force_broadcast                    :  1;  /* RW */
+       unsigned long   force_lock_nop                     :  1;  /* RW */
+       unsigned long   qpi_agent_presence_vector          :  3;  /* RW */
        unsigned long   descriptor_fetch_mode              :  1;  /* RW */
        unsigned long   enable_intd_soft_ack_mode          :  1;  /* RW */
        unsigned long   intd_soft_ack_timeout_period       :  4;  /* RW */
@@ -673,14 +1019,40 @@ union uvh_lb_bau_misc_control_u {
        unsigned long   enable_programmed_initial_priority :  1;  /* RW */
        unsigned long   rsvd_29_47                         : 19;  /*    */
        unsigned long   fun                                : 16;  /* RW */
-    } s;
+    } s1;
+    struct uv2h_lb_bau_misc_control_s {
+       unsigned long   rejection_delay                      :  8;  /* RW */
+       unsigned long   apic_mode                            :  1;  /* RW */
+       unsigned long   force_broadcast                      :  1;  /* RW */
+       unsigned long   force_lock_nop                       :  1;  /* RW */
+       unsigned long   qpi_agent_presence_vector            :  3;  /* RW */
+       unsigned long   descriptor_fetch_mode                :  1;  /* RW */
+       unsigned long   enable_intd_soft_ack_mode            :  1;  /* RW */
+       unsigned long   intd_soft_ack_timeout_period         :  4;  /* RW */
+       unsigned long   enable_dual_mapping_mode             :  1;  /* RW */
+       unsigned long   vga_io_port_decode_enable            :  1;  /* RW */
+       unsigned long   vga_io_port_16_bit_decode            :  1;  /* RW */
+       unsigned long   suppress_dest_registration           :  1;  /* RW */
+       unsigned long   programmed_initial_priority          :  3;  /* RW */
+       unsigned long   use_incoming_priority                :  1;  /* RW */
+       unsigned long   enable_programmed_initial_priority   :  1;  /* RW */
+       unsigned long   enable_automatic_apic_mode_selection :  1;  /* RW */
+       unsigned long   apic_mode_status                     :  1;  /* RO */
+       unsigned long   suppress_interrupts_to_self          :  1;  /* RW */
+       unsigned long   enable_lock_based_system_flush       :  1;  /* RW */
+       unsigned long   enable_extended_sb_status            :  1;  /* RW */
+       unsigned long   suppress_int_prio_udt_to_self        :  1;  /* RW */
+       unsigned long   use_legacy_descriptor_formats        :  1;  /* RW */
+       unsigned long   rsvd_36_47                           : 12;  /*    */
+       unsigned long   fun                                  : 16;  /* RW */
+    } s2;
 };
 
 /* ========================================================================= */
 /*                     UVH_LB_BAU_SB_ACTIVATION_CONTROL                      */
 /* ========================================================================= */
 #define UVH_LB_BAU_SB_ACTIVATION_CONTROL 0x320020UL
-#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_32 0x009a8
+#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_32 0x9a8
 
 #define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INDEX_SHFT 0
 #define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INDEX_MASK 0x000000000000003fUL
@@ -703,7 +1075,7 @@ union uvh_lb_bau_sb_activation_control_u {
 /*                    UVH_LB_BAU_SB_ACTIVATION_STATUS_0                      */
 /* ========================================================================= */
 #define UVH_LB_BAU_SB_ACTIVATION_STATUS_0 0x320030UL
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_32 0x009b0
+#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_32 0x9b0
 
 #define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_STATUS_SHFT 0
 #define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_STATUS_MASK 0xffffffffffffffffUL
@@ -719,7 +1091,7 @@ union uvh_lb_bau_sb_activation_status_0_u {
 /*                    UVH_LB_BAU_SB_ACTIVATION_STATUS_1                      */
 /* ========================================================================= */
 #define UVH_LB_BAU_SB_ACTIVATION_STATUS_1 0x320040UL
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_32 0x009b8
+#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_32 0x9b8
 
 #define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_STATUS_SHFT 0
 #define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_STATUS_MASK 0xffffffffffffffffUL
@@ -735,7 +1107,7 @@ union uvh_lb_bau_sb_activation_status_1_u {
 /*                      UVH_LB_BAU_SB_DESCRIPTOR_BASE                        */
 /* ========================================================================= */
 #define UVH_LB_BAU_SB_DESCRIPTOR_BASE 0x320010UL
-#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_32 0x009a0
+#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_32 0x9a0
 
 #define UVH_LB_BAU_SB_DESCRIPTOR_BASE_PAGE_ADDRESS_SHFT 12
 #define UVH_LB_BAU_SB_DESCRIPTOR_BASE_PAGE_ADDRESS_MASK 0x000007fffffff000UL
@@ -753,23 +1125,6 @@ union uvh_lb_bau_sb_descriptor_base_u {
     } s;
 };
 
-/* ========================================================================= */
-/*                   UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK                     */
-/* ========================================================================= */
-#define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK 0x320130UL
-#define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK_32 0x009f0
-
-#define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK_BIT_ENABLES_SHFT 0
-#define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK_BIT_ENABLES_MASK 0x00000000ffffffffUL
-
-union uvh_lb_target_physical_apic_id_mask_u {
-       unsigned long v;
-       struct uvh_lb_target_physical_apic_id_mask_s {
-               unsigned long bit_enables : 32;  /* RW */
-               unsigned long rsvd_32_63  : 32;  /*    */
-       } s;
-};
-
 /* ========================================================================= */
 /*                               UVH_NODE_ID                                 */
 /* ========================================================================= */
@@ -785,14 +1140,48 @@ union uvh_lb_target_physical_apic_id_mask_u {
 #define UVH_NODE_ID_REVISION_MASK 0x00000000f0000000UL
 #define UVH_NODE_ID_NODE_ID_SHFT 32
 #define UVH_NODE_ID_NODE_ID_MASK 0x00007fff00000000UL
-#define UVH_NODE_ID_NODES_PER_BIT_SHFT 48
-#define UVH_NODE_ID_NODES_PER_BIT_MASK 0x007f000000000000UL
-#define UVH_NODE_ID_NI_PORT_SHFT 56
-#define UVH_NODE_ID_NI_PORT_MASK 0x0f00000000000000UL
+
+#define UV1H_NODE_ID_FORCE1_SHFT 0
+#define UV1H_NODE_ID_FORCE1_MASK 0x0000000000000001UL
+#define UV1H_NODE_ID_MANUFACTURER_SHFT 1
+#define UV1H_NODE_ID_MANUFACTURER_MASK 0x0000000000000ffeUL
+#define UV1H_NODE_ID_PART_NUMBER_SHFT 12
+#define UV1H_NODE_ID_PART_NUMBER_MASK 0x000000000ffff000UL
+#define UV1H_NODE_ID_REVISION_SHFT 28
+#define UV1H_NODE_ID_REVISION_MASK 0x00000000f0000000UL
+#define UV1H_NODE_ID_NODE_ID_SHFT 32
+#define UV1H_NODE_ID_NODE_ID_MASK 0x00007fff00000000UL
+#define UV1H_NODE_ID_NODES_PER_BIT_SHFT 48
+#define UV1H_NODE_ID_NODES_PER_BIT_MASK 0x007f000000000000UL
+#define UV1H_NODE_ID_NI_PORT_SHFT 56
+#define UV1H_NODE_ID_NI_PORT_MASK 0x0f00000000000000UL
+
+#define UV2H_NODE_ID_FORCE1_SHFT 0
+#define UV2H_NODE_ID_FORCE1_MASK 0x0000000000000001UL
+#define UV2H_NODE_ID_MANUFACTURER_SHFT 1
+#define UV2H_NODE_ID_MANUFACTURER_MASK 0x0000000000000ffeUL
+#define UV2H_NODE_ID_PART_NUMBER_SHFT 12
+#define UV2H_NODE_ID_PART_NUMBER_MASK 0x000000000ffff000UL
+#define UV2H_NODE_ID_REVISION_SHFT 28
+#define UV2H_NODE_ID_REVISION_MASK 0x00000000f0000000UL
+#define UV2H_NODE_ID_NODE_ID_SHFT 32
+#define UV2H_NODE_ID_NODE_ID_MASK 0x00007fff00000000UL
+#define UV2H_NODE_ID_NODES_PER_BIT_SHFT 50
+#define UV2H_NODE_ID_NODES_PER_BIT_MASK 0x01fc000000000000UL
+#define UV2H_NODE_ID_NI_PORT_SHFT 57
+#define UV2H_NODE_ID_NI_PORT_MASK 0x3e00000000000000UL
 
 union uvh_node_id_u {
     unsigned long      v;
     struct uvh_node_id_s {
+       unsigned long   force1        :  1;  /* RO */
+       unsigned long   manufacturer  : 11;  /* RO */
+       unsigned long   part_number   : 16;  /* RO */
+       unsigned long   revision      :  4;  /* RO */
+       unsigned long   node_id       : 15;  /* RW */
+       unsigned long   rsvd_47_63    : 17;
+    } s;
+    struct uv1h_node_id_s {
        unsigned long   force1        :  1;  /* RO */
        unsigned long   manufacturer  : 11;  /* RO */
        unsigned long   part_number   : 16;  /* RO */
@@ -803,7 +1192,18 @@ union uvh_node_id_u {
        unsigned long   rsvd_55       :  1;  /*    */
        unsigned long   ni_port       :  4;  /* RO */
        unsigned long   rsvd_60_63    :  4;  /*    */
-    } s;
+    } s1;
+    struct uv2h_node_id_s {
+       unsigned long   force1        :  1;  /* RO */
+       unsigned long   manufacturer  : 11;  /* RO */
+       unsigned long   part_number   : 16;  /* RO */
+       unsigned long   revision      :  4;  /* RO */
+       unsigned long   node_id       : 15;  /* RW */
+       unsigned long   rsvd_47_49    :  3;  /*    */
+       unsigned long   nodes_per_bit :  7;  /* RO */
+       unsigned long   ni_port       :  5;  /* RO */
+       unsigned long   rsvd_62_63    :  2;  /*    */
+    } s2;
 };
 
 /* ========================================================================= */
@@ -954,18 +1354,38 @@ union uvh_rh_gam_alias210_redirect_config_2_mmr_u {
 #define UVH_RH_GAM_CONFIG_MMR_M_SKT_MASK 0x000000000000003fUL
 #define UVH_RH_GAM_CONFIG_MMR_N_SKT_SHFT 6
 #define UVH_RH_GAM_CONFIG_MMR_N_SKT_MASK 0x00000000000003c0UL
-#define UVH_RH_GAM_CONFIG_MMR_MMIOL_CFG_SHFT 12
-#define UVH_RH_GAM_CONFIG_MMR_MMIOL_CFG_MASK 0x0000000000001000UL
+
+#define UV1H_RH_GAM_CONFIG_MMR_M_SKT_SHFT 0
+#define UV1H_RH_GAM_CONFIG_MMR_M_SKT_MASK 0x000000000000003fUL
+#define UV1H_RH_GAM_CONFIG_MMR_N_SKT_SHFT 6
+#define UV1H_RH_GAM_CONFIG_MMR_N_SKT_MASK 0x00000000000003c0UL
+#define UV1H_RH_GAM_CONFIG_MMR_MMIOL_CFG_SHFT 12
+#define UV1H_RH_GAM_CONFIG_MMR_MMIOL_CFG_MASK 0x0000000000001000UL
+
+#define UV2H_RH_GAM_CONFIG_MMR_M_SKT_SHFT 0
+#define UV2H_RH_GAM_CONFIG_MMR_M_SKT_MASK 0x000000000000003fUL
+#define UV2H_RH_GAM_CONFIG_MMR_N_SKT_SHFT 6
+#define UV2H_RH_GAM_CONFIG_MMR_N_SKT_MASK 0x00000000000003c0UL
 
 union uvh_rh_gam_config_mmr_u {
     unsigned long      v;
     struct uvh_rh_gam_config_mmr_s {
+       unsigned long   m_skt     :  6;  /* RW */
+       unsigned long   n_skt     :  4;  /* RW */
+       unsigned long   rsvd_10_63    : 54;
+    } s;
+    struct uv1h_rh_gam_config_mmr_s {
        unsigned long   m_skt     :  6;  /* RW */
        unsigned long   n_skt     :  4;  /* RW */
        unsigned long   rsvd_10_11:  2;  /*    */
        unsigned long   mmiol_cfg :  1;  /* RW */
        unsigned long   rsvd_13_63: 51;  /*    */
-    } s;
+    } s1;
+    struct uv2h_rh_gam_config_mmr_s {
+       unsigned long   m_skt :  6;  /* RW */
+       unsigned long   n_skt :  4;  /* RW */
+       unsigned long   rsvd_10_63: 54;  /*    */
+    } s2;
 };
 
 /* ========================================================================= */
@@ -975,16 +1395,32 @@ union uvh_rh_gam_config_mmr_u {
 
 #define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT 28
 #define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffff0000000UL
-#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_GR4_SHFT 48
-#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_GR4_MASK 0x0001000000000000UL
-#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT 52
-#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK 0x00f0000000000000UL
-#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
-#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+
+#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT 28
+#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffff0000000UL
+#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_GR4_SHFT 48
+#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_GR4_MASK 0x0001000000000000UL
+#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT 52
+#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK 0x00f0000000000000UL
+#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
+#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+
+#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT 28
+#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffff0000000UL
+#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT 52
+#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK 0x00f0000000000000UL
+#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
+#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
 
 union uvh_rh_gam_gru_overlay_config_mmr_u {
     unsigned long      v;
     struct uvh_rh_gam_gru_overlay_config_mmr_s {
+       unsigned long   rsvd_0_27: 28;  /*    */
+       unsigned long   base   : 18;  /* RW */
+       unsigned long   rsvd_46_62    : 17;
+       unsigned long   enable :  1;  /* RW */
+    } s;
+    struct uv1h_rh_gam_gru_overlay_config_mmr_s {
        unsigned long   rsvd_0_27: 28;  /*    */
        unsigned long   base   : 18;  /* RW */
        unsigned long   rsvd_46_47:  2;  /*    */
@@ -993,7 +1429,15 @@ union uvh_rh_gam_gru_overlay_config_mmr_u {
        unsigned long   n_gru  :  4;  /* RW */
        unsigned long   rsvd_56_62:  7;  /*    */
        unsigned long   enable :  1;  /* RW */
-    } s;
+    } s1;
+    struct uv2h_rh_gam_gru_overlay_config_mmr_s {
+       unsigned long   rsvd_0_27: 28;  /*    */
+       unsigned long   base   : 18;  /* RW */
+       unsigned long   rsvd_46_51:  6;  /*    */
+       unsigned long   n_gru  :  4;  /* RW */
+       unsigned long   rsvd_56_62:  7;  /*    */
+       unsigned long   enable :  1;  /* RW */
+    } s2;
 };
 
 /* ========================================================================= */
@@ -1001,25 +1445,42 @@ union uvh_rh_gam_gru_overlay_config_mmr_u {
 /* ========================================================================= */
 #define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR 0x1600030UL
 
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT 30
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003fffc0000000UL
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_SHFT 46
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_MASK 0x000fc00000000000UL
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_SHFT 52
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_MASK 0x00f0000000000000UL
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT 30
+#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003fffc0000000UL
+#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_SHFT 46
+#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_MASK 0x000fc00000000000UL
+#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_SHFT 52
+#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_MASK 0x00f0000000000000UL
+#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
+#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT 27
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffff8000000UL
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_SHFT 46
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_MASK 0x000fc00000000000UL
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_SHFT 52
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_MASK 0x00f0000000000000UL
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
 
 union uvh_rh_gam_mmioh_overlay_config_mmr_u {
     unsigned long      v;
-    struct uvh_rh_gam_mmioh_overlay_config_mmr_s {
+    struct uv1h_rh_gam_mmioh_overlay_config_mmr_s {
        unsigned long   rsvd_0_29: 30;  /*    */
        unsigned long   base   : 16;  /* RW */
        unsigned long   m_io   :  6;  /* RW */
        unsigned long   n_io   :  4;  /* RW */
        unsigned long   rsvd_56_62:  7;  /*    */
        unsigned long   enable :  1;  /* RW */
-    } s;
+    } s1;
+    struct uv2h_rh_gam_mmioh_overlay_config_mmr_s {
+       unsigned long   rsvd_0_26: 27;  /*    */
+       unsigned long   base   : 19;  /* RW */
+       unsigned long   m_io   :  6;  /* RW */
+       unsigned long   n_io   :  4;  /* RW */
+       unsigned long   rsvd_56_62:  7;  /*    */
+       unsigned long   enable :  1;  /* RW */
+    } s2;
 };
 
 /* ========================================================================= */
@@ -1029,20 +1490,40 @@ union uvh_rh_gam_mmioh_overlay_config_mmr_u {
 
 #define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT 26
 #define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffffc000000UL
-#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_DUAL_HUB_SHFT 46
-#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_DUAL_HUB_MASK 0x0000400000000000UL
-#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
-#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+
+#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT 26
+#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffffc000000UL
+#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_DUAL_HUB_SHFT 46
+#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_DUAL_HUB_MASK 0x0000400000000000UL
+#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
+#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+
+#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT 26
+#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffffc000000UL
+#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
+#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
 
 union uvh_rh_gam_mmr_overlay_config_mmr_u {
     unsigned long      v;
     struct uvh_rh_gam_mmr_overlay_config_mmr_s {
+       unsigned long   rsvd_0_25: 26;  /*    */
+       unsigned long   base     : 20;  /* RW */
+       unsigned long   rsvd_46_62    : 17;
+       unsigned long   enable   :  1;  /* RW */
+    } s;
+    struct uv1h_rh_gam_mmr_overlay_config_mmr_s {
        unsigned long   rsvd_0_25: 26;  /*    */
        unsigned long   base     : 20;  /* RW */
        unsigned long   dual_hub :  1;  /* RW */
        unsigned long   rsvd_47_62: 16;  /*    */
        unsigned long   enable   :  1;  /* RW */
-    } s;
+    } s1;
+    struct uv2h_rh_gam_mmr_overlay_config_mmr_s {
+       unsigned long   rsvd_0_25: 26;  /*    */
+       unsigned long   base   : 20;  /* RW */
+       unsigned long   rsvd_46_62: 17;  /*    */
+       unsigned long   enable :  1;  /* RW */
+    } s2;
 };
 
 /* ========================================================================= */
@@ -1103,10 +1584,11 @@ union uvh_rtc1_int_config_u {
 /*                               UVH_SCRATCH5                                */
 /* ========================================================================= */
 #define UVH_SCRATCH5 0x2d0200UL
-#define UVH_SCRATCH5_32 0x00778
+#define UVH_SCRATCH5_32 0x778
 
 #define UVH_SCRATCH5_SCRATCH5_SHFT 0
 #define UVH_SCRATCH5_SCRATCH5_MASK 0xffffffffffffffffUL
+
 union uvh_scratch5_u {
     unsigned long      v;
     struct uvh_scratch5_s {
@@ -1114,4 +1596,154 @@ union uvh_scratch5_u {
     } s;
 };
 
+/* ========================================================================= */
+/*                           UV2H_EVENT_OCCURRED2                            */
+/* ========================================================================= */
+#define UV2H_EVENT_OCCURRED2 0x70100UL
+#define UV2H_EVENT_OCCURRED2_32 0xb68
+
+#define UV2H_EVENT_OCCURRED2_RTC_0_SHFT 0
+#define UV2H_EVENT_OCCURRED2_RTC_0_MASK 0x0000000000000001UL
+#define UV2H_EVENT_OCCURRED2_RTC_1_SHFT 1
+#define UV2H_EVENT_OCCURRED2_RTC_1_MASK 0x0000000000000002UL
+#define UV2H_EVENT_OCCURRED2_RTC_2_SHFT 2
+#define UV2H_EVENT_OCCURRED2_RTC_2_MASK 0x0000000000000004UL
+#define UV2H_EVENT_OCCURRED2_RTC_3_SHFT 3
+#define UV2H_EVENT_OCCURRED2_RTC_3_MASK 0x0000000000000008UL
+#define UV2H_EVENT_OCCURRED2_RTC_4_SHFT 4
+#define UV2H_EVENT_OCCURRED2_RTC_4_MASK 0x0000000000000010UL
+#define UV2H_EVENT_OCCURRED2_RTC_5_SHFT 5
+#define UV2H_EVENT_OCCURRED2_RTC_5_MASK 0x0000000000000020UL
+#define UV2H_EVENT_OCCURRED2_RTC_6_SHFT 6
+#define UV2H_EVENT_OCCURRED2_RTC_6_MASK 0x0000000000000040UL
+#define UV2H_EVENT_OCCURRED2_RTC_7_SHFT 7
+#define UV2H_EVENT_OCCURRED2_RTC_7_MASK 0x0000000000000080UL
+#define UV2H_EVENT_OCCURRED2_RTC_8_SHFT 8
+#define UV2H_EVENT_OCCURRED2_RTC_8_MASK 0x0000000000000100UL
+#define UV2H_EVENT_OCCURRED2_RTC_9_SHFT 9
+#define UV2H_EVENT_OCCURRED2_RTC_9_MASK 0x0000000000000200UL
+#define UV2H_EVENT_OCCURRED2_RTC_10_SHFT 10
+#define UV2H_EVENT_OCCURRED2_RTC_10_MASK 0x0000000000000400UL
+#define UV2H_EVENT_OCCURRED2_RTC_11_SHFT 11
+#define UV2H_EVENT_OCCURRED2_RTC_11_MASK 0x0000000000000800UL
+#define UV2H_EVENT_OCCURRED2_RTC_12_SHFT 12
+#define UV2H_EVENT_OCCURRED2_RTC_12_MASK 0x0000000000001000UL
+#define UV2H_EVENT_OCCURRED2_RTC_13_SHFT 13
+#define UV2H_EVENT_OCCURRED2_RTC_13_MASK 0x0000000000002000UL
+#define UV2H_EVENT_OCCURRED2_RTC_14_SHFT 14
+#define UV2H_EVENT_OCCURRED2_RTC_14_MASK 0x0000000000004000UL
+#define UV2H_EVENT_OCCURRED2_RTC_15_SHFT 15
+#define UV2H_EVENT_OCCURRED2_RTC_15_MASK 0x0000000000008000UL
+#define UV2H_EVENT_OCCURRED2_RTC_16_SHFT 16
+#define UV2H_EVENT_OCCURRED2_RTC_16_MASK 0x0000000000010000UL
+#define UV2H_EVENT_OCCURRED2_RTC_17_SHFT 17
+#define UV2H_EVENT_OCCURRED2_RTC_17_MASK 0x0000000000020000UL
+#define UV2H_EVENT_OCCURRED2_RTC_18_SHFT 18
+#define UV2H_EVENT_OCCURRED2_RTC_18_MASK 0x0000000000040000UL
+#define UV2H_EVENT_OCCURRED2_RTC_19_SHFT 19
+#define UV2H_EVENT_OCCURRED2_RTC_19_MASK 0x0000000000080000UL
+#define UV2H_EVENT_OCCURRED2_RTC_20_SHFT 20
+#define UV2H_EVENT_OCCURRED2_RTC_20_MASK 0x0000000000100000UL
+#define UV2H_EVENT_OCCURRED2_RTC_21_SHFT 21
+#define UV2H_EVENT_OCCURRED2_RTC_21_MASK 0x0000000000200000UL
+#define UV2H_EVENT_OCCURRED2_RTC_22_SHFT 22
+#define UV2H_EVENT_OCCURRED2_RTC_22_MASK 0x0000000000400000UL
+#define UV2H_EVENT_OCCURRED2_RTC_23_SHFT 23
+#define UV2H_EVENT_OCCURRED2_RTC_23_MASK 0x0000000000800000UL
+#define UV2H_EVENT_OCCURRED2_RTC_24_SHFT 24
+#define UV2H_EVENT_OCCURRED2_RTC_24_MASK 0x0000000001000000UL
+#define UV2H_EVENT_OCCURRED2_RTC_25_SHFT 25
+#define UV2H_EVENT_OCCURRED2_RTC_25_MASK 0x0000000002000000UL
+#define UV2H_EVENT_OCCURRED2_RTC_26_SHFT 26
+#define UV2H_EVENT_OCCURRED2_RTC_26_MASK 0x0000000004000000UL
+#define UV2H_EVENT_OCCURRED2_RTC_27_SHFT 27
+#define UV2H_EVENT_OCCURRED2_RTC_27_MASK 0x0000000008000000UL
+#define UV2H_EVENT_OCCURRED2_RTC_28_SHFT 28
+#define UV2H_EVENT_OCCURRED2_RTC_28_MASK 0x0000000010000000UL
+#define UV2H_EVENT_OCCURRED2_RTC_29_SHFT 29
+#define UV2H_EVENT_OCCURRED2_RTC_29_MASK 0x0000000020000000UL
+#define UV2H_EVENT_OCCURRED2_RTC_30_SHFT 30
+#define UV2H_EVENT_OCCURRED2_RTC_30_MASK 0x0000000040000000UL
+#define UV2H_EVENT_OCCURRED2_RTC_31_SHFT 31
+#define UV2H_EVENT_OCCURRED2_RTC_31_MASK 0x0000000080000000UL
+
+union uv2h_event_occurred2_u {
+    unsigned long      v;
+    struct uv2h_event_occurred2_s {
+       unsigned long   rtc_0  :  1;  /* RW */
+       unsigned long   rtc_1  :  1;  /* RW */
+       unsigned long   rtc_2  :  1;  /* RW */
+       unsigned long   rtc_3  :  1;  /* RW */
+       unsigned long   rtc_4  :  1;  /* RW */
+       unsigned long   rtc_5  :  1;  /* RW */
+       unsigned long   rtc_6  :  1;  /* RW */
+       unsigned long   rtc_7  :  1;  /* RW */
+       unsigned long   rtc_8  :  1;  /* RW */
+       unsigned long   rtc_9  :  1;  /* RW */
+       unsigned long   rtc_10 :  1;  /* RW */
+       unsigned long   rtc_11 :  1;  /* RW */
+       unsigned long   rtc_12 :  1;  /* RW */
+       unsigned long   rtc_13 :  1;  /* RW */
+       unsigned long   rtc_14 :  1;  /* RW */
+       unsigned long   rtc_15 :  1;  /* RW */
+       unsigned long   rtc_16 :  1;  /* RW */
+       unsigned long   rtc_17 :  1;  /* RW */
+       unsigned long   rtc_18 :  1;  /* RW */
+       unsigned long   rtc_19 :  1;  /* RW */
+       unsigned long   rtc_20 :  1;  /* RW */
+       unsigned long   rtc_21 :  1;  /* RW */
+       unsigned long   rtc_22 :  1;  /* RW */
+       unsigned long   rtc_23 :  1;  /* RW */
+       unsigned long   rtc_24 :  1;  /* RW */
+       unsigned long   rtc_25 :  1;  /* RW */
+       unsigned long   rtc_26 :  1;  /* RW */
+       unsigned long   rtc_27 :  1;  /* RW */
+       unsigned long   rtc_28 :  1;  /* RW */
+       unsigned long   rtc_29 :  1;  /* RW */
+       unsigned long   rtc_30 :  1;  /* RW */
+       unsigned long   rtc_31 :  1;  /* RW */
+       unsigned long   rsvd_32_63: 32;  /*    */
+    } s1;
+};
+
+/* ========================================================================= */
+/*                        UV2H_EVENT_OCCURRED2_ALIAS                         */
+/* ========================================================================= */
+#define UV2H_EVENT_OCCURRED2_ALIAS 0x70108UL
+#define UV2H_EVENT_OCCURRED2_ALIAS_32 0xb70
+
+/* ========================================================================= */
+/*                    UV2H_LB_BAU_SB_ACTIVATION_STATUS_2                     */
+/* ========================================================================= */
+#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2 0x320130UL
+#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_32 0x9f0
+
+#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_SHFT 0
+#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_MASK 0xffffffffffffffffUL
+
+union uv2h_lb_bau_sb_activation_status_2_u {
+    unsigned long      v;
+    struct uv2h_lb_bau_sb_activation_status_2_s {
+       unsigned long   aux_error : 64;  /* RW */
+    } s1;
+};
+
+/* ========================================================================= */
+/*                   UV1H_LB_TARGET_PHYSICAL_APIC_ID_MASK                    */
+/* ========================================================================= */
+#define UV1H_LB_TARGET_PHYSICAL_APIC_ID_MASK 0x320130UL
+#define UV1H_LB_TARGET_PHYSICAL_APIC_ID_MASK_32 0x9f0
+
+#define UV1H_LB_TARGET_PHYSICAL_APIC_ID_MASK_BIT_ENABLES_SHFT 0
+#define UV1H_LB_TARGET_PHYSICAL_APIC_ID_MASK_BIT_ENABLES_MASK 0x00000000ffffffffUL
+
+union uv1h_lb_target_physical_apic_id_mask_u {
+    unsigned long      v;
+    struct uv1h_lb_target_physical_apic_id_mask_s {
+       unsigned long   bit_enables : 32;  /* RW */
+       unsigned long   rsvd_32_63  : 32;  /*    */
+    } s1;
+};
+
+
 #endif /* __ASM_UV_MMRS_X86_H__ */
index 9064052b73ded033f961c2756a981ad1789678f0..bb0522850b74c2ae780b6c81981efde9f76f2aa3 100644 (file)
@@ -1,20 +1,6 @@
 #ifndef _ASM_X86_VDSO_H
 #define _ASM_X86_VDSO_H
 
-#ifdef CONFIG_X86_64
-extern const char VDSO64_PRELINK[];
-
-/*
- * Given a pointer to the vDSO image, find the pointer to VDSO64_name
- * as that symbol is defined in the vDSO sources or linker script.
- */
-#define VDSO64_SYMBOL(base, name)                                      \
-({                                                                     \
-       extern const char VDSO64_##name[];                              \
-       (void *)(VDSO64_##name - VDSO64_PRELINK + (unsigned long)(base)); \
-})
-#endif
-
 #if defined CONFIG_X86_32 || defined CONFIG_COMPAT
 extern const char VDSO32_PRELINK[];
 
index 3d61e204826f1da5b6cb747957818a0e7b2d3913..646b4c1ca6958f351d9138cfea58840f4b1c3ae6 100644 (file)
@@ -23,8 +23,6 @@ struct vsyscall_gtod_data {
        struct timespec wall_to_monotonic;
        struct timespec wall_time_coarse;
 };
-extern struct vsyscall_gtod_data __vsyscall_gtod_data
-__section_vsyscall_gtod_data;
 extern struct vsyscall_gtod_data vsyscall_gtod_data;
 
 #endif /* _ASM_X86_VGTOD_H */
index d0983d255fbdd13d1830bd8e9aa39cbd8c8ceae5..d55597351f6a5ab4a558a02b3f09830152232840 100644 (file)
@@ -16,27 +16,19 @@ enum vsyscall_num {
 #ifdef __KERNEL__
 #include <linux/seqlock.h>
 
-#define __section_vgetcpu_mode __attribute__ ((unused, __section__ (".vgetcpu_mode"), aligned(16)))
-#define __section_jiffies __attribute__ ((unused, __section__ (".jiffies"), aligned(16)))
-
 /* Definitions for CONFIG_GENERIC_TIME definitions */
-#define __section_vsyscall_gtod_data __attribute__ \
-       ((unused, __section__ (".vsyscall_gtod_data"),aligned(16)))
-#define __section_vsyscall_clock __attribute__ \
-       ((unused, __section__ (".vsyscall_clock"),aligned(16)))
 #define __vsyscall_fn \
        __attribute__ ((unused, __section__(".vsyscall_fn"))) notrace
 
 #define VGETCPU_RDTSCP 1
 #define VGETCPU_LSL    2
 
-extern int __vgetcpu_mode;
-extern volatile unsigned long __jiffies;
-
 /* kernel space (writeable) */
 extern int vgetcpu_mode;
 extern struct timezone sys_tz;
 
+#include <asm/vvar.h>
+
 extern void map_vsyscall(void);
 
 #endif /* __KERNEL__ */
diff --git a/arch/x86/include/asm/vvar.h b/arch/x86/include/asm/vvar.h
new file mode 100644 (file)
index 0000000..341b355
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * vvar.h: Shared vDSO/kernel variable declarations
+ * Copyright (c) 2011 Andy Lutomirski
+ * Subject to the GNU General Public License, version 2
+ *
+ * A handful of variables are accessible (read-only) from userspace
+ * code in the vsyscall page and the vdso.  They are declared here.
+ * Some other file must define them with DEFINE_VVAR.
+ *
+ * In normal kernel code, they are used like any other variable.
+ * In user code, they are accessed through the VVAR macro.
+ *
+ * Each of these variables lives in the vsyscall page, and each
+ * one needs a unique offset within the little piece of the page
+ * reserved for vvars.  Specify that offset in DECLARE_VVAR.
+ * (There are 896 bytes available.  If you mess up, the linker will
+ * catch it.)
+ */
+
+/* Offset of vars within vsyscall page */
+#define VSYSCALL_VARS_OFFSET (3072 + 128)
+
+#if defined(__VVAR_KERNEL_LDS)
+
+/* The kernel linker script defines its own magic to put vvars in the
+ * right place.
+ */
+#define DECLARE_VVAR(offset, type, name) \
+       EMIT_VVAR(name, VSYSCALL_VARS_OFFSET + offset)
+
+#else
+
+#define DECLARE_VVAR(offset, type, name)                               \
+       static type const * const vvaraddr_ ## name =                   \
+               (void *)(VSYSCALL_START + VSYSCALL_VARS_OFFSET + (offset));
+
+#define DEFINE_VVAR(type, name)                                                \
+       type __vvar_ ## name                                            \
+       __attribute__((section(".vsyscall_var_" #name), aligned(16)))
+
+#define VVAR(name) (*vvaraddr_ ## name)
+
+#endif
+
+/* DECLARE_VVAR(offset, type, name) */
+
+DECLARE_VVAR(0, volatile unsigned long, jiffies)
+DECLARE_VVAR(8, int, vgetcpu_mode)
+DECLARE_VVAR(128, struct vsyscall_gtod_data, vsyscall_gtod_data)
+
+#undef DECLARE_VVAR
+#undef VSYSCALL_VARS_OFFSET
index 8508bfe52296b18b5b3164acff6e2cf449a31792..d240ea950519343231514be75f4e6a6cea15dd8f 100644 (file)
@@ -447,6 +447,13 @@ HYPERVISOR_hvm_op(int op, void *arg)
        return _hypercall2(unsigned long, hvm_op, op, arg);
 }
 
+static inline int
+HYPERVISOR_tmem_op(
+       struct tmem_op *op)
+{
+       return _hypercall1(int, tmem_op, op);
+}
+
 static inline void
 MULTI_fpu_taskswitch(struct multicall_entry *mcl, int set)
 {
index 250806472a7e07373c7bf5cd66acfc8bca81d032..90b06d4daee252e758f72af1d4566c5c58fbd5a6 100644 (file)
@@ -24,13 +24,17 @@ endif
 nostackp := $(call cc-option, -fno-stack-protector)
 CFLAGS_vsyscall_64.o   := $(PROFILING) -g0 $(nostackp)
 CFLAGS_hpet.o          := $(nostackp)
-CFLAGS_tsc.o           := $(nostackp)
+CFLAGS_vread_tsc_64.o  := $(nostackp)
 CFLAGS_paravirt.o      := $(nostackp)
 GCOV_PROFILE_vsyscall_64.o     := n
 GCOV_PROFILE_hpet.o            := n
 GCOV_PROFILE_tsc.o             := n
+GCOV_PROFILE_vread_tsc_64.o    := n
 GCOV_PROFILE_paravirt.o                := n
 
+# vread_tsc_64 is hot and should be fully optimized:
+CFLAGS_REMOVE_vread_tsc_64.o = -pg -fno-optimize-sibling-calls
+
 obj-y                  := process_$(BITS).o signal.o entry_$(BITS).o
 obj-y                  += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
 obj-y                  += time.o ioport.o ldt.o dumpstack.o
@@ -39,7 +43,7 @@ obj-$(CONFIG_IRQ_WORK)  += irq_work.o
 obj-y                  += probe_roms.o
 obj-$(CONFIG_X86_32)   += sys_i386_32.o i386_ksyms_32.o
 obj-$(CONFIG_X86_64)   += sys_x86_64.o x8664_ksyms_64.o
-obj-$(CONFIG_X86_64)   += syscall_64.o vsyscall_64.o
+obj-$(CONFIG_X86_64)   += syscall_64.o vsyscall_64.o vread_tsc_64.o
 obj-y                  += bootflag.o e820.o
 obj-y                  += pci-dma.o quirks.o topology.o kdebugfs.o
 obj-y                  += alternative.o i8253.o pci-nommu.o hw_breakpoint.o
index cd8cbeb5fa34f4ed685d9247995846e4c2d0fd32..7c3a95e54ec57cae2f9dd96a831bc5b7f53a6f69 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/proto.h>
 #include <asm/iommu.h>
 #include <asm/gart.h>
+#include <asm/dma.h>
 #include <asm/amd_iommu_proto.h>
 #include <asm/amd_iommu_types.h>
 #include <asm/amd_iommu.h>
@@ -154,6 +155,10 @@ static int iommu_init_device(struct device *dev)
        pdev = pci_get_bus_and_slot(PCI_BUS(alias), alias & 0xff);
        if (pdev)
                dev_data->alias = &pdev->dev;
+       else {
+               kfree(dev_data);
+               return -ENOTSUPP;
+       }
 
        atomic_set(&dev_data->bind, 0);
 
@@ -163,6 +168,20 @@ static int iommu_init_device(struct device *dev)
        return 0;
 }
 
+static void iommu_ignore_device(struct device *dev)
+{
+       u16 devid, alias;
+
+       devid = get_device_id(dev);
+       alias = amd_iommu_alias_table[devid];
+
+       memset(&amd_iommu_dev_table[devid], 0, sizeof(struct dev_table_entry));
+       memset(&amd_iommu_dev_table[alias], 0, sizeof(struct dev_table_entry));
+
+       amd_iommu_rlookup_table[devid] = NULL;
+       amd_iommu_rlookup_table[alias] = NULL;
+}
+
 static void iommu_uninit_device(struct device *dev)
 {
        kfree(dev->archdata.iommu);
@@ -192,7 +211,9 @@ int __init amd_iommu_init_devices(void)
                        continue;
 
                ret = iommu_init_device(&pdev->dev);
-               if (ret)
+               if (ret == -ENOTSUPP)
+                       iommu_ignore_device(&pdev->dev);
+               else if (ret)
                        goto out_free;
        }
 
@@ -2383,6 +2404,23 @@ static struct dma_map_ops amd_iommu_dma_ops = {
        .dma_supported = amd_iommu_dma_supported,
 };
 
+static unsigned device_dma_ops_init(void)
+{
+       struct pci_dev *pdev = NULL;
+       unsigned unhandled = 0;
+
+       for_each_pci_dev(pdev) {
+               if (!check_device(&pdev->dev)) {
+                       unhandled += 1;
+                       continue;
+               }
+
+               pdev->dev.archdata.dma_ops = &amd_iommu_dma_ops;
+       }
+
+       return unhandled;
+}
+
 /*
  * The function which clues the AMD IOMMU driver into dma_ops.
  */
@@ -2395,7 +2433,7 @@ void __init amd_iommu_init_api(void)
 int __init amd_iommu_init_dma_ops(void)
 {
        struct amd_iommu *iommu;
-       int ret;
+       int ret, unhandled;
 
        /*
         * first allocate a default protection domain for every IOMMU we
@@ -2421,7 +2459,11 @@ int __init amd_iommu_init_dma_ops(void)
        swiotlb = 0;
 
        /* Make the driver finally visible to the drivers */
-       dma_ops = &amd_iommu_dma_ops;
+       unhandled = device_dma_ops_init();
+       if (unhandled && max_pfn > MAX_DMA32_PFN) {
+               /* There are unhandled devices - initialize swiotlb for them */
+               swiotlb = 1;
+       }
 
        amd_iommu_stats_init();
 
index 9179c21120a88ea5e764297fc5c91c6a488fb51c..bfc8453bd98dfae4bd62620e1ebd20a9151b9ea3 100644 (file)
@@ -731,8 +731,8 @@ static void __init init_iommu_from_acpi(struct amd_iommu *iommu,
 {
        u8 *p = (u8 *)h;
        u8 *end = p, flags = 0;
-       u16 dev_i, devid = 0, devid_start = 0, devid_to = 0;
-       u32 ext_flags = 0;
+       u16 devid = 0, devid_start = 0, devid_to = 0;
+       u32 dev_i, ext_flags = 0;
        bool alias = false;
        struct ivhd_entry *e;
 
@@ -887,7 +887,7 @@ static void __init init_iommu_from_acpi(struct amd_iommu *iommu,
 /* Initializes the device->iommu mapping for the driver */
 static int __init init_iommu_devices(struct amd_iommu *iommu)
 {
-       u16 i;
+       u32 i;
 
        for (i = iommu->first_device; i <= iommu->last_device; ++i)
                set_iommu_for_device(iommu, i);
@@ -1177,7 +1177,7 @@ static int __init init_memory_definitions(struct acpi_table_header *table)
  */
 static void init_device_table(void)
 {
-       u16 devid;
+       u32 devid;
 
        for (devid = 0; devid <= amd_iommu_last_bdf; ++devid) {
                set_dev_entry_bit(devid, DEV_ENTRY_VALID);
index b961af86bfea214d273a392b69cf0e359e2a3a83..b9338b8cf420ca94e37c7da64dc1fa1910f19f91 100644 (file)
@@ -390,7 +390,8 @@ static unsigned int reserve_eilvt_offset(int offset, unsigned int new)
 
 /*
  * If mask=1, the LVT entry does not generate interrupts while mask=0
- * enables the vector. See also the BKDGs.
+ * enables the vector. See also the BKDGs. Must be called with
+ * preemption disabled.
  */
 
 int setup_APIC_eilvt(u8 offset, u8 vector, u8 msg_type, u8 mask)
index 9488dcff7aec8261b994076cdd59638da5097f73..e5293394b548426b2ec26f577825d71fe73465c0 100644 (file)
@@ -676,7 +676,7 @@ void mask_ioapic_entries(void)
        int apic, pin;
 
        for (apic = 0; apic < nr_ioapics; apic++) {
-               if (ioapics[apic].saved_registers)
+               if (!ioapics[apic].saved_registers)
                        continue;
 
                for (pin = 0; pin < ioapics[apic].nr_registers; pin++) {
@@ -699,7 +699,7 @@ int restore_ioapic_entries(void)
        int apic, pin;
 
        for (apic = 0; apic < nr_ioapics; apic++) {
-               if (ioapics[apic].saved_registers)
+               if (!ioapics[apic].saved_registers)
                        continue;
 
                for (pin = 0; pin < ioapics[apic].nr_registers; pin++)
index f450b683dfcf4672f87669877f4de6ad7cb596bc..adc66c3a1fef2417be8741d334d5f8460c23ff10 100644 (file)
@@ -91,6 +91,10 @@ static int __init early_get_pnodeid(void)
        m_n_config.v = uv_early_read_mmr(UVH_RH_GAM_CONFIG_MMR);
        uv_min_hub_revision_id = node_id.s.revision;
 
+       if (node_id.s.part_number == UV2_HUB_PART_NUMBER)
+               uv_min_hub_revision_id += UV2_HUB_REVISION_BASE - 1;
+
+       uv_hub_info->hub_revision = uv_min_hub_revision_id;
        pnode = (node_id.s.node_id >> 1) & ((1 << m_n_config.s.n_skt) - 1);
        return pnode;
 }
@@ -112,17 +116,25 @@ static void __init early_get_apic_pnode_shift(void)
  */
 static void __init uv_set_apicid_hibit(void)
 {
-       union uvh_lb_target_physical_apic_id_mask_u apicid_mask;
+       union uv1h_lb_target_physical_apic_id_mask_u apicid_mask;
 
-       apicid_mask.v = uv_early_read_mmr(UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK);
-       uv_apicid_hibits = apicid_mask.s.bit_enables & UV_APICID_HIBIT_MASK;
+       if (is_uv1_hub()) {
+               apicid_mask.v =
+                       uv_early_read_mmr(UV1H_LB_TARGET_PHYSICAL_APIC_ID_MASK);
+               uv_apicid_hibits =
+                       apicid_mask.s1.bit_enables & UV_APICID_HIBIT_MASK;
+       }
 }
 
 static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
-       int pnodeid;
+       int pnodeid, is_uv1, is_uv2;
 
-       if (!strcmp(oem_id, "SGI")) {
+       is_uv1 = !strcmp(oem_id, "SGI");
+       is_uv2 = !strcmp(oem_id, "SGI2");
+       if (is_uv1 || is_uv2) {
+               uv_hub_info->hub_revision =
+                       is_uv1 ? UV1_HUB_REVISION_BASE : UV2_HUB_REVISION_BASE;
                pnodeid = early_get_pnodeid();
                early_get_apic_pnode_shift();
                x86_platform.is_untracked_pat_range =  uv_is_untracked_pat_range;
@@ -484,12 +496,19 @@ static __init void map_mmr_high(int max_pnode)
 static __init void map_mmioh_high(int max_pnode)
 {
        union uvh_rh_gam_mmioh_overlay_config_mmr_u mmioh;
-       int shift = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT;
+       int shift;
 
        mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR);
-       if (mmioh.s.enable)
-               map_high("MMIOH", mmioh.s.base, shift, mmioh.s.m_io,
+       if (is_uv1_hub() && mmioh.s1.enable) {
+               shift = UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT;
+               map_high("MMIOH", mmioh.s1.base, shift, mmioh.s1.m_io,
+                       max_pnode, map_uc);
+       }
+       if (is_uv2_hub() && mmioh.s2.enable) {
+               shift = UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT;
+               map_high("MMIOH", mmioh.s2.base, shift, mmioh.s2.m_io,
                        max_pnode, map_uc);
+       }
 }
 
 static __init void map_low_mmrs(void)
@@ -613,14 +632,14 @@ late_initcall(uv_init_heartbeat);
 
 /* Direct Legacy VGA I/O traffic to designated IOH */
 int uv_set_vga_state(struct pci_dev *pdev, bool decode,
-                     unsigned int command_bits, bool change_bridge)
+                     unsigned int command_bits, u32 flags)
 {
        int domain, bus, rc;
 
-       PR_DEVEL("devfn %x decode %d cmd %x chg_brdg %d\n",
-                       pdev->devfn, decode, command_bits, change_bridge);
+       PR_DEVEL("devfn %x decode %d cmd %x flags %d\n",
+                       pdev->devfn, decode, command_bits, flags);
 
-       if (!change_bridge)
+       if (!(flags & PCI_VGA_STATE_CHANGE_BRIDGE))
                return 0;
 
        if ((command_bits & PCI_COMMAND_IO) == 0)
@@ -736,13 +755,14 @@ void __init uv_system_init(void)
        unsigned long mmr_base, present, paddr;
        unsigned short pnode_mask, pnode_io_mask;
 
+       printk(KERN_INFO "UV: Found %s hub\n", is_uv1_hub() ? "UV1" : "UV2");
        map_low_mmrs();
 
        m_n_config.v = uv_read_local_mmr(UVH_RH_GAM_CONFIG_MMR );
        m_val = m_n_config.s.m_skt;
        n_val = m_n_config.s.n_skt;
        mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR);
-       n_io = mmioh.s.n_io;
+       n_io = is_uv1_hub() ? mmioh.s1.n_io : mmioh.s2.n_io;
        mmr_base =
            uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) &
            ~UV_MMR_ENABLE;
@@ -811,6 +831,8 @@ void __init uv_system_init(void)
                 */
                uv_cpu_hub_info(cpu)->pnode_mask = pnode_mask;
                uv_cpu_hub_info(cpu)->apic_pnode_shift = uvh_apicid.s.pnode_shift;
+               uv_cpu_hub_info(cpu)->hub_revision = uv_hub_info->hub_revision;
+
                pnode = uv_apicid_to_pnode(apicid);
                blade = boot_pnode_to_blade(pnode);
                lcpu = uv_blade_info[blade].nr_possible_cpus;
index 3bfa022359659d26a609cc4c951ea8e3865609b7..965a7666c283a5180e29f5c40e9de28097b2c8c1 100644 (file)
@@ -361,6 +361,7 @@ struct apm_user {
  * idle percentage above which bios idle calls are done
  */
 #ifdef CONFIG_APM_CPU_IDLE
+#warning deprecated CONFIG_APM_CPU_IDLE will be deleted in 2012
 #define DEFAULT_IDLE_THRESHOLD 95
 #else
 #define DEFAULT_IDLE_THRESHOLD 100
@@ -904,6 +905,7 @@ static void apm_cpu_idle(void)
        unsigned int jiffies_since_last_check = jiffies - last_jiffies;
        unsigned int bucket;
 
+       WARN_ONCE(1, "deprecated apm_cpu_idle will be deleted in 2012");
 recalc:
        if (jiffies_since_last_check > IDLE_CALC_LIMIT) {
                use_apm_idle = 0;
index 8f5cabb3c5b055c41c0aa41fd4a37d227c06bfb0..b13ed393dfcee83b330443e378a922ed016d0514 100644 (file)
@@ -612,8 +612,11 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
        }
 #endif
 
-       /* As a rule processors have APIC timer running in deep C states */
-       if (c->x86 > 0xf && !cpu_has_amd_erratum(amd_erratum_400))
+       /*
+        * Family 0x12 and above processors have APIC timer
+        * running in deep C states.
+        */
+       if (c->x86 > 0x11)
                set_cpu_cap(c, X86_FEATURE_ARAT);
 
        /*
index c39576cb3018507f2d359521741c1764778b68f7..525514cf33c308aff9d29e66d274207e7f4e8308 100644 (file)
@@ -19,6 +19,7 @@
 
 static int __init no_halt(char *s)
 {
+       WARN_ONCE(1, "\"no-hlt\" is deprecated, please use \"idle=poll\"\n");
        boot_cpu_data.hlt_works_ok = 0;
        return 1;
 }
index c8b41623377f14462a248b245ffab97792e9409c..22a073d7fbff25df173d42ef710d67da1a70c077 100644 (file)
@@ -477,13 +477,6 @@ void __cpuinit detect_ht(struct cpuinfo_x86 *c)
        if (smp_num_siblings <= 1)
                goto out;
 
-       if (smp_num_siblings > nr_cpu_ids) {
-               pr_warning("CPU: Unsupported number of siblings %d",
-                          smp_num_siblings);
-               smp_num_siblings = 1;
-               return;
-       }
-
        index_msb = get_count_order(smp_num_siblings);
        c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid, index_msb);
 
@@ -909,7 +902,7 @@ static void vgetcpu_set_mode(void)
 void __init identify_boot_cpu(void)
 {
        identify_cpu(&boot_cpu_data);
-       init_c1e_mask();
+       init_amd_e400_c1e_mask();
 #ifdef CONFIG_X86_32
        sysenter_setup();
        enable_sep_cpu();
index 690bc8461835bc01fb6f6cf436fcd94a960db9f2..9aeb78a23de4658fb279787a75c391a6c603c1e9 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/of_pci.h>
+#include <linux/initrd.h>
 
 #include <asm/hpet.h>
 #include <asm/irq_controller.h>
@@ -98,6 +99,16 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
        return __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS));
 }
 
+#ifdef CONFIG_BLK_DEV_INITRD
+void __init early_init_dt_setup_initrd_arch(unsigned long start,
+                                           unsigned long end)
+{
+       initrd_start = (unsigned long)__va(start);
+       initrd_end = (unsigned long)__va(end);
+       initrd_below_start_ok = 1;
+}
+#endif
+
 void __init add_dtb(u64 data)
 {
        initial_dtb = data + offsetof(struct setup_data, data);
index 0ba15a6cc57eeacc3944c09f8e894b3a9348a54f..c9a281f272fd994423e830131dbdfffd6ee6510a 100644 (file)
@@ -123,7 +123,7 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
 static atomic_t nmi_running = ATOMIC_INIT(0);
 static int mod_code_status;            /* holds return value of text write */
 static void *mod_code_ip;              /* holds the IP to write to */
-static void *mod_code_newcode;         /* holds the text to write to the IP */
+static const void *mod_code_newcode;   /* holds the text to write to the IP */
 
 static unsigned nmi_wait_count;
 static atomic_t nmi_update_count = ATOMIC_INIT(0);
@@ -225,7 +225,7 @@ within(unsigned long addr, unsigned long start, unsigned long end)
 }
 
 static int
-do_ftrace_mod_code(unsigned long ip, void *new_code)
+do_ftrace_mod_code(unsigned long ip, const void *new_code)
 {
        /*
         * On x86_64, kernel text mappings are mapped read-only with
@@ -266,8 +266,8 @@ static const unsigned char *ftrace_nop_replace(void)
 }
 
 static int
-ftrace_modify_code(unsigned long ip, unsigned char *old_code,
-                  unsigned char *new_code)
+ftrace_modify_code(unsigned long ip, unsigned const char *old_code,
+                  unsigned const char *new_code)
 {
        unsigned char replaced[MCOUNT_INSN_SIZE];
 
@@ -301,7 +301,7 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
 int ftrace_make_nop(struct module *mod,
                    struct dyn_ftrace *rec, unsigned long addr)
 {
-       unsigned char *new, *old;
+       unsigned const char *new, *old;
        unsigned long ip = rec->ip;
 
        old = ftrace_call_replace(ip, addr);
@@ -312,7 +312,7 @@ int ftrace_make_nop(struct module *mod,
 
 int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 {
-       unsigned char *new, *old;
+       unsigned const char *new, *old;
        unsigned long ip = rec->ip;
 
        old = ftrace_nop_replace();
index 88a90a977f8ee58d58b5bf14546b66a82f85aabf..e1ba8cb24e4edb6629a9107312c071739c32de75 100644 (file)
@@ -337,7 +337,9 @@ EXPORT_SYMBOL(boot_option_idle_override);
  * Powermanagement idle function, if any..
  */
 void (*pm_idle)(void);
+#ifdef CONFIG_APM_MODULE
 EXPORT_SYMBOL(pm_idle);
+#endif
 
 #ifdef CONFIG_X86_32
 /*
@@ -535,45 +537,45 @@ int mwait_usable(const struct cpuinfo_x86 *c)
        return (edx & MWAIT_EDX_C1);
 }
 
-bool c1e_detected;
-EXPORT_SYMBOL(c1e_detected);
+bool amd_e400_c1e_detected;
+EXPORT_SYMBOL(amd_e400_c1e_detected);
 
-static cpumask_var_t c1e_mask;
+static cpumask_var_t amd_e400_c1e_mask;
 
-void c1e_remove_cpu(int cpu)
+void amd_e400_remove_cpu(int cpu)
 {
-       if (c1e_mask != NULL)
-               cpumask_clear_cpu(cpu, c1e_mask);
+       if (amd_e400_c1e_mask != NULL)
+               cpumask_clear_cpu(cpu, amd_e400_c1e_mask);
 }
 
 /*
- * C1E aware idle routine. We check for C1E active in the interrupt
+ * AMD Erratum 400 aware idle routine. We check for C1E active in the interrupt
  * pending message MSR. If we detect C1E, then we handle it the same
  * way as C3 power states (local apic timer and TSC stop)
  */
-static void c1e_idle(void)
+static void amd_e400_idle(void)
 {
        if (need_resched())
                return;
 
-       if (!c1e_detected) {
+       if (!amd_e400_c1e_detected) {
                u32 lo, hi;
 
                rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi);
 
                if (lo & K8_INTP_C1E_ACTIVE_MASK) {
-                       c1e_detected = true;
+                       amd_e400_c1e_detected = true;
                        if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
                                mark_tsc_unstable("TSC halt in AMD C1E");
                        printk(KERN_INFO "System has AMD C1E enabled\n");
                }
        }
 
-       if (c1e_detected) {
+       if (amd_e400_c1e_detected) {
                int cpu = smp_processor_id();
 
-               if (!cpumask_test_cpu(cpu, c1e_mask)) {
-                       cpumask_set_cpu(cpu, c1e_mask);
+               if (!cpumask_test_cpu(cpu, amd_e400_c1e_mask)) {
+                       cpumask_set_cpu(cpu, amd_e400_c1e_mask);
                        /*
                         * Force broadcast so ACPI can not interfere.
                         */
@@ -616,17 +618,17 @@ void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
                pm_idle = mwait_idle;
        } else if (cpu_has_amd_erratum(amd_erratum_400)) {
                /* E400: APIC timer interrupt does not wake up CPU from C1e */
-               printk(KERN_INFO "using C1E aware idle routine\n");
-               pm_idle = c1e_idle;
+               printk(KERN_INFO "using AMD E400 aware idle routine\n");
+               pm_idle = amd_e400_idle;
        } else
                pm_idle = default_idle;
 }
 
-void __init init_c1e_mask(void)
+void __init init_amd_e400_c1e_mask(void)
 {
-       /* If we're using c1e_idle, we need to allocate c1e_mask. */
-       if (pm_idle == c1e_idle)
-               zalloc_cpumask_var(&c1e_mask, GFP_KERNEL);
+       /* If we're using amd_e400_idle, we need to allocate amd_e400_c1e_mask. */
+       if (pm_idle == amd_e400_idle)
+               zalloc_cpumask_var(&amd_e400_c1e_mask, GFP_KERNEL);
 }
 
 static int __init idle_setup(char *str)
@@ -640,6 +642,7 @@ static int __init idle_setup(char *str)
                boot_option_idle_override = IDLE_POLL;
        } else if (!strcmp(str, "mwait")) {
                boot_option_idle_override = IDLE_FORCE_MWAIT;
+               WARN_ONCE(1, "\"idle=mwait\" will be removed in 2012\n");
        } else if (!strcmp(str, "halt")) {
                /*
                 * When the boot option of idle=halt is added, halt is
index 8d128783af47374e56412d01d0488aa12af1647b..a3d0dc59067be542d7423d2a8abbc99801c0d3f6 100644 (file)
@@ -245,7 +245,6 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
 {
        set_user_gs(regs, 0);
        regs->fs                = 0;
-       set_fs(USER_DS);
        regs->ds                = __USER_DS;
        regs->es                = __USER_DS;
        regs->ss                = __USER_DS;
index 6c9dd922ac0d8b34ff9cac883ef86bf8843cb912..ca6f7ab8df332992166d51c802216d350c8729cc 100644 (file)
@@ -338,7 +338,6 @@ start_thread_common(struct pt_regs *regs, unsigned long new_ip,
        regs->cs                = _cs;
        regs->ss                = _ss;
        regs->flags             = X86_EFLAGS_IF;
-       set_fs(USER_DS);
        /*
         * Free the old FP and other extended state
         */
index f65e5b521dbd4b3d28c8dc30faecec02073e56fb..807c2a2b80f12d711240cc56b4b292b9cb616b89 100644 (file)
@@ -1363,7 +1363,7 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
  * We must return the syscall number to actually look up in the table.
  * This can be -1L to skip running any syscall at all.
  */
-asmregparm long syscall_trace_enter(struct pt_regs *regs)
+long syscall_trace_enter(struct pt_regs *regs)
 {
        long ret = 0;
 
@@ -1408,7 +1408,7 @@ asmregparm long syscall_trace_enter(struct pt_regs *regs)
        return ret ?: regs->orig_ax;
 }
 
-asmregparm void syscall_trace_leave(struct pt_regs *regs)
+void syscall_trace_leave(struct pt_regs *regs)
 {
        bool step;
 
index 605e5ae19c7fe8a1dd754f3c2c96b290b13b48bc..afaf38447ef5fc42c53e78168492fa9eb89a032b 100644 (file)
@@ -910,6 +910,13 @@ void __init setup_arch(char **cmdline_p)
        memblock.current_limit = get_max_mapped();
        memblock_x86_fill();
 
+       /*
+        * The EFI specification says that boot service code won't be called
+        * after ExitBootServices(). This is, in fact, a lie.
+        */
+       if (efi_enabled)
+               efi_reserve_boot_services();
+
        /* preallocate 4k for mptable mpc */
        early_reserve_e820_mpc_new();
 
@@ -946,6 +953,8 @@ void __init setup_arch(char **cmdline_p)
        if (init_ohci1394_dma_early)
                init_ohci1394_dma_on_all_controllers();
 #endif
+       /* Allocate bigger log buffer */
+       setup_log_buf(1);
 
        reserve_initrd();
 
index a3c430bdfb6020aaefd4a7c97717f30c627d0a85..9fd3137230d46af2053cdebb88c3a6ef4867984f 100644 (file)
@@ -285,6 +285,19 @@ notrace static void __cpuinit start_secondary(void *unused)
        per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
        x86_platform.nmi_init();
 
+       /*
+        * Wait until the cpu which brought this one up marked it
+        * online before enabling interrupts. If we don't do that then
+        * we can end up waking up the softirq thread before this cpu
+        * reached the active state, which makes the scheduler unhappy
+        * and schedule the softirq thread on the wrong cpu. This is
+        * only observable with forced threaded interrupts, but in
+        * theory it could also happen w/o them. It's just way harder
+        * to achieve.
+        */
+       while (!cpumask_test_cpu(smp_processor_id(), cpu_active_mask))
+               cpu_relax();
+
        /* enable local interrupts */
        local_irq_enable();
 
@@ -1307,7 +1320,7 @@ void play_dead_common(void)
 {
        idle_task_exit();
        reset_lazy_tlbstate();
-       c1e_remove_cpu(raw_smp_processor_id());
+       amd_e400_remove_cpu(raw_smp_processor_id());
 
        mb();
        /* Ack it */
@@ -1332,7 +1345,7 @@ static inline void mwait_play_dead(void)
        void *mwait_ptr;
        struct cpuinfo_x86 *c = __this_cpu_ptr(&cpu_info);
 
-       if (!this_cpu_has(X86_FEATURE_MWAIT) && mwait_usable(c))
+       if (!(this_cpu_has(X86_FEATURE_MWAIT) && mwait_usable(c)))
                return;
        if (!this_cpu_has(X86_FEATURE_CLFLSH))
                return;
index 32cbffb0c494bb881f4341c174ad0ece29205ed0..fbb0a045a1a23bc9bdc2f9dd23c6c9673e2e13f7 100644 (file)
@@ -345,3 +345,4 @@ ENTRY(sys_call_table)
        .long sys_clock_adjtime
        .long sys_syncfs
        .long sys_sendmmsg              /* 345 */
+       .long sys_setns
index 998e972f3b1a93638c7456650927db96704e68c6..30ac65df7d4eeaa956777c53e2846997cdd59464 100644 (file)
@@ -110,7 +110,6 @@ static struct mm_struct tboot_mm = {
        .mmap_sem       = __RWSEM_INITIALIZER(init_mm.mmap_sem),
        .page_table_lock =  __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock),
        .mmlist         = LIST_HEAD_INIT(init_mm.mmlist),
-       .cpu_vm_mask    = CPU_MASK_ALL,
 };
 
 static inline void switch_to_tboot_pt(void)
index 25a28a245937989d2de9abfb94d96835a1b01615..00cbb272627ff8d9ef2fb7f963c613969cc3710a 100644 (file)
@@ -23,7 +23,7 @@
 #include <asm/time.h>
 
 #ifdef CONFIG_X86_64
-volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
+DEFINE_VVAR(volatile unsigned long, jiffies) = INITIAL_JIFFIES;
 #endif
 
 unsigned long profile_pc(struct pt_regs *regs)
index 9335bf7dd2e7635f8bca255532919e98ff015388..6cc6922262af7ca285c814eaf13fdf65fd30e033 100644 (file)
@@ -763,25 +763,6 @@ static cycle_t read_tsc(struct clocksource *cs)
                ret : clocksource_tsc.cycle_last;
 }
 
-#ifdef CONFIG_X86_64
-static cycle_t __vsyscall_fn vread_tsc(void)
-{
-       cycle_t ret;
-
-       /*
-        * Surround the RDTSC by barriers, to make sure it's not
-        * speculated to outside the seqlock critical section and
-        * does not cause time warps:
-        */
-       rdtsc_barrier();
-       ret = (cycle_t)vget_cycles();
-       rdtsc_barrier();
-
-       return ret >= __vsyscall_gtod_data.clock.cycle_last ?
-               ret : __vsyscall_gtod_data.clock.cycle_last;
-}
-#endif
-
 static void resume_tsc(struct clocksource *cs)
 {
        clocksource_tsc.cycle_last = 0;
index 49927a863cc18089d1f1ab156c63e1080af841d7..89aed99aafceb3b8ce1df591a77f619418166273 100644 (file)
@@ -161,6 +161,12 @@ SECTIONS
 
 #define VVIRT_OFFSET (VSYSCALL_ADDR - __vsyscall_0)
 #define VVIRT(x) (ADDR(x) - VVIRT_OFFSET)
+#define EMIT_VVAR(x, offset) .vsyscall_var_ ## x       \
+       ADDR(.vsyscall_0) + offset                      \
+       : AT(VLOAD(.vsyscall_var_ ## x)) {              \
+               *(.vsyscall_var_ ## x)                  \
+       }                                               \
+       x = VVIRT(.vsyscall_var_ ## x);
 
        . = ALIGN(4096);
        __vsyscall_0 = .;
@@ -175,18 +181,6 @@ SECTIONS
                *(.vsyscall_fn)
        }
 
-       . = ALIGN(L1_CACHE_BYTES);
-       .vsyscall_gtod_data : AT(VLOAD(.vsyscall_gtod_data)) {
-               *(.vsyscall_gtod_data)
-       }
-
-       vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data);
-       .vsyscall_clock : AT(VLOAD(.vsyscall_clock)) {
-               *(.vsyscall_clock)
-       }
-       vsyscall_clock = VVIRT(.vsyscall_clock);
-
-
        .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1)) {
                *(.vsyscall_1)
        }
@@ -194,21 +188,14 @@ SECTIONS
                *(.vsyscall_2)
        }
 
-       .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) {
-               *(.vgetcpu_mode)
-       }
-       vgetcpu_mode = VVIRT(.vgetcpu_mode);
-
-       . = ALIGN(L1_CACHE_BYTES);
-       .jiffies : AT(VLOAD(.jiffies)) {
-               *(.jiffies)
-       }
-       jiffies = VVIRT(.jiffies);
-
        .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3)) {
                *(.vsyscall_3)
        }
 
+#define __VVAR_KERNEL_LDS
+#include <asm/vvar.h>
+#undef __VVAR_KERNEL_LDS
+
        . = __vsyscall_0 + PAGE_SIZE;
 
 #undef VSYSCALL_ADDR
@@ -216,6 +203,7 @@ SECTIONS
 #undef VLOAD
 #undef VVIRT_OFFSET
 #undef VVIRT
+#undef EMIT_VVAR
 
 #endif /* CONFIG_X86_64 */
 
@@ -326,7 +314,7 @@ SECTIONS
        }
 
 #if !defined(CONFIG_X86_64) || !defined(CONFIG_SMP)
-       PERCPU(INTERNODE_CACHE_BYTES, PAGE_SIZE)
+       PERCPU_SECTION(INTERNODE_CACHE_BYTES)
 #endif
 
        . = ALIGN(PAGE_SIZE);
diff --git a/arch/x86/kernel/vread_tsc_64.c b/arch/x86/kernel/vread_tsc_64.c
new file mode 100644 (file)
index 0000000..a81aa9e
--- /dev/null
@@ -0,0 +1,36 @@
+/* This code runs in userspace. */
+
+#define DISABLE_BRANCH_PROFILING
+#include <asm/vgtod.h>
+
+notrace cycle_t __vsyscall_fn vread_tsc(void)
+{
+       cycle_t ret;
+       u64 last;
+
+       /*
+        * Empirically, a fence (of type that depends on the CPU)
+        * before rdtsc is enough to ensure that rdtsc is ordered
+        * with respect to loads.  The various CPU manuals are unclear
+        * as to whether rdtsc can be reordered with later loads,
+        * but no one has ever seen it happen.
+        */
+       rdtsc_barrier();
+       ret = (cycle_t)vget_cycles();
+
+       last = VVAR(vsyscall_gtod_data).clock.cycle_last;
+
+       if (likely(ret >= last))
+               return ret;
+
+       /*
+        * GCC likes to generate cmov here, but this branch is extremely
+        * predictable (it's just a funciton of time and the likely is
+        * very likely) and there's a data dependence, so force GCC
+        * to generate a branch instead.  I don't barrier() because
+        * we don't actually need a barrier, and if this function
+        * ever gets inlined it will generate worse code.
+        */
+       asm volatile ("");
+       return last;
+}
index dcbb28c4b69461723147e2b863919301083b68b5..3e682184d76c7997d090430db61d52e4826270e8 100644 (file)
                __attribute__ ((unused, __section__(".vsyscall_" #nr))) notrace
 #define __syscall_clobber "r11","cx","memory"
 
-/*
- * vsyscall_gtod_data contains data that is :
- * - readonly from vsyscalls
- * - written by timer interrupt or systcl (/proc/sys/kernel/vsyscall64)
- * Try to keep this structure as small as possible to avoid cache line ping pongs
- */
-int __vgetcpu_mode __section_vgetcpu_mode;
-
-struct vsyscall_gtod_data __vsyscall_gtod_data __section_vsyscall_gtod_data =
+DEFINE_VVAR(int, vgetcpu_mode);
+DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data) =
 {
-       .lock = SEQLOCK_UNLOCKED,
+       .lock = __SEQLOCK_UNLOCKED(__vsyscall_gtod_data.lock),
        .sysctl_enabled = 1,
 };
 
@@ -97,7 +90,7 @@ void update_vsyscall(struct timespec *wall_time, struct timespec *wtm,
  */
 static __always_inline void do_get_tz(struct timezone * tz)
 {
-       *tz = __vsyscall_gtod_data.sys_tz;
+       *tz = VVAR(vsyscall_gtod_data).sys_tz;
 }
 
 static __always_inline int gettimeofday(struct timeval *tv, struct timezone *tz)
@@ -126,23 +119,24 @@ static __always_inline void do_vgettimeofday(struct timeval * tv)
        unsigned long mult, shift, nsec;
        cycle_t (*vread)(void);
        do {
-               seq = read_seqbegin(&__vsyscall_gtod_data.lock);
+               seq = read_seqbegin(&VVAR(vsyscall_gtod_data).lock);
 
-               vread = __vsyscall_gtod_data.clock.vread;
-               if (unlikely(!__vsyscall_gtod_data.sysctl_enabled || !vread)) {
+               vread = VVAR(vsyscall_gtod_data).clock.vread;
+               if (unlikely(!VVAR(vsyscall_gtod_data).sysctl_enabled ||
+                            !vread)) {
                        gettimeofday(tv,NULL);
                        return;
                }
 
                now = vread();
-               base = __vsyscall_gtod_data.clock.cycle_last;
-               mask = __vsyscall_gtod_data.clock.mask;
-               mult = __vsyscall_gtod_data.clock.mult;
-               shift = __vsyscall_gtod_data.clock.shift;
+               base = VVAR(vsyscall_gtod_data).clock.cycle_last;
+               mask = VVAR(vsyscall_gtod_data).clock.mask;
+               mult = VVAR(vsyscall_gtod_data).clock.mult;
+               shift = VVAR(vsyscall_gtod_data).clock.shift;
 
-               tv->tv_sec = __vsyscall_gtod_data.wall_time_sec;
-               nsec = __vsyscall_gtod_data.wall_time_nsec;
-       } while (read_seqretry(&__vsyscall_gtod_data.lock, seq));
+               tv->tv_sec = VVAR(vsyscall_gtod_data).wall_time_sec;
+               nsec = VVAR(vsyscall_gtod_data).wall_time_nsec;
+       } while (read_seqretry(&VVAR(vsyscall_gtod_data).lock, seq));
 
        /* calculate interval: */
        cycle_delta = (now - base) & mask;
@@ -171,15 +165,15 @@ time_t __vsyscall(1) vtime(time_t *t)
 {
        unsigned seq;
        time_t result;
-       if (unlikely(!__vsyscall_gtod_data.sysctl_enabled))
+       if (unlikely(!VVAR(vsyscall_gtod_data).sysctl_enabled))
                return time_syscall(t);
 
        do {
-               seq = read_seqbegin(&__vsyscall_gtod_data.lock);
+               seq = read_seqbegin(&VVAR(vsyscall_gtod_data).lock);
 
-               result = __vsyscall_gtod_data.wall_time_sec;
+               result = VVAR(vsyscall_gtod_data).wall_time_sec;
 
-       } while (read_seqretry(&__vsyscall_gtod_data.lock, seq));
+       } while (read_seqretry(&VVAR(vsyscall_gtod_data).lock, seq));
 
        if (t)
                *t = result;
@@ -208,9 +202,9 @@ vgetcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache)
           We do this here because otherwise user space would do it on
           its own in a likely inferior way (no access to jiffies).
           If you don't like it pass NULL. */
-       if (tcache && tcache->blob[0] == (j = __jiffies)) {
+       if (tcache && tcache->blob[0] == (j = VVAR(jiffies))) {
                p = tcache->blob[1];
-       } else if (__vgetcpu_mode == VGETCPU_RDTSCP) {
+       } else if (VVAR(vgetcpu_mode) == VGETCPU_RDTSCP) {
                /* Load per CPU data from RDTSCP */
                native_read_tscp(&p);
        } else {
index d6e2477feb180e3787b57758f3e0151eb4a3f0b6..6df88c7885c0e24bbbdfcad54682d52cbfb085fb 100644 (file)
 #define DstDI       (5<<1)     /* Destination is in ES:(E)DI */
 #define DstMem64    (6<<1)     /* 64bit memory operand */
 #define DstImmUByte (7<<1)     /* 8-bit unsigned immediate operand */
-#define DstMask     (7<<1)
+#define DstDX       (8<<1)     /* Destination is in DX register */
+#define DstMask     (0xf<<1)
 /* Source operand type. */
-#define SrcNone     (0<<4)     /* No source operand. */
-#define SrcReg      (1<<4)     /* Register operand. */
-#define SrcMem      (2<<4)     /* Memory operand. */
-#define SrcMem16    (3<<4)     /* Memory operand (16-bit). */
-#define SrcMem32    (4<<4)     /* Memory operand (32-bit). */
-#define SrcImm      (5<<4)     /* Immediate operand. */
-#define SrcImmByte  (6<<4)     /* 8-bit sign-extended immediate operand. */
-#define SrcOne      (7<<4)     /* Implied '1' */
-#define SrcImmUByte (8<<4)      /* 8-bit unsigned immediate operand. */
-#define SrcImmU     (9<<4)      /* Immediate operand, unsigned */
-#define SrcSI       (0xa<<4)   /* Source is in the DS:RSI */
-#define SrcImmFAddr (0xb<<4)   /* Source is immediate far address */
-#define SrcMemFAddr (0xc<<4)   /* Source is far address in memory */
-#define SrcAcc      (0xd<<4)   /* Source Accumulator */
-#define SrcImmU16   (0xe<<4)    /* Immediate operand, unsigned, 16 bits */
-#define SrcMask     (0xf<<4)
+#define SrcNone     (0<<5)     /* No source operand. */
+#define SrcReg      (1<<5)     /* Register operand. */
+#define SrcMem      (2<<5)     /* Memory operand. */
+#define SrcMem16    (3<<5)     /* Memory operand (16-bit). */
+#define SrcMem32    (4<<5)     /* Memory operand (32-bit). */
+#define SrcImm      (5<<5)     /* Immediate operand. */
+#define SrcImmByte  (6<<5)     /* 8-bit sign-extended immediate operand. */
+#define SrcOne      (7<<5)     /* Implied '1' */
+#define SrcImmUByte (8<<5)      /* 8-bit unsigned immediate operand. */
+#define SrcImmU     (9<<5)      /* Immediate operand, unsigned */
+#define SrcSI       (0xa<<5)   /* Source is in the DS:RSI */
+#define SrcImmFAddr (0xb<<5)   /* Source is immediate far address */
+#define SrcMemFAddr (0xc<<5)   /* Source is far address in memory */
+#define SrcAcc      (0xd<<5)   /* Source Accumulator */
+#define SrcImmU16   (0xe<<5)    /* Immediate operand, unsigned, 16 bits */
+#define SrcDX       (0xf<<5)   /* Source is in DX register */
+#define SrcMask     (0xf<<5)
 /* Generic ModRM decode. */
-#define ModRM       (1<<8)
+#define ModRM       (1<<9)
 /* Destination is only written; never read. */
-#define Mov         (1<<9)
-#define BitOp       (1<<10)
-#define MemAbs      (1<<11)      /* Memory operand is absolute displacement */
-#define String      (1<<12)     /* String instruction (rep capable) */
-#define Stack       (1<<13)     /* Stack instruction (push/pop) */
-#define GroupMask   (7<<14)     /* Opcode uses one of the group mechanisms */
-#define Group       (1<<14)     /* Bits 3:5 of modrm byte extend opcode */
-#define GroupDual   (2<<14)     /* Alternate decoding of mod == 3 */
-#define Prefix      (3<<14)     /* Instruction varies with 66/f2/f3 prefix */
-#define RMExt       (4<<14)     /* Opcode extension in ModRM r/m if mod == 3 */
-#define Sse         (1<<17)     /* SSE Vector instruction */
+#define Mov         (1<<10)
+#define BitOp       (1<<11)
+#define MemAbs      (1<<12)      /* Memory operand is absolute displacement */
+#define String      (1<<13)     /* String instruction (rep capable) */
+#define Stack       (1<<14)     /* Stack instruction (push/pop) */
+#define GroupMask   (7<<15)     /* Opcode uses one of the group mechanisms */
+#define Group       (1<<15)     /* Bits 3:5 of modrm byte extend opcode */
+#define GroupDual   (2<<15)     /* Alternate decoding of mod == 3 */
+#define Prefix      (3<<15)     /* Instruction varies with 66/f2/f3 prefix */
+#define RMExt       (4<<15)     /* Opcode extension in ModRM r/m if mod == 3 */
+#define Sse         (1<<18)     /* SSE Vector instruction */
 /* Misc flags */
 #define Prot        (1<<21) /* instruction generates #UD if not in prot-mode */
 #define VendorSpecific (1<<22) /* Vendor specific instruction */
@@ -3154,8 +3156,8 @@ static struct opcode opcode_table[256] = {
        I(DstReg | SrcMem | ModRM | Src2Imm, em_imul_3op),
        I(SrcImmByte | Mov | Stack, em_push),
        I(DstReg | SrcMem | ModRM | Src2ImmByte, em_imul_3op),
-       D2bvIP(DstDI | Mov | String, ins, check_perm_in), /* insb, insw/insd */
-       D2bvIP(SrcSI | ImplicitOps | String, outs, check_perm_out), /* outsb, outsw/outsd */
+       D2bvIP(DstDI | SrcDX | Mov | String, ins, check_perm_in), /* insb, insw/insd */
+       D2bvIP(SrcSI | DstDX | String, outs, check_perm_out), /* outsb, outsw/outsd */
        /* 0x70 - 0x7F */
        X16(D(SrcImmByte)),
        /* 0x80 - 0x87 */
@@ -3212,8 +3214,8 @@ static struct opcode opcode_table[256] = {
        /* 0xE8 - 0xEF */
        D(SrcImm | Stack), D(SrcImm | ImplicitOps),
        D(SrcImmFAddr | No64), D(SrcImmByte | ImplicitOps),
-       D2bvIP(SrcNone | DstAcc,     in,  check_perm_in),
-       D2bvIP(SrcAcc | ImplicitOps, out, check_perm_out),
+       D2bvIP(SrcDX | DstAcc, in,  check_perm_in),
+       D2bvIP(SrcAcc | DstDX, out, check_perm_out),
        /* 0xF0 - 0xF7 */
        N, DI(ImplicitOps, icebp), N, N,
        DI(ImplicitOps | Priv, hlt), D(ImplicitOps),
@@ -3613,6 +3615,12 @@ done_prefixes:
                memop.bytes = c->op_bytes + 2;
                goto srcmem_common;
                break;
+       case SrcDX:
+               c->src.type = OP_REG;
+               c->src.bytes = 2;
+               c->src.addr.reg = &c->regs[VCPU_REGS_RDX];
+               fetch_register_operand(&c->src);
+               break;
        }
 
        if (rc != X86EMUL_CONTINUE)
@@ -3682,6 +3690,12 @@ done_prefixes:
                c->dst.addr.mem.seg = VCPU_SREG_ES;
                c->dst.val = 0;
                break;
+       case DstDX:
+               c->dst.type = OP_REG;
+               c->dst.bytes = 2;
+               c->dst.addr.reg = &c->regs[VCPU_REGS_RDX];
+               fetch_register_operand(&c->dst);
+               break;
        case ImplicitOps:
                /* Special instructions do their own operand decoding. */
        default:
@@ -4027,7 +4041,6 @@ special_insn:
                break;
        case 0xec: /* in al,dx */
        case 0xed: /* in (e/r)ax,dx */
-               c->src.val = c->regs[VCPU_REGS_RDX];
        do_io_in:
                if (!pio_in_emulated(ctxt, ops, c->dst.bytes, c->src.val,
                                     &c->dst.val))
@@ -4035,7 +4048,6 @@ special_insn:
                break;
        case 0xee: /* out dx,al */
        case 0xef: /* out dx,(e/r)ax */
-               c->dst.val = c->regs[VCPU_REGS_RDX];
        do_io_out:
                ops->pio_out_emulated(ctxt, c->src.bytes, c->dst.val,
                                      &c->src.val, 1);
index 28418054b8808e190981b8d4b080b11dea9b84b6..aee38623b768edae62394fc09c64742f54b5b955 100644 (file)
@@ -565,7 +565,7 @@ gfn_to_memslot_dirty_bitmap(struct kvm_vcpu *vcpu, gfn_t gfn,
 
 static bool mapping_level_dirty_bitmap(struct kvm_vcpu *vcpu, gfn_t large_gfn)
 {
-       return gfn_to_memslot_dirty_bitmap(vcpu, large_gfn, true);
+       return !gfn_to_memslot_dirty_bitmap(vcpu, large_gfn, true);
 }
 
 static int mapping_level(struct kvm_vcpu *vcpu, gfn_t large_gfn)
@@ -3545,10 +3545,11 @@ static int kvm_mmu_remove_some_alloc_mmu_pages(struct kvm *kvm,
        return kvm_mmu_prepare_zap_page(kvm, page, invalid_list);
 }
 
-static int mmu_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
+static int mmu_shrink(struct shrinker *shrink, struct shrink_control *sc)
 {
        struct kvm *kvm;
        struct kvm *kvm_freed = NULL;
+       int nr_to_scan = sc->nr_to_scan;
 
        if (nr_to_scan == 0)
                goto out;
index 6c4dc010c4cbfdc2dd49f1e82696022373e817fd..9d03ad4dd5ec95366b1e5b22ccf76c8a737a7155 100644 (file)
@@ -121,7 +121,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
                                    gva_t addr, u32 access)
 {
        pt_element_t pte;
-       pt_element_t __user *ptep_user;
+       pt_element_t __user *uninitialized_var(ptep_user);
        gfn_t table_gfn;
        unsigned index, pt_access, uninitialized_var(pte_access);
        gpa_t pte_gpa;
index 4c3fa0f6746970cef9bb5d26e5808d8bbdabcb1f..d48ec60ea421a8211271195db0193bc42a9a7532 100644 (file)
@@ -2047,7 +2047,8 @@ static void ept_update_paging_mode_cr0(unsigned long *hw_cr0,
                                        unsigned long cr0,
                                        struct kvm_vcpu *vcpu)
 {
-       vmx_decache_cr3(vcpu);
+       if (!test_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail))
+               vmx_decache_cr3(vcpu);
        if (!(cr0 & X86_CR0_PG)) {
                /* From paging/starting to nonpaging */
                vmcs_write32(CPU_BASED_VM_EXEC_CONTROL,
index e191c096ab90363228965e746a0f898d6f8a9451..db832fd65ecbf8d749720b449eed3fd2b8d55cab 100644 (file)
@@ -993,6 +993,7 @@ static void lguest_time_irq(unsigned int irq, struct irq_desc *desc)
 static void lguest_time_init(void)
 {
        /* Set up the timer interrupt (0) to go to our simple timer routine */
+       lguest_setup_irq(0);
        irq_set_handler(0, lguest_time_irq);
 
        clocksource_register_hz(&lguest_clock, NSEC_PER_SEC);
index bcb394dfbb3587f8b4d40cc096b6ff7334ce6b12..2dbf6bf4c7e5295906d5f0b25fcb97dd9845d363 100644 (file)
@@ -823,16 +823,30 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
        force_sig_info_fault(SIGBUS, code, address, tsk, fault);
 }
 
-static noinline void
+static noinline int
 mm_fault_error(struct pt_regs *regs, unsigned long error_code,
               unsigned long address, unsigned int fault)
 {
+       /*
+        * Pagefault was interrupted by SIGKILL. We have no reason to
+        * continue pagefault.
+        */
+       if (fatal_signal_pending(current)) {
+               if (!(fault & VM_FAULT_RETRY))
+                       up_read(&current->mm->mmap_sem);
+               if (!(error_code & PF_USER))
+                       no_context(regs, error_code, address);
+               return 1;
+       }
+       if (!(fault & VM_FAULT_ERROR))
+               return 0;
+
        if (fault & VM_FAULT_OOM) {
                /* Kernel mode? Handle exceptions or die: */
                if (!(error_code & PF_USER)) {
                        up_read(&current->mm->mmap_sem);
                        no_context(regs, error_code, address);
-                       return;
+                       return 1;
                }
 
                out_of_memory(regs, error_code, address);
@@ -843,6 +857,7 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
                else
                        BUG();
        }
+       return 1;
 }
 
 static int spurious_fault_check(unsigned long error_code, pte_t *pte)
@@ -965,7 +980,7 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)
        struct mm_struct *mm;
        int fault;
        int write = error_code & PF_WRITE;
-       unsigned int flags = FAULT_FLAG_ALLOW_RETRY |
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
                                        (write ? FAULT_FLAG_WRITE : 0);
 
        tsk = current;
@@ -1133,9 +1148,9 @@ good_area:
         */
        fault = handle_mm_fault(mm, vma, address, flags);
 
-       if (unlikely(fault & VM_FAULT_ERROR)) {
-               mm_fault_error(regs, error_code, address, fault);
-               return;
+       if (unlikely(fault & (VM_FAULT_RETRY|VM_FAULT_ERROR))) {
+               if (mm_fault_error(regs, error_code, address, fault))
+                       return;
        }
 
        /*
index d4203988504ae871e9e6bf4f8a294d0e8b696dff..f581a18c0d4d7d07aac5cdfa8fb443106e3d5e92 100644 (file)
@@ -72,7 +72,7 @@ static void huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
        if (!vma_shareable(vma, addr))
                return;
 
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
        vma_prio_tree_foreach(svma, &iter, &mapping->i_mmap, idx, idx) {
                if (svma == vma)
                        continue;
@@ -97,7 +97,7 @@ static void huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
                put_page(virt_to_page(spte));
        spin_unlock(&mm->page_table_lock);
 out:
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
 }
 
 /*
index 37b8b0fe8320952c89158d29a508568affbd8c8e..30326443ab81d9189224cf0c373ded68da51332d 100644 (file)
@@ -16,8 +16,6 @@
 #include <asm/tlb.h>
 #include <asm/proto.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 unsigned long __initdata pgt_buf_start;
 unsigned long __meminitdata pgt_buf_end;
 unsigned long __meminitdata pgt_buf_top;
index aa1169392b83eb44350ec5da13cd23bfc3477986..992da5ec5a64d69ddc3381d9e8508e4d6061d4ef 100644 (file)
@@ -8,7 +8,7 @@
 #include <linux/range.h>
 
 /* Check for already reserved areas */
-static bool __init check_with_memblock_reserved_size(u64 *addrp, u64 *sizep, u64 align)
+bool __init memblock_x86_check_reserved_size(u64 *addrp, u64 *sizep, u64 align)
 {
        struct memblock_region *r;
        u64 addr = *addrp, last;
@@ -59,7 +59,7 @@ u64 __init memblock_x86_find_in_range_size(u64 start, u64 *sizep, u64 align)
                if (addr >= ei_last)
                        continue;
                *sizep = ei_last - addr;
-               while (check_with_memblock_reserved_size(&addr, sizep, align))
+               while (memblock_x86_check_reserved_size(&addr, sizep, align))
                        ;
 
                if (*sizep)
index c3b8e24f2b16f4f6441c286268a61ac6a320b7c3..9cbb710dc94b6ee8c6df0fec2004173ac667d882 100644 (file)
@@ -316,16 +316,23 @@ static void op_amd_stop_ibs(void)
                wrmsrl(MSR_AMD64_IBSOPCTL, 0);
 }
 
-static inline int eilvt_is_available(int offset)
+static inline int get_eilvt(int offset)
 {
-       /* check if we may assign a vector */
        return !setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_NMI, 1);
 }
 
+static inline int put_eilvt(int offset)
+{
+       return !setup_APIC_eilvt(offset, 0, 0, 1);
+}
+
 static inline int ibs_eilvt_valid(void)
 {
        int offset;
        u64 val;
+       int valid = 0;
+
+       preempt_disable();
 
        rdmsrl(MSR_AMD64_IBSCTL, val);
        offset = val & IBSCTL_LVT_OFFSET_MASK;
@@ -333,16 +340,20 @@ static inline int ibs_eilvt_valid(void)
        if (!(val & IBSCTL_LVT_OFFSET_VALID)) {
                pr_err(FW_BUG "cpu %d, invalid IBS interrupt offset %d (MSR%08X=0x%016llx)\n",
                       smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
-               return 0;
+               goto out;
        }
 
-       if (!eilvt_is_available(offset)) {
+       if (!get_eilvt(offset)) {
                pr_err(FW_BUG "cpu %d, IBS interrupt offset %d not available (MSR%08X=0x%016llx)\n",
                       smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
-               return 0;
+               goto out;
        }
 
-       return 1;
+       valid = 1;
+out:
+       preempt_enable();
+
+       return valid;
 }
 
 static inline int get_ibs_offset(void)
@@ -598,69 +609,76 @@ static int setup_ibs_ctl(int ibs_eilvt_off)
        return 0;
 }
 
+/*
+ * This runs only on the current cpu. We try to find an LVT offset and
+ * setup the local APIC. For this we must disable preemption. On
+ * success we initialize all nodes with this offset. This updates then
+ * the offset in the IBS_CTL per-node msr. The per-core APIC setup of
+ * the IBS interrupt vector is called from op_amd_setup_ctrs()/op_-
+ * amd_cpu_shutdown() using the new offset.
+ */
 static int force_ibs_eilvt_setup(void)
 {
-       int i;
+       int offset;
        int ret;
 
-       /* find the next free available EILVT entry */
-       for (i = 1; i < 4; i++) {
-               if (!eilvt_is_available(i))
-                       continue;
-               ret = setup_ibs_ctl(i);
-               if (ret)
-                       return ret;
-               pr_err(FW_BUG "using offset %d for IBS interrupts\n", i);
-               return 0;
+       preempt_disable();
+       /* find the next free available EILVT entry, skip offset 0 */
+       for (offset = 1; offset < APIC_EILVT_NR_MAX; offset++) {
+               if (get_eilvt(offset))
+                       break;
        }
+       preempt_enable();
 
-       printk(KERN_DEBUG "No EILVT entry available\n");
-
-       return -EBUSY;
-}
-
-static int __init_ibs_nmi(void)
-{
-       int ret;
-
-       if (ibs_eilvt_valid())
-               return 0;
+       if (offset == APIC_EILVT_NR_MAX) {
+               printk(KERN_DEBUG "No EILVT entry available\n");
+               return -EBUSY;
+       }
 
-       ret = force_ibs_eilvt_setup();
+       ret = setup_ibs_ctl(offset);
        if (ret)
-               return ret;
+               goto out;
 
-       if (!ibs_eilvt_valid())
-               return -EFAULT;
+       if (!ibs_eilvt_valid()) {
+               ret = -EFAULT;
+               goto out;
+       }
 
+       pr_err(FW_BUG "using offset %d for IBS interrupts\n", offset);
        pr_err(FW_BUG "workaround enabled for IBS LVT offset\n");
 
        return 0;
+out:
+       preempt_disable();
+       put_eilvt(offset);
+       preempt_enable();
+       return ret;
 }
 
 /*
  * check and reserve APIC extended interrupt LVT offset for IBS if
  * available
- *
- * init_ibs() preforms implicitly cpu-local operations, so pin this
- * thread to its current CPU
  */
 
 static void init_ibs(void)
 {
-       preempt_disable();
-
        ibs_caps = get_ibs_caps();
+
        if (!ibs_caps)
+               return;
+
+       if (ibs_eilvt_valid())
                goto out;
 
-       if (__init_ibs_nmi() < 0)
-               ibs_caps = 0;
-       else
-               printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n", ibs_caps);
+       if (!force_ibs_eilvt_setup())
+               goto out;
+
+       /* Failed to setup ibs */
+       ibs_caps = 0;
+       return;
 
 out:
-       preempt_enable();
+       printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n", ibs_caps);
 }
 
 static int (*create_arch_files)(struct super_block *sb, struct dentry *root);
index 0972315c3860c40c719f1b03081b892c3e8f20bf..68c3c1395202eec5ad68bfc584d14ee9f4c1975e 100644 (file)
@@ -188,7 +188,7 @@ static bool resource_contains(struct resource *res, resource_size_t point)
        return false;
 }
 
-static void coalesce_windows(struct pci_root_info *info, int type)
+static void coalesce_windows(struct pci_root_info *info, unsigned long type)
 {
        int i, j;
        struct resource *res1, *res2;
index b30aa26a8df25304b1aa798be441a84c27ce7afc..474356b98ede32e647d4343c32a7e7893fe4beff 100644 (file)
@@ -304,6 +304,61 @@ static void __init print_efi_memmap(void)
 }
 #endif  /*  EFI_DEBUG  */
 
+void __init efi_reserve_boot_services(void)
+{
+       void *p;
+
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               efi_memory_desc_t *md = p;
+               u64 start = md->phys_addr;
+               u64 size = md->num_pages << EFI_PAGE_SHIFT;
+
+               if (md->type != EFI_BOOT_SERVICES_CODE &&
+                   md->type != EFI_BOOT_SERVICES_DATA)
+                       continue;
+               /* Only reserve where possible:
+                * - Not within any already allocated areas
+                * - Not over any memory area (really needed, if above?)
+                * - Not within any part of the kernel
+                * - Not the bios reserved area
+               */
+               if ((start+size >= virt_to_phys(_text)
+                               && start <= virt_to_phys(_end)) ||
+                       !e820_all_mapped(start, start+size, E820_RAM) ||
+                       memblock_x86_check_reserved_size(&start, &size,
+                                                       1<<EFI_PAGE_SHIFT)) {
+                       /* Could not reserve, skip it */
+                       md->num_pages = 0;
+                       memblock_dbg(PFX "Could not reserve boot range "
+                                       "[0x%010llx-0x%010llx]\n",
+                                               start, start+size-1);
+               } else
+                       memblock_x86_reserve_range(start, start+size,
+                                                       "EFI Boot");
+       }
+}
+
+static void __init efi_free_boot_services(void)
+{
+       void *p;
+
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               efi_memory_desc_t *md = p;
+               unsigned long long start = md->phys_addr;
+               unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
+
+               if (md->type != EFI_BOOT_SERVICES_CODE &&
+                   md->type != EFI_BOOT_SERVICES_DATA)
+                       continue;
+
+               /* Could not reserve boot area */
+               if (!size)
+                       continue;
+
+               free_bootmem_late(start, size);
+       }
+}
+
 void __init efi_init(void)
 {
        efi_config_table_t *config_tables;
@@ -536,7 +591,9 @@ void __init efi_enter_virtual_mode(void)
 
        for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
                md = p;
-               if (!(md->attribute & EFI_MEMORY_RUNTIME))
+               if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
+                   md->type != EFI_BOOT_SERVICES_CODE &&
+                   md->type != EFI_BOOT_SERVICES_DATA)
                        continue;
 
                size = md->num_pages << EFI_PAGE_SHIFT;
@@ -592,6 +649,13 @@ void __init efi_enter_virtual_mode(void)
                panic("EFI call to SetVirtualAddressMap() failed!");
        }
 
+       /*
+        * Thankfully, it does seem that no runtime services other than
+        * SetVirtualAddressMap() will touch boot services code, so we can
+        * get rid of it all at this point
+        */
+       efi_free_boot_services();
+
        /*
         * Now that EFI is in virtual mode, update the function
         * pointers in the runtime service table to the new virtual addresses.
index 2649426a79055f5449c68e6e986baf6a0b150d43..ac3aa54e26546ba5cb4121eba0c58ca00f06ea82 100644 (file)
@@ -49,10 +49,11 @@ static void __init early_code_mapping_set_exec(int executable)
        if (!(__supported_pte_mask & _PAGE_NX))
                return;
 
-       /* Make EFI runtime service code area executable */
+       /* Make EFI service code area executable */
        for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
                md = p;
-               if (md->type == EFI_RUNTIME_SERVICES_CODE)
+               if (md->type == EFI_RUNTIME_SERVICES_CODE ||
+                   md->type == EFI_BOOT_SERVICES_CODE)
                        efi_set_executable(md, executable);
        }
 }
index c58e0ea39ef5facdaa630fa8138cb77fb530aa06..68e467f69fec8b022446de87ff60d4327b38f893 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     SGI UltraViolet TLB flush routines.
  *
- *     (c) 2008-2010 Cliff Wickman <cpw@sgi.com>, SGI.
+ *     (c) 2008-2011 Cliff Wickman <cpw@sgi.com>, SGI.
  *
  *     This code is released under the GNU General Public License version 2 or
  *     later.
@@ -35,6 +35,7 @@ static int timeout_base_ns[] = {
                5242880,
                167772160
 };
+
 static int timeout_us;
 static int nobau;
 static int baudisabled;
@@ -42,20 +43,70 @@ static spinlock_t disable_lock;
 static cycles_t congested_cycles;
 
 /* tunables: */
-static int max_bau_concurrent = MAX_BAU_CONCURRENT;
-static int max_bau_concurrent_constant = MAX_BAU_CONCURRENT;
-static int plugged_delay = PLUGGED_DELAY;
-static int plugsb4reset = PLUGSB4RESET;
-static int timeoutsb4reset = TIMEOUTSB4RESET;
-static int ipi_reset_limit = IPI_RESET_LIMIT;
-static int complete_threshold = COMPLETE_THRESHOLD;
-static int congested_response_us = CONGESTED_RESPONSE_US;
-static int congested_reps = CONGESTED_REPS;
-static int congested_period = CONGESTED_PERIOD;
+static int max_concurr         = MAX_BAU_CONCURRENT;
+static int max_concurr_const   = MAX_BAU_CONCURRENT;
+static int plugged_delay       = PLUGGED_DELAY;
+static int plugsb4reset                = PLUGSB4RESET;
+static int timeoutsb4reset     = TIMEOUTSB4RESET;
+static int ipi_reset_limit     = IPI_RESET_LIMIT;
+static int complete_threshold  = COMPLETE_THRESHOLD;
+static int congested_respns_us = CONGESTED_RESPONSE_US;
+static int congested_reps      = CONGESTED_REPS;
+static int congested_period    = CONGESTED_PERIOD;
+
+static struct tunables tunables[] = {
+       {&max_concurr, MAX_BAU_CONCURRENT}, /* must be [0] */
+       {&plugged_delay, PLUGGED_DELAY},
+       {&plugsb4reset, PLUGSB4RESET},
+       {&timeoutsb4reset, TIMEOUTSB4RESET},
+       {&ipi_reset_limit, IPI_RESET_LIMIT},
+       {&complete_threshold, COMPLETE_THRESHOLD},
+       {&congested_respns_us, CONGESTED_RESPONSE_US},
+       {&congested_reps, CONGESTED_REPS},
+       {&congested_period, CONGESTED_PERIOD}
+};
+
 static struct dentry *tunables_dir;
 static struct dentry *tunables_file;
 
-static int __init setup_nobau(char *arg)
+/* these correspond to the statistics printed by ptc_seq_show() */
+static char *stat_description[] = {
+       "sent:     number of shootdown messages sent",
+       "stime:    time spent sending messages",
+       "numuvhubs: number of hubs targeted with shootdown",
+       "numuvhubs16: number times 16 or more hubs targeted",
+       "numuvhubs8: number times 8 or more hubs targeted",
+       "numuvhubs4: number times 4 or more hubs targeted",
+       "numuvhubs2: number times 2 or more hubs targeted",
+       "numuvhubs1: number times 1 hub targeted",
+       "numcpus:  number of cpus targeted with shootdown",
+       "dto:      number of destination timeouts",
+       "retries:  destination timeout retries sent",
+       "rok:   :  destination timeouts successfully retried",
+       "resetp:   ipi-style resource resets for plugs",
+       "resett:   ipi-style resource resets for timeouts",
+       "giveup:   fall-backs to ipi-style shootdowns",
+       "sto:      number of source timeouts",
+       "bz:       number of stay-busy's",
+       "throt:    number times spun in throttle",
+       "swack:   image of UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE",
+       "recv:     shootdown messages received",
+       "rtime:    time spent processing messages",
+       "all:      shootdown all-tlb messages",
+       "one:      shootdown one-tlb messages",
+       "mult:     interrupts that found multiple messages",
+       "none:     interrupts that found no messages",
+       "retry:    number of retry messages processed",
+       "canc:     number messages canceled by retries",
+       "nocan:    number retries that found nothing to cancel",
+       "reset:    number of ipi-style reset requests processed",
+       "rcan:     number messages canceled by reset requests",
+       "disable:  number times use of the BAU was disabled",
+       "enable:   number times use of the BAU was re-enabled"
+};
+
+static int __init
+setup_nobau(char *arg)
 {
        nobau = 1;
        return 0;
@@ -63,7 +114,7 @@ static int __init setup_nobau(char *arg)
 early_param("nobau", setup_nobau);
 
 /* base pnode in this partition */
-static int uv_partition_base_pnode __read_mostly;
+static int uv_base_pnode __read_mostly;
 /* position of pnode (which is nasid>>1): */
 static int uv_nshift __read_mostly;
 static unsigned long uv_mmask __read_mostly;
@@ -109,60 +160,52 @@ static int __init uvhub_to_first_apicid(int uvhub)
  * clear of the Timeout bit (as well) will free the resource. No reply will
  * be sent (the hardware will only do one reply per message).
  */
-static inline void uv_reply_to_message(struct msg_desc *mdp,
-                                      struct bau_control *bcp)
+static void reply_to_message(struct msg_desc *mdp, struct bau_control *bcp)
 {
        unsigned long dw;
-       struct bau_payload_queue_entry *msg;
+       struct bau_pq_entry *msg;
 
        msg = mdp->msg;
        if (!msg->canceled) {
-               dw = (msg->sw_ack_vector << UV_SW_ACK_NPENDING) |
-                                               msg->sw_ack_vector;
-               uv_write_local_mmr(
-                               UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS, dw);
+               dw = (msg->swack_vec << UV_SW_ACK_NPENDING) | msg->swack_vec;
+               write_mmr_sw_ack(dw);
        }
        msg->replied_to = 1;
-       msg->sw_ack_vector = 0;
+       msg->swack_vec = 0;
 }
 
 /*
  * Process the receipt of a RETRY message
  */
-static inline void uv_bau_process_retry_msg(struct msg_desc *mdp,
-                                           struct bau_control *bcp)
+static void bau_process_retry_msg(struct msg_desc *mdp,
+                                       struct bau_control *bcp)
 {
        int i;
        int cancel_count = 0;
-       int slot2;
        unsigned long msg_res;
        unsigned long mmr = 0;
-       struct bau_payload_queue_entry *msg;
-       struct bau_payload_queue_entry *msg2;
-       struct ptc_stats *stat;
+       struct bau_pq_entry *msg = mdp->msg;
+       struct bau_pq_entry *msg2;
+       struct ptc_stats *stat = bcp->statp;
 
-       msg = mdp->msg;
-       stat = bcp->statp;
        stat->d_retries++;
        /*
         * cancel any message from msg+1 to the retry itself
         */
        for (msg2 = msg+1, i = 0; i < DEST_Q_SIZE; msg2++, i++) {
-               if (msg2 > mdp->va_queue_last)
-                       msg2 = mdp->va_queue_first;
+               if (msg2 > mdp->queue_last)
+                       msg2 = mdp->queue_first;
                if (msg2 == msg)
                        break;
 
-               /* same conditions for cancellation as uv_do_reset */
+               /* same conditions for cancellation as do_reset */
                if ((msg2->replied_to == 0) && (msg2->canceled == 0) &&
-                   (msg2->sw_ack_vector) && ((msg2->sw_ack_vector &
-                       msg->sw_ack_vector) == 0) &&
+                   (msg2->swack_vec) && ((msg2->swack_vec &
+                       msg->swack_vec) == 0) &&
                    (msg2->sending_cpu == msg->sending_cpu) &&
                    (msg2->msg_type != MSG_NOOP)) {
-                       slot2 = msg2 - mdp->va_queue_first;
-                       mmr = uv_read_local_mmr
-                               (UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE);
-                       msg_res = msg2->sw_ack_vector;
+                       mmr = read_mmr_sw_ack();
+                       msg_res = msg2->swack_vec;
                        /*
                         * This is a message retry; clear the resources held
                         * by the previous message only if they timed out.
@@ -170,6 +213,7 @@ static inline void uv_bau_process_retry_msg(struct msg_desc *mdp,
                         * situation to report.
                         */
                        if (mmr & (msg_res << UV_SW_ACK_NPENDING)) {
+                               unsigned long mr;
                                /*
                                 * is the resource timed out?
                                 * make everyone ignore the cancelled message.
@@ -177,10 +221,8 @@ static inline void uv_bau_process_retry_msg(struct msg_desc *mdp,
                                msg2->canceled = 1;
                                stat->d_canceled++;
                                cancel_count++;
-                               uv_write_local_mmr(
-                                   UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS,
-                                       (msg_res << UV_SW_ACK_NPENDING) |
-                                        msg_res);
+                               mr = (msg_res << UV_SW_ACK_NPENDING) | msg_res;
+                               write_mmr_sw_ack(mr);
                        }
                }
        }
@@ -192,20 +234,19 @@ static inline void uv_bau_process_retry_msg(struct msg_desc *mdp,
  * Do all the things a cpu should do for a TLB shootdown message.
  * Other cpu's may come here at the same time for this message.
  */
-static void uv_bau_process_message(struct msg_desc *mdp,
-                                  struct bau_control *bcp)
+static void bau_process_message(struct msg_desc *mdp,
+                                       struct bau_control *bcp)
 {
-       int msg_ack_count;
        short socket_ack_count = 0;
-       struct ptc_stats *stat;
-       struct bau_payload_queue_entry *msg;
+       short *sp;
+       struct atomic_short *asp;
+       struct ptc_stats *stat = bcp->statp;
+       struct bau_pq_entry *msg = mdp->msg;
        struct bau_control *smaster = bcp->socket_master;
 
        /*
         * This must be a normal message, or retry of a normal message
         */
-       msg = mdp->msg;
-       stat = bcp->statp;
        if (msg->address == TLB_FLUSH_ALL) {
                local_flush_tlb();
                stat->d_alltlb++;
@@ -222,30 +263,32 @@ static void uv_bau_process_message(struct msg_desc *mdp,
         * cpu number.
         */
        if (msg->msg_type == MSG_RETRY && bcp == bcp->uvhub_master)
-               uv_bau_process_retry_msg(mdp, bcp);
+               bau_process_retry_msg(mdp, bcp);
 
        /*
-        * This is a sw_ack message, so we have to reply to it.
+        * This is a swack message, so we have to reply to it.
         * Count each responding cpu on the socket. This avoids
         * pinging the count's cache line back and forth between
         * the sockets.
         */
-       socket_ack_count = atomic_add_short_return(1, (struct atomic_short *)
-                       &smaster->socket_acknowledge_count[mdp->msg_slot]);
+       sp = &smaster->socket_acknowledge_count[mdp->msg_slot];
+       asp = (struct atomic_short *)sp;
+       socket_ack_count = atom_asr(1, asp);
        if (socket_ack_count == bcp->cpus_in_socket) {
+               int msg_ack_count;
                /*
                 * Both sockets dump their completed count total into
                 * the message's count.
                 */
                smaster->socket_acknowledge_count[mdp->msg_slot] = 0;
-               msg_ack_count = atomic_add_short_return(socket_ack_count,
-                               (struct atomic_short *)&msg->acknowledge_count);
+               asp = (struct atomic_short *)&msg->acknowledge_count;
+               msg_ack_count = atom_asr(socket_ack_count, asp);
 
                if (msg_ack_count == bcp->cpus_in_uvhub) {
                        /*
                         * All cpus in uvhub saw it; reply
                         */
-                       uv_reply_to_message(mdp, bcp);
+                       reply_to_message(mdp, bcp);
                }
        }
 
@@ -268,62 +311,51 @@ static int uvhub_to_first_cpu(int uvhub)
  * Last resort when we get a large number of destination timeouts is
  * to clear resources held by a given cpu.
  * Do this with IPI so that all messages in the BAU message queue
- * can be identified by their nonzero sw_ack_vector field.
+ * can be identified by their nonzero swack_vec field.
  *
  * This is entered for a single cpu on the uvhub.
  * The sender want's this uvhub to free a specific message's
- * sw_ack resources.
+ * swack resources.
  */
-static void
-uv_do_reset(void *ptr)
+static void do_reset(void *ptr)
 {
        int i;
-       int slot;
-       int count = 0;
-       unsigned long mmr;
-       unsigned long msg_res;
-       struct bau_control *bcp;
-       struct reset_args *rap;
-       struct bau_payload_queue_entry *msg;
-       struct ptc_stats *stat;
+       struct bau_control *bcp = &per_cpu(bau_control, smp_processor_id());
+       struct reset_args *rap = (struct reset_args *)ptr;
+       struct bau_pq_entry *msg;
+       struct ptc_stats *stat = bcp->statp;
 
-       bcp = &per_cpu(bau_control, smp_processor_id());
-       rap = (struct reset_args *)ptr;
-       stat = bcp->statp;
        stat->d_resets++;
-
        /*
         * We're looking for the given sender, and
-        * will free its sw_ack resource.
+        * will free its swack resource.
         * If all cpu's finally responded after the timeout, its
         * message 'replied_to' was set.
         */
-       for (msg = bcp->va_queue_first, i = 0; i < DEST_Q_SIZE; msg++, i++) {
-               /* uv_do_reset: same conditions for cancellation as
-                  uv_bau_process_retry_msg() */
+       for (msg = bcp->queue_first, i = 0; i < DEST_Q_SIZE; msg++, i++) {
+               unsigned long msg_res;
+               /* do_reset: same conditions for cancellation as
+                  bau_process_retry_msg() */
                if ((msg->replied_to == 0) &&
                    (msg->canceled == 0) &&
                    (msg->sending_cpu == rap->sender) &&
-                   (msg->sw_ack_vector) &&
+                   (msg->swack_vec) &&
                    (msg->msg_type != MSG_NOOP)) {
+                       unsigned long mmr;
+                       unsigned long mr;
                        /*
                         * make everyone else ignore this message
                         */
                        msg->canceled = 1;
-                       slot = msg - bcp->va_queue_first;
-                       count++;
                        /*
                         * only reset the resource if it is still pending
                         */
-                       mmr = uv_read_local_mmr
-                                       (UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE);
-                       msg_res = msg->sw_ack_vector;
+                       mmr = read_mmr_sw_ack();
+                       msg_res = msg->swack_vec;
+                       mr = (msg_res << UV_SW_ACK_NPENDING) | msg_res;
                        if (mmr & msg_res) {
                                stat->d_rcanceled++;
-                               uv_write_local_mmr(
-                                   UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS,
-                                       (msg_res << UV_SW_ACK_NPENDING) |
-                                        msg_res);
+                               write_mmr_sw_ack(mr);
                        }
                }
        }
@@ -334,39 +366,38 @@ uv_do_reset(void *ptr)
  * Use IPI to get all target uvhubs to release resources held by
  * a given sending cpu number.
  */
-static void uv_reset_with_ipi(struct bau_target_uvhubmask *distribution,
-                             int sender)
+static void reset_with_ipi(struct bau_targ_hubmask *distribution, int sender)
 {
        int uvhub;
-       int cpu;
+       int maskbits;
        cpumask_t mask;
        struct reset_args reset_args;
 
        reset_args.sender = sender;
-
        cpus_clear(mask);
        /* find a single cpu for each uvhub in this distribution mask */
-       for (uvhub = 0;
-                   uvhub < sizeof(struct bau_target_uvhubmask) * BITSPERBYTE;
-                   uvhub++) {
+       maskbits = sizeof(struct bau_targ_hubmask) * BITSPERBYTE;
+       for (uvhub = 0; uvhub < maskbits; uvhub++) {
+               int cpu;
                if (!bau_uvhub_isset(uvhub, distribution))
                        continue;
                /* find a cpu for this uvhub */
                cpu = uvhub_to_first_cpu(uvhub);
                cpu_set(cpu, mask);
        }
-       /* IPI all cpus; Preemption is already disabled */
-       smp_call_function_many(&mask, uv_do_reset, (void *)&reset_args, 1);
+
+       /* IPI all cpus; preemption is already disabled */
+       smp_call_function_many(&mask, do_reset, (void *)&reset_args, 1);
        return;
 }
 
-static inline unsigned long
-cycles_2_us(unsigned long long cyc)
+static inline unsigned long cycles_2_us(unsigned long long cyc)
 {
        unsigned long long ns;
        unsigned long us;
-       ns =  (cyc * per_cpu(cyc2ns, smp_processor_id()))
-                                               >> CYC2NS_SCALE_FACTOR;
+       int cpu = smp_processor_id();
+
+       ns =  (cyc * per_cpu(cyc2ns, cpu)) >> CYC2NS_SCALE_FACTOR;
        us = ns / 1000;
        return us;
 }
@@ -376,56 +407,56 @@ cycles_2_us(unsigned long long cyc)
  * leaves uvhub_quiesce set so that no new broadcasts are started by
  * bau_flush_send_and_wait()
  */
-static inline void
-quiesce_local_uvhub(struct bau_control *hmaster)
+static inline void quiesce_local_uvhub(struct bau_control *hmaster)
 {
-       atomic_add_short_return(1, (struct atomic_short *)
-                &hmaster->uvhub_quiesce);
+       atom_asr(1, (struct atomic_short *)&hmaster->uvhub_quiesce);
 }
 
 /*
  * mark this quiet-requestor as done
  */
-static inline void
-end_uvhub_quiesce(struct bau_control *hmaster)
+static inline void end_uvhub_quiesce(struct bau_control *hmaster)
 {
-       atomic_add_short_return(-1, (struct atomic_short *)
-               &hmaster->uvhub_quiesce);
+       atom_asr(-1, (struct atomic_short *)&hmaster->uvhub_quiesce);
+}
+
+static unsigned long uv1_read_status(unsigned long mmr_offset, int right_shift)
+{
+       unsigned long descriptor_status;
+
+       descriptor_status = uv_read_local_mmr(mmr_offset);
+       descriptor_status >>= right_shift;
+       descriptor_status &= UV_ACT_STATUS_MASK;
+       return descriptor_status;
 }
 
 /*
  * Wait for completion of a broadcast software ack message
  * return COMPLETE, RETRY(PLUGGED or TIMEOUT) or GIVEUP
  */
-static int uv_wait_completion(struct bau_desc *bau_desc,
-       unsigned long mmr_offset, int right_shift, int this_cpu,
-       struct bau_control *bcp, struct bau_control *smaster, long try)
+static int uv1_wait_completion(struct bau_desc *bau_desc,
+                               unsigned long mmr_offset, int right_shift,
+                               struct bau_control *bcp, long try)
 {
        unsigned long descriptor_status;
-       cycles_t ttime;
+       cycles_t ttm;
        struct ptc_stats *stat = bcp->statp;
-       struct bau_control *hmaster;
-
-       hmaster = bcp->uvhub_master;
 
+       descriptor_status = uv1_read_status(mmr_offset, right_shift);
        /* spin on the status MMR, waiting for it to go idle */
-       while ((descriptor_status = (((unsigned long)
-               uv_read_local_mmr(mmr_offset) >>
-                       right_shift) & UV_ACT_STATUS_MASK)) !=
-                       DESC_STATUS_IDLE) {
+       while ((descriptor_status != DS_IDLE)) {
                /*
-                * Our software ack messages may be blocked because there are
-                * no swack resources available.  As long as none of them
-                * has timed out hardware will NACK our message and its
-                * state will stay IDLE.
+                * Our software ack messages may be blocked because
+                * there are no swack resources available.  As long
+                * as none of them has timed out hardware will NACK
+                * our message and its state will stay IDLE.
                 */
-               if (descriptor_status == DESC_STATUS_SOURCE_TIMEOUT) {
+               if (descriptor_status == DS_SOURCE_TIMEOUT) {
                        stat->s_stimeout++;
                        return FLUSH_GIVEUP;
-               } else if (descriptor_status ==
-                                       DESC_STATUS_DESTINATION_TIMEOUT) {
+               } else if (descriptor_status == DS_DESTINATION_TIMEOUT) {
                        stat->s_dtimeout++;
-                       ttime = get_cycles();
+                       ttm = get_cycles();
 
                        /*
                         * Our retries may be blocked by all destination
@@ -433,8 +464,7 @@ static int uv_wait_completion(struct bau_desc *bau_desc,
                         * pending.  In that case hardware returns the
                         * ERROR that looks like a destination timeout.
                         */
-                       if (cycles_2_us(ttime - bcp->send_message) <
-                                                       timeout_us) {
+                       if (cycles_2_us(ttm - bcp->send_message) < timeout_us) {
                                bcp->conseccompletes = 0;
                                return FLUSH_RETRY_PLUGGED;
                        }
@@ -447,80 +477,160 @@ static int uv_wait_completion(struct bau_desc *bau_desc,
                         */
                        cpu_relax();
                }
+               descriptor_status = uv1_read_status(mmr_offset, right_shift);
        }
        bcp->conseccompletes++;
        return FLUSH_COMPLETE;
 }
 
-static inline cycles_t
-sec_2_cycles(unsigned long sec)
+/*
+ * UV2 has an extra bit of status in the ACTIVATION_STATUS_2 register.
+ */
+static unsigned long uv2_read_status(unsigned long offset, int rshft, int cpu)
 {
-       unsigned long ns;
-       cycles_t cyc;
+       unsigned long descriptor_status;
+       unsigned long descriptor_status2;
 
-       ns = sec * 1000000000;
-       cyc = (ns << CYC2NS_SCALE_FACTOR)/(per_cpu(cyc2ns, smp_processor_id()));
-       return cyc;
+       descriptor_status = ((read_lmmr(offset) >> rshft) & UV_ACT_STATUS_MASK);
+       descriptor_status2 = (read_mmr_uv2_status() >> cpu) & 0x1UL;
+       descriptor_status = (descriptor_status << 1) | descriptor_status2;
+       return descriptor_status;
+}
+
+static int uv2_wait_completion(struct bau_desc *bau_desc,
+                               unsigned long mmr_offset, int right_shift,
+                               struct bau_control *bcp, long try)
+{
+       unsigned long descriptor_stat;
+       cycles_t ttm;
+       int cpu = bcp->uvhub_cpu;
+       struct ptc_stats *stat = bcp->statp;
+
+       descriptor_stat = uv2_read_status(mmr_offset, right_shift, cpu);
+
+       /* spin on the status MMR, waiting for it to go idle */
+       while (descriptor_stat != UV2H_DESC_IDLE) {
+               /*
+                * Our software ack messages may be blocked because
+                * there are no swack resources available.  As long
+                * as none of them has timed out hardware will NACK
+                * our message and its state will stay IDLE.
+                */
+               if ((descriptor_stat == UV2H_DESC_SOURCE_TIMEOUT) ||
+                   (descriptor_stat == UV2H_DESC_DEST_STRONG_NACK) ||
+                   (descriptor_stat == UV2H_DESC_DEST_PUT_ERR)) {
+                       stat->s_stimeout++;
+                       return FLUSH_GIVEUP;
+               } else if (descriptor_stat == UV2H_DESC_DEST_TIMEOUT) {
+                       stat->s_dtimeout++;
+                       ttm = get_cycles();
+                       /*
+                        * Our retries may be blocked by all destination
+                        * swack resources being consumed, and a timeout
+                        * pending.  In that case hardware returns the
+                        * ERROR that looks like a destination timeout.
+                        */
+                       if (cycles_2_us(ttm - bcp->send_message) < timeout_us) {
+                               bcp->conseccompletes = 0;
+                               return FLUSH_RETRY_PLUGGED;
+                       }
+                       bcp->conseccompletes = 0;
+                       return FLUSH_RETRY_TIMEOUT;
+               } else {
+                       /*
+                        * descriptor_stat is still BUSY
+                        */
+                       cpu_relax();
+               }
+               descriptor_stat = uv2_read_status(mmr_offset, right_shift, cpu);
+       }
+       bcp->conseccompletes++;
+       return FLUSH_COMPLETE;
 }
 
 /*
- * conditionally add 1 to *v, unless *v is >= u
- * return 0 if we cannot add 1 to *v because it is >= u
- * return 1 if we can add 1 to *v because it is < u
- * the add is atomic
- *
- * This is close to atomic_add_unless(), but this allows the 'u' value
- * to be lowered below the current 'v'.  atomic_add_unless can only stop
- * on equal.
+ * There are 2 status registers; each and array[32] of 2 bits. Set up for
+ * which register to read and position in that register based on cpu in
+ * current hub.
  */
-static inline int atomic_inc_unless_ge(spinlock_t *lock, atomic_t *v, int u)
+static int wait_completion(struct bau_desc *bau_desc,
+                               struct bau_control *bcp, long try)
 {
-       spin_lock(lock);
-       if (atomic_read(v) >= u) {
-               spin_unlock(lock);
-               return 0;
+       int right_shift;
+       unsigned long mmr_offset;
+       int cpu = bcp->uvhub_cpu;
+
+       if (cpu < UV_CPUS_PER_AS) {
+               mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_0;
+               right_shift = cpu * UV_ACT_STATUS_SIZE;
+       } else {
+               mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_1;
+               right_shift = ((cpu - UV_CPUS_PER_AS) * UV_ACT_STATUS_SIZE);
        }
-       atomic_inc(v);
-       spin_unlock(lock);
-       return 1;
+
+       if (is_uv1_hub())
+               return uv1_wait_completion(bau_desc, mmr_offset, right_shift,
+                                                               bcp, try);
+       else
+               return uv2_wait_completion(bau_desc, mmr_offset, right_shift,
+                                                               bcp, try);
+}
+
+static inline cycles_t sec_2_cycles(unsigned long sec)
+{
+       unsigned long ns;
+       cycles_t cyc;
+
+       ns = sec * 1000000000;
+       cyc = (ns << CYC2NS_SCALE_FACTOR)/(per_cpu(cyc2ns, smp_processor_id()));
+       return cyc;
 }
 
 /*
- * Our retries are blocked by all destination swack resources being
+ * Our retries are blocked by all destination sw ack resources being
  * in use, and a timeout is pending. In that case hardware immediately
  * returns the ERROR that looks like a destination timeout.
  */
-static void
-destination_plugged(struct bau_desc *bau_desc, struct bau_control *bcp,
+static void destination_plugged(struct bau_desc *bau_desc,
+                       struct bau_control *bcp,
                        struct bau_control *hmaster, struct ptc_stats *stat)
 {
        udelay(bcp->plugged_delay);
        bcp->plugged_tries++;
+
        if (bcp->plugged_tries >= bcp->plugsb4reset) {
                bcp->plugged_tries = 0;
+
                quiesce_local_uvhub(hmaster);
+
                spin_lock(&hmaster->queue_lock);
-               uv_reset_with_ipi(&bau_desc->distribution, bcp->cpu);
+               reset_with_ipi(&bau_desc->distribution, bcp->cpu);
                spin_unlock(&hmaster->queue_lock);
+
                end_uvhub_quiesce(hmaster);
+
                bcp->ipi_attempts++;
                stat->s_resets_plug++;
        }
 }
 
-static void
-destination_timeout(struct bau_desc *bau_desc, struct bau_control *bcp,
-                       struct bau_control *hmaster, struct ptc_stats *stat)
+static void destination_timeout(struct bau_desc *bau_desc,
+                       struct bau_control *bcp, struct bau_control *hmaster,
+                       struct ptc_stats *stat)
 {
-       hmaster->max_bau_concurrent = 1;
+       hmaster->max_concurr = 1;
        bcp->timeout_tries++;
        if (bcp->timeout_tries >= bcp->timeoutsb4reset) {
                bcp->timeout_tries = 0;
+
                quiesce_local_uvhub(hmaster);
+
                spin_lock(&hmaster->queue_lock);
-               uv_reset_with_ipi(&bau_desc->distribution, bcp->cpu);
+               reset_with_ipi(&bau_desc->distribution, bcp->cpu);
                spin_unlock(&hmaster->queue_lock);
+
                end_uvhub_quiesce(hmaster);
+
                bcp->ipi_attempts++;
                stat->s_resets_timeout++;
        }
@@ -530,34 +640,104 @@ destination_timeout(struct bau_desc *bau_desc, struct bau_control *bcp,
  * Completions are taking a very long time due to a congested numalink
  * network.
  */
-static void
-disable_for_congestion(struct bau_control *bcp, struct ptc_stats *stat)
+static void disable_for_congestion(struct bau_control *bcp,
+                                       struct ptc_stats *stat)
 {
-       int tcpu;
-       struct bau_control *tbcp;
-
        /* let only one cpu do this disabling */
        spin_lock(&disable_lock);
+
        if (!baudisabled && bcp->period_requests &&
            ((bcp->period_time / bcp->period_requests) > congested_cycles)) {
+               int tcpu;
+               struct bau_control *tbcp;
                /* it becomes this cpu's job to turn on the use of the
                   BAU again */
                baudisabled = 1;
                bcp->set_bau_off = 1;
-               bcp->set_bau_on_time = get_cycles() +
-                       sec_2_cycles(bcp->congested_period);
+               bcp->set_bau_on_time = get_cycles();
+               bcp->set_bau_on_time += sec_2_cycles(bcp->cong_period);
                stat->s_bau_disabled++;
                for_each_present_cpu(tcpu) {
                        tbcp = &per_cpu(bau_control, tcpu);
-                               tbcp->baudisabled = 1;
+                       tbcp->baudisabled = 1;
                }
        }
+
        spin_unlock(&disable_lock);
 }
 
-/**
- * uv_flush_send_and_wait
- *
+static void count_max_concurr(int stat, struct bau_control *bcp,
+                               struct bau_control *hmaster)
+{
+       bcp->plugged_tries = 0;
+       bcp->timeout_tries = 0;
+       if (stat != FLUSH_COMPLETE)
+               return;
+       if (bcp->conseccompletes <= bcp->complete_threshold)
+               return;
+       if (hmaster->max_concurr >= hmaster->max_concurr_const)
+               return;
+       hmaster->max_concurr++;
+}
+
+static void record_send_stats(cycles_t time1, cycles_t time2,
+               struct bau_control *bcp, struct ptc_stats *stat,
+               int completion_status, int try)
+{
+       cycles_t elapsed;
+
+       if (time2 > time1) {
+               elapsed = time2 - time1;
+               stat->s_time += elapsed;
+
+               if ((completion_status == FLUSH_COMPLETE) && (try == 1)) {
+                       bcp->period_requests++;
+                       bcp->period_time += elapsed;
+                       if ((elapsed > congested_cycles) &&
+                           (bcp->period_requests > bcp->cong_reps))
+                               disable_for_congestion(bcp, stat);
+               }
+       } else
+               stat->s_requestor--;
+
+       if (completion_status == FLUSH_COMPLETE && try > 1)
+               stat->s_retriesok++;
+       else if (completion_status == FLUSH_GIVEUP)
+               stat->s_giveup++;
+}
+
+/*
+ * Because of a uv1 hardware bug only a limited number of concurrent
+ * requests can be made.
+ */
+static void uv1_throttle(struct bau_control *hmaster, struct ptc_stats *stat)
+{
+       spinlock_t *lock = &hmaster->uvhub_lock;
+       atomic_t *v;
+
+       v = &hmaster->active_descriptor_count;
+       if (!atomic_inc_unless_ge(lock, v, hmaster->max_concurr)) {
+               stat->s_throttles++;
+               do {
+                       cpu_relax();
+               } while (!atomic_inc_unless_ge(lock, v, hmaster->max_concurr));
+       }
+}
+
+/*
+ * Handle the completion status of a message send.
+ */
+static void handle_cmplt(int completion_status, struct bau_desc *bau_desc,
+                       struct bau_control *bcp, struct bau_control *hmaster,
+                       struct ptc_stats *stat)
+{
+       if (completion_status == FLUSH_RETRY_PLUGGED)
+               destination_plugged(bau_desc, bcp, hmaster, stat);
+       else if (completion_status == FLUSH_RETRY_TIMEOUT)
+               destination_timeout(bau_desc, bcp, hmaster, stat);
+}
+
+/*
  * Send a broadcast and wait for it to complete.
  *
  * The flush_mask contains the cpus the broadcast is to be sent to including
@@ -568,44 +748,23 @@ disable_for_congestion(struct bau_control *bcp, struct ptc_stats *stat)
  * returned to the kernel.
  */
 int uv_flush_send_and_wait(struct bau_desc *bau_desc,
-                          struct cpumask *flush_mask, struct bau_control *bcp)
+                       struct cpumask *flush_mask, struct bau_control *bcp)
 {
-       int right_shift;
-       int completion_status = 0;
        int seq_number = 0;
+       int completion_stat = 0;
        long try = 0;
-       int cpu = bcp->uvhub_cpu;
-       int this_cpu = bcp->cpu;
-       unsigned long mmr_offset;
        unsigned long index;
        cycles_t time1;
        cycles_t time2;
-       cycles_t elapsed;
        struct ptc_stats *stat = bcp->statp;
-       struct bau_control *smaster = bcp->socket_master;
        struct bau_control *hmaster = bcp->uvhub_master;
 
-       if (!atomic_inc_unless_ge(&hmaster->uvhub_lock,
-                       &hmaster->active_descriptor_count,
-                       hmaster->max_bau_concurrent)) {
-               stat->s_throttles++;
-               do {
-                       cpu_relax();
-               } while (!atomic_inc_unless_ge(&hmaster->uvhub_lock,
-                       &hmaster->active_descriptor_count,
-                       hmaster->max_bau_concurrent));
-       }
+       if (is_uv1_hub())
+               uv1_throttle(hmaster, stat);
+
        while (hmaster->uvhub_quiesce)
                cpu_relax();
 
-       if (cpu < UV_CPUS_PER_ACT_STATUS) {
-               mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_0;
-               right_shift = cpu * UV_ACT_STATUS_SIZE;
-       } else {
-               mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_1;
-               right_shift =
-                   ((cpu - UV_CPUS_PER_ACT_STATUS) * UV_ACT_STATUS_SIZE);
-       }
        time1 = get_cycles();
        do {
                if (try == 0) {
@@ -615,64 +774,134 @@ int uv_flush_send_and_wait(struct bau_desc *bau_desc,
                        bau_desc->header.msg_type = MSG_RETRY;
                        stat->s_retry_messages++;
                }
+
                bau_desc->header.sequence = seq_number;
-               index = (1UL << UVH_LB_BAU_SB_ACTIVATION_CONTROL_PUSH_SHFT) |
-                       bcp->uvhub_cpu;
+               index = (1UL << AS_PUSH_SHIFT) | bcp->uvhub_cpu;
                bcp->send_message = get_cycles();
-               uv_write_local_mmr(UVH_LB_BAU_SB_ACTIVATION_CONTROL, index);
+
+               write_mmr_activation(index);
+
                try++;
-               completion_status = uv_wait_completion(bau_desc, mmr_offset,
-                       right_shift, this_cpu, bcp, smaster, try);
+               completion_stat = wait_completion(bau_desc, bcp, try);
+
+               handle_cmplt(completion_stat, bau_desc, bcp, hmaster, stat);
 
-               if (completion_status == FLUSH_RETRY_PLUGGED) {
-                       destination_plugged(bau_desc, bcp, hmaster, stat);
-               } else if (completion_status == FLUSH_RETRY_TIMEOUT) {
-                       destination_timeout(bau_desc, bcp, hmaster, stat);
-               }
                if (bcp->ipi_attempts >= bcp->ipi_reset_limit) {
                        bcp->ipi_attempts = 0;
-                       completion_status = FLUSH_GIVEUP;
+                       completion_stat = FLUSH_GIVEUP;
                        break;
                }
                cpu_relax();
-       } while ((completion_status == FLUSH_RETRY_PLUGGED) ||
-                (completion_status == FLUSH_RETRY_TIMEOUT));
+       } while ((completion_stat == FLUSH_RETRY_PLUGGED) ||
+                (completion_stat == FLUSH_RETRY_TIMEOUT));
+
        time2 = get_cycles();
-       bcp->plugged_tries = 0;
-       bcp->timeout_tries = 0;
-       if ((completion_status == FLUSH_COMPLETE) &&
-           (bcp->conseccompletes > bcp->complete_threshold) &&
-           (hmaster->max_bau_concurrent <
-                                       hmaster->max_bau_concurrent_constant))
-                       hmaster->max_bau_concurrent++;
+
+       count_max_concurr(completion_stat, bcp, hmaster);
+
        while (hmaster->uvhub_quiesce)
                cpu_relax();
+
        atomic_dec(&hmaster->active_descriptor_count);
-       if (time2 > time1) {
-               elapsed = time2 - time1;
-               stat->s_time += elapsed;
-               if ((completion_status == FLUSH_COMPLETE) && (try == 1)) {
-                       bcp->period_requests++;
-                       bcp->period_time += elapsed;
-                       if ((elapsed > congested_cycles) &&
-                           (bcp->period_requests > bcp->congested_reps)) {
-                               disable_for_congestion(bcp, stat);
+
+       record_send_stats(time1, time2, bcp, stat, completion_stat, try);
+
+       if (completion_stat == FLUSH_GIVEUP)
+               return 1;
+       return 0;
+}
+
+/*
+ * The BAU is disabled. When the disabled time period has expired, the cpu
+ * that disabled it must re-enable it.
+ * Return 0 if it is re-enabled for all cpus.
+ */
+static int check_enable(struct bau_control *bcp, struct ptc_stats *stat)
+{
+       int tcpu;
+       struct bau_control *tbcp;
+
+       if (bcp->set_bau_off) {
+               if (get_cycles() >= bcp->set_bau_on_time) {
+                       stat->s_bau_reenabled++;
+                       baudisabled = 0;
+                       for_each_present_cpu(tcpu) {
+                               tbcp = &per_cpu(bau_control, tcpu);
+                               tbcp->baudisabled = 0;
+                               tbcp->period_requests = 0;
+                               tbcp->period_time = 0;
                        }
+                       return 0;
                }
+       }
+       return -1;
+}
+
+static void record_send_statistics(struct ptc_stats *stat, int locals, int hubs,
+                               int remotes, struct bau_desc *bau_desc)
+{
+       stat->s_requestor++;
+       stat->s_ntargcpu += remotes + locals;
+       stat->s_ntargremotes += remotes;
+       stat->s_ntarglocals += locals;
+
+       /* uvhub statistics */
+       hubs = bau_uvhub_weight(&bau_desc->distribution);
+       if (locals) {
+               stat->s_ntarglocaluvhub++;
+               stat->s_ntargremoteuvhub += (hubs - 1);
        } else
-               stat->s_requestor--;
-       if (completion_status == FLUSH_COMPLETE && try > 1)
-               stat->s_retriesok++;
-       else if (completion_status == FLUSH_GIVEUP) {
-               stat->s_giveup++;
-               return 1;
+               stat->s_ntargremoteuvhub += hubs;
+
+       stat->s_ntarguvhub += hubs;
+
+       if (hubs >= 16)
+               stat->s_ntarguvhub16++;
+       else if (hubs >= 8)
+               stat->s_ntarguvhub8++;
+       else if (hubs >= 4)
+               stat->s_ntarguvhub4++;
+       else if (hubs >= 2)
+               stat->s_ntarguvhub2++;
+       else
+               stat->s_ntarguvhub1++;
+}
+
+/*
+ * Translate a cpu mask to the uvhub distribution mask in the BAU
+ * activation descriptor.
+ */
+static int set_distrib_bits(struct cpumask *flush_mask, struct bau_control *bcp,
+                       struct bau_desc *bau_desc, int *localsp, int *remotesp)
+{
+       int cpu;
+       int pnode;
+       int cnt = 0;
+       struct hub_and_pnode *hpp;
+
+       for_each_cpu(cpu, flush_mask) {
+               /*
+                * The distribution vector is a bit map of pnodes, relative
+                * to the partition base pnode (and the partition base nasid
+                * in the header).
+                * Translate cpu to pnode and hub using a local memory array.
+                */
+               hpp = &bcp->socket_master->thp[cpu];
+               pnode = hpp->pnode - bcp->partition_base_pnode;
+               bau_uvhub_set(pnode, &bau_desc->distribution);
+               cnt++;
+               if (hpp->uvhub == bcp->uvhub)
+                       (*localsp)++;
+               else
+                       (*remotesp)++;
        }
+       if (!cnt)
+               return 1;
        return 0;
 }
 
-/**
- * uv_flush_tlb_others - globally purge translation cache of a virtual
- * address or all TLB's
+/*
+ * globally purge translation cache of a virtual address or all TLB's
  * @cpumask: mask of all cpu's in which the address is to be removed
  * @mm: mm_struct containing virtual address range
  * @va: virtual address to be removed (or TLB_FLUSH_ALL for all TLB's on cpu)
@@ -696,20 +925,16 @@ int uv_flush_send_and_wait(struct bau_desc *bau_desc,
  * done.  The returned pointer is valid till preemption is re-enabled.
  */
 const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
-                                         struct mm_struct *mm,
-                                         unsigned long va, unsigned int cpu)
+                               struct mm_struct *mm, unsigned long va,
+                               unsigned int cpu)
 {
        int locals = 0;
        int remotes = 0;
        int hubs = 0;
-       int tcpu;
-       int tpnode;
        struct bau_desc *bau_desc;
        struct cpumask *flush_mask;
        struct ptc_stats *stat;
        struct bau_control *bcp;
-       struct bau_control *tbcp;
-       struct hub_and_pnode *hpp;
 
        /* kernel was booted 'nobau' */
        if (nobau)
@@ -720,20 +945,8 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
 
        /* bau was disabled due to slow response */
        if (bcp->baudisabled) {
-               /* the cpu that disabled it must re-enable it */
-               if (bcp->set_bau_off) {
-                       if (get_cycles() >= bcp->set_bau_on_time) {
-                               stat->s_bau_reenabled++;
-                               baudisabled = 0;
-                               for_each_present_cpu(tcpu) {
-                                       tbcp = &per_cpu(bau_control, tcpu);
-                                       tbcp->baudisabled = 0;
-                                       tbcp->period_requests = 0;
-                                       tbcp->period_time = 0;
-                               }
-                       }
-               }
-               return cpumask;
+               if (check_enable(bcp, stat))
+                       return cpumask;
        }
 
        /*
@@ -744,59 +957,20 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
        flush_mask = (struct cpumask *)per_cpu(uv_flush_tlb_mask, cpu);
        /* don't actually do a shootdown of the local cpu */
        cpumask_andnot(flush_mask, cpumask, cpumask_of(cpu));
+
        if (cpu_isset(cpu, *cpumask))
                stat->s_ntargself++;
 
        bau_desc = bcp->descriptor_base;
-       bau_desc += UV_ITEMS_PER_DESCRIPTOR * bcp->uvhub_cpu;
+       bau_desc += ITEMS_PER_DESC * bcp->uvhub_cpu;
        bau_uvhubs_clear(&bau_desc->distribution, UV_DISTRIBUTION_SIZE);
-
-       for_each_cpu(tcpu, flush_mask) {
-               /*
-                * The distribution vector is a bit map of pnodes, relative
-                * to the partition base pnode (and the partition base nasid
-                * in the header).
-                * Translate cpu to pnode and hub using an array stored
-                * in local memory.
-                */
-               hpp = &bcp->socket_master->target_hub_and_pnode[tcpu];
-               tpnode = hpp->pnode - bcp->partition_base_pnode;
-               bau_uvhub_set(tpnode, &bau_desc->distribution);
-               if (hpp->uvhub == bcp->uvhub)
-                       locals++;
-               else
-                       remotes++;
-       }
-       if ((locals + remotes) == 0)
+       if (set_distrib_bits(flush_mask, bcp, bau_desc, &locals, &remotes))
                return NULL;
-       stat->s_requestor++;
-       stat->s_ntargcpu += remotes + locals;
-       stat->s_ntargremotes += remotes;
-       stat->s_ntarglocals += locals;
-       remotes = bau_uvhub_weight(&bau_desc->distribution);
 
-       /* uvhub statistics */
-       hubs = bau_uvhub_weight(&bau_desc->distribution);
-       if (locals) {
-               stat->s_ntarglocaluvhub++;
-               stat->s_ntargremoteuvhub += (hubs - 1);
-       } else
-               stat->s_ntargremoteuvhub += hubs;
-       stat->s_ntarguvhub += hubs;
-       if (hubs >= 16)
-               stat->s_ntarguvhub16++;
-       else if (hubs >= 8)
-               stat->s_ntarguvhub8++;
-       else if (hubs >= 4)
-               stat->s_ntarguvhub4++;
-       else if (hubs >= 2)
-               stat->s_ntarguvhub2++;
-       else
-               stat->s_ntarguvhub1++;
+       record_send_statistics(stat, locals, hubs, remotes, bau_desc);
 
        bau_desc->payload.address = va;
        bau_desc->payload.sending_cpu = cpu;
-
        /*
         * uv_flush_send_and_wait returns 0 if all cpu's were messaged,
         * or 1 if it gave up and the original cpumask should be returned.
@@ -825,26 +999,31 @@ void uv_bau_message_interrupt(struct pt_regs *regs)
 {
        int count = 0;
        cycles_t time_start;
-       struct bau_payload_queue_entry *msg;
+       struct bau_pq_entry *msg;
        struct bau_control *bcp;
        struct ptc_stats *stat;
        struct msg_desc msgdesc;
 
        time_start = get_cycles();
+
        bcp = &per_cpu(bau_control, smp_processor_id());
        stat = bcp->statp;
-       msgdesc.va_queue_first = bcp->va_queue_first;
-       msgdesc.va_queue_last = bcp->va_queue_last;
+
+       msgdesc.queue_first = bcp->queue_first;
+       msgdesc.queue_last = bcp->queue_last;
+
        msg = bcp->bau_msg_head;
-       while (msg->sw_ack_vector) {
+       while (msg->swack_vec) {
                count++;
-               msgdesc.msg_slot = msg - msgdesc.va_queue_first;
-               msgdesc.sw_ack_slot = ffs(msg->sw_ack_vector) - 1;
+
+               msgdesc.msg_slot = msg - msgdesc.queue_first;
+               msgdesc.swack_slot = ffs(msg->swack_vec) - 1;
                msgdesc.msg = msg;
-               uv_bau_process_message(&msgdesc, bcp);
+               bau_process_message(&msgdesc, bcp);
+
                msg++;
-               if (msg > msgdesc.va_queue_last)
-                       msg = msgdesc.va_queue_first;
+               if (msg > msgdesc.queue_last)
+                       msg = msgdesc.queue_first;
                bcp->bau_msg_head = msg;
        }
        stat->d_time += (get_cycles() - time_start);
@@ -852,18 +1031,17 @@ void uv_bau_message_interrupt(struct pt_regs *regs)
                stat->d_nomsg++;
        else if (count > 1)
                stat->d_multmsg++;
+
        ack_APIC_irq();
 }
 
 /*
- * uv_enable_timeouts
- *
- * Each target uvhub (i.e. a uvhub that has no cpu's) needs to have
+ * Each target uvhub (i.e. a uvhub that has cpu's) needs to have
  * shootdown message timeouts enabled.  The timeout does not cause
  * an interrupt, but causes an error message to be returned to
  * the sender.
  */
-static void __init uv_enable_timeouts(void)
+static void __init enable_timeouts(void)
 {
        int uvhub;
        int nuvhubs;
@@ -877,47 +1055,44 @@ static void __init uv_enable_timeouts(void)
                        continue;
 
                pnode = uv_blade_to_pnode(uvhub);
-               mmr_image =
-                   uv_read_global_mmr64(pnode, UVH_LB_BAU_MISC_CONTROL);
+               mmr_image = read_mmr_misc_control(pnode);
                /*
                 * Set the timeout period and then lock it in, in three
                 * steps; captures and locks in the period.
                 *
                 * To program the period, the SOFT_ACK_MODE must be off.
                 */
-               mmr_image &= ~((unsigned long)1 <<
-                   UVH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT);
-               uv_write_global_mmr64
-                   (pnode, UVH_LB_BAU_MISC_CONTROL, mmr_image);
+               mmr_image &= ~(1L << SOFTACK_MSHIFT);
+               write_mmr_misc_control(pnode, mmr_image);
                /*
                 * Set the 4-bit period.
                 */
-               mmr_image &= ~((unsigned long)0xf <<
-                    UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT);
-               mmr_image |= (UV_INTD_SOFT_ACK_TIMEOUT_PERIOD <<
-                    UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT);
-               uv_write_global_mmr64
-                   (pnode, UVH_LB_BAU_MISC_CONTROL, mmr_image);
+               mmr_image &= ~((unsigned long)0xf << SOFTACK_PSHIFT);
+               mmr_image |= (SOFTACK_TIMEOUT_PERIOD << SOFTACK_PSHIFT);
+               write_mmr_misc_control(pnode, mmr_image);
                /*
+                * UV1:
                 * Subsequent reversals of the timebase bit (3) cause an
                 * immediate timeout of one or all INTD resources as
                 * indicated in bits 2:0 (7 causes all of them to timeout).
                 */
-               mmr_image |= ((unsigned long)1 <<
-                   UVH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT);
-               uv_write_global_mmr64
-                   (pnode, UVH_LB_BAU_MISC_CONTROL, mmr_image);
+               mmr_image |= (1L << SOFTACK_MSHIFT);
+               if (is_uv2_hub()) {
+                       mmr_image |= (1L << UV2_LEG_SHFT);
+                       mmr_image |= (1L << UV2_EXT_SHFT);
+               }
+               write_mmr_misc_control(pnode, mmr_image);
        }
 }
 
-static void *uv_ptc_seq_start(struct seq_file *file, loff_t *offset)
+static void *ptc_seq_start(struct seq_file *file, loff_t *offset)
 {
        if (*offset < num_possible_cpus())
                return offset;
        return NULL;
 }
 
-static void *uv_ptc_seq_next(struct seq_file *file, void *data, loff_t *offset)
+static void *ptc_seq_next(struct seq_file *file, void *data, loff_t *offset)
 {
        (*offset)++;
        if (*offset < num_possible_cpus())
@@ -925,12 +1100,11 @@ static void *uv_ptc_seq_next(struct seq_file *file, void *data, loff_t *offset)
        return NULL;
 }
 
-static void uv_ptc_seq_stop(struct seq_file *file, void *data)
+static void ptc_seq_stop(struct seq_file *file, void *data)
 {
 }
 
-static inline unsigned long long
-microsec_2_cycles(unsigned long microsec)
+static inline unsigned long long usec_2_cycles(unsigned long microsec)
 {
        unsigned long ns;
        unsigned long long cyc;
@@ -941,29 +1115,27 @@ microsec_2_cycles(unsigned long microsec)
 }
 
 /*
- * Display the statistics thru /proc.
+ * Display the statistics thru /proc/sgi_uv/ptc_statistics
  * 'data' points to the cpu number
+ * Note: see the descriptions in stat_description[].
  */
-static int uv_ptc_seq_show(struct seq_file *file, void *data)
+static int ptc_seq_show(struct seq_file *file, void *data)
 {
        struct ptc_stats *stat;
        int cpu;
 
        cpu = *(loff_t *)data;
-
        if (!cpu) {
                seq_printf(file,
                        "# cpu sent stime self locals remotes ncpus localhub ");
                seq_printf(file,
                        "remotehub numuvhubs numuvhubs16 numuvhubs8 ");
                seq_printf(file,
-                       "numuvhubs4 numuvhubs2 numuvhubs1 dto ");
-               seq_printf(file,
-                       "retries rok resetp resett giveup sto bz throt ");
+                       "numuvhubs4 numuvhubs2 numuvhubs1 dto retries rok ");
                seq_printf(file,
-                       "sw_ack recv rtime all ");
+                       "resetp resett giveup sto bz throt swack recv rtime ");
                seq_printf(file,
-                       "one mult none retry canc nocan reset rcan ");
+                       "all one mult none retry canc nocan reset rcan ");
                seq_printf(file,
                        "disable enable\n");
        }
@@ -990,8 +1162,7 @@ static int uv_ptc_seq_show(struct seq_file *file, void *data)
                /* destination side statistics */
                seq_printf(file,
                           "%lx %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ",
-                          uv_read_global_mmr64(uv_cpu_to_pnode(cpu),
-                                       UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE),
+                          read_gmmr_sw_ack(uv_cpu_to_pnode(cpu)),
                           stat->d_requestee, cycles_2_us(stat->d_time),
                           stat->d_alltlb, stat->d_onetlb, stat->d_multmsg,
                           stat->d_nomsg, stat->d_retries, stat->d_canceled,
@@ -1000,7 +1171,6 @@ static int uv_ptc_seq_show(struct seq_file *file, void *data)
                seq_printf(file, "%ld %ld\n",
                        stat->s_bau_disabled, stat->s_bau_reenabled);
        }
-
        return 0;
 }
 
@@ -1008,18 +1178,18 @@ static int uv_ptc_seq_show(struct seq_file *file, void *data)
  * Display the tunables thru debugfs
  */
 static ssize_t tunables_read(struct file *file, char __user *userbuf,
-                                               size_t count, loff_t *ppos)
+                               size_t count, loff_t *ppos)
 {
        char *buf;
        int ret;
 
        buf = kasprintf(GFP_KERNEL, "%s %s %s\n%d %d %d %d %d %d %d %d %d\n",
-               "max_bau_concurrent plugged_delay plugsb4reset",
+               "max_concur plugged_delay plugsb4reset",
                "timeoutsb4reset ipi_reset_limit complete_threshold",
                "congested_response_us congested_reps congested_period",
-               max_bau_concurrent, plugged_delay, plugsb4reset,
+               max_concurr, plugged_delay, plugsb4reset,
                timeoutsb4reset, ipi_reset_limit, complete_threshold,
-               congested_response_us, congested_reps, congested_period);
+               congested_respns_us, congested_reps, congested_period);
 
        if (!buf)
                return -ENOMEM;
@@ -1030,13 +1200,16 @@ static ssize_t tunables_read(struct file *file, char __user *userbuf,
 }
 
 /*
- * -1: resetf the statistics
+ * handle a write to /proc/sgi_uv/ptc_statistics
+ * -1: reset the statistics
  *  0: display meaning of the statistics
  */
-static ssize_t uv_ptc_proc_write(struct file *file, const char __user *user,
-                                size_t count, loff_t *data)
+static ssize_t ptc_proc_write(struct file *file, const char __user *user,
+                               size_t count, loff_t *data)
 {
        int cpu;
+       int i;
+       int elements;
        long input_arg;
        char optstr[64];
        struct ptc_stats *stat;
@@ -1046,79 +1219,18 @@ static ssize_t uv_ptc_proc_write(struct file *file, const char __user *user,
        if (copy_from_user(optstr, user, count))
                return -EFAULT;
        optstr[count - 1] = '\0';
+
        if (strict_strtol(optstr, 10, &input_arg) < 0) {
                printk(KERN_DEBUG "%s is invalid\n", optstr);
                return -EINVAL;
        }
 
        if (input_arg == 0) {
+               elements = sizeof(stat_description)/sizeof(*stat_description);
                printk(KERN_DEBUG "# cpu:      cpu number\n");
                printk(KERN_DEBUG "Sender statistics:\n");
-               printk(KERN_DEBUG
-               "sent:     number of shootdown messages sent\n");
-               printk(KERN_DEBUG
-               "stime:    time spent sending messages\n");
-               printk(KERN_DEBUG
-               "numuvhubs: number of hubs targeted with shootdown\n");
-               printk(KERN_DEBUG
-               "numuvhubs16: number times 16 or more hubs targeted\n");
-               printk(KERN_DEBUG
-               "numuvhubs8: number times 8 or more hubs targeted\n");
-               printk(KERN_DEBUG
-               "numuvhubs4: number times 4 or more hubs targeted\n");
-               printk(KERN_DEBUG
-               "numuvhubs2: number times 2 or more hubs targeted\n");
-               printk(KERN_DEBUG
-               "numuvhubs1: number times 1 hub targeted\n");
-               printk(KERN_DEBUG
-               "numcpus:  number of cpus targeted with shootdown\n");
-               printk(KERN_DEBUG
-               "dto:      number of destination timeouts\n");
-               printk(KERN_DEBUG
-               "retries:  destination timeout retries sent\n");
-               printk(KERN_DEBUG
-               "rok:   :  destination timeouts successfully retried\n");
-               printk(KERN_DEBUG
-               "resetp:   ipi-style resource resets for plugs\n");
-               printk(KERN_DEBUG
-               "resett:   ipi-style resource resets for timeouts\n");
-               printk(KERN_DEBUG
-               "giveup:   fall-backs to ipi-style shootdowns\n");
-               printk(KERN_DEBUG
-               "sto:      number of source timeouts\n");
-               printk(KERN_DEBUG
-               "bz:       number of stay-busy's\n");
-               printk(KERN_DEBUG
-               "throt:    number times spun in throttle\n");
-               printk(KERN_DEBUG "Destination side statistics:\n");
-               printk(KERN_DEBUG
-               "sw_ack:   image of UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE\n");
-               printk(KERN_DEBUG
-               "recv:     shootdown messages received\n");
-               printk(KERN_DEBUG
-               "rtime:    time spent processing messages\n");
-               printk(KERN_DEBUG
-               "all:      shootdown all-tlb messages\n");
-               printk(KERN_DEBUG
-               "one:      shootdown one-tlb messages\n");
-               printk(KERN_DEBUG
-               "mult:     interrupts that found multiple messages\n");
-               printk(KERN_DEBUG
-               "none:     interrupts that found no messages\n");
-               printk(KERN_DEBUG
-               "retry:    number of retry messages processed\n");
-               printk(KERN_DEBUG
-               "canc:     number messages canceled by retries\n");
-               printk(KERN_DEBUG
-               "nocan:    number retries that found nothing to cancel\n");
-               printk(KERN_DEBUG
-               "reset:    number of ipi-style reset requests processed\n");
-               printk(KERN_DEBUG
-               "rcan:     number messages canceled by reset requests\n");
-               printk(KERN_DEBUG
-               "disable:  number times use of the BAU was disabled\n");
-               printk(KERN_DEBUG
-               "enable:   number times use of the BAU was re-enabled\n");
+               for (i = 0; i < elements; i++)
+                       printk(KERN_DEBUG "%s\n", stat_description[i]);
        } else if (input_arg == -1) {
                for_each_present_cpu(cpu) {
                        stat = &per_cpu(ptcstats, cpu);
@@ -1145,27 +1257,18 @@ static int local_atoi(const char *name)
 }
 
 /*
- * set the tunables
- * 0 values reset them to defaults
+ * Parse the values written to /sys/kernel/debug/sgi_uv/bau_tunables.
+ * Zero values reset them to defaults.
  */
-static ssize_t tunables_write(struct file *file, const char __user *user,
-                                size_t count, loff_t *data)
+static int parse_tunables_write(struct bau_control *bcp, char *instr,
+                               int count)
 {
-       int cpu;
-       int cnt = 0;
-       int val;
        char *p;
        char *q;
-       char instr[64];
-       struct bau_control *bcp;
-
-       if (count == 0 || count > sizeof(instr)-1)
-               return -EINVAL;
-       if (copy_from_user(instr, user, count))
-               return -EFAULT;
+       int cnt = 0;
+       int val;
+       int e = sizeof(tunables) / sizeof(*tunables);
 
-       instr[count] = '\0';
-       /* count the fields */
        p = instr + strspn(instr, WHITESPACE);
        q = p;
        for (; *p; p = q + strspn(q, WHITESPACE)) {
@@ -1174,8 +1277,8 @@ static ssize_t tunables_write(struct file *file, const char __user *user,
                if (q == p)
                        break;
        }
-       if (cnt != 9) {
-               printk(KERN_INFO "bau tunable error: should be 9 numbers\n");
+       if (cnt != e) {
+               printk(KERN_INFO "bau tunable error: should be %d values\n", e);
                return -EINVAL;
        }
 
@@ -1187,97 +1290,80 @@ static ssize_t tunables_write(struct file *file, const char __user *user,
                switch (cnt) {
                case 0:
                        if (val == 0) {
-                               max_bau_concurrent = MAX_BAU_CONCURRENT;
-                               max_bau_concurrent_constant =
-                                                       MAX_BAU_CONCURRENT;
+                               max_concurr = MAX_BAU_CONCURRENT;
+                               max_concurr_const = MAX_BAU_CONCURRENT;
                                continue;
                        }
-                       bcp = &per_cpu(bau_control, smp_processor_id());
                        if (val < 1 || val > bcp->cpus_in_uvhub) {
                                printk(KERN_DEBUG
                                "Error: BAU max concurrent %d is invalid\n",
                                val);
                                return -EINVAL;
                        }
-                       max_bau_concurrent = val;
-                       max_bau_concurrent_constant = val;
-                       continue;
-               case 1:
-                       if (val == 0)
-                               plugged_delay = PLUGGED_DELAY;
-                       else
-                               plugged_delay = val;
-                       continue;
-               case 2:
-                       if (val == 0)
-                               plugsb4reset = PLUGSB4RESET;
-                       else
-                               plugsb4reset = val;
-                       continue;
-               case 3:
-                       if (val == 0)
-                               timeoutsb4reset = TIMEOUTSB4RESET;
-                       else
-                               timeoutsb4reset = val;
-                       continue;
-               case 4:
-                       if (val == 0)
-                               ipi_reset_limit = IPI_RESET_LIMIT;
-                       else
-                               ipi_reset_limit = val;
-                       continue;
-               case 5:
-                       if (val == 0)
-                               complete_threshold = COMPLETE_THRESHOLD;
-                       else
-                               complete_threshold = val;
-                       continue;
-               case 6:
-                       if (val == 0)
-                               congested_response_us = CONGESTED_RESPONSE_US;
-                       else
-                               congested_response_us = val;
-                       continue;
-               case 7:
-                       if (val == 0)
-                               congested_reps = CONGESTED_REPS;
-                       else
-                               congested_reps = val;
+                       max_concurr = val;
+                       max_concurr_const = val;
                        continue;
-               case 8:
+               default:
                        if (val == 0)
-                               congested_period = CONGESTED_PERIOD;
+                               *tunables[cnt].tunp = tunables[cnt].deflt;
                        else
-                               congested_period = val;
+                               *tunables[cnt].tunp = val;
                        continue;
                }
                if (q == p)
                        break;
        }
+       return 0;
+}
+
+/*
+ * Handle a write to debugfs. (/sys/kernel/debug/sgi_uv/bau_tunables)
+ */
+static ssize_t tunables_write(struct file *file, const char __user *user,
+                               size_t count, loff_t *data)
+{
+       int cpu;
+       int ret;
+       char instr[100];
+       struct bau_control *bcp;
+
+       if (count == 0 || count > sizeof(instr)-1)
+               return -EINVAL;
+       if (copy_from_user(instr, user, count))
+               return -EFAULT;
+
+       instr[count] = '\0';
+
+       bcp = &per_cpu(bau_control, smp_processor_id());
+
+       ret = parse_tunables_write(bcp, instr, count);
+       if (ret)
+               return ret;
+
        for_each_present_cpu(cpu) {
                bcp = &per_cpu(bau_control, cpu);
-               bcp->max_bau_concurrent = max_bau_concurrent;
-               bcp->max_bau_concurrent_constant = max_bau_concurrent;
-               bcp->plugged_delay = plugged_delay;
-               bcp->plugsb4reset = plugsb4reset;
-               bcp->timeoutsb4reset = timeoutsb4reset;
-               bcp->ipi_reset_limit = ipi_reset_limit;
-               bcp->complete_threshold = complete_threshold;
-               bcp->congested_response_us = congested_response_us;
-               bcp->congested_reps = congested_reps;
-               bcp->congested_period = congested_period;
+               bcp->max_concurr =              max_concurr;
+               bcp->max_concurr_const =        max_concurr;
+               bcp->plugged_delay =            plugged_delay;
+               bcp->plugsb4reset =             plugsb4reset;
+               bcp->timeoutsb4reset =          timeoutsb4reset;
+               bcp->ipi_reset_limit =          ipi_reset_limit;
+               bcp->complete_threshold =       complete_threshold;
+               bcp->cong_response_us =         congested_respns_us;
+               bcp->cong_reps =                congested_reps;
+               bcp->cong_period =              congested_period;
        }
        return count;
 }
 
 static const struct seq_operations uv_ptc_seq_ops = {
-       .start          = uv_ptc_seq_start,
-       .next           = uv_ptc_seq_next,
-       .stop           = uv_ptc_seq_stop,
-       .show           = uv_ptc_seq_show
+       .start          = ptc_seq_start,
+       .next           = ptc_seq_next,
+       .stop           = ptc_seq_stop,
+       .show           = ptc_seq_show
 };
 
-static int uv_ptc_proc_open(struct inode *inode, struct file *file)
+static int ptc_proc_open(struct inode *inode, struct file *file)
 {
        return seq_open(file, &uv_ptc_seq_ops);
 }
@@ -1288,9 +1374,9 @@ static int tunables_open(struct inode *inode, struct file *file)
 }
 
 static const struct file_operations proc_uv_ptc_operations = {
-       .open           = uv_ptc_proc_open,
+       .open           = ptc_proc_open,
        .read           = seq_read,
-       .write          = uv_ptc_proc_write,
+       .write          = ptc_proc_write,
        .llseek         = seq_lseek,
        .release        = seq_release,
 };
@@ -1324,7 +1410,7 @@ static int __init uv_ptc_init(void)
                return -EINVAL;
        }
        tunables_file = debugfs_create_file(UV_BAU_TUNABLES_FILE, 0600,
-                       tunables_dir, NULL, &tunables_fops);
+                                       tunables_dir, NULL, &tunables_fops);
        if (!tunables_file) {
                printk(KERN_ERR "unable to create debugfs file %s\n",
                       UV_BAU_TUNABLES_FILE);
@@ -1336,24 +1422,24 @@ static int __init uv_ptc_init(void)
 /*
  * Initialize the sending side's sending buffers.
  */
-static void
-uv_activation_descriptor_init(int node, int pnode, int base_pnode)
+static void activation_descriptor_init(int node, int pnode, int base_pnode)
 {
        int i;
        int cpu;
        unsigned long pa;
        unsigned long m;
        unsigned long n;
+       size_t dsize;
        struct bau_desc *bau_desc;
        struct bau_desc *bd2;
        struct bau_control *bcp;
 
        /*
-        * each bau_desc is 64 bytes; there are 8 (UV_ITEMS_PER_DESCRIPTOR)
-        * per cpu; and one per cpu on the uvhub (UV_ADP_SIZE)
+        * each bau_desc is 64 bytes; there are 8 (ITEMS_PER_DESC)
+        * per cpu; and one per cpu on the uvhub (ADP_SZ)
         */
-       bau_desc = kmalloc_node(sizeof(struct bau_desc) * UV_ADP_SIZE
-                               * UV_ITEMS_PER_DESCRIPTOR, GFP_KERNEL, node);
+       dsize = sizeof(struct bau_desc) * ADP_SZ * ITEMS_PER_DESC;
+       bau_desc = kmalloc_node(dsize, GFP_KERNEL, node);
        BUG_ON(!bau_desc);
 
        pa = uv_gpa(bau_desc); /* need the real nasid*/
@@ -1361,27 +1447,25 @@ uv_activation_descriptor_init(int node, int pnode, int base_pnode)
        m = pa & uv_mmask;
 
        /* the 14-bit pnode */
-       uv_write_global_mmr64(pnode, UVH_LB_BAU_SB_DESCRIPTOR_BASE,
-                             (n << UV_DESC_BASE_PNODE_SHIFT | m));
+       write_mmr_descriptor_base(pnode, (n << UV_DESC_PSHIFT | m));
        /*
-        * Initializing all 8 (UV_ITEMS_PER_DESCRIPTOR) descriptors for each
+        * Initializing all 8 (ITEMS_PER_DESC) descriptors for each
         * cpu even though we only use the first one; one descriptor can
         * describe a broadcast to 256 uv hubs.
         */
-       for (i = 0, bd2 = bau_desc; i < (UV_ADP_SIZE*UV_ITEMS_PER_DESCRIPTOR);
-               i++, bd2++) {
+       for (i = 0, bd2 = bau_desc; i < (ADP_SZ * ITEMS_PER_DESC); i++, bd2++) {
                memset(bd2, 0, sizeof(struct bau_desc));
-               bd2->header.sw_ack_flag = 1;
+               bd2->header.swack_flag =        1;
                /*
                 * The base_dest_nasid set in the message header is the nasid
                 * of the first uvhub in the partition. The bit map will
                 * indicate destination pnode numbers relative to that base.
                 * They may not be consecutive if nasid striding is being used.
                 */
-               bd2->header.base_dest_nasid = UV_PNODE_TO_NASID(base_pnode);
-               bd2->header.dest_subnodeid = UV_LB_SUBNODEID;
-               bd2->header.command = UV_NET_ENDPOINT_INTD;
-               bd2->header.int_both = 1;
+               bd2->header.base_dest_nasid =   UV_PNODE_TO_NASID(base_pnode);
+               bd2->header.dest_subnodeid =    UV_LB_SUBNODEID;
+               bd2->header.command =           UV_NET_ENDPOINT_INTD;
+               bd2->header.int_both =          1;
                /*
                 * all others need to be set to zero:
                 *   fairness chaining multilevel count replied_to
@@ -1401,57 +1485,55 @@ uv_activation_descriptor_init(int node, int pnode, int base_pnode)
  * - node is first node (kernel memory notion) on the uvhub
  * - pnode is the uvhub's physical identifier
  */
-static void
-uv_payload_queue_init(int node, int pnode)
+static void pq_init(int node, int pnode)
 {
-       int pn;
        int cpu;
+       size_t plsize;
        char *cp;
-       unsigned long pa;
-       struct bau_payload_queue_entry *pqp;
-       struct bau_payload_queue_entry *pqp_malloc;
+       void *vp;
+       unsigned long pn;
+       unsigned long first;
+       unsigned long pn_first;
+       unsigned long last;
+       struct bau_pq_entry *pqp;
        struct bau_control *bcp;
 
-       pqp = kmalloc_node((DEST_Q_SIZE + 1)
-                          * sizeof(struct bau_payload_queue_entry),
-                          GFP_KERNEL, node);
+       plsize = (DEST_Q_SIZE + 1) * sizeof(struct bau_pq_entry);
+       vp = kmalloc_node(plsize, GFP_KERNEL, node);
+       pqp = (struct bau_pq_entry *)vp;
        BUG_ON(!pqp);
-       pqp_malloc = pqp;
 
        cp = (char *)pqp + 31;
-       pqp = (struct bau_payload_queue_entry *)(((unsigned long)cp >> 5) << 5);
+       pqp = (struct bau_pq_entry *)(((unsigned long)cp >> 5) << 5);
 
        for_each_present_cpu(cpu) {
                if (pnode != uv_cpu_to_pnode(cpu))
                        continue;
                /* for every cpu on this pnode: */
                bcp = &per_cpu(bau_control, cpu);
-               bcp->va_queue_first = pqp;
-               bcp->bau_msg_head = pqp;
-               bcp->va_queue_last = pqp + (DEST_Q_SIZE - 1);
+               bcp->queue_first        = pqp;
+               bcp->bau_msg_head       = pqp;
+               bcp->queue_last         = pqp + (DEST_Q_SIZE - 1);
        }
        /*
         * need the pnode of where the memory was really allocated
         */
-       pa = uv_gpa(pqp);
-       pn = pa >> uv_nshift;
-       uv_write_global_mmr64(pnode,
-                             UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST,
-                             ((unsigned long)pn << UV_PAYLOADQ_PNODE_SHIFT) |
-                             uv_physnodeaddr(pqp));
-       uv_write_global_mmr64(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL,
-                             uv_physnodeaddr(pqp));
-       uv_write_global_mmr64(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST,
-                             (unsigned long)
-                             uv_physnodeaddr(pqp + (DEST_Q_SIZE - 1)));
+       pn = uv_gpa(pqp) >> uv_nshift;
+       first = uv_physnodeaddr(pqp);
+       pn_first = ((unsigned long)pn << UV_PAYLOADQ_PNODE_SHIFT) | first;
+       last = uv_physnodeaddr(pqp + (DEST_Q_SIZE - 1));
+       write_mmr_payload_first(pnode, pn_first);
+       write_mmr_payload_tail(pnode, first);
+       write_mmr_payload_last(pnode, last);
+
        /* in effect, all msg_type's are set to MSG_NOOP */
-       memset(pqp, 0, sizeof(struct bau_payload_queue_entry) * DEST_Q_SIZE);
+       memset(pqp, 0, sizeof(struct bau_pq_entry) * DEST_Q_SIZE);
 }
 
 /*
  * Initialization of each UV hub's structures
  */
-static void __init uv_init_uvhub(int uvhub, int vector, int base_pnode)
+static void __init init_uvhub(int uvhub, int vector, int base_pnode)
 {
        int node;
        int pnode;
@@ -1459,24 +1541,24 @@ static void __init uv_init_uvhub(int uvhub, int vector, int base_pnode)
 
        node = uvhub_to_first_node(uvhub);
        pnode = uv_blade_to_pnode(uvhub);
-       uv_activation_descriptor_init(node, pnode, base_pnode);
-       uv_payload_queue_init(node, pnode);
+
+       activation_descriptor_init(node, pnode, base_pnode);
+
+       pq_init(node, pnode);
        /*
         * The below initialization can't be in firmware because the
         * messaging IRQ will be determined by the OS.
         */
        apicid = uvhub_to_first_apicid(uvhub) | uv_apicid_hibits;
-       uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG,
-                                     ((apicid << 32) | vector));
+       write_mmr_data_config(pnode, ((apicid << 32) | vector));
 }
 
 /*
  * We will set BAU_MISC_CONTROL with a timeout period.
  * But the BIOS has set UVH_AGING_PRESCALE_SEL and UVH_TRANSACTION_TIMEOUT.
- * So the destination timeout period has be be calculated from them.
+ * So the destination timeout period has to be calculated from them.
  */
-static int
-calculate_destination_timeout(void)
+static int calculate_destination_timeout(void)
 {
        unsigned long mmr_image;
        int mult1;
@@ -1486,73 +1568,92 @@ calculate_destination_timeout(void)
        int ret;
        unsigned long ts_ns;
 
-       mult1 = UV_INTD_SOFT_ACK_TIMEOUT_PERIOD & BAU_MISC_CONTROL_MULT_MASK;
-       mmr_image = uv_read_local_mmr(UVH_AGING_PRESCALE_SEL);
-       index = (mmr_image >> BAU_URGENCY_7_SHIFT) & BAU_URGENCY_7_MASK;
-       mmr_image = uv_read_local_mmr(UVH_TRANSACTION_TIMEOUT);
-       mult2 = (mmr_image >> BAU_TRANS_SHIFT) & BAU_TRANS_MASK;
-       base = timeout_base_ns[index];
-       ts_ns = base * mult1 * mult2;
-       ret = ts_ns / 1000;
+       if (is_uv1_hub()) {
+               mult1 = SOFTACK_TIMEOUT_PERIOD & BAU_MISC_CONTROL_MULT_MASK;
+               mmr_image = uv_read_local_mmr(UVH_AGING_PRESCALE_SEL);
+               index = (mmr_image >> BAU_URGENCY_7_SHIFT) & BAU_URGENCY_7_MASK;
+               mmr_image = uv_read_local_mmr(UVH_TRANSACTION_TIMEOUT);
+               mult2 = (mmr_image >> BAU_TRANS_SHIFT) & BAU_TRANS_MASK;
+               base = timeout_base_ns[index];
+               ts_ns = base * mult1 * mult2;
+               ret = ts_ns / 1000;
+       } else {
+               /* 4 bits  0/1 for 10/80us, 3 bits of multiplier */
+               mmr_image = uv_read_local_mmr(UVH_AGING_PRESCALE_SEL);
+               mmr_image = (mmr_image & UV_SA_MASK) >> UV_SA_SHFT;
+               if (mmr_image & (1L << UV2_ACK_UNITS_SHFT))
+                       mult1 = 80;
+               else
+                       mult1 = 10;
+               base = mmr_image & UV2_ACK_MASK;
+               ret = mult1 * base;
+       }
        return ret;
 }
 
+static void __init init_per_cpu_tunables(void)
+{
+       int cpu;
+       struct bau_control *bcp;
+
+       for_each_present_cpu(cpu) {
+               bcp = &per_cpu(bau_control, cpu);
+               bcp->baudisabled                = 0;
+               bcp->statp                      = &per_cpu(ptcstats, cpu);
+               /* time interval to catch a hardware stay-busy bug */
+               bcp->timeout_interval           = usec_2_cycles(2*timeout_us);
+               bcp->max_concurr                = max_concurr;
+               bcp->max_concurr_const          = max_concurr;
+               bcp->plugged_delay              = plugged_delay;
+               bcp->plugsb4reset               = plugsb4reset;
+               bcp->timeoutsb4reset            = timeoutsb4reset;
+               bcp->ipi_reset_limit            = ipi_reset_limit;
+               bcp->complete_threshold         = complete_threshold;
+               bcp->cong_response_us           = congested_respns_us;
+               bcp->cong_reps                  = congested_reps;
+               bcp->cong_period                = congested_period;
+       }
+}
+
 /*
- * initialize the bau_control structure for each cpu
+ * Scan all cpus to collect blade and socket summaries.
  */
-static int __init uv_init_per_cpu(int nuvhubs, int base_part_pnode)
+static int __init get_cpu_topology(int base_pnode,
+                                       struct uvhub_desc *uvhub_descs,
+                                       unsigned char *uvhub_mask)
 {
-       int i;
        int cpu;
-       int tcpu;
        int pnode;
        int uvhub;
-       int have_hmaster;
-       short socket = 0;
-       unsigned short socket_mask;
-       unsigned char *uvhub_mask;
+       int socket;
        struct bau_control *bcp;
        struct uvhub_desc *bdp;
        struct socket_desc *sdp;
-       struct bau_control *hmaster = NULL;
-       struct bau_control *smaster = NULL;
-       struct socket_desc {
-               short num_cpus;
-               short cpu_number[MAX_CPUS_PER_SOCKET];
-       };
-       struct uvhub_desc {
-               unsigned short socket_mask;
-               short num_cpus;
-               short uvhub;
-               short pnode;
-               struct socket_desc socket[2];
-       };
-       struct uvhub_desc *uvhub_descs;
-
-       timeout_us = calculate_destination_timeout();
 
-       uvhub_descs = kmalloc(nuvhubs * sizeof(struct uvhub_desc), GFP_KERNEL);
-       memset(uvhub_descs, 0, nuvhubs * sizeof(struct uvhub_desc));
-       uvhub_mask = kzalloc((nuvhubs+7)/8, GFP_KERNEL);
        for_each_present_cpu(cpu) {
                bcp = &per_cpu(bau_control, cpu);
+
                memset(bcp, 0, sizeof(struct bau_control));
+
                pnode = uv_cpu_hub_info(cpu)->pnode;
-               if ((pnode - base_part_pnode) >= UV_DISTRIBUTION_SIZE) {
+               if ((pnode - base_pnode) >= UV_DISTRIBUTION_SIZE) {
                        printk(KERN_EMERG
                                "cpu %d pnode %d-%d beyond %d; BAU disabled\n",
-                               cpu, pnode, base_part_pnode,
-                               UV_DISTRIBUTION_SIZE);
+                               cpu, pnode, base_pnode, UV_DISTRIBUTION_SIZE);
                        return 1;
                }
+
                bcp->osnode = cpu_to_node(cpu);
-               bcp->partition_base_pnode = uv_partition_base_pnode;
+               bcp->partition_base_pnode = base_pnode;
+
                uvhub = uv_cpu_hub_info(cpu)->numa_blade_id;
                *(uvhub_mask + (uvhub/8)) |= (1 << (uvhub%8));
                bdp = &uvhub_descs[uvhub];
+
                bdp->num_cpus++;
                bdp->uvhub = uvhub;
                bdp->pnode = pnode;
+
                /* kludge: 'assuming' one node per socket, and assuming that
                   disabling a socket just leaves a gap in node numbers */
                socket = bcp->osnode & 1;
@@ -1561,84 +1662,129 @@ static int __init uv_init_per_cpu(int nuvhubs, int base_part_pnode)
                sdp->cpu_number[sdp->num_cpus] = cpu;
                sdp->num_cpus++;
                if (sdp->num_cpus > MAX_CPUS_PER_SOCKET) {
-                       printk(KERN_EMERG "%d cpus per socket invalid\n", sdp->num_cpus);
+                       printk(KERN_EMERG "%d cpus per socket invalid\n",
+                               sdp->num_cpus);
                        return 1;
                }
        }
+       return 0;
+}
+
+/*
+ * Each socket is to get a local array of pnodes/hubs.
+ */
+static void make_per_cpu_thp(struct bau_control *smaster)
+{
+       int cpu;
+       size_t hpsz = sizeof(struct hub_and_pnode) * num_possible_cpus();
+
+       smaster->thp = kmalloc_node(hpsz, GFP_KERNEL, smaster->osnode);
+       memset(smaster->thp, 0, hpsz);
+       for_each_present_cpu(cpu) {
+               smaster->thp[cpu].pnode = uv_cpu_hub_info(cpu)->pnode;
+               smaster->thp[cpu].uvhub = uv_cpu_hub_info(cpu)->numa_blade_id;
+       }
+}
+
+/*
+ * Initialize all the per_cpu information for the cpu's on a given socket,
+ * given what has been gathered into the socket_desc struct.
+ * And reports the chosen hub and socket masters back to the caller.
+ */
+static int scan_sock(struct socket_desc *sdp, struct uvhub_desc *bdp,
+                       struct bau_control **smasterp,
+                       struct bau_control **hmasterp)
+{
+       int i;
+       int cpu;
+       struct bau_control *bcp;
+
+       for (i = 0; i < sdp->num_cpus; i++) {
+               cpu = sdp->cpu_number[i];
+               bcp = &per_cpu(bau_control, cpu);
+               bcp->cpu = cpu;
+               if (i == 0) {
+                       *smasterp = bcp;
+                       if (!(*hmasterp))
+                               *hmasterp = bcp;
+               }
+               bcp->cpus_in_uvhub = bdp->num_cpus;
+               bcp->cpus_in_socket = sdp->num_cpus;
+               bcp->socket_master = *smasterp;
+               bcp->uvhub = bdp->uvhub;
+               bcp->uvhub_master = *hmasterp;
+               bcp->uvhub_cpu = uv_cpu_hub_info(cpu)->blade_processor_id;
+               if (bcp->uvhub_cpu >= MAX_CPUS_PER_UVHUB) {
+                       printk(KERN_EMERG "%d cpus per uvhub invalid\n",
+                               bcp->uvhub_cpu);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Summarize the blade and socket topology into the per_cpu structures.
+ */
+static int __init summarize_uvhub_sockets(int nuvhubs,
+                       struct uvhub_desc *uvhub_descs,
+                       unsigned char *uvhub_mask)
+{
+       int socket;
+       int uvhub;
+       unsigned short socket_mask;
+
        for (uvhub = 0; uvhub < nuvhubs; uvhub++) {
+               struct uvhub_desc *bdp;
+               struct bau_control *smaster = NULL;
+               struct bau_control *hmaster = NULL;
+
                if (!(*(uvhub_mask + (uvhub/8)) & (1 << (uvhub%8))))
                        continue;
-               have_hmaster = 0;
+
                bdp = &uvhub_descs[uvhub];
                socket_mask = bdp->socket_mask;
                socket = 0;
                while (socket_mask) {
-                       if (!(socket_mask & 1))
-                               goto nextsocket;
-                       sdp = &bdp->socket[socket];
-                       for (i = 0; i < sdp->num_cpus; i++) {
-                               cpu = sdp->cpu_number[i];
-                               bcp = &per_cpu(bau_control, cpu);
-                               bcp->cpu = cpu;
-                               if (i == 0) {
-                                       smaster = bcp;
-                                       if (!have_hmaster) {
-                                               have_hmaster++;
-                                               hmaster = bcp;
-                                       }
-                               }
-                               bcp->cpus_in_uvhub = bdp->num_cpus;
-                               bcp->cpus_in_socket = sdp->num_cpus;
-                               bcp->socket_master = smaster;
-                               bcp->uvhub = bdp->uvhub;
-                               bcp->uvhub_master = hmaster;
-                               bcp->uvhub_cpu = uv_cpu_hub_info(cpu)->
-                                               blade_processor_id;
-                               if (bcp->uvhub_cpu >= MAX_CPUS_PER_UVHUB) {
-                                       printk(KERN_EMERG
-                                               "%d cpus per uvhub invalid\n",
-                                               bcp->uvhub_cpu);
+                       struct socket_desc *sdp;
+                       if ((socket_mask & 1)) {
+                               sdp = &bdp->socket[socket];
+                               if (scan_sock(sdp, bdp, &smaster, &hmaster))
                                        return 1;
-                               }
                        }
-nextsocket:
                        socket++;
                        socket_mask = (socket_mask >> 1);
-                       /* each socket gets a local array of pnodes/hubs */
-                       bcp = smaster;
-                       bcp->target_hub_and_pnode = kmalloc_node(
-                               sizeof(struct hub_and_pnode) *
-                               num_possible_cpus(), GFP_KERNEL, bcp->osnode);
-                       memset(bcp->target_hub_and_pnode, 0,
-                               sizeof(struct hub_and_pnode) *
-                               num_possible_cpus());
-                       for_each_present_cpu(tcpu) {
-                               bcp->target_hub_and_pnode[tcpu].pnode =
-                                       uv_cpu_hub_info(tcpu)->pnode;
-                               bcp->target_hub_and_pnode[tcpu].uvhub =
-                                       uv_cpu_hub_info(tcpu)->numa_blade_id;
-                       }
+                       make_per_cpu_thp(smaster);
                }
        }
+       return 0;
+}
+
+/*
+ * initialize the bau_control structure for each cpu
+ */
+static int __init init_per_cpu(int nuvhubs, int base_part_pnode)
+{
+       unsigned char *uvhub_mask;
+       void *vp;
+       struct uvhub_desc *uvhub_descs;
+
+       timeout_us = calculate_destination_timeout();
+
+       vp = kmalloc(nuvhubs * sizeof(struct uvhub_desc), GFP_KERNEL);
+       uvhub_descs = (struct uvhub_desc *)vp;
+       memset(uvhub_descs, 0, nuvhubs * sizeof(struct uvhub_desc));
+       uvhub_mask = kzalloc((nuvhubs+7)/8, GFP_KERNEL);
+
+       if (get_cpu_topology(base_part_pnode, uvhub_descs, uvhub_mask))
+               return 1;
+
+       if (summarize_uvhub_sockets(nuvhubs, uvhub_descs, uvhub_mask))
+               return 1;
+
        kfree(uvhub_descs);
        kfree(uvhub_mask);
-       for_each_present_cpu(cpu) {
-               bcp = &per_cpu(bau_control, cpu);
-               bcp->baudisabled = 0;
-               bcp->statp = &per_cpu(ptcstats, cpu);
-               /* time interval to catch a hardware stay-busy bug */
-               bcp->timeout_interval = microsec_2_cycles(2*timeout_us);
-               bcp->max_bau_concurrent = max_bau_concurrent;
-               bcp->max_bau_concurrent_constant = max_bau_concurrent;
-               bcp->plugged_delay = plugged_delay;
-               bcp->plugsb4reset = plugsb4reset;
-               bcp->timeoutsb4reset = timeoutsb4reset;
-               bcp->ipi_reset_limit = ipi_reset_limit;
-               bcp->complete_threshold = complete_threshold;
-               bcp->congested_response_us = congested_response_us;
-               bcp->congested_reps = congested_reps;
-               bcp->congested_period = congested_period;
-       }
+       init_per_cpu_tunables();
        return 0;
 }
 
@@ -1651,8 +1797,9 @@ static int __init uv_bau_init(void)
        int pnode;
        int nuvhubs;
        int cur_cpu;
+       int cpus;
        int vector;
-       unsigned long mmr;
+       cpumask_var_t *mask;
 
        if (!is_uv_system())
                return 0;
@@ -1660,24 +1807,25 @@ static int __init uv_bau_init(void)
        if (nobau)
                return 0;
 
-       for_each_possible_cpu(cur_cpu)
-               zalloc_cpumask_var_node(&per_cpu(uv_flush_tlb_mask, cur_cpu),
-                                      GFP_KERNEL, cpu_to_node(cur_cpu));
+       for_each_possible_cpu(cur_cpu) {
+               mask = &per_cpu(uv_flush_tlb_mask, cur_cpu);
+               zalloc_cpumask_var_node(mask, GFP_KERNEL, cpu_to_node(cur_cpu));
+       }
 
        uv_nshift = uv_hub_info->m_val;
        uv_mmask = (1UL << uv_hub_info->m_val) - 1;
        nuvhubs = uv_num_possible_blades();
        spin_lock_init(&disable_lock);
-       congested_cycles = microsec_2_cycles(congested_response_us);
+       congested_cycles = usec_2_cycles(congested_respns_us);
 
-       uv_partition_base_pnode = 0x7fffffff;
+       uv_base_pnode = 0x7fffffff;
        for (uvhub = 0; uvhub < nuvhubs; uvhub++) {
-               if (uv_blade_nr_possible_cpus(uvhub) &&
-                       (uv_blade_to_pnode(uvhub) < uv_partition_base_pnode))
-                       uv_partition_base_pnode = uv_blade_to_pnode(uvhub);
+               cpus = uv_blade_nr_possible_cpus(uvhub);
+               if (cpus && (uv_blade_to_pnode(uvhub) < uv_base_pnode))
+                       uv_base_pnode = uv_blade_to_pnode(uvhub);
        }
 
-       if (uv_init_per_cpu(nuvhubs, uv_partition_base_pnode)) {
+       if (init_per_cpu(nuvhubs, uv_base_pnode)) {
                nobau = 1;
                return 0;
        }
@@ -1685,21 +1833,21 @@ static int __init uv_bau_init(void)
        vector = UV_BAU_MESSAGE;
        for_each_possible_blade(uvhub)
                if (uv_blade_nr_possible_cpus(uvhub))
-                       uv_init_uvhub(uvhub, vector, uv_partition_base_pnode);
+                       init_uvhub(uvhub, vector, uv_base_pnode);
 
-       uv_enable_timeouts();
+       enable_timeouts();
        alloc_intr_gate(vector, uv_bau_message_intr1);
 
        for_each_possible_blade(uvhub) {
                if (uv_blade_nr_possible_cpus(uvhub)) {
+                       unsigned long val;
+                       unsigned long mmr;
                        pnode = uv_blade_to_pnode(uvhub);
                        /* INIT the bau */
-                       uv_write_global_mmr64(pnode,
-                                       UVH_LB_BAU_SB_ACTIVATION_CONTROL,
-                                       ((unsigned long)1 << 63));
+                       val = 1L << 63;
+                       write_gmmr_activation(pnode, val);
                        mmr = 1; /* should be 1 to broadcast to both sockets */
-                       uv_write_global_mmr64(pnode, UVH_BAU_DATA_BROADCAST,
-                                               mmr);
+                       write_mmr_data_broadcast(pnode, mmr);
                }
        }
 
index 0eb90184515fe132c42b3fb8459f55671c71bd8d..9f29a01ee1b3fec6e8d13dce479d352d8a2eae0c 100644 (file)
@@ -99,8 +99,12 @@ static void uv_rtc_send_IPI(int cpu)
 /* Check for an RTC interrupt pending */
 static int uv_intr_pending(int pnode)
 {
-       return uv_read_global_mmr64(pnode, UVH_EVENT_OCCURRED0) &
-               UVH_EVENT_OCCURRED0_RTC1_MASK;
+       if (is_uv1_hub())
+               return uv_read_global_mmr64(pnode, UVH_EVENT_OCCURRED0) &
+                       UV1H_EVENT_OCCURRED0_RTC1_MASK;
+       else
+               return uv_read_global_mmr64(pnode, UV2H_EVENT_OCCURRED2) &
+                       UV2H_EVENT_OCCURRED2_RTC_1_MASK;
 }
 
 /* Setup interrupt and return non-zero if early expiration occurred. */
@@ -114,8 +118,12 @@ static int uv_setup_intr(int cpu, u64 expires)
                UVH_RTC1_INT_CONFIG_M_MASK);
        uv_write_global_mmr64(pnode, UVH_INT_CMPB, -1L);
 
-       uv_write_global_mmr64(pnode, UVH_EVENT_OCCURRED0_ALIAS,
-               UVH_EVENT_OCCURRED0_RTC1_MASK);
+       if (is_uv1_hub())
+               uv_write_global_mmr64(pnode, UVH_EVENT_OCCURRED0_ALIAS,
+                               UV1H_EVENT_OCCURRED0_RTC1_MASK);
+       else
+               uv_write_global_mmr64(pnode, UV2H_EVENT_OCCURRED2_ALIAS,
+                               UV2H_EVENT_OCCURRED2_RTC_1_MASK);
 
        val = (X86_PLATFORM_IPI_VECTOR << UVH_RTC1_INT_CONFIG_VECTOR_SHFT) |
                ((u64)apicid << UVH_RTC1_INT_CONFIG_APIC_ID_SHFT);
index b6552b189bcdbb43b1f3627616f1f69d488f9efa..bef0bc9624006d1839dc3050ab8356d7852593f4 100644 (file)
@@ -11,7 +11,7 @@ vdso-install-$(VDSO32-y)      += $(vdso32-images)
 
 
 # files to link into the vdso
-vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o vvar.o
+vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o
 
 # files to link into kernel
 obj-$(VDSO64-y)                        += vma.o vdso.o
@@ -37,11 +37,24 @@ $(obj)/%.so: OBJCOPYFLAGS := -S
 $(obj)/%.so: $(obj)/%.so.dbg FORCE
        $(call if_changed,objcopy)
 
+#
+# Don't omit frame pointers for ease of userspace debugging, but do
+# optimize sibling calls.
+#
 CFL := $(PROFILING) -mcmodel=small -fPIC -O2 -fasynchronous-unwind-tables -m64 \
-       $(filter -g%,$(KBUILD_CFLAGS)) $(call cc-option, -fno-stack-protector)
+       $(filter -g%,$(KBUILD_CFLAGS)) $(call cc-option, -fno-stack-protector) \
+       -fno-omit-frame-pointer -foptimize-sibling-calls
 
 $(vobjs): KBUILD_CFLAGS += $(CFL)
 
+#
+# vDSO code runs in userspace and -pg doesn't help with profiling anyway.
+#
+CFLAGS_REMOVE_vdso-note.o = -pg
+CFLAGS_REMOVE_vclock_gettime.o = -pg
+CFLAGS_REMOVE_vgetcpu.o = -pg
+CFLAGS_REMOVE_vvar.o = -pg
+
 targets += vdso-syms.lds
 obj-$(VDSO64-y)                        += vdso-syms.lds
 
index ee55754cc3c5ff378b76f2065a610b72e757f088..a724905fdae7c296bb40492505225f5cf053f35a 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright 2006 Andi Kleen, SUSE Labs.
  * Subject to the GNU Public License, v.2
  *
- * Fast user context implementation of clock_gettime and gettimeofday.
+ * Fast user context implementation of clock_gettime, gettimeofday, and time.
  *
  * The code should have no internal unresolved relocations.
  * Check with readelf after changing.
@@ -22,9 +22,8 @@
 #include <asm/hpet.h>
 #include <asm/unistd.h>
 #include <asm/io.h>
-#include "vextern.h"
 
-#define gtod vdso_vsyscall_gtod_data
+#define gtod (&VVAR(vsyscall_gtod_data))
 
 notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
 {
@@ -56,22 +55,6 @@ notrace static noinline int do_realtime(struct timespec *ts)
        return 0;
 }
 
-/* Copy of the version in kernel/time.c which we cannot directly access */
-notrace static void
-vset_normalized_timespec(struct timespec *ts, long sec, long nsec)
-{
-       while (nsec >= NSEC_PER_SEC) {
-               nsec -= NSEC_PER_SEC;
-               ++sec;
-       }
-       while (nsec < 0) {
-               nsec += NSEC_PER_SEC;
-               --sec;
-       }
-       ts->tv_sec = sec;
-       ts->tv_nsec = nsec;
-}
-
 notrace static noinline int do_monotonic(struct timespec *ts)
 {
        unsigned long seq, ns, secs;
@@ -82,7 +65,17 @@ notrace static noinline int do_monotonic(struct timespec *ts)
                secs += gtod->wall_to_monotonic.tv_sec;
                ns += gtod->wall_to_monotonic.tv_nsec;
        } while (unlikely(read_seqretry(&gtod->lock, seq)));
-       vset_normalized_timespec(ts, secs, ns);
+
+       /* wall_time_nsec, vgetns(), and wall_to_monotonic.tv_nsec
+        * are all guaranteed to be nonnegative.
+        */
+       while (ns >= NSEC_PER_SEC) {
+               ns -= NSEC_PER_SEC;
+               ++secs;
+       }
+       ts->tv_sec = secs;
+       ts->tv_nsec = ns;
+
        return 0;
 }
 
@@ -107,7 +100,17 @@ notrace static noinline int do_monotonic_coarse(struct timespec *ts)
                secs += gtod->wall_to_monotonic.tv_sec;
                ns += gtod->wall_to_monotonic.tv_nsec;
        } while (unlikely(read_seqretry(&gtod->lock, seq)));
-       vset_normalized_timespec(ts, secs, ns);
+
+       /* wall_time_nsec and wall_to_monotonic.tv_nsec are
+        * guaranteed to be between 0 and NSEC_PER_SEC.
+        */
+       if (ns >= NSEC_PER_SEC) {
+               ns -= NSEC_PER_SEC;
+               ++secs;
+       }
+       ts->tv_sec = secs;
+       ts->tv_nsec = ns;
+
        return 0;
 }
 
@@ -157,3 +160,32 @@ notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
 }
 int gettimeofday(struct timeval *, struct timezone *)
        __attribute__((weak, alias("__vdso_gettimeofday")));
+
+/* This will break when the xtime seconds get inaccurate, but that is
+ * unlikely */
+
+static __always_inline long time_syscall(long *t)
+{
+       long secs;
+       asm volatile("syscall"
+                    : "=a" (secs)
+                    : "0" (__NR_time), "D" (t) : "cc", "r11", "cx", "memory");
+       return secs;
+}
+
+notrace time_t __vdso_time(time_t *t)
+{
+       time_t result;
+
+       if (unlikely(!VVAR(vsyscall_gtod_data).sysctl_enabled))
+               return time_syscall(t);
+
+       /* This is atomic on x86_64 so we don't need any locks. */
+       result = ACCESS_ONCE(VVAR(vsyscall_gtod_data).wall_time_sec);
+
+       if (t)
+               *t = result;
+       return result;
+}
+int time(time_t *t)
+       __attribute__((weak, alias("__vdso_time")));
index 4e5dd3b4de7f64428db97c5ef7ef9c29ceecfbf6..b96b2677cad82820207bb38a3e09bdd8c4a61eba 100644 (file)
@@ -23,15 +23,10 @@ VERSION {
                __vdso_gettimeofday;
                getcpu;
                __vdso_getcpu;
+               time;
+               __vdso_time;
        local: *;
        };
 }
 
 VDSO64_PRELINK = VDSO_PRELINK;
-
-/*
- * Define VDSO64_x for each VEXTERN(x), for use via VDSO64_SYMBOL.
- */
-#define VEXTERN(x)     VDSO64_ ## x = vdso_ ## x;
-#include "vextern.h"
-#undef VEXTERN
diff --git a/arch/x86/vdso/vextern.h b/arch/x86/vdso/vextern.h
deleted file mode 100644 (file)
index 1683ba2..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef VEXTERN
-#include <asm/vsyscall.h>
-#define VEXTERN(x) \
-       extern typeof(x) *vdso_ ## x __attribute__((visibility("hidden")));
-#endif
-
-#define VMAGIC 0xfeedbabeabcdefabUL
-
-/* Any kernel variables used in the vDSO must be exported in the main
-   kernel's vmlinux.lds.S/vsyscall.h/proper __section and
-   put into vextern.h and be referenced as a pointer with vdso prefix.
-   The main kernel later fills in the values.   */
-
-VEXTERN(jiffies)
-VEXTERN(vgetcpu_mode)
-VEXTERN(vsyscall_gtod_data)
index 9fbc6b20026b5ac4f23f9704e2cac9b1daaaf3a6..5463ad558573de5424d4d654e0cfdc20263930dd 100644 (file)
 #include <linux/time.h>
 #include <asm/vsyscall.h>
 #include <asm/vgtod.h>
-#include "vextern.h"
 
 notrace long
 __vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *unused)
 {
        unsigned int p;
 
-       if (*vdso_vgetcpu_mode == VGETCPU_RDTSCP) {
+       if (VVAR(vgetcpu_mode) == VGETCPU_RDTSCP) {
                /* Load per CPU data from RDTSCP */
                native_read_tscp(&p);
        } else {
index 4b5d26f108bbb21f9ff1ac494388b70fa610c247..7abd2be0f9b95ff847770472b3ee015e92c47197 100644 (file)
@@ -15,9 +15,6 @@
 #include <asm/proto.h>
 #include <asm/vdso.h>
 
-#include "vextern.h"           /* Just for VMAGIC.  */
-#undef VEXTERN
-
 unsigned int __read_mostly vdso_enabled = 1;
 
 extern char vdso_start[], vdso_end[];
@@ -26,20 +23,10 @@ extern unsigned short vdso_sync_cpuid;
 static struct page **vdso_pages;
 static unsigned vdso_size;
 
-static inline void *var_ref(void *p, char *name)
-{
-       if (*(void **)p != (void *)VMAGIC) {
-               printk("VDSO: variable %s broken\n", name);
-               vdso_enabled = 0;
-       }
-       return p;
-}
-
 static int __init init_vdso_vars(void)
 {
        int npages = (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE;
        int i;
-       char *vbase;
 
        vdso_size = npages << PAGE_SHIFT;
        vdso_pages = kmalloc(sizeof(struct page *) * npages, GFP_KERNEL);
@@ -54,20 +41,6 @@ static int __init init_vdso_vars(void)
                copy_page(page_address(p), vdso_start + i*PAGE_SIZE);
        }
 
-       vbase = vmap(vdso_pages, npages, 0, PAGE_KERNEL);
-       if (!vbase)
-               goto oom;
-
-       if (memcmp(vbase, "\177ELF", 4)) {
-               printk("VDSO: I'm broken; not ELF\n");
-               vdso_enabled = 0;
-       }
-
-#define VEXTERN(x) \
-       *(typeof(__ ## x) **) var_ref(VDSO64_SYMBOL(vbase, x), #x) = &__ ## x;
-#include "vextern.h"
-#undef VEXTERN
-       vunmap(vbase);
        return 0;
 
  oom:
diff --git a/arch/x86/vdso/vvar.c b/arch/x86/vdso/vvar.c
deleted file mode 100644 (file)
index 1b7e703..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* Define pointer to external vDSO variables.
-   These are part of the vDSO. The kernel fills in the real addresses
-   at boot time. This is done because when the vdso is linked the
-   kernel isn't yet and we don't know the final addresses. */
-#include <linux/kernel.h>
-#include <linux/time.h>
-#include <asm/vsyscall.h>
-#include <asm/timex.h>
-#include <asm/vgtod.h>
-
-#define VEXTERN(x) typeof (__ ## x) *const vdso_ ## x = (void *)VMAGIC;
-#include "vextern.h"
index dd7b88f2ec7a6f30bf4ec628fc7f59112cf4d65e..5525163a03985a517e7a043c3daa92fe04d4bb6e 100644 (file)
@@ -1033,6 +1033,13 @@ static void xen_machine_halt(void)
        xen_reboot(SHUTDOWN_poweroff);
 }
 
+static void xen_machine_power_off(void)
+{
+       if (pm_power_off)
+               pm_power_off();
+       xen_reboot(SHUTDOWN_poweroff);
+}
+
 static void xen_crash_shutdown(struct pt_regs *regs)
 {
        xen_reboot(SHUTDOWN_crash);
@@ -1058,7 +1065,7 @@ int xen_panic_handler_init(void)
 static const struct machine_ops xen_machine_ops __initconst = {
        .restart = xen_restart,
        .halt = xen_machine_halt,
-       .power_off = xen_machine_halt,
+       .power_off = xen_machine_power_off,
        .shutdown = xen_machine_halt,
        .crash_shutdown = xen_crash_shutdown,
        .emergency_restart = xen_emergency_restart,
index 02d7524603710bf1afed949598645f6ebab2413b..673e968df3cfd6c67a1b8a9dc3885fcaad15249f 100644 (file)
@@ -59,6 +59,7 @@
 #include <asm/page.h>
 #include <asm/init.h>
 #include <asm/pat.h>
+#include <asm/smp.h>
 
 #include <asm/xen/hypercall.h>
 #include <asm/xen/hypervisor.h>
 #include "mmu.h"
 #include "debugfs.h"
 
-#define MMU_UPDATE_HISTO       30
-
 /*
  * Protects atomic reservation decrease/increase against concurrent increases.
  * Also protects non-atomic updates of current_pages and balloon lists.
  */
 DEFINE_SPINLOCK(xen_reservation_lock);
 
-#ifdef CONFIG_XEN_DEBUG_FS
-
-static struct {
-       u32 pgd_update;
-       u32 pgd_update_pinned;
-       u32 pgd_update_batched;
-
-       u32 pud_update;
-       u32 pud_update_pinned;
-       u32 pud_update_batched;
-
-       u32 pmd_update;
-       u32 pmd_update_pinned;
-       u32 pmd_update_batched;
-
-       u32 pte_update;
-       u32 pte_update_pinned;
-       u32 pte_update_batched;
-
-       u32 mmu_update;
-       u32 mmu_update_extended;
-       u32 mmu_update_histo[MMU_UPDATE_HISTO];
-
-       u32 prot_commit;
-       u32 prot_commit_batched;
-
-       u32 set_pte_at;
-       u32 set_pte_at_batched;
-       u32 set_pte_at_pinned;
-       u32 set_pte_at_current;
-       u32 set_pte_at_kernel;
-} mmu_stats;
-
-static u8 zero_stats;
-
-static inline void check_zero(void)
-{
-       if (unlikely(zero_stats)) {
-               memset(&mmu_stats, 0, sizeof(mmu_stats));
-               zero_stats = 0;
-       }
-}
-
-#define ADD_STATS(elem, val)                   \
-       do { check_zero(); mmu_stats.elem += (val); } while(0)
-
-#else  /* !CONFIG_XEN_DEBUG_FS */
-
-#define ADD_STATS(elem, val)   do { (void)(val); } while(0)
-
-#endif /* CONFIG_XEN_DEBUG_FS */
-
-
 /*
  * Identity map, in addition to plain kernel map.  This needs to be
  * large enough to allocate page table pages to allocate the rest.
@@ -243,11 +189,6 @@ static bool xen_page_pinned(void *ptr)
        return PagePinned(page);
 }
 
-static bool xen_iomap_pte(pte_t pte)
-{
-       return pte_flags(pte) & _PAGE_IOMAP;
-}
-
 void xen_set_domain_pte(pte_t *ptep, pte_t pteval, unsigned domid)
 {
        struct multicall_space mcs;
@@ -257,7 +198,7 @@ void xen_set_domain_pte(pte_t *ptep, pte_t pteval, unsigned domid)
        u = mcs.args;
 
        /* ptep might be kmapped when using 32-bit HIGHPTE */
-       u->ptr = arbitrary_virt_to_machine(ptep).maddr;
+       u->ptr = virt_to_machine(ptep).maddr;
        u->val = pte_val_ma(pteval);
 
        MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, domid);
@@ -266,11 +207,6 @@ void xen_set_domain_pte(pte_t *ptep, pte_t pteval, unsigned domid)
 }
 EXPORT_SYMBOL_GPL(xen_set_domain_pte);
 
-static void xen_set_iomap_pte(pte_t *ptep, pte_t pteval)
-{
-       xen_set_domain_pte(ptep, pteval, DOMID_IO);
-}
-
 static void xen_extend_mmu_update(const struct mmu_update *update)
 {
        struct multicall_space mcs;
@@ -279,27 +215,17 @@ static void xen_extend_mmu_update(const struct mmu_update *update)
        mcs = xen_mc_extend_args(__HYPERVISOR_mmu_update, sizeof(*u));
 
        if (mcs.mc != NULL) {
-               ADD_STATS(mmu_update_extended, 1);
-               ADD_STATS(mmu_update_histo[mcs.mc->args[1]], -1);
-
                mcs.mc->args[1]++;
-
-               if (mcs.mc->args[1] < MMU_UPDATE_HISTO)
-                       ADD_STATS(mmu_update_histo[mcs.mc->args[1]], 1);
-               else
-                       ADD_STATS(mmu_update_histo[0], 1);
        } else {
-               ADD_STATS(mmu_update, 1);
                mcs = __xen_mc_entry(sizeof(*u));
                MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, DOMID_SELF);
-               ADD_STATS(mmu_update_histo[1], 1);
        }
 
        u = mcs.args;
        *u = *update;
 }
 
-void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
+static void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
 {
        struct mmu_update u;
 
@@ -312,17 +238,13 @@ void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
        u.val = pmd_val_ma(val);
        xen_extend_mmu_update(&u);
 
-       ADD_STATS(pmd_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
-
        xen_mc_issue(PARAVIRT_LAZY_MMU);
 
        preempt_enable();
 }
 
-void xen_set_pmd(pmd_t *ptr, pmd_t val)
+static void xen_set_pmd(pmd_t *ptr, pmd_t val)
 {
-       ADD_STATS(pmd_update, 1);
-
        /* If page is not pinned, we can just update the entry
           directly */
        if (!xen_page_pinned(ptr)) {
@@ -330,8 +252,6 @@ void xen_set_pmd(pmd_t *ptr, pmd_t val)
                return;
        }
 
-       ADD_STATS(pmd_update_pinned, 1);
-
        xen_set_pmd_hyper(ptr, val);
 }
 
@@ -344,35 +264,34 @@ void set_pte_mfn(unsigned long vaddr, unsigned long mfn, pgprot_t flags)
        set_pte_vaddr(vaddr, mfn_pte(mfn, flags));
 }
 
-void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
-                   pte_t *ptep, pte_t pteval)
+static bool xen_batched_set_pte(pte_t *ptep, pte_t pteval)
 {
-       if (xen_iomap_pte(pteval)) {
-               xen_set_iomap_pte(ptep, pteval);
-               goto out;
-       }
+       struct mmu_update u;
 
-       ADD_STATS(set_pte_at, 1);
-//     ADD_STATS(set_pte_at_pinned, xen_page_pinned(ptep));
-       ADD_STATS(set_pte_at_current, mm == current->mm);
-       ADD_STATS(set_pte_at_kernel, mm == &init_mm);
+       if (paravirt_get_lazy_mode() != PARAVIRT_LAZY_MMU)
+               return false;
 
-       if (mm == current->mm || mm == &init_mm) {
-               if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
-                       struct multicall_space mcs;
-                       mcs = xen_mc_entry(0);
+       xen_mc_batch();
 
-                       MULTI_update_va_mapping(mcs.mc, addr, pteval, 0);
-                       ADD_STATS(set_pte_at_batched, 1);
-                       xen_mc_issue(PARAVIRT_LAZY_MMU);
-                       goto out;
-               } else
-                       if (HYPERVISOR_update_va_mapping(addr, pteval, 0) == 0)
-                               goto out;
-       }
-       xen_set_pte(ptep, pteval);
+       u.ptr = virt_to_machine(ptep).maddr | MMU_NORMAL_PT_UPDATE;
+       u.val = pte_val_ma(pteval);
+       xen_extend_mmu_update(&u);
+
+       xen_mc_issue(PARAVIRT_LAZY_MMU);
+
+       return true;
+}
 
-out:   return;
+static void xen_set_pte(pte_t *ptep, pte_t pteval)
+{
+       if (!xen_batched_set_pte(ptep, pteval))
+               native_set_pte(ptep, pteval);
+}
+
+static void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
+                   pte_t *ptep, pte_t pteval)
+{
+       xen_set_pte(ptep, pteval);
 }
 
 pte_t xen_ptep_modify_prot_start(struct mm_struct *mm,
@@ -389,13 +308,10 @@ void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
 
        xen_mc_batch();
 
-       u.ptr = arbitrary_virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD;
+       u.ptr = virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD;
        u.val = pte_val_ma(pte);
        xen_extend_mmu_update(&u);
 
-       ADD_STATS(prot_commit, 1);
-       ADD_STATS(prot_commit_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
-
        xen_mc_issue(PARAVIRT_LAZY_MMU);
 }
 
@@ -463,7 +379,7 @@ static pteval_t iomap_pte(pteval_t val)
        return val;
 }
 
-pteval_t xen_pte_val(pte_t pte)
+static pteval_t xen_pte_val(pte_t pte)
 {
        pteval_t pteval = pte.pte;
 
@@ -480,7 +396,7 @@ pteval_t xen_pte_val(pte_t pte)
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_pte_val);
 
-pgdval_t xen_pgd_val(pgd_t pgd)
+static pgdval_t xen_pgd_val(pgd_t pgd)
 {
        return pte_mfn_to_pfn(pgd.pgd);
 }
@@ -511,7 +427,7 @@ void xen_set_pat(u64 pat)
        WARN_ON(pat != 0x0007010600070106ull);
 }
 
-pte_t xen_make_pte(pteval_t pte)
+static pte_t xen_make_pte(pteval_t pte)
 {
        phys_addr_t addr = (pte & PTE_PFN_MASK);
 
@@ -581,20 +497,20 @@ pte_t xen_make_pte_debug(pteval_t pte)
 PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte_debug);
 #endif
 
-pgd_t xen_make_pgd(pgdval_t pgd)
+static pgd_t xen_make_pgd(pgdval_t pgd)
 {
        pgd = pte_pfn_to_mfn(pgd);
        return native_make_pgd(pgd);
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_make_pgd);
 
-pmdval_t xen_pmd_val(pmd_t pmd)
+static pmdval_t xen_pmd_val(pmd_t pmd)
 {
        return pte_mfn_to_pfn(pmd.pmd);
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_pmd_val);
 
-void xen_set_pud_hyper(pud_t *ptr, pud_t val)
+static void xen_set_pud_hyper(pud_t *ptr, pud_t val)
 {
        struct mmu_update u;
 
@@ -607,17 +523,13 @@ void xen_set_pud_hyper(pud_t *ptr, pud_t val)
        u.val = pud_val_ma(val);
        xen_extend_mmu_update(&u);
 
-       ADD_STATS(pud_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
-
        xen_mc_issue(PARAVIRT_LAZY_MMU);
 
        preempt_enable();
 }
 
-void xen_set_pud(pud_t *ptr, pud_t val)
+static void xen_set_pud(pud_t *ptr, pud_t val)
 {
-       ADD_STATS(pud_update, 1);
-
        /* If page is not pinned, we can just update the entry
           directly */
        if (!xen_page_pinned(ptr)) {
@@ -625,56 +537,28 @@ void xen_set_pud(pud_t *ptr, pud_t val)
                return;
        }
 
-       ADD_STATS(pud_update_pinned, 1);
-
        xen_set_pud_hyper(ptr, val);
 }
 
-void xen_set_pte(pte_t *ptep, pte_t pte)
-{
-       if (xen_iomap_pte(pte)) {
-               xen_set_iomap_pte(ptep, pte);
-               return;
-       }
-
-       ADD_STATS(pte_update, 1);
-//     ADD_STATS(pte_update_pinned, xen_page_pinned(ptep));
-       ADD_STATS(pte_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
-
 #ifdef CONFIG_X86_PAE
-       ptep->pte_high = pte.pte_high;
-       smp_wmb();
-       ptep->pte_low = pte.pte_low;
-#else
-       *ptep = pte;
-#endif
-}
-
-#ifdef CONFIG_X86_PAE
-void xen_set_pte_atomic(pte_t *ptep, pte_t pte)
+static void xen_set_pte_atomic(pte_t *ptep, pte_t pte)
 {
-       if (xen_iomap_pte(pte)) {
-               xen_set_iomap_pte(ptep, pte);
-               return;
-       }
-
        set_64bit((u64 *)ptep, native_pte_val(pte));
 }
 
-void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+static void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
-       ptep->pte_low = 0;
-       smp_wmb();              /* make sure low gets written first */
-       ptep->pte_high = 0;
+       if (!xen_batched_set_pte(ptep, native_make_pte(0)))
+               native_pte_clear(mm, addr, ptep);
 }
 
-void xen_pmd_clear(pmd_t *pmdp)
+static void xen_pmd_clear(pmd_t *pmdp)
 {
        set_pmd(pmdp, __pmd(0));
 }
 #endif /* CONFIG_X86_PAE */
 
-pmd_t xen_make_pmd(pmdval_t pmd)
+static pmd_t xen_make_pmd(pmdval_t pmd)
 {
        pmd = pte_pfn_to_mfn(pmd);
        return native_make_pmd(pmd);
@@ -682,13 +566,13 @@ pmd_t xen_make_pmd(pmdval_t pmd)
 PV_CALLEE_SAVE_REGS_THUNK(xen_make_pmd);
 
 #if PAGETABLE_LEVELS == 4
-pudval_t xen_pud_val(pud_t pud)
+static pudval_t xen_pud_val(pud_t pud)
 {
        return pte_mfn_to_pfn(pud.pud);
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_pud_val);
 
-pud_t xen_make_pud(pudval_t pud)
+static pud_t xen_make_pud(pudval_t pud)
 {
        pud = pte_pfn_to_mfn(pud);
 
@@ -696,7 +580,7 @@ pud_t xen_make_pud(pudval_t pud)
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_make_pud);
 
-pgd_t *xen_get_user_pgd(pgd_t *pgd)
+static pgd_t *xen_get_user_pgd(pgd_t *pgd)
 {
        pgd_t *pgd_page = (pgd_t *)(((unsigned long)pgd) & PAGE_MASK);
        unsigned offset = pgd - pgd_page;
@@ -728,7 +612,7 @@ static void __xen_set_pgd_hyper(pgd_t *ptr, pgd_t val)
  *  2. It is always pinned
  *  3. It has no user pagetable attached to it
  */
-void __init xen_set_pgd_hyper(pgd_t *ptr, pgd_t val)
+static void __init xen_set_pgd_hyper(pgd_t *ptr, pgd_t val)
 {
        preempt_disable();
 
@@ -741,12 +625,10 @@ void __init xen_set_pgd_hyper(pgd_t *ptr, pgd_t val)
        preempt_enable();
 }
 
-void xen_set_pgd(pgd_t *ptr, pgd_t val)
+static void xen_set_pgd(pgd_t *ptr, pgd_t val)
 {
        pgd_t *user_ptr = xen_get_user_pgd(ptr);
 
-       ADD_STATS(pgd_update, 1);
-
        /* If page is not pinned, we can just update the entry
           directly */
        if (!xen_page_pinned(ptr)) {
@@ -758,9 +640,6 @@ void xen_set_pgd(pgd_t *ptr, pgd_t val)
                return;
        }
 
-       ADD_STATS(pgd_update_pinned, 1);
-       ADD_STATS(pgd_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
-
        /* If it's pinned, then we can at least batch the kernel and
           user updates together. */
        xen_mc_batch();
@@ -1162,14 +1041,14 @@ void xen_mm_unpin_all(void)
        spin_unlock(&pgd_lock);
 }
 
-void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
+static void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
 {
        spin_lock(&next->page_table_lock);
        xen_pgd_pin(next);
        spin_unlock(&next->page_table_lock);
 }
 
-void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
+static void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
 {
        spin_lock(&mm->page_table_lock);
        xen_pgd_pin(mm);
@@ -1256,7 +1135,7 @@ static void xen_drop_mm_ref(struct mm_struct *mm)
  * pagetable because of lazy tlb flushing.  This means we need need to
  * switch all CPUs off this pagetable before we can unpin it.
  */
-void xen_exit_mmap(struct mm_struct *mm)
+static void xen_exit_mmap(struct mm_struct *mm)
 {
        get_cpu();              /* make sure we don't move around */
        xen_drop_mm_ref(mm);
@@ -1353,7 +1232,7 @@ static void xen_flush_tlb_others(const struct cpumask *cpus,
 {
        struct {
                struct mmuext_op op;
-               DECLARE_BITMAP(mask, NR_CPUS);
+               DECLARE_BITMAP(mask, num_processors);
        } *args;
        struct multicall_space mcs;
 
@@ -1721,6 +1600,11 @@ static void __init xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
                for (pteidx = 0; pteidx < PTRS_PER_PTE; pteidx++, pfn++) {
                        pte_t pte;
 
+#ifdef CONFIG_X86_32
+                       if (pfn > max_pfn_mapped)
+                               max_pfn_mapped = pfn;
+#endif
+
                        if (!pte_none(pte_page[pteidx]))
                                continue;
 
@@ -1888,7 +1772,9 @@ pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd,
        initial_kernel_pmd =
                extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE);
 
-       max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->mfn_list));
+       max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->pt_base) +
+                                 xen_start_info->nr_pt_frames * PAGE_SIZE +
+                                 512*1024);
 
        kernel_pmd = m2v(pgd[KERNEL_PGD_BOUNDARY].pgd);
        memcpy(initial_kernel_pmd, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD);
@@ -2371,7 +2257,7 @@ static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token,
        struct remap_data *rmd = data;
        pte_t pte = pte_mkspecial(pfn_pte(rmd->mfn++, rmd->prot));
 
-       rmd->mmu_update->ptr = arbitrary_virt_to_machine(ptep).maddr;
+       rmd->mmu_update->ptr = virt_to_machine(ptep).maddr;
        rmd->mmu_update->val = pte_val_ma(pte);
        rmd->mmu_update++;
 
@@ -2425,7 +2311,6 @@ out:
 EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range);
 
 #ifdef CONFIG_XEN_DEBUG_FS
-
 static int p2m_dump_open(struct inode *inode, struct file *filp)
 {
        return single_open(filp, p2m_dump_show, NULL);
@@ -2437,65 +2322,4 @@ static const struct file_operations p2m_dump_fops = {
        .llseek         = seq_lseek,
        .release        = single_release,
 };
-
-static struct dentry *d_mmu_debug;
-
-static int __init xen_mmu_debugfs(void)
-{
-       struct dentry *d_xen = xen_init_debugfs();
-
-       if (d_xen == NULL)
-               return -ENOMEM;
-
-       d_mmu_debug = debugfs_create_dir("mmu", d_xen);
-
-       debugfs_create_u8("zero_stats", 0644, d_mmu_debug, &zero_stats);
-
-       debugfs_create_u32("pgd_update", 0444, d_mmu_debug, &mmu_stats.pgd_update);
-       debugfs_create_u32("pgd_update_pinned", 0444, d_mmu_debug,
-                          &mmu_stats.pgd_update_pinned);
-       debugfs_create_u32("pgd_update_batched", 0444, d_mmu_debug,
-                          &mmu_stats.pgd_update_pinned);
-
-       debugfs_create_u32("pud_update", 0444, d_mmu_debug, &mmu_stats.pud_update);
-       debugfs_create_u32("pud_update_pinned", 0444, d_mmu_debug,
-                          &mmu_stats.pud_update_pinned);
-       debugfs_create_u32("pud_update_batched", 0444, d_mmu_debug,
-                          &mmu_stats.pud_update_pinned);
-
-       debugfs_create_u32("pmd_update", 0444, d_mmu_debug, &mmu_stats.pmd_update);
-       debugfs_create_u32("pmd_update_pinned", 0444, d_mmu_debug,
-                          &mmu_stats.pmd_update_pinned);
-       debugfs_create_u32("pmd_update_batched", 0444, d_mmu_debug,
-                          &mmu_stats.pmd_update_pinned);
-
-       debugfs_create_u32("pte_update", 0444, d_mmu_debug, &mmu_stats.pte_update);
-//     debugfs_create_u32("pte_update_pinned", 0444, d_mmu_debug,
-//                        &mmu_stats.pte_update_pinned);
-       debugfs_create_u32("pte_update_batched", 0444, d_mmu_debug,
-                          &mmu_stats.pte_update_pinned);
-
-       debugfs_create_u32("mmu_update", 0444, d_mmu_debug, &mmu_stats.mmu_update);
-       debugfs_create_u32("mmu_update_extended", 0444, d_mmu_debug,
-                          &mmu_stats.mmu_update_extended);
-       xen_debugfs_create_u32_array("mmu_update_histo", 0444, d_mmu_debug,
-                                    mmu_stats.mmu_update_histo, 20);
-
-       debugfs_create_u32("set_pte_at", 0444, d_mmu_debug, &mmu_stats.set_pte_at);
-       debugfs_create_u32("set_pte_at_batched", 0444, d_mmu_debug,
-                          &mmu_stats.set_pte_at_batched);
-       debugfs_create_u32("set_pte_at_current", 0444, d_mmu_debug,
-                          &mmu_stats.set_pte_at_current);
-       debugfs_create_u32("set_pte_at_kernel", 0444, d_mmu_debug,
-                          &mmu_stats.set_pte_at_kernel);
-
-       debugfs_create_u32("prot_commit", 0444, d_mmu_debug, &mmu_stats.prot_commit);
-       debugfs_create_u32("prot_commit_batched", 0444, d_mmu_debug,
-                          &mmu_stats.prot_commit_batched);
-
-       debugfs_create_file("p2m", 0600, d_mmu_debug, NULL, &p2m_dump_fops);
-       return 0;
-}
-fs_initcall(xen_mmu_debugfs);
-
-#endif /* CONFIG_XEN_DEBUG_FS */
+#endif /* CONFIG_XEN_DEBUG_FS */
index 537bb9aab777ab00b446d1cec9daded81a3ed71f..73809bb951b40a7b8baf73773260276ed575c623 100644 (file)
@@ -15,43 +15,6 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
 
 void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
 
-
-void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next);
-void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm);
-void xen_exit_mmap(struct mm_struct *mm);
-
-pteval_t xen_pte_val(pte_t);
-pmdval_t xen_pmd_val(pmd_t);
-pgdval_t xen_pgd_val(pgd_t);
-
-pte_t xen_make_pte(pteval_t);
-pmd_t xen_make_pmd(pmdval_t);
-pgd_t xen_make_pgd(pgdval_t);
-
-void xen_set_pte(pte_t *ptep, pte_t pteval);
-void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
-                   pte_t *ptep, pte_t pteval);
-
-#ifdef CONFIG_X86_PAE
-void xen_set_pte_atomic(pte_t *ptep, pte_t pte);
-void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
-void xen_pmd_clear(pmd_t *pmdp);
-#endif /* CONFIG_X86_PAE */
-
-void xen_set_pmd(pmd_t *pmdp, pmd_t pmdval);
-void xen_set_pud(pud_t *ptr, pud_t val);
-void xen_set_pmd_hyper(pmd_t *pmdp, pmd_t pmdval);
-void xen_set_pud_hyper(pud_t *ptr, pud_t val);
-
-#if PAGETABLE_LEVELS == 4
-pudval_t xen_pud_val(pud_t pud);
-pud_t xen_make_pud(pudval_t pudval);
-void xen_set_pgd(pgd_t *pgdp, pgd_t pgd);
-void xen_set_pgd_hyper(pgd_t *pgdp, pgd_t pgd);
-#endif
-
-pgd_t *xen_get_user_pgd(pgd_t *pgd);
-
 pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
 void  xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
                                  pte_t *ptep, pte_t pte);
index 8bff7e7c290b7d30ef805061115690e7267dc4a9..1b2b73ff0a6e52176ba4a08d324ade8785382bd4 100644 (file)
@@ -189,10 +189,10 @@ struct multicall_space __xen_mc_entry(size_t args)
        unsigned argidx = roundup(b->argidx, sizeof(u64));
 
        BUG_ON(preemptible());
-       BUG_ON(b->argidx > MC_ARGS);
+       BUG_ON(b->argidx >= MC_ARGS);
 
        if (b->mcidx == MC_BATCH ||
-           (argidx + args) > MC_ARGS) {
+           (argidx + args) >= MC_ARGS) {
                mc_stats_flush(b->mcidx == MC_BATCH ? FL_SLOTS : FL_ARGS);
                xen_mc_flush();
                argidx = roundup(b->argidx, sizeof(u64));
@@ -206,7 +206,7 @@ struct multicall_space __xen_mc_entry(size_t args)
        ret.args = &b->args[argidx];
        b->argidx = argidx + args;
 
-       BUG_ON(b->argidx > MC_ARGS);
+       BUG_ON(b->argidx >= MC_ARGS);
        return ret;
 }
 
@@ -216,7 +216,7 @@ struct multicall_space xen_mc_extend_args(unsigned long op, size_t size)
        struct multicall_space ret = { NULL, NULL };
 
        BUG_ON(preemptible());
-       BUG_ON(b->argidx > MC_ARGS);
+       BUG_ON(b->argidx >= MC_ARGS);
 
        if (b->mcidx == 0)
                return ret;
@@ -224,14 +224,14 @@ struct multicall_space xen_mc_extend_args(unsigned long op, size_t size)
        if (b->entries[b->mcidx - 1].op != op)
                return ret;
 
-       if ((b->argidx + size) > MC_ARGS)
+       if ((b->argidx + size) >= MC_ARGS)
                return ret;
 
        ret.mc = &b->entries[b->mcidx - 1];
        ret.args = &b->args[b->argidx];
        b->argidx += size;
 
-       BUG_ON(b->argidx > MC_ARGS);
+       BUG_ON(b->argidx >= MC_ARGS);
        return ret;
 }
 
index be1a464f6d66eac7f6d24ae74894b321dc1cd4b5..60aeeb56948f753f87559f3e4ff8c1f8704d21a4 100644 (file)
@@ -227,11 +227,7 @@ char * __init xen_memory_setup(void)
 
        memcpy(map_raw, map, sizeof(map));
        e820.nr_map = 0;
-#ifdef CONFIG_X86_32
        xen_extra_mem_start = mem_end;
-#else
-       xen_extra_mem_start = max((1ULL << 32), mem_end);
-#endif
        for (i = 0; i < memmap.nr_entries; i++) {
                unsigned long long end;
 
@@ -266,6 +262,12 @@ char * __init xen_memory_setup(void)
                if (map[i].size > 0)
                        e820_add_region(map[i].addr, map[i].size, map[i].type);
        }
+       /* Align the balloon area so that max_low_pfn does not get set
+        * to be at the _end_ of the PCI gap at the far end (fee01000).
+        * Note that xen_extra_mem_start gets set in the loop above to be
+        * past the last E820 region. */
+       if (xen_initial_domain() && (xen_extra_mem_start < (1ULL<<32)))
+               xen_extra_mem_start = (1ULL<<32);
 
        /*
         * In domU, the ISA region is normal, usable memory, but we
index 41038c01de403e48c71052ab615dcf7f647f2653..b4533a86d7e410668e24033cae32d8382bf4111d 100644 (file)
@@ -205,11 +205,18 @@ static void __init xen_smp_prepare_boot_cpu(void)
 static void __init xen_smp_prepare_cpus(unsigned int max_cpus)
 {
        unsigned cpu;
+       unsigned int i;
 
        xen_init_lock_cpu(0);
 
        smp_store_cpu_info(0);
        cpu_data(0).x86_max_cores = 1;
+
+       for_each_possible_cpu(i) {
+               zalloc_cpumask_var(&per_cpu(cpu_sibling_map, i), GFP_KERNEL);
+               zalloc_cpumask_var(&per_cpu(cpu_core_map, i), GFP_KERNEL);
+               zalloc_cpumask_var(&per_cpu(cpu_llc_shared_map, i), GFP_KERNEL);
+       }
        set_cpu_sibling_map(0);
 
        if (xen_smp_intr_init(0))
index 7c275f5d0df00603cdc4c468bb89a8470f850515..5d43c1f8ada8b1406e5b7784c063c157274f1155 100644 (file)
@@ -20,12 +20,6 @@ config XTENSA
 config RWSEM_XCHGADD_ALGORITHM
        def_bool y
 
-config GENERIC_FIND_NEXT_BIT
-       def_bool y
-
-config GENERIC_FIND_BIT_LE
-       def_bool y
-
 config GENERIC_HWEIGHT
        def_bool y
 
index 161bb89e98c8b20f8b76f9c194bffa2727fa6cf2..7a5591a71f85093a8f58effc5a195f4f9b48c147 100644 (file)
@@ -171,10 +171,6 @@ extern void copy_user_page(void*, void*, unsigned long, struct page*);
 #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 #define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
 
-#ifdef CONFIG_MMU
-#define WANT_PAGE_VIRTUAL
-#endif
-
 #endif /* __ASSEMBLY__ */
 
 #define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
index 528042c2951ea5949bcf6c27875e7977dd2a90db..a6f934f37f1abe463432eb43644dbce871280690 100644 (file)
@@ -683,8 +683,10 @@ __SYSCALL(305, sys_ni_syscall, 0)
 __SYSCALL(306, sys_eventfd, 1)
 #define __NR_recvmmsg                          307
 __SYSCALL(307, sys_recvmmsg, 5)
+#define __NR_setns                             308
+__SYSCALL(308, sys_setns, 2)
 
-#define __NR_syscall_count                     308
+#define __NR_syscall_count                     309
 
 /*
  * sysxtensa syscall handler
index a2820065927eaa642224af0d748491506fdd473d..88ecea3facb4e8c81f507a667ed55feda6cfcb1a 100644 (file)
@@ -155,7 +155,7 @@ SECTIONS
     INIT_RAM_FS
   }
 
-  PERCPU(XCHAL_ICACHE_LINESIZE, PAGE_SIZE)
+  PERCPU_SECTION(XCHAL_ICACHE_LINESIZE)
 
   /* We need this dummy segment here */
 
index 4bb91a970f1f48eee6919e5104c8075f0481f71e..ca81654f3ec2c34e95f9ec8585c050ad1324f161 100644 (file)
@@ -14,8 +14,6 @@
 #include <asm/mmu_context.h>
 #include <asm/page.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 void __init paging_init(void)
 {
        memset(swapper_pg_dir, 0, PAGE_SIZE);
diff --git a/arch/xtensa/mm/pgtable.c b/arch/xtensa/mm/pgtable.c
deleted file mode 100644 (file)
index 6979927..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * arch/xtensa/mm/pgtable.c
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- *
- * Chris Zankel <chris@zankel.net>
- */
-
-#if (DCACHE_SIZE > PAGE_SIZE)
-
-pte_t* pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
-{
-       pte_t *pte = NULL, *p;
-       int color = ADDR_COLOR(address);
-       int i;
-
-       p = (pte_t*) __get_free_pages(GFP_KERNEL|__GFP_REPEAT, COLOR_ORDER);
-
-       if (likely(p)) {
-               split_page(virt_to_page(p), COLOR_ORDER);
-
-               for (i = 0; i < COLOR_SIZE; i++) {
-                       if (ADDR_COLOR(p) == color)
-                               pte = p;
-                       else
-                               free_page(p);
-                       p += PTRS_PER_PTE;
-               }
-               clear_page(pte);
-       }
-       return pte;
-}
-
-#ifdef PROFILING
-
-int mask;
-int hit;
-int flush;
-
-#endif
-
-struct page* pte_alloc_one(struct mm_struct *mm, unsigned long address)
-{
-       struct page *page = NULL, *p;
-       int color = ADDR_COLOR(address);
-
-       p = alloc_pages(GFP_KERNEL | __GFP_REPEAT, PTE_ORDER);
-
-       if (likely(p)) {
-               split_page(p, COLOR_ORDER);
-
-               for (i = 0; i < PAGE_ORDER; i++) {
-                       if (PADDR_COLOR(page_address(p)) == color)
-                               page = p;
-                       else
-                               __free_page(p);
-                       p++;
-               }
-               clear_highpage(page);
-       }
-
-       return page;
-}
-
-#endif
-
-
-
index 471fdcc5df85e3135dfefac29aa81a889d0ed567..bcaf16ee6ad1ba321836413ee8841ab0bbde8f5e 100644 (file)
@@ -30,10 +30,8 @@ EXPORT_SYMBOL_GPL(blkio_root_cgroup);
 
 static struct cgroup_subsys_state *blkiocg_create(struct cgroup_subsys *,
                                                  struct cgroup *);
-static int blkiocg_can_attach(struct cgroup_subsys *, struct cgroup *,
-                             struct task_struct *, bool);
-static void blkiocg_attach(struct cgroup_subsys *, struct cgroup *,
-                          struct cgroup *, struct task_struct *, bool);
+static int blkiocg_can_attach_task(struct cgroup *, struct task_struct *);
+static void blkiocg_attach_task(struct cgroup *, struct task_struct *);
 static void blkiocg_destroy(struct cgroup_subsys *, struct cgroup *);
 static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *);
 
@@ -46,8 +44,8 @@ static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *);
 struct cgroup_subsys blkio_subsys = {
        .name = "blkio",
        .create = blkiocg_create,
-       .can_attach = blkiocg_can_attach,
-       .attach = blkiocg_attach,
+       .can_attach_task = blkiocg_can_attach_task,
+       .attach_task = blkiocg_attach_task,
        .destroy = blkiocg_destroy,
        .populate = blkiocg_populate,
 #ifdef CONFIG_BLK_CGROUP
@@ -385,25 +383,40 @@ void blkiocg_update_timeslice_used(struct blkio_group *blkg, unsigned long time,
 
        spin_lock_irqsave(&blkg->stats_lock, flags);
        blkg->stats.time += time;
+#ifdef CONFIG_DEBUG_BLK_CGROUP
        blkg->stats.unaccounted_time += unaccounted_time;
+#endif
        spin_unlock_irqrestore(&blkg->stats_lock, flags);
 }
 EXPORT_SYMBOL_GPL(blkiocg_update_timeslice_used);
 
+/*
+ * should be called under rcu read lock or queue lock to make sure blkg pointer
+ * is valid.
+ */
 void blkiocg_update_dispatch_stats(struct blkio_group *blkg,
                                uint64_t bytes, bool direction, bool sync)
 {
-       struct blkio_group_stats *stats;
+       struct blkio_group_stats_cpu *stats_cpu;
        unsigned long flags;
 
-       spin_lock_irqsave(&blkg->stats_lock, flags);
-       stats = &blkg->stats;
-       stats->sectors += bytes >> 9;
-       blkio_add_stat(stats->stat_arr[BLKIO_STAT_SERVICED], 1, direction,
-                       sync);
-       blkio_add_stat(stats->stat_arr[BLKIO_STAT_SERVICE_BYTES], bytes,
-                       direction, sync);
-       spin_unlock_irqrestore(&blkg->stats_lock, flags);
+       /*
+        * Disabling interrupts to provide mutual exclusion between two
+        * writes on same cpu. It probably is not needed for 64bit. Not
+        * optimizing that case yet.
+        */
+       local_irq_save(flags);
+
+       stats_cpu = this_cpu_ptr(blkg->stats_cpu);
+
+       u64_stats_update_begin(&stats_cpu->syncp);
+       stats_cpu->sectors += bytes >> 9;
+       blkio_add_stat(stats_cpu->stat_arr_cpu[BLKIO_STAT_CPU_SERVICED],
+                       1, direction, sync);
+       blkio_add_stat(stats_cpu->stat_arr_cpu[BLKIO_STAT_CPU_SERVICE_BYTES],
+                       bytes, direction, sync);
+       u64_stats_update_end(&stats_cpu->syncp);
+       local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(blkiocg_update_dispatch_stats);
 
@@ -426,18 +439,44 @@ void blkiocg_update_completion_stats(struct blkio_group *blkg,
 }
 EXPORT_SYMBOL_GPL(blkiocg_update_completion_stats);
 
+/*  Merged stats are per cpu.  */
 void blkiocg_update_io_merged_stats(struct blkio_group *blkg, bool direction,
                                        bool sync)
 {
+       struct blkio_group_stats_cpu *stats_cpu;
        unsigned long flags;
 
-       spin_lock_irqsave(&blkg->stats_lock, flags);
-       blkio_add_stat(blkg->stats.stat_arr[BLKIO_STAT_MERGED], 1, direction,
-                       sync);
-       spin_unlock_irqrestore(&blkg->stats_lock, flags);
+       /*
+        * Disabling interrupts to provide mutual exclusion between two
+        * writes on same cpu. It probably is not needed for 64bit. Not
+        * optimizing that case yet.
+        */
+       local_irq_save(flags);
+
+       stats_cpu = this_cpu_ptr(blkg->stats_cpu);
+
+       u64_stats_update_begin(&stats_cpu->syncp);
+       blkio_add_stat(stats_cpu->stat_arr_cpu[BLKIO_STAT_CPU_MERGED], 1,
+                               direction, sync);
+       u64_stats_update_end(&stats_cpu->syncp);
+       local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(blkiocg_update_io_merged_stats);
 
+/*
+ * This function allocates the per cpu stats for blkio_group. Should be called
+ * from sleepable context as alloc_per_cpu() requires that.
+ */
+int blkio_alloc_blkg_stats(struct blkio_group *blkg)
+{
+       /* Allocate memory for per cpu stats */
+       blkg->stats_cpu = alloc_percpu(struct blkio_group_stats_cpu);
+       if (!blkg->stats_cpu)
+               return -ENOMEM;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(blkio_alloc_blkg_stats);
+
 void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
                struct blkio_group *blkg, void *key, dev_t dev,
                enum blkio_policy_id plid)
@@ -508,6 +547,30 @@ struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg, void *key)
 }
 EXPORT_SYMBOL_GPL(blkiocg_lookup_group);
 
+static void blkio_reset_stats_cpu(struct blkio_group *blkg)
+{
+       struct blkio_group_stats_cpu *stats_cpu;
+       int i, j, k;
+       /*
+        * Note: On 64 bit arch this should not be an issue. This has the
+        * possibility of returning some inconsistent value on 32bit arch
+        * as 64bit update on 32bit is non atomic. Taking care of this
+        * corner case makes code very complicated, like sending IPIs to
+        * cpus, taking care of stats of offline cpus etc.
+        *
+        * reset stats is anyway more of a debug feature and this sounds a
+        * corner case. So I am not complicating the code yet until and
+        * unless this becomes a real issue.
+        */
+       for_each_possible_cpu(i) {
+               stats_cpu = per_cpu_ptr(blkg->stats_cpu, i);
+               stats_cpu->sectors = 0;
+               for(j = 0; j < BLKIO_STAT_CPU_NR; j++)
+                       for (k = 0; k < BLKIO_STAT_TOTAL; k++)
+                               stats_cpu->stat_arr_cpu[j][k] = 0;
+       }
+}
+
 static int
 blkiocg_reset_stats(struct cgroup *cgroup, struct cftype *cftype, u64 val)
 {
@@ -552,7 +615,11 @@ blkiocg_reset_stats(struct cgroup *cgroup, struct cftype *cftype, u64 val)
                }
 #endif
                spin_unlock(&blkg->stats_lock);
+
+               /* Reset Per cpu stats which don't take blkg->stats_lock */
+               blkio_reset_stats_cpu(blkg);
        }
+
        spin_unlock_irq(&blkcg->lock);
        return 0;
 }
@@ -598,6 +665,59 @@ static uint64_t blkio_fill_stat(char *str, int chars_left, uint64_t val,
        return val;
 }
 
+
+static uint64_t blkio_read_stat_cpu(struct blkio_group *blkg,
+                       enum stat_type_cpu type, enum stat_sub_type sub_type)
+{
+       int cpu;
+       struct blkio_group_stats_cpu *stats_cpu;
+       u64 val = 0, tval;
+
+       for_each_possible_cpu(cpu) {
+               unsigned int start;
+               stats_cpu  = per_cpu_ptr(blkg->stats_cpu, cpu);
+
+               do {
+                       start = u64_stats_fetch_begin(&stats_cpu->syncp);
+                       if (type == BLKIO_STAT_CPU_SECTORS)
+                               tval = stats_cpu->sectors;
+                       else
+                               tval = stats_cpu->stat_arr_cpu[type][sub_type];
+               } while(u64_stats_fetch_retry(&stats_cpu->syncp, start));
+
+               val += tval;
+       }
+
+       return val;
+}
+
+static uint64_t blkio_get_stat_cpu(struct blkio_group *blkg,
+               struct cgroup_map_cb *cb, dev_t dev, enum stat_type_cpu type)
+{
+       uint64_t disk_total, val;
+       char key_str[MAX_KEY_LEN];
+       enum stat_sub_type sub_type;
+
+       if (type == BLKIO_STAT_CPU_SECTORS) {
+               val = blkio_read_stat_cpu(blkg, type, 0);
+               return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, val, cb, dev);
+       }
+
+       for (sub_type = BLKIO_STAT_READ; sub_type < BLKIO_STAT_TOTAL;
+                       sub_type++) {
+               blkio_get_key_name(sub_type, dev, key_str, MAX_KEY_LEN, false);
+               val = blkio_read_stat_cpu(blkg, type, sub_type);
+               cb->fill(cb, key_str, val);
+       }
+
+       disk_total = blkio_read_stat_cpu(blkg, type, BLKIO_STAT_READ) +
+                       blkio_read_stat_cpu(blkg, type, BLKIO_STAT_WRITE);
+
+       blkio_get_key_name(BLKIO_STAT_TOTAL, dev, key_str, MAX_KEY_LEN, false);
+       cb->fill(cb, key_str, disk_total);
+       return disk_total;
+}
+
 /* This should be called with blkg->stats_lock held */
 static uint64_t blkio_get_stat(struct blkio_group *blkg,
                struct cgroup_map_cb *cb, dev_t dev, enum stat_type type)
@@ -609,9 +729,6 @@ static uint64_t blkio_get_stat(struct blkio_group *blkg,
        if (type == BLKIO_STAT_TIME)
                return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
                                        blkg->stats.time, cb, dev);
-       if (type == BLKIO_STAT_SECTORS)
-               return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
-                                       blkg->stats.sectors, cb, dev);
 #ifdef CONFIG_DEBUG_BLK_CGROUP
        if (type == BLKIO_STAT_UNACCOUNTED_TIME)
                return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
@@ -1075,8 +1192,8 @@ static int blkiocg_file_read(struct cgroup *cgrp, struct cftype *cft,
 }
 
 static int blkio_read_blkg_stats(struct blkio_cgroup *blkcg,
-               struct cftype *cft, struct cgroup_map_cb *cb, enum stat_type type,
-               bool show_total)
+               struct cftype *cft, struct cgroup_map_cb *cb,
+               enum stat_type type, bool show_total, bool pcpu)
 {
        struct blkio_group *blkg;
        struct hlist_node *n;
@@ -1087,10 +1204,15 @@ static int blkio_read_blkg_stats(struct blkio_cgroup *blkcg,
                if (blkg->dev) {
                        if (!cftype_blkg_same_policy(cft, blkg))
                                continue;
-                       spin_lock_irq(&blkg->stats_lock);
-                       cgroup_total += blkio_get_stat(blkg, cb, blkg->dev,
-                                               type);
-                       spin_unlock_irq(&blkg->stats_lock);
+                       if (pcpu)
+                               cgroup_total += blkio_get_stat_cpu(blkg, cb,
+                                               blkg->dev, type);
+                       else {
+                               spin_lock_irq(&blkg->stats_lock);
+                               cgroup_total += blkio_get_stat(blkg, cb,
+                                               blkg->dev, type);
+                               spin_unlock_irq(&blkg->stats_lock);
+                       }
                }
        }
        if (show_total)
@@ -1114,47 +1236,47 @@ static int blkiocg_file_read_map(struct cgroup *cgrp, struct cftype *cft,
                switch(name) {
                case BLKIO_PROP_time:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_TIME, 0);
+                                               BLKIO_STAT_TIME, 0, 0);
                case BLKIO_PROP_sectors:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_SECTORS, 0);
+                                               BLKIO_STAT_CPU_SECTORS, 0, 1);
                case BLKIO_PROP_io_service_bytes:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_SERVICE_BYTES, 1);
+                                       BLKIO_STAT_CPU_SERVICE_BYTES, 1, 1);
                case BLKIO_PROP_io_serviced:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_SERVICED, 1);
+                                               BLKIO_STAT_CPU_SERVICED, 1, 1);
                case BLKIO_PROP_io_service_time:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_SERVICE_TIME, 1);
+                                               BLKIO_STAT_SERVICE_TIME, 1, 0);
                case BLKIO_PROP_io_wait_time:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_WAIT_TIME, 1);
+                                               BLKIO_STAT_WAIT_TIME, 1, 0);
                case BLKIO_PROP_io_merged:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_MERGED, 1);
+                                               BLKIO_STAT_CPU_MERGED, 1, 1);
                case BLKIO_PROP_io_queued:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_QUEUED, 1);
+                                               BLKIO_STAT_QUEUED, 1, 0);
 #ifdef CONFIG_DEBUG_BLK_CGROUP
                case BLKIO_PROP_unaccounted_time:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_UNACCOUNTED_TIME, 0);
+                                       BLKIO_STAT_UNACCOUNTED_TIME, 0, 0);
                case BLKIO_PROP_dequeue:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_DEQUEUE, 0);
+                                               BLKIO_STAT_DEQUEUE, 0, 0);
                case BLKIO_PROP_avg_queue_size:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_AVG_QUEUE_SIZE, 0);
+                                       BLKIO_STAT_AVG_QUEUE_SIZE, 0, 0);
                case BLKIO_PROP_group_wait_time:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_GROUP_WAIT_TIME, 0);
+                                       BLKIO_STAT_GROUP_WAIT_TIME, 0, 0);
                case BLKIO_PROP_idle_time:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_IDLE_TIME, 0);
+                                               BLKIO_STAT_IDLE_TIME, 0, 0);
                case BLKIO_PROP_empty_time:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_EMPTY_TIME, 0);
+                                               BLKIO_STAT_EMPTY_TIME, 0, 0);
 #endif
                default:
                        BUG();
@@ -1164,10 +1286,10 @@ static int blkiocg_file_read_map(struct cgroup *cgrp, struct cftype *cft,
                switch(name){
                case BLKIO_THROTL_io_service_bytes:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_SERVICE_BYTES, 1);
+                                               BLKIO_STAT_CPU_SERVICE_BYTES, 1, 1);
                case BLKIO_THROTL_io_serviced:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_SERVICED, 1);
+                                               BLKIO_STAT_CPU_SERVICED, 1, 1);
                default:
                        BUG();
                }
@@ -1492,9 +1614,7 @@ done:
  * of the main cic data structures.  For now we allow a task to change
  * its cgroup only if it's the only owner of its ioc.
  */
-static int blkiocg_can_attach(struct cgroup_subsys *subsys,
-                               struct cgroup *cgroup, struct task_struct *tsk,
-                               bool threadgroup)
+static int blkiocg_can_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
 {
        struct io_context *ioc;
        int ret = 0;
@@ -1509,9 +1629,7 @@ static int blkiocg_can_attach(struct cgroup_subsys *subsys,
        return ret;
 }
 
-static void blkiocg_attach(struct cgroup_subsys *subsys, struct cgroup *cgroup,
-                               struct cgroup *prev, struct task_struct *tsk,
-                               bool threadgroup)
+static void blkiocg_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
 {
        struct io_context *ioc;
 
index c774930cc20659de992ccebc21d35ffd1e80e234..a71d2904ffb97c1f6f2e9f9d5480d389b0ffccff 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/cgroup.h>
+#include <linux/u64_stats_sync.h>
 
 enum blkio_policy_id {
        BLKIO_POLICY_PROP = 0,          /* Proportional Bandwidth division */
@@ -36,22 +37,15 @@ enum stat_type {
         * request completion for IOs doen by this cgroup. This may not be
         * accurate when NCQ is turned on. */
        BLKIO_STAT_SERVICE_TIME = 0,
-       /* Total bytes transferred */
-       BLKIO_STAT_SERVICE_BYTES,
-       /* Total IOs serviced, post merge */
-       BLKIO_STAT_SERVICED,
        /* Total time spent waiting in scheduler queue in ns */
        BLKIO_STAT_WAIT_TIME,
-       /* Number of IOs merged */
-       BLKIO_STAT_MERGED,
        /* Number of IOs queued up */
        BLKIO_STAT_QUEUED,
        /* All the single valued stats go below this */
        BLKIO_STAT_TIME,
-       BLKIO_STAT_SECTORS,
+#ifdef CONFIG_DEBUG_BLK_CGROUP
        /* Time not charged to this cgroup */
        BLKIO_STAT_UNACCOUNTED_TIME,
-#ifdef CONFIG_DEBUG_BLK_CGROUP
        BLKIO_STAT_AVG_QUEUE_SIZE,
        BLKIO_STAT_IDLE_TIME,
        BLKIO_STAT_EMPTY_TIME,
@@ -60,6 +54,18 @@ enum stat_type {
 #endif
 };
 
+/* Per cpu stats */
+enum stat_type_cpu {
+       BLKIO_STAT_CPU_SECTORS,
+       /* Total bytes transferred */
+       BLKIO_STAT_CPU_SERVICE_BYTES,
+       /* Total IOs serviced, post merge */
+       BLKIO_STAT_CPU_SERVICED,
+       /* Number of IOs merged */
+       BLKIO_STAT_CPU_MERGED,
+       BLKIO_STAT_CPU_NR
+};
+
 enum stat_sub_type {
        BLKIO_STAT_READ = 0,
        BLKIO_STAT_WRITE,
@@ -116,11 +122,11 @@ struct blkio_cgroup {
 struct blkio_group_stats {
        /* total disk time and nr sectors dispatched by this group */
        uint64_t time;
-       uint64_t sectors;
-       /* Time not charged to this cgroup */
-       uint64_t unaccounted_time;
        uint64_t stat_arr[BLKIO_STAT_QUEUED + 1][BLKIO_STAT_TOTAL];
 #ifdef CONFIG_DEBUG_BLK_CGROUP
+       /* Time not charged to this cgroup */
+       uint64_t unaccounted_time;
+
        /* Sum of number of IOs queued across all samples */
        uint64_t avg_queue_size_sum;
        /* Count of samples taken for average */
@@ -145,6 +151,13 @@ struct blkio_group_stats {
 #endif
 };
 
+/* Per cpu blkio group stats */
+struct blkio_group_stats_cpu {
+       uint64_t sectors;
+       uint64_t stat_arr_cpu[BLKIO_STAT_CPU_NR][BLKIO_STAT_TOTAL];
+       struct u64_stats_sync syncp;
+};
+
 struct blkio_group {
        /* An rcu protected unique identifier for the group */
        void *key;
@@ -160,6 +173,8 @@ struct blkio_group {
        /* Need to serialize the stats in the case of reset/update */
        spinlock_t stats_lock;
        struct blkio_group_stats stats;
+       /* Per cpu stats pointer */
+       struct blkio_group_stats_cpu __percpu *stats_cpu;
 };
 
 struct blkio_policy_node {
@@ -295,6 +310,7 @@ extern struct blkio_cgroup *task_blkio_cgroup(struct task_struct *tsk);
 extern void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
        struct blkio_group *blkg, void *key, dev_t dev,
        enum blkio_policy_id plid);
+extern int blkio_alloc_blkg_stats(struct blkio_group *blkg);
 extern int blkiocg_del_blkio_group(struct blkio_group *blkg);
 extern struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg,
                                                void *key);
@@ -322,6 +338,8 @@ static inline void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
                struct blkio_group *blkg, void *key, dev_t dev,
                enum blkio_policy_id plid) {}
 
+static inline int blkio_alloc_blkg_stats(struct blkio_group *blkg) { return 0; }
+
 static inline int
 blkiocg_del_blkio_group(struct blkio_group *blkg) { return 0; }
 
index 3fe00a14822a203cacc0529ad0610cf5ce7dae06..d2f8f4049abddbf76d3414cd85ef36d2d4027d07 100644 (file)
@@ -345,6 +345,7 @@ void blk_put_queue(struct request_queue *q)
 {
        kobject_put(&q->kobj);
 }
+EXPORT_SYMBOL(blk_put_queue);
 
 /*
  * Note: If a driver supplied the queue lock, it should not zap that lock
@@ -566,11 +567,10 @@ int blk_get_queue(struct request_queue *q)
 
        return 1;
 }
+EXPORT_SYMBOL(blk_get_queue);
 
 static inline void blk_free_request(struct request_queue *q, struct request *rq)
 {
-       BUG_ON(rq->cmd_flags & REQ_ON_PLUG);
-
        if (rq->cmd_flags & REQ_ELVPRIV)
                elv_put_request(q, rq);
        mempool_free(rq, q->rq.rq_pool);
@@ -1110,14 +1110,6 @@ static bool bio_attempt_back_merge(struct request_queue *q, struct request *req,
 {
        const int ff = bio->bi_rw & REQ_FAILFAST_MASK;
 
-       /*
-        * Debug stuff, kill later
-        */
-       if (!rq_mergeable(req)) {
-               blk_dump_rq_flags(req, "back");
-               return false;
-       }
-
        if (!ll_back_merge_fn(q, req, bio))
                return false;
 
@@ -1132,6 +1124,7 @@ static bool bio_attempt_back_merge(struct request_queue *q, struct request *req,
        req->ioprio = ioprio_best(req->ioprio, bio_prio(bio));
 
        drive_stat_acct(req, 0);
+       elv_bio_merged(q, req, bio);
        return true;
 }
 
@@ -1139,15 +1132,6 @@ static bool bio_attempt_front_merge(struct request_queue *q,
                                    struct request *req, struct bio *bio)
 {
        const int ff = bio->bi_rw & REQ_FAILFAST_MASK;
-       sector_t sector;
-
-       /*
-        * Debug stuff, kill later
-        */
-       if (!rq_mergeable(req)) {
-               blk_dump_rq_flags(req, "front");
-               return false;
-       }
 
        if (!ll_front_merge_fn(q, req, bio))
                return false;
@@ -1157,8 +1141,6 @@ static bool bio_attempt_front_merge(struct request_queue *q,
        if ((req->cmd_flags & REQ_FAILFAST_MASK) != ff)
                blk_rq_set_mixed_merge(req);
 
-       sector = bio->bi_sector;
-
        bio->bi_next = req->bio;
        req->bio = bio;
 
@@ -1173,6 +1155,7 @@ static bool bio_attempt_front_merge(struct request_queue *q,
        req->ioprio = ioprio_best(req->ioprio, bio_prio(bio));
 
        drive_stat_acct(req, 0);
+       elv_bio_merged(q, req, bio);
        return true;
 }
 
@@ -1258,14 +1241,12 @@ static int __make_request(struct request_queue *q, struct bio *bio)
 
        el_ret = elv_merge(q, &req, bio);
        if (el_ret == ELEVATOR_BACK_MERGE) {
-               BUG_ON(req->cmd_flags & REQ_ON_PLUG);
                if (bio_attempt_back_merge(q, req, bio)) {
                        if (!attempt_back_merge(q, req))
                                elv_merged_request(q, req, el_ret);
                        goto out_unlock;
                }
        } else if (el_ret == ELEVATOR_FRONT_MERGE) {
-               BUG_ON(req->cmd_flags & REQ_ON_PLUG);
                if (bio_attempt_front_merge(q, req, bio)) {
                        if (!attempt_front_merge(q, req))
                                elv_merged_request(q, req, el_ret);
@@ -1320,10 +1301,6 @@ get_rq:
                        if (__rq->q != q)
                                plug->should_sort = 1;
                }
-               /*
-                * Debug flag, kill later
-                */
-               req->cmd_flags |= REQ_ON_PLUG;
                list_add_tail(&req->queuelist, &plug->list);
                drive_stat_acct(req, 1);
        } else {
@@ -1550,7 +1527,8 @@ static inline void __generic_make_request(struct bio *bio)
                        goto end_io;
                }
 
-               blk_throtl_bio(q, &bio);
+               if (blk_throtl_bio(q, &bio))
+                       goto end_io;
 
                /*
                 * If bio = NULL, bio has been throttled and will be submitted
@@ -2748,7 +2726,6 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
        while (!list_empty(&list)) {
                rq = list_entry_rq(list.next);
                list_del_init(&rq->queuelist);
-               BUG_ON(!(rq->cmd_flags & REQ_ON_PLUG));
                BUG_ON(!rq->q);
                if (rq->q != q) {
                        /*
@@ -2760,8 +2737,6 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
                        depth = 0;
                        spin_lock(q->queue_lock);
                }
-               rq->cmd_flags &= ~REQ_ON_PLUG;
-
                /*
                 * rq is already accounted, so use raw insert
                 */
index 81e31819a597bb0c6ed6dd4f781eb037c986a243..8a0e7ec056e7a3bd6db31f19ec72202ae97c581e 100644 (file)
@@ -56,7 +56,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
        spin_lock_irq(q->queue_lock);
        __elv_add_request(q, rq, where);
        __blk_run_queue(q);
-       /* the queue is stopped so it won't be plugged+unplugged */
+       /* the queue is stopped so it won't be run */
        if (rq->cmd_type == REQ_TYPE_PM_RESUME)
                q->request_fn(q);
        spin_unlock_irq(q->queue_lock);
index 6c9b5e189e624888860e5185d1d9b3479b3e49a4..bb21e4c36f70ca437162356edd87d2ce3a265a46 100644 (file)
@@ -212,13 +212,19 @@ static void flush_end_io(struct request *flush_rq, int error)
        }
 
        /*
-        * Moving a request silently to empty queue_head may stall the
-        * queue.  Kick the queue in those cases.  This function is called
-        * from request completion path and calling directly into
-        * request_fn may confuse the driver.  Always use kblockd.
+        * Kick the queue to avoid stall for two cases:
+        * 1. Moving a request silently to empty queue_head may stall the
+        * queue.
+        * 2. When flush request is running in non-queueable queue, the
+        * queue is hold. Restart the queue after flush request is finished
+        * to avoid stall.
+        * This function is called from request completion path and calling
+        * directly into request_fn may confuse the driver.  Always use
+        * kblockd.
         */
-       if (queued)
+       if (queued || q->flush_queue_delayed)
                blk_run_queue_async(q);
+       q->flush_queue_delayed = 0;
 }
 
 /**
index b791022beef3158ba02a739c061838bf57500bf5..342eae9b0d3cf982762987dfc5efb9a59f9b7275 100644 (file)
@@ -21,7 +21,7 @@ static void cfq_dtor(struct io_context *ioc)
        if (!hlist_empty(&ioc->cic_list)) {
                struct cfq_io_context *cic;
 
-               cic = list_entry(ioc->cic_list.first, struct cfq_io_context,
+               cic = hlist_entry(ioc->cic_list.first, struct cfq_io_context,
                                                                cic_list);
                cic->dtor(ioc);
        }
@@ -57,7 +57,7 @@ static void cfq_exit(struct io_context *ioc)
        if (!hlist_empty(&ioc->cic_list)) {
                struct cfq_io_context *cic;
 
-               cic = list_entry(ioc->cic_list.first, struct cfq_io_context,
+               cic = hlist_entry(ioc->cic_list.first, struct cfq_io_context,
                                                                cic_list);
                cic->exit(ioc);
        }
@@ -96,6 +96,9 @@ struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
                INIT_RADIX_TREE(&ret->radix_root, GFP_ATOMIC | __GFP_HIGH);
                INIT_HLIST_HEAD(&ret->cic_list);
                ret->ioc_data = NULL;
+#if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE)
+               ret->cgroup_changed = 0;
+#endif
        }
 
        return ret;
index 25de73e4759b82d624c2a89b545baf6ea859f624..78e627e2581d5a6c80ec12d9267c57c0468ecf5f 100644 (file)
@@ -9,17 +9,20 @@
 
 #include "blk.h"
 
-static void blkdev_discard_end_io(struct bio *bio, int err)
-{
-       if (err) {
-               if (err == -EOPNOTSUPP)
-                       set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
-               clear_bit(BIO_UPTODATE, &bio->bi_flags);
-       }
+struct bio_batch {
+       atomic_t                done;
+       unsigned long           flags;
+       struct completion       *wait;
+};
 
-       if (bio->bi_private)
-               complete(bio->bi_private);
+static void bio_batch_end_io(struct bio *bio, int err)
+{
+       struct bio_batch *bb = bio->bi_private;
 
+       if (err && (err != -EOPNOTSUPP))
+               clear_bit(BIO_UPTODATE, &bb->flags);
+       if (atomic_dec_and_test(&bb->done))
+               complete(bb->wait);
        bio_put(bio);
 }
 
@@ -41,6 +44,7 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
        struct request_queue *q = bdev_get_queue(bdev);
        int type = REQ_WRITE | REQ_DISCARD;
        unsigned int max_discard_sectors;
+       struct bio_batch bb;
        struct bio *bio;
        int ret = 0;
 
@@ -67,7 +71,11 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
                type |= REQ_SECURE;
        }
 
-       while (nr_sects && !ret) {
+       atomic_set(&bb.done, 1);
+       bb.flags = 1 << BIO_UPTODATE;
+       bb.wait = &wait;
+
+       while (nr_sects) {
                bio = bio_alloc(gfp_mask, 1);
                if (!bio) {
                        ret = -ENOMEM;
@@ -75,9 +83,9 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
                }
 
                bio->bi_sector = sector;
-               bio->bi_end_io = blkdev_discard_end_io;
+               bio->bi_end_io = bio_batch_end_io;
                bio->bi_bdev = bdev;
-               bio->bi_private = &wait;
+               bio->bi_private = &bb;
 
                if (nr_sects > max_discard_sectors) {
                        bio->bi_size = max_discard_sectors << 9;
@@ -88,45 +96,21 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
                        nr_sects = 0;
                }
 
-               bio_get(bio);
+               atomic_inc(&bb.done);
                submit_bio(type, bio);
+       }
 
+       /* Wait for bios in-flight */
+       if (!atomic_dec_and_test(&bb.done))
                wait_for_completion(&wait);
 
-               if (bio_flagged(bio, BIO_EOPNOTSUPP))
-                       ret = -EOPNOTSUPP;
-               else if (!bio_flagged(bio, BIO_UPTODATE))
-                       ret = -EIO;
-               bio_put(bio);
-       }
+       if (!test_bit(BIO_UPTODATE, &bb.flags))
+               ret = -EIO;
 
        return ret;
 }
 EXPORT_SYMBOL(blkdev_issue_discard);
 
-struct bio_batch
-{
-       atomic_t                done;
-       unsigned long           flags;
-       struct completion       *wait;
-};
-
-static void bio_batch_end_io(struct bio *bio, int err)
-{
-       struct bio_batch *bb = bio->bi_private;
-
-       if (err) {
-               if (err == -EOPNOTSUPP)
-                       set_bit(BIO_EOPNOTSUPP, &bb->flags);
-               else
-                       clear_bit(BIO_UPTODATE, &bb->flags);
-       }
-       if (bb)
-               if (atomic_dec_and_test(&bb->done))
-                       complete(bb->wait);
-       bio_put(bio);
-}
-
 /**
  * blkdev_issue_zeroout - generate number of zero filed write bios
  * @bdev:      blockdev to issue
@@ -151,7 +135,6 @@ int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
        bb.flags = 1 << BIO_UPTODATE;
        bb.wait = &wait;
 
-submit:
        ret = 0;
        while (nr_sects != 0) {
                bio = bio_alloc(gfp_mask,
@@ -168,9 +151,6 @@ submit:
 
                while (nr_sects != 0) {
                        sz = min((sector_t) PAGE_SIZE >> 9 , nr_sects);
-                       if (sz == 0)
-                               /* bio has maximum size possible */
-                               break;
                        ret = bio_add_page(bio, ZERO_PAGE(0), sz << 9, 0);
                        nr_sects -= ret >> 9;
                        sector += ret >> 9;
@@ -190,16 +170,6 @@ submit:
                /* One of bios in the batch was completed with error.*/
                ret = -EIO;
 
-       if (ret)
-               goto out;
-
-       if (test_bit(BIO_EOPNOTSUPP, &bb.flags)) {
-               ret = -EOPNOTSUPP;
-               goto out;
-       }
-       if (nr_sects != 0)
-               goto submit;
-out:
        return ret;
 }
 EXPORT_SYMBOL(blkdev_issue_zeroout);
index 1fa7692935976f4e60393e8d7289acf1c56c74c3..fa1eb0449a05f0db45de3ab8e6a01a2fc2a95238 100644 (file)
@@ -120,7 +120,7 @@ void blk_set_default_limits(struct queue_limits *lim)
        lim->discard_granularity = 0;
        lim->discard_alignment = 0;
        lim->discard_misaligned = 0;
-       lim->discard_zeroes_data = -1;
+       lim->discard_zeroes_data = 1;
        lim->logical_block_size = lim->physical_block_size = lim->io_min = 512;
        lim->bounce_pfn = (unsigned long)(BLK_BOUNCE_ANY >> PAGE_SHIFT);
        lim->alignment_offset = 0;
@@ -166,6 +166,7 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
 
        blk_set_default_limits(&q->limits);
        blk_queue_max_hw_sectors(q, BLK_SAFE_MAX_SECTORS);
+       q->limits.discard_zeroes_data = 0;
 
        /*
         * by default assume old behaviour and bounce for any highmem page
@@ -790,6 +791,12 @@ void blk_queue_flush(struct request_queue *q, unsigned int flush)
 }
 EXPORT_SYMBOL_GPL(blk_queue_flush);
 
+void blk_queue_flush_queueable(struct request_queue *q, bool queueable)
+{
+       q->flush_not_queueable = !queueable;
+}
+EXPORT_SYMBOL_GPL(blk_queue_flush_queueable);
+
 static int __init blk_settings_init(void)
 {
        blk_max_low_pfn = max_low_pfn - 1;
index bd236313f35d59bd08da5a3d375cc29eed6fd86f..d935bd859c87bc1c9a0e39eb61438583f91690f9 100644 (file)
@@ -152,7 +152,8 @@ static ssize_t queue_discard_granularity_show(struct request_queue *q, char *pag
 
 static ssize_t queue_discard_max_show(struct request_queue *q, char *page)
 {
-       return queue_var_show(q->limits.max_discard_sectors << 9, page);
+       return sprintf(page, "%llu\n",
+                      (unsigned long long)q->limits.max_discard_sectors << 9);
 }
 
 static ssize_t queue_discard_zeroes_data_show(struct request_queue *q, char *page)
index 252a81a306f7bef0179f953ab1535a4a06a40798..3689f833afdc57c12916e2fc985ef8c18ccc2904 100644 (file)
@@ -78,6 +78,8 @@ struct throtl_grp {
 
        /* Some throttle limits got updated for the group */
        int limits_changed;
+
+       struct rcu_head rcu_head;
 };
 
 struct throtl_data
@@ -88,7 +90,7 @@ struct throtl_data
        /* service tree for active throtl groups */
        struct throtl_rb_root tg_service_tree;
 
-       struct throtl_grp root_tg;
+       struct throtl_grp *root_tg;
        struct request_queue *queue;
 
        /* Total Number of queued bios on READ and WRITE lists */
@@ -151,56 +153,44 @@ static inline struct throtl_grp *throtl_ref_get_tg(struct throtl_grp *tg)
        return tg;
 }
 
-static void throtl_put_tg(struct throtl_grp *tg)
+static void throtl_free_tg(struct rcu_head *head)
 {
-       BUG_ON(atomic_read(&tg->ref) <= 0);
-       if (!atomic_dec_and_test(&tg->ref))
-               return;
+       struct throtl_grp *tg;
+
+       tg = container_of(head, struct throtl_grp, rcu_head);
+       free_percpu(tg->blkg.stats_cpu);
        kfree(tg);
 }
 
-static struct throtl_grp * throtl_find_alloc_tg(struct throtl_data *td,
-                       struct blkio_cgroup *blkcg)
+static void throtl_put_tg(struct throtl_grp *tg)
 {
-       struct throtl_grp *tg = NULL;
-       void *key = td;
-       struct backing_dev_info *bdi = &td->queue->backing_dev_info;
-       unsigned int major, minor;
+       BUG_ON(atomic_read(&tg->ref) <= 0);
+       if (!atomic_dec_and_test(&tg->ref))
+               return;
 
        /*
-        * TODO: Speed up blkiocg_lookup_group() by maintaining a radix
-        * tree of blkg (instead of traversing through hash list all
-        * the time.
+        * A group is freed in rcu manner. But having an rcu lock does not
+        * mean that one can access all the fields of blkg and assume these
+        * are valid. For example, don't try to follow throtl_data and
+        * request queue links.
+        *
+        * Having a reference to blkg under an rcu allows acess to only
+        * values local to groups like group stats and group rate limits
         */
+       call_rcu(&tg->rcu_head, throtl_free_tg);
+}
 
-       /*
-        * This is the common case when there are no blkio cgroups.
-        * Avoid lookup in this case
-        */
-       if (blkcg == &blkio_root_cgroup)
-               tg = &td->root_tg;
-       else
-               tg = tg_of_blkg(blkiocg_lookup_group(blkcg, key));
-
-       /* Fill in device details for root group */
-       if (tg && !tg->blkg.dev && bdi->dev && dev_name(bdi->dev)) {
-               sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
-               tg->blkg.dev = MKDEV(major, minor);
-               goto done;
-       }
-
-       if (tg)
-               goto done;
-
-       tg = kzalloc_node(sizeof(*tg), GFP_ATOMIC, td->queue->node);
-       if (!tg)
-               goto done;
-
+static void throtl_init_group(struct throtl_grp *tg)
+{
        INIT_HLIST_NODE(&tg->tg_node);
        RB_CLEAR_NODE(&tg->rb_node);
        bio_list_init(&tg->bio_lists[0]);
        bio_list_init(&tg->bio_lists[1]);
-       td->limits_changed = false;
+       tg->limits_changed = false;
+
+       /* Practically unlimited BW */
+       tg->bps[0] = tg->bps[1] = -1;
+       tg->iops[0] = tg->iops[1] = -1;
 
        /*
         * Take the initial reference that will be released on destroy
@@ -209,33 +199,181 @@ static struct throtl_grp * throtl_find_alloc_tg(struct throtl_data *td,
         * exit or cgroup deletion path depending on who is exiting first.
         */
        atomic_set(&tg->ref, 1);
+}
+
+/* Should be called with rcu read lock held (needed for blkcg) */
+static void
+throtl_add_group_to_td_list(struct throtl_data *td, struct throtl_grp *tg)
+{
+       hlist_add_head(&tg->tg_node, &td->tg_list);
+       td->nr_undestroyed_grps++;
+}
+
+static void
+__throtl_tg_fill_dev_details(struct throtl_data *td, struct throtl_grp *tg)
+{
+       struct backing_dev_info *bdi = &td->queue->backing_dev_info;
+       unsigned int major, minor;
+
+       if (!tg || tg->blkg.dev)
+               return;
+
+       /*
+        * Fill in device details for a group which might not have been
+        * filled at group creation time as queue was being instantiated
+        * and driver had not attached a device yet
+        */
+       if (bdi->dev && dev_name(bdi->dev)) {
+               sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
+               tg->blkg.dev = MKDEV(major, minor);
+       }
+}
+
+/*
+ * Should be called with without queue lock held. Here queue lock will be
+ * taken rarely. It will be taken only once during life time of a group
+ * if need be
+ */
+static void
+throtl_tg_fill_dev_details(struct throtl_data *td, struct throtl_grp *tg)
+{
+       if (!tg || tg->blkg.dev)
+               return;
+
+       spin_lock_irq(td->queue->queue_lock);
+       __throtl_tg_fill_dev_details(td, tg);
+       spin_unlock_irq(td->queue->queue_lock);
+}
+
+static void throtl_init_add_tg_lists(struct throtl_data *td,
+                       struct throtl_grp *tg, struct blkio_cgroup *blkcg)
+{
+       __throtl_tg_fill_dev_details(td, tg);
 
        /* Add group onto cgroup list */
-       sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
        blkiocg_add_blkio_group(blkcg, &tg->blkg, (void *)td,
-                               MKDEV(major, minor), BLKIO_POLICY_THROTL);
+                               tg->blkg.dev, BLKIO_POLICY_THROTL);
 
        tg->bps[READ] = blkcg_get_read_bps(blkcg, tg->blkg.dev);
        tg->bps[WRITE] = blkcg_get_write_bps(blkcg, tg->blkg.dev);
        tg->iops[READ] = blkcg_get_read_iops(blkcg, tg->blkg.dev);
        tg->iops[WRITE] = blkcg_get_write_iops(blkcg, tg->blkg.dev);
 
-       hlist_add_head(&tg->tg_node, &td->tg_list);
-       td->nr_undestroyed_grps++;
-done:
+       throtl_add_group_to_td_list(td, tg);
+}
+
+/* Should be called without queue lock and outside of rcu period */
+static struct throtl_grp *throtl_alloc_tg(struct throtl_data *td)
+{
+       struct throtl_grp *tg = NULL;
+       int ret;
+
+       tg = kzalloc_node(sizeof(*tg), GFP_ATOMIC, td->queue->node);
+       if (!tg)
+               return NULL;
+
+       ret = blkio_alloc_blkg_stats(&tg->blkg);
+
+       if (ret) {
+               kfree(tg);
+               return NULL;
+       }
+
+       throtl_init_group(tg);
        return tg;
 }
 
-static struct throtl_grp * throtl_get_tg(struct throtl_data *td)
+static struct
+throtl_grp *throtl_find_tg(struct throtl_data *td, struct blkio_cgroup *blkcg)
 {
        struct throtl_grp *tg = NULL;
+       void *key = td;
+
+       /*
+        * This is the common case when there are no blkio cgroups.
+        * Avoid lookup in this case
+        */
+       if (blkcg == &blkio_root_cgroup)
+               tg = td->root_tg;
+       else
+               tg = tg_of_blkg(blkiocg_lookup_group(blkcg, key));
+
+       __throtl_tg_fill_dev_details(td, tg);
+       return tg;
+}
+
+/*
+ * This function returns with queue lock unlocked in case of error, like
+ * request queue is no more
+ */
+static struct throtl_grp * throtl_get_tg(struct throtl_data *td)
+{
+       struct throtl_grp *tg = NULL, *__tg = NULL;
        struct blkio_cgroup *blkcg;
+       struct request_queue *q = td->queue;
 
        rcu_read_lock();
        blkcg = task_blkio_cgroup(current);
-       tg = throtl_find_alloc_tg(td, blkcg);
-       if (!tg)
-               tg = &td->root_tg;
+       tg = throtl_find_tg(td, blkcg);
+       if (tg) {
+               rcu_read_unlock();
+               return tg;
+       }
+
+       /*
+        * Need to allocate a group. Allocation of group also needs allocation
+        * of per cpu stats which in-turn takes a mutex() and can block. Hence
+        * we need to drop rcu lock and queue_lock before we call alloc
+        *
+        * Take the request queue reference to make sure queue does not
+        * go away once we return from allocation.
+        */
+       blk_get_queue(q);
+       rcu_read_unlock();
+       spin_unlock_irq(q->queue_lock);
+
+       tg = throtl_alloc_tg(td);
+       /*
+        * We might have slept in group allocation. Make sure queue is not
+        * dead
+        */
+       if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) {
+               blk_put_queue(q);
+               if (tg)
+                       kfree(tg);
+
+               return ERR_PTR(-ENODEV);
+       }
+       blk_put_queue(q);
+
+       /* Group allocated and queue is still alive. take the lock */
+       spin_lock_irq(q->queue_lock);
+
+       /*
+        * Initialize the new group. After sleeping, read the blkcg again.
+        */
+       rcu_read_lock();
+       blkcg = task_blkio_cgroup(current);
+
+       /*
+        * If some other thread already allocated the group while we were
+        * not holding queue lock, free up the group
+        */
+       __tg = throtl_find_tg(td, blkcg);
+
+       if (__tg) {
+               kfree(tg);
+               rcu_read_unlock();
+               return __tg;
+       }
+
+       /* Group allocation failed. Account the IO to root group */
+       if (!tg) {
+               tg = td->root_tg;
+               return tg;
+       }
+
+       throtl_init_add_tg_lists(td, tg, blkcg);
        rcu_read_unlock();
        return tg;
 }
@@ -544,6 +682,12 @@ static bool tg_with_in_bps_limit(struct throtl_data *td, struct throtl_grp *tg,
        return 0;
 }
 
+static bool tg_no_rule_group(struct throtl_grp *tg, bool rw) {
+       if (tg->bps[rw] == -1 && tg->iops[rw] == -1)
+               return 1;
+       return 0;
+}
+
 /*
  * Returns whether one can dispatch a bio or not. Also returns approx number
  * of jiffies to wait before this bio is with-in IO rate and can be dispatched
@@ -608,10 +752,6 @@ static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio)
        tg->bytes_disp[rw] += bio->bi_size;
        tg->io_disp[rw]++;
 
-       /*
-        * TODO: This will take blkg->stats_lock. Figure out a way
-        * to avoid this cost.
-        */
        blkiocg_update_dispatch_stats(&tg->blkg, bio->bi_size, rw, sync);
 }
 
@@ -787,7 +927,7 @@ static int throtl_dispatch(struct request_queue *q)
 
        bio_list_init(&bio_list_on_stack);
 
-       throtl_log(td, "dispatch nr_queued=%lu read=%u write=%u",
+       throtl_log(td, "dispatch nr_queued=%d read=%u write=%u",
                        total_nr_queued(td), td->nr_queued[READ],
                        td->nr_queued[WRITE]);
 
@@ -989,15 +1129,51 @@ int blk_throtl_bio(struct request_queue *q, struct bio **biop)
        struct throtl_grp *tg;
        struct bio *bio = *biop;
        bool rw = bio_data_dir(bio), update_disptime = true;
+       struct blkio_cgroup *blkcg;
 
        if (bio->bi_rw & REQ_THROTTLED) {
                bio->bi_rw &= ~REQ_THROTTLED;
                return 0;
        }
 
+       /*
+        * A throtl_grp pointer retrieved under rcu can be used to access
+        * basic fields like stats and io rates. If a group has no rules,
+        * just update the dispatch stats in lockless manner and return.
+        */
+
+       rcu_read_lock();
+       blkcg = task_blkio_cgroup(current);
+       tg = throtl_find_tg(td, blkcg);
+       if (tg) {
+               throtl_tg_fill_dev_details(td, tg);
+
+               if (tg_no_rule_group(tg, rw)) {
+                       blkiocg_update_dispatch_stats(&tg->blkg, bio->bi_size,
+                                       rw, bio->bi_rw & REQ_SYNC);
+                       rcu_read_unlock();
+                       return 0;
+               }
+       }
+       rcu_read_unlock();
+
+       /*
+        * Either group has not been allocated yet or it is not an unlimited
+        * IO group
+        */
+
        spin_lock_irq(q->queue_lock);
        tg = throtl_get_tg(td);
 
+       if (IS_ERR(tg)) {
+               if (PTR_ERR(tg) == -ENODEV) {
+                       /*
+                        * Queue is gone. No queue lock held here.
+                        */
+                       return -ENODEV;
+               }
+       }
+
        if (tg->nr_queued[rw]) {
                /*
                 * There is already another bio queued in same dir. No
@@ -1028,7 +1204,7 @@ int blk_throtl_bio(struct request_queue *q, struct bio **biop)
        }
 
 queue_bio:
-       throtl_log_tg(td, tg, "[%c] bio. bdisp=%u sz=%u bps=%llu"
+       throtl_log_tg(td, tg, "[%c] bio. bdisp=%llu sz=%u bps=%llu"
                        " iodisp=%u iops=%u queued=%d/%d",
                        rw == READ ? 'R' : 'W',
                        tg->bytes_disp[rw], bio->bi_size, tg->bps[rw],
@@ -1060,39 +1236,24 @@ int blk_throtl_init(struct request_queue *q)
        INIT_HLIST_HEAD(&td->tg_list);
        td->tg_service_tree = THROTL_RB_ROOT;
        td->limits_changed = false;
+       INIT_DELAYED_WORK(&td->throtl_work, blk_throtl_work);
 
-       /* Init root group */
-       tg = &td->root_tg;
-       INIT_HLIST_NODE(&tg->tg_node);
-       RB_CLEAR_NODE(&tg->rb_node);
-       bio_list_init(&tg->bio_lists[0]);
-       bio_list_init(&tg->bio_lists[1]);
-
-       /* Practically unlimited BW */
-       tg->bps[0] = tg->bps[1] = -1;
-       tg->iops[0] = tg->iops[1] = -1;
-       td->limits_changed = false;
+       /* alloc and Init root group. */
+       td->queue = q;
+       tg = throtl_alloc_tg(td);
 
-       /*
-        * Set root group reference to 2. One reference will be dropped when
-        * all groups on tg_list are being deleted during queue exit. Other
-        * reference will remain there as we don't want to delete this group
-        * as it is statically allocated and gets destroyed when throtl_data
-        * goes away.
-        */
-       atomic_set(&tg->ref, 2);
-       hlist_add_head(&tg->tg_node, &td->tg_list);
-       td->nr_undestroyed_grps++;
+       if (!tg) {
+               kfree(td);
+               return -ENOMEM;
+       }
 
-       INIT_DELAYED_WORK(&td->throtl_work, blk_throtl_work);
+       td->root_tg = tg;
 
        rcu_read_lock();
-       blkiocg_add_blkio_group(&blkio_root_cgroup, &tg->blkg, (void *)td,
-                                       0, BLKIO_POLICY_THROTL);
+       throtl_init_add_tg_lists(td, tg, &blkio_root_cgroup);
        rcu_read_unlock();
 
        /* Attach throtl data to request queue */
-       td->queue = q;
        q->td = td;
        return 0;
 }
index 61263463e38e17be7c7f742f0bbe9233eec2ecd2..d6586287adc9ccf44e0adc556b552c7b1404ca4b 100644 (file)
@@ -62,7 +62,28 @@ static inline struct request *__elv_next_request(struct request_queue *q)
                        return rq;
                }
 
-               if (!q->elevator->ops->elevator_dispatch_fn(q, 0))
+               /*
+                * Flush request is running and flush request isn't queueable
+                * in the drive, we can hold the queue till flush request is
+                * finished. Even we don't do this, driver can't dispatch next
+                * requests and will requeue them. And this can improve
+                * throughput too. For example, we have request flush1, write1,
+                * flush 2. flush1 is dispatched, then queue is hold, write1
+                * isn't inserted to queue. After flush1 is finished, flush2
+                * will be dispatched. Since disk cache is already clean,
+                * flush2 will be finished very soon, so looks like flush2 is
+                * folded to flush1.
+                * Since the queue is hold, a flag is set to indicate the queue
+                * should be restarted later. Please see flush_end_io() for
+                * details.
+                */
+               if (q->flush_pending_idx != q->flush_running_idx &&
+                               !queue_flush_queueable(q)) {
+                       q->flush_queue_delayed = 1;
+                       return NULL;
+               }
+               if (test_bit(QUEUE_FLAG_DEAD, &q->queue_flags) ||
+                   !q->elevator->ops->elevator_dispatch_fn(q, 0))
                        return NULL;
        }
 }
index ab7a9e6a9b1cb12c1952f5fd725ca2ea0dd20fd1..f3799432676d53cc3648c9ab6801fe4fd084b911 100644 (file)
@@ -185,7 +185,7 @@ struct cfq_group {
        int nr_cfqq;
 
        /*
-        * Per group busy queus average. Useful for workload slice calc. We
+        * Per group busy queues average. Useful for workload slice calc. We
         * create the array for each prio class but at run time it is used
         * only for RT and BE class and slot for IDLE class remains unused.
         * This is primarily done to avoid confusion and a gcc warning.
@@ -300,7 +300,9 @@ struct cfq_data {
 
        /* List of cfq groups being managed on this device*/
        struct hlist_head cfqg_list;
-       struct rcu_head rcu;
+
+       /* Number of groups which are on blkcg->blkg_list */
+       unsigned int nr_blkcg_linked_grps;
 };
 
 static struct cfq_group *cfq_get_next_cfqg(struct cfq_data *cfqd);
@@ -367,16 +369,16 @@ CFQ_CFQQ_FNS(wait_busy);
 #define cfq_log_cfqq(cfqd, cfqq, fmt, args...) \
        blk_add_trace_msg((cfqd)->queue, "cfq%d%c %s " fmt, (cfqq)->pid, \
                        cfq_cfqq_sync((cfqq)) ? 'S' : 'A', \
-                       blkg_path(&(cfqq)->cfqg->blkg), ##args);
+                       blkg_path(&(cfqq)->cfqg->blkg), ##args)
 
 #define cfq_log_cfqg(cfqd, cfqg, fmt, args...)                         \
        blk_add_trace_msg((cfqd)->queue, "%s " fmt,                     \
-                               blkg_path(&(cfqg)->blkg), ##args);      \
+                               blkg_path(&(cfqg)->blkg), ##args)       \
 
 #else
 #define cfq_log_cfqq(cfqd, cfqq, fmt, args...) \
        blk_add_trace_msg((cfqd)->queue, "cfq%d " fmt, (cfqq)->pid, ##args)
-#define cfq_log_cfqg(cfqd, cfqg, fmt, args...)         do {} while (0);
+#define cfq_log_cfqg(cfqd, cfqg, fmt, args...)         do {} while (0)
 #endif
 #define cfq_log(cfqd, fmt, args...)    \
        blk_add_trace_msg((cfqd)->queue, "cfq " fmt, ##args)
@@ -665,15 +667,11 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2,
        if (rq2 == NULL)
                return rq1;
 
-       if (rq_is_sync(rq1) && !rq_is_sync(rq2))
-               return rq1;
-       else if (rq_is_sync(rq2) && !rq_is_sync(rq1))
-               return rq2;
-       if ((rq1->cmd_flags & REQ_META) && !(rq2->cmd_flags & REQ_META))
-               return rq1;
-       else if ((rq2->cmd_flags & REQ_META) &&
-                !(rq1->cmd_flags & REQ_META))
-               return rq2;
+       if (rq_is_sync(rq1) != rq_is_sync(rq2))
+               return rq_is_sync(rq1) ? rq1 : rq2;
+
+       if ((rq1->cmd_flags ^ rq2->cmd_flags) & REQ_META)
+               return rq1->cmd_flags & REQ_META ? rq1 : rq2;
 
        s1 = blk_rq_pos(rq1);
        s2 = blk_rq_pos(rq2);
@@ -990,9 +988,10 @@ static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg,
 
        cfq_log_cfqg(cfqd, cfqg, "served: vt=%llu min_vt=%llu", cfqg->vdisktime,
                                        st->min_vdisktime);
-       cfq_log_cfqq(cfqq->cfqd, cfqq, "sl_used=%u disp=%u charge=%u iops=%u"
-                       " sect=%u", used_sl, cfqq->slice_dispatch, charge,
-                       iops_mode(cfqd), cfqq->nr_sectors);
+       cfq_log_cfqq(cfqq->cfqd, cfqq,
+                    "sl_used=%u disp=%u charge=%u iops=%u sect=%lu",
+                    used_sl, cfqq->slice_dispatch, charge,
+                    iops_mode(cfqd), cfqq->nr_sectors);
        cfq_blkiocg_update_timeslice_used(&cfqg->blkg, used_sl,
                                          unaccounted_sl);
        cfq_blkiocg_set_start_empty_time(&cfqg->blkg);
@@ -1014,28 +1013,47 @@ void cfq_update_blkio_group_weight(void *key, struct blkio_group *blkg,
        cfqg->needs_update = true;
 }
 
-static struct cfq_group * cfq_find_alloc_cfqg(struct cfq_data *cfqd,
-               struct blkio_cgroup *blkcg, int create)
+static void cfq_init_add_cfqg_lists(struct cfq_data *cfqd,
+                       struct cfq_group *cfqg, struct blkio_cgroup *blkcg)
 {
-       struct cfq_group *cfqg = NULL;
-       void *key = cfqd;
-       int i, j;
-       struct cfq_rb_root *st;
        struct backing_dev_info *bdi = &cfqd->queue->backing_dev_info;
        unsigned int major, minor;
 
-       cfqg = cfqg_of_blkg(blkiocg_lookup_group(blkcg, key));
-       if (cfqg && !cfqg->blkg.dev && bdi->dev && dev_name(bdi->dev)) {
+       /*
+        * Add group onto cgroup list. It might happen that bdi->dev is
+        * not initialized yet. Initialize this new group without major
+        * and minor info and this info will be filled in once a new thread
+        * comes for IO.
+        */
+       if (bdi->dev) {
                sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
-               cfqg->blkg.dev = MKDEV(major, minor);
-               goto done;
-       }
-       if (cfqg || !create)
-               goto done;
+               cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg,
+                                       (void *)cfqd, MKDEV(major, minor));
+       } else
+               cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg,
+                                       (void *)cfqd, 0);
+
+       cfqd->nr_blkcg_linked_grps++;
+       cfqg->weight = blkcg_get_weight(blkcg, cfqg->blkg.dev);
+
+       /* Add group on cfqd list */
+       hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list);
+}
+
+/*
+ * Should be called from sleepable context. No request queue lock as per
+ * cpu stats are allocated dynamically and alloc_percpu needs to be called
+ * from sleepable context.
+ */
+static struct cfq_group * cfq_alloc_cfqg(struct cfq_data *cfqd)
+{
+       struct cfq_group *cfqg = NULL;
+       int i, j, ret;
+       struct cfq_rb_root *st;
 
        cfqg = kzalloc_node(sizeof(*cfqg), GFP_ATOMIC, cfqd->queue->node);
        if (!cfqg)
-               goto done;
+               return NULL;
 
        for_each_cfqg_st(cfqg, i, j, st)
                *st = CFQ_RB_ROOT;
@@ -1049,43 +1067,94 @@ static struct cfq_group * cfq_find_alloc_cfqg(struct cfq_data *cfqd,
         */
        cfqg->ref = 1;
 
+       ret = blkio_alloc_blkg_stats(&cfqg->blkg);
+       if (ret) {
+               kfree(cfqg);
+               return NULL;
+       }
+
+       return cfqg;
+}
+
+static struct cfq_group *
+cfq_find_cfqg(struct cfq_data *cfqd, struct blkio_cgroup *blkcg)
+{
+       struct cfq_group *cfqg = NULL;
+       void *key = cfqd;
+       struct backing_dev_info *bdi = &cfqd->queue->backing_dev_info;
+       unsigned int major, minor;
+
        /*
-        * Add group onto cgroup list. It might happen that bdi->dev is
-        * not initialized yet. Initialize this new group without major
-        * and minor info and this info will be filled in once a new thread
-        * comes for IO. See code above.
+        * This is the common case when there are no blkio cgroups.
+        * Avoid lookup in this case
         */
-       if (bdi->dev) {
-               sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
-               cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd,
-                                       MKDEV(major, minor));
-       } else
-               cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd,
-                                       0);
-
-       cfqg->weight = blkcg_get_weight(blkcg, cfqg->blkg.dev);
+       if (blkcg == &blkio_root_cgroup)
+               cfqg = &cfqd->root_group;
+       else
+               cfqg = cfqg_of_blkg(blkiocg_lookup_group(blkcg, key));
 
-       /* Add group on cfqd list */
-       hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list);
+       if (cfqg && !cfqg->blkg.dev && bdi->dev && dev_name(bdi->dev)) {
+               sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
+               cfqg->blkg.dev = MKDEV(major, minor);
+       }
 
-done:
        return cfqg;
 }
 
 /*
- * Search for the cfq group current task belongs to. If create = 1, then also
- * create the cfq group if it does not exist. request_queue lock must be held.
+ * Search for the cfq group current task belongs to. request_queue lock must
+ * be held.
  */
-static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd, int create)
+static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd)
 {
        struct blkio_cgroup *blkcg;
-       struct cfq_group *cfqg = NULL;
+       struct cfq_group *cfqg = NULL, *__cfqg = NULL;
+       struct request_queue *q = cfqd->queue;
+
+       rcu_read_lock();
+       blkcg = task_blkio_cgroup(current);
+       cfqg = cfq_find_cfqg(cfqd, blkcg);
+       if (cfqg) {
+               rcu_read_unlock();
+               return cfqg;
+       }
+
+       /*
+        * Need to allocate a group. Allocation of group also needs allocation
+        * of per cpu stats which in-turn takes a mutex() and can block. Hence
+        * we need to drop rcu lock and queue_lock before we call alloc.
+        *
+        * Not taking any queue reference here and assuming that queue is
+        * around by the time we return. CFQ queue allocation code does
+        * the same. It might be racy though.
+        */
+
+       rcu_read_unlock();
+       spin_unlock_irq(q->queue_lock);
+
+       cfqg = cfq_alloc_cfqg(cfqd);
+
+       spin_lock_irq(q->queue_lock);
 
        rcu_read_lock();
        blkcg = task_blkio_cgroup(current);
-       cfqg = cfq_find_alloc_cfqg(cfqd, blkcg, create);
-       if (!cfqg && create)
+
+       /*
+        * If some other thread already allocated the group while we were
+        * not holding queue lock, free up the group
+        */
+       __cfqg = cfq_find_cfqg(cfqd, blkcg);
+
+       if (__cfqg) {
+               kfree(cfqg);
+               rcu_read_unlock();
+               return __cfqg;
+       }
+
+       if (!cfqg)
                cfqg = &cfqd->root_group;
+
+       cfq_init_add_cfqg_lists(cfqd, cfqg, blkcg);
        rcu_read_unlock();
        return cfqg;
 }
@@ -1118,6 +1187,7 @@ static void cfq_put_cfqg(struct cfq_group *cfqg)
                return;
        for_each_cfqg_st(cfqg, i, j, st)
                BUG_ON(!RB_EMPTY_ROOT(&st->rb));
+       free_percpu(cfqg->blkg.stats_cpu);
        kfree(cfqg);
 }
 
@@ -1176,7 +1246,7 @@ void cfq_unlink_blkio_group(void *key, struct blkio_group *blkg)
 }
 
 #else /* GROUP_IOSCHED */
-static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd, int create)
+static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd)
 {
        return &cfqd->root_group;
 }
@@ -1210,7 +1280,6 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        struct cfq_rb_root *service_tree;
        int left;
        int new_cfqq = 1;
-       int group_changed = 0;
 
        service_tree = service_tree_for(cfqq->cfqg, cfqq_prio(cfqq),
                                                cfqq_type(cfqq));
@@ -1281,7 +1350,7 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        rb_link_node(&cfqq->rb_node, parent, p);
        rb_insert_color(&cfqq->rb_node, &service_tree->rb);
        service_tree->count++;
-       if ((add_front || !new_cfqq) && !group_changed)
+       if (add_front || !new_cfqq)
                return;
        cfq_group_notify_queue_add(cfqd, cfqq->cfqg);
 }
@@ -1955,8 +2024,8 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
         */
        if (sample_valid(cic->ttime_samples) &&
            (cfqq->slice_end - jiffies < cic->ttime_mean)) {
-               cfq_log_cfqq(cfqd, cfqq, "Not idling. think_time:%d",
-                               cic->ttime_mean);
+               cfq_log_cfqq(cfqd, cfqq, "Not idling. think_time:%lu",
+                            cic->ttime_mean);
                return;
        }
 
@@ -2029,7 +2098,7 @@ cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 
        WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
 
-       return 2 * (base_rq + base_rq * (CFQ_PRIO_LISTS - 1 - cfqq->ioprio));
+       return 2 * base_rq * (IOPRIO_BE_NR - cfqq->ioprio);
 }
 
 /*
@@ -2704,8 +2773,11 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
        smp_wmb();
        cic->key = cfqd_dead_key(cfqd);
 
-       if (ioc->ioc_data == cic)
+       if (rcu_dereference(ioc->ioc_data) == cic) {
+               spin_lock(&ioc->lock);
                rcu_assign_pointer(ioc->ioc_data, NULL);
+               spin_unlock(&ioc->lock);
+       }
 
        if (cic->cfqq[BLK_RW_ASYNC]) {
                cfq_exit_cfqq(cfqd, cic->cfqq[BLK_RW_ASYNC]);
@@ -2911,7 +2983,7 @@ cfq_find_alloc_queue(struct cfq_data *cfqd, bool is_sync,
        struct cfq_group *cfqg;
 
 retry:
-       cfqg = cfq_get_cfqg(cfqd, 1);
+       cfqg = cfq_get_cfqg(cfqd);
        cic = cfq_cic_lookup(cfqd, ioc);
        /* cic always exists here */
        cfqq = cic_to_cfqq(cic, is_sync);
@@ -3718,9 +3790,6 @@ new_queue:
        return 0;
 
 queue_fail:
-       if (cic)
-               put_io_context(cic->ioc);
-
        cfq_schedule_dispatch(cfqd);
        spin_unlock_irqrestore(q->queue_lock, flags);
        cfq_log(cfqd, "set_request fail");
@@ -3815,15 +3884,11 @@ static void cfq_put_async_queues(struct cfq_data *cfqd)
                cfq_put_queue(cfqd->async_idle_cfqq);
 }
 
-static void cfq_cfqd_free(struct rcu_head *head)
-{
-       kfree(container_of(head, struct cfq_data, rcu));
-}
-
 static void cfq_exit_queue(struct elevator_queue *e)
 {
        struct cfq_data *cfqd = e->elevator_data;
        struct request_queue *q = cfqd->queue;
+       bool wait = false;
 
        cfq_shutdown_timer_wq(cfqd);
 
@@ -3842,7 +3907,13 @@ static void cfq_exit_queue(struct elevator_queue *e)
 
        cfq_put_async_queues(cfqd);
        cfq_release_cfq_groups(cfqd);
-       cfq_blkiocg_del_blkio_group(&cfqd->root_group.blkg);
+
+       /*
+        * If there are groups which we could not unlink from blkcg list,
+        * wait for a rcu period for them to be freed.
+        */
+       if (cfqd->nr_blkcg_linked_grps)
+               wait = true;
 
        spin_unlock_irq(q->queue_lock);
 
@@ -3852,8 +3923,25 @@ static void cfq_exit_queue(struct elevator_queue *e)
        ida_remove(&cic_index_ida, cfqd->cic_index);
        spin_unlock(&cic_index_lock);
 
-       /* Wait for cfqg->blkg->key accessors to exit their grace periods. */
-       call_rcu(&cfqd->rcu, cfq_cfqd_free);
+       /*
+        * Wait for cfqg->blkg->key accessors to exit their grace periods.
+        * Do this wait only if there are other unlinked groups out
+        * there. This can happen if cgroup deletion path claimed the
+        * responsibility of cleaning up a group before queue cleanup code
+        * get to the group.
+        *
+        * Do not call synchronize_rcu() unconditionally as there are drivers
+        * which create/delete request queue hundreds of times during scan/boot
+        * and synchronize_rcu() can take significant time and slow down boot.
+        */
+       if (wait)
+               synchronize_rcu();
+
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
+       /* Free up per cpu stats for root group */
+       free_percpu(cfqd->root_group.blkg.stats_cpu);
+#endif
+       kfree(cfqd);
 }
 
 static int cfq_alloc_cic_index(void)
@@ -3886,8 +3974,12 @@ static void *cfq_init_queue(struct request_queue *q)
                return NULL;
 
        cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node);
-       if (!cfqd)
+       if (!cfqd) {
+               spin_lock(&cic_index_lock);
+               ida_remove(&cic_index_ida, i);
+               spin_unlock(&cic_index_lock);
                return NULL;
+       }
 
        /*
         * Don't need take queue_lock in the routine, since we are
@@ -3909,14 +4001,29 @@ static void *cfq_init_queue(struct request_queue *q)
 
 #ifdef CONFIG_CFQ_GROUP_IOSCHED
        /*
-        * Take a reference to root group which we never drop. This is just
-        * to make sure that cfq_put_cfqg() does not try to kfree root group
+        * Set root group reference to 2. One reference will be dropped when
+        * all groups on cfqd->cfqg_list are being deleted during queue exit.
+        * Other reference will remain there as we don't want to delete this
+        * group as it is statically allocated and gets destroyed when
+        * throtl_data goes away.
         */
-       cfqg->ref = 1;
+       cfqg->ref = 2;
+
+       if (blkio_alloc_blkg_stats(&cfqg->blkg)) {
+               kfree(cfqg);
+               kfree(cfqd);
+               return NULL;
+       }
+
        rcu_read_lock();
+
        cfq_blkiocg_add_blkio_group(&blkio_root_cgroup, &cfqg->blkg,
                                        (void *)cfqd, 0);
        rcu_read_unlock();
+       cfqd->nr_blkcg_linked_grps++;
+
+       /* Add group on cfqd->cfqg_list */
+       hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list);
 #endif
        /*
         * Not strictly needed (since RB_ROOT just clears the node and we
index 45ca1e34f58249ff5b3838c0ec89fbc1c6ea2bb7..b0b38ce0dcb6ec4cca1cbf28454e834cf3f1073e 100644 (file)
@@ -155,13 +155,8 @@ static struct elevator_type *elevator_get(const char *name)
 
        e = elevator_find(name);
        if (!e) {
-               char elv[ELV_NAME_MAX + strlen("-iosched")];
-
                spin_unlock(&elv_list_lock);
-
-               snprintf(elv, sizeof(elv), "%s-iosched", name);
-
-               request_module("%s", elv);
+               request_module("%s-iosched", name);
                spin_lock(&elv_list_lock);
                e = elevator_find(name);
        }
@@ -421,8 +416,6 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq)
        struct list_head *entry;
        int stop_flags;
 
-       BUG_ON(rq->cmd_flags & REQ_ON_PLUG);
-
        if (q->last_merge == rq)
                q->last_merge = NULL;
 
@@ -661,8 +654,6 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where)
 
        rq->q = q;
 
-       BUG_ON(rq->cmd_flags & REQ_ON_PLUG);
-
        if (rq->cmd_flags & REQ_SOFTBARRIER) {
                /* barriers are scheduling boundary, update end_sector */
                if (rq->cmd_type == REQ_TYPE_FS ||
index 2dd988723d73e98880d271b84dc77ef36b49a0a9..3608289c8ecdc0c8506af62421ccaabbae38438b 100644 (file)
@@ -1371,6 +1371,7 @@ struct disk_events {
        struct gendisk          *disk;          /* the associated disk */
        spinlock_t              lock;
 
+       struct mutex            block_mutex;    /* protects blocking */
        int                     block;          /* event blocking depth */
        unsigned int            pending;        /* events already sent out */
        unsigned int            clearing;       /* events being cleared */
@@ -1414,22 +1415,44 @@ static unsigned long disk_events_poll_jiffies(struct gendisk *disk)
        return msecs_to_jiffies(intv_msecs);
 }
 
-static void __disk_block_events(struct gendisk *disk, bool sync)
+/**
+ * disk_block_events - block and flush disk event checking
+ * @disk: disk to block events for
+ *
+ * On return from this function, it is guaranteed that event checking
+ * isn't in progress and won't happen until unblocked by
+ * disk_unblock_events().  Events blocking is counted and the actual
+ * unblocking happens after the matching number of unblocks are done.
+ *
+ * Note that this intentionally does not block event checking from
+ * disk_clear_events().
+ *
+ * CONTEXT:
+ * Might sleep.
+ */
+void disk_block_events(struct gendisk *disk)
 {
        struct disk_events *ev = disk->ev;
        unsigned long flags;
        bool cancel;
 
+       if (!ev)
+               return;
+
+       /*
+        * Outer mutex ensures that the first blocker completes canceling
+        * the event work before further blockers are allowed to finish.
+        */
+       mutex_lock(&ev->block_mutex);
+
        spin_lock_irqsave(&ev->lock, flags);
        cancel = !ev->block++;
        spin_unlock_irqrestore(&ev->lock, flags);
 
-       if (cancel) {
-               if (sync)
-                       cancel_delayed_work_sync(&disk->ev->dwork);
-               else
-                       cancel_delayed_work(&disk->ev->dwork);
-       }
+       if (cancel)
+               cancel_delayed_work_sync(&disk->ev->dwork);
+
+       mutex_unlock(&ev->block_mutex);
 }
 
 static void __disk_unblock_events(struct gendisk *disk, bool check_now)
@@ -1460,27 +1483,6 @@ out_unlock:
        spin_unlock_irqrestore(&ev->lock, flags);
 }
 
-/**
- * disk_block_events - block and flush disk event checking
- * @disk: disk to block events for
- *
- * On return from this function, it is guaranteed that event checking
- * isn't in progress and won't happen until unblocked by
- * disk_unblock_events().  Events blocking is counted and the actual
- * unblocking happens after the matching number of unblocks are done.
- *
- * Note that this intentionally does not block event checking from
- * disk_clear_events().
- *
- * CONTEXT:
- * Might sleep.
- */
-void disk_block_events(struct gendisk *disk)
-{
-       if (disk->ev)
-               __disk_block_events(disk, true);
-}
-
 /**
  * disk_unblock_events - unblock disk event checking
  * @disk: disk to unblock events for
@@ -1508,10 +1510,18 @@ void disk_unblock_events(struct gendisk *disk)
  */
 void disk_check_events(struct gendisk *disk)
 {
-       if (disk->ev) {
-               __disk_block_events(disk, false);
-               __disk_unblock_events(disk, true);
+       struct disk_events *ev = disk->ev;
+       unsigned long flags;
+
+       if (!ev)
+               return;
+
+       spin_lock_irqsave(&ev->lock, flags);
+       if (!ev->block) {
+               cancel_delayed_work(&ev->dwork);
+               queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
        }
+       spin_unlock_irqrestore(&ev->lock, flags);
 }
 EXPORT_SYMBOL_GPL(disk_check_events);
 
@@ -1546,7 +1556,7 @@ unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
        spin_unlock_irq(&ev->lock);
 
        /* uncondtionally schedule event check and wait for it to finish */
-       __disk_block_events(disk, true);
+       disk_block_events(disk);
        queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
        flush_delayed_work(&ev->dwork);
        __disk_unblock_events(disk, false);
@@ -1664,7 +1674,7 @@ static ssize_t disk_events_poll_msecs_store(struct device *dev,
        if (intv < 0 && intv != -1)
                return -EINVAL;
 
-       __disk_block_events(disk, true);
+       disk_block_events(disk);
        disk->ev->poll_msecs = intv;
        __disk_unblock_events(disk, true);
 
@@ -1728,7 +1738,7 @@ static void disk_add_events(struct gendisk *disk)
 {
        struct disk_events *ev;
 
-       if (!disk->fops->check_events || !(disk->events | disk->async_events))
+       if (!disk->fops->check_events)
                return;
 
        ev = kzalloc(sizeof(*ev), GFP_KERNEL);
@@ -1750,6 +1760,7 @@ static void disk_add_events(struct gendisk *disk)
        INIT_LIST_HEAD(&ev->node);
        ev->disk = disk;
        spin_lock_init(&ev->lock);
+       mutex_init(&ev->block_mutex);
        ev->block = 1;
        ev->poll_msecs = -1;
        INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn);
@@ -1770,7 +1781,7 @@ static void disk_del_events(struct gendisk *disk)
        if (!disk->ev)
                return;
 
-       __disk_block_events(disk, true);
+       disk_block_events(disk);
 
        mutex_lock(&disk_events_mutex);
        list_del_init(&disk->ev->node);
index 61631edfecc208d611d1d93b6f069e440e2223bc..3bb154d8c8cc778713c28e0d335282cb715594a2 100644 (file)
@@ -54,6 +54,8 @@ source "drivers/spi/Kconfig"
 
 source "drivers/pps/Kconfig"
 
+source "drivers/ptp/Kconfig"
+
 source "drivers/gpio/Kconfig"
 
 source "drivers/w1/Kconfig"
index 145aeadb6c034d4e058ea782c64d90775879c20c..09f3232bcdcddd2ff2ce042cd0a7a977320356c4 100644 (file)
@@ -17,6 +17,9 @@ obj-$(CONFIG_SFI)             += sfi/
 # was used and do nothing if so
 obj-$(CONFIG_PNP)              += pnp/
 obj-$(CONFIG_ARM_AMBA)         += amba/
+# Many drivers will want to use DMA so this has to be made available
+# really early.
+obj-$(CONFIG_DMA_ENGINE)       += dma/
 
 obj-$(CONFIG_VIRTIO)           += virtio/
 obj-$(CONFIG_XEN)              += xen/
@@ -75,6 +78,7 @@ obj-$(CONFIG_I2O)             += message/
 obj-$(CONFIG_RTC_LIB)          += rtc/
 obj-y                          += i2c/ media/
 obj-$(CONFIG_PPS)              += pps/
+obj-$(CONFIG_PTP_1588_CLOCK)   += ptp/
 obj-$(CONFIG_W1)               += w1/
 obj-$(CONFIG_POWER_SUPPLY)     += power/
 obj-$(CONFIG_HWMON)            += hwmon/
@@ -91,10 +95,9 @@ obj-$(CONFIG_EISA)           += eisa/
 obj-y                          += lguest/
 obj-$(CONFIG_CPU_FREQ)         += cpufreq/
 obj-$(CONFIG_CPU_IDLE)         += cpuidle/
-obj-$(CONFIG_DMA_ENGINE)       += dma/
 obj-$(CONFIG_MMC)              += mmc/
 obj-$(CONFIG_MEMSTICK)         += memstick/
-obj-$(CONFIG_NEW_LEDS)         += leds/
+obj-y                          += leds/
 obj-$(CONFIG_INFINIBAND)       += infiniband/
 obj-$(CONFIG_SGI_SN)           += sn/
 obj-y                          += firmware/
index 3a17ca5fff6f022d207107ff741b6b22ba300190..de0e3df767762220a670aa640c47029ba72603ff 100644 (file)
@@ -73,17 +73,6 @@ config ACPI_PROCFS_POWER
 
          Say N to delete power /proc/acpi/ directories that have moved to /sys/
 
-config ACPI_POWER_METER
-       tristate "ACPI 4.0 power meter"
-       depends on HWMON
-       help
-         This driver exposes ACPI 4.0 power meters as hardware monitoring
-         devices.  Say Y (or M) if you have a computer with ACPI 4.0 firmware
-         and a power meter.
-
-         To compile this driver as a module, choose M here:
-         the module will be called power-meter.
-
 config ACPI_EC_DEBUGFS
        tristate "EC read/write access through /sys/kernel/debug/ec"
        default n
@@ -380,6 +369,21 @@ config ACPI_HED
          which is used to report some hardware errors notified via
          SCI, mainly the corrected errors.
 
+config ACPI_CUSTOM_METHOD
+       tristate "Allow ACPI methods to be inserted/replaced at run time"
+       depends on DEBUG_FS
+       default n
+       help
+         This debug facility allows ACPI AML methods to me inserted and/or
+         replaced without rebooting the system. For details refer to:
+         Documentation/acpi/method-customizing.txt.
+
+         NOTE: This option is security sensitive, because it allows arbitrary
+         kernel memory to be written to by root (uid=0) users, allowing them
+         to bypass certain security measures (e.g. if root is not allowed to
+         load additional kernel modules after boot, this feature may be used
+         to override that restriction).
+
 source "drivers/acpi/apei/Kconfig"
 
 endif  # ACPI
index d113fa5100b20331d8b52d548cb07fcf5f281885..ecb26b4f29a0581d697a26c69fa9b52532e0f327 100644 (file)
@@ -59,9 +59,9 @@ obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
 obj-$(CONFIG_ACPI_BATTERY)     += battery.o
 obj-$(CONFIG_ACPI_SBS)         += sbshc.o
 obj-$(CONFIG_ACPI_SBS)         += sbs.o
-obj-$(CONFIG_ACPI_POWER_METER) += power_meter.o
 obj-$(CONFIG_ACPI_HED)         += hed.o
 obj-$(CONFIG_ACPI_EC_DEBUGFS)  += ec_sys.o
+obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
 
 # processor has its own "processor." module_param namespace
 processor-y                    := processor_driver.o processor_throttling.o
index a1224712fd0c1abaab12a70e8f97237252380090..301bd2d388ad1dc7a6a00268ebbec4266470150a 100644 (file)
@@ -14,7 +14,7 @@ acpi-y := dsfield.o   dsmthdat.o  dsopcode.o  dswexec.o  dswscope.o \
 
 acpi-y += evevent.o  evregion.o  evsci.o    evxfevnt.o \
         evmisc.o   evrgnini.o  evxface.o  evxfregn.o \
-        evgpe.o    evgpeblk.o evgpeinit.o  evgpeutil.o evxfgpe.o
+        evgpe.o    evgpeblk.o evgpeinit.o  evgpeutil.o evxfgpe.o evglock.o
 
 acpi-y += exconfig.o  exfield.o  exnames.o   exoparg6.o  exresolv.o  exstorob.o\
         exconvrt.o  exfldio.o  exoparg1.o  exprep.o    exresop.o   exsystem.o\
index ab87396c2c07452c2f6b8485591103a6280d9b10..bc533dde16c47785d2c0321a173039eeede4e69b 100644 (file)
 
 /* Operation regions */
 
-#define ACPI_NUM_PREDEFINED_REGIONS     9
 #define ACPI_USER_REGION_BEGIN          0x80
 
 /* Maximum space_ids for Operation Regions */
index 41d247daf461bd63a8b6abe6e1974106d57b334b..bea3b4899183bae0fce0ecfa44238160d438a9d3 100644 (file)
@@ -58,18 +58,23 @@ u32 acpi_ev_fixed_event_detect(void);
  */
 u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node);
 
-acpi_status acpi_ev_acquire_global_lock(u16 timeout);
-
-acpi_status acpi_ev_release_global_lock(void);
-
-acpi_status acpi_ev_init_global_lock_handler(void);
-
 u32 acpi_ev_get_gpe_number_index(u32 gpe_number);
 
 acpi_status
 acpi_ev_queue_notify_request(struct acpi_namespace_node *node,
                             u32 notify_value);
 
+/*
+ * evglock - Global Lock support
+ */
+acpi_status acpi_ev_init_global_lock_handler(void);
+
+acpi_status acpi_ev_acquire_global_lock(u16 timeout);
+
+acpi_status acpi_ev_release_global_lock(void);
+
+acpi_status acpi_ev_remove_global_lock_handler(void);
+
 /*
  * evgpe - Low-level GPE support
  */
index d69750b83b365a236567815f723102b53a57ac80..73863d86f022c659506997f0496bac3f3673865b 100644 (file)
@@ -214,24 +214,23 @@ ACPI_EXTERN struct acpi_mutex_info acpi_gbl_mutex_info[ACPI_NUM_MUTEX];
 
 /*
  * Global lock mutex is an actual AML mutex object
- * Global lock semaphore works in conjunction with the HW global lock
+ * Global lock semaphore works in conjunction with the actual global lock
+ * Global lock spinlock is used for "pending" handshake
  */
 ACPI_EXTERN union acpi_operand_object *acpi_gbl_global_lock_mutex;
 ACPI_EXTERN acpi_semaphore acpi_gbl_global_lock_semaphore;
+ACPI_EXTERN acpi_spinlock acpi_gbl_global_lock_pending_lock;
 ACPI_EXTERN u16 acpi_gbl_global_lock_handle;
 ACPI_EXTERN u8 acpi_gbl_global_lock_acquired;
 ACPI_EXTERN u8 acpi_gbl_global_lock_present;
+ACPI_EXTERN u8 acpi_gbl_global_lock_pending;
 
 /*
  * Spinlocks are used for interfaces that can be possibly called at
  * interrupt level
  */
-ACPI_EXTERN spinlock_t _acpi_gbl_gpe_lock;     /* For GPE data structs and registers */
-ACPI_EXTERN spinlock_t _acpi_gbl_hardware_lock;        /* For ACPI H/W except GPE registers */
-ACPI_EXTERN spinlock_t _acpi_ev_global_lock_pending_lock; /* For global lock */
-#define acpi_gbl_gpe_lock      &_acpi_gbl_gpe_lock
-#define acpi_gbl_hardware_lock &_acpi_gbl_hardware_lock
-#define acpi_ev_global_lock_pending_lock &_acpi_ev_global_lock_pending_lock
+ACPI_EXTERN acpi_spinlock acpi_gbl_gpe_lock;   /* For GPE data structs and registers */
+ACPI_EXTERN acpi_spinlock acpi_gbl_hardware_lock;      /* For ACPI H/W except GPE registers */
 
 /*****************************************************************************
  *
index f4f0998d3967ef86511de9b06adf37b6dcaa990f..1077f17859ed3d3fb74d2280966b2a847025e424 100644 (file)
 #define AML_CLASS_METHOD_CALL       0x09
 #define AML_CLASS_UNKNOWN           0x0A
 
-/* Predefined Operation Region space_iDs */
-
-typedef enum {
-       REGION_MEMORY = 0,
-       REGION_IO,
-       REGION_PCI_CONFIG,
-       REGION_EC,
-       REGION_SMBUS,
-       REGION_CMOS,
-       REGION_PCI_BAR,
-       REGION_IPMI,
-       REGION_DATA_TABLE,      /* Internal use only */
-       REGION_FIXED_HW = 0x7F
-} AML_REGION_TYPES;
-
 /* Comparison operation codes for match_op operator */
 
 typedef enum {
index 23a3b1ab20c1c0ec0cc62cdbc5419c77da6fcb8f..324acec1179abaef80d5bb6fdbbd50e2f4106469 100644 (file)
@@ -450,7 +450,7 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state)
                        status =
                            acpi_ex_create_region(op->named.data,
                                                  op->named.length,
-                                                 REGION_DATA_TABLE,
+                                                 ACPI_ADR_SPACE_DATA_TABLE,
                                                  walk_state);
                        if (ACPI_FAILURE(status)) {
                                return_ACPI_STATUS(status);
index 4be4e921dfe1b0bc7b79c81335a78aac1f4a3b67..976318138c56aa983f74f3786f4016040354d44c 100644 (file)
@@ -562,7 +562,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
                                    ((op->common.value.arg)->common.value.
                                     integer);
                        } else {
-                               region_space = REGION_DATA_TABLE;
+                               region_space = ACPI_ADR_SPACE_DATA_TABLE;
                        }
 
                        /*
diff --git a/drivers/acpi/acpica/evglock.c b/drivers/acpi/acpica/evglock.c
new file mode 100644 (file)
index 0000000..56a562a
--- /dev/null
@@ -0,0 +1,335 @@
+/******************************************************************************
+ *
+ * Module Name: evglock - Global Lock support
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2011, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acevents.h"
+#include "acinterp.h"
+
+#define _COMPONENT          ACPI_EVENTS
+ACPI_MODULE_NAME("evglock")
+
+/* Local prototypes */
+static u32 acpi_ev_global_lock_handler(void *context);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_init_global_lock_handler
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Install a handler for the global lock release event
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ev_init_global_lock_handler(void)
+{
+       acpi_status status;
+
+       ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
+
+       /* Attempt installation of the global lock handler */
+
+       status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL,
+                                                 acpi_ev_global_lock_handler,
+                                                 NULL);
+
+       /*
+        * If the global lock does not exist on this platform, the attempt to
+        * enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick).
+        * Map to AE_OK, but mark global lock as not present. Any attempt to
+        * actually use the global lock will be flagged with an error.
+        */
+       acpi_gbl_global_lock_present = FALSE;
+       if (status == AE_NO_HARDWARE_RESPONSE) {
+               ACPI_ERROR((AE_INFO,
+                           "No response from Global Lock hardware, disabling lock"));
+
+               return_ACPI_STATUS(AE_OK);
+       }
+
+       status = acpi_os_create_lock(&acpi_gbl_global_lock_pending_lock);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
+       acpi_gbl_global_lock_pending = FALSE;
+       acpi_gbl_global_lock_present = TRUE;
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_remove_global_lock_handler
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Remove the handler for the Global Lock
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ev_remove_global_lock_handler(void)
+{
+       acpi_status status;
+
+       ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler);
+
+       acpi_gbl_global_lock_present = FALSE;
+       status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL,
+                                                acpi_ev_global_lock_handler);
+
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_global_lock_handler
+ *
+ * PARAMETERS:  Context         - From thread interface, not used
+ *
+ * RETURN:      ACPI_INTERRUPT_HANDLED
+ *
+ * DESCRIPTION: Invoked directly from the SCI handler when a global lock
+ *              release interrupt occurs. If there is actually a pending
+ *              request for the lock, signal the waiting thread.
+ *
+ ******************************************************************************/
+
+static u32 acpi_ev_global_lock_handler(void *context)
+{
+       acpi_status status;
+       acpi_cpu_flags flags;
+
+       flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);
+
+       /*
+        * If a request for the global lock is not actually pending,
+        * we are done. This handles "spurious" global lock interrupts
+        * which are possible (and have been seen) with bad BIOSs.
+        */
+       if (!acpi_gbl_global_lock_pending) {
+               goto cleanup_and_exit;
+       }
+
+       /*
+        * Send a unit to the global lock semaphore. The actual acquisition
+        * of the global lock will be performed by the waiting thread.
+        */
+       status = acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, 1);
+       if (ACPI_FAILURE(status)) {
+               ACPI_ERROR((AE_INFO, "Could not signal Global Lock semaphore"));
+       }
+
+       acpi_gbl_global_lock_pending = FALSE;
+
+      cleanup_and_exit:
+
+       acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);
+       return (ACPI_INTERRUPT_HANDLED);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_acquire_global_lock
+ *
+ * PARAMETERS:  Timeout         - Max time to wait for the lock, in millisec.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Attempt to gain ownership of the Global Lock.
+ *
+ * MUTEX:       Interpreter must be locked
+ *
+ * Note: The original implementation allowed multiple threads to "acquire" the
+ * Global Lock, and the OS would hold the lock until the last thread had
+ * released it. However, this could potentially starve the BIOS out of the
+ * lock, especially in the case where there is a tight handshake between the
+ * Embedded Controller driver and the BIOS. Therefore, this implementation
+ * allows only one thread to acquire the HW Global Lock at a time, and makes
+ * the global lock appear as a standard mutex on the OS side.
+ *
+ *****************************************************************************/
+
+acpi_status acpi_ev_acquire_global_lock(u16 timeout)
+{
+       acpi_cpu_flags flags;
+       acpi_status status;
+       u8 acquired = FALSE;
+
+       ACPI_FUNCTION_TRACE(ev_acquire_global_lock);
+
+       /*
+        * Only one thread can acquire the GL at a time, the global_lock_mutex
+        * enforces this. This interface releases the interpreter if we must wait.
+        */
+       status =
+           acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex->mutex.
+                                     os_mutex, timeout);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
+       /*
+        * Update the global lock handle and check for wraparound. The handle is
+        * only used for the external global lock interfaces, but it is updated
+        * here to properly handle the case where a single thread may acquire the
+        * lock via both the AML and the acpi_acquire_global_lock interfaces. The
+        * handle is therefore updated on the first acquire from a given thread
+        * regardless of where the acquisition request originated.
+        */
+       acpi_gbl_global_lock_handle++;
+       if (acpi_gbl_global_lock_handle == 0) {
+               acpi_gbl_global_lock_handle = 1;
+       }
+
+       /*
+        * Make sure that a global lock actually exists. If not, just
+        * treat the lock as a standard mutex.
+        */
+       if (!acpi_gbl_global_lock_present) {
+               acpi_gbl_global_lock_acquired = TRUE;
+               return_ACPI_STATUS(AE_OK);
+       }
+
+       flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);
+
+       do {
+
+               /* Attempt to acquire the actual hardware lock */
+
+               ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
+               if (acquired) {
+                       acpi_gbl_global_lock_acquired = TRUE;
+                       ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+                                         "Acquired hardware Global Lock\n"));
+                       break;
+               }
+
+               /*
+                * Did not get the lock. The pending bit was set above, and
+                * we must now wait until we receive the global lock
+                * released interrupt.
+                */
+               acpi_gbl_global_lock_pending = TRUE;
+               acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);
+
+               ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+                                 "Waiting for hardware Global Lock\n"));
+
+               /*
+                * Wait for handshake with the global lock interrupt handler.
+                * This interface releases the interpreter if we must wait.
+                */
+               status =
+                   acpi_ex_system_wait_semaphore
+                   (acpi_gbl_global_lock_semaphore, ACPI_WAIT_FOREVER);
+
+               flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);
+
+       } while (ACPI_SUCCESS(status));
+
+       acpi_gbl_global_lock_pending = FALSE;
+       acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);
+
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_release_global_lock
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Releases ownership of the Global Lock.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ev_release_global_lock(void)
+{
+       u8 pending = FALSE;
+       acpi_status status = AE_OK;
+
+       ACPI_FUNCTION_TRACE(ev_release_global_lock);
+
+       /* Lock must be already acquired */
+
+       if (!acpi_gbl_global_lock_acquired) {
+               ACPI_WARNING((AE_INFO,
+                             "Cannot release the ACPI Global Lock, it has not been acquired"));
+               return_ACPI_STATUS(AE_NOT_ACQUIRED);
+       }
+
+       if (acpi_gbl_global_lock_present) {
+
+               /* Allow any thread to release the lock */
+
+               ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_FACS, pending);
+
+               /*
+                * If the pending bit was set, we must write GBL_RLS to the control
+                * register
+                */
+               if (pending) {
+                       status =
+                           acpi_write_bit_register
+                           (ACPI_BITREG_GLOBAL_LOCK_RELEASE,
+                            ACPI_ENABLE_EVENT);
+               }
+
+               ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+                                 "Released hardware Global Lock\n"));
+       }
+
+       acpi_gbl_global_lock_acquired = FALSE;
+
+       /* Release the local GL mutex */
+
+       acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex);
+       return_ACPI_STATUS(status);
+}
index 7dc80946f7bd3c0f10a09fb35b38d44f3f23d651..d0b3318444273977a382afb74ffcc5a0ed2ddb65 100644 (file)
@@ -45,7 +45,6 @@
 #include "accommon.h"
 #include "acevents.h"
 #include "acnamesp.h"
-#include "acinterp.h"
 
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evmisc")
@@ -53,10 +52,6 @@ ACPI_MODULE_NAME("evmisc")
 /* Local prototypes */
 static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context);
 
-static u32 acpi_ev_global_lock_handler(void *context);
-
-static acpi_status acpi_ev_remove_global_lock_handler(void);
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ev_is_notify_object
@@ -275,304 +270,6 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
        acpi_ut_delete_generic_state(notify_info);
 }
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ev_global_lock_handler
- *
- * PARAMETERS:  Context         - From thread interface, not used
- *
- * RETURN:      ACPI_INTERRUPT_HANDLED
- *
- * DESCRIPTION: Invoked directly from the SCI handler when a global lock
- *              release interrupt occurs.  If there's a thread waiting for
- *              the global lock, signal it.
- *
- * NOTE: Assumes that the semaphore can be signaled from interrupt level. If
- * this is not possible for some reason, a separate thread will have to be
- * scheduled to do this.
- *
- ******************************************************************************/
-static u8 acpi_ev_global_lock_pending;
-
-static u32 acpi_ev_global_lock_handler(void *context)
-{
-       acpi_status status;
-       acpi_cpu_flags flags;
-
-       flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock);
-
-       if (!acpi_ev_global_lock_pending) {
-               goto out;
-       }
-
-       /* Send a unit to the semaphore */
-
-       status = acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, 1);
-       if (ACPI_FAILURE(status)) {
-               ACPI_ERROR((AE_INFO, "Could not signal Global Lock semaphore"));
-       }
-
-       acpi_ev_global_lock_pending = FALSE;
-
- out:
-       acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags);
-
-       return (ACPI_INTERRUPT_HANDLED);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ev_init_global_lock_handler
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Install a handler for the global lock release event
- *
- ******************************************************************************/
-
-acpi_status acpi_ev_init_global_lock_handler(void)
-{
-       acpi_status status;
-
-       ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
-
-       /* Attempt installation of the global lock handler */
-
-       status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL,
-                                                 acpi_ev_global_lock_handler,
-                                                 NULL);
-
-       /*
-        * If the global lock does not exist on this platform, the attempt to
-        * enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick).
-        * Map to AE_OK, but mark global lock as not present. Any attempt to
-        * actually use the global lock will be flagged with an error.
-        */
-       if (status == AE_NO_HARDWARE_RESPONSE) {
-               ACPI_ERROR((AE_INFO,
-                           "No response from Global Lock hardware, disabling lock"));
-
-               acpi_gbl_global_lock_present = FALSE;
-               return_ACPI_STATUS(AE_OK);
-       }
-
-       acpi_gbl_global_lock_present = TRUE;
-       return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ev_remove_global_lock_handler
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Remove the handler for the Global Lock
- *
- ******************************************************************************/
-
-static acpi_status acpi_ev_remove_global_lock_handler(void)
-{
-       acpi_status status;
-
-       ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler);
-
-       acpi_gbl_global_lock_present = FALSE;
-       status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL,
-                                                acpi_ev_global_lock_handler);
-
-       return_ACPI_STATUS(status);
-}
-
-/******************************************************************************
- *
- * FUNCTION:    acpi_ev_acquire_global_lock
- *
- * PARAMETERS:  Timeout         - Max time to wait for the lock, in millisec.
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Attempt to gain ownership of the Global Lock.
- *
- * MUTEX:       Interpreter must be locked
- *
- * Note: The original implementation allowed multiple threads to "acquire" the
- * Global Lock, and the OS would hold the lock until the last thread had
- * released it. However, this could potentially starve the BIOS out of the
- * lock, especially in the case where there is a tight handshake between the
- * Embedded Controller driver and the BIOS. Therefore, this implementation
- * allows only one thread to acquire the HW Global Lock at a time, and makes
- * the global lock appear as a standard mutex on the OS side.
- *
- *****************************************************************************/
-static acpi_thread_id acpi_ev_global_lock_thread_id;
-static int acpi_ev_global_lock_acquired;
-
-acpi_status acpi_ev_acquire_global_lock(u16 timeout)
-{
-       acpi_cpu_flags flags;
-       acpi_status status = AE_OK;
-       u8 acquired = FALSE;
-
-       ACPI_FUNCTION_TRACE(ev_acquire_global_lock);
-
-       /*
-        * Only one thread can acquire the GL at a time, the global_lock_mutex
-        * enforces this. This interface releases the interpreter if we must wait.
-        */
-       status = acpi_ex_system_wait_mutex(
-                       acpi_gbl_global_lock_mutex->mutex.os_mutex, 0);
-       if (status == AE_TIME) {
-               if (acpi_ev_global_lock_thread_id == acpi_os_get_thread_id()) {
-                       acpi_ev_global_lock_acquired++;
-                       return AE_OK;
-               }
-       }
-
-       if (ACPI_FAILURE(status)) {
-               status = acpi_ex_system_wait_mutex(
-                               acpi_gbl_global_lock_mutex->mutex.os_mutex,
-                               timeout);
-       }
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
-       acpi_ev_global_lock_thread_id = acpi_os_get_thread_id();
-       acpi_ev_global_lock_acquired++;
-
-       /*
-        * Update the global lock handle and check for wraparound. The handle is
-        * only used for the external global lock interfaces, but it is updated
-        * here to properly handle the case where a single thread may acquire the
-        * lock via both the AML and the acpi_acquire_global_lock interfaces. The
-        * handle is therefore updated on the first acquire from a given thread
-        * regardless of where the acquisition request originated.
-        */
-       acpi_gbl_global_lock_handle++;
-       if (acpi_gbl_global_lock_handle == 0) {
-               acpi_gbl_global_lock_handle = 1;
-       }
-
-       /*
-        * Make sure that a global lock actually exists. If not, just treat the
-        * lock as a standard mutex.
-        */
-       if (!acpi_gbl_global_lock_present) {
-               acpi_gbl_global_lock_acquired = TRUE;
-               return_ACPI_STATUS(AE_OK);
-       }
-
-       flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock);
-
-       do {
-
-               /* Attempt to acquire the actual hardware lock */
-
-               ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
-               if (acquired) {
-                       acpi_gbl_global_lock_acquired = TRUE;
-
-                       ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-                                         "Acquired hardware Global Lock\n"));
-                       break;
-               }
-
-               acpi_ev_global_lock_pending = TRUE;
-
-               acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags);
-
-               /*
-                * Did not get the lock. The pending bit was set above, and we
-                * must wait until we get the global lock released interrupt.
-                */
-               ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-                                 "Waiting for hardware Global Lock\n"));
-
-               /*
-                * Wait for handshake with the global lock interrupt handler.
-                * This interface releases the interpreter if we must wait.
-                */
-               status = acpi_ex_system_wait_semaphore(
-                                               acpi_gbl_global_lock_semaphore,
-                                               ACPI_WAIT_FOREVER);
-
-               flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock);
-
-       } while (ACPI_SUCCESS(status));
-
-       acpi_ev_global_lock_pending = FALSE;
-
-       acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags);
-
-       return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ev_release_global_lock
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Releases ownership of the Global Lock.
- *
- ******************************************************************************/
-
-acpi_status acpi_ev_release_global_lock(void)
-{
-       u8 pending = FALSE;
-       acpi_status status = AE_OK;
-
-       ACPI_FUNCTION_TRACE(ev_release_global_lock);
-
-       /* Lock must be already acquired */
-
-       if (!acpi_gbl_global_lock_acquired) {
-               ACPI_WARNING((AE_INFO,
-                             "Cannot release the ACPI Global Lock, it has not been acquired"));
-               return_ACPI_STATUS(AE_NOT_ACQUIRED);
-       }
-
-       acpi_ev_global_lock_acquired--;
-       if (acpi_ev_global_lock_acquired > 0) {
-               return AE_OK;
-       }
-
-       if (acpi_gbl_global_lock_present) {
-
-               /* Allow any thread to release the lock */
-
-               ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_FACS, pending);
-
-               /*
-                * If the pending bit was set, we must write GBL_RLS to the control
-                * register
-                */
-               if (pending) {
-                       status =
-                           acpi_write_bit_register
-                           (ACPI_BITREG_GLOBAL_LOCK_RELEASE,
-                            ACPI_ENABLE_EVENT);
-               }
-
-               ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-                                 "Released hardware Global Lock\n"));
-       }
-
-       acpi_gbl_global_lock_acquired = FALSE;
-
-       /* Release the local GL mutex */
-       acpi_ev_global_lock_thread_id = 0;
-       acpi_ev_global_lock_acquired = 0;
-       acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex);
-       return_ACPI_STATUS(status);
-}
-
 /******************************************************************************
  *
  * FUNCTION:    acpi_ev_terminate
index bea7223d7a710558d40a1c774a1760bd38670940..f0edf5c43c035f0da64345ffe30894099beecc2d 100644 (file)
@@ -55,6 +55,8 @@ static u8
 acpi_ev_has_default_handler(struct acpi_namespace_node *node,
                            acpi_adr_space_type space_id);
 
+static void acpi_ev_orphan_ec_reg_method(void);
+
 static acpi_status
 acpi_ev_reg_run(acpi_handle obj_handle,
                u32 level, void *context, void **return_value);
@@ -561,7 +563,9 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
 
                        /* Now stop region accesses by executing the _REG method */
 
-                       status = acpi_ev_execute_reg_method(region_obj, 0);
+                       status =
+                           acpi_ev_execute_reg_method(region_obj,
+                                                      ACPI_REG_DISCONNECT);
                        if (ACPI_FAILURE(status)) {
                                ACPI_EXCEPTION((AE_INFO, status,
                                                "from region _REG, [%s]",
@@ -1062,6 +1066,12 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
                                        ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run,
                                        NULL, &space_id, NULL);
 
+       /* Special case for EC: handle "orphan" _REG methods with no region */
+
+       if (space_id == ACPI_ADR_SPACE_EC) {
+               acpi_ev_orphan_ec_reg_method();
+       }
+
        return_ACPI_STATUS(status);
 }
 
@@ -1120,6 +1130,113 @@ acpi_ev_reg_run(acpi_handle obj_handle,
                return (AE_OK);
        }
 
-       status = acpi_ev_execute_reg_method(obj_desc, 1);
+       status = acpi_ev_execute_reg_method(obj_desc, ACPI_REG_CONNECT);
        return (status);
 }
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_orphan_ec_reg_method
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Execute an "orphan" _REG method that appears under the EC
+ *              device. This is a _REG method that has no corresponding region
+ *              within the EC device scope. The orphan _REG method appears to
+ *              have been enabled by the description of the ECDT in the ACPI
+ *              specification: "The availability of the region space can be
+ *              detected by providing a _REG method object underneath the
+ *              Embedded Controller device."
+ *
+ *              To quickly access the EC device, we use the EC_ID that appears
+ *              within the ECDT. Otherwise, we would need to perform a time-
+ *              consuming namespace walk, executing _HID methods to find the
+ *              EC device.
+ *
+ ******************************************************************************/
+
+static void acpi_ev_orphan_ec_reg_method(void)
+{
+       struct acpi_table_ecdt *table;
+       acpi_status status;
+       struct acpi_object_list args;
+       union acpi_object objects[2];
+       struct acpi_namespace_node *ec_device_node;
+       struct acpi_namespace_node *reg_method;
+       struct acpi_namespace_node *next_node;
+
+       ACPI_FUNCTION_TRACE(ev_orphan_ec_reg_method);
+
+       /* Get the ECDT (if present in system) */
+
+       status = acpi_get_table(ACPI_SIG_ECDT, 0,
+                               ACPI_CAST_INDIRECT_PTR(struct acpi_table_header,
+                                                      &table));
+       if (ACPI_FAILURE(status)) {
+               return_VOID;
+       }
+
+       /* We need a valid EC_ID string */
+
+       if (!(*table->id)) {
+               return_VOID;
+       }
+
+       /* Namespace is currently locked, must release */
+
+       (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+
+       /* Get a handle to the EC device referenced in the ECDT */
+
+       status = acpi_get_handle(NULL,
+                                ACPI_CAST_PTR(char, table->id),
+                                ACPI_CAST_PTR(acpi_handle, &ec_device_node));
+       if (ACPI_FAILURE(status)) {
+               goto exit;
+       }
+
+       /* Get a handle to a _REG method immediately under the EC device */
+
+       status = acpi_get_handle(ec_device_node,
+                                METHOD_NAME__REG, ACPI_CAST_PTR(acpi_handle,
+                                                                &reg_method));
+       if (ACPI_FAILURE(status)) {
+               goto exit;
+       }
+
+       /*
+        * Execute the _REG method only if there is no Operation Region in
+        * this scope with the Embedded Controller space ID. Otherwise, it
+        * will already have been executed. Note, this allows for Regions
+        * with other space IDs to be present; but the code below will then
+        * execute the _REG method with the EC space ID argument.
+        */
+       next_node = acpi_ns_get_next_node(ec_device_node, NULL);
+       while (next_node) {
+               if ((next_node->type == ACPI_TYPE_REGION) &&
+                   (next_node->object) &&
+                   (next_node->object->region.space_id == ACPI_ADR_SPACE_EC)) {
+                       goto exit;      /* Do not execute _REG */
+               }
+               next_node = acpi_ns_get_next_node(ec_device_node, next_node);
+       }
+
+       /* Evaluate the _REG(EC,Connect) method */
+
+       args.count = 2;
+       args.pointer = objects;
+       objects[0].type = ACPI_TYPE_INTEGER;
+       objects[0].integer.value = ACPI_ADR_SPACE_EC;
+       objects[1].type = ACPI_TYPE_INTEGER;
+       objects[1].integer.value = ACPI_REG_CONNECT;
+
+       status = acpi_evaluate_object(reg_method, NULL, &args, NULL);
+
+      exit:
+       /* We ignore all errors from above, don't care */
+
+       status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+       return_VOID;
+}
index 9659cee6093e3f835caf4a082680d95f12bca97d..55a5d35ef34a0d2f85e86020b96d305dd25b356f 100644 (file)
@@ -637,7 +637,7 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
 
                                        status =
                                            acpi_ev_execute_reg_method
-                                           (region_obj, 1);
+                                           (region_obj, ACPI_REG_CONNECT);
 
                                        if (acpi_ns_locked) {
                                                status =
index c85c8c45599d9242134503cdcde2998e39492f2e..00cd95692a91df8af9535bdba3032fce17f0309a 100644 (file)
@@ -130,20 +130,21 @@ acpi_install_address_space_handler(acpi_handle device,
        case ACPI_ADR_SPACE_PCI_CONFIG:
        case ACPI_ADR_SPACE_DATA_TABLE:
 
-               if (acpi_gbl_reg_methods_executed) {
+               if (!acpi_gbl_reg_methods_executed) {
 
-                       /* Run all _REG methods for this address space */
-
-                       status = acpi_ev_execute_reg_methods(node, space_id);
+                       /* We will defer execution of the _REG methods for this space */
+                       goto unlock_and_exit;
                }
                break;
 
        default:
-
-               status = acpi_ev_execute_reg_methods(node, space_id);
                break;
        }
 
+       /* Run all _REG methods for this address space */
+
+       status = acpi_ev_execute_reg_methods(node, space_id);
+
       unlock_and_exit:
        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
        return_ACPI_STATUS(status);
index e7b372d176671e02383788e31f8a3490aa1debc9..110711afada8be5c0b769c693c6fd3b624251ef4 100644 (file)
@@ -305,7 +305,8 @@ acpi_ex_create_region(u8 * aml_start,
         * range
         */
        if ((region_space >= ACPI_NUM_PREDEFINED_REGIONS) &&
-           (region_space < ACPI_USER_REGION_BEGIN)) {
+           (region_space < ACPI_USER_REGION_BEGIN) &&
+           (region_space != ACPI_ADR_SPACE_DATA_TABLE)) {
                ACPI_ERROR((AE_INFO, "Invalid AddressSpace type 0x%X",
                            region_space));
                return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
index 1d76ac85b5e79fdd9c1c41573a92ddf78686aeab..ac7b854b0bd740fb16ee73c6f5df978d79952900 100644 (file)
@@ -74,7 +74,6 @@ ACPI_MODULE_NAME("nsrepair")
  *
  * Additional possible repairs:
  *
- * Optional/unnecessary NULL package elements removed
  * Required package elements that are NULL replaced by Integer/String/Buffer
  * Incorrect standalone package wrapped with required outer package
  *
@@ -623,16 +622,12 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
        ACPI_FUNCTION_NAME(ns_remove_null_elements);
 
        /*
-        * PTYPE1 packages contain no subpackages.
-        * PTYPE2 packages contain a variable number of sub-packages. We can
-        * safely remove all NULL elements from the PTYPE2 packages.
+        * We can safely remove all NULL elements from these package types:
+        * PTYPE1_VAR packages contain a variable number of simple data types.
+        * PTYPE2 packages contain a variable number of sub-packages.
         */
        switch (package_type) {
-       case ACPI_PTYPE1_FIXED:
        case ACPI_PTYPE1_VAR:
-       case ACPI_PTYPE1_OPTION:
-               return;
-
        case ACPI_PTYPE2:
        case ACPI_PTYPE2_COUNT:
        case ACPI_PTYPE2_PKG_COUNT:
@@ -642,6 +637,8 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
                break;
 
        default:
+       case ACPI_PTYPE1_FIXED:
+       case ACPI_PTYPE1_OPTION:
                return;
        }
 
index 136a814cec69d15857856158760560499ccd4207..97cb36f85ce9d4e98f8e5576df9a4d70a049aeb6 100644 (file)
@@ -170,8 +170,7 @@ const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = {
        "SMBus",
        "SystemCMOS",
        "PCIBARTarget",
-       "IPMI",
-       "DataTable"
+       "IPMI"
 };
 
 char *acpi_ut_get_region_name(u8 space_id)
@@ -179,6 +178,8 @@ char *acpi_ut_get_region_name(u8 space_id)
 
        if (space_id >= ACPI_USER_REGION_BEGIN) {
                return ("UserDefinedRegion");
+       } else if (space_id == ACPI_ADR_SPACE_DATA_TABLE) {
+               return ("DataTable");
        } else if (space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
                return ("FunctionalFixedHW");
        } else if (space_id >= ACPI_NUM_PREDEFINED_REGIONS) {
index a946c689f03b164b5ab7131fe6506a6958553801..7d797e2baecd11996ae49525bc99e79f1fbbd5e9 100644 (file)
@@ -83,9 +83,15 @@ acpi_status acpi_ut_mutex_initialize(void)
 
        /* Create the spinlocks for use at interrupt level */
 
-       spin_lock_init(acpi_gbl_gpe_lock);
-       spin_lock_init(acpi_gbl_hardware_lock);
-       spin_lock_init(acpi_ev_global_lock_pending_lock);
+       status = acpi_os_create_lock (&acpi_gbl_gpe_lock);
+       if (ACPI_FAILURE (status)) {
+               return_ACPI_STATUS (status);
+       }
+
+       status = acpi_os_create_lock (&acpi_gbl_hardware_lock);
+       if (ACPI_FAILURE (status)) {
+               return_ACPI_STATUS (status);
+       }
 
        /* Mutex for _OSI support */
        status = acpi_os_create_mutex(&acpi_gbl_osi_mutex);
index 096aebfe7f325aae2e39cb36c9537a53a61b3bae..f74b2ea11f21128dc9c0beff600f18a57d7fbea0 100644 (file)
@@ -101,6 +101,14 @@ static DEFINE_MUTEX(einj_mutex);
 
 static struct einj_parameter *einj_param;
 
+#ifndef writeq
+static inline void writeq(__u64 val, volatile void __iomem *addr)
+{
+       writel(val, addr);
+       writel(val >> 32, addr+4);
+}
+#endif
+
 static void einj_exec_ctx_init(struct apei_exec_context *ctx)
 {
        apei_exec_ctx_init(ctx, einj_ins_type, ARRAY_SIZE(einj_ins_type),
index 542e5390389120de7ecd7da4cb7bd059baa18b01..7489b89c300fc3b0ab2f0a55c2bc09ead5e2c738 100644 (file)
@@ -280,9 +280,11 @@ static int acpi_atomic_read_mem(u64 paddr, u64 *val, u32 width)
        case 32:
                *val = readl(addr);
                break;
+#ifdef readq
        case 64:
                *val = readq(addr);
                break;
+#endif
        default:
                return -EINVAL;
        }
@@ -307,9 +309,11 @@ static int acpi_atomic_write_mem(u64 paddr, u64 val, u32 width)
        case 32:
                writel(val, addr);
                break;
+#ifdef writeq
        case 64:
                writeq(val, addr);
                break;
+#endif
        default:
                return -EINVAL;
        }
index 9749980ca6ca6c7669aa8c669a1102b881a2929f..d1e06c182cdba8ee46d404dc7cdb95571e9fe893 100644 (file)
@@ -227,7 +227,7 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state)
        acpi_status status = AE_OK;
        char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' };
 
-       if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
+       if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
                return -EINVAL;
 
        /* Make sure this is a valid target state */
diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c
new file mode 100644 (file)
index 0000000..5d42c24
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * debugfs.c - ACPI debugfs interface to userspace.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <acpi/acpi_drivers.h>
+
+#include "internal.h"
+
+#define _COMPONENT             ACPI_SYSTEM_COMPONENT
+ACPI_MODULE_NAME("custom_method");
+MODULE_LICENSE("GPL");
+
+static struct dentry *cm_dentry;
+
+/* /sys/kernel/debug/acpi/custom_method */
+
+static ssize_t cm_write(struct file *file, const char __user * user_buf,
+                       size_t count, loff_t *ppos)
+{
+       static char *buf;
+       static u32 max_size;
+       static u32 uncopied_bytes;
+
+       struct acpi_table_header table;
+       acpi_status status;
+
+       if (!(*ppos)) {
+               /* parse the table header to get the table length */
+               if (count <= sizeof(struct acpi_table_header))
+                       return -EINVAL;
+               if (copy_from_user(&table, user_buf,
+                                  sizeof(struct acpi_table_header)))
+                       return -EFAULT;
+               uncopied_bytes = max_size = table.length;
+               buf = kzalloc(max_size, GFP_KERNEL);
+               if (!buf)
+                       return -ENOMEM;
+       }
+
+       if (buf == NULL)
+               return -EINVAL;
+
+       if ((*ppos > max_size) ||
+           (*ppos + count > max_size) ||
+           (*ppos + count < count) ||
+           (count > uncopied_bytes))
+               return -EINVAL;
+
+       if (copy_from_user(buf + (*ppos), user_buf, count)) {
+               kfree(buf);
+               buf = NULL;
+               return -EFAULT;
+       }
+
+       uncopied_bytes -= count;
+       *ppos += count;
+
+       if (!uncopied_bytes) {
+               status = acpi_install_method(buf);
+               kfree(buf);
+               buf = NULL;
+               if (ACPI_FAILURE(status))
+                       return -EINVAL;
+               add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
+       }
+
+       return count;
+}
+
+static const struct file_operations cm_fops = {
+       .write = cm_write,
+       .llseek = default_llseek,
+};
+
+static int __init acpi_custom_method_init(void)
+{
+       if (acpi_debugfs_dir == NULL)
+               return -ENOENT;
+
+       cm_dentry = debugfs_create_file("custom_method", S_IWUSR,
+                                       acpi_debugfs_dir, NULL, &cm_fops);
+       if (cm_dentry == NULL)
+               return -ENODEV;
+
+       return 0;
+}
+
+static void __exit acpi_custom_method_exit(void)
+{
+       if (cm_dentry)
+               debugfs_remove(cm_dentry);
+ }
+
+module_init(acpi_custom_method_init);
+module_exit(acpi_custom_method_exit);
index 384f7abcff77984fb67c21c34b462761bc8f611e..182a9fc363553d5ef7372ad253fe06b449c0da96 100644 (file)
  */
 
 #include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/uaccess.h>
 #include <linux/debugfs.h>
 #include <acpi/acpi_drivers.h>
 
 #define _COMPONENT             ACPI_SYSTEM_COMPONENT
 ACPI_MODULE_NAME("debugfs");
 
+struct dentry *acpi_debugfs_dir;
+EXPORT_SYMBOL_GPL(acpi_debugfs_dir);
 
-/* /sys/modules/acpi/parameters/aml_debug_output */
-
-module_param_named(aml_debug_output, acpi_gbl_enable_aml_debug_object,
-                  bool, 0644);
-MODULE_PARM_DESC(aml_debug_output,
-                "To enable/disable the ACPI Debug Object output.");
-
-/* /sys/kernel/debug/acpi/custom_method */
-
-static ssize_t cm_write(struct file *file, const char __user * user_buf,
-                       size_t count, loff_t *ppos)
+void __init acpi_debugfs_init(void)
 {
-       static char *buf;
-       static u32 max_size;
-       static u32 uncopied_bytes;
-
-       struct acpi_table_header table;
-       acpi_status status;
-
-       if (!(*ppos)) {
-               /* parse the table header to get the table length */
-               if (count <= sizeof(struct acpi_table_header))
-                       return -EINVAL;
-               if (copy_from_user(&table, user_buf,
-                                  sizeof(struct acpi_table_header)))
-                       return -EFAULT;
-               uncopied_bytes = max_size = table.length;
-               buf = kzalloc(max_size, GFP_KERNEL);
-               if (!buf)
-                       return -ENOMEM;
-       }
-
-       if (buf == NULL)
-               return -EINVAL;
-
-       if ((*ppos > max_size) ||
-           (*ppos + count > max_size) ||
-           (*ppos + count < count) ||
-           (count > uncopied_bytes))
-               return -EINVAL;
-
-       if (copy_from_user(buf + (*ppos), user_buf, count)) {
-               kfree(buf);
-               buf = NULL;
-               return -EFAULT;
-       }
-
-       uncopied_bytes -= count;
-       *ppos += count;
-
-       if (!uncopied_bytes) {
-               status = acpi_install_method(buf);
-               kfree(buf);
-               buf = NULL;
-               if (ACPI_FAILURE(status))
-                       return -EINVAL;
-               add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
-       }
-
-       return count;
-}
-
-static const struct file_operations cm_fops = {
-       .write = cm_write,
-       .llseek = default_llseek,
-};
-
-int __init acpi_debugfs_init(void)
-{
-       struct dentry *acpi_dir, *cm_dentry;
-
-       acpi_dir = debugfs_create_dir("acpi", NULL);
-       if (!acpi_dir)
-               goto err;
-
-       cm_dentry = debugfs_create_file("custom_method", S_IWUSR,
-                                       acpi_dir, NULL, &cm_fops);
-       if (!cm_dentry)
-               goto err;
-
-       return 0;
-
-err:
-       if (acpi_dir)
-               debugfs_remove(acpi_dir);
-       return -EINVAL;
+       acpi_debugfs_dir = debugfs_create_dir("acpi", NULL);
 }
index fa848c4116a84b3572f0142ccb3d87df8dff2ada..b19a18dd994fd0565897d2e0dfebfedaab230c36 100644 (file)
@@ -69,7 +69,6 @@ enum ec_command {
 
 #define ACPI_EC_DELAY          500     /* Wait 500ms max. during EC ops */
 #define ACPI_EC_UDELAY_GLK     1000    /* Wait 1ms max. to get global lock */
-#define ACPI_EC_CDELAY         10      /* Wait 10us before polling EC */
 #define ACPI_EC_MSI_UDELAY     550     /* Wait 550us for MSI EC */
 
 #define ACPI_EC_STORM_THRESHOLD 8      /* number of false interrupts
@@ -433,8 +432,7 @@ EXPORT_SYMBOL(ec_write);
 
 int ec_transaction(u8 command,
                   const u8 * wdata, unsigned wdata_len,
-                  u8 * rdata, unsigned rdata_len,
-                  int force_poll)
+                  u8 * rdata, unsigned rdata_len)
 {
        struct transaction t = {.command = command,
                                .wdata = wdata, .rdata = rdata,
@@ -592,8 +590,6 @@ static void acpi_ec_gpe_query(void *ec_cxt)
        mutex_unlock(&ec->lock);
 }
 
-static void acpi_ec_gpe_query(void *ec_cxt);
-
 static int ec_check_sci(struct acpi_ec *ec, u8 state)
 {
        if (state & ACPI_EC_FLAG_SCI) {
@@ -808,8 +804,6 @@ static int acpi_ec_add(struct acpi_device *device)
                        return -EINVAL;
        }
 
-       ec->handle = device->handle;
-
        /* Find and register all query methods */
        acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
                            acpi_ec_register_query_methods, NULL, ec, NULL);
@@ -938,8 +932,19 @@ static struct dmi_system_id __initdata ec_dmi_table[] = {
        ec_flag_msi, "MSI hardware", {
        DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR")}, NULL},
        {
+       ec_flag_msi, "Quanta hardware", {
+       DMI_MATCH(DMI_SYS_VENDOR, "Quanta"),
+       DMI_MATCH(DMI_PRODUCT_NAME, "TW8/SW8/DW8"),}, NULL},
+       {
+       ec_flag_msi, "Quanta hardware", {
+       DMI_MATCH(DMI_SYS_VENDOR, "Quanta"),
+       DMI_MATCH(DMI_PRODUCT_NAME, "TW9/SW9"),}, NULL},
+       {
        ec_validate_ecdt, "ASUS hardware", {
        DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL},
+       {
+       ec_validate_ecdt, "ASUS hardware", {
+       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc.") }, NULL},
        {},
 };
 
index 4bfb759deb104e6febcf837a84d52c3cb39916a3..ca75b9ce0489f0fb1140d994ccf2476bf4935a60 100644 (file)
@@ -28,9 +28,10 @@ int acpi_scan_init(void);
 int acpi_sysfs_init(void);
 
 #ifdef CONFIG_DEBUG_FS
+extern struct dentry *acpi_debugfs_dir;
 int acpi_debugfs_init(void);
 #else
-static inline int acpi_debugfs_init(void) { return 0; }
+static inline void acpi_debugfs_init(void) { return; }
 #endif
 
 /* --------------------------------------------------------------------------
index 45ad4ffef5334ba692e7883515399f863fe22e24..52ca9649d76925abc1718e9c3bed4391cf189006 100644 (file)
@@ -902,14 +902,6 @@ void acpi_os_wait_events_complete(void *context)
 
 EXPORT_SYMBOL(acpi_os_wait_events_complete);
 
-/*
- * Deallocate the memory for a spinlock.
- */
-void acpi_os_delete_lock(acpi_spinlock handle)
-{
-       return;
-}
-
 acpi_status
 acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
 {
@@ -1340,6 +1332,31 @@ int acpi_resources_are_enforced(void)
 }
 EXPORT_SYMBOL(acpi_resources_are_enforced);
 
+/*
+ * Create and initialize a spinlock.
+ */
+acpi_status
+acpi_os_create_lock(acpi_spinlock *out_handle)
+{
+       spinlock_t *lock;
+
+       lock = ACPI_ALLOCATE(sizeof(spinlock_t));
+       if (!lock)
+               return AE_NO_MEMORY;
+       spin_lock_init(lock);
+       *out_handle = lock;
+
+       return AE_OK;
+}
+
+/*
+ * Deallocate the memory for a spinlock.
+ */
+void acpi_os_delete_lock(acpi_spinlock handle)
+{
+       ACPI_FREE(handle);
+}
+
 /*
  * Acquire a spinlock.
  *
index 25bf17da69fd8a298d1bb875a5942fe253720168..02d2a4c9084df510c7f6929d08a7082f1ecba5d8 100644 (file)
@@ -37,7 +37,6 @@ static struct dmi_system_id __initdata processor_idle_dmi_table[] = {
        {},
 };
 
-#ifdef CONFIG_SMP
 static int map_lapic_id(struct acpi_subtable_header *entry,
                 u32 acpi_id, int *apic_id)
 {
@@ -165,7 +164,9 @@ exit:
 
 int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
 {
+#ifdef CONFIG_SMP
        int i;
+#endif
        int apic_id = -1;
 
        apic_id = map_mat_entry(handle, type, acpi_id);
@@ -174,14 +175,19 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
        if (apic_id == -1)
                return apic_id;
 
+#ifdef CONFIG_SMP
        for_each_possible_cpu(i) {
                if (cpu_physical_id(i) == apic_id)
                        return i;
        }
+#else
+       /* In UP kernel, only processor 0 is valid */
+       if (apic_id == 0)
+               return apic_id;
+#endif
        return -1;
 }
 EXPORT_SYMBOL_GPL(acpi_get_cpuid);
-#endif
 
 static bool __init processor_physically_present(acpi_handle handle)
 {
@@ -217,7 +223,7 @@ static bool __init processor_physically_present(acpi_handle handle)
        type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0;
        cpuid = acpi_get_cpuid(handle, type, acpi_id);
 
-       if ((cpuid == -1) && (num_possible_cpus() > 1))
+       if (cpuid == -1)
                return false;
 
        return true;
index d615b7d69bcaff7c29847b2eee37e4b08876dc90..431ab11c8c1b6736aec984754c9f6002d3542ad8 100644 (file)
@@ -161,7 +161,7 @@ static void lapic_timer_check_state(int state, struct acpi_processor *pr,
        if (cpu_has(&cpu_data(pr->id), X86_FEATURE_ARAT))
                return;
 
-       if (c1e_detected)
+       if (amd_e400_c1e_detected)
                type = ACPI_STATE_C1;
 
        /*
index 61891e75583da971f7973393fc9071b5ec14dfaa..77255f250dbb7c2afe29aabc640d5227fddf7d08 100644 (file)
@@ -220,6 +220,14 @@ module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
                  NULL, 0644);
 #endif /* CONFIG_ACPI_DEBUG */
 
+
+/* /sys/modules/acpi/parameters/aml_debug_output */
+
+module_param_named(aml_debug_output, acpi_gbl_enable_aml_debug_object,
+                  bool, 0644);
+MODULE_PARM_DESC(aml_debug_output,
+                "To enable/disable the ACPI Debug Object output.");
+
 /* /sys/module/acpi/parameters/acpica_version */
 static int param_get_acpica_version(char *buffer, struct kernel_param *kp)
 {
index 7025593a58c89d39cb3ff260801b242730d8fdf2..d74926e0939e9f9362bcfa09e8301a105bdfb76b 100644 (file)
@@ -603,6 +603,10 @@ int amba_device_register(struct amba_device *dev, struct resource *parent)
        if (ret)
                goto err_out;
 
+       /* Hard-coded primecell ID instead of plug-n-play */
+       if (dev->periphid != 0)
+               goto skip_probe;
+
        /*
         * Dynamically calculate the size of the resource
         * and use this for iomap
@@ -643,6 +647,7 @@ int amba_device_register(struct amba_device *dev, struct resource *parent)
        if (ret)
                goto err_release;
 
+ skip_probe:
        ret = device_add(&dev->dev);
        if (ret)
                goto err_release;
index 736bee5dafebcffc3e13bcf9f8a4b48d13680903..000d03ae6653d7ad294d7477ab84d254d7e2f012 100644 (file)
@@ -4143,9 +4143,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
         * Devices which choke on SETXFER.  Applies only if both the
         * device and controller are SATA.
         */
-       { "PIONEER DVD-RW  DVRTD08",    "1.00", ATA_HORKAGE_NOSETXFER },
-       { "PIONEER DVD-RW  DVR-212D",   "1.28", ATA_HORKAGE_NOSETXFER },
-       { "PIONEER DVD-RW  DVR-216D",   "1.08", ATA_HORKAGE_NOSETXFER },
+       { "PIONEER DVD-RW  DVRTD08",    NULL,   ATA_HORKAGE_NOSETXFER },
+       { "PIONEER DVD-RW  DVR-212D",   NULL,   ATA_HORKAGE_NOSETXFER },
+       { "PIONEER DVD-RW  DVR-216D",   NULL,   ATA_HORKAGE_NOSETXFER },
 
        /* End Marker */
        { }
index dfb6e9d3d759921419d8713fc7c48764ad943207..7f099d6e4e0bca601f26f83597e01ec185f03d54 100644 (file)
@@ -2802,10 +2802,11 @@ int ata_eh_reset(struct ata_link *link, int classify,
        }
 
        /*
-        * Some controllers can't be frozen very well and may set
-        * spuruious error conditions during reset.  Clear accumulated
-        * error information.  As reset is the final recovery action,
-        * nothing is lost by doing this.
+        * Some controllers can't be frozen very well and may set spurious
+        * error conditions during reset.  Clear accumulated error
+        * information and re-thaw the port if frozen.  As reset is the
+        * final recovery action and we cross check link onlineness against
+        * device classification later, no hotplug event is lost by this.
         */
        spin_lock_irqsave(link->ap->lock, flags);
        memset(&link->eh_info, 0, sizeof(link->eh_info));
@@ -2814,6 +2815,9 @@ int ata_eh_reset(struct ata_link *link, int classify,
        ap->pflags &= ~ATA_PFLAG_EH_PENDING;
        spin_unlock_irqrestore(link->ap->lock, flags);
 
+       if (ap->pflags & ATA_PFLAG_FROZEN)
+               ata_eh_thaw_port(ap);
+
        /*
         * Make sure onlineness and classification result correspond.
         * Hotplug could have happened during reset and some
index 30ea95f43e7910cf8f4cdc1742d4213e53240fb5..927f968e99d9f8b4dd896c8c8eb5f521fb1cff72 100644 (file)
@@ -1089,21 +1089,21 @@ static int atapi_drain_needed(struct request *rq)
 static int ata_scsi_dev_config(struct scsi_device *sdev,
                               struct ata_device *dev)
 {
+       struct request_queue *q = sdev->request_queue;
+
        if (!ata_id_has_unload(dev->id))
                dev->flags |= ATA_DFLAG_NO_UNLOAD;
 
        /* configure max sectors */
-       blk_queue_max_hw_sectors(sdev->request_queue, dev->max_sectors);
+       blk_queue_max_hw_sectors(q, dev->max_sectors);
 
        if (dev->class == ATA_DEV_ATAPI) {
-               struct request_queue *q = sdev->request_queue;
                void *buf;
 
                sdev->sector_size = ATA_SECT_SIZE;
 
                /* set DMA padding */
-               blk_queue_update_dma_pad(sdev->request_queue,
-                                        ATA_DMA_PAD_SZ - 1);
+               blk_queue_update_dma_pad(q, ATA_DMA_PAD_SZ - 1);
 
                /* configure draining */
                buf = kmalloc(ATAPI_MAX_DRAIN, q->bounce_gfp | GFP_KERNEL);
@@ -1131,8 +1131,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
                        "sector_size=%u > PAGE_SIZE, PIO may malfunction\n",
                        sdev->sector_size);
 
-       blk_queue_update_dma_alignment(sdev->request_queue,
-                                      sdev->sector_size - 1);
+       blk_queue_update_dma_alignment(q, sdev->sector_size - 1);
 
        if (dev->flags & ATA_DFLAG_AN)
                set_bit(SDEV_EVT_MEDIA_CHANGE, sdev->supported_events);
@@ -1145,6 +1144,8 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
                scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
        }
 
+       blk_queue_flush_queueable(q, false);
+
        dev->sdev = sdev;
        return 0;
 }
@@ -3796,6 +3797,12 @@ EXPORT_SYMBOL_GPL(ata_sas_port_alloc);
  */
 int ata_sas_port_start(struct ata_port *ap)
 {
+       /*
+        * the port is marked as frozen at allocation time, but if we don't
+        * have new eh, we won't thaw it
+        */
+       if (!ap->ops->error_handler)
+               ap->pflags &= ~ATA_PFLAG_FROZEN;
        return 0;
 }
 EXPORT_SYMBOL_GPL(ata_sas_port_start);
index 75a6a0c0094fb1b8220a50ddd2cc94765003c18b..5d7f58a7e34dba624e5319cbdf15aab24a1f3ea6 100644 (file)
@@ -161,6 +161,9 @@ static const struct pci_device_id marvell_pci_tbl[] = {
        { PCI_DEVICE(0x11AB, 0x6121), },
        { PCI_DEVICE(0x11AB, 0x6123), },
        { PCI_DEVICE(0x11AB, 0x6145), },
+       { PCI_DEVICE(0x1B4B, 0x91A0), },
+       { PCI_DEVICE(0x1B4B, 0x91A4), },
+
        { }     /* terminate list */
 };
 
index 29af660d968b7664f8d182454a6dbc23a6708fa9..021abe6d8527ae93bd6ff52eda0565f936741094 100644 (file)
@@ -309,7 +309,7 @@ static void pcmcia_remove_one(struct pcmcia_device *pdev)
        pcmcia_disable_device(pdev);
 }
 
-static struct pcmcia_device_id pcmcia_devices[] = {
+static const struct pcmcia_device_id pcmcia_devices[] = {
        PCMCIA_DEVICE_FUNC_ID(4),
        PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000),        /* Corsair */
        PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000),        /* Hitachi */
index 1c4b3aa4c7c40da65c8c6f86f936be6891839e6c..dc88a39e7db8b04c9a2ec3e85ed888ee90194e69 100644 (file)
@@ -389,7 +389,7 @@ static void sata_dwc_tf_dump(struct ata_taskfile *tf)
 /*
  * Function: get_burst_length_encode
  * arguments: datalength: length in bytes of data
- * returns value to be programmed in register corrresponding to data length
+ * returns value to be programmed in register corresponding to data length
  * This value is effectively the log(base 2) of the length
  */
 static  int get_burst_length_encode(int datalength)
index b3b72d64e80594bdc7527fcf0273dee0fd41e8bf..793f796c4da3e1cd20143e1266d41246f2289b73 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/memory.h>
+#include <linux/vmstat.h>
 #include <linux/node.h>
 #include <linux/hugetlb.h>
 #include <linux/compaction.h>
@@ -179,11 +180,14 @@ static ssize_t node_read_vmstat(struct sys_device *dev,
                                struct sysdev_attribute *attr, char *buf)
 {
        int nid = dev->id;
-       return sprintf(buf,
-               "nr_written %lu\n"
-               "nr_dirtied %lu\n",
-               node_page_state(nid, NR_WRITTEN),
-               node_page_state(nid, NR_DIRTIED));
+       int i;
+       int n = 0;
+
+       for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
+               n += sprintf(buf+n, "%s %lu\n", vmstat_text[i],
+                            node_page_state(nid, i));
+
+       return n;
 }
 static SYSDEV_ATTR(vmstat, S_IRUGO, node_read_vmstat, NULL);
 
index c0dd09df7be891a113e94bd2a53cc7a6de8bd1e5..ad367c4139b14ead6102ed2e31d03f52c63d1fcf 100644 (file)
@@ -291,7 +291,7 @@ static int pm_runtime_clk_notify(struct notifier_block *nb,
 {
        struct pm_clk_notifier_block *clknb;
        struct device *dev = data;
-       char *con_id;
+       char **con_id;
        int error;
 
        dev_dbg(dev, "%s() %ld\n", __func__, action);
@@ -309,8 +309,8 @@ static int pm_runtime_clk_notify(struct notifier_block *nb,
 
                dev->pwr_domain = clknb->pwr_domain;
                if (clknb->con_ids[0]) {
-                       for (con_id = clknb->con_ids[0]; *con_id; con_id++)
-                               pm_runtime_clk_add(dev, con_id);
+                       for (con_id = clknb->con_ids; *con_id; con_id++)
+                               pm_runtime_clk_add(dev, *con_id);
                } else {
                        pm_runtime_clk_add(dev, NULL);
                }
@@ -380,25 +380,25 @@ static int pm_runtime_clk_notify(struct notifier_block *nb,
 {
        struct pm_clk_notifier_block *clknb;
        struct device *dev = data;
-       char *con_id;
+       char **con_id;
 
        dev_dbg(dev, "%s() %ld\n", __func__, action);
 
        clknb = container_of(nb, struct pm_clk_notifier_block, nb);
 
        switch (action) {
-       case BUS_NOTIFY_ADD_DEVICE:
+       case BUS_NOTIFY_BIND_DRIVER:
                if (clknb->con_ids[0]) {
-                       for (con_id = clknb->con_ids[0]; *con_id; con_id++)
-                               enable_clock(dev, con_id);
+                       for (con_id = clknb->con_ids; *con_id; con_id++)
+                               enable_clock(dev, *con_id);
                } else {
                        enable_clock(dev, NULL);
                }
                break;
-       case BUS_NOTIFY_DEL_DEVICE:
+       case BUS_NOTIFY_UNBOUND_DRIVER:
                if (clknb->con_ids[0]) {
-                       for (con_id = clknb->con_ids[0]; *con_id; con_id++)
-                               disable_clock(dev, con_id);
+                       for (con_id = clknb->con_ids; *con_id; con_id++)
+                               disable_clock(dev, *con_id);
                } else {
                        disable_clock(dev, NULL);
                }
index aa6320207745d636641178f3d9ca89c2d489fe6e..06f09bf89cb2bab3319d800ca2dd7939dfb59a3b 100644 (file)
@@ -57,7 +57,8 @@ static int async_error;
  */
 void device_pm_init(struct device *dev)
 {
-       dev->power.in_suspend = false;
+       dev->power.is_prepared = false;
+       dev->power.is_suspended = false;
        init_completion(&dev->power.completion);
        complete_all(&dev->power.completion);
        dev->power.wakeup = NULL;
@@ -91,7 +92,7 @@ void device_pm_add(struct device *dev)
        pr_debug("PM: Adding info for %s:%s\n",
                 dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
        mutex_lock(&dpm_list_mtx);
-       if (dev->parent && dev->parent->power.in_suspend)
+       if (dev->parent && dev->parent->power.is_prepared)
                dev_warn(dev, "parent %s should not be sleeping\n",
                        dev_name(dev->parent));
        list_add_tail(&dev->power.entry, &dpm_list);
@@ -511,7 +512,14 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
        dpm_wait(dev->parent, async);
        device_lock(dev);
 
-       dev->power.in_suspend = false;
+       /*
+        * This is a fib.  But we'll allow new children to be added below
+        * a resumed device, even if the device hasn't been completed yet.
+        */
+       dev->power.is_prepared = false;
+
+       if (!dev->power.is_suspended)
+               goto Unlock;
 
        if (dev->pwr_domain) {
                pm_dev_dbg(dev, state, "power domain ");
@@ -548,6 +556,9 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
        }
 
  End:
+       dev->power.is_suspended = false;
+
+ Unlock:
        device_unlock(dev);
        complete_all(&dev->power.completion);
 
@@ -670,7 +681,7 @@ void dpm_complete(pm_message_t state)
                struct device *dev = to_device(dpm_prepared_list.prev);
 
                get_device(dev);
-               dev->power.in_suspend = false;
+               dev->power.is_prepared = false;
                list_move(&dev->power.entry, &list);
                mutex_unlock(&dpm_list_mtx);
 
@@ -835,11 +846,11 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
        device_lock(dev);
 
        if (async_error)
-               goto End;
+               goto Unlock;
 
        if (pm_wakeup_pending()) {
                async_error = -EBUSY;
-               goto End;
+               goto Unlock;
        }
 
        if (dev->pwr_domain) {
@@ -877,6 +888,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
        }
 
  End:
+       dev->power.is_suspended = !error;
+
+ Unlock:
        device_unlock(dev);
        complete_all(&dev->power.completion);
 
@@ -1042,7 +1056,7 @@ int dpm_prepare(pm_message_t state)
                        put_device(dev);
                        break;
                }
-               dev->power.in_suspend = true;
+               dev->power.is_prepared = true;
                if (!list_empty(&dev->power.entry))
                        list_move_tail(&dev->power.entry, &dpm_prepared_list);
                put_device(dev);
index 99dd36e8500b8df8706885bcc2d9dc31694e73cb..471a04013fe01771bc4b4bf41396af350c50e456 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #include "bcma_private.h"
+#include <linux/slab.h>
 #include <linux/bcma/bcma.h>
 #include <linux/pci.h>
 
@@ -171,6 +172,7 @@ static void bcma_host_pci_remove(struct pci_dev *dev)
 }
 
 static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
index 83c32cb72582bd6a1c33524ff61bdc757e76d6f2..717d6e4e18d3d08086fd2d5365574adbd613aef8 100644 (file)
@@ -470,6 +470,27 @@ config XEN_BLKDEV_FRONTEND
          block device driver.  It communicates with a back-end driver
          in another domain which drives the actual block device.
 
+config XEN_BLKDEV_BACKEND
+       tristate "Block-device backend driver"
+       depends on XEN_BACKEND
+       help
+         The block-device backend driver allows the kernel to export its
+         block devices to other guests via a high-performance shared-memory
+         interface.
+
+         The corresponding Linux frontend driver is enabled by the
+         CONFIG_XEN_BLKDEV_FRONTEND configuration option.
+
+         The backend driver attaches itself to a any block device specified
+         in the XenBus configuration. There are no limits to what the block
+         device as long as it has a major and minor.
+
+         If you are compiling a kernel to run in a Xen block backend driver
+         domain (often this is domain 0) you should say Y here. To
+         compile this driver as a module, chose M here: the module
+         will be called xen-blkback.
+
+
 config VIRTIO_BLK
        tristate "Virtio block driver (EXPERIMENTAL)"
        depends on EXPERIMENTAL && VIRTIO
index 40528ba56d1bf1a1a2db7c2728b10219b98cd029..76646e9a1c91528617c22e2c3f429201531acdf4 100644 (file)
@@ -36,6 +36,7 @@ obj-$(CONFIG_BLK_DEV_UB)      += ub.o
 obj-$(CONFIG_BLK_DEV_HD)       += hd.o
 
 obj-$(CONFIG_XEN_BLKDEV_FRONTEND)      += xen-blkfront.o
+obj-$(CONFIG_XEN_BLKDEV_BACKEND)       += xen-blkback/
 obj-$(CONFIG_BLK_DEV_DRBD)     += drbd/
 obj-$(CONFIG_BLK_DEV_RBD)     += rbd.o
 
index b7f51e4594f8660f0a54472d264d957dbe533312..dba1c32e1ddfc48229d93d014fedaa9c370e92e3 100644 (file)
  */
 struct brd_device {
        int             brd_number;
-       int             brd_refcnt;
-       loff_t          brd_offset;
-       loff_t          brd_sizelimit;
-       unsigned        brd_blocksize;
 
        struct request_queue    *brd_queue;
        struct gendisk          *brd_disk;
@@ -440,11 +436,11 @@ static int rd_nr;
 int rd_size = CONFIG_BLK_DEV_RAM_SIZE;
 static int max_part;
 static int part_shift;
-module_param(rd_nr, int, 0);
+module_param(rd_nr, int, S_IRUGO);
 MODULE_PARM_DESC(rd_nr, "Maximum number of brd devices");
-module_param(rd_size, int, 0);
+module_param(rd_size, int, S_IRUGO);
 MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes.");
-module_param(max_part, int, 0);
+module_param(max_part, int, S_IRUGO);
 MODULE_PARM_DESC(max_part, "Maximum number of partitions per RAM disk");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_BLOCKDEV_MAJOR(RAMDISK_MAJOR);
@@ -552,7 +548,7 @@ static struct kobject *brd_probe(dev_t dev, int *part, void *data)
        struct kobject *kobj;
 
        mutex_lock(&brd_devices_mutex);
-       brd = brd_init_one(dev & MINORMASK);
+       brd = brd_init_one(MINOR(dev) >> part_shift);
        kobj = brd ? get_disk(brd->brd_disk) : ERR_PTR(-ENOMEM);
        mutex_unlock(&brd_devices_mutex);
 
@@ -575,25 +571,39 @@ static int __init brd_init(void)
         *
         * (1) if rd_nr is specified, create that many upfront, and this
         *     also becomes a hard limit.
-        * (2) if rd_nr is not specified, create 1 rd device on module
-        *     load, user can further extend brd device by create dev node
-        *     themselves and have kernel automatically instantiate actual
-        *     device on-demand.
+        * (2) if rd_nr is not specified, create CONFIG_BLK_DEV_RAM_COUNT
+        *     (default 16) rd device on module load, user can further
+        *     extend brd device by create dev node themselves and have
+        *     kernel automatically instantiate actual device on-demand.
         */
 
        part_shift = 0;
-       if (max_part > 0)
+       if (max_part > 0) {
                part_shift = fls(max_part);
 
+               /*
+                * Adjust max_part according to part_shift as it is exported
+                * to user space so that user can decide correct minor number
+                * if [s]he want to create more devices.
+                *
+                * Note that -1 is required because partition 0 is reserved
+                * for the whole disk.
+                */
+               max_part = (1UL << part_shift) - 1;
+       }
+
+       if ((1UL << part_shift) > DISK_MAX_PARTS)
+               return -EINVAL;
+
        if (rd_nr > 1UL << (MINORBITS - part_shift))
                return -EINVAL;
 
        if (rd_nr) {
                nr = rd_nr;
-               range = rd_nr;
+               range = rd_nr << part_shift;
        } else {
                nr = CONFIG_BLK_DEV_RAM_COUNT;
-               range = 1UL << (MINORBITS - part_shift);
+               range = 1UL << MINORBITS;
        }
 
        if (register_blkdev(RAMDISK_MAJOR, "ramdisk"))
@@ -632,7 +642,7 @@ static void __exit brd_exit(void)
        unsigned long range;
        struct brd_device *brd, *next;
 
-       range = rd_nr ? rd_nr :  1UL << (MINORBITS - part_shift);
+       range = rd_nr ? rd_nr << part_shift : 1UL << MINORBITS;
 
        list_for_each_entry_safe(brd, next, &brd_devices, brd_list)
                brd_del_one(brd);
index 9bf13988f1a2f813ff20d6d65d5c9dd22426579e..8f4ef656a1af4ca435ff3ecc5e0d6079e6a1e34d 100644 (file)
@@ -64,6 +64,10 @@ MODULE_DESCRIPTION("Driver for HP Smart Array Controllers");
 MODULE_SUPPORTED_DEVICE("HP Smart Array Controllers");
 MODULE_VERSION("3.6.26");
 MODULE_LICENSE("GPL");
+static int cciss_tape_cmds = 6;
+module_param(cciss_tape_cmds, int, 0644);
+MODULE_PARM_DESC(cciss_tape_cmds,
+       "number of commands to allocate for tape devices (default: 6)");
 
 static DEFINE_MUTEX(cciss_mutex);
 static struct proc_dir_entry *proc_cciss;
@@ -194,6 +198,8 @@ static int __devinit cciss_find_cfg_addrs(struct pci_dev *pdev,
 static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev,
        unsigned long *memory_bar);
 static inline u32 cciss_tag_discard_error_bits(ctlr_info_t *h, u32 tag);
+static __devinit int write_driver_ver_to_cfgtable(
+       CfgTable_struct __iomem *cfgtable);
 
 /* performant mode helper functions */
 static void  calc_bucket_map(int *bucket, int num_buckets, int nsgs,
@@ -556,7 +562,7 @@ static void __devinit cciss_procinit(ctlr_info_t *h)
 #define to_hba(n) container_of(n, struct ctlr_info, dev)
 #define to_drv(n) container_of(n, drive_info_struct, dev)
 
-/* List of controllers which cannot be reset on kexec with reset_devices */
+/* List of controllers which cannot be hard reset on kexec with reset_devices */
 static u32 unresettable_controller[] = {
        0x324a103C, /* Smart Array P712m */
        0x324b103C, /* SmartArray P711m */
@@ -574,23 +580,45 @@ static u32 unresettable_controller[] = {
        0x409D0E11, /* Smart Array 6400 EM */
 };
 
-static int ctlr_is_resettable(struct ctlr_info *h)
+/* List of controllers which cannot even be soft reset */
+static u32 soft_unresettable_controller[] = {
+       0x409C0E11, /* Smart Array 6400 */
+       0x409D0E11, /* Smart Array 6400 EM */
+};
+
+static int ctlr_is_hard_resettable(u32 board_id)
 {
        int i;
 
        for (i = 0; i < ARRAY_SIZE(unresettable_controller); i++)
-               if (unresettable_controller[i] == h->board_id)
+               if (unresettable_controller[i] == board_id)
                        return 0;
        return 1;
 }
 
+static int ctlr_is_soft_resettable(u32 board_id)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(soft_unresettable_controller); i++)
+               if (soft_unresettable_controller[i] == board_id)
+                       return 0;
+       return 1;
+}
+
+static int ctlr_is_resettable(u32 board_id)
+{
+       return ctlr_is_hard_resettable(board_id) ||
+               ctlr_is_soft_resettable(board_id);
+}
+
 static ssize_t host_show_resettable(struct device *dev,
                                    struct device_attribute *attr,
                                    char *buf)
 {
        struct ctlr_info *h = to_hba(dev);
 
-       return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h));
+       return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h->board_id));
 }
 static DEVICE_ATTR(resettable, S_IRUGO, host_show_resettable, NULL);
 
@@ -2567,7 +2595,7 @@ static int fill_cmd(ctlr_info_t *h, CommandList_struct *c, __u8 cmd, void *buff,
                }
        } else if (cmd_type == TYPE_MSG) {
                switch (cmd) {
-               case 0: /* ABORT message */
+               case CCISS_ABORT_MSG:
                        c->Request.CDBLen = 12;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
                        c->Request.Type.Direction = XFER_WRITE;
@@ -2577,16 +2605,16 @@ static int fill_cmd(ctlr_info_t *h, CommandList_struct *c, __u8 cmd, void *buff,
                        /* buff contains the tag of the command to abort */
                        memcpy(&c->Request.CDB[4], buff, 8);
                        break;
-               case 1: /* RESET message */
+               case CCISS_RESET_MSG:
                        c->Request.CDBLen = 16;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
                        c->Request.Type.Direction = XFER_NONE;
                        c->Request.Timeout = 0;
                        memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
                        c->Request.CDB[0] = cmd;        /* reset */
-                       c->Request.CDB[1] = 0x03;       /* reset a target */
+                       c->Request.CDB[1] = CCISS_RESET_TYPE_TARGET;
                        break;
-               case 3: /* No-Op message */
+               case CCISS_NOOP_MSG:
                        c->Request.CDBLen = 1;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
                        c->Request.Type.Direction = XFER_WRITE;
@@ -2615,6 +2643,31 @@ static int fill_cmd(ctlr_info_t *h, CommandList_struct *c, __u8 cmd, void *buff,
        return status;
 }
 
+static int __devinit cciss_send_reset(ctlr_info_t *h, unsigned char *scsi3addr,
+       u8 reset_type)
+{
+       CommandList_struct *c;
+       int return_status;
+
+       c = cmd_alloc(h);
+       if (!c)
+               return -ENOMEM;
+       return_status = fill_cmd(h, c, CCISS_RESET_MSG, NULL, 0, 0,
+               CTLR_LUNID, TYPE_MSG);
+       c->Request.CDB[1] = reset_type; /* fill_cmd defaults to target reset */
+       if (return_status != IO_OK) {
+               cmd_special_free(h, c);
+               return return_status;
+       }
+       c->waiting = NULL;
+       enqueue_cmd_and_start_io(h, c);
+       /* Don't wait for completion, the reset won't complete.  Don't free
+        * the command either.  This is the last command we will send before
+        * re-initializing everything, so it doesn't matter and won't leak.
+        */
+       return 0;
+}
+
 static int check_target_status(ctlr_info_t *h, CommandList_struct *c)
 {
        switch (c->err_info->ScsiStatus) {
@@ -3461,6 +3514,63 @@ static inline u32 process_nonindexed_cmd(ctlr_info_t *h, u32 raw_tag)
        return next_command(h);
 }
 
+/* Some controllers, like p400, will give us one interrupt
+ * after a soft reset, even if we turned interrupts off.
+ * Only need to check for this in the cciss_xxx_discard_completions
+ * functions.
+ */
+static int ignore_bogus_interrupt(ctlr_info_t *h)
+{
+       if (likely(!reset_devices))
+               return 0;
+
+       if (likely(h->interrupts_enabled))
+               return 0;
+
+       dev_info(&h->pdev->dev, "Received interrupt while interrupts disabled "
+               "(known firmware bug.)  Ignoring.\n");
+
+       return 1;
+}
+
+static irqreturn_t cciss_intx_discard_completions(int irq, void *dev_id)
+{
+       ctlr_info_t *h = dev_id;
+       unsigned long flags;
+       u32 raw_tag;
+
+       if (ignore_bogus_interrupt(h))
+               return IRQ_NONE;
+
+       if (interrupt_not_for_us(h))
+               return IRQ_NONE;
+       spin_lock_irqsave(&h->lock, flags);
+       while (interrupt_pending(h)) {
+               raw_tag = get_next_completion(h);
+               while (raw_tag != FIFO_EMPTY)
+                       raw_tag = next_command(h);
+       }
+       spin_unlock_irqrestore(&h->lock, flags);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t cciss_msix_discard_completions(int irq, void *dev_id)
+{
+       ctlr_info_t *h = dev_id;
+       unsigned long flags;
+       u32 raw_tag;
+
+       if (ignore_bogus_interrupt(h))
+               return IRQ_NONE;
+
+       spin_lock_irqsave(&h->lock, flags);
+       raw_tag = get_next_completion(h);
+       while (raw_tag != FIFO_EMPTY)
+               raw_tag = next_command(h);
+       spin_unlock_irqrestore(&h->lock, flags);
+       return IRQ_HANDLED;
+}
+
 static irqreturn_t do_cciss_intx(int irq, void *dev_id)
 {
        ctlr_info_t *h = dev_id;
@@ -4078,6 +4188,9 @@ static int __devinit cciss_find_cfgtables(ctlr_info_t *h)
                cfg_base_addr_index) + cfg_offset, sizeof(h->cfgtable));
        if (!h->cfgtable)
                return -ENOMEM;
+       rc = write_driver_ver_to_cfgtable(h->cfgtable);
+       if (rc)
+               return rc;
        /* Find performant mode table. */
        trans_offset = readl(&h->cfgtable->TransMethodOffset);
        h->transtable = remap_pci_mem(pci_resource_start(h->pdev,
@@ -4112,7 +4225,7 @@ static void __devinit cciss_get_max_perf_mode_cmds(struct ctlr_info *h)
 static void __devinit cciss_find_board_params(ctlr_info_t *h)
 {
        cciss_get_max_perf_mode_cmds(h);
-       h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */
+       h->nr_cmds = h->max_commands - 4 - cciss_tape_cmds;
        h->maxsgentries = readl(&(h->cfgtable->MaxSGElements));
        /*
         * Limit in-command s/g elements to 32 save dma'able memory.
@@ -4348,7 +4461,7 @@ static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, u
                tag = readl(vaddr + SA5_REPLY_PORT_OFFSET);
                if ((tag & ~3) == paddr32)
                        break;
-               schedule_timeout_uninterruptible(HZ);
+               msleep(CCISS_POST_RESET_NOOP_TIMEOUT_MSECS);
        }
 
        iounmap(vaddr);
@@ -4375,11 +4488,10 @@ static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, u
        return 0;
 }
 
-#define cciss_soft_reset_controller(p) cciss_message(p, 1, 0)
 #define cciss_noop(p) cciss_message(p, 3, 0)
 
 static int cciss_controller_hard_reset(struct pci_dev *pdev,
-       void * __iomem vaddr, bool use_doorbell)
+       void * __iomem vaddr, u32 use_doorbell)
 {
        u16 pmcsr;
        int pos;
@@ -4390,8 +4502,7 @@ static int cciss_controller_hard_reset(struct pci_dev *pdev,
                 * other way using the doorbell register.
                 */
                dev_info(&pdev->dev, "using doorbell to reset controller\n");
-               writel(DOORBELL_CTLR_RESET, vaddr + SA5_DOORBELL);
-               msleep(1000);
+               writel(use_doorbell, vaddr + SA5_DOORBELL);
        } else { /* Try to do it the PCI power state way */
 
                /* Quoting from the Open CISS Specification: "The Power
@@ -4422,12 +4533,64 @@ static int cciss_controller_hard_reset(struct pci_dev *pdev,
                pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
                pmcsr |= PCI_D0;
                pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
-
-               msleep(500);
        }
        return 0;
 }
 
+static __devinit void init_driver_version(char *driver_version, int len)
+{
+       memset(driver_version, 0, len);
+       strncpy(driver_version, "cciss " DRIVER_NAME, len - 1);
+}
+
+static __devinit int write_driver_ver_to_cfgtable(
+       CfgTable_struct __iomem *cfgtable)
+{
+       char *driver_version;
+       int i, size = sizeof(cfgtable->driver_version);
+
+       driver_version = kmalloc(size, GFP_KERNEL);
+       if (!driver_version)
+               return -ENOMEM;
+
+       init_driver_version(driver_version, size);
+       for (i = 0; i < size; i++)
+               writeb(driver_version[i], &cfgtable->driver_version[i]);
+       kfree(driver_version);
+       return 0;
+}
+
+static __devinit void read_driver_ver_from_cfgtable(
+       CfgTable_struct __iomem *cfgtable, unsigned char *driver_ver)
+{
+       int i;
+
+       for (i = 0; i < sizeof(cfgtable->driver_version); i++)
+               driver_ver[i] = readb(&cfgtable->driver_version[i]);
+}
+
+static __devinit int controller_reset_failed(
+       CfgTable_struct __iomem *cfgtable)
+{
+
+       char *driver_ver, *old_driver_ver;
+       int rc, size = sizeof(cfgtable->driver_version);
+
+       old_driver_ver = kmalloc(2 * size, GFP_KERNEL);
+       if (!old_driver_ver)
+               return -ENOMEM;
+       driver_ver = old_driver_ver + size;
+
+       /* After a reset, the 32 bytes of "driver version" in the cfgtable
+        * should have been changed, otherwise we know the reset failed.
+        */
+       init_driver_version(old_driver_ver, size);
+       read_driver_ver_from_cfgtable(cfgtable, driver_ver);
+       rc = !memcmp(driver_ver, old_driver_ver, size);
+       kfree(old_driver_ver);
+       return rc;
+}
+
 /* This does a hard reset of the controller using PCI power management
  * states or using the doorbell register. */
 static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
@@ -4437,10 +4600,10 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
        u64 cfg_base_addr_index;
        void __iomem *vaddr;
        unsigned long paddr;
-       u32 misc_fw_support, active_transport;
+       u32 misc_fw_support;
        int rc;
        CfgTable_struct __iomem *cfgtable;
-       bool use_doorbell;
+       u32 use_doorbell;
        u32 board_id;
        u16 command_register;
 
@@ -4464,12 +4627,16 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
         * likely not be happy.  Just forbid resetting this conjoined mess.
         */
        cciss_lookup_board_id(pdev, &board_id);
-       if (board_id == 0x409C0E11 || board_id == 0x409D0E11) {
+       if (!ctlr_is_resettable(board_id)) {
                dev_warn(&pdev->dev, "Cannot reset Smart Array 640x "
                                "due to shared cache module.");
                return -ENODEV;
        }
 
+       /* if controller is soft- but not hard resettable... */
+       if (!ctlr_is_hard_resettable(board_id))
+               return -ENOTSUPP; /* try soft reset later. */
+
        /* Save the PCI command register */
        pci_read_config_word(pdev, 4, &command_register);
        /* Turn the board off.  This is so that later pci_restore_state()
@@ -4497,16 +4664,28 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
                rc = -ENOMEM;
                goto unmap_vaddr;
        }
+       rc = write_driver_ver_to_cfgtable(cfgtable);
+       if (rc)
+               goto unmap_vaddr;
 
-       /* If reset via doorbell register is supported, use that. */
-       misc_fw_support = readl(&cfgtable->misc_fw_support);
-       use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
-
-       /* The doorbell reset seems to cause lockups on some Smart
-        * Arrays (e.g. P410, P410i, maybe others).  Until this is
-        * fixed or at least isolated, avoid the doorbell reset.
+       /* If reset via doorbell register is supported, use that.
+        * There are two such methods.  Favor the newest method.
         */
-       use_doorbell = 0;
+       misc_fw_support = readl(&cfgtable->misc_fw_support);
+       use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET2;
+       if (use_doorbell) {
+               use_doorbell = DOORBELL_CTLR_RESET2;
+       } else {
+               use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
+               if (use_doorbell) {
+                       dev_warn(&pdev->dev, "Controller claims that "
+                               "'Bit 2 doorbell reset' is "
+                               "supported, but not 'bit 5 doorbell reset'.  "
+                               "Firmware update is recommended.\n");
+                       rc = -ENOTSUPP; /* use the soft reset */
+                       goto unmap_cfgtable;
+               }
+       }
 
        rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell);
        if (rc)
@@ -4524,30 +4703,31 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
        msleep(CCISS_POST_RESET_PAUSE_MSECS);
 
        /* Wait for board to become not ready, then ready. */
-       dev_info(&pdev->dev, "Waiting for board to become ready.\n");
+       dev_info(&pdev->dev, "Waiting for board to reset.\n");
        rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY);
-       if (rc) /* Don't bail, might be E500, etc. which can't be reset */
-               dev_warn(&pdev->dev,
-                       "failed waiting for board to become not ready\n");
+       if (rc) {
+               dev_warn(&pdev->dev, "Failed waiting for board to hard reset."
+                               "  Will try soft reset.\n");
+               rc = -ENOTSUPP; /* Not expected, but try soft reset later */
+               goto unmap_cfgtable;
+       }
        rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_READY);
        if (rc) {
                dev_warn(&pdev->dev,
-                       "failed waiting for board to become ready\n");
+                       "failed waiting for board to become ready "
+                       "after hard reset\n");
                goto unmap_cfgtable;
        }
-       dev_info(&pdev->dev, "board ready.\n");
 
-       /* Controller should be in simple mode at this point.  If it's not,
-        * It means we're on one of those controllers which doesn't support
-        * the doorbell reset method and on which the PCI power management reset
-        * method doesn't work (P800, for example.)
-        * In those cases, don't try to proceed, as it generally doesn't work.
-        */
-       active_transport = readl(&cfgtable->TransportActive);
-       if (active_transport & PERFORMANT_MODE) {
-               dev_warn(&pdev->dev, "Unable to successfully reset controller,"
-                       " Ignoring controller.\n");
-               rc = -ENODEV;
+       rc = controller_reset_failed(vaddr);
+       if (rc < 0)
+               goto unmap_cfgtable;
+       if (rc) {
+               dev_warn(&pdev->dev, "Unable to successfully hard reset "
+                       "controller. Will try soft reset.\n");
+               rc = -ENOTSUPP; /* Not expected, but try soft reset later */
+       } else {
+               dev_info(&pdev->dev, "Board ready after hard reset.\n");
        }
 
 unmap_cfgtable:
@@ -4574,11 +4754,12 @@ static __devinit int cciss_init_reset_devices(struct pci_dev *pdev)
         * due to concerns about shared bbwc between 6402/6404 pair.
         */
        if (rc == -ENOTSUPP)
-               return 0; /* just try to do the kdump anyhow. */
+               return rc; /* just try to do the kdump anyhow. */
        if (rc)
                return -ENODEV;
 
        /* Now try to get the controller to respond to a no-op */
+       dev_warn(&pdev->dev, "Waiting for controller to respond to no-op\n");
        for (i = 0; i < CCISS_POST_RESET_NOOP_RETRIES; i++) {
                if (cciss_noop(pdev) == 0)
                        break;
@@ -4591,6 +4772,148 @@ static __devinit int cciss_init_reset_devices(struct pci_dev *pdev)
        return 0;
 }
 
+static __devinit int cciss_allocate_cmd_pool(ctlr_info_t *h)
+{
+       h->cmd_pool_bits = kmalloc(
+               DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG) *
+               sizeof(unsigned long), GFP_KERNEL);
+       h->cmd_pool = pci_alloc_consistent(h->pdev,
+               h->nr_cmds * sizeof(CommandList_struct),
+               &(h->cmd_pool_dhandle));
+       h->errinfo_pool = pci_alloc_consistent(h->pdev,
+               h->nr_cmds * sizeof(ErrorInfo_struct),
+               &(h->errinfo_pool_dhandle));
+       if ((h->cmd_pool_bits == NULL)
+               || (h->cmd_pool == NULL)
+               || (h->errinfo_pool == NULL)) {
+               dev_err(&h->pdev->dev, "out of memory");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static __devinit int cciss_allocate_scatterlists(ctlr_info_t *h)
+{
+       int i;
+
+       /* zero it, so that on free we need not know how many were alloc'ed */
+       h->scatter_list = kzalloc(h->max_commands *
+                               sizeof(struct scatterlist *), GFP_KERNEL);
+       if (!h->scatter_list)
+               return -ENOMEM;
+
+       for (i = 0; i < h->nr_cmds; i++) {
+               h->scatter_list[i] = kmalloc(sizeof(struct scatterlist) *
+                                               h->maxsgentries, GFP_KERNEL);
+               if (h->scatter_list[i] == NULL) {
+                       dev_err(&h->pdev->dev, "could not allocate "
+                               "s/g lists\n");
+                       return -ENOMEM;
+               }
+       }
+       return 0;
+}
+
+static void cciss_free_scatterlists(ctlr_info_t *h)
+{
+       int i;
+
+       if (h->scatter_list) {
+               for (i = 0; i < h->nr_cmds; i++)
+                       kfree(h->scatter_list[i]);
+               kfree(h->scatter_list);
+       }
+}
+
+static void cciss_free_cmd_pool(ctlr_info_t *h)
+{
+       kfree(h->cmd_pool_bits);
+       if (h->cmd_pool)
+               pci_free_consistent(h->pdev,
+                       h->nr_cmds * sizeof(CommandList_struct),
+                       h->cmd_pool, h->cmd_pool_dhandle);
+       if (h->errinfo_pool)
+               pci_free_consistent(h->pdev,
+                       h->nr_cmds * sizeof(ErrorInfo_struct),
+                       h->errinfo_pool, h->errinfo_pool_dhandle);
+}
+
+static int cciss_request_irq(ctlr_info_t *h,
+       irqreturn_t (*msixhandler)(int, void *),
+       irqreturn_t (*intxhandler)(int, void *))
+{
+       if (h->msix_vector || h->msi_vector) {
+               if (!request_irq(h->intr[PERF_MODE_INT], msixhandler,
+                               IRQF_DISABLED, h->devname, h))
+                       return 0;
+               dev_err(&h->pdev->dev, "Unable to get msi irq %d"
+                       " for %s\n", h->intr[PERF_MODE_INT],
+                       h->devname);
+               return -1;
+       }
+
+       if (!request_irq(h->intr[PERF_MODE_INT], intxhandler,
+                       IRQF_DISABLED, h->devname, h))
+               return 0;
+       dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n",
+               h->intr[PERF_MODE_INT], h->devname);
+       return -1;
+}
+
+static int __devinit cciss_kdump_soft_reset(ctlr_info_t *h)
+{
+       if (cciss_send_reset(h, CTLR_LUNID, CCISS_RESET_TYPE_CONTROLLER)) {
+               dev_warn(&h->pdev->dev, "Resetting array controller failed.\n");
+               return -EIO;
+       }
+
+       dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n");
+       if (cciss_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY)) {
+               dev_warn(&h->pdev->dev, "Soft reset had no effect.\n");
+               return -1;
+       }
+
+       dev_info(&h->pdev->dev, "Board reset, awaiting READY status.\n");
+       if (cciss_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY)) {
+               dev_warn(&h->pdev->dev, "Board failed to become ready "
+                       "after soft reset.\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static void cciss_undo_allocations_after_kdump_soft_reset(ctlr_info_t *h)
+{
+       int ctlr = h->ctlr;
+
+       free_irq(h->intr[PERF_MODE_INT], h);
+#ifdef CONFIG_PCI_MSI
+       if (h->msix_vector)
+               pci_disable_msix(h->pdev);
+       else if (h->msi_vector)
+               pci_disable_msi(h->pdev);
+#endif /* CONFIG_PCI_MSI */
+       cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds);
+       cciss_free_scatterlists(h);
+       cciss_free_cmd_pool(h);
+       kfree(h->blockFetchTable);
+       if (h->reply_pool)
+               pci_free_consistent(h->pdev, h->max_commands * sizeof(__u64),
+                               h->reply_pool, h->reply_pool_dhandle);
+       if (h->transtable)
+               iounmap(h->transtable);
+       if (h->cfgtable)
+               iounmap(h->cfgtable);
+       if (h->vaddr)
+               iounmap(h->vaddr);
+       unregister_blkdev(h->major, h->devname);
+       cciss_destroy_hba_sysfs_entry(h);
+       pci_release_regions(h->pdev);
+       kfree(h);
+       hba[ctlr] = NULL;
+}
+
 /*
  *  This is it.  Find all the controllers and register them.  I really hate
  *  stealing all these major device numbers.
@@ -4601,15 +4924,28 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 {
        int i;
        int j = 0;
-       int k = 0;
        int rc;
+       int try_soft_reset = 0;
        int dac, return_code;
        InquiryData_struct *inq_buff;
        ctlr_info_t *h;
+       unsigned long flags;
 
        rc = cciss_init_reset_devices(pdev);
-       if (rc)
-               return rc;
+       if (rc) {
+               if (rc != -ENOTSUPP)
+                       return rc;
+               /* If the reset fails in a particular way (it has no way to do
+                * a proper hard reset, so returns -ENOTSUPP) we can try to do
+                * a soft reset once we get the controller configured up to the
+                * point that it can accept a command.
+                */
+               try_soft_reset = 1;
+               rc = 0;
+       }
+
+reinit_after_soft_reset:
+
        i = alloc_cciss_hba(pdev);
        if (i < 0)
                return -1;
@@ -4627,6 +4963,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        sprintf(h->devname, "cciss%d", i);
        h->ctlr = i;
 
+       if (cciss_tape_cmds < 2)
+               cciss_tape_cmds = 2;
+       if (cciss_tape_cmds > 16)
+               cciss_tape_cmds = 16;
+
        init_completion(&h->scan_wait);
 
        if (cciss_create_hba_sysfs_entry(h))
@@ -4662,62 +5003,20 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 
        /* make sure the board interrupts are off */
        h->access.set_intr_mask(h, CCISS_INTR_OFF);
-       if (h->msi_vector || h->msix_vector) {
-               if (request_irq(h->intr[PERF_MODE_INT],
-                               do_cciss_msix_intr,
-                               IRQF_DISABLED, h->devname, h)) {
-                       dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n",
-                              h->intr[PERF_MODE_INT], h->devname);
-                       goto clean2;
-               }
-       } else {
-               if (request_irq(h->intr[PERF_MODE_INT], do_cciss_intx,
-                               IRQF_DISABLED, h->devname, h)) {
-                       dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n",
-                              h->intr[PERF_MODE_INT], h->devname);
-                       goto clean2;
-               }
-       }
+       rc = cciss_request_irq(h, do_cciss_msix_intr, do_cciss_intx);
+       if (rc)
+               goto clean2;
 
        dev_info(&h->pdev->dev, "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n",
               h->devname, pdev->device, pci_name(pdev),
               h->intr[PERF_MODE_INT], dac ? "" : " not");
 
-       h->cmd_pool_bits =
-           kmalloc(DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG)
-                       * sizeof(unsigned long), GFP_KERNEL);
-       h->cmd_pool = (CommandList_struct *)
-           pci_alloc_consistent(h->pdev,
-                   h->nr_cmds * sizeof(CommandList_struct),
-                   &(h->cmd_pool_dhandle));
-       h->errinfo_pool = (ErrorInfo_struct *)
-           pci_alloc_consistent(h->pdev,
-                   h->nr_cmds * sizeof(ErrorInfo_struct),
-                   &(h->errinfo_pool_dhandle));
-       if ((h->cmd_pool_bits == NULL)
-           || (h->cmd_pool == NULL)
-           || (h->errinfo_pool == NULL)) {
-               dev_err(&h->pdev->dev, "out of memory");
+       if (cciss_allocate_cmd_pool(h))
                goto clean4;
-       }
 
-       /* Need space for temp scatter list */
-       h->scatter_list = kmalloc(h->max_commands *
-                                               sizeof(struct scatterlist *),
-                                               GFP_KERNEL);
-       if (!h->scatter_list)
+       if (cciss_allocate_scatterlists(h))
                goto clean4;
 
-       for (k = 0; k < h->nr_cmds; k++) {
-               h->scatter_list[k] = kmalloc(sizeof(struct scatterlist) *
-                                                       h->maxsgentries,
-                                                       GFP_KERNEL);
-               if (h->scatter_list[k] == NULL) {
-                       dev_err(&h->pdev->dev,
-                               "could not allocate s/g lists\n");
-                       goto clean4;
-               }
-       }
        h->cmd_sg_list = cciss_allocate_sg_chain_blocks(h,
                h->chainsize, h->nr_cmds);
        if (!h->cmd_sg_list && h->chainsize > 0)
@@ -4741,6 +5040,62 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
                h->gendisk[j] = NULL;
        }
 
+       /* At this point, the controller is ready to take commands.
+        * Now, if reset_devices and the hard reset didn't work, try
+        * the soft reset and see if that works.
+        */
+       if (try_soft_reset) {
+
+               /* This is kind of gross.  We may or may not get a completion
+                * from the soft reset command, and if we do, then the value
+                * from the fifo may or may not be valid.  So, we wait 10 secs
+                * after the reset throwing away any completions we get during
+                * that time.  Unregister the interrupt handler and register
+                * fake ones to scoop up any residual completions.
+                */
+               spin_lock_irqsave(&h->lock, flags);
+               h->access.set_intr_mask(h, CCISS_INTR_OFF);
+               spin_unlock_irqrestore(&h->lock, flags);
+               free_irq(h->intr[PERF_MODE_INT], h);
+               rc = cciss_request_irq(h, cciss_msix_discard_completions,
+                                       cciss_intx_discard_completions);
+               if (rc) {
+                       dev_warn(&h->pdev->dev, "Failed to request_irq after "
+                               "soft reset.\n");
+                       goto clean4;
+               }
+
+               rc = cciss_kdump_soft_reset(h);
+               if (rc) {
+                       dev_warn(&h->pdev->dev, "Soft reset failed.\n");
+                       goto clean4;
+               }
+
+               dev_info(&h->pdev->dev, "Board READY.\n");
+               dev_info(&h->pdev->dev,
+                       "Waiting for stale completions to drain.\n");
+               h->access.set_intr_mask(h, CCISS_INTR_ON);
+               msleep(10000);
+               h->access.set_intr_mask(h, CCISS_INTR_OFF);
+
+               rc = controller_reset_failed(h->cfgtable);
+               if (rc)
+                       dev_info(&h->pdev->dev,
+                               "Soft reset appears to have failed.\n");
+
+               /* since the controller's reset, we have to go back and re-init
+                * everything.  Easiest to just forget what we've done and do it
+                * all over again.
+                */
+               cciss_undo_allocations_after_kdump_soft_reset(h);
+               try_soft_reset = 0;
+               if (rc)
+                       /* don't go to clean4, we already unallocated */
+                       return -ENODEV;
+
+               goto reinit_after_soft_reset;
+       }
+
        cciss_scsi_setup(h);
 
        /* Turn the interrupts on so we can service requests */
@@ -4775,21 +5130,9 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        return 1;
 
 clean4:
-       kfree(h->cmd_pool_bits);
-       /* Free up sg elements */
-       for (k-- ; k >= 0; k--)
-               kfree(h->scatter_list[k]);
-       kfree(h->scatter_list);
+       cciss_free_cmd_pool(h);
+       cciss_free_scatterlists(h);
        cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds);
-       if (h->cmd_pool)
-               pci_free_consistent(h->pdev,
-                                   h->nr_cmds * sizeof(CommandList_struct),
-                                   h->cmd_pool, h->cmd_pool_dhandle);
-       if (h->errinfo_pool)
-               pci_free_consistent(h->pdev,
-                                   h->nr_cmds * sizeof(ErrorInfo_struct),
-                                   h->errinfo_pool,
-                                   h->errinfo_pool_dhandle);
        free_irq(h->intr[PERF_MODE_INT], h);
 clean2:
        unregister_blkdev(h->major, h->devname);
@@ -4887,16 +5230,16 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
        iounmap(h->cfgtable);
        iounmap(h->vaddr);
 
-       pci_free_consistent(h->pdev, h->nr_cmds * sizeof(CommandList_struct),
-                           h->cmd_pool, h->cmd_pool_dhandle);
-       pci_free_consistent(h->pdev, h->nr_cmds * sizeof(ErrorInfo_struct),
-                           h->errinfo_pool, h->errinfo_pool_dhandle);
-       kfree(h->cmd_pool_bits);
+       cciss_free_cmd_pool(h);
        /* Free up sg elements */
        for (j = 0; j < h->nr_cmds; j++)
                kfree(h->scatter_list[j]);
        kfree(h->scatter_list);
        cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds);
+       kfree(h->blockFetchTable);
+       if (h->reply_pool)
+               pci_free_consistent(h->pdev, h->max_commands * sizeof(__u64),
+                               h->reply_pool, h->reply_pool_dhandle);
        /*
         * Deliberately omit pci_disable_device(): it does something nasty to
         * Smart Array controllers that pci_enable_device does not undo
index 554bbd907d144500817a615702ab6155cb7f7243..16b4d58d84dd1e690a63b2f91efdce58aafe8d44 100644 (file)
@@ -200,7 +200,7 @@ struct ctlr_info
  * the above.
  */
 #define CCISS_BOARD_READY_WAIT_SECS (120)
-#define CCISS_BOARD_NOT_READY_WAIT_SECS (10)
+#define CCISS_BOARD_NOT_READY_WAIT_SECS (100)
 #define CCISS_BOARD_READY_POLL_INTERVAL_MSECS (100)
 #define CCISS_BOARD_READY_ITERATIONS \
        ((CCISS_BOARD_READY_WAIT_SECS * 1000) / \
@@ -209,8 +209,9 @@ struct ctlr_info
        ((CCISS_BOARD_NOT_READY_WAIT_SECS * 1000) / \
                CCISS_BOARD_READY_POLL_INTERVAL_MSECS)
 #define CCISS_POST_RESET_PAUSE_MSECS (3000)
-#define CCISS_POST_RESET_NOOP_INTERVAL_MSECS (1000)
+#define CCISS_POST_RESET_NOOP_INTERVAL_MSECS (4000)
 #define CCISS_POST_RESET_NOOP_RETRIES (12)
+#define CCISS_POST_RESET_NOOP_TIMEOUT_MSECS (10000)
 
 /* 
        Send the command to the hardware 
@@ -239,11 +240,13 @@ static void SA5_intr_mask(ctlr_info_t *h, unsigned long val)
        { /* Turn interrupts on */
                h->interrupts_enabled = 1;
                writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+               (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
        } else /* Turn them off */
        {
                h->interrupts_enabled = 0;
                writel( SA5_INTR_OFF, 
                        h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+               (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
        }
 }
 /*
@@ -257,11 +260,13 @@ static void SA5B_intr_mask(ctlr_info_t *h, unsigned long val)
         { /* Turn interrupts on */
                h->interrupts_enabled = 1;
                 writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+               (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
         } else /* Turn them off */
         {
                h->interrupts_enabled = 0;
                 writel( SA5B_INTR_OFF,
                         h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+               (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
         }
 }
 
@@ -271,10 +276,12 @@ static void SA5_performant_intr_mask(ctlr_info_t *h, unsigned long val)
        if (val) { /* turn on interrupts */
                h->interrupts_enabled = 1;
                writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+               (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
        } else {
                h->interrupts_enabled = 0;
                writel(SA5_PERF_INTR_OFF,
                                h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+               (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
        }
 }
 
index cd441bef031f1a4806ba29df8067c47b050bfae7..d9be6b4d49a6a0e3bc950d3cb395edbef5af6d3b 100644 (file)
@@ -53,6 +53,7 @@
 #define CFGTBL_ChangeReq        0x00000001l
 #define CFGTBL_AccCmds          0x00000001l
 #define DOORBELL_CTLR_RESET     0x00000004l
+#define DOORBELL_CTLR_RESET2    0x00000020l
 
 #define CFGTBL_Trans_Simple     0x00000002l
 #define CFGTBL_Trans_Performant 0x00000004l
@@ -142,6 +143,14 @@ typedef struct _ReadCapdata_struct_16
 #define BMIC_CACHE_FLUSH 0xc2
 #define CCISS_CACHE_FLUSH 0x01 /* C2 was already being used by CCISS */
 
+#define CCISS_ABORT_MSG 0x00
+#define CCISS_RESET_MSG 0x01
+#define CCISS_RESET_TYPE_CONTROLLER 0x00
+#define CCISS_RESET_TYPE_BUS 0x01
+#define CCISS_RESET_TYPE_TARGET 0x03
+#define CCISS_RESET_TYPE_LUN 0x04
+#define CCISS_NOOP_MSG 0x03
+
 /* Command List Structure */
 #define CTLR_LUNID "\0\0\0\0\0\0\0\0"
 
@@ -235,6 +244,8 @@ typedef struct _CfgTable_struct {
   u8              reserved[0x78 - 0x58];
   u32             misc_fw_support; /* offset 0x78 */
 #define MISC_FW_DOORBELL_RESET (0x02)
+#define MISC_FW_DOORBELL_RESET2 (0x10)
+       u8         driver_version[32];
 } CfgTable_struct;
 
 struct TransTable_struct {
index df793803f5ae5c70615df404a442d525442184a0..696100241a6fd017c655c424004af621ae0a491b 100644 (file)
@@ -84,7 +84,6 @@ static struct scsi_host_template cciss_driver_template = {
        .proc_name              = "cciss",
        .proc_info              = cciss_scsi_proc_info,
        .queuecommand           = cciss_scsi_queue_command,
-       .can_queue              = SCSI_CCISS_CAN_QUEUE,
        .this_id                = 7,
        .cmd_per_lun            = 1,
        .use_clustering         = DISABLE_CLUSTERING,
@@ -108,16 +107,13 @@ struct cciss_scsi_cmd_stack_elem_t {
 
 #pragma pack()
 
-#define CMD_STACK_SIZE (SCSI_CCISS_CAN_QUEUE * \
-               CCISS_MAX_SCSI_DEVS_PER_HBA + 2)
-                       // plus two for init time usage
-
 #pragma pack(1)
 struct cciss_scsi_cmd_stack_t {
        struct cciss_scsi_cmd_stack_elem_t *pool;
-       struct cciss_scsi_cmd_stack_elem_t *elem[CMD_STACK_SIZE];
+       struct cciss_scsi_cmd_stack_elem_t **elem;
        dma_addr_t cmd_pool_handle;
        int top;
+       int nelems;
 };
 #pragma pack()
 
@@ -191,7 +187,7 @@ scsi_cmd_free(ctlr_info_t *h, CommandList_struct *c)
        sa = h->scsi_ctlr;
        stk = &sa->cmd_stack; 
        stk->top++;
-       if (stk->top >= CMD_STACK_SIZE) {
+       if (stk->top >= stk->nelems) {
                dev_err(&h->pdev->dev,
                        "scsi_cmd_free called too many times.\n");
                BUG();
@@ -206,13 +202,14 @@ scsi_cmd_stack_setup(ctlr_info_t *h, struct cciss_scsi_adapter_data_t *sa)
        struct cciss_scsi_cmd_stack_t *stk;
        size_t size;
 
+       stk = &sa->cmd_stack;
+       stk->nelems = cciss_tape_cmds + 2;
        sa->cmd_sg_list = cciss_allocate_sg_chain_blocks(h,
-               h->chainsize, CMD_STACK_SIZE);
+               h->chainsize, stk->nelems);
        if (!sa->cmd_sg_list && h->chainsize > 0)
                return -ENOMEM;
 
-       stk = &sa->cmd_stack; 
-       size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
+       size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * stk->nelems;
 
        /* Check alignment, see cciss_cmd.h near CommandList_struct def. */
        BUILD_BUG_ON((sizeof(*stk->pool) % COMMANDLIST_ALIGNMENT) != 0);
@@ -221,18 +218,23 @@ scsi_cmd_stack_setup(ctlr_info_t *h, struct cciss_scsi_adapter_data_t *sa)
                pci_alloc_consistent(h->pdev, size, &stk->cmd_pool_handle);
 
        if (stk->pool == NULL) {
-               cciss_free_sg_chain_blocks(sa->cmd_sg_list, CMD_STACK_SIZE);
+               cciss_free_sg_chain_blocks(sa->cmd_sg_list, stk->nelems);
                sa->cmd_sg_list = NULL;
                return -ENOMEM;
        }
-
-       for (i=0; i<CMD_STACK_SIZE; i++) {
+       stk->elem = kmalloc(sizeof(stk->elem[0]) * stk->nelems, GFP_KERNEL);
+       if (!stk->elem) {
+               pci_free_consistent(h->pdev, size, stk->pool,
+               stk->cmd_pool_handle);
+               return -1;
+       }
+       for (i = 0; i < stk->nelems; i++) {
                stk->elem[i] = &stk->pool[i];
                stk->elem[i]->busaddr = (__u32) (stk->cmd_pool_handle + 
                        (sizeof(struct cciss_scsi_cmd_stack_elem_t) * i));
                stk->elem[i]->cmdindex = i;
        }
-       stk->top = CMD_STACK_SIZE-1;
+       stk->top = stk->nelems-1;
        return 0;
 }
 
@@ -245,16 +247,18 @@ scsi_cmd_stack_free(ctlr_info_t *h)
 
        sa = h->scsi_ctlr;
        stk = &sa->cmd_stack; 
-       if (stk->top != CMD_STACK_SIZE-1) {
+       if (stk->top != stk->nelems-1) {
                dev_warn(&h->pdev->dev,
                        "bug: %d scsi commands are still outstanding.\n",
-                       CMD_STACK_SIZE - stk->top);
+                       stk->nelems - stk->top);
        }
-       size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
+       size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * stk->nelems;
 
        pci_free_consistent(h->pdev, size, stk->pool, stk->cmd_pool_handle);
        stk->pool = NULL;
-       cciss_free_sg_chain_blocks(sa->cmd_sg_list, CMD_STACK_SIZE);
+       cciss_free_sg_chain_blocks(sa->cmd_sg_list, stk->nelems);
+       kfree(stk->elem);
+       stk->elem = NULL;
 }
 
 #if 0
@@ -859,6 +863,7 @@ cciss_scsi_detect(ctlr_info_t *h)
        sh->io_port = 0;        // good enough?  FIXME, 
        sh->n_io_port = 0;      // I don't think we use these two...
        sh->this_id = SELF_SCSI_ID;  
+       sh->can_queue = cciss_tape_cmds;
        sh->sg_tablesize = h->maxsgentries;
        sh->max_cmd_len = MAX_COMMAND_SIZE;
 
index 6d5822fe851aeaf6759b76ea68fd39c116ea81d7..e71d986727cac7c4a11b0e2f2b6c568ec4f2e829 100644 (file)
                   addressible natively, and may in fact turn
                   out to be not scsi at all. */
 
-#define SCSI_CCISS_CAN_QUEUE 2
 
 /* 
 
-Note, cmd_per_lun could give us some trouble, so I'm setting it very low.
-Likewise, SCSI_CCISS_CAN_QUEUE is set very conservatively.
-
 If the upper scsi layer tries to track how many commands we have 
 outstanding, it will be operating under the misapprehension that it is
 the only one sending us requests.  We also have the block interface,
index c6828b68d77b00831e3f45ae5555f9c2c2751c7a..09ef9a878ef06335393cbc4509f38425a5465713 100644 (file)
@@ -28,7 +28,7 @@
 #include "drbd_int.h"
 #include "drbd_wrappers.h"
 
-/* We maintain a trivial check sum in our on disk activity log.
+/* We maintain a trivial checksum in our on disk activity log.
  * With that we can ensure correct operation even when the storage
  * device might do a partial (last) sector write while losing power.
  */
index 76210ba401ac4d3e8871c4eac99336aa67d899cd..f440a02dfdb15519799c64e2ab7c219db9a95ab5 100644 (file)
@@ -74,7 +74,7 @@
  *     as we are "attached" to a local disk, which at 32 GiB for 1PiB storage
  *     seems excessive.
  *
- *     We plan to reduce the amount of in-core bitmap pages by pageing them in
+ *     We plan to reduce the amount of in-core bitmap pages by paging them in
  *     and out against their on-disk location as necessary, but need to make
  *     sure we don't cause too much meta data IO, and must not deadlock in
  *     tight memory situations. This needs some more work.
@@ -200,7 +200,7 @@ void drbd_bm_unlock(struct drbd_conf *mdev)
  * we if bits have been cleared since last IO. */
 #define BM_PAGE_LAZY_WRITEOUT  28
 
-/* store_page_idx uses non-atomic assingment. It is only used directly after
+/* store_page_idx uses non-atomic assignment. It is only used directly after
  * allocating the page.  All other bm_set_page_* and bm_clear_page_* need to
  * use atomic bit manipulation, as set_out_of_sync (and therefore bitmap
  * changes) may happen from various contexts, and wait_on_bit/wake_up_bit
@@ -318,7 +318,7 @@ static void bm_unmap(unsigned long *p_addr)
 /* word offset from start of bitmap to word number _in_page_
  * modulo longs per page
 #define MLPP(X) ((X) % (PAGE_SIZE/sizeof(long))
- hm, well, Philipp thinks gcc might not optimze the % into & (... - 1)
+ hm, well, Philipp thinks gcc might not optimize the % into & (... - 1)
  so do it explicitly:
  */
 #define MLPP(X) ((X) & ((PAGE_SIZE/sizeof(long))-1))
index d871b14ed5a186a22d758308f1a498fbfe66de26..ef2ceed3be4b2767f6b3886a48a002609597e2e8 100644 (file)
@@ -700,7 +700,7 @@ struct drbd_request {
         * see drbd_endio_pri(). */
        struct bio *private_bio;
 
-       struct hlist_node colision;
+       struct hlist_node collision;
        sector_t sector;
        unsigned int size;
        unsigned int epoch; /* barrier_nr */
@@ -766,7 +766,7 @@ struct digest_info {
 
 struct drbd_epoch_entry {
        struct drbd_work w;
-       struct hlist_node colision;
+       struct hlist_node collision;
        struct drbd_epoch *epoch; /* for writes */
        struct drbd_conf *mdev;
        struct page *pages;
@@ -1129,6 +1129,8 @@ struct drbd_conf {
        int rs_in_flight; /* resync sectors in flight (to proxy, in proxy and from proxy) */
        int rs_planed;    /* resync sectors already planned */
        atomic_t ap_in_flight; /* App sectors in flight (waiting for ack) */
+       int peer_max_bio_size;
+       int local_max_bio_size;
 };
 
 static inline struct drbd_conf *minor_to_mdev(unsigned int minor)
@@ -1218,8 +1220,6 @@ extern void drbd_free_resources(struct drbd_conf *mdev);
 extern void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr,
                       unsigned int set_size);
 extern void tl_clear(struct drbd_conf *mdev);
-enum drbd_req_event;
-extern void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what);
 extern void _tl_add_barrier(struct drbd_conf *, struct drbd_tl_epoch *);
 extern void drbd_free_sock(struct drbd_conf *mdev);
 extern int drbd_send(struct drbd_conf *mdev, struct socket *sock,
@@ -1434,6 +1434,7 @@ struct bm_extent {
  * hash table. */
 #define HT_SHIFT 8
 #define DRBD_MAX_BIO_SIZE (1U<<(9+HT_SHIFT))
+#define DRBD_MAX_BIO_SIZE_SAFE (1 << 12)       /* Works always = 4k */
 
 #define DRBD_MAX_SIZE_H80_PACKET (1 << 15) /* The old header only allows packets up to 32Kib data */
 
@@ -1518,9 +1519,9 @@ extern void drbd_resume_io(struct drbd_conf *mdev);
 extern char *ppsize(char *buf, unsigned long long size);
 extern sector_t drbd_new_dev_size(struct drbd_conf *, struct drbd_backing_dev *, int);
 enum determine_dev_size { dev_size_error = -1, unchanged = 0, shrunk = 1, grew = 2 };
-extern enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *, enum dds_flags) __must_hold(local);
+extern enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *, enum dds_flags) __must_hold(local);
 extern void resync_after_online_grow(struct drbd_conf *);
-extern void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int) __must_hold(local);
+extern void drbd_reconsider_max_bio_size(struct drbd_conf *mdev);
 extern enum drbd_state_rv drbd_set_role(struct drbd_conf *mdev,
                                        enum drbd_role new_role,
                                        int force);
@@ -1828,6 +1829,8 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach,
                if (!forcedetach) {
                        if (__ratelimit(&drbd_ratelimit_state))
                                dev_err(DEV, "Local IO failed in %s.\n", where);
+                       if (mdev->state.disk > D_INCONSISTENT)
+                               _drbd_set_state(_NS(mdev, disk, D_INCONSISTENT), CS_HARD, NULL);
                        break;
                }
                /* NOTE fall through to detach case if forcedetach set */
@@ -2153,6 +2156,10 @@ static inline int get_net_conf(struct drbd_conf *mdev)
 static inline void put_ldev(struct drbd_conf *mdev)
 {
        int i = atomic_dec_return(&mdev->local_cnt);
+
+       /* This may be called from some endio handler,
+        * so we must not sleep here. */
+
        __release(local);
        D_ASSERT(i >= 0);
        if (i == 0) {
index 5b525c179f39919d6e245948a434e3248c9f329b..0358e55356c85f13ce96670f94b4cef626ce70ae 100644 (file)
@@ -745,6 +745,9 @@ is_valid_state(struct drbd_conf *mdev, union drbd_state ns)
                  mdev->agreed_pro_version < 88)
                rv = SS_NOT_SUPPORTED;
 
+       else if (ns.conn >= C_CONNECTED && ns.pdsk == D_UNKNOWN)
+               rv = SS_CONNECTED_OUTDATES;
+
        return rv;
 }
 
@@ -1565,6 +1568,10 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
                put_ldev(mdev);
        }
 
+       /* Notify peer that I had a local IO error, and did not detached.. */
+       if (os.disk == D_UP_TO_DATE && ns.disk == D_INCONSISTENT)
+               drbd_send_state(mdev);
+
        /* Disks got bigger while they were detached */
        if (ns.disk > D_NEGOTIATING && ns.pdsk > D_NEGOTIATING &&
            test_and_clear_bit(RESYNC_AFTER_NEG, &mdev->flags)) {
@@ -2064,7 +2071,7 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl
 {
        struct p_sizes p;
        sector_t d_size, u_size;
-       int q_order_type;
+       int q_order_type, max_bio_size;
        int ok;
 
        if (get_ldev_if_state(mdev, D_NEGOTIATING)) {
@@ -2072,17 +2079,20 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl
                d_size = drbd_get_max_capacity(mdev->ldev);
                u_size = mdev->ldev->dc.disk_size;
                q_order_type = drbd_queue_order_type(mdev);
+               max_bio_size = queue_max_hw_sectors(mdev->ldev->backing_bdev->bd_disk->queue) << 9;
+               max_bio_size = min_t(int, max_bio_size, DRBD_MAX_BIO_SIZE);
                put_ldev(mdev);
        } else {
                d_size = 0;
                u_size = 0;
                q_order_type = QUEUE_ORDERED_NONE;
+               max_bio_size = DRBD_MAX_BIO_SIZE; /* ... multiple BIOs per peer_request */
        }
 
        p.d_size = cpu_to_be64(d_size);
        p.u_size = cpu_to_be64(u_size);
        p.c_size = cpu_to_be64(trigger_reply ? 0 : drbd_get_capacity(mdev->this_bdev));
-       p.max_bio_size = cpu_to_be32(queue_max_hw_sectors(mdev->rq_queue) << 9);
+       p.max_bio_size = cpu_to_be32(max_bio_size);
        p.queue_order_type = cpu_to_be16(q_order_type);
        p.dds_flags = cpu_to_be16(flags);
 
@@ -2722,7 +2732,7 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req)
 
                /* double check digest, sometimes buffers have been modified in flight. */
                if (dgs > 0 && dgs <= 64) {
-                       /* 64 byte, 512 bit, is the larges digest size
+                       /* 64 byte, 512 bit, is the largest digest size
                         * currently supported in kernel crypto. */
                        unsigned char digest[64];
                        drbd_csum_bio(mdev, mdev->integrity_w_tfm, req->master_bio, digest);
@@ -3041,6 +3051,8 @@ void drbd_init_set_defaults(struct drbd_conf *mdev)
        mdev->agreed_pro_version = PRO_VERSION_MAX;
        mdev->write_ordering = WO_bdev_flush;
        mdev->resync_wenr = LC_FREE;
+       mdev->peer_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE;
+       mdev->local_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE;
 }
 
 void drbd_mdev_cleanup(struct drbd_conf *mdev)
@@ -3275,7 +3287,7 @@ static void drbd_delete_device(unsigned int minor)
 
        drbd_release_ee_lists(mdev);
 
-       /* should be free'd on disconnect? */
+       /* should be freed on disconnect? */
        kfree(mdev->ee_hash);
        /*
        mdev->ee_hash_s = 0;
@@ -3415,7 +3427,9 @@ struct drbd_conf *drbd_new_device(unsigned int minor)
        q->backing_dev_info.congested_data = mdev;
 
        blk_queue_make_request(q, drbd_make_request);
-       blk_queue_max_hw_sectors(q, DRBD_MAX_BIO_SIZE >> 9);
+       /* Setting the max_hw_sectors to an odd value of 8kibyte here
+          This triggers a max_bio_size message upon first attach or connect */
+       blk_queue_max_hw_sectors(q, DRBD_MAX_BIO_SIZE_SAFE >> 8);
        blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
        blk_queue_merge_bvec(q, drbd_merge_bvec);
        q->queue_lock = &mdev->req_lock;
@@ -3627,7 +3641,8 @@ struct meta_data_on_disk {
              /* `-- act_log->nr_elements <-- sync_conf.al_extents */
        u32 bm_offset;         /* offset to the bitmap, from here */
        u32 bm_bytes_per_bit;  /* BM_BLOCK_SIZE */
-       u32 reserved_u32[4];
+       u32 la_peer_max_bio_size;   /* last peer max_bio_size */
+       u32 reserved_u32[3];
 
 } __packed;
 
@@ -3668,6 +3683,7 @@ void drbd_md_sync(struct drbd_conf *mdev)
        buffer->device_uuid = cpu_to_be64(mdev->ldev->md.device_uuid);
 
        buffer->bm_offset = cpu_to_be32(mdev->ldev->md.bm_offset);
+       buffer->la_peer_max_bio_size = cpu_to_be32(mdev->peer_max_bio_size);
 
        D_ASSERT(drbd_md_ss__(mdev, mdev->ldev) == mdev->ldev->md.md_offset);
        sector = mdev->ldev->md.md_offset;
@@ -3751,6 +3767,15 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
        mdev->sync_conf.al_extents = be32_to_cpu(buffer->al_nr_extents);
        bdev->md.device_uuid = be64_to_cpu(buffer->device_uuid);
 
+       spin_lock_irq(&mdev->req_lock);
+       if (mdev->state.conn < C_CONNECTED) {
+               int peer;
+               peer = be32_to_cpu(buffer->la_peer_max_bio_size);
+               peer = max_t(int, peer, DRBD_MAX_BIO_SIZE_SAFE);
+               mdev->peer_max_bio_size = peer;
+       }
+       spin_unlock_irq(&mdev->req_lock);
+
        if (mdev->sync_conf.al_extents < 7)
                mdev->sync_conf.al_extents = 127;
 
index 03b29f78a37d78ac8955db9ae43ca8609b963d91..515bcd948a43d7ee04650a06044e7bea6bc4742c 100644 (file)
@@ -272,9 +272,28 @@ static int _try_outdate_peer_async(void *data)
 {
        struct drbd_conf *mdev = (struct drbd_conf *)data;
        enum drbd_disk_state nps;
+       union drbd_state ns;
 
        nps = drbd_try_outdate_peer(mdev);
-       drbd_request_state(mdev, NS(pdsk, nps));
+
+       /* Not using
+          drbd_request_state(mdev, NS(pdsk, nps));
+          here, because we might were able to re-establish the connection
+          in the meantime. This can only partially be solved in the state's
+          engine is_valid_state() and is_valid_state_transition()
+          functions.
+
+          nps can be D_INCONSISTENT, D_OUTDATED or D_UNKNOWN.
+          pdsk == D_INCONSISTENT while conn >= C_CONNECTED is valid,
+          therefore we have to have the pre state change check here.
+       */
+       spin_lock_irq(&mdev->req_lock);
+       ns = mdev->state;
+       if (ns.conn < C_WF_REPORT_PARAMS) {
+               ns.pdsk = nps;
+               _drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
+       }
+       spin_unlock_irq(&mdev->req_lock);
 
        return 0;
 }
@@ -577,7 +596,7 @@ void drbd_resume_io(struct drbd_conf *mdev)
  * Returns 0 on success, negative return values indicate errors.
  * You should call drbd_md_sync() after calling this function.
  */
-enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *mdev, enum dds_flags flags) __must_hold(local)
+enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags) __must_hold(local)
 {
        sector_t prev_first_sect, prev_size; /* previous meta location */
        sector_t la_size;
@@ -773,30 +792,78 @@ static int drbd_check_al_size(struct drbd_conf *mdev)
        return 0;
 }
 
-void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_bio_size) __must_hold(local)
+static void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_bio_size)
 {
        struct request_queue * const q = mdev->rq_queue;
-       struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
-       int max_segments = mdev->ldev->dc.max_bio_bvecs;
-       int max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9);
+       int max_hw_sectors = max_bio_size >> 9;
+       int max_segments = 0;
+
+       if (get_ldev_if_state(mdev, D_ATTACHING)) {
+               struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
+
+               max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9);
+               max_segments = mdev->ldev->dc.max_bio_bvecs;
+               put_ldev(mdev);
+       }
 
        blk_queue_logical_block_size(q, 512);
        blk_queue_max_hw_sectors(q, max_hw_sectors);
        /* This is the workaround for "bio would need to, but cannot, be split" */
        blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS);
        blk_queue_segment_boundary(q, PAGE_CACHE_SIZE-1);
-       blk_queue_stack_limits(q, b);
 
-       dev_info(DEV, "max BIO size = %u\n", queue_max_hw_sectors(q) << 9);
+       if (get_ldev_if_state(mdev, D_ATTACHING)) {
+               struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
+
+               blk_queue_stack_limits(q, b);
 
-       if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) {
-               dev_info(DEV, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
-                    q->backing_dev_info.ra_pages,
-                    b->backing_dev_info.ra_pages);
-               q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages;
+               if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) {
+                       dev_info(DEV, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
+                                q->backing_dev_info.ra_pages,
+                                b->backing_dev_info.ra_pages);
+                       q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages;
+               }
+               put_ldev(mdev);
        }
 }
 
+void drbd_reconsider_max_bio_size(struct drbd_conf *mdev)
+{
+       int now, new, local, peer;
+
+       now = queue_max_hw_sectors(mdev->rq_queue) << 9;
+       local = mdev->local_max_bio_size; /* Eventually last known value, from volatile memory */
+       peer = mdev->peer_max_bio_size; /* Eventually last known value, from meta data */
+
+       if (get_ldev_if_state(mdev, D_ATTACHING)) {
+               local = queue_max_hw_sectors(mdev->ldev->backing_bdev->bd_disk->queue) << 9;
+               mdev->local_max_bio_size = local;
+               put_ldev(mdev);
+       }
+
+       /* We may ignore peer limits if the peer is modern enough.
+          Because new from 8.3.8 onwards the peer can use multiple
+          BIOs for a single peer_request */
+       if (mdev->state.conn >= C_CONNECTED) {
+               if (mdev->agreed_pro_version < 94)
+                       peer = mdev->peer_max_bio_size;
+               else if (mdev->agreed_pro_version == 94)
+                       peer = DRBD_MAX_SIZE_H80_PACKET;
+               else /* drbd 8.3.8 onwards */
+                       peer = DRBD_MAX_BIO_SIZE;
+       }
+
+       new = min_t(int, local, peer);
+
+       if (mdev->state.role == R_PRIMARY && new < now)
+               dev_err(DEV, "ASSERT FAILED new < now; (%d < %d)\n", new, now);
+
+       if (new != now)
+               dev_info(DEV, "max BIO size = %u\n", new);
+
+       drbd_setup_queue_param(mdev, new);
+}
+
 /* serialize deconfig (worker exiting, doing cleanup)
  * and reconfig (drbdsetup disk, drbdsetup net)
  *
@@ -865,7 +932,6 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
        struct block_device *bdev;
        struct lru_cache *resync_lru = NULL;
        union drbd_state ns, os;
-       unsigned int max_bio_size;
        enum drbd_state_rv rv;
        int cp_discovered = 0;
        int logical_block_size;
@@ -1117,20 +1183,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
        mdev->read_cnt = 0;
        mdev->writ_cnt = 0;
 
-       max_bio_size = DRBD_MAX_BIO_SIZE;
-       if (mdev->state.conn == C_CONNECTED) {
-               /* We are Primary, Connected, and now attach a new local
-                * backing store. We must not increase the user visible maximum
-                * bio size on this device to something the peer may not be
-                * able to handle. */
-               if (mdev->agreed_pro_version < 94)
-                       max_bio_size = queue_max_hw_sectors(mdev->rq_queue) << 9;
-               else if (mdev->agreed_pro_version == 94)
-                       max_bio_size = DRBD_MAX_SIZE_H80_PACKET;
-               /* else: drbd 8.3.9 and later, stay with default */
-       }
-
-       drbd_setup_queue_param(mdev, max_bio_size);
+       drbd_reconsider_max_bio_size(mdev);
 
        /* If I am currently not R_PRIMARY,
         * but meta data primary indicator is set,
@@ -1152,7 +1205,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
            !drbd_md_test_flag(mdev->ldev, MDF_CONNECTED_IND))
                set_bit(USE_DEGR_WFC_T, &mdev->flags);
 
-       dd = drbd_determin_dev_size(mdev, 0);
+       dd = drbd_determine_dev_size(mdev, 0);
        if (dd == dev_size_error) {
                retcode = ERR_NOMEM_BITMAP;
                goto force_diskless_dec;
@@ -1281,11 +1334,19 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
 static int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
                          struct drbd_nl_cfg_reply *reply)
 {
+       enum drbd_ret_code retcode;
+       int ret;
        drbd_suspend_io(mdev); /* so no-one is stuck in drbd_al_begin_io */
-       reply->ret_code = drbd_request_state(mdev, NS(disk, D_DISKLESS));
-       if (mdev->state.disk == D_DISKLESS)
-               wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
+       retcode = drbd_request_state(mdev, NS(disk, D_FAILED));
+       /* D_FAILED will transition to DISKLESS. */
+       ret = wait_event_interruptible(mdev->misc_wait,
+                       mdev->state.disk != D_FAILED);
        drbd_resume_io(mdev);
+       if ((int)retcode == (int)SS_IS_DISKLESS)
+               retcode = SS_NOTHING_TO_DO;
+       if (ret)
+               retcode = ERR_INTR;
+       reply->ret_code = retcode;
        return 0;
 }
 
@@ -1658,7 +1719,7 @@ static int drbd_nl_resize(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
 
        mdev->ldev->dc.disk_size = (sector_t)rs.resize_size;
        ddsf = (rs.resize_force ? DDSF_FORCED : 0) | (rs.no_resync ? DDSF_NO_RESYNC : 0);
-       dd = drbd_determin_dev_size(mdev, ddsf);
+       dd = drbd_determine_dev_size(mdev, ddsf);
        drbd_md_sync(mdev);
        put_ldev(mdev);
        if (dd == dev_size_error) {
index fd26666c0b08436fe0c648f3f09c016b0c999207..25d32c5aa50ab58e0b2fdb4e7dfde2377ec96878 100644 (file)
@@ -333,7 +333,7 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev,
        if (!page)
                goto fail;
 
-       INIT_HLIST_NODE(&e->colision);
+       INIT_HLIST_NODE(&e->collision);
        e->epoch = NULL;
        e->mdev = mdev;
        e->pages = page;
@@ -356,7 +356,7 @@ void drbd_free_some_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, int i
                kfree(e->digest);
        drbd_pp_free(mdev, e->pages, is_net);
        D_ASSERT(atomic_read(&e->pending_bios) == 0);
-       D_ASSERT(hlist_unhashed(&e->colision));
+       D_ASSERT(hlist_unhashed(&e->collision));
        mempool_free(e, drbd_ee_mempool);
 }
 
@@ -787,7 +787,7 @@ static int drbd_connect(struct drbd_conf *mdev)
                }
 
                if (sock && msock) {
-                       schedule_timeout_interruptible(HZ / 10);
+                       schedule_timeout_interruptible(mdev->net_conf->ping_timeo*HZ/10);
                        ok = drbd_socket_okay(mdev, &sock);
                        ok = drbd_socket_okay(mdev, &msock) && ok;
                        if (ok)
@@ -899,11 +899,6 @@ retry:
 
        drbd_thread_start(&mdev->asender);
 
-       if (mdev->agreed_pro_version < 95 && get_ldev(mdev)) {
-               drbd_setup_queue_param(mdev, DRBD_MAX_SIZE_H80_PACKET);
-               put_ldev(mdev);
-       }
-
        if (drbd_send_protocol(mdev) == -1)
                return -1;
        drbd_send_sync_param(mdev, &mdev->sync_conf);
@@ -1418,7 +1413,7 @@ static int e_end_resync_block(struct drbd_conf *mdev, struct drbd_work *w, int u
        sector_t sector = e->sector;
        int ok;
 
-       D_ASSERT(hlist_unhashed(&e->colision));
+       D_ASSERT(hlist_unhashed(&e->collision));
 
        if (likely((e->flags & EE_WAS_ERROR) == 0)) {
                drbd_set_in_sync(mdev, sector, e->size);
@@ -1487,7 +1482,7 @@ static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsi
                return false;
        }
 
-       /* hlist_del(&req->colision) is done in _req_may_be_done, to avoid
+       /* hlist_del(&req->collision) is done in _req_may_be_done, to avoid
         * special casing it there for the various failure cases.
         * still no race with drbd_fail_pending_reads */
        ok = recv_dless_read(mdev, req, sector, data_size);
@@ -1558,11 +1553,11 @@ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
         * P_WRITE_ACK / P_NEG_ACK, to get the sequence number right.  */
        if (mdev->net_conf->two_primaries) {
                spin_lock_irq(&mdev->req_lock);
-               D_ASSERT(!hlist_unhashed(&e->colision));
-               hlist_del_init(&e->colision);
+               D_ASSERT(!hlist_unhashed(&e->collision));
+               hlist_del_init(&e->collision);
                spin_unlock_irq(&mdev->req_lock);
        } else {
-               D_ASSERT(hlist_unhashed(&e->colision));
+               D_ASSERT(hlist_unhashed(&e->collision));
        }
 
        drbd_may_finish_epoch(mdev, e->epoch, EV_PUT + (cancel ? EV_CLEANUP : 0));
@@ -1579,8 +1574,8 @@ static int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int u
        ok = drbd_send_ack(mdev, P_DISCARD_ACK, e);
 
        spin_lock_irq(&mdev->req_lock);
-       D_ASSERT(!hlist_unhashed(&e->colision));
-       hlist_del_init(&e->colision);
+       D_ASSERT(!hlist_unhashed(&e->collision));
+       hlist_del_init(&e->collision);
        spin_unlock_irq(&mdev->req_lock);
 
        dec_unacked(mdev);
@@ -1755,7 +1750,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
 
                spin_lock_irq(&mdev->req_lock);
 
-               hlist_add_head(&e->colision, ee_hash_slot(mdev, sector));
+               hlist_add_head(&e->collision, ee_hash_slot(mdev, sector));
 
 #define OVERLAPS overlaps(i->sector, i->size, sector, size)
                slot = tl_hash_slot(mdev, sector);
@@ -1765,7 +1760,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
                        int have_conflict = 0;
                        prepare_to_wait(&mdev->misc_wait, &wait,
                                TASK_INTERRUPTIBLE);
-                       hlist_for_each_entry(i, n, slot, colision) {
+                       hlist_for_each_entry(i, n, slot, collision) {
                                if (OVERLAPS) {
                                        /* only ALERT on first iteration,
                                         * we may be woken up early... */
@@ -1804,7 +1799,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
                        }
 
                        if (signal_pending(current)) {
-                               hlist_del_init(&e->colision);
+                               hlist_del_init(&e->collision);
 
                                spin_unlock_irq(&mdev->req_lock);
 
@@ -1862,7 +1857,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
        dev_err(DEV, "submit failed, triggering re-connect\n");
        spin_lock_irq(&mdev->req_lock);
        list_del(&e->w.list);
-       hlist_del_init(&e->colision);
+       hlist_del_init(&e->collision);
        spin_unlock_irq(&mdev->req_lock);
        if (e->flags & EE_CALL_AL_COMPLETE_IO)
                drbd_al_complete_io(mdev, e->sector);
@@ -2916,12 +2911,6 @@ disconnect:
        return false;
 }
 
-static void drbd_setup_order_type(struct drbd_conf *mdev, int peer)
-{
-       /* sorry, we currently have no working implementation
-        * of distributed TCQ */
-}
-
 /* warn if the arguments differ by more than 12.5% */
 static void warn_if_differ_considerably(struct drbd_conf *mdev,
        const char *s, sector_t a, sector_t b)
@@ -2939,7 +2928,6 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
 {
        struct p_sizes *p = &mdev->data.rbuf.sizes;
        enum determine_dev_size dd = unchanged;
-       unsigned int max_bio_size;
        sector_t p_size, p_usize, my_usize;
        int ldsc = 0; /* local disk size changed */
        enum dds_flags ddsf;
@@ -2994,7 +2982,7 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
 
        ddsf = be16_to_cpu(p->dds_flags);
        if (get_ldev(mdev)) {
-               dd = drbd_determin_dev_size(mdev, ddsf);
+               dd = drbd_determine_dev_size(mdev, ddsf);
                put_ldev(mdev);
                if (dd == dev_size_error)
                        return false;
@@ -3004,23 +2992,15 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
                drbd_set_my_capacity(mdev, p_size);
        }
 
+       mdev->peer_max_bio_size = be32_to_cpu(p->max_bio_size);
+       drbd_reconsider_max_bio_size(mdev);
+
        if (get_ldev(mdev)) {
                if (mdev->ldev->known_size != drbd_get_capacity(mdev->ldev->backing_bdev)) {
                        mdev->ldev->known_size = drbd_get_capacity(mdev->ldev->backing_bdev);
                        ldsc = 1;
                }
 
-               if (mdev->agreed_pro_version < 94)
-                       max_bio_size = be32_to_cpu(p->max_bio_size);
-               else if (mdev->agreed_pro_version == 94)
-                       max_bio_size = DRBD_MAX_SIZE_H80_PACKET;
-               else /* drbd 8.3.8 onwards */
-                       max_bio_size = DRBD_MAX_BIO_SIZE;
-
-               if (max_bio_size != queue_max_hw_sectors(mdev->rq_queue) << 9)
-                       drbd_setup_queue_param(mdev, max_bio_size);
-
-               drbd_setup_order_type(mdev, be16_to_cpu(p->queue_order_type));
                put_ldev(mdev);
        }
 
@@ -4275,7 +4255,7 @@ static struct drbd_request *_ack_id_to_req(struct drbd_conf *mdev,
        struct hlist_node *n;
        struct drbd_request *req;
 
-       hlist_for_each_entry(req, n, slot, colision) {
+       hlist_for_each_entry(req, n, slot, collision) {
                if ((unsigned long)req == (unsigned long)id) {
                        if (req->sector != sector) {
                                dev_err(DEV, "_ack_id_to_req: found req %p but it has "
@@ -4554,6 +4534,7 @@ int drbd_asender(struct drbd_thread *thi)
        int received = 0;
        int expect   = sizeof(struct p_header80);
        int empty;
+       int ping_timeout_active = 0;
 
        sprintf(current->comm, "drbd%d_asender", mdev_to_minor(mdev));
 
@@ -4566,6 +4547,7 @@ int drbd_asender(struct drbd_thread *thi)
                        ERR_IF(!drbd_send_ping(mdev)) goto reconnect;
                        mdev->meta.socket->sk->sk_rcvtimeo =
                                mdev->net_conf->ping_timeo*HZ/10;
+                       ping_timeout_active = 1;
                }
 
                /* conditionally cork;
@@ -4620,8 +4602,7 @@ int drbd_asender(struct drbd_thread *thi)
                        dev_err(DEV, "meta connection shut down by peer.\n");
                        goto reconnect;
                } else if (rv == -EAGAIN) {
-                       if (mdev->meta.socket->sk->sk_rcvtimeo ==
-                           mdev->net_conf->ping_timeo*HZ/10) {
+                       if (ping_timeout_active) {
                                dev_err(DEV, "PingAck did not arrive in time.\n");
                                goto reconnect;
                        }
@@ -4660,6 +4641,11 @@ int drbd_asender(struct drbd_thread *thi)
                        if (!cmd->process(mdev, h))
                                goto reconnect;
 
+                       /* the idle_timeout (ping-int)
+                        * has been restored in got_PingAck() */
+                       if (cmd == get_asender_cmd(P_PING_ACK))
+                               ping_timeout_active = 0;
+
                        buf      = h;
                        received = 0;
                        expect   = sizeof(struct p_header80);
index 5c0c8be1bb0ae144e4d82ef9d3da257ca06af99d..3424d675b769a661857cdd41aa90a30e28c07b59 100644 (file)
@@ -163,7 +163,7 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev,
                 * they must have been failed on the spot */
 #define OVERLAPS overlaps(sector, size, i->sector, i->size)
                slot = tl_hash_slot(mdev, sector);
-               hlist_for_each_entry(i, n, slot, colision) {
+               hlist_for_each_entry(i, n, slot, collision) {
                        if (OVERLAPS) {
                                dev_alert(DEV, "LOGIC BUG: completed: %p %llus +%u; "
                                      "other: %p %llus +%u\n",
@@ -187,7 +187,7 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev,
 #undef OVERLAPS
 #define OVERLAPS overlaps(sector, size, e->sector, e->size)
                slot = ee_hash_slot(mdev, req->sector);
-               hlist_for_each_entry(e, n, slot, colision) {
+               hlist_for_each_entry(e, n, slot, collision) {
                        if (OVERLAPS) {
                                wake_up(&mdev->misc_wait);
                                break;
@@ -260,8 +260,8 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m)
 
                /* remove the request from the conflict detection
                 * respective block_id verification hash */
-               if (!hlist_unhashed(&req->colision))
-                       hlist_del(&req->colision);
+               if (!hlist_unhashed(&req->collision))
+                       hlist_del(&req->collision);
                else
                        D_ASSERT((s & (RQ_NET_MASK & ~RQ_NET_DONE)) == 0);
 
@@ -329,7 +329,7 @@ static int _req_conflicts(struct drbd_request *req)
        struct hlist_node *n;
        struct hlist_head *slot;
 
-       D_ASSERT(hlist_unhashed(&req->colision));
+       D_ASSERT(hlist_unhashed(&req->collision));
 
        if (!get_net_conf(mdev))
                return 0;
@@ -341,7 +341,7 @@ static int _req_conflicts(struct drbd_request *req)
 
 #define OVERLAPS overlaps(i->sector, i->size, sector, size)
        slot = tl_hash_slot(mdev, sector);
-       hlist_for_each_entry(i, n, slot, colision) {
+       hlist_for_each_entry(i, n, slot, collision) {
                if (OVERLAPS) {
                        dev_alert(DEV, "%s[%u] Concurrent local write detected! "
                              "[DISCARD L] new: %llus +%u; "
@@ -359,7 +359,7 @@ static int _req_conflicts(struct drbd_request *req)
 #undef OVERLAPS
 #define OVERLAPS overlaps(e->sector, e->size, sector, size)
                slot = ee_hash_slot(mdev, sector);
-               hlist_for_each_entry(e, n, slot, colision) {
+               hlist_for_each_entry(e, n, slot, collision) {
                        if (OVERLAPS) {
                                dev_alert(DEV, "%s[%u] Concurrent remote write detected!"
                                      " [DISCARD L] new: %llus +%u; "
@@ -491,7 +491,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
 
                /* so we can verify the handle in the answer packet
                 * corresponding hlist_del is in _req_may_be_done() */
-               hlist_add_head(&req->colision, ar_hash_slot(mdev, req->sector));
+               hlist_add_head(&req->collision, ar_hash_slot(mdev, req->sector));
 
                set_bit(UNPLUG_REMOTE, &mdev->flags);
 
@@ -507,7 +507,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
                /* assert something? */
                /* from drbd_make_request_common only */
 
-               hlist_add_head(&req->colision, tl_hash_slot(mdev, req->sector));
+               hlist_add_head(&req->collision, tl_hash_slot(mdev, req->sector));
                /* corresponding hlist_del is in _req_may_be_done() */
 
                /* NOTE
@@ -1033,7 +1033,7 @@ fail_conflicting:
        err = 0;
 
 fail_free_complete:
-       if (rw == WRITE && local)
+       if (req->rq_state & RQ_IN_ACT_LOG)
                drbd_al_complete_io(mdev, sector);
 fail_and_free_req:
        if (local) {
index 32e2c3e6a8134220943873c671cb7ac6adf83a10..68a234a5fdc5bc4ab19e2a5ab85cd198e588b9bd 100644 (file)
@@ -256,7 +256,7 @@ static inline struct drbd_request *_ar_id_to_req(struct drbd_conf *mdev,
        struct hlist_node *n;
        struct drbd_request *req;
 
-       hlist_for_each_entry(req, n, slot, colision) {
+       hlist_for_each_entry(req, n, slot, collision) {
                if ((unsigned long)req == (unsigned long)id) {
                        D_ASSERT(req->sector == sector);
                        return req;
@@ -291,7 +291,7 @@ static inline struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
                req->epoch       = 0;
                req->sector      = bio_src->bi_sector;
                req->size        = bio_src->bi_size;
-               INIT_HLIST_NODE(&req->colision);
+               INIT_HLIST_NODE(&req->collision);
                INIT_LIST_HEAD(&req->tl_requests);
                INIT_LIST_HEAD(&req->w.list);
        }
@@ -323,6 +323,7 @@ extern int __req_mod(struct drbd_request *req, enum drbd_req_event what,
 extern void complete_master_bio(struct drbd_conf *mdev,
                struct bio_and_error *m);
 extern void request_timer_fn(unsigned long data);
+extern void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what);
 
 /* use this if you don't want to deal with calling complete_master_bio()
  * outside the spinlock, e.g. when walking some list on cleanup. */
index f7e6c92f8d03d001c1a452fe92b0c605c450bd38..4d76b06b6b20966f176e9b3dc9a795345a23798b 100644 (file)
@@ -126,7 +126,7 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo
        list_del(&e->w.list); /* has been on active_ee or sync_ee */
        list_add_tail(&e->w.list, &mdev->done_ee);
 
-       /* No hlist_del_init(&e->colision) here, we did not send the Ack yet,
+       /* No hlist_del_init(&e->collision) here, we did not send the Ack yet,
         * neither did we wake possibly waiting conflicting requests.
         * done from "drbd_process_done_ee" within the appropriate w.cb
         * (e_end_block/e_end_resync_block) or from _drbd_clear_done_ee */
@@ -297,42 +297,48 @@ void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio *
        crypto_hash_final(&desc, digest);
 }
 
-static int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+/* TODO merge common code with w_e_end_ov_req */
+int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
 {
        struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
        int digest_size;
        void *digest;
-       int ok;
+       int ok = 1;
 
        D_ASSERT(e->block_id == DRBD_MAGIC + 0xbeef);
 
-       if (unlikely(cancel)) {
-               drbd_free_ee(mdev, e);
-               return 1;
-       }
+       if (unlikely(cancel))
+               goto out;
 
-       if (likely((e->flags & EE_WAS_ERROR) == 0)) {
-               digest_size = crypto_hash_digestsize(mdev->csums_tfm);
-               digest = kmalloc(digest_size, GFP_NOIO);
-               if (digest) {
-                       drbd_csum_ee(mdev, mdev->csums_tfm, e, digest);
+       if (likely((e->flags & EE_WAS_ERROR) != 0))
+               goto out;
 
-                       inc_rs_pending(mdev);
-                       ok = drbd_send_drequest_csum(mdev,
-                                                    e->sector,
-                                                    e->size,
-                                                    digest,
-                                                    digest_size,
-                                                    P_CSUM_RS_REQUEST);
-                       kfree(digest);
-               } else {
-                       dev_err(DEV, "kmalloc() of digest failed.\n");
-                       ok = 0;
-               }
-       } else
-               ok = 1;
+       digest_size = crypto_hash_digestsize(mdev->csums_tfm);
+       digest = kmalloc(digest_size, GFP_NOIO);
+       if (digest) {
+               sector_t sector = e->sector;
+               unsigned int size = e->size;
+               drbd_csum_ee(mdev, mdev->csums_tfm, e, digest);
+               /* Free e and pages before send.
+                * In case we block on congestion, we could otherwise run into
+                * some distributed deadlock, if the other side blocks on
+                * congestion as well, because our receiver blocks in
+                * drbd_pp_alloc due to pp_in_use > max_buffers. */
+               drbd_free_ee(mdev, e);
+               e = NULL;
+               inc_rs_pending(mdev);
+               ok = drbd_send_drequest_csum(mdev, sector, size,
+                                            digest, digest_size,
+                                            P_CSUM_RS_REQUEST);
+               kfree(digest);
+       } else {
+               dev_err(DEV, "kmalloc() of digest failed.\n");
+               ok = 0;
+       }
 
-       drbd_free_ee(mdev, e);
+out:
+       if (e)
+               drbd_free_ee(mdev, e);
 
        if (unlikely(!ok))
                dev_err(DEV, "drbd_send_drequest(..., csum) failed\n");
@@ -834,7 +840,7 @@ int drbd_resync_finished(struct drbd_conf *mdev)
                        const int ratio =
                                (t == 0)     ? 0 :
                        (t < 100000) ? ((s*100)/t) : (s/(t/100));
-                       dev_info(DEV, "%u %% had equal check sums, eliminated: %luK; "
+                       dev_info(DEV, "%u %% had equal checksums, eliminated: %luK; "
                             "transferred %luK total %luK\n",
                             ratio,
                             Bit2KB(mdev->rs_same_csum),
@@ -1071,9 +1077,12 @@ int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
        return ok;
 }
 
+/* TODO merge common code with w_e_send_csum */
 int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
 {
        struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
+       sector_t sector = e->sector;
+       unsigned int size = e->size;
        int digest_size;
        void *digest;
        int ok = 1;
@@ -1093,17 +1102,25 @@ int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
        else
                memset(digest, 0, digest_size);
 
+       /* Free e and pages before send.
+        * In case we block on congestion, we could otherwise run into
+        * some distributed deadlock, if the other side blocks on
+        * congestion as well, because our receiver blocks in
+        * drbd_pp_alloc due to pp_in_use > max_buffers. */
+       drbd_free_ee(mdev, e);
+       e = NULL;
        inc_rs_pending(mdev);
-       ok = drbd_send_drequest_csum(mdev, e->sector, e->size,
-                                    digest, digest_size, P_OV_REPLY);
+       ok = drbd_send_drequest_csum(mdev, sector, size,
+                                    digest, digest_size,
+                                    P_OV_REPLY);
        if (!ok)
                dec_rs_pending(mdev);
        kfree(digest);
 
 out:
-       drbd_free_ee(mdev, e);
+       if (e)
+               drbd_free_ee(mdev, e);
        dec_unacked(mdev);
-
        return ok;
 }
 
@@ -1122,8 +1139,10 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
 {
        struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
        struct digest_info *di;
-       int digest_size;
        void *digest;
+       sector_t sector = e->sector;
+       unsigned int size = e->size;
+       int digest_size;
        int ok, eq = 0;
 
        if (unlikely(cancel)) {
@@ -1153,16 +1172,21 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
                }
        }
 
-       dec_unacked(mdev);
+               /* Free e and pages before send.
+                * In case we block on congestion, we could otherwise run into
+                * some distributed deadlock, if the other side blocks on
+                * congestion as well, because our receiver blocks in
+                * drbd_pp_alloc due to pp_in_use > max_buffers. */
+       drbd_free_ee(mdev, e);
        if (!eq)
-               drbd_ov_oos_found(mdev, e->sector, e->size);
+               drbd_ov_oos_found(mdev, sector, size);
        else
                ov_oos_print(mdev);
 
-       ok = drbd_send_ack_ex(mdev, P_OV_RESULT, e->sector, e->size,
+       ok = drbd_send_ack_ex(mdev, P_OV_RESULT, sector, size,
                              eq ? ID_IN_SYNC : ID_OUT_OF_SYNC);
 
-       drbd_free_ee(mdev, e);
+       dec_unacked(mdev);
 
        --mdev->ov_left;
 
index db8f88586c8d3b2d97dbc910835a0de846ac1fd1..98de8f4186762680a0ea1ccd2d0cf907c1314b40 100644 (file)
@@ -1038,6 +1038,7 @@ static void floppy_disable_hlt(void)
 {
        unsigned long flags;
 
+       WARN_ONCE(1, "floppy_disable_hlt() scheduled for removal in 2012");
        spin_lock_irqsave(&floppy_hlt_lock, flags);
        if (!hlt_disabled) {
                hlt_disabled = 1;
index a076a14ca72d848fbf144042a7272038eab22390..76c8da78212bffec71f5dc7af025a84e4028d456 100644 (file)
@@ -1540,9 +1540,9 @@ static const struct block_device_operations lo_fops = {
  * And now the modules code and kernel interface.
  */
 static int max_loop;
-module_param(max_loop, int, 0);
+module_param(max_loop, int, S_IRUGO);
 MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
-module_param(max_part, int, 0);
+module_param(max_part, int, S_IRUGO);
 MODULE_PARM_DESC(max_part, "Maximum number of partitions per loop device");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR);
@@ -1658,7 +1658,7 @@ static struct kobject *loop_probe(dev_t dev, int *part, void *data)
        struct kobject *kobj;
 
        mutex_lock(&loop_devices_mutex);
-       lo = loop_init_one(dev & MINORMASK);
+       lo = loop_init_one(MINOR(dev) >> part_shift);
        kobj = lo ? get_disk(lo->lo_disk) : ERR_PTR(-ENOMEM);
        mutex_unlock(&loop_devices_mutex);
 
@@ -1688,18 +1688,32 @@ static int __init loop_init(void)
         */
 
        part_shift = 0;
-       if (max_part > 0)
+       if (max_part > 0) {
                part_shift = fls(max_part);
 
+               /*
+                * Adjust max_part according to part_shift as it is exported
+                * to user space so that user can decide correct minor number
+                * if [s]he want to create more devices.
+                *
+                * Note that -1 is required because partition 0 is reserved
+                * for the whole disk.
+                */
+               max_part = (1UL << part_shift) - 1;
+       }
+
+       if ((1UL << part_shift) > DISK_MAX_PARTS)
+               return -EINVAL;
+
        if (max_loop > 1UL << (MINORBITS - part_shift))
                return -EINVAL;
 
        if (max_loop) {
                nr = max_loop;
-               range = max_loop;
+               range = max_loop << part_shift;
        } else {
                nr = 8;
-               range = 1UL << (MINORBITS - part_shift);
+               range = 1UL << MINORBITS;
        }
 
        if (register_blkdev(LOOP_MAJOR, "loop"))
@@ -1738,7 +1752,7 @@ static void __exit loop_exit(void)
        unsigned long range;
        struct loop_device *lo, *next;
 
-       range = max_loop ? max_loop :  1UL << (MINORBITS - part_shift);
+       range = max_loop ? max_loop << part_shift : 1UL << MINORBITS;
 
        list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
                loop_del_one(lo);
index e6fc716aca4521cc7537e09a393b6213b0a3ea88..f533f3375e24751feaf4e065b920291c7abe149d 100644 (file)
@@ -192,7 +192,8 @@ static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size,
                        if (lo->xmit_timeout)
                                del_timer_sync(&ti);
                } else
-                       result = kernel_recvmsg(sock, &msg, &iov, 1, size, 0);
+                       result = kernel_recvmsg(sock, &msg, &iov, 1, size,
+                                               msg.msg_flags);
 
                if (signal_pending(current)) {
                        siginfo_t info;
@@ -753,9 +754,26 @@ static int __init nbd_init(void)
                return -ENOMEM;
 
        part_shift = 0;
-       if (max_part > 0)
+       if (max_part > 0) {
                part_shift = fls(max_part);
 
+               /*
+                * Adjust max_part according to part_shift as it is exported
+                * to user space so that user can know the max number of
+                * partition kernel should be able to manage.
+                *
+                * Note that -1 is required because partition 0 is reserved
+                * for the whole disk.
+                */
+               max_part = (1UL << part_shift) - 1;
+       }
+
+       if ((1UL << part_shift) > DISK_MAX_PARTS)
+               return -EINVAL;
+
+       if (nbds_max > 1UL << (MINORBITS - part_shift))
+               return -EINVAL;
+
        for (i = 0; i < nbds_max; i++) {
                struct gendisk *disk = alloc_disk(1 << part_shift);
                if (!disk)
index 8690e31d993287e16a68caca0e2125c0c7e6bdb0..46b8136c31bbe4aab3bccee9923ca755f6833ea8 100644 (file)
@@ -320,6 +320,7 @@ static void pcd_init_units(void)
                disk->first_minor = unit;
                strcpy(disk->disk_name, cd->name);      /* umm... */
                disk->fops = &pcd_bdops;
+               disk->flags = GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
        }
 }
 
index 9712fad82bc6cf2be78daaa503432e8725ab2a4f..1278098624e6382ab77522c68535d39b3c863916 100644 (file)
@@ -1191,14 +1191,19 @@ static int rbd_req_sync_notify_ack(struct rbd_device *dev,
 static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data)
 {
        struct rbd_device *dev = (struct rbd_device *)data;
+       int rc;
+
        if (!dev)
                return;
 
        dout("rbd_watch_cb %s notify_id=%lld opcode=%d\n", dev->obj_md_name,
                notify_id, (int)opcode);
        mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-       __rbd_update_snaps(dev);
+       rc = __rbd_update_snaps(dev);
        mutex_unlock(&ctl_mutex);
+       if (rc)
+               pr_warning(DRV_NAME "%d got notification but failed to update"
+                          " snaps: %d\n", dev->major, rc);
 
        rbd_req_sync_notify_ack(dev, ver, notify_id, dev->obj_md_name);
 }
@@ -1597,7 +1602,7 @@ static int rbd_header_add_snap(struct rbd_device *dev,
        int name_len = strlen(snap_name);
        u64 new_snapid;
        int ret;
-       void *data, *data_start, *data_end;
+       void *data, *p, *e;
        u64 ver;
 
        /* we should create a snapshot only if we're pointing at the head */
@@ -1614,16 +1619,16 @@ static int rbd_header_add_snap(struct rbd_device *dev,
        if (!data)
                return -ENOMEM;
 
-       data_start = data;
-       data_end = data + name_len + 16;
+       p = data;
+       e = data + name_len + 16;
 
-       ceph_encode_string_safe(&data, data_end, snap_name, name_len, bad);
-       ceph_encode_64_safe(&data, data_end, new_snapid, bad);
+       ceph_encode_string_safe(&p, e, snap_name, name_len, bad);
+       ceph_encode_64_safe(&p, e, new_snapid, bad);
 
        ret = rbd_req_sync_exec(dev, dev->obj_md_name, "rbd", "snap_add",
-                               data_start, data - data_start, &ver);
+                               data, p - data, &ver);
 
-       kfree(data_start);
+       kfree(data);
 
        if (ret < 0)
                return ret;
@@ -1659,6 +1664,9 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev)
        if (ret < 0)
                return ret;
 
+       /* resized? */
+       set_capacity(rbd_dev->disk, h.image_size / 512ULL);
+
        down_write(&rbd_dev->header.snap_rwsem);
 
        snap_seq = rbd_dev->header.snapc->seq;
@@ -1716,7 +1724,8 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
        if (!disk)
                goto out;
 
-       sprintf(disk->disk_name, DRV_NAME "%d", rbd_dev->id);
+       snprintf(disk->disk_name, sizeof(disk->disk_name), DRV_NAME "%d",
+                rbd_dev->id);
        disk->major = rbd_dev->major;
        disk->first_minor = 0;
        disk->fops = &rbd_bd_ops;
index 6ecf89cdf006a3f6605d15fb062f134a2d3a0621..079c08808d8a41b7fe5d27b00d389579ffae0930 100644 (file)
@@ -6,10 +6,13 @@
 #include <linux/virtio.h>
 #include <linux/virtio_blk.h>
 #include <linux/scatterlist.h>
+#include <linux/string_helpers.h>
+#include <scsi/scsi_cmnd.h>
 
 #define PART_BITS 4
 
 static int major, index;
+struct workqueue_struct *virtblk_wq;
 
 struct virtio_blk
 {
@@ -26,6 +29,9 @@ struct virtio_blk
 
        mempool_t *pool;
 
+       /* Process context for config space updates */
+       struct work_struct config_work;
+
        /* What host tells us, plus 2 for header & tailer. */
        unsigned int sg_elems;
 
@@ -141,7 +147,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
        num = blk_rq_map_sg(q, vbr->req, vblk->sg + out);
 
        if (vbr->req->cmd_type == REQ_TYPE_BLOCK_PC) {
-               sg_set_buf(&vblk->sg[num + out + in++], vbr->req->sense, 96);
+               sg_set_buf(&vblk->sg[num + out + in++], vbr->req->sense, SCSI_SENSE_BUFFERSIZE);
                sg_set_buf(&vblk->sg[num + out + in++], &vbr->in_hdr,
                           sizeof(vbr->in_hdr));
        }
@@ -291,6 +297,46 @@ static ssize_t virtblk_serial_show(struct device *dev,
 }
 DEVICE_ATTR(serial, S_IRUGO, virtblk_serial_show, NULL);
 
+static void virtblk_config_changed_work(struct work_struct *work)
+{
+       struct virtio_blk *vblk =
+               container_of(work, struct virtio_blk, config_work);
+       struct virtio_device *vdev = vblk->vdev;
+       struct request_queue *q = vblk->disk->queue;
+       char cap_str_2[10], cap_str_10[10];
+       u64 capacity, size;
+
+       /* Host must always specify the capacity. */
+       vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
+                         &capacity, sizeof(capacity));
+
+       /* If capacity is too big, truncate with warning. */
+       if ((sector_t)capacity != capacity) {
+               dev_warn(&vdev->dev, "Capacity %llu too large: truncating\n",
+                        (unsigned long long)capacity);
+               capacity = (sector_t)-1;
+       }
+
+       size = capacity * queue_logical_block_size(q);
+       string_get_size(size, STRING_UNITS_2, cap_str_2, sizeof(cap_str_2));
+       string_get_size(size, STRING_UNITS_10, cap_str_10, sizeof(cap_str_10));
+
+       dev_notice(&vdev->dev,
+                 "new size: %llu %d-byte logical blocks (%s/%s)\n",
+                 (unsigned long long)capacity,
+                 queue_logical_block_size(q),
+                 cap_str_10, cap_str_2);
+
+       set_capacity(vblk->disk, capacity);
+}
+
+static void virtblk_config_changed(struct virtio_device *vdev)
+{
+       struct virtio_blk *vblk = vdev->priv;
+
+       queue_work(virtblk_wq, &vblk->config_work);
+}
+
 static int __devinit virtblk_probe(struct virtio_device *vdev)
 {
        struct virtio_blk *vblk;
@@ -327,6 +373,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
        vblk->vdev = vdev;
        vblk->sg_elems = sg_elems;
        sg_init_table(vblk->sg, vblk->sg_elems);
+       INIT_WORK(&vblk->config_work, virtblk_config_changed_work);
 
        /* We expect one virtqueue, for output. */
        vblk->vq = virtio_find_single_vq(vdev, blk_done, "requests");
@@ -477,6 +524,8 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
 {
        struct virtio_blk *vblk = vdev->priv;
 
+       flush_work(&vblk->config_work);
+
        /* Nothing should be pending. */
        BUG_ON(!list_empty(&vblk->reqs));
 
@@ -508,27 +557,47 @@ static unsigned int features[] = {
  * Use __refdata to avoid this warning.
  */
 static struct virtio_driver __refdata virtio_blk = {
-       .feature_table = features,
-       .feature_table_size = ARRAY_SIZE(features),
-       .driver.name =  KBUILD_MODNAME,
-       .driver.owner = THIS_MODULE,
-       .id_table =     id_table,
-       .probe =        virtblk_probe,
-       .remove =       __devexit_p(virtblk_remove),
+       .feature_table          = features,
+       .feature_table_size     = ARRAY_SIZE(features),
+       .driver.name            = KBUILD_MODNAME,
+       .driver.owner           = THIS_MODULE,
+       .id_table               = id_table,
+       .probe                  = virtblk_probe,
+       .remove                 = __devexit_p(virtblk_remove),
+       .config_changed         = virtblk_config_changed,
 };
 
 static int __init init(void)
 {
+       int error;
+
+       virtblk_wq = alloc_workqueue("virtio-blk", 0, 0);
+       if (!virtblk_wq)
+               return -ENOMEM;
+
        major = register_blkdev(0, "virtblk");
-       if (major < 0)
-               return major;
-       return register_virtio_driver(&virtio_blk);
+       if (major < 0) {
+               error = major;
+               goto out_destroy_workqueue;
+       }
+
+       error = register_virtio_driver(&virtio_blk);
+       if (error)
+               goto out_unregister_blkdev;
+       return 0;
+
+out_unregister_blkdev:
+       unregister_blkdev(major, "virtblk");
+out_destroy_workqueue:
+       destroy_workqueue(virtblk_wq);
+       return error;
 }
 
 static void __exit fini(void)
 {
        unregister_blkdev(major, "virtblk");
        unregister_virtio_driver(&virtio_blk);
+       destroy_workqueue(virtblk_wq);
 }
 module_init(init);
 module_exit(fini);
diff --git a/drivers/block/xen-blkback/Makefile b/drivers/block/xen-blkback/Makefile
new file mode 100644 (file)
index 0000000..e491c1b
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_XEN_BLKDEV_BACKEND) := xen-blkback.o
+
+xen-blkback-y  := blkback.o xenbus.o
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
new file mode 100644 (file)
index 0000000..5cf2993
--- /dev/null
@@ -0,0 +1,826 @@
+/******************************************************************************
+ *
+ * Back-end of the driver for virtual block devices. This portion of the
+ * driver exports a 'unified' block-device interface that can be accessed
+ * by any operating system that implements a compatible front end. A
+ * reference front-end implementation can be found in:
+ *  drivers/block/xen-blkfront.c
+ *
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Copyright (c) 2005, Christopher Clark
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (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/spinlock.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/freezer.h>
+
+#include <xen/events.h>
+#include <xen/page.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+#include "common.h"
+
+/*
+ * These are rather arbitrary. They are fairly large because adjacent requests
+ * pulled from a communication ring are quite likely to end up being part of
+ * the same scatter/gather request at the disc.
+ *
+ * ** TRY INCREASING 'xen_blkif_reqs' IF WRITE SPEEDS SEEM TOO LOW **
+ *
+ * This will increase the chances of being able to write whole tracks.
+ * 64 should be enough to keep us competitive with Linux.
+ */
+static int xen_blkif_reqs = 64;
+module_param_named(reqs, xen_blkif_reqs, int, 0);
+MODULE_PARM_DESC(reqs, "Number of blkback requests to allocate");
+
+/* Run-time switchable: /sys/module/blkback/parameters/ */
+static unsigned int log_stats;
+module_param(log_stats, int, 0644);
+
+/*
+ * Each outstanding request that we've passed to the lower device layers has a
+ * 'pending_req' allocated to it. Each buffer_head that completes decrements
+ * the pendcnt towards zero. When it hits zero, the specified domain has a
+ * response queued for it, with the saved 'id' passed back.
+ */
+struct pending_req {
+       struct xen_blkif        *blkif;
+       u64                     id;
+       int                     nr_pages;
+       atomic_t                pendcnt;
+       unsigned short          operation;
+       int                     status;
+       struct list_head        free_list;
+};
+
+#define BLKBACK_INVALID_HANDLE (~0)
+
+struct xen_blkbk {
+       struct pending_req      *pending_reqs;
+       /* List of all 'pending_req' available */
+       struct list_head        pending_free;
+       /* And its spinlock. */
+       spinlock_t              pending_free_lock;
+       wait_queue_head_t       pending_free_wq;
+       /* The list of all pages that are available. */
+       struct page             **pending_pages;
+       /* And the grant handles that are available. */
+       grant_handle_t          *pending_grant_handles;
+};
+
+static struct xen_blkbk *blkbk;
+
+/*
+ * Little helpful macro to figure out the index and virtual address of the
+ * pending_pages[..]. For each 'pending_req' we have have up to
+ * BLKIF_MAX_SEGMENTS_PER_REQUEST (11) pages. The seg would be from 0 through
+ * 10 and would index in the pending_pages[..].
+ */
+static inline int vaddr_pagenr(struct pending_req *req, int seg)
+{
+       return (req - blkbk->pending_reqs) *
+               BLKIF_MAX_SEGMENTS_PER_REQUEST + seg;
+}
+
+#define pending_page(req, seg) pending_pages[vaddr_pagenr(req, seg)]
+
+static inline unsigned long vaddr(struct pending_req *req, int seg)
+{
+       unsigned long pfn = page_to_pfn(blkbk->pending_page(req, seg));
+       return (unsigned long)pfn_to_kaddr(pfn);
+}
+
+#define pending_handle(_req, _seg) \
+       (blkbk->pending_grant_handles[vaddr_pagenr(_req, _seg)])
+
+
+static int do_block_io_op(struct xen_blkif *blkif);
+static int dispatch_rw_block_io(struct xen_blkif *blkif,
+                               struct blkif_request *req,
+                               struct pending_req *pending_req);
+static void make_response(struct xen_blkif *blkif, u64 id,
+                         unsigned short op, int st);
+
+/*
+ * Retrieve from the 'pending_reqs' a free pending_req structure to be used.
+ */
+static struct pending_req *alloc_req(void)
+{
+       struct pending_req *req = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&blkbk->pending_free_lock, flags);
+       if (!list_empty(&blkbk->pending_free)) {
+               req = list_entry(blkbk->pending_free.next, struct pending_req,
+                                free_list);
+               list_del(&req->free_list);
+       }
+       spin_unlock_irqrestore(&blkbk->pending_free_lock, flags);
+       return req;
+}
+
+/*
+ * Return the 'pending_req' structure back to the freepool. We also
+ * wake up the thread if it was waiting for a free page.
+ */
+static void free_req(struct pending_req *req)
+{
+       unsigned long flags;
+       int was_empty;
+
+       spin_lock_irqsave(&blkbk->pending_free_lock, flags);
+       was_empty = list_empty(&blkbk->pending_free);
+       list_add(&req->free_list, &blkbk->pending_free);
+       spin_unlock_irqrestore(&blkbk->pending_free_lock, flags);
+       if (was_empty)
+               wake_up(&blkbk->pending_free_wq);
+}
+
+/*
+ * Routines for managing virtual block devices (vbds).
+ */
+static int xen_vbd_translate(struct phys_req *req, struct xen_blkif *blkif,
+                            int operation)
+{
+       struct xen_vbd *vbd = &blkif->vbd;
+       int rc = -EACCES;
+
+       if ((operation != READ) && vbd->readonly)
+               goto out;
+
+       if (likely(req->nr_sects)) {
+               blkif_sector_t end = req->sector_number + req->nr_sects;
+
+               if (unlikely(end < req->sector_number))
+                       goto out;
+               if (unlikely(end > vbd_sz(vbd)))
+                       goto out;
+       }
+
+       req->dev  = vbd->pdevice;
+       req->bdev = vbd->bdev;
+       rc = 0;
+
+ out:
+       return rc;
+}
+
+static void xen_vbd_resize(struct xen_blkif *blkif)
+{
+       struct xen_vbd *vbd = &blkif->vbd;
+       struct xenbus_transaction xbt;
+       int err;
+       struct xenbus_device *dev = xen_blkbk_xenbus(blkif->be);
+       unsigned long long new_size = vbd_sz(vbd);
+
+       pr_info(DRV_PFX "VBD Resize: Domid: %d, Device: (%d, %d)\n",
+               blkif->domid, MAJOR(vbd->pdevice), MINOR(vbd->pdevice));
+       pr_info(DRV_PFX "VBD Resize: new size %llu\n", new_size);
+       vbd->size = new_size;
+again:
+       err = xenbus_transaction_start(&xbt);
+       if (err) {
+               pr_warn(DRV_PFX "Error starting transaction");
+               return;
+       }
+       err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu",
+                           (unsigned long long)vbd_sz(vbd));
+       if (err) {
+               pr_warn(DRV_PFX "Error writing new size");
+               goto abort;
+       }
+       /*
+        * Write the current state; we will use this to synchronize
+        * the front-end. If the current state is "connected" the
+        * front-end will get the new size information online.
+        */
+       err = xenbus_printf(xbt, dev->nodename, "state", "%d", dev->state);
+       if (err) {
+               pr_warn(DRV_PFX "Error writing the state");
+               goto abort;
+       }
+
+       err = xenbus_transaction_end(xbt, 0);
+       if (err == -EAGAIN)
+               goto again;
+       if (err)
+               pr_warn(DRV_PFX "Error ending transaction");
+       return;
+abort:
+       xenbus_transaction_end(xbt, 1);
+}
+
+/*
+ * Notification from the guest OS.
+ */
+static void blkif_notify_work(struct xen_blkif *blkif)
+{
+       blkif->waiting_reqs = 1;
+       wake_up(&blkif->wq);
+}
+
+irqreturn_t xen_blkif_be_int(int irq, void *dev_id)
+{
+       blkif_notify_work(dev_id);
+       return IRQ_HANDLED;
+}
+
+/*
+ * SCHEDULER FUNCTIONS
+ */
+
+static void print_stats(struct xen_blkif *blkif)
+{
+       pr_info("xen-blkback (%s): oo %3d  |  rd %4d  |  wr %4d  |  f %4d\n",
+                current->comm, blkif->st_oo_req,
+                blkif->st_rd_req, blkif->st_wr_req, blkif->st_f_req);
+       blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
+       blkif->st_rd_req = 0;
+       blkif->st_wr_req = 0;
+       blkif->st_oo_req = 0;
+}
+
+int xen_blkif_schedule(void *arg)
+{
+       struct xen_blkif *blkif = arg;
+       struct xen_vbd *vbd = &blkif->vbd;
+
+       xen_blkif_get(blkif);
+
+       while (!kthread_should_stop()) {
+               if (try_to_freeze())
+                       continue;
+               if (unlikely(vbd->size != vbd_sz(vbd)))
+                       xen_vbd_resize(blkif);
+
+               wait_event_interruptible(
+                       blkif->wq,
+                       blkif->waiting_reqs || kthread_should_stop());
+               wait_event_interruptible(
+                       blkbk->pending_free_wq,
+                       !list_empty(&blkbk->pending_free) ||
+                       kthread_should_stop());
+
+               blkif->waiting_reqs = 0;
+               smp_mb(); /* clear flag *before* checking for work */
+
+               if (do_block_io_op(blkif))
+                       blkif->waiting_reqs = 1;
+
+               if (log_stats && time_after(jiffies, blkif->st_print))
+                       print_stats(blkif);
+       }
+
+       if (log_stats)
+               print_stats(blkif);
+
+       blkif->xenblkd = NULL;
+       xen_blkif_put(blkif);
+
+       return 0;
+}
+
+struct seg_buf {
+       unsigned long buf;
+       unsigned int nsec;
+};
+/*
+ * Unmap the grant references, and also remove the M2P over-rides
+ * used in the 'pending_req'.
+ */
+static void xen_blkbk_unmap(struct pending_req *req)
+{
+       struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+       unsigned int i, invcount = 0;
+       grant_handle_t handle;
+       int ret;
+
+       for (i = 0; i < req->nr_pages; i++) {
+               handle = pending_handle(req, i);
+               if (handle == BLKBACK_INVALID_HANDLE)
+                       continue;
+               gnttab_set_unmap_op(&unmap[invcount], vaddr(req, i),
+                                   GNTMAP_host_map, handle);
+               pending_handle(req, i) = BLKBACK_INVALID_HANDLE;
+               invcount++;
+       }
+
+       ret = HYPERVISOR_grant_table_op(
+               GNTTABOP_unmap_grant_ref, unmap, invcount);
+       BUG_ON(ret);
+       /*
+        * Note, we use invcount, so nr->pages, so we can't index
+        * using vaddr(req, i).
+        */
+       for (i = 0; i < invcount; i++) {
+               ret = m2p_remove_override(
+                       virt_to_page(unmap[i].host_addr), false);
+               if (ret) {
+                       pr_alert(DRV_PFX "Failed to remove M2P override for %lx\n",
+                                (unsigned long)unmap[i].host_addr);
+                       continue;
+               }
+       }
+}
+
+static int xen_blkbk_map(struct blkif_request *req,
+                        struct pending_req *pending_req,
+                        struct seg_buf seg[])
+{
+       struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+       int i;
+       int nseg = req->nr_segments;
+       int ret = 0;
+
+       /*
+        * Fill out preq.nr_sects with proper amount of sectors, and setup
+        * assign map[..] with the PFN of the page in our domain with the
+        * corresponding grant reference for each page.
+        */
+       for (i = 0; i < nseg; i++) {
+               uint32_t flags;
+
+               flags = GNTMAP_host_map;
+               if (pending_req->operation != BLKIF_OP_READ)
+                       flags |= GNTMAP_readonly;
+               gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags,
+                                 req->u.rw.seg[i].gref,
+                                 pending_req->blkif->domid);
+       }
+
+       ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, nseg);
+       BUG_ON(ret);
+
+       /*
+        * Now swizzle the MFN in our domain with the MFN from the other domain
+        * so that when we access vaddr(pending_req,i) it has the contents of
+        * the page from the other domain.
+        */
+       for (i = 0; i < nseg; i++) {
+               if (unlikely(map[i].status != 0)) {
+                       pr_debug(DRV_PFX "invalid buffer -- could not remap it\n");
+                       map[i].handle = BLKBACK_INVALID_HANDLE;
+                       ret |= 1;
+               }
+
+               pending_handle(pending_req, i) = map[i].handle;
+
+               if (ret)
+                       continue;
+
+               ret = m2p_add_override(PFN_DOWN(map[i].dev_bus_addr),
+                       blkbk->pending_page(pending_req, i), false);
+               if (ret) {
+                       pr_alert(DRV_PFX "Failed to install M2P override for %lx (ret: %d)\n",
+                                (unsigned long)map[i].dev_bus_addr, ret);
+                       /* We could switch over to GNTTABOP_copy */
+                       continue;
+               }
+
+               seg[i].buf  = map[i].dev_bus_addr |
+                       (req->u.rw.seg[i].first_sect << 9);
+       }
+       return ret;
+}
+
+/*
+ * Completion callback on the bio's. Called as bh->b_end_io()
+ */
+
+static void __end_block_io_op(struct pending_req *pending_req, int error)
+{
+       /* An error fails the entire request. */
+       if ((pending_req->operation == BLKIF_OP_FLUSH_DISKCACHE) &&
+           (error == -EOPNOTSUPP)) {
+               pr_debug(DRV_PFX "flush diskcache op failed, not supported\n");
+               xen_blkbk_flush_diskcache(XBT_NIL, pending_req->blkif->be, 0);
+               pending_req->status = BLKIF_RSP_EOPNOTSUPP;
+       } else if (error) {
+               pr_debug(DRV_PFX "Buffer not up-to-date at end of operation,"
+                        " error=%d\n", error);
+               pending_req->status = BLKIF_RSP_ERROR;
+       }
+
+       /*
+        * If all of the bio's have completed it is time to unmap
+        * the grant references associated with 'request' and provide
+        * the proper response on the ring.
+        */
+       if (atomic_dec_and_test(&pending_req->pendcnt)) {
+               xen_blkbk_unmap(pending_req);
+               make_response(pending_req->blkif, pending_req->id,
+                             pending_req->operation, pending_req->status);
+               xen_blkif_put(pending_req->blkif);
+               free_req(pending_req);
+       }
+}
+
+/*
+ * bio callback.
+ */
+static void end_block_io_op(struct bio *bio, int error)
+{
+       __end_block_io_op(bio->bi_private, error);
+       bio_put(bio);
+}
+
+
+
+/*
+ * Function to copy the from the ring buffer the 'struct blkif_request'
+ * (which has the sectors we want, number of them, grant references, etc),
+ * and transmute  it to the block API to hand it over to the proper block disk.
+ */
+static int do_block_io_op(struct xen_blkif *blkif)
+{
+       union blkif_back_rings *blk_rings = &blkif->blk_rings;
+       struct blkif_request req;
+       struct pending_req *pending_req;
+       RING_IDX rc, rp;
+       int more_to_do = 0;
+
+       rc = blk_rings->common.req_cons;
+       rp = blk_rings->common.sring->req_prod;
+       rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+       while (rc != rp) {
+
+               if (RING_REQUEST_CONS_OVERFLOW(&blk_rings->common, rc))
+                       break;
+
+               if (kthread_should_stop()) {
+                       more_to_do = 1;
+                       break;
+               }
+
+               pending_req = alloc_req();
+               if (NULL == pending_req) {
+                       blkif->st_oo_req++;
+                       more_to_do = 1;
+                       break;
+               }
+
+               switch (blkif->blk_protocol) {
+               case BLKIF_PROTOCOL_NATIVE:
+                       memcpy(&req, RING_GET_REQUEST(&blk_rings->native, rc), sizeof(req));
+                       break;
+               case BLKIF_PROTOCOL_X86_32:
+                       blkif_get_x86_32_req(&req, RING_GET_REQUEST(&blk_rings->x86_32, rc));
+                       break;
+               case BLKIF_PROTOCOL_X86_64:
+                       blkif_get_x86_64_req(&req, RING_GET_REQUEST(&blk_rings->x86_64, rc));
+                       break;
+               default:
+                       BUG();
+               }
+               blk_rings->common.req_cons = ++rc; /* before make_response() */
+
+               /* Apply all sanity checks to /private copy/ of request. */
+               barrier();
+
+               if (dispatch_rw_block_io(blkif, &req, pending_req))
+                       break;
+
+               /* Yield point for this unbounded loop. */
+               cond_resched();
+       }
+
+       return more_to_do;
+}
+
+/*
+ * Transmutation of the 'struct blkif_request' to a proper 'struct bio'
+ * and call the 'submit_bio' to pass it to the underlying storage.
+ */
+static int dispatch_rw_block_io(struct xen_blkif *blkif,
+                               struct blkif_request *req,
+                               struct pending_req *pending_req)
+{
+       struct phys_req preq;
+       struct seg_buf seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+       unsigned int nseg;
+       struct bio *bio = NULL;
+       struct bio *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+       int i, nbio = 0;
+       int operation;
+       struct blk_plug plug;
+
+       switch (req->operation) {
+       case BLKIF_OP_READ:
+               blkif->st_rd_req++;
+               operation = READ;
+               break;
+       case BLKIF_OP_WRITE:
+               blkif->st_wr_req++;
+               operation = WRITE_ODIRECT;
+               break;
+       case BLKIF_OP_FLUSH_DISKCACHE:
+               blkif->st_f_req++;
+               operation = WRITE_FLUSH;
+               break;
+       case BLKIF_OP_WRITE_BARRIER:
+       default:
+               operation = 0; /* make gcc happy */
+               goto fail_response;
+               break;
+       }
+
+       /* Check that the number of segments is sane. */
+       nseg = req->nr_segments;
+       if (unlikely(nseg == 0 && operation != WRITE_FLUSH) ||
+           unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) {
+               pr_debug(DRV_PFX "Bad number of segments in request (%d)\n",
+                        nseg);
+               /* Haven't submitted any bio's yet. */
+               goto fail_response;
+       }
+
+       preq.dev           = req->handle;
+       preq.sector_number = req->u.rw.sector_number;
+       preq.nr_sects      = 0;
+
+       pending_req->blkif     = blkif;
+       pending_req->id        = req->id;
+       pending_req->operation = req->operation;
+       pending_req->status    = BLKIF_RSP_OKAY;
+       pending_req->nr_pages  = nseg;
+
+       for (i = 0; i < nseg; i++) {
+               seg[i].nsec = req->u.rw.seg[i].last_sect -
+                       req->u.rw.seg[i].first_sect + 1;
+               if ((req->u.rw.seg[i].last_sect >= (PAGE_SIZE >> 9)) ||
+                   (req->u.rw.seg[i].last_sect < req->u.rw.seg[i].first_sect))
+                       goto fail_response;
+               preq.nr_sects += seg[i].nsec;
+
+       }
+
+       if (xen_vbd_translate(&preq, blkif, operation) != 0) {
+               pr_debug(DRV_PFX "access denied: %s of [%llu,%llu] on dev=%04x\n",
+                        operation == READ ? "read" : "write",
+                        preq.sector_number,
+                        preq.sector_number + preq.nr_sects, preq.dev);
+               goto fail_response;
+       }
+
+       /*
+        * This check _MUST_ be done after xen_vbd_translate as the preq.bdev
+        * is set there.
+        */
+       for (i = 0; i < nseg; i++) {
+               if (((int)preq.sector_number|(int)seg[i].nsec) &
+                   ((bdev_logical_block_size(preq.bdev) >> 9) - 1)) {
+                       pr_debug(DRV_PFX "Misaligned I/O request from domain %d",
+                                blkif->domid);
+                       goto fail_response;
+               }
+       }
+
+       /*
+        * If we have failed at this point, we need to undo the M2P override,
+        * set gnttab_set_unmap_op on all of the grant references and perform
+        * the hypercall to unmap the grants - that is all done in
+        * xen_blkbk_unmap.
+        */
+       if (xen_blkbk_map(req, pending_req, seg))
+               goto fail_flush;
+
+       /* This corresponding xen_blkif_put is done in __end_block_io_op */
+       xen_blkif_get(blkif);
+
+       for (i = 0; i < nseg; i++) {
+               while ((bio == NULL) ||
+                      (bio_add_page(bio,
+                                    blkbk->pending_page(pending_req, i),
+                                    seg[i].nsec << 9,
+                                    seg[i].buf & ~PAGE_MASK) == 0)) {
+
+                       bio = bio_alloc(GFP_KERNEL, nseg-i);
+                       if (unlikely(bio == NULL))
+                               goto fail_put_bio;
+
+                       biolist[nbio++] = bio;
+                       bio->bi_bdev    = preq.bdev;
+                       bio->bi_private = pending_req;
+                       bio->bi_end_io  = end_block_io_op;
+                       bio->bi_sector  = preq.sector_number;
+               }
+
+               preq.sector_number += seg[i].nsec;
+       }
+
+       /* This will be hit if the operation was a flush. */
+       if (!bio) {
+               BUG_ON(operation != WRITE_FLUSH);
+
+               bio = bio_alloc(GFP_KERNEL, 0);
+               if (unlikely(bio == NULL))
+                       goto fail_put_bio;
+
+               biolist[nbio++] = bio;
+               bio->bi_bdev    = preq.bdev;
+               bio->bi_private = pending_req;
+               bio->bi_end_io  = end_block_io_op;
+       }
+
+       /*
+        * We set it one so that the last submit_bio does not have to call
+        * atomic_inc.
+        */
+       atomic_set(&pending_req->pendcnt, nbio);
+
+       /* Get a reference count for the disk queue and start sending I/O */
+       blk_start_plug(&plug);
+
+       for (i = 0; i < nbio; i++)
+               submit_bio(operation, biolist[i]);
+
+       /* Let the I/Os go.. */
+       blk_finish_plug(&plug);
+
+       if (operation == READ)
+               blkif->st_rd_sect += preq.nr_sects;
+       else if (operation == WRITE || operation == WRITE_FLUSH)
+               blkif->st_wr_sect += preq.nr_sects;
+
+       return 0;
+
+ fail_flush:
+       xen_blkbk_unmap(pending_req);
+ fail_response:
+       /* Haven't submitted any bio's yet. */
+       make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
+       free_req(pending_req);
+       msleep(1); /* back off a bit */
+       return -EIO;
+
+ fail_put_bio:
+       for (i = 0; i < nbio; i++)
+               bio_put(biolist[i]);
+       __end_block_io_op(pending_req, -EINVAL);
+       msleep(1); /* back off a bit */
+       return -EIO;
+}
+
+
+
+/*
+ * Put a response on the ring on how the operation fared.
+ */
+static void make_response(struct xen_blkif *blkif, u64 id,
+                         unsigned short op, int st)
+{
+       struct blkif_response  resp;
+       unsigned long     flags;
+       union blkif_back_rings *blk_rings = &blkif->blk_rings;
+       int more_to_do = 0;
+       int notify;
+
+       resp.id        = id;
+       resp.operation = op;
+       resp.status    = st;
+
+       spin_lock_irqsave(&blkif->blk_ring_lock, flags);
+       /* Place on the response ring for the relevant domain. */
+       switch (blkif->blk_protocol) {
+       case BLKIF_PROTOCOL_NATIVE:
+               memcpy(RING_GET_RESPONSE(&blk_rings->native, blk_rings->native.rsp_prod_pvt),
+                      &resp, sizeof(resp));
+               break;
+       case BLKIF_PROTOCOL_X86_32:
+               memcpy(RING_GET_RESPONSE(&blk_rings->x86_32, blk_rings->x86_32.rsp_prod_pvt),
+                      &resp, sizeof(resp));
+               break;
+       case BLKIF_PROTOCOL_X86_64:
+               memcpy(RING_GET_RESPONSE(&blk_rings->x86_64, blk_rings->x86_64.rsp_prod_pvt),
+                      &resp, sizeof(resp));
+               break;
+       default:
+               BUG();
+       }
+       blk_rings->common.rsp_prod_pvt++;
+       RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blk_rings->common, notify);
+       if (blk_rings->common.rsp_prod_pvt == blk_rings->common.req_cons) {
+               /*
+                * Tail check for pending requests. Allows frontend to avoid
+                * notifications if requests are already in flight (lower
+                * overheads and promotes batching).
+                */
+               RING_FINAL_CHECK_FOR_REQUESTS(&blk_rings->common, more_to_do);
+
+       } else if (RING_HAS_UNCONSUMED_REQUESTS(&blk_rings->common)) {
+               more_to_do = 1;
+       }
+
+       spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
+
+       if (more_to_do)
+               blkif_notify_work(blkif);
+       if (notify)
+               notify_remote_via_irq(blkif->irq);
+}
+
+static int __init xen_blkif_init(void)
+{
+       int i, mmap_pages;
+       int rc = 0;
+
+       if (!xen_pv_domain())
+               return -ENODEV;
+
+       blkbk = kzalloc(sizeof(struct xen_blkbk), GFP_KERNEL);
+       if (!blkbk) {
+               pr_alert(DRV_PFX "%s: out of memory!\n", __func__);
+               return -ENOMEM;
+       }
+
+       mmap_pages = xen_blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST;
+
+       blkbk->pending_reqs          = kmalloc(sizeof(blkbk->pending_reqs[0]) *
+                                       xen_blkif_reqs, GFP_KERNEL);
+       blkbk->pending_grant_handles = kzalloc(sizeof(blkbk->pending_grant_handles[0]) *
+                                       mmap_pages, GFP_KERNEL);
+       blkbk->pending_pages         = kzalloc(sizeof(blkbk->pending_pages[0]) *
+                                       mmap_pages, GFP_KERNEL);
+
+       if (!blkbk->pending_reqs || !blkbk->pending_grant_handles ||
+           !blkbk->pending_pages) {
+               rc = -ENOMEM;
+               goto out_of_memory;
+       }
+
+       for (i = 0; i < mmap_pages; i++) {
+               blkbk->pending_grant_handles[i] = BLKBACK_INVALID_HANDLE;
+               blkbk->pending_pages[i] = alloc_page(GFP_KERNEL);
+               if (blkbk->pending_pages[i] == NULL) {
+                       rc = -ENOMEM;
+                       goto out_of_memory;
+               }
+       }
+       rc = xen_blkif_interface_init();
+       if (rc)
+               goto failed_init;
+
+       memset(blkbk->pending_reqs, 0, sizeof(blkbk->pending_reqs));
+
+       INIT_LIST_HEAD(&blkbk->pending_free);
+       spin_lock_init(&blkbk->pending_free_lock);
+       init_waitqueue_head(&blkbk->pending_free_wq);
+
+       for (i = 0; i < xen_blkif_reqs; i++)
+               list_add_tail(&blkbk->pending_reqs[i].free_list,
+                             &blkbk->pending_free);
+
+       rc = xen_blkif_xenbus_init();
+       if (rc)
+               goto failed_init;
+
+       return 0;
+
+ out_of_memory:
+       pr_alert(DRV_PFX "%s: out of memory\n", __func__);
+ failed_init:
+       kfree(blkbk->pending_reqs);
+       kfree(blkbk->pending_grant_handles);
+       if (blkbk->pending_pages) {
+               for (i = 0; i < mmap_pages; i++) {
+                       if (blkbk->pending_pages[i])
+                               __free_page(blkbk->pending_pages[i]);
+               }
+               kfree(blkbk->pending_pages);
+       }
+       kfree(blkbk);
+       blkbk = NULL;
+       return rc;
+}
+
+module_init(xen_blkif_init);
+
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h
new file mode 100644 (file)
index 0000000..9e40b28
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (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.
+ */
+
+#ifndef __XEN_BLKIF__BACKEND__COMMON_H__
+#define __XEN_BLKIF__BACKEND__COMMON_H__
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <linux/io.h>
+#include <asm/setup.h>
+#include <asm/pgalloc.h>
+#include <asm/hypervisor.h>
+#include <xen/grant_table.h>
+#include <xen/xenbus.h>
+#include <xen/interface/io/ring.h>
+#include <xen/interface/io/blkif.h>
+#include <xen/interface/io/protocols.h>
+
+#define DRV_PFX "xen-blkback:"
+#define DPRINTK(fmt, args...)                          \
+       pr_debug(DRV_PFX "(%s:%d) " fmt ".\n",  \
+                __func__, __LINE__, ##args)
+
+
+/* Not a real protocol.  Used to generate ring structs which contain
+ * the elements common to all protocols only.  This way we get a
+ * compiler-checkable way to use common struct elements, so we can
+ * avoid using switch(protocol) in a number of places.  */
+struct blkif_common_request {
+       char dummy;
+};
+struct blkif_common_response {
+       char dummy;
+};
+
+/* i386 protocol version */
+#pragma pack(push, 4)
+struct blkif_x86_32_request {
+       uint8_t        operation;    /* BLKIF_OP_???                         */
+       uint8_t        nr_segments;  /* number of segments                   */
+       blkif_vdev_t   handle;       /* only for read/write requests         */
+       uint64_t       id;           /* private guest value, echoed in resp  */
+       blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
+       struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+struct blkif_x86_32_response {
+       uint64_t        id;              /* copied from request */
+       uint8_t         operation;       /* copied from request */
+       int16_t         status;          /* BLKIF_RSP_???       */
+};
+#pragma pack(pop)
+
+/* x86_64 protocol version */
+struct blkif_x86_64_request {
+       uint8_t        operation;    /* BLKIF_OP_???                         */
+       uint8_t        nr_segments;  /* number of segments                   */
+       blkif_vdev_t   handle;       /* only for read/write requests         */
+       uint64_t       __attribute__((__aligned__(8))) id;
+       blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
+       struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+struct blkif_x86_64_response {
+       uint64_t       __attribute__((__aligned__(8))) id;
+       uint8_t         operation;       /* copied from request */
+       int16_t         status;          /* BLKIF_RSP_???       */
+};
+
+DEFINE_RING_TYPES(blkif_common, struct blkif_common_request,
+                 struct blkif_common_response);
+DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request,
+                 struct blkif_x86_32_response);
+DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request,
+                 struct blkif_x86_64_response);
+
+union blkif_back_rings {
+       struct blkif_back_ring        native;
+       struct blkif_common_back_ring common;
+       struct blkif_x86_32_back_ring x86_32;
+       struct blkif_x86_64_back_ring x86_64;
+};
+
+enum blkif_protocol {
+       BLKIF_PROTOCOL_NATIVE = 1,
+       BLKIF_PROTOCOL_X86_32 = 2,
+       BLKIF_PROTOCOL_X86_64 = 3,
+};
+
+struct xen_vbd {
+       /* What the domain refers to this vbd as. */
+       blkif_vdev_t            handle;
+       /* Non-zero -> read-only */
+       unsigned char           readonly;
+       /* VDISK_xxx */
+       unsigned char           type;
+       /* phys device that this vbd maps to. */
+       u32                     pdevice;
+       struct block_device     *bdev;
+       /* Cached size parameter. */
+       sector_t                size;
+       bool                    flush_support;
+};
+
+struct backend_info;
+
+struct xen_blkif {
+       /* Unique identifier for this interface. */
+       domid_t                 domid;
+       unsigned int            handle;
+       /* Physical parameters of the comms window. */
+       unsigned int            irq;
+       /* Comms information. */
+       enum blkif_protocol     blk_protocol;
+       union blkif_back_rings  blk_rings;
+       struct vm_struct        *blk_ring_area;
+       /* The VBD attached to this interface. */
+       struct xen_vbd          vbd;
+       /* Back pointer to the backend_info. */
+       struct backend_info     *be;
+       /* Private fields. */
+       spinlock_t              blk_ring_lock;
+       atomic_t                refcnt;
+
+       wait_queue_head_t       wq;
+       /* One thread per one blkif. */
+       struct task_struct      *xenblkd;
+       unsigned int            waiting_reqs;
+
+       /* statistics */
+       unsigned long           st_print;
+       int                     st_rd_req;
+       int                     st_wr_req;
+       int                     st_oo_req;
+       int                     st_f_req;
+       int                     st_rd_sect;
+       int                     st_wr_sect;
+
+       wait_queue_head_t       waiting_to_free;
+
+       grant_handle_t          shmem_handle;
+       grant_ref_t             shmem_ref;
+};
+
+
+#define vbd_sz(_v)     ((_v)->bdev->bd_part ? \
+                        (_v)->bdev->bd_part->nr_sects : \
+                         get_capacity((_v)->bdev->bd_disk))
+
+#define xen_blkif_get(_b) (atomic_inc(&(_b)->refcnt))
+#define xen_blkif_put(_b)                              \
+       do {                                            \
+               if (atomic_dec_and_test(&(_b)->refcnt)) \
+                       wake_up(&(_b)->waiting_to_free);\
+       } while (0)
+
+struct phys_req {
+       unsigned short          dev;
+       unsigned short          nr_sects;
+       struct block_device     *bdev;
+       blkif_sector_t          sector_number;
+};
+int xen_blkif_interface_init(void);
+
+int xen_blkif_xenbus_init(void);
+
+irqreturn_t xen_blkif_be_int(int irq, void *dev_id);
+int xen_blkif_schedule(void *arg);
+
+int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt,
+                             struct backend_info *be, int state);
+
+struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be);
+
+static inline void blkif_get_x86_32_req(struct blkif_request *dst,
+                                       struct blkif_x86_32_request *src)
+{
+       int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+       dst->operation = src->operation;
+       dst->nr_segments = src->nr_segments;
+       dst->handle = src->handle;
+       dst->id = src->id;
+       dst->u.rw.sector_number = src->sector_number;
+       barrier();
+       if (n > dst->nr_segments)
+               n = dst->nr_segments;
+       for (i = 0; i < n; i++)
+               dst->u.rw.seg[i] = src->seg[i];
+}
+
+static inline void blkif_get_x86_64_req(struct blkif_request *dst,
+                                       struct blkif_x86_64_request *src)
+{
+       int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+       dst->operation = src->operation;
+       dst->nr_segments = src->nr_segments;
+       dst->handle = src->handle;
+       dst->id = src->id;
+       dst->u.rw.sector_number = src->sector_number;
+       barrier();
+       if (n > dst->nr_segments)
+               n = dst->nr_segments;
+       for (i = 0; i < n; i++)
+               dst->u.rw.seg[i] = src->seg[i];
+}
+
+#endif /* __XEN_BLKIF__BACKEND__COMMON_H__ */
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c
new file mode 100644 (file)
index 0000000..6cc0db1
--- /dev/null
@@ -0,0 +1,767 @@
+/*  Xenbus code for blkif backend
+    Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
+    Copyright (C) 2005 XenSource Ltd
+
+    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 <stdarg.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <xen/events.h>
+#include <xen/grant_table.h>
+#include "common.h"
+
+struct backend_info {
+       struct xenbus_device    *dev;
+       struct xen_blkif        *blkif;
+       struct xenbus_watch     backend_watch;
+       unsigned                major;
+       unsigned                minor;
+       char                    *mode;
+};
+
+static struct kmem_cache *xen_blkif_cachep;
+static void connect(struct backend_info *);
+static int connect_ring(struct backend_info *);
+static void backend_changed(struct xenbus_watch *, const char **,
+                           unsigned int);
+
+struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be)
+{
+       return be->dev;
+}
+
+static int blkback_name(struct xen_blkif *blkif, char *buf)
+{
+       char *devpath, *devname;
+       struct xenbus_device *dev = blkif->be->dev;
+
+       devpath = xenbus_read(XBT_NIL, dev->nodename, "dev", NULL);
+       if (IS_ERR(devpath))
+               return PTR_ERR(devpath);
+
+       devname = strstr(devpath, "/dev/");
+       if (devname != NULL)
+               devname += strlen("/dev/");
+       else
+               devname  = devpath;
+
+       snprintf(buf, TASK_COMM_LEN, "blkback.%d.%s", blkif->domid, devname);
+       kfree(devpath);
+
+       return 0;
+}
+
+static void xen_update_blkif_status(struct xen_blkif *blkif)
+{
+       int err;
+       char name[TASK_COMM_LEN];
+
+       /* Not ready to connect? */
+       if (!blkif->irq || !blkif->vbd.bdev)
+               return;
+
+       /* Already connected? */
+       if (blkif->be->dev->state == XenbusStateConnected)
+               return;
+
+       /* Attempt to connect: exit if we fail to. */
+       connect(blkif->be);
+       if (blkif->be->dev->state != XenbusStateConnected)
+               return;
+
+       err = blkback_name(blkif, name);
+       if (err) {
+               xenbus_dev_error(blkif->be->dev, err, "get blkback dev name");
+               return;
+       }
+
+       err = filemap_write_and_wait(blkif->vbd.bdev->bd_inode->i_mapping);
+       if (err) {
+               xenbus_dev_error(blkif->be->dev, err, "block flush");
+               return;
+       }
+       invalidate_inode_pages2(blkif->vbd.bdev->bd_inode->i_mapping);
+
+       blkif->xenblkd = kthread_run(xen_blkif_schedule, blkif, name);
+       if (IS_ERR(blkif->xenblkd)) {
+               err = PTR_ERR(blkif->xenblkd);
+               blkif->xenblkd = NULL;
+               xenbus_dev_error(blkif->be->dev, err, "start xenblkd");
+       }
+}
+
+static struct xen_blkif *xen_blkif_alloc(domid_t domid)
+{
+       struct xen_blkif *blkif;
+
+       blkif = kmem_cache_alloc(xen_blkif_cachep, GFP_KERNEL);
+       if (!blkif)
+               return ERR_PTR(-ENOMEM);
+
+       memset(blkif, 0, sizeof(*blkif));
+       blkif->domid = domid;
+       spin_lock_init(&blkif->blk_ring_lock);
+       atomic_set(&blkif->refcnt, 1);
+       init_waitqueue_head(&blkif->wq);
+       blkif->st_print = jiffies;
+       init_waitqueue_head(&blkif->waiting_to_free);
+
+       return blkif;
+}
+
+static int map_frontend_page(struct xen_blkif *blkif, unsigned long shared_page)
+{
+       struct gnttab_map_grant_ref op;
+
+       gnttab_set_map_op(&op, (unsigned long)blkif->blk_ring_area->addr,
+                         GNTMAP_host_map, shared_page, blkif->domid);
+
+       if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+               BUG();
+
+       if (op.status) {
+               DPRINTK("Grant table operation failure !\n");
+               return op.status;
+       }
+
+       blkif->shmem_ref = shared_page;
+       blkif->shmem_handle = op.handle;
+
+       return 0;
+}
+
+static void unmap_frontend_page(struct xen_blkif *blkif)
+{
+       struct gnttab_unmap_grant_ref op;
+
+       gnttab_set_unmap_op(&op, (unsigned long)blkif->blk_ring_area->addr,
+                           GNTMAP_host_map, blkif->shmem_handle);
+
+       if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+               BUG();
+}
+
+static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page,
+                        unsigned int evtchn)
+{
+       int err;
+
+       /* Already connected through? */
+       if (blkif->irq)
+               return 0;
+
+       blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE);
+       if (!blkif->blk_ring_area)
+               return -ENOMEM;
+
+       err = map_frontend_page(blkif, shared_page);
+       if (err) {
+               free_vm_area(blkif->blk_ring_area);
+               return err;
+       }
+
+       switch (blkif->blk_protocol) {
+       case BLKIF_PROTOCOL_NATIVE:
+       {
+               struct blkif_sring *sring;
+               sring = (struct blkif_sring *)blkif->blk_ring_area->addr;
+               BACK_RING_INIT(&blkif->blk_rings.native, sring, PAGE_SIZE);
+               break;
+       }
+       case BLKIF_PROTOCOL_X86_32:
+       {
+               struct blkif_x86_32_sring *sring_x86_32;
+               sring_x86_32 = (struct blkif_x86_32_sring *)blkif->blk_ring_area->addr;
+               BACK_RING_INIT(&blkif->blk_rings.x86_32, sring_x86_32, PAGE_SIZE);
+               break;
+       }
+       case BLKIF_PROTOCOL_X86_64:
+       {
+               struct blkif_x86_64_sring *sring_x86_64;
+               sring_x86_64 = (struct blkif_x86_64_sring *)blkif->blk_ring_area->addr;
+               BACK_RING_INIT(&blkif->blk_rings.x86_64, sring_x86_64, PAGE_SIZE);
+               break;
+       }
+       default:
+               BUG();
+       }
+
+       err = bind_interdomain_evtchn_to_irqhandler(blkif->domid, evtchn,
+                                                   xen_blkif_be_int, 0,
+                                                   "blkif-backend", blkif);
+       if (err < 0) {
+               unmap_frontend_page(blkif);
+               free_vm_area(blkif->blk_ring_area);
+               blkif->blk_rings.common.sring = NULL;
+               return err;
+       }
+       blkif->irq = err;
+
+       return 0;
+}
+
+static void xen_blkif_disconnect(struct xen_blkif *blkif)
+{
+       if (blkif->xenblkd) {
+               kthread_stop(blkif->xenblkd);
+               blkif->xenblkd = NULL;
+       }
+
+       atomic_dec(&blkif->refcnt);
+       wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0);
+       atomic_inc(&blkif->refcnt);
+
+       if (blkif->irq) {
+               unbind_from_irqhandler(blkif->irq, blkif);
+               blkif->irq = 0;
+       }
+
+       if (blkif->blk_rings.common.sring) {
+               unmap_frontend_page(blkif);
+               free_vm_area(blkif->blk_ring_area);
+               blkif->blk_rings.common.sring = NULL;
+       }
+}
+
+void xen_blkif_free(struct xen_blkif *blkif)
+{
+       if (!atomic_dec_and_test(&blkif->refcnt))
+               BUG();
+       kmem_cache_free(xen_blkif_cachep, blkif);
+}
+
+int __init xen_blkif_interface_init(void)
+{
+       xen_blkif_cachep = kmem_cache_create("blkif_cache",
+                                            sizeof(struct xen_blkif),
+                                            0, 0, NULL);
+       if (!xen_blkif_cachep)
+               return -ENOMEM;
+
+       return 0;
+}
+
+/*
+ *  sysfs interface for VBD I/O requests
+ */
+
+#define VBD_SHOW(name, format, args...)                                        \
+       static ssize_t show_##name(struct device *_dev,                 \
+                                  struct device_attribute *attr,       \
+                                  char *buf)                           \
+       {                                                               \
+               struct xenbus_device *dev = to_xenbus_device(_dev);     \
+               struct backend_info *be = dev_get_drvdata(&dev->dev);   \
+                                                                       \
+               return sprintf(buf, format, ##args);                    \
+       }                                                               \
+       static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+
+VBD_SHOW(oo_req,  "%d\n", be->blkif->st_oo_req);
+VBD_SHOW(rd_req,  "%d\n", be->blkif->st_rd_req);
+VBD_SHOW(wr_req,  "%d\n", be->blkif->st_wr_req);
+VBD_SHOW(f_req,  "%d\n", be->blkif->st_f_req);
+VBD_SHOW(rd_sect, "%d\n", be->blkif->st_rd_sect);
+VBD_SHOW(wr_sect, "%d\n", be->blkif->st_wr_sect);
+
+static struct attribute *xen_vbdstat_attrs[] = {
+       &dev_attr_oo_req.attr,
+       &dev_attr_rd_req.attr,
+       &dev_attr_wr_req.attr,
+       &dev_attr_f_req.attr,
+       &dev_attr_rd_sect.attr,
+       &dev_attr_wr_sect.attr,
+       NULL
+};
+
+static struct attribute_group xen_vbdstat_group = {
+       .name = "statistics",
+       .attrs = xen_vbdstat_attrs,
+};
+
+VBD_SHOW(physical_device, "%x:%x\n", be->major, be->minor);
+VBD_SHOW(mode, "%s\n", be->mode);
+
+int xenvbd_sysfs_addif(struct xenbus_device *dev)
+{
+       int error;
+
+       error = device_create_file(&dev->dev, &dev_attr_physical_device);
+       if (error)
+               goto fail1;
+
+       error = device_create_file(&dev->dev, &dev_attr_mode);
+       if (error)
+               goto fail2;
+
+       error = sysfs_create_group(&dev->dev.kobj, &xen_vbdstat_group);
+       if (error)
+               goto fail3;
+
+       return 0;
+
+fail3: sysfs_remove_group(&dev->dev.kobj, &xen_vbdstat_group);
+fail2: device_remove_file(&dev->dev, &dev_attr_mode);
+fail1: device_remove_file(&dev->dev, &dev_attr_physical_device);
+       return error;
+}
+
+void xenvbd_sysfs_delif(struct xenbus_device *dev)
+{
+       sysfs_remove_group(&dev->dev.kobj, &xen_vbdstat_group);
+       device_remove_file(&dev->dev, &dev_attr_mode);
+       device_remove_file(&dev->dev, &dev_attr_physical_device);
+}
+
+
+static void xen_vbd_free(struct xen_vbd *vbd)
+{
+       if (vbd->bdev)
+               blkdev_put(vbd->bdev, vbd->readonly ? FMODE_READ : FMODE_WRITE);
+       vbd->bdev = NULL;
+}
+
+static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle,
+                         unsigned major, unsigned minor, int readonly,
+                         int cdrom)
+{
+       struct xen_vbd *vbd;
+       struct block_device *bdev;
+       struct request_queue *q;
+
+       vbd = &blkif->vbd;
+       vbd->handle   = handle;
+       vbd->readonly = readonly;
+       vbd->type     = 0;
+
+       vbd->pdevice  = MKDEV(major, minor);
+
+       bdev = blkdev_get_by_dev(vbd->pdevice, vbd->readonly ?
+                                FMODE_READ : FMODE_WRITE, NULL);
+
+       if (IS_ERR(bdev)) {
+               DPRINTK("xen_vbd_create: device %08x could not be opened.\n",
+                       vbd->pdevice);
+               return -ENOENT;
+       }
+
+       vbd->bdev = bdev;
+       if (vbd->bdev->bd_disk == NULL) {
+               DPRINTK("xen_vbd_create: device %08x doesn't exist.\n",
+                       vbd->pdevice);
+               xen_vbd_free(vbd);
+               return -ENOENT;
+       }
+       vbd->size = vbd_sz(vbd);
+
+       if (vbd->bdev->bd_disk->flags & GENHD_FL_CD || cdrom)
+               vbd->type |= VDISK_CDROM;
+       if (vbd->bdev->bd_disk->flags & GENHD_FL_REMOVABLE)
+               vbd->type |= VDISK_REMOVABLE;
+
+       q = bdev_get_queue(bdev);
+       if (q && q->flush_flags)
+               vbd->flush_support = true;
+
+       DPRINTK("Successful creation of handle=%04x (dom=%u)\n",
+               handle, blkif->domid);
+       return 0;
+}
+static int xen_blkbk_remove(struct xenbus_device *dev)
+{
+       struct backend_info *be = dev_get_drvdata(&dev->dev);
+
+       DPRINTK("");
+
+       if (be->major || be->minor)
+               xenvbd_sysfs_delif(dev);
+
+       if (be->backend_watch.node) {
+               unregister_xenbus_watch(&be->backend_watch);
+               kfree(be->backend_watch.node);
+               be->backend_watch.node = NULL;
+       }
+
+       if (be->blkif) {
+               xen_blkif_disconnect(be->blkif);
+               xen_vbd_free(&be->blkif->vbd);
+               xen_blkif_free(be->blkif);
+               be->blkif = NULL;
+       }
+
+       kfree(be);
+       dev_set_drvdata(&dev->dev, NULL);
+       return 0;
+}
+
+int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt,
+                             struct backend_info *be, int state)
+{
+       struct xenbus_device *dev = be->dev;
+       int err;
+
+       err = xenbus_printf(xbt, dev->nodename, "feature-flush-cache",
+                           "%d", state);
+       if (err)
+               xenbus_dev_fatal(dev, err, "writing feature-flush-cache");
+
+       return err;
+}
+
+/*
+ * Entry point to this code when a new device is created.  Allocate the basic
+ * structures, and watch the store waiting for the hotplug scripts to tell us
+ * the device's physical major and minor numbers.  Switch to InitWait.
+ */
+static int xen_blkbk_probe(struct xenbus_device *dev,
+                          const struct xenbus_device_id *id)
+{
+       int err;
+       struct backend_info *be = kzalloc(sizeof(struct backend_info),
+                                         GFP_KERNEL);
+       if (!be) {
+               xenbus_dev_fatal(dev, -ENOMEM,
+                                "allocating backend structure");
+               return -ENOMEM;
+       }
+       be->dev = dev;
+       dev_set_drvdata(&dev->dev, be);
+
+       be->blkif = xen_blkif_alloc(dev->otherend_id);
+       if (IS_ERR(be->blkif)) {
+               err = PTR_ERR(be->blkif);
+               be->blkif = NULL;
+               xenbus_dev_fatal(dev, err, "creating block interface");
+               goto fail;
+       }
+
+       /* setup back pointer */
+       be->blkif->be = be;
+
+       err = xenbus_watch_pathfmt(dev, &be->backend_watch, backend_changed,
+                                  "%s/%s", dev->nodename, "physical-device");
+       if (err)
+               goto fail;
+
+       err = xenbus_switch_state(dev, XenbusStateInitWait);
+       if (err)
+               goto fail;
+
+       return 0;
+
+fail:
+       DPRINTK("failed");
+       xen_blkbk_remove(dev);
+       return err;
+}
+
+
+/*
+ * Callback received when the hotplug scripts have placed the physical-device
+ * node.  Read it and the mode node, and create a vbd.  If the frontend is
+ * ready, connect.
+ */
+static void backend_changed(struct xenbus_watch *watch,
+                           const char **vec, unsigned int len)
+{
+       int err;
+       unsigned major;
+       unsigned minor;
+       struct backend_info *be
+               = container_of(watch, struct backend_info, backend_watch);
+       struct xenbus_device *dev = be->dev;
+       int cdrom = 0;
+       char *device_type;
+
+       DPRINTK("");
+
+       err = xenbus_scanf(XBT_NIL, dev->nodename, "physical-device", "%x:%x",
+                          &major, &minor);
+       if (XENBUS_EXIST_ERR(err)) {
+               /*
+                * Since this watch will fire once immediately after it is
+                * registered, we expect this.  Ignore it, and wait for the
+                * hotplug scripts.
+                */
+               return;
+       }
+       if (err != 2) {
+               xenbus_dev_fatal(dev, err, "reading physical-device");
+               return;
+       }
+
+       if ((be->major || be->minor) &&
+           ((be->major != major) || (be->minor != minor))) {
+               pr_warn(DRV_PFX "changing physical device (from %x:%x to %x:%x) not supported.\n",
+                       be->major, be->minor, major, minor);
+               return;
+       }
+
+       be->mode = xenbus_read(XBT_NIL, dev->nodename, "mode", NULL);
+       if (IS_ERR(be->mode)) {
+               err = PTR_ERR(be->mode);
+               be->mode = NULL;
+               xenbus_dev_fatal(dev, err, "reading mode");
+               return;
+       }
+
+       device_type = xenbus_read(XBT_NIL, dev->otherend, "device-type", NULL);
+       if (!IS_ERR(device_type)) {
+               cdrom = strcmp(device_type, "cdrom") == 0;
+               kfree(device_type);
+       }
+
+       if (be->major == 0 && be->minor == 0) {
+               /* Front end dir is a number, which is used as the handle. */
+
+               char *p = strrchr(dev->otherend, '/') + 1;
+               long handle;
+               err = strict_strtoul(p, 0, &handle);
+               if (err)
+                       return;
+
+               be->major = major;
+               be->minor = minor;
+
+               err = xen_vbd_create(be->blkif, handle, major, minor,
+                                (NULL == strchr(be->mode, 'w')), cdrom);
+               if (err) {
+                       be->major = 0;
+                       be->minor = 0;
+                       xenbus_dev_fatal(dev, err, "creating vbd structure");
+                       return;
+               }
+
+               err = xenvbd_sysfs_addif(dev);
+               if (err) {
+                       xen_vbd_free(&be->blkif->vbd);
+                       be->major = 0;
+                       be->minor = 0;
+                       xenbus_dev_fatal(dev, err, "creating sysfs entries");
+                       return;
+               }
+
+               /* We're potentially connected now */
+               xen_update_blkif_status(be->blkif);
+       }
+}
+
+
+/*
+ * Callback received when the frontend's state changes.
+ */
+static void frontend_changed(struct xenbus_device *dev,
+                            enum xenbus_state frontend_state)
+{
+       struct backend_info *be = dev_get_drvdata(&dev->dev);
+       int err;
+
+       DPRINTK("%s", xenbus_strstate(frontend_state));
+
+       switch (frontend_state) {
+       case XenbusStateInitialising:
+               if (dev->state == XenbusStateClosed) {
+                       pr_info(DRV_PFX "%s: prepare for reconnect\n",
+                               dev->nodename);
+                       xenbus_switch_state(dev, XenbusStateInitWait);
+               }
+               break;
+
+       case XenbusStateInitialised:
+       case XenbusStateConnected:
+               /*
+                * Ensure we connect even when two watches fire in
+                * close successsion and we miss the intermediate value
+                * of frontend_state.
+                */
+               if (dev->state == XenbusStateConnected)
+                       break;
+
+               /*
+                * Enforce precondition before potential leak point.
+                * blkif_disconnect() is idempotent.
+                */
+               xen_blkif_disconnect(be->blkif);
+
+               err = connect_ring(be);
+               if (err)
+                       break;
+               xen_update_blkif_status(be->blkif);
+               break;
+
+       case XenbusStateClosing:
+               xen_blkif_disconnect(be->blkif);
+               xenbus_switch_state(dev, XenbusStateClosing);
+               break;
+
+       case XenbusStateClosed:
+               xenbus_switch_state(dev, XenbusStateClosed);
+               if (xenbus_dev_is_online(dev))
+                       break;
+               /* fall through if not online */
+       case XenbusStateUnknown:
+               /* implies blkif_disconnect() via blkback_remove() */
+               device_unregister(&dev->dev);
+               break;
+
+       default:
+               xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
+                                frontend_state);
+               break;
+       }
+}
+
+
+/* ** Connection ** */
+
+
+/*
+ * Write the physical details regarding the block device to the store, and
+ * switch to Connected state.
+ */
+static void connect(struct backend_info *be)
+{
+       struct xenbus_transaction xbt;
+       int err;
+       struct xenbus_device *dev = be->dev;
+
+       DPRINTK("%s", dev->otherend);
+
+       /* Supply the information about the device the frontend needs */
+again:
+       err = xenbus_transaction_start(&xbt);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "starting transaction");
+               return;
+       }
+
+       err = xen_blkbk_flush_diskcache(xbt, be, be->blkif->vbd.flush_support);
+       if (err)
+               goto abort;
+
+       err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu",
+                           (unsigned long long)vbd_sz(&be->blkif->vbd));
+       if (err) {
+               xenbus_dev_fatal(dev, err, "writing %s/sectors",
+                                dev->nodename);
+               goto abort;
+       }
+
+       /* FIXME: use a typename instead */
+       err = xenbus_printf(xbt, dev->nodename, "info", "%u",
+                           be->blkif->vbd.type |
+                           (be->blkif->vbd.readonly ? VDISK_READONLY : 0));
+       if (err) {
+               xenbus_dev_fatal(dev, err, "writing %s/info",
+                                dev->nodename);
+               goto abort;
+       }
+       err = xenbus_printf(xbt, dev->nodename, "sector-size", "%lu",
+                           (unsigned long)
+                           bdev_logical_block_size(be->blkif->vbd.bdev));
+       if (err) {
+               xenbus_dev_fatal(dev, err, "writing %s/sector-size",
+                                dev->nodename);
+               goto abort;
+       }
+
+       err = xenbus_transaction_end(xbt, 0);
+       if (err == -EAGAIN)
+               goto again;
+       if (err)
+               xenbus_dev_fatal(dev, err, "ending transaction");
+
+       err = xenbus_switch_state(dev, XenbusStateConnected);
+       if (err)
+               xenbus_dev_fatal(dev, err, "switching to Connected state",
+                                dev->nodename);
+
+       return;
+ abort:
+       xenbus_transaction_end(xbt, 1);
+}
+
+
+static int connect_ring(struct backend_info *be)
+{
+       struct xenbus_device *dev = be->dev;
+       unsigned long ring_ref;
+       unsigned int evtchn;
+       char protocol[64] = "";
+       int err;
+
+       DPRINTK("%s", dev->otherend);
+
+       err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu",
+                           &ring_ref, "event-channel", "%u", &evtchn, NULL);
+       if (err) {
+               xenbus_dev_fatal(dev, err,
+                                "reading %s/ring-ref and event-channel",
+                                dev->otherend);
+               return err;
+       }
+
+       be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
+       err = xenbus_gather(XBT_NIL, dev->otherend, "protocol",
+                           "%63s", protocol, NULL);
+       if (err)
+               strcpy(protocol, "unspecified, assuming native");
+       else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE))
+               be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
+       else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32))
+               be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32;
+       else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64))
+               be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64;
+       else {
+               xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol);
+               return -1;
+       }
+       pr_info(DRV_PFX "ring-ref %ld, event-channel %d, protocol %d (%s)\n",
+               ring_ref, evtchn, be->blkif->blk_protocol, protocol);
+
+       /* Map the shared frame, irq etc. */
+       err = xen_blkif_map(be->blkif, ring_ref, evtchn);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
+                                ring_ref, evtchn);
+               return err;
+       }
+
+       return 0;
+}
+
+
+/* ** Driver Registration ** */
+
+
+static const struct xenbus_device_id xen_blkbk_ids[] = {
+       { "vbd" },
+       { "" }
+};
+
+
+static struct xenbus_driver xen_blkbk = {
+       .name = "vbd",
+       .owner = THIS_MODULE,
+       .ids = xen_blkbk_ids,
+       .probe = xen_blkbk_probe,
+       .remove = xen_blkbk_remove,
+       .otherend_changed = frontend_changed
+};
+
+
+int xen_blkif_xenbus_init(void)
+{
+       return xenbus_register_backend(&xen_blkbk);
+}
index 9cb8668ff5f412908e99dadcafd6d025904a2cdc..b536a9cef917516d23448e589a7955ad984e6dd3 100644 (file)
@@ -97,6 +97,7 @@ struct blkfront_info
        struct blk_shadow shadow[BLK_RING_SIZE];
        unsigned long shadow_free;
        unsigned int feature_flush;
+       unsigned int flush_op;
        int is_ready;
 };
 
@@ -250,8 +251,7 @@ static int blkif_ioctl(struct block_device *bdev, fmode_t mode,
 
 /*
  * Generate a Xen blkfront IO request from a blk layer request.  Reads
- * and writes are handled as expected.  Since we lack a loose flush
- * request, we map flushes into a full ordered barrier.
+ * and writes are handled as expected.
  *
  * @req: a request struct
  */
@@ -293,14 +293,13 @@ static int blkif_queue_request(struct request *req)
 
        if (req->cmd_flags & (REQ_FLUSH | REQ_FUA)) {
                /*
-                * Ideally we could just do an unordered
-                * flush-to-disk, but all we have is a full write
-                * barrier at the moment.  However, a barrier write is
+                * Ideally we can do an unordered flush-to-disk. In case the
+                * backend onlysupports barriers, use that. A barrier request
                 * a superset of FUA, so we can implement it the same
                 * way.  (It's also a FLUSH+FUA, since it is
                 * guaranteed ordered WRT previous writes.)
                 */
-               ring_req->operation = BLKIF_OP_WRITE_BARRIER;
+               ring_req->operation = info->flush_op;
        }
 
        ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg);
@@ -433,8 +432,11 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
 static void xlvbd_flush(struct blkfront_info *info)
 {
        blk_queue_flush(info->rq, info->feature_flush);
-       printk(KERN_INFO "blkfront: %s: barriers %s\n",
+       printk(KERN_INFO "blkfront: %s: %s: %s\n",
               info->gd->disk_name,
+              info->flush_op == BLKIF_OP_WRITE_BARRIER ?
+               "barrier" : (info->flush_op == BLKIF_OP_FLUSH_DISKCACHE ?
+               "flush diskcache" : "barrier or flush"),
               info->feature_flush ? "enabled" : "disabled");
 }
 
@@ -720,15 +722,20 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
 
                error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO;
                switch (bret->operation) {
+               case BLKIF_OP_FLUSH_DISKCACHE:
                case BLKIF_OP_WRITE_BARRIER:
                        if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
-                               printk(KERN_WARNING "blkfront: %s: write barrier op failed\n",
+                               printk(KERN_WARNING "blkfront: %s: write %s op failed\n",
+                                      info->flush_op == BLKIF_OP_WRITE_BARRIER ?
+                                      "barrier" :  "flush disk cache",
                                       info->gd->disk_name);
                                error = -EOPNOTSUPP;
                        }
                        if (unlikely(bret->status == BLKIF_RSP_ERROR &&
                                     info->shadow[id].req.nr_segments == 0)) {
-                               printk(KERN_WARNING "blkfront: %s: empty write barrier op failed\n",
+                               printk(KERN_WARNING "blkfront: %s: empty write %s op failed\n",
+                                      info->flush_op == BLKIF_OP_WRITE_BARRIER ?
+                                      "barrier" :  "flush disk cache",
                                       info->gd->disk_name);
                                error = -EOPNOTSUPP;
                        }
@@ -736,6 +743,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
                                if (error == -EOPNOTSUPP)
                                        error = 0;
                                info->feature_flush = 0;
+                               info->flush_op = 0;
                                xlvbd_flush(info);
                        }
                        /* fall through */
@@ -1100,7 +1108,7 @@ static void blkfront_connect(struct blkfront_info *info)
        unsigned long sector_size;
        unsigned int binfo;
        int err;
-       int barrier;
+       int barrier, flush;
 
        switch (info->connected) {
        case BLKIF_STATE_CONNECTED:
@@ -1140,8 +1148,11 @@ static void blkfront_connect(struct blkfront_info *info)
                return;
        }
 
+       info->feature_flush = 0;
+       info->flush_op = 0;
+
        err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
-                           "feature-barrier", "%lu", &barrier,
+                           "feature-barrier", "%d", &barrier,
                            NULL);
 
        /*
@@ -1151,11 +1162,23 @@ static void blkfront_connect(struct blkfront_info *info)
         *
         * If there are barriers, then we use flush.
         */
-       info->feature_flush = 0;
-
-       if (!err && barrier)
+       if (!err && barrier) {
                info->feature_flush = REQ_FLUSH | REQ_FUA;
+               info->flush_op = BLKIF_OP_WRITE_BARRIER;
+       }
+       /*
+        * And if there is "feature-flush-cache" use that above
+        * barriers.
+        */
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                           "feature-flush-cache", "%d", &flush,
+                           NULL);
 
+       if (!err && flush) {
+               info->feature_flush = REQ_FLUSH;
+               info->flush_op = BLKIF_OP_FLUSH_DISKCACHE;
+       }
+               
        err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size);
        if (err) {
                xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
index 4104b7feae6741c585af6d87db7c1333478e6891..aed1904ea67b54f54d1c033073a6af281f3b0070 100644 (file)
@@ -930,7 +930,7 @@ static void bluecard_release(struct pcmcia_device *link)
        pcmcia_disable_device(link);
 }
 
-static struct pcmcia_device_id bluecard_ids[] = {
+static const struct pcmcia_device_id bluecard_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("BlueCard", "LSE041", 0xbaf16fbf, 0x657cc15e),
        PCMCIA_DEVICE_PROD_ID12("BTCFCARD", "LSE139", 0xe3987764, 0x2524b59c),
        PCMCIA_DEVICE_PROD_ID12("WSS", "LSE039", 0x0a0736ec, 0x24e6dfab),
index 0c8a655874914d0604784d09c32c3b1651de03f5..4fc01949d39981a77b6e9dca90606ab94ae259b8 100644 (file)
@@ -761,7 +761,7 @@ static void bt3c_release(struct pcmcia_device *link)
 }
 
 
-static struct pcmcia_device_id bt3c_ids[] = {
+static const struct pcmcia_device_id bt3c_ids[] = {
        PCMCIA_DEVICE_PROD_ID13("3COM", "Bluetooth PC Card", 0xefce0a31, 0xd4ce9b02),
        PCMCIA_DEVICE_NULL
 };
index fd6305bf953e4084c9b7557a26acb002deb101fe..8ecf4c6c28740243979920dd98ea7bdc638e5172 100644 (file)
@@ -64,6 +64,8 @@ static ssize_t btmrvl_hscfgcmd_write(struct file *file,
                return -EFAULT;
 
        ret = strict_strtol(buf, 10, &result);
+       if (ret)
+               return ret;
 
        priv->btmrvl_dev.hscfgcmd = result;
 
@@ -108,6 +110,8 @@ static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf,
                return -EFAULT;
 
        ret = strict_strtol(buf, 10, &result);
+       if (ret)
+               return ret;
 
        priv->btmrvl_dev.psmode = result;
 
@@ -147,6 +151,8 @@ static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf,
                return -EFAULT;
 
        ret = strict_strtol(buf, 10, &result);
+       if (ret)
+               return ret;
 
        priv->btmrvl_dev.pscmd = result;
 
@@ -191,6 +197,8 @@ static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf,
                return -EFAULT;
 
        ret = strict_strtol(buf, 16, &result);
+       if (ret)
+               return ret;
 
        priv->btmrvl_dev.gpio_gap = result;
 
@@ -230,6 +238,8 @@ static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf,
                return -EFAULT;
 
        ret = strict_strtol(buf, 10, &result);
+       if (ret)
+               return ret;
 
        priv->btmrvl_dev.hscmd = result;
        if (priv->btmrvl_dev.hscmd) {
@@ -272,6 +282,8 @@ static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf,
                return -EFAULT;
 
        ret = strict_strtol(buf, 10, &result);
+       if (ret)
+               return ret;
 
        priv->btmrvl_dev.hsmode = result;
 
index f8a0708e23110446de1f8a4ccc5e344306b88820..526b61807d945dda8a6983758b348fe7ea0bd233 100644 (file)
@@ -689,7 +689,7 @@ static void btuart_release(struct pcmcia_device *link)
        pcmcia_disable_device(link);
 }
 
-static struct pcmcia_device_id btuart_ids[] = {
+static const struct pcmcia_device_id btuart_ids[] = {
        /* don't use this driver. Use serial_cs + hci_uart instead */
        PCMCIA_DEVICE_NULL
 };
index 26ee0cf88d20487c0c830b5dec0c753bbf11a3b8..5e4c2de9fc3f778bf71c71c89d9222edce4bcd36 100644 (file)
@@ -636,7 +636,7 @@ static void dtl1_release(struct pcmcia_device *link)
 }
 
 
-static struct pcmcia_device_id dtl1_ids[] = {
+static const struct pcmcia_device_id dtl1_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
        PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-4", 0xe1bfdd64, 0x9102bc82),
        PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863),
index b3f01996318f04c0f432a38112226dbbeba0efcf..48ad2a7ab080ba9a58c425da7cc959dba0e1e3de 100644 (file)
@@ -355,29 +355,24 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
  *             flags        pointer to flags for data
  *             count        count of received data in bytes
  *     
- * Return Value:    Number of bytes received
+ * Return Value:    None
  */
-static unsigned int hci_uart_tty_receive(struct tty_struct *tty,
-               const u8 *data, char *flags, int count)
+static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
 {
        struct hci_uart *hu = (void *)tty->disc_data;
-       int received;
 
        if (!hu || tty != hu->tty)
-               return -ENODEV;
+               return;
 
        if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
-               return -EINVAL;
+               return;
 
        spin_lock(&hu->rx_lock);
-       received = hu->proto->recv(hu, (void *) data, count);
-       if (received > 0)
-               hu->hdev->stat.byte_rx += received;
+       hu->proto->recv(hu, (void *) data, count);
+       hu->hdev->stat.byte_rx += count;
        spin_unlock(&hu->rx_lock);
 
        tty_unthrottle(tty);
-
-       return received;
 }
 
 static int hci_uart_register_dev(struct hci_uart *hu)
index e427fbe459994a8491945a65fd085201f40ed01f..7878da89d29e2afef850461254f43ab4ae58722e 100644 (file)
@@ -625,7 +625,8 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        blk_queue_max_hw_sectors(q, 4096 / 512);
        gendisk->queue = q;
        gendisk->fops = &viocd_fops;
-       gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE;
+       gendisk->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE |
+                        GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
        set_capacity(gendisk, 0);
        gendisk->private_data = d;
        d->viocd_disk = gendisk;
index b0a0dccc98c16e479d679414d2bcf617570bab9f..b427711be4be385c2704d4c971dc5cd512ed85c4 100644 (file)
@@ -903,6 +903,9 @@ static struct pci_device_id agp_intel_pci_table[] = {
        ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB),
        ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB),
        ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB),
+       ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_HB),
+       ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_HB),
+       ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_HB),
        { }
 };
 
index 5feebe2800e9a5147fa04e951ff40dfd62e1688d..999803ce10dc5cae9c3571c155de3a5d1276a5c7 100644 (file)
 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG  0x0126
 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB           0x0108  /* Server */
 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG           0x010A
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_HB               0x0150  /* Desktop */
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT1_IG           0x0152
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT2_IG           0x0162
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_HB             0x0154  /* Mobile */
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT1_IG         0x0156
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT2_IG         0x0166
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_HB             0x0158  /* Server */
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG         0x015A
 
 int intel_gmch_probe(struct pci_dev *pdev,
                               struct agp_bridge_data *bridge);
index 0d09b537bb9a5cbd52691874b7b8a77534ee1720..85151019dde12572e458260b6d56068fd0e271c4 100644 (file)
@@ -1420,6 +1420,16 @@ static const struct intel_gtt_driver_description {
            "Sandybridge", &sandybridge_gtt_driver },
        { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG,
            "Sandybridge", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT1_IG,
+           "Ivybridge", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT2_IG,
+           "Ivybridge", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT1_IG,
+           "Ivybridge", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT2_IG,
+           "Ivybridge", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG,
+           "Ivybridge", &sandybridge_gtt_driver },
        { 0, NULL, NULL }
 };
 
index f845a8f718b39af2bd1277e331d50143e24ae9fc..a32c492baf5cc15001ad6882dc25a14d1be86419 100644 (file)
@@ -80,7 +80,7 @@ static void uninorth_tlbflush(struct agp_memory *mem)
                               ctrl | UNI_N_CFG_GART_INVAL);
        pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, ctrl);
 
-       if (uninorth_rev <= 0x30) {
+       if (!mem && uninorth_rev <= 0x30) {
                pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
                                       ctrl | UNI_N_CFG_GART_2xRESET);
                pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
index 051474c65b783c5e9f3315de2fb3732516810027..34d6a1cab8def622d95c46b138b02a7d8a0eeeec 100644 (file)
@@ -163,11 +163,32 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
         * This has the effect of treating non-periodic like periodic.
         */
        if ((devp->hd_flags & (HPET_IE | HPET_PERIODIC)) == HPET_IE) {
-               unsigned long m, t;
+               unsigned long m, t, mc, base, k;
+               struct hpet __iomem *hpet = devp->hd_hpet;
+               struct hpets *hpetp = devp->hd_hpets;
 
                t = devp->hd_ireqfreq;
                m = read_counter(&devp->hd_timer->hpet_compare);
-               write_counter(t + m, &devp->hd_timer->hpet_compare);
+               mc = read_counter(&hpet->hpet_mc);
+               /* The time for the next interrupt would logically be t + m,
+                * however, if we are very unlucky and the interrupt is delayed
+                * for longer than t then we will completely miss the next
+                * interrupt if we set t + m and an application will hang.
+                * Therefore we need to make a more complex computation assuming
+                * that there exists a k for which the following is true:
+                * k * t + base < mc + delta
+                * (k + 1) * t + base > mc + delta
+                * where t is the interval in hpet ticks for the given freq,
+                * base is the theoretical start value 0 < base < t,
+                * mc is the main counter value at the time of the interrupt,
+                * delta is the time it takes to write the a value to the
+                * comparator.
+                * k may then be computed as (mc - base + delta) / t .
+                */
+               base = mc % t;
+               k = (mc - base + hpetp->hp_delta) / t;
+               write_counter(t * (k + 1) + base,
+                             &devp->hd_timer->hpet_compare);
        }
 
        if (devp->hd_flags & HPET_SHARED_IRQ)
index d72433f2d310deb6cf909cb1feb30e92919887cd..6e40072fbf675e3c69b105cc8ea1d05491bba485 100644 (file)
@@ -5,6 +5,9 @@
  *
  * Copyright (C) 2001  Massimo Dal Zotto <dz@debian.org>
  *
+ * Hwmon integration:
+ * Copyright (C) 2011  Jean Delvare <khali@linux-fr.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, or (at your option) any
@@ -24,6 +27,8 @@
 #include <linux/dmi.h>
 #include <linux/capability.h>
 #include <linux/mutex.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
@@ -58,6 +63,7 @@
 
 static DEFINE_MUTEX(i8k_mutex);
 static char bios_version[4];
+static struct device *i8k_hwmon_dev;
 
 MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
 MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
@@ -139,8 +145,8 @@ static int i8k_smm(struct smm_regs *regs)
                "movl %%edi,20(%%rax)\n\t"
                "popq %%rdx\n\t"
                "movl %%edx,0(%%rax)\n\t"
-               "lahf\n\t"
-               "shrl $8,%%eax\n\t"
+               "pushfq\n\t"
+               "popq %%rax\n\t"
                "andl $1,%%eax\n"
                :"=a"(rc)
                :    "a"(regs)
@@ -455,6 +461,152 @@ static int i8k_open_fs(struct inode *inode, struct file *file)
        return single_open(file, i8k_proc_show, NULL);
 }
 
+
+/*
+ * Hwmon interface
+ */
+
+static ssize_t i8k_hwmon_show_temp(struct device *dev,
+                                  struct device_attribute *devattr,
+                                  char *buf)
+{
+       int cpu_temp;
+
+       cpu_temp = i8k_get_temp(0);
+       if (cpu_temp < 0)
+               return cpu_temp;
+       return sprintf(buf, "%d\n", cpu_temp * 1000);
+}
+
+static ssize_t i8k_hwmon_show_fan(struct device *dev,
+                                 struct device_attribute *devattr,
+                                 char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       int fan_speed;
+
+       fan_speed = i8k_get_fan_speed(index);
+       if (fan_speed < 0)
+               return fan_speed;
+       return sprintf(buf, "%d\n", fan_speed);
+}
+
+static ssize_t i8k_hwmon_show_label(struct device *dev,
+                                   struct device_attribute *devattr,
+                                   char *buf)
+{
+       static const char *labels[4] = {
+               "i8k",
+               "CPU",
+               "Left Fan",
+               "Right Fan",
+       };
+       int index = to_sensor_dev_attr(devattr)->index;
+
+       return sprintf(buf, "%s\n", labels[index]);
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
+                         I8K_FAN_LEFT);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
+                         I8K_FAN_RIGHT);
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, i8k_hwmon_show_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_label, NULL, 3);
+
+static void i8k_hwmon_remove_files(struct device *dev)
+{
+       device_remove_file(dev, &dev_attr_temp1_input);
+       device_remove_file(dev, &sensor_dev_attr_fan1_input.dev_attr);
+       device_remove_file(dev, &sensor_dev_attr_fan2_input.dev_attr);
+       device_remove_file(dev, &sensor_dev_attr_temp1_label.dev_attr);
+       device_remove_file(dev, &sensor_dev_attr_fan1_label.dev_attr);
+       device_remove_file(dev, &sensor_dev_attr_fan2_label.dev_attr);
+       device_remove_file(dev, &sensor_dev_attr_name.dev_attr);
+}
+
+static int __init i8k_init_hwmon(void)
+{
+       int err;
+
+       i8k_hwmon_dev = hwmon_device_register(NULL);
+       if (IS_ERR(i8k_hwmon_dev)) {
+               err = PTR_ERR(i8k_hwmon_dev);
+               i8k_hwmon_dev = NULL;
+               printk(KERN_ERR "i8k: hwmon registration failed (%d)\n", err);
+               return err;
+       }
+
+       /* Required name attribute */
+       err = device_create_file(i8k_hwmon_dev,
+                                &sensor_dev_attr_name.dev_attr);
+       if (err)
+               goto exit_unregister;
+
+       /* CPU temperature attributes, if temperature reading is OK */
+       err = i8k_get_temp(0);
+       if (err < 0) {
+               dev_dbg(i8k_hwmon_dev,
+                       "Not creating temperature attributes (%d)\n", err);
+       } else {
+               err = device_create_file(i8k_hwmon_dev, &dev_attr_temp1_input);
+               if (err)
+                       goto exit_remove_files;
+               err = device_create_file(i8k_hwmon_dev,
+                                        &sensor_dev_attr_temp1_label.dev_attr);
+               if (err)
+                       goto exit_remove_files;
+       }
+
+       /* Left fan attributes, if left fan is present */
+       err = i8k_get_fan_status(I8K_FAN_LEFT);
+       if (err < 0) {
+               dev_dbg(i8k_hwmon_dev,
+                       "Not creating %s fan attributes (%d)\n", "left", err);
+       } else {
+               err = device_create_file(i8k_hwmon_dev,
+                                        &sensor_dev_attr_fan1_input.dev_attr);
+               if (err)
+                       goto exit_remove_files;
+               err = device_create_file(i8k_hwmon_dev,
+                                        &sensor_dev_attr_fan1_label.dev_attr);
+               if (err)
+                       goto exit_remove_files;
+       }
+
+       /* Right fan attributes, if right fan is present */
+       err = i8k_get_fan_status(I8K_FAN_RIGHT);
+       if (err < 0) {
+               dev_dbg(i8k_hwmon_dev,
+                       "Not creating %s fan attributes (%d)\n", "right", err);
+       } else {
+               err = device_create_file(i8k_hwmon_dev,
+                                        &sensor_dev_attr_fan2_input.dev_attr);
+               if (err)
+                       goto exit_remove_files;
+               err = device_create_file(i8k_hwmon_dev,
+                                        &sensor_dev_attr_fan2_label.dev_attr);
+               if (err)
+                       goto exit_remove_files;
+       }
+
+       return 0;
+
+ exit_remove_files:
+       i8k_hwmon_remove_files(i8k_hwmon_dev);
+ exit_unregister:
+       hwmon_device_unregister(i8k_hwmon_dev);
+       return err;
+}
+
+static void __exit i8k_exit_hwmon(void)
+{
+       i8k_hwmon_remove_files(i8k_hwmon_dev);
+       hwmon_device_unregister(i8k_hwmon_dev);
+}
+
 static struct dmi_system_id __initdata i8k_dmi_table[] = {
        {
                .ident = "Dell Inspiron",
@@ -580,6 +732,7 @@ static int __init i8k_probe(void)
 static int __init i8k_init(void)
 {
        struct proc_dir_entry *proc_i8k;
+       int err;
 
        /* Are we running on an supported laptop? */
        if (i8k_probe())
@@ -590,15 +743,24 @@ static int __init i8k_init(void)
        if (!proc_i8k)
                return -ENOENT;
 
+       err = i8k_init_hwmon();
+       if (err)
+               goto exit_remove_proc;
+
        printk(KERN_INFO
               "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
               I8K_VERSION);
 
        return 0;
+
+ exit_remove_proc:
+       remove_proc_entry("i8k", NULL);
+       return err;
 }
 
 static void __exit i8k_exit(void)
 {
+       i8k_exit_hwmon();
        remove_proc_entry("i8k", NULL);
 }
 
index 38223e93aa988f020e98a2b0d42a1a50720f6aea..58c0e6387cf73ddfd016baeb38384e08f5a6f794 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/system.h>
 #include <linux/poll.h>
 #include <linux/sched.h>
+#include <linux/seq_file.h>
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
@@ -1896,102 +1897,128 @@ int ipmi_request_supply_msgs(ipmi_user_t          user,
 EXPORT_SYMBOL(ipmi_request_supply_msgs);
 
 #ifdef CONFIG_PROC_FS
-static int ipmb_file_read_proc(char *page, char **start, off_t off,
-                              int count, int *eof, void *data)
+static int smi_ipmb_proc_show(struct seq_file *m, void *v)
 {
-       char       *out = (char *) page;
-       ipmi_smi_t intf = data;
+       ipmi_smi_t intf = m->private;
        int        i;
-       int        rv = 0;
 
-       for (i = 0; i < IPMI_MAX_CHANNELS; i++)
-               rv += sprintf(out+rv, "%x ", intf->channels[i].address);
-       out[rv-1] = '\n'; /* Replace the final space with a newline */
-       out[rv] = '\0';
-       rv++;
-       return rv;
+       seq_printf(m, "%x", intf->channels[0].address);
+       for (i = 1; i < IPMI_MAX_CHANNELS; i++)
+               seq_printf(m, " %x", intf->channels[i].address);
+       return seq_putc(m, '\n');
 }
 
-static int version_file_read_proc(char *page, char **start, off_t off,
-                                 int count, int *eof, void *data)
+static int smi_ipmb_proc_open(struct inode *inode, struct file *file)
 {
-       char       *out = (char *) page;
-       ipmi_smi_t intf = data;
+       return single_open(file, smi_ipmb_proc_show, PDE(inode)->data);
+}
 
-       return sprintf(out, "%u.%u\n",
+static const struct file_operations smi_ipmb_proc_ops = {
+       .open           = smi_ipmb_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int smi_version_proc_show(struct seq_file *m, void *v)
+{
+       ipmi_smi_t intf = m->private;
+
+       return seq_printf(m, "%u.%u\n",
                       ipmi_version_major(&intf->bmc->id),
                       ipmi_version_minor(&intf->bmc->id));
 }
 
-static int stat_file_read_proc(char *page, char **start, off_t off,
-                              int count, int *eof, void *data)
+static int smi_version_proc_open(struct inode *inode, struct file *file)
 {
-       char       *out = (char *) page;
-       ipmi_smi_t intf = data;
+       return single_open(file, smi_version_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations smi_version_proc_ops = {
+       .open           = smi_version_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
-       out += sprintf(out, "sent_invalid_commands:       %u\n",
+static int smi_stats_proc_show(struct seq_file *m, void *v)
+{
+       ipmi_smi_t intf = m->private;
+
+       seq_printf(m, "sent_invalid_commands:       %u\n",
                       ipmi_get_stat(intf, sent_invalid_commands));
-       out += sprintf(out, "sent_local_commands:         %u\n",
+       seq_printf(m, "sent_local_commands:         %u\n",
                       ipmi_get_stat(intf, sent_local_commands));
-       out += sprintf(out, "handled_local_responses:     %u\n",
+       seq_printf(m, "handled_local_responses:     %u\n",
                       ipmi_get_stat(intf, handled_local_responses));
-       out += sprintf(out, "unhandled_local_responses:   %u\n",
+       seq_printf(m, "unhandled_local_responses:   %u\n",
                       ipmi_get_stat(intf, unhandled_local_responses));
-       out += sprintf(out, "sent_ipmb_commands:          %u\n",
+       seq_printf(m, "sent_ipmb_commands:          %u\n",
                       ipmi_get_stat(intf, sent_ipmb_commands));
-       out += sprintf(out, "sent_ipmb_command_errs:      %u\n",
+       seq_printf(m, "sent_ipmb_command_errs:      %u\n",
                       ipmi_get_stat(intf, sent_ipmb_command_errs));
-       out += sprintf(out, "retransmitted_ipmb_commands: %u\n",
+       seq_printf(m, "retransmitted_ipmb_commands: %u\n",
                       ipmi_get_stat(intf, retransmitted_ipmb_commands));
-       out += sprintf(out, "timed_out_ipmb_commands:     %u\n",
+       seq_printf(m, "timed_out_ipmb_commands:     %u\n",
                       ipmi_get_stat(intf, timed_out_ipmb_commands));
-       out += sprintf(out, "timed_out_ipmb_broadcasts:   %u\n",
+       seq_printf(m, "timed_out_ipmb_broadcasts:   %u\n",
                       ipmi_get_stat(intf, timed_out_ipmb_broadcasts));
-       out += sprintf(out, "sent_ipmb_responses:         %u\n",
+       seq_printf(m, "sent_ipmb_responses:         %u\n",
                       ipmi_get_stat(intf, sent_ipmb_responses));
-       out += sprintf(out, "handled_ipmb_responses:      %u\n",
+       seq_printf(m, "handled_ipmb_responses:      %u\n",
                       ipmi_get_stat(intf, handled_ipmb_responses));
-       out += sprintf(out, "invalid_ipmb_responses:      %u\n",
+       seq_printf(m, "invalid_ipmb_responses:      %u\n",
                       ipmi_get_stat(intf, invalid_ipmb_responses));
-       out += sprintf(out, "unhandled_ipmb_responses:    %u\n",
+       seq_printf(m, "unhandled_ipmb_responses:    %u\n",
                       ipmi_get_stat(intf, unhandled_ipmb_responses));
-       out += sprintf(out, "sent_lan_commands:           %u\n",
+       seq_printf(m, "sent_lan_commands:           %u\n",
                       ipmi_get_stat(intf, sent_lan_commands));
-       out += sprintf(out, "sent_lan_command_errs:       %u\n",
+       seq_printf(m, "sent_lan_command_errs:       %u\n",
                       ipmi_get_stat(intf, sent_lan_command_errs));
-       out += sprintf(out, "retransmitted_lan_commands:  %u\n",
+       seq_printf(m, "retransmitted_lan_commands:  %u\n",
                       ipmi_get_stat(intf, retransmitted_lan_commands));
-       out += sprintf(out, "timed_out_lan_commands:      %u\n",
+       seq_printf(m, "timed_out_lan_commands:      %u\n",
                       ipmi_get_stat(intf, timed_out_lan_commands));
-       out += sprintf(out, "sent_lan_responses:          %u\n",
+       seq_printf(m, "sent_lan_responses:          %u\n",
                       ipmi_get_stat(intf, sent_lan_responses));
-       out += sprintf(out, "handled_lan_responses:       %u\n",
+       seq_printf(m, "handled_lan_responses:       %u\n",
                       ipmi_get_stat(intf, handled_lan_responses));
-       out += sprintf(out, "invalid_lan_responses:       %u\n",
+       seq_printf(m, "invalid_lan_responses:       %u\n",
                       ipmi_get_stat(intf, invalid_lan_responses));
-       out += sprintf(out, "unhandled_lan_responses:     %u\n",
+       seq_printf(m, "unhandled_lan_responses:     %u\n",
                       ipmi_get_stat(intf, unhandled_lan_responses));
-       out += sprintf(out, "handled_commands:            %u\n",
+       seq_printf(m, "handled_commands:            %u\n",
                       ipmi_get_stat(intf, handled_commands));
-       out += sprintf(out, "invalid_commands:            %u\n",
+       seq_printf(m, "invalid_commands:            %u\n",
                       ipmi_get_stat(intf, invalid_commands));
-       out += sprintf(out, "unhandled_commands:          %u\n",
+       seq_printf(m, "unhandled_commands:          %u\n",
                       ipmi_get_stat(intf, unhandled_commands));
-       out += sprintf(out, "invalid_events:              %u\n",
+       seq_printf(m, "invalid_events:              %u\n",
                       ipmi_get_stat(intf, invalid_events));
-       out += sprintf(out, "events:                      %u\n",
+       seq_printf(m, "events:                      %u\n",
                       ipmi_get_stat(intf, events));
-       out += sprintf(out, "failed rexmit LAN msgs:      %u\n",
+       seq_printf(m, "failed rexmit LAN msgs:      %u\n",
                       ipmi_get_stat(intf, dropped_rexmit_lan_commands));
-       out += sprintf(out, "failed rexmit IPMB msgs:     %u\n",
+       seq_printf(m, "failed rexmit IPMB msgs:     %u\n",
                       ipmi_get_stat(intf, dropped_rexmit_ipmb_commands));
+       return 0;
+}
 
-       return (out - ((char *) page));
+static int smi_stats_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, smi_stats_proc_show, PDE(inode)->data);
 }
+
+static const struct file_operations smi_stats_proc_ops = {
+       .open           = smi_stats_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 #endif /* CONFIG_PROC_FS */
 
 int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
-                           read_proc_t *read_proc,
+                           const struct file_operations *proc_ops,
                            void *data)
 {
        int                    rv = 0;
@@ -2010,15 +2037,12 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
        }
        strcpy(entry->name, name);
 
-       file = create_proc_entry(name, 0, smi->proc_dir);
+       file = proc_create_data(name, 0, smi->proc_dir, proc_ops, data);
        if (!file) {
                kfree(entry->name);
                kfree(entry);
                rv = -ENOMEM;
        } else {
-               file->data = data;
-               file->read_proc = read_proc;
-
                mutex_lock(&smi->proc_entry_lock);
                /* Stick it on the list. */
                entry->next = smi->proc_entries;
@@ -2043,17 +2067,17 @@ static int add_proc_entries(ipmi_smi_t smi, int num)
 
        if (rv == 0)
                rv = ipmi_smi_add_proc_entry(smi, "stats",
-                                            stat_file_read_proc,
+                                            &smi_stats_proc_ops,
                                             smi);
 
        if (rv == 0)
                rv = ipmi_smi_add_proc_entry(smi, "ipmb",
-                                            ipmb_file_read_proc,
+                                            &smi_ipmb_proc_ops,
                                             smi);
 
        if (rv == 0)
                rv = ipmi_smi_add_proc_entry(smi, "version",
-                                            version_file_read_proc,
+                                            &smi_version_proc_ops,
                                             smi);
 #endif /* CONFIG_PROC_FS */
 
index 64c6b85306150723ad8206f11fab7f54d8dd597b..9397ab49b72e8b20f3984a55e31819fea26e20d7 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/moduleparam.h>
 #include <asm/system.h>
 #include <linux/sched.h>
+#include <linux/seq_file.h>
 #include <linux/timer.h>
 #include <linux/errno.h>
 #include <linux/spinlock.h>
@@ -2805,54 +2806,73 @@ static int try_enable_event_buffer(struct smi_info *smi_info)
        return rv;
 }
 
-static int type_file_read_proc(char *page, char **start, off_t off,
-                              int count, int *eof, void *data)
+static int smi_type_proc_show(struct seq_file *m, void *v)
 {
-       struct smi_info *smi = data;
+       struct smi_info *smi = m->private;
 
-       return sprintf(page, "%s\n", si_to_str[smi->si_type]);
+       return seq_printf(m, "%s\n", si_to_str[smi->si_type]);
 }
 
-static int stat_file_read_proc(char *page, char **start, off_t off,
-                              int count, int *eof, void *data)
+static int smi_type_proc_open(struct inode *inode, struct file *file)
 {
-       char            *out = (char *) page;
-       struct smi_info *smi = data;
+       return single_open(file, smi_type_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations smi_type_proc_ops = {
+       .open           = smi_type_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int smi_si_stats_proc_show(struct seq_file *m, void *v)
+{
+       struct smi_info *smi = m->private;
 
-       out += sprintf(out, "interrupts_enabled:    %d\n",
+       seq_printf(m, "interrupts_enabled:    %d\n",
                       smi->irq && !smi->interrupt_disabled);
-       out += sprintf(out, "short_timeouts:        %u\n",
+       seq_printf(m, "short_timeouts:        %u\n",
                       smi_get_stat(smi, short_timeouts));
-       out += sprintf(out, "long_timeouts:         %u\n",
+       seq_printf(m, "long_timeouts:         %u\n",
                       smi_get_stat(smi, long_timeouts));
-       out += sprintf(out, "idles:                 %u\n",
+       seq_printf(m, "idles:                 %u\n",
                       smi_get_stat(smi, idles));
-       out += sprintf(out, "interrupts:            %u\n",
+       seq_printf(m, "interrupts:            %u\n",
                       smi_get_stat(smi, interrupts));
-       out += sprintf(out, "attentions:            %u\n",
+       seq_printf(m, "attentions:            %u\n",
                       smi_get_stat(smi, attentions));
-       out += sprintf(out, "flag_fetches:          %u\n",
+       seq_printf(m, "flag_fetches:          %u\n",
                       smi_get_stat(smi, flag_fetches));
-       out += sprintf(out, "hosed_count:           %u\n",
+       seq_printf(m, "hosed_count:           %u\n",
                       smi_get_stat(smi, hosed_count));
-       out += sprintf(out, "complete_transactions: %u\n",
+       seq_printf(m, "complete_transactions: %u\n",
                       smi_get_stat(smi, complete_transactions));
-       out += sprintf(out, "events:                %u\n",
+       seq_printf(m, "events:                %u\n",
                       smi_get_stat(smi, events));
-       out += sprintf(out, "watchdog_pretimeouts:  %u\n",
+       seq_printf(m, "watchdog_pretimeouts:  %u\n",
                       smi_get_stat(smi, watchdog_pretimeouts));
-       out += sprintf(out, "incoming_messages:     %u\n",
+       seq_printf(m, "incoming_messages:     %u\n",
                       smi_get_stat(smi, incoming_messages));
+       return 0;
+}
 
-       return out - page;
+static int smi_si_stats_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, smi_si_stats_proc_show, PDE(inode)->data);
 }
 
-static int param_read_proc(char *page, char **start, off_t off,
-                          int count, int *eof, void *data)
+static const struct file_operations smi_si_stats_proc_ops = {
+       .open           = smi_si_stats_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int smi_params_proc_show(struct seq_file *m, void *v)
 {
-       struct smi_info *smi = data;
+       struct smi_info *smi = m->private;
 
-       return sprintf(page,
+       return seq_printf(m,
                       "%s,%s,0x%lx,rsp=%d,rsi=%d,rsh=%d,irq=%d,ipmb=%d\n",
                       si_to_str[smi->si_type],
                       addr_space_to_str[smi->io.addr_type],
@@ -2864,6 +2884,18 @@ static int param_read_proc(char *page, char **start, off_t off,
                       smi->slave_addr);
 }
 
+static int smi_params_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, smi_params_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations smi_params_proc_ops = {
+       .open           = smi_params_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*
  * oem_data_avail_to_receive_msg_avail
  * @info - smi_info structure with msg_flags set
@@ -3257,7 +3289,7 @@ static int try_smi_init(struct smi_info *new_smi)
        }
 
        rv = ipmi_smi_add_proc_entry(new_smi->intf, "type",
-                                    type_file_read_proc,
+                                    &smi_type_proc_ops,
                                     new_smi);
        if (rv) {
                dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv);
@@ -3265,7 +3297,7 @@ static int try_smi_init(struct smi_info *new_smi)
        }
 
        rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats",
-                                    stat_file_read_proc,
+                                    &smi_si_stats_proc_ops,
                                     new_smi);
        if (rv) {
                dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv);
@@ -3273,7 +3305,7 @@ static int try_smi_init(struct smi_info *new_smi)
        }
 
        rv = ipmi_smi_add_proc_entry(new_smi->intf, "params",
-                                    param_read_proc,
+                                    &smi_params_proc_ops,
                                     new_smi);
        if (rv) {
                dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv);
index 966a95bc974b2c0489c7c4f33b52d1b3872238a0..25d139c9dbeddd86440847f3ced302950883ef98 100644 (file)
@@ -271,14 +271,13 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma,
        pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
        vdata_size = sizeof(struct vma_data) + pages * sizeof(long);
        if (vdata_size <= PAGE_SIZE)
-               vdata = kmalloc(vdata_size, GFP_KERNEL);
+               vdata = kzalloc(vdata_size, GFP_KERNEL);
        else {
-               vdata = vmalloc(vdata_size);
+               vdata = vzalloc(vdata_size);
                flags = VMD_VMALLOCED;
        }
        if (!vdata)
                return -ENOMEM;
-       memset(vdata, 0, vdata_size);
 
        vdata->vm_start = vma->vm_start;
        vdata->vm_end = vma->vm_end;
index 90bd01671c70e230be0fdf47211b9d7d3eae1885..a7584860e9a731b36c6b64f39f106a51dd0ec023 100644 (file)
@@ -1869,7 +1869,7 @@ static const struct file_operations cm4000_fops = {
        .llseek = no_llseek,
 };
 
-static struct pcmcia_device_id cm4000_ids[] = {
+static const struct pcmcia_device_id cm4000_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0002),
        PCMCIA_DEVICE_PROD_ID12("CardMan", "4000", 0x2FB368CA, 0xA2BD8C39),
        PCMCIA_DEVICE_NULL,
index 5d8d59e865f4b15cea3194ec8ef23c8f5d07c736..8dd48a2be911db2626dd972c44fa2421c609ba8b 100644 (file)
@@ -633,7 +633,7 @@ static const struct file_operations reader_fops = {
        .llseek         = no_llseek,
 };
 
-static struct pcmcia_device_id cm4040_ids[] = {
+static const struct pcmcia_device_id cm4040_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0200),
        PCMCIA_DEVICE_PROD_ID12("OMNIKEY", "CardMan 4040",
                                0xE32CDD8C, 0x8F23318B),
index b575411c69b2e813024251628cc7faad4cfe7ec6..15781396af25a7ae301d04a92024e74b3e94f373 100644 (file)
@@ -2758,7 +2758,7 @@ static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
        }
 }
 
-static struct pcmcia_device_id mgslpc_ids[] = {
+static const struct pcmcia_device_id mgslpc_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x02c5, 0x0050),
        PCMCIA_DEVICE_NULL
 };
index f176dbaeb15adfaaceda46ad6bd97e030065ccd8..3fcf80ff12f2226fce01f5749e96972d3857072b 100644 (file)
@@ -457,6 +457,7 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        return -ENODEV;
 
                modes = port->modes;
+               parport_put_port(port);
                if (copy_to_user (argp, &modes, sizeof (modes))) {
                        return -EFAULT;
                }
index 838568a7dbf56845755bf6e579142505a7172809..fb68b1295373e7287aa92a577b6aa937ba7ffe09 100644 (file)
@@ -1677,17 +1677,12 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
        portdev->config.max_nr_ports = 1;
        if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) {
                multiport = true;
-               vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT;
-
                vdev->config->get(vdev, offsetof(struct virtio_console_config,
                                                 max_nr_ports),
                                  &portdev->config.max_nr_ports,
                                  sizeof(portdev->config.max_nr_ports));
        }
 
-       /* Let the Host know we support multiple ports.*/
-       vdev->config->finalize_features(vdev);
-
        err = init_vqs(portdev);
        if (err < 0) {
                dev_err(&vdev->dev, "Error %d initializing vqs\n", err);
index 036e5865eb40005f026f571fd679a7db09bd4859..dc7c033ef587142ce080e33a2b2711a94ece1d89 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/ioport.h>
 #include <linux/io.h>
 #include <linux/clk.h>
-#include <linux/pm_runtime.h>
 #include <linux/irq.h>
 #include <linux/err.h>
 #include <linux/clocksource.h>
@@ -153,12 +152,10 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
 {
        int ret;
 
-       /* wake up device and enable clock */
-       pm_runtime_get_sync(&p->pdev->dev);
+       /* enable clock */
        ret = clk_enable(p->clk);
        if (ret) {
                dev_err(&p->pdev->dev, "cannot enable clock\n");
-               pm_runtime_put_sync(&p->pdev->dev);
                return ret;
        }
 
@@ -190,9 +187,8 @@ static void sh_cmt_disable(struct sh_cmt_priv *p)
        /* disable interrupts in CMT block */
        sh_cmt_write(p, CMCSR, 0);
 
-       /* stop clock and mark device as idle */
+       /* stop clock */
        clk_disable(p->clk);
-       pm_runtime_put_sync(&p->pdev->dev);
 }
 
 /* private flags */
@@ -664,7 +660,6 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev)
 
        if (p) {
                dev_info(&pdev->dev, "kept as earlytimer\n");
-               pm_runtime_enable(&pdev->dev);
                return 0;
        }
 
@@ -679,9 +674,6 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev)
                kfree(p);
                platform_set_drvdata(pdev, NULL);
        }
-
-       if (!is_early_platform_device(pdev))
-               pm_runtime_enable(&pdev->dev);
        return ret;
 }
 
index 17296288a2052ef757a5e22b6a0d3e52d37036ee..80813576861781194f235f52507480e1d44a92f7 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/clk.h>
-#include <linux/pm_runtime.h>
 #include <linux/irq.h>
 #include <linux/err.h>
 #include <linux/clocksource.h>
@@ -110,12 +109,10 @@ static int sh_tmu_enable(struct sh_tmu_priv *p)
 {
        int ret;
 
-       /* wake up device and enable clock */
-       pm_runtime_get_sync(&p->pdev->dev);
+       /* enable clock */
        ret = clk_enable(p->clk);
        if (ret) {
                dev_err(&p->pdev->dev, "cannot enable clock\n");
-               pm_runtime_put_sync(&p->pdev->dev);
                return ret;
        }
 
@@ -144,9 +141,8 @@ static void sh_tmu_disable(struct sh_tmu_priv *p)
        /* disable interrupts in TMU block */
        sh_tmu_write(p, TCR, 0x0000);
 
-       /* stop clock and mark device as idle */
+       /* stop clock */
        clk_disable(p->clk);
-       pm_runtime_put_sync(&p->pdev->dev);
 }
 
 static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta,
@@ -415,7 +411,6 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev)
 
        if (p) {
                dev_info(&pdev->dev, "kept as earlytimer\n");
-               pm_runtime_enable(&pdev->dev);
                return 0;
        }
 
@@ -430,9 +425,6 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev)
                kfree(p);
                platform_set_drvdata(pdev, NULL);
        }
-
-       if (!is_early_platform_device(pdev))
-               pm_runtime_enable(&pdev->dev);
        return ret;
 }
 
index c7f1a6f16b6e6a6b1faf2dfb2a3c180cea7aec1f..e2fc2d21fa6168c16acf5dcab7b75c012879630b 100644 (file)
@@ -39,3 +39,5 @@ obj-$(CONFIG_X86_CPUFREQ_NFORCE2)     += cpufreq-nforce2.o
 
 ##################################################################################d
 
+# ARM SoC drivers
+obj-$(CONFIG_UX500_SOC_DB8500)         += db8500-cpufreq.o
index b60a4c263686ab56693c5df6993e084e8f9f7e29..faf7c521784874c0dbbce7a65b9b05d3ea379f2f 100644 (file)
@@ -298,11 +298,13 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
        old_index = stat->last_index;
        new_index = freq_table_get_index(stat, freq->new);
 
-       cpufreq_stats_update(freq->cpu);
-       if (old_index == new_index)
+       /* We can't do stat->time_in_state[-1]= .. */
+       if (old_index == -1 || new_index == -1)
                return 0;
 
-       if (old_index == -1 || new_index == -1)
+       cpufreq_stats_update(freq->cpu);
+
+       if (old_index == new_index)
                return 0;
 
        spin_lock(&cpufreq_stats_lock);
@@ -387,6 +389,7 @@ static void __exit cpufreq_stats_exit(void)
        unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
        for_each_online_cpu(cpu) {
                cpufreq_stats_free_table(cpu);
+               cpufreq_stats_free_sysfs(cpu);
        }
 }
 
diff --git a/drivers/cpufreq/db8500-cpufreq.c b/drivers/cpufreq/db8500-cpufreq.c
new file mode 100644 (file)
index 0000000..d90456a
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ * Author: Martin Persson <martin.persson@stericsson.com>
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/mfd/db8500-prcmu.h>
+#include <mach/id.h>
+
+static struct cpufreq_frequency_table freq_table[] = {
+       [0] = {
+               .index = 0,
+               .frequency = 300000,
+       },
+       [1] = {
+               .index = 1,
+               .frequency = 600000,
+       },
+       [2] = {
+               /* Used for MAX_OPP, if available */
+               .index = 2,
+               .frequency = CPUFREQ_TABLE_END,
+       },
+       [3] = {
+               .index = 3,
+               .frequency = CPUFREQ_TABLE_END,
+       },
+};
+
+static enum arm_opp idx2opp[] = {
+       ARM_50_OPP,
+       ARM_100_OPP,
+       ARM_MAX_OPP
+};
+
+static struct freq_attr *db8500_cpufreq_attr[] = {
+       &cpufreq_freq_attr_scaling_available_freqs,
+       NULL,
+};
+
+static int db8500_cpufreq_verify_speed(struct cpufreq_policy *policy)
+{
+       return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static int db8500_cpufreq_target(struct cpufreq_policy *policy,
+                               unsigned int target_freq,
+                               unsigned int relation)
+{
+       struct cpufreq_freqs freqs;
+       unsigned int idx;
+
+       /* scale the target frequency to one of the extremes supported */
+       if (target_freq < policy->cpuinfo.min_freq)
+               target_freq = policy->cpuinfo.min_freq;
+       if (target_freq > policy->cpuinfo.max_freq)
+               target_freq = policy->cpuinfo.max_freq;
+
+       /* Lookup the next frequency */
+       if (cpufreq_frequency_table_target
+           (policy, freq_table, target_freq, relation, &idx)) {
+               return -EINVAL;
+       }
+
+       freqs.old = policy->cur;
+       freqs.new = freq_table[idx].frequency;
+       freqs.cpu = policy->cpu;
+
+       if (freqs.old == freqs.new)
+               return 0;
+
+       /* pre-change notification */
+       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+       /* request the PRCM unit for opp change */
+       if (prcmu_set_arm_opp(idx2opp[idx])) {
+               pr_err("db8500-cpufreq:  Failed to set OPP level\n");
+               return -EINVAL;
+       }
+
+       /* post change notification */
+       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+       return 0;
+}
+
+static unsigned int db8500_cpufreq_getspeed(unsigned int cpu)
+{
+       int i;
+       /* request the prcm to get the current ARM opp */
+       for (i = 0; prcmu_get_arm_opp() != idx2opp[i]; i++)
+               ;
+       return freq_table[i].frequency;
+}
+
+static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
+{
+       int res;
+       int i;
+
+       BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
+
+       if (cpu_is_u8500v2() && !prcmu_is_u8400()) {
+               freq_table[0].frequency = 400000;
+               freq_table[1].frequency = 800000;
+               if (prcmu_has_arm_maxopp())
+                       freq_table[2].frequency = 1000000;
+       }
+
+       /* get policy fields based on the table */
+       res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+       if (!res)
+               cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+       else {
+               pr_err("db8500-cpufreq : Failed to read policy table\n");
+               return res;
+       }
+
+       policy->min = policy->cpuinfo.min_freq;
+       policy->max = policy->cpuinfo.max_freq;
+       policy->cur = db8500_cpufreq_getspeed(policy->cpu);
+
+       for (i = 0; freq_table[i].frequency != policy->cur; i++)
+               ;
+
+       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+       /*
+        * FIXME : Need to take time measurement across the target()
+        *         function with no/some/all drivers in the notification
+        *         list.
+        */
+       policy->cpuinfo.transition_latency = 20 * 1000; /* in ns */
+
+       /* policy sharing between dual CPUs */
+       cpumask_copy(policy->cpus, &cpu_present_map);
+
+       policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+
+       return 0;
+}
+
+static struct cpufreq_driver db8500_cpufreq_driver = {
+       .flags  = CPUFREQ_STICKY,
+       .verify = db8500_cpufreq_verify_speed,
+       .target = db8500_cpufreq_target,
+       .get    = db8500_cpufreq_getspeed,
+       .init   = db8500_cpufreq_init,
+       .name   = "DB8500",
+       .attr   = db8500_cpufreq_attr,
+};
+
+static int __init db8500_cpufreq_register(void)
+{
+       if (!cpu_is_u8500v20_or_later())
+               return -ENODEV;
+
+       pr_info("cpufreq for DB8500 started\n");
+       return cpufreq_register_driver(&db8500_cpufreq_driver);
+}
+device_initcall(db8500_cpufreq_register);
index 83479b6fb9a14fc9ef9826c18274560951c45f19..bce576d7478ed41f9b69ac727cc5d143d850bb83 100644 (file)
@@ -1079,6 +1079,9 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
        }
 
        res = transition_fid_vid(data, fid, vid);
+       if (res)
+               return res;
+
        freqs.new = find_khz_freq_from_fid(data->currfid);
 
        for_each_cpu(i, data->available_cores) {
@@ -1101,7 +1104,8 @@ static int transition_frequency_pstate(struct powernow_k8_data *data,
        /* get MSR index for hardware pstate transition */
        pstate = index & HW_PSTATE_MASK;
        if (pstate > data->max_hw_pstate)
-               return 0;
+               return -EINVAL;
+
        freqs.old = find_khz_freq_from_pstate(data->powernow_table,
                        data->currpstate);
        freqs.new = find_khz_freq_from_pstate(data->powernow_table, pstate);
index f508690eb95859ef80e217f68db827daba606f29..c47f3d09c1eeb6184420632a78e892f125c36bf8 100644 (file)
@@ -237,6 +237,7 @@ static int menu_select(struct cpuidle_device *dev)
        unsigned int power_usage = -1;
        int i;
        int multiplier;
+       struct timespec t;
 
        if (data->needs_update) {
                menu_update(dev);
@@ -251,8 +252,9 @@ static int menu_select(struct cpuidle_device *dev)
                return 0;
 
        /* determine the expected residency time, round up */
+       t = ktime_to_timespec(tick_nohz_get_sleep_length());
        data->expected_us =
-           DIV_ROUND_UP((u32)ktime_to_ns(tick_nohz_get_sleep_length()), 1000);
+               t.tv_sec * USEC_PER_SEC + t.tv_nsec / NSEC_PER_USEC;
 
 
        data->bucket = which_bucket(data->expected_us);
index c64c3807f51665a111ae3bb10728d227d1e6581d..e0b25de1e339249773287c13d8f457d1f9e94352 100644 (file)
@@ -74,6 +74,8 @@ config ZCRYPT
          + PCI-X Cryptographic Coprocessor (PCIXCC)
          + Crypto Express2 Coprocessor (CEX2C)
          + Crypto Express2 Accelerator (CEX2A)
+         + Crypto Express3 Coprocessor (CEX3C)
+         + Crypto Express3 Accelerator (CEX3A)
 
 config ZCRYPT_MONOLITHIC
        bool "Monolithic zcrypt module"
index a572600e44eb3e28d10b3b52b748eac5419661fd..25cf327cd1cb4c298acc6cf5416c1c25e045da99 100644 (file)
@@ -200,16 +200,18 @@ config PL330_DMA
          platform_data for a dma-pl330 device.
 
 config PCH_DMA
-       tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7213 IOH DMA support"
+       tristate "Intel EG20T PCH / OKI Semi IOH(ML7213/ML7223) DMA support"
        depends on PCI && X86
        select DMA_ENGINE
        help
          Enable support for Intel EG20T PCH DMA engine.
 
-         This driver also can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/
-         Output Hub) which is for IVI(In-Vehicle Infotainment) use.
-         ML7213 is companion chip for Intel Atom E6xx series.
-         ML7213 is completely compatible for Intel EG20T PCH.
+         This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
+         Output Hub), ML7213 and ML7223.
+         ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is
+         for MP(Media Phone) use.
+         ML7213/ML7223 is companion chip for Intel Atom E6xx series.
+         ML7213/ML7223 is completely compatible for Intel EG20T PCH.
 
 config IMX_SDMA
        tristate "i.MX SDMA support"
diff --git a/drivers/dma/TODO b/drivers/dma/TODO
new file mode 100644 (file)
index 0000000..a4af858
--- /dev/null
@@ -0,0 +1,14 @@
+TODO for slave dma
+
+1. Move remaining drivers to use new slave interface
+2. Remove old slave pointer machansim
+3. Make issue_pending to start the transaction in below drivers
+       - mpc512x_dma
+       - imx-dma
+       - imx-sdma
+       - mxs-dma.c
+       - dw_dmac
+       - intel_mid_dma
+       - ste_dma40
+4. Check other subsystems for dma drivers and merge/move to dmaengine
+5. Remove dma_slave_config's dma direction.
index 235f53bf494eabec1affaff2d840b3d3e00ed5a3..36144f88d718f383b232b25d168030077f6769d3 100644 (file)
@@ -37,8 +37,8 @@
 
 #define        ATC_DEFAULT_CFG         (ATC_FIFOCFG_HALFFIFO)
 #define        ATC_DEFAULT_CTRLA       (0)
-#define        ATC_DEFAULT_CTRLB       (ATC_SIF(0)     \
-                               |ATC_DIF(1))
+#define        ATC_DEFAULT_CTRLB       (ATC_SIF(AT_DMA_MEM_IF) \
+                               |ATC_DIF(AT_DMA_MEM_IF))
 
 /*
  * Initial number of descriptors to allocate for each channel. This could
@@ -164,6 +164,29 @@ static void atc_desc_put(struct at_dma_chan *atchan, struct at_desc *desc)
        }
 }
 
+/**
+ * atc_desc_chain - build chain adding a descripor
+ * @first: address of first descripor of the chain
+ * @prev: address of previous descripor of the chain
+ * @desc: descriptor to queue
+ *
+ * Called from prep_* functions
+ */
+static void atc_desc_chain(struct at_desc **first, struct at_desc **prev,
+                          struct at_desc *desc)
+{
+       if (!(*first)) {
+               *first = desc;
+       } else {
+               /* inform the HW lli about chaining */
+               (*prev)->lli.dscr = desc->txd.phys;
+               /* insert the link descriptor to the LD ring */
+               list_add_tail(&desc->desc_node,
+                               &(*first)->tx_list);
+       }
+       *prev = desc;
+}
+
 /**
  * atc_assign_cookie - compute and assign new cookie
  * @atchan: channel we work on
@@ -237,16 +260,12 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
 static void
 atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
 {
-       dma_async_tx_callback           callback;
-       void                            *param;
        struct dma_async_tx_descriptor  *txd = &desc->txd;
 
        dev_vdbg(chan2dev(&atchan->chan_common),
                "descriptor %u complete\n", txd->cookie);
 
        atchan->completed_cookie = txd->cookie;
-       callback = txd->callback;
-       param = txd->callback_param;
 
        /* move children to free_list */
        list_splice_init(&desc->tx_list, &atchan->free_list);
@@ -278,12 +297,19 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
                }
        }
 
-       /*
-        * The API requires that no submissions are done from a
-        * callback, so we don't need to drop the lock here
-        */
-       if (callback)
-               callback(param);
+       /* for cyclic transfers,
+        * no need to replay callback function while stopping */
+       if (!test_bit(ATC_IS_CYCLIC, &atchan->status)) {
+               dma_async_tx_callback   callback = txd->callback;
+               void                    *param = txd->callback_param;
+
+               /*
+                * The API requires that no submissions are done from a
+                * callback, so we don't need to drop the lock here
+                */
+               if (callback)
+                       callback(param);
+       }
 
        dma_run_dependencies(txd);
 }
@@ -419,6 +445,26 @@ static void atc_handle_error(struct at_dma_chan *atchan)
        atc_chain_complete(atchan, bad_desc);
 }
 
+/**
+ * atc_handle_cyclic - at the end of a period, run callback function
+ * @atchan: channel used for cyclic operations
+ *
+ * Called with atchan->lock held and bh disabled
+ */
+static void atc_handle_cyclic(struct at_dma_chan *atchan)
+{
+       struct at_desc                  *first = atc_first_active(atchan);
+       struct dma_async_tx_descriptor  *txd = &first->txd;
+       dma_async_tx_callback           callback = txd->callback;
+       void                            *param = txd->callback_param;
+
+       dev_vdbg(chan2dev(&atchan->chan_common),
+                       "new cyclic period llp 0x%08x\n",
+                       channel_readl(atchan, DSCR));
+
+       if (callback)
+               callback(param);
+}
 
 /*--  IRQ & Tasklet  ---------------------------------------------------*/
 
@@ -426,16 +472,11 @@ static void atc_tasklet(unsigned long data)
 {
        struct at_dma_chan *atchan = (struct at_dma_chan *)data;
 
-       /* Channel cannot be enabled here */
-       if (atc_chan_is_enabled(atchan)) {
-               dev_err(chan2dev(&atchan->chan_common),
-                       "BUG: channel enabled in tasklet\n");
-               return;
-       }
-
        spin_lock(&atchan->lock);
-       if (test_and_clear_bit(0, &atchan->error_status))
+       if (test_and_clear_bit(ATC_IS_ERROR, &atchan->status))
                atc_handle_error(atchan);
+       else if (test_bit(ATC_IS_CYCLIC, &atchan->status))
+               atc_handle_cyclic(atchan);
        else
                atc_advance_work(atchan);
 
@@ -464,12 +505,13 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
 
                for (i = 0; i < atdma->dma_common.chancnt; i++) {
                        atchan = &atdma->chan[i];
-                       if (pending & (AT_DMA_CBTC(i) | AT_DMA_ERR(i))) {
+                       if (pending & (AT_DMA_BTC(i) | AT_DMA_ERR(i))) {
                                if (pending & AT_DMA_ERR(i)) {
                                        /* Disable channel on AHB error */
-                                       dma_writel(atdma, CHDR, atchan->mask);
+                                       dma_writel(atdma, CHDR,
+                                               AT_DMA_RES(i) | atchan->mask);
                                        /* Give information to tasklet */
-                                       set_bit(0, &atchan->error_status);
+                                       set_bit(ATC_IS_ERROR, &atchan->status);
                                }
                                tasklet_schedule(&atchan->tasklet);
                                ret = IRQ_HANDLED;
@@ -549,7 +591,7 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
        }
 
        ctrla =   ATC_DEFAULT_CTRLA;
-       ctrlb =   ATC_DEFAULT_CTRLB
+       ctrlb =   ATC_DEFAULT_CTRLB | ATC_IEN
                | ATC_SRC_ADDR_MODE_INCR
                | ATC_DST_ADDR_MODE_INCR
                | ATC_FC_MEM2MEM;
@@ -584,16 +626,7 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 
                desc->txd.cookie = 0;
 
-               if (!first) {
-                       first = desc;
-               } else {
-                       /* inform the HW lli about chaining */
-                       prev->lli.dscr = desc->txd.phys;
-                       /* insert the link descriptor to the LD ring */
-                       list_add_tail(&desc->desc_node,
-                                       &first->tx_list);
-               }
-               prev = desc;
+               atc_desc_chain(&first, &prev, desc);
        }
 
        /* First descriptor of the chain embedds additional information */
@@ -639,7 +672,8 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
        struct scatterlist      *sg;
        size_t                  total_len = 0;
 
-       dev_vdbg(chan2dev(chan), "prep_slave_sg: %s f0x%lx\n",
+       dev_vdbg(chan2dev(chan), "prep_slave_sg (%d): %s f0x%lx\n",
+                       sg_len,
                        direction == DMA_TO_DEVICE ? "TO DEVICE" : "FROM DEVICE",
                        flags);
 
@@ -651,14 +685,15 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
        reg_width = atslave->reg_width;
 
        ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla;
-       ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN;
+       ctrlb = ATC_IEN;
 
        switch (direction) {
        case DMA_TO_DEVICE:
                ctrla |=  ATC_DST_WIDTH(reg_width);
                ctrlb |=  ATC_DST_ADDR_MODE_FIXED
                        | ATC_SRC_ADDR_MODE_INCR
-                       | ATC_FC_MEM2PER;
+                       | ATC_FC_MEM2PER
+                       | ATC_SIF(AT_DMA_MEM_IF) | ATC_DIF(AT_DMA_PER_IF);
                reg = atslave->tx_reg;
                for_each_sg(sgl, sg, sg_len, i) {
                        struct at_desc  *desc;
@@ -682,16 +717,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                                        | len >> mem_width;
                        desc->lli.ctrlb = ctrlb;
 
-                       if (!first) {
-                               first = desc;
-                       } else {
-                               /* inform the HW lli about chaining */
-                               prev->lli.dscr = desc->txd.phys;
-                               /* insert the link descriptor to the LD ring */
-                               list_add_tail(&desc->desc_node,
-                                               &first->tx_list);
-                       }
-                       prev = desc;
+                       atc_desc_chain(&first, &prev, desc);
                        total_len += len;
                }
                break;
@@ -699,7 +725,8 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                ctrla |=  ATC_SRC_WIDTH(reg_width);
                ctrlb |=  ATC_DST_ADDR_MODE_INCR
                        | ATC_SRC_ADDR_MODE_FIXED
-                       | ATC_FC_PER2MEM;
+                       | ATC_FC_PER2MEM
+                       | ATC_SIF(AT_DMA_PER_IF) | ATC_DIF(AT_DMA_MEM_IF);
 
                reg = atslave->rx_reg;
                for_each_sg(sgl, sg, sg_len, i) {
@@ -724,16 +751,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                                        | len >> reg_width;
                        desc->lli.ctrlb = ctrlb;
 
-                       if (!first) {
-                               first = desc;
-                       } else {
-                               /* inform the HW lli about chaining */
-                               prev->lli.dscr = desc->txd.phys;
-                               /* insert the link descriptor to the LD ring */
-                               list_add_tail(&desc->desc_node,
-                                               &first->tx_list);
-                       }
-                       prev = desc;
+                       atc_desc_chain(&first, &prev, desc);
                        total_len += len;
                }
                break;
@@ -759,41 +777,211 @@ err_desc_get:
        return NULL;
 }
 
+/**
+ * atc_dma_cyclic_check_values
+ * Check for too big/unaligned periods and unaligned DMA buffer
+ */
+static int
+atc_dma_cyclic_check_values(unsigned int reg_width, dma_addr_t buf_addr,
+               size_t period_len, enum dma_data_direction direction)
+{
+       if (period_len > (ATC_BTSIZE_MAX << reg_width))
+               goto err_out;
+       if (unlikely(period_len & ((1 << reg_width) - 1)))
+               goto err_out;
+       if (unlikely(buf_addr & ((1 << reg_width) - 1)))
+               goto err_out;
+       if (unlikely(!(direction & (DMA_TO_DEVICE | DMA_FROM_DEVICE))))
+               goto err_out;
+
+       return 0;
+
+err_out:
+       return -EINVAL;
+}
+
+/**
+ * atc_dma_cyclic_fill_desc - Fill one period decriptor
+ */
+static int
+atc_dma_cyclic_fill_desc(struct at_dma_slave *atslave, struct at_desc *desc,
+               unsigned int period_index, dma_addr_t buf_addr,
+               size_t period_len, enum dma_data_direction direction)
+{
+       u32             ctrla;
+       unsigned int    reg_width = atslave->reg_width;
+
+       /* prepare common CRTLA value */
+       ctrla =   ATC_DEFAULT_CTRLA | atslave->ctrla
+               | ATC_DST_WIDTH(reg_width)
+               | ATC_SRC_WIDTH(reg_width)
+               | period_len >> reg_width;
+
+       switch (direction) {
+       case DMA_TO_DEVICE:
+               desc->lli.saddr = buf_addr + (period_len * period_index);
+               desc->lli.daddr = atslave->tx_reg;
+               desc->lli.ctrla = ctrla;
+               desc->lli.ctrlb = ATC_DST_ADDR_MODE_FIXED
+                               | ATC_SRC_ADDR_MODE_INCR
+                               | ATC_FC_MEM2PER
+                               | ATC_SIF(AT_DMA_MEM_IF)
+                               | ATC_DIF(AT_DMA_PER_IF);
+               break;
+
+       case DMA_FROM_DEVICE:
+               desc->lli.saddr = atslave->rx_reg;
+               desc->lli.daddr = buf_addr + (period_len * period_index);
+               desc->lli.ctrla = ctrla;
+               desc->lli.ctrlb = ATC_DST_ADDR_MODE_INCR
+                               | ATC_SRC_ADDR_MODE_FIXED
+                               | ATC_FC_PER2MEM
+                               | ATC_SIF(AT_DMA_PER_IF)
+                               | ATC_DIF(AT_DMA_MEM_IF);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * atc_prep_dma_cyclic - prepare the cyclic DMA transfer
+ * @chan: the DMA channel to prepare
+ * @buf_addr: physical DMA address where the buffer starts
+ * @buf_len: total number of bytes for the entire buffer
+ * @period_len: number of bytes for each period
+ * @direction: transfer direction, to or from device
+ */
+static struct dma_async_tx_descriptor *
+atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+               size_t period_len, enum dma_data_direction direction)
+{
+       struct at_dma_chan      *atchan = to_at_dma_chan(chan);
+       struct at_dma_slave     *atslave = chan->private;
+       struct at_desc          *first = NULL;
+       struct at_desc          *prev = NULL;
+       unsigned long           was_cyclic;
+       unsigned int            periods = buf_len / period_len;
+       unsigned int            i;
+
+       dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@0x%08x - %d (%d/%d)\n",
+                       direction == DMA_TO_DEVICE ? "TO DEVICE" : "FROM DEVICE",
+                       buf_addr,
+                       periods, buf_len, period_len);
+
+       if (unlikely(!atslave || !buf_len || !period_len)) {
+               dev_dbg(chan2dev(chan), "prep_dma_cyclic: length is zero!\n");
+               return NULL;
+       }
+
+       was_cyclic = test_and_set_bit(ATC_IS_CYCLIC, &atchan->status);
+       if (was_cyclic) {
+               dev_dbg(chan2dev(chan), "prep_dma_cyclic: channel in use!\n");
+               return NULL;
+       }
+
+       /* Check for too big/unaligned periods and unaligned DMA buffer */
+       if (atc_dma_cyclic_check_values(atslave->reg_width, buf_addr,
+                                       period_len, direction))
+               goto err_out;
+
+       /* build cyclic linked list */
+       for (i = 0; i < periods; i++) {
+               struct at_desc  *desc;
+
+               desc = atc_desc_get(atchan);
+               if (!desc)
+                       goto err_desc_get;
+
+               if (atc_dma_cyclic_fill_desc(atslave, desc, i, buf_addr,
+                                               period_len, direction))
+                       goto err_desc_get;
+
+               atc_desc_chain(&first, &prev, desc);
+       }
+
+       /* lets make a cyclic list */
+       prev->lli.dscr = first->txd.phys;
+
+       /* First descriptor of the chain embedds additional information */
+       first->txd.cookie = -EBUSY;
+       first->len = buf_len;
+
+       return &first->txd;
+
+err_desc_get:
+       dev_err(chan2dev(chan), "not enough descriptors available\n");
+       atc_desc_put(atchan, first);
+err_out:
+       clear_bit(ATC_IS_CYCLIC, &atchan->status);
+       return NULL;
+}
+
+
 static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
                       unsigned long arg)
 {
        struct at_dma_chan      *atchan = to_at_dma_chan(chan);
        struct at_dma           *atdma = to_at_dma(chan->device);
-       struct at_desc          *desc, *_desc;
+       int                     chan_id = atchan->chan_common.chan_id;
+
        LIST_HEAD(list);
 
-       /* Only supports DMA_TERMINATE_ALL */
-       if (cmd != DMA_TERMINATE_ALL)
-               return -ENXIO;
+       dev_vdbg(chan2dev(chan), "atc_control (%d)\n", cmd);
 
-       /*
-        * This is only called when something went wrong elsewhere, so
-        * we don't really care about the data. Just disable the
-        * channel. We still have to poll the channel enable bit due
-        * to AHB/HSB limitations.
-        */
-       spin_lock_bh(&atchan->lock);
+       if (cmd == DMA_PAUSE) {
+               spin_lock_bh(&atchan->lock);
 
-       dma_writel(atdma, CHDR, atchan->mask);
+               dma_writel(atdma, CHER, AT_DMA_SUSP(chan_id));
+               set_bit(ATC_IS_PAUSED, &atchan->status);
 
-       /* confirm that this channel is disabled */
-       while (dma_readl(atdma, CHSR) & atchan->mask)
-               cpu_relax();
+               spin_unlock_bh(&atchan->lock);
+       } else if (cmd == DMA_RESUME) {
+               if (!test_bit(ATC_IS_PAUSED, &atchan->status))
+                       return 0;
 
-       /* active_list entries will end up before queued entries */
-       list_splice_init(&atchan->queue, &list);
-       list_splice_init(&atchan->active_list, &list);
+               spin_lock_bh(&atchan->lock);
 
-       /* Flush all pending and queued descriptors */
-       list_for_each_entry_safe(desc, _desc, &list, desc_node)
-               atc_chain_complete(atchan, desc);
+               dma_writel(atdma, CHDR, AT_DMA_RES(chan_id));
+               clear_bit(ATC_IS_PAUSED, &atchan->status);
 
-       spin_unlock_bh(&atchan->lock);
+               spin_unlock_bh(&atchan->lock);
+       } else if (cmd == DMA_TERMINATE_ALL) {
+               struct at_desc  *desc, *_desc;
+               /*
+                * This is only called when something went wrong elsewhere, so
+                * we don't really care about the data. Just disable the
+                * channel. We still have to poll the channel enable bit due
+                * to AHB/HSB limitations.
+                */
+               spin_lock_bh(&atchan->lock);
+
+               /* disabling channel: must also remove suspend state */
+               dma_writel(atdma, CHDR, AT_DMA_RES(chan_id) | atchan->mask);
+
+               /* confirm that this channel is disabled */
+               while (dma_readl(atdma, CHSR) & atchan->mask)
+                       cpu_relax();
+
+               /* active_list entries will end up before queued entries */
+               list_splice_init(&atchan->queue, &list);
+               list_splice_init(&atchan->active_list, &list);
+
+               /* Flush all pending and queued descriptors */
+               list_for_each_entry_safe(desc, _desc, &list, desc_node)
+                       atc_chain_complete(atchan, desc);
+
+               clear_bit(ATC_IS_PAUSED, &atchan->status);
+               /* if channel dedicated to cyclic operations, free it */
+               clear_bit(ATC_IS_CYCLIC, &atchan->status);
+
+               spin_unlock_bh(&atchan->lock);
+       } else {
+               return -ENXIO;
+       }
 
        return 0;
 }
@@ -835,9 +1023,17 @@ atc_tx_status(struct dma_chan *chan,
 
        spin_unlock_bh(&atchan->lock);
 
-       dma_set_tx_state(txstate, last_complete, last_used, 0);
-       dev_vdbg(chan2dev(chan), "tx_status: %d (d%d, u%d)\n",
-                cookie, last_complete ? last_complete : 0,
+       if (ret != DMA_SUCCESS)
+               dma_set_tx_state(txstate, last_complete, last_used,
+                       atc_first_active(atchan)->len);
+       else
+               dma_set_tx_state(txstate, last_complete, last_used, 0);
+
+       if (test_bit(ATC_IS_PAUSED, &atchan->status))
+               ret = DMA_PAUSED;
+
+       dev_vdbg(chan2dev(chan), "tx_status %d: cookie = %d (d%d, u%d)\n",
+                ret, cookie, last_complete ? last_complete : 0,
                 last_used ? last_used : 0);
 
        return ret;
@@ -853,6 +1049,10 @@ static void atc_issue_pending(struct dma_chan *chan)
 
        dev_vdbg(chan2dev(chan), "issue_pending\n");
 
+       /* Not needed for cyclic transfers */
+       if (test_bit(ATC_IS_CYCLIC, &atchan->status))
+               return;
+
        spin_lock_bh(&atchan->lock);
        if (!atc_chan_is_enabled(atchan)) {
                atc_advance_work(atchan);
@@ -959,6 +1159,7 @@ static void atc_free_chan_resources(struct dma_chan *chan)
        }
        list_splice_init(&atchan->free_list, &list);
        atchan->descs_allocated = 0;
+       atchan->status = 0;
 
        dev_vdbg(chan2dev(chan), "free_chan_resources: done\n");
 }
@@ -1092,10 +1293,15 @@ static int __init at_dma_probe(struct platform_device *pdev)
        if (dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask))
                atdma->dma_common.device_prep_dma_memcpy = atc_prep_dma_memcpy;
 
-       if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)) {
+       if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask))
                atdma->dma_common.device_prep_slave_sg = atc_prep_slave_sg;
+
+       if (dma_has_cap(DMA_CYCLIC, atdma->dma_common.cap_mask))
+               atdma->dma_common.device_prep_dma_cyclic = atc_prep_dma_cyclic;
+
+       if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask) ||
+           dma_has_cap(DMA_CYCLIC, atdma->dma_common.cap_mask))
                atdma->dma_common.device_control = atc_control;
-       }
 
        dma_writel(atdma, EN, AT_DMA_ENABLE);
 
index 495457e3dc4b6133dc6c846392961db3a461aaf9..087dbf1dd39cc0d87416e24e093ca7841a714b3f 100644 (file)
 /* Bitfields in CTRLB */
 #define        ATC_SIF(i)              (0x3 & (i))     /* Src tx done via AHB-Lite Interface i */
 #define        ATC_DIF(i)              ((0x3 & (i)) <<  4)     /* Dst tx done via AHB-Lite Interface i */
+                                 /* Specify AHB interfaces */
+#define AT_DMA_MEM_IF          0 /* interface 0 as memory interface */
+#define AT_DMA_PER_IF          1 /* interface 1 as peripheral interface */
+
 #define        ATC_SRC_PIP             (0x1 <<  8)     /* Source Picture-in-Picture enabled */
 #define        ATC_DST_PIP             (0x1 << 12)     /* Destination Picture-in-Picture enabled */
 #define        ATC_SRC_DSCR_DIS        (0x1 << 16)     /* Src Descriptor fetch disable */
@@ -180,13 +184,24 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd)
 
 /*--  Channels  --------------------------------------------------------*/
 
+/**
+ * atc_status - information bits stored in channel status flag
+ *
+ * Manipulated with atomic operations.
+ */
+enum atc_status {
+       ATC_IS_ERROR = 0,
+       ATC_IS_PAUSED = 1,
+       ATC_IS_CYCLIC = 24,
+};
+
 /**
  * struct at_dma_chan - internal representation of an Atmel HDMAC channel
  * @chan_common: common dmaengine channel object members
  * @device: parent device
  * @ch_regs: memory mapped register base
  * @mask: channel index in a mask
- * @error_status: transmit error status information from irq handler
+ * @status: transmit status information from irq/prep* functions
  *                to tasklet (use atomic operations)
  * @tasklet: bottom half to finish transaction work
  * @lock: serializes enqueue/dequeue operations to descriptors lists
@@ -201,7 +216,7 @@ struct at_dma_chan {
        struct at_dma           *device;
        void __iomem            *ch_regs;
        u8                      mask;
-       unsigned long           error_status;
+       unsigned long           status;
        struct tasklet_struct   tasklet;
 
        spinlock_t              lock;
@@ -309,8 +324,8 @@ static void atc_setup_irq(struct at_dma_chan *atchan, int on)
        struct at_dma   *atdma = to_at_dma(atchan->chan_common.device);
        u32             ebci;
 
-       /* enable interrupts on buffer chain completion & error */
-       ebci =    AT_DMA_CBTC(atchan->chan_common.chan_id)
+       /* enable interrupts on buffer transfer completion & error */
+       ebci =    AT_DMA_BTC(atchan->chan_common.chan_id)
                | AT_DMA_ERR(atchan->chan_common.chan_id);
        if (on)
                dma_writel(atdma, EBCIER, ebci);
@@ -347,7 +362,12 @@ static inline int atc_chan_is_enabled(struct at_dma_chan *atchan)
  */
 static void set_desc_eol(struct at_desc *desc)
 {
-       desc->lli.ctrlb |= ATC_SRC_DSCR_DIS | ATC_DST_DSCR_DIS;
+       u32 ctrlb = desc->lli.ctrlb;
+
+       ctrlb &= ~ATC_IEN;
+       ctrlb |= ATC_SRC_DSCR_DIS | ATC_DST_DSCR_DIS;
+
+       desc->lli.ctrlb = ctrlb;
        desc->lli.dscr = 0;
 }
 
index f48e54006518e9929cbae1c2af2cf135a4edaa13..af8c0b5ed70f0a8257756abdca44a7d014ed3b72 100644 (file)
@@ -1610,7 +1610,7 @@ int __init coh901318_init(void)
 {
        return platform_driver_probe(&coh901318_driver, coh901318_probe);
 }
-arch_initcall(coh901318_init);
+subsys_initcall(coh901318_init);
 
 void __exit coh901318_exit(void)
 {
index 2a2e2fa00e91427434286e5f3267defff300ff24..4d180ca9a1d86a46e311b25b568e99380c1399a6 100644 (file)
@@ -3,6 +3,7 @@
  * AVR32 systems.)
  *
  * Copyright (C) 2007-2008 Atmel Corporation
+ * Copyright (C) 2010-2011 ST Microelectronics
  *
  * 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
@@ -93,8 +94,9 @@ static struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc)
        struct dw_desc *desc, *_desc;
        struct dw_desc *ret = NULL;
        unsigned int i = 0;
+       unsigned long flags;
 
-       spin_lock_bh(&dwc->lock);
+       spin_lock_irqsave(&dwc->lock, flags);
        list_for_each_entry_safe(desc, _desc, &dwc->free_list, desc_node) {
                if (async_tx_test_ack(&desc->txd)) {
                        list_del(&desc->desc_node);
@@ -104,7 +106,7 @@ static struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc)
                dev_dbg(chan2dev(&dwc->chan), "desc %p not ACKed\n", desc);
                i++;
        }
-       spin_unlock_bh(&dwc->lock);
+       spin_unlock_irqrestore(&dwc->lock, flags);
 
        dev_vdbg(chan2dev(&dwc->chan), "scanned %u descriptors on freelist\n", i);
 
@@ -130,12 +132,14 @@ static void dwc_sync_desc_for_cpu(struct dw_dma_chan *dwc, struct dw_desc *desc)
  */
 static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
 {
+       unsigned long flags;
+
        if (desc) {
                struct dw_desc *child;
 
                dwc_sync_desc_for_cpu(dwc, desc);
 
-               spin_lock_bh(&dwc->lock);
+               spin_lock_irqsave(&dwc->lock, flags);
                list_for_each_entry(child, &desc->tx_list, desc_node)
                        dev_vdbg(chan2dev(&dwc->chan),
                                        "moving child desc %p to freelist\n",
@@ -143,7 +147,7 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
                list_splice_init(&desc->tx_list, &dwc->free_list);
                dev_vdbg(chan2dev(&dwc->chan), "moving desc %p to freelist\n", desc);
                list_add(&desc->desc_node, &dwc->free_list);
-               spin_unlock_bh(&dwc->lock);
+               spin_unlock_irqrestore(&dwc->lock, flags);
        }
 }
 
@@ -195,18 +199,23 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
 /*----------------------------------------------------------------------*/
 
 static void
-dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc)
+dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc,
+               bool callback_required)
 {
-       dma_async_tx_callback           callback;
-       void                            *param;
+       dma_async_tx_callback           callback = NULL;
+       void                            *param = NULL;
        struct dma_async_tx_descriptor  *txd = &desc->txd;
        struct dw_desc                  *child;
+       unsigned long                   flags;
 
        dev_vdbg(chan2dev(&dwc->chan), "descriptor %u complete\n", txd->cookie);
 
+       spin_lock_irqsave(&dwc->lock, flags);
        dwc->completed = txd->cookie;
-       callback = txd->callback;
-       param = txd->callback_param;
+       if (callback_required) {
+               callback = txd->callback;
+               param = txd->callback_param;
+       }
 
        dwc_sync_desc_for_cpu(dwc, desc);
 
@@ -238,11 +247,9 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc)
                }
        }
 
-       /*
-        * The API requires that no submissions are done from a
-        * callback, so we don't need to drop the lock here
-        */
-       if (callback)
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       if (callback_required && callback)
                callback(param);
 }
 
@@ -250,7 +257,9 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc)
 {
        struct dw_desc *desc, *_desc;
        LIST_HEAD(list);
+       unsigned long flags;
 
+       spin_lock_irqsave(&dwc->lock, flags);
        if (dma_readl(dw, CH_EN) & dwc->mask) {
                dev_err(chan2dev(&dwc->chan),
                        "BUG: XFER bit set, but channel not idle!\n");
@@ -271,8 +280,10 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc)
                dwc_dostart(dwc, dwc_first_active(dwc));
        }
 
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
        list_for_each_entry_safe(desc, _desc, &list, desc_node)
-               dwc_descriptor_complete(dwc, desc);
+               dwc_descriptor_complete(dwc, desc, true);
 }
 
 static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
@@ -281,7 +292,9 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
        struct dw_desc *desc, *_desc;
        struct dw_desc *child;
        u32 status_xfer;
+       unsigned long flags;
 
+       spin_lock_irqsave(&dwc->lock, flags);
        /*
         * Clear block interrupt flag before scanning so that we don't
         * miss any, and read LLP before RAW_XFER to ensure it is
@@ -294,30 +307,47 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
        if (status_xfer & dwc->mask) {
                /* Everything we've submitted is done */
                dma_writel(dw, CLEAR.XFER, dwc->mask);
+               spin_unlock_irqrestore(&dwc->lock, flags);
+
                dwc_complete_all(dw, dwc);
                return;
        }
 
-       if (list_empty(&dwc->active_list))
+       if (list_empty(&dwc->active_list)) {
+               spin_unlock_irqrestore(&dwc->lock, flags);
                return;
+       }
 
        dev_vdbg(chan2dev(&dwc->chan), "scan_descriptors: llp=0x%x\n", llp);
 
        list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
-               if (desc->lli.llp == llp)
+               /* check first descriptors addr */
+               if (desc->txd.phys == llp) {
+                       spin_unlock_irqrestore(&dwc->lock, flags);
+                       return;
+               }
+
+               /* check first descriptors llp */
+               if (desc->lli.llp == llp) {
                        /* This one is currently in progress */
+                       spin_unlock_irqrestore(&dwc->lock, flags);
                        return;
+               }
 
                list_for_each_entry(child, &desc->tx_list, desc_node)
-                       if (child->lli.llp == llp)
+                       if (child->lli.llp == llp) {
                                /* Currently in progress */
+                               spin_unlock_irqrestore(&dwc->lock, flags);
                                return;
+                       }
 
                /*
                 * No descriptors so far seem to be in progress, i.e.
                 * this one must be done.
                 */
-               dwc_descriptor_complete(dwc, desc);
+               spin_unlock_irqrestore(&dwc->lock, flags);
+               dwc_descriptor_complete(dwc, desc, true);
+               spin_lock_irqsave(&dwc->lock, flags);
        }
 
        dev_err(chan2dev(&dwc->chan),
@@ -332,6 +362,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
                list_move(dwc->queue.next, &dwc->active_list);
                dwc_dostart(dwc, dwc_first_active(dwc));
        }
+       spin_unlock_irqrestore(&dwc->lock, flags);
 }
 
 static void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_lli *lli)
@@ -346,9 +377,12 @@ static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc)
 {
        struct dw_desc *bad_desc;
        struct dw_desc *child;
+       unsigned long flags;
 
        dwc_scan_descriptors(dw, dwc);
 
+       spin_lock_irqsave(&dwc->lock, flags);
+
        /*
         * The descriptor currently at the head of the active list is
         * borked. Since we don't have any way to report errors, we'll
@@ -378,8 +412,10 @@ static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc)
        list_for_each_entry(child, &bad_desc->tx_list, desc_node)
                dwc_dump_lli(dwc, &child->lli);
 
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
        /* Pretend the descriptor completed successfully */
-       dwc_descriptor_complete(dwc, bad_desc);
+       dwc_descriptor_complete(dwc, bad_desc, true);
 }
 
 /* --------------------- Cyclic DMA API extensions -------------------- */
@@ -402,6 +438,8 @@ EXPORT_SYMBOL(dw_dma_get_dst_addr);
 static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
                u32 status_block, u32 status_err, u32 status_xfer)
 {
+       unsigned long flags;
+
        if (status_block & dwc->mask) {
                void (*callback)(void *param);
                void *callback_param;
@@ -412,11 +450,9 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
 
                callback = dwc->cdesc->period_callback;
                callback_param = dwc->cdesc->period_callback_param;
-               if (callback) {
-                       spin_unlock(&dwc->lock);
+
+               if (callback)
                        callback(callback_param);
-                       spin_lock(&dwc->lock);
-               }
        }
 
        /*
@@ -430,6 +466,9 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
                dev_err(chan2dev(&dwc->chan), "cyclic DMA unexpected %s "
                                "interrupt, stopping DMA transfer\n",
                                status_xfer ? "xfer" : "error");
+
+               spin_lock_irqsave(&dwc->lock, flags);
+
                dev_err(chan2dev(&dwc->chan),
                        "  SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
                        channel_readl(dwc, SAR),
@@ -453,6 +492,8 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
 
                for (i = 0; i < dwc->cdesc->periods; i++)
                        dwc_dump_lli(dwc, &dwc->cdesc->desc[i]->lli);
+
+               spin_unlock_irqrestore(&dwc->lock, flags);
        }
 }
 
@@ -476,7 +517,6 @@ static void dw_dma_tasklet(unsigned long data)
 
        for (i = 0; i < dw->dma.chancnt; i++) {
                dwc = &dw->chan[i];
-               spin_lock(&dwc->lock);
                if (test_bit(DW_DMA_IS_CYCLIC, &dwc->flags))
                        dwc_handle_cyclic(dw, dwc, status_block, status_err,
                                        status_xfer);
@@ -484,7 +524,6 @@ static void dw_dma_tasklet(unsigned long data)
                        dwc_handle_error(dw, dwc);
                else if ((status_block | status_xfer) & (1 << i))
                        dwc_scan_descriptors(dw, dwc);
-               spin_unlock(&dwc->lock);
        }
 
        /*
@@ -539,8 +578,9 @@ static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx)
        struct dw_desc          *desc = txd_to_dw_desc(tx);
        struct dw_dma_chan      *dwc = to_dw_dma_chan(tx->chan);
        dma_cookie_t            cookie;
+       unsigned long           flags;
 
-       spin_lock_bh(&dwc->lock);
+       spin_lock_irqsave(&dwc->lock, flags);
        cookie = dwc_assign_cookie(dwc, desc);
 
        /*
@@ -560,7 +600,7 @@ static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx)
                list_add_tail(&desc->desc_node, &dwc->queue);
        }
 
-       spin_unlock_bh(&dwc->lock);
+       spin_unlock_irqrestore(&dwc->lock, flags);
 
        return cookie;
 }
@@ -689,9 +729,15 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                reg = dws->tx_reg;
                for_each_sg(sgl, sg, sg_len, i) {
                        struct dw_desc  *desc;
-                       u32             len;
-                       u32             mem;
+                       u32             len, dlen, mem;
+
+                       mem = sg_phys(sg);
+                       len = sg_dma_len(sg);
+                       mem_width = 2;
+                       if (unlikely(mem & 3 || len & 3))
+                               mem_width = 0;
 
+slave_sg_todev_fill_desc:
                        desc = dwc_desc_get(dwc);
                        if (!desc) {
                                dev_err(chan2dev(chan),
@@ -699,16 +745,19 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                                goto err_desc_get;
                        }
 
-                       mem = sg_phys(sg);
-                       len = sg_dma_len(sg);
-                       mem_width = 2;
-                       if (unlikely(mem & 3 || len & 3))
-                               mem_width = 0;
-
                        desc->lli.sar = mem;
                        desc->lli.dar = reg;
                        desc->lli.ctllo = ctllo | DWC_CTLL_SRC_WIDTH(mem_width);
-                       desc->lli.ctlhi = len >> mem_width;
+                       if ((len >> mem_width) > DWC_MAX_COUNT) {
+                               dlen = DWC_MAX_COUNT << mem_width;
+                               mem += dlen;
+                               len -= dlen;
+                       } else {
+                               dlen = len;
+                               len = 0;
+                       }
+
+                       desc->lli.ctlhi = dlen >> mem_width;
 
                        if (!first) {
                                first = desc;
@@ -722,7 +771,10 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                                                &first->tx_list);
                        }
                        prev = desc;
-                       total_len += len;
+                       total_len += dlen;
+
+                       if (len)
+                               goto slave_sg_todev_fill_desc;
                }
                break;
        case DMA_FROM_DEVICE:
@@ -735,15 +787,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                reg = dws->rx_reg;
                for_each_sg(sgl, sg, sg_len, i) {
                        struct dw_desc  *desc;
-                       u32             len;
-                       u32             mem;
-
-                       desc = dwc_desc_get(dwc);
-                       if (!desc) {
-                               dev_err(chan2dev(chan),
-                                       "not enough descriptors available\n");
-                               goto err_desc_get;
-                       }
+                       u32             len, dlen, mem;
 
                        mem = sg_phys(sg);
                        len = sg_dma_len(sg);
@@ -751,10 +795,26 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                        if (unlikely(mem & 3 || len & 3))
                                mem_width = 0;
 
+slave_sg_fromdev_fill_desc:
+                       desc = dwc_desc_get(dwc);
+                       if (!desc) {
+                               dev_err(chan2dev(chan),
+                                               "not enough descriptors available\n");
+                               goto err_desc_get;
+                       }
+
                        desc->lli.sar = reg;
                        desc->lli.dar = mem;
                        desc->lli.ctllo = ctllo | DWC_CTLL_DST_WIDTH(mem_width);
-                       desc->lli.ctlhi = len >> reg_width;
+                       if ((len >> reg_width) > DWC_MAX_COUNT) {
+                               dlen = DWC_MAX_COUNT << reg_width;
+                               mem += dlen;
+                               len -= dlen;
+                       } else {
+                               dlen = len;
+                               len = 0;
+                       }
+                       desc->lli.ctlhi = dlen >> reg_width;
 
                        if (!first) {
                                first = desc;
@@ -768,7 +828,10 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                                                &first->tx_list);
                        }
                        prev = desc;
-                       total_len += len;
+                       total_len += dlen;
+
+                       if (len)
+                               goto slave_sg_fromdev_fill_desc;
                }
                break;
        default:
@@ -799,34 +862,51 @@ static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
        struct dw_dma_chan      *dwc = to_dw_dma_chan(chan);
        struct dw_dma           *dw = to_dw_dma(chan->device);
        struct dw_desc          *desc, *_desc;
+       unsigned long           flags;
+       u32                     cfglo;
        LIST_HEAD(list);
 
-       /* Only supports DMA_TERMINATE_ALL */
-       if (cmd != DMA_TERMINATE_ALL)
-               return -ENXIO;
+       if (cmd == DMA_PAUSE) {
+               spin_lock_irqsave(&dwc->lock, flags);
 
-       /*
-        * This is only called when something went wrong elsewhere, so
-        * we don't really care about the data. Just disable the
-        * channel. We still have to poll the channel enable bit due
-        * to AHB/HSB limitations.
-        */
-       spin_lock_bh(&dwc->lock);
+               cfglo = channel_readl(dwc, CFG_LO);
+               channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP);
+               while (!(channel_readl(dwc, CFG_LO) & DWC_CFGL_FIFO_EMPTY))
+                       cpu_relax();
 
-       channel_clear_bit(dw, CH_EN, dwc->mask);
+               dwc->paused = true;
+               spin_unlock_irqrestore(&dwc->lock, flags);
+       } else if (cmd == DMA_RESUME) {
+               if (!dwc->paused)
+                       return 0;
 
-       while (dma_readl(dw, CH_EN) & dwc->mask)
-               cpu_relax();
+               spin_lock_irqsave(&dwc->lock, flags);
 
-       /* active_list entries will end up before queued entries */
-       list_splice_init(&dwc->queue, &list);
-       list_splice_init(&dwc->active_list, &list);
+               cfglo = channel_readl(dwc, CFG_LO);
+               channel_writel(dwc, CFG_LO, cfglo & ~DWC_CFGL_CH_SUSP);
+               dwc->paused = false;
 
-       spin_unlock_bh(&dwc->lock);
+               spin_unlock_irqrestore(&dwc->lock, flags);
+       } else if (cmd == DMA_TERMINATE_ALL) {
+               spin_lock_irqsave(&dwc->lock, flags);
 
-       /* Flush all pending and queued descriptors */
-       list_for_each_entry_safe(desc, _desc, &list, desc_node)
-               dwc_descriptor_complete(dwc, desc);
+               channel_clear_bit(dw, CH_EN, dwc->mask);
+               while (dma_readl(dw, CH_EN) & dwc->mask)
+                       cpu_relax();
+
+               dwc->paused = false;
+
+               /* active_list entries will end up before queued entries */
+               list_splice_init(&dwc->queue, &list);
+               list_splice_init(&dwc->active_list, &list);
+
+               spin_unlock_irqrestore(&dwc->lock, flags);
+
+               /* Flush all pending and queued descriptors */
+               list_for_each_entry_safe(desc, _desc, &list, desc_node)
+                       dwc_descriptor_complete(dwc, desc, false);
+       } else
+               return -ENXIO;
 
        return 0;
 }
@@ -846,9 +926,7 @@ dwc_tx_status(struct dma_chan *chan,
 
        ret = dma_async_is_complete(cookie, last_complete, last_used);
        if (ret != DMA_SUCCESS) {
-               spin_lock_bh(&dwc->lock);
                dwc_scan_descriptors(to_dw_dma(chan->device), dwc);
-               spin_unlock_bh(&dwc->lock);
 
                last_complete = dwc->completed;
                last_used = chan->cookie;
@@ -856,7 +934,14 @@ dwc_tx_status(struct dma_chan *chan,
                ret = dma_async_is_complete(cookie, last_complete, last_used);
        }
 
-       dma_set_tx_state(txstate, last_complete, last_used, 0);
+       if (ret != DMA_SUCCESS)
+               dma_set_tx_state(txstate, last_complete, last_used,
+                               dwc_first_active(dwc)->len);
+       else
+               dma_set_tx_state(txstate, last_complete, last_used, 0);
+
+       if (dwc->paused)
+               return DMA_PAUSED;
 
        return ret;
 }
@@ -865,10 +950,8 @@ static void dwc_issue_pending(struct dma_chan *chan)
 {
        struct dw_dma_chan      *dwc = to_dw_dma_chan(chan);
 
-       spin_lock_bh(&dwc->lock);
        if (!list_empty(&dwc->queue))
                dwc_scan_descriptors(to_dw_dma(chan->device), dwc);
-       spin_unlock_bh(&dwc->lock);
 }
 
 static int dwc_alloc_chan_resources(struct dma_chan *chan)
@@ -880,6 +963,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
        int                     i;
        u32                     cfghi;
        u32                     cfglo;
+       unsigned long           flags;
 
        dev_vdbg(chan2dev(chan), "alloc_chan_resources\n");
 
@@ -917,16 +1001,16 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
         * doesn't mean what you think it means), and status writeback.
         */
 
-       spin_lock_bh(&dwc->lock);
+       spin_lock_irqsave(&dwc->lock, flags);
        i = dwc->descs_allocated;
        while (dwc->descs_allocated < NR_DESCS_PER_CHANNEL) {
-               spin_unlock_bh(&dwc->lock);
+               spin_unlock_irqrestore(&dwc->lock, flags);
 
                desc = kzalloc(sizeof(struct dw_desc), GFP_KERNEL);
                if (!desc) {
                        dev_info(chan2dev(chan),
                                "only allocated %d descriptors\n", i);
-                       spin_lock_bh(&dwc->lock);
+                       spin_lock_irqsave(&dwc->lock, flags);
                        break;
                }
 
@@ -938,7 +1022,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
                                sizeof(desc->lli), DMA_TO_DEVICE);
                dwc_desc_put(dwc, desc);
 
-               spin_lock_bh(&dwc->lock);
+               spin_lock_irqsave(&dwc->lock, flags);
                i = ++dwc->descs_allocated;
        }
 
@@ -947,7 +1031,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
        channel_set_bit(dw, MASK.BLOCK, dwc->mask);
        channel_set_bit(dw, MASK.ERROR, dwc->mask);
 
-       spin_unlock_bh(&dwc->lock);
+       spin_unlock_irqrestore(&dwc->lock, flags);
 
        dev_dbg(chan2dev(chan),
                "alloc_chan_resources allocated %d descriptors\n", i);
@@ -960,6 +1044,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
        struct dw_dma_chan      *dwc = to_dw_dma_chan(chan);
        struct dw_dma           *dw = to_dw_dma(chan->device);
        struct dw_desc          *desc, *_desc;
+       unsigned long           flags;
        LIST_HEAD(list);
 
        dev_dbg(chan2dev(chan), "free_chan_resources (descs allocated=%u)\n",
@@ -970,7 +1055,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
        BUG_ON(!list_empty(&dwc->queue));
        BUG_ON(dma_readl(to_dw_dma(chan->device), CH_EN) & dwc->mask);
 
-       spin_lock_bh(&dwc->lock);
+       spin_lock_irqsave(&dwc->lock, flags);
        list_splice_init(&dwc->free_list, &list);
        dwc->descs_allocated = 0;
 
@@ -979,7 +1064,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
        channel_clear_bit(dw, MASK.BLOCK, dwc->mask);
        channel_clear_bit(dw, MASK.ERROR, dwc->mask);
 
-       spin_unlock_bh(&dwc->lock);
+       spin_unlock_irqrestore(&dwc->lock, flags);
 
        list_for_each_entry_safe(desc, _desc, &list, desc_node) {
                dev_vdbg(chan2dev(chan), "  freeing descriptor %p\n", desc);
@@ -1004,13 +1089,14 @@ int dw_dma_cyclic_start(struct dma_chan *chan)
 {
        struct dw_dma_chan      *dwc = to_dw_dma_chan(chan);
        struct dw_dma           *dw = to_dw_dma(dwc->chan.device);
+       unsigned long           flags;
 
        if (!test_bit(DW_DMA_IS_CYCLIC, &dwc->flags)) {
                dev_err(chan2dev(&dwc->chan), "missing prep for cyclic DMA\n");
                return -ENODEV;
        }
 
-       spin_lock(&dwc->lock);
+       spin_lock_irqsave(&dwc->lock, flags);
 
        /* assert channel is idle */
        if (dma_readl(dw, CH_EN) & dwc->mask) {
@@ -1023,7 +1109,7 @@ int dw_dma_cyclic_start(struct dma_chan *chan)
                        channel_readl(dwc, LLP),
                        channel_readl(dwc, CTL_HI),
                        channel_readl(dwc, CTL_LO));
-               spin_unlock(&dwc->lock);
+               spin_unlock_irqrestore(&dwc->lock, flags);
                return -EBUSY;
        }
 
@@ -1038,7 +1124,7 @@ int dw_dma_cyclic_start(struct dma_chan *chan)
 
        channel_set_bit(dw, CH_EN, dwc->mask);
 
-       spin_unlock(&dwc->lock);
+       spin_unlock_irqrestore(&dwc->lock, flags);
 
        return 0;
 }
@@ -1054,14 +1140,15 @@ void dw_dma_cyclic_stop(struct dma_chan *chan)
 {
        struct dw_dma_chan      *dwc = to_dw_dma_chan(chan);
        struct dw_dma           *dw = to_dw_dma(dwc->chan.device);
+       unsigned long           flags;
 
-       spin_lock(&dwc->lock);
+       spin_lock_irqsave(&dwc->lock, flags);
 
        channel_clear_bit(dw, CH_EN, dwc->mask);
        while (dma_readl(dw, CH_EN) & dwc->mask)
                cpu_relax();
 
-       spin_unlock(&dwc->lock);
+       spin_unlock_irqrestore(&dwc->lock, flags);
 }
 EXPORT_SYMBOL(dw_dma_cyclic_stop);
 
@@ -1090,17 +1177,18 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
        unsigned int                    reg_width;
        unsigned int                    periods;
        unsigned int                    i;
+       unsigned long                   flags;
 
-       spin_lock_bh(&dwc->lock);
+       spin_lock_irqsave(&dwc->lock, flags);
        if (!list_empty(&dwc->queue) || !list_empty(&dwc->active_list)) {
-               spin_unlock_bh(&dwc->lock);
+               spin_unlock_irqrestore(&dwc->lock, flags);
                dev_dbg(chan2dev(&dwc->chan),
                                "queue and/or active list are not empty\n");
                return ERR_PTR(-EBUSY);
        }
 
        was_cyclic = test_and_set_bit(DW_DMA_IS_CYCLIC, &dwc->flags);
-       spin_unlock_bh(&dwc->lock);
+       spin_unlock_irqrestore(&dwc->lock, flags);
        if (was_cyclic) {
                dev_dbg(chan2dev(&dwc->chan),
                                "channel already prepared for cyclic DMA\n");
@@ -1214,13 +1302,14 @@ void dw_dma_cyclic_free(struct dma_chan *chan)
        struct dw_dma           *dw = to_dw_dma(dwc->chan.device);
        struct dw_cyclic_desc   *cdesc = dwc->cdesc;
        int                     i;
+       unsigned long           flags;
 
        dev_dbg(chan2dev(&dwc->chan), "cyclic free\n");
 
        if (!cdesc)
                return;
 
-       spin_lock_bh(&dwc->lock);
+       spin_lock_irqsave(&dwc->lock, flags);
 
        channel_clear_bit(dw, CH_EN, dwc->mask);
        while (dma_readl(dw, CH_EN) & dwc->mask)
@@ -1230,7 +1319,7 @@ void dw_dma_cyclic_free(struct dma_chan *chan)
        dma_writel(dw, CLEAR.ERROR, dwc->mask);
        dma_writel(dw, CLEAR.XFER, dwc->mask);
 
-       spin_unlock_bh(&dwc->lock);
+       spin_unlock_irqrestore(&dwc->lock, flags);
 
        for (i = 0; i < cdesc->periods; i++)
                dwc_desc_put(dwc, cdesc->desc[i]);
@@ -1487,3 +1576,4 @@ module_exit(dw_exit);
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller driver");
 MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
index 720f821527f8aeebd8738c34f1f5c87a5a34f867..c3419518d701dbe3a0671cbc906a88c7ee3823a3 100644 (file)
@@ -2,6 +2,7 @@
  * Driver for the Synopsys DesignWare AHB DMA Controller
  *
  * Copyright (C) 2005-2007 Atmel Corporation
+ * Copyright (C) 2010-2011 ST Microelectronics
  *
  * 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
@@ -138,6 +139,7 @@ struct dw_dma_chan {
        void __iomem            *ch_regs;
        u8                      mask;
        u8                      priority;
+       bool                    paused;
 
        spinlock_t              lock;
 
index 3d4ec38b9b62879ea9175b9ddf59b5f7ea07f3a2..f653517ef7445c484580ef140b64315781c05d13 100644 (file)
@@ -1292,8 +1292,7 @@ static int __devinit intel_mid_dma_probe(struct pci_dev *pdev,
        if (err)
                goto err_dma;
 
-       pm_runtime_set_active(&pdev->dev);
-       pm_runtime_enable(&pdev->dev);
+       pm_runtime_put_noidle(&pdev->dev);
        pm_runtime_allow(&pdev->dev);
        return 0;
 
@@ -1322,6 +1321,9 @@ err_enable_device:
 static void __devexit intel_mid_dma_remove(struct pci_dev *pdev)
 {
        struct middma_device *device = pci_get_drvdata(pdev);
+
+       pm_runtime_get_noresume(&pdev->dev);
+       pm_runtime_forbid(&pdev->dev);
        middma_shutdown(pdev);
        pci_dev_put(pdev);
        kfree(device);
@@ -1385,13 +1387,20 @@ int dma_resume(struct pci_dev *pci)
 static int dma_runtime_suspend(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       return dma_suspend(pci_dev, PMSG_SUSPEND);
+       struct middma_device *device = pci_get_drvdata(pci_dev);
+
+       device->state = SUSPENDED;
+       return 0;
 }
 
 static int dma_runtime_resume(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       return dma_resume(pci_dev);
+       struct middma_device *device = pci_get_drvdata(pci_dev);
+
+       device->state = RUNNING;
+       iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
+       return 0;
 }
 
 static int dma_runtime_idle(struct device *dev)
index f4a51d4d0349f95800b84ff85839c0f6869036a1..5d65f8377971d697a0452988a59c5bb35639ba8e 100644 (file)
@@ -508,6 +508,7 @@ int ioat2_alloc_chan_resources(struct dma_chan *c)
        struct ioat_ring_ent **ring;
        u64 status;
        int order;
+       int i = 0;
 
        /* have we already been set up? */
        if (ioat->ring)
@@ -548,8 +549,11 @@ int ioat2_alloc_chan_resources(struct dma_chan *c)
        ioat2_start_null_desc(ioat);
 
        /* check that we got off the ground */
-       udelay(5);
-       status = ioat_chansts(chan);
+       do {
+               udelay(1);
+               status = ioat_chansts(chan);
+       } while (i++ < 20 && !is_ioat_active(status) && !is_ioat_idle(status));
+
        if (is_ioat_active(status) || is_ioat_idle(status)) {
                set_bit(IOAT_RUN, &chan->state);
                return 1 << ioat->alloc_order;
index c6b01f535b29bbf9f89eb607cc7fc30b5a9356ce..e03f811a83dd980e5aad9e2b25b0acdc291769f5 100644 (file)
@@ -619,7 +619,7 @@ iop_adma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dma_dest,
 
        if (unlikely(!len))
                return NULL;
-       BUG_ON(unlikely(len > IOP_ADMA_MAX_BYTE_COUNT));
+       BUG_ON(len > IOP_ADMA_MAX_BYTE_COUNT);
 
        dev_dbg(iop_chan->device->common.dev, "%s len: %u\n",
                __func__, len);
@@ -652,7 +652,7 @@ iop_adma_prep_dma_memset(struct dma_chan *chan, dma_addr_t dma_dest,
 
        if (unlikely(!len))
                return NULL;
-       BUG_ON(unlikely(len > IOP_ADMA_MAX_BYTE_COUNT));
+       BUG_ON(len > IOP_ADMA_MAX_BYTE_COUNT);
 
        dev_dbg(iop_chan->device->common.dev, "%s len: %u\n",
                __func__, len);
@@ -686,7 +686,7 @@ iop_adma_prep_dma_xor(struct dma_chan *chan, dma_addr_t dma_dest,
 
        if (unlikely(!len))
                return NULL;
-       BUG_ON(unlikely(len > IOP_ADMA_XOR_MAX_BYTE_COUNT));
+       BUG_ON(len > IOP_ADMA_XOR_MAX_BYTE_COUNT);
 
        dev_dbg(iop_chan->device->common.dev,
                "%s src_cnt: %d len: %u flags: %lx\n",
index a25f5f61e0e00becc22b5b5b4d8ce1e4ce6e31b8..954e334e01bbea5a5c028f445dd8551dd51dd718 100644 (file)
@@ -671,7 +671,7 @@ mv_xor_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
        if (unlikely(len < MV_XOR_MIN_BYTE_COUNT))
                return NULL;
 
-       BUG_ON(unlikely(len > MV_XOR_MAX_BYTE_COUNT));
+       BUG_ON(len > MV_XOR_MAX_BYTE_COUNT);
 
        spin_lock_bh(&mv_chan->lock);
        slot_cnt = mv_chan_memcpy_slot_count(len);
@@ -710,7 +710,7 @@ mv_xor_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
        if (unlikely(len < MV_XOR_MIN_BYTE_COUNT))
                return NULL;
 
-       BUG_ON(unlikely(len > MV_XOR_MAX_BYTE_COUNT));
+       BUG_ON(len > MV_XOR_MAX_BYTE_COUNT);
 
        spin_lock_bh(&mv_chan->lock);
        slot_cnt = mv_chan_memset_slot_count(len);
@@ -744,7 +744,7 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
        if (unlikely(len < MV_XOR_MIN_BYTE_COUNT))
                return NULL;
 
-       BUG_ON(unlikely(len > MV_XOR_MAX_BYTE_COUNT));
+       BUG_ON(len > MV_XOR_MAX_BYTE_COUNT);
 
        dev_dbg(mv_chan->device->common.dev,
                "%s src_cnt: %d len: dest %x %u flags: %ld\n",
index 8d8fef1480a93115ab17c51f6c97d0130b44b21d..ff5b38f9d45bc98249ddf2a648a5b338f63f3496 100644 (file)
@@ -77,10 +77,10 @@ struct pch_dma_regs {
        u32     dma_ctl0;
        u32     dma_ctl1;
        u32     dma_ctl2;
-       u32     reserved1;
+       u32     dma_ctl3;
        u32     dma_sts0;
        u32     dma_sts1;
-       u32     reserved2;
+       u32     dma_sts2;
        u32     reserved3;
        struct pch_dma_desc_regs desc[MAX_CHAN_NR];
 };
@@ -130,6 +130,7 @@ struct pch_dma {
 #define PCH_DMA_CTL0   0x00
 #define PCH_DMA_CTL1   0x04
 #define PCH_DMA_CTL2   0x08
+#define PCH_DMA_CTL3   0x0C
 #define PCH_DMA_STS0   0x10
 #define PCH_DMA_STS1   0x14
 
@@ -138,7 +139,8 @@ struct pch_dma {
 #define dma_writel(pd, name, val) \
        writel((val), (pd)->membase + PCH_DMA_##name)
 
-static inline struct pch_dma_desc *to_pd_desc(struct dma_async_tx_descriptor *txd)
+static inline
+struct pch_dma_desc *to_pd_desc(struct dma_async_tx_descriptor *txd)
 {
        return container_of(txd, struct pch_dma_desc, txd);
 }
@@ -163,13 +165,15 @@ static inline struct device *chan2parent(struct dma_chan *chan)
        return chan->dev->device.parent;
 }
 
-static inline struct pch_dma_desc *pdc_first_active(struct pch_dma_chan *pd_chan)
+static inline
+struct pch_dma_desc *pdc_first_active(struct pch_dma_chan *pd_chan)
 {
        return list_first_entry(&pd_chan->active_list,
                                struct pch_dma_desc, desc_node);
 }
 
-static inline struct pch_dma_desc *pdc_first_queued(struct pch_dma_chan *pd_chan)
+static inline
+struct pch_dma_desc *pdc_first_queued(struct pch_dma_chan *pd_chan)
 {
        return list_first_entry(&pd_chan->queue,
                                struct pch_dma_desc, desc_node);
@@ -199,16 +203,30 @@ static void pdc_set_dir(struct dma_chan *chan)
        struct pch_dma *pd = to_pd(chan->device);
        u32 val;
 
-       val = dma_readl(pd, CTL0);
+       if (chan->chan_id < 8) {
+               val = dma_readl(pd, CTL0);
 
-       if (pd_chan->dir == DMA_TO_DEVICE)
-               val |= 0x1 << (DMA_CTL0_BITS_PER_CH * chan->chan_id +
-                              DMA_CTL0_DIR_SHIFT_BITS);
-       else
-               val &= ~(0x1 << (DMA_CTL0_BITS_PER_CH * chan->chan_id +
-                                DMA_CTL0_DIR_SHIFT_BITS));
+               if (pd_chan->dir == DMA_TO_DEVICE)
+                       val |= 0x1 << (DMA_CTL0_BITS_PER_CH * chan->chan_id +
+                                      DMA_CTL0_DIR_SHIFT_BITS);
+               else
+                       val &= ~(0x1 << (DMA_CTL0_BITS_PER_CH * chan->chan_id +
+                                        DMA_CTL0_DIR_SHIFT_BITS));
+
+               dma_writel(pd, CTL0, val);
+       } else {
+               int ch = chan->chan_id - 8; /* ch8-->0 ch9-->1 ... ch11->3 */
+               val = dma_readl(pd, CTL3);
 
-       dma_writel(pd, CTL0, val);
+               if (pd_chan->dir == DMA_TO_DEVICE)
+                       val |= 0x1 << (DMA_CTL0_BITS_PER_CH * ch +
+                                      DMA_CTL0_DIR_SHIFT_BITS);
+               else
+                       val &= ~(0x1 << (DMA_CTL0_BITS_PER_CH * ch +
+                                        DMA_CTL0_DIR_SHIFT_BITS));
+
+               dma_writel(pd, CTL3, val);
+       }
 
        dev_dbg(chan2dev(chan), "pdc_set_dir: chan %d -> %x\n",
                chan->chan_id, val);
@@ -219,13 +237,26 @@ static void pdc_set_mode(struct dma_chan *chan, u32 mode)
        struct pch_dma *pd = to_pd(chan->device);
        u32 val;
 
-       val = dma_readl(pd, CTL0);
+       if (chan->chan_id < 8) {
+               val = dma_readl(pd, CTL0);
+
+               val &= ~(DMA_CTL0_MODE_MASK_BITS <<
+                       (DMA_CTL0_BITS_PER_CH * chan->chan_id));
+               val |= mode << (DMA_CTL0_BITS_PER_CH * chan->chan_id);
 
-       val &= ~(DMA_CTL0_MODE_MASK_BITS <<
-               (DMA_CTL0_BITS_PER_CH * chan->chan_id));
-       val |= mode << (DMA_CTL0_BITS_PER_CH * chan->chan_id);
+               dma_writel(pd, CTL0, val);
+       } else {
+               int ch = chan->chan_id - 8; /* ch8-->0 ch9-->1 ... ch11->3 */
+
+               val = dma_readl(pd, CTL3);
+
+               val &= ~(DMA_CTL0_MODE_MASK_BITS <<
+                       (DMA_CTL0_BITS_PER_CH * ch));
+               val |= mode << (DMA_CTL0_BITS_PER_CH * ch);
 
-       dma_writel(pd, CTL0, val);
+               dma_writel(pd, CTL3, val);
+
+       }
 
        dev_dbg(chan2dev(chan), "pdc_set_mode: chan %d -> %x\n",
                chan->chan_id, val);
@@ -251,9 +282,6 @@ static bool pdc_is_idle(struct pch_dma_chan *pd_chan)
 
 static void pdc_dostart(struct pch_dma_chan *pd_chan, struct pch_dma_desc* desc)
 {
-       struct pch_dma *pd = to_pd(pd_chan->chan.device);
-       u32 val;
-
        if (!pdc_is_idle(pd_chan)) {
                dev_err(chan2dev(&pd_chan->chan),
                        "BUG: Attempt to start non-idle channel\n");
@@ -279,10 +307,6 @@ static void pdc_dostart(struct pch_dma_chan *pd_chan, struct pch_dma_desc* desc)
                channel_writel(pd_chan, NEXT, desc->txd.phys);
                pdc_set_mode(&pd_chan->chan, DMA_CTL0_SG);
        }
-
-       val = dma_readl(pd, CTL2);
-       val |= 1 << (DMA_CTL2_START_SHIFT_BITS + pd_chan->chan.chan_id);
-       dma_writel(pd, CTL2, val);
 }
 
 static void pdc_chain_complete(struct pch_dma_chan *pd_chan,
@@ -403,7 +427,7 @@ static struct pch_dma_desc *pdc_desc_get(struct pch_dma_chan *pd_chan)
 {
        struct pch_dma_desc *desc, *_d;
        struct pch_dma_desc *ret = NULL;
-       int i;
+       int i = 0;
 
        spin_lock(&pd_chan->lock);
        list_for_each_entry_safe(desc, _d, &pd_chan->free_list, desc_node) {
@@ -478,7 +502,6 @@ static int pd_alloc_chan_resources(struct dma_chan *chan)
        spin_unlock_bh(&pd_chan->lock);
 
        pdc_enable_irq(chan, 1);
-       pdc_set_dir(chan);
 
        return pd_chan->descs_allocated;
 }
@@ -561,6 +584,9 @@ static struct dma_async_tx_descriptor *pd_prep_slave_sg(struct dma_chan *chan,
        else
                return NULL;
 
+       pd_chan->dir = direction;
+       pdc_set_dir(chan);
+
        for_each_sg(sgl, sg, sg_len, i) {
                desc = pdc_desc_get(pd_chan);
 
@@ -703,6 +729,7 @@ static void pch_dma_save_regs(struct pch_dma *pd)
        pd->regs.dma_ctl0 = dma_readl(pd, CTL0);
        pd->regs.dma_ctl1 = dma_readl(pd, CTL1);
        pd->regs.dma_ctl2 = dma_readl(pd, CTL2);
+       pd->regs.dma_ctl3 = dma_readl(pd, CTL3);
 
        list_for_each_entry_safe(chan, _c, &pd->dma.channels, device_node) {
                pd_chan = to_pd_chan(chan);
@@ -725,6 +752,7 @@ static void pch_dma_restore_regs(struct pch_dma *pd)
        dma_writel(pd, CTL0, pd->regs.dma_ctl0);
        dma_writel(pd, CTL1, pd->regs.dma_ctl1);
        dma_writel(pd, CTL2, pd->regs.dma_ctl2);
+       dma_writel(pd, CTL3, pd->regs.dma_ctl3);
 
        list_for_each_entry_safe(chan, _c, &pd->dma.channels, device_node) {
                pd_chan = to_pd_chan(chan);
@@ -850,8 +878,6 @@ static int __devinit pch_dma_probe(struct pci_dev *pdev,
 
                pd_chan->membase = &regs->desc[i];
 
-               pd_chan->dir = (i % 2) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-
                spin_lock_init(&pd_chan->lock);
 
                INIT_LIST_HEAD(&pd_chan->active_list);
@@ -929,13 +955,23 @@ static void __devexit pch_dma_remove(struct pci_dev *pdev)
 #define PCI_DEVICE_ID_ML7213_DMA1_8CH  0x8026
 #define PCI_DEVICE_ID_ML7213_DMA2_8CH  0x802B
 #define PCI_DEVICE_ID_ML7213_DMA3_4CH  0x8034
+#define PCI_DEVICE_ID_ML7213_DMA4_12CH 0x8032
+#define PCI_DEVICE_ID_ML7223_DMA1_4CH  0x800B
+#define PCI_DEVICE_ID_ML7223_DMA2_4CH  0x800E
+#define PCI_DEVICE_ID_ML7223_DMA3_4CH  0x8017
+#define PCI_DEVICE_ID_ML7223_DMA4_4CH  0x803B
 
-static const struct pci_device_id pch_dma_id_table[] = {
+DEFINE_PCI_DEVICE_TABLE(pch_dma_id_table) = {
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_EG20T_PCH_DMA_8CH), 8 },
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_EG20T_PCH_DMA_4CH), 4 },
        { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA1_8CH), 8}, /* UART Video */
        { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA2_8CH), 8}, /* PCMIF SPI */
        { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA3_4CH), 4}, /* FPGA */
+       { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA4_12CH), 12}, /* I2S */
+       { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_DMA1_4CH), 4}, /* UART */
+       { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_DMA2_4CH), 4}, /* Video SPI */
+       { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_DMA3_4CH), 4}, /* Security */
+       { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_DMA4_4CH), 4}, /* FPGA */
        { 0, },
 };
 
index 3b0247e74cc4871cb703938ef82f3146011d077f..fc457a7e8832dc8f29ed4055cc781369de4ef7aa 100644 (file)
@@ -2313,7 +2313,7 @@ static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_memcpy(
        if (unlikely(!len))
                return NULL;
 
-       BUG_ON(unlikely(len > PPC440SPE_ADMA_DMA_MAX_BYTE_COUNT));
+       BUG_ON(len > PPC440SPE_ADMA_DMA_MAX_BYTE_COUNT);
 
        spin_lock_bh(&ppc440spe_chan->lock);
 
@@ -2354,7 +2354,7 @@ static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_memset(
        if (unlikely(!len))
                return NULL;
 
-       BUG_ON(unlikely(len > PPC440SPE_ADMA_DMA_MAX_BYTE_COUNT));
+       BUG_ON(len > PPC440SPE_ADMA_DMA_MAX_BYTE_COUNT);
 
        spin_lock_bh(&ppc440spe_chan->lock);
 
@@ -2397,7 +2397,7 @@ static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_xor(
                                     dma_dest, dma_src, src_cnt));
        if (unlikely(!len))
                return NULL;
-       BUG_ON(unlikely(len > PPC440SPE_ADMA_XOR_MAX_BYTE_COUNT));
+       BUG_ON(len > PPC440SPE_ADMA_XOR_MAX_BYTE_COUNT);
 
        dev_dbg(ppc440spe_chan->device->common.dev,
                "ppc440spe adma%d: %s src_cnt: %d len: %u int_en: %d\n",
@@ -2887,7 +2887,7 @@ static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_pq(
        ADMA_LL_DBG(prep_dma_pq_dbg(ppc440spe_chan->device->id,
                                    dst, src, src_cnt));
        BUG_ON(!len);
-       BUG_ON(unlikely(len > PPC440SPE_ADMA_XOR_MAX_BYTE_COUNT));
+       BUG_ON(len > PPC440SPE_ADMA_XOR_MAX_BYTE_COUNT);
        BUG_ON(!src_cnt);
 
        if (src_cnt == 1 && dst[1] == src[0]) {
index dcc1b2139fffdbe5809857abfe124f2a0e984a75..02833004420151fac42fdbb07e6cebd86d29df70 100644 (file)
@@ -213,12 +213,17 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
                                                struct sh_dmae_device, common);
        struct sh_dmae_pdata *pdata = shdev->pdata;
        const struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->id];
-       u16 __iomem *addr = shdev->dmars + chan_pdata->dmars / sizeof(u16);
+       u16 __iomem *addr = shdev->dmars;
        int shift = chan_pdata->dmars_bit;
 
        if (dmae_is_busy(sh_chan))
                return -EBUSY;
 
+       /* in the case of a missing DMARS resource use first memory window */
+       if (!addr)
+               addr = (u16 __iomem *)shdev->chan_reg;
+       addr += chan_pdata->dmars / sizeof(u16);
+
        __raw_writew((__raw_readw(addr) & (0xff00 >> shift)) | (val << shift),
                     addr);
 
@@ -338,7 +343,7 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan)
 
                dmae_set_dmars(sh_chan, cfg->mid_rid);
                dmae_set_chcr(sh_chan, cfg->chcr);
-       } else if ((sh_dmae_readl(sh_chan, CHCR) & 0xf00) != 0x400) {
+       } else {
                dmae_init(sh_chan);
        }
 
@@ -1078,7 +1083,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
        unsigned long irqflags = IRQF_DISABLED,
                chan_flag[SH_DMAC_MAX_CHANNELS] = {};
        int errirq, chan_irq[SH_DMAC_MAX_CHANNELS];
-       int err, i, irq_cnt = 0, irqres = 0;
+       int err, i, irq_cnt = 0, irqres = 0, irq_cap = 0;
        struct sh_dmae_device *shdev;
        struct resource *chan, *dmars, *errirq_res, *chanirq_res;
 
@@ -1087,7 +1092,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
                return -ENODEV;
 
        chan = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       /* DMARS area is optional, if absent, this controller cannot do slave DMA */
+       /* DMARS area is optional */
        dmars = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        /*
         * IRQ resources:
@@ -1139,6 +1144,8 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
        /* platform data */
        shdev->pdata = pdata;
 
+       platform_set_drvdata(pdev, shdev);
+
        pm_runtime_enable(&pdev->dev);
        pm_runtime_get_sync(&pdev->dev);
 
@@ -1154,7 +1161,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
        INIT_LIST_HEAD(&shdev->common.channels);
 
        dma_cap_set(DMA_MEMCPY, shdev->common.cap_mask);
-       if (dmars)
+       if (pdata->slave && pdata->slave_num)
                dma_cap_set(DMA_SLAVE, shdev->common.cap_mask);
 
        shdev->common.device_alloc_chan_resources
@@ -1203,12 +1210,22 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
            !platform_get_resource(pdev, IORESOURCE_IRQ, 1)) {
                /* Special case - all multiplexed */
                for (; irq_cnt < pdata->channel_num; irq_cnt++) {
-                       chan_irq[irq_cnt] = chanirq_res->start;
-                       chan_flag[irq_cnt] = IRQF_SHARED;
+                       if (irq_cnt < SH_DMAC_MAX_CHANNELS) {
+                               chan_irq[irq_cnt] = chanirq_res->start;
+                               chan_flag[irq_cnt] = IRQF_SHARED;
+                       } else {
+                               irq_cap = 1;
+                               break;
+                       }
                }
        } else {
                do {
                        for (i = chanirq_res->start; i <= chanirq_res->end; i++) {
+                               if (irq_cnt >= SH_DMAC_MAX_CHANNELS) {
+                                       irq_cap = 1;
+                                       break;
+                               }
+
                                if ((errirq_res->flags & IORESOURCE_BITS) ==
                                    IORESOURCE_IRQ_SHAREABLE)
                                        chan_flag[irq_cnt] = IRQF_SHARED;
@@ -1219,31 +1236,36 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
                                        i, irq_cnt);
                                chan_irq[irq_cnt++] = i;
                        }
+
+                       if (irq_cnt >= SH_DMAC_MAX_CHANNELS)
+                               break;
+
                        chanirq_res = platform_get_resource(pdev,
                                                IORESOURCE_IRQ, ++irqres);
                } while (irq_cnt < pdata->channel_num && chanirq_res);
        }
 
-       if (irq_cnt < pdata->channel_num)
-               goto eirqres;
-
        /* Create DMA Channel */
-       for (i = 0; i < pdata->channel_num; i++) {
+       for (i = 0; i < irq_cnt; i++) {
                err = sh_dmae_chan_probe(shdev, i, chan_irq[i], chan_flag[i]);
                if (err)
                        goto chan_probe_err;
        }
 
+       if (irq_cap)
+               dev_notice(&pdev->dev, "Attempting to register %d DMA "
+                          "channels when a maximum of %d are supported.\n",
+                          pdata->channel_num, SH_DMAC_MAX_CHANNELS);
+
        pm_runtime_put(&pdev->dev);
 
-       platform_set_drvdata(pdev, shdev);
        dma_async_device_register(&shdev->common);
 
        return err;
 
 chan_probe_err:
        sh_dmae_chan_remove(shdev);
-eirqres:
+
 #if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
        free_irq(errirq, shdev);
 eirq_err:
@@ -1258,6 +1280,8 @@ rst_err:
 
        if (dmars)
                iounmap(shdev->dmars);
+
+       platform_set_drvdata(pdev, NULL);
 emapdmars:
        iounmap(shdev->chan_reg);
        synchronize_rcu();
@@ -1296,6 +1320,8 @@ static int __exit sh_dmae_remove(struct platform_device *pdev)
                iounmap(shdev->dmars);
        iounmap(shdev->chan_reg);
 
+       platform_set_drvdata(pdev, NULL);
+
        synchronize_rcu();
        kfree(shdev);
 
index 3f9d3cd065841d1e7845ef26b1ba8c1009f4a87a..5ae9fc512180c979deac5bbad5687b266778032a 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/list.h>
 
-#define SH_DMAC_MAX_CHANNELS 6
+#define SH_DMAC_MAX_CHANNELS 20
 #define SH_DMA_SLAVE_NUMBER 256
 #define SH_DMA_TCR_MAX 0x00FFFFFF      /* 16MB */
 
index 94ee15dd3aed7ca0c0dc55c0a06f4e12e7834097..8f222d4db7def301de14cf662988163d8a2b5bd0 100644 (file)
@@ -1829,7 +1829,7 @@ d40_get_dev_addr(struct d40_chan *chan, enum dma_data_direction direction)
 {
        struct stedma40_platform_data *plat = chan->base->plat_data;
        struct stedma40_chan_cfg *cfg = &chan->dma_cfg;
-       dma_addr_t addr;
+       dma_addr_t addr = 0;
 
        if (chan->runtime_addr)
                return chan->runtime_addr;
@@ -2962,4 +2962,4 @@ static int __init stedma40_init(void)
 {
        return platform_driver_probe(&d40_driver, d40_probe);
 }
-arch_initcall(stedma40_init);
+subsys_initcall(stedma40_init);
index d2c75feff7df32925bc668d01a41cc724a44c9d2..f69f90a61873819c7ff743f9afb93d80ed8c3116 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/slab.h>
 
 #include <linux/timb_dma.h>
@@ -685,7 +684,7 @@ static irqreturn_t td_irq(int irq, void *devid)
 
 static int __devinit td_probe(struct platform_device *pdev)
 {
-       struct timb_dma_platform_data *pdata = mfd_get_data(pdev);
+       struct timb_dma_platform_data *pdata = pdev->dev.platform_data;
        struct timb_dma *td;
        struct resource *iomem;
        int irq;
index cace0a7b707af37b394d0e34b00afb2d9968b251..e47e73bbbcc5585ca214b3486cc57ebaaff662c8 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/edac.h>
 #include "edac_core.h"
 
-#define AMD76X_REVISION        " Ver: 2.0.2 "  __DATE__
+#define AMD76X_REVISION        " Ver: 2.0.2"
 #define EDAC_MOD_STR   "amd76x_edac"
 
 #define amd76x_printk(level, fmt, arg...) \
index 35b78d04bbfa589682efcdc744a7e4db2300ccaa..ddd890052ce2c344673d09d31e24d8436cb47e92 100644 (file)
@@ -33,7 +33,7 @@
 #include "edac_module.h"
 #include "amd8111_edac.h"
 
-#define AMD8111_EDAC_REVISION  " Ver: 1.0.0 " __DATE__
+#define AMD8111_EDAC_REVISION  " Ver: 1.0.0"
 #define AMD8111_EDAC_MOD_STR   "amd8111_edac"
 
 #define PCI_DEVICE_ID_AMD_8111_PCI     0x7460
index b432d60c622a5bc52f951bde2983d0e325bea2b4..a5c680561c73f6ec33bbe73b0059d055d4f41574 100644 (file)
@@ -33,7 +33,7 @@
 #include "edac_module.h"
 #include "amd8131_edac.h"
 
-#define AMD8131_EDAC_REVISION  " Ver: 1.0.0 " __DATE__
+#define AMD8131_EDAC_REVISION  " Ver: 1.0.0"
 #define AMD8131_EDAC_MOD_STR   "amd8131_edac"
 
 /* Wrapper functions for accessing PCI configuration space */
index 837ad8f85b48e1197dfd4e3f72a7a4340dd432bb..a687a0d169624f9f22c82fe3047c83e143ce953d 100644 (file)
@@ -30,7 +30,7 @@
 #include "edac_core.h"
 #include "edac_module.h"
 
-#define CPC925_EDAC_REVISION   " Ver: 1.0.0 " __DATE__
+#define CPC925_EDAC_REVISION   " Ver: 1.0.0"
 #define CPC925_EDAC_MOD_STR    "cpc925_edac"
 
 #define cpc925_printk(level, fmt, arg...) \
index ec302d42658919ff0afcd782fed08c6dfba0bcce..1af531a11d21f9d0c638e13d6332f9c9092085e7 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/edac.h>
 #include "edac_core.h"
 
-#define E752X_REVISION " Ver: 2.0.2 " __DATE__
+#define E752X_REVISION " Ver: 2.0.2"
 #define EDAC_MOD_STR   "e752x_edac"
 
 static int report_non_memory_errors;
index 1731d7245816fdedf681d14a5b9290acdeb11a1f..6ffb6d23281f62f4046110b6109c68ff7dfdf630 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/edac.h>
 #include "edac_core.h"
 
-#define        E7XXX_REVISION " Ver: 2.0.2 " __DATE__
+#define        E7XXX_REVISION " Ver: 2.0.2"
 #define        EDAC_MOD_STR    "e7xxx_edac"
 
 #define e7xxx_printk(level, fmt, arg...) \
index eefa3501916b60c0da2a6df740b8413da3df136a..55b8278bb172f6feda52e225581b258b3404402a 100644 (file)
@@ -421,10 +421,6 @@ struct mem_ctl_info {
        u32 ce_count;           /* Total Correctable Errors for this MC */
        unsigned long start_time;       /* mci load start time (in jiffies) */
 
-       /* this stuff is for safe removal of mc devices from global list while
-        * NMI handlers may be traversing list
-        */
-       struct rcu_head rcu;
        struct completion complete;
 
        /* edac sysfs device control */
@@ -620,10 +616,6 @@ struct edac_device_ctl_info {
 
        unsigned long start_time;       /* edac_device load start time (jiffies) */
 
-       /* these are for safe removal of mc devices from global list while
-        * NMI handlers may be traversing list
-        */
-       struct rcu_head rcu;
        struct completion removal_complete;
 
        /* sysfs top name under 'edac' directory
@@ -722,10 +714,6 @@ struct edac_pci_ctl_info {
 
        unsigned long start_time;       /* edac_pci load start time (jiffies) */
 
-       /* these are for safe removal of devices from global list while
-        * NMI handlers may be traversing list
-        */
-       struct rcu_head rcu;
        struct completion complete;
 
        /* sysfs top name under 'edac' directory
index a7408cf86f37f5ece603052bd8956cae30269777..c3f67437afb666f489cf926d573501fb79c344a4 100644 (file)
@@ -345,31 +345,19 @@ fail1:
        return 1;
 }
 
-/*
- * complete_edac_device_list_del
- *
- *     callback function when reference count is zero
- */
-static void complete_edac_device_list_del(struct rcu_head *head)
-{
-       struct edac_device_ctl_info *edac_dev;
-
-       edac_dev = container_of(head, struct edac_device_ctl_info, rcu);
-       INIT_LIST_HEAD(&edac_dev->link);
-}
-
 /*
  * del_edac_device_from_global_list
- *
- *     remove the RCU, setup for a callback call,
- *     then wait for the callback to occur
  */
 static void del_edac_device_from_global_list(struct edac_device_ctl_info
                                                *edac_device)
 {
        list_del_rcu(&edac_device->link);
-       call_rcu(&edac_device->rcu, complete_edac_device_list_del);
-       rcu_barrier();
+
+       /* these are for safe removal of devices from global list while
+        * NMI handlers may be traversing list
+        */
+       synchronize_rcu();
+       INIT_LIST_HEAD(&edac_device->link);
 }
 
 /*
index 1d8056049072698361a2eeb83db0d0a5935964e0..d69144a090435cbfdd5d883e231475e649c666d8 100644 (file)
@@ -447,20 +447,16 @@ fail1:
        return 1;
 }
 
-static void complete_mc_list_del(struct rcu_head *head)
-{
-       struct mem_ctl_info *mci;
-
-       mci = container_of(head, struct mem_ctl_info, rcu);
-       INIT_LIST_HEAD(&mci->link);
-}
-
 static void del_mc_from_global_list(struct mem_ctl_info *mci)
 {
        atomic_dec(&edac_handlers);
        list_del_rcu(&mci->link);
-       call_rcu(&mci->rcu, complete_mc_list_del);
-       rcu_barrier();
+
+       /* these are for safe removal of devices from global list while
+        * NMI handlers may be traversing list
+        */
+       synchronize_rcu();
+       INIT_LIST_HEAD(&mci->link);
 }
 
 /**
index be4b075c30984c1b408246a306664c0a6bb626f0..5ddaa86d6a6e86ef8ed0671070168d7541cd7073 100644 (file)
@@ -15,7 +15,7 @@
 #include "edac_core.h"
 #include "edac_module.h"
 
-#define EDAC_VERSION "Ver: 2.1.0 " __DATE__
+#define EDAC_VERSION "Ver: 2.1.0"
 
 #ifdef CONFIG_EDAC_DEBUG
 /* Values of 0 to 4 will generate output */
index efb5d565078304c60ea096b84bf1ae2b9761e4a4..2b378207d571b6bbd2220ac4b7deb263537b34b4 100644 (file)
@@ -163,19 +163,6 @@ fail1:
        return 1;
 }
 
-/*
- * complete_edac_pci_list_del
- *
- *     RCU completion callback to indicate item is deleted
- */
-static void complete_edac_pci_list_del(struct rcu_head *head)
-{
-       struct edac_pci_ctl_info *pci;
-
-       pci = container_of(head, struct edac_pci_ctl_info, rcu);
-       INIT_LIST_HEAD(&pci->link);
-}
-
 /*
  * del_edac_pci_from_global_list
  *
@@ -184,8 +171,12 @@ static void complete_edac_pci_list_del(struct rcu_head *head)
 static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci)
 {
        list_del_rcu(&pci->link);
-       call_rcu(&pci->rcu, complete_edac_pci_list_del);
-       rcu_barrier();
+
+       /* these are for safe removal of devices from global list while
+        * NMI handlers may be traversing list
+        */
+       synchronize_rcu();
+       INIT_LIST_HEAD(&pci->link);
 }
 
 #if 0
index d41f9002da45d403eb8bc36ca5cc1dccaf477490..aa08497a075a70d1e33ee0de9dcdc9a64c9221ea 100644 (file)
@@ -101,6 +101,19 @@ struct i3200_priv {
 
 static int nr_channels;
 
+#ifndef readq
+static inline __u64 readq(const volatile void __iomem *addr)
+{
+       const volatile u32 __iomem *p = addr;
+       u32 low, high;
+
+       low = readl(p);
+       high = readl(p + 1);
+
+       return low + ((u64)high << 32);
+}
+#endif
+
 static int how_many_channels(struct pci_dev *pdev)
 {
        unsigned char capid0_8b; /* 8th byte of CAPID0 */
index 87f427c2ce5c56dd6b303eea470baa28b2799ace..4dc3ac25a42261946fe9b8fc6798464ffc104db1 100644 (file)
@@ -27,7 +27,7 @@
 /*
  * Alter this version for the I5000 module when modifications are made
  */
-#define I5000_REVISION    " Ver: 2.0.12 " __DATE__
+#define I5000_REVISION    " Ver: 2.0.12"
 #define EDAC_MOD_STR      "i5000_edac"
 
 #define i5000_printk(level, fmt, arg...) \
index 80a465efbae89e2739e493082a0494cfb11e4faf..74d6ec342afbf2e0f34c9d8fe808f3c8b0f6d9c5 100644 (file)
@@ -33,7 +33,7 @@
 /*
  * Alter this version for the I5400 module when modifications are made
  */
-#define I5400_REVISION    " Ver: 1.0.0 " __DATE__
+#define I5400_REVISION    " Ver: 1.0.0"
 
 #define EDAC_MOD_STR      "i5400_edac"
 
index 363cc1602944086a9bcbe6406ef1bbee0be209cb..a76fe8366b681d14cc2e6158fba49133525aeaa3 100644 (file)
@@ -31,7 +31,7 @@
 /*
  * Alter this version for the I7300 module when modifications are made
  */
-#define I7300_REVISION    " Ver: 1.0.0 " __DATE__
+#define I7300_REVISION    " Ver: 1.0.0"
 
 #define EDAC_MOD_STR      "i7300_edac"
 
index 465cbc25149fffab899997e3d133cacacd5bad5f..04f1e7ce02b196868d42253243d79d1044d9b7cc 100644 (file)
@@ -59,7 +59,7 @@ MODULE_PARM_DESC(use_pci_fixup, "Enable PCI fixup to seek for hidden devices");
 /*
  * Alter this version for the module when modifications are made
  */
-#define I7CORE_REVISION    " Ver: 1.0.0 " __DATE__
+#define I7CORE_REVISION    " Ver: 1.0.0"
 #define EDAC_MOD_STR      "i7core_edac"
 
 /*
index b8a95cf50718b8e6ef15f74a9c12d49b2b486568..931a057750491a80bcc300fea6efa13f8cf58703 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/edac.h>
 #include "edac_core.h"
 
-#define  I82860_REVISION " Ver: 2.0.2 " __DATE__
+#define  I82860_REVISION " Ver: 2.0.2"
 #define EDAC_MOD_STR   "i82860_edac"
 
 #define i82860_printk(level, fmt, arg...) \
index b2fd1e899142a15d0020f618e79f218e366a0676..33864c63c6840908a082121154f470daeeaf0344 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/edac.h>
 #include "edac_core.h"
 
-#define I82875P_REVISION       " Ver: 2.0.2 " __DATE__
+#define I82875P_REVISION       " Ver: 2.0.2"
 #define EDAC_MOD_STR           "i82875p_edac"
 
 #define i82875p_printk(level, fmt, arg...) \
index 92e65e7038e906b63769b441e170c38c510ecf97..a5da732fe5b2680be5a197a97e580619e9717b52 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/edac.h>
 #include "edac_core.h"
 
-#define I82975X_REVISION       " Ver: 1.0.0 " __DATE__
+#define I82975X_REVISION       " Ver: 1.0.0"
 #define EDAC_MOD_STR           "i82975x_edac"
 
 #define i82975x_printk(level, fmt, arg...) \
index cb24df839460cd59c988e07ca828d71f564a9ff3..932016f2cf06032a78f48297899a9a9c8b3c8eb2 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef _MPC85XX_EDAC_H_
 #define _MPC85XX_EDAC_H_
 
-#define MPC85XX_REVISION " Ver: 2.0.0 " __DATE__
+#define MPC85XX_REVISION " Ver: 2.0.0"
 #define EDAC_MOD_STR   "MPC85xx_edac"
 
 #define mpc85xx_printk(level, fmt, arg...) \
index e042e2daa8f42b99c6b40aa2c1af89b7f1f1aa47..c7f209c92a1a4e73d34ca0b86400a19bf527a4fb 100644 (file)
@@ -12,7 +12,7 @@
 #ifndef _MV64X60_EDAC_H_
 #define _MV64X60_EDAC_H_
 
-#define MV64x60_REVISION " Ver: 2.0.0 " __DATE__
+#define MV64x60_REVISION " Ver: 2.0.0"
 #define EDAC_MOD_STR   "MV64x60_edac"
 
 #define mv64x60_printk(level, fmt, arg...) \
index af8e7b1aa290a2e0d682de5d1aefb9e8808c23e1..0de7d8770891e5421a52f7a8732b66e09dd13423 100644 (file)
 #define EDAC_OPSTATE_UNKNOWN_STR       "unknown"
 
 #define PPC4XX_EDAC_MODULE_NAME                "ppc4xx_edac"
-#define PPC4XX_EDAC_MODULE_REVISION    "v1.0.0 " __DATE__
+#define PPC4XX_EDAC_MODULE_REVISION    "v1.0.0"
 
 #define PPC4XX_EDAC_MESSAGE_SIZE       256
 
index 678513738c331fbd1497d2c772aab9d0b3dcc143..b153674431f19c7f4674a03c000da279a62ee878 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/edac.h>
 #include "edac_core.h"
 
-#define R82600_REVISION        " Ver: 2.0.2 " __DATE__
+#define R82600_REVISION        " Ver: 2.0.2"
 #define EDAC_MOD_STR   "r82600_edac"
 
 #define r82600_printk(level, fmt, arg...) \
index f032e446fc11bb8a0c943e519b0987c8cdd02d01..bfe723266fd89bb84726d88cf15c206c020ee707 100644 (file)
@@ -108,7 +108,9 @@ done:
  */
 unsigned long __init find_ibft_region(unsigned long *sizep)
 {
+#ifdef CONFIG_ACPI
        int i;
+#endif
        ibft_addr = NULL;
 
 #ifdef CONFIG_ACPI
index d3b295305542a2b71e00f5cc97d7682557cef0c4..2967002a9f820b2894dd1f8f1110a47a9694e250 100644 (file)
@@ -1,5 +1,5 @@
 #
-# platform-neutral GPIO infrastructure and expanders
+# GPIO infrastructure and drivers
 #
 
 config ARCH_WANT_OPTIONAL_GPIOLIB
@@ -31,7 +31,7 @@ menuconfig GPIOLIB
        help
          This enables GPIO support through the generic GPIO library.
          You only need to enable this, if you also want to enable
-         one or more of the GPIO expansion card drivers below.
+         one or more of the GPIO drivers below.
 
          If unsure, say N.
 
@@ -63,24 +63,45 @@ config GPIO_SYSFS
          Kernel drivers may also request that a particular GPIO be
          exported to userspace; this can be useful when debugging.
 
-# put expanders in the right section, in alphabetical order
+# put drivers in the right section, in alphabetical order
 
 config GPIO_MAX730X
        tristate
 
-comment "Memory mapped GPIO expanders:"
+comment "Memory mapped GPIO drivers:"
+
+config GPIO_BASIC_MMIO_CORE
+       tristate
+       help
+         Provides core functionality for basic memory-mapped GPIO controllers.
 
 config GPIO_BASIC_MMIO
        tristate "Basic memory-mapped GPIO controllers support"
+       select GPIO_BASIC_MMIO_CORE
        help
          Say yes here to support basic memory-mapped GPIO controllers.
 
 config GPIO_IT8761E
        tristate "IT8761E GPIO support"
-       depends on GPIOLIB
        help
          Say yes here to support GPIO functionality of IT8761E super I/O chip.
 
+config GPIO_EXYNOS4
+       def_bool y
+       depends on CPU_EXYNOS4210
+
+config GPIO_PLAT_SAMSUNG
+       def_bool y
+       depends on SAMSUNG_GPIOLIB_4BIT
+
+config GPIO_S5PC100
+       def_bool y
+       depends on CPU_S5PC100
+
+config GPIO_S5PV210
+       def_bool y
+       depends on CPU_S5PV210
+
 config GPIO_PL061
        bool "PrimeCell PL061 GPIO support"
        depends on ARM_AMBA
@@ -101,7 +122,7 @@ config GPIO_VR41XX
 
 config GPIO_SCH
        tristate "Intel SCH/TunnelCreek GPIO"
-       depends on GPIOLIB && PCI && X86
+       depends on PCI && X86
        select MFD_CORE
        select LPC_SCH
        help
@@ -121,7 +142,7 @@ config GPIO_SCH
 
 config GPIO_VX855
        tristate "VIA VX855/VX875 GPIO"
-       depends on GPIOLIB && MFD_SUPPORT && PCI
+       depends on MFD_SUPPORT && PCI
        select MFD_CORE
        select MFD_VX855
        help
@@ -298,7 +319,7 @@ comment "PCI GPIO expanders:"
 
 config GPIO_CS5535
        tristate "AMD CS5535/CS5536 GPIO support"
-       depends on PCI && X86 && !CS5535_GPIO
+       depends on PCI && X86 && !CS5535_GPIO && MFD_CS5535
        help
          The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that
          can be used for quite a number of things.  The CS5535/6 is found on
@@ -329,13 +350,19 @@ config GPIO_LANGWELL
          Say Y here to support Intel Langwell/Penwell GPIO.
 
 config GPIO_PCH
-       tristate "PCH GPIO of Intel Topcliff"
+       tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7223 IOH GPIO"
        depends on PCI && X86
        help
          This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff
          which is an IOH(Input/Output Hub) for x86 embedded processor.
          This driver can access PCH GPIO device.
 
+         This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
+         Output Hub), ML7223.
+         ML7223 IOH is for MP(Media Phone) use.
+         ML7223 is companion chip for Intel Atom E6xx series.
+         ML7223 is completely compatible for Intel EG20T PCH.
+
 config GPIO_ML_IOH
        tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
        depends on PCI
@@ -347,13 +374,13 @@ config GPIO_ML_IOH
 
 config GPIO_TIMBERDALE
        bool "Support for timberdale GPIO IP"
-       depends on MFD_TIMBERDALE && GPIOLIB && HAS_IOMEM
+       depends on MFD_TIMBERDALE && HAS_IOMEM
        ---help---
        Add support for the GPIO IP in the timberdale FPGA.
 
 config GPIO_RDC321X
        tristate "RDC R-321x GPIO support"
-       depends on PCI && GPIOLIB
+       depends on PCI
        select MFD_SUPPORT
        select MFD_CORE
        select MFD_RDC321X
@@ -419,4 +446,11 @@ config AB8500_GPIO
        depends on AB8500_CORE && BROKEN
        help
          Select this to enable the AB8500 IC GPIO driver
+
+config GPIO_TPS65910
+       bool "TPS65910 GPIO"
+       depends on MFD_TPS65910
+       help
+         Select this option to enable GPIO driver for the TPS65910
+         chip family.
 endif
index becef5954356bdc6b126a5c8a1bbb208f1e6ee1f..b605f8ec6fbe0afc01e6c4604de67e6a85f98add 100644 (file)
@@ -1,8 +1,4 @@
-# generic gpio support: dedicated expander chips, etc
-#
-# NOTE: platform-specific GPIO drivers don't belong in the
-# drivers/gpio directory; put them with other platform setup
-# code, IRQ controllers, board init, etc.
+# generic gpio support: platform drivers, dedicated expander chips, etc
 
 ccflags-$(CONFIG_DEBUG_GPIO)   += -DDEBUG
 
@@ -10,7 +6,12 @@ obj-$(CONFIG_GPIOLIB)         += gpiolib.o
 
 obj-$(CONFIG_GPIO_ADP5520)     += adp5520-gpio.o
 obj-$(CONFIG_GPIO_ADP5588)     += adp5588-gpio.o
+obj-$(CONFIG_GPIO_BASIC_MMIO_CORE)     += basic_mmio_gpio.o
 obj-$(CONFIG_GPIO_BASIC_MMIO)  += basic_mmio_gpio.o
+obj-$(CONFIG_GPIO_EXYNOS4)     += gpio-exynos4.o
+obj-$(CONFIG_GPIO_PLAT_SAMSUNG)        += gpio-plat-samsung.o
+obj-$(CONFIG_GPIO_S5PC100)     += gpio-s5pc100.o
+obj-$(CONFIG_GPIO_S5PV210)     += gpio-s5pv210.o
 obj-$(CONFIG_GPIO_LANGWELL)    += langwell_gpio.o
 obj-$(CONFIG_GPIO_MAX730X)     += max730x.o
 obj-$(CONFIG_GPIO_MAX7300)     += max7300.o
@@ -19,6 +20,7 @@ obj-$(CONFIG_GPIO_MAX732X)    += max732x.o
 obj-$(CONFIG_GPIO_MC33880)     += mc33880.o
 obj-$(CONFIG_GPIO_MCP23S08)    += mcp23s08.o
 obj-$(CONFIG_GPIO_74X164)      += 74x164.o
+obj-$(CONFIG_ARCH_OMAP)         += gpio-omap.o
 obj-$(CONFIG_GPIO_PCA953X)     += pca953x.o
 obj-$(CONFIG_GPIO_PCF857X)     += pcf857x.o
 obj-$(CONFIG_GPIO_PCH)         += pch_gpio.o
@@ -37,9 +39,12 @@ obj-$(CONFIG_GPIO_WM831X)    += wm831x-gpio.o
 obj-$(CONFIG_GPIO_WM8350)      += wm8350-gpiolib.o
 obj-$(CONFIG_GPIO_WM8994)      += wm8994-gpio.o
 obj-$(CONFIG_GPIO_SCH)         += sch_gpio.o
+obj-$(CONFIG_MACH_U300)                += gpio-u300.o
+obj-$(CONFIG_PLAT_NOMADIK)     += gpio-nomadik.o
 obj-$(CONFIG_GPIO_RDC321X)     += rdc321x-gpio.o
 obj-$(CONFIG_GPIO_JANZ_TTL)    += janz-ttl.o
 obj-$(CONFIG_GPIO_SX150X)      += sx150x.o
 obj-$(CONFIG_GPIO_VX855)       += vx855_gpio.o
 obj-$(CONFIG_GPIO_ML_IOH)      += ml_ioh_gpio.o
 obj-$(CONFIG_AB8500_GPIO)       += ab8500-gpio.o
+obj-$(CONFIG_GPIO_TPS65910)    += tps65910-gpio.o
index 3addea65894e47969a56687dc2d9c1f2f95180eb..8152e9f516b0786d04d358c4921f50924431ca62 100644 (file)
@@ -45,6 +45,7 @@ o        `                     ~~~~\___/~~~~    ` controller in FPGA is ,.`
  */
 
 #include <linux/init.h>
+#include <linux/err.h>
 #include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -61,102 +62,101 @@ o        `                     ~~~~\___/~~~~    ` controller in FPGA is ,.`
 #include <linux/mod_devicetable.h>
 #include <linux/basic_mmio_gpio.h>
 
-struct bgpio_chip {
-       struct gpio_chip gc;
-       void __iomem *reg_dat;
-       void __iomem *reg_set;
-       void __iomem *reg_clr;
-
-       /* Number of bits (GPIOs): <register width> * 8. */
-       int bits;
-
-       /*
-        * Some GPIO controllers work with the big-endian bits notation,
-        * e.g. in a 8-bits register, GPIO7 is the least significant bit.
-        */
-       int big_endian_bits;
-
-       /*
-        * Used to lock bgpio_chip->data. Also, this is needed to keep
-        * shadowed and real data registers writes together.
-        */
-       spinlock_t lock;
-
-       /* Shadowed data register to clear/set bits safely. */
-       unsigned long data;
-};
+static void bgpio_write8(void __iomem *reg, unsigned long data)
+{
+       writeb(data, reg);
+}
 
-static struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc)
+static unsigned long bgpio_read8(void __iomem *reg)
 {
-       return container_of(gc, struct bgpio_chip, gc);
+       return readb(reg);
 }
 
-static unsigned long bgpio_in(struct bgpio_chip *bgc)
+static void bgpio_write16(void __iomem *reg, unsigned long data)
 {
-       switch (bgc->bits) {
-       case 8:
-               return __raw_readb(bgc->reg_dat);
-       case 16:
-               return __raw_readw(bgc->reg_dat);
-       case 32:
-               return __raw_readl(bgc->reg_dat);
-#if BITS_PER_LONG >= 64
-       case 64:
-               return __raw_readq(bgc->reg_dat);
-#endif
-       }
-       return -EINVAL;
+       writew(data, reg);
 }
 
-static void bgpio_out(struct bgpio_chip *bgc, void __iomem *reg,
-                     unsigned long data)
+static unsigned long bgpio_read16(void __iomem *reg)
 {
-       switch (bgc->bits) {
-       case 8:
-               __raw_writeb(data, reg);
-               return;
-       case 16:
-               __raw_writew(data, reg);
-               return;
-       case 32:
-               __raw_writel(data, reg);
-               return;
+       return readw(reg);
+}
+
+static void bgpio_write32(void __iomem *reg, unsigned long data)
+{
+       writel(data, reg);
+}
+
+static unsigned long bgpio_read32(void __iomem *reg)
+{
+       return readl(reg);
+}
+
 #if BITS_PER_LONG >= 64
-       case 64:
-               __raw_writeq(data, reg);
-               return;
-#endif
-       }
+static void bgpio_write64(void __iomem *reg, unsigned long data)
+{
+       writeq(data, reg);
 }
 
+static unsigned long bgpio_read64(void __iomem *reg)
+{
+       return readq(reg);
+}
+#endif /* BITS_PER_LONG >= 64 */
+
 static unsigned long bgpio_pin2mask(struct bgpio_chip *bgc, unsigned int pin)
 {
-       if (bgc->big_endian_bits)
-               return 1 << (bgc->bits - 1 - pin);
-       else
-               return 1 << pin;
+       return 1 << pin;
+}
+
+static unsigned long bgpio_pin2mask_be(struct bgpio_chip *bgc,
+                                      unsigned int pin)
+{
+       return 1 << (bgc->bits - 1 - pin);
 }
 
 static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
 {
        struct bgpio_chip *bgc = to_bgpio_chip(gc);
 
-       return bgpio_in(bgc) & bgpio_pin2mask(bgc, gpio);
+       return bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio);
 }
 
 static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
 {
        struct bgpio_chip *bgc = to_bgpio_chip(gc);
-       unsigned long mask = bgpio_pin2mask(bgc, gpio);
+       unsigned long mask = bgc->pin2mask(bgc, gpio);
        unsigned long flags;
 
-       if (bgc->reg_set) {
-               if (val)
-                       bgpio_out(bgc, bgc->reg_set, mask);
-               else
-                       bgpio_out(bgc, bgc->reg_clr, mask);
-               return;
-       }
+       spin_lock_irqsave(&bgc->lock, flags);
+
+       if (val)
+               bgc->data |= mask;
+       else
+               bgc->data &= ~mask;
+
+       bgc->write_reg(bgc->reg_dat, bgc->data);
+
+       spin_unlock_irqrestore(&bgc->lock, flags);
+}
+
+static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
+                                int val)
+{
+       struct bgpio_chip *bgc = to_bgpio_chip(gc);
+       unsigned long mask = bgc->pin2mask(bgc, gpio);
+
+       if (val)
+               bgc->write_reg(bgc->reg_set, mask);
+       else
+               bgc->write_reg(bgc->reg_clr, mask);
+}
+
+static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+       struct bgpio_chip *bgc = to_bgpio_chip(gc);
+       unsigned long mask = bgc->pin2mask(bgc, gpio);
+       unsigned long flags;
 
        spin_lock_irqsave(&bgc->lock, flags);
 
@@ -165,103 +165,352 @@ static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
        else
                bgc->data &= ~mask;
 
-       bgpio_out(bgc, bgc->reg_dat, bgc->data);
+       bgc->write_reg(bgc->reg_set, bgc->data);
 
        spin_unlock_irqrestore(&bgc->lock, flags);
 }
 
+static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+       return 0;
+}
+
+static int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio,
+                               int val)
+{
+       gc->set(gc, gpio, val);
+
+       return 0;
+}
+
 static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
 {
+       struct bgpio_chip *bgc = to_bgpio_chip(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&bgc->lock, flags);
+
+       bgc->dir &= ~bgc->pin2mask(bgc, gpio);
+       bgc->write_reg(bgc->reg_dir, bgc->dir);
+
+       spin_unlock_irqrestore(&bgc->lock, flags);
+
        return 0;
 }
 
 static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 {
-       bgpio_set(gc, gpio, val);
+       struct bgpio_chip *bgc = to_bgpio_chip(gc);
+       unsigned long flags;
+
+       gc->set(gc, gpio, val);
+
+       spin_lock_irqsave(&bgc->lock, flags);
+
+       bgc->dir |= bgc->pin2mask(bgc, gpio);
+       bgc->write_reg(bgc->reg_dir, bgc->dir);
+
+       spin_unlock_irqrestore(&bgc->lock, flags);
+
        return 0;
 }
 
-static int __devinit bgpio_probe(struct platform_device *pdev)
+static int bgpio_dir_in_inv(struct gpio_chip *gc, unsigned int gpio)
 {
-       const struct platform_device_id *platid = platform_get_device_id(pdev);
-       struct device *dev = &pdev->dev;
-       struct bgpio_pdata *pdata = dev_get_platdata(dev);
-       struct bgpio_chip *bgc;
-       struct resource *res_dat;
-       struct resource *res_set;
-       struct resource *res_clr;
-       resource_size_t dat_sz;
-       int bits;
-       int ret;
+       struct bgpio_chip *bgc = to_bgpio_chip(gc);
+       unsigned long flags;
 
-       res_dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
-       if (!res_dat)
-               return -EINVAL;
+       spin_lock_irqsave(&bgc->lock, flags);
 
-       dat_sz = resource_size(res_dat);
-       if (!is_power_of_2(dat_sz))
-               return -EINVAL;
+       bgc->dir |= bgc->pin2mask(bgc, gpio);
+       bgc->write_reg(bgc->reg_dir, bgc->dir);
+
+       spin_unlock_irqrestore(&bgc->lock, flags);
+
+       return 0;
+}
 
-       bits = dat_sz * 8;
-       if (bits > BITS_PER_LONG)
+static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+       struct bgpio_chip *bgc = to_bgpio_chip(gc);
+       unsigned long flags;
+
+       gc->set(gc, gpio, val);
+
+       spin_lock_irqsave(&bgc->lock, flags);
+
+       bgc->dir &= ~bgc->pin2mask(bgc, gpio);
+       bgc->write_reg(bgc->reg_dir, bgc->dir);
+
+       spin_unlock_irqrestore(&bgc->lock, flags);
+
+       return 0;
+}
+
+static int bgpio_setup_accessors(struct device *dev,
+                                struct bgpio_chip *bgc,
+                                bool be)
+{
+
+       switch (bgc->bits) {
+       case 8:
+               bgc->read_reg   = bgpio_read8;
+               bgc->write_reg  = bgpio_write8;
+               break;
+       case 16:
+               bgc->read_reg   = bgpio_read16;
+               bgc->write_reg  = bgpio_write16;
+               break;
+       case 32:
+               bgc->read_reg   = bgpio_read32;
+               bgc->write_reg  = bgpio_write32;
+               break;
+#if BITS_PER_LONG >= 64
+       case 64:
+               bgc->read_reg   = bgpio_read64;
+               bgc->write_reg  = bgpio_write64;
+               break;
+#endif /* BITS_PER_LONG >= 64 */
+       default:
+               dev_err(dev, "unsupported data width %u bits\n", bgc->bits);
                return -EINVAL;
+       }
 
-       bgc = devm_kzalloc(dev, sizeof(*bgc), GFP_KERNEL);
-       if (!bgc)
-               return -ENOMEM;
+       bgc->pin2mask = be ? bgpio_pin2mask_be : bgpio_pin2mask;
+
+       return 0;
+}
+
+/*
+ * Create the device and allocate the resources.  For setting GPIO's there are
+ * three supported configurations:
+ *
+ *     - single input/output register resource (named "dat").
+ *     - set/clear pair (named "set" and "clr").
+ *     - single output register resource and single input resource ("set" and
+ *     dat").
+ *
+ * For the single output register, this drives a 1 by setting a bit and a zero
+ * by clearing a bit.  For the set clr pair, this drives a 1 by setting a bit
+ * in the set register and clears it by setting a bit in the clear register.
+ * The configuration is detected by which resources are present.
+ *
+ * For setting the GPIO direction, there are three supported configurations:
+ *
+ *     - simple bidirection GPIO that requires no configuration.
+ *     - an output direction register (named "dirout") where a 1 bit
+ *     indicates the GPIO is an output.
+ *     - an input direction register (named "dirin") where a 1 bit indicates
+ *     the GPIO is an input.
+ */
+static int bgpio_setup_io(struct bgpio_chip *bgc,
+                         void __iomem *dat,
+                         void __iomem *set,
+                         void __iomem *clr)
+{
 
-       bgc->reg_dat = devm_ioremap(dev, res_dat->start, dat_sz);
+       bgc->reg_dat = dat;
        if (!bgc->reg_dat)
-               return -ENOMEM;
+               return -EINVAL;
+
+       if (set && clr) {
+               bgc->reg_set = set;
+               bgc->reg_clr = clr;
+               bgc->gc.set = bgpio_set_with_clear;
+       } else if (set && !clr) {
+               bgc->reg_set = set;
+               bgc->gc.set = bgpio_set_set;
+       } else {
+               bgc->gc.set = bgpio_set;
+       }
+
+       bgc->gc.get = bgpio_get;
+
+       return 0;
+}
 
-       res_set = platform_get_resource_byname(pdev, IORESOURCE_MEM, "set");
-       res_clr = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clr");
-       if (res_set && res_clr) {
-               if (resource_size(res_set) != resource_size(res_clr) ||
-                               resource_size(res_set) != dat_sz)
-                       return -EINVAL;
-
-               bgc->reg_set = devm_ioremap(dev, res_set->start, dat_sz);
-               bgc->reg_clr = devm_ioremap(dev, res_clr->start, dat_sz);
-               if (!bgc->reg_set || !bgc->reg_clr)
-                       return -ENOMEM;
-       } else if (res_set || res_clr) {
+static int bgpio_setup_direction(struct bgpio_chip *bgc,
+                                void __iomem *dirout,
+                                void __iomem *dirin)
+{
+       if (dirout && dirin) {
                return -EINVAL;
+       } else if (dirout) {
+               bgc->reg_dir = dirout;
+               bgc->gc.direction_output = bgpio_dir_out;
+               bgc->gc.direction_input = bgpio_dir_in;
+       } else if (dirin) {
+               bgc->reg_dir = dirin;
+               bgc->gc.direction_output = bgpio_dir_out_inv;
+               bgc->gc.direction_input = bgpio_dir_in_inv;
+       } else {
+               bgc->gc.direction_output = bgpio_simple_dir_out;
+               bgc->gc.direction_input = bgpio_simple_dir_in;
        }
 
-       spin_lock_init(&bgc->lock);
+       return 0;
+}
 
-       bgc->bits = bits;
-       bgc->big_endian_bits = !strcmp(platid->name, "basic-mmio-gpio-be");
-       bgc->data = bgpio_in(bgc);
+int __devexit bgpio_remove(struct bgpio_chip *bgc)
+{
+       int err = gpiochip_remove(&bgc->gc);
 
-       bgc->gc.ngpio = bits;
-       bgc->gc.direction_input = bgpio_dir_in;
-       bgc->gc.direction_output = bgpio_dir_out;
-       bgc->gc.get = bgpio_get;
-       bgc->gc.set = bgpio_set;
+       kfree(bgc);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(bgpio_remove);
+
+int __devinit bgpio_init(struct bgpio_chip *bgc,
+                        struct device *dev,
+                        unsigned long sz,
+                        void __iomem *dat,
+                        void __iomem *set,
+                        void __iomem *clr,
+                        void __iomem *dirout,
+                        void __iomem *dirin,
+                        bool big_endian)
+{
+       int ret;
+
+       if (!is_power_of_2(sz))
+               return -EINVAL;
+
+       bgc->bits = sz * 8;
+       if (bgc->bits > BITS_PER_LONG)
+               return -EINVAL;
+
+       spin_lock_init(&bgc->lock);
        bgc->gc.dev = dev;
        bgc->gc.label = dev_name(dev);
+       bgc->gc.base = -1;
+       bgc->gc.ngpio = bgc->bits;
 
-       if (pdata)
-               bgc->gc.base = pdata->base;
-       else
-               bgc->gc.base = -1;
+       ret = bgpio_setup_io(bgc, dat, set, clr);
+       if (ret)
+               return ret;
 
-       dev_set_drvdata(dev, bgc);
+       ret = bgpio_setup_accessors(dev, bgc, big_endian);
+       if (ret)
+               return ret;
 
-       ret = gpiochip_add(&bgc->gc);
+       ret = bgpio_setup_direction(bgc, dirout, dirin);
        if (ret)
-               dev_err(dev, "gpiochip_add() failed: %d\n", ret);
+               return ret;
+
+       bgc->data = bgc->read_reg(bgc->reg_dat);
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(bgpio_init);
+
+#ifdef CONFIG_GPIO_BASIC_MMIO
 
-static int __devexit bgpio_remove(struct platform_device *pdev)
+static void __iomem *bgpio_map(struct platform_device *pdev,
+                              const char *name,
+                              resource_size_t sane_sz,
+                              int *err)
 {
-       struct bgpio_chip *bgc = dev_get_drvdata(&pdev->dev);
+       struct device *dev = &pdev->dev;
+       struct resource *r;
+       resource_size_t start;
+       resource_size_t sz;
+       void __iomem *ret;
+
+       *err = 0;
+
+       r = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+       if (!r)
+               return NULL;
 
-       return gpiochip_remove(&bgc->gc);
+       sz = resource_size(r);
+       if (sz != sane_sz) {
+               *err = -EINVAL;
+               return NULL;
+       }
+
+       start = r->start;
+       if (!devm_request_mem_region(dev, start, sz, r->name)) {
+               *err = -EBUSY;
+               return NULL;
+       }
+
+       ret = devm_ioremap(dev, start, sz);
+       if (!ret) {
+               *err = -ENOMEM;
+               return NULL;
+       }
+
+       return ret;
+}
+
+static int __devinit bgpio_pdev_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *r;
+       void __iomem *dat;
+       void __iomem *set;
+       void __iomem *clr;
+       void __iomem *dirout;
+       void __iomem *dirin;
+       unsigned long sz;
+       bool be;
+       int err;
+       struct bgpio_chip *bgc;
+       struct bgpio_pdata *pdata = dev_get_platdata(dev);
+
+       r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
+       if (!r)
+               return -EINVAL;
+
+       sz = resource_size(r);
+
+       dat = bgpio_map(pdev, "dat", sz, &err);
+       if (!dat)
+               return err ? err : -EINVAL;
+
+       set = bgpio_map(pdev, "set", sz, &err);
+       if (err)
+               return err;
+
+       clr = bgpio_map(pdev, "clr", sz, &err);
+       if (err)
+               return err;
+
+       dirout = bgpio_map(pdev, "dirout", sz, &err);
+       if (err)
+               return err;
+
+       dirin = bgpio_map(pdev, "dirin", sz, &err);
+       if (err)
+               return err;
+
+       be = !strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be");
+
+       bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
+       if (!bgc)
+               return -ENOMEM;
+
+       err = bgpio_init(bgc, dev, sz, dat, set, clr, dirout, dirin, be);
+       if (err)
+               return err;
+
+       if (pdata) {
+               bgc->gc.base = pdata->base;
+               if (pdata->ngpio > 0)
+                       bgc->gc.ngpio = pdata->ngpio;
+       }
+
+       platform_set_drvdata(pdev, bgc);
+
+       return gpiochip_add(&bgc->gc);
+}
+
+static int __devexit bgpio_pdev_remove(struct platform_device *pdev)
+{
+       struct bgpio_chip *bgc = platform_get_drvdata(pdev);
+
+       return bgpio_remove(bgc);
 }
 
 static const struct platform_device_id bgpio_id_table[] = {
@@ -276,21 +525,23 @@ static struct platform_driver bgpio_driver = {
                .name = "basic-mmio-gpio",
        },
        .id_table = bgpio_id_table,
-       .probe = bgpio_probe,
-       .remove = __devexit_p(bgpio_remove),
+       .probe = bgpio_pdev_probe,
+       .remove = __devexit_p(bgpio_pdev_remove),
 };
 
-static int __init bgpio_init(void)
+static int __init bgpio_platform_init(void)
 {
        return platform_driver_register(&bgpio_driver);
 }
-module_init(bgpio_init);
+module_init(bgpio_platform_init);
 
-static void __exit bgpio_exit(void)
+static void __exit bgpio_platform_exit(void)
 {
        platform_driver_unregister(&bgpio_driver);
 }
-module_exit(bgpio_exit);
+module_exit(bgpio_platform_exit);
+
+#endif /* CONFIG_GPIO_BASIC_MMIO */
 
 MODULE_DESCRIPTION("Driver for basic memory-mapped GPIO controllers");
 MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");
similarity index 92%
rename from arch/arm/mach-exynos4/gpiolib.c
rename to drivers/gpio/gpio-exynos4.c
index d54ca6adb660be5c92a320c829a4361492ef226e..9029835112e7e0989321a346f95d89c3da63087d 100644 (file)
 #include <plat/gpio-cfg.h>
 #include <plat/gpio-cfg-helpers.h>
 
+int s3c_gpio_setpull_exynos4(struct s3c_gpio_chip *chip,
+                               unsigned int off, s3c_gpio_pull_t pull)
+{
+       if (pull == S3C_GPIO_PULL_UP)
+               pull = 3;
+
+       return s3c_gpio_setpull_updown(chip, off, pull);
+}
+
+s3c_gpio_pull_t s3c_gpio_getpull_exynos4(struct s3c_gpio_chip *chip,
+                                               unsigned int off)
+{
+       s3c_gpio_pull_t pull;
+
+       pull = s3c_gpio_getpull_updown(chip, off);
+       if (pull == 3)
+               pull = S3C_GPIO_PULL_UP;
+
+       return pull;
+}
+
 static struct s3c_gpio_cfg gpio_cfg = {
        .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
-       .set_pull       = s3c_gpio_setpull_updown,
-       .get_pull       = s3c_gpio_getpull_updown,
+       .set_pull       = s3c_gpio_setpull_exynos4,
+       .get_pull       = s3c_gpio_getpull_exynos4,
 };
 
 static struct s3c_gpio_cfg gpio_cfg_noint = {
        .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
-       .set_pull       = s3c_gpio_setpull_updown,
-       .get_pull       = s3c_gpio_getpull_updown,
+       .set_pull       = s3c_gpio_setpull_exynos4,
+       .get_pull       = s3c_gpio_getpull_exynos4,
 };
 
 /*
similarity index 89%
rename from arch/arm/plat-nomadik/gpio.c
rename to drivers/gpio/gpio-nomadik.c
index 307b8131aa8cce03e301bcf24ccfe6c093fc0d27..2c212c732d76e5e0996fb90a354f33e383ab7297 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2008,2009 STMicroelectronics
  * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
  *   Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com>
+ * Copyright (C) 2011 Linus Walleij <linus.walleij@linaro.org>
  *
  * 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
@@ -49,6 +50,7 @@ struct nmk_gpio_chip {
        u32 (*get_secondary_status)(unsigned int bank);
        void (*set_ioforce)(bool enable);
        spinlock_t lock;
+       bool sleepmode;
        /* Keep track of configured edges */
        u32 edge_rising;
        u32 edge_falling;
@@ -57,6 +59,7 @@ struct nmk_gpio_chip {
        u32 fwimsc;
        u32 slpm;
        u32 enabled;
+       u32 pull_up;
 };
 
 static struct nmk_gpio_chip *
@@ -103,16 +106,22 @@ static void __nmk_gpio_set_pull(struct nmk_gpio_chip *nmk_chip,
        u32 pdis;
 
        pdis = readl(nmk_chip->addr + NMK_GPIO_PDIS);
-       if (pull == NMK_GPIO_PULL_NONE)
+       if (pull == NMK_GPIO_PULL_NONE) {
                pdis |= bit;
-       else
+               nmk_chip->pull_up &= ~bit;
+       } else {
                pdis &= ~bit;
+       }
+
        writel(pdis, nmk_chip->addr + NMK_GPIO_PDIS);
 
-       if (pull == NMK_GPIO_PULL_UP)
+       if (pull == NMK_GPIO_PULL_UP) {
+               nmk_chip->pull_up |= bit;
                writel(bit, nmk_chip->addr + NMK_GPIO_DATS);
-       else if (pull == NMK_GPIO_PULL_DOWN)
+       } else if (pull == NMK_GPIO_PULL_DOWN) {
+               nmk_chip->pull_up &= ~bit;
                writel(bit, nmk_chip->addr + NMK_GPIO_DATC);
+       }
 }
 
 static void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip,
@@ -386,14 +395,25 @@ EXPORT_SYMBOL(nmk_config_pins_sleep);
  * @gpio: pin number
  * @mode: NMK_GPIO_SLPM_INPUT or NMK_GPIO_SLPM_NOCHANGE,
  *
- * Sets the sleep mode of a pin.  If @mode is NMK_GPIO_SLPM_INPUT, the pin is
- * changed to an input (with pullup/down enabled) in sleep and deep sleep.  If
- * @mode is NMK_GPIO_SLPM_NOCHANGE, the pin remains in the state it was
- * configured even when in sleep and deep sleep.
+ * This register is actually in the pinmux layer, not the GPIO block itself.
+ * The GPIO1B_SLPM register defines the GPIO mode when SLEEP/DEEP-SLEEP
+ * mode is entered (i.e. when signal IOFORCE is HIGH by the platform code).
+ * Each GPIO can be configured to be forced into GPIO mode when IOFORCE is
+ * HIGH, overriding the normal setting defined by GPIO_AFSELx registers.
+ * When IOFORCE returns LOW (by software, after SLEEP/DEEP-SLEEP exit),
+ * the GPIOs return to the normal setting defined by GPIO_AFSELx registers.
+ *
+ * If @mode is NMK_GPIO_SLPM_INPUT, the corresponding GPIO is switched to GPIO
+ * mode when signal IOFORCE is HIGH (i.e. when SLEEP/DEEP-SLEEP mode is
+ * entered) regardless of the altfunction selected. Also wake-up detection is
+ * ENABLED.
+ *
+ * If @mode is NMK_GPIO_SLPM_NOCHANGE, the corresponding GPIO remains
+ * controlled by NMK_GPIO_DATC, NMK_GPIO_DATS, NMK_GPIO_DIR, NMK_GPIO_PDIS
+ * (for altfunction GPIO) or respective on-chip peripherals (for other
+ * altfuncs) when IOFORCE is HIGH. Also wake-up detection DISABLED.
  *
- * On DB8500v2 onwards, this setting loses the previous meaning and instead
- * indicates if wakeup detection is enabled on the pin.  Note that
- * enable_irq_wake() will automatically enable wakeup detection.
+ * Note that enable_irq_wake() will automatically enable wakeup detection.
  */
 int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
 {
@@ -544,6 +564,12 @@ static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip,
 static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip,
                                int gpio, bool on)
 {
+       if (nmk_chip->sleepmode) {
+               __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base,
+                                   on ? NMK_GPIO_SLPM_WAKEUP_ENABLE
+                                   : NMK_GPIO_SLPM_WAKEUP_DISABLE);
+       }
+
        __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on);
 }
 
@@ -811,20 +837,43 @@ static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
                bool pull;
                u32 bit = 1 << i;
 
-               if (!label)
-                       continue;
-
                is_out = readl(nmk_chip->addr + NMK_GPIO_DIR) & bit;
                pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit);
                mode = nmk_gpio_get_mode(gpio);
                seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s",
-                       gpio, label,
+                       gpio, label ?: "(none)",
                        is_out ? "out" : "in ",
                        chip->get
                                ? (chip->get(chip, i) ? "hi" : "lo")
                                : "?  ",
                        (mode < 0) ? "unknown" : modes[mode],
                        pull ? "pull" : "none");
+
+               if (label && !is_out) {
+                       int             irq = gpio_to_irq(gpio);
+                       struct irq_desc *desc = irq_to_desc(irq);
+
+                       /* This races with request_irq(), set_irq_type(),
+                        * and set_irq_wake() ... but those are "rare".
+                        */
+                       if (irq >= 0 && desc->action) {
+                               char *trigger;
+                               u32 bitmask = nmk_gpio_get_bitmask(gpio);
+
+                               if (nmk_chip->edge_rising & bitmask)
+                                       trigger = "edge-rising";
+                               else if (nmk_chip->edge_falling & bitmask)
+                                       trigger = "edge-falling";
+                               else
+                                       trigger = "edge-undefined";
+
+                               seq_printf(s, " irq-%d %s%s",
+                                       irq, trigger,
+                                       irqd_is_wakeup_set(&desc->irq_data)
+                                               ? " wakeup" : "");
+                       }
+               }
+
                seq_printf(s, "\n");
        }
 }
@@ -871,7 +920,7 @@ void nmk_gpio_wakeups_suspend(void)
                writel(chip->fwimsc & chip->real_wake,
                       chip->addr + NMK_GPIO_FWIMSC);
 
-               if (cpu_is_u8500v2()) {
+               if (chip->sleepmode) {
                        chip->slpm = readl(chip->addr + NMK_GPIO_SLPC);
 
                        /* 0 -> wakeup enable */
@@ -893,11 +942,30 @@ void nmk_gpio_wakeups_resume(void)
                writel(chip->rwimsc, chip->addr + NMK_GPIO_RWIMSC);
                writel(chip->fwimsc, chip->addr + NMK_GPIO_FWIMSC);
 
-               if (cpu_is_u8500v2())
+               if (chip->sleepmode)
                        writel(chip->slpm, chip->addr + NMK_GPIO_SLPC);
        }
 }
 
+/*
+ * Read the pull up/pull down status.
+ * A bit set in 'pull_up' means that pull up
+ * is selected if pull is enabled in PDIS register.
+ * Note: only pull up/down set via this driver can
+ * be detected due to HW limitations.
+ */
+void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up)
+{
+       if (gpio_bank < NUM_BANKS) {
+               struct nmk_gpio_chip *chip = nmk_gpio_chips[gpio_bank];
+
+               if (!chip)
+                       return;
+
+               *pull_up = chip->pull_up;
+       }
+}
+
 static int __devinit nmk_gpio_probe(struct platform_device *dev)
 {
        struct nmk_gpio_platform_data *pdata = dev->dev.platform_data;
@@ -961,6 +1029,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
        nmk_chip->secondary_parent_irq = secondary_irq;
        nmk_chip->get_secondary_status = pdata->get_secondary_status;
        nmk_chip->set_ioforce = pdata->set_ioforce;
+       nmk_chip->sleepmode = pdata->supports_sleepmode;
        spin_lock_init(&nmk_chip->lock);
 
        chip = &nmk_chip->chip;
@@ -1016,5 +1085,3 @@ core_initcall(nmk_gpio_init);
 MODULE_AUTHOR("Prafulla WADASKAR and Alessandro Rubini");
 MODULE_DESCRIPTION("Nomadik GPIO Driver");
 MODULE_LICENSE("GPL");
-
-
similarity index 92%
rename from arch/arm/plat-omap/gpio.c
rename to drivers/gpio/gpio-omap.c
index efb86939019944d6da32b1edeafd7d2bf965e653..35bebde23e835c7674aaaa5e6bbf0e998ab0fd32 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/arm/plat-omap/gpio.c
- *
  * Support functions for OMAP GPIO
  *
  * Copyright (C) 2003-2005 Nokia Corporation
 #include <mach/gpio.h>
 #include <asm/mach/irq.h>
 
-/*
- * OMAP1510 GPIO registers
- */
-#define OMAP1510_GPIO_DATA_INPUT       0x00
-#define OMAP1510_GPIO_DATA_OUTPUT      0x04
-#define OMAP1510_GPIO_DIR_CONTROL      0x08
-#define OMAP1510_GPIO_INT_CONTROL      0x0c
-#define OMAP1510_GPIO_INT_MASK         0x10
-#define OMAP1510_GPIO_INT_STATUS       0x14
-#define OMAP1510_GPIO_PIN_CONTROL      0x18
-
-#define OMAP1510_IH_GPIO_BASE          64
-
-/*
- * OMAP1610 specific GPIO registers
- */
-#define OMAP1610_GPIO_REVISION         0x0000
-#define OMAP1610_GPIO_SYSCONFIG                0x0010
-#define OMAP1610_GPIO_SYSSTATUS                0x0014
-#define OMAP1610_GPIO_IRQSTATUS1       0x0018
-#define OMAP1610_GPIO_IRQENABLE1       0x001c
-#define OMAP1610_GPIO_WAKEUPENABLE     0x0028
-#define OMAP1610_GPIO_DATAIN           0x002c
-#define OMAP1610_GPIO_DATAOUT          0x0030
-#define OMAP1610_GPIO_DIRECTION                0x0034
-#define OMAP1610_GPIO_EDGE_CTRL1       0x0038
-#define OMAP1610_GPIO_EDGE_CTRL2       0x003c
-#define OMAP1610_GPIO_CLEAR_IRQENABLE1 0x009c
-#define OMAP1610_GPIO_CLEAR_WAKEUPENA  0x00a8
-#define OMAP1610_GPIO_CLEAR_DATAOUT    0x00b0
-#define OMAP1610_GPIO_SET_IRQENABLE1   0x00dc
-#define OMAP1610_GPIO_SET_WAKEUPENA    0x00e8
-#define OMAP1610_GPIO_SET_DATAOUT      0x00f0
-
-/*
- * OMAP7XX specific GPIO registers
- */
-#define OMAP7XX_GPIO_DATA_INPUT                0x00
-#define OMAP7XX_GPIO_DATA_OUTPUT       0x04
-#define OMAP7XX_GPIO_DIR_CONTROL       0x08
-#define OMAP7XX_GPIO_INT_CONTROL       0x0c
-#define OMAP7XX_GPIO_INT_MASK          0x10
-#define OMAP7XX_GPIO_INT_STATUS                0x14
-
-/*
- * omap2+ specific GPIO registers
- */
-#define OMAP24XX_GPIO_REVISION         0x0000
-#define OMAP24XX_GPIO_IRQSTATUS1       0x0018
-#define OMAP24XX_GPIO_IRQSTATUS2       0x0028
-#define OMAP24XX_GPIO_IRQENABLE2       0x002c
-#define OMAP24XX_GPIO_IRQENABLE1       0x001c
-#define OMAP24XX_GPIO_WAKE_EN          0x0020
-#define OMAP24XX_GPIO_CTRL             0x0030
-#define OMAP24XX_GPIO_OE               0x0034
-#define OMAP24XX_GPIO_DATAIN           0x0038
-#define OMAP24XX_GPIO_DATAOUT          0x003c
-#define OMAP24XX_GPIO_LEVELDETECT0     0x0040
-#define OMAP24XX_GPIO_LEVELDETECT1     0x0044
-#define OMAP24XX_GPIO_RISINGDETECT     0x0048
-#define OMAP24XX_GPIO_FALLINGDETECT    0x004c
-#define OMAP24XX_GPIO_DEBOUNCE_EN      0x0050
-#define OMAP24XX_GPIO_DEBOUNCE_VAL     0x0054
-#define OMAP24XX_GPIO_CLEARIRQENABLE1  0x0060
-#define OMAP24XX_GPIO_SETIRQENABLE1    0x0064
-#define OMAP24XX_GPIO_CLEARWKUENA      0x0080
-#define OMAP24XX_GPIO_SETWKUENA                0x0084
-#define OMAP24XX_GPIO_CLEARDATAOUT     0x0090
-#define OMAP24XX_GPIO_SETDATAOUT       0x0094
-
-#define OMAP4_GPIO_REVISION            0x0000
-#define OMAP4_GPIO_EOI                 0x0020
-#define OMAP4_GPIO_IRQSTATUSRAW0       0x0024
-#define OMAP4_GPIO_IRQSTATUSRAW1       0x0028
-#define OMAP4_GPIO_IRQSTATUS0          0x002c
-#define OMAP4_GPIO_IRQSTATUS1          0x0030
-#define OMAP4_GPIO_IRQSTATUSSET0       0x0034
-#define OMAP4_GPIO_IRQSTATUSSET1       0x0038
-#define OMAP4_GPIO_IRQSTATUSCLR0       0x003c
-#define OMAP4_GPIO_IRQSTATUSCLR1       0x0040
-#define OMAP4_GPIO_IRQWAKEN0           0x0044
-#define OMAP4_GPIO_IRQWAKEN1           0x0048
-#define OMAP4_GPIO_IRQENABLE1          0x011c
-#define OMAP4_GPIO_WAKE_EN             0x0120
-#define OMAP4_GPIO_IRQSTATUS2          0x0128
-#define OMAP4_GPIO_IRQENABLE2          0x012c
-#define OMAP4_GPIO_CTRL                        0x0130
-#define OMAP4_GPIO_OE                  0x0134
-#define OMAP4_GPIO_DATAIN              0x0138
-#define OMAP4_GPIO_DATAOUT             0x013c
-#define OMAP4_GPIO_LEVELDETECT0                0x0140
-#define OMAP4_GPIO_LEVELDETECT1                0x0144
-#define OMAP4_GPIO_RISINGDETECT                0x0148
-#define OMAP4_GPIO_FALLINGDETECT       0x014c
-#define OMAP4_GPIO_DEBOUNCENABLE       0x0150
-#define OMAP4_GPIO_DEBOUNCINGTIME      0x0154
-#define OMAP4_GPIO_CLEARIRQENABLE1     0x0160
-#define OMAP4_GPIO_SETIRQENABLE1       0x0164
-#define OMAP4_GPIO_CLEARWKUENA         0x0180
-#define OMAP4_GPIO_SETWKUENA           0x0184
-#define OMAP4_GPIO_CLEARDATAOUT                0x0190
-#define OMAP4_GPIO_SETDATAOUT          0x0194
-
 struct gpio_bank {
        unsigned long pbase;
        void __iomem *base;
@@ -537,7 +432,6 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
 {
        void __iomem *base = bank->base;
        u32 gpio_bit = 1 << gpio;
-       u32 val;
 
        if (cpu_is_omap44xx()) {
                MOD_REG_BIT(OMAP4_GPIO_LEVELDETECT0, gpio_bit,
@@ -560,15 +454,8 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
        }
        if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
                if (cpu_is_omap44xx()) {
-                       if (trigger != 0)
-                               __raw_writel(1 << gpio, bank->base+
-                                               OMAP4_GPIO_IRQWAKEN0);
-                       else {
-                               val = __raw_readl(bank->base +
-                                                       OMAP4_GPIO_IRQWAKEN0);
-                               __raw_writel(val & (~(1 << gpio)), bank->base +
-                                                        OMAP4_GPIO_IRQWAKEN0);
-                       }
+                       MOD_REG_BIT(OMAP4_GPIO_IRQWAKEN0, gpio_bit,
+                               trigger != 0);
                } else {
                        /*
                         * GPIO wakeup request can only be generated on edge
@@ -582,8 +469,9 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
                                        + OMAP24XX_GPIO_CLEARWKUENA);
                }
        }
-       /* This part needs to be executed always for OMAP34xx */
-       if (cpu_is_omap34xx() || (bank->non_wakeup_gpios & gpio_bit)) {
+       /* This part needs to be executed always for OMAP{34xx, 44xx} */
+       if (cpu_is_omap34xx() || cpu_is_omap44xx() ||
+                       (bank->non_wakeup_gpios & gpio_bit)) {
                /*
                 * Log the edge gpio and manually trigger the IRQ
                 * after resume if the input level changes
@@ -1239,8 +1127,11 @@ static void gpio_irq_shutdown(struct irq_data *d)
 {
        unsigned int gpio = d->irq - IH_GPIO_BASE;
        struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+       unsigned long flags;
 
+       spin_lock_irqsave(&bank->lock, flags);
        _reset_gpio(bank, gpio);
+       spin_unlock_irqrestore(&bank->lock, flags);
 }
 
 static void gpio_ack_irq(struct irq_data *d)
@@ -1255,9 +1146,12 @@ static void gpio_mask_irq(struct irq_data *d)
 {
        unsigned int gpio = d->irq - IH_GPIO_BASE;
        struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+       unsigned long flags;
 
+       spin_lock_irqsave(&bank->lock, flags);
        _set_gpio_irqenable(bank, gpio, 0);
        _set_gpio_triggering(bank, get_gpio_index(gpio), IRQ_TYPE_NONE);
+       spin_unlock_irqrestore(&bank->lock, flags);
 }
 
 static void gpio_unmask_irq(struct irq_data *d)
@@ -1266,7 +1160,9 @@ static void gpio_unmask_irq(struct irq_data *d)
        struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
        unsigned int irq_mask = 1 << get_gpio_index(gpio);
        u32 trigger = irqd_get_trigger_type(d);
+       unsigned long flags;
 
+       spin_lock_irqsave(&bank->lock, flags);
        if (trigger)
                _set_gpio_triggering(bank, get_gpio_index(gpio), trigger);
 
@@ -1278,6 +1174,7 @@ static void gpio_unmask_irq(struct irq_data *d)
        }
 
        _set_gpio_irqenable(bank, gpio, 1);
+       spin_unlock_irqrestore(&bank->lock, flags);
 }
 
 static struct irq_chip gpio_irq_chip = {
@@ -1629,7 +1526,7 @@ static void omap_gpio_mod_init(struct gpio_bank *bank, int id)
        }
 }
 
-static void __init omap_gpio_chip_init(struct gpio_bank *bank)
+static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)
 {
        int j;
        static int gpio;
index 36a2974815b70d4bb0346c7b14b6d84c2ac7accc..a971e3d043ba0535ed0539146b5530443cd8af17 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/idr.h>
 #include <linux/slab.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/gpio.h>
 
 /* Optional implementation infrastructure for GPIO interfaces.
  *
@@ -1165,6 +1167,7 @@ struct gpio_chip *gpiochip_find(void *data,
 
        return chip;
 }
+EXPORT_SYMBOL_GPL(gpiochip_find);
 
 /* These "optional" allocation calls help prevent drivers from stomping
  * on each other, and help provide better diagnostics in debugfs.
@@ -1293,7 +1296,7 @@ EXPORT_SYMBOL_GPL(gpio_request_one);
  * @array:     array of the 'struct gpio'
  * @num:       how many GPIOs in the array
  */
-int gpio_request_array(struct gpio *array, size_t num)
+int gpio_request_array(const struct gpio *array, size_t num)
 {
        int i, err;
 
@@ -1316,7 +1319,7 @@ EXPORT_SYMBOL_GPL(gpio_request_array);
  * @array:     array of the 'struct gpio'
  * @num:       how many GPIOs in the array
  */
-void gpio_free_array(struct gpio *array, size_t num)
+void gpio_free_array(const struct gpio *array, size_t num)
 {
        while (num--)
                gpio_free((array++)->gpio);
@@ -1404,6 +1407,8 @@ int gpio_direction_input(unsigned gpio)
        status = chip->direction_input(chip, gpio);
        if (status == 0)
                clear_bit(FLAG_IS_OUT, &desc->flags);
+
+       trace_gpio_direction(chip->base + gpio, 1, status);
 lose:
        return status;
 fail:
@@ -1457,6 +1462,8 @@ int gpio_direction_output(unsigned gpio, int value)
        status = chip->direction_output(chip, gpio, value);
        if (status == 0)
                set_bit(FLAG_IS_OUT, &desc->flags);
+       trace_gpio_value(chip->base + gpio, 0, value);
+       trace_gpio_direction(chip->base + gpio, 0, status);
 lose:
        return status;
 fail:
@@ -1546,10 +1553,13 @@ EXPORT_SYMBOL_GPL(gpio_set_debounce);
 int __gpio_get_value(unsigned gpio)
 {
        struct gpio_chip        *chip;
+       int value;
 
        chip = gpio_to_chip(gpio);
        WARN_ON(chip->can_sleep);
-       return chip->get ? chip->get(chip, gpio - chip->base) : 0;
+       value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
+       trace_gpio_value(gpio, 1, value);
+       return value;
 }
 EXPORT_SYMBOL_GPL(__gpio_get_value);
 
@@ -1568,6 +1578,7 @@ void __gpio_set_value(unsigned gpio, int value)
 
        chip = gpio_to_chip(gpio);
        WARN_ON(chip->can_sleep);
+       trace_gpio_value(gpio, 0, value);
        chip->set(chip, gpio - chip->base, value);
 }
 EXPORT_SYMBOL_GPL(__gpio_set_value);
@@ -1618,10 +1629,13 @@ EXPORT_SYMBOL_GPL(__gpio_to_irq);
 int gpio_get_value_cansleep(unsigned gpio)
 {
        struct gpio_chip        *chip;
+       int value;
 
        might_sleep_if(extra_checks);
        chip = gpio_to_chip(gpio);
-       return chip->get ? chip->get(chip, gpio - chip->base) : 0;
+       value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
+       trace_gpio_value(gpio, 1, value);
+       return value;
 }
 EXPORT_SYMBOL_GPL(gpio_get_value_cansleep);
 
@@ -1631,6 +1645,7 @@ void gpio_set_value_cansleep(unsigned gpio, int value)
 
        might_sleep_if(extra_checks);
        chip = gpio_to_chip(gpio);
+       trace_gpio_value(gpio, 0, value);
        chip->set(chip, gpio - chip->base, value);
 }
 EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
index 2514fb075f4afbdc1bb7a0ad62a9e3dff3bd9994..813ac077e5d7d5b0d25e465c53dcb10a023ef595 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
@@ -150,7 +149,7 @@ static int __devinit ttl_probe(struct platform_device *pdev)
        struct resource *res;
        int ret;
 
-       pdata = mfd_get_data(pdev);
+       pdata = pdev->dev.platform_data;
        if (!pdata) {
                dev_err(dev, "no platform data\n");
                ret = -ENXIO;
index 1b06f67e1f69b4f19f1318b1fbbe6b252e2a1df0..bd6571e0097a8be17b8fe3c27db173f3c8d9438b 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 
 /*
  * Langwell chip has 64 pins and thus there are 2 32bit registers to control
@@ -63,6 +64,7 @@ struct lnw_gpio {
        void                            *reg_base;
        spinlock_t                      lock;
        unsigned                        irq_base;
+       struct pci_dev                  *pdev;
 };
 
 static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
@@ -104,11 +106,18 @@ static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
        u32 value;
        unsigned long flags;
 
+       if (lnw->pdev)
+               pm_runtime_get(&lnw->pdev->dev);
+
        spin_lock_irqsave(&lnw->lock, flags);
        value = readl(gpdr);
        value &= ~BIT(offset % 32);
        writel(value, gpdr);
        spin_unlock_irqrestore(&lnw->lock, flags);
+
+       if (lnw->pdev)
+               pm_runtime_put(&lnw->pdev->dev);
+
        return 0;
 }
 
@@ -120,11 +129,19 @@ static int lnw_gpio_direction_output(struct gpio_chip *chip,
        unsigned long flags;
 
        lnw_gpio_set(chip, offset, value);
+
+       if (lnw->pdev)
+               pm_runtime_get(&lnw->pdev->dev);
+
        spin_lock_irqsave(&lnw->lock, flags);
        value = readl(gpdr);
        value |= BIT(offset % 32);
        writel(value, gpdr);
        spin_unlock_irqrestore(&lnw->lock, flags);
+
+       if (lnw->pdev)
+               pm_runtime_put(&lnw->pdev->dev);
+
        return 0;
 }
 
@@ -145,6 +162,10 @@ static int lnw_irq_type(struct irq_data *d, unsigned type)
 
        if (gpio >= lnw->chip.ngpio)
                return -EINVAL;
+
+       if (lnw->pdev)
+               pm_runtime_get(&lnw->pdev->dev);
+
        spin_lock_irqsave(&lnw->lock, flags);
        if (type & IRQ_TYPE_EDGE_RISING)
                value = readl(grer) | BIT(gpio % 32);
@@ -159,6 +180,9 @@ static int lnw_irq_type(struct irq_data *d, unsigned type)
        writel(value, gfer);
        spin_unlock_irqrestore(&lnw->lock, flags);
 
+       if (lnw->pdev)
+               pm_runtime_put(&lnw->pdev->dev);
+
        return 0;
 }
 
@@ -211,6 +235,39 @@ static void lnw_irq_handler(unsigned irq, struct irq_desc *desc)
        chip->irq_eoi(data);
 }
 
+#ifdef CONFIG_PM
+static int lnw_gpio_runtime_resume(struct device *dev)
+{
+       return 0;
+}
+
+static int lnw_gpio_runtime_suspend(struct device *dev)
+{
+       return 0;
+}
+
+static int lnw_gpio_runtime_idle(struct device *dev)
+{
+       int err = pm_schedule_suspend(dev, 500);
+
+       if (!err)
+               return 0;
+
+       return -EBUSY;
+}
+
+#else
+#define lnw_gpio_runtime_suspend       NULL
+#define lnw_gpio_runtime_resume                NULL
+#define lnw_gpio_runtime_idle          NULL
+#endif
+
+static const struct dev_pm_ops lnw_gpio_pm_ops = {
+       .runtime_suspend = lnw_gpio_runtime_suspend,
+       .runtime_resume = lnw_gpio_runtime_resume,
+       .runtime_idle = lnw_gpio_runtime_idle,
+};
+
 static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
                        const struct pci_device_id *id)
 {
@@ -270,6 +327,7 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
        lnw->chip.base = gpio_base;
        lnw->chip.ngpio = id->driver_data;
        lnw->chip.can_sleep = 0;
+       lnw->pdev = pdev;
        pci_set_drvdata(pdev, lnw);
        retval = gpiochip_add(&lnw->chip);
        if (retval) {
@@ -285,6 +343,10 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
        }
 
        spin_lock_init(&lnw->lock);
+
+       pm_runtime_put_noidle(&pdev->dev);
+       pm_runtime_allow(&pdev->dev);
+
        goto done;
 err5:
        kfree(lnw);
@@ -302,6 +364,9 @@ static struct pci_driver lnw_gpio_driver = {
        .name           = "langwell_gpio",
        .id_table       = lnw_gpio_ids,
        .probe          = lnw_gpio_probe,
+       .driver         = {
+               .pm     = &lnw_gpio_pm_ops,
+       },
 };
 
 
index 0a775f7987c257237943879a1d08e5ac20f3cd14..1bc621ac35364917be287773d081a2801f12a5be 100644 (file)
@@ -15,6 +15,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  */
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/gpio.h>
 
@@ -138,6 +139,7 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
        return 0;
 }
 
+#ifdef CONFIG_PM
 /*
  * Save register configuration and disable interrupts.
  */
@@ -157,6 +159,7 @@ static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip)
        /* to store contents of PM register */
        iowrite32(chip->ioh_gpio_reg.pm_reg, &chip->reg->regs[chip->ch].pm);
 }
+#endif
 
 static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port)
 {
index 7630ab7b9bec30cdad9628908d74813075413b65..0451d7ac94ac1d51b062d0da4ce19e4e12b6bdf4 100644 (file)
 #include <linux/of_gpio.h>
 #endif
 
-#define PCA953X_INPUT          0
-#define PCA953X_OUTPUT         1
-#define PCA953X_INVERT         2
-#define PCA953X_DIRECTION      3
-
-#define PCA953X_GPIOS         0x00FF
-#define PCA953X_INT           0x0100
+#define PCA953X_INPUT          0
+#define PCA953X_OUTPUT         1
+#define PCA953X_INVERT         2
+#define PCA953X_DIRECTION      3
+
+#define PCA957X_IN             0
+#define PCA957X_INVRT          1
+#define PCA957X_BKEN           2
+#define PCA957X_PUPD           3
+#define PCA957X_CFG            4
+#define PCA957X_OUT            5
+#define PCA957X_MSK            6
+#define PCA957X_INTS           7
+
+#define PCA_GPIO_MASK          0x00FF
+#define PCA_INT                        0x0100
+#define PCA953X_TYPE           0x1000
+#define PCA957X_TYPE           0x2000
 
 static const struct i2c_device_id pca953x_id[] = {
-       { "pca9534", 8  | PCA953X_INT, },
-       { "pca9535", 16 | PCA953X_INT, },
-       { "pca9536", 4, },
-       { "pca9537", 4  | PCA953X_INT, },
-       { "pca9538", 8  | PCA953X_INT, },
-       { "pca9539", 16 | PCA953X_INT, },
-       { "pca9554", 8  | PCA953X_INT, },
-       { "pca9555", 16 | PCA953X_INT, },
-       { "pca9556", 8, },
-       { "pca9557", 8, },
-
-       { "max7310", 8, },
-       { "max7312", 16 | PCA953X_INT, },
-       { "max7313", 16 | PCA953X_INT, },
-       { "max7315", 8  | PCA953X_INT, },
-       { "pca6107", 8  | PCA953X_INT, },
-       { "tca6408", 8  | PCA953X_INT, },
-       { "tca6416", 16 | PCA953X_INT, },
+       { "pca9534", 8  | PCA953X_TYPE | PCA_INT, },
+       { "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
+       { "pca9536", 4  | PCA953X_TYPE, },
+       { "pca9537", 4  | PCA953X_TYPE | PCA_INT, },
+       { "pca9538", 8  | PCA953X_TYPE | PCA_INT, },
+       { "pca9539", 16 | PCA953X_TYPE | PCA_INT, },
+       { "pca9554", 8  | PCA953X_TYPE | PCA_INT, },
+       { "pca9555", 16 | PCA953X_TYPE | PCA_INT, },
+       { "pca9556", 8  | PCA953X_TYPE, },
+       { "pca9557", 8  | PCA953X_TYPE, },
+       { "pca9574", 8  | PCA957X_TYPE | PCA_INT, },
+       { "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
+
+       { "max7310", 8  | PCA953X_TYPE, },
+       { "max7312", 16 | PCA953X_TYPE | PCA_INT, },
+       { "max7313", 16 | PCA953X_TYPE | PCA_INT, },
+       { "max7315", 8  | PCA953X_TYPE | PCA_INT, },
+       { "pca6107", 8  | PCA953X_TYPE | PCA_INT, },
+       { "tca6408", 8  | PCA953X_TYPE | PCA_INT, },
+       { "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
        /* NYET:  { "tca6424", 24, }, */
        { }
 };
@@ -75,16 +88,32 @@ struct pca953x_chip {
        struct pca953x_platform_data *dyn_pdata;
        struct gpio_chip gpio_chip;
        const char *const *names;
+       int     chip_type;
 };
 
 static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val)
 {
-       int ret;
+       int ret = 0;
 
        if (chip->gpio_chip.ngpio <= 8)
                ret = i2c_smbus_write_byte_data(chip->client, reg, val);
-       else
-               ret = i2c_smbus_write_word_data(chip->client, reg << 1, val);
+       else {
+               switch (chip->chip_type) {
+               case PCA953X_TYPE:
+                       ret = i2c_smbus_write_word_data(chip->client,
+                                                       reg << 1, val);
+                       break;
+               case PCA957X_TYPE:
+                       ret = i2c_smbus_write_byte_data(chip->client, reg << 1,
+                                                       val & 0xff);
+                       if (ret < 0)
+                               break;
+                       ret = i2c_smbus_write_byte_data(chip->client,
+                                                       (reg << 1) + 1,
+                                                       (val & 0xff00) >> 8);
+                       break;
+               }
+       }
 
        if (ret < 0) {
                dev_err(&chip->client->dev, "failed writing register\n");
@@ -116,13 +145,22 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
 {
        struct pca953x_chip *chip;
        uint16_t reg_val;
-       int ret;
+       int ret, offset = 0;
 
        chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
        mutex_lock(&chip->i2c_lock);
        reg_val = chip->reg_direction | (1u << off);
-       ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
+
+       switch (chip->chip_type) {
+       case PCA953X_TYPE:
+               offset = PCA953X_DIRECTION;
+               break;
+       case PCA957X_TYPE:
+               offset = PCA957X_CFG;
+               break;
+       }
+       ret = pca953x_write_reg(chip, offset, reg_val);
        if (ret)
                goto exit;
 
@@ -138,7 +176,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 {
        struct pca953x_chip *chip;
        uint16_t reg_val;
-       int ret;
+       int ret, offset = 0;
 
        chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
@@ -149,7 +187,15 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
        else
                reg_val = chip->reg_output & ~(1u << off);
 
-       ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
+       switch (chip->chip_type) {
+       case PCA953X_TYPE:
+               offset = PCA953X_OUTPUT;
+               break;
+       case PCA957X_TYPE:
+               offset = PCA957X_OUT;
+               break;
+       }
+       ret = pca953x_write_reg(chip, offset, reg_val);
        if (ret)
                goto exit;
 
@@ -157,7 +203,15 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 
        /* then direction */
        reg_val = chip->reg_direction & ~(1u << off);
-       ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
+       switch (chip->chip_type) {
+       case PCA953X_TYPE:
+               offset = PCA953X_DIRECTION;
+               break;
+       case PCA957X_TYPE:
+               offset = PCA957X_CFG;
+               break;
+       }
+       ret = pca953x_write_reg(chip, offset, reg_val);
        if (ret)
                goto exit;
 
@@ -172,12 +226,20 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
 {
        struct pca953x_chip *chip;
        uint16_t reg_val;
-       int ret;
+       int ret, offset = 0;
 
        chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
        mutex_lock(&chip->i2c_lock);
-       ret = pca953x_read_reg(chip, PCA953X_INPUT, &reg_val);
+       switch (chip->chip_type) {
+       case PCA953X_TYPE:
+               offset = PCA953X_INPUT;
+               break;
+       case PCA957X_TYPE:
+               offset = PCA957X_IN;
+               break;
+       }
+       ret = pca953x_read_reg(chip, offset, &reg_val);
        mutex_unlock(&chip->i2c_lock);
        if (ret < 0) {
                /* NOTE:  diagnostic already emitted; that's all we should
@@ -194,7 +256,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
 {
        struct pca953x_chip *chip;
        uint16_t reg_val;
-       int ret;
+       int ret, offset = 0;
 
        chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
@@ -204,7 +266,15 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
        else
                reg_val = chip->reg_output & ~(1u << off);
 
-       ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
+       switch (chip->chip_type) {
+       case PCA953X_TYPE:
+               offset = PCA953X_OUTPUT;
+               break;
+       case PCA957X_TYPE:
+               offset = PCA957X_OUT;
+               break;
+       }
+       ret = pca953x_write_reg(chip, offset, reg_val);
        if (ret)
                goto exit;
 
@@ -322,9 +392,17 @@ static uint16_t pca953x_irq_pending(struct pca953x_chip *chip)
        uint16_t old_stat;
        uint16_t pending;
        uint16_t trigger;
-       int ret;
-
-       ret = pca953x_read_reg(chip, PCA953X_INPUT, &cur_stat);
+       int ret, offset = 0;
+
+       switch (chip->chip_type) {
+       case PCA953X_TYPE:
+               offset = PCA953X_INPUT;
+               break;
+       case PCA957X_TYPE:
+               offset = PCA957X_IN;
+               break;
+       }
+       ret = pca953x_read_reg(chip, offset, &cur_stat);
        if (ret)
                return 0;
 
@@ -372,14 +450,21 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 {
        struct i2c_client *client = chip->client;
        struct pca953x_platform_data *pdata = client->dev.platform_data;
-       int ret;
+       int ret, offset = 0;
 
        if (pdata->irq_base != -1
-                       && (id->driver_data & PCA953X_INT)) {
+                       && (id->driver_data & PCA_INT)) {
                int lvl;
 
-               ret = pca953x_read_reg(chip, PCA953X_INPUT,
-                                      &chip->irq_stat);
+               switch (chip->chip_type) {
+               case PCA953X_TYPE:
+                       offset = PCA953X_INPUT;
+                       break;
+               case PCA957X_TYPE:
+                       offset = PCA957X_IN;
+                       break;
+               }
+               ret = pca953x_read_reg(chip, offset, &chip->irq_stat);
                if (ret)
                        goto out_failed;
 
@@ -397,7 +482,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 
                        irq_set_chip_data(irq, chip);
                        irq_set_chip_and_handler(irq, &pca953x_irq_chip,
-                                                handle_edge_irq);
+                                                handle_simple_irq);
 #ifdef CONFIG_ARM
                        set_irq_flags(irq, IRQF_VALID);
 #else
@@ -439,7 +524,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
        struct i2c_client *client = chip->client;
        struct pca953x_platform_data *pdata = client->dev.platform_data;
 
-       if (pdata->irq_base != -1 && (id->driver_data & PCA953X_INT))
+       if (pdata->irq_base != -1 && (id->driver_data & PCA_INT))
                dev_warn(&client->dev, "interrupt support not compiled in\n");
 
        return 0;
@@ -499,12 +584,65 @@ pca953x_get_alt_pdata(struct i2c_client *client)
 }
 #endif
 
+static int __devinit device_pca953x_init(struct pca953x_chip *chip, int invert)
+{
+       int ret;
+
+       ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
+       if (ret)
+               goto out;
+
+       ret = pca953x_read_reg(chip, PCA953X_DIRECTION,
+                              &chip->reg_direction);
+       if (ret)
+               goto out;
+
+       /* set platform specific polarity inversion */
+       ret = pca953x_write_reg(chip, PCA953X_INVERT, invert);
+       if (ret)
+               goto out;
+       return 0;
+out:
+       return ret;
+}
+
+static int __devinit device_pca957x_init(struct pca953x_chip *chip, int invert)
+{
+       int ret;
+       uint16_t val = 0;
+
+       /* Let every port in proper state, that could save power */
+       pca953x_write_reg(chip, PCA957X_PUPD, 0x0);
+       pca953x_write_reg(chip, PCA957X_CFG, 0xffff);
+       pca953x_write_reg(chip, PCA957X_OUT, 0x0);
+
+       ret = pca953x_read_reg(chip, PCA957X_IN, &val);
+       if (ret)
+               goto out;
+       ret = pca953x_read_reg(chip, PCA957X_OUT, &chip->reg_output);
+       if (ret)
+               goto out;
+       ret = pca953x_read_reg(chip, PCA957X_CFG, &chip->reg_direction);
+       if (ret)
+               goto out;
+
+       /* set platform specific polarity inversion */
+       pca953x_write_reg(chip, PCA957X_INVRT, invert);
+
+       /* To enable register 6, 7 to controll pull up and pull down */
+       pca953x_write_reg(chip, PCA957X_BKEN, 0x202);
+
+       return 0;
+out:
+       return ret;
+}
+
 static int __devinit pca953x_probe(struct i2c_client *client,
                                   const struct i2c_device_id *id)
 {
        struct pca953x_platform_data *pdata;
        struct pca953x_chip *chip;
-       int ret;
+       int ret = 0;
 
        chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
        if (chip == NULL)
@@ -531,25 +669,20 @@ static int __devinit pca953x_probe(struct i2c_client *client,
        chip->gpio_start = pdata->gpio_base;
 
        chip->names = pdata->names;
+       chip->chip_type = id->driver_data & (PCA953X_TYPE | PCA957X_TYPE);
 
        mutex_init(&chip->i2c_lock);
 
        /* initialize cached registers from their original values.
         * we can't share this chip with another i2c master.
         */
-       pca953x_setup_gpio(chip, id->driver_data & PCA953X_GPIOS);
+       pca953x_setup_gpio(chip, id->driver_data & PCA_GPIO_MASK);
 
-       ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
-       if (ret)
-               goto out_failed;
-
-       ret = pca953x_read_reg(chip, PCA953X_DIRECTION, &chip->reg_direction);
-       if (ret)
-               goto out_failed;
-
-       /* set platform specific polarity inversion */
-       ret = pca953x_write_reg(chip, PCA953X_INVERT, pdata->invert);
-       if (ret)
+       if (chip->chip_type == PCA953X_TYPE)
+               device_pca953x_init(chip, pdata->invert);
+       else if (chip->chip_type == PCA957X_TYPE)
+               device_pca957x_init(chip, pdata->invert);
+       else
                goto out_failed;
 
        ret = pca953x_irq_setup(chip, id);
index f970a5f3585e03b5395b74f32f6103d21a67128d..36919e77c495cb97c3ae3a5896a6d7dabdce38df 100644 (file)
@@ -283,8 +283,10 @@ static int pch_gpio_resume(struct pci_dev *pdev)
 #define pch_gpio_resume NULL
 #endif
 
+#define PCI_VENDOR_ID_ROHM             0x10DB
 static DEFINE_PCI_DEVICE_TABLE(pch_gpio_pcidev_id) = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8014) },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, pch_gpio_pcidev_id);
index a9bda881935a82907ff0c5c753efee59b924cdf5..2762698e0204adc99699839137680bafc7fcc0c7 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/pci.h>
 #include <linux/gpio.h>
 #include <linux/mfd/rdc321x.h>
-#include <linux/mfd/core.h>
 #include <linux/slab.h>
 
 struct rdc321x_gpio {
@@ -136,7 +135,7 @@ static int __devinit rdc321x_gpio_probe(struct platform_device *pdev)
        struct rdc321x_gpio *rdc321x_gpio_dev;
        struct rdc321x_gpio_pdata *pdata;
 
-       pdata = mfd_get_data(pdev);
+       pdata = pdev->dev.platform_data;
        if (!pdata) {
                dev_err(&pdev->dev, "no platform data supplied\n");
                return -ENODEV;
index edbe1eae531fa6ad35394232af3de40f78425622..0265872e57d15e666b1365b2954befb9e98bf59b 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/module.h>
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/timb_gpio.h>
@@ -229,7 +228,7 @@ static int __devinit timbgpio_probe(struct platform_device *pdev)
        struct gpio_chip *gc;
        struct timbgpio *tgpio;
        struct resource *iomem;
-       struct timbgpio_platform_data *pdata = mfd_get_data(pdev);
+       struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
        int irq = platform_get_irq(pdev, 0);
 
        if (!pdata || pdata->nr_pins > 32) {
@@ -320,13 +319,14 @@ err_mem:
 static int __devexit timbgpio_remove(struct platform_device *pdev)
 {
        int err;
+       struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
        struct timbgpio *tgpio = platform_get_drvdata(pdev);
        struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        int irq = platform_get_irq(pdev, 0);
 
        if (irq >= 0 && tgpio->irq_base > 0) {
                int i;
-               for (i = 0; i < tgpio->gpio.ngpio; i++) {
+               for (i = 0; i < pdata->nr_pins; i++) {
                        irq_set_chip(tgpio->irq_base + i, NULL);
                        irq_set_chip_data(tgpio->irq_base + i, NULL);
                }
diff --git a/drivers/gpio/tps65910-gpio.c b/drivers/gpio/tps65910-gpio.c
new file mode 100644 (file)
index 0000000..8d1ddfd
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * tps65910-gpio.c  --  TI TPS6591x
+ *
+ * Copyright 2010 Texas Instruments Inc.
+ *
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ * Author: Jorge Eduardo Candelaria jedu@slimlogic.co.uk>
+ *
+ *  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/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/mfd/tps65910.h>
+
+static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+       struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
+       uint8_t val;
+
+       tps65910->read(tps65910, TPS65910_GPIO0 + offset, 1, &val);
+
+       if (val & GPIO_STS_MASK)
+               return 1;
+
+       return 0;
+}
+
+static void tps65910_gpio_set(struct gpio_chip *gc, unsigned offset,
+                             int value)
+{
+       struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
+
+       if (value)
+               tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset,
+                                               GPIO_SET_MASK);
+       else
+               tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset,
+                                               GPIO_SET_MASK);
+}
+
+static int tps65910_gpio_output(struct gpio_chip *gc, unsigned offset,
+                               int value)
+{
+       struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
+
+       /* Set the initial value */
+       tps65910_gpio_set(gc, 0, value);
+
+       return tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset,
+                                               GPIO_CFG_MASK);
+}
+
+static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset)
+{
+       struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
+
+       return tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset,
+                                               GPIO_CFG_MASK);
+}
+
+void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
+{
+       int ret;
+
+       if (!gpio_base)
+               return;
+
+       tps65910->gpio.owner            = THIS_MODULE;
+       tps65910->gpio.label            = tps65910->i2c_client->name;
+       tps65910->gpio.dev              = tps65910->dev;
+       tps65910->gpio.base             = gpio_base;
+
+       switch(tps65910_chip_id(tps65910)) {
+       case TPS65910:
+               tps65910->gpio.ngpio    = 6;
+       case TPS65911:
+               tps65910->gpio.ngpio    = 9;
+       default:
+               return;
+       }
+       tps65910->gpio.can_sleep        = 1;
+
+       tps65910->gpio.direction_input  = tps65910_gpio_input;
+       tps65910->gpio.direction_output = tps65910_gpio_output;
+       tps65910->gpio.set              = tps65910_gpio_set;
+       tps65910->gpio.get              = tps65910_gpio_get;
+
+       ret = gpiochip_add(&tps65910->gpio);
+
+       if (ret)
+               dev_warn(tps65910->dev, "GPIO registration failed: %d\n", ret);
+}
index 8a98ee5d5f6c636a93c6c88f43c1ab497b02fb6e..ef5aabd8b8b779a52dbc34d1f70465a3c9f3adec 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/gpio.h>
+#include <linux/slab.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/pci.h>
index 3e257a50bf56f447563318d86bff3f6b2650c517..61e1ef90d4e5190cc9ca515f5f043b55a0465c5f 100644 (file)
@@ -46,10 +46,11 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
        list_for_each_entry(entry, &dev->maplist, head) {
                /*
                 * Because the kernel-userspace ABI is fixed at a 32-bit offset
-                * while PCI resources may live above that, we ignore the map
-                * offset for maps of type _DRM_FRAMEBUFFER or _DRM_REGISTERS.
-                * It is assumed that each driver will have only one resource of
-                * each type.
+                * while PCI resources may live above that, we only compare the
+                * lower 32 bits of the map offset for maps of type
+                * _DRM_FRAMEBUFFER or _DRM_REGISTERS.
+                * It is assumed that if a driver have more than one resource
+                * of each type, the lower 32 bits are different.
                 */
                if (!entry->map ||
                    map->type != entry->map->type ||
@@ -59,9 +60,12 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
                case _DRM_SHM:
                        if (map->flags != _DRM_CONTAINS_LOCK)
                                break;
+                       return entry;
                case _DRM_REGISTERS:
                case _DRM_FRAME_BUFFER:
-                       return entry;
+                       if ((entry->map->offset & 0xffffffff) ==
+                           (map->offset & 0xffffffff))
+                               return entry;
                default: /* Make gcc happy */
                        ;
                }
@@ -182,9 +186,6 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
                        kfree(map);
                        return -EINVAL;
                }
-#endif
-#ifdef __alpha__
-               map->offset += dev->hose->mem_space->start;
 #endif
                /* Some drivers preinitialize some maps, without the X Server
                 * needing to be aware of it.  Therefore, we just return success
index 872747c5a544a08ffb57c1e0b55578b9d3b3596f..21058e6ad2b80ccbc10be90795402701270d1585 100644 (file)
@@ -1113,7 +1113,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
        if (card_res->count_fbs >= fb_count) {
                copied = 0;
                fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
-               list_for_each_entry(fb, &file_priv->fbs, head) {
+               list_for_each_entry(fb, &file_priv->fbs, filp_head) {
                        if (put_user(fb->base.id, fb_id + copied)) {
                                ret = -EFAULT;
                                goto out;
index adc9358c9bec4a2b1f0d86a7a7ebb32655c36184..09292193dafe0b28466e37061acc7bee25e348f5 100644 (file)
@@ -184,9 +184,9 @@ drm_edid_block_valid(u8 *raw_edid)
 
 bad:
        if (raw_edid) {
-               DRM_ERROR("Raw EDID:\n");
+               printk(KERN_ERR "Raw EDID:\n");
                print_hex_dump_bytes(KERN_ERR, DUMP_PREFIX_NONE, raw_edid, EDID_LENGTH);
-               printk("\n");
+               printk(KERN_ERR "\n");
        }
        return 0;
 }
@@ -258,6 +258,17 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
        return ret == 2 ? 0 : -1;
 }
 
+static bool drm_edid_is_zero(u8 *in_edid, int length)
+{
+       int i;
+       u32 *raw_edid = (u32 *)in_edid;
+
+       for (i = 0; i < length / 4; i++)
+               if (*(raw_edid + i) != 0)
+                       return false;
+       return true;
+}
+
 static u8 *
 drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
 {
@@ -273,6 +284,10 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
                        goto out;
                if (drm_edid_block_valid(block))
                        break;
+               if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) {
+                       connector->null_edid_counter++;
+                       goto carp;
+               }
        }
        if (i == 4)
                goto carp;
@@ -1412,6 +1427,64 @@ end:
 }
 EXPORT_SYMBOL(drm_detect_monitor_audio);
 
+/**
+ * drm_add_display_info - pull display info out if present
+ * @edid: EDID data
+ * @info: display info (attached to connector)
+ *
+ * Grab any available display info and stuff it into the drm_display_info
+ * structure that's part of the connector.  Useful for tracking bpp and
+ * color spaces.
+ */
+static void drm_add_display_info(struct edid *edid,
+                                struct drm_display_info *info)
+{
+       info->width_mm = edid->width_cm * 10;
+       info->height_mm = edid->height_cm * 10;
+
+       /* driver figures it out in this case */
+       info->bpc = 0;
+       info->color_formats = 0;
+
+       /* Only defined for 1.4 with digital displays */
+       if (edid->revision < 4)
+               return;
+
+       if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
+               return;
+
+       switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
+       case DRM_EDID_DIGITAL_DEPTH_6:
+               info->bpc = 6;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_8:
+               info->bpc = 8;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_10:
+               info->bpc = 10;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_12:
+               info->bpc = 12;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_14:
+               info->bpc = 14;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_16:
+               info->bpc = 16;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_UNDEF:
+       default:
+               info->bpc = 0;
+               break;
+       }
+
+       info->color_formats = DRM_COLOR_FORMAT_RGB444;
+       if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB444)
+               info->color_formats = DRM_COLOR_FORMAT_YCRCB444;
+       if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB422)
+               info->color_formats = DRM_COLOR_FORMAT_YCRCB422;
+}
+
 /**
  * drm_add_edid_modes - add modes from EDID data, if available
  * @connector: connector we're probing
@@ -1460,8 +1533,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
        if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
                edid_fixup_preferred(connector, quirks);
 
-       connector->display_info.width_mm = edid->width_cm * 10;
-       connector->display_info.height_mm = edid->height_cm * 10;
+       drm_add_display_info(edid, &connector->display_info);
 
        return num_modes;
 }
index 140b9525b48a47a83cf159c010f9818969ee3877..802b61ac31390d92b2affaf14f787b75f8caab2f 100644 (file)
@@ -70,174 +70,50 @@ fail:
 }
 EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
 
-/**
- * drm_fb_helper_connector_parse_command_line - parse command line for connector
- * @connector - connector to parse line for
- * @mode_option - per connector mode option
- *
- * This parses the connector specific then generic command lines for
- * modes and options to configure the connector.
- *
- * This uses the same parameters as the fb modedb.c, except for extra
- *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
- *
- * enable/enable Digital/disable bit at the end
- */
-static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_connector *fb_helper_conn,
-                                                      const char *mode_option)
-{
-       const char *name;
-       unsigned int namelen;
-       int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
-       unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
-       int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
-       int i;
-       enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
-       struct drm_fb_helper_cmdline_mode *cmdline_mode;
-       struct drm_connector *connector;
-
-       if (!fb_helper_conn)
-               return false;
-       connector = fb_helper_conn->connector;
-
-       cmdline_mode = &fb_helper_conn->cmdline_mode;
-       if (!mode_option)
-               mode_option = fb_mode_option;
-
-       if (!mode_option) {
-               cmdline_mode->specified = false;
-               return false;
-       }
-
-       name = mode_option;
-       namelen = strlen(name);
-       for (i = namelen-1; i >= 0; i--) {
-               switch (name[i]) {
-               case '@':
-                       namelen = i;
-                       if (!refresh_specified && !bpp_specified &&
-                           !yres_specified) {
-                               refresh = simple_strtol(&name[i+1], NULL, 10);
-                               refresh_specified = 1;
-                               if (cvt || rb)
-                                       cvt = 0;
-                       } else
-                               goto done;
-                       break;
-               case '-':
-                       namelen = i;
-                       if (!bpp_specified && !yres_specified) {
-                               bpp = simple_strtol(&name[i+1], NULL, 10);
-                               bpp_specified = 1;
-                               if (cvt || rb)
-                                       cvt = 0;
-                       } else
-                               goto done;
-                       break;
-               case 'x':
-                       if (!yres_specified) {
-                               yres = simple_strtol(&name[i+1], NULL, 10);
-                               yres_specified = 1;
-                       } else
-                               goto done;
-               case '0' ... '9':
-                       break;
-               case 'M':
-                       if (!yres_specified)
-                               cvt = 1;
-                       break;
-               case 'R':
-                       if (cvt)
-                               rb = 1;
-                       break;
-               case 'm':
-                       if (!cvt)
-                               margins = 1;
-                       break;
-               case 'i':
-                       if (!cvt)
-                               interlace = 1;
-                       break;
-               case 'e':
-                       force = DRM_FORCE_ON;
-                       break;
-               case 'D':
-                       if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
-                           (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
-                               force = DRM_FORCE_ON;
-                       else
-                               force = DRM_FORCE_ON_DIGITAL;
-                       break;
-               case 'd':
-                       force = DRM_FORCE_OFF;
-                       break;
-               default:
-                       goto done;
-               }
-       }
-       if (i < 0 && yres_specified) {
-               xres = simple_strtol(name, NULL, 10);
-               res_specified = 1;
-       }
-done:
-
-       DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
-               drm_get_connector_name(connector), xres, yres,
-               (refresh) ? refresh : 60, (rb) ? " reduced blanking" :
-               "", (margins) ? " with margins" : "", (interlace) ?
-               " interlaced" : "");
-
-       if (force) {
-               const char *s;
-               switch (force) {
-               case DRM_FORCE_OFF: s = "OFF"; break;
-               case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
-               default:
-               case DRM_FORCE_ON: s = "ON"; break;
-               }
-
-               DRM_INFO("forcing %s connector %s\n",
-                        drm_get_connector_name(connector), s);
-               connector->force = force;
-       }
-
-       if (res_specified) {
-               cmdline_mode->specified = true;
-               cmdline_mode->xres = xres;
-               cmdline_mode->yres = yres;
-       }
-
-       if (refresh_specified) {
-               cmdline_mode->refresh_specified = true;
-               cmdline_mode->refresh = refresh;
-       }
-
-       if (bpp_specified) {
-               cmdline_mode->bpp_specified = true;
-               cmdline_mode->bpp = bpp;
-       }
-       cmdline_mode->rb = rb ? true : false;
-       cmdline_mode->cvt = cvt  ? true : false;
-       cmdline_mode->interlace = interlace ? true : false;
-
-       return true;
-}
-
 static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
 {
        struct drm_fb_helper_connector *fb_helper_conn;
        int i;
 
        for (i = 0; i < fb_helper->connector_count; i++) {
+               struct drm_cmdline_mode *mode;
+               struct drm_connector *connector;
                char *option = NULL;
 
                fb_helper_conn = fb_helper->connector_info[i];
+               connector = fb_helper_conn->connector;
+               mode = &fb_helper_conn->cmdline_mode;
 
                /* do something on return - turn off connector maybe */
-               if (fb_get_options(drm_get_connector_name(fb_helper_conn->connector), &option))
+               if (fb_get_options(drm_get_connector_name(connector), &option))
                        continue;
 
-               drm_fb_helper_connector_parse_command_line(fb_helper_conn, option);
+               if (drm_mode_parse_command_line_for_connector(option,
+                                                             connector,
+                                                             mode)) {
+                       if (mode->force) {
+                               const char *s;
+                               switch (mode->force) {
+                               case DRM_FORCE_OFF: s = "OFF"; break;
+                               case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
+                               default:
+                               case DRM_FORCE_ON: s = "ON"; break;
+                               }
+
+                               DRM_INFO("forcing %s connector %s\n",
+                                        drm_get_connector_name(connector), s);
+                               connector->force = mode->force;
+                       }
+
+                       DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
+                                     drm_get_connector_name(connector),
+                                     mode->xres, mode->yres,
+                                     mode->refresh_specified ? mode->refresh : 60,
+                                     mode->rb ? " reduced blanking" : "",
+                                     mode->margins ? " with margins" : "",
+                                     mode->interlace ?  " interlaced" : "");
+               }
+
        }
        return 0;
 }
@@ -901,7 +777,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
        /* first up get a count of crtcs now in use and new min/maxes width/heights */
        for (i = 0; i < fb_helper->connector_count; i++) {
                struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
-               struct drm_fb_helper_cmdline_mode *cmdline_mode;
+               struct drm_cmdline_mode *cmdline_mode;
 
                cmdline_mode = &fb_helper_conn->cmdline_mode;
 
@@ -1123,7 +999,7 @@ static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_conn
 
 static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
 {
-       struct drm_fb_helper_cmdline_mode *cmdline_mode;
+       struct drm_cmdline_mode *cmdline_mode;
        cmdline_mode = &fb_connector->cmdline_mode;
        return cmdline_mode->specified;
 }
@@ -1131,7 +1007,7 @@ static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
 static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
                                                      int width, int height)
 {
-       struct drm_fb_helper_cmdline_mode *cmdline_mode;
+       struct drm_cmdline_mode *cmdline_mode;
        struct drm_display_mode *mode = NULL;
 
        cmdline_mode = &fb_helper_conn->cmdline_mode;
@@ -1163,19 +1039,8 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne
        }
 
 create_mode:
-       if (cmdline_mode->cvt)
-               mode = drm_cvt_mode(fb_helper_conn->connector->dev,
-                                   cmdline_mode->xres, cmdline_mode->yres,
-                                   cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
-                                   cmdline_mode->rb, cmdline_mode->interlace,
-                                   cmdline_mode->margins);
-       else
-               mode = drm_gtf_mode(fb_helper_conn->connector->dev,
-                                   cmdline_mode->xres, cmdline_mode->yres,
-                                   cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
-                                   cmdline_mode->interlace,
-                                   cmdline_mode->margins);
-       drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+       mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
+                                                cmdline_mode);
        list_add(&mode->head, &fb_helper_conn->connector->modes);
        return mode;
 }
index d61d185cf040499232d508d4daa66e2f85113fdf..4a058c7af6c096f6dd69dd533701a9adb3091b09 100644 (file)
@@ -28,6 +28,7 @@
  * IN THE SOFTWARE.
  */
 #include <linux/compat.h>
+#include <linux/ratelimit.h>
 
 #include "drmP.h"
 #include "drm_core.h"
@@ -253,10 +254,10 @@ static int compat_drm_addmap(struct file *file, unsigned int cmd,
                return -EFAULT;
 
        m32.handle = (unsigned long)handle;
-       if (m32.handle != (unsigned long)handle && printk_ratelimit())
-               printk(KERN_ERR "compat_drm_addmap truncated handle"
-                      " %p for type %d offset %x\n",
-                      handle, m32.type, m32.offset);
+       if (m32.handle != (unsigned long)handle)
+               printk_ratelimited(KERN_ERR "compat_drm_addmap truncated handle"
+                                  " %p for type %d offset %x\n",
+                                  handle, m32.type, m32.offset);
 
        if (copy_to_user(argp, &m32, sizeof(m32)))
                return -EFAULT;
index a1f12cb043deb233484f9a4957300fa475c3a024..2022a5c966bb050d89084a699cc6e6ab8508a026 100644 (file)
@@ -684,10 +684,11 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
         */
        *vblank_time = ns_to_timeval(timeval_to_ns(&raw_time) - delta_ns);
 
-       DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %d.%d -> %d.%d [e %d us, %d rep]\n",
-                 crtc, (int) vbl_status, hpos, vpos, raw_time.tv_sec,
-                 raw_time.tv_usec, vblank_time->tv_sec, vblank_time->tv_usec,
-                 (int) duration_ns/1000, i);
+       DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n",
+                 crtc, (int)vbl_status, hpos, vpos,
+                 (long)raw_time.tv_sec, (long)raw_time.tv_usec,
+                 (long)vblank_time->tv_sec, (long)vblank_time->tv_usec,
+                 (int)duration_ns/1000, i);
 
        vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD;
        if (invbl)
index 25bf87390f53bd86ed3bd32db419f1ecf65de732..c2d32f20e2fb606838f5799b538f57baa765ce9e 100644 (file)
@@ -974,3 +974,159 @@ void drm_mode_connector_list_update(struct drm_connector *connector)
        }
 }
 EXPORT_SYMBOL(drm_mode_connector_list_update);
+
+/**
+ * drm_mode_parse_command_line_for_connector - parse command line for connector
+ * @mode_option - per connector mode option
+ * @connector - connector to parse line for
+ *
+ * This parses the connector specific then generic command lines for
+ * modes and options to configure the connector.
+ *
+ * This uses the same parameters as the fb modedb.c, except for extra
+ *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
+ *
+ * enable/enable Digital/disable bit at the end
+ */
+bool drm_mode_parse_command_line_for_connector(const char *mode_option,
+                                              struct drm_connector *connector,
+                                              struct drm_cmdline_mode *mode)
+{
+       const char *name;
+       unsigned int namelen;
+       int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
+       unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
+       int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
+       int i;
+       enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
+
+#ifdef CONFIG_FB
+       if (!mode_option)
+               mode_option = fb_mode_option;
+#endif
+
+       if (!mode_option) {
+               mode->specified = false;
+               return false;
+       }
+
+       name = mode_option;
+       namelen = strlen(name);
+       for (i = namelen-1; i >= 0; i--) {
+               switch (name[i]) {
+               case '@':
+                       namelen = i;
+                       if (!refresh_specified && !bpp_specified &&
+                           !yres_specified) {
+                               refresh = simple_strtol(&name[i+1], NULL, 10);
+                               refresh_specified = 1;
+                               if (cvt || rb)
+                                       cvt = 0;
+                       } else
+                               goto done;
+                       break;
+               case '-':
+                       namelen = i;
+                       if (!bpp_specified && !yres_specified) {
+                               bpp = simple_strtol(&name[i+1], NULL, 10);
+                               bpp_specified = 1;
+                               if (cvt || rb)
+                                       cvt = 0;
+                       } else
+                               goto done;
+                       break;
+               case 'x':
+                       if (!yres_specified) {
+                               yres = simple_strtol(&name[i+1], NULL, 10);
+                               yres_specified = 1;
+                       } else
+                               goto done;
+               case '0' ... '9':
+                       break;
+               case 'M':
+                       if (!yres_specified)
+                               cvt = 1;
+                       break;
+               case 'R':
+                       if (cvt)
+                               rb = 1;
+                       break;
+               case 'm':
+                       if (!cvt)
+                               margins = 1;
+                       break;
+               case 'i':
+                       if (!cvt)
+                               interlace = 1;
+                       break;
+               case 'e':
+                       force = DRM_FORCE_ON;
+                       break;
+               case 'D':
+                       if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
+                           (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
+                               force = DRM_FORCE_ON;
+                       else
+                               force = DRM_FORCE_ON_DIGITAL;
+                       break;
+               case 'd':
+                       force = DRM_FORCE_OFF;
+                       break;
+               default:
+                       goto done;
+               }
+       }
+       if (i < 0 && yres_specified) {
+               xres = simple_strtol(name, NULL, 10);
+               res_specified = 1;
+       }
+done:
+       if (res_specified) {
+               mode->specified = true;
+               mode->xres = xres;
+               mode->yres = yres;
+       }
+
+       if (refresh_specified) {
+               mode->refresh_specified = true;
+               mode->refresh = refresh;
+       }
+
+       if (bpp_specified) {
+               mode->bpp_specified = true;
+               mode->bpp = bpp;
+       }
+       mode->rb = rb ? true : false;
+       mode->cvt = cvt  ? true : false;
+       mode->interlace = interlace ? true : false;
+       mode->force = force;
+
+       return true;
+}
+EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
+
+struct drm_display_mode *
+drm_mode_create_from_cmdline_mode(struct drm_device *dev,
+                                 struct drm_cmdline_mode *cmd)
+{
+       struct drm_display_mode *mode;
+
+       if (cmd->cvt)
+               mode = drm_cvt_mode(dev,
+                                   cmd->xres, cmd->yres,
+                                   cmd->refresh_specified ? cmd->refresh : 60,
+                                   cmd->rb, cmd->interlace,
+                                   cmd->margins);
+       else
+               mode = drm_gtf_mode(dev,
+                                   cmd->xres, cmd->yres,
+                                   cmd->refresh_specified ? cmd->refresh : 60,
+                                   cmd->interlace,
+                                   cmd->margins);
+       if (!mode)
+               return NULL;
+
+       drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+       return mode;
+}
+EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
index e1aee4f6a7c69dacdc59ff2a057340ee914bc4b5..b6a19cb07cafc3591f2ff946532851f63a14270d 100644 (file)
@@ -251,7 +251,7 @@ err:
 }
 
 
-int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p)
+static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p)
 {
        if ((p->busnum >> 8) != drm_get_pci_domain(dev) ||
            (p->busnum & 0xff) != dev->pdev->bus->number ||
@@ -292,6 +292,7 @@ static struct drm_bus drm_pci_bus = {
        .get_name = drm_pci_get_name,
        .set_busid = drm_pci_set_busid,
        .set_unique = drm_pci_set_unique,
+       .irq_by_busid = drm_pci_irq_by_busid,
        .agp_init = drm_pci_agp_init,
 };
 
index 001273d57f2d689b6b08f9dd8916a10211b427a0..6d7b083c5b776d482d3b0a21f60a43adebd8f66d 100644 (file)
@@ -62,6 +62,26 @@ struct idr drm_minors_idr;
 struct class *drm_class;
 struct proc_dir_entry *drm_proc_root;
 struct dentry *drm_debugfs_root;
+
+int drm_err(const char *func, const char *format, ...)
+{
+       struct va_format vaf;
+       va_list args;
+       int r;
+
+       va_start(args, format);
+
+       vaf.fmt = format;
+       vaf.va = &args;
+
+       r = printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* %pV", func, &vaf);
+
+       va_end(args);
+
+       return r;
+}
+EXPORT_SYMBOL(drm_err);
+
 void drm_ut_debug_printk(unsigned int request_level,
                         const char *prefix,
                         const char *function_name,
@@ -78,6 +98,7 @@ void drm_ut_debug_printk(unsigned int request_level,
        }
 }
 EXPORT_SYMBOL(drm_ut_debug_printk);
+
 static int drm_minor_get_id(struct drm_device *dev, int type)
 {
        int new_id;
index 2c3fcbdfd8ff64f8c5a53ff35884f59ce51bd621..5db96d45fc71677fcf0b6432e0f32dfd22b774d4 100644 (file)
@@ -526,7 +526,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
 static resource_size_t drm_core_get_reg_ofs(struct drm_device *dev)
 {
 #ifdef __alpha__
-       return dev->hose->dense_mem_base - dev->hose->mem_space->start;
+       return dev->hose->dense_mem_base;
 #else
        return 0;
 #endif
index 87c8e29465e30a7963afdd03c1aa0666ed89d55d..4d46441cbe2d830de73ffacdb5821dbdd11f6340 100644 (file)
@@ -106,11 +106,12 @@ static const char *get_tiling_flag(struct drm_i915_gem_object *obj)
     }
 }
 
-static const char *agp_type_str(int type)
+static const char *cache_level_str(int type)
 {
        switch (type) {
-       case 0: return " uncached";
-       case 1: return " snooped";
+       case I915_CACHE_NONE: return " uncached";
+       case I915_CACHE_LLC: return " snooped (LLC)";
+       case I915_CACHE_LLC_MLC: return " snooped (LLC+MLC)";
        default: return "";
        }
 }
@@ -127,7 +128,7 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
                   obj->base.write_domain,
                   obj->last_rendering_seqno,
                   obj->last_fenced_seqno,
-                  agp_type_str(obj->agp_type == AGP_USER_CACHED_MEMORY),
+                  cache_level_str(obj->cache_level),
                   obj->dirty ? " dirty" : "",
                   obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
        if (obj->base.name)
@@ -714,7 +715,7 @@ static void print_error_buffers(struct seq_file *m,
                           dirty_flag(err->dirty),
                           purgeable_flag(err->purgeable),
                           ring_str(err->ring),
-                          agp_type_str(err->agp_type));
+                          cache_level_str(err->cache_level));
 
                if (err->name)
                        seq_printf(m, " (name: %d)", err->name);
@@ -775,7 +776,7 @@ static int i915_error_state(struct seq_file *m, void *unused)
        seq_printf(m, "  INSTPM: 0x%08x\n", error->instpm);
        seq_printf(m, "  seqno: 0x%08x\n", error->seqno);
 
-       for (i = 0; i < 16; i++)
+       for (i = 0; i < dev_priv->num_fence_regs; i++)
                seq_printf(m, "  fence[%d] = %08llx\n", i, error->fence[i]);
 
        if (error->active_bo)
@@ -852,6 +853,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
+       int ret;
 
        if (IS_GEN5(dev)) {
                u16 rgvswctl = I915_READ16(MEMSWCTL);
@@ -873,7 +875,11 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                int max_freq;
 
                /* RPSTAT1 is in the GT power well */
-               __gen6_gt_force_wake_get(dev_priv);
+               ret = mutex_lock_interruptible(&dev->struct_mutex);
+               if (ret)
+                       return ret;
+
+               gen6_gt_force_wake_get(dev_priv);
 
                rpstat = I915_READ(GEN6_RPSTAT1);
                rpupei = I915_READ(GEN6_RP_CUR_UP_EI);
@@ -883,6 +889,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                rpcurdown = I915_READ(GEN6_RP_CUR_DOWN);
                rpprevdown = I915_READ(GEN6_RP_PREV_DOWN);
 
+               gen6_gt_force_wake_put(dev_priv);
+               mutex_unlock(&dev->struct_mutex);
+
                seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
                seq_printf(m, "RPSTAT1: 0x%08x\n", rpstat);
                seq_printf(m, "Render p-state ratio: %d\n",
@@ -917,8 +926,6 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                max_freq = rp_state_cap & 0xff;
                seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
                           max_freq * 50);
-
-               __gen6_gt_force_wake_put(dev_priv);
        } else {
                seq_printf(m, "no P-state info available\n");
        }
@@ -1058,6 +1065,9 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
                case FBC_MULTIPLE_PIPES:
                        seq_printf(m, "multiple pipes are enabled");
                        break;
+               case FBC_MODULE_PARAM:
+                       seq_printf(m, "disabled per module param (default off)");
+                       break;
                default:
                        seq_printf(m, "unknown reason");
                }
@@ -1186,6 +1196,42 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
        return 0;
 }
 
+static int i915_context_status(struct seq_file *m, void *unused)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->mode_config.mutex);
+       if (ret)
+               return ret;
+
+       seq_printf(m, "power context ");
+       describe_obj(m, dev_priv->pwrctx);
+       seq_printf(m, "\n");
+
+       seq_printf(m, "render context ");
+       describe_obj(m, dev_priv->renderctx);
+       seq_printf(m, "\n");
+
+       mutex_unlock(&dev->mode_config.mutex);
+
+       return 0;
+}
+
+static int i915_gen6_forcewake_count_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       seq_printf(m, "forcewake count = %d\n",
+                  atomic_read(&dev_priv->forcewake_count));
+
+       return 0;
+}
+
 static int
 i915_wedged_open(struct inode *inode,
                 struct file *filp)
@@ -1288,6 +1334,67 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor)
        return drm_add_fake_info_node(minor, ent, &i915_wedged_fops);
 }
 
+static int i915_forcewake_open(struct inode *inode, struct file *file)
+{
+       struct drm_device *dev = inode->i_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
+
+       if (!IS_GEN6(dev))
+               return 0;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+       gen6_gt_force_wake_get(dev_priv);
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+int i915_forcewake_release(struct inode *inode, struct file *file)
+{
+       struct drm_device *dev = inode->i_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (!IS_GEN6(dev))
+               return 0;
+
+       /*
+        * It's bad that we can potentially hang userspace if struct_mutex gets
+        * forever stuck.  However, if we cannot acquire this lock it means that
+        * almost certainly the driver has hung, is not unload-able. Therefore
+        * hanging here is probably a minor inconvenience not to be seen my
+        * almost every user.
+        */
+       mutex_lock(&dev->struct_mutex);
+       gen6_gt_force_wake_put(dev_priv);
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+static const struct file_operations i915_forcewake_fops = {
+       .owner = THIS_MODULE,
+       .open = i915_forcewake_open,
+       .release = i915_forcewake_release,
+};
+
+static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor)
+{
+       struct drm_device *dev = minor->dev;
+       struct dentry *ent;
+
+       ent = debugfs_create_file("i915_forcewake_user",
+                                 S_IRUSR,
+                                 root, dev,
+                                 &i915_forcewake_fops);
+       if (IS_ERR(ent))
+               return PTR_ERR(ent);
+
+       return drm_add_fake_info_node(minor, ent, &i915_forcewake_fops);
+}
+
 static struct drm_info_list i915_debugfs_list[] = {
        {"i915_capabilities", i915_capabilities, 0},
        {"i915_gem_objects", i915_gem_object_info, 0},
@@ -1324,6 +1431,8 @@ static struct drm_info_list i915_debugfs_list[] = {
        {"i915_sr_status", i915_sr_status, 0},
        {"i915_opregion", i915_opregion, 0},
        {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
+       {"i915_context_status", i915_context_status, 0},
+       {"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0},
 };
 #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
 
@@ -1335,6 +1444,10 @@ int i915_debugfs_init(struct drm_minor *minor)
        if (ret)
                return ret;
 
+       ret = i915_forcewake_create(minor->debugfs_root, minor);
+       if (ret)
+               return ret;
+
        return drm_debugfs_create_files(i915_debugfs_list,
                                        I915_DEBUGFS_ENTRIES,
                                        minor->debugfs_root, minor);
@@ -1344,6 +1457,8 @@ void i915_debugfs_cleanup(struct drm_minor *minor)
 {
        drm_debugfs_remove_files(i915_debugfs_list,
                                 I915_DEBUGFS_ENTRIES, minor);
+       drm_debugfs_remove_files((struct drm_info_list *) &i915_forcewake_fops,
+                                1, minor);
        drm_debugfs_remove_files((struct drm_info_list *) &i915_wedged_fops,
                                 1, minor);
 }
index 12876f2795d2b373d9cac4130ec0052b44db23e6..0239e9974bf29cf8053c54fd42cb0239b21e65d6 100644 (file)
@@ -571,7 +571,7 @@ static int i915_quiescent(struct drm_device *dev)
        struct intel_ring_buffer *ring = LP_RING(dev->dev_private);
 
        i915_kernel_lost_context(dev);
-       return intel_wait_ring_buffer(ring, ring->size - 8);
+       return intel_wait_ring_idle(ring);
 }
 
 static int i915_flush_ioctl(struct drm_device *dev, void *data,
@@ -1176,11 +1176,11 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
        return can_switch;
 }
 
-static int i915_load_modeset_init(struct drm_device *dev)
+static int i915_load_gem_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long prealloc_size, gtt_size, mappable_size;
-       int ret = 0;
+       int ret;
 
        prealloc_size = dev_priv->mm.gtt->stolen_size;
        gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT;
@@ -1204,7 +1204,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
        ret = i915_gem_init_ringbuffer(dev);
        mutex_unlock(&dev->struct_mutex);
        if (ret)
-               goto out;
+               return ret;
 
        /* Try to set up FBC with a reasonable compressed buffer size */
        if (I915_HAS_FBC(dev) && i915_powersave) {
@@ -1222,6 +1222,13 @@ static int i915_load_modeset_init(struct drm_device *dev)
 
        /* Allow hardware batchbuffers unless told otherwise. */
        dev_priv->allow_batchbuffer = 1;
+       return 0;
+}
+
+static int i915_load_modeset_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
 
        ret = intel_parse_bios(dev);
        if (ret)
@@ -1236,7 +1243,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
         */
        ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode);
        if (ret && ret != -ENODEV)
-               goto cleanup_ringbuffer;
+               goto out;
 
        intel_register_dsm_handler();
 
@@ -1253,10 +1260,40 @@ static int i915_load_modeset_init(struct drm_device *dev)
 
        intel_modeset_init(dev);
 
-       ret = drm_irq_install(dev);
+       ret = i915_load_gem_init(dev);
        if (ret)
                goto cleanup_vga_switcheroo;
 
+       intel_modeset_gem_init(dev);
+
+       if (IS_IVYBRIDGE(dev)) {
+               /* Share pre & uninstall handlers with ILK/SNB */
+               dev->driver->irq_handler = ivybridge_irq_handler;
+               dev->driver->irq_preinstall = ironlake_irq_preinstall;
+               dev->driver->irq_postinstall = ivybridge_irq_postinstall;
+               dev->driver->irq_uninstall = ironlake_irq_uninstall;
+               dev->driver->enable_vblank = ivybridge_enable_vblank;
+               dev->driver->disable_vblank = ivybridge_disable_vblank;
+       } else if (HAS_PCH_SPLIT(dev)) {
+               dev->driver->irq_handler = ironlake_irq_handler;
+               dev->driver->irq_preinstall = ironlake_irq_preinstall;
+               dev->driver->irq_postinstall = ironlake_irq_postinstall;
+               dev->driver->irq_uninstall = ironlake_irq_uninstall;
+               dev->driver->enable_vblank = ironlake_enable_vblank;
+               dev->driver->disable_vblank = ironlake_disable_vblank;
+       } else {
+               dev->driver->irq_preinstall = i915_driver_irq_preinstall;
+               dev->driver->irq_postinstall = i915_driver_irq_postinstall;
+               dev->driver->irq_uninstall = i915_driver_irq_uninstall;
+               dev->driver->irq_handler = i915_driver_irq_handler;
+               dev->driver->enable_vblank = i915_enable_vblank;
+               dev->driver->disable_vblank = i915_disable_vblank;
+       }
+
+       ret = drm_irq_install(dev);
+       if (ret)
+               goto cleanup_gem;
+
        /* Always safe in the mode setting case. */
        /* FIXME: do pre/post-mode set stuff in core KMS code */
        dev->vblank_disable_allowed = 1;
@@ -1274,14 +1311,14 @@ static int i915_load_modeset_init(struct drm_device *dev)
 
 cleanup_irq:
        drm_irq_uninstall(dev);
+cleanup_gem:
+       mutex_lock(&dev->struct_mutex);
+       i915_gem_cleanup_ringbuffer(dev);
+       mutex_unlock(&dev->struct_mutex);
 cleanup_vga_switcheroo:
        vga_switcheroo_unregister_client(dev->pdev);
 cleanup_vga_client:
        vga_client_register(dev->pdev, NULL, NULL, NULL);
-cleanup_ringbuffer:
-       mutex_lock(&dev->struct_mutex);
-       i915_gem_cleanup_ringbuffer(dev);
-       mutex_unlock(&dev->struct_mutex);
 out:
        return ret;
 }
@@ -1982,7 +2019,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        dev->driver->get_vblank_counter = i915_get_vblank_counter;
        dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
-       if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev)) {
+       if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev)) {
                dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
                dev->driver->get_vblank_counter = gm45_get_vblank_counter;
        }
@@ -2025,6 +2062,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        spin_lock_init(&dev_priv->irq_lock);
        spin_lock_init(&dev_priv->error_lock);
+       spin_lock_init(&dev_priv->rps_lock);
 
        if (IS_MOBILE(dev) || !IS_GEN2(dev))
                dev_priv->num_pipe = 2;
index 32d1b3e829c8d35433f0b170052e9be96f358a1c..0defd42705943e1776b3e9447a770048142d1a73 100644 (file)
@@ -52,9 +52,12 @@ module_param_named(powersave, i915_powersave, int, 0600);
 unsigned int i915_semaphores = 0;
 module_param_named(semaphores, i915_semaphores, int, 0600);
 
-unsigned int i915_enable_rc6 = 0;
+unsigned int i915_enable_rc6 = 1;
 module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600);
 
+unsigned int i915_enable_fbc = 0;
+module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600);
+
 unsigned int i915_lvds_downclock = 0;
 module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
 
@@ -169,7 +172,7 @@ static const struct intel_device_info intel_ironlake_d_info = {
 static const struct intel_device_info intel_ironlake_m_info = {
        .gen = 5, .is_mobile = 1,
        .need_gfx_hws = 1, .has_hotplug = 1,
-       .has_fbc = 0, /* disabled due to buggy hardware */
+       .has_fbc = 1,
        .has_bsd_ring = 1,
 };
 
@@ -188,6 +191,21 @@ static const struct intel_device_info intel_sandybridge_m_info = {
        .has_blt_ring = 1,
 };
 
+static const struct intel_device_info intel_ivybridge_d_info = {
+       .is_ivybridge = 1, .gen = 7,
+       .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_bsd_ring = 1,
+       .has_blt_ring = 1,
+};
+
+static const struct intel_device_info intel_ivybridge_m_info = {
+       .is_ivybridge = 1, .gen = 7, .is_mobile = 1,
+       .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_fbc = 0,   /* FBC is not enabled on Ivybridge mobile yet */
+       .has_bsd_ring = 1,
+       .has_blt_ring = 1,
+};
+
 static const struct pci_device_id pciidlist[] = {              /* aka */
        INTEL_VGA_DEVICE(0x3577, &intel_i830_info),             /* I830_M */
        INTEL_VGA_DEVICE(0x2562, &intel_845g_info),             /* 845_G */
@@ -227,6 +245,11 @@ static const struct pci_device_id pciidlist[] = {          /* aka */
        INTEL_VGA_DEVICE(0x0116, &intel_sandybridge_m_info),
        INTEL_VGA_DEVICE(0x0126, &intel_sandybridge_m_info),
        INTEL_VGA_DEVICE(0x010A, &intel_sandybridge_d_info),
+       INTEL_VGA_DEVICE(0x0156, &intel_ivybridge_m_info), /* GT1 mobile */
+       INTEL_VGA_DEVICE(0x0166, &intel_ivybridge_m_info), /* GT2 mobile */
+       INTEL_VGA_DEVICE(0x0152, &intel_ivybridge_d_info), /* GT1 desktop */
+       INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */
+       INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */
        {0, 0, 0}
 };
 
@@ -235,7 +258,9 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
 #endif
 
 #define INTEL_PCH_DEVICE_ID_MASK       0xff00
+#define INTEL_PCH_IBX_DEVICE_ID_TYPE   0x3b00
 #define INTEL_PCH_CPT_DEVICE_ID_TYPE   0x1c00
+#define INTEL_PCH_PPT_DEVICE_ID_TYPE   0x1e00
 
 void intel_detect_pch (struct drm_device *dev)
 {
@@ -254,16 +279,23 @@ void intel_detect_pch (struct drm_device *dev)
                        int id;
                        id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
 
-                       if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) {
+                       if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) {
+                               dev_priv->pch_type = PCH_IBX;
+                               DRM_DEBUG_KMS("Found Ibex Peak PCH\n");
+                       } else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) {
                                dev_priv->pch_type = PCH_CPT;
                                DRM_DEBUG_KMS("Found CougarPoint PCH\n");
+                       } else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) {
+                               /* PantherPoint is CPT compatible */
+                               dev_priv->pch_type = PCH_CPT;
+                               DRM_DEBUG_KMS("Found PatherPoint PCH\n");
                        }
                }
                pci_dev_put(pch);
        }
 }
 
-void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
+static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
 {
        int count;
 
@@ -279,12 +311,38 @@ void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
                udelay(10);
 }
 
-void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
+/*
+ * Generally this is called implicitly by the register read function. However,
+ * if some sequence requires the GT to not power down then this function should
+ * be called at the beginning of the sequence followed by a call to
+ * gen6_gt_force_wake_put() at the end of the sequence.
+ */
+void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
+{
+       WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
+
+       /* Forcewake is atomic in case we get in here without the lock */
+       if (atomic_add_return(1, &dev_priv->forcewake_count) == 1)
+               __gen6_gt_force_wake_get(dev_priv);
+}
+
+static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
 {
        I915_WRITE_NOTRACE(FORCEWAKE, 0);
        POSTING_READ(FORCEWAKE);
 }
 
+/*
+ * see gen6_gt_force_wake_get()
+ */
+void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
+{
+       WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
+
+       if (atomic_dec_and_test(&dev_priv->forcewake_count))
+               __gen6_gt_force_wake_put(dev_priv);
+}
+
 void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
 {
        int loop = 500;
index 1c1b27c97e5cee3aa26138a1d5c6ebf8ba5f85c0..f63ee162f1245dcffc5844c6c401df7ce9b885c8 100644 (file)
@@ -188,7 +188,7 @@ struct drm_i915_error_state {
                u32 dirty:1;
                u32 purgeable:1;
                u32 ring:4;
-               u32 agp_type:1;
+               u32 cache_level:2;
        } *active_bo, *pinned_bo;
        u32 active_bo_count, pinned_bo_count;
        struct intel_overlay_error_state *overlay;
@@ -203,12 +203,19 @@ struct drm_i915_display_funcs {
        int (*get_display_clock_speed)(struct drm_device *dev);
        int (*get_fifo_size)(struct drm_device *dev, int plane);
        void (*update_wm)(struct drm_device *dev);
+       int (*crtc_mode_set)(struct drm_crtc *crtc,
+                            struct drm_display_mode *mode,
+                            struct drm_display_mode *adjusted_mode,
+                            int x, int y,
+                            struct drm_framebuffer *old_fb);
+       void (*fdi_link_train)(struct drm_crtc *crtc);
+       void (*init_clock_gating)(struct drm_device *dev);
+       void (*init_pch_clock_gating)(struct drm_device *dev);
        /* clock updates for mode set */
        /* cursor updates */
        /* render clock increase/decrease */
        /* display clock increase/decrease */
        /* pll clock increase/decrease */
-       /* clock gating init */
 };
 
 struct intel_device_info {
@@ -223,6 +230,7 @@ struct intel_device_info {
        u8 is_pineview : 1;
        u8 is_broadwater : 1;
        u8 is_crestline : 1;
+       u8 is_ivybridge : 1;
        u8 has_fbc : 1;
        u8 has_pipe_cxsr : 1;
        u8 has_hotplug : 1;
@@ -242,6 +250,7 @@ enum no_fbc_reason {
        FBC_BAD_PLANE, /* fbc not supported on plane */
        FBC_NOT_TILED, /* buffer not tiled */
        FBC_MULTIPLE_PIPES, /* more than one pipe active */
+       FBC_MODULE_PARAM,
 };
 
 enum intel_pch {
@@ -676,6 +685,10 @@ typedef struct drm_i915_private {
 
        bool mchbar_need_disable;
 
+       struct work_struct rps_work;
+       spinlock_t rps_lock;
+       u32 pm_iir;
+
        u8 cur_delay;
        u8 min_delay;
        u8 max_delay;
@@ -703,8 +716,17 @@ typedef struct drm_i915_private {
        struct intel_fbdev *fbdev;
 
        struct drm_property *broadcast_rgb_property;
+       struct drm_property *force_audio_property;
+
+       atomic_t forcewake_count;
 } drm_i915_private_t;
 
+enum i915_cache_level {
+       I915_CACHE_NONE,
+       I915_CACHE_LLC,
+       I915_CACHE_LLC_MLC, /* gen6+ */
+};
+
 struct drm_i915_gem_object {
        struct drm_gem_object base;
 
@@ -791,6 +813,8 @@ struct drm_i915_gem_object {
        unsigned int pending_fenced_gpu_access:1;
        unsigned int fenced_gpu_access:1;
 
+       unsigned int cache_level:2;
+
        struct page **pages;
 
        /**
@@ -827,8 +851,6 @@ struct drm_i915_gem_object {
        /** Record of address bit 17 of each page at last unbind. */
        unsigned long *bit_17;
 
-       /** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */
-       uint32_t agp_type;
 
        /**
         * If present, while GEM_DOMAIN_CPU is in the read domain this array
@@ -888,13 +910,6 @@ struct drm_i915_file_private {
        } mm;
 };
 
-enum intel_chip_family {
-       CHIP_I8XX = 0x01,
-       CHIP_I9XX = 0x02,
-       CHIP_I915 = 0x04,
-       CHIP_I965 = 0x08,
-};
-
 #define INTEL_INFO(dev)        (((struct drm_i915_private *) (dev)->dev_private)->info)
 
 #define IS_I830(dev)           ((dev)->pci_device == 0x3577)
@@ -915,13 +930,21 @@ enum intel_chip_family {
 #define IS_G33(dev)            (INTEL_INFO(dev)->is_g33)
 #define IS_IRONLAKE_D(dev)     ((dev)->pci_device == 0x0042)
 #define IS_IRONLAKE_M(dev)     ((dev)->pci_device == 0x0046)
+#define IS_IVYBRIDGE(dev)      (INTEL_INFO(dev)->is_ivybridge)
 #define IS_MOBILE(dev)         (INTEL_INFO(dev)->is_mobile)
 
+/*
+ * The genX designation typically refers to the render engine, so render
+ * capability related checks should use IS_GEN, while display and other checks
+ * have their own (e.g. HAS_PCH_SPLIT for ILK+ display, IS_foo for particular
+ * chips, etc.).
+ */
 #define IS_GEN2(dev)   (INTEL_INFO(dev)->gen == 2)
 #define IS_GEN3(dev)   (INTEL_INFO(dev)->gen == 3)
 #define IS_GEN4(dev)   (INTEL_INFO(dev)->gen == 4)
 #define IS_GEN5(dev)   (INTEL_INFO(dev)->gen == 5)
 #define IS_GEN6(dev)   (INTEL_INFO(dev)->gen == 6)
+#define IS_GEN7(dev)   (INTEL_INFO(dev)->gen == 7)
 
 #define HAS_BSD(dev)            (INTEL_INFO(dev)->has_bsd_ring)
 #define HAS_BLT(dev)            (INTEL_INFO(dev)->has_blt_ring)
@@ -948,8 +971,8 @@ enum intel_chip_family {
 #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
 #define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
 
-#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev))
-#define HAS_PIPE_CONTROL(dev) (IS_GEN5(dev) || IS_GEN6(dev))
+#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev))
+#define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5)
 
 #define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type)
 #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
@@ -967,6 +990,7 @@ extern unsigned int i915_lvds_downclock;
 extern unsigned int i915_panel_use_ssc;
 extern int i915_vbt_sdvo_panel_type;
 extern unsigned int i915_enable_rc6;
+extern unsigned int i915_enable_fbc;
 
 extern int i915_suspend(struct drm_device *dev, pm_message_t state);
 extern int i915_resume(struct drm_device *dev);
@@ -1010,12 +1034,27 @@ extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
 extern void i915_driver_irq_preinstall(struct drm_device * dev);
 extern int i915_driver_irq_postinstall(struct drm_device *dev);
 extern void i915_driver_irq_uninstall(struct drm_device * dev);
+
+extern irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS);
+extern void ironlake_irq_preinstall(struct drm_device *dev);
+extern int ironlake_irq_postinstall(struct drm_device *dev);
+extern void ironlake_irq_uninstall(struct drm_device *dev);
+
+extern irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS);
+extern void ivybridge_irq_preinstall(struct drm_device *dev);
+extern int ivybridge_irq_postinstall(struct drm_device *dev);
+extern void ivybridge_irq_uninstall(struct drm_device *dev);
+
 extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
 extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
 extern int i915_enable_vblank(struct drm_device *dev, int crtc);
 extern void i915_disable_vblank(struct drm_device *dev, int crtc);
+extern int ironlake_enable_vblank(struct drm_device *dev, int crtc);
+extern void ironlake_disable_vblank(struct drm_device *dev, int crtc);
+extern int ivybridge_enable_vblank(struct drm_device *dev, int crtc);
+extern void ivybridge_disable_vblank(struct drm_device *dev, int crtc);
 extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc);
 extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc);
 extern int i915_vblank_swap(struct drm_device *dev, void *data,
@@ -1265,6 +1304,7 @@ static inline void intel_unregister_dsm_handler(void) { return; }
 
 /* modesetting */
 extern void intel_modeset_init(struct drm_device *dev);
+extern void intel_modeset_gem_init(struct drm_device *dev);
 extern void intel_modeset_cleanup(struct drm_device *dev);
 extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
 extern void i8xx_disable_fbc(struct drm_device *dev);
@@ -1312,13 +1352,34 @@ extern void intel_display_print_error_state(struct seq_file *m,
                LOCK_TEST_WITH_RETURN(dev, file);                       \
 } while (0)
 
+/* On SNB platform, before reading ring registers forcewake bit
+ * must be set to prevent GT core from power down and stale values being
+ * returned.
+ */
+void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
+void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
+void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
+
+/* We give fast paths for the really cool registers */
+#define NEEDS_FORCE_WAKE(dev_priv, reg) \
+       (((dev_priv)->info->gen >= 6) && \
+       ((reg) < 0x40000) && \
+       ((reg) != FORCEWAKE))
 
 #define __i915_read(x, y) \
 static inline u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
-       u##x val = read##y(dev_priv->regs + reg); \
+       u##x val = 0; \
+       if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
+               gen6_gt_force_wake_get(dev_priv); \
+               val = read##y(dev_priv->regs + reg); \
+               gen6_gt_force_wake_put(dev_priv); \
+       } else { \
+               val = read##y(dev_priv->regs + reg); \
+       } \
        trace_i915_reg_rw(false, reg, val, sizeof(val)); \
        return val; \
 }
+
 __i915_read(8, b)
 __i915_read(16, w)
 __i915_read(32, l)
@@ -1328,6 +1389,9 @@ __i915_read(64, q)
 #define __i915_write(x, y) \
 static inline void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
        trace_i915_reg_rw(true, reg, val, sizeof(val)); \
+       if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
+               __gen6_gt_wait_for_fifo(dev_priv); \
+       } \
        write##y(val, dev_priv->regs + reg); \
 }
 __i915_write(8, b)
@@ -1356,33 +1420,4 @@ __i915_write(64, q)
 #define POSTING_READ16(reg)    (void)I915_READ16_NOTRACE(reg)
 
 
-/* On SNB platform, before reading ring registers forcewake bit
- * must be set to prevent GT core from power down and stale values being
- * returned.
- */
-void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
-void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
-void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
-
-static inline u32 i915_gt_read(struct drm_i915_private *dev_priv, u32 reg)
-{
-       u32 val;
-
-       if (dev_priv->info->gen >= 6) {
-               __gen6_gt_force_wake_get(dev_priv);
-               val = I915_READ(reg);
-               __gen6_gt_force_wake_put(dev_priv);
-       } else
-               val = I915_READ(reg);
-
-       return val;
-}
-
-static inline void i915_gt_write(struct drm_i915_private *dev_priv,
-                               u32 reg, u32 val)
-{
-       if (dev_priv->info->gen >= 6)
-               __gen6_gt_wait_for_fifo(dev_priv);
-       I915_WRITE(reg, val);
-}
 #endif
index 7ce3f353af33657e612f40887a89aefb9b936dda..c6389de531612c11d78439207ebd051ba804e3a1 100644 (file)
@@ -56,9 +56,7 @@ static int i915_gem_phys_pwrite(struct drm_device *dev,
 static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj);
 
 static int i915_gem_inactive_shrink(struct shrinker *shrinker,
-                                   int nr_to_scan,
-                                   gfp_t gfp_mask);
-
+                                   struct shrink_control *sc);
 
 /* some bookkeeping */
 static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv,
@@ -356,7 +354,7 @@ i915_gem_shmem_pread_fast(struct drm_device *dev,
                 * page_offset = offset within page
                 * page_length = bytes to copy for this page
                 */
-               page_offset = offset & (PAGE_SIZE-1);
+               page_offset = offset_in_page(offset);
                page_length = remain;
                if ((page_offset + remain) > PAGE_SIZE)
                        page_length = PAGE_SIZE - page_offset;
@@ -455,9 +453,9 @@ i915_gem_shmem_pread_slow(struct drm_device *dev,
                 * data_page_offset = offset with data_page_index page.
                 * page_length = bytes to copy for this page
                 */
-               shmem_page_offset = offset & ~PAGE_MASK;
+               shmem_page_offset = offset_in_page(offset);
                data_page_index = data_ptr / PAGE_SIZE - first_data_page;
-               data_page_offset = data_ptr & ~PAGE_MASK;
+               data_page_offset = offset_in_page(data_ptr);
 
                page_length = remain;
                if ((shmem_page_offset + page_length) > PAGE_SIZE)
@@ -467,8 +465,10 @@ i915_gem_shmem_pread_slow(struct drm_device *dev,
 
                page = read_cache_page_gfp(mapping, offset >> PAGE_SHIFT,
                                           GFP_HIGHUSER | __GFP_RECLAIMABLE);
-               if (IS_ERR(page))
-                       return PTR_ERR(page);
+               if (IS_ERR(page)) {
+                       ret = PTR_ERR(page);
+                       goto out;
+               }
 
                if (do_bit17_swizzling) {
                        slow_shmem_bit17_copy(page,
@@ -640,8 +640,8 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
                 * page_offset = offset within page
                 * page_length = bytes to copy for this page
                 */
-               page_base = (offset & ~(PAGE_SIZE-1));
-               page_offset = offset & (PAGE_SIZE-1);
+               page_base = offset & PAGE_MASK;
+               page_offset = offset_in_page(offset);
                page_length = remain;
                if ((page_offset + remain) > PAGE_SIZE)
                        page_length = PAGE_SIZE - page_offset;
@@ -652,7 +652,6 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
                 */
                if (fast_user_write(dev_priv->mm.gtt_mapping, page_base,
                                    page_offset, user_data, page_length))
-
                        return -EFAULT;
 
                remain -= page_length;
@@ -732,9 +731,9 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev,
                 * page_length = bytes to copy for this page
                 */
                gtt_page_base = offset & PAGE_MASK;
-               gtt_page_offset = offset & ~PAGE_MASK;
+               gtt_page_offset = offset_in_page(offset);
                data_page_index = data_ptr / PAGE_SIZE - first_data_page;
-               data_page_offset = data_ptr & ~PAGE_MASK;
+               data_page_offset = offset_in_page(data_ptr);
 
                page_length = remain;
                if ((gtt_page_offset + page_length) > PAGE_SIZE)
@@ -793,7 +792,7 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev,
                 * page_offset = offset within page
                 * page_length = bytes to copy for this page
                 */
-               page_offset = offset & (PAGE_SIZE-1);
+               page_offset = offset_in_page(offset);
                page_length = remain;
                if ((page_offset + remain) > PAGE_SIZE)
                        page_length = PAGE_SIZE - page_offset;
@@ -898,9 +897,9 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev,
                 * data_page_offset = offset with data_page_index page.
                 * page_length = bytes to copy for this page
                 */
-               shmem_page_offset = offset & ~PAGE_MASK;
+               shmem_page_offset = offset_in_page(offset);
                data_page_index = data_ptr / PAGE_SIZE - first_data_page;
-               data_page_offset = data_ptr & ~PAGE_MASK;
+               data_page_offset = offset_in_page(data_ptr);
 
                page_length = remain;
                if ((shmem_page_offset + page_length) > PAGE_SIZE)
@@ -1220,11 +1219,11 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                ret = i915_gem_object_bind_to_gtt(obj, 0, true);
                if (ret)
                        goto unlock;
-       }
 
-       ret = i915_gem_object_set_to_gtt_domain(obj, write);
-       if (ret)
-               goto unlock;
+               ret = i915_gem_object_set_to_gtt_domain(obj, write);
+               if (ret)
+                       goto unlock;
+       }
 
        if (obj->tiling_mode == I915_TILING_NONE)
                ret = i915_gem_object_put_fence(obj);
@@ -1452,8 +1451,9 @@ i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj)
         * edge of an even tile row (where tile rows are counted as if the bo is
         * placed in a fenced gtt region).
         */
-       if (IS_GEN2(dev) ||
-           (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)))
+       if (IS_GEN2(dev))
+               tile_height = 16;
+       else if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))
                tile_height = 32;
        else
                tile_height = 8;
@@ -2673,6 +2673,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj,
 update:
        obj->tiling_changed = false;
        switch (INTEL_INFO(dev)->gen) {
+       case 7:
        case 6:
                ret = sandybridge_write_fence_reg(obj, pipelined);
                break;
@@ -2706,6 +2707,7 @@ i915_gem_clear_fence_reg(struct drm_device *dev,
        uint32_t fence_reg = reg - dev_priv->fence_regs;
 
        switch (INTEL_INFO(dev)->gen) {
+       case 7:
        case 6:
                I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + fence_reg*8, 0);
                break;
@@ -2878,6 +2880,17 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj)
        if (obj->pages == NULL)
                return;
 
+       /* If the GPU is snooping the contents of the CPU cache,
+        * we do not need to manually clear the CPU cache lines.  However,
+        * the caches are only snooped when the render cache is
+        * flushed/invalidated.  As we always have to emit invalidations
+        * and flushes when moving into and out of the RENDER domain, correct
+        * snooping behaviour occurs naturally as the result of our domain
+        * tracking.
+        */
+       if (obj->cache_level != I915_CACHE_NONE)
+               return;
+
        trace_i915_gem_object_clflush(obj);
 
        drm_clflush_pages(obj->pages, obj->base.size / PAGE_SIZE);
@@ -2913,8 +2926,6 @@ i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj)
         */
        wmb();
 
-       i915_gem_release_mmap(obj);
-
        old_write_domain = obj->base.write_domain;
        obj->base.write_domain = 0;
 
@@ -3569,7 +3580,7 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
        obj->base.write_domain = I915_GEM_DOMAIN_CPU;
        obj->base.read_domains = I915_GEM_DOMAIN_CPU;
 
-       obj->agp_type = AGP_USER_MEMORY;
+       obj->cache_level = I915_CACHE_NONE;
        obj->base.driver_private = NULL;
        obj->fence_reg = I915_FENCE_REG_NONE;
        INIT_LIST_HEAD(&obj->mm_list);
@@ -3845,25 +3856,10 @@ i915_gem_load(struct drm_device *dev)
                dev_priv->num_fence_regs = 8;
 
        /* Initialize fence registers to zero */
-       switch (INTEL_INFO(dev)->gen) {
-       case 6:
-               for (i = 0; i < 16; i++)
-                       I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), 0);
-               break;
-       case 5:
-       case 4:
-               for (i = 0; i < 16; i++)
-                       I915_WRITE64(FENCE_REG_965_0 + (i * 8), 0);
-               break;
-       case 3:
-               if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
-                       for (i = 0; i < 8; i++)
-                               I915_WRITE(FENCE_REG_945_8 + (i * 4), 0);
-       case 2:
-               for (i = 0; i < 8; i++)
-                       I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
-               break;
+       for (i = 0; i < dev_priv->num_fence_regs; i++) {
+               i915_gem_clear_fence_reg(dev, &dev_priv->fence_regs[i]);
        }
+
        i915_gem_detect_bit_6_swizzle(dev);
        init_waitqueue_head(&dev_priv->pending_flip_queue);
 
@@ -4094,9 +4090,7 @@ i915_gpu_is_active(struct drm_device *dev)
 }
 
 static int
-i915_gem_inactive_shrink(struct shrinker *shrinker,
-                        int nr_to_scan,
-                        gfp_t gfp_mask)
+i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
 {
        struct drm_i915_private *dev_priv =
                container_of(shrinker,
@@ -4104,6 +4098,7 @@ i915_gem_inactive_shrink(struct shrinker *shrinker,
                             mm.inactive_shrinker);
        struct drm_device *dev = dev_priv->dev;
        struct drm_i915_gem_object *obj, *next;
+       int nr_to_scan = sc->nr_to_scan;
        int cnt;
 
        if (!mutex_trylock(&dev->struct_mutex))
index 20a4cc5b818f51632ad50a94bdfa4092c3f1a454..4934cf84c320336aa84320da544cc1e0d091da1c 100644 (file)
@@ -187,10 +187,6 @@ i915_gem_object_set_to_gpu_domain(struct drm_i915_gem_object *obj,
        if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU)
                i915_gem_clflush_object(obj);
 
-       /* blow away mappings if mapped through GTT */
-       if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_GTT)
-               i915_gem_release_mmap(obj);
-
        if (obj->base.pending_write_domain)
                cd->flips |= atomic_read(&obj->pending_flip);
 
index b0abdc64aa9f63aba4b018626da562421deb2a84..e46b645773cfcb7ca65352996d49761a8cf7872f 100644 (file)
 #include "i915_trace.h"
 #include "intel_drv.h"
 
+/* XXX kill agp_type! */
+static unsigned int cache_level_to_agp_type(struct drm_device *dev,
+                                           enum i915_cache_level cache_level)
+{
+       switch (cache_level) {
+       case I915_CACHE_LLC_MLC:
+               if (INTEL_INFO(dev)->gen >= 6)
+                       return AGP_USER_CACHED_MEMORY_LLC_MLC;
+               /* Older chipsets do not have this extra level of CPU
+                * cacheing, so fallthrough and request the PTE simply
+                * as cached.
+                */
+       case I915_CACHE_LLC:
+               return AGP_USER_CACHED_MEMORY;
+       default:
+       case I915_CACHE_NONE:
+               return AGP_USER_MEMORY;
+       }
+}
+
 void i915_gem_restore_gtt_mappings(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -39,6 +59,9 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
                              (dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE);
 
        list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
+               unsigned int agp_type =
+                       cache_level_to_agp_type(dev, obj->cache_level);
+
                i915_gem_clflush_object(obj);
 
                if (dev_priv->mm.gtt->needs_dmar) {
@@ -46,15 +69,14 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
 
                        intel_gtt_insert_sg_entries(obj->sg_list,
                                                    obj->num_sg,
-                                                   obj->gtt_space->start
-                                                       >> PAGE_SHIFT,
-                                                   obj->agp_type);
+                                                   obj->gtt_space->start >> PAGE_SHIFT,
+                                                   agp_type);
                } else
                        intel_gtt_insert_pages(obj->gtt_space->start
                                                   >> PAGE_SHIFT,
                                               obj->base.size >> PAGE_SHIFT,
                                               obj->pages,
-                                              obj->agp_type);
+                                              agp_type);
        }
 
        intel_gtt_chipset_flush();
@@ -64,6 +86,7 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
 {
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned int agp_type = cache_level_to_agp_type(dev, obj->cache_level);
        int ret;
 
        if (dev_priv->mm.gtt->needs_dmar) {
@@ -77,12 +100,12 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
                intel_gtt_insert_sg_entries(obj->sg_list,
                                            obj->num_sg,
                                            obj->gtt_space->start >> PAGE_SHIFT,
-                                           obj->agp_type);
+                                           agp_type);
        } else
                intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT,
                                       obj->base.size >> PAGE_SHIFT,
                                       obj->pages,
-                                      obj->agp_type);
+                                      agp_type);
 
        return 0;
 }
index 281ad3d6115d08a3f40a666b60673b0d22cd6d6e..82d70fd9e933b8aff68afeffca08dca89e937fe2 100644 (file)
@@ -92,7 +92,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
        uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
        uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
 
-       if (IS_GEN5(dev) || IS_GEN6(dev)) {
+       if (INTEL_INFO(dev)->gen >= 5) {
                /* On Ironlake whatever DRAM config, GPU always do
                 * same swizzling setup.
                 */
index 188b497e50768d56a3a93f2422000c03a0bcaddf..ae2b49969b995c0b1c7f7f76f65d2426ea003522 100644 (file)
@@ -367,22 +367,30 @@ static void notify_ring(struct drm_device *dev,
                  jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
 }
 
-static void gen6_pm_irq_handler(struct drm_device *dev)
+static void gen6_pm_rps_work(struct work_struct *work)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
+                                                   rps_work);
        u8 new_delay = dev_priv->cur_delay;
-       u32 pm_iir;
+       u32 pm_iir, pm_imr;
+
+       spin_lock_irq(&dev_priv->rps_lock);
+       pm_iir = dev_priv->pm_iir;
+       dev_priv->pm_iir = 0;
+       pm_imr = I915_READ(GEN6_PMIMR);
+       spin_unlock_irq(&dev_priv->rps_lock);
 
-       pm_iir = I915_READ(GEN6_PMIIR);
        if (!pm_iir)
                return;
 
+       mutex_lock(&dev_priv->dev->struct_mutex);
        if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
                if (dev_priv->cur_delay != dev_priv->max_delay)
                        new_delay = dev_priv->cur_delay + 1;
                if (new_delay > dev_priv->max_delay)
                        new_delay = dev_priv->max_delay;
        } else if (pm_iir & (GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT)) {
+               gen6_gt_force_wake_get(dev_priv);
                if (dev_priv->cur_delay != dev_priv->min_delay)
                        new_delay = dev_priv->cur_delay - 1;
                if (new_delay < dev_priv->min_delay) {
@@ -396,13 +404,19 @@ static void gen6_pm_irq_handler(struct drm_device *dev)
                        I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
                                   I915_READ(GEN6_RP_INTERRUPT_LIMITS) & ~0x3f0000);
                }
-
+               gen6_gt_force_wake_put(dev_priv);
        }
 
-       gen6_set_rps(dev, new_delay);
+       gen6_set_rps(dev_priv->dev, new_delay);
        dev_priv->cur_delay = new_delay;
 
-       I915_WRITE(GEN6_PMIIR, pm_iir);
+       /*
+        * rps_lock not held here because clearing is non-destructive. There is
+        * an *extremely* unlikely race with gen6_rps_enable() that is prevented
+        * by holding struct_mutex for the duration of the write.
+        */
+       I915_WRITE(GEN6_PMIMR, pm_imr & ~pm_iir);
+       mutex_unlock(&dev_priv->dev->struct_mutex);
 }
 
 static void pch_irq_handler(struct drm_device *dev)
@@ -448,8 +462,97 @@ static void pch_irq_handler(struct drm_device *dev)
                DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n");
 }
 
-static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
+irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS)
 {
+       struct drm_device *dev = (struct drm_device *) arg;
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       int ret = IRQ_NONE;
+       u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
+       struct drm_i915_master_private *master_priv;
+
+       atomic_inc(&dev_priv->irq_received);
+
+       /* disable master interrupt before clearing iir  */
+       de_ier = I915_READ(DEIER);
+       I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
+       POSTING_READ(DEIER);
+
+       de_iir = I915_READ(DEIIR);
+       gt_iir = I915_READ(GTIIR);
+       pch_iir = I915_READ(SDEIIR);
+       pm_iir = I915_READ(GEN6_PMIIR);
+
+       if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 && pm_iir == 0)
+               goto done;
+
+       ret = IRQ_HANDLED;
+
+       if (dev->primary->master) {
+               master_priv = dev->primary->master->driver_priv;
+               if (master_priv->sarea_priv)
+                       master_priv->sarea_priv->last_dispatch =
+                               READ_BREADCRUMB(dev_priv);
+       }
+
+       if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY))
+               notify_ring(dev, &dev_priv->ring[RCS]);
+       if (gt_iir & GT_GEN6_BSD_USER_INTERRUPT)
+               notify_ring(dev, &dev_priv->ring[VCS]);
+       if (gt_iir & GT_BLT_USER_INTERRUPT)
+               notify_ring(dev, &dev_priv->ring[BCS]);
+
+       if (de_iir & DE_GSE_IVB)
+               intel_opregion_gse_intr(dev);
+
+       if (de_iir & DE_PLANEA_FLIP_DONE_IVB) {
+               intel_prepare_page_flip(dev, 0);
+               intel_finish_page_flip_plane(dev, 0);
+       }
+
+       if (de_iir & DE_PLANEB_FLIP_DONE_IVB) {
+               intel_prepare_page_flip(dev, 1);
+               intel_finish_page_flip_plane(dev, 1);
+       }
+
+       if (de_iir & DE_PIPEA_VBLANK_IVB)
+               drm_handle_vblank(dev, 0);
+
+       if (de_iir & DE_PIPEB_VBLANK_IVB)
+               drm_handle_vblank(dev, 1);
+
+       /* check event from PCH */
+       if (de_iir & DE_PCH_EVENT_IVB) {
+               if (pch_iir & SDE_HOTPLUG_MASK_CPT)
+                       queue_work(dev_priv->wq, &dev_priv->hotplug_work);
+               pch_irq_handler(dev);
+       }
+
+       if (pm_iir & GEN6_PM_DEFERRED_EVENTS) {
+               unsigned long flags;
+               spin_lock_irqsave(&dev_priv->rps_lock, flags);
+               WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
+               I915_WRITE(GEN6_PMIMR, pm_iir);
+               dev_priv->pm_iir |= pm_iir;
+               spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
+               queue_work(dev_priv->wq, &dev_priv->rps_work);
+       }
+
+       /* should clear PCH hotplug event before clear CPU irq */
+       I915_WRITE(SDEIIR, pch_iir);
+       I915_WRITE(GTIIR, gt_iir);
+       I915_WRITE(DEIIR, de_iir);
+       I915_WRITE(GEN6_PMIIR, pm_iir);
+
+done:
+       I915_WRITE(DEIER, de_ier);
+       POSTING_READ(DEIER);
+
+       return ret;
+}
+
+irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
+{
+       struct drm_device *dev = (struct drm_device *) arg;
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int ret = IRQ_NONE;
        u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
@@ -457,6 +560,8 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
        struct drm_i915_master_private *master_priv;
        u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
 
+       atomic_inc(&dev_priv->irq_received);
+
        if (IS_GEN6(dev))
                bsd_usr_interrupt = GT_GEN6_BSD_USER_INTERRUPT;
 
@@ -526,13 +631,30 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
                i915_handle_rps_change(dev);
        }
 
-       if (IS_GEN6(dev))
-               gen6_pm_irq_handler(dev);
+       if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) {
+               /*
+                * IIR bits should never already be set because IMR should
+                * prevent an interrupt from being shown in IIR. The warning
+                * displays a case where we've unsafely cleared
+                * dev_priv->pm_iir. Although missing an interrupt of the same
+                * type is not a problem, it displays a problem in the logic.
+                *
+                * The mask bit in IMR is cleared by rps_work.
+                */
+               unsigned long flags;
+               spin_lock_irqsave(&dev_priv->rps_lock, flags);
+               WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
+               I915_WRITE(GEN6_PMIMR, pm_iir);
+               dev_priv->pm_iir |= pm_iir;
+               spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
+               queue_work(dev_priv->wq, &dev_priv->rps_work);
+       }
 
        /* should clear PCH hotplug event before clear CPU irq */
        I915_WRITE(SDEIIR, pch_iir);
        I915_WRITE(GTIIR, gt_iir);
        I915_WRITE(DEIIR, de_iir);
+       I915_WRITE(GEN6_PMIIR, pm_iir);
 
 done:
        I915_WRITE(DEIER, de_ier);
@@ -676,7 +798,7 @@ static u32 capture_bo_list(struct drm_i915_error_buffer *err,
                err->dirty = obj->dirty;
                err->purgeable = obj->madv != I915_MADV_WILLNEED;
                err->ring = obj->ring ? obj->ring->id : 0;
-               err->agp_type = obj->agp_type == AGP_USER_CACHED_MEMORY;
+               err->cache_level = obj->cache_level;
 
                if (++i == count)
                        break;
@@ -1103,9 +1225,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 
        atomic_inc(&dev_priv->irq_received);
 
-       if (HAS_PCH_SPLIT(dev))
-               return ironlake_irq_handler(dev);
-
        iir = I915_READ(IIR);
 
        if (INTEL_INFO(dev)->gen >= 4)
@@ -1344,10 +1463,7 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
                return -EINVAL;
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       if (HAS_PCH_SPLIT(dev))
-               ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
-                                           DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
-       else if (INTEL_INFO(dev)->gen >= 4)
+       if (INTEL_INFO(dev)->gen >= 4)
                i915_enable_pipestat(dev_priv, pipe,
                                     PIPE_START_VBLANK_INTERRUPT_ENABLE);
        else
@@ -1362,6 +1478,38 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
        return 0;
 }
 
+int ironlake_enable_vblank(struct drm_device *dev, int pipe)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       unsigned long irqflags;
+
+       if (!i915_pipe_enabled(dev, pipe))
+               return -EINVAL;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
+                                   DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+       return 0;
+}
+
+int ivybridge_enable_vblank(struct drm_device *dev, int pipe)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       unsigned long irqflags;
+
+       if (!i915_pipe_enabled(dev, pipe))
+               return -EINVAL;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
+                                   DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+       return 0;
+}
+
 /* Called from drm generic code, passed 'crtc' which
  * we use as a pipe index
  */
@@ -1375,13 +1523,31 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
                I915_WRITE(INSTPM,
                           INSTPM_AGPBUSY_DIS << 16 | INSTPM_AGPBUSY_DIS);
 
-       if (HAS_PCH_SPLIT(dev))
-               ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
-                                            DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
-       else
-               i915_disable_pipestat(dev_priv, pipe,
-                                     PIPE_VBLANK_INTERRUPT_ENABLE |
-                                     PIPE_START_VBLANK_INTERRUPT_ENABLE);
+       i915_disable_pipestat(dev_priv, pipe,
+                             PIPE_VBLANK_INTERRUPT_ENABLE |
+                             PIPE_START_VBLANK_INTERRUPT_ENABLE);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+}
+
+void ironlake_disable_vblank(struct drm_device *dev, int pipe)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
+                                    DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+}
+
+void ivybridge_disable_vblank(struct drm_device *dev, int pipe)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
+                                    DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
@@ -1562,11 +1728,29 @@ repeat:
 
 /* drm_dma.h hooks
 */
-static void ironlake_irq_preinstall(struct drm_device *dev)
+void ironlake_irq_preinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
+       atomic_set(&dev_priv->irq_received, 0);
+
+       INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
+       INIT_WORK(&dev_priv->error_work, i915_error_work_func);
+       if (IS_GEN6(dev) || IS_IVYBRIDGE(dev))
+               INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work);
+
        I915_WRITE(HWSTAM, 0xeffe);
+       if (IS_GEN6(dev)) {
+               /* Workaround stalls observed on Sandy Bridge GPUs by
+                * making the blitter command streamer generate a
+                * write to the Hardware Status Page for
+                * MI_USER_INTERRUPT.  This appears to serialize the
+                * previous seqno write out before the interrupt
+                * happens.
+                */
+               I915_WRITE(GEN6_BLITTER_HWSTAM, ~GEN6_BLITTER_USER_INTERRUPT);
+               I915_WRITE(GEN6_BSD_HWSTAM, ~GEN6_BSD_USER_INTERRUPT);
+       }
 
        /* XXX hotplug from PCH */
 
@@ -1585,7 +1769,7 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
        POSTING_READ(SDEIER);
 }
 
-static int ironlake_irq_postinstall(struct drm_device *dev)
+int ironlake_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        /* enable kind of interrupts always enabled */
@@ -1594,6 +1778,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        u32 render_irqs;
        u32 hotplug_mask;
 
+       DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
+       if (HAS_BSD(dev))
+               DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
+       if (HAS_BLT(dev))
+               DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
+
+       dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
        dev_priv->irq_mask = ~display_mask;
 
        /* should always can generate irq */
@@ -1650,6 +1841,56 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        return 0;
 }
 
+int ivybridge_irq_postinstall(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       /* enable kind of interrupts always enabled */
+       u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
+               DE_PCH_EVENT_IVB | DE_PLANEA_FLIP_DONE_IVB |
+               DE_PLANEB_FLIP_DONE_IVB;
+       u32 render_irqs;
+       u32 hotplug_mask;
+
+       DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
+       if (HAS_BSD(dev))
+               DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
+       if (HAS_BLT(dev))
+               DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
+
+       dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
+       dev_priv->irq_mask = ~display_mask;
+
+       /* should always can generate irq */
+       I915_WRITE(DEIIR, I915_READ(DEIIR));
+       I915_WRITE(DEIMR, dev_priv->irq_mask);
+       I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK_IVB |
+                  DE_PIPEB_VBLANK_IVB);
+       POSTING_READ(DEIER);
+
+       dev_priv->gt_irq_mask = ~0;
+
+       I915_WRITE(GTIIR, I915_READ(GTIIR));
+       I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+
+       render_irqs = GT_USER_INTERRUPT | GT_GEN6_BSD_USER_INTERRUPT |
+               GT_BLT_USER_INTERRUPT;
+       I915_WRITE(GTIER, render_irqs);
+       POSTING_READ(GTIER);
+
+       hotplug_mask = (SDE_CRT_HOTPLUG_CPT |
+                       SDE_PORTB_HOTPLUG_CPT |
+                       SDE_PORTC_HOTPLUG_CPT |
+                       SDE_PORTD_HOTPLUG_CPT);
+       dev_priv->pch_irq_mask = ~hotplug_mask;
+
+       I915_WRITE(SDEIIR, I915_READ(SDEIIR));
+       I915_WRITE(SDEIMR, dev_priv->pch_irq_mask);
+       I915_WRITE(SDEIER, hotplug_mask);
+       POSTING_READ(SDEIER);
+
+       return 0;
+}
+
 void i915_driver_irq_preinstall(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -1660,11 +1901,6 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
        INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
        INIT_WORK(&dev_priv->error_work, i915_error_work_func);
 
-       if (HAS_PCH_SPLIT(dev)) {
-               ironlake_irq_preinstall(dev);
-               return;
-       }
-
        if (I915_HAS_HOTPLUG(dev)) {
                I915_WRITE(PORT_HOTPLUG_EN, 0);
                I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -1688,17 +1924,8 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
        u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
        u32 error_mask;
 
-       DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
-       if (HAS_BSD(dev))
-               DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
-       if (HAS_BLT(dev))
-               DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
-
        dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
 
-       if (HAS_PCH_SPLIT(dev))
-               return ironlake_irq_postinstall(dev);
-
        /* Unmask the interrupts that we always want on. */
        dev_priv->irq_mask = ~I915_INTERRUPT_ENABLE_FIX;
 
@@ -1767,9 +1994,15 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
        return 0;
 }
 
-static void ironlake_irq_uninstall(struct drm_device *dev)
+void ironlake_irq_uninstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+       if (!dev_priv)
+               return;
+
+       dev_priv->vblank_pipe = 0;
+
        I915_WRITE(HWSTAM, 0xffffffff);
 
        I915_WRITE(DEIMR, 0xffffffff);
@@ -1791,11 +2024,6 @@ void i915_driver_irq_uninstall(struct drm_device * dev)
 
        dev_priv->vblank_pipe = 0;
 
-       if (HAS_PCH_SPLIT(dev)) {
-               ironlake_irq_uninstall(dev);
-               return;
-       }
-
        if (I915_HAS_HOTPLUG(dev)) {
                I915_WRITE(PORT_HOTPLUG_EN, 0);
                I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
index f39ac3a0fa9339e3d5ae4276e5ec354ad410746b..5d5def756c9e5beee9ae10def1cbe39d5f7cf02f 100644 (file)
 #define RING_MAX_IDLE(base)    ((base)+0x54)
 #define RING_HWS_PGA(base)     ((base)+0x80)
 #define RING_HWS_PGA_GEN6(base)        ((base)+0x2080)
+#define RENDER_HWS_PGA_GEN7    (0x04080)
+#define BSD_HWS_PGA_GEN7       (0x04180)
+#define BLT_HWS_PGA_GEN7       (0x04280)
 #define RING_ACTHD(base)       ((base)+0x74)
 #define RING_NOPID(base)       ((base)+0x94)
 #define RING_IMR(base)         ((base)+0xa8)
 #define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE           0
 #define   GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR                   (1 << 3)
 
+#define GEN6_BSD_HWSTAM                        0x12098
 #define GEN6_BSD_IMR                   0x120a8
 #define   GEN6_BSD_USER_INTERRUPT      (1 << 12)
 
 #define DE_PIPEA_VSYNC          (1 << 3)
 #define DE_PIPEA_FIFO_UNDERRUN  (1 << 0)
 
+/* More Ivybridge lolz */
+#define DE_ERR_DEBUG_IVB               (1<<30)
+#define DE_GSE_IVB                     (1<<29)
+#define DE_PCH_EVENT_IVB               (1<<28)
+#define DE_DP_A_HOTPLUG_IVB            (1<<27)
+#define DE_AUX_CHANNEL_A_IVB           (1<<26)
+#define DE_SPRITEB_FLIP_DONE_IVB       (1<<9)
+#define DE_SPRITEA_FLIP_DONE_IVB       (1<<4)
+#define DE_PLANEB_FLIP_DONE_IVB                (1<<8)
+#define DE_PLANEA_FLIP_DONE_IVB                (1<<3)
+#define DE_PIPEB_VBLANK_IVB            (1<<5)
+#define DE_PIPEA_VBLANK_IVB            (1<<0)
+
 #define DEISR   0x44000
 #define DEIMR   0x44004
 #define DEIIR   0x44008
 #define  ILK_eDP_A_DISABLE             (1<<24)
 #define  ILK_DESKTOP                   (1<<23)
 #define ILK_DSPCLK_GATE                0x42020
+#define  IVB_VRHUNIT_CLK_GATE  (1<<28)
 #define  ILK_DPARB_CLK_GATE    (1<<5)
 #define  ILK_DPFD_CLK_GATE     (1<<7)
 
 #define  TRANS_6BPC             (2<<5)
 #define  TRANS_12BPC            (3<<5)
 
+#define SOUTH_CHICKEN2         0xc2004
+#define  DPLS_EDP_PPS_FIX_DIS  (1<<0)
+
 #define _FDI_RXA_CHICKEN         0xc200c
 #define _FDI_RXB_CHICKEN         0xc2010
 #define  FDI_RX_PHASE_SYNC_POINTER_OVR (1<<1)
 #define  FDI_TX_ENHANCE_FRAME_ENABLE    (1<<18)
 /* Ironlake: hardwired to 1 */
 #define  FDI_TX_PLL_ENABLE              (1<<14)
+
+/* Ivybridge has different bits for lolz */
+#define  FDI_LINK_TRAIN_PATTERN_1_IVB       (0<<8)
+#define  FDI_LINK_TRAIN_PATTERN_2_IVB       (1<<8)
+#define  FDI_LINK_TRAIN_PATTERN_IDLE_IVB    (2<<8)
+#define  FDI_LINK_TRAIN_NONE_IVB            (3<<8)
+
 /* both Tx and Rx */
+#define  FDI_LINK_TRAIN_AUTO           (1<<10)
 #define  FDI_SCRAMBLING_ENABLE          (0<<7)
 #define  FDI_SCRAMBLING_DISABLE         (1<<7)
 
 #define FDI_RX_CTL(pipe) _PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL)
 #define  FDI_RX_ENABLE          (1<<31)
 /* train, dp width same as FDI_TX */
+#define  FDI_FS_ERRC_ENABLE            (1<<27)
+#define  FDI_FE_ERRC_ENABLE            (1<<26)
 #define  FDI_DP_PORT_WIDTH_X8           (7<<19)
 #define  FDI_8BPC                       (0<<16)
 #define  FDI_10BPC                      (1<<16)
 #define GEN6_PMINTRMSK                         0xA168
 
 #define GEN6_PMISR                             0x44020
-#define GEN6_PMIMR                             0x44024
+#define GEN6_PMIMR                             0x44024 /* rps_lock */
 #define GEN6_PMIIR                             0x44028
 #define GEN6_PMIER                             0x4402C
 #define  GEN6_PM_MBOX_EVENT                    (1<<25)
 #define  GEN6_PM_RP_DOWN_THRESHOLD             (1<<4)
 #define  GEN6_PM_RP_UP_EI_EXPIRED              (1<<2)
 #define  GEN6_PM_RP_DOWN_EI_EXPIRED            (1<<1)
+#define  GEN6_PM_DEFERRED_EVENTS               (GEN6_PM_RP_UP_THRESHOLD | \
+                                                GEN6_PM_RP_DOWN_THRESHOLD | \
+                                                GEN6_PM_RP_DOWN_TIMEOUT)
 
 #define GEN6_PCODE_MAILBOX                     0x138124
 #define   GEN6_PCODE_READY                     (1<<31)
index da474153a0a228626cef23e08b5d3c9566642dee..e8152d23d5b67c31ecf77b39f7250df71cb12bca 100644 (file)
@@ -678,6 +678,7 @@ void i915_save_display(struct drm_device *dev)
        }
 
        /* VGA state */
+       mutex_lock(&dev->struct_mutex);
        dev_priv->saveVGA0 = I915_READ(VGA0);
        dev_priv->saveVGA1 = I915_READ(VGA1);
        dev_priv->saveVGA_PD = I915_READ(VGA_PD);
@@ -687,6 +688,7 @@ void i915_save_display(struct drm_device *dev)
                dev_priv->saveVGACNTRL = I915_READ(VGACNTRL);
 
        i915_save_vga(dev);
+       mutex_unlock(&dev->struct_mutex);
 }
 
 void i915_restore_display(struct drm_device *dev)
@@ -780,6 +782,8 @@ void i915_restore_display(struct drm_device *dev)
                I915_WRITE(CPU_VGACNTRL, dev_priv->saveVGACNTRL);
        else
                I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL);
+
+       mutex_lock(&dev->struct_mutex);
        I915_WRITE(VGA0, dev_priv->saveVGA0);
        I915_WRITE(VGA1, dev_priv->saveVGA1);
        I915_WRITE(VGA_PD, dev_priv->saveVGA_PD);
@@ -787,6 +791,7 @@ void i915_restore_display(struct drm_device *dev)
        udelay(150);
 
        i915_restore_vga(dev);
+       mutex_unlock(&dev->struct_mutex);
 }
 
 int i915_save_state(struct drm_device *dev)
@@ -863,8 +868,7 @@ int i915_restore_state(struct drm_device *dev)
                I915_WRITE(IMR, dev_priv->saveIMR);
        }
 
-       /* Clock gating state */
-       intel_enable_clock_gating(dev);
+       intel_init_clock_gating(dev);
 
        if (IS_IRONLAKE_M(dev)) {
                ironlake_enable_drps(dev);
index fb5b4d426ae0793baa93836cffe2aaf93c6f9241..927442a11925f990fcb45b5cba763a3cb7d521bc 100644 (file)
@@ -214,9 +214,9 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
            i915_lvds_downclock) {
                dev_priv->lvds_downclock_avail = 1;
                dev_priv->lvds_downclock = temp_downclock;
-               DRM_DEBUG_KMS("LVDS downclock is found in VBT. ",
-                               "Normal Clock %dKHz, downclock %dKHz\n",
-                               temp_downclock, panel_fixed_mode->clock);
+               DRM_DEBUG_KMS("LVDS downclock is found in VBT. "
+                             "Normal Clock %dKHz, downclock %dKHz\n",
+                             temp_downclock, panel_fixed_mode->clock);
        }
        return;
 }
index d03fc05b39c0e008236406a9820f459103154f10..0979d8877880d11acacd692de840660e6e60022c 100644 (file)
@@ -288,6 +288,8 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
                 * This may be a DVI-I connector with a shared DDC
                 * link between analog and digital outputs, so we
                 * have to check the EDID input spec of the attached device.
+                *
+                * On the other hand, what should we do if it is a broken EDID?
                 */
                if (edid != NULL) {
                        is_digital = edid->input & DRM_EDID_INPUT_DIGITAL;
@@ -298,6 +300,8 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
                if (!is_digital) {
                        DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
                        return true;
+               } else {
+                       DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n");
                }
        }
 
@@ -305,13 +309,11 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
 }
 
 static enum drm_connector_status
-intel_crt_load_detect(struct drm_crtc *crtc, struct intel_crt *crt)
+intel_crt_load_detect(struct intel_crt *crt)
 {
-       struct drm_encoder *encoder = &crt->base.base;
-       struct drm_device *dev = encoder->dev;
+       struct drm_device *dev = crt->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       uint32_t pipe = intel_crtc->pipe;
+       uint32_t pipe = to_intel_crtc(crt->base.base.crtc)->pipe;
        uint32_t save_bclrpat;
        uint32_t save_vtotal;
        uint32_t vtotal, vactive;
@@ -432,7 +434,6 @@ intel_crt_detect(struct drm_connector *connector, bool force)
        struct drm_device *dev = connector->dev;
        struct intel_crt *crt = intel_attached_crt(connector);
        struct drm_crtc *crtc;
-       int dpms_mode;
        enum drm_connector_status status;
 
        if (I915_HAS_HOTPLUG(dev)) {
@@ -454,17 +455,18 @@ intel_crt_detect(struct drm_connector *connector, bool force)
        /* for pre-945g platforms use load detect */
        crtc = crt->base.base.crtc;
        if (crtc && crtc->enabled) {
-               status = intel_crt_load_detect(crtc, crt);
+               status = intel_crt_load_detect(crt);
        } else {
-               crtc = intel_get_load_detect_pipe(&crt->base, connector,
-                                                 NULL, &dpms_mode);
-               if (crtc) {
+               struct intel_load_detect_pipe tmp;
+
+               if (intel_get_load_detect_pipe(&crt->base, connector, NULL,
+                                              &tmp)) {
                        if (intel_crt_detect_ddc(connector))
                                status = connector_status_connected;
                        else
-                               status = intel_crt_load_detect(crtc, crt);
-                       intel_release_load_detect_pipe(&crt->base,
-                                                      connector, dpms_mode);
+                               status = intel_crt_load_detect(crt);
+                       intel_release_load_detect_pipe(&crt->base, connector,
+                                                      &tmp);
                } else
                        status = connector_status_unknown;
        }
index 2166ee071ddbe99655c3c977beecec68bb6a7a19..aa43e7be6053bdfd6dc6fd7274d17ccd544b799f 100644 (file)
@@ -76,255 +76,6 @@ struct intel_limit {
                      int, int, intel_clock_t *);
 };
 
-#define I8XX_DOT_MIN             25000
-#define I8XX_DOT_MAX            350000
-#define I8XX_VCO_MIN            930000
-#define I8XX_VCO_MAX           1400000
-#define I8XX_N_MIN                   3
-#define I8XX_N_MAX                  16
-#define I8XX_M_MIN                  96
-#define I8XX_M_MAX                 140
-#define I8XX_M1_MIN                 18
-#define I8XX_M1_MAX                 26
-#define I8XX_M2_MIN                  6
-#define I8XX_M2_MAX                 16
-#define I8XX_P_MIN                   4
-#define I8XX_P_MAX                 128
-#define I8XX_P1_MIN                  2
-#define I8XX_P1_MAX                 33
-#define I8XX_P1_LVDS_MIN             1
-#define I8XX_P1_LVDS_MAX             6
-#define I8XX_P2_SLOW                 4
-#define I8XX_P2_FAST                 2
-#define I8XX_P2_LVDS_SLOW            14
-#define I8XX_P2_LVDS_FAST            7
-#define I8XX_P2_SLOW_LIMIT      165000
-
-#define I9XX_DOT_MIN             20000
-#define I9XX_DOT_MAX            400000
-#define I9XX_VCO_MIN           1400000
-#define I9XX_VCO_MAX           2800000
-#define PINEVIEW_VCO_MIN               1700000
-#define PINEVIEW_VCO_MAX               3500000
-#define I9XX_N_MIN                   1
-#define I9XX_N_MAX                   6
-/* Pineview's Ncounter is a ring counter */
-#define PINEVIEW_N_MIN               3
-#define PINEVIEW_N_MAX               6
-#define I9XX_M_MIN                  70
-#define I9XX_M_MAX                 120
-#define PINEVIEW_M_MIN               2
-#define PINEVIEW_M_MAX             256
-#define I9XX_M1_MIN                 10
-#define I9XX_M1_MAX                 22
-#define I9XX_M2_MIN                  5
-#define I9XX_M2_MAX                  9
-/* Pineview M1 is reserved, and must be 0 */
-#define PINEVIEW_M1_MIN                      0
-#define PINEVIEW_M1_MAX                      0
-#define PINEVIEW_M2_MIN                      0
-#define PINEVIEW_M2_MAX                      254
-#define I9XX_P_SDVO_DAC_MIN          5
-#define I9XX_P_SDVO_DAC_MAX         80
-#define I9XX_P_LVDS_MIN                      7
-#define I9XX_P_LVDS_MAX                     98
-#define PINEVIEW_P_LVDS_MIN                  7
-#define PINEVIEW_P_LVDS_MAX                 112
-#define I9XX_P1_MIN                  1
-#define I9XX_P1_MAX                  8
-#define I9XX_P2_SDVO_DAC_SLOW               10
-#define I9XX_P2_SDVO_DAC_FAST                5
-#define I9XX_P2_SDVO_DAC_SLOW_LIMIT     200000
-#define I9XX_P2_LVDS_SLOW                   14
-#define I9XX_P2_LVDS_FAST                    7
-#define I9XX_P2_LVDS_SLOW_LIMIT                 112000
-
-/*The parameter is for SDVO on G4x platform*/
-#define G4X_DOT_SDVO_MIN           25000
-#define G4X_DOT_SDVO_MAX           270000
-#define G4X_VCO_MIN                1750000
-#define G4X_VCO_MAX                3500000
-#define G4X_N_SDVO_MIN             1
-#define G4X_N_SDVO_MAX             4
-#define G4X_M_SDVO_MIN             104
-#define G4X_M_SDVO_MAX             138
-#define G4X_M1_SDVO_MIN            17
-#define G4X_M1_SDVO_MAX            23
-#define G4X_M2_SDVO_MIN            5
-#define G4X_M2_SDVO_MAX            11
-#define G4X_P_SDVO_MIN             10
-#define G4X_P_SDVO_MAX             30
-#define G4X_P1_SDVO_MIN            1
-#define G4X_P1_SDVO_MAX            3
-#define G4X_P2_SDVO_SLOW           10
-#define G4X_P2_SDVO_FAST           10
-#define G4X_P2_SDVO_LIMIT          270000
-
-/*The parameter is for HDMI_DAC on G4x platform*/
-#define G4X_DOT_HDMI_DAC_MIN           22000
-#define G4X_DOT_HDMI_DAC_MAX           400000
-#define G4X_N_HDMI_DAC_MIN             1
-#define G4X_N_HDMI_DAC_MAX             4
-#define G4X_M_HDMI_DAC_MIN             104
-#define G4X_M_HDMI_DAC_MAX             138
-#define G4X_M1_HDMI_DAC_MIN            16
-#define G4X_M1_HDMI_DAC_MAX            23
-#define G4X_M2_HDMI_DAC_MIN            5
-#define G4X_M2_HDMI_DAC_MAX            11
-#define G4X_P_HDMI_DAC_MIN             5
-#define G4X_P_HDMI_DAC_MAX             80
-#define G4X_P1_HDMI_DAC_MIN            1
-#define G4X_P1_HDMI_DAC_MAX            8
-#define G4X_P2_HDMI_DAC_SLOW           10
-#define G4X_P2_HDMI_DAC_FAST           5
-#define G4X_P2_HDMI_DAC_LIMIT          165000
-
-/*The parameter is for SINGLE_CHANNEL_LVDS on G4x platform*/
-#define G4X_DOT_SINGLE_CHANNEL_LVDS_MIN           20000
-#define G4X_DOT_SINGLE_CHANNEL_LVDS_MAX           115000
-#define G4X_N_SINGLE_CHANNEL_LVDS_MIN             1
-#define G4X_N_SINGLE_CHANNEL_LVDS_MAX             3
-#define G4X_M_SINGLE_CHANNEL_LVDS_MIN             104
-#define G4X_M_SINGLE_CHANNEL_LVDS_MAX             138
-#define G4X_M1_SINGLE_CHANNEL_LVDS_MIN            17
-#define G4X_M1_SINGLE_CHANNEL_LVDS_MAX            23
-#define G4X_M2_SINGLE_CHANNEL_LVDS_MIN            5
-#define G4X_M2_SINGLE_CHANNEL_LVDS_MAX            11
-#define G4X_P_SINGLE_CHANNEL_LVDS_MIN             28
-#define G4X_P_SINGLE_CHANNEL_LVDS_MAX             112
-#define G4X_P1_SINGLE_CHANNEL_LVDS_MIN            2
-#define G4X_P1_SINGLE_CHANNEL_LVDS_MAX            8
-#define G4X_P2_SINGLE_CHANNEL_LVDS_SLOW           14
-#define G4X_P2_SINGLE_CHANNEL_LVDS_FAST           14
-#define G4X_P2_SINGLE_CHANNEL_LVDS_LIMIT          0
-
-/*The parameter is for DUAL_CHANNEL_LVDS on G4x platform*/
-#define G4X_DOT_DUAL_CHANNEL_LVDS_MIN           80000
-#define G4X_DOT_DUAL_CHANNEL_LVDS_MAX           224000
-#define G4X_N_DUAL_CHANNEL_LVDS_MIN             1
-#define G4X_N_DUAL_CHANNEL_LVDS_MAX             3
-#define G4X_M_DUAL_CHANNEL_LVDS_MIN             104
-#define G4X_M_DUAL_CHANNEL_LVDS_MAX             138
-#define G4X_M1_DUAL_CHANNEL_LVDS_MIN            17
-#define G4X_M1_DUAL_CHANNEL_LVDS_MAX            23
-#define G4X_M2_DUAL_CHANNEL_LVDS_MIN            5
-#define G4X_M2_DUAL_CHANNEL_LVDS_MAX            11
-#define G4X_P_DUAL_CHANNEL_LVDS_MIN             14
-#define G4X_P_DUAL_CHANNEL_LVDS_MAX             42
-#define G4X_P1_DUAL_CHANNEL_LVDS_MIN            2
-#define G4X_P1_DUAL_CHANNEL_LVDS_MAX            6
-#define G4X_P2_DUAL_CHANNEL_LVDS_SLOW           7
-#define G4X_P2_DUAL_CHANNEL_LVDS_FAST           7
-#define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT          0
-
-/*The parameter is for DISPLAY PORT on G4x platform*/
-#define G4X_DOT_DISPLAY_PORT_MIN           161670
-#define G4X_DOT_DISPLAY_PORT_MAX           227000
-#define G4X_N_DISPLAY_PORT_MIN             1
-#define G4X_N_DISPLAY_PORT_MAX             2
-#define G4X_M_DISPLAY_PORT_MIN             97
-#define G4X_M_DISPLAY_PORT_MAX             108
-#define G4X_M1_DISPLAY_PORT_MIN            0x10
-#define G4X_M1_DISPLAY_PORT_MAX            0x12
-#define G4X_M2_DISPLAY_PORT_MIN            0x05
-#define G4X_M2_DISPLAY_PORT_MAX            0x06
-#define G4X_P_DISPLAY_PORT_MIN             10
-#define G4X_P_DISPLAY_PORT_MAX             20
-#define G4X_P1_DISPLAY_PORT_MIN            1
-#define G4X_P1_DISPLAY_PORT_MAX            2
-#define G4X_P2_DISPLAY_PORT_SLOW           10
-#define G4X_P2_DISPLAY_PORT_FAST           10
-#define G4X_P2_DISPLAY_PORT_LIMIT          0
-
-/* Ironlake / Sandybridge */
-/* as we calculate clock using (register_value + 2) for
-   N/M1/M2, so here the range value for them is (actual_value-2).
- */
-#define IRONLAKE_DOT_MIN         25000
-#define IRONLAKE_DOT_MAX         350000
-#define IRONLAKE_VCO_MIN         1760000
-#define IRONLAKE_VCO_MAX         3510000
-#define IRONLAKE_M1_MIN          12
-#define IRONLAKE_M1_MAX          22
-#define IRONLAKE_M2_MIN          5
-#define IRONLAKE_M2_MAX          9
-#define IRONLAKE_P2_DOT_LIMIT    225000 /* 225Mhz */
-
-/* We have parameter ranges for different type of outputs. */
-
-/* DAC & HDMI Refclk 120Mhz */
-#define IRONLAKE_DAC_N_MIN     1
-#define IRONLAKE_DAC_N_MAX     5
-#define IRONLAKE_DAC_M_MIN     79
-#define IRONLAKE_DAC_M_MAX     127
-#define IRONLAKE_DAC_P_MIN     5
-#define IRONLAKE_DAC_P_MAX     80
-#define IRONLAKE_DAC_P1_MIN    1
-#define IRONLAKE_DAC_P1_MAX    8
-#define IRONLAKE_DAC_P2_SLOW   10
-#define IRONLAKE_DAC_P2_FAST   5
-
-/* LVDS single-channel 120Mhz refclk */
-#define IRONLAKE_LVDS_S_N_MIN  1
-#define IRONLAKE_LVDS_S_N_MAX  3
-#define IRONLAKE_LVDS_S_M_MIN  79
-#define IRONLAKE_LVDS_S_M_MAX  118
-#define IRONLAKE_LVDS_S_P_MIN  28
-#define IRONLAKE_LVDS_S_P_MAX  112
-#define IRONLAKE_LVDS_S_P1_MIN 2
-#define IRONLAKE_LVDS_S_P1_MAX 8
-#define IRONLAKE_LVDS_S_P2_SLOW        14
-#define IRONLAKE_LVDS_S_P2_FAST        14
-
-/* LVDS dual-channel 120Mhz refclk */
-#define IRONLAKE_LVDS_D_N_MIN  1
-#define IRONLAKE_LVDS_D_N_MAX  3
-#define IRONLAKE_LVDS_D_M_MIN  79
-#define IRONLAKE_LVDS_D_M_MAX  127
-#define IRONLAKE_LVDS_D_P_MIN  14
-#define IRONLAKE_LVDS_D_P_MAX  56
-#define IRONLAKE_LVDS_D_P1_MIN 2
-#define IRONLAKE_LVDS_D_P1_MAX 8
-#define IRONLAKE_LVDS_D_P2_SLOW        7
-#define IRONLAKE_LVDS_D_P2_FAST        7
-
-/* LVDS single-channel 100Mhz refclk */
-#define IRONLAKE_LVDS_S_SSC_N_MIN      1
-#define IRONLAKE_LVDS_S_SSC_N_MAX      2
-#define IRONLAKE_LVDS_S_SSC_M_MIN      79
-#define IRONLAKE_LVDS_S_SSC_M_MAX      126
-#define IRONLAKE_LVDS_S_SSC_P_MIN      28
-#define IRONLAKE_LVDS_S_SSC_P_MAX      112
-#define IRONLAKE_LVDS_S_SSC_P1_MIN     2
-#define IRONLAKE_LVDS_S_SSC_P1_MAX     8
-#define IRONLAKE_LVDS_S_SSC_P2_SLOW    14
-#define IRONLAKE_LVDS_S_SSC_P2_FAST    14
-
-/* LVDS dual-channel 100Mhz refclk */
-#define IRONLAKE_LVDS_D_SSC_N_MIN      1
-#define IRONLAKE_LVDS_D_SSC_N_MAX      3
-#define IRONLAKE_LVDS_D_SSC_M_MIN      79
-#define IRONLAKE_LVDS_D_SSC_M_MAX      126
-#define IRONLAKE_LVDS_D_SSC_P_MIN      14
-#define IRONLAKE_LVDS_D_SSC_P_MAX      42
-#define IRONLAKE_LVDS_D_SSC_P1_MIN     2
-#define IRONLAKE_LVDS_D_SSC_P1_MAX     6
-#define IRONLAKE_LVDS_D_SSC_P2_SLOW    7
-#define IRONLAKE_LVDS_D_SSC_P2_FAST    7
-
-/* DisplayPort */
-#define IRONLAKE_DP_N_MIN              1
-#define IRONLAKE_DP_N_MAX              2
-#define IRONLAKE_DP_M_MIN              81
-#define IRONLAKE_DP_M_MAX              90
-#define IRONLAKE_DP_P_MIN              10
-#define IRONLAKE_DP_P_MAX              20
-#define IRONLAKE_DP_P2_FAST            10
-#define IRONLAKE_DP_P2_SLOW            10
-#define IRONLAKE_DP_P2_LIMIT           0
-#define IRONLAKE_DP_P1_MIN             1
-#define IRONLAKE_DP_P1_MAX             2
-
 /* FDI */
 #define IRONLAKE_FDI_FREQ              2700000 /* in kHz for mode->clock */
 
@@ -353,292 +104,253 @@ intel_fdi_link_freq(struct drm_device *dev)
 }
 
 static const intel_limit_t intel_limits_i8xx_dvo = {
-        .dot = { .min = I8XX_DOT_MIN,          .max = I8XX_DOT_MAX },
-        .vco = { .min = I8XX_VCO_MIN,          .max = I8XX_VCO_MAX },
-        .n   = { .min = I8XX_N_MIN,            .max = I8XX_N_MAX },
-        .m   = { .min = I8XX_M_MIN,            .max = I8XX_M_MAX },
-        .m1  = { .min = I8XX_M1_MIN,           .max = I8XX_M1_MAX },
-        .m2  = { .min = I8XX_M2_MIN,           .max = I8XX_M2_MAX },
-        .p   = { .min = I8XX_P_MIN,            .max = I8XX_P_MAX },
-        .p1  = { .min = I8XX_P1_MIN,           .max = I8XX_P1_MAX },
-       .p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
-                .p2_slow = I8XX_P2_SLOW,       .p2_fast = I8XX_P2_FAST },
+        .dot = { .min = 25000, .max = 350000 },
+        .vco = { .min = 930000, .max = 1400000 },
+        .n = { .min = 3, .max = 16 },
+        .m = { .min = 96, .max = 140 },
+        .m1 = { .min = 18, .max = 26 },
+        .m2 = { .min = 6, .max = 16 },
+        .p = { .min = 4, .max = 128 },
+        .p1 = { .min = 2, .max = 33 },
+       .p2 = { .dot_limit = 165000,
+               .p2_slow = 4, .p2_fast = 2 },
        .find_pll = intel_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_i8xx_lvds = {
-        .dot = { .min = I8XX_DOT_MIN,          .max = I8XX_DOT_MAX },
-        .vco = { .min = I8XX_VCO_MIN,          .max = I8XX_VCO_MAX },
-        .n   = { .min = I8XX_N_MIN,            .max = I8XX_N_MAX },
-        .m   = { .min = I8XX_M_MIN,            .max = I8XX_M_MAX },
-        .m1  = { .min = I8XX_M1_MIN,           .max = I8XX_M1_MAX },
-        .m2  = { .min = I8XX_M2_MIN,           .max = I8XX_M2_MAX },
-        .p   = { .min = I8XX_P_MIN,            .max = I8XX_P_MAX },
-        .p1  = { .min = I8XX_P1_LVDS_MIN,      .max = I8XX_P1_LVDS_MAX },
-       .p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
-                .p2_slow = I8XX_P2_LVDS_SLOW,  .p2_fast = I8XX_P2_LVDS_FAST },
+        .dot = { .min = 25000, .max = 350000 },
+        .vco = { .min = 930000, .max = 1400000 },
+        .n = { .min = 3, .max = 16 },
+        .m = { .min = 96, .max = 140 },
+        .m1 = { .min = 18, .max = 26 },
+        .m2 = { .min = 6, .max = 16 },
+        .p = { .min = 4, .max = 128 },
+        .p1 = { .min = 1, .max = 6 },
+       .p2 = { .dot_limit = 165000,
+               .p2_slow = 14, .p2_fast = 7 },
        .find_pll = intel_find_best_PLL,
 };
-       
+
 static const intel_limit_t intel_limits_i9xx_sdvo = {
-        .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX },
-        .vco = { .min = I9XX_VCO_MIN,          .max = I9XX_VCO_MAX },
-        .n   = { .min = I9XX_N_MIN,            .max = I9XX_N_MAX },
-        .m   = { .min = I9XX_M_MIN,            .max = I9XX_M_MAX },
-        .m1  = { .min = I9XX_M1_MIN,           .max = I9XX_M1_MAX },
-        .m2  = { .min = I9XX_M2_MIN,           .max = I9XX_M2_MAX },
-        .p   = { .min = I9XX_P_SDVO_DAC_MIN,   .max = I9XX_P_SDVO_DAC_MAX },
-        .p1  = { .min = I9XX_P1_MIN,           .max = I9XX_P1_MAX },
-       .p2  = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
-                .p2_slow = I9XX_P2_SDVO_DAC_SLOW,      .p2_fast = I9XX_P2_SDVO_DAC_FAST },
+        .dot = { .min = 20000, .max = 400000 },
+        .vco = { .min = 1400000, .max = 2800000 },
+        .n = { .min = 1, .max = 6 },
+        .m = { .min = 70, .max = 120 },
+        .m1 = { .min = 10, .max = 22 },
+        .m2 = { .min = 5, .max = 9 },
+        .p = { .min = 5, .max = 80 },
+        .p1 = { .min = 1, .max = 8 },
+       .p2 = { .dot_limit = 200000,
+               .p2_slow = 10, .p2_fast = 5 },
        .find_pll = intel_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_i9xx_lvds = {
-        .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX },
-        .vco = { .min = I9XX_VCO_MIN,          .max = I9XX_VCO_MAX },
-        .n   = { .min = I9XX_N_MIN,            .max = I9XX_N_MAX },
-        .m   = { .min = I9XX_M_MIN,            .max = I9XX_M_MAX },
-        .m1  = { .min = I9XX_M1_MIN,           .max = I9XX_M1_MAX },
-        .m2  = { .min = I9XX_M2_MIN,           .max = I9XX_M2_MAX },
-        .p   = { .min = I9XX_P_LVDS_MIN,       .max = I9XX_P_LVDS_MAX },
-        .p1  = { .min = I9XX_P1_MIN,           .max = I9XX_P1_MAX },
-       /* The single-channel range is 25-112Mhz, and dual-channel
-        * is 80-224Mhz.  Prefer single channel as much as possible.
-        */
-       .p2  = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
-                .p2_slow = I9XX_P2_LVDS_SLOW,  .p2_fast = I9XX_P2_LVDS_FAST },
+        .dot = { .min = 20000, .max = 400000 },
+        .vco = { .min = 1400000, .max = 2800000 },
+        .n = { .min = 1, .max = 6 },
+        .m = { .min = 70, .max = 120 },
+        .m1 = { .min = 10, .max = 22 },
+        .m2 = { .min = 5, .max = 9 },
+        .p = { .min = 7, .max = 98 },
+        .p1 = { .min = 1, .max = 8 },
+       .p2 = { .dot_limit = 112000,
+               .p2_slow = 14, .p2_fast = 7 },
        .find_pll = intel_find_best_PLL,
 };
 
-    /* below parameter and function is for G4X Chipset Family*/
+
 static const intel_limit_t intel_limits_g4x_sdvo = {
-       .dot = { .min = G4X_DOT_SDVO_MIN,       .max = G4X_DOT_SDVO_MAX },
-       .vco = { .min = G4X_VCO_MIN,            .max = G4X_VCO_MAX},
-       .n   = { .min = G4X_N_SDVO_MIN,         .max = G4X_N_SDVO_MAX },
-       .m   = { .min = G4X_M_SDVO_MIN,         .max = G4X_M_SDVO_MAX },
-       .m1  = { .min = G4X_M1_SDVO_MIN,        .max = G4X_M1_SDVO_MAX },
-       .m2  = { .min = G4X_M2_SDVO_MIN,        .max = G4X_M2_SDVO_MAX },
-       .p   = { .min = G4X_P_SDVO_MIN,         .max = G4X_P_SDVO_MAX },
-       .p1  = { .min = G4X_P1_SDVO_MIN,        .max = G4X_P1_SDVO_MAX},
-       .p2  = { .dot_limit = G4X_P2_SDVO_LIMIT,
-                .p2_slow = G4X_P2_SDVO_SLOW,
-                .p2_fast = G4X_P2_SDVO_FAST
+       .dot = { .min = 25000, .max = 270000 },
+       .vco = { .min = 1750000, .max = 3500000},
+       .n = { .min = 1, .max = 4 },
+       .m = { .min = 104, .max = 138 },
+       .m1 = { .min = 17, .max = 23 },
+       .m2 = { .min = 5, .max = 11 },
+       .p = { .min = 10, .max = 30 },
+       .p1 = { .min = 1, .max = 3},
+       .p2 = { .dot_limit = 270000,
+               .p2_slow = 10,
+               .p2_fast = 10
        },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_hdmi = {
-       .dot = { .min = G4X_DOT_HDMI_DAC_MIN,   .max = G4X_DOT_HDMI_DAC_MAX },
-       .vco = { .min = G4X_VCO_MIN,            .max = G4X_VCO_MAX},
-       .n   = { .min = G4X_N_HDMI_DAC_MIN,     .max = G4X_N_HDMI_DAC_MAX },
-       .m   = { .min = G4X_M_HDMI_DAC_MIN,     .max = G4X_M_HDMI_DAC_MAX },
-       .m1  = { .min = G4X_M1_HDMI_DAC_MIN,    .max = G4X_M1_HDMI_DAC_MAX },
-       .m2  = { .min = G4X_M2_HDMI_DAC_MIN,    .max = G4X_M2_HDMI_DAC_MAX },
-       .p   = { .min = G4X_P_HDMI_DAC_MIN,     .max = G4X_P_HDMI_DAC_MAX },
-       .p1  = { .min = G4X_P1_HDMI_DAC_MIN,    .max = G4X_P1_HDMI_DAC_MAX},
-       .p2  = { .dot_limit = G4X_P2_HDMI_DAC_LIMIT,
-                .p2_slow = G4X_P2_HDMI_DAC_SLOW,
-                .p2_fast = G4X_P2_HDMI_DAC_FAST
-       },
+       .dot = { .min = 22000, .max = 400000 },
+       .vco = { .min = 1750000, .max = 3500000},
+       .n = { .min = 1, .max = 4 },
+       .m = { .min = 104, .max = 138 },
+       .m1 = { .min = 16, .max = 23 },
+       .m2 = { .min = 5, .max = 11 },
+       .p = { .min = 5, .max = 80 },
+       .p1 = { .min = 1, .max = 8},
+       .p2 = { .dot_limit = 165000,
+               .p2_slow = 10, .p2_fast = 5 },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
-       .dot = { .min = G4X_DOT_SINGLE_CHANNEL_LVDS_MIN,
-                .max = G4X_DOT_SINGLE_CHANNEL_LVDS_MAX },
-       .vco = { .min = G4X_VCO_MIN,
-                .max = G4X_VCO_MAX },
-       .n   = { .min = G4X_N_SINGLE_CHANNEL_LVDS_MIN,
-                .max = G4X_N_SINGLE_CHANNEL_LVDS_MAX },
-       .m   = { .min = G4X_M_SINGLE_CHANNEL_LVDS_MIN,
-                .max = G4X_M_SINGLE_CHANNEL_LVDS_MAX },
-       .m1  = { .min = G4X_M1_SINGLE_CHANNEL_LVDS_MIN,
-                .max = G4X_M1_SINGLE_CHANNEL_LVDS_MAX },
-       .m2  = { .min = G4X_M2_SINGLE_CHANNEL_LVDS_MIN,
-                .max = G4X_M2_SINGLE_CHANNEL_LVDS_MAX },
-       .p   = { .min = G4X_P_SINGLE_CHANNEL_LVDS_MIN,
-                .max = G4X_P_SINGLE_CHANNEL_LVDS_MAX },
-       .p1  = { .min = G4X_P1_SINGLE_CHANNEL_LVDS_MIN,
-                .max = G4X_P1_SINGLE_CHANNEL_LVDS_MAX },
-       .p2  = { .dot_limit = G4X_P2_SINGLE_CHANNEL_LVDS_LIMIT,
-                .p2_slow = G4X_P2_SINGLE_CHANNEL_LVDS_SLOW,
-                .p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST
+       .dot = { .min = 20000, .max = 115000 },
+       .vco = { .min = 1750000, .max = 3500000 },
+       .n = { .min = 1, .max = 3 },
+       .m = { .min = 104, .max = 138 },
+       .m1 = { .min = 17, .max = 23 },
+       .m2 = { .min = 5, .max = 11 },
+       .p = { .min = 28, .max = 112 },
+       .p1 = { .min = 2, .max = 8 },
+       .p2 = { .dot_limit = 0,
+               .p2_slow = 14, .p2_fast = 14
        },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
-       .dot = { .min = G4X_DOT_DUAL_CHANNEL_LVDS_MIN,
-                .max = G4X_DOT_DUAL_CHANNEL_LVDS_MAX },
-       .vco = { .min = G4X_VCO_MIN,
-                .max = G4X_VCO_MAX },
-       .n   = { .min = G4X_N_DUAL_CHANNEL_LVDS_MIN,
-                .max = G4X_N_DUAL_CHANNEL_LVDS_MAX },
-       .m   = { .min = G4X_M_DUAL_CHANNEL_LVDS_MIN,
-                .max = G4X_M_DUAL_CHANNEL_LVDS_MAX },
-       .m1  = { .min = G4X_M1_DUAL_CHANNEL_LVDS_MIN,
-                .max = G4X_M1_DUAL_CHANNEL_LVDS_MAX },
-       .m2  = { .min = G4X_M2_DUAL_CHANNEL_LVDS_MIN,
-                .max = G4X_M2_DUAL_CHANNEL_LVDS_MAX },
-       .p   = { .min = G4X_P_DUAL_CHANNEL_LVDS_MIN,
-                .max = G4X_P_DUAL_CHANNEL_LVDS_MAX },
-       .p1  = { .min = G4X_P1_DUAL_CHANNEL_LVDS_MIN,
-                .max = G4X_P1_DUAL_CHANNEL_LVDS_MAX },
-       .p2  = { .dot_limit = G4X_P2_DUAL_CHANNEL_LVDS_LIMIT,
-                .p2_slow = G4X_P2_DUAL_CHANNEL_LVDS_SLOW,
-                .p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST
+       .dot = { .min = 80000, .max = 224000 },
+       .vco = { .min = 1750000, .max = 3500000 },
+       .n = { .min = 1, .max = 3 },
+       .m = { .min = 104, .max = 138 },
+       .m1 = { .min = 17, .max = 23 },
+       .m2 = { .min = 5, .max = 11 },
+       .p = { .min = 14, .max = 42 },
+       .p1 = { .min = 2, .max = 6 },
+       .p2 = { .dot_limit = 0,
+               .p2_slow = 7, .p2_fast = 7
        },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_display_port = {
-        .dot = { .min = G4X_DOT_DISPLAY_PORT_MIN,
-                 .max = G4X_DOT_DISPLAY_PORT_MAX },
-        .vco = { .min = G4X_VCO_MIN,
-                 .max = G4X_VCO_MAX},
-        .n   = { .min = G4X_N_DISPLAY_PORT_MIN,
-                 .max = G4X_N_DISPLAY_PORT_MAX },
-        .m   = { .min = G4X_M_DISPLAY_PORT_MIN,
-                 .max = G4X_M_DISPLAY_PORT_MAX },
-        .m1  = { .min = G4X_M1_DISPLAY_PORT_MIN,
-                 .max = G4X_M1_DISPLAY_PORT_MAX },
-        .m2  = { .min = G4X_M2_DISPLAY_PORT_MIN,
-                 .max = G4X_M2_DISPLAY_PORT_MAX },
-        .p   = { .min = G4X_P_DISPLAY_PORT_MIN,
-                 .max = G4X_P_DISPLAY_PORT_MAX },
-        .p1  = { .min = G4X_P1_DISPLAY_PORT_MIN,
-                 .max = G4X_P1_DISPLAY_PORT_MAX},
-        .p2  = { .dot_limit = G4X_P2_DISPLAY_PORT_LIMIT,
-                 .p2_slow = G4X_P2_DISPLAY_PORT_SLOW,
-                 .p2_fast = G4X_P2_DISPLAY_PORT_FAST },
+        .dot = { .min = 161670, .max = 227000 },
+        .vco = { .min = 1750000, .max = 3500000},
+        .n = { .min = 1, .max = 2 },
+        .m = { .min = 97, .max = 108 },
+        .m1 = { .min = 0x10, .max = 0x12 },
+        .m2 = { .min = 0x05, .max = 0x06 },
+        .p = { .min = 10, .max = 20 },
+        .p1 = { .min = 1, .max = 2},
+        .p2 = { .dot_limit = 0,
+               .p2_slow = 10, .p2_fast = 10 },
         .find_pll = intel_find_pll_g4x_dp,
 };
 
 static const intel_limit_t intel_limits_pineview_sdvo = {
-        .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX},
-        .vco = { .min = PINEVIEW_VCO_MIN,              .max = PINEVIEW_VCO_MAX },
-        .n   = { .min = PINEVIEW_N_MIN,                .max = PINEVIEW_N_MAX },
-        .m   = { .min = PINEVIEW_M_MIN,                .max = PINEVIEW_M_MAX },
-        .m1  = { .min = PINEVIEW_M1_MIN,               .max = PINEVIEW_M1_MAX },
-        .m2  = { .min = PINEVIEW_M2_MIN,               .max = PINEVIEW_M2_MAX },
-        .p   = { .min = I9XX_P_SDVO_DAC_MIN,    .max = I9XX_P_SDVO_DAC_MAX },
-        .p1  = { .min = I9XX_P1_MIN,           .max = I9XX_P1_MAX },
-       .p2  = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
-                .p2_slow = I9XX_P2_SDVO_DAC_SLOW,      .p2_fast = I9XX_P2_SDVO_DAC_FAST },
+        .dot = { .min = 20000, .max = 400000},
+        .vco = { .min = 1700000, .max = 3500000 },
+       /* Pineview's Ncounter is a ring counter */
+        .n = { .min = 3, .max = 6 },
+        .m = { .min = 2, .max = 256 },
+       /* Pineview only has one combined m divider, which we treat as m2. */
+        .m1 = { .min = 0, .max = 0 },
+        .m2 = { .min = 0, .max = 254 },
+        .p = { .min = 5, .max = 80 },
+        .p1 = { .min = 1, .max = 8 },
+       .p2 = { .dot_limit = 200000,
+               .p2_slow = 10, .p2_fast = 5 },
        .find_pll = intel_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_pineview_lvds = {
-        .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX },
-        .vco = { .min = PINEVIEW_VCO_MIN,              .max = PINEVIEW_VCO_MAX },
-        .n   = { .min = PINEVIEW_N_MIN,                .max = PINEVIEW_N_MAX },
-        .m   = { .min = PINEVIEW_M_MIN,                .max = PINEVIEW_M_MAX },
-        .m1  = { .min = PINEVIEW_M1_MIN,               .max = PINEVIEW_M1_MAX },
-        .m2  = { .min = PINEVIEW_M2_MIN,               .max = PINEVIEW_M2_MAX },
-        .p   = { .min = PINEVIEW_P_LVDS_MIN,   .max = PINEVIEW_P_LVDS_MAX },
-        .p1  = { .min = I9XX_P1_MIN,           .max = I9XX_P1_MAX },
-       /* Pineview only supports single-channel mode. */
-       .p2  = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
-                .p2_slow = I9XX_P2_LVDS_SLOW,  .p2_fast = I9XX_P2_LVDS_SLOW },
+        .dot = { .min = 20000, .max = 400000 },
+        .vco = { .min = 1700000, .max = 3500000 },
+        .n = { .min = 3, .max = 6 },
+        .m = { .min = 2, .max = 256 },
+        .m1 = { .min = 0, .max = 0 },
+        .m2 = { .min = 0, .max = 254 },
+        .p = { .min = 7, .max = 112 },
+        .p1 = { .min = 1, .max = 8 },
+       .p2 = { .dot_limit = 112000,
+               .p2_slow = 14, .p2_fast = 14 },
        .find_pll = intel_find_best_PLL,
 };
 
+/* Ironlake / Sandybridge
+ *
+ * We calculate clock using (register_value + 2) for N/M1/M2, so here
+ * the range value for them is (actual_value - 2).
+ */
 static const intel_limit_t intel_limits_ironlake_dac = {
-       .dot = { .min = IRONLAKE_DOT_MIN,          .max = IRONLAKE_DOT_MAX },
-       .vco = { .min = IRONLAKE_VCO_MIN,          .max = IRONLAKE_VCO_MAX },
-       .n   = { .min = IRONLAKE_DAC_N_MIN,        .max = IRONLAKE_DAC_N_MAX },
-       .m   = { .min = IRONLAKE_DAC_M_MIN,        .max = IRONLAKE_DAC_M_MAX },
-       .m1  = { .min = IRONLAKE_M1_MIN,           .max = IRONLAKE_M1_MAX },
-       .m2  = { .min = IRONLAKE_M2_MIN,           .max = IRONLAKE_M2_MAX },
-       .p   = { .min = IRONLAKE_DAC_P_MIN,        .max = IRONLAKE_DAC_P_MAX },
-       .p1  = { .min = IRONLAKE_DAC_P1_MIN,       .max = IRONLAKE_DAC_P1_MAX },
-       .p2  = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
-                .p2_slow = IRONLAKE_DAC_P2_SLOW,
-                .p2_fast = IRONLAKE_DAC_P2_FAST },
+       .dot = { .min = 25000, .max = 350000 },
+       .vco = { .min = 1760000, .max = 3510000 },
+       .n = { .min = 1, .max = 5 },
+       .m = { .min = 79, .max = 127 },
+       .m1 = { .min = 12, .max = 22 },
+       .m2 = { .min = 5, .max = 9 },
+       .p = { .min = 5, .max = 80 },
+       .p1 = { .min = 1, .max = 8 },
+       .p2 = { .dot_limit = 225000,
+               .p2_slow = 10, .p2_fast = 5 },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_ironlake_single_lvds = {
-       .dot = { .min = IRONLAKE_DOT_MIN,          .max = IRONLAKE_DOT_MAX },
-       .vco = { .min = IRONLAKE_VCO_MIN,          .max = IRONLAKE_VCO_MAX },
-       .n   = { .min = IRONLAKE_LVDS_S_N_MIN,     .max = IRONLAKE_LVDS_S_N_MAX },
-       .m   = { .min = IRONLAKE_LVDS_S_M_MIN,     .max = IRONLAKE_LVDS_S_M_MAX },
-       .m1  = { .min = IRONLAKE_M1_MIN,           .max = IRONLAKE_M1_MAX },
-       .m2  = { .min = IRONLAKE_M2_MIN,           .max = IRONLAKE_M2_MAX },
-       .p   = { .min = IRONLAKE_LVDS_S_P_MIN,     .max = IRONLAKE_LVDS_S_P_MAX },
-       .p1  = { .min = IRONLAKE_LVDS_S_P1_MIN,    .max = IRONLAKE_LVDS_S_P1_MAX },
-       .p2  = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
-                .p2_slow = IRONLAKE_LVDS_S_P2_SLOW,
-                .p2_fast = IRONLAKE_LVDS_S_P2_FAST },
+       .dot = { .min = 25000, .max = 350000 },
+       .vco = { .min = 1760000, .max = 3510000 },
+       .n = { .min = 1, .max = 3 },
+       .m = { .min = 79, .max = 118 },
+       .m1 = { .min = 12, .max = 22 },
+       .m2 = { .min = 5, .max = 9 },
+       .p = { .min = 28, .max = 112 },
+       .p1 = { .min = 2, .max = 8 },
+       .p2 = { .dot_limit = 225000,
+               .p2_slow = 14, .p2_fast = 14 },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_ironlake_dual_lvds = {
-       .dot = { .min = IRONLAKE_DOT_MIN,          .max = IRONLAKE_DOT_MAX },
-       .vco = { .min = IRONLAKE_VCO_MIN,          .max = IRONLAKE_VCO_MAX },
-       .n   = { .min = IRONLAKE_LVDS_D_N_MIN,     .max = IRONLAKE_LVDS_D_N_MAX },
-       .m   = { .min = IRONLAKE_LVDS_D_M_MIN,     .max = IRONLAKE_LVDS_D_M_MAX },
-       .m1  = { .min = IRONLAKE_M1_MIN,           .max = IRONLAKE_M1_MAX },
-       .m2  = { .min = IRONLAKE_M2_MIN,           .max = IRONLAKE_M2_MAX },
-       .p   = { .min = IRONLAKE_LVDS_D_P_MIN,     .max = IRONLAKE_LVDS_D_P_MAX },
-       .p1  = { .min = IRONLAKE_LVDS_D_P1_MIN,    .max = IRONLAKE_LVDS_D_P1_MAX },
-       .p2  = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
-                .p2_slow = IRONLAKE_LVDS_D_P2_SLOW,
-                .p2_fast = IRONLAKE_LVDS_D_P2_FAST },
+       .dot = { .min = 25000, .max = 350000 },
+       .vco = { .min = 1760000, .max = 3510000 },
+       .n = { .min = 1, .max = 3 },
+       .m = { .min = 79, .max = 127 },
+       .m1 = { .min = 12, .max = 22 },
+       .m2 = { .min = 5, .max = 9 },
+       .p = { .min = 14, .max = 56 },
+       .p1 = { .min = 2, .max = 8 },
+       .p2 = { .dot_limit = 225000,
+               .p2_slow = 7, .p2_fast = 7 },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
+/* LVDS 100mhz refclk limits. */
 static const intel_limit_t intel_limits_ironlake_single_lvds_100m = {
-       .dot = { .min = IRONLAKE_DOT_MIN,          .max = IRONLAKE_DOT_MAX },
-       .vco = { .min = IRONLAKE_VCO_MIN,          .max = IRONLAKE_VCO_MAX },
-       .n   = { .min = IRONLAKE_LVDS_S_SSC_N_MIN, .max = IRONLAKE_LVDS_S_SSC_N_MAX },
-       .m   = { .min = IRONLAKE_LVDS_S_SSC_M_MIN, .max = IRONLAKE_LVDS_S_SSC_M_MAX },
-       .m1  = { .min = IRONLAKE_M1_MIN,           .max = IRONLAKE_M1_MAX },
-       .m2  = { .min = IRONLAKE_M2_MIN,           .max = IRONLAKE_M2_MAX },
-       .p   = { .min = IRONLAKE_LVDS_S_SSC_P_MIN, .max = IRONLAKE_LVDS_S_SSC_P_MAX },
-       .p1  = { .min = IRONLAKE_LVDS_S_SSC_P1_MIN,.max = IRONLAKE_LVDS_S_SSC_P1_MAX },
-       .p2  = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
-                .p2_slow = IRONLAKE_LVDS_S_SSC_P2_SLOW,
-                .p2_fast = IRONLAKE_LVDS_S_SSC_P2_FAST },
+       .dot = { .min = 25000, .max = 350000 },
+       .vco = { .min = 1760000, .max = 3510000 },
+       .n = { .min = 1, .max = 2 },
+       .m = { .min = 79, .max = 126 },
+       .m1 = { .min = 12, .max = 22 },
+       .m2 = { .min = 5, .max = 9 },
+       .p = { .min = 28, .max = 112 },
+       .p1 = { .min = 2,.max = 8 },
+       .p2 = { .dot_limit = 225000,
+               .p2_slow = 14, .p2_fast = 14 },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = {
-       .dot = { .min = IRONLAKE_DOT_MIN,          .max = IRONLAKE_DOT_MAX },
-       .vco = { .min = IRONLAKE_VCO_MIN,          .max = IRONLAKE_VCO_MAX },
-       .n   = { .min = IRONLAKE_LVDS_D_SSC_N_MIN, .max = IRONLAKE_LVDS_D_SSC_N_MAX },
-       .m   = { .min = IRONLAKE_LVDS_D_SSC_M_MIN, .max = IRONLAKE_LVDS_D_SSC_M_MAX },
-       .m1  = { .min = IRONLAKE_M1_MIN,           .max = IRONLAKE_M1_MAX },
-       .m2  = { .min = IRONLAKE_M2_MIN,           .max = IRONLAKE_M2_MAX },
-       .p   = { .min = IRONLAKE_LVDS_D_SSC_P_MIN, .max = IRONLAKE_LVDS_D_SSC_P_MAX },
-       .p1  = { .min = IRONLAKE_LVDS_D_SSC_P1_MIN,.max = IRONLAKE_LVDS_D_SSC_P1_MAX },
-       .p2  = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
-                .p2_slow = IRONLAKE_LVDS_D_SSC_P2_SLOW,
-                .p2_fast = IRONLAKE_LVDS_D_SSC_P2_FAST },
+       .dot = { .min = 25000, .max = 350000 },
+       .vco = { .min = 1760000, .max = 3510000 },
+       .n = { .min = 1, .max = 3 },
+       .m = { .min = 79, .max = 126 },
+       .m1 = { .min = 12, .max = 22 },
+       .m2 = { .min = 5, .max = 9 },
+       .p = { .min = 14, .max = 42 },
+       .p1 = { .min = 2,.max = 6 },
+       .p2 = { .dot_limit = 225000,
+               .p2_slow = 7, .p2_fast = 7 },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_ironlake_display_port = {
-        .dot = { .min = IRONLAKE_DOT_MIN,
-                 .max = IRONLAKE_DOT_MAX },
-        .vco = { .min = IRONLAKE_VCO_MIN,
-                 .max = IRONLAKE_VCO_MAX},
-        .n   = { .min = IRONLAKE_DP_N_MIN,
-                 .max = IRONLAKE_DP_N_MAX },
-        .m   = { .min = IRONLAKE_DP_M_MIN,
-                 .max = IRONLAKE_DP_M_MAX },
-        .m1  = { .min = IRONLAKE_M1_MIN,
-                 .max = IRONLAKE_M1_MAX },
-        .m2  = { .min = IRONLAKE_M2_MIN,
-                 .max = IRONLAKE_M2_MAX },
-        .p   = { .min = IRONLAKE_DP_P_MIN,
-                 .max = IRONLAKE_DP_P_MAX },
-        .p1  = { .min = IRONLAKE_DP_P1_MIN,
-                 .max = IRONLAKE_DP_P1_MAX},
-        .p2  = { .dot_limit = IRONLAKE_DP_P2_LIMIT,
-                 .p2_slow = IRONLAKE_DP_P2_SLOW,
-                 .p2_fast = IRONLAKE_DP_P2_FAST },
+        .dot = { .min = 25000, .max = 350000 },
+        .vco = { .min = 1760000, .max = 3510000},
+        .n = { .min = 1, .max = 2 },
+        .m = { .min = 81, .max = 90 },
+        .m1 = { .min = 12, .max = 22 },
+        .m2 = { .min = 5, .max = 9 },
+        .p = { .min = 10, .max = 20 },
+        .p1 = { .min = 1, .max = 2},
+        .p2 = { .dot_limit = 0,
+               .p2_slow = 10, .p2_fast = 10 },
         .find_pll = intel_find_pll_ironlake_dp,
 };
 
@@ -1828,7 +1540,7 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev)
        u32 blt_ecoskpd;
 
        /* Make sure blitter notifies FBC of writes */
-       __gen6_gt_force_wake_get(dev_priv);
+       gen6_gt_force_wake_get(dev_priv);
        blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
        blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
                GEN6_BLITTER_LOCK_SHIFT;
@@ -1839,7 +1551,7 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev)
                         GEN6_BLITTER_LOCK_SHIFT);
        I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
        POSTING_READ(GEN6_BLITTER_ECOSKPD);
-       __gen6_gt_force_wake_put(dev_priv);
+       gen6_gt_force_wake_put(dev_priv);
 }
 
 static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
@@ -2019,6 +1731,11 @@ static void intel_update_fbc(struct drm_device *dev)
        intel_fb = to_intel_framebuffer(fb);
        obj = intel_fb->obj;
 
+       if (!i915_enable_fbc) {
+               DRM_DEBUG_KMS("fbc disabled per module param (default off)\n");
+               dev_priv->no_fbc_reason = FBC_MODULE_PARAM;
+               goto out_disable;
+       }
        if (intel_fb->obj->base.size > dev_priv->cfb_size) {
                DRM_DEBUG_KMS("framebuffer too large, disabling "
                              "compression\n");
@@ -2339,8 +2056,13 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc)
        /* enable normal train */
        reg = FDI_TX_CTL(pipe);
        temp = I915_READ(reg);
-       temp &= ~FDI_LINK_TRAIN_NONE;
-       temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+       if (IS_IVYBRIDGE(dev)) {
+               temp &= ~FDI_LINK_TRAIN_NONE_IVB;
+               temp |= FDI_LINK_TRAIN_NONE_IVB | FDI_TX_ENHANCE_FRAME_ENABLE;
+       } else {
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+       }
        I915_WRITE(reg, temp);
 
        reg = FDI_RX_CTL(pipe);
@@ -2357,6 +2079,11 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc)
        /* wait one idle pattern time */
        POSTING_READ(reg);
        udelay(1000);
+
+       /* IVB wants error correction enabled */
+       if (IS_IVYBRIDGE(dev))
+               I915_WRITE(reg, I915_READ(reg) | FDI_FS_ERRC_ENABLE |
+                          FDI_FE_ERRC_ENABLE);
 }
 
 /* The FDI link training functions for ILK/Ibexpeak. */
@@ -2584,7 +2311,116 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
        DRM_DEBUG_KMS("FDI train done.\n");
 }
 
-static void ironlake_fdi_enable(struct drm_crtc *crtc)
+/* Manual link training for Ivy Bridge A0 parts */
+static void ivb_manual_fdi_link_train(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       u32 reg, temp, i;
+
+       /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+          for train result */
+       reg = FDI_RX_IMR(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_RX_SYMBOL_LOCK;
+       temp &= ~FDI_RX_BIT_LOCK;
+       I915_WRITE(reg, temp);
+
+       POSTING_READ(reg);
+       udelay(150);
+
+       /* enable CPU FDI TX and PCH FDI RX */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~(7 << 19);
+       temp |= (intel_crtc->fdi_lanes - 1) << 19;
+       temp &= ~(FDI_LINK_TRAIN_AUTO | FDI_LINK_TRAIN_NONE_IVB);
+       temp |= FDI_LINK_TRAIN_PATTERN_1_IVB;
+       temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+       temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+       I915_WRITE(reg, temp | FDI_TX_ENABLE);
+
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_LINK_TRAIN_AUTO;
+       temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+       temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+       I915_WRITE(reg, temp | FDI_RX_ENABLE);
+
+       POSTING_READ(reg);
+       udelay(150);
+
+       for (i = 0; i < 4; i++ ) {
+               reg = FDI_TX_CTL(pipe);
+               temp = I915_READ(reg);
+               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+               temp |= snb_b_fdi_train_param[i];
+               I915_WRITE(reg, temp);
+
+               POSTING_READ(reg);
+               udelay(500);
+
+               reg = FDI_RX_IIR(pipe);
+               temp = I915_READ(reg);
+               DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+
+               if (temp & FDI_RX_BIT_LOCK ||
+                   (I915_READ(reg) & FDI_RX_BIT_LOCK)) {
+                       I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
+                       DRM_DEBUG_KMS("FDI train 1 done.\n");
+                       break;
+               }
+       }
+       if (i == 4)
+               DRM_ERROR("FDI train 1 fail!\n");
+
+       /* Train 2 */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_LINK_TRAIN_NONE_IVB;
+       temp |= FDI_LINK_TRAIN_PATTERN_2_IVB;
+       temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+       temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+       I915_WRITE(reg, temp);
+
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+       temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
+       I915_WRITE(reg, temp);
+
+       POSTING_READ(reg);
+       udelay(150);
+
+       for (i = 0; i < 4; i++ ) {
+               reg = FDI_TX_CTL(pipe);
+               temp = I915_READ(reg);
+               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+               temp |= snb_b_fdi_train_param[i];
+               I915_WRITE(reg, temp);
+
+               POSTING_READ(reg);
+               udelay(500);
+
+               reg = FDI_RX_IIR(pipe);
+               temp = I915_READ(reg);
+               DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+
+               if (temp & FDI_RX_SYMBOL_LOCK) {
+                       I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
+                       DRM_DEBUG_KMS("FDI train 2 done.\n");
+                       break;
+               }
+       }
+       if (i == 4)
+               DRM_ERROR("FDI train 2 fail!\n");
+
+       DRM_DEBUG_KMS("FDI train done.\n");
+}
+
+static void ironlake_fdi_pll_enable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2757,10 +2593,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
        u32 reg, temp;
 
        /* For PCH output, training FDI link */
-       if (IS_GEN6(dev))
-               gen6_fdi_link_train(crtc);
-       else
-               ironlake_fdi_link_train(crtc);
+       dev_priv->display.fdi_link_train(crtc);
 
        intel_enable_pch_pll(dev_priv, pipe);
 
@@ -2850,7 +2683,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        is_pch_port = intel_crtc_driving_pch(crtc);
 
        if (is_pch_port)
-               ironlake_fdi_enable(crtc);
+               ironlake_fdi_pll_enable(crtc);
        else
                ironlake_fdi_disable(crtc);
 
@@ -2873,7 +2706,11 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
                ironlake_pch_enable(crtc);
 
        intel_crtc_load_lut(crtc);
+
+       mutex_lock(&dev->struct_mutex);
        intel_update_fbc(dev);
+       mutex_unlock(&dev->struct_mutex);
+
        intel_crtc_update_cursor(crtc, true);
 }
 
@@ -2969,8 +2806,11 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
 
        intel_crtc->active = false;
        intel_update_watermarks(dev);
+
+       mutex_lock(&dev->struct_mutex);
        intel_update_fbc(dev);
        intel_clear_scanline_wait(dev);
+       mutex_unlock(&dev->struct_mutex);
 }
 
 static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
@@ -3497,11 +3337,11 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
                1000;
        entries_required = DIV_ROUND_UP(entries_required, wm->cacheline_size);
 
-       DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", entries_required);
+       DRM_DEBUG_KMS("FIFO entries required for mode: %ld\n", entries_required);
 
        wm_size = fifo_size - (entries_required + wm->guard_size);
 
-       DRM_DEBUG_KMS("FIFO watermark level: %d\n", wm_size);
+       DRM_DEBUG_KMS("FIFO watermark level: %ld\n", wm_size);
 
        /* Don't promote wm_size to unsigned... */
        if (wm_size > (long)wm->max_wm)
@@ -3823,13 +3663,13 @@ static bool g4x_check_srwm(struct drm_device *dev,
                      display_wm, cursor_wm);
 
        if (display_wm > display->max_wm) {
-               DRM_DEBUG_KMS("display watermark is too large(%d), disabling\n",
+               DRM_DEBUG_KMS("display watermark is too large(%d/%ld), disabling\n",
                              display_wm, display->max_wm);
                return false;
        }
 
        if (cursor_wm > cursor->max_wm) {
-               DRM_DEBUG_KMS("cursor watermark is too large(%d), disabling\n",
+               DRM_DEBUG_KMS("cursor watermark is too large(%d/%ld), disabling\n",
                              cursor_wm, cursor->max_wm);
                return false;
        }
@@ -4143,54 +3983,6 @@ static void i830_update_wm(struct drm_device *dev)
 #define ILK_LP0_PLANE_LATENCY          700
 #define ILK_LP0_CURSOR_LATENCY         1300
 
-static bool ironlake_compute_wm0(struct drm_device *dev,
-                                int pipe,
-                                const struct intel_watermark_params *display,
-                                int display_latency_ns,
-                                const struct intel_watermark_params *cursor,
-                                int cursor_latency_ns,
-                                int *plane_wm,
-                                int *cursor_wm)
-{
-       struct drm_crtc *crtc;
-       int htotal, hdisplay, clock, pixel_size;
-       int line_time_us, line_count;
-       int entries, tlb_miss;
-
-       crtc = intel_get_crtc_for_pipe(dev, pipe);
-       if (crtc->fb == NULL || !crtc->enabled)
-               return false;
-
-       htotal = crtc->mode.htotal;
-       hdisplay = crtc->mode.hdisplay;
-       clock = crtc->mode.clock;
-       pixel_size = crtc->fb->bits_per_pixel / 8;
-
-       /* Use the small buffer method to calculate plane watermark */
-       entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
-       tlb_miss = display->fifo_size*display->cacheline_size - hdisplay * 8;
-       if (tlb_miss > 0)
-               entries += tlb_miss;
-       entries = DIV_ROUND_UP(entries, display->cacheline_size);
-       *plane_wm = entries + display->guard_size;
-       if (*plane_wm > (int)display->max_wm)
-               *plane_wm = display->max_wm;
-
-       /* Use the large buffer method to calculate cursor watermark */
-       line_time_us = ((htotal * 1000) / clock);
-       line_count = (cursor_latency_ns / line_time_us + 1000) / 1000;
-       entries = line_count * 64 * pixel_size;
-       tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8;
-       if (tlb_miss > 0)
-               entries += tlb_miss;
-       entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
-       *cursor_wm = entries + cursor->guard_size;
-       if (*cursor_wm > (int)cursor->max_wm)
-               *cursor_wm = (int)cursor->max_wm;
-
-       return true;
-}
-
 /*
  * Check the wm result.
  *
@@ -4299,12 +4091,12 @@ static void ironlake_update_wm(struct drm_device *dev)
        unsigned int enabled;
 
        enabled = 0;
-       if (ironlake_compute_wm0(dev, 0,
-                                &ironlake_display_wm_info,
-                                ILK_LP0_PLANE_LATENCY,
-                                &ironlake_cursor_wm_info,
-                                ILK_LP0_CURSOR_LATENCY,
-                                &plane_wm, &cursor_wm)) {
+       if (g4x_compute_wm0(dev, 0,
+                           &ironlake_display_wm_info,
+                           ILK_LP0_PLANE_LATENCY,
+                           &ironlake_cursor_wm_info,
+                           ILK_LP0_CURSOR_LATENCY,
+                           &plane_wm, &cursor_wm)) {
                I915_WRITE(WM0_PIPEA_ILK,
                           (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
                DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
@@ -4313,12 +4105,12 @@ static void ironlake_update_wm(struct drm_device *dev)
                enabled |= 1;
        }
 
-       if (ironlake_compute_wm0(dev, 1,
-                                &ironlake_display_wm_info,
-                                ILK_LP0_PLANE_LATENCY,
-                                &ironlake_cursor_wm_info,
-                                ILK_LP0_CURSOR_LATENCY,
-                                &plane_wm, &cursor_wm)) {
+       if (g4x_compute_wm0(dev, 1,
+                           &ironlake_display_wm_info,
+                           ILK_LP0_PLANE_LATENCY,
+                           &ironlake_cursor_wm_info,
+                           ILK_LP0_CURSOR_LATENCY,
+                           &plane_wm, &cursor_wm)) {
                I915_WRITE(WM0_PIPEB_ILK,
                           (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
                DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
@@ -4383,10 +4175,10 @@ static void sandybridge_update_wm(struct drm_device *dev)
        unsigned int enabled;
 
        enabled = 0;
-       if (ironlake_compute_wm0(dev, 0,
-                                &sandybridge_display_wm_info, latency,
-                                &sandybridge_cursor_wm_info, latency,
-                                &plane_wm, &cursor_wm)) {
+       if (g4x_compute_wm0(dev, 0,
+                           &sandybridge_display_wm_info, latency,
+                           &sandybridge_cursor_wm_info, latency,
+                           &plane_wm, &cursor_wm)) {
                I915_WRITE(WM0_PIPEA_ILK,
                           (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
                DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
@@ -4395,10 +4187,10 @@ static void sandybridge_update_wm(struct drm_device *dev)
                enabled |= 1;
        }
 
-       if (ironlake_compute_wm0(dev, 1,
-                                &sandybridge_display_wm_info, latency,
-                                &sandybridge_cursor_wm_info, latency,
-                                &plane_wm, &cursor_wm)) {
+       if (g4x_compute_wm0(dev, 1,
+                           &sandybridge_display_wm_info, latency,
+                           &sandybridge_cursor_wm_info, latency,
+                           &plane_wm, &cursor_wm)) {
                I915_WRITE(WM0_PIPEB_ILK,
                           (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
                DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
@@ -4516,34 +4308,28 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
        return dev_priv->lvds_use_ssc && i915_panel_use_ssc;
 }
 
-static int intel_crtc_mode_set(struct drm_crtc *crtc,
-                              struct drm_display_mode *mode,
-                              struct drm_display_mode *adjusted_mode,
-                              int x, int y,
-                              struct drm_framebuffer *old_fb)
+static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
+                             struct drm_display_mode *mode,
+                             struct drm_display_mode *adjusted_mode,
+                             int x, int y,
+                             struct drm_framebuffer *old_fb)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
-       u32 fp_reg, dpll_reg;
        int refclk, num_connectors = 0;
        intel_clock_t clock, reduced_clock;
        u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
        bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false;
        bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
-       struct intel_encoder *has_edp_encoder = NULL;
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct intel_encoder *encoder;
        const intel_limit_t *limit;
        int ret;
-       struct fdi_m_n m_n = {0};
-       u32 reg, temp;
+       u32 temp;
        u32 lvds_sync = 0;
-       int target_clock;
-
-       drm_vblank_pre_modeset(dev, pipe);
 
        list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
                if (encoder->base.crtc != crtc)
@@ -4571,9 +4357,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                case INTEL_OUTPUT_DISPLAYPORT:
                        is_dp = true;
                        break;
-               case INTEL_OUTPUT_EDP:
-                       has_edp_encoder = encoder;
-                       break;
                }
 
                num_connectors++;
@@ -4585,9 +4368,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                              refclk / 1000);
        } else if (!IS_GEN2(dev)) {
                refclk = 96000;
-               if (HAS_PCH_SPLIT(dev) &&
-                   (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)))
-                       refclk = 120000; /* 120Mhz refclk */
        } else {
                refclk = 48000;
        }
@@ -4601,7 +4381,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
        if (!ok) {
                DRM_ERROR("Couldn't find PLL settings for mode!\n");
-               drm_vblank_post_modeset(dev, pipe);
                return -EINVAL;
        }
 
@@ -4645,143 +4424,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                }
        }
 
-       /* FDI link */
-       if (HAS_PCH_SPLIT(dev)) {
-               int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
-               int lane = 0, link_bw, bpp;
-               /* CPU eDP doesn't require FDI link, so just set DP M/N
-                  according to current link config */
-               if (has_edp_encoder && !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-                       target_clock = mode->clock;
-                       intel_edp_link_config(has_edp_encoder,
-                                             &lane, &link_bw);
-               } else {
-                       /* [e]DP over FDI requires target mode clock
-                          instead of link clock */
-                       if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
-                               target_clock = mode->clock;
-                       else
-                               target_clock = adjusted_mode->clock;
-
-                       /* FDI is a binary signal running at ~2.7GHz, encoding
-                        * each output octet as 10 bits. The actual frequency
-                        * is stored as a divider into a 100MHz clock, and the
-                        * mode pixel clock is stored in units of 1KHz.
-                        * Hence the bw of each lane in terms of the mode signal
-                        * is:
-                        */
-                       link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
-               }
-
-               /* determine panel color depth */
-               temp = I915_READ(PIPECONF(pipe));
-               temp &= ~PIPE_BPC_MASK;
-               if (is_lvds) {
-                       /* the BPC will be 6 if it is 18-bit LVDS panel */
-                       if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
-                               temp |= PIPE_8BPC;
-                       else
-                               temp |= PIPE_6BPC;
-               } else if (has_edp_encoder) {
-                       switch (dev_priv->edp.bpp/3) {
-                       case 8:
-                               temp |= PIPE_8BPC;
-                               break;
-                       case 10:
-                               temp |= PIPE_10BPC;
-                               break;
-                       case 6:
-                               temp |= PIPE_6BPC;
-                               break;
-                       case 12:
-                               temp |= PIPE_12BPC;
-                               break;
-                       }
-               } else
-                       temp |= PIPE_8BPC;
-               I915_WRITE(PIPECONF(pipe), temp);
-
-               switch (temp & PIPE_BPC_MASK) {
-               case PIPE_8BPC:
-                       bpp = 24;
-                       break;
-               case PIPE_10BPC:
-                       bpp = 30;
-                       break;
-               case PIPE_6BPC:
-                       bpp = 18;
-                       break;
-               case PIPE_12BPC:
-                       bpp = 36;
-                       break;
-               default:
-                       DRM_ERROR("unknown pipe bpc value\n");
-                       bpp = 24;
-               }
-
-               if (!lane) {
-                       /* 
-                        * Account for spread spectrum to avoid
-                        * oversubscribing the link. Max center spread
-                        * is 2.5%; use 5% for safety's sake.
-                        */
-                       u32 bps = target_clock * bpp * 21 / 20;
-                       lane = bps / (link_bw * 8) + 1;
-               }
-
-               intel_crtc->fdi_lanes = lane;
-
-               if (pixel_multiplier > 1)
-                       link_bw *= pixel_multiplier;
-               ironlake_compute_m_n(bpp, lane, target_clock, link_bw, &m_n);
-       }
-
-       /* Ironlake: try to setup display ref clock before DPLL
-        * enabling. This is only under driver's control after
-        * PCH B stepping, previous chipset stepping should be
-        * ignoring this setting.
-        */
-       if (HAS_PCH_SPLIT(dev)) {
-               temp = I915_READ(PCH_DREF_CONTROL);
-               /* Always enable nonspread source */
-               temp &= ~DREF_NONSPREAD_SOURCE_MASK;
-               temp |= DREF_NONSPREAD_SOURCE_ENABLE;
-               temp &= ~DREF_SSC_SOURCE_MASK;
-               temp |= DREF_SSC_SOURCE_ENABLE;
-               I915_WRITE(PCH_DREF_CONTROL, temp);
-
-               POSTING_READ(PCH_DREF_CONTROL);
-               udelay(200);
-
-               if (has_edp_encoder) {
-                       if (intel_panel_use_ssc(dev_priv)) {
-                               temp |= DREF_SSC1_ENABLE;
-                               I915_WRITE(PCH_DREF_CONTROL, temp);
-
-                               POSTING_READ(PCH_DREF_CONTROL);
-                               udelay(200);
-                       }
-                       temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
-
-                       /* Enable CPU source on CPU attached eDP */
-                       if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-                               if (intel_panel_use_ssc(dev_priv))
-                                       temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
-                               else
-                                       temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
-                       } else {
-                               /* Enable SSC on PCH eDP if needed */
-                               if (intel_panel_use_ssc(dev_priv)) {
-                                       DRM_ERROR("enabling SSC on PCH\n");
-                                       temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
-                               }
-                       }
-                       I915_WRITE(PCH_DREF_CONTROL, temp);
-                       POSTING_READ(PCH_DREF_CONTROL);
-                       udelay(200);
-               }
-       }
-
        if (IS_PINEVIEW(dev)) {
                fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
                if (has_reduced_clock)
@@ -4794,25 +4436,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                                reduced_clock.m2;
        }
 
-       /* Enable autotuning of the PLL clock (if permissible) */
-       if (HAS_PCH_SPLIT(dev)) {
-               int factor = 21;
-
-               if (is_lvds) {
-                       if ((intel_panel_use_ssc(dev_priv) &&
-                            dev_priv->lvds_ssc_freq == 100) ||
-                           (I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP)
-                               factor = 25;
-               } else if (is_sdvo && is_tv)
-                       factor = 20;
-
-               if (clock.m1 < factor * clock.n)
-                       fp |= FP_CB_TUNE;
-       }
-
-       dpll = 0;
-       if (!HAS_PCH_SPLIT(dev))
-               dpll = DPLL_VGA_MODE_DIS;
+       dpll = DPLL_VGA_MODE_DIS;
 
        if (!IS_GEN2(dev)) {
                if (is_lvds)
@@ -4824,12 +4448,10 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        if (pixel_multiplier > 1) {
                                if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
                                        dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
-                               else if (HAS_PCH_SPLIT(dev))
-                                       dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
                        }
                        dpll |= DPLL_DVO_HIGH_SPEED;
                }
-               if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
+               if (is_dp)
                        dpll |= DPLL_DVO_HIGH_SPEED;
 
                /* compute bitmask from p1 value */
@@ -4837,9 +4459,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW;
                else {
                        dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
-                       /* also FPA1 */
-                       if (HAS_PCH_SPLIT(dev))
-                               dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
                        if (IS_G4X(dev) && has_reduced_clock)
                                dpll |= (1 << (reduced_clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
                }
@@ -4857,7 +4476,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
                        break;
                }
-               if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
+               if (INTEL_INFO(dev)->gen >= 4)
                        dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
        } else {
                if (is_lvds) {
@@ -4891,12 +4510,10 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
        /* Ironlake's plane is forced to pipe, bit 24 is to
           enable color space conversion */
-       if (!HAS_PCH_SPLIT(dev)) {
-               if (pipe == 0)
-                       dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
-               else
-                       dspcntr |= DISPPLANE_SEL_PIPE_B;
-       }
+       if (pipe == 0)
+               dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
+       else
+               dspcntr |= DISPPLANE_SEL_PIPE_B;
 
        if (pipe == 0 && INTEL_INFO(dev)->gen < 4) {
                /* Enable pixel doubling when the dot clock is > 90% of the (display)
@@ -4912,33 +4529,513 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        pipeconf &= ~PIPECONF_DOUBLE_WIDE;
        }
 
-       if (!HAS_PCH_SPLIT(dev))
-               dpll |= DPLL_VCO_ENABLE;
+       dpll |= DPLL_VCO_ENABLE;
 
        DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
        drm_mode_debug_printmodeline(mode);
 
-       /* assign to Ironlake registers */
-       if (HAS_PCH_SPLIT(dev)) {
-               fp_reg = PCH_FP0(pipe);
-               dpll_reg = PCH_DPLL(pipe);
-       } else {
-               fp_reg = FP0(pipe);
-               dpll_reg = DPLL(pipe);
-       }
-
-       /* PCH eDP needs FDI, but CPU eDP does not */
-       if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-               I915_WRITE(fp_reg, fp);
-               I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
+       I915_WRITE(FP0(pipe), fp);
+       I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
 
-               POSTING_READ(dpll_reg);
-               udelay(150);
-       }
+       POSTING_READ(DPLL(pipe));
+       udelay(150);
 
-       /* enable transcoder DPLL */
-       if (HAS_PCH_CPT(dev)) {
-               temp = I915_READ(PCH_DPLL_SEL);
+       /* The LVDS pin pair needs to be on before the DPLLs are enabled.
+        * This is an exception to the general rule that mode_set doesn't turn
+        * things on.
+        */
+       if (is_lvds) {
+               temp = I915_READ(LVDS);
+               temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
+               if (pipe == 1) {
+                       temp |= LVDS_PIPEB_SELECT;
+               } else {
+                       temp &= ~LVDS_PIPEB_SELECT;
+               }
+               /* set the corresponsding LVDS_BORDER bit */
+               temp |= dev_priv->lvds_border_bits;
+               /* Set the B0-B3 data pairs corresponding to whether we're going to
+                * set the DPLLs for dual-channel mode or not.
+                */
+               if (clock.p2 == 7)
+                       temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
+               else
+                       temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
+
+               /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
+                * appropriately here, but we need to look more thoroughly into how
+                * panels behave in the two modes.
+                */
+               /* set the dithering flag on LVDS as needed */
+               if (INTEL_INFO(dev)->gen >= 4) {
+                       if (dev_priv->lvds_dither)
+                               temp |= LVDS_ENABLE_DITHER;
+                       else
+                               temp &= ~LVDS_ENABLE_DITHER;
+               }
+               if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
+                       lvds_sync |= LVDS_HSYNC_POLARITY;
+               if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
+                       lvds_sync |= LVDS_VSYNC_POLARITY;
+               if ((temp & (LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY))
+                   != lvds_sync) {
+                       char flags[2] = "-+";
+                       DRM_INFO("Changing LVDS panel from "
+                                "(%chsync, %cvsync) to (%chsync, %cvsync)\n",
+                                flags[!(temp & LVDS_HSYNC_POLARITY)],
+                                flags[!(temp & LVDS_VSYNC_POLARITY)],
+                                flags[!(lvds_sync & LVDS_HSYNC_POLARITY)],
+                                flags[!(lvds_sync & LVDS_VSYNC_POLARITY)]);
+                       temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
+                       temp |= lvds_sync;
+               }
+               I915_WRITE(LVDS, temp);
+       }
+
+       if (is_dp) {
+               intel_dp_set_m_n(crtc, mode, adjusted_mode);
+       }
+
+       I915_WRITE(DPLL(pipe), dpll);
+
+       /* Wait for the clocks to stabilize. */
+       POSTING_READ(DPLL(pipe));
+       udelay(150);
+
+       if (INTEL_INFO(dev)->gen >= 4) {
+               temp = 0;
+               if (is_sdvo) {
+                       temp = intel_mode_get_pixel_multiplier(adjusted_mode);
+                       if (temp > 1)
+                               temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+                       else
+                               temp = 0;
+               }
+               I915_WRITE(DPLL_MD(pipe), temp);
+       } else {
+               /* The pixel multiplier can only be updated once the
+                * DPLL is enabled and the clocks are stable.
+                *
+                * So write it again.
+                */
+               I915_WRITE(DPLL(pipe), dpll);
+       }
+
+       intel_crtc->lowfreq_avail = false;
+       if (is_lvds && has_reduced_clock && i915_powersave) {
+               I915_WRITE(FP1(pipe), fp2);
+               intel_crtc->lowfreq_avail = true;
+               if (HAS_PIPE_CXSR(dev)) {
+                       DRM_DEBUG_KMS("enabling CxSR downclocking\n");
+                       pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
+               }
+       } else {
+               I915_WRITE(FP1(pipe), fp);
+               if (HAS_PIPE_CXSR(dev)) {
+                       DRM_DEBUG_KMS("disabling CxSR downclocking\n");
+                       pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
+               }
+       }
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
+               pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
+               /* the chip adds 2 halflines automatically */
+               adjusted_mode->crtc_vdisplay -= 1;
+               adjusted_mode->crtc_vtotal -= 1;
+               adjusted_mode->crtc_vblank_start -= 1;
+               adjusted_mode->crtc_vblank_end -= 1;
+               adjusted_mode->crtc_vsync_end -= 1;
+               adjusted_mode->crtc_vsync_start -= 1;
+       } else
+               pipeconf &= ~PIPECONF_INTERLACE_W_FIELD_INDICATION; /* progressive */
+
+       I915_WRITE(HTOTAL(pipe),
+                  (adjusted_mode->crtc_hdisplay - 1) |
+                  ((adjusted_mode->crtc_htotal - 1) << 16));
+       I915_WRITE(HBLANK(pipe),
+                  (adjusted_mode->crtc_hblank_start - 1) |
+                  ((adjusted_mode->crtc_hblank_end - 1) << 16));
+       I915_WRITE(HSYNC(pipe),
+                  (adjusted_mode->crtc_hsync_start - 1) |
+                  ((adjusted_mode->crtc_hsync_end - 1) << 16));
+
+       I915_WRITE(VTOTAL(pipe),
+                  (adjusted_mode->crtc_vdisplay - 1) |
+                  ((adjusted_mode->crtc_vtotal - 1) << 16));
+       I915_WRITE(VBLANK(pipe),
+                  (adjusted_mode->crtc_vblank_start - 1) |
+                  ((adjusted_mode->crtc_vblank_end - 1) << 16));
+       I915_WRITE(VSYNC(pipe),
+                  (adjusted_mode->crtc_vsync_start - 1) |
+                  ((adjusted_mode->crtc_vsync_end - 1) << 16));
+
+       /* pipesrc and dspsize control the size that is scaled from,
+        * which should always be the user's requested size.
+        */
+       I915_WRITE(DSPSIZE(plane),
+                  ((mode->vdisplay - 1) << 16) |
+                  (mode->hdisplay - 1));
+       I915_WRITE(DSPPOS(plane), 0);
+       I915_WRITE(PIPESRC(pipe),
+                  ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
+
+       I915_WRITE(PIPECONF(pipe), pipeconf);
+       POSTING_READ(PIPECONF(pipe));
+       intel_enable_pipe(dev_priv, pipe, false);
+
+       intel_wait_for_vblank(dev, pipe);
+
+       I915_WRITE(DSPCNTR(plane), dspcntr);
+       POSTING_READ(DSPCNTR(plane));
+       intel_enable_plane(dev_priv, plane, pipe);
+
+       ret = intel_pipe_set_base(crtc, x, y, old_fb);
+
+       intel_update_watermarks(dev);
+
+       return ret;
+}
+
+static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
+                                 struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode,
+                                 int x, int y,
+                                 struct drm_framebuffer *old_fb)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int plane = intel_crtc->plane;
+       int refclk, num_connectors = 0;
+       intel_clock_t clock, reduced_clock;
+       u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
+       bool ok, has_reduced_clock = false, is_sdvo = false;
+       bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
+       struct intel_encoder *has_edp_encoder = NULL;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *encoder;
+       const intel_limit_t *limit;
+       int ret;
+       struct fdi_m_n m_n = {0};
+       u32 temp;
+       u32 lvds_sync = 0;
+       int target_clock, pixel_multiplier, lane, link_bw, bpp, factor;
+
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+               if (encoder->base.crtc != crtc)
+                       continue;
+
+               switch (encoder->type) {
+               case INTEL_OUTPUT_LVDS:
+                       is_lvds = true;
+                       break;
+               case INTEL_OUTPUT_SDVO:
+               case INTEL_OUTPUT_HDMI:
+                       is_sdvo = true;
+                       if (encoder->needs_tv_clock)
+                               is_tv = true;
+                       break;
+               case INTEL_OUTPUT_TVOUT:
+                       is_tv = true;
+                       break;
+               case INTEL_OUTPUT_ANALOG:
+                       is_crt = true;
+                       break;
+               case INTEL_OUTPUT_DISPLAYPORT:
+                       is_dp = true;
+                       break;
+               case INTEL_OUTPUT_EDP:
+                       has_edp_encoder = encoder;
+                       break;
+               }
+
+               num_connectors++;
+       }
+
+       if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
+               refclk = dev_priv->lvds_ssc_freq * 1000;
+               DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
+                             refclk / 1000);
+       } else {
+               refclk = 96000;
+               if (!has_edp_encoder ||
+                   intel_encoder_is_pch_edp(&has_edp_encoder->base))
+                       refclk = 120000; /* 120Mhz refclk */
+       }
+
+       /*
+        * Returns a set of divisors for the desired target clock with the given
+        * refclk, or FALSE.  The returned values represent the clock equation:
+        * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+        */
+       limit = intel_limit(crtc, refclk);
+       ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
+       if (!ok) {
+               DRM_ERROR("Couldn't find PLL settings for mode!\n");
+               return -EINVAL;
+       }
+
+       /* Ensure that the cursor is valid for the new mode before changing... */
+       intel_crtc_update_cursor(crtc, true);
+
+       if (is_lvds && dev_priv->lvds_downclock_avail) {
+               has_reduced_clock = limit->find_pll(limit, crtc,
+                                                   dev_priv->lvds_downclock,
+                                                   refclk,
+                                                   &reduced_clock);
+               if (has_reduced_clock && (clock.p != reduced_clock.p)) {
+                       /*
+                        * If the different P is found, it means that we can't
+                        * switch the display clock by using the FP0/FP1.
+                        * In such case we will disable the LVDS downclock
+                        * feature.
+                        */
+                       DRM_DEBUG_KMS("Different P is found for "
+                                     "LVDS clock/downclock\n");
+                       has_reduced_clock = 0;
+               }
+       }
+       /* SDVO TV has fixed PLL values depend on its clock range,
+          this mirrors vbios setting. */
+       if (is_sdvo && is_tv) {
+               if (adjusted_mode->clock >= 100000
+                   && adjusted_mode->clock < 140500) {
+                       clock.p1 = 2;
+                       clock.p2 = 10;
+                       clock.n = 3;
+                       clock.m1 = 16;
+                       clock.m2 = 8;
+               } else if (adjusted_mode->clock >= 140500
+                          && adjusted_mode->clock <= 200000) {
+                       clock.p1 = 1;
+                       clock.p2 = 10;
+                       clock.n = 6;
+                       clock.m1 = 12;
+                       clock.m2 = 8;
+               }
+       }
+
+       /* FDI link */
+       pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+       lane = 0;
+       /* CPU eDP doesn't require FDI link, so just set DP M/N
+          according to current link config */
+       if (has_edp_encoder &&
+           !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+               target_clock = mode->clock;
+               intel_edp_link_config(has_edp_encoder,
+                                     &lane, &link_bw);
+       } else {
+               /* [e]DP over FDI requires target mode clock
+                  instead of link clock */
+               if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
+                       target_clock = mode->clock;
+               else
+                       target_clock = adjusted_mode->clock;
+
+               /* FDI is a binary signal running at ~2.7GHz, encoding
+                * each output octet as 10 bits. The actual frequency
+                * is stored as a divider into a 100MHz clock, and the
+                * mode pixel clock is stored in units of 1KHz.
+                * Hence the bw of each lane in terms of the mode signal
+                * is:
+                */
+               link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
+       }
+
+       /* determine panel color depth */
+       temp = I915_READ(PIPECONF(pipe));
+       temp &= ~PIPE_BPC_MASK;
+       if (is_lvds) {
+               /* the BPC will be 6 if it is 18-bit LVDS panel */
+               if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
+                       temp |= PIPE_8BPC;
+               else
+                       temp |= PIPE_6BPC;
+       } else if (has_edp_encoder) {
+               switch (dev_priv->edp.bpp/3) {
+               case 8:
+                       temp |= PIPE_8BPC;
+                       break;
+               case 10:
+                       temp |= PIPE_10BPC;
+                       break;
+               case 6:
+                       temp |= PIPE_6BPC;
+                       break;
+               case 12:
+                       temp |= PIPE_12BPC;
+                       break;
+               }
+       } else
+               temp |= PIPE_8BPC;
+       I915_WRITE(PIPECONF(pipe), temp);
+
+       switch (temp & PIPE_BPC_MASK) {
+       case PIPE_8BPC:
+               bpp = 24;
+               break;
+       case PIPE_10BPC:
+               bpp = 30;
+               break;
+       case PIPE_6BPC:
+               bpp = 18;
+               break;
+       case PIPE_12BPC:
+               bpp = 36;
+               break;
+       default:
+               DRM_ERROR("unknown pipe bpc value\n");
+               bpp = 24;
+       }
+
+       if (!lane) {
+               /*
+                * Account for spread spectrum to avoid
+                * oversubscribing the link. Max center spread
+                * is 2.5%; use 5% for safety's sake.
+                */
+               u32 bps = target_clock * bpp * 21 / 20;
+               lane = bps / (link_bw * 8) + 1;
+       }
+
+       intel_crtc->fdi_lanes = lane;
+
+       if (pixel_multiplier > 1)
+               link_bw *= pixel_multiplier;
+       ironlake_compute_m_n(bpp, lane, target_clock, link_bw, &m_n);
+
+       /* Ironlake: try to setup display ref clock before DPLL
+        * enabling. This is only under driver's control after
+        * PCH B stepping, previous chipset stepping should be
+        * ignoring this setting.
+        */
+       temp = I915_READ(PCH_DREF_CONTROL);
+       /* Always enable nonspread source */
+       temp &= ~DREF_NONSPREAD_SOURCE_MASK;
+       temp |= DREF_NONSPREAD_SOURCE_ENABLE;
+       temp &= ~DREF_SSC_SOURCE_MASK;
+       temp |= DREF_SSC_SOURCE_ENABLE;
+       I915_WRITE(PCH_DREF_CONTROL, temp);
+
+       POSTING_READ(PCH_DREF_CONTROL);
+       udelay(200);
+
+       if (has_edp_encoder) {
+               if (intel_panel_use_ssc(dev_priv)) {
+                       temp |= DREF_SSC1_ENABLE;
+                       I915_WRITE(PCH_DREF_CONTROL, temp);
+
+                       POSTING_READ(PCH_DREF_CONTROL);
+                       udelay(200);
+               }
+               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+
+               /* Enable CPU source on CPU attached eDP */
+               if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+                       if (intel_panel_use_ssc(dev_priv))
+                               temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+                       else
+                               temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
+               } else {
+                       /* Enable SSC on PCH eDP if needed */
+                       if (intel_panel_use_ssc(dev_priv)) {
+                               DRM_ERROR("enabling SSC on PCH\n");
+                               temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
+                       }
+               }
+               I915_WRITE(PCH_DREF_CONTROL, temp);
+               POSTING_READ(PCH_DREF_CONTROL);
+               udelay(200);
+       }
+
+       fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
+       if (has_reduced_clock)
+               fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
+                       reduced_clock.m2;
+
+       /* Enable autotuning of the PLL clock (if permissible) */
+       factor = 21;
+       if (is_lvds) {
+               if ((intel_panel_use_ssc(dev_priv) &&
+                    dev_priv->lvds_ssc_freq == 100) ||
+                   (I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP)
+                       factor = 25;
+       } else if (is_sdvo && is_tv)
+               factor = 20;
+
+       if (clock.m1 < factor * clock.n)
+               fp |= FP_CB_TUNE;
+
+       dpll = 0;
+
+       if (is_lvds)
+               dpll |= DPLLB_MODE_LVDS;
+       else
+               dpll |= DPLLB_MODE_DAC_SERIAL;
+       if (is_sdvo) {
+               int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+               if (pixel_multiplier > 1) {
+                       dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
+               }
+               dpll |= DPLL_DVO_HIGH_SPEED;
+       }
+       if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
+               dpll |= DPLL_DVO_HIGH_SPEED;
+
+       /* compute bitmask from p1 value */
+       dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+       /* also FPA1 */
+       dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
+
+       switch (clock.p2) {
+       case 5:
+               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
+               break;
+       case 7:
+               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
+               break;
+       case 10:
+               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
+               break;
+       case 14:
+               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
+               break;
+       }
+
+       if (is_sdvo && is_tv)
+               dpll |= PLL_REF_INPUT_TVCLKINBC;
+       else if (is_tv)
+               /* XXX: just matching BIOS for now */
+               /*      dpll |= PLL_REF_INPUT_TVCLKINBC; */
+               dpll |= 3;
+       else if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2)
+               dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
+       else
+               dpll |= PLL_REF_INPUT_DREFCLK;
+
+       /* setup pipeconf */
+       pipeconf = I915_READ(PIPECONF(pipe));
+
+       /* Set up the display plane register */
+       dspcntr = DISPPLANE_GAMMA_ENABLE;
+
+       DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
+       drm_mode_debug_printmodeline(mode);
+
+       /* PCH eDP needs FDI, but CPU eDP does not */
+       if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+               I915_WRITE(PCH_FP0(pipe), fp);
+               I915_WRITE(PCH_DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
+
+               POSTING_READ(PCH_DPLL(pipe));
+               udelay(150);
+       }
+
+       /* enable transcoder DPLL */
+       if (HAS_PCH_CPT(dev)) {
+               temp = I915_READ(PCH_DPLL_SEL);
                switch (pipe) {
                case 0:
                        temp |= TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL;
@@ -4964,11 +5061,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
         * things on.
         */
        if (is_lvds) {
-               reg = LVDS;
-               if (HAS_PCH_SPLIT(dev))
-                       reg = PCH_LVDS;
-
-               temp = I915_READ(reg);
+               temp = I915_READ(PCH_LVDS);
                temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
                if (pipe == 1) {
                        if (HAS_PCH_CPT(dev))
@@ -4995,13 +5088,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                 * appropriately here, but we need to look more thoroughly into how
                 * panels behave in the two modes.
                 */
-               /* set the dithering flag on non-PCH LVDS as needed */
-               if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
-                       if (dev_priv->lvds_dither)
-                               temp |= LVDS_ENABLE_DITHER;
-                       else
-                               temp &= ~LVDS_ENABLE_DITHER;
-               }
                if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
                        lvds_sync |= LVDS_HSYNC_POLARITY;
                if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
@@ -5018,22 +5104,20 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
                        temp |= lvds_sync;
                }
-               I915_WRITE(reg, temp);
+               I915_WRITE(PCH_LVDS, temp);
        }
 
        /* set the dithering flag and clear for anything other than a panel. */
-       if (HAS_PCH_SPLIT(dev)) {
-               pipeconf &= ~PIPECONF_DITHER_EN;
-               pipeconf &= ~PIPECONF_DITHER_TYPE_MASK;
-               if (dev_priv->lvds_dither && (is_lvds || has_edp_encoder)) {
-                       pipeconf |= PIPECONF_DITHER_EN;
-                       pipeconf |= PIPECONF_DITHER_TYPE_ST1;
-               }
+       pipeconf &= ~PIPECONF_DITHER_EN;
+       pipeconf &= ~PIPECONF_DITHER_TYPE_MASK;
+       if (dev_priv->lvds_dither && (is_lvds || has_edp_encoder)) {
+               pipeconf |= PIPECONF_DITHER_EN;
+               pipeconf |= PIPECONF_DITHER_TYPE_ST1;
        }
 
        if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
                intel_dp_set_m_n(crtc, mode, adjusted_mode);
-       } else if (HAS_PCH_SPLIT(dev)) {
+       } else {
                /* For non-DP output, clear any trans DP clock recovery setting.*/
                I915_WRITE(TRANSDATA_M1(pipe), 0);
                I915_WRITE(TRANSDATA_N1(pipe), 0);
@@ -5041,43 +5125,32 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                I915_WRITE(TRANSDPLINK_N1(pipe), 0);
        }
 
-       if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-               I915_WRITE(dpll_reg, dpll);
+       if (!has_edp_encoder ||
+           intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+               I915_WRITE(PCH_DPLL(pipe), dpll);
 
                /* Wait for the clocks to stabilize. */
-               POSTING_READ(dpll_reg);
+               POSTING_READ(PCH_DPLL(pipe));
                udelay(150);
 
-               if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
-                       temp = 0;
-                       if (is_sdvo) {
-                               temp = intel_mode_get_pixel_multiplier(adjusted_mode);
-                               if (temp > 1)
-                                       temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
-                               else
-                                       temp = 0;
-                       }
-                       I915_WRITE(DPLL_MD(pipe), temp);
-               } else {
-                       /* The pixel multiplier can only be updated once the
-                        * DPLL is enabled and the clocks are stable.
-                        *
-                        * So write it again.
-                        */
-                       I915_WRITE(dpll_reg, dpll);
-               }
+               /* The pixel multiplier can only be updated once the
+                * DPLL is enabled and the clocks are stable.
+                *
+                * So write it again.
+                */
+               I915_WRITE(PCH_DPLL(pipe), dpll);
        }
 
        intel_crtc->lowfreq_avail = false;
        if (is_lvds && has_reduced_clock && i915_powersave) {
-               I915_WRITE(fp_reg + 4, fp2);
+               I915_WRITE(PCH_FP1(pipe), fp2);
                intel_crtc->lowfreq_avail = true;
                if (HAS_PIPE_CXSR(dev)) {
                        DRM_DEBUG_KMS("enabling CxSR downclocking\n");
                        pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
                }
        } else {
-               I915_WRITE(fp_reg + 4, fp);
+               I915_WRITE(PCH_FP1(pipe), fp);
                if (HAS_PIPE_CXSR(dev)) {
                        DRM_DEBUG_KMS("disabling CxSR downclocking\n");
                        pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
@@ -5116,33 +5189,24 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                   (adjusted_mode->crtc_vsync_start - 1) |
                   ((adjusted_mode->crtc_vsync_end - 1) << 16));
 
-       /* pipesrc and dspsize control the size that is scaled from,
-        * which should always be the user's requested size.
+       /* pipesrc controls the size that is scaled from, which should
+        * always be the user's requested size.
         */
-       if (!HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(DSPSIZE(plane),
-                          ((mode->vdisplay - 1) << 16) |
-                          (mode->hdisplay - 1));
-               I915_WRITE(DSPPOS(plane), 0);
-       }
        I915_WRITE(PIPESRC(pipe),
                   ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
 
-       if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m);
-               I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n);
-               I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m);
-               I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n);
+       I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m);
+       I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n);
+       I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m);
+       I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n);
 
-               if (has_edp_encoder && !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-                       ironlake_set_pll_edp(crtc, adjusted_mode->clock);
-               }
+       if (has_edp_encoder &&
+           !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+               ironlake_set_pll_edp(crtc, adjusted_mode->clock);
        }
 
        I915_WRITE(PIPECONF(pipe), pipeconf);
        POSTING_READ(PIPECONF(pipe));
-       if (!HAS_PCH_SPLIT(dev))
-               intel_enable_pipe(dev_priv, pipe, false);
 
        intel_wait_for_vblank(dev, pipe);
 
@@ -5154,13 +5218,31 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
        I915_WRITE(DSPCNTR(plane), dspcntr);
        POSTING_READ(DSPCNTR(plane));
-       if (!HAS_PCH_SPLIT(dev))
-               intel_enable_plane(dev_priv, plane, pipe);
 
        ret = intel_pipe_set_base(crtc, x, y, old_fb);
 
        intel_update_watermarks(dev);
 
+       return ret;
+}
+
+static int intel_crtc_mode_set(struct drm_crtc *crtc,
+                              struct drm_display_mode *mode,
+                              struct drm_display_mode *adjusted_mode,
+                              int x, int y,
+                              struct drm_framebuffer *old_fb)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int ret;
+
+       drm_vblank_pre_modeset(dev, pipe);
+
+       ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode,
+                                             x, y, old_fb);
+
        drm_vblank_post_modeset(dev, pipe);
 
        return ret;
@@ -5483,43 +5565,140 @@ static struct drm_display_mode load_detect_mode = {
                 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
 };
 
-struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
-                                           struct drm_connector *connector,
-                                           struct drm_display_mode *mode,
-                                           int *dpms_mode)
+static struct drm_framebuffer *
+intel_framebuffer_create(struct drm_device *dev,
+                        struct drm_mode_fb_cmd *mode_cmd,
+                        struct drm_i915_gem_object *obj)
+{
+       struct intel_framebuffer *intel_fb;
+       int ret;
+
+       intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
+       if (!intel_fb) {
+               drm_gem_object_unreference_unlocked(&obj->base);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj);
+       if (ret) {
+               drm_gem_object_unreference_unlocked(&obj->base);
+               kfree(intel_fb);
+               return ERR_PTR(ret);
+       }
+
+       return &intel_fb->base;
+}
+
+static u32
+intel_framebuffer_pitch_for_width(int width, int bpp)
+{
+       u32 pitch = DIV_ROUND_UP(width * bpp, 8);
+       return ALIGN(pitch, 64);
+}
+
+static u32
+intel_framebuffer_size_for_mode(struct drm_display_mode *mode, int bpp)
+{
+       u32 pitch = intel_framebuffer_pitch_for_width(mode->hdisplay, bpp);
+       return ALIGN(pitch * mode->vdisplay, PAGE_SIZE);
+}
+
+static struct drm_framebuffer *
+intel_framebuffer_create_for_mode(struct drm_device *dev,
+                                 struct drm_display_mode *mode,
+                                 int depth, int bpp)
+{
+       struct drm_i915_gem_object *obj;
+       struct drm_mode_fb_cmd mode_cmd;
+
+       obj = i915_gem_alloc_object(dev,
+                                   intel_framebuffer_size_for_mode(mode, bpp));
+       if (obj == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       mode_cmd.width = mode->hdisplay;
+       mode_cmd.height = mode->vdisplay;
+       mode_cmd.depth = depth;
+       mode_cmd.bpp = bpp;
+       mode_cmd.pitch = intel_framebuffer_pitch_for_width(mode_cmd.width, bpp);
+
+       return intel_framebuffer_create(dev, &mode_cmd, obj);
+}
+
+static struct drm_framebuffer *
+mode_fits_in_fbdev(struct drm_device *dev,
+                  struct drm_display_mode *mode)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj;
+       struct drm_framebuffer *fb;
+
+       if (dev_priv->fbdev == NULL)
+               return NULL;
+
+       obj = dev_priv->fbdev->ifb.obj;
+       if (obj == NULL)
+               return NULL;
+
+       fb = &dev_priv->fbdev->ifb.base;
+       if (fb->pitch < intel_framebuffer_pitch_for_width(mode->hdisplay,
+                                                         fb->bits_per_pixel))
+               return NULL;
+
+       if (obj->base.size < mode->vdisplay * fb->pitch)
+               return NULL;
+
+       return fb;
+}
+
+bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
+                               struct drm_connector *connector,
+                               struct drm_display_mode *mode,
+                               struct intel_load_detect_pipe *old)
 {
        struct intel_crtc *intel_crtc;
        struct drm_crtc *possible_crtc;
-       struct drm_crtc *supported_crtc =NULL;
        struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_crtc *crtc = NULL;
        struct drm_device *dev = encoder->dev;
-       struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
-       struct drm_crtc_helper_funcs *crtc_funcs;
+       struct drm_framebuffer *old_fb;
        int i = -1;
 
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
+                     connector->base.id, drm_get_connector_name(connector),
+                     encoder->base.id, drm_get_encoder_name(encoder));
+
        /*
         * Algorithm gets a little messy:
+        *
         *   - if the connector already has an assigned crtc, use it (but make
         *     sure it's on first)
+        *
         *   - try to find the first unused crtc that can drive this connector,
         *     and use that if we find one
-        *   - if there are no unused crtcs available, try to use the first
-        *     one we found that supports the connector
         */
 
        /* See if we already have a CRTC for this connector */
        if (encoder->crtc) {
                crtc = encoder->crtc;
-               /* Make sure the crtc and connector are running */
+
                intel_crtc = to_intel_crtc(crtc);
-               *dpms_mode = intel_crtc->dpms_mode;
+               old->dpms_mode = intel_crtc->dpms_mode;
+               old->load_detect_temp = false;
+
+               /* Make sure the crtc and connector are running */
                if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
+                       struct drm_encoder_helper_funcs *encoder_funcs;
+                       struct drm_crtc_helper_funcs *crtc_funcs;
+
                        crtc_funcs = crtc->helper_private;
                        crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+
+                       encoder_funcs = encoder->helper_private;
                        encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
                }
-               return crtc;
+
+               return true;
        }
 
        /* Find an unused one (if possible) */
@@ -5531,46 +5710,66 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
                        crtc = possible_crtc;
                        break;
                }
-               if (!supported_crtc)
-                       supported_crtc = possible_crtc;
        }
 
        /*
         * If we didn't find an unused CRTC, don't use any.
         */
        if (!crtc) {
-               return NULL;
+               DRM_DEBUG_KMS("no pipe available for load-detect\n");
+               return false;
        }
 
        encoder->crtc = crtc;
        connector->encoder = encoder;
-       intel_encoder->load_detect_temp = true;
 
        intel_crtc = to_intel_crtc(crtc);
-       *dpms_mode = intel_crtc->dpms_mode;
+       old->dpms_mode = intel_crtc->dpms_mode;
+       old->load_detect_temp = true;
+       old->release_fb = NULL;
 
-       if (!crtc->enabled) {
-               if (!mode)
-                       mode = &load_detect_mode;
-               drm_crtc_helper_set_mode(crtc, mode, 0, 0, crtc->fb);
-       } else {
-               if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
-                       crtc_funcs = crtc->helper_private;
-                       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
-               }
+       if (!mode)
+               mode = &load_detect_mode;
 
-               /* Add this connector to the crtc */
-               encoder_funcs->mode_set(encoder, &crtc->mode, &crtc->mode);
-               encoder_funcs->commit(encoder);
+       old_fb = crtc->fb;
+
+       /* We need a framebuffer large enough to accommodate all accesses
+        * that the plane may generate whilst we perform load detection.
+        * We can not rely on the fbcon either being present (we get called
+        * during its initialisation to detect all boot displays, or it may
+        * not even exist) or that it is large enough to satisfy the
+        * requested mode.
+        */
+       crtc->fb = mode_fits_in_fbdev(dev, mode);
+       if (crtc->fb == NULL) {
+               DRM_DEBUG_KMS("creating tmp fb for load-detection\n");
+               crtc->fb = intel_framebuffer_create_for_mode(dev, mode, 24, 32);
+               old->release_fb = crtc->fb;
+       } else
+               DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n");
+       if (IS_ERR(crtc->fb)) {
+               DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n");
+               crtc->fb = old_fb;
+               return false;
        }
+
+       if (!drm_crtc_helper_set_mode(crtc, mode, 0, 0, old_fb)) {
+               DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
+               if (old->release_fb)
+                       old->release_fb->funcs->destroy(old->release_fb);
+               crtc->fb = old_fb;
+               return false;
+       }
+
        /* let the connector get through one full cycle before testing */
        intel_wait_for_vblank(dev, intel_crtc->pipe);
 
-       return crtc;
+       return true;
 }
 
 void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
-                                   struct drm_connector *connector, int dpms_mode)
+                                   struct drm_connector *connector,
+                                   struct intel_load_detect_pipe *old)
 {
        struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_device *dev = encoder->dev;
@@ -5578,19 +5777,24 @@ void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
        struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
        struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
 
-       if (intel_encoder->load_detect_temp) {
-               encoder->crtc = NULL;
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
+                     connector->base.id, drm_get_connector_name(connector),
+                     encoder->base.id, drm_get_encoder_name(encoder));
+
+       if (old->load_detect_temp) {
                connector->encoder = NULL;
-               intel_encoder->load_detect_temp = false;
-               crtc->enabled = drm_helper_crtc_in_use(crtc);
                drm_helper_disable_unused_functions(dev);
+
+               if (old->release_fb)
+                       old->release_fb->funcs->destroy(old->release_fb);
+
+               return;
        }
 
        /* Switch crtc and encoder back off if necessary */
-       if (crtc->enabled && dpms_mode != DRM_MODE_DPMS_ON) {
-               if (encoder->crtc == crtc)
-                       encoder_funcs->dpms(encoder, dpms_mode);
-               crtc_funcs->dpms(crtc, dpms_mode);
+       if (old->dpms_mode != DRM_MODE_DPMS_ON) {
+               encoder_funcs->dpms(encoder, old->dpms_mode);
+               crtc_funcs->dpms(crtc, old->dpms_mode);
        }
 }
 
@@ -6185,6 +6389,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                break;
 
        case 6:
+       case 7:
                OUT_RING(MI_DISPLAY_FLIP |
                         MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
                OUT_RING(fb->pitch | obj->tiling_mode);
@@ -6504,6 +6709,9 @@ static void intel_setup_outputs(struct drm_device *dev)
        }
 
        intel_panel_setup_backlight(dev);
+
+       /* disable all the possible outputs/crtcs before entering KMS mode */
+       drm_helper_disable_unused_functions(dev);
 }
 
 static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
@@ -6571,27 +6779,12 @@ intel_user_framebuffer_create(struct drm_device *dev,
                              struct drm_mode_fb_cmd *mode_cmd)
 {
        struct drm_i915_gem_object *obj;
-       struct intel_framebuffer *intel_fb;
-       int ret;
 
        obj = to_intel_bo(drm_gem_object_lookup(dev, filp, mode_cmd->handle));
        if (&obj->base == NULL)
                return ERR_PTR(-ENOENT);
 
-       intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
-       if (!intel_fb) {
-               drm_gem_object_unreference_unlocked(&obj->base);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj);
-       if (ret) {
-               drm_gem_object_unreference_unlocked(&obj->base);
-               kfree(intel_fb);
-               return ERR_PTR(ret);
-       }
-
-       return &intel_fb->base;
+       return intel_framebuffer_create(dev, mode_cmd, obj);
 }
 
 static const struct drm_mode_config_funcs intel_mode_funcs = {
@@ -6605,13 +6798,14 @@ intel_alloc_context_page(struct drm_device *dev)
        struct drm_i915_gem_object *ctx;
        int ret;
 
+       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
        ctx = i915_gem_alloc_object(dev, 4096);
        if (!ctx) {
                DRM_DEBUG("failed to alloc power context, RC6 disabled\n");
                return NULL;
        }
 
-       mutex_lock(&dev->struct_mutex);
        ret = i915_gem_object_pin(ctx, 4096, true);
        if (ret) {
                DRM_ERROR("failed to pin power context: %d\n", ret);
@@ -6623,7 +6817,6 @@ intel_alloc_context_page(struct drm_device *dev)
                DRM_ERROR("failed to set-domain on power context: %d\n", ret);
                goto err_unpin;
        }
-       mutex_unlock(&dev->struct_mutex);
 
        return ctx;
 
@@ -6758,6 +6951,11 @@ void gen6_disable_rps(struct drm_device *dev)
        I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
        I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
        I915_WRITE(GEN6_PMIER, 0);
+
+       spin_lock_irq(&dev_priv->rps_lock);
+       dev_priv->pm_iir = 0;
+       spin_unlock_irq(&dev_priv->rps_lock);
+
        I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
 }
 
@@ -6851,7 +7049,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
 {
        u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
        u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
-       u32 pcu_mbox;
+       u32 pcu_mbox, rc6_mask = 0;
        int cur_freq, min_freq, max_freq;
        int i;
 
@@ -6862,7 +7060,8 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
         * userspace...
         */
        I915_WRITE(GEN6_RC_STATE, 0);
-       __gen6_gt_force_wake_get(dev_priv);
+       mutex_lock(&dev_priv->dev->struct_mutex);
+       gen6_gt_force_wake_get(dev_priv);
 
        /* disable the counters and set deterministic thresholds */
        I915_WRITE(GEN6_RC_CONTROL, 0);
@@ -6882,9 +7081,12 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
        I915_WRITE(GEN6_RC6p_THRESHOLD, 100000);
        I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */
 
+       if (i915_enable_rc6)
+               rc6_mask = GEN6_RC_CTL_RC6p_ENABLE |
+                       GEN6_RC_CTL_RC6_ENABLE;
+
        I915_WRITE(GEN6_RC_CONTROL,
-                  GEN6_RC_CTL_RC6p_ENABLE |
-                  GEN6_RC_CTL_RC6_ENABLE |
+                  rc6_mask |
                   GEN6_RC_CTL_EI_MODE(1) |
                   GEN6_RC_CTL_HW_ENABLE);
 
@@ -6956,168 +7158,237 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
                   GEN6_PM_RP_DOWN_THRESHOLD |
                   GEN6_PM_RP_UP_EI_EXPIRED |
                   GEN6_PM_RP_DOWN_EI_EXPIRED);
+       spin_lock_irq(&dev_priv->rps_lock);
+       WARN_ON(dev_priv->pm_iir != 0);
        I915_WRITE(GEN6_PMIMR, 0);
+       spin_unlock_irq(&dev_priv->rps_lock);
        /* enable all PM interrupts */
        I915_WRITE(GEN6_PMINTRMSK, 0);
 
-       __gen6_gt_force_wake_put(dev_priv);
+       gen6_gt_force_wake_put(dev_priv);
+       mutex_unlock(&dev_priv->dev->struct_mutex);
+}
+
+static void ironlake_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+
+       /* Required for FBC */
+       dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE |
+               DPFCRUNIT_CLOCK_GATE_DISABLE |
+               DPFDUNIT_CLOCK_GATE_DISABLE;
+       /* Required for CxSR */
+       dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE;
+
+       I915_WRITE(PCH_3DCGDIS0,
+                  MARIUNIT_CLOCK_GATE_DISABLE |
+                  SVSMUNIT_CLOCK_GATE_DISABLE);
+       I915_WRITE(PCH_3DCGDIS1,
+                  VFMUNIT_CLOCK_GATE_DISABLE);
+
+       I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+
+       /*
+        * According to the spec the following bits should be set in
+        * order to enable memory self-refresh
+        * The bit 22/21 of 0x42004
+        * The bit 5 of 0x42020
+        * The bit 15 of 0x45000
+        */
+       I915_WRITE(ILK_DISPLAY_CHICKEN2,
+                  (I915_READ(ILK_DISPLAY_CHICKEN2) |
+                   ILK_DPARB_GATE | ILK_VSDPFD_FULL));
+       I915_WRITE(ILK_DSPCLK_GATE,
+                  (I915_READ(ILK_DSPCLK_GATE) |
+                   ILK_DPARB_CLK_GATE));
+       I915_WRITE(DISP_ARB_CTL,
+                  (I915_READ(DISP_ARB_CTL) |
+                   DISP_FBC_WM_DIS));
+       I915_WRITE(WM3_LP_ILK, 0);
+       I915_WRITE(WM2_LP_ILK, 0);
+       I915_WRITE(WM1_LP_ILK, 0);
+
+       /*
+        * Based on the document from hardware guys the following bits
+        * should be set unconditionally in order to enable FBC.
+        * The bit 22 of 0x42000
+        * The bit 22 of 0x42004
+        * The bit 7,8,9 of 0x42020.
+        */
+       if (IS_IRONLAKE_M(dev)) {
+               I915_WRITE(ILK_DISPLAY_CHICKEN1,
+                          I915_READ(ILK_DISPLAY_CHICKEN1) |
+                          ILK_FBCQ_DIS);
+               I915_WRITE(ILK_DISPLAY_CHICKEN2,
+                          I915_READ(ILK_DISPLAY_CHICKEN2) |
+                          ILK_DPARB_GATE);
+               I915_WRITE(ILK_DSPCLK_GATE,
+                          I915_READ(ILK_DSPCLK_GATE) |
+                          ILK_DPFC_DIS1 |
+                          ILK_DPFC_DIS2 |
+                          ILK_CLK_FBC);
+       }
+
+       I915_WRITE(ILK_DISPLAY_CHICKEN2,
+                  I915_READ(ILK_DISPLAY_CHICKEN2) |
+                  ILK_ELPIN_409_SELECT);
+       I915_WRITE(_3D_CHICKEN2,
+                  _3D_CHICKEN2_WM_READ_PIPELINED << 16 |
+                  _3D_CHICKEN2_WM_READ_PIPELINED);
 }
 
-void intel_enable_clock_gating(struct drm_device *dev)
+static void gen6_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
+       uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+
+       I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+
+       I915_WRITE(ILK_DISPLAY_CHICKEN2,
+                  I915_READ(ILK_DISPLAY_CHICKEN2) |
+                  ILK_ELPIN_409_SELECT);
+
+       I915_WRITE(WM3_LP_ILK, 0);
+       I915_WRITE(WM2_LP_ILK, 0);
+       I915_WRITE(WM1_LP_ILK, 0);
 
        /*
-        * Disable clock gating reported to work incorrectly according to the
-        * specs, but enable as much else as we can.
+        * According to the spec the following bits should be
+        * set in order to enable memory self-refresh and fbc:
+        * The bit21 and bit22 of 0x42000
+        * The bit21 and bit22 of 0x42004
+        * The bit5 and bit7 of 0x42020
+        * The bit14 of 0x70180
+        * The bit14 of 0x71180
         */
-       if (HAS_PCH_SPLIT(dev)) {
-               uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+       I915_WRITE(ILK_DISPLAY_CHICKEN1,
+                  I915_READ(ILK_DISPLAY_CHICKEN1) |
+                  ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS);
+       I915_WRITE(ILK_DISPLAY_CHICKEN2,
+                  I915_READ(ILK_DISPLAY_CHICKEN2) |
+                  ILK_DPARB_GATE | ILK_VSDPFD_FULL);
+       I915_WRITE(ILK_DSPCLK_GATE,
+                  I915_READ(ILK_DSPCLK_GATE) |
+                  ILK_DPARB_CLK_GATE  |
+                  ILK_DPFD_CLK_GATE);
 
-               if (IS_GEN5(dev)) {
-                       /* Required for FBC */
-                       dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE |
-                               DPFCRUNIT_CLOCK_GATE_DISABLE |
-                               DPFDUNIT_CLOCK_GATE_DISABLE;
-                       /* Required for CxSR */
-                       dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE;
-
-                       I915_WRITE(PCH_3DCGDIS0,
-                                  MARIUNIT_CLOCK_GATE_DISABLE |
-                                  SVSMUNIT_CLOCK_GATE_DISABLE);
-                       I915_WRITE(PCH_3DCGDIS1,
-                                  VFMUNIT_CLOCK_GATE_DISABLE);
-               }
+       for_each_pipe(pipe)
+               I915_WRITE(DSPCNTR(pipe),
+                          I915_READ(DSPCNTR(pipe)) |
+                          DISPPLANE_TRICKLE_FEED_DISABLE);
+}
 
-               I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+static void ivybridge_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe;
+       uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
 
-               /*
-                * On Ibex Peak and Cougar Point, we need to disable clock
-                * gating for the panel power sequencer or it will fail to
-                * start up when no ports are active.
-                */
-               I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+       I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
 
-               /*
-                * According to the spec the following bits should be set in
-                * order to enable memory self-refresh
-                * The bit 22/21 of 0x42004
-                * The bit 5 of 0x42020
-                * The bit 15 of 0x45000
-                */
-               if (IS_GEN5(dev)) {
-                       I915_WRITE(ILK_DISPLAY_CHICKEN2,
-                                       (I915_READ(ILK_DISPLAY_CHICKEN2) |
-                                       ILK_DPARB_GATE | ILK_VSDPFD_FULL));
-                       I915_WRITE(ILK_DSPCLK_GATE,
-                                       (I915_READ(ILK_DSPCLK_GATE) |
-                                               ILK_DPARB_CLK_GATE));
-                       I915_WRITE(DISP_ARB_CTL,
-                                       (I915_READ(DISP_ARB_CTL) |
-                                               DISP_FBC_WM_DIS));
-                       I915_WRITE(WM3_LP_ILK, 0);
-                       I915_WRITE(WM2_LP_ILK, 0);
-                       I915_WRITE(WM1_LP_ILK, 0);
-               }
-               /*
-                * Based on the document from hardware guys the following bits
-                * should be set unconditionally in order to enable FBC.
-                * The bit 22 of 0x42000
-                * The bit 22 of 0x42004
-                * The bit 7,8,9 of 0x42020.
-                */
-               if (IS_IRONLAKE_M(dev)) {
-                       I915_WRITE(ILK_DISPLAY_CHICKEN1,
-                                  I915_READ(ILK_DISPLAY_CHICKEN1) |
-                                  ILK_FBCQ_DIS);
-                       I915_WRITE(ILK_DISPLAY_CHICKEN2,
-                                  I915_READ(ILK_DISPLAY_CHICKEN2) |
-                                  ILK_DPARB_GATE);
-                       I915_WRITE(ILK_DSPCLK_GATE,
-                                  I915_READ(ILK_DSPCLK_GATE) |
-                                  ILK_DPFC_DIS1 |
-                                  ILK_DPFC_DIS2 |
-                                  ILK_CLK_FBC);
-               }
+       I915_WRITE(WM3_LP_ILK, 0);
+       I915_WRITE(WM2_LP_ILK, 0);
+       I915_WRITE(WM1_LP_ILK, 0);
 
-               I915_WRITE(ILK_DISPLAY_CHICKEN2,
-                          I915_READ(ILK_DISPLAY_CHICKEN2) |
-                          ILK_ELPIN_409_SELECT);
+       I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE);
 
-               if (IS_GEN5(dev)) {
-                       I915_WRITE(_3D_CHICKEN2,
-                                  _3D_CHICKEN2_WM_READ_PIPELINED << 16 |
-                                  _3D_CHICKEN2_WM_READ_PIPELINED);
-               }
+       for_each_pipe(pipe)
+               I915_WRITE(DSPCNTR(pipe),
+                          I915_READ(DSPCNTR(pipe)) |
+                          DISPPLANE_TRICKLE_FEED_DISABLE);
+}
+
+static void g4x_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t dspclk_gate;
 
-               if (IS_GEN6(dev)) {
-                       I915_WRITE(WM3_LP_ILK, 0);
-                       I915_WRITE(WM2_LP_ILK, 0);
-                       I915_WRITE(WM1_LP_ILK, 0);
+       I915_WRITE(RENCLK_GATE_D1, 0);
+       I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE |
+                  GS_UNIT_CLOCK_GATE_DISABLE |
+                  CL_UNIT_CLOCK_GATE_DISABLE);
+       I915_WRITE(RAMCLK_GATE_D, 0);
+       dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE |
+               OVRUNIT_CLOCK_GATE_DISABLE |
+               OVCUNIT_CLOCK_GATE_DISABLE;
+       if (IS_GM45(dev))
+               dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
+       I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
+}
 
-                       /*
-                        * According to the spec the following bits should be
-                        * set in order to enable memory self-refresh and fbc:
-                        * The bit21 and bit22 of 0x42000
-                        * The bit21 and bit22 of 0x42004
-                        * The bit5 and bit7 of 0x42020
-                        * The bit14 of 0x70180
-                        * The bit14 of 0x71180
-                        */
-                       I915_WRITE(ILK_DISPLAY_CHICKEN1,
-                                  I915_READ(ILK_DISPLAY_CHICKEN1) |
-                                  ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS);
-                       I915_WRITE(ILK_DISPLAY_CHICKEN2,
-                                  I915_READ(ILK_DISPLAY_CHICKEN2) |
-                                  ILK_DPARB_GATE | ILK_VSDPFD_FULL);
-                       I915_WRITE(ILK_DSPCLK_GATE,
-                                  I915_READ(ILK_DSPCLK_GATE) |
-                                  ILK_DPARB_CLK_GATE  |
-                                  ILK_DPFD_CLK_GATE);
-
-                       for_each_pipe(pipe)
-                               I915_WRITE(DSPCNTR(pipe),
-                                          I915_READ(DSPCNTR(pipe)) |
-                                          DISPPLANE_TRICKLE_FEED_DISABLE);
-               }
-       } else if (IS_G4X(dev)) {
-               uint32_t dspclk_gate;
-               I915_WRITE(RENCLK_GATE_D1, 0);
-               I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE |
-                      GS_UNIT_CLOCK_GATE_DISABLE |
-                      CL_UNIT_CLOCK_GATE_DISABLE);
-               I915_WRITE(RAMCLK_GATE_D, 0);
-               dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE |
-                       OVRUNIT_CLOCK_GATE_DISABLE |
-                       OVCUNIT_CLOCK_GATE_DISABLE;
-               if (IS_GM45(dev))
-                       dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
-               I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
-       } else if (IS_CRESTLINE(dev)) {
-               I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
-               I915_WRITE(RENCLK_GATE_D2, 0);
-               I915_WRITE(DSPCLK_GATE_D, 0);
-               I915_WRITE(RAMCLK_GATE_D, 0);
-               I915_WRITE16(DEUC, 0);
-       } else if (IS_BROADWATER(dev)) {
-               I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
-                      I965_RCC_CLOCK_GATE_DISABLE |
-                      I965_RCPB_CLOCK_GATE_DISABLE |
-                      I965_ISC_CLOCK_GATE_DISABLE |
-                      I965_FBC_CLOCK_GATE_DISABLE);
-               I915_WRITE(RENCLK_GATE_D2, 0);
-       } else if (IS_GEN3(dev)) {
-               u32 dstate = I915_READ(D_STATE);
+static void crestline_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
-               dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
-                       DSTATE_DOT_CLOCK_GATING;
-               I915_WRITE(D_STATE, dstate);
-       } else if (IS_I85X(dev) || IS_I865G(dev)) {
-               I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
-       } else if (IS_I830(dev)) {
-               I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
-       }
+       I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
+       I915_WRITE(RENCLK_GATE_D2, 0);
+       I915_WRITE(DSPCLK_GATE_D, 0);
+       I915_WRITE(RAMCLK_GATE_D, 0);
+       I915_WRITE16(DEUC, 0);
+}
+
+static void broadwater_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
+                  I965_RCC_CLOCK_GATE_DISABLE |
+                  I965_RCPB_CLOCK_GATE_DISABLE |
+                  I965_ISC_CLOCK_GATE_DISABLE |
+                  I965_FBC_CLOCK_GATE_DISABLE);
+       I915_WRITE(RENCLK_GATE_D2, 0);
+}
+
+static void gen3_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 dstate = I915_READ(D_STATE);
+
+       dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
+               DSTATE_DOT_CLOCK_GATING;
+       I915_WRITE(D_STATE, dstate);
+}
+
+static void i85x_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
+}
+
+static void i830_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
+}
+
+static void ibx_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       /*
+        * On Ibex Peak and Cougar Point, we need to disable clock
+        * gating for the panel power sequencer or it will fail to
+        * start up when no ports are active.
+        */
+       I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+}
+
+static void cpt_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       /*
+        * On Ibex Peak and Cougar Point, we need to disable clock
+        * gating for the panel power sequencer or it will fail to
+        * start up when no ports are active.
+        */
+       I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+       I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) |
+                  DPLS_EDP_PPS_FIX_DIS);
 }
 
 static void ironlake_teardown_rc6(struct drm_device *dev)
@@ -7187,9 +7458,12 @@ void ironlake_enable_rc6(struct drm_device *dev)
        if (!i915_enable_rc6)
                return;
 
+       mutex_lock(&dev->struct_mutex);
        ret = ironlake_setup_rc6(dev);
-       if (ret)
+       if (ret) {
+               mutex_unlock(&dev->struct_mutex);
                return;
+       }
 
        /*
         * GPU can automatically power down the render unit if given a page
@@ -7198,6 +7472,7 @@ void ironlake_enable_rc6(struct drm_device *dev)
        ret = BEGIN_LP_RING(6);
        if (ret) {
                ironlake_teardown_rc6(dev);
+               mutex_unlock(&dev->struct_mutex);
                return;
        }
 
@@ -7213,10 +7488,33 @@ void ironlake_enable_rc6(struct drm_device *dev)
        OUT_RING(MI_FLUSH);
        ADVANCE_LP_RING();
 
+       /*
+        * Wait for the command parser to advance past MI_SET_CONTEXT. The HW
+        * does an implicit flush, combined with MI_FLUSH above, it should be
+        * safe to assume that renderctx is valid
+        */
+       ret = intel_wait_ring_idle(LP_RING(dev_priv));
+       if (ret) {
+               DRM_ERROR("failed to enable ironlake power power savings\n");
+               ironlake_teardown_rc6(dev);
+               mutex_unlock(&dev->struct_mutex);
+               return;
+       }
+
        I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN);
        I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
+       mutex_unlock(&dev->struct_mutex);
 }
 
+void intel_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       dev_priv->display.init_clock_gating(dev);
+
+       if (dev_priv->display.init_pch_clock_gating)
+               dev_priv->display.init_pch_clock_gating(dev);
+}
 
 /* Set up chip specific display functions */
 static void intel_init_display(struct drm_device *dev)
@@ -7224,10 +7522,13 @@ static void intel_init_display(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        /* We always want a DPMS function */
-       if (HAS_PCH_SPLIT(dev))
+       if (HAS_PCH_SPLIT(dev)) {
                dev_priv->display.dpms = ironlake_crtc_dpms;
-       else
+               dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
+       } else {
                dev_priv->display.dpms = i9xx_crtc_dpms;
+               dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
+       }
 
        if (I915_HAS_FBC(dev)) {
                if (HAS_PCH_SPLIT(dev)) {
@@ -7271,6 +7572,11 @@ static void intel_init_display(struct drm_device *dev)
 
        /* For FIFO watermark updates */
        if (HAS_PCH_SPLIT(dev)) {
+               if (HAS_PCH_IBX(dev))
+                       dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating;
+               else if (HAS_PCH_CPT(dev))
+                       dev_priv->display.init_pch_clock_gating = cpt_init_clock_gating;
+
                if (IS_GEN5(dev)) {
                        if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK)
                                dev_priv->display.update_wm = ironlake_update_wm;
@@ -7279,6 +7585,8 @@ static void intel_init_display(struct drm_device *dev)
                                              "Disable CxSR\n");
                                dev_priv->display.update_wm = NULL;
                        }
+                       dev_priv->display.fdi_link_train = ironlake_fdi_link_train;
+                       dev_priv->display.init_clock_gating = ironlake_init_clock_gating;
                } else if (IS_GEN6(dev)) {
                        if (SNB_READ_WM0_LATENCY()) {
                                dev_priv->display.update_wm = sandybridge_update_wm;
@@ -7287,6 +7595,20 @@ static void intel_init_display(struct drm_device *dev)
                                              "Disable CxSR\n");
                                dev_priv->display.update_wm = NULL;
                        }
+                       dev_priv->display.fdi_link_train = gen6_fdi_link_train;
+                       dev_priv->display.init_clock_gating = gen6_init_clock_gating;
+               } else if (IS_IVYBRIDGE(dev)) {
+                       /* FIXME: detect B0+ stepping and use auto training */
+                       dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
+                       if (SNB_READ_WM0_LATENCY()) {
+                               dev_priv->display.update_wm = sandybridge_update_wm;
+                       } else {
+                               DRM_DEBUG_KMS("Failed to read display plane latency. "
+                                             "Disable CxSR\n");
+                               dev_priv->display.update_wm = NULL;
+                       }
+                       dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
+
                } else
                        dev_priv->display.update_wm = NULL;
        } else if (IS_PINEVIEW(dev)) {
@@ -7304,18 +7626,31 @@ static void intel_init_display(struct drm_device *dev)
                        dev_priv->display.update_wm = NULL;
                } else
                        dev_priv->display.update_wm = pineview_update_wm;
-       } else if (IS_G4X(dev))
+               dev_priv->display.init_clock_gating = gen3_init_clock_gating;
+       } else if (IS_G4X(dev)) {
                dev_priv->display.update_wm = g4x_update_wm;
-       else if (IS_GEN4(dev))
+               dev_priv->display.init_clock_gating = g4x_init_clock_gating;
+       } else if (IS_GEN4(dev)) {
                dev_priv->display.update_wm = i965_update_wm;
-       else if (IS_GEN3(dev)) {
+               if (IS_CRESTLINE(dev))
+                       dev_priv->display.init_clock_gating = crestline_init_clock_gating;
+               else if (IS_BROADWATER(dev))
+                       dev_priv->display.init_clock_gating = broadwater_init_clock_gating;
+       } else if (IS_GEN3(dev)) {
                dev_priv->display.update_wm = i9xx_update_wm;
                dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
+               dev_priv->display.init_clock_gating = gen3_init_clock_gating;
+       } else if (IS_I865G(dev)) {
+               dev_priv->display.update_wm = i830_update_wm;
+               dev_priv->display.init_clock_gating = i85x_init_clock_gating;
+               dev_priv->display.get_fifo_size = i830_get_fifo_size;
        } else if (IS_I85X(dev)) {
                dev_priv->display.update_wm = i9xx_update_wm;
                dev_priv->display.get_fifo_size = i85x_get_fifo_size;
+               dev_priv->display.init_clock_gating = i85x_init_clock_gating;
        } else {
                dev_priv->display.update_wm = i830_update_wm;
+               dev_priv->display.init_clock_gating = i830_init_clock_gating;
                if (IS_845G(dev))
                        dev_priv->display.get_fifo_size = i845_get_fifo_size;
                else
@@ -7441,12 +7776,11 @@ void intel_modeset_init(struct drm_device *dev)
                intel_crtc_init(dev, i);
        }
 
-       intel_setup_outputs(dev);
-
-       intel_enable_clock_gating(dev);
-
        /* Just disable it once at startup */
        i915_disable_vga(dev);
+       intel_setup_outputs(dev);
+
+       intel_init_clock_gating(dev);
 
        if (IS_IRONLAKE_M(dev)) {
                ironlake_enable_drps(dev);
@@ -7456,12 +7790,15 @@ void intel_modeset_init(struct drm_device *dev)
        if (IS_GEN6(dev))
                gen6_enable_rps(dev_priv);
 
-       if (IS_IRONLAKE_M(dev))
-               ironlake_enable_rc6(dev);
-
        INIT_WORK(&dev_priv->idle_work, intel_idle_update);
        setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
                    (unsigned long)dev);
+}
+
+void intel_modeset_gem_init(struct drm_device *dev)
+{
+       if (IS_IRONLAKE_M(dev))
+               ironlake_enable_rc6(dev);
 
        intel_setup_overlay(dev);
 }
index a4d80314e7f8cf5edb13bce97328a60f1f26f6ce..391b55f1cc7496e2e313d77332fafb35ecd4aa15 100644 (file)
@@ -59,8 +59,6 @@ struct intel_dp {
        bool is_pch_edp;
        uint8_t train_set[4];
        uint8_t link_status[DP_LINK_STATUS_SIZE];
-
-       struct drm_property *force_audio_property;
 };
 
 /**
@@ -1702,7 +1700,7 @@ intel_dp_set_property(struct drm_connector *connector,
        if (ret)
                return ret;
 
-       if (property == intel_dp->force_audio_property) {
+       if (property == dev_priv->force_audio_property) {
                int i = val;
                bool has_audio;
 
@@ -1841,16 +1839,7 @@ bool intel_dpd_is_edp(struct drm_device *dev)
 static void
 intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector)
 {
-       struct drm_device *dev = connector->dev;
-
-       intel_dp->force_audio_property =
-               drm_property_create(dev, DRM_MODE_PROP_RANGE, "force_audio", 2);
-       if (intel_dp->force_audio_property) {
-               intel_dp->force_audio_property->values[0] = -1;
-               intel_dp->force_audio_property->values[1] = 1;
-               drm_connector_attach_property(connector, intel_dp->force_audio_property, 0);
-       }
-
+       intel_attach_force_audio_property(connector);
        intel_attach_broadcast_rgb_property(connector);
 }
 
index 1d20712d527f1e5d38a192f59f2aa3c6493e5e53..9ffa61eb4d7efab156819980452e22e5507c3c76 100644 (file)
@@ -140,7 +140,6 @@ struct intel_fbdev {
 struct intel_encoder {
        struct drm_encoder base;
        int type;
-       bool load_detect_temp;
        bool needs_tv_clock;
        void (*hot_plug)(struct intel_encoder *);
        int crtc_mask;
@@ -237,6 +236,7 @@ struct intel_unpin_work {
 int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
 extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus);
 
+extern void intel_attach_force_audio_property(struct drm_connector *connector);
 extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector);
 
 extern void intel_crt_init(struct drm_device *dev);
@@ -291,13 +291,19 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
 extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
 extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
-extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
-                                                  struct drm_connector *connector,
-                                                  struct drm_display_mode *mode,
-                                                  int *dpms_mode);
+
+struct intel_load_detect_pipe {
+       struct drm_framebuffer *release_fb;
+       bool load_detect_temp;
+       int dpms_mode;
+};
+extern bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
+                                      struct drm_connector *connector,
+                                      struct drm_display_mode *mode,
+                                      struct intel_load_detect_pipe *old);
 extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
                                           struct drm_connector *connector,
-                                          int dpms_mode);
+                                          struct intel_load_detect_pipe *old);
 
 extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB);
 extern int intel_sdvo_supports_hotplug(struct drm_connector *connector);
@@ -339,4 +345,6 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data,
 
 extern void intel_fb_output_poll_changed(struct drm_device *dev);
 extern void intel_fb_restore_mode(struct drm_device *dev);
+
+extern void intel_init_clock_gating(struct drm_device *dev);
 #endif /* __INTEL_DRV_H__ */
index f289b86429762e7b644e3b454c7f8b1a0d345987..aa0a8e83142e1c8ee5562d0884ad92c8656b30ed 100644 (file)
@@ -45,7 +45,6 @@ struct intel_hdmi {
        bool has_hdmi_sink;
        bool has_audio;
        int force_audio;
-       struct drm_property *force_audio_property;
 };
 
 static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
@@ -194,7 +193,7 @@ static int intel_hdmi_mode_valid(struct drm_connector *connector,
        if (mode->clock > 165000)
                return MODE_CLOCK_HIGH;
        if (mode->clock < 20000)
-               return MODE_CLOCK_HIGH;
+               return MODE_CLOCK_LOW;
 
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return MODE_NO_DBLESCAN;
@@ -287,7 +286,7 @@ intel_hdmi_set_property(struct drm_connector *connector,
        if (ret)
                return ret;
 
-       if (property == intel_hdmi->force_audio_property) {
+       if (property == dev_priv->force_audio_property) {
                int i = val;
                bool has_audio;
 
@@ -365,16 +364,7 @@ static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
 static void
 intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector)
 {
-       struct drm_device *dev = connector->dev;
-
-       intel_hdmi->force_audio_property =
-               drm_property_create(dev, DRM_MODE_PROP_RANGE, "force_audio", 2);
-       if (intel_hdmi->force_audio_property) {
-               intel_hdmi->force_audio_property->values[0] = -1;
-               intel_hdmi->force_audio_property->values[1] = 1;
-               drm_connector_attach_property(connector, intel_hdmi->force_audio_property, 0);
-       }
-
+       intel_attach_force_audio_property(connector);
        intel_attach_broadcast_rgb_property(connector);
 }
 
index d3b903bce7c5b3a25845c570aaf21f064d416224..d98cee60b602650063225ce9fbbf4f01220de562 100644 (file)
@@ -401,8 +401,7 @@ int intel_setup_gmbus(struct drm_device *dev)
                bus->reg0 = i | GMBUS_RATE_100KHZ;
 
                /* XXX force bit banging until GMBUS is fully debugged */
-               if (IS_GEN2(dev))
-                       bus->force_bit = intel_gpio_create(dev_priv, i);
+               bus->force_bit = intel_gpio_create(dev_priv, i);
        }
 
        intel_i2c_reset(dev_priv->dev);
index 67cb076d271b5eb00a4c87a9022f0957f3ff569e..b28f7bd9f88a1fca15fdb0ade73cb724658d1cf8 100644 (file)
@@ -727,6 +727,14 @@ static const struct dmi_system_id intel_no_lvds[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "U800"),
                },
        },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Asus EeeBox PC EB1007",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "EB1007"),
+               },
+       },
 
        { }     /* terminating entry */
 };
index 9034dd8f33c75646eedceeba9d010e26f198ae5c..3b26a3ba02dd349c9715ad16768a1a06a52b7bdb 100644 (file)
@@ -81,6 +81,36 @@ int intel_ddc_get_modes(struct drm_connector *connector,
        return ret;
 }
 
+static const char *force_audio_names[] = {
+       "off",
+       "auto",
+       "on",
+};
+
+void
+intel_attach_force_audio_property(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_property *prop;
+       int i;
+
+       prop = dev_priv->force_audio_property;
+       if (prop == NULL) {
+               prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
+                                          "audio",
+                                          ARRAY_SIZE(force_audio_names));
+               if (prop == NULL)
+                       return;
+
+               for (i = 0; i < ARRAY_SIZE(force_audio_names); i++)
+                       drm_property_add_enum(prop, i, i-1, force_audio_names[i]);
+
+               dev_priv->force_audio_property = prop;
+       }
+       drm_connector_attach_property(connector, prop, 0);
+}
+
 static const char *broadcast_rgb_names[] = {
        "Full",
        "Limited 16:235",
index e9e6f71418a43122c3545d712c2ea3268861c2c4..95c4b1429935d562a6ee54f464f0bd52ba3ae6ba 100644 (file)
@@ -236,7 +236,7 @@ init_pipe_control(struct intel_ring_buffer *ring)
                ret = -ENOMEM;
                goto err;
        }
-       obj->agp_type = AGP_USER_CACHED_MEMORY;
+       obj->cache_level = I915_CACHE_LLC;
 
        ret = i915_gem_object_pin(obj, 4096, true);
        if (ret)
@@ -286,7 +286,7 @@ static int init_render_ring(struct intel_ring_buffer *ring)
 
        if (INTEL_INFO(dev)->gen > 3) {
                int mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH;
-               if (IS_GEN6(dev))
+               if (IS_GEN6(dev) || IS_GEN7(dev))
                        mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE;
                I915_WRITE(MI_MODE, mode);
        }
@@ -551,10 +551,31 @@ render_ring_put_irq(struct intel_ring_buffer *ring)
 
 void intel_ring_setup_status_page(struct intel_ring_buffer *ring)
 {
+       struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = ring->dev->dev_private;
-       u32 mmio = IS_GEN6(ring->dev) ?
-               RING_HWS_PGA_GEN6(ring->mmio_base) :
-               RING_HWS_PGA(ring->mmio_base);
+       u32 mmio = 0;
+
+       /* The ring status page addresses are no longer next to the rest of
+        * the ring registers as of gen7.
+        */
+       if (IS_GEN7(dev)) {
+               switch (ring->id) {
+               case RING_RENDER:
+                       mmio = RENDER_HWS_PGA_GEN7;
+                       break;
+               case RING_BLT:
+                       mmio = BLT_HWS_PGA_GEN7;
+                       break;
+               case RING_BSD:
+                       mmio = BSD_HWS_PGA_GEN7;
+                       break;
+               }
+       } else if (IS_GEN6(ring->dev)) {
+               mmio = RING_HWS_PGA_GEN6(ring->mmio_base);
+       } else {
+               mmio = RING_HWS_PGA(ring->mmio_base);
+       }
+
        I915_WRITE(mmio, (u32)ring->status_page.gfx_addr);
        POSTING_READ(mmio);
 }
@@ -600,7 +621,7 @@ ring_add_request(struct intel_ring_buffer *ring,
 }
 
 static bool
-ring_get_irq(struct intel_ring_buffer *ring, u32 flag)
+gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
 {
        struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -609,71 +630,67 @@ ring_get_irq(struct intel_ring_buffer *ring, u32 flag)
               return false;
 
        spin_lock(&ring->irq_lock);
-       if (ring->irq_refcount++ == 0)
-               ironlake_enable_irq(dev_priv, flag);
+       if (ring->irq_refcount++ == 0) {
+               ring->irq_mask &= ~rflag;
+               I915_WRITE_IMR(ring, ring->irq_mask);
+               ironlake_enable_irq(dev_priv, gflag);
+       }
        spin_unlock(&ring->irq_lock);
 
        return true;
 }
 
 static void
-ring_put_irq(struct intel_ring_buffer *ring, u32 flag)
+gen6_ring_put_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
 {
        struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
 
        spin_lock(&ring->irq_lock);
-       if (--ring->irq_refcount == 0)
-               ironlake_disable_irq(dev_priv, flag);
+       if (--ring->irq_refcount == 0) {
+               ring->irq_mask |= rflag;
+               I915_WRITE_IMR(ring, ring->irq_mask);
+               ironlake_disable_irq(dev_priv, gflag);
+       }
        spin_unlock(&ring->irq_lock);
 }
 
 static bool
-gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
+bsd_ring_get_irq(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
 
        if (!dev->irq_enabled)
-              return false;
+               return false;
 
        spin_lock(&ring->irq_lock);
        if (ring->irq_refcount++ == 0) {
-               ring->irq_mask &= ~rflag;
-               I915_WRITE_IMR(ring, ring->irq_mask);
-               ironlake_enable_irq(dev_priv, gflag);
+               if (IS_G4X(dev))
+                       i915_enable_irq(dev_priv, I915_BSD_USER_INTERRUPT);
+               else
+                       ironlake_enable_irq(dev_priv, GT_BSD_USER_INTERRUPT);
        }
        spin_unlock(&ring->irq_lock);
 
        return true;
 }
-
 static void
-gen6_ring_put_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
+bsd_ring_put_irq(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
 
        spin_lock(&ring->irq_lock);
        if (--ring->irq_refcount == 0) {
-               ring->irq_mask |= rflag;
-               I915_WRITE_IMR(ring, ring->irq_mask);
-               ironlake_disable_irq(dev_priv, gflag);
+               if (IS_G4X(dev))
+                       i915_disable_irq(dev_priv, I915_BSD_USER_INTERRUPT);
+               else
+                       ironlake_disable_irq(dev_priv, GT_BSD_USER_INTERRUPT);
        }
        spin_unlock(&ring->irq_lock);
 }
 
-static bool
-bsd_ring_get_irq(struct intel_ring_buffer *ring)
-{
-       return ring_get_irq(ring, GT_BSD_USER_INTERRUPT);
-}
-static void
-bsd_ring_put_irq(struct intel_ring_buffer *ring)
-{
-       ring_put_irq(ring, GT_BSD_USER_INTERRUPT);
-}
-
 static int
 ring_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length)
 {
@@ -759,7 +776,7 @@ static int init_status_page(struct intel_ring_buffer *ring)
                ret = -ENOMEM;
                goto err;
        }
-       obj->agp_type = AGP_USER_CACHED_MEMORY;
+       obj->cache_level = I915_CACHE_LLC;
 
        ret = i915_gem_object_pin(obj, 4096, true);
        if (ret != 0) {
@@ -800,6 +817,7 @@ int intel_init_ring_buffer(struct drm_device *dev,
        INIT_LIST_HEAD(&ring->request_list);
        INIT_LIST_HEAD(&ring->gpu_write_list);
 
+       init_waitqueue_head(&ring->irq_queue);
        spin_lock_init(&ring->irq_lock);
        ring->irq_mask = ~0;
 
@@ -872,7 +890,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring)
 
        /* Disable the ring buffer. The ring must be idle at this point */
        dev_priv = ring->dev->dev_private;
-       ret = intel_wait_ring_buffer(ring, ring->size - 8);
+       ret = intel_wait_ring_idle(ring);
        if (ret)
                DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n",
                          ring->name, ret);
@@ -1333,7 +1351,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring = &dev_priv->ring[VCS];
 
-       if (IS_GEN6(dev))
+       if (IS_GEN6(dev) || IS_GEN7(dev))
                *ring = gen6_bsd_ring;
        else
                *ring = bsd_ring;
index f23cc5f037a6cbf62bec342ec1f237de165d9c72..c0e0ee63fbf4fb012b06beac97238d68f0fa3f4d 100644 (file)
@@ -14,27 +14,24 @@ struct  intel_hw_status_page {
        struct          drm_i915_gem_object *obj;
 };
 
-#define I915_RING_READ(reg) i915_gt_read(dev_priv, reg)
-#define I915_RING_WRITE(reg, val) i915_gt_write(dev_priv, reg, val)
+#define I915_READ_TAIL(ring) I915_READ(RING_TAIL((ring)->mmio_base))
+#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL((ring)->mmio_base), val)
 
-#define I915_READ_TAIL(ring) I915_RING_READ(RING_TAIL((ring)->mmio_base))
-#define I915_WRITE_TAIL(ring, val) I915_RING_WRITE(RING_TAIL((ring)->mmio_base), val)
+#define I915_READ_START(ring) I915_READ(RING_START((ring)->mmio_base))
+#define I915_WRITE_START(ring, val) I915_WRITE(RING_START((ring)->mmio_base), val)
 
-#define I915_READ_START(ring) I915_RING_READ(RING_START((ring)->mmio_base))
-#define I915_WRITE_START(ring, val) I915_RING_WRITE(RING_START((ring)->mmio_base), val)
+#define I915_READ_HEAD(ring)  I915_READ(RING_HEAD((ring)->mmio_base))
+#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD((ring)->mmio_base), val)
 
-#define I915_READ_HEAD(ring)  I915_RING_READ(RING_HEAD((ring)->mmio_base))
-#define I915_WRITE_HEAD(ring, val) I915_RING_WRITE(RING_HEAD((ring)->mmio_base), val)
+#define I915_READ_CTL(ring) I915_READ(RING_CTL((ring)->mmio_base))
+#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL((ring)->mmio_base), val)
 
-#define I915_READ_CTL(ring) I915_RING_READ(RING_CTL((ring)->mmio_base))
-#define I915_WRITE_CTL(ring, val) I915_RING_WRITE(RING_CTL((ring)->mmio_base), val)
+#define I915_READ_IMR(ring) I915_READ(RING_IMR((ring)->mmio_base))
+#define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR((ring)->mmio_base), val)
 
-#define I915_READ_IMR(ring) I915_RING_READ(RING_IMR((ring)->mmio_base))
-#define I915_WRITE_IMR(ring, val) I915_RING_WRITE(RING_IMR((ring)->mmio_base), val)
-
-#define I915_READ_NOPID(ring) I915_RING_READ(RING_NOPID((ring)->mmio_base))
-#define I915_READ_SYNC_0(ring) I915_RING_READ(RING_SYNC_0((ring)->mmio_base))
-#define I915_READ_SYNC_1(ring) I915_RING_READ(RING_SYNC_1((ring)->mmio_base))
+#define I915_READ_NOPID(ring) I915_READ(RING_NOPID((ring)->mmio_base))
+#define I915_READ_SYNC_0(ring) I915_READ(RING_SYNC_0((ring)->mmio_base))
+#define I915_READ_SYNC_1(ring) I915_READ(RING_SYNC_1((ring)->mmio_base))
 
 struct  intel_ring_buffer {
        const char      *name;
@@ -164,7 +161,13 @@ intel_read_status_page(struct intel_ring_buffer *ring,
 #define I915_BREADCRUMB_INDEX          0x21
 
 void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring);
+
 int __must_check intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n);
+static inline int intel_wait_ring_idle(struct intel_ring_buffer *ring)
+{
+       return intel_wait_ring_buffer(ring, ring->space - 8);
+}
+
 int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n);
 
 static inline void intel_ring_emit(struct intel_ring_buffer *ring,
index 4324f33212d639a357520ced14447264d78233e4..30fe554d8936a8cd965b083a0de9064f44865db6 100644 (file)
@@ -148,8 +148,6 @@ struct intel_sdvo_connector {
        int   format_supported_num;
        struct drm_property *tv_format;
 
-       struct drm_property *force_audio_property;
-
        /* add the property for the SDVO-TV */
        struct drm_property *left;
        struct drm_property *right;
@@ -1712,7 +1710,7 @@ intel_sdvo_set_property(struct drm_connector *connector,
        if (ret)
                return ret;
 
-       if (property == intel_sdvo_connector->force_audio_property) {
+       if (property == dev_priv->force_audio_property) {
                int i = val;
                bool has_audio;
 
@@ -2037,15 +2035,7 @@ intel_sdvo_add_hdmi_properties(struct intel_sdvo_connector *connector)
 {
        struct drm_device *dev = connector->base.base.dev;
 
-       connector->force_audio_property =
-               drm_property_create(dev, DRM_MODE_PROP_RANGE, "force_audio", 2);
-       if (connector->force_audio_property) {
-               connector->force_audio_property->values[0] = -1;
-               connector->force_audio_property->values[1] = 1;
-               drm_connector_attach_property(&connector->base.base,
-                                             connector->force_audio_property, 0);
-       }
-
+       intel_attach_force_audio_property(&connector->base.base);
        if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev))
                intel_attach_broadcast_rgb_property(&connector->base.base);
 }
@@ -2544,21 +2534,19 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
        if (!intel_sdvo)
                return false;
 
+       intel_sdvo->sdvo_reg = sdvo_reg;
+       intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1;
+       intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg);
        if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) {
                kfree(intel_sdvo);
                return false;
        }
 
-       intel_sdvo->sdvo_reg = sdvo_reg;
-
+       /* encoder type will be decided later */
        intel_encoder = &intel_sdvo->base;
        intel_encoder->type = INTEL_OUTPUT_SDVO;
-       /* encoder type will be decided later */
        drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0);
 
-       intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1;
-       intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg);
-
        /* Read the regs to test if we can talk to the device */
        for (i = 0; i < 0x40; i++) {
                u8 byte;
index 6b22c1dcc015f406bf2fcdbc866511bc92f3d882..113e4e7264cdfdb4ba4c3b26af49c15911c2b679 100644 (file)
@@ -1361,15 +1361,14 @@ intel_tv_detect(struct drm_connector *connector, bool force)
        if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
                type = intel_tv_detect_type(intel_tv, connector);
        } else if (force) {
-               struct drm_crtc *crtc;
-               int dpms_mode;
+               struct intel_load_detect_pipe tmp;
 
-               crtc = intel_get_load_detect_pipe(&intel_tv->base, connector,
-                                                 &mode, &dpms_mode);
-               if (crtc) {
+               if (intel_get_load_detect_pipe(&intel_tv->base, connector,
+                                              &mode, &tmp)) {
                        type = intel_tv_detect_type(intel_tv, connector);
-                       intel_release_load_detect_pipe(&intel_tv->base, connector,
-                                                      dpms_mode);
+                       intel_release_load_detect_pipe(&intel_tv->base,
+                                                      connector,
+                                                      &tmp);
                } else
                        return connector_status_unknown;
        } else
index 1084fa4d261b7c9d6638d965a5a4c401c9949720..54558a01969ae02d6875c99fafb605f27a717ce0 100644 (file)
@@ -195,29 +195,10 @@ extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
 
 #define mga_flush_write_combine()      DRM_WRITEMEMORYBARRIER()
 
-#if defined(__linux__) && defined(__alpha__)
-#define MGA_BASE(reg)          ((unsigned long)(dev_priv->mmio->handle))
-#define MGA_ADDR(reg)          (MGA_BASE(reg) + reg)
-
-#define MGA_DEREF(reg)         (*(volatile u32 *)MGA_ADDR(reg))
-#define MGA_DEREF8(reg)                (*(volatile u8 *)MGA_ADDR(reg))
-
-#define MGA_READ(reg)          (_MGA_READ((u32 *)MGA_ADDR(reg)))
-#define MGA_READ8(reg)         (_MGA_READ((u8 *)MGA_ADDR(reg)))
-#define MGA_WRITE(reg, val)    do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF(reg) = val; } while (0)
-#define MGA_WRITE8(reg, val)   do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF8(reg) = val; } while (0)
-
-static inline u32 _MGA_READ(u32 *addr)
-{
-       DRM_MEMORYBARRIER();
-       return *(volatile u32 *)addr;
-}
-#else
 #define MGA_READ8(reg)         DRM_READ8(dev_priv->mmio, (reg))
 #define MGA_READ(reg)          DRM_READ32(dev_priv->mmio, (reg))
 #define MGA_WRITE8(reg, val)   DRM_WRITE8(dev_priv->mmio, (reg), (val))
 #define MGA_WRITE(reg, val)    DRM_WRITE32(dev_priv->mmio, (reg), (val))
-#endif
 
 #define DWGREG0                0x1c00
 #define DWGREG0_END    0x1dff
index de70959b9ed51371a42eefccba299b76ab738274..ca1639918f57976b852bdcaab751d18402a882ad 100644 (file)
@@ -11,6 +11,8 @@ config DRM_NOUVEAU
        select FRAMEBUFFER_CONSOLE if !EXPERT
        select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
        select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT
+       select ACPI_WMI if ACPI
+       select MXM_WMI if ACPI
        help
          Choose this option for open-source nVidia support.
 
index e12c97fd8db89790299836773533827a8d7af3ee..0583677e4581c2faa476f20a8a7a68acee2398b5 100644 (file)
@@ -20,6 +20,8 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
              nv40_graph.o nv50_graph.o nvc0_graph.o \
              nv40_grctx.o nv50_grctx.o nvc0_grctx.o \
              nv84_crypt.o \
+             nva3_copy.o nvc0_copy.o \
+             nv40_mpeg.o nv50_mpeg.o \
              nv04_instmem.o nv50_instmem.o nvc0_instmem.o \
              nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \
              nv50_cursor.o nv50_display.o \
index a54238058dc54a5d75cb2bacb5b9467eccb7a8b4..525744d593c1e981cc1039c79391f6aa38813b1d 100644 (file)
@@ -4,6 +4,8 @@
 #include <acpi/acpi_drivers.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/video.h>
+#include <acpi/acpi.h>
+#include <linux/mxm-wmi.h>
 
 #include "drmP.h"
 #include "drm.h"
 
 static struct nouveau_dsm_priv {
        bool dsm_detected;
+       bool optimus_detected;
        acpi_handle dhandle;
        acpi_handle rom_handle;
 } nouveau_dsm_priv;
 
+#define NOUVEAU_DSM_HAS_MUX 0x1
+#define NOUVEAU_DSM_HAS_OPT 0x2
+
 static const char nouveau_dsm_muid[] = {
        0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
        0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
 };
 
+static const char nouveau_op_dsm_muid[] = {
+       0xF8, 0xD8, 0x86, 0xA4, 0xDA, 0x0B, 0x1B, 0x47,
+       0xA7, 0x2B, 0x60, 0x42, 0xA6, 0xB5, 0xBE, 0xE0,
+};
+
+static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
+{
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_object_list input;
+       union acpi_object params[4];
+       union acpi_object *obj;
+       int err;
+
+       input.count = 4;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_BUFFER;
+       params[0].buffer.length = sizeof(nouveau_op_dsm_muid);
+       params[0].buffer.pointer = (char *)nouveau_op_dsm_muid;
+       params[1].type = ACPI_TYPE_INTEGER;
+       params[1].integer.value = 0x00000100;
+       params[2].type = ACPI_TYPE_INTEGER;
+       params[2].integer.value = func;
+       params[3].type = ACPI_TYPE_BUFFER;
+       params[3].buffer.length = 0;
+
+       err = acpi_evaluate_object(handle, "_DSM", &input, &output);
+       if (err) {
+               printk(KERN_INFO "failed to evaluate _DSM: %d\n", err);
+               return err;
+       }
+
+       obj = (union acpi_object *)output.pointer;
+
+       if (obj->type == ACPI_TYPE_INTEGER)
+               if (obj->integer.value == 0x80000002) {
+                       return -ENODEV;
+               }
+
+       if (obj->type == ACPI_TYPE_BUFFER) {
+               if (obj->buffer.length == 4 && result) {
+                       *result = 0;
+                       *result |= obj->buffer.pointer[0];
+                       *result |= (obj->buffer.pointer[1] << 8);
+                       *result |= (obj->buffer.pointer[2] << 16);
+                       *result |= (obj->buffer.pointer[3] << 24);
+               }
+       }
+
+       kfree(output.pointer);
+       return 0;
+}
+
 static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
 {
        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -92,6 +150,8 @@ static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
 
 static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
 {
+       mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
+       mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
        return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL);
 }
 
@@ -148,11 +208,11 @@ static struct vga_switcheroo_handler nouveau_dsm_handler = {
        .get_client_id = nouveau_dsm_get_client_id,
 };
 
-static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
+static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
 {
        acpi_handle dhandle, nvidia_handle;
        acpi_status status;
-       int ret;
+       int ret, retval = 0;
        uint32_t result;
 
        dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
@@ -166,11 +226,17 @@ static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
 
        ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED,
                          NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result);
-       if (ret < 0)
-               return false;
+       if (ret == 0)
+               retval |= NOUVEAU_DSM_HAS_MUX;
 
-       nouveau_dsm_priv.dhandle = dhandle;
-       return true;
+       ret = nouveau_optimus_dsm(dhandle, 0, 0, &result);
+       if (ret == 0)
+               retval |= NOUVEAU_DSM_HAS_OPT;
+
+       if (retval)
+               nouveau_dsm_priv.dhandle = dhandle;
+
+       return retval;
 }
 
 static bool nouveau_dsm_detect(void)
@@ -179,22 +245,41 @@ static bool nouveau_dsm_detect(void)
        struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
        struct pci_dev *pdev = NULL;
        int has_dsm = 0;
+       int has_optimus;
        int vga_count = 0;
+       bool guid_valid;
+       int retval;
+       bool ret = false;
+
+       /* lookup the MXM GUID */
+       guid_valid = mxm_wmi_supported();
 
+       if (guid_valid)
+               printk("MXM: GUID detected in BIOS\n");
+
+       /* now do DSM detection */
        while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
                vga_count++;
 
-               has_dsm |= (nouveau_dsm_pci_probe(pdev) == true);
+               retval = nouveau_dsm_pci_probe(pdev);
+               if (retval & NOUVEAU_DSM_HAS_MUX)
+                       has_dsm |= 1;
+               if (retval & NOUVEAU_DSM_HAS_OPT)
+                       has_optimus = 1;
        }
 
-       if (vga_count == 2 && has_dsm) {
+       if (vga_count == 2 && has_dsm && guid_valid) {
                acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
                printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
                       acpi_method_name);
                nouveau_dsm_priv.dsm_detected = true;
-               return true;
+               ret = true;
        }
-       return false;
+
+       if (has_optimus == 1)
+               nouveau_dsm_priv.optimus_detected = true;
+
+       return ret;
 }
 
 void nouveau_register_dsm_handler(void)
@@ -247,7 +332,7 @@ bool nouveau_acpi_rom_supported(struct pci_dev *pdev)
        acpi_status status;
        acpi_handle dhandle, rom_handle;
 
-       if (!nouveau_dsm_priv.dsm_detected)
+       if (!nouveau_dsm_priv.dsm_detected && !nouveau_dsm_priv.optimus_detected)
                return false;
 
        dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
index 90aef64b76f277a649cd8e7caf79bfa40851cf3f..729d5fd7c88d246fda09dad22c599efad448623b 100644 (file)
@@ -5049,11 +5049,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
                pll_lim->vco1.max_n = record[11];
                pll_lim->min_p = record[12];
                pll_lim->max_p = record[13];
-               /* where did this go to?? */
-               if ((entry[0] & 0xf0) == 0x80)
-                       pll_lim->refclk = 27000;
-               else
-                       pll_lim->refclk = 100000;
+               pll_lim->refclk = ROM16(entry[9]) * 1000;
        }
 
        /*
@@ -6035,6 +6031,7 @@ parse_dcb_connector_table(struct nvbios *bios)
                case DCB_CONNECTOR_DVI_I:
                case DCB_CONNECTOR_DVI_D:
                case DCB_CONNECTOR_LVDS:
+               case DCB_CONNECTOR_LVDS_SPWG:
                case DCB_CONNECTOR_DP:
                case DCB_CONNECTOR_eDP:
                case DCB_CONNECTOR_HDMI_0:
index 8a54fa7edf5c18d692ecb2bfc94dfa1696800c43..050c314119dff4c0eb37fb36df860031ba61397c 100644 (file)
@@ -82,6 +82,7 @@ enum dcb_connector_type {
        DCB_CONNECTOR_DVI_I = 0x30,
        DCB_CONNECTOR_DVI_D = 0x31,
        DCB_CONNECTOR_LVDS = 0x40,
+       DCB_CONNECTOR_LVDS_SPWG = 0x41,
        DCB_CONNECTOR_DP = 0x46,
        DCB_CONNECTOR_eDP = 0x47,
        DCB_CONNECTOR_HDMI_0 = 0x60,
index 4cea35c57d15a4582ac0dfbd76add6b9934e9317..a7583a8ddb01f13dba3f12a43d1c263630cb261a 100644 (file)
@@ -268,9 +268,8 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
        unsigned long flags;
+       int i;
 
        /* decrement the refcount, and we're done if there's still refs */
        if (likely(!atomic_dec_and_test(&chan->users))) {
@@ -294,19 +293,12 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
        /* boot it off the hardware */
        pfifo->reassign(dev, false);
 
-       /* We want to give pgraph a chance to idle and get rid of all
-        * potential errors. We need to do this without the context
-        * switch lock held, otherwise the irq handler is unable to
-        * process them.
-        */
-       if (pgraph->channel(dev) == chan)
-               nouveau_wait_for_idle(dev);
-
        /* destroy the engine specific contexts */
        pfifo->destroy_context(chan);
-       pgraph->destroy_context(chan);
-       if (pcrypt->destroy_context)
-               pcrypt->destroy_context(chan);
+       for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+               if (chan->engctx[i])
+                       dev_priv->eng[i]->context_del(chan, i);
+       }
 
        pfifo->reassign(dev, true);
 
@@ -414,7 +406,7 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
        struct nouveau_channel *chan;
        int ret;
 
-       if (dev_priv->engine.graph.accel_blocked)
+       if (!dev_priv->eng[NVOBJ_ENGINE_GR])
                return -ENODEV;
 
        if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
index 7ae151109a66f76eb467557f66f055c5ea7cb5c7..1595d0b6e8154544b0149b7053366fbf29baa880 100644 (file)
@@ -442,7 +442,7 @@ nouveau_connector_set_property(struct drm_connector *connector,
                }
 
                /* LVDS always needs gpu scaling */
-               if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS &&
+               if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS &&
                    value == DRM_MODE_SCALE_NONE)
                        return -EINVAL;
 
@@ -650,6 +650,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
                ret = get_slave_funcs(encoder)->get_modes(encoder, connector);
 
        if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS ||
+           nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG ||
            nv_connector->dcb->type == DCB_CONNECTOR_eDP)
                ret += nouveau_connector_scaler_modes_add(connector);
 
@@ -810,6 +811,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
                type = DRM_MODE_CONNECTOR_HDMIA;
                break;
        case DCB_CONNECTOR_LVDS:
+       case DCB_CONNECTOR_LVDS_SPWG:
                type = DRM_MODE_CONNECTOR_LVDS;
                funcs = &nouveau_connector_funcs_lvds;
                break;
@@ -838,7 +840,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
        drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
 
        /* Check if we need dithering enabled */
-       if (dcb->type == DCB_CONNECTOR_LVDS) {
+       if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
                bool dummy, is_24bit = false;
 
                ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &is_24bit);
@@ -883,7 +885,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
                                nv_connector->use_dithering ?
                                DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF);
 
-               if (dcb->type != DCB_CONNECTOR_LVDS) {
+               if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS) {
                        if (dev_priv->card_type >= NV_50)
                                connector->polled = DRM_CONNECTOR_POLL_HPD;
                        else
index 764c15d537bac897d64eebfc791ba3db401fae67..eb514ea29377aee0f79a5073725b990e39800c7c 100644 (file)
@@ -276,7 +276,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        struct nouveau_fence *fence;
        int ret;
 
-       if (dev_priv->engine.graph.accel_blocked)
+       if (!dev_priv->channel)
                return -ENODEV;
 
        s = kzalloc(sizeof(*s), GFP_KERNEL);
index 155ebdcbf06fe2ab1d41f047733a307dd9656389..02c6f37d8bd78b4685ddd07a87c24a3a2ebd4e3c 100644 (file)
@@ -162,11 +162,10 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
        struct drm_device *dev = pci_get_drvdata(pdev);
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        struct nouveau_channel *chan;
        struct drm_crtc *crtc;
-       int ret, i;
+       int ret, i, e;
 
        if (pm_state.event == PM_EVENT_PRETHAW)
                return 0;
@@ -206,12 +205,17 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
                        nouveau_channel_idle(chan);
        }
 
-       pgraph->fifo_access(dev, false);
-       nouveau_wait_for_idle(dev);
        pfifo->reassign(dev, false);
        pfifo->disable(dev);
        pfifo->unload_context(dev);
-       pgraph->unload_context(dev);
+
+       for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
+               if (dev_priv->eng[e]) {
+                       ret = dev_priv->eng[e]->fini(dev, e);
+                       if (ret)
+                               goto out_abort;
+               }
+       }
 
        ret = pinstmem->suspend(dev);
        if (ret) {
@@ -242,9 +246,12 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
 
 out_abort:
        NV_INFO(dev, "Re-enabling acceleration..\n");
+       for (e = e + 1; e < NVOBJ_ENGINE_NR; e++) {
+               if (dev_priv->eng[e])
+                       dev_priv->eng[e]->init(dev, e);
+       }
        pfifo->enable(dev);
        pfifo->reassign(dev, true);
-       pgraph->fifo_access(dev, true);
        return ret;
 }
 
@@ -299,8 +306,10 @@ nouveau_pci_resume(struct pci_dev *pdev)
        engine->mc.init(dev);
        engine->timer.init(dev);
        engine->fb.init(dev);
-       engine->graph.init(dev);
-       engine->crypt.init(dev);
+       for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+               if (dev_priv->eng[i])
+                       dev_priv->eng[i]->init(dev, i);
+       }
        engine->fifo.init(dev);
 
        nouveau_irq_postinstall(dev);
index a76514a209b369880ac8b5ced881bb337a186695..9c56331941e2430cd2dda20ca9c3ab06a6b1c0cf 100644 (file)
@@ -150,13 +150,12 @@ enum nouveau_flags {
 
 #define NVOBJ_ENGINE_SW                0
 #define NVOBJ_ENGINE_GR                1
-#define NVOBJ_ENGINE_PPP       2
-#define NVOBJ_ENGINE_COPY      3
-#define NVOBJ_ENGINE_VP                4
-#define NVOBJ_ENGINE_CRYPT      5
-#define NVOBJ_ENGINE_BSP       6
-#define NVOBJ_ENGINE_DISPLAY   0xcafe0001
-#define NVOBJ_ENGINE_INT       0xdeadbeef
+#define NVOBJ_ENGINE_CRYPT     2
+#define NVOBJ_ENGINE_COPY0     3
+#define NVOBJ_ENGINE_COPY1     4
+#define NVOBJ_ENGINE_MPEG      5
+#define NVOBJ_ENGINE_DISPLAY   15
+#define NVOBJ_ENGINE_NR                16
 
 #define NVOBJ_FLAG_DONT_MAP             (1 << 0)
 #define NVOBJ_FLAG_ZERO_ALLOC          (1 << 1)
@@ -245,11 +244,8 @@ struct nouveau_channel {
        struct nouveau_gpuobj *cache;
        void *fifo_priv;
 
-       /* PGRAPH context */
-       /* XXX may be merge 2 pointers as private data ??? */
-       struct nouveau_gpuobj *ramin_grctx;
-       struct nouveau_gpuobj *crypt_ctx;
-       void *pgraph_ctx;
+       /* Execution engine contexts */
+       void *engctx[NVOBJ_ENGINE_NR];
 
        /* NV50 VM */
        struct nouveau_vm     *vm;
@@ -298,6 +294,18 @@ struct nouveau_channel {
        } debugfs;
 };
 
+struct nouveau_exec_engine {
+       void (*destroy)(struct drm_device *, int engine);
+       int  (*init)(struct drm_device *, int engine);
+       int  (*fini)(struct drm_device *, int engine);
+       int  (*context_new)(struct nouveau_channel *, int engine);
+       void (*context_del)(struct nouveau_channel *, int engine);
+       int  (*object_new)(struct nouveau_channel *, int engine,
+                          u32 handle, u16 class);
+       void (*set_tile_region)(struct drm_device *dev, int i);
+       void (*tlb_flush)(struct drm_device *, int engine);
+};
+
 struct nouveau_instmem_engine {
        void    *priv;
 
@@ -364,30 +372,6 @@ struct nouveau_fifo_engine {
        void (*tlb_flush)(struct drm_device *dev);
 };
 
-struct nouveau_pgraph_engine {
-       bool accel_blocked;
-       bool registered;
-       int grctx_size;
-       void *priv;
-
-       /* NV2x/NV3x context table (0x400780) */
-       struct nouveau_gpuobj *ctx_table;
-
-       int  (*init)(struct drm_device *);
-       void (*takedown)(struct drm_device *);
-
-       void (*fifo_access)(struct drm_device *, bool);
-
-       struct nouveau_channel *(*channel)(struct drm_device *);
-       int  (*create_context)(struct nouveau_channel *);
-       void (*destroy_context)(struct nouveau_channel *);
-       int  (*load_context)(struct nouveau_channel *);
-       int  (*unload_context)(struct drm_device *);
-       void (*tlb_flush)(struct drm_device *dev);
-
-       void (*set_tile_region)(struct drm_device *dev, int i);
-};
-
 struct nouveau_display_engine {
        void *priv;
        int (*early_init)(struct drm_device *);
@@ -426,6 +410,19 @@ struct nouveau_pm_voltage {
        int nr_level;
 };
 
+struct nouveau_pm_memtiming {
+       int id;
+       u32 reg_100220;
+       u32 reg_100224;
+       u32 reg_100228;
+       u32 reg_10022c;
+       u32 reg_100230;
+       u32 reg_100234;
+       u32 reg_100238;
+       u32 reg_10023c;
+       u32 reg_100240;
+};
+
 #define NOUVEAU_PM_MAX_LEVEL 8
 struct nouveau_pm_level {
        struct device_attribute dev_attr;
@@ -436,11 +433,13 @@ struct nouveau_pm_level {
        u32 memory;
        u32 shader;
        u32 unk05;
+       u32 unk0a;
 
        u8 voltage;
        u8 fanspeed;
 
        u16 memscript;
+       struct nouveau_pm_memtiming *timing;
 };
 
 struct nouveau_pm_temp_sensor_constants {
@@ -457,17 +456,6 @@ struct nouveau_pm_threshold_temp {
        s16 fan_boost;
 };
 
-struct nouveau_pm_memtiming {
-       u32 reg_100220;
-       u32 reg_100224;
-       u32 reg_100228;
-       u32 reg_10022c;
-       u32 reg_100230;
-       u32 reg_100234;
-       u32 reg_100238;
-       u32 reg_10023c;
-};
-
 struct nouveau_pm_memtimings {
        bool supported;
        struct nouveau_pm_memtiming *timing;
@@ -499,16 +487,6 @@ struct nouveau_pm_engine {
        int (*temp_get)(struct drm_device *);
 };
 
-struct nouveau_crypt_engine {
-       bool registered;
-
-       int  (*init)(struct drm_device *);
-       void (*takedown)(struct drm_device *);
-       int  (*create_context)(struct nouveau_channel *);
-       void (*destroy_context)(struct nouveau_channel *);
-       void (*tlb_flush)(struct drm_device *dev);
-};
-
 struct nouveau_vram_engine {
        int  (*init)(struct drm_device *);
        int  (*get)(struct drm_device *, u64, u32 align, u32 size_nc,
@@ -523,12 +501,10 @@ struct nouveau_engine {
        struct nouveau_mc_engine      mc;
        struct nouveau_timer_engine   timer;
        struct nouveau_fb_engine      fb;
-       struct nouveau_pgraph_engine  graph;
        struct nouveau_fifo_engine    fifo;
        struct nouveau_display_engine display;
        struct nouveau_gpio_engine    gpio;
        struct nouveau_pm_engine      pm;
-       struct nouveau_crypt_engine   crypt;
        struct nouveau_vram_engine    vram;
 };
 
@@ -637,6 +613,7 @@ struct drm_nouveau_private {
        enum nouveau_card_type card_type;
        /* exact chipset, derived from NV_PMC_BOOT_0 */
        int chipset;
+       int stepping;
        int flags;
 
        void __iomem *mmio;
@@ -647,6 +624,7 @@ struct drm_nouveau_private {
        u32 ramin_base;
        bool ramin_available;
        struct drm_mm ramin_heap;
+       struct nouveau_exec_engine *eng[NVOBJ_ENGINE_NR];
        struct list_head gpuobj_list;
        struct list_head classes;
 
@@ -745,10 +723,6 @@ struct drm_nouveau_private {
        uint32_t crtc_owner;
        uint32_t dac_users[4];
 
-       struct nouveau_suspend_resume {
-               uint32_t *ramin_copy;
-       } susres;
-
        struct backlight_device *backlight;
 
        struct {
@@ -757,8 +731,6 @@ struct drm_nouveau_private {
 
        struct nouveau_fbdev *nfbdev;
        struct apertures_struct *apertures;
-
-       bool powered_down;
 };
 
 static inline struct drm_nouveau_private *
@@ -883,17 +855,27 @@ extern void nouveau_channel_ref(struct nouveau_channel *chan,
 extern void nouveau_channel_idle(struct nouveau_channel *chan);
 
 /* nouveau_object.c */
-#define NVOBJ_CLASS(d,c,e) do {                                                \
+#define NVOBJ_ENGINE_ADD(d, e, p) do {                                         \
+       struct drm_nouveau_private *dev_priv = (d)->dev_private;               \
+       dev_priv->eng[NVOBJ_ENGINE_##e] = (p);                                 \
+} while (0)
+
+#define NVOBJ_ENGINE_DEL(d, e) do {                                            \
+       struct drm_nouveau_private *dev_priv = (d)->dev_private;               \
+       dev_priv->eng[NVOBJ_ENGINE_##e] = NULL;                                \
+} while (0)
+
+#define NVOBJ_CLASS(d, c, e) do {                                              \
        int ret = nouveau_gpuobj_class_new((d), (c), NVOBJ_ENGINE_##e);        \
        if (ret)                                                               \
                return ret;                                                    \
-} while(0)
+} while (0)
 
-#define NVOBJ_MTHD(d,c,m,e) do {                                               \
+#define NVOBJ_MTHD(d, c, m, e) do {                                            \
        int ret = nouveau_gpuobj_mthd_new((d), (c), (m), (e));                 \
        if (ret)                                                               \
                return ret;                                                    \
-} while(0)
+} while (0)
 
 extern int  nouveau_gpuobj_early_init(struct drm_device *);
 extern int  nouveau_gpuobj_init(struct drm_device *);
@@ -903,7 +885,7 @@ extern void nouveau_gpuobj_resume(struct drm_device *dev);
 extern int  nouveau_gpuobj_class_new(struct drm_device *, u32 class, u32 eng);
 extern int  nouveau_gpuobj_mthd_new(struct drm_device *, u32 class, u32 mthd,
                                    int (*exec)(struct nouveau_channel *,
-                                               u32 class, u32 mthd, u32 data));
+                                               u32 class, u32 mthd, u32 data));
 extern int  nouveau_gpuobj_mthd_call(struct nouveau_channel *, u32, u32, u32);
 extern int  nouveau_gpuobj_mthd_call2(struct drm_device *, int, u32, u32, u32);
 extern int nouveau_gpuobj_channel_init(struct nouveau_channel *,
@@ -1137,81 +1119,50 @@ extern int  nvc0_fifo_load_context(struct nouveau_channel *);
 extern int  nvc0_fifo_unload_context(struct drm_device *);
 
 /* nv04_graph.c */
-extern int  nv04_graph_init(struct drm_device *);
-extern void nv04_graph_takedown(struct drm_device *);
+extern int  nv04_graph_create(struct drm_device *);
 extern void nv04_graph_fifo_access(struct drm_device *, bool);
-extern struct nouveau_channel *nv04_graph_channel(struct drm_device *);
-extern int  nv04_graph_create_context(struct nouveau_channel *);
-extern void nv04_graph_destroy_context(struct nouveau_channel *);
-extern int  nv04_graph_load_context(struct nouveau_channel *);
-extern int  nv04_graph_unload_context(struct drm_device *);
+extern int  nv04_graph_object_new(struct nouveau_channel *, int, u32, u16);
 extern int  nv04_graph_mthd_page_flip(struct nouveau_channel *chan,
                                      u32 class, u32 mthd, u32 data);
 extern struct nouveau_bitfield nv04_graph_nsource[];
 
 /* nv10_graph.c */
-extern int  nv10_graph_init(struct drm_device *);
-extern void nv10_graph_takedown(struct drm_device *);
+extern int  nv10_graph_create(struct drm_device *);
 extern struct nouveau_channel *nv10_graph_channel(struct drm_device *);
-extern int  nv10_graph_create_context(struct nouveau_channel *);
-extern void nv10_graph_destroy_context(struct nouveau_channel *);
-extern int  nv10_graph_load_context(struct nouveau_channel *);
-extern int  nv10_graph_unload_context(struct drm_device *);
-extern void nv10_graph_set_tile_region(struct drm_device *dev, int i);
 extern struct nouveau_bitfield nv10_graph_intr[];
 extern struct nouveau_bitfield nv10_graph_nstatus[];
 
 /* nv20_graph.c */
-extern int  nv20_graph_create_context(struct nouveau_channel *);
-extern void nv20_graph_destroy_context(struct nouveau_channel *);
-extern int  nv20_graph_load_context(struct nouveau_channel *);
-extern int  nv20_graph_unload_context(struct drm_device *);
-extern int  nv20_graph_init(struct drm_device *);
-extern void nv20_graph_takedown(struct drm_device *);
-extern int  nv30_graph_init(struct drm_device *);
-extern void nv20_graph_set_tile_region(struct drm_device *dev, int i);
+extern int  nv20_graph_create(struct drm_device *);
 
 /* nv40_graph.c */
-extern int  nv40_graph_init(struct drm_device *);
-extern void nv40_graph_takedown(struct drm_device *);
-extern struct nouveau_channel *nv40_graph_channel(struct drm_device *);
-extern int  nv40_graph_create_context(struct nouveau_channel *);
-extern void nv40_graph_destroy_context(struct nouveau_channel *);
-extern int  nv40_graph_load_context(struct nouveau_channel *);
-extern int  nv40_graph_unload_context(struct drm_device *);
+extern int  nv40_graph_create(struct drm_device *);
 extern void nv40_grctx_init(struct nouveau_grctx *);
-extern void nv40_graph_set_tile_region(struct drm_device *dev, int i);
 
 /* nv50_graph.c */
-extern int  nv50_graph_init(struct drm_device *);
-extern void nv50_graph_takedown(struct drm_device *);
-extern void nv50_graph_fifo_access(struct drm_device *, bool);
-extern struct nouveau_channel *nv50_graph_channel(struct drm_device *);
-extern int  nv50_graph_create_context(struct nouveau_channel *);
-extern void nv50_graph_destroy_context(struct nouveau_channel *);
-extern int  nv50_graph_load_context(struct nouveau_channel *);
-extern int  nv50_graph_unload_context(struct drm_device *);
+extern int  nv50_graph_create(struct drm_device *);
 extern int  nv50_grctx_init(struct nouveau_grctx *);
-extern void nv50_graph_tlb_flush(struct drm_device *dev);
-extern void nv84_graph_tlb_flush(struct drm_device *dev);
 extern struct nouveau_enum nv50_data_error_names[];
+extern int  nv50_graph_isr_chid(struct drm_device *dev, u64 inst);
 
 /* nvc0_graph.c */
-extern int  nvc0_graph_init(struct drm_device *);
-extern void nvc0_graph_takedown(struct drm_device *);
-extern void nvc0_graph_fifo_access(struct drm_device *, bool);
-extern struct nouveau_channel *nvc0_graph_channel(struct drm_device *);
-extern int  nvc0_graph_create_context(struct nouveau_channel *);
-extern void nvc0_graph_destroy_context(struct nouveau_channel *);
-extern int  nvc0_graph_load_context(struct nouveau_channel *);
-extern int  nvc0_graph_unload_context(struct drm_device *);
+extern int  nvc0_graph_create(struct drm_device *);
+extern int  nvc0_graph_isr_chid(struct drm_device *dev, u64 inst);
 
 /* nv84_crypt.c */
-extern int  nv84_crypt_init(struct drm_device *dev);
-extern void nv84_crypt_fini(struct drm_device *dev);
-extern int  nv84_crypt_create_context(struct nouveau_channel *);
-extern void nv84_crypt_destroy_context(struct nouveau_channel *);
-extern void nv84_crypt_tlb_flush(struct drm_device *dev);
+extern int  nv84_crypt_create(struct drm_device *);
+
+/* nva3_copy.c */
+extern int  nva3_copy_create(struct drm_device *dev);
+
+/* nvc0_copy.c */
+extern int  nvc0_copy_create(struct drm_device *dev, int engine);
+
+/* nv40_mpeg.c */
+extern int  nv40_mpeg_create(struct drm_device *dev);
+
+/* nv50_mpeg.c */
+extern int  nv50_mpeg_create(struct drm_device *dev);
 
 /* nv04_instmem.c */
 extern int  nv04_instmem_init(struct drm_device *);
@@ -1402,8 +1353,8 @@ bool nv50_gpio_irq_enable(struct drm_device *, enum dcb_gpio_tag, bool on);
 /* nv50_calc. */
 int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk,
                  int *N1, int *M1, int *N2, int *M2, int *P);
-int nv50_calc_pll2(struct drm_device *, struct pll_lims *,
-                  int clk, int *N, int *fN, int *M, int *P);
+int nva3_calc_pll(struct drm_device *, struct pll_lims *,
+                 int clk, int *N, int *fN, int *M, int *P);
 
 #ifndef ioread32_native
 #ifdef __BIG_ENDIAN
@@ -1579,6 +1530,13 @@ nv_match_device(struct drm_device *dev, unsigned device,
                dev->pdev->subsystem_device == sub_device;
 }
 
+static inline void *
+nv_engine(struct drm_device *dev, int engine)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       return (void *)dev_priv->eng[engine];
+}
+
 /* returns 1 if device is one of the nv4x using the 0x4497 object class,
  * helpful to determine a number of other hardware features
  */
index 4b9f4493c9f9d3008d46b64597d7c27d51a21197..7347075ca5b873a2192f57ad0647ee8fb15d8908 100644 (file)
@@ -339,11 +339,12 @@ semaphore_acquire(struct nouveau_channel *chan, struct nouveau_semaphore *sema)
        int ret;
 
        if (dev_priv->chipset < 0x84) {
-               ret = RING_SPACE(chan, 3);
+               ret = RING_SPACE(chan, 4);
                if (ret)
                        return ret;
 
-               BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_OFFSET, 2);
+               BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 3);
+               OUT_RING  (chan, NvSema);
                OUT_RING  (chan, sema->mem->start);
                OUT_RING  (chan, 1);
        } else
@@ -351,10 +352,12 @@ semaphore_acquire(struct nouveau_channel *chan, struct nouveau_semaphore *sema)
                struct nouveau_vma *vma = &dev_priv->fence.bo->vma;
                u64 offset = vma->offset + sema->mem->start;
 
-               ret = RING_SPACE(chan, 5);
+               ret = RING_SPACE(chan, 7);
                if (ret)
                        return ret;
 
+               BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1);
+               OUT_RING  (chan, chan->vram_handle);
                BEGIN_RING(chan, NvSubSw, 0x0010, 4);
                OUT_RING  (chan, upper_32_bits(offset));
                OUT_RING  (chan, lower_32_bits(offset));
@@ -394,11 +397,12 @@ semaphore_release(struct nouveau_channel *chan, struct nouveau_semaphore *sema)
        int ret;
 
        if (dev_priv->chipset < 0x84) {
-               ret = RING_SPACE(chan, 4);
+               ret = RING_SPACE(chan, 5);
                if (ret)
                        return ret;
 
-               BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_OFFSET, 1);
+               BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 2);
+               OUT_RING  (chan, NvSema);
                OUT_RING  (chan, sema->mem->start);
                BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_RELEASE, 1);
                OUT_RING  (chan, 1);
@@ -407,10 +411,12 @@ semaphore_release(struct nouveau_channel *chan, struct nouveau_semaphore *sema)
                struct nouveau_vma *vma = &dev_priv->fence.bo->vma;
                u64 offset = vma->offset + sema->mem->start;
 
-               ret = RING_SPACE(chan, 5);
+               ret = RING_SPACE(chan, 7);
                if (ret)
                        return ret;
 
+               BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1);
+               OUT_RING  (chan, chan->vram_handle);
                BEGIN_RING(chan, NvSubSw, 0x0010, 4);
                OUT_RING  (chan, upper_32_bits(offset));
                OUT_RING  (chan, lower_32_bits(offset));
@@ -504,22 +510,22 @@ nouveau_fence_channel_init(struct nouveau_channel *chan)
        struct nouveau_gpuobj *obj = NULL;
        int ret;
 
-       if (dev_priv->card_type >= NV_C0)
-               goto out_initialised;
+       if (dev_priv->card_type < NV_C0) {
+               /* Create an NV_SW object for various sync purposes */
+               ret = nouveau_gpuobj_gr_new(chan, NvSw, NV_SW);
+               if (ret)
+                       return ret;
 
-       /* Create an NV_SW object for various sync purposes */
-       ret = nouveau_gpuobj_gr_new(chan, NvSw, NV_SW);
-       if (ret)
-               return ret;
+               ret = RING_SPACE(chan, 2);
+               if (ret)
+                       return ret;
 
-       /* we leave subchannel empty for nvc0 */
-       ret = RING_SPACE(chan, 2);
-       if (ret)
-               return ret;
-       BEGIN_RING(chan, NvSubSw, 0, 1);
-       OUT_RING(chan, NvSw);
+               BEGIN_RING(chan, NvSubSw, 0, 1);
+               OUT_RING  (chan, NvSw);
+               FIRE_RING (chan);
+       }
 
-       /* Create a DMA object for the shared cross-channel sync area. */
+       /* Setup area of memory shared between all channels for x-chan sync */
        if (USE_SEMA(dev) && dev_priv->chipset < 0x84) {
                struct ttm_mem_reg *mem = &dev_priv->fence.bo->bo.mem;
 
@@ -534,23 +540,8 @@ nouveau_fence_channel_init(struct nouveau_channel *chan)
                nouveau_gpuobj_ref(NULL, &obj);
                if (ret)
                        return ret;
-
-               ret = RING_SPACE(chan, 2);
-               if (ret)
-                       return ret;
-               BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1);
-               OUT_RING(chan, NvSema);
-       } else {
-               ret = RING_SPACE(chan, 2);
-               if (ret)
-                       return ret;
-               BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1);
-               OUT_RING  (chan, chan->vram_handle); /* whole VM */
        }
 
-       FIRE_RING(chan);
-
-out_initialised:
        INIT_LIST_HEAD(&chan->fence.pending);
        spin_lock_init(&chan->fence.lock);
        atomic_set(&chan->fence.last_sequence_irq, 0);
index 4a8ad1307fa49403f53e5768488afd7e4b49f8c9..86c2e374e938e644070f533214bbd6038e72eaf3 100644 (file)
@@ -87,10 +87,10 @@ _cp_bra(struct nouveau_grctx *ctx, u32 mod, int flag, int state, int name)
        cp_out(ctx, CP_BRA | (mod << 18) | ip | flag |
                    (state ? 0 : CP_BRA_IF_CLEAR));
 }
-#define cp_bra(c,f,s,n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#define cp_bra(c, f, s, n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
 #ifdef CP_BRA_MOD
-#define cp_cal(c,f,s,n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
-#define cp_ret(c,f,s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0)
+#define cp_cal(c, f, s, n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#define cp_ret(c, f, s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0)
 #endif
 
 static inline void
@@ -98,14 +98,14 @@ _cp_wait(struct nouveau_grctx *ctx, int flag, int state)
 {
        cp_out(ctx, CP_WAIT | flag | (state ? CP_WAIT_SET : 0));
 }
-#define cp_wait(c,f,s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+#define cp_wait(c, f, s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
 
 static inline void
 _cp_set(struct nouveau_grctx *ctx, int flag, int state)
 {
        cp_out(ctx, CP_SET | flag | (state ? CP_SET_1 : 0));
 }
-#define cp_set(c,f,s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+#define cp_set(c, f, s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
 
 static inline void
 cp_pos(struct nouveau_grctx *ctx, int offset)
index 053edf9d2f67db4c6ed86536ea08f89d8c5b8b51..ba896e54b799bfd43b92291358234197c4cd56b3 100644 (file)
@@ -900,6 +900,7 @@ nv_save_state_ext(struct drm_device *dev, int head,
        }
        /* NV11 and NV20 don't have this, they stop at 0x52. */
        if (nv_gf4_disp_arch(dev)) {
+               rd_cio_state(dev, head, regp, NV_CIO_CRE_42);
                rd_cio_state(dev, head, regp, NV_CIO_CRE_53);
                rd_cio_state(dev, head, regp, NV_CIO_CRE_54);
 
@@ -1003,6 +1004,7 @@ nv_load_state_ext(struct drm_device *dev, int head,
                        nouveau_wait_eq(dev, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x0);
                }
 
+               wr_cio_state(dev, head, regp, NV_CIO_CRE_42);
                wr_cio_state(dev, head, regp, NV_CIO_CRE_53);
                wr_cio_state(dev, head, regp, NV_CIO_CRE_54);
 
index c3e953b089923d552de922e8007c13e1e8eb94e5..5ee14d216ce88474eb3d903b5b3519a69019d218 100644 (file)
@@ -51,8 +51,7 @@ nv10_mem_update_tile_region(struct drm_device *dev,
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       int i = tile - dev_priv->tile.reg;
+       int i = tile - dev_priv->tile.reg, j;
        unsigned long save;
 
        nouveau_fence_unref(&tile->fence);
@@ -70,7 +69,10 @@ nv10_mem_update_tile_region(struct drm_device *dev,
        nouveau_wait_for_idle(dev);
 
        pfb->set_tile_region(dev, i);
-       pgraph->set_tile_region(dev, i);
+       for (j = 0; j < NVOBJ_ENGINE_NR; j++) {
+               if (dev_priv->eng[j] && dev_priv->eng[j]->set_tile_region)
+                       dev_priv->eng[j]->set_tile_region(dev, i);
+       }
 
        pfifo->cache_pull(dev, true);
        pfifo->reassign(dev, true);
@@ -395,7 +397,7 @@ nouveau_mem_vram_init(struct drm_device *dev)
                if (pci_dma_supported(dev->pdev, DMA_BIT_MASK(40)))
                        dma_bits = 40;
        } else
-       if (drm_pci_device_is_pcie(dev) &&
+       if (0 && drm_pci_device_is_pcie(dev) &&
            dev_priv->chipset  > 0x40 &&
            dev_priv->chipset != 0x45) {
                if (pci_dma_supported(dev->pdev, DMA_BIT_MASK(39)))
@@ -595,10 +597,10 @@ nouveau_mem_timing_init(struct drm_device *dev)
        if (!memtimings->timing)
                return;
 
-       /* Get "some number" from the timing reg for NV_40
+       /* Get "some number" from the timing reg for NV_40 and NV_50
         * Used in calculations later */
-       if(dev_priv->card_type == NV_40) {
-               magic_number = (nv_rd32(dev,0x100228) & 0x0f000000) >> 24;
+       if (dev_priv->card_type >= NV_40 && dev_priv->chipset < 0x98) {
+               magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24;
        }
 
        entry = mem + mem[1];
@@ -641,51 +643,68 @@ nouveau_mem_timing_init(struct drm_device *dev)
                /* XXX: I don't trust the -1's and +1's... they must come
                 *      from somewhere! */
                timing->reg_100224 = (tUNK_0 + tUNK_19 + 1 + magic_number) << 24 |
-                                     tUNK_18 << 16 |
+                                     max(tUNK_18, (u8) 1) << 16 |
                                      (tUNK_1 + tUNK_19 + 1 + magic_number) << 8;
-               if(dev_priv->chipset == 0xa8) {
+               if (dev_priv->chipset == 0xa8) {
                        timing->reg_100224 |= (tUNK_2 - 1);
                } else {
                        timing->reg_100224 |= (tUNK_2 + 2 - magic_number);
                }
 
                timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
-               if(dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) {
+               if (dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa)
                        timing->reg_100228 |= (tUNK_19 - 1) << 24;
-               }
+               else
+                       timing->reg_100228 |= magic_number << 24;
 
-               if(dev_priv->card_type == NV_40) {
+               if (dev_priv->card_type == NV_40) {
                        /* NV40: don't know what the rest of the regs are..
                         * And don't need to know either */
-                       timing->reg_100228 |= 0x20200000 | magic_number << 24;
-               } else if(dev_priv->card_type >= NV_50) {
-                       /* XXX: reg_10022c */
-                       timing->reg_10022c = tUNK_2 - 1;
+                       timing->reg_100228 |= 0x20200000;
+               } else if (dev_priv->card_type >= NV_50) {
+                       if (dev_priv->chipset < 0x98 ||
+                           (dev_priv->chipset == 0x98 &&
+                            dev_priv->stepping <= 0xa1)) {
+                               timing->reg_10022c = (0x14 + tUNK_2) << 24 |
+                                                    0x16 << 16 |
+                                                    (tUNK_2 - 1) << 8 |
+                                                    (tUNK_2 - 1);
+                       } else {
+                               /* XXX: reg_10022c for recentish cards */
+                               timing->reg_10022c = tUNK_2 - 1;
+                       }
 
                        timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
                                                  tUNK_13 << 8  | tUNK_13);
 
                        timing->reg_100234 = (tRAS << 24 | tRC);
-                       timing->reg_100234 += max(tUNK_10,tUNK_11) << 16;
+                       timing->reg_100234 += max(tUNK_10, tUNK_11) << 16;
 
-                       if(dev_priv->chipset < 0xa3) {
+                       if (dev_priv->chipset < 0x98 ||
+                           (dev_priv->chipset == 0x98 &&
+                            dev_priv->stepping <= 0xa1)) {
                                timing->reg_100234 |= (tUNK_2 + 2) << 8;
                        } else {
                                /* XXX: +6? */
                                timing->reg_100234 |= (tUNK_19 + 6) << 8;
                        }
 
-                       /* XXX; reg_100238, reg_10023c
-                        * reg_100238: 0x00??????
-                        * reg_10023c: 0x!!??0202 for NV50+ cards (empirical evidence) */
+                       /* XXX; reg_100238
+                        * reg_100238: 0x00?????? */
                        timing->reg_10023c = 0x202;
-                       if(dev_priv->chipset < 0xa3) {
+                       if (dev_priv->chipset < 0x98 ||
+                           (dev_priv->chipset == 0x98 &&
+                            dev_priv->stepping <= 0xa1)) {
                                timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16;
                        } else {
-                               /* currently unknown
+                               /* XXX: reg_10023c
+                                * currently unknown
                                 * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */
                        }
+
+                       /* XXX: reg_100240? */
                }
+               timing->id = i;
 
                NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
                         timing->reg_100220, timing->reg_100224,
@@ -693,10 +712,11 @@ nouveau_mem_timing_init(struct drm_device *dev)
                NV_DEBUG(dev, "         230: %08x %08x %08x %08x\n",
                         timing->reg_100230, timing->reg_100234,
                         timing->reg_100238, timing->reg_10023c);
+               NV_DEBUG(dev, "         240: %08x\n", timing->reg_100240);
        }
 
        memtimings->nr_timing = entries;
-       memtimings->supported = true;
+       memtimings->supported = (dev_priv->chipset <= 0x98);
 }
 
 void
@@ -848,7 +868,9 @@ nouveau_gart_manager_del(struct ttm_mem_type_manager *man,
                nouveau_vm_unmap(&node->tmp_vma);
                nouveau_vm_put(&node->tmp_vma);
        }
+
        mem->mm_node = NULL;
+       kfree(node);
 }
 
 static int
index 67a16e01ffa6db3030fd789d500dafd9b03eaf54..8f97016f5b2648a22fbdb1197f6e26168b1851b2 100644 (file)
@@ -361,20 +361,6 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, u32 pinst, u64 vinst,
        return 0;
 }
 
-
-static uint32_t
-nouveau_gpuobj_class_instmem_size(struct drm_device *dev, int class)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       /*XXX: dodgy hack for now */
-       if (dev_priv->card_type >= NV_50)
-               return 24;
-       if (dev_priv->card_type >= NV_40)
-               return 32;
-       return 16;
-}
-
 /*
    DMA objects are used to reference a piece of memory in the
    framebuffer, PCI or AGP address space. Each object is 16 bytes big
@@ -606,11 +592,11 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base,
    set to 0?
 */
 static int
-nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
-                     struct nouveau_gpuobj **gpuobj_ret)
+nouveau_gpuobj_sw_new(struct nouveau_channel *chan, u32 handle, u16 class)
 {
        struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
        struct nouveau_gpuobj *gpuobj;
+       int ret;
 
        gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
        if (!gpuobj)
@@ -624,8 +610,10 @@ nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
        spin_lock(&dev_priv->ramin_lock);
        list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
        spin_unlock(&dev_priv->ramin_lock);
-       *gpuobj_ret = gpuobj;
-       return 0;
+
+       ret = nouveau_ramht_insert(chan, handle, gpuobj);
+       nouveau_gpuobj_ref(NULL, &gpuobj);
+       return ret;
 }
 
 int
@@ -634,101 +622,30 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class)
        struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
        struct drm_device *dev = chan->dev;
        struct nouveau_gpuobj_class *oc;
-       struct nouveau_gpuobj *gpuobj;
        int ret;
 
        NV_DEBUG(dev, "ch%d class=0x%04x\n", chan->id, class);
 
        list_for_each_entry(oc, &dev_priv->classes, head) {
-               if (oc->id == class)
-                       goto found;
-       }
-
-       NV_ERROR(dev, "illegal object class: 0x%x\n", class);
-       return -EINVAL;
+               struct nouveau_exec_engine *eng = dev_priv->eng[oc->engine];
 
-found:
-       switch (oc->engine) {
-       case NVOBJ_ENGINE_SW:
-               if (dev_priv->card_type < NV_C0) {
-                       ret = nouveau_gpuobj_sw_new(chan, class, &gpuobj);
-                       if (ret)
-                               return ret;
-                       goto insert;
-               }
-               break;
-       case NVOBJ_ENGINE_GR:
-               if ((dev_priv->card_type >= NV_20 && !chan->ramin_grctx) ||
-                   (dev_priv->card_type  < NV_20 && !chan->pgraph_ctx)) {
-                       struct nouveau_pgraph_engine *pgraph =
-                               &dev_priv->engine.graph;
+               if (oc->id != class)
+                       continue;
 
-                       ret = pgraph->create_context(chan);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NVOBJ_ENGINE_CRYPT:
-               if (!chan->crypt_ctx) {
-                       struct nouveau_crypt_engine *pcrypt =
-                               &dev_priv->engine.crypt;
+               if (oc->engine == NVOBJ_ENGINE_SW)
+                       return nouveau_gpuobj_sw_new(chan, handle, class);
 
-                       ret = pcrypt->create_context(chan);
+               if (!chan->engctx[oc->engine]) {
+                       ret = eng->context_new(chan, oc->engine);
                        if (ret)
                                return ret;
                }
-               break;
-       }
-
-       /* we're done if this is fermi */
-       if (dev_priv->card_type >= NV_C0)
-               return 0;
-
-       ret = nouveau_gpuobj_new(dev, chan,
-                                nouveau_gpuobj_class_instmem_size(dev, class),
-                                16,
-                                NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
-                                &gpuobj);
-       if (ret) {
-               NV_ERROR(dev, "error creating gpuobj: %d\n", ret);
-               return ret;
-       }
 
-       if (dev_priv->card_type >= NV_50) {
-               nv_wo32(gpuobj,  0, class);
-               nv_wo32(gpuobj, 20, 0x00010000);
-       } else {
-               switch (class) {
-               case NV_CLASS_NULL:
-                       nv_wo32(gpuobj, 0, 0x00001030);
-                       nv_wo32(gpuobj, 4, 0xFFFFFFFF);
-                       break;
-               default:
-                       if (dev_priv->card_type >= NV_40) {
-                               nv_wo32(gpuobj, 0, class);
-#ifdef __BIG_ENDIAN
-                               nv_wo32(gpuobj, 8, 0x01000000);
-#endif
-                       } else {
-#ifdef __BIG_ENDIAN
-                               nv_wo32(gpuobj, 0, class | 0x00080000);
-#else
-                               nv_wo32(gpuobj, 0, class);
-#endif
-                       }
-               }
+               return eng->object_new(chan, oc->engine, handle, class);
        }
-       dev_priv->engine.instmem.flush(dev);
-
-       gpuobj->engine = oc->engine;
-       gpuobj->class  = oc->id;
 
-insert:
-       ret = nouveau_ramht_insert(chan, handle, gpuobj);
-       if (ret)
-               NV_ERROR(dev, "error adding gpuobj to RAMHT: %d\n", ret);
-       nouveau_gpuobj_ref(NULL, &gpuobj);
-       return ret;
+       NV_ERROR(dev, "illegal object class: 0x%x\n", class);
+       return -EINVAL;
 }
 
 static int
@@ -746,9 +663,6 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
        size = 0x2000;
        base = 0;
 
-       /* PGRAPH context */
-       size += dev_priv->engine.graph.grctx_size;
-
        if (dev_priv->card_type == NV_50) {
                /* Various fixed table thingos */
                size += 0x1400; /* mostly unknown stuff */
index 670e3cb697ec7664921e1fc87f57fa6fa40cd68e..ef9dec0e6f8b343c293eb7002560686838731180 100644 (file)
@@ -72,6 +72,68 @@ legacy_perf_init(struct drm_device *dev)
        pm->nr_perflvl = 1;
 }
 
+static struct nouveau_pm_memtiming *
+nouveau_perf_timing(struct drm_device *dev, struct bit_entry *P,
+                   u16 memclk, u8 *entry, u8 recordlen, u8 entries)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nvbios *bios = &dev_priv->vbios;
+       u8 ramcfg;
+       int i;
+
+       /* perf v2 has a separate "timing map" table, we have to match
+        * the target memory clock to a specific entry, *then* use
+        * ramcfg to select the correct subentry
+        */
+       if (P->version == 2) {
+               u8 *tmap = ROMPTR(bios, P->data[4]);
+               if (!tmap) {
+                       NV_DEBUG(dev, "no timing map pointer\n");
+                       return NULL;
+               }
+
+               if (tmap[0] != 0x10) {
+                       NV_WARN(dev, "timing map 0x%02x unknown\n", tmap[0]);
+                       return NULL;
+               }
+
+               entry = tmap + tmap[1];
+               recordlen = tmap[2] + (tmap[4] * tmap[3]);
+               for (i = 0; i < tmap[5]; i++, entry += recordlen) {
+                       if (memclk >= ROM16(entry[0]) &&
+                           memclk <= ROM16(entry[2]))
+                               break;
+               }
+
+               if (i == tmap[5]) {
+                       NV_WARN(dev, "no match in timing map table\n");
+                       return NULL;
+               }
+
+               entry += tmap[2];
+               recordlen = tmap[3];
+               entries   = tmap[4];
+       }
+
+       ramcfg = (nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x0000003c) >> 2;
+       if (bios->ram_restrict_tbl_ptr)
+               ramcfg = bios->data[bios->ram_restrict_tbl_ptr + ramcfg];
+
+       if (ramcfg >= entries) {
+               NV_WARN(dev, "ramcfg strap out of bounds!\n");
+               return NULL;
+       }
+
+       entry += ramcfg * recordlen;
+       if (entry[1] >= pm->memtimings.nr_timing) {
+               NV_WARN(dev, "timingset %d does not exist\n", entry[1]);
+               return NULL;
+       }
+
+       return &pm->memtimings.timing[entry[1]];
+}
+
 void
 nouveau_perf_init(struct drm_device *dev)
 {
@@ -120,10 +182,17 @@ nouveau_perf_init(struct drm_device *dev)
                entries   = perf[2];
        }
 
+       if (entries > NOUVEAU_PM_MAX_LEVEL) {
+               NV_DEBUG(dev, "perf table has too many entries - buggy vbios?\n");
+               entries = NOUVEAU_PM_MAX_LEVEL;
+       }
+
        entry = perf + headerlen;
        for (i = 0; i < entries; i++) {
                struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
 
+               perflvl->timing = NULL;
+
                if (entry[0] == 0xff) {
                        entry += recordlen;
                        continue;
@@ -174,9 +243,21 @@ nouveau_perf_init(struct drm_device *dev)
 #define subent(n) entry[perf[2] + ((n) * perf[3])]
                        perflvl->fanspeed = 0; /*XXX*/
                        perflvl->voltage = entry[2];
-                       perflvl->core = (ROM16(subent(0)) & 0xfff) * 1000;
-                       perflvl->shader = (ROM16(subent(1)) & 0xfff) * 1000;
-                       perflvl->memory = (ROM16(subent(2)) & 0xfff) * 1000;
+                       if (dev_priv->card_type == NV_50) {
+                               perflvl->core = ROM16(subent(0)) & 0xfff;
+                               perflvl->shader = ROM16(subent(1)) & 0xfff;
+                               perflvl->memory = ROM16(subent(2)) & 0xfff;
+                       } else {
+                               perflvl->shader = ROM16(subent(3)) & 0xfff;
+                               perflvl->core   = perflvl->shader / 2;
+                               perflvl->unk0a  = ROM16(subent(4)) & 0xfff;
+                               perflvl->memory = ROM16(subent(5)) & 0xfff;
+                       }
+
+                       perflvl->core *= 1000;
+                       perflvl->shader *= 1000;
+                       perflvl->memory *= 1000;
+                       perflvl->unk0a *= 1000;
                        break;
                }
 
@@ -190,6 +271,16 @@ nouveau_perf_init(struct drm_device *dev)
                        }
                }
 
+               /* get the corresponding memory timings */
+               if (version > 0x15) {
+                       /* last 3 args are for < 0x40, ignored for >= 0x40 */
+                       perflvl->timing =
+                               nouveau_perf_timing(dev, &P,
+                                                   perflvl->memory / 1000,
+                                                   entry + perf[3],
+                                                   perf[5], perf[4]);
+               }
+
                snprintf(perflvl->name, sizeof(perflvl->name),
                         "performance_level_%d", i);
                perflvl->id = i;
index 4399e2f34db41068dd1769a06af1547b6603a263..da8d994d5e8a3f2b505a7d9fefa9f764a51112df 100644 (file)
@@ -156,7 +156,7 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
 static void
 nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
 {
-       char c[16], s[16], v[16], f[16];
+       char c[16], s[16], v[16], f[16], t[16];
 
        c[0] = '\0';
        if (perflvl->core)
@@ -174,8 +174,12 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
        if (perflvl->fanspeed)
                snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed);
 
-       snprintf(ptr, len, "memory %dMHz%s%s%s%s\n", perflvl->memory / 1000,
-                c, s, v, f);
+       t[0] = '\0';
+       if (perflvl->timing)
+               snprintf(t, sizeof(t), " timing %d", perflvl->timing->id);
+
+       snprintf(ptr, len, "memory %dMHz%s%s%s%s%s\n", perflvl->memory / 1000,
+                c, s, v, f, t);
 }
 
 static ssize_t
@@ -449,7 +453,7 @@ nouveau_hwmon_fini(struct drm_device *dev)
 #endif
 }
 
-#ifdef CONFIG_ACPI
+#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
 static int
 nouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data)
 {
@@ -476,10 +480,10 @@ nouveau_pm_init(struct drm_device *dev)
        char info[256];
        int ret, i;
 
+       nouveau_mem_timing_init(dev);
        nouveau_volt_init(dev);
        nouveau_perf_init(dev);
        nouveau_temp_init(dev);
-       nouveau_mem_timing_init(dev);
 
        NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl);
        for (i = 0; i < pm->nr_perflvl; i++) {
@@ -490,6 +494,7 @@ nouveau_pm_init(struct drm_device *dev)
        /* determine current ("boot") performance level */
        ret = nouveau_pm_perflvl_get(dev, &pm->boot);
        if (ret == 0) {
+               strncpy(pm->boot.name, "boot", 4);
                pm->cur = &pm->boot;
 
                nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info));
@@ -507,7 +512,7 @@ nouveau_pm_init(struct drm_device *dev)
 
        nouveau_sysfs_init(dev);
        nouveau_hwmon_init(dev);
-#ifdef CONFIG_ACPI
+#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
        pm->acpi_nb.notifier_call = nouveau_pm_acpi_event;
        register_acpi_notifier(&pm->acpi_nb);
 #endif
@@ -524,12 +529,12 @@ nouveau_pm_fini(struct drm_device *dev)
        if (pm->cur != &pm->boot)
                nouveau_pm_perflvl_set(dev, &pm->boot);
 
-       nouveau_mem_timing_fini(dev);
        nouveau_temp_fini(dev);
        nouveau_perf_fini(dev);
        nouveau_volt_fini(dev);
+       nouveau_mem_timing_fini(dev);
 
-#ifdef CONFIG_ACPI
+#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
        unregister_acpi_notifier(&pm->acpi_nb);
 #endif
        nouveau_hwmon_fini(dev);
index 04e8fb7952692ccfde1524439d12e51a7cd88f64..f18cdfc3400fc00894dd8f40c3e3239114e2a2e5 100644 (file)
 #    define NV50_PCONNECTOR_I2C_PORT_4                      0x0000e240
 #    define NV50_PCONNECTOR_I2C_PORT_5                      0x0000e258
 
-#define NV50_AUXCH_DATA_OUT(i,n)             ((n) * 4 + (i) * 0x50 + 0x0000e4c0)
+#define NV50_AUXCH_DATA_OUT(i, n)            ((n) * 4 + (i) * 0x50 + 0x0000e4c0)
 #define NV50_AUXCH_DATA_OUT__SIZE                                             4
-#define NV50_AUXCH_DATA_IN(i,n)              ((n) * 4 + (i) * 0x50 + 0x0000e4d0)
+#define NV50_AUXCH_DATA_IN(i, n)             ((n) * 4 + (i) * 0x50 + 0x0000e4d0)
 #define NV50_AUXCH_DATA_IN__SIZE                                              4
 #define NV50_AUXCH_ADDR(i)                             ((i) * 0x50 + 0x0000e4e0)
 #define NV50_AUXCH_CTRL(i)                             ((i) * 0x50 + 0x0000e4e4)
 #define NV50_PDISPLAY_SOR_BACKLIGHT                                  0x0061c084
 #define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE                           0x80000000
 #define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL                            0x00000fff
-#define NV50_SOR_DP_CTRL(i,l)            (0x0061c10c + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_CTRL(i, l)           (0x0061c10c + (i) * 0x800 + (l) * 0x80)
 #define NV50_SOR_DP_CTRL_ENABLED                                     0x00000001
 #define NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED                      0x00004000
 #define NV50_SOR_DP_CTRL_LANE_MASK                                   0x001f0000
 #define NV50_SOR_DP_CTRL_TRAINING_PATTERN_DISABLED                   0x00000000
 #define NV50_SOR_DP_CTRL_TRAINING_PATTERN_1                          0x01000000
 #define NV50_SOR_DP_CTRL_TRAINING_PATTERN_2                          0x02000000
-#define NV50_SOR_DP_UNK118(i,l)          (0x0061c118 + (i) * 0x800 + (l) * 0x80)
-#define NV50_SOR_DP_UNK120(i,l)          (0x0061c120 + (i) * 0x800 + (l) * 0x80)
-#define NV50_SOR_DP_UNK128(i,l)          (0x0061c128 + (i) * 0x800 + (l) * 0x80)
-#define NV50_SOR_DP_UNK130(i,l)          (0x0061c130 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK118(i, l)         (0x0061c118 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK120(i, l)         (0x0061c120 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK128(i, l)         (0x0061c128 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK130(i, l)         (0x0061c130 + (i) * 0x800 + (l) * 0x80)
 
 #define NV50_PDISPLAY_USER(i)                        ((i) * 0x1000 + 0x00640000)
 #define NV50_PDISPLAY_USER_PUT(i)                    ((i) * 0x1000 + 0x00640000)
index c77111eca6acefc8ab31acb7bb060547b64b5f7a..82fad914e648441340a836bf306d761d09afc904 100644 (file)
@@ -458,7 +458,7 @@ nouveau_sgdma_init(struct drm_device *dev)
                dev_priv->gart_info.type = NOUVEAU_GART_HW;
                dev_priv->gart_info.func = &nv50_sgdma_backend;
        } else
-       if (drm_pci_device_is_pcie(dev) &&
+       if (0 && drm_pci_device_is_pcie(dev) &&
            dev_priv->chipset > 0x40 && dev_priv->chipset != 0x45) {
                if (nv44_graph_class(dev)) {
                        dev_priv->gart_info.func = &nv44_sgdma_backend;
index 915fbce8959517f4c51a9114a8224617ecbe265b..144f79a350ae3d69b542a7f364988d194a28cbcb 100644 (file)
@@ -65,14 +65,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->timer.takedown          = nv04_timer_takedown;
                engine->fb.init                 = nv04_fb_init;
                engine->fb.takedown             = nv04_fb_takedown;
-               engine->graph.init              = nv04_graph_init;
-               engine->graph.takedown          = nv04_graph_takedown;
-               engine->graph.fifo_access       = nv04_graph_fifo_access;
-               engine->graph.channel           = nv04_graph_channel;
-               engine->graph.create_context    = nv04_graph_create_context;
-               engine->graph.destroy_context   = nv04_graph_destroy_context;
-               engine->graph.load_context      = nv04_graph_load_context;
-               engine->graph.unload_context    = nv04_graph_unload_context;
                engine->fifo.channels           = 16;
                engine->fifo.init               = nv04_fifo_init;
                engine->fifo.takedown           = nv04_fifo_fini;
@@ -98,8 +90,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.clock_get            = nv04_pm_clock_get;
                engine->pm.clock_pre            = nv04_pm_clock_pre;
                engine->pm.clock_set            = nv04_pm_clock_set;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -123,15 +113,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fb.init_tile_region     = nv10_fb_init_tile_region;
                engine->fb.set_tile_region      = nv10_fb_set_tile_region;
                engine->fb.free_tile_region     = nv10_fb_free_tile_region;
-               engine->graph.init              = nv10_graph_init;
-               engine->graph.takedown          = nv10_graph_takedown;
-               engine->graph.channel           = nv10_graph_channel;
-               engine->graph.create_context    = nv10_graph_create_context;
-               engine->graph.destroy_context   = nv10_graph_destroy_context;
-               engine->graph.fifo_access       = nv04_graph_fifo_access;
-               engine->graph.load_context      = nv10_graph_load_context;
-               engine->graph.unload_context    = nv10_graph_unload_context;
-               engine->graph.set_tile_region   = nv10_graph_set_tile_region;
                engine->fifo.channels           = 32;
                engine->fifo.init               = nv10_fifo_init;
                engine->fifo.takedown           = nv04_fifo_fini;
@@ -157,8 +138,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.clock_get            = nv04_pm_clock_get;
                engine->pm.clock_pre            = nv04_pm_clock_pre;
                engine->pm.clock_set            = nv04_pm_clock_set;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -182,15 +161,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fb.init_tile_region     = nv10_fb_init_tile_region;
                engine->fb.set_tile_region      = nv10_fb_set_tile_region;
                engine->fb.free_tile_region     = nv10_fb_free_tile_region;
-               engine->graph.init              = nv20_graph_init;
-               engine->graph.takedown          = nv20_graph_takedown;
-               engine->graph.channel           = nv10_graph_channel;
-               engine->graph.create_context    = nv20_graph_create_context;
-               engine->graph.destroy_context   = nv20_graph_destroy_context;
-               engine->graph.fifo_access       = nv04_graph_fifo_access;
-               engine->graph.load_context      = nv20_graph_load_context;
-               engine->graph.unload_context    = nv20_graph_unload_context;
-               engine->graph.set_tile_region   = nv20_graph_set_tile_region;
                engine->fifo.channels           = 32;
                engine->fifo.init               = nv10_fifo_init;
                engine->fifo.takedown           = nv04_fifo_fini;
@@ -216,8 +186,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.clock_get            = nv04_pm_clock_get;
                engine->pm.clock_pre            = nv04_pm_clock_pre;
                engine->pm.clock_set            = nv04_pm_clock_set;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -241,15 +209,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fb.init_tile_region     = nv30_fb_init_tile_region;
                engine->fb.set_tile_region      = nv10_fb_set_tile_region;
                engine->fb.free_tile_region     = nv30_fb_free_tile_region;
-               engine->graph.init              = nv30_graph_init;
-               engine->graph.takedown          = nv20_graph_takedown;
-               engine->graph.fifo_access       = nv04_graph_fifo_access;
-               engine->graph.channel           = nv10_graph_channel;
-               engine->graph.create_context    = nv20_graph_create_context;
-               engine->graph.destroy_context   = nv20_graph_destroy_context;
-               engine->graph.load_context      = nv20_graph_load_context;
-               engine->graph.unload_context    = nv20_graph_unload_context;
-               engine->graph.set_tile_region   = nv20_graph_set_tile_region;
                engine->fifo.channels           = 32;
                engine->fifo.init               = nv10_fifo_init;
                engine->fifo.takedown           = nv04_fifo_fini;
@@ -277,8 +236,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.clock_set            = nv04_pm_clock_set;
                engine->pm.voltage_get          = nouveau_voltage_gpio_get;
                engine->pm.voltage_set          = nouveau_voltage_gpio_set;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -303,15 +260,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fb.init_tile_region     = nv30_fb_init_tile_region;
                engine->fb.set_tile_region      = nv40_fb_set_tile_region;
                engine->fb.free_tile_region     = nv30_fb_free_tile_region;
-               engine->graph.init              = nv40_graph_init;
-               engine->graph.takedown          = nv40_graph_takedown;
-               engine->graph.fifo_access       = nv04_graph_fifo_access;
-               engine->graph.channel           = nv40_graph_channel;
-               engine->graph.create_context    = nv40_graph_create_context;
-               engine->graph.destroy_context   = nv40_graph_destroy_context;
-               engine->graph.load_context      = nv40_graph_load_context;
-               engine->graph.unload_context    = nv40_graph_unload_context;
-               engine->graph.set_tile_region   = nv40_graph_set_tile_region;
                engine->fifo.channels           = 32;
                engine->fifo.init               = nv40_fifo_init;
                engine->fifo.takedown           = nv04_fifo_fini;
@@ -340,8 +288,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.voltage_get          = nouveau_voltage_gpio_get;
                engine->pm.voltage_set          = nouveau_voltage_gpio_set;
                engine->pm.temp_get             = nv40_temp_get;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -368,19 +314,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->timer.takedown          = nv04_timer_takedown;
                engine->fb.init                 = nv50_fb_init;
                engine->fb.takedown             = nv50_fb_takedown;
-               engine->graph.init              = nv50_graph_init;
-               engine->graph.takedown          = nv50_graph_takedown;
-               engine->graph.fifo_access       = nv50_graph_fifo_access;
-               engine->graph.channel           = nv50_graph_channel;
-               engine->graph.create_context    = nv50_graph_create_context;
-               engine->graph.destroy_context   = nv50_graph_destroy_context;
-               engine->graph.load_context      = nv50_graph_load_context;
-               engine->graph.unload_context    = nv50_graph_unload_context;
-               if (dev_priv->chipset == 0x50 ||
-                   dev_priv->chipset == 0xac)
-                       engine->graph.tlb_flush = nv50_graph_tlb_flush;
-               else
-                       engine->graph.tlb_flush = nv84_graph_tlb_flush;
                engine->fifo.channels           = 128;
                engine->fifo.init               = nv50_fifo_init;
                engine->fifo.takedown           = nv50_fifo_takedown;
@@ -432,30 +365,13 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                        engine->pm.temp_get     = nv84_temp_get;
                else
                        engine->pm.temp_get     = nv40_temp_get;
-               switch (dev_priv->chipset) {
-               case 0x84:
-               case 0x86:
-               case 0x92:
-               case 0x94:
-               case 0x96:
-               case 0xa0:
-                       engine->crypt.init      = nv84_crypt_init;
-                       engine->crypt.takedown  = nv84_crypt_fini;
-                       engine->crypt.create_context = nv84_crypt_create_context;
-                       engine->crypt.destroy_context = nv84_crypt_destroy_context;
-                       engine->crypt.tlb_flush = nv84_crypt_tlb_flush;
-                       break;
-               default:
-                       engine->crypt.init      = nouveau_stub_init;
-                       engine->crypt.takedown  = nouveau_stub_takedown;
-                       break;
-               }
                engine->vram.init               = nv50_vram_init;
                engine->vram.get                = nv50_vram_new;
                engine->vram.put                = nv50_vram_del;
                engine->vram.flags_valid        = nv50_vram_flags_valid;
                break;
        case 0xC0:
+       case 0xD0:
                engine->instmem.init            = nvc0_instmem_init;
                engine->instmem.takedown        = nvc0_instmem_takedown;
                engine->instmem.suspend         = nvc0_instmem_suspend;
@@ -472,14 +388,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->timer.takedown          = nv04_timer_takedown;
                engine->fb.init                 = nvc0_fb_init;
                engine->fb.takedown             = nvc0_fb_takedown;
-               engine->graph.init              = nvc0_graph_init;
-               engine->graph.takedown          = nvc0_graph_takedown;
-               engine->graph.fifo_access       = nvc0_graph_fifo_access;
-               engine->graph.channel           = nvc0_graph_channel;
-               engine->graph.create_context    = nvc0_graph_create_context;
-               engine->graph.destroy_context   = nvc0_graph_destroy_context;
-               engine->graph.load_context      = nvc0_graph_load_context;
-               engine->graph.unload_context    = nvc0_graph_unload_context;
                engine->fifo.channels           = 128;
                engine->fifo.init               = nvc0_fifo_init;
                engine->fifo.takedown           = nvc0_fifo_takedown;
@@ -503,8 +411,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->gpio.irq_register       = nv50_gpio_irq_register;
                engine->gpio.irq_unregister     = nv50_gpio_irq_unregister;
                engine->gpio.irq_enable         = nv50_gpio_irq_enable;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nvc0_vram_init;
                engine->vram.get                = nvc0_vram_new;
                engine->vram.put                = nv50_vram_del;
@@ -593,7 +499,7 @@ nouveau_card_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_engine *engine;
-       int ret;
+       int ret, e = 0;
 
        vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
        vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state,
@@ -658,23 +564,80 @@ nouveau_card_init(struct drm_device *dev)
        if (ret)
                goto out_timer;
 
-       if (nouveau_noaccel)
-               engine->graph.accel_blocked = true;
-       else {
-               /* PGRAPH */
-               ret = engine->graph.init(dev);
-               if (ret)
-                       goto out_fb;
+       if (!nouveau_noaccel) {
+               switch (dev_priv->card_type) {
+               case NV_04:
+                       nv04_graph_create(dev);
+                       break;
+               case NV_10:
+                       nv10_graph_create(dev);
+                       break;
+               case NV_20:
+               case NV_30:
+                       nv20_graph_create(dev);
+                       break;
+               case NV_40:
+                       nv40_graph_create(dev);
+                       break;
+               case NV_50:
+                       nv50_graph_create(dev);
+                       break;
+               case NV_C0:
+                       nvc0_graph_create(dev);
+                       break;
+               default:
+                       break;
+               }
 
-               /* PCRYPT */
-               ret = engine->crypt.init(dev);
-               if (ret)
-                       goto out_graph;
+               switch (dev_priv->chipset) {
+               case 0x84:
+               case 0x86:
+               case 0x92:
+               case 0x94:
+               case 0x96:
+               case 0xa0:
+                       nv84_crypt_create(dev);
+                       break;
+               }
+
+               switch (dev_priv->card_type) {
+               case NV_50:
+                       switch (dev_priv->chipset) {
+                       case 0xa3:
+                       case 0xa5:
+                       case 0xa8:
+                       case 0xaf:
+                               nva3_copy_create(dev);
+                               break;
+                       }
+                       break;
+               case NV_C0:
+                       nvc0_copy_create(dev, 0);
+                       nvc0_copy_create(dev, 1);
+                       break;
+               default:
+                       break;
+               }
+
+               if (dev_priv->card_type == NV_40)
+                       nv40_mpeg_create(dev);
+               else
+               if (dev_priv->card_type == NV_50 &&
+                   (dev_priv->chipset < 0x98 || dev_priv->chipset == 0xa0))
+                       nv50_mpeg_create(dev);
+
+               for (e = 0; e < NVOBJ_ENGINE_NR; e++) {
+                       if (dev_priv->eng[e]) {
+                               ret = dev_priv->eng[e]->init(dev, e);
+                               if (ret)
+                                       goto out_engine;
+                       }
+               }
 
                /* PFIFO */
                ret = engine->fifo.init(dev);
                if (ret)
-                       goto out_crypt;
+                       goto out_engine;
        }
 
        ret = engine->display.create(dev);
@@ -691,7 +654,7 @@ nouveau_card_init(struct drm_device *dev)
 
        /* what about PVIDEO/PCRTC/PRAMDAC etc? */
 
-       if (!engine->graph.accel_blocked) {
+       if (dev_priv->eng[NVOBJ_ENGINE_GR]) {
                ret = nouveau_fence_init(dev);
                if (ret)
                        goto out_irq;
@@ -715,13 +678,16 @@ out_vblank:
 out_fifo:
        if (!nouveau_noaccel)
                engine->fifo.takedown(dev);
-out_crypt:
-       if (!nouveau_noaccel)
-               engine->crypt.takedown(dev);
-out_graph:
-       if (!nouveau_noaccel)
-               engine->graph.takedown(dev);
-out_fb:
+out_engine:
+       if (!nouveau_noaccel) {
+               for (e = e - 1; e >= 0; e--) {
+                       if (!dev_priv->eng[e])
+                               continue;
+                       dev_priv->eng[e]->fini(dev, e);
+                       dev_priv->eng[e]->destroy(dev,e );
+               }
+       }
+
        engine->fb.takedown(dev);
 out_timer:
        engine->timer.takedown(dev);
@@ -751,16 +717,21 @@ static void nouveau_card_takedown(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_engine *engine = &dev_priv->engine;
+       int e;
 
-       if (!engine->graph.accel_blocked) {
+       if (dev_priv->channel) {
                nouveau_fence_fini(dev);
                nouveau_channel_put_unlocked(&dev_priv->channel);
        }
 
        if (!nouveau_noaccel) {
                engine->fifo.takedown(dev);
-               engine->crypt.takedown(dev);
-               engine->graph.takedown(dev);
+               for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
+                       if (dev_priv->eng[e]) {
+                               dev_priv->eng[e]->fini(dev, e);
+                               dev_priv->eng[e]->destroy(dev,e );
+                       }
+               }
        }
        engine->fb.takedown(dev);
        engine->timer.takedown(dev);
@@ -866,7 +837,7 @@ static int nouveau_remove_conflicting_drivers(struct drm_device *dev)
 #ifdef CONFIG_X86
        primary = dev->pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
 #endif
-       
+
        remove_conflicting_framebuffers(dev_priv->apertures, "nouveaufb", primary);
        return 0;
 }
@@ -910,19 +881,21 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
 
 #ifdef __BIG_ENDIAN
        /* Put the card in BE mode if it's not */
-       if (nv_rd32(dev, NV03_PMC_BOOT_1))
-               nv_wr32(dev, NV03_PMC_BOOT_1, 0x00000001);
+       if (nv_rd32(dev, NV03_PMC_BOOT_1) != 0x01000001)
+               nv_wr32(dev, NV03_PMC_BOOT_1, 0x01000001);
 
        DRM_MEMORYBARRIER();
 #endif
 
        /* Time to determine the card architecture */
        reg0 = nv_rd32(dev, NV03_PMC_BOOT_0);
+       dev_priv->stepping = 0; /* XXX: add stepping for pre-NV10? */
 
        /* We're dealing with >=NV10 */
        if ((reg0 & 0x0f000000) > 0) {
                /* Bit 27-20 contain the architecture in hex */
                dev_priv->chipset = (reg0 & 0xff00000) >> 20;
+               dev_priv->stepping = (reg0 & 0xff);
        /* NV04 or NV05 */
        } else if ((reg0 & 0xff00fff0) == 0x20004000) {
                if (reg0 & 0x00f00000)
@@ -950,6 +923,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
                dev_priv->card_type = NV_50;
                break;
        case 0xc0:
+       case 0xd0:
                dev_priv->card_type = NV_C0;
                break;
        default:
index 0059e6f58a8b642c9d88f00b7991a97dc68b1772..519a6b4bba466fce9a46577908b411e5cfdbbdfa 100644 (file)
@@ -58,6 +58,7 @@ nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_mem *node)
                        num -= len;
                        pte += len;
                        if (unlikely(end >= max)) {
+                               phys += len << (bits + 12);
                                pde++;
                                pte = 0;
                        }
index 2e06b55cfdc1844eb4e1a376890fa35912fb10ca..c48a9fc2b47b41eb870f17a7f9fa95c28a4daa20 100644 (file)
@@ -53,8 +53,7 @@ struct nouveau_vm {
        int refcount;
 
        struct list_head pgd_list;
-       atomic_t pgraph_refs;
-       atomic_t pcrypt_refs;
+       atomic_t engref[16];
 
        struct nouveau_vm_pgt *pgt;
        u32 fpde;
index 04fdc00a67d540324bb8a5ef4ee4fcf0d9b1ecfa..75e872741d9218c91aeb49c46dfd7f3f6268cdf2 100644 (file)
@@ -159,8 +159,16 @@ nouveau_volt_init(struct drm_device *dev)
                headerlen = volt[1];
                recordlen = volt[2];
                entries   = volt[3];
-               vidshift  = hweight8(volt[5]);
                vidmask   = volt[4];
+               /* no longer certain what volt[5] is, if it's related to
+                * the vid shift then it's definitely not a function of
+                * how many bits are set.
+                *
+                * after looking at a number of nva3+ vbios images, they
+                * all seem likely to have a static shift of 2.. lets
+                * go with that for now until proven otherwise.
+                */
+               vidshift  = 2;
                break;
        default:
                NV_WARN(dev, "voltage table 0x%02x unknown\n", volt[0]);
index 748b9d9c2949df0f24a998e1caf0cfec2f929258..f1a3ae49199505d7ab1d0b187733a33a6bb6a0a2 100644 (file)
@@ -376,7 +376,10 @@ nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode)
         */
 
        /* framebuffer can be larger than crtc scanout area. */
-       regp->CRTC[NV_CIO_CRE_RPC0_INDEX] = XLATE(fb->pitch / 8, 8, NV_CIO_CRE_RPC0_OFFSET_10_8);
+       regp->CRTC[NV_CIO_CRE_RPC0_INDEX] =
+               XLATE(fb->pitch / 8, 8, NV_CIO_CRE_RPC0_OFFSET_10_8);
+       regp->CRTC[NV_CIO_CRE_42] =
+               XLATE(fb->pitch / 8, 11, NV_CIO_CRE_42_OFFSET_11);
        regp->CRTC[NV_CIO_CRE_RPC1_INDEX] = mode->crtc_hdisplay < 1280 ?
                                            MASK(NV_CIO_CRE_RPC1_LARGE) : 0x00;
        regp->CRTC[NV_CIO_CRE_LSR_INDEX] = XLATE(horizBlankEnd, 6, NV_CIO_CRE_LSR_HBE_6) |
@@ -790,8 +793,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
        if (atomic) {
                drm_fb = passed_fb;
                fb = nouveau_framebuffer(passed_fb);
-       }
-       else {
+       } else {
                /* If not atomic, we can go ahead and pin, and unpin the
                 * old fb we were passed.
                 */
@@ -825,8 +827,11 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
        regp->CRTC[NV_CIO_CR_OFFSET_INDEX] = drm_fb->pitch >> 3;
        regp->CRTC[NV_CIO_CRE_RPC0_INDEX] =
                XLATE(drm_fb->pitch >> 3, 8, NV_CIO_CRE_RPC0_OFFSET_10_8);
+       regp->CRTC[NV_CIO_CRE_42] =
+               XLATE(drm_fb->pitch / 8, 11, NV_CIO_CRE_42_OFFSET_11);
        crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_RPC0_INDEX);
        crtc_wr_cio_state(crtc, regp, NV_CIO_CR_OFFSET_INDEX);
+       crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_42);
 
        /* Update the framebuffer location. */
        regp->fb_start = nv_crtc->fb.offset & ~3;
@@ -944,14 +949,14 @@ nv04_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
        struct drm_gem_object *gem;
        int ret = 0;
 
-       if (width != 64 || height != 64)
-               return -EINVAL;
-
        if (!buffer_handle) {
                nv_crtc->cursor.hide(nv_crtc, true);
                return 0;
        }
 
+       if (width != 64 || height != 64)
+               return -EINVAL;
+
        gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
        if (!gem)
                return -ENOENT;
index af75015068d6bd89477d81f5a5b5aabae41c9a3b..3626ee7db3ba5924cfc5dcd5412b1d618203c5f7 100644 (file)
 #include "nouveau_drv.h"
 #include "nouveau_hw.h"
 #include "nouveau_util.h"
+#include "nouveau_ramht.h"
 
-static int  nv04_graph_register(struct drm_device *dev);
-static void nv04_graph_isr(struct drm_device *dev);
+struct nv04_graph_engine {
+       struct nouveau_exec_engine base;
+};
 
 static uint32_t nv04_graph_ctx_regs[] = {
        0x0040053c,
@@ -350,7 +352,7 @@ struct graph_state {
        uint32_t nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
 };
 
-struct nouveau_channel *
+static struct nouveau_channel *
 nv04_graph_channel(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -365,26 +367,6 @@ nv04_graph_channel(struct drm_device *dev)
        return dev_priv->channels.ptr[chid];
 }
 
-static void
-nv04_graph_context_switch(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_channel *chan = NULL;
-       int chid;
-
-       nouveau_wait_for_idle(dev);
-
-       /* If previous context is valid, we need to save it */
-       pgraph->unload_context(dev);
-
-       /* Load context for next channel */
-       chid = dev_priv->engine.fifo.channel_id(dev);
-       chan = dev_priv->channels.ptr[chid];
-       if (chan)
-               nv04_graph_load_context(chan);
-}
-
 static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg)
 {
        int i;
@@ -397,48 +379,11 @@ static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg)
        return NULL;
 }
 
-int nv04_graph_create_context(struct nouveau_channel *chan)
-{
-       struct graph_state *pgraph_ctx;
-       NV_DEBUG(chan->dev, "nv04_graph_context_create %d\n", chan->id);
-
-       chan->pgraph_ctx = pgraph_ctx = kzalloc(sizeof(*pgraph_ctx),
-                                               GFP_KERNEL);
-       if (pgraph_ctx == NULL)
-               return -ENOMEM;
-
-       *ctx_reg(pgraph_ctx, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
-
-       return 0;
-}
-
-void nv04_graph_destroy_context(struct nouveau_channel *chan)
-{
-       struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       pgraph->fifo_access(dev, false);
-
-       /* Unload the context if it's the currently active one */
-       if (pgraph->channel(dev) == chan)
-               pgraph->unload_context(dev);
-
-       /* Free the context resources */
-       kfree(pgraph_ctx);
-       chan->pgraph_ctx = NULL;
-
-       pgraph->fifo_access(dev, true);
-       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-}
-
-int nv04_graph_load_context(struct nouveau_channel *chan)
+static int
+nv04_graph_load_context(struct nouveau_channel *chan)
 {
+       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
        struct drm_device *dev = chan->dev;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
        uint32_t tmp;
        int i;
 
@@ -456,20 +401,19 @@ int nv04_graph_load_context(struct nouveau_channel *chan)
        return 0;
 }
 
-int
+static int
 nv04_graph_unload_context(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        struct nouveau_channel *chan = NULL;
        struct graph_state *ctx;
        uint32_t tmp;
        int i;
 
-       chan = pgraph->channel(dev);
+       chan = nv04_graph_channel(dev);
        if (!chan)
                return 0;
-       ctx = chan->pgraph_ctx;
+       ctx = chan->engctx[NVOBJ_ENGINE_GR];
 
        for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++)
                ctx->nv04[i] = nv_rd32(dev, nv04_graph_ctx_regs[i]);
@@ -481,23 +425,85 @@ nv04_graph_unload_context(struct drm_device *dev)
        return 0;
 }
 
-int nv04_graph_init(struct drm_device *dev)
+static int
+nv04_graph_context_new(struct nouveau_channel *chan, int engine)
 {
+       struct graph_state *pgraph_ctx;
+       NV_DEBUG(chan->dev, "nv04_graph_context_create %d\n", chan->id);
+
+       pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL);
+       if (pgraph_ctx == NULL)
+               return -ENOMEM;
+
+       *ctx_reg(pgraph_ctx, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
+
+       chan->engctx[engine] = pgraph_ctx;
+       return 0;
+}
+
+static void
+nv04_graph_context_del(struct nouveau_channel *chan, int engine)
+{
+       struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t tmp;
+       struct graph_state *pgraph_ctx = chan->engctx[engine];
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv04_graph_fifo_access(dev, false);
+
+       /* Unload the context if it's the currently active one */
+       if (nv04_graph_channel(dev) == chan)
+               nv04_graph_unload_context(dev);
+
+       nv04_graph_fifo_access(dev, true);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       /* Free the context resources */
+       kfree(pgraph_ctx);
+       chan->engctx[engine] = NULL;
+}
+
+int
+nv04_graph_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
+{
+       struct drm_device *dev = chan->dev;
+       struct nouveau_gpuobj *obj = NULL;
        int ret;
 
+       ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 1;
+       obj->class  = class;
+
+#ifdef __BIG_ENDIAN
+       nv_wo32(obj, 0x00, 0x00080000 | class);
+#else
+       nv_wo32(obj, 0x00, class);
+#endif
+       nv_wo32(obj, 0x04, 0x00000000);
+       nv_wo32(obj, 0x08, 0x00000000);
+       nv_wo32(obj, 0x0c, 0x00000000);
+
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       return ret;
+}
+
+static int
+nv04_graph_init(struct drm_device *dev, int engine)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       uint32_t tmp;
+
        nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
                        ~NV_PMC_ENABLE_PGRAPH);
        nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
                         NV_PMC_ENABLE_PGRAPH);
 
-       ret = nv04_graph_register(dev);
-       if (ret)
-               return ret;
-
        /* Enable PGRAPH interrupts */
-       nouveau_irq_register(dev, 12, nv04_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR, 0xFFFFFFFF);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
@@ -507,7 +513,7 @@ int nv04_graph_init(struct drm_device *dev)
        nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/
        nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x1231c000);
        /*1231C000 blob, 001 haiku*/
-       //*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
+       /*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
        nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x72111100);
        /*0x72111100 blob , 01 haiku*/
        /*nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/
@@ -531,10 +537,12 @@ int nv04_graph_init(struct drm_device *dev)
        return 0;
 }
 
-void nv04_graph_takedown(struct drm_device *dev)
+static int
+nv04_graph_fini(struct drm_device *dev, int engine)
 {
+       nv04_graph_unload_context(dev);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
-       nouveau_irq_unregister(dev, 12);
+       return 0;
 }
 
 void
@@ -969,13 +977,138 @@ nv04_graph_mthd_bind_chroma(struct nouveau_channel *chan,
        return 1;
 }
 
-static int
-nv04_graph_register(struct drm_device *dev)
+static struct nouveau_bitfield nv04_graph_intr[] = {
+       { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
+       {}
+};
+
+static struct nouveau_bitfield nv04_graph_nstatus[] = {
+       { NV04_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
+       { NV04_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
+       { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
+       { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT,   "PROTECTION_FAULT" },
+       {}
+};
+
+struct nouveau_bitfield nv04_graph_nsource[] = {
+       { NV03_PGRAPH_NSOURCE_NOTIFICATION,       "NOTIFICATION" },
+       { NV03_PGRAPH_NSOURCE_DATA_ERROR,         "DATA_ERROR" },
+       { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR,   "PROTECTION_ERROR" },
+       { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION,    "RANGE_EXCEPTION" },
+       { NV03_PGRAPH_NSOURCE_LIMIT_COLOR,        "LIMIT_COLOR" },
+       { NV03_PGRAPH_NSOURCE_LIMIT_ZETA,         "LIMIT_ZETA" },
+       { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD,       "ILLEGAL_MTHD" },
+       { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION,   "DMA_R_PROTECTION" },
+       { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION,   "DMA_W_PROTECTION" },
+       { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION,   "FORMAT_EXCEPTION" },
+       { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION,    "PATCH_EXCEPTION" },
+       { NV03_PGRAPH_NSOURCE_STATE_INVALID,      "STATE_INVALID" },
+       { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY,      "DOUBLE_NOTIFY" },
+       { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE,      "NOTIFY_IN_USE" },
+       { NV03_PGRAPH_NSOURCE_METHOD_CNT,         "METHOD_CNT" },
+       { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION,   "BFR_NOTIFICATION" },
+       { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
+       { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A,        "DMA_WIDTH_A" },
+       { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B,        "DMA_WIDTH_B" },
+       {}
+};
+
+static void
+nv04_graph_context_switch(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_channel *chan = NULL;
+       int chid;
 
-       if (dev_priv->engine.graph.registered)
-               return 0;
+       nouveau_wait_for_idle(dev);
+
+       /* If previous context is valid, we need to save it */
+       nv04_graph_unload_context(dev);
+
+       /* Load context for next channel */
+       chid = dev_priv->engine.fifo.channel_id(dev);
+       chan = dev_priv->channels.ptr[chid];
+       if (chan)
+               nv04_graph_load_context(chan);
+}
+
+static void
+nv04_graph_isr(struct drm_device *dev)
+{
+       u32 stat;
+
+       while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
+               u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
+               u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
+               u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
+               u32 chid = (addr & 0x0f000000) >> 24;
+               u32 subc = (addr & 0x0000e000) >> 13;
+               u32 mthd = (addr & 0x00001ffc);
+               u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
+               u32 class = nv_rd32(dev, 0x400180 + subc * 4) & 0xff;
+               u32 show = stat;
+
+               if (stat & NV_PGRAPH_INTR_NOTIFY) {
+                       if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
+                               if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
+                                       show &= ~NV_PGRAPH_INTR_NOTIFY;
+                       }
+               }
+
+               if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
+                       nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
+                       stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+                       show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+                       nv04_graph_context_switch(dev);
+               }
+
+               nv_wr32(dev, NV03_PGRAPH_INTR, stat);
+               nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
+
+               if (show && nouveau_ratelimit()) {
+                       NV_INFO(dev, "PGRAPH -");
+                       nouveau_bitfield_print(nv04_graph_intr, show);
+                       printk(" nsource:");
+                       nouveau_bitfield_print(nv04_graph_nsource, nsource);
+                       printk(" nstatus:");
+                       nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
+                       printk("\n");
+                       NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
+                                    "mthd 0x%04x data 0x%08x\n",
+                               chid, subc, class, mthd, data);
+               }
+       }
+}
+
+static void
+nv04_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nv04_graph_engine *pgraph = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 12);
+
+       NVOBJ_ENGINE_DEL(dev, GR);
+       kfree(pgraph);
+}
+
+int
+nv04_graph_create(struct drm_device *dev)
+{
+       struct nv04_graph_engine *pgraph;
+
+       pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+       if (!pgraph)
+               return -ENOMEM;
+
+       pgraph->base.destroy = nv04_graph_destroy;
+       pgraph->base.init = nv04_graph_init;
+       pgraph->base.fini = nv04_graph_fini;
+       pgraph->base.context_new = nv04_graph_context_new;
+       pgraph->base.context_del = nv04_graph_context_del;
+       pgraph->base.object_new = nv04_graph_object_new;
+
+       NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+       nouveau_irq_register(dev, 12, nv04_graph_isr);
 
        /* dvd subpicture */
        NVOBJ_CLASS(dev, 0x0038, GR);
@@ -1222,93 +1355,5 @@ nv04_graph_register(struct drm_device *dev)
        NVOBJ_CLASS(dev, 0x506e, SW);
        NVOBJ_MTHD (dev, 0x506e, 0x0150, nv04_graph_mthd_set_ref);
        NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
-       dev_priv->engine.graph.registered = true;
        return 0;
-};
-
-static struct nouveau_bitfield nv04_graph_intr[] = {
-       { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
-       {}
-};
-
-static struct nouveau_bitfield nv04_graph_nstatus[] =
-{
-       { NV04_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
-       { NV04_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
-       { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
-       { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT,   "PROTECTION_FAULT" },
-       {}
-};
-
-struct nouveau_bitfield nv04_graph_nsource[] =
-{
-       { NV03_PGRAPH_NSOURCE_NOTIFICATION,       "NOTIFICATION" },
-       { NV03_PGRAPH_NSOURCE_DATA_ERROR,         "DATA_ERROR" },
-       { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR,   "PROTECTION_ERROR" },
-       { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION,    "RANGE_EXCEPTION" },
-       { NV03_PGRAPH_NSOURCE_LIMIT_COLOR,        "LIMIT_COLOR" },
-       { NV03_PGRAPH_NSOURCE_LIMIT_ZETA,         "LIMIT_ZETA" },
-       { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD,       "ILLEGAL_MTHD" },
-       { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION,   "DMA_R_PROTECTION" },
-       { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION,   "DMA_W_PROTECTION" },
-       { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION,   "FORMAT_EXCEPTION" },
-       { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION,    "PATCH_EXCEPTION" },
-       { NV03_PGRAPH_NSOURCE_STATE_INVALID,      "STATE_INVALID" },
-       { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY,      "DOUBLE_NOTIFY" },
-       { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE,      "NOTIFY_IN_USE" },
-       { NV03_PGRAPH_NSOURCE_METHOD_CNT,         "METHOD_CNT" },
-       { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION,   "BFR_NOTIFICATION" },
-       { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
-       { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A,        "DMA_WIDTH_A" },
-       { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B,        "DMA_WIDTH_B" },
-       {}
-};
-
-static void
-nv04_graph_isr(struct drm_device *dev)
-{
-       u32 stat;
-
-       while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
-               u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
-               u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
-               u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
-               u32 chid = (addr & 0x0f000000) >> 24;
-               u32 subc = (addr & 0x0000e000) >> 13;
-               u32 mthd = (addr & 0x00001ffc);
-               u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
-               u32 class = nv_rd32(dev, 0x400180 + subc * 4) & 0xff;
-               u32 show = stat;
-
-               if (stat & NV_PGRAPH_INTR_NOTIFY) {
-                       if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
-                               if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
-                                       show &= ~NV_PGRAPH_INTR_NOTIFY;
-                       }
-               }
-
-               if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
-                       nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
-                       stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-                       show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-                       nv04_graph_context_switch(dev);
-               }
-
-               nv_wr32(dev, NV03_PGRAPH_INTR, stat);
-               nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
-
-               if (show && nouveau_ratelimit()) {
-                       NV_INFO(dev, "PGRAPH -");
-                       nouveau_bitfield_print(nv04_graph_intr, show);
-                       printk(" nsource:");
-                       nouveau_bitfield_print(nv04_graph_nsource, nsource);
-                       printk(" nstatus:");
-                       nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
-                       printk("\n");
-                       NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
-                                    "mthd 0x%04x data 0x%08x\n",
-                               chid, subc, class, mthd, data);
-               }
-       }
 }
index b8e3edb5c063f2bb2f704485e6336779848c29ac..b8611b9553131b1df7669f394586dc8e4e80abff 100644 (file)
@@ -95,6 +95,9 @@ nv04_instmem_takedown(struct drm_device *dev)
        nouveau_ramht_ref(NULL, &dev_priv->ramht, NULL);
        nouveau_gpuobj_ref(NULL, &dev_priv->ramro);
        nouveau_gpuobj_ref(NULL, &dev_priv->ramfc);
+
+       if (drm_mm_initialized(&dev_priv->ramin_heap))
+               drm_mm_takedown(&dev_priv->ramin_heap);
 }
 
 int
index 8c92edb7bbcd1833dcc2c823f230793b243e86e1..0930c6cb88e079cb6b6d2f4aaca45a55b1c0ca7d 100644 (file)
 #include "nouveau_drv.h"
 #include "nouveau_util.h"
 
-static int  nv10_graph_register(struct drm_device *);
-static void nv10_graph_isr(struct drm_device *);
-
-#define NV10_FIFO_NUMBER 32
+struct nv10_graph_engine {
+       struct nouveau_exec_engine base;
+};
 
 struct pipe_state {
        uint32_t pipe_0x0000[0x040/4];
@@ -414,9 +413,9 @@ struct graph_state {
 
 static void nv10_graph_save_pipe(struct nouveau_channel *chan)
 {
-       struct drm_device *dev = chan->dev;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
        struct pipe_state *pipe = &pgraph_ctx->pipe_state;
+       struct drm_device *dev = chan->dev;
 
        PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400);
        PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200);
@@ -432,9 +431,9 @@ static void nv10_graph_save_pipe(struct nouveau_channel *chan)
 
 static void nv10_graph_load_pipe(struct nouveau_channel *chan)
 {
-       struct drm_device *dev = chan->dev;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
        struct pipe_state *pipe = &pgraph_ctx->pipe_state;
+       struct drm_device *dev = chan->dev;
        uint32_t xfmode0, xfmode1;
        int i;
 
@@ -482,9 +481,9 @@ static void nv10_graph_load_pipe(struct nouveau_channel *chan)
 
 static void nv10_graph_create_pipe(struct nouveau_channel *chan)
 {
-       struct drm_device *dev = chan->dev;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
        struct pipe_state *fifo_pipe_state = &pgraph_ctx->pipe_state;
+       struct drm_device *dev = chan->dev;
        uint32_t *fifo_pipe_state_addr;
        int i;
 #define PIPE_INIT(addr) \
@@ -661,8 +660,6 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
                                       uint32_t inst)
 {
        struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        uint32_t st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
        uint32_t ctx_user, ctx_switch[5];
        int i, subchan = -1;
@@ -711,8 +708,8 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
                0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c);
        nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
        nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
-       pgraph->fifo_access(dev, true);
-       pgraph->fifo_access(dev, false);
+       nv04_graph_fifo_access(dev, true);
+       nv04_graph_fifo_access(dev, false);
 
        /* Restore the FIFO state */
        for (i = 0; i < ARRAY_SIZE(fifo); i++)
@@ -729,11 +726,12 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
        nv_wr32(dev, NV10_PGRAPH_CTX_USER, ctx_user);
 }
 
-int nv10_graph_load_context(struct nouveau_channel *chan)
+static int
+nv10_graph_load_context(struct nouveau_channel *chan)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
        uint32_t tmp;
        int i;
 
@@ -757,21 +755,20 @@ int nv10_graph_load_context(struct nouveau_channel *chan)
        return 0;
 }
 
-int
+static int
 nv10_graph_unload_context(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        struct nouveau_channel *chan;
        struct graph_state *ctx;
        uint32_t tmp;
        int i;
 
-       chan = pgraph->channel(dev);
+       chan = nv10_graph_channel(dev);
        if (!chan)
                return 0;
-       ctx = chan->pgraph_ctx;
+       ctx = chan->engctx[NVOBJ_ENGINE_GR];
 
        for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++)
                ctx->nv10[i] = nv_rd32(dev, nv10_graph_ctx_regs[i]);
@@ -805,7 +802,7 @@ nv10_graph_context_switch(struct drm_device *dev)
        /* Load context for next channel */
        chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
        chan = dev_priv->channels.ptr[chid];
-       if (chan && chan->pgraph_ctx)
+       if (chan && chan->engctx[NVOBJ_ENGINE_GR])
                nv10_graph_load_context(chan);
 }
 
@@ -836,7 +833,8 @@ nv10_graph_channel(struct drm_device *dev)
        return dev_priv->channels.ptr[chid];
 }
 
-int nv10_graph_create_context(struct nouveau_channel *chan)
+static int
+nv10_graph_context_new(struct nouveau_channel *chan, int engine)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -844,11 +842,10 @@ int nv10_graph_create_context(struct nouveau_channel *chan)
 
        NV_DEBUG(dev, "nv10_graph_context_create %d\n", chan->id);
 
-       chan->pgraph_ctx = pgraph_ctx = kzalloc(sizeof(*pgraph_ctx),
-                                               GFP_KERNEL);
+       pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL);
        if (pgraph_ctx == NULL)
                return -ENOMEM;
-
+       chan->engctx[engine] = pgraph_ctx;
 
        NV_WRITE_CTX(0x00400e88, 0x08000000);
        NV_WRITE_CTX(0x00400e9c, 0x4b7fffff);
@@ -873,30 +870,30 @@ int nv10_graph_create_context(struct nouveau_channel *chan)
        return 0;
 }
 
-void nv10_graph_destroy_context(struct nouveau_channel *chan)
+static void
+nv10_graph_context_del(struct nouveau_channel *chan, int engine)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+       struct graph_state *pgraph_ctx = chan->engctx[engine];
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       pgraph->fifo_access(dev, false);
+       nv04_graph_fifo_access(dev, false);
 
        /* Unload the context if it's the currently active one */
-       if (pgraph->channel(dev) == chan)
-               pgraph->unload_context(dev);
+       if (nv10_graph_channel(dev) == chan)
+               nv10_graph_unload_context(dev);
+
+       nv04_graph_fifo_access(dev, true);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
        /* Free the context resources */
+       chan->engctx[engine] = NULL;
        kfree(pgraph_ctx);
-       chan->pgraph_ctx = NULL;
-
-       pgraph->fifo_access(dev, true);
-       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 }
 
-void
+static void
 nv10_graph_set_tile_region(struct drm_device *dev, int i)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -907,22 +904,18 @@ nv10_graph_set_tile_region(struct drm_device *dev, int i)
        nv_wr32(dev, NV10_PGRAPH_TILE(i), tile->addr);
 }
 
-int nv10_graph_init(struct drm_device *dev)
+static int
+nv10_graph_init(struct drm_device *dev, int engine)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t tmp;
-       int ret, i;
+       u32 tmp;
+       int i;
 
        nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
                        ~NV_PMC_ENABLE_PGRAPH);
        nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
                         NV_PMC_ENABLE_PGRAPH);
 
-       ret = nv10_graph_register(dev);
-       if (ret)
-               return ret;
-
-       nouveau_irq_register(dev, 12, nv10_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
@@ -963,18 +956,20 @@ int nv10_graph_init(struct drm_device *dev)
        return 0;
 }
 
-void nv10_graph_takedown(struct drm_device *dev)
+static int
+nv10_graph_fini(struct drm_device *dev, int engine)
 {
+       nv10_graph_unload_context(dev);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
-       nouveau_irq_unregister(dev, 12);
+       return 0;
 }
 
 static int
 nv17_graph_mthd_lma_window(struct nouveau_channel *chan,
                           u32 class, u32 mthd, u32 data)
 {
+       struct graph_state *ctx = chan->engctx[NVOBJ_ENGINE_GR];
        struct drm_device *dev = chan->dev;
-       struct graph_state *ctx = chan->pgraph_ctx;
        struct pipe_state *pipe = &ctx->pipe_state;
        uint32_t pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
        uint32_t xfmode0, xfmode1;
@@ -1061,64 +1056,13 @@ nv17_graph_mthd_lma_enable(struct nouveau_channel *chan,
        return 0;
 }
 
-static int
-nv10_graph_register(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->engine.graph.registered)
-               return 0;
-
-       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
-       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-       NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */
-       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-       NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */
-       NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */
-       NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */
-       NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */
-
-       /* celcius */
-       if (dev_priv->chipset <= 0x10) {
-               NVOBJ_CLASS(dev, 0x0056, GR);
-       } else
-       if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) {
-               NVOBJ_CLASS(dev, 0x0096, GR);
-       } else {
-               NVOBJ_CLASS(dev, 0x0099, GR);
-               NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window);
-               NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window);
-               NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window);
-               NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window);
-               NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable);
-       }
-
-       /* nvsw */
-       NVOBJ_CLASS(dev, 0x506e, SW);
-       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
-       dev_priv->engine.graph.registered = true;
-       return 0;
-}
-
 struct nouveau_bitfield nv10_graph_intr[] = {
        { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
        { NV_PGRAPH_INTR_ERROR,  "ERROR"  },
        {}
 };
 
-struct nouveau_bitfield nv10_graph_nstatus[] =
-{
+struct nouveau_bitfield nv10_graph_nstatus[] = {
        { NV10_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
        { NV10_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
        { NV10_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
@@ -1173,3 +1117,73 @@ nv10_graph_isr(struct drm_device *dev)
                }
        }
 }
+
+static void
+nv10_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nv10_graph_engine *pgraph = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 12);
+       kfree(pgraph);
+}
+
+int
+nv10_graph_create(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nv10_graph_engine *pgraph;
+
+       pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+       if (!pgraph)
+               return -ENOMEM;
+
+       pgraph->base.destroy = nv10_graph_destroy;
+       pgraph->base.init = nv10_graph_init;
+       pgraph->base.fini = nv10_graph_fini;
+       pgraph->base.context_new = nv10_graph_context_new;
+       pgraph->base.context_del = nv10_graph_context_del;
+       pgraph->base.object_new = nv04_graph_object_new;
+       pgraph->base.set_tile_region = nv10_graph_set_tile_region;
+
+       NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+       nouveau_irq_register(dev, 12, nv10_graph_isr);
+
+       /* nvsw */
+       NVOBJ_CLASS(dev, 0x506e, SW);
+       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+
+       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+       NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */
+       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+       NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */
+       NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */
+       NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */
+       NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */
+
+       /* celcius */
+       if (dev_priv->chipset <= 0x10) {
+               NVOBJ_CLASS(dev, 0x0056, GR);
+       } else
+       if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) {
+               NVOBJ_CLASS(dev, 0x0096, GR);
+       } else {
+               NVOBJ_CLASS(dev, 0x0099, GR);
+               NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window);
+               NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window);
+               NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window);
+               NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window);
+               NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable);
+       }
+
+       return 0;
+}
index 8464b76798d5e4746af344ef260526a4b97fdee9..affc7d7dd0291d1707a6e714eb5e57294fbcc807 100644 (file)
  *
  */
 
+struct nv20_graph_engine {
+       struct nouveau_exec_engine base;
+       struct nouveau_gpuobj *ctxtab;
+       void (*grctx_init)(struct nouveau_gpuobj *);
+       u32 grctx_size;
+       u32 grctx_user;
+};
+
 #define NV20_GRCTX_SIZE (3580*4)
 #define NV25_GRCTX_SIZE (3529*4)
 #define NV2A_GRCTX_SIZE (3500*4)
 #define NV34_GRCTX_SIZE    (18140)
 #define NV35_36_GRCTX_SIZE (22396)
 
-static int nv20_graph_register(struct drm_device *);
-static int nv30_graph_register(struct drm_device *);
-static void nv20_graph_isr(struct drm_device *);
+int
+nv20_graph_unload_context(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+       struct nouveau_channel *chan;
+       struct nouveau_gpuobj *grctx;
+       u32 tmp;
+
+       chan = nv10_graph_channel(dev);
+       if (!chan)
+               return 0;
+       grctx = chan->engctx[NVOBJ_ENGINE_GR];
+
+       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, grctx->pinst >> 4);
+       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
+                    NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE);
+
+       nouveau_wait_for_idle(dev);
+
+       nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
+       tmp  = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
+       tmp |= (pfifo->channels - 1) << 24;
+       nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
+       return 0;
+}
+
+static void
+nv20_graph_rdi(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       int i, writecount = 32;
+       uint32_t rdi_index = 0x2c80000;
+
+       if (dev_priv->chipset == 0x20) {
+               rdi_index = 0x3d0000;
+               writecount = 15;
+       }
+
+       nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, rdi_index);
+       for (i = 0; i < writecount; i++)
+               nv_wr32(dev, NV10_PGRAPH_RDI_DATA, 0);
+
+       nouveau_wait_for_idle(dev);
+}
 
 static void
-nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv20_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -87,7 +137,7 @@ nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 static void
-nv25_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv25_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -146,7 +196,7 @@ nv25_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 static void
-nv2a_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv2a_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -196,7 +246,7 @@ nv2a_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 static void
-nv30_31_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv30_31_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -254,7 +304,7 @@ nv30_31_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 static void
-nv34_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv34_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -312,7 +362,7 @@ nv34_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 static void
-nv35_36_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv35_36_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -370,148 +420,57 @@ nv35_36_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 int
-nv20_graph_create_context(struct nouveau_channel *chan)
+nv20_graph_context_new(struct nouveau_channel *chan, int engine)
 {
+       struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine);
+       struct nouveau_gpuobj *grctx = NULL;
        struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *);
-       unsigned int idoffs = 0x28;
        int ret;
 
-       switch (dev_priv->chipset) {
-       case 0x20:
-               ctx_init = nv20_graph_context_init;
-               idoffs = 0;
-               break;
-       case 0x25:
-       case 0x28:
-               ctx_init = nv25_graph_context_init;
-               break;
-       case 0x2a:
-               ctx_init = nv2a_graph_context_init;
-               idoffs = 0;
-               break;
-       case 0x30:
-       case 0x31:
-               ctx_init = nv30_31_graph_context_init;
-               break;
-       case 0x34:
-               ctx_init = nv34_graph_context_init;
-               break;
-       case 0x35:
-       case 0x36:
-               ctx_init = nv35_36_graph_context_init;
-               break;
-       default:
-               BUG_ON(1);
-       }
-
-       ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
-                                NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
+       ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16,
+                                NVOBJ_FLAG_ZERO_ALLOC, &grctx);
        if (ret)
                return ret;
 
        /* Initialise default context values */
-       ctx_init(dev, chan->ramin_grctx);
+       pgraph->grctx_init(grctx);
 
        /* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */
-       nv_wo32(chan->ramin_grctx, idoffs,
-               (chan->id << 24) | 0x1); /* CTX_USER */
+       /* CTX_USER */
+       nv_wo32(grctx, pgraph->grctx_user, (chan->id << 24) | 0x1);
 
-       nv_wo32(pgraph->ctx_table, chan->id * 4, chan->ramin_grctx->pinst >> 4);
+       nv_wo32(pgraph->ctxtab, chan->id * 4, grctx->pinst >> 4);
+       chan->engctx[engine] = grctx;
        return 0;
 }
 
 void
-nv20_graph_destroy_context(struct nouveau_channel *chan)
+nv20_graph_context_del(struct nouveau_channel *chan, int engine)
 {
+       struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine);
+       struct nouveau_gpuobj *grctx = chan->engctx[engine];
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       pgraph->fifo_access(dev, false);
+       nv04_graph_fifo_access(dev, false);
 
        /* Unload the context if it's the currently active one */
-       if (pgraph->channel(dev) == chan)
-               pgraph->unload_context(dev);
+       if (nv10_graph_channel(dev) == chan)
+               nv20_graph_unload_context(dev);
 
-       pgraph->fifo_access(dev, true);
+       nv04_graph_fifo_access(dev, true);
        spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
        /* Free the context resources */
-       nv_wo32(pgraph->ctx_table, chan->id * 4, 0);
-       nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
-}
-
-int
-nv20_graph_load_context(struct nouveau_channel *chan)
-{
-       struct drm_device *dev = chan->dev;
-       uint32_t inst;
+       nv_wo32(pgraph->ctxtab, chan->id * 4, 0);
 
-       if (!chan->ramin_grctx)
-               return -EINVAL;
-       inst = chan->ramin_grctx->pinst >> 4;
-
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
-                    NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD);
-       nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
-
-       nouveau_wait_for_idle(dev);
-       return 0;
-}
-
-int
-nv20_graph_unload_context(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
-       struct nouveau_channel *chan;
-       uint32_t inst, tmp;
-
-       chan = pgraph->channel(dev);
-       if (!chan)
-               return 0;
-       inst = chan->ramin_grctx->pinst >> 4;
-
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
-                    NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE);
-
-       nouveau_wait_for_idle(dev);
-
-       nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
-       tmp  = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
-       tmp |= (pfifo->channels - 1) << 24;
-       nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
-       return 0;
+       nouveau_gpuobj_ref(NULL, &grctx);
+       chan->engctx[engine] = NULL;
 }
 
 static void
-nv20_graph_rdi(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       int i, writecount = 32;
-       uint32_t rdi_index = 0x2c80000;
-
-       if (dev_priv->chipset == 0x20) {
-               rdi_index = 0x3d0000;
-               writecount = 15;
-       }
-
-       nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, rdi_index);
-       for (i = 0; i < writecount; i++)
-               nv_wr32(dev, NV10_PGRAPH_RDI_DATA, 0);
-
-       nouveau_wait_for_idle(dev);
-}
-
-void
 nv20_graph_set_tile_region(struct drm_device *dev, int i)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -536,56 +495,22 @@ nv20_graph_set_tile_region(struct drm_device *dev, int i)
 }
 
 int
-nv20_graph_init(struct drm_device *dev)
+nv20_graph_init(struct drm_device *dev, int engine)
 {
+       struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        uint32_t tmp, vramsz;
-       int ret, i;
-
-       switch (dev_priv->chipset) {
-       case 0x20:
-               pgraph->grctx_size = NV20_GRCTX_SIZE;
-               break;
-       case 0x25:
-       case 0x28:
-               pgraph->grctx_size = NV25_GRCTX_SIZE;
-               break;
-       case 0x2a:
-               pgraph->grctx_size = NV2A_GRCTX_SIZE;
-               break;
-       default:
-               NV_ERROR(dev, "unknown chipset, disabling acceleration\n");
-               pgraph->accel_blocked = true;
-               return 0;
-       }
+       int i;
 
        nv_wr32(dev, NV03_PMC_ENABLE,
                nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
        nv_wr32(dev, NV03_PMC_ENABLE,
                nv_rd32(dev, NV03_PMC_ENABLE) |  NV_PMC_ENABLE_PGRAPH);
 
-       if (!pgraph->ctx_table) {
-               /* Create Context Pointer Table */
-               ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
-                                        NVOBJ_FLAG_ZERO_ALLOC,
-                                        &pgraph->ctx_table);
-               if (ret)
-                       return ret;
-       }
-
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
-                    pgraph->ctx_table->pinst >> 4);
+       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->pinst >> 4);
 
        nv20_graph_rdi(dev);
 
-       ret = nv20_graph_register(dev);
-       if (ret) {
-               nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
-               return ret;
-       }
-
-       nouveau_irq_register(dev, 12, nv20_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
@@ -657,67 +582,20 @@ nv20_graph_init(struct drm_device *dev)
        return 0;
 }
 
-void
-nv20_graph_takedown(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-
-       nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
-       nouveau_irq_unregister(dev, 12);
-
-       nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
-}
-
 int
-nv30_graph_init(struct drm_device *dev)
+nv30_graph_init(struct drm_device *dev, int engine)
 {
+       struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       int ret, i;
-
-       switch (dev_priv->chipset) {
-       case 0x30:
-       case 0x31:
-               pgraph->grctx_size = NV30_31_GRCTX_SIZE;
-               break;
-       case 0x34:
-               pgraph->grctx_size = NV34_GRCTX_SIZE;
-               break;
-       case 0x35:
-       case 0x36:
-               pgraph->grctx_size = NV35_36_GRCTX_SIZE;
-               break;
-       default:
-               NV_ERROR(dev, "unknown chipset, disabling acceleration\n");
-               pgraph->accel_blocked = true;
-               return 0;
-       }
+       int i;
 
        nv_wr32(dev, NV03_PMC_ENABLE,
                nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
        nv_wr32(dev, NV03_PMC_ENABLE,
                nv_rd32(dev, NV03_PMC_ENABLE) |  NV_PMC_ENABLE_PGRAPH);
 
-       if (!pgraph->ctx_table) {
-               /* Create Context Pointer Table */
-               ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
-                                        NVOBJ_FLAG_ZERO_ALLOC,
-                                        &pgraph->ctx_table);
-               if (ret)
-                       return ret;
-       }
-
-       ret = nv30_graph_register(dev);
-       if (ret) {
-               nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
-               return ret;
-       }
+       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->pinst >> 4);
 
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
-                    pgraph->ctx_table->pinst >> 4);
-
-       nouveau_irq_register(dev, 12, nv20_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
@@ -775,85 +653,11 @@ nv30_graph_init(struct drm_device *dev)
        return 0;
 }
 
-static int
-nv20_graph_register(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->engine.graph.registered)
-               return 0;
-
-       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
-       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-       NVOBJ_CLASS(dev, 0x009e, GR); /* swzsurf */
-       NVOBJ_CLASS(dev, 0x0096, GR); /* celcius */
-
-       /* kelvin */
-       if (dev_priv->chipset < 0x25)
-               NVOBJ_CLASS(dev, 0x0097, GR);
-       else
-               NVOBJ_CLASS(dev, 0x0597, GR);
-
-       /* nvsw */
-       NVOBJ_CLASS(dev, 0x506e, SW);
-       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
-       dev_priv->engine.graph.registered = true;
-       return 0;
-}
-
-static int
-nv30_graph_register(struct drm_device *dev)
+int
+nv20_graph_fini(struct drm_device *dev, int engine)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->engine.graph.registered)
-               return 0;
-
-       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
-       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-       NVOBJ_CLASS(dev, 0x038a, GR); /* ifc (nv30) */
-       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-       NVOBJ_CLASS(dev, 0x0389, GR); /* sifm (nv30) */
-       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-       NVOBJ_CLASS(dev, 0x0362, GR); /* surf2d (nv30) */
-       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-       NVOBJ_CLASS(dev, 0x039e, GR); /* swzsurf */
-
-       /* rankine */
-       if (0x00000003 & (1 << (dev_priv->chipset & 0x0f)))
-               NVOBJ_CLASS(dev, 0x0397, GR);
-       else
-       if (0x00000010 & (1 << (dev_priv->chipset & 0x0f)))
-               NVOBJ_CLASS(dev, 0x0697, GR);
-       else
-       if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f)))
-               NVOBJ_CLASS(dev, 0x0497, GR);
-
-       /* nvsw */
-       NVOBJ_CLASS(dev, 0x506e, SW);
-       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
-       dev_priv->engine.graph.registered = true;
+       nv20_graph_unload_context(dev);
+       nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
        return 0;
 }
 
@@ -897,3 +701,135 @@ nv20_graph_isr(struct drm_device *dev)
                }
        }
 }
+
+static void
+nv20_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 12);
+       nouveau_gpuobj_ref(NULL, &pgraph->ctxtab);
+
+       NVOBJ_ENGINE_DEL(dev, GR);
+       kfree(pgraph);
+}
+
+int
+nv20_graph_create(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nv20_graph_engine *pgraph;
+       int ret;
+
+       pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+       if (!pgraph)
+               return -ENOMEM;
+
+       pgraph->base.destroy = nv20_graph_destroy;
+       pgraph->base.fini = nv20_graph_fini;
+       pgraph->base.context_new = nv20_graph_context_new;
+       pgraph->base.context_del = nv20_graph_context_del;
+       pgraph->base.object_new = nv04_graph_object_new;
+       pgraph->base.set_tile_region = nv20_graph_set_tile_region;
+
+       pgraph->grctx_user = 0x0028;
+       if (dev_priv->card_type == NV_20) {
+               pgraph->base.init = nv20_graph_init;
+               switch (dev_priv->chipset) {
+               case 0x20:
+                       pgraph->grctx_init = nv20_graph_context_init;
+                       pgraph->grctx_size = NV20_GRCTX_SIZE;
+                       pgraph->grctx_user = 0x0000;
+                       break;
+               case 0x25:
+               case 0x28:
+                       pgraph->grctx_init = nv25_graph_context_init;
+                       pgraph->grctx_size = NV25_GRCTX_SIZE;
+                       break;
+               case 0x2a:
+                       pgraph->grctx_init = nv2a_graph_context_init;
+                       pgraph->grctx_size = NV2A_GRCTX_SIZE;
+                       pgraph->grctx_user = 0x0000;
+                       break;
+               default:
+                       NV_ERROR(dev, "PGRAPH: unknown chipset\n");
+                       return 0;
+               }
+       } else {
+               pgraph->base.init = nv30_graph_init;
+               switch (dev_priv->chipset) {
+               case 0x30:
+               case 0x31:
+                       pgraph->grctx_init = nv30_31_graph_context_init;
+                       pgraph->grctx_size = NV30_31_GRCTX_SIZE;
+                       break;
+               case 0x34:
+                       pgraph->grctx_init = nv34_graph_context_init;
+                       pgraph->grctx_size = NV34_GRCTX_SIZE;
+                       break;
+               case 0x35:
+               case 0x36:
+                       pgraph->grctx_init = nv35_36_graph_context_init;
+                       pgraph->grctx_size = NV35_36_GRCTX_SIZE;
+                       break;
+               default:
+                       NV_ERROR(dev, "PGRAPH: unknown chipset\n");
+                       return 0;
+               }
+       }
+
+       /* Create Context Pointer Table */
+       ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC,
+                                &pgraph->ctxtab);
+       if (ret) {
+               kfree(pgraph);
+               return ret;
+       }
+
+       NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+       nouveau_irq_register(dev, 12, nv20_graph_isr);
+
+       /* nvsw */
+       NVOBJ_CLASS(dev, 0x506e, SW);
+       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+
+       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+       if (dev_priv->card_type == NV_20) {
+               NVOBJ_CLASS(dev, 0x009e, GR); /* swzsurf */
+               NVOBJ_CLASS(dev, 0x0096, GR); /* celcius */
+
+               /* kelvin */
+               if (dev_priv->chipset < 0x25)
+                       NVOBJ_CLASS(dev, 0x0097, GR);
+               else
+                       NVOBJ_CLASS(dev, 0x0597, GR);
+       } else {
+               NVOBJ_CLASS(dev, 0x038a, GR); /* ifc (nv30) */
+               NVOBJ_CLASS(dev, 0x0389, GR); /* sifm (nv30) */
+               NVOBJ_CLASS(dev, 0x0362, GR); /* surf2d (nv30) */
+               NVOBJ_CLASS(dev, 0x039e, GR); /* swzsurf */
+
+               /* rankine */
+               if (0x00000003 & (1 << (dev_priv->chipset & 0x0f)))
+                       NVOBJ_CLASS(dev, 0x0397, GR);
+               else
+               if (0x00000010 & (1 << (dev_priv->chipset & 0x0f)))
+                       NVOBJ_CLASS(dev, 0x0697, GR);
+               else
+               if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f)))
+                       NVOBJ_CLASS(dev, 0x0497, GR);
+       }
+
+       return 0;
+}
index 49b9a35a9cd6c79857fab54e69590f3e046cac53..68cb2d991c88c5c865062ed9bc5d88f14c242357 100644 (file)
@@ -115,6 +115,7 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid)
        nv_wr32(dev, 0x32e8, nv_ri32(dev, fc + 68));
        nv_wr32(dev, 0x2088, nv_ri32(dev, fc + 76));
        nv_wr32(dev, 0x3300, nv_ri32(dev, fc + 80));
+       nv_wr32(dev, 0x330c, nv_ri32(dev, fc + 84));
 
        nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
        nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
@@ -186,6 +187,7 @@ nv40_fifo_unload_context(struct drm_device *dev)
        tmp |= (nv_rd32(dev, NV04_PFIFO_CACHE1_PUT) << 16);
        nv_wi32(dev, fc + 72, tmp);
 #endif
+       nv_wi32(dev, fc + 84, nv_rd32(dev, 0x330c));
 
        nv40_fifo_do_load_context(dev, pfifo->channels - 1);
        nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1,
index fceb44c0ec748d2f1499dc6255983339c675c830..5beb01b8ace1387bd04639a7b49be90d28bd4d9f 100644 (file)
 #include "drm.h"
 #include "nouveau_drv.h"
 #include "nouveau_grctx.h"
+#include "nouveau_ramht.h"
 
-static int nv40_graph_register(struct drm_device *);
-static void nv40_graph_isr(struct drm_device *);
+struct nv40_graph_engine {
+       struct nouveau_exec_engine base;
+       u32 grctx_size;
+};
 
-struct nouveau_channel *
+static struct nouveau_channel *
 nv40_graph_channel(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *grctx;
        uint32_t inst;
        int i;
 
@@ -45,74 +49,17 @@ nv40_graph_channel(struct drm_device *dev)
        inst = (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) << 4;
 
        for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
-               struct nouveau_channel *chan = dev_priv->channels.ptr[i];
+               if (!dev_priv->channels.ptr[i])
+                       continue;
 
-               if (chan && chan->ramin_grctx &&
-                   chan->ramin_grctx->pinst == inst)
-                       return chan;
+               grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
+               if (grctx && grctx->pinst == inst)
+                       return dev_priv->channels.ptr[i];
        }
 
        return NULL;
 }
 
-int
-nv40_graph_create_context(struct nouveau_channel *chan)
-{
-       struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_grctx ctx = {};
-       unsigned long flags;
-       int ret;
-
-       ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
-                                NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
-       if (ret)
-               return ret;
-
-       /* Initialise default context values */
-       ctx.dev = chan->dev;
-       ctx.mode = NOUVEAU_GRCTX_VALS;
-       ctx.data = chan->ramin_grctx;
-       nv40_grctx_init(&ctx);
-
-       nv_wo32(chan->ramin_grctx, 0, chan->ramin_grctx->pinst);
-
-       /* init grctx pointer in ramfc, and on PFIFO if channel is
-        * already active there
-        */
-       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       nv_wo32(chan->ramfc, 0x38, chan->ramin_grctx->pinst >> 4);
-       nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
-       if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id)
-               nv_wr32(dev, 0x0032e0, chan->ramin_grctx->pinst >> 4);
-       nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
-       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-       return 0;
-}
-
-void
-nv40_graph_destroy_context(struct nouveau_channel *chan)
-{
-       struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       pgraph->fifo_access(dev, false);
-
-       /* Unload the context if it's the currently active one */
-       if (pgraph->channel(dev) == chan)
-               pgraph->unload_context(dev);
-
-       pgraph->fifo_access(dev, true);
-       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-       /* Free the context resources */
-       nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
-}
-
 static int
 nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save)
 {
@@ -154,57 +101,115 @@ nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save)
        return 0;
 }
 
-/* Restore the context for a specific channel into PGRAPH */
-int
-nv40_graph_load_context(struct nouveau_channel *chan)
+static int
+nv40_graph_unload_context(struct drm_device *dev)
 {
-       struct drm_device *dev = chan->dev;
        uint32_t inst;
        int ret;
 
-       if (!chan->ramin_grctx)
-               return -EINVAL;
-       inst = chan->ramin_grctx->pinst >> 4;
+       inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
+       if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
+               return 0;
+       inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE;
+
+       ret = nv40_graph_transfer_context(dev, inst, 1);
+
+       nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst);
+       return ret;
+}
+
+static int
+nv40_graph_context_new(struct nouveau_channel *chan, int engine)
+{
+       struct nv40_graph_engine *pgraph = nv_engine(chan->dev, engine);
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *grctx = NULL;
+       struct nouveau_grctx ctx = {};
+       unsigned long flags;
+       int ret;
 
-       ret = nv40_graph_transfer_context(dev, inst, 0);
+       ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16,
+                                NVOBJ_FLAG_ZERO_ALLOC, &grctx);
        if (ret)
                return ret;
 
-       /* 0x40032C, no idea of it's exact function.  Could simply be a
-        * record of the currently active PGRAPH context.  It's currently
-        * unknown as to what bit 24 does.  The nv ddx has it set, so we will
-        * set it here too.
-        */
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
-       nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR,
-                (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) |
-                 NV40_PGRAPH_CTXCTL_CUR_LOADED);
-       /* 0x32E0 records the instance address of the active FIFO's PGRAPH
-        * context.  If at any time this doesn't match 0x40032C, you will
-        * receive PGRAPH_INTR_CONTEXT_SWITCH
+       /* Initialise default context values */
+       ctx.dev = chan->dev;
+       ctx.mode = NOUVEAU_GRCTX_VALS;
+       ctx.data = grctx;
+       nv40_grctx_init(&ctx);
+
+       nv_wo32(grctx, 0, grctx->vinst);
+
+       /* init grctx pointer in ramfc, and on PFIFO if channel is
+        * already active there
         */
-       nv_wr32(dev, NV40_PFIFO_GRCTX_INSTANCE, inst);
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv_wo32(chan->ramfc, 0x38, grctx->vinst >> 4);
+       nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
+       if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id)
+               nv_wr32(dev, 0x0032e0, grctx->vinst >> 4);
+       nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       chan->engctx[engine] = grctx;
        return 0;
 }
 
-int
-nv40_graph_unload_context(struct drm_device *dev)
+static void
+nv40_graph_context_del(struct nouveau_channel *chan, int engine)
 {
-       uint32_t inst;
-       int ret;
+       struct nouveau_gpuobj *grctx = chan->engctx[engine];
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       unsigned long flags;
 
-       inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
-       if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
-               return 0;
-       inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE;
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv04_graph_fifo_access(dev, false);
 
-       ret = nv40_graph_transfer_context(dev, inst, 1);
+       /* Unload the context if it's the currently active one */
+       if (nv40_graph_channel(dev) == chan)
+               nv40_graph_unload_context(dev);
 
-       nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst);
+       nv04_graph_fifo_access(dev, true);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       /* Free the context resources */
+       nouveau_gpuobj_ref(NULL, &grctx);
+       chan->engctx[engine] = NULL;
+}
+
+int
+nv40_graph_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
+{
+       struct drm_device *dev = chan->dev;
+       struct nouveau_gpuobj *obj = NULL;
+       int ret;
+
+       ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 1;
+       obj->class  = class;
+
+       nv_wo32(obj, 0x00, class);
+       nv_wo32(obj, 0x04, 0x00000000);
+#ifndef __BIG_ENDIAN
+       nv_wo32(obj, 0x08, 0x00000000);
+#else
+       nv_wo32(obj, 0x08, 0x01000000);
+#endif
+       nv_wo32(obj, 0x0c, 0x00000000);
+       nv_wo32(obj, 0x10, 0x00000000);
+
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
        return ret;
 }
 
-void
+static void
 nv40_graph_set_tile_region(struct drm_device *dev, int i)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -257,14 +262,14 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i)
  * C51         0x4e
  */
 int
-nv40_graph_init(struct drm_device *dev)
+nv40_graph_init(struct drm_device *dev, int engine)
 {
-       struct drm_nouveau_private *dev_priv =
-               (struct drm_nouveau_private *)dev->dev_private;
+       struct nv40_graph_engine *pgraph = nv_engine(dev, engine);
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
        struct nouveau_grctx ctx = {};
        uint32_t vramsz, *cp;
-       int ret, i, j;
+       int i, j;
 
        nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
                        ~NV_PMC_ENABLE_PGRAPH);
@@ -280,7 +285,7 @@ nv40_graph_init(struct drm_device *dev)
        ctx.data = cp;
        ctx.ctxprog_max = 256;
        nv40_grctx_init(&ctx);
-       dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
+       pgraph->grctx_size = ctx.ctxvals_pos * 4;
 
        nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
        for (i = 0; i < ctx.ctxprog_len; i++)
@@ -288,14 +293,9 @@ nv40_graph_init(struct drm_device *dev)
 
        kfree(cp);
 
-       ret = nv40_graph_register(dev);
-       if (ret)
-               return ret;
-
        /* No context present currently */
        nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
 
-       nouveau_irq_register(dev, 12, nv40_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
        nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
@@ -428,47 +428,10 @@ nv40_graph_init(struct drm_device *dev)
        return 0;
 }
 
-void nv40_graph_takedown(struct drm_device *dev)
-{
-       nouveau_irq_unregister(dev, 12);
-}
-
 static int
-nv40_graph_register(struct drm_device *dev)
+nv40_graph_fini(struct drm_device *dev, int engine)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->engine.graph.registered)
-               return 0;
-
-       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
-       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-       NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */
-       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-       NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */
-       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-       NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */
-
-       /* curie */
-       if (nv44_graph_class(dev))
-               NVOBJ_CLASS(dev, 0x4497, GR);
-       else
-               NVOBJ_CLASS(dev, 0x4097, GR);
-
-       /* nvsw */
-       NVOBJ_CLASS(dev, 0x506e, SW);
-       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
-       dev_priv->engine.graph.registered = true;
+       nv40_graph_unload_context(dev);
        return 0;
 }
 
@@ -476,17 +439,17 @@ static int
 nv40_graph_isr_chid(struct drm_device *dev, u32 inst)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_channel *chan;
+       struct nouveau_gpuobj *grctx;
        unsigned long flags;
        int i;
 
        spin_lock_irqsave(&dev_priv->channels.lock, flags);
        for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
-               chan = dev_priv->channels.ptr[i];
-               if (!chan || !chan->ramin_grctx)
+               if (!dev_priv->channels.ptr[i])
                        continue;
+               grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
 
-               if (inst == chan->ramin_grctx->pinst)
+               if (grctx && grctx->pinst == inst)
                        break;
        }
        spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
@@ -537,3 +500,63 @@ nv40_graph_isr(struct drm_device *dev)
                }
        }
 }
+
+static void
+nv40_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nv40_graph_engine *pgraph = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 12);
+
+       NVOBJ_ENGINE_DEL(dev, GR);
+       kfree(pgraph);
+}
+
+int
+nv40_graph_create(struct drm_device *dev)
+{
+       struct nv40_graph_engine *pgraph;
+
+       pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+       if (!pgraph)
+               return -ENOMEM;
+
+       pgraph->base.destroy = nv40_graph_destroy;
+       pgraph->base.init = nv40_graph_init;
+       pgraph->base.fini = nv40_graph_fini;
+       pgraph->base.context_new = nv40_graph_context_new;
+       pgraph->base.context_del = nv40_graph_context_del;
+       pgraph->base.object_new = nv40_graph_object_new;
+       pgraph->base.set_tile_region = nv40_graph_set_tile_region;
+
+       NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+       nouveau_irq_register(dev, 12, nv40_graph_isr);
+
+       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
+       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+       NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */
+       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+       NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */
+       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+       NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */
+
+       /* curie */
+       if (nv44_graph_class(dev))
+               NVOBJ_CLASS(dev, 0x4497, GR);
+       else
+               NVOBJ_CLASS(dev, 0x4097, GR);
+
+       /* nvsw */
+       NVOBJ_CLASS(dev, 0x506e, SW);
+       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv40_mpeg.c b/drivers/gpu/drm/nouveau/nv40_mpeg.c
new file mode 100644 (file)
index 0000000..6d2af29
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
+
+struct nv40_mpeg_engine {
+       struct nouveau_exec_engine base;
+};
+
+static int
+nv40_mpeg_context_new(struct nouveau_channel *chan, int engine)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *ctx = NULL;
+       unsigned long flags;
+       int ret;
+
+       NV_DEBUG(dev, "ch%d\n", chan->id);
+
+       ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC |
+                                NVOBJ_FLAG_ZERO_FREE, &ctx);
+       if (ret)
+               return ret;
+
+       nv_wo32(ctx, 0x78, 0x02001ec1);
+
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
+       if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id)
+               nv_wr32(dev, 0x00330c, ctx->pinst >> 4);
+       nv_wo32(chan->ramfc, 0x54, ctx->pinst >> 4);
+       nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       chan->engctx[engine] = ctx;
+       return 0;
+}
+
+static void
+nv40_mpeg_context_del(struct nouveau_channel *chan, int engine)
+{
+       struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
+       struct drm_device *dev = chan->dev;
+       unsigned long flags;
+       u32 inst = 0x80000000 | (ctx->pinst >> 4);
+
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+       if (nv_rd32(dev, 0x00b318) == inst)
+               nv_mask(dev, 0x00b318, 0x80000000, 0x00000000);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       nouveau_gpuobj_ref(NULL, &ctx);
+       chan->engctx[engine] = NULL;
+}
+
+static int
+nv40_mpeg_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
+{
+       struct drm_device *dev = chan->dev;
+       struct nouveau_gpuobj *obj = NULL;
+       int ret;
+
+       ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC |
+                                NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 2;
+       obj->class  = class;
+
+       nv_wo32(obj, 0x00, class);
+
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       return ret;
+}
+
+static int
+nv40_mpeg_init(struct drm_device *dev, int engine)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine);
+       int i;
+
+       /* VPE init */
+       nv_mask(dev, 0x000200, 0x00000002, 0x00000000);
+       nv_mask(dev, 0x000200, 0x00000002, 0x00000002);
+       nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+       nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+
+       for (i = 0; i < dev_priv->engine.fb.num_tiles; i++)
+               pmpeg->base.set_tile_region(dev, i);
+
+       /* PMPEG init */
+       nv_wr32(dev, 0x00b32c, 0x00000000);
+       nv_wr32(dev, 0x00b314, 0x00000100);
+       nv_wr32(dev, 0x00b220, 0x00000044);
+       nv_wr32(dev, 0x00b300, 0x02001ec1);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+
+       nv_wr32(dev, 0x00b100, 0xffffffff);
+       nv_wr32(dev, 0x00b140, 0xffffffff);
+
+       if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) {
+               NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200));
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int
+nv40_mpeg_fini(struct drm_device *dev, int engine)
+{
+       /*XXX: context save? */
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+       nv_wr32(dev, 0x00b140, 0x00000000);
+       return 0;
+}
+
+static int
+nv40_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
+{
+       struct drm_device *dev = chan->dev;
+       u32 inst = data << 4;
+       u32 dma0 = nv_ri32(dev, inst + 0);
+       u32 dma1 = nv_ri32(dev, inst + 4);
+       u32 dma2 = nv_ri32(dev, inst + 8);
+       u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
+       u32 size = dma1 + 1;
+
+       /* only allow linear DMA objects */
+       if (!(dma0 & 0x00002000))
+               return -EINVAL;
+
+       if (mthd == 0x0190) {
+               /* DMA_CMD */
+               nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000));
+               nv_wr32(dev, 0x00b334, base);
+               nv_wr32(dev, 0x00b324, size);
+       } else
+       if (mthd == 0x01a0) {
+               /* DMA_DATA */
+               nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2);
+               nv_wr32(dev, 0x00b360, base);
+               nv_wr32(dev, 0x00b364, size);
+       } else {
+               /* DMA_IMAGE, VRAM only */
+               if (dma0 & 0x000c0000)
+                       return -EINVAL;
+
+               nv_wr32(dev, 0x00b370, base);
+               nv_wr32(dev, 0x00b374, size);
+       }
+
+       return 0;
+}
+
+static int
+nv40_mpeg_isr_chid(struct drm_device *dev, u32 inst)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *ctx;
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&dev_priv->channels.lock, flags);
+       for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+               if (!dev_priv->channels.ptr[i])
+                       continue;
+
+               ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG];
+               if (ctx && ctx->pinst == inst)
+                       break;
+       }
+       spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+       return i;
+}
+
+static void
+nv40_vpe_set_tile_region(struct drm_device *dev, int i)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+
+       nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch);
+       nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit);
+       nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr);
+}
+
+static void
+nv40_mpeg_isr(struct drm_device *dev)
+{
+       u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4;
+       u32 chid = nv40_mpeg_isr_chid(dev, inst);
+       u32 stat = nv_rd32(dev, 0x00b100);
+       u32 type = nv_rd32(dev, 0x00b230);
+       u32 mthd = nv_rd32(dev, 0x00b234);
+       u32 data = nv_rd32(dev, 0x00b238);
+       u32 show = stat;
+
+       if (stat & 0x01000000) {
+               /* happens on initial binding of the object */
+               if (type == 0x00000020 && mthd == 0x0000) {
+                       nv_mask(dev, 0x00b308, 0x00000000, 0x00000000);
+                       show &= ~0x01000000;
+               }
+
+               if (type == 0x00000010) {
+                       if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data))
+                               show &= ~0x01000000;
+               }
+       }
+
+       nv_wr32(dev, 0x00b100, stat);
+       nv_wr32(dev, 0x00b230, 0x00000001);
+
+       if (show && nouveau_ratelimit()) {
+               NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                       chid, inst, stat, type, mthd, data);
+       }
+}
+
+static void
+nv40_vpe_isr(struct drm_device *dev)
+{
+       if (nv_rd32(dev, 0x00b100))
+               nv40_mpeg_isr(dev);
+
+       if (nv_rd32(dev, 0x00b800)) {
+               u32 stat = nv_rd32(dev, 0x00b800);
+               NV_INFO(dev, "PMSRCH: 0x%08x\n", stat);
+               nv_wr32(dev, 0xb800, stat);
+       }
+}
+
+static void
+nv40_mpeg_destroy(struct drm_device *dev, int engine)
+{
+       struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 0);
+
+       NVOBJ_ENGINE_DEL(dev, MPEG);
+       kfree(pmpeg);
+}
+
+int
+nv40_mpeg_create(struct drm_device *dev)
+{
+       struct nv40_mpeg_engine *pmpeg;
+
+       pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL);
+       if (!pmpeg)
+               return -ENOMEM;
+
+       pmpeg->base.destroy = nv40_mpeg_destroy;
+       pmpeg->base.init = nv40_mpeg_init;
+       pmpeg->base.fini = nv40_mpeg_fini;
+       pmpeg->base.context_new = nv40_mpeg_context_new;
+       pmpeg->base.context_del = nv40_mpeg_context_del;
+       pmpeg->base.object_new = nv40_mpeg_object_new;
+
+       /* ISR vector, PMC_ENABLE bit,  and TILE regs are shared between
+        * all VPE engines, for this driver's purposes the PMPEG engine
+        * will be treated as the "master" and handle the global VPE
+        * bits too
+        */
+       pmpeg->base.set_tile_region = nv40_vpe_set_tile_region;
+       nouveau_irq_register(dev, 0, nv40_vpe_isr);
+
+       NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
+       NVOBJ_CLASS(dev, 0x3174, MPEG);
+       NVOBJ_MTHD (dev, 0x3174, 0x0190, nv40_mpeg_mthd_dma);
+       NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv40_mpeg_mthd_dma);
+       NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv40_mpeg_mthd_dma);
+
+#if 0
+       NVOBJ_ENGINE_ADD(dev, ME, &pme->base);
+       NVOBJ_CLASS(dev, 0x4075, ME);
+#endif
+       return 0;
+
+}
index de81151648f831c5a7c97b9491d3670c356276f5..8cf63a8b30cdb96198e8b8be469e48e2c42604a4 100644 (file)
@@ -23,7 +23,6 @@
  */
 
 #include "drmP.h"
-#include "drm_fixed.h"
 #include "nouveau_drv.h"
 #include "nouveau_hw.h"
 
@@ -47,45 +46,52 @@ nv50_calc_pll(struct drm_device *dev, struct pll_lims *pll, int clk,
 }
 
 int
-nv50_calc_pll2(struct drm_device *dev, struct pll_lims *pll, int clk,
-              int *N, int *fN, int *M, int *P)
+nva3_calc_pll(struct drm_device *dev, struct pll_lims *pll, int clk,
+             int *pN, int *pfN, int *pM, int *P)
 {
-       fixed20_12 fb_div, a, b;
-       u32 refclk = pll->refclk / 10;
-       u32 max_vco_freq = pll->vco1.maxfreq / 10;
-       u32 max_vco_inputfreq = pll->vco1.max_inputfreq / 10;
-       clk /= 10;
+       u32 best_err = ~0, err;
+       int M, lM, hM, N, fN;
 
-       *P = max_vco_freq / clk;
+       *P = pll->vco1.maxfreq / clk;
        if (*P > pll->max_p)
                *P = pll->max_p;
        if (*P < pll->min_p)
                *P = pll->min_p;
 
-       /* *M = floor((refclk + max_vco_inputfreq) / max_vco_inputfreq); */
-       a.full = dfixed_const(refclk + max_vco_inputfreq);
-       b.full = dfixed_const(max_vco_inputfreq);
-       a.full = dfixed_div(a, b);
-       a.full = dfixed_floor(a);
-       *M = dfixed_trunc(a);
+       lM = (pll->refclk + pll->vco1.max_inputfreq) / pll->vco1.max_inputfreq;
+       lM = max(lM, (int)pll->vco1.min_m);
+       hM = (pll->refclk + pll->vco1.min_inputfreq) / pll->vco1.min_inputfreq;
+       hM = min(hM, (int)pll->vco1.max_m);
 
-       /* fb_div = (vco * *M) / refclk; */
-       fb_div.full = dfixed_const(clk * *P);
-       fb_div.full = dfixed_mul(fb_div, a);
-       a.full = dfixed_const(refclk);
-       fb_div.full = dfixed_div(fb_div, a);
+       for (M = lM; M <= hM; M++) {
+               u32 tmp = clk * *P * M;
+               N  = tmp / pll->refclk;
+               fN = tmp % pll->refclk;
+               if (!pfN && fN >= pll->refclk / 2)
+                       N++;
 
-       /* *N = floor(fb_div); */
-       a.full = dfixed_floor(fb_div);
-       *N = dfixed_trunc(fb_div);
+               if (N < pll->vco1.min_n)
+                       continue;
+               if (N > pll->vco1.max_n)
+                       break;
 
-       /* *fN = (fmod(fb_div, 1.0) * 8192) - 4096; */
-       b.full = dfixed_const(8192);
-       a.full = dfixed_mul(a, b);
-       fb_div.full = dfixed_mul(fb_div, b);
-       fb_div.full = fb_div.full - a.full;
-       *fN = dfixed_trunc(fb_div) - 4096;
-       *fN &= 0xffff;
+               err = abs(clk - (pll->refclk * N / M / *P));
+               if (err < best_err) {
+                       best_err = err;
+                       *pN = N;
+                       *pM = M;
+               }
 
-       return clk;
+               if (pfN) {
+                       *pfN = (((fN << 13) / pll->refclk) - 4096) & 0xffff;
+                       return clk;
+               }
+       }
+
+       if (unlikely(best_err == ~0)) {
+               NV_ERROR(dev, "unable to find matching pll values\n");
+               return -EINVAL;
+       }
+
+       return pll->refclk * *pN / *pM / *P;
 }
index a19ccaa025b389508f604f72a10a060d338a32ee..ebabacf38da9ff02ae5f2f0f2503e1ffb3fd0ce5 100644 (file)
@@ -286,7 +286,7 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
                nv_wr32(dev, pll.reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
        } else
        if (dev_priv->chipset < NV_C0) {
-               ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
+               ret = nva3_calc_pll(dev, &pll, pclk, &N1, &N2, &M1, &P);
                if (ret <= 0)
                        return 0;
 
@@ -298,7 +298,7 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
                nv_wr32(dev, pll.reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
                nv_wr32(dev, pll.reg + 8, N2);
        } else {
-               ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
+               ret = nva3_calc_pll(dev, &pll, pclk, &N1, &N2, &M1, &P);
                if (ret <= 0)
                        return 0;
 
@@ -349,14 +349,14 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
        struct drm_gem_object *gem;
        int ret = 0, i;
 
-       if (width != 64 || height != 64)
-               return -EINVAL;
-
        if (!buffer_handle) {
                nv_crtc->cursor.hide(nv_crtc, true);
                return 0;
        }
 
+       if (width != 64 || height != 64)
+               return -EINVAL;
+
        gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
        if (!gem)
                return -ENOENT;
@@ -532,8 +532,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
        if (atomic) {
                drm_fb = passed_fb;
                fb = nouveau_framebuffer(passed_fb);
-       }
-       else {
+       } else {
                /* If not atomic, we can go ahead and pin, and unpin the
                 * old fb we were passed.
                 */
index 75a376cc342a54e4201c978bf8d7a08de21ccd0d..08da478ba544e312ab72b4b23b1db23607a433e5 100644 (file)
@@ -409,7 +409,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        struct nouveau_channel *evo = dispc->sync;
        int ret;
 
-       ret = RING_SPACE(evo, 24);
+       ret = RING_SPACE(evo, chan ? 25 : 27);
        if (unlikely(ret))
                return ret;
 
@@ -458,8 +458,19 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        /* queue the flip on the crtc's "display sync" channel */
        BEGIN_RING(evo, 0, 0x0100, 1);
        OUT_RING  (evo, 0xfffe0000);
-       BEGIN_RING(evo, 0, 0x0084, 5);
-       OUT_RING  (evo, chan ? 0x00000100 : 0x00000010);
+       if (chan) {
+               BEGIN_RING(evo, 0, 0x0084, 1);
+               OUT_RING  (evo, 0x00000100);
+       } else {
+               BEGIN_RING(evo, 0, 0x0084, 1);
+               OUT_RING  (evo, 0x00000010);
+               /* allows gamma somehow, PDISP will bitch at you if
+                * you don't wait for vblank before changing this..
+                */
+               BEGIN_RING(evo, 0, 0x00e0, 1);
+               OUT_RING  (evo, 0x40000000);
+       }
+       BEGIN_RING(evo, 0, 0x0088, 4);
        OUT_RING  (evo, dispc->sem.offset);
        OUT_RING  (evo, 0xf00d0000 | dispc->sem.value);
        OUT_RING  (evo, 0x74b1e000);
@@ -517,13 +528,25 @@ nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb,
                        if (bios->fp.if_is_24bit)
                                script |= 0x0200;
                } else {
+                       /* determine number of lvds links */
+                       if (nv_connector && nv_connector->edid &&
+                           nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) {
+                               /* http://www.spwg.org */
+                               if (((u8 *)nv_connector->edid)[121] == 2)
+                                       script |= 0x0100;
+                       } else
                        if (pxclk >= bios->fp.duallink_transition_clk) {
                                script |= 0x0100;
+                       }
+
+                       /* determine panel depth */
+                       if (script & 0x0100) {
                                if (bios->fp.strapless_is_24bit & 2)
                                        script |= 0x0200;
-                       } else
-                       if (bios->fp.strapless_is_24bit & 1)
-                               script |= 0x0200;
+                       } else {
+                               if (bios->fp.strapless_is_24bit & 1)
+                                       script |= 0x0200;
+                       }
 
                        if (nv_connector && nv_connector->edid &&
                            (nv_connector->edid->revision >= 4) &&
index b02a5b1e7d379fb1928467a668b905ddb4fa30b9..e25cbb46789a6780b5cf9611680468a835a09cff 100644 (file)
 #include "nouveau_grctx.h"
 #include "nouveau_dma.h"
 #include "nouveau_vm.h"
+#include "nouveau_ramht.h"
 #include "nv50_evo.h"
 
-static int  nv50_graph_register(struct drm_device *);
-static void nv50_graph_isr(struct drm_device *);
+struct nv50_graph_engine {
+       struct nouveau_exec_engine base;
+       u32 ctxprog[512];
+       u32 ctxprog_size;
+       u32 grctx_size;
+};
+
+static void
+nv50_graph_fifo_access(struct drm_device *dev, bool enabled)
+{
+       const uint32_t mask = 0x00010001;
+
+       if (enabled)
+               nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | mask);
+       else
+               nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) & ~mask);
+}
+
+static struct nouveau_channel *
+nv50_graph_channel(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       uint32_t inst;
+       int i;
+
+       /* Be sure we're not in the middle of a context switch or bad things
+        * will happen, such as unloading the wrong pgraph context.
+        */
+       if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000))
+               NV_ERROR(dev, "Ctxprog is still running\n");
+
+       inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
+       if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
+               return NULL;
+       inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12;
+
+       for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+               struct nouveau_channel *chan = dev_priv->channels.ptr[i];
+
+               if (chan && chan->ramin && chan->ramin->vinst == inst)
+                       return chan;
+       }
+
+       return NULL;
+}
+
+static int
+nv50_graph_do_load_context(struct drm_device *dev, uint32_t inst)
+{
+       uint32_t fifo = nv_rd32(dev, 0x400500);
+
+       nv_wr32(dev, 0x400500, fifo & ~1);
+       nv_wr32(dev, 0x400784, inst);
+       nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x40);
+       nv_wr32(dev, 0x400320, nv_rd32(dev, 0x400320) | 0x11);
+       nv_wr32(dev, 0x400040, 0xffffffff);
+       (void)nv_rd32(dev, 0x400040);
+       nv_wr32(dev, 0x400040, 0x00000000);
+       nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 1);
+
+       if (nouveau_wait_for_idle(dev))
+               nv_wr32(dev, 0x40032c, inst | (1<<31));
+       nv_wr32(dev, 0x400500, fifo);
+
+       return 0;
+}
+
+static int
+nv50_graph_unload_context(struct drm_device *dev)
+{
+       uint32_t inst;
+
+       inst  = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
+       if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
+               return 0;
+       inst &= NV50_PGRAPH_CTXCTL_CUR_INSTANCE;
+
+       nouveau_wait_for_idle(dev);
+       nv_wr32(dev, 0x400784, inst);
+       nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x20);
+       nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 0x01);
+       nouveau_wait_for_idle(dev);
+
+       nv_wr32(dev, NV50_PGRAPH_CTXCTL_CUR, inst);
+       return 0;
+}
 
 static void
 nv50_graph_init_reset(struct drm_device *dev)
@@ -52,7 +137,6 @@ nv50_graph_init_intr(struct drm_device *dev)
 {
        NV_DEBUG(dev, "\n");
 
-       nouveau_irq_register(dev, 12, nv50_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR, 0xffffffff);
        nv_wr32(dev, 0x400138, 0xffffffff);
        nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xffffffff);
@@ -135,34 +219,14 @@ nv50_graph_init_zcull(struct drm_device *dev)
 static int
 nv50_graph_init_ctxctl(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_grctx ctx = {};
-       uint32_t *cp;
+       struct nv50_graph_engine *pgraph = nv_engine(dev, NVOBJ_ENGINE_GR);
        int i;
 
        NV_DEBUG(dev, "\n");
 
-       cp = kmalloc(512 * 4, GFP_KERNEL);
-       if (!cp) {
-               NV_ERROR(dev, "failed to allocate ctxprog\n");
-               dev_priv->engine.graph.accel_blocked = true;
-               return 0;
-       }
-
-       ctx.dev = dev;
-       ctx.mode = NOUVEAU_GRCTX_PROG;
-       ctx.data = cp;
-       ctx.ctxprog_max = 512;
-       if (!nv50_grctx_init(&ctx)) {
-               dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
-
-               nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
-               for (i = 0; i < ctx.ctxprog_len; i++)
-                       nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
-       } else {
-               dev_priv->engine.graph.accel_blocked = true;
-       }
-       kfree(cp);
+       nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+       for (i = 0; i < pgraph->ctxprog_size; i++)
+               nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, pgraph->ctxprog[i]);
 
        nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */
        nv_wr32(dev, 0x400320, 4);
@@ -171,8 +235,8 @@ nv50_graph_init_ctxctl(struct drm_device *dev)
        return 0;
 }
 
-int
-nv50_graph_init(struct drm_device *dev)
+static int
+nv50_graph_init(struct drm_device *dev, int engine)
 {
        int ret;
 
@@ -186,105 +250,66 @@ nv50_graph_init(struct drm_device *dev)
        if (ret)
                return ret;
 
-       ret = nv50_graph_register(dev);
-       if (ret)
-               return ret;
        nv50_graph_init_intr(dev);
        return 0;
 }
 
-void
-nv50_graph_takedown(struct drm_device *dev)
+static int
+nv50_graph_fini(struct drm_device *dev, int engine)
 {
        NV_DEBUG(dev, "\n");
+       nv50_graph_unload_context(dev);
        nv_wr32(dev, 0x40013c, 0x00000000);
-       nouveau_irq_unregister(dev, 12);
-}
-
-void
-nv50_graph_fifo_access(struct drm_device *dev, bool enabled)
-{
-       const uint32_t mask = 0x00010001;
-
-       if (enabled)
-               nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | mask);
-       else
-               nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) & ~mask);
-}
-
-struct nouveau_channel *
-nv50_graph_channel(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t inst;
-       int i;
-
-       /* Be sure we're not in the middle of a context switch or bad things
-        * will happen, such as unloading the wrong pgraph context.
-        */
-       if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000))
-               NV_ERROR(dev, "Ctxprog is still running\n");
-
-       inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
-       if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
-               return NULL;
-       inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12;
-
-       for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
-               struct nouveau_channel *chan = dev_priv->channels.ptr[i];
-
-               if (chan && chan->ramin && chan->ramin->vinst == inst)
-                       return chan;
-       }
-
-       return NULL;
+       return 0;
 }
 
-int
-nv50_graph_create_context(struct nouveau_channel *chan)
+static int
+nv50_graph_context_new(struct nouveau_channel *chan, int engine)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_gpuobj *ramin = chan->ramin;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+       struct nouveau_gpuobj *grctx = NULL;
+       struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
        struct nouveau_grctx ctx = {};
        int hdr, ret;
 
        NV_DEBUG(dev, "ch%d\n", chan->id);
 
-       ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0,
+       ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 0,
                                 NVOBJ_FLAG_ZERO_ALLOC |
-                                NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
+                                NVOBJ_FLAG_ZERO_FREE, &grctx);
        if (ret)
                return ret;
 
        hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
        nv_wo32(ramin, hdr + 0x00, 0x00190002);
-       nv_wo32(ramin, hdr + 0x04, chan->ramin_grctx->vinst +
-                                  pgraph->grctx_size - 1);
-       nv_wo32(ramin, hdr + 0x08, chan->ramin_grctx->vinst);
+       nv_wo32(ramin, hdr + 0x04, grctx->vinst + grctx->size - 1);
+       nv_wo32(ramin, hdr + 0x08, grctx->vinst);
        nv_wo32(ramin, hdr + 0x0c, 0);
        nv_wo32(ramin, hdr + 0x10, 0);
        nv_wo32(ramin, hdr + 0x14, 0x00010000);
 
        ctx.dev = chan->dev;
        ctx.mode = NOUVEAU_GRCTX_VALS;
-       ctx.data = chan->ramin_grctx;
+       ctx.data = grctx;
        nv50_grctx_init(&ctx);
 
-       nv_wo32(chan->ramin_grctx, 0x00000, chan->ramin->vinst >> 12);
+       nv_wo32(grctx, 0x00000, chan->ramin->vinst >> 12);
 
        dev_priv->engine.instmem.flush(dev);
-       atomic_inc(&chan->vm->pgraph_refs);
+
+       atomic_inc(&chan->vm->engref[NVOBJ_ENGINE_GR]);
+       chan->engctx[NVOBJ_ENGINE_GR] = grctx;
        return 0;
 }
 
-void
-nv50_graph_destroy_context(struct nouveau_channel *chan)
+static void
+nv50_graph_context_del(struct nouveau_channel *chan, int engine)
 {
+       struct nouveau_gpuobj *grctx = chan->engctx[engine];
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
        unsigned long flags;
@@ -296,72 +321,49 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
 
        spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
        pfifo->reassign(dev, false);
-       pgraph->fifo_access(dev, false);
+       nv50_graph_fifo_access(dev, false);
 
-       if (pgraph->channel(dev) == chan)
-               pgraph->unload_context(dev);
+       if (nv50_graph_channel(dev) == chan)
+               nv50_graph_unload_context(dev);
 
        for (i = hdr; i < hdr + 24; i += 4)
                nv_wo32(chan->ramin, i, 0);
        dev_priv->engine.instmem.flush(dev);
 
-       pgraph->fifo_access(dev, true);
+       nv50_graph_fifo_access(dev, true);
        pfifo->reassign(dev, true);
        spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
-       nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
+       nouveau_gpuobj_ref(NULL, &grctx);
 
-       atomic_dec(&chan->vm->pgraph_refs);
+       atomic_dec(&chan->vm->engref[engine]);
+       chan->engctx[engine] = NULL;
 }
 
 static int
-nv50_graph_do_load_context(struct drm_device *dev, uint32_t inst)
-{
-       uint32_t fifo = nv_rd32(dev, 0x400500);
-
-       nv_wr32(dev, 0x400500, fifo & ~1);
-       nv_wr32(dev, 0x400784, inst);
-       nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x40);
-       nv_wr32(dev, 0x400320, nv_rd32(dev, 0x400320) | 0x11);
-       nv_wr32(dev, 0x400040, 0xffffffff);
-       (void)nv_rd32(dev, 0x400040);
-       nv_wr32(dev, 0x400040, 0x00000000);
-       nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 1);
-
-       if (nouveau_wait_for_idle(dev))
-               nv_wr32(dev, 0x40032c, inst | (1<<31));
-       nv_wr32(dev, 0x400500, fifo);
-
-       return 0;
-}
-
-int
-nv50_graph_load_context(struct nouveau_channel *chan)
-{
-       uint32_t inst = chan->ramin->vinst >> 12;
-
-       NV_DEBUG(chan->dev, "ch%d\n", chan->id);
-       return nv50_graph_do_load_context(chan->dev, inst);
-}
-
-int
-nv50_graph_unload_context(struct drm_device *dev)
+nv50_graph_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
 {
-       uint32_t inst;
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *obj = NULL;
+       int ret;
 
-       inst  = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
-       if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
-               return 0;
-       inst &= NV50_PGRAPH_CTXCTL_CUR_INSTANCE;
+       ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 1;
+       obj->class  = class;
 
-       nouveau_wait_for_idle(dev);
-       nv_wr32(dev, 0x400784, inst);
-       nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x20);
-       nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 0x01);
-       nouveau_wait_for_idle(dev);
+       nv_wo32(obj, 0x00, class);
+       nv_wo32(obj, 0x04, 0x00000000);
+       nv_wo32(obj, 0x08, 0x00000000);
+       nv_wo32(obj, 0x0c, 0x00000000);
+       dev_priv->engine.instmem.flush(dev);
 
-       nv_wr32(dev, NV50_PGRAPH_CTXCTL_CUR, inst);
-       return 0;
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       return ret;
 }
 
 static void
@@ -442,68 +444,15 @@ nv50_graph_nvsw_mthd_page_flip(struct nouveau_channel *chan,
        return 0;
 }
 
-static int
-nv50_graph_register(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->engine.graph.registered)
-               return 0;
-
-       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
-       NVOBJ_MTHD (dev, 0x506e, 0x018c, nv50_graph_nvsw_dma_vblsem);
-       NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset);
-       NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val);
-       NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release);
-       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip);
-
-       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-       NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */
-       NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */
-
-       /* tesla */
-       if (dev_priv->chipset == 0x50)
-               NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */
-       else
-       if (dev_priv->chipset < 0xa0)
-               NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */
-       else {
-               switch (dev_priv->chipset) {
-               case 0xa0:
-               case 0xaa:
-               case 0xac:
-                       NVOBJ_CLASS(dev, 0x8397, GR);
-                       break;
-               case 0xa3:
-               case 0xa5:
-               case 0xa8:
-                       NVOBJ_CLASS(dev, 0x8597, GR);
-                       break;
-               case 0xaf:
-                       NVOBJ_CLASS(dev, 0x8697, GR);
-                       break;
-               }
-       }
-
-       /* compute */
-       NVOBJ_CLASS(dev, 0x50c0, GR);
-       if (dev_priv->chipset  > 0xa0 &&
-           dev_priv->chipset != 0xaa &&
-           dev_priv->chipset != 0xac)
-               NVOBJ_CLASS(dev, 0x85c0, GR);
-
-       dev_priv->engine.graph.registered = true;
-       return 0;
-}
 
-void
-nv50_graph_tlb_flush(struct drm_device *dev)
+static void
+nv50_graph_tlb_flush(struct drm_device *dev, int engine)
 {
        nv50_vm_flush_engine(dev, 0);
 }
 
-void
-nv84_graph_tlb_flush(struct drm_device *dev)
+static void
+nv84_graph_tlb_flush(struct drm_device *dev, int engine)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
@@ -548,8 +497,7 @@ nv84_graph_tlb_flush(struct drm_device *dev)
        spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 }
 
-static struct nouveau_enum nv50_mp_exec_error_names[] =
-{
+static struct nouveau_enum nv50_mp_exec_error_names[] = {
        { 3, "STACK_UNDERFLOW", NULL },
        { 4, "QUADON_ACTIVE", NULL },
        { 8, "TIMEOUT", NULL },
@@ -663,7 +611,7 @@ nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display)
                        nv_rd32(dev, addr + 0x20);
                        pc = nv_rd32(dev, addr + 0x24);
                        oplow = nv_rd32(dev, addr + 0x70);
-                       ophigh= nv_rd32(dev, addr + 0x74);
+                       ophigh = nv_rd32(dev, addr + 0x74);
                        NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - "
                                        "TP %d MP %d: ", tpid, i);
                        nouveau_enum_print(nv50_mp_exec_error_names, status);
@@ -991,7 +939,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid
        return 1;
 }
 
-static int
+int
 nv50_graph_isr_chid(struct drm_device *dev, u64 inst)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1073,3 +1021,101 @@ nv50_graph_isr(struct drm_device *dev)
        if (nv_rd32(dev, 0x400824) & (1 << 31))
                nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31));
 }
+
+static void
+nv50_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
+
+       NVOBJ_ENGINE_DEL(dev, GR);
+
+       nouveau_irq_unregister(dev, 12);
+       kfree(pgraph);
+}
+
+int
+nv50_graph_create(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nv50_graph_engine *pgraph;
+       struct nouveau_grctx ctx = {};
+       int ret;
+
+       pgraph = kzalloc(sizeof(*pgraph),GFP_KERNEL);
+       if (!pgraph)
+               return -ENOMEM;
+
+       ctx.dev = dev;
+       ctx.mode = NOUVEAU_GRCTX_PROG;
+       ctx.data = pgraph->ctxprog;
+       ctx.ctxprog_max = ARRAY_SIZE(pgraph->ctxprog);
+
+       ret = nv50_grctx_init(&ctx);
+       if (ret) {
+               NV_ERROR(dev, "PGRAPH: ctxprog build failed\n");
+               kfree(pgraph);
+               return 0;
+       }
+
+       pgraph->grctx_size = ctx.ctxvals_pos * 4;
+       pgraph->ctxprog_size = ctx.ctxprog_len;
+
+       pgraph->base.destroy = nv50_graph_destroy;
+       pgraph->base.init = nv50_graph_init;
+       pgraph->base.fini = nv50_graph_fini;
+       pgraph->base.context_new = nv50_graph_context_new;
+       pgraph->base.context_del = nv50_graph_context_del;
+       pgraph->base.object_new = nv50_graph_object_new;
+       if (dev_priv->chipset == 0x50 || dev_priv->chipset == 0xac)
+               pgraph->base.tlb_flush = nv50_graph_tlb_flush;
+       else
+               pgraph->base.tlb_flush = nv84_graph_tlb_flush;
+
+       nouveau_irq_register(dev, 12, nv50_graph_isr);
+
+       /* NVSW really doesn't live here... */
+       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
+       NVOBJ_MTHD (dev, 0x506e, 0x018c, nv50_graph_nvsw_dma_vblsem);
+       NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset);
+       NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val);
+       NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release);
+       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip);
+
+       NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+       NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */
+       NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */
+
+       /* tesla */
+       if (dev_priv->chipset == 0x50)
+               NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */
+       else
+       if (dev_priv->chipset < 0xa0)
+               NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */
+       else {
+               switch (dev_priv->chipset) {
+               case 0xa0:
+               case 0xaa:
+               case 0xac:
+                       NVOBJ_CLASS(dev, 0x8397, GR);
+                       break;
+               case 0xa3:
+               case 0xa5:
+               case 0xa8:
+                       NVOBJ_CLASS(dev, 0x8597, GR);
+                       break;
+               case 0xaf:
+                       NVOBJ_CLASS(dev, 0x8697, GR);
+                       break;
+               }
+       }
+
+       /* compute */
+       NVOBJ_CLASS(dev, 0x50c0, GR);
+       if (dev_priv->chipset  > 0xa0 &&
+           dev_priv->chipset != 0xaa &&
+           dev_priv->chipset != 0xac)
+               NVOBJ_CLASS(dev, 0x85c0, GR);
+
+       return 0;
+}
index 336aab2a24a66ff030b7af629db43f53aaa9ef8e..de9abff12b909122faf612f16a2dfd0ab17d0052 100644 (file)
@@ -747,7 +747,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
                                gr_def(ctx, offset + 0x64, 0x0000001f);
                                gr_def(ctx, offset + 0x68, 0x0000000f);
                                gr_def(ctx, offset + 0x6c, 0x0000000f);
-                       } else if(dev_priv->chipset < 0xa0) {
+                       } else if (dev_priv->chipset < 0xa0) {
                                cp_ctx(ctx, offset + 0x50, 1);
                                cp_ctx(ctx, offset + 0x70, 1);
                        } else {
@@ -924,7 +924,7 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx)
                dd_emit(ctx, 1, 0);     /* 0000007f MULTISAMPLE_SAMPLES_LOG2 */
        } else {
                dd_emit(ctx, 1, 0);     /* 0000000f MULTISAMPLE_SAMPLES_LOG2 */
-       } 
+       }
        dd_emit(ctx, 1, 0xc);           /* 000000ff SEMANTIC_COLOR.BFC0_ID */
        if (dev_priv->chipset != 0x50)
                dd_emit(ctx, 1, 0);     /* 00000001 SEMANTIC_COLOR.CLMP_EN */
@@ -1803,9 +1803,7 @@ nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx)
                xf_emit(ctx, 1, 0);     /* 1ff */
                xf_emit(ctx, 8, 0);     /* 0? */
                xf_emit(ctx, 9, 0);     /* ffffffff, 7ff */
-       }
-       else
-       {
+       } else {
                xf_emit(ctx, 0xc, 0);   /* RO */
                /* SEEK */
                xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
@@ -2836,7 +2834,7 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx)
        xf_emit(ctx, 1, 1);             /* 00000001 DST_LINEAR */
        if (IS_NVA3F(dev_priv->chipset))
                xf_emit(ctx, 1, 1);     /* 0000001f tesla UNK169C */
-       if(dev_priv->chipset == 0x50)
+       if (dev_priv->chipset == 0x50)
                xf_emit(ctx, 1, 0);     /* ff */
        else
                xf_emit(ctx, 3, 0);     /* 1, 7, 3ff */
diff --git a/drivers/gpu/drm/nouveau/nv50_mpeg.c b/drivers/gpu/drm/nouveau/nv50_mpeg.c
new file mode 100644 (file)
index 0000000..1dc5913
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
+
+struct nv50_mpeg_engine {
+       struct nouveau_exec_engine base;
+};
+
+static inline u32
+CTX_PTR(struct drm_device *dev, u32 offset)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->chipset == 0x50)
+               offset += 0x0260;
+       else
+               offset += 0x0060;
+
+       return offset;
+}
+
+static int
+nv50_mpeg_context_new(struct nouveau_channel *chan, int engine)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *ramin = chan->ramin;
+       struct nouveau_gpuobj *ctx = NULL;
+       int ret;
+
+       NV_DEBUG(dev, "ch%d\n", chan->id);
+
+       ret = nouveau_gpuobj_new(dev, chan, 128 * 4, 0, NVOBJ_FLAG_ZERO_ALLOC |
+                                NVOBJ_FLAG_ZERO_FREE, &ctx);
+       if (ret)
+               return ret;
+
+       nv_wo32(ramin, CTX_PTR(dev, 0x00), 0x80190002);
+       nv_wo32(ramin, CTX_PTR(dev, 0x04), ctx->vinst + ctx->size - 1);
+       nv_wo32(ramin, CTX_PTR(dev, 0x08), ctx->vinst);
+       nv_wo32(ramin, CTX_PTR(dev, 0x0c), 0);
+       nv_wo32(ramin, CTX_PTR(dev, 0x10), 0);
+       nv_wo32(ramin, CTX_PTR(dev, 0x14), 0x00010000);
+
+       nv_wo32(ctx, 0x70, 0x00801ec1);
+       nv_wo32(ctx, 0x7c, 0x0000037c);
+       dev_priv->engine.instmem.flush(dev);
+
+       chan->engctx[engine] = ctx;
+       return 0;
+}
+
+static void
+nv50_mpeg_context_del(struct nouveau_channel *chan, int engine)
+{
+       struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
+       struct drm_device *dev = chan->dev;
+       unsigned long flags;
+       u32 inst, i;
+
+       if (!chan->ramin)
+               return;
+
+       inst  = chan->ramin->vinst >> 12;
+       inst |= 0x80000000;
+
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+       if (nv_rd32(dev, 0x00b318) == inst)
+               nv_mask(dev, 0x00b318, 0x80000000, 0x00000000);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       for (i = 0x00; i <= 0x14; i += 4)
+               nv_wo32(chan->ramin, CTX_PTR(dev, i), 0x00000000);
+       nouveau_gpuobj_ref(NULL, &ctx);
+       chan->engctx[engine] = NULL;
+}
+
+static int
+nv50_mpeg_object_new(struct nouveau_channel *chan, int engine,
+                    u32 handle, u16 class)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *obj = NULL;
+       int ret;
+
+       ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 2;
+       obj->class  = class;
+
+       nv_wo32(obj, 0x00, class);
+       nv_wo32(obj, 0x04, 0x00000000);
+       nv_wo32(obj, 0x08, 0x00000000);
+       nv_wo32(obj, 0x0c, 0x00000000);
+       dev_priv->engine.instmem.flush(dev);
+
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       return ret;
+}
+
+static void
+nv50_mpeg_tlb_flush(struct drm_device *dev, int engine)
+{
+       nv50_vm_flush_engine(dev, 0x08);
+}
+
+static int
+nv50_mpeg_init(struct drm_device *dev, int engine)
+{
+       nv_wr32(dev, 0x00b32c, 0x00000000);
+       nv_wr32(dev, 0x00b314, 0x00000100);
+       nv_wr32(dev, 0x00b0e0, 0x0000001a);
+
+       nv_wr32(dev, 0x00b220, 0x00000044);
+       nv_wr32(dev, 0x00b300, 0x00801ec1);
+       nv_wr32(dev, 0x00b390, 0x00000000);
+       nv_wr32(dev, 0x00b394, 0x00000000);
+       nv_wr32(dev, 0x00b398, 0x00000000);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+
+       nv_wr32(dev, 0x00b100, 0xffffffff);
+       nv_wr32(dev, 0x00b140, 0xffffffff);
+
+       if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) {
+               NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200));
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int
+nv50_mpeg_fini(struct drm_device *dev, int engine)
+{
+       /*XXX: context save for s/r */
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+       nv_wr32(dev, 0x00b140, 0x00000000);
+       return 0;
+}
+
+static void
+nv50_mpeg_isr(struct drm_device *dev)
+{
+       u32 stat = nv_rd32(dev, 0x00b100);
+       u32 type = nv_rd32(dev, 0x00b230);
+       u32 mthd = nv_rd32(dev, 0x00b234);
+       u32 data = nv_rd32(dev, 0x00b238);
+       u32 show = stat;
+
+       if (stat & 0x01000000) {
+               /* happens on initial binding of the object */
+               if (type == 0x00000020 && mthd == 0x0000) {
+                       nv_wr32(dev, 0x00b308, 0x00000100);
+                       show &= ~0x01000000;
+               }
+       }
+
+       if (show && nouveau_ratelimit()) {
+               NV_INFO(dev, "PMPEG - 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                       stat, type, mthd, data);
+       }
+
+       nv_wr32(dev, 0x00b100, stat);
+       nv_wr32(dev, 0x00b230, 0x00000001);
+       nv50_fb_vm_trap(dev, 1);
+}
+
+static void
+nv50_vpe_isr(struct drm_device *dev)
+{
+       if (nv_rd32(dev, 0x00b100))
+               nv50_mpeg_isr(dev);
+
+       if (nv_rd32(dev, 0x00b800)) {
+               u32 stat = nv_rd32(dev, 0x00b800);
+               NV_INFO(dev, "PMSRCH: 0x%08x\n", stat);
+               nv_wr32(dev, 0xb800, stat);
+       }
+}
+
+static void
+nv50_mpeg_destroy(struct drm_device *dev, int engine)
+{
+       struct nv50_mpeg_engine *pmpeg = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 0);
+
+       NVOBJ_ENGINE_DEL(dev, MPEG);
+       kfree(pmpeg);
+}
+
+int
+nv50_mpeg_create(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nv50_mpeg_engine *pmpeg;
+
+       pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL);
+       if (!pmpeg)
+               return -ENOMEM;
+
+       pmpeg->base.destroy = nv50_mpeg_destroy;
+       pmpeg->base.init = nv50_mpeg_init;
+       pmpeg->base.fini = nv50_mpeg_fini;
+       pmpeg->base.context_new = nv50_mpeg_context_new;
+       pmpeg->base.context_del = nv50_mpeg_context_del;
+       pmpeg->base.object_new = nv50_mpeg_object_new;
+       pmpeg->base.tlb_flush = nv50_mpeg_tlb_flush;
+
+       if (dev_priv->chipset == 0x50) {
+               nouveau_irq_register(dev, 0, nv50_vpe_isr);
+               NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
+               NVOBJ_CLASS(dev, 0x3174, MPEG);
+#if 0
+               NVOBJ_ENGINE_ADD(dev, ME, &pme->base);
+               NVOBJ_CLASS(dev, 0x4075, ME);
+#endif
+       } else {
+               nouveau_irq_register(dev, 0, nv50_mpeg_isr);
+               NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
+               NVOBJ_CLASS(dev, 0x8274, MPEG);
+       }
+
+       return 0;
+
+}
index 7dbb305d7e63598056678c8e3e20b594c8c25a18..8a2810011bda5e9cd1861d03ecf3482229be20da 100644 (file)
@@ -47,6 +47,21 @@ nv50_pm_clock_get(struct drm_device *dev, u32 id)
 
        reg0 = nv_rd32(dev, pll.reg + 0);
        reg1 = nv_rd32(dev, pll.reg + 4);
+
+       if ((reg0 & 0x80000000) == 0) {
+               if (id == PLL_SHADER) {
+                       NV_DEBUG(dev, "Shader PLL is disabled. "
+                               "Shader clock is twice the core\n");
+                       ret = nv50_pm_clock_get(dev, PLL_CORE);
+                       if (ret > 0)
+                               return ret << 1;
+               } else if (id == PLL_MEMORY) {
+                       NV_DEBUG(dev, "Memory PLL is disabled. "
+                               "Memory clock is equal to the ref_clk\n");
+                       return pll.refclk;
+               }
+       }
+
        P = (reg0 & 0x00070000) >> 16;
        N = (reg1 & 0x0000ff00) >> 8;
        M = (reg1 & 0x000000ff);
index 6c26944907418b0d090d35758b8e22d7ce9de06c..1a0dd491a0e44257dc1eb4dc87005b4b3d18f1dc 100644 (file)
@@ -151,8 +151,7 @@ nv50_vm_flush(struct nouveau_vm *vm)
        struct drm_nouveau_private *dev_priv = vm->dev->dev_private;
        struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
+       int i;
 
        pinstmem->flush(vm->dev);
 
@@ -163,11 +162,10 @@ nv50_vm_flush(struct nouveau_vm *vm)
        }
 
        pfifo->tlb_flush(vm->dev);
-
-       if (atomic_read(&vm->pgraph_refs))
-               pgraph->tlb_flush(vm->dev);
-       if (atomic_read(&vm->pcrypt_refs))
-               pcrypt->tlb_flush(vm->dev);
+       for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+               if (atomic_read(&vm->engref[i]))
+                       dev_priv->eng[i]->tlb_flush(vm->dev, i);
+       }
 }
 
 void
index fabc7fd30b1d9150e7f532f7cf58de8e5f9f247f..75b809a51748e09eaa78cd8e07d5a7b754b3e408 100644 (file)
 #include "nouveau_drv.h"
 #include "nouveau_util.h"
 #include "nouveau_vm.h"
+#include "nouveau_ramht.h"
 
-static void nv84_crypt_isr(struct drm_device *);
+struct nv84_crypt_engine {
+       struct nouveau_exec_engine base;
+};
 
-int
-nv84_crypt_create_context(struct nouveau_channel *chan)
+static int
+nv84_crypt_context_new(struct nouveau_channel *chan, int engine)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_gpuobj *ramin = chan->ramin;
+       struct nouveau_gpuobj *ctx;
        int ret;
 
        NV_DEBUG(dev, "ch%d\n", chan->id);
 
-       ret = nouveau_gpuobj_new(dev, chan, 256, 0,
-                                NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
-                                &chan->crypt_ctx);
+       ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC |
+                                NVOBJ_FLAG_ZERO_FREE, &ctx);
        if (ret)
                return ret;
 
        nv_wo32(ramin, 0xa0, 0x00190000);
-       nv_wo32(ramin, 0xa4, chan->crypt_ctx->vinst + 0xff);
-       nv_wo32(ramin, 0xa8, chan->crypt_ctx->vinst);
+       nv_wo32(ramin, 0xa4, ctx->vinst + ctx->size - 1);
+       nv_wo32(ramin, 0xa8, ctx->vinst);
        nv_wo32(ramin, 0xac, 0);
        nv_wo32(ramin, 0xb0, 0);
        nv_wo32(ramin, 0xb4, 0);
-
        dev_priv->engine.instmem.flush(dev);
-       atomic_inc(&chan->vm->pcrypt_refs);
+
+       atomic_inc(&chan->vm->engref[engine]);
+       chan->engctx[engine] = ctx;
        return 0;
 }
 
-void
-nv84_crypt_destroy_context(struct nouveau_channel *chan)
+static void
+nv84_crypt_context_del(struct nouveau_channel *chan, int engine)
 {
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
        struct drm_device *dev = chan->dev;
        u32 inst;
 
-       if (!chan->crypt_ctx)
-               return;
-
        inst  = (chan->ramin->vinst >> 12);
        inst |= 0x80000000;
 
@@ -80,43 +82,39 @@ nv84_crypt_destroy_context(struct nouveau_channel *chan)
                nv_mask(dev, 0x10218c, 0x80000000, 0x00000000);
        nv_wr32(dev, 0x10200c, 0x00000010);
 
-       nouveau_gpuobj_ref(NULL, &chan->crypt_ctx);
-       atomic_dec(&chan->vm->pcrypt_refs);
-}
+       nouveau_gpuobj_ref(NULL, &ctx);
 
-void
-nv84_crypt_tlb_flush(struct drm_device *dev)
-{
-       nv50_vm_flush_engine(dev, 0x0a);
+       atomic_dec(&chan->vm->engref[engine]);
+       chan->engctx[engine] = NULL;
 }
 
-int
-nv84_crypt_init(struct drm_device *dev)
+static int
+nv84_crypt_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
 {
+       struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
-
-       if (!pcrypt->registered) {
-               NVOBJ_CLASS(dev, 0x74c1, CRYPT);
-               pcrypt->registered = true;
-       }
+       struct nouveau_gpuobj *obj = NULL;
+       int ret;
 
-       nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
-       nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
+       ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 5;
+       obj->class  = class;
 
-       nouveau_irq_register(dev, 14, nv84_crypt_isr);
-       nv_wr32(dev, 0x102130, 0xffffffff);
-       nv_wr32(dev, 0x102140, 0xffffffbf);
+       nv_wo32(obj, 0x00, class);
+       dev_priv->engine.instmem.flush(dev);
 
-       nv_wr32(dev, 0x10200c, 0x00000010);
-       return 0;
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       return ret;
 }
 
-void
-nv84_crypt_fini(struct drm_device *dev)
+static void
+nv84_crypt_tlb_flush(struct drm_device *dev, int engine)
 {
-       nv_wr32(dev, 0x102140, 0x00000000);
-       nouveau_irq_unregister(dev, 14);
+       nv50_vm_flush_engine(dev, 0x0a);
 }
 
 static void
@@ -138,3 +136,58 @@ nv84_crypt_isr(struct drm_device *dev)
 
        nv50_fb_vm_trap(dev, show);
 }
+
+static int
+nv84_crypt_fini(struct drm_device *dev, int engine)
+{
+       nv_wr32(dev, 0x102140, 0x00000000);
+       return 0;
+}
+
+static int
+nv84_crypt_init(struct drm_device *dev, int engine)
+{
+       nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
+       nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
+
+       nv_wr32(dev, 0x102130, 0xffffffff);
+       nv_wr32(dev, 0x102140, 0xffffffbf);
+
+       nv_wr32(dev, 0x10200c, 0x00000010);
+       return 0;
+}
+
+static void
+nv84_crypt_destroy(struct drm_device *dev, int engine)
+{
+       struct nv84_crypt_engine *pcrypt = nv_engine(dev, engine);
+
+       NVOBJ_ENGINE_DEL(dev, CRYPT);
+
+       nouveau_irq_unregister(dev, 14);
+       kfree(pcrypt);
+}
+
+int
+nv84_crypt_create(struct drm_device *dev)
+{
+       struct nv84_crypt_engine *pcrypt;
+
+       pcrypt = kzalloc(sizeof(*pcrypt), GFP_KERNEL);
+       if (!pcrypt)
+               return -ENOMEM;
+
+       pcrypt->base.destroy = nv84_crypt_destroy;
+       pcrypt->base.init = nv84_crypt_init;
+       pcrypt->base.fini = nv84_crypt_fini;
+       pcrypt->base.context_new = nv84_crypt_context_new;
+       pcrypt->base.context_del = nv84_crypt_context_del;
+       pcrypt->base.object_new = nv84_crypt_object_new;
+       pcrypt->base.tlb_flush = nv84_crypt_tlb_flush;
+
+       nouveau_irq_register(dev, 14, nv84_crypt_isr);
+
+       NVOBJ_ENGINE_ADD(dev, CRYPT, &pcrypt->base);
+       NVOBJ_CLASS (dev, 0x74c1, CRYPT);
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nva3_copy.c b/drivers/gpu/drm/nouveau/nva3_copy.c
new file mode 100644 (file)
index 0000000..b86820a
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs
+ */
+
+#include <linux/firmware.h>
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_util.h"
+#include "nouveau_vm.h"
+#include "nouveau_ramht.h"
+#include "nva3_copy.fuc.h"
+
+struct nva3_copy_engine {
+       struct nouveau_exec_engine base;
+};
+
+static int
+nva3_copy_context_new(struct nouveau_channel *chan, int engine)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *ramin = chan->ramin;
+       struct nouveau_gpuobj *ctx = NULL;
+       int ret;
+
+       NV_DEBUG(dev, "ch%d\n", chan->id);
+
+       ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC |
+                                NVOBJ_FLAG_ZERO_FREE, &ctx);
+       if (ret)
+               return ret;
+
+       nv_wo32(ramin, 0xc0, 0x00190000);
+       nv_wo32(ramin, 0xc4, ctx->vinst + ctx->size - 1);
+       nv_wo32(ramin, 0xc8, ctx->vinst);
+       nv_wo32(ramin, 0xcc, 0x00000000);
+       nv_wo32(ramin, 0xd0, 0x00000000);
+       nv_wo32(ramin, 0xd4, 0x00000000);
+       dev_priv->engine.instmem.flush(dev);
+
+       atomic_inc(&chan->vm->engref[engine]);
+       chan->engctx[engine] = ctx;
+       return 0;
+}
+
+static int
+nva3_copy_object_new(struct nouveau_channel *chan, int engine,
+                    u32 handle, u16 class)
+{
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
+
+       /* fuc engine doesn't need an object, our ramht code does.. */
+       ctx->engine = 3;
+       ctx->class  = class;
+       return nouveau_ramht_insert(chan, handle, ctx);
+}
+
+static void
+nva3_copy_context_del(struct nouveau_channel *chan, int engine)
+{
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
+       struct drm_device *dev = chan->dev;
+       u32 inst;
+
+       inst  = (chan->ramin->vinst >> 12);
+       inst |= 0x40000000;
+
+       /* disable fifo access */
+       nv_wr32(dev, 0x104048, 0x00000000);
+       /* mark channel as unloaded if it's currently active */
+       if (nv_rd32(dev, 0x104050) == inst)
+               nv_mask(dev, 0x104050, 0x40000000, 0x00000000);
+       /* mark next channel as invalid if it's about to be loaded */
+       if (nv_rd32(dev, 0x104054) == inst)
+               nv_mask(dev, 0x104054, 0x40000000, 0x00000000);
+       /* restore fifo access */
+       nv_wr32(dev, 0x104048, 0x00000003);
+
+       for (inst = 0xc0; inst <= 0xd4; inst += 4)
+               nv_wo32(chan->ramin, inst, 0x00000000);
+
+       nouveau_gpuobj_ref(NULL, &ctx);
+
+       atomic_dec(&chan->vm->engref[engine]);
+       chan->engctx[engine] = ctx;
+}
+
+static void
+nva3_copy_tlb_flush(struct drm_device *dev, int engine)
+{
+       nv50_vm_flush_engine(dev, 0x0d);
+}
+
+static int
+nva3_copy_init(struct drm_device *dev, int engine)
+{
+       int i;
+
+       nv_mask(dev, 0x000200, 0x00002000, 0x00000000);
+       nv_mask(dev, 0x000200, 0x00002000, 0x00002000);
+       nv_wr32(dev, 0x104014, 0xffffffff); /* disable all interrupts */
+
+       /* upload ucode */
+       nv_wr32(dev, 0x1041c0, 0x01000000);
+       for (i = 0; i < sizeof(nva3_pcopy_data) / 4; i++)
+               nv_wr32(dev, 0x1041c4, nva3_pcopy_data[i]);
+
+       nv_wr32(dev, 0x104180, 0x01000000);
+       for (i = 0; i < sizeof(nva3_pcopy_code) / 4; i++) {
+               if ((i & 0x3f) == 0)
+                       nv_wr32(dev, 0x104188, i >> 6);
+               nv_wr32(dev, 0x104184, nva3_pcopy_code[i]);
+       }
+
+       /* start it running */
+       nv_wr32(dev, 0x10410c, 0x00000000);
+       nv_wr32(dev, 0x104104, 0x00000000); /* ENTRY */
+       nv_wr32(dev, 0x104100, 0x00000002); /* TRIGGER */
+       return 0;
+}
+
+static int
+nva3_copy_fini(struct drm_device *dev, int engine)
+{
+       nv_mask(dev, 0x104048, 0x00000003, 0x00000000);
+
+       /* trigger fuc context unload */
+       nv_wait(dev, 0x104008, 0x0000000c, 0x00000000);
+       nv_mask(dev, 0x104054, 0x40000000, 0x00000000);
+       nv_wr32(dev, 0x104000, 0x00000008);
+       nv_wait(dev, 0x104008, 0x00000008, 0x00000000);
+
+       nv_wr32(dev, 0x104014, 0xffffffff);
+       return 0;
+}
+
+static struct nouveau_enum nva3_copy_isr_error_name[] = {
+       { 0x0001, "ILLEGAL_MTHD" },
+       { 0x0002, "INVALID_ENUM" },
+       { 0x0003, "INVALID_BITFIELD" },
+       {}
+};
+
+static void
+nva3_copy_isr(struct drm_device *dev)
+{
+       u32 dispatch = nv_rd32(dev, 0x10401c);
+       u32 stat = nv_rd32(dev, 0x104008) & dispatch & ~(dispatch >> 16);
+       u32 inst = nv_rd32(dev, 0x104050) & 0x3fffffff;
+       u32 ssta = nv_rd32(dev, 0x104040) & 0x0000ffff;
+       u32 addr = nv_rd32(dev, 0x104040) >> 16;
+       u32 mthd = (addr & 0x07ff) << 2;
+       u32 subc = (addr & 0x3800) >> 11;
+       u32 data = nv_rd32(dev, 0x104044);
+       int chid = nv50_graph_isr_chid(dev, inst);
+
+       if (stat & 0x00000040) {
+               NV_INFO(dev, "PCOPY: DISPATCH_ERROR [");
+               nouveau_enum_print(nva3_copy_isr_error_name, ssta);
+               printk("] ch %d [0x%08x] subc %d mthd 0x%04x data 0x%08x\n",
+                       chid, inst, subc, mthd, data);
+               nv_wr32(dev, 0x104004, 0x00000040);
+               stat &= ~0x00000040;
+       }
+
+       if (stat) {
+               NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat);
+               nv_wr32(dev, 0x104004, stat);
+       }
+       nv50_fb_vm_trap(dev, 1);
+}
+
+static void
+nva3_copy_destroy(struct drm_device *dev, int engine)
+{
+       struct nva3_copy_engine *pcopy = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 22);
+
+       NVOBJ_ENGINE_DEL(dev, COPY0);
+       kfree(pcopy);
+}
+
+int
+nva3_copy_create(struct drm_device *dev)
+{
+       struct nva3_copy_engine *pcopy;
+
+       pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL);
+       if (!pcopy)
+               return -ENOMEM;
+
+       pcopy->base.destroy = nva3_copy_destroy;
+       pcopy->base.init = nva3_copy_init;
+       pcopy->base.fini = nva3_copy_fini;
+       pcopy->base.context_new = nva3_copy_context_new;
+       pcopy->base.context_del = nva3_copy_context_del;
+       pcopy->base.object_new = nva3_copy_object_new;
+       pcopy->base.tlb_flush = nva3_copy_tlb_flush;
+
+       nouveau_irq_register(dev, 22, nva3_copy_isr);
+
+       NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base);
+       NVOBJ_CLASS(dev, 0x85b5, COPY0);
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nva3_copy.fuc b/drivers/gpu/drm/nouveau/nva3_copy.fuc
new file mode 100644 (file)
index 0000000..eaf35f8
--- /dev/null
@@ -0,0 +1,870 @@
+/* fuc microcode for copy engine on nva3- chipsets
+ *
+ * Copyright 2011 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs
+ */
+
+/* To build for nva3:nvc0
+ *    m4 -DNVA3 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nva3_copy.fuc.h
+ *
+ * To build for nvc0-
+ *    m4 -DNVC0 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_copy.fuc.h
+ */
+
+ifdef(`NVA3',
+.section nva3_pcopy_data,
+.section nvc0_pcopy_data
+)
+
+ctx_object:                   .b32 0
+ifdef(`NVA3',
+ctx_dma:
+ctx_dma_query:                .b32 0
+ctx_dma_src:                  .b32 0
+ctx_dma_dst:                  .b32 0
+,)
+.equ ctx_dma_count 3
+ctx_query_address_high:       .b32 0
+ctx_query_address_low:        .b32 0
+ctx_query_counter:            .b32 0
+ctx_src_address_high:         .b32 0
+ctx_src_address_low:          .b32 0
+ctx_src_pitch:                .b32 0
+ctx_src_tile_mode:            .b32 0
+ctx_src_xsize:                .b32 0
+ctx_src_ysize:                .b32 0
+ctx_src_zsize:                .b32 0
+ctx_src_zoff:                 .b32 0
+ctx_src_xoff:                 .b32 0
+ctx_src_yoff:                 .b32 0
+ctx_src_cpp:                  .b32 0
+ctx_dst_address_high:         .b32 0
+ctx_dst_address_low:          .b32 0
+ctx_dst_pitch:                .b32 0
+ctx_dst_tile_mode:            .b32 0
+ctx_dst_xsize:                .b32 0
+ctx_dst_ysize:                .b32 0
+ctx_dst_zsize:                .b32 0
+ctx_dst_zoff:                 .b32 0
+ctx_dst_xoff:                 .b32 0
+ctx_dst_yoff:                 .b32 0
+ctx_dst_cpp:                  .b32 0
+ctx_format:                   .b32 0
+ctx_swz_const0:               .b32 0
+ctx_swz_const1:               .b32 0
+ctx_xcnt:                     .b32 0
+ctx_ycnt:                     .b32 0
+.align 256
+
+dispatch_table:
+// mthd 0x0000, NAME
+.b16 0x000 1
+.b32 ctx_object                     ~0xffffffff
+// mthd 0x0100, NOP
+.b16 0x040 1
+.b32 0x00010000 + cmd_nop           ~0xffffffff
+// mthd 0x0140, PM_TRIGGER
+.b16 0x050 1
+.b32 0x00010000 + cmd_pm_trigger    ~0xffffffff
+ifdef(`NVA3', `
+// mthd 0x0180-0x018c, DMA_
+.b16 0x060 ctx_dma_count
+dispatch_dma:
+.b32 0x00010000 + cmd_dma           ~0xffffffff
+.b32 0x00010000 + cmd_dma           ~0xffffffff
+.b32 0x00010000 + cmd_dma           ~0xffffffff
+',)
+// mthd 0x0200-0x0218, SRC_TILE
+.b16 0x80 7
+.b32 ctx_src_tile_mode              ~0x00000fff
+.b32 ctx_src_xsize                  ~0x0007ffff
+.b32 ctx_src_ysize                  ~0x00001fff
+.b32 ctx_src_zsize                  ~0x000007ff
+.b32 ctx_src_zoff                   ~0x00000fff
+.b32 ctx_src_xoff                   ~0x0007ffff
+.b32 ctx_src_yoff                   ~0x00001fff
+// mthd 0x0220-0x0238, DST_TILE
+.b16 0x88 7
+.b32 ctx_dst_tile_mode              ~0x00000fff
+.b32 ctx_dst_xsize                  ~0x0007ffff
+.b32 ctx_dst_ysize                  ~0x00001fff
+.b32 ctx_dst_zsize                  ~0x000007ff
+.b32 ctx_dst_zoff                   ~0x00000fff
+.b32 ctx_dst_xoff                   ~0x0007ffff
+.b32 ctx_dst_yoff                   ~0x00001fff
+// mthd 0x0300-0x0304, EXEC, WRCACHE_FLUSH
+.b16 0xc0 2
+.b32 0x00010000 + cmd_exec          ~0xffffffff
+.b32 0x00010000 + cmd_wrcache_flush ~0xffffffff
+// mthd 0x030c-0x0340, various stuff
+.b16 0xc3 14
+.b32 ctx_src_address_high           ~0x000000ff
+.b32 ctx_src_address_low            ~0xfffffff0
+.b32 ctx_dst_address_high           ~0x000000ff
+.b32 ctx_dst_address_low            ~0xfffffff0
+.b32 ctx_src_pitch                  ~0x0007ffff
+.b32 ctx_dst_pitch                  ~0x0007ffff
+.b32 ctx_xcnt                       ~0x0000ffff
+.b32 ctx_ycnt                       ~0x00001fff
+.b32 ctx_format                     ~0x0333ffff
+.b32 ctx_swz_const0                 ~0xffffffff
+.b32 ctx_swz_const1                 ~0xffffffff
+.b32 ctx_query_address_high         ~0x000000ff
+.b32 ctx_query_address_low          ~0xffffffff
+.b32 ctx_query_counter              ~0xffffffff
+.b16 0x800 0
+
+ifdef(`NVA3',
+.section nva3_pcopy_code,
+.section nvc0_pcopy_code
+)
+
+main:
+   clear b32 $r0
+   mov $sp $r0
+
+   // setup i0 handler and route fifo and ctxswitch to it
+   mov $r1 ih
+   mov $iv0 $r1
+   mov $r1 0x400
+   movw $r2 0xfff3
+   sethi $r2 0
+   iowr I[$r2 + 0x300] $r2
+
+   // enable interrupts
+   or $r2 0xc
+   iowr I[$r1] $r2
+   bset $flags ie0
+
+   // enable fifo access and context switching
+   mov $r1 0x1200
+   mov $r2 3
+   iowr I[$r1] $r2
+
+   // sleep forever, waking for interrupts
+   bset $flags $p0
+   spin:
+      sleep $p0
+      bra spin
+
+// i0 handler
+ih:
+   iord $r1 I[$r0 + 0x200]
+
+   and $r2 $r1 0x00000008
+   bra e ih_no_chsw
+      call chsw
+   ih_no_chsw:
+   and $r2 $r1 0x00000004
+   bra e ih_no_cmd
+      call dispatch
+
+   ih_no_cmd:
+   and $r1 $r1 0x0000000c
+   iowr I[$r0 + 0x100] $r1
+   iret
+
+// $p1 direction (0 = unload, 1 = load)
+// $r3 channel
+swctx:
+   mov $r4 0x7700
+   mov $xtargets $r4
+ifdef(`NVA3', `
+   // target 7 hardcoded to ctx dma object
+   mov $xdbase $r0
+', ` // NVC0
+   // read SCRATCH3 to decide if we are PCOPY0 or PCOPY1
+   mov $r4 0x2100
+   iord $r4 I[$r4 + 0]
+   and $r4 1
+   shl b32 $r4 4
+   add b32 $r4 0x30
+
+   // channel is in vram
+   mov $r15 0x61c
+   shl b32 $r15 6
+   mov $r5 0x114
+   iowrs I[$r15] $r5
+
+   // read 16-byte PCOPYn info, containing context pointer, from channel
+   shl b32 $r5 $r3 4
+   add b32 $r5 2
+   mov $xdbase $r5
+   mov $r5 $sp
+   // get a chunk of stack space, aligned to 256 byte boundary
+   sub b32 $r5 0x100
+   mov $r6 0xff
+   not b32 $r6
+   and $r5 $r6
+   sethi $r5 0x00020000
+   xdld $r4 $r5
+   xdwait
+   sethi $r5 0
+
+   // set context pointer, from within channel VM
+   mov $r14 0
+   iowrs I[$r15] $r14
+   ld b32 $r4 D[$r5 + 0]
+   shr b32 $r4 8
+   ld b32 $r6 D[$r5 + 4]
+   shl b32 $r6 24
+   or $r4 $r6
+   mov $xdbase $r4
+')
+   // 256-byte context, at start of data segment
+   mov b32 $r4 $r0
+   sethi $r4 0x60000
+
+   // swap!
+   bra $p1 swctx_load
+      xdst $r0 $r4
+      bra swctx_done
+   swctx_load:
+      xdld $r0 $r4
+   swctx_done:
+   xdwait
+   ret
+
+chsw:
+   // read current channel
+   mov $r2 0x1400
+   iord $r3 I[$r2]
+
+   // if it's active, unload it and return
+   xbit $r15 $r3 0x1e
+   bra e chsw_no_unload
+      bclr $flags $p1
+      call swctx
+      bclr $r3 0x1e
+      iowr I[$r2] $r3
+      mov $r4 1
+      iowr I[$r2 + 0x200] $r4
+      ret
+
+   // read next channel
+   chsw_no_unload:
+   iord $r3 I[$r2 + 0x100]
+
+   // is there a channel waiting to be loaded?
+   xbit $r13 $r3 0x1e
+   bra e chsw_finish_load
+      bset $flags $p1
+      call swctx
+ifdef(`NVA3',
+      // load dma objects back into TARGET regs
+      mov $r5 ctx_dma
+      mov $r6 ctx_dma_count
+      chsw_load_ctx_dma:
+         ld b32 $r7 D[$r5 + $r6 * 4]
+         add b32 $r8 $r6 0x180
+         shl b32 $r8 8
+         iowr I[$r8] $r7
+         sub b32 $r6 1
+         bra nc chsw_load_ctx_dma
+,)
+
+   chsw_finish_load:
+   mov $r3 2
+   iowr I[$r2 + 0x200] $r3
+   ret
+
+dispatch:
+   // read incoming fifo command
+   mov $r3 0x1900
+   iord $r2 I[$r3 + 0x100]
+   iord $r3 I[$r3 + 0x000]
+   and $r4 $r2 0x7ff
+   // $r2 will be used to store exception data
+   shl b32 $r2 0x10
+
+   // lookup method in the dispatch table, ILLEGAL_MTHD if not found
+   mov $r5 dispatch_table
+   clear b32 $r6
+   clear b32 $r7
+   dispatch_loop:
+      ld b16 $r6 D[$r5 + 0]
+      ld b16 $r7 D[$r5 + 2]
+      add b32 $r5 4
+      cmpu b32 $r4 $r6
+      bra c dispatch_illegal_mthd
+      add b32 $r7 $r6
+      cmpu b32 $r4 $r7
+      bra c dispatch_valid_mthd
+      sub b32 $r7 $r6
+      shl b32 $r7 3
+      add b32 $r5 $r7
+      bra dispatch_loop
+
+   // ensure no bits set in reserved fields, INVALID_BITFIELD
+   dispatch_valid_mthd:
+   sub b32 $r4 $r6
+   shl b32 $r4 3
+   add b32 $r4 $r5
+   ld b32 $r5 D[$r4 + 4]
+   and $r5 $r3
+   cmpu b32 $r5 0
+   bra ne dispatch_invalid_bitfield
+
+   // depending on dispatch flags: execute method, or save data as state
+   ld b16 $r5 D[$r4 + 0]
+   ld b16 $r6 D[$r4 + 2]
+   cmpu b32 $r6 0
+   bra ne dispatch_cmd
+      st b32 D[$r5] $r3
+      bra dispatch_done
+   dispatch_cmd:
+      bclr $flags $p1
+      call $r5
+      bra $p1 dispatch_error
+      bra dispatch_done
+
+   dispatch_invalid_bitfield:
+   or $r2 2
+   dispatch_illegal_mthd:
+   or $r2 1
+
+   // store exception data in SCRATCH0/SCRATCH1, signal hostirq
+   dispatch_error:
+   mov $r4 0x1000
+   iowr I[$r4 + 0x000] $r2
+   iowr I[$r4 + 0x100] $r3
+   mov $r2 0x40
+   iowr I[$r0] $r2
+   hostirq_wait:
+      iord $r2 I[$r0 + 0x200]
+      and $r2 0x40
+      cmpu b32 $r2 0
+      bra ne hostirq_wait
+
+   dispatch_done:
+   mov $r2 0x1d00
+   mov $r3 1
+   iowr I[$r2] $r3
+   ret
+
+// No-operation
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_nop:
+   ret
+
+// PM_TRIGGER
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_pm_trigger:
+   mov $r2 0x2200
+   clear b32 $r3
+   sethi $r3 0x20000
+   iowr I[$r2] $r3
+   ret
+
+ifdef(`NVA3',
+// SET_DMA_* method handler
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_dma:
+   sub b32 $r4 dispatch_dma
+   shr b32 $r4 1
+   bset $r3 0x1e
+   st b32 D[$r4 + ctx_dma] $r3
+   add b32 $r4 0x600
+   shl b32 $r4 6
+   iowr I[$r4] $r3
+   ret
+,)
+
+// Calculates the hw swizzle mask and adjusts the surface's xcnt to match
+//
+cmd_exec_set_format:
+   // zero out a chunk of the stack to store the swizzle into
+   add $sp -0x10
+   st b32 D[$sp + 0x00] $r0
+   st b32 D[$sp + 0x04] $r0
+   st b32 D[$sp + 0x08] $r0
+   st b32 D[$sp + 0x0c] $r0
+
+   // extract cpp, src_ncomp and dst_ncomp from FORMAT
+   ld b32 $r4 D[$r0 + ctx_format]
+   extr $r5 $r4 16:17
+   add b32 $r5 1
+   extr $r6 $r4 20:21
+   add b32 $r6 1
+   extr $r7 $r4 24:25
+   add b32 $r7 1
+
+   // convert FORMAT swizzle mask to hw swizzle mask
+   bclr $flags $p2
+   clear b32 $r8
+   clear b32 $r9
+   ncomp_loop:
+      and $r10 $r4 0xf
+      shr b32 $r4 4
+      clear b32 $r11
+      bpc_loop:
+         cmpu b8 $r10 4
+         bra nc cmp_c0
+            mulu $r12 $r10 $r5
+            add b32 $r12 $r11
+            bset $flags $p2
+            bra bpc_next
+         cmp_c0:
+         bra ne cmp_c1
+            mov $r12 0x10
+            add b32 $r12 $r11
+            bra bpc_next
+         cmp_c1:
+         cmpu b8 $r10 6
+         bra nc cmp_zero
+            mov $r12 0x14
+            add b32 $r12 $r11
+            bra bpc_next
+         cmp_zero:
+            mov $r12 0x80
+         bpc_next:
+         st b8 D[$sp + $r8] $r12
+         add b32 $r8 1
+         add b32 $r11 1
+         cmpu b32 $r11 $r5
+         bra c bpc_loop
+      add b32 $r9 1
+      cmpu b32 $r9 $r7
+      bra c ncomp_loop
+
+   // SRC_XCNT = (xcnt * src_cpp), or 0 if no src ref in swz (hw will hang)
+   mulu $r6 $r5
+   st b32 D[$r0 + ctx_src_cpp] $r6
+   ld b32 $r8 D[$r0 + ctx_xcnt]
+   mulu $r6 $r8
+   bra $p2 dst_xcnt
+   clear b32 $r6
+
+   dst_xcnt:
+   mulu $r7 $r5
+   st b32 D[$r0 + ctx_dst_cpp] $r7
+   mulu $r7 $r8
+
+   mov $r5 0x810
+   shl b32 $r5 6
+   iowr I[$r5 + 0x000] $r6
+   iowr I[$r5 + 0x100] $r7
+   add b32 $r5 0x800
+   ld b32 $r6 D[$r0 + ctx_dst_cpp]
+   sub b32 $r6 1
+   shl b32 $r6 8
+   ld b32 $r7 D[$r0 + ctx_src_cpp]
+   sub b32 $r7 1
+   or $r6 $r7
+   iowr I[$r5 + 0x000] $r6
+   add b32 $r5 0x100
+   ld b32 $r6 D[$sp + 0x00]
+   iowr I[$r5 + 0x000] $r6
+   ld b32 $r6 D[$sp + 0x04]
+   iowr I[$r5 + 0x100] $r6
+   ld b32 $r6 D[$sp + 0x08]
+   iowr I[$r5 + 0x200] $r6
+   ld b32 $r6 D[$sp + 0x0c]
+   iowr I[$r5 + 0x300] $r6
+   add b32 $r5 0x400
+   ld b32 $r6 D[$r0 + ctx_swz_const0]
+   iowr I[$r5 + 0x000] $r6
+   ld b32 $r6 D[$r0 + ctx_swz_const1]
+   iowr I[$r5 + 0x100] $r6
+   add $sp 0x10
+   ret
+
+// Setup to handle a tiled surface
+//
+// Calculates a number of parameters the hardware requires in order
+// to correctly handle tiling.
+//
+// Offset calculation is performed as follows (Tp/Th/Td from TILE_MODE):
+//    nTx = round_up(w * cpp, 1 << Tp) >> Tp
+//    nTy = round_up(h, 1 << Th) >> Th
+//    Txo = (x * cpp) & ((1 << Tp) - 1)
+//     Tx = (x * cpp) >> Tp
+//    Tyo = y & ((1 << Th) - 1)
+//     Ty = y >> Th
+//    Tzo = z & ((1 << Td) - 1)
+//     Tz = z >> Td
+//
+//    off  = (Tzo << Tp << Th) + (Tyo << Tp) + Txo
+//    off += ((Tz * nTy * nTx)) + (Ty * nTx) + Tx) << Td << Th << Tp;
+//
+// Inputs:
+//    $r4: hw command (0x104800)
+//    $r5: ctx offset adjustment for src/dst selection
+//    $p2: set if dst surface
+//
+cmd_exec_set_surface_tiled:
+   // translate TILE_MODE into Tp, Th, Td shift values
+   ld b32 $r7 D[$r5 + ctx_src_tile_mode]
+   extr $r9 $r7 8:11
+   extr $r8 $r7 4:7
+ifdef(`NVA3',
+   add b32 $r8 2
+,
+   add b32 $r8 3
+)
+   extr $r7 $r7 0:3
+   cmp b32 $r7 0xe
+   bra ne xtile64
+   mov $r7 4
+   bra xtileok
+   xtile64:
+   xbit $r7 $flags $p2
+   add b32 $r7 17
+   bset $r4 $r7
+   mov $r7 6
+   xtileok:
+
+   // Op = (x * cpp) & ((1 << Tp) - 1)
+   // Tx = (x * cpp) >> Tp
+   ld b32 $r10 D[$r5 + ctx_src_xoff]
+   ld b32 $r11 D[$r5 + ctx_src_cpp]
+   mulu $r10 $r11
+   mov $r11 1
+   shl b32 $r11 $r7
+   sub b32 $r11 1
+   and $r12 $r10 $r11
+   shr b32 $r10 $r7
+
+   // Tyo = y & ((1 << Th) - 1)
+   // Ty  = y >> Th
+   ld b32 $r13 D[$r5 + ctx_src_yoff]
+   mov $r14 1
+   shl b32 $r14 $r8
+   sub b32 $r14 1
+   and $r11 $r13 $r14
+   shr b32 $r13 $r8
+
+   // YTILE = ((1 << Th) << 12) | ((1 << Th) - Tyo)
+   add b32 $r14 1
+   shl b32 $r15 $r14 12
+   sub b32 $r14 $r11
+   or $r15 $r14
+   xbit $r6 $flags $p2
+   add b32 $r6 0x208
+   shl b32 $r6 8
+   iowr I[$r6 + 0x000] $r15
+
+   // Op += Tyo << Tp
+   shl b32 $r11 $r7
+   add b32 $r12 $r11
+
+   // nTx = ((w * cpp) + ((1 << Tp) - 1) >> Tp)
+   ld b32 $r15 D[$r5 + ctx_src_xsize]
+   ld b32 $r11 D[$r5 + ctx_src_cpp]
+   mulu $r15 $r11
+   mov $r11 1
+   shl b32 $r11 $r7
+   sub b32 $r11 1
+   add b32 $r15 $r11
+   shr b32 $r15 $r7
+   push $r15
+
+   // nTy = (h + ((1 << Th) - 1)) >> Th
+   ld b32 $r15 D[$r5 + ctx_src_ysize]
+   mov $r11 1
+   shl b32 $r11 $r8
+   sub b32 $r11 1
+   add b32 $r15 $r11
+   shr b32 $r15 $r8
+   push $r15
+
+   // Tys = Tp + Th
+   // CFG_YZ_TILE_SIZE = ((1 << Th) >> 2) << Td
+   add b32 $r7 $r8
+   sub b32 $r8 2
+   mov $r11 1
+   shl b32 $r11 $r8
+   shl b32 $r11 $r9
+
+   // Tzo = z & ((1 << Td) - 1)
+   // Tz  = z >> Td
+   // Op += Tzo << Tys
+   // Ts  = Tys + Td
+   ld b32 $r8 D[$r5 + ctx_src_zoff]
+   mov $r14 1
+   shl b32 $r14 $r9
+   sub b32 $r14 1
+   and $r15 $r8 $r14
+   shl b32 $r15 $r7
+   add b32 $r12 $r15
+   add b32 $r7 $r9
+   shr b32 $r8 $r9
+
+   // Ot = ((Tz * nTy * nTx) + (Ty * nTx) + Tx) << Ts
+   pop $r15
+   pop $r9
+   mulu $r13 $r9
+   add b32 $r10 $r13
+   mulu $r8 $r9
+   mulu $r8 $r15
+   add b32 $r10 $r8
+   shl b32 $r10 $r7
+
+   // PITCH = (nTx - 1) << Ts
+   sub b32 $r9 1
+   shl b32 $r9 $r7
+   iowr I[$r6 + 0x200] $r9
+
+   // SRC_ADDRESS_LOW   = (Ot + Op) & 0xffffffff
+   // CFG_ADDRESS_HIGH |= ((Ot + Op) >> 32) << 16
+   ld b32 $r7 D[$r5 + ctx_src_address_low]
+   ld b32 $r8 D[$r5 + ctx_src_address_high]
+   add b32 $r10 $r12
+   add b32 $r7 $r10
+   adc b32 $r8 0
+   shl b32 $r8 16
+   or $r8 $r11
+   sub b32 $r6 0x600
+   iowr I[$r6 + 0x000] $r7
+   add b32 $r6 0x400
+   iowr I[$r6 + 0x000] $r8
+   ret
+
+// Setup to handle a linear surface
+//
+// Nothing to see here.. Sets ADDRESS and PITCH, pretty non-exciting
+//
+cmd_exec_set_surface_linear:
+   xbit $r6 $flags $p2
+   add b32 $r6 0x202
+   shl b32 $r6 8
+   ld b32 $r7 D[$r5 + ctx_src_address_low]
+   iowr I[$r6 + 0x000] $r7
+   add b32 $r6 0x400
+   ld b32 $r7 D[$r5 + ctx_src_address_high]
+   shl b32 $r7 16
+   iowr I[$r6 + 0x000] $r7
+   add b32 $r6 0x400
+   ld b32 $r7 D[$r5 + ctx_src_pitch]
+   iowr I[$r6 + 0x000] $r7
+   ret
+
+// wait for regs to be available for use
+cmd_exec_wait:
+   push $r0
+   push $r1
+   mov $r0 0x800
+   shl b32 $r0 6
+   loop:
+      iord $r1 I[$r0]
+      and $r1 1
+      bra ne loop
+   pop $r1
+   pop $r0
+   ret
+
+cmd_exec_query:
+   // if QUERY_SHORT not set, write out { -, 0, TIME_LO, TIME_HI }
+   xbit $r4 $r3 13
+   bra ne query_counter
+      call cmd_exec_wait
+      mov $r4 0x80c
+      shl b32 $r4 6
+      ld b32 $r5 D[$r0 + ctx_query_address_low]
+      add b32 $r5 4
+      iowr I[$r4 + 0x000] $r5
+      iowr I[$r4 + 0x100] $r0
+      mov $r5 0xc
+      iowr I[$r4 + 0x200] $r5
+      add b32 $r4 0x400
+      ld b32 $r5 D[$r0 + ctx_query_address_high]
+      shl b32 $r5 16
+      iowr I[$r4 + 0x000] $r5
+      add b32 $r4 0x500
+      mov $r5 0x00000b00
+      sethi $r5 0x00010000
+      iowr I[$r4 + 0x000] $r5
+      mov $r5 0x00004040
+      shl b32 $r5 1
+      sethi $r5 0x80800000
+      iowr I[$r4 + 0x100] $r5
+      mov $r5 0x00001110
+      sethi $r5 0x13120000
+      iowr I[$r4 + 0x200] $r5
+      mov $r5 0x00001514
+      sethi $r5 0x17160000
+      iowr I[$r4 + 0x300] $r5
+      mov $r5 0x00002601
+      sethi $r5 0x00010000
+      mov $r4 0x800
+      shl b32 $r4 6
+      iowr I[$r4 + 0x000] $r5
+
+   // write COUNTER
+   query_counter:
+   call cmd_exec_wait
+   mov $r4 0x80c
+   shl b32 $r4 6
+   ld b32 $r5 D[$r0 + ctx_query_address_low]
+   iowr I[$r4 + 0x000] $r5
+   iowr I[$r4 + 0x100] $r0
+   mov $r5 0x4
+   iowr I[$r4 + 0x200] $r5
+   add b32 $r4 0x400
+   ld b32 $r5 D[$r0 + ctx_query_address_high]
+   shl b32 $r5 16
+   iowr I[$r4 + 0x000] $r5
+   add b32 $r4 0x500
+   mov $r5 0x00000300
+   iowr I[$r4 + 0x000] $r5
+   mov $r5 0x00001110
+   sethi $r5 0x13120000
+   iowr I[$r4 + 0x100] $r5
+   ld b32 $r5 D[$r0 + ctx_query_counter]
+   add b32 $r4 0x500
+   iowr I[$r4 + 0x000] $r5
+   mov $r5 0x00002601
+   sethi $r5 0x00010000
+   mov $r4 0x800
+   shl b32 $r4 6
+   iowr I[$r4 + 0x000] $r5
+   ret
+
+// Execute a copy operation
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//       000002000 QUERY_SHORT
+//       000001000 QUERY
+//       000000100 DST_LINEAR
+//       000000010 SRC_LINEAR
+//       000000001 FORMAT
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_exec:
+   call cmd_exec_wait
+
+   // if format requested, call function to calculate it, otherwise
+   // fill in cpp/xcnt for both surfaces as if (cpp == 1)
+   xbit $r15 $r3 0
+   bra e cmd_exec_no_format
+      call cmd_exec_set_format
+      mov $r4 0x200
+      bra cmd_exec_init_src_surface
+   cmd_exec_no_format:
+      mov $r6 0x810
+      shl b32 $r6 6
+      mov $r7 1
+      st b32 D[$r0 + ctx_src_cpp] $r7
+      st b32 D[$r0 + ctx_dst_cpp] $r7
+      ld b32 $r7 D[$r0 + ctx_xcnt]
+      iowr I[$r6 + 0x000] $r7
+      iowr I[$r6 + 0x100] $r7
+      clear b32 $r4
+
+   cmd_exec_init_src_surface:
+   bclr $flags $p2
+   clear b32 $r5
+   xbit $r15 $r3 4
+   bra e src_tiled
+      call cmd_exec_set_surface_linear
+      bra cmd_exec_init_dst_surface
+   src_tiled:
+      call cmd_exec_set_surface_tiled
+      bset $r4 7
+
+   cmd_exec_init_dst_surface:
+   bset $flags $p2
+   mov $r5 ctx_dst_address_high - ctx_src_address_high
+   xbit $r15 $r3 8
+   bra e dst_tiled
+      call cmd_exec_set_surface_linear
+      bra cmd_exec_kick
+   dst_tiled:
+      call cmd_exec_set_surface_tiled
+      bset $r4 8
+
+   cmd_exec_kick:
+   mov $r5 0x800
+   shl b32 $r5 6
+   ld b32 $r6 D[$r0 + ctx_ycnt]
+   iowr I[$r5 + 0x100] $r6
+   mov $r6 0x0041
+   // SRC_TARGET = 1, DST_TARGET = 2
+   sethi $r6 0x44000000
+   or $r4 $r6
+   iowr I[$r5] $r4
+
+   // if requested, queue up a QUERY write after the copy has completed
+   xbit $r15 $r3 12
+   bra e cmd_exec_done
+      call cmd_exec_query
+
+   cmd_exec_done:
+   ret
+
+// Flush write cache
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_wrcache_flush:
+   mov $r2 0x2200
+   clear b32 $r3
+   sethi $r3 0x10000
+   iowr I[$r2] $r3
+   ret
+
+.align 0x100
diff --git a/drivers/gpu/drm/nouveau/nva3_copy.fuc.h b/drivers/gpu/drm/nouveau/nva3_copy.fuc.h
new file mode 100644 (file)
index 0000000..2731de2
--- /dev/null
@@ -0,0 +1,534 @@
+uint32_t nva3_pcopy_data[] = {
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00010000,
+       0x00000000,
+       0x00000000,
+       0x00010040,
+       0x00010160,
+       0x00000000,
+       0x00010050,
+       0x00010162,
+       0x00000000,
+       0x00030060,
+       0x00010170,
+       0x00000000,
+       0x00010170,
+       0x00000000,
+       0x00010170,
+       0x00000000,
+       0x00070080,
+       0x00000028,
+       0xfffff000,
+       0x0000002c,
+       0xfff80000,
+       0x00000030,
+       0xffffe000,
+       0x00000034,
+       0xfffff800,
+       0x00000038,
+       0xfffff000,
+       0x0000003c,
+       0xfff80000,
+       0x00000040,
+       0xffffe000,
+       0x00070088,
+       0x00000054,
+       0xfffff000,
+       0x00000058,
+       0xfff80000,
+       0x0000005c,
+       0xffffe000,
+       0x00000060,
+       0xfffff800,
+       0x00000064,
+       0xfffff000,
+       0x00000068,
+       0xfff80000,
+       0x0000006c,
+       0xffffe000,
+       0x000200c0,
+       0x00010492,
+       0x00000000,
+       0x0001051b,
+       0x00000000,
+       0x000e00c3,
+       0x0000001c,
+       0xffffff00,
+       0x00000020,
+       0x0000000f,
+       0x00000048,
+       0xffffff00,
+       0x0000004c,
+       0x0000000f,
+       0x00000024,
+       0xfff80000,
+       0x00000050,
+       0xfff80000,
+       0x00000080,
+       0xffff0000,
+       0x00000084,
+       0xffffe000,
+       0x00000074,
+       0xfccc0000,
+       0x00000078,
+       0x00000000,
+       0x0000007c,
+       0x00000000,
+       0x00000010,
+       0xffffff00,
+       0x00000014,
+       0x00000000,
+       0x00000018,
+       0x00000000,
+       0x00000800,
+};
+
+uint32_t nva3_pcopy_code[] = {
+       0x04fe04bd,
+       0x3517f000,
+       0xf10010fe,
+       0xf1040017,
+       0xf0fff327,
+       0x22d00023,
+       0x0c25f0c0,
+       0xf40012d0,
+       0x17f11031,
+       0x27f01200,
+       0x0012d003,
+       0xf40031f4,
+       0x0ef40028,
+       0x8001cffd,
+       0xf40812c4,
+       0x21f4060b,
+       0x0412c472,
+       0xf4060bf4,
+       0x11c4c321,
+       0x4001d00c,
+       0x47f101f8,
+       0x4bfe7700,
+       0x0007fe00,
+       0xf00204b9,
+       0x01f40643,
+       0x0604fa09,
+       0xfa060ef4,
+       0x03f80504,
+       0x27f100f8,
+       0x23cf1400,
+       0x1e3fc800,
+       0xf4170bf4,
+       0x21f40132,
+       0x1e3af052,
+       0xf00023d0,
+       0x24d00147,
+       0xcf00f880,
+       0x3dc84023,
+       0x220bf41e,
+       0xf40131f4,
+       0x57f05221,
+       0x0367f004,
+       0xa07856bc,
+       0xb6018068,
+       0x87d00884,
+       0x0162b600,
+       0xf0f018f4,
+       0x23d00237,
+       0xf100f880,
+       0xcf190037,
+       0x33cf4032,
+       0xff24e400,
+       0x1024b607,
+       0x010057f1,
+       0x74bd64bd,
+       0x58005658,
+       0x50b60157,
+       0x0446b804,
+       0xbb4d08f4,
+       0x47b80076,
+       0x0f08f404,
+       0xb60276bb,
+       0x57bb0374,
+       0xdf0ef400,
+       0xb60246bb,
+       0x45bb0344,
+       0x01459800,
+       0xb00453fd,
+       0x1bf40054,
+       0x00455820,
+       0xb0014658,
+       0x1bf40064,
+       0x00538009,
+       0xf4300ef4,
+       0x55f90132,
+       0xf40c01f4,
+       0x25f0250e,
+       0x0125f002,
+       0x100047f1,
+       0xd00042d0,
+       0x27f04043,
+       0x0002d040,
+       0xf08002cf,
+       0x24b04024,
+       0xf71bf400,
+       0x1d0027f1,
+       0xd00137f0,
+       0x00f80023,
+       0x27f100f8,
+       0x34bd2200,
+       0xd00233f0,
+       0x00f80023,
+       0x012842b7,
+       0xf00145b6,
+       0x43801e39,
+       0x0040b701,
+       0x0644b606,
+       0xf80043d0,
+       0xf030f400,
+       0xb00001b0,
+       0x01b00101,
+       0x0301b002,
+       0xc71d0498,
+       0x50b63045,
+       0x3446c701,
+       0xc70160b6,
+       0x70b63847,
+       0x0232f401,
+       0x94bd84bd,
+       0xb60f4ac4,
+       0xb4bd0445,
+       0xf404a430,
+       0xa5ff0f18,
+       0x00cbbbc0,
+       0xf40231f4,
+       0x1bf4220e,
+       0x10c7f00c,
+       0xf400cbbb,
+       0xa430160e,
+       0x0c18f406,
+       0xbb14c7f0,
+       0x0ef400cb,
+       0x80c7f107,
+       0x01c83800,
+       0xb60180b6,
+       0xb5b801b0,
+       0xc308f404,
+       0xb80190b6,
+       0x08f40497,
+       0x0065fdb2,
+       0x98110680,
+       0x68fd2008,
+       0x0502f400,
+       0x75fd64bd,
+       0x1c078000,
+       0xf10078fd,
+       0xb6081057,
+       0x56d00654,
+       0x4057d000,
+       0x080050b7,
+       0xb61c0698,
+       0x64b60162,
+       0x11079808,
+       0xfd0172b6,
+       0x56d00567,
+       0x0050b700,
+       0x0060b401,
+       0xb40056d0,
+       0x56d00160,
+       0x0260b440,
+       0xb48056d0,
+       0x56d00360,
+       0x0050b7c0,
+       0x1e069804,
+       0x980056d0,
+       0x56d01f06,
+       0x1030f440,
+       0x579800f8,
+       0x6879c70a,
+       0xb66478c7,
+       0x77c70280,
+       0x0e76b060,
+       0xf0091bf4,
+       0x0ef40477,
+       0x027cf00f,
+       0xfd1170b6,
+       0x77f00947,
+       0x0f5a9806,
+       0xfd115b98,
+       0xb7f000ab,
+       0x04b7bb01,
+       0xff01b2b6,
+       0xa7bbc4ab,
+       0x105d9805,
+       0xbb01e7f0,
+       0xe2b604e8,
+       0xb4deff01,
+       0xb605d8bb,
+       0xef9401e0,
+       0x02ebbb0c,
+       0xf005fefd,
+       0x60b7026c,
+       0x64b60208,
+       0x006fd008,
+       0xbb04b7bb,
+       0x5f9800cb,
+       0x115b980b,
+       0xf000fbfd,
+       0xb7bb01b7,
+       0x01b2b604,
+       0xbb00fbbb,
+       0xf0f905f7,
+       0xf00c5f98,
+       0xb8bb01b7,
+       0x01b2b604,
+       0xbb00fbbb,
+       0xf0f905f8,
+       0xb60078bb,
+       0xb7f00282,
+       0x04b8bb01,
+       0x9804b9bb,
+       0xe7f00e58,
+       0x04e9bb01,
+       0xff01e2b6,
+       0xf7bbf48e,
+       0x00cfbb04,
+       0xbb0079bb,
+       0xf0fc0589,
+       0xd9fd90fc,
+       0x00adbb00,
+       0xfd0089fd,
+       0xa8bb008f,
+       0x04a7bb00,
+       0xbb0192b6,
+       0x69d00497,
+       0x08579880,
+       0xbb075898,
+       0x7abb00ac,
+       0x0081b600,
+       0xfd1084b6,
+       0x62b7058b,
+       0x67d00600,
+       0x0060b700,
+       0x0068d004,
+       0x6cf000f8,
+       0x0260b702,
+       0x0864b602,
+       0xd0085798,
+       0x60b70067,
+       0x57980400,
+       0x1074b607,
+       0xb70067d0,
+       0x98040060,
+       0x67d00957,
+       0xf900f800,
+       0xf110f900,
+       0xb6080007,
+       0x01cf0604,
+       0x0114f000,
+       0xfcfa1bf4,
+       0xf800fc10,
+       0x0d34c800,
+       0xf5701bf4,
+       0xf103ab21,
+       0xb6080c47,
+       0x05980644,
+       0x0450b605,
+       0xd00045d0,
+       0x57f04040,
+       0x8045d00c,
+       0x040040b7,
+       0xb6040598,
+       0x45d01054,
+       0x0040b700,
+       0x0057f105,
+       0x0153f00b,
+       0xf10045d0,
+       0xb6404057,
+       0x53f10154,
+       0x45d08080,
+       0x1057f140,
+       0x1253f111,
+       0x8045d013,
+       0x151457f1,
+       0x171653f1,
+       0xf1c045d0,
+       0xf0260157,
+       0x47f10153,
+       0x44b60800,
+       0x0045d006,
+       0x03ab21f5,
+       0x080c47f1,
+       0x980644b6,
+       0x45d00505,
+       0x4040d000,
+       0xd00457f0,
+       0x40b78045,
+       0x05980400,
+       0x1054b604,
+       0xb70045d0,
+       0xf1050040,
+       0xd0030057,
+       0x57f10045,
+       0x53f11110,
+       0x45d01312,
+       0x06059840,
+       0x050040b7,
+       0xf10045d0,
+       0xf0260157,
+       0x47f10153,
+       0x44b60800,
+       0x0045d006,
+       0x21f500f8,
+       0x3fc803ab,
+       0x0e0bf400,
+       0x018921f5,
+       0x020047f1,
+       0xf11e0ef4,
+       0xb6081067,
+       0x77f00664,
+       0x11078001,
+       0x981c0780,
+       0x67d02007,
+       0x4067d000,
+       0x32f444bd,
+       0xc854bd02,
+       0x0bf4043f,
+       0x8221f50a,
+       0x0a0ef403,
+       0x027621f5,
+       0xf40749f0,
+       0x57f00231,
+       0x083fc82c,
+       0xf50a0bf4,
+       0xf4038221,
+       0x21f50a0e,
+       0x49f00276,
+       0x0057f108,
+       0x0654b608,
+       0xd0210698,
+       0x67f04056,
+       0x0063f141,
+       0x0546fd44,
+       0xc80054d0,
+       0x0bf40c3f,
+       0xc521f507,
+       0xf100f803,
+       0xbd220027,
+       0x0133f034,
+       0xf80023d0,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
index dbbafed36406d6609502a0e6ccbeabf0c33dcc66..e4b2b9e934b2733e910ee7f2cab77c6548680857 100644 (file)
 #include "nouveau_bios.h"
 #include "nouveau_pm.h"
 
-/*XXX: boards using limits 0x40 need fixing, the register layout
- *     is correct here, but, there's some other funny magic
- *     that modifies things, so it's not likely we'll set/read
- *     the correct timings yet..  working on it...
+/* This is actually a lot more complex than it appears here, but hopefully
+ * this should be able to deal with what the VBIOS leaves for us..
+ *
+ * If not, well, I'll jump off that bridge when I come to it.
  */
 
 struct nva3_pm_state {
-       struct pll_lims pll;
-       int N, M, P;
+       enum pll_types type;
+       u32 src0;
+       u32 src1;
+       u32 ctrl;
+       u32 coef;
+       u32 old_pnm;
+       u32 new_pnm;
+       u32 new_div;
 };
 
+static int
+nva3_pm_pll_offset(u32 id)
+{
+       static const u32 pll_map[] = {
+               0x00, PLL_CORE,
+               0x01, PLL_SHADER,
+               0x02, PLL_MEMORY,
+               0x00, 0x00
+       };
+       const u32 *map = pll_map;
+
+       while (map[1]) {
+               if (id == map[1])
+                       return map[0];
+               map += 2;
+       }
+
+       return -ENOENT;
+}
+
 int
 nva3_pm_clock_get(struct drm_device *dev, u32 id)
 {
+       u32 src0, src1, ctrl, coef;
        struct pll_lims pll;
-       int P, N, M, ret;
-       u32 reg;
+       int ret, off;
+       int P, N, M;
 
        ret = get_pll_limits(dev, id, &pll);
        if (ret)
                return ret;
 
-       reg = nv_rd32(dev, pll.reg + 4);
-       P = (reg & 0x003f0000) >> 16;
-       N = (reg & 0x0000ff00) >> 8;
-       M = (reg & 0x000000ff);
+       off = nva3_pm_pll_offset(id);
+       if (off < 0)
+               return off;
+
+       src0 = nv_rd32(dev, 0x4120 + (off * 4));
+       src1 = nv_rd32(dev, 0x4160 + (off * 4));
+       ctrl = nv_rd32(dev, pll.reg + 0);
+       coef = nv_rd32(dev, pll.reg + 4);
+       NV_DEBUG(dev, "PLL %02x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                     id, src0, src1, ctrl, coef);
+
+       if (ctrl & 0x00000008) {
+               u32 div = ((src1 & 0x003c0000) >> 18) + 1;
+               return (pll.refclk * 2) / div;
+       }
+
+       P = (coef & 0x003f0000) >> 16;
+       N = (coef & 0x0000ff00) >> 8;
+       M = (coef & 0x000000ff);
        return pll.refclk * N / M / P;
 }
 
@@ -60,36 +102,103 @@ void *
 nva3_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
                  u32 id, int khz)
 {
-       struct nva3_pm_state *state;
-       int dummy, ret;
+       struct nva3_pm_state *pll;
+       struct pll_lims limits;
+       int N, M, P, diff;
+       int ret, off;
+
+       ret = get_pll_limits(dev, id, &limits);
+       if (ret < 0)
+               return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+
+       off = nva3_pm_pll_offset(id);
+       if (id < 0)
+               return ERR_PTR(-EINVAL);
 
-       state = kzalloc(sizeof(*state), GFP_KERNEL);
-       if (!state)
+
+       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+       if (!pll)
                return ERR_PTR(-ENOMEM);
+       pll->type = id;
+       pll->src0 = 0x004120 + (off * 4);
+       pll->src1 = 0x004160 + (off * 4);
+       pll->ctrl = limits.reg + 0;
+       pll->coef = limits.reg + 4;
 
-       ret = get_pll_limits(dev, id, &state->pll);
-       if (ret < 0) {
-               kfree(state);
-               return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+       /* If target clock is within [-2, 3) MHz of a divisor, we'll
+        * use that instead of calculating MNP values
+        */
+       pll->new_div = min((limits.refclk * 2) / (khz - 2999), 16);
+       if (pll->new_div) {
+               diff = khz - ((limits.refclk * 2) / pll->new_div);
+               if (diff < -2000 || diff >= 3000)
+                       pll->new_div = 0;
        }
 
-       ret = nv50_calc_pll2(dev, &state->pll, khz, &state->N, &dummy,
-                            &state->M, &state->P);
-       if (ret < 0) {
-               kfree(state);
-               return ERR_PTR(ret);
+       if (!pll->new_div) {
+               ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P);
+               if (ret < 0)
+                       return ERR_PTR(ret);
+
+               pll->new_pnm = (P << 16) | (N << 8) | M;
+               pll->new_div = 2 - 1;
+       } else {
+               pll->new_pnm = 0;
+               pll->new_div--;
        }
 
-       return state;
+       if ((nv_rd32(dev, pll->src1) & 0x00000101) != 0x00000101)
+               pll->old_pnm = nv_rd32(dev, pll->coef);
+       return pll;
 }
 
 void
 nva3_pm_clock_set(struct drm_device *dev, void *pre_state)
 {
-       struct nva3_pm_state *state = pre_state;
-       u32 reg = state->pll.reg;
+       struct nva3_pm_state *pll = pre_state;
+       u32 ctrl = 0;
+
+       /* For the memory clock, NVIDIA will build a "script" describing
+        * the reclocking process and ask PDAEMON to execute it.
+        */
+       if (pll->type == PLL_MEMORY) {
+               nv_wr32(dev, 0x100210, 0);
+               nv_wr32(dev, 0x1002dc, 1);
+               nv_wr32(dev, 0x004018, 0x00001000);
+               ctrl = 0x18000100;
+       }
+
+       if (pll->old_pnm || !pll->new_pnm) {
+               nv_mask(dev, pll->src1, 0x003c0101, 0x00000101 |
+                                                   (pll->new_div << 18));
+               nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl);
+               nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000);
+       }
+
+       if (pll->new_pnm) {
+               nv_mask(dev, pll->src0, 0x00000101, 0x00000101);
+               nv_wr32(dev, pll->coef, pll->new_pnm);
+               nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl);
+               nv_mask(dev, pll->ctrl, 0x00000010, 0x00000000);
+               nv_mask(dev, pll->ctrl, 0x00020010, 0x00020010);
+               nv_wr32(dev, pll->ctrl, 0x00010015 | ctrl);
+               nv_mask(dev, pll->src1, 0x00000100, 0x00000000);
+               nv_mask(dev, pll->src1, 0x00000001, 0x00000000);
+               if (pll->type == PLL_MEMORY)
+                       nv_wr32(dev, 0x4018, 0x10005000);
+       } else {
+               nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000);
+               nv_mask(dev, pll->src0, 0x00000100, 0x00000000);
+               nv_mask(dev, pll->src0, 0x00000001, 0x00000000);
+               if (pll->type == PLL_MEMORY)
+                       nv_wr32(dev, 0x4018, 0x1000d000);
+       }
+
+       if (pll->type == PLL_MEMORY) {
+               nv_wr32(dev, 0x1002dc, 0);
+               nv_wr32(dev, 0x100210, 0x80000000);
+       }
 
-       nv_wr32(dev, reg + 4, (state->P << 16) | (state->N << 8) | state->M);
-       kfree(state);
+       kfree(pll);
 }
 
diff --git a/drivers/gpu/drm/nouveau/nvc0_copy.c b/drivers/gpu/drm/nouveau/nvc0_copy.c
new file mode 100644 (file)
index 0000000..208fa7a
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs
+ */
+
+#include <linux/firmware.h>
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_util.h"
+#include "nouveau_vm.h"
+#include "nouveau_ramht.h"
+#include "nvc0_copy.fuc.h"
+
+struct nvc0_copy_engine {
+       struct nouveau_exec_engine base;
+       u32 irq;
+       u32 pmc;
+       u32 fuc;
+       u32 ctx;
+};
+
+static int
+nvc0_copy_context_new(struct nouveau_channel *chan, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine);
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *ramin = chan->ramin;
+       struct nouveau_gpuobj *ctx = NULL;
+       int ret;
+
+       ret = nouveau_gpuobj_new(dev, NULL, 256, 256,
+                                NVOBJ_FLAG_VM | NVOBJ_FLAG_VM_USER |
+                                NVOBJ_FLAG_ZERO_ALLOC, &ctx);
+       if (ret)
+               return ret;
+
+       nv_wo32(ramin, pcopy->ctx + 0, lower_32_bits(ctx->vinst));
+       nv_wo32(ramin, pcopy->ctx + 4, upper_32_bits(ctx->vinst));
+       dev_priv->engine.instmem.flush(dev);
+
+       chan->engctx[engine] = ctx;
+       return 0;
+}
+
+static int
+nvc0_copy_object_new(struct nouveau_channel *chan, int engine,
+                    u32 handle, u16 class)
+{
+       return 0;
+}
+
+static void
+nvc0_copy_context_del(struct nouveau_channel *chan, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine);
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
+       struct drm_device *dev = chan->dev;
+       u32 inst;
+
+       inst  = (chan->ramin->vinst >> 12);
+       inst |= 0x40000000;
+
+       /* disable fifo access */
+       nv_wr32(dev, pcopy->fuc + 0x048, 0x00000000);
+       /* mark channel as unloaded if it's currently active */
+       if (nv_rd32(dev, pcopy->fuc + 0x050) == inst)
+               nv_mask(dev, pcopy->fuc + 0x050, 0x40000000, 0x00000000);
+       /* mark next channel as invalid if it's about to be loaded */
+       if (nv_rd32(dev, pcopy->fuc + 0x054) == inst)
+               nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000);
+       /* restore fifo access */
+       nv_wr32(dev, pcopy->fuc + 0x048, 0x00000003);
+
+       nv_wo32(chan->ramin, pcopy->ctx + 0, 0x00000000);
+       nv_wo32(chan->ramin, pcopy->ctx + 4, 0x00000000);
+       nouveau_gpuobj_ref(NULL, &ctx);
+
+       chan->engctx[engine] = ctx;
+}
+
+static int
+nvc0_copy_init(struct drm_device *dev, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+       int i;
+
+       nv_mask(dev, 0x000200, pcopy->pmc, 0x00000000);
+       nv_mask(dev, 0x000200, pcopy->pmc, pcopy->pmc);
+       nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff);
+
+       nv_wr32(dev, pcopy->fuc + 0x1c0, 0x01000000);
+       for (i = 0; i < sizeof(nvc0_pcopy_data) / 4; i++)
+               nv_wr32(dev, pcopy->fuc + 0x1c4, nvc0_pcopy_data[i]);
+
+       nv_wr32(dev, pcopy->fuc + 0x180, 0x01000000);
+       for (i = 0; i < sizeof(nvc0_pcopy_code) / 4; i++) {
+               if ((i & 0x3f) == 0)
+                       nv_wr32(dev, pcopy->fuc + 0x188, i >> 6);
+               nv_wr32(dev, pcopy->fuc + 0x184, nvc0_pcopy_code[i]);
+       }
+
+       nv_wr32(dev, pcopy->fuc + 0x084, engine - NVOBJ_ENGINE_COPY0);
+       nv_wr32(dev, pcopy->fuc + 0x10c, 0x00000000);
+       nv_wr32(dev, pcopy->fuc + 0x104, 0x00000000); /* ENTRY */
+       nv_wr32(dev, pcopy->fuc + 0x100, 0x00000002); /* TRIGGER */
+       return 0;
+}
+
+static int
+nvc0_copy_fini(struct drm_device *dev, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+
+       nv_mask(dev, pcopy->fuc + 0x048, 0x00000003, 0x00000000);
+
+       /* trigger fuc context unload */
+       nv_wait(dev, pcopy->fuc + 0x008, 0x0000000c, 0x00000000);
+       nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000);
+       nv_wr32(dev, pcopy->fuc + 0x000, 0x00000008);
+       nv_wait(dev, pcopy->fuc + 0x008, 0x00000008, 0x00000000);
+
+       nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff);
+       return 0;
+}
+
+static struct nouveau_enum nvc0_copy_isr_error_name[] = {
+       { 0x0001, "ILLEGAL_MTHD" },
+       { 0x0002, "INVALID_ENUM" },
+       { 0x0003, "INVALID_BITFIELD" },
+       {}
+};
+
+static void
+nvc0_copy_isr(struct drm_device *dev, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+       u32 disp = nv_rd32(dev, pcopy->fuc + 0x01c);
+       u32 stat = nv_rd32(dev, pcopy->fuc + 0x008) & disp & ~(disp >> 16);
+       u64 inst = (u64)(nv_rd32(dev, pcopy->fuc + 0x050) & 0x0fffffff) << 12;
+       u32 chid = nvc0_graph_isr_chid(dev, inst);
+       u32 ssta = nv_rd32(dev, pcopy->fuc + 0x040) & 0x0000ffff;
+       u32 addr = nv_rd32(dev, pcopy->fuc + 0x040) >> 16;
+       u32 mthd = (addr & 0x07ff) << 2;
+       u32 subc = (addr & 0x3800) >> 11;
+       u32 data = nv_rd32(dev, pcopy->fuc + 0x044);
+
+       if (stat & 0x00000040) {
+               NV_INFO(dev, "PCOPY: DISPATCH_ERROR [");
+               nouveau_enum_print(nvc0_copy_isr_error_name, ssta);
+               printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n",
+                       chid, inst, subc, mthd, data);
+               nv_wr32(dev, pcopy->fuc + 0x004, 0x00000040);
+               stat &= ~0x00000040;
+       }
+
+       if (stat) {
+               NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat);
+               nv_wr32(dev, pcopy->fuc + 0x004, stat);
+       }
+}
+
+static void
+nvc0_copy_isr_0(struct drm_device *dev)
+{
+       nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY0);
+}
+
+static void
+nvc0_copy_isr_1(struct drm_device *dev)
+{
+       nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY1);
+}
+
+static void
+nvc0_copy_destroy(struct drm_device *dev, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, pcopy->irq);
+
+       if (engine == NVOBJ_ENGINE_COPY0)
+               NVOBJ_ENGINE_DEL(dev, COPY0);
+       else
+               NVOBJ_ENGINE_DEL(dev, COPY1);
+       kfree(pcopy);
+}
+
+int
+nvc0_copy_create(struct drm_device *dev, int engine)
+{
+       struct nvc0_copy_engine *pcopy;
+
+       pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL);
+       if (!pcopy)
+               return -ENOMEM;
+
+       pcopy->base.destroy = nvc0_copy_destroy;
+       pcopy->base.init = nvc0_copy_init;
+       pcopy->base.fini = nvc0_copy_fini;
+       pcopy->base.context_new = nvc0_copy_context_new;
+       pcopy->base.context_del = nvc0_copy_context_del;
+       pcopy->base.object_new = nvc0_copy_object_new;
+
+       if (engine == 0) {
+               pcopy->irq = 5;
+               pcopy->pmc = 0x00000040;
+               pcopy->fuc = 0x104000;
+               pcopy->ctx = 0x0230;
+               nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_0);
+               NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base);
+               NVOBJ_CLASS(dev, 0x90b5, COPY0);
+       } else {
+               pcopy->irq = 6;
+               pcopy->pmc = 0x00000080;
+               pcopy->fuc = 0x105000;
+               pcopy->ctx = 0x0240;
+               nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_1);
+               NVOBJ_ENGINE_ADD(dev, COPY1, &pcopy->base);
+               NVOBJ_CLASS(dev, 0x90b8, COPY1);
+       }
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h b/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h
new file mode 100644 (file)
index 0000000..4199038
--- /dev/null
@@ -0,0 +1,527 @@
+uint32_t nvc0_pcopy_data[] = {
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00010000,
+       0x00000000,
+       0x00000000,
+       0x00010040,
+       0x0001019f,
+       0x00000000,
+       0x00010050,
+       0x000101a1,
+       0x00000000,
+       0x00070080,
+       0x0000001c,
+       0xfffff000,
+       0x00000020,
+       0xfff80000,
+       0x00000024,
+       0xffffe000,
+       0x00000028,
+       0xfffff800,
+       0x0000002c,
+       0xfffff000,
+       0x00000030,
+       0xfff80000,
+       0x00000034,
+       0xffffe000,
+       0x00070088,
+       0x00000048,
+       0xfffff000,
+       0x0000004c,
+       0xfff80000,
+       0x00000050,
+       0xffffe000,
+       0x00000054,
+       0xfffff800,
+       0x00000058,
+       0xfffff000,
+       0x0000005c,
+       0xfff80000,
+       0x00000060,
+       0xffffe000,
+       0x000200c0,
+       0x000104b8,
+       0x00000000,
+       0x00010541,
+       0x00000000,
+       0x000e00c3,
+       0x00000010,
+       0xffffff00,
+       0x00000014,
+       0x0000000f,
+       0x0000003c,
+       0xffffff00,
+       0x00000040,
+       0x0000000f,
+       0x00000018,
+       0xfff80000,
+       0x00000044,
+       0xfff80000,
+       0x00000074,
+       0xffff0000,
+       0x00000078,
+       0xffffe000,
+       0x00000068,
+       0xfccc0000,
+       0x0000006c,
+       0x00000000,
+       0x00000070,
+       0x00000000,
+       0x00000004,
+       0xffffff00,
+       0x00000008,
+       0x00000000,
+       0x0000000c,
+       0x00000000,
+       0x00000800,
+};
+
+uint32_t nvc0_pcopy_code[] = {
+       0x04fe04bd,
+       0x3517f000,
+       0xf10010fe,
+       0xf1040017,
+       0xf0fff327,
+       0x22d00023,
+       0x0c25f0c0,
+       0xf40012d0,
+       0x17f11031,
+       0x27f01200,
+       0x0012d003,
+       0xf40031f4,
+       0x0ef40028,
+       0x8001cffd,
+       0xf40812c4,
+       0x21f4060b,
+       0x0412c4ca,
+       0xf5070bf4,
+       0xc4010221,
+       0x01d00c11,
+       0xf101f840,
+       0xfe770047,
+       0x47f1004b,
+       0x44cf2100,
+       0x0144f000,
+       0xb60444b6,
+       0xf7f13040,
+       0xf4b6061c,
+       0x1457f106,
+       0x00f5d101,
+       0xb6043594,
+       0x57fe0250,
+       0x0145fe00,
+       0x010052b7,
+       0x00ff67f1,
+       0x56fd60bd,
+       0x0253f004,
+       0xf80545fa,
+       0x0053f003,
+       0xd100e7f0,
+       0x549800fe,
+       0x0845b600,
+       0xb6015698,
+       0x46fd1864,
+       0x0047fe05,
+       0xf00204b9,
+       0x01f40643,
+       0x0604fa09,
+       0xfa060ef4,
+       0x03f80504,
+       0x27f100f8,
+       0x23cf1400,
+       0x1e3fc800,
+       0xf4170bf4,
+       0x21f40132,
+       0x1e3af053,
+       0xf00023d0,
+       0x24d00147,
+       0xcf00f880,
+       0x3dc84023,
+       0x090bf41e,
+       0xf40131f4,
+       0x37f05321,
+       0x8023d002,
+       0x37f100f8,
+       0x32cf1900,
+       0x0033cf40,
+       0x07ff24e4,
+       0xf11024b6,
+       0xbd010057,
+       0x5874bd64,
+       0x57580056,
+       0x0450b601,
+       0xf40446b8,
+       0x76bb4d08,
+       0x0447b800,
+       0xbb0f08f4,
+       0x74b60276,
+       0x0057bb03,
+       0xbbdf0ef4,
+       0x44b60246,
+       0x0045bb03,
+       0xfd014598,
+       0x54b00453,
+       0x201bf400,
+       0x58004558,
+       0x64b00146,
+       0x091bf400,
+       0xf4005380,
+       0x32f4300e,
+       0xf455f901,
+       0x0ef40c01,
+       0x0225f025,
+       0xf10125f0,
+       0xd0100047,
+       0x43d00042,
+       0x4027f040,
+       0xcf0002d0,
+       0x24f08002,
+       0x0024b040,
+       0xf1f71bf4,
+       0xf01d0027,
+       0x23d00137,
+       0xf800f800,
+       0x0027f100,
+       0xf034bd22,
+       0x23d00233,
+       0xf400f800,
+       0x01b0f030,
+       0x0101b000,
+       0xb00201b0,
+       0x04980301,
+       0x3045c71a,
+       0xc70150b6,
+       0x60b63446,
+       0x3847c701,
+       0xf40170b6,
+       0x84bd0232,
+       0x4ac494bd,
+       0x0445b60f,
+       0xa430b4bd,
+       0x0f18f404,
+       0xbbc0a5ff,
+       0x31f400cb,
+       0x220ef402,
+       0xf00c1bf4,
+       0xcbbb10c7,
+       0x160ef400,
+       0xf406a430,
+       0xc7f00c18,
+       0x00cbbb14,
+       0xf1070ef4,
+       0x380080c7,
+       0x80b601c8,
+       0x01b0b601,
+       0xf404b5b8,
+       0x90b6c308,
+       0x0497b801,
+       0xfdb208f4,
+       0x06800065,
+       0x1d08980e,
+       0xf40068fd,
+       0x64bd0502,
+       0x800075fd,
+       0x78fd1907,
+       0x1057f100,
+       0x0654b608,
+       0xd00056d0,
+       0x50b74057,
+       0x06980800,
+       0x0162b619,
+       0x980864b6,
+       0x72b60e07,
+       0x0567fd01,
+       0xb70056d0,
+       0xb4010050,
+       0x56d00060,
+       0x0160b400,
+       0xb44056d0,
+       0x56d00260,
+       0x0360b480,
+       0xb7c056d0,
+       0x98040050,
+       0x56d01b06,
+       0x1c069800,
+       0xf44056d0,
+       0x00f81030,
+       0xc7075798,
+       0x78c76879,
+       0x0380b664,
+       0xb06077c7,
+       0x1bf40e76,
+       0x0477f009,
+       0xf00f0ef4,
+       0x70b6027c,
+       0x0947fd11,
+       0x980677f0,
+       0x5b980c5a,
+       0x00abfd0e,
+       0xbb01b7f0,
+       0xb2b604b7,
+       0xc4abff01,
+       0x9805a7bb,
+       0xe7f00d5d,
+       0x04e8bb01,
+       0xff01e2b6,
+       0xd8bbb4de,
+       0x01e0b605,
+       0xbb0cef94,
+       0xfefd02eb,
+       0x026cf005,
+       0x020860b7,
+       0xd00864b6,
+       0xb7bb006f,
+       0x00cbbb04,
+       0x98085f98,
+       0xfbfd0e5b,
+       0x01b7f000,
+       0xb604b7bb,
+       0xfbbb01b2,
+       0x05f7bb00,
+       0x5f98f0f9,
+       0x01b7f009,
+       0xb604b8bb,
+       0xfbbb01b2,
+       0x05f8bb00,
+       0x78bbf0f9,
+       0x0282b600,
+       0xbb01b7f0,
+       0xb9bb04b8,
+       0x0b589804,
+       0xbb01e7f0,
+       0xe2b604e9,
+       0xf48eff01,
+       0xbb04f7bb,
+       0x79bb00cf,
+       0x0589bb00,
+       0x90fcf0fc,
+       0xbb00d9fd,
+       0x89fd00ad,
+       0x008ffd00,
+       0xbb00a8bb,
+       0x92b604a7,
+       0x0497bb01,
+       0x988069d0,
+       0x58980557,
+       0x00acbb04,
+       0xb6007abb,
+       0x84b60081,
+       0x058bfd10,
+       0x060062b7,
+       0xb70067d0,
+       0xd0040060,
+       0x00f80068,
+       0xb7026cf0,
+       0xb6020260,
+       0x57980864,
+       0x0067d005,
+       0x040060b7,
+       0xb6045798,
+       0x67d01074,
+       0x0060b700,
+       0x06579804,
+       0xf80067d0,
+       0xf900f900,
+       0x0007f110,
+       0x0604b608,
+       0xf00001cf,
+       0x1bf40114,
+       0xfc10fcfa,
+       0xc800f800,
+       0x1bf40d34,
+       0xd121f570,
+       0x0c47f103,
+       0x0644b608,
+       0xb6020598,
+       0x45d00450,
+       0x4040d000,
+       0xd00c57f0,
+       0x40b78045,
+       0x05980400,
+       0x1054b601,
+       0xb70045d0,
+       0xf1050040,
+       0xf00b0057,
+       0x45d00153,
+       0x4057f100,
+       0x0154b640,
+       0x808053f1,
+       0xf14045d0,
+       0xf1111057,
+       0xd0131253,
+       0x57f18045,
+       0x53f11514,
+       0x45d01716,
+       0x0157f1c0,
+       0x0153f026,
+       0x080047f1,
+       0xd00644b6,
+       0x21f50045,
+       0x47f103d1,
+       0x44b6080c,
+       0x02059806,
+       0xd00045d0,
+       0x57f04040,
+       0x8045d004,
+       0x040040b7,
+       0xb6010598,
+       0x45d01054,
+       0x0040b700,
+       0x0057f105,
+       0x0045d003,
+       0x111057f1,
+       0x131253f1,
+       0x984045d0,
+       0x40b70305,
+       0x45d00500,
+       0x0157f100,
+       0x0153f026,
+       0x080047f1,
+       0xd00644b6,
+       0x00f80045,
+       0x03d121f5,
+       0xf4003fc8,
+       0x21f50e0b,
+       0x47f101af,
+       0x0ef40200,
+       0x1067f11e,
+       0x0664b608,
+       0x800177f0,
+       0x07800e07,
+       0x1d079819,
+       0xd00067d0,
+       0x44bd4067,
+       0xbd0232f4,
+       0x043fc854,
+       0xf50a0bf4,
+       0xf403a821,
+       0x21f50a0e,
+       0x49f0029c,
+       0x0231f407,
+       0xc82c57f0,
+       0x0bf4083f,
+       0xa821f50a,
+       0x0a0ef403,
+       0x029c21f5,
+       0xf10849f0,
+       0xb6080057,
+       0x06980654,
+       0x4056d01e,
+       0xf14167f0,
+       0xfd440063,
+       0x54d00546,
+       0x0c3fc800,
+       0xf5070bf4,
+       0xf803eb21,
+       0x0027f100,
+       0xf034bd22,
+       0x23d00133,
+       0x0000f800,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
index 2886f2726a9e07ebe25eddb484a061fa2990a503..fb4f5943e01b5f947ee3119ef0988eda83b98171 100644 (file)
@@ -37,7 +37,7 @@ struct nvc0_fifo_priv {
 };
 
 struct nvc0_fifo_chan {
-       struct nouveau_bo *user;
+       struct nouveau_gpuobj *user;
        struct nouveau_gpuobj *ramfc;
 };
 
@@ -106,7 +106,7 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        struct nvc0_fifo_priv *priv = pfifo->priv;
        struct nvc0_fifo_chan *fifoch;
-       u64 ib_virt, user_vinst;
+       u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
        int ret;
 
        chan->fifo_priv = kzalloc(sizeof(*fifoch), GFP_KERNEL);
@@ -115,28 +115,13 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
        fifoch = chan->fifo_priv;
 
        /* allocate vram for control regs, map into polling area */
-       ret = nouveau_bo_new(dev, NULL, 0x1000, 0, TTM_PL_FLAG_VRAM,
-                            0, 0, &fifoch->user);
+       ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000,
+                                NVOBJ_FLAG_ZERO_ALLOC, &fifoch->user);
        if (ret)
                goto error;
 
-       ret = nouveau_bo_pin(fifoch->user, TTM_PL_FLAG_VRAM);
-       if (ret) {
-               nouveau_bo_ref(NULL, &fifoch->user);
-               goto error;
-       }
-
-       user_vinst = fifoch->user->bo.mem.start << PAGE_SHIFT;
-
-       ret = nouveau_bo_map(fifoch->user);
-       if (ret) {
-               nouveau_bo_unpin(fifoch->user);
-               nouveau_bo_ref(NULL, &fifoch->user);
-               goto error;
-       }
-
        nouveau_vm_map_at(&priv->user_vma, chan->id * 0x1000,
-                         fifoch->user->bo.mem.mm_node);
+                         *(struct nouveau_mem **)fifoch->user->node);
 
        chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) +
                                priv->user_vma.offset + (chan->id * 0x1000),
@@ -146,20 +131,6 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
                goto error;
        }
 
-       ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
-
-       /* zero channel regs */
-       nouveau_bo_wr32(fifoch->user, 0x0040/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0044/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0048/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x004c/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0050/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0058/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x005c/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0060/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0088/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x008c/4, 0);
-
        /* ramfc */
        ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst,
                                      chan->ramin->vinst, 0x100,
@@ -167,8 +138,8 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
        if (ret)
                goto error;
 
-       nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(user_vinst));
-       nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(user_vinst));
+       nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(fifoch->user->vinst));
+       nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(fifoch->user->vinst));
        nv_wo32(fifoch->ramfc, 0x10, 0x0000face);
        nv_wo32(fifoch->ramfc, 0x30, 0xfffff902);
        nv_wo32(fifoch->ramfc, 0x48, lower_32_bits(ib_virt));
@@ -223,11 +194,7 @@ nvc0_fifo_destroy_context(struct nouveau_channel *chan)
                return;
 
        nouveau_gpuobj_ref(NULL, &fifoch->ramfc);
-       if (fifoch->user) {
-               nouveau_bo_unmap(fifoch->user);
-               nouveau_bo_unpin(fifoch->user);
-               nouveau_bo_ref(NULL, &fifoch->user);
-       }
+       nouveau_gpuobj_ref(NULL, &fifoch->user);
        kfree(fifoch);
 }
 
@@ -240,6 +207,21 @@ nvc0_fifo_load_context(struct nouveau_channel *chan)
 int
 nvc0_fifo_unload_context(struct drm_device *dev)
 {
+       int i;
+
+       for (i = 0; i < 128; i++) {
+               if (!(nv_rd32(dev, 0x003004 + (i * 4)) & 1))
+                       continue;
+
+               nv_mask(dev, 0x003004 + (i * 4), 0x00000001, 0x00000000);
+               nv_wr32(dev, 0x002634, i);
+               if (!nv_wait(dev, 0x002634, 0xffffffff, i)) {
+                       NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n",
+                               i, nv_rd32(dev, 0x002634));
+                       return -EBUSY;
+               }
+       }
+
        return 0;
 }
 
@@ -309,6 +291,7 @@ nvc0_fifo_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+       struct nouveau_channel *chan;
        struct nvc0_fifo_priv *priv;
        int ret, i;
 
@@ -351,23 +334,74 @@ nvc0_fifo_init(struct drm_device *dev)
        nv_wr32(dev, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */
        nv_wr32(dev, 0x002100, 0xffffffff);
        nv_wr32(dev, 0x002140, 0xbfffffff);
+
+       /* restore PFIFO context table */
+       for (i = 0; i < 128; i++) {
+               chan = dev_priv->channels.ptr[i];
+               if (!chan || !chan->fifo_priv)
+                       continue;
+
+               nv_wr32(dev, 0x003000 + (i * 8), 0xc0000000 |
+                                                (chan->ramin->vinst >> 12));
+               nv_wr32(dev, 0x003004 + (i * 8), 0x001f0001);
+       }
+       nvc0_fifo_playlist_update(dev);
+
        return 0;
 }
 
 struct nouveau_enum nvc0_fifo_fault_unit[] = {
-       { 0, "PGRAPH" },
-       { 3, "PEEPHOLE" },
-       { 4, "BAR1" },
-       { 5, "BAR3" },
-       { 7, "PFIFO" },
+       { 0x00, "PGRAPH" },
+       { 0x03, "PEEPHOLE" },
+       { 0x04, "BAR1" },
+       { 0x05, "BAR3" },
+       { 0x07, "PFIFO" },
+       { 0x10, "PBSP" },
+       { 0x11, "PPPP" },
+       { 0x13, "PCOUNTER" },
+       { 0x14, "PVP" },
+       { 0x15, "PCOPY0" },
+       { 0x16, "PCOPY1" },
+       { 0x17, "PDAEMON" },
        {}
 };
 
 struct nouveau_enum nvc0_fifo_fault_reason[] = {
-       { 0, "PT_NOT_PRESENT" },
-       { 1, "PT_TOO_SHORT" },
-       { 2, "PAGE_NOT_PRESENT" },
-       { 3, "VM_LIMIT_EXCEEDED" },
+       { 0x00, "PT_NOT_PRESENT" },
+       { 0x01, "PT_TOO_SHORT" },
+       { 0x02, "PAGE_NOT_PRESENT" },
+       { 0x03, "VM_LIMIT_EXCEEDED" },
+       { 0x04, "NO_CHANNEL" },
+       { 0x05, "PAGE_SYSTEM_ONLY" },
+       { 0x06, "PAGE_READ_ONLY" },
+       { 0x0a, "COMPRESSED_SYSRAM" },
+       { 0x0c, "INVALID_STORAGE_TYPE" },
+       {}
+};
+
+struct nouveau_enum nvc0_fifo_fault_hubclient[] = {
+       { 0x01, "PCOPY0" },
+       { 0x02, "PCOPY1" },
+       { 0x04, "DISPATCH" },
+       { 0x05, "CTXCTL" },
+       { 0x06, "PFIFO" },
+       { 0x07, "BAR_READ" },
+       { 0x08, "BAR_WRITE" },
+       { 0x0b, "PVP" },
+       { 0x0c, "PPPP" },
+       { 0x0d, "PBSP" },
+       { 0x11, "PCOUNTER" },
+       { 0x12, "PDAEMON" },
+       { 0x14, "CCACHE" },
+       { 0x15, "CCACHE_POST" },
+       {}
+};
+
+struct nouveau_enum nvc0_fifo_fault_gpcclient[] = {
+       { 0x01, "TEX" },
+       { 0x0c, "ESETUP" },
+       { 0x0e, "CTXCTL" },
+       { 0x0f, "PROP" },
        {}
 };
 
@@ -385,12 +419,20 @@ nvc0_fifo_isr_vm_fault(struct drm_device *dev, int unit)
        u32 valo = nv_rd32(dev, 0x2804 + (unit * 0x10));
        u32 vahi = nv_rd32(dev, 0x2808 + (unit * 0x10));
        u32 stat = nv_rd32(dev, 0x280c + (unit * 0x10));
+       u32 client = (stat & 0x00001f00) >> 8;
 
        NV_INFO(dev, "PFIFO: %s fault at 0x%010llx [",
                (stat & 0x00000080) ? "write" : "read", (u64)vahi << 32 | valo);
        nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f);
        printk("] from ");
        nouveau_enum_print(nvc0_fifo_fault_unit, unit);
+       if (stat & 0x00000040) {
+               printk("/");
+               nouveau_enum_print(nvc0_fifo_fault_hubclient, client);
+       } else {
+               printk("/GPC%d/", (stat & 0x1f000000) >> 24);
+               nouveau_enum_print(nvc0_fifo_fault_gpcclient, client);
+       }
        printk(" on channel 0x%010llx\n", (u64)inst << 12);
 }
 
index 3de9b721d8dbe61260af7487ce086fc23acaa758..ca6db204d644711dafcaa8e9eaf2c88deada27ae 100644 (file)
 #include "nouveau_mm.h"
 #include "nvc0_graph.h"
 
-static void nvc0_graph_isr(struct drm_device *);
-static void nvc0_runk140_isr(struct drm_device *);
-static int  nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan);
-
-void
-nvc0_graph_fifo_access(struct drm_device *dev, bool enabled)
+static int
+nvc0_graph_load_context(struct nouveau_channel *chan)
 {
+       struct drm_device *dev = chan->dev;
+
+       nv_wr32(dev, 0x409840, 0x00000030);
+       nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12);
+       nv_wr32(dev, 0x409504, 0x00000003);
+       if (!nv_wait(dev, 0x409800, 0x00000010, 0x00000010))
+               NV_ERROR(dev, "PGRAPH: load_ctx timeout\n");
+
+       return 0;
 }
 
-struct nouveau_channel *
-nvc0_graph_channel(struct drm_device *dev)
+static int
+nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan)
 {
-       return NULL;
+       nv_wr32(dev, 0x409840, 0x00000003);
+       nv_wr32(dev, 0x409500, 0x80000000 | chan >> 12);
+       nv_wr32(dev, 0x409504, 0x00000009);
+       if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000000)) {
+               NV_ERROR(dev, "PGRAPH: unload_ctx timeout\n");
+               return -EBUSY;
+       }
+
+       return 0;
 }
 
 static int
 nvc0_graph_construct_context(struct nouveau_channel *chan)
 {
        struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
-       struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+       struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+       struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
        struct drm_device *dev = chan->dev;
        int ret, i;
        u32 *ctx;
@@ -89,9 +102,8 @@ nvc0_graph_construct_context(struct nouveau_channel *chan)
 static int
 nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan)
 {
-       struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
-       struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+       struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+       struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
        struct drm_device *dev = chan->dev;
        int i = 0, gpc, tp, ret;
        u32 magic;
@@ -158,29 +170,27 @@ nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan)
        return 0;
 }
 
-int
-nvc0_graph_create_context(struct nouveau_channel *chan)
+static int
+nvc0_graph_context_new(struct nouveau_channel *chan, int engine)
 {
-       struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nvc0_graph_priv *priv = pgraph->priv;
+       struct nvc0_graph_priv *priv = nv_engine(dev, engine);
        struct nvc0_graph_chan *grch;
-       struct drm_device *dev = chan->dev;
        struct nouveau_gpuobj *grctx;
        int ret, i;
 
-       chan->pgraph_ctx = kzalloc(sizeof(*grch), GFP_KERNEL);
-       if (!chan->pgraph_ctx)
+       grch = kzalloc(sizeof(*grch), GFP_KERNEL);
+       if (!grch)
                return -ENOMEM;
-       grch = chan->pgraph_ctx;
+       chan->engctx[NVOBJ_ENGINE_GR] = grch;
 
        ret = nouveau_gpuobj_new(dev, NULL, priv->grctx_size, 256,
                                 NVOBJ_FLAG_VM | NVOBJ_FLAG_ZERO_ALLOC,
                                 &grch->grctx);
        if (ret)
                goto error;
-       chan->ramin_grctx = grch->grctx;
        grctx = grch->grctx;
 
        ret = nvc0_graph_create_context_mmio_list(chan);
@@ -200,104 +210,49 @@ nvc0_graph_create_context(struct nouveau_channel *chan)
        for (i = 0; i < priv->grctx_size; i += 4)
                nv_wo32(grctx, i, priv->grctx_vals[i / 4]);
 
-        nv_wo32(grctx, 0xf4, 0);
-        nv_wo32(grctx, 0xf8, 0);
-        nv_wo32(grctx, 0x10, grch->mmio_nr);
-        nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio->vinst));
-        nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->vinst));
-        nv_wo32(grctx, 0x1c, 1);
-        nv_wo32(grctx, 0x20, 0);
-        nv_wo32(grctx, 0x28, 0);
-        nv_wo32(grctx, 0x2c, 0);
+       nv_wo32(grctx, 0xf4, 0);
+       nv_wo32(grctx, 0xf8, 0);
+       nv_wo32(grctx, 0x10, grch->mmio_nr);
+       nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio->vinst));
+       nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->vinst));
+       nv_wo32(grctx, 0x1c, 1);
+       nv_wo32(grctx, 0x20, 0);
+       nv_wo32(grctx, 0x28, 0);
+       nv_wo32(grctx, 0x2c, 0);
        pinstmem->flush(dev);
        return 0;
 
 error:
-       pgraph->destroy_context(chan);
+       priv->base.context_del(chan, engine);
        return ret;
 }
 
-void
-nvc0_graph_destroy_context(struct nouveau_channel *chan)
+static void
+nvc0_graph_context_del(struct nouveau_channel *chan, int engine)
 {
-       struct nvc0_graph_chan *grch;
-
-       grch = chan->pgraph_ctx;
-       chan->pgraph_ctx = NULL;
-       if (!grch)
-               return;
+       struct nvc0_graph_chan *grch = chan->engctx[engine];
 
        nouveau_gpuobj_ref(NULL, &grch->mmio);
        nouveau_gpuobj_ref(NULL, &grch->unk418810);
        nouveau_gpuobj_ref(NULL, &grch->unk40800c);
        nouveau_gpuobj_ref(NULL, &grch->unk408004);
        nouveau_gpuobj_ref(NULL, &grch->grctx);
-       chan->ramin_grctx = NULL;
+       chan->engctx[engine] = NULL;
 }
 
-int
-nvc0_graph_load_context(struct nouveau_channel *chan)
+static int
+nvc0_graph_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
 {
-       struct drm_device *dev = chan->dev;
-
-       nv_wr32(dev, 0x409840, 0x00000030);
-       nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12);
-       nv_wr32(dev, 0x409504, 0x00000003);
-       if (!nv_wait(dev, 0x409800, 0x00000010, 0x00000010))
-               NV_ERROR(dev, "PGRAPH: load_ctx timeout\n");
-
        return 0;
 }
 
 static int
-nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan)
+nvc0_graph_fini(struct drm_device *dev, int engine)
 {
-       nv_wr32(dev, 0x409840, 0x00000003);
-       nv_wr32(dev, 0x409500, 0x80000000 | chan >> 12);
-       nv_wr32(dev, 0x409504, 0x00000009);
-       if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000000)) {
-               NV_ERROR(dev, "PGRAPH: unload_ctx timeout\n");
-               return -EBUSY;
-       }
-
        return 0;
 }
 
-int
-nvc0_graph_unload_context(struct drm_device *dev)
-{
-       u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12;
-       return nvc0_graph_unload_context_to(dev, inst);
-}
-
-static void
-nvc0_graph_destroy(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nvc0_graph_priv *priv;
-
-       priv = pgraph->priv;
-       if (!priv)
-               return;
-
-       nouveau_irq_unregister(dev, 12);
-       nouveau_irq_unregister(dev, 25);
-
-       nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
-       nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
-
-       if (priv->grctx_vals)
-               kfree(priv->grctx_vals);
-       kfree(priv);
-}
-
-void
-nvc0_graph_takedown(struct drm_device *dev)
-{
-       nvc0_graph_destroy(dev);
-}
-
 static int
 nvc0_graph_mthd_page_flip(struct nouveau_channel *chan,
                          u32 class, u32 mthd, u32 data)
@@ -306,119 +261,10 @@ nvc0_graph_mthd_page_flip(struct nouveau_channel *chan,
        return 0;
 }
 
-static int
-nvc0_graph_create(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nvc0_graph_priv *priv;
-       int ret, gpc, i;
-
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-       pgraph->priv = priv;
-
-       ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
-       if (ret)
-               goto error;
-
-       ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8);
-       if (ret)
-               goto error;
-
-       for (i = 0; i < 0x1000; i += 4) {
-               nv_wo32(priv->unk4188b4, i, 0x00000010);
-               nv_wo32(priv->unk4188b8, i, 0x00000010);
-       }
-
-       priv->gpc_nr  =  nv_rd32(dev, 0x409604) & 0x0000001f;
-       priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16;
-       for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-               priv->tp_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608));
-               priv->tp_total += priv->tp_nr[gpc];
-       }
-
-       /*XXX: these need figuring out... */
-       switch (dev_priv->chipset) {
-       case 0xc0:
-               if (priv->tp_total == 11) { /* 465, 3/4/4/0, 4 */
-                       priv->magic_not_rop_nr = 0x07;
-                       /* filled values up to tp_total, the rest 0 */
-                       priv->magicgpc980[0]   = 0x22111000;
-                       priv->magicgpc980[1]   = 0x00000233;
-                       priv->magicgpc980[2]   = 0x00000000;
-                       priv->magicgpc980[3]   = 0x00000000;
-                       priv->magicgpc918      = 0x000ba2e9;
-               } else
-               if (priv->tp_total == 14) { /* 470, 3/3/4/4, 5 */
-                       priv->magic_not_rop_nr = 0x05;
-                       priv->magicgpc980[0]   = 0x11110000;
-                       priv->magicgpc980[1]   = 0x00233222;
-                       priv->magicgpc980[2]   = 0x00000000;
-                       priv->magicgpc980[3]   = 0x00000000;
-                       priv->magicgpc918      = 0x00092493;
-               } else
-               if (priv->tp_total == 15) { /* 480, 3/4/4/4, 6 */
-                       priv->magic_not_rop_nr = 0x06;
-                       priv->magicgpc980[0]   = 0x11110000;
-                       priv->magicgpc980[1]   = 0x03332222;
-                       priv->magicgpc980[2]   = 0x00000000;
-                       priv->magicgpc980[3]   = 0x00000000;
-                       priv->magicgpc918      = 0x00088889;
-               }
-               break;
-       case 0xc3: /* 450, 4/0/0/0, 2 */
-               priv->magic_not_rop_nr = 0x03;
-               priv->magicgpc980[0]   = 0x00003210;
-               priv->magicgpc980[1]   = 0x00000000;
-               priv->magicgpc980[2]   = 0x00000000;
-               priv->magicgpc980[3]   = 0x00000000;
-               priv->magicgpc918      = 0x00200000;
-               break;
-       case 0xc4: /* 460, 3/4/0/0, 4 */
-               priv->magic_not_rop_nr = 0x01;
-               priv->magicgpc980[0]   = 0x02321100;
-               priv->magicgpc980[1]   = 0x00000000;
-               priv->magicgpc980[2]   = 0x00000000;
-               priv->magicgpc980[3]   = 0x00000000;
-               priv->magicgpc918      = 0x00124925;
-               break;
-       }
-
-       if (!priv->magic_not_rop_nr) {
-               NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n",
-                        priv->tp_nr[0], priv->tp_nr[1], priv->tp_nr[2],
-                        priv->tp_nr[3], priv->rop_nr);
-               /* use 0xc3's values... */
-               priv->magic_not_rop_nr = 0x03;
-               priv->magicgpc980[0]   = 0x00003210;
-               priv->magicgpc980[1]   = 0x00000000;
-               priv->magicgpc980[2]   = 0x00000000;
-               priv->magicgpc980[3]   = 0x00000000;
-               priv->magicgpc918      = 0x00200000;
-       }
-
-       nouveau_irq_register(dev, 12, nvc0_graph_isr);
-       nouveau_irq_register(dev, 25, nvc0_runk140_isr);
-       NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */
-       NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */
-       NVOBJ_MTHD (dev, 0x9039, 0x0500, nvc0_graph_mthd_page_flip);
-       NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */
-       NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */
-       return 0;
-
-error:
-       nvc0_graph_destroy(dev);
-       return ret;
-}
-
 static void
 nvc0_graph_init_obj418880(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nvc0_graph_priv *priv = pgraph->priv;
+       struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
        int i;
 
        nv_wr32(dev, GPC_BCAST(0x0880), 0x00000000);
@@ -449,35 +295,42 @@ nvc0_graph_init_regs(struct drm_device *dev)
 static void
 nvc0_graph_init_gpc_0(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
-       int gpc;
-       
-       //      TP      ROP UNKVAL(magic_not_rop_nr)
-       // 450: 4/0/0/0 2        3
-       // 460: 3/4/0/0 4        1
-       // 465: 3/4/4/0 4        7
-       // 470: 3/3/4/4 5        5
-       // 480: 3/4/4/4 6        6
-
-       // magicgpc918
-       // 450: 00200000 00000000001000000000000000000000
-       // 460: 00124925 00000000000100100100100100100101
-       // 465: 000ba2e9 00000000000010111010001011101001
-       // 470: 00092493 00000000000010010010010010010011
-       // 480: 00088889 00000000000010001000100010001001
-
-       /* filled values up to tp_total, remainder 0 */
-       // 450: 00003210 00000000 00000000 00000000
-       // 460: 02321100 00000000 00000000 00000000
-       // 465: 22111000 00000233 00000000 00000000
-       // 470: 11110000 00233222 00000000 00000000
-       // 480: 11110000 03332222 00000000 00000000
-       
-       nv_wr32(dev, GPC_BCAST(0x0980), priv->magicgpc980[0]);
-       nv_wr32(dev, GPC_BCAST(0x0984), priv->magicgpc980[1]);
-       nv_wr32(dev, GPC_BCAST(0x0988), priv->magicgpc980[2]);
-       nv_wr32(dev, GPC_BCAST(0x098c), priv->magicgpc980[3]);
+       struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
+       u32 data[TP_MAX / 8];
+       u8  tpnr[GPC_MAX];
+       int i, gpc, tpc;
+
+       /*
+        *      TP      ROP UNKVAL(magic_not_rop_nr)
+        * 450: 4/0/0/0 2        3
+        * 460: 3/4/0/0 4        1
+        * 465: 3/4/4/0 4        7
+        * 470: 3/3/4/4 5        5
+        * 480: 3/4/4/4 6        6
+        *
+        * magicgpc918
+        * 450: 00200000 00000000001000000000000000000000
+        * 460: 00124925 00000000000100100100100100100101
+        * 465: 000ba2e9 00000000000010111010001011101001
+        * 470: 00092493 00000000000010010010010010010011
+        * 480: 00088889 00000000000010001000100010001001
+        */
+
+       memset(data, 0x00, sizeof(data));
+       memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr));
+       for (i = 0, gpc = -1; i < priv->tp_total; i++) {
+               do {
+                       gpc = (gpc + 1) % priv->gpc_nr;
+               } while (!tpnr[gpc]);
+               tpc = priv->tp_nr[gpc] - tpnr[gpc]--;
+
+               data[i / 8] |= tpc << ((i % 8) * 4);
+       }
+
+       nv_wr32(dev, GPC_BCAST(0x0980), data[0]);
+       nv_wr32(dev, GPC_BCAST(0x0984), data[1]);
+       nv_wr32(dev, GPC_BCAST(0x0988), data[2]);
+       nv_wr32(dev, GPC_BCAST(0x098c), data[3]);
 
        for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
                nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
@@ -509,8 +362,7 @@ nvc0_graph_init_units(struct drm_device *dev)
 static void
 nvc0_graph_init_gpc_1(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+       struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
        int gpc, tp;
 
        for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
@@ -535,8 +387,7 @@ nvc0_graph_init_gpc_1(struct drm_device *dev)
 static void
 nvc0_graph_init_rop(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+       struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
        int rop;
 
        for (rop = 0; rop < priv->rop_nr; rop++) {
@@ -547,62 +398,36 @@ nvc0_graph_init_rop(struct drm_device *dev)
        }
 }
 
-static int
-nvc0_fuc_load_fw(struct drm_device *dev, u32 fuc_base,
-                const char *code_fw, const char *data_fw)
+static void
+nvc0_graph_init_fuc(struct drm_device *dev, u32 fuc_base,
+                   struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data)
 {
-       const struct firmware *fw;
-       char name[32];
-       int ret, i;
-
-       snprintf(name, sizeof(name), "nouveau/%s", data_fw);
-       ret = request_firmware(&fw, name, &dev->pdev->dev);
-       if (ret) {
-               NV_ERROR(dev, "failed to load %s\n", data_fw);
-               return ret;
-       }
+       int i;
 
        nv_wr32(dev, fuc_base + 0x01c0, 0x01000000);
-       for (i = 0; i < fw->size / 4; i++)
-               nv_wr32(dev, fuc_base + 0x01c4, ((u32 *)fw->data)[i]);
-       release_firmware(fw);
-
-       snprintf(name, sizeof(name), "nouveau/%s", code_fw);
-       ret = request_firmware(&fw, name, &dev->pdev->dev);
-       if (ret) {
-               NV_ERROR(dev, "failed to load %s\n", code_fw);
-               return ret;
-       }
+       for (i = 0; i < data->size / 4; i++)
+               nv_wr32(dev, fuc_base + 0x01c4, data->data[i]);
 
        nv_wr32(dev, fuc_base + 0x0180, 0x01000000);
-       for (i = 0; i < fw->size / 4; i++) {
+       for (i = 0; i < code->size / 4; i++) {
                if ((i & 0x3f) == 0)
                        nv_wr32(dev, fuc_base + 0x0188, i >> 6);
-               nv_wr32(dev, fuc_base + 0x0184, ((u32 *)fw->data)[i]);
+               nv_wr32(dev, fuc_base + 0x0184, code->data[i]);
        }
-       release_firmware(fw);
-
-       return 0;
 }
 
 static int
 nvc0_graph_init_ctxctl(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+       struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
        u32 r000260;
-       int ret;
 
        /* load fuc microcode */
        r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
-       ret = nvc0_fuc_load_fw(dev, 0x409000, "fuc409c", "fuc409d");
-       if (ret == 0)
-               ret = nvc0_fuc_load_fw(dev, 0x41a000, "fuc41ac", "fuc41ad");
+       nvc0_graph_init_fuc(dev, 0x409000, &priv->fuc409c, &priv->fuc409d);
+       nvc0_graph_init_fuc(dev, 0x41a000, &priv->fuc41ac, &priv->fuc41ad);
        nv_wr32(dev, 0x000260, r000260);
 
-       if (ret)
-               return ret;
-
        /* start both of them running */
        nv_wr32(dev, 0x409840, 0xffffffff);
        nv_wr32(dev, 0x41a10c, 0x00000000);
@@ -644,41 +469,19 @@ nvc0_graph_init_ctxctl(struct drm_device *dev)
        return 0;
 }
 
-int
-nvc0_graph_init(struct drm_device *dev)
+static int
+nvc0_graph_init(struct drm_device *dev, int engine)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        int ret;
 
-       dev_priv->engine.graph.accel_blocked = true;
-
-       switch (dev_priv->chipset) {
-       case 0xc0:
-       case 0xc3:
-       case 0xc4:
-               break;
-       default:
-               NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n");
-               if (nouveau_noaccel != 0)
-                       return 0;
-               break;
-       }
-
        nv_mask(dev, 0x000200, 0x18001000, 0x00000000);
        nv_mask(dev, 0x000200, 0x18001000, 0x18001000);
 
-       if (!pgraph->priv) {
-               ret = nvc0_graph_create(dev);
-               if (ret)
-                       return ret;
-       }
-
        nvc0_graph_init_obj418880(dev);
        nvc0_graph_init_regs(dev);
-       //nvc0_graph_init_unitplemented_magics(dev);
+       /*nvc0_graph_init_unitplemented_magics(dev);*/
        nvc0_graph_init_gpc_0(dev);
-       //nvc0_graph_init_unitplemented_c242(dev);
+       /*nvc0_graph_init_unitplemented_c242(dev);*/
 
        nv_wr32(dev, 0x400500, 0x00010001);
        nv_wr32(dev, 0x400100, 0xffffffff);
@@ -697,12 +500,13 @@ nvc0_graph_init(struct drm_device *dev)
        nv_wr32(dev, 0x400054, 0x34ce3464);
 
        ret = nvc0_graph_init_ctxctl(dev);
-       if (ret == 0)
-               dev_priv->engine.graph.accel_blocked = false;
+       if (ret)
+               return ret;
+
        return 0;
 }
 
-static int
+int
 nvc0_graph_isr_chid(struct drm_device *dev, u64 inst)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -806,3 +610,187 @@ nvc0_runk140_isr(struct drm_device *dev)
                units &= ~(1 << unit);
        }
 }
+
+static int
+nvc0_graph_create_fw(struct drm_device *dev, const char *fwname,
+                    struct nvc0_graph_fuc *fuc)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       const struct firmware *fw;
+       char f[32];
+       int ret;
+
+       snprintf(f, sizeof(f), "nouveau/nv%02x_%s", dev_priv->chipset, fwname);
+       ret = request_firmware(&fw, f, &dev->pdev->dev);
+       if (ret) {
+               snprintf(f, sizeof(f), "nouveau/%s", fwname);
+               ret = request_firmware(&fw, f, &dev->pdev->dev);
+               if (ret) {
+                       NV_ERROR(dev, "failed to load %s\n", fwname);
+                       return ret;
+               }
+       }
+
+       fuc->size = fw->size;
+       fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
+       release_firmware(fw);
+       return (fuc->data != NULL) ? 0 : -ENOMEM;
+}
+
+static void
+nvc0_graph_destroy_fw(struct nvc0_graph_fuc *fuc)
+{
+       if (fuc->data) {
+               kfree(fuc->data);
+               fuc->data = NULL;
+       }
+}
+
+static void
+nvc0_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nvc0_graph_priv *priv = nv_engine(dev, engine);
+
+       nvc0_graph_destroy_fw(&priv->fuc409c);
+       nvc0_graph_destroy_fw(&priv->fuc409d);
+       nvc0_graph_destroy_fw(&priv->fuc41ac);
+       nvc0_graph_destroy_fw(&priv->fuc41ad);
+
+       nouveau_irq_unregister(dev, 12);
+       nouveau_irq_unregister(dev, 25);
+
+       nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
+       nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
+
+       if (priv->grctx_vals)
+               kfree(priv->grctx_vals);
+
+       NVOBJ_ENGINE_DEL(dev, GR);
+       kfree(priv);
+}
+
+int
+nvc0_graph_create(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nvc0_graph_priv *priv;
+       int ret, gpc, i;
+
+       switch (dev_priv->chipset) {
+       case 0xc0:
+       case 0xc3:
+       case 0xc4:
+               break;
+       default:
+               NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n");
+               return 0;
+       }
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->base.destroy = nvc0_graph_destroy;
+       priv->base.init = nvc0_graph_init;
+       priv->base.fini = nvc0_graph_fini;
+       priv->base.context_new = nvc0_graph_context_new;
+       priv->base.context_del = nvc0_graph_context_del;
+       priv->base.object_new = nvc0_graph_object_new;
+
+       NVOBJ_ENGINE_ADD(dev, GR, &priv->base);
+       nouveau_irq_register(dev, 12, nvc0_graph_isr);
+       nouveau_irq_register(dev, 25, nvc0_runk140_isr);
+
+       if (nvc0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) ||
+           nvc0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) ||
+           nvc0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) ||
+           nvc0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) {
+               ret = 0;
+               goto error;
+       }
+
+
+       ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
+       if (ret)
+               goto error;
+
+       ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8);
+       if (ret)
+               goto error;
+
+       for (i = 0; i < 0x1000; i += 4) {
+               nv_wo32(priv->unk4188b4, i, 0x00000010);
+               nv_wo32(priv->unk4188b8, i, 0x00000010);
+       }
+
+       priv->gpc_nr  =  nv_rd32(dev, 0x409604) & 0x0000001f;
+       priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16;
+       for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+               priv->tp_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608));
+               priv->tp_total += priv->tp_nr[gpc];
+       }
+
+       /*XXX: these need figuring out... */
+       switch (dev_priv->chipset) {
+       case 0xc0:
+               if (priv->tp_total == 11) { /* 465, 3/4/4/0, 4 */
+                       priv->magic_not_rop_nr = 0x07;
+                       /* filled values up to tp_total, the rest 0 */
+                       priv->magicgpc918      = 0x000ba2e9;
+               } else
+               if (priv->tp_total == 14) { /* 470, 3/3/4/4, 5 */
+                       priv->magic_not_rop_nr = 0x05;
+                       priv->magicgpc918      = 0x00092493;
+               } else
+               if (priv->tp_total == 15) { /* 480, 3/4/4/4, 6 */
+                       priv->magic_not_rop_nr = 0x06;
+                       priv->magicgpc918      = 0x00088889;
+               }
+               break;
+       case 0xc3: /* 450, 4/0/0/0, 2 */
+               priv->magic_not_rop_nr = 0x03;
+               priv->magicgpc918      = 0x00200000;
+               break;
+       case 0xc4: /* 460, 3/4/0/0, 4 */
+               priv->magic_not_rop_nr = 0x01;
+               priv->magicgpc918      = 0x00124925;
+               break;
+       }
+
+       if (!priv->magic_not_rop_nr) {
+               NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n",
+                        priv->tp_nr[0], priv->tp_nr[1], priv->tp_nr[2],
+                        priv->tp_nr[3], priv->rop_nr);
+               /* use 0xc3's values... */
+               priv->magic_not_rop_nr = 0x03;
+               priv->magicgpc918      = 0x00200000;
+       }
+
+       NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */
+       NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */
+       NVOBJ_MTHD (dev, 0x9039, 0x0500, nvc0_graph_mthd_page_flip);
+       NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */
+       NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */
+       return 0;
+
+error:
+       nvc0_graph_destroy(dev, NVOBJ_ENGINE_GR);
+       return ret;
+}
+
+MODULE_FIRMWARE("nouveau/nvc0_fuc409c");
+MODULE_FIRMWARE("nouveau/nvc0_fuc409d");
+MODULE_FIRMWARE("nouveau/nvc0_fuc41ac");
+MODULE_FIRMWARE("nouveau/nvc0_fuc41ad");
+MODULE_FIRMWARE("nouveau/nvc3_fuc409c");
+MODULE_FIRMWARE("nouveau/nvc3_fuc409d");
+MODULE_FIRMWARE("nouveau/nvc3_fuc41ac");
+MODULE_FIRMWARE("nouveau/nvc3_fuc41ad");
+MODULE_FIRMWARE("nouveau/nvc4_fuc409c");
+MODULE_FIRMWARE("nouveau/nvc4_fuc409d");
+MODULE_FIRMWARE("nouveau/nvc4_fuc41ac");
+MODULE_FIRMWARE("nouveau/nvc4_fuc41ad");
+MODULE_FIRMWARE("nouveau/fuc409c");
+MODULE_FIRMWARE("nouveau/fuc409d");
+MODULE_FIRMWARE("nouveau/fuc41ac");
+MODULE_FIRMWARE("nouveau/fuc41ad");
index 40e26f9c56c44c0af8a9dcaed0d0ac64872db5d8..f5d184e0689df4bad0f99ce792167c1c8ea960f9 100644 (file)
 #define GPC_MAX 4
 #define TP_MAX 32
 
-#define ROP_BCAST(r)   (0x408800 + (r))
-#define ROP_UNIT(u,r)  (0x410000 + (u) * 0x400 + (r))
-#define GPC_BCAST(r)   (0x418000 + (r))
-#define GPC_UNIT(t,r)  (0x500000 + (t) * 0x8000 + (r))
-#define TP_UNIT(t,m,r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
+#define ROP_BCAST(r)     (0x408800 + (r))
+#define ROP_UNIT(u, r)   (0x410000 + (u) * 0x400 + (r))
+#define GPC_BCAST(r)     (0x418000 + (r))
+#define GPC_UNIT(t, r)   (0x500000 + (t) * 0x8000 + (r))
+#define TP_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
+
+struct nvc0_graph_fuc {
+       u32 *data;
+       u32  size;
+};
 
 struct nvc0_graph_priv {
+       struct nouveau_exec_engine base;
+
+       struct nvc0_graph_fuc fuc409c;
+       struct nvc0_graph_fuc fuc409d;
+       struct nvc0_graph_fuc fuc41ac;
+       struct nvc0_graph_fuc fuc41ad;
+
        u8 gpc_nr;
        u8 rop_nr;
        u8 tp_nr[GPC_MAX];
@@ -46,15 +58,14 @@ struct nvc0_graph_priv {
        struct nouveau_gpuobj *unk4188b8;
 
        u8  magic_not_rop_nr;
-       u32 magicgpc980[4];
        u32 magicgpc918;
 };
 
 struct nvc0_graph_chan {
        struct nouveau_gpuobj *grctx;
-       struct nouveau_gpuobj *unk408004; // 0x418810 too
-       struct nouveau_gpuobj *unk40800c; // 0x419004 too
-       struct nouveau_gpuobj *unk418810; // 0x419848 too
+       struct nouveau_gpuobj *unk408004; /* 0x418810 too */
+       struct nouveau_gpuobj *unk40800c; /* 0x419004 too */
+       struct nouveau_gpuobj *unk418810; /* 0x419848 too */
        struct nouveau_gpuobj *mmio;
        int mmio_nr;
 };
index f880ff776db8562842142ebbc5482632e9ff2ecd..6df066114133dfc4beb9c1c142ce0391b15ab527 100644 (file)
@@ -1623,7 +1623,7 @@ nvc0_grctx_generate_rop(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
-       // ROPC_BROADCAST
+       /* ROPC_BROADCAST */
        nv_wr32(dev, 0x408800, 0x02802a3c);
        nv_wr32(dev, 0x408804, 0x00000040);
        nv_wr32(dev, 0x408808, 0x0003e00d);
@@ -1647,7 +1647,7 @@ nvc0_grctx_generate_gpc(struct drm_device *dev)
 {
        int i;
 
-       // GPC_BROADCAST
+       /* GPC_BROADCAST */
        nv_wr32(dev, 0x418380, 0x00000016);
        nv_wr32(dev, 0x418400, 0x38004e00);
        nv_wr32(dev, 0x418404, 0x71e0ffff);
@@ -1728,7 +1728,7 @@ nvc0_grctx_generate_tp(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
-       // GPC_BROADCAST.TP_BROADCAST
+       /* GPC_BROADCAST.TP_BROADCAST */
        nv_wr32(dev, 0x419848, 0x00000000);
        nv_wr32(dev, 0x419864, 0x0000012a);
        nv_wr32(dev, 0x419888, 0x00000000);
@@ -1741,7 +1741,7 @@ nvc0_grctx_generate_tp(struct drm_device *dev)
        nv_wr32(dev, 0x419a1c, 0x00000000);
        nv_wr32(dev, 0x419a20, 0x00000800);
        if (dev_priv->chipset != 0xc0)
-               nv_wr32(dev, 0x00419ac4, 0x0007f440); // 0xc3
+               nv_wr32(dev, 0x00419ac4, 0x0007f440); /* 0xc3 */
        nv_wr32(dev, 0x419b00, 0x0a418820);
        nv_wr32(dev, 0x419b04, 0x062080e6);
        nv_wr32(dev, 0x419b08, 0x020398a4);
@@ -1797,8 +1797,8 @@ int
 nvc0_grctx_generate(struct nouveau_channel *chan)
 {
        struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
-       struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+       struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+       struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
        struct drm_device *dev = chan->dev;
        int i, gpc, tp, id;
        u32 r000260, tmp;
@@ -1912,13 +1912,13 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
                for (i = 1; i < 7; i++)
                        data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
 
-               // GPC_BROADCAST
+               /* GPC_BROADCAST */
                nv_wr32(dev, 0x418bb8, (priv->tp_total << 8) |
                                        priv->magic_not_rop_nr);
                for (i = 0; i < 6; i++)
                        nv_wr32(dev, 0x418b08 + (i * 4), data[i]);
 
-               // GPC_BROADCAST.TP_BROADCAST
+               /* GPC_BROADCAST.TP_BROADCAST */
                nv_wr32(dev, 0x419bd0, (priv->tp_total << 8) |
                                       priv->magic_not_rop_nr |
                                       data2[0]);
@@ -1926,7 +1926,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
                for (i = 0; i < 6; i++)
                        nv_wr32(dev, 0x419b00 + (i * 4), data[i]);
 
-               // UNK78xx
+               /* UNK78xx */
                nv_wr32(dev, 0x4078bc, (priv->tp_total << 8) |
                                        priv->magic_not_rop_nr);
                for (i = 0; i < 6; i++)
@@ -1944,7 +1944,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
                gpc = -1;
                for (i = 0, gpc = -1; i < 32; i++) {
                        int ltp = i * (priv->tp_total - 1) / 32;
-                       
+
                        do {
                                gpc = (gpc + 1) % priv->gpc_nr;
                        } while (!tpnr[gpc]);
index fe0f253089acf6e15de9d1dd93934fd23d315fdb..bbfb1a68fb1170d1a48f45d03f3ce08d38496f31 100644 (file)
 #              define NV_CIO_CRE_EBR_VDE_11            2:2
 #              define NV_CIO_CRE_EBR_VRS_11            4:4
 #              define NV_CIO_CRE_EBR_VBS_11            6:6
+#      define NV_CIO_CRE_42                    0x42
+#              define NV_CIO_CRE_42_OFFSET_11          6:6
 #      define NV_CIO_CRE_43                    0x43
 #      define NV_CIO_CRE_44                    0x44    /* head control */
 #      define NV_CIO_CRE_CSB                   0x45    /* colour saturation boost */
index 9746fee59f567856511b0eae1a2ed9310e3e52d0..ea92bbe3ed37002865f8850255a4e68859a0c8c7 100644 (file)
@@ -28,11 +28,4 @@ config DRM_RADEON_KMS
          The kernel will also perform security check on command stream
          provided by the user, we want to catch and forbid any illegal use
          of the GPU such as DMA into random system memory or into memory
-         not owned by the process supplying the command stream. This part
-         of the code is still incomplete and this why we propose that patch
-         as a staging driver addition, future security might forbid current
-         experimental userspace to run.
-
-         This code support the following hardware : R1XX,R2XX,R3XX,R4XX,R5XX
-         (radeon up to X1950). Works is underway to provide support for R6XX,
-         R7XX and newer hardware (radeon from HD2XXX to HD4XXX).
+         not owned by the process supplying the command stream.
index 7bd7456890974025c74bfce11f8516bad909eacf..ebdb0fdb8348ad7b217e3d46027207789e0ad67f 100644 (file)
@@ -652,12 +652,12 @@ static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg)
 
 static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
 {
-       uint8_t count = U8((*ptr)++);
+       unsigned count = U8((*ptr)++);
        SDEBUG("   count: %d\n", count);
        if (arg == ATOM_UNIT_MICROSEC)
                udelay(count);
        else
-               schedule_timeout_uninterruptible(msecs_to_jiffies(count));
+               msleep(count);
 }
 
 static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg)
index 7fd88497b93042eacae1736a3762fe61e60e044e..1b50ad8919d55e9e268095dcd54e824006ffd895 100644 (file)
@@ -726,6 +726,7 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V2
 #define ATOM_ENCODER_CMD_DP_VIDEO_ON                  0x0d
 #define ATOM_ENCODER_CMD_QUERY_DP_LINK_TRAINING_STATUS    0x0e
 #define ATOM_ENCODER_CMD_SETUP                        0x0f
+#define ATOM_ENCODER_CMD_SETUP_PANEL_MODE             0x10
 
 // ucStatus
 #define ATOM_ENCODER_STATUS_LINK_TRAINING_COMPLETE    0x10
@@ -765,13 +766,19 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V3
   USHORT usPixelClock;      // in 10KHz; for bios convenient
   ATOM_DIG_ENCODER_CONFIG_V3 acConfig;
   UCHAR ucAction;                              
-  UCHAR ucEncoderMode;
+  union {
+    UCHAR ucEncoderMode;
                             // =0: DP   encoder      
                             // =1: LVDS encoder          
                             // =2: DVI  encoder  
                             // =3: HDMI encoder
                             // =4: SDVO encoder
                             // =5: DP audio
+    UCHAR ucPanelMode;      // only valid when ucAction == ATOM_ENCODER_CMD_SETUP_PANEL_MODE
+                           // =0:     external DP
+                           // =1:     internal DP2
+                           // =0x11:  internal DP1 for NutMeg/Travis DP translator
+  };
   UCHAR ucLaneNum;          // how many lanes to enable
   UCHAR ucBitPerColor;      // only valid for DP mode when ucAction = ATOM_ENCODER_CMD_SETUP
   UCHAR ucReserved;
@@ -816,13 +823,19 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V4
   UCHAR ucConfig;
   };
   UCHAR ucAction;                              
-  UCHAR ucEncoderMode;
+  union {
+    UCHAR ucEncoderMode;
                             // =0: DP   encoder      
                             // =1: LVDS encoder          
                             // =2: DVI  encoder  
                             // =3: HDMI encoder
                             // =4: SDVO encoder
                             // =5: DP audio
+    UCHAR ucPanelMode;      // only valid when ucAction == ATOM_ENCODER_CMD_SETUP_PANEL_MODE
+                           // =0:     external DP
+                           // =1:     internal DP2
+                           // =0x11:  internal DP1 for NutMeg/Travis DP translator
+  };
   UCHAR ucLaneNum;          // how many lanes to enable
   UCHAR ucBitPerColor;      // only valid for DP mode when ucAction = ATOM_ENCODER_CMD_SETUP
   UCHAR ucHPD_ID;           // HPD ID (1-6). =0 means to skip HDP programming. New comparing to previous version
@@ -836,6 +849,11 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V4
 #define PANEL_12BIT_PER_COLOR                            0x04
 #define PANEL_16BIT_PER_COLOR                            0x05
 
+//define ucPanelMode
+#define DP_PANEL_MODE_EXTERNAL_DP_MODE                   0x00
+#define DP_PANEL_MODE_INTERNAL_DP2_MODE                  0x01
+#define DP_PANEL_MODE_INTERNAL_DP1_MODE                  0x11
+
 /****************************************************************************/ 
 // Structures used by UNIPHYTransmitterControlTable
 //                    LVTMATransmitterControlTable
@@ -1182,6 +1200,7 @@ typedef struct _EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3
 #define EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING_OFF   0x10
 #define EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING       0x11
 #define EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION      0x12
+#define EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP              0x14
 
 // ucConfig
 #define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_MASK                             0x03
index 529a3a704731ba39d77b423ac1ebe670697816f3..9541995e4b21df3d4ba5cb9b3ab496a3255b8034 100644 (file)
@@ -420,7 +420,7 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc,
 
        if (ASIC_IS_DCE5(rdev)) {
                args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0);
-               args.v3.ucSpreadSpectrumType = ss->type;
+               args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
                switch (pll_id) {
                case ATOM_PPLL1:
                        args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL;
@@ -440,10 +440,12 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc,
                case ATOM_PPLL_INVALID:
                        return;
                }
-               args.v2.ucEnable = enable;
+               args.v3.ucEnable = enable;
+               if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK))
+                       args.v3.ucEnable = ATOM_DISABLE;
        } else if (ASIC_IS_DCE4(rdev)) {
                args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
-               args.v2.ucSpreadSpectrumType = ss->type;
+               args.v2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
                switch (pll_id) {
                case ATOM_PPLL1:
                        args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL;
@@ -464,32 +466,36 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc,
                        return;
                }
                args.v2.ucEnable = enable;
+               if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK))
+                       args.v2.ucEnable = ATOM_DISABLE;
        } else if (ASIC_IS_DCE3(rdev)) {
                args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
-               args.v1.ucSpreadSpectrumType = ss->type;
+               args.v1.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
                args.v1.ucSpreadSpectrumStep = ss->step;
                args.v1.ucSpreadSpectrumDelay = ss->delay;
                args.v1.ucSpreadSpectrumRange = ss->range;
                args.v1.ucPpll = pll_id;
                args.v1.ucEnable = enable;
        } else if (ASIC_IS_AVIVO(rdev)) {
-               if (enable == ATOM_DISABLE) {
+               if ((enable == ATOM_DISABLE) || (ss->percentage == 0) ||
+                   (ss->type & ATOM_EXTERNAL_SS_MASK)) {
                        atombios_disable_ss(crtc);
                        return;
                }
                args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
-               args.lvds_ss_2.ucSpreadSpectrumType = ss->type;
+               args.lvds_ss_2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
                args.lvds_ss_2.ucSpreadSpectrumStep = ss->step;
                args.lvds_ss_2.ucSpreadSpectrumDelay = ss->delay;
                args.lvds_ss_2.ucSpreadSpectrumRange = ss->range;
                args.lvds_ss_2.ucEnable = enable;
        } else {
-               if (enable == ATOM_DISABLE) {
+               if ((enable == ATOM_DISABLE) || (ss->percentage == 0) ||
+                   (ss->type & ATOM_EXTERNAL_SS_MASK)) {
                        atombios_disable_ss(crtc);
                        return;
                }
                args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
-               args.lvds_ss.ucSpreadSpectrumType = ss->type;
+               args.lvds_ss.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
                args.lvds_ss.ucSpreadSpectrumStepSize_Delay = (ss->step & 3) << 2;
                args.lvds_ss.ucSpreadSpectrumStepSize_Delay |= (ss->delay & 7) << 4;
                args.lvds_ss.ucEnable = enable;
@@ -512,6 +518,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
        struct radeon_device *rdev = dev->dev_private;
        struct drm_encoder *encoder = NULL;
        struct radeon_encoder *radeon_encoder = NULL;
+       struct drm_connector *connector = NULL;
        u32 adjusted_clock = mode->clock;
        int encoder_mode = 0;
        u32 dp_clock = mode->clock;
@@ -546,9 +553,12 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
                if (encoder->crtc == crtc) {
                        radeon_encoder = to_radeon_encoder(encoder);
+                       connector = radeon_get_connector_for_encoder(encoder);
+                       if (connector)
+                               bpc = connector->display_info.bpc;
                        encoder_mode = atombios_get_encoder_mode(encoder);
-                       if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) {
-                               struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+                       if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
+                           radeon_encoder_is_dp_bridge(encoder)) {
                                if (connector) {
                                        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
                                        struct radeon_connector_atom_dig *dig_connector =
@@ -612,7 +622,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                args.v1.usPixelClock = cpu_to_le16(mode->clock / 10);
                                args.v1.ucTransmitterID = radeon_encoder->encoder_id;
                                args.v1.ucEncodeMode = encoder_mode;
-                               if (ss_enabled)
+                               if (ss_enabled && ss->percentage)
                                        args.v1.ucConfig |=
                                                ADJUST_DISPLAY_CONFIG_SS_ENABLE;
 
@@ -625,10 +635,11 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id;
                                args.v3.sInput.ucEncodeMode = encoder_mode;
                                args.v3.sInput.ucDispPllConfig = 0;
-                               if (ss_enabled)
+                               if (ss_enabled && ss->percentage)
                                        args.v3.sInput.ucDispPllConfig |=
                                                DISPPLL_CONFIG_SS_ENABLE;
-                               if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+                               if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT) ||
+                                   radeon_encoder_is_dp_bridge(encoder)) {
                                        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
                                        if (encoder_mode == ATOM_ENCODER_MODE_DP) {
                                                args.v3.sInput.ucDispPllConfig |=
@@ -660,6 +671,13 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                                                DISPPLL_CONFIG_DUAL_LINK;
                                        }
                                }
+                               if (radeon_encoder_is_dp_bridge(encoder)) {
+                                       struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder);
+                                       struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder);
+                                       args.v3.sInput.ucExtTransmitterID = ext_radeon_encoder->encoder_id;
+                               } else
+                                       args.v3.sInput.ucExtTransmitterID = 0;
+
                                atom_execute_table(rdev->mode_info.atom_context,
                                                   index, (uint32_t *)&args);
                                adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10;
@@ -754,7 +772,10 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
                                      u32 ref_div,
                                      u32 fb_div,
                                      u32 frac_fb_div,
-                                     u32 post_div)
+                                     u32 post_div,
+                                     int bpc,
+                                     bool ss_enabled,
+                                     struct radeon_atom_ss *ss)
 {
        struct drm_device *dev = crtc->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -801,6 +822,8 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
                        args.v3.ucPostDiv = post_div;
                        args.v3.ucPpll = pll_id;
                        args.v3.ucMiscInfo = (pll_id << 2);
+                       if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
+                               args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
                        args.v3.ucTransmitterId = encoder_id;
                        args.v3.ucEncoderMode = encoder_mode;
                        break;
@@ -812,6 +835,17 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
                        args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
                        args.v5.ucPostDiv = post_div;
                        args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
+                       if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
+                               args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC;
+                       switch (bpc) {
+                       case 8:
+                       default:
+                               args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
+                               break;
+                       case 10:
+                               args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
+                               break;
+                       }
                        args.v5.ucTransmitterID = encoder_id;
                        args.v5.ucEncoderMode = encoder_mode;
                        args.v5.ucPpll = pll_id;
@@ -824,6 +858,23 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
                        args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
                        args.v6.ucPostDiv = post_div;
                        args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */
+                       if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
+                               args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC;
+                       switch (bpc) {
+                       case 8:
+                       default:
+                               args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
+                               break;
+                       case 10:
+                               args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP;
+                               break;
+                       case 12:
+                               args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP;
+                               break;
+                       case 16:
+                               args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
+                               break;
+                       }
                        args.v6.ucTransmitterID = encoder_id;
                        args.v6.ucEncoderMode = encoder_mode;
                        args.v6.ucPpll = pll_id;
@@ -855,6 +906,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
        int encoder_mode = 0;
        struct radeon_atom_ss ss;
        bool ss_enabled = false;
+       int bpc = 8;
 
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
                if (encoder->crtc == crtc) {
@@ -891,41 +943,30 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
                struct radeon_connector_atom_dig *dig_connector =
                        radeon_connector->con_priv;
                int dp_clock;
+               bpc = connector->display_info.bpc;
 
                switch (encoder_mode) {
                case ATOM_ENCODER_MODE_DP:
                        /* DP/eDP */
                        dp_clock = dig_connector->dp_clock / 10;
-                       if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
-                               if (ASIC_IS_DCE4(rdev))
-                                       ss_enabled =
-                                               radeon_atombios_get_asic_ss_info(rdev, &ss,
-                                                                                dig->lcd_ss_id,
-                                                                                dp_clock);
-                               else
+                       if (ASIC_IS_DCE4(rdev))
+                               ss_enabled =
+                                       radeon_atombios_get_asic_ss_info(rdev, &ss,
+                                                                        ASIC_INTERNAL_SS_ON_DP,
+                                                                        dp_clock);
+                       else {
+                               if (dp_clock == 16200) {
                                        ss_enabled =
                                                radeon_atombios_get_ppll_ss_info(rdev, &ss,
-                                                                                dig->lcd_ss_id);
-                       } else {
-                               if (ASIC_IS_DCE4(rdev))
-                                       ss_enabled =
-                                               radeon_atombios_get_asic_ss_info(rdev, &ss,
-                                                                                ASIC_INTERNAL_SS_ON_DP,
-                                                                                dp_clock);
-                               else {
-                                       if (dp_clock == 16200) {
-                                               ss_enabled =
-                                                       radeon_atombios_get_ppll_ss_info(rdev, &ss,
-                                                                                        ATOM_DP_SS_ID2);
-                                               if (!ss_enabled)
-                                                       ss_enabled =
-                                                               radeon_atombios_get_ppll_ss_info(rdev, &ss,
-                                                                                                ATOM_DP_SS_ID1);
-                                       } else
+                                                                                ATOM_DP_SS_ID2);
+                                       if (!ss_enabled)
                                                ss_enabled =
                                                        radeon_atombios_get_ppll_ss_info(rdev, &ss,
                                                                                         ATOM_DP_SS_ID1);
-                               }
+                               } else
+                                       ss_enabled =
+                                               radeon_atombios_get_ppll_ss_info(rdev, &ss,
+                                                                                ATOM_DP_SS_ID1);
                        }
                        break;
                case ATOM_ENCODER_MODE_LVDS:
@@ -974,7 +1015,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
 
        atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
                                  encoder_mode, radeon_encoder->encoder_id, mode->clock,
-                                 ref_div, fb_div, frac_fb_div, post_div);
+                                 ref_div, fb_div, frac_fb_div, post_div, bpc, ss_enabled, &ss);
 
        if (ss_enabled) {
                /* calculate ss amount and step size */
@@ -982,7 +1023,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
                        u32 step_size;
                        u32 amount = (((fb_div * 10) + frac_fb_div) * ss.percentage) / 10000;
                        ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK;
-                       ss.amount |= ((amount - (ss.amount * 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
+                       ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
                                ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK;
                        if (ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD)
                                step_size = (4 * amount * ref_div * (ss.rate * 2048)) /
@@ -1011,7 +1052,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
        uint64_t fb_location;
        uint32_t fb_format, fb_pitch_pixels, tiling_flags;
        u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE);
-       u32 tmp;
+       u32 tmp, viewport_w, viewport_h;
        int r;
 
        /* no fb bound */
@@ -1137,8 +1178,10 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
        y &= ~1;
        WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset,
               (x << 16) | y);
+       viewport_w = crtc->mode.hdisplay;
+       viewport_h = (crtc->mode.vdisplay + 1) & ~1;
        WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
-              (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay);
+              (viewport_w << 16) | viewport_h);
 
        /* pageflip setup */
        /* make sure flip is at vb rather than hb */
@@ -1179,7 +1222,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
        uint64_t fb_location;
        uint32_t fb_format, fb_pitch_pixels, tiling_flags;
        u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE;
-       u32 tmp;
+       u32 tmp, viewport_w, viewport_h;
        int r;
 
        /* no fb bound */
@@ -1304,8 +1347,10 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
        y &= ~1;
        WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset,
               (x << 16) | y);
+       viewport_w = crtc->mode.hdisplay;
+       viewport_h = (crtc->mode.vdisplay + 1) & ~1;
        WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
-              (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay);
+              (viewport_w << 16) | viewport_h);
 
        /* pageflip setup */
        /* make sure flip is at vb rather than hb */
@@ -1395,11 +1440,19 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
        uint32_t pll_in_use = 0;
 
        if (ASIC_IS_DCE4(rdev)) {
-               /* if crtc is driving DP and we have an ext clock, use that */
                list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
                        if (test_encoder->crtc && (test_encoder->crtc == crtc)) {
+                               /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock,
+                                * depending on the asic:
+                                * DCE4: PPLL or ext clock
+                                * DCE5: DCPLL or ext clock
+                                *
+                                * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip
+                                * PPLL/DCPLL programming and only program the DP DTO for the
+                                * crtc virtual pixel clock.
+                                */
                                if (atombios_get_encoder_mode(test_encoder) == ATOM_ENCODER_MODE_DP) {
-                                       if (rdev->clock.dp_extclk)
+                                       if (ASIC_IS_DCE5(rdev) || rdev->clock.dp_extclk)
                                                return ATOM_PPLL_INVALID;
                                }
                        }
@@ -1515,6 +1568,8 @@ static void atombios_crtc_commit(struct drm_crtc *crtc)
 static void atombios_crtc_disable(struct drm_crtc *crtc)
 {
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct radeon_atom_ss ss;
+
        atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
 
        switch (radeon_crtc->pll_id) {
@@ -1522,7 +1577,7 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)
        case ATOM_PPLL2:
                /* disable the ppll */
                atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
-                                         0, 0, ATOM_DISABLE, 0, 0, 0, 0);
+                                         0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);
                break;
        default:
                break;
index 695de9a38506dea0aa19c8b2ec315486c7b26bb1..8c0f9e36ff8e1ee452db546d6b88611991a518ea 100644 (file)
@@ -43,158 +43,242 @@ static char *pre_emph_names[] = {
         "0dB", "3.5dB", "6dB", "9.5dB"
 };
 
-static const int dp_clocks[] = {
-       54000,  /* 1 lane, 1.62 Ghz */
-       90000,  /* 1 lane, 2.70 Ghz */
-       108000, /* 2 lane, 1.62 Ghz */
-       180000, /* 2 lane, 2.70 Ghz */
-       216000, /* 4 lane, 1.62 Ghz */
-       360000, /* 4 lane, 2.70 Ghz */
+/***** radeon AUX functions *****/
+union aux_channel_transaction {
+       PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
+       PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
 };
 
-static const int num_dp_clocks = sizeof(dp_clocks) / sizeof(int);
+static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
+                                u8 *send, int send_bytes,
+                                u8 *recv, int recv_size,
+                                u8 delay, u8 *ack)
+{
+       struct drm_device *dev = chan->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       union aux_channel_transaction args;
+       int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
+       unsigned char *base;
+       int recv_bytes;
+
+       memset(&args, 0, sizeof(args));
 
-/* common helper functions */
-static int dp_lanes_for_mode_clock(u8 dpcd[DP_DPCD_SIZE], int mode_clock)
+       base = (unsigned char *)rdev->mode_info.atom_context->scratch;
+
+       memcpy(base, send, send_bytes);
+
+       args.v1.lpAuxRequest = 0;
+       args.v1.lpDataOut = 16;
+       args.v1.ucDataOutLen = 0;
+       args.v1.ucChannelID = chan->rec.i2c_id;
+       args.v1.ucDelay = delay / 10;
+       if (ASIC_IS_DCE4(rdev))
+               args.v2.ucHPD_ID = chan->rec.hpd;
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+       *ack = args.v1.ucReplyStatus;
+
+       /* timeout */
+       if (args.v1.ucReplyStatus == 1) {
+               DRM_DEBUG_KMS("dp_aux_ch timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       /* flags not zero */
+       if (args.v1.ucReplyStatus == 2) {
+               DRM_DEBUG_KMS("dp_aux_ch flags not zero\n");
+               return -EBUSY;
+       }
+
+       /* error */
+       if (args.v1.ucReplyStatus == 3) {
+               DRM_DEBUG_KMS("dp_aux_ch error\n");
+               return -EIO;
+       }
+
+       recv_bytes = args.v1.ucDataOutLen;
+       if (recv_bytes > recv_size)
+               recv_bytes = recv_size;
+
+       if (recv && recv_size)
+               memcpy(recv, base + 16, recv_bytes);
+
+       return recv_bytes;
+}
+
+static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector,
+                                     u16 address, u8 *send, u8 send_bytes, u8 delay)
 {
-       int i;
-       u8 max_link_bw;
-       u8 max_lane_count;
+       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+       int ret;
+       u8 msg[20];
+       int msg_bytes = send_bytes + 4;
+       u8 ack;
 
-       if (!dpcd)
-               return 0;
+       if (send_bytes > 16)
+               return -1;
 
-       max_link_bw = dpcd[DP_MAX_LINK_RATE];
-       max_lane_count = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
+       msg[0] = address;
+       msg[1] = address >> 8;
+       msg[2] = AUX_NATIVE_WRITE << 4;
+       msg[3] = (msg_bytes << 4) | (send_bytes - 1);
+       memcpy(&msg[4], send, send_bytes);
 
-       switch (max_link_bw) {
-       case DP_LINK_BW_1_62:
-       default:
-               for (i = 0; i < num_dp_clocks; i++) {
-                       if (i % 2)
-                               continue;
-                       switch (max_lane_count) {
-                       case 1:
-                               if (i > 1)
-                                       return 0;
-                               break;
-                       case 2:
-                               if (i > 3)
-                                       return 0;
-                               break;
-                       case 4:
-                       default:
-                               break;
-                       }
-                       if (dp_clocks[i] > mode_clock) {
-                               if (i < 2)
-                                       return 1;
-                               else if (i < 4)
-                                       return 2;
-                               else
-                                       return 4;
-                       }
-               }
-               break;
-       case DP_LINK_BW_2_7:
-               for (i = 0; i < num_dp_clocks; i++) {
-                       switch (max_lane_count) {
-                       case 1:
-                               if (i > 1)
-                                       return 0;
-                               break;
-                       case 2:
-                               if (i > 3)
-                                       return 0;
-                               break;
-                       case 4:
-                       default:
-                               break;
-                       }
-                       if (dp_clocks[i] > mode_clock) {
-                               if (i < 2)
-                                       return 1;
-                               else if (i < 4)
-                                       return 2;
-                               else
-                                       return 4;
-                       }
-               }
-               break;
+       while (1) {
+               ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
+                                           msg, msg_bytes, NULL, 0, delay, &ack);
+               if (ret < 0)
+                       return ret;
+               if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
+                       break;
+               else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+                       udelay(400);
+               else
+                       return -EIO;
        }
 
-       return 0;
+       return send_bytes;
 }
 
-static int dp_link_clock_for_mode_clock(u8 dpcd[DP_DPCD_SIZE], int mode_clock)
+static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector,
+                                    u16 address, u8 *recv, int recv_bytes, u8 delay)
 {
-       int i;
-       u8 max_link_bw;
-       u8 max_lane_count;
+       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+       u8 msg[4];
+       int msg_bytes = 4;
+       u8 ack;
+       int ret;
 
-       if (!dpcd)
-               return 0;
+       msg[0] = address;
+       msg[1] = address >> 8;
+       msg[2] = AUX_NATIVE_READ << 4;
+       msg[3] = (msg_bytes << 4) | (recv_bytes - 1);
+
+       while (1) {
+               ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
+                                           msg, msg_bytes, recv, recv_bytes, delay, &ack);
+               if (ret == 0)
+                       return -EPROTO;
+               if (ret < 0)
+                       return ret;
+               if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
+                       return ret;
+               else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+                       udelay(400);
+               else
+                       return -EIO;
+       }
+}
 
-       max_link_bw = dpcd[DP_MAX_LINK_RATE];
-       max_lane_count = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
+static void radeon_write_dpcd_reg(struct radeon_connector *radeon_connector,
+                                u16 reg, u8 val)
+{
+       radeon_dp_aux_native_write(radeon_connector, reg, &val, 1, 0);
+}
 
-       switch (max_link_bw) {
-       case DP_LINK_BW_1_62:
+static u8 radeon_read_dpcd_reg(struct radeon_connector *radeon_connector,
+                              u16 reg)
+{
+       u8 val = 0;
+
+       radeon_dp_aux_native_read(radeon_connector, reg, &val, 1, 0);
+
+       return val;
+}
+
+int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
+                        u8 write_byte, u8 *read_byte)
+{
+       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+       struct radeon_i2c_chan *auxch = (struct radeon_i2c_chan *)adapter;
+       u16 address = algo_data->address;
+       u8 msg[5];
+       u8 reply[2];
+       unsigned retry;
+       int msg_bytes;
+       int reply_bytes = 1;
+       int ret;
+       u8 ack;
+
+       /* Set up the command byte */
+       if (mode & MODE_I2C_READ)
+               msg[2] = AUX_I2C_READ << 4;
+       else
+               msg[2] = AUX_I2C_WRITE << 4;
+
+       if (!(mode & MODE_I2C_STOP))
+               msg[2] |= AUX_I2C_MOT << 4;
+
+       msg[0] = address;
+       msg[1] = address >> 8;
+
+       switch (mode) {
+       case MODE_I2C_WRITE:
+               msg_bytes = 5;
+               msg[3] = msg_bytes << 4;
+               msg[4] = write_byte;
+               break;
+       case MODE_I2C_READ:
+               msg_bytes = 4;
+               msg[3] = msg_bytes << 4;
+               break;
        default:
-               for (i = 0; i < num_dp_clocks; i++) {
-                       if (i % 2)
-                               continue;
-                       switch (max_lane_count) {
-                       case 1:
-                               if (i > 1)
-                                       return 0;
-                               break;
-                       case 2:
-                               if (i > 3)
-                                       return 0;
-                               break;
-                       case 4:
-                       default:
-                               break;
-                       }
-                       if (dp_clocks[i] > mode_clock)
-                               return 162000;
-               }
+               msg_bytes = 4;
+               msg[3] = 3 << 4;
                break;
-       case DP_LINK_BW_2_7:
-               for (i = 0; i < num_dp_clocks; i++) {
-                       switch (max_lane_count) {
-                       case 1:
-                               if (i > 1)
-                                       return 0;
-                               break;
-                       case 2:
-                               if (i > 3)
-                                       return 0;
-                               break;
-                       case 4:
-                       default:
-                               break;
-                       }
-                       if (dp_clocks[i] > mode_clock)
-                               return (i % 2) ? 270000 : 162000;
-               }
        }
 
-       return 0;
-}
+       for (retry = 0; retry < 4; retry++) {
+               ret = radeon_process_aux_ch(auxch,
+                                           msg, msg_bytes, reply, reply_bytes, 0, &ack);
+               if (ret < 0) {
+                       DRM_DEBUG_KMS("aux_ch failed %d\n", ret);
+                       return ret;
+               }
 
-int dp_mode_valid(u8 dpcd[DP_DPCD_SIZE], int mode_clock)
-{
-       int lanes = dp_lanes_for_mode_clock(dpcd, mode_clock);
-       int dp_clock = dp_link_clock_for_mode_clock(dpcd, mode_clock);
+               switch (ack & AUX_NATIVE_REPLY_MASK) {
+               case AUX_NATIVE_REPLY_ACK:
+                       /* I2C-over-AUX Reply field is only valid
+                        * when paired with AUX ACK.
+                        */
+                       break;
+               case AUX_NATIVE_REPLY_NACK:
+                       DRM_DEBUG_KMS("aux_ch native nack\n");
+                       return -EREMOTEIO;
+               case AUX_NATIVE_REPLY_DEFER:
+                       DRM_DEBUG_KMS("aux_ch native defer\n");
+                       udelay(400);
+                       continue;
+               default:
+                       DRM_ERROR("aux_ch invalid native reply 0x%02x\n", ack);
+                       return -EREMOTEIO;
+               }
 
-       if ((lanes == 0) || (dp_clock == 0))
-               return MODE_CLOCK_HIGH;
+               switch (ack & AUX_I2C_REPLY_MASK) {
+               case AUX_I2C_REPLY_ACK:
+                       if (mode == MODE_I2C_READ)
+                               *read_byte = reply[0];
+                       return ret;
+               case AUX_I2C_REPLY_NACK:
+                       DRM_DEBUG_KMS("aux_i2c nack\n");
+                       return -EREMOTEIO;
+               case AUX_I2C_REPLY_DEFER:
+                       DRM_DEBUG_KMS("aux_i2c defer\n");
+                       udelay(400);
+                       break;
+               default:
+                       DRM_ERROR("aux_i2c invalid reply 0x%02x\n", ack);
+                       return -EREMOTEIO;
+               }
+       }
 
-       return MODE_OK;
+       DRM_ERROR("aux i2c too many retries, giving up\n");
+       return -EREMOTEIO;
 }
 
+/***** general DP utility functions *****/
+
 static u8 dp_link_status(u8 link_status[DP_LINK_STATUS_SIZE], int r)
 {
        return link_status[r - DP_LANE0_1_STATUS];
@@ -242,7 +326,7 @@ static bool dp_channel_eq_ok(u8 link_status[DP_LINK_STATUS_SIZE],
        return true;
 }
 
-static u8 dp_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE],
+static u8 dp_get_adjust_request_voltage(u8 link_status[DP_LINK_STATUS_SIZE],
                                        int lane)
 
 {
@@ -255,7 +339,7 @@ static u8 dp_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE]
        return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
 }
 
-static u8 dp_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE],
+static u8 dp_get_adjust_request_pre_emphasis(u8 link_status[DP_LINK_STATUS_SIZE],
                                             int lane)
 {
        int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
@@ -267,22 +351,8 @@ static u8 dp_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_
        return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
 }
 
-/* XXX fix me -- chip specific */
 #define DP_VOLTAGE_MAX         DP_TRAIN_VOLTAGE_SWING_1200
-static u8 dp_pre_emphasis_max(u8 voltage_swing)
-{
-       switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
-       case DP_TRAIN_VOLTAGE_SWING_400:
-               return DP_TRAIN_PRE_EMPHASIS_6;
-       case DP_TRAIN_VOLTAGE_SWING_600:
-               return DP_TRAIN_PRE_EMPHASIS_6;
-       case DP_TRAIN_VOLTAGE_SWING_800:
-               return DP_TRAIN_PRE_EMPHASIS_3_5;
-       case DP_TRAIN_VOLTAGE_SWING_1200:
-       default:
-               return DP_TRAIN_PRE_EMPHASIS_0;
-       }
-}
+#define DP_PRE_EMPHASIS_MAX    DP_TRAIN_PRE_EMPHASIS_9_5
 
 static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
                                int lane_count,
@@ -308,10 +378,10 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
        }
 
        if (v >= DP_VOLTAGE_MAX)
-               v = DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED;
+               v |= DP_TRAIN_MAX_SWING_REACHED;
 
-       if (p >= dp_pre_emphasis_max(v))
-               p = dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+       if (p >= DP_PRE_EMPHASIS_MAX)
+               p |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
 
        DRM_DEBUG_KMS("using signal parameters: voltage %s pre_emph %s\n",
                  voltage_names[(v & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
@@ -321,110 +391,109 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
                train_set[lane] = v | p;
 }
 
-union aux_channel_transaction {
-       PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
-       PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
-};
-
-/* radeon aux chan functions */
-bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes,
-                          int num_bytes, u8 *read_byte,
-                          u8 read_buf_len, u8 delay)
+/* convert bits per color to bits per pixel */
+/* get bpc from the EDID */
+static int convert_bpc_to_bpp(int bpc)
 {
-       struct drm_device *dev = chan->dev;
-       struct radeon_device *rdev = dev->dev_private;
-       union aux_channel_transaction args;
-       int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
-       unsigned char *base;
-       int retry_count = 0;
-
-       memset(&args, 0, sizeof(args));
-
-       base = (unsigned char *)rdev->mode_info.atom_context->scratch;
-
-retry:
-       memcpy(base, req_bytes, num_bytes);
-
-       args.v1.lpAuxRequest = 0;
-       args.v1.lpDataOut = 16;
-       args.v1.ucDataOutLen = 0;
-       args.v1.ucChannelID = chan->rec.i2c_id;
-       args.v1.ucDelay = delay / 10;
-       if (ASIC_IS_DCE4(rdev))
-               args.v2.ucHPD_ID = chan->rec.hpd;
+       if (bpc == 0)
+               return 24;
+       else
+               return bpc * 3;
+}
 
-       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+/* get the max pix clock supported by the link rate and lane num */
+static int dp_get_max_dp_pix_clock(int link_rate,
+                                  int lane_num,
+                                  int bpp)
+{
+       return (link_rate * lane_num * 8) / bpp;
+}
 
-       if (args.v1.ucReplyStatus && !args.v1.ucDataOutLen) {
-               if (args.v1.ucReplyStatus == 0x20 && retry_count++ < 10)
-                       goto retry;
-               DRM_DEBUG_KMS("failed to get auxch %02x%02x %02x %02x 0x%02x %02x after %d retries\n",
-                         req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3],
-                         chan->rec.i2c_id, args.v1.ucReplyStatus, retry_count);
-               return false;
+static int dp_get_max_link_rate(u8 dpcd[DP_DPCD_SIZE])
+{
+       switch (dpcd[DP_MAX_LINK_RATE]) {
+       case DP_LINK_BW_1_62:
+       default:
+               return 162000;
+       case DP_LINK_BW_2_7:
+               return 270000;
+       case DP_LINK_BW_5_4:
+               return 540000;
        }
+}
 
-       if (args.v1.ucDataOutLen && read_byte && read_buf_len) {
-               if (read_buf_len < args.v1.ucDataOutLen) {
-                       DRM_ERROR("Buffer to small for return answer %d %d\n",
-                                 read_buf_len, args.v1.ucDataOutLen);
-                       return false;
-               }
-               {
-                       int len = min(read_buf_len, args.v1.ucDataOutLen);
-                       memcpy(read_byte, base + 16, len);
-               }
-       }
-       return true;
+static u8 dp_get_max_lane_number(u8 dpcd[DP_DPCD_SIZE])
+{
+       return dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
 }
 
-bool radeon_dp_aux_native_write(struct radeon_connector *radeon_connector, uint16_t address,
-                               uint8_t send_bytes, uint8_t *send)
+static u8 dp_get_dp_link_rate_coded(int link_rate)
 {
-       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
-       u8 msg[20];
-       u8 msg_len, dp_msg_len;
-       bool ret;
+       switch (link_rate) {
+       case 162000:
+       default:
+               return DP_LINK_BW_1_62;
+       case 270000:
+               return DP_LINK_BW_2_7;
+       case 540000:
+               return DP_LINK_BW_5_4;
+       }
+}
 
-       dp_msg_len = 4;
-       msg[0] = address;
-       msg[1] = address >> 8;
-       msg[2] = AUX_NATIVE_WRITE << 4;
-       dp_msg_len += send_bytes;
-       msg[3] = (dp_msg_len << 4) | (send_bytes - 1);
+/***** radeon specific DP functions *****/
 
-       if (send_bytes > 16)
-               return false;
+/* First get the min lane# when low rate is used according to pixel clock
+ * (prefer low rate), second check max lane# supported by DP panel,
+ * if the max lane# < low rate lane# then use max lane# instead.
+ */
+static int radeon_dp_get_dp_lane_number(struct drm_connector *connector,
+                                       u8 dpcd[DP_DPCD_SIZE],
+                                       int pix_clock)
+{
+       int bpp = convert_bpc_to_bpp(connector->display_info.bpc);
+       int max_link_rate = dp_get_max_link_rate(dpcd);
+       int max_lane_num = dp_get_max_lane_number(dpcd);
+       int lane_num;
+       int max_dp_pix_clock;
+
+       for (lane_num = 1; lane_num < max_lane_num; lane_num <<= 1) {
+               max_dp_pix_clock = dp_get_max_dp_pix_clock(max_link_rate, lane_num, bpp);
+               if (pix_clock <= max_dp_pix_clock)
+                       break;
+       }
 
-       memcpy(&msg[4], send, send_bytes);
-       msg_len = 4 + send_bytes;
-       ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, msg, msg_len, NULL, 0, 0);
-       return ret;
+       return lane_num;
 }
 
-bool radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, uint16_t address,
-                              uint8_t delay, uint8_t expected_bytes,
-                              uint8_t *read_p)
+static int radeon_dp_get_dp_link_clock(struct drm_connector *connector,
+                                      u8 dpcd[DP_DPCD_SIZE],
+                                      int pix_clock)
 {
-       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
-       u8 msg[20];
-       u8 msg_len, dp_msg_len;
-       bool ret = false;
-       msg_len = 4;
-       dp_msg_len = 4;
-       msg[0] = address;
-       msg[1] = address >> 8;
-       msg[2] = AUX_NATIVE_READ << 4;
-       msg[3] = (dp_msg_len) << 4;
-       msg[3] |= expected_bytes - 1;
+       int bpp = convert_bpc_to_bpp(connector->display_info.bpc);
+       int lane_num, max_pix_clock;
+
+       if (radeon_connector_encoder_is_dp_bridge(connector))
+               return 270000;
+
+       lane_num = radeon_dp_get_dp_lane_number(connector, dpcd, pix_clock);
+       max_pix_clock = dp_get_max_dp_pix_clock(162000, lane_num, bpp);
+       if (pix_clock <= max_pix_clock)
+               return 162000;
+       max_pix_clock = dp_get_max_dp_pix_clock(270000, lane_num, bpp);
+       if (pix_clock <= max_pix_clock)
+               return 270000;
+       if (radeon_connector_is_dp12_capable(connector)) {
+               max_pix_clock = dp_get_max_dp_pix_clock(540000, lane_num, bpp);
+               if (pix_clock <= max_pix_clock)
+                       return 540000;
+       }
 
-       ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, msg, msg_len, read_p, expected_bytes, delay);
-       return ret;
+       return dp_get_max_link_rate(dpcd);
 }
 
-/* radeon dp functions */
-static u8 radeon_dp_encoder_service(struct radeon_device *rdev, int action, int dp_clock,
-                                   uint8_t ucconfig, uint8_t lane_num)
+static u8 radeon_dp_encoder_service(struct radeon_device *rdev,
+                                   int action, int dp_clock,
+                                   u8 ucconfig, u8 lane_num)
 {
        DP_ENCODER_SERVICE_PARAMETERS args;
        int index = GetIndexIntoMasterTable(COMMAND, DPEncoderService);
@@ -454,60 +523,86 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector)
 {
        struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
        u8 msg[25];
-       int ret;
+       int ret, i;
 
-       ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, 0, 8, msg);
-       if (ret) {
+       ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, msg, 8, 0);
+       if (ret > 0) {
                memcpy(dig_connector->dpcd, msg, 8);
-               {
-                       int i;
-                       DRM_DEBUG_KMS("DPCD: ");
-                       for (i = 0; i < 8; i++)
-                               DRM_DEBUG_KMS("%02x ", msg[i]);
-                       DRM_DEBUG_KMS("\n");
-               }
+               DRM_DEBUG_KMS("DPCD: ");
+               for (i = 0; i < 8; i++)
+                       DRM_DEBUG_KMS("%02x ", msg[i]);
+               DRM_DEBUG_KMS("\n");
                return true;
        }
        dig_connector->dpcd[0] = 0;
        return false;
 }
 
+static void radeon_dp_set_panel_mode(struct drm_encoder *encoder,
+                                    struct drm_connector *connector)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
+
+       if (!ASIC_IS_DCE4(rdev))
+               return;
+
+       if (radeon_connector_encoder_is_dp_bridge(connector))
+               panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE;
+
+       atombios_dig_encoder_setup(encoder,
+                                  ATOM_ENCODER_CMD_SETUP_PANEL_MODE,
+                                  panel_mode);
+}
+
 void radeon_dp_set_link_config(struct drm_connector *connector,
                               struct drm_display_mode *mode)
 {
-       struct radeon_connector *radeon_connector;
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
        struct radeon_connector_atom_dig *dig_connector;
 
-       if ((connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) &&
-           (connector->connector_type != DRM_MODE_CONNECTOR_eDP))
-               return;
-
-       radeon_connector = to_radeon_connector(connector);
        if (!radeon_connector->con_priv)
                return;
        dig_connector = radeon_connector->con_priv;
 
-       dig_connector->dp_clock =
-               dp_link_clock_for_mode_clock(dig_connector->dpcd, mode->clock);
-       dig_connector->dp_lane_count =
-               dp_lanes_for_mode_clock(dig_connector->dpcd, mode->clock);
+       if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
+           (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
+               dig_connector->dp_clock =
+                       radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
+               dig_connector->dp_lane_count =
+                       radeon_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock);
+       }
 }
 
-int radeon_dp_mode_valid_helper(struct radeon_connector *radeon_connector,
+int radeon_dp_mode_valid_helper(struct drm_connector *connector,
                                struct drm_display_mode *mode)
 {
-       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct radeon_connector_atom_dig *dig_connector;
+       int dp_clock;
+
+       if (!radeon_connector->con_priv)
+               return MODE_CLOCK_HIGH;
+       dig_connector = radeon_connector->con_priv;
+
+       dp_clock =
+               radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
+
+       if ((dp_clock == 540000) &&
+           (!radeon_connector_is_dp12_capable(connector)))
+               return MODE_CLOCK_HIGH;
 
-       return dp_mode_valid(dig_connector->dpcd, mode->clock);
+       return MODE_OK;
 }
 
-static bool atom_dp_get_link_status(struct radeon_connector *radeon_connector,
-                                   u8 link_status[DP_LINK_STATUS_SIZE])
+static bool radeon_dp_get_link_status(struct radeon_connector *radeon_connector,
+                                     u8 link_status[DP_LINK_STATUS_SIZE])
 {
        int ret;
-       ret = radeon_dp_aux_native_read(radeon_connector, DP_LANE0_1_STATUS, 100,
-                                       DP_LINK_STATUS_SIZE, link_status);
-       if (!ret) {
+       ret = radeon_dp_aux_native_read(radeon_connector, DP_LANE0_1_STATUS,
+                                       link_status, DP_LINK_STATUS_SIZE, 100);
+       if (ret <= 0) {
                DRM_ERROR("displayport link status failed\n");
                return false;
        }
@@ -518,292 +613,309 @@ static bool atom_dp_get_link_status(struct radeon_connector *radeon_connector,
        return true;
 }
 
-bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector)
-{
-       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+struct radeon_dp_link_train_info {
+       struct radeon_device *rdev;
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+       int enc_id;
+       int dp_clock;
+       int dp_lane_count;
+       int rd_interval;
+       bool tp3_supported;
+       u8 dpcd[8];
+       u8 train_set[4];
        u8 link_status[DP_LINK_STATUS_SIZE];
+       u8 tries;
+};
 
-       if (!atom_dp_get_link_status(radeon_connector, link_status))
-               return false;
-       if (dp_channel_eq_ok(link_status, dig_connector->dp_lane_count))
-               return false;
-       return true;
+static void radeon_dp_update_vs_emph(struct radeon_dp_link_train_info *dp_info)
+{
+       /* set the initial vs/emph on the source */
+       atombios_dig_transmitter_setup(dp_info->encoder,
+                                      ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH,
+                                      0, dp_info->train_set[0]); /* sets all lanes at once */
+
+       /* set the vs/emph on the sink */
+       radeon_dp_aux_native_write(dp_info->radeon_connector, DP_TRAINING_LANE0_SET,
+                                  dp_info->train_set, dp_info->dp_lane_count, 0);
 }
 
-static void dp_set_power(struct radeon_connector *radeon_connector, u8 power_state)
+static void radeon_dp_set_tp(struct radeon_dp_link_train_info *dp_info, int tp)
 {
-       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+       int rtp = 0;
 
-       if (dig_connector->dpcd[0] >= 0x11) {
-               radeon_dp_aux_native_write(radeon_connector, DP_SET_POWER, 1,
-                                          &power_state);
+       /* set training pattern on the source */
+       if (ASIC_IS_DCE4(dp_info->rdev)) {
+               switch (tp) {
+               case DP_TRAINING_PATTERN_1:
+                       rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1;
+                       break;
+               case DP_TRAINING_PATTERN_2:
+                       rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2;
+                       break;
+               case DP_TRAINING_PATTERN_3:
+                       rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3;
+                       break;
+               }
+               atombios_dig_encoder_setup(dp_info->encoder, rtp, 0);
+       } else {
+               switch (tp) {
+               case DP_TRAINING_PATTERN_1:
+                       rtp = 0;
+                       break;
+               case DP_TRAINING_PATTERN_2:
+                       rtp = 1;
+                       break;
+               }
+               radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
+                                         dp_info->dp_clock, dp_info->enc_id, rtp);
        }
-}
 
-static void dp_set_downspread(struct radeon_connector *radeon_connector, u8 downspread)
-{
-       radeon_dp_aux_native_write(radeon_connector, DP_DOWNSPREAD_CTRL, 1,
-                                  &downspread);
+       /* enable training pattern on the sink */
+       radeon_write_dpcd_reg(dp_info->radeon_connector, DP_TRAINING_PATTERN_SET, tp);
 }
 
-static void dp_set_link_bw_lanes(struct radeon_connector *radeon_connector,
-                                u8 link_configuration[DP_LINK_CONFIGURATION_SIZE])
+static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)
 {
-       radeon_dp_aux_native_write(radeon_connector, DP_LINK_BW_SET, 2,
-                                  link_configuration);
-}
+       u8 tmp;
 
-static void dp_update_dpvs_emph(struct radeon_connector *radeon_connector,
-                               struct drm_encoder *encoder,
-                               u8 train_set[4])
-{
-       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
-       int i;
+       /* power up the sink */
+       if (dp_info->dpcd[0] >= 0x11)
+               radeon_write_dpcd_reg(dp_info->radeon_connector,
+                                     DP_SET_POWER, DP_SET_POWER_D0);
+
+       /* possibly enable downspread on the sink */
+       if (dp_info->dpcd[3] & 0x1)
+               radeon_write_dpcd_reg(dp_info->radeon_connector,
+                                     DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5);
+       else
+               radeon_write_dpcd_reg(dp_info->radeon_connector,
+                                     DP_DOWNSPREAD_CTRL, 0);
 
-       for (i = 0; i < dig_connector->dp_lane_count; i++)
-               atombios_dig_transmitter_setup(encoder,
-                                              ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH,
-                                              i, train_set[i]);
+       radeon_dp_set_panel_mode(dp_info->encoder, dp_info->connector);
 
-       radeon_dp_aux_native_write(radeon_connector, DP_TRAINING_LANE0_SET,
-                                  dig_connector->dp_lane_count, train_set);
-}
+       /* set the lane count on the sink */
+       tmp = dp_info->dp_lane_count;
+       if (dp_info->dpcd[0] >= 0x11)
+               tmp |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+       radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LANE_COUNT_SET, tmp);
 
-static void dp_set_training(struct radeon_connector *radeon_connector,
-                           u8 training)
-{
-       radeon_dp_aux_native_write(radeon_connector, DP_TRAINING_PATTERN_SET,
-                                  1, &training);
-}
+       /* set the link rate on the sink */
+       tmp = dp_get_dp_link_rate_coded(dp_info->dp_clock);
+       radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LINK_BW_SET, tmp);
 
-void dp_link_train(struct drm_encoder *encoder,
-                  struct drm_connector *connector)
-{
-       struct drm_device *dev = encoder->dev;
-       struct radeon_device *rdev = dev->dev_private;
-       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-       struct radeon_encoder_atom_dig *dig;
-       struct radeon_connector *radeon_connector;
-       struct radeon_connector_atom_dig *dig_connector;
-       int enc_id = 0;
-       bool clock_recovery, channel_eq;
-       u8 link_status[DP_LINK_STATUS_SIZE];
-       u8 link_configuration[DP_LINK_CONFIGURATION_SIZE];
-       u8 tries, voltage;
-       u8 train_set[4];
-       int i;
+       /* start training on the source */
+       if (ASIC_IS_DCE4(dp_info->rdev))
+               atombios_dig_encoder_setup(dp_info->encoder,
+                                          ATOM_ENCODER_CMD_DP_LINK_TRAINING_START, 0);
+       else
+               radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_START,
+                                         dp_info->dp_clock, dp_info->enc_id, 0);
 
-       if ((connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) &&
-           (connector->connector_type != DRM_MODE_CONNECTOR_eDP))
-               return;
+       /* disable the training pattern on the sink */
+       radeon_write_dpcd_reg(dp_info->radeon_connector,
+                             DP_TRAINING_PATTERN_SET,
+                             DP_TRAINING_PATTERN_DISABLE);
 
-       if (!radeon_encoder->enc_priv)
-               return;
-       dig = radeon_encoder->enc_priv;
+       return 0;
+}
 
-       radeon_connector = to_radeon_connector(connector);
-       if (!radeon_connector->con_priv)
-               return;
-       dig_connector = radeon_connector->con_priv;
+static int radeon_dp_link_train_finish(struct radeon_dp_link_train_info *dp_info)
+{
+       udelay(400);
 
-       if (dig->dig_encoder)
-               enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER;
-       else
-               enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER;
-       if (dig->linkb)
-               enc_id |= ATOM_DP_CONFIG_LINK_B;
-       else
-               enc_id |= ATOM_DP_CONFIG_LINK_A;
+       /* disable the training pattern on the sink */
+       radeon_write_dpcd_reg(dp_info->radeon_connector,
+                             DP_TRAINING_PATTERN_SET,
+                             DP_TRAINING_PATTERN_DISABLE);
 
-       memset(link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
-       if (dig_connector->dp_clock == 270000)
-               link_configuration[0] = DP_LINK_BW_2_7;
+       /* disable the training pattern on the source */
+       if (ASIC_IS_DCE4(dp_info->rdev))
+               atombios_dig_encoder_setup(dp_info->encoder,
+                                          ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE, 0);
        else
-               link_configuration[0] = DP_LINK_BW_1_62;
-       link_configuration[1] = dig_connector->dp_lane_count;
-       if (dig_connector->dpcd[0] >= 0x11)
-               link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+               radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_COMPLETE,
+                                         dp_info->dp_clock, dp_info->enc_id, 0);
 
-       /* power up the sink */
-       dp_set_power(radeon_connector, DP_SET_POWER_D0);
-       /* disable the training pattern on the sink */
-       dp_set_training(radeon_connector, DP_TRAINING_PATTERN_DISABLE);
-       /* set link bw and lanes on the sink */
-       dp_set_link_bw_lanes(radeon_connector, link_configuration);
-       /* disable downspread on the sink */
-       dp_set_downspread(radeon_connector, 0);
-       if (ASIC_IS_DCE4(rdev)) {
-               /* start training on the source */
-               atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_START);
-               /* set training pattern 1 on the source */
-               atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1);
-       } else {
-               /* start training on the source */
-               radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_START,
-                                         dig_connector->dp_clock, enc_id, 0);
-               /* set training pattern 1 on the source */
-               radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
-                                         dig_connector->dp_clock, enc_id, 0);
-       }
+       return 0;
+}
 
-       /* set initial vs/emph */
-       memset(train_set, 0, 4);
-       udelay(400);
-       /* set training pattern 1 on the sink */
-       dp_set_training(radeon_connector, DP_TRAINING_PATTERN_1);
+static int radeon_dp_link_train_cr(struct radeon_dp_link_train_info *dp_info)
+{
+       bool clock_recovery;
+       u8 voltage;
+       int i;
 
-       dp_update_dpvs_emph(radeon_connector, encoder, train_set);
+       radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_1);
+       memset(dp_info->train_set, 0, 4);
+       radeon_dp_update_vs_emph(dp_info);
+
+       udelay(400);
 
        /* clock recovery loop */
        clock_recovery = false;
-       tries = 0;
+       dp_info->tries = 0;
        voltage = 0xff;
-       for (;;) {
-               udelay(100);
-               if (!atom_dp_get_link_status(radeon_connector, link_status))
+       while (1) {
+               if (dp_info->rd_interval == 0)
+                       udelay(100);
+               else
+                       mdelay(dp_info->rd_interval * 4);
+
+               if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status))
                        break;
 
-               if (dp_clock_recovery_ok(link_status, dig_connector->dp_lane_count)) {
+               if (dp_clock_recovery_ok(dp_info->link_status, dp_info->dp_lane_count)) {
                        clock_recovery = true;
                        break;
                }
 
-               for (i = 0; i < dig_connector->dp_lane_count; i++) {
-                       if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+               for (i = 0; i < dp_info->dp_lane_count; i++) {
+                       if ((dp_info->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
                                break;
                }
-               if (i == dig_connector->dp_lane_count) {
+               if (i == dp_info->dp_lane_count) {
                        DRM_ERROR("clock recovery reached max voltage\n");
                        break;
                }
 
-               if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
-                       ++tries;
-                       if (tries == 5) {
+               if ((dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+                       ++dp_info->tries;
+                       if (dp_info->tries == 5) {
                                DRM_ERROR("clock recovery tried 5 times\n");
                                break;
                        }
                } else
-                       tries = 0;
+                       dp_info->tries = 0;
 
-               voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+               voltage = dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
 
                /* Compute new train_set as requested by sink */
-               dp_get_adjust_train(link_status, dig_connector->dp_lane_count, train_set);
-               dp_update_dpvs_emph(radeon_connector, encoder, train_set);
+               dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count, dp_info->train_set);
+
+               radeon_dp_update_vs_emph(dp_info);
        }
-       if (!clock_recovery)
+       if (!clock_recovery) {
                DRM_ERROR("clock recovery failed\n");
-       else
+               return -1;
+       } else {
                DRM_DEBUG_KMS("clock recovery at voltage %d pre-emphasis %d\n",
-                         train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
-                         (train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >>
+                         dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
+                         (dp_info->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >>
                          DP_TRAIN_PRE_EMPHASIS_SHIFT);
+               return 0;
+       }
+}
 
+static int radeon_dp_link_train_ce(struct radeon_dp_link_train_info *dp_info)
+{
+       bool channel_eq;
 
-       /* set training pattern 2 on the sink */
-       dp_set_training(radeon_connector, DP_TRAINING_PATTERN_2);
-       /* set training pattern 2 on the source */
-       if (ASIC_IS_DCE4(rdev))
-               atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2);
+       if (dp_info->tp3_supported)
+               radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_3);
        else
-               radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
-                                         dig_connector->dp_clock, enc_id, 1);
+               radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_2);
 
        /* channel equalization loop */
-       tries = 0;
+       dp_info->tries = 0;
        channel_eq = false;
-       for (;;) {
-               udelay(400);
-               if (!atom_dp_get_link_status(radeon_connector, link_status))
+       while (1) {
+               if (dp_info->rd_interval == 0)
+                       udelay(400);
+               else
+                       mdelay(dp_info->rd_interval * 4);
+
+               if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status))
                        break;
 
-               if (dp_channel_eq_ok(link_status, dig_connector->dp_lane_count)) {
+               if (dp_channel_eq_ok(dp_info->link_status, dp_info->dp_lane_count)) {
                        channel_eq = true;
                        break;
                }
 
                /* Try 5 times */
-               if (tries > 5) {
+               if (dp_info->tries > 5) {
                        DRM_ERROR("channel eq failed: 5 tries\n");
                        break;
                }
 
                /* Compute new train_set as requested by sink */
-               dp_get_adjust_train(link_status, dig_connector->dp_lane_count, train_set);
-               dp_update_dpvs_emph(radeon_connector, encoder, train_set);
+               dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count, dp_info->train_set);
 
-               tries++;
+               radeon_dp_update_vs_emph(dp_info);
+               dp_info->tries++;
        }
 
-       if (!channel_eq)
+       if (!channel_eq) {
                DRM_ERROR("channel eq failed\n");
-       else
+               return -1;
+       } else {
                DRM_DEBUG_KMS("channel eq at voltage %d pre-emphasis %d\n",
-                         train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
-                         (train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
+                         dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
+                         (dp_info->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
                          >> DP_TRAIN_PRE_EMPHASIS_SHIFT);
-
-       /* disable the training pattern on the sink */
-       dp_set_training(radeon_connector, DP_TRAINING_PATTERN_DISABLE);
-
-       /* disable the training pattern on the source */
-       if (ASIC_IS_DCE4(rdev))
-               atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE);
-       else
-               radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_COMPLETE,
-                                         dig_connector->dp_clock, enc_id, 0);
+               return 0;
+       }
 }
 
-int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
-                        uint8_t write_byte, uint8_t *read_byte)
+void radeon_dp_link_train(struct drm_encoder *encoder,
+                         struct drm_connector *connector)
 {
-       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
-       struct radeon_i2c_chan *auxch = (struct radeon_i2c_chan *)adapter;
-       int ret = 0;
-       uint16_t address = algo_data->address;
-       uint8_t msg[5];
-       uint8_t reply[2];
-       int msg_len, dp_msg_len;
-       int reply_bytes;
-
-       /* Set up the command byte */
-       if (mode & MODE_I2C_READ)
-               msg[2] = AUX_I2C_READ << 4;
-       else
-               msg[2] = AUX_I2C_WRITE << 4;
-
-       if (!(mode & MODE_I2C_STOP))
-               msg[2] |= AUX_I2C_MOT << 4;
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct radeon_encoder_atom_dig *dig;
+       struct radeon_connector *radeon_connector;
+       struct radeon_connector_atom_dig *dig_connector;
+       struct radeon_dp_link_train_info dp_info;
+       u8 tmp;
 
-       msg[0] = address;
-       msg[1] = address >> 8;
+       if (!radeon_encoder->enc_priv)
+               return;
+       dig = radeon_encoder->enc_priv;
 
-       reply_bytes = 1;
+       radeon_connector = to_radeon_connector(connector);
+       if (!radeon_connector->con_priv)
+               return;
+       dig_connector = radeon_connector->con_priv;
 
-       msg_len = 4;
-       dp_msg_len = 3;
-       switch (mode) {
-       case MODE_I2C_WRITE:
-               msg[4] = write_byte;
-               msg_len++;
-               dp_msg_len += 2;
-               break;
-       case MODE_I2C_READ:
-               dp_msg_len += 1;
-               break;
-       default:
-               break;
-       }
+       if ((dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_DISPLAYPORT) &&
+           (dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_eDP))
+               return;
 
-       msg[3] = (dp_msg_len) << 4;
-       ret = radeon_process_aux_ch(auxch, msg, msg_len, reply, reply_bytes, 0);
+       dp_info.enc_id = 0;
+       if (dig->dig_encoder)
+               dp_info.enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER;
+       else
+               dp_info.enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER;
+       if (dig->linkb)
+               dp_info.enc_id |= ATOM_DP_CONFIG_LINK_B;
+       else
+               dp_info.enc_id |= ATOM_DP_CONFIG_LINK_A;
 
-       if (ret) {
-               if (read_byte)
-                       *read_byte = reply[0];
-               return reply_bytes;
-       }
-       return -EREMOTEIO;
+       dp_info.rd_interval = radeon_read_dpcd_reg(radeon_connector, DP_TRAINING_AUX_RD_INTERVAL);
+       tmp = radeon_read_dpcd_reg(radeon_connector, DP_MAX_LANE_COUNT);
+       if (ASIC_IS_DCE5(rdev) && (tmp & DP_TPS3_SUPPORTED))
+               dp_info.tp3_supported = true;
+       else
+               dp_info.tp3_supported = false;
+
+       memcpy(dp_info.dpcd, dig_connector->dpcd, 8);
+       dp_info.rdev = rdev;
+       dp_info.encoder = encoder;
+       dp_info.connector = connector;
+       dp_info.radeon_connector = radeon_connector;
+       dp_info.dp_lane_count = dig_connector->dp_lane_count;
+       dp_info.dp_clock = dig_connector->dp_clock;
+
+       if (radeon_dp_link_train_init(&dp_info))
+               goto done;
+       if (radeon_dp_link_train_cr(&dp_info))
+               goto done;
+       if (radeon_dp_link_train_ce(&dp_info))
+               goto done;
+done:
+       if (radeon_dp_link_train_finish(&dp_info))
+               return;
 }
-
index e148ab04b80b3adc88d0ac4a0329599f57ac2c00..7b4eeb7b4a8c5c3205e1f5c91cd3e51c53658c42 100644 (file)
 
 const u32 cayman_default_state[] =
 {
-       /* XXX fill in additional blit state */
+       0xc0066900,
+       0x00000000,
+       0x00000060, /* DB_RENDER_CONTROL */
+       0x00000000, /* DB_COUNT_CONTROL */
+       0x00000000, /* DB_DEPTH_VIEW */
+       0x0000002a, /* DB_RENDER_OVERRIDE */
+       0x00000000, /* DB_RENDER_OVERRIDE2 */
+       0x00000000, /* DB_HTILE_DATA_BASE */
 
        0xc0026900,
-       0x00000316,
-       0x0000000e, /* VGT_VERTEX_REUSE_BLOCK_CNTL */
-       0x00000010, /*  */
+       0x0000000a,
+       0x00000000, /* DB_STENCIL_CLEAR */
+       0x00000000, /* DB_DEPTH_CLEAR */
+
+       0xc0036900,
+       0x0000000f,
+       0x00000000, /* DB_DEPTH_INFO */
+       0x00000000, /* DB_Z_INFO */
+       0x00000000, /* DB_STENCIL_INFO */
+
+       0xc0016900,
+       0x00000080,
+       0x00000000, /* PA_SC_WINDOW_OFFSET */
+
+       0xc00d6900,
+       0x00000083,
+       0x0000ffff, /* PA_SC_CLIPRECT_RULE */
+       0x00000000, /* PA_SC_CLIPRECT_0_TL */
+       0x20002000, /* PA_SC_CLIPRECT_0_BR */
+       0x00000000,
+       0x20002000,
+       0x00000000,
+       0x20002000,
+       0x00000000,
+       0x20002000,
+       0xaaaaaaaa, /* PA_SC_EDGERULE */
+       0x00000000, /* PA_SU_HARDWARE_SCREEN_OFFSET */
+       0x0000000f, /* CB_TARGET_MASK */
+       0x0000000f, /* CB_SHADER_MASK */
+
+       0xc0226900,
+       0x00000094,
+       0x80000000, /* PA_SC_VPORT_SCISSOR_0_TL */
+       0x20002000, /* PA_SC_VPORT_SCISSOR_0_BR */
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x80000000,
+       0x20002000,
+       0x00000000, /* PA_SC_VPORT_ZMIN_0 */
+       0x3f800000, /* PA_SC_VPORT_ZMAX_0 */
+
+       0xc0016900,
+       0x000000d4,
+       0x00000000, /* SX_MISC */
 
        0xc0026900,
        0x000000d9,
        0x00000000, /* CP_RINGID */
        0x00000000, /* CP_VMID */
+
+       0xc0096900,
+       0x00000100,
+       0x00ffffff, /* VGT_MAX_VTX_INDX */
+       0x00000000, /* VGT_MIN_VTX_INDX */
+       0x00000000, /* VGT_INDX_OFFSET */
+       0x00000000, /* VGT_MULTI_PRIM_IB_RESET_INDX */
+       0x00000000, /* SX_ALPHA_TEST_CONTROL */
+       0x00000000, /* CB_BLEND_RED */
+       0x00000000, /* CB_BLEND_GREEN */
+       0x00000000, /* CB_BLEND_BLUE */
+       0x00000000, /* CB_BLEND_ALPHA */
+
+       0xc0016900,
+       0x00000187,
+       0x00000100, /* SPI_VS_OUT_ID_0 */
+
+       0xc0026900,
+       0x00000191,
+       0x00000100, /* SPI_PS_INPUT_CNTL_0 */
+       0x00000101, /* SPI_PS_INPUT_CNTL_1 */
+
+       0xc0016900,
+       0x000001b1,
+       0x00000000, /* SPI_VS_OUT_CONFIG */
+
+       0xc0106900,
+       0x000001b3,
+       0x20000001, /* SPI_PS_IN_CONTROL_0 */
+       0x00000000, /* SPI_PS_IN_CONTROL_1 */
+       0x00000000, /* SPI_INTERP_CONTROL_0 */
+       0x00000000, /* SPI_INPUT_Z */
+       0x00000000, /* SPI_FOG_CNTL */
+       0x00100000, /* SPI_BARYC_CNTL */
+       0x00000000, /* SPI_PS_IN_CONTROL_2 */
+       0x00000000, /* SPI_COMPUTE_INPUT_CNTL */
+       0x00000000, /* SPI_COMPUTE_NUM_THREAD_X */
+       0x00000000, /* SPI_COMPUTE_NUM_THREAD_Y */
+       0x00000000, /* SPI_COMPUTE_NUM_THREAD_Z */
+       0x00000000, /* SPI_GPR_MGMT */
+       0x00000000, /* SPI_LDS_MGMT */
+       0x00000000, /* SPI_STACK_MGMT */
+       0x00000000, /* SPI_WAVE_MGMT_1 */
+       0x00000000, /* SPI_WAVE_MGMT_2 */
+
+       0xc0016900,
+       0x000001e0,
+       0x00000000, /* CB_BLEND0_CONTROL */
+
+       0xc00e6900,
+       0x00000200,
+       0x00000000, /* DB_DEPTH_CONTROL */
+       0x00000000, /* DB_EQAA */
+       0x00cc0010, /* CB_COLOR_CONTROL */
+       0x00000210, /* DB_SHADER_CONTROL */
+       0x00010000, /* PA_CL_CLIP_CNTL */
+       0x00000004, /* PA_SU_SC_MODE_CNTL */
+       0x00000100, /* PA_CL_VTE_CNTL */
+       0x00000000, /* PA_CL_VS_OUT_CNTL */
+       0x00000000, /* PA_CL_NANINF_CNTL */
+       0x00000000, /* PA_SU_LINE_STIPPLE_CNTL */
+       0x00000000, /* PA_SU_LINE_STIPPLE_SCALE */
+       0x00000000, /* PA_SU_PRIM_FILTER_CNTL */
+       0x00000000, /*  */
+       0x00000000, /*  */
+
+       0xc0026900,
+       0x00000229,
+       0x00000000, /* SQ_PGM_START_FS */
+       0x00000000,
+
+       0xc0016900,
+       0x0000023b,
+       0x00000000, /* SQ_LDS_ALLOC_PS */
+
+       0xc0066900,
+       0x00000240,
+       0x00000000, /* SQ_ESGS_RING_ITEMSIZE */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+
+       0xc0046900,
+       0x00000247,
+       0x00000000, /* SQ_GS_VERT_ITEMSIZE */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+
+       0xc0116900,
+       0x00000280,
+       0x00000000, /* PA_SU_POINT_SIZE */
+       0x00000000, /* PA_SU_POINT_MINMAX */
+       0x00000008, /* PA_SU_LINE_CNTL */
+       0x00000000, /* PA_SC_LINE_STIPPLE */
+       0x00000000, /* VGT_OUTPUT_PATH_CNTL */
+       0x00000000, /* VGT_HOS_CNTL */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000, /* VGT_GS_MODE */
+
+       0xc0026900,
+       0x00000292,
+       0x00000000, /* PA_SC_MODE_CNTL_0 */
+       0x00000000, /* PA_SC_MODE_CNTL_1 */
+
+       0xc0016900,
+       0x000002a1,
+       0x00000000, /* VGT_PRIMITIVEID_EN */
+
+       0xc0016900,
+       0x000002a5,
+       0x00000000, /* VGT_MULTI_PRIM_IB_RESET_EN */
+
+       0xc0026900,
+       0x000002a8,
+       0x00000000, /* VGT_INSTANCE_STEP_RATE_0 */
+       0x00000000,
+
+       0xc0026900,
+       0x000002ad,
+       0x00000000, /* VGT_REUSE_OFF */
+       0x00000000,
+
+       0xc0016900,
+       0x000002d5,
+       0x00000000, /* VGT_SHADER_STAGES_EN */
+
+       0xc0016900,
+       0x000002dc,
+       0x0000aa00, /* DB_ALPHA_TO_MASK */
+
+       0xc0066900,
+       0x000002de,
+       0x00000000, /* PA_SU_POLY_OFFSET_DB_FMT_CNTL */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+
+       0xc0026900,
+       0x000002e5,
+       0x00000000, /* VGT_STRMOUT_CONFIG */
+       0x00000000,
+
+       0xc01b6900,
+       0x000002f5,
+       0x76543210, /* PA_SC_CENTROID_PRIORITY_0 */
+       0xfedcba98, /* PA_SC_CENTROID_PRIORITY_1 */
+       0x00000000, /* PA_SC_LINE_CNTL */
+       0x00000000, /* PA_SC_AA_CONFIG */
+       0x00000005, /* PA_SU_VTX_CNTL */
+       0x3f800000, /* PA_CL_GB_VERT_CLIP_ADJ */
+       0x3f800000, /* PA_CL_GB_VERT_DISC_ADJ */
+       0x3f800000, /* PA_CL_GB_HORZ_CLIP_ADJ */
+       0x3f800000, /* PA_CL_GB_HORZ_DISC_ADJ */
+       0x00000000, /* PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0 */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0xffffffff, /* PA_SC_AA_MASK_X0Y0_X1Y0 */
+       0xffffffff,
+
+       0xc0026900,
+       0x00000316,
+       0x0000000e, /* VGT_VERTEX_REUSE_BLOCK_CNTL */
+       0x00000010, /*  */
+};
+
+const u32 cayman_vs[] =
+{
+       0x00000004,
+       0x80400400,
+       0x0000a03c,
+       0x95000688,
+       0x00004000,
+       0x15000688,
+       0x00000000,
+       0x88000000,
+       0x04000000,
+       0x67961001,
+#ifdef __BIG_ENDIAN
+       0x00020000,
+#else
+       0x00000000,
+#endif
+       0x00000000,
+       0x04000000,
+       0x67961000,
+#ifdef __BIG_ENDIAN
+       0x00020008,
+#else
+       0x00000008,
+#endif
+       0x00000000,
+};
+
+const u32 cayman_ps[] =
+{
+       0x00000004,
+       0xa00c0000,
+       0x00000008,
+       0x80400000,
+       0x00000000,
+       0x95000688,
+       0x00000000,
+       0x88000000,
+       0x00380400,
+       0x00146b10,
+       0x00380000,
+       0x20146b10,
+       0x00380400,
+       0x40146b00,
+       0x80380000,
+       0x60146b00,
+       0x00000010,
+       0x000d1000,
+       0xb0800000,
+       0x00000000,
 };
 
+const u32 cayman_ps_size = ARRAY_SIZE(cayman_ps);
+const u32 cayman_vs_size = ARRAY_SIZE(cayman_vs);
 const u32 cayman_default_size = ARRAY_SIZE(cayman_default_state);
index 33b75e5d0fa468e64d1a0c15292fa72a7bc0cee6..f5d0e9a602675d24b135a4491d583d44e53bcbec 100644 (file)
 #ifndef CAYMAN_BLIT_SHADERS_H
 #define CAYMAN_BLIT_SHADERS_H
 
+extern const u32 cayman_ps[];
+extern const u32 cayman_vs[];
 extern const u32 cayman_default_state[];
 
+extern const u32 cayman_ps_size, cayman_vs_size;
 extern const u32 cayman_default_size;
 
 #endif
index 9073e3bfb08c7cde39ee411700e0ba838611fc2c..12d2fdc52414463d42cdc0ecb2a66f0b7e1e76e2 100644 (file)
@@ -88,21 +88,40 @@ u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
 /* get temperature in millidegrees */
 int evergreen_get_temp(struct radeon_device *rdev)
 {
-       u32 temp = (RREG32(CG_MULT_THERMAL_STATUS) & ASIC_T_MASK) >>
-               ASIC_T_SHIFT;
-       u32 actual_temp = 0;
-
-       if (temp & 0x400)
-               actual_temp = -256;
-       else if (temp & 0x200)
-               actual_temp = 255;
-       else if (temp & 0x100) {
-               actual_temp = temp & 0x1ff;
-               actual_temp |= ~0x1ff;
-       } else
-               actual_temp = temp & 0xff;
+       u32 temp, toffset;
+       int actual_temp = 0;
+
+       if (rdev->family == CHIP_JUNIPER) {
+               toffset = (RREG32(CG_THERMAL_CTRL) & TOFFSET_MASK) >>
+                       TOFFSET_SHIFT;
+               temp = (RREG32(CG_TS0_STATUS) & TS0_ADC_DOUT_MASK) >>
+                       TS0_ADC_DOUT_SHIFT;
+
+               if (toffset & 0x100)
+                       actual_temp = temp / 2 - (0x200 - toffset);
+               else
+                       actual_temp = temp / 2 + toffset;
+
+               actual_temp = actual_temp * 1000;
 
-       return (actual_temp * 1000) / 2;
+       } else {
+               temp = (RREG32(CG_MULT_THERMAL_STATUS) & ASIC_T_MASK) >>
+                       ASIC_T_SHIFT;
+
+               if (temp & 0x400)
+                       actual_temp = -256;
+               else if (temp & 0x200)
+                       actual_temp = 255;
+               else if (temp & 0x100) {
+                       actual_temp = temp & 0x1ff;
+                       actual_temp |= ~0x1ff;
+               } else
+                       actual_temp = temp & 0xff;
+
+               actual_temp = (actual_temp * 1000) / 2;
+       }
+
+       return actual_temp;
 }
 
 int sumo_get_temp(struct radeon_device *rdev)
@@ -121,11 +140,17 @@ void evergreen_pm_misc(struct radeon_device *rdev)
        struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage;
 
        if (voltage->type == VOLTAGE_SW) {
+               /* 0xff01 is a flag rather then an actual voltage */
+               if (voltage->voltage == 0xff01)
+                       return;
                if (voltage->voltage && (voltage->voltage != rdev->pm.current_vddc)) {
                        radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC);
                        rdev->pm.current_vddc = voltage->voltage;
                        DRM_DEBUG("Setting: vddc: %d\n", voltage->voltage);
                }
+               /* 0xff01 is a flag rather then an actual voltage */
+               if (voltage->vddci == 0xff01)
+                       return;
                if (voltage->vddci && (voltage->vddci != rdev->pm.current_vddci)) {
                        radeon_atom_set_voltage(rdev, voltage->vddci, SET_VOLTAGE_TYPE_ASIC_VDDCI);
                        rdev->pm.current_vddci = voltage->vddci;
@@ -1415,6 +1440,8 @@ static u32 evergreen_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
        case CHIP_CEDAR:
        case CHIP_REDWOOD:
        case CHIP_PALM:
+       case CHIP_SUMO:
+       case CHIP_SUMO2:
        case CHIP_TURKS:
        case CHIP_CAICOS:
                force_no_swizzle = false;
@@ -1544,6 +1571,8 @@ static void evergreen_program_channel_remap(struct radeon_device *rdev)
        case CHIP_REDWOOD:
        case CHIP_CEDAR:
        case CHIP_PALM:
+       case CHIP_SUMO:
+       case CHIP_SUMO2:
        case CHIP_TURKS:
        case CHIP_CAICOS:
        default:
@@ -1578,7 +1607,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
        u32 sq_stack_resource_mgmt_2;
        u32 sq_stack_resource_mgmt_3;
        u32 vgt_cache_invalidation;
-       u32 hdp_host_path_cntl;
+       u32 hdp_host_path_cntl, tmp;
        int i, j, num_shader_engines, ps_thread_count;
 
        switch (rdev->family) {
@@ -1685,6 +1714,54 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
                rdev->config.evergreen.max_hw_contexts = 4;
                rdev->config.evergreen.sq_num_cf_insts = 1;
 
+               rdev->config.evergreen.sc_prim_fifo_size = 0x40;
+               rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30;
+               rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130;
+               break;
+       case CHIP_SUMO:
+               rdev->config.evergreen.num_ses = 1;
+               rdev->config.evergreen.max_pipes = 4;
+               rdev->config.evergreen.max_tile_pipes = 2;
+               if (rdev->pdev->device == 0x9648)
+                       rdev->config.evergreen.max_simds = 3;
+               else if ((rdev->pdev->device == 0x9647) ||
+                        (rdev->pdev->device == 0x964a))
+                       rdev->config.evergreen.max_simds = 4;
+               else
+                       rdev->config.evergreen.max_simds = 5;
+               rdev->config.evergreen.max_backends = 2 * rdev->config.evergreen.num_ses;
+               rdev->config.evergreen.max_gprs = 256;
+               rdev->config.evergreen.max_threads = 248;
+               rdev->config.evergreen.max_gs_threads = 32;
+               rdev->config.evergreen.max_stack_entries = 256;
+               rdev->config.evergreen.sx_num_of_sets = 4;
+               rdev->config.evergreen.sx_max_export_size = 256;
+               rdev->config.evergreen.sx_max_export_pos_size = 64;
+               rdev->config.evergreen.sx_max_export_smx_size = 192;
+               rdev->config.evergreen.max_hw_contexts = 8;
+               rdev->config.evergreen.sq_num_cf_insts = 2;
+
+               rdev->config.evergreen.sc_prim_fifo_size = 0x40;
+               rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30;
+               rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130;
+               break;
+       case CHIP_SUMO2:
+               rdev->config.evergreen.num_ses = 1;
+               rdev->config.evergreen.max_pipes = 4;
+               rdev->config.evergreen.max_tile_pipes = 4;
+               rdev->config.evergreen.max_simds = 2;
+               rdev->config.evergreen.max_backends = 1 * rdev->config.evergreen.num_ses;
+               rdev->config.evergreen.max_gprs = 256;
+               rdev->config.evergreen.max_threads = 248;
+               rdev->config.evergreen.max_gs_threads = 32;
+               rdev->config.evergreen.max_stack_entries = 512;
+               rdev->config.evergreen.sx_num_of_sets = 4;
+               rdev->config.evergreen.sx_max_export_size = 256;
+               rdev->config.evergreen.sx_max_export_pos_size = 64;
+               rdev->config.evergreen.sx_max_export_smx_size = 192;
+               rdev->config.evergreen.max_hw_contexts = 8;
+               rdev->config.evergreen.sq_num_cf_insts = 2;
+
                rdev->config.evergreen.sc_prim_fifo_size = 0x40;
                rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30;
                rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130;
@@ -1936,8 +2013,12 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
                rdev->config.evergreen.tile_config |= (3 << 0);
                break;
        }
-       rdev->config.evergreen.tile_config |=
-               ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
+       /* num banks is 8 on all fusion asics. 0 = 4, 1 = 8, 2 = 16 */
+       if (rdev->flags & RADEON_IS_IGP)
+               rdev->config.evergreen.tile_config |= 1 << 4;
+       else
+               rdev->config.evergreen.tile_config |=
+                       ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
        rdev->config.evergreen.tile_config |=
                ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) << 8;
        rdev->config.evergreen.tile_config |=
@@ -2035,6 +2116,8 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
        switch (rdev->family) {
        case CHIP_CEDAR:
        case CHIP_PALM:
+       case CHIP_SUMO:
+       case CHIP_SUMO2:
        case CHIP_CAICOS:
                /* no vertex cache */
                sq_config &= ~VC_ENABLE;
@@ -2056,6 +2139,8 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
        switch (rdev->family) {
        case CHIP_CEDAR:
        case CHIP_PALM:
+       case CHIP_SUMO:
+       case CHIP_SUMO2:
                ps_thread_count = 96;
                break;
        default:
@@ -2095,6 +2180,8 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
        switch (rdev->family) {
        case CHIP_CEDAR:
        case CHIP_PALM:
+       case CHIP_SUMO:
+       case CHIP_SUMO2:
        case CHIP_CAICOS:
                vgt_cache_invalidation = CACHE_INVALIDATION(TC_ONLY);
                break;
@@ -2141,6 +2228,10 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
        for (i = SQ_ALU_CONST_BUFFER_SIZE_HS_0; i < 0x29000; i += 4)
                WREG32(i, 0);
 
+       tmp = RREG32(HDP_MISC_CNTL);
+       tmp |= HDP_FLUSH_INVALIDATE_CACHE;
+       WREG32(HDP_MISC_CNTL, tmp);
+
        hdp_host_path_cntl = RREG32(HDP_HOST_PATH_CNTL);
        WREG32(HDP_HOST_PATH_CNTL, hdp_host_path_cntl);
 
@@ -2610,28 +2701,25 @@ static inline u32 evergreen_get_ih_wptr(struct radeon_device *rdev)
 
 int evergreen_irq_process(struct radeon_device *rdev)
 {
-       u32 wptr = evergreen_get_ih_wptr(rdev);
-       u32 rptr = rdev->ih.rptr;
+       u32 wptr;
+       u32 rptr;
        u32 src_id, src_data;
        u32 ring_index;
        unsigned long flags;
        bool queue_hotplug = false;
 
-       DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr);
-       if (!rdev->ih.enabled)
+       if (!rdev->ih.enabled || rdev->shutdown)
                return IRQ_NONE;
 
-       spin_lock_irqsave(&rdev->ih.lock, flags);
+       wptr = evergreen_get_ih_wptr(rdev);
+       rptr = rdev->ih.rptr;
+       DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr);
 
+       spin_lock_irqsave(&rdev->ih.lock, flags);
        if (rptr == wptr) {
                spin_unlock_irqrestore(&rdev->ih.lock, flags);
                return IRQ_NONE;
        }
-       if (rdev->shutdown) {
-               spin_unlock_irqrestore(&rdev->ih.lock, flags);
-               return IRQ_NONE;
-       }
-
 restart_ih:
        /* display interrupts */
        evergreen_irq_ack(rdev);
@@ -2860,7 +2948,7 @@ restart_ih:
                        radeon_fence_process(rdev);
                        break;
                case 233: /* GUI IDLE */
-                       DRM_DEBUG("IH: CP EOP\n");
+                       DRM_DEBUG("IH: GUI idle\n");
                        rdev->pm.gui_idle = true;
                        wake_up(&rdev->irq.idle_queue);
                        break;
index ba06a69c6de857bd250b6c7258faa8a308361e43..57f3bc17b87e09a9dd0d1fd99fe66800e43ee9fb 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "evergreend.h"
 #include "evergreen_blit_shaders.h"
+#include "cayman_blit_shaders.h"
 
 #define DI_PT_RECTLIST        0x11
 #define DI_INDEX_SIZE_16_BIT  0x0
@@ -152,6 +153,8 @@ set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr)
 
        if ((rdev->family == CHIP_CEDAR) ||
            (rdev->family == CHIP_PALM) ||
+           (rdev->family == CHIP_SUMO) ||
+           (rdev->family == CHIP_SUMO2) ||
            (rdev->family == CHIP_CAICOS))
                cp_set_surface_sync(rdev,
                                    PACKET3_TC_ACTION_ENA, 48, gpu_addr);
@@ -199,6 +202,16 @@ static void
 set_scissors(struct radeon_device *rdev, int x1, int y1,
             int x2, int y2)
 {
+       /* workaround some hw bugs */
+       if (x2 == 0)
+               x1 = 1;
+       if (y2 == 0)
+               y1 = 1;
+       if (rdev->family == CHIP_CAYMAN) {
+               if ((x2 == 1) && (y2 == 1))
+                       x2 = 2;
+       }
+
        radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
        radeon_ring_write(rdev, (PA_SC_SCREEN_SCISSOR_TL - PACKET3_SET_CONTEXT_REG_START) >> 2);
        radeon_ring_write(rdev, (x1 << 0) | (y1 << 16));
@@ -255,238 +268,284 @@ set_default_state(struct radeon_device *rdev)
        u64 gpu_addr;
        int dwords;
 
-       switch (rdev->family) {
-       case CHIP_CEDAR:
-       default:
-               num_ps_gprs = 93;
-               num_vs_gprs = 46;
-               num_temp_gprs = 4;
-               num_gs_gprs = 31;
-               num_es_gprs = 31;
-               num_hs_gprs = 23;
-               num_ls_gprs = 23;
-               num_ps_threads = 96;
-               num_vs_threads = 16;
-               num_gs_threads = 16;
-               num_es_threads = 16;
-               num_hs_threads = 16;
-               num_ls_threads = 16;
-               num_ps_stack_entries = 42;
-               num_vs_stack_entries = 42;
-               num_gs_stack_entries = 42;
-               num_es_stack_entries = 42;
-               num_hs_stack_entries = 42;
-               num_ls_stack_entries = 42;
-               break;
-       case CHIP_REDWOOD:
-               num_ps_gprs = 93;
-               num_vs_gprs = 46;
-               num_temp_gprs = 4;
-               num_gs_gprs = 31;
-               num_es_gprs = 31;
-               num_hs_gprs = 23;
-               num_ls_gprs = 23;
-               num_ps_threads = 128;
-               num_vs_threads = 20;
-               num_gs_threads = 20;
-               num_es_threads = 20;
-               num_hs_threads = 20;
-               num_ls_threads = 20;
-               num_ps_stack_entries = 42;
-               num_vs_stack_entries = 42;
-               num_gs_stack_entries = 42;
-               num_es_stack_entries = 42;
-               num_hs_stack_entries = 42;
-               num_ls_stack_entries = 42;
-               break;
-       case CHIP_JUNIPER:
-               num_ps_gprs = 93;
-               num_vs_gprs = 46;
-               num_temp_gprs = 4;
-               num_gs_gprs = 31;
-               num_es_gprs = 31;
-               num_hs_gprs = 23;
-               num_ls_gprs = 23;
-               num_ps_threads = 128;
-               num_vs_threads = 20;
-               num_gs_threads = 20;
-               num_es_threads = 20;
-               num_hs_threads = 20;
-               num_ls_threads = 20;
-               num_ps_stack_entries = 85;
-               num_vs_stack_entries = 85;
-               num_gs_stack_entries = 85;
-               num_es_stack_entries = 85;
-               num_hs_stack_entries = 85;
-               num_ls_stack_entries = 85;
-               break;
-       case CHIP_CYPRESS:
-       case CHIP_HEMLOCK:
-               num_ps_gprs = 93;
-               num_vs_gprs = 46;
-               num_temp_gprs = 4;
-               num_gs_gprs = 31;
-               num_es_gprs = 31;
-               num_hs_gprs = 23;
-               num_ls_gprs = 23;
-               num_ps_threads = 128;
-               num_vs_threads = 20;
-               num_gs_threads = 20;
-               num_es_threads = 20;
-               num_hs_threads = 20;
-               num_ls_threads = 20;
-               num_ps_stack_entries = 85;
-               num_vs_stack_entries = 85;
-               num_gs_stack_entries = 85;
-               num_es_stack_entries = 85;
-               num_hs_stack_entries = 85;
-               num_ls_stack_entries = 85;
-               break;
-       case CHIP_PALM:
-               num_ps_gprs = 93;
-               num_vs_gprs = 46;
-               num_temp_gprs = 4;
-               num_gs_gprs = 31;
-               num_es_gprs = 31;
-               num_hs_gprs = 23;
-               num_ls_gprs = 23;
-               num_ps_threads = 96;
-               num_vs_threads = 16;
-               num_gs_threads = 16;
-               num_es_threads = 16;
-               num_hs_threads = 16;
-               num_ls_threads = 16;
-               num_ps_stack_entries = 42;
-               num_vs_stack_entries = 42;
-               num_gs_stack_entries = 42;
-               num_es_stack_entries = 42;
-               num_hs_stack_entries = 42;
-               num_ls_stack_entries = 42;
-               break;
-       case CHIP_BARTS:
-               num_ps_gprs = 93;
-               num_vs_gprs = 46;
-               num_temp_gprs = 4;
-               num_gs_gprs = 31;
-               num_es_gprs = 31;
-               num_hs_gprs = 23;
-               num_ls_gprs = 23;
-               num_ps_threads = 128;
-               num_vs_threads = 20;
-               num_gs_threads = 20;
-               num_es_threads = 20;
-               num_hs_threads = 20;
-               num_ls_threads = 20;
-               num_ps_stack_entries = 85;
-               num_vs_stack_entries = 85;
-               num_gs_stack_entries = 85;
-               num_es_stack_entries = 85;
-               num_hs_stack_entries = 85;
-               num_ls_stack_entries = 85;
-               break;
-       case CHIP_TURKS:
-               num_ps_gprs = 93;
-               num_vs_gprs = 46;
-               num_temp_gprs = 4;
-               num_gs_gprs = 31;
-               num_es_gprs = 31;
-               num_hs_gprs = 23;
-               num_ls_gprs = 23;
-               num_ps_threads = 128;
-               num_vs_threads = 20;
-               num_gs_threads = 20;
-               num_es_threads = 20;
-               num_hs_threads = 20;
-               num_ls_threads = 20;
-               num_ps_stack_entries = 42;
-               num_vs_stack_entries = 42;
-               num_gs_stack_entries = 42;
-               num_es_stack_entries = 42;
-               num_hs_stack_entries = 42;
-               num_ls_stack_entries = 42;
-               break;
-       case CHIP_CAICOS:
-               num_ps_gprs = 93;
-               num_vs_gprs = 46;
-               num_temp_gprs = 4;
-               num_gs_gprs = 31;
-               num_es_gprs = 31;
-               num_hs_gprs = 23;
-               num_ls_gprs = 23;
-               num_ps_threads = 128;
-               num_vs_threads = 10;
-               num_gs_threads = 10;
-               num_es_threads = 10;
-               num_hs_threads = 10;
-               num_ls_threads = 10;
-               num_ps_stack_entries = 42;
-               num_vs_stack_entries = 42;
-               num_gs_stack_entries = 42;
-               num_es_stack_entries = 42;
-               num_hs_stack_entries = 42;
-               num_ls_stack_entries = 42;
-               break;
-       }
-
-       if ((rdev->family == CHIP_CEDAR) ||
-           (rdev->family == CHIP_PALM) ||
-           (rdev->family == CHIP_CAICOS))
-               sq_config = 0;
-       else
-               sq_config = VC_ENABLE;
-
-       sq_config |= (EXPORT_SRC_C |
-                     CS_PRIO(0) |
-                     LS_PRIO(0) |
-                     HS_PRIO(0) |
-                     PS_PRIO(0) |
-                     VS_PRIO(1) |
-                     GS_PRIO(2) |
-                     ES_PRIO(3));
-
-       sq_gpr_resource_mgmt_1 = (NUM_PS_GPRS(num_ps_gprs) |
-                                 NUM_VS_GPRS(num_vs_gprs) |
-                                 NUM_CLAUSE_TEMP_GPRS(num_temp_gprs));
-       sq_gpr_resource_mgmt_2 = (NUM_GS_GPRS(num_gs_gprs) |
-                                 NUM_ES_GPRS(num_es_gprs));
-       sq_gpr_resource_mgmt_3 = (NUM_HS_GPRS(num_hs_gprs) |
-                                 NUM_LS_GPRS(num_ls_gprs));
-       sq_thread_resource_mgmt = (NUM_PS_THREADS(num_ps_threads) |
-                                  NUM_VS_THREADS(num_vs_threads) |
-                                  NUM_GS_THREADS(num_gs_threads) |
-                                  NUM_ES_THREADS(num_es_threads));
-       sq_thread_resource_mgmt_2 = (NUM_HS_THREADS(num_hs_threads) |
-                                    NUM_LS_THREADS(num_ls_threads));
-       sq_stack_resource_mgmt_1 = (NUM_PS_STACK_ENTRIES(num_ps_stack_entries) |
-                                   NUM_VS_STACK_ENTRIES(num_vs_stack_entries));
-       sq_stack_resource_mgmt_2 = (NUM_GS_STACK_ENTRIES(num_gs_stack_entries) |
-                                   NUM_ES_STACK_ENTRIES(num_es_stack_entries));
-       sq_stack_resource_mgmt_3 = (NUM_HS_STACK_ENTRIES(num_hs_stack_entries) |
-                                   NUM_LS_STACK_ENTRIES(num_ls_stack_entries));
-
        /* set clear context state */
        radeon_ring_write(rdev, PACKET3(PACKET3_CLEAR_STATE, 0));
        radeon_ring_write(rdev, 0);
 
-       /* disable dyn gprs */
-       radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
-       radeon_ring_write(rdev, (SQ_DYN_GPR_CNTL_PS_FLUSH_REQ - PACKET3_SET_CONFIG_REG_START) >> 2);
-       radeon_ring_write(rdev, 0);
+       if (rdev->family < CHIP_CAYMAN) {
+               switch (rdev->family) {
+               case CHIP_CEDAR:
+               default:
+                       num_ps_gprs = 93;
+                       num_vs_gprs = 46;
+                       num_temp_gprs = 4;
+                       num_gs_gprs = 31;
+                       num_es_gprs = 31;
+                       num_hs_gprs = 23;
+                       num_ls_gprs = 23;
+                       num_ps_threads = 96;
+                       num_vs_threads = 16;
+                       num_gs_threads = 16;
+                       num_es_threads = 16;
+                       num_hs_threads = 16;
+                       num_ls_threads = 16;
+                       num_ps_stack_entries = 42;
+                       num_vs_stack_entries = 42;
+                       num_gs_stack_entries = 42;
+                       num_es_stack_entries = 42;
+                       num_hs_stack_entries = 42;
+                       num_ls_stack_entries = 42;
+                       break;
+               case CHIP_REDWOOD:
+                       num_ps_gprs = 93;
+                       num_vs_gprs = 46;
+                       num_temp_gprs = 4;
+                       num_gs_gprs = 31;
+                       num_es_gprs = 31;
+                       num_hs_gprs = 23;
+                       num_ls_gprs = 23;
+                       num_ps_threads = 128;
+                       num_vs_threads = 20;
+                       num_gs_threads = 20;
+                       num_es_threads = 20;
+                       num_hs_threads = 20;
+                       num_ls_threads = 20;
+                       num_ps_stack_entries = 42;
+                       num_vs_stack_entries = 42;
+                       num_gs_stack_entries = 42;
+                       num_es_stack_entries = 42;
+                       num_hs_stack_entries = 42;
+                       num_ls_stack_entries = 42;
+                       break;
+               case CHIP_JUNIPER:
+                       num_ps_gprs = 93;
+                       num_vs_gprs = 46;
+                       num_temp_gprs = 4;
+                       num_gs_gprs = 31;
+                       num_es_gprs = 31;
+                       num_hs_gprs = 23;
+                       num_ls_gprs = 23;
+                       num_ps_threads = 128;
+                       num_vs_threads = 20;
+                       num_gs_threads = 20;
+                       num_es_threads = 20;
+                       num_hs_threads = 20;
+                       num_ls_threads = 20;
+                       num_ps_stack_entries = 85;
+                       num_vs_stack_entries = 85;
+                       num_gs_stack_entries = 85;
+                       num_es_stack_entries = 85;
+                       num_hs_stack_entries = 85;
+                       num_ls_stack_entries = 85;
+                       break;
+               case CHIP_CYPRESS:
+               case CHIP_HEMLOCK:
+                       num_ps_gprs = 93;
+                       num_vs_gprs = 46;
+                       num_temp_gprs = 4;
+                       num_gs_gprs = 31;
+                       num_es_gprs = 31;
+                       num_hs_gprs = 23;
+                       num_ls_gprs = 23;
+                       num_ps_threads = 128;
+                       num_vs_threads = 20;
+                       num_gs_threads = 20;
+                       num_es_threads = 20;
+                       num_hs_threads = 20;
+                       num_ls_threads = 20;
+                       num_ps_stack_entries = 85;
+                       num_vs_stack_entries = 85;
+                       num_gs_stack_entries = 85;
+                       num_es_stack_entries = 85;
+                       num_hs_stack_entries = 85;
+                       num_ls_stack_entries = 85;
+                       break;
+               case CHIP_PALM:
+                       num_ps_gprs = 93;
+                       num_vs_gprs = 46;
+                       num_temp_gprs = 4;
+                       num_gs_gprs = 31;
+                       num_es_gprs = 31;
+                       num_hs_gprs = 23;
+                       num_ls_gprs = 23;
+                       num_ps_threads = 96;
+                       num_vs_threads = 16;
+                       num_gs_threads = 16;
+                       num_es_threads = 16;
+                       num_hs_threads = 16;
+                       num_ls_threads = 16;
+                       num_ps_stack_entries = 42;
+                       num_vs_stack_entries = 42;
+                       num_gs_stack_entries = 42;
+                       num_es_stack_entries = 42;
+                       num_hs_stack_entries = 42;
+                       num_ls_stack_entries = 42;
+                       break;
+               case CHIP_SUMO:
+                       num_ps_gprs = 93;
+                       num_vs_gprs = 46;
+                       num_temp_gprs = 4;
+                       num_gs_gprs = 31;
+                       num_es_gprs = 31;
+                       num_hs_gprs = 23;
+                       num_ls_gprs = 23;
+                       num_ps_threads = 96;
+                       num_vs_threads = 25;
+                       num_gs_threads = 25;
+                       num_es_threads = 25;
+                       num_hs_threads = 25;
+                       num_ls_threads = 25;
+                       num_ps_stack_entries = 42;
+                       num_vs_stack_entries = 42;
+                       num_gs_stack_entries = 42;
+                       num_es_stack_entries = 42;
+                       num_hs_stack_entries = 42;
+                       num_ls_stack_entries = 42;
+                       break;
+               case CHIP_SUMO2:
+                       num_ps_gprs = 93;
+                       num_vs_gprs = 46;
+                       num_temp_gprs = 4;
+                       num_gs_gprs = 31;
+                       num_es_gprs = 31;
+                       num_hs_gprs = 23;
+                       num_ls_gprs = 23;
+                       num_ps_threads = 96;
+                       num_vs_threads = 25;
+                       num_gs_threads = 25;
+                       num_es_threads = 25;
+                       num_hs_threads = 25;
+                       num_ls_threads = 25;
+                       num_ps_stack_entries = 85;
+                       num_vs_stack_entries = 85;
+                       num_gs_stack_entries = 85;
+                       num_es_stack_entries = 85;
+                       num_hs_stack_entries = 85;
+                       num_ls_stack_entries = 85;
+                       break;
+               case CHIP_BARTS:
+                       num_ps_gprs = 93;
+                       num_vs_gprs = 46;
+                       num_temp_gprs = 4;
+                       num_gs_gprs = 31;
+                       num_es_gprs = 31;
+                       num_hs_gprs = 23;
+                       num_ls_gprs = 23;
+                       num_ps_threads = 128;
+                       num_vs_threads = 20;
+                       num_gs_threads = 20;
+                       num_es_threads = 20;
+                       num_hs_threads = 20;
+                       num_ls_threads = 20;
+                       num_ps_stack_entries = 85;
+                       num_vs_stack_entries = 85;
+                       num_gs_stack_entries = 85;
+                       num_es_stack_entries = 85;
+                       num_hs_stack_entries = 85;
+                       num_ls_stack_entries = 85;
+                       break;
+               case CHIP_TURKS:
+                       num_ps_gprs = 93;
+                       num_vs_gprs = 46;
+                       num_temp_gprs = 4;
+                       num_gs_gprs = 31;
+                       num_es_gprs = 31;
+                       num_hs_gprs = 23;
+                       num_ls_gprs = 23;
+                       num_ps_threads = 128;
+                       num_vs_threads = 20;
+                       num_gs_threads = 20;
+                       num_es_threads = 20;
+                       num_hs_threads = 20;
+                       num_ls_threads = 20;
+                       num_ps_stack_entries = 42;
+                       num_vs_stack_entries = 42;
+                       num_gs_stack_entries = 42;
+                       num_es_stack_entries = 42;
+                       num_hs_stack_entries = 42;
+                       num_ls_stack_entries = 42;
+                       break;
+               case CHIP_CAICOS:
+                       num_ps_gprs = 93;
+                       num_vs_gprs = 46;
+                       num_temp_gprs = 4;
+                       num_gs_gprs = 31;
+                       num_es_gprs = 31;
+                       num_hs_gprs = 23;
+                       num_ls_gprs = 23;
+                       num_ps_threads = 128;
+                       num_vs_threads = 10;
+                       num_gs_threads = 10;
+                       num_es_threads = 10;
+                       num_hs_threads = 10;
+                       num_ls_threads = 10;
+                       num_ps_stack_entries = 42;
+                       num_vs_stack_entries = 42;
+                       num_gs_stack_entries = 42;
+                       num_es_stack_entries = 42;
+                       num_hs_stack_entries = 42;
+                       num_ls_stack_entries = 42;
+                       break;
+               }
 
-       /* SQ config */
-       radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 11));
-       radeon_ring_write(rdev, (SQ_CONFIG - PACKET3_SET_CONFIG_REG_START) >> 2);
-       radeon_ring_write(rdev, sq_config);
-       radeon_ring_write(rdev, sq_gpr_resource_mgmt_1);
-       radeon_ring_write(rdev, sq_gpr_resource_mgmt_2);
-       radeon_ring_write(rdev, sq_gpr_resource_mgmt_3);
-       radeon_ring_write(rdev, 0);
-       radeon_ring_write(rdev, 0);
-       radeon_ring_write(rdev, sq_thread_resource_mgmt);
-       radeon_ring_write(rdev, sq_thread_resource_mgmt_2);
-       radeon_ring_write(rdev, sq_stack_resource_mgmt_1);
-       radeon_ring_write(rdev, sq_stack_resource_mgmt_2);
-       radeon_ring_write(rdev, sq_stack_resource_mgmt_3);
+               if ((rdev->family == CHIP_CEDAR) ||
+                   (rdev->family == CHIP_PALM) ||
+                   (rdev->family == CHIP_SUMO) ||
+                   (rdev->family == CHIP_SUMO2) ||
+                   (rdev->family == CHIP_CAICOS))
+                       sq_config = 0;
+               else
+                       sq_config = VC_ENABLE;
+
+               sq_config |= (EXPORT_SRC_C |
+                             CS_PRIO(0) |
+                             LS_PRIO(0) |
+                             HS_PRIO(0) |
+                             PS_PRIO(0) |
+                             VS_PRIO(1) |
+                             GS_PRIO(2) |
+                             ES_PRIO(3));
+
+               sq_gpr_resource_mgmt_1 = (NUM_PS_GPRS(num_ps_gprs) |
+                                         NUM_VS_GPRS(num_vs_gprs) |
+                                         NUM_CLAUSE_TEMP_GPRS(num_temp_gprs));
+               sq_gpr_resource_mgmt_2 = (NUM_GS_GPRS(num_gs_gprs) |
+                                         NUM_ES_GPRS(num_es_gprs));
+               sq_gpr_resource_mgmt_3 = (NUM_HS_GPRS(num_hs_gprs) |
+                                         NUM_LS_GPRS(num_ls_gprs));
+               sq_thread_resource_mgmt = (NUM_PS_THREADS(num_ps_threads) |
+                                          NUM_VS_THREADS(num_vs_threads) |
+                                          NUM_GS_THREADS(num_gs_threads) |
+                                          NUM_ES_THREADS(num_es_threads));
+               sq_thread_resource_mgmt_2 = (NUM_HS_THREADS(num_hs_threads) |
+                                            NUM_LS_THREADS(num_ls_threads));
+               sq_stack_resource_mgmt_1 = (NUM_PS_STACK_ENTRIES(num_ps_stack_entries) |
+                                           NUM_VS_STACK_ENTRIES(num_vs_stack_entries));
+               sq_stack_resource_mgmt_2 = (NUM_GS_STACK_ENTRIES(num_gs_stack_entries) |
+                                           NUM_ES_STACK_ENTRIES(num_es_stack_entries));
+               sq_stack_resource_mgmt_3 = (NUM_HS_STACK_ENTRIES(num_hs_stack_entries) |
+                                           NUM_LS_STACK_ENTRIES(num_ls_stack_entries));
+
+               /* disable dyn gprs */
+               radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+               radeon_ring_write(rdev, (SQ_DYN_GPR_CNTL_PS_FLUSH_REQ - PACKET3_SET_CONFIG_REG_START) >> 2);
+               radeon_ring_write(rdev, 0);
+
+               /* SQ config */
+               radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 11));
+               radeon_ring_write(rdev, (SQ_CONFIG - PACKET3_SET_CONFIG_REG_START) >> 2);
+               radeon_ring_write(rdev, sq_config);
+               radeon_ring_write(rdev, sq_gpr_resource_mgmt_1);
+               radeon_ring_write(rdev, sq_gpr_resource_mgmt_2);
+               radeon_ring_write(rdev, sq_gpr_resource_mgmt_3);
+               radeon_ring_write(rdev, 0);
+               radeon_ring_write(rdev, 0);
+               radeon_ring_write(rdev, sq_thread_resource_mgmt);
+               radeon_ring_write(rdev, sq_thread_resource_mgmt_2);
+               radeon_ring_write(rdev, sq_stack_resource_mgmt_1);
+               radeon_ring_write(rdev, sq_stack_resource_mgmt_2);
+               radeon_ring_write(rdev, sq_stack_resource_mgmt_3);
+       }
 
        /* CONTEXT_CONTROL */
        radeon_ring_write(rdev, 0xc0012800);
@@ -560,7 +619,10 @@ int evergreen_blit_init(struct radeon_device *rdev)
        mutex_init(&rdev->r600_blit.mutex);
        rdev->r600_blit.state_offset = 0;
 
-       rdev->r600_blit.state_len = evergreen_default_size;
+       if (rdev->family < CHIP_CAYMAN)
+               rdev->r600_blit.state_len = evergreen_default_size;
+       else
+               rdev->r600_blit.state_len = cayman_default_size;
 
        dwords = rdev->r600_blit.state_len;
        while (dwords & 0xf) {
@@ -572,11 +634,17 @@ int evergreen_blit_init(struct radeon_device *rdev)
        obj_size = ALIGN(obj_size, 256);
 
        rdev->r600_blit.vs_offset = obj_size;
-       obj_size += evergreen_vs_size * 4;
+       if (rdev->family < CHIP_CAYMAN)
+               obj_size += evergreen_vs_size * 4;
+       else
+               obj_size += cayman_vs_size * 4;
        obj_size = ALIGN(obj_size, 256);
 
        rdev->r600_blit.ps_offset = obj_size;
-       obj_size += evergreen_ps_size * 4;
+       if (rdev->family < CHIP_CAYMAN)
+               obj_size += evergreen_ps_size * 4;
+       else
+               obj_size += cayman_ps_size * 4;
        obj_size = ALIGN(obj_size, 256);
 
        r = radeon_bo_create(rdev, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
@@ -599,16 +667,29 @@ int evergreen_blit_init(struct radeon_device *rdev)
                return r;
        }
 
-       memcpy_toio(ptr + rdev->r600_blit.state_offset,
-                   evergreen_default_state, rdev->r600_blit.state_len * 4);
-
-       if (num_packet2s)
-               memcpy_toio(ptr + rdev->r600_blit.state_offset + (rdev->r600_blit.state_len * 4),
-                           packet2s, num_packet2s * 4);
-       for (i = 0; i < evergreen_vs_size; i++)
-               *(u32 *)((unsigned long)ptr + rdev->r600_blit.vs_offset + i * 4) = cpu_to_le32(evergreen_vs[i]);
-       for (i = 0; i < evergreen_ps_size; i++)
-               *(u32 *)((unsigned long)ptr + rdev->r600_blit.ps_offset + i * 4) = cpu_to_le32(evergreen_ps[i]);
+       if (rdev->family < CHIP_CAYMAN) {
+               memcpy_toio(ptr + rdev->r600_blit.state_offset,
+                           evergreen_default_state, rdev->r600_blit.state_len * 4);
+
+               if (num_packet2s)
+                       memcpy_toio(ptr + rdev->r600_blit.state_offset + (rdev->r600_blit.state_len * 4),
+                                   packet2s, num_packet2s * 4);
+               for (i = 0; i < evergreen_vs_size; i++)
+                       *(u32 *)((unsigned long)ptr + rdev->r600_blit.vs_offset + i * 4) = cpu_to_le32(evergreen_vs[i]);
+               for (i = 0; i < evergreen_ps_size; i++)
+                       *(u32 *)((unsigned long)ptr + rdev->r600_blit.ps_offset + i * 4) = cpu_to_le32(evergreen_ps[i]);
+       } else {
+               memcpy_toio(ptr + rdev->r600_blit.state_offset,
+                           cayman_default_state, rdev->r600_blit.state_len * 4);
+
+               if (num_packet2s)
+                       memcpy_toio(ptr + rdev->r600_blit.state_offset + (rdev->r600_blit.state_len * 4),
+                                   packet2s, num_packet2s * 4);
+               for (i = 0; i < cayman_vs_size; i++)
+                       *(u32 *)((unsigned long)ptr + rdev->r600_blit.vs_offset + i * 4) = cpu_to_le32(cayman_vs[i]);
+               for (i = 0; i < cayman_ps_size; i++)
+                       *(u32 *)((unsigned long)ptr + rdev->r600_blit.ps_offset + i * 4) = cpu_to_le32(cayman_ps[i]);
+       }
        radeon_bo_kunmap(rdev->r600_blit.shader_obj);
        radeon_bo_unreserve(rdev->r600_blit.shader_obj);
 
index fc40e0cc34516bb96af19f1a7615b6889a7425e3..1636e34498252c3550e17a6515aa6097974bbf7f 100644 (file)
@@ -64,6 +64,8 @@
 #define GB_BACKEND_MAP                                 0x98FC
 #define DMIF_ADDR_CONFIG                               0xBD4
 #define HDP_ADDR_CONFIG                                0x2F48
+#define HDP_MISC_CNTL                                          0x2F4C
+#define                HDP_FLUSH_INVALIDATE_CACHE              (1 << 0)
 
 #define        CC_SYS_RB_BACKEND_DISABLE                       0x3F88
 #define        GC_USER_RB_BACKEND_DISABLE                      0x9B7C
 #define                SE_DB_BUSY                                      (1 << 30)
 #define                SE_CB_BUSY                                      (1 << 31)
 /* evergreen */
+#define        CG_THERMAL_CTRL                                 0x72c
+#define                TOFFSET_MASK                            0x00003FE0
+#define                TOFFSET_SHIFT                           5
 #define        CG_MULT_THERMAL_STATUS                          0x740
 #define                ASIC_T(x)                               ((x) << 16)
-#define                ASIC_T_MASK                             0x7FF0000
+#define                ASIC_T_MASK                             0x07FF0000
 #define                ASIC_T_SHIFT                            16
+#define        CG_TS0_STATUS                                   0x760
+#define                TS0_ADC_DOUT_MASK                       0x000003FF
+#define                TS0_ADC_DOUT_SHIFT                      0
 /* APU */
 #define        CG_THERMAL_STATUS                               0x678
 
index 3d8a7634bbe99ade0344aeb2061bc5f3ac183757..16caafeadf5e5603208a3055b2344355106d5a05 100644 (file)
@@ -417,7 +417,7 @@ static u32 cayman_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
                num_shader_engines = 1;
        if (num_shader_engines > rdev->config.cayman.max_shader_engines)
                num_shader_engines = rdev->config.cayman.max_shader_engines;
-       if (num_backends_per_asic > num_shader_engines)
+       if (num_backends_per_asic < num_shader_engines)
                num_backends_per_asic = num_shader_engines;
        if (num_backends_per_asic > (rdev->config.cayman.max_backends_per_se * num_shader_engines))
                num_backends_per_asic = rdev->config.cayman.max_backends_per_se * num_shader_engines;
@@ -829,7 +829,7 @@ static void cayman_gpu_init(struct radeon_device *rdev)
        rdev->config.cayman.tile_config |=
                ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
        rdev->config.cayman.tile_config |=
-               (gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT;
+               ((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8;
        rdev->config.cayman.tile_config |=
                ((gb_addr_config & ROW_SIZE_MASK) >> ROW_SIZE_SHIFT) << 12;
 
@@ -931,6 +931,10 @@ static void cayman_gpu_init(struct radeon_device *rdev)
        WREG32(CB_PERF_CTR3_SEL_0, 0);
        WREG32(CB_PERF_CTR3_SEL_1, 0);
 
+       tmp = RREG32(HDP_MISC_CNTL);
+       tmp |= HDP_FLUSH_INVALIDATE_CACHE;
+       WREG32(HDP_MISC_CNTL, tmp);
+
        hdp_host_path_cntl = RREG32(HDP_HOST_PATH_CNTL);
        WREG32(HDP_HOST_PATH_CNTL, hdp_host_path_cntl);
 
@@ -1383,14 +1387,12 @@ static int cayman_startup(struct radeon_device *rdev)
                return r;
        cayman_gpu_init(rdev);
 
-#if 0
-       r = cayman_blit_init(rdev);
+       r = evergreen_blit_init(rdev);
        if (r) {
-               cayman_blit_fini(rdev);
+               evergreen_blit_fini(rdev);
                rdev->asic->copy = NULL;
                dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
        }
-#endif
 
        /* allocate wb buffer */
        r = radeon_wb_init(rdev);
@@ -1448,7 +1450,7 @@ int cayman_resume(struct radeon_device *rdev)
 
 int cayman_suspend(struct radeon_device *rdev)
 {
-       /* int r; */
+       int r;
 
        /* FIXME: we should wait for ring to be empty */
        cayman_cp_enable(rdev, false);
@@ -1457,14 +1459,13 @@ int cayman_suspend(struct radeon_device *rdev)
        radeon_wb_disable(rdev);
        cayman_pcie_gart_disable(rdev);
 
-#if 0
        /* unpin shaders bo */
        r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
        if (likely(r == 0)) {
                radeon_bo_unpin(rdev->r600_blit.shader_obj);
                radeon_bo_unreserve(rdev->r600_blit.shader_obj);
        }
-#endif
+
        return 0;
 }
 
@@ -1576,7 +1577,7 @@ int cayman_init(struct radeon_device *rdev)
 
 void cayman_fini(struct radeon_device *rdev)
 {
-       /* cayman_blit_fini(rdev); */
+       evergreen_blit_fini(rdev);
        cayman_cp_fini(rdev);
        r600_irq_fini(rdev);
        radeon_wb_fini(rdev);
index 0f9a08b53fbd4b9b4e4e90e8c63aad02a554f229..9736746da2d6d79b3a9b4c3e6e2e286fc524c901 100644 (file)
 #define        HDP_NONSURFACE_INFO                             0x2C08
 #define        HDP_NONSURFACE_SIZE                             0x2C0C
 #define HDP_ADDR_CONFIG                                0x2F48
+#define HDP_MISC_CNTL                                  0x2F4C
+#define        HDP_FLUSH_INVALIDATE_CACHE                      (1 << 0)
 
 #define        CC_SYS_RB_BACKEND_DISABLE                       0x3F88
 #define        GC_USER_SYS_RB_BACKEND_DISABLE                  0x3F8C
 #define                MULTI_GPU_TILE_SIZE_MASK                0x03000000
 #define                MULTI_GPU_TILE_SIZE_SHIFT               24
 #define                ROW_SIZE(x)                             ((x) << 28)
-#define                ROW_SIZE_MASK                           0x30000007
+#define                ROW_SIZE_MASK                           0x30000000
 #define                ROW_SIZE_SHIFT                          28
 #define                NUM_LOWER_PIPES(x)                      ((x) << 30)
 #define                NUM_LOWER_PIPES_MASK                    0x40000000
index 2fef9de7f363b2fb47478e8720ea1a7ca7fb7331..686f9dc5d4bd94f8f8dec4a23de185aee832542a 100644 (file)
@@ -63,7 +63,7 @@ struct r100_cs_track {
        unsigned                        num_arrays;
        unsigned                        max_indx;
        unsigned                        color_channel_mask;
-       struct r100_cs_track_array      arrays[11];
+       struct r100_cs_track_array      arrays[16];
        struct r100_cs_track_cb         cb[R300_MAX_CB];
        struct r100_cs_track_cb         zb;
        struct r100_cs_track_cb         aa;
@@ -146,6 +146,12 @@ static inline int r100_packet3_load_vbpntr(struct radeon_cs_parser *p,
        ib = p->ib->ptr;
        track = (struct r100_cs_track *)p->track;
        c = radeon_get_ib_value(p, idx++) & 0x1F;
+       if (c > 16) {
+           DRM_ERROR("Only 16 vertex buffers are allowed %d\n",
+                     pkt->opcode);
+           r100_cs_dump_packet(p, pkt);
+           return -EINVAL;
+       }
        track->num_arrays = c;
        for (i = 0; i < (c - 1); i+=2, idx+=3) {
                r = r100_cs_packet_next_reloc(p, &reloc);
index 6f27593901c7110752b9b2f39267f04546f544eb..f79d2ccb675553c73204c14bd46183f05fd4567b 100644 (file)
@@ -87,6 +87,10 @@ MODULE_FIRMWARE("radeon/CYPRESS_rlc.bin");
 MODULE_FIRMWARE("radeon/PALM_pfp.bin");
 MODULE_FIRMWARE("radeon/PALM_me.bin");
 MODULE_FIRMWARE("radeon/SUMO_rlc.bin");
+MODULE_FIRMWARE("radeon/SUMO_pfp.bin");
+MODULE_FIRMWARE("radeon/SUMO_me.bin");
+MODULE_FIRMWARE("radeon/SUMO2_pfp.bin");
+MODULE_FIRMWARE("radeon/SUMO2_me.bin");
 
 int r600_debugfs_mc_info_init(struct radeon_device *rdev);
 
@@ -586,6 +590,9 @@ void r600_pm_misc(struct radeon_device *rdev)
        struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage;
 
        if ((voltage->type == VOLTAGE_SW) && voltage->voltage) {
+               /* 0xff01 is a flag rather then an actual voltage */
+               if (voltage->voltage == 0xff01)
+                       return;
                if (voltage->voltage != rdev->pm.current_vddc) {
                        radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC);
                        rdev->pm.current_vddc = voltage->voltage;
@@ -2024,6 +2031,14 @@ int r600_init_microcode(struct radeon_device *rdev)
                chip_name = "PALM";
                rlc_chip_name = "SUMO";
                break;
+       case CHIP_SUMO:
+               chip_name = "SUMO";
+               rlc_chip_name = "SUMO";
+               break;
+       case CHIP_SUMO2:
+               chip_name = "SUMO2";
+               rlc_chip_name = "SUMO";
+               break;
        default: BUG();
        }
 
@@ -3282,27 +3297,26 @@ static inline u32 r600_get_ih_wptr(struct radeon_device *rdev)
 
 int r600_irq_process(struct radeon_device *rdev)
 {
-       u32 wptr = r600_get_ih_wptr(rdev);
-       u32 rptr = rdev->ih.rptr;
+       u32 wptr;
+       u32 rptr;
        u32 src_id, src_data;
        u32 ring_index;
        unsigned long flags;
        bool queue_hotplug = false;
 
-       DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr);
-       if (!rdev->ih.enabled)
+       if (!rdev->ih.enabled || rdev->shutdown)
                return IRQ_NONE;
 
+       wptr = r600_get_ih_wptr(rdev);
+       rptr = rdev->ih.rptr;
+       DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr);
+
        spin_lock_irqsave(&rdev->ih.lock, flags);
 
        if (rptr == wptr) {
                spin_unlock_irqrestore(&rdev->ih.lock, flags);
                return IRQ_NONE;
        }
-       if (rdev->shutdown) {
-               spin_unlock_irqrestore(&rdev->ih.lock, flags);
-               return IRQ_NONE;
-       }
 
 restart_ih:
        /* display interrupts */
@@ -3432,7 +3446,7 @@ restart_ih:
                        radeon_fence_process(rdev);
                        break;
                case 233: /* GUI IDLE */
-                       DRM_DEBUG("IH: CP EOP\n");
+                       DRM_DEBUG("IH: GUI idle\n");
                        rdev->pm.gui_idle = true;
                        wake_up(&rdev->irq.idle_queue);
                        break;
index fd18be9871ab5b897cc93c4a309a9081653f9489..909bda8dd550c54a9965e787d6876ff3fc325d33 100644 (file)
@@ -71,20 +71,21 @@ struct r600_cs_track {
        u64                     db_bo_mc;
 };
 
-#define FMT_8_BIT(fmt, vc) [fmt] = { 1, 1, 1, vc }
-#define FMT_16_BIT(fmt, vc) [fmt] = { 1, 1, 2, vc }
-#define FMT_24_BIT(fmt) [fmt] = { 1, 1, 3, 0 }
-#define FMT_32_BIT(fmt, vc) [fmt] = { 1, 1, 4, vc }
-#define FMT_48_BIT(fmt) [fmt] = { 1, 1, 6, 0 }
-#define FMT_64_BIT(fmt, vc) [fmt] = { 1, 1, 8, vc }
-#define FMT_96_BIT(fmt) [fmt] = { 1, 1, 12, 0 }
-#define FMT_128_BIT(fmt, vc) [fmt] = { 1, 1, 16, vc }
+#define FMT_8_BIT(fmt, vc)   [fmt] = { 1, 1, 1, vc, CHIP_R600 }
+#define FMT_16_BIT(fmt, vc)  [fmt] = { 1, 1, 2, vc, CHIP_R600 }
+#define FMT_24_BIT(fmt)      [fmt] = { 1, 1, 3,  0, CHIP_R600 }
+#define FMT_32_BIT(fmt, vc)  [fmt] = { 1, 1, 4, vc, CHIP_R600 }
+#define FMT_48_BIT(fmt)      [fmt] = { 1, 1, 6,  0, CHIP_R600 }
+#define FMT_64_BIT(fmt, vc)  [fmt] = { 1, 1, 8, vc, CHIP_R600 }
+#define FMT_96_BIT(fmt)      [fmt] = { 1, 1, 12, 0, CHIP_R600 }
+#define FMT_128_BIT(fmt, vc) [fmt] = { 1, 1, 16,vc, CHIP_R600 }
 
 struct gpu_formats {
        unsigned blockwidth;
        unsigned blockheight;
        unsigned blocksize;
        unsigned valid_color;
+       enum radeon_family min_family;
 };
 
 static const struct gpu_formats color_formats_table[] = {
@@ -154,7 +155,11 @@ static const struct gpu_formats color_formats_table[] = {
        [V_038004_FMT_BC3] = { 4, 4, 16, 0 },
        [V_038004_FMT_BC4] = { 4, 4, 8, 0 },
        [V_038004_FMT_BC5] = { 4, 4, 16, 0},
+       [V_038004_FMT_BC6] = { 4, 4, 16, 0, CHIP_CEDAR}, /* Evergreen-only */
+       [V_038004_FMT_BC7] = { 4, 4, 16, 0, CHIP_CEDAR}, /* Evergreen-only */
 
+       /* The other Evergreen formats */
+       [V_038004_FMT_32_AS_32_32_32_32] = { 1, 1, 4, 0, CHIP_CEDAR},
 };
 
 static inline bool fmt_is_valid_color(u32 format)
@@ -168,11 +173,14 @@ static inline bool fmt_is_valid_color(u32 format)
        return false;
 }
 
-static inline bool fmt_is_valid_texture(u32 format)
+static inline bool fmt_is_valid_texture(u32 format, enum radeon_family family)
 {
        if (format >= ARRAY_SIZE(color_formats_table))
                return false;
        
+       if (family < color_formats_table[format].min_family)
+               return false;
+
        if (color_formats_table[format].blockwidth > 0)
                return true;
 
@@ -1325,7 +1333,7 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 i
                return -EINVAL;
        }
        format = G_038004_DATA_FORMAT(word1);
-       if (!fmt_is_valid_texture(format)) {
+       if (!fmt_is_valid_texture(format, p->family)) {
                dev_warn(p->dev, "%s:%d texture invalid format %d\n",
                         __func__, __LINE__, format);
                return -EINVAL;
index b2b944bcd05ae53d1ff19aa16edeee941aba3187..f140a0d5cb543c0281c8e8a85f62df873fa51809 100644 (file)
 #define     V_038004_FMT_BC3                           0x00000033
 #define     V_038004_FMT_BC4                           0x00000034
 #define     V_038004_FMT_BC5                           0x00000035
+#define     V_038004_FMT_BC6                           0x00000036
+#define     V_038004_FMT_BC7                           0x00000037
+#define     V_038004_FMT_32_AS_32_32_32_32             0x00000038
 #define R_038010_SQ_TEX_RESOURCE_WORD4_0             0x038010
 #define   S_038010_FORMAT_COMP_X(x)                    (((x) & 0x3) << 0)
 #define   G_038010_FORMAT_COMP_X(x)                    (((x) >> 0) & 0x3)
index ba643b5760542e0e6ad3298464be1e7505995739..ef0e0e016914d53aadcddbd897913d07da495bd4 100644 (file)
@@ -165,6 +165,7 @@ struct radeon_clock {
        uint32_t default_sclk;
        uint32_t default_dispclk;
        uint32_t dp_extclk;
+       uint32_t max_pixel_clock;
 };
 
 /*
@@ -178,6 +179,7 @@ void radeon_pm_resume(struct radeon_device *rdev);
 void radeon_combios_get_power_modes(struct radeon_device *rdev);
 void radeon_atombios_get_power_modes(struct radeon_device *rdev);
 void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type);
+int radeon_atom_get_max_vddc(struct radeon_device *rdev, u16 *voltage);
 void rs690_pm_info(struct radeon_device *rdev);
 extern int rv6xx_get_temp(struct radeon_device *rdev);
 extern int rv770_get_temp(struct radeon_device *rdev);
index ca576191d0588bb23356b2c40d25afa668736cb8..b2449629537d3b5922e86e325ac85bb214cacea2 100644 (file)
@@ -782,6 +782,7 @@ static struct radeon_asic evergreen_asic = {
        .hpd_fini = &evergreen_hpd_fini,
        .hpd_sense = &evergreen_hpd_sense,
        .hpd_set_polarity = &evergreen_hpd_set_polarity,
+       .ioctl_wait_idle = r600_ioctl_wait_idle,
        .gui_idle = &r600_gui_idle,
        .pm_misc = &evergreen_pm_misc,
        .pm_prepare = &evergreen_pm_prepare,
@@ -828,6 +829,7 @@ static struct radeon_asic sumo_asic = {
        .hpd_fini = &evergreen_hpd_fini,
        .hpd_sense = &evergreen_hpd_sense,
        .hpd_set_polarity = &evergreen_hpd_set_polarity,
+       .ioctl_wait_idle = r600_ioctl_wait_idle,
        .gui_idle = &r600_gui_idle,
        .pm_misc = &evergreen_pm_misc,
        .pm_prepare = &evergreen_pm_prepare,
@@ -874,6 +876,7 @@ static struct radeon_asic btc_asic = {
        .hpd_fini = &evergreen_hpd_fini,
        .hpd_sense = &evergreen_hpd_sense,
        .hpd_set_polarity = &evergreen_hpd_set_polarity,
+       .ioctl_wait_idle = r600_ioctl_wait_idle,
        .gui_idle = &r600_gui_idle,
        .pm_misc = &evergreen_pm_misc,
        .pm_prepare = &evergreen_pm_prepare,
@@ -903,9 +906,9 @@ static struct radeon_asic cayman_asic = {
        .get_vblank_counter = &evergreen_get_vblank_counter,
        .fence_ring_emit = &r600_fence_ring_emit,
        .cs_parse = &evergreen_cs_parse,
-       .copy_blit = NULL,
-       .copy_dma = NULL,
-       .copy = NULL,
+       .copy_blit = &evergreen_copy_blit,
+       .copy_dma = &evergreen_copy_blit,
+       .copy = &evergreen_copy_blit,
        .get_engine_clock = &radeon_atom_get_engine_clock,
        .set_engine_clock = &radeon_atom_set_engine_clock,
        .get_memory_clock = &radeon_atom_get_memory_clock,
@@ -920,6 +923,7 @@ static struct radeon_asic cayman_asic = {
        .hpd_fini = &evergreen_hpd_fini,
        .hpd_sense = &evergreen_hpd_sense,
        .hpd_set_polarity = &evergreen_hpd_set_polarity,
+       .ioctl_wait_idle = r600_ioctl_wait_idle,
        .gui_idle = &r600_gui_idle,
        .pm_misc = &evergreen_pm_misc,
        .pm_prepare = &evergreen_pm_prepare,
@@ -934,6 +938,13 @@ static struct radeon_asic cayman_asic = {
 int radeon_asic_init(struct radeon_device *rdev)
 {
        radeon_register_accessor_init(rdev);
+
+       /* set the number of crtcs */
+       if (rdev->flags & RADEON_SINGLE_CRTC)
+               rdev->num_crtc = 1;
+       else
+               rdev->num_crtc = 2;
+
        switch (rdev->family) {
        case CHIP_R100:
        case CHIP_RV100:
@@ -1013,18 +1024,32 @@ int radeon_asic_init(struct radeon_device *rdev)
        case CHIP_JUNIPER:
        case CHIP_CYPRESS:
        case CHIP_HEMLOCK:
+               /* set num crtcs */
+               if (rdev->family == CHIP_CEDAR)
+                       rdev->num_crtc = 4;
+               else
+                       rdev->num_crtc = 6;
                rdev->asic = &evergreen_asic;
                break;
        case CHIP_PALM:
+       case CHIP_SUMO:
+       case CHIP_SUMO2:
                rdev->asic = &sumo_asic;
                break;
        case CHIP_BARTS:
        case CHIP_TURKS:
        case CHIP_CAICOS:
+               /* set num crtcs */
+               if (rdev->family == CHIP_CAICOS)
+                       rdev->num_crtc = 4;
+               else
+                       rdev->num_crtc = 6;
                rdev->asic = &btc_asic;
                break;
        case CHIP_CAYMAN:
                rdev->asic = &cayman_asic;
+               /* set num crtcs */
+               rdev->num_crtc = 6;
                break;
        default:
                /* FIXME: not supported yet */
@@ -1036,18 +1061,6 @@ int radeon_asic_init(struct radeon_device *rdev)
                rdev->asic->set_memory_clock = NULL;
        }
 
-       /* set the number of crtcs */
-       if (rdev->flags & RADEON_SINGLE_CRTC)
-               rdev->num_crtc = 1;
-       else {
-               if (ASIC_IS_DCE41(rdev))
-                       rdev->num_crtc = 2;
-               else if (ASIC_IS_DCE4(rdev))
-                       rdev->num_crtc = 6;
-               else
-                       rdev->num_crtc = 2;
-       }
-
        return 0;
 }
 
index 90dfb2b8cf0318529b28b84b0bfd831764e5d59e..bf2b61584cdb5a70fc06fbc41dd2ca51733532fc 100644 (file)
@@ -1246,6 +1246,10 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
                }
                *dcpll = *p1pll;
 
+               rdev->clock.max_pixel_clock = le16_to_cpu(firmware_info->info.usMaxPixelClock);
+               if (rdev->clock.max_pixel_clock == 0)
+                       rdev->clock.max_pixel_clock = 40000;
+
                return true;
        }
 
@@ -2316,6 +2320,14 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev,
                        le16_to_cpu(clock_info->r600.usVDDC);
        }
 
+       /* patch up vddc if necessary */
+       if (rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage == 0xff01) {
+               u16 vddc;
+
+               if (radeon_atom_get_max_vddc(rdev, &vddc) == 0)
+                       rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = vddc;
+       }
+
        if (rdev->flags & RADEON_IS_IGP) {
                /* skip invalid modes */
                if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)
@@ -2603,6 +2615,10 @@ void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 v
        if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
                return;
 
+       /* 0xff01 is a flag rather then an actual voltage */
+       if (voltage_level == 0xff01)
+               return;
+
        switch (crev) {
        case 1:
                args.v1.ucVoltageType = voltage_type;
@@ -2622,7 +2638,35 @@ void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 v
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
+int radeon_atom_get_max_vddc(struct radeon_device *rdev,
+                            u16 *voltage)
+{
+       union set_voltage args;
+       int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
+       u8 frev, crev;
+
+       if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
+               return -EINVAL;
 
+       switch (crev) {
+       case 1:
+               return -EINVAL;
+       case 2:
+               args.v2.ucVoltageType = SET_VOLTAGE_GET_MAX_VOLTAGE;
+               args.v2.ucVoltageMode = 0;
+               args.v2.usVoltageLevel = 0;
+
+               atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+               *voltage = le16_to_cpu(args.v2.usVoltageLevel);
+               break;
+       default:
+               DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+               return -EINVAL;
+       }
+
+       return 0;
+}
 
 void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)
 {
index 5249af8931e60549e01362102f9c8ca941ba0d24..2d48e7a1474b4d915652cc8c6718dc4c8f4a8db4 100644 (file)
@@ -117,7 +117,7 @@ static bool __devinit radeon_read_clocks_OF(struct drm_device *dev)
        p1pll->reference_div = RREG32_PLL(RADEON_PPLL_REF_DIV) & 0x3ff;
        if (p1pll->reference_div < 2)
                p1pll->reference_div = 12;
-       p2pll->reference_div = p1pll->reference_div;    
+       p2pll->reference_div = p1pll->reference_div;
 
        /* These aren't in the device-tree */
        if (rdev->family >= CHIP_R420) {
@@ -139,6 +139,8 @@ static bool __devinit radeon_read_clocks_OF(struct drm_device *dev)
                p2pll->pll_out_min = 12500;
                p2pll->pll_out_max = 35000;
        }
+       /* not sure what the max should be in all cases */
+       rdev->clock.max_pixel_clock = 35000;
 
        spll->reference_freq = mpll->reference_freq = p1pll->reference_freq;
        spll->reference_div = mpll->reference_div =
@@ -151,7 +153,7 @@ static bool __devinit radeon_read_clocks_OF(struct drm_device *dev)
        else
                rdev->clock.default_sclk =
                        radeon_legacy_get_engine_clock(rdev);
-                       
+
        val = of_get_property(dp, "ATY,MCLK", NULL);
        if (val && *val)
                rdev->clock.default_mclk = (*val) / 10;
@@ -160,7 +162,7 @@ static bool __devinit radeon_read_clocks_OF(struct drm_device *dev)
                        radeon_legacy_get_memory_clock(rdev);
 
        DRM_INFO("Using device-tree clock info\n");
-       
+
        return true;
 }
 #else
index 8caf546c8e92f189d6576939081b7afa1a7a33c2..e4594676a07c2c4bdb0c1f3575e91e8e98c8265d 100644 (file)
@@ -505,12 +505,18 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
         * DDC_VGA           = RADEON_GPIO_VGA_DDC
         * DDC_LCD           = RADEON_GPIOPAD_MASK
         * DDC_GPIO          = RADEON_MDGPIO_MASK
-        * r1xx/r2xx
+        * r1xx
         * DDC_MONID         = RADEON_GPIO_MONID
         * DDC_CRT2          = RADEON_GPIO_CRT2_DDC
-        * r3xx
+        * r200
         * DDC_MONID         = RADEON_GPIO_MONID
         * DDC_CRT2          = RADEON_GPIO_DVI_DDC
+        * r300/r350
+        * DDC_MONID         = RADEON_GPIO_DVI_DDC
+        * DDC_CRT2          = RADEON_GPIO_DVI_DDC
+        * rv2xx/rv3xx
+        * DDC_MONID         = RADEON_GPIO_MONID
+        * DDC_CRT2          = RADEON_GPIO_MONID
         * rs3xx/rs4xx
         * DDC_MONID         = RADEON_GPIOPAD_MASK
         * DDC_CRT2          = RADEON_GPIO_MONID
@@ -537,17 +543,26 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
                    rdev->family == CHIP_RS400 ||
                    rdev->family == CHIP_RS480)
                        ddc_line = RADEON_GPIOPAD_MASK;
-               else
+               else if (rdev->family == CHIP_R300 ||
+                        rdev->family == CHIP_R350) {
+                       ddc_line = RADEON_GPIO_DVI_DDC;
+                       ddc = DDC_DVI;
+               } else
                        ddc_line = RADEON_GPIO_MONID;
                break;
        case DDC_CRT2:
-               if (rdev->family == CHIP_RS300 ||
-                   rdev->family == CHIP_RS400 ||
-                   rdev->family == CHIP_RS480)
-                       ddc_line = RADEON_GPIO_MONID;
-               else if (rdev->family >= CHIP_R300) {
+               if (rdev->family == CHIP_R200 ||
+                   rdev->family == CHIP_R300 ||
+                   rdev->family == CHIP_R350) {
                        ddc_line = RADEON_GPIO_DVI_DDC;
                        ddc = DDC_DVI;
+               } else if (rdev->family == CHIP_RS300 ||
+                          rdev->family == CHIP_RS400 ||
+                          rdev->family == CHIP_RS480)
+                       ddc_line = RADEON_GPIO_MONID;
+               else if (rdev->family >= CHIP_RV350) {
+                       ddc_line = RADEON_GPIO_MONID;
+                       ddc = DDC_MONID;
                } else
                        ddc_line = RADEON_GPIO_CRT2_DDC;
                break;
@@ -709,26 +724,42 @@ void radeon_combios_i2c_init(struct radeon_device *rdev)
        struct drm_device *dev = rdev->ddev;
        struct radeon_i2c_bus_rec i2c;
 
+       /* actual hw pads
+        * r1xx/rs2xx/rs3xx
+        * 0x60, 0x64, 0x68, 0x6c, gpiopads, mm
+        * r200
+        * 0x60, 0x64, 0x68, mm
+        * r300/r350
+        * 0x60, 0x64, mm
+        * rv2xx/rv3xx/rs4xx
+        * 0x60, 0x64, 0x68, gpiopads, mm
+        */
 
+       /* 0x60 */
        i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
        rdev->i2c_bus[0] = radeon_i2c_create(dev, &i2c, "DVI_DDC");
-
+       /* 0x64 */
        i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
        rdev->i2c_bus[1] = radeon_i2c_create(dev, &i2c, "VGA_DDC");
 
+       /* mm i2c */
        i2c.valid = true;
        i2c.hw_capable = true;
        i2c.mm_i2c = true;
        i2c.i2c_id = 0xa0;
        rdev->i2c_bus[2] = radeon_i2c_create(dev, &i2c, "MM_I2C");
 
-       if (rdev->family == CHIP_RS300 ||
-           rdev->family == CHIP_RS400 ||
-           rdev->family == CHIP_RS480) {
+       if (rdev->family == CHIP_R300 ||
+           rdev->family == CHIP_R350) {
+               /* only 2 sw i2c pads */
+       } else if (rdev->family == CHIP_RS300 ||
+                  rdev->family == CHIP_RS400 ||
+                  rdev->family == CHIP_RS480) {
                u16 offset;
                u8 id, blocks, clk, data;
                int i;
 
+               /* 0x68 */
                i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
                rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
 
@@ -740,6 +771,7 @@ void radeon_combios_i2c_init(struct radeon_device *rdev)
                                if (id == 136) {
                                        clk = RBIOS8(offset + 3 + (i * 5) + 3);
                                        data = RBIOS8(offset + 3 + (i * 5) + 4);
+                                       /* gpiopad */
                                        i2c = combios_setup_i2c_bus(rdev, DDC_MONID,
                                                                    (1 << clk), (1 << data));
                                        rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "GPIOPAD_MASK");
@@ -747,14 +779,15 @@ void radeon_combios_i2c_init(struct radeon_device *rdev)
                                }
                        }
                }
-
-       } else if (rdev->family >= CHIP_R300) {
+       } else if (rdev->family >= CHIP_R200) {
+               /* 0x68 */
                i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
                rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
        } else {
+               /* 0x68 */
                i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
                rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
-
+               /* 0x6c */
                i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
                rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "CRT2_DDC");
        }
@@ -833,6 +866,11 @@ bool radeon_combios_get_clock_info(struct drm_device *dev)
                rdev->clock.default_sclk = sclk;
                rdev->clock.default_mclk = mclk;
 
+               if (RBIOS32(pll_info + 0x16))
+                       rdev->clock.max_pixel_clock = RBIOS32(pll_info + 0x16);
+               else
+                       rdev->clock.max_pixel_clock = 35000; /* might need something asic specific */
+
                return true;
        }
        return false;
@@ -1515,10 +1553,12 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                           (rdev->pdev->subsystem_device == 0x4a48)) {
                        /* Mac X800 */
                        rdev->mode_info.connector_table = CT_MAC_X800;
-               } else if ((rdev->pdev->device == 0x4150) &&
+               } else if ((of_machine_is_compatible("PowerMac7,2") ||
+                           of_machine_is_compatible("PowerMac7,3")) &&
+                          (rdev->pdev->device == 0x4150) &&
                           (rdev->pdev->subsystem_vendor == 0x1002) &&
                           (rdev->pdev->subsystem_device == 0x4150)) {
-                       /* Mac G5 9600 */
+                       /* Mac G5 tower 9600 */
                        rdev->mode_info.connector_table = CT_MAC_G5_9600;
                } else
 #endif /* CONFIG_PPC_PMAC */
@@ -2504,6 +2544,12 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
        return true;
 }
 
+static const char *thermal_controller_names[] = {
+       "NONE",
+       "lm63",
+       "adm1032",
+};
+
 void radeon_combios_get_power_modes(struct radeon_device *rdev)
 {
        struct drm_device *dev = rdev->ddev;
@@ -2524,6 +2570,54 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev)
                return;
        }
 
+       /* check for a thermal chip */
+       offset = combios_get_table_offset(dev, COMBIOS_OVERDRIVE_INFO_TABLE);
+       if (offset) {
+               u8 thermal_controller = 0, gpio = 0, i2c_addr = 0, clk_bit = 0, data_bit = 0;
+               struct radeon_i2c_bus_rec i2c_bus;
+
+               rev = RBIOS8(offset);
+
+               if (rev == 0) {
+                       thermal_controller = RBIOS8(offset + 3);
+                       gpio = RBIOS8(offset + 4) & 0x3f;
+                       i2c_addr = RBIOS8(offset + 5);
+               } else if (rev == 1) {
+                       thermal_controller = RBIOS8(offset + 4);
+                       gpio = RBIOS8(offset + 5) & 0x3f;
+                       i2c_addr = RBIOS8(offset + 6);
+               } else if (rev == 2) {
+                       thermal_controller = RBIOS8(offset + 4);
+                       gpio = RBIOS8(offset + 5) & 0x3f;
+                       i2c_addr = RBIOS8(offset + 6);
+                       clk_bit = RBIOS8(offset + 0xa);
+                       data_bit = RBIOS8(offset + 0xb);
+               }
+               if ((thermal_controller > 0) && (thermal_controller < 3)) {
+                       DRM_INFO("Possible %s thermal controller at 0x%02x\n",
+                                thermal_controller_names[thermal_controller],
+                                i2c_addr >> 1);
+                       if (gpio == DDC_LCD) {
+                               /* MM i2c */
+                               i2c_bus.valid = true;
+                               i2c_bus.hw_capable = true;
+                               i2c_bus.mm_i2c = true;
+                               i2c_bus.i2c_id = 0xa0;
+                       } else if (gpio == DDC_GPIO)
+                               i2c_bus = combios_setup_i2c_bus(rdev, gpio, 1 << clk_bit, 1 << data_bit);
+                       else
+                               i2c_bus = combios_setup_i2c_bus(rdev, gpio, 0, 0);
+                       rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
+                       if (rdev->pm.i2c_bus) {
+                               struct i2c_board_info info = { };
+                               const char *name = thermal_controller_names[thermal_controller];
+                               info.addr = i2c_addr >> 1;
+                               strlcpy(info.type, name, sizeof(info.type));
+                               i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
+                       }
+               }
+       }
+
        if (rdev->flags & RADEON_IS_MOBILITY) {
                offset = combios_get_table_offset(dev, COMBIOS_POWERPLAY_INFO_TABLE);
                if (offset) {
index 5f45fa12bb8b88471f5a301e44a893c97a6f96b3..cbfca3a24fdf9caac828d4cca8ce8445963af4c4 100644 (file)
@@ -44,26 +44,29 @@ extern void
 radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,
                             struct drm_connector *drm_connector);
 
+bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector);
+
 void radeon_connector_hotplug(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
 
-       if (radeon_connector->hpd.hpd != RADEON_HPD_NONE)
-               radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
+       radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
 
-       if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
-           (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
-               if ((radeon_dp_getsinktype(radeon_connector) == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
-                   (radeon_dp_getsinktype(radeon_connector) == CONNECTOR_OBJECT_ID_eDP)) {
-                       if (radeon_dp_needs_link_train(radeon_connector)) {
-                               if (connector->encoder)
-                                       dp_link_train(connector->encoder, connector);
-                       }
-               }
-       }
+       /* powering up/down the eDP panel generates hpd events which
+        * can interfere with modesetting.
+        */
+       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+               return;
 
+       /* pre-r600 did not always have the hpd pins mapped accurately to connectors */
+       if (rdev->family >= CHIP_R600) {
+               if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
+                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
+               else
+                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+       }
 }
 
 static void radeon_property_change_mode(struct drm_encoder *encoder)
@@ -625,8 +628,14 @@ static int radeon_vga_get_modes(struct drm_connector *connector)
 static int radeon_vga_mode_valid(struct drm_connector *connector,
                                  struct drm_display_mode *mode)
 {
+       struct drm_device *dev = connector->dev;
+       struct radeon_device *rdev = dev->dev_private;
+
        /* XXX check mode bandwidth */
-       /* XXX verify against max DAC output frequency */
+
+       if ((mode->clock / 10) > rdev->clock.max_pixel_clock)
+               return MODE_CLOCK_HIGH;
+
        return MODE_OK;
 }
 
@@ -829,6 +838,13 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
                if (!radeon_connector->edid) {
                        DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
                                        drm_get_connector_name(connector));
+                       /* rs690 seems to have a problem with connectors not existing and always
+                        * return a block of 0's. If we see this just stop polling on this output */
+                       if ((rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) && radeon_connector->base.null_edid_counter) {
+                               ret = connector_status_disconnected;
+                               DRM_ERROR("%s: detected RS690 floating bus bug, stopping ddc detect\n", drm_get_connector_name(connector));
+                               radeon_connector->ddc_bus = NULL;
+                       }
                } else {
                        radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
 
@@ -1014,6 +1030,11 @@ static int radeon_dvi_mode_valid(struct drm_connector *connector,
                } else
                        return MODE_CLOCK_HIGH;
        }
+
+       /* check against the max pixel clock */
+       if ((mode->clock / 10) > rdev->clock.max_pixel_clock)
+               return MODE_CLOCK_HIGH;
+
        return MODE_OK;
 }
 
@@ -1051,36 +1072,153 @@ static int radeon_dp_get_modes(struct drm_connector *connector)
 {
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
        struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
+       struct drm_encoder *encoder = radeon_best_single_encoder(connector);
        int ret;
 
-       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+       if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
+           (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
+               struct drm_display_mode *mode;
+
                if (!radeon_dig_connector->edp_on)
                        atombios_set_edp_panel_power(connector,
                                                     ATOM_TRANSMITTER_ACTION_POWER_ON);
-       }
-       ret = radeon_ddc_get_modes(radeon_connector);
-       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+               ret = radeon_ddc_get_modes(radeon_connector);
                if (!radeon_dig_connector->edp_on)
                        atombios_set_edp_panel_power(connector,
                                                     ATOM_TRANSMITTER_ACTION_POWER_OFF);
+
+               if (ret > 0) {
+                       if (encoder) {
+                               radeon_fixup_lvds_native_mode(encoder, connector);
+                               /* add scaled modes */
+                               radeon_add_common_modes(encoder, connector);
+                       }
+                       return ret;
+               }
+
+               encoder = radeon_best_single_encoder(connector);
+               if (!encoder)
+                       return 0;
+
+               /* we have no EDID modes */
+               mode = radeon_fp_native_mode(encoder);
+               if (mode) {
+                       ret = 1;
+                       drm_mode_probed_add(connector, mode);
+                       /* add the width/height from vbios tables if available */
+                       connector->display_info.width_mm = mode->width_mm;
+                       connector->display_info.height_mm = mode->height_mm;
+                       /* add scaled modes */
+                       radeon_add_common_modes(encoder, connector);
+               }
+       } else {
+               /* need to setup ddc on the bridge */
+               if (radeon_connector_encoder_is_dp_bridge(connector)) {
+                       if (encoder)
+                               radeon_atom_ext_encoder_setup_ddc(encoder);
+               }
+               ret = radeon_ddc_get_modes(radeon_connector);
        }
 
        return ret;
 }
 
+bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector)
+{
+       struct drm_mode_object *obj;
+       struct drm_encoder *encoder;
+       struct radeon_encoder *radeon_encoder;
+       int i;
+       bool found = false;
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+               if (connector->encoder_ids[i] == 0)
+                       break;
+
+               obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER);
+               if (!obj)
+                       continue;
+
+               encoder = obj_to_encoder(obj);
+               radeon_encoder = to_radeon_encoder(encoder);
+
+               switch (radeon_encoder->encoder_id) {
+               case ENCODER_OBJECT_ID_TRAVIS:
+               case ENCODER_OBJECT_ID_NUTMEG:
+                       found = true;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return found;
+}
+
+bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector)
+{
+       struct drm_mode_object *obj;
+       struct drm_encoder *encoder;
+       struct radeon_encoder *radeon_encoder;
+       int i;
+       bool found = false;
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+               if (connector->encoder_ids[i] == 0)
+                       break;
+
+               obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER);
+               if (!obj)
+                       continue;
+
+               encoder = obj_to_encoder(obj);
+               radeon_encoder = to_radeon_encoder(encoder);
+               if (radeon_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2)
+                       found = true;
+       }
+
+       return found;
+}
+
+bool radeon_connector_is_dp12_capable(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct radeon_device *rdev = dev->dev_private;
+
+       if (ASIC_IS_DCE5(rdev) &&
+           (rdev->clock.dp_extclk >= 53900) &&
+           radeon_connector_encoder_is_hbr2(connector)) {
+               return true;
+       }
+
+       return false;
+}
+
 static enum drm_connector_status
 radeon_dp_detect(struct drm_connector *connector, bool force)
 {
+       struct drm_device *dev = connector->dev;
+       struct radeon_device *rdev = dev->dev_private;
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
        enum drm_connector_status ret = connector_status_disconnected;
        struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
+       struct drm_encoder *encoder = radeon_best_single_encoder(connector);
 
        if (radeon_connector->edid) {
                kfree(radeon_connector->edid);
                radeon_connector->edid = NULL;
        }
 
-       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+       if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
+           (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
+               if (encoder) {
+                       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+                       struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
+
+                       /* check if panel is valid */
+                       if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
+                               ret = connector_status_connected;
+               }
                /* eDP is always DP */
                radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
                if (!radeon_dig_connector->edp_on)
@@ -1092,13 +1230,34 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
                        atombios_set_edp_panel_power(connector,
                                                     ATOM_TRANSMITTER_ACTION_POWER_OFF);
        } else {
+               /* need to setup ddc on the bridge */
+               if (radeon_connector_encoder_is_dp_bridge(connector)) {
+                       if (encoder)
+                               radeon_atom_ext_encoder_setup_ddc(encoder);
+               }
                radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
-               if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
-                       if (radeon_dp_getdpcd(radeon_connector))
-                               ret = connector_status_connected;
+               if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
+                       ret = connector_status_connected;
+                       if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
+                               radeon_dp_getdpcd(radeon_connector);
                } else {
-                       if (radeon_ddc_probe(radeon_connector))
-                               ret = connector_status_connected;
+                       if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
+                               if (radeon_dp_getdpcd(radeon_connector))
+                                       ret = connector_status_connected;
+                       } else {
+                               if (radeon_ddc_probe(radeon_connector))
+                                       ret = connector_status_connected;
+                       }
+               }
+
+               if ((ret == connector_status_disconnected) &&
+                   radeon_connector->dac_load_detect) {
+                       struct drm_encoder *encoder = radeon_best_single_encoder(connector);
+                       struct drm_encoder_helper_funcs *encoder_funcs;
+                       if (encoder) {
+                               encoder_funcs = encoder->helper_private;
+                               ret = encoder_funcs->detect(encoder, connector);
+                       }
                }
        }
 
@@ -1114,11 +1273,39 @@ static int radeon_dp_mode_valid(struct drm_connector *connector,
 
        /* XXX check mode bandwidth */
 
-       if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
-           (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
-               return radeon_dp_mode_valid_helper(radeon_connector, mode);
-       else
+       if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
+           (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
+               struct drm_encoder *encoder = radeon_best_single_encoder(connector);
+
+               if ((mode->hdisplay < 320) || (mode->vdisplay < 240))
+                       return MODE_PANEL;
+
+               if (encoder) {
+                       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+                       struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
+
+                       /* AVIVO hardware supports downscaling modes larger than the panel
+                        * to the panel size, but I'm not sure this is desirable.
+                        */
+                       if ((mode->hdisplay > native_mode->hdisplay) ||
+                           (mode->vdisplay > native_mode->vdisplay))
+                               return MODE_PANEL;
+
+                       /* if scaling is disabled, block non-native modes */
+                       if (radeon_encoder->rmx_type == RMX_OFF) {
+                               if ((mode->hdisplay != native_mode->hdisplay) ||
+                                   (mode->vdisplay != native_mode->vdisplay))
+                                       return MODE_PANEL;
+                       }
+               }
                return MODE_OK;
+       } else {
+               if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
+                   (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
+                       return radeon_dp_mode_valid_helper(connector, mode);
+               else
+                       return MODE_OK;
+       }
 }
 
 struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = {
@@ -1151,8 +1338,11 @@ radeon_add_atom_connector(struct drm_device *dev,
        struct drm_connector *connector;
        struct radeon_connector *radeon_connector;
        struct radeon_connector_atom_dig *radeon_dig_connector;
+       struct drm_encoder *encoder;
+       struct radeon_encoder *radeon_encoder;
        uint32_t subpixel_order = SubPixelNone;
        bool shared_ddc = false;
+       bool is_dp_bridge = false;
 
        if (connector_type == DRM_MODE_CONNECTOR_Unknown)
                return;
@@ -1184,6 +1374,21 @@ radeon_add_atom_connector(struct drm_device *dev,
                }
        }
 
+       /* check if it's a dp bridge */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               radeon_encoder = to_radeon_encoder(encoder);
+               if (radeon_encoder->devices & supported_device) {
+                       switch (radeon_encoder->encoder_id) {
+                       case ENCODER_OBJECT_ID_TRAVIS:
+                       case ENCODER_OBJECT_ID_NUTMEG:
+                               is_dp_bridge = true;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+
        radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
        if (!radeon_connector)
                return;
@@ -1201,61 +1406,43 @@ radeon_add_atom_connector(struct drm_device *dev,
                if (!radeon_connector->router_bus)
                        DRM_ERROR("Failed to assign router i2c bus! Check dmesg for i2c errors.\n");
        }
-       switch (connector_type) {
-       case DRM_MODE_CONNECTOR_VGA:
-               drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
-               drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
-               if (i2c_bus->valid) {
-                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
-                       if (!radeon_connector->ddc_bus)
-                               DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
-               }
-               radeon_connector->dac_load_detect = true;
-               drm_connector_attach_property(&radeon_connector->base,
-                                             rdev->mode_info.load_detect_property,
-                                             1);
-               /* no HPD on analog connectors */
-               radeon_connector->hpd.hpd = RADEON_HPD_NONE;
-               connector->polled = DRM_CONNECTOR_POLL_CONNECT;
-               connector->interlace_allowed = true;
-               connector->doublescan_allowed = true;
-               break;
-       case DRM_MODE_CONNECTOR_DVIA:
-               drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
-               drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
-               if (i2c_bus->valid) {
-                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
-                       if (!radeon_connector->ddc_bus)
-                               DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
-               }
-               radeon_connector->dac_load_detect = true;
-               drm_connector_attach_property(&radeon_connector->base,
-                                             rdev->mode_info.load_detect_property,
-                                             1);
-               /* no HPD on analog connectors */
-               radeon_connector->hpd.hpd = RADEON_HPD_NONE;
-               connector->interlace_allowed = true;
-               connector->doublescan_allowed = true;
-               break;
-       case DRM_MODE_CONNECTOR_DVII:
-       case DRM_MODE_CONNECTOR_DVID:
+
+       if (is_dp_bridge) {
                radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
                if (!radeon_dig_connector)
                        goto failed;
                radeon_dig_connector->igp_lane_info = igp_lane_info;
                radeon_connector->con_priv = radeon_dig_connector;
-               drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
-               drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
+               drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
+               drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
                if (i2c_bus->valid) {
+                       /* add DP i2c bus */
+                       if (connector_type == DRM_MODE_CONNECTOR_eDP)
+                               radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch");
+                       else
+                               radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch");
+                       if (!radeon_dig_connector->dp_i2c_bus)
+                               DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
                        radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
-                               DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                               DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
                }
-               subpixel_order = SubPixelHorizontalRGB;
-               drm_connector_attach_property(&radeon_connector->base,
-                                             rdev->mode_info.coherent_mode_property,
-                                             1);
-               if (ASIC_IS_AVIVO(rdev)) {
+               switch (connector_type) {
+               case DRM_MODE_CONNECTOR_VGA:
+               case DRM_MODE_CONNECTOR_DVIA:
+               default:
+                       connector->interlace_allowed = true;
+                       connector->doublescan_allowed = true;
+                       radeon_connector->dac_load_detect = true;
+                       drm_connector_attach_property(&radeon_connector->base,
+                                                     rdev->mode_info.load_detect_property,
+                                                     1);
+                       break;
+               case DRM_MODE_CONNECTOR_DVII:
+               case DRM_MODE_CONNECTOR_DVID:
+               case DRM_MODE_CONNECTOR_HDMIA:
+               case DRM_MODE_CONNECTOR_HDMIB:
+               case DRM_MODE_CONNECTOR_DisplayPort:
                        drm_connector_attach_property(&radeon_connector->base,
                                                      rdev->mode_info.underscan_property,
                                                      UNDERSCAN_OFF);
@@ -1265,131 +1452,240 @@ radeon_add_atom_connector(struct drm_device *dev,
                        drm_connector_attach_property(&radeon_connector->base,
                                                      rdev->mode_info.underscan_vborder_property,
                                                      0);
+                       subpixel_order = SubPixelHorizontalRGB;
+                       connector->interlace_allowed = true;
+                       if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
+                               connector->doublescan_allowed = true;
+                       else
+                               connector->doublescan_allowed = false;
+                       if (connector_type == DRM_MODE_CONNECTOR_DVII) {
+                               radeon_connector->dac_load_detect = true;
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.load_detect_property,
+                                                             1);
+                       }
+                       break;
+               case DRM_MODE_CONNECTOR_LVDS:
+               case DRM_MODE_CONNECTOR_eDP:
+                       drm_connector_attach_property(&radeon_connector->base,
+                                                     dev->mode_config.scaling_mode_property,
+                                                     DRM_MODE_SCALE_FULLSCREEN);
+                       subpixel_order = SubPixelHorizontalRGB;
+                       connector->interlace_allowed = false;
+                       connector->doublescan_allowed = false;
+                       break;
                }
-               if (connector_type == DRM_MODE_CONNECTOR_DVII) {
+       } else {
+               switch (connector_type) {
+               case DRM_MODE_CONNECTOR_VGA:
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
+                       if (i2c_bus->valid) {
+                               radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+                               if (!radeon_connector->ddc_bus)
+                                       DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                       }
                        radeon_connector->dac_load_detect = true;
                        drm_connector_attach_property(&radeon_connector->base,
                                                      rdev->mode_info.load_detect_property,
                                                      1);
-               }
-               connector->interlace_allowed = true;
-               if (connector_type == DRM_MODE_CONNECTOR_DVII)
+                       /* no HPD on analog connectors */
+                       radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+                       connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+                       connector->interlace_allowed = true;
                        connector->doublescan_allowed = true;
-               else
-                       connector->doublescan_allowed = false;
-               break;
-       case DRM_MODE_CONNECTOR_HDMIA:
-       case DRM_MODE_CONNECTOR_HDMIB:
-               radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
-               if (!radeon_dig_connector)
-                       goto failed;
-               radeon_dig_connector->igp_lane_info = igp_lane_info;
-               radeon_connector->con_priv = radeon_dig_connector;
-               drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
-               drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
-               if (i2c_bus->valid) {
-                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
-                       if (!radeon_connector->ddc_bus)
-                               DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
-               }
-               drm_connector_attach_property(&radeon_connector->base,
-                                             rdev->mode_info.coherent_mode_property,
-                                             1);
-               if (ASIC_IS_AVIVO(rdev)) {
+                       break;
+               case DRM_MODE_CONNECTOR_DVIA:
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
+                       if (i2c_bus->valid) {
+                               radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+                               if (!radeon_connector->ddc_bus)
+                                       DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                       }
+                       radeon_connector->dac_load_detect = true;
                        drm_connector_attach_property(&radeon_connector->base,
-                                                     rdev->mode_info.underscan_property,
-                                                     UNDERSCAN_OFF);
+                                                     rdev->mode_info.load_detect_property,
+                                                     1);
+                       /* no HPD on analog connectors */
+                       radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+                       connector->interlace_allowed = true;
+                       connector->doublescan_allowed = true;
+                       break;
+               case DRM_MODE_CONNECTOR_DVII:
+               case DRM_MODE_CONNECTOR_DVID:
+                       radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+                       if (!radeon_dig_connector)
+                               goto failed;
+                       radeon_dig_connector->igp_lane_info = igp_lane_info;
+                       radeon_connector->con_priv = radeon_dig_connector;
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
+                       if (i2c_bus->valid) {
+                               radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+                               if (!radeon_connector->ddc_bus)
+                                       DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                       }
+                       subpixel_order = SubPixelHorizontalRGB;
                        drm_connector_attach_property(&radeon_connector->base,
-                                                     rdev->mode_info.underscan_hborder_property,
-                                                     0);
+                                                     rdev->mode_info.coherent_mode_property,
+                                                     1);
+                       if (ASIC_IS_AVIVO(rdev)) {
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_property,
+                                                             UNDERSCAN_OFF);
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_hborder_property,
+                                                             0);
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_vborder_property,
+                                                             0);
+                       }
+                       if (connector_type == DRM_MODE_CONNECTOR_DVII) {
+                               radeon_connector->dac_load_detect = true;
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.load_detect_property,
+                                                             1);
+                       }
+                       connector->interlace_allowed = true;
+                       if (connector_type == DRM_MODE_CONNECTOR_DVII)
+                               connector->doublescan_allowed = true;
+                       else
+                               connector->doublescan_allowed = false;
+                       break;
+               case DRM_MODE_CONNECTOR_HDMIA:
+               case DRM_MODE_CONNECTOR_HDMIB:
+                       radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+                       if (!radeon_dig_connector)
+                               goto failed;
+                       radeon_dig_connector->igp_lane_info = igp_lane_info;
+                       radeon_connector->con_priv = radeon_dig_connector;
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
+                       if (i2c_bus->valid) {
+                               radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+                               if (!radeon_connector->ddc_bus)
+                                       DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                       }
                        drm_connector_attach_property(&radeon_connector->base,
-                                                     rdev->mode_info.underscan_vborder_property,
-                                                     0);
-               }
-               subpixel_order = SubPixelHorizontalRGB;
-               connector->interlace_allowed = true;
-               if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
-                       connector->doublescan_allowed = true;
-               else
-                       connector->doublescan_allowed = false;
-               break;
-       case DRM_MODE_CONNECTOR_DisplayPort:
-       case DRM_MODE_CONNECTOR_eDP:
-               radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
-               if (!radeon_dig_connector)
-                       goto failed;
-               radeon_dig_connector->igp_lane_info = igp_lane_info;
-               radeon_connector->con_priv = radeon_dig_connector;
-               drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
-               drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
-               if (i2c_bus->valid) {
-                       /* add DP i2c bus */
-                       if (connector_type == DRM_MODE_CONNECTOR_eDP)
-                               radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch");
+                                                     rdev->mode_info.coherent_mode_property,
+                                                     1);
+                       if (ASIC_IS_AVIVO(rdev)) {
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_property,
+                                                             UNDERSCAN_OFF);
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_hborder_property,
+                                                             0);
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_vborder_property,
+                                                             0);
+                       }
+                       subpixel_order = SubPixelHorizontalRGB;
+                       connector->interlace_allowed = true;
+                       if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
+                               connector->doublescan_allowed = true;
                        else
+                               connector->doublescan_allowed = false;
+                       break;
+               case DRM_MODE_CONNECTOR_DisplayPort:
+                       radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+                       if (!radeon_dig_connector)
+                               goto failed;
+                       radeon_dig_connector->igp_lane_info = igp_lane_info;
+                       radeon_connector->con_priv = radeon_dig_connector;
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
+                       if (i2c_bus->valid) {
+                               /* add DP i2c bus */
                                radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch");
-                       if (!radeon_dig_connector->dp_i2c_bus)
-                               DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
-                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
-                       if (!radeon_connector->ddc_bus)
-                               DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
-               }
-               subpixel_order = SubPixelHorizontalRGB;
-               drm_connector_attach_property(&radeon_connector->base,
-                                             rdev->mode_info.coherent_mode_property,
-                                             1);
-               if (ASIC_IS_AVIVO(rdev)) {
+                               if (!radeon_dig_connector->dp_i2c_bus)
+                                       DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
+                               radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+                               if (!radeon_connector->ddc_bus)
+                                       DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                       }
+                       subpixel_order = SubPixelHorizontalRGB;
                        drm_connector_attach_property(&radeon_connector->base,
-                                                     rdev->mode_info.underscan_property,
-                                                     UNDERSCAN_OFF);
+                                                     rdev->mode_info.coherent_mode_property,
+                                                     1);
+                       if (ASIC_IS_AVIVO(rdev)) {
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_property,
+                                                             UNDERSCAN_OFF);
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_hborder_property,
+                                                             0);
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_vborder_property,
+                                                             0);
+                       }
+                       connector->interlace_allowed = true;
+                       /* in theory with a DP to VGA converter... */
+                       connector->doublescan_allowed = false;
+                       break;
+               case DRM_MODE_CONNECTOR_eDP:
+                       radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+                       if (!radeon_dig_connector)
+                               goto failed;
+                       radeon_dig_connector->igp_lane_info = igp_lane_info;
+                       radeon_connector->con_priv = radeon_dig_connector;
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
+                       if (i2c_bus->valid) {
+                               /* add DP i2c bus */
+                               radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch");
+                               if (!radeon_dig_connector->dp_i2c_bus)
+                                       DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
+                               radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+                               if (!radeon_connector->ddc_bus)
+                                       DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                       }
                        drm_connector_attach_property(&radeon_connector->base,
-                                                     rdev->mode_info.underscan_hborder_property,
-                                                     0);
+                                                     dev->mode_config.scaling_mode_property,
+                                                     DRM_MODE_SCALE_FULLSCREEN);
+                       subpixel_order = SubPixelHorizontalRGB;
+                       connector->interlace_allowed = false;
+                       connector->doublescan_allowed = false;
+                       break;
+               case DRM_MODE_CONNECTOR_SVIDEO:
+               case DRM_MODE_CONNECTOR_Composite:
+               case DRM_MODE_CONNECTOR_9PinDIN:
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
+                       radeon_connector->dac_load_detect = true;
                        drm_connector_attach_property(&radeon_connector->base,
-                                                     rdev->mode_info.underscan_vborder_property,
-                                                     0);
-               }
-               connector->interlace_allowed = true;
-               /* in theory with a DP to VGA converter... */
-               connector->doublescan_allowed = false;
-               break;
-       case DRM_MODE_CONNECTOR_SVIDEO:
-       case DRM_MODE_CONNECTOR_Composite:
-       case DRM_MODE_CONNECTOR_9PinDIN:
-               drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
-               drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
-               radeon_connector->dac_load_detect = true;
-               drm_connector_attach_property(&radeon_connector->base,
-                                             rdev->mode_info.load_detect_property,
-                                             1);
-               drm_connector_attach_property(&radeon_connector->base,
-                                             rdev->mode_info.tv_std_property,
-                                             radeon_atombios_get_tv_info(rdev));
-               /* no HPD on analog connectors */
-               radeon_connector->hpd.hpd = RADEON_HPD_NONE;
-               connector->interlace_allowed = false;
-               connector->doublescan_allowed = false;
-               break;
-       case DRM_MODE_CONNECTOR_LVDS:
-               radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
-               if (!radeon_dig_connector)
-                       goto failed;
-               radeon_dig_connector->igp_lane_info = igp_lane_info;
-               radeon_connector->con_priv = radeon_dig_connector;
-               drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
-               drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
-               if (i2c_bus->valid) {
-                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
-                       if (!radeon_connector->ddc_bus)
-                               DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                                                     rdev->mode_info.load_detect_property,
+                                                     1);
+                       drm_connector_attach_property(&radeon_connector->base,
+                                                     rdev->mode_info.tv_std_property,
+                                                     radeon_atombios_get_tv_info(rdev));
+                       /* no HPD on analog connectors */
+                       radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+                       connector->interlace_allowed = false;
+                       connector->doublescan_allowed = false;
+                       break;
+               case DRM_MODE_CONNECTOR_LVDS:
+                       radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+                       if (!radeon_dig_connector)
+                               goto failed;
+                       radeon_dig_connector->igp_lane_info = igp_lane_info;
+                       radeon_connector->con_priv = radeon_dig_connector;
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
+                       if (i2c_bus->valid) {
+                               radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+                               if (!radeon_connector->ddc_bus)
+                                       DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                       }
+                       drm_connector_attach_property(&radeon_connector->base,
+                                                     dev->mode_config.scaling_mode_property,
+                                                     DRM_MODE_SCALE_FULLSCREEN);
+                       subpixel_order = SubPixelHorizontalRGB;
+                       connector->interlace_allowed = false;
+                       connector->doublescan_allowed = false;
+                       break;
                }
-               drm_connector_attach_property(&radeon_connector->base,
-                                             dev->mode_config.scaling_mode_property,
-                                             DRM_MODE_SCALE_FULLSCREEN);
-               subpixel_order = SubPixelHorizontalRGB;
-               connector->interlace_allowed = false;
-               connector->doublescan_allowed = false;
-               break;
        }
 
        if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
index 8c1916941871d4bd10b0c3fda53eecdaad3e96cd..fae00c0d75aaf1fae7fcbfc9b504370f560f5d42 100644 (file)
@@ -228,6 +228,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
        parser.filp = filp;
        parser.rdev = rdev;
        parser.dev = rdev->dev;
+       parser.family = rdev->family;
        r = radeon_cs_parser_init(&parser, data);
        if (r) {
                DRM_ERROR("Failed to initialize parser !\n");
index 890217e678d37f7591e7004bb4253e0f06f2d998..7cfaa7e2f3b57195671beb6958c8447f9f108683 100644 (file)
@@ -82,6 +82,8 @@ static const char radeon_family_name[][16] = {
        "CYPRESS",
        "HEMLOCK",
        "PALM",
+       "SUMO",
+       "SUMO2",
        "BARTS",
        "TURKS",
        "CAICOS",
@@ -213,6 +215,8 @@ int radeon_wb_init(struct radeon_device *rdev)
                return r;
        }
 
+       /* clear wb memory */
+       memset((char *)rdev->wb.wb, 0, RADEON_GPU_PAGE_SIZE);
        /* disable event_write fences */
        rdev->wb.use_event = false;
        /* disabled via module param */
@@ -752,6 +756,7 @@ int radeon_device_init(struct radeon_device *rdev,
        dma_bits = rdev->need_dma32 ? 32 : 40;
        r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits));
        if (r) {
+               rdev->need_dma32 = true;
                printk(KERN_WARNING "radeon: No suitable DMA available.\n");
        }
 
@@ -923,6 +928,9 @@ int radeon_resume_kms(struct drm_device *dev)
        radeon_fbdev_set_suspend(rdev, 0);
        console_unlock();
 
+       /* init dig PHYs */
+       if (rdev->is_atom_bios)
+               radeon_atom_encoder_init(rdev);
        /* reset hpd state */
        radeon_hpd_init(rdev);
        /* blat the mode back in */
index bdbab5c43bdc05f3305155d35303ab1bfdf25a5e..292f73f0ddbd51210b8bf3494acdd79dc3d54719 100644 (file)
@@ -264,6 +264,8 @@ static void radeon_unpin_work_func(struct work_struct *__work)
                radeon_bo_unreserve(work->old_rbo);
        } else
                DRM_ERROR("failed to reserve buffer after flip\n");
+
+       drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);
        kfree(work);
 }
 
@@ -371,6 +373,8 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
        new_radeon_fb = to_radeon_framebuffer(fb);
        /* schedule unpin of the old buffer */
        obj = old_radeon_fb->obj;
+       /* take a reference to the old object */
+       drm_gem_object_reference(obj);
        rbo = gem_to_radeon_bo(obj);
        work->old_rbo = rbo;
        INIT_WORK(&work->work, radeon_unpin_work_func);
@@ -378,12 +382,9 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
        /* We borrow the event spin lock for protecting unpin_work */
        spin_lock_irqsave(&dev->event_lock, flags);
        if (radeon_crtc->unpin_work) {
-               spin_unlock_irqrestore(&dev->event_lock, flags);
-               kfree(work);
-               radeon_fence_unref(&fence);
-
                DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
-               return -EBUSY;
+               r = -EBUSY;
+               goto unlock_free;
        }
        radeon_crtc->unpin_work = work;
        radeon_crtc->deferred_flip_completion = 0;
@@ -497,6 +498,8 @@ pflip_cleanup1:
 pflip_cleanup:
        spin_lock_irqsave(&dev->event_lock, flags);
        radeon_crtc->unpin_work = NULL;
+unlock_free:
+       drm_gem_object_unreference_unlocked(old_radeon_fb->obj);
        spin_unlock_irqrestore(&dev->event_lock, flags);
        radeon_fence_unref(&fence);
        kfree(work);
@@ -1087,8 +1090,9 @@ void radeon_compute_pll_legacy(struct radeon_pll *pll,
        *frac_fb_div_p = best_frac_feedback_div;
        *ref_div_p = best_ref_div;
        *post_div_p = best_post_div;
-       DRM_DEBUG_KMS("%d %d, pll dividers - fb: %d.%d ref: %d, post %d\n",
-                     freq, best_freq / 1000, best_feedback_div, best_frac_feedback_div,
+       DRM_DEBUG_KMS("%lld %d, pll dividers - fb: %d.%d ref: %d, post %d\n",
+                     (long long)freq,
+                     best_freq / 1000, best_feedback_div, best_frac_feedback_div,
                      best_ref_div, best_post_div);
 
 }
@@ -1344,6 +1348,11 @@ int radeon_modeset_init(struct radeon_device *rdev)
        if (!ret) {
                return ret;
        }
+
+       /* init dig PHYs */
+       if (rdev->is_atom_bios)
+               radeon_atom_encoder_init(rdev);
+
        /* initialize hpd */
        radeon_hpd_init(rdev);
 
index 63d2de8771dc1ab20dade4b96270a51b0ad5409e..73dfbe8e5f9ed7d750a424c5fa9aa7a8ed6ab025 100644 (file)
  *   2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs
  *   2.8.0 - pageflip support, r500 US_FORMAT regs. r500 ARGB2101010 colorbuf, r300->r500 CMASK, clock crystal query
  *   2.9.0 - r600 tiling (s3tc,rgtc) working, SET_PREDICATION packet 3 on r600 + eg, backend query
+ *   2.10.0 - fusion 2D tiling
  */
 #define KMS_DRIVER_MAJOR       2
-#define KMS_DRIVER_MINOR       9
+#define KMS_DRIVER_MINOR       10
 #define KMS_DRIVER_PATCHLEVEL  0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
@@ -112,7 +113,7 @@ int radeon_benchmarking = 0;
 int radeon_testing = 0;
 int radeon_connector_table = 0;
 int radeon_tv = 1;
-int radeon_audio = 1;
+int radeon_audio = 0;
 int radeon_disp_priority = 0;
 int radeon_hw_i2c = 0;
 int radeon_pcie_gen2 = 0;
@@ -150,7 +151,7 @@ module_param_named(connector_table, radeon_connector_table, int, 0444);
 MODULE_PARM_DESC(tv, "TV enable (0 = disable)");
 module_param_named(tv, radeon_tv, int, 0444);
 
-MODULE_PARM_DESC(audio, "Audio enable (0 = disable)");
+MODULE_PARM_DESC(audio, "Audio enable (1 = enable)");
 module_param_named(audio, radeon_audio, int, 0444);
 
 MODULE_PARM_DESC(disp_priority, "Display Priority (0 = auto, 1 = normal, 2 = high)");
index b4274883227fee64e283f39934050cefa6d36cde..b293487e5aa3dc2193fee36eb0f9c00fe7080a0c 100644 (file)
@@ -229,6 +229,22 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder)
        return NULL;
 }
 
+static struct drm_connector *
+radeon_get_connector_for_encoder_init(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               radeon_connector = to_radeon_connector(connector);
+               if (radeon_encoder->devices & radeon_connector->devices)
+                       return connector;
+       }
+       return NULL;
+}
+
 struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
@@ -250,6 +266,25 @@ struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder
        return NULL;
 }
 
+bool radeon_encoder_is_dp_bridge(struct drm_encoder *encoder)
+{
+       struct drm_encoder *other_encoder = radeon_atom_get_external_encoder(encoder);
+
+       if (other_encoder) {
+               struct radeon_encoder *radeon_encoder = to_radeon_encoder(other_encoder);
+
+               switch (radeon_encoder->encoder_id) {
+               case ENCODER_OBJECT_ID_TRAVIS:
+               case ENCODER_OBJECT_ID_NUTMEG:
+                       return true;
+               default:
+                       return false;
+               }
+       }
+
+       return false;
+}
+
 void radeon_panel_mode_fixup(struct drm_encoder *encoder,
                             struct drm_display_mode *adjusted_mode)
 {
@@ -332,7 +367,8 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
        }
 
        if (ASIC_IS_DCE3(rdev) &&
-           (radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT))) {
+           ((radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) ||
+            radeon_encoder_is_dp_bridge(encoder))) {
                struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
                radeon_dp_set_link_config(connector, mode);
        }
@@ -621,21 +657,20 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        struct radeon_connector *radeon_connector;
        struct radeon_connector_atom_dig *dig_connector;
 
+       /* dp bridges are always DP */
+       if (radeon_encoder_is_dp_bridge(encoder))
+               return ATOM_ENCODER_MODE_DP;
+
+       /* DVO is always DVO */
+       if (radeon_encoder->encoder_id == ATOM_ENCODER_MODE_DVO)
+               return ATOM_ENCODER_MODE_DVO;
+
        connector = radeon_get_connector_for_encoder(encoder);
-       if (!connector) {
-               switch (radeon_encoder->encoder_id) {
-               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
-               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
-               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
-               case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
-               case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
-                       return ATOM_ENCODER_MODE_DVI;
-               case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
-               case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
-               default:
-                       return ATOM_ENCODER_MODE_CRT;
-               }
-       }
+       /* if we don't have an active device yet, just use one of
+        * the connectors tied to the encoder.
+        */
+       if (!connector)
+               connector = radeon_get_connector_for_encoder_init(encoder);
        radeon_connector = to_radeon_connector(connector);
 
        switch (connector->connector_type) {
@@ -668,7 +703,6 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
                return ATOM_ENCODER_MODE_LVDS;
                break;
        case DRM_MODE_CONNECTOR_DisplayPort:
-       case DRM_MODE_CONNECTOR_eDP:
                dig_connector = radeon_connector->con_priv;
                if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
                    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
@@ -682,6 +716,8 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
                } else
                        return ATOM_ENCODER_MODE_DVI;
                break;
+       case DRM_MODE_CONNECTOR_eDP:
+               return ATOM_ENCODER_MODE_DP;
        case DRM_MODE_CONNECTOR_DVIA:
        case DRM_MODE_CONNECTOR_VGA:
                return ATOM_ENCODER_MODE_CRT;
@@ -747,7 +783,7 @@ union dig_encoder_control {
 };
 
 void
-atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
+atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -760,6 +796,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
        int dp_clock = 0;
        int dp_lane_count = 0;
        int hpd_id = RADEON_HPD_NONE;
+       int bpc = 8;
 
        if (connector) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -769,6 +806,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
                dp_clock = dig_connector->dp_clock;
                dp_lane_count = dig_connector->dp_lane_count;
                hpd_id = radeon_connector->hpd.hpd;
+               bpc = connector->display_info.bpc;
        }
 
        /* no dig encoder assigned */
@@ -791,7 +829,10 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
 
        args.v1.ucAction = action;
        args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
-       args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder);
+       if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
+               args.v3.ucPanelMode = panel_mode;
+       else
+               args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder);
 
        if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) ||
            (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST))
@@ -810,7 +851,27 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
                                args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ;
                }
                args.v4.acConfig.ucDigSel = dig->dig_encoder;
-               args.v4.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+               switch (bpc) {
+               case 0:
+                       args.v4.ucBitPerColor = PANEL_BPC_UNDEFINE;
+                       break;
+               case 6:
+                       args.v4.ucBitPerColor = PANEL_6BIT_PER_COLOR;
+                       break;
+               case 8:
+               default:
+                       args.v4.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+                       break;
+               case 10:
+                       args.v4.ucBitPerColor = PANEL_10BIT_PER_COLOR;
+                       break;
+               case 12:
+                       args.v4.ucBitPerColor = PANEL_12BIT_PER_COLOR;
+                       break;
+               case 16:
+                       args.v4.ucBitPerColor = PANEL_16BIT_PER_COLOR;
+                       break;
+               }
                if (hpd_id == RADEON_HPD_NONE)
                        args.v4.ucHPD_ID = 0;
                else
@@ -819,7 +880,27 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
                if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) && (dp_clock == 270000))
                        args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
                args.v3.acConfig.ucDigSel = dig->dig_encoder;
-               args.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+               switch (bpc) {
+               case 0:
+                       args.v3.ucBitPerColor = PANEL_BPC_UNDEFINE;
+                       break;
+               case 6:
+                       args.v3.ucBitPerColor = PANEL_6BIT_PER_COLOR;
+                       break;
+               case 8:
+               default:
+                       args.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+                       break;
+               case 10:
+                       args.v3.ucBitPerColor = PANEL_10BIT_PER_COLOR;
+                       break;
+               case 12:
+                       args.v3.ucBitPerColor = PANEL_12BIT_PER_COLOR;
+                       break;
+               case 16:
+                       args.v3.ucBitPerColor = PANEL_16BIT_PER_COLOR;
+                       break;
+               }
        } else {
                if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) && (dp_clock == 270000))
                        args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
@@ -859,7 +940,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+       struct drm_connector *connector;
        union dig_transmitter_control args;
        int index = 0;
        uint8_t frev, crev;
@@ -869,6 +950,16 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
        int dp_lane_count = 0;
        int connector_object_id = 0;
        int igp_lane_info = 0;
+       int dig_encoder = dig->dig_encoder;
+
+       if (action == ATOM_TRANSMITTER_ACTION_INIT) {
+               connector = radeon_get_connector_for_encoder_init(encoder);
+               /* just needed to avoid bailing in the encoder check.  the encoder
+                * isn't used for init
+                */
+               dig_encoder = 0;
+       } else
+               connector = radeon_get_connector_for_encoder(encoder);
 
        if (connector) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -883,7 +974,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
        }
 
        /* no dig encoder assigned */
-       if (dig->dig_encoder == -1)
+       if (dig_encoder == -1)
                return;
 
        if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP)
@@ -931,10 +1022,10 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
                else
                        args.v3.ucLaneNum = 4;
 
-               if (dig->linkb) {
+               if (dig->linkb)
                        args.v3.acConfig.ucLinkSel = 1;
+               if (dig_encoder & 1)
                        args.v3.acConfig.ucEncoderSel = 1;
-               }
 
                /* Select the PLL for the PHY
                 * DP PHY should be clocked from external src if there is
@@ -946,11 +1037,16 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
                }
 
                if (ASIC_IS_DCE5(rdev)) {
-                       if (is_dp && rdev->clock.dp_extclk)
-                               args.v4.acConfig.ucRefClkSource = 3; /* external src */
-                       else
+                       /* On DCE5 DCPLL usually generates the DP ref clock */
+                       if (is_dp) {
+                               if (rdev->clock.dp_extclk)
+                                       args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_EXTCLK;
+                               else
+                                       args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_DCPLL;
+                       } else
                                args.v4.acConfig.ucRefClkSource = pll_id;
                } else {
+                       /* On DCE4, if there is an external clock, it generates the DP ref clock */
                        if (is_dp && rdev->clock.dp_extclk)
                                args.v3.acConfig.ucRefClkSource = 2; /* external src */
                        else
@@ -978,7 +1074,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
                                args.v3.acConfig.fDualLinkConnector = 1;
                }
        } else if (ASIC_IS_DCE32(rdev)) {
-               args.v2.acConfig.ucEncoderSel = dig->dig_encoder;
+               args.v2.acConfig.ucEncoderSel = dig_encoder;
                if (dig->linkb)
                        args.v2.acConfig.ucLinkSel = 1;
 
@@ -994,9 +1090,10 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
                        break;
                }
 
-               if (is_dp)
+               if (is_dp) {
                        args.v2.acConfig.fCoherentMode = 1;
-               else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+                       args.v2.acConfig.fDPConnector = 1;
+               } else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
                        if (dig->coherent_mode)
                                args.v2.acConfig.fCoherentMode = 1;
                        if (radeon_encoder->pixel_clock > 165000)
@@ -1005,7 +1102,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
        } else {
                args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL;
 
-               if (dig->dig_encoder)
+               if (dig_encoder)
                        args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
                else
                        args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
@@ -1047,7 +1144,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
-void
+bool
 atombios_set_edp_panel_power(struct drm_connector *connector, int action)
 {
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -1058,23 +1155,37 @@ atombios_set_edp_panel_power(struct drm_connector *connector, int action)
        uint8_t frev, crev;
 
        if (connector->connector_type != DRM_MODE_CONNECTOR_eDP)
-               return;
+               goto done;
 
        if (!ASIC_IS_DCE4(rdev))
-               return;
+               goto done;
 
        if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) &&
            (action != ATOM_TRANSMITTER_ACTION_POWER_OFF))
-               return;
+               goto done;
 
        if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
-               return;
+               goto done;
 
        memset(&args, 0, sizeof(args));
 
        args.v1.ucAction = action;
 
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+       /* wait for the panel to power up */
+       if (action == ATOM_TRANSMITTER_ACTION_POWER_ON) {
+               int i;
+
+               for (i = 0; i < 300; i++) {
+                       if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
+                               return true;
+                       mdelay(1);
+               }
+               return false;
+       }
+done:
+       return true;
 }
 
 union external_encoder_control {
@@ -1092,13 +1203,19 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder);
        union external_encoder_control args;
-       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+       struct drm_connector *connector;
        int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl);
        u8 frev, crev;
        int dp_clock = 0;
        int dp_lane_count = 0;
        int connector_object_id = 0;
        u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
+       int bpc = 8;
+
+       if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT)
+               connector = radeon_get_connector_for_encoder_init(encoder);
+       else
+               connector = radeon_get_connector_for_encoder(encoder);
 
        if (connector) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -1109,6 +1226,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
                dp_lane_count = dig_connector->dp_lane_count;
                connector_object_id =
                        (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
+               bpc = connector->display_info.bpc;
        }
 
        memset(&args, 0, sizeof(args));
@@ -1166,7 +1284,27 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
                                args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3;
                                break;
                        }
-                       args.v3.sExtEncoder.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+                       switch (bpc) {
+                       case 0:
+                               args.v3.sExtEncoder.ucBitPerColor = PANEL_BPC_UNDEFINE;
+                               break;
+                       case 6:
+                               args.v3.sExtEncoder.ucBitPerColor = PANEL_6BIT_PER_COLOR;
+                               break;
+                       case 8:
+                       default:
+                               args.v3.sExtEncoder.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+                               break;
+                       case 10:
+                               args.v3.sExtEncoder.ucBitPerColor = PANEL_10BIT_PER_COLOR;
+                               break;
+                       case 12:
+                               args.v3.sExtEncoder.ucBitPerColor = PANEL_12BIT_PER_COLOR;
+                               break;
+                       case 16:
+                               args.v3.sExtEncoder.ucBitPerColor = PANEL_16BIT_PER_COLOR;
+                               break;
+                       }
                        break;
                default:
                        DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
@@ -1294,7 +1432,11 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
        if (is_dig) {
                switch (mode) {
                case DRM_MODE_DPMS_ON:
-                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0);
+                       /* some early dce3.2 boards have a bug in their transmitter control table */
+                       if ((rdev->family == CHIP_RV710) || (rdev->family == CHIP_RV730))
+                               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
+                       else
+                               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0);
                        if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) {
                                struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
 
@@ -1307,9 +1449,11 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
                                                                     ATOM_TRANSMITTER_ACTION_POWER_ON);
                                        radeon_dig_connector->edp_on = true;
                                }
-                               dp_link_train(encoder, connector);
                                if (ASIC_IS_DCE4(rdev))
-                                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON);
+                                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
+                               radeon_dp_link_train(encoder, connector);
+                               if (ASIC_IS_DCE4(rdev))
+                                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0);
                        }
                        if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
                                atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0);
@@ -1322,7 +1466,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
                                struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
 
                                if (ASIC_IS_DCE4(rdev))
-                                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF);
+                                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
                                if (connector &&
                                    (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
                                        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -1383,26 +1527,29 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
        }
 
        if (ext_encoder) {
-               int action;
-
                switch (mode) {
                case DRM_MODE_DPMS_ON:
                default:
-                       if (ASIC_IS_DCE41(rdev))
-                               action = EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT;
-                       else
-                               action = ATOM_ENABLE;
+                       if (ASIC_IS_DCE41(rdev)) {
+                               atombios_external_encoder_setup(encoder, ext_encoder,
+                                                               EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT);
+                               atombios_external_encoder_setup(encoder, ext_encoder,
+                                                               EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING_OFF);
+                       } else
+                               atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE);
                        break;
                case DRM_MODE_DPMS_STANDBY:
                case DRM_MODE_DPMS_SUSPEND:
                case DRM_MODE_DPMS_OFF:
-                       if (ASIC_IS_DCE41(rdev))
-                               action = EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT;
-                       else
-                               action = ATOM_DISABLE;
+                       if (ASIC_IS_DCE41(rdev)) {
+                               atombios_external_encoder_setup(encoder, ext_encoder,
+                                                               EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING);
+                               atombios_external_encoder_setup(encoder, ext_encoder,
+                                                               EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT);
+                       } else
+                               atombios_external_encoder_setup(encoder, ext_encoder, ATOM_DISABLE);
                        break;
                }
-               atombios_external_encoder_setup(encoder, ext_encoder, action);
        }
 
        radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
@@ -1601,12 +1748,9 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
        /* DCE4/5 */
        if (ASIC_IS_DCE4(rdev)) {
                dig = radeon_encoder->enc_priv;
-               if (ASIC_IS_DCE41(rdev)) {
-                       if (dig->linkb)
-                               return 1;
-                       else
-                               return 0;
-               } else {
+               if (ASIC_IS_DCE41(rdev))
+                       return radeon_crtc->crtc_id;
+               else {
                        switch (radeon_encoder->encoder_id) {
                        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
                                if (dig->linkb)
@@ -1662,6 +1806,34 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
        return 1;
 }
 
+/* This only needs to be called once at startup */
+void
+radeon_atom_encoder_init(struct radeon_device *rdev)
+{
+       struct drm_device *dev = rdev->ddev;
+       struct drm_encoder *encoder;
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+               struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder);
+
+               switch (radeon_encoder->encoder_id) {
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+               case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
+                       break;
+               default:
+                       break;
+               }
+
+               if (ext_encoder && ASIC_IS_DCE41(rdev))
+                       atombios_external_encoder_setup(encoder, ext_encoder,
+                                                       EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT);
+       }
+}
+
 static void
 radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
                             struct drm_display_mode *mode,
@@ -1696,19 +1868,17 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
                        /* disable the transmitter */
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
                        /* setup and enable the encoder */
-                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP);
+                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0);
 
-                       /* init and enable the transmitter */
-                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
+                       /* enable the transmitter */
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
                } else {
                        /* disable the encoder and transmitter */
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
-                       atombios_dig_encoder_setup(encoder, ATOM_DISABLE);
+                       atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0);
 
                        /* setup and enable the encoder and transmitter */
-                       atombios_dig_encoder_setup(encoder, ATOM_ENABLE);
-                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
+                       atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0);
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0);
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
                }
@@ -1733,12 +1903,10 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
        }
 
        if (ext_encoder) {
-               if (ASIC_IS_DCE41(rdev)) {
-                       atombios_external_encoder_setup(encoder, ext_encoder,
-                                                       EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT);
+               if (ASIC_IS_DCE41(rdev))
                        atombios_external_encoder_setup(encoder, ext_encoder,
                                                        EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP);
-               else
+               else
                        atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE);
        }
 
@@ -1840,13 +2008,73 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec
        return connector_status_disconnected;
 }
 
+static enum drm_connector_status
+radeon_atom_dig_detect(struct drm_encoder *encoder, struct drm_connector *connector)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder);
+       u32 bios_0_scratch;
+
+       if (!ASIC_IS_DCE4(rdev))
+               return connector_status_unknown;
+
+       if (!ext_encoder)
+               return connector_status_unknown;
+
+       if ((radeon_connector->devices & ATOM_DEVICE_CRT_SUPPORT) == 0)
+               return connector_status_unknown;
+
+       /* load detect on the dp bridge */
+       atombios_external_encoder_setup(encoder, ext_encoder,
+                                       EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION);
+
+       bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH);
+
+       DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices);
+       if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) {
+               if (bios_0_scratch & ATOM_S0_CRT1_MASK)
+                       return connector_status_connected;
+       }
+       if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) {
+               if (bios_0_scratch & ATOM_S0_CRT2_MASK)
+                       return connector_status_connected;
+       }
+       if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) {
+               if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A))
+                       return connector_status_connected;
+       }
+       if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) {
+               if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A))
+                       return connector_status_connected; /* CTV */
+               else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A))
+                       return connector_status_connected; /* STV */
+       }
+       return connector_status_disconnected;
+}
+
+void
+radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder)
+{
+       struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder);
+
+       if (ext_encoder)
+               /* ddc_setup on the dp bridge */
+               atombios_external_encoder_setup(encoder, ext_encoder,
+                                               EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP);
+
+}
+
 static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
 {
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
 
-       if (radeon_encoder->active_device &
-           (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) {
+       if ((radeon_encoder->active_device &
+            (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) ||
+           radeon_encoder_is_dp_bridge(encoder)) {
                struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
                if (dig)
                        dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder);
@@ -1855,11 +2083,17 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
        radeon_atom_output_lock(encoder, true);
        radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
 
-       /* select the clock/data port if it uses a router */
        if (connector) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+
+               /* select the clock/data port if it uses a router */
                if (radeon_connector->router.cd_valid)
                        radeon_router_select_cd_port(radeon_connector);
+
+               /* turn eDP panel on for mode set */
+               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+                       atombios_set_edp_panel_power(connector,
+                                                    ATOM_TRANSMITTER_ACTION_POWER_ON);
        }
 
        /* this is needed for the pll/ss setup to work correctly in some cases */
@@ -1914,7 +2148,7 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
                else {
                        /* disable the encoder and transmitter */
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
-                       atombios_dig_encoder_setup(encoder, ATOM_DISABLE);
+                       atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0);
                }
                break;
        case ENCODER_OBJECT_ID_INTERNAL_DDI:
@@ -1996,7 +2230,7 @@ static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = {
        .mode_set = radeon_atom_encoder_mode_set,
        .commit = radeon_atom_encoder_commit,
        .disable = radeon_atom_encoder_disable,
-       /* no detect for TMDS/LVDS yet */
+       .detect = radeon_atom_dig_detect,
 };
 
 static const struct drm_encoder_helper_funcs radeon_atom_dac_helper_funcs = {
@@ -2116,8 +2350,6 @@ radeon_add_atom_encoder(struct drm_device *dev,
                } else {
                        drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
                        radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
-                       if (ASIC_IS_AVIVO(rdev))
-                               radeon_encoder->underscan_type = UNDERSCAN_AUTO;
                }
                drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
                break;
@@ -2150,8 +2382,6 @@ radeon_add_atom_encoder(struct drm_device *dev,
                } else {
                        drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
                        radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
-                       if (ASIC_IS_AVIVO(rdev))
-                               radeon_encoder->underscan_type = UNDERSCAN_AUTO;
                }
                drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
                break;
index 6f1d9e563e7701f4f6817769e9ea02955ac70f96..ec2f1ea84f81e6c292543aa1e1a56433a19a253f 100644 (file)
@@ -81,6 +81,8 @@ enum radeon_family {
        CHIP_CYPRESS,
        CHIP_HEMLOCK,
        CHIP_PALM,
+       CHIP_SUMO,
+       CHIP_SUMO2,
        CHIP_BARTS,
        CHIP_TURKS,
        CHIP_CAICOS,
index 1f822943657017b3684d6204ae19c76abd95ae6a..021d2b6b556f9e837d2c8a508891c4b6bc19850e 100644 (file)
 #include "radeon.h"
 #include "radeon_trace.h"
 
+static void radeon_fence_write(struct radeon_device *rdev, u32 seq)
+{
+       if (rdev->wb.enabled) {
+               u32 scratch_index;
+               if (rdev->wb.use_event)
+                       scratch_index = R600_WB_EVENT_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base;
+               else
+                       scratch_index = RADEON_WB_SCRATCH_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base;
+               rdev->wb.wb[scratch_index/4] = cpu_to_le32(seq);;
+       } else
+               WREG32(rdev->fence_drv.scratch_reg, seq);
+}
+
+static u32 radeon_fence_read(struct radeon_device *rdev)
+{
+       u32 seq;
+
+       if (rdev->wb.enabled) {
+               u32 scratch_index;
+               if (rdev->wb.use_event)
+                       scratch_index = R600_WB_EVENT_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base;
+               else
+                       scratch_index = RADEON_WB_SCRATCH_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base;
+               seq = le32_to_cpu(rdev->wb.wb[scratch_index/4]);
+       } else
+               seq = RREG32(rdev->fence_drv.scratch_reg);
+       return seq;
+}
+
 int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence)
 {
        unsigned long irq_flags;
@@ -50,12 +79,12 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence)
                return 0;
        }
        fence->seq = atomic_add_return(1, &rdev->fence_drv.seq);
-       if (!rdev->cp.ready) {
+       if (!rdev->cp.ready)
                /* FIXME: cp is not running assume everythings is done right
                 * away
                 */
-               WREG32(rdev->fence_drv.scratch_reg, fence->seq);
-       else
+               radeon_fence_write(rdev, fence->seq);
+       else
                radeon_fence_ring_emit(rdev, fence);
 
        trace_radeon_fence_emit(rdev->ddev, fence->seq);
@@ -73,15 +102,7 @@ static bool radeon_fence_poll_locked(struct radeon_device *rdev)
        bool wake = false;
        unsigned long cjiffies;
 
-       if (rdev->wb.enabled) {
-               u32 scratch_index;
-               if (rdev->wb.use_event)
-                       scratch_index = R600_WB_EVENT_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base;
-               else
-                       scratch_index = RADEON_WB_SCRATCH_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base;
-               seq = le32_to_cpu(rdev->wb.wb[scratch_index/4]);
-       } else
-               seq = RREG32(rdev->fence_drv.scratch_reg);
+       seq = radeon_fence_read(rdev);
        if (seq != rdev->fence_drv.last_seq) {
                rdev->fence_drv.last_seq = seq;
                rdev->fence_drv.last_jiffies = jiffies;
@@ -251,7 +272,7 @@ retry:
                        r = radeon_gpu_reset(rdev);
                        if (r)
                                return r;
-                       WREG32(rdev->fence_drv.scratch_reg, fence->seq);
+                       radeon_fence_write(rdev, fence->seq);
                        rdev->gpu_lockup = false;
                }
                timeout = RADEON_FENCE_JIFFIES_TIMEOUT;
@@ -351,7 +372,7 @@ int radeon_fence_driver_init(struct radeon_device *rdev)
                write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
                return r;
        }
-       WREG32(rdev->fence_drv.scratch_reg, 0);
+       radeon_fence_write(rdev, 0);
        atomic_set(&rdev->fence_drv.seq, 0);
        INIT_LIST_HEAD(&rdev->fence_drv.created);
        INIT_LIST_HEAD(&rdev->fence_drv.emited);
@@ -391,7 +412,7 @@ static int radeon_debugfs_fence_info(struct seq_file *m, void *data)
        struct radeon_fence *fence;
 
        seq_printf(m, "Last signaled fence 0x%08X\n",
-                  RREG32(rdev->fence_drv.scratch_reg));
+                  radeon_fence_read(rdev));
        if (!list_empty(&rdev->fence_drv.emited)) {
                   fence = list_entry(rdev->fence_drv.emited.prev,
                                      struct radeon_fence, list);
index 983cbac75af0159d493c7b81dbe2da1fd90866e6..781196db792f15ff919df30323cf37c5aca4ab63 100644 (file)
@@ -888,6 +888,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
 
        i2c->rec = *rec;
        i2c->adapter.owner = THIS_MODULE;
+       i2c->adapter.class = I2C_CLASS_DDC;
        i2c->dev = dev;
        i2c_set_adapdata(&i2c->adapter, i2c);
        if (rec->mm_i2c ||
@@ -947,6 +948,7 @@ struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev,
 
        i2c->rec = *rec;
        i2c->adapter.owner = THIS_MODULE;
+       i2c->adapter.class = I2C_CLASS_DDC;
        i2c->dev = dev;
        snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
                 "Radeon aux bus %s", name);
index 9c57538231d5f2c9b42c1516797472e149583f04..6df4e3cec0c23cdced34b0da862eddd6d08c2c88 100644 (file)
@@ -464,22 +464,29 @@ radeon_atombios_get_tv_info(struct radeon_device *rdev);
 extern struct drm_connector *
 radeon_get_connector_for_encoder(struct drm_encoder *encoder);
 
+extern bool radeon_encoder_is_dp_bridge(struct drm_encoder *encoder);
+extern bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector);
+extern bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector);
+extern bool radeon_connector_is_dp12_capable(struct drm_connector *connector);
+
 extern void radeon_connector_hotplug(struct drm_connector *connector);
-extern bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector);
-extern int radeon_dp_mode_valid_helper(struct radeon_connector *radeon_connector,
+extern int radeon_dp_mode_valid_helper(struct drm_connector *connector,
                                       struct drm_display_mode *mode);
 extern void radeon_dp_set_link_config(struct drm_connector *connector,
                                      struct drm_display_mode *mode);
-extern void dp_link_train(struct drm_encoder *encoder,
-                         struct drm_connector *connector);
+extern void radeon_dp_link_train(struct drm_encoder *encoder,
+                                struct drm_connector *connector);
 extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
 extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
-extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action);
+extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode);
+extern void radeon_atom_encoder_init(struct radeon_device *rdev);
 extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder,
                                           int action, uint8_t lane_num,
                                           uint8_t lane_set);
+extern void radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder);
+extern struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder);
 extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
-                               uint8_t write_byte, uint8_t *read_byte);
+                               u8 write_byte, u8 *read_byte);
 
 extern void radeon_i2c_init(struct radeon_device *rdev);
 extern void radeon_i2c_fini(struct radeon_device *rdev);
@@ -545,7 +552,7 @@ struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, i
 extern void atombios_dvo_setup(struct drm_encoder *encoder, int action);
 extern void atombios_digital_setup(struct drm_encoder *encoder, int action);
 extern int atombios_get_encoder_mode(struct drm_encoder *encoder);
-extern void atombios_set_edp_panel_power(struct drm_connector *connector, int action);
+extern bool atombios_set_edp_panel_power(struct drm_connector *connector, int action);
 extern void radeon_encoder_set_active_device(struct drm_encoder *encoder);
 
 extern void radeon_crtc_load_lut(struct drm_crtc *crtc);
index 86eda1ea94dfc7a250d7add83ad2b25b8ae0dd76..aaa19dc418a0f0bf194d789592de943d3e5c2dca 100644 (file)
@@ -487,6 +487,7 @@ static int radeon_hwmon_init(struct radeon_device *rdev)
        case THERMAL_TYPE_RV6XX:
        case THERMAL_TYPE_RV770:
        case THERMAL_TYPE_EVERGREEN:
+       case THERMAL_TYPE_NI:
        case THERMAL_TYPE_SUMO:
                rdev->pm.int_hwmon_dev = hwmon_device_register(rdev->dev);
                if (IS_ERR(rdev->pm.int_hwmon_dev)) {
index 92f1900dc7caf10f14dba34edec2e34b721ff09d..ea49752ee99c472a15025efb2335c9a03394ce61 100644 (file)
@@ -758,6 +758,5 @@ r600 0x9400
 0x00009714 VC_ENHANCE
 0x00009830 DB_DEBUG
 0x00009838 DB_WATERMARKS
-0x00028D28 DB_SRESULTS_COMPARE_STATE0
 0x00028D44 DB_ALPHA_TO_MASK
 0x00009700 VC_CNTL
index ef8a5babe9f7679fce662775faa98afb4f1002a2..6f508ffd1035c0814d7096af09d718e9b040ec9a 100644 (file)
@@ -105,6 +105,9 @@ void rv770_pm_misc(struct radeon_device *rdev)
        struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage;
 
        if ((voltage->type == VOLTAGE_SW) && voltage->voltage) {
+               /* 0xff01 is a flag rather then an actual voltage */
+               if (voltage->voltage == 0xff01)
+                       return;
                if (voltage->voltage != rdev->pm.current_vddc) {
                        radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC);
                        rdev->pm.current_vddc = voltage->voltage;
index bf5f83ea14fe19819874311b66618957859286f2..cb1ee4e0050ade2a0da63d4b8cdac714f10c1aff 100644 (file)
@@ -647,9 +647,6 @@ int savage_driver_firstopen(struct drm_device *dev)
        ret = drm_addmap(dev, aperture_base, SAVAGE_APERTURE_SIZE,
                         _DRM_FRAME_BUFFER, _DRM_WRITE_COMBINING,
                         &dev_priv->aperture);
-       if (ret)
-               return ret;
-
        return ret;
 }
 
index 9d9d92945f8c5e515adc87dc40e9f4b1f97427bc..d948575717bf9407c97fd12dd199d7a57c3e0d7f 100644 (file)
@@ -395,12 +395,14 @@ static int ttm_pool_get_num_unused_pages(void)
 /**
  * Callback for mm to request pool to reduce number of page held.
  */
-static int ttm_pool_mm_shrink(struct shrinker *shrink, int shrink_pages, gfp_t gfp_mask)
+static int ttm_pool_mm_shrink(struct shrinker *shrink,
+                             struct shrink_control *sc)
 {
        static atomic_t start_pool = ATOMIC_INIT(0);
        unsigned i;
        unsigned pool_offset = atomic_add_return(1, &start_pool);
        struct ttm_page_pool *pool;
+       int shrink_pages = sc->nr_to_scan;
 
        pool_offset = pool_offset % NUM_POOLS;
        /* select start pool in round robin fashion */
index 498b284e5ef955d11b3ccc3b4a9aaad7bd275df6..58434e804d91c5863c460390addcf10c2530bc29 100644 (file)
@@ -215,7 +215,6 @@ static int vga_switchoff(struct vga_switcheroo_client *client)
 /* stage one happens before delay */
 static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
 {
-       int ret;
        int i;
        struct vga_switcheroo_client *active = NULL;
 
@@ -228,11 +227,6 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
        if (!active)
                return 0;
 
-       /* power up the first device */
-       ret = pci_enable_device(new_client->pdev);
-       if (ret)
-               return ret;
-
        if (new_client->pwr_state == VGA_SWITCHEROO_OFF)
                vga_switchon(new_client);
 
index be8d4cb5861cbce7999a2c09bc7305c1ba3b558f..8a1021f2e319e1f1918fadd25550bf9e1a7c4b84 100644 (file)
@@ -61,7 +61,7 @@ struct vga_device {
        unsigned int mem_lock_cnt;      /* legacy MEM lock count */
        unsigned int io_norm_cnt;       /* normal IO count */
        unsigned int mem_norm_cnt;      /* normal MEM count */
-
+       bool bridge_has_one_vga;
        /* allow IRQ enable/disable hook */
        void *cookie;
        void (*irq_set_state)(void *cookie, bool enable);
@@ -165,6 +165,8 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
        unsigned int wants, legacy_wants, match;
        struct vga_device *conflict;
        unsigned int pci_bits;
+       u32 flags = 0;
+
        /* Account for "normal" resources to lock. If we decode the legacy,
         * counterpart, we need to request it as well
         */
@@ -237,16 +239,23 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
                /* looks like he doesn't have a lock, we can steal
                 * them from him
                 */
-               vga_irq_set_state(conflict, false);
 
+               flags = 0;
                pci_bits = 0;
-               if (lwants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
-                       pci_bits |= PCI_COMMAND_MEMORY;
-               if (lwants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
-                       pci_bits |= PCI_COMMAND_IO;
 
-               pci_set_vga_state(conflict->pdev, false, pci_bits,
-                                 change_bridge);
+               if (!conflict->bridge_has_one_vga) {
+                       vga_irq_set_state(conflict, false);
+                       flags |= PCI_VGA_STATE_CHANGE_DECODES;
+                       if (lwants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
+                               pci_bits |= PCI_COMMAND_MEMORY;
+                       if (lwants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
+                               pci_bits |= PCI_COMMAND_IO;
+               }
+
+               if (change_bridge)
+                       flags |= PCI_VGA_STATE_CHANGE_BRIDGE;
+
+               pci_set_vga_state(conflict->pdev, false, pci_bits, flags);
                conflict->owns &= ~lwants;
                /* If he also owned non-legacy, that is no longer the case */
                if (lwants & VGA_RSRC_LEGACY_MEM)
@@ -261,14 +270,24 @@ enable_them:
         * also have in "decodes". We can lock resources we don't decode but
         * not own them.
         */
+       flags = 0;
        pci_bits = 0;
-       if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
-               pci_bits |= PCI_COMMAND_MEMORY;
-       if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
-               pci_bits |= PCI_COMMAND_IO;
-       pci_set_vga_state(vgadev->pdev, true, pci_bits, !!(wants & VGA_RSRC_LEGACY_MASK));
 
-       vga_irq_set_state(vgadev, true);
+       if (!vgadev->bridge_has_one_vga) {
+               flags |= PCI_VGA_STATE_CHANGE_DECODES;
+               if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
+                       pci_bits |= PCI_COMMAND_MEMORY;
+               if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
+                       pci_bits |= PCI_COMMAND_IO;
+       }
+       if (!!(wants & VGA_RSRC_LEGACY_MASK))
+               flags |= PCI_VGA_STATE_CHANGE_BRIDGE;
+
+       pci_set_vga_state(vgadev->pdev, true, pci_bits, flags);
+
+       if (!vgadev->bridge_has_one_vga) {
+               vga_irq_set_state(vgadev, true);
+       }
        vgadev->owns |= (wants & vgadev->decodes);
 lock_them:
        vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK);
@@ -421,6 +440,62 @@ bail:
 }
 EXPORT_SYMBOL(vga_put);
 
+/* Rules for using a bridge to control a VGA descendant decoding:
+   if a bridge has only one VGA descendant then it can be used
+   to control the VGA routing for that device.
+   It should always use the bridge closest to the device to control it.
+   If a bridge has a direct VGA descendant, but also have a sub-bridge
+   VGA descendant then we cannot use that bridge to control the direct VGA descendant.
+   So for every device we register, we need to iterate all its parent bridges
+   so we can invalidate any devices using them properly.
+*/
+static void vga_arbiter_check_bridge_sharing(struct vga_device *vgadev)
+{
+       struct vga_device *same_bridge_vgadev;
+       struct pci_bus *new_bus, *bus;
+       struct pci_dev *new_bridge, *bridge;
+
+       vgadev->bridge_has_one_vga = true;
+
+       if (list_empty(&vga_list))
+               return;
+
+       /* okay iterate the new devices bridge hierarachy */
+       new_bus = vgadev->pdev->bus;
+       while (new_bus) {
+               new_bridge = new_bus->self;
+
+               if (new_bridge) {
+                       /* go through list of devices already registered */
+                       list_for_each_entry(same_bridge_vgadev, &vga_list, list) {
+                               bus = same_bridge_vgadev->pdev->bus;
+                               bridge = bus->self;
+
+                               /* see if the share a bridge with this device */
+                               if (new_bridge == bridge) {
+                                       /* if their direct parent bridge is the same
+                                          as any bridge of this device then it can't be used
+                                          for that device */
+                                       same_bridge_vgadev->bridge_has_one_vga = false;
+                               }
+
+                               /* now iterate the previous devices bridge hierarchy */
+                               /* if the new devices parent bridge is in the other devices
+                                  hierarchy then we can't use it to control this device */
+                               while (bus) {
+                                       bridge = bus->self;
+                                       if (bridge) {
+                                               if (bridge == vgadev->pdev->bus->self)
+                                                       vgadev->bridge_has_one_vga = false;
+                                       }
+                                       bus = bus->parent;
+                               }
+                       }
+               }
+               new_bus = new_bus->parent;
+       }
+}
+
 /*
  * Currently, we assume that the "initial" setup of the system is
  * not sane, that is we come up with conflicting devices and let
@@ -500,6 +575,8 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
                vga_default = pci_dev_get(pdev);
 #endif
 
+       vga_arbiter_check_bridge_sharing(vgadev);
+
        /* Add to the list */
        list_add(&vgadev->list, &vga_list);
        vga_count++;
@@ -1222,6 +1299,7 @@ static int __init vga_arb_device_init(void)
 {
        int rc;
        struct pci_dev *pdev;
+       struct vga_device *vgadev;
 
        rc = misc_register(&vga_arb_device);
        if (rc < 0)
@@ -1238,6 +1316,13 @@ static int __init vga_arb_device_init(void)
                vga_arbiter_add_pci_device(pdev);
 
        pr_info("vgaarb: loaded\n");
+
+       list_for_each_entry(vgadev, &vga_list, list) {
+               if (vgadev->bridge_has_one_vga)
+                       pr_info("vgaarb: bridge control possible %s\n", pci_name(vgadev->pdev));
+               else
+                       pr_info("vgaarb: no bridge control possible %s\n", pci_name(vgadev->pdev));
+       }
        return rc;
 }
 subsys_initcall(vga_arb_device_init);
index acc39e8ef3e7fab143be3f63d9199a61fa0c17c3..04d5678c29dd2d97e4c35b59ce6a724c09fda159 100644 (file)
@@ -319,6 +319,7 @@ config HID_MULTITOUCH
          - 3M PCT touch screens
          - ActionStar dual touch panels
          - Cando dual touch panels
+         - Chunghwa panels
          - CVTouch panels
          - Cypress TrueTouch panels
          - Elo TouchSystems IntelliTouch Plus panels
@@ -448,6 +449,7 @@ config HID_QUANTA
 config HID_ROCCAT
        tristate "Roccat special event support"
        depends on USB_HID
+       select HID_ROCCAT_COMMON
        ---help---
        Support for Roccat special events.
        Say Y here if you have a Roccat mouse or keyboard and want OSD or
@@ -455,44 +457,40 @@ config HID_ROCCAT
 
 config HID_ROCCAT_COMMON
        tristate
+       depends on HID_ROCCAT
 
 config HID_ROCCAT_ARVO
        tristate "Roccat Arvo keyboard support"
        depends on USB_HID
-       select HID_ROCCAT
-       select HID_ROCCAT_COMMON
+       depends on HID_ROCCAT
        ---help---
        Support for Roccat Arvo keyboard.
 
 config HID_ROCCAT_KONE
        tristate "Roccat Kone Mouse support"
        depends on USB_HID
-       select HID_ROCCAT
-       select HID_ROCCAT_COMMON
+       depends on HID_ROCCAT
        ---help---
        Support for Roccat Kone mouse.
 
 config HID_ROCCAT_KONEPLUS
        tristate "Roccat Kone[+] mouse support"
        depends on USB_HID
-       select HID_ROCCAT
-       select HID_ROCCAT_COMMON
+       depends on HID_ROCCAT
        ---help---
        Support for Roccat Kone[+] mouse.
 
 config HID_ROCCAT_KOVAPLUS
        tristate "Roccat Kova[+] mouse support"
        depends on USB_HID
-       select HID_ROCCAT
-       select HID_ROCCAT_COMMON
+       depends on HID_ROCCAT
        ---help---
        Support for Roccat Kova[+] mouse.
 
 config HID_ROCCAT_PYRA
        tristate "Roccat Pyra mouse support"
        depends on USB_HID
-       select HID_ROCCAT
-       select HID_ROCCAT_COMMON
+       depends on HID_ROCCAT
        ---help---
        Support for Roccat Pyra mouse.
 
@@ -587,6 +585,12 @@ config HID_WACOM_POWER_SUPPLY
          Say Y here if you want to enable power supply status monitoring for
          Wacom Bluetooth devices.
 
+config HID_WIIMOTE
+       tristate "Nintendo Wii Remote support"
+       depends on BT_HIDP
+       ---help---
+       Support for the Nintendo Wii Remote bluetooth device.
+
 config HID_ZEROPLUS
        tristate "Zeroplus based game controller support"
        depends on USB_HID
index 21dea54b448201b472bb62a76ab6d104734801bc..0a0a38e9fd28477d1bae9a2a778bcf889d4289ba 100644 (file)
@@ -75,6 +75,7 @@ obj-$(CONFIG_HID_ZEROPLUS)    += hid-zpff.o
 obj-$(CONFIG_HID_ZYDACRON)     += hid-zydacron.o
 obj-$(CONFIG_HID_WACOM)                += hid-wacom.o
 obj-$(CONFIG_HID_WALTOP)       += hid-waltop.o
+obj-$(CONFIG_HID_WIIMOTE)      += hid-wiimote.o
 
 obj-$(CONFIG_USB_HID)          += usbhid/
 obj-$(CONFIG_USB_MOUSE)                += usbhid/
index 2a268fc4db9a44e51b05f72c34d9e3a955ab3403..3d3a58a46326f3c91a32304d3d3eea1c65c98a8f 100644 (file)
@@ -1359,6 +1359,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
@@ -1423,6 +1424,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH_DUAL) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
@@ -1506,6 +1508,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
 
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
        { }
 };
 
index 8c00e4a261a938c64a5ee715bea80946f8788bbc..f18a22cd23042799bca2b7fc8872886f0239367e 100644 (file)
 #define USB_DEVICE_ID_CHICONY_MULTI_TOUCH      0xb19d
 #define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618
 
+#define USB_VENDOR_ID_CHUNGHWAT                0x2247
+#define USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH     0x0001
+
 #define USB_VENDOR_ID_CIDC             0x1677
 
 #define USB_VENDOR_ID_CMEDIA           0x0d8c
 
 #define USB_VENDOR_ID_LUMIO            0x202e
 #define USB_DEVICE_ID_CRYSTALTOUCH     0x0006
+#define USB_DEVICE_ID_CRYSTALTOUCH_DUAL        0x0007
 
 #define USB_VENDOR_ID_MCC              0x09db
 #define USB_DEVICE_ID_MCC_PMD1024LS    0x0076
 #define USB_VENDOR_ID_NEXTWINDOW       0x1926
 #define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN   0x0003
 
+#define USB_VENDOR_ID_NINTENDO         0x057e
+#define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306
+
 #define USB_VENDOR_ID_NTRIG            0x1b96
 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN   0x0001
 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1   0x0003
 #define USB_VENDOR_ID_UCLOGIC          0x5543
 #define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209    0x0042
 #define USB_DEVICE_ID_UCLOGIC_TABLET_KNA5      0x6001
+#define USB_DEVICE_ID_UCLOGIC_TABLET_TWA60     0x0064
 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U   0x0003
 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U   0x0004
 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U   0x0005
index a5eda4c8127a274ee20343d26a82383135c3048b..0ec91c18a4216a52a4a3c7d85292a22f61a6e828 100644 (file)
@@ -501,17 +501,9 @@ static int magicmouse_probe(struct hid_device *hdev,
        }
        report->size = 6;
 
-       /*
-        * The device reponds with 'invalid report id' when feature
-        * report switching it into multitouch mode is sent to it.
-        *
-        * This results in -EIO from the _raw low-level transport callback,
-        * but there seems to be no other way of switching the mode.
-        * Thus the super-ugly hacky success check below.
-        */
        ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature),
                        HID_FEATURE_REPORT);
-       if (ret != -EIO) {
+       if (ret != sizeof(feature)) {
                hid_err(hdev, "unable to request touch data (%d)\n", ret);
                goto err_stop_hw;
        }
index ecd4d2db9e800ca2397c3ad18945d30b2080a028..62cac4dc3b627c6bb598a77ce0c1cb78eee62be5 100644 (file)
@@ -64,6 +64,7 @@ struct mt_device {
        struct mt_class *mtclass;       /* our mt device class */
        unsigned last_field_index;      /* last field index of the report */
        unsigned last_slot_field;       /* the last field of a slot */
+       int last_mt_collection; /* last known mt-related collection */
        __s8 inputmode;         /* InputMode HID feature, -1 if non-existent */
        __u8 num_received;      /* how many contacts we received */
        __u8 num_expected;      /* expected last contact index */
@@ -225,8 +226,10 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                                cls->sn_move);
                        /* touchscreen emulation */
                        set_abs(hi->input, ABS_X, field, cls->sn_move);
-                       td->last_slot_field = usage->hid;
-                       td->last_field_index = field->index;
+                       if (td->last_mt_collection == usage->collection_index) {
+                               td->last_slot_field = usage->hid;
+                               td->last_field_index = field->index;
+                       }
                        return 1;
                case HID_GD_Y:
                        if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP)
@@ -237,8 +240,10 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                                cls->sn_move);
                        /* touchscreen emulation */
                        set_abs(hi->input, ABS_Y, field, cls->sn_move);
-                       td->last_slot_field = usage->hid;
-                       td->last_field_index = field->index;
+                       if (td->last_mt_collection == usage->collection_index) {
+                               td->last_slot_field = usage->hid;
+                               td->last_field_index = field->index;
+                       }
                        return 1;
                }
                return 0;
@@ -246,31 +251,42 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
        case HID_UP_DIGITIZER:
                switch (usage->hid) {
                case HID_DG_INRANGE:
-                       td->last_slot_field = usage->hid;
-                       td->last_field_index = field->index;
+                       if (td->last_mt_collection == usage->collection_index) {
+                               td->last_slot_field = usage->hid;
+                               td->last_field_index = field->index;
+                       }
                        return 1;
                case HID_DG_CONFIDENCE:
-                       td->last_slot_field = usage->hid;
-                       td->last_field_index = field->index;
+                       if (td->last_mt_collection == usage->collection_index) {
+                               td->last_slot_field = usage->hid;
+                               td->last_field_index = field->index;
+                       }
                        return 1;
                case HID_DG_TIPSWITCH:
                        hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
                        input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
-                       td->last_slot_field = usage->hid;
-                       td->last_field_index = field->index;
+                       if (td->last_mt_collection == usage->collection_index) {
+                               td->last_slot_field = usage->hid;
+                               td->last_field_index = field->index;
+                       }
                        return 1;
                case HID_DG_CONTACTID:
+                       if (!td->maxcontacts)
+                               td->maxcontacts = MT_DEFAULT_MAXCONTACT;
                        input_mt_init_slots(hi->input, td->maxcontacts);
                        td->last_slot_field = usage->hid;
                        td->last_field_index = field->index;
+                       td->last_mt_collection = usage->collection_index;
                        return 1;
                case HID_DG_WIDTH:
                        hid_map_usage(hi, usage, bit, max,
                                        EV_ABS, ABS_MT_TOUCH_MAJOR);
                        set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
                                cls->sn_width);
-                       td->last_slot_field = usage->hid;
-                       td->last_field_index = field->index;
+                       if (td->last_mt_collection == usage->collection_index) {
+                               td->last_slot_field = usage->hid;
+                               td->last_field_index = field->index;
+                       }
                        return 1;
                case HID_DG_HEIGHT:
                        hid_map_usage(hi, usage, bit, max,
@@ -279,8 +295,10 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                                cls->sn_height);
                        input_set_abs_params(hi->input,
                                        ABS_MT_ORIENTATION, 0, 1, 0, 0);
-                       td->last_slot_field = usage->hid;
-                       td->last_field_index = field->index;
+                       if (td->last_mt_collection == usage->collection_index) {
+                               td->last_slot_field = usage->hid;
+                               td->last_field_index = field->index;
+                       }
                        return 1;
                case HID_DG_TIPPRESSURE:
                        if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP)
@@ -292,16 +310,20 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                        /* touchscreen emulation */
                        set_abs(hi->input, ABS_PRESSURE, field,
                                cls->sn_pressure);
-                       td->last_slot_field = usage->hid;
-                       td->last_field_index = field->index;
+                       if (td->last_mt_collection == usage->collection_index) {
+                               td->last_slot_field = usage->hid;
+                               td->last_field_index = field->index;
+                       }
                        return 1;
                case HID_DG_CONTACTCOUNT:
-                       td->last_field_index = field->index;
+                       if (td->last_mt_collection == usage->collection_index)
+                               td->last_field_index = field->index;
                        return 1;
                case HID_DG_CONTACTMAX:
                        /* we don't set td->last_slot_field as contactcount and
                         * contact max are global to the report */
-                       td->last_field_index = field->index;
+                       if (td->last_mt_collection == usage->collection_index)
+                               td->last_field_index = field->index;
                        return -1;
                }
                /* let hid-input decide for the others */
@@ -516,6 +538,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        }
        td->mtclass = mtclass;
        td->inputmode = -1;
+       td->last_mt_collection = -1;
        hid_set_drvdata(hdev, td);
 
        ret = hid_parse(hdev);
@@ -526,9 +549,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        if (ret)
                goto fail;
 
-       if (!td->maxcontacts)
-               td->maxcontacts = MT_DEFAULT_MAXCONTACT;
-
        td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot),
                                GFP_KERNEL);
        if (!td->slots) {
@@ -593,6 +613,11 @@ static const struct hid_device_id mt_devices[] = {
                HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
                        USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
 
+       /* Chunghwa Telecom touch panels */
+       {  .driver_data = MT_CLS_DEFAULT,
+               HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
+                       USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
+
        /* CVTouch panels */
        { .driver_data = MT_CLS_DEFAULT,
                HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
@@ -651,6 +676,9 @@ static const struct hid_device_id mt_devices[] = {
        { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
                HID_USB_DEVICE(USB_VENDOR_ID_LUMIO,
                        USB_DEVICE_ID_CRYSTALTOUCH) },
+       { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
+               HID_USB_DEVICE(USB_VENDOR_ID_LUMIO,
+                       USB_DEVICE_ID_CRYSTALTOUCH_DUAL) },
 
        /* MosArt panels */
        { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
@@ -681,10 +709,10 @@ static const struct hid_device_id mt_devices[] = {
                HID_USB_DEVICE(USB_VENDOR_ID_STANTUM,
                        USB_DEVICE_ID_MTP)},
        { .driver_data = MT_CLS_CONFIDENCE,
-               HID_USB_DEVICE(USB_VENDOR_ID_STANTUM,
+               HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
                        USB_DEVICE_ID_MTP_STM)},
        { .driver_data = MT_CLS_CONFIDENCE,
-               HID_USB_DEVICE(USB_VENDOR_ID_STANTUM,
+               HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX,
                        USB_DEVICE_ID_MTP_SITRONIX)},
 
        /* Touch International panels */
index 2307471d96dc994914e19ea16e860f7e3dcaa75e..093bfad00b023d8a22a6bf17c382f4eef311b7ce 100644 (file)
@@ -39,7 +39,7 @@ static ssize_t arvo_sysfs_show_mode_key(struct device *dev,
        int retval;
 
        mutex_lock(&arvo->arvo_lock);
-       retval = roccat_common_receive(usb_dev, ARVO_USB_COMMAND_MODE_KEY,
+       retval = roccat_common_receive(usb_dev, ARVO_COMMAND_MODE_KEY,
                        &temp_buf, sizeof(struct arvo_mode_key));
        mutex_unlock(&arvo->arvo_lock);
        if (retval)
@@ -67,7 +67,7 @@ static ssize_t arvo_sysfs_set_mode_key(struct device *dev,
        temp_buf.state = state;
 
        mutex_lock(&arvo->arvo_lock);
-       retval = roccat_common_send(usb_dev, ARVO_USB_COMMAND_MODE_KEY,
+       retval = roccat_common_send(usb_dev, ARVO_COMMAND_MODE_KEY,
                        &temp_buf, sizeof(struct arvo_mode_key));
        mutex_unlock(&arvo->arvo_lock);
        if (retval)
@@ -87,7 +87,7 @@ static ssize_t arvo_sysfs_show_key_mask(struct device *dev,
        int retval;
 
        mutex_lock(&arvo->arvo_lock);
-       retval = roccat_common_receive(usb_dev, ARVO_USB_COMMAND_KEY_MASK,
+       retval = roccat_common_receive(usb_dev, ARVO_COMMAND_KEY_MASK,
                        &temp_buf, sizeof(struct arvo_key_mask));
        mutex_unlock(&arvo->arvo_lock);
        if (retval)
@@ -115,7 +115,7 @@ static ssize_t arvo_sysfs_set_key_mask(struct device *dev,
        temp_buf.key_mask = key_mask;
 
        mutex_lock(&arvo->arvo_lock);
-       retval = roccat_common_send(usb_dev, ARVO_USB_COMMAND_KEY_MASK,
+       retval = roccat_common_send(usb_dev, ARVO_COMMAND_KEY_MASK,
                        &temp_buf, sizeof(struct arvo_key_mask));
        mutex_unlock(&arvo->arvo_lock);
        if (retval)
@@ -130,7 +130,7 @@ static int arvo_get_actual_profile(struct usb_device *usb_dev)
        struct arvo_actual_profile temp_buf;
        int retval;
 
-       retval = roccat_common_receive(usb_dev, ARVO_USB_COMMAND_ACTUAL_PROFILE,
+       retval = roccat_common_receive(usb_dev, ARVO_COMMAND_ACTUAL_PROFILE,
                        &temp_buf, sizeof(struct arvo_actual_profile));
 
        if (retval)
@@ -163,11 +163,14 @@ static ssize_t arvo_sysfs_set_actual_profile(struct device *dev,
        if (retval)
                return retval;
 
+       if (profile < 1 || profile > 5)
+               return -EINVAL;
+
        temp_buf.command = ARVO_COMMAND_ACTUAL_PROFILE;
        temp_buf.actual_profile = profile;
 
        mutex_lock(&arvo->arvo_lock);
-       retval = roccat_common_send(usb_dev, ARVO_USB_COMMAND_ACTUAL_PROFILE,
+       retval = roccat_common_send(usb_dev, ARVO_COMMAND_ACTUAL_PROFILE,
                        &temp_buf, sizeof(struct arvo_actual_profile));
        if (!retval) {
                arvo->actual_profile = profile;
@@ -225,7 +228,7 @@ static ssize_t arvo_sysfs_write_button(struct file *fp,
                loff_t off, size_t count)
 {
        return arvo_sysfs_write(fp, kobj, buf, off, count,
-                       sizeof(struct arvo_button), ARVO_USB_COMMAND_BUTTON);
+                       sizeof(struct arvo_button), ARVO_COMMAND_BUTTON);
 }
 
 static ssize_t arvo_sysfs_read_info(struct file *fp,
@@ -233,7 +236,7 @@ static ssize_t arvo_sysfs_read_info(struct file *fp,
                loff_t off, size_t count)
 {
        return arvo_sysfs_read(fp, kobj, buf, off, count,
-                       sizeof(struct arvo_info), ARVO_USB_COMMAND_INFO);
+                       sizeof(struct arvo_info), ARVO_COMMAND_INFO);
 }
 
 
@@ -399,7 +402,7 @@ static int arvo_raw_event(struct hid_device *hdev,
        if (size != 3)
                return 0;
 
-       if (arvo->roccat_claimed)
+       if (arvo && arvo->roccat_claimed)
                arvo_report_to_chrdev(arvo, data);
 
        return 0;
index d284a781c99e407a9b2abacfeaa4cf3359c45931..ce8415e4f009a4505d4117339045c141f5509ba7 100644 (file)
@@ -46,19 +46,6 @@ enum arvo_commands {
        ARVO_COMMAND_ACTUAL_PROFILE = 0x7,
 };
 
-enum arvo_usb_commands {
-       ARVO_USB_COMMAND_MODE_KEY = 0x303,
-       /*
-        * read/write
-        * Read uses both index bytes as profile/key indexes
-        * Write has index 0, profile/key is determined by payload
-        */
-       ARVO_USB_COMMAND_BUTTON = 0x304,
-       ARVO_USB_COMMAND_INFO = 0x305,
-       ARVO_USB_COMMAND_KEY_MASK = 0x306,
-       ARVO_USB_COMMAND_ACTUAL_PROFILE = 0x307,
-};
-
 struct arvo_special_report {
        uint8_t unknown1; /* always 0x01 */
        uint8_t event;
index 13b1eb0c8c65f932993db85c3885e71d9a2074aa..edf898dee28bd177a0e7c4fc7a40971aee72e457 100644 (file)
  * any later version.
  */
 
+#include <linux/hid.h>
 #include <linux/slab.h>
 #include "hid-roccat-common.h"
 
-int roccat_common_receive(struct usb_device *usb_dev, uint usb_command,
+static inline uint16_t roccat_common_feature_report(uint8_t report_id)
+{
+       return 0x300 | report_id;
+}
+
+int roccat_common_receive(struct usb_device *usb_dev, uint report_id,
                void *data, uint size)
 {
        char *buf;
@@ -25,9 +31,10 @@ int roccat_common_receive(struct usb_device *usb_dev, uint usb_command,
                return -ENOMEM;
 
        len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
-                       USB_REQ_CLEAR_FEATURE,
+                       HID_REQ_GET_REPORT,
                        USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
-                       usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
+                       roccat_common_feature_report(report_id),
+                       0, buf, size, USB_CTRL_SET_TIMEOUT);
 
        memcpy(data, buf, size);
        kfree(buf);
@@ -35,7 +42,7 @@ int roccat_common_receive(struct usb_device *usb_dev, uint usb_command,
 }
 EXPORT_SYMBOL_GPL(roccat_common_receive);
 
-int roccat_common_send(struct usb_device *usb_dev, uint usb_command,
+int roccat_common_send(struct usb_device *usb_dev, uint report_id,
                void const *data, uint size)
 {
        char *buf;
@@ -48,9 +55,10 @@ int roccat_common_send(struct usb_device *usb_dev, uint usb_command,
        memcpy(buf, data, size);
 
        len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
-                       USB_REQ_SET_CONFIGURATION,
+                       HID_REQ_SET_REPORT,
                        USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
-                       usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
+                       roccat_common_feature_report(report_id),
+                       0, buf, size, USB_CTRL_SET_TIMEOUT);
 
        kfree(buf);
        return ((len < 0) ? len : ((len != size) ? -EIO : 0));
index fe45fae05bb9fc51db04ec7e86b080efb563a983..9a5bc61f9699785faf4daa754256b44eec8abb2c 100644 (file)
@@ -15,9 +15,9 @@
 #include <linux/usb.h>
 #include <linux/types.h>
 
-int roccat_common_receive(struct usb_device *usb_dev, uint usb_command,
+int roccat_common_receive(struct usb_device *usb_dev, uint report_id,
                void *data, uint size);
-int roccat_common_send(struct usb_device *usb_dev, uint usb_command,
+int roccat_common_send(struct usb_device *usb_dev, uint report_id,
                void const *data, uint size);
 
 #endif
index a57838d152673d76264e48d46c801f3065c78471..2b8f3a31ffb314aa814e560d6fa7c221c9c3035a 100644 (file)
 
 static uint profile_numbers[5] = {0, 1, 2, 3, 4};
 
+static int kone_receive(struct usb_device *usb_dev, uint usb_command,
+               void *data, uint size)
+{
+       char *buf;
+       int len;
+
+       buf = kmalloc(size, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+                       HID_REQ_GET_REPORT,
+                       USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+                       usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
+
+       memcpy(data, buf, size);
+       kfree(buf);
+       return ((len < 0) ? len : ((len != size) ? -EIO : 0));
+}
+
+static int kone_send(struct usb_device *usb_dev, uint usb_command,
+               void const *data, uint size)
+{
+       char *buf;
+       int len;
+
+       buf = kmalloc(size, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       memcpy(buf, data, size);
+
+       len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+                       HID_REQ_SET_REPORT,
+                       USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                       usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
+
+       kfree(buf);
+       return ((len < 0) ? len : ((len != size) ? -EIO : 0));
+}
+
 /* kone_class is used for creating sysfs attributes via roccat char device */
 static struct class *kone_class;
 
@@ -68,7 +109,7 @@ static int kone_check_write(struct usb_device *usb_dev)
                 */
                msleep(80);
 
-               retval = roccat_common_receive(usb_dev,
+               retval = kone_receive(usb_dev,
                                kone_command_confirm_write, &data, 1);
                if (retval)
                        return retval;
@@ -96,7 +137,7 @@ static int kone_check_write(struct usb_device *usb_dev)
 static int kone_get_settings(struct usb_device *usb_dev,
                struct kone_settings *buf)
 {
-       return roccat_common_receive(usb_dev, kone_command_settings, buf,
+       return kone_receive(usb_dev, kone_command_settings, buf,
                        sizeof(struct kone_settings));
 }
 
@@ -109,7 +150,7 @@ static int kone_set_settings(struct usb_device *usb_dev,
                struct kone_settings const *settings)
 {
        int retval;
-       retval = roccat_common_send(usb_dev, kone_command_settings,
+       retval = kone_send(usb_dev, kone_command_settings,
                        settings, sizeof(struct kone_settings));
        if (retval)
                return retval;
@@ -182,7 +223,7 @@ static int kone_get_weight(struct usb_device *usb_dev, int *result)
        int retval;
        uint8_t data;
 
-       retval = roccat_common_receive(usb_dev, kone_command_weight, &data, 1);
+       retval = kone_receive(usb_dev, kone_command_weight, &data, 1);
 
        if (retval)
                return retval;
@@ -201,7 +242,7 @@ static int kone_get_firmware_version(struct usb_device *usb_dev, int *result)
        int retval;
        uint16_t data;
 
-       retval = roccat_common_receive(usb_dev, kone_command_firmware_version,
+       retval = kone_receive(usb_dev, kone_command_firmware_version,
                        &data, 2);
        if (retval)
                return retval;
@@ -384,7 +425,7 @@ static int kone_tcu_command(struct usb_device *usb_dev, int number)
 {
        unsigned char value;
        value = number;
-       return roccat_common_send(usb_dev, kone_command_calibrate, &value, 1);
+       return kone_send(usb_dev, kone_command_calibrate, &value, 1);
 }
 
 /*
@@ -791,6 +832,9 @@ static int kone_raw_event(struct hid_device *hdev, struct hid_report *report,
        if (size != sizeof(struct kone_mouse_event))
                return 0;
 
+       if (kone == NULL)
+               return 0;
+
        /*
         * Firmware 1.38 introduced new behaviour for tilt and special buttons.
         * Pressed button is reported in each movement event.
index 4109a028e138be2317c7510d2daefb26d7bb86e3..64abb5b8a59a5909a759f3ef37e232a8991fb902 100644 (file)
@@ -166,7 +166,7 @@ enum kone_mouse_events {
        /* osd events are thought to be display on screen */
        kone_mouse_event_osd_dpi = 0xa0,
        kone_mouse_event_osd_profile = 0xb0,
-       /* TODO clarify meaning and occurrence of kone_mouse_event_calibration */
+       /* TODO clarify meaning and occurence of kone_mouse_event_calibration */
        kone_mouse_event_calibration = 0xc0,
        kone_mouse_event_call_overlong_macro = 0xe0,
        /* switch events notify if user changed values with mousebutton click */
index 5b640a7a15a72857e1d7705d8a819b21edc72063..59e47770fa1036aeaf72c145eadb9d8804bb33d8 100644 (file)
@@ -50,7 +50,7 @@ static int koneplus_send_control(struct usb_device *usb_dev, uint value,
        control.value = value;
        control.request = request;
 
-       return roccat_common_send(usb_dev, KONEPLUS_USB_COMMAND_CONTROL,
+       return roccat_common_send(usb_dev, KONEPLUS_COMMAND_CONTROL,
                        &control, sizeof(struct koneplus_control));
 }
 
@@ -60,7 +60,7 @@ static int koneplus_receive_control_status(struct usb_device *usb_dev)
        struct koneplus_control control;
 
        do {
-               retval = roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_CONTROL,
+               retval = roccat_common_receive(usb_dev, KONEPLUS_COMMAND_CONTROL,
                                &control, sizeof(struct koneplus_control));
 
                /* check if we get a completely wrong answer */
@@ -120,7 +120,7 @@ static int koneplus_select_profile(struct usb_device *usb_dev, uint number,
 static int koneplus_get_info(struct usb_device *usb_dev,
                struct koneplus_info *buf)
 {
-       return roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_INFO,
+       return roccat_common_receive(usb_dev, KONEPLUS_COMMAND_INFO,
                        buf, sizeof(struct koneplus_info));
 }
 
@@ -134,14 +134,14 @@ static int koneplus_get_profile_settings(struct usb_device *usb_dev,
        if (retval)
                return retval;
 
-       return roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS,
+       return roccat_common_receive(usb_dev, KONEPLUS_COMMAND_PROFILE_SETTINGS,
                        buf, sizeof(struct koneplus_profile_settings));
 }
 
 static int koneplus_set_profile_settings(struct usb_device *usb_dev,
                struct koneplus_profile_settings const *settings)
 {
-       return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS,
+       return koneplus_send(usb_dev, KONEPLUS_COMMAND_PROFILE_SETTINGS,
                        settings, sizeof(struct koneplus_profile_settings));
 }
 
@@ -155,14 +155,14 @@ static int koneplus_get_profile_buttons(struct usb_device *usb_dev,
        if (retval)
                return retval;
 
-       return roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS,
+       return roccat_common_receive(usb_dev, KONEPLUS_COMMAND_PROFILE_BUTTONS,
                        buf, sizeof(struct koneplus_profile_buttons));
 }
 
 static int koneplus_set_profile_buttons(struct usb_device *usb_dev,
                struct koneplus_profile_buttons const *buttons)
 {
-       return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS,
+       return koneplus_send(usb_dev, KONEPLUS_COMMAND_PROFILE_BUTTONS,
                        buttons, sizeof(struct koneplus_profile_buttons));
 }
 
@@ -172,7 +172,7 @@ static int koneplus_get_actual_profile(struct usb_device *usb_dev)
        struct koneplus_actual_profile buf;
        int retval;
 
-       retval = roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_ACTUAL_PROFILE,
+       retval = roccat_common_receive(usb_dev, KONEPLUS_COMMAND_ACTUAL_PROFILE,
                        &buf, sizeof(struct koneplus_actual_profile));
 
        return retval ? retval : buf.actual_profile;
@@ -187,7 +187,7 @@ static int koneplus_set_actual_profile(struct usb_device *usb_dev,
        buf.size = sizeof(struct koneplus_actual_profile);
        buf.actual_profile = new_profile;
 
-       return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_ACTUAL_PROFILE,
+       return koneplus_send(usb_dev, KONEPLUS_COMMAND_ACTUAL_PROFILE,
                        &buf, sizeof(struct koneplus_actual_profile));
 }
 
@@ -240,12 +240,20 @@ static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj,
        return real_size;
 }
 
+static ssize_t koneplus_sysfs_write_talk(struct file *fp,
+               struct kobject *kobj, struct bin_attribute *attr, char *buf,
+               loff_t off, size_t count)
+{
+       return koneplus_sysfs_write(fp, kobj, buf, off, count,
+                       sizeof(struct koneplus_talk), KONEPLUS_COMMAND_TALK);
+}
+
 static ssize_t koneplus_sysfs_write_macro(struct file *fp,
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
                loff_t off, size_t count)
 {
        return koneplus_sysfs_write(fp, kobj, buf, off, count,
-                       sizeof(struct koneplus_macro), KONEPLUS_USB_COMMAND_MACRO);
+                       sizeof(struct koneplus_macro), KONEPLUS_COMMAND_MACRO);
 }
 
 static ssize_t koneplus_sysfs_read_sensor(struct file *fp,
@@ -253,7 +261,7 @@ static ssize_t koneplus_sysfs_read_sensor(struct file *fp,
                loff_t off, size_t count)
 {
        return koneplus_sysfs_read(fp, kobj, buf, off, count,
-                       sizeof(struct koneplus_sensor), KONEPLUS_USB_COMMAND_SENSOR);
+                       sizeof(struct koneplus_sensor), KONEPLUS_COMMAND_SENSOR);
 }
 
 static ssize_t koneplus_sysfs_write_sensor(struct file *fp,
@@ -261,7 +269,7 @@ static ssize_t koneplus_sysfs_write_sensor(struct file *fp,
                loff_t off, size_t count)
 {
        return koneplus_sysfs_write(fp, kobj, buf, off, count,
-                       sizeof(struct koneplus_sensor), KONEPLUS_USB_COMMAND_SENSOR);
+                       sizeof(struct koneplus_sensor), KONEPLUS_COMMAND_SENSOR);
 }
 
 static ssize_t koneplus_sysfs_write_tcu(struct file *fp,
@@ -269,7 +277,7 @@ static ssize_t koneplus_sysfs_write_tcu(struct file *fp,
                loff_t off, size_t count)
 {
        return koneplus_sysfs_write(fp, kobj, buf, off, count,
-                       sizeof(struct koneplus_tcu), KONEPLUS_USB_COMMAND_TCU);
+                       sizeof(struct koneplus_tcu), KONEPLUS_COMMAND_TCU);
 }
 
 static ssize_t koneplus_sysfs_read_tcu_image(struct file *fp,
@@ -277,7 +285,7 @@ static ssize_t koneplus_sysfs_read_tcu_image(struct file *fp,
                loff_t off, size_t count)
 {
        return koneplus_sysfs_read(fp, kobj, buf, off, count,
-                       sizeof(struct koneplus_tcu_image), KONEPLUS_USB_COMMAND_TCU);
+                       sizeof(struct koneplus_tcu_image), KONEPLUS_COMMAND_TCU);
 }
 
 static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp,
@@ -423,6 +431,9 @@ static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev,
        if (retval)
                return retval;
 
+       if (profile > 4)
+               return -EINVAL;
+
        mutex_lock(&koneplus->koneplus_lock);
 
        retval = koneplus_set_actual_profile(usb_dev, profile);
@@ -431,7 +442,7 @@ static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev,
                return retval;
        }
 
-       koneplus->actual_profile = profile;
+       koneplus_profile_activated(koneplus, profile);
 
        roccat_report.type = KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE;
        roccat_report.data1 = profile + 1;
@@ -557,6 +568,11 @@ static struct bin_attribute koneplus_bin_attributes[] = {
                .size = sizeof(struct koneplus_macro),
                .write = koneplus_sysfs_write_macro
        },
+       {
+               .attr = { .name = "talk", .mode = 0220 },
+               .size = sizeof(struct koneplus_talk),
+               .write = koneplus_sysfs_write_talk
+       },
        __ATTR_NULL
 };
 
@@ -738,6 +754,9 @@ static int koneplus_raw_event(struct hid_device *hdev,
                        != USB_INTERFACE_PROTOCOL_MOUSE)
                return 0;
 
+       if (koneplus == NULL)
+               return 0;
+
        koneplus_keep_values_up_to_date(koneplus, data);
 
        if (koneplus->roccat_claimed)
index c57a376ab8aed31cea2580bafd47ef4fe4f9749c..c03332a4fa9aeb07ddf30ecf6071c8a8dcc1fb9f 100644 (file)
 
 #include <linux/types.h>
 
+struct koneplus_talk {
+       uint8_t command; /* KONEPLUS_COMMAND_TALK */
+       uint8_t size; /* always 0x10 */
+       uint8_t data[14];
+} __packed;
+
 /*
  * case 1: writes request 80 and reads value 1
  *
@@ -137,26 +143,14 @@ enum koneplus_commands {
        KONEPLUS_COMMAND_PROFILE_BUTTONS = 0x7,
        KONEPLUS_COMMAND_MACRO = 0x8,
        KONEPLUS_COMMAND_INFO = 0x9,
+       KONEPLUS_COMMAND_TCU = 0xc,
        KONEPLUS_COMMAND_E = 0xe,
        KONEPLUS_COMMAND_SENSOR = 0xf,
+       KONEPLUS_COMMAND_TALK = 0x10,
        KONEPLUS_COMMAND_FIRMWARE_WRITE = 0x1b,
        KONEPLUS_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c,
 };
 
-enum koneplus_usb_commands {
-       KONEPLUS_USB_COMMAND_CONTROL = 0x304,
-       KONEPLUS_USB_COMMAND_ACTUAL_PROFILE = 0x305,
-       KONEPLUS_USB_COMMAND_PROFILE_SETTINGS = 0x306,
-       KONEPLUS_USB_COMMAND_PROFILE_BUTTONS = 0x307,
-       KONEPLUS_USB_COMMAND_MACRO = 0x308,
-       KONEPLUS_USB_COMMAND_INFO = 0x309,
-       KONEPLUS_USB_COMMAND_TCU = 0x30c,
-       KONEPLUS_USB_COMMAND_E = 0x30e,
-       KONEPLUS_USB_COMMAND_SENSOR = 0x30f,
-       KONEPLUS_USB_COMMAND_FIRMWARE_WRITE = 0x31b,
-       KONEPLUS_USB_COMMAND_FIRMWARE_WRITE_CONTROL = 0x31c,
-};
-
 enum koneplus_mouse_report_numbers {
        KONEPLUS_MOUSE_REPORT_NUMBER_HID = 1,
        KONEPLUS_MOUSE_REPORT_NUMBER_AUDIO = 2,
@@ -193,6 +187,7 @@ enum koneplus_mouse_report_button_types {
         * data2 = action
         */
        KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_MULTIMEDIA = 0xf0,
+       KONEPLUS_MOUSE_REPORT_TALK = 0xff,
 };
 
 enum koneplus_mouse_report_button_action {
index 984be2f8967e719dfa31e2d1887eb9d4e1bf1f55..1f8336e3f584ab270d1519063dffc79c99f9e6c3 100644 (file)
@@ -58,7 +58,7 @@ static int kovaplus_send_control(struct usb_device *usb_dev, uint value,
        control.value = value;
        control.request = request;
 
-       retval = roccat_common_send(usb_dev, KOVAPLUS_USB_COMMAND_CONTROL,
+       retval = roccat_common_send(usb_dev, KOVAPLUS_COMMAND_CONTROL,
                        &control, sizeof(struct kovaplus_control));
 
        return retval;
@@ -70,7 +70,7 @@ static int kovaplus_receive_control_status(struct usb_device *usb_dev)
        struct kovaplus_control control;
 
        do {
-               retval = roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_CONTROL,
+               retval = roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_CONTROL,
                                &control, sizeof(struct kovaplus_control));
 
                /* check if we get a completely wrong answer */
@@ -90,7 +90,7 @@ static int kovaplus_receive_control_status(struct usb_device *usb_dev)
                if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_OVERLOAD)
                        return -EINVAL;
 
-               hid_err(usb_dev, "kovaplus_receive_control_status: "
+               hid_err(usb_dev, "roccat_common_receive_control_status: "
                                "unknown response value 0x%x\n", control.value);
                return -EINVAL;
        } while (1);
@@ -119,7 +119,7 @@ static int kovaplus_select_profile(struct usb_device *usb_dev, uint number,
 static int kovaplus_get_info(struct usb_device *usb_dev,
                struct kovaplus_info *buf)
 {
-       return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_INFO,
+       return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_INFO,
                        buf, sizeof(struct kovaplus_info));
 }
 
@@ -133,14 +133,14 @@ static int kovaplus_get_profile_settings(struct usb_device *usb_dev,
        if (retval)
                return retval;
 
-       return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS,
+       return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_SETTINGS,
                        buf, sizeof(struct kovaplus_profile_settings));
 }
 
 static int kovaplus_set_profile_settings(struct usb_device *usb_dev,
                struct kovaplus_profile_settings const *settings)
 {
-       return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS,
+       return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_PROFILE_SETTINGS,
                        settings, sizeof(struct kovaplus_profile_settings));
 }
 
@@ -154,14 +154,14 @@ static int kovaplus_get_profile_buttons(struct usb_device *usb_dev,
        if (retval)
                return retval;
 
-       return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS,
+       return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_BUTTONS,
                        buf, sizeof(struct kovaplus_profile_buttons));
 }
 
 static int kovaplus_set_profile_buttons(struct usb_device *usb_dev,
                struct kovaplus_profile_buttons const *buttons)
 {
-       return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS,
+       return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_PROFILE_BUTTONS,
                        buttons, sizeof(struct kovaplus_profile_buttons));
 }
 
@@ -171,7 +171,7 @@ static int kovaplus_get_actual_profile(struct usb_device *usb_dev)
        struct kovaplus_actual_profile buf;
        int retval;
 
-       retval = roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE,
+       retval = roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_ACTUAL_PROFILE,
                        &buf, sizeof(struct kovaplus_actual_profile));
 
        return retval ? retval : buf.actual_profile;
@@ -186,7 +186,7 @@ static int kovaplus_set_actual_profile(struct usb_device *usb_dev,
        buf.size = sizeof(struct kovaplus_actual_profile);
        buf.actual_profile = new_profile;
 
-       return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE,
+       return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_ACTUAL_PROFILE,
                        &buf, sizeof(struct kovaplus_actual_profile));
 }
 
@@ -337,7 +337,7 @@ static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev,
 
        mutex_lock(&kovaplus->kovaplus_lock);
        retval = kovaplus_set_actual_profile(usb_dev, profile);
-       kovaplus->actual_profile = profile;
+       kovaplus_profile_activated(kovaplus, profile);
        mutex_unlock(&kovaplus->kovaplus_lock);
        if (retval)
                return retval;
@@ -662,6 +662,9 @@ static int kovaplus_raw_event(struct hid_device *hdev,
                        != USB_INTERFACE_PROTOCOL_MOUSE)
                return 0;
 
+       if (kovaplus == NULL)
+               return 0;
+
        kovaplus_keep_values_up_to_date(kovaplus, data);
 
        if (kovaplus->roccat_claimed)
index ce40607d21c761fd82e3f9c4a036e82e9395f314..fb2aed44a8e07b89e351ff71b4169c662b33948a 100644 (file)
@@ -83,15 +83,6 @@ enum kovaplus_commands {
        KOVAPLUS_COMMAND_A = 0xa,
 };
 
-enum kovaplus_usb_commands {
-       KOVAPLUS_USB_COMMAND_CONTROL = 0x304,
-       KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE = 0x305,
-       KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS = 0x306,
-       KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS = 0x307,
-       KOVAPLUS_USB_COMMAND_INFO = 0x309,
-       KOVAPLUS_USB_COMMAND_A = 0x30a,
-};
-
 enum kovaplus_mouse_report_numbers {
        KOVAPLUS_MOUSE_REPORT_NUMBER_MOUSE = 1,
        KOVAPLUS_MOUSE_REPORT_NUMBER_AUDIO = 2,
index 38280c055a1929a319e32d8111908f580c420f86..8140776bd8c51906f7f1296ef1d1ea5ff6d49299 100644 (file)
@@ -53,7 +53,7 @@ static int pyra_send_control(struct usb_device *usb_dev, int value,
        control.value = value;
        control.request = request;
 
-       return roccat_common_send(usb_dev, PYRA_USB_COMMAND_CONTROL,
+       return roccat_common_send(usb_dev, PYRA_COMMAND_CONTROL,
                        &control, sizeof(struct pyra_control));
 }
 
@@ -64,7 +64,7 @@ static int pyra_receive_control_status(struct usb_device *usb_dev)
 
        do {
                msleep(10);
-               retval = roccat_common_receive(usb_dev, PYRA_USB_COMMAND_CONTROL,
+               retval = roccat_common_receive(usb_dev, PYRA_COMMAND_CONTROL,
                                &control, sizeof(struct pyra_control));
 
                /* requested too early, try again */
@@ -89,7 +89,7 @@ static int pyra_get_profile_settings(struct usb_device *usb_dev,
                        PYRA_CONTROL_REQUEST_PROFILE_SETTINGS);
        if (retval)
                return retval;
-       return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_PROFILE_SETTINGS,
+       return roccat_common_receive(usb_dev, PYRA_COMMAND_PROFILE_SETTINGS,
                        buf, sizeof(struct pyra_profile_settings));
 }
 
@@ -101,20 +101,20 @@ static int pyra_get_profile_buttons(struct usb_device *usb_dev,
                        PYRA_CONTROL_REQUEST_PROFILE_BUTTONS);
        if (retval)
                return retval;
-       return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_PROFILE_BUTTONS,
+       return roccat_common_receive(usb_dev, PYRA_COMMAND_PROFILE_BUTTONS,
                        buf, sizeof(struct pyra_profile_buttons));
 }
 
 static int pyra_get_settings(struct usb_device *usb_dev,
                struct pyra_settings *buf)
 {
-       return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_SETTINGS,
+       return roccat_common_receive(usb_dev, PYRA_COMMAND_SETTINGS,
                        buf, sizeof(struct pyra_settings));
 }
 
 static int pyra_get_info(struct usb_device *usb_dev, struct pyra_info *buf)
 {
-       return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_INFO,
+       return roccat_common_receive(usb_dev, PYRA_COMMAND_INFO,
                        buf, sizeof(struct pyra_info));
 }
 
@@ -131,26 +131,22 @@ static int pyra_send(struct usb_device *usb_dev, uint command,
 static int pyra_set_profile_settings(struct usb_device *usb_dev,
                struct pyra_profile_settings const *settings)
 {
-       return pyra_send(usb_dev, PYRA_USB_COMMAND_PROFILE_SETTINGS, settings,
+       return pyra_send(usb_dev, PYRA_COMMAND_PROFILE_SETTINGS, settings,
                        sizeof(struct pyra_profile_settings));
 }
 
 static int pyra_set_profile_buttons(struct usb_device *usb_dev,
                struct pyra_profile_buttons const *buttons)
 {
-       return pyra_send(usb_dev, PYRA_USB_COMMAND_PROFILE_BUTTONS, buttons,
+       return pyra_send(usb_dev, PYRA_COMMAND_PROFILE_BUTTONS, buttons,
                        sizeof(struct pyra_profile_buttons));
 }
 
 static int pyra_set_settings(struct usb_device *usb_dev,
                struct pyra_settings const *settings)
 {
-       int retval;
-       retval = roccat_common_send(usb_dev, PYRA_USB_COMMAND_SETTINGS, settings,
+       return pyra_send(usb_dev, PYRA_COMMAND_SETTINGS, settings,
                        sizeof(struct pyra_settings));
-       if (retval)
-               return retval;
-       return pyra_receive_control_status(usb_dev);
 }
 
 static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
@@ -641,6 +637,9 @@ static int pyra_raw_event(struct hid_device *hdev, struct hid_report *report,
                        != USB_INTERFACE_PROTOCOL_MOUSE)
                return 0;
 
+       if (pyra == NULL)
+               return 0;
+
        pyra_keep_values_up_to_date(pyra, data);
 
        if (pyra->roccat_claimed)
index 14cbbe1621e008c6862ec7b0322463c27fff5d19..0442d7fa2dcf00112910fe84f76ad7a3f348df0a 100644 (file)
@@ -83,15 +83,6 @@ enum pyra_commands {
        PYRA_COMMAND_B = 0xb
 };
 
-enum pyra_usb_commands {
-       PYRA_USB_COMMAND_CONTROL = 0x304,
-       PYRA_USB_COMMAND_SETTINGS = 0x305,
-       PYRA_USB_COMMAND_PROFILE_SETTINGS = 0x306,
-       PYRA_USB_COMMAND_PROFILE_BUTTONS = 0x307,
-       PYRA_USB_COMMAND_INFO = 0x309,
-       PYRA_USB_COMMAND_B = 0x30b /* writes 3 bytes */
-};
-
 enum pyra_mouse_report_numbers {
        PYRA_MOUSE_REPORT_NUMBER_HID = 1,
        PYRA_MOUSE_REPORT_NUMBER_AUDIO = 2,
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
new file mode 100644 (file)
index 0000000..a594383
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+ * HID driver for Nintendo Wiimote devices
+ * Copyright (c) 2011 David Herrmann
+ */
+
+/*
+ * 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/atomic.h>
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include "hid-ids.h"
+
+#define WIIMOTE_VERSION "0.1"
+#define WIIMOTE_NAME "Nintendo Wii Remote"
+#define WIIMOTE_BUFSIZE 32
+
+struct wiimote_buf {
+       __u8 data[HID_MAX_BUFFER_SIZE];
+       size_t size;
+};
+
+struct wiimote_state {
+       spinlock_t lock;
+       __u8 flags;
+};
+
+struct wiimote_data {
+       atomic_t ready;
+       struct hid_device *hdev;
+       struct input_dev *input;
+
+       spinlock_t qlock;
+       __u8 head;
+       __u8 tail;
+       struct wiimote_buf outq[WIIMOTE_BUFSIZE];
+       struct work_struct worker;
+
+       struct wiimote_state state;
+};
+
+#define WIIPROTO_FLAG_LED1 0x01
+#define WIIPROTO_FLAG_LED2 0x02
+#define WIIPROTO_FLAG_LED3 0x04
+#define WIIPROTO_FLAG_LED4 0x08
+#define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \
+                                       WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4)
+
+enum wiiproto_reqs {
+       WIIPROTO_REQ_LED = 0x11,
+       WIIPROTO_REQ_DRM_K = 0x30,
+};
+
+enum wiiproto_keys {
+       WIIPROTO_KEY_LEFT,
+       WIIPROTO_KEY_RIGHT,
+       WIIPROTO_KEY_UP,
+       WIIPROTO_KEY_DOWN,
+       WIIPROTO_KEY_PLUS,
+       WIIPROTO_KEY_MINUS,
+       WIIPROTO_KEY_ONE,
+       WIIPROTO_KEY_TWO,
+       WIIPROTO_KEY_A,
+       WIIPROTO_KEY_B,
+       WIIPROTO_KEY_HOME,
+       WIIPROTO_KEY_COUNT
+};
+
+static __u16 wiiproto_keymap[] = {
+       KEY_LEFT,       /* WIIPROTO_KEY_LEFT */
+       KEY_RIGHT,      /* WIIPROTO_KEY_RIGHT */
+       KEY_UP,         /* WIIPROTO_KEY_UP */
+       KEY_DOWN,       /* WIIPROTO_KEY_DOWN */
+       KEY_NEXT,       /* WIIPROTO_KEY_PLUS */
+       KEY_PREVIOUS,   /* WIIPROTO_KEY_MINUS */
+       BTN_1,          /* WIIPROTO_KEY_ONE */
+       BTN_2,          /* WIIPROTO_KEY_TWO */
+       BTN_A,          /* WIIPROTO_KEY_A */
+       BTN_B,          /* WIIPROTO_KEY_B */
+       BTN_MODE,       /* WIIPROTO_KEY_HOME */
+};
+
+#define dev_to_wii(pdev) hid_get_drvdata(container_of(pdev, struct hid_device, \
+                                                                       dev))
+
+static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
+                                                               size_t count)
+{
+       __u8 *buf;
+       ssize_t ret;
+
+       if (!hdev->hid_output_raw_report)
+               return -ENODEV;
+
+       buf = kmemdup(buffer, count, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = hdev->hid_output_raw_report(hdev, buf, count, HID_OUTPUT_REPORT);
+
+       kfree(buf);
+       return ret;
+}
+
+static void wiimote_worker(struct work_struct *work)
+{
+       struct wiimote_data *wdata = container_of(work, struct wiimote_data,
+                                                                       worker);
+       unsigned long flags;
+
+       spin_lock_irqsave(&wdata->qlock, flags);
+
+       while (wdata->head != wdata->tail) {
+               spin_unlock_irqrestore(&wdata->qlock, flags);
+               wiimote_hid_send(wdata->hdev, wdata->outq[wdata->tail].data,
+                                               wdata->outq[wdata->tail].size);
+               spin_lock_irqsave(&wdata->qlock, flags);
+
+               wdata->tail = (wdata->tail + 1) % WIIMOTE_BUFSIZE;
+       }
+
+       spin_unlock_irqrestore(&wdata->qlock, flags);
+}
+
+static void wiimote_queue(struct wiimote_data *wdata, const __u8 *buffer,
+                                                               size_t count)
+{
+       unsigned long flags;
+       __u8 newhead;
+
+       if (count > HID_MAX_BUFFER_SIZE) {
+               hid_warn(wdata->hdev, "Sending too large output report\n");
+               return;
+       }
+
+       /*
+        * Copy new request into our output queue and check whether the
+        * queue is full. If it is full, discard this request.
+        * If it is empty we need to start a new worker that will
+        * send out the buffer to the hid device.
+        * If the queue is not empty, then there must be a worker
+        * that is currently sending out our buffer and this worker
+        * will reschedule itself until the queue is empty.
+        */
+
+       spin_lock_irqsave(&wdata->qlock, flags);
+
+       memcpy(wdata->outq[wdata->head].data, buffer, count);
+       wdata->outq[wdata->head].size = count;
+       newhead = (wdata->head + 1) % WIIMOTE_BUFSIZE;
+
+       if (wdata->head == wdata->tail) {
+               wdata->head = newhead;
+               schedule_work(&wdata->worker);
+       } else if (newhead != wdata->tail) {
+               wdata->head = newhead;
+       } else {
+               hid_warn(wdata->hdev, "Output queue is full");
+       }
+
+       spin_unlock_irqrestore(&wdata->qlock, flags);
+}
+
+static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
+{
+       __u8 cmd[2];
+
+       leds &= WIIPROTO_FLAGS_LEDS;
+       if ((wdata->state.flags & WIIPROTO_FLAGS_LEDS) == leds)
+               return;
+       wdata->state.flags = (wdata->state.flags & ~WIIPROTO_FLAGS_LEDS) | leds;
+
+       cmd[0] = WIIPROTO_REQ_LED;
+       cmd[1] = 0;
+
+       if (leds & WIIPROTO_FLAG_LED1)
+               cmd[1] |= 0x10;
+       if (leds & WIIPROTO_FLAG_LED2)
+               cmd[1] |= 0x20;
+       if (leds & WIIPROTO_FLAG_LED3)
+               cmd[1] |= 0x40;
+       if (leds & WIIPROTO_FLAG_LED4)
+               cmd[1] |= 0x80;
+
+       wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
+#define wiifs_led_show_set(num)                                                \
+static ssize_t wiifs_led_show_##num(struct device *dev,                        \
+                       struct device_attribute *attr, char *buf)       \
+{                                                                      \
+       struct wiimote_data *wdata = dev_to_wii(dev);                   \
+       unsigned long flags;                                            \
+       int state;                                                      \
+                                                                       \
+       if (!atomic_read(&wdata->ready))                                \
+               return -EBUSY;                                          \
+                                                                       \
+       spin_lock_irqsave(&wdata->state.lock, flags);                   \
+       state = !!(wdata->state.flags & WIIPROTO_FLAG_LED##num);        \
+       spin_unlock_irqrestore(&wdata->state.lock, flags);              \
+                                                                       \
+       return sprintf(buf, "%d\n", state);                             \
+}                                                                      \
+static ssize_t wiifs_led_set_##num(struct device *dev,                 \
+       struct device_attribute *attr, const char *buf, size_t count)   \
+{                                                                      \
+       struct wiimote_data *wdata = dev_to_wii(dev);                   \
+       int tmp = simple_strtoul(buf, NULL, 10);                        \
+       unsigned long flags;                                            \
+       __u8 state;                                                     \
+                                                                       \
+       if (!atomic_read(&wdata->ready))                                \
+               return -EBUSY;                                          \
+                                                                       \
+       spin_lock_irqsave(&wdata->state.lock, flags);                   \
+                                                                       \
+       state = wdata->state.flags;                                     \
+                                                                       \
+       if (tmp)                                                        \
+               wiiproto_req_leds(wdata, state | WIIPROTO_FLAG_LED##num);\
+       else                                                            \
+               wiiproto_req_leds(wdata, state & ~WIIPROTO_FLAG_LED##num);\
+                                                                       \
+       spin_unlock_irqrestore(&wdata->state.lock, flags);              \
+                                                                       \
+       return count;                                                   \
+}                                                                      \
+static DEVICE_ATTR(led##num, S_IRUGO | S_IWUSR, wiifs_led_show_##num,  \
+                                               wiifs_led_set_##num)
+
+wiifs_led_show_set(1);
+wiifs_led_show_set(2);
+wiifs_led_show_set(3);
+wiifs_led_show_set(4);
+
+static int wiimote_input_event(struct input_dev *dev, unsigned int type,
+                                               unsigned int code, int value)
+{
+       struct wiimote_data *wdata = input_get_drvdata(dev);
+
+       if (!atomic_read(&wdata->ready))
+               return -EBUSY;
+       /* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */
+       smp_rmb();
+
+       return 0;
+}
+
+static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
+{
+       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_LEFT],
+                                                       !!(payload[0] & 0x01));
+       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_RIGHT],
+                                                       !!(payload[0] & 0x02));
+       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_DOWN],
+                                                       !!(payload[0] & 0x04));
+       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_UP],
+                                                       !!(payload[0] & 0x08));
+       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_PLUS],
+                                                       !!(payload[0] & 0x10));
+       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_TWO],
+                                                       !!(payload[1] & 0x01));
+       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_ONE],
+                                                       !!(payload[1] & 0x02));
+       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_B],
+                                                       !!(payload[1] & 0x04));
+       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_A],
+                                                       !!(payload[1] & 0x08));
+       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_MINUS],
+                                                       !!(payload[1] & 0x10));
+       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_HOME],
+                                                       !!(payload[1] & 0x80));
+       input_sync(wdata->input);
+}
+
+struct wiiproto_handler {
+       __u8 id;
+       size_t size;
+       void (*func)(struct wiimote_data *wdata, const __u8 *payload);
+};
+
+static struct wiiproto_handler handlers[] = {
+       { .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys },
+       { .id = 0 }
+};
+
+static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
+                                                       u8 *raw_data, int size)
+{
+       struct wiimote_data *wdata = hid_get_drvdata(hdev);
+       struct wiiproto_handler *h;
+       int i;
+       unsigned long flags;
+
+       if (!atomic_read(&wdata->ready))
+               return -EBUSY;
+       /* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */
+       smp_rmb();
+
+       if (size < 1)
+               return -EINVAL;
+
+       spin_lock_irqsave(&wdata->state.lock, flags);
+
+       for (i = 0; handlers[i].id; ++i) {
+               h = &handlers[i];
+               if (h->id == raw_data[0] && h->size < size)
+                       h->func(wdata, &raw_data[1]);
+       }
+
+       spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+       return 0;
+}
+
+static struct wiimote_data *wiimote_create(struct hid_device *hdev)
+{
+       struct wiimote_data *wdata;
+       int i;
+
+       wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
+       if (!wdata)
+               return NULL;
+
+       wdata->input = input_allocate_device();
+       if (!wdata->input) {
+               kfree(wdata);
+               return NULL;
+       }
+
+       wdata->hdev = hdev;
+       hid_set_drvdata(hdev, wdata);
+
+       input_set_drvdata(wdata->input, wdata);
+       wdata->input->event = wiimote_input_event;
+       wdata->input->dev.parent = &wdata->hdev->dev;
+       wdata->input->id.bustype = wdata->hdev->bus;
+       wdata->input->id.vendor = wdata->hdev->vendor;
+       wdata->input->id.product = wdata->hdev->product;
+       wdata->input->id.version = wdata->hdev->version;
+       wdata->input->name = WIIMOTE_NAME;
+
+       set_bit(EV_KEY, wdata->input->evbit);
+       for (i = 0; i < WIIPROTO_KEY_COUNT; ++i)
+               set_bit(wiiproto_keymap[i], wdata->input->keybit);
+
+       spin_lock_init(&wdata->qlock);
+       INIT_WORK(&wdata->worker, wiimote_worker);
+
+       spin_lock_init(&wdata->state.lock);
+
+       return wdata;
+}
+
+static void wiimote_destroy(struct wiimote_data *wdata)
+{
+       kfree(wdata);
+}
+
+static int wiimote_hid_probe(struct hid_device *hdev,
+                               const struct hid_device_id *id)
+{
+       struct wiimote_data *wdata;
+       int ret;
+
+       wdata = wiimote_create(hdev);
+       if (!wdata) {
+               hid_err(hdev, "Can't alloc device\n");
+               return -ENOMEM;
+       }
+
+       ret = device_create_file(&hdev->dev, &dev_attr_led1);
+       if (ret)
+               goto err;
+       ret = device_create_file(&hdev->dev, &dev_attr_led2);
+       if (ret)
+               goto err;
+       ret = device_create_file(&hdev->dev, &dev_attr_led3);
+       if (ret)
+               goto err;
+       ret = device_create_file(&hdev->dev, &dev_attr_led4);
+       if (ret)
+               goto err;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               hid_err(hdev, "HID parse failed\n");
+               goto err;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+       if (ret) {
+               hid_err(hdev, "HW start failed\n");
+               goto err;
+       }
+
+       ret = input_register_device(wdata->input);
+       if (ret) {
+               hid_err(hdev, "Cannot register input device\n");
+               goto err_stop;
+       }
+
+       /* smp_wmb: Write wdata->xy first before wdata->ready is set to 1 */
+       smp_wmb();
+       atomic_set(&wdata->ready, 1);
+       hid_info(hdev, "New device registered\n");
+
+       /* by default set led1 after device initialization */
+       spin_lock_irq(&wdata->state.lock);
+       wiiproto_req_leds(wdata, WIIPROTO_FLAG_LED1);
+       spin_unlock_irq(&wdata->state.lock);
+
+       return 0;
+
+err_stop:
+       hid_hw_stop(hdev);
+err:
+       input_free_device(wdata->input);
+       device_remove_file(&hdev->dev, &dev_attr_led1);
+       device_remove_file(&hdev->dev, &dev_attr_led2);
+       device_remove_file(&hdev->dev, &dev_attr_led3);
+       device_remove_file(&hdev->dev, &dev_attr_led4);
+       wiimote_destroy(wdata);
+       return ret;
+}
+
+static void wiimote_hid_remove(struct hid_device *hdev)
+{
+       struct wiimote_data *wdata = hid_get_drvdata(hdev);
+
+       hid_info(hdev, "Device removed\n");
+
+       device_remove_file(&hdev->dev, &dev_attr_led1);
+       device_remove_file(&hdev->dev, &dev_attr_led2);
+       device_remove_file(&hdev->dev, &dev_attr_led3);
+       device_remove_file(&hdev->dev, &dev_attr_led4);
+
+       hid_hw_stop(hdev);
+       input_unregister_device(wdata->input);
+
+       cancel_work_sync(&wdata->worker);
+       wiimote_destroy(wdata);
+}
+
+static const struct hid_device_id wiimote_hid_devices[] = {
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
+                               USB_DEVICE_ID_NINTENDO_WIIMOTE) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, wiimote_hid_devices);
+
+static struct hid_driver wiimote_hid_driver = {
+       .name = "wiimote",
+       .id_table = wiimote_hid_devices,
+       .probe = wiimote_hid_probe,
+       .remove = wiimote_hid_remove,
+       .raw_event = wiimote_hid_event,
+};
+
+static int __init wiimote_init(void)
+{
+       int ret;
+
+       ret = hid_register_driver(&wiimote_hid_driver);
+       if (ret)
+               pr_err("Can't register wiimote hid driver\n");
+
+       return ret;
+}
+
+static void __exit wiimote_exit(void)
+{
+       hid_unregister_driver(&wiimote_hid_driver);
+}
+
+module_init(wiimote_init);
+module_exit(wiimote_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
+MODULE_DESCRIPTION(WIIMOTE_NAME " Device Driver");
+MODULE_VERSION(WIIMOTE_VERSION);
index 0e30b140edca173d3fb47b4d2b756ad7c53f9f43..621959d5cc42c6b6798328fe32ce32072fa8669a 100644 (file)
@@ -74,6 +74,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5, HID_QUIRK_MULTI_INPUT },
+       { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT },
index ff3c644888b1ba8b0bf14e2426313b66db3688c0..7c1188b53c3ec0ea4aca4364239d9e3596cb7cfa 100644 (file)
@@ -248,12 +248,15 @@ static int hiddev_release(struct inode * inode, struct file * file)
                        usbhid_close(list->hiddev->hid);
                        usbhid_put_power(list->hiddev->hid);
                } else {
+                       mutex_unlock(&list->hiddev->existancelock);
                        kfree(list->hiddev);
+                       kfree(list);
+                       return 0;
                }
        }
 
-       kfree(list);
        mutex_unlock(&list->hiddev->existancelock);
+       kfree(list);
 
        return 0;
 }
@@ -923,10 +926,11 @@ void hiddev_disconnect(struct hid_device *hid)
        usb_deregister_dev(usbhid->intf, &hiddev_class);
 
        if (hiddev->open) {
+               mutex_unlock(&hiddev->existancelock);
                usbhid_close(hiddev->hid);
                wake_up_interruptible(&hiddev->wait);
        } else {
+               mutex_unlock(&hiddev->existancelock);
                kfree(hiddev);
        }
-       mutex_unlock(&hiddev->existancelock);
 }
index 43221beb9e97369b5e245bb489bb8a2e97e42da4..16db83c83c8b9ecea02a19f1e0b0e80971053b1c 100644 (file)
@@ -41,7 +41,7 @@ comment "Native drivers"
 
 config SENSORS_ABITUGURU
        tristate "Abit uGuru (rev 1 & 2)"
-       depends on X86 && EXPERIMENTAL
+       depends on X86 && DMI && EXPERIMENTAL
        help
          If you say yes here you get support for the sensor part of the first
          and second revision of the Abit uGuru chip. The voltage and frequency
@@ -56,7 +56,7 @@ config SENSORS_ABITUGURU
 
 config SENSORS_ABITUGURU3
        tristate "Abit uGuru (rev 3)"
-       depends on X86 && EXPERIMENTAL
+       depends on X86 && DMI && EXPERIMENTAL
        help
          If you say yes here you get support for the sensor part of the
          third revision of the Abit uGuru chip. Only reading the sensors
@@ -213,7 +213,7 @@ config SENSORS_ADT7475
 
 config SENSORS_ASC7621
        tristate "Andigilog aSC7621"
-       depends on HWMON && I2C
+       depends on I2C
        help
          If you say yes here you get support for the aSC7621
          family of SMBus sensors chip found on most Intel X38, X48, X58,
@@ -237,17 +237,27 @@ config SENSORS_K8TEMP
          will be called k8temp.
 
 config SENSORS_K10TEMP
-       tristate "AMD Family 10h/11h/12h/14h temperature sensor"
+       tristate "AMD Family 10h+ temperature sensor"
        depends on X86 && PCI
        help
          If you say yes here you get support for the temperature
          sensor(s) inside your CPU. Supported are later revisions of
          the AMD Family 10h and all revisions of the AMD Family 11h,
-         12h (Llano), and 14h (Brazos) microarchitectures.
+         12h (Llano), 14h (Brazos) and 15h (Bulldozer) microarchitectures.
 
          This driver can also be built as a module.  If so, the module
          will be called k10temp.
 
+config SENSORS_FAM15H_POWER
+       tristate "AMD Family 15h processor power"
+       depends on X86 && PCI
+       help
+         If you say yes here you get support for processor power
+         information of your AMD family 15h CPU.
+
+         This driver can also be built as a module.  If so, the module
+         will be called fam15h_power.
+
 config SENSORS_ASB100
        tristate "Asus ASB100 Bach"
        depends on X86 && I2C && EXPERIMENTAL
@@ -319,7 +329,7 @@ config SENSORS_F71882FG
          If you say yes here you get support for hardware monitoring
          features of many Fintek Super-I/O (LPC) chips. The currently
          supported chips are:
-           F71808E
+           F71808E/A
            F71858FG
            F71862FG
            F71863FG
@@ -978,6 +988,16 @@ config SENSORS_EMC2103
          This driver can also be built as a module.  If so, the module
          will be called emc2103.
 
+config SENSORS_EMC6W201
+       tristate "SMSC EMC6W201"
+       depends on I2C
+       help
+         If you say yes here you get support for the SMSC EMC6W201
+         hardware monitoring chip.
+
+         This driver can also be built as a module.  If so, the module
+         will be called emc6w201.
+
 config SENSORS_SMSC47M1
        tristate "SMSC LPC47M10x and compatibles"
        help
@@ -1341,6 +1361,16 @@ if ACPI
 
 comment "ACPI drivers"
 
+config SENSORS_ACPI_POWER
+       tristate "ACPI 4.0 power meter"
+       help
+         This driver exposes ACPI 4.0 power meters as hardware monitoring
+         devices.  Say Y (or M) if you have a computer with ACPI 4.0 firmware
+         and a power meter.
+
+         To compile this driver as a module, choose M here:
+         the module will be called acpi_power_meter.
+
 config SENSORS_ATK0110
        tristate "ASUS ATK0110"
        depends on X86 && EXPERIMENTAL
index 28e8d52f637923fdfc1e15200fce281760439ac4..28061cfa0cdb11c26558d3e0af68eb5c17c7af33 100644 (file)
@@ -6,6 +6,7 @@ obj-$(CONFIG_HWMON)             += hwmon.o
 obj-$(CONFIG_HWMON_VID)                += hwmon-vid.o
 
 # APCI drivers
+obj-$(CONFIG_SENSORS_ACPI_POWER) += acpi_power_meter.o
 obj-$(CONFIG_SENSORS_ATK0110)  += asus_atk0110.o
 
 # Native drivers
@@ -45,9 +46,11 @@ obj-$(CONFIG_SENSORS_DS620)  += ds620.o
 obj-$(CONFIG_SENSORS_DS1621)   += ds1621.o
 obj-$(CONFIG_SENSORS_EMC1403)  += emc1403.o
 obj-$(CONFIG_SENSORS_EMC2103)  += emc2103.o
+obj-$(CONFIG_SENSORS_EMC6W201) += emc6w201.o
 obj-$(CONFIG_SENSORS_F71805F)  += f71805f.o
 obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
 obj-$(CONFIG_SENSORS_F75375S)  += f75375s.o
+obj-$(CONFIG_SENSORS_FAM15H_POWER) += fam15h_power.o
 obj-$(CONFIG_SENSORS_FSCHMD)   += fschmd.o
 obj-$(CONFIG_SENSORS_G760A)    += g760a.o
 obj-$(CONFIG_SENSORS_GL518SM)  += gl518sm.o
index e7d4c4687f022dc57546776d00ad3c0d371f6e50..65a35cf5b3c5c57b58803e78ae3eda0b0e99f266 100644 (file)
@@ -1448,15 +1448,12 @@ static int __init abituguru_init(void)
 {
        int address, err;
        struct resource res = { .flags = IORESOURCE_IO };
-
-#ifdef CONFIG_DMI
        const char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
 
        /* safety check, refuse to load on non Abit motherboards */
        if (!force && (!board_vendor ||
                        strcmp(board_vendor, "http://www.abit.com.tw/")))
                return -ENODEV;
-#endif
 
        address = abituguru_detect();
        if (address < 0)
index e89d572e33202a45c7d2fc4c444f740d44eec87b..d30855a75786ec7609b624b7492631cda41ab540 100644 (file)
@@ -1119,8 +1119,6 @@ static struct platform_driver abituguru3_driver = {
        .resume = abituguru3_resume
 };
 
-#ifdef CONFIG_DMI
-
 static int __init abituguru3_dmi_detect(void)
 {
        const char *board_vendor, *board_name;
@@ -1159,15 +1157,6 @@ static int __init abituguru3_dmi_detect(void)
        return 1;
 }
 
-#else /* !CONFIG_DMI */
-
-static inline int abituguru3_dmi_detect(void)
-{
-       return 1;
-}
-
-#endif /* CONFIG_DMI */
-
 /* FIXME: Manual detection should die eventually; we need to collect stable
  *        DMI model names first before we can rely entirely on CONFIG_DMI.
  */
@@ -1216,10 +1205,8 @@ static int __init abituguru3_init(void)
                if (err)
                        return err;
 
-#ifdef CONFIG_DMI
                pr_warn("this motherboard was not detected using DMI. "
                        "Please send the output of \"dmidecode\" to the abituguru3 maintainer (see MAINTAINERS)\n");
-#endif
        }
 
        err = platform_driver_register(&abituguru3_driver);
index fbdc7655303b71b49027828f8e125e8c6d606b5a..b2cacbe707a8bcc91d6fb3a30194b470e8f715c2 100644 (file)
@@ -62,7 +62,7 @@ static ssize_t adcxx_read(struct device *dev,
 {
        struct spi_device *spi = to_spi_device(dev);
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct adcxx *adc = dev_get_drvdata(&spi->dev);
+       struct adcxx *adc = spi_get_drvdata(spi);
        u8 tx_buf[2];
        u8 rx_buf[2];
        int status;
@@ -105,7 +105,7 @@ static ssize_t adcxx_show_max(struct device *dev,
                struct device_attribute *devattr, char *buf)
 {
        struct spi_device *spi = to_spi_device(dev);
-       struct adcxx *adc = dev_get_drvdata(&spi->dev);
+       struct adcxx *adc = spi_get_drvdata(spi);
        u32 reference;
 
        if (mutex_lock_interruptible(&adc->lock))
@@ -122,7 +122,7 @@ static ssize_t adcxx_set_max(struct device *dev,
        struct device_attribute *devattr, const char *buf, size_t count)
 {
        struct spi_device *spi = to_spi_device(dev);
-       struct adcxx *adc = dev_get_drvdata(&spi->dev);
+       struct adcxx *adc = spi_get_drvdata(spi);
        unsigned long value;
 
        if (strict_strtoul(buf, 10, &value))
@@ -142,7 +142,7 @@ static ssize_t adcxx_show_name(struct device *dev, struct device_attribute
                              *devattr, char *buf)
 {
        struct spi_device *spi = to_spi_device(dev);
-       struct adcxx *adc = dev_get_drvdata(&spi->dev);
+       struct adcxx *adc = spi_get_drvdata(spi);
 
        return sprintf(buf, "adcxx%ds\n", adc->channels);
 }
@@ -182,7 +182,7 @@ static int __devinit adcxx_probe(struct spi_device *spi)
 
        mutex_lock(&adc->lock);
 
-       dev_set_drvdata(&spi->dev, adc);
+       spi_set_drvdata(spi, adc);
 
        for (i = 0; i < 3 + adc->channels; i++) {
                status = device_create_file(&spi->dev, &ad_input[i].dev_attr);
@@ -206,7 +206,7 @@ out_err:
        for (i--; i >= 0; i--)
                device_remove_file(&spi->dev, &ad_input[i].dev_attr);
 
-       dev_set_drvdata(&spi->dev, NULL);
+       spi_set_drvdata(spi, NULL);
        mutex_unlock(&adc->lock);
        kfree(adc);
        return status;
@@ -214,7 +214,7 @@ out_err:
 
 static int __devexit adcxx_remove(struct spi_device *spi)
 {
-       struct adcxx *adc = dev_get_drvdata(&spi->dev);
+       struct adcxx *adc = spi_get_drvdata(spi);
        int i;
 
        mutex_lock(&adc->lock);
@@ -222,7 +222,7 @@ static int __devexit adcxx_remove(struct spi_device *spi)
        for (i = 0; i < 3 + adc->channels; i++)
                device_remove_file(&spi->dev, &ad_input[i].dev_attr);
 
-       dev_set_drvdata(&spi->dev, NULL);
+       spi_set_drvdata(spi, NULL);
        mutex_unlock(&adc->lock);
        kfree(adc);
 
index b5e892017e0c57497f7726d59812a56144f35ea8..dcb78a7a804754956035f2c57e2e1f8673ac45df 100644 (file)
@@ -268,6 +268,7 @@ static struct device_attribute atk_name_attr =
 static void atk_init_attribute(struct device_attribute *attr, char *name,
                sysfs_show_func show)
 {
+       sysfs_attr_init(&attr->attr);
        attr->attr.name = name;
        attr->attr.mode = 0444;
        attr->show = show;
@@ -1188,19 +1189,15 @@ static int atk_create_files(struct atk_data *data)
        int err;
 
        list_for_each_entry(s, &data->sensor_list, list) {
-               sysfs_attr_init(&s->input_attr.attr);
                err = device_create_file(data->hwmon_dev, &s->input_attr);
                if (err)
                        return err;
-               sysfs_attr_init(&s->label_attr.attr);
                err = device_create_file(data->hwmon_dev, &s->label_attr);
                if (err)
                        return err;
-               sysfs_attr_init(&s->limit1_attr.attr);
                err = device_create_file(data->hwmon_dev, &s->limit1_attr);
                if (err)
                        return err;
-               sysfs_attr_init(&s->limit2_attr.attr);
                err = device_create_file(data->hwmon_dev, &s->limit2_attr);
                if (err)
                        return err;
index 9577c432e77ffd75ae6316b78256c2519f62124b..0070d5476dd0b5ee96bba29259c821d5419bf117 100644 (file)
@@ -97,9 +97,7 @@ struct platform_data {
 struct pdev_entry {
        struct list_head list;
        struct platform_device *pdev;
-       unsigned int cpu;
        u16 phys_proc_id;
-       u16 cpu_core_id;
 };
 
 static LIST_HEAD(pdev_list);
@@ -296,7 +294,7 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
                 * If the TjMax is not plausible, an assumption
                 * will be used
                 */
-               if (val > 80 && val < 120) {
+               if (val) {
                        dev_info(dev, "TjMax is %d C.\n", val);
                        return val * 1000;
                }
@@ -304,24 +302,9 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
 
        /*
         * An assumption is made for early CPUs and unreadable MSR.
-        * NOTE: the given value may not be correct.
+        * NOTE: the calculated value may not be correct.
         */
-
-       switch (c->x86_model) {
-       case 0xe:
-       case 0xf:
-       case 0x16:
-       case 0x1a:
-               dev_warn(dev, "TjMax is assumed as 100 C!\n");
-               return 100000;
-       case 0x17:
-       case 0x1c:              /* Atom CPUs */
-               return adjust_tjmax(c, id, dev);
-       default:
-               dev_warn(dev, "CPU (model=0x%x) is not supported yet,"
-                       " using default TjMax of 100C.\n", c->x86_model);
-               return 100000;
-       }
+       return adjust_tjmax(c, id, dev);
 }
 
 static void __devinit get_ucode_rev_on_cpu(void *edx)
@@ -341,7 +324,7 @@ static int get_pkg_tjmax(unsigned int cpu, struct device *dev)
        err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
        if (!err) {
                val = (eax >> 16) & 0xff;
-               if (val > 80 && val < 120)
+               if (val)
                        return val * 1000;
        }
        dev_warn(dev, "Unable to read Pkg-TjMax from CPU:%u\n", cpu);
@@ -350,6 +333,7 @@ static int get_pkg_tjmax(unsigned int cpu, struct device *dev)
 
 static int create_name_attr(struct platform_data *pdata, struct device *dev)
 {
+       sysfs_attr_init(&pdata->name_attr.attr);
        pdata->name_attr.attr.name = "name";
        pdata->name_attr.attr.mode = S_IRUGO;
        pdata->name_attr.show = show_name;
@@ -372,6 +356,7 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev,
        for (i = 0; i < MAX_ATTRS; i++) {
                snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH, names[i],
                        attr_no);
+               sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr);
                tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i];
                tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO;
                tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
@@ -422,7 +407,7 @@ static void update_ttarget(__u8 cpu_model, struct temp_data *tdata,
        }
 }
 
-static int chk_ucode_version(struct platform_device *pdev)
+static int __devinit chk_ucode_version(struct platform_device *pdev)
 {
        struct cpuinfo_x86 *c = &cpu_data(pdev->id);
        int err;
@@ -509,8 +494,8 @@ static int create_core_data(struct platform_data *pdata,
        /*
         * Provide a single set of attributes for all HT siblings of a core
         * to avoid duplicate sensors (the processor ID and core ID of all
-        * HT siblings of a core is the same).
-        * Skip if a HT sibling of this core is already online.
+        * HT siblings of a core are the same).
+        * Skip if a HT sibling of this core is already registered.
         * This is not an error.
         */
        if (pdata->core_data[attr_no] != NULL)
@@ -666,9 +651,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu)
        }
 
        pdev_entry->pdev = pdev;
-       pdev_entry->cpu = cpu;
        pdev_entry->phys_proc_id = TO_PHYS_ID(cpu);
-       pdev_entry->cpu_core_id = TO_CORE_ID(cpu);
 
        list_add_tail(&pdev_entry->list, &pdev_list);
        mutex_unlock(&pdev_list_mutex);
@@ -770,10 +753,10 @@ static void __cpuinit put_core_offline(unsigned int cpu)
                coretemp_remove_core(pdata, &pdev->dev, indx);
 
        /*
-        * If a core is taken offline, but a HT sibling of the same core is
-        * still online, register the alternate sibling. This ensures that
-        * exactly one set of attributes is provided as long as at least one
-        * HT sibling of a core is online.
+        * If a HT sibling of a core is taken offline, but another HT sibling
+        * of the same core is still online, register the alternate sibling.
+        * This ensures that exactly one set of attributes is provided as long
+        * as at least one HT sibling of a core is online.
         */
        for_each_sibling(i, cpu) {
                if (i != cpu) {
diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c
new file mode 100644 (file)
index 0000000..e0ef323
--- /dev/null
@@ -0,0 +1,539 @@
+/*
+ * emc6w201.c - Hardware monitoring driver for the SMSC EMC6W201
+ * Copyright (C) 2011  Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/*
+ * Addresses to scan
+ */
+
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+/*
+ * The EMC6W201 registers
+ */
+
+#define EMC6W201_REG_IN(nr)            (0x20 + (nr))
+#define EMC6W201_REG_TEMP(nr)          (0x26 + (nr))
+#define EMC6W201_REG_FAN(nr)           (0x2C + (nr) * 2)
+#define EMC6W201_REG_COMPANY           0x3E
+#define EMC6W201_REG_VERSTEP           0x3F
+#define EMC6W201_REG_CONFIG            0x40
+#define EMC6W201_REG_IN_LOW(nr)                (0x4A + (nr) * 2)
+#define EMC6W201_REG_IN_HIGH(nr)       (0x4B + (nr) * 2)
+#define EMC6W201_REG_TEMP_LOW(nr)      (0x56 + (nr) * 2)
+#define EMC6W201_REG_TEMP_HIGH(nr)     (0x57 + (nr) * 2)
+#define EMC6W201_REG_FAN_MIN(nr)       (0x62 + (nr) * 2)
+
+enum { input, min, max } subfeature;
+
+/*
+ * Per-device data
+ */
+
+struct emc6w201_data {
+       struct device *hwmon_dev;
+       struct mutex update_lock;
+       char valid; /* zero until following fields are valid */
+       unsigned long last_updated; /* in jiffies */
+
+       /* registers values */
+       u8 in[3][6];
+       s8 temp[3][6];
+       u16 fan[2][5];
+};
+
+/*
+ * Combine LSB and MSB registers in a single value
+ * Locking: must be called with data->update_lock held
+ */
+static u16 emc6w201_read16(struct i2c_client *client, u8 reg)
+{
+       int lsb, msb;
+
+       lsb = i2c_smbus_read_byte_data(client, reg);
+       msb = i2c_smbus_read_byte_data(client, reg + 1);
+       if (lsb < 0 || msb < 0) {
+               dev_err(&client->dev, "16-bit read failed at 0x%02x\n", reg);
+               return 0xFFFF;  /* Arbitrary value */
+       }
+
+       return (msb << 8) | lsb;
+}
+
+/*
+ * Write 16-bit value to LSB and MSB registers
+ * Locking: must be called with data->update_lock held
+ */
+static int emc6w201_write16(struct i2c_client *client, u8 reg, u16 val)
+{
+       int err;
+
+       err = i2c_smbus_write_byte_data(client, reg, val & 0xff);
+       if (!err)
+               err = i2c_smbus_write_byte_data(client, reg + 1, val >> 8);
+       if (err < 0)
+               dev_err(&client->dev, "16-bit write failed at 0x%02x\n", reg);
+
+       return err;
+}
+
+static struct emc6w201_data *emc6w201_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct emc6w201_data *data = i2c_get_clientdata(client);
+       int nr;
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+               for (nr = 0; nr < 6; nr++) {
+                       data->in[input][nr] =
+                               i2c_smbus_read_byte_data(client,
+                                               EMC6W201_REG_IN(nr));
+                       data->in[min][nr] =
+                               i2c_smbus_read_byte_data(client,
+                                               EMC6W201_REG_IN_LOW(nr));
+                       data->in[max][nr] =
+                               i2c_smbus_read_byte_data(client,
+                                               EMC6W201_REG_IN_HIGH(nr));
+               }
+
+               for (nr = 0; nr < 6; nr++) {
+                       data->temp[input][nr] =
+                               i2c_smbus_read_byte_data(client,
+                                               EMC6W201_REG_TEMP(nr));
+                       data->temp[min][nr] =
+                               i2c_smbus_read_byte_data(client,
+                                               EMC6W201_REG_TEMP_LOW(nr));
+                       data->temp[max][nr] =
+                               i2c_smbus_read_byte_data(client,
+                                               EMC6W201_REG_TEMP_HIGH(nr));
+               }
+
+               for (nr = 0; nr < 5; nr++) {
+                       data->fan[input][nr] =
+                               emc6w201_read16(client,
+                                               EMC6W201_REG_FAN(nr));
+                       data->fan[min][nr] =
+                               emc6w201_read16(client,
+                                               EMC6W201_REG_FAN_MIN(nr));
+               }
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
+/*
+ * Sysfs callback functions
+ */
+
+static const u16 nominal_mv[6] = { 2500, 1500, 3300, 5000, 1500, 1500 };
+
+static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
+       char *buf)
+{
+       struct emc6w201_data *data = emc6w201_update_device(dev);
+       int sf = to_sensor_dev_attr_2(devattr)->index;
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+
+       return sprintf(buf, "%u\n",
+                      (unsigned)data->in[sf][nr] * nominal_mv[nr] / 0xC0);
+}
+
+static ssize_t set_in(struct device *dev, struct device_attribute *devattr,
+                     const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct emc6w201_data *data = i2c_get_clientdata(client);
+       int sf = to_sensor_dev_attr_2(devattr)->index;
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+       int err;
+       long val;
+       u8 reg;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       val = DIV_ROUND_CLOSEST(val * 0xC0, nominal_mv[nr]);
+       reg = (sf == min) ? EMC6W201_REG_IN_LOW(nr)
+                         : EMC6W201_REG_IN_HIGH(nr);
+
+       mutex_lock(&data->update_lock);
+       data->in[sf][nr] = SENSORS_LIMIT(val, 0, 255);
+       err = i2c_smbus_write_byte_data(client, reg, data->in[sf][nr]);
+       mutex_unlock(&data->update_lock);
+
+       return err < 0 ? err : count;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+       char *buf)
+{
+       struct emc6w201_data *data = emc6w201_update_device(dev);
+       int sf = to_sensor_dev_attr_2(devattr)->index;
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+
+       return sprintf(buf, "%d\n", (int)data->temp[sf][nr] * 1000);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+                       const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct emc6w201_data *data = i2c_get_clientdata(client);
+       int sf = to_sensor_dev_attr_2(devattr)->index;
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+       int err;
+       long val;
+       u8 reg;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       val /= 1000;
+       reg = (sf == min) ? EMC6W201_REG_TEMP_LOW(nr)
+                         : EMC6W201_REG_TEMP_HIGH(nr);
+
+       mutex_lock(&data->update_lock);
+       data->temp[sf][nr] = SENSORS_LIMIT(val, -127, 128);
+       err = i2c_smbus_write_byte_data(client, reg, data->temp[sf][nr]);
+       mutex_unlock(&data->update_lock);
+
+       return err < 0 ? err : count;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+       char *buf)
+{
+       struct emc6w201_data *data = emc6w201_update_device(dev);
+       int sf = to_sensor_dev_attr_2(devattr)->index;
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+       unsigned rpm;
+
+       if (data->fan[sf][nr] == 0 || data->fan[sf][nr] == 0xFFFF)
+               rpm = 0;
+       else
+               rpm = 5400000U / data->fan[sf][nr];
+
+       return sprintf(buf, "%u\n", rpm);
+}
+
+static ssize_t set_fan(struct device *dev, struct device_attribute *devattr,
+                      const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct emc6w201_data *data = i2c_get_clientdata(client);
+       int sf = to_sensor_dev_attr_2(devattr)->index;
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+       int err;
+       unsigned long val;
+
+       err = strict_strtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       if (val == 0) {
+               val = 0xFFFF;
+       } else {
+               val = DIV_ROUND_CLOSEST(5400000U, val);
+               val = SENSORS_LIMIT(val, 0, 0xFFFE);
+       }
+
+       mutex_lock(&data->update_lock);
+       data->fan[sf][nr] = val;
+       err = emc6w201_write16(client, EMC6W201_REG_FAN_MIN(nr),
+                              data->fan[sf][nr]);
+       mutex_unlock(&data->update_lock);
+
+       return err < 0 ? err : count;
+}
+
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, input);
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           0, min);
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           0, max);
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 1, input);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           1, min);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           1, max);
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 2, input);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           2, min);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           2, max);
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 3, input);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           3, min);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           3, max);
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 4, input);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           4, min);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           4, max);
+static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 5, input);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           5, min);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           5, max);
+
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, input);
+static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           0, min);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           0, max);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, input);
+static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           1, min);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           1, max);
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, input);
+static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           2, min);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           2, max);
+static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, input);
+static SENSOR_DEVICE_ATTR_2(temp4_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           3, min);
+static SENSOR_DEVICE_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           3, max);
+static SENSOR_DEVICE_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, input);
+static SENSOR_DEVICE_ATTR_2(temp5_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           4, min);
+static SENSOR_DEVICE_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           4, max);
+static SENSOR_DEVICE_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, input);
+static SENSOR_DEVICE_ATTR_2(temp6_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           5, min);
+static SENSOR_DEVICE_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           5, max);
+
+static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, input);
+static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+                           0, min);
+static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 1, input);
+static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+                           1, min);
+static SENSOR_DEVICE_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 2, input);
+static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+                           2, min);
+static SENSOR_DEVICE_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 3, input);
+static SENSOR_DEVICE_ATTR_2(fan4_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+                           3, min);
+static SENSOR_DEVICE_ATTR_2(fan5_input, S_IRUGO, show_fan, NULL, 4, input);
+static SENSOR_DEVICE_ATTR_2(fan5_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+                           4, min);
+
+static struct attribute *emc6w201_attributes[] = {
+       &sensor_dev_attr_in0_input.dev_attr.attr,
+       &sensor_dev_attr_in0_min.dev_attr.attr,
+       &sensor_dev_attr_in0_max.dev_attr.attr,
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in1_min.dev_attr.attr,
+       &sensor_dev_attr_in1_max.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in2_min.dev_attr.attr,
+       &sensor_dev_attr_in2_max.dev_attr.attr,
+       &sensor_dev_attr_in3_input.dev_attr.attr,
+       &sensor_dev_attr_in3_min.dev_attr.attr,
+       &sensor_dev_attr_in3_max.dev_attr.attr,
+       &sensor_dev_attr_in4_input.dev_attr.attr,
+       &sensor_dev_attr_in4_min.dev_attr.attr,
+       &sensor_dev_attr_in4_max.dev_attr.attr,
+       &sensor_dev_attr_in5_input.dev_attr.attr,
+       &sensor_dev_attr_in5_min.dev_attr.attr,
+       &sensor_dev_attr_in5_max.dev_attr.attr,
+
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_min.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_temp4_input.dev_attr.attr,
+       &sensor_dev_attr_temp4_min.dev_attr.attr,
+       &sensor_dev_attr_temp4_max.dev_attr.attr,
+       &sensor_dev_attr_temp5_input.dev_attr.attr,
+       &sensor_dev_attr_temp5_min.dev_attr.attr,
+       &sensor_dev_attr_temp5_max.dev_attr.attr,
+       &sensor_dev_attr_temp6_input.dev_attr.attr,
+       &sensor_dev_attr_temp6_min.dev_attr.attr,
+       &sensor_dev_attr_temp6_max.dev_attr.attr,
+
+       &sensor_dev_attr_fan1_input.dev_attr.attr,
+       &sensor_dev_attr_fan1_min.dev_attr.attr,
+       &sensor_dev_attr_fan2_input.dev_attr.attr,
+       &sensor_dev_attr_fan2_min.dev_attr.attr,
+       &sensor_dev_attr_fan3_input.dev_attr.attr,
+       &sensor_dev_attr_fan3_min.dev_attr.attr,
+       &sensor_dev_attr_fan4_input.dev_attr.attr,
+       &sensor_dev_attr_fan4_min.dev_attr.attr,
+       &sensor_dev_attr_fan5_input.dev_attr.attr,
+       &sensor_dev_attr_fan5_min.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group emc6w201_group = {
+       .attrs = emc6w201_attributes,
+};
+
+/*
+ * Driver interface
+ */
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int emc6w201_detect(struct i2c_client *client,
+                          struct i2c_board_info *info)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       int company, verstep, config;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       /* Identification */
+       company = i2c_smbus_read_byte_data(client, EMC6W201_REG_COMPANY);
+       if (company != 0x5C)
+               return -ENODEV;
+       verstep = i2c_smbus_read_byte_data(client, EMC6W201_REG_VERSTEP);
+       if (verstep < 0 || (verstep & 0xF0) != 0xB0)
+               return -ENODEV;
+       if ((verstep & 0x0F) > 2) {
+               dev_dbg(&client->dev, "Unknwown EMC6W201 stepping %d\n",
+                       verstep & 0x0F);
+               return -ENODEV;
+       }
+
+       /* Check configuration */
+       config = i2c_smbus_read_byte_data(client, EMC6W201_REG_CONFIG);
+       if ((config & 0xF4) != 0x04)
+               return -ENODEV;
+       if (!(config & 0x01)) {
+               dev_err(&client->dev, "Monitoring not enabled\n");
+               return -ENODEV;
+       }
+
+       strlcpy(info->type, "emc6w201", I2C_NAME_SIZE);
+
+       return 0;
+}
+
+static int emc6w201_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       struct emc6w201_data *data;
+       int err;
+
+       data = kzalloc(sizeof(struct emc6w201_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+
+       /* Create sysfs attribute */
+       err = sysfs_create_group(&client->dev.kobj, &emc6w201_group);
+       if (err)
+               goto exit_free;
+
+       /* Expose as a hwmon device */
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove;
+       }
+
+       return 0;
+
+ exit_remove:
+       sysfs_remove_group(&client->dev.kobj, &emc6w201_group);
+ exit_free:
+       kfree(data);
+ exit:
+       return err;
+}
+
+static int emc6w201_remove(struct i2c_client *client)
+{
+       struct emc6w201_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &emc6w201_group);
+       kfree(data);
+
+       return 0;
+}
+
+static const struct i2c_device_id emc6w201_id[] = {
+       { "emc6w201", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, emc6w201_id);
+
+static struct i2c_driver emc6w201_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "emc6w201",
+       },
+       .probe          = emc6w201_probe,
+       .remove         = emc6w201_remove,
+       .id_table       = emc6w201_id,
+       .detect         = emc6w201_detect,
+       .address_list   = normal_i2c,
+};
+
+static int __init sensors_emc6w201_init(void)
+{
+       return i2c_add_driver(&emc6w201_driver);
+}
+module_init(sensors_emc6w201_init);
+
+static void __exit sensors_emc6w201_exit(void)
+{
+       i2c_del_driver(&emc6w201_driver);
+}
+module_exit(sensors_emc6w201_exit);
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("SMSC EMC6W201 hardware monitoring driver");
+MODULE_LICENSE("GPL");
index ca07a32447c23406ef8e39523eb1830d42d56286..a4a94a096c90e993a3019e75de2c285939748ab9 100644 (file)
@@ -48,6 +48,7 @@
 
 #define SIO_FINTEK_ID          0x1934  /* Manufacturers ID */
 #define SIO_F71808E_ID         0x0901  /* Chipset ID */
+#define SIO_F71808A_ID         0x1001  /* Chipset ID */
 #define SIO_F71858_ID          0x0507  /* Chipset ID */
 #define SIO_F71862_ID          0x0601  /* Chipset ID */
 #define SIO_F71869_ID          0x0814  /* Chipset ID */
@@ -107,11 +108,12 @@ static unsigned short force_id;
 module_param(force_id, ushort, 0);
 MODULE_PARM_DESC(force_id, "Override the detected device ID");
 
-enum chips { f71808e, f71858fg, f71862fg, f71869, f71882fg, f71889fg,
+enum chips { f71808e, f71808a, f71858fg, f71862fg, f71869, f71882fg, f71889fg,
             f71889ed, f71889a, f8000, f81865f };
 
 static const char *f71882fg_names[] = {
        "f71808e",
+       "f71808a",
        "f71858fg",
        "f71862fg",
        "f71869", /* Both f71869f and f71869e, reg. compatible and same id */
@@ -125,6 +127,7 @@ static const char *f71882fg_names[] = {
 
 static const char f71882fg_has_in[][F71882FG_MAX_INS] = {
        [f71808e]       = { 1, 1, 1, 1, 1, 1, 0, 1, 1 },
+       [f71808a]       = { 1, 1, 1, 1, 0, 0, 0, 1, 1 },
        [f71858fg]      = { 1, 1, 1, 0, 0, 0, 0, 0, 0 },
        [f71862fg]      = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
        [f71869]        = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
@@ -138,6 +141,7 @@ static const char f71882fg_has_in[][F71882FG_MAX_INS] = {
 
 static const char f71882fg_has_in1_alarm[] = {
        [f71808e]       = 0,
+       [f71808a]       = 0,
        [f71858fg]      = 0,
        [f71862fg]      = 0,
        [f71869]        = 0,
@@ -149,8 +153,9 @@ static const char f71882fg_has_in1_alarm[] = {
        [f81865f]       = 1,
 };
 
-static const char f71882fg_has_beep[] = {
+static const char f71882fg_fan_has_beep[] = {
        [f71808e]       = 0,
+       [f71808a]       = 0,
        [f71858fg]      = 0,
        [f71862fg]      = 1,
        [f71869]        = 1,
@@ -164,6 +169,7 @@ static const char f71882fg_has_beep[] = {
 
 static const char f71882fg_nr_fans[] = {
        [f71808e]       = 3,
+       [f71808a]       = 2, /* +1 fan which is monitor + simple pwm only */
        [f71858fg]      = 3,
        [f71862fg]      = 3,
        [f71869]        = 3,
@@ -171,12 +177,27 @@ static const char f71882fg_nr_fans[] = {
        [f71889fg]      = 3,
        [f71889ed]      = 3,
        [f71889a]       = 3,
-       [f8000]         = 3,
+       [f8000]         = 3, /* +1 fan which is monitor only */
        [f81865f]       = 2,
 };
 
+static const char f71882fg_temp_has_beep[] = {
+       [f71808e]       = 0,
+       [f71808a]       = 1,
+       [f71858fg]      = 0,
+       [f71862fg]      = 1,
+       [f71869]        = 1,
+       [f71882fg]      = 1,
+       [f71889fg]      = 1,
+       [f71889ed]      = 1,
+       [f71889a]       = 1,
+       [f8000]         = 0,
+       [f81865f]       = 1,
+};
+
 static const char f71882fg_nr_temps[] = {
        [f71808e]       = 2,
+       [f71808a]       = 2,
        [f71858fg]      = 3,
        [f71862fg]      = 3,
        [f71869]        = 3,
@@ -301,6 +322,10 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
        char *buf);
 static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
        const char *buf, size_t count);
+static ssize_t show_simple_pwm(struct device *dev,
+       struct device_attribute *devattr, char *buf);
+static ssize_t store_simple_pwm(struct device *dev,
+       struct device_attribute *devattr, const char *buf, size_t count);
 static ssize_t show_pwm_enable(struct device *dev,
        struct device_attribute *devattr, char *buf);
 static ssize_t store_pwm_enable(struct device *dev,
@@ -550,6 +575,14 @@ static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
                      show_pwm_interpolate, store_pwm_interpolate, 0, 3),
 } };
 
+/* Attr for the third fan of the f71808a, which only has manual pwm */
+static struct sensor_device_attribute_2 f71808a_fan3_attr[] = {
+       SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
+       SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
+       SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR,
+                     show_simple_pwm, store_simple_pwm, 0, 2),
+};
+
 /* Attr for models which can beep on Fan alarm */
 static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
        SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
@@ -1146,12 +1179,13 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
                        data->temp_type[3] = (reg & 0x08) ? 2 : 4;
                }
 
-               if (f71882fg_has_beep[data->type]) {
+               if (f71882fg_fan_has_beep[data->type])
                        data->fan_beep = f71882fg_read8(data,
                                                F71882FG_REG_FAN_BEEP);
+
+               if (f71882fg_temp_has_beep[data->type])
                        data->temp_beep = f71882fg_read8(data,
                                                F71882FG_REG_TEMP_BEEP);
-               }
 
                data->pwm_enable = f71882fg_read8(data,
                                                  F71882FG_REG_PWM_ENABLE);
@@ -1232,7 +1266,13 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
                        data->pwm[nr] =
                            f71882fg_read8(data, F71882FG_REG_PWM(nr));
                }
-               /* The f8000 can monitor 1 more fan, but has no pwm for it */
+               /* Some models have 1 more fan with limited capabilities */
+               if (data->type == f71808a) {
+                       data->fan[2] = f71882fg_read16(data,
+                                               F71882FG_REG_FAN(2));
+                       data->pwm[2] = f71882fg_read8(data,
+                                                       F71882FG_REG_PWM(2));
+               }
                if (data->type == f8000)
                        data->fan[3] = f71882fg_read16(data,
                                                F71882FG_REG_FAN(3));
@@ -1722,6 +1762,38 @@ leave:
        return count;
 }
 
+static ssize_t show_simple_pwm(struct device *dev,
+                              struct device_attribute *devattr, char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int val, nr = to_sensor_dev_attr_2(devattr)->index;
+
+       val = data->pwm[nr];
+       return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t store_simple_pwm(struct device *dev,
+                               struct device_attribute *devattr,
+                               const char *buf, size_t count)
+{
+       struct f71882fg_data *data = dev_get_drvdata(dev);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
+       val = SENSORS_LIMIT(val, 0, 255);
+
+       mutex_lock(&data->update_lock);
+       f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
+       data->pwm[nr] = val;
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
 static ssize_t show_pwm_enable(struct device *dev,
                               struct device_attribute *devattr, char *buf)
 {
@@ -2140,7 +2212,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
                if (err)
                        goto exit_unregister_sysfs;
 
-               if (f71882fg_has_beep[data->type]) {
+               if (f71882fg_temp_has_beep[data->type]) {
                        err = f71882fg_create_sysfs_files(pdev,
                                        &fxxxx_temp_beep_attr[0][0],
                                        ARRAY_SIZE(fxxxx_temp_beep_attr[0])
@@ -2169,6 +2241,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
        if (start_reg & 0x02) {
                switch (data->type) {
                case f71808e:
+               case f71808a:
                case f71869:
                        /* These always have signed auto point temps */
                        data->auto_point_temp_signed = 1;
@@ -2221,7 +2294,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
                if (err)
                        goto exit_unregister_sysfs;
 
-               if (f71882fg_has_beep[data->type]) {
+               if (f71882fg_fan_has_beep[data->type]) {
                        err = f71882fg_create_sysfs_files(pdev,
                                        fxxxx_fan_beep_attr, nr_fans);
                        if (err)
@@ -2230,6 +2303,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
 
                switch (data->type) {
                case f71808e:
+               case f71808a:
                case f71869:
                case f71889fg:
                case f71889ed:
@@ -2255,6 +2329,16 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
                }
 
                switch (data->type) {
+               case f71808a:
+                       err = f71882fg_create_sysfs_files(pdev,
+                               &fxxxx_auto_pwm_attr[0][0],
+                               ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
+                       if (err)
+                               goto exit_unregister_sysfs;
+                       err = f71882fg_create_sysfs_files(pdev,
+                                       f71808a_fan3_attr,
+                                       ARRAY_SIZE(f71808a_fan3_attr));
+                       break;
                case f71862fg:
                        err = f71882fg_create_sysfs_files(pdev,
                                        f71862fg_auto_pwm_attr,
@@ -2343,7 +2427,7 @@ static int f71882fg_remove(struct platform_device *pdev)
                                &fxxxx_temp_attr[0][0],
                                ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
                }
-               if (f71882fg_has_beep[data->type]) {
+               if (f71882fg_temp_has_beep[data->type]) {
                        f71882fg_remove_sysfs_files(pdev,
                               &fxxxx_temp_beep_attr[0][0],
                               ARRAY_SIZE(fxxxx_temp_beep_attr[0]) * nr_temps);
@@ -2366,12 +2450,20 @@ static int f71882fg_remove(struct platform_device *pdev)
                f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
                                ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
 
-               if (f71882fg_has_beep[data->type]) {
+               if (f71882fg_fan_has_beep[data->type]) {
                        f71882fg_remove_sysfs_files(pdev,
                                        fxxxx_fan_beep_attr, nr_fans);
                }
 
                switch (data->type) {
+               case f71808a:
+                       f71882fg_remove_sysfs_files(pdev,
+                               &fxxxx_auto_pwm_attr[0][0],
+                               ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
+                       f71882fg_remove_sysfs_files(pdev,
+                                       f71808a_fan3_attr,
+                                       ARRAY_SIZE(f71808a_fan3_attr));
+                       break;
                case f71862fg:
                        f71882fg_remove_sysfs_files(pdev,
                                        f71862fg_auto_pwm_attr,
@@ -2424,6 +2516,9 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
        case SIO_F71808E_ID:
                sio_data->type = f71808e;
                break;
+       case SIO_F71808A_ID:
+               sio_data->type = f71808a;
+               break;
        case SIO_F71858_ID:
                sio_data->type = f71858fg;
                break;
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c
new file mode 100644 (file)
index 0000000..523f8fb
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * fam15h_power.c - AMD Family 15h processor power monitoring
+ *
+ * Copyright (c) 2011 Advanced Micro Devices, Inc.
+ * Author: Andreas Herrmann <andreas.herrmann3@amd.com>
+ *
+ *
+ * This driver is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This driver 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 driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/bitops.h>
+#include <asm/processor.h>
+
+MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor");
+MODULE_AUTHOR("Andreas Herrmann <andreas.herrmann3@amd.com>");
+MODULE_LICENSE("GPL");
+
+/* D18F3 */
+#define REG_NORTHBRIDGE_CAP            0xe8
+
+/* D18F4 */
+#define REG_PROCESSOR_TDP              0x1b8
+
+/* D18F5 */
+#define REG_TDP_RUNNING_AVERAGE                0xe0
+#define REG_TDP_LIMIT3                 0xe8
+
+struct fam15h_power_data {
+       struct device *hwmon_dev;
+       unsigned int tdp_to_watts;
+       unsigned int base_tdp;
+       unsigned int processor_pwr_watts;
+};
+
+static ssize_t show_power(struct device *dev,
+                         struct device_attribute *attr, char *buf)
+{
+       u32 val, tdp_limit, running_avg_range;
+       s32 running_avg_capture;
+       u64 curr_pwr_watts;
+       struct pci_dev *f4 = to_pci_dev(dev);
+       struct fam15h_power_data *data = dev_get_drvdata(dev);
+
+       pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
+                                 REG_TDP_RUNNING_AVERAGE, &val);
+       running_avg_capture = (val >> 4) & 0x3fffff;
+       running_avg_capture = sign_extend32(running_avg_capture, 22);
+       running_avg_range = val & 0xf;
+
+       pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
+                                 REG_TDP_LIMIT3, &val);
+
+       tdp_limit = val >> 16;
+       curr_pwr_watts = tdp_limit + data->base_tdp -
+               (s32)(running_avg_capture >> (running_avg_range + 1));
+       curr_pwr_watts *= data->tdp_to_watts;
+
+       /*
+        * Convert to microWatt
+        *
+        * power is in Watt provided as fixed point integer with
+        * scaling factor 1/(2^16).  For conversion we use
+        * (10^6)/(2^16) = 15625/(2^10)
+        */
+       curr_pwr_watts = (curr_pwr_watts * 15625) >> 10;
+       return sprintf(buf, "%u\n", (unsigned int) curr_pwr_watts);
+}
+static DEVICE_ATTR(power1_input, S_IRUGO, show_power, NULL);
+
+static ssize_t show_power_crit(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       struct fam15h_power_data *data = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", data->processor_pwr_watts);
+}
+static DEVICE_ATTR(power1_crit, S_IRUGO, show_power_crit, NULL);
+
+static ssize_t show_name(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "fam15h_power\n");
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct attribute *fam15h_power_attrs[] = {
+       &dev_attr_power1_input.attr,
+       &dev_attr_power1_crit.attr,
+       &dev_attr_name.attr,
+       NULL
+};
+
+static const struct attribute_group fam15h_power_attr_group = {
+       .attrs  = fam15h_power_attrs,
+};
+
+static bool __devinit fam15h_power_is_internal_node0(struct pci_dev *f4)
+{
+       u32 val;
+
+       pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 3),
+                                 REG_NORTHBRIDGE_CAP, &val);
+       if ((val & BIT(29)) && ((val >> 30) & 3))
+               return false;
+
+       return true;
+}
+
+static void __devinit fam15h_power_init_data(struct pci_dev *f4,
+                                            struct fam15h_power_data *data)
+{
+       u32 val;
+       u64 tmp;
+
+       pci_read_config_dword(f4, REG_PROCESSOR_TDP, &val);
+       data->base_tdp = val >> 16;
+       tmp = val & 0xffff;
+
+       pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
+                                 REG_TDP_LIMIT3, &val);
+
+       data->tdp_to_watts = ((val & 0x3ff) << 6) | ((val >> 10) & 0x3f);
+       tmp *= data->tdp_to_watts;
+
+       /* result not allowed to be >= 256W */
+       if ((tmp >> 16) >= 256)
+               dev_warn(&f4->dev, "Bogus value for ProcessorPwrWatts "
+                        "(processor_pwr_watts>=%u)\n",
+                        (unsigned int) (tmp >> 16));
+
+       /* convert to microWatt */
+       data->processor_pwr_watts = (tmp * 15625) >> 10;
+}
+
+static int __devinit fam15h_power_probe(struct pci_dev *pdev,
+                                       const struct pci_device_id *id)
+{
+       struct fam15h_power_data *data;
+       struct device *dev;
+       int err;
+
+       if (!fam15h_power_is_internal_node0(pdev)) {
+               err = -ENODEV;
+               goto exit;
+       }
+
+       data = kzalloc(sizeof(struct fam15h_power_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto exit;
+       }
+       fam15h_power_init_data(pdev, data);
+       dev = &pdev->dev;
+
+       dev_set_drvdata(dev, data);
+       err = sysfs_create_group(&dev->kobj, &fam15h_power_attr_group);
+       if (err)
+               goto exit_free_data;
+
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove_group;
+       }
+
+       return 0;
+
+exit_remove_group:
+       sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group);
+exit_free_data:
+       kfree(data);
+exit:
+       return err;
+}
+
+static void __devexit fam15h_power_remove(struct pci_dev *pdev)
+{
+       struct device *dev;
+       struct fam15h_power_data *data;
+
+       dev = &pdev->dev;
+       data = dev_get_drvdata(dev);
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group);
+       dev_set_drvdata(dev, NULL);
+       kfree(data);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(fam15h_power_id_table) = {
+       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
+       {}
+};
+MODULE_DEVICE_TABLE(pci, fam15h_power_id_table);
+
+static struct pci_driver fam15h_power_driver = {
+       .name = "fam15h_power",
+       .id_table = fam15h_power_id_table,
+       .probe = fam15h_power_probe,
+       .remove = __devexit_p(fam15h_power_remove),
+};
+
+static int __init fam15h_power_init(void)
+{
+       return pci_register_driver(&fam15h_power_driver);
+}
+
+static void __exit fam15h_power_exit(void)
+{
+       pci_unregister_driver(&fam15h_power_driver);
+}
+
+module_init(fam15h_power_init)
+module_exit(fam15h_power_exit)
index bc6e2ab3a361d539befcc2055ebcb5a1c119f5a9..1a409c5bc9bce687922ce5389150599c6e928f39 100644 (file)
@@ -523,7 +523,7 @@ static void aem_delete(struct aem_data *data)
        aem_remove_sensors(data);
        hwmon_device_unregister(data->hwmon_dev);
        ipmi_destroy_user(data->ipmi.user);
-       dev_set_drvdata(&data->pdev->dev, NULL);
+       platform_set_drvdata(data->pdev, NULL);
        platform_device_unregister(data->pdev);
        aem_idr_put(data->id);
        kfree(data);
@@ -594,7 +594,7 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle)
        if (res)
                goto ipmi_err;
 
-       dev_set_drvdata(&data->pdev->dev, data);
+       platform_set_drvdata(data->pdev, data);
 
        /* Set up IPMI interface */
        if (aem_init_ipmi_data(&data->ipmi, probe->interface,
@@ -630,7 +630,7 @@ sensor_err:
 hwmon_reg_err:
        ipmi_destroy_user(data->ipmi.user);
 ipmi_err:
-       dev_set_drvdata(&data->pdev->dev, NULL);
+       platform_set_drvdata(data->pdev, NULL);
        platform_device_unregister(data->pdev);
 dev_err:
        aem_idr_put(data->id);
@@ -727,7 +727,7 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe,
        if (res)
                goto ipmi_err;
 
-       dev_set_drvdata(&data->pdev->dev, data);
+       platform_set_drvdata(data->pdev, data);
 
        /* Set up IPMI interface */
        if (aem_init_ipmi_data(&data->ipmi, probe->interface,
@@ -763,7 +763,7 @@ sensor_err:
 hwmon_reg_err:
        ipmi_destroy_user(data->ipmi.user);
 ipmi_err:
-       dev_set_drvdata(&data->pdev->dev, NULL);
+       platform_set_drvdata(data->pdev, NULL);
        platform_device_unregister(data->pdev);
 dev_err:
        aem_idr_put(data->id);
@@ -947,6 +947,7 @@ static int aem_register_sensors(struct aem_data *data,
 
        /* Set up read-only sensors */
        while (ro->label) {
+               sysfs_attr_init(&sensors->dev_attr.attr);
                sensors->dev_attr.attr.name = ro->label;
                sensors->dev_attr.attr.mode = S_IRUGO;
                sensors->dev_attr.show = ro->show;
@@ -963,6 +964,7 @@ static int aem_register_sensors(struct aem_data *data,
 
        /* Set up read-write sensors */
        while (rw->label) {
+               sysfs_attr_init(&sensors->dev_attr.attr);
                sensors->dev_attr.attr.name = rw->label;
                sensors->dev_attr.attr.mode = S_IRUGO | S_IWUSR;
                sensors->dev_attr.show = rw->show;
index 06d4eafcf76b231fdc74e0418341e496387b78d9..41dbf8161ed7b4fb1bc29811c61f006152c9a41c 100644 (file)
@@ -358,6 +358,7 @@ static int create_sensor(struct ibmpex_bmc_data *data, int type,
        else if (type == POWER_SENSOR)
                sprintf(n, power_sensor_name_templates[func], "power", counter);
 
+       sysfs_attr_init(&data->sensors[sensor].attr[func].dev_attr.attr);
        data->sensors[sensor].attr[func].dev_attr.attr.name = n;
        data->sensors[sensor].attr[func].dev_attr.attr.mode = S_IRUGO;
        data->sensors[sensor].attr[func].dev_attr.show = ibmpex_show_sensor;
index 316b64823f7b39b805823e606453e244a32d3bae..bb6405b92007b7b9a9ba2c95038e49f01211c7a0 100644 (file)
@@ -77,15 +77,13 @@ static struct platform_device *pdev;
 #define        DEVID   0x20    /* Register: Device ID */
 #define        DEVREV  0x22    /* Register: Device Revision */
 
-static inline int
-superio_inb(int reg)
+static inline int superio_inb(int reg)
 {
        outb(reg, REG);
        return inb(VAL);
 }
 
-static inline void
-superio_outb(int reg, int val)
+static inline void superio_outb(int reg, int val)
 {
        outb(reg, REG);
        outb(val, VAL);
@@ -101,27 +99,32 @@ static int superio_inw(int reg)
        return val;
 }
 
-static inline void
-superio_select(int ldn)
+static inline void superio_select(int ldn)
 {
        outb(DEV, REG);
        outb(ldn, VAL);
 }
 
-static inline void
-superio_enter(void)
+static inline int superio_enter(void)
 {
+       /*
+        * Try to reserve REG and REG + 1 for exclusive access.
+        */
+       if (!request_muxed_region(REG, 2, DRVNAME))
+               return -EBUSY;
+
        outb(0x87, REG);
        outb(0x01, REG);
        outb(0x55, REG);
        outb(0x55, REG);
+       return 0;
 }
 
-static inline void
-superio_exit(void)
+static inline void superio_exit(void)
 {
        outb(0x02, REG);
        outb(0x02, VAL);
+       release_region(REG, 2);
 }
 
 /* Logical device 4 registers */
@@ -1542,11 +1545,15 @@ static const struct attribute_group it87_group_label = {
 static int __init it87_find(unsigned short *address,
        struct it87_sio_data *sio_data)
 {
-       int err = -ENODEV;
+       int err;
        u16 chip_type;
        const char *board_vendor, *board_name;
 
-       superio_enter();
+       err = superio_enter();
+       if (err)
+               return err;
+
+       err = -ENODEV;
        chip_type = force_id ? force_id : superio_inw(DEVID);
 
        switch (chip_type) {
index 93499123706182b9bdf42b3da295759eda67b18c..02cebb74e206743f08608ad2f101398ec9ab61d8 100644 (file)
@@ -213,7 +213,7 @@ static const struct dev_pm_ops jc42_dev_pm_ops = {
 
 /* This is the driver that will be inserted */
 static struct i2c_driver jc42_driver = {
-       .class          = I2C_CLASS_HWMON,
+       .class          = I2C_CLASS_SPD,
        .driver = {
                .name   = "jc42",
                .pm = JC42_DEV_PM_OPS,
index 82bf65aa2968bcfb3d89b6c9280e72f437762037..41aa6a319870cdcc6435ad8690be095aa8ab8675 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * k10temp.c - AMD Family 10h/11h/12h/14h processor hardware monitoring
+ * k10temp.c - AMD Family 10h/11h/12h/14h/15h processor hardware monitoring
  *
  * Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de>
  *
@@ -25,7 +25,7 @@
 #include <linux/pci.h>
 #include <asm/processor.h>
 
-MODULE_DESCRIPTION("AMD Family 10h/11h/12h/14h CPU core temperature monitor");
+MODULE_DESCRIPTION("AMD Family 10h+ CPU core temperature monitor");
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_LICENSE("GPL");
 
@@ -173,7 +173,7 @@ static int __devinit k10temp_probe(struct pci_dev *pdev,
                err = PTR_ERR(hwmon_dev);
                goto exit_remove;
        }
-       dev_set_drvdata(&pdev->dev, hwmon_dev);
+       pci_set_drvdata(pdev, hwmon_dev);
 
        if (unreliable && force)
                dev_warn(&pdev->dev,
@@ -194,7 +194,7 @@ exit:
 
 static void __devexit k10temp_remove(struct pci_dev *pdev)
 {
-       hwmon_device_unregister(dev_get_drvdata(&pdev->dev));
+       hwmon_device_unregister(pci_get_drvdata(pdev));
        device_remove_file(&pdev->dev, &dev_attr_name);
        device_remove_file(&pdev->dev, &dev_attr_temp1_input);
        device_remove_file(&pdev->dev, &dev_attr_temp1_max);
@@ -202,13 +202,14 @@ static void __devexit k10temp_remove(struct pci_dev *pdev)
                           &sensor_dev_attr_temp1_crit.dev_attr);
        device_remove_file(&pdev->dev,
                           &sensor_dev_attr_temp1_crit_hyst.dev_attr);
-       dev_set_drvdata(&pdev->dev, NULL);
+       pci_set_drvdata(pdev, NULL);
 }
 
 static const struct pci_device_id k10temp_id_table[] = {
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
+       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
        {}
 };
 MODULE_DEVICE_TABLE(pci, k10temp_id_table);
index 418496f13020ba58f57e23eece28417a48466aea..b923bc2307ad2e09758086daba616863bb2e1a00 100644 (file)
@@ -252,7 +252,7 @@ static int __devinit k8temp_probe(struct pci_dev *pdev,
 
        data->name = "k8temp";
        mutex_init(&data->update_lock);
-       dev_set_drvdata(&pdev->dev, data);
+       pci_set_drvdata(pdev, data);
 
        /* Register sysfs hooks */
        err = device_create_file(&pdev->dev,
@@ -307,7 +307,7 @@ exit_remove:
                           &sensor_dev_attr_temp4_input.dev_attr);
        device_remove_file(&pdev->dev, &dev_attr_name);
 exit_free:
-       dev_set_drvdata(&pdev->dev, NULL);
+       pci_set_drvdata(pdev, NULL);
        kfree(data);
 exit:
        return err;
@@ -315,7 +315,7 @@ exit:
 
 static void __devexit k8temp_remove(struct pci_dev *pdev)
 {
-       struct k8temp_data *data = dev_get_drvdata(&pdev->dev);
+       struct k8temp_data *data = pci_get_drvdata(pdev);
 
        hwmon_device_unregister(data->hwmon_dev);
        device_remove_file(&pdev->dev,
@@ -327,7 +327,7 @@ static void __devexit k8temp_remove(struct pci_dev *pdev)
        device_remove_file(&pdev->dev,
                           &sensor_dev_attr_temp4_input.dev_attr);
        device_remove_file(&pdev->dev, &dev_attr_name);
-       dev_set_drvdata(&pdev->dev, NULL);
+       pci_set_drvdata(pdev, NULL);
        kfree(data);
 }
 
index 3b84fb5030535d3e16d60e164a68dd0fb8ef8a4f..c274ea25d899f5766d06d41283c5ec26876adddd 100644 (file)
@@ -58,7 +58,7 @@ static ssize_t lm70_sense_temp(struct device *dev,
        int status, val = 0;
        u8 rxbuf[2];
        s16 raw=0;
-       struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
+       struct lm70 *p_lm70 = spi_get_drvdata(spi);
 
        if (mutex_lock_interruptible(&p_lm70->lock))
                return -ERESTARTSYS;
@@ -163,7 +163,7 @@ static int __devinit lm70_probe(struct spi_device *spi)
                status = PTR_ERR(p_lm70->hwmon_dev);
                goto out_dev_reg_failed;
        }
-       dev_set_drvdata(&spi->dev, p_lm70);
+       spi_set_drvdata(spi, p_lm70);
 
        if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))
         || (status = device_create_file(&spi->dev, &dev_attr_name))) {
@@ -177,19 +177,19 @@ out_dev_create_file_failed:
        device_remove_file(&spi->dev, &dev_attr_temp1_input);
        hwmon_device_unregister(p_lm70->hwmon_dev);
 out_dev_reg_failed:
-       dev_set_drvdata(&spi->dev, NULL);
+       spi_set_drvdata(spi, NULL);
        kfree(p_lm70);
        return status;
 }
 
 static int __devexit lm70_remove(struct spi_device *spi)
 {
-       struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
+       struct lm70 *p_lm70 = spi_get_drvdata(spi);
 
        device_remove_file(&spi->dev, &dev_attr_temp1_input);
        device_remove_file(&spi->dev, &dev_attr_name);
        hwmon_device_unregister(p_lm70->hwmon_dev);
-       dev_set_drvdata(&spi->dev, NULL);
+       spi_set_drvdata(spi, NULL);
        kfree(p_lm70);
 
        return 0;
index 0f9fc40379cd14df869f15f8d8608d9f8393eb19..e855d3b0bd1f1d5e623c913343ae8ec9d6834e01 100644 (file)
@@ -136,15 +136,29 @@ static int max6642_detect(struct i2c_client *client,
        if (man_id != 0x4D)
                return -ENODEV;
 
+       /* sanity check */
+       if (i2c_smbus_read_byte_data(client, 0x04) != 0x4D
+           || i2c_smbus_read_byte_data(client, 0x06) != 0x4D
+           || i2c_smbus_read_byte_data(client, 0xff) != 0x4D)
+               return -ENODEV;
+
        /*
         * We read the config and status register, the 4 lower bits in the
         * config register should be zero and bit 5, 3, 1 and 0 should be
         * zero in the status register.
         */
        reg_config = i2c_smbus_read_byte_data(client, MAX6642_REG_R_CONFIG);
+       if ((reg_config & 0x0f) != 0x00)
+               return -ENODEV;
+
+       /* in between, another round of sanity checks */
+       if (i2c_smbus_read_byte_data(client, 0x04) != reg_config
+           || i2c_smbus_read_byte_data(client, 0x06) != reg_config
+           || i2c_smbus_read_byte_data(client, 0xff) != reg_config)
+               return -ENODEV;
+
        reg_status = i2c_smbus_read_byte_data(client, MAX6642_REG_R_STATUS);
-       if (((reg_config & 0x0f) != 0x00) ||
-           ((reg_status & 0x2b) != 0x00))
+       if ((reg_status & 0x2b) != 0x00)
                return -ENODEV;
 
        strlcpy(info->type, "max6642", I2C_NAME_SIZE);
@@ -246,7 +260,7 @@ static SENSOR_DEVICE_ATTR_2(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
                            set_temp_max, 0, MAX6642_REG_W_LOCAL_HIGH);
 static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
                            set_temp_max, 1, MAX6642_REG_W_REMOTE_HIGH);
-static SENSOR_DEVICE_ATTR(temp_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
 static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
 static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
 
@@ -256,7 +270,7 @@ static struct attribute *max6642_attributes[] = {
        &sensor_dev_attr_temp1_max.dev_attr.attr,
        &sensor_dev_attr_temp2_max.dev_attr.attr,
 
-       &sensor_dev_attr_temp_fault.dev_attr.attr,
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
        &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
        &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
        NULL
index 9a11532ecae84384d105e1f2c0b070a5107c0c3c..ece3aafa54b3f42a23518d958ca515b29b13d25f 100644 (file)
 #include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 
-/*
- * Addresses to scan. There are four disjoint possibilities, by pin config.
- */
-
-static const unsigned short normal_i2c[] = {0x1b, 0x1f, 0x48, 0x4b,
-                                               I2C_CLIENT_END};
-
 /*
  * Insmod parameters
  */
@@ -114,8 +107,6 @@ module_param(clock, int, S_IRUGO);
 
 static int max6650_probe(struct i2c_client *client,
                         const struct i2c_device_id *id);
-static int max6650_detect(struct i2c_client *client,
-                         struct i2c_board_info *info);
 static int max6650_init_client(struct i2c_client *client);
 static int max6650_remove(struct i2c_client *client);
 static struct max6650_data *max6650_update_device(struct device *dev);
@@ -125,21 +116,19 @@ static struct max6650_data *max6650_update_device(struct device *dev);
  */
 
 static const struct i2c_device_id max6650_id[] = {
-       { "max6650", 0 },
+       { "max6650", 1 },
+       { "max6651", 4 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, max6650_id);
 
 static struct i2c_driver max6650_driver = {
-       .class          = I2C_CLASS_HWMON,
        .driver = {
                .name   = "max6650",
        },
        .probe          = max6650_probe,
        .remove         = max6650_remove,
        .id_table       = max6650_id,
-       .detect         = max6650_detect,
-       .address_list   = normal_i2c,
 };
 
 /*
@@ -150,6 +139,7 @@ struct max6650_data
 {
        struct device *hwmon_dev;
        struct mutex update_lock;
+       int nr_fans;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
 
@@ -501,9 +491,6 @@ static mode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
 
 static struct attribute *max6650_attrs[] = {
        &sensor_dev_attr_fan1_input.dev_attr.attr,
-       &sensor_dev_attr_fan2_input.dev_attr.attr,
-       &sensor_dev_attr_fan3_input.dev_attr.attr,
-       &sensor_dev_attr_fan4_input.dev_attr.attr,
        &dev_attr_fan1_target.attr,
        &dev_attr_fan1_div.attr,
        &dev_attr_pwm1_enable.attr,
@@ -521,42 +508,21 @@ static struct attribute_group max6650_attr_grp = {
        .is_visible = max6650_attrs_visible,
 };
 
+static struct attribute *max6651_attrs[] = {
+       &sensor_dev_attr_fan2_input.dev_attr.attr,
+       &sensor_dev_attr_fan3_input.dev_attr.attr,
+       &sensor_dev_attr_fan4_input.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group max6651_attr_grp = {
+       .attrs = max6651_attrs,
+};
+
 /*
  * Real code
  */
 
-/* Return 0 if detection is successful, -ENODEV otherwise */
-static int max6650_detect(struct i2c_client *client,
-                         struct i2c_board_info *info)
-{
-       struct i2c_adapter *adapter = client->adapter;
-       int address = client->addr;
-
-       dev_dbg(&adapter->dev, "max6650_detect called\n");
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
-               dev_dbg(&adapter->dev, "max6650: I2C bus doesn't support "
-                                       "byte read mode, skipping.\n");
-               return -ENODEV;
-       }
-
-       if (((i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG) & 0xC0)
-           ||(i2c_smbus_read_byte_data(client, MAX6650_REG_GPIO_STAT) & 0xE0)
-           ||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN) & 0xE0)
-           ||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM) & 0xE0)
-           ||(i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT) & 0xFC))) {
-               dev_dbg(&adapter->dev,
-                       "max6650: detection failed at 0x%02x.\n", address);
-               return -ENODEV;
-       }
-
-       dev_info(&adapter->dev, "max6650: chip found at 0x%02x.\n", address);
-
-       strlcpy(info->type, "max6650", I2C_NAME_SIZE);
-
-       return 0;
-}
-
 static int max6650_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
@@ -570,6 +536,7 @@ static int max6650_probe(struct i2c_client *client,
 
        i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
+       data->nr_fans = id->driver_data;
 
        /*
         * Initialize the max6650 chip
@@ -581,6 +548,12 @@ static int max6650_probe(struct i2c_client *client,
        err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp);
        if (err)
                goto err_free;
+       /* 3 additional fan inputs for the MAX6651 */
+       if (data->nr_fans == 4) {
+               err = sysfs_create_group(&client->dev.kobj, &max6651_attr_grp);
+               if (err)
+                       goto err_remove;
+       }
 
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (!IS_ERR(data->hwmon_dev))
@@ -588,6 +561,9 @@ static int max6650_probe(struct i2c_client *client,
 
        err = PTR_ERR(data->hwmon_dev);
        dev_err(&client->dev, "error registering hwmon device.\n");
+       if (data->nr_fans == 4)
+               sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp);
+err_remove:
        sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
 err_free:
        kfree(data);
@@ -598,8 +574,10 @@ static int max6650_remove(struct i2c_client *client)
 {
        struct max6650_data *data = i2c_get_clientdata(client);
 
-       sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
        hwmon_device_unregister(data->hwmon_dev);
+       if (data->nr_fans == 4)
+               sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp);
+       sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
        kfree(data);
        return 0;
 }
@@ -712,7 +690,7 @@ static struct max6650_data *max6650_update_device(struct device *dev)
                                                       MAX6650_REG_SPEED);
                data->config = i2c_smbus_read_byte_data(client,
                                                        MAX6650_REG_CONFIG);
-               for (i = 0; i < 4; i++) {
+               for (i = 0; i < data->nr_fans; i++) {
                        data->tach[i] = i2c_smbus_read_byte_data(client,
                                                                 tach_reg[i]);
                }
index 98799bab69ce44a19b61afc3ce7ab64074504da8..354770ed3186cdfa30ae07fcd829f5b46906f7e4 100644 (file)
@@ -707,6 +707,7 @@ do {                                                                        \
        struct sensor_device_attribute *a                               \
            = &data->_type##s[data->num_##_type##s].attribute;          \
        BUG_ON(data->num_attributes >= data->max_attributes);           \
+       sysfs_attr_init(&a->dev_attr.attr);                             \
        a->dev_attr.attr.name = _name;                                  \
        a->dev_attr.attr.mode = _mode;                                  \
        a->dev_attr.show = _show;                                       \
index 92b42db43bcfd9e5706c41bfb9049a26fd967b93..b39f52e2752a7bca54a1bb25c7083382b01aa52e 100644 (file)
@@ -232,6 +232,7 @@ static int s3c_hwmon_create_attr(struct device *dev,
 
        attr = &attrs->in;
        attr->index = channel;
+       sysfs_attr_init(&attr->dev_attr.attr);
        attr->dev_attr.attr.name  = attrs->in_name;
        attr->dev_attr.attr.mode  = S_IRUGO;
        attr->dev_attr.show = s3c_hwmon_ch_show;
@@ -249,6 +250,7 @@ static int s3c_hwmon_create_attr(struct device *dev,
 
                attr = &attrs->label;
                attr->index = channel;
+               sysfs_attr_init(&attr->dev_attr.attr);
                attr->dev_attr.attr.name  = attrs->label_name;
                attr->dev_attr.attr.mode  = S_IRUGO;
                attr->dev_attr.show = s3c_hwmon_label_show;
index 9a51dcca9b0db6410779c1bccb26b13d584b6676..020c87273ea11d6c60383889a8a9cccae7dfdf02 100644 (file)
@@ -52,6 +52,9 @@
 #define SCH5627_COMPANY_ID             0x5c
 #define SCH5627_PRIMARY_ID             0xa0
 
+#define SCH5627_CMD_READ               0x02
+#define SCH5627_CMD_WRITE              0x03
+
 #define SCH5627_REG_BUILD_CODE         0x39
 #define SCH5627_REG_BUILD_ID           0x3a
 #define SCH5627_REG_HWMON_ID           0x3c
@@ -94,11 +97,13 @@ static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = {
 struct sch5627_data {
        unsigned short addr;
        struct device *hwmon_dev;
+       u8 control;
        u8 temp_max[SCH5627_NO_TEMPS];
        u8 temp_crit[SCH5627_NO_TEMPS];
        u16 fan_min[SCH5627_NO_FANS];
 
        struct mutex update_lock;
+       unsigned long last_battery;     /* In jiffies */
        char valid;                     /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
        u16 temp[SCH5627_NO_TEMPS];
@@ -140,7 +145,7 @@ static inline void superio_exit(int base)
        release_region(base, 2);
 }
 
-static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg)
+static int sch5627_send_cmd(struct sch5627_data *data, u8 cmd, u16 reg, u8 v)
 {
        u8 val;
        int i;
@@ -163,10 +168,14 @@ static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg)
        outb(0x80, data->addr + 3);
 
        /* Write Request Packet Header */
-       outb(0x02, data->addr + 4); /* Access Type: VREG read */
+       outb(cmd, data->addr + 4); /* VREG Access Type read:0x02 write:0x03 */
        outb(0x01, data->addr + 5); /* # of Entries: 1 Byte (8-bit) */
        outb(0x04, data->addr + 2); /* Mailbox AP to first data entry loc. */
 
+       /* Write Value field */
+       if (cmd == SCH5627_CMD_WRITE)
+               outb(v, data->addr + 4);
+
        /* Write Address field */
        outb(reg & 0xff, data->addr + 6);
        outb(reg >> 8, data->addr + 7);
@@ -224,8 +233,22 @@ static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg)
         * But if we do that things don't work, so let's not.
         */
 
-       /* Read Data from Mailbox */
-       return inb(data->addr + 4);
+       /* Read Value field */
+       if (cmd == SCH5627_CMD_READ)
+               return inb(data->addr + 4);
+
+       return 0;
+}
+
+static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg)
+{
+       return sch5627_send_cmd(data, SCH5627_CMD_READ, reg, 0);
+}
+
+static int sch5627_write_virtual_reg(struct sch5627_data *data,
+                                    u16 reg, u8 val)
+{
+       return sch5627_send_cmd(data, SCH5627_CMD_WRITE, reg, val);
 }
 
 static int sch5627_read_virtual_reg16(struct sch5627_data *data, u16 reg)
@@ -272,6 +295,13 @@ static struct sch5627_data *sch5627_update_device(struct device *dev)
 
        mutex_lock(&data->update_lock);
 
+       /* Trigger a Vbat voltage measurement every 5 minutes */
+       if (time_after(jiffies, data->last_battery + 300 * HZ)) {
+               sch5627_write_virtual_reg(data, SCH5627_REG_CTRL,
+                                         data->control | 0x10);
+               data->last_battery = jiffies;
+       }
+
        /* Cache the values for 1 second */
        if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
                for (i = 0; i < SCH5627_NO_TEMPS; i++) {
@@ -696,11 +726,17 @@ static int __devinit sch5627_probe(struct platform_device *pdev)
                err = val;
                goto error;
        }
-       if (!(val & 0x01)) {
+       data->control = val;
+       if (!(data->control & 0x01)) {
                pr_err("hardware monitoring not enabled\n");
                err = -ENODEV;
                goto error;
        }
+       /* Trigger a Vbat voltage measurement, so that we get a valid reading
+          the first time we read Vbat */
+       sch5627_write_virtual_reg(data, SCH5627_REG_CTRL,
+                                 data->control | 0x10);
+       data->last_battery = jiffies;
 
        /*
         * Read limits, we do this only once as reading a register on
index 1f36c635d93341727c26976daedcd0c953e5b6ad..27a62711e0a6170c4d32fa1c608660af761b9a48 100644 (file)
@@ -258,7 +258,7 @@ static int __devinit env_probe(struct platform_device *op)
                goto out_sysfs_remove_group;
        }
 
-       dev_set_drvdata(&op->dev, p);
+       platform_set_drvdata(op, p);
        err = 0;
 
 out:
@@ -277,7 +277,7 @@ out_free:
 
 static int __devexit env_remove(struct platform_device *op)
 {
-       struct env *p = dev_get_drvdata(&op->dev);
+       struct env *p = platform_get_drvdata(op);
 
        if (p) {
                sysfs_remove_group(&op->dev.kobj, &env_group);
index 326652f673f7e0fc1b709320204046290e6c7ae7..646068e5100bac8c6e3e9840bd0ac53596e4728a 100644 (file)
@@ -79,6 +79,7 @@ config I2C_AMD8111
 config I2C_I801
        tristate "Intel 82801 (ICH/PCH)"
        depends on PCI
+       select CHECK_SIGNATURE if X86 && DMI
        help
          If you say yes to this option, support will be included for the Intel
          801 family of mainboard I2C interfaces.  Specifically, the following
@@ -101,6 +102,7 @@ config I2C_I801
            6 Series (PCH)
            Patsburg (PCH)
            DH89xxCC (PCH)
+           Panther Point (PCH)
 
          This driver can also be built as a module.  If so, the module
          will be called i2c-i801.
@@ -671,15 +673,19 @@ config I2C_XILINX
          will be called xilinx_i2c.
 
 config I2C_EG20T
-       tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH"
+       tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223)"
        depends on PCI
        help
          This driver is for PCH(Platform controller Hub) I2C of EG20T which
          is an IOH(Input/Output Hub) for x86 embedded processor.
          This driver can access PCH I2C bus device.
 
-         This driver also supports the ML7213, a companion chip for the
-         Atom E6xx series and compatible with the Intel EG20T PCH.
+         This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
+         Output Hub), ML7213 and ML7223.
+         ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is
+         for MP(Media Phone) use.
+         ML7213/ML7223 is companion chip for Intel Atom E6xx series.
+         ML7213/ML7223 is completely compatible for Intel EG20T PCH.
 
 comment "External I2C/SMBus adapter drivers"
 
index 878a12026af2e2fa1b89225563248fe597659c02..8abfa4a03ce1d7610f34417d7033581c39cb3a8f 100644 (file)
@@ -182,10 +182,12 @@ static DEFINE_MUTEX(pch_mutex);
 /* Definition for ML7213 by OKI SEMICONDUCTOR */
 #define PCI_VENDOR_ID_ROHM             0x10DB
 #define PCI_DEVICE_ID_ML7213_I2C       0x802D
+#define PCI_DEVICE_ID_ML7223_I2C       0x8010
 
 static struct pci_device_id __devinitdata pch_pcidev_id[] = {
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C),   1, },
        { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
+       { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, },
        {0,}
 };
 
index ec36208c9977a7dca0201dad5fcd21b6b922d163..ab26840d0c7087073dbbba598953ebfca699b7b9 100644 (file)
@@ -50,6 +50,7 @@
   Patsburg (PCH) IDF    0x1d71     32     hard     yes     yes     yes
   Patsburg (PCH) IDF    0x1d72     32     hard     yes     yes     yes
   DH89xxCC (PCH)        0x2330     32     hard     yes     yes     yes
+  Panther Point (PCH)   0x1e22     32     hard     yes     yes     yes
 
   Features supported by this driver:
   Software PEC                     no
 /* Older devices have their ID defined in <linux/pci_ids.h> */
 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS  0x1c22
 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS     0x1d22
-#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
 /* Patsburg also has three 'Integrated Device Function' SMBus controllers */
 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0        0x1d70
 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1        0x1d71
 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2        0x1d72
+#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
 #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS     0x2330
 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS        0x3b30
 
@@ -159,6 +160,8 @@ static struct pci_driver i801_driver;
 #define FEATURE_BLOCK_BUFFER   (1 << 1)
 #define FEATURE_BLOCK_PROC     (1 << 2)
 #define FEATURE_I2C_BLOCK_READ (1 << 3)
+/* Not really a feature, but it's convenient to handle it as such */
+#define FEATURE_IDF            (1 << 15)
 
 static const char *i801_feature_names[] = {
        "SMBus PEC",
@@ -629,12 +632,13 @@ static const struct pci_device_id i801_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) },
        { 0, }
 };
 
 MODULE_DEVICE_TABLE(pci, i801_ids);
 
-#if defined CONFIG_INPUT_APANEL || defined CONFIG_INPUT_APANEL_MODULE
+#if defined CONFIG_X86 && defined CONFIG_DMI
 static unsigned char apanel_addr;
 
 /* Scan the system ROM for the signature "FJKEYINF" */
@@ -664,11 +668,7 @@ static void __init input_apanel_init(void)
        }
        iounmap(bios);
 }
-#else
-static void __init input_apanel_init(void) {}
-#endif
 
-#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
 struct dmi_onboard_device_info {
        const char *name;
        u8 type;
@@ -734,7 +734,30 @@ static void __devinit dmi_check_onboard_devices(const struct dmi_header *dm,
                dmi_check_onboard_device(type, name, adap);
        }
 }
-#endif
+
+/* Register optional slaves */
+static void __devinit i801_probe_optional_slaves(struct i801_priv *priv)
+{
+       /* Only register slaves on main SMBus channel */
+       if (priv->features & FEATURE_IDF)
+               return;
+
+       if (apanel_addr) {
+               struct i2c_board_info info;
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               info.addr = apanel_addr;
+               strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
+               i2c_new_device(&priv->adapter, &info);
+       }
+
+       if (dmi_name_in_vendors("FUJITSU"))
+               dmi_walk(dmi_check_onboard_devices, &priv->adapter);
+}
+#else
+static void __init input_apanel_init(void) {}
+static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) {}
+#endif /* CONFIG_X86 && CONFIG_DMI */
 
 static int __devinit i801_probe(struct pci_dev *dev,
                                const struct pci_device_id *id)
@@ -754,6 +777,11 @@ static int __devinit i801_probe(struct pci_dev *dev,
 
        priv->pci_dev = dev;
        switch (dev->device) {
+       case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0:
+       case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1:
+       case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2:
+               priv->features |= FEATURE_IDF;
+               /* fall through */
        default:
                priv->features |= FEATURE_I2C_BLOCK_READ;
                /* fall through */
@@ -839,21 +867,7 @@ static int __devinit i801_probe(struct pci_dev *dev,
                goto exit_release;
        }
 
-       /* Register optional slaves */
-#if defined CONFIG_INPUT_APANEL || defined CONFIG_INPUT_APANEL_MODULE
-       if (apanel_addr) {
-               struct i2c_board_info info;
-
-               memset(&info, 0, sizeof(struct i2c_board_info));
-               info.addr = apanel_addr;
-               strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
-               i2c_new_device(&priv->adapter, &info);
-       }
-#endif
-#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
-       if (dmi_name_in_vendors("FUJITSU"))
-               dmi_walk(dmi_check_onboard_devices, &priv->adapter);
-#endif
+       i801_probe_optional_slaves(priv);
 
        pci_set_drvdata(dev, priv);
        return 0;
@@ -913,7 +927,8 @@ static struct pci_driver i801_driver = {
 
 static int __init i2c_i801_init(void)
 {
-       input_apanel_init();
+       if (dmi_name_in_vendors("FUJITSU"))
+               input_apanel_init();
        return pci_register_driver(&i801_driver);
 }
 
index e10e5cf3751a211058588bd33e66320b3dc48779..0c731ca69f1506d70b05da8c2d895c6493e4b1f3 100644 (file)
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
 
 #include <plat/i2c.h>
 
 /* maximum threshold value */
 #define MAX_I2C_FIFO_THRESHOLD 15
 
-/* per-transfer delay, required for the hardware to stabilize */
-#define I2C_DELAY              150
-
 enum i2c_status {
        I2C_NOP,
        I2C_ON_GOING,
@@ -120,9 +118,6 @@ enum i2c_operation {
        I2C_READ = 0x01
 };
 
-/* controller response timeout in ms */
-#define I2C_TIMEOUT_MS 2000
-
 /**
  * struct i2c_nmk_client - client specific data
  * @slave_adr: 7-bit slave address
@@ -151,6 +146,7 @@ struct i2c_nmk_client {
  * @stop: stop condition
  * @xfer_complete: acknowledge completion for a I2C message
  * @result: controller propogated result
+ * @busy: Busy doing transfer
  */
 struct nmk_i2c_dev {
        struct platform_device          *pdev;
@@ -163,6 +159,8 @@ struct nmk_i2c_dev {
        int                             stop;
        struct completion               xfer_complete;
        int                             result;
+       struct regulator                *regulator;
+       bool                            busy;
 };
 
 /* controller's abort causes */
@@ -209,7 +207,7 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
        writel((I2C_CR_FTX | I2C_CR_FRX), dev->virtbase + I2C_CR);
 
        for (i = 0; i < LOOP_ATTEMPTS; i++) {
-               timeout = jiffies + msecs_to_jiffies(I2C_TIMEOUT_MS);
+               timeout = jiffies + dev->adap.timeout;
 
                while (!time_after(jiffies, timeout)) {
                        if ((readl(dev->virtbase + I2C_CR) &
@@ -253,11 +251,9 @@ static int init_hw(struct nmk_i2c_dev *dev)
 {
        int stat;
 
-       clk_enable(dev->clk);
-
        stat = flush_i2c_fifo(dev);
        if (stat)
-               return stat;
+               goto exit;
 
        /* disable the controller */
        i2c_clr_bit(dev->virtbase + I2C_CR , I2C_CR_PE);
@@ -268,10 +264,8 @@ static int init_hw(struct nmk_i2c_dev *dev)
 
        dev->cli.operation = I2C_NO_OPERATION;
 
-       clk_disable(dev->clk);
-
-       udelay(I2C_DELAY);
-       return 0;
+exit:
+       return stat;
 }
 
 /* enable peripheral, master mode operation */
@@ -424,7 +418,7 @@ static int read_i2c(struct nmk_i2c_dev *dev)
                        dev->virtbase + I2C_IMSCR);
 
        timeout = wait_for_completion_interruptible_timeout(
-               &dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS));
+               &dev->xfer_complete, dev->adap.timeout);
 
        if (timeout < 0) {
                dev_err(&dev->pdev->dev,
@@ -434,14 +428,32 @@ static int read_i2c(struct nmk_i2c_dev *dev)
        }
 
        if (timeout == 0) {
-               /* controller has timedout, re-init the h/w */
-               dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n");
-               (void) init_hw(dev);
+               /* Controller timed out */
+               dev_err(&dev->pdev->dev, "read from slave 0x%x timed out\n",
+                               dev->cli.slave_adr);
                status = -ETIMEDOUT;
        }
        return status;
 }
 
+static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes)
+{
+       int count;
+
+       for (count = (no_bytes - 2);
+                       (count > 0) &&
+                       (dev->cli.count != 0);
+                       count--) {
+               /* write to the Tx FIFO */
+               writeb(*dev->cli.buffer,
+                       dev->virtbase + I2C_TFR);
+               dev->cli.buffer++;
+               dev->cli.count--;
+               dev->cli.xfer_bytes++;
+       }
+
+}
+
 /**
  * write_i2c() - Write data to I2C client.
  * @dev: private data of I2C Driver
@@ -469,8 +481,13 @@ static int write_i2c(struct nmk_i2c_dev *dev)
        init_completion(&dev->xfer_complete);
 
        /* enable interrupts by settings the masks */
-       irq_mask = (I2C_IT_TXFNE | I2C_IT_TXFOVR |
-                       I2C_IT_MAL | I2C_IT_BERR);
+       irq_mask = (I2C_IT_TXFOVR | I2C_IT_MAL | I2C_IT_BERR);
+
+       /* Fill the TX FIFO with transmit data */
+       fill_tx_fifo(dev, MAX_I2C_FIFO_THRESHOLD);
+
+       if (dev->cli.count != 0)
+               irq_mask |= I2C_IT_TXFNE;
 
        /*
         * check if we want to transfer a single or multiple bytes, if so
@@ -488,7 +505,7 @@ static int write_i2c(struct nmk_i2c_dev *dev)
                        dev->virtbase + I2C_IMSCR);
 
        timeout = wait_for_completion_interruptible_timeout(
-               &dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS));
+               &dev->xfer_complete, dev->adap.timeout);
 
        if (timeout < 0) {
                dev_err(&dev->pdev->dev,
@@ -498,15 +515,60 @@ static int write_i2c(struct nmk_i2c_dev *dev)
        }
 
        if (timeout == 0) {
-               /* controller has timedout, re-init the h/w */
-               dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n");
-               (void) init_hw(dev);
+               /* Controller timed out */
+               dev_err(&dev->pdev->dev, "write to slave 0x%x timed out\n",
+                               dev->cli.slave_adr);
                status = -ETIMEDOUT;
        }
 
        return status;
 }
 
+/**
+ * nmk_i2c_xfer_one() - transmit a single I2C message
+ * @dev: device with a message encoded into it
+ * @flags: message flags
+ */
+static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
+{
+       int status;
+
+       if (flags & I2C_M_RD) {
+               /* read operation */
+               dev->cli.operation = I2C_READ;
+               status = read_i2c(dev);
+       } else {
+               /* write operation */
+               dev->cli.operation = I2C_WRITE;
+               status = write_i2c(dev);
+       }
+
+       if (status || (dev->result)) {
+               u32 i2c_sr;
+               u32 cause;
+
+               i2c_sr = readl(dev->virtbase + I2C_SR);
+               /*
+                * Check if the controller I2C operation status
+                * is set to ABORT(11b).
+                */
+               if (((i2c_sr >> 2) & 0x3) == 0x3) {
+                       /* get the abort cause */
+                       cause = (i2c_sr >> 4) & 0x7;
+                       dev_err(&dev->pdev->dev, "%s\n", cause
+                               >= ARRAY_SIZE(abort_causes) ?
+                               "unknown reason" :
+                               abort_causes[cause]);
+               }
+
+               (void) init_hw(dev);
+
+               status = status ? status : dev->result;
+       }
+
+       return status;
+}
+
 /**
  * nmk_i2c_xfer() - I2C transfer function used by kernel framework
  * @i2c_adap: Adapter pointer to the controller
@@ -559,53 +621,55 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
 {
        int status;
        int i;
-       u32 cause;
        struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);
+       int j;
+
+       dev->busy = true;
+
+       if (dev->regulator)
+               regulator_enable(dev->regulator);
+       pm_runtime_get_sync(&dev->pdev->dev);
+
+       clk_enable(dev->clk);
 
        status = init_hw(dev);
        if (status)
-               return status;
+               goto out;
 
-       clk_enable(dev->clk);
+       /* Attempt three times to send the message queue */
+       for (j = 0; j < 3; j++) {
+               /* setup the i2c controller */
+               setup_i2c_controller(dev);
 
-       /* setup the i2c controller */
-       setup_i2c_controller(dev);
+               for (i = 0; i < num_msgs; i++) {
+                       if (unlikely(msgs[i].flags & I2C_M_TEN)) {
+                               dev_err(&dev->pdev->dev, "10 bit addressing"
+                                               "not supported\n");
 
-       for (i = 0; i < num_msgs; i++) {
-               if (unlikely(msgs[i].flags & I2C_M_TEN)) {
-                       dev_err(&dev->pdev->dev, "10 bit addressing"
-                                       "not supported\n");
-                       return -EINVAL;
-               }
-               dev->cli.slave_adr      = msgs[i].addr;
-               dev->cli.buffer         = msgs[i].buf;
-               dev->cli.count          = msgs[i].len;
-               dev->stop = (i < (num_msgs - 1)) ? 0 : 1;
-               dev->result = 0;
-
-               if (msgs[i].flags & I2C_M_RD) {
-                       /* it is a read operation */
-                       dev->cli.operation = I2C_READ;
-                       status = read_i2c(dev);
-               } else {
-                       /* write operation */
-                       dev->cli.operation = I2C_WRITE;
-                       status = write_i2c(dev);
-               }
-               if (status || (dev->result)) {
-                       /* get the abort cause */
-                       cause = (readl(dev->virtbase + I2C_SR) >> 4) & 0x7;
-                       dev_err(&dev->pdev->dev, "error during I2C"
-                                       "message xfer: %d\n", cause);
-                       dev_err(&dev->pdev->dev, "%s\n",
-                               cause >= ARRAY_SIZE(abort_causes)
-                               ? "unknown reason" : abort_causes[cause]);
-                       clk_disable(dev->clk);
-                       return status;
+                               status = -EINVAL;
+                               goto out;
+                       }
+                       dev->cli.slave_adr      = msgs[i].addr;
+                       dev->cli.buffer         = msgs[i].buf;
+                       dev->cli.count          = msgs[i].len;
+                       dev->stop = (i < (num_msgs - 1)) ? 0 : 1;
+                       dev->result = 0;
+
+                       status = nmk_i2c_xfer_one(dev, msgs[i].flags);
+                       if (status != 0)
+                               break;
                }
-               udelay(I2C_DELAY);
+               if (status == 0)
+                       break;
        }
+
+out:
        clk_disable(dev->clk);
+       pm_runtime_put_sync(&dev->pdev->dev);
+       if (dev->regulator)
+               regulator_disable(dev->regulator);
+
+       dev->busy = false;
 
        /* return the no. messages processed */
        if (status)
@@ -666,17 +730,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
                         */
                        disable_interrupts(dev, I2C_IT_TXFNE);
                } else {
-                       for (count = (MAX_I2C_FIFO_THRESHOLD - tft - 2);
-                                       (count > 0) &&
-                                       (dev->cli.count != 0);
-                                       count--) {
-                               /* write to the Tx FIFO */
-                               writeb(*dev->cli.buffer,
-                                       dev->virtbase + I2C_TFR);
-                               dev->cli.buffer++;
-                               dev->cli.count--;
-                               dev->cli.xfer_bytes++;
-                       }
+                       fill_tx_fifo(dev, (MAX_I2C_FIFO_THRESHOLD - tft));
                        /*
                         * if done, close the transfer by disabling the
                         * corresponding TXFNE interrupt
@@ -729,16 +783,11 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
                        }
                }
 
-               i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTD);
-               i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTDWS);
-
-               disable_interrupts(dev,
-                               (I2C_IT_TXFNE | I2C_IT_TXFE | I2C_IT_TXFF
-                                       | I2C_IT_TXFOVR | I2C_IT_RXFNF
-                                       | I2C_IT_RXFF | I2C_IT_RXFE));
+               disable_all_interrupts(dev);
+               clear_all_interrupts(dev);
 
                if (dev->cli.count) {
-                       dev->result = -1;
+                       dev->result = -EIO;
                        dev_err(&dev->pdev->dev, "%lu bytes still remain to be"
                                        "xfered\n", dev->cli.count);
                        (void) init_hw(dev);
@@ -749,7 +798,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
 
        /* Master Arbitration lost interrupt */
        case I2C_IT_MAL:
-               dev->result = -1;
+               dev->result = -EIO;
                (void) init_hw(dev);
 
                i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MAL);
@@ -763,7 +812,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
         * during the transaction.
         */
        case I2C_IT_BERR:
-               dev->result = -1;
+               dev->result = -EIO;
                /* get the status */
                if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT)
                        (void) init_hw(dev);
@@ -779,7 +828,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
         * the Tx FIFO is full.
         */
        case I2C_IT_TXFOVR:
-               dev->result = -1;
+               dev->result = -EIO;
                (void) init_hw(dev);
 
                dev_err(&dev->pdev->dev, "Tx Fifo Over run\n");
@@ -805,6 +854,38 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
+
+#ifdef CONFIG_PM
+static int nmk_i2c_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct nmk_i2c_dev *nmk_i2c = platform_get_drvdata(pdev);
+
+       if (nmk_i2c->busy)
+               return -EBUSY;
+
+       return 0;
+}
+
+static int nmk_i2c_resume(struct device *dev)
+{
+       return 0;
+}
+#else
+#define nmk_i2c_suspend        NULL
+#define nmk_i2c_resume NULL
+#endif
+
+/*
+ * We use noirq so that we suspend late and resume before the wakeup interrupt
+ * to ensure that we do the !pm_runtime_suspended() check in resume before
+ * there has been a regular pm runtime resume (via pm_runtime_get_sync()).
+ */
+static const struct dev_pm_ops nmk_i2c_pm = {
+       .suspend_noirq  = nmk_i2c_suspend,
+       .resume_noirq   = nmk_i2c_resume,
+};
+
 static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
 {
        return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
@@ -830,7 +911,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
                ret = -ENOMEM;
                goto err_no_mem;
        }
-
+       dev->busy = false;
        dev->pdev = pdev;
        platform_set_drvdata(pdev, dev);
 
@@ -860,6 +941,15 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
                goto err_irq;
        }
 
+       dev->regulator = regulator_get(&pdev->dev, "v-i2c");
+       if (IS_ERR(dev->regulator)) {
+               dev_warn(&pdev->dev, "could not get i2c regulator\n");
+               dev->regulator = NULL;
+       }
+
+       pm_suspend_ignore_children(&pdev->dev, true);
+       pm_runtime_enable(&pdev->dev);
+
        dev->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(dev->clk)) {
                dev_err(&pdev->dev, "could not get i2c clock\n");
@@ -872,6 +962,8 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
        adap->owner     = THIS_MODULE;
        adap->class     = I2C_CLASS_HWMON | I2C_CLASS_SPD;
        adap->algo      = &nmk_i2c_algo;
+       adap->timeout   = pdata->timeout ? msecs_to_jiffies(pdata->timeout) :
+               msecs_to_jiffies(20000);
        snprintf(adap->name, sizeof(adap->name),
                 "Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start);
 
@@ -887,12 +979,6 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
 
        i2c_set_adapdata(adap, dev);
 
-       ret = init_hw(dev);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "error in initializing i2c hardware\n");
-               goto err_init_hw;
-       }
-
        dev_info(&pdev->dev, "initialize %s on virtual "
                "base %p\n", adap->name, dev->virtbase);
 
@@ -904,10 +990,12 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
 
        return 0;
 
- err_init_hw:
  err_add_adap:
        clk_put(dev->clk);
  err_no_clk:
+       if (dev->regulator)
+               regulator_put(dev->regulator);
+       pm_runtime_disable(&pdev->dev);
        free_irq(dev->irq, dev);
  err_irq:
        iounmap(dev->virtbase);
@@ -938,6 +1026,9 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev)
        if (res)
                release_mem_region(res->start, resource_size(res));
        clk_put(dev->clk);
+       if (dev->regulator)
+               regulator_put(dev->regulator);
+       pm_runtime_disable(&pdev->dev);
        platform_set_drvdata(pdev, NULL);
        kfree(dev);
 
@@ -948,6 +1039,7 @@ static struct platform_driver nmk_i2c_driver = {
        .driver = {
                .owner = THIS_MODULE,
                .name = DRIVER_NAME,
+               .pm = &nmk_i2c_pm,
        },
        .probe = nmk_i2c_probe,
        .remove = __devexit_p(nmk_i2c_remove),
index fee1a2613861a8d1ea16d12b9e660dd0947df05c..1b46a9d9f907336fb70526ca93881ce3b3934950 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/wait.h>
@@ -306,7 +305,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
                return -EIO;
        }
 
-       pdata = mfd_get_data(pdev);
+       pdata = pdev->dev.platform_data;
        if (pdata) {
                i2c->regstep = pdata->regstep;
                i2c->clock_khz = pdata->clock_khz;
index fc5fbd1012c98af5a8b458a1b058ea5c2374e4e1..4b95f7a63a3b04de69618f80ea3f3a25c57273ce 100644 (file)
@@ -2,13 +2,13 @@
  * i2c-parport-light.c I2C bus over parallel port                           *
  * ------------------------------------------------------------------------ *
    Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
-   
+
    Based on older i2c-velleman.c driver
    Copyright (C) 1995-2000 Simon G. Vogl
    With some changes from:
    Frodo Looijaard <frodol@dds.nl>
    Kyösti Mälkki <kmalkki@cc.hut.fi>
-   
+
    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
@@ -114,7 +114,7 @@ static struct i2c_algo_bit_data parport_algo_data = {
        .getscl         = parport_getscl,
        .udelay         = 50,
        .timeout        = HZ,
-}; 
+};
 
 /* ----- Driver registration ---------------------------------------------- */
 
@@ -132,7 +132,7 @@ static struct i2c_smbus_alert_setup alert_data = {
 static struct i2c_client *ara;
 static struct lineop parport_ctrl_irq = {
        .val            = (1 << 4),
-       .port           = CTRL,
+       .port           = PORT_CTRL,
 };
 
 static int __devinit i2c_parport_probe(struct platform_device *pdev)
@@ -245,7 +245,7 @@ static int __init i2c_parport_init(void)
        if (irq != 0)
                pr_info(DRVNAME ": using irq %d\n", irq);
 
-        if (!adapter_parm[type].getscl.val)
+       if (!adapter_parm[type].getscl.val)
                parport_algo_data.getscl = NULL;
 
        /* Sets global pdev as a side effect */
index 2dbba163b10202cf51aba175f7ffbf9cfd57aea2..24565687ac9bc06548bfa8dd17bfb488bcd96291 100644 (file)
@@ -2,13 +2,13 @@
  * i2c-parport.c I2C bus over parallel port                                 *
  * ------------------------------------------------------------------------ *
    Copyright (C) 2003-2011 Jean Delvare <khali@linux-fr.org>
-   
+
    Based on older i2c-philips-par.c driver
    Copyright (C) 1995-2000 Simon G. Vogl
    With some changes from:
    Frodo Looijaard <frodol@dds.nl>
    Kyösti Mälkki <kmalkki@cc.hut.fi>
-   
+
    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
@@ -78,13 +78,13 @@ static unsigned char port_read_control(struct parport *p)
        return parport_read_control(p);
 }
 
-static void (*port_write[])(struct parport *, unsigned char) = {
+static void (* const port_write[])(struct parport *, unsigned char) = {
        port_write_data,
        NULL,
        port_write_control,
 };
 
-static unsigned char (*port_read[])(struct parport *) = {
+static unsigned char (* const port_read[])(struct parport *) = {
        port_read_data,
        port_read_status,
        port_read_control,
@@ -147,7 +147,7 @@ static const struct i2c_algo_bit_data parport_algo_data = {
        .getscl         = parport_getscl,
        .udelay         = 10, /* ~50 kbps */
        .timeout        = HZ,
-}; 
+};
 
 /* ----- I2c and parallel port call-back functions and structures --------- */
 
@@ -164,10 +164,10 @@ void i2c_parport_irq(void *data)
                        "SMBus alert received but no ARA client!\n");
 }
 
-static void i2c_parport_attach (struct parport *port)
+static void i2c_parport_attach(struct parport *port)
 {
        struct i2c_par *adapter;
-       
+
        adapter = kzalloc(sizeof(struct i2c_par), GFP_KERNEL);
        if (adapter == NULL) {
                printk(KERN_ERR "i2c-parport: Failed to kzalloc\n");
@@ -180,7 +180,7 @@ static void i2c_parport_attach (struct parport *port)
                NULL, NULL, i2c_parport_irq, PARPORT_FLAG_EXCL, adapter);
        if (!adapter->pdev) {
                printk(KERN_ERR "i2c-parport: Unable to register with parport\n");
-               goto ERROR0;
+               goto err_free;
        }
 
        /* Fill the rest of the structure */
@@ -200,7 +200,7 @@ static void i2c_parport_attach (struct parport *port)
 
        if (parport_claim_or_block(adapter->pdev) < 0) {
                printk(KERN_ERR "i2c-parport: Could not claim parallel port\n");
-               goto ERROR1;
+               goto err_unregister;
        }
 
        /* Reset hardware to a sane state (SCL and SDA high) */
@@ -215,7 +215,7 @@ static void i2c_parport_attach (struct parport *port)
 
        if (i2c_bit_add_bus(&adapter->adapter) < 0) {
                printk(KERN_ERR "i2c-parport: Unable to register with I2C\n");
-               goto ERROR1;
+               goto err_unregister;
        }
 
        /* Setup SMBus alert if supported */
@@ -234,16 +234,16 @@ static void i2c_parport_attach (struct parport *port)
        mutex_lock(&adapter_list_lock);
        list_add_tail(&adapter->node, &adapter_list);
        mutex_unlock(&adapter_list_lock);
-        return;
+       return;
 
-ERROR1:
+ err_unregister:
        parport_release(adapter->pdev);
        parport_unregister_device(adapter->pdev);
-ERROR0:
+ err_free:
        kfree(adapter);
 }
 
-static void i2c_parport_detach (struct parport *port)
+static void i2c_parport_detach(struct parport *port)
 {
        struct i2c_par *adapter, *_n;
 
@@ -260,7 +260,7 @@ static void i2c_parport_detach (struct parport *port)
                        /* Un-init if needed (power off...) */
                        if (adapter_parm[type].init.val)
                                line_set(port, 0, &adapter_parm[type].init);
-                               
+
                        parport_release(adapter->pdev);
                        parport_unregister_device(adapter->pdev);
                        list_del(&adapter->node);
index a9f66816546c519f9bd1cd31f54a21683f29d6b6..3fe652302ea7d2286bad2f5d9f0d696395d8a55c 100644 (file)
@@ -2,7 +2,7 @@
  * i2c-parport.h I2C bus over parallel port                                 *
  * ------------------------------------------------------------------------ *
    Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.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
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  * ------------------------------------------------------------------------ */
 
-#ifdef DATA
-#undef DATA
-#endif
-
-#define DATA   0
-#define STAT   1
-#define CTRL   2
+#define PORT_DATA      0
+#define PORT_STAT      1
+#define PORT_CTRL      2
 
 struct lineop {
        u8 val;
@@ -41,61 +37,61 @@ struct adapter_parm {
        unsigned int smbus_alert:1;
 };
 
-static struct adapter_parm adapter_parm[] = {
+static const struct adapter_parm adapter_parm[] = {
        /* type 0: Philips adapter */
        {
-               .setsda = { 0x80, DATA, 1 },
-               .setscl = { 0x08, CTRL, 0 },
-               .getsda = { 0x80, STAT, 0 },
-               .getscl = { 0x08, STAT, 0 },
+               .setsda = { 0x80, PORT_DATA, 1 },
+               .setscl = { 0x08, PORT_CTRL, 0 },
+               .getsda = { 0x80, PORT_STAT, 0 },
+               .getscl = { 0x08, PORT_STAT, 0 },
        },
        /* type 1: home brew teletext adapter */
        {
-               .setsda = { 0x02, DATA, 0 },
-               .setscl = { 0x01, DATA, 0 },
-               .getsda = { 0x80, STAT, 1 },
+               .setsda = { 0x02, PORT_DATA, 0 },
+               .setscl = { 0x01, PORT_DATA, 0 },
+               .getsda = { 0x80, PORT_STAT, 1 },
        },
        /* type 2: Velleman K8000 adapter */
        {
-               .setsda = { 0x02, CTRL, 1 },
-               .setscl = { 0x08, CTRL, 1 },
-               .getsda = { 0x10, STAT, 0 },
+               .setsda = { 0x02, PORT_CTRL, 1 },
+               .setscl = { 0x08, PORT_CTRL, 1 },
+               .getsda = { 0x10, PORT_STAT, 0 },
        },
        /* type 3: ELV adapter */
        {
-               .setsda = { 0x02, DATA, 1 },
-               .setscl = { 0x01, DATA, 1 },
-               .getsda = { 0x40, STAT, 1 },
-               .getscl = { 0x08, STAT, 1 },
+               .setsda = { 0x02, PORT_DATA, 1 },
+               .setscl = { 0x01, PORT_DATA, 1 },
+               .getsda = { 0x40, PORT_STAT, 1 },
+               .getscl = { 0x08, PORT_STAT, 1 },
        },
        /* type 4: ADM1032 evaluation board */
        {
-               .setsda = { 0x02, DATA, 1 },
-               .setscl = { 0x01, DATA, 1 },
-               .getsda = { 0x10, STAT, 1 },
-               .init   = { 0xf0, DATA, 0 },
+               .setsda = { 0x02, PORT_DATA, 1 },
+               .setscl = { 0x01, PORT_DATA, 1 },
+               .getsda = { 0x10, PORT_STAT, 1 },
+               .init   = { 0xf0, PORT_DATA, 0 },
                .smbus_alert = 1,
        },
        /* type 5: ADM1025, ADM1030 and ADM1031 evaluation boards */
        {
-               .setsda = { 0x02, DATA, 1 },
-               .setscl = { 0x01, DATA, 1 },
-               .getsda = { 0x10, STAT, 1 },
+               .setsda = { 0x02, PORT_DATA, 1 },
+               .setscl = { 0x01, PORT_DATA, 1 },
+               .getsda = { 0x10, PORT_STAT, 1 },
        },
        /* type 6: Barco LPT->DVI (K5800236) adapter */
        {
-               .setsda = { 0x02, DATA, 1 },
-               .setscl = { 0x01, DATA, 1 },
-               .getsda = { 0x20, STAT, 0 },
-               .getscl = { 0x40, STAT, 0 },
-               .init   = { 0xfc, DATA, 0 },
+               .setsda = { 0x02, PORT_DATA, 1 },
+               .setscl = { 0x01, PORT_DATA, 1 },
+               .getsda = { 0x20, PORT_STAT, 0 },
+               .getscl = { 0x40, PORT_STAT, 0 },
+               .init   = { 0xfc, PORT_DATA, 0 },
        },
        /* type 7: One For All JP1 parallel port adapter */
        {
-               .setsda = { 0x01, DATA, 0 },
-               .setscl = { 0x02, DATA, 0 },
-               .getsda = { 0x80, STAT, 1 },
-               .init   = { 0x04, DATA, 1 },
+               .setsda = { 0x01, PORT_DATA, 0 },
+               .setscl = { 0x02, PORT_DATA, 0 },
+               .getsda = { 0x80, PORT_STAT, 1 },
+               .init   = { 0x04, PORT_DATA, 1 },
        },
 };
 
index 81ccd7875627e0c1e28b2086b039685168fb39b8..f633a53b6dbe0bb3c43daecc345dfac5d4982e7e 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/i2c/i2c-sh_mobile.h>
 
 /* Transmit operation:                                                      */
 /*                                                                          */
@@ -117,7 +118,7 @@ struct sh_mobile_i2c_data {
        struct device *dev;
        void __iomem *reg;
        struct i2c_adapter adap;
-
+       unsigned long bus_speed;
        struct clk *clk;
        u_int8_t icic;
        u_int8_t iccl;
@@ -205,7 +206,7 @@ static void activate_ch(struct sh_mobile_i2c_data *pd)
         * We also round off the result.
         */
        num = i2c_clk * 5;
-       denom = NORMAL_SPEED * 9;
+       denom = pd->bus_speed * 9;
        tmp = num * 10 / denom;
        if (tmp % 10 >= 5)
                pd->iccl = (u_int8_t)((num/denom) + 1);
@@ -574,10 +575,10 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
 
 static int sh_mobile_i2c_probe(struct platform_device *dev)
 {
+       struct i2c_sh_mobile_platform_data *pdata = dev->dev.platform_data;
        struct sh_mobile_i2c_data *pd;
        struct i2c_adapter *adap;
        struct resource *res;
-       char clk_name[8];
        int size;
        int ret;
 
@@ -587,10 +588,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
                return -ENOMEM;
        }
 
-       snprintf(clk_name, sizeof(clk_name), "i2c%d", dev->id);
-       pd->clk = clk_get(&dev->dev, clk_name);
+       pd->clk = clk_get(&dev->dev, NULL);
        if (IS_ERR(pd->clk)) {
-               dev_err(&dev->dev, "cannot get clock \"%s\"\n", clk_name);
+               dev_err(&dev->dev, "cannot get clock\n");
                ret = PTR_ERR(pd->clk);
                goto err;
        }
@@ -620,6 +620,11 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
                goto err_irq;
        }
 
+       /* Use platformd data bus speed or NORMAL_SPEED */
+       pd->bus_speed = NORMAL_SPEED;
+       if (pdata && pdata->bus_speed)
+               pd->bus_speed = pdata->bus_speed;
+
        /* The IIC blocks on SH-Mobile ARM processors
         * come with two new bits in ICIC.
         */
@@ -660,6 +665,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
                goto err_all;
        }
 
+       dev_info(&dev->dev, "I2C adapter %d with bus speed %lu Hz\n",
+                adap->nr, pd->bus_speed);
        return 0;
 
  err_all:
index b4ab39b741eb768bd1a0d733b9329546fd0fe428..4d9319665e328176993886494516e208181c38aa 100644 (file)
 #define BYTES_PER_FIFO_WORD 4
 
 #define I2C_CNFG                               0x000
+#define I2C_CNFG_DEBOUNCE_CNT_SHIFT            12
 #define I2C_CNFG_PACKET_MODE_EN                        (1<<10)
 #define I2C_CNFG_NEW_MASTER_FSM                        (1<<11)
+#define I2C_STATUS                             0x01C
 #define I2C_SL_CNFG                            0x020
 #define I2C_SL_CNFG_NEWSL                      (1<<2)
 #define I2C_SL_ADDR1                           0x02c
@@ -77,6 +79,7 @@
 #define I2C_ERR_NONE                           0x00
 #define I2C_ERR_NO_ACK                         0x01
 #define I2C_ERR_ARBITRATION_LOST               0x02
+#define I2C_ERR_UNKNOWN_INTERRUPT              0x04
 
 #define PACKET_HEADER0_HEADER_SIZE_SHIFT       28
 #define PACKET_HEADER0_PACKET_ID_SHIFT         16
@@ -121,6 +124,7 @@ struct tegra_i2c_dev {
        void __iomem *base;
        int cont_id;
        int irq;
+       bool irq_disabled;
        int is_dvc;
        struct completion msg_complete;
        int msg_err;
@@ -325,11 +329,17 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
        if (i2c_dev->is_dvc)
                tegra_dvc_init(i2c_dev);
 
-       val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN;
+       val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN |
+               (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
        i2c_writel(i2c_dev, val, I2C_CNFG);
        i2c_writel(i2c_dev, 0, I2C_INT_MASK);
        clk_set_rate(i2c_dev->clk, i2c_dev->bus_clk_rate * 8);
 
+       if (!i2c_dev->is_dvc) {
+               u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
+               i2c_writel(i2c_dev, sl_cfg | I2C_SL_CNFG_NEWSL, I2C_SL_CNFG);
+       }
+
        val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT |
                0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT;
        i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
@@ -338,6 +348,12 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
                err = -ETIMEDOUT;
 
        clk_disable(i2c_dev->clk);
+
+       if (i2c_dev->irq_disabled) {
+               i2c_dev->irq_disabled = 0;
+               enable_irq(i2c_dev->irq);
+       }
+
        return err;
 }
 
@@ -350,8 +366,19 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
        status = i2c_readl(i2c_dev, I2C_INT_STATUS);
 
        if (status == 0) {
-               dev_warn(i2c_dev->dev, "interrupt with no status\n");
-               return IRQ_NONE;
+               dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
+                        i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
+                        i2c_readl(i2c_dev, I2C_STATUS),
+                        i2c_readl(i2c_dev, I2C_CNFG));
+               i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT;
+
+               if (!i2c_dev->irq_disabled) {
+                       disable_irq_nosync(i2c_dev->irq);
+                       i2c_dev->irq_disabled = 1;
+               }
+
+               complete(&i2c_dev->msg_complete);
+               goto err;
        }
 
        if (unlikely(status & status_err)) {
@@ -391,6 +418,8 @@ err:
                I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ |
                I2C_INT_RX_FIFO_DATA_REQ);
        i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+       if (i2c_dev->is_dvc)
+               dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
        return IRQ_HANDLED;
 }
 
@@ -424,12 +453,12 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 
        packet_header = msg->addr << I2C_HEADER_SLAVE_ADDR_SHIFT;
        packet_header |= I2C_HEADER_IE_ENABLE;
+       if (!stop)
+               packet_header |= I2C_HEADER_REPEAT_START;
        if (msg->flags & I2C_M_TEN)
                packet_header |= I2C_HEADER_10BIT_ADDR;
        if (msg->flags & I2C_M_IGNORE_NAK)
                packet_header |= I2C_HEADER_CONT_ON_NAK;
-       if (msg->flags & I2C_M_NOSTART)
-               packet_header |= I2C_HEADER_REPEAT_START;
        if (msg->flags & I2C_M_RD)
                packet_header |= I2C_HEADER_READ;
        i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
index e9d5ff4d14966c2a47bb98d57277933efd24b153..4bb68f35caf2efc30fdd0466a114ad0822e27d5a 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/wait.h>
@@ -705,7 +704,7 @@ static int __devinit xiic_i2c_probe(struct platform_device *pdev)
        if (irq < 0)
                goto resource_missing;
 
-       pdata = mfd_get_data(pdev);
+       pdata = (struct xiic_i2c_platform_data *) pdev->dev.platform_data;
        if (!pdata)
                return -EINVAL;
 
index a5ec5a7cb381bbffac45a13c9e2cdccfd0a7d8b0..04b09564bfa902bf84f6a313594112e74a1db2c6 100644 (file)
@@ -778,7 +778,8 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
                                        sector_t block)
 {
        struct ide_cmd cmd;
-       int uptodate = 0, nsectors;
+       int uptodate = 0;
+       unsigned int nsectors;
 
        ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, block: %llu",
                                  rq->cmd[0], (unsigned long long)block);
@@ -1781,7 +1782,7 @@ static int ide_cd_probe(ide_drive_t *drive)
 
        ide_cd_read_toc(drive, &sense);
        g->fops = &idecd_ops;
-       g->flags |= GENHD_FL_REMOVABLE;
+       g->flags |= GENHD_FL_REMOVABLE | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
        add_disk(g);
        return 0;
 
index 404843e8611b158d3feb1efc5a4c281d3fde660b..d2f3db3cf3ed523db978fa7e4f4d1adea9ef7c27 100644 (file)
@@ -272,7 +272,7 @@ static void ide_release(struct pcmcia_device *link)
 } /* ide_release */
 
 
-static struct pcmcia_device_id ide_ids[] = {
+static const struct pcmcia_device_id ide_ids[] = {
        PCMCIA_DEVICE_FUNC_ID(4),
        PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000),        /* Corsair */
        PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000),        /* Hitachi */
index 6e35eccc9caacb9677f771568a39583423056887..0f9a84c1046ab38776abe891ef0ff98ea0c19c98 100644 (file)
@@ -2,6 +2,7 @@ menuconfig INFINIBAND
        tristate "InfiniBand support"
        depends on PCI || BROKEN
        depends on HAS_IOMEM
+       depends on NET
        ---help---
          Core support for InfiniBand (IB).  Make sure to also select
          any protocols you wish to use as well as drivers for your
index cb1ab3ea49986f448474ce941c8e2f9cf7418b64..c8bbaef1becb1588c8051c214db9c378b39c37c3 100644 (file)
@@ -8,7 +8,7 @@ obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o \
                                        $(user_access-y)
 
 ib_core-y :=                   packer.o ud_header.o verbs.o sysfs.o \
-                               device.o fmr_pool.o cache.o
+                               device.o fmr_pool.o cache.o netlink.o
 ib_core-$(CONFIG_INFINIBAND_USER_MEM) += umem.o
 
 ib_mad-y :=                    mad.o smi.o agent.o mad_rmpp.o
index f804e28e1ebb5b9dc8ebdfdf8f4c53a81e9b8a72..f62f52fb9ece776000fb98dc830d52bf8bfb4f57 100644 (file)
@@ -3639,8 +3639,16 @@ static struct kobj_type cm_port_obj_type = {
        .release = cm_release_port_obj
 };
 
+static char *cm_devnode(struct device *dev, mode_t *mode)
+{
+       *mode = 0666;
+       return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev));
+}
+
 struct class cm_class = {
+       .owner   = THIS_MODULE,
        .name    = "infiniband_cm",
+       .devnode = cm_devnode,
 };
 EXPORT_SYMBOL(cm_class);
 
index 99dde874fbbdf53e93675643ac1b1e1bba372bd9..b6a33b3c516de9b8d1c12f0c20e958ff3608e9a5 100644 (file)
@@ -47,6 +47,7 @@
 
 #include <rdma/rdma_cm.h>
 #include <rdma/rdma_cm_ib.h>
+#include <rdma/rdma_netlink.h>
 #include <rdma/ib_cache.h>
 #include <rdma/ib_cm.h>
 #include <rdma/ib_sa.h>
@@ -89,20 +90,6 @@ struct cma_device {
        struct list_head        id_list;
 };
 
-enum cma_state {
-       CMA_IDLE,
-       CMA_ADDR_QUERY,
-       CMA_ADDR_RESOLVED,
-       CMA_ROUTE_QUERY,
-       CMA_ROUTE_RESOLVED,
-       CMA_CONNECT,
-       CMA_DISCONNECT,
-       CMA_ADDR_BOUND,
-       CMA_LISTEN,
-       CMA_DEVICE_REMOVAL,
-       CMA_DESTROYING
-};
-
 struct rdma_bind_list {
        struct idr              *ps;
        struct hlist_head       owners;
@@ -126,7 +113,7 @@ struct rdma_id_private {
        struct list_head        mc_list;
 
        int                     internal_id;
-       enum cma_state          state;
+       enum rdma_cm_state      state;
        spinlock_t              lock;
        struct mutex            qp_mutex;
 
@@ -146,6 +133,7 @@ struct rdma_id_private {
        u32                     seq_num;
        u32                     qkey;
        u32                     qp_num;
+       pid_t                   owner;
        u8                      srq;
        u8                      tos;
        u8                      reuseaddr;
@@ -165,8 +153,8 @@ struct cma_multicast {
 struct cma_work {
        struct work_struct      work;
        struct rdma_id_private  *id;
-       enum cma_state          old_state;
-       enum cma_state          new_state;
+       enum rdma_cm_state      old_state;
+       enum rdma_cm_state      new_state;
        struct rdma_cm_event    event;
 };
 
@@ -217,7 +205,7 @@ struct sdp_hah {
 #define CMA_VERSION 0x00
 #define SDP_MAJ_VERSION 0x2
 
-static int cma_comp(struct rdma_id_private *id_priv, enum cma_state comp)
+static int cma_comp(struct rdma_id_private *id_priv, enum rdma_cm_state comp)
 {
        unsigned long flags;
        int ret;
@@ -229,7 +217,7 @@ static int cma_comp(struct rdma_id_private *id_priv, enum cma_state comp)
 }
 
 static int cma_comp_exch(struct rdma_id_private *id_priv,
-                        enum cma_state comp, enum cma_state exch)
+                        enum rdma_cm_state comp, enum rdma_cm_state exch)
 {
        unsigned long flags;
        int ret;
@@ -241,11 +229,11 @@ static int cma_comp_exch(struct rdma_id_private *id_priv,
        return ret;
 }
 
-static enum cma_state cma_exch(struct rdma_id_private *id_priv,
-                              enum cma_state exch)
+static enum rdma_cm_state cma_exch(struct rdma_id_private *id_priv,
+                                  enum rdma_cm_state exch)
 {
        unsigned long flags;
-       enum cma_state old;
+       enum rdma_cm_state old;
 
        spin_lock_irqsave(&id_priv->lock, flags);
        old = id_priv->state;
@@ -279,11 +267,6 @@ static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver)
        hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF);
 }
 
-static inline int cma_is_ud_ps(enum rdma_port_space ps)
-{
-       return (ps == RDMA_PS_UDP || ps == RDMA_PS_IPOIB);
-}
-
 static void cma_attach_to_dev(struct rdma_id_private *id_priv,
                              struct cma_device *cma_dev)
 {
@@ -413,7 +396,7 @@ static void cma_deref_id(struct rdma_id_private *id_priv)
 }
 
 static int cma_disable_callback(struct rdma_id_private *id_priv,
-                             enum cma_state state)
+                               enum rdma_cm_state state)
 {
        mutex_lock(&id_priv->handler_mutex);
        if (id_priv->state != state) {
@@ -429,7 +412,8 @@ static int cma_has_cm_dev(struct rdma_id_private *id_priv)
 }
 
 struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler,
-                                 void *context, enum rdma_port_space ps)
+                                 void *context, enum rdma_port_space ps,
+                                 enum ib_qp_type qp_type)
 {
        struct rdma_id_private *id_priv;
 
@@ -437,10 +421,12 @@ struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler,
        if (!id_priv)
                return ERR_PTR(-ENOMEM);
 
-       id_priv->state = CMA_IDLE;
+       id_priv->owner = task_pid_nr(current);
+       id_priv->state = RDMA_CM_IDLE;
        id_priv->id.context = context;
        id_priv->id.event_handler = event_handler;
        id_priv->id.ps = ps;
+       id_priv->id.qp_type = qp_type;
        spin_lock_init(&id_priv->lock);
        mutex_init(&id_priv->qp_mutex);
        init_completion(&id_priv->comp);
@@ -508,7 +494,7 @@ int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd,
        if (IS_ERR(qp))
                return PTR_ERR(qp);
 
-       if (cma_is_ud_ps(id_priv->id.ps))
+       if (id->qp_type == IB_QPT_UD)
                ret = cma_init_ud_qp(id_priv, qp);
        else
                ret = cma_init_conn_qp(id_priv, qp);
@@ -636,7 +622,7 @@ static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv,
        qp_attr->port_num = id_priv->id.port_num;
        *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT;
 
-       if (cma_is_ud_ps(id_priv->id.ps)) {
+       if (id_priv->id.qp_type == IB_QPT_UD) {
                ret = cma_set_qkey(id_priv);
                if (ret)
                        return ret;
@@ -659,7 +645,7 @@ int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr,
        id_priv = container_of(id, struct rdma_id_private, id);
        switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
        case RDMA_TRANSPORT_IB:
-               if (!id_priv->cm_id.ib || cma_is_ud_ps(id_priv->id.ps))
+               if (!id_priv->cm_id.ib || (id_priv->id.qp_type == IB_QPT_UD))
                        ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask);
                else
                        ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr,
@@ -858,16 +844,16 @@ static void cma_cancel_listens(struct rdma_id_private *id_priv)
 }
 
 static void cma_cancel_operation(struct rdma_id_private *id_priv,
-                                enum cma_state state)
+                                enum rdma_cm_state state)
 {
        switch (state) {
-       case CMA_ADDR_QUERY:
+       case RDMA_CM_ADDR_QUERY:
                rdma_addr_cancel(&id_priv->id.route.addr.dev_addr);
                break;
-       case CMA_ROUTE_QUERY:
+       case RDMA_CM_ROUTE_QUERY:
                cma_cancel_route(id_priv);
                break;
-       case CMA_LISTEN:
+       case RDMA_CM_LISTEN:
                if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr)
                                && !id_priv->cma_dev)
                        cma_cancel_listens(id_priv);
@@ -918,10 +904,10 @@ static void cma_leave_mc_groups(struct rdma_id_private *id_priv)
 void rdma_destroy_id(struct rdma_cm_id *id)
 {
        struct rdma_id_private *id_priv;
-       enum cma_state state;
+       enum rdma_cm_state state;
 
        id_priv = container_of(id, struct rdma_id_private, id);
-       state = cma_exch(id_priv, CMA_DESTROYING);
+       state = cma_exch(id_priv, RDMA_CM_DESTROYING);
        cma_cancel_operation(id_priv, state);
 
        /*
@@ -1015,9 +1001,9 @@ static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
        int ret = 0;
 
        if ((ib_event->event != IB_CM_TIMEWAIT_EXIT &&
-               cma_disable_callback(id_priv, CMA_CONNECT)) ||
+               cma_disable_callback(id_priv, RDMA_CM_CONNECT)) ||
            (ib_event->event == IB_CM_TIMEWAIT_EXIT &&
-               cma_disable_callback(id_priv, CMA_DISCONNECT)))
+               cma_disable_callback(id_priv, RDMA_CM_DISCONNECT)))
                return 0;
 
        memset(&event, 0, sizeof event);
@@ -1048,7 +1034,8 @@ static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
                event.status = -ETIMEDOUT; /* fall through */
        case IB_CM_DREQ_RECEIVED:
        case IB_CM_DREP_RECEIVED:
-               if (!cma_comp_exch(id_priv, CMA_CONNECT, CMA_DISCONNECT))
+               if (!cma_comp_exch(id_priv, RDMA_CM_CONNECT,
+                                  RDMA_CM_DISCONNECT))
                        goto out;
                event.event = RDMA_CM_EVENT_DISCONNECTED;
                break;
@@ -1075,7 +1062,7 @@ static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
        if (ret) {
                /* Destroy the CM ID by returning a non-zero value. */
                id_priv->cm_id.ib = NULL;
-               cma_exch(id_priv, CMA_DESTROYING);
+               cma_exch(id_priv, RDMA_CM_DESTROYING);
                mutex_unlock(&id_priv->handler_mutex);
                rdma_destroy_id(&id_priv->id);
                return ret;
@@ -1101,7 +1088,7 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
                goto err;
 
        id = rdma_create_id(listen_id->event_handler, listen_id->context,
-                           listen_id->ps);
+                           listen_id->ps, ib_event->param.req_rcvd.qp_type);
        if (IS_ERR(id))
                goto err;
 
@@ -1132,7 +1119,7 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
        rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid);
 
        id_priv = container_of(id, struct rdma_id_private, id);
-       id_priv->state = CMA_CONNECT;
+       id_priv->state = RDMA_CM_CONNECT;
        return id_priv;
 
 destroy_id:
@@ -1152,7 +1139,7 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
        int ret;
 
        id = rdma_create_id(listen_id->event_handler, listen_id->context,
-                           listen_id->ps);
+                           listen_id->ps, IB_QPT_UD);
        if (IS_ERR(id))
                return NULL;
 
@@ -1172,7 +1159,7 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
        }
 
        id_priv = container_of(id, struct rdma_id_private, id);
-       id_priv->state = CMA_CONNECT;
+       id_priv->state = RDMA_CM_CONNECT;
        return id_priv;
 err:
        rdma_destroy_id(id);
@@ -1201,13 +1188,13 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
        int offset, ret;
 
        listen_id = cm_id->context;
-       if (cma_disable_callback(listen_id, CMA_LISTEN))
+       if (cma_disable_callback(listen_id, RDMA_CM_LISTEN))
                return -ECONNABORTED;
 
        memset(&event, 0, sizeof event);
        offset = cma_user_data_offset(listen_id->id.ps);
        event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
-       if (cma_is_ud_ps(listen_id->id.ps)) {
+       if (listen_id->id.qp_type == IB_QPT_UD) {
                conn_id = cma_new_udp_id(&listen_id->id, ib_event);
                event.param.ud.private_data = ib_event->private_data + offset;
                event.param.ud.private_data_len =
@@ -1243,8 +1230,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
                 * while we're accessing the cm_id.
                 */
                mutex_lock(&lock);
-               if (cma_comp(conn_id, CMA_CONNECT) &&
-                   !cma_is_ud_ps(conn_id->id.ps))
+               if (cma_comp(conn_id, RDMA_CM_CONNECT) && (conn_id->id.qp_type != IB_QPT_UD))
                        ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0);
                mutex_unlock(&lock);
                mutex_unlock(&conn_id->handler_mutex);
@@ -1257,7 +1243,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
        conn_id->cm_id.ib = NULL;
 
 release_conn_id:
-       cma_exch(conn_id, CMA_DESTROYING);
+       cma_exch(conn_id, RDMA_CM_DESTROYING);
        mutex_unlock(&conn_id->handler_mutex);
        rdma_destroy_id(&conn_id->id);
 
@@ -1328,7 +1314,7 @@ static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event)
        struct sockaddr_in *sin;
        int ret = 0;
 
-       if (cma_disable_callback(id_priv, CMA_CONNECT))
+       if (cma_disable_callback(id_priv, RDMA_CM_CONNECT))
                return 0;
 
        memset(&event, 0, sizeof event);
@@ -1371,7 +1357,7 @@ static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event)
        if (ret) {
                /* Destroy the CM ID by returning a non-zero value. */
                id_priv->cm_id.iw = NULL;
-               cma_exch(id_priv, CMA_DESTROYING);
+               cma_exch(id_priv, RDMA_CM_DESTROYING);
                mutex_unlock(&id_priv->handler_mutex);
                rdma_destroy_id(&id_priv->id);
                return ret;
@@ -1393,20 +1379,20 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
        struct ib_device_attr attr;
 
        listen_id = cm_id->context;
-       if (cma_disable_callback(listen_id, CMA_LISTEN))
+       if (cma_disable_callback(listen_id, RDMA_CM_LISTEN))
                return -ECONNABORTED;
 
        /* Create a new RDMA id for the new IW CM ID */
        new_cm_id = rdma_create_id(listen_id->id.event_handler,
                                   listen_id->id.context,
-                                  RDMA_PS_TCP);
+                                  RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(new_cm_id)) {
                ret = -ENOMEM;
                goto out;
        }
        conn_id = container_of(new_cm_id, struct rdma_id_private, id);
        mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING);
-       conn_id->state = CMA_CONNECT;
+       conn_id->state = RDMA_CM_CONNECT;
 
        dev = ip_dev_find(&init_net, iw_event->local_addr.sin_addr.s_addr);
        if (!dev) {
@@ -1461,7 +1447,7 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
        if (ret) {
                /* User wants to destroy the CM ID */
                conn_id->cm_id.iw = NULL;
-               cma_exch(conn_id, CMA_DESTROYING);
+               cma_exch(conn_id, RDMA_CM_DESTROYING);
                mutex_unlock(&conn_id->handler_mutex);
                cma_deref_id(conn_id);
                rdma_destroy_id(&conn_id->id);
@@ -1548,13 +1534,14 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
        struct rdma_cm_id *id;
        int ret;
 
-       id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps);
+       id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps,
+                           id_priv->id.qp_type);
        if (IS_ERR(id))
                return;
 
        dev_id_priv = container_of(id, struct rdma_id_private, id);
 
-       dev_id_priv->state = CMA_ADDR_BOUND;
+       dev_id_priv->state = RDMA_CM_ADDR_BOUND;
        memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr,
               ip_addr_size((struct sockaddr *) &id_priv->id.route.addr.src_addr));
 
@@ -1601,8 +1588,8 @@ static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec,
                route->num_paths = 1;
                *route->path_rec = *path_rec;
        } else {
-               work->old_state = CMA_ROUTE_QUERY;
-               work->new_state = CMA_ADDR_RESOLVED;
+               work->old_state = RDMA_CM_ROUTE_QUERY;
+               work->new_state = RDMA_CM_ADDR_RESOLVED;
                work->event.event = RDMA_CM_EVENT_ROUTE_ERROR;
                work->event.status = status;
        }
@@ -1660,7 +1647,7 @@ static void cma_work_handler(struct work_struct *_work)
                goto out;
 
        if (id_priv->id.event_handler(&id_priv->id, &work->event)) {
-               cma_exch(id_priv, CMA_DESTROYING);
+               cma_exch(id_priv, RDMA_CM_DESTROYING);
                destroy = 1;
        }
 out:
@@ -1678,12 +1665,12 @@ static void cma_ndev_work_handler(struct work_struct *_work)
        int destroy = 0;
 
        mutex_lock(&id_priv->handler_mutex);
-       if (id_priv->state == CMA_DESTROYING ||
-           id_priv->state == CMA_DEVICE_REMOVAL)
+       if (id_priv->state == RDMA_CM_DESTROYING ||
+           id_priv->state == RDMA_CM_DEVICE_REMOVAL)
                goto out;
 
        if (id_priv->id.event_handler(&id_priv->id, &work->event)) {
-               cma_exch(id_priv, CMA_DESTROYING);
+               cma_exch(id_priv, RDMA_CM_DESTROYING);
                destroy = 1;
        }
 
@@ -1707,8 +1694,8 @@ static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms)
 
        work->id = id_priv;
        INIT_WORK(&work->work, cma_work_handler);
-       work->old_state = CMA_ROUTE_QUERY;
-       work->new_state = CMA_ROUTE_RESOLVED;
+       work->old_state = RDMA_CM_ROUTE_QUERY;
+       work->new_state = RDMA_CM_ROUTE_RESOLVED;
        work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
 
        route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL);
@@ -1737,7 +1724,8 @@ int rdma_set_ib_paths(struct rdma_cm_id *id,
        int ret;
 
        id_priv = container_of(id, struct rdma_id_private, id);
-       if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_RESOLVED))
+       if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED,
+                          RDMA_CM_ROUTE_RESOLVED))
                return -EINVAL;
 
        id->route.path_rec = kmemdup(path_rec, sizeof *path_rec * num_paths,
@@ -1750,7 +1738,7 @@ int rdma_set_ib_paths(struct rdma_cm_id *id,
        id->route.num_paths = num_paths;
        return 0;
 err:
-       cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_ADDR_RESOLVED);
+       cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_ADDR_RESOLVED);
        return ret;
 }
 EXPORT_SYMBOL(rdma_set_ib_paths);
@@ -1765,8 +1753,8 @@ static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms)
 
        work->id = id_priv;
        INIT_WORK(&work->work, cma_work_handler);
-       work->old_state = CMA_ROUTE_QUERY;
-       work->new_state = CMA_ROUTE_RESOLVED;
+       work->old_state = RDMA_CM_ROUTE_QUERY;
+       work->new_state = RDMA_CM_ROUTE_RESOLVED;
        work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
        queue_work(cma_wq, &work->work);
        return 0;
@@ -1830,8 +1818,8 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
                goto err2;
        }
 
-       work->old_state = CMA_ROUTE_QUERY;
-       work->new_state = CMA_ROUTE_RESOLVED;
+       work->old_state = RDMA_CM_ROUTE_QUERY;
+       work->new_state = RDMA_CM_ROUTE_RESOLVED;
        work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
        work->event.status = 0;
 
@@ -1853,7 +1841,7 @@ int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
        int ret;
 
        id_priv = container_of(id, struct rdma_id_private, id);
-       if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_QUERY))
+       if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, RDMA_CM_ROUTE_QUERY))
                return -EINVAL;
 
        atomic_inc(&id_priv->refcount);
@@ -1882,7 +1870,7 @@ int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
 
        return 0;
 err:
-       cma_comp_exch(id_priv, CMA_ROUTE_QUERY, CMA_ADDR_RESOLVED);
+       cma_comp_exch(id_priv, RDMA_CM_ROUTE_QUERY, RDMA_CM_ADDR_RESOLVED);
        cma_deref_id(id_priv);
        return ret;
 }
@@ -1941,14 +1929,16 @@ static void addr_handler(int status, struct sockaddr *src_addr,
 
        memset(&event, 0, sizeof event);
        mutex_lock(&id_priv->handler_mutex);
-       if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED))
+       if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY,
+                          RDMA_CM_ADDR_RESOLVED))
                goto out;
 
        if (!status && !id_priv->cma_dev)
                status = cma_acquire_dev(id_priv);
 
        if (status) {
-               if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ADDR_BOUND))
+               if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED,
+                                  RDMA_CM_ADDR_BOUND))
                        goto out;
                event.event = RDMA_CM_EVENT_ADDR_ERROR;
                event.status = status;
@@ -1959,7 +1949,7 @@ static void addr_handler(int status, struct sockaddr *src_addr,
        }
 
        if (id_priv->id.event_handler(&id_priv->id, &event)) {
-               cma_exch(id_priv, CMA_DESTROYING);
+               cma_exch(id_priv, RDMA_CM_DESTROYING);
                mutex_unlock(&id_priv->handler_mutex);
                cma_deref_id(id_priv);
                rdma_destroy_id(&id_priv->id);
@@ -2004,8 +1994,8 @@ static int cma_resolve_loopback(struct rdma_id_private *id_priv)
 
        work->id = id_priv;
        INIT_WORK(&work->work, cma_work_handler);
-       work->old_state = CMA_ADDR_QUERY;
-       work->new_state = CMA_ADDR_RESOLVED;
+       work->old_state = RDMA_CM_ADDR_QUERY;
+       work->new_state = RDMA_CM_ADDR_RESOLVED;
        work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
        queue_work(cma_wq, &work->work);
        return 0;
@@ -2034,13 +2024,13 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
        int ret;
 
        id_priv = container_of(id, struct rdma_id_private, id);
-       if (id_priv->state == CMA_IDLE) {
+       if (id_priv->state == RDMA_CM_IDLE) {
                ret = cma_bind_addr(id, src_addr, dst_addr);
                if (ret)
                        return ret;
        }
 
-       if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_ADDR_QUERY))
+       if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY))
                return -EINVAL;
 
        atomic_inc(&id_priv->refcount);
@@ -2056,7 +2046,7 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
 
        return 0;
 err:
-       cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND);
+       cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND);
        cma_deref_id(id_priv);
        return ret;
 }
@@ -2070,7 +2060,7 @@ int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse)
 
        id_priv = container_of(id, struct rdma_id_private, id);
        spin_lock_irqsave(&id_priv->lock, flags);
-       if (id_priv->state == CMA_IDLE) {
+       if (id_priv->state == RDMA_CM_IDLE) {
                id_priv->reuseaddr = reuse;
                ret = 0;
        } else {
@@ -2177,7 +2167,7 @@ static int cma_check_port(struct rdma_bind_list *bind_list,
                if (id_priv == cur_id)
                        continue;
 
-               if ((cur_id->state == CMA_LISTEN) ||
+               if ((cur_id->state == RDMA_CM_LISTEN) ||
                    !reuseaddr || !cur_id->reuseaddr) {
                        cur_addr = (struct sockaddr *) &cur_id->id.route.addr.src_addr;
                        if (cma_any_addr(cur_addr))
@@ -2280,14 +2270,14 @@ int rdma_listen(struct rdma_cm_id *id, int backlog)
        int ret;
 
        id_priv = container_of(id, struct rdma_id_private, id);
-       if (id_priv->state == CMA_IDLE) {
+       if (id_priv->state == RDMA_CM_IDLE) {
                ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET;
                ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr);
                if (ret)
                        return ret;
        }
 
-       if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_LISTEN))
+       if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_LISTEN))
                return -EINVAL;
 
        if (id_priv->reuseaddr) {
@@ -2319,7 +2309,7 @@ int rdma_listen(struct rdma_cm_id *id, int backlog)
        return 0;
 err:
        id_priv->backlog = 0;
-       cma_comp_exch(id_priv, CMA_LISTEN, CMA_ADDR_BOUND);
+       cma_comp_exch(id_priv, RDMA_CM_LISTEN, RDMA_CM_ADDR_BOUND);
        return ret;
 }
 EXPORT_SYMBOL(rdma_listen);
@@ -2333,7 +2323,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
                return -EAFNOSUPPORT;
 
        id_priv = container_of(id, struct rdma_id_private, id);
-       if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND))
+       if (!cma_comp_exch(id_priv, RDMA_CM_IDLE, RDMA_CM_ADDR_BOUND))
                return -EINVAL;
 
        ret = cma_check_linklocal(&id->route.addr.dev_addr, addr);
@@ -2360,7 +2350,7 @@ err2:
        if (id_priv->cma_dev)
                cma_release_dev(id_priv);
 err1:
-       cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_IDLE);
+       cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE);
        return ret;
 }
 EXPORT_SYMBOL(rdma_bind_addr);
@@ -2433,7 +2423,7 @@ static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
        struct ib_cm_sidr_rep_event_param *rep = &ib_event->param.sidr_rep_rcvd;
        int ret = 0;
 
-       if (cma_disable_callback(id_priv, CMA_CONNECT))
+       if (cma_disable_callback(id_priv, RDMA_CM_CONNECT))
                return 0;
 
        memset(&event, 0, sizeof event);
@@ -2479,7 +2469,7 @@ static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
        if (ret) {
                /* Destroy the CM ID by returning a non-zero value. */
                id_priv->cm_id.ib = NULL;
-               cma_exch(id_priv, CMA_DESTROYING);
+               cma_exch(id_priv, RDMA_CM_DESTROYING);
                mutex_unlock(&id_priv->handler_mutex);
                rdma_destroy_id(&id_priv->id);
                return ret;
@@ -2645,7 +2635,7 @@ int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
        int ret;
 
        id_priv = container_of(id, struct rdma_id_private, id);
-       if (!cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_CONNECT))
+       if (!cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_CONNECT))
                return -EINVAL;
 
        if (!id->qp) {
@@ -2655,7 +2645,7 @@ int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
 
        switch (rdma_node_get_transport(id->device->node_type)) {
        case RDMA_TRANSPORT_IB:
-               if (cma_is_ud_ps(id->ps))
+               if (id->qp_type == IB_QPT_UD)
                        ret = cma_resolve_ib_udp(id_priv, conn_param);
                else
                        ret = cma_connect_ib(id_priv, conn_param);
@@ -2672,7 +2662,7 @@ int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
 
        return 0;
 err:
-       cma_comp_exch(id_priv, CMA_CONNECT, CMA_ROUTE_RESOLVED);
+       cma_comp_exch(id_priv, RDMA_CM_CONNECT, RDMA_CM_ROUTE_RESOLVED);
        return ret;
 }
 EXPORT_SYMBOL(rdma_connect);
@@ -2758,7 +2748,10 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
        int ret;
 
        id_priv = container_of(id, struct rdma_id_private, id);
-       if (!cma_comp(id_priv, CMA_CONNECT))
+
+       id_priv->owner = task_pid_nr(current);
+
+       if (!cma_comp(id_priv, RDMA_CM_CONNECT))
                return -EINVAL;
 
        if (!id->qp && conn_param) {
@@ -2768,7 +2761,7 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
 
        switch (rdma_node_get_transport(id->device->node_type)) {
        case RDMA_TRANSPORT_IB:
-               if (cma_is_ud_ps(id->ps))
+               if (id->qp_type == IB_QPT_UD)
                        ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
                                                conn_param->private_data,
                                                conn_param->private_data_len);
@@ -2829,7 +2822,7 @@ int rdma_reject(struct rdma_cm_id *id, const void *private_data,
 
        switch (rdma_node_get_transport(id->device->node_type)) {
        case RDMA_TRANSPORT_IB:
-               if (cma_is_ud_ps(id->ps))
+               if (id->qp_type == IB_QPT_UD)
                        ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT,
                                                private_data, private_data_len);
                else
@@ -2887,8 +2880,8 @@ static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast)
        int ret;
 
        id_priv = mc->id_priv;
-       if (cma_disable_callback(id_priv, CMA_ADDR_BOUND) &&
-           cma_disable_callback(id_priv, CMA_ADDR_RESOLVED))
+       if (cma_disable_callback(id_priv, RDMA_CM_ADDR_BOUND) &&
+           cma_disable_callback(id_priv, RDMA_CM_ADDR_RESOLVED))
                return 0;
 
        mutex_lock(&id_priv->qp_mutex);
@@ -2912,7 +2905,7 @@ static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast)
 
        ret = id_priv->id.event_handler(&id_priv->id, &event);
        if (ret) {
-               cma_exch(id_priv, CMA_DESTROYING);
+               cma_exch(id_priv, RDMA_CM_DESTROYING);
                mutex_unlock(&id_priv->handler_mutex);
                rdma_destroy_id(&id_priv->id);
                return 0;
@@ -3095,8 +3088,8 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
        int ret;
 
        id_priv = container_of(id, struct rdma_id_private, id);
-       if (!cma_comp(id_priv, CMA_ADDR_BOUND) &&
-           !cma_comp(id_priv, CMA_ADDR_RESOLVED))
+       if (!cma_comp(id_priv, RDMA_CM_ADDR_BOUND) &&
+           !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED))
                return -EINVAL;
 
        mc = kmalloc(sizeof *mc, GFP_KERNEL);
@@ -3261,19 +3254,19 @@ static void cma_add_one(struct ib_device *device)
 static int cma_remove_id_dev(struct rdma_id_private *id_priv)
 {
        struct rdma_cm_event event;
-       enum cma_state state;
+       enum rdma_cm_state state;
        int ret = 0;
 
        /* Record that we want to remove the device */
-       state = cma_exch(id_priv, CMA_DEVICE_REMOVAL);
-       if (state == CMA_DESTROYING)
+       state = cma_exch(id_priv, RDMA_CM_DEVICE_REMOVAL);
+       if (state == RDMA_CM_DESTROYING)
                return 0;
 
        cma_cancel_operation(id_priv, state);
        mutex_lock(&id_priv->handler_mutex);
 
        /* Check for destruction from another callback. */
-       if (!cma_comp(id_priv, CMA_DEVICE_REMOVAL))
+       if (!cma_comp(id_priv, RDMA_CM_DEVICE_REMOVAL))
                goto out;
 
        memset(&event, 0, sizeof event);
@@ -3328,6 +3321,100 @@ static void cma_remove_one(struct ib_device *device)
        kfree(cma_dev);
 }
 
+static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       struct nlmsghdr *nlh;
+       struct rdma_cm_id_stats *id_stats;
+       struct rdma_id_private *id_priv;
+       struct rdma_cm_id *id = NULL;
+       struct cma_device *cma_dev;
+       int i_dev = 0, i_id = 0;
+
+       /*
+        * We export all of the IDs as a sequence of messages.  Each
+        * ID gets its own netlink message.
+        */
+       mutex_lock(&lock);
+
+       list_for_each_entry(cma_dev, &dev_list, list) {
+               if (i_dev < cb->args[0]) {
+                       i_dev++;
+                       continue;
+               }
+
+               i_id = 0;
+               list_for_each_entry(id_priv, &cma_dev->id_list, list) {
+                       if (i_id < cb->args[1]) {
+                               i_id++;
+                               continue;
+                       }
+
+                       id_stats = ibnl_put_msg(skb, &nlh, cb->nlh->nlmsg_seq,
+                                               sizeof *id_stats, RDMA_NL_RDMA_CM,
+                                               RDMA_NL_RDMA_CM_ID_STATS);
+                       if (!id_stats)
+                               goto out;
+
+                       memset(id_stats, 0, sizeof *id_stats);
+                       id = &id_priv->id;
+                       id_stats->node_type = id->route.addr.dev_addr.dev_type;
+                       id_stats->port_num = id->port_num;
+                       id_stats->bound_dev_if =
+                               id->route.addr.dev_addr.bound_dev_if;
+
+                       if (id->route.addr.src_addr.ss_family == AF_INET) {
+                               if (ibnl_put_attr(skb, nlh,
+                                                 sizeof(struct sockaddr_in),
+                                                 &id->route.addr.src_addr,
+                                                 RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) {
+                                       goto out;
+                               }
+                               if (ibnl_put_attr(skb, nlh,
+                                                 sizeof(struct sockaddr_in),
+                                                 &id->route.addr.dst_addr,
+                                                 RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) {
+                                       goto out;
+                               }
+                       } else if (id->route.addr.src_addr.ss_family == AF_INET6) {
+                               if (ibnl_put_attr(skb, nlh,
+                                                 sizeof(struct sockaddr_in6),
+                                                 &id->route.addr.src_addr,
+                                                 RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) {
+                                       goto out;
+                               }
+                               if (ibnl_put_attr(skb, nlh,
+                                                 sizeof(struct sockaddr_in6),
+                                                 &id->route.addr.dst_addr,
+                                                 RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) {
+                                       goto out;
+                               }
+                       }
+
+                       id_stats->pid           = id_priv->owner;
+                       id_stats->port_space    = id->ps;
+                       id_stats->cm_state      = id_priv->state;
+                       id_stats->qp_num        = id_priv->qp_num;
+                       id_stats->qp_type       = id->qp_type;
+
+                       i_id++;
+               }
+
+               cb->args[1] = 0;
+               i_dev++;
+       }
+
+out:
+       mutex_unlock(&lock);
+       cb->args[0] = i_dev;
+       cb->args[1] = i_id;
+
+       return skb->len;
+}
+
+static const struct ibnl_client_cbs cma_cb_table[] = {
+       [RDMA_NL_RDMA_CM_ID_STATS] = { .dump = cma_get_id_stats },
+};
+
 static int __init cma_init(void)
 {
        int ret;
@@ -3343,6 +3430,10 @@ static int __init cma_init(void)
        ret = ib_register_client(&cma_client);
        if (ret)
                goto err;
+
+       if (ibnl_add_client(RDMA_NL_RDMA_CM, RDMA_NL_RDMA_CM_NUM_OPS, cma_cb_table))
+               printk(KERN_WARNING "RDMA CMA: failed to add netlink callback\n");
+
        return 0;
 
 err:
@@ -3355,6 +3446,7 @@ err:
 
 static void __exit cma_cleanup(void)
 {
+       ibnl_remove_client(RDMA_NL_RDMA_CM);
        ib_unregister_client(&cma_client);
        unregister_netdevice_notifier(&cma_nb);
        rdma_addr_unregister_client(&addr_client);
index f793bf2f5da7cf035d6f05da681aea7473cfd4ea..4007f721d25d2dda4bfb176802d06fb71705fe65 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/mutex.h>
+#include <rdma/rdma_netlink.h>
 
 #include "core_priv.h"
 
@@ -725,22 +726,40 @@ static int __init ib_core_init(void)
                return -ENOMEM;
 
        ret = ib_sysfs_setup();
-       if (ret)
+       if (ret) {
                printk(KERN_WARNING "Couldn't create InfiniBand device class\n");
+               goto err;
+       }
+
+       ret = ibnl_init();
+       if (ret) {
+               printk(KERN_WARNING "Couldn't init IB netlink interface\n");
+               goto err_sysfs;
+       }
 
        ret = ib_cache_setup();
        if (ret) {
                printk(KERN_WARNING "Couldn't set up InfiniBand P_Key/GID cache\n");
-               ib_sysfs_cleanup();
-               destroy_workqueue(ib_wq);
+               goto err_nl;
        }
 
+       return 0;
+
+err_nl:
+       ibnl_cleanup();
+
+err_sysfs:
+       ib_sysfs_cleanup();
+
+err:
+       destroy_workqueue(ib_wq);
        return ret;
 }
 
 static void __exit ib_core_cleanup(void)
 {
        ib_cache_cleanup();
+       ibnl_cleanup();
        ib_sysfs_cleanup();
        /* Make sure that any pending umem accounting work is done. */
        destroy_workqueue(ib_wq);
index 822cfdcd9f785af9fffb9a2b2b9b9f037b328e33..b4d8672a3e4ef539481a4089cc25f8c7b8f38901 100644 (file)
@@ -276,6 +276,13 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device,
                goto error1;
        }
 
+       /* Verify the QP requested is supported.  For example, Ethernet devices
+        * will not have QP0 */
+       if (!port_priv->qp_info[qpn].qp) {
+               ret = ERR_PTR(-EPROTONOSUPPORT);
+               goto error1;
+       }
+
        /* Allocate structures */
        mad_agent_priv = kzalloc(sizeof *mad_agent_priv, GFP_KERNEL);
        if (!mad_agent_priv) {
diff --git a/drivers/infiniband/core/netlink.c b/drivers/infiniband/core/netlink.c
new file mode 100644 (file)
index 0000000..4a5abaf
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2010 Voltaire Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
+
+#include <net/netlink.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+#include <rdma/rdma_netlink.h>
+
+struct ibnl_client {
+       struct list_head                list;
+       int                             index;
+       int                             nops;
+       const struct ibnl_client_cbs   *cb_table;
+};
+
+static DEFINE_MUTEX(ibnl_mutex);
+static struct sock *nls;
+static LIST_HEAD(client_list);
+
+int ibnl_add_client(int index, int nops,
+                   const struct ibnl_client_cbs cb_table[])
+{
+       struct ibnl_client *cur;
+       struct ibnl_client *nl_client;
+
+       nl_client = kmalloc(sizeof *nl_client, GFP_KERNEL);
+       if (!nl_client)
+               return -ENOMEM;
+
+       nl_client->index        = index;
+       nl_client->nops         = nops;
+       nl_client->cb_table     = cb_table;
+
+       mutex_lock(&ibnl_mutex);
+
+       list_for_each_entry(cur, &client_list, list) {
+               if (cur->index == index) {
+                       pr_warn("Client for %d already exists\n", index);
+                       mutex_unlock(&ibnl_mutex);
+                       kfree(nl_client);
+                       return -EINVAL;
+               }
+       }
+
+       list_add_tail(&nl_client->list, &client_list);
+
+       mutex_unlock(&ibnl_mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL(ibnl_add_client);
+
+int ibnl_remove_client(int index)
+{
+       struct ibnl_client *cur, *next;
+
+       mutex_lock(&ibnl_mutex);
+       list_for_each_entry_safe(cur, next, &client_list, list) {
+               if (cur->index == index) {
+                       list_del(&(cur->list));
+                       mutex_unlock(&ibnl_mutex);
+                       kfree(cur);
+                       return 0;
+               }
+       }
+       pr_warn("Can't remove callback for client idx %d. Not found\n", index);
+       mutex_unlock(&ibnl_mutex);
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL(ibnl_remove_client);
+
+void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq,
+                  int len, int client, int op)
+{
+       unsigned char *prev_tail;
+
+       prev_tail = skb_tail_pointer(skb);
+       *nlh = NLMSG_NEW(skb, 0, seq, RDMA_NL_GET_TYPE(client, op),
+                       len, NLM_F_MULTI);
+       (*nlh)->nlmsg_len = skb_tail_pointer(skb) - prev_tail;
+       return NLMSG_DATA(*nlh);
+
+nlmsg_failure:
+       nlmsg_trim(skb, prev_tail);
+       return NULL;
+}
+EXPORT_SYMBOL(ibnl_put_msg);
+
+int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh,
+                 int len, void *data, int type)
+{
+       unsigned char *prev_tail;
+
+       prev_tail = skb_tail_pointer(skb);
+       NLA_PUT(skb, type, len, data);
+       nlh->nlmsg_len += skb_tail_pointer(skb) - prev_tail;
+       return 0;
+
+nla_put_failure:
+       nlmsg_trim(skb, prev_tail - nlh->nlmsg_len);
+       return -EMSGSIZE;
+}
+EXPORT_SYMBOL(ibnl_put_attr);
+
+static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+       struct ibnl_client *client;
+       int type = nlh->nlmsg_type;
+       int index = RDMA_NL_GET_CLIENT(type);
+       int op = RDMA_NL_GET_OP(type);
+
+       list_for_each_entry(client, &client_list, list) {
+               if (client->index == index) {
+                       if (op < 0 || op >= client->nops ||
+                           !client->cb_table[RDMA_NL_GET_OP(op)].dump)
+                               return -EINVAL;
+                       return netlink_dump_start(nls, skb, nlh,
+                                                 client->cb_table[op].dump,
+                                                 NULL);
+               }
+       }
+
+       pr_info("Index %d wasn't found in client list\n", index);
+       return -EINVAL;
+}
+
+static void ibnl_rcv(struct sk_buff *skb)
+{
+       mutex_lock(&ibnl_mutex);
+       netlink_rcv_skb(skb, &ibnl_rcv_msg);
+       mutex_unlock(&ibnl_mutex);
+}
+
+int __init ibnl_init(void)
+{
+       nls = netlink_kernel_create(&init_net, NETLINK_RDMA, 0, ibnl_rcv,
+                                   NULL, THIS_MODULE);
+       if (!nls) {
+               pr_warn("Failed to create netlink socket\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+void ibnl_cleanup(void)
+{
+       struct ibnl_client *cur, *next;
+
+       mutex_lock(&ibnl_mutex);
+       list_for_each_entry_safe(cur, next, &client_list, list) {
+               list_del(&(cur->list));
+               kfree(cur);
+       }
+       mutex_unlock(&ibnl_mutex);
+
+       netlink_kernel_release(nls);
+}
index b3fa798525b2a1d8d3df793f41fe255eacf676dd..71be5eebd683a52605096ecf7745ee0d93af758d 100644 (file)
@@ -367,13 +367,28 @@ done:
        return ret;
 }
 
-static ssize_t ucma_create_id(struct ucma_file *file,
-                               const char __user *inbuf,
-                               int in_len, int out_len)
+static int ucma_get_qp_type(struct rdma_ucm_create_id *cmd, enum ib_qp_type *qp_type)
+{
+       switch (cmd->ps) {
+       case RDMA_PS_TCP:
+               *qp_type = IB_QPT_RC;
+               return 0;
+       case RDMA_PS_UDP:
+       case RDMA_PS_IPOIB:
+               *qp_type = IB_QPT_UD;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf,
+                             int in_len, int out_len)
 {
        struct rdma_ucm_create_id cmd;
        struct rdma_ucm_create_id_resp resp;
        struct ucma_context *ctx;
+       enum ib_qp_type qp_type;
        int ret;
 
        if (out_len < sizeof(resp))
@@ -382,6 +397,10 @@ static ssize_t ucma_create_id(struct ucma_file *file,
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
 
+       ret = ucma_get_qp_type(&cmd, &qp_type);
+       if (ret)
+               return ret;
+
        mutex_lock(&file->mut);
        ctx = ucma_alloc_ctx(file);
        mutex_unlock(&file->mut);
@@ -389,7 +408,7 @@ static ssize_t ucma_create_id(struct ucma_file *file,
                return -ENOMEM;
 
        ctx->uid = cmd.uid;
-       ctx->cm_id = rdma_create_id(ucma_event_handler, ctx, cmd.ps);
+       ctx->cm_id = rdma_create_id(ucma_event_handler, ctx, cmd.ps, qp_type);
        if (IS_ERR(ctx->cm_id)) {
                ret = PTR_ERR(ctx->cm_id);
                goto err1;
@@ -1338,9 +1357,11 @@ static const struct file_operations ucma_fops = {
 };
 
 static struct miscdevice ucma_misc = {
-       .minor  = MISC_DYNAMIC_MINOR,
-       .name   = "rdma_cm",
-       .fops   = &ucma_fops,
+       .minor          = MISC_DYNAMIC_MINOR,
+       .name           = "rdma_cm",
+       .nodename       = "infiniband/rdma_cm",
+       .mode           = 0666,
+       .fops           = &ucma_fops,
 };
 
 static ssize_t show_abi_version(struct device *dev,
index cd1996d0ad089950960ba8bb3f4eaa0bff24f7fe..8d261b6ea5feaef85091726c81df2230d38e56b0 100644 (file)
@@ -1176,6 +1176,11 @@ static void ib_umad_remove_one(struct ib_device *device)
        kref_put(&umad_dev->ref, ib_umad_release_dev);
 }
 
+static char *umad_devnode(struct device *dev, mode_t *mode)
+{
+       return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev));
+}
+
 static int __init ib_umad_init(void)
 {
        int ret;
@@ -1194,6 +1199,8 @@ static int __init ib_umad_init(void)
                goto out_chrdev;
        }
 
+       umad_class->devnode = umad_devnode;
+
        ret = class_create_file(umad_class, &class_attr_abi_version.attr);
        if (ret) {
                printk(KERN_ERR "user_mad: couldn't create abi_version attribute\n");
index ec83e9fe387bd9112266d984254a9f00200e7652..e49a85f8a44debe499e0bcd2c4d489174b5aab3d 100644 (file)
@@ -824,6 +824,12 @@ static void ib_uverbs_remove_one(struct ib_device *device)
        kfree(uverbs_dev);
 }
 
+static char *uverbs_devnode(struct device *dev, mode_t *mode)
+{
+       *mode = 0666;
+       return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev));
+}
+
 static int __init ib_uverbs_init(void)
 {
        int ret;
@@ -842,6 +848,8 @@ static int __init ib_uverbs_init(void)
                goto out_chrdev;
        }
 
+       uverbs_class->devnode = uverbs_devnode;
+
        ret = class_create_file(uverbs_class, &class_attr_abi_version.attr);
        if (ret) {
                printk(KERN_ERR "user_verbs: couldn't create abi_version attribute\n");
index 2391841389944f914c3d4bc224f136b27f170fa3..0a5008fbebac553e90dae527f88549eb90210936 100644 (file)
@@ -914,7 +914,7 @@ static void process_mpa_reply(struct iwch_ep *ep, struct sk_buff *skb)
                goto err;
 
        if (peer2peer && iwch_rqes_posted(ep->com.qp) == 0) {
-               iwch_post_zb_read(ep->com.qp);
+               iwch_post_zb_read(ep);
        }
 
        goto out;
@@ -1078,6 +1078,8 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
        struct iwch_ep *ep = ctx;
        struct cpl_wr_ack *hdr = cplhdr(skb);
        unsigned int credits = ntohs(hdr->credits);
+       unsigned long flags;
+       int post_zb = 0;
 
        PDBG("%s ep %p credits %u\n", __func__, ep, credits);
 
@@ -1087,28 +1089,34 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
                return CPL_RET_BUF_DONE;
        }
 
+       spin_lock_irqsave(&ep->com.lock, flags);
        BUG_ON(credits != 1);
        dst_confirm(ep->dst);
        if (!ep->mpa_skb) {
                PDBG("%s rdma_init wr_ack ep %p state %u\n",
-                       __func__, ep, state_read(&ep->com));
+                       __func__, ep, ep->com.state);
                if (ep->mpa_attr.initiator) {
                        PDBG("%s initiator ep %p state %u\n",
-                               __func__, ep, state_read(&ep->com));
-                       if (peer2peer)
-                               iwch_post_zb_read(ep->com.qp);
+                               __func__, ep, ep->com.state);
+                       if (peer2peer && ep->com.state == FPDU_MODE)
+                               post_zb = 1;
                } else {
                        PDBG("%s responder ep %p state %u\n",
-                               __func__, ep, state_read(&ep->com));
-                       ep->com.rpl_done = 1;
-                       wake_up(&ep->com.waitq);
+                               __func__, ep, ep->com.state);
+                       if (ep->com.state == MPA_REQ_RCVD) {
+                               ep->com.rpl_done = 1;
+                               wake_up(&ep->com.waitq);
+                       }
                }
        } else {
                PDBG("%s lsm ack ep %p state %u freeing skb\n",
-                       __func__, ep, state_read(&ep->com));
+                       __func__, ep, ep->com.state);
                kfree_skb(ep->mpa_skb);
                ep->mpa_skb = NULL;
        }
+       spin_unlock_irqrestore(&ep->com.lock, flags);
+       if (post_zb)
+               iwch_post_zb_read(ep);
        return CPL_RET_BUF_DONE;
 }
 
index c5406da3f4cd2d28dc02e7480d6a4c224516095c..9a342c9b220d240afebce55e5abfac6f67ee4953 100644 (file)
@@ -332,7 +332,7 @@ int iwch_bind_mw(struct ib_qp *qp,
                             struct ib_mw_bind *mw_bind);
 int iwch_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc);
 int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg);
-int iwch_post_zb_read(struct iwch_qp *qhp);
+int iwch_post_zb_read(struct iwch_ep *ep);
 int iwch_register_device(struct iwch_dev *dev);
 void iwch_unregister_device(struct iwch_dev *dev);
 void stop_read_rep_timer(struct iwch_qp *qhp);
index 1b4cd09f74dc2517567d8595fdd416c13ddd4941..ecd313f359a45ac6d90c0184ae1ccea3eeda7a6c 100644 (file)
@@ -738,7 +738,7 @@ static inline void build_term_codes(struct respQ_msg_t *rsp_msg,
        }
 }
 
-int iwch_post_zb_read(struct iwch_qp *qhp)
+int iwch_post_zb_read(struct iwch_ep *ep)
 {
        union t3_wr *wqe;
        struct sk_buff *skb;
@@ -761,10 +761,10 @@ int iwch_post_zb_read(struct iwch_qp *qhp)
        wqe->read.local_len = cpu_to_be32(0);
        wqe->read.local_to = cpu_to_be64(1);
        wqe->send.wrh.op_seop_flags = cpu_to_be32(V_FW_RIWR_OP(T3_WR_READ));
-       wqe->send.wrh.gen_tid_len = cpu_to_be32(V_FW_RIWR_TID(qhp->ep->hwtid)|
+       wqe->send.wrh.gen_tid_len = cpu_to_be32(V_FW_RIWR_TID(ep->hwtid)|
                                                V_FW_RIWR_LEN(flit_cnt));
        skb->priority = CPL_PRIORITY_DATA;
-       return iwch_cxgb3_ofld_send(qhp->rhp->rdev.t3cdev_p, skb);
+       return iwch_cxgb3_ofld_send(ep->com.qp->rhp->rdev.t3cdev_p, skb);
 }
 
 /*
index f660cd04ec2f31774ed678b16dbb85d3a8ed6b39..31fb44085c9b4dd7e3cdd4f97f59727f4a82d107 100644 (file)
@@ -1463,9 +1463,9 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
        struct c4iw_qp_attributes attrs;
        int disconnect = 1;
        int release = 0;
-       int abort = 0;
        struct tid_info *t = dev->rdev.lldi.tids;
        unsigned int tid = GET_TID(hdr);
+       int ret;
 
        ep = lookup_tid(t, tid);
        PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
@@ -1501,10 +1501,12 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
                start_ep_timer(ep);
                __state_set(&ep->com, CLOSING);
                attrs.next_state = C4IW_QP_STATE_CLOSING;
-               abort = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
+               ret = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
                                       C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
-               peer_close_upcall(ep);
-               disconnect = 1;
+               if (ret != -ECONNRESET) {
+                       peer_close_upcall(ep);
+                       disconnect = 1;
+               }
                break;
        case ABORTING:
                disconnect = 0;
@@ -2109,15 +2111,16 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
                break;
        }
 
-       mutex_unlock(&ep->com.mutex);
        if (close) {
-               if (abrupt)
-                       ret = abort_connection(ep, NULL, gfp);
-               else
+               if (abrupt) {
+                       close_complete_upcall(ep);
+                       ret = send_abort(ep, NULL, gfp);
+               } else
                        ret = send_halfclose(ep, gfp);
                if (ret)
                        fatal = 1;
        }
+       mutex_unlock(&ep->com.mutex);
        if (fatal)
                release_ep_resources(ep);
        return ret;
@@ -2301,6 +2304,31 @@ static int fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb)
        return 0;
 }
 
+static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb)
+{
+       struct cpl_abort_req_rss *req = cplhdr(skb);
+       struct c4iw_ep *ep;
+       struct tid_info *t = dev->rdev.lldi.tids;
+       unsigned int tid = GET_TID(req);
+
+       ep = lookup_tid(t, tid);
+       if (is_neg_adv_abort(req->status)) {
+               PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep,
+                    ep->hwtid);
+               kfree_skb(skb);
+               return 0;
+       }
+       PDBG("%s ep %p tid %u state %u\n", __func__, ep, ep->hwtid,
+            ep->com.state);
+
+       /*
+        * Wake up any threads in rdma_init() or rdma_fini().
+        */
+       c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
+       sched(dev, skb);
+       return 0;
+}
+
 /*
  * Most upcalls from the T4 Core go to sched() to
  * schedule the processing on a work queue.
@@ -2317,7 +2345,7 @@ c4iw_handler_func c4iw_handlers[NUM_CPL_CMDS] = {
        [CPL_PASS_ESTABLISH] = sched,
        [CPL_PEER_CLOSE] = sched,
        [CPL_CLOSE_CON_RPL] = sched,
-       [CPL_ABORT_REQ_RSS] = sched,
+       [CPL_ABORT_REQ_RSS] = peer_abort_intr,
        [CPL_RDMA_TERMINATE] = sched,
        [CPL_FW4_ACK] = sched,
        [CPL_SET_TCB_RPL] = set_tcb_rpl,
index 8d8f8add6fcd93e71fd5b8931616554099bd7b00..1720dc790d13d1367594478a95ad1c9148bb91b1 100644 (file)
@@ -801,6 +801,10 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries,
        if (ucontext) {
                memsize = roundup(memsize, PAGE_SIZE);
                hwentries = memsize / sizeof *chp->cq.queue;
+               while (hwentries > T4_MAX_IQ_SIZE) {
+                       memsize -= PAGE_SIZE;
+                       hwentries = memsize / sizeof *chp->cq.queue;
+               }
        }
        chp->cq.size = hwentries;
        chp->cq.memsize = memsize;
index 35d2a5dd9bb402d212c5f5ad5f8aa82480d7ce24..4f045375c8e27b8fb7dc93776c9b1a7e6eb7a4da 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/idr.h>
-#include <linux/workqueue.h>
+#include <linux/completion.h>
 #include <linux/netdevice.h>
 #include <linux/sched.h>
 #include <linux/pci.h>
@@ -131,28 +131,21 @@ static inline int c4iw_num_stags(struct c4iw_rdev *rdev)
 
 #define C4IW_WR_TO (10*HZ)
 
-enum {
-       REPLY_READY = 0,
-};
-
 struct c4iw_wr_wait {
-       wait_queue_head_t wait;
-       unsigned long status;
+       struct completion completion;
        int ret;
 };
 
 static inline void c4iw_init_wr_wait(struct c4iw_wr_wait *wr_waitp)
 {
        wr_waitp->ret = 0;
-       wr_waitp->status = 0;
-       init_waitqueue_head(&wr_waitp->wait);
+       init_completion(&wr_waitp->completion);
 }
 
 static inline void c4iw_wake_up(struct c4iw_wr_wait *wr_waitp, int ret)
 {
        wr_waitp->ret = ret;
-       set_bit(REPLY_READY, &wr_waitp->status);
-       wake_up(&wr_waitp->wait);
+       complete(&wr_waitp->completion);
 }
 
 static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
@@ -164,8 +157,7 @@ static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
        int ret;
 
        do {
-               ret = wait_event_timeout(wr_waitp->wait,
-                       test_and_clear_bit(REPLY_READY, &wr_waitp->status), to);
+               ret = wait_for_completion_timeout(&wr_waitp->completion, to);
                if (!ret) {
                        printk(KERN_ERR MOD "%s - Device %s not responding - "
                               "tid %u qpid %u\n", func,
index 273ffe49525a5d3d1642a292730af15a388ad9da..0347eed4a16778f173415f47c49c45d9f6d99acc 100644 (file)
@@ -625,7 +625,7 @@ pbl_done:
        mhp->attr.perms = c4iw_ib_to_tpt_access(acc);
        mhp->attr.va_fbo = virt;
        mhp->attr.page_size = shift - 12;
-       mhp->attr.len = (u32) length;
+       mhp->attr.len = length;
 
        err = register_mem(rhp, php, mhp, shift);
        if (err)
index 3b773b05a8989a0a7b81bda16f64c0f747577344..a41578e48c7b0bb366795bfd3da1dd961f3d42d1 100644 (file)
@@ -1207,11 +1207,8 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
                                c4iw_get_ep(&qhp->ep->com);
                        }
                        ret = rdma_fini(rhp, qhp, ep);
-                       if (ret) {
-                               if (internal)
-                                       c4iw_get_ep(&qhp->ep->com);
+                       if (ret)
                                goto err;
-                       }
                        break;
                case C4IW_QP_STATE_TERMINATE:
                        set_state(qhp, C4IW_QP_STATE_TERMINATE);
index 13de1192927cc50da063562fdc8a47e8a4336422..2d668c69f6d958bcd9ba275967c8bbc1f3a93b9d 100644 (file)
@@ -1138,7 +1138,9 @@ static ssize_t nes_store_wqm_quanta(struct device_driver *ddp,
        u32 i = 0;
        struct nes_device *nesdev;
 
-       strict_strtoul(buf, 0, &wqm_quanta_value);
+       if (kstrtoul(buf, 0, &wqm_quanta_value) < 0)
+               return -EINVAL;
+
        list_for_each_entry(nesdev, &nes_dev_list, list) {
                if (i == ee_flsh_adapter) {
                        nesdev->nesadapter->wqm_quanta = wqm_quanta_value;
index 7c03a70c55a2815586c805bd17fc9fd69f21b2fc..8349f9c5064c042d568cf56619b76dd391410402 100644 (file)
@@ -1,6 +1,6 @@
 config INFINIBAND_QIB
        tristate "QLogic PCIe HCA support"
-       depends on 64BIT && NET
+       depends on 64BIT
        ---help---
        This is a low-level driver for QLogic PCIe QLE InfiniBand host
        channel adapters.  This driver does not support the QLogic
index 9f53e68a096a329f499cbb1c9d63b6800b5add55..8ec5237031a08f3aa493ccf84715a2d5652f0e39 100644 (file)
@@ -469,6 +469,8 @@ static u8 ib_rate_to_delay[IB_RATE_120_GBPS + 1] = {
 #define IB_7322_LT_STATE_RECOVERIDLE     0x0f
 #define IB_7322_LT_STATE_CFGENH          0x10
 #define IB_7322_LT_STATE_CFGTEST         0x11
+#define IB_7322_LT_STATE_CFGWAITRMTTEST  0x12
+#define IB_7322_LT_STATE_CFGWAITENH      0x13
 
 /* link state machine states from IBC */
 #define IB_7322_L_STATE_DOWN             0x0
@@ -498,8 +500,10 @@ static const u8 qib_7322_physportstate[0x20] = {
                IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
        [IB_7322_LT_STATE_CFGENH] = IB_PHYSPORTSTATE_CFG_ENH,
        [IB_7322_LT_STATE_CFGTEST] = IB_PHYSPORTSTATE_CFG_TRAIN,
-       [0x12] = IB_PHYSPORTSTATE_CFG_TRAIN,
-       [0x13] = IB_PHYSPORTSTATE_CFG_WAIT_ENH,
+       [IB_7322_LT_STATE_CFGWAITRMTTEST] =
+               IB_PHYSPORTSTATE_CFG_TRAIN,
+       [IB_7322_LT_STATE_CFGWAITENH] =
+               IB_PHYSPORTSTATE_CFG_WAIT_ENH,
        [0x14] = IB_PHYSPORTSTATE_CFG_TRAIN,
        [0x15] = IB_PHYSPORTSTATE_CFG_TRAIN,
        [0x16] = IB_PHYSPORTSTATE_CFG_TRAIN,
@@ -1692,7 +1696,9 @@ static void handle_serdes_issues(struct qib_pportdata *ppd, u64 ibcst)
                break;
        }
 
-       if (ibclt == IB_7322_LT_STATE_CFGTEST &&
+       if (((ibclt >= IB_7322_LT_STATE_CFGTEST &&
+             ibclt <= IB_7322_LT_STATE_CFGWAITENH) ||
+            ibclt == IB_7322_LT_STATE_LINKUP) &&
            (ibcst & SYM_MASK(IBCStatusA_0, LinkSpeedQDR))) {
                force_h1(ppd);
                ppd->cpspec->qdr_reforce = 1;
@@ -7301,12 +7307,17 @@ static void ibsd_wr_allchans(struct qib_pportdata *ppd, int addr, unsigned data,
 static void serdes_7322_los_enable(struct qib_pportdata *ppd, int enable)
 {
        u64 data = qib_read_kreg_port(ppd, krp_serdesctrl);
-       printk(KERN_INFO QIB_DRV_NAME " IB%u:%u Turning LOS %s\n",
-               ppd->dd->unit, ppd->port, (enable ? "on" : "off"));
-       if (enable)
+       u8 state = SYM_FIELD(data, IBSerdesCtrl_0, RXLOSEN);
+
+       if (enable && !state) {
+               printk(KERN_INFO QIB_DRV_NAME " IB%u:%u Turning LOS on\n",
+                       ppd->dd->unit, ppd->port);
                data |= SYM_MASK(IBSerdesCtrl_0, RXLOSEN);
-       else
+       } else if (!enable && state) {
+               printk(KERN_INFO QIB_DRV_NAME " IB%u:%u Turning LOS off\n",
+                       ppd->dd->unit, ppd->port);
                data &= ~SYM_MASK(IBSerdesCtrl_0, RXLOSEN);
+       }
        qib_write_kreg_port(ppd, krp_serdesctrl, data);
 }
 
index a693c56ec8a6bf97df295c23868e74272c21ef40..6ae57d23004a11310f6f1e77556a961f50584c7c 100644 (file)
@@ -96,8 +96,12 @@ void qib_handle_e_ibstatuschanged(struct qib_pportdata *ppd, u64 ibcs)
         * states, or if it transitions from any of the up (INIT or better)
         * states into any of the down states (except link recovery), then
         * call the chip-specific code to take appropriate actions.
+        *
+        * ppd->lflags could be 0 if this is the first time the interrupt
+        * handlers has been called but the link is already up.
         */
-       if (lstate >= IB_PORT_INIT && (ppd->lflags & QIBL_LINKDOWN) &&
+       if (lstate >= IB_PORT_INIT &&
+           (!ppd->lflags || (ppd->lflags & QIBL_LINKDOWN)) &&
            ltstate == IB_PHYSPORTSTATE_LINKUP) {
                /* transitioned to UP */
                if (dd->f_ib_updown(ppd, 1, ibcs))
index 9876865732f76c4abd815072dbc9b5c86075c3d8..ede1475bee09cc74ef7b6269f65d001c7dc97198 100644 (file)
@@ -548,7 +548,7 @@ int iser_connect(struct iser_conn   *ib_conn,
        iser_conn_get(ib_conn); /* ref ib conn's cma id */
        ib_conn->cma_id = rdma_create_id(iser_cma_handler,
                                             (void *)ib_conn,
-                                            RDMA_PS_TCP);
+                                            RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(ib_conn->cma_id)) {
                err = PTR_ERR(ib_conn->cma_id);
                iser_err("rdma_create_id failed: %d\n", err);
index 376d640487d2ce942ff58d348a38a8a9737c5699..ee165fdcb5968431d1cf96a9cb02d56a7e338ba4 100644 (file)
@@ -1147,7 +1147,7 @@ static void srp_process_aer_req(struct srp_target_port *target,
 static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
 {
        struct ib_device *dev = target->srp_host->srp_dev->dev;
-       struct srp_iu *iu = (struct srp_iu *) wc->wr_id;
+       struct srp_iu *iu = (struct srp_iu *) (uintptr_t) wc->wr_id;
        int res;
        u8 opcode;
 
@@ -1231,7 +1231,7 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
                        break;
                }
 
-               iu = (struct srp_iu *) wc.wr_id;
+               iu = (struct srp_iu *) (uintptr_t) wc.wr_id;
                list_add(&iu->list, &target->free_tx);
        }
 }
index 88d8e4cb419a1d0d6cc17828894dc4d3b67e0201..4cf25347b01546b1578e0b9987d6717c38db0366 100644 (file)
@@ -41,6 +41,7 @@ struct evdev {
 struct evdev_client {
        unsigned int head;
        unsigned int tail;
+       unsigned int packet_head; /* [future] position of the first element of next packet */
        spinlock_t buffer_lock; /* protects access to buffer, head and tail */
        struct fasync_struct *fasync;
        struct evdev *evdev;
@@ -72,12 +73,16 @@ static void evdev_pass_event(struct evdev_client *client,
                client->buffer[client->tail].type = EV_SYN;
                client->buffer[client->tail].code = SYN_DROPPED;
                client->buffer[client->tail].value = 0;
-       }
 
-       spin_unlock(&client->buffer_lock);
+               client->packet_head = client->tail;
+       }
 
-       if (event->type == EV_SYN)
+       if (event->type == EV_SYN && event->code == SYN_REPORT) {
+               client->packet_head = client->head;
                kill_fasync(&client->fasync, SIGIO, POLL_IN);
+       }
+
+       spin_unlock(&client->buffer_lock);
 }
 
 /*
@@ -106,7 +111,8 @@ static void evdev_event(struct input_handle *handle,
 
        rcu_read_unlock();
 
-       wake_up_interruptible(&evdev->wait);
+       if (type == EV_SYN && code == SYN_REPORT)
+               wake_up_interruptible(&evdev->wait);
 }
 
 static int evdev_fasync(int fd, struct file *file, int on)
@@ -159,7 +165,6 @@ static int evdev_grab(struct evdev *evdev, struct evdev_client *client)
                return error;
 
        rcu_assign_pointer(evdev->grab, client);
-       synchronize_rcu();
 
        return 0;
 }
@@ -182,7 +187,6 @@ static void evdev_attach_client(struct evdev *evdev,
        spin_lock(&evdev->client_lock);
        list_add_tail_rcu(&client->node, &evdev->client_list);
        spin_unlock(&evdev->client_lock);
-       synchronize_rcu();
 }
 
 static void evdev_detach_client(struct evdev *evdev,
@@ -387,12 +391,12 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
        if (count < input_event_size())
                return -EINVAL;
 
-       if (client->head == client->tail && evdev->exist &&
+       if (client->packet_head == client->tail && evdev->exist &&
            (file->f_flags & O_NONBLOCK))
                return -EAGAIN;
 
        retval = wait_event_interruptible(evdev->wait,
-               client->head != client->tail || !evdev->exist);
+               client->packet_head != client->tail || !evdev->exist);
        if (retval)
                return retval;
 
@@ -421,7 +425,7 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
        poll_wait(file, &evdev->wait, wait);
 
        mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
-       if (client->head != client->tail)
+       if (client->packet_head != client->tail)
                mask |= POLLIN | POLLRDNORM;
 
        return mask;
index 4d8ea32e8a001847746a796c43cf79dc70ae3c3c..22be27b424def00dbd8cc0167439b508b2564b78 100644 (file)
@@ -19,7 +19,7 @@
 
 /* Note to the author of this code: did it ever occur to
    you why the ifdefs are needed? Think about it again. -AK */
-#ifdef CONFIG_X86_64
+#if defined(CONFIG_X86_64) || defined(CONFIG_TILE)
 #  define INPUT_COMPAT_TEST is_compat_task()
 #elif defined(CONFIG_S390)
 #  define INPUT_COMPAT_TEST test_thread_flag(TIF_31BIT)
index 3037842a60d8a10e0533033b665aca490c10b030..b1aabde87523176f17ce0896e98403d4fda6f0a1 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/jiffies.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
+#include <linux/workqueue.h>
 #include <linux/input-polldev.h>
 
 MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
@@ -20,44 +21,6 @@ MODULE_DESCRIPTION("Generic implementation of a polled input device");
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION("0.1");
 
-static DEFINE_MUTEX(polldev_mutex);
-static int polldev_users;
-static struct workqueue_struct *polldev_wq;
-
-static int input_polldev_start_workqueue(void)
-{
-       int retval;
-
-       retval = mutex_lock_interruptible(&polldev_mutex);
-       if (retval)
-               return retval;
-
-       if (!polldev_users) {
-               polldev_wq = create_singlethread_workqueue("ipolldevd");
-               if (!polldev_wq) {
-                       pr_err("failed to create ipolldevd workqueue\n");
-                       retval = -ENOMEM;
-                       goto out;
-               }
-       }
-
-       polldev_users++;
-
- out:
-       mutex_unlock(&polldev_mutex);
-       return retval;
-}
-
-static void input_polldev_stop_workqueue(void)
-{
-       mutex_lock(&polldev_mutex);
-
-       if (!--polldev_users)
-               destroy_workqueue(polldev_wq);
-
-       mutex_unlock(&polldev_mutex);
-}
-
 static void input_polldev_queue_work(struct input_polled_dev *dev)
 {
        unsigned long delay;
@@ -66,7 +29,7 @@ static void input_polldev_queue_work(struct input_polled_dev *dev)
        if (delay >= HZ)
                delay = round_jiffies_relative(delay);
 
-       queue_delayed_work(polldev_wq, &dev->work, delay);
+       queue_delayed_work(system_freezable_wq, &dev->work, delay);
 }
 
 static void input_polled_device_work(struct work_struct *work)
@@ -81,18 +44,13 @@ static void input_polled_device_work(struct work_struct *work)
 static int input_open_polled_device(struct input_dev *input)
 {
        struct input_polled_dev *dev = input_get_drvdata(input);
-       int error;
-
-       error = input_polldev_start_workqueue();
-       if (error)
-               return error;
 
        if (dev->open)
                dev->open(dev);
 
        /* Only start polling if polling is enabled */
        if (dev->poll_interval > 0)
-               queue_delayed_work(polldev_wq, &dev->work, 0);
+               queue_delayed_work(system_freezable_wq, &dev->work, 0);
 
        return 0;
 }
@@ -102,13 +60,6 @@ static void input_close_polled_device(struct input_dev *input)
        struct input_polled_dev *dev = input_get_drvdata(input);
 
        cancel_delayed_work_sync(&dev->work);
-       /*
-        * Clean up work struct to remove references to the workqueue.
-        * It may be destroyed by the next call. This causes problems
-        * at next device open-close in case of poll_interval == 0.
-        */
-       INIT_DELAYED_WORK(&dev->work, dev->work.work.func);
-       input_polldev_stop_workqueue();
 
        if (dev->close)
                dev->close(dev);
@@ -295,4 +246,3 @@ void input_unregister_polled_device(struct input_polled_dev *dev)
        input_unregister_device(dev->input);
 }
 EXPORT_SYMBOL(input_unregister_polled_device);
-
index ebbceedc92f4fb8a9f8bc959734be4b442586d01..da38d97a51b1c67782f3265a19bac3cdb5fd2686 100644 (file)
@@ -451,7 +451,6 @@ int input_grab_device(struct input_handle *handle)
        }
 
        rcu_assign_pointer(dev->grab, handle);
-       synchronize_rcu();
 
  out:
        mutex_unlock(&dev->mutex);
@@ -1757,7 +1756,7 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev)
        } else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) {
                mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum -
                           dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1,
-               clamp(mt_slots, 2, 32);
+               mt_slots = clamp(mt_slots, 2, 32);
        } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
                mt_slots = 2;
        } else {
index 5688b5c88f2491a15b173b0a6f6a6e1c7998a5e5..c24ec2d5f9266cb969bd3a73ea229c08adcc8d9b 100644 (file)
@@ -180,7 +180,6 @@ static void joydev_attach_client(struct joydev *joydev,
        spin_lock(&joydev->client_lock);
        list_add_tail_rcu(&client->node, &joydev->client_list);
        spin_unlock(&joydev->client_lock);
-       synchronize_rcu();
 }
 
 static void joydev_detach_client(struct joydev *joydev,
index b16bed038f7245634aa3a6ffbbac45b40d168878..b4dee9d5a0555ff76dabb1b85b7e23c92db63222 100644 (file)
@@ -32,6 +32,16 @@ config KEYBOARD_ADP5588
          To compile this driver as a module, choose M here: the
          module will be called adp5588-keys.
 
+config KEYBOARD_ADP5589
+       tristate "ADP5589 I2C QWERTY Keypad and IO Expander"
+       depends on I2C
+       help
+         Say Y here if you want to use a ADP5589 attached to your
+         system I2C bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called adp5589-keys.
+
 config KEYBOARD_AMIGA
        tristate "Amiga keyboard"
        depends on AMIGA
@@ -325,6 +335,18 @@ config KEYBOARD_MCS
          To compile this driver as a module, choose M here: the
          module will be called mcs_touchkey.
 
+config KEYBOARD_MPR121
+       tristate "Freescale MPR121 Touchkey"
+       depends on I2C
+       help
+         Say Y here if you have Freescale MPR121 touchkey controller
+         chip in your system.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called mpr121_touchkey.
+
 config KEYBOARD_IMX
        tristate "IMX keypad support"
        depends on ARCH_MXC
@@ -390,6 +412,17 @@ config KEYBOARD_PXA930_ROTARY
          To compile this driver as a module, choose M here: the
          module will be called pxa930_rotary.
 
+config KEYBOARD_PMIC8XXX
+       tristate "Qualcomm PMIC8XXX keypad support"
+       depends on MFD_PM8XXX
+       help
+         Say Y here if you want to enable the driver for the PMIC8XXX
+         keypad provided as a reference design from Qualcomm. This is intended
+         to support upto 18x8 matrix based keypad design.
+
+         To compile this driver as a module, choose M here: the module will
+         be called pmic8xxx-keypad.
+
 config KEYBOARD_SAMSUNG
        tristate "Samsung keypad support"
        depends on SAMSUNG_DEV_KEYPAD
index 878e6c20deb0e1f231526e26846aedd1e1ce60d4..ddde0fd476f744c2aa2cd250362f809c4469310b 100644 (file)
@@ -6,6 +6,7 @@
 
 obj-$(CONFIG_KEYBOARD_ADP5520)         += adp5520-keys.o
 obj-$(CONFIG_KEYBOARD_ADP5588)         += adp5588-keys.o
+obj-$(CONFIG_KEYBOARD_ADP5589)         += adp5589-keys.o
 obj-$(CONFIG_KEYBOARD_AMIGA)           += amikbd.o
 obj-$(CONFIG_KEYBOARD_ATARI)           += atakbd.o
 obj-$(CONFIG_KEYBOARD_ATKBD)           += atkbd.o
@@ -27,11 +28,13 @@ obj-$(CONFIG_KEYBOARD_MAPLE)                += maple_keyb.o
 obj-$(CONFIG_KEYBOARD_MATRIX)          += matrix_keypad.o
 obj-$(CONFIG_KEYBOARD_MAX7359)         += max7359_keypad.o
 obj-$(CONFIG_KEYBOARD_MCS)             += mcs_touchkey.o
+obj-$(CONFIG_KEYBOARD_MPR121)          += mpr121_touchkey.o
 obj-$(CONFIG_KEYBOARD_NEWTON)          += newtonkbd.o
 obj-$(CONFIG_KEYBOARD_NOMADIK)         += nomadik-ske-keypad.o
 obj-$(CONFIG_KEYBOARD_OMAP)            += omap-keypad.o
 obj-$(CONFIG_KEYBOARD_OMAP4)           += omap4-keypad.o
 obj-$(CONFIG_KEYBOARD_OPENCORES)       += opencores-kbd.o
+obj-$(CONFIG_KEYBOARD_PMIC8XXX)                += pmic8xxx-keypad.o
 obj-$(CONFIG_KEYBOARD_PXA27x)          += pxa27x_keypad.o
 obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)   += pxa930_rotary.o
 obj-$(CONFIG_KEYBOARD_QT1070)           += qt1070.o
diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c
new file mode 100644 (file)
index 0000000..6315986
--- /dev/null
@@ -0,0 +1,771 @@
+/*
+ * Description:  keypad driver for ADP5589
+ *              I2C QWERTY Keypad and IO Expander
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2010-2011 Analog Devices Inc.
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include <linux/input/adp5589.h>
+
+/* GENERAL_CFG Register */
+#define OSC_EN         (1 << 7)
+#define CORE_CLK(x)    (((x) & 0x3) << 5)
+#define LCK_TRK_LOGIC  (1 << 4)
+#define LCK_TRK_GPI    (1 << 3)
+#define INT_CFG                (1 << 1)
+#define RST_CFG                (1 << 0)
+
+/* INT_EN Register */
+#define LOGIC2_IEN     (1 << 5)
+#define LOGIC1_IEN     (1 << 4)
+#define LOCK_IEN       (1 << 3)
+#define OVRFLOW_IEN    (1 << 2)
+#define GPI_IEN                (1 << 1)
+#define EVENT_IEN      (1 << 0)
+
+/* Interrupt Status Register */
+#define LOGIC2_INT     (1 << 5)
+#define LOGIC1_INT     (1 << 4)
+#define LOCK_INT       (1 << 3)
+#define OVRFLOW_INT    (1 << 2)
+#define GPI_INT                (1 << 1)
+#define EVENT_INT      (1 << 0)
+
+/* STATUS Register */
+
+#define LOGIC2_STAT    (1 << 7)
+#define LOGIC1_STAT    (1 << 6)
+#define LOCK_STAT      (1 << 5)
+#define KEC            0xF
+
+/* PIN_CONFIG_D Register */
+#define C4_EXTEND_CFG  (1 << 6)        /* RESET2 */
+#define R4_EXTEND_CFG  (1 << 5)        /* RESET1 */
+
+/* LOCK_CFG */
+#define LOCK_EN                (1 << 0)
+
+#define PTIME_MASK     0x3
+#define LTIME_MASK     0x3
+
+/* Key Event Register xy */
+#define KEY_EV_PRESSED         (1 << 7)
+#define KEY_EV_MASK            (0x7F)
+
+#define KEYP_MAX_EVENT         16
+
+#define MAXGPIO                        19
+#define ADP_BANK(offs)         ((offs) >> 3)
+#define ADP_BIT(offs)          (1u << ((offs) & 0x7))
+
+struct adp5589_kpad {
+       struct i2c_client *client;
+       struct input_dev *input;
+       unsigned short keycode[ADP5589_KEYMAPSIZE];
+       const struct adp5589_gpi_map *gpimap;
+       unsigned short gpimapsize;
+       unsigned extend_cfg;
+#ifdef CONFIG_GPIOLIB
+       unsigned char gpiomap[MAXGPIO];
+       bool export_gpio;
+       struct gpio_chip gc;
+       struct mutex gpio_lock; /* Protect cached dir, dat_out */
+       u8 dat_out[3];
+       u8 dir[3];
+#endif
+};
+
+static int adp5589_read(struct i2c_client *client, u8 reg)
+{
+       int ret = i2c_smbus_read_byte_data(client, reg);
+
+       if (ret < 0)
+               dev_err(&client->dev, "Read Error\n");
+
+       return ret;
+}
+
+static int adp5589_write(struct i2c_client *client, u8 reg, u8 val)
+{
+       return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+#ifdef CONFIG_GPIOLIB
+static int adp5589_gpio_get_value(struct gpio_chip *chip, unsigned off)
+{
+       struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+
+       return !!(adp5589_read(kpad->client, ADP5589_GPI_STATUS_A + bank) &
+                 bit);
+}
+
+static void adp5589_gpio_set_value(struct gpio_chip *chip,
+                                  unsigned off, int val)
+{
+       struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+
+       mutex_lock(&kpad->gpio_lock);
+
+       if (val)
+               kpad->dat_out[bank] |= bit;
+       else
+               kpad->dat_out[bank] &= ~bit;
+
+       adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank,
+                     kpad->dat_out[bank]);
+
+       mutex_unlock(&kpad->gpio_lock);
+}
+
+static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off)
+{
+       struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       int ret;
+
+       mutex_lock(&kpad->gpio_lock);
+
+       kpad->dir[bank] &= ~bit;
+       ret = adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank,
+                           kpad->dir[bank]);
+
+       mutex_unlock(&kpad->gpio_lock);
+
+       return ret;
+}
+
+static int adp5589_gpio_direction_output(struct gpio_chip *chip,
+                                        unsigned off, int val)
+{
+       struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       int ret;
+
+       mutex_lock(&kpad->gpio_lock);
+
+       kpad->dir[bank] |= bit;
+
+       if (val)
+               kpad->dat_out[bank] |= bit;
+       else
+               kpad->dat_out[bank] &= ~bit;
+
+       ret = adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank,
+                           kpad->dat_out[bank]);
+       ret |= adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank,
+                            kpad->dir[bank]);
+
+       mutex_unlock(&kpad->gpio_lock);
+
+       return ret;
+}
+
+static int __devinit adp5589_build_gpiomap(struct adp5589_kpad *kpad,
+                               const struct adp5589_kpad_platform_data *pdata)
+{
+       bool pin_used[MAXGPIO];
+       int n_unused = 0;
+       int i;
+
+       memset(pin_used, false, sizeof(pin_used));
+
+       for (i = 0; i < MAXGPIO; i++)
+               if (pdata->keypad_en_mask & (1 << i))
+                       pin_used[i] = true;
+
+       for (i = 0; i < kpad->gpimapsize; i++)
+               pin_used[kpad->gpimap[i].pin - ADP5589_GPI_PIN_BASE] = true;
+
+       if (kpad->extend_cfg & R4_EXTEND_CFG)
+               pin_used[4] = true;
+
+       if (kpad->extend_cfg & C4_EXTEND_CFG)
+               pin_used[12] = true;
+
+       for (i = 0; i < MAXGPIO; i++)
+               if (!pin_used[i])
+                       kpad->gpiomap[n_unused++] = i;
+
+       return n_unused;
+}
+
+static int __devinit adp5589_gpio_add(struct adp5589_kpad *kpad)
+{
+       struct device *dev = &kpad->client->dev;
+       const struct adp5589_kpad_platform_data *pdata = dev->platform_data;
+       const struct adp5589_gpio_platform_data *gpio_data = pdata->gpio_data;
+       int i, error;
+
+       if (!gpio_data)
+               return 0;
+
+       kpad->gc.ngpio = adp5589_build_gpiomap(kpad, pdata);
+       if (kpad->gc.ngpio == 0) {
+               dev_info(dev, "No unused gpios left to export\n");
+               return 0;
+       }
+
+       kpad->export_gpio = true;
+
+       kpad->gc.direction_input = adp5589_gpio_direction_input;
+       kpad->gc.direction_output = adp5589_gpio_direction_output;
+       kpad->gc.get = adp5589_gpio_get_value;
+       kpad->gc.set = adp5589_gpio_set_value;
+       kpad->gc.can_sleep = 1;
+
+       kpad->gc.base = gpio_data->gpio_start;
+       kpad->gc.label = kpad->client->name;
+       kpad->gc.owner = THIS_MODULE;
+
+       mutex_init(&kpad->gpio_lock);
+
+       error = gpiochip_add(&kpad->gc);
+       if (error) {
+               dev_err(dev, "gpiochip_add failed, err: %d\n", error);
+               return error;
+       }
+
+       for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+               kpad->dat_out[i] = adp5589_read(kpad->client,
+                                               ADP5589_GPO_DATA_OUT_A + i);
+               kpad->dir[i] = adp5589_read(kpad->client,
+                                           ADP5589_GPIO_DIRECTION_A + i);
+       }
+
+       if (gpio_data->setup) {
+               error = gpio_data->setup(kpad->client,
+                                        kpad->gc.base, kpad->gc.ngpio,
+                                        gpio_data->context);
+               if (error)
+                       dev_warn(dev, "setup failed, %d\n", error);
+       }
+
+       return 0;
+}
+
+static void __devexit adp5589_gpio_remove(struct adp5589_kpad *kpad)
+{
+       struct device *dev = &kpad->client->dev;
+       const struct adp5589_kpad_platform_data *pdata = dev->platform_data;
+       const struct adp5589_gpio_platform_data *gpio_data = pdata->gpio_data;
+       int error;
+
+       if (!kpad->export_gpio)
+               return;
+
+       if (gpio_data->teardown) {
+               error = gpio_data->teardown(kpad->client,
+                                           kpad->gc.base, kpad->gc.ngpio,
+                                           gpio_data->context);
+               if (error)
+                       dev_warn(dev, "teardown failed %d\n", error);
+       }
+
+       error = gpiochip_remove(&kpad->gc);
+       if (error)
+               dev_warn(dev, "gpiochip_remove failed %d\n", error);
+}
+#else
+static inline int adp5589_gpio_add(struct adp5589_kpad *kpad)
+{
+       return 0;
+}
+
+static inline void adp5589_gpio_remove(struct adp5589_kpad *kpad)
+{
+}
+#endif
+
+static void adp5589_report_switches(struct adp5589_kpad *kpad,
+                                   int key, int key_val)
+{
+       int i;
+
+       for (i = 0; i < kpad->gpimapsize; i++) {
+               if (key_val == kpad->gpimap[i].pin) {
+                       input_report_switch(kpad->input,
+                                           kpad->gpimap[i].sw_evt,
+                                           key & KEY_EV_PRESSED);
+                       break;
+               }
+       }
+}
+
+static void adp5589_report_events(struct adp5589_kpad *kpad, int ev_cnt)
+{
+       int i;
+
+       for (i = 0; i < ev_cnt; i++) {
+               int key = adp5589_read(kpad->client, ADP5589_FIFO_1 + i);
+               int key_val = key & KEY_EV_MASK;
+
+               if (key_val >= ADP5589_GPI_PIN_BASE &&
+                   key_val <= ADP5589_GPI_PIN_END) {
+                       adp5589_report_switches(kpad, key, key_val);
+               } else {
+                       input_report_key(kpad->input,
+                                        kpad->keycode[key_val - 1],
+                                        key & KEY_EV_PRESSED);
+               }
+       }
+}
+
+static irqreturn_t adp5589_irq(int irq, void *handle)
+{
+       struct adp5589_kpad *kpad = handle;
+       struct i2c_client *client = kpad->client;
+       int status, ev_cnt;
+
+       status = adp5589_read(client, ADP5589_INT_STATUS);
+
+       if (status & OVRFLOW_INT)       /* Unlikely and should never happen */
+               dev_err(&client->dev, "Event Overflow Error\n");
+
+       if (status & EVENT_INT) {
+               ev_cnt = adp5589_read(client, ADP5589_STATUS) & KEC;
+               if (ev_cnt) {
+                       adp5589_report_events(kpad, ev_cnt);
+                       input_sync(kpad->input);
+               }
+       }
+
+       adp5589_write(client, ADP5589_INT_STATUS, status);      /* Status is W1C */
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad, unsigned short key)
+{
+       int i;
+
+       for (i = 0; i < ADP5589_KEYMAPSIZE; i++)
+               if (key == kpad->keycode[i])
+                       return (i + 1) | KEY_EV_PRESSED;
+
+       dev_err(&kpad->client->dev, "RESET/UNLOCK key not in keycode map\n");
+
+       return -EINVAL;
+}
+
+static int __devinit adp5589_setup(struct adp5589_kpad *kpad)
+{
+       struct i2c_client *client = kpad->client;
+       const struct adp5589_kpad_platform_data *pdata =
+           client->dev.platform_data;
+       int i, ret;
+       unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0;
+       unsigned char pull_mask = 0;
+
+       ret = adp5589_write(client, ADP5589_PIN_CONFIG_A,
+                           pdata->keypad_en_mask & 0xFF);
+       ret |= adp5589_write(client, ADP5589_PIN_CONFIG_B,
+                            (pdata->keypad_en_mask >> 8) & 0xFF);
+       ret |= adp5589_write(client, ADP5589_PIN_CONFIG_C,
+                            (pdata->keypad_en_mask >> 16) & 0xFF);
+
+       if (pdata->en_keylock) {
+               ret |= adp5589_write(client, ADP5589_UNLOCK1,
+                                    pdata->unlock_key1);
+               ret |= adp5589_write(client, ADP5589_UNLOCK2,
+                                    pdata->unlock_key2);
+               ret |= adp5589_write(client, ADP5589_UNLOCK_TIMERS,
+                                    pdata->unlock_timer & LTIME_MASK);
+               ret |= adp5589_write(client, ADP5589_LOCK_CFG, LOCK_EN);
+       }
+
+       for (i = 0; i < KEYP_MAX_EVENT; i++)
+               ret |= adp5589_read(client, ADP5589_FIFO_1 + i);
+
+       for (i = 0; i < pdata->gpimapsize; i++) {
+               unsigned short pin = pdata->gpimap[i].pin;
+
+               if (pin <= ADP5589_GPI_PIN_ROW_END) {
+                       evt_mode1 |= (1 << (pin - ADP5589_GPI_PIN_ROW_BASE));
+               } else {
+                       evt_mode2 |=
+                           ((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) & 0xFF);
+                       evt_mode3 |=
+                           ((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) >> 8);
+               }
+       }
+
+       if (pdata->gpimapsize) {
+               ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_A, evt_mode1);
+               ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_B, evt_mode2);
+               ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_C, evt_mode3);
+       }
+
+       if (pdata->pull_dis_mask & pdata->pullup_en_100k &
+           pdata->pullup_en_300k & pdata->pulldown_en_300k)
+               dev_warn(&client->dev, "Conflicting pull resistor config\n");
+
+       for (i = 0; i < MAXGPIO; i++) {
+               unsigned val = 0;
+
+               if (pdata->pullup_en_300k & (1 << i))
+                       val = 0;
+               else if (pdata->pulldown_en_300k & (1 << i))
+                       val = 1;
+               else if (pdata->pullup_en_100k & (1 << i))
+                       val = 2;
+               else if (pdata->pull_dis_mask & (1 << i))
+                       val = 3;
+
+               pull_mask |= val << (2 * (i & 0x3));
+
+               if ((i & 0x3) == 0x3 || i == MAXGPIO - 1) {
+                       ret |= adp5589_write(client,
+                                            ADP5589_RPULL_CONFIG_A + (i >> 2),
+                                            pull_mask);
+                       pull_mask = 0;
+               }
+       }
+
+       if (pdata->reset1_key_1 && pdata->reset1_key_2 && pdata->reset1_key_3) {
+               ret |= adp5589_write(client, ADP5589_RESET1_EVENT_A,
+                                    adp5589_get_evcode(kpad,
+                                                       pdata->reset1_key_1));
+               ret |= adp5589_write(client, ADP5589_RESET1_EVENT_B,
+                                    adp5589_get_evcode(kpad,
+                                                       pdata->reset1_key_2));
+               ret |= adp5589_write(client, ADP5589_RESET1_EVENT_C,
+                                    adp5589_get_evcode(kpad,
+                                                       pdata->reset1_key_3));
+               kpad->extend_cfg |= R4_EXTEND_CFG;
+       }
+
+       if (pdata->reset2_key_1 && pdata->reset2_key_2) {
+               ret |= adp5589_write(client, ADP5589_RESET2_EVENT_A,
+                                    adp5589_get_evcode(kpad,
+                                                       pdata->reset2_key_1));
+               ret |= adp5589_write(client, ADP5589_RESET2_EVENT_B,
+                                    adp5589_get_evcode(kpad,
+                                                       pdata->reset2_key_2));
+               kpad->extend_cfg |= C4_EXTEND_CFG;
+       }
+
+       if (kpad->extend_cfg) {
+               ret |= adp5589_write(client, ADP5589_RESET_CFG,
+                                    pdata->reset_cfg);
+               ret |= adp5589_write(client, ADP5589_PIN_CONFIG_D,
+                                    kpad->extend_cfg);
+       }
+
+       for (i = 0; i <= ADP_BANK(MAXGPIO); i++)
+               ret |= adp5589_write(client, ADP5589_DEBOUNCE_DIS_A + i,
+                                    pdata->debounce_dis_mask >> (i * 8));
+
+       ret |= adp5589_write(client, ADP5589_POLL_PTIME_CFG,
+                            pdata->scan_cycle_time & PTIME_MASK);
+       ret |= adp5589_write(client, ADP5589_INT_STATUS, LOGIC2_INT |
+                            LOGIC1_INT | OVRFLOW_INT | LOCK_INT |
+                            GPI_INT | EVENT_INT);      /* Status is W1C */
+
+       ret |= adp5589_write(client, ADP5589_GENERAL_CFG,
+                            INT_CFG | OSC_EN | CORE_CLK(3));
+       ret |= adp5589_write(client, ADP5589_INT_EN,
+                            OVRFLOW_IEN | GPI_IEN | EVENT_IEN);
+
+       if (ret < 0) {
+               dev_err(&client->dev, "Write Error\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void __devinit adp5589_report_switch_state(struct adp5589_kpad *kpad)
+{
+       int gpi_stat1 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_A);
+       int gpi_stat2 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_B);
+       int gpi_stat3 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_C);
+       int gpi_stat_tmp, pin_loc;
+       int i;
+
+       for (i = 0; i < kpad->gpimapsize; i++) {
+               unsigned short pin = kpad->gpimap[i].pin;
+
+               if (pin <= ADP5589_GPI_PIN_ROW_END) {
+                       gpi_stat_tmp = gpi_stat1;
+                       pin_loc = pin - ADP5589_GPI_PIN_ROW_BASE;
+               } else if ((pin - ADP5589_GPI_PIN_COL_BASE) < 8) {
+                       gpi_stat_tmp = gpi_stat2;
+                       pin_loc = pin - ADP5589_GPI_PIN_COL_BASE;
+               } else {
+                       gpi_stat_tmp = gpi_stat3;
+                       pin_loc = pin - ADP5589_GPI_PIN_COL_BASE - 8;
+               }
+
+               if (gpi_stat_tmp < 0) {
+                       dev_err(&kpad->client->dev,
+                               "Can't read GPIO_DAT_STAT switch"
+                               " %d default to OFF\n", pin);
+                       gpi_stat_tmp = 0;
+               }
+
+               input_report_switch(kpad->input,
+                                   kpad->gpimap[i].sw_evt,
+                                   !(gpi_stat_tmp & (1 << pin_loc)));
+       }
+
+       input_sync(kpad->input);
+}
+
+static int __devinit adp5589_probe(struct i2c_client *client,
+                                  const struct i2c_device_id *id)
+{
+       struct adp5589_kpad *kpad;
+       const struct adp5589_kpad_platform_data *pdata;
+       struct input_dev *input;
+       unsigned int revid;
+       int ret, i;
+       int error;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
+               return -EIO;
+       }
+
+       pdata = client->dev.platform_data;
+       if (!pdata) {
+               dev_err(&client->dev, "no platform data?\n");
+               return -EINVAL;
+       }
+
+       if (!((pdata->keypad_en_mask & 0xFF) &&
+                       (pdata->keypad_en_mask >> 8)) || !pdata->keymap) {
+               dev_err(&client->dev, "no rows, cols or keymap from pdata\n");
+               return -EINVAL;
+       }
+
+       if (pdata->keymapsize != ADP5589_KEYMAPSIZE) {
+               dev_err(&client->dev, "invalid keymapsize\n");
+               return -EINVAL;
+       }
+
+       if (!pdata->gpimap && pdata->gpimapsize) {
+               dev_err(&client->dev, "invalid gpimap from pdata\n");
+               return -EINVAL;
+       }
+
+       if (pdata->gpimapsize > ADP5589_GPIMAPSIZE_MAX) {
+               dev_err(&client->dev, "invalid gpimapsize\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < pdata->gpimapsize; i++) {
+               unsigned short pin = pdata->gpimap[i].pin;
+
+               if (pin < ADP5589_GPI_PIN_BASE || pin > ADP5589_GPI_PIN_END) {
+                       dev_err(&client->dev, "invalid gpi pin data\n");
+                       return -EINVAL;
+               }
+
+               if ((1 << (pin - ADP5589_GPI_PIN_ROW_BASE)) &
+                               pdata->keypad_en_mask) {
+                       dev_err(&client->dev, "invalid gpi row/col data\n");
+                       return -EINVAL;
+               }
+       }
+
+       if (!client->irq) {
+               dev_err(&client->dev, "no IRQ?\n");
+               return -EINVAL;
+       }
+
+       kpad = kzalloc(sizeof(*kpad), GFP_KERNEL);
+       input = input_allocate_device();
+       if (!kpad || !input) {
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       kpad->client = client;
+       kpad->input = input;
+
+       ret = adp5589_read(client, ADP5589_ID);
+       if (ret < 0) {
+               error = ret;
+               goto err_free_mem;
+       }
+
+       revid = (u8) ret & ADP5589_DEVICE_ID_MASK;
+
+       input->name = client->name;
+       input->phys = "adp5589-keys/input0";
+       input->dev.parent = &client->dev;
+
+       input_set_drvdata(input, kpad);
+
+       input->id.bustype = BUS_I2C;
+       input->id.vendor = 0x0001;
+       input->id.product = 0x0001;
+       input->id.version = revid;
+
+       input->keycodesize = sizeof(kpad->keycode[0]);
+       input->keycodemax = pdata->keymapsize;
+       input->keycode = kpad->keycode;
+
+       memcpy(kpad->keycode, pdata->keymap,
+              pdata->keymapsize * input->keycodesize);
+
+       kpad->gpimap = pdata->gpimap;
+       kpad->gpimapsize = pdata->gpimapsize;
+
+       /* setup input device */
+       __set_bit(EV_KEY, input->evbit);
+
+       if (pdata->repeat)
+               __set_bit(EV_REP, input->evbit);
+
+       for (i = 0; i < input->keycodemax; i++)
+               __set_bit(kpad->keycode[i] & KEY_MAX, input->keybit);
+       __clear_bit(KEY_RESERVED, input->keybit);
+
+       if (kpad->gpimapsize)
+               __set_bit(EV_SW, input->evbit);
+       for (i = 0; i < kpad->gpimapsize; i++)
+               __set_bit(kpad->gpimap[i].sw_evt, input->swbit);
+
+       error = input_register_device(input);
+       if (error) {
+               dev_err(&client->dev, "unable to register input device\n");
+               goto err_free_mem;
+       }
+
+       error = request_threaded_irq(client->irq, NULL, adp5589_irq,
+                                    IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                    client->dev.driver->name, kpad);
+       if (error) {
+               dev_err(&client->dev, "irq %d busy?\n", client->irq);
+               goto err_unreg_dev;
+       }
+
+       error = adp5589_setup(kpad);
+       if (error)
+               goto err_free_irq;
+
+       if (kpad->gpimapsize)
+               adp5589_report_switch_state(kpad);
+
+       error = adp5589_gpio_add(kpad);
+       if (error)
+               goto err_free_irq;
+
+       device_init_wakeup(&client->dev, 1);
+       i2c_set_clientdata(client, kpad);
+
+       dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq);
+       return 0;
+
+err_free_irq:
+       free_irq(client->irq, kpad);
+err_unreg_dev:
+       input_unregister_device(input);
+       input = NULL;
+err_free_mem:
+       input_free_device(input);
+       kfree(kpad);
+
+       return error;
+}
+
+static int __devexit adp5589_remove(struct i2c_client *client)
+{
+       struct adp5589_kpad *kpad = i2c_get_clientdata(client);
+
+       adp5589_write(client, ADP5589_GENERAL_CFG, 0);
+       free_irq(client->irq, kpad);
+       input_unregister_device(kpad->input);
+       adp5589_gpio_remove(kpad);
+       kfree(kpad);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int adp5589_suspend(struct device *dev)
+{
+       struct adp5589_kpad *kpad = dev_get_drvdata(dev);
+       struct i2c_client *client = kpad->client;
+
+       disable_irq(client->irq);
+
+       if (device_may_wakeup(&client->dev))
+               enable_irq_wake(client->irq);
+
+       return 0;
+}
+
+static int adp5589_resume(struct device *dev)
+{
+       struct adp5589_kpad *kpad = dev_get_drvdata(dev);
+       struct i2c_client *client = kpad->client;
+
+       if (device_may_wakeup(&client->dev))
+               disable_irq_wake(client->irq);
+
+       enable_irq(client->irq);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(adp5589_dev_pm_ops, adp5589_suspend, adp5589_resume);
+
+static const struct i2c_device_id adp5589_id[] = {
+       {"adp5589-keys", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, adp5589_id);
+
+static struct i2c_driver adp5589_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .owner = THIS_MODULE,
+               .pm = &adp5589_dev_pm_ops,
+       },
+       .probe = adp5589_probe,
+       .remove = __devexit_p(adp5589_remove),
+       .id_table = adp5589_id,
+};
+
+static int __init adp5589_init(void)
+{
+       return i2c_add_driver(&adp5589_driver);
+}
+module_init(adp5589_init);
+
+static void __exit adp5589_exit(void)
+{
+       i2c_del_driver(&adp5589_driver);
+}
+module_exit(adp5589_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADP5589 Keypad driver");
index eb3006361ee4440179b46377e272f97e6c7010b3..6e6145b9a4c10b2d84bfd3cce75b1ea12a100b43 100644 (file)
@@ -324,7 +324,12 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata)
        unsigned int type = button->type ?: EV_KEY;
        int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;
 
-       input_event(input, type, button->code, !!state);
+       if (type == EV_ABS) {
+               if (state)
+                       input_event(input, type, button->code, button->value);
+       } else {
+               input_event(input, type, button->code, !!state);
+       }
        input_sync(input);
 }
 
@@ -363,7 +368,7 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
                                         struct gpio_button_data *bdata,
                                         struct gpio_keys_button *button)
 {
-       char *desc = button->desc ? button->desc : "gpio_keys";
+       const char *desc = button->desc ? button->desc : "gpio_keys";
        struct device *dev = &pdev->dev;
        unsigned long irqflags;
        int irq, error;
@@ -468,7 +473,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, ddata);
        input_set_drvdata(input, ddata);
 
-       input->name = pdev->name;
+       input->name = pdata->name ? : pdev->name;
        input->phys = "gpio-keys/input0";
        input->dev.parent = &pdev->dev;
        input->open = gpio_keys_open;
diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c
new file mode 100644 (file)
index 0000000..0a9e811
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Touchkey driver for Freescale MPR121 Controllor
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Author: Zhang Jiejing <jiejing.zhang@freescale.com>
+ *
+ * Based on mcs_touchkey.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/i2c/mpr121_touchkey.h>
+
+/* Register definitions */
+#define ELE_TOUCH_STATUS_0_ADDR        0x0
+#define ELE_TOUCH_STATUS_1_ADDR        0X1
+#define MHD_RISING_ADDR                0x2b
+#define NHD_RISING_ADDR                0x2c
+#define NCL_RISING_ADDR                0x2d
+#define FDL_RISING_ADDR                0x2e
+#define MHD_FALLING_ADDR       0x2f
+#define NHD_FALLING_ADDR       0x30
+#define NCL_FALLING_ADDR       0x31
+#define FDL_FALLING_ADDR       0x32
+#define ELE0_TOUCH_THRESHOLD_ADDR      0x41
+#define ELE0_RELEASE_THRESHOLD_ADDR    0x42
+#define AFE_CONF_ADDR                  0x5c
+#define FILTER_CONF_ADDR               0x5d
+
+/*
+ * ELECTRODE_CONF_ADDR: This register configures the number of
+ * enabled capacitance sensing inputs and its run/suspend mode.
+ */
+#define ELECTRODE_CONF_ADDR            0x5e
+#define AUTO_CONFIG_CTRL_ADDR          0x7b
+#define AUTO_CONFIG_USL_ADDR           0x7d
+#define AUTO_CONFIG_LSL_ADDR           0x7e
+#define AUTO_CONFIG_TL_ADDR            0x7f
+
+/* Threshold of touch/release trigger */
+#define TOUCH_THRESHOLD                        0x0f
+#define RELEASE_THRESHOLD              0x0a
+/* Masks for touch and release triggers */
+#define TOUCH_STATUS_MASK              0xfff
+/* MPR121 has 12 keys */
+#define MPR121_MAX_KEY_COUNT           12
+
+struct mpr121_touchkey {
+       struct i2c_client       *client;
+       struct input_dev        *input_dev;
+       unsigned int            key_val;
+       unsigned int            statusbits;
+       unsigned int            keycount;
+       u16                     keycodes[MPR121_MAX_KEY_COUNT];
+};
+
+struct mpr121_init_register {
+       int addr;
+       u8 val;
+};
+
+static const struct mpr121_init_register init_reg_table[] __devinitconst = {
+       { MHD_RISING_ADDR,      0x1 },
+       { NHD_RISING_ADDR,      0x1 },
+       { MHD_FALLING_ADDR,     0x1 },
+       { NHD_FALLING_ADDR,     0x1 },
+       { NCL_FALLING_ADDR,     0xff },
+       { FDL_FALLING_ADDR,     0x02 },
+       { FILTER_CONF_ADDR,     0x04 },
+       { AFE_CONF_ADDR,        0x0b },
+       { AUTO_CONFIG_CTRL_ADDR, 0x0b },
+};
+
+static irqreturn_t mpr_touchkey_interrupt(int irq, void *dev_id)
+{
+       struct mpr121_touchkey *mpr121 = dev_id;
+       struct i2c_client *client = mpr121->client;
+       struct input_dev *input = mpr121->input_dev;
+       unsigned int key_num, key_val, pressed;
+       int reg;
+
+       reg = i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_1_ADDR);
+       if (reg < 0) {
+               dev_err(&client->dev, "i2c read error [%d]\n", reg);
+               goto out;
+       }
+
+       reg <<= 8;
+       reg |= i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_0_ADDR);
+       if (reg < 0) {
+               dev_err(&client->dev, "i2c read error [%d]\n", reg);
+               goto out;
+       }
+
+       reg &= TOUCH_STATUS_MASK;
+       /* use old press bit to figure out which bit changed */
+       key_num = ffs(reg ^ mpr121->statusbits) - 1;
+       pressed = reg & (1 << key_num);
+       mpr121->statusbits = reg;
+
+       key_val = mpr121->keycodes[key_num];
+
+       input_event(input, EV_MSC, MSC_SCAN, key_num);
+       input_report_key(input, key_val, pressed);
+       input_sync(input);
+
+       dev_dbg(&client->dev, "key %d %d %s\n", key_num, key_val,
+               pressed ? "pressed" : "released");
+
+out:
+       return IRQ_HANDLED;
+}
+
+static int __devinit mpr121_phys_init(const struct mpr121_platform_data *pdata,
+                                     struct mpr121_touchkey *mpr121,
+                                     struct i2c_client *client)
+{
+       const struct mpr121_init_register *reg;
+       unsigned char usl, lsl, tl;
+       int i, t, vdd, ret;
+
+       /* Set up touch/release threshold for ele0-ele11 */
+       for (i = 0; i <= MPR121_MAX_KEY_COUNT; i++) {
+               t = ELE0_TOUCH_THRESHOLD_ADDR + (i * 2);
+               ret = i2c_smbus_write_byte_data(client, t, TOUCH_THRESHOLD);
+               if (ret < 0)
+                       goto err_i2c_write;
+               ret = i2c_smbus_write_byte_data(client, t + 1,
+                                               RELEASE_THRESHOLD);
+               if (ret < 0)
+                       goto err_i2c_write;
+       }
+
+       /* Set up init register */
+       for (i = 0; i < ARRAY_SIZE(init_reg_table); i++) {
+               reg = &init_reg_table[i];
+               ret = i2c_smbus_write_byte_data(client, reg->addr, reg->val);
+               if (ret < 0)
+                       goto err_i2c_write;
+       }
+
+
+       /*
+        * Capacitance on sensing input varies and needs to be compensated.
+        * The internal MPR121-auto-configuration can do this if it's
+        * registers are set properly (based on pdata->vdd_uv).
+        */
+       vdd = pdata->vdd_uv / 1000;
+       usl = ((vdd - 700) * 256) / vdd;
+       lsl = (usl * 65) / 100;
+       tl = (usl * 90) / 100;
+       ret = i2c_smbus_write_byte_data(client, AUTO_CONFIG_USL_ADDR, usl);
+       ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_LSL_ADDR, lsl);
+       ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_TL_ADDR, tl);
+       ret |= i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR,
+                                        mpr121->keycount);
+       if (ret != 0)
+               goto err_i2c_write;
+
+       dev_dbg(&client->dev, "set up with %x keys.\n", mpr121->keycount);
+
+       return 0;
+
+err_i2c_write:
+       dev_err(&client->dev, "i2c write error: %d\n", ret);
+       return ret;
+}
+
+static int __devinit mpr_touchkey_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       const struct mpr121_platform_data *pdata = client->dev.platform_data;
+       struct mpr121_touchkey *mpr121;
+       struct input_dev *input_dev;
+       int error;
+       int i;
+
+       if (!pdata) {
+               dev_err(&client->dev, "no platform data defined\n");
+               return -EINVAL;
+       }
+
+       if (!pdata->keymap || !pdata->keymap_size) {
+               dev_err(&client->dev, "missing keymap data\n");
+               return -EINVAL;
+       }
+
+       if (pdata->keymap_size > MPR121_MAX_KEY_COUNT) {
+               dev_err(&client->dev, "too many keys defined\n");
+               return -EINVAL;
+       }
+
+       if (!client->irq) {
+               dev_err(&client->dev, "irq number should not be zero\n");
+               return -EINVAL;
+       }
+
+       mpr121 = kzalloc(sizeof(struct mpr121_touchkey), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!mpr121 || !input_dev) {
+               dev_err(&client->dev, "Failed to allocate memory\n");
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       mpr121->client = client;
+       mpr121->input_dev = input_dev;
+       mpr121->keycount = pdata->keymap_size;
+
+       input_dev->name = "Freescale MPR121 Touchkey";
+       input_dev->id.bustype = BUS_I2C;
+       input_dev->dev.parent = &client->dev;
+       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+
+       input_dev->keycode = mpr121->keycodes;
+       input_dev->keycodesize = sizeof(mpr121->keycodes[0]);
+       input_dev->keycodemax = mpr121->keycount;
+
+       for (i = 0; i < pdata->keymap_size; i++) {
+               input_set_capability(input_dev, EV_KEY, pdata->keymap[i]);
+               mpr121->keycodes[i] = pdata->keymap[i];
+       }
+
+       error = mpr121_phys_init(pdata, mpr121, client);
+       if (error) {
+               dev_err(&client->dev, "Failed to init register\n");
+               goto err_free_mem;
+       }
+
+       error = request_threaded_irq(client->irq, NULL,
+                                    mpr_touchkey_interrupt,
+                                    IRQF_TRIGGER_FALLING,
+                                    client->dev.driver->name, mpr121);
+       if (error) {
+               dev_err(&client->dev, "Failed to register interrupt\n");
+               goto err_free_mem;
+       }
+
+       error = input_register_device(input_dev);
+       if (error)
+               goto err_free_irq;
+
+       i2c_set_clientdata(client, mpr121);
+       device_init_wakeup(&client->dev, pdata->wakeup);
+
+       return 0;
+
+err_free_irq:
+       free_irq(client->irq, mpr121);
+err_free_mem:
+       input_free_device(input_dev);
+       kfree(mpr121);
+       return error;
+}
+
+static int __devexit mpr_touchkey_remove(struct i2c_client *client)
+{
+       struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client);
+
+       free_irq(client->irq, mpr121);
+       input_unregister_device(mpr121->input_dev);
+       kfree(mpr121);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mpr_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       if (device_may_wakeup(&client->dev))
+               enable_irq_wake(client->irq);
+
+       i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR, 0x00);
+
+       return 0;
+}
+
+static int mpr_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(&client->dev))
+               disable_irq_wake(client->irq);
+
+       i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR,
+                                 mpr121->keycount);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(mpr121_touchkey_pm_ops, mpr_suspend, mpr_resume);
+
+static const struct i2c_device_id mpr121_id[] = {
+       { "mpr121_touchkey", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mpr121_id);
+
+static struct i2c_driver mpr_touchkey_driver = {
+       .driver = {
+               .name   = "mpr121",
+               .owner  = THIS_MODULE,
+               .pm     = &mpr121_touchkey_pm_ops,
+       },
+       .id_table       = mpr121_id,
+       .probe          = mpr_touchkey_probe,
+       .remove         = __devexit_p(mpr_touchkey_remove),
+};
+
+static int __init mpr_touchkey_init(void)
+{
+       return i2c_add_driver(&mpr_touchkey_driver);
+}
+module_init(mpr_touchkey_init);
+
+static void __exit mpr_touchkey_exit(void)
+{
+       i2c_del_driver(&mpr_touchkey_driver);
+}
+module_exit(mpr_touchkey_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Zhang Jiejing <jiejing.zhang@freescale.com>");
+MODULE_DESCRIPTION("Touch Key driver for Freescale MPR121 Chip");
index 0e2a19cb43d812ad784f74ed07dfc9fc8f60fa84..33d0bdc837c099a486e2bffc95dbe0fb6a8ee7c4 100644 (file)
@@ -209,6 +209,7 @@ static void omap_kp_tasklet(unsigned long data)
 #endif
                }
        }
+       input_sync(omap_kp_data->input);
        memcpy(keypad_state, new_state, sizeof(keypad_state));
 
        if (key_down) {
@@ -413,7 +414,7 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
        return 0;
 err5:
        for (i = irq_idx - 1; i >=0; i--)
-               free_irq(row_gpios[i], NULL);
+               free_irq(row_gpios[i], omap_kp);
 err4:
        input_unregister_device(omap_kp->input);
        input_dev = NULL;
@@ -444,11 +445,11 @@ static int __devexit omap_kp_remove(struct platform_device *pdev)
                        gpio_free(col_gpios[i]);
                for (i = 0; i < omap_kp->rows; i++) {
                        gpio_free(row_gpios[i]);
-                       free_irq(gpio_to_irq(row_gpios[i]), NULL);
+                       free_irq(gpio_to_irq(row_gpios[i]), omap_kp);
                }
        } else {
                omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
-               free_irq(omap_kp->irq, NULL);
+               free_irq(omap_kp->irq, omap_kp);
        }
 
        del_timer_sync(&omap_kp->timer);
diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c
new file mode 100644 (file)
index 0000000..40b02ae
--- /dev/null
@@ -0,0 +1,799 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/gpio.h>
+#include <linux/input/pmic8xxx-keypad.h>
+
+#define PM8XXX_MAX_ROWS                18
+#define PM8XXX_MAX_COLS                8
+#define PM8XXX_ROW_SHIFT       3
+#define PM8XXX_MATRIX_MAX_SIZE (PM8XXX_MAX_ROWS * PM8XXX_MAX_COLS)
+
+#define PM8XXX_MIN_ROWS                5
+#define PM8XXX_MIN_COLS                5
+
+#define MAX_SCAN_DELAY         128
+#define MIN_SCAN_DELAY         1
+
+/* in nanoseconds */
+#define MAX_ROW_HOLD_DELAY     122000
+#define MIN_ROW_HOLD_DELAY     30500
+
+#define MAX_DEBOUNCE_TIME      20
+#define MIN_DEBOUNCE_TIME      5
+
+#define KEYP_CTRL                      0x148
+
+#define KEYP_CTRL_EVNTS                        BIT(0)
+#define KEYP_CTRL_EVNTS_MASK           0x3
+
+#define KEYP_CTRL_SCAN_COLS_SHIFT      5
+#define KEYP_CTRL_SCAN_COLS_MIN                5
+#define KEYP_CTRL_SCAN_COLS_BITS       0x3
+
+#define KEYP_CTRL_SCAN_ROWS_SHIFT      2
+#define KEYP_CTRL_SCAN_ROWS_MIN                5
+#define KEYP_CTRL_SCAN_ROWS_BITS       0x7
+
+#define KEYP_CTRL_KEYP_EN              BIT(7)
+
+#define KEYP_SCAN                      0x149
+
+#define KEYP_SCAN_READ_STATE           BIT(0)
+#define KEYP_SCAN_DBOUNCE_SHIFT                1
+#define KEYP_SCAN_PAUSE_SHIFT          3
+#define KEYP_SCAN_ROW_HOLD_SHIFT       6
+
+#define KEYP_TEST                      0x14A
+
+#define KEYP_TEST_CLEAR_RECENT_SCAN    BIT(6)
+#define KEYP_TEST_CLEAR_OLD_SCAN       BIT(5)
+#define KEYP_TEST_READ_RESET           BIT(4)
+#define KEYP_TEST_DTEST_EN             BIT(3)
+#define KEYP_TEST_ABORT_READ           BIT(0)
+
+#define KEYP_TEST_DBG_SELECT_SHIFT     1
+
+/* bits of these registers represent
+ * '0' for key press
+ * '1' for key release
+ */
+#define KEYP_RECENT_DATA               0x14B
+#define KEYP_OLD_DATA                  0x14C
+
+#define KEYP_CLOCK_FREQ                        32768
+
+/**
+ * struct pmic8xxx_kp - internal keypad data structure
+ * @pdata - keypad platform data pointer
+ * @input - input device pointer for keypad
+ * @key_sense_irq - key press/release irq number
+ * @key_stuck_irq - key stuck notification irq number
+ * @keycodes - array to hold the key codes
+ * @dev - parent device pointer
+ * @keystate - present key press/release state
+ * @stuckstate - present state when key stuck irq
+ * @ctrl_reg - control register value
+ */
+struct pmic8xxx_kp {
+       const struct pm8xxx_keypad_platform_data *pdata;
+       struct input_dev *input;
+       int key_sense_irq;
+       int key_stuck_irq;
+
+       unsigned short keycodes[PM8XXX_MATRIX_MAX_SIZE];
+
+       struct device *dev;
+       u16 keystate[PM8XXX_MAX_ROWS];
+       u16 stuckstate[PM8XXX_MAX_ROWS];
+
+       u8 ctrl_reg;
+};
+
+static int pmic8xxx_kp_write_u8(struct pmic8xxx_kp *kp,
+                                u8 data, u16 reg)
+{
+       int rc;
+
+       rc = pm8xxx_writeb(kp->dev->parent, reg, data);
+       return rc;
+}
+
+static int pmic8xxx_kp_read(struct pmic8xxx_kp *kp,
+                                u8 *data, u16 reg, unsigned num_bytes)
+{
+       int rc;
+
+       rc = pm8xxx_read_buf(kp->dev->parent, reg, data, num_bytes);
+       return rc;
+}
+
+static int pmic8xxx_kp_read_u8(struct pmic8xxx_kp *kp,
+                                u8 *data, u16 reg)
+{
+       int rc;
+
+       rc = pmic8xxx_kp_read(kp, data, reg, 1);
+       return rc;
+}
+
+static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col)
+{
+       /* all keys pressed on that particular row? */
+       if (col == 0x00)
+               return 1 << kp->pdata->num_cols;
+       else
+               return col & ((1 << kp->pdata->num_cols) - 1);
+}
+
+/*
+ * Synchronous read protocol for RevB0 onwards:
+ *
+ * 1. Write '1' to ReadState bit in KEYP_SCAN register
+ * 2. Wait 2*32KHz clocks, so that HW can successfully enter read mode
+ *    synchronously
+ * 3. Read rows in old array first if events are more than one
+ * 4. Read rows in recent array
+ * 5. Wait 4*32KHz clocks
+ * 6. Write '0' to ReadState bit of KEYP_SCAN register so that hw can
+ *    synchronously exit read mode.
+ */
+static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp)
+{
+       int rc;
+       u8 scan_val;
+
+       rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN);
+       if (rc < 0) {
+               dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc);
+               return rc;
+       }
+
+       scan_val |= 0x1;
+
+       rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
+       if (rc < 0) {
+               dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
+               return rc;
+       }
+
+       /* 2 * 32KHz clocks */
+       udelay((2 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1);
+
+       return rc;
+}
+
+static int pmic8xxx_kp_read_data(struct pmic8xxx_kp *kp, u16 *state,
+                                       u16 data_reg, int read_rows)
+{
+       int rc, row;
+       u8 new_data[PM8XXX_MAX_ROWS];
+
+       rc = pmic8xxx_kp_read(kp, new_data, data_reg, read_rows);
+       if (rc)
+               return rc;
+
+       for (row = 0; row < kp->pdata->num_rows; row++) {
+               dev_dbg(kp->dev, "new_data[%d] = %d\n", row,
+                                       new_data[row]);
+               state[row] = pmic8xxx_col_state(kp, new_data[row]);
+       }
+
+       return rc;
+}
+
+static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
+                                        u16 *old_state)
+{
+       int rc, read_rows;
+       u8 scan_val;
+
+       if (kp->pdata->num_rows < PM8XXX_MIN_ROWS)
+               read_rows = PM8XXX_MIN_ROWS;
+       else
+               read_rows = kp->pdata->num_rows;
+
+       pmic8xxx_chk_sync_read(kp);
+
+       if (old_state) {
+               rc = pmic8xxx_kp_read_data(kp, old_state, KEYP_OLD_DATA,
+                                               read_rows);
+               if (rc < 0) {
+                       dev_err(kp->dev,
+                               "Error reading KEYP_OLD_DATA, rc=%d\n", rc);
+                       return rc;
+               }
+       }
+
+       rc = pmic8xxx_kp_read_data(kp, new_state, KEYP_RECENT_DATA,
+                                        read_rows);
+       if (rc < 0) {
+               dev_err(kp->dev,
+                       "Error reading KEYP_RECENT_DATA, rc=%d\n", rc);
+               return rc;
+       }
+
+       /* 4 * 32KHz clocks */
+       udelay((4 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1);
+
+       rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN);
+       if (rc < 0) {
+               dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc);
+               return rc;
+       }
+
+       scan_val &= 0xFE;
+       rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
+       if (rc < 0)
+               dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
+
+       return rc;
+}
+
+static void __pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
+                                        u16 *old_state)
+{
+       int row, col, code;
+
+       for (row = 0; row < kp->pdata->num_rows; row++) {
+               int bits_changed = new_state[row] ^ old_state[row];
+
+               if (!bits_changed)
+                       continue;
+
+               for (col = 0; col < kp->pdata->num_cols; col++) {
+                       if (!(bits_changed & (1 << col)))
+                               continue;
+
+                       dev_dbg(kp->dev, "key [%d:%d] %s\n", row, col,
+                                       !(new_state[row] & (1 << col)) ?
+                                       "pressed" : "released");
+
+                       code = MATRIX_SCAN_CODE(row, col, PM8XXX_ROW_SHIFT);
+
+                       input_event(kp->input, EV_MSC, MSC_SCAN, code);
+                       input_report_key(kp->input,
+                                       kp->keycodes[code],
+                                       !(new_state[row] & (1 << col)));
+
+                       input_sync(kp->input);
+               }
+       }
+}
+
+static bool pmic8xxx_detect_ghost_keys(struct pmic8xxx_kp *kp, u16 *new_state)
+{
+       int row, found_first = -1;
+       u16 check, row_state;
+
+       check = 0;
+       for (row = 0; row < kp->pdata->num_rows; row++) {
+               row_state = (~new_state[row]) &
+                                ((1 << kp->pdata->num_cols) - 1);
+
+               if (hweight16(row_state) > 1) {
+                       if (found_first == -1)
+                               found_first = row;
+                       if (check & row_state) {
+                               dev_dbg(kp->dev, "detected ghost key on row[%d]"
+                                        " and row[%d]\n", found_first, row);
+                               return true;
+                       }
+               }
+               check |= row_state;
+       }
+       return false;
+}
+
+static int pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, unsigned int events)
+{
+       u16 new_state[PM8XXX_MAX_ROWS];
+       u16 old_state[PM8XXX_MAX_ROWS];
+       int rc;
+
+       switch (events) {
+       case 0x1:
+               rc = pmic8xxx_kp_read_matrix(kp, new_state, NULL);
+               if (rc < 0)
+                       return rc;
+
+               /* detecting ghost key is not an error */
+               if (pmic8xxx_detect_ghost_keys(kp, new_state))
+                       return 0;
+               __pmic8xxx_kp_scan_matrix(kp, new_state, kp->keystate);
+               memcpy(kp->keystate, new_state, sizeof(new_state));
+       break;
+       case 0x3: /* two events - eventcounter is gray-coded */
+               rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state);
+               if (rc < 0)
+                       return rc;
+
+               __pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate);
+               __pmic8xxx_kp_scan_matrix(kp, new_state, old_state);
+               memcpy(kp->keystate, new_state, sizeof(new_state));
+       break;
+       case 0x2:
+               dev_dbg(kp->dev, "Some key events were lost\n");
+               rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state);
+               if (rc < 0)
+                       return rc;
+               __pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate);
+               __pmic8xxx_kp_scan_matrix(kp, new_state, old_state);
+               memcpy(kp->keystate, new_state, sizeof(new_state));
+       break;
+       default:
+               rc = -EINVAL;
+       }
+       return rc;
+}
+
+/*
+ * NOTE: We are reading recent and old data registers blindly
+ * whenever key-stuck interrupt happens, because events counter doesn't
+ * get updated when this interrupt happens due to key stuck doesn't get
+ * considered as key state change.
+ *
+ * We are not using old data register contents after they are being read
+ * because it might report the key which was pressed before the key being stuck
+ * as stuck key because it's pressed status is stored in the old data
+ * register.
+ */
+static irqreturn_t pmic8xxx_kp_stuck_irq(int irq, void *data)
+{
+       u16 new_state[PM8XXX_MAX_ROWS];
+       u16 old_state[PM8XXX_MAX_ROWS];
+       int rc;
+       struct pmic8xxx_kp *kp = data;
+
+       rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state);
+       if (rc < 0) {
+               dev_err(kp->dev, "failed to read keypad matrix\n");
+               return IRQ_HANDLED;
+       }
+
+       __pmic8xxx_kp_scan_matrix(kp, new_state, kp->stuckstate);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t pmic8xxx_kp_irq(int irq, void *data)
+{
+       struct pmic8xxx_kp *kp = data;
+       u8 ctrl_val, events;
+       int rc;
+
+       rc = pmic8xxx_kp_read(kp, &ctrl_val, KEYP_CTRL, 1);
+       if (rc < 0) {
+               dev_err(kp->dev, "failed to read keyp_ctrl register\n");
+               return IRQ_HANDLED;
+       }
+
+       events = ctrl_val & KEYP_CTRL_EVNTS_MASK;
+
+       rc = pmic8xxx_kp_scan_matrix(kp, events);
+       if (rc < 0)
+               dev_err(kp->dev, "failed to scan matrix\n");
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)
+{
+       int bits, rc, cycles;
+       u8 scan_val = 0, ctrl_val = 0;
+       static const u8 row_bits[] = {
+               0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7,
+       };
+
+       /* Find column bits */
+       if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN)
+               bits = 0;
+       else
+               bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN;
+       ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) <<
+               KEYP_CTRL_SCAN_COLS_SHIFT;
+
+       /* Find row bits */
+       if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN)
+               bits = 0;
+       else
+               bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN];
+
+       ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT);
+
+       rc = pmic8xxx_kp_write_u8(kp, ctrl_val, KEYP_CTRL);
+       if (rc < 0) {
+               dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc);
+               return rc;
+       }
+
+       bits = (kp->pdata->debounce_ms / 5) - 1;
+
+       scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT);
+
+       bits = fls(kp->pdata->scan_delay_ms) - 1;
+       scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT);
+
+       /* Row hold time is a multiple of 32KHz cycles. */
+       cycles = (kp->pdata->row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC;
+
+       scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT);
+
+       rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
+       if (rc)
+               dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
+
+       return rc;
+
+}
+
+static int  __devinit pmic8xxx_kp_config_gpio(int gpio_start, int num_gpios,
+                       struct pmic8xxx_kp *kp, struct pm_gpio *gpio_config)
+{
+       int     rc, i;
+
+       if (gpio_start < 0 || num_gpios < 0)
+               return -EINVAL;
+
+       for (i = 0; i < num_gpios; i++) {
+               rc = pm8xxx_gpio_config(gpio_start + i, gpio_config);
+               if (rc) {
+                       dev_err(kp->dev, "%s: FAIL pm8xxx_gpio_config():"
+                                       "for PM GPIO [%d] rc=%d.\n",
+                                       __func__, gpio_start + i, rc);
+                       return rc;
+               }
+        }
+
+       return 0;
+}
+
+static int pmic8xxx_kp_enable(struct pmic8xxx_kp *kp)
+{
+       int rc;
+
+       kp->ctrl_reg |= KEYP_CTRL_KEYP_EN;
+
+       rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
+       if (rc < 0)
+               dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc);
+
+       return rc;
+}
+
+static int pmic8xxx_kp_disable(struct pmic8xxx_kp *kp)
+{
+       int rc;
+
+       kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN;
+
+       rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
+       if (rc < 0)
+               return rc;
+
+       return rc;
+}
+
+static int pmic8xxx_kp_open(struct input_dev *dev)
+{
+       struct pmic8xxx_kp *kp = input_get_drvdata(dev);
+
+       return pmic8xxx_kp_enable(kp);
+}
+
+static void pmic8xxx_kp_close(struct input_dev *dev)
+{
+       struct pmic8xxx_kp *kp = input_get_drvdata(dev);
+
+       pmic8xxx_kp_disable(kp);
+}
+
+/*
+ * keypad controller should be initialized in the following sequence
+ * only, otherwise it might get into FSM stuck state.
+ *
+ * - Initialize keypad control parameters, like no. of rows, columns,
+ *   timing values etc.,
+ * - configure rows and column gpios pull up/down.
+ * - set irq edge type.
+ * - enable the keypad controller.
+ */
+static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev)
+{
+       const struct pm8xxx_keypad_platform_data *pdata = mfd_get_data(pdev);
+       const struct matrix_keymap_data *keymap_data;
+       struct pmic8xxx_kp *kp;
+       int rc;
+       u8 ctrl_val;
+
+       struct pm_gpio kypd_drv = {
+               .direction      = PM_GPIO_DIR_OUT,
+               .output_buffer  = PM_GPIO_OUT_BUF_OPEN_DRAIN,
+               .output_value   = 0,
+               .pull           = PM_GPIO_PULL_NO,
+               .vin_sel        = PM_GPIO_VIN_S3,
+               .out_strength   = PM_GPIO_STRENGTH_LOW,
+               .function       = PM_GPIO_FUNC_1,
+               .inv_int_pol    = 1,
+       };
+
+       struct pm_gpio kypd_sns = {
+               .direction      = PM_GPIO_DIR_IN,
+               .pull           = PM_GPIO_PULL_UP_31P5,
+               .vin_sel        = PM_GPIO_VIN_S3,
+               .out_strength   = PM_GPIO_STRENGTH_NO,
+               .function       = PM_GPIO_FUNC_NORMAL,
+               .inv_int_pol    = 1,
+       };
+
+
+       if (!pdata || !pdata->num_cols || !pdata->num_rows ||
+               pdata->num_cols > PM8XXX_MAX_COLS ||
+               pdata->num_rows > PM8XXX_MAX_ROWS ||
+               pdata->num_cols < PM8XXX_MIN_COLS) {
+               dev_err(&pdev->dev, "invalid platform data\n");
+               return -EINVAL;
+       }
+
+       if (!pdata->scan_delay_ms ||
+               pdata->scan_delay_ms > MAX_SCAN_DELAY ||
+               pdata->scan_delay_ms < MIN_SCAN_DELAY ||
+               !is_power_of_2(pdata->scan_delay_ms)) {
+               dev_err(&pdev->dev, "invalid keypad scan time supplied\n");
+               return -EINVAL;
+       }
+
+       if (!pdata->row_hold_ns ||
+               pdata->row_hold_ns > MAX_ROW_HOLD_DELAY ||
+               pdata->row_hold_ns < MIN_ROW_HOLD_DELAY ||
+               ((pdata->row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) {
+               dev_err(&pdev->dev, "invalid keypad row hold time supplied\n");
+               return -EINVAL;
+       }
+
+       if (!pdata->debounce_ms ||
+               ((pdata->debounce_ms % 5) != 0) ||
+               pdata->debounce_ms > MAX_DEBOUNCE_TIME ||
+               pdata->debounce_ms < MIN_DEBOUNCE_TIME) {
+               dev_err(&pdev->dev, "invalid debounce time supplied\n");
+               return -EINVAL;
+       }
+
+       keymap_data = pdata->keymap_data;
+       if (!keymap_data) {
+               dev_err(&pdev->dev, "no keymap data supplied\n");
+               return -EINVAL;
+       }
+
+       kp = kzalloc(sizeof(*kp), GFP_KERNEL);
+       if (!kp)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, kp);
+
+       kp->pdata       = pdata;
+       kp->dev         = &pdev->dev;
+
+       kp->input = input_allocate_device();
+       if (!kp->input) {
+               dev_err(&pdev->dev, "unable to allocate input device\n");
+               rc = -ENOMEM;
+               goto err_alloc_device;
+       }
+
+       kp->key_sense_irq = platform_get_irq(pdev, 0);
+       if (kp->key_sense_irq < 0) {
+               dev_err(&pdev->dev, "unable to get keypad sense irq\n");
+               rc = -ENXIO;
+               goto err_get_irq;
+       }
+
+       kp->key_stuck_irq = platform_get_irq(pdev, 1);
+       if (kp->key_stuck_irq < 0) {
+               dev_err(&pdev->dev, "unable to get keypad stuck irq\n");
+               rc = -ENXIO;
+               goto err_get_irq;
+       }
+
+       kp->input->name = pdata->input_name ? : "PMIC8XXX keypad";
+       kp->input->phys = pdata->input_phys_device ? : "pmic8xxx_keypad/input0";
+
+       kp->input->dev.parent   = &pdev->dev;
+
+       kp->input->id.bustype   = BUS_I2C;
+       kp->input->id.version   = 0x0001;
+       kp->input->id.product   = 0x0001;
+       kp->input->id.vendor    = 0x0001;
+
+       kp->input->evbit[0]     = BIT_MASK(EV_KEY);
+
+       if (pdata->rep)
+               __set_bit(EV_REP, kp->input->evbit);
+
+       kp->input->keycode      = kp->keycodes;
+       kp->input->keycodemax   = PM8XXX_MATRIX_MAX_SIZE;
+       kp->input->keycodesize  = sizeof(kp->keycodes);
+       kp->input->open         = pmic8xxx_kp_open;
+       kp->input->close        = pmic8xxx_kp_close;
+
+       matrix_keypad_build_keymap(keymap_data, PM8XXX_ROW_SHIFT,
+                                       kp->input->keycode, kp->input->keybit);
+
+       input_set_capability(kp->input, EV_MSC, MSC_SCAN);
+       input_set_drvdata(kp->input, kp);
+
+       /* initialize keypad state */
+       memset(kp->keystate, 0xff, sizeof(kp->keystate));
+       memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate));
+
+       rc = pmic8xxx_kpd_init(kp);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "unable to initialize keypad controller\n");
+               goto err_get_irq;
+       }
+
+       rc = pmic8xxx_kp_config_gpio(pdata->cols_gpio_start,
+                                       pdata->num_cols, kp, &kypd_sns);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "unable to configure keypad sense lines\n");
+               goto err_gpio_config;
+       }
+
+       rc = pmic8xxx_kp_config_gpio(pdata->rows_gpio_start,
+                                       pdata->num_rows, kp, &kypd_drv);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "unable to configure keypad drive lines\n");
+               goto err_gpio_config;
+       }
+
+       rc = request_any_context_irq(kp->key_sense_irq, pmic8xxx_kp_irq,
+                                IRQF_TRIGGER_RISING, "pmic-keypad", kp);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "failed to request keypad sense irq\n");
+               goto err_get_irq;
+       }
+
+       rc = request_any_context_irq(kp->key_stuck_irq, pmic8xxx_kp_stuck_irq,
+                                IRQF_TRIGGER_RISING, "pmic-keypad-stuck", kp);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "failed to request keypad stuck irq\n");
+               goto err_req_stuck_irq;
+       }
+
+       rc = pmic8xxx_kp_read_u8(kp, &ctrl_val, KEYP_CTRL);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "failed to read KEYP_CTRL register\n");
+               goto err_pmic_reg_read;
+       }
+
+       kp->ctrl_reg = ctrl_val;
+
+       rc = input_register_device(kp->input);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "unable to register keypad input device\n");
+               goto err_pmic_reg_read;
+       }
+
+       device_init_wakeup(&pdev->dev, pdata->wakeup);
+
+       return 0;
+
+err_pmic_reg_read:
+       free_irq(kp->key_stuck_irq, NULL);
+err_req_stuck_irq:
+       free_irq(kp->key_sense_irq, NULL);
+err_gpio_config:
+err_get_irq:
+       input_free_device(kp->input);
+err_alloc_device:
+       platform_set_drvdata(pdev, NULL);
+       kfree(kp);
+       return rc;
+}
+
+static int __devexit pmic8xxx_kp_remove(struct platform_device *pdev)
+{
+       struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
+
+       device_init_wakeup(&pdev->dev, 0);
+       free_irq(kp->key_stuck_irq, NULL);
+       free_irq(kp->key_sense_irq, NULL);
+       input_unregister_device(kp->input);
+       kfree(kp);
+
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pmic8xxx_kp_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
+       struct input_dev *input_dev = kp->input;
+
+       if (device_may_wakeup(dev)) {
+               enable_irq_wake(kp->key_sense_irq);
+       } else {
+               mutex_lock(&input_dev->mutex);
+
+               if (input_dev->users)
+                       pmic8xxx_kp_disable(kp);
+
+               mutex_unlock(&input_dev->mutex);
+       }
+
+       return 0;
+}
+
+static int pmic8xxx_kp_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
+       struct input_dev *input_dev = kp->input;
+
+       if (device_may_wakeup(dev)) {
+               disable_irq_wake(kp->key_sense_irq);
+       } else {
+               mutex_lock(&input_dev->mutex);
+
+               if (input_dev->users)
+                       pmic8xxx_kp_enable(kp);
+
+               mutex_unlock(&input_dev->mutex);
+       }
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm8xxx_kp_pm_ops,
+                        pmic8xxx_kp_suspend, pmic8xxx_kp_resume);
+
+static struct platform_driver pmic8xxx_kp_driver = {
+       .probe          = pmic8xxx_kp_probe,
+       .remove         = __devexit_p(pmic8xxx_kp_remove),
+       .driver         = {
+               .name = PM8XXX_KEYPAD_DEV_NAME,
+               .owner = THIS_MODULE,
+               .pm = &pm8xxx_kp_pm_ops,
+       },
+};
+
+static int __init pmic8xxx_kp_init(void)
+{
+       return platform_driver_register(&pmic8xxx_kp_driver);
+}
+module_init(pmic8xxx_kp_init);
+
+static void __exit pmic8xxx_kp_exit(void)
+{
+       platform_driver_unregister(&pmic8xxx_kp_driver);
+}
+module_exit(pmic8xxx_kp_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PMIC8XXX keypad driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:pmic8xxx_keypad");
+MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>");
index fba8404c7297536d80fcbc2a3efac6129f996ace..ca7b89196ab79a4ceee7b05ebe2ce65044c055b3 100644 (file)
@@ -248,6 +248,7 @@ static const struct i2c_device_id qt1070_id[] = {
        { "qt1070", 0 },
        { },
 };
+MODULE_DEVICE_TABLE(i2c, qt1070_id);
 
 static struct i2c_driver qt1070_driver = {
        .driver = {
index d7dafd9425b69b0682035822185900b8e8ac3d72..6876700a4469d191446a20a9c81dc2606279b9d2 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/input.h>
 #include <linux/input/sh_keysc.h>
 #include <linux/bitmap.h>
-#include <linux/clk.h>
+#include <linux/pm_runtime.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 
@@ -32,12 +32,11 @@ static const struct {
        [SH_KEYSC_MODE_3] = { 2, 4, 7 },
        [SH_KEYSC_MODE_4] = { 3, 6, 6 },
        [SH_KEYSC_MODE_5] = { 4, 6, 7 },
-       [SH_KEYSC_MODE_6] = { 5, 7, 7 },
+       [SH_KEYSC_MODE_6] = { 5, 8, 8 },
 };
 
 struct sh_keysc_priv {
        void __iomem *iomem_base;
-       struct clk *clk;
        DECLARE_BITMAP(last_keys, SH_KEYSC_MAXKEYS);
        struct input_dev *input;
        struct sh_keysc_info pdata;
@@ -169,7 +168,6 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
        struct sh_keysc_info *pdata;
        struct resource *res;
        struct input_dev *input;
-       char clk_name[8];
        int i;
        int irq, error;
 
@@ -210,19 +208,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
                goto err1;
        }
 
-       snprintf(clk_name, sizeof(clk_name), "keysc%d", pdev->id);
-       priv->clk = clk_get(&pdev->dev, clk_name);
-       if (IS_ERR(priv->clk)) {
-               dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
-               error = PTR_ERR(priv->clk);
-               goto err2;
-       }
-
        priv->input = input_allocate_device();
        if (!priv->input) {
                dev_err(&pdev->dev, "failed to allocate input device\n");
                error = -ENOMEM;
-               goto err3;
+               goto err2;
        }
 
        input = priv->input;
@@ -241,10 +231,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
        input->keycodesize = sizeof(pdata->keycodes[0]);
        input->keycodemax = ARRAY_SIZE(pdata->keycodes);
 
-       error = request_irq(irq, sh_keysc_isr, 0, pdev->name, pdev);
+       error = request_threaded_irq(irq, NULL, sh_keysc_isr, IRQF_ONESHOT,
+                                    dev_name(&pdev->dev), pdev);
        if (error) {
                dev_err(&pdev->dev, "failed to request IRQ\n");
-               goto err4;
+               goto err3;
        }
 
        for (i = 0; i < SH_KEYSC_MAXKEYS; i++)
@@ -254,10 +245,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
        error = input_register_device(input);
        if (error) {
                dev_err(&pdev->dev, "failed to register input device\n");
-               goto err5;
+               goto err4;
        }
 
-       clk_enable(priv->clk);
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
 
        sh_keysc_write(priv, KYCR1, (sh_keysc_mode[pdata->mode].kymd << 8) |
                       pdata->scan_timing);
@@ -267,12 +259,10 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
 
        return 0;
 
- err5:
-       free_irq(irq, pdev);
  err4:
-       input_free_device(input);
+       free_irq(irq, pdev);
  err3:
-       clk_put(priv->clk);
+       input_free_device(input);
  err2:
        iounmap(priv->iomem_base);
  err1:
@@ -292,8 +282,8 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
        free_irq(platform_get_irq(pdev, 0), pdev);
        iounmap(priv->iomem_base);
 
-       clk_disable(priv->clk);
-       clk_put(priv->clk);
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
 
        platform_set_drvdata(pdev, NULL);
        kfree(priv);
@@ -301,6 +291,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
        return 0;
 }
 
+#if CONFIG_PM_SLEEP
 static int sh_keysc_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -311,14 +302,13 @@ static int sh_keysc_suspend(struct device *dev)
        value = sh_keysc_read(priv, KYCR1);
 
        if (device_may_wakeup(dev)) {
-               value |= 0x80;
+               sh_keysc_write(priv, KYCR1, value | 0x80);
                enable_irq_wake(irq);
        } else {
-               value &= ~0x80;
+               sh_keysc_write(priv, KYCR1, value & ~0x80);
+               pm_runtime_put_sync(dev);
        }
 
-       sh_keysc_write(priv, KYCR1, value);
-
        return 0;
 }
 
@@ -329,16 +319,17 @@ static int sh_keysc_resume(struct device *dev)
 
        if (device_may_wakeup(dev))
                disable_irq_wake(irq);
+       else
+               pm_runtime_get_sync(dev);
 
        return 0;
 }
+#endif
 
-static const struct dev_pm_ops sh_keysc_dev_pm_ops = {
-       .suspend = sh_keysc_suspend,
-       .resume = sh_keysc_resume,
-};
+static SIMPLE_DEV_PM_OPS(sh_keysc_dev_pm_ops,
+                        sh_keysc_suspend, sh_keysc_resume);
 
-struct platform_driver sh_keysc_device_driver = {
+static struct platform_driver sh_keysc_device_driver = {
        .probe          = sh_keysc_probe,
        .remove         = __devexit_p(sh_keysc_remove),
        .driver         = {
index 99ce9032d08cd61f437fb5e3256db537cfa751e8..2b3b73ec6689599596704a5bd175ee98d7b2d23b 100644 (file)
@@ -66,12 +66,11 @@ struct tegra_kbc {
        void __iomem *mmio;
        struct input_dev *idev;
        unsigned int irq;
-       unsigned int wake_enable_rows;
-       unsigned int wake_enable_cols;
        spinlock_t lock;
        unsigned int repoll_dly;
        unsigned long cp_dly_jiffies;
        bool use_fn_map;
+       bool use_ghost_filter;
        const struct tegra_kbc_platform_data *pdata;
        unsigned short keycode[KBC_MAX_KEY * 2];
        unsigned short current_keys[KBC_MAX_KPENT];
@@ -260,6 +259,8 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
        unsigned int num_down = 0;
        unsigned long flags;
        bool fn_keypress = false;
+       bool key_in_same_row = false;
+       bool key_in_same_col = false;
 
        spin_lock_irqsave(&kbc->lock, flags);
        for (i = 0; i < KBC_MAX_KPENT; i++) {
@@ -284,6 +285,34 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
                val >>= 8;
        }
 
+       /*
+        * Matrix keyboard designs are prone to keyboard ghosting.
+        * Ghosting occurs if there are 3 keys such that -
+        * any 2 of the 3 keys share a row, and any 2 of them share a column.
+        * If so ignore the key presses for this iteration.
+        */
+       if ((kbc->use_ghost_filter) && (num_down >= 3)) {
+               for (i = 0; i < num_down; i++) {
+                       unsigned int j;
+                       u8 curr_col = scancodes[i] & 0x07;
+                       u8 curr_row = scancodes[i] >> KBC_ROW_SHIFT;
+
+                       /*
+                        * Find 2 keys such that one key is in the same row
+                        * and the other is in the same column as the i-th key.
+                        */
+                       for (j = i + 1; j < num_down; j++) {
+                               u8 col = scancodes[j] & 0x07;
+                               u8 row = scancodes[j] >> KBC_ROW_SHIFT;
+
+                               if (col == curr_col)
+                                       key_in_same_col = true;
+                               if (row == curr_row)
+                                       key_in_same_row = true;
+                       }
+               }
+       }
+
        /*
         * If the platform uses Fn keymaps, translate keys on a Fn keypress.
         * Function keycodes are KBC_MAX_KEY apart from the plain keycodes.
@@ -297,6 +326,10 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
 
        spin_unlock_irqrestore(&kbc->lock, flags);
 
+       /* Ignore the key presses for this iteration? */
+       if (key_in_same_col && key_in_same_row)
+               return;
+
        tegra_kbc_report_released_keys(kbc->idev,
                                       kbc->current_keys, kbc->num_pressed_keys,
                                       keycodes, num_down);
@@ -383,21 +416,11 @@ static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter)
        int i;
        unsigned int rst_val;
 
-       BUG_ON(pdata->wake_cnt > KBC_MAX_KEY);
-       rst_val = (filter && pdata->wake_cnt) ? ~0 : 0;
+       /* Either mask all keys or none. */
+       rst_val = (filter && !pdata->wakeup) ? ~0 : 0;
 
        for (i = 0; i < KBC_MAX_ROW; i++)
                writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4);
-
-       if (filter) {
-               for (i = 0; i < pdata->wake_cnt; i++) {
-                       u32 val, addr;
-                       addr = pdata->wake_cfg[i].row * 4 + KBC_ROW0_MASK_0;
-                       val = readl(kbc->mmio + addr);
-                       val &= ~(1 << pdata->wake_cfg[i].col);
-                       writel(val, kbc->mmio + addr);
-               }
-       }
 }
 
 static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
@@ -559,7 +582,6 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
        struct resource *res;
        int irq;
        int err;
-       int i;
        int num_rows = 0;
        unsigned int debounce_cnt;
        unsigned int scan_time_rows;
@@ -616,13 +638,6 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
                goto err_iounmap;
        }
 
-       kbc->wake_enable_rows = 0;
-       kbc->wake_enable_cols = 0;
-       for (i = 0; i < pdata->wake_cnt; i++) {
-               kbc->wake_enable_rows |= (1 << pdata->wake_cfg[i].row);
-               kbc->wake_enable_cols |= (1 << pdata->wake_cfg[i].col);
-       }
-
        /*
         * The time delay between two consecutive reads of the FIFO is
         * the sum of the repeat time and the time taken for scanning
@@ -652,6 +667,7 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
                input_dev->keycodemax *= 2;
 
        kbc->use_fn_map = pdata->use_fn_map;
+       kbc->use_ghost_filter = pdata->use_ghost_filter;
        keymap_data = pdata->keymap_data ?: &tegra_kbc_default_keymap_data;
        matrix_keypad_build_keymap(keymap_data, KBC_ROW_SHIFT,
                                   input_dev->keycode, input_dev->keybit);
index f9cf0881b0e3cf386a3e606d462aebf4bacd5575..45dc6aa62ba4fce3715c20b504da7f02745997e5 100644 (file)
@@ -330,6 +330,17 @@ config INPUT_PWM_BEEPER
          To compile this driver as a module, choose M here: the module will be
          called pwm-beeper.
 
+config INPUT_PMIC8XXX_PWRKEY
+       tristate "PMIC8XXX power key support"
+       depends on MFD_PM8XXX
+       help
+         Say Y here if you want support for the PMIC8XXX power key.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called pmic8xxx-pwrkey.
+
 config INPUT_GPIO_ROTARY_ENCODER
        tristate "Rotary encoders connected to GPIO pins"
        depends on GPIOLIB && GENERIC_GPIO
index e3f7984e627427ead449de2d6e6452d3aac1c915..38efb2cb182b90646e7e4e7e41288e0222fca641 100644 (file)
@@ -33,6 +33,7 @@ obj-$(CONFIG_INPUT_PCF8574)           += pcf8574_keypad.o
 obj-$(CONFIG_INPUT_PCSPKR)             += pcspkr.o
 obj-$(CONFIG_INPUT_POWERMATE)          += powermate.o
 obj-$(CONFIG_INPUT_PWM_BEEPER)         += pwm-beeper.o
+obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY)    += pmic8xxx-pwrkey.o
 obj-$(CONFIG_INPUT_RB532_BUTTON)       += rb532_button.o
 obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)        += rotary_encoder.o
 obj-$(CONFIG_INPUT_SGI_BTNS)           += sgi_btns.o
index c431d09e401ac2f91d0627990c781cc2f183a69f..c3a62c42cd28838a64fa4cb432d2ac4e430a0fc0 100644 (file)
@@ -79,13 +79,7 @@ struct ad714x_slider_drv {
 struct ad714x_wheel_drv {
        int abs_pos;
        int flt_pos;
-       int pre_mean_value;
        int pre_highest_stage;
-       int pre_mean_value_no_offset;
-       int mean_value;
-       int mean_value_no_offset;
-       int pos_offset;
-       int pos_ratio;
        int highest_stage;
        enum ad714x_device_state state;
        struct input_dev *input;
@@ -158,10 +152,10 @@ static void ad714x_use_com_int(struct ad714x_chip *ad714x,
        unsigned short data;
        unsigned short mask;
 
-       mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage);
+       mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
 
        ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
-       data |= 1 << start_stage;
+       data |= 1 << end_stage;
        ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
 
        ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
@@ -175,10 +169,10 @@ static void ad714x_use_thr_int(struct ad714x_chip *ad714x,
        unsigned short data;
        unsigned short mask;
 
-       mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage);
+       mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
 
        ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
-       data &= ~(1 << start_stage);
+       data &= ~(1 << end_stage);
        ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
 
        ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
@@ -404,7 +398,6 @@ static void ad714x_slider_state_machine(struct ad714x_chip *ad714x, int idx)
                                ad714x_slider_cal_highest_stage(ad714x, idx);
                                ad714x_slider_cal_abs_pos(ad714x, idx);
                                ad714x_slider_cal_flt_pos(ad714x, idx);
-
                                input_report_abs(sw->input, ABS_X, sw->flt_pos);
                                input_report_key(sw->input, BTN_TOUCH, 1);
                        } else {
@@ -468,104 +461,41 @@ static void ad714x_wheel_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
 /*
  * When the scroll wheel is activated, we compute the absolute position based
  * on the sensor values. To calculate the position, we first determine the
- * sensor that has the greatest response among the sensors that constitutes
- * the scrollwheel. Then we determined the sensors on either sides of the
+ * sensor that has the greatest response among the sensors that constitutes
+ * the scrollwheel. Then we determined the sensors on either sides of the
  * sensor with the highest response and we apply weights to these sensors. The
- * result of this computation gives us the mean value which defined by the
- * following formula:
- * For i= second_before_highest_stage to i= second_after_highest_stage
- *         v += Sensor response(i)*WEIGHT*(i+3)
- *         w += Sensor response(i)
- * Mean_Value=v/w
- * pos_on_scrollwheel = (Mean_Value - position_offset) / position_ratio
+ * result of this computation gives us the mean value.
  */
 
-#define WEIGHT_FACTOR 30
-/* This constant prevents the "PositionOffset" from reaching a big value */
-#define OFFSET_POSITION_CLAMP  120
 static void ad714x_wheel_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
 {
        struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
        struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
        int stage_num = hw->end_stage - hw->start_stage + 1;
-       int second_before, first_before, highest, first_after, second_after;
+       int first_before, highest, first_after;
        int a_param, b_param;
 
-       /* Calculate Mean value */
-
-       second_before = (sw->highest_stage + stage_num - 2) % stage_num;
        first_before = (sw->highest_stage + stage_num - 1) % stage_num;
        highest = sw->highest_stage;
        first_after = (sw->highest_stage + stage_num + 1) % stage_num;
-       second_after = (sw->highest_stage + stage_num + 2) % stage_num;
-
-       if (((sw->highest_stage - hw->start_stage) > 1) &&
-           ((hw->end_stage - sw->highest_stage) > 1)) {
-               a_param = ad714x->sensor_val[second_before] *
-                       (second_before - hw->start_stage + 3) +
-                       ad714x->sensor_val[first_before] *
-                       (second_before - hw->start_stage + 3) +
-                       ad714x->sensor_val[highest] *
-                       (second_before - hw->start_stage + 3) +
-                       ad714x->sensor_val[first_after] *
-                       (first_after - hw->start_stage + 3) +
-                       ad714x->sensor_val[second_after] *
-                       (second_after - hw->start_stage + 3);
-       } else {
-               a_param = ad714x->sensor_val[second_before] *
-                       (second_before - hw->start_stage + 1) +
-                       ad714x->sensor_val[first_before] *
-                       (second_before - hw->start_stage + 2) +
-                       ad714x->sensor_val[highest] *
-                       (second_before - hw->start_stage + 3) +
-                       ad714x->sensor_val[first_after] *
-                       (first_after - hw->start_stage + 4) +
-                       ad714x->sensor_val[second_after] *
-                       (second_after - hw->start_stage + 5);
-       }
-       a_param *= WEIGHT_FACTOR;
 
-       b_param = ad714x->sensor_val[second_before] +
+       a_param = ad714x->sensor_val[highest] *
+               (highest - hw->start_stage) +
+               ad714x->sensor_val[first_before] *
+               (highest - hw->start_stage - 1) +
+               ad714x->sensor_val[first_after] *
+               (highest - hw->start_stage + 1);
+       b_param = ad714x->sensor_val[highest] +
                ad714x->sensor_val[first_before] +
-               ad714x->sensor_val[highest] +
-               ad714x->sensor_val[first_after] +
-               ad714x->sensor_val[second_after];
-
-       sw->pre_mean_value = sw->mean_value;
-       sw->mean_value = a_param / b_param;
-
-       /* Calculate the offset */
-
-       if ((sw->pre_highest_stage == hw->end_stage) &&
-                       (sw->highest_stage == hw->start_stage))
-               sw->pos_offset = sw->mean_value;
-       else if ((sw->pre_highest_stage == hw->start_stage) &&
-                       (sw->highest_stage == hw->end_stage))
-               sw->pos_offset = sw->pre_mean_value;
-
-       if (sw->pos_offset > OFFSET_POSITION_CLAMP)
-               sw->pos_offset = OFFSET_POSITION_CLAMP;
-
-       /* Calculate the mean value without the offset */
-
-       sw->pre_mean_value_no_offset = sw->mean_value_no_offset;
-       sw->mean_value_no_offset = sw->mean_value - sw->pos_offset;
-       if (sw->mean_value_no_offset < 0)
-               sw->mean_value_no_offset = 0;
-
-       /* Calculate ratio to scale down to NUMBER_OF_WANTED_POSITIONS */
-
-       if ((sw->pre_highest_stage == hw->end_stage) &&
-                       (sw->highest_stage == hw->start_stage))
-               sw->pos_ratio = (sw->pre_mean_value_no_offset * 100) /
-                       hw->max_coord;
-       else if ((sw->pre_highest_stage == hw->start_stage) &&
-                       (sw->highest_stage == hw->end_stage))
-               sw->pos_ratio = (sw->mean_value_no_offset * 100) /
-                       hw->max_coord;
-       sw->abs_pos = (sw->mean_value_no_offset * 100) / sw->pos_ratio;
+               ad714x->sensor_val[first_after];
+
+       sw->abs_pos = ((hw->max_coord / (hw->end_stage - hw->start_stage)) *
+                       a_param) / b_param;
+
        if (sw->abs_pos > hw->max_coord)
                sw->abs_pos = hw->max_coord;
+       else if (sw->abs_pos < 0)
+               sw->abs_pos = 0;
 }
 
 static void ad714x_wheel_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
@@ -639,9 +569,8 @@ static void ad714x_wheel_state_machine(struct ad714x_chip *ad714x, int idx)
                                ad714x_wheel_cal_highest_stage(ad714x, idx);
                                ad714x_wheel_cal_abs_pos(ad714x, idx);
                                ad714x_wheel_cal_flt_pos(ad714x, idx);
-
                                input_report_abs(sw->input, ABS_WHEEL,
-                                       sw->abs_pos);
+                                       sw->flt_pos);
                                input_report_key(sw->input, BTN_TOUCH, 1);
                        } else {
                                /* When the user lifts off the sensor, configure
@@ -1149,6 +1078,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
                        input[alloc_idx]->id.bustype = bus_type;
                        input[alloc_idx]->id.product = ad714x->product;
                        input[alloc_idx]->id.version = ad714x->version;
+                       input[alloc_idx]->name = "ad714x_captouch_slider";
+                       input[alloc_idx]->dev.parent = dev;
 
                        error = input_register_device(input[alloc_idx]);
                        if (error)
@@ -1179,6 +1110,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
                        input[alloc_idx]->id.bustype = bus_type;
                        input[alloc_idx]->id.product = ad714x->product;
                        input[alloc_idx]->id.version = ad714x->version;
+                       input[alloc_idx]->name = "ad714x_captouch_wheel";
+                       input[alloc_idx]->dev.parent = dev;
 
                        error = input_register_device(input[alloc_idx]);
                        if (error)
@@ -1212,6 +1145,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
                        input[alloc_idx]->id.bustype = bus_type;
                        input[alloc_idx]->id.product = ad714x->product;
                        input[alloc_idx]->id.version = ad714x->version;
+                       input[alloc_idx]->name = "ad714x_captouch_pad";
+                       input[alloc_idx]->dev.parent = dev;
 
                        error = input_register_device(input[alloc_idx]);
                        if (error)
@@ -1240,6 +1175,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
                input[alloc_idx]->id.bustype = bus_type;
                input[alloc_idx]->id.product = ad714x->product;
                input[alloc_idx]->id.version = ad714x->version;
+               input[alloc_idx]->name = "ad714x_captouch_button";
+               input[alloc_idx]->dev.parent = dev;
 
                error = input_register_device(input[alloc_idx]);
                if (error)
@@ -1249,7 +1186,9 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
        }
 
        error = request_threaded_irq(ad714x->irq, NULL, ad714x_interrupt_thread,
-                       IRQF_TRIGGER_FALLING, "ad714x_captouch", ad714x);
+                               plat_data->irqflags ?
+                                       plat_data->irqflags : IRQF_TRIGGER_FALLING,
+                               "ad714x_captouch", ad714x);
        if (error) {
                dev_err(dev, "can't allocate irq %d\n", ad714x->irq);
                goto err_unreg_dev;
index 9ccdb82d869a09245c80bf125a99c5fcac5cffd7..1de58e8a1b71216180808f7bd2c2e7d233f1cce7 100644 (file)
@@ -737,14 +737,17 @@ static ssize_t ati_remote2_store_channel_mask(struct device *dev,
 
        mutex_lock(&ati_remote2_mutex);
 
-       if (mask != ar2->channel_mask && !ati_remote2_setup(ar2, mask))
-               ar2->channel_mask = mask;
+       if (mask != ar2->channel_mask) {
+               r = ati_remote2_setup(ar2, mask);
+               if (!r)
+                       ar2->channel_mask = mask;
+       }
 
        mutex_unlock(&ati_remote2_mutex);
 
        usb_autopm_put_interface(ar2->intf[0]);
 
-       return count;
+       return r ? r : count;
 }
 
 static ssize_t ati_remote2_show_mode_mask(struct device *dev,
diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c
new file mode 100644 (file)
index 0000000..97e07e7
--- /dev/null
@@ -0,0 +1,231 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/log2.h>
+
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/input/pmic8xxx-pwrkey.h>
+
+#define PON_CNTL_1 0x1C
+#define PON_CNTL_PULL_UP BIT(7)
+#define PON_CNTL_TRIG_DELAY_MASK (0x7)
+
+/**
+ * struct pmic8xxx_pwrkey - pmic8xxx pwrkey information
+ * @key_press_irq: key press irq number
+ */
+struct pmic8xxx_pwrkey {
+       struct input_dev *pwr;
+       int key_press_irq;
+};
+
+static irqreturn_t pwrkey_press_irq(int irq, void *_pwrkey)
+{
+       struct pmic8xxx_pwrkey *pwrkey = _pwrkey;
+
+       input_report_key(pwrkey->pwr, KEY_POWER, 1);
+       input_sync(pwrkey->pwr);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t pwrkey_release_irq(int irq, void *_pwrkey)
+{
+       struct pmic8xxx_pwrkey *pwrkey = _pwrkey;
+
+       input_report_key(pwrkey->pwr, KEY_POWER, 0);
+       input_sync(pwrkey->pwr);
+
+       return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pmic8xxx_pwrkey_suspend(struct device *dev)
+{
+       struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(pwrkey->key_press_irq);
+
+       return 0;
+}
+
+static int pmic8xxx_pwrkey_resume(struct device *dev)
+{
+       struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(pwrkey->key_press_irq);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
+               pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume);
+
+static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
+{
+       struct input_dev *pwr;
+       int key_release_irq = platform_get_irq(pdev, 0);
+       int key_press_irq = platform_get_irq(pdev, 1);
+       int err;
+       unsigned int delay;
+       u8 pon_cntl;
+       struct pmic8xxx_pwrkey *pwrkey;
+       const struct pm8xxx_pwrkey_platform_data *pdata = mfd_get_data(pdev);
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "power key platform data not supplied\n");
+               return -EINVAL;
+       }
+
+       if (pdata->kpd_trigger_delay_us > 62500) {
+               dev_err(&pdev->dev, "invalid power key trigger delay\n");
+               return -EINVAL;
+       }
+
+       pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);
+       if (!pwrkey)
+               return -ENOMEM;
+
+       pwr = input_allocate_device();
+       if (!pwr) {
+               dev_dbg(&pdev->dev, "Can't allocate power button\n");
+               err = -ENOMEM;
+               goto free_pwrkey;
+       }
+
+       input_set_capability(pwr, EV_KEY, KEY_POWER);
+
+       pwr->name = "pmic8xxx_pwrkey";
+       pwr->phys = "pmic8xxx_pwrkey/input0";
+       pwr->dev.parent = &pdev->dev;
+
+       delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC;
+       delay = 1 + ilog2(delay);
+
+       err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
+               goto free_input_dev;
+       }
+
+       pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
+       pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
+       if (pdata->pull_up)
+               pon_cntl |= PON_CNTL_PULL_UP;
+       else
+               pon_cntl &= ~PON_CNTL_PULL_UP;
+
+       err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
+               goto free_input_dev;
+       }
+
+       err = input_register_device(pwr);
+       if (err) {
+               dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);
+               goto free_input_dev;
+       }
+
+       pwrkey->key_press_irq = key_press_irq;
+       pwrkey->pwr = pwr;
+
+       platform_set_drvdata(pdev, pwrkey);
+
+       err = request_irq(key_press_irq, pwrkey_press_irq,
+               IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_press", pwrkey);
+       if (err < 0) {
+               dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
+                                key_press_irq, err);
+               goto unreg_input_dev;
+       }
+
+       err = request_irq(key_release_irq, pwrkey_release_irq,
+                IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_release", pwrkey);
+       if (err < 0) {
+               dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
+                                key_release_irq, err);
+
+               goto free_press_irq;
+       }
+
+       device_init_wakeup(&pdev->dev, pdata->wakeup);
+
+       return 0;
+
+free_press_irq:
+       free_irq(key_press_irq, NULL);
+unreg_input_dev:
+       platform_set_drvdata(pdev, NULL);
+       input_unregister_device(pwr);
+       pwr = NULL;
+free_input_dev:
+       input_free_device(pwr);
+free_pwrkey:
+       kfree(pwrkey);
+       return err;
+}
+
+static int __devexit pmic8xxx_pwrkey_remove(struct platform_device *pdev)
+{
+       struct pmic8xxx_pwrkey *pwrkey = platform_get_drvdata(pdev);
+       int key_release_irq = platform_get_irq(pdev, 0);
+       int key_press_irq = platform_get_irq(pdev, 1);
+
+       device_init_wakeup(&pdev->dev, 0);
+
+       free_irq(key_press_irq, pwrkey);
+       free_irq(key_release_irq, pwrkey);
+       input_unregister_device(pwrkey->pwr);
+       platform_set_drvdata(pdev, NULL);
+       kfree(pwrkey);
+
+       return 0;
+}
+
+static struct platform_driver pmic8xxx_pwrkey_driver = {
+       .probe          = pmic8xxx_pwrkey_probe,
+       .remove         = __devexit_p(pmic8xxx_pwrkey_remove),
+       .driver         = {
+               .name   = PM8XXX_PWRKEY_DEV_NAME,
+               .owner  = THIS_MODULE,
+               .pm     = &pm8xxx_pwr_key_pm_ops,
+       },
+};
+
+static int __init pmic8xxx_pwrkey_init(void)
+{
+       return platform_driver_register(&pmic8xxx_pwrkey_driver);
+}
+module_init(pmic8xxx_pwrkey_init);
+
+static void __exit pmic8xxx_pwrkey_exit(void)
+{
+       platform_driver_unregister(&pmic8xxx_pwrkey_driver);
+}
+module_exit(pmic8xxx_pwrkey_exit);
+
+MODULE_ALIAS("platform:pmic8xxx_pwrkey");
+MODULE_DESCRIPTION("PMIC8XXX Power Key driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>");
index 7e64d01da2beb9238f78e567b210179e551b161b..2c8b84dd9dacca5bac905810fbf3cc452ad0541a 100644 (file)
@@ -2,6 +2,7 @@
  * rotary_encoder.c
  *
  * (c) 2009 Daniel Mack <daniel@caiaq.de>
+ * Copyright (C) 2011 Johan Hovold <jhovold@gmail.com>
  *
  * state machine code inspired by code from Tim Ruetz
  *
@@ -38,52 +39,66 @@ struct rotary_encoder {
 
        bool armed;
        unsigned char dir;      /* 0 - clockwise, 1 - CCW */
+
+       char last_stable;
 };
 
-static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
+static int rotary_encoder_get_state(struct rotary_encoder_platform_data *pdata)
 {
-       struct rotary_encoder *encoder = dev_id;
-       struct rotary_encoder_platform_data *pdata = encoder->pdata;
        int a = !!gpio_get_value(pdata->gpio_a);
        int b = !!gpio_get_value(pdata->gpio_b);
-       int state;
 
        a ^= pdata->inverted_a;
        b ^= pdata->inverted_b;
-       state = (a << 1) | b;
 
-       switch (state) {
+       return ((a << 1) | b);
+}
 
-       case 0x0:
-               if (!encoder->armed)
-                       break;
+static void rotary_encoder_report_event(struct rotary_encoder *encoder)
+{
+       struct rotary_encoder_platform_data *pdata = encoder->pdata;
 
-               if (pdata->relative_axis) {
-                       input_report_rel(encoder->input, pdata->axis,
-                                        encoder->dir ? -1 : 1);
-               } else {
-                       unsigned int pos = encoder->pos;
-
-                       if (encoder->dir) {
-                               /* turning counter-clockwise */
-                               if (pdata->rollover)
-                                       pos += pdata->steps;
-                               if (pos)
-                                       pos--;
-                       } else {
-                               /* turning clockwise */
-                               if (pdata->rollover || pos < pdata->steps)
-                                       pos++;
-                       }
+       if (pdata->relative_axis) {
+               input_report_rel(encoder->input,
+                                pdata->axis, encoder->dir ? -1 : 1);
+       } else {
+               unsigned int pos = encoder->pos;
+
+               if (encoder->dir) {
+                       /* turning counter-clockwise */
                        if (pdata->rollover)
-                               pos %= pdata->steps;
-                       encoder->pos = pos;
-                       input_report_abs(encoder->input, pdata->axis,
-                                        encoder->pos);
+                               pos += pdata->steps;
+                       if (pos)
+                               pos--;
+               } else {
+                       /* turning clockwise */
+                       if (pdata->rollover || pos < pdata->steps)
+                               pos++;
                }
-               input_sync(encoder->input);
 
-               encoder->armed = false;
+               if (pdata->rollover)
+                       pos %= pdata->steps;
+
+               encoder->pos = pos;
+               input_report_abs(encoder->input, pdata->axis, encoder->pos);
+       }
+
+       input_sync(encoder->input);
+}
+
+static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
+{
+       struct rotary_encoder *encoder = dev_id;
+       int state;
+
+       state = rotary_encoder_get_state(encoder->pdata);
+
+       switch (state) {
+       case 0x0:
+               if (encoder->armed) {
+                       rotary_encoder_report_event(encoder);
+                       encoder->armed = false;
+               }
                break;
 
        case 0x1:
@@ -100,11 +115,37 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
+{
+       struct rotary_encoder *encoder = dev_id;
+       int state;
+
+       state = rotary_encoder_get_state(encoder->pdata);
+
+       switch (state) {
+       case 0x00:
+       case 0x03:
+               if (state != encoder->last_stable) {
+                       rotary_encoder_report_event(encoder);
+                       encoder->last_stable = state;
+               }
+               break;
+
+       case 0x01:
+       case 0x02:
+               encoder->dir = (encoder->last_stable + state) & 0x01;
+               break;
+       }
+
+       return IRQ_HANDLED;
+}
+
 static int __devinit rotary_encoder_probe(struct platform_device *pdev)
 {
        struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data;
        struct rotary_encoder *encoder;
        struct input_dev *input;
+       irq_handler_t handler;
        int err;
 
        if (!pdata) {
@@ -175,7 +216,14 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
        }
 
        /* request the IRQs */
-       err = request_irq(encoder->irq_a, &rotary_encoder_irq,
+       if (pdata->half_period) {
+               handler = &rotary_encoder_half_period_irq;
+               encoder->last_stable = rotary_encoder_get_state(pdata);
+       } else {
+               handler = &rotary_encoder_irq;
+       }
+
+       err = request_irq(encoder->irq_a, handler,
                          IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
                          DRV_NAME, encoder);
        if (err) {
@@ -184,7 +232,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
                goto exit_free_gpio_b;
        }
 
-       err = request_irq(encoder->irq_b, &rotary_encoder_irq,
+       err = request_irq(encoder->irq_b, handler,
                          IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
                          DRV_NAME, encoder);
        if (err) {
@@ -252,6 +300,5 @@ module_exit(rotary_encoder_exit);
 
 MODULE_ALIAS("platform:" DRV_NAME);
 MODULE_DESCRIPTION("GPIO rotary encoder driver");
-MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
+MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>, Johan Hovold");
 MODULE_LICENSE("GPL v2");
-
index f16972bddca473b54f8388fe6ba2709b0b65dd77..38e4b507b94cc629ef330cf173b1b41d3765e904 100644 (file)
@@ -89,7 +89,7 @@ static int __init twl4030_pwrbutton_probe(struct platform_device *pdev)
        return 0;
 
 free_irq:
-       free_irq(irq, NULL);
+       free_irq(irq, pwr);
 free_input_dev:
        input_free_device(pwr);
        return err;
index 6a11694e3fc7bb1274f59105e35f9d0b7c7d33c9..014dd4ad0d4fecede04221e5348fc78e023d76e2 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/workqueue.h>
 #include <linux/i2c/twl.h>
 #include <linux/mfd/twl4030-codec.h>
-#include <linux/mfd/core.h>
 #include <linux/input.h>
 #include <linux/slab.h>
 
@@ -197,7 +196,7 @@ static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
 
 static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
 {
-       struct twl4030_codec_vibra_data *pdata = mfd_get_data(pdev);
+       struct twl4030_codec_vibra_data *pdata = pdev->dev.platform_data;
        struct vibra_info *info;
        int ret;
 
index 04d9bf320a4f9c090b8d4f46aeca8e848bc4f988..32503565faf90faf229c4560d7fdfcda3f8c8561 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/input.h>
+#include <linux/input/mt.h>
 #include <linux/serio.h>
 #include <linux/libps2.h>
 #include "psmouse.h"
@@ -242,15 +243,37 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
        input_sync(dev);
 }
 
+static void elantech_set_slot(struct input_dev *dev, int slot, bool active,
+                             unsigned int x, unsigned int y)
+{
+       input_mt_slot(dev, slot);
+       input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
+       if (active) {
+               input_report_abs(dev, ABS_MT_POSITION_X, x);
+               input_report_abs(dev, ABS_MT_POSITION_Y, y);
+       }
+}
+
+/* x1 < x2 and y1 < y2 when two fingers, x = y = 0 when not pressed */
+static void elantech_report_semi_mt_data(struct input_dev *dev,
+                                        unsigned int num_fingers,
+                                        unsigned int x1, unsigned int y1,
+                                        unsigned int x2, unsigned int y2)
+{
+       elantech_set_slot(dev, 0, num_fingers != 0, x1, y1);
+       elantech_set_slot(dev, 1, num_fingers == 2, x2, y2);
+}
+
 /*
  * Interpret complete data packets and report absolute mode input events for
  * hardware version 2. (6 byte packets)
  */
 static void elantech_report_absolute_v2(struct psmouse *psmouse)
 {
+       struct elantech_data *etd = psmouse->private;
        struct input_dev *dev = psmouse->dev;
        unsigned char *packet = psmouse->packet;
-       int fingers, x1, y1, x2, y2;
+       unsigned int fingers, x1 = 0, y1 = 0, x2 = 0, y2 = 0, width = 0, pres = 0;
 
        /* byte 0: n1  n0   .   .   .   .   R   L */
        fingers = (packet[0] & 0xc0) >> 6;
@@ -270,14 +293,18 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
                 * byte 1:  .   .   .   .   .  x10 x9  x8
                 * byte 2: x7  x6  x5  x4  x4  x2  x1  x0
                 */
-               input_report_abs(dev, ABS_X,
-                       ((packet[1] & 0x07) << 8) | packet[2]);
+               x1 = ((packet[1] & 0x07) << 8) | packet[2];
                /*
                 * byte 4:  .   .   .   .   .   .  y9  y8
                 * byte 5: y7  y6  y5  y4  y3  y2  y1  y0
                 */
-               input_report_abs(dev, ABS_Y,
-                       ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5]));
+               y1 = ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5]);
+
+               input_report_abs(dev, ABS_X, x1);
+               input_report_abs(dev, ABS_Y, y1);
+
+               pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4);
+               width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4);
                break;
 
        case 2:
@@ -303,23 +330,24 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
                 */
                input_report_abs(dev, ABS_X, x1 << 2);
                input_report_abs(dev, ABS_Y, y1 << 2);
-               /*
-                * For compatibility with the proprietary X Elantech driver
-                * report both coordinates as hat coordinates
-                */
-               input_report_abs(dev, ABS_HAT0X, x1);
-               input_report_abs(dev, ABS_HAT0Y, y1);
-               input_report_abs(dev, ABS_HAT1X, x2);
-               input_report_abs(dev, ABS_HAT1Y, y2);
+
+               /* Unknown so just report sensible values */
+               pres = 127;
+               width = 7;
                break;
        }
 
+       elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
        input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
        input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
        input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
        input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4);
        input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
        input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+       if (etd->reports_pressure) {
+               input_report_abs(dev, ABS_PRESSURE, pres);
+               input_report_abs(dev, ABS_TOOL_WIDTH, width);
+       }
 
        input_sync(dev);
 }
@@ -478,10 +506,16 @@ static void elantech_set_input_params(struct psmouse *psmouse)
                __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
                input_set_abs_params(dev, ABS_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0);
                input_set_abs_params(dev, ABS_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0);
-               input_set_abs_params(dev, ABS_HAT0X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0);
-               input_set_abs_params(dev, ABS_HAT0Y, ETP_2FT_YMIN, ETP_2FT_YMAX, 0, 0);
-               input_set_abs_params(dev, ABS_HAT1X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0);
-               input_set_abs_params(dev, ABS_HAT1Y, ETP_2FT_YMIN, ETP_2FT_YMAX, 0, 0);
+               if (etd->reports_pressure) {
+                       input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
+                                            ETP_PMAX_V2, 0, 0);
+                       input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
+                                            ETP_WMAX_V2, 0, 0);
+               }
+               __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
+               input_mt_init_slots(dev, 2);
+               input_set_abs_params(dev, ABS_MT_POSITION_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0);
+               input_set_abs_params(dev, ABS_MT_POSITION_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0);
                break;
        }
 }
@@ -725,6 +759,10 @@ int elantech_init(struct psmouse *psmouse)
                etd->debug = 1;
                /* Don't know how to do parity checking for version 2 */
                etd->paritycheck = 0;
+
+               if (etd->fw_version >= 0x020800)
+                       etd->reports_pressure = true;
+
        } else {
                etd->hw_version = 1;
                etd->paritycheck = 1;
index aa4aac5d21983988e8e8de6c3d150d579dba0ae0..fabb2b99615cda63347e8d0bee9f9f15f70cc3ae 100644 (file)
 #define ETP_YMIN_V2                    (   0 + ETP_EDGE_FUZZ_V2)
 #define ETP_YMAX_V2                    ( 768 - ETP_EDGE_FUZZ_V2)
 
+#define ETP_PMIN_V2                    0
+#define ETP_PMAX_V2                    255
+#define ETP_WMIN_V2                    0
+#define ETP_WMAX_V2                    15
+
 /*
  * For two finger touches the coordinate of each finger gets reported
  * separately but with reduced resolution.
@@ -102,6 +107,7 @@ struct elantech_data {
        unsigned char capabilities;
        bool paritycheck;
        bool jumpy_cursor;
+       bool reports_pressure;
        unsigned char hw_version;
        unsigned int fw_version;
        unsigned int single_finger_reports;
index 7630273e9474051c3ba4886012e61f1088b43a81..0110b5a3a1678a7a0843672b8505e6f42c664fc1 100644 (file)
@@ -187,7 +187,7 @@ static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev,
                if (size == 0)
                        size = xres ? : 1;
 
-               clamp(value, min, max);
+               value = clamp(value, min, max);
 
                mousedev->packet.x = ((value - min) * xres) / size;
                mousedev->packet.abs_event = 1;
@@ -201,7 +201,7 @@ static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev,
                if (size == 0)
                        size = yres ? : 1;
 
-               clamp(value, min, max);
+               value = clamp(value, min, max);
 
                mousedev->packet.y = yres - ((value - min) * yres) / size;
                mousedev->packet.abs_event = 1;
@@ -508,7 +508,6 @@ static void mousedev_attach_client(struct mousedev *mousedev,
        spin_lock(&mousedev->client_lock);
        list_add_tail_rcu(&client->node, &mousedev->client_list);
        spin_unlock(&mousedev->client_lock);
-       synchronize_rcu();
 }
 
 static void mousedev_detach_client(struct mousedev *mousedev,
index f3698967edf6bdd0e8b7f4b19abdb19e335a2c3d..8755f5f3ad37c2218de60b96782c0863615a705e 100644 (file)
@@ -120,21 +120,17 @@ static void serport_ldisc_close(struct tty_struct *tty)
  * 'interrupt' routine.
  */
 
-static unsigned int serport_ldisc_receive(struct tty_struct *tty,
-               const unsigned char *cp, char *fp, int count)
+static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
 {
        struct serport *serport = (struct serport*) tty->disc_data;
        unsigned long flags;
        unsigned int ch_flags;
-       int ret = 0;
        int i;
 
        spin_lock_irqsave(&serport->lock, flags);
 
-       if (!test_bit(SERPORT_ACTIVE, &serport->flags)) {
-               ret = -EINVAL;
+       if (!test_bit(SERPORT_ACTIVE, &serport->flags))
                goto out;
-       }
 
        for (i = 0; i < count; i++) {
                switch (fp[i]) {
@@ -156,8 +152,6 @@ static unsigned int serport_ldisc_receive(struct tty_struct *tty,
 
 out:
        spin_unlock_irqrestore(&serport->lock, flags);
-
-       return ret == 0 ? count : ret;
 }
 
 /*
index 434fd800cd24e7eb54adf896b8ec20e7f17e4dc5..cabd9e54863f9643664eb1e71c5cd5217d3fe528 100644 (file)
@@ -248,6 +248,18 @@ config TOUCHSCREEN_LPC32XX
          To compile this driver as a module, choose M here: the
          module will be called lpc32xx_ts.
 
+config TOUCHSCREEN_MAX11801
+       tristate "MAX11801 based touchscreens"
+       depends on I2C
+       help
+         Say Y here if you have a MAX11801 based touchscreen
+         controller.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called max11801_ts.
+
 config TOUCHSCREEN_MCS5000
        tristate "MELFAS MCS-5000 touchscreen"
        depends on I2C
index ca94098d4c92b8116815c17a9ac742e77aa622e3..282d6f76ae26d10576332903ea633b8b03a17d05 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_TOUCHSCREEN_FUJITSU)     += fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_INEXIO)       += inexio.o
 obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)    += intel-mid-touch.o
 obj-$(CONFIG_TOUCHSCREEN_LPC32XX)      += lpc32xx_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MAX11801)     += max11801_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MC13783)      += mc13783_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MCS5000)      += mcs5000_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MIGOR)                += migor_ts.o
index 1de1c19dad30f2e0ef089f0901e8d6d0b2584b43..5196861b86ef2d8c2d4d559b5471caa4e1e464b4 100644 (file)
@@ -109,6 +109,7 @@ struct ads7846 {
        u16                     pressure_max;
 
        bool                    swap_xy;
+       bool                    use_internal;
 
        struct ads7846_packet   *packet;
 
@@ -307,7 +308,6 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
        struct ads7846 *ts = dev_get_drvdata(dev);
        struct ser_req *req;
        int status;
-       int use_internal;
 
        req = kzalloc(sizeof *req, GFP_KERNEL);
        if (!req)
@@ -315,11 +315,8 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
 
        spi_message_init(&req->msg);
 
-       /* FIXME boards with ads7846 might use external vref instead ... */
-       use_internal = (ts->model == 7846);
-
        /* maybe turn on internal vREF, and let it settle */
-       if (use_internal) {
+       if (ts->use_internal) {
                req->ref_on = REF_ON;
                req->xfer[0].tx_buf = &req->ref_on;
                req->xfer[0].len = 1;
@@ -331,8 +328,14 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
                /* for 1uF, settle for 800 usec; no cap, 100 usec.  */
                req->xfer[1].delay_usecs = ts->vref_delay_usecs;
                spi_message_add_tail(&req->xfer[1], &req->msg);
+
+               /* Enable reference voltage */
+               command |= ADS_PD10_REF_ON;
        }
 
+       /* Enable ADC in every case */
+       command |= ADS_PD10_ADC_ON;
+
        /* take sample */
        req->command = (u8) command;
        req->xfer[2].tx_buf = &req->command;
@@ -416,7 +419,7 @@ name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
 { \
        struct ads7846 *ts = dev_get_drvdata(dev); \
        ssize_t v = ads7846_read12_ser(dev, \
-                       READ_12BIT_SER(var) | ADS_PD10_ALL_ON); \
+                       READ_12BIT_SER(var)); \
        if (v < 0) \
                return v; \
        return sprintf(buf, "%u\n", adjust(ts, v)); \
@@ -509,6 +512,7 @@ static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
                if (!ts->vref_mv) {
                        dev_dbg(&spi->dev, "assuming 2.5V internal vREF\n");
                        ts->vref_mv = 2500;
+                       ts->use_internal = true;
                }
                break;
        case 7845:
@@ -969,6 +973,13 @@ static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads784
                                pdata->gpio_pendown);
                        return err;
                }
+               err = gpio_direction_input(pdata->gpio_pendown);
+               if (err) {
+                       dev_err(&spi->dev, "failed to setup pendown GPIO%d\n",
+                               pdata->gpio_pendown);
+                       gpio_free(pdata->gpio_pendown);
+                       return err;
+               }
 
                ts->gpio_pendown = pdata->gpio_pendown;
 
@@ -1340,8 +1351,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        if (ts->model == 7845)
                ads7845_read12_ser(&spi->dev, PWRDOWN);
        else
-               (void) ads7846_read12_ser(&spi->dev,
-                               READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
+               (void) ads7846_read12_ser(&spi->dev, READ_12BIT_SER(vaux));
 
        err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
        if (err)
index 4012436633b18ef0d087b95ca4f6792c6c8e290b..1e61387c73cafa01f40825a710427414a4a7e2aa 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/firmware.h>
 #include <linux/i2c.h>
 #include <linux/i2c/atmel_mxt_ts.h>
-#include <linux/input.h>
+#include <linux/input/mt.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 
 #define MXT_PRESS              (1 << 6)
 #define MXT_DETECT             (1 << 7)
 
+/* Touch orient bits */
+#define MXT_XY_SWITCH          (1 << 0)
+#define MXT_X_INVERT           (1 << 1)
+#define MXT_Y_INVERT           (1 << 2)
+
 /* Touchscreen absolute values */
-#define MXT_MAX_XC             0x3ff
-#define MXT_MAX_YC             0x3ff
 #define MXT_MAX_AREA           0xff
 
 #define MXT_MAX_FINGER         10
@@ -246,6 +249,8 @@ struct mxt_data {
        struct mxt_info info;
        struct mxt_finger finger[MXT_MAX_FINGER];
        unsigned int irq;
+       unsigned int max_x;
+       unsigned int max_y;
 };
 
 static bool mxt_object_readable(unsigned int type)
@@ -499,19 +504,21 @@ static void mxt_input_report(struct mxt_data *data, int single_id)
                if (!finger[id].status)
                        continue;
 
-               input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
-                               finger[id].status != MXT_RELEASE ?
-                               finger[id].area : 0);
-               input_report_abs(input_dev, ABS_MT_POSITION_X,
-                               finger[id].x);
-               input_report_abs(input_dev, ABS_MT_POSITION_Y,
-                               finger[id].y);
-               input_mt_sync(input_dev);
+               input_mt_slot(input_dev, id);
+               input_mt_report_slot_state(input_dev, MT_TOOL_FINGER,
+                               finger[id].status != MXT_RELEASE);
 
-               if (finger[id].status == MXT_RELEASE)
-                       finger[id].status = 0;
-               else
+               if (finger[id].status != MXT_RELEASE) {
                        finger_num++;
+                       input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
+                                       finger[id].area);
+                       input_report_abs(input_dev, ABS_MT_POSITION_X,
+                                       finger[id].x);
+                       input_report_abs(input_dev, ABS_MT_POSITION_Y,
+                                       finger[id].y);
+               } else {
+                       finger[id].status = 0;
+               }
        }
 
        input_report_key(input_dev, BTN_TOUCH, finger_num > 0);
@@ -549,8 +556,13 @@ static void mxt_input_touchevent(struct mxt_data *data,
        if (!(status & (MXT_PRESS | MXT_MOVE)))
                return;
 
-       x = (message->message[1] << 2) | ((message->message[3] & ~0x3f) >> 6);
-       y = (message->message[2] << 2) | ((message->message[3] & ~0xf3) >> 2);
+       x = (message->message[1] << 4) | ((message->message[3] >> 4) & 0xf);
+       y = (message->message[2] << 4) | ((message->message[3] & 0xf));
+       if (data->max_x < 1024)
+               x = x >> 2;
+       if (data->max_y < 1024)
+               y = y >> 2;
+
        area = message->message[4];
 
        dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
@@ -804,10 +816,6 @@ static int mxt_initialize(struct mxt_data *data)
        if (error)
                return error;
 
-       error = mxt_make_highchg(data);
-       if (error)
-               return error;
-
        mxt_handle_pdata(data);
 
        /* Backup to memory */
@@ -845,6 +853,20 @@ static int mxt_initialize(struct mxt_data *data)
        return 0;
 }
 
+static void mxt_calc_resolution(struct mxt_data *data)
+{
+       unsigned int max_x = data->pdata->x_size - 1;
+       unsigned int max_y = data->pdata->y_size - 1;
+
+       if (data->pdata->orient & MXT_XY_SWITCH) {
+               data->max_x = max_y;
+               data->max_y = max_x;
+       } else {
+               data->max_x = max_x;
+               data->max_y = max_y;
+       }
+}
+
 static ssize_t mxt_object_show(struct device *dev,
                                    struct device_attribute *attr, char *buf)
 {
@@ -981,6 +1003,10 @@ static ssize_t mxt_update_fw_store(struct device *dev,
 
        enable_irq(data->irq);
 
+       error = mxt_make_highchg(data);
+       if (error)
+               return error;
+
        return count;
 }
 
@@ -1052,31 +1078,33 @@ static int __devinit mxt_probe(struct i2c_client *client,
        input_dev->open = mxt_input_open;
        input_dev->close = mxt_input_close;
 
+       data->client = client;
+       data->input_dev = input_dev;
+       data->pdata = pdata;
+       data->irq = client->irq;
+
+       mxt_calc_resolution(data);
+
        __set_bit(EV_ABS, input_dev->evbit);
        __set_bit(EV_KEY, input_dev->evbit);
        __set_bit(BTN_TOUCH, input_dev->keybit);
 
        /* For single touch */
        input_set_abs_params(input_dev, ABS_X,
-                            0, MXT_MAX_XC, 0, 0);
+                            0, data->max_x, 0, 0);
        input_set_abs_params(input_dev, ABS_Y,
-                            0, MXT_MAX_YC, 0, 0);
+                            0, data->max_y, 0, 0);
 
        /* For multi touch */
+       input_mt_init_slots(input_dev, MXT_MAX_FINGER);
        input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
                             0, MXT_MAX_AREA, 0, 0);
        input_set_abs_params(input_dev, ABS_MT_POSITION_X,
-                            0, MXT_MAX_XC, 0, 0);
+                            0, data->max_x, 0, 0);
        input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
-                            0, MXT_MAX_YC, 0, 0);
+                            0, data->max_y, 0, 0);
 
        input_set_drvdata(input_dev, data);
-
-       data->client = client;
-       data->input_dev = input_dev;
-       data->pdata = pdata;
-       data->irq = client->irq;
-
        i2c_set_clientdata(client, data);
 
        error = mxt_initialize(data);
@@ -1090,6 +1118,10 @@ static int __devinit mxt_probe(struct i2c_client *client,
                goto err_free_object;
        }
 
+       error = mxt_make_highchg(data);
+       if (error)
+               goto err_free_irq;
+
        error = input_register_device(input_dev);
        if (error)
                goto err_free_irq;
index 3d9b5166ebe95d79712b9382d4f22ef666386e7c..432c69be6ac61561a383b026eac149588daca99f 100644 (file)
@@ -317,7 +317,7 @@ err_unmap_regs:
 err_release_mem:
        release_mem_region(res->start, resource_size(res));
 err_free_dev:
-       input_free_device(ts_dev->input);
+       input_free_device(input_dev);
 err_free_mem:
        kfree(ts_dev);
        return err;
index 45f93d0f5592e2c3adcdcfdad32ce83696312647..211811ae552538b529b32ce470991b266454a9c7 100644 (file)
@@ -396,14 +396,14 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
        set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
 
        if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
-                       IRQF_SHARED | IRQF_DISABLED, "h3600_action", &ts->dev)) {
+                       IRQF_SHARED | IRQF_DISABLED, "h3600_action", ts->dev)) {
                printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
                err = -EBUSY;
                goto fail1;
        }
 
        if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
-                       IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", &ts->dev)) {
+                       IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", ts->dev)) {
                printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
                err = -EBUSY;
                goto fail2;
@@ -439,8 +439,8 @@ static void h3600ts_disconnect(struct serio *serio)
 {
        struct h3600_dev *ts = serio_get_drvdata(serio);
 
-       free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
-       free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, &ts->dev);
+       free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts->dev);
+       free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev);
        input_get_device(ts->dev);
        input_unregister_device(ts->dev);
        serio_close(serio);
diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c
new file mode 100644 (file)
index 0000000..4f2713d
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Driver for MAXI MAX11801 - A Resistive touch screen controller with
+ * i2c interface
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Author: Zhang Jiejing <jiejing.zhang@freescale.com>
+ *
+ * Based on mcs5000_ts.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ */
+
+/*
+ * This driver aims to support the series of MAXI touch chips max11801
+ * through max11803. The main difference between these 4 chips can be
+ * found in the table below:
+ * -----------------------------------------------------
+ * | CHIP     |  AUTO MODE SUPPORT(FIFO) | INTERFACE    |
+ * |----------------------------------------------------|
+ * | max11800 |  YES                     |   SPI        |
+ * | max11801 |  YES                     |   I2C        |
+ * | max11802 |  NO                      |   SPI        |
+ * | max11803 |  NO                      |   I2C        |
+ * ------------------------------------------------------
+ *
+ * Currently, this driver only supports max11801.
+ *
+ * Data Sheet:
+ * http://www.maxim-ic.com/datasheet/index.mvp/id/5943
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+
+/* Register Address define */
+#define GENERNAL_STATUS_REG            0x00
+#define GENERNAL_CONF_REG              0x01
+#define MESURE_RES_CONF_REG            0x02
+#define MESURE_AVER_CONF_REG           0x03
+#define ADC_SAMPLE_TIME_CONF_REG       0x04
+#define PANEL_SETUPTIME_CONF_REG       0x05
+#define DELAY_CONVERSION_CONF_REG      0x06
+#define TOUCH_DETECT_PULLUP_CONF_REG   0x07
+#define AUTO_MODE_TIME_CONF_REG                0x08 /* only for max11800/max11801 */
+#define APERTURE_CONF_REG              0x09 /* only for max11800/max11801 */
+#define AUX_MESURE_CONF_REG            0x0a
+#define OP_MODE_CONF_REG               0x0b
+
+/* FIFO is found only in max11800 and max11801 */
+#define FIFO_RD_CMD                    (0x50 << 1)
+#define MAX11801_FIFO_INT              (1 << 2)
+#define MAX11801_FIFO_OVERFLOW         (1 << 3)
+
+#define XY_BUFSIZE                     4
+#define XY_BUF_OFFSET                  4
+
+#define MAX11801_MAX_X                 0xfff
+#define MAX11801_MAX_Y                 0xfff
+
+#define MEASURE_TAG_OFFSET             2
+#define MEASURE_TAG_MASK               (3 << MEASURE_TAG_OFFSET)
+#define EVENT_TAG_OFFSET               0
+#define EVENT_TAG_MASK                 (3 << EVENT_TAG_OFFSET)
+#define MEASURE_X_TAG                  (0 << MEASURE_TAG_OFFSET)
+#define MEASURE_Y_TAG                  (1 << MEASURE_TAG_OFFSET)
+
+/* These are the state of touch event state machine */
+enum {
+       EVENT_INIT,
+       EVENT_MIDDLE,
+       EVENT_RELEASE,
+       EVENT_FIFO_END
+};
+
+struct max11801_data {
+       struct i2c_client               *client;
+       struct input_dev                *input_dev;
+};
+
+static u8 read_register(struct i2c_client *client, int addr)
+{
+       /* XXX: The chip ignores LSB of register address */
+       return i2c_smbus_read_byte_data(client, addr << 1);
+}
+
+static int max11801_write_reg(struct i2c_client *client, int addr, int data)
+{
+       /* XXX: The chip ignores LSB of register address */
+       return i2c_smbus_write_byte_data(client, addr << 1, data);
+}
+
+static irqreturn_t max11801_ts_interrupt(int irq, void *dev_id)
+{
+       struct max11801_data *data = dev_id;
+       struct i2c_client *client = data->client;
+       int status, i, ret;
+       u8 buf[XY_BUFSIZE];
+       int x = -1;
+       int y = -1;
+
+       status = read_register(data->client, GENERNAL_STATUS_REG);
+
+       if (status & (MAX11801_FIFO_INT | MAX11801_FIFO_OVERFLOW)) {
+               status = read_register(data->client, GENERNAL_STATUS_REG);
+
+               ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_CMD,
+                                                   XY_BUFSIZE, buf);
+
+               /*
+                * We should get 4 bytes buffer that contains X,Y
+                * and event tag
+                */
+               if (ret < XY_BUFSIZE)
+                       goto out;
+
+               for (i = 0; i < XY_BUFSIZE; i += XY_BUFSIZE / 2) {
+                       if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_X_TAG)
+                               x = (buf[i] << XY_BUF_OFFSET) +
+                                   (buf[i + 1] >> XY_BUF_OFFSET);
+                       else if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_Y_TAG)
+                               y = (buf[i] << XY_BUF_OFFSET) +
+                                   (buf[i + 1] >> XY_BUF_OFFSET);
+               }
+
+               if ((buf[1] & EVENT_TAG_MASK) != (buf[3] & EVENT_TAG_MASK))
+                       goto out;
+
+               switch (buf[1] & EVENT_TAG_MASK) {
+               case EVENT_INIT:
+                       /* fall through */
+               case EVENT_MIDDLE:
+                       input_report_abs(data->input_dev, ABS_X, x);
+                       input_report_abs(data->input_dev, ABS_Y, y);
+                       input_event(data->input_dev, EV_KEY, BTN_TOUCH, 1);
+                       input_sync(data->input_dev);
+                       break;
+
+               case EVENT_RELEASE:
+                       input_event(data->input_dev, EV_KEY, BTN_TOUCH, 0);
+                       input_sync(data->input_dev);
+                       break;
+
+               case EVENT_FIFO_END:
+                       break;
+               }
+       }
+out:
+       return IRQ_HANDLED;
+}
+
+static void __devinit max11801_ts_phy_init(struct max11801_data *data)
+{
+       struct i2c_client *client = data->client;
+
+       /* Average X,Y, take 16 samples, average eight media sample */
+       max11801_write_reg(client, MESURE_AVER_CONF_REG, 0xff);
+       /* X,Y panel setup time set to 20us */
+       max11801_write_reg(client, PANEL_SETUPTIME_CONF_REG, 0x11);
+       /* Rough pullup time (2uS), Fine pullup time (10us)  */
+       max11801_write_reg(client, TOUCH_DETECT_PULLUP_CONF_REG, 0x10);
+       /* Auto mode init period = 5ms , scan period = 5ms*/
+       max11801_write_reg(client, AUTO_MODE_TIME_CONF_REG, 0xaa);
+       /* Aperture X,Y set to +- 4LSB */
+       max11801_write_reg(client, APERTURE_CONF_REG, 0x33);
+       /* Enable Power, enable Automode, enable Aperture, enable Average X,Y */
+       max11801_write_reg(client, OP_MODE_CONF_REG, 0x36);
+}
+
+static int __devinit max11801_ts_probe(struct i2c_client *client,
+                                      const struct i2c_device_id *id)
+{
+       struct max11801_data *data;
+       struct input_dev *input_dev;
+       int error;
+
+       data = kzalloc(sizeof(struct max11801_data), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!data || !input_dev) {
+               dev_err(&client->dev, "Failed to allocate memory\n");
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       data->client = client;
+       data->input_dev = input_dev;
+
+       input_dev->name = "max11801_ts";
+       input_dev->id.bustype = BUS_I2C;
+       input_dev->dev.parent = &client->dev;
+
+       __set_bit(EV_ABS, input_dev->evbit);
+       __set_bit(EV_KEY, input_dev->evbit);
+       __set_bit(BTN_TOUCH, input_dev->keybit);
+       input_set_abs_params(input_dev, ABS_X, 0, MAX11801_MAX_X, 0, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, MAX11801_MAX_Y, 0, 0);
+       input_set_drvdata(input_dev, data);
+
+       max11801_ts_phy_init(data);
+
+       error = request_threaded_irq(client->irq, NULL, max11801_ts_interrupt,
+                                    IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                    "max11801_ts", data);
+       if (error) {
+               dev_err(&client->dev, "Failed to register interrupt\n");
+               goto err_free_mem;
+       }
+
+       error = input_register_device(data->input_dev);
+       if (error)
+               goto err_free_irq;
+
+       i2c_set_clientdata(client, data);
+       return 0;
+
+err_free_irq:
+       free_irq(client->irq, data);
+err_free_mem:
+       input_free_device(input_dev);
+       kfree(data);
+       return error;
+}
+
+static __devexit int max11801_ts_remove(struct i2c_client *client)
+{
+       struct max11801_data *data = i2c_get_clientdata(client);
+
+       free_irq(client->irq, data);
+       input_unregister_device(data->input_dev);
+       kfree(data);
+
+       return 0;
+}
+
+static const struct i2c_device_id max11801_ts_id[] = {
+       {"max11801", 0},
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max11801_ts_id);
+
+static struct i2c_driver max11801_ts_driver = {
+       .driver = {
+               .name   = "max11801_ts",
+               .owner  = THIS_MODULE,
+       },
+       .id_table       = max11801_ts_id,
+       .probe          = max11801_ts_probe,
+       .remove         = __devexit_p(max11801_ts_remove),
+};
+
+static int __init max11801_ts_init(void)
+{
+       return i2c_add_driver(&max11801_ts_driver);
+}
+
+static void __exit max11801_ts_exit(void)
+{
+       i2c_del_driver(&max11801_ts_driver);
+}
+
+module_init(max11801_ts_init);
+module_exit(max11801_ts_exit);
+
+MODULE_AUTHOR("Zhang Jiejing <jiejing.zhang@freescale.com>");
+MODULE_DESCRIPTION("Touchscreen driver for MAXI MAX11801 controller");
+MODULE_LICENSE("GPL");
index 80467f262331e2c94ae9686f21e473b4d203f3f5..fadc11545b1eed03124b1c6cd152db8c737345de 100644 (file)
@@ -27,9 +27,6 @@
 #include <linux/i2c.h>
 #include <linux/i2c/tsc2007.h>
 
-#define TS_POLL_DELAY                  1 /* ms delay between samples */
-#define TS_POLL_PERIOD                 1 /* ms delay between samples */
-
 #define TSC2007_MEASURE_TEMP0          (0x0 << 4)
 #define TSC2007_MEASURE_AUX            (0x2 << 4)
 #define TSC2007_MEASURE_TEMP1          (0x4 << 4)
@@ -75,6 +72,9 @@ struct tsc2007 {
 
        u16                     model;
        u16                     x_plate_ohms;
+       u16                     max_rt;
+       unsigned long           poll_delay;
+       unsigned long           poll_period;
 
        bool                    pendown;
        int                     irq;
@@ -156,6 +156,7 @@ static void tsc2007_work(struct work_struct *work)
 {
        struct tsc2007 *ts =
                container_of(to_delayed_work(work), struct tsc2007, work);
+       bool debounced = false;
        struct ts_event tc;
        u32 rt;
 
@@ -184,13 +185,14 @@ static void tsc2007_work(struct work_struct *work)
        tsc2007_read_values(ts, &tc);
 
        rt = tsc2007_calculate_pressure(ts, &tc);
-       if (rt > MAX_12BIT) {
+       if (rt > ts->max_rt) {
                /*
                 * Sample found inconsistent by debouncing or pressure is
                 * beyond the maximum. Don't report it to user space,
                 * repeat at least once more the measurement.
                 */
                dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
+               debounced = true;
                goto out;
 
        }
@@ -225,9 +227,9 @@ static void tsc2007_work(struct work_struct *work)
        }
 
  out:
-       if (ts->pendown)
+       if (ts->pendown || debounced)
                schedule_delayed_work(&ts->work,
-                                     msecs_to_jiffies(TS_POLL_PERIOD));
+                                     msecs_to_jiffies(ts->poll_period));
        else
                enable_irq(ts->irq);
 }
@@ -239,7 +241,7 @@ static irqreturn_t tsc2007_irq(int irq, void *handle)
        if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {
                disable_irq_nosync(ts->irq);
                schedule_delayed_work(&ts->work,
-                                     msecs_to_jiffies(TS_POLL_DELAY));
+                                     msecs_to_jiffies(ts->poll_delay));
        }
 
        if (ts->clear_penirq)
@@ -292,6 +294,9 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
 
        ts->model             = pdata->model;
        ts->x_plate_ohms      = pdata->x_plate_ohms;
+       ts->max_rt            = pdata->max_rt ? : MAX_12BIT;
+       ts->poll_delay        = pdata->poll_delay ? : 1;
+       ts->poll_period       = pdata->poll_period ? : 1;
        ts->get_pendown_state = pdata->get_pendown_state;
        ts->clear_penirq      = pdata->clear_penirq;
 
@@ -305,9 +310,10 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
        input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
        input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 
-       input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
-       input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
-       input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
+       input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, pdata->fuzzx, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, pdata->fuzzy, 0);
+       input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT,
+                       pdata->fuzzz, 0);
 
        if (pdata->init_platform_hw)
                pdata->init_platform_hw();
index 59de638225fe4b30b71bcddc1cdf4ff8b50a4fa5..e35058bcd7b98e0f1b690f2e359cec96df05140e 100644 (file)
@@ -156,8 +156,10 @@ static int if_open(struct tty_struct *tty, struct file *filp)
        if (!cs || !try_module_get(cs->driver->owner))
                return -ENODEV;
 
-       if (mutex_lock_interruptible(&cs->mutex))
+       if (mutex_lock_interruptible(&cs->mutex)) {
+               module_put(cs->driver->owner);
                return -ERESTARTSYS;
+       }
        tty->driver_data = cs;
 
        ++cs->open_count;
index 1d44d470897ca4660b6e4f4e05218293f3e9c398..86a5c4f7775eb5c95a23a35b1bf05a77a8ba9681 100644 (file)
@@ -674,7 +674,7 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
  *     cflags  buffer containing error flags for received characters (ignored)
  *     count   number of received characters
  */
-static unsigned int
+static void
 gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
                    char *cflags, int count)
 {
@@ -683,12 +683,12 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
        struct inbuf_t *inbuf;
 
        if (!cs)
-               return -ENODEV;
+               return;
        inbuf = cs->inbuf;
        if (!inbuf) {
                dev_err(cs->dev, "%s: no inbuf\n", __func__);
                cs_put(cs);
-               return -EINVAL;
+               return;
        }
 
        tail = inbuf->tail;
@@ -725,8 +725,6 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
        gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
        gigaset_schedule_event(cs);
        cs_put(cs);
-
-       return count;
 }
 
 /*
index 91f06a3ef00223a4403230579fa71f9cc404c7c1..61f516f376dc8d9dd2db0c9d366054c6cec4f266 100644 (file)
@@ -149,7 +149,7 @@ static void avmcs_release(struct pcmcia_device *link)
 } /* avmcs_release */
 
 
-static struct pcmcia_device_id avmcs_ids[] = {
+static const struct pcmcia_device_id avmcs_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),
        PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430),
        PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a),
index d36a4c09e25db2b5d8ee558ab2bf31664455e508..0bbee7824d78790130b6ea4afdc42ebe8895d399 100644 (file)
@@ -113,9 +113,8 @@ void diva_xdi_didd_remove_adapter(int card)
 static void start_dbg(void)
 {
        DbgRegister("DIVAS", DRIVERRELEASE_DIVAS, (debugmask) ? debugmask : DBG_DEFAULT);
-       DBG_LOG(("DIVA ISDNXDI BUILD (%s[%s]-%s-%s)",
-                DIVA_BUILD, diva_xdi_common_code_build, __DATE__,
-                __TIME__))
+       DBG_LOG(("DIVA ISDNXDI BUILD (%s[%s])",
+                DIVA_BUILD, diva_xdi_common_code_build))
 }
 
 /*
index 3ccbff13eaf238541beb0564542db9a647cbdd8b..71a8eb6ef71ead7efca9b247f205aef4cca86817 100644 (file)
@@ -283,6 +283,7 @@ hfcsusb_ph_info(struct hfcsusb *hw)
        _queue_data(&dch->dev.D, MPH_INFORMATION_IND, MISDN_ID_ANY,
                sizeof(struct ph_info_dch) + dch->dev.nrbchan *
                sizeof(struct ph_info_ch), phi, GFP_ATOMIC);
+       kfree(phi);
 }
 
 /*
index 54ae71a907f937c8fcf3d443bf79d4a43a5499bd..db25b6b2ae3911a808a8f2dfb968bc37a4fe6e65 100644 (file)
@@ -1072,6 +1072,12 @@ nj_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                return -ENODEV;
        }
 
+       if (pdev->subsystem_vendor == 0xb100 &&
+           pdev->subsystem_device == 0x0003 ) {
+               pr_notice("Netjet: Digium TDM400P not handled yet\n");
+               return -ENODEV;
+       }
+
        card = kzalloc(sizeof(struct tiger_hw), GFP_ATOMIC);
        if (!card) {
                pr_info("No kmem for Netjet\n");
index ac4dd7857cbd3e50edb12b3eb715614a0e17643c..8f0ad2a52e8705adf33ca60624e871107918b315 100644 (file)
@@ -146,7 +146,7 @@ static void avma1cs_release(struct pcmcia_device *link)
        pcmcia_disable_device(link);
 } /* avma1cs_release */
 
-static struct pcmcia_device_id avma1cs_ids[] = {
+static const struct pcmcia_device_id avma1cs_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
        PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
        PCMCIA_DEVICE_NULL
index 9e5e87be756b179db066467b8c3eefdba1d67b9c..f0b6c0ef99bbf58f25cf7ca49a420e31913b6b91 100644 (file)
@@ -200,7 +200,7 @@ static int elsa_resume(struct pcmcia_device *link)
        return 0;
 }
 
-static struct pcmcia_device_id elsa_ids[] = {
+static const struct pcmcia_device_id elsa_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257),
        PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257),
        PCMCIA_DEVICE_NULL
index 360204bc2777d6f2b941f478ab0a11d2881f07fb..06473f81f0395fd74d54dd44fd18b72c6a187b82 100644 (file)
@@ -186,7 +186,7 @@ static int sedlbauer_resume(struct pcmcia_device *link)
 }
 
 
-static struct pcmcia_device_id sedlbauer_ids[] = {
+static const struct pcmcia_device_id sedlbauer_ids[] = {
        PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "speed star II", "V 3.1", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a),
        PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D67", 0x81fb79f5, 0xe4e9bc12, 0x397b7e90),
        PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D98", 0x81fb79f5, 0xe4e9bc12, 0x2e5c7fce),
index 360f9ec7c8023e73796ce66a1c6594324c0109a6..161a1938552ee6ba836c6a7a4ba6dcd9b459cd15 100644 (file)
@@ -183,7 +183,7 @@ static int teles_resume(struct pcmcia_device *link)
 }
 
 
-static struct pcmcia_device_id teles_ids[] = {
+static const struct pcmcia_device_id teles_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
        PCMCIA_DEVICE_NULL,
 };
index 9bec8699b8a327e107ddeb4fcfadb01e588c54e7..713d43b4e563396f419e9583af58b6a4ed636290 100644 (file)
@@ -1,3 +1,10 @@
+config LEDS_GPIO_REGISTER
+       bool
+       help
+         This option provides the function gpio_led_register_device.
+         As this function is used by arch code it must not be compiled as a
+         module.
+
 menuconfig NEW_LEDS
        bool "LED Support"
        help
@@ -7,15 +14,14 @@ menuconfig NEW_LEDS
          This is not related to standard keyboard LEDs which are controlled
          via the input system.
 
+if NEW_LEDS
+
 config LEDS_CLASS
        bool "LED Class Support"
-       depends on NEW_LEDS
        help
          This option enables the led sysfs class in /sys/class/leds.  You'll
          need this to do anything useful with LEDs.  If unsure, say N.
 
-if NEW_LEDS
-
 comment "LED drivers"
 
 config LEDS_88PM860X
@@ -115,13 +121,6 @@ config LEDS_ALIX2
          This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs.
          You have to set leds-alix2.force=1 for boards with Award BIOS.
 
-config LEDS_H1940
-       tristate "LED Support for iPAQ H1940 device"
-       depends on LEDS_CLASS
-       depends on ARCH_H1940
-       help
-         This option enables support for the LEDs on the h1940.
-
 config LEDS_COBALT_QUBE
        tristate "LED Support for the Cobalt Qube series front LED"
        depends on LEDS_CLASS
@@ -162,6 +161,16 @@ config LEDS_PCA9532
          LED controller. It is generally only useful
          as a platform driver
 
+config LEDS_PCA9532_GPIO
+       bool "Enable GPIO support for PCA9532"
+       depends on LEDS_PCA9532
+       depends on GPIOLIB
+       help
+         Allow unused pins on PCA9532 to be used as gpio.
+
+         To use a pin as gpio pca9532_type in pca9532_platform data needs to
+         set to PCA9532_TYPE_GPIO.
+
 config LEDS_GPIO
        tristate "LED Support for GPIO connected LEDs"
        depends on LEDS_CLASS
@@ -379,6 +388,17 @@ config LEDS_NETXBIG
          and 5Big Network v2 boards. The LEDs are wired to a CPLD and are
          controlled through a GPIO extension bus.
 
+config LEDS_ASIC3
+       bool "LED support for the HTC ASIC3"
+       depends on LEDS_CLASS
+       depends on MFD_ASIC3
+       default y
+       help
+         This option enables support for the LEDs on the HTC ASIC3. The HTC
+         ASIC3 LED GPIOs are inputs, not outputs, thus the leds-gpio driver
+         cannot be used. This driver supports hardware blinking with an on+off
+         period from 62ms to 125s. Say Y to enable LEDs on the HP iPAQ hx4700.
+
 config LEDS_TRIGGERS
        bool "LED Trigger support"
        depends on LEDS_CLASS
index 39c80fca84d276e3327ec4a69a902a85ebc6ae44..bbfd2e367dc0e8a6b917c2c94b092bfa66bea35e 100644 (file)
@@ -17,11 +17,11 @@ obj-$(CONFIG_LEDS_NET48XX)          += leds-net48xx.o
 obj-$(CONFIG_LEDS_NET5501)             += leds-net5501.o
 obj-$(CONFIG_LEDS_WRAP)                        += leds-wrap.o
 obj-$(CONFIG_LEDS_ALIX2)               += leds-alix2.o
-obj-$(CONFIG_LEDS_H1940)               += leds-h1940.o
 obj-$(CONFIG_LEDS_COBALT_QUBE)         += leds-cobalt-qube.o
 obj-$(CONFIG_LEDS_COBALT_RAQ)          += leds-cobalt-raq.o
 obj-$(CONFIG_LEDS_SUNFIRE)             += leds-sunfire.o
 obj-$(CONFIG_LEDS_PCA9532)             += leds-pca9532.o
+obj-$(CONFIG_LEDS_GPIO_REGISTER)       += leds-gpio-register.o
 obj-$(CONFIG_LEDS_GPIO)                        += leds-gpio.o
 obj-$(CONFIG_LEDS_LP3944)              += leds-lp3944.o
 obj-$(CONFIG_LEDS_LP5521)              += leds-lp5521.o
@@ -42,6 +42,7 @@ obj-$(CONFIG_LEDS_DELL_NETBOOKS)      += dell-led.o
 obj-$(CONFIG_LEDS_MC13783)             += leds-mc13783.o
 obj-$(CONFIG_LEDS_NS2)                 += leds-ns2.o
 obj-$(CONFIG_LEDS_NETXBIG)             += leds-netxbig.o
+obj-$(CONFIG_LEDS_ASIC3)               += leds-asic3.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)          += leds-dac124s085.o
index d5a4ade88991eb690e053a6a4218de0512ad9387..dc3d3d83191a043de95e7e7b41a5aa47cf57100c 100644 (file)
@@ -131,7 +131,8 @@ static void led_set_software_blink(struct led_classdev *led_cdev,
        if (!led_cdev->blink_brightness)
                led_cdev->blink_brightness = led_cdev->max_brightness;
 
-       if (delay_on == led_cdev->blink_delay_on &&
+       if (led_get_trigger_data(led_cdev) &&
+           delay_on == led_cdev->blink_delay_on &&
            delay_off == led_cdev->blink_delay_off)
                return;
 
index 416def84d0459e5a5c3a9708261d12fdf76280a6..0d4c16678ace37a2030f68d141bdf19cfc50d3b3 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/leds.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
-#include <linux/mfd/core.h>
 #include <linux/mfd/88pm860x.h>
 
 #define LED_PWM_SHIFT          (3)
@@ -171,7 +170,6 @@ static int pm860x_led_probe(struct platform_device *pdev)
        struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
        struct pm860x_led_pdata *pdata;
        struct pm860x_led *data;
-       struct mfd_cell *cell;
        struct resource *res;
        int ret;
 
@@ -181,10 +179,7 @@ static int pm860x_led_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       cell = pdev->dev.platform_data;
-       if (cell == NULL)
-               return -ENODEV;
-       pdata = cell->mfd_data;
+       pdata = pdev->dev.platform_data;
        if (pdata == NULL) {
                dev_err(&pdev->dev, "No platform data!\n");
                return -EINVAL;
diff --git a/drivers/leds/leds-asic3.c b/drivers/leds/leds-asic3.c
new file mode 100644 (file)
index 0000000..22f847c
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ *  Copyright (C) 2011 Paul Parsons <lost.distance@yahoo.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/asic3.h>
+#include <linux/mfd/core.h>
+
+/*
+ *     The HTC ASIC3 LED GPIOs are inputs, not outputs.
+ *     Hence we turn the LEDs on/off via the TimeBase register.
+ */
+
+/*
+ *     When TimeBase is 4 the clock resolution is about 32Hz.
+ *     This driver supports hardware blinking with an on+off
+ *     period from 62ms (2 clocks) to 125s (4000 clocks).
+ */
+#define MS_TO_CLK(ms)  DIV_ROUND_CLOSEST(((ms)*1024), 32000)
+#define CLK_TO_MS(clk) (((clk)*32000)/1024)
+#define MAX_CLK                4000            /* Fits into 12-bit Time registers */
+#define MAX_MS         CLK_TO_MS(MAX_CLK)
+
+static const unsigned int led_n_base[ASIC3_NUM_LEDS] = {
+       [0] = ASIC3_LED_0_Base,
+       [1] = ASIC3_LED_1_Base,
+       [2] = ASIC3_LED_2_Base,
+};
+
+static void brightness_set(struct led_classdev *cdev,
+       enum led_brightness value)
+{
+       struct platform_device *pdev = to_platform_device(cdev->dev->parent);
+       const struct mfd_cell *cell = mfd_get_cell(pdev);
+       struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+       u32 timebase;
+       unsigned int base;
+
+       timebase = (value == LED_OFF) ? 0 : (LED_EN|0x4);
+
+       base = led_n_base[cell->id];
+       asic3_write_register(asic, (base + ASIC3_LED_PeriodTime), 32);
+       asic3_write_register(asic, (base + ASIC3_LED_DutyTime), 32);
+       asic3_write_register(asic, (base + ASIC3_LED_AutoStopCount), 0);
+       asic3_write_register(asic, (base + ASIC3_LED_TimeBase), timebase);
+}
+
+static int blink_set(struct led_classdev *cdev,
+       unsigned long *delay_on,
+       unsigned long *delay_off)
+{
+       struct platform_device *pdev = to_platform_device(cdev->dev->parent);
+       const struct mfd_cell *cell = mfd_get_cell(pdev);
+       struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+       u32 on;
+       u32 off;
+       unsigned int base;
+
+       if (*delay_on > MAX_MS || *delay_off > MAX_MS)
+               return -EINVAL;
+
+       if (*delay_on == 0 && *delay_off == 0) {
+               /* If both are zero then a sensible default should be chosen */
+               on = MS_TO_CLK(500);
+               off = MS_TO_CLK(500);
+       } else {
+               on = MS_TO_CLK(*delay_on);
+               off = MS_TO_CLK(*delay_off);
+               if ((on + off) > MAX_CLK)
+                       return -EINVAL;
+       }
+
+       base = led_n_base[cell->id];
+       asic3_write_register(asic, (base + ASIC3_LED_PeriodTime), (on + off));
+       asic3_write_register(asic, (base + ASIC3_LED_DutyTime), on);
+       asic3_write_register(asic, (base + ASIC3_LED_AutoStopCount), 0);
+       asic3_write_register(asic, (base + ASIC3_LED_TimeBase), (LED_EN|0x4));
+
+       *delay_on = CLK_TO_MS(on);
+       *delay_off = CLK_TO_MS(off);
+
+       return 0;
+}
+
+static int __devinit asic3_led_probe(struct platform_device *pdev)
+{
+       struct asic3_led *led = pdev->dev.platform_data;
+       int ret;
+
+       ret = mfd_cell_enable(pdev);
+       if (ret < 0)
+               goto ret0;
+
+       led->cdev = kzalloc(sizeof(struct led_classdev), GFP_KERNEL);
+       if (!led->cdev) {
+               ret = -ENOMEM;
+               goto ret1;
+       }
+
+       led->cdev->name = led->name;
+       led->cdev->default_trigger = led->default_trigger;
+       led->cdev->brightness_set = brightness_set;
+       led->cdev->blink_set = blink_set;
+
+       ret = led_classdev_register(&pdev->dev, led->cdev);
+       if (ret < 0)
+               goto ret2;
+
+       return 0;
+
+ret2:
+       kfree(led->cdev);
+ret1:
+       (void) mfd_cell_disable(pdev);
+ret0:
+       return ret;
+}
+
+static int __devexit asic3_led_remove(struct platform_device *pdev)
+{
+       struct asic3_led *led = pdev->dev.platform_data;
+
+       led_classdev_unregister(led->cdev);
+
+       kfree(led->cdev);
+
+       return mfd_cell_disable(pdev);
+}
+
+static struct platform_driver asic3_led_driver = {
+       .probe          = asic3_led_probe,
+       .remove         = __devexit_p(asic3_led_remove),
+       .driver         = {
+               .name   = "leds-asic3",
+               .owner  = THIS_MODULE,
+       },
+};
+
+MODULE_ALIAS("platform:leds-asic3");
+
+static int __init asic3_led_init(void)
+{
+       return platform_driver_register(&asic3_led_driver);
+}
+
+static void __exit asic3_led_exit(void)
+{
+       platform_driver_unregister(&asic3_led_driver);
+}
+
+module_init(asic3_led_init);
+module_exit(asic3_led_exit);
+
+MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
+MODULE_DESCRIPTION("HTC ASIC3 LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-gpio-register.c b/drivers/leds/leds-gpio-register.c
new file mode 100644 (file)
index 0000000..1c4ed55
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
+ *
+ * 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/err.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
+
+/**
+ * gpio_led_register_device - register a gpio-led device
+ * @pdata: the platform data used for the new device
+ *
+ * Makes a copy of pdata and pdata->leds and registers a new leds-gpio device
+ * with the result. This allows to have pdata and pdata-leds in .init.rodata
+ * and so saves some bytes compared to a static struct platform_device with
+ * static platform data.
+ *
+ * Returns the registered device or an error pointer.
+ */
+struct platform_device *__init gpio_led_register_device(
+               int id, const struct gpio_led_platform_data *pdata)
+{
+       struct platform_device *ret;
+       struct gpio_led_platform_data _pdata = *pdata;
+
+       _pdata.leds = kmemdup(pdata->leds,
+                       pdata->num_leds * sizeof(*pdata->leds), GFP_KERNEL);
+       if (!_pdata.leds)
+               return ERR_PTR(-ENOMEM);
+
+       ret = platform_device_register_resndata(NULL, "leds-gpio", id,
+                       NULL, 0, &_pdata, sizeof(_pdata));
+       if (IS_ERR(ret))
+               kfree(_pdata.leds);
+
+       return ret;
+}
diff --git a/drivers/leds/leds-h1940.c b/drivers/leds/leds-h1940.c
deleted file mode 100644 (file)
index 173d104..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * drivers/leds/leds-h1940.c
- * Copyright (c) Arnaud Patard <arnaud.patard@rtp-net.org>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive for
- * more details.
- *
- * H1940 leds driver
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/leds.h>
-#include <linux/gpio.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/hardware.h>
-#include <mach/h1940-latch.h>
-
-/*
- * Green led.
- */
-static void h1940_greenled_set(struct led_classdev *led_dev,
-                              enum led_brightness value)
-{
-       switch (value) {
-       case LED_HALF:
-               h1940_latch_control(0, H1940_LATCH_LED_FLASH);
-               s3c2410_gpio_setpin(S3C2410_GPA7, 1);
-               break;
-       case LED_FULL:
-               h1940_latch_control(0, H1940_LATCH_LED_GREEN);
-               s3c2410_gpio_setpin(S3C2410_GPA7, 1);
-               break;
-       default:
-       case LED_OFF:
-               h1940_latch_control(H1940_LATCH_LED_FLASH, 0);
-               h1940_latch_control(H1940_LATCH_LED_GREEN, 0);
-               s3c2410_gpio_setpin(S3C2410_GPA7, 0);
-               break;
-       }
-}
-
-static struct led_classdev h1940_greenled = {
-       .name                   = "h1940:green",
-       .brightness_set         = h1940_greenled_set,
-       .default_trigger        = "h1940-charger",
-};
-
-/*
- * Red led.
- */
-static void h1940_redled_set(struct led_classdev *led_dev,
-                            enum led_brightness value)
-{
-       switch (value) {
-       case LED_HALF:
-               h1940_latch_control(0, H1940_LATCH_LED_FLASH);
-               s3c2410_gpio_setpin(S3C2410_GPA1, 1);
-               break;
-       case LED_FULL:
-               h1940_latch_control(0, H1940_LATCH_LED_RED);
-               s3c2410_gpio_setpin(S3C2410_GPA1, 1);
-               break;
-       default:
-       case LED_OFF:
-               h1940_latch_control(H1940_LATCH_LED_FLASH, 0);
-               h1940_latch_control(H1940_LATCH_LED_RED, 0);
-               s3c2410_gpio_setpin(S3C2410_GPA1, 0);
-               break;
-       }
-}
-
-static struct led_classdev h1940_redled = {
-       .name                   = "h1940:red",
-       .brightness_set         = h1940_redled_set,
-       .default_trigger        = "h1940-charger",
-};
-
-/*
- * Blue led.
- * (it can only be blue flashing led)
- */
-static void h1940_blueled_set(struct led_classdev *led_dev,
-                             enum led_brightness value)
-{
-       if (value) {
-               /* flashing Blue */
-               h1940_latch_control(0, H1940_LATCH_LED_FLASH);
-               s3c2410_gpio_setpin(S3C2410_GPA3, 1);
-       } else {
-               h1940_latch_control(H1940_LATCH_LED_FLASH, 0);
-               s3c2410_gpio_setpin(S3C2410_GPA3, 0);
-       }
-
-}
-
-static struct led_classdev h1940_blueled = {
-       .name                   = "h1940:blue",
-       .brightness_set         = h1940_blueled_set,
-       .default_trigger        = "h1940-bluetooth",
-};
-
-static int __devinit h1940leds_probe(struct platform_device *pdev)
-{
-       int ret;
-
-       ret = led_classdev_register(&pdev->dev, &h1940_greenled);
-       if (ret)
-               goto err_green;
-
-       ret = led_classdev_register(&pdev->dev, &h1940_redled);
-       if (ret)
-               goto err_red;
-
-       ret = led_classdev_register(&pdev->dev, &h1940_blueled);
-       if (ret)
-               goto err_blue;
-
-       return 0;
-
-err_blue:
-       led_classdev_unregister(&h1940_redled);
-err_red:
-       led_classdev_unregister(&h1940_greenled);
-err_green:
-       return ret;
-}
-
-static int h1940leds_remove(struct platform_device *pdev)
-{
-       led_classdev_unregister(&h1940_greenled);
-       led_classdev_unregister(&h1940_redled);
-       led_classdev_unregister(&h1940_blueled);
-       return 0;
-}
-
-
-static struct platform_driver h1940leds_driver = {
-       .driver         = {
-               .name   = "h1940-leds",
-               .owner  = THIS_MODULE,
-       },
-       .probe          = h1940leds_probe,
-       .remove         = h1940leds_remove,
-};
-
-
-static int __init h1940leds_init(void)
-{
-       return platform_driver_register(&h1940leds_driver);
-}
-
-static void __exit h1940leds_exit(void)
-{
-       platform_driver_unregister(&h1940leds_driver);
-}
-
-module_init(h1940leds_init);
-module_exit(h1940leds_exit);
-
-MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
-MODULE_DESCRIPTION("LED driver for the iPAQ H1940");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:h1940-leds");
index b37e6186d0fa007e2edc23f8186643b803429b2b..4d7ce7631acf93eca1d0e3eaf88d8bfac7414c79 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/input.h>
 #include <linux/led-lm3530.h>
 #include <linux/types.h>
+#include <linux/regulator/consumer.h>
 
 #define LM3530_LED_DEV "lcd-backlight"
 #define LM3530_NAME "lm3530-led"
@@ -96,12 +97,18 @@ static struct lm3530_mode_map mode_map[] = {
  * @client: i2c client
  * @pdata: LM3530 platform data
  * @mode: mode of operation - manual, ALS, PWM
+ * @regulator: regulator
+ * @brighness: previous brightness value
+ * @enable: regulator is enabled
  */
 struct lm3530_data {
        struct led_classdev led_dev;
        struct i2c_client *client;
        struct lm3530_platform_data *pdata;
        enum lm3530_mode mode;
+       struct regulator *regulator;
+       enum led_brightness brightness;
+       bool enable;
 };
 
 static const u8 lm3530_reg[LM3530_REG_MAX] = {
@@ -172,7 +179,10 @@ static int lm3530_init_registers(struct lm3530_data *drvdata)
        brt_ramp = (pltfm->brt_ramp_fall << LM3530_BRT_RAMP_FALL_SHIFT) |
                        (pltfm->brt_ramp_rise << LM3530_BRT_RAMP_RISE_SHIFT);
 
-       brightness = pltfm->brt_val;
+       if (drvdata->brightness)
+               brightness = drvdata->brightness;
+       else
+               brightness = drvdata->brightness = pltfm->brt_val;
 
        reg_val[0] = gen_config;        /* LM3530_GEN_CONFIG */
        reg_val[1] = als_config;        /* LM3530_ALS_CONFIG */
@@ -190,6 +200,16 @@ static int lm3530_init_registers(struct lm3530_data *drvdata)
        reg_val[13] = LM3530_DEF_ZT_3;  /* LM3530_ALS_Z3T_REG */
        reg_val[14] = LM3530_DEF_ZT_4;  /* LM3530_ALS_Z4T_REG */
 
+       if (!drvdata->enable) {
+               ret = regulator_enable(drvdata->regulator);
+               if (ret) {
+                       dev_err(&drvdata->client->dev,
+                                       "Enable regulator failed\n");
+                       return ret;
+               }
+               drvdata->enable = true;
+       }
+
        for (i = 0; i < LM3530_REG_MAX; i++) {
                ret = i2c_smbus_write_byte_data(client,
                                lm3530_reg[i], reg_val[i]);
@@ -210,12 +230,31 @@ static void lm3530_brightness_set(struct led_classdev *led_cdev,
        switch (drvdata->mode) {
        case LM3530_BL_MODE_MANUAL:
 
+               if (!drvdata->enable) {
+                       err = lm3530_init_registers(drvdata);
+                       if (err) {
+                               dev_err(&drvdata->client->dev,
+                                       "Register Init failed: %d\n", err);
+                               break;
+                       }
+               }
+
                /* set the brightness in brightness control register*/
                err = i2c_smbus_write_byte_data(drvdata->client,
                                LM3530_BRT_CTRL_REG, brt_val / 2);
                if (err)
                        dev_err(&drvdata->client->dev,
                                "Unable to set brightness: %d\n", err);
+               else
+                       drvdata->brightness = brt_val / 2;
+
+               if (brt_val == 0) {
+                       err = regulator_disable(drvdata->regulator);
+                       if (err)
+                               dev_err(&drvdata->client->dev,
+                                       "Disable regulator failed\n");
+                       drvdata->enable = false;
+               }
                break;
        case LM3530_BL_MODE_ALS:
                break;
@@ -297,20 +336,31 @@ static int __devinit lm3530_probe(struct i2c_client *client,
        drvdata->mode = pdata->mode;
        drvdata->client = client;
        drvdata->pdata = pdata;
+       drvdata->brightness = LED_OFF;
+       drvdata->enable = false;
        drvdata->led_dev.name = LM3530_LED_DEV;
        drvdata->led_dev.brightness_set = lm3530_brightness_set;
 
        i2c_set_clientdata(client, drvdata);
 
-       err = lm3530_init_registers(drvdata);
-       if (err < 0) {
-               dev_err(&client->dev, "Register Init failed: %d\n", err);
-               err = -ENODEV;
-               goto err_reg_init;
+       drvdata->regulator = regulator_get(&client->dev, "vin");
+       if (IS_ERR(drvdata->regulator)) {
+               dev_err(&client->dev, "regulator get failed\n");
+               err = PTR_ERR(drvdata->regulator);
+               drvdata->regulator = NULL;
+               goto err_regulator_get;
        }
 
-       err = led_classdev_register((struct device *)
-                                     &client->dev, &drvdata->led_dev);
+       if (drvdata->pdata->brt_val) {
+               err = lm3530_init_registers(drvdata);
+               if (err < 0) {
+                       dev_err(&client->dev,
+                               "Register Init failed: %d\n", err);
+                       err = -ENODEV;
+                       goto err_reg_init;
+               }
+       }
+       err = led_classdev_register(&client->dev, &drvdata->led_dev);
        if (err < 0) {
                dev_err(&client->dev, "Register led class failed: %d\n", err);
                err = -ENODEV;
@@ -330,6 +380,9 @@ err_create_file:
        led_classdev_unregister(&drvdata->led_dev);
 err_class_register:
 err_reg_init:
+       regulator_put(drvdata->regulator);
+err_regulator_get:
+       i2c_set_clientdata(client, NULL);
        kfree(drvdata);
 err_out:
        return err;
@@ -340,6 +393,10 @@ static int __devexit lm3530_remove(struct i2c_client *client)
        struct lm3530_data *drvdata = i2c_get_clientdata(client);
 
        device_remove_file(drvdata->led_dev.dev, &dev_attr_mode);
+
+       if (drvdata->enable)
+               regulator_disable(drvdata->regulator);
+       regulator_put(drvdata->regulator);
        led_classdev_unregister(&drvdata->led_dev);
        kfree(drvdata);
        return 0;
index 126ca7955f6e16f4f43cd72ec387d4a8a0fd3637..f369e56d6547ced1e92444c8f22cad3e3e09060d 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/leds.h>
 #include <linux/workqueue.h>
 #include <linux/mfd/mc13783.h>
-#include <linux/mfd/core.h>
 #include <linux/slab.h>
 
 struct mc13783_led {
@@ -184,7 +183,7 @@ static int __devinit mc13783_led_setup(struct mc13783_led *led, int max_current)
 
 static int __devinit mc13783_leds_prepare(struct platform_device *pdev)
 {
-       struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
+       struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
        int ret = 0;
        int reg = 0;
@@ -265,7 +264,7 @@ out:
 
 static int __devinit mc13783_led_probe(struct platform_device *pdev)
 {
-       struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
+       struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct mc13783_led_platform_data *led_cur;
        struct mc13783_led *led, *led_dat;
        int ret, i;
@@ -352,7 +351,7 @@ err_free:
 
 static int __devexit mc13783_led_remove(struct platform_device *pdev)
 {
-       struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
+       struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct mc13783_led *led = platform_get_drvdata(pdev);
        struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
        int i;
index 5bf63af09ddf04adb63dac74bfa97b8882e0c754..d8d3a1e910a1bbb7f81e9c1d7c4cb58452415691 100644 (file)
@@ -1,13 +1,14 @@
 /*
  * pca9532.c - 16-bit Led dimmer
  *
+ * Copyright (C) 2011 Jan Weitzel
  * Copyright (C) 2008 Riku Voipio
  *
  * 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.
  *
- * Datasheet: http://www.nxp.com/acrobat/datasheets/PCA9532_3.pdf
+ * Datasheet: http://www.nxp.com/documents/data_sheet/PCA9532.pdf
  *
  */
 
 #include <linux/mutex.h>
 #include <linux/workqueue.h>
 #include <linux/leds-pca9532.h>
+#include <linux/gpio.h>
 
-#define PCA9532_REG_PSC(i) (0x2+(i)*2)
-#define PCA9532_REG_PWM(i) (0x3+(i)*2)
-#define PCA9532_REG_LS0  0x6
-#define LED_REG(led) ((led>>2)+PCA9532_REG_LS0)
-#define LED_NUM(led) (led & 0x3)
+/* m =  num_leds*/
+#define PCA9532_REG_INPUT(i)   ((i) >> 3)
+#define PCA9532_REG_OFFSET(m)  ((m) >> 4)
+#define PCA9532_REG_PSC(m, i)  (PCA9532_REG_OFFSET(m) + 0x1 + (i) * 2)
+#define PCA9532_REG_PWM(m, i)  (PCA9532_REG_OFFSET(m) + 0x2 + (i) * 2)
+#define LED_REG(m, led)                (PCA9532_REG_OFFSET(m) + 0x5 + (led >> 2))
+#define LED_NUM(led)           (led & 0x3)
 
 #define ldev_to_led(c)       container_of(c, struct pca9532_led, ldev)
 
+struct pca9532_chip_info {
+       u8      num_leds;
+};
+
 struct pca9532_data {
        struct i2c_client *client;
        struct pca9532_led leds[16];
        struct mutex update_lock;
        struct input_dev *idev;
        struct work_struct work;
+#ifdef CONFIG_LEDS_PCA9532_GPIO
+       struct gpio_chip gpio;
+#endif
+       const struct pca9532_chip_info *chip_info;
        u8 pwm[2];
        u8 psc[2];
 };
@@ -42,16 +54,41 @@ static int pca9532_probe(struct i2c_client *client,
        const struct i2c_device_id *id);
 static int pca9532_remove(struct i2c_client *client);
 
+enum {
+       pca9530,
+       pca9531,
+       pca9532,
+       pca9533,
+};
+
 static const struct i2c_device_id pca9532_id[] = {
-       { "pca9532", 0 },
+       { "pca9530", pca9530 },
+       { "pca9531", pca9531 },
+       { "pca9532", pca9532 },
+       { "pca9533", pca9533 },
        { }
 };
 
 MODULE_DEVICE_TABLE(i2c, pca9532_id);
 
+static const struct pca9532_chip_info pca9532_chip_info_tbl[] = {
+       [pca9530] = {
+               .num_leds = 2,
+       },
+       [pca9531] = {
+               .num_leds = 8,
+       },
+       [pca9532] = {
+               .num_leds = 16,
+       },
+       [pca9533] = {
+               .num_leds = 4,
+       },
+};
+
 static struct i2c_driver pca9532_driver = {
        .driver = {
-               .name = "pca9532",
+               .name = "pca953x",
        },
        .probe = pca9532_probe,
        .remove = pca9532_remove,
@@ -68,7 +105,7 @@ static int pca9532_calcpwm(struct i2c_client *client, int pwm, int blink,
 {
        int a = 0, b = 0, i = 0;
        struct pca9532_data *data = i2c_get_clientdata(client);
-       for (i = 0; i < 16; i++) {
+       for (i = 0; i < data->chip_info->num_leds; i++) {
                if (data->leds[i].type == PCA9532_TYPE_LED &&
                        data->leds[i].state == PCA9532_PWM0+pwm) {
                                a++;
@@ -92,10 +129,12 @@ static int pca9532_calcpwm(struct i2c_client *client, int pwm, int blink,
 static int pca9532_setpwm(struct i2c_client *client, int pwm)
 {
        struct pca9532_data *data = i2c_get_clientdata(client);
+       u8 maxleds = data->chip_info->num_leds;
+
        mutex_lock(&data->update_lock);
-       i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(pwm),
+       i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(maxleds, pwm),
                data->pwm[pwm]);
-       i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(pwm),
+       i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(maxleds, pwm),
                data->psc[pwm]);
        mutex_unlock(&data->update_lock);
        return 0;
@@ -106,15 +145,16 @@ static void pca9532_setled(struct pca9532_led *led)
 {
        struct i2c_client *client = led->client;
        struct pca9532_data *data = i2c_get_clientdata(client);
+       u8 maxleds = data->chip_info->num_leds;
        char reg;
 
        mutex_lock(&data->update_lock);
-       reg = i2c_smbus_read_byte_data(client, LED_REG(led->id));
+       reg = i2c_smbus_read_byte_data(client, LED_REG(maxleds, led->id));
        /* zero led bits */
        reg = reg & ~(0x3<<LED_NUM(led->id)*2);
        /* set the new value */
        reg = reg | (led->state << LED_NUM(led->id)*2);
-       i2c_smbus_write_byte_data(client, LED_REG(led->id), reg);
+       i2c_smbus_write_byte_data(client, LED_REG(maxleds, led->id), reg);
        mutex_unlock(&data->update_lock);
 }
 
@@ -183,10 +223,12 @@ static int pca9532_event(struct input_dev *dev, unsigned int type,
 
 static void pca9532_input_work(struct work_struct *work)
 {
-       struct pca9532_data *data;
-       data = container_of(work, struct pca9532_data, work);
+       struct pca9532_data *data =
+               container_of(work, struct pca9532_data, work);
+       u8 maxleds = data->chip_info->num_leds;
+
        mutex_lock(&data->update_lock);
-       i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(1),
+       i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(maxleds, 1),
                data->pwm[1]);
        mutex_unlock(&data->update_lock);
 }
@@ -200,16 +242,68 @@ static void pca9532_led_work(struct work_struct *work)
        pca9532_setled(led);
 }
 
-static void pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
+#ifdef CONFIG_LEDS_PCA9532_GPIO
+static int pca9532_gpio_request_pin(struct gpio_chip *gc, unsigned offset)
+{
+       struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
+       struct pca9532_led *led = &data->leds[offset];
+
+       if (led->type == PCA9532_TYPE_GPIO)
+               return 0;
+
+       return -EBUSY;
+}
+
+static void pca9532_gpio_set_value(struct gpio_chip *gc, unsigned offset, int val)
+{
+       struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
+       struct pca9532_led *led = &data->leds[offset];
+
+       if (val)
+               led->state = PCA9532_ON;
+       else
+               led->state = PCA9532_OFF;
+
+       pca9532_setled(led);
+}
+
+static int pca9532_gpio_get_value(struct gpio_chip *gc, unsigned offset)
+{
+       struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
+       unsigned char reg;
+
+       reg = i2c_smbus_read_byte_data(data->client, PCA9532_REG_INPUT(offset));
+
+       return !!(reg & (1 << (offset % 8)));
+}
+
+static int pca9532_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+       /* To use as input ensure pin is not driven */
+       pca9532_gpio_set_value(gc, offset, 0);
+
+       return 0;
+}
+
+static int pca9532_gpio_direction_output(struct gpio_chip *gc, unsigned offset, int val)
+{
+       pca9532_gpio_set_value(gc, offset, val);
+
+       return 0;
+}
+#endif /* CONFIG_LEDS_PCA9532_GPIO */
+
+static int pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
 {
        int i = n_devs;
 
        if (!data)
-               return;
+               return -EINVAL;
 
        while (--i >= 0) {
                switch (data->leds[i].type) {
                case PCA9532_TYPE_NONE:
+               case PCA9532_TYPE_GPIO:
                        break;
                case PCA9532_TYPE_LED:
                        led_classdev_unregister(&data->leds[i].ldev);
@@ -224,23 +318,38 @@ static void pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
                        break;
                }
        }
+
+#ifdef CONFIG_LEDS_PCA9532_GPIO
+       if (data->gpio.dev) {
+               int err = gpiochip_remove(&data->gpio);
+               if (err) {
+                       dev_err(&data->client->dev, "%s failed, %d\n",
+                                               "gpiochip_remove()", err);
+                       return err;
+               }
+       }
+#endif
+
+       return 0;
 }
 
 static int pca9532_configure(struct i2c_client *client,
        struct pca9532_data *data, struct pca9532_platform_data *pdata)
 {
        int i, err = 0;
+       int gpios = 0;
+       u8 maxleds = data->chip_info->num_leds;
 
        for (i = 0; i < 2; i++) {
                data->pwm[i] = pdata->pwm[i];
                data->psc[i] = pdata->psc[i];
-               i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(i),
+               i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(maxleds, i),
                        data->pwm[i]);
-               i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(i),
+               i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(maxleds, i),
                        data->psc[i]);
        }
 
-       for (i = 0; i < 16; i++) {
+       for (i = 0; i < data->chip_info->num_leds; i++) {
                struct pca9532_led *led = &data->leds[i];
                struct pca9532_led *pled = &pdata->leds[i];
                led->client = client;
@@ -249,6 +358,9 @@ static int pca9532_configure(struct i2c_client *client,
                switch (led->type) {
                case PCA9532_TYPE_NONE:
                        break;
+               case PCA9532_TYPE_GPIO:
+                       gpios++;
+                       break;
                case PCA9532_TYPE_LED:
                        led->state = pled->state;
                        led->name = pled->name;
@@ -297,6 +409,34 @@ static int pca9532_configure(struct i2c_client *client,
                        break;
                }
        }
+
+#ifdef CONFIG_LEDS_PCA9532_GPIO
+       if (gpios) {
+               data->gpio.label = "gpio-pca9532";
+               data->gpio.direction_input = pca9532_gpio_direction_input;
+               data->gpio.direction_output = pca9532_gpio_direction_output;
+               data->gpio.set = pca9532_gpio_set_value;
+               data->gpio.get = pca9532_gpio_get_value;
+               data->gpio.request = pca9532_gpio_request_pin;
+               data->gpio.can_sleep = 1;
+               data->gpio.base = pdata->gpio_base;
+               data->gpio.ngpio = data->chip_info->num_leds;
+               data->gpio.dev = &client->dev;
+               data->gpio.owner = THIS_MODULE;
+
+               err = gpiochip_add(&data->gpio);
+               if (err) {
+                       /* Use data->gpio.dev as a flag for freeing gpiochip */
+                       data->gpio.dev = NULL;
+                       dev_warn(&client->dev, "could not add gpiochip\n");
+               } else {
+                       dev_info(&client->dev, "gpios %i...%i\n",
+                               data->gpio.base, data->gpio.base +
+                               data->gpio.ngpio - 1);
+               }
+       }
+#endif
+
        return 0;
 
 exit:
@@ -322,6 +462,8 @@ static int pca9532_probe(struct i2c_client *client,
        if (!data)
                return -ENOMEM;
 
+       data->chip_info = &pca9532_chip_info_tbl[id->driver_data];
+
        dev_info(&client->dev, "setting platform data\n");
        i2c_set_clientdata(client, data);
        data->client = client;
@@ -337,7 +479,12 @@ static int pca9532_probe(struct i2c_client *client,
 static int pca9532_remove(struct i2c_client *client)
 {
        struct pca9532_data *data = i2c_get_clientdata(client);
-       pca9532_destroy_devices(data, 16);
+       int err;
+
+       err = pca9532_destroy_devices(data, data->chip_info->num_leds);
+       if (err)
+               return err;
+
        kfree(data);
        return 0;
 }
index 2dd8ecbfdc3155250d3608897db8d1d0047fc317..e77c7f8dcdd469bfa8b84472dabb81e2df1b10e7 100644 (file)
@@ -40,10 +40,17 @@ void led_trigger_set_default(struct led_classdev *led_cdev);
 void led_trigger_set(struct led_classdev *led_cdev,
                        struct led_trigger *trigger);
 void led_trigger_remove(struct led_classdev *led_cdev);
+
+static inline void *led_get_trigger_data(struct led_classdev *led_cdev)
+{
+       return led_cdev->trigger_data;
+}
+
 #else
 #define led_trigger_set_default(x) do {} while (0)
 #define led_trigger_set(x, y) do {} while (0)
 #define led_trigger_remove(x) do {} while (0)
+#define led_get_trigger_data(x) (NULL)
 #endif
 
 ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
index b09bcbeade9c433c56365204b4848690bf08a366..d87c9d02f786df2570385faea517e54e883c5b30 100644 (file)
@@ -91,6 +91,9 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
        if (rc)
                goto err_out_delayon;
 
+       led_blink_set(led_cdev, &led_cdev->blink_delay_on,
+                     &led_cdev->blink_delay_off);
+
        led_cdev->trigger_data = (void *)1;
 
        return;
index 70bd738b8b99eff89185b8dee59f5a4f6599e4d3..574b09afedd32ff1f8f30ddefab722fb01edd17d 100644 (file)
@@ -534,6 +534,82 @@ void bitmap_print_sb(struct bitmap *bitmap)
        kunmap_atomic(sb, KM_USER0);
 }
 
+/*
+ * bitmap_new_disk_sb
+ * @bitmap
+ *
+ * This function is somewhat the reverse of bitmap_read_sb.  bitmap_read_sb
+ * reads and verifies the on-disk bitmap superblock and populates bitmap_info.
+ * This function verifies 'bitmap_info' and populates the on-disk bitmap
+ * structure, which is to be written to disk.
+ *
+ * Returns: 0 on success, -Exxx on error
+ */
+static int bitmap_new_disk_sb(struct bitmap *bitmap)
+{
+       bitmap_super_t *sb;
+       unsigned long chunksize, daemon_sleep, write_behind;
+       int err = -EINVAL;
+
+       bitmap->sb_page = alloc_page(GFP_KERNEL);
+       if (IS_ERR(bitmap->sb_page)) {
+               err = PTR_ERR(bitmap->sb_page);
+               bitmap->sb_page = NULL;
+               return err;
+       }
+       bitmap->sb_page->index = 0;
+
+       sb = kmap_atomic(bitmap->sb_page, KM_USER0);
+
+       sb->magic = cpu_to_le32(BITMAP_MAGIC);
+       sb->version = cpu_to_le32(BITMAP_MAJOR_HI);
+
+       chunksize = bitmap->mddev->bitmap_info.chunksize;
+       BUG_ON(!chunksize);
+       if (!is_power_of_2(chunksize)) {
+               kunmap_atomic(sb, KM_USER0);
+               printk(KERN_ERR "bitmap chunksize not a power of 2\n");
+               return -EINVAL;
+       }
+       sb->chunksize = cpu_to_le32(chunksize);
+
+       daemon_sleep = bitmap->mddev->bitmap_info.daemon_sleep;
+       if (!daemon_sleep ||
+           (daemon_sleep < 1) || (daemon_sleep > MAX_SCHEDULE_TIMEOUT)) {
+               printk(KERN_INFO "Choosing daemon_sleep default (5 sec)\n");
+               daemon_sleep = 5 * HZ;
+       }
+       sb->daemon_sleep = cpu_to_le32(daemon_sleep);
+       bitmap->mddev->bitmap_info.daemon_sleep = daemon_sleep;
+
+       /*
+        * FIXME: write_behind for RAID1.  If not specified, what
+        * is a good choice?  We choose COUNTER_MAX / 2 arbitrarily.
+        */
+       write_behind = bitmap->mddev->bitmap_info.max_write_behind;
+       if (write_behind > COUNTER_MAX)
+               write_behind = COUNTER_MAX / 2;
+       sb->write_behind = cpu_to_le32(write_behind);
+       bitmap->mddev->bitmap_info.max_write_behind = write_behind;
+
+       /* keep the array size field of the bitmap superblock up to date */
+       sb->sync_size = cpu_to_le64(bitmap->mddev->resync_max_sectors);
+
+       memcpy(sb->uuid, bitmap->mddev->uuid, 16);
+
+       bitmap->flags |= BITMAP_STALE;
+       sb->state |= cpu_to_le32(BITMAP_STALE);
+       bitmap->events_cleared = bitmap->mddev->events;
+       sb->events_cleared = cpu_to_le64(bitmap->mddev->events);
+
+       bitmap->flags |= BITMAP_HOSTENDIAN;
+       sb->version = cpu_to_le32(BITMAP_MAJOR_HOSTENDIAN);
+
+       kunmap_atomic(sb, KM_USER0);
+
+       return 0;
+}
+
 /* read the superblock from the bitmap file and initialize some bitmap fields */
 static int bitmap_read_sb(struct bitmap *bitmap)
 {
@@ -575,7 +651,7 @@ static int bitmap_read_sb(struct bitmap *bitmap)
                reason = "unrecognized superblock version";
        else if (chunksize < 512)
                reason = "bitmap chunksize too small";
-       else if ((1 << ffz(~chunksize)) != chunksize)
+       else if (!is_power_of_2(chunksize))
                reason = "bitmap chunksize not a power of 2";
        else if (daemon_sleep < 1 || daemon_sleep > MAX_SCHEDULE_TIMEOUT)
                reason = "daemon sleep period out of range";
@@ -1076,8 +1152,8 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
        }
 
        printk(KERN_INFO "%s: bitmap initialized from disk: "
-               "read %lu/%lu pages, set %lu bits\n",
-               bmname(bitmap), bitmap->file_pages, num_pages, bit_cnt);
+              "read %lu/%lu pages, set %lu of %lu bits\n",
+              bmname(bitmap), bitmap->file_pages, num_pages, bit_cnt, chunks);
 
        return 0;
 
@@ -1332,7 +1408,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
                        return 0;
                }
 
-               if (unlikely((*bmc & COUNTER_MAX) == COUNTER_MAX)) {
+               if (unlikely(COUNTER(*bmc) == COUNTER_MAX)) {
                        DEFINE_WAIT(__wait);
                        /* note that it is safe to do the prepare_to_wait
                         * after the test as long as we do it before dropping
@@ -1404,10 +1480,10 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto
                        sysfs_notify_dirent_safe(bitmap->sysfs_can_clear);
                }
 
-               if (!success && ! (*bmc & NEEDED_MASK))
+               if (!success && !NEEDED(*bmc))
                        *bmc |= NEEDED_MASK;
 
-               if ((*bmc & COUNTER_MAX) == COUNTER_MAX)
+               if (COUNTER(*bmc) == COUNTER_MAX)
                        wake_up(&bitmap->overflow_wait);
 
                (*bmc)--;
@@ -1728,9 +1804,16 @@ int bitmap_create(mddev_t *mddev)
                vfs_fsync(file, 1);
        }
        /* read superblock from bitmap file (this sets mddev->bitmap_info.chunksize) */
-       if (!mddev->bitmap_info.external)
-               err = bitmap_read_sb(bitmap);
-       else {
+       if (!mddev->bitmap_info.external) {
+               /*
+                * If 'MD_ARRAY_FIRST_USE' is set, then device-mapper is
+                * instructing us to create a new on-disk bitmap instance.
+                */
+               if (test_and_clear_bit(MD_ARRAY_FIRST_USE, &mddev->flags))
+                       err = bitmap_new_disk_sb(bitmap);
+               else
+                       err = bitmap_read_sb(bitmap);
+       } else {
                err = 0;
                if (mddev->bitmap_info.chunksize == 0 ||
                    mddev->bitmap_info.daemon_sleep == 0)
@@ -1754,9 +1837,6 @@ int bitmap_create(mddev_t *mddev)
        bitmap->chunks = chunks;
        bitmap->pages = pages;
        bitmap->missing_pages = pages;
-       bitmap->counter_bits = COUNTER_BITS;
-
-       bitmap->syncchunk = ~0UL;
 
 #ifdef INJECT_FATAL_FAULT_1
        bitmap->bp = NULL;
index d0aeaf46d932017505e4b3728cfa1ca3c9e6fe3c..b2a127e891acedc9843ff4b61e1e8c62b2456a48 100644 (file)
@@ -85,7 +85,6 @@
 typedef __u16 bitmap_counter_t;
 #define COUNTER_BITS 16
 #define COUNTER_BIT_SHIFT 4
-#define COUNTER_BYTE_RATIO (COUNTER_BITS / 8)
 #define COUNTER_BYTE_SHIFT (COUNTER_BIT_SHIFT - 3)
 
 #define NEEDED_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 1)))
@@ -196,19 +195,10 @@ struct bitmap {
 
        mddev_t *mddev; /* the md device that the bitmap is for */
 
-       int counter_bits; /* how many bits per block counter */
-
        /* bitmap chunksize -- how much data does each bit represent? */
        unsigned long chunkshift; /* chunksize = 2^chunkshift (for bitops) */
        unsigned long chunks; /* total number of data chunks for the array */
 
-       /* We hold a count on the chunk currently being synced, and drop
-        * it when the last block is started.  If the resync is aborted
-        * midway, we need to be able to drop that count, so we remember
-        * the counted chunk..
-        */
-       unsigned long syncchunk;
-
        __u64   events_cleared;
        int need_sync;
 
index 76a5af00a26b5b52ce45a72bc0e58d6744d33468..2067288f61f9b5e868da28c6c7c9694b9a5269cf 100644 (file)
@@ -19,6 +19,8 @@
 #define DM_MSG_PREFIX "io"
 
 #define DM_IO_MAX_REGIONS      BITS_PER_LONG
+#define MIN_IOS                16
+#define MIN_BIOS       16
 
 struct dm_io_client {
        mempool_t *pool;
@@ -40,34 +42,22 @@ struct io {
 
 static struct kmem_cache *_dm_io_cache;
 
-/*
- * io contexts are only dynamically allocated for asynchronous
- * io.  Since async io is likely to be the majority of io we'll
- * have the same number of io contexts as bios! (FIXME: must reduce this).
- */
-
-static unsigned int pages_to_ios(unsigned int pages)
-{
-       return 4 * pages;       /* too many ? */
-}
-
 /*
  * Create a client with mempool and bioset.
  */
-struct dm_io_client *dm_io_client_create(unsigned num_pages)
+struct dm_io_client *dm_io_client_create(void)
 {
-       unsigned ios = pages_to_ios(num_pages);
        struct dm_io_client *client;
 
        client = kmalloc(sizeof(*client), GFP_KERNEL);
        if (!client)
                return ERR_PTR(-ENOMEM);
 
-       client->pool = mempool_create_slab_pool(ios, _dm_io_cache);
+       client->pool = mempool_create_slab_pool(MIN_IOS, _dm_io_cache);
        if (!client->pool)
                goto bad;
 
-       client->bios = bioset_create(16, 0);
+       client->bios = bioset_create(MIN_BIOS, 0);
        if (!client->bios)
                goto bad;
 
@@ -81,13 +71,6 @@ struct dm_io_client *dm_io_client_create(unsigned num_pages)
 }
 EXPORT_SYMBOL(dm_io_client_create);
 
-int dm_io_client_resize(unsigned num_pages, struct dm_io_client *client)
-{
-       return mempool_resize(client->pool, pages_to_ios(num_pages),
-                             GFP_KERNEL);
-}
-EXPORT_SYMBOL(dm_io_client_resize);
-
 void dm_io_client_destroy(struct dm_io_client *client)
 {
        mempool_destroy(client->pool);
index 1bb73a13ca4003d841446efbe70ffda93a62061d..819e37eaaeba17cc3acf8009432f7b99f3dea4dd 100644 (file)
 
 #include "dm.h"
 
+#define SUB_JOB_SIZE   128
+#define SPLIT_COUNT    8
+#define MIN_JOBS       8
+#define RESERVE_PAGES  (DIV_ROUND_UP(SUB_JOB_SIZE << SECTOR_SHIFT, PAGE_SIZE))
+
 /*-----------------------------------------------------------------
  * Each kcopyd client has its own little pool of preallocated
  * pages for kcopyd io.
  *---------------------------------------------------------------*/
 struct dm_kcopyd_client {
-       spinlock_t lock;
        struct page_list *pages;
-       unsigned int nr_pages;
-       unsigned int nr_free_pages;
+       unsigned nr_reserved_pages;
+       unsigned nr_free_pages;
 
        struct dm_io_client *io_client;
 
@@ -67,15 +71,18 @@ static void wake(struct dm_kcopyd_client *kc)
        queue_work(kc->kcopyd_wq, &kc->kcopyd_work);
 }
 
-static struct page_list *alloc_pl(void)
+/*
+ * Obtain one page for the use of kcopyd.
+ */
+static struct page_list *alloc_pl(gfp_t gfp)
 {
        struct page_list *pl;
 
-       pl = kmalloc(sizeof(*pl), GFP_KERNEL);
+       pl = kmalloc(sizeof(*pl), gfp);
        if (!pl)
                return NULL;
 
-       pl->page = alloc_page(GFP_KERNEL);
+       pl->page = alloc_page(gfp);
        if (!pl->page) {
                kfree(pl);
                return NULL;
@@ -90,41 +97,56 @@ static void free_pl(struct page_list *pl)
        kfree(pl);
 }
 
-static int kcopyd_get_pages(struct dm_kcopyd_client *kc,
-                           unsigned int nr, struct page_list **pages)
+/*
+ * Add the provided pages to a client's free page list, releasing
+ * back to the system any beyond the reserved_pages limit.
+ */
+static void kcopyd_put_pages(struct dm_kcopyd_client *kc, struct page_list *pl)
 {
-       struct page_list *pl;
-
-       spin_lock(&kc->lock);
-       if (kc->nr_free_pages < nr) {
-               spin_unlock(&kc->lock);
-               return -ENOMEM;
-       }
-
-       kc->nr_free_pages -= nr;
-       for (*pages = pl = kc->pages; --nr; pl = pl->next)
-               ;
+       struct page_list *next;
 
-       kc->pages = pl->next;
-       pl->next = NULL;
+       do {
+               next = pl->next;
 
-       spin_unlock(&kc->lock);
+               if (kc->nr_free_pages >= kc->nr_reserved_pages)
+                       free_pl(pl);
+               else {
+                       pl->next = kc->pages;
+                       kc->pages = pl;
+                       kc->nr_free_pages++;
+               }
 
-       return 0;
+               pl = next;
+       } while (pl);
 }
 
-static void kcopyd_put_pages(struct dm_kcopyd_client *kc, struct page_list *pl)
+static int kcopyd_get_pages(struct dm_kcopyd_client *kc,
+                           unsigned int nr, struct page_list **pages)
 {
-       struct page_list *cursor;
+       struct page_list *pl;
+
+       *pages = NULL;
+
+       do {
+               pl = alloc_pl(__GFP_NOWARN | __GFP_NORETRY);
+               if (unlikely(!pl)) {
+                       /* Use reserved pages */
+                       pl = kc->pages;
+                       if (unlikely(!pl))
+                               goto out_of_memory;
+                       kc->pages = pl->next;
+                       kc->nr_free_pages--;
+               }
+               pl->next = *pages;
+               *pages = pl;
+       } while (--nr);
 
-       spin_lock(&kc->lock);
-       for (cursor = pl; cursor->next; cursor = cursor->next)
-               kc->nr_free_pages++;
+       return 0;
 
-       kc->nr_free_pages++;
-       cursor->next = kc->pages;
-       kc->pages = pl;
-       spin_unlock(&kc->lock);
+out_of_memory:
+       if (*pages)
+               kcopyd_put_pages(kc, *pages);
+       return -ENOMEM;
 }
 
 /*
@@ -141,13 +163,16 @@ static void drop_pages(struct page_list *pl)
        }
 }
 
-static int client_alloc_pages(struct dm_kcopyd_client *kc, unsigned int nr)
+/*
+ * Allocate and reserve nr_pages for the use of a specific client.
+ */
+static int client_reserve_pages(struct dm_kcopyd_client *kc, unsigned nr_pages)
 {
-       unsigned int i;
+       unsigned i;
        struct page_list *pl = NULL, *next;
 
-       for (i = 0; i < nr; i++) {
-               next = alloc_pl();
+       for (i = 0; i < nr_pages; i++) {
+               next = alloc_pl(GFP_KERNEL);
                if (!next) {
                        if (pl)
                                drop_pages(pl);
@@ -157,17 +182,18 @@ static int client_alloc_pages(struct dm_kcopyd_client *kc, unsigned int nr)
                pl = next;
        }
 
+       kc->nr_reserved_pages += nr_pages;
        kcopyd_put_pages(kc, pl);
-       kc->nr_pages += nr;
+
        return 0;
 }
 
 static void client_free_pages(struct dm_kcopyd_client *kc)
 {
-       BUG_ON(kc->nr_free_pages != kc->nr_pages);
+       BUG_ON(kc->nr_free_pages != kc->nr_reserved_pages);
        drop_pages(kc->pages);
        kc->pages = NULL;
-       kc->nr_free_pages = kc->nr_pages = 0;
+       kc->nr_free_pages = kc->nr_reserved_pages = 0;
 }
 
 /*-----------------------------------------------------------------
@@ -216,16 +242,17 @@ struct kcopyd_job {
        struct mutex lock;
        atomic_t sub_jobs;
        sector_t progress;
-};
 
-/* FIXME: this should scale with the number of pages */
-#define MIN_JOBS 512
+       struct kcopyd_job *master_job;
+};
 
 static struct kmem_cache *_job_cache;
 
 int __init dm_kcopyd_init(void)
 {
-       _job_cache = KMEM_CACHE(kcopyd_job, 0);
+       _job_cache = kmem_cache_create("kcopyd_job",
+                               sizeof(struct kcopyd_job) * (SPLIT_COUNT + 1),
+                               __alignof__(struct kcopyd_job), 0, NULL);
        if (!_job_cache)
                return -ENOMEM;
 
@@ -299,7 +326,12 @@ static int run_complete_job(struct kcopyd_job *job)
 
        if (job->pages)
                kcopyd_put_pages(kc, job->pages);
-       mempool_free(job, kc->job_pool);
+       /*
+        * If this is the master job, the sub jobs have already
+        * completed so we can free everything.
+        */
+       if (job->master_job == job)
+               mempool_free(job, kc->job_pool);
        fn(read_err, write_err, context);
 
        if (atomic_dec_and_test(&kc->nr_jobs))
@@ -460,14 +492,14 @@ static void dispatch_job(struct kcopyd_job *job)
        wake(kc);
 }
 
-#define SUB_JOB_SIZE 128
 static void segment_complete(int read_err, unsigned long write_err,
                             void *context)
 {
        /* FIXME: tidy this function */
        sector_t progress = 0;
        sector_t count = 0;
-       struct kcopyd_job *job = (struct kcopyd_job *) context;
+       struct kcopyd_job *sub_job = (struct kcopyd_job *) context;
+       struct kcopyd_job *job = sub_job->master_job;
        struct dm_kcopyd_client *kc = job->kc;
 
        mutex_lock(&job->lock);
@@ -498,8 +530,6 @@ static void segment_complete(int read_err, unsigned long write_err,
 
        if (count) {
                int i;
-               struct kcopyd_job *sub_job = mempool_alloc(kc->job_pool,
-                                                          GFP_NOIO);
 
                *sub_job = *job;
                sub_job->source.sector += progress;
@@ -511,7 +541,7 @@ static void segment_complete(int read_err, unsigned long write_err,
                }
 
                sub_job->fn = segment_complete;
-               sub_job->context = job;
+               sub_job->context = sub_job;
                dispatch_job(sub_job);
 
        } else if (atomic_dec_and_test(&job->sub_jobs)) {
@@ -531,19 +561,19 @@ static void segment_complete(int read_err, unsigned long write_err,
 }
 
 /*
- * Create some little jobs that will do the move between
- * them.
+ * Create some sub jobs to share the work between them.
  */
-#define SPLIT_COUNT 8
-static void split_job(struct kcopyd_job *job)
+static void split_job(struct kcopyd_job *master_job)
 {
        int i;
 
-       atomic_inc(&job->kc->nr_jobs);
+       atomic_inc(&master_job->kc->nr_jobs);
 
-       atomic_set(&job->sub_jobs, SPLIT_COUNT);
-       for (i = 0; i < SPLIT_COUNT; i++)
-               segment_complete(0, 0u, job);
+       atomic_set(&master_job->sub_jobs, SPLIT_COUNT);
+       for (i = 0; i < SPLIT_COUNT; i++) {
+               master_job[i + 1].master_job = master_job;
+               segment_complete(0, 0u, &master_job[i + 1]);
+       }
 }
 
 int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
@@ -553,7 +583,8 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
        struct kcopyd_job *job;
 
        /*
-        * Allocate a new job.
+        * Allocate an array of jobs consisting of one master job
+        * followed by SPLIT_COUNT sub jobs.
         */
        job = mempool_alloc(kc->job_pool, GFP_NOIO);
 
@@ -577,10 +608,10 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
 
        job->fn = fn;
        job->context = context;
+       job->master_job = job;
 
-       if (job->source.count < SUB_JOB_SIZE)
+       if (job->source.count <= SUB_JOB_SIZE)
                dispatch_job(job);
-
        else {
                mutex_init(&job->lock);
                job->progress = 0;
@@ -606,17 +637,15 @@ int kcopyd_cancel(struct kcopyd_job *job, int block)
 /*-----------------------------------------------------------------
  * Client setup
  *---------------------------------------------------------------*/
-int dm_kcopyd_client_create(unsigned int nr_pages,
-                           struct dm_kcopyd_client **result)
+struct dm_kcopyd_client *dm_kcopyd_client_create(void)
 {
        int r = -ENOMEM;
        struct dm_kcopyd_client *kc;
 
        kc = kmalloc(sizeof(*kc), GFP_KERNEL);
        if (!kc)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
-       spin_lock_init(&kc->lock);
        spin_lock_init(&kc->job_lock);
        INIT_LIST_HEAD(&kc->complete_jobs);
        INIT_LIST_HEAD(&kc->io_jobs);
@@ -633,12 +662,12 @@ int dm_kcopyd_client_create(unsigned int nr_pages,
                goto bad_workqueue;
 
        kc->pages = NULL;
-       kc->nr_pages = kc->nr_free_pages = 0;
-       r = client_alloc_pages(kc, nr_pages);
+       kc->nr_reserved_pages = kc->nr_free_pages = 0;
+       r = client_reserve_pages(kc, RESERVE_PAGES);
        if (r)
                goto bad_client_pages;
 
-       kc->io_client = dm_io_client_create(nr_pages);
+       kc->io_client = dm_io_client_create();
        if (IS_ERR(kc->io_client)) {
                r = PTR_ERR(kc->io_client);
                goto bad_io_client;
@@ -647,8 +676,7 @@ int dm_kcopyd_client_create(unsigned int nr_pages,
        init_waitqueue_head(&kc->destroyq);
        atomic_set(&kc->nr_jobs, 0);
 
-       *result = kc;
-       return 0;
+       return kc;
 
 bad_io_client:
        client_free_pages(kc);
@@ -659,7 +687,7 @@ bad_workqueue:
 bad_slab:
        kfree(kc);
 
-       return r;
+       return ERR_PTR(r);
 }
 EXPORT_SYMBOL(dm_kcopyd_client_create);
 
index a1f321889676d4b51eee4f08ce874e86d6449a57..948e3f4925bfe6d28a39aeed22e11324f1b1b8df 100644 (file)
@@ -449,8 +449,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
 
                lc->io_req.mem.type = DM_IO_VMA;
                lc->io_req.notify.fn = NULL;
-               lc->io_req.client = dm_io_client_create(dm_div_up(buf_size,
-                                                                  PAGE_SIZE));
+               lc->io_req.client = dm_io_client_create();
                if (IS_ERR(lc->io_req.client)) {
                        r = PTR_ERR(lc->io_req.client);
                        DMWARN("couldn't allocate disk io client");
index a550a057d991bc309b68cfa0f97481365bb1de6e..aa4e570c2cb5007cde5de16b9be07c001d980d68 100644 (file)
@@ -1290,7 +1290,7 @@ static int do_end_io(struct multipath *m, struct request *clone,
        if (!error && !clone->errors)
                return 0;       /* I/O complete */
 
-       if (error == -EOPNOTSUPP || error == -EREMOTEIO)
+       if (error == -EOPNOTSUPP || error == -EREMOTEIO || error == -EILSEQ)
                return error;
 
        if (mpio->pgpath)
index 976ad4688afc2ee03189e208663429a74f759109..9bfd057be6869dff2aba03a498b20e1c148ba4c8 100644 (file)
@@ -22,8 +22,6 @@
 #define DM_MSG_PREFIX "raid1"
 
 #define MAX_RECOVERY 1 /* Maximum number of regions recovered in parallel. */
-#define DM_IO_PAGES 64
-#define DM_KCOPYD_PAGES 64
 
 #define DM_RAID1_HANDLE_ERRORS 0x01
 #define errors_handled(p)      ((p)->features & DM_RAID1_HANDLE_ERRORS)
@@ -887,7 +885,7 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors,
                return NULL;
        }
 
-       ms->io_client = dm_io_client_create(DM_IO_PAGES);
+       ms->io_client = dm_io_client_create();
        if (IS_ERR(ms->io_client)) {
                ti->error = "Error creating dm_io client";
                mempool_destroy(ms->read_record_pool);
@@ -1117,9 +1115,11 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto err_destroy_wq;
        }
 
-       r = dm_kcopyd_client_create(DM_KCOPYD_PAGES, &ms->kcopyd_client);
-       if (r)
+       ms->kcopyd_client = dm_kcopyd_client_create();
+       if (IS_ERR(ms->kcopyd_client)) {
+               r = PTR_ERR(ms->kcopyd_client);
                goto err_destroy_wq;
+       }
 
        wakeup_mirrord(ms);
        return 0;
index 95891dfcbca021563a465751dacf064aee3a46df..135c2f1fdbfcc95aefb0d842030e71a089e87d30 100644 (file)
@@ -154,11 +154,6 @@ struct pstore {
        struct workqueue_struct *metadata_wq;
 };
 
-static unsigned sectors_to_pages(unsigned sectors)
-{
-       return DIV_ROUND_UP(sectors, PAGE_SIZE >> 9);
-}
-
 static int alloc_area(struct pstore *ps)
 {
        int r = -ENOMEM;
@@ -318,8 +313,7 @@ static int read_header(struct pstore *ps, int *new_snapshot)
                chunk_size_supplied = 0;
        }
 
-       ps->io_client = dm_io_client_create(sectors_to_pages(ps->store->
-                                                            chunk_size));
+       ps->io_client = dm_io_client_create();
        if (IS_ERR(ps->io_client))
                return PTR_ERR(ps->io_client);
 
@@ -368,11 +362,6 @@ static int read_header(struct pstore *ps, int *new_snapshot)
                return r;
        }
 
-       r = dm_io_client_resize(sectors_to_pages(ps->store->chunk_size),
-                               ps->io_client);
-       if (r)
-               return r;
-
        r = alloc_area(ps);
        return r;
 
index a2d330942cb29f824c029973ae12a98a2d39efec..9ecff5f3023a4c4f0721b958ef1541e762e910ff 100644 (file)
@@ -39,11 +39,6 @@ static const char dm_snapshot_merge_target_name[] = "snapshot-merge";
  */
 #define SNAPSHOT_COPY_PRIORITY 2
 
-/*
- * Reserve 1MB for each snapshot initially (with minimum of 1 page).
- */
-#define SNAPSHOT_PAGES (((1UL << 20) >> PAGE_SHIFT) ? : 1)
-
 /*
  * The size of the mempool used to track chunks in use.
  */
@@ -1116,8 +1111,9 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad_hash_tables;
        }
 
-       r = dm_kcopyd_client_create(SNAPSHOT_PAGES, &s->kcopyd_client);
-       if (r) {
+       s->kcopyd_client = dm_kcopyd_client_create();
+       if (IS_ERR(s->kcopyd_client)) {
+               r = PTR_ERR(s->kcopyd_client);
                ti->error = "Could not create kcopyd client";
                goto bad_kcopyd;
        }
index cb8380c9767fd3d5bb815d7fec4a46308b0270c5..451c3bb176d2953fcc8c5da8fccc42f34e83fc74 100644 (file)
@@ -362,6 +362,7 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
 static int device_area_is_invalid(struct dm_target *ti, struct dm_dev *dev,
                                  sector_t start, sector_t len, void *data)
 {
+       struct request_queue *q;
        struct queue_limits *limits = data;
        struct block_device *bdev = dev->bdev;
        sector_t dev_size =
@@ -370,6 +371,22 @@ static int device_area_is_invalid(struct dm_target *ti, struct dm_dev *dev,
                limits->logical_block_size >> SECTOR_SHIFT;
        char b[BDEVNAME_SIZE];
 
+       /*
+        * Some devices exist without request functions,
+        * such as loop devices not yet bound to backing files.
+        * Forbid the use of such devices.
+        */
+       q = bdev_get_queue(bdev);
+       if (!q || !q->make_request_fn) {
+               DMWARN("%s: %s is not yet initialised: "
+                      "start=%llu, len=%llu, dev_size=%llu",
+                      dm_device_name(ti->table->md), bdevname(bdev, b),
+                      (unsigned long long)start,
+                      (unsigned long long)len,
+                      (unsigned long long)dev_size);
+               return 1;
+       }
+
        if (!dev_size)
                return 0;
 
@@ -1346,7 +1363,8 @@ bool dm_table_supports_discards(struct dm_table *t)
                return 0;
 
        /*
-        * Ensure that at least one underlying device supports discards.
+        * Unless any target used by the table set discards_supported,
+        * require at least one underlying device to support discards.
         * t->devices includes internal dm devices such as mirror logs
         * so we need to use iterate_devices here, which targets
         * supporting discard must provide.
@@ -1354,6 +1372,9 @@ bool dm_table_supports_discards(struct dm_table *t)
        while (i < dm_table_get_num_targets(t)) {
                ti = dm_table_get_target(t, i++);
 
+               if (ti->discards_supported)
+                       return 1;
+
                if (ti->type->iterate_devices &&
                    ti->type->iterate_devices(ti, device_discard_capable, NULL))
                        return 1;
index aa640a85bb2169aa14fb8d9875beb0ac9091192c..4332fc2f25d4a2260b575f66229514bad10a2fa4 100644 (file)
@@ -351,6 +351,9 @@ void mddev_resume(mddev_t *mddev)
        mddev->suspended = 0;
        wake_up(&mddev->sb_wait);
        mddev->pers->quiesce(mddev, 0);
+
+       md_wakeup_thread(mddev->thread);
+       md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
 }
 EXPORT_SYMBOL_GPL(mddev_resume);
 
@@ -1750,6 +1753,18 @@ static struct super_type super_types[] = {
        },
 };
 
+static void sync_super(mddev_t *mddev, mdk_rdev_t *rdev)
+{
+       if (mddev->sync_super) {
+               mddev->sync_super(mddev, rdev);
+               return;
+       }
+
+       BUG_ON(mddev->major_version >= ARRAY_SIZE(super_types));
+
+       super_types[mddev->major_version].sync_super(mddev, rdev);
+}
+
 static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2)
 {
        mdk_rdev_t *rdev, *rdev2;
@@ -1781,8 +1796,8 @@ int md_integrity_register(mddev_t *mddev)
 
        if (list_empty(&mddev->disks))
                return 0; /* nothing to do */
-       if (blk_get_integrity(mddev->gendisk))
-               return 0; /* already registered */
+       if (!mddev->gendisk || blk_get_integrity(mddev->gendisk))
+               return 0; /* shouldn't register, or already is */
        list_for_each_entry(rdev, &mddev->disks, same_set) {
                /* skip spares and non-functional disks */
                if (test_bit(Faulty, &rdev->flags))
@@ -2168,8 +2183,7 @@ static void sync_sbs(mddev_t * mddev, int nospares)
                        /* Don't update this superblock */
                        rdev->sb_loaded = 2;
                } else {
-                       super_types[mddev->major_version].
-                               sync_super(mddev, rdev);
+                       sync_super(mddev, rdev);
                        rdev->sb_loaded = 1;
                }
        }
@@ -2462,7 +2476,7 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len)
                if (rdev->raid_disk == -1)
                        return -EEXIST;
                /* personality does all needed checks */
-               if (rdev->mddev->pers->hot_add_disk == NULL)
+               if (rdev->mddev->pers->hot_remove_disk == NULL)
                        return -EINVAL;
                err = rdev->mddev->pers->
                        hot_remove_disk(rdev->mddev, rdev->raid_disk);
@@ -4619,9 +4633,6 @@ int md_run(mddev_t *mddev)
        if (mddev->flags)
                md_update_sb(mddev, 0);
 
-       md_wakeup_thread(mddev->thread);
-       md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
-
        md_new_event(mddev);
        sysfs_notify_dirent_safe(mddev->sysfs_state);
        sysfs_notify_dirent_safe(mddev->sysfs_action);
@@ -4642,6 +4653,10 @@ static int do_md_run(mddev_t *mddev)
                bitmap_destroy(mddev);
                goto out;
        }
+
+       md_wakeup_thread(mddev->thread);
+       md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
+
        set_capacity(mddev->gendisk, mddev->array_sectors);
        revalidate_disk(mddev->gendisk);
        mddev->changed = 1;
@@ -5259,6 +5274,8 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
                if (mddev->degraded)
                        set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
                set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+               if (!err)
+                       md_new_event(mddev);
                md_wakeup_thread(mddev->thread);
                return err;
        }
@@ -6866,8 +6883,8 @@ void md_do_sync(mddev_t *mddev)
         * Tune reconstruction:
         */
        window = 32*(PAGE_SIZE/512);
-       printk(KERN_INFO "md: using %dk window, over a total of %llu blocks.\n",
-               window/2,(unsigned long long) max_sectors/2);
+       printk(KERN_INFO "md: using %dk window, over a total of %lluk.\n",
+               window/2, (unsigned long long)max_sectors/2);
 
        atomic_set(&mddev->recovery_active, 0);
        last_check = 0;
@@ -7045,7 +7062,6 @@ void md_do_sync(mddev_t *mddev)
 }
 EXPORT_SYMBOL_GPL(md_do_sync);
 
-
 static int remove_and_add_spares(mddev_t *mddev)
 {
        mdk_rdev_t *rdev;
@@ -7157,6 +7173,9 @@ static void reap_sync_thread(mddev_t *mddev)
  */
 void md_check_recovery(mddev_t *mddev)
 {
+       if (mddev->suspended)
+               return;
+
        if (mddev->bitmap)
                bitmap_daemon_work(mddev);
 
index 0b1fd3f1d85b5decfaaba4ab8b70595fffbaba1f..1c26c7a08ae6c053524cbee6c751c84935c5cfe3 100644 (file)
@@ -124,6 +124,7 @@ struct mddev_s
 #define MD_CHANGE_DEVS 0       /* Some device status has changed */
 #define MD_CHANGE_CLEAN 1      /* transition to or from 'clean' */
 #define MD_CHANGE_PENDING 2    /* switch from 'clean' to 'active' in progress */
+#define MD_ARRAY_FIRST_USE 3    /* First use of array, needs initialization */
 
        int                             suspended;
        atomic_t                        active_io;
@@ -330,6 +331,7 @@ struct mddev_s
        atomic_t flush_pending;
        struct work_struct flush_work;
        struct work_struct event_work;  /* used by dm to report failure event */
+       void (*sync_super)(mddev_t *mddev, mdk_rdev_t *rdev);
 };
 
 
index 5d096096f9584972a9da2197ed1bef9303edf95f..f7431b6d8447df5979c0b80a5ded841f61a16cc1 100644 (file)
@@ -497,21 +497,19 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
        return best_disk;
 }
 
-static int raid1_congested(void *data, int bits)
+int md_raid1_congested(mddev_t *mddev, int bits)
 {
-       mddev_t *mddev = data;
        conf_t *conf = mddev->private;
        int i, ret = 0;
 
-       if (mddev_congested(mddev, bits))
-               return 1;
-
        rcu_read_lock();
        for (i = 0; i < mddev->raid_disks; i++) {
                mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
                if (rdev && !test_bit(Faulty, &rdev->flags)) {
                        struct request_queue *q = bdev_get_queue(rdev->bdev);
 
+                       BUG_ON(!q);
+
                        /* Note the '|| 1' - when read_balance prefers
                         * non-congested targets, it can be removed
                         */
@@ -524,7 +522,15 @@ static int raid1_congested(void *data, int bits)
        rcu_read_unlock();
        return ret;
 }
+EXPORT_SYMBOL_GPL(md_raid1_congested);
 
+static int raid1_congested(void *data, int bits)
+{
+       mddev_t *mddev = data;
+
+       return mddev_congested(mddev, bits) ||
+               md_raid1_congested(mddev, bits);
+}
 
 static void flush_pending_writes(conf_t *conf)
 {
@@ -1972,6 +1978,8 @@ static int run(mddev_t *mddev)
                return PTR_ERR(conf);
 
        list_for_each_entry(rdev, &mddev->disks, same_set) {
+               if (!mddev->gendisk)
+                       continue;
                disk_stack_limits(mddev->gendisk, rdev->bdev,
                                  rdev->data_offset << 9);
                /* as we don't honour merge_bvec_fn, we must never risk
@@ -2013,8 +2021,10 @@ static int run(mddev_t *mddev)
 
        md_set_array_sectors(mddev, raid1_size(mddev, 0, 0));
 
-       mddev->queue->backing_dev_info.congested_fn = raid1_congested;
-       mddev->queue->backing_dev_info.congested_data = mddev;
+       if (mddev->queue) {
+               mddev->queue->backing_dev_info.congested_fn = raid1_congested;
+               mddev->queue->backing_dev_info.congested_data = mddev;
+       }
        return md_integrity_register(mddev);
 }
 
index 5fc4ca1af8639b5a61a6a17901866fe0987effcc..e743a64fac4f10f2dbc27f2c194658fdd35f3fa7 100644 (file)
@@ -126,4 +126,6 @@ struct r1bio_s {
  */
 #define        R1BIO_Returned 6
 
+extern int md_raid1_congested(mddev_t *mddev, int bits);
+
 #endif
index 346e69bfdab3f8b0b744f6b239c93ea0f3f099e2..b72edf35ec544d0da66346107cededa933ed20dc 100644 (file)
@@ -129,7 +129,7 @@ static inline int raid5_dec_bi_hw_segments(struct bio *bio)
 
 static inline void raid5_set_bi_hw_segments(struct bio *bio, unsigned int cnt)
 {
-       bio->bi_phys_segments = raid5_bi_phys_segments(bio) || (cnt << 16);
+       bio->bi_phys_segments = raid5_bi_phys_segments(bio) | (cnt << 16);
 }
 
 /* Find first data disk in a raid6 stripe */
@@ -514,7 +514,7 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
                bi = &sh->dev[i].req;
 
                bi->bi_rw = rw;
-               if (rw == WRITE)
+               if (rw & WRITE)
                        bi->bi_end_io = raid5_end_write_request;
                else
                        bi->bi_end_io = raid5_end_read_request;
@@ -548,13 +548,13 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
                        bi->bi_io_vec[0].bv_offset = 0;
                        bi->bi_size = STRIPE_SIZE;
                        bi->bi_next = NULL;
-                       if (rw == WRITE &&
+                       if ((rw & WRITE) &&
                            test_bit(R5_ReWrite, &sh->dev[i].flags))
                                atomic_add(STRIPE_SECTORS,
                                        &rdev->corrected_errors);
                        generic_make_request(bi);
                } else {
-                       if (rw == WRITE)
+                       if (rw & WRITE)
                                set_bit(STRIPE_DEGRADED, &sh->state);
                        pr_debug("skip op %ld on disc %d for sector %llu\n",
                                bi->bi_rw, i, (unsigned long long)sh->sector);
@@ -585,7 +585,7 @@ async_copy_data(int frombio, struct bio *bio, struct page *page,
        init_async_submit(&submit, flags, tx, NULL, NULL, NULL);
 
        bio_for_each_segment(bvl, bio, i) {
-               int len = bio_iovec_idx(bio, i)->bv_len;
+               int len = bvl->bv_len;
                int clen;
                int b_offset = 0;
 
@@ -601,8 +601,8 @@ async_copy_data(int frombio, struct bio *bio, struct page *page,
                        clen = len;
 
                if (clen > 0) {
-                       b_offset += bio_iovec_idx(bio, i)->bv_offset;
-                       bio_page = bio_iovec_idx(bio, i)->bv_page;
+                       b_offset += bvl->bv_offset;
+                       bio_page = bvl->bv_page;
                        if (frombio)
                                tx = async_memcpy(page, bio_page, page_offset,
                                                  b_offset, clen, &submit);
@@ -4858,7 +4858,7 @@ static raid5_conf_t *setup_conf(mddev_t *mddev)
                        printk(KERN_INFO "md/raid:%s: device %s operational as raid"
                               " disk %d\n",
                               mdname(mddev), bdevname(rdev->bdev, b), raid_disk);
-               } else
+               } else if (rdev->saved_raid_disk != raid_disk)
                        /* Cannot rely on bitmap to complete recovery */
                        conf->fullsync = 1;
        }
index 2d8b4044be36b0ab0436f9f9dde08b487763f90b..b2b0c45f32a91892ee08f778317c12b91b17cf52 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 
 #define UNSET (-1U)
 
-#define DM1105_BOARD_NOAUTO            UNSET
-#define DM1105_BOARD_UNKNOWN           0
-#define DM1105_BOARD_DVBWORLD_2002     1
-#define DM1105_BOARD_DVBWORLD_2004     2
-#define DM1105_BOARD_AXESS_DM05                3
+#define DM1105_BOARD_NOAUTO                    UNSET
+#define DM1105_BOARD_UNKNOWN                   0
+#define DM1105_BOARD_DVBWORLD_2002             1
+#define DM1105_BOARD_DVBWORLD_2004             2
+#define DM1105_BOARD_AXESS_DM05                        3
+#define DM1105_BOARD_UNBRANDED_I2C_ON_GPIO     4
 
 /* ----------------------------------------------- */
 /*
 #define DM1105_MAX                             0x04
 
 #define DRIVER_NAME                            "dm1105"
+#define DM1105_I2C_GPIO_NAME                   "dm1105-gpio"
 
 #define DM1105_DMA_PACKETS                     47
 #define DM1105_DMA_PACKET_LENGTH               (128*4)
 #define DM1105_DMA_BYTES                       (128 * 4 * DM1105_DMA_PACKETS)
 
+/*  */
+#define GPIO08                                 (1 << 8)
+#define GPIO13                                 (1 << 13)
+#define GPIO14                                 (1 << 14)
+#define GPIO15                                 (1 << 15)
+#define GPIO16                                 (1 << 16)
+#define GPIO17                                 (1 << 17)
+#define GPIO_ALL                               0x03ffff
+
 /* GPIO's for LNB power control */
-#define DM1105_LNB_MASK                                0x00000000
-#define DM1105_LNB_OFF                         0x00020000
-#define DM1105_LNB_13V                         0x00010100
-#define DM1105_LNB_18V                         0x00000100
+#define DM1105_LNB_MASK                                (GPIO_ALL & ~(GPIO14 | GPIO13))
+#define DM1105_LNB_OFF                         GPIO17
+#define DM1105_LNB_13V                         (GPIO16 | GPIO08)
+#define DM1105_LNB_18V                         GPIO08
 
 /* GPIO's for LNB power control for Axess DM05 */
-#define DM05_LNB_MASK                          0x00000000
-#define DM05_LNB_OFF                           0x00020000/* actually 13v */
-#define DM05_LNB_13V                           0x00020000
-#define DM05_LNB_18V                           0x00030000
+#define DM05_LNB_MASK                          (GPIO_ALL & ~(GPIO14 | GPIO13))
+#define DM05_LNB_OFF                           GPIO17/* actually 13v */
+#define DM05_LNB_13V                           GPIO17
+#define DM05_LNB_18V                           (GPIO17 | GPIO16)
+
+/* GPIO's for LNB power control for unbranded with I2C on GPIO */
+#define UNBR_LNB_MASK                          (GPIO17 | GPIO16)
+#define UNBR_LNB_OFF                           0
+#define UNBR_LNB_13V                           GPIO17
+#define UNBR_LNB_18V                           (GPIO17 | GPIO16)
 
 static unsigned int card[]  = {[0 ... 3] = UNSET };
 module_param_array(card,  int, NULL, 0444);
@@ -187,7 +205,11 @@ static unsigned int dm1105_devcount;
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 struct dm1105_board {
-       char                    *name;
+       char    *name;
+       struct  {
+               u32     mask, off, v13, v18;
+       } lnb;
+       u32     gpio_scl, gpio_sda;
 };
 
 struct dm1105_subid {
@@ -199,15 +221,50 @@ struct dm1105_subid {
 static const struct dm1105_board dm1105_boards[] = {
        [DM1105_BOARD_UNKNOWN] = {
                .name           = "UNKNOWN/GENERIC",
+               .lnb = {
+                       .mask = DM1105_LNB_MASK,
+                       .off = DM1105_LNB_OFF,
+                       .v13 = DM1105_LNB_13V,
+                       .v18 = DM1105_LNB_18V,
+               },
        },
        [DM1105_BOARD_DVBWORLD_2002] = {
                .name           = "DVBWorld PCI 2002",
+               .lnb = {
+                       .mask = DM1105_LNB_MASK,
+                       .off = DM1105_LNB_OFF,
+                       .v13 = DM1105_LNB_13V,
+                       .v18 = DM1105_LNB_18V,
+               },
        },
        [DM1105_BOARD_DVBWORLD_2004] = {
                .name           = "DVBWorld PCI 2004",
+               .lnb = {
+                       .mask = DM1105_LNB_MASK,
+                       .off = DM1105_LNB_OFF,
+                       .v13 = DM1105_LNB_13V,
+                       .v18 = DM1105_LNB_18V,
+               },
        },
        [DM1105_BOARD_AXESS_DM05] = {
                .name           = "Axess/EasyTv DM05",
+               .lnb = {
+                       .mask = DM05_LNB_MASK,
+                       .off = DM05_LNB_OFF,
+                       .v13 = DM05_LNB_13V,
+                       .v18 = DM05_LNB_18V,
+               },
+       },
+       [DM1105_BOARD_UNBRANDED_I2C_ON_GPIO] = {
+               .name           = "Unbranded DM1105 with i2c on GPIOs",
+               .lnb = {
+                       .mask = UNBR_LNB_MASK,
+                       .off = UNBR_LNB_OFF,
+                       .v13 = UNBR_LNB_13V,
+                       .v18 = UNBR_LNB_18V,
+               },
+               .gpio_scl       = GPIO14,
+               .gpio_sda       = GPIO13,
        },
 };
 
@@ -293,6 +350,8 @@ struct dm1105_dev {
 
        /* i2c */
        struct i2c_adapter i2c_adap;
+       struct i2c_adapter i2c_bb_adap;
+       struct i2c_algo_bit_data i2c_bit;
 
        /* irq */
        struct work_struct work;
@@ -328,6 +387,103 @@ struct dm1105_dev {
 #define dm_setl(reg, bit)      dm_andorl((reg), (bit), (bit))
 #define dm_clearl(reg, bit)    dm_andorl((reg), (bit), 0)
 
+/* The chip has 18 GPIOs. In HOST mode GPIO's used as 15 bit address lines,
+ so we can use only 3 GPIO's from GPIO15 to GPIO17.
+ Here I don't check whether HOST is enebled as it is not implemented yet.
+ */
+static void dm1105_gpio_set(struct dm1105_dev *dev, u32 mask)
+{
+       if (mask & 0xfffc0000)
+               printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
+
+       if (mask & 0x0003ffff)
+               dm_setl(DM1105_GPIOVAL, mask & 0x0003ffff);
+
+}
+
+static void dm1105_gpio_clear(struct dm1105_dev *dev, u32 mask)
+{
+       if (mask & 0xfffc0000)
+               printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
+
+       if (mask & 0x0003ffff)
+               dm_clearl(DM1105_GPIOVAL, mask & 0x0003ffff);
+
+}
+
+static void dm1105_gpio_andor(struct dm1105_dev *dev, u32 mask, u32 val)
+{
+       if (mask & 0xfffc0000)
+               printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
+
+       if (mask & 0x0003ffff)
+               dm_andorl(DM1105_GPIOVAL, mask & 0x0003ffff, val);
+
+}
+
+static u32 dm1105_gpio_get(struct dm1105_dev *dev, u32 mask)
+{
+       if (mask & 0xfffc0000)
+               printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
+
+       if (mask & 0x0003ffff)
+               return dm_readl(DM1105_GPIOVAL) & mask & 0x0003ffff;
+
+       return 0;
+}
+
+static void dm1105_gpio_enable(struct dm1105_dev *dev, u32 mask, int asoutput)
+{
+       if (mask & 0xfffc0000)
+               printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
+
+       if ((mask & 0x0003ffff) && asoutput)
+               dm_clearl(DM1105_GPIOCTR, mask & 0x0003ffff);
+       else if ((mask & 0x0003ffff) && !asoutput)
+               dm_setl(DM1105_GPIOCTR, mask & 0x0003ffff);
+
+}
+
+static void dm1105_setline(struct dm1105_dev *dev, u32 line, int state)
+{
+       if (state)
+               dm1105_gpio_enable(dev, line, 0);
+       else {
+               dm1105_gpio_enable(dev, line, 1);
+               dm1105_gpio_clear(dev, line);
+       }
+}
+
+static void dm1105_setsda(void *data, int state)
+{
+       struct dm1105_dev *dev = data;
+
+       dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_sda, state);
+}
+
+static void dm1105_setscl(void *data, int state)
+{
+       struct dm1105_dev *dev = data;
+
+       dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_scl, state);
+}
+
+static int dm1105_getsda(void *data)
+{
+       struct dm1105_dev *dev = data;
+
+       return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_sda)
+                                                                       ? 1 : 0;
+}
+
+static int dm1105_getscl(void *data)
+{
+       struct dm1105_dev *dev = data;
+
+       return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_scl)
+                                                                       ? 1 : 0;
+}
+
 static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
                            struct i2c_msg *msgs, int num)
 {
@@ -436,31 +592,20 @@ static inline struct dm1105_dev *frontend_to_dm1105_dev(struct dvb_frontend *fe)
 static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
        struct dm1105_dev *dev = frontend_to_dm1105_dev(fe);
-       u32 lnb_mask, lnb_13v, lnb_18v, lnb_off;
 
-       switch (dev->boardnr) {
-       case DM1105_BOARD_AXESS_DM05:
-               lnb_mask = DM05_LNB_MASK;
-               lnb_off = DM05_LNB_OFF;
-               lnb_13v = DM05_LNB_13V;
-               lnb_18v = DM05_LNB_18V;
-               break;
-       case DM1105_BOARD_DVBWORLD_2002:
-       case DM1105_BOARD_DVBWORLD_2004:
-       default:
-               lnb_mask = DM1105_LNB_MASK;
-               lnb_off = DM1105_LNB_OFF;
-               lnb_13v = DM1105_LNB_13V;
-               lnb_18v = DM1105_LNB_18V;
-       }
-
-       dm_writel(DM1105_GPIOCTR, lnb_mask);
+       dm1105_gpio_enable(dev, dm1105_boards[dev->boardnr].lnb.mask, 1);
        if (voltage == SEC_VOLTAGE_18)
-               dm_writel(DM1105_GPIOVAL, lnb_18v);
+               dm1105_gpio_andor(dev,
+                               dm1105_boards[dev->boardnr].lnb.mask,
+                               dm1105_boards[dev->boardnr].lnb.v18);
        else if (voltage == SEC_VOLTAGE_13)
-               dm_writel(DM1105_GPIOVAL, lnb_13v);
+               dm1105_gpio_andor(dev,
+                               dm1105_boards[dev->boardnr].lnb.mask,
+                               dm1105_boards[dev->boardnr].lnb.v13);
        else
-               dm_writel(DM1105_GPIOVAL, lnb_off);
+               dm1105_gpio_andor(dev,
+                               dm1105_boards[dev->boardnr].lnb.mask,
+                               dm1105_boards[dev->boardnr].lnb.off);
 
        return 0;
 }
@@ -708,6 +853,38 @@ static int __devinit frontend_init(struct dm1105_dev *dev)
        int ret;
 
        switch (dev->boardnr) {
+       case DM1105_BOARD_UNBRANDED_I2C_ON_GPIO:
+               dm1105_gpio_enable(dev, GPIO15, 1);
+               dm1105_gpio_clear(dev, GPIO15);
+               msleep(100);
+               dm1105_gpio_set(dev, GPIO15);
+               msleep(200);
+               dev->fe = dvb_attach(
+                       stv0299_attach, &sharp_z0194a_config,
+                       &dev->i2c_bb_adap);
+               if (dev->fe) {
+                       dev->fe->ops.set_voltage = dm1105_set_voltage;
+                       dvb_attach(dvb_pll_attach, dev->fe, 0x60,
+                                       &dev->i2c_bb_adap, DVB_PLL_OPERA1);
+                       break;
+               }
+
+               dev->fe = dvb_attach(
+                       stv0288_attach, &earda_config,
+                       &dev->i2c_bb_adap);
+               if (dev->fe) {
+                       dev->fe->ops.set_voltage = dm1105_set_voltage;
+                       dvb_attach(stb6000_attach, dev->fe, 0x61,
+                                       &dev->i2c_bb_adap);
+                       break;
+               }
+
+               dev->fe = dvb_attach(
+                       si21xx_attach, &serit_config,
+                       &dev->i2c_bb_adap);
+               if (dev->fe)
+                       dev->fe->ops.set_voltage = dm1105_set_voltage;
+               break;
        case DM1105_BOARD_DVBWORLD_2004:
                dev->fe = dvb_attach(
                        cx24116_attach, &serit_sp2633_config,
@@ -870,11 +1047,32 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
        if (ret < 0)
                goto err_dm1105_hw_exit;
 
+       i2c_set_adapdata(&dev->i2c_bb_adap, dev);
+       strcpy(dev->i2c_bb_adap.name, DM1105_I2C_GPIO_NAME);
+       dev->i2c_bb_adap.owner = THIS_MODULE;
+       dev->i2c_bb_adap.dev.parent = &pdev->dev;
+       dev->i2c_bb_adap.algo_data = &dev->i2c_bit;
+       dev->i2c_bit.data = dev;
+       dev->i2c_bit.setsda = dm1105_setsda;
+       dev->i2c_bit.setscl = dm1105_setscl;
+       dev->i2c_bit.getsda = dm1105_getsda;
+       dev->i2c_bit.getscl = dm1105_getscl;
+       dev->i2c_bit.udelay = 10;
+       dev->i2c_bit.timeout = 10;
+
+       /* Raise SCL and SDA */
+       dm1105_setsda(dev, 1);
+       dm1105_setscl(dev, 1);
+
+       ret = i2c_bit_add_bus(&dev->i2c_bb_adap);
+       if (ret < 0)
+               goto err_i2c_del_adapter;
+
        /* dvb */
        ret = dvb_register_adapter(&dev->dvb_adapter, DRIVER_NAME,
                                        THIS_MODULE, &pdev->dev, adapter_nr);
        if (ret < 0)
-               goto err_i2c_del_adapter;
+               goto err_i2c_del_adapters;
 
        dvb_adapter = &dev->dvb_adapter;
 
@@ -952,6 +1150,8 @@ err_dvb_dmx_release:
        dvb_dmx_release(dvbdemux);
 err_dvb_unregister_adapter:
        dvb_unregister_adapter(dvb_adapter);
+err_i2c_del_adapters:
+       i2c_del_adapter(&dev->i2c_bb_adap);
 err_i2c_del_adapter:
        i2c_del_adapter(&dev->i2c_adap);
 err_dm1105_hw_exit:
index 4dc1ca3332363e7569f34e08a034f13186f677fd..7c327b54308e30312848d7b9c4c289f28fe2d937 100644 (file)
@@ -60,8 +60,6 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
        int act_len, ret;
        u8 buf[64];
 
-       if (slen > sizeof(buf))
-               slen = sizeof(buf);
        memcpy(&buf[0], sbuf, slen);
        buf[60] = state->seq++;
 
@@ -180,30 +178,37 @@ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
        int ret = 0, inc, i = 0;
+       u8 buf[52]; /* 4 + 48 (I2C WR USB command header + I2C WR max) */
 
        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
                return -EAGAIN;
 
        while (i < num) {
                if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
-                       u8 buf[6];
+                       if (msg[i].len > 2 || msg[i+1].len > 60) {
+                               ret = -EOPNOTSUPP;
+                               break;
+                       }
                        buf[0] = CMD_I2C_READ;
                        buf[1] = (msg[i].addr << 1) | 0x01;
                        buf[2] = msg[i].buf[0];
                        buf[3] = msg[i].buf[1];
                        buf[4] = msg[i].len-1;
                        buf[5] = msg[i+1].len;
-                       ret = anysee_ctrl_msg(d, buf, sizeof(buf), msg[i+1].buf,
+                       ret = anysee_ctrl_msg(d, buf, 6, msg[i+1].buf,
                                msg[i+1].len);
                        inc = 2;
                } else {
-                       u8 buf[4+msg[i].len];
+                       if (msg[i].len > 48) {
+                               ret = -EOPNOTSUPP;
+                               break;
+                       }
                        buf[0] = CMD_I2C_WRITE;
                        buf[1] = (msg[i].addr << 1);
                        buf[2] = msg[i].len;
                        buf[3] = 0x01;
                        memcpy(&buf[4], msg[i].buf, msg[i].len);
-                       ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+                       ret = anysee_ctrl_msg(d, buf, 4 + msg[i].len, NULL, 0);
                        inc = 1;
                }
                if (ret)
index f36f471deae26e0327299e2469d662e938b1caa9..37b146961ae2d00d185e5b7c992096e66531a2f0 100644 (file)
@@ -207,17 +207,6 @@ static int lme2510_stream_restart(struct dvb_usb_device *d)
                        rbuff, sizeof(rbuff));
        return ret;
 }
-static int lme2510_remote_keypress(struct dvb_usb_adapter *adap, u32 keypress)
-{
-       struct dvb_usb_device *d = adap->dev;
-
-       deb_info(1, "INT Key Keypress =%04x", keypress);
-
-       if (keypress > 0)
-               rc_keydown(d->rc_dev, keypress, 0);
-
-       return 0;
-}
 
 static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out)
 {
@@ -256,6 +245,7 @@ static void lme2510_int_response(struct urb *lme_urb)
        struct lme2510_state *st = adap->dev->priv;
        static u8 *ibuf, *rbuf;
        int i = 0, offset;
+       u32 key;
 
        switch (lme_urb->status) {
        case 0:
@@ -282,10 +272,16 @@ static void lme2510_int_response(struct urb *lme_urb)
 
                switch (ibuf[0]) {
                case 0xaa:
-                       debug_data_snipet(1, "INT Remote data snipet in", ibuf);
-                       lme2510_remote_keypress(adap,
-                               (u32)(ibuf[2] << 24) + (ibuf[3] << 16) +
-                               (ibuf[4] << 8) + ibuf[5]);
+                       debug_data_snipet(1, "INT Remote data snipet", ibuf);
+                       if ((ibuf[4] + ibuf[5]) == 0xff) {
+                               key = ibuf[5];
+                               key += (ibuf[3] > 0)
+                                       ? (ibuf[3] ^ 0xff) << 8 : 0;
+                               key += (ibuf[2] ^ 0xff) << 16;
+                               deb_info(1, "INT Key =%08x", key);
+                               if (adap->dev->rc_dev != NULL)
+                                       rc_keydown(adap->dev->rc_dev, key, 0);
+                       }
                        break;
                case 0xbb:
                        switch (st->tuner_config) {
@@ -691,45 +687,6 @@ static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
        return (ret < 0) ? -ENODEV : 0;
 }
 
-static int lme2510_int_service(struct dvb_usb_adapter *adap)
-{
-       struct dvb_usb_device *d = adap->dev;
-       struct rc_dev *rc;
-       int ret;
-
-       info("STA Configuring Remote");
-
-       rc = rc_allocate_device();
-       if (!rc)
-               return -ENOMEM;
-
-       usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
-       strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
-
-       rc->input_name = "LME2510 Remote Control";
-       rc->input_phys = d->rc_phys;
-       rc->map_name = RC_MAP_LME2510;
-       rc->driver_name = "LME 2510";
-       usb_to_input_id(d->udev, &rc->input_id);
-
-       ret = rc_register_device(rc);
-       if (ret) {
-               rc_free_device(rc);
-               return ret;
-       }
-       d->rc_dev = rc;
-
-       /* Start the Interrupt */
-       ret = lme2510_int_read(adap);
-       if (ret < 0) {
-               rc_unregister_device(rc);
-               info("INT Unable to start Interrupt Service");
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
 static u8 check_sum(u8 *p, u8 len)
 {
        u8 sum = 0;
@@ -831,7 +788,7 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
 
        cold_fw = !cold;
 
-       if (udev->descriptor.idProduct == 0x1122) {
+       if (le16_to_cpu(udev->descriptor.idProduct) == 0x1122) {
                switch (dvb_usb_lme2510_firmware) {
                default:
                        dvb_usb_lme2510_firmware = TUNER_S0194;
@@ -1053,8 +1010,11 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
 
 
 end:   if (ret) {
-               kfree(adap->fe);
-               adap->fe = NULL;
+               if (adap->fe) {
+                       dvb_frontend_detach(adap->fe);
+                       adap->fe = NULL;
+               }
+               adap->dev->props.rc.core.rc_codes = NULL;
                return -ENODEV;
        }
 
@@ -1097,8 +1057,12 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
                return -ENODEV;
        }
 
-       /* Start the Interrupt & Remote*/
-       ret = lme2510_int_service(adap);
+       /* Start the Interrupt*/
+       ret = lme2510_int_read(adap);
+       if (ret < 0) {
+               info("INT Unable to start Interrupt Service");
+               return -ENODEV;
+       }
 
        return ret;
 }
@@ -1204,6 +1168,12 @@ static struct dvb_usb_device_properties lme2510_properties = {
                        }
                }
        },
+       .rc.core = {
+               .protocol       = RC_TYPE_NEC,
+               .module_name    = "LME2510 Remote Control",
+               .allowed_protos = RC_TYPE_NEC,
+               .rc_codes       = RC_MAP_LME2510,
+       },
        .power_ctrl       = lme2510_powerup,
        .identify_state   = lme2510_identify_state,
        .i2c_algo         = &lme2510_i2c_algo,
@@ -1246,6 +1216,12 @@ static struct dvb_usb_device_properties lme2510c_properties = {
                        }
                }
        },
+       .rc.core = {
+               .protocol       = RC_TYPE_NEC,
+               .module_name    = "LME2510 Remote Control",
+               .allowed_protos = RC_TYPE_NEC,
+               .rc_codes       = RC_MAP_LME2510,
+       },
        .power_ctrl       = lme2510_powerup,
        .identify_state   = lme2510_identify_state,
        .i2c_algo         = &lme2510_i2c_algo,
@@ -1269,19 +1245,21 @@ static void *lme2510_exit_int(struct dvb_usb_device *d)
                adap->feedcount = 0;
        }
 
-       if (st->lme_urb != NULL) {
+       if (st->usb_buffer != NULL) {
                st->i2c_talk_onoff = 1;
                st->signal_lock = 0;
                st->signal_level = 0;
                st->signal_sn = 0;
                buffer = st->usb_buffer;
+       }
+
+       if (st->lme_urb != NULL) {
                usb_kill_urb(st->lme_urb);
                usb_free_coherent(d->udev, 5000, st->buffer,
                                  st->lme_urb->transfer_dma);
                info("Interrupt Service Stopped");
-               rc_unregister_device(d->rc_dev);
-               info("Remote Stopped");
        }
+
        return buffer;
 }
 
@@ -1293,7 +1271,8 @@ static void lme2510_exit(struct usb_interface *intf)
        if (d != NULL) {
                usb_buffer = lme2510_exit_int(d);
                dvb_usb_device_exit(intf);
-               kfree(usb_buffer);
+               if (usb_buffer != NULL)
+                       kfree(usb_buffer);
        }
 }
 
@@ -1327,5 +1306,5 @@ module_exit(lme2510_module_exit);
 
 MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
 MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
-MODULE_VERSION("1.86");
+MODULE_VERSION("1.88");
 MODULE_LICENSE("GPL");
index 2da55ec2039259d4e05e6154502e4e9068af487a..d70eee00f33a5d33fbefef13860f20ba15c020c4 100644 (file)
@@ -23,7 +23,7 @@
 #include "stb0899_priv.h"
 #include "stb0899_reg.h"
 
-inline u32 stb0899_do_div(u64 n, u32 d)
+static inline u32 stb0899_do_div(u64 n, u32 d)
 {
        /* wrap do_div() for ease of use */
 
index 1742056a34e8c0a8270aee6a81a8ecba4917fc9e..53c7d8f1df289a373a3b96a143f87841f6fd0d43 100644 (file)
@@ -224,7 +224,6 @@ exit:
 }
 
 EXPORT_SYMBOL(tda8261_attach);
-MODULE_PARM_DESC(verbose, "Set verbosity level");
 
 MODULE_AUTHOR("Manu Abraham");
 MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner");
index af5263c6625adeafab44bfa5cdff167122ff52d5..7b42ace419d9378c32407650044b2daa69adc0a6 100644 (file)
@@ -213,14 +213,14 @@ int __must_check media_devnode_register(struct media_devnode *mdev)
 
        /* Part 1: Find a free minor number */
        mutex_lock(&media_devnode_lock);
-       minor = find_next_zero_bit(media_devnode_nums, 0, MEDIA_NUM_DEVICES);
+       minor = find_next_zero_bit(media_devnode_nums, MEDIA_NUM_DEVICES, 0);
        if (minor == MEDIA_NUM_DEVICES) {
                mutex_unlock(&media_devnode_lock);
                printk(KERN_ERR "could not get a free minor\n");
                return -ENFILE;
        }
 
-       set_bit(mdev->minor, media_devnode_nums);
+       set_bit(minor, media_devnode_nums);
        mutex_unlock(&media_devnode_lock);
 
        mdev->minor = minor;
index 5c2a9058c09fd6966d4c47c8c44b8fd681e8d9a6..e83e84003025222f4a74d95024fa5df80f658ca8 100644 (file)
@@ -412,8 +412,7 @@ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_d
                goto err_out_free_region;
        }
 
-       v4l2_info(v4l2_dev, "version " DRIVER_VERSION
-                       " time " __TIME__ "  " __DATE__ "\n");
+       v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n");
 
        v4l2_info(v4l2_dev, "found Guillemot MAXI Radio device (io = 0x%x)\n",
               dev->io);
index 1e3a8dd820a4382a26272ff4557024e64adc619d..a185610b376be1a14e79b52751c7f95aab777dd0 100644 (file)
@@ -21,7 +21,6 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
@@ -149,7 +148,7 @@ static const struct v4l2_file_operations timbradio_fops = {
 
 static int __devinit timbradio_probe(struct platform_device *pdev)
 {
-       struct timb_radio_platform_data *pdata = mfd_get_data(pdev);
+       struct timb_radio_platform_data *pdata = pdev->dev.platform_data;
        struct timbradio *tr;
        int err;
 
index e2550dc2944f939812805d2c23778c86df2ff7e0..459f7272d32634d67143ee679a5375fc85f37f99 100644 (file)
@@ -1382,7 +1382,7 @@ static int wl1273_fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 
        switch (ctrl->id) {
        case  V4L2_CID_TUNE_ANTENNA_CAPACITOR:
-               ctrl->val = wl1273_fm_get_tx_ctune(radio);
+               ctrl->cur.val = wl1273_fm_get_tx_ctune(radio);
                break;
 
        default:
@@ -1990,7 +1990,7 @@ static int wl1273_fm_radio_remove(struct platform_device *pdev)
 
 static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
 {
-       struct wl1273_core **core = mfd_get_data(pdev);
+       struct wl1273_core **core = pdev->dev.platform_data;
        struct wl1273_device *radio;
        struct v4l2_ctrl *ctrl;
        int r = 0;
index d50e5ac75ab68659743be2005473db6789e89192..87010724f9147b53170dc59f1e603115ae2fd72c 100644 (file)
@@ -191,7 +191,7 @@ static int fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 
        switch (ctrl->id) {
        case  V4L2_CID_TUNE_ANTENNA_CAPACITOR:
-               ctrl->val = fm_tx_get_tune_cap_val(fmdev);
+               ctrl->cur.val = fm_tx_get_tune_cap_val(fmdev);
                break;
        default:
                fmwarn("%s: Unknown IOCTL: %d\n", __func__, ctrl->id);
index 154c337f00fda10182e30222c37533596d1b40e5..7d4bbc226d068dd263a18b9ee69c70793245669f 100644 (file)
@@ -148,6 +148,18 @@ config IR_ITE_CIR
           To compile this driver as a module, choose M here: the
           module will be called ite-cir.
 
+config IR_FINTEK
+       tristate "Fintek Consumer Infrared Transceiver"
+       depends on PNP
+       depends on RC_CORE
+       ---help---
+          Say Y here to enable support for integrated infrared receiver
+          /transciever made by Fintek. This chip is found on assorted
+          Jetway motherboards (and of course, possibly others).
+
+          To compile this driver as a module, choose M here: the
+          module will be called fintek-cir.
+
 config IR_NUVOTON
        tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
        depends on PNP
index 1f90a219a1627f98d13de3095844bd9f733d87d4..52830e5f4eaaa4ee184fc20ff0ece6e3f3809ace 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
 obj-$(CONFIG_IR_IMON) += imon.o
 obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o
 obj-$(CONFIG_IR_MCEUSB) += mceusb.o
+obj-$(CONFIG_IR_FINTEK) += fintek-cir.o
 obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
 obj-$(CONFIG_IR_ENE) += ene_ir.o
 obj-$(CONFIG_IR_REDRAT3) += redrat3.o
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
new file mode 100644 (file)
index 0000000..8fa539d
--- /dev/null
@@ -0,0 +1,684 @@
+/*
+ * Driver for Feature Integration Technology Inc. (aka Fintek) LPC CIR
+ *
+ * Copyright (C) 2011 Jarod Wilson <jarod@redhat.com>
+ *
+ * Special thanks to Fintek for providing hardware and spec sheets.
+ * This driver is based upon the nuvoton, ite and ene drivers for
+ * similar hardware.
+ *
+ * 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/pnp.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <media/rc-core.h>
+#include <linux/pci_ids.h>
+
+#include "fintek-cir.h"
+
+/* write val to config reg */
+static inline void fintek_cr_write(struct fintek_dev *fintek, u8 val, u8 reg)
+{
+       fit_dbg("%s: reg 0x%02x, val 0x%02x  (ip/dp: %02x/%02x)",
+               __func__, reg, val, fintek->cr_ip, fintek->cr_dp);
+       outb(reg, fintek->cr_ip);
+       outb(val, fintek->cr_dp);
+}
+
+/* read val from config reg */
+static inline u8 fintek_cr_read(struct fintek_dev *fintek, u8 reg)
+{
+       u8 val;
+
+       outb(reg, fintek->cr_ip);
+       val = inb(fintek->cr_dp);
+
+       fit_dbg("%s: reg 0x%02x, val 0x%02x  (ip/dp: %02x/%02x)",
+               __func__, reg, val, fintek->cr_ip, fintek->cr_dp);
+       return val;
+}
+
+/* update config register bit without changing other bits */
+static inline void fintek_set_reg_bit(struct fintek_dev *fintek, u8 val, u8 reg)
+{
+       u8 tmp = fintek_cr_read(fintek, reg) | val;
+       fintek_cr_write(fintek, tmp, reg);
+}
+
+/* clear config register bit without changing other bits */
+static inline void fintek_clear_reg_bit(struct fintek_dev *fintek, u8 val, u8 reg)
+{
+       u8 tmp = fintek_cr_read(fintek, reg) & ~val;
+       fintek_cr_write(fintek, tmp, reg);
+}
+
+/* enter config mode */
+static inline void fintek_config_mode_enable(struct fintek_dev *fintek)
+{
+       /* Enabling Config Mode explicitly requires writing 2x */
+       outb(CONFIG_REG_ENABLE, fintek->cr_ip);
+       outb(CONFIG_REG_ENABLE, fintek->cr_ip);
+}
+
+/* exit config mode */
+static inline void fintek_config_mode_disable(struct fintek_dev *fintek)
+{
+       outb(CONFIG_REG_DISABLE, fintek->cr_ip);
+}
+
+/*
+ * When you want to address a specific logical device, write its logical
+ * device number to GCR_LOGICAL_DEV_NO
+ */
+static inline void fintek_select_logical_dev(struct fintek_dev *fintek, u8 ldev)
+{
+       fintek_cr_write(fintek, ldev, GCR_LOGICAL_DEV_NO);
+}
+
+/* write val to cir config register */
+static inline void fintek_cir_reg_write(struct fintek_dev *fintek, u8 val, u8 offset)
+{
+       outb(val, fintek->cir_addr + offset);
+}
+
+/* read val from cir config register */
+static u8 fintek_cir_reg_read(struct fintek_dev *fintek, u8 offset)
+{
+       u8 val;
+
+       val = inb(fintek->cir_addr + offset);
+
+       return val;
+}
+
+#define pr_reg(text, ...) \
+       printk(KERN_INFO KBUILD_MODNAME ": " text, ## __VA_ARGS__)
+
+/* dump current cir register contents */
+static void cir_dump_regs(struct fintek_dev *fintek)
+{
+       fintek_config_mode_enable(fintek);
+       fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+
+       pr_reg("%s: Dump CIR logical device registers:\n", FINTEK_DRIVER_NAME);
+       pr_reg(" * CR CIR BASE ADDR: 0x%x\n",
+              (fintek_cr_read(fintek, CIR_CR_BASE_ADDR_HI) << 8) |
+               fintek_cr_read(fintek, CIR_CR_BASE_ADDR_LO));
+       pr_reg(" * CR CIR IRQ NUM:   0x%x\n",
+              fintek_cr_read(fintek, CIR_CR_IRQ_SEL));
+
+       fintek_config_mode_disable(fintek);
+
+       pr_reg("%s: Dump CIR registers:\n", FINTEK_DRIVER_NAME);
+       pr_reg(" * STATUS:     0x%x\n", fintek_cir_reg_read(fintek, CIR_STATUS));
+       pr_reg(" * CONTROL:    0x%x\n", fintek_cir_reg_read(fintek, CIR_CONTROL));
+       pr_reg(" * RX_DATA:    0x%x\n", fintek_cir_reg_read(fintek, CIR_RX_DATA));
+       pr_reg(" * TX_CONTROL: 0x%x\n", fintek_cir_reg_read(fintek, CIR_TX_CONTROL));
+       pr_reg(" * TX_DATA:    0x%x\n", fintek_cir_reg_read(fintek, CIR_TX_DATA));
+}
+
+/* detect hardware features */
+static int fintek_hw_detect(struct fintek_dev *fintek)
+{
+       unsigned long flags;
+       u8 chip_major, chip_minor;
+       u8 vendor_major, vendor_minor;
+       u8 portsel, ir_class;
+       u16 vendor;
+       int ret = 0;
+
+       fintek_config_mode_enable(fintek);
+
+       /* Check if we're using config port 0x4e or 0x2e */
+       portsel = fintek_cr_read(fintek, GCR_CONFIG_PORT_SEL);
+       if (portsel == 0xff) {
+               fit_pr(KERN_INFO, "first portsel read was bunk, trying alt");
+               fintek_config_mode_disable(fintek);
+               fintek->cr_ip = CR_INDEX_PORT2;
+               fintek->cr_dp = CR_DATA_PORT2;
+               fintek_config_mode_enable(fintek);
+               portsel = fintek_cr_read(fintek, GCR_CONFIG_PORT_SEL);
+       }
+       fit_dbg("portsel reg: 0x%02x", portsel);
+
+       ir_class = fintek_cir_reg_read(fintek, CIR_CR_CLASS);
+       fit_dbg("ir_class reg: 0x%02x", ir_class);
+
+       switch (ir_class) {
+       case CLASS_RX_2TX:
+       case CLASS_RX_1TX:
+               fintek->hw_tx_capable = true;
+               break;
+       case CLASS_RX_ONLY:
+       default:
+               fintek->hw_tx_capable = false;
+               break;
+       }
+
+       chip_major = fintek_cr_read(fintek, GCR_CHIP_ID_HI);
+       chip_minor = fintek_cr_read(fintek, GCR_CHIP_ID_LO);
+
+       vendor_major = fintek_cr_read(fintek, GCR_VENDOR_ID_HI);
+       vendor_minor = fintek_cr_read(fintek, GCR_VENDOR_ID_LO);
+       vendor = vendor_major << 8 | vendor_minor;
+
+       if (vendor != VENDOR_ID_FINTEK)
+               fit_pr(KERN_WARNING, "Unknown vendor ID: 0x%04x", vendor);
+       else
+               fit_dbg("Read Fintek vendor ID from chip");
+
+       fintek_config_mode_disable(fintek);
+
+       spin_lock_irqsave(&fintek->fintek_lock, flags);
+       fintek->chip_major  = chip_major;
+       fintek->chip_minor  = chip_minor;
+       fintek->chip_vendor = vendor;
+       spin_unlock_irqrestore(&fintek->fintek_lock, flags);
+
+       return ret;
+}
+
+static void fintek_cir_ldev_init(struct fintek_dev *fintek)
+{
+       /* Select CIR logical device and enable */
+       fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+       fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
+
+       /* Write allocated CIR address and IRQ information to hardware */
+       fintek_cr_write(fintek, fintek->cir_addr >> 8, CIR_CR_BASE_ADDR_HI);
+       fintek_cr_write(fintek, fintek->cir_addr & 0xff, CIR_CR_BASE_ADDR_LO);
+
+       fintek_cr_write(fintek, fintek->cir_irq, CIR_CR_IRQ_SEL);
+
+       fit_dbg("CIR initialized, base io address: 0x%lx, irq: %d (len: %d)",
+               fintek->cir_addr, fintek->cir_irq, fintek->cir_port_len);
+}
+
+/* enable CIR interrupts */
+static void fintek_enable_cir_irq(struct fintek_dev *fintek)
+{
+       fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_EN, CIR_STATUS);
+}
+
+static void fintek_cir_regs_init(struct fintek_dev *fintek)
+{
+       /* clear any and all stray interrupts */
+       fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
+
+       /* and finally, enable interrupts */
+       fintek_enable_cir_irq(fintek);
+}
+
+static void fintek_enable_wake(struct fintek_dev *fintek)
+{
+       fintek_config_mode_enable(fintek);
+       fintek_select_logical_dev(fintek, LOGICAL_DEV_ACPI);
+
+       /* Allow CIR PME's to wake system */
+       fintek_set_reg_bit(fintek, ACPI_WAKE_EN_CIR_BIT, LDEV_ACPI_WAKE_EN_REG);
+       /* Enable CIR PME's */
+       fintek_set_reg_bit(fintek, ACPI_PME_CIR_BIT, LDEV_ACPI_PME_EN_REG);
+       /* Clear CIR PME status register */
+       fintek_set_reg_bit(fintek, ACPI_PME_CIR_BIT, LDEV_ACPI_PME_CLR_REG);
+       /* Save state */
+       fintek_set_reg_bit(fintek, ACPI_STATE_CIR_BIT, LDEV_ACPI_STATE_REG);
+
+       fintek_config_mode_disable(fintek);
+}
+
+static int fintek_cmdsize(u8 cmd, u8 subcmd)
+{
+       int datasize = 0;
+
+       switch (cmd) {
+       case BUF_COMMAND_NULL:
+               if (subcmd == BUF_HW_CMD_HEADER)
+                       datasize = 1;
+               break;
+       case BUF_HW_CMD_HEADER:
+               if (subcmd == BUF_CMD_G_REVISION)
+                       datasize = 2;
+               break;
+       case BUF_COMMAND_HEADER:
+               switch (subcmd) {
+               case BUF_CMD_S_CARRIER:
+               case BUF_CMD_S_TIMEOUT:
+               case BUF_RSP_PULSE_COUNT:
+                       datasize = 2;
+                       break;
+               case BUF_CMD_SIG_END:
+               case BUF_CMD_S_TXMASK:
+               case BUF_CMD_S_RXSENSOR:
+                       datasize = 1;
+                       break;
+               }
+       }
+
+       return datasize;
+}
+
+/* process ir data stored in driver buffer */
+static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
+{
+       DEFINE_IR_RAW_EVENT(rawir);
+       u8 sample;
+       int i;
+
+       for (i = 0; i < fintek->pkts; i++) {
+               sample = fintek->buf[i];
+               switch (fintek->parser_state) {
+               case CMD_HEADER:
+                       fintek->cmd = sample;
+                       if ((fintek->cmd == BUF_COMMAND_HEADER) ||
+                           ((fintek->cmd & BUF_COMMAND_MASK) !=
+                            BUF_PULSE_BIT)) {
+                               fintek->parser_state = SUBCMD;
+                               continue;
+                       }
+                       fintek->rem = (fintek->cmd & BUF_LEN_MASK);
+                       fit_dbg("%s: rem: 0x%02x", __func__, fintek->rem);
+                       if (fintek->rem)
+                               fintek->parser_state = PARSE_IRDATA;
+                       else
+                               ir_raw_event_reset(fintek->rdev);
+                       break;
+               case SUBCMD:
+                       fintek->rem = fintek_cmdsize(fintek->cmd, sample);
+                       fintek->parser_state = CMD_DATA;
+                       break;
+               case CMD_DATA:
+                       fintek->rem--;
+                       break;
+               case PARSE_IRDATA:
+                       fintek->rem--;
+                       init_ir_raw_event(&rawir);
+                       rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
+                       rawir.duration = US_TO_NS((sample & BUF_SAMPLE_MASK)
+                                         * CIR_SAMPLE_PERIOD);
+
+                       fit_dbg("Storing %s with duration %d",
+                               rawir.pulse ? "pulse" : "space",
+                               rawir.duration);
+                       ir_raw_event_store_with_filter(fintek->rdev, &rawir);
+                       break;
+               }
+
+               if ((fintek->parser_state != CMD_HEADER) && !fintek->rem)
+                       fintek->parser_state = CMD_HEADER;
+       }
+
+       fintek->pkts = 0;
+
+       fit_dbg("Calling ir_raw_event_handle");
+       ir_raw_event_handle(fintek->rdev);
+}
+
+/* copy data from hardware rx register into driver buffer */
+static void fintek_get_rx_ir_data(struct fintek_dev *fintek, u8 rx_irqs)
+{
+       unsigned long flags;
+       u8 sample, status;
+
+       spin_lock_irqsave(&fintek->fintek_lock, flags);
+
+       /*
+        * We must read data from CIR_RX_DATA until the hardware IR buffer
+        * is empty and clears the RX_TIMEOUT and/or RX_RECEIVE flags in
+        * the CIR_STATUS register
+        */
+       do {
+               sample = fintek_cir_reg_read(fintek, CIR_RX_DATA);
+               fit_dbg("%s: sample: 0x%02x", __func__, sample);
+
+               fintek->buf[fintek->pkts] = sample;
+               fintek->pkts++;
+
+               status = fintek_cir_reg_read(fintek, CIR_STATUS);
+               if (!(status & CIR_STATUS_IRQ_EN))
+                       break;
+       } while (status & rx_irqs);
+
+       fintek_process_rx_ir_data(fintek);
+
+       spin_unlock_irqrestore(&fintek->fintek_lock, flags);
+}
+
+static void fintek_cir_log_irqs(u8 status)
+{
+       fit_pr(KERN_INFO, "IRQ 0x%02x:%s%s%s%s%s", status,
+               status & CIR_STATUS_IRQ_EN      ? " IRQEN"      : "",
+               status & CIR_STATUS_TX_FINISH   ? " TXF"        : "",
+               status & CIR_STATUS_TX_UNDERRUN ? " TXU"        : "",
+               status & CIR_STATUS_RX_TIMEOUT  ? " RXTO"       : "",
+               status & CIR_STATUS_RX_RECEIVE  ? " RXOK"       : "");
+}
+
+/* interrupt service routine for incoming and outgoing CIR data */
+static irqreturn_t fintek_cir_isr(int irq, void *data)
+{
+       struct fintek_dev *fintek = data;
+       u8 status, rx_irqs;
+
+       fit_dbg_verbose("%s firing", __func__);
+
+       fintek_config_mode_enable(fintek);
+       fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+       fintek_config_mode_disable(fintek);
+
+       /*
+        * Get IR Status register contents. Write 1 to ack/clear
+        *
+        * bit: reg name    - description
+        *   3: TX_FINISH   - TX is finished
+        *   2: TX_UNDERRUN - TX underrun
+        *   1: RX_TIMEOUT  - RX data timeout
+        *   0: RX_RECEIVE  - RX data received
+        */
+       status = fintek_cir_reg_read(fintek, CIR_STATUS);
+       if (!(status & CIR_STATUS_IRQ_MASK) || status == 0xff) {
+               fit_dbg_verbose("%s exiting, IRSTS 0x%02x", __func__, status);
+               fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
+               return IRQ_RETVAL(IRQ_NONE);
+       }
+
+       if (debug)
+               fintek_cir_log_irqs(status);
+
+       rx_irqs = status & (CIR_STATUS_RX_RECEIVE | CIR_STATUS_RX_TIMEOUT);
+       if (rx_irqs)
+               fintek_get_rx_ir_data(fintek, rx_irqs);
+
+       /* ack/clear all irq flags we've got */
+       fintek_cir_reg_write(fintek, status, CIR_STATUS);
+
+       fit_dbg_verbose("%s done", __func__);
+       return IRQ_RETVAL(IRQ_HANDLED);
+}
+
+static void fintek_enable_cir(struct fintek_dev *fintek)
+{
+       /* set IRQ enabled */
+       fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_EN, CIR_STATUS);
+
+       fintek_config_mode_enable(fintek);
+
+       /* enable the CIR logical device */
+       fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+       fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
+
+       fintek_config_mode_disable(fintek);
+
+       /* clear all pending interrupts */
+       fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
+
+       /* enable interrupts */
+       fintek_enable_cir_irq(fintek);
+}
+
+static void fintek_disable_cir(struct fintek_dev *fintek)
+{
+       fintek_config_mode_enable(fintek);
+
+       /* disable the CIR logical device */
+       fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+       fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN);
+
+       fintek_config_mode_disable(fintek);
+}
+
+static int fintek_open(struct rc_dev *dev)
+{
+       struct fintek_dev *fintek = dev->priv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&fintek->fintek_lock, flags);
+       fintek_enable_cir(fintek);
+       spin_unlock_irqrestore(&fintek->fintek_lock, flags);
+
+       return 0;
+}
+
+static void fintek_close(struct rc_dev *dev)
+{
+       struct fintek_dev *fintek = dev->priv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&fintek->fintek_lock, flags);
+       fintek_disable_cir(fintek);
+       spin_unlock_irqrestore(&fintek->fintek_lock, flags);
+}
+
+/* Allocate memory, probe hardware, and initialize everything */
+static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
+{
+       struct fintek_dev *fintek;
+       struct rc_dev *rdev;
+       int ret = -ENOMEM;
+
+       fintek = kzalloc(sizeof(struct fintek_dev), GFP_KERNEL);
+       if (!fintek)
+               return ret;
+
+       /* input device for IR remote (and tx) */
+       rdev = rc_allocate_device();
+       if (!rdev)
+               goto failure;
+
+       ret = -ENODEV;
+       /* validate pnp resources */
+       if (!pnp_port_valid(pdev, 0)) {
+               dev_err(&pdev->dev, "IR PNP Port not valid!\n");
+               goto failure;
+       }
+
+       if (!pnp_irq_valid(pdev, 0)) {
+               dev_err(&pdev->dev, "IR PNP IRQ not valid!\n");
+               goto failure;
+       }
+
+       fintek->cir_addr = pnp_port_start(pdev, 0);
+       fintek->cir_irq  = pnp_irq(pdev, 0);
+       fintek->cir_port_len = pnp_port_len(pdev, 0);
+
+       fintek->cr_ip = CR_INDEX_PORT;
+       fintek->cr_dp = CR_DATA_PORT;
+
+       spin_lock_init(&fintek->fintek_lock);
+
+       ret = -EBUSY;
+       /* now claim resources */
+       if (!request_region(fintek->cir_addr,
+                           fintek->cir_port_len, FINTEK_DRIVER_NAME))
+               goto failure;
+
+       if (request_irq(fintek->cir_irq, fintek_cir_isr, IRQF_SHARED,
+                       FINTEK_DRIVER_NAME, (void *)fintek))
+               goto failure;
+
+       pnp_set_drvdata(pdev, fintek);
+       fintek->pdev = pdev;
+
+       ret = fintek_hw_detect(fintek);
+       if (ret)
+               goto failure;
+
+       /* Initialize CIR & CIR Wake Logical Devices */
+       fintek_config_mode_enable(fintek);
+       fintek_cir_ldev_init(fintek);
+       fintek_config_mode_disable(fintek);
+
+       /* Initialize CIR & CIR Wake Config Registers */
+       fintek_cir_regs_init(fintek);
+
+       /* Set up the rc device */
+       rdev->priv = fintek;
+       rdev->driver_type = RC_DRIVER_IR_RAW;
+       rdev->allowed_protos = RC_TYPE_ALL;
+       rdev->open = fintek_open;
+       rdev->close = fintek_close;
+       rdev->input_name = FINTEK_DESCRIPTION;
+       rdev->input_phys = "fintek/cir0";
+       rdev->input_id.bustype = BUS_HOST;
+       rdev->input_id.vendor = VENDOR_ID_FINTEK;
+       rdev->input_id.product = fintek->chip_major;
+       rdev->input_id.version = fintek->chip_minor;
+       rdev->dev.parent = &pdev->dev;
+       rdev->driver_name = FINTEK_DRIVER_NAME;
+       rdev->map_name = RC_MAP_RC6_MCE;
+       rdev->timeout = US_TO_NS(1000);
+       /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
+       rdev->rx_resolution = US_TO_NS(CIR_SAMPLE_PERIOD);
+
+       ret = rc_register_device(rdev);
+       if (ret)
+               goto failure;
+
+       device_init_wakeup(&pdev->dev, true);
+       fintek->rdev = rdev;
+       fit_pr(KERN_NOTICE, "driver has been successfully loaded\n");
+       if (debug)
+               cir_dump_regs(fintek);
+
+       return 0;
+
+failure:
+       if (fintek->cir_irq)
+               free_irq(fintek->cir_irq, fintek);
+       if (fintek->cir_addr)
+               release_region(fintek->cir_addr, fintek->cir_port_len);
+
+       rc_free_device(rdev);
+       kfree(fintek);
+
+       return ret;
+}
+
+static void __devexit fintek_remove(struct pnp_dev *pdev)
+{
+       struct fintek_dev *fintek = pnp_get_drvdata(pdev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&fintek->fintek_lock, flags);
+       /* disable CIR */
+       fintek_disable_cir(fintek);
+       fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
+       /* enable CIR Wake (for IR power-on) */
+       fintek_enable_wake(fintek);
+       spin_unlock_irqrestore(&fintek->fintek_lock, flags);
+
+       /* free resources */
+       free_irq(fintek->cir_irq, fintek);
+       release_region(fintek->cir_addr, fintek->cir_port_len);
+
+       rc_unregister_device(fintek->rdev);
+
+       kfree(fintek);
+}
+
+static int fintek_suspend(struct pnp_dev *pdev, pm_message_t state)
+{
+       struct fintek_dev *fintek = pnp_get_drvdata(pdev);
+
+       fit_dbg("%s called", __func__);
+
+       /* disable all CIR interrupts */
+       fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
+
+       fintek_config_mode_enable(fintek);
+
+       /* disable cir logical dev */
+       fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+       fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN);
+
+       fintek_config_mode_disable(fintek);
+
+       /* make sure wake is enabled */
+       fintek_enable_wake(fintek);
+
+       return 0;
+}
+
+static int fintek_resume(struct pnp_dev *pdev)
+{
+       int ret = 0;
+       struct fintek_dev *fintek = pnp_get_drvdata(pdev);
+
+       fit_dbg("%s called", __func__);
+
+       /* open interrupt */
+       fintek_enable_cir_irq(fintek);
+
+       /* Enable CIR logical device */
+       fintek_config_mode_enable(fintek);
+       fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+       fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
+
+       fintek_config_mode_disable(fintek);
+
+       fintek_cir_regs_init(fintek);
+
+       return ret;
+}
+
+static void fintek_shutdown(struct pnp_dev *pdev)
+{
+       struct fintek_dev *fintek = pnp_get_drvdata(pdev);
+       fintek_enable_wake(fintek);
+}
+
+static const struct pnp_device_id fintek_ids[] = {
+       { "FIT0002", 0 },   /* CIR */
+       { "", 0 },
+};
+
+static struct pnp_driver fintek_driver = {
+       .name           = FINTEK_DRIVER_NAME,
+       .id_table       = fintek_ids,
+       .flags          = PNP_DRIVER_RES_DO_NOT_CHANGE,
+       .probe          = fintek_probe,
+       .remove         = __devexit_p(fintek_remove),
+       .suspend        = fintek_suspend,
+       .resume         = fintek_resume,
+       .shutdown       = fintek_shutdown,
+};
+
+int fintek_init(void)
+{
+       return pnp_register_driver(&fintek_driver);
+}
+
+void fintek_exit(void)
+{
+       pnp_unregister_driver(&fintek_driver);
+}
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging output");
+
+MODULE_DEVICE_TABLE(pnp, fintek_ids);
+MODULE_DESCRIPTION(FINTEK_DESCRIPTION " driver");
+
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
+MODULE_LICENSE("GPL");
+
+module_init(fintek_init);
+module_exit(fintek_exit);
diff --git a/drivers/media/rc/fintek-cir.h b/drivers/media/rc/fintek-cir.h
new file mode 100644 (file)
index 0000000..1b10b20
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Driver for Feature Integration Technology Inc. (aka Fintek) LPC CIR
+ *
+ * Copyright (C) 2011 Jarod Wilson <jarod@redhat.com>
+ *
+ * Special thanks to Fintek for providing hardware and spec sheets.
+ * This driver is based upon the nuvoton, ite and ene drivers for
+ * similar hardware.
+ *
+ * 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/spinlock.h>
+#include <linux/ioctl.h>
+
+/* platform driver name to register */
+#define FINTEK_DRIVER_NAME     "fintek-cir"
+#define FINTEK_DESCRIPTION     "Fintek LPC SuperIO Consumer IR Transceiver"
+#define VENDOR_ID_FINTEK       0x1934
+
+
+/* debugging module parameter */
+static int debug;
+
+#define fit_pr(level, text, ...) \
+       printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__)
+
+#define fit_dbg(text, ...) \
+       if (debug) \
+               printk(KERN_DEBUG \
+                       KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
+
+#define fit_dbg_verbose(text, ...) \
+       if (debug > 1) \
+               printk(KERN_DEBUG \
+                       KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
+
+#define fit_dbg_wake(text, ...) \
+       if (debug > 2) \
+               printk(KERN_DEBUG \
+                       KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
+
+
+#define TX_BUF_LEN 256
+#define RX_BUF_LEN 32
+
+struct fintek_dev {
+       struct pnp_dev *pdev;
+       struct rc_dev *rdev;
+
+       spinlock_t fintek_lock;
+
+       /* for rx */
+       u8 buf[RX_BUF_LEN];
+       unsigned int pkts;
+
+       struct {
+               spinlock_t lock;
+               u8 buf[TX_BUF_LEN];
+               unsigned int buf_count;
+               unsigned int cur_buf_num;
+               wait_queue_head_t queue;
+       } tx;
+
+       /* Config register index/data port pair */
+       u8 cr_ip;
+       u8 cr_dp;
+
+       /* hardware I/O settings */
+       unsigned long cir_addr;
+       int cir_irq;
+       int cir_port_len;
+
+       /* hardware id */
+       u8 chip_major;
+       u8 chip_minor;
+       u16 chip_vendor;
+
+       /* hardware features */
+       bool hw_learning_capable;
+       bool hw_tx_capable;
+
+       /* rx settings */
+       bool learning_enabled;
+       bool carrier_detect_enabled;
+
+       enum {
+               CMD_HEADER = 0,
+               SUBCMD,
+               CMD_DATA,
+               PARSE_IRDATA,
+       } parser_state;
+
+       u8 cmd, rem;
+
+       /* carrier period = 1 / frequency */
+       u32 carrier;
+};
+
+/* buffer packet constants, largely identical to mceusb.c */
+#define BUF_PULSE_BIT          0x80
+#define BUF_LEN_MASK           0x1f
+#define BUF_SAMPLE_MASK                0x7f
+
+#define BUF_COMMAND_HEADER     0x9f
+#define BUF_COMMAND_MASK       0xe0
+#define BUF_COMMAND_NULL       0x00
+#define BUF_HW_CMD_HEADER      0xff
+#define BUF_CMD_G_REVISION     0x0b
+#define BUF_CMD_S_CARRIER      0x06
+#define BUF_CMD_S_TIMEOUT      0x0c
+#define BUF_CMD_SIG_END                0x01
+#define BUF_CMD_S_TXMASK       0x08
+#define BUF_CMD_S_RXSENSOR     0x14
+#define BUF_RSP_PULSE_COUNT    0x15
+
+#define CIR_SAMPLE_PERIOD      50
+
+/*
+ * Configuration Register:
+ *  Index Port
+ *  Data Port
+ */
+#define CR_INDEX_PORT          0x2e
+#define CR_DATA_PORT           0x2f
+
+/* Possible alternate values, depends on how the chip is wired */
+#define CR_INDEX_PORT2         0x4e
+#define CR_DATA_PORT2          0x4f
+
+/*
+ * GCR_CONFIG_PORT_SEL bit 4 specifies which Index Port value is
+ * active. 1 = 0x4e, 0 = 0x2e
+ */
+#define PORT_SEL_PORT_4E_EN    0x10
+
+/* Extended Function Mode enable/disable magic values */
+#define CONFIG_REG_ENABLE      0x87
+#define CONFIG_REG_DISABLE     0xaa
+
+/* Chip IDs found in CR_CHIP_ID_{HI,LO} */
+#define CHIP_ID_HIGH_F71809U   0x04
+#define CHIP_ID_LOW_F71809U    0x08
+
+/*
+ * Global control regs we need to care about:
+ *      Global Control                  def.
+ *      Register name           addr    val. */
+#define GCR_SOFTWARE_RESET     0x02 /* 0x00 */
+#define GCR_LOGICAL_DEV_NO     0x07 /* 0x00 */
+#define GCR_CHIP_ID_HI         0x20 /* 0x04 */
+#define GCR_CHIP_ID_LO         0x21 /* 0x08 */
+#define GCR_VENDOR_ID_HI       0x23 /* 0x19 */
+#define GCR_VENDOR_ID_LO       0x24 /* 0x34 */
+#define GCR_CONFIG_PORT_SEL    0x25 /* 0x01 */
+#define GCR_KBMOUSE_WAKEUP     0x27
+
+#define LOGICAL_DEV_DISABLE    0x00
+#define LOGICAL_DEV_ENABLE     0x01
+
+/* Logical device number of the CIR function */
+#define LOGICAL_DEV_CIR                0x05
+
+/* CIR Logical Device (LDN 0x08) config registers */
+#define CIR_CR_COMMAND_INDEX   0x04
+#define CIR_CR_IRCS            0x05 /* Before host writes command to IR, host
+                                       must set to 1. When host finshes write
+                                       command to IR, host must clear to 0. */
+#define CIR_CR_COMMAND_DATA    0x06 /* Host read or write comand data */
+#define CIR_CR_CLASS           0x07 /* 0xff = rx-only, 0x66 = rx + 2 tx,
+                                       0x33 = rx + 1 tx */
+#define CIR_CR_DEV_EN          0x30 /* bit0 = 1 enables CIR */
+#define CIR_CR_BASE_ADDR_HI    0x60 /* MSB of CIR IO base addr */
+#define CIR_CR_BASE_ADDR_LO    0x61 /* LSB of CIR IO base addr */
+#define CIR_CR_IRQ_SEL         0x70 /* bits3-0 store CIR IRQ */
+#define CIR_CR_PSOUT_STATUS    0xf1
+#define CIR_CR_WAKE_KEY3_ADDR  0xf8
+#define CIR_CR_WAKE_KEY3_CODE  0xf9
+#define CIR_CR_WAKE_KEY3_DC    0xfa
+#define CIR_CR_WAKE_CONTROL    0xfb
+#define CIR_CR_WAKE_KEY12_ADDR 0xfc
+#define CIR_CR_WAKE_KEY4_ADDR  0xfd
+#define CIR_CR_WAKE_KEY5_ADDR  0xfe
+
+#define CLASS_RX_ONLY          0xff
+#define CLASS_RX_2TX           0x66
+#define CLASS_RX_1TX           0x33
+
+/* CIR device registers */
+#define CIR_STATUS             0x00
+#define CIR_RX_DATA            0x01
+#define CIR_TX_CONTROL         0x02
+#define CIR_TX_DATA            0x03
+#define CIR_CONTROL            0x04
+
+/* Bits to enable CIR wake */
+#define LOGICAL_DEV_ACPI       0x01
+#define LDEV_ACPI_WAKE_EN_REG  0xe8
+#define ACPI_WAKE_EN_CIR_BIT   0x04
+
+#define LDEV_ACPI_PME_EN_REG   0xf0
+#define LDEV_ACPI_PME_CLR_REG  0xf1
+#define ACPI_PME_CIR_BIT       0x02
+
+#define LDEV_ACPI_STATE_REG    0xf4
+#define ACPI_STATE_CIR_BIT     0x20
+
+/*
+ * CIR status register (0x00):
+ *   7 - CIR_IRQ_EN (1 = enable CIR IRQ, 0 = disable)
+ *   3 - TX_FINISH (1 when TX finished, write 1 to clear)
+ *   2 - TX_UNDERRUN (1 on TX underrun, write 1 to clear)
+ *   1 - RX_TIMEOUT (1 on RX timeout, write 1 to clear)
+ *   0 - RX_RECEIVE (1 on RX receive, write 1 to clear)
+ */
+#define CIR_STATUS_IRQ_EN      0x80
+#define CIR_STATUS_TX_FINISH   0x08
+#define CIR_STATUS_TX_UNDERRUN 0x04
+#define CIR_STATUS_RX_TIMEOUT  0x02
+#define CIR_STATUS_RX_RECEIVE  0x01
+#define CIR_STATUS_IRQ_MASK    0x0f
+
+/*
+ * CIR TX control register (0x02):
+ *   7 - TX_START (1 to indicate TX start, auto-cleared when done)
+ *   6 - TX_END (1 to indicate TX data written to TX fifo)
+ */
+#define CIR_TX_CONTROL_TX_START        0x80
+#define CIR_TX_CONTROL_TX_END  0x40
+
index afae14fd152ea26289c67135f017e09858560326..129d3f9a461de94b415b01a6bd1d77cd67da5758 100644 (file)
 
 static struct rc_map_table lme2510_rc[] = {
        /* Type 1 - 26 buttons */
-       { 0xef12ba45, KEY_0 },
-       { 0xef12a05f, KEY_1 },
-       { 0xef12af50, KEY_2 },
-       { 0xef12a25d, KEY_3 },
-       { 0xef12be41, KEY_4 },
-       { 0xef12f50a, KEY_5 },
-       { 0xef12bd42, KEY_6 },
-       { 0xef12b847, KEY_7 },
-       { 0xef12b649, KEY_8 },
-       { 0xef12fa05, KEY_9 },
-       { 0xef12bc43, KEY_POWER },
-       { 0xef12b946, KEY_SUBTITLE },
-       { 0xef12f906, KEY_PAUSE },
-       { 0xef12fc03, KEY_MEDIA_REPEAT},
-       { 0xef12fd02, KEY_PAUSE },
-       { 0xef12a15e, KEY_VOLUMEUP },
-       { 0xef12a35c, KEY_VOLUMEDOWN },
-       { 0xef12f609, KEY_CHANNELUP },
-       { 0xef12e51a, KEY_CHANNELDOWN },
-       { 0xef12e11e, KEY_PLAY },
-       { 0xef12e41b, KEY_ZOOM },
-       { 0xef12a659, KEY_MUTE },
-       { 0xef12a55a, KEY_TV },
-       { 0xef12e718, KEY_RECORD },
-       { 0xef12f807, KEY_EPG },
-       { 0xef12fe01, KEY_STOP },
+       { 0x10ed45, KEY_0 },
+       { 0x10ed5f, KEY_1 },
+       { 0x10ed50, KEY_2 },
+       { 0x10ed5d, KEY_3 },
+       { 0x10ed41, KEY_4 },
+       { 0x10ed0a, KEY_5 },
+       { 0x10ed42, KEY_6 },
+       { 0x10ed47, KEY_7 },
+       { 0x10ed49, KEY_8 },
+       { 0x10ed05, KEY_9 },
+       { 0x10ed43, KEY_POWER },
+       { 0x10ed46, KEY_SUBTITLE },
+       { 0x10ed06, KEY_PAUSE },
+       { 0x10ed03, KEY_MEDIA_REPEAT},
+       { 0x10ed02, KEY_PAUSE },
+       { 0x10ed5e, KEY_VOLUMEUP },
+       { 0x10ed5c, KEY_VOLUMEDOWN },
+       { 0x10ed09, KEY_CHANNELUP },
+       { 0x10ed1a, KEY_CHANNELDOWN },
+       { 0x10ed1e, KEY_PLAY },
+       { 0x10ed1b, KEY_ZOOM },
+       { 0x10ed59, KEY_MUTE },
+       { 0x10ed5a, KEY_TV },
+       { 0x10ed18, KEY_RECORD },
+       { 0x10ed07, KEY_EPG },
+       { 0x10ed01, KEY_STOP },
        /* Type 2 - 20 buttons */
-       { 0xff40ea15, KEY_0 },
-       { 0xff40f708, KEY_1 },
-       { 0xff40f609, KEY_2 },
-       { 0xff40f50a, KEY_3 },
-       { 0xff40f30c, KEY_4 },
-       { 0xff40f20d, KEY_5 },
-       { 0xff40f10e, KEY_6 },
-       { 0xff40ef10, KEY_7 },
-       { 0xff40ee11, KEY_8 },
-       { 0xff40ed12, KEY_9 },
-       { 0xff40ff00, KEY_POWER },
-       { 0xff40fb04, KEY_MEDIA_REPEAT}, /* Recall */
-       { 0xff40e51a, KEY_PAUSE }, /* Timeshift */
-       { 0xff40fd02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
-       { 0xff40f906, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
-       { 0xff40fe01, KEY_CHANNELUP },
-       { 0xff40fa05, KEY_CHANNELDOWN },
-       { 0xff40eb14, KEY_ZOOM },
-       { 0xff40e718, KEY_RECORD },
-       { 0xff40e916, KEY_STOP },
+       { 0xbf15, KEY_0 },
+       { 0xbf08, KEY_1 },
+       { 0xbf09, KEY_2 },
+       { 0xbf0a, KEY_3 },
+       { 0xbf0c, KEY_4 },
+       { 0xbf0d, KEY_5 },
+       { 0xbf0e, KEY_6 },
+       { 0xbf10, KEY_7 },
+       { 0xbf11, KEY_8 },
+       { 0xbf12, KEY_9 },
+       { 0xbf00, KEY_POWER },
+       { 0xbf04, KEY_MEDIA_REPEAT}, /* Recall */
+       { 0xbf1a, KEY_PAUSE }, /* Timeshift */
+       { 0xbf02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
+       { 0xbf06, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
+       { 0xbf01, KEY_CHANNELUP },
+       { 0xbf05, KEY_CHANNELDOWN },
+       { 0xbf14, KEY_ZOOM },
+       { 0xbf18, KEY_RECORD },
+       { 0xbf16, KEY_STOP },
        /* Type 3 - 20 buttons */
-       { 0xff00e31c, KEY_0 },
-       { 0xff00f807, KEY_1 },
-       { 0xff00ea15, KEY_2 },
-       { 0xff00f609, KEY_3 },
-       { 0xff00e916, KEY_4 },
-       { 0xff00e619, KEY_5 },
-       { 0xff00f20d, KEY_6 },
-       { 0xff00f30c, KEY_7 },
-       { 0xff00e718, KEY_8 },
-       { 0xff00a15e, KEY_9 },
-       { 0xff00ba45, KEY_POWER },
-       { 0xff00bb44, KEY_MEDIA_REPEAT}, /* Recall */
-       { 0xff00b54a, KEY_PAUSE }, /* Timeshift */
-       { 0xff00b847, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
-       { 0xff00bc43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
-       { 0xff00b946, KEY_CHANNELUP },
-       { 0xff00bf40, KEY_CHANNELDOWN },
-       { 0xff00f708, KEY_ZOOM },
-       { 0xff00bd42, KEY_RECORD },
-       { 0xff00a55a, KEY_STOP },
+       { 0x1c, KEY_0 },
+       { 0x07, KEY_1 },
+       { 0x15, KEY_2 },
+       { 0x09, KEY_3 },
+       { 0x16, KEY_4 },
+       { 0x19, KEY_5 },
+       { 0x0d, KEY_6 },
+       { 0x0c, KEY_7 },
+       { 0x18, KEY_8 },
+       { 0x5e, KEY_9 },
+       { 0x45, KEY_POWER },
+       { 0x44, KEY_MEDIA_REPEAT}, /* Recall */
+       { 0x4a, KEY_PAUSE }, /* Timeshift */
+       { 0x47, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
+       { 0x43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
+       { 0x46, KEY_CHANNELUP },
+       { 0x40, KEY_CHANNELDOWN },
+       { 0x08, KEY_ZOOM },
+       { 0x42, KEY_RECORD },
+       { 0x5a, KEY_STOP },
 };
 
 static struct rc_map_list lme2510_map = {
        .map = {
                .scan    = lme2510_rc,
                .size    = ARRAY_SIZE(lme2510_rc),
-               .rc_type = RC_TYPE_UNKNOWN,
+               .rc_type = RC_TYPE_NEC,
                .name    = RC_MAP_LME2510,
        }
 };
index 3be180b3ba274294561e83b9e48ebb60c0e7fe2c..bb53de7fe4087b227f98b63cdc15b035d28f008c 100644 (file)
@@ -687,7 +687,7 @@ config VIDEO_HEXIUM_GEMINI
 
 config VIDEO_TIMBERDALE
        tristate "Support for timberdale Video In/LogiWIN"
-       depends on VIDEO_V4L2 && I2C
+       depends on VIDEO_V4L2 && I2C && DMADEVICES
        select DMA_ENGINE
        select TIMB_DMA
        select VIDEO_ADV7180
@@ -757,6 +757,8 @@ config VIDEO_NOON010PC30
        ---help---
          This driver supports NOON010PC30 CIF camera from Siliconfile
 
+source "drivers/media/video/m5mols/Kconfig"
+
 config VIDEO_OMAP3
        tristate "OMAP 3 Camera support (EXPERIMENTAL)"
        select OMAP_IOMMU
@@ -952,7 +954,7 @@ config  VIDEO_SAMSUNG_S5P_FIMC
 
 config VIDEO_S5P_MIPI_CSIS
        tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver"
-       depends on VIDEO_V4L2 && PM_RUNTIME && VIDEO_V4L2_SUBDEV_API
+       depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P && VIDEO_V4L2_SUBDEV_API
        ---help---
          This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver.
 
index 9519160c2e01eb1da9b49ca4eaf2cd9ce4318b3e..f0fecd6f6a33e818c4f4713d2b62e1ecd762e4a9 100644 (file)
@@ -69,6 +69,7 @@ obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
 obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
 obj-$(CONFIG_VIDEO_SR030PC30)  += sr030pc30.o
 obj-$(CONFIG_VIDEO_NOON010PC30)        += noon010pc30.o
+obj-$(CONFIG_VIDEO_M5MOLS)     += m5mols/
 
 obj-$(CONFIG_SOC_CAMERA_IMX074)                += imx074.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)       += mt9m001.o
index 0073a8c553361aadab0d3f214b6e9520f1838f59..40eb6326e48a8ab95ca7c476999772bd3e76ff3b 100644 (file)
@@ -438,7 +438,7 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v
                strcat(vc->card, " (676/");
                break;
        default:
-               strcat(vc->card, " (???/");
+               strcat(vc->card, " (XXX/");
                break;
        }
        switch (cam->params.version.sensor_flags) {
@@ -458,7 +458,7 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v
                strcat(vc->card, "500)");
                break;
        default:
-               strcat(vc->card, "???)");
+               strcat(vc->card, "XXX)");
                break;
        }
 
index 280df43ca446458f639879bf5e3aa18f2229579d..8d7813415760e5f1cf753368f86b0f124e642b55 100644 (file)
@@ -1354,7 +1354,7 @@ void cx231xx_dump_SC_reg(struct cx231xx *dev)
 {
        u8 value[4] = { 0, 0, 0, 0 };
        int status = 0;
-       cx231xx_info("cx231xx_dump_SC_reg %s!\n", __TIME__);
+       cx231xx_info("cx231xx_dump_SC_reg!\n");
 
        status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT,
                                 value, 4);
index 2354336862cf7f0d0f1203093295dae5fc77c423..934185cca758d7461e3bc96bead9f64db90625c0 100644 (file)
@@ -25,8 +25,8 @@
 #include <linux/delay.h>
 #include <media/cx25840.h>
 #include <linux/firmware.h>
-#include <staging/altera.h>
 
+#include "../../../staging/altera-stapl/altera.h"
 #include "cx23885.h"
 #include "tuner-xc2028.h"
 #include "netup-init.h"
diff --git a/drivers/media/video/gspca/coarse_expo_autogain.h b/drivers/media/video/gspca/coarse_expo_autogain.h
deleted file mode 100644 (file)
index 1cb9d94..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Auto gain algorithm for camera's with a coarse exposure control
- *
- * Copyright (C) 2010 Hans de Goede <hdegoede@redhat.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
- */
-
-/* Autogain + exposure algorithm for cameras with a coarse exposure control
-   (usually this means we can only control the clockdiv to change exposure)
-   As changing the clockdiv so that the fps drops from 30 to 15 fps for
-   example, will lead to a huge exposure change (it effectively doubles),
-   this algorithm normally tries to only adjust the gain (between 40 and
-   80 %) and if that does not help, only then changes exposure. This leads
-   to a much more stable image then using the knee algorithm which at
-   certain points of the knee graph will only try to adjust exposure,
-   which leads to oscilating as one exposure step is huge.
-
-   Note this assumes that the sd struct for the cam in question has
-   exp_too_high_cnt and exp_too_high_cnt int members for use by this function.
-
-   Returns 0 if no changes were made, 1 if the gain and or exposure settings
-   where changed. */
-static int gspca_coarse_grained_expo_autogain(struct gspca_dev *gspca_dev,
-       int avg_lum, int desired_avg_lum, int deadzone)
-{
-       int i, steps, gain, orig_gain, exposure, orig_exposure;
-       int gain_low, gain_high;
-       const struct ctrl *gain_ctrl = NULL;
-       const struct ctrl *exposure_ctrl = NULL;
-       struct sd *sd = (struct sd *) gspca_dev;
-       int retval = 0;
-
-       for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
-               if (gspca_dev->ctrl_dis & (1 << i))
-                       continue;
-               if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_GAIN)
-                       gain_ctrl = &gspca_dev->sd_desc->ctrls[i];
-               if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_EXPOSURE)
-                       exposure_ctrl = &gspca_dev->sd_desc->ctrls[i];
-       }
-       if (!gain_ctrl || !exposure_ctrl) {
-               PDEBUG(D_ERR, "Error: gspca_coarse_grained_expo_autogain "
-                       "called on cam without gain or exposure");
-               return 0;
-       }
-
-       if (gain_ctrl->get(gspca_dev, &gain) ||
-           exposure_ctrl->get(gspca_dev, &exposure))
-               return 0;
-
-       orig_gain = gain;
-       orig_exposure = exposure;
-       gain_low =
-               (gain_ctrl->qctrl.maximum - gain_ctrl->qctrl.minimum) / 5 * 2;
-       gain_low += gain_ctrl->qctrl.minimum;
-       gain_high =
-               (gain_ctrl->qctrl.maximum - gain_ctrl->qctrl.minimum) / 5 * 4;
-       gain_high += gain_ctrl->qctrl.minimum;
-
-       /* If we are of a multiple of deadzone, do multiple steps to reach the
-          desired lumination fast (with the risc of a slight overshoot) */
-       steps = (desired_avg_lum - avg_lum) / deadzone;
-
-       PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
-               avg_lum, desired_avg_lum, steps);
-
-       if ((gain + steps) > gain_high &&
-           sd->exposure < exposure_ctrl->qctrl.maximum) {
-               gain = gain_high;
-               sd->exp_too_low_cnt++;
-       } else if ((gain + steps) < gain_low &&
-                  sd->exposure > exposure_ctrl->qctrl.minimum) {
-               gain = gain_low;
-               sd->exp_too_high_cnt++;
-       } else {
-               gain += steps;
-               if (gain > gain_ctrl->qctrl.maximum)
-                       gain = gain_ctrl->qctrl.maximum;
-               else if (gain < gain_ctrl->qctrl.minimum)
-                       gain = gain_ctrl->qctrl.minimum;
-               sd->exp_too_high_cnt = 0;
-               sd->exp_too_low_cnt = 0;
-       }
-
-       if (sd->exp_too_high_cnt > 3) {
-               exposure--;
-               sd->exp_too_high_cnt = 0;
-       } else if (sd->exp_too_low_cnt > 3) {
-               exposure++;
-               sd->exp_too_low_cnt = 0;
-       }
-
-       if (gain != orig_gain) {
-               gain_ctrl->set(gspca_dev, gain);
-               retval = 1;
-       }
-       if (exposure != orig_exposure) {
-               exposure_ctrl->set(gspca_dev, exposure);
-               retval = 1;
-       }
-
-       return retval;
-}
index 66671a4092e4e68344e0314cec0e9a984c7e49a7..26fc206f095e13f9e202c13e7754236af0daa551 100644 (file)
@@ -34,7 +34,7 @@ MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
 MODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-#ifdef DEBUG
+#ifdef GSPCA_DEBUG
 int gspca_debug = D_ERR | D_PROBE | D_CONF | D_STREAM | D_FRAM | D_PACK |
        D_USBI | D_USBO | D_V4L2;
 #endif
index 36a46fc787341b86dbd8ceaa1fef5c1ab21541b7..057e287b9152a78fea793bdefa8ec6d26b699085 100644 (file)
@@ -609,7 +609,7 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
  * buffers, there are some pretty strict real time constraints for
  * isochronous transfer for larger frame sizes).
  */
-/*jfm: this value works well for 1600x1200, but not 800x600 - see isoc_init */
+/*jfm: this value does not work for 800x600 - see isoc_init */
 #define OVFX2_BULK_SIZE (13 * 4096)
 
 /* I2C registers */
@@ -3307,6 +3307,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
        gspca_dev->cam.ctrls = sd->ctrls;
        sd->quality = QUALITY_DEF;
+       sd->frame_rate = 15;
 
        return 0;
 }
@@ -3469,7 +3470,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
                                ARRAY_SIZE(init_519_ov7660));
                write_i2c_regvals(sd, norm_7660, ARRAY_SIZE(norm_7660));
                sd->gspca_dev.curr_mode = 1;    /* 640x480 */
-               sd->frame_rate = 15;
                ov519_set_mode(sd);
                ov519_set_fr(sd);
                sd->ctrls[COLORS].max = 4;      /* 0..4 */
@@ -3511,7 +3511,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
 
        switch (sd->bridge) {
        case BRIDGE_OVFX2:
-               if (gspca_dev->width == 1600)
+               if (gspca_dev->width != 800)
                        gspca_dev->cam.bulk_size = OVFX2_BULK_SIZE;
                else
                        gspca_dev->cam.bulk_size = 7 * 4096;
@@ -4478,7 +4478,7 @@ static void ovfx2_pkt_scan(struct gspca_dev *gspca_dev,
        gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 
        /* A short read signals EOF */
-       if (len < OVFX2_BULK_SIZE) {
+       if (len < gspca_dev->cam.bulk_size) {
                /* If the frame is short, and it is one of the first ones
                   the sensor and bridge are still syncing, so drop it. */
                if (sd->first_frame) {
index 6415aff5cbd1675cb4f96d106b9eb72b78b8977b..81b8a600783b575290814af47931ee5b1702ebcf 100644 (file)
@@ -60,7 +60,7 @@ struct sd {
 
        u32 pktsz;                      /* (used by pkt_scan) */
        u16 npkt;
-       u8 nchg;
+       s8 nchg;
        s8 short_mark;
 
        u8 quality;                     /* image quality */
index b538dce96f78d8cbb1c7297ea8b40ce21712ea7b..a14a84a5079b96d4da4b932d206d99b4d1a9532e 100644 (file)
 #define HDCS_SLEEP_MODE                (1 << 1)
 
 #define HDCS_DEFAULT_EXPOSURE  48
-#define HDCS_DEFAULT_GAIN      128
+#define HDCS_DEFAULT_GAIN      50
 
 static int hdcs_probe_1x00(struct sd *sd);
 static int hdcs_probe_1020(struct sd *sd);
index a4e4dfdbc2f2c9474c5616b9b68f44abb762dd75..0fb75524484d909af4925c3c33c9f12cf6d6519e 100644 (file)
@@ -1328,6 +1328,8 @@ int ivtv_init_on_first_open(struct ivtv *itv)
        if (!itv->has_cx23415)
                write_reg_sync(0x03, IVTV_REG_DMACONTROL);
 
+       ivtv_s_std_enc(itv, &itv->tuner_std);
+
        /* Default interrupts enabled. For the PVR350 this includes the
           decoder VSYNC interrupt, which is always on. It is not only used
           during decoding but also by the OSD.
@@ -1336,12 +1338,10 @@ int ivtv_init_on_first_open(struct ivtv *itv)
        if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
                ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC);
                ivtv_set_osd_alpha(itv);
-       }
-       else
+               ivtv_s_std_dec(itv, &itv->tuner_std);
+       } else {
                ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT);
-
-       /* For cards with video out, this call needs interrupts enabled */
-       ivtv_s_std(NULL, &fh, &itv->tuner_std);
+       }
 
        /* Setup initial controls */
        cx2341x_handler_setup(&itv->cxhdl);
index 14a1cea1d70da6bdcefc06184d4153f804348de8..02c5adebf517aac57248c473a60c793952629e75 100644 (file)
@@ -280,8 +280,6 @@ int ivtv_firmware_restart(struct ivtv *itv)
 {
        int rc = 0;
        v4l2_std_id std;
-       struct ivtv_open_id fh;
-       fh.itv = itv;
 
        if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
                /* Display test image during restart */
@@ -301,14 +299,19 @@ int ivtv_firmware_restart(struct ivtv *itv)
        /* Allow settings to reload */
        ivtv_mailbox_cache_invalidate(itv);
 
-       /* Restore video standard */
+       /* Restore encoder video standard */
        std = itv->std;
        itv->std = 0;
-       ivtv_s_std(NULL, &fh, &std);
+       ivtv_s_std_enc(itv, &std);
 
        if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
                ivtv_init_mpeg_decoder(itv);
 
+               /* Restore decoder video standard */
+               std = itv->std_out;
+               itv->std_out = 0;
+               ivtv_s_std_dec(itv, &std);
+
                /* Restore framebuffer if active */
                if (itv->ivtvfb_restore)
                        itv->ivtvfb_restore(itv);
index 1689783cd19aa81261147b35870a485eb16736aa..f9e347dae7391a4487e15ac17e9e16578f59d16e 100644 (file)
@@ -1071,28 +1071,8 @@ static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std)
        return 0;
 }
 
-int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
+void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std)
 {
-       DEFINE_WAIT(wait);
-       struct ivtv *itv = fh2id(fh)->itv;
-       struct yuv_playback_info *yi = &itv->yuv_info;
-       int f;
-
-       if ((*std & V4L2_STD_ALL) == 0)
-               return -EINVAL;
-
-       if (*std == itv->std)
-               return 0;
-
-       if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ||
-           atomic_read(&itv->capturing) > 0 ||
-           atomic_read(&itv->decoding) > 0) {
-               /* Switching standard would turn off the radio or mess
-                  with already running streams, prevent that by
-                  returning EBUSY. */
-               return -EBUSY;
-       }
-
        itv->std = *std;
        itv->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
        itv->is_50hz = !itv->is_60hz;
@@ -1106,48 +1086,79 @@ int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
        if (itv->hw_flags & IVTV_HW_CX25840)
                itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284;
 
-       IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std);
-
        /* Tuner */
        ivtv_call_all(itv, core, s_std, itv->std);
+}
 
-       if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
-               /* set display standard */
-               itv->std_out = *std;
-               itv->is_out_60hz = itv->is_60hz;
-               itv->is_out_50hz = itv->is_50hz;
-               ivtv_call_all(itv, video, s_std_output, itv->std_out);
-
-               /*
-                * The next firmware call is time sensitive. Time it to
-                * avoid risk of a hard lock, by trying to ensure the call
-                * happens within the first 100 lines of the top field.
-                * Make 4 attempts to sync to the decoder before giving up.
-                */
-               for (f = 0; f < 4; f++) {
-                       prepare_to_wait(&itv->vsync_waitq, &wait,
-                                       TASK_UNINTERRUPTIBLE);
-                       if ((read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16) < 100)
-                               break;
-                       schedule_timeout(msecs_to_jiffies(25));
-               }
-               finish_wait(&itv->vsync_waitq, &wait);
-
-               if (f == 4)
-                       IVTV_WARN("Mode change failed to sync to decoder\n");
-
-               ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
-               itv->main_rect.left = itv->main_rect.top = 0;
-               itv->main_rect.width = 720;
-               itv->main_rect.height = itv->cxhdl.height;
-               ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
-                       720, itv->main_rect.height, 0, 0);
-               yi->main_rect = itv->main_rect;
-               if (!itv->osd_info) {
-                       yi->osd_full_w = 720;
-                       yi->osd_full_h = itv->is_out_50hz ? 576 : 480;
-               }
+void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std)
+{
+       struct yuv_playback_info *yi = &itv->yuv_info;
+       DEFINE_WAIT(wait);
+       int f;
+
+       /* set display standard */
+       itv->std_out = *std;
+       itv->is_out_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
+       itv->is_out_50hz = !itv->is_out_60hz;
+       ivtv_call_all(itv, video, s_std_output, itv->std_out);
+
+       /*
+        * The next firmware call is time sensitive. Time it to
+        * avoid risk of a hard lock, by trying to ensure the call
+        * happens within the first 100 lines of the top field.
+        * Make 4 attempts to sync to the decoder before giving up.
+        */
+       for (f = 0; f < 4; f++) {
+               prepare_to_wait(&itv->vsync_waitq, &wait,
+                               TASK_UNINTERRUPTIBLE);
+               if ((read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16) < 100)
+                       break;
+               schedule_timeout(msecs_to_jiffies(25));
        }
+       finish_wait(&itv->vsync_waitq, &wait);
+
+       if (f == 4)
+               IVTV_WARN("Mode change failed to sync to decoder\n");
+
+       ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
+       itv->main_rect.left = 0;
+       itv->main_rect.top = 0;
+       itv->main_rect.width = 720;
+       itv->main_rect.height = itv->is_out_50hz ? 576 : 480;
+       ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
+               720, itv->main_rect.height, 0, 0);
+       yi->main_rect = itv->main_rect;
+       if (!itv->osd_info) {
+               yi->osd_full_w = 720;
+               yi->osd_full_h = itv->is_out_50hz ? 576 : 480;
+       }
+}
+
+int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+       struct ivtv *itv = fh2id(fh)->itv;
+
+       if ((*std & V4L2_STD_ALL) == 0)
+               return -EINVAL;
+
+       if (*std == itv->std)
+               return 0;
+
+       if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ||
+           atomic_read(&itv->capturing) > 0 ||
+           atomic_read(&itv->decoding) > 0) {
+               /* Switching standard would mess with already running
+                  streams, prevent that by returning EBUSY. */
+               return -EBUSY;
+       }
+
+       IVTV_DEBUG_INFO("Switching standard to %llx.\n",
+               (unsigned long long)itv->std);
+
+       ivtv_s_std_enc(itv, std);
+       if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
+               ivtv_s_std_dec(itv, std);
+
        return 0;
 }
 
index 58f003412afdd5141a854c41779b80ad38a4884d..89185caeafae0a5c72c8423d6b3ad6b242947227 100644 (file)
@@ -27,7 +27,8 @@ u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt);
 void ivtv_set_osd_alpha(struct ivtv *itv);
 int ivtv_set_speed(struct ivtv *itv, int speed);
 void ivtv_set_funcs(struct video_device *vdev);
-int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std);
+void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std);
+void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std);
 int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
 int ivtv_s_input(struct file *file, void *fh, unsigned int inp);
 long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
index 942683336555e02311c6d0b1d63acdab633fc777..e7794dc1330e50348a5e358714abf9f54702e56d 100644 (file)
@@ -589,7 +589,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
                v4l2_subdev_call(itv->sd_audio, audio, s_stream, 1);
                /* Avoid unpredictable PCI bus hang - disable video clocks */
                v4l2_subdev_call(itv->sd_video, video, s_stream, 0);
-               ivtv_msleep_timeout(300, 1);
+               ivtv_msleep_timeout(300, 0);
                ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
                v4l2_subdev_call(itv->sd_video, video, s_stream, 1);
        }
@@ -834,7 +834,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
                }
 
                /* Handle any pending interrupts */
-               ivtv_msleep_timeout(100, 1);
+               ivtv_msleep_timeout(100, 0);
        }
 
        atomic_dec(&itv->capturing);
index b6eb51ce773503ad60031b999934253edbc39d67..293db806d9362b688f000ed90ed3475c0b85ae09 100644 (file)
@@ -71,7 +71,7 @@ static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
           Turning this signal on and off can confuse certain
           TVs. As far as I can tell there is no reason not to
           transmit this signal. */
-       if ((itv->std & V4L2_STD_625_50) && !enabled) {
+       if ((itv->std_out & V4L2_STD_625_50) && !enabled) {
                enabled = 1;
                mode = 0x08;  /* 4x3 full format */
        }
index 17247451c69326f3159cb6913e7eabaa152d72fc..6b7c9c8233309975726e42a65f97296df84cff54 100644 (file)
@@ -247,7 +247,7 @@ static int ivtvfb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords
 
 static int ivtvfb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
 {
-       int osd_height_limit = itv->is_50hz ? 576 : 480;
+       int osd_height_limit = itv->is_out_50hz ? 576 : 480;
 
        /* Only fail if resolution too high, otherwise fudge the start coords. */
        if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
@@ -471,9 +471,9 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar
                        vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
                                        FB_VBLANK_HAVE_VSYNC;
                        trace = read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16;
-                       if (itv->is_50hz && trace > 312)
+                       if (itv->is_out_50hz && trace > 312)
                                trace -= 312;
-                       else if (itv->is_60hz && trace > 262)
+                       else if (itv->is_out_60hz && trace > 262)
                                trace -= 262;
                        if (trace == 1)
                                vblank.flags |= FB_VBLANK_VSYNCING;
@@ -656,7 +656,7 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
        IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
 
        /* Set base references for mode calcs. */
-       if (itv->is_50hz) {
+       if (itv->is_out_50hz) {
                pixclock = 84316;
                hlimit = 776;
                vlimit = 591;
@@ -784,12 +784,12 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
           If the margins are too large, just center the screen
           (enforcing margins causes too many problems) */
 
-       if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) {
+       if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1)
                var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
-       }
-       if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) {
-               var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2);
-       }
+
+       if (var->upper_margin + var->yres > (itv->is_out_50hz ? 577 : 481))
+               var->upper_margin = 1 + (((itv->is_out_50hz ? 576 : 480) -
+                       var->yres) / 2);
 
        /* Maintain overall 'size' for a constant refresh rate */
        var->right_margin = hlimit - var->left_margin - var->xres;
@@ -836,7 +836,12 @@ static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *inf
        u32 osd_pan_index;
        struct ivtv *itv = (struct ivtv *) info->par;
 
-       osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8;
+       if (var->yoffset + info->var.yres > info->var.yres_virtual ||
+           var->xoffset + info->var.xres > info->var.xres_virtual)
+               return -EINVAL;
+
+       osd_pan_index = var->yoffset * info->fix.line_length
+                     + var->xoffset * info->var.bits_per_pixel / 8;
        write_reg(osd_pan_index, 0x02A0C);
 
        /* Pass this info back the yuv handler */
@@ -1003,19 +1008,21 @@ static int ivtvfb_init_vidmode(struct ivtv *itv)
        /* Hardware coords start at 0, user coords start at 1. */
        osd_left--;
 
-       start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
+       start_window.left = osd_left >= 0 ?
+                osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
 
        oi->display_byte_stride =
                        start_window.width * oi->bytes_per_pixel;
 
        /* Vertical size & position */
 
-       max_height = itv->is_50hz ? 576 : 480;
+       max_height = itv->is_out_50hz ? 576 : 480;
 
        if (osd_yres > max_height)
                osd_yres = max_height;
 
-       start_window.height = osd_yres ? osd_yres : itv->is_50hz ? 480 : 400;
+       start_window.height = osd_yres ?
+               osd_yres : itv->is_out_50hz ? 480 : 400;
 
        /* Check vertical start (osd_upper). */
        if (osd_upper + start_window.height > max_height + 1) {
diff --git a/drivers/media/video/m5mols/Kconfig b/drivers/media/video/m5mols/Kconfig
new file mode 100644 (file)
index 0000000..302dc3d
--- /dev/null
@@ -0,0 +1,5 @@
+config VIDEO_M5MOLS
+       tristate "Fujitsu M-5MOLS 8MP sensor support"
+       depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+       ---help---
+         This driver supports Fujitsu M-5MOLS camera sensor with ISP
diff --git a/drivers/media/video/m5mols/Makefile b/drivers/media/video/m5mols/Makefile
new file mode 100644 (file)
index 0000000..0a44e02
--- /dev/null
@@ -0,0 +1,3 @@
+m5mols-objs    := m5mols_core.o m5mols_controls.o m5mols_capture.o
+
+obj-$(CONFIG_VIDEO_M5MOLS)             += m5mols.o
diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h
new file mode 100644 (file)
index 0000000..10b55c8
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * Header for M-5MOLS 8M Pixel camera sensor with ISP
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Author: HeungJun Kim, riverful.kim@samsung.com
+ *
+ * Copyright (C) 2009 Samsung Electronics Co., Ltd.
+ * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.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.
+ */
+
+#ifndef M5MOLS_H
+#define M5MOLS_H
+
+#include <media/v4l2-subdev.h>
+#include "m5mols_reg.h"
+
+extern int m5mols_debug;
+
+#define to_m5mols(__sd)        container_of(__sd, struct m5mols_info, sd)
+
+#define to_sd(__ctrl) \
+       (&container_of(__ctrl->handler, struct m5mols_info, handle)->sd)
+
+enum m5mols_restype {
+       M5MOLS_RESTYPE_MONITOR,
+       M5MOLS_RESTYPE_CAPTURE,
+       M5MOLS_RESTYPE_MAX,
+};
+
+/**
+ * struct m5mols_resolution - structure for the resolution
+ * @type: resolution type according to the pixel code
+ * @width: width of the resolution
+ * @height: height of the resolution
+ * @reg: resolution preset register value
+ */
+struct m5mols_resolution {
+       u8 reg;
+       enum m5mols_restype type;
+       u16 width;
+       u16 height;
+};
+
+/**
+ * struct m5mols_exif - structure for the EXIF information of M-5MOLS
+ * @exposure_time: exposure time register value
+ * @shutter_speed: speed of the shutter register value
+ * @aperture: aperture register value
+ * @exposure_bias: it calls also EV bias
+ * @iso_speed: ISO register value
+ * @flash: status register value of the flash
+ * @sdr: status register value of the Subject Distance Range
+ * @qval: not written exact meaning in document
+ */
+struct m5mols_exif {
+       u32 exposure_time;
+       u32 shutter_speed;
+       u32 aperture;
+       u32 brightness;
+       u32 exposure_bias;
+       u16 iso_speed;
+       u16 flash;
+       u16 sdr;
+       u16 qval;
+};
+
+/**
+ * struct m5mols_capture - Structure for the capture capability
+ * @exif: EXIF information
+ * @main: size in bytes of the main image
+ * @thumb: size in bytes of the thumb image, if it was accompanied
+ * @total: total size in bytes of the produced image
+ */
+struct m5mols_capture {
+       struct m5mols_exif exif;
+       u32 main;
+       u32 thumb;
+       u32 total;
+};
+
+/**
+ * struct m5mols_scenemode - structure for the scenemode capability
+ * @metering: metering light register value
+ * @ev_bias: EV bias register value
+ * @wb_mode: mode which means the WhiteBalance is Auto or Manual
+ * @wb_preset: whitebalance preset register value in the Manual mode
+ * @chroma_en: register value whether the Chroma capability is enabled or not
+ * @chroma_lvl: chroma's level register value
+ * @edge_en: register value Whether the Edge capability is enabled or not
+ * @edge_lvl: edge's level register value
+ * @af_range: Auto Focus's range
+ * @fd_mode: Face Detection mode
+ * @mcc: Multi-axis Color Conversion which means emotion color
+ * @light: status of the Light
+ * @flash: status of the Flash
+ * @tone: Tone color which means Contrast
+ * @iso: ISO register value
+ * @capt_mode: Mode of the Image Stabilization while the camera capturing
+ * @wdr: Wide Dynamic Range register value
+ *
+ * The each value according to each scenemode is recommended in the documents.
+ */
+struct m5mols_scenemode {
+       u32 metering;
+       u32 ev_bias;
+       u32 wb_mode;
+       u32 wb_preset;
+       u32 chroma_en;
+       u32 chroma_lvl;
+       u32 edge_en;
+       u32 edge_lvl;
+       u32 af_range;
+       u32 fd_mode;
+       u32 mcc;
+       u32 light;
+       u32 flash;
+       u32 tone;
+       u32 iso;
+       u32 capt_mode;
+       u32 wdr;
+};
+
+/**
+ * struct m5mols_version - firmware version information
+ * @customer:  customer information
+ * @project:   version of project information according to customer
+ * @fw:                firmware revision
+ * @hw:                hardware revision
+ * @param:     version of the parameter
+ * @awb:       Auto WhiteBalance algorithm version
+ * @str:       information about manufacturer and packaging vendor
+ * @af:                Auto Focus version
+ *
+ * The register offset starts the customer version at 0x0, and it ends
+ * the awb version at 0x09. The customer, project information occupies 1 bytes
+ * each. And also the fw, hw, param, awb each requires 2 bytes. The str is
+ * unique string associated with firmware's version. It includes information
+ * about manufacturer and the vendor of the sensor's packaging. The least
+ * significant 2 bytes of the string indicate packaging manufacturer.
+ */
+#define VERSION_STRING_SIZE    22
+struct m5mols_version {
+       u8      customer;
+       u8      project;
+       u16     fw;
+       u16     hw;
+       u16     param;
+       u16     awb;
+       u8      str[VERSION_STRING_SIZE];
+       u8      af;
+};
+#define VERSION_SIZE sizeof(struct m5mols_version)
+
+/**
+ * struct m5mols_info - M-5MOLS driver data structure
+ * @pdata: platform data
+ * @sd: v4l-subdev instance
+ * @pad: media pad
+ * @ffmt: current fmt according to resolution type
+ * @res_type: current resolution type
+ * @code: current code
+ * @irq_waitq: waitqueue for the capture
+ * @work_irq: workqueue for the IRQ
+ * @flags: state variable for the interrupt handler
+ * @handle: control handler
+ * @autoexposure: Auto Exposure control
+ * @exposure: Exposure control
+ * @autowb: Auto White Balance control
+ * @colorfx: Color effect control
+ * @saturation:        Saturation control
+ * @zoom: Zoom control
+ * @ver: information of the version
+ * @cap: the capture mode attributes
+ * @power: current sensor's power status
+ * @ctrl_sync: true means all controls of the sensor are initialized
+ * @int_capture: true means the capture interrupt is issued once
+ * @lock_ae: true means the Auto Exposure is locked
+ * @lock_awb: true means the Aut WhiteBalance is locked
+ * @resolution:        register value for current resolution
+ * @interrupt: register value for current interrupt status
+ * @mode: register value for current operation mode
+ * @mode_save: register value for current operation mode for saving
+ * @set_power: optional power callback to the board code
+ */
+struct m5mols_info {
+       const struct m5mols_platform_data *pdata;
+       struct v4l2_subdev sd;
+       struct media_pad pad;
+       struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX];
+       int res_type;
+       enum v4l2_mbus_pixelcode code;
+       wait_queue_head_t irq_waitq;
+       struct work_struct work_irq;
+       unsigned long flags;
+
+       struct v4l2_ctrl_handler handle;
+       /* Autoexposure/exposure control cluster */
+       struct {
+               struct v4l2_ctrl *autoexposure;
+               struct v4l2_ctrl *exposure;
+       };
+       struct v4l2_ctrl *autowb;
+       struct v4l2_ctrl *colorfx;
+       struct v4l2_ctrl *saturation;
+       struct v4l2_ctrl *zoom;
+
+       struct m5mols_version ver;
+       struct m5mols_capture cap;
+       bool power;
+       bool ctrl_sync;
+       bool lock_ae;
+       bool lock_awb;
+       u8 resolution;
+       u32 interrupt;
+       u32 mode;
+       u32 mode_save;
+       int (*set_power)(struct device *dev, int on);
+};
+
+#define ST_CAPT_IRQ 0
+
+#define is_powered(__info) (__info->power)
+#define is_ctrl_synced(__info) (__info->ctrl_sync)
+#define is_available_af(__info)        (__info->ver.af)
+#define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code)
+#define is_manufacturer(__info, __manufacturer)        \
+                               (__info->ver.str[0] == __manufacturer[0] && \
+                                __info->ver.str[1] == __manufacturer[1])
+/*
+ * I2C operation of the M-5MOLS
+ *
+ * The I2C read operation of the M-5MOLS requires 2 messages. The first
+ * message sends the information about the command, command category, and total
+ * message size. The second message is used to retrieve the data specifed in
+ * the first message
+ *
+ *   1st message                                2nd message
+ *   +-------+---+----------+-----+-------+     +------+------+------+------+
+ *   | size1 | R | category | cmd | size2 |     | d[0] | d[1] | d[2] | d[3] |
+ *   +-------+---+----------+-----+-------+     +------+------+------+------+
+ *   - size1: message data size(5 in this case)
+ *   - size2: desired buffer size of the 2nd message
+ *   - d[0..3]: according to size2
+ *
+ * The I2C write operation needs just one message. The message includes
+ * category, command, total size, and desired data.
+ *
+ *   1st message
+ *   +-------+---+----------+-----+------+------+------+------+
+ *   | size1 | W | category | cmd | d[0] | d[1] | d[2] | d[3] |
+ *   +-------+---+----------+-----+------+------+------+------+
+ *   - d[0..3]: according to size1
+ */
+int m5mols_read(struct v4l2_subdev *sd, u32 reg_comb, u32 *val);
+int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val);
+int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 value);
+
+/*
+ * Mode operation of the M-5MOLS
+ *
+ * Changing the mode of the M-5MOLS is needed right executing order.
+ * There are three modes(PARAMETER, MONITOR, CAPTURE) which can be changed
+ * by user. There are various categories associated with each mode.
+ *
+ * +============================================================+
+ * | mode      | category                                      |
+ * +============================================================+
+ * | FLASH     | FLASH(only after Stand-by or Power-on)        |
+ * | SYSTEM    | SYSTEM(only after sensor arm-booting)         |
+ * | PARAMETER | PARAMETER                                     |
+ * | MONITOR   | MONITOR(preview), Auto Focus, Face Detection  |
+ * | CAPTURE   | Single CAPTURE, Preview(recording)            |
+ * +============================================================+
+ *
+ * The available executing order between each modes are as follows:
+ *   PARAMETER <---> MONITOR <---> CAPTURE
+ */
+int m5mols_mode(struct m5mols_info *info, u32 mode);
+
+int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg);
+int m5mols_sync_controls(struct m5mols_info *info);
+int m5mols_start_capture(struct m5mols_info *info);
+int m5mols_do_scenemode(struct m5mols_info *info, u32 mode);
+int m5mols_lock_3a(struct m5mols_info *info, bool lock);
+int m5mols_set_ctrl(struct v4l2_ctrl *ctrl);
+
+/* The firmware function */
+int m5mols_update_fw(struct v4l2_subdev *sd,
+                    int (*set_power)(struct m5mols_info *, bool));
+
+#endif /* M5MOLS_H */
diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c
new file mode 100644 (file)
index 0000000..d71a390
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * The Capture code for Fujitsu M-5MOLS ISP
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Author: HeungJun Kim, riverful.kim@samsung.com
+ *
+ * Copyright (C) 2009 Samsung Electronics Co., Ltd.
+ * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.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.
+ */
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/version.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/m5mols.h>
+
+#include "m5mols.h"
+#include "m5mols_reg.h"
+
+static int m5mols_capture_error_handler(struct m5mols_info *info,
+                                       int timeout)
+{
+       int ret;
+
+       /* Disable all interrupts and clear relevant interrupt staus bits */
+       ret = m5mols_write(&info->sd, SYSTEM_INT_ENABLE,
+                          info->interrupt & ~(REG_INT_CAPTURE));
+       if (ret)
+               return ret;
+
+       if (timeout == 0)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+/**
+ * m5mols_read_rational - I2C read of a rational number
+ *
+ * Read numerator and denominator from registers @addr_num and @addr_den
+ * respectively and return the division result in @val.
+ */
+static int m5mols_read_rational(struct v4l2_subdev *sd, u32 addr_num,
+                               u32 addr_den, u32 *val)
+{
+       u32 num, den;
+
+       int ret = m5mols_read(sd, addr_num, &num);
+       if (!ret)
+               ret = m5mols_read(sd, addr_den, &den);
+       if (ret)
+               return ret;
+       *val = den == 0 ? 0 : num / den;
+       return ret;
+}
+
+/**
+ * m5mols_capture_info - Gather captured image information
+ *
+ * For now it gathers only EXIF information and file size.
+ */
+static int m5mols_capture_info(struct m5mols_info *info)
+{
+       struct m5mols_exif *exif = &info->cap.exif;
+       struct v4l2_subdev *sd = &info->sd;
+       int ret;
+
+       ret = m5mols_read_rational(sd, EXIF_INFO_EXPTIME_NU,
+                                  EXIF_INFO_EXPTIME_DE, &exif->exposure_time);
+       if (ret)
+               return ret;
+       ret = m5mols_read_rational(sd, EXIF_INFO_TV_NU, EXIF_INFO_TV_DE,
+                                  &exif->shutter_speed);
+       if (ret)
+               return ret;
+       ret = m5mols_read_rational(sd, EXIF_INFO_AV_NU, EXIF_INFO_AV_DE,
+                                  &exif->aperture);
+       if (ret)
+               return ret;
+       ret = m5mols_read_rational(sd, EXIF_INFO_BV_NU, EXIF_INFO_BV_DE,
+                                  &exif->brightness);
+       if (ret)
+               return ret;
+       ret = m5mols_read_rational(sd, EXIF_INFO_EBV_NU, EXIF_INFO_EBV_DE,
+                                  &exif->exposure_bias);
+       if (ret)
+               return ret;
+
+       ret = m5mols_read(sd, EXIF_INFO_ISO, (u32 *)&exif->iso_speed);
+       if (!ret)
+               ret = m5mols_read(sd, EXIF_INFO_FLASH, (u32 *)&exif->flash);
+       if (!ret)
+               ret = m5mols_read(sd, EXIF_INFO_SDR, (u32 *)&exif->sdr);
+       if (!ret)
+               ret = m5mols_read(sd, EXIF_INFO_QVAL, (u32 *)&exif->qval);
+       if (ret)
+               return ret;
+
+       if (!ret)
+               ret = m5mols_read(sd, CAPC_IMAGE_SIZE, &info->cap.main);
+       if (!ret)
+               ret = m5mols_read(sd, CAPC_THUMB_SIZE, &info->cap.thumb);
+       if (!ret)
+               info->cap.total = info->cap.main + info->cap.thumb;
+
+       return ret;
+}
+
+int m5mols_start_capture(struct m5mols_info *info)
+{
+       struct v4l2_subdev *sd = &info->sd;
+       u32 resolution = info->resolution;
+       int timeout;
+       int ret;
+
+       /*
+        * Preparing capture. Setting control & interrupt before entering
+        * capture mode
+        *
+        * 1) change to MONITOR mode for operating control & interrupt
+        * 2) set controls (considering v4l2_control value & lock 3A)
+        * 3) set interrupt
+        * 4) change to CAPTURE mode
+        */
+       ret = m5mols_mode(info, REG_MONITOR);
+       if (!ret)
+               ret = m5mols_sync_controls(info);
+       if (!ret)
+               ret = m5mols_lock_3a(info, true);
+       if (!ret)
+               ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE);
+       if (!ret)
+               ret = m5mols_mode(info, REG_CAPTURE);
+       if (!ret) {
+               /* Wait for capture interrupt, after changing capture mode */
+               timeout = wait_event_interruptible_timeout(info->irq_waitq,
+                                          test_bit(ST_CAPT_IRQ, &info->flags),
+                                          msecs_to_jiffies(2000));
+               if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags))
+                       ret = m5mols_capture_error_handler(info, timeout);
+       }
+       if (!ret)
+               ret = m5mols_lock_3a(info, false);
+       if (ret)
+               return ret;
+       /*
+        * Starting capture. Setting capture frame count and resolution and
+        * the format(available format: JPEG, Bayer RAW, YUV).
+        *
+        * 1) select single or multi(enable to 25), format, size
+        * 2) set interrupt
+        * 3) start capture(for main image, now)
+        * 4) get information
+        * 5) notify file size to v4l2 device(e.g, to s5p-fimc v4l2 device)
+        */
+       ret = m5mols_write(sd, CAPC_SEL_FRAME, 1);
+       if (!ret)
+               ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG);
+       if (!ret)
+               ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution);
+       if (!ret)
+               ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE);
+       if (!ret)
+               ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN);
+       if (!ret) {
+               /* Wait for the capture completion interrupt */
+               timeout = wait_event_interruptible_timeout(info->irq_waitq,
+                                          test_bit(ST_CAPT_IRQ, &info->flags),
+                                          msecs_to_jiffies(2000));
+               if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) {
+                       ret = m5mols_capture_info(info);
+                       if (!ret)
+                               v4l2_subdev_notify(sd, 0, &info->cap.total);
+               }
+       }
+
+       return m5mols_capture_error_handler(info, timeout);
+}
diff --git a/drivers/media/video/m5mols/m5mols_controls.c b/drivers/media/video/m5mols/m5mols_controls.c
new file mode 100644 (file)
index 0000000..817c16f
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * Controls for M-5MOLS 8M Pixel camera sensor with ISP
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Author: HeungJun Kim, riverful.kim@samsung.com
+ *
+ * Copyright (C) 2009 Samsung Electronics Co., Ltd.
+ * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.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.
+ */
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+
+#include "m5mols.h"
+#include "m5mols_reg.h"
+
+static struct m5mols_scenemode m5mols_default_scenemode[] = {
+       [REG_SCENE_NORMAL] = {
+               REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+               REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+               REG_AF_NORMAL, REG_FD_OFF,
+               REG_MCC_NORMAL, REG_LIGHT_OFF, REG_FLASH_OFF,
+               5, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+       },
+       [REG_SCENE_PORTRAIT] = {
+               REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+               REG_CHROMA_ON, 3, REG_EDGE_ON, 4,
+               REG_AF_NORMAL, BIT_FD_EN | BIT_FD_DRAW_FACE_FRAME,
+               REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+               6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+       },
+       [REG_SCENE_LANDSCAPE] = {
+               REG_AE_ALL, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+               REG_CHROMA_ON, 4, REG_EDGE_ON, 6,
+               REG_AF_NORMAL, REG_FD_OFF,
+               REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+               6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+       },
+       [REG_SCENE_SPORTS] = {
+               REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+               REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+               REG_AF_NORMAL, REG_FD_OFF,
+               REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+               6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+       },
+       [REG_SCENE_PARTY_INDOOR] = {
+               REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+               REG_CHROMA_ON, 4, REG_EDGE_ON, 5,
+               REG_AF_NORMAL, REG_FD_OFF,
+               REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+               6, REG_ISO_200, REG_CAP_NONE, REG_WDR_OFF,
+       },
+       [REG_SCENE_BEACH_SNOW] = {
+               REG_AE_CENTER, REG_AE_INDEX_10_POS, REG_AWB_AUTO, 0,
+               REG_CHROMA_ON, 4, REG_EDGE_ON, 5,
+               REG_AF_NORMAL, REG_FD_OFF,
+               REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+               6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF,
+       },
+       [REG_SCENE_SUNSET] = {
+               REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET,
+               REG_AWB_DAYLIGHT,
+               REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+               REG_AF_NORMAL, REG_FD_OFF,
+               REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+               6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+       },
+       [REG_SCENE_DAWN_DUSK] = {
+               REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET,
+               REG_AWB_FLUORESCENT_1,
+               REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+               REG_AF_NORMAL, REG_FD_OFF,
+               REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+               6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+       },
+       [REG_SCENE_FALL] = {
+               REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+               REG_CHROMA_ON, 5, REG_EDGE_ON, 5,
+               REG_AF_NORMAL, REG_FD_OFF,
+               REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+               6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+       },
+       [REG_SCENE_NIGHT] = {
+               REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+               REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+               REG_AF_NORMAL, REG_FD_OFF,
+               REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+               6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+       },
+       [REG_SCENE_AGAINST_LIGHT] = {
+               REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+               REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+               REG_AF_NORMAL, REG_FD_OFF,
+               REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+               6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+       },
+       [REG_SCENE_FIRE] = {
+               REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+               REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+               REG_AF_NORMAL, REG_FD_OFF,
+               REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+               6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF,
+       },
+       [REG_SCENE_TEXT] = {
+               REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+               REG_CHROMA_ON, 3, REG_EDGE_ON, 7,
+               REG_AF_MACRO, REG_FD_OFF,
+               REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+               6, REG_ISO_AUTO, REG_CAP_ANTI_SHAKE, REG_WDR_ON,
+       },
+       [REG_SCENE_CANDLE] = {
+               REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+               REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+               REG_AF_NORMAL, REG_FD_OFF,
+               REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+               6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+       },
+};
+
+/**
+ * m5mols_do_scenemode() - Change current scenemode
+ * @mode:      Desired mode of the scenemode
+ *
+ * WARNING: The execution order is important. Do not change the order.
+ */
+int m5mols_do_scenemode(struct m5mols_info *info, u32 mode)
+{
+       struct v4l2_subdev *sd = &info->sd;
+       struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode];
+       int ret;
+
+       if (mode > REG_SCENE_CANDLE)
+               return -EINVAL;
+
+       ret = m5mols_lock_3a(info, false);
+       if (!ret)
+               ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode);
+       if (!ret)
+               ret = m5mols_write(sd, AE_EV_PRESET_CAPTURE, mode);
+       if (!ret)
+               ret = m5mols_write(sd, AE_MODE, scenemode.metering);
+       if (!ret)
+               ret = m5mols_write(sd, AE_INDEX, scenemode.ev_bias);
+       if (!ret)
+               ret = m5mols_write(sd, AWB_MODE, scenemode.wb_mode);
+       if (!ret)
+               ret = m5mols_write(sd, AWB_MANUAL, scenemode.wb_preset);
+       if (!ret)
+               ret = m5mols_write(sd, MON_CHROMA_EN, scenemode.chroma_en);
+       if (!ret)
+               ret = m5mols_write(sd, MON_CHROMA_LVL, scenemode.chroma_lvl);
+       if (!ret)
+               ret = m5mols_write(sd, MON_EDGE_EN, scenemode.edge_en);
+       if (!ret)
+               ret = m5mols_write(sd, MON_EDGE_LVL, scenemode.edge_lvl);
+       if (!ret && is_available_af(info))
+               ret = m5mols_write(sd, AF_MODE, scenemode.af_range);
+       if (!ret && is_available_af(info))
+               ret = m5mols_write(sd, FD_CTL, scenemode.fd_mode);
+       if (!ret)
+               ret = m5mols_write(sd, MON_TONE_CTL, scenemode.tone);
+       if (!ret)
+               ret = m5mols_write(sd, AE_ISO, scenemode.iso);
+       if (!ret)
+               ret = m5mols_mode(info, REG_CAPTURE);
+       if (!ret)
+               ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr);
+       if (!ret)
+               ret = m5mols_write(sd, CAPP_MCC_MODE, scenemode.mcc);
+       if (!ret)
+               ret = m5mols_write(sd, CAPP_LIGHT_CTRL, scenemode.light);
+       if (!ret)
+               ret = m5mols_write(sd, CAPP_FLASH_CTRL, scenemode.flash);
+       if (!ret)
+               ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode);
+       if (!ret)
+               ret = m5mols_mode(info, REG_MONITOR);
+
+       return ret;
+}
+
+static int m5mols_lock_ae(struct m5mols_info *info, bool lock)
+{
+       int ret = 0;
+
+       if (info->lock_ae != lock)
+               ret = m5mols_write(&info->sd, AE_LOCK,
+                               lock ? REG_AE_LOCK : REG_AE_UNLOCK);
+       if (!ret)
+               info->lock_ae = lock;
+
+       return ret;
+}
+
+static int m5mols_lock_awb(struct m5mols_info *info, bool lock)
+{
+       int ret = 0;
+
+       if (info->lock_awb != lock)
+               ret = m5mols_write(&info->sd, AWB_LOCK,
+                               lock ? REG_AWB_LOCK : REG_AWB_UNLOCK);
+       if (!ret)
+               info->lock_awb = lock;
+
+       return ret;
+}
+
+/* m5mols_lock_3a() - Lock 3A(Auto Exposure, Auto Whitebalance, Auto Focus) */
+int m5mols_lock_3a(struct m5mols_info *info, bool lock)
+{
+       int ret;
+
+       ret = m5mols_lock_ae(info, lock);
+       if (!ret)
+               ret = m5mols_lock_awb(info, lock);
+       /* Don't need to handle unlocking AF */
+       if (!ret && is_available_af(info) && lock)
+               ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP);
+
+       return ret;
+}
+
+/* m5mols_set_ctrl() - The main s_ctrl function called by m5mols_set_ctrl() */
+int m5mols_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct v4l2_subdev *sd = to_sd(ctrl);
+       struct m5mols_info *info = to_m5mols(sd);
+       int ret;
+
+       switch (ctrl->id) {
+       case V4L2_CID_ZOOM_ABSOLUTE:
+               return m5mols_write(sd, MON_ZOOM, ctrl->val);
+
+       case V4L2_CID_EXPOSURE_AUTO:
+               ret = m5mols_lock_ae(info,
+                       ctrl->val == V4L2_EXPOSURE_AUTO ? false : true);
+               if (!ret && ctrl->val == V4L2_EXPOSURE_AUTO)
+                       ret = m5mols_write(sd, AE_MODE, REG_AE_ALL);
+               if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) {
+                       int val = info->exposure->val;
+                       ret = m5mols_write(sd, AE_MODE, REG_AE_OFF);
+                       if (!ret)
+                               ret = m5mols_write(sd, AE_MAN_GAIN_MON, val);
+                       if (!ret)
+                               ret = m5mols_write(sd, AE_MAN_GAIN_CAP, val);
+               }
+               return ret;
+
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               ret = m5mols_lock_awb(info, ctrl->val ? false : true);
+               if (!ret)
+                       ret = m5mols_write(sd, AWB_MODE, ctrl->val ?
+                               REG_AWB_AUTO : REG_AWB_PRESET);
+               return ret;
+
+       case V4L2_CID_SATURATION:
+               ret = m5mols_write(sd, MON_CHROMA_LVL, ctrl->val);
+               if (!ret)
+                       ret = m5mols_write(sd, MON_CHROMA_EN, REG_CHROMA_ON);
+               return ret;
+
+       case V4L2_CID_COLORFX:
+               /*
+                * This control uses two kinds of registers: normal & color.
+                * The normal effect belongs to category 1, while the color
+                * one belongs to category 2.
+                *
+                * The normal effect uses one register: CAT1_EFFECT.
+                * The color effect uses three registers:
+                * CAT2_COLOR_EFFECT, CAT2_CFIXR, CAT2_CFIXB.
+                */
+               ret = m5mols_write(sd, PARM_EFFECT,
+                       ctrl->val == V4L2_COLORFX_NEGATIVE ? REG_EFFECT_NEGA :
+                       ctrl->val == V4L2_COLORFX_EMBOSS ? REG_EFFECT_EMBOSS :
+                       REG_EFFECT_OFF);
+               if (!ret)
+                       ret = m5mols_write(sd, MON_EFFECT,
+                               ctrl->val == V4L2_COLORFX_SEPIA ?
+                               REG_COLOR_EFFECT_ON : REG_COLOR_EFFECT_OFF);
+               if (!ret)
+                       ret = m5mols_write(sd, MON_CFIXR,
+                               ctrl->val == V4L2_COLORFX_SEPIA ?
+                               REG_CFIXR_SEPIA : 0);
+               if (!ret)
+                       ret = m5mols_write(sd, MON_CFIXB,
+                               ctrl->val == V4L2_COLORFX_SEPIA ?
+                               REG_CFIXB_SEPIA : 0);
+               return ret;
+       }
+
+       return -EINVAL;
+}
diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c
new file mode 100644 (file)
index 0000000..76eac26
--- /dev/null
@@ -0,0 +1,1004 @@
+/*
+ * Driver for M-5MOLS 8M Pixel camera sensor with ISP
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Author: HeungJun Kim, riverful.kim@samsung.com
+ *
+ * Copyright (C) 2009 Samsung Electronics Co., Ltd.
+ * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.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.
+ */
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/m5mols.h>
+
+#include "m5mols.h"
+#include "m5mols_reg.h"
+
+int m5mols_debug;
+module_param(m5mols_debug, int, 0644);
+
+#define MODULE_NAME            "M5MOLS"
+#define M5MOLS_I2C_CHECK_RETRY 500
+
+/* The regulator consumer names for external voltage regulators */
+static struct regulator_bulk_data supplies[] = {
+       {
+               .supply = "core",       /* ARM core power, 1.2V */
+       }, {
+               .supply = "dig_18",     /* digital power 1, 1.8V */
+       }, {
+               .supply = "d_sensor",   /* sensor power 1, 1.8V */
+       }, {
+               .supply = "dig_28",     /* digital power 2, 2.8V */
+       }, {
+               .supply = "a_sensor",   /* analog power */
+       }, {
+               .supply = "dig_12",     /* digital power 3, 1.2V */
+       },
+};
+
+static struct v4l2_mbus_framefmt m5mols_default_ffmt[M5MOLS_RESTYPE_MAX] = {
+       [M5MOLS_RESTYPE_MONITOR] = {
+               .width          = 1920,
+               .height         = 1080,
+               .code           = V4L2_MBUS_FMT_VYUY8_2X8,
+               .field          = V4L2_FIELD_NONE,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+       },
+       [M5MOLS_RESTYPE_CAPTURE] = {
+               .width          = 1920,
+               .height         = 1080,
+               .code           = V4L2_MBUS_FMT_JPEG_1X8,
+               .field          = V4L2_FIELD_NONE,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+       },
+};
+#define SIZE_DEFAULT_FFMT      ARRAY_SIZE(m5mols_default_ffmt)
+
+static const struct m5mols_resolution m5mols_reg_res[] = {
+       { 0x01, M5MOLS_RESTYPE_MONITOR, 128, 96 },      /* SUB-QCIF */
+       { 0x03, M5MOLS_RESTYPE_MONITOR, 160, 120 },     /* QQVGA */
+       { 0x05, M5MOLS_RESTYPE_MONITOR, 176, 144 },     /* QCIF */
+       { 0x06, M5MOLS_RESTYPE_MONITOR, 176, 176 },
+       { 0x08, M5MOLS_RESTYPE_MONITOR, 240, 320 },     /* QVGA */
+       { 0x09, M5MOLS_RESTYPE_MONITOR, 320, 240 },     /* QVGA */
+       { 0x0c, M5MOLS_RESTYPE_MONITOR, 240, 400 },     /* WQVGA */
+       { 0x0d, M5MOLS_RESTYPE_MONITOR, 400, 240 },     /* WQVGA */
+       { 0x0e, M5MOLS_RESTYPE_MONITOR, 352, 288 },     /* CIF */
+       { 0x13, M5MOLS_RESTYPE_MONITOR, 480, 360 },
+       { 0x15, M5MOLS_RESTYPE_MONITOR, 640, 360 },     /* qHD */
+       { 0x17, M5MOLS_RESTYPE_MONITOR, 640, 480 },     /* VGA */
+       { 0x18, M5MOLS_RESTYPE_MONITOR, 720, 480 },
+       { 0x1a, M5MOLS_RESTYPE_MONITOR, 800, 480 },     /* WVGA */
+       { 0x1f, M5MOLS_RESTYPE_MONITOR, 800, 600 },     /* SVGA */
+       { 0x21, M5MOLS_RESTYPE_MONITOR, 1280, 720 },    /* HD */
+       { 0x25, M5MOLS_RESTYPE_MONITOR, 1920, 1080 },   /* 1080p */
+       { 0x29, M5MOLS_RESTYPE_MONITOR, 3264, 2448 },   /* 2.63fps 8M */
+       { 0x39, M5MOLS_RESTYPE_MONITOR, 800, 602 },     /* AHS_MON debug */
+
+       { 0x02, M5MOLS_RESTYPE_CAPTURE, 320, 240 },     /* QVGA */
+       { 0x04, M5MOLS_RESTYPE_CAPTURE, 400, 240 },     /* WQVGA */
+       { 0x07, M5MOLS_RESTYPE_CAPTURE, 480, 360 },
+       { 0x08, M5MOLS_RESTYPE_CAPTURE, 640, 360 },     /* qHD */
+       { 0x09, M5MOLS_RESTYPE_CAPTURE, 640, 480 },     /* VGA */
+       { 0x0a, M5MOLS_RESTYPE_CAPTURE, 800, 480 },     /* WVGA */
+       { 0x10, M5MOLS_RESTYPE_CAPTURE, 1280, 720 },    /* HD */
+       { 0x14, M5MOLS_RESTYPE_CAPTURE, 1280, 960 },    /* 1M */
+       { 0x17, M5MOLS_RESTYPE_CAPTURE, 1600, 1200 },   /* 2M */
+       { 0x19, M5MOLS_RESTYPE_CAPTURE, 1920, 1080 },   /* Full-HD */
+       { 0x1a, M5MOLS_RESTYPE_CAPTURE, 2048, 1152 },   /* 3Mega */
+       { 0x1b, M5MOLS_RESTYPE_CAPTURE, 2048, 1536 },
+       { 0x1c, M5MOLS_RESTYPE_CAPTURE, 2560, 1440 },   /* 4Mega */
+       { 0x1d, M5MOLS_RESTYPE_CAPTURE, 2560, 1536 },
+       { 0x1f, M5MOLS_RESTYPE_CAPTURE, 2560, 1920 },   /* 5Mega */
+       { 0x21, M5MOLS_RESTYPE_CAPTURE, 3264, 1836 },   /* 6Mega */
+       { 0x22, M5MOLS_RESTYPE_CAPTURE, 3264, 1960 },
+       { 0x25, M5MOLS_RESTYPE_CAPTURE, 3264, 2448 },   /* 8Mega */
+};
+
+/**
+ * m5mols_swap_byte - an byte array to integer conversion function
+ * @size: size in bytes of I2C packet defined in the M-5MOLS datasheet
+ *
+ * Convert I2C data byte array with performing any required byte
+ * reordering to assure proper values for each data type, regardless
+ * of the architecture endianness.
+ */
+static u32 m5mols_swap_byte(u8 *data, u8 length)
+{
+       if (length == 1)
+               return *data;
+       else if (length == 2)
+               return be16_to_cpu(*((u16 *)data));
+       else
+               return be32_to_cpu(*((u32 *)data));
+}
+
+/**
+ * m5mols_read -  I2C read function
+ * @reg: combination of size, category and command for the I2C packet
+ * @val: read value
+ */
+int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1];
+       u8 size = I2C_SIZE(reg);
+       u8 category = I2C_CATEGORY(reg);
+       u8 cmd = I2C_COMMAND(reg);
+       struct i2c_msg msg[2];
+       u8 wbuf[5];
+       int ret;
+
+       if (!client->adapter)
+               return -ENODEV;
+
+       if (size != 1 && size != 2 && size != 4) {
+               v4l2_err(sd, "Wrong data size\n");
+               return -EINVAL;
+       }
+
+       msg[0].addr = client->addr;
+       msg[0].flags = 0;
+       msg[0].len = 5;
+       msg[0].buf = wbuf;
+       wbuf[0] = 5;
+       wbuf[1] = M5MOLS_BYTE_READ;
+       wbuf[2] = category;
+       wbuf[3] = cmd;
+       wbuf[4] = size;
+
+       msg[1].addr = client->addr;
+       msg[1].flags = I2C_M_RD;
+       msg[1].len = size + 1;
+       msg[1].buf = rbuf;
+
+       /* minimum stabilization time */
+       usleep_range(200, 200);
+
+       ret = i2c_transfer(client->adapter, msg, 2);
+       if (ret < 0) {
+               v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n",
+                        size, category, cmd, ret);
+               return ret;
+       }
+
+       *val = m5mols_swap_byte(&rbuf[1], size);
+
+       return 0;
+}
+
+/**
+ * m5mols_write - I2C command write function
+ * @reg: combination of size, category and command for the I2C packet
+ * @val: value to write
+ */
+int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4];
+       u8 category = I2C_CATEGORY(reg);
+       u8 cmd = I2C_COMMAND(reg);
+       u8 size = I2C_SIZE(reg);
+       u32 *buf = (u32 *)&wbuf[4];
+       struct i2c_msg msg[1];
+       int ret;
+
+       if (!client->adapter)
+               return -ENODEV;
+
+       if (size != 1 && size != 2 && size != 4) {
+               v4l2_err(sd, "Wrong data size\n");
+               return -EINVAL;
+       }
+
+       msg->addr = client->addr;
+       msg->flags = 0;
+       msg->len = (u16)size + 4;
+       msg->buf = wbuf;
+       wbuf[0] = size + 4;
+       wbuf[1] = M5MOLS_BYTE_WRITE;
+       wbuf[2] = category;
+       wbuf[3] = cmd;
+
+       *buf = m5mols_swap_byte((u8 *)&val, size);
+
+       usleep_range(200, 200);
+
+       ret = i2c_transfer(client->adapter, msg, 1);
+       if (ret < 0) {
+               v4l2_err(sd, "write failed: size:%d cat:%02x cmd:%02x. %d\n",
+                       size, category, cmd, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 mask)
+{
+       u32 busy, i;
+       int ret;
+
+       for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) {
+               ret = m5mols_read(sd, I2C_REG(category, cmd, 1), &busy);
+               if (ret < 0)
+                       return ret;
+               if ((busy & mask) == mask)
+                       return 0;
+       }
+       return -EBUSY;
+}
+
+/**
+ * m5mols_enable_interrupt - Clear interrupt pending bits and unmask interrupts
+ *
+ * Before writing desired interrupt value the INT_FACTOR register should
+ * be read to clear pending interrupts.
+ */
+int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg)
+{
+       struct m5mols_info *info = to_m5mols(sd);
+       u32 mask = is_available_af(info) ? REG_INT_AF : 0;
+       u32 dummy;
+       int ret;
+
+       ret = m5mols_read(sd, SYSTEM_INT_FACTOR, &dummy);
+       if (!ret)
+               ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask);
+       return ret;
+}
+
+/**
+ * m5mols_reg_mode - Write the mode and check busy status
+ *
+ * It always accompanies a little delay changing the M-5MOLS mode, so it is
+ * needed checking current busy status to guarantee right mode.
+ */
+static int m5mols_reg_mode(struct v4l2_subdev *sd, u32 mode)
+{
+       int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode);
+
+       return ret ? ret : m5mols_busy(sd, CAT_SYSTEM, CAT0_SYSMODE, mode);
+}
+
+/**
+ * m5mols_mode - manage the M-5MOLS's mode
+ * @mode: the required operation mode
+ *
+ * The commands of M-5MOLS are grouped into specific modes. Each functionality
+ * can be guaranteed only when the sensor is operating in mode which which
+ * a command belongs to.
+ */
+int m5mols_mode(struct m5mols_info *info, u32 mode)
+{
+       struct v4l2_subdev *sd = &info->sd;
+       int ret = -EINVAL;
+       u32 reg;
+
+       if (mode < REG_PARAMETER && mode > REG_CAPTURE)
+               return ret;
+
+       ret = m5mols_read(sd, SYSTEM_SYSMODE, &reg);
+       if ((!ret && reg == mode) || ret)
+               return ret;
+
+       switch (reg) {
+       case REG_PARAMETER:
+               ret = m5mols_reg_mode(sd, REG_MONITOR);
+               if (!ret && mode == REG_MONITOR)
+                       break;
+               if (!ret)
+                       ret = m5mols_reg_mode(sd, REG_CAPTURE);
+               break;
+
+       case REG_MONITOR:
+               if (mode == REG_PARAMETER) {
+                       ret = m5mols_reg_mode(sd, REG_PARAMETER);
+                       break;
+               }
+
+               ret = m5mols_reg_mode(sd, REG_CAPTURE);
+               break;
+
+       case REG_CAPTURE:
+               ret = m5mols_reg_mode(sd, REG_MONITOR);
+               if (!ret && mode == REG_MONITOR)
+                       break;
+               if (!ret)
+                       ret = m5mols_reg_mode(sd, REG_PARAMETER);
+               break;
+
+       default:
+               v4l2_warn(sd, "Wrong mode: %d\n", mode);
+       }
+
+       if (!ret)
+               info->mode = mode;
+
+       return ret;
+}
+
+/**
+ * m5mols_get_version - retrieve full revisions information of M-5MOLS
+ *
+ * The version information includes revisions of hardware and firmware,
+ * AutoFocus alghorithm version and the version string.
+ */
+static int m5mols_get_version(struct v4l2_subdev *sd)
+{
+       struct m5mols_info *info = to_m5mols(sd);
+       union {
+               struct m5mols_version ver;
+               u8 bytes[VERSION_SIZE];
+       } version;
+       u32 *value;
+       u8 cmd = CAT0_VER_CUSTOMER;
+       int ret;
+
+       do {
+               value = (u32 *)&version.bytes[cmd];
+               ret = m5mols_read(sd, SYSTEM_CMD(cmd), value);
+               if (ret)
+                       return ret;
+       } while (cmd++ != CAT0_VER_AWB);
+
+       do {
+               value = (u32 *)&version.bytes[cmd];
+               ret = m5mols_read(sd, SYSTEM_VER_STRING, value);
+               if (ret)
+                       return ret;
+               if (cmd >= VERSION_SIZE - 1)
+                       return -EINVAL;
+       } while (version.bytes[cmd++]);
+
+       value = (u32 *)&version.bytes[cmd];
+       ret = m5mols_read(sd, AF_VERSION, value);
+       if (ret)
+               return ret;
+
+       /* store version information swapped for being readable */
+       info->ver       = version.ver;
+       info->ver.fw    = be16_to_cpu(info->ver.fw);
+       info->ver.hw    = be16_to_cpu(info->ver.hw);
+       info->ver.param = be16_to_cpu(info->ver.param);
+       info->ver.awb   = be16_to_cpu(info->ver.awb);
+
+       v4l2_info(sd, "Manufacturer\t[%s]\n",
+                       is_manufacturer(info, REG_SAMSUNG_ELECTRO) ?
+                       "Samsung Electro-Machanics" :
+                       is_manufacturer(info, REG_SAMSUNG_OPTICS) ?
+                       "Samsung Fiber-Optics" :
+                       is_manufacturer(info, REG_SAMSUNG_TECHWIN) ?
+                       "Samsung Techwin" : "None");
+       v4l2_info(sd, "Customer/Project\t[0x%02x/0x%02x]\n",
+                       info->ver.customer, info->ver.project);
+
+       if (!is_available_af(info))
+               v4l2_info(sd, "No support Auto Focus on this firmware\n");
+
+       return ret;
+}
+
+/**
+ * __find_restype - Lookup M-5MOLS resolution type according to pixel code
+ * @code: pixel code
+ */
+static enum m5mols_restype __find_restype(enum v4l2_mbus_pixelcode code)
+{
+       enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR;
+
+       do {
+               if (code == m5mols_default_ffmt[type].code)
+                       return type;
+       } while (type++ != SIZE_DEFAULT_FFMT);
+
+       return 0;
+}
+
+/**
+ * __find_resolution - Lookup preset and type of M-5MOLS's resolution
+ * @mf: pixel format to find/negotiate the resolution preset for
+ * @type: M-5MOLS resolution type
+ * @resolution:        M-5MOLS resolution preset register value
+ *
+ * Find nearest resolution matching resolution preset and adjust mf
+ * to supported values.
+ */
+static int __find_resolution(struct v4l2_subdev *sd,
+                            struct v4l2_mbus_framefmt *mf,
+                            enum m5mols_restype *type,
+                            u32 *resolution)
+{
+       const struct m5mols_resolution *fsize = &m5mols_reg_res[0];
+       const struct m5mols_resolution *match = NULL;
+       enum m5mols_restype stype = __find_restype(mf->code);
+       int i = ARRAY_SIZE(m5mols_reg_res);
+       unsigned int min_err = ~0;
+
+       while (i--) {
+               int err;
+               if (stype == fsize->type) {
+                       err = abs(fsize->width - mf->width)
+                               + abs(fsize->height - mf->height);
+
+                       if (err < min_err) {
+                               min_err = err;
+                               match = fsize;
+                       }
+               }
+               fsize++;
+       }
+       if (match) {
+               mf->width  = match->width;
+               mf->height = match->height;
+               *resolution = match->reg;
+               *type = stype;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info,
+                               struct v4l2_subdev_fh *fh,
+                               enum v4l2_subdev_format_whence which,
+                               enum m5mols_restype type)
+{
+       if (which == V4L2_SUBDEV_FORMAT_TRY)
+               return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL;
+
+       return &info->ffmt[type];
+}
+
+static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                         struct v4l2_subdev_format *fmt)
+{
+       struct m5mols_info *info = to_m5mols(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       if (fmt->pad != 0)
+               return -EINVAL;
+
+       format = __find_format(info, fh, fmt->which, info->res_type);
+       if (!format)
+               return -EINVAL;
+
+       fmt->format = *format;
+       return 0;
+}
+
+static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                         struct v4l2_subdev_format *fmt)
+{
+       struct m5mols_info *info = to_m5mols(sd);
+       struct v4l2_mbus_framefmt *format = &fmt->format;
+       struct v4l2_mbus_framefmt *sfmt;
+       enum m5mols_restype type;
+       u32 resolution = 0;
+       int ret;
+
+       if (fmt->pad != 0)
+               return -EINVAL;
+
+       ret = __find_resolution(sd, format, &type, &resolution);
+       if (ret < 0)
+               return ret;
+
+       sfmt = __find_format(info, fh, fmt->which, type);
+       if (!sfmt)
+               return 0;
+
+       *sfmt           = m5mols_default_ffmt[type];
+       sfmt->width     = format->width;
+       sfmt->height    = format->height;
+
+       if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+               info->resolution = resolution;
+               info->code = format->code;
+               info->res_type = type;
+       }
+
+       return 0;
+}
+
+static int m5mols_enum_mbus_code(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_fh *fh,
+                                struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (!code || code->index >= SIZE_DEFAULT_FFMT)
+               return -EINVAL;
+
+       code->code = m5mols_default_ffmt[code->index].code;
+
+       return 0;
+}
+
+static struct v4l2_subdev_pad_ops m5mols_pad_ops = {
+       .enum_mbus_code = m5mols_enum_mbus_code,
+       .get_fmt        = m5mols_get_fmt,
+       .set_fmt        = m5mols_set_fmt,
+};
+
+/**
+ * m5mols_sync_controls - Apply default scene mode and the current controls
+ *
+ * This is used only streaming for syncing between v4l2_ctrl framework and
+ * m5mols's controls. First, do the scenemode to the sensor, then call
+ * v4l2_ctrl_handler_setup. It can be same between some commands and
+ * the scenemode's in the default v4l2_ctrls. But, such commands of control
+ * should be prior to the scenemode's one.
+ */
+int m5mols_sync_controls(struct m5mols_info *info)
+{
+       int ret = -EINVAL;
+
+       if (!is_ctrl_synced(info)) {
+               ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL);
+               if (ret)
+                       return ret;
+
+               v4l2_ctrl_handler_setup(&info->handle);
+               info->ctrl_sync = true;
+       }
+
+       return ret;
+}
+
+/**
+ * m5mols_start_monitor - Start the monitor mode
+ *
+ * Before applying the controls setup the resolution and frame rate
+ * in PARAMETER mode, and then switch over to MONITOR mode.
+ */
+static int m5mols_start_monitor(struct m5mols_info *info)
+{
+       struct v4l2_subdev *sd = &info->sd;
+       int ret;
+
+       ret = m5mols_mode(info, REG_PARAMETER);
+       if (!ret)
+               ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution);
+       if (!ret)
+               ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30);
+       if (!ret)
+               ret = m5mols_mode(info, REG_MONITOR);
+       if (!ret)
+               ret = m5mols_sync_controls(info);
+
+       return ret;
+}
+
+static int m5mols_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct m5mols_info *info = to_m5mols(sd);
+
+       if (enable) {
+               int ret = -EINVAL;
+
+               if (is_code(info->code, M5MOLS_RESTYPE_MONITOR))
+                       ret = m5mols_start_monitor(info);
+               if (is_code(info->code, M5MOLS_RESTYPE_CAPTURE))
+                       ret = m5mols_start_capture(info);
+
+               return ret;
+       }
+
+       return m5mols_mode(info, REG_PARAMETER);
+}
+
+static const struct v4l2_subdev_video_ops m5mols_video_ops = {
+       .s_stream       = m5mols_s_stream,
+};
+
+static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct v4l2_subdev *sd = to_sd(ctrl);
+       struct m5mols_info *info = to_m5mols(sd);
+       int ret;
+
+       info->mode_save = info->mode;
+
+       ret = m5mols_mode(info, REG_PARAMETER);
+       if (!ret)
+               ret = m5mols_set_ctrl(ctrl);
+       if (!ret)
+               ret = m5mols_mode(info, info->mode_save);
+
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
+       .s_ctrl = m5mols_s_ctrl,
+};
+
+static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
+{
+       struct v4l2_subdev *sd = &info->sd;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       const struct m5mols_platform_data *pdata = info->pdata;
+       int ret;
+
+       if (enable) {
+               if (is_powered(info))
+                       return 0;
+
+               if (info->set_power) {
+                       ret = info->set_power(&client->dev, 1);
+                       if (ret)
+                               return ret;
+               }
+
+               ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
+               if (ret) {
+                       info->set_power(&client->dev, 0);
+                       return ret;
+               }
+
+               gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity);
+               usleep_range(1000, 1000);
+               info->power = true;
+
+               return ret;
+       }
+
+       if (!is_powered(info))
+               return 0;
+
+       ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
+       if (ret)
+               return ret;
+
+       if (info->set_power)
+               info->set_power(&client->dev, 0);
+
+       gpio_set_value(pdata->gpio_reset, pdata->reset_polarity);
+       usleep_range(1000, 1000);
+       info->power = false;
+
+       return ret;
+}
+
+/* m5mols_update_fw - optional firmware update routine */
+int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd,
+               int (*set_power)(struct m5mols_info *, bool))
+{
+       return 0;
+}
+
+/**
+ * m5mols_sensor_armboot - Booting M-5MOLS internal ARM core.
+ *
+ * Booting internal ARM core makes the M-5MOLS is ready for getting commands
+ * with I2C. It's the first thing to be done after it powered up. It must wait
+ * at least 520ms recommended by M-5MOLS datasheet, after executing arm booting.
+ */
+static int m5mols_sensor_armboot(struct v4l2_subdev *sd)
+{
+       int ret;
+
+       ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT);
+       if (ret < 0)
+               return ret;
+
+       msleep(520);
+
+       ret = m5mols_get_version(sd);
+       if (!ret)
+               ret = m5mols_update_fw(sd, m5mols_sensor_power);
+       if (ret)
+               return ret;
+
+       v4l2_dbg(1, m5mols_debug, sd, "Success ARM Booting\n");
+
+       ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI);
+       if (!ret)
+               ret = m5mols_enable_interrupt(sd, REG_INT_AF);
+
+       return ret;
+}
+
+static int m5mols_init_controls(struct m5mols_info *info)
+{
+       struct v4l2_subdev *sd = &info->sd;
+       u16 max_exposure;
+       u16 step_zoom;
+       int ret;
+
+       /* Determine value's range & step of controls for various FW version */
+       ret = m5mols_read(sd, AE_MAX_GAIN_MON, (u32 *)&max_exposure);
+       if (!ret)
+               step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1;
+       if (ret)
+               return ret;
+
+       v4l2_ctrl_handler_init(&info->handle, 6);
+       info->autowb = v4l2_ctrl_new_std(&info->handle,
+                       &m5mols_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE,
+                       0, 1, 1, 0);
+       info->saturation = v4l2_ctrl_new_std(&info->handle,
+                       &m5mols_ctrl_ops, V4L2_CID_SATURATION,
+                       1, 5, 1, 3);
+       info->zoom = v4l2_ctrl_new_std(&info->handle,
+                       &m5mols_ctrl_ops, V4L2_CID_ZOOM_ABSOLUTE,
+                       1, 70, step_zoom, 1);
+       info->exposure = v4l2_ctrl_new_std(&info->handle,
+                       &m5mols_ctrl_ops, V4L2_CID_EXPOSURE,
+                       0, max_exposure, 1, (int)max_exposure/2);
+       info->colorfx = v4l2_ctrl_new_std_menu(&info->handle,
+                       &m5mols_ctrl_ops, V4L2_CID_COLORFX,
+                       4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE);
+       info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle,
+                       &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
+                       1, 0, V4L2_EXPOSURE_MANUAL);
+
+       sd->ctrl_handler = &info->handle;
+       if (info->handle.error) {
+               v4l2_err(sd, "Failed to initialize controls: %d\n", ret);
+               v4l2_ctrl_handler_free(&info->handle);
+               return info->handle.error;
+       }
+
+       v4l2_ctrl_cluster(2, &info->autoexposure);
+
+       return 0;
+}
+
+/**
+ * m5mols_s_power - Main sensor power control function
+ *
+ * To prevent breaking the lens when the sensor is powered off the Soft-Landing
+ * algorithm is called where available. The Soft-Landing algorithm availability
+ * dependends on the firmware provider.
+ */
+static int m5mols_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct m5mols_info *info = to_m5mols(sd);
+       int ret;
+
+       if (on) {
+               ret = m5mols_sensor_power(info, true);
+               if (!ret)
+                       ret = m5mols_sensor_armboot(sd);
+               if (!ret)
+                       ret = m5mols_init_controls(info);
+               if (ret)
+                       return ret;
+
+               info->ffmt[M5MOLS_RESTYPE_MONITOR] =
+                       m5mols_default_ffmt[M5MOLS_RESTYPE_MONITOR];
+               info->ffmt[M5MOLS_RESTYPE_CAPTURE] =
+                       m5mols_default_ffmt[M5MOLS_RESTYPE_CAPTURE];
+               return ret;
+       }
+
+       if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) {
+               ret = m5mols_mode(info, REG_MONITOR);
+               if (!ret)
+                       ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP);
+               if (!ret)
+                       ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF);
+               if (!ret)
+                       ret = m5mols_busy(sd, CAT_SYSTEM, CAT0_STATUS,
+                                       REG_AF_IDLE);
+               if (!ret)
+                       v4l2_info(sd, "Success soft-landing lens\n");
+       }
+
+       ret = m5mols_sensor_power(info, false);
+       if (!ret) {
+               v4l2_ctrl_handler_free(&info->handle);
+               info->ctrl_sync = false;
+       }
+
+       return ret;
+}
+
+static int m5mols_log_status(struct v4l2_subdev *sd)
+{
+       struct m5mols_info *info = to_m5mols(sd);
+
+       v4l2_ctrl_handler_log_status(&info->handle, sd->name);
+
+       return 0;
+}
+
+static const struct v4l2_subdev_core_ops m5mols_core_ops = {
+       .s_power        = m5mols_s_power,
+       .g_ctrl         = v4l2_subdev_g_ctrl,
+       .s_ctrl         = v4l2_subdev_s_ctrl,
+       .queryctrl      = v4l2_subdev_queryctrl,
+       .querymenu      = v4l2_subdev_querymenu,
+       .g_ext_ctrls    = v4l2_subdev_g_ext_ctrls,
+       .try_ext_ctrls  = v4l2_subdev_try_ext_ctrls,
+       .s_ext_ctrls    = v4l2_subdev_s_ext_ctrls,
+       .log_status     = m5mols_log_status,
+};
+
+static const struct v4l2_subdev_ops m5mols_ops = {
+       .core           = &m5mols_core_ops,
+       .pad            = &m5mols_pad_ops,
+       .video          = &m5mols_video_ops,
+};
+
+static void m5mols_irq_work(struct work_struct *work)
+{
+       struct m5mols_info *info =
+               container_of(work, struct m5mols_info, work_irq);
+       struct v4l2_subdev *sd = &info->sd;
+       u32 reg;
+       int ret;
+
+       if (!is_powered(info) ||
+                       m5mols_read(sd, SYSTEM_INT_FACTOR, &info->interrupt))
+               return;
+
+       switch (info->interrupt & REG_INT_MASK) {
+       case REG_INT_AF:
+               if (!is_available_af(info))
+                       break;
+               ret = m5mols_read(sd, AF_STATUS, &reg);
+               v4l2_dbg(2, m5mols_debug, sd, "AF %s\n",
+                        reg == REG_AF_FAIL ? "Failed" :
+                        reg == REG_AF_SUCCESS ? "Success" :
+                        reg == REG_AF_IDLE ? "Idle" : "Busy");
+               break;
+       case REG_INT_CAPTURE:
+               if (!test_and_set_bit(ST_CAPT_IRQ, &info->flags))
+                       wake_up_interruptible(&info->irq_waitq);
+
+               v4l2_dbg(2, m5mols_debug, sd, "CAPTURE\n");
+               break;
+       default:
+               v4l2_dbg(2, m5mols_debug, sd, "Undefined: %02x\n", reg);
+               break;
+       };
+}
+
+static irqreturn_t m5mols_irq_handler(int irq, void *data)
+{
+       struct v4l2_subdev *sd = data;
+       struct m5mols_info *info = to_m5mols(sd);
+
+       schedule_work(&info->work_irq);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit m5mols_probe(struct i2c_client *client,
+                                 const struct i2c_device_id *id)
+{
+       const struct m5mols_platform_data *pdata = client->dev.platform_data;
+       struct m5mols_info *info;
+       struct v4l2_subdev *sd;
+       int ret;
+
+       if (pdata == NULL) {
+               dev_err(&client->dev, "No platform data\n");
+               return -EINVAL;
+       }
+
+       if (!gpio_is_valid(pdata->gpio_reset)) {
+               dev_err(&client->dev, "No valid RESET GPIO specified\n");
+               return -EINVAL;
+       }
+
+       if (!pdata->irq) {
+               dev_err(&client->dev, "Interrupt not assigned\n");
+               return -EINVAL;
+       }
+
+       info = kzalloc(sizeof(struct m5mols_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       info->pdata = pdata;
+       info->set_power = pdata->set_power;
+
+       ret = gpio_request(pdata->gpio_reset, "M5MOLS_NRST");
+       if (ret) {
+               dev_err(&client->dev, "Failed to request gpio: %d\n", ret);
+               goto out_free;
+       }
+       gpio_direction_output(pdata->gpio_reset, pdata->reset_polarity);
+
+       ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies);
+       if (ret) {
+               dev_err(&client->dev, "Failed to get regulators: %d\n", ret);
+               goto out_gpio;
+       }
+
+       sd = &info->sd;
+       strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
+       v4l2_i2c_subdev_init(sd, client, &m5mols_ops);
+
+       info->pad.flags = MEDIA_PAD_FL_SOURCE;
+       ret = media_entity_init(&sd->entity, 1, &info->pad, 0);
+       if (ret < 0)
+               goto out_reg;
+       sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+
+       init_waitqueue_head(&info->irq_waitq);
+       INIT_WORK(&info->work_irq, m5mols_irq_work);
+       ret = request_irq(pdata->irq, m5mols_irq_handler,
+                         IRQF_TRIGGER_RISING, MODULE_NAME, sd);
+       if (ret) {
+               dev_err(&client->dev, "Interrupt request failed: %d\n", ret);
+               goto out_me;
+       }
+       info->res_type = M5MOLS_RESTYPE_MONITOR;
+       return 0;
+out_me:
+       media_entity_cleanup(&sd->entity);
+out_reg:
+       regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
+out_gpio:
+       gpio_free(pdata->gpio_reset);
+out_free:
+       kfree(info);
+       return ret;
+}
+
+static int __devexit m5mols_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct m5mols_info *info = to_m5mols(sd);
+
+       v4l2_device_unregister_subdev(sd);
+       free_irq(info->pdata->irq, sd);
+
+       regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
+       gpio_free(info->pdata->gpio_reset);
+       media_entity_cleanup(&sd->entity);
+       kfree(info);
+       return 0;
+}
+
+static const struct i2c_device_id m5mols_id[] = {
+       { MODULE_NAME, 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, m5mols_id);
+
+static struct i2c_driver m5mols_i2c_driver = {
+       .driver = {
+               .name   = MODULE_NAME,
+       },
+       .probe          = m5mols_probe,
+       .remove         = __devexit_p(m5mols_remove),
+       .id_table       = m5mols_id,
+};
+
+static int __init m5mols_mod_init(void)
+{
+       return i2c_add_driver(&m5mols_i2c_driver);
+}
+
+static void __exit m5mols_mod_exit(void)
+{
+       i2c_del_driver(&m5mols_i2c_driver);
+}
+
+module_init(m5mols_mod_init);
+module_exit(m5mols_mod_exit);
+
+MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
+MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>");
+MODULE_DESCRIPTION("Fujitsu M-5MOLS 8M Pixel camera driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/m5mols/m5mols_reg.h b/drivers/media/video/m5mols/m5mols_reg.h
new file mode 100644 (file)
index 0000000..b83e36f
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * Register map for M-5MOLS 8M Pixel camera sensor with ISP
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Author: HeungJun Kim, riverful.kim@samsung.com
+ *
+ * Copyright (C) 2009 Samsung Electronics Co., Ltd.
+ * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.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.
+ */
+
+#ifndef M5MOLS_REG_H
+#define M5MOLS_REG_H
+
+#define M5MOLS_I2C_MAX_SIZE    4
+#define M5MOLS_BYTE_READ       0x01
+#define M5MOLS_BYTE_WRITE      0x02
+
+#define I2C_CATEGORY(__cat)            ((__cat >> 16) & 0xff)
+#define I2C_COMMAND(__comm)            ((__comm >> 8) & 0xff)
+#define I2C_SIZE(__reg_s)              ((__reg_s) & 0xff)
+#define I2C_REG(__cat, __cmd, __reg_s) ((__cat << 16) | (__cmd << 8) | __reg_s)
+
+/*
+ * Category section register
+ *
+ * The category means set including relevant command of M-5MOLS.
+ */
+#define CAT_SYSTEM             0x00
+#define CAT_PARAM              0x01
+#define CAT_MONITOR            0x02
+#define CAT_AE                 0x03
+#define CAT_WB                 0x06
+#define CAT_EXIF               0x07
+#define CAT_FD                 0x09
+#define CAT_LENS               0x0a
+#define CAT_CAPT_PARM          0x0b
+#define CAT_CAPT_CTRL          0x0c
+#define CAT_FLASH              0x0f    /* related to FW, revisions, booting */
+
+/*
+ * Category 0 - SYSTEM mode
+ *
+ * The SYSTEM mode in the M-5MOLS means area available to handle with the whole
+ * & all-round system of sensor. It deals with version/interrupt/setting mode &
+ * even sensor's status. Especially, the M-5MOLS sensor with ISP varies by
+ * packaging & manufacturer, even the customer and project code. And the
+ * function details may vary among them. The version information helps to
+ * determine what methods shall be used in the driver.
+ *
+ * There is many registers between customer version address and awb one. For
+ * more specific contents, see definition if file m5mols.h.
+ */
+#define CAT0_VER_CUSTOMER      0x00    /* customer version */
+#define CAT0_VER_AWB           0x09    /* Auto WB version */
+#define CAT0_VER_STRING                0x0a    /* string including M-5MOLS */
+#define CAT0_SYSMODE           0x0b    /* SYSTEM mode register */
+#define CAT0_STATUS            0x0c    /* SYSTEM mode status register */
+#define CAT0_INT_FACTOR                0x10    /* interrupt pending register */
+#define CAT0_INT_ENABLE                0x11    /* interrupt enable register */
+
+#define SYSTEM_SYSMODE         I2C_REG(CAT_SYSTEM, CAT0_SYSMODE, 1)
+#define REG_SYSINIT            0x00    /* SYSTEM mode */
+#define REG_PARAMETER          0x01    /* PARAMETER mode */
+#define REG_MONITOR            0x02    /* MONITOR mode */
+#define REG_CAPTURE            0x03    /* CAPTURE mode */
+
+#define SYSTEM_CMD(__cmd)      I2C_REG(CAT_SYSTEM, cmd, 1)
+#define SYSTEM_VER_STRING      I2C_REG(CAT_SYSTEM, CAT0_VER_STRING, 1)
+#define REG_SAMSUNG_ELECTRO    "SE"    /* Samsung Electro-Mechanics */
+#define REG_SAMSUNG_OPTICS     "OP"    /* Samsung Fiber-Optics */
+#define REG_SAMSUNG_TECHWIN    "TB"    /* Samsung Techwin */
+
+#define SYSTEM_INT_FACTOR      I2C_REG(CAT_SYSTEM, CAT0_INT_FACTOR, 1)
+#define SYSTEM_INT_ENABLE      I2C_REG(CAT_SYSTEM, CAT0_INT_ENABLE, 1)
+#define REG_INT_MODE           (1 << 0)
+#define REG_INT_AF             (1 << 1)
+#define REG_INT_ZOOM           (1 << 2)
+#define REG_INT_CAPTURE                (1 << 3)
+#define REG_INT_FRAMESYNC      (1 << 4)
+#define REG_INT_FD             (1 << 5)
+#define REG_INT_LENS_INIT      (1 << 6)
+#define REG_INT_SOUND          (1 << 7)
+#define REG_INT_MASK           0x0f
+
+/*
+ * category 1 - PARAMETER mode
+ *
+ * This category supports function of camera features of M-5MOLS. It means we
+ * can handle with preview(MONITOR) resolution size/frame per second/interface
+ * between the sensor and the Application Processor/even the image effect.
+ */
+#define CAT1_DATA_INTERFACE    0x00    /* interface between sensor and AP */
+#define CAT1_MONITOR_SIZE      0x01    /* resolution at the MONITOR mode */
+#define CAT1_MONITOR_FPS       0x02    /* frame per second at this mode */
+#define CAT1_EFFECT            0x0b    /* image effects */
+
+#define PARM_MON_SIZE          I2C_REG(CAT_PARAM, CAT1_MONITOR_SIZE, 1)
+
+#define PARM_MON_FPS           I2C_REG(CAT_PARAM, CAT1_MONITOR_FPS, 1)
+#define REG_FPS_30             0x02
+
+#define PARM_INTERFACE         I2C_REG(CAT_PARAM, CAT1_DATA_INTERFACE, 1)
+#define REG_INTERFACE_MIPI     0x02
+
+#define PARM_EFFECT            I2C_REG(CAT_PARAM, CAT1_EFFECT, 1)
+#define REG_EFFECT_OFF         0x00
+#define REG_EFFECT_NEGA                0x01
+#define REG_EFFECT_EMBOSS      0x06
+#define REG_EFFECT_OUTLINE     0x07
+#define REG_EFFECT_WATERCOLOR  0x08
+
+/*
+ * Category 2 - MONITOR mode
+ *
+ * The MONITOR mode is same as preview mode as we said. The M-5MOLS has another
+ * mode named "Preview", but this preview mode is used at the case specific
+ * vider-recording mode. This mmode supports only YUYV format. On the other
+ * hand, the JPEG & RAW formats is supports by CAPTURE mode. And, there are
+ * another options like zoom/color effect(different with effect in PARAMETER
+ * mode)/anti hand shaking algorithm.
+ */
+#define CAT2_ZOOM              0x01    /* set the zoom position & execute */
+#define CAT2_ZOOM_STEP         0x03    /* set the zoom step */
+#define CAT2_CFIXB             0x09    /* CB value for color effect */
+#define CAT2_CFIXR             0x0a    /* CR value for color effect */
+#define CAT2_COLOR_EFFECT      0x0b    /* set on/off of color effect */
+#define CAT2_CHROMA_LVL                0x0f    /* set chroma level */
+#define CAT2_CHROMA_EN         0x10    /* set on/off of choroma */
+#define CAT2_EDGE_LVL          0x11    /* set sharpness level */
+#define CAT2_EDGE_EN           0x12    /* set on/off sharpness */
+#define CAT2_TONE_CTL          0x25    /* set tone color(contrast) */
+
+#define MON_ZOOM               I2C_REG(CAT_MONITOR, CAT2_ZOOM, 1)
+
+#define MON_CFIXR              I2C_REG(CAT_MONITOR, CAT2_CFIXR, 1)
+#define MON_CFIXB              I2C_REG(CAT_MONITOR, CAT2_CFIXB, 1)
+#define REG_CFIXB_SEPIA                0xd8
+#define REG_CFIXR_SEPIA                0x18
+
+#define MON_EFFECT             I2C_REG(CAT_MONITOR, CAT2_COLOR_EFFECT, 1)
+#define REG_COLOR_EFFECT_OFF   0x00
+#define REG_COLOR_EFFECT_ON    0x01
+
+#define MON_CHROMA_EN          I2C_REG(CAT_MONITOR, CAT2_CHROMA_EN, 1)
+#define MON_CHROMA_LVL         I2C_REG(CAT_MONITOR, CAT2_CHROMA_LVL, 1)
+#define REG_CHROMA_OFF         0x00
+#define REG_CHROMA_ON          0x01
+
+#define MON_EDGE_EN            I2C_REG(CAT_MONITOR, CAT2_EDGE_EN, 1)
+#define MON_EDGE_LVL           I2C_REG(CAT_MONITOR, CAT2_EDGE_LVL, 1)
+#define REG_EDGE_OFF           0x00
+#define REG_EDGE_ON            0x01
+
+#define MON_TONE_CTL           I2C_REG(CAT_MONITOR, CAT2_TONE_CTL, 1)
+
+/*
+ * Category 3 - Auto Exposure
+ *
+ * The M-5MOLS exposure capbility is detailed as which is similar to digital
+ * camera. This category supports AE locking/various AE mode(range of exposure)
+ * /ISO/flickering/EV bias/shutter/meteoring, and anything else. And the
+ * maximum/minimum exposure gain value depending on M-5MOLS firmware, may be
+ * different. So, this category also provide getting the max/min values. And,
+ * each MONITOR and CAPTURE mode has each gain/shutter/max exposure values.
+ */
+#define CAT3_AE_LOCK           0x00    /* locking Auto exposure */
+#define CAT3_AE_MODE           0x01    /* set AE mode, mode means range */
+#define CAT3_ISO               0x05    /* set ISO */
+#define CAT3_EV_PRESET_MONITOR 0x0a    /* EV(scenemode) preset for MONITOR */
+#define CAT3_EV_PRESET_CAPTURE 0x0b    /* EV(scenemode) preset for CAPTURE */
+#define CAT3_MANUAL_GAIN_MON   0x12    /* meteoring value for the MONITOR */
+#define CAT3_MAX_GAIN_MON      0x1a    /* max gain value for the MONITOR */
+#define CAT3_MANUAL_GAIN_CAP   0x26    /* meteoring value for the CAPTURE */
+#define CAT3_AE_INDEX          0x38    /* AE index */
+
+#define AE_LOCK                        I2C_REG(CAT_AE, CAT3_AE_LOCK, 1)
+#define REG_AE_UNLOCK          0x00
+#define REG_AE_LOCK            0x01
+
+#define AE_MODE                        I2C_REG(CAT_AE, CAT3_AE_MODE, 1)
+#define REG_AE_OFF             0x00    /* AE off */
+#define REG_AE_ALL             0x01    /* calc AE in all block integral */
+#define REG_AE_CENTER          0x03    /* calc AE in center weighted */
+#define REG_AE_SPOT            0x06    /* calc AE in specific spot */
+
+#define AE_ISO                 I2C_REG(CAT_AE, CAT3_ISO, 1)
+#define REG_ISO_AUTO           0x00
+#define REG_ISO_50             0x01
+#define REG_ISO_100            0x02
+#define REG_ISO_200            0x03
+#define REG_ISO_400            0x04
+#define REG_ISO_800            0x05
+
+#define AE_EV_PRESET_MONITOR   I2C_REG(CAT_AE, CAT3_EV_PRESET_MONITOR, 1)
+#define AE_EV_PRESET_CAPTURE   I2C_REG(CAT_AE, CAT3_EV_PRESET_CAPTURE, 1)
+#define REG_SCENE_NORMAL       0x00
+#define REG_SCENE_PORTRAIT     0x01
+#define REG_SCENE_LANDSCAPE    0x02
+#define REG_SCENE_SPORTS       0x03
+#define REG_SCENE_PARTY_INDOOR 0x04
+#define REG_SCENE_BEACH_SNOW   0x05
+#define REG_SCENE_SUNSET       0x06
+#define REG_SCENE_DAWN_DUSK    0x07
+#define REG_SCENE_FALL         0x08
+#define REG_SCENE_NIGHT                0x09
+#define REG_SCENE_AGAINST_LIGHT        0x0a
+#define REG_SCENE_FIRE         0x0b
+#define REG_SCENE_TEXT         0x0c
+#define REG_SCENE_CANDLE       0x0d
+
+#define AE_MAN_GAIN_MON                I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_MON, 2)
+#define AE_MAX_GAIN_MON                I2C_REG(CAT_AE, CAT3_MAX_GAIN_MON, 2)
+#define AE_MAN_GAIN_CAP                I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_CAP, 2)
+
+#define AE_INDEX               I2C_REG(CAT_AE, CAT3_AE_INDEX, 1)
+#define REG_AE_INDEX_20_NEG    0x00
+#define REG_AE_INDEX_15_NEG    0x01
+#define REG_AE_INDEX_10_NEG    0x02
+#define REG_AE_INDEX_05_NEG    0x03
+#define REG_AE_INDEX_00                0x04
+#define REG_AE_INDEX_05_POS    0x05
+#define REG_AE_INDEX_10_POS    0x06
+#define REG_AE_INDEX_15_POS    0x07
+#define REG_AE_INDEX_20_POS    0x08
+
+/*
+ * Category 6 - White Balance
+ *
+ * This category provide AWB locking/mode/preset/speed/gain bias, etc.
+ */
+#define CAT6_AWB_LOCK          0x00    /* locking Auto Whitebalance */
+#define CAT6_AWB_MODE          0x02    /* set Auto or Manual */
+#define CAT6_AWB_MANUAL                0x03    /* set Manual(preset) value */
+
+#define AWB_LOCK               I2C_REG(CAT_WB, CAT6_AWB_LOCK, 1)
+#define REG_AWB_UNLOCK         0x00
+#define REG_AWB_LOCK           0x01
+
+#define AWB_MODE               I2C_REG(CAT_WB, CAT6_AWB_MODE, 1)
+#define REG_AWB_AUTO           0x01    /* AWB off */
+#define REG_AWB_PRESET         0x02    /* AWB preset */
+
+#define AWB_MANUAL             I2C_REG(CAT_WB, CAT6_AWB_MANUAL, 1)
+#define REG_AWB_INCANDESCENT   0x01
+#define REG_AWB_FLUORESCENT_1  0x02
+#define REG_AWB_FLUORESCENT_2  0x03
+#define REG_AWB_DAYLIGHT       0x04
+#define REG_AWB_CLOUDY         0x05
+#define REG_AWB_SHADE          0x06
+#define REG_AWB_HORIZON                0x07
+#define REG_AWB_LEDLIGHT       0x09
+
+/*
+ * Category 7 - EXIF information
+ */
+#define CAT7_INFO_EXPTIME_NU   0x00
+#define CAT7_INFO_EXPTIME_DE   0x04
+#define CAT7_INFO_TV_NU                0x08
+#define CAT7_INFO_TV_DE                0x0c
+#define CAT7_INFO_AV_NU                0x10
+#define CAT7_INFO_AV_DE                0x14
+#define CAT7_INFO_BV_NU                0x18
+#define CAT7_INFO_BV_DE                0x1c
+#define CAT7_INFO_EBV_NU       0x20
+#define CAT7_INFO_EBV_DE       0x24
+#define CAT7_INFO_ISO          0x28
+#define CAT7_INFO_FLASH                0x2a
+#define CAT7_INFO_SDR          0x2c
+#define CAT7_INFO_QVAL         0x2e
+
+#define EXIF_INFO_EXPTIME_NU   I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_NU, 4)
+#define EXIF_INFO_EXPTIME_DE   I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_DE, 4)
+#define EXIF_INFO_TV_NU                I2C_REG(CAT_EXIF, CAT7_INFO_TV_NU, 4)
+#define EXIF_INFO_TV_DE                I2C_REG(CAT_EXIF, CAT7_INFO_TV_DE, 4)
+#define EXIF_INFO_AV_NU                I2C_REG(CAT_EXIF, CAT7_INFO_AV_NU, 4)
+#define EXIF_INFO_AV_DE                I2C_REG(CAT_EXIF, CAT7_INFO_AV_DE, 4)
+#define EXIF_INFO_BV_NU                I2C_REG(CAT_EXIF, CAT7_INFO_BV_NU, 4)
+#define EXIF_INFO_BV_DE                I2C_REG(CAT_EXIF, CAT7_INFO_BV_DE, 4)
+#define EXIF_INFO_EBV_NU       I2C_REG(CAT_EXIF, CAT7_INFO_EBV_NU, 4)
+#define EXIF_INFO_EBV_DE       I2C_REG(CAT_EXIF, CAT7_INFO_EBV_DE, 4)
+#define EXIF_INFO_ISO          I2C_REG(CAT_EXIF, CAT7_INFO_ISO, 2)
+#define EXIF_INFO_FLASH                I2C_REG(CAT_EXIF, CAT7_INFO_FLASH, 2)
+#define EXIF_INFO_SDR          I2C_REG(CAT_EXIF, CAT7_INFO_SDR, 2)
+#define EXIF_INFO_QVAL         I2C_REG(CAT_EXIF, CAT7_INFO_QVAL, 2)
+
+/*
+ * Category 9 - Face Detection
+ */
+#define CAT9_FD_CTL            0x00
+
+#define FD_CTL                 I2C_REG(CAT_FD, CAT9_FD_CTL, 1)
+#define BIT_FD_EN              0
+#define BIT_FD_DRAW_FACE_FRAME 4
+#define BIT_FD_DRAW_SMILE_LVL  6
+#define REG_FD(shift)          (1 << shift)
+#define REG_FD_OFF             0x0
+
+/*
+ * Category A - Lens Parameter
+ */
+#define CATA_AF_MODE           0x01
+#define CATA_AF_EXECUTE                0x02
+#define CATA_AF_STATUS         0x03
+#define CATA_AF_VERSION                0x0a
+
+#define AF_MODE                        I2C_REG(CAT_LENS, CATA_AF_MODE, 1)
+#define REG_AF_NORMAL          0x00    /* Normal AF, one time */
+#define REG_AF_MACRO           0x01    /* Macro AF, one time */
+#define REG_AF_POWEROFF                0x07
+
+#define AF_EXECUTE             I2C_REG(CAT_LENS, CATA_AF_EXECUTE, 1)
+#define REG_AF_STOP            0x00
+#define REG_AF_EXE_AUTO                0x01
+#define REG_AF_EXE_CAF         0x02
+
+#define AF_STATUS              I2C_REG(CAT_LENS, CATA_AF_STATUS, 1)
+#define REG_AF_FAIL            0x00
+#define REG_AF_SUCCESS         0x02
+#define REG_AF_IDLE            0x04
+#define REG_AF_BUSY            0x05
+
+#define AF_VERSION             I2C_REG(CAT_LENS, CATA_AF_VERSION, 1)
+
+/*
+ * Category B - CAPTURE Parameter
+ */
+#define CATB_YUVOUT_MAIN       0x00
+#define CATB_MAIN_IMAGE_SIZE   0x01
+#define CATB_MCC_MODE          0x1d
+#define CATB_WDR_EN            0x2c
+#define CATB_LIGHT_CTRL                0x40
+#define CATB_FLASH_CTRL                0x41
+
+#define CAPP_YUVOUT_MAIN       I2C_REG(CAT_CAPT_PARM, CATB_YUVOUT_MAIN, 1)
+#define REG_YUV422             0x00
+#define REG_BAYER10            0x05
+#define REG_BAYER8             0x06
+#define REG_JPEG               0x10
+
+#define CAPP_MAIN_IMAGE_SIZE   I2C_REG(CAT_CAPT_PARM, CATB_MAIN_IMAGE_SIZE, 1)
+
+#define CAPP_MCC_MODE          I2C_REG(CAT_CAPT_PARM, CATB_MCC_MODE, 1)
+#define REG_MCC_OFF            0x00
+#define REG_MCC_NORMAL         0x01
+
+#define CAPP_WDR_EN            I2C_REG(CAT_CAPT_PARM, CATB_WDR_EN, 1)
+#define REG_WDR_OFF            0x00
+#define REG_WDR_ON             0x01
+#define REG_WDR_AUTO           0x02
+
+#define CAPP_LIGHT_CTRL                I2C_REG(CAT_CAPT_PARM, CATB_LIGHT_CTRL, 1)
+#define REG_LIGHT_OFF          0x00
+#define REG_LIGHT_ON           0x01
+#define REG_LIGHT_AUTO         0x02
+
+#define CAPP_FLASH_CTRL                I2C_REG(CAT_CAPT_PARM, CATB_FLASH_CTRL, 1)
+#define REG_FLASH_OFF          0x00
+#define REG_FLASH_ON           0x01
+#define REG_FLASH_AUTO         0x02
+
+/*
+ * Category C - CAPTURE Control
+ */
+#define CATC_CAP_MODE          0x00
+#define CATC_CAP_SEL_FRAME     0x06    /* It determines Single or Multi */
+#define CATC_CAP_START         0x09
+#define CATC_CAP_IMAGE_SIZE    0x0d
+#define CATC_CAP_THUMB_SIZE    0x11
+
+#define CAPC_MODE              I2C_REG(CAT_CAPT_CTRL, CATC_CAP_MODE, 1)
+#define REG_CAP_NONE           0x00
+#define REG_CAP_ANTI_SHAKE     0x02
+
+#define CAPC_SEL_FRAME         I2C_REG(CAT_CAPT_CTRL, CATC_CAP_SEL_FRAME, 1)
+
+#define CAPC_START             I2C_REG(CAT_CAPT_CTRL, CATC_CAP_START, 1)
+#define REG_CAP_START_MAIN     0x01
+#define REG_CAP_START_THUMB    0x03
+
+#define CAPC_IMAGE_SIZE                I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 1)
+#define CAPC_THUMB_SIZE                I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 1)
+
+/*
+ * Category F - Flash
+ *
+ * This mode provides functions about internal flash stuff and system startup.
+ */
+#define CATF_CAM_START         0x12    /* It starts internal ARM core booting
+                                        * after power-up */
+
+#define FLASH_CAM_START                I2C_REG(CAT_FLASH, CATF_CAM_START, 1)
+#define REG_START_ARM_BOOT     0x01
+
+#endif /* M5MOLS_REG_H */
index d4fe7bc92a1d82525f77a43f31e4d9ef856bdbde..4ada9be1d430d0f50f9f63e866b5ca82e835226a 100644 (file)
@@ -47,7 +47,7 @@
 #include <plat/dma.h>
 #include <plat/vram.h>
 #include <plat/vrfb.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #include "omap_voutlib.h"
 #include "omap_voutdef.h"
index ea3a047f8bca6bd32a6cb0b78b68b9c678ee717d..659497b849965e9c017ec5a0846291bb513337ca 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef OMAP_VOUTDEF_H
 #define OMAP_VOUTDEF_H
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define YUYV_BPP        2
 #define RGB565_BPP      2
index 472a69359e609c16c67b014da479e7bbeb2c29ed..c9fd04ee70a8ae766811059c6942657334ac7621 100644 (file)
@@ -391,7 +391,7 @@ static inline void isp_isr_dbg(struct isp_device *isp, u32 irqstatus)
        };
        int i;
 
-       dev_dbg(isp->dev, "");
+       dev_dbg(isp->dev, "ISP IRQ: ");
 
        for (i = 0; i < ARRAY_SIZE(name); i++) {
                if ((1 << i) & irqstatus)
index 398864370267f33d12a7fe56a5feaa5ce6c916fa..4e4d4122d9a60339175486b999a8576b25565c09 100644 (file)
@@ -1512,7 +1512,7 @@ static int video_dev_create(struct soc_camera_device *icd)
  */
 static int soc_camera_video_start(struct soc_camera_device *icd)
 {
-       struct device_type *type = icd->vdev->dev.type;
+       const struct device_type *type = icd->vdev->dev.type;
        int ret;
 
        if (!icd->dev.parent)
index 84d4c7c83435caa355971c1bd0536d27253e0bd3..fc611ebeb82c3a550b3d2425c58927813dfb448d 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/dmaengine.h>
-#include <linux/mfd/core.h>
 #include <linux/scatterlist.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
@@ -791,7 +790,7 @@ static int __devinit timblogiw_probe(struct platform_device *pdev)
 {
        int err;
        struct timblogiw *lw = NULL;
-       struct timb_video_platform_data *pdata = mfd_get_data(pdev);
+       struct timb_video_platform_data *pdata = pdev->dev.platform_data;
 
        if (!pdata) {
                dev_err(&pdev->dev, "No platform data\n");
index 968c1994eda01f8ec87b2a95c803fc30a927bbde..2071ca8a2f031d86bb876fde6e3dcd79af31b92a 100644 (file)
@@ -1,3 +1,6 @@
 uvcvideo-objs  := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
                  uvc_status.o uvc_isight.o
+ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
+uvcvideo-objs  += uvc_entity.o
+endif
 obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o
index 823f4b3897459c7dc335c7ba3babb678c02261bb..b6eae48d7fb802f53a950b90ef3f9107f96e9271 100644 (file)
@@ -248,7 +248,7 @@ uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator)
  * Terminal and unit management
  */
 
-static struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id)
+struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id)
 {
        struct uvc_entity *entity;
 
@@ -795,9 +795,12 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id,
        struct uvc_entity *entity;
        unsigned int num_inputs;
        unsigned int size;
+       unsigned int i;
 
+       extra_size = ALIGN(extra_size, sizeof(*entity->pads));
        num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1;
-       size = sizeof(*entity) + extra_size + num_inputs;
+       size = sizeof(*entity) + extra_size + sizeof(*entity->pads) * num_pads
+            + num_inputs;
        entity = kzalloc(size, GFP_KERNEL);
        if (entity == NULL)
                return NULL;
@@ -805,8 +808,17 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id,
        entity->id = id;
        entity->type = type;
 
+       entity->num_links = 0;
+       entity->num_pads = num_pads;
+       entity->pads = ((void *)(entity + 1)) + extra_size;
+
+       for (i = 0; i < num_inputs; ++i)
+               entity->pads[i].flags = MEDIA_PAD_FL_SINK;
+       if (!UVC_ENTITY_IS_OTERM(entity))
+               entity->pads[num_pads-1].flags = MEDIA_PAD_FL_SOURCE;
+
        entity->bNrInPins = num_inputs;
-       entity->baSourceID = ((__u8 *)entity) + sizeof(*entity) + extra_size;
+       entity->baSourceID = (__u8 *)(&entity->pads[num_pads]);
 
        return entity;
 }
@@ -1585,6 +1597,13 @@ static void uvc_delete(struct uvc_device *dev)
        uvc_status_cleanup(dev);
        uvc_ctrl_cleanup_device(dev);
 
+       if (dev->vdev.dev)
+               v4l2_device_unregister(&dev->vdev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+       if (media_devnode_is_registered(&dev->mdev.devnode))
+               media_device_unregister(&dev->mdev);
+#endif
+
        list_for_each_safe(p, n, &dev->chains) {
                struct uvc_video_chain *chain;
                chain = list_entry(p, struct uvc_video_chain, list);
@@ -1594,6 +1613,13 @@ static void uvc_delete(struct uvc_device *dev)
        list_for_each_safe(p, n, &dev->entities) {
                struct uvc_entity *entity;
                entity = list_entry(p, struct uvc_entity, list);
+#ifdef CONFIG_MEDIA_CONTROLLER
+               uvc_mc_cleanup_entity(entity);
+#endif
+               if (entity->vdev) {
+                       video_device_release(entity->vdev);
+                       entity->vdev = NULL;
+               }
                kfree(entity);
        }
 
@@ -1616,8 +1642,6 @@ static void uvc_release(struct video_device *vdev)
        struct uvc_streaming *stream = video_get_drvdata(vdev);
        struct uvc_device *dev = stream->dev;
 
-       video_device_release(vdev);
-
        /* Decrement the registered streams count and delete the device when it
         * reaches zero.
         */
@@ -1682,7 +1706,7 @@ static int uvc_register_video(struct uvc_device *dev,
         * unregistered before the reference is released, so we don't need to
         * get another one.
         */
-       vdev->parent = &dev->intf->dev;
+       vdev->v4l2_dev = &dev->vdev;
        vdev->fops = &uvc_fops;
        vdev->release = uvc_release;
        strlcpy(vdev->name, dev->name, sizeof vdev->name);
@@ -1731,6 +1755,8 @@ static int uvc_register_terms(struct uvc_device *dev,
                ret = uvc_register_video(dev, stream);
                if (ret < 0)
                        return ret;
+
+               term->vdev = stream->vdev;
        }
 
        return 0;
@@ -1745,6 +1771,14 @@ static int uvc_register_chains(struct uvc_device *dev)
                ret = uvc_register_terms(dev, chain);
                if (ret < 0)
                        return ret;
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+               ret = uvc_mc_register_entities(chain);
+               if (ret < 0) {
+                       uvc_printk(KERN_INFO, "Failed to register entites "
+                               "(%d).\n", ret);
+               }
+#endif
        }
 
        return 0;
@@ -1814,6 +1848,24 @@ static int uvc_probe(struct usb_interface *intf,
                        "linux-uvc-devel mailing list.\n");
        }
 
+       /* Register the media and V4L2 devices. */
+#ifdef CONFIG_MEDIA_CONTROLLER
+       dev->mdev.dev = &intf->dev;
+       strlcpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model));
+       if (udev->serial)
+               strlcpy(dev->mdev.serial, udev->serial,
+                       sizeof(dev->mdev.serial));
+       strcpy(dev->mdev.bus_info, udev->devpath);
+       dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
+       dev->mdev.driver_version = DRIVER_VERSION_NUMBER;
+       if (media_device_register(&dev->mdev) < 0)
+               goto error;
+
+       dev->vdev.mdev = &dev->mdev;
+#endif
+       if (v4l2_device_register(&intf->dev, &dev->vdev) < 0)
+               goto error;
+
        /* Initialize controls. */
        if (uvc_ctrl_init_device(dev) < 0)
                goto error;
@@ -1822,7 +1874,7 @@ static int uvc_probe(struct usb_interface *intf,
        if (uvc_scan_device(dev) < 0)
                goto error;
 
-       /* Register video devices. */
+       /* Register video device nodes. */
        if (uvc_register_chains(dev) < 0)
                goto error;
 
diff --git a/drivers/media/video/uvc/uvc_entity.c b/drivers/media/video/uvc/uvc_entity.c
new file mode 100644 (file)
index 0000000..c3ab0c8
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ *      uvc_entity.c  --  USB Video Class driver
+ *
+ *      Copyright (C) 2005-2011
+ *          Laurent Pinchart (laurent.pinchart@ideasonboard.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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-common.h>
+
+#include "uvcvideo.h"
+
+/* ------------------------------------------------------------------------
+ * Video subdevices registration and unregistration
+ */
+
+static int uvc_mc_register_entity(struct uvc_video_chain *chain,
+       struct uvc_entity *entity)
+{
+       const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE;
+       struct uvc_entity *remote;
+       unsigned int i;
+       u8 remote_pad;
+       int ret = 0;
+
+       for (i = 0; i < entity->num_pads; ++i) {
+               struct media_entity *source;
+               struct media_entity *sink;
+
+               if (!(entity->pads[i].flags & MEDIA_PAD_FL_SINK))
+                       continue;
+
+               remote = uvc_entity_by_id(chain->dev, entity->baSourceID[i]);
+               if (remote == NULL)
+                       return -EINVAL;
+
+               source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING)
+                      ? &remote->vdev->entity : &remote->subdev.entity;
+               sink = (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING)
+                    ? &entity->vdev->entity : &entity->subdev.entity;
+
+               remote_pad = remote->num_pads - 1;
+               ret = media_entity_create_link(source, remote_pad,
+                                              sink, i, flags);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING)
+               ret = v4l2_device_register_subdev(&chain->dev->vdev,
+                                                 &entity->subdev);
+
+       return ret;
+}
+
+static struct v4l2_subdev_ops uvc_subdev_ops = {
+};
+
+void uvc_mc_cleanup_entity(struct uvc_entity *entity)
+{
+       if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING)
+               media_entity_cleanup(&entity->subdev.entity);
+       else if (entity->vdev != NULL)
+               media_entity_cleanup(&entity->vdev->entity);
+}
+
+static int uvc_mc_init_entity(struct uvc_entity *entity)
+{
+       int ret;
+
+       if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) {
+               v4l2_subdev_init(&entity->subdev, &uvc_subdev_ops);
+               strlcpy(entity->subdev.name, entity->name,
+                       sizeof(entity->subdev.name));
+
+               ret = media_entity_init(&entity->subdev.entity,
+                                       entity->num_pads, entity->pads, 0);
+       } else
+               ret = media_entity_init(&entity->vdev->entity,
+                                       entity->num_pads, entity->pads, 0);
+
+       return ret;
+}
+
+int uvc_mc_register_entities(struct uvc_video_chain *chain)
+{
+       struct uvc_entity *entity;
+       int ret;
+
+       list_for_each_entry(entity, &chain->entities, chain) {
+               ret = uvc_mc_init_entity(entity);
+               if (ret < 0) {
+                       uvc_printk(KERN_INFO, "Failed to initialize entity for "
+                                  "entity %u\n", entity->id);
+                       return ret;
+               }
+       }
+
+       list_for_each_entry(entity, &chain->entities, chain) {
+               ret = uvc_mc_register_entity(chain, entity);
+               if (ret < 0) {
+                       uvc_printk(KERN_INFO, "Failed to register entity for "
+                                  "entity %u\n", entity->id);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
index 7cf224bae2e527eb2d14a3baf53f6d31168d241c..20107fd3574da44508f69835e5fc098b3eec86a6 100644 (file)
@@ -98,8 +98,11 @@ struct uvc_xu_control {
 #ifdef __KERNEL__
 
 #include <linux/poll.h>
+#include <linux/usb.h>
 #include <linux/usb/video.h>
 #include <linux/uvcvideo.h>
+#include <media/media-device.h>
+#include <media/v4l2-device.h>
 
 /* --------------------------------------------------------------------------
  * UVC constants
@@ -301,6 +304,13 @@ struct uvc_entity {
        __u16 type;
        char name[64];
 
+       /* Media controller-related fields. */
+       struct video_device *vdev;
+       struct v4l2_subdev subdev;
+       unsigned int num_pads;
+       unsigned int num_links;
+       struct media_pad *pads;
+
        union {
                struct {
                        __u16 wObjectiveFocalLengthMin;
@@ -504,6 +514,10 @@ struct uvc_device {
        atomic_t nmappings;
 
        /* Video control interface */
+#ifdef CONFIG_MEDIA_CONTROLLER
+       struct media_device mdev;
+#endif
+       struct v4l2_device vdev;
        __u16 uvc_version;
        __u32 clock_frequency;
 
@@ -583,6 +597,8 @@ extern unsigned int uvc_timeout_param;
 /* Core driver */
 extern struct uvc_driver uvc_driver;
 
+extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
+
 /* Video buffers queue management. */
 extern void uvc_queue_init(struct uvc_video_queue *queue,
                enum v4l2_buf_type type, int drop_corrupted);
@@ -616,6 +632,10 @@ static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
 /* V4L2 interface */
 extern const struct v4l2_file_operations uvc_fops;
 
+/* Media controller */
+extern int uvc_mc_register_entities(struct uvc_video_chain *chain);
+extern void uvc_mc_cleanup_entity(struct uvc_entity *entity);
+
 /* Video */
 extern int uvc_video_init(struct uvc_streaming *stream);
 extern int uvc_video_suspend(struct uvc_streaming *stream);
index 011cb6ce861bcd8f4d820f6b1e77bff51ec9cd99..17dfe9bb6d2745c2bb5f6123b1afbc6c6d997ca6 100644 (file)
 
 #define INT_STATUS_NUM                 3
 
-static struct resource bk_resources[] __initdata = {
+static struct resource bk_resources[] __devinitdata = {
        {PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,},
        {PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,},
        {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,},
 };
 
-static struct resource led_resources[] __initdata = {
+static struct resource led_resources[] __devinitdata = {
        {PM8606_LED1_RED,   PM8606_LED1_RED,   "led0-red",   IORESOURCE_IO,},
        {PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,},
        {PM8606_LED1_BLUE,  PM8606_LED1_BLUE,  "led0-blue",  IORESOURCE_IO,},
@@ -36,7 +36,7 @@ static struct resource led_resources[] __initdata = {
        {PM8606_LED2_BLUE,  PM8606_LED2_BLUE,  "led1-blue",  IORESOURCE_IO,},
 };
 
-static struct resource regulator_resources[] __initdata = {
+static struct resource regulator_resources[] __devinitdata = {
        {PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,},
        {PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,},
        {PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,},
@@ -57,15 +57,15 @@ static struct resource regulator_resources[] __initdata = {
        {PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,},
 };
 
-static struct resource touch_resources[] __initdata = {
+static struct resource touch_resources[] __devinitdata = {
        {PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,},
 };
 
-static struct resource onkey_resources[] __initdata = {
+static struct resource onkey_resources[] __devinitdata = {
        {PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,},
 };
 
-static struct resource codec_resources[] __initdata = {
+static struct resource codec_resources[] __devinitdata = {
        /* Headset microphone insertion or removal */
        {PM8607_IRQ_MICIN,   PM8607_IRQ_MICIN,   "micin",   IORESOURCE_IRQ,},
        /* Hook-switch press or release */
@@ -76,12 +76,12 @@ static struct resource codec_resources[] __initdata = {
        {PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,},
 };
 
-static struct resource battery_resources[] __initdata = {
+static struct resource battery_resources[] __devinitdata = {
        {PM8607_IRQ_CC,  PM8607_IRQ_CC,  "columb counter", IORESOURCE_IRQ,},
        {PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery",        IORESOURCE_IRQ,},
 };
 
-static struct resource charger_resources[] __initdata = {
+static struct resource charger_resources[] __devinitdata = {
        {PM8607_IRQ_CHG,  PM8607_IRQ_CHG,  "charger detect",  IORESOURCE_IRQ,},
        {PM8607_IRQ_CHG_DONE,  PM8607_IRQ_CHG_DONE,  "charging done",       IORESOURCE_IRQ,},
        {PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging timeout",    IORESOURCE_IRQ,},
@@ -90,13 +90,17 @@ static struct resource charger_resources[] __initdata = {
        {PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage",    IORESOURCE_IRQ,},
 };
 
-static struct mfd_cell bk_devs[] __initdata = {
+static struct resource rtc_resources[] __devinitdata = {
+       {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,},
+};
+
+static struct mfd_cell bk_devs[] = {
        {"88pm860x-backlight", 0,},
        {"88pm860x-backlight", 1,},
        {"88pm860x-backlight", 2,},
 };
 
-static struct mfd_cell led_devs[] __initdata = {
+static struct mfd_cell led_devs[] = {
        {"88pm860x-led", 0,},
        {"88pm860x-led", 1,},
        {"88pm860x-led", 2,},
@@ -105,7 +109,7 @@ static struct mfd_cell led_devs[] __initdata = {
        {"88pm860x-led", 5,},
 };
 
-static struct mfd_cell regulator_devs[] __initdata = {
+static struct mfd_cell regulator_devs[] = {
        {"88pm860x-regulator", 0,},
        {"88pm860x-regulator", 1,},
        {"88pm860x-regulator", 2,},
@@ -126,15 +130,15 @@ static struct mfd_cell regulator_devs[] __initdata = {
        {"88pm860x-regulator", 17,},
 };
 
-static struct mfd_cell touch_devs[] __initdata = {
+static struct mfd_cell touch_devs[] = {
        {"88pm860x-touch", -1,},
 };
 
-static struct mfd_cell onkey_devs[] __initdata = {
+static struct mfd_cell onkey_devs[] = {
        {"88pm860x-onkey", -1,},
 };
 
-static struct mfd_cell codec_devs[] __initdata = {
+static struct mfd_cell codec_devs[] = {
        {"88pm860x-codec", -1,},
 };
 
@@ -143,11 +147,10 @@ static struct mfd_cell power_devs[] = {
        {"88pm860x-charger", -1,},
 };
 
-static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)];
-static struct pm860x_led_pdata led_pdata[ARRAY_SIZE(led_devs)];
-static struct regulator_init_data regulator_pdata[ARRAY_SIZE(regulator_devs)];
-static struct pm860x_touch_pdata touch_pdata;
-static struct pm860x_power_pdata power_pdata;
+static struct mfd_cell rtc_devs[] = {
+       {"88pm860x-rtc", -1,},
+};
+
 
 struct pm860x_irq_data {
        int     reg;
@@ -501,7 +504,6 @@ static void device_irq_exit(struct pm860x_chip *chip)
 }
 
 static void __devinit device_bk_init(struct pm860x_chip *chip,
-                                    struct i2c_client *i2c,
                                     struct pm860x_platform_data *pdata)
 {
        int ret;
@@ -514,13 +516,12 @@ static void __devinit device_bk_init(struct pm860x_chip *chip,
                pdata->num_backlights = ARRAY_SIZE(bk_devs);
 
        for (i = 0; i < pdata->num_backlights; i++) {
-               memcpy(&bk_pdata[i], &pdata->backlight[i],
-                       sizeof(struct pm860x_backlight_pdata));
-               bk_devs[i].mfd_data = &bk_pdata[i];
+               bk_devs[i].platform_data = &pdata->backlight[i];
+               bk_devs[i].pdata_size = sizeof(struct pm860x_backlight_pdata);
 
                for (j = 0; j < ARRAY_SIZE(bk_devs); j++) {
                        id = bk_resources[j].start;
-                       if (bk_pdata[i].flags != id)
+                       if (pdata->backlight[i].flags != id)
                                continue;
 
                        bk_devs[i].num_resources = 1;
@@ -538,7 +539,6 @@ static void __devinit device_bk_init(struct pm860x_chip *chip,
 }
 
 static void __devinit device_led_init(struct pm860x_chip *chip,
-                                     struct i2c_client *i2c,
                                      struct pm860x_platform_data *pdata)
 {
        int ret;
@@ -551,13 +551,12 @@ static void __devinit device_led_init(struct pm860x_chip *chip,
                pdata->num_leds = ARRAY_SIZE(led_devs);
 
        for (i = 0; i < pdata->num_leds; i++) {
-               memcpy(&led_pdata[i], &pdata->led[i],
-                       sizeof(struct pm860x_led_pdata));
-               led_devs[i].mfd_data = &led_pdata[i];
+               led_devs[i].platform_data = &pdata->led[i];
+               led_devs[i].pdata_size = sizeof(struct pm860x_led_pdata);
 
                for (j = 0; j < ARRAY_SIZE(led_devs); j++) {
                        id = led_resources[j].start;
-                       if (led_pdata[i].flags != id)
+                       if (pdata->led[i].flags != id)
                                continue;
 
                        led_devs[i].num_resources = 1;
@@ -575,12 +574,11 @@ static void __devinit device_led_init(struct pm860x_chip *chip,
 }
 
 static void __devinit device_regulator_init(struct pm860x_chip *chip,
-                                           struct i2c_client *i2c,
                                            struct pm860x_platform_data *pdata)
 {
        struct regulator_init_data *initdata;
        int ret;
-       int i, j;
+       int i, seq;
 
        if ((pdata == NULL) || (pdata->regulator == NULL))
                return;
@@ -588,41 +586,21 @@ static void __devinit device_regulator_init(struct pm860x_chip *chip,
        if (pdata->num_regulators > ARRAY_SIZE(regulator_devs))
                pdata->num_regulators = ARRAY_SIZE(regulator_devs);
 
-       for (i = 0, j = -1; i < pdata->num_regulators; i++) {
+       for (i = 0, seq = -1; i < pdata->num_regulators; i++) {
                initdata = &pdata->regulator[i];
-               if (strstr(initdata->constraints.name, "BUCK")) {
-                       sscanf(initdata->constraints.name, "BUCK%d", &j);
-                       /* BUCK1 ~ BUCK3 */
-                       if ((j < 1) || (j > 3)) {
-                               dev_err(chip->dev, "Failed to add constraint "
-                                       "(%s)\n", initdata->constraints.name);
-                               goto out;
-                       }
-                       j = (j - 1) + PM8607_ID_BUCK1;
-               }
-               if (strstr(initdata->constraints.name, "LDO")) {
-                       sscanf(initdata->constraints.name, "LDO%d", &j);
-                       /* LDO1 ~ LDO15 */
-                       if ((j < 1) || (j > 15)) {
-                               dev_err(chip->dev, "Failed to add constraint "
-                                       "(%s)\n", initdata->constraints.name);
-                               goto out;
-                       }
-                       j = (j - 1) + PM8607_ID_LDO1;
-               }
-               if (j == -1) {
-                       dev_err(chip->dev, "Failed to add constraint (%s)\n",
-                               initdata->constraints.name);
+               seq = *(unsigned int *)initdata->driver_data;
+               if ((seq < 0) || (seq > PM8607_ID_RG_MAX)) {
+                       dev_err(chip->dev, "Wrong ID(%d) on regulator(%s)\n",
+                               seq, initdata->constraints.name);
                        goto out;
                }
-               memcpy(&regulator_pdata[i], &pdata->regulator[i],
-                       sizeof(struct regulator_init_data));
-               regulator_devs[i].mfd_data = &regulator_pdata[i];
+               regulator_devs[i].platform_data = &pdata->regulator[i];
+               regulator_devs[i].pdata_size = sizeof(struct regulator_init_data);
                regulator_devs[i].num_resources = 1;
-               regulator_devs[i].resources = &regulator_resources[j];
+               regulator_devs[i].resources = &regulator_resources[seq];
 
                ret = mfd_add_devices(chip->dev, 0, &regulator_devs[i], 1,
-                                     &regulator_resources[j], 0);
+                                     &regulator_resources[seq], 0);
                if (ret < 0) {
                        dev_err(chip->dev, "Failed to add regulator subdev\n");
                        goto out;
@@ -632,17 +610,35 @@ out:
        return;
 }
 
+static void __devinit device_rtc_init(struct pm860x_chip *chip,
+                                     struct pm860x_platform_data *pdata)
+{
+       int ret;
+
+       if ((pdata == NULL))
+               return;
+
+       rtc_devs[0].platform_data = pdata->rtc;
+       rtc_devs[0].pdata_size = sizeof(struct pm860x_rtc_pdata);
+       rtc_devs[0].num_resources = ARRAY_SIZE(rtc_resources);
+       rtc_devs[0].resources = &rtc_resources[0];
+       ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
+                             ARRAY_SIZE(rtc_devs), &rtc_resources[0],
+                             chip->irq_base);
+       if (ret < 0)
+               dev_err(chip->dev, "Failed to add rtc subdev\n");
+}
+
 static void __devinit device_touch_init(struct pm860x_chip *chip,
-                                       struct i2c_client *i2c,
                                        struct pm860x_platform_data *pdata)
 {
        int ret;
 
-       if ((pdata == NULL) || (pdata->touch == NULL))
+       if (pdata == NULL)
                return;
 
-       memcpy(&touch_pdata, pdata->touch, sizeof(struct pm860x_touch_pdata));
-       touch_devs[0].mfd_data = &touch_pdata;
+       touch_devs[0].platform_data = pdata->touch;
+       touch_devs[0].pdata_size = sizeof(struct pm860x_touch_pdata);
        touch_devs[0].num_resources = ARRAY_SIZE(touch_resources);
        touch_devs[0].resources = &touch_resources[0];
        ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
@@ -653,16 +649,15 @@ static void __devinit device_touch_init(struct pm860x_chip *chip,
 }
 
 static void __devinit device_power_init(struct pm860x_chip *chip,
-                                       struct i2c_client *i2c,
                                        struct pm860x_platform_data *pdata)
 {
        int ret;
 
-       if ((pdata == NULL) || (pdata->power == NULL))
+       if (pdata == NULL)
                return;
 
-       memcpy(&power_pdata, pdata->power, sizeof(struct pm860x_power_pdata));
-       power_devs[0].mfd_data = &power_pdata;
+       power_devs[0].platform_data = pdata->power;
+       power_devs[0].pdata_size = sizeof(struct pm860x_power_pdata);
        power_devs[0].num_resources = ARRAY_SIZE(battery_resources);
        power_devs[0].resources = &battery_resources[0],
        ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1,
@@ -670,7 +665,8 @@ static void __devinit device_power_init(struct pm860x_chip *chip,
        if (ret < 0)
                dev_err(chip->dev, "Failed to add battery subdev\n");
 
-       power_devs[1].mfd_data = &power_pdata;
+       power_devs[1].platform_data = pdata->power;
+       power_devs[1].pdata_size = sizeof(struct pm860x_power_pdata);
        power_devs[1].num_resources = ARRAY_SIZE(charger_resources);
        power_devs[1].resources = &charger_resources[0],
        ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1,
@@ -680,7 +676,6 @@ static void __devinit device_power_init(struct pm860x_chip *chip,
 }
 
 static void __devinit device_onkey_init(struct pm860x_chip *chip,
-                                       struct i2c_client *i2c,
                                        struct pm860x_platform_data *pdata)
 {
        int ret;
@@ -695,7 +690,6 @@ static void __devinit device_onkey_init(struct pm860x_chip *chip,
 }
 
 static void __devinit device_codec_init(struct pm860x_chip *chip,
-                                       struct i2c_client *i2c,
                                        struct pm860x_platform_data *pdata)
 {
        int ret;
@@ -763,11 +757,12 @@ static void __devinit device_8607_init(struct pm860x_chip *chip,
        if (ret < 0)
                goto out;
 
-       device_regulator_init(chip, i2c, pdata);
-       device_onkey_init(chip, i2c, pdata);
-       device_touch_init(chip, i2c, pdata);
-       device_power_init(chip, i2c, pdata);
-       device_codec_init(chip, i2c, pdata);
+       device_regulator_init(chip, pdata);
+       device_rtc_init(chip, pdata);
+       device_onkey_init(chip, pdata);
+       device_touch_init(chip, pdata);
+       device_power_init(chip, pdata);
+       device_codec_init(chip, pdata);
 out:
        return;
 }
@@ -779,8 +774,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
 
        switch (chip->id) {
        case CHIP_PM8606:
-               device_bk_init(chip, chip->client, pdata);
-               device_led_init(chip, chip->client, pdata);
+               device_bk_init(chip, pdata);
+               device_led_init(chip, pdata);
                break;
        case CHIP_PM8607:
                device_8607_init(chip, chip->client, pdata);
@@ -790,8 +785,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
        if (chip->companion) {
                switch (chip->id) {
                case CHIP_PM8607:
-                       device_bk_init(chip, chip->companion, pdata);
-                       device_led_init(chip, chip->companion, pdata);
+                       device_bk_init(chip, pdata);
+                       device_led_init(chip, pdata);
                        break;
                case CHIP_PM8606:
                        device_8607_init(chip, chip->companion, pdata);
index 3ed3ff06be5d7e93d8e276ab78623a81610b30fa..0f09c057e7960ca203886b61be108dfb9d3003d3 100644 (file)
@@ -157,6 +157,20 @@ config TPS6507X
          This driver can also be built as a module.  If so, the module
          will be called tps6507x.
 
+config MFD_TPS6586X
+       bool "TPS6586x Power Management chips"
+       depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
+       select MFD_CORE
+       help
+         If you say yes here you get support for the TPS6586X series of
+         Power Management chips.
+         This driver provides common support for accessing the device,
+         additional drivers must be enabled in order to use the
+         functionality of the device.
+
+         This driver can also be built as a module.  If so, the module
+         will be called tps6586x.
+
 config MENELAUS
        bool "Texas Instruments TWL92330/Menelaus PM chip"
        depends on I2C=y && ARCH_OMAP2
@@ -455,6 +469,20 @@ config MFD_PCF50633
          facilities, and registers devices for the various functions
          so that function-specific drivers can bind to them.
 
+config PCF50633_ADC
+       tristate "Support for NXP PCF50633 ADC"
+       depends on MFD_PCF50633
+       help
+        Say yes here if you want to include support for ADC in the
+        NXP PCF50633 chip.
+
+config PCF50633_GPIO
+       tristate "Support for NXP PCF50633 GPIO"
+       depends on MFD_PCF50633
+       help
+        Say yes here if you want to include support GPIO for pins on
+        the PCF50633 chip.
+
 config MFD_MC13783
        tristate
 
@@ -470,20 +498,6 @@ config MFD_MC13XXX
          additional drivers must be enabled in order to use the
          functionality of the device.
 
-config PCF50633_ADC
-       tristate "Support for NXP PCF50633 ADC"
-       depends on MFD_PCF50633
-       help
-        Say yes here if you want to include support for ADC in the
-        NXP PCF50633 chip.
-
-config PCF50633_GPIO
-       tristate "Support for NXP PCF50633 GPIO"
-       depends on MFD_PCF50633
-       help
-        Say yes here if you want to include support GPIO for pins on
-        the PCF50633 chip.
-
 config ABX500_CORE
        bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
        default y if ARCH_U300 || ARCH_U8500
@@ -538,7 +552,7 @@ config AB8500_CORE
 
 config AB8500_I2C_CORE
        bool "AB8500 register access via PRCMU I2C"
-       depends on AB8500_CORE && UX500_SOC_DB8500
+       depends on AB8500_CORE && MFD_DB8500_PRCMU
        default y
        help
          This enables register access to the AB8500 chip via PRCMU I2C.
@@ -575,6 +589,26 @@ config AB3550_CORE
          LEDs, vibrator, system power and temperature, power management
          and ALSA sound.
 
+config MFD_DB8500_PRCMU
+       bool "ST-Ericsson DB8500 Power Reset Control Management Unit"
+       depends on UX500_SOC_DB8500
+       select MFD_CORE
+       help
+         Select this option to enable support for the DB8500 Power Reset
+         and Control Management Unit. This is basically an autonomous
+         system controller running an XP70 microprocessor, which is accessed
+         through a register map.
+
+config MFD_DB5500_PRCMU
+       bool "ST-Ericsson DB5500 Power Reset Control Management Unit"
+       depends on UX500_SOC_DB5500
+       select MFD_CORE
+       help
+         Select this option to enable support for the DB5500 Power Reset
+         and Control Management Unit. This is basically an autonomous
+         system controller running an XP70 microprocessor, which is accessed
+         through a register map.
+
 config MFD_CS5535
        tristate "Support for CS5535 and CS5536 southbridge core functions"
        select MFD_CORE
@@ -629,20 +663,6 @@ config MFD_JZ4740_ADC
          Say yes here if you want support for the ADC unit in the JZ4740 SoC.
          This driver is necessary for jz4740-battery and jz4740-hwmon driver.
 
-config MFD_TPS6586X
-       bool "TPS6586x Power Management chips"
-       depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
-       select MFD_CORE
-       help
-         If you say yes here you get support for the TPS6586X series of
-         Power Management chips.
-         This driver provides common support for accessing the device,
-         additional drivers must be enabled in order to use the
-         functionality of the device.
-
-         This driver can also be built as a module.  If so, the module
-         will be called tps6586x.
-
 config MFD_VX855
        tristate "Support for VIA VX855/VX875 integrated south bridge"
        depends on PCI
@@ -671,6 +691,43 @@ config MFD_OMAP_USB_HOST
          This MFD driver does the required setup functionalities for
          OMAP USB Host drivers.
 
+config MFD_PM8XXX
+       tristate
+
+config MFD_PM8921_CORE
+       tristate "Qualcomm PM8921 PMIC chip"
+       depends on MSM_SSBI
+       select MFD_CORE
+       select MFD_PM8XXX
+       help
+         If you say yes to this option, support will be included for the
+         built-in PM8921 PMIC chip.
+
+         This is required if your board has a PM8921 and uses its features,
+         such as: MPPs, GPIOs, regulators, interrupts, and PWM.
+
+         Say M here if you want to include support for PM8921 chip as a module.
+         This will build a module called "pm8921-core".
+
+config MFD_PM8XXX_IRQ
+       bool "Support for Qualcomm PM8xxx IRQ features"
+       depends on MFD_PM8XXX
+       default y if MFD_PM8XXX
+       help
+         This is the IRQ driver for Qualcomm PM 8xxx PMIC chips.
+
+         This is required to use certain other PM 8xxx features, such as GPIO
+         and MPP.
+
+config MFD_TPS65910
+       bool "TPS65910 Power Management chip"
+       depends on I2C=y && GPIOLIB
+       select MFD_CORE
+       select GPIO_TPS65910
+       help
+         if you say yes here you get support for the TPS65910 series of
+         Power Management chips.
+
 endif # MFD_SUPPORT
 
 menu "Multimedia Capabilities Port drivers"
index 419caa9d7dcfe395282ef85c8b50bf2238ce0308..efe3cc33ed92ed83a7a8ece78f32686c87bb6170 100644 (file)
@@ -74,9 +74,12 @@ obj-$(CONFIG_AB3100_CORE)    += ab3100-core.o
 obj-$(CONFIG_AB3100_OTP)       += ab3100-otp.o
 obj-$(CONFIG_AB3550_CORE)      += ab3550-core.o
 obj-$(CONFIG_AB8500_CORE)      += ab8500-core.o ab8500-sysctrl.o
-obj-$(CONFIG_AB8500_I2C_CORE)  += ab8500-i2c.o
 obj-$(CONFIG_AB8500_DEBUG)     += ab8500-debugfs.o
 obj-$(CONFIG_AB8500_GPADC)     += ab8500-gpadc.o
+obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
+# ab8500-i2c need to come after db8500-prcmu (which provides the channel)
+obj-$(CONFIG_AB8500_I2C_CORE)  += ab8500-i2c.o
+obj-$(CONFIG_MFD_DB5500_PRCMU) += db5500-prcmu.o
 obj-$(CONFIG_MFD_TIMBERDALE)    += timberdale.o
 obj-$(CONFIG_PMIC_ADP5520)     += adp5520.o
 obj-$(CONFIG_LPC_SCH)          += lpc_sch.o
@@ -88,3 +91,6 @@ obj-$(CONFIG_MFD_VX855)               += vx855.o
 obj-$(CONFIG_MFD_WL1273_CORE)  += wl1273-core.o
 obj-$(CONFIG_MFD_CS5535)       += cs5535-mfd.o
 obj-$(CONFIG_MFD_OMAP_USB_HOST)        += omap-usb-host.o
+obj-$(CONFIG_MFD_PM8921_CORE)  += pm8921-core.o
+obj-$(CONFIG_MFD_PM8XXX_IRQ)   += pm8xxx-irq.o
+obj-$(CONFIG_MFD_TPS65910)     += tps65910.o tps65910-irq.o
index a751927047ac967b6111359c3d8942253382be12..a20e1c41bed2f67c7fcdf65958ef83e62dde98e2 100644 (file)
@@ -949,8 +949,10 @@ static int __devinit ab3100_probe(struct i2c_client *client,
                goto exit_no_ops;
 
        /* Set up and register the platform devices. */
-       for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++)
-               ab3100_devs[i].mfd_data = ab3100_plf_data;
+       for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) {
+               ab3100_devs[i].platform_data = ab3100_plf_data;
+               ab3100_devs[i].pdata_size = sizeof(struct ab3100_platform_data);
+       }
 
        err = mfd_add_devices(&client->dev, 0, ab3100_devs,
                ARRAY_SIZE(ab3100_devs), NULL, 0);
index ff86acf3e6bde2b16f6e95f2f8c6af90e92bcd64..3d7dce671b936a1affb6429c2469d56a436e8cf2 100644 (file)
@@ -1320,8 +1320,10 @@ static int __init ab3550_probe(struct i2c_client *client,
                goto exit_no_ops;
 
        /* Set up and register the platform devices. */
-       for (i = 0; i < AB3550_NUM_DEVICES; i++)
-               ab3550_devs[i].mfd_data = ab3550_plf_data->dev_data[i];
+       for (i = 0; i < AB3550_NUM_DEVICES; i++) {
+               ab3550_devs[i].platform_data = ab3550_plf_data->dev_data[i];
+               ab3550_devs[i].pdata_size = ab3550_plf_data->dev_data_sz[i];
+       }
 
        err = mfd_add_devices(&client->dev, 0, ab3550_devs,
                ARRAY_SIZE(ab3550_devs), NULL,
index 67d01c9382844f9e1b6c793181e82cd2865e58c4..fc0c1af1566e08d01b7351de9e1a00466d2c0614 100644 (file)
@@ -254,8 +254,9 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
                if (new == old)
                        continue;
 
-               /* Interrupt register 12 does'nt exist prior to version 0x20 */
-               if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
+               /* Interrupt register 12 doesn't exist prior to version 2.0 */
+               if (ab8500_irq_regoffset[i] == 11 &&
+                       ab8500->chip_id < AB8500_CUT2P0)
                        continue;
 
                ab8500->oldmask[i] = new;
@@ -307,8 +308,8 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
                int status;
                u8 value;
 
-               /* Interrupt register 12 does'nt exist prior to version 0x20 */
-               if (regoffset == 11 && ab8500->chip_id < 0x20)
+               /* Interrupt register 12 doesn't exist prior to version 2.0 */
+               if (regoffset == 11 && ab8500->chip_id < AB8500_CUT2P0)
                        continue;
 
                status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
@@ -724,17 +725,15 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
        if (ret < 0)
                return ret;
 
-       /*
-        * 0x0 - Early Drop
-        * 0x10 - Cut 1.0
-        * 0x11 - Cut 1.1
-        * 0x20 - Cut 2.0
-        * 0x30 - Cut 3.0
-        */
-       if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20 ||
-               value == 0x30) {
+       switch (value) {
+       case AB8500_CUTEARLY:
+       case AB8500_CUT1P0:
+       case AB8500_CUT1P1:
+       case AB8500_CUT2P0:
+       case AB8500_CUT3P0:
                dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
-       } else {
+               break;
+       default:
                dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value);
                return -EINVAL;
        }
@@ -763,8 +762,9 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
 
        /* Clear and mask all interrupts */
        for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
-               /* Interrupt register 12 does'nt exist prior to version 0x20 */
-               if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
+               /* Interrupt register 12 doesn't exist prior to version 2.0 */
+               if (ab8500_irq_regoffset[i] == 11 &&
+                       ab8500->chip_id < AB8500_CUT2P0)
                        continue;
 
                get_register_interruptible(ab8500, AB8500_INTERRUPT,
index 6421ad1160de2084c2a9a03b69a628c55681f893..f16afb234ff98a250d0ded3a9aac0d1768ab679b 100644 (file)
@@ -57,6 +57,7 @@
 #define SW_AVG_16                      0x60
 #define ADC_SW_CONV                    0x04
 #define EN_ICHAR                       0x80
+#define BTEMP_PULL_UP                  0x08
 #define EN_BUF                         0x40
 #define DIS_ZERO                       0x00
 #define GPADC_BUSY                     0x01
@@ -101,6 +102,7 @@ struct adc_cal_data {
 
 /**
  * struct ab8500_gpadc - AB8500 GPADC device information
+ * @chip_id                    ABB chip id
  * @dev:                       pointer to the struct device
  * @node:                      a list of AB8500 GPADCs, hence prepared for
                                reentrance
@@ -112,6 +114,7 @@ struct adc_cal_data {
  * @cal_data                   array of ADC calibration data structs
  */
 struct ab8500_gpadc {
+       u8 chip_id;
        struct device *dev;
        struct list_head node;
        struct completion ab8500_gpadc_complete;
@@ -274,6 +277,7 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
                dev_err(gpadc->dev, "gpadc_conversion: enable gpadc failed\n");
                goto out;
        }
+
        /* Select the input source and set average samples to 16 */
        ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
                AB8500_GPADC_CTRL2_REG, (input | SW_AVG_16));
@@ -282,9 +286,11 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
                        "gpadc_conversion: set avg samples failed\n");
                goto out;
        }
+
        /*
         * Enable ADC, buffering, select rising edge and enable ADC path
-        * charging current sense if it needed
+        * charging current sense if it needed, ABB 3.0 needs some special
+        * treatment too.
         */
        switch (input) {
        case MAIN_CHARGER_C:
@@ -294,6 +300,23 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
                        EN_BUF | EN_ICHAR,
                        EN_BUF | EN_ICHAR);
                break;
+       case BTEMP_BALL:
+               if (gpadc->chip_id >= AB8500_CUT3P0) {
+                       /* Turn on btemp pull-up on ABB 3.0 */
+                       ret = abx500_mask_and_set_register_interruptible(
+                               gpadc->dev,
+                               AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
+                               EN_BUF | BTEMP_PULL_UP,
+                               EN_BUF | BTEMP_PULL_UP);
+
+                /*
+                 * Delay might be needed for ABB8500 cut 3.0, if not, remove
+                 * when hardware will be availible
+                 */
+                       msleep(1);
+                       break;
+               }
+               /* Intentional fallthrough */
        default:
                ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
                        AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF);
@@ -304,6 +327,7 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
                        "gpadc_conversion: select falling edge failed\n");
                goto out;
        }
+
        ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
                AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV);
        if (ret < 0) {
@@ -552,6 +576,14 @@ static int __devinit ab8500_gpadc_probe(struct platform_device *pdev)
                goto fail;
        }
 
+       /* Get Chip ID of the ABB ASIC  */
+       ret = abx500_get_chip_id(gpadc->dev);
+       if (ret < 0) {
+               dev_err(gpadc->dev, "failed to get chip ID\n");
+               goto fail_irq;
+       }
+       gpadc->chip_id = (u8) ret;
+
        /* VTVout LDO used to power up ab8500-GPADC */
        gpadc->regu = regulator_get(&pdev->dev, "vddadc");
        if (IS_ERR(gpadc->regu)) {
index 821e6b86afd2a82a73811f65176fca1b3e835110..9be541c6b004c8adc9cf6cde3416c6bff31c9e31 100644 (file)
@@ -11,8 +11,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/ab8500.h>
-
-#include <mach/prcmu.h>
+#include <linux/mfd/db8500-prcmu.h>
 
 static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
 {
index 0b4d5b23bec9b36d212fa068c6663b8f23365638..c27fd1fc3b86789a73cf725ce57a5863e5175d6f 100644 (file)
@@ -88,19 +88,19 @@ struct asic3 {
 
 static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset);
 
-static inline void asic3_write_register(struct asic3 *asic,
-                                unsigned int reg, u32 value)
+void asic3_write_register(struct asic3 *asic, unsigned int reg, u32 value)
 {
        iowrite16(value, asic->mapping +
                  (reg >> asic->bus_shift));
 }
+EXPORT_SYMBOL_GPL(asic3_write_register);
 
-static inline u32 asic3_read_register(struct asic3 *asic,
-                              unsigned int reg)
+u32 asic3_read_register(struct asic3 *asic, unsigned int reg)
 {
        return ioread16(asic->mapping +
                        (reg >> asic->bus_shift));
 }
+EXPORT_SYMBOL_GPL(asic3_read_register);
 
 static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
 {
@@ -676,7 +676,8 @@ static struct mfd_cell asic3_cell_ds1wm = {
        .name          = "ds1wm",
        .enable        = ds1wm_enable,
        .disable       = ds1wm_disable,
-       .mfd_data      = &ds1wm_pdata,
+       .platform_data = &ds1wm_pdata,
+       .pdata_size    = sizeof(ds1wm_pdata),
        .num_resources = ARRAY_SIZE(ds1wm_resources),
        .resources     = ds1wm_resources,
 };
@@ -777,12 +778,61 @@ static struct mfd_cell asic3_cell_mmc = {
        .name          = "tmio-mmc",
        .enable        = asic3_mmc_enable,
        .disable       = asic3_mmc_disable,
-       .mfd_data      = &asic3_mmc_data,
+       .platform_data = &asic3_mmc_data,
+       .pdata_size    = sizeof(asic3_mmc_data),
        .num_resources = ARRAY_SIZE(asic3_mmc_resources),
        .resources     = asic3_mmc_resources,
 };
 
+static const int clock_ledn[ASIC3_NUM_LEDS] = {
+       [0] = ASIC3_CLOCK_LED0,
+       [1] = ASIC3_CLOCK_LED1,
+       [2] = ASIC3_CLOCK_LED2,
+};
+
+static int asic3_leds_enable(struct platform_device *pdev)
+{
+       const struct mfd_cell *cell = mfd_get_cell(pdev);
+       struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+
+       asic3_clk_enable(asic, &asic->clocks[clock_ledn[cell->id]]);
+
+       return 0;
+}
+
+static int asic3_leds_disable(struct platform_device *pdev)
+{
+       const struct mfd_cell *cell = mfd_get_cell(pdev);
+       struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+
+       asic3_clk_disable(asic, &asic->clocks[clock_ledn[cell->id]]);
+
+       return 0;
+}
+
+static struct mfd_cell asic3_cell_leds[ASIC3_NUM_LEDS] = {
+       [0] = {
+               .name          = "leds-asic3",
+               .id            = 0,
+               .enable        = asic3_leds_enable,
+               .disable       = asic3_leds_disable,
+       },
+       [1] = {
+               .name          = "leds-asic3",
+               .id            = 1,
+               .enable        = asic3_leds_enable,
+               .disable       = asic3_leds_disable,
+       },
+       [2] = {
+               .name          = "leds-asic3",
+               .id            = 2,
+               .enable        = asic3_leds_enable,
+               .disable       = asic3_leds_disable,
+       },
+};
+
 static int __init asic3_mfd_probe(struct platform_device *pdev,
+                                 struct asic3_platform_data *pdata,
                                  struct resource *mem)
 {
        struct asic3 *asic = platform_get_drvdata(pdev);
@@ -806,7 +856,8 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
 
        /* MMC */
        asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) +
-                                mem_sdio->start, 0x400 >> asic->bus_shift);
+                                mem_sdio->start,
+                                ASIC3_SD_CONFIG_SIZE >> asic->bus_shift);
        if (!asic->tmio_cnf) {
                ret = -ENOMEM;
                dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG\n");
@@ -820,9 +871,23 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
        if (ret < 0)
                goto out;
 
-       if (mem_sdio && (irq >= 0))
+       if (mem_sdio && (irq >= 0)) {
                ret = mfd_add_devices(&pdev->dev, pdev->id,
                        &asic3_cell_mmc, 1, mem_sdio, irq);
+               if (ret < 0)
+                       goto out;
+       }
+
+       if (pdata->leds) {
+               int i;
+
+               for (i = 0; i < ASIC3_NUM_LEDS; ++i) {
+                       asic3_cell_leds[i].platform_data = &pdata->leds[i];
+                       asic3_cell_leds[i].pdata_size = sizeof(pdata->leds[i]);
+               }
+               ret = mfd_add_devices(&pdev->dev, 0,
+                       asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0);
+       }
 
  out:
        return ret;
@@ -903,7 +968,7 @@ static int __init asic3_probe(struct platform_device *pdev)
         */
        memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init));
 
-       asic3_mfd_probe(pdev, mem);
+       asic3_mfd_probe(pdev, pdata, mem);
 
        dev_info(asic->dev, "ASIC3 Core driver\n");
 
index 414783b048490b7a03a021781c79acd29d32367c..4e2af2cb2d26a76534c884c3cc57fe97f3c30d52 100644 (file)
@@ -119,12 +119,14 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
        /* Voice codec interface client */
        cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL];
        cell->name = "davinci-vcif";
-       cell->mfd_data = davinci_vc;
+       cell->platform_data = davinci_vc;
+       cell->pdata_size = sizeof(*davinci_vc);
 
        /* Voice codec CQ93VC client */
        cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL];
        cell->name = "cq93vc-codec";
-       cell->mfd_data = davinci_vc;
+       cell->platform_data = davinci_vc;
+       cell->pdata_size = sizeof(*davinci_vc);
 
        ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells,
                              DAVINCI_VC_CELLS, NULL, 0);
similarity index 80%
rename from arch/arm/mach-ux500/include/mach/prcmu-regs.h
rename to drivers/mfd/db5500-prcmu-regs.h
index 455467e887915d628cd13ea416e47fc5d86ebdc6..9a8e9e4ddd3319c08388f5f98da83fca29208d03 100644 (file)
 
 #include <mach/hardware.h>
 
-#define _PRCMU_BASE            IO_ADDRESS(U8500_PRCMU_BASE)
-
 #define PRCM_ARM_PLLDIVPS      (_PRCMU_BASE + 0x118)
+#define PRCM_ARM_PLLDIVPS_ARM_BRM_RATE         0x3f
+#define PRCM_ARM_PLLDIVPS_MAX_MASK             0xf
+
+#define PRCM_PLLARM_LOCKP       (_PRCMU_BASE + 0x0a8)
+#define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3   0x2
+
 #define PRCM_ARM_CHGCLKREQ     (_PRCMU_BASE + 0x114)
+#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ  0x1
+
 #define PRCM_PLLARM_ENABLE     (_PRCMU_BASE + 0x98)
+#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE  0x1
+#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_COUNTON 0x100
+
 #define PRCM_ARMCLKFIX_MGT     (_PRCMU_BASE + 0x0)
 #define PRCM_A9_RESETN_CLR     (_PRCMU_BASE + 0x1f4)
 #define PRCM_A9_RESETN_SET     (_PRCMU_BASE + 0x1f0)
@@ -28,7 +37,8 @@
 
 /* ARM WFI Standby signal register */
 #define PRCM_ARM_WFI_STANDBY    (_PRCMU_BASE + 0x130)
-#define PRCMU_IOCR              (_PRCMU_BASE + 0x310)
+#define PRCM_IOCR              (_PRCMU_BASE + 0x310)
+#define PRCM_IOCR_IOFORCE                      0x1
 
 /* CPU mailbox registers */
 #define PRCM_MBOX_CPU_VAL      (_PRCMU_BASE + 0x0fc)
@@ -37,6 +47,8 @@
 
 /* Dual A9 core interrupt management unit registers */
 #define PRCM_A9_MASK_REQ       (_PRCMU_BASE + 0x328)
+#define PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ      0x1
+
 #define PRCM_A9_MASK_ACK       (_PRCMU_BASE + 0x32c)
 #define PRCM_ARMITMSK31TO0     (_PRCMU_BASE + 0x11c)
 #define PRCM_ARMITMSK63TO32    (_PRCMU_BASE + 0x120)
 /* PRCMU clock/PLL/reset registers */
 #define PRCM_PLLDSI_FREQ           (_PRCMU_BASE + 0x500)
 #define PRCM_PLLDSI_ENABLE         (_PRCMU_BASE + 0x504)
+#define PRCM_PLLDSI_LOCKP          (_PRCMU_BASE + 0x508)
 #define PRCM_LCDCLK_MGT            (_PRCMU_BASE + 0x044)
 #define PRCM_MCDECLK_MGT           (_PRCMU_BASE + 0x064)
 #define PRCM_HDMICLK_MGT           (_PRCMU_BASE + 0x058)
 #define PRCM_TVCLK_MGT             (_PRCMU_BASE + 0x07c)
 #define PRCM_DSI_PLLOUT_SEL        (_PRCMU_BASE + 0x530)
 #define PRCM_DSITVCLK_DIV          (_PRCMU_BASE + 0x52C)
+#define PRCM_PLLDSI_LOCKP          (_PRCMU_BASE + 0x508)
 #define PRCM_APE_RESETN_SET        (_PRCMU_BASE + 0x1E4)
 #define PRCM_APE_RESETN_CLR        (_PRCMU_BASE + 0x1E8)
+#define PRCM_CLKOCR               (_PRCMU_BASE + 0x1CC)
 
 /* ePOD and memory power signal control registers */
 #define PRCM_EPOD_C_SET            (_PRCMU_BASE + 0x410)
 
 /* Miscellaneous unit registers */
 #define PRCM_DSI_SW_RESET          (_PRCMU_BASE + 0x324)
+#define PRCM_GPIOCR                (_PRCMU_BASE + 0x138)
+#define PRCM_GPIOCR_DBG_STM_MOD_CMD1            0x800
+#define PRCM_GPIOCR_DBG_UARTMOD_CMD0            0x1
+
 
-#endif /* __MACH_PRCMU_REGS_H */
+#endif /* __MACH_PRCMU__REGS_H */
diff --git a/drivers/mfd/db5500-prcmu.c b/drivers/mfd/db5500-prcmu.c
new file mode 100644 (file)
index 0000000..9dbb3ca
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
+ *
+ * U5500 PRCM Unit interface driver
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/db5500-prcmu.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/db5500-regs.h>
+#include "db5500-prcmu-regs.h"
+
+#define _PRCM_MB_HEADER (tcdm_base + 0xFE8)
+#define PRCM_REQ_MB0_HEADER (_PRCM_MB_HEADER + 0x0)
+#define PRCM_REQ_MB1_HEADER (_PRCM_MB_HEADER + 0x1)
+#define PRCM_REQ_MB2_HEADER (_PRCM_MB_HEADER + 0x2)
+#define PRCM_REQ_MB3_HEADER (_PRCM_MB_HEADER + 0x3)
+#define PRCM_REQ_MB4_HEADER (_PRCM_MB_HEADER + 0x4)
+#define PRCM_REQ_MB5_HEADER (_PRCM_MB_HEADER + 0x5)
+#define PRCM_REQ_MB6_HEADER (_PRCM_MB_HEADER + 0x6)
+#define PRCM_REQ_MB7_HEADER (_PRCM_MB_HEADER + 0x7)
+#define PRCM_ACK_MB0_HEADER (_PRCM_MB_HEADER + 0x8)
+#define PRCM_ACK_MB1_HEADER (_PRCM_MB_HEADER + 0x9)
+#define PRCM_ACK_MB2_HEADER (_PRCM_MB_HEADER + 0xa)
+#define PRCM_ACK_MB3_HEADER (_PRCM_MB_HEADER + 0xb)
+#define PRCM_ACK_MB4_HEADER (_PRCM_MB_HEADER + 0xc)
+#define PRCM_ACK_MB5_HEADER (_PRCM_MB_HEADER + 0xd)
+#define PRCM_ACK_MB6_HEADER (_PRCM_MB_HEADER + 0xe)
+#define PRCM_ACK_MB7_HEADER (_PRCM_MB_HEADER + 0xf)
+
+/* Req Mailboxes */
+#define PRCM_REQ_MB0 (tcdm_base + 0xFD8)
+#define PRCM_REQ_MB1 (tcdm_base + 0xFCC)
+#define PRCM_REQ_MB2 (tcdm_base + 0xFC4)
+#define PRCM_REQ_MB3 (tcdm_base + 0xFC0)
+#define PRCM_REQ_MB4 (tcdm_base + 0xF98)
+#define PRCM_REQ_MB5 (tcdm_base + 0xF90)
+#define PRCM_REQ_MB6 (tcdm_base + 0xF8C)
+#define PRCM_REQ_MB7 (tcdm_base + 0xF84)
+
+/* Ack Mailboxes */
+#define PRCM_ACK_MB0 (tcdm_base + 0xF38)
+#define PRCM_ACK_MB1 (tcdm_base + 0xF30)
+#define PRCM_ACK_MB2 (tcdm_base + 0xF24)
+#define PRCM_ACK_MB3 (tcdm_base + 0xF20)
+#define PRCM_ACK_MB4 (tcdm_base + 0xF1C)
+#define PRCM_ACK_MB5 (tcdm_base + 0xF14)
+#define PRCM_ACK_MB6 (tcdm_base + 0xF0C)
+#define PRCM_ACK_MB7 (tcdm_base + 0xF08)
+
+enum mb_return_code {
+       RC_SUCCESS,
+       RC_FAIL,
+};
+
+/* Mailbox 0 headers. */
+enum mb0_header {
+       /* request */
+       RMB0H_PWR_STATE_TRANS = 1,
+       RMB0H_WAKE_UP_CFG,
+       RMB0H_RD_WAKE_UP_ACK,
+       /* acknowledge */
+       AMB0H_WAKE_UP = 1,
+};
+
+/* Mailbox 5 headers. */
+enum mb5_header {
+       MB5H_I2C_WRITE = 1,
+       MB5H_I2C_READ,
+};
+
+/* Request mailbox 5 fields. */
+#define PRCM_REQ_MB5_I2C_SLAVE (PRCM_REQ_MB5 + 0)
+#define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 1)
+#define PRCM_REQ_MB5_I2C_SIZE (PRCM_REQ_MB5 + 2)
+#define PRCM_REQ_MB5_I2C_DATA (PRCM_REQ_MB5 + 4)
+
+/* Acknowledge mailbox 5 fields. */
+#define PRCM_ACK_MB5_RETURN_CODE (PRCM_ACK_MB5 + 0)
+#define PRCM_ACK_MB5_I2C_DATA (PRCM_ACK_MB5 + 4)
+
+#define NUM_MB 8
+#define MBOX_BIT BIT
+#define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1)
+
+/*
+* Used by MCDE to setup all necessary PRCMU registers
+*/
+#define PRCMU_RESET_DSIPLL                     0x00004000
+#define PRCMU_UNCLAMP_DSIPLL                   0x00400800
+
+/* HDMI CLK MGT PLLSW=001 (PLLSOC0), PLLDIV=0x8, = 50 Mhz*/
+#define PRCMU_DSI_CLOCK_SETTING                        0x00000128
+/* TVCLK_MGT PLLSW=001 (PLLSOC0) PLLDIV=0x13, = 19.05 MHZ */
+#define PRCMU_DSI_LP_CLOCK_SETTING             0x00000135
+#define PRCMU_PLLDSI_FREQ_SETTING              0x0004013C
+#define PRCMU_DSI_PLLOUT_SEL_SETTING           0x00000002
+#define PRCMU_ENABLE_ESCAPE_CLOCK_DIV          0x03000101
+#define PRCMU_DISABLE_ESCAPE_CLOCK_DIV         0x00000101
+
+#define PRCMU_ENABLE_PLLDSI                    0x00000001
+#define PRCMU_DISABLE_PLLDSI                   0x00000000
+
+#define PRCMU_DSI_RESET_SW                     0x00000003
+
+#define PRCMU_PLLDSI_LOCKP_LOCKED              0x3
+
+/*
+ * mb0_transfer - state needed for mailbox 0 communication.
+ * @lock:              The transaction lock.
+ */
+static struct {
+       spinlock_t lock;
+} mb0_transfer;
+
+/*
+ * mb5_transfer - state needed for mailbox 5 communication.
+ * @lock:      The transaction lock.
+ * @work:      The transaction completion structure.
+ * @ack:       Reply ("acknowledge") data.
+ */
+static struct {
+       struct mutex lock;
+       struct completion work;
+       struct {
+               u8 header;
+               u8 status;
+               u8 value[4];
+       } ack;
+} mb5_transfer;
+
+/* PRCMU TCDM base IO address. */
+static __iomem void *tcdm_base;
+
+/**
+ * db5500_prcmu_abb_read() - Read register value(s) from the ABB.
+ * @slave:     The I2C slave address.
+ * @reg:       The (start) register address.
+ * @value:     The read out value(s).
+ * @size:      The number of registers to read.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be <= 4.
+ */
+int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       int r;
+
+       if ((size < 1) || (4 < size))
+               return -EINVAL;
+
+       mutex_lock(&mb5_transfer.lock);
+
+       while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+               cpu_relax();
+       writeb(slave, PRCM_REQ_MB5_I2C_SLAVE);
+       writeb(reg, PRCM_REQ_MB5_I2C_REG);
+       writeb(size, PRCM_REQ_MB5_I2C_SIZE);
+       writeb(MB5H_I2C_READ, PRCM_REQ_MB5_HEADER);
+
+       writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
+       wait_for_completion(&mb5_transfer.work);
+
+       r = 0;
+       if ((mb5_transfer.ack.header == MB5H_I2C_READ) &&
+               (mb5_transfer.ack.status == RC_SUCCESS))
+               memcpy(value, mb5_transfer.ack.value, (size_t)size);
+       else
+               r = -EIO;
+
+       mutex_unlock(&mb5_transfer.lock);
+
+       return r;
+}
+
+/**
+ * db5500_prcmu_abb_write() - Write register value(s) to the ABB.
+ * @slave:     The I2C slave address.
+ * @reg:       The (start) register address.
+ * @value:     The value(s) to write.
+ * @size:      The number of registers to write.
+ *
+ * Writes register value(s) to the ABB.
+ * @size has to be <= 4.
+ */
+int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       int r;
+
+       if ((size < 1) || (4 < size))
+               return -EINVAL;
+
+       mutex_lock(&mb5_transfer.lock);
+
+       while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+               cpu_relax();
+       writeb(slave, PRCM_REQ_MB5_I2C_SLAVE);
+       writeb(reg, PRCM_REQ_MB5_I2C_REG);
+       writeb(size, PRCM_REQ_MB5_I2C_SIZE);
+       memcpy_toio(PRCM_REQ_MB5_I2C_DATA, value, size);
+       writeb(MB5H_I2C_WRITE, PRCM_REQ_MB5_HEADER);
+
+       writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
+       wait_for_completion(&mb5_transfer.work);
+
+       if ((mb5_transfer.ack.header == MB5H_I2C_WRITE) &&
+               (mb5_transfer.ack.status == RC_SUCCESS))
+               r = 0;
+       else
+               r = -EIO;
+
+       mutex_unlock(&mb5_transfer.lock);
+
+       return r;
+}
+
+int db5500_prcmu_enable_dsipll(void)
+{
+       int i;
+
+       /* Enable DSIPLL_RESETN resets */
+       writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR);
+       /* Unclamp DSIPLL in/out */
+       writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR);
+       /* Set DSI PLL FREQ */
+       writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ);
+       writel(PRCMU_DSI_PLLOUT_SEL_SETTING,
+               PRCM_DSI_PLLOUT_SEL);
+       /* Enable Escape clocks */
+       writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
+
+       /* Start DSI PLL */
+       writel(PRCMU_ENABLE_PLLDSI, PRCM_PLLDSI_ENABLE);
+       /* Reset DSI PLL */
+       writel(PRCMU_DSI_RESET_SW, PRCM_DSI_SW_RESET);
+       for (i = 0; i < 10; i++) {
+               if ((readl(PRCM_PLLDSI_LOCKP) &
+                       PRCMU_PLLDSI_LOCKP_LOCKED) == PRCMU_PLLDSI_LOCKP_LOCKED)
+                       break;
+               udelay(100);
+       }
+       /* Release DSIPLL_RESETN */
+       writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_SET);
+       return 0;
+}
+
+int db5500_prcmu_disable_dsipll(void)
+{
+       /* Disable dsi pll */
+       writel(PRCMU_DISABLE_PLLDSI, PRCM_PLLDSI_ENABLE);
+       /* Disable  escapeclock */
+       writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
+       return 0;
+}
+
+int db5500_prcmu_set_display_clocks(void)
+{
+       /* HDMI and TVCLK Should be handled somewhere else */
+       /* PLLDIV=8, PLLSW=2, CLKEN=1 */
+       writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT);
+       /* PLLDIV=14, PLLSW=2, CLKEN=1 */
+       writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT);
+       return 0;
+}
+
+static void ack_dbb_wakeup(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+       while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
+               cpu_relax();
+
+       writeb(RMB0H_RD_WAKE_UP_ACK, PRCM_REQ_MB0_HEADER);
+       writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET);
+
+       spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+static inline void print_unknown_header_warning(u8 n, u8 header)
+{
+       pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n",
+               header, n);
+}
+
+static bool read_mailbox_0(void)
+{
+       bool r;
+       u8 header;
+
+       header = readb(PRCM_ACK_MB0_HEADER);
+       switch (header) {
+       case AMB0H_WAKE_UP:
+               r = true;
+               break;
+       default:
+               print_unknown_header_warning(0, header);
+               r = false;
+               break;
+       }
+       writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR);
+       return r;
+}
+
+static bool read_mailbox_1(void)
+{
+       writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR);
+       return false;
+}
+
+static bool read_mailbox_2(void)
+{
+       writel(MBOX_BIT(2), PRCM_ARM_IT1_CLEAR);
+       return false;
+}
+
+static bool read_mailbox_3(void)
+{
+       writel(MBOX_BIT(3), PRCM_ARM_IT1_CLEAR);
+       return false;
+}
+
+static bool read_mailbox_4(void)
+{
+       writel(MBOX_BIT(4), PRCM_ARM_IT1_CLEAR);
+       return false;
+}
+
+static bool read_mailbox_5(void)
+{
+       u8 header;
+
+       header = readb(PRCM_ACK_MB5_HEADER);
+       switch (header) {
+       case MB5H_I2C_READ:
+               memcpy_fromio(mb5_transfer.ack.value, PRCM_ACK_MB5_I2C_DATA, 4);
+       case MB5H_I2C_WRITE:
+               mb5_transfer.ack.header = header;
+               mb5_transfer.ack.status = readb(PRCM_ACK_MB5_RETURN_CODE);
+               complete(&mb5_transfer.work);
+               break;
+       default:
+               print_unknown_header_warning(5, header);
+               break;
+       }
+       writel(MBOX_BIT(5), PRCM_ARM_IT1_CLEAR);
+       return false;
+}
+
+static bool read_mailbox_6(void)
+{
+       writel(MBOX_BIT(6), PRCM_ARM_IT1_CLEAR);
+       return false;
+}
+
+static bool read_mailbox_7(void)
+{
+       writel(MBOX_BIT(7), PRCM_ARM_IT1_CLEAR);
+       return false;
+}
+
+static bool (* const read_mailbox[NUM_MB])(void) = {
+       read_mailbox_0,
+       read_mailbox_1,
+       read_mailbox_2,
+       read_mailbox_3,
+       read_mailbox_4,
+       read_mailbox_5,
+       read_mailbox_6,
+       read_mailbox_7
+};
+
+static irqreturn_t prcmu_irq_handler(int irq, void *data)
+{
+       u32 bits;
+       u8 n;
+       irqreturn_t r;
+
+       bits = (readl(PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS);
+       if (unlikely(!bits))
+               return IRQ_NONE;
+
+       r = IRQ_HANDLED;
+       for (n = 0; bits; n++) {
+               if (bits & MBOX_BIT(n)) {
+                       bits -= MBOX_BIT(n);
+                       if (read_mailbox[n]())
+                               r = IRQ_WAKE_THREAD;
+               }
+       }
+       return r;
+}
+
+static irqreturn_t prcmu_irq_thread_fn(int irq, void *data)
+{
+       ack_dbb_wakeup();
+       return IRQ_HANDLED;
+}
+
+void __init db5500_prcmu_early_init(void)
+{
+       tcdm_base = __io_address(U5500_PRCMU_TCDM_BASE);
+       spin_lock_init(&mb0_transfer.lock);
+       mutex_init(&mb5_transfer.lock);
+       init_completion(&mb5_transfer.work);
+}
+
+/**
+ * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic
+ *
+ */
+int __init db5500_prcmu_init(void)
+{
+       int r = 0;
+
+       if (ux500_is_svp() || !cpu_is_u5500())
+               return -ENODEV;
+
+       /* Clean up the mailbox interrupts after pre-kernel code. */
+       writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLEAR);
+
+       r = request_threaded_irq(IRQ_DB5500_PRCMU1, prcmu_irq_handler,
+               prcmu_irq_thread_fn, 0, "prcmu", NULL);
+       if (r < 0) {
+               pr_err("prcmu: Failed to allocate IRQ_DB5500_PRCMU1.\n");
+               return -EBUSY;
+       }
+       return 0;
+}
+
+arch_initcall(db5500_prcmu_init);
diff --git a/drivers/mfd/db8500-prcmu-regs.h b/drivers/mfd/db8500-prcmu-regs.h
new file mode 100644 (file)
index 0000000..3bbf04d
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * PRCM Unit registers
+ */
+#ifndef __DB8500_PRCMU_REGS_H
+#define __DB8500_PRCMU_REGS_H
+
+#include <linux/bitops.h>
+#include <mach/hardware.h>
+
+#define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end))
+
+#define PRCM_ARM_PLLDIVPS 0x118
+#define PRCM_ARM_PLLDIVPS_ARM_BRM_RATE BITS(0, 5)
+#define PRCM_ARM_PLLDIVPS_MAX_MASK     0xF
+
+#define PRCM_PLLARM_LOCKP 0x0A8
+#define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3 BIT(1)
+
+#define PRCM_ARM_CHGCLKREQ 0x114
+#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ BIT(0)
+
+#define PRCM_PLLARM_ENABLE 0x98
+#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE  BIT(0)
+#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_COUNTON BIT(8)
+
+#define PRCM_ARMCLKFIX_MGT     0x0
+#define PRCM_A9_RESETN_CLR     0x1f4
+#define PRCM_A9_RESETN_SET     0x1f0
+#define PRCM_ARM_LS_CLAMP      0x30C
+#define PRCM_SRAM_A9           0x308
+
+/* ARM WFI Standby signal register */
+#define PRCM_ARM_WFI_STANDBY   0x130
+#define PRCM_IOCR              0x310
+#define PRCM_IOCR_IOFORCE BIT(0)
+
+/* CPU mailbox registers */
+#define PRCM_MBOX_CPU_VAL 0x0FC
+#define PRCM_MBOX_CPU_SET 0x100
+
+/* Dual A9 core interrupt management unit registers */
+#define PRCM_A9_MASK_REQ 0x328
+#define PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ BIT(0)
+
+#define PRCM_A9_MASK_ACK       0x32C
+#define PRCM_ARMITMSK31TO0     0x11C
+#define PRCM_ARMITMSK63TO32    0x120
+#define PRCM_ARMITMSK95TO64    0x124
+#define PRCM_ARMITMSK127TO96   0x128
+#define PRCM_POWER_STATE_VAL   0x25C
+#define PRCM_ARMITVAL31TO0     0x260
+#define PRCM_ARMITVAL63TO32    0x264
+#define PRCM_ARMITVAL95TO64    0x268
+#define PRCM_ARMITVAL127TO96   0x26C
+
+#define PRCM_HOSTACCESS_REQ 0x334
+#define PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ BIT(0)
+
+#define PRCM_ARM_IT1_CLR 0x48C
+#define PRCM_ARM_IT1_VAL 0x494
+
+#define PRCM_ITSTATUS0         0x148
+#define PRCM_ITSTATUS1         0x150
+#define PRCM_ITSTATUS2         0x158
+#define PRCM_ITSTATUS3         0x160
+#define PRCM_ITSTATUS4         0x168
+#define PRCM_ITSTATUS5         0x484
+#define PRCM_ITCLEAR5          0x488
+#define PRCM_ARMIT_MASKXP70_IT 0x1018
+
+/* System reset register */
+#define PRCM_APE_SOFTRST 0x228
+
+/* Level shifter and clamp control registers */
+#define PRCM_MMIP_LS_CLAMP_SET 0x420
+#define PRCM_MMIP_LS_CLAMP_CLR 0x424
+
+/* PRCMU HW semaphore */
+#define PRCM_SEM 0x400
+#define PRCM_SEM_PRCM_SEM BIT(0)
+
+/* PRCMU clock/PLL/reset registers */
+#define PRCM_PLLDSI_FREQ       0x500
+#define PRCM_PLLDSI_ENABLE     0x504
+#define PRCM_PLLDSI_LOCKP      0x508
+#define PRCM_DSI_PLLOUT_SEL    0x530
+#define PRCM_DSITVCLK_DIV      0x52C
+#define PRCM_APE_RESETN_SET    0x1E4
+#define PRCM_APE_RESETN_CLR    0x1E8
+
+#define PRCM_TCR               0x1C8
+#define PRCM_TCR_TENSEL_MASK   BITS(0, 7)
+#define PRCM_TCR_STOP_TIMERS   BIT(16)
+#define PRCM_TCR_DOZE_MODE     BIT(17)
+
+#define PRCM_CLKOCR                    0x1CC
+#define PRCM_CLKOCR_CLKODIV0_SHIFT     0
+#define PRCM_CLKOCR_CLKODIV0_MASK      BITS(0, 5)
+#define PRCM_CLKOCR_CLKOSEL0_SHIFT     6
+#define PRCM_CLKOCR_CLKOSEL0_MASK      BITS(6, 8)
+#define PRCM_CLKOCR_CLKODIV1_SHIFT     16
+#define PRCM_CLKOCR_CLKODIV1_MASK      BITS(16, 21)
+#define PRCM_CLKOCR_CLKOSEL1_SHIFT     22
+#define PRCM_CLKOCR_CLKOSEL1_MASK      BITS(22, 24)
+#define PRCM_CLKOCR_CLK1TYPE           BIT(28)
+
+#define PRCM_SGACLK_MGT                0x014
+#define PRCM_UARTCLK_MGT       0x018
+#define PRCM_MSP02CLK_MGT      0x01C
+#define PRCM_MSP1CLK_MGT       0x288
+#define PRCM_I2CCLK_MGT                0x020
+#define PRCM_SDMMCCLK_MGT      0x024
+#define PRCM_SLIMCLK_MGT       0x028
+#define PRCM_PER1CLK_MGT       0x02C
+#define PRCM_PER2CLK_MGT       0x030
+#define PRCM_PER3CLK_MGT       0x034
+#define PRCM_PER5CLK_MGT       0x038
+#define PRCM_PER6CLK_MGT       0x03C
+#define PRCM_PER7CLK_MGT       0x040
+#define PRCM_LCDCLK_MGT                0x044
+#define PRCM_BMLCLK_MGT                0x04C
+#define PRCM_HSITXCLK_MGT      0x050
+#define PRCM_HSIRXCLK_MGT      0x054
+#define PRCM_HDMICLK_MGT       0x058
+#define PRCM_APEATCLK_MGT      0x05C
+#define PRCM_APETRACECLK_MGT   0x060
+#define PRCM_MCDECLK_MGT       0x064
+#define PRCM_IPI2CCLK_MGT      0x068
+#define PRCM_DSIALTCLK_MGT     0x06C
+#define PRCM_DMACLK_MGT                0x074
+#define PRCM_B2R2CLK_MGT       0x078
+#define PRCM_TVCLK_MGT         0x07C
+#define PRCM_UNIPROCLK_MGT     0x278
+#define PRCM_SSPCLK_MGT                0x280
+#define PRCM_RNGCLK_MGT                0x284
+#define PRCM_UICCCLK_MGT       0x27C
+
+#define PRCM_CLK_MGT_CLKPLLDIV_MASK    BITS(0, 4)
+#define PRCM_CLK_MGT_CLKPLLSW_MASK     BITS(5, 7)
+#define PRCM_CLK_MGT_CLKEN             BIT(8)
+
+/* ePOD and memory power signal control registers */
+#define PRCM_EPOD_C_SET                0x410
+#define PRCM_SRAM_LS_SLEEP     0x304
+
+/* Debug power control unit registers */
+#define PRCM_POWER_STATE_SET 0x254
+
+/* Miscellaneous unit registers */
+#define PRCM_DSI_SW_RESET 0x324
+#define PRCM_GPIOCR            0x138
+
+/* GPIOCR register */
+#define PRCM_GPIOCR_SPI2_SELECT BIT(23)
+
+#define PRCM_DDR_SUBSYS_APE_MINBW  0x438
+
+#endif /* __DB8500_PRCMU_REGS_H */
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
new file mode 100644 (file)
index 0000000..02a15d7
--- /dev/null
@@ -0,0 +1,2070 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
+ *
+ * U8500 PRCM Unit interface driver
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/bitops.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/db8500-prcmu.h>
+#include <linux/regulator/db8500-prcmu.h>
+#include <linux/regulator/machine.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/db8500-regs.h>
+#include <mach/id.h>
+#include "db8500-prcmu-regs.h"
+
+/* Offset for the firmware version within the TCPM */
+#define PRCMU_FW_VERSION_OFFSET 0xA4
+
+/* PRCMU project numbers, defined by PRCMU FW */
+#define PRCMU_PROJECT_ID_8500V1_0 1
+#define PRCMU_PROJECT_ID_8500V2_0 2
+#define PRCMU_PROJECT_ID_8400V2_0 3
+
+/* Index of different voltages to be used when accessing AVSData */
+#define PRCM_AVS_BASE          0x2FC
+#define PRCM_AVS_VBB_RET       (PRCM_AVS_BASE + 0x0)
+#define PRCM_AVS_VBB_MAX_OPP   (PRCM_AVS_BASE + 0x1)
+#define PRCM_AVS_VBB_100_OPP   (PRCM_AVS_BASE + 0x2)
+#define PRCM_AVS_VBB_50_OPP    (PRCM_AVS_BASE + 0x3)
+#define PRCM_AVS_VARM_MAX_OPP  (PRCM_AVS_BASE + 0x4)
+#define PRCM_AVS_VARM_100_OPP  (PRCM_AVS_BASE + 0x5)
+#define PRCM_AVS_VARM_50_OPP   (PRCM_AVS_BASE + 0x6)
+#define PRCM_AVS_VARM_RET      (PRCM_AVS_BASE + 0x7)
+#define PRCM_AVS_VAPE_100_OPP  (PRCM_AVS_BASE + 0x8)
+#define PRCM_AVS_VAPE_50_OPP   (PRCM_AVS_BASE + 0x9)
+#define PRCM_AVS_VMOD_100_OPP  (PRCM_AVS_BASE + 0xA)
+#define PRCM_AVS_VMOD_50_OPP   (PRCM_AVS_BASE + 0xB)
+#define PRCM_AVS_VSAFE         (PRCM_AVS_BASE + 0xC)
+
+#define PRCM_AVS_VOLTAGE               0
+#define PRCM_AVS_VOLTAGE_MASK          0x3f
+#define PRCM_AVS_ISSLOWSTARTUP         6
+#define PRCM_AVS_ISSLOWSTARTUP_MASK    (1 << PRCM_AVS_ISSLOWSTARTUP)
+#define PRCM_AVS_ISMODEENABLE          7
+#define PRCM_AVS_ISMODEENABLE_MASK     (1 << PRCM_AVS_ISMODEENABLE)
+
+#define PRCM_BOOT_STATUS       0xFFF
+#define PRCM_ROMCODE_A2P       0xFFE
+#define PRCM_ROMCODE_P2A       0xFFD
+#define PRCM_XP70_CUR_PWR_STATE 0xFFC      /* 4 BYTES */
+
+#define PRCM_SW_RST_REASON 0xFF8 /* 2 bytes */
+
+#define _PRCM_MBOX_HEADER              0xFE8 /* 16 bytes */
+#define PRCM_MBOX_HEADER_REQ_MB0       (_PRCM_MBOX_HEADER + 0x0)
+#define PRCM_MBOX_HEADER_REQ_MB1       (_PRCM_MBOX_HEADER + 0x1)
+#define PRCM_MBOX_HEADER_REQ_MB2       (_PRCM_MBOX_HEADER + 0x2)
+#define PRCM_MBOX_HEADER_REQ_MB3       (_PRCM_MBOX_HEADER + 0x3)
+#define PRCM_MBOX_HEADER_REQ_MB4       (_PRCM_MBOX_HEADER + 0x4)
+#define PRCM_MBOX_HEADER_REQ_MB5       (_PRCM_MBOX_HEADER + 0x5)
+#define PRCM_MBOX_HEADER_ACK_MB0       (_PRCM_MBOX_HEADER + 0x8)
+
+/* Req Mailboxes */
+#define PRCM_REQ_MB0 0xFDC /* 12 bytes  */
+#define PRCM_REQ_MB1 0xFD0 /* 12 bytes  */
+#define PRCM_REQ_MB2 0xFC0 /* 16 bytes  */
+#define PRCM_REQ_MB3 0xE4C /* 372 bytes  */
+#define PRCM_REQ_MB4 0xE48 /* 4 bytes  */
+#define PRCM_REQ_MB5 0xE44 /* 4 bytes  */
+
+/* Ack Mailboxes */
+#define PRCM_ACK_MB0 0xE08 /* 52 bytes  */
+#define PRCM_ACK_MB1 0xE04 /* 4 bytes */
+#define PRCM_ACK_MB2 0xE00 /* 4 bytes */
+#define PRCM_ACK_MB3 0xDFC /* 4 bytes */
+#define PRCM_ACK_MB4 0xDF8 /* 4 bytes */
+#define PRCM_ACK_MB5 0xDF4 /* 4 bytes */
+
+/* Mailbox 0 headers */
+#define MB0H_POWER_STATE_TRANS         0
+#define MB0H_CONFIG_WAKEUPS_EXE                1
+#define MB0H_READ_WAKEUP_ACK           3
+#define MB0H_CONFIG_WAKEUPS_SLEEP      4
+
+#define MB0H_WAKEUP_EXE 2
+#define MB0H_WAKEUP_SLEEP 5
+
+/* Mailbox 0 REQs */
+#define PRCM_REQ_MB0_AP_POWER_STATE    (PRCM_REQ_MB0 + 0x0)
+#define PRCM_REQ_MB0_AP_PLL_STATE      (PRCM_REQ_MB0 + 0x1)
+#define PRCM_REQ_MB0_ULP_CLOCK_STATE   (PRCM_REQ_MB0 + 0x2)
+#define PRCM_REQ_MB0_DO_NOT_WFI                (PRCM_REQ_MB0 + 0x3)
+#define PRCM_REQ_MB0_WAKEUP_8500       (PRCM_REQ_MB0 + 0x4)
+#define PRCM_REQ_MB0_WAKEUP_4500       (PRCM_REQ_MB0 + 0x8)
+
+/* Mailbox 0 ACKs */
+#define PRCM_ACK_MB0_AP_PWRSTTR_STATUS (PRCM_ACK_MB0 + 0x0)
+#define PRCM_ACK_MB0_READ_POINTER      (PRCM_ACK_MB0 + 0x1)
+#define PRCM_ACK_MB0_WAKEUP_0_8500     (PRCM_ACK_MB0 + 0x4)
+#define PRCM_ACK_MB0_WAKEUP_0_4500     (PRCM_ACK_MB0 + 0x8)
+#define PRCM_ACK_MB0_WAKEUP_1_8500     (PRCM_ACK_MB0 + 0x1C)
+#define PRCM_ACK_MB0_WAKEUP_1_4500     (PRCM_ACK_MB0 + 0x20)
+#define PRCM_ACK_MB0_EVENT_4500_NUMBERS        20
+
+/* Mailbox 1 headers */
+#define MB1H_ARM_APE_OPP 0x0
+#define MB1H_RESET_MODEM 0x2
+#define MB1H_REQUEST_APE_OPP_100_VOLT 0x3
+#define MB1H_RELEASE_APE_OPP_100_VOLT 0x4
+#define MB1H_RELEASE_USB_WAKEUP 0x5
+
+/* Mailbox 1 Requests */
+#define PRCM_REQ_MB1_ARM_OPP                   (PRCM_REQ_MB1 + 0x0)
+#define PRCM_REQ_MB1_APE_OPP                   (PRCM_REQ_MB1 + 0x1)
+#define PRCM_REQ_MB1_APE_OPP_100_RESTORE       (PRCM_REQ_MB1 + 0x4)
+#define PRCM_REQ_MB1_ARM_OPP_100_RESTORE       (PRCM_REQ_MB1 + 0x8)
+
+/* Mailbox 1 ACKs */
+#define PRCM_ACK_MB1_CURRENT_ARM_OPP   (PRCM_ACK_MB1 + 0x0)
+#define PRCM_ACK_MB1_CURRENT_APE_OPP   (PRCM_ACK_MB1 + 0x1)
+#define PRCM_ACK_MB1_APE_VOLTAGE_STATUS        (PRCM_ACK_MB1 + 0x2)
+#define PRCM_ACK_MB1_DVFS_STATUS       (PRCM_ACK_MB1 + 0x3)
+
+/* Mailbox 2 headers */
+#define MB2H_DPS       0x0
+#define MB2H_AUTO_PWR  0x1
+
+/* Mailbox 2 REQs */
+#define PRCM_REQ_MB2_SVA_MMDSP         (PRCM_REQ_MB2 + 0x0)
+#define PRCM_REQ_MB2_SVA_PIPE          (PRCM_REQ_MB2 + 0x1)
+#define PRCM_REQ_MB2_SIA_MMDSP         (PRCM_REQ_MB2 + 0x2)
+#define PRCM_REQ_MB2_SIA_PIPE          (PRCM_REQ_MB2 + 0x3)
+#define PRCM_REQ_MB2_SGA               (PRCM_REQ_MB2 + 0x4)
+#define PRCM_REQ_MB2_B2R2_MCDE         (PRCM_REQ_MB2 + 0x5)
+#define PRCM_REQ_MB2_ESRAM12           (PRCM_REQ_MB2 + 0x6)
+#define PRCM_REQ_MB2_ESRAM34           (PRCM_REQ_MB2 + 0x7)
+#define PRCM_REQ_MB2_AUTO_PM_SLEEP     (PRCM_REQ_MB2 + 0x8)
+#define PRCM_REQ_MB2_AUTO_PM_IDLE      (PRCM_REQ_MB2 + 0xC)
+
+/* Mailbox 2 ACKs */
+#define PRCM_ACK_MB2_DPS_STATUS (PRCM_ACK_MB2 + 0x0)
+#define HWACC_PWR_ST_OK 0xFE
+
+/* Mailbox 3 headers */
+#define MB3H_ANC       0x0
+#define MB3H_SIDETONE  0x1
+#define MB3H_SYSCLK    0xE
+
+/* Mailbox 3 Requests */
+#define PRCM_REQ_MB3_ANC_FIR_COEFF     (PRCM_REQ_MB3 + 0x0)
+#define PRCM_REQ_MB3_ANC_IIR_COEFF     (PRCM_REQ_MB3 + 0x20)
+#define PRCM_REQ_MB3_ANC_SHIFTER       (PRCM_REQ_MB3 + 0x60)
+#define PRCM_REQ_MB3_ANC_WARP          (PRCM_REQ_MB3 + 0x64)
+#define PRCM_REQ_MB3_SIDETONE_FIR_GAIN (PRCM_REQ_MB3 + 0x68)
+#define PRCM_REQ_MB3_SIDETONE_FIR_COEFF        (PRCM_REQ_MB3 + 0x6C)
+#define PRCM_REQ_MB3_SYSCLK_MGT                (PRCM_REQ_MB3 + 0x16C)
+
+/* Mailbox 4 headers */
+#define MB4H_DDR_INIT  0x0
+#define MB4H_MEM_ST    0x1
+#define MB4H_HOTDOG    0x12
+#define MB4H_HOTMON    0x13
+#define MB4H_HOT_PERIOD        0x14
+
+/* Mailbox 4 Requests */
+#define PRCM_REQ_MB4_DDR_ST_AP_SLEEP_IDLE      (PRCM_REQ_MB4 + 0x0)
+#define PRCM_REQ_MB4_DDR_ST_AP_DEEP_IDLE       (PRCM_REQ_MB4 + 0x1)
+#define PRCM_REQ_MB4_ESRAM0_ST                 (PRCM_REQ_MB4 + 0x3)
+#define PRCM_REQ_MB4_HOTDOG_THRESHOLD          (PRCM_REQ_MB4 + 0x0)
+#define PRCM_REQ_MB4_HOTMON_LOW                        (PRCM_REQ_MB4 + 0x0)
+#define PRCM_REQ_MB4_HOTMON_HIGH               (PRCM_REQ_MB4 + 0x1)
+#define PRCM_REQ_MB4_HOTMON_CONFIG             (PRCM_REQ_MB4 + 0x2)
+#define PRCM_REQ_MB4_HOT_PERIOD                        (PRCM_REQ_MB4 + 0x0)
+#define HOTMON_CONFIG_LOW                      BIT(0)
+#define HOTMON_CONFIG_HIGH                     BIT(1)
+
+/* Mailbox 5 Requests */
+#define PRCM_REQ_MB5_I2C_SLAVE_OP      (PRCM_REQ_MB5 + 0x0)
+#define PRCM_REQ_MB5_I2C_HW_BITS       (PRCM_REQ_MB5 + 0x1)
+#define PRCM_REQ_MB5_I2C_REG           (PRCM_REQ_MB5 + 0x2)
+#define PRCM_REQ_MB5_I2C_VAL           (PRCM_REQ_MB5 + 0x3)
+#define PRCMU_I2C_WRITE(slave) \
+       (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0))
+#define PRCMU_I2C_READ(slave) \
+       (((slave) << 1) | BIT(0) | (cpu_is_u8500v2() ? BIT(6) : 0))
+#define PRCMU_I2C_STOP_EN              BIT(3)
+
+/* Mailbox 5 ACKs */
+#define PRCM_ACK_MB5_I2C_STATUS        (PRCM_ACK_MB5 + 0x1)
+#define PRCM_ACK_MB5_I2C_VAL   (PRCM_ACK_MB5 + 0x3)
+#define I2C_WR_OK 0x1
+#define I2C_RD_OK 0x2
+
+#define NUM_MB 8
+#define MBOX_BIT BIT
+#define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1)
+
+/*
+ * Wakeups/IRQs
+ */
+
+#define WAKEUP_BIT_RTC BIT(0)
+#define WAKEUP_BIT_RTT0 BIT(1)
+#define WAKEUP_BIT_RTT1 BIT(2)
+#define WAKEUP_BIT_HSI0 BIT(3)
+#define WAKEUP_BIT_HSI1 BIT(4)
+#define WAKEUP_BIT_CA_WAKE BIT(5)
+#define WAKEUP_BIT_USB BIT(6)
+#define WAKEUP_BIT_ABB BIT(7)
+#define WAKEUP_BIT_ABB_FIFO BIT(8)
+#define WAKEUP_BIT_SYSCLK_OK BIT(9)
+#define WAKEUP_BIT_CA_SLEEP BIT(10)
+#define WAKEUP_BIT_AC_WAKE_ACK BIT(11)
+#define WAKEUP_BIT_SIDE_TONE_OK BIT(12)
+#define WAKEUP_BIT_ANC_OK BIT(13)
+#define WAKEUP_BIT_SW_ERROR BIT(14)
+#define WAKEUP_BIT_AC_SLEEP_ACK BIT(15)
+#define WAKEUP_BIT_ARM BIT(17)
+#define WAKEUP_BIT_HOTMON_LOW BIT(18)
+#define WAKEUP_BIT_HOTMON_HIGH BIT(19)
+#define WAKEUP_BIT_MODEM_SW_RESET_REQ BIT(20)
+#define WAKEUP_BIT_GPIO0 BIT(23)
+#define WAKEUP_BIT_GPIO1 BIT(24)
+#define WAKEUP_BIT_GPIO2 BIT(25)
+#define WAKEUP_BIT_GPIO3 BIT(26)
+#define WAKEUP_BIT_GPIO4 BIT(27)
+#define WAKEUP_BIT_GPIO5 BIT(28)
+#define WAKEUP_BIT_GPIO6 BIT(29)
+#define WAKEUP_BIT_GPIO7 BIT(30)
+#define WAKEUP_BIT_GPIO8 BIT(31)
+
+/*
+ * This vector maps irq numbers to the bits in the bit field used in
+ * communication with the PRCMU firmware.
+ *
+ * The reason for having this is to keep the irq numbers contiguous even though
+ * the bits in the bit field are not. (The bits also have a tendency to move
+ * around, to further complicate matters.)
+ */
+#define IRQ_INDEX(_name) ((IRQ_PRCMU_##_name) - IRQ_PRCMU_BASE)
+#define IRQ_ENTRY(_name)[IRQ_INDEX(_name)] = (WAKEUP_BIT_##_name)
+static u32 prcmu_irq_bit[NUM_PRCMU_WAKEUPS] = {
+       IRQ_ENTRY(RTC),
+       IRQ_ENTRY(RTT0),
+       IRQ_ENTRY(RTT1),
+       IRQ_ENTRY(HSI0),
+       IRQ_ENTRY(HSI1),
+       IRQ_ENTRY(CA_WAKE),
+       IRQ_ENTRY(USB),
+       IRQ_ENTRY(ABB),
+       IRQ_ENTRY(ABB_FIFO),
+       IRQ_ENTRY(CA_SLEEP),
+       IRQ_ENTRY(ARM),
+       IRQ_ENTRY(HOTMON_LOW),
+       IRQ_ENTRY(HOTMON_HIGH),
+       IRQ_ENTRY(MODEM_SW_RESET_REQ),
+       IRQ_ENTRY(GPIO0),
+       IRQ_ENTRY(GPIO1),
+       IRQ_ENTRY(GPIO2),
+       IRQ_ENTRY(GPIO3),
+       IRQ_ENTRY(GPIO4),
+       IRQ_ENTRY(GPIO5),
+       IRQ_ENTRY(GPIO6),
+       IRQ_ENTRY(GPIO7),
+       IRQ_ENTRY(GPIO8)
+};
+
+#define VALID_WAKEUPS (BIT(NUM_PRCMU_WAKEUP_INDICES) - 1)
+#define WAKEUP_ENTRY(_name)[PRCMU_WAKEUP_INDEX_##_name] = (WAKEUP_BIT_##_name)
+static u32 prcmu_wakeup_bit[NUM_PRCMU_WAKEUP_INDICES] = {
+       WAKEUP_ENTRY(RTC),
+       WAKEUP_ENTRY(RTT0),
+       WAKEUP_ENTRY(RTT1),
+       WAKEUP_ENTRY(HSI0),
+       WAKEUP_ENTRY(HSI1),
+       WAKEUP_ENTRY(USB),
+       WAKEUP_ENTRY(ABB),
+       WAKEUP_ENTRY(ABB_FIFO),
+       WAKEUP_ENTRY(ARM)
+};
+
+/*
+ * mb0_transfer - state needed for mailbox 0 communication.
+ * @lock:              The transaction lock.
+ * @dbb_events_lock:   A lock used to handle concurrent access to (parts of)
+ *                     the request data.
+ * @mask_work:         Work structure used for (un)masking wakeup interrupts.
+ * @req:               Request data that need to persist between requests.
+ */
+static struct {
+       spinlock_t lock;
+       spinlock_t dbb_irqs_lock;
+       struct work_struct mask_work;
+       struct mutex ac_wake_lock;
+       struct completion ac_wake_work;
+       struct {
+               u32 dbb_irqs;
+               u32 dbb_wakeups;
+               u32 abb_events;
+       } req;
+} mb0_transfer;
+
+/*
+ * mb1_transfer - state needed for mailbox 1 communication.
+ * @lock:      The transaction lock.
+ * @work:      The transaction completion structure.
+ * @ack:       Reply ("acknowledge") data.
+ */
+static struct {
+       struct mutex lock;
+       struct completion work;
+       struct {
+               u8 header;
+               u8 arm_opp;
+               u8 ape_opp;
+               u8 ape_voltage_status;
+       } ack;
+} mb1_transfer;
+
+/*
+ * mb2_transfer - state needed for mailbox 2 communication.
+ * @lock:            The transaction lock.
+ * @work:            The transaction completion structure.
+ * @auto_pm_lock:    The autonomous power management configuration lock.
+ * @auto_pm_enabled: A flag indicating whether autonomous PM is enabled.
+ * @req:             Request data that need to persist between requests.
+ * @ack:             Reply ("acknowledge") data.
+ */
+static struct {
+       struct mutex lock;
+       struct completion work;
+       spinlock_t auto_pm_lock;
+       bool auto_pm_enabled;
+       struct {
+               u8 status;
+       } ack;
+} mb2_transfer;
+
+/*
+ * mb3_transfer - state needed for mailbox 3 communication.
+ * @lock:              The request lock.
+ * @sysclk_lock:       A lock used to handle concurrent sysclk requests.
+ * @sysclk_work:       Work structure used for sysclk requests.
+ */
+static struct {
+       spinlock_t lock;
+       struct mutex sysclk_lock;
+       struct completion sysclk_work;
+} mb3_transfer;
+
+/*
+ * mb4_transfer - state needed for mailbox 4 communication.
+ * @lock:      The transaction lock.
+ * @work:      The transaction completion structure.
+ */
+static struct {
+       struct mutex lock;
+       struct completion work;
+} mb4_transfer;
+
+/*
+ * mb5_transfer - state needed for mailbox 5 communication.
+ * @lock:      The transaction lock.
+ * @work:      The transaction completion structure.
+ * @ack:       Reply ("acknowledge") data.
+ */
+static struct {
+       struct mutex lock;
+       struct completion work;
+       struct {
+               u8 status;
+               u8 value;
+       } ack;
+} mb5_transfer;
+
+static atomic_t ac_wake_req_state = ATOMIC_INIT(0);
+
+/* Spinlocks */
+static DEFINE_SPINLOCK(clkout_lock);
+static DEFINE_SPINLOCK(gpiocr_lock);
+
+/* Global var to runtime determine TCDM base for v2 or v1 */
+static __iomem void *tcdm_base;
+
+struct clk_mgt {
+       unsigned int offset;
+       u32 pllsw;
+};
+
+static DEFINE_SPINLOCK(clk_mgt_lock);
+
+#define CLK_MGT_ENTRY(_name)[PRCMU_##_name] = { (PRCM_##_name##_MGT), 0 }
+struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
+       CLK_MGT_ENTRY(SGACLK),
+       CLK_MGT_ENTRY(UARTCLK),
+       CLK_MGT_ENTRY(MSP02CLK),
+       CLK_MGT_ENTRY(MSP1CLK),
+       CLK_MGT_ENTRY(I2CCLK),
+       CLK_MGT_ENTRY(SDMMCCLK),
+       CLK_MGT_ENTRY(SLIMCLK),
+       CLK_MGT_ENTRY(PER1CLK),
+       CLK_MGT_ENTRY(PER2CLK),
+       CLK_MGT_ENTRY(PER3CLK),
+       CLK_MGT_ENTRY(PER5CLK),
+       CLK_MGT_ENTRY(PER6CLK),
+       CLK_MGT_ENTRY(PER7CLK),
+       CLK_MGT_ENTRY(LCDCLK),
+       CLK_MGT_ENTRY(BMLCLK),
+       CLK_MGT_ENTRY(HSITXCLK),
+       CLK_MGT_ENTRY(HSIRXCLK),
+       CLK_MGT_ENTRY(HDMICLK),
+       CLK_MGT_ENTRY(APEATCLK),
+       CLK_MGT_ENTRY(APETRACECLK),
+       CLK_MGT_ENTRY(MCDECLK),
+       CLK_MGT_ENTRY(IPI2CCLK),
+       CLK_MGT_ENTRY(DSIALTCLK),
+       CLK_MGT_ENTRY(DMACLK),
+       CLK_MGT_ENTRY(B2R2CLK),
+       CLK_MGT_ENTRY(TVCLK),
+       CLK_MGT_ENTRY(SSPCLK),
+       CLK_MGT_ENTRY(RNGCLK),
+       CLK_MGT_ENTRY(UICCCLK),
+};
+
+/*
+* Used by MCDE to setup all necessary PRCMU registers
+*/
+#define PRCMU_RESET_DSIPLL             0x00004000
+#define PRCMU_UNCLAMP_DSIPLL           0x00400800
+
+#define PRCMU_CLK_PLL_DIV_SHIFT                0
+#define PRCMU_CLK_PLL_SW_SHIFT         5
+#define PRCMU_CLK_38                   (1 << 9)
+#define PRCMU_CLK_38_SRC               (1 << 10)
+#define PRCMU_CLK_38_DIV               (1 << 11)
+
+/* PLLDIV=12, PLLSW=4 (PLLDDR) */
+#define PRCMU_DSI_CLOCK_SETTING                0x0000008C
+
+/* PLLDIV=8, PLLSW=4 (PLLDDR) */
+#define PRCMU_DSI_CLOCK_SETTING_U8400  0x00000088
+
+/* DPI 50000000 Hz */
+#define PRCMU_DPI_CLOCK_SETTING                ((1 << PRCMU_CLK_PLL_SW_SHIFT) | \
+                                         (16 << PRCMU_CLK_PLL_DIV_SHIFT))
+#define PRCMU_DSI_LP_CLOCK_SETTING     0x00000E00
+
+/* D=101, N=1, R=4, SELDIV2=0 */
+#define PRCMU_PLLDSI_FREQ_SETTING      0x00040165
+
+/* D=70, N=1, R=3, SELDIV2=0 */
+#define PRCMU_PLLDSI_FREQ_SETTING_U8400        0x00030146
+
+#define PRCMU_ENABLE_PLLDSI            0x00000001
+#define PRCMU_DISABLE_PLLDSI           0x00000000
+#define PRCMU_RELEASE_RESET_DSS                0x0000400C
+#define PRCMU_DSI_PLLOUT_SEL_SETTING   0x00000202
+/* ESC clk, div0=1, div1=1, div2=3 */
+#define PRCMU_ENABLE_ESCAPE_CLOCK_DIV  0x07030101
+#define PRCMU_DISABLE_ESCAPE_CLOCK_DIV 0x00030101
+#define PRCMU_DSI_RESET_SW             0x00000007
+
+#define PRCMU_PLLDSI_LOCKP_LOCKED      0x3
+
+static struct {
+       u8 project_number;
+       u8 api_version;
+       u8 func_version;
+       u8 errata;
+} prcmu_version;
+
+
+int prcmu_enable_dsipll(void)
+{
+       int i;
+       unsigned int plldsifreq;
+
+       /* Clear DSIPLL_RESETN */
+       writel(PRCMU_RESET_DSIPLL, (_PRCMU_BASE + PRCM_APE_RESETN_CLR));
+       /* Unclamp DSIPLL in/out */
+       writel(PRCMU_UNCLAMP_DSIPLL, (_PRCMU_BASE + PRCM_MMIP_LS_CLAMP_CLR));
+
+       if (prcmu_is_u8400())
+               plldsifreq = PRCMU_PLLDSI_FREQ_SETTING_U8400;
+       else
+               plldsifreq = PRCMU_PLLDSI_FREQ_SETTING;
+       /* Set DSI PLL FREQ */
+       writel(plldsifreq, (_PRCMU_BASE + PRCM_PLLDSI_FREQ));
+       writel(PRCMU_DSI_PLLOUT_SEL_SETTING,
+               (_PRCMU_BASE + PRCM_DSI_PLLOUT_SEL));
+       /* Enable Escape clocks */
+       writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV,
+                                       (_PRCMU_BASE + PRCM_DSITVCLK_DIV));
+
+       /* Start DSI PLL */
+       writel(PRCMU_ENABLE_PLLDSI, (_PRCMU_BASE + PRCM_PLLDSI_ENABLE));
+       /* Reset DSI PLL */
+       writel(PRCMU_DSI_RESET_SW, (_PRCMU_BASE + PRCM_DSI_SW_RESET));
+       for (i = 0; i < 10; i++) {
+               if ((readl(_PRCMU_BASE + PRCM_PLLDSI_LOCKP) &
+                       PRCMU_PLLDSI_LOCKP_LOCKED)
+                                       == PRCMU_PLLDSI_LOCKP_LOCKED)
+                       break;
+               udelay(100);
+       }
+       /* Set DSIPLL_RESETN */
+       writel(PRCMU_RESET_DSIPLL, (_PRCMU_BASE + PRCM_APE_RESETN_SET));
+       return 0;
+}
+
+int prcmu_disable_dsipll(void)
+{
+       /* Disable dsi pll */
+       writel(PRCMU_DISABLE_PLLDSI, (_PRCMU_BASE + PRCM_PLLDSI_ENABLE));
+       /* Disable  escapeclock */
+       writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV,
+                                       (_PRCMU_BASE + PRCM_DSITVCLK_DIV));
+       return 0;
+}
+
+int prcmu_set_display_clocks(void)
+{
+       unsigned long flags;
+       unsigned int dsiclk;
+
+       if (prcmu_is_u8400())
+               dsiclk = PRCMU_DSI_CLOCK_SETTING_U8400;
+       else
+               dsiclk = PRCMU_DSI_CLOCK_SETTING;
+
+       spin_lock_irqsave(&clk_mgt_lock, flags);
+
+       /* Grab the HW semaphore. */
+       while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+               cpu_relax();
+
+       writel(dsiclk, (_PRCMU_BASE + PRCM_HDMICLK_MGT));
+       writel(PRCMU_DSI_LP_CLOCK_SETTING, (_PRCMU_BASE + PRCM_TVCLK_MGT));
+       writel(PRCMU_DPI_CLOCK_SETTING, (_PRCMU_BASE + PRCM_LCDCLK_MGT));
+
+       /* Release the HW semaphore. */
+       writel(0, (_PRCMU_BASE + PRCM_SEM));
+
+       spin_unlock_irqrestore(&clk_mgt_lock, flags);
+
+       return 0;
+}
+
+/**
+ * prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1.
+ */
+void prcmu_enable_spi2(void)
+{
+       u32 reg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpiocr_lock, flags);
+       reg = readl(_PRCMU_BASE + PRCM_GPIOCR);
+       writel(reg | PRCM_GPIOCR_SPI2_SELECT, _PRCMU_BASE + PRCM_GPIOCR);
+       spin_unlock_irqrestore(&gpiocr_lock, flags);
+}
+
+/**
+ * prcmu_disable_spi2 - Disables pin muxing for SPI2 on OtherAlternateC1.
+ */
+void prcmu_disable_spi2(void)
+{
+       u32 reg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpiocr_lock, flags);
+       reg = readl(_PRCMU_BASE + PRCM_GPIOCR);
+       writel(reg & ~PRCM_GPIOCR_SPI2_SELECT, _PRCMU_BASE + PRCM_GPIOCR);
+       spin_unlock_irqrestore(&gpiocr_lock, flags);
+}
+
+bool prcmu_has_arm_maxopp(void)
+{
+       return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) &
+               PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK;
+}
+
+bool prcmu_is_u8400(void)
+{
+       return prcmu_version.project_number == PRCMU_PROJECT_ID_8400V2_0;
+}
+
+/**
+ * prcmu_get_boot_status - PRCMU boot status checking
+ * Returns: the current PRCMU boot status
+ */
+int prcmu_get_boot_status(void)
+{
+       return readb(tcdm_base + PRCM_BOOT_STATUS);
+}
+
+/**
+ * prcmu_set_rc_a2p - This function is used to run few power state sequences
+ * @val: Value to be set, i.e. transition requested
+ * Returns: 0 on success, -EINVAL on invalid argument
+ *
+ * This function is used to run the following power state sequences -
+ * any state to ApReset,  ApDeepSleep to ApExecute, ApExecute to ApDeepSleep
+ */
+int prcmu_set_rc_a2p(enum romcode_write val)
+{
+       if (val < RDY_2_DS || val > RDY_2_XP70_RST)
+               return -EINVAL;
+       writeb(val, (tcdm_base + PRCM_ROMCODE_A2P));
+       return 0;
+}
+
+/**
+ * prcmu_get_rc_p2a - This function is used to get power state sequences
+ * Returns: the power transition that has last happened
+ *
+ * This function can return the following transitions-
+ * any state to ApReset,  ApDeepSleep to ApExecute, ApExecute to ApDeepSleep
+ */
+enum romcode_read prcmu_get_rc_p2a(void)
+{
+       return readb(tcdm_base + PRCM_ROMCODE_P2A);
+}
+
+/**
+ * prcmu_get_current_mode - Return the current XP70 power mode
+ * Returns: Returns the current AP(ARM) power mode: init,
+ * apBoot, apExecute, apDeepSleep, apSleep, apIdle, apReset
+ */
+enum ap_pwrst prcmu_get_xp70_current_state(void)
+{
+       return readb(tcdm_base + PRCM_XP70_CUR_PWR_STATE);
+}
+
+/**
+ * prcmu_config_clkout - Configure one of the programmable clock outputs.
+ * @clkout:    The CLKOUT number (0 or 1).
+ * @source:    The clock to be used (one of the PRCMU_CLKSRC_*).
+ * @div:       The divider to be applied.
+ *
+ * Configures one of the programmable clock outputs (CLKOUTs).
+ * @div should be in the range [1,63] to request a configuration, or 0 to
+ * inform that the configuration is no longer requested.
+ */
+int prcmu_config_clkout(u8 clkout, u8 source, u8 div)
+{
+       static int requests[2];
+       int r = 0;
+       unsigned long flags;
+       u32 val;
+       u32 bits;
+       u32 mask;
+       u32 div_mask;
+
+       BUG_ON(clkout > 1);
+       BUG_ON(div > 63);
+       BUG_ON((clkout == 0) && (source > PRCMU_CLKSRC_CLK009));
+
+       if (!div && !requests[clkout])
+               return -EINVAL;
+
+       switch (clkout) {
+       case 0:
+               div_mask = PRCM_CLKOCR_CLKODIV0_MASK;
+               mask = (PRCM_CLKOCR_CLKODIV0_MASK | PRCM_CLKOCR_CLKOSEL0_MASK);
+               bits = ((source << PRCM_CLKOCR_CLKOSEL0_SHIFT) |
+                       (div << PRCM_CLKOCR_CLKODIV0_SHIFT));
+               break;
+       case 1:
+               div_mask = PRCM_CLKOCR_CLKODIV1_MASK;
+               mask = (PRCM_CLKOCR_CLKODIV1_MASK | PRCM_CLKOCR_CLKOSEL1_MASK |
+                       PRCM_CLKOCR_CLK1TYPE);
+               bits = ((source << PRCM_CLKOCR_CLKOSEL1_SHIFT) |
+                       (div << PRCM_CLKOCR_CLKODIV1_SHIFT));
+               break;
+       }
+       bits &= mask;
+
+       spin_lock_irqsave(&clkout_lock, flags);
+
+       val = readl(_PRCMU_BASE + PRCM_CLKOCR);
+       if (val & div_mask) {
+               if (div) {
+                       if ((val & mask) != bits) {
+                               r = -EBUSY;
+                               goto unlock_and_return;
+                       }
+               } else {
+                       if ((val & mask & ~div_mask) != bits) {
+                               r = -EINVAL;
+                               goto unlock_and_return;
+                       }
+               }
+       }
+       writel((bits | (val & ~mask)), (_PRCMU_BASE + PRCM_CLKOCR));
+       requests[clkout] += (div ? 1 : -1);
+
+unlock_and_return:
+       spin_unlock_irqrestore(&clkout_lock, flags);
+
+       return r;
+}
+
+int prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll)
+{
+       unsigned long flags;
+
+       BUG_ON((state < PRCMU_AP_SLEEP) || (PRCMU_AP_DEEP_IDLE < state));
+
+       spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
+               cpu_relax();
+
+       writeb(MB0H_POWER_STATE_TRANS, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0));
+       writeb(state, (tcdm_base + PRCM_REQ_MB0_AP_POWER_STATE));
+       writeb((keep_ap_pll ? 1 : 0), (tcdm_base + PRCM_REQ_MB0_AP_PLL_STATE));
+       writeb((keep_ulp_clk ? 1 : 0),
+               (tcdm_base + PRCM_REQ_MB0_ULP_CLOCK_STATE));
+       writeb(0, (tcdm_base + PRCM_REQ_MB0_DO_NOT_WFI));
+       writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+       spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+
+       return 0;
+}
+
+/* This function should only be called while mb0_transfer.lock is held. */
+static void config_wakeups(void)
+{
+       const u8 header[2] = {
+               MB0H_CONFIG_WAKEUPS_EXE,
+               MB0H_CONFIG_WAKEUPS_SLEEP
+       };
+       static u32 last_dbb_events;
+       static u32 last_abb_events;
+       u32 dbb_events;
+       u32 abb_events;
+       unsigned int i;
+
+       dbb_events = mb0_transfer.req.dbb_irqs | mb0_transfer.req.dbb_wakeups;
+       dbb_events |= (WAKEUP_BIT_AC_WAKE_ACK | WAKEUP_BIT_AC_SLEEP_ACK);
+
+       abb_events = mb0_transfer.req.abb_events;
+
+       if ((dbb_events == last_dbb_events) && (abb_events == last_abb_events))
+               return;
+
+       for (i = 0; i < 2; i++) {
+               while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
+                       cpu_relax();
+               writel(dbb_events, (tcdm_base + PRCM_REQ_MB0_WAKEUP_8500));
+               writel(abb_events, (tcdm_base + PRCM_REQ_MB0_WAKEUP_4500));
+               writeb(header[i], (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0));
+               writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       }
+       last_dbb_events = dbb_events;
+       last_abb_events = abb_events;
+}
+
+void prcmu_enable_wakeups(u32 wakeups)
+{
+       unsigned long flags;
+       u32 bits;
+       int i;
+
+       BUG_ON(wakeups != (wakeups & VALID_WAKEUPS));
+
+       for (i = 0, bits = 0; i < NUM_PRCMU_WAKEUP_INDICES; i++) {
+               if (wakeups & BIT(i))
+                       bits |= prcmu_wakeup_bit[i];
+       }
+
+       spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+       mb0_transfer.req.dbb_wakeups = bits;
+       config_wakeups();
+
+       spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+void prcmu_config_abb_event_readout(u32 abb_events)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+       mb0_transfer.req.abb_events = abb_events;
+       config_wakeups();
+
+       spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+void prcmu_get_abb_event_buffer(void __iomem **buf)
+{
+       if (readb(tcdm_base + PRCM_ACK_MB0_READ_POINTER) & 1)
+               *buf = (tcdm_base + PRCM_ACK_MB0_WAKEUP_1_4500);
+       else
+               *buf = (tcdm_base + PRCM_ACK_MB0_WAKEUP_0_4500);
+}
+
+/**
+ * prcmu_set_arm_opp - set the appropriate ARM OPP
+ * @opp: The new ARM operating point to which transition is to be made
+ * Returns: 0 on success, non-zero on failure
+ *
+ * This function sets the the operating point of the ARM.
+ */
+int prcmu_set_arm_opp(u8 opp)
+{
+       int r;
+
+       if (opp < ARM_NO_CHANGE || opp > ARM_EXTCLK)
+               return -EINVAL;
+
+       r = 0;
+
+       mutex_lock(&mb1_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
+               cpu_relax();
+
+       writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
+       writeb(opp, (tcdm_base + PRCM_REQ_MB1_ARM_OPP));
+       writeb(APE_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_APE_OPP));
+
+       writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb1_transfer.work);
+
+       if ((mb1_transfer.ack.header != MB1H_ARM_APE_OPP) ||
+               (mb1_transfer.ack.arm_opp != opp))
+               r = -EIO;
+
+       mutex_unlock(&mb1_transfer.lock);
+
+       return r;
+}
+
+/**
+ * prcmu_get_arm_opp - get the current ARM OPP
+ *
+ * Returns: the current ARM OPP
+ */
+int prcmu_get_arm_opp(void)
+{
+       return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_ARM_OPP);
+}
+
+/**
+ * prcmu_get_ddr_opp - get the current DDR OPP
+ *
+ * Returns: the current DDR OPP
+ */
+int prcmu_get_ddr_opp(void)
+{
+       return readb(_PRCMU_BASE + PRCM_DDR_SUBSYS_APE_MINBW);
+}
+
+/**
+ * set_ddr_opp - set the appropriate DDR OPP
+ * @opp: The new DDR operating point to which transition is to be made
+ * Returns: 0 on success, non-zero on failure
+ *
+ * This function sets the operating point of the DDR.
+ */
+int prcmu_set_ddr_opp(u8 opp)
+{
+       if (opp < DDR_100_OPP || opp > DDR_25_OPP)
+               return -EINVAL;
+       /* Changing the DDR OPP can hang the hardware pre-v21 */
+       if (cpu_is_u8500v20_or_later() && !cpu_is_u8500v20())
+               writeb(opp, (_PRCMU_BASE + PRCM_DDR_SUBSYS_APE_MINBW));
+
+       return 0;
+}
+/**
+ * set_ape_opp - set the appropriate APE OPP
+ * @opp: The new APE operating point to which transition is to be made
+ * Returns: 0 on success, non-zero on failure
+ *
+ * This function sets the operating point of the APE.
+ */
+int prcmu_set_ape_opp(u8 opp)
+{
+       int r = 0;
+
+       mutex_lock(&mb1_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
+               cpu_relax();
+
+       writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
+       writeb(ARM_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_ARM_OPP));
+       writeb(opp, (tcdm_base + PRCM_REQ_MB1_APE_OPP));
+
+       writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb1_transfer.work);
+
+       if ((mb1_transfer.ack.header != MB1H_ARM_APE_OPP) ||
+               (mb1_transfer.ack.ape_opp != opp))
+               r = -EIO;
+
+       mutex_unlock(&mb1_transfer.lock);
+
+       return r;
+}
+
+/**
+ * prcmu_get_ape_opp - get the current APE OPP
+ *
+ * Returns: the current APE OPP
+ */
+int prcmu_get_ape_opp(void)
+{
+       return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_APE_OPP);
+}
+
+/**
+ * prcmu_request_ape_opp_100_voltage - Request APE OPP 100% voltage
+ * @enable: true to request the higher voltage, false to drop a request.
+ *
+ * Calls to this function to enable and disable requests must be balanced.
+ */
+int prcmu_request_ape_opp_100_voltage(bool enable)
+{
+       int r = 0;
+       u8 header;
+       static unsigned int requests;
+
+       mutex_lock(&mb1_transfer.lock);
+
+       if (enable) {
+               if (0 != requests++)
+                       goto unlock_and_return;
+               header = MB1H_REQUEST_APE_OPP_100_VOLT;
+       } else {
+               if (requests == 0) {
+                       r = -EIO;
+                       goto unlock_and_return;
+               } else if (1 != requests--) {
+                       goto unlock_and_return;
+               }
+               header = MB1H_RELEASE_APE_OPP_100_VOLT;
+       }
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
+               cpu_relax();
+
+       writeb(header, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
+
+       writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb1_transfer.work);
+
+       if ((mb1_transfer.ack.header != header) ||
+               ((mb1_transfer.ack.ape_voltage_status & BIT(0)) != 0))
+               r = -EIO;
+
+unlock_and_return:
+       mutex_unlock(&mb1_transfer.lock);
+
+       return r;
+}
+
+/**
+ * prcmu_release_usb_wakeup_state - release the state required by a USB wakeup
+ *
+ * This function releases the power state requirements of a USB wakeup.
+ */
+int prcmu_release_usb_wakeup_state(void)
+{
+       int r = 0;
+
+       mutex_lock(&mb1_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
+               cpu_relax();
+
+       writeb(MB1H_RELEASE_USB_WAKEUP,
+               (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
+
+       writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb1_transfer.work);
+
+       if ((mb1_transfer.ack.header != MB1H_RELEASE_USB_WAKEUP) ||
+               ((mb1_transfer.ack.ape_voltage_status & BIT(0)) != 0))
+               r = -EIO;
+
+       mutex_unlock(&mb1_transfer.lock);
+
+       return r;
+}
+
+/**
+ * prcmu_set_epod - set the state of a EPOD (power domain)
+ * @epod_id: The EPOD to set
+ * @epod_state: The new EPOD state
+ *
+ * This function sets the state of a EPOD (power domain). It may not be called
+ * from interrupt context.
+ */
+int prcmu_set_epod(u16 epod_id, u8 epod_state)
+{
+       int r = 0;
+       bool ram_retention = false;
+       int i;
+
+       /* check argument */
+       BUG_ON(epod_id >= NUM_EPOD_ID);
+
+       /* set flag if retention is possible */
+       switch (epod_id) {
+       case EPOD_ID_SVAMMDSP:
+       case EPOD_ID_SIAMMDSP:
+       case EPOD_ID_ESRAM12:
+       case EPOD_ID_ESRAM34:
+               ram_retention = true;
+               break;
+       }
+
+       /* check argument */
+       BUG_ON(epod_state > EPOD_STATE_ON);
+       BUG_ON(epod_state == EPOD_STATE_RAMRET && !ram_retention);
+
+       /* get lock */
+       mutex_lock(&mb2_transfer.lock);
+
+       /* wait for mailbox */
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(2))
+               cpu_relax();
+
+       /* fill in mailbox */
+       for (i = 0; i < NUM_EPOD_ID; i++)
+               writeb(EPOD_STATE_NO_CHANGE, (tcdm_base + PRCM_REQ_MB2 + i));
+       writeb(epod_state, (tcdm_base + PRCM_REQ_MB2 + epod_id));
+
+       writeb(MB2H_DPS, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB2));
+
+       writel(MBOX_BIT(2), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+       /*
+        * The current firmware version does not handle errors correctly,
+        * and we cannot recover if there is an error.
+        * This is expected to change when the firmware is updated.
+        */
+       if (!wait_for_completion_timeout(&mb2_transfer.work,
+                       msecs_to_jiffies(20000))) {
+               pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+                       __func__);
+               r = -EIO;
+               goto unlock_and_return;
+       }
+
+       if (mb2_transfer.ack.status != HWACC_PWR_ST_OK)
+               r = -EIO;
+
+unlock_and_return:
+       mutex_unlock(&mb2_transfer.lock);
+       return r;
+}
+
+/**
+ * prcmu_configure_auto_pm - Configure autonomous power management.
+ * @sleep: Configuration for ApSleep.
+ * @idle:  Configuration for ApIdle.
+ */
+void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
+       struct prcmu_auto_pm_config *idle)
+{
+       u32 sleep_cfg;
+       u32 idle_cfg;
+       unsigned long flags;
+
+       BUG_ON((sleep == NULL) || (idle == NULL));
+
+       sleep_cfg = (sleep->sva_auto_pm_enable & 0xF);
+       sleep_cfg = ((sleep_cfg << 4) | (sleep->sia_auto_pm_enable & 0xF));
+       sleep_cfg = ((sleep_cfg << 8) | (sleep->sva_power_on & 0xFF));
+       sleep_cfg = ((sleep_cfg << 8) | (sleep->sia_power_on & 0xFF));
+       sleep_cfg = ((sleep_cfg << 4) | (sleep->sva_policy & 0xF));
+       sleep_cfg = ((sleep_cfg << 4) | (sleep->sia_policy & 0xF));
+
+       idle_cfg = (idle->sva_auto_pm_enable & 0xF);
+       idle_cfg = ((idle_cfg << 4) | (idle->sia_auto_pm_enable & 0xF));
+       idle_cfg = ((idle_cfg << 8) | (idle->sva_power_on & 0xFF));
+       idle_cfg = ((idle_cfg << 8) | (idle->sia_power_on & 0xFF));
+       idle_cfg = ((idle_cfg << 4) | (idle->sva_policy & 0xF));
+       idle_cfg = ((idle_cfg << 4) | (idle->sia_policy & 0xF));
+
+       spin_lock_irqsave(&mb2_transfer.auto_pm_lock, flags);
+
+       /*
+        * The autonomous power management configuration is done through
+        * fields in mailbox 2, but these fields are only used as shared
+        * variables - i.e. there is no need to send a message.
+        */
+       writel(sleep_cfg, (tcdm_base + PRCM_REQ_MB2_AUTO_PM_SLEEP));
+       writel(idle_cfg, (tcdm_base + PRCM_REQ_MB2_AUTO_PM_IDLE));
+
+       mb2_transfer.auto_pm_enabled =
+               ((sleep->sva_auto_pm_enable == PRCMU_AUTO_PM_ON) ||
+                (sleep->sia_auto_pm_enable == PRCMU_AUTO_PM_ON) ||
+                (idle->sva_auto_pm_enable == PRCMU_AUTO_PM_ON) ||
+                (idle->sia_auto_pm_enable == PRCMU_AUTO_PM_ON));
+
+       spin_unlock_irqrestore(&mb2_transfer.auto_pm_lock, flags);
+}
+EXPORT_SYMBOL(prcmu_configure_auto_pm);
+
+bool prcmu_is_auto_pm_enabled(void)
+{
+       return mb2_transfer.auto_pm_enabled;
+}
+
+static int request_sysclk(bool enable)
+{
+       int r;
+       unsigned long flags;
+
+       r = 0;
+
+       mutex_lock(&mb3_transfer.sysclk_lock);
+
+       spin_lock_irqsave(&mb3_transfer.lock, flags);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(3))
+               cpu_relax();
+
+       writeb((enable ? ON : OFF), (tcdm_base + PRCM_REQ_MB3_SYSCLK_MGT));
+
+       writeb(MB3H_SYSCLK, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB3));
+       writel(MBOX_BIT(3), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+       spin_unlock_irqrestore(&mb3_transfer.lock, flags);
+
+       /*
+        * The firmware only sends an ACK if we want to enable the
+        * SysClk, and it succeeds.
+        */
+       if (enable && !wait_for_completion_timeout(&mb3_transfer.sysclk_work,
+                       msecs_to_jiffies(20000))) {
+               pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+                       __func__);
+               r = -EIO;
+       }
+
+       mutex_unlock(&mb3_transfer.sysclk_lock);
+
+       return r;
+}
+
+static int request_timclk(bool enable)
+{
+       u32 val = (PRCM_TCR_DOZE_MODE | PRCM_TCR_TENSEL_MASK);
+
+       if (!enable)
+               val |= PRCM_TCR_STOP_TIMERS;
+       writel(val, (_PRCMU_BASE + PRCM_TCR));
+
+       return 0;
+}
+
+static int request_reg_clock(u8 clock, bool enable)
+{
+       u32 val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&clk_mgt_lock, flags);
+
+       /* Grab the HW semaphore. */
+       while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+               cpu_relax();
+
+       val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
+       if (enable) {
+               val |= (PRCM_CLK_MGT_CLKEN | clk_mgt[clock].pllsw);
+       } else {
+               clk_mgt[clock].pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
+               val &= ~(PRCM_CLK_MGT_CLKEN | PRCM_CLK_MGT_CLKPLLSW_MASK);
+       }
+       writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
+
+       /* Release the HW semaphore. */
+       writel(0, (_PRCMU_BASE + PRCM_SEM));
+
+       spin_unlock_irqrestore(&clk_mgt_lock, flags);
+
+       return 0;
+}
+
+/**
+ * prcmu_request_clock() - Request for a clock to be enabled or disabled.
+ * @clock:      The clock for which the request is made.
+ * @enable:     Whether the clock should be enabled (true) or disabled (false).
+ *
+ * This function should only be used by the clock implementation.
+ * Do not use it from any other place!
+ */
+int prcmu_request_clock(u8 clock, bool enable)
+{
+       if (clock < PRCMU_NUM_REG_CLOCKS)
+               return request_reg_clock(clock, enable);
+       else if (clock == PRCMU_TIMCLK)
+               return request_timclk(enable);
+       else if (clock == PRCMU_SYSCLK)
+               return request_sysclk(enable);
+       else
+               return -EINVAL;
+}
+
+int prcmu_config_esram0_deep_sleep(u8 state)
+{
+       if ((state > ESRAM0_DEEP_SLEEP_STATE_RET) ||
+           (state < ESRAM0_DEEP_SLEEP_STATE_OFF))
+               return -EINVAL;
+
+       mutex_lock(&mb4_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
+               cpu_relax();
+
+       writeb(MB4H_MEM_ST, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4));
+       writeb(((DDR_PWR_STATE_OFFHIGHLAT << 4) | DDR_PWR_STATE_ON),
+              (tcdm_base + PRCM_REQ_MB4_DDR_ST_AP_SLEEP_IDLE));
+       writeb(DDR_PWR_STATE_ON,
+              (tcdm_base + PRCM_REQ_MB4_DDR_ST_AP_DEEP_IDLE));
+       writeb(state, (tcdm_base + PRCM_REQ_MB4_ESRAM0_ST));
+
+       writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb4_transfer.work);
+
+       mutex_unlock(&mb4_transfer.lock);
+
+       return 0;
+}
+
+int prcmu_config_hotdog(u8 threshold)
+{
+       mutex_lock(&mb4_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
+               cpu_relax();
+
+       writeb(threshold, (tcdm_base + PRCM_REQ_MB4_HOTDOG_THRESHOLD));
+       writeb(MB4H_HOTDOG, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4));
+
+       writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb4_transfer.work);
+
+       mutex_unlock(&mb4_transfer.lock);
+
+       return 0;
+}
+
+int prcmu_config_hotmon(u8 low, u8 high)
+{
+       mutex_lock(&mb4_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
+               cpu_relax();
+
+       writeb(low, (tcdm_base + PRCM_REQ_MB4_HOTMON_LOW));
+       writeb(high, (tcdm_base + PRCM_REQ_MB4_HOTMON_HIGH));
+       writeb((HOTMON_CONFIG_LOW | HOTMON_CONFIG_HIGH),
+               (tcdm_base + PRCM_REQ_MB4_HOTMON_CONFIG));
+       writeb(MB4H_HOTMON, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4));
+
+       writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb4_transfer.work);
+
+       mutex_unlock(&mb4_transfer.lock);
+
+       return 0;
+}
+
+static int config_hot_period(u16 val)
+{
+       mutex_lock(&mb4_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
+               cpu_relax();
+
+       writew(val, (tcdm_base + PRCM_REQ_MB4_HOT_PERIOD));
+       writeb(MB4H_HOT_PERIOD, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4));
+
+       writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb4_transfer.work);
+
+       mutex_unlock(&mb4_transfer.lock);
+
+       return 0;
+}
+
+int prcmu_start_temp_sense(u16 cycles32k)
+{
+       if (cycles32k == 0xFFFF)
+               return -EINVAL;
+
+       return config_hot_period(cycles32k);
+}
+
+int prcmu_stop_temp_sense(void)
+{
+       return config_hot_period(0xFFFF);
+}
+
+/**
+ * prcmu_set_clock_divider() - Configure the clock divider.
+ * @clock:     The clock for which the request is made.
+ * @divider:   The clock divider. (< 32)
+ *
+ * This function should only be used by the clock implementation.
+ * Do not use it from any other place!
+ */
+int prcmu_set_clock_divider(u8 clock, u8 divider)
+{
+       u32 val;
+       unsigned long flags;
+
+       if ((clock >= PRCMU_NUM_REG_CLOCKS) || (divider < 1) || (31 < divider))
+               return -EINVAL;
+
+       spin_lock_irqsave(&clk_mgt_lock, flags);
+
+       /* Grab the HW semaphore. */
+       while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+               cpu_relax();
+
+       val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
+       val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK);
+       val |= (u32)divider;
+       writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
+
+       /* Release the HW semaphore. */
+       writel(0, (_PRCMU_BASE + PRCM_SEM));
+
+       spin_unlock_irqrestore(&clk_mgt_lock, flags);
+
+       return 0;
+}
+
+/**
+ * prcmu_abb_read() - Read register value(s) from the ABB.
+ * @slave:     The I2C slave address.
+ * @reg:       The (start) register address.
+ * @value:     The read out value(s).
+ * @size:      The number of registers to read.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       int r;
+
+       if (size != 1)
+               return -EINVAL;
+
+       mutex_lock(&mb5_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+               cpu_relax();
+
+       writeb(PRCMU_I2C_READ(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
+       writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
+       writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
+       writeb(0, (tcdm_base + PRCM_REQ_MB5_I2C_VAL));
+
+       writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+       if (!wait_for_completion_timeout(&mb5_transfer.work,
+                               msecs_to_jiffies(20000))) {
+               pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+                       __func__);
+               r = -EIO;
+       } else {
+               r = ((mb5_transfer.ack.status == I2C_RD_OK) ? 0 : -EIO);
+       }
+
+       if (!r)
+               *value = mb5_transfer.ack.value;
+
+       mutex_unlock(&mb5_transfer.lock);
+
+       return r;
+}
+
+/**
+ * prcmu_abb_write() - Write register value(s) to the ABB.
+ * @slave:     The I2C slave address.
+ * @reg:       The (start) register address.
+ * @value:     The value(s) to write.
+ * @size:      The number of registers to write.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       int r;
+
+       if (size != 1)
+               return -EINVAL;
+
+       mutex_lock(&mb5_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+               cpu_relax();
+
+       writeb(PRCMU_I2C_WRITE(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
+       writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
+       writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
+       writeb(*value, (tcdm_base + PRCM_REQ_MB5_I2C_VAL));
+
+       writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+       if (!wait_for_completion_timeout(&mb5_transfer.work,
+                               msecs_to_jiffies(20000))) {
+               pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+                       __func__);
+               r = -EIO;
+       } else {
+               r = ((mb5_transfer.ack.status == I2C_WR_OK) ? 0 : -EIO);
+       }
+
+       mutex_unlock(&mb5_transfer.lock);
+
+       return r;
+}
+
+/**
+ * prcmu_ac_wake_req - should be called whenever ARM wants to wakeup Modem
+ */
+void prcmu_ac_wake_req(void)
+{
+       u32 val;
+
+       mutex_lock(&mb0_transfer.ac_wake_lock);
+
+       val = readl(_PRCMU_BASE + PRCM_HOSTACCESS_REQ);
+       if (val & PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ)
+               goto unlock_and_return;
+
+       atomic_set(&ac_wake_req_state, 1);
+
+       writel((val | PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ),
+               (_PRCMU_BASE + PRCM_HOSTACCESS_REQ));
+
+       if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work,
+                       msecs_to_jiffies(20000))) {
+               pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+                       __func__);
+       }
+
+unlock_and_return:
+       mutex_unlock(&mb0_transfer.ac_wake_lock);
+}
+
+/**
+ * prcmu_ac_sleep_req - called when ARM no longer needs to talk to modem
+ */
+void prcmu_ac_sleep_req()
+{
+       u32 val;
+
+       mutex_lock(&mb0_transfer.ac_wake_lock);
+
+       val = readl(_PRCMU_BASE + PRCM_HOSTACCESS_REQ);
+       if (!(val & PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ))
+               goto unlock_and_return;
+
+       writel((val & ~PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ),
+               (_PRCMU_BASE + PRCM_HOSTACCESS_REQ));
+
+       if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work,
+                       msecs_to_jiffies(20000))) {
+               pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+                       __func__);
+       }
+
+       atomic_set(&ac_wake_req_state, 0);
+
+unlock_and_return:
+       mutex_unlock(&mb0_transfer.ac_wake_lock);
+}
+
+bool prcmu_is_ac_wake_requested(void)
+{
+       return (atomic_read(&ac_wake_req_state) != 0);
+}
+
+/**
+ * prcmu_system_reset - System reset
+ *
+ * Saves the reset reason code and then sets the APE_SOFRST register which
+ * fires interrupt to fw
+ */
+void prcmu_system_reset(u16 reset_code)
+{
+       writew(reset_code, (tcdm_base + PRCM_SW_RST_REASON));
+       writel(1, (_PRCMU_BASE + PRCM_APE_SOFTRST));
+}
+
+/**
+ * prcmu_reset_modem - ask the PRCMU to reset modem
+ */
+void prcmu_modem_reset(void)
+{
+       mutex_lock(&mb1_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
+               cpu_relax();
+
+       writeb(MB1H_RESET_MODEM, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
+       writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb1_transfer.work);
+
+       /*
+        * No need to check return from PRCMU as modem should go in reset state
+        * This state is already managed by upper layer
+        */
+
+       mutex_unlock(&mb1_transfer.lock);
+}
+
+static void ack_dbb_wakeup(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
+               cpu_relax();
+
+       writeb(MB0H_READ_WAKEUP_ACK, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0));
+       writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+       spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+static inline void print_unknown_header_warning(u8 n, u8 header)
+{
+       pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n",
+               header, n);
+}
+
+static bool read_mailbox_0(void)
+{
+       bool r;
+       u32 ev;
+       unsigned int n;
+       u8 header;
+
+       header = readb(tcdm_base + PRCM_MBOX_HEADER_ACK_MB0);
+       switch (header) {
+       case MB0H_WAKEUP_EXE:
+       case MB0H_WAKEUP_SLEEP:
+               if (readb(tcdm_base + PRCM_ACK_MB0_READ_POINTER) & 1)
+                       ev = readl(tcdm_base + PRCM_ACK_MB0_WAKEUP_1_8500);
+               else
+                       ev = readl(tcdm_base + PRCM_ACK_MB0_WAKEUP_0_8500);
+
+               if (ev & (WAKEUP_BIT_AC_WAKE_ACK | WAKEUP_BIT_AC_SLEEP_ACK))
+                       complete(&mb0_transfer.ac_wake_work);
+               if (ev & WAKEUP_BIT_SYSCLK_OK)
+                       complete(&mb3_transfer.sysclk_work);
+
+               ev &= mb0_transfer.req.dbb_irqs;
+
+               for (n = 0; n < NUM_PRCMU_WAKEUPS; n++) {
+                       if (ev & prcmu_irq_bit[n])
+                               generic_handle_irq(IRQ_PRCMU_BASE + n);
+               }
+               r = true;
+               break;
+       default:
+               print_unknown_header_warning(0, header);
+               r = false;
+               break;
+       }
+       writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+       return r;
+}
+
+static bool read_mailbox_1(void)
+{
+       mb1_transfer.ack.header = readb(tcdm_base + PRCM_MBOX_HEADER_REQ_MB1);
+       mb1_transfer.ack.arm_opp = readb(tcdm_base +
+               PRCM_ACK_MB1_CURRENT_ARM_OPP);
+       mb1_transfer.ack.ape_opp = readb(tcdm_base +
+               PRCM_ACK_MB1_CURRENT_APE_OPP);
+       mb1_transfer.ack.ape_voltage_status = readb(tcdm_base +
+               PRCM_ACK_MB1_APE_VOLTAGE_STATUS);
+       writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+       complete(&mb1_transfer.work);
+       return false;
+}
+
+static bool read_mailbox_2(void)
+{
+       mb2_transfer.ack.status = readb(tcdm_base + PRCM_ACK_MB2_DPS_STATUS);
+       writel(MBOX_BIT(2), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+       complete(&mb2_transfer.work);
+       return false;
+}
+
+static bool read_mailbox_3(void)
+{
+       writel(MBOX_BIT(3), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+       return false;
+}
+
+static bool read_mailbox_4(void)
+{
+       u8 header;
+       bool do_complete = true;
+
+       header = readb(tcdm_base + PRCM_MBOX_HEADER_REQ_MB4);
+       switch (header) {
+       case MB4H_MEM_ST:
+       case MB4H_HOTDOG:
+       case MB4H_HOTMON:
+       case MB4H_HOT_PERIOD:
+               break;
+       default:
+               print_unknown_header_warning(4, header);
+               do_complete = false;
+               break;
+       }
+
+       writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+
+       if (do_complete)
+               complete(&mb4_transfer.work);
+
+       return false;
+}
+
+static bool read_mailbox_5(void)
+{
+       mb5_transfer.ack.status = readb(tcdm_base + PRCM_ACK_MB5_I2C_STATUS);
+       mb5_transfer.ack.value = readb(tcdm_base + PRCM_ACK_MB5_I2C_VAL);
+       writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+       complete(&mb5_transfer.work);
+       return false;
+}
+
+static bool read_mailbox_6(void)
+{
+       writel(MBOX_BIT(6), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+       return false;
+}
+
+static bool read_mailbox_7(void)
+{
+       writel(MBOX_BIT(7), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+       return false;
+}
+
+static bool (* const read_mailbox[NUM_MB])(void) = {
+       read_mailbox_0,
+       read_mailbox_1,
+       read_mailbox_2,
+       read_mailbox_3,
+       read_mailbox_4,
+       read_mailbox_5,
+       read_mailbox_6,
+       read_mailbox_7
+};
+
+static irqreturn_t prcmu_irq_handler(int irq, void *data)
+{
+       u32 bits;
+       u8 n;
+       irqreturn_t r;
+
+       bits = (readl(_PRCMU_BASE + PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS);
+       if (unlikely(!bits))
+               return IRQ_NONE;
+
+       r = IRQ_HANDLED;
+       for (n = 0; bits; n++) {
+               if (bits & MBOX_BIT(n)) {
+                       bits -= MBOX_BIT(n);
+                       if (read_mailbox[n]())
+                               r = IRQ_WAKE_THREAD;
+               }
+       }
+       return r;
+}
+
+static irqreturn_t prcmu_irq_thread_fn(int irq, void *data)
+{
+       ack_dbb_wakeup();
+       return IRQ_HANDLED;
+}
+
+static void prcmu_mask_work(struct work_struct *work)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+       config_wakeups();
+
+       spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+static void prcmu_irq_mask(struct irq_data *d)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags);
+
+       mb0_transfer.req.dbb_irqs &= ~prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE];
+
+       spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags);
+
+       if (d->irq != IRQ_PRCMU_CA_SLEEP)
+               schedule_work(&mb0_transfer.mask_work);
+}
+
+static void prcmu_irq_unmask(struct irq_data *d)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags);
+
+       mb0_transfer.req.dbb_irqs |= prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE];
+
+       spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags);
+
+       if (d->irq != IRQ_PRCMU_CA_SLEEP)
+               schedule_work(&mb0_transfer.mask_work);
+}
+
+static void noop(struct irq_data *d)
+{
+}
+
+static struct irq_chip prcmu_irq_chip = {
+       .name           = "prcmu",
+       .irq_disable    = prcmu_irq_mask,
+       .irq_ack        = noop,
+       .irq_mask       = prcmu_irq_mask,
+       .irq_unmask     = prcmu_irq_unmask,
+};
+
+void __init prcmu_early_init(void)
+{
+       unsigned int i;
+
+       if (cpu_is_u8500v1()) {
+               tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE_V1);
+       } else if (cpu_is_u8500v2()) {
+               void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K);
+
+               if (tcpm_base != NULL) {
+                       int version;
+                       version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET);
+                       prcmu_version.project_number = version & 0xFF;
+                       prcmu_version.api_version = (version >> 8) & 0xFF;
+                       prcmu_version.func_version = (version >> 16) & 0xFF;
+                       prcmu_version.errata = (version >> 24) & 0xFF;
+                       pr_info("PRCMU firmware version %d.%d.%d\n",
+                               (version >> 8) & 0xFF, (version >> 16) & 0xFF,
+                               (version >> 24) & 0xFF);
+                       iounmap(tcpm_base);
+               }
+
+               tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE);
+       } else {
+               pr_err("prcmu: Unsupported chip version\n");
+               BUG();
+       }
+
+       spin_lock_init(&mb0_transfer.lock);
+       spin_lock_init(&mb0_transfer.dbb_irqs_lock);
+       mutex_init(&mb0_transfer.ac_wake_lock);
+       init_completion(&mb0_transfer.ac_wake_work);
+       mutex_init(&mb1_transfer.lock);
+       init_completion(&mb1_transfer.work);
+       mutex_init(&mb2_transfer.lock);
+       init_completion(&mb2_transfer.work);
+       spin_lock_init(&mb2_transfer.auto_pm_lock);
+       spin_lock_init(&mb3_transfer.lock);
+       mutex_init(&mb3_transfer.sysclk_lock);
+       init_completion(&mb3_transfer.sysclk_work);
+       mutex_init(&mb4_transfer.lock);
+       init_completion(&mb4_transfer.work);
+       mutex_init(&mb5_transfer.lock);
+       init_completion(&mb5_transfer.work);
+
+       INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work);
+
+       /* Initalize irqs. */
+       for (i = 0; i < NUM_PRCMU_WAKEUPS; i++) {
+               unsigned int irq;
+
+               irq = IRQ_PRCMU_BASE + i;
+               irq_set_chip_and_handler(irq, &prcmu_irq_chip,
+                                        handle_simple_irq);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+}
+
+/*
+ * Power domain switches (ePODs) modeled as regulators for the DB8500 SoC
+ */
+static struct regulator_consumer_supply db8500_vape_consumers[] = {
+       REGULATOR_SUPPLY("v-ape", NULL),
+       REGULATOR_SUPPLY("v-i2c", "nmk-i2c.0"),
+       REGULATOR_SUPPLY("v-i2c", "nmk-i2c.1"),
+       REGULATOR_SUPPLY("v-i2c", "nmk-i2c.2"),
+       REGULATOR_SUPPLY("v-i2c", "nmk-i2c.3"),
+       /* "v-mmc" changed to "vcore" in the mainline kernel */
+       REGULATOR_SUPPLY("vcore", "sdi0"),
+       REGULATOR_SUPPLY("vcore", "sdi1"),
+       REGULATOR_SUPPLY("vcore", "sdi2"),
+       REGULATOR_SUPPLY("vcore", "sdi3"),
+       REGULATOR_SUPPLY("vcore", "sdi4"),
+       REGULATOR_SUPPLY("v-dma", "dma40.0"),
+       REGULATOR_SUPPLY("v-ape", "ab8500-usb.0"),
+       /* "v-uart" changed to "vcore" in the mainline kernel */
+       REGULATOR_SUPPLY("vcore", "uart0"),
+       REGULATOR_SUPPLY("vcore", "uart1"),
+       REGULATOR_SUPPLY("vcore", "uart2"),
+       REGULATOR_SUPPLY("v-ape", "nmk-ske-keypad.0"),
+};
+
+static struct regulator_consumer_supply db8500_vsmps2_consumers[] = {
+       /* CG2900 and CW1200 power to off-chip peripherals */
+       REGULATOR_SUPPLY("gbf_1v8", "cg2900-uart.0"),
+       REGULATOR_SUPPLY("wlan_1v8", "cw1200.0"),
+       REGULATOR_SUPPLY("musb_1v8", "ab8500-usb.0"),
+       /* AV8100 regulator */
+       REGULATOR_SUPPLY("hdmi_1v8", "0-0070"),
+};
+
+static struct regulator_consumer_supply db8500_b2r2_mcde_consumers[] = {
+       REGULATOR_SUPPLY("vsupply", "b2r2.0"),
+       REGULATOR_SUPPLY("vsupply", "mcde.0"),
+};
+
+static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
+       [DB8500_REGULATOR_VAPE] = {
+               .constraints = {
+                       .name = "db8500-vape",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+               .consumer_supplies = db8500_vape_consumers,
+               .num_consumer_supplies = ARRAY_SIZE(db8500_vape_consumers),
+       },
+       [DB8500_REGULATOR_VARM] = {
+               .constraints = {
+                       .name = "db8500-varm",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_VMODEM] = {
+               .constraints = {
+                       .name = "db8500-vmodem",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_VPLL] = {
+               .constraints = {
+                       .name = "db8500-vpll",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_VSMPS1] = {
+               .constraints = {
+                       .name = "db8500-vsmps1",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_VSMPS2] = {
+               .constraints = {
+                       .name = "db8500-vsmps2",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+               .consumer_supplies = db8500_vsmps2_consumers,
+               .num_consumer_supplies = ARRAY_SIZE(db8500_vsmps2_consumers),
+       },
+       [DB8500_REGULATOR_VSMPS3] = {
+               .constraints = {
+                       .name = "db8500-vsmps3",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_VRF1] = {
+               .constraints = {
+                       .name = "db8500-vrf1",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
+               .supply_regulator = "db8500-vape",
+               .constraints = {
+                       .name = "db8500-sva-mmdsp",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_SVAMMDSPRET] = {
+               .constraints = {
+                       /* "ret" means "retention" */
+                       .name = "db8500-sva-mmdsp-ret",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_SVAPIPE] = {
+               .supply_regulator = "db8500-vape",
+               .constraints = {
+                       .name = "db8500-sva-pipe",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
+               .supply_regulator = "db8500-vape",
+               .constraints = {
+                       .name = "db8500-sia-mmdsp",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_SIAMMDSPRET] = {
+               .constraints = {
+                       .name = "db8500-sia-mmdsp-ret",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_SIAPIPE] = {
+               .supply_regulator = "db8500-vape",
+               .constraints = {
+                       .name = "db8500-sia-pipe",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_SGA] = {
+               .supply_regulator = "db8500-vape",
+               .constraints = {
+                       .name = "db8500-sga",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_B2R2_MCDE] = {
+               .supply_regulator = "db8500-vape",
+               .constraints = {
+                       .name = "db8500-b2r2-mcde",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+               .consumer_supplies = db8500_b2r2_mcde_consumers,
+               .num_consumer_supplies = ARRAY_SIZE(db8500_b2r2_mcde_consumers),
+       },
+       [DB8500_REGULATOR_SWITCH_ESRAM12] = {
+               .supply_regulator = "db8500-vape",
+               .constraints = {
+                       .name = "db8500-esram12",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_ESRAM12RET] = {
+               .constraints = {
+                       .name = "db8500-esram12-ret",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_ESRAM34] = {
+               .supply_regulator = "db8500-vape",
+               .constraints = {
+                       .name = "db8500-esram34",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_ESRAM34RET] = {
+               .constraints = {
+                       .name = "db8500-esram34-ret",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+};
+
+static struct mfd_cell db8500_prcmu_devs[] = {
+       {
+               .name = "db8500-prcmu-regulators",
+               .platform_data = &db8500_regulators,
+               .pdata_size = sizeof(db8500_regulators),
+       },
+       {
+               .name = "cpufreq-u8500",
+       },
+};
+
+/**
+ * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic
+ *
+ */
+static int __init db8500_prcmu_probe(struct platform_device *pdev)
+{
+       int err = 0;
+
+       if (ux500_is_svp())
+               return -ENODEV;
+
+       /* Clean up the mailbox interrupts after pre-kernel code. */
+       writel(ALL_MBOX_BITS, (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+
+       err = request_threaded_irq(IRQ_DB8500_PRCMU1, prcmu_irq_handler,
+               prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL);
+       if (err < 0) {
+               pr_err("prcmu: Failed to allocate IRQ_DB8500_PRCMU1.\n");
+               err = -EBUSY;
+               goto no_irq_return;
+       }
+
+       if (cpu_is_u8500v20_or_later())
+               prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
+
+       err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs,
+                             ARRAY_SIZE(db8500_prcmu_devs), NULL,
+                             0);
+
+       if (err)
+               pr_err("prcmu: Failed to add subdevices\n");
+       else
+               pr_info("DB8500 PRCMU initialized\n");
+
+no_irq_return:
+       return err;
+}
+
+static struct platform_driver db8500_prcmu_driver = {
+       .driver = {
+               .name = "db8500-prcmu",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init db8500_prcmu_init(void)
+{
+       return platform_driver_probe(&db8500_prcmu_driver, db8500_prcmu_probe);
+}
+
+arch_initcall(db8500_prcmu_init);
+
+MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com>");
+MODULE_DESCRIPTION("DB8500 PRCM Unit driver");
+MODULE_LICENSE("GPL v2");
index fb9770b39a3253edcc92a83a3e77fb020b72b93f..2808bd125d1352303ee49ed968aca8913dc2d6c8 100644 (file)
@@ -117,7 +117,8 @@ static struct mfd_cell ds1wm_cell __initdata = {
        .name          = "ds1wm",
        .enable        = ds1wm_enable,
        .disable       = ds1wm_disable,
-       .mfd_data      = &ds1wm_pdata,
+       .platform_data = &ds1wm_pdata,
+       .pdata_size    = sizeof(ds1wm_pdata),
        .num_resources = 2,
        .resources     = ds1wm_resources,
 };
@@ -172,6 +173,8 @@ static int __init pasic3_probe(struct platform_device *pdev)
        }
 
        if (pdata && pdata->led_pdata) {
+               led_cell.platform_data = pdata->led_pdata;
+               led_cell.pdata_size = sizeof(struct pasic3_leds_machinfo);
                ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, 0);
                if (ret < 0)
                        dev_warn(dev, "failed to register LED device\n");
index fc4191137e9069f20cfd4c87ac76987e8eec3435..5c2a06acb77fce5d226c183e2197602eff8f434d 100644 (file)
@@ -86,7 +86,8 @@ static int __devinit cmodio_setup_subdevice(struct cmodio_device *priv,
 
        /* Add platform data */
        pdata->modno = modno;
-       cell->mfd_data = pdata;
+       cell->platform_data = pdata;
+       cell->pdata_size = sizeof(*pdata);
 
        /* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */
        res->flags = IORESOURCE_MEM;
index 58cc5fdde01647be4260f4736a55596d5c684242..e1e59c92f7588592e141839f2af5c0c4298d53d5 100644 (file)
@@ -627,7 +627,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip,
                goto out_dev;
        }
 
-       if (pdata && pdata->regulator[0]) {
+       if (pdata) {
                ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
                                      ARRAY_SIZE(regulator_devs),
                                      &regulator_resources[0], 0);
index 668634e89e81e1e616bbdab7562db258de72c8a0..7e4d44bf92ab90b10725ac14310782b1b6143e31 100644 (file)
@@ -683,13 +683,14 @@ out:
 EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion);
 
 static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
-               const char *format, void *pdata)
+               const char *format, void *pdata, size_t pdata_size)
 {
        char buf[30];
        const char *name = mc13xxx_get_chipname(mc13xxx);
 
        struct mfd_cell cell = {
-               .mfd_data = pdata,
+               .platform_data = pdata,
+               .pdata_size = pdata_size,
        };
 
        /* there is no asnprintf in the kernel :-( */
@@ -705,7 +706,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
 
 static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
 {
-       return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL);
+       return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
 }
 
 static int mc13xxx_probe(struct spi_device *spi)
@@ -764,7 +765,7 @@ err_revision:
 
        if (pdata->flags & MC13XXX_USE_REGULATOR) {
                mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
-                               &pdata->regulators);
+                               &pdata->regulators, sizeof(pdata->regulators));
        }
 
        if (pdata->flags & MC13XXX_USE_RTC)
@@ -774,7 +775,8 @@ err_revision:
                mc13xxx_add_subdevice(mc13xxx, "%s-ts");
 
        if (pdata->flags & MC13XXX_USE_LED)
-               mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", pdata->leds);
+               mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
+                               pdata->leds, sizeof(*pdata->leds));
 
        return 0;
 }
index f4c8c844b913060c6e0bb12f35db8cba983a81dc..0902523af62d47e33e139c1feab75e5b0ef2a49c 100644 (file)
@@ -88,6 +88,13 @@ static int mfd_add_device(struct device *parent, int id,
 
        pdev->dev.parent = parent;
 
+       if (cell->pdata_size) {
+               ret = platform_device_add_data(pdev,
+                                       cell->platform_data, cell->pdata_size);
+               if (ret)
+                       goto fail_res;
+       }
+
        ret = mfd_platform_add_cell(pdev, cell);
        if (ret)
                goto fail_res;
index 3ab9ffa00aadf8c805477e2c323c2f1f889da2a8..855219526ccb9ec390afe9e2a74b138b1b415f31 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/spinlock.h>
 #include <linux/gpio.h>
 #include <plat/usb.h>
+#include <linux/pm_runtime.h>
 
 #define USBHS_DRIVER_NAME      "usbhs-omap"
 #define OMAP_EHCI_DEVICE       "ehci-omap"
 
 
 struct usbhs_hcd_omap {
-       struct clk                      *usbhost_ick;
-       struct clk                      *usbhost_hs_fck;
-       struct clk                      *usbhost_fs_fck;
        struct clk                      *xclk60mhsp1_ck;
        struct clk                      *xclk60mhsp2_ck;
        struct clk                      *utmi_p1_fck;
@@ -158,8 +156,6 @@ struct usbhs_hcd_omap {
        struct clk                      *usbhost_p2_fck;
        struct clk                      *usbtll_p2_fck;
        struct clk                      *init_60m_fclk;
-       struct clk                      *usbtll_fck;
-       struct clk                      *usbtll_ick;
 
        void __iomem                    *uhh_base;
        void __iomem                    *tll_base;
@@ -281,6 +277,7 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev)
 
        if (!ehci) {
                dev_err(dev, "omap_usbhs_alloc_child failed\n");
+               ret = -ENOMEM;
                goto err_end;
        }
 
@@ -304,13 +301,14 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev)
                sizeof(*ohci_data), dev);
        if (!ohci) {
                dev_err(dev, "omap_usbhs_alloc_child failed\n");
+               ret = -ENOMEM;
                goto err_ehci;
        }
 
        return 0;
 
 err_ehci:
-       platform_device_put(ehci);
+       platform_device_unregister(ehci);
 
 err_end:
        return ret;
@@ -351,46 +349,13 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev)
        omap->platdata.ehci_data = pdata->ehci_data;
        omap->platdata.ohci_data = pdata->ohci_data;
 
-       omap->usbhost_ick = clk_get(dev, "usbhost_ick");
-       if (IS_ERR(omap->usbhost_ick)) {
-               ret =  PTR_ERR(omap->usbhost_ick);
-               dev_err(dev, "usbhost_ick failed error:%d\n", ret);
-               goto err_end;
-       }
-
-       omap->usbhost_hs_fck = clk_get(dev, "hs_fck");
-       if (IS_ERR(omap->usbhost_hs_fck)) {
-               ret = PTR_ERR(omap->usbhost_hs_fck);
-               dev_err(dev, "usbhost_hs_fck failed error:%d\n", ret);
-               goto err_usbhost_ick;
-       }
-
-       omap->usbhost_fs_fck = clk_get(dev, "fs_fck");
-       if (IS_ERR(omap->usbhost_fs_fck)) {
-               ret = PTR_ERR(omap->usbhost_fs_fck);
-               dev_err(dev, "usbhost_fs_fck failed error:%d\n", ret);
-               goto err_usbhost_hs_fck;
-       }
-
-       omap->usbtll_fck = clk_get(dev, "usbtll_fck");
-       if (IS_ERR(omap->usbtll_fck)) {
-               ret = PTR_ERR(omap->usbtll_fck);
-               dev_err(dev, "usbtll_fck failed error:%d\n", ret);
-               goto err_usbhost_fs_fck;
-       }
-
-       omap->usbtll_ick = clk_get(dev, "usbtll_ick");
-       if (IS_ERR(omap->usbtll_ick)) {
-               ret = PTR_ERR(omap->usbtll_ick);
-               dev_err(dev, "usbtll_ick failed error:%d\n", ret);
-               goto err_usbtll_fck;
-       }
+       pm_runtime_enable(&pdev->dev);
 
        omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
        if (IS_ERR(omap->utmi_p1_fck)) {
                ret = PTR_ERR(omap->utmi_p1_fck);
                dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
-               goto err_usbtll_ick;
+               goto err_end;
        }
 
        omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
@@ -520,22 +485,8 @@ err_xclk60mhsp1_ck:
 err_utmi_p1_fck:
        clk_put(omap->utmi_p1_fck);
 
-err_usbtll_ick:
-       clk_put(omap->usbtll_ick);
-
-err_usbtll_fck:
-       clk_put(omap->usbtll_fck);
-
-err_usbhost_fs_fck:
-       clk_put(omap->usbhost_fs_fck);
-
-err_usbhost_hs_fck:
-       clk_put(omap->usbhost_hs_fck);
-
-err_usbhost_ick:
-       clk_put(omap->usbhost_ick);
-
 err_end:
+       pm_runtime_disable(&pdev->dev);
        kfree(omap);
 
 end_probe:
@@ -569,11 +520,7 @@ static int __devexit usbhs_omap_remove(struct platform_device *pdev)
        clk_put(omap->utmi_p2_fck);
        clk_put(omap->xclk60mhsp1_ck);
        clk_put(omap->utmi_p1_fck);
-       clk_put(omap->usbtll_ick);
-       clk_put(omap->usbtll_fck);
-       clk_put(omap->usbhost_fs_fck);
-       clk_put(omap->usbhost_hs_fck);
-       clk_put(omap->usbhost_ick);
+       pm_runtime_disable(&pdev->dev);
        kfree(omap);
 
        return 0;
@@ -693,7 +640,6 @@ static int usbhs_enable(struct device *dev)
        struct usbhs_omap_platform_data *pdata = &omap->platdata;
        unsigned long                   flags = 0;
        int                             ret = 0;
-       unsigned long                   timeout;
        unsigned                        reg;
 
        dev_dbg(dev, "starting TI HSUSB Controller\n");
@@ -706,11 +652,7 @@ static int usbhs_enable(struct device *dev)
        if (omap->count > 0)
                goto end_count;
 
-       clk_enable(omap->usbhost_ick);
-       clk_enable(omap->usbhost_hs_fck);
-       clk_enable(omap->usbhost_fs_fck);
-       clk_enable(omap->usbtll_fck);
-       clk_enable(omap->usbtll_ick);
+       pm_runtime_get_sync(dev);
 
        if (pdata->ehci_data->phy_reset) {
                if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) {
@@ -734,50 +676,6 @@ static int usbhs_enable(struct device *dev)
        omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
        dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
 
-       /* perform TLL soft reset, and wait until reset is complete */
-       usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
-                       OMAP_USBTLL_SYSCONFIG_SOFTRESET);
-
-       /* Wait for TLL reset to complete */
-       timeout = jiffies + msecs_to_jiffies(1000);
-       while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
-                       & OMAP_USBTLL_SYSSTATUS_RESETDONE)) {
-               cpu_relax();
-
-               if (time_after(jiffies, timeout)) {
-                       dev_dbg(dev, "operation timed out\n");
-                       ret = -EINVAL;
-                       goto err_tll;
-               }
-       }
-
-       dev_dbg(dev, "TLL RESET DONE\n");
-
-       /* (1<<3) = no idle mode only for initial debugging */
-       usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
-                       OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
-                       OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
-                       OMAP_USBTLL_SYSCONFIG_AUTOIDLE);
-
-       /* Put UHH in NoIdle/NoStandby mode */
-       reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG);
-       if (is_omap_usbhs_rev1(omap)) {
-               reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP
-                               | OMAP_UHH_SYSCONFIG_SIDLEMODE
-                               | OMAP_UHH_SYSCONFIG_CACTIVITY
-                               | OMAP_UHH_SYSCONFIG_MIDLEMODE);
-               reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE;
-
-
-       } else if (is_omap_usbhs_rev2(omap)) {
-               reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR;
-               reg |= OMAP4_UHH_SYSCONFIG_NOIDLE;
-               reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR;
-               reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY;
-       }
-
-       usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);
-
        reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
        /* setup ULPI bypass and burst configurations */
        reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
@@ -917,6 +815,8 @@ end_count:
        return 0;
 
 err_tll:
+       pm_runtime_put_sync(dev);
+       spin_unlock_irqrestore(&omap->lock, flags);
        if (pdata->ehci_data->phy_reset) {
                if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
                        gpio_free(pdata->ehci_data->reset_gpio_port[0]);
@@ -924,13 +824,6 @@ err_tll:
                if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
                        gpio_free(pdata->ehci_data->reset_gpio_port[1]);
        }
-
-       clk_disable(omap->usbtll_ick);
-       clk_disable(omap->usbtll_fck);
-       clk_disable(omap->usbhost_fs_fck);
-       clk_disable(omap->usbhost_hs_fck);
-       clk_disable(omap->usbhost_ick);
-       spin_unlock_irqrestore(&omap->lock, flags);
        return ret;
 }
 
@@ -994,6 +887,20 @@ static void usbhs_disable(struct device *dev)
                        dev_dbg(dev, "operation timed out\n");
        }
 
+       if (is_omap_usbhs_rev2(omap)) {
+               if (is_ehci_tll_mode(pdata->port_mode[0]))
+                       clk_enable(omap->usbtll_p1_fck);
+               if (is_ehci_tll_mode(pdata->port_mode[1]))
+                       clk_enable(omap->usbtll_p2_fck);
+               clk_disable(omap->utmi_p2_fck);
+               clk_disable(omap->utmi_p1_fck);
+       }
+
+       pm_runtime_put_sync(dev);
+
+       /* The gpio_free migh sleep; so unlock the spinlock */
+       spin_unlock_irqrestore(&omap->lock, flags);
+
        if (pdata->ehci_data->phy_reset) {
                if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
                        gpio_free(pdata->ehci_data->reset_gpio_port[0]);
@@ -1001,14 +908,7 @@ static void usbhs_disable(struct device *dev)
                if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
                        gpio_free(pdata->ehci_data->reset_gpio_port[1]);
        }
-
-       clk_disable(omap->utmi_p2_fck);
-       clk_disable(omap->utmi_p1_fck);
-       clk_disable(omap->usbtll_ick);
-       clk_disable(omap->usbtll_fck);
-       clk_disable(omap->usbhost_fs_fck);
-       clk_disable(omap->usbhost_hs_fck);
-       clk_disable(omap->usbhost_ick);
+       return;
 
 end_disble:
        spin_unlock_irqrestore(&omap->lock, flags);
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
new file mode 100644 (file)
index 0000000..e873b15
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/msm_ssbi.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/mfd/pm8xxx/core.h>
+
+#define REG_HWREV              0x002  /* PMIC4 revision */
+#define REG_HWREV_2            0x0E8  /* PMIC4 revision 2 */
+
+struct pm8921 {
+       struct device                   *dev;
+       struct pm_irq_chip              *irq_chip;
+};
+
+static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
+{
+       const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
+       const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
+
+       return msm_ssbi_read(pmic->dev->parent, addr, val, 1);
+}
+
+static int pm8921_writeb(const struct device *dev, u16 addr, u8 val)
+{
+       const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
+       const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
+
+       return msm_ssbi_write(pmic->dev->parent, addr, &val, 1);
+}
+
+static int pm8921_read_buf(const struct device *dev, u16 addr, u8 *buf,
+                                                                       int cnt)
+{
+       const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
+       const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
+
+       return msm_ssbi_read(pmic->dev->parent, addr, buf, cnt);
+}
+
+static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf,
+                                                                       int cnt)
+{
+       const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
+       const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
+
+       return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt);
+}
+
+static int pm8921_read_irq_stat(const struct device *dev, int irq)
+{
+       const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
+       const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
+
+       return pm8xxx_get_irq_stat(pmic->irq_chip, irq);
+}
+
+static struct pm8xxx_drvdata pm8921_drvdata = {
+       .pmic_readb             = pm8921_readb,
+       .pmic_writeb            = pm8921_writeb,
+       .pmic_read_buf          = pm8921_read_buf,
+       .pmic_write_buf         = pm8921_write_buf,
+       .pmic_read_irq_stat     = pm8921_read_irq_stat,
+};
+
+static int __devinit pm8921_add_subdevices(const struct pm8921_platform_data
+                                          *pdata,
+                                          struct pm8921 *pmic,
+                                          u32 rev)
+{
+       int ret = 0, irq_base = 0;
+       struct pm_irq_chip *irq_chip;
+
+       if (pdata->irq_pdata) {
+               pdata->irq_pdata->irq_cdata.nirqs = PM8921_NR_IRQS;
+               pdata->irq_pdata->irq_cdata.rev = rev;
+               irq_base = pdata->irq_pdata->irq_base;
+               irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
+
+               if (IS_ERR(irq_chip)) {
+                       pr_err("Failed to init interrupts ret=%ld\n",
+                                       PTR_ERR(irq_chip));
+                       return PTR_ERR(irq_chip);
+               }
+               pmic->irq_chip = irq_chip;
+       }
+       return ret;
+}
+
+static int __devinit pm8921_probe(struct platform_device *pdev)
+{
+       const struct pm8921_platform_data *pdata = pdev->dev.platform_data;
+       struct pm8921 *pmic;
+       int rc;
+       u8 val;
+       u32 rev;
+
+       if (!pdata) {
+               pr_err("missing platform data\n");
+               return -EINVAL;
+       }
+
+       pmic = kzalloc(sizeof(struct pm8921), GFP_KERNEL);
+       if (!pmic) {
+               pr_err("Cannot alloc pm8921 struct\n");
+               return -ENOMEM;
+       }
+
+       /* Read PMIC chip revision */
+       rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
+       if (rc) {
+               pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc);
+               goto err_read_rev;
+       }
+       pr_info("PMIC revision 1: %02X\n", val);
+       rev = val;
+
+       /* Read PMIC chip revision 2 */
+       rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
+       if (rc) {
+               pr_err("Failed to read hw rev 2 reg %d:rc=%d\n",
+                       REG_HWREV_2, rc);
+               goto err_read_rev;
+       }
+       pr_info("PMIC revision 2: %02X\n", val);
+       rev |= val << BITS_PER_BYTE;
+
+       pmic->dev = &pdev->dev;
+       pm8921_drvdata.pm_chip_data = pmic;
+       platform_set_drvdata(pdev, &pm8921_drvdata);
+
+       rc = pm8921_add_subdevices(pdata, pmic, rev);
+       if (rc) {
+               pr_err("Cannot add subdevices rc=%d\n", rc);
+               goto err;
+       }
+
+       /* gpio might not work if no irq device is found */
+       WARN_ON(pmic->irq_chip == NULL);
+
+       return 0;
+
+err:
+       mfd_remove_devices(pmic->dev);
+       platform_set_drvdata(pdev, NULL);
+err_read_rev:
+       kfree(pmic);
+       return rc;
+}
+
+static int __devexit pm8921_remove(struct platform_device *pdev)
+{
+       struct pm8xxx_drvdata *drvdata;
+       struct pm8921 *pmic = NULL;
+
+       drvdata = platform_get_drvdata(pdev);
+       if (drvdata)
+               pmic = drvdata->pm_chip_data;
+       if (pmic)
+               mfd_remove_devices(pmic->dev);
+       if (pmic->irq_chip) {
+               pm8xxx_irq_exit(pmic->irq_chip);
+               pmic->irq_chip = NULL;
+       }
+       platform_set_drvdata(pdev, NULL);
+       kfree(pmic);
+
+       return 0;
+}
+
+static struct platform_driver pm8921_driver = {
+       .probe          = pm8921_probe,
+       .remove         = __devexit_p(pm8921_remove),
+       .driver         = {
+               .name   = "pm8921-core",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init pm8921_init(void)
+{
+       return platform_driver_register(&pm8921_driver);
+}
+subsys_initcall(pm8921_init);
+
+static void __exit pm8921_exit(void)
+{
+       platform_driver_unregister(&pm8921_driver);
+}
+module_exit(pm8921_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PMIC 8921 core driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:pm8921-core");
diff --git a/drivers/mfd/pm8xxx-irq.c b/drivers/mfd/pm8xxx-irq.c
new file mode 100644 (file)
index 0000000..d452dd0
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#define pr_fmt(fmt)    "%s: " fmt, __func__
+
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* PMIC8xxx IRQ */
+
+#define        SSBI_REG_ADDR_IRQ_BASE          0x1BB
+
+#define        SSBI_REG_ADDR_IRQ_ROOT          (SSBI_REG_ADDR_IRQ_BASE + 0)
+#define        SSBI_REG_ADDR_IRQ_M_STATUS1     (SSBI_REG_ADDR_IRQ_BASE + 1)
+#define        SSBI_REG_ADDR_IRQ_M_STATUS2     (SSBI_REG_ADDR_IRQ_BASE + 2)
+#define        SSBI_REG_ADDR_IRQ_M_STATUS3     (SSBI_REG_ADDR_IRQ_BASE + 3)
+#define        SSBI_REG_ADDR_IRQ_M_STATUS4     (SSBI_REG_ADDR_IRQ_BASE + 4)
+#define        SSBI_REG_ADDR_IRQ_BLK_SEL       (SSBI_REG_ADDR_IRQ_BASE + 5)
+#define        SSBI_REG_ADDR_IRQ_IT_STATUS     (SSBI_REG_ADDR_IRQ_BASE + 6)
+#define        SSBI_REG_ADDR_IRQ_CONFIG        (SSBI_REG_ADDR_IRQ_BASE + 7)
+#define        SSBI_REG_ADDR_IRQ_RT_STATUS     (SSBI_REG_ADDR_IRQ_BASE + 8)
+
+#define        PM_IRQF_LVL_SEL                 0x01    /* level select */
+#define        PM_IRQF_MASK_FE                 0x02    /* mask falling edge */
+#define        PM_IRQF_MASK_RE                 0x04    /* mask rising edge */
+#define        PM_IRQF_CLR                     0x08    /* clear interrupt */
+#define        PM_IRQF_BITS_MASK               0x70
+#define        PM_IRQF_BITS_SHIFT              4
+#define        PM_IRQF_WRITE                   0x80
+
+#define        PM_IRQF_MASK_ALL                (PM_IRQF_MASK_FE | \
+                                       PM_IRQF_MASK_RE)
+
+struct pm_irq_chip {
+       struct device           *dev;
+       spinlock_t              pm_irq_lock;
+       unsigned int            devirq;
+       unsigned int            irq_base;
+       unsigned int            num_irqs;
+       unsigned int            num_blocks;
+       unsigned int            num_masters;
+       u8                      config[0];
+};
+
+static int pm8xxx_read_root_irq(const struct pm_irq_chip *chip, u8 *rp)
+{
+       return pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_ROOT, rp);
+}
+
+static int pm8xxx_read_master_irq(const struct pm_irq_chip *chip, u8 m, u8 *bp)
+{
+       return pm8xxx_readb(chip->dev,
+                       SSBI_REG_ADDR_IRQ_M_STATUS1 + m, bp);
+}
+
+static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, u8 bp, u8 *ip)
+{
+       int     rc;
+
+       spin_lock(&chip->pm_irq_lock);
+       rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+       if (rc) {
+               pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
+               goto bail;
+       }
+
+       rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_IT_STATUS, ip);
+       if (rc)
+               pr_err("Failed Reading Status rc=%d\n", rc);
+bail:
+       spin_unlock(&chip->pm_irq_lock);
+       return rc;
+}
+
+static int pm8xxx_config_irq(struct pm_irq_chip *chip, u8 bp, u8 cp)
+{
+       int     rc;
+
+       spin_lock(&chip->pm_irq_lock);
+       rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+       if (rc) {
+               pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
+               goto bail;
+       }
+
+       cp |= PM_IRQF_WRITE;
+       rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, cp);
+       if (rc)
+               pr_err("Failed Configuring IRQ rc=%d\n", rc);
+bail:
+       spin_unlock(&chip->pm_irq_lock);
+       return rc;
+}
+
+static int pm8xxx_irq_block_handler(struct pm_irq_chip *chip, int block)
+{
+       int pmirq, irq, i, ret = 0;
+       u8 bits;
+
+       ret = pm8xxx_read_block_irq(chip, block, &bits);
+       if (ret) {
+               pr_err("Failed reading %d block ret=%d", block, ret);
+               return ret;
+       }
+       if (!bits) {
+               pr_err("block bit set in master but no irqs: %d", block);
+               return 0;
+       }
+
+       /* Check IRQ bits */
+       for (i = 0; i < 8; i++) {
+               if (bits & (1 << i)) {
+                       pmirq = block * 8 + i;
+                       irq = pmirq + chip->irq_base;
+                       generic_handle_irq(irq);
+               }
+       }
+       return 0;
+}
+
+static int pm8xxx_irq_master_handler(struct pm_irq_chip *chip, int master)
+{
+       u8 blockbits;
+       int block_number, i, ret = 0;
+
+       ret = pm8xxx_read_master_irq(chip, master, &blockbits);
+       if (ret) {
+               pr_err("Failed to read master %d ret=%d\n", master, ret);
+               return ret;
+       }
+       if (!blockbits) {
+               pr_err("master bit set in root but no blocks: %d", master);
+               return 0;
+       }
+
+       for (i = 0; i < 8; i++)
+               if (blockbits & (1 << i)) {
+                       block_number = master * 8 + i;  /* block # */
+                       ret |= pm8xxx_irq_block_handler(chip, block_number);
+               }
+       return ret;
+}
+
+static void pm8xxx_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       struct pm_irq_chip *chip = irq_desc_get_handler_data(desc);
+       struct irq_chip *irq_chip = irq_desc_get_chip(desc);
+       u8      root;
+       int     i, ret, masters = 0;
+
+       ret = pm8xxx_read_root_irq(chip, &root);
+       if (ret) {
+               pr_err("Can't read root status ret=%d\n", ret);
+               return;
+       }
+
+       /* on pm8xxx series masters start from bit 1 of the root */
+       masters = root >> 1;
+
+       /* Read allowed masters for blocks. */
+       for (i = 0; i < chip->num_masters; i++)
+               if (masters & (1 << i))
+                       pm8xxx_irq_master_handler(chip, i);
+
+       irq_chip->irq_ack(&desc->irq_data);
+}
+
+static void pm8xxx_irq_mask_ack(struct irq_data *d)
+{
+       struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+       unsigned int pmirq = d->irq - chip->irq_base;
+       int     master, irq_bit;
+       u8      block, config;
+
+       block = pmirq / 8;
+       master = block / 8;
+       irq_bit = pmirq % 8;
+
+       config = chip->config[pmirq] | PM_IRQF_MASK_ALL | PM_IRQF_CLR;
+       pm8xxx_config_irq(chip, block, config);
+}
+
+static void pm8xxx_irq_unmask(struct irq_data *d)
+{
+       struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+       unsigned int pmirq = d->irq - chip->irq_base;
+       int     master, irq_bit;
+       u8      block, config;
+
+       block = pmirq / 8;
+       master = block / 8;
+       irq_bit = pmirq % 8;
+
+       config = chip->config[pmirq];
+       pm8xxx_config_irq(chip, block, config);
+}
+
+static int pm8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+       struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+       unsigned int pmirq = d->irq - chip->irq_base;
+       int master, irq_bit;
+       u8 block, config;
+
+       block = pmirq / 8;
+       master = block / 8;
+       irq_bit  = pmirq % 8;
+
+       chip->config[pmirq] = (irq_bit << PM_IRQF_BITS_SHIFT)
+                                                       | PM_IRQF_MASK_ALL;
+       if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+               if (flow_type & IRQF_TRIGGER_RISING)
+                       chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
+               if (flow_type & IRQF_TRIGGER_FALLING)
+                       chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
+       } else {
+               chip->config[pmirq] |= PM_IRQF_LVL_SEL;
+
+               if (flow_type & IRQF_TRIGGER_HIGH)
+                       chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
+               else
+                       chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
+       }
+
+       config = chip->config[pmirq] | PM_IRQF_CLR;
+       return pm8xxx_config_irq(chip, block, config);
+}
+
+static int pm8xxx_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+       return 0;
+}
+
+static struct irq_chip pm8xxx_irq_chip = {
+       .name           = "pm8xxx",
+       .irq_mask_ack   = pm8xxx_irq_mask_ack,
+       .irq_unmask     = pm8xxx_irq_unmask,
+       .irq_set_type   = pm8xxx_irq_set_type,
+       .irq_set_wake   = pm8xxx_irq_set_wake,
+       .flags          = IRQCHIP_MASK_ON_SUSPEND,
+};
+
+/**
+ * pm8xxx_get_irq_stat - get the status of the irq line
+ * @chip: pointer to identify a pmic irq controller
+ * @irq: the irq number
+ *
+ * The pm8xxx gpio and mpp rely on the interrupt block to read
+ * the values on their pins. This function is to facilitate reading
+ * the status of a gpio or an mpp line. The caller has to convert the
+ * gpio number to irq number.
+ *
+ * RETURNS:
+ * an int indicating the value read on that line
+ */
+int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
+{
+       int pmirq, rc;
+       u8  block, bits, bit;
+       unsigned long flags;
+
+       if (chip == NULL || irq < chip->irq_base ||
+                       irq >= chip->irq_base + chip->num_irqs)
+               return -EINVAL;
+
+       pmirq = irq - chip->irq_base;
+
+       block = pmirq / 8;
+       bit = pmirq % 8;
+
+       spin_lock_irqsave(&chip->pm_irq_lock, flags);
+
+       rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, block);
+       if (rc) {
+               pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n",
+                       irq, pmirq, block, rc);
+               goto bail_out;
+       }
+
+       rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits);
+       if (rc) {
+               pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n",
+                       irq, pmirq, block, rc);
+               goto bail_out;
+       }
+
+       rc = (bits & (1 << bit)) ? 1 : 0;
+
+bail_out:
+       spin_unlock_irqrestore(&chip->pm_irq_lock, flags);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(pm8xxx_get_irq_stat);
+
+struct pm_irq_chip *  __devinit pm8xxx_irq_init(struct device *dev,
+                               const struct pm8xxx_irq_platform_data *pdata)
+{
+       struct pm_irq_chip  *chip;
+       int devirq, rc;
+       unsigned int pmirq;
+
+       if (!pdata) {
+               pr_err("No platform data\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       devirq = pdata->devirq;
+       if (devirq < 0) {
+               pr_err("missing devirq\n");
+               rc = devirq;
+               return ERR_PTR(-EINVAL);
+       }
+
+       chip = kzalloc(sizeof(struct pm_irq_chip)
+                       + sizeof(u8) * pdata->irq_cdata.nirqs, GFP_KERNEL);
+       if (!chip) {
+               pr_err("Cannot alloc pm_irq_chip struct\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       chip->dev = dev;
+       chip->devirq = devirq;
+       chip->irq_base = pdata->irq_base;
+       chip->num_irqs = pdata->irq_cdata.nirqs;
+       chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
+       chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
+       spin_lock_init(&chip->pm_irq_lock);
+
+       for (pmirq = 0; pmirq < chip->num_irqs; pmirq++) {
+               irq_set_chip_and_handler(chip->irq_base + pmirq,
+                               &pm8xxx_irq_chip,
+                               handle_level_irq);
+               irq_set_chip_data(chip->irq_base + pmirq, chip);
+#ifdef CONFIG_ARM
+               set_irq_flags(chip->irq_base + pmirq, IRQF_VALID);
+#else
+               irq_set_noprobe(chip->irq_base + pmirq);
+#endif
+       }
+
+       irq_set_irq_type(devirq, pdata->irq_trigger_flag);
+       irq_set_handler_data(devirq, chip);
+       irq_set_chained_handler(devirq, pm8xxx_irq_handler);
+       set_irq_wake(devirq, 1);
+
+       return chip;
+}
+
+int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip)
+{
+       irq_set_chained_handler(chip->devirq, NULL);
+       kfree(chip);
+       return 0;
+}
index 10dbe6374a89328b00da7014e4eccfa886906f2f..809bd4a610895c75baf469ceb1d3bec417aa64c8 100644 (file)
@@ -61,12 +61,14 @@ static struct mfd_cell rdc321x_sb_cells[] = {
                .name           = "rdc321x-wdt",
                .resources      = rdc321x_wdt_resource,
                .num_resources  = ARRAY_SIZE(rdc321x_wdt_resource),
-               .mfd_data       = &rdc321x_wdt_pdata,
+               .platform_data  = &rdc321x_wdt_pdata,
+               .pdata_size     = sizeof(rdc321x_wdt_pdata),
        }, {
                .name           = "rdc321x-gpio",
                .resources      = rdc321x_gpio_resources,
                .num_resources  = ARRAY_SIZE(rdc321x_gpio_resources),
-               .mfd_data       = &rdc321x_gpio_pdata,
+               .platform_data  = &rdc321x_gpio_pdata,
+               .pdata_size     = sizeof(rdc321x_gpio_pdata),
        },
 };
 
index 42830e6929649ae99e729479eb76dd1dd4bd917c..91ad21ef7721cddd335e5470717f3f878191bf0d 100644 (file)
@@ -170,7 +170,8 @@ static struct mfd_cell t7l66xb_cells[] = {
                .name = "tmio-mmc",
                .enable = t7l66xb_mmc_enable,
                .disable = t7l66xb_mmc_disable,
-               .mfd_data = &t7166xb_mmc_data,
+               .platform_data = &t7166xb_mmc_data,
+               .pdata_size    = sizeof(t7166xb_mmc_data),
                .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources),
                .resources = t7l66xb_mmc_resources,
        },
@@ -382,7 +383,8 @@ static int t7l66xb_probe(struct platform_device *dev)
 
        t7l66xb_attach_irq(dev);
 
-       t7l66xb_cells[T7L66XB_CELL_NAND].mfd_data = pdata->nand_data;
+       t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = pdata->nand_data;
+       t7l66xb_cells[T7L66XB_CELL_NAND].pdata_size = sizeof(*pdata->nand_data);
 
        ret = mfd_add_devices(&dev->dev, dev->id,
                              t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells),
index b006f7cee9521673acf6e65e9b599dfc98d73a26..ad715bf49cac916fa86b15179c3f6415ecec265f 100644 (file)
@@ -131,7 +131,8 @@ static struct mfd_cell tc6387xb_cells[] = {
                .name = "tmio-mmc",
                .enable = tc6387xb_mmc_enable,
                .disable = tc6387xb_mmc_disable,
-               .mfd_data = &tc6387xb_mmc_data,
+               .platform_data = &tc6387xb_mmc_data,
+               .pdata_size    = sizeof(tc6387xb_mmc_data),
                .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources),
                .resources = tc6387xb_mmc_resources,
        },
index fc53ce287601b84062940d80428fdf3dcb358c16..9612264f0e6dcf7832ebf2f4736815b4eabc6a4b 100644 (file)
@@ -393,7 +393,8 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = {
                .name = "tmio-mmc",
                .enable = tc6393xb_mmc_enable,
                .resume = tc6393xb_mmc_resume,
-               .mfd_data = &tc6393xb_mmc_data,
+               .platform_data = &tc6393xb_mmc_data,
+               .pdata_size    = sizeof(tc6393xb_mmc_data),
                .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources),
                .resources = tc6393xb_mmc_resources,
        },
@@ -692,8 +693,11 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
                        goto err_setup;
        }
 
-       tc6393xb_cells[TC6393XB_CELL_NAND].mfd_data = tcpd->nand_data;
-       tc6393xb_cells[TC6393XB_CELL_FB].mfd_data = tcpd->fb_data;
+       tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = tcpd->nand_data;
+       tc6393xb_cells[TC6393XB_CELL_NAND].pdata_size =
+                                               sizeof(*tcpd->nand_data);
+       tc6393xb_cells[TC6393XB_CELL_FB].platform_data = tcpd->fb_data;
+       tc6393xb_cells[TC6393XB_CELL_FB].pdata_size = sizeof(*tcpd->fb_data);
 
        ret = mfd_add_devices(&dev->dev, dev->id,
                        tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells),
index 94c6c8afad12e5abe9e0728b833db5c70f0d23aa..69272e4e34596a60b059a4d30f6eadddd4a473c3 100644 (file)
@@ -384,7 +384,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
                .name = "timb-dma",
                .num_resources = ARRAY_SIZE(timberdale_dma_resources),
                .resources = timberdale_dma_resources,
-               .mfd_data = &timb_dma_platform_data,
+               .platform_data = &timb_dma_platform_data,
+               .pdata_size = sizeof(timb_dma_platform_data),
        },
        {
                .name = "timb-uart",
@@ -395,37 +396,43 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
                .name = "xiic-i2c",
                .num_resources = ARRAY_SIZE(timberdale_xiic_resources),
                .resources = timberdale_xiic_resources,
-               .mfd_data = &timberdale_xiic_platform_data,
+               .platform_data = &timberdale_xiic_platform_data,
+               .pdata_size = sizeof(timberdale_xiic_platform_data),
        },
        {
                .name = "timb-gpio",
                .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
                .resources = timberdale_gpio_resources,
-               .mfd_data = &timberdale_gpio_platform_data,
+               .platform_data = &timberdale_gpio_platform_data,
+               .pdata_size = sizeof(timberdale_gpio_platform_data),
        },
        {
                .name = "timb-video",
                .num_resources = ARRAY_SIZE(timberdale_video_resources),
                .resources = timberdale_video_resources,
-               .mfd_data = &timberdale_video_platform_data,
+               .platform_data = &timberdale_video_platform_data,
+               .pdata_size = sizeof(timberdale_video_platform_data),
        },
        {
                .name = "timb-radio",
                .num_resources = ARRAY_SIZE(timberdale_radio_resources),
                .resources = timberdale_radio_resources,
-               .mfd_data = &timberdale_radio_platform_data,
+               .platform_data = &timberdale_radio_platform_data,
+               .pdata_size = sizeof(timberdale_radio_platform_data),
        },
        {
                .name = "xilinx_spi",
                .num_resources = ARRAY_SIZE(timberdale_spi_resources),
                .resources = timberdale_spi_resources,
-               .mfd_data = &timberdale_xspi_platform_data,
+               .platform_data = &timberdale_xspi_platform_data,
+               .pdata_size = sizeof(timberdale_xspi_platform_data),
        },
        {
                .name = "ks8842",
                .num_resources = ARRAY_SIZE(timberdale_eth_resources),
                .resources = timberdale_eth_resources,
-               .mfd_data = &timberdale_ks8842_platform_data,
+               .platform_data = &timberdale_ks8842_platform_data,
+               .pdata_size = sizeof(timberdale_ks8842_platform_data),
        },
 };
 
@@ -434,7 +441,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
                .name = "timb-dma",
                .num_resources = ARRAY_SIZE(timberdale_dma_resources),
                .resources = timberdale_dma_resources,
-               .mfd_data = &timb_dma_platform_data,
+               .platform_data = &timb_dma_platform_data,
+               .pdata_size = sizeof(timb_dma_platform_data),
        },
        {
                .name = "timb-uart",
@@ -450,13 +458,15 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
                .name = "xiic-i2c",
                .num_resources = ARRAY_SIZE(timberdale_xiic_resources),
                .resources = timberdale_xiic_resources,
-               .mfd_data = &timberdale_xiic_platform_data,
+               .platform_data = &timberdale_xiic_platform_data,
+               .pdata_size = sizeof(timberdale_xiic_platform_data),
        },
        {
                .name = "timb-gpio",
                .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
                .resources = timberdale_gpio_resources,
-               .mfd_data = &timberdale_gpio_platform_data,
+               .platform_data = &timberdale_gpio_platform_data,
+               .pdata_size = sizeof(timberdale_gpio_platform_data),
        },
        {
                .name = "timb-mlogicore",
@@ -467,25 +477,29 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
                .name = "timb-video",
                .num_resources = ARRAY_SIZE(timberdale_video_resources),
                .resources = timberdale_video_resources,
-               .mfd_data = &timberdale_video_platform_data,
+               .platform_data = &timberdale_video_platform_data,
+               .pdata_size = sizeof(timberdale_video_platform_data),
        },
        {
                .name = "timb-radio",
                .num_resources = ARRAY_SIZE(timberdale_radio_resources),
                .resources = timberdale_radio_resources,
-               .mfd_data = &timberdale_radio_platform_data,
+               .platform_data = &timberdale_radio_platform_data,
+               .pdata_size = sizeof(timberdale_radio_platform_data),
        },
        {
                .name = "xilinx_spi",
                .num_resources = ARRAY_SIZE(timberdale_spi_resources),
                .resources = timberdale_spi_resources,
-               .mfd_data = &timberdale_xspi_platform_data,
+               .platform_data = &timberdale_xspi_platform_data,
+               .pdata_size = sizeof(timberdale_xspi_platform_data),
        },
        {
                .name = "ks8842",
                .num_resources = ARRAY_SIZE(timberdale_eth_resources),
                .resources = timberdale_eth_resources,
-               .mfd_data = &timberdale_ks8842_platform_data,
+               .platform_data = &timberdale_ks8842_platform_data,
+               .pdata_size = sizeof(timberdale_ks8842_platform_data),
        },
 };
 
@@ -494,7 +508,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
                .name = "timb-dma",
                .num_resources = ARRAY_SIZE(timberdale_dma_resources),
                .resources = timberdale_dma_resources,
-               .mfd_data = &timb_dma_platform_data,
+               .platform_data = &timb_dma_platform_data,
+               .pdata_size = sizeof(timb_dma_platform_data),
        },
        {
                .name = "timb-uart",
@@ -505,31 +520,36 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
                .name = "xiic-i2c",
                .num_resources = ARRAY_SIZE(timberdale_xiic_resources),
                .resources = timberdale_xiic_resources,
-               .mfd_data = &timberdale_xiic_platform_data,
+               .platform_data = &timberdale_xiic_platform_data,
+               .pdata_size = sizeof(timberdale_xiic_platform_data),
        },
        {
                .name = "timb-gpio",
                .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
                .resources = timberdale_gpio_resources,
-               .mfd_data = &timberdale_gpio_platform_data,
+               .platform_data = &timberdale_gpio_platform_data,
+               .pdata_size = sizeof(timberdale_gpio_platform_data),
        },
        {
                .name = "timb-video",
                .num_resources = ARRAY_SIZE(timberdale_video_resources),
                .resources = timberdale_video_resources,
-               .mfd_data = &timberdale_video_platform_data,
+               .platform_data = &timberdale_video_platform_data,
+               .pdata_size = sizeof(timberdale_video_platform_data),
        },
        {
                .name = "timb-radio",
                .num_resources = ARRAY_SIZE(timberdale_radio_resources),
                .resources = timberdale_radio_resources,
-               .mfd_data = &timberdale_radio_platform_data,
+               .platform_data = &timberdale_radio_platform_data,
+               .pdata_size = sizeof(timberdale_radio_platform_data),
        },
        {
                .name = "xilinx_spi",
                .num_resources = ARRAY_SIZE(timberdale_spi_resources),
                .resources = timberdale_spi_resources,
-               .mfd_data = &timberdale_xspi_platform_data,
+               .platform_data = &timberdale_xspi_platform_data,
+               .pdata_size = sizeof(timberdale_xspi_platform_data),
        },
 };
 
@@ -538,7 +558,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
                .name = "timb-dma",
                .num_resources = ARRAY_SIZE(timberdale_dma_resources),
                .resources = timberdale_dma_resources,
-               .mfd_data = &timb_dma_platform_data,
+               .platform_data = &timb_dma_platform_data,
+               .pdata_size = sizeof(timb_dma_platform_data),
        },
        {
                .name = "timb-uart",
@@ -549,37 +570,43 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
                .name = "ocores-i2c",
                .num_resources = ARRAY_SIZE(timberdale_ocores_resources),
                .resources = timberdale_ocores_resources,
-               .mfd_data = &timberdale_ocores_platform_data,
+               .platform_data = &timberdale_ocores_platform_data,
+               .pdata_size = sizeof(timberdale_ocores_platform_data),
        },
        {
                .name = "timb-gpio",
                .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
                .resources = timberdale_gpio_resources,
-               .mfd_data = &timberdale_gpio_platform_data,
+               .platform_data = &timberdale_gpio_platform_data,
+               .pdata_size = sizeof(timberdale_gpio_platform_data),
        },
        {
                .name = "timb-video",
                .num_resources = ARRAY_SIZE(timberdale_video_resources),
                .resources = timberdale_video_resources,
-               .mfd_data = &timberdale_video_platform_data,
+               .platform_data = &timberdale_video_platform_data,
+               .pdata_size = sizeof(timberdale_video_platform_data),
        },
        {
                .name = "timb-radio",
                .num_resources = ARRAY_SIZE(timberdale_radio_resources),
                .resources = timberdale_radio_resources,
-               .mfd_data = &timberdale_radio_platform_data,
+               .platform_data = &timberdale_radio_platform_data,
+               .pdata_size = sizeof(timberdale_radio_platform_data),
        },
        {
                .name = "xilinx_spi",
                .num_resources = ARRAY_SIZE(timberdale_spi_resources),
                .resources = timberdale_spi_resources,
-               .mfd_data = &timberdale_xspi_platform_data,
+               .platform_data = &timberdale_xspi_platform_data,
+               .pdata_size = sizeof(timberdale_xspi_platform_data),
        },
        {
                .name = "ks8842",
                .num_resources = ARRAY_SIZE(timberdale_eth_resources),
                .resources = timberdale_eth_resources,
-               .mfd_data = &timberdale_ks8842_platform_data,
+               .platform_data = &timberdale_ks8842_platform_data,
+               .pdata_size = sizeof(timberdale_ks8842_platform_data),
        },
 };
 
index 46d8205646b6cfdd93b90d1ee02c91b8bac5746b..a293b978e27ce19b116025e3ab4e87be6ae0dd74 100644 (file)
@@ -183,7 +183,8 @@ static int __devinit tps6105x_probe(struct i2c_client *client,
        /* Set up and register the platform devices. */
        for (i = 0; i < ARRAY_SIZE(tps6105x_cells); i++) {
                /* One state holder for all drivers, this is simple */
-               tps6105x_cells[i].mfd_data = tps6105x;
+               tps6105x_cells[i].platform_data = tps6105x;
+               tps6105x_cells[i].pdata_size = sizeof(*tps6105x);
        }
 
        ret = mfd_add_devices(&client->dev, 0, tps6105x_cells,
index b600808690c1092e1d9946f848e537647dbd1def..bba26d96c24075a3cbca9a320fabe3177b4de1a8 100644 (file)
@@ -270,8 +270,8 @@ static void tps6586x_gpio_set(struct gpio_chip *chip, unsigned offset,
 {
        struct tps6586x *tps6586x = container_of(chip, struct tps6586x, gpio);
 
-       __tps6586x_write(tps6586x->client, TPS6586X_GPIOSET2,
-                        value << offset);
+       tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET2,
+                       value << offset, 1 << offset);
 }
 
 static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,
diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c
new file mode 100644 (file)
index 0000000..2bfad5c
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * tps65910-irq.c  --  TI TPS6591x
+ *
+ * Copyright 2010 Texas Instruments Inc.
+ *
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
+ *
+ *  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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/mfd/tps65910.h>
+
+static inline int irq_to_tps65910_irq(struct tps65910 *tps65910,
+                                                       int irq)
+{
+       return (irq - tps65910->irq_base);
+}
+
+/*
+ * This is a threaded IRQ handler so can access I2C/SPI.  Since all
+ * interrupts are clear on read the IRQ line will be reasserted and
+ * the physical IRQ will be handled again if another interrupt is
+ * asserted while we run - in the normal course of events this is a
+ * rare occurrence so we save I2C/SPI reads.  We're also assuming that
+ * it's rare to get lots of interrupts firing simultaneously so try to
+ * minimise I/O.
+ */
+static irqreturn_t tps65910_irq(int irq, void *irq_data)
+{
+       struct tps65910 *tps65910 = irq_data;
+       u32 irq_sts;
+       u32 irq_mask;
+       u8 reg;
+       int i;
+
+       tps65910->read(tps65910, TPS65910_INT_STS, 1, &reg);
+       irq_sts = reg;
+       tps65910->read(tps65910, TPS65910_INT_STS2, 1, &reg);
+       irq_sts |= reg << 8;
+       switch (tps65910_chip_id(tps65910)) {
+       case TPS65911:
+               tps65910->read(tps65910, TPS65910_INT_STS3, 1, &reg);
+               irq_sts |= reg << 16;
+       }
+
+       tps65910->read(tps65910, TPS65910_INT_MSK, 1, &reg);
+       irq_mask = reg;
+       tps65910->read(tps65910, TPS65910_INT_MSK2, 1, &reg);
+       irq_mask |= reg << 8;
+       switch (tps65910_chip_id(tps65910)) {
+       case TPS65911:
+               tps65910->read(tps65910, TPS65910_INT_MSK3, 1, &reg);
+               irq_mask |= reg << 16;
+       }
+
+       irq_sts &= ~irq_mask;
+
+       if (!irq_sts)
+               return IRQ_NONE;
+
+       for (i = 0; i < tps65910->irq_num; i++) {
+
+               if (!(irq_sts & (1 << i)))
+                       continue;
+
+               handle_nested_irq(tps65910->irq_base + i);
+       }
+
+       /* Write the STS register back to clear IRQs we handled */
+       reg = irq_sts & 0xFF;
+       irq_sts >>= 8;
+       tps65910->write(tps65910, TPS65910_INT_STS, 1, &reg);
+       reg = irq_sts & 0xFF;
+       tps65910->write(tps65910, TPS65910_INT_STS2, 1, &reg);
+       switch (tps65910_chip_id(tps65910)) {
+       case TPS65911:
+               reg = irq_sts >> 8;
+               tps65910->write(tps65910, TPS65910_INT_STS3, 1, &reg);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void tps65910_irq_lock(struct irq_data *data)
+{
+       struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
+
+       mutex_lock(&tps65910->irq_lock);
+}
+
+static void tps65910_irq_sync_unlock(struct irq_data *data)
+{
+       struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
+       u32 reg_mask;
+       u8 reg;
+
+       tps65910->read(tps65910, TPS65910_INT_MSK, 1, &reg);
+       reg_mask = reg;
+       tps65910->read(tps65910, TPS65910_INT_MSK2, 1, &reg);
+       reg_mask |= reg << 8;
+       switch (tps65910_chip_id(tps65910)) {
+       case TPS65911:
+               tps65910->read(tps65910, TPS65910_INT_MSK3, 1, &reg);
+               reg_mask |= reg << 16;
+       }
+
+       if (tps65910->irq_mask != reg_mask) {
+               reg = tps65910->irq_mask & 0xFF;
+               tps65910->write(tps65910, TPS65910_INT_MSK, 1, &reg);
+               reg = tps65910->irq_mask >> 8 & 0xFF;
+               tps65910->write(tps65910, TPS65910_INT_MSK2, 1, &reg);
+               switch (tps65910_chip_id(tps65910)) {
+               case TPS65911:
+                       reg = tps65910->irq_mask >> 16;
+                       tps65910->write(tps65910, TPS65910_INT_MSK3, 1, &reg);
+               }
+       }
+       mutex_unlock(&tps65910->irq_lock);
+}
+
+static void tps65910_irq_enable(struct irq_data *data)
+{
+       struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
+
+       tps65910->irq_mask &= ~( 1 << irq_to_tps65910_irq(tps65910, data->irq));
+}
+
+static void tps65910_irq_disable(struct irq_data *data)
+{
+       struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
+
+       tps65910->irq_mask |= ( 1 << irq_to_tps65910_irq(tps65910, data->irq));
+}
+
+static struct irq_chip tps65910_irq_chip = {
+       .name = "tps65910",
+       .irq_bus_lock = tps65910_irq_lock,
+       .irq_bus_sync_unlock = tps65910_irq_sync_unlock,
+       .irq_disable = tps65910_irq_disable,
+       .irq_enable = tps65910_irq_enable,
+};
+
+int tps65910_irq_init(struct tps65910 *tps65910, int irq,
+                   struct tps65910_platform_data *pdata)
+{
+       int ret, cur_irq;
+       int flags = IRQF_ONESHOT;
+
+       if (!irq) {
+               dev_warn(tps65910->dev, "No interrupt support, no core IRQ\n");
+               return -EINVAL;
+       }
+
+       if (!pdata || !pdata->irq_base) {
+               dev_warn(tps65910->dev, "No interrupt support, no IRQ base\n");
+               return -EINVAL;
+       }
+
+       tps65910->irq_mask = 0xFFFFFF;
+
+       mutex_init(&tps65910->irq_lock);
+       tps65910->chip_irq = irq;
+       tps65910->irq_base = pdata->irq_base;
+
+       switch (tps65910_chip_id(tps65910)) {
+       case TPS65910:
+               tps65910->irq_num = TPS65910_NUM_IRQ;
+       case TPS65911:
+               tps65910->irq_num = TPS65911_NUM_IRQ;
+       }
+
+       /* Register with genirq */
+       for (cur_irq = tps65910->irq_base;
+            cur_irq < tps65910->irq_num + tps65910->irq_base;
+            cur_irq++) {
+               irq_set_chip_data(cur_irq, tps65910);
+               irq_set_chip_and_handler(cur_irq, &tps65910_irq_chip,
+                                        handle_edge_irq);
+               irq_set_nested_thread(cur_irq, 1);
+
+               /* ARM needs us to explicitly flag the IRQ as valid
+                * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+               set_irq_flags(cur_irq, IRQF_VALID);
+#else
+               irq_set_noprobe(cur_irq);
+#endif
+       }
+
+       ret = request_threaded_irq(irq, NULL, tps65910_irq, flags,
+                                  "tps65910", tps65910);
+
+       irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
+
+       if (ret != 0)
+               dev_err(tps65910->dev, "Failed to request IRQ: %d\n", ret);
+
+       return ret;
+}
+
+int tps65910_irq_exit(struct tps65910 *tps65910)
+{
+       free_irq(tps65910->chip_irq, tps65910);
+       return 0;
+}
diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c
new file mode 100644 (file)
index 0000000..2229e66
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * tps65910.c  --  TI TPS6591x
+ *
+ * Copyright 2010 Texas Instruments Inc.
+ *
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
+ *
+ *  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/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65910.h>
+
+static struct mfd_cell tps65910s[] = {
+       {
+               .name = "tps65910-pmic",
+       },
+       {
+               .name = "tps65910-rtc",
+       },
+       {
+               .name = "tps65910-power",
+       },
+};
+
+
+static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
+                                 int bytes, void *dest)
+{
+       struct i2c_client *i2c = tps65910->i2c_client;
+       struct i2c_msg xfer[2];
+       int ret;
+
+       /* Write register */
+       xfer[0].addr = i2c->addr;
+       xfer[0].flags = 0;
+       xfer[0].len = 1;
+       xfer[0].buf = &reg;
+
+       /* Read data */
+       xfer[1].addr = i2c->addr;
+       xfer[1].flags = I2C_M_RD;
+       xfer[1].len = bytes;
+       xfer[1].buf = dest;
+
+       ret = i2c_transfer(i2c->adapter, xfer, 2);
+       if (ret == 2)
+               ret = 0;
+       else if (ret >= 0)
+               ret = -EIO;
+
+       return ret;
+}
+
+static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg,
+                                  int bytes, void *src)
+{
+       struct i2c_client *i2c = tps65910->i2c_client;
+       /* we add 1 byte for device register */
+       u8 msg[TPS65910_MAX_REGISTER + 1];
+       int ret;
+
+       if (bytes > TPS65910_MAX_REGISTER)
+               return -EINVAL;
+
+       msg[0] = reg;
+       memcpy(&msg[1], src, bytes);
+
+       ret = i2c_master_send(i2c, msg, bytes + 1);
+       if (ret < 0)
+               return ret;
+       if (ret != bytes + 1)
+               return -EIO;
+       return 0;
+}
+
+int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
+{
+       u8 data;
+       int err;
+
+       mutex_lock(&tps65910->io_mutex);
+       err = tps65910_i2c_read(tps65910, reg, 1, &data);
+       if (err) {
+               dev_err(tps65910->dev, "read from reg %x failed\n", reg);
+               goto out;
+       }
+
+       data |= mask;
+       err = tps65910_i2c_write(tps65910, reg, 1, &data);
+       if (err)
+               dev_err(tps65910->dev, "write to reg %x failed\n", reg);
+
+out:
+       mutex_unlock(&tps65910->io_mutex);
+       return err;
+}
+EXPORT_SYMBOL_GPL(tps65910_set_bits);
+
+int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
+{
+       u8 data;
+       int err;
+
+       mutex_lock(&tps65910->io_mutex);
+       err = tps65910_i2c_read(tps65910, reg, 1, &data);
+       if (err) {
+               dev_err(tps65910->dev, "read from reg %x failed\n", reg);
+               goto out;
+       }
+
+       data &= mask;
+       err = tps65910_i2c_write(tps65910, reg, 1, &data);
+       if (err)
+               dev_err(tps65910->dev, "write to reg %x failed\n", reg);
+
+out:
+       mutex_unlock(&tps65910->io_mutex);
+       return err;
+}
+EXPORT_SYMBOL_GPL(tps65910_clear_bits);
+
+static int tps65910_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct tps65910 *tps65910;
+       struct tps65910_board *pmic_plat_data;
+       struct tps65910_platform_data *init_data;
+       int ret = 0;
+
+       pmic_plat_data = dev_get_platdata(&i2c->dev);
+       if (!pmic_plat_data)
+               return -EINVAL;
+
+       init_data = kzalloc(sizeof(struct tps65910_platform_data), GFP_KERNEL);
+       if (init_data == NULL)
+               return -ENOMEM;
+
+       init_data->irq = pmic_plat_data->irq;
+       init_data->irq_base = pmic_plat_data->irq;
+
+       tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL);
+       if (tps65910 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, tps65910);
+       tps65910->dev = &i2c->dev;
+       tps65910->i2c_client = i2c;
+       tps65910->id = id->driver_data;
+       tps65910->read = tps65910_i2c_read;
+       tps65910->write = tps65910_i2c_write;
+       mutex_init(&tps65910->io_mutex);
+
+       ret = mfd_add_devices(tps65910->dev, -1,
+                             tps65910s, ARRAY_SIZE(tps65910s),
+                             NULL, 0);
+       if (ret < 0)
+               goto err;
+
+       tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base);
+
+       ret = tps65910_irq_init(tps65910, init_data->irq, init_data);
+       if (ret < 0)
+               goto err;
+
+       return ret;
+
+err:
+       mfd_remove_devices(tps65910->dev);
+       kfree(tps65910);
+       return ret;
+}
+
+static int tps65910_i2c_remove(struct i2c_client *i2c)
+{
+       struct tps65910 *tps65910 = i2c_get_clientdata(i2c);
+
+       mfd_remove_devices(tps65910->dev);
+       kfree(tps65910);
+
+       return 0;
+}
+
+static const struct i2c_device_id tps65910_i2c_id[] = {
+       { "tps65910", TPS65910 },
+       { "tps65911", TPS65911 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tps65910_i2c_id);
+
+
+static struct i2c_driver tps65910_i2c_driver = {
+       .driver = {
+                  .name = "tps65910",
+                  .owner = THIS_MODULE,
+       },
+       .probe = tps65910_i2c_probe,
+       .remove = tps65910_i2c_remove,
+       .id_table = tps65910_i2c_id,
+};
+
+static int __init tps65910_i2c_init(void)
+{
+       return i2c_add_driver(&tps65910_i2c_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(tps65910_i2c_init);
+
+static void __exit tps65910_i2c_exit(void)
+{
+       i2c_del_driver(&tps65910_i2c_driver);
+}
+module_exit(tps65910_i2c_exit);
+
+MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
+MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>");
+MODULE_DESCRIPTION("TPS6591x chip family multi-function driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/tps65911-comparator.c b/drivers/mfd/tps65911-comparator.c
new file mode 100644 (file)
index 0000000..3d2dc56
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * tps65910.c  --  TI TPS6591x
+ *
+ * Copyright 2010 Texas Instruments Inc.
+ *
+ * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
+ *
+ *  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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/gpio.h>
+#include <linux/mfd/tps65910.h>
+
+#define COMP                                   0
+#define COMP1                                  1
+#define COMP2                                  2
+
+/* Comparator 1 voltage selection table in milivolts */
+static const u16 COMP_VSEL_TABLE[] = {
+       0, 2500, 2500, 2500, 2500, 2550, 2600, 2650,
+       2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050,
+       3100, 3150, 3200, 3250, 3300, 3350, 3400, 3450,
+       3500,
+};
+
+struct comparator {
+       const char *name;
+       int reg;
+       int uV_max;
+       const u16 *vsel_table;
+};
+
+static struct comparator tps_comparators[] = {
+       {
+               .name = "COMP1",
+               .reg = TPS65911_VMBCH,
+               .uV_max = 3500,
+               .vsel_table = COMP_VSEL_TABLE,
+       },
+       {
+               .name = "COMP2",
+               .reg = TPS65911_VMBCH2,
+               .uV_max = 3500,
+               .vsel_table = COMP_VSEL_TABLE,
+       },
+};
+
+static int comp_threshold_set(struct tps65910 *tps65910, int id, int voltage)
+{
+       struct comparator tps_comp = tps_comparators[id];
+       int curr_voltage = 0;
+       int ret;
+       u8 index = 0, val;
+
+       if (id == COMP)
+               return 0;
+
+       while (curr_voltage < tps_comp.uV_max) {
+               curr_voltage = tps_comp.vsel_table[index];
+               if (curr_voltage >= voltage)
+                       break;
+               else if (curr_voltage < voltage)
+                       index ++;
+       }
+
+       if (curr_voltage > tps_comp.uV_max)
+               return -EINVAL;
+
+       val = index << 1;
+       ret = tps65910->write(tps65910, tps_comp.reg, 1, &val);
+
+       return ret;
+}
+
+static int comp_threshold_get(struct tps65910 *tps65910, int id)
+{
+       struct comparator tps_comp = tps_comparators[id];
+       int ret;
+       u8 val;
+
+       if (id == COMP)
+               return 0;
+
+       ret = tps65910->read(tps65910, tps_comp.reg, 1, &val);
+       if (ret < 0)
+               return ret;
+
+       val >>= 1;
+       return tps_comp.vsel_table[val];
+}
+
+static ssize_t comp_threshold_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct tps65910 *tps65910 = dev_get_drvdata(dev->parent);
+       struct attribute comp_attr = attr->attr;
+       int id, uVolt;
+
+       if (!strcmp(comp_attr.name, "comp1_threshold"))
+               id = COMP1;
+       else if (!strcmp(comp_attr.name, "comp2_threshold"))
+               id = COMP2;
+       else
+               return -EINVAL;
+
+       uVolt = comp_threshold_get(tps65910, id);
+
+       return sprintf(buf, "%d\n", uVolt);
+}
+
+static DEVICE_ATTR(comp1_threshold, S_IRUGO, comp_threshold_show, NULL);
+static DEVICE_ATTR(comp2_threshold, S_IRUGO, comp_threshold_show, NULL);
+
+static __devinit int tps65911_comparator_probe(struct platform_device *pdev)
+{
+       struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
+       struct tps65910_platform_data *pdata = dev_get_platdata(tps65910->dev);
+       int ret;
+
+       ret = comp_threshold_set(tps65910, COMP1,  pdata->vmbch_threshold);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "cannot set COMP1 threshold\n");
+               return ret;
+       }
+
+       ret = comp_threshold_set(tps65910, COMP2, pdata->vmbch2_threshold);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "cannot set COMP2 theshold\n");
+               return ret;
+       }
+
+       /* Create sysfs entry */
+       ret = device_create_file(&pdev->dev, &dev_attr_comp1_threshold);
+       if (ret < 0)
+               dev_err(&pdev->dev, "failed to add COMP1 sysfs file\n");
+
+       ret = device_create_file(&pdev->dev, &dev_attr_comp2_threshold);
+       if (ret < 0)
+               dev_err(&pdev->dev, "failed to add COMP2 sysfs file\n");
+
+       return ret;
+}
+
+static __devexit int tps65911_comparator_remove(struct platform_device *pdev)
+{
+       struct tps65910 *tps65910;
+
+       tps65910 = dev_get_drvdata(pdev->dev.parent);
+
+       return 0;
+}
+
+static struct platform_driver tps65911_comparator_driver = {
+       .driver = {
+               .name = "tps65911-comparator",
+               .owner = THIS_MODULE,
+       },
+       .probe = tps65911_comparator_probe,
+       .remove = __devexit_p(tps65911_comparator_remove),
+};
+
+static int __init tps65911_comparator_init(void)
+{
+       return platform_driver_register(&tps65911_comparator_driver);
+}
+subsys_initcall(tps65911_comparator_init);
+
+static void __exit tps65911_comparator_exit(void)
+{
+       platform_driver_unregister(&tps65911_comparator_driver);
+}
+module_exit(tps65911_comparator_exit);
+
+MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>");
+MODULE_DESCRIPTION("TPS65911 comparator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tps65911-comparator");
index 960b5bed7f5237afdd769583db90908ed7a45fca..b8f2a4e7f6e767f47da933edd805ffd0bdba2120 100644 (file)
 #define TWL6030_BASEADD_GASGAUGE       0x00C0
 #define TWL6030_BASEADD_PIH            0x00D0
 #define TWL6030_BASEADD_CHARGER                0x00E0
+#define TWL6025_BASEADD_CHARGER                0x00DA
 
 /* subchip/slave 2 0x4A - DFT */
 #define TWL6030_BASEADD_DIEID          0x00C0
 /* is driver active, bound to a chip? */
 static bool inuse;
 
+/* TWL IDCODE Register value */
+static u32 twl_idcode;
+
 static unsigned int twl_id;
 unsigned int twl_rev(void)
 {
@@ -328,6 +332,7 @@ static struct twl_mapping twl6030_map[] = {
 
        { SUB_CHIP_ID0, TWL6030_BASEADD_RTC },
        { SUB_CHIP_ID0, TWL6030_BASEADD_MEM },
+       { SUB_CHIP_ID1, TWL6025_BASEADD_CHARGER },
 };
 
 /*----------------------------------------------------------------------*/
@@ -487,6 +492,58 @@ EXPORT_SYMBOL(twl_i2c_read_u8);
 
 /*----------------------------------------------------------------------*/
 
+/**
+ * twl_read_idcode_register - API to read the IDCODE register.
+ *
+ * Unlocks the IDCODE register and read the 32 bit value.
+ */
+static int twl_read_idcode_register(void)
+{
+       int err;
+
+       err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, TWL_EEPROM_R_UNLOCK,
+                                               REG_UNLOCK_TEST_REG);
+       if (err) {
+               pr_err("TWL4030 Unable to unlock IDCODE registers -%d\n", err);
+               goto fail;
+       }
+
+       err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_idcode),
+                                               REG_IDCODE_7_0, 4);
+       if (err) {
+               pr_err("TWL4030: unable to read IDCODE -%d\n", err);
+               goto fail;
+       }
+
+       err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, 0x0, REG_UNLOCK_TEST_REG);
+       if (err)
+               pr_err("TWL4030 Unable to relock IDCODE registers -%d\n", err);
+fail:
+       return err;
+}
+
+/**
+ * twl_get_type - API to get TWL Si type.
+ *
+ * Api to get the TWL Si type from IDCODE value.
+ */
+int twl_get_type(void)
+{
+       return TWL_SIL_TYPE(twl_idcode);
+}
+EXPORT_SYMBOL_GPL(twl_get_type);
+
+/**
+ * twl_get_version - API to get TWL Si version.
+ *
+ * Api to get the TWL Si version from IDCODE value.
+ */
+int twl_get_version(void)
+{
+       return TWL_SIL_REV(twl_idcode);
+}
+EXPORT_SYMBOL_GPL(twl_get_version);
+
 static struct device *
 add_numbered_child(unsigned chip, const char *name, int num,
                void *pdata, unsigned pdata_len,
@@ -549,7 +606,7 @@ static inline struct device *add_child(unsigned chip, const char *name,
 static struct device *
 add_regulator_linked(int num, struct regulator_init_data *pdata,
                struct regulator_consumer_supply *consumers,
-               unsigned num_consumers)
+               unsigned num_consumers, unsigned long features)
 {
        unsigned sub_chip_id;
        /* regulator framework demands init_data ... */
@@ -561,6 +618,8 @@ add_regulator_linked(int num, struct regulator_init_data *pdata,
                pdata->num_consumer_supplies = num_consumers;
        }
 
+       pdata->driver_data = (void *)features;
+
        /* NOTE:  we currently ignore regulator IRQs, e.g. for short circuits */
        sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid;
        return add_numbered_child(sub_chip_id, "twl_reg", num,
@@ -568,9 +627,10 @@ add_regulator_linked(int num, struct regulator_init_data *pdata,
 }
 
 static struct device *
-add_regulator(int num, struct regulator_init_data *pdata)
+add_regulator(int num, struct regulator_init_data *pdata,
+               unsigned long features)
 {
-       return add_regulator_linked(num, pdata, NULL, 0);
+       return add_regulator_linked(num, pdata, NULL, 0, features);
 }
 
 /*
@@ -650,17 +710,20 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                        };
 
                        child = add_regulator_linked(TWL4030_REG_VUSB1V5,
-                                                     &usb_fixed, &usb1v5, 1);
+                                                     &usb_fixed, &usb1v5, 1,
+                                                     features);
                        if (IS_ERR(child))
                                return PTR_ERR(child);
 
                        child = add_regulator_linked(TWL4030_REG_VUSB1V8,
-                                                     &usb_fixed, &usb1v8, 1);
+                                                     &usb_fixed, &usb1v8, 1,
+                                                     features);
                        if (IS_ERR(child))
                                return PTR_ERR(child);
 
                        child = add_regulator_linked(TWL4030_REG_VUSB3V1,
-                                                     &usb_fixed, &usb3v1, 1);
+                                                     &usb_fixed, &usb3v1, 1,
+                                                     features);
                        if (IS_ERR(child))
                                return PTR_ERR(child);
 
@@ -685,9 +748,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
        }
        if (twl_has_usb() && pdata->usb && twl_class_is_6030()) {
 
-               static struct regulator_consumer_supply usb3v3 = {
-                       .supply =       "vusb",
-               };
+               static struct regulator_consumer_supply usb3v3;
+               int regulator;
 
                if (twl_has_regulator()) {
                        /* this is a template that gets copied */
@@ -700,12 +762,22 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                                        | REGULATOR_CHANGE_STATUS,
                        };
 
-                       child = add_regulator_linked(TWL6030_REG_VUSB,
-                                                     &usb_fixed, &usb3v3, 1);
+                       if (features & TWL6025_SUBCLASS) {
+                               usb3v3.supply = "ldousb";
+                               regulator = TWL6025_REG_LDOUSB;
+                       } else {
+                               usb3v3.supply = "vusb";
+                               regulator = TWL6030_REG_VUSB;
+                       }
+                       child = add_regulator_linked(regulator, &usb_fixed,
+                                                       &usb3v3, 1,
+                                                       features);
                        if (IS_ERR(child))
                                return PTR_ERR(child);
                }
 
+               pdata->usb->features = features;
+
                child = add_child(0, "twl6030_usb",
                        pdata->usb, sizeof(*pdata->usb),
                        true,
@@ -718,7 +790,16 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                /* we need to connect regulators to this transceiver */
                if (twl_has_regulator() && child)
                        usb3v3.dev = child;
+       } else if (twl_has_regulator() && twl_class_is_6030()) {
+               if (features & TWL6025_SUBCLASS)
+                       child = add_regulator(TWL6025_REG_LDOUSB,
+                                               pdata->ldousb, features);
+               else
+                       child = add_regulator(TWL6030_REG_VUSB,
+                                               pdata->vusb, features);
 
+                       if (IS_ERR(child))
+                                       return PTR_ERR(child);
        }
 
        if (twl_has_watchdog() && twl_class_is_4030()) {
@@ -755,46 +836,55 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 
        /* twl4030 regulators */
        if (twl_has_regulator() && twl_class_is_4030()) {
-               child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1);
+               child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL4030_REG_VIO, pdata->vio);
+               child = add_regulator(TWL4030_REG_VIO, pdata->vio,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1);
+               child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2);
+               child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1);
+               child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL4030_REG_VDAC, pdata->vdac);
+               child = add_regulator(TWL4030_REG_VDAC, pdata->vdac,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
                child = add_regulator((features & TWL4030_VAUX2)
                                        ? TWL4030_REG_VAUX2_4030
                                        : TWL4030_REG_VAUX2,
-                               pdata->vaux2);
+                               pdata->vaux2, features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1);
+               child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2);
+               child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig);
+               child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
@@ -802,72 +892,152 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
        /* maybe add LDOs that are omitted on cost-reduced parts */
        if (twl_has_regulator() && !(features & TPS_SUBSET)
          && twl_class_is_4030()) {
-               child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2);
+               child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2);
+               child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL4030_REG_VSIM, pdata->vsim);
+               child = add_regulator(TWL4030_REG_VSIM, pdata->vsim,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1);
+               child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3);
+               child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4);
+               child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
 
        /* twl6030 regulators */
+       if (twl_has_regulator() && twl_class_is_6030() &&
+                       !(features & TWL6025_SUBCLASS)) {
+               child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc,
+                                       features);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_VPP, pdata->vpp,
+                                       features);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim,
+                                       features);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio,
+                                       features);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_VDAC, pdata->vdac,
+                                       features);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1,
+                                       features);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2,
+                                       features);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3,
+                                       features);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg,
+                                       features);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       /* 6030 and 6025 share this regulator */
        if (twl_has_regulator() && twl_class_is_6030()) {
-               child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc);
+               child = add_regulator(TWL6030_REG_VANA, pdata->vana,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
+       }
 
-               child = add_regulator(TWL6030_REG_VPP, pdata->vpp);
+       /* twl6025 regulators */
+       if (twl_has_regulator() && twl_class_is_6030() &&
+                       (features & TWL6025_SUBCLASS)) {
+               child = add_regulator(TWL6025_REG_LDO5, pdata->ldo5,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim);
+               child = add_regulator(TWL6025_REG_LDO1, pdata->ldo1,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6030_REG_VANA, pdata->vana);
+               child = add_regulator(TWL6025_REG_LDO7, pdata->ldo7,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio);
+               child = add_regulator(TWL6025_REG_LDO6, pdata->ldo6,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6030_REG_VDAC, pdata->vdac);
+               child = add_regulator(TWL6025_REG_LDOLN, pdata->ldoln,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1);
+               child = add_regulator(TWL6025_REG_LDO2, pdata->ldo2,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2);
+               child = add_regulator(TWL6025_REG_LDO4, pdata->ldo4,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3);
+               child = add_regulator(TWL6025_REG_LDO3, pdata->ldo3,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg);
+               child = add_regulator(TWL6025_REG_SMPS3, pdata->smps3,
+                                       features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
+
+               child = add_regulator(TWL6025_REG_SMPS4, pdata->smps4,
+                                       features);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL6025_REG_VIO, pdata->vio6025,
+                                       features);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
        }
 
        if (twl_has_bci() && pdata->bci &&
@@ -1014,6 +1184,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
        unsigned                        i;
        struct twl4030_platform_data    *pdata = client->dev.platform_data;
        u8 temp;
+       int ret = 0;
 
        if (!pdata) {
                dev_dbg(&client->dev, "no platform data?\n");
@@ -1060,6 +1231,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
        /* setup clock framework */
        clocks_init(&client->dev, pdata->clock);
 
+       /* read TWL IDCODE Register */
+       if (twl_id == TWL4030_CLASS_ID) {
+               ret = twl_read_idcode_register();
+               WARN(ret < 0, "Error: reading twl_idcode register value\n");
+       }
+
        /* load power event scripts */
        if (twl_has_power() && pdata->power)
                twl4030_power_init(pdata->power);
@@ -1108,6 +1285,7 @@ static const struct i2c_device_id twl_ids[] = {
        { "tps65930", TPS_SUBSET },     /* fewer LDOs and DACs; no charger */
        { "tps65920", TPS_SUBSET },     /* fewer LDOs; no codec or charger */
        { "twl6030", TWL6030_CLASS },   /* "Phoenix power chip" */
+       { "twl6025", TWL6030_CLASS | TWL6025_SUBCLASS }, /* "Phoenix lite" */
        { /* end of list */ },
 };
 MODULE_DEVICE_TABLE(i2c, twl_ids);
index c02fded316c9f1ce1ee8fd2343b1bfb476399a9f..2bf4136464c1f30c2428638de1b7f1fddaf3b3f0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * MFD driver for twl4030 codec submodule
  *
- * Author:     Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * Copyright:   (C) 2009 Nokia Corporation
  *
@@ -208,13 +208,15 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
        if (pdata->audio) {
                cell = &codec->cells[childs];
                cell->name = "twl4030-codec";
-               cell->mfd_data = pdata->audio;
+               cell->platform_data = pdata->audio;
+               cell->pdata_size = sizeof(*pdata->audio);
                childs++;
        }
        if (pdata->vibra) {
                cell = &codec->cells[childs];
                cell->name = "twl4030-vibra";
-               cell->mfd_data = pdata->vibra;
+               cell->platform_data = pdata->vibra;
+               cell->pdata_size = sizeof(*pdata->vibra);
                childs++;
        }
 
@@ -270,6 +272,6 @@ static void __devexit twl4030_codec_exit(void)
 }
 module_exit(twl4030_codec_exit);
 
-MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@nokia.com>");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
 MODULE_LICENSE("GPL");
 
index 2c0d4d16491ab4c3ef35d881c3fb11334b25ed7d..a764676f09220146fb0ebc84addfe5e79ad9943e 100644 (file)
@@ -120,7 +120,7 @@ static u8 res_config_addrs[] = {
        [RES_HFCLKOUT]  = 0x8b,
        [RES_32KCLKOUT] = 0x8e,
        [RES_RESET]     = 0x91,
-       [RES_Main_Ref]  = 0x94,
+       [RES_MAIN_REF]  = 0x94,
 };
 
 static int __init twl4030_write_script_byte(u8 address, u8 byte)
@@ -448,7 +448,7 @@ static int __init load_twl4030_script(struct twl4030_script *tscript,
                        goto out;
        }
        if (tscript->flags & TWL4030_SLEEP_SCRIPT) {
-               if (order)
+               if (!order)
                        pr_warning("TWL4030: Bad order of scripts (sleep "\
                                        "script before wakeup) Leads to boot"\
                                        "failure on some boards\n");
@@ -485,9 +485,9 @@ int twl4030_remove_script(u8 flags)
                        return err;
        }
        if (flags & TWL4030_WAKEUP12_SCRIPT) {
-               if (err)
                err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
                                R_SEQ_ADD_S2A12);
+               if (err)
                        return err;
        }
        if (flags & TWL4030_WAKEUP3_SCRIPT) {
index dfbae34e18046c69d28f04fa502172a9346cb585..eb3b5f88e566c73e6599705649c83ec9b2758f2d 100644 (file)
@@ -76,8 +76,8 @@ static int twl6030_interrupt_mapping[24] = {
        USBOTG_INTR_OFFSET,     /* Bit 18       ID                      */
        USB_PRES_INTR_OFFSET,   /* Bit 19       VBUS                    */
        CHARGER_INTR_OFFSET,    /* Bit 20       CHRG_CTRL               */
-       CHARGER_INTR_OFFSET,    /* Bit 21       EXT_CHRG                */
-       CHARGER_INTR_OFFSET,    /* Bit 22       INT_CHRG                */
+       CHARGERFAULT_INTR_OFFSET,       /* Bit 21       EXT_CHRG        */
+       CHARGERFAULT_INTR_OFFSET,       /* Bit 22       INT_CHRG        */
        RSV_INTR_OFFSET,        /* Bit 23       Reserved                */
 };
 /*----------------------------------------------------------------------*/
index 04914f2836c0ad3d22a97d2787d789a1f34e1ae9..d97a86945174519a6d333bf0527875b63537384d 100644 (file)
@@ -153,7 +153,6 @@ out:
  */
 static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume)
 {
-       u16 val;
        int r;
 
        if (volume > WL1273_MAX_VOLUME)
@@ -217,7 +216,8 @@ static int __devinit wl1273_core_probe(struct i2c_client *client,
 
        cell = &core->cells[children];
        cell->name = "wl1273_fm_radio";
-       cell->mfd_data = &core;
+       cell->platform_data = &core;
+       cell->pdata_size = sizeof(core);
        children++;
 
        core->read = wl1273_fm_read_reg;
@@ -231,7 +231,8 @@ static int __devinit wl1273_core_probe(struct i2c_client *client,
 
                dev_dbg(&client->dev, "%s: Have codec.\n", __func__);
                cell->name = "wl1273-codec";
-               cell->mfd_data = &core;
+               cell->platform_data = &core;
+               cell->pdata_size = sizeof(core);
                children++;
        }
 
index 3fe9a58fe6c76a304a2eb61e93c375840d4b3d2d..265f75fc6a25f404a60d0954f2228585bb149938 100644 (file)
@@ -1442,7 +1442,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
        struct wm831x_pdata *pdata = wm831x->dev->platform_data;
        int rev;
        enum wm831x_parent parent;
-       int ret;
+       int ret, i;
 
        mutex_init(&wm831x->io_lock);
        mutex_init(&wm831x->key_lock);
@@ -1581,6 +1581,17 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
                }
        }
 
+       if (pdata) {
+               for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) {
+                       if (!pdata->gpio_defaults[i])
+                               continue;
+
+                       wm831x_reg_write(wm831x,
+                                        WM831X_GPIO1_CONTROL + i,
+                                        pdata->gpio_defaults[i] & 0xffff);
+               }
+       }
+
        ret = wm831x_irq_init(wm831x, irq);
        if (ret != 0)
                goto err;
index 23e66af89dea12d0871aa44fe2b824e692aee8b3..42b928ec891e6b4b2a60a6323ed5d6265659e978 100644 (file)
@@ -515,12 +515,6 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
                                 0xffff);
        }
 
-       if (!irq) {
-               dev_warn(wm831x->dev,
-                        "No interrupt specified - functionality limited\n");
-               return 0;
-       }
-
        if (!pdata || !pdata->irq_base) {
                dev_err(wm831x->dev,
                        "No interrupt base specified, no interrupts\n");
@@ -567,15 +561,22 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
 #endif
        }
 
-       ret = request_threaded_irq(irq, NULL, wm831x_irq_thread,
-                                  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-                                  "wm831x", wm831x);
-       if (ret != 0) {
-               dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n",
-                       irq, ret);
-               return ret;
+       if (irq) {
+               ret = request_threaded_irq(irq, NULL, wm831x_irq_thread,
+                                          IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                          "wm831x", wm831x);
+               if (ret != 0) {
+                       dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n",
+                               irq, ret);
+                       return ret;
+               }
+       } else {
+               dev_warn(wm831x->dev,
+                        "No interrupt specified - functionality limited\n");
        }
 
+
+
        /* Enable top level interrupts, we mask at secondary level */
        wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0);
 
index 3a6e78cb038458936e4679483ba564ac98f25936..597f82edacaa8cc010aaa2b3e28d3e5985a17f81 100644 (file)
@@ -245,7 +245,8 @@ static int wm8400_register_codec(struct wm8400 *wm8400)
 {
        struct mfd_cell cell = {
                .name = "wm8400-codec",
-               .mfd_data = wm8400,
+               .platform_data = wm8400,
+               .pdata_size = sizeof(*wm8400),
        };
 
        return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0);
index 200311fea369e6a952f38b8c205a0fb5c0c01f00..e2a52e5cf449c7f65f97e3e492a8304e321a80df 100644 (file)
@@ -609,6 +609,7 @@ static int apds990x_detect(struct apds990x_chip *chip)
        return ret;
 }
 
+#if defined(CONFIG_PM) || defined(CONFIG_PM_RUNTIME)
 static int apds990x_chip_on(struct apds990x_chip *chip)
 {
        int err  = regulator_bulk_enable(ARRAY_SIZE(chip->regs),
@@ -624,6 +625,7 @@ static int apds990x_chip_on(struct apds990x_chip *chip)
        apds990x_mode_on(chip);
        return 0;
 }
+#endif
 
 static int apds990x_chip_off(struct apds990x_chip *chip)
 {
index e01e08c8c88b6cb72e3e585fec9ccfacfe79eb2e..bc685bfc4c33aaacf89a5dc7205943bd69f14f8d 100644 (file)
@@ -174,7 +174,7 @@ struct cs5535_mfgpt_timer *cs5535_mfgpt_alloc_timer(int timer_nr, int domain)
                timer_nr = t < max ? (int) t : -1;
        } else {
                /* check if the requested timer's available */
-               if (test_bit(timer_nr, mfgpt->avail))
+               if (!test_bit(timer_nr, mfgpt->avail))
                        timer_nr = -1;
        }
 
index 74f16f167b8e1dcce5faaa41d75b1a2452f0eb5f..8cebec5e85eeb3d3c80bd998815a3e07f1a913ad 100644 (file)
@@ -285,32 +285,28 @@ static void hw_break_val_write(void)
 static int check_and_rewind_pc(char *put_str, char *arg)
 {
        unsigned long addr = lookup_addr(arg);
+       unsigned long ip;
        int offset = 0;
 
        kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs,
                 NUMREGBYTES);
        gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs);
-       v2printk("Stopped at IP: %lx\n", instruction_pointer(&kgdbts_regs));
-#ifdef CONFIG_X86
-       /* On x86 a breakpoint stop requires it to be decremented */
-       if (addr + 1 == kgdbts_regs.ip)
-               offset = -1;
-#elif defined(CONFIG_SUPERH)
-       /* On SUPERH a breakpoint stop requires it to be decremented */
-       if (addr + 2 == kgdbts_regs.pc)
-               offset = -2;
+       ip = instruction_pointer(&kgdbts_regs);
+       v2printk("Stopped at IP: %lx\n", ip);
+#ifdef GDB_ADJUSTS_BREAK_OFFSET
+       /* On some arches, a breakpoint stop requires it to be decremented */
+       if (addr + BREAK_INSTR_SIZE == ip)
+               offset = -BREAK_INSTR_SIZE;
 #endif
-       if (strcmp(arg, "silent") &&
-               instruction_pointer(&kgdbts_regs) + offset != addr) {
+       if (strcmp(arg, "silent") && ip + offset != addr) {
                eprintk("kgdbts: BP mismatch %lx expected %lx\n",
-                          instruction_pointer(&kgdbts_regs) + offset, addr);
+                          ip + offset, addr);
                return 1;
        }
-#ifdef CONFIG_X86
-       /* On x86 adjust the instruction pointer if needed */
-       kgdbts_regs.ip += offset;
-#elif defined(CONFIG_SUPERH)
-       kgdbts_regs.pc += offset;
+       /* Readjust the instruction pointer if needed */
+       ip += offset;
+#ifdef GDB_ADJUSTS_BREAK_OFFSET
+       instruction_pointer_set(&kgdbts_regs, ip);
 #endif
        return 0;
 }
index ee5109a3cd984f287c824fd71d3221ead361bccd..42f067347bc70fd8f24466ed4384408191812611 100644 (file)
@@ -495,14 +495,14 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
                }
        }
 
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
+
        if (atomic_dec_return(&queued_msg->use_count) == 0) {
                dev_kfree_skb(skb);
                kfree(queued_msg);
        }
 
-       dev->stats.tx_packets++;
-       dev->stats.tx_bytes += skb->len;
-
        return NETDEV_TX_OK;
 }
 
index 7aded90f9daa1683b7a40fa24befed62b26376da..cfbddbef11de3b67c54be85797dd124843ca8596 100644 (file)
@@ -845,7 +845,7 @@ err_iounmap:
 err_iounmap_app:
        iounmap(config->va_app_base);
 err_kzalloc:
-       kfree(config);
+       kfree(target);
 err_rel_res:
        release_mem_region(res1->start, resource_size(res1));
 err_rel_res0:
index 1a05fe08e2cb7dc4462b76d360115e725321fc7e..f91f82eabda72a311602a8979ab835e0d938ffd6 100644 (file)
@@ -747,8 +747,8 @@ static void st_tty_close(struct tty_struct *tty)
        pr_debug("%s: done ", __func__);
 }
 
-static unsigned int st_tty_receive(struct tty_struct *tty,
-               const unsigned char *data, char *tty_flags, int count)
+static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
+                          char *tty_flags, int count)
 {
 #ifdef VERBOSE
        print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE,
@@ -761,8 +761,6 @@ static unsigned int st_tty_receive(struct tty_struct *tty,
         */
        st_recv(tty->disc_data, data, count);
        pr_debug("done %s", __func__);
-
-       return count;
 }
 
 /* wake-up function called in from the TTY layer
index 61d233a7c1180e4b9fea129104ad60f631e60de2..71da5641e258e041cb9b72439d3d18eac9d9baa9 100644 (file)
 #include <linux/mutex.h>
 #include <linux/scatterlist.h>
 #include <linux/string_helpers.h>
+#include <linux/delay.h>
+#include <linux/capability.h>
+#include <linux/compat.h>
 
+#include <linux/mmc/ioctl.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
@@ -48,6 +52,13 @@ MODULE_ALIAS("mmc:block");
 #endif
 #define MODULE_PARAM_PREFIX "mmcblk."
 
+#define INAND_CMD38_ARG_EXT_CSD  113
+#define INAND_CMD38_ARG_ERASE    0x00
+#define INAND_CMD38_ARG_TRIM     0x01
+#define INAND_CMD38_ARG_SECERASE 0x80
+#define INAND_CMD38_ARG_SECTRIM1 0x81
+#define INAND_CMD38_ARG_SECTRIM2 0x88
+
 static DEFINE_MUTEX(block_mutex);
 
 /*
@@ -64,6 +75,7 @@ static int max_devices;
 
 /* 256 minors, so at most 256 separate devices */
 static DECLARE_BITMAP(dev_use, 256);
+static DECLARE_BITMAP(name_use, 256);
 
 /*
  * There is one mmc_blk_data per slot.
@@ -72,9 +84,24 @@ struct mmc_blk_data {
        spinlock_t      lock;
        struct gendisk  *disk;
        struct mmc_queue queue;
+       struct list_head part;
+
+       unsigned int    flags;
+#define MMC_BLK_CMD23  (1 << 0)        /* Can do SET_BLOCK_COUNT for multiblock */
+#define MMC_BLK_REL_WR (1 << 1)        /* MMC Reliable write support */
 
        unsigned int    usage;
        unsigned int    read_only;
+       unsigned int    part_type;
+       unsigned int    name_idx;
+
+       /*
+        * Only set in main mmc_blk_data associated
+        * with mmc_card with mmc_set_drvdata, and keeps
+        * track of the current selected device partition.
+        */
+       unsigned int    part_curr;
+       struct device_attribute force_ro;
 };
 
 static DEFINE_MUTEX(open_lock);
@@ -97,17 +124,22 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
        return md;
 }
 
+static inline int mmc_get_devidx(struct gendisk *disk)
+{
+       int devmaj = MAJOR(disk_devt(disk));
+       int devidx = MINOR(disk_devt(disk)) / perdev_minors;
+
+       if (!devmaj)
+               devidx = disk->first_minor / perdev_minors;
+       return devidx;
+}
+
 static void mmc_blk_put(struct mmc_blk_data *md)
 {
        mutex_lock(&open_lock);
        md->usage--;
        if (md->usage == 0) {
-               int devmaj = MAJOR(disk_devt(md->disk));
-               int devidx = MINOR(disk_devt(md->disk)) / perdev_minors;
-
-               if (!devmaj)
-                       devidx = md->disk->first_minor / perdev_minors;
-
+               int devidx = mmc_get_devidx(md->disk);
                blk_cleanup_queue(md->queue.queue);
 
                __clear_bit(devidx, dev_use);
@@ -118,6 +150,38 @@ static void mmc_blk_put(struct mmc_blk_data *md)
        mutex_unlock(&open_lock);
 }
 
+static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       int ret;
+       struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+
+       ret = snprintf(buf, PAGE_SIZE, "%d",
+                      get_disk_ro(dev_to_disk(dev)) ^
+                      md->read_only);
+       mmc_blk_put(md);
+       return ret;
+}
+
+static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
+                             const char *buf, size_t count)
+{
+       int ret;
+       char *end;
+       struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+       unsigned long set = simple_strtoul(buf, &end, 0);
+       if (end == buf) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       set_disk_ro(dev_to_disk(dev), set || md->read_only);
+       ret = count;
+out:
+       mmc_blk_put(md);
+       return ret;
+}
+
 static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
 {
        struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -158,35 +222,255 @@ mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        return 0;
 }
 
+struct mmc_blk_ioc_data {
+       struct mmc_ioc_cmd ic;
+       unsigned char *buf;
+       u64 buf_bytes;
+};
+
+static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
+       struct mmc_ioc_cmd __user *user)
+{
+       struct mmc_blk_ioc_data *idata;
+       int err;
+
+       idata = kzalloc(sizeof(*idata), GFP_KERNEL);
+       if (!idata) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       if (copy_from_user(&idata->ic, user, sizeof(idata->ic))) {
+               err = -EFAULT;
+               goto idata_err;
+       }
+
+       idata->buf_bytes = (u64) idata->ic.blksz * idata->ic.blocks;
+       if (idata->buf_bytes > MMC_IOC_MAX_BYTES) {
+               err = -EOVERFLOW;
+               goto idata_err;
+       }
+
+       idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL);
+       if (!idata->buf) {
+               err = -ENOMEM;
+               goto idata_err;
+       }
+
+       if (copy_from_user(idata->buf, (void __user *)(unsigned long)
+                                       idata->ic.data_ptr, idata->buf_bytes)) {
+               err = -EFAULT;
+               goto copy_err;
+       }
+
+       return idata;
+
+copy_err:
+       kfree(idata->buf);
+idata_err:
+       kfree(idata);
+out:
+       return ERR_PTR(err);
+}
+
+static int mmc_blk_ioctl_cmd(struct block_device *bdev,
+       struct mmc_ioc_cmd __user *ic_ptr)
+{
+       struct mmc_blk_ioc_data *idata;
+       struct mmc_blk_data *md;
+       struct mmc_card *card;
+       struct mmc_command cmd = {0};
+       struct mmc_data data = {0};
+       struct mmc_request mrq = {0};
+       struct scatterlist sg;
+       int err;
+
+       /*
+        * The caller must have CAP_SYS_RAWIO, and must be calling this on the
+        * whole block device, not on a partition.  This prevents overspray
+        * between sibling partitions.
+        */
+       if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
+               return -EPERM;
+
+       idata = mmc_blk_ioctl_copy_from_user(ic_ptr);
+       if (IS_ERR(idata))
+               return PTR_ERR(idata);
+
+       cmd.opcode = idata->ic.opcode;
+       cmd.arg = idata->ic.arg;
+       cmd.flags = idata->ic.flags;
+
+       data.sg = &sg;
+       data.sg_len = 1;
+       data.blksz = idata->ic.blksz;
+       data.blocks = idata->ic.blocks;
+
+       sg_init_one(data.sg, idata->buf, idata->buf_bytes);
+
+       if (idata->ic.write_flag)
+               data.flags = MMC_DATA_WRITE;
+       else
+               data.flags = MMC_DATA_READ;
+
+       mrq.cmd = &cmd;
+       mrq.data = &data;
+
+       md = mmc_blk_get(bdev->bd_disk);
+       if (!md) {
+               err = -EINVAL;
+               goto cmd_done;
+       }
+
+       card = md->queue.card;
+       if (IS_ERR(card)) {
+               err = PTR_ERR(card);
+               goto cmd_done;
+       }
+
+       mmc_claim_host(card->host);
+
+       if (idata->ic.is_acmd) {
+               err = mmc_app_cmd(card->host, card);
+               if (err)
+                       goto cmd_rel_host;
+       }
+
+       /* data.flags must already be set before doing this. */
+       mmc_set_data_timeout(&data, card);
+       /* Allow overriding the timeout_ns for empirical tuning. */
+       if (idata->ic.data_timeout_ns)
+               data.timeout_ns = idata->ic.data_timeout_ns;
+
+       if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
+               /*
+                * Pretend this is a data transfer and rely on the host driver
+                * to compute timeout.  When all host drivers support
+                * cmd.cmd_timeout for R1B, this can be changed to:
+                *
+                *     mrq.data = NULL;
+                *     cmd.cmd_timeout = idata->ic.cmd_timeout_ms;
+                */
+               data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000;
+       }
+
+       mmc_wait_for_req(card->host, &mrq);
+
+       if (cmd.error) {
+               dev_err(mmc_dev(card->host), "%s: cmd error %d\n",
+                                               __func__, cmd.error);
+               err = cmd.error;
+               goto cmd_rel_host;
+       }
+       if (data.error) {
+               dev_err(mmc_dev(card->host), "%s: data error %d\n",
+                                               __func__, data.error);
+               err = data.error;
+               goto cmd_rel_host;
+       }
+
+       /*
+        * According to the SD specs, some commands require a delay after
+        * issuing the command.
+        */
+       if (idata->ic.postsleep_min_us)
+               usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us);
+
+       if (copy_to_user(&(ic_ptr->response), cmd.resp, sizeof(cmd.resp))) {
+               err = -EFAULT;
+               goto cmd_rel_host;
+       }
+
+       if (!idata->ic.write_flag) {
+               if (copy_to_user((void __user *)(unsigned long) idata->ic.data_ptr,
+                                               idata->buf, idata->buf_bytes)) {
+                       err = -EFAULT;
+                       goto cmd_rel_host;
+               }
+       }
+
+cmd_rel_host:
+       mmc_release_host(card->host);
+
+cmd_done:
+       mmc_blk_put(md);
+       kfree(idata->buf);
+       kfree(idata);
+       return err;
+}
+
+static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
+       unsigned int cmd, unsigned long arg)
+{
+       int ret = -EINVAL;
+       if (cmd == MMC_IOC_CMD)
+               ret = mmc_blk_ioctl_cmd(bdev, (struct mmc_ioc_cmd __user *)arg);
+       return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static int mmc_blk_compat_ioctl(struct block_device *bdev, fmode_t mode,
+       unsigned int cmd, unsigned long arg)
+{
+       return mmc_blk_ioctl(bdev, mode, cmd, (unsigned long) compat_ptr(arg));
+}
+#endif
+
 static const struct block_device_operations mmc_bdops = {
        .open                   = mmc_blk_open,
        .release                = mmc_blk_release,
        .getgeo                 = mmc_blk_getgeo,
        .owner                  = THIS_MODULE,
+       .ioctl                  = mmc_blk_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl           = mmc_blk_compat_ioctl,
+#endif
 };
 
 struct mmc_blk_request {
        struct mmc_request      mrq;
+       struct mmc_command      sbc;
        struct mmc_command      cmd;
        struct mmc_command      stop;
        struct mmc_data         data;
 };
 
+static inline int mmc_blk_part_switch(struct mmc_card *card,
+                                     struct mmc_blk_data *md)
+{
+       int ret;
+       struct mmc_blk_data *main_md = mmc_get_drvdata(card);
+       if (main_md->part_curr == md->part_type)
+               return 0;
+
+       if (mmc_card_mmc(card)) {
+               card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+               card->ext_csd.part_config |= md->part_type;
+
+               ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                EXT_CSD_PART_CONFIG, card->ext_csd.part_config,
+                                card->ext_csd.part_time);
+               if (ret)
+                       return ret;
+}
+
+       main_md->part_curr = md->part_type;
+       return 0;
+}
+
 static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
 {
        int err;
        u32 result;
        __be32 *blocks;
 
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_data data = {0};
        unsigned int timeout_us;
 
        struct scatterlist sg;
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_APP_CMD;
        cmd.arg = card->rca << 16;
        cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
@@ -203,8 +487,6 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
        cmd.arg = 0;
        cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
 
-       memset(&data, 0, sizeof(struct mmc_data));
-
        data.timeout_ns = card->csd.tacc_ns * 100;
        data.timeout_clks = card->csd.tacc_clks * 100;
 
@@ -223,8 +505,6 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
        data.sg = &sg;
        data.sg_len = 1;
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
 
@@ -247,10 +527,9 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
 
 static u32 get_card_status(struct mmc_card *card, struct request *req)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        int err;
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
        cmd.opcode = MMC_SEND_STATUS;
        if (!mmc_host_is_spi(card->host))
                cmd.arg = card->rca << 16;
@@ -269,8 +548,6 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
        unsigned int from, nr, arg;
        int err = 0;
 
-       mmc_claim_host(card->host);
-
        if (!mmc_can_erase(card)) {
                err = -EOPNOTSUPP;
                goto out;
@@ -284,14 +561,22 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
        else
                arg = MMC_ERASE_ARG;
 
+       if (card->quirks & MMC_QUIRK_INAND_CMD38) {
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                INAND_CMD38_ARG_EXT_CSD,
+                                arg == MMC_TRIM_ARG ?
+                                INAND_CMD38_ARG_TRIM :
+                                INAND_CMD38_ARG_ERASE,
+                                0);
+               if (err)
+                       goto out;
+       }
        err = mmc_erase(card, from, nr, arg);
 out:
        spin_lock_irq(&md->lock);
        __blk_end_request(req, err, blk_rq_bytes(req));
        spin_unlock_irq(&md->lock);
 
-       mmc_release_host(card->host);
-
        return err ? 0 : 1;
 }
 
@@ -303,8 +588,6 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
        unsigned int from, nr, arg;
        int err = 0;
 
-       mmc_claim_host(card->host);
-
        if (!mmc_can_secure_erase_trim(card)) {
                err = -EOPNOTSUPP;
                goto out;
@@ -318,19 +601,74 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
        else
                arg = MMC_SECURE_ERASE_ARG;
 
+       if (card->quirks & MMC_QUIRK_INAND_CMD38) {
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                INAND_CMD38_ARG_EXT_CSD,
+                                arg == MMC_SECURE_TRIM1_ARG ?
+                                INAND_CMD38_ARG_SECTRIM1 :
+                                INAND_CMD38_ARG_SECERASE,
+                                0);
+               if (err)
+                       goto out;
+       }
        err = mmc_erase(card, from, nr, arg);
-       if (!err && arg == MMC_SECURE_TRIM1_ARG)
+       if (!err && arg == MMC_SECURE_TRIM1_ARG) {
+               if (card->quirks & MMC_QUIRK_INAND_CMD38) {
+                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                        INAND_CMD38_ARG_EXT_CSD,
+                                        INAND_CMD38_ARG_SECTRIM2,
+                                        0);
+                       if (err)
+                               goto out;
+               }
                err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG);
+       }
 out:
        spin_lock_irq(&md->lock);
        __blk_end_request(req, err, blk_rq_bytes(req));
        spin_unlock_irq(&md->lock);
 
-       mmc_release_host(card->host);
-
        return err ? 0 : 1;
 }
 
+static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
+{
+       struct mmc_blk_data *md = mq->data;
+
+       /*
+        * No-op, only service this because we need REQ_FUA for reliable
+        * writes.
+        */
+       spin_lock_irq(&md->lock);
+       __blk_end_request_all(req, 0);
+       spin_unlock_irq(&md->lock);
+
+       return 1;
+}
+
+/*
+ * Reformat current write as a reliable write, supporting
+ * both legacy and the enhanced reliable write MMC cards.
+ * In each transfer we'll handle only as much as a single
+ * reliable write can handle, thus finish the request in
+ * partial completions.
+ */
+static inline void mmc_apply_rel_rw(struct mmc_blk_request *brq,
+                                   struct mmc_card *card,
+                                   struct request *req)
+{
+       if (!(card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN)) {
+               /* Legacy mode imposes restrictions on transfers. */
+               if (!IS_ALIGNED(brq->cmd.arg, card->ext_csd.rel_sectors))
+                       brq->data.blocks = 1;
+
+               if (brq->data.blocks > card->ext_csd.rel_sectors)
+                       brq->data.blocks = card->ext_csd.rel_sectors;
+               else if (brq->data.blocks < card->ext_csd.rel_sectors)
+                       brq->data.blocks = 1;
+       }
+}
+
 static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 {
        struct mmc_blk_data *md = mq->data;
@@ -338,10 +676,17 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
        struct mmc_blk_request brq;
        int ret = 1, disable_multi = 0;
 
-       mmc_claim_host(card->host);
+       /*
+        * Reliable writes are used to implement Forced Unit Access and
+        * REQ_META accesses, and are supported only on MMCs.
+        */
+       bool do_rel_wr = ((req->cmd_flags & REQ_FUA) ||
+                         (req->cmd_flags & REQ_META)) &&
+               (rq_data_dir(req) == WRITE) &&
+               (md->flags & MMC_BLK_REL_WR);
 
        do {
-               struct mmc_command cmd;
+               struct mmc_command cmd = {0};
                u32 readcmd, writecmd, status = 0;
 
                memset(&brq, 0, sizeof(struct mmc_blk_request));
@@ -374,12 +719,12 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
                if (disable_multi && brq.data.blocks > 1)
                        brq.data.blocks = 1;
 
-               if (brq.data.blocks > 1) {
+               if (brq.data.blocks > 1 || do_rel_wr) {
                        /* SPI multiblock writes terminate using a special
                         * token, not a STOP_TRANSMISSION request.
                         */
-                       if (!mmc_host_is_spi(card->host)
-                                       || rq_data_dir(req) == READ)
+                       if (!mmc_host_is_spi(card->host) ||
+                           rq_data_dir(req) == READ)
                                brq.mrq.stop = &brq.stop;
                        readcmd = MMC_READ_MULTIPLE_BLOCK;
                        writecmd = MMC_WRITE_MULTIPLE_BLOCK;
@@ -396,6 +741,38 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
                        brq.data.flags |= MMC_DATA_WRITE;
                }
 
+               if (do_rel_wr)
+                       mmc_apply_rel_rw(&brq, card, req);
+
+               /*
+                * Pre-defined multi-block transfers are preferable to
+                * open ended-ones (and necessary for reliable writes).
+                * However, it is not sufficient to just send CMD23,
+                * and avoid the final CMD12, as on an error condition
+                * CMD12 (stop) needs to be sent anyway. This, coupled
+                * with Auto-CMD23 enhancements provided by some
+                * hosts, means that the complexity of dealing
+                * with this is best left to the host. If CMD23 is
+                * supported by card and host, we'll fill sbc in and let
+                * the host deal with handling it correctly. This means
+                * that for hosts that don't expose MMC_CAP_CMD23, no
+                * change of behavior will be observed.
+                *
+                * N.B: Some MMC cards experience perf degradation.
+                * We'll avoid using CMD23-bounded multiblock writes for
+                * these, while retaining features like reliable writes.
+                */
+
+               if ((md->flags & MMC_BLK_CMD23) &&
+                   mmc_op_multi(brq.cmd.opcode) &&
+                   (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23))) {
+                       brq.sbc.opcode = MMC_SET_BLOCK_COUNT;
+                       brq.sbc.arg = brq.data.blocks |
+                               (do_rel_wr ? (1 << 31) : 0);
+                       brq.sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
+                       brq.mrq.sbc = &brq.sbc;
+               }
+
                mmc_set_data_timeout(&brq.data, card);
 
                brq.data.sg = mq->sg;
@@ -431,7 +808,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
                 * until later as we need to wait for the card to leave
                 * programming mode even when things go wrong.
                 */
-               if (brq.cmd.error || brq.data.error || brq.stop.error) {
+               if (brq.sbc.error || brq.cmd.error ||
+                   brq.data.error || brq.stop.error) {
                        if (brq.data.blocks > 1 && rq_data_dir(req) == READ) {
                                /* Redo read one sector at a time */
                                printk(KERN_WARNING "%s: retrying using single "
@@ -442,6 +820,13 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
                        status = get_card_status(card, req);
                }
 
+               if (brq.sbc.error) {
+                       printk(KERN_ERR "%s: error %d sending SET_BLOCK_COUNT "
+                              "command, response %#x, card status %#x\n",
+                              req->rq_disk->disk_name, brq.sbc.error,
+                              brq.sbc.resp[0], status);
+               }
+
                if (brq.cmd.error) {
                        printk(KERN_ERR "%s: error %d sending read/write "
                               "command, response %#x, card status %#x\n",
@@ -520,8 +905,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
                spin_unlock_irq(&md->lock);
        } while (ret);
 
-       mmc_release_host(card->host);
-
        return 1;
 
  cmd_err:
@@ -548,8 +931,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
                spin_unlock_irq(&md->lock);
        }
 
-       mmc_release_host(card->host);
-
        spin_lock_irq(&md->lock);
        while (ret)
                ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
@@ -560,14 +941,31 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 
 static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 {
+       int ret;
+       struct mmc_blk_data *md = mq->data;
+       struct mmc_card *card = md->queue.card;
+
+       mmc_claim_host(card->host);
+       ret = mmc_blk_part_switch(card, md);
+       if (ret) {
+               ret = 0;
+               goto out;
+       }
+
        if (req->cmd_flags & REQ_DISCARD) {
                if (req->cmd_flags & REQ_SECURE)
-                       return mmc_blk_issue_secdiscard_rq(mq, req);
+                       ret = mmc_blk_issue_secdiscard_rq(mq, req);
                else
-                       return mmc_blk_issue_discard_rq(mq, req);
+                       ret = mmc_blk_issue_discard_rq(mq, req);
+       } else if (req->cmd_flags & REQ_FLUSH) {
+               ret = mmc_blk_issue_flush(mq, req);
        } else {
-               return mmc_blk_issue_rw_rq(mq, req);
+               ret = mmc_blk_issue_rw_rq(mq, req);
        }
+
+out:
+       mmc_release_host(card->host);
+       return ret;
 }
 
 static inline int mmc_blk_readonly(struct mmc_card *card)
@@ -576,7 +974,11 @@ static inline int mmc_blk_readonly(struct mmc_card *card)
               !(card->csd.cmdclass & CCC_BLOCK_WRITE);
 }
 
-static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+                                             struct device *parent,
+                                             sector_t size,
+                                             bool default_ro,
+                                             const char *subname)
 {
        struct mmc_blk_data *md;
        int devidx, ret;
@@ -592,6 +994,19 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
                goto out;
        }
 
+       /*
+        * !subname implies we are creating main mmc_blk_data that will be
+        * associated with mmc_card with mmc_set_drvdata. Due to device
+        * partitions, devidx will not coincide with a per-physical card
+        * index anymore so we keep track of a name index.
+        */
+       if (!subname) {
+               md->name_idx = find_first_zero_bit(name_use, max_devices);
+               __set_bit(md->name_idx, name_use);
+       }
+       else
+               md->name_idx = ((struct mmc_blk_data *)
+                               dev_to_disk(parent)->private_data)->name_idx;
 
        /*
         * Set the read-only status based on the supported commands
@@ -606,6 +1021,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
        }
 
        spin_lock_init(&md->lock);
+       INIT_LIST_HEAD(&md->part);
        md->usage = 1;
 
        ret = mmc_init_queue(&md->queue, card, &md->lock);
@@ -620,8 +1036,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
        md->disk->fops = &mmc_bdops;
        md->disk->private_data = md;
        md->disk->queue = md->queue.queue;
-       md->disk->driverfs_dev = &card->dev;
-       set_disk_ro(md->disk, md->read_only);
+       md->disk->driverfs_dev = parent;
+       set_disk_ro(md->disk, md->read_only || default_ro);
 
        /*
         * As discussed on lkml, GENHD_FL_REMOVABLE should:
@@ -636,32 +1052,107 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
         */
 
        snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
-               "mmcblk%d", devidx);
+                "mmcblk%d%s", md->name_idx, subname ? subname : "");
 
        blk_queue_logical_block_size(md->queue.queue, 512);
+       set_capacity(md->disk, size);
+
+       if (mmc_host_cmd23(card->host)) {
+               if (mmc_card_mmc(card) ||
+                   (mmc_card_sd(card) &&
+                    card->scr.cmds & SD_SCR_CMD23_SUPPORT))
+                       md->flags |= MMC_BLK_CMD23;
+       }
+
+       if (mmc_card_mmc(card) &&
+           md->flags & MMC_BLK_CMD23 &&
+           ((card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN) ||
+            card->ext_csd.rel_sectors)) {
+               md->flags |= MMC_BLK_REL_WR;
+               blk_queue_flush(md->queue.queue, REQ_FLUSH | REQ_FUA);
+       }
+
+       return md;
+
+ err_putdisk:
+       put_disk(md->disk);
+ err_kfree:
+       kfree(md);
+ out:
+       return ERR_PTR(ret);
+}
+
+static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+{
+       sector_t size;
+       struct mmc_blk_data *md;
 
        if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
                /*
                 * The EXT_CSD sector count is in number or 512 byte
                 * sectors.
                 */
-               set_capacity(md->disk, card->ext_csd.sectors);
+               size = card->ext_csd.sectors;
        } else {
                /*
                 * The CSD capacity field is in units of read_blkbits.
                 * set_capacity takes units of 512 bytes.
                 */
-               set_capacity(md->disk,
-                       card->csd.capacity << (card->csd.read_blkbits - 9));
+               size = card->csd.capacity << (card->csd.read_blkbits - 9);
        }
+
+       md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL);
        return md;
+}
 
- err_putdisk:
-       put_disk(md->disk);
- err_kfree:
-       kfree(md);
- out:
-       return ERR_PTR(ret);
+static int mmc_blk_alloc_part(struct mmc_card *card,
+                             struct mmc_blk_data *md,
+                             unsigned int part_type,
+                             sector_t size,
+                             bool default_ro,
+                             const char *subname)
+{
+       char cap_str[10];
+       struct mmc_blk_data *part_md;
+
+       part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro,
+                                   subname);
+       if (IS_ERR(part_md))
+               return PTR_ERR(part_md);
+       part_md->part_type = part_type;
+       list_add(&part_md->part, &md->part);
+
+       string_get_size((u64)get_capacity(part_md->disk) << 9, STRING_UNITS_2,
+                       cap_str, sizeof(cap_str));
+       printk(KERN_INFO "%s: %s %s partition %u %s\n",
+              part_md->disk->disk_name, mmc_card_id(card),
+              mmc_card_name(card), part_md->part_type, cap_str);
+       return 0;
+}
+
+static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
+{
+       int ret = 0;
+
+       if (!mmc_card_mmc(card))
+               return 0;
+
+       if (card->ext_csd.boot_size) {
+               ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT0,
+                                        card->ext_csd.boot_size >> 9,
+                                        true,
+                                        "boot0");
+               if (ret)
+                       return ret;
+               ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT1,
+                                        card->ext_csd.boot_size >> 9,
+                                        true,
+                                        "boot1");
+               if (ret)
+                       return ret;
+       }
+
+       return ret;
 }
 
 static int
@@ -682,9 +1173,81 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
        return 0;
 }
 
+static void mmc_blk_remove_req(struct mmc_blk_data *md)
+{
+       if (md) {
+               if (md->disk->flags & GENHD_FL_UP) {
+                       device_remove_file(disk_to_dev(md->disk), &md->force_ro);
+
+                       /* Stop new requests from getting into the queue */
+                       del_gendisk(md->disk);
+               }
+
+               /* Then flush out any already in there */
+               mmc_cleanup_queue(&md->queue);
+               mmc_blk_put(md);
+       }
+}
+
+static void mmc_blk_remove_parts(struct mmc_card *card,
+                                struct mmc_blk_data *md)
+{
+       struct list_head *pos, *q;
+       struct mmc_blk_data *part_md;
+
+       __clear_bit(md->name_idx, name_use);
+       list_for_each_safe(pos, q, &md->part) {
+               part_md = list_entry(pos, struct mmc_blk_data, part);
+               list_del(pos);
+               mmc_blk_remove_req(part_md);
+       }
+}
+
+static int mmc_add_disk(struct mmc_blk_data *md)
+{
+       int ret;
+
+       add_disk(md->disk);
+       md->force_ro.show = force_ro_show;
+       md->force_ro.store = force_ro_store;
+       sysfs_attr_init(&md->force_ro.attr);
+       md->force_ro.attr.name = "force_ro";
+       md->force_ro.attr.mode = S_IRUGO | S_IWUSR;
+       ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
+       if (ret)
+               del_gendisk(md->disk);
+
+       return ret;
+}
+
+static const struct mmc_fixup blk_fixups[] =
+{
+       MMC_FIXUP("SEM02G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM04G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM08G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM16G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM32G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+
+       /*
+        * Some MMC cards experience performance degradation with CMD23
+        * instead of CMD12-bounded multiblock transfers. For now we'll
+        * black list what's bad...
+        * - Certain Toshiba cards.
+        *
+        * N.B. This doesn't affect SD cards.
+        */
+       MMC_FIXUP("MMC08G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_BLK_NO_CMD23),
+       MMC_FIXUP("MMC16G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_BLK_NO_CMD23),
+       MMC_FIXUP("MMC32G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_BLK_NO_CMD23),
+       END_FIXUP
+};
+
 static int mmc_blk_probe(struct mmc_card *card)
 {
-       struct mmc_blk_data *md;
+       struct mmc_blk_data *md, *part_md;
        int err;
        char cap_str[10];
 
@@ -708,14 +1271,24 @@ static int mmc_blk_probe(struct mmc_card *card)
                md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
                cap_str, md->read_only ? "(ro)" : "");
 
+       if (mmc_blk_alloc_parts(card, md))
+               goto out;
+
        mmc_set_drvdata(card, md);
-       add_disk(md->disk);
+       mmc_fixup_device(card, blk_fixups);
+
+       if (mmc_add_disk(md))
+               goto out;
+
+       list_for_each_entry(part_md, &md->part, part) {
+               if (mmc_add_disk(part_md))
+                       goto out;
+       }
        return 0;
 
  out:
-       mmc_cleanup_queue(&md->queue);
-       mmc_blk_put(md);
-
+       mmc_blk_remove_parts(card, md);
+       mmc_blk_remove_req(md);
        return err;
 }
 
@@ -723,36 +1296,43 @@ static void mmc_blk_remove(struct mmc_card *card)
 {
        struct mmc_blk_data *md = mmc_get_drvdata(card);
 
-       if (md) {
-               /* Stop new requests from getting into the queue */
-               del_gendisk(md->disk);
-
-               /* Then flush out any already in there */
-               mmc_cleanup_queue(&md->queue);
-
-               mmc_blk_put(md);
-       }
+       mmc_blk_remove_parts(card, md);
+       mmc_blk_remove_req(md);
        mmc_set_drvdata(card, NULL);
 }
 
 #ifdef CONFIG_PM
 static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
 {
+       struct mmc_blk_data *part_md;
        struct mmc_blk_data *md = mmc_get_drvdata(card);
 
        if (md) {
                mmc_queue_suspend(&md->queue);
+               list_for_each_entry(part_md, &md->part, part) {
+                       mmc_queue_suspend(&part_md->queue);
+               }
        }
        return 0;
 }
 
 static int mmc_blk_resume(struct mmc_card *card)
 {
+       struct mmc_blk_data *part_md;
        struct mmc_blk_data *md = mmc_get_drvdata(card);
 
        if (md) {
                mmc_blk_set_blksize(md, card);
+
+               /*
+                * Resume involves the card going into idle state,
+                * so current partition is always the main one.
+                */
+               md->part_curr = md->part_type;
                mmc_queue_resume(&md->queue);
+               list_for_each_entry(part_md, &md->part, part) {
+                       mmc_queue_resume(&part_md->queue);
+               }
        }
        return 0;
 }
index abc1a63bcc5ee9f0ceb1c76ded78fda2b4fd5f97..233cdfae92f4bdff7c814737ad2c6a4a4dd1c26e 100644 (file)
@@ -212,7 +212,7 @@ static int mmc_test_busy(struct mmc_command *cmd)
 static int mmc_test_wait_busy(struct mmc_test_card *test)
 {
        int ret, busy;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        busy = 0;
        do {
@@ -246,18 +246,13 @@ static int mmc_test_buffer_transfer(struct mmc_test_card *test,
 {
        int ret;
 
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_command stop;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_command stop = {0};
+       struct mmc_data data = {0};
 
        struct scatterlist sg;
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-       memset(&stop, 0, sizeof(struct mmc_command));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
        mrq.stop = &stop;
@@ -731,15 +726,10 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test,
        struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
        unsigned blocks, unsigned blksz, int write)
 {
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_command stop;
-       struct mmc_data data;
-
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-       memset(&stop, 0, sizeof(struct mmc_command));
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_command stop = {0};
+       struct mmc_data data = {0};
 
        mrq.cmd = &cmd;
        mrq.data = &data;
@@ -761,18 +751,13 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test,
 static int mmc_test_broken_transfer(struct mmc_test_card *test,
        unsigned blocks, unsigned blksz, int write)
 {
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_command stop;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_command stop = {0};
+       struct mmc_data data = {0};
 
        struct scatterlist sg;
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-       memset(&stop, 0, sizeof(struct mmc_command));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
        mrq.stop = &stop;
@@ -1401,8 +1386,9 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
  */
 static int mmc_test_area_fill(struct mmc_test_card *test)
 {
-       return mmc_test_area_io(test, test->area.max_tfr, test->area.dev_addr,
-                               1, 0, 0);
+       struct mmc_test_area *t = &test->area;
+
+       return mmc_test_area_io(test, t->max_tfr, t->dev_addr, 1, 0, 0);
 }
 
 /*
@@ -1415,7 +1401,7 @@ static int mmc_test_area_erase(struct mmc_test_card *test)
        if (!mmc_can_erase(test->card))
                return 0;
 
-       return mmc_erase(test->card, t->dev_addr, test->area.max_sz >> 9,
+       return mmc_erase(test->card, t->dev_addr, t->max_sz >> 9,
                         MMC_ERASE_ARG);
 }
 
@@ -1542,8 +1528,10 @@ static int mmc_test_area_prepare_fill(struct mmc_test_card *test)
 static int mmc_test_best_performance(struct mmc_test_card *test, int write,
                                     int max_scatter)
 {
-       return mmc_test_area_io(test, test->area.max_tfr, test->area.dev_addr,
-                               write, max_scatter, 1);
+       struct mmc_test_area *t = &test->area;
+
+       return mmc_test_area_io(test, t->max_tfr, t->dev_addr, write,
+                               max_scatter, 1);
 }
 
 /*
@@ -1583,18 +1571,19 @@ static int mmc_test_best_write_perf_max_scatter(struct mmc_test_card *test)
  */
 static int mmc_test_profile_read_perf(struct mmc_test_card *test)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned long sz;
        unsigned int dev_addr;
        int ret;
 
-       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
-               dev_addr = test->area.dev_addr + (sz >> 9);
+       for (sz = 512; sz < t->max_tfr; sz <<= 1) {
+               dev_addr = t->dev_addr + (sz >> 9);
                ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
                if (ret)
                        return ret;
        }
-       sz = test->area.max_tfr;
-       dev_addr = test->area.dev_addr;
+       sz = t->max_tfr;
+       dev_addr = t->dev_addr;
        return mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
 }
 
@@ -1603,6 +1592,7 @@ static int mmc_test_profile_read_perf(struct mmc_test_card *test)
  */
 static int mmc_test_profile_write_perf(struct mmc_test_card *test)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned long sz;
        unsigned int dev_addr;
        int ret;
@@ -1610,8 +1600,8 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
        ret = mmc_test_area_erase(test);
        if (ret)
                return ret;
-       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
-               dev_addr = test->area.dev_addr + (sz >> 9);
+       for (sz = 512; sz < t->max_tfr; sz <<= 1) {
+               dev_addr = t->dev_addr + (sz >> 9);
                ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
                if (ret)
                        return ret;
@@ -1619,8 +1609,8 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
        ret = mmc_test_area_erase(test);
        if (ret)
                return ret;
-       sz = test->area.max_tfr;
-       dev_addr = test->area.dev_addr;
+       sz = t->max_tfr;
+       dev_addr = t->dev_addr;
        return mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
 }
 
@@ -1629,6 +1619,7 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
  */
 static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned long sz;
        unsigned int dev_addr;
        struct timespec ts1, ts2;
@@ -1640,8 +1631,8 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
        if (!mmc_can_erase(test->card))
                return RESULT_UNSUP_HOST;
 
-       for (sz = 512; sz < test->area.max_sz; sz <<= 1) {
-               dev_addr = test->area.dev_addr + (sz >> 9);
+       for (sz = 512; sz < t->max_sz; sz <<= 1) {
+               dev_addr = t->dev_addr + (sz >> 9);
                getnstimeofday(&ts1);
                ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG);
                if (ret)
@@ -1649,7 +1640,7 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
                getnstimeofday(&ts2);
                mmc_test_print_rate(test, sz, &ts1, &ts2);
        }
-       dev_addr = test->area.dev_addr;
+       dev_addr = t->dev_addr;
        getnstimeofday(&ts1);
        ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG);
        if (ret)
@@ -1661,12 +1652,13 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
 
 static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned int dev_addr, i, cnt;
        struct timespec ts1, ts2;
        int ret;
 
-       cnt = test->area.max_sz / sz;
-       dev_addr = test->area.dev_addr;
+       cnt = t->max_sz / sz;
+       dev_addr = t->dev_addr;
        getnstimeofday(&ts1);
        for (i = 0; i < cnt; i++) {
                ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0);
@@ -1684,20 +1676,22 @@ static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz)
  */
 static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned long sz;
        int ret;
 
-       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
+       for (sz = 512; sz < t->max_tfr; sz <<= 1) {
                ret = mmc_test_seq_read_perf(test, sz);
                if (ret)
                        return ret;
        }
-       sz = test->area.max_tfr;
+       sz = t->max_tfr;
        return mmc_test_seq_read_perf(test, sz);
 }
 
 static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned int dev_addr, i, cnt;
        struct timespec ts1, ts2;
        int ret;
@@ -1705,8 +1699,8 @@ static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
        ret = mmc_test_area_erase(test);
        if (ret)
                return ret;
-       cnt = test->area.max_sz / sz;
-       dev_addr = test->area.dev_addr;
+       cnt = t->max_sz / sz;
+       dev_addr = t->dev_addr;
        getnstimeofday(&ts1);
        for (i = 0; i < cnt; i++) {
                ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0);
@@ -1724,15 +1718,16 @@ static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
  */
 static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned long sz;
        int ret;
 
-       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
+       for (sz = 512; sz < t->max_tfr; sz <<= 1) {
                ret = mmc_test_seq_write_perf(test, sz);
                if (ret)
                        return ret;
        }
-       sz = test->area.max_tfr;
+       sz = t->max_tfr;
        return mmc_test_seq_write_perf(test, sz);
 }
 
@@ -1741,6 +1736,7 @@ static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
  */
 static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned long sz;
        unsigned int dev_addr, i, cnt;
        struct timespec ts1, ts2;
@@ -1752,15 +1748,15 @@ static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test)
        if (!mmc_can_erase(test->card))
                return RESULT_UNSUP_HOST;
 
-       for (sz = 512; sz <= test->area.max_sz; sz <<= 1) {
+       for (sz = 512; sz <= t->max_sz; sz <<= 1) {
                ret = mmc_test_area_erase(test);
                if (ret)
                        return ret;
                ret = mmc_test_area_fill(test);
                if (ret)
                        return ret;
-               cnt = test->area.max_sz / sz;
-               dev_addr = test->area.dev_addr;
+               cnt = t->max_sz / sz;
+               dev_addr = t->dev_addr;
                getnstimeofday(&ts1);
                for (i = 0; i < cnt; i++) {
                        ret = mmc_erase(test->card, dev_addr, sz >> 9,
@@ -1823,11 +1819,12 @@ static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print,
 
 static int mmc_test_random_perf(struct mmc_test_card *test, int write)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned int next;
        unsigned long sz;
        int ret;
 
-       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
+       for (sz = 512; sz < t->max_tfr; sz <<= 1) {
                /*
                 * When writing, try to get more consistent results by running
                 * the test twice with exactly the same I/O but outputting the
@@ -1844,7 +1841,7 @@ static int mmc_test_random_perf(struct mmc_test_card *test, int write)
                if (ret)
                        return ret;
        }
-       sz = test->area.max_tfr;
+       sz = t->max_tfr;
        if (write) {
                next = rnd_next;
                ret = mmc_test_rnd_perf(test, write, 0, sz);
@@ -1874,17 +1871,18 @@ static int mmc_test_random_write_perf(struct mmc_test_card *test)
 static int mmc_test_seq_perf(struct mmc_test_card *test, int write,
                             unsigned int tot_sz, int max_scatter)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned int dev_addr, i, cnt, sz, ssz;
        struct timespec ts1, ts2;
        int ret;
 
-       sz = test->area.max_tfr;
+       sz = t->max_tfr;
+
        /*
         * In the case of a maximally scattered transfer, the maximum transfer
         * size is further limited by using PAGE_SIZE segments.
         */
        if (max_scatter) {
-               struct mmc_test_area *t = &test->area;
                unsigned long max_tfr;
 
                if (t->max_seg_sz >= PAGE_SIZE)
index 2ae727568df92b9edeaf330ea46751d6e0493474..c07322c2658cd171049bf59d4325f2e04ae2a90c 100644 (file)
@@ -343,18 +343,14 @@ unsigned int mmc_queue_map_sg(struct mmc_queue *mq)
  */
 void mmc_queue_bounce_pre(struct mmc_queue *mq)
 {
-       unsigned long flags;
-
        if (!mq->bounce_buf)
                return;
 
        if (rq_data_dir(mq->req) != WRITE)
                return;
 
-       local_irq_save(flags);
        sg_copy_to_buffer(mq->bounce_sg, mq->bounce_sg_len,
                mq->bounce_buf, mq->sg[0].length);
-       local_irq_restore(flags);
 }
 
 /*
@@ -363,17 +359,13 @@ void mmc_queue_bounce_pre(struct mmc_queue *mq)
  */
 void mmc_queue_bounce_post(struct mmc_queue *mq)
 {
-       unsigned long flags;
-
        if (!mq->bounce_buf)
                return;
 
        if (rq_data_dir(mq->req) != READ)
                return;
 
-       local_irq_save(flags);
        sg_copy_from_buffer(mq->bounce_sg, mq->bounce_sg_len,
                mq->bounce_buf, mq->sg[0].length);
-       local_irq_restore(flags);
 }
 
index d6d62fd07ee9fd0b492d6c7e0a80d116840009b2..393d817ed04076dca934511f4522b698776073ae 100644 (file)
@@ -274,8 +274,12 @@ int mmc_add_card(struct mmc_card *card)
                break;
        case MMC_TYPE_SD:
                type = "SD";
-               if (mmc_card_blockaddr(card))
-                       type = "SDHC";
+               if (mmc_card_blockaddr(card)) {
+                       if (mmc_card_ext_capacity(card))
+                               type = "SDXC";
+                       else
+                               type = "SDHC";
+               }
                break;
        case MMC_TYPE_SDIO:
                type = "SDIO";
@@ -299,7 +303,8 @@ int mmc_add_card(struct mmc_card *card)
        } else {
                printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
                        mmc_hostname(card->host),
-                       mmc_card_highspeed(card) ? "high speed " : "",
+                       mmc_sd_card_uhs(card) ? "ultra high speed " :
+                       (mmc_card_highspeed(card) ? "high speed " : ""),
                        mmc_card_ddr_mode(card) ? "DDR " : "",
                        type, card->rca);
        }
index 1f453acc8682b8f828b4f6c9574f2b0f6e1ff7f9..68091dda3f31f49ab9d7130cbad178e93d5ca1c8 100644 (file)
@@ -236,12 +236,10 @@ EXPORT_SYMBOL(mmc_wait_for_req);
  */
 int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
 {
-       struct mmc_request mrq;
+       struct mmc_request mrq = {0};
 
        WARN_ON(!host->claimed);
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-
        memset(cmd->resp, 0, sizeof(cmd->resp));
        cmd->retries = retries;
 
@@ -719,23 +717,13 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
        mmc_set_ios(host);
 }
 
-/*
- * Change data bus width and DDR mode of a host.
- */
-void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
-                          unsigned int ddr)
-{
-       host->ios.bus_width = width;
-       host->ios.ddr = ddr;
-       mmc_set_ios(host);
-}
-
 /*
  * Change data bus width of a host.
  */
 void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
 {
-       mmc_set_bus_width_ddr(host, width, MMC_SDR_MODE);
+       host->ios.bus_width = width;
+       mmc_set_ios(host);
 }
 
 /**
@@ -944,6 +932,38 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
        return ocr;
 }
 
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11)
+{
+       struct mmc_command cmd = {0};
+       int err = 0;
+
+       BUG_ON(!host);
+
+       /*
+        * Send CMD11 only if the request is to switch the card to
+        * 1.8V signalling.
+        */
+       if ((signal_voltage != MMC_SIGNAL_VOLTAGE_330) && cmd11) {
+               cmd.opcode = SD_SWITCH_VOLTAGE;
+               cmd.arg = 0;
+               cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+               err = mmc_wait_for_cmd(host, &cmd, 0);
+               if (err)
+                       return err;
+
+               if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
+                       return -EIO;
+       }
+
+       host->ios.signal_voltage = signal_voltage;
+
+       if (host->ops->start_signal_voltage_switch)
+               err = host->ops->start_signal_voltage_switch(host, &host->ios);
+
+       return err;
+}
+
 /*
  * Select timing parameters for host.
  */
@@ -953,6 +973,15 @@ void mmc_set_timing(struct mmc_host *host, unsigned int timing)
        mmc_set_ios(host);
 }
 
+/*
+ * Select appropriate driver type for host.
+ */
+void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
+{
+       host->ios.drv_type = drv_type;
+       mmc_set_ios(host);
+}
+
 /*
  * Apply power to the MMC stack.  This is a two-stage process.
  * First, we enable power to the card without the clock running.
@@ -1187,9 +1216,8 @@ void mmc_init_erase(struct mmc_card *card)
        }
 }
 
-static void mmc_set_mmc_erase_timeout(struct mmc_card *card,
-                                     struct mmc_command *cmd,
-                                     unsigned int arg, unsigned int qty)
+static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
+                                         unsigned int arg, unsigned int qty)
 {
        unsigned int erase_timeout;
 
@@ -1246,44 +1274,48 @@ static void mmc_set_mmc_erase_timeout(struct mmc_card *card,
        if (mmc_host_is_spi(card->host) && erase_timeout < 1000)
                erase_timeout = 1000;
 
-       cmd->erase_timeout = erase_timeout;
+       return erase_timeout;
 }
 
-static void mmc_set_sd_erase_timeout(struct mmc_card *card,
-                                    struct mmc_command *cmd, unsigned int arg,
-                                    unsigned int qty)
+static unsigned int mmc_sd_erase_timeout(struct mmc_card *card,
+                                        unsigned int arg,
+                                        unsigned int qty)
 {
+       unsigned int erase_timeout;
+
        if (card->ssr.erase_timeout) {
                /* Erase timeout specified in SD Status Register (SSR) */
-               cmd->erase_timeout = card->ssr.erase_timeout * qty +
-                                    card->ssr.erase_offset;
+               erase_timeout = card->ssr.erase_timeout * qty +
+                               card->ssr.erase_offset;
        } else {
                /*
                 * Erase timeout not specified in SD Status Register (SSR) so
                 * use 250ms per write block.
                 */
-               cmd->erase_timeout = 250 * qty;
+               erase_timeout = 250 * qty;
        }
 
        /* Must not be less than 1 second */
-       if (cmd->erase_timeout < 1000)
-               cmd->erase_timeout = 1000;
+       if (erase_timeout < 1000)
+               erase_timeout = 1000;
+
+       return erase_timeout;
 }
 
-static void mmc_set_erase_timeout(struct mmc_card *card,
-                                 struct mmc_command *cmd, unsigned int arg,
-                                 unsigned int qty)
+static unsigned int mmc_erase_timeout(struct mmc_card *card,
+                                     unsigned int arg,
+                                     unsigned int qty)
 {
        if (mmc_card_sd(card))
-               mmc_set_sd_erase_timeout(card, cmd, arg, qty);
+               return mmc_sd_erase_timeout(card, arg, qty);
        else
-               mmc_set_mmc_erase_timeout(card, cmd, arg, qty);
+               return mmc_mmc_erase_timeout(card, arg, qty);
 }
 
 static int mmc_do_erase(struct mmc_card *card, unsigned int from,
                        unsigned int to, unsigned int arg)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        unsigned int qty = 0;
        int err;
 
@@ -1317,7 +1349,6 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
                to <<= 9;
        }
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
        if (mmc_card_sd(card))
                cmd.opcode = SD_ERASE_WR_BLK_START;
        else
@@ -1351,7 +1382,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
        cmd.opcode = MMC_ERASE;
        cmd.arg = arg;
        cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-       mmc_set_erase_timeout(card, &cmd, arg, qty);
+       cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty);
        err = mmc_wait_for_cmd(card->host, &cmd, 0);
        if (err) {
                printk(KERN_ERR "mmc_erase: erase error %d, status %#x\n",
@@ -1487,12 +1518,11 @@ EXPORT_SYMBOL(mmc_erase_group_aligned);
 
 int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
                return 0;
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
        cmd.opcode = MMC_SET_BLOCKLEN;
        cmd.arg = blocklen;
        cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
@@ -1578,7 +1608,7 @@ void mmc_rescan(struct work_struct *work)
        for (i = 0; i < ARRAY_SIZE(freqs); i++) {
                if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
                        break;
-               if (freqs[i] < host->f_min)
+               if (freqs[i] <= host->f_min)
                        break;
        }
        mmc_release_host(host);
@@ -1746,7 +1776,7 @@ int mmc_suspend_host(struct mmc_host *host)
        }
        mmc_bus_put(host);
 
-       if (!err && !(host->pm_flags & MMC_PM_KEEP_POWER))
+       if (!err && !mmc_card_keep_power(host))
                mmc_power_off(host);
 
        return err;
@@ -1764,7 +1794,7 @@ int mmc_resume_host(struct mmc_host *host)
 
        mmc_bus_get(host);
        if (host->bus_ops && !host->bus_dead) {
-               if (!(host->pm_flags & MMC_PM_KEEP_POWER)) {
+               if (!mmc_card_keep_power(host)) {
                        mmc_power_up(host);
                        mmc_select_voltage(host, host->ocr);
                        /*
@@ -1789,6 +1819,7 @@ int mmc_resume_host(struct mmc_host *host)
                        err = 0;
                }
        }
+       host->pm_flags &= ~MMC_PM_KEEP_POWER;
        mmc_bus_put(host);
 
        return err;
index 20b1c0831eac8f01e0bd8234d547f37618bd1494..d9411ed2a39bf6490a5a788629d45a628e14e6fe 100644 (file)
@@ -38,10 +38,11 @@ void mmc_ungate_clock(struct mmc_host *host);
 void mmc_set_ungated(struct mmc_host *host);
 void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
 void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
-void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
-                          unsigned int ddr);
 u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage,
+                          bool cmd11);
 void mmc_set_timing(struct mmc_host *host, unsigned int timing);
+void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
 
 static inline void mmc_delay(unsigned int ms)
 {
@@ -61,8 +62,6 @@ int mmc_attach_mmc(struct mmc_host *host);
 int mmc_attach_sd(struct mmc_host *host);
 int mmc_attach_sdio(struct mmc_host *host);
 
-void mmc_fixup_device(struct mmc_card *card);
-
 /* Module parameters */
 extern int use_spi_crc;
 
index 461e6a17fb90e8526d96054f2ec90f44a85e70c3..b29d3e8fd3a2ad713525c4be82c9b2f9699910ec 100644 (file)
@@ -325,12 +325,12 @@ int mmc_add_host(struct mmc_host *host)
        WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
                !host->ops->enable_sdio_irq);
 
-       led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
-
        err = device_add(&host->class_dev);
        if (err)
                return err;
 
+       led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
+
 #ifdef CONFIG_DEBUG_FS
        mmc_add_host_debugfs(host);
 #endif
index 772d0d0a541b6f9bbfc5208cba135e03ea38b57f..2a7e43bc796dfd1e798ad60a1ae6d0e7b98278a2 100644 (file)
@@ -20,6 +20,7 @@
 #include "core.h"
 #include "bus.h"
 #include "mmc_ops.h"
+#include "sd_ops.h"
 
 static const unsigned int tran_exp[] = {
        10000,          100000,         1000000,        10000000,
@@ -173,14 +174,17 @@ static int mmc_decode_csd(struct mmc_card *card)
 }
 
 /*
- * Read and decode extended CSD.
+ * Read extended CSD.
  */
-static int mmc_read_ext_csd(struct mmc_card *card)
+static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
 {
        int err;
        u8 *ext_csd;
 
        BUG_ON(!card);
+       BUG_ON(!new_ext_csd);
+
+       *new_ext_csd = NULL;
 
        if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
                return 0;
@@ -198,12 +202,15 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 
        err = mmc_send_ext_csd(card, ext_csd);
        if (err) {
+               kfree(ext_csd);
+               *new_ext_csd = NULL;
+
                /* If the host or the card can't do the switch,
                 * fail more gracefully. */
                if ((err != -EINVAL)
                 && (err != -ENOSYS)
                 && (err != -EFAULT))
-                       goto out;
+                       return err;
 
                /*
                 * High capacity cards should have this "magic" size
@@ -221,9 +228,23 @@ static int mmc_read_ext_csd(struct mmc_card *card)
                                mmc_hostname(card->host));
                        err = 0;
                }
+       } else
+               *new_ext_csd = ext_csd;
 
-               goto out;
-       }
+       return err;
+}
+
+/*
+ * Decode extended CSD.
+ */
+static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+       int err = 0;
+
+       BUG_ON(!card);
+
+       if (!ext_csd)
+               return 0;
 
        /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
        if (card->csd.structure == 3) {
@@ -288,6 +309,10 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 
        if (card->ext_csd.rev >= 3) {
                u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
+               card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG];
+
+               /* EXT_CSD value is in units of 10ms, but we store in ms */
+               card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME];
 
                /* Sleep / awake timeout in 100ns units */
                if (sa_shift > 0 && sa_shift <= 0x17)
@@ -299,6 +324,14 @@ static int mmc_read_ext_csd(struct mmc_card *card)
                        ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
                card->ext_csd.hc_erase_size =
                        ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10;
+
+               card->ext_csd.rel_sectors = ext_csd[EXT_CSD_REL_WR_SEC_C];
+
+               /*
+                * There are two boot regions of equal size, defined in
+                * multiples of 128K.
+                */
+               card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;
        }
 
        if (card->ext_csd.rev >= 4) {
@@ -350,14 +383,78 @@ static int mmc_read_ext_csd(struct mmc_card *card)
                        ext_csd[EXT_CSD_TRIM_MULT];
        }
 
+       if (card->ext_csd.rev >= 5)
+               card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
+
        if (ext_csd[EXT_CSD_ERASED_MEM_CONT])
                card->erased_byte = 0xFF;
        else
                card->erased_byte = 0x0;
 
 out:
+       return err;
+}
+
+static inline void mmc_free_ext_csd(u8 *ext_csd)
+{
        kfree(ext_csd);
+}
+
+
+static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd,
+                       unsigned bus_width)
+{
+       u8 *bw_ext_csd;
+       int err;
+
+       err = mmc_get_ext_csd(card, &bw_ext_csd);
+       if (err)
+               return err;
+
+       if ((ext_csd == NULL || bw_ext_csd == NULL)) {
+               if (bus_width != MMC_BUS_WIDTH_1)
+                       err = -EINVAL;
+               goto out;
+       }
 
+       if (bus_width == MMC_BUS_WIDTH_1)
+               goto out;
+
+       /* only compare read only fields */
+       err = (!(ext_csd[EXT_CSD_PARTITION_SUPPORT] ==
+                       bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
+               (ext_csd[EXT_CSD_ERASED_MEM_CONT] ==
+                       bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
+               (ext_csd[EXT_CSD_REV] ==
+                       bw_ext_csd[EXT_CSD_REV]) &&
+               (ext_csd[EXT_CSD_STRUCTURE] ==
+                       bw_ext_csd[EXT_CSD_STRUCTURE]) &&
+               (ext_csd[EXT_CSD_CARD_TYPE] ==
+                       bw_ext_csd[EXT_CSD_CARD_TYPE]) &&
+               (ext_csd[EXT_CSD_S_A_TIMEOUT] ==
+                       bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) &&
+               (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] ==
+                       bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
+               (ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] ==
+                       bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) &&
+               (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] ==
+                       bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
+               (ext_csd[EXT_CSD_SEC_TRIM_MULT] ==
+                       bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) &&
+               (ext_csd[EXT_CSD_SEC_ERASE_MULT] ==
+                       bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) &&
+               (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] ==
+                       bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) &&
+               (ext_csd[EXT_CSD_TRIM_MULT] ==
+                       bw_ext_csd[EXT_CSD_TRIM_MULT]) &&
+               memcmp(&ext_csd[EXT_CSD_SEC_CNT],
+                      &bw_ext_csd[EXT_CSD_SEC_CNT],
+                      4) != 0);
+       if (err)
+               err = -EINVAL;
+
+out:
+       mmc_free_ext_csd(bw_ext_csd);
        return err;
 }
 
@@ -422,6 +519,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        u32 cid[4];
        unsigned int max_dtr;
        u32 rocr;
+       u8 *ext_csd = NULL;
 
        BUG_ON(!host);
        WARN_ON(!host->claimed);
@@ -520,7 +618,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                /*
                 * Fetch and process extended CSD.
                 */
-               err = mmc_read_ext_csd(card);
+
+               err = mmc_get_ext_csd(card, &ext_csd);
+               if (err)
+                       goto free_card;
+               err = mmc_read_ext_csd(card, ext_csd);
                if (err)
                        goto free_card;
 
@@ -542,7 +644,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
         */
        if (card->ext_csd.enhanced_area_en) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                               EXT_CSD_ERASE_GROUP_DEF, 1);
+                                EXT_CSD_ERASE_GROUP_DEF, 1, 0);
 
                if (err && err != -EBADMSG)
                        goto free_card;
@@ -567,13 +669,25 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                }
        }
 
+       /*
+        * Ensure eMMC user default partition is enabled
+        */
+       if (card->ext_csd.part_config & EXT_CSD_PART_CONFIG_ACC_MASK) {
+               card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG,
+                                card->ext_csd.part_config,
+                                card->ext_csd.part_time);
+               if (err && err != -EBADMSG)
+                       goto free_card;
+       }
+
        /*
         * Activate high speed (if supported)
         */
        if ((card->ext_csd.hs_max_dtr != 0) &&
                (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                       EXT_CSD_HS_TIMING, 1);
+                                EXT_CSD_HS_TIMING, 1, 0);
                if (err && err != -EBADMSG)
                        goto free_card;
 
@@ -606,10 +720,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
         */
        if (mmc_card_highspeed(card)) {
                if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
-                       && (host->caps & (MMC_CAP_1_8V_DDR)))
+                       && ((host->caps & (MMC_CAP_1_8V_DDR |
+                            MMC_CAP_UHS_DDR50))
+                               == (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50)))
                                ddr = MMC_1_8V_DDR_MODE;
                else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
-                       && (host->caps & (MMC_CAP_1_2V_DDR)))
+                       && ((host->caps & (MMC_CAP_1_2V_DDR |
+                            MMC_CAP_UHS_DDR50))
+                               == (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50)))
                                ddr = MMC_1_2V_DDR_MODE;
        }
 
@@ -640,18 +758,22 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                                ddr = 0; /* no DDR for 1-bit width */
                        err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                                         EXT_CSD_BUS_WIDTH,
-                                        ext_csd_bits[idx][0]);
+                                        ext_csd_bits[idx][0],
+                                        0);
                        if (!err) {
-                               mmc_set_bus_width_ddr(card->host,
-                                                     bus_width, MMC_SDR_MODE);
+                               mmc_set_bus_width(card->host, bus_width);
+
                                /*
                                 * If controller can't handle bus width test,
-                                * use the highest bus width to maintain
-                                * compatibility with previous MMC behavior.
+                                * compare ext_csd previously read in 1 bit mode
+                                * against ext_csd at new bus width
                                 */
                                if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-                                       break;
-                               err = mmc_bus_test(card, bus_width);
+                                       err = mmc_compare_ext_csds(card,
+                                               ext_csd,
+                                               bus_width);
+                               else
+                                       err = mmc_bus_test(card, bus_width);
                                if (!err)
                                        break;
                        }
@@ -659,8 +781,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 
                if (!err && ddr) {
                        err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                       EXT_CSD_BUS_WIDTH,
-                                       ext_csd_bits[idx][1]);
+                                        EXT_CSD_BUS_WIDTH,
+                                        ext_csd_bits[idx][1],
+                                        0);
                }
                if (err) {
                        printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
@@ -668,20 +791,43 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                                1 << bus_width, ddr);
                        goto free_card;
                } else if (ddr) {
+                       /*
+                        * eMMC cards can support 3.3V to 1.2V i/o (vccq)
+                        * signaling.
+                        *
+                        * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
+                        *
+                        * 1.8V vccq at 3.3V core voltage (vcc) is not required
+                        * in the JEDEC spec for DDR.
+                        *
+                        * Do not force change in vccq since we are obviously
+                        * working and no change to vccq is needed.
+                        *
+                        * WARNING: eMMC rules are NOT the same as SD DDR
+                        */
+                       if (ddr == EXT_CSD_CARD_TYPE_DDR_1_2V) {
+                               err = mmc_set_signal_voltage(host,
+                                       MMC_SIGNAL_VOLTAGE_120, 0);
+                               if (err)
+                                       goto err;
+                       }
                        mmc_card_set_ddr_mode(card);
-                       mmc_set_bus_width_ddr(card->host, bus_width, ddr);
+                       mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
+                       mmc_set_bus_width(card->host, bus_width);
                }
        }
 
        if (!oldcard)
                host->card = card;
 
+       mmc_free_ext_csd(ext_csd);
        return 0;
 
 free_card:
        if (!oldcard)
                mmc_remove_card(card);
 err:
+       mmc_free_ext_csd(ext_csd);
 
        return err;
 }
index f3b22bf89cc98b68ab3e107154ec82b11aeb8a02..845ce7c533b901b0895a6bf4c5715c676c5cd902 100644 (file)
 static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        BUG_ON(!host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_SELECT_CARD;
 
        if (card) {
@@ -60,15 +58,13 @@ int mmc_deselect_cards(struct mmc_host *host)
 
 int mmc_card_sleepawake(struct mmc_host *host, int sleep)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        struct mmc_card *card = host->card;
        int err;
 
        if (sleep)
                mmc_deselect_cards(host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_SLEEP_AWAKE;
        cmd.arg = card->rca << 16;
        if (sleep)
@@ -97,7 +93,7 @@ int mmc_card_sleepawake(struct mmc_host *host, int sleep)
 int mmc_go_idle(struct mmc_host *host)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        /*
         * Non-SPI hosts need to prevent chipselect going active during
@@ -113,8 +109,6 @@ int mmc_go_idle(struct mmc_host *host)
                mmc_delay(1);
        }
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_GO_IDLE_STATE;
        cmd.arg = 0;
        cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
@@ -135,13 +129,11 @@ int mmc_go_idle(struct mmc_host *host)
 
 int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        int i, err = 0;
 
        BUG_ON(!host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_SEND_OP_COND;
        cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
        cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
@@ -178,13 +170,11 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        BUG_ON(!host);
        BUG_ON(!cid);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_ALL_SEND_CID;
        cmd.arg = 0;
        cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
@@ -201,13 +191,11 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
 int mmc_set_relative_addr(struct mmc_card *card)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        BUG_ON(!card);
        BUG_ON(!card->host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_SET_RELATIVE_ADDR;
        cmd.arg = card->rca << 16;
        cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
@@ -223,13 +211,11 @@ static int
 mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        BUG_ON(!host);
        BUG_ON(!cxd);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = opcode;
        cmd.arg = arg;
        cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
@@ -247,9 +233,9 @@ static int
 mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
                u32 opcode, void *buf, unsigned len)
 {
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_data data = {0};
        struct scatterlist sg;
        void *data_buf;
 
@@ -260,10 +246,6 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
        if (data_buf == NULL)
                return -ENOMEM;
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
 
@@ -355,11 +337,9 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
 
 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        int err;
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_SPI_READ_OCR;
        cmd.arg = highcap ? (1 << 30) : 0;
        cmd.flags = MMC_RSP_SPI_R3;
@@ -372,11 +352,9 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
 
 int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        int err;
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_SPI_CRC_ON_OFF;
        cmd.flags = MMC_RSP_SPI_R1;
        cmd.arg = use_crc;
@@ -387,23 +365,34 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
        return err;
 }
 
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
+/**
+ *     mmc_switch - modify EXT_CSD register
+ *     @card: the MMC card associated with the data transfer
+ *     @set: cmd set values
+ *     @index: EXT_CSD register index
+ *     @value: value to program into EXT_CSD register
+ *     @timeout_ms: timeout (ms) for operation performed by register write,
+ *                   timeout of zero implies maximum possible timeout
+ *
+ *     Modifies the EXT_CSD register for selected card.
+ */
+int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
+              unsigned int timeout_ms)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        u32 status;
 
        BUG_ON(!card);
        BUG_ON(!card->host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_SWITCH;
        cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
                  (index << 16) |
                  (value << 8) |
                  set;
        cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+       cmd.cmd_timeout_ms = timeout_ms;
 
        err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
        if (err)
@@ -433,17 +422,16 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(mmc_switch);
 
 int mmc_send_status(struct mmc_card *card, u32 *status)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        BUG_ON(!card);
        BUG_ON(!card->host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_SEND_STATUS;
        if (!mmc_host_is_spi(card->host))
                cmd.arg = card->rca << 16;
@@ -466,9 +454,9 @@ static int
 mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
                  u8 len)
 {
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_data data = {0};
        struct scatterlist sg;
        u8 *data_buf;
        u8 *test_buf;
@@ -497,10 +485,6 @@ mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
        if (opcode == MMC_BUS_TEST_W)
                memcpy(data_buf, test_buf, len);
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
        cmd.opcode = opcode;
index e6d44b8a18db52b438f7c422970c3cc6444588fc..9276946fa5b719b8d1128c2ed94dedc73406ab12 100644 (file)
@@ -20,7 +20,6 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_set_relative_addr(struct mmc_card *card);
 int mmc_send_csd(struct mmc_card *card, u32 *csd);
 int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
 int mmc_send_status(struct mmc_card *card, u32 *status);
 int mmc_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
index 11118b74eb20dc3c82f9fc96401d00c754c49b41..3a596217029e1e94fbd9797f2d324fa5dde03472 100644 (file)
@@ -1,7 +1,8 @@
 /*
- *  This file contains work-arounds for many known sdio hardware
- *  bugs.
+ *  This file contains work-arounds for many known SD/MMC
+ *  and SDIO hardware bugs.
  *
+ *  Copyright (c) 2011 Andrei Warkentin <andreiw@motorola.com>
  *  Copyright (c) 2011 Pierre Tardy <tardyp@gmail.com>
  *  Inspired from pci fixup code:
  *  Copyright (c) 1999 Martin Mares <mj@ucw.cz>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mmc/card.h>
-#include <linux/mod_devicetable.h>
 
-/*
- *  The world is not perfect and supplies us with broken mmc/sdio devices.
- *  For at least a part of these bugs we need a work-around
- */
-
-struct mmc_fixup {
-       u16 vendor, device;     /* You can use SDIO_ANY_ID here of course */
-       void (*vendor_fixup)(struct mmc_card *card, int data);
-       int data;
-};
-
-/*
- * This hook just adds a quirk unconditionnally
- */
-static void __maybe_unused add_quirk(struct mmc_card *card, int data)
-{
-       card->quirks |= data;
-}
+#ifndef SDIO_VENDOR_ID_TI
+#define SDIO_VENDOR_ID_TI              0x0097
+#endif
 
-/*
- * This hook just removes a quirk unconditionnally
- */
-static void __maybe_unused remove_quirk(struct mmc_card *card, int data)
-{
-       card->quirks &= ~data;
-}
+#ifndef SDIO_DEVICE_ID_TI_WL1271
+#define SDIO_DEVICE_ID_TI_WL1271       0x4076
+#endif
 
 /*
  * This hook just adds a quirk for all sdio devices
@@ -49,33 +30,47 @@ static void add_quirk_for_sdio_devices(struct mmc_card *card, int data)
                card->quirks |= data;
 }
 
-#ifndef SDIO_VENDOR_ID_TI
-#define SDIO_VENDOR_ID_TI              0x0097
-#endif
-
-#ifndef SDIO_DEVICE_ID_TI_WL1271
-#define SDIO_DEVICE_ID_TI_WL1271       0x4076
-#endif
-
 static const struct mmc_fixup mmc_fixup_methods[] = {
        /* by default sdio devices are considered CLK_GATING broken */
        /* good cards will be whitelisted as they are tested */
-       { SDIO_ANY_ID, SDIO_ANY_ID,
-               add_quirk_for_sdio_devices, MMC_QUIRK_BROKEN_CLK_GATING },
-       { SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
-               remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING },
-       { 0 }
+       SDIO_FIXUP(SDIO_ANY_ID, SDIO_ANY_ID,
+                  add_quirk_for_sdio_devices,
+                  MMC_QUIRK_BROKEN_CLK_GATING),
+
+       SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
+                  remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
+       SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
+                  add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
+
+       SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
+                  add_quirk, MMC_QUIRK_DISABLE_CD),
+
+       END_FIXUP
 };
 
-void mmc_fixup_device(struct mmc_card *card)
+void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
 {
        const struct mmc_fixup *f;
+       u64 rev = cid_rev_card(card);
+
+       /* Non-core specific workarounds. */
+       if (!table)
+               table = mmc_fixup_methods;
 
-       for (f = mmc_fixup_methods; f->vendor_fixup; f++) {
-               if ((f->vendor == card->cis.vendor
-                    || f->vendor == (u16) SDIO_ANY_ID) &&
-                   (f->device == card->cis.device
-                    || f->device == (u16) SDIO_ANY_ID)) {
+       for (f = table; f->vendor_fixup; f++) {
+               if ((f->manfid == CID_MANFID_ANY ||
+                    f->manfid == card->cid.manfid) &&
+                   (f->oemid == CID_OEMID_ANY ||
+                    f->oemid == card->cid.oemid) &&
+                   (f->name == CID_NAME_ANY ||
+                    !strncmp(f->name, card->cid.prod_name,
+                             sizeof(card->cid.prod_name))) &&
+                   (f->cis_vendor == card->cis.vendor ||
+                    f->cis_vendor == (u16) SDIO_ANY_ID) &&
+                   (f->cis_device == card->cis.device ||
+                    f->cis_device == (u16) SDIO_ANY_ID) &&
+                   rev >= f->rev_start && rev <= f->rev_end) {
                        dev_dbg(&card->dev, "calling %pF\n", f->vendor_fixup);
                        f->vendor_fixup(card, f->data);
                }
index 6dac89fe0535ad02b272e5fbe658627d0263fd29..ff2774128aa93b1231538b1f5e014b0df987e7ca 100644 (file)
@@ -130,7 +130,7 @@ static int mmc_decode_csd(struct mmc_card *card)
                break;
        case 1:
                /*
-                * This is a block-addressed SDHC card. Most
+                * This is a block-addressed SDHC or SDXC card. Most
                 * interesting fields are unused and have fixed
                 * values. To avoid getting tripped by buggy cards,
                 * we assume those fixed values ourselves.
@@ -144,6 +144,11 @@ static int mmc_decode_csd(struct mmc_card *card)
                e = UNSTUFF_BITS(resp, 96, 3);
                csd->max_dtr      = tran_exp[e] * tran_mant[m];
                csd->cmdclass     = UNSTUFF_BITS(resp, 84, 12);
+               csd->c_size       = UNSTUFF_BITS(resp, 48, 22);
+
+               /* SDXC cards have a minimum C_SIZE of 0x00FFFF */
+               if (csd->c_size >= 0xFFFF)
+                       mmc_card_set_ext_capacity(card);
 
                m = UNSTUFF_BITS(resp, 48, 22);
                csd->capacity     = (1 + m) << 10;
@@ -189,12 +194,17 @@ static int mmc_decode_scr(struct mmc_card *card)
 
        scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
        scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
+       if (scr->sda_vsn == SCR_SPEC_VER_2)
+               /* Check if Physical Layer Spec v3.0 is supported */
+               scr->sda_spec3 = UNSTUFF_BITS(resp, 47, 1);
 
        if (UNSTUFF_BITS(resp, 55, 1))
                card->erased_byte = 0xFF;
        else
                card->erased_byte = 0x0;
 
+       if (scr->sda_spec3)
+               scr->cmds = UNSTUFF_BITS(resp, 32, 2);
        return 0;
 }
 
@@ -274,29 +284,74 @@ static int mmc_read_switch(struct mmc_card *card)
        status = kmalloc(64, GFP_KERNEL);
        if (!status) {
                printk(KERN_ERR "%s: could not allocate a buffer for "
-                       "switch capabilities.\n", mmc_hostname(card->host));
+                       "switch capabilities.\n",
+                       mmc_hostname(card->host));
                return -ENOMEM;
        }
 
+       /* Find out the supported Bus Speed Modes. */
        err = mmc_sd_switch(card, 0, 0, 1, status);
        if (err) {
-               /* If the host or the card can't do the switch,
-                * fail more gracefully. */
-               if ((err != -EINVAL)
-                && (err != -ENOSYS)
-                && (err != -EFAULT))
+               /*
+                * If the host or the card can't do the switch,
+                * fail more gracefully.
+                */
+               if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
                        goto out;
 
-               printk(KERN_WARNING "%s: problem reading switch "
-                       "capabilities, performance might suffer.\n",
+               printk(KERN_WARNING "%s: problem reading Bus Speed modes.\n",
                        mmc_hostname(card->host));
                err = 0;
 
                goto out;
        }
 
-       if (status[13] & 0x02)
-               card->sw_caps.hs_max_dtr = 50000000;
+       if (card->scr.sda_spec3) {
+               card->sw_caps.sd3_bus_mode = status[13];
+
+               /* Find out Driver Strengths supported by the card */
+               err = mmc_sd_switch(card, 0, 2, 1, status);
+               if (err) {
+                       /*
+                        * If the host or the card can't do the switch,
+                        * fail more gracefully.
+                        */
+                       if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
+                               goto out;
+
+                       printk(KERN_WARNING "%s: problem reading "
+                               "Driver Strength.\n",
+                               mmc_hostname(card->host));
+                       err = 0;
+
+                       goto out;
+               }
+
+               card->sw_caps.sd3_drv_type = status[9];
+
+               /* Find out Current Limits supported by the card */
+               err = mmc_sd_switch(card, 0, 3, 1, status);
+               if (err) {
+                       /*
+                        * If the host or the card can't do the switch,
+                        * fail more gracefully.
+                        */
+                       if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
+                               goto out;
+
+                       printk(KERN_WARNING "%s: problem reading "
+                               "Current Limit.\n",
+                               mmc_hostname(card->host));
+                       err = 0;
+
+                       goto out;
+               }
+
+               card->sw_caps.sd3_curr_limit = status[7];
+       } else {
+               if (status[13] & 0x02)
+                       card->sw_caps.hs_max_dtr = 50000000;
+       }
 
 out:
        kfree(status);
@@ -352,6 +407,232 @@ out:
        return err;
 }
 
+static int sd_select_driver_type(struct mmc_card *card, u8 *status)
+{
+       int host_drv_type = 0, card_drv_type = 0;
+       int err;
+
+       /*
+        * If the host doesn't support any of the Driver Types A,C or D,
+        * default Driver Type B is used.
+        */
+       if (!(card->host->caps & (MMC_CAP_DRIVER_TYPE_A | MMC_CAP_DRIVER_TYPE_C
+           | MMC_CAP_DRIVER_TYPE_D)))
+               return 0;
+
+       if (card->host->caps & MMC_CAP_DRIVER_TYPE_A) {
+               host_drv_type = MMC_SET_DRIVER_TYPE_A;
+               if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A)
+                       card_drv_type = MMC_SET_DRIVER_TYPE_A;
+               else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B)
+                       card_drv_type = MMC_SET_DRIVER_TYPE_B;
+               else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
+                       card_drv_type = MMC_SET_DRIVER_TYPE_C;
+       } else if (card->host->caps & MMC_CAP_DRIVER_TYPE_C) {
+               host_drv_type = MMC_SET_DRIVER_TYPE_C;
+               if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
+                       card_drv_type = MMC_SET_DRIVER_TYPE_C;
+       } else if (!(card->host->caps & MMC_CAP_DRIVER_TYPE_D)) {
+               /*
+                * If we are here, that means only the default driver type
+                * B is supported by the host.
+                */
+               host_drv_type = MMC_SET_DRIVER_TYPE_B;
+               if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B)
+                       card_drv_type = MMC_SET_DRIVER_TYPE_B;
+               else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
+                       card_drv_type = MMC_SET_DRIVER_TYPE_C;
+       }
+
+       err = mmc_sd_switch(card, 1, 2, card_drv_type, status);
+       if (err)
+               return err;
+
+       if ((status[15] & 0xF) != card_drv_type) {
+               printk(KERN_WARNING "%s: Problem setting driver strength!\n",
+                       mmc_hostname(card->host));
+               return 0;
+       }
+
+       mmc_set_driver_type(card->host, host_drv_type);
+
+       return 0;
+}
+
+static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
+{
+       unsigned int bus_speed = 0, timing = 0;
+       int err;
+
+       /*
+        * If the host doesn't support any of the UHS-I modes, fallback on
+        * default speed.
+        */
+       if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+           MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)))
+               return 0;
+
+       if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
+           (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
+                       bus_speed = UHS_SDR104_BUS_SPEED;
+                       timing = MMC_TIMING_UHS_SDR104;
+                       card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
+       } else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
+                  (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
+                       bus_speed = UHS_DDR50_BUS_SPEED;
+                       timing = MMC_TIMING_UHS_DDR50;
+                       card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
+       } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
+                   MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
+                   SD_MODE_UHS_SDR50)) {
+                       bus_speed = UHS_SDR50_BUS_SPEED;
+                       timing = MMC_TIMING_UHS_SDR50;
+                       card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
+       } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
+                   MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
+                  (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
+                       bus_speed = UHS_SDR25_BUS_SPEED;
+                       timing = MMC_TIMING_UHS_SDR25;
+                       card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
+       } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
+                   MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
+                   MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
+                   SD_MODE_UHS_SDR12)) {
+                       bus_speed = UHS_SDR12_BUS_SPEED;
+                       timing = MMC_TIMING_UHS_SDR12;
+                       card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
+       }
+
+       card->sd_bus_speed = bus_speed;
+       err = mmc_sd_switch(card, 1, 0, bus_speed, status);
+       if (err)
+               return err;
+
+       if ((status[16] & 0xF) != bus_speed)
+               printk(KERN_WARNING "%s: Problem setting bus speed mode!\n",
+                       mmc_hostname(card->host));
+       else {
+               mmc_set_timing(card->host, timing);
+               mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
+       }
+
+       return 0;
+}
+
+static int sd_set_current_limit(struct mmc_card *card, u8 *status)
+{
+       int current_limit = 0;
+       int err;
+
+       /*
+        * Current limit switch is only defined for SDR50, SDR104, and DDR50
+        * bus speed modes. For other bus speed modes, we set the default
+        * current limit of 200mA.
+        */
+       if ((card->sd_bus_speed == UHS_SDR50_BUS_SPEED) ||
+           (card->sd_bus_speed == UHS_SDR104_BUS_SPEED) ||
+           (card->sd_bus_speed == UHS_DDR50_BUS_SPEED)) {
+               if (card->host->caps & MMC_CAP_MAX_CURRENT_800) {
+                       if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800)
+                               current_limit = SD_SET_CURRENT_LIMIT_800;
+                       else if (card->sw_caps.sd3_curr_limit &
+                                       SD_MAX_CURRENT_600)
+                               current_limit = SD_SET_CURRENT_LIMIT_600;
+                       else if (card->sw_caps.sd3_curr_limit &
+                                       SD_MAX_CURRENT_400)
+                               current_limit = SD_SET_CURRENT_LIMIT_400;
+                       else if (card->sw_caps.sd3_curr_limit &
+                                       SD_MAX_CURRENT_200)
+                               current_limit = SD_SET_CURRENT_LIMIT_200;
+               } else if (card->host->caps & MMC_CAP_MAX_CURRENT_600) {
+                       if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600)
+                               current_limit = SD_SET_CURRENT_LIMIT_600;
+                       else if (card->sw_caps.sd3_curr_limit &
+                                       SD_MAX_CURRENT_400)
+                               current_limit = SD_SET_CURRENT_LIMIT_400;
+                       else if (card->sw_caps.sd3_curr_limit &
+                                       SD_MAX_CURRENT_200)
+                               current_limit = SD_SET_CURRENT_LIMIT_200;
+               } else if (card->host->caps & MMC_CAP_MAX_CURRENT_400) {
+                       if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400)
+                               current_limit = SD_SET_CURRENT_LIMIT_400;
+                       else if (card->sw_caps.sd3_curr_limit &
+                                       SD_MAX_CURRENT_200)
+                               current_limit = SD_SET_CURRENT_LIMIT_200;
+               } else if (card->host->caps & MMC_CAP_MAX_CURRENT_200) {
+                       if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200)
+                               current_limit = SD_SET_CURRENT_LIMIT_200;
+               }
+       } else
+               current_limit = SD_SET_CURRENT_LIMIT_200;
+
+       err = mmc_sd_switch(card, 1, 3, current_limit, status);
+       if (err)
+               return err;
+
+       if (((status[15] >> 4) & 0x0F) != current_limit)
+               printk(KERN_WARNING "%s: Problem setting current limit!\n",
+                       mmc_hostname(card->host));
+
+       return 0;
+}
+
+/*
+ * UHS-I specific initialization procedure
+ */
+static int mmc_sd_init_uhs_card(struct mmc_card *card)
+{
+       int err;
+       u8 *status;
+
+       if (!card->scr.sda_spec3)
+               return 0;
+
+       if (!(card->csd.cmdclass & CCC_SWITCH))
+               return 0;
+
+       status = kmalloc(64, GFP_KERNEL);
+       if (!status) {
+               printk(KERN_ERR "%s: could not allocate a buffer for "
+                       "switch capabilities.\n", mmc_hostname(card->host));
+               return -ENOMEM;
+       }
+
+       /* Set 4-bit bus width */
+       if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
+           (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+               err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
+               if (err)
+                       goto out;
+
+               mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+       }
+
+       /* Set the driver strength for the card */
+       err = sd_select_driver_type(card, status);
+       if (err)
+               goto out;
+
+       /* Set bus speed mode of the card */
+       err = sd_set_bus_speed_mode(card, status);
+       if (err)
+               goto out;
+
+       /* Set current limit for the card */
+       err = sd_set_current_limit(card, status);
+       if (err)
+               goto out;
+
+       /* SPI mode doesn't define CMD19 */
+       if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
+               err = card->host->ops->execute_tuning(card->host);
+
+out:
+       kfree(status);
+
+       return err;
+}
+
 MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
        card->raw_cid[2], card->raw_cid[3]);
 MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
@@ -400,7 +681,7 @@ struct device_type sd_type = {
 /*
  * Fetch CID from card.
  */
-int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid)
+int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
 {
        int err;
 
@@ -420,12 +701,39 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid)
         */
        err = mmc_send_if_cond(host, ocr);
        if (!err)
-               ocr |= 1 << 30;
+               ocr |= SD_OCR_CCS;
+
+       /*
+        * If the host supports one of UHS-I modes, request the card
+        * to switch to 1.8V signaling level.
+        */
+       if (host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+           MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))
+               ocr |= SD_OCR_S18R;
+
+       /* If the host can supply more than 150mA, XPC should be set to 1. */
+       if (host->caps & (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
+           MMC_CAP_SET_XPC_180))
+               ocr |= SD_OCR_XPC;
 
-       err = mmc_send_app_op_cond(host, ocr, NULL);
+try_again:
+       err = mmc_send_app_op_cond(host, ocr, rocr);
        if (err)
                return err;
 
+       /*
+        * In case CCS and S18A in the response is set, start Signal Voltage
+        * Switch procedure. SPI mode doesn't support CMD11.
+        */
+       if (!mmc_host_is_spi(host) && rocr &&
+          ((*rocr & 0x41000000) == 0x41000000)) {
+               err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, true);
+               if (err) {
+                       ocr &= ~SD_OCR_S18R;
+                       goto try_again;
+               }
+       }
+
        if (mmc_host_is_spi(host))
                err = mmc_send_cid(host, cid);
        else
@@ -553,11 +861,12 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
        struct mmc_card *card;
        int err;
        u32 cid[4];
+       u32 rocr = 0;
 
        BUG_ON(!host);
        WARN_ON(!host->claimed);
 
-       err = mmc_sd_get_cid(host, ocr, cid);
+       err = mmc_sd_get_cid(host, ocr, cid, &rocr);
        if (err)
                return err;
 
@@ -610,30 +919,47 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
        if (err)
                goto free_card;
 
-       /*
-        * Attempt to change to high-speed (if supported)
-        */
-       err = mmc_sd_switch_hs(card);
-       if (err > 0)
-               mmc_sd_go_highspeed(card);
-       else if (err)
-               goto free_card;
+       /* Initialization sequence for UHS-I cards */
+       if (rocr & SD_ROCR_S18A) {
+               err = mmc_sd_init_uhs_card(card);
+               if (err)
+                       goto free_card;
 
-       /*
-        * Set bus speed.
-        */
-       mmc_set_clock(host, mmc_sd_get_max_clock(card));
+               /* Card is an ultra-high-speed card */
+               mmc_sd_card_set_uhs(card);
 
-       /*
-        * Switch to wider bus (if supported).
-        */
-       if ((host->caps & MMC_CAP_4_BIT_DATA) &&
-               (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
-               err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
-               if (err)
+               /*
+                * Since initialization is now complete, enable preset
+                * value registers for UHS-I cards.
+                */
+               if (host->ops->enable_preset_value)
+                       host->ops->enable_preset_value(host, true);
+       } else {
+               /*
+                * Attempt to change to high-speed (if supported)
+                */
+               err = mmc_sd_switch_hs(card);
+               if (err > 0)
+                       mmc_sd_go_highspeed(card);
+               else if (err)
                        goto free_card;
 
-               mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
+               /*
+                * Set bus speed.
+                */
+               mmc_set_clock(host, mmc_sd_get_max_clock(card));
+
+               /*
+                * Switch to wider bus (if supported).
+                */
+               if ((host->caps & MMC_CAP_4_BIT_DATA) &&
+                       (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+                       err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
+                       if (err)
+                               goto free_card;
+
+                       mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
+               }
        }
 
        host->card = card;
@@ -773,6 +1099,15 @@ int mmc_attach_sd(struct mmc_host *host)
        BUG_ON(!host);
        WARN_ON(!host->claimed);
 
+       /* Make sure we are at 3.3V signalling voltage */
+       err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false);
+       if (err)
+               return err;
+
+       /* Disable preset value enable if already set since last time */
+       if (host->ops->enable_preset_value)
+               host->ops->enable_preset_value(host, false);
+
        err = mmc_send_app_op_cond(host, 0, &ocr);
        if (err)
                return err;
index 3d8800fa7600ac011acc72d168a23939b14b4409..4b34b24f3f762f62ea026b491661f9e496d99b8d 100644 (file)
@@ -5,7 +5,7 @@
 
 extern struct device_type sd_type;
 
-int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid);
+int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr);
 int mmc_sd_get_csd(struct mmc_host *host, struct mmc_card *card);
 void mmc_decode_cid(struct mmc_card *card);
 int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
index 76af349c14b41e41c8e6de62878ee364c6a61232..021fed153804cf0c9d3ad20598895ae093b36e5d 100644 (file)
 #include "core.h"
 #include "sd_ops.h"
 
-static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
+int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        BUG_ON(!host);
        BUG_ON(card && (card->host != host));
@@ -49,6 +49,7 @@ static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(mmc_app_cmd);
 
 /**
  *     mmc_wait_for_app_cmd - start an application command and wait for
@@ -66,7 +67,7 @@ static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
 int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
        struct mmc_command *cmd, int retries)
 {
-       struct mmc_request mrq;
+       struct mmc_request mrq = {0};
 
        int i, err;
 
@@ -119,13 +120,11 @@ EXPORT_SYMBOL(mmc_wait_for_app_cmd);
 int mmc_app_set_bus_width(struct mmc_card *card, int width)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        BUG_ON(!card);
        BUG_ON(!card->host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = SD_APP_SET_BUS_WIDTH;
        cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 
@@ -149,13 +148,11 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width)
 
 int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        int i, err = 0;
 
        BUG_ON(!host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = SD_APP_OP_COND;
        if (mmc_host_is_spi(host))
                cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */
@@ -194,7 +191,7 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 
 int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        int err;
        static const u8 test_pattern = 0xAA;
        u8 result_pattern;
@@ -226,13 +223,11 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
 int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        BUG_ON(!host);
        BUG_ON(!rca);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = SD_SEND_RELATIVE_ADDR;
        cmd.arg = 0;
        cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
@@ -249,9 +244,9 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
 int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
 {
        int err;
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_data data = {0};
        struct scatterlist sg;
        void *data_buf;
 
@@ -272,10 +267,6 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
        if (data_buf == NULL)
                return -ENOMEM;
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
 
@@ -312,9 +303,9 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
 int mmc_sd_switch(struct mmc_card *card, int mode, int group,
        u8 value, u8 *resp)
 {
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_data data = {0};
        struct scatterlist sg;
 
        BUG_ON(!card);
@@ -325,10 +316,6 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
        mode = !!mode;
        value &= 0xF;
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
 
@@ -361,9 +348,9 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
 int mmc_app_sd_status(struct mmc_card *card, void *ssr)
 {
        int err;
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_data data = {0};
        struct scatterlist sg;
 
        BUG_ON(!card);
@@ -376,10 +363,6 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr)
        if (err)
                return err;
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
 
index db0f0b44d684617b006b7eaa787e07fd0cd1017b..4d0c15bfa51465c91026972417c17652129e09d8 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/mmc/card.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
 
 #include "core.h"
 #include "bus.h"
@@ -31,6 +32,11 @@ static int sdio_read_fbr(struct sdio_func *func)
        int ret;
        unsigned char data;
 
+       if (mmc_card_nonstd_func_interface(func->card)) {
+               func->class = SDIO_CLASS_NONE;
+               return 0;
+       }
+
        ret = mmc_io_rw_direct(func->card, 0, 0,
                SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF, 0, &data);
        if (ret)
@@ -181,7 +187,7 @@ static int sdio_disable_cd(struct mmc_card *card)
        int ret;
        u8 ctrl;
 
-       if (!card->cccr.disable_cd)
+       if (!mmc_card_disable_cd(card))
                return 0;
 
        ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl);
@@ -363,8 +369,8 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
                goto err;
        }
 
-       if (ocr & R4_MEMORY_PRESENT
-           && mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid) == 0) {
+       if ((ocr & R4_MEMORY_PRESENT) &&
+           mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid, NULL) == 0) {
                card->type = MMC_TYPE_SD_COMBO;
 
                if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO ||
@@ -466,7 +472,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
 
                card = oldcard;
        }
-       mmc_fixup_device(card);
+       mmc_fixup_device(card, NULL);
 
        if (card->type == MMC_TYPE_SD_COMBO) {
                err = mmc_sd_setup_card(host, card, oldcard != NULL);
@@ -625,7 +631,7 @@ static int mmc_sdio_suspend(struct mmc_host *host)
                }
        }
 
-       if (!err && host->pm_flags & MMC_PM_KEEP_POWER) {
+       if (!err && mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
                mmc_claim_host(host);
                sdio_disable_wide(host->card);
                mmc_release_host(host);
@@ -645,10 +651,10 @@ static int mmc_sdio_resume(struct mmc_host *host)
        mmc_claim_host(host);
 
        /* No need to reinitialize powered-resumed nonremovable cards */
-       if (mmc_card_is_removable(host) || !mmc_card_is_powered_resumed(host))
+       if (mmc_card_is_removable(host) || !mmc_card_keep_power(host))
                err = mmc_sdio_init_card(host, host->ocr, host->card,
-                                (host->pm_flags & MMC_PM_KEEP_POWER));
-       else if (mmc_card_is_powered_resumed(host)) {
+                                       mmc_card_keep_power(host));
+       else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
                /* We may have switched to 1-bit mode during suspend */
                err = sdio_enable_4bit_bus(host->card);
                if (err > 0) {
@@ -691,7 +697,7 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
 
        mmc_claim_host(host);
        ret = mmc_sdio_init_card(host, host->ocr, host->card,
-                       (host->pm_flags & MMC_PM_KEEP_POWER));
+                               mmc_card_keep_power(host));
        if (!ret && host->sdio_irqs)
                mmc_signal_sdio_irq(host);
        mmc_release_host(host);
index b3001617e67d764c8157f45f60c4d677eaa6d161..03ead028d2ce147ac9a33387814b040ec1e91e53 100644 (file)
@@ -31,6 +31,17 @@ static int process_sdio_pending_irqs(struct mmc_card *card)
 {
        int i, ret, count;
        unsigned char pending;
+       struct sdio_func *func;
+
+       /*
+        * Optimization, if there is only 1 function interrupt registered
+        * call irq handler directly
+        */
+       func = card->sdio_single_irq;
+       if (func) {
+               func->irq_handler(func);
+               return 1;
+       }
 
        ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending);
        if (ret) {
@@ -42,7 +53,7 @@ static int process_sdio_pending_irqs(struct mmc_card *card)
        count = 0;
        for (i = 1; i <= 7; i++) {
                if (pending & (1 << i)) {
-                       struct sdio_func *func = card->sdio_func[i - 1];
+                       func = card->sdio_func[i - 1];
                        if (!func) {
                                printk(KERN_WARNING "%s: pending IRQ for "
                                        "non-existent function\n",
@@ -186,6 +197,24 @@ static int sdio_card_irq_put(struct mmc_card *card)
        return 0;
 }
 
+/* If there is only 1 function registered set sdio_single_irq */
+static void sdio_single_irq_set(struct mmc_card *card)
+{
+       struct sdio_func *func;
+       int i;
+
+       card->sdio_single_irq = NULL;
+       if ((card->host->caps & MMC_CAP_SDIO_IRQ) &&
+           card->host->sdio_irqs == 1)
+               for (i = 0; i < card->sdio_funcs; i++) {
+                      func = card->sdio_func[i];
+                      if (func && func->irq_handler) {
+                              card->sdio_single_irq = func;
+                              break;
+                      }
+              }
+}
+
 /**
  *     sdio_claim_irq - claim the IRQ for a SDIO function
  *     @func: SDIO function
@@ -227,6 +256,7 @@ int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler)
        ret = sdio_card_irq_get(func->card);
        if (ret)
                func->irq_handler = NULL;
+       sdio_single_irq_set(func->card);
 
        return ret;
 }
@@ -251,6 +281,7 @@ int sdio_release_irq(struct sdio_func *func)
        if (func->irq_handler) {
                func->irq_handler = NULL;
                sdio_card_irq_put(func->card);
+               sdio_single_irq_set(func->card);
        }
 
        ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
index dea36d9c22e6df01afa6ca5689455c195b0d6685..f087d876c5731ebb0feefe14244811936ddefa70 100644 (file)
 
 int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        int i, err = 0;
 
        BUG_ON(!host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = SD_IO_SEND_OP_COND;
        cmd.arg = ocr;
        cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR;
@@ -70,7 +68,7 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
        unsigned addr, u8 in, u8 *out)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        int err;
 
        BUG_ON(!host);
@@ -80,8 +78,6 @@ static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
        if (addr & ~0x1FFFF)
                return -EINVAL;
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = SD_IO_RW_DIRECT;
        cmd.arg = write ? 0x80000000 : 0x00000000;
        cmd.arg |= fn << 28;
@@ -125,9 +121,9 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
 int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
        unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
 {
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_data data = {0};
        struct scatterlist sg;
 
        BUG_ON(!card);
@@ -140,10 +136,6 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
        if (addr & ~0x1FFFF)
                return -EINVAL;
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
 
index 94df40531c38caaa597fc05086b9e14b36f166d5..56dbf3f6ad08a495075b2e254dccc1cb61d2c707 100644 (file)
@@ -154,7 +154,7 @@ config MMC_SDHCI_DOVE
          If unsure, say N.
 
 config MMC_SDHCI_TEGRA
-       tristate "SDHCI platform support for the Tegra SD/MMC Controller"
+       bool "SDHCI platform support for the Tegra SD/MMC Controller"
        depends on MMC_SDHCI_PLTFM && ARCH_TEGRA
        select MMC_SDHCI_IO_ACCESSORS
        help
@@ -535,6 +535,37 @@ config MMC_JZ4740
          If you have a board based on such a SoC and with a SD/MMC slot,
          say Y or M here.
 
+config MMC_VUB300
+       tristate "VUB300 USB to SDIO/SD/MMC Host Controller support"
+       depends on USB
+       help
+         This selects support for Elan Digital Systems' VUB300 chip.
+
+         The VUB300 is a USB-SDIO Host Controller Interface chip
+         that enables the host computer to use SDIO/SD/MMC cards
+         via a USB 2.0 or USB 1.1 host.
+
+         The VUB300 chip will be found in both physically separate
+         USB to SDIO/SD/MMC adapters and embedded on some motherboards.
+
+         The VUB300 chip supports SD and MMC memory cards in addition
+         to single and multifunction SDIO cards.
+
+         Some SDIO cards will need a firmware file to be loaded and
+         sent to VUB300 chip in order to achieve better data throughput.
+         Download these "Offload Pseudocode" from Elan Digital Systems'
+         web-site http://www.elandigitalsystems.com/support/downloads.php
+         and put them in /lib/firmware. Note that without these additional
+         firmware files the VUB300 chip will still function, but not at
+         the best obtainable data rate.
+
+         To compile this mmc host controller driver as a module,
+         choose M here: the module will be called vub300.
+
+         If you have a computer with an embedded VUB300 chip
+         or if you intend connecting a USB adapter based on a
+         VUB300 chip say Y or M here.
+
 config MMC_USHC
        tristate "USB SD Host Controller (USHC) support"
        depends on USB
index 4f1df0aae574eb429f2f0356d20ffd57a7da1e8d..58a5cf73d6e9a0fa77646b5a4ca40c5f48a8f847 100644 (file)
@@ -41,6 +41,7 @@ obj-$(CONFIG_SDH_BFIN)                += bfin_sdh.o
 obj-$(CONFIG_MMC_DW)           += dw_mmc.o
 obj-$(CONFIG_MMC_SH_MMCIF)     += sh_mmcif.o
 obj-$(CONFIG_MMC_JZ4740)       += jz4740_mmc.o
+obj-$(CONFIG_MMC_VUB300)       += vub300.o
 obj-$(CONFIG_MMC_USHC)         += ushc.o
 
 obj-$(CONFIG_MMC_SDHCI_PLTFM)                  += sdhci-platform.o
index 87e1f57ec9bae7ea4711c9ddfed81600ce819dcb..66dcddb9c20592690c31cd233af7354018c1f4b2 100644 (file)
@@ -1769,9 +1769,6 @@ static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg)
        int i, ret;
        struct dw_mci *host = platform_get_drvdata(pdev);
 
-       if (host->vmmc)
-               regulator_enable(host->vmmc);
-
        for (i = 0; i < host->num_slots; i++) {
                struct dw_mci_slot *slot = host->slot[i];
                if (!slot)
@@ -1798,6 +1795,9 @@ static int dw_mci_resume(struct platform_device *pdev)
        int i, ret;
        struct dw_mci *host = platform_get_drvdata(pdev);
 
+       if (host->vmmc)
+               regulator_enable(host->vmmc);
+
        if (host->dma_ops->init)
                host->dma_ops->init(host);
 
index 4941e06fe2e17511b552bd5a605ea12fb86c5880..7721de942c69e29cd0d36300eb48a695dfbdafbf 100644 (file)
@@ -51,6 +51,7 @@ static unsigned int fmax = 515633;
  *               is asserted (likewise for RX)
  * @sdio: variant supports SDIO
  * @st_clkdiv: true if using a ST-specific clock divider algorithm
+ * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
  */
 struct variant_data {
        unsigned int            clkreg;
@@ -60,6 +61,7 @@ struct variant_data {
        unsigned int            fifohalfsize;
        bool                    sdio;
        bool                    st_clkdiv;
+       bool                    blksz_datactrl16;
 };
 
 static struct variant_data variant_arm = {
@@ -92,6 +94,17 @@ static struct variant_data variant_ux500 = {
        .st_clkdiv              = true,
 };
 
+static struct variant_data variant_ux500v2 = {
+       .fifosize               = 30 * 4,
+       .fifohalfsize           = 8 * 4,
+       .clkreg                 = MCI_CLK_ENABLE,
+       .clkreg_enable          = MCI_ST_UX500_HWFCEN,
+       .datalength_bits        = 24,
+       .sdio                   = true,
+       .st_clkdiv              = true,
+       .blksz_datactrl16       = true,
+};
+
 /*
  * This must be called with host->lock held
  */
@@ -465,7 +478,10 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
        blksz_bits = ffs(data->blksz) - 1;
        BUG_ON(1 << blksz_bits != data->blksz);
 
-       datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
+       if (variant->blksz_datactrl16)
+               datactrl = MCI_DPSM_ENABLE | (data->blksz << 16);
+       else
+               datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
 
        if (data->flags & MMC_DATA_READ)
                datactrl |= MCI_DPSM_DIRECTION;
@@ -1128,9 +1144,17 @@ static int __devinit mmci_probe(struct amba_device *dev,
                else if (ret != -ENOSYS)
                        goto err_gpio_cd;
 
+               /*
+                * A gpio pin that will detect cards when inserted and removed
+                * will most likely want to trigger on the edges if it is
+                * 0 when ejected and 1 when inserted (or mutatis mutandis
+                * for the inverted case) so we request triggers on both
+                * edges.
+                */
                ret = request_any_context_irq(gpio_to_irq(plat->gpio_cd),
-                                             mmci_cd_irq, 0,
-                                             DRIVER_NAME " (cd)", host);
+                               mmci_cd_irq,
+                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                               DRIVER_NAME " (cd)", host);
                if (ret >= 0)
                        host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd);
        }
@@ -1311,9 +1335,14 @@ static struct amba_id mmci_ids[] = {
        },
        {
                .id     = 0x00480180,
-               .mask   = 0x00ffffff,
+               .mask   = 0xf0ffffff,
                .data   = &variant_ux500,
        },
+       {
+               .id     = 0x10480180,
+               .mask   = 0xf0ffffff,
+               .data   = &variant_ux500v2,
+       },
        { 0, 0 },
 };
 
index 259ece047afcd6057bff748f7850d15430ae2136..5b2e2155b413bc988cabbd5125fe5c4c64f27d5b 100644 (file)
@@ -435,6 +435,9 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
                reg = regulator_get(host->dev, "vmmc_aux");
                host->vcc_aux = IS_ERR(reg) ? NULL : reg;
 
+               /* For eMMC do not power off when not in sleep state */
+               if (mmc_slot(host).no_regulator_off_init)
+                       return 0;
                /*
                * UGLY HACK:  workaround regulator framework bugs.
                * When the bootloader leaves a supply active, it's
index f8b5f37007b2a0b8115e62032664e6d96a04e214..936bbca19c0a47b13066b935221f2b583c574a3c 100644 (file)
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/device.h>
-
 #include <linux/mmc/host.h>
-
-#include <asm/scatterlist.h>
-#include <asm/io.h>
+#include <linux/scatterlist.h>
+#include <linux/io.h>
 
 #include "sdhci.h"
 
@@ -46,14 +44,14 @@ struct sdhci_pci_slot;
 struct sdhci_pci_fixes {
        unsigned int            quirks;
 
-       int                     (*probe)(struct sdhci_pci_chip*);
+       int                     (*probe) (struct sdhci_pci_chip *);
 
-       int                     (*probe_slot)(struct sdhci_pci_slot*);
-       void                    (*remove_slot)(struct sdhci_pci_slot*, int);
+       int                     (*probe_slot) (struct sdhci_pci_slot *);
+       void                    (*remove_slot) (struct sdhci_pci_slot *, int);
 
-       int                     (*suspend)(struct sdhci_pci_chip*,
+       int                     (*suspend) (struct sdhci_pci_chip *,
                                        pm_message_t);
-       int                     (*resume)(struct sdhci_pci_chip*);
+       int                     (*resume) (struct sdhci_pci_chip *);
 };
 
 struct sdhci_pci_slot {
@@ -329,6 +327,11 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
                return ret;
        }
 
+       /* quirk for unsable RO-detection on JM388 chips */
+       if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD ||
+           chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD)
+               chip->quirks |= SDHCI_QUIRK_UNSTABLE_RO_DETECT;
+
        return 0;
 }
 
@@ -402,7 +405,7 @@ static int jmicron_suspend(struct sdhci_pci_chip *chip, pm_message_t state)
 
        if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
            chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
-               for (i = 0;i < chip->num_slots;i++)
+               for (i = 0; i < chip->num_slots; i++)
                        jmicron_enable_mmc(chip->slots[i]->host, 0);
        }
 
@@ -415,7 +418,7 @@ static int jmicron_resume(struct sdhci_pci_chip *chip)
 
        if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
            chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
-               for (i = 0;i < chip->num_slots;i++)
+               for (i = 0; i < chip->num_slots; i++)
                        jmicron_enable_mmc(chip->slots[i]->host, 1);
        }
 
@@ -798,7 +801,7 @@ static struct sdhci_ops sdhci_pci_ops = {
 
 #ifdef CONFIG_PM
 
-static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
+static int sdhci_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct sdhci_pci_chip *chip;
        struct sdhci_pci_slot *slot;
@@ -810,7 +813,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
        if (!chip)
                return 0;
 
-       for (i = 0;i < chip->num_slots;i++) {
+       for (i = 0; i < chip->num_slots; i++) {
                slot = chip->slots[i];
                if (!slot)
                        continue;
@@ -818,7 +821,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
                ret = sdhci_suspend_host(slot->host, state);
 
                if (ret) {
-                       for (i--;i >= 0;i--)
+                       for (i--; i >= 0; i--)
                                sdhci_resume_host(chip->slots[i]->host);
                        return ret;
                }
@@ -833,7 +836,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
        if (chip->fixes && chip->fixes->suspend) {
                ret = chip->fixes->suspend(chip, state);
                if (ret) {
-                       for (i = chip->num_slots - 1;i >= 0;i--)
+                       for (i = chip->num_slots - 1; i >= 0; i--)
                                sdhci_resume_host(chip->slots[i]->host);
                        return ret;
                }
@@ -855,7 +858,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
        return 0;
 }
 
-static int sdhci_pci_resume (struct pci_dev *pdev)
+static int sdhci_pci_resume(struct pci_dev *pdev)
 {
        struct sdhci_pci_chip *chip;
        struct sdhci_pci_slot *slot;
@@ -877,7 +880,7 @@ static int sdhci_pci_resume (struct pci_dev *pdev)
                        return ret;
        }
 
-       for (i = 0;i < chip->num_slots;i++) {
+       for (i = 0; i < chip->num_slots; i++) {
                slot = chip->slots[i];
                if (!slot)
                        continue;
@@ -1059,7 +1062,7 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
        }
 
        chip->pdev = pdev;
-       chip->fixes = (const struct sdhci_pci_fixes*)ent->driver_data;
+       chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data;
        if (chip->fixes)
                chip->quirks = chip->fixes->quirks;
        chip->num_slots = slots;
@@ -1074,10 +1077,10 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
 
        slots = chip->num_slots;        /* Quirk may have changed this */
 
-       for (i = 0;i < slots;i++) {
+       for (i = 0; i < slots; i++) {
                slot = sdhci_pci_probe_slot(pdev, chip, first_bar + i);
                if (IS_ERR(slot)) {
-                       for (i--;i >= 0;i--)
+                       for (i--; i >= 0; i--)
                                sdhci_pci_remove_slot(chip->slots[i]);
                        ret = PTR_ERR(slot);
                        goto free;
@@ -1105,7 +1108,7 @@ static void __devexit sdhci_pci_remove(struct pci_dev *pdev)
        chip = pci_get_drvdata(pdev);
 
        if (chip) {
-               for (i = 0;i < chip->num_slots; i++)
+               for (i = 0; i < chip->num_slots; i++)
                        sdhci_pci_remove_slot(chip->slots[i]);
 
                pci_set_drvdata(pdev, NULL);
@@ -1116,9 +1119,9 @@ static void __devexit sdhci_pci_remove(struct pci_dev *pdev)
 }
 
 static struct pci_driver sdhci_driver = {
-       .name =         "sdhci-pci",
+       .name =         "sdhci-pci",
        .id_table =     pci_ids,
-       .probe =        sdhci_pci_probe,
+       .probe =        sdhci_pci_probe,
        .remove =       __devexit_p(sdhci_pci_remove),
        .suspend =      sdhci_pci_suspend,
        .resume =       sdhci_pci_resume,
index 5a61208cbc66c8f41f2f760b7321f07f1cd8e131..089c9a68b7b1df68d1cd6a06267aa985664ecfd7 100644 (file)
@@ -69,7 +69,45 @@ static void set_clock(struct sdhci_host *host, unsigned int clock)
        }
 }
 
+static int set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
+{
+       u16 ctrl_2;
+
+       /*
+        * Set V18_EN -- UHS modes do not work without this.
+        * does not change signaling voltage
+        */
+       ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+
+       /* Select Bus Speed Mode for host */
+       ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+       switch (uhs) {
+       case MMC_TIMING_UHS_SDR12:
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+               break;
+       case MMC_TIMING_UHS_SDR25:
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+               break;
+       case MMC_TIMING_UHS_SDR50:
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180;
+               break;
+       case MMC_TIMING_UHS_SDR104:
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180;
+               break;
+       case MMC_TIMING_UHS_DDR50:
+               ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180;
+               break;
+       }
+
+       sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+       pr_debug("%s:%s uhs = %d, ctrl_2 = %04X\n",
+               __func__, mmc_hostname(host->mmc), uhs, ctrl_2);
+
+       return 0;
+}
+
 static struct sdhci_ops sdhci_pxa_ops = {
+       .set_uhs_signaling = set_uhs_signaling,
        .set_clock = set_clock,
 };
 
@@ -136,11 +174,19 @@ static int __devinit sdhci_pxa_probe(struct platform_device *pdev)
        host->hw_name = "MMC";
        host->ops = &sdhci_pxa_ops;
        host->irq = irq;
-       host->quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+       host->quirks = SDHCI_QUIRK_BROKEN_ADMA
+               | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
+               | SDHCI_QUIRK_32BIT_DMA_ADDR
+               | SDHCI_QUIRK_32BIT_DMA_SIZE
+               | SDHCI_QUIRK_32BIT_ADMA_SIZE
+               | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC;
 
        if (pdata->quirks)
                host->quirks |= pdata->quirks;
 
+       /* enable 1/8V DDR capable */
+       host->mmc->caps |= MMC_CAP_1_8V_DDR;
+
        /* If slot design supports 8 bit data, indicate this to MMC. */
        if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT)
                host->mmc->caps |= MMC_CAP_8_BIT_DATA;
index f7e1f964395fd5bb46264e98c0e474046204293b..343c97edba32bfc780295784cc25869699b734d5 100644 (file)
@@ -184,6 +184,8 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
        clk_enable(clk);
        pltfm_host->clk = clk;
 
+       host->mmc->pm_caps = plat->pm_flags;
+
        if (plat->is_8bit)
                host->mmc->caps |= MMC_CAP_8_BIT_DATA;
 
index 5d20661bc357ba387601b6b2089185bceb144aac..58d5436ff649fb7b0319657464344be692a583c8 100644 (file)
 #define SDHCI_USE_LEDS_CLASS
 #endif
 
+#define MAX_TUNING_LOOP 40
+
 static unsigned int debug_quirks = 0;
 
-static void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *);
 static void sdhci_finish_data(struct sdhci_host *);
 
 static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
 static void sdhci_finish_command(struct sdhci_host *);
+static int sdhci_execute_tuning(struct mmc_host *mmc);
+static void sdhci_tuning_timer(unsigned long data);
 
 static void sdhci_dumpregs(struct sdhci_host *host)
 {
@@ -84,6 +87,8 @@ static void sdhci_dumpregs(struct sdhci_host *host)
        printk(KERN_DEBUG DRIVER_NAME ": Cmd:      0x%08x | Max curr: 0x%08x\n",
                sdhci_readw(host, SDHCI_COMMAND),
                sdhci_readl(host, SDHCI_MAX_CURRENT));
+       printk(KERN_DEBUG DRIVER_NAME ": Host ctl2: 0x%08x\n",
+               sdhci_readw(host, SDHCI_HOST_CONTROL2));
 
        if (host->flags & SDHCI_USE_ADMA)
                printk(KERN_DEBUG DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
@@ -157,6 +162,9 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
        if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
                ier = sdhci_readl(host, SDHCI_INT_ENABLE);
 
+       if (host->ops->platform_reset_enter)
+               host->ops->platform_reset_enter(host, mask);
+
        sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
 
        if (mask & SDHCI_RESET_ALL)
@@ -177,6 +185,9 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
                mdelay(1);
        }
 
+       if (host->ops->platform_reset_exit)
+               host->ops->platform_reset_exit(host, mask);
+
        if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
                sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
 }
@@ -591,9 +602,10 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
                data->sg_len, direction);
 }
 
-static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
+static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 {
        u8 count;
+       struct mmc_data *data = cmd->data;
        unsigned target_timeout, current_timeout;
 
        /*
@@ -605,9 +617,16 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
        if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
                return 0xE;
 
+       /* Unspecified timeout, assume max */
+       if (!data && !cmd->cmd_timeout_ms)
+               return 0xE;
+
        /* timeout in us */
-       target_timeout = data->timeout_ns / 1000 +
-               data->timeout_clks / host->clock;
+       if (!data)
+               target_timeout = cmd->cmd_timeout_ms * 1000;
+       else
+               target_timeout = data->timeout_ns / 1000 +
+                       data->timeout_clks / host->clock;
 
        if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
                host->timeout_clk = host->clock / 1000;
@@ -622,6 +641,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
         *     =>
         *     (1) / (2) > 2^6
         */
+       BUG_ON(!host->timeout_clk);
        count = 0;
        current_timeout = (1 << 13) * 1000 / host->timeout_clk;
        while (current_timeout < target_timeout) {
@@ -632,8 +652,8 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
        }
 
        if (count >= 0xF) {
-               printk(KERN_WARNING "%s: Too large timeout requested!\n",
-                       mmc_hostname(host->mmc));
+               printk(KERN_WARNING "%s: Too large timeout requested for CMD%d!\n",
+                      mmc_hostname(host->mmc), cmd->opcode);
                count = 0xE;
        }
 
@@ -651,15 +671,21 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
                sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
 }
 
-static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
+static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
 {
        u8 count;
        u8 ctrl;
+       struct mmc_data *data = cmd->data;
        int ret;
 
        WARN_ON(host->data);
 
-       if (data == NULL)
+       if (data || (cmd->flags & MMC_RSP_BUSY)) {
+               count = sdhci_calc_timeout(host, cmd);
+               sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
+       }
+
+       if (!data)
                return;
 
        /* Sanity checks */
@@ -669,9 +695,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 
        host->data = data;
        host->data_early = 0;
-
-       count = sdhci_calc_timeout(host, data);
-       sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
+       host->data->bytes_xfered = 0;
 
        if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))
                host->flags |= SDHCI_REQ_USE_DMA;
@@ -807,15 +831,17 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 
        sdhci_set_transfer_irqs(host);
 
-       /* We do not handle DMA boundaries, so set it to max (512 KiB) */
-       sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, data->blksz), SDHCI_BLOCK_SIZE);
+       /* Set the DMA boundary value and block size */
+       sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
+               data->blksz), SDHCI_BLOCK_SIZE);
        sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
 }
 
 static void sdhci_set_transfer_mode(struct sdhci_host *host,
-       struct mmc_data *data)
+       struct mmc_command *cmd)
 {
        u16 mode;
+       struct mmc_data *data = cmd->data;
 
        if (data == NULL)
                return;
@@ -823,12 +849,20 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
        WARN_ON(!host->data);
 
        mode = SDHCI_TRNS_BLK_CNT_EN;
-       if (data->blocks > 1) {
-               if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
-                       mode |= SDHCI_TRNS_MULTI | SDHCI_TRNS_ACMD12;
-               else
-                       mode |= SDHCI_TRNS_MULTI;
+       if (mmc_op_multi(cmd->opcode) || data->blocks > 1) {
+               mode |= SDHCI_TRNS_MULTI;
+               /*
+                * If we are sending CMD23, CMD12 never gets sent
+                * on successful completion (so no Auto-CMD12).
+                */
+               if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12))
+                       mode |= SDHCI_TRNS_AUTO_CMD12;
+               else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
+                       mode |= SDHCI_TRNS_AUTO_CMD23;
+                       sdhci_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2);
+               }
        }
+
        if (data->flags & MMC_DATA_READ)
                mode |= SDHCI_TRNS_READ;
        if (host->flags & SDHCI_REQ_USE_DMA)
@@ -868,7 +902,15 @@ static void sdhci_finish_data(struct sdhci_host *host)
        else
                data->bytes_xfered = data->blksz * data->blocks;
 
-       if (data->stop) {
+       /*
+        * Need to send CMD12 if -
+        * a) open-ended multiblock transfer (no CMD23)
+        * b) error in multiblock transfer
+        */
+       if (data->stop &&
+           (data->error ||
+            !host->mrq->sbc)) {
+
                /*
                 * The controller needs a reset of internal state machines
                 * upon error conditions.
@@ -920,11 +962,11 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 
        host->cmd = cmd;
 
-       sdhci_prepare_data(host, cmd->data);
+       sdhci_prepare_data(host, cmd);
 
        sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
 
-       sdhci_set_transfer_mode(host, cmd->data);
+       sdhci_set_transfer_mode(host, cmd);
 
        if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
                printk(KERN_ERR "%s: Unsupported response type!\n",
@@ -947,7 +989,9 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
                flags |= SDHCI_CMD_CRC;
        if (cmd->flags & MMC_RSP_OPCODE)
                flags |= SDHCI_CMD_INDEX;
-       if (cmd->data)
+
+       /* CMD19 is special in that the Data Present Select should be set */
+       if (cmd->data || (cmd->opcode == MMC_SEND_TUNING_BLOCK))
                flags |= SDHCI_CMD_DATA;
 
        sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
@@ -977,19 +1021,27 @@ static void sdhci_finish_command(struct sdhci_host *host)
 
        host->cmd->error = 0;
 
-       if (host->data && host->data_early)
-               sdhci_finish_data(host);
+       /* Finished CMD23, now send actual command. */
+       if (host->cmd == host->mrq->sbc) {
+               host->cmd = NULL;
+               sdhci_send_command(host, host->mrq->cmd);
+       } else {
 
-       if (!host->cmd->data)
-               tasklet_schedule(&host->finish_tasklet);
+               /* Processed actual command. */
+               if (host->data && host->data_early)
+                       sdhci_finish_data(host);
 
-       host->cmd = NULL;
+               if (!host->cmd->data)
+                       tasklet_schedule(&host->finish_tasklet);
+
+               host->cmd = NULL;
+       }
 }
 
 static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 {
-       int div;
-       u16 clk;
+       int div = 0; /* Initialized for compiler warning */
+       u16 clk = 0;
        unsigned long timeout;
 
        if (clock == host->clock)
@@ -1007,14 +1059,45 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
                goto out;
 
        if (host->version >= SDHCI_SPEC_300) {
-               /* Version 3.00 divisors must be a multiple of 2. */
-               if (host->max_clk <= clock)
-                       div = 1;
-               else {
-                       for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) {
-                               if ((host->max_clk / div) <= clock)
-                                       break;
+               /*
+                * Check if the Host Controller supports Programmable Clock
+                * Mode.
+                */
+               if (host->clk_mul) {
+                       u16 ctrl;
+
+                       /*
+                        * We need to figure out whether the Host Driver needs
+                        * to select Programmable Clock Mode, or the value can
+                        * be set automatically by the Host Controller based on
+                        * the Preset Value registers.
+                        */
+                       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+                       if (!(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
+                               for (div = 1; div <= 1024; div++) {
+                                       if (((host->max_clk * host->clk_mul) /
+                                             div) <= clock)
+                                               break;
+                               }
+                               /*
+                                * Set Programmable Clock Mode in the Clock
+                                * Control register.
+                                */
+                               clk = SDHCI_PROG_CLOCK_MODE;
+                               div--;
                        }
+               } else {
+                       /* Version 3.00 divisors must be a multiple of 2. */
+                       if (host->max_clk <= clock)
+                               div = 1;
+                       else {
+                               for (div = 2; div < SDHCI_MAX_DIV_SPEC_300;
+                                    div += 2) {
+                                       if ((host->max_clk / div) <= clock)
+                                               break;
+                               }
+                       }
+                       div >>= 1;
                }
        } else {
                /* Version 2.00 divisors must be a power of 2. */
@@ -1022,10 +1105,10 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
                        if ((host->max_clk / div) <= clock)
                                break;
                }
+               div >>= 1;
        }
-       div >>= 1;
 
-       clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
+       clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
        clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
                << SDHCI_DIVIDER_HI_SHIFT;
        clk |= SDHCI_CLOCK_INT_EN;
@@ -1131,7 +1214,12 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 #ifndef SDHCI_USE_LEDS_CLASS
        sdhci_activate_led(host);
 #endif
-       if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) {
+
+       /*
+        * Ensure we don't send the STOP for non-SET_BLOCK_COUNTED
+        * requests if Auto-CMD12 is enabled.
+        */
+       if (!mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) {
                if (mrq->stop) {
                        mrq->data->stop = NULL;
                        mrq->stop = NULL;
@@ -1150,8 +1238,30 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
        if (!present || host->flags & SDHCI_DEVICE_DEAD) {
                host->mrq->cmd->error = -ENOMEDIUM;
                tasklet_schedule(&host->finish_tasklet);
-       } else
-               sdhci_send_command(host, mrq->cmd);
+       } else {
+               u32 present_state;
+
+               present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
+               /*
+                * Check if the re-tuning timer has already expired and there
+                * is no on-going data transfer. If so, we need to execute
+                * tuning procedure before sending command.
+                */
+               if ((host->flags & SDHCI_NEEDS_RETUNING) &&
+                   !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) {
+                       spin_unlock_irqrestore(&host->lock, flags);
+                       sdhci_execute_tuning(mmc);
+                       spin_lock_irqsave(&host->lock, flags);
+
+                       /* Restore original mmc_request structure */
+                       host->mrq = mrq;
+               }
+
+               if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23))
+                       sdhci_send_command(host, mrq->sbc);
+               else
+                       sdhci_send_command(host, mrq->cmd);
+       }
 
        mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
@@ -1222,7 +1332,84 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        else
                ctrl &= ~SDHCI_CTRL_HISPD;
 
-       sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+       if (host->version >= SDHCI_SPEC_300) {
+               u16 clk, ctrl_2;
+               unsigned int clock;
+
+               /* In case of UHS-I modes, set High Speed Enable */
+               if ((ios->timing == MMC_TIMING_UHS_SDR50) ||
+                   (ios->timing == MMC_TIMING_UHS_SDR104) ||
+                   (ios->timing == MMC_TIMING_UHS_DDR50) ||
+                   (ios->timing == MMC_TIMING_UHS_SDR25) ||
+                   (ios->timing == MMC_TIMING_UHS_SDR12))
+                       ctrl |= SDHCI_CTRL_HISPD;
+
+               ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+               if (!(ctrl_2 & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
+                       sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+                       /*
+                        * We only need to set Driver Strength if the
+                        * preset value enable is not set.
+                        */
+                       ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK;
+                       if (ios->drv_type == MMC_SET_DRIVER_TYPE_A)
+                               ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A;
+                       else if (ios->drv_type == MMC_SET_DRIVER_TYPE_C)
+                               ctrl_2 |= SDHCI_CTRL_DRV_TYPE_C;
+
+                       sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+               } else {
+                       /*
+                        * According to SDHC Spec v3.00, if the Preset Value
+                        * Enable in the Host Control 2 register is set, we
+                        * need to reset SD Clock Enable before changing High
+                        * Speed Enable to avoid generating clock gliches.
+                        */
+
+                       /* Reset SD Clock Enable */
+                       clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+                       clk &= ~SDHCI_CLOCK_CARD_EN;
+                       sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+                       sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+
+                       /* Re-enable SD Clock */
+                       clock = host->clock;
+                       host->clock = 0;
+                       sdhci_set_clock(host, clock);
+               }
+
+
+               /* Reset SD Clock Enable */
+               clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+               clk &= ~SDHCI_CLOCK_CARD_EN;
+               sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+               if (host->ops->set_uhs_signaling)
+                       host->ops->set_uhs_signaling(host, ios->timing);
+               else {
+                       ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+                       /* Select Bus Speed Mode for host */
+                       ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+                       if (ios->timing == MMC_TIMING_UHS_SDR12)
+                               ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+                       else if (ios->timing == MMC_TIMING_UHS_SDR25)
+                               ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+                       else if (ios->timing == MMC_TIMING_UHS_SDR50)
+                               ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
+                       else if (ios->timing == MMC_TIMING_UHS_SDR104)
+                               ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
+                       else if (ios->timing == MMC_TIMING_UHS_DDR50)
+                               ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+                       sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+               }
+
+               /* Re-enable SD Clock */
+               clock = host->clock;
+               host->clock = 0;
+               sdhci_set_clock(host, clock);
+       } else
+               sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
        /*
         * Some (ENE) controllers go apeshit on some ios operation,
@@ -1237,14 +1424,11 @@ out:
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int sdhci_get_ro(struct mmc_host *mmc)
+static int check_ro(struct sdhci_host *host)
 {
-       struct sdhci_host *host;
        unsigned long flags;
        int is_readonly;
 
-       host = mmc_priv(mmc);
-
        spin_lock_irqsave(&host->lock, flags);
 
        if (host->flags & SDHCI_DEVICE_DEAD)
@@ -1262,6 +1446,29 @@ static int sdhci_get_ro(struct mmc_host *mmc)
                !is_readonly : is_readonly;
 }
 
+#define SAMPLE_COUNT   5
+
+static int sdhci_get_ro(struct mmc_host *mmc)
+{
+       struct sdhci_host *host;
+       int i, ro_count;
+
+       host = mmc_priv(mmc);
+
+       if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT))
+               return check_ro(host);
+
+       ro_count = 0;
+       for (i = 0; i < SAMPLE_COUNT; i++) {
+               if (check_ro(host)) {
+                       if (++ro_count > SAMPLE_COUNT / 2)
+                               return 1;
+               }
+               msleep(30);
+       }
+       return 0;
+}
+
 static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
 {
        struct sdhci_host *host;
@@ -1284,11 +1491,322 @@ out:
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
+static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
+       struct mmc_ios *ios)
+{
+       struct sdhci_host *host;
+       u8 pwr;
+       u16 clk, ctrl;
+       u32 present_state;
+
+       host = mmc_priv(mmc);
+
+       /*
+        * Signal Voltage Switching is only applicable for Host Controllers
+        * v3.00 and above.
+        */
+       if (host->version < SDHCI_SPEC_300)
+               return 0;
+
+       /*
+        * We first check whether the request is to set signalling voltage
+        * to 3.3V. If so, we change the voltage to 3.3V and return quickly.
+        */
+       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+       if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+               /* Set 1.8V Signal Enable in the Host Control2 register to 0 */
+               ctrl &= ~SDHCI_CTRL_VDD_180;
+               sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+               /* Wait for 5ms */
+               usleep_range(5000, 5500);
+
+               /* 3.3V regulator output should be stable within 5 ms */
+               ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+               if (!(ctrl & SDHCI_CTRL_VDD_180))
+                       return 0;
+               else {
+                       printk(KERN_INFO DRIVER_NAME ": Switching to 3.3V "
+                               "signalling voltage failed\n");
+                       return -EIO;
+               }
+       } else if (!(ctrl & SDHCI_CTRL_VDD_180) &&
+                 (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)) {
+               /* Stop SDCLK */
+               clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+               clk &= ~SDHCI_CLOCK_CARD_EN;
+               sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+               /* Check whether DAT[3:0] is 0000 */
+               present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
+               if (!((present_state & SDHCI_DATA_LVL_MASK) >>
+                      SDHCI_DATA_LVL_SHIFT)) {
+                       /*
+                        * Enable 1.8V Signal Enable in the Host Control2
+                        * register
+                        */
+                       ctrl |= SDHCI_CTRL_VDD_180;
+                       sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+                       /* Wait for 5ms */
+                       usleep_range(5000, 5500);
+
+                       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+                       if (ctrl & SDHCI_CTRL_VDD_180) {
+                               /* Provide SDCLK again and wait for 1ms*/
+                               clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+                               clk |= SDHCI_CLOCK_CARD_EN;
+                               sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+                               usleep_range(1000, 1500);
+
+                               /*
+                                * If DAT[3:0] level is 1111b, then the card
+                                * was successfully switched to 1.8V signaling.
+                                */
+                               present_state = sdhci_readl(host,
+                                                       SDHCI_PRESENT_STATE);
+                               if ((present_state & SDHCI_DATA_LVL_MASK) ==
+                                    SDHCI_DATA_LVL_MASK)
+                                       return 0;
+                       }
+               }
+
+               /*
+                * If we are here, that means the switch to 1.8V signaling
+                * failed. We power cycle the card, and retry initialization
+                * sequence by setting S18R to 0.
+                */
+               pwr = sdhci_readb(host, SDHCI_POWER_CONTROL);
+               pwr &= ~SDHCI_POWER_ON;
+               sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+
+               /* Wait for 1ms as per the spec */
+               usleep_range(1000, 1500);
+               pwr |= SDHCI_POWER_ON;
+               sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+
+               printk(KERN_INFO DRIVER_NAME ": Switching to 1.8V signalling "
+                       "voltage failed, retrying with S18R set to 0\n");
+               return -EAGAIN;
+       } else
+               /* No signal voltage switch required */
+               return 0;
+}
+
+static int sdhci_execute_tuning(struct mmc_host *mmc)
+{
+       struct sdhci_host *host;
+       u16 ctrl;
+       u32 ier;
+       int tuning_loop_counter = MAX_TUNING_LOOP;
+       unsigned long timeout;
+       int err = 0;
+
+       host = mmc_priv(mmc);
+
+       disable_irq(host->irq);
+       spin_lock(&host->lock);
+
+       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+
+       /*
+        * Host Controller needs tuning only in case of SDR104 mode
+        * and for SDR50 mode when Use Tuning for SDR50 is set in
+        * Capabilities register.
+        */
+       if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) ||
+           (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
+           (host->flags & SDHCI_SDR50_NEEDS_TUNING)))
+               ctrl |= SDHCI_CTRL_EXEC_TUNING;
+       else {
+               spin_unlock(&host->lock);
+               enable_irq(host->irq);
+               return 0;
+       }
+
+       sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+       /*
+        * As per the Host Controller spec v3.00, tuning command
+        * generates Buffer Read Ready interrupt, so enable that.
+        *
+        * Note: The spec clearly says that when tuning sequence
+        * is being performed, the controller does not generate
+        * interrupts other than Buffer Read Ready interrupt. But
+        * to make sure we don't hit a controller bug, we _only_
+        * enable Buffer Read Ready interrupt here.
+        */
+       ier = sdhci_readl(host, SDHCI_INT_ENABLE);
+       sdhci_clear_set_irqs(host, ier, SDHCI_INT_DATA_AVAIL);
+
+       /*
+        * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
+        * of loops reaches 40 times or a timeout of 150ms occurs.
+        */
+       timeout = 150;
+       do {
+               struct mmc_command cmd = {0};
+               struct mmc_request mrq = {0};
+
+               if (!tuning_loop_counter && !timeout)
+                       break;
+
+               cmd.opcode = MMC_SEND_TUNING_BLOCK;
+               cmd.arg = 0;
+               cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+               cmd.retries = 0;
+               cmd.data = NULL;
+               cmd.error = 0;
+
+               mrq.cmd = &cmd;
+               host->mrq = &mrq;
+
+               /*
+                * In response to CMD19, the card sends 64 bytes of tuning
+                * block to the Host Controller. So we set the block size
+                * to 64 here.
+                */
+               sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE);
+
+               /*
+                * The tuning block is sent by the card to the host controller.
+                * So we set the TRNS_READ bit in the Transfer Mode register.
+                * This also takes care of setting DMA Enable and Multi Block
+                * Select in the same register to 0.
+                */
+               sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
+
+               sdhci_send_command(host, &cmd);
+
+               host->cmd = NULL;
+               host->mrq = NULL;
+
+               spin_unlock(&host->lock);
+               enable_irq(host->irq);
+
+               /* Wait for Buffer Read Ready interrupt */
+               wait_event_interruptible_timeout(host->buf_ready_int,
+                                       (host->tuning_done == 1),
+                                       msecs_to_jiffies(50));
+               disable_irq(host->irq);
+               spin_lock(&host->lock);
+
+               if (!host->tuning_done) {
+                       printk(KERN_INFO DRIVER_NAME ": Timeout waiting for "
+                               "Buffer Read Ready interrupt during tuning "
+                               "procedure, falling back to fixed sampling "
+                               "clock\n");
+                       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+                       ctrl &= ~SDHCI_CTRL_TUNED_CLK;
+                       ctrl &= ~SDHCI_CTRL_EXEC_TUNING;
+                       sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+                       err = -EIO;
+                       goto out;
+               }
+
+               host->tuning_done = 0;
+
+               ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+               tuning_loop_counter--;
+               timeout--;
+               mdelay(1);
+       } while (ctrl & SDHCI_CTRL_EXEC_TUNING);
+
+       /*
+        * The Host Driver has exhausted the maximum number of loops allowed,
+        * so use fixed sampling frequency.
+        */
+       if (!tuning_loop_counter || !timeout) {
+               ctrl &= ~SDHCI_CTRL_TUNED_CLK;
+               sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+       } else {
+               if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
+                       printk(KERN_INFO DRIVER_NAME ": Tuning procedure"
+                               " failed, falling back to fixed sampling"
+                               " clock\n");
+                       err = -EIO;
+               }
+       }
+
+out:
+       /*
+        * If this is the very first time we are here, we start the retuning
+        * timer. Since only during the first time, SDHCI_NEEDS_RETUNING
+        * flag won't be set, we check this condition before actually starting
+        * the timer.
+        */
+       if (!(host->flags & SDHCI_NEEDS_RETUNING) && host->tuning_count &&
+           (host->tuning_mode == SDHCI_TUNING_MODE_1)) {
+               mod_timer(&host->tuning_timer, jiffies +
+                       host->tuning_count * HZ);
+               /* Tuning mode 1 limits the maximum data length to 4MB */
+               mmc->max_blk_count = (4 * 1024 * 1024) / mmc->max_blk_size;
+       } else {
+               host->flags &= ~SDHCI_NEEDS_RETUNING;
+               /* Reload the new initial value for timer */
+               if (host->tuning_mode == SDHCI_TUNING_MODE_1)
+                       mod_timer(&host->tuning_timer, jiffies +
+                               host->tuning_count * HZ);
+       }
+
+       /*
+        * In case tuning fails, host controllers which support re-tuning can
+        * try tuning again at a later time, when the re-tuning timer expires.
+        * So for these controllers, we return 0. Since there might be other
+        * controllers who do not have this capability, we return error for
+        * them.
+        */
+       if (err && host->tuning_count &&
+           host->tuning_mode == SDHCI_TUNING_MODE_1)
+               err = 0;
+
+       sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier);
+       spin_unlock(&host->lock);
+       enable_irq(host->irq);
+
+       return err;
+}
+
+static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
+{
+       struct sdhci_host *host;
+       u16 ctrl;
+       unsigned long flags;
+
+       host = mmc_priv(mmc);
+
+       /* Host Controller v3.00 defines preset value registers */
+       if (host->version < SDHCI_SPEC_300)
+               return;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+
+       /*
+        * We only enable or disable Preset Value if they are not already
+        * enabled or disabled respectively. Otherwise, we bail out.
+        */
+       if (enable && !(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
+               ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE;
+               sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+       } else if (!enable && (ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
+               ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
+               sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+       }
+
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
 static const struct mmc_host_ops sdhci_ops = {
        .request        = sdhci_request,
        .set_ios        = sdhci_set_ios,
        .get_ro         = sdhci_get_ro,
        .enable_sdio_irq = sdhci_enable_sdio_irq,
+       .start_signal_voltage_switch    = sdhci_start_signal_voltage_switch,
+       .execute_tuning                 = sdhci_execute_tuning,
+       .enable_preset_value            = sdhci_enable_preset_value,
 };
 
 /*****************************************************************************\
@@ -1345,6 +1863,9 @@ static void sdhci_tasklet_finish(unsigned long param)
 
        del_timer(&host->timer);
 
+       if (host->version >= SDHCI_SPEC_300)
+               del_timer(&host->tuning_timer);
+
        mrq = host->mrq;
 
        /*
@@ -1418,6 +1939,20 @@ static void sdhci_timeout_timer(unsigned long data)
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
+static void sdhci_tuning_timer(unsigned long data)
+{
+       struct sdhci_host *host;
+       unsigned long flags;
+
+       host = (struct sdhci_host *)data;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       host->flags |= SDHCI_NEEDS_RETUNING;
+
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
 /*****************************************************************************\
  *                                                                           *
  * Interrupt handling                                                        *
@@ -1506,6 +2041,16 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 {
        BUG_ON(intmask == 0);
 
+       /* CMD19 generates _only_ Buffer Read Ready interrupt */
+       if (intmask & SDHCI_INT_DATA_AVAIL) {
+               if (SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) ==
+                   MMC_SEND_TUNING_BLOCK) {
+                       host->tuning_done = 1;
+                       wake_up(&host->buf_ready_int);
+                       return;
+               }
+       }
+
        if (!host->data) {
                /*
                 * The "data complete" interrupt is also used to
@@ -1551,10 +2096,28 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
                 * We currently don't do anything fancy with DMA
                 * boundaries, but as we can't disable the feature
                 * we need to at least restart the transfer.
+                *
+                * According to the spec sdhci_readl(host, SDHCI_DMA_ADDRESS)
+                * should return a valid address to continue from, but as
+                * some controllers are faulty, don't trust them.
                 */
-               if (intmask & SDHCI_INT_DMA_END)
-                       sdhci_writel(host, sdhci_readl(host, SDHCI_DMA_ADDRESS),
-                               SDHCI_DMA_ADDRESS);
+               if (intmask & SDHCI_INT_DMA_END) {
+                       u32 dmastart, dmanow;
+                       dmastart = sg_dma_address(host->data->sg);
+                       dmanow = dmastart + host->data->bytes_xfered;
+                       /*
+                        * Force update to the next DMA block boundary.
+                        */
+                       dmanow = (dmanow &
+                               ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
+                               SDHCI_DEFAULT_BOUNDARY_SIZE;
+                       host->data->bytes_xfered = dmanow - dmastart;
+                       DBG("%s: DMA base 0x%08x, transferred 0x%06x bytes,"
+                               " next 0x%08x\n",
+                               mmc_hostname(host->mmc), dmastart,
+                               host->data->bytes_xfered, dmanow);
+                       sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
+               }
 
                if (intmask & SDHCI_INT_DATA_END) {
                        if (host->cmd) {
@@ -1664,6 +2227,14 @@ int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state)
 
        sdhci_disable_card_detection(host);
 
+       /* Disable tuning since we are suspending */
+       if (host->version >= SDHCI_SPEC_300 && host->tuning_count &&
+           host->tuning_mode == SDHCI_TUNING_MODE_1) {
+               host->flags &= ~SDHCI_NEEDS_RETUNING;
+               mod_timer(&host->tuning_timer, jiffies +
+                       host->tuning_count * HZ);
+       }
+
        ret = mmc_suspend_host(host->mmc);
        if (ret)
                return ret;
@@ -1705,6 +2276,11 @@ int sdhci_resume_host(struct sdhci_host *host)
        ret = mmc_resume_host(host->mmc);
        sdhci_enable_card_detection(host);
 
+       /* Set the re-tuning expiration flag */
+       if ((host->version >= SDHCI_SPEC_300) && host->tuning_count &&
+           (host->tuning_mode == SDHCI_TUNING_MODE_1))
+               host->flags |= SDHCI_NEEDS_RETUNING;
+
        return ret;
 }
 
@@ -1751,7 +2327,9 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host);
 int sdhci_add_host(struct sdhci_host *host)
 {
        struct mmc_host *mmc;
-       unsigned int caps, ocr_avail;
+       u32 caps[2];
+       u32 max_current_caps;
+       unsigned int ocr_avail;
        int ret;
 
        WARN_ON(host == NULL);
@@ -1774,12 +2352,15 @@ int sdhci_add_host(struct sdhci_host *host)
                        host->version);
        }
 
-       caps = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
+       caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
                sdhci_readl(host, SDHCI_CAPABILITIES);
 
+       caps[1] = (host->version >= SDHCI_SPEC_300) ?
+               sdhci_readl(host, SDHCI_CAPABILITIES_1) : 0;
+
        if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
                host->flags |= SDHCI_USE_SDMA;
-       else if (!(caps & SDHCI_CAN_DO_SDMA))
+       else if (!(caps[0] & SDHCI_CAN_DO_SDMA))
                DBG("Controller doesn't have SDMA capability\n");
        else
                host->flags |= SDHCI_USE_SDMA;
@@ -1790,7 +2371,8 @@ int sdhci_add_host(struct sdhci_host *host)
                host->flags &= ~SDHCI_USE_SDMA;
        }
 
-       if ((host->version >= SDHCI_SPEC_200) && (caps & SDHCI_CAN_DO_ADMA2))
+       if ((host->version >= SDHCI_SPEC_200) &&
+               (caps[0] & SDHCI_CAN_DO_ADMA2))
                host->flags |= SDHCI_USE_ADMA;
 
        if ((host->quirks & SDHCI_QUIRK_BROKEN_ADMA) &&
@@ -1840,10 +2422,10 @@ int sdhci_add_host(struct sdhci_host *host)
        }
 
        if (host->version >= SDHCI_SPEC_300)
-               host->max_clk = (caps & SDHCI_CLOCK_V3_BASE_MASK)
+               host->max_clk = (caps[0] & SDHCI_CLOCK_V3_BASE_MASK)
                        >> SDHCI_CLOCK_BASE_SHIFT;
        else
-               host->max_clk = (caps & SDHCI_CLOCK_BASE_MASK)
+               host->max_clk = (caps[0] & SDHCI_CLOCK_BASE_MASK)
                        >> SDHCI_CLOCK_BASE_SHIFT;
 
        host->max_clk *= 1000000;
@@ -1859,7 +2441,7 @@ int sdhci_add_host(struct sdhci_host *host)
        }
 
        host->timeout_clk =
-               (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
+               (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
        if (host->timeout_clk == 0) {
                if (host->ops->get_timeout_clock) {
                        host->timeout_clk = host->ops->get_timeout_clock(host);
@@ -1871,22 +2453,55 @@ int sdhci_add_host(struct sdhci_host *host)
                        return -ENODEV;
                }
        }
-       if (caps & SDHCI_TIMEOUT_CLK_UNIT)
+       if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
                host->timeout_clk *= 1000;
 
+       /*
+        * In case of Host Controller v3.00, find out whether clock
+        * multiplier is supported.
+        */
+       host->clk_mul = (caps[1] & SDHCI_CLOCK_MUL_MASK) >>
+                       SDHCI_CLOCK_MUL_SHIFT;
+
+       /*
+        * In case the value in Clock Multiplier is 0, then programmable
+        * clock mode is not supported, otherwise the actual clock
+        * multiplier is one more than the value of Clock Multiplier
+        * in the Capabilities Register.
+        */
+       if (host->clk_mul)
+               host->clk_mul += 1;
+
        /*
         * Set host parameters.
         */
        mmc->ops = &sdhci_ops;
+       mmc->f_max = host->max_clk;
        if (host->ops->get_min_clock)
                mmc->f_min = host->ops->get_min_clock(host);
-       else if (host->version >= SDHCI_SPEC_300)
-               mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
-       else
+       else if (host->version >= SDHCI_SPEC_300) {
+               if (host->clk_mul) {
+                       mmc->f_min = (host->max_clk * host->clk_mul) / 1024;
+                       mmc->f_max = host->max_clk * host->clk_mul;
+               } else
+                       mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
+       } else
                mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
 
-       mmc->f_max = host->max_clk;
-       mmc->caps |= MMC_CAP_SDIO_IRQ;
+       mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
+
+       if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
+               host->flags |= SDHCI_AUTO_CMD12;
+
+       /* Auto-CMD23 stuff only works in ADMA or PIO. */
+       if ((host->version >= SDHCI_SPEC_300) &&
+           ((host->flags & SDHCI_USE_ADMA) ||
+            !(host->flags & SDHCI_USE_SDMA))) {
+               host->flags |= SDHCI_AUTO_CMD23;
+               DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc));
+       } else {
+               DBG("%s: Auto-CMD23 unavailable\n", mmc_hostname(mmc));
+       }
 
        /*
         * A controller may support 8-bit width, but the board itself
@@ -1898,21 +2513,113 @@ int sdhci_add_host(struct sdhci_host *host)
        if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
                mmc->caps |= MMC_CAP_4_BIT_DATA;
 
-       if (caps & SDHCI_CAN_DO_HISPD)
+       if (caps[0] & SDHCI_CAN_DO_HISPD)
                mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
 
        if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
            mmc_card_is_removable(mmc))
                mmc->caps |= MMC_CAP_NEEDS_POLL;
 
+       /* UHS-I mode(s) supported by the host controller. */
+       if (host->version >= SDHCI_SPEC_300)
+               mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
+
+       /* SDR104 supports also implies SDR50 support */
+       if (caps[1] & SDHCI_SUPPORT_SDR104)
+               mmc->caps |= MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50;
+       else if (caps[1] & SDHCI_SUPPORT_SDR50)
+               mmc->caps |= MMC_CAP_UHS_SDR50;
+
+       if (caps[1] & SDHCI_SUPPORT_DDR50)
+               mmc->caps |= MMC_CAP_UHS_DDR50;
+
+       /* Does the host needs tuning for SDR50? */
+       if (caps[1] & SDHCI_USE_SDR50_TUNING)
+               host->flags |= SDHCI_SDR50_NEEDS_TUNING;
+
+       /* Driver Type(s) (A, C, D) supported by the host */
+       if (caps[1] & SDHCI_DRIVER_TYPE_A)
+               mmc->caps |= MMC_CAP_DRIVER_TYPE_A;
+       if (caps[1] & SDHCI_DRIVER_TYPE_C)
+               mmc->caps |= MMC_CAP_DRIVER_TYPE_C;
+       if (caps[1] & SDHCI_DRIVER_TYPE_D)
+               mmc->caps |= MMC_CAP_DRIVER_TYPE_D;
+
+       /* Initial value for re-tuning timer count */
+       host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >>
+                             SDHCI_RETUNING_TIMER_COUNT_SHIFT;
+
+       /*
+        * In case Re-tuning Timer is not disabled, the actual value of
+        * re-tuning timer will be 2 ^ (n - 1).
+        */
+       if (host->tuning_count)
+               host->tuning_count = 1 << (host->tuning_count - 1);
+
+       /* Re-tuning mode supported by the Host Controller */
+       host->tuning_mode = (caps[1] & SDHCI_RETUNING_MODE_MASK) >>
+                            SDHCI_RETUNING_MODE_SHIFT;
+
        ocr_avail = 0;
-       if (caps & SDHCI_CAN_VDD_330)
+       /*
+        * According to SD Host Controller spec v3.00, if the Host System
+        * can afford more than 150mA, Host Driver should set XPC to 1. Also
+        * the value is meaningful only if Voltage Support in the Capabilities
+        * register is set. The actual current value is 4 times the register
+        * value.
+        */
+       max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT);
+
+       if (caps[0] & SDHCI_CAN_VDD_330) {
+               int max_current_330;
+
                ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
-       if (caps & SDHCI_CAN_VDD_300)
+
+               max_current_330 = ((max_current_caps &
+                                  SDHCI_MAX_CURRENT_330_MASK) >>
+                                  SDHCI_MAX_CURRENT_330_SHIFT) *
+                                  SDHCI_MAX_CURRENT_MULTIPLIER;
+
+               if (max_current_330 > 150)
+                       mmc->caps |= MMC_CAP_SET_XPC_330;
+       }
+       if (caps[0] & SDHCI_CAN_VDD_300) {
+               int max_current_300;
+
                ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
-       if (caps & SDHCI_CAN_VDD_180)
+
+               max_current_300 = ((max_current_caps &
+                                  SDHCI_MAX_CURRENT_300_MASK) >>
+                                  SDHCI_MAX_CURRENT_300_SHIFT) *
+                                  SDHCI_MAX_CURRENT_MULTIPLIER;
+
+               if (max_current_300 > 150)
+                       mmc->caps |= MMC_CAP_SET_XPC_300;
+       }
+       if (caps[0] & SDHCI_CAN_VDD_180) {
+               int max_current_180;
+
                ocr_avail |= MMC_VDD_165_195;
 
+               max_current_180 = ((max_current_caps &
+                                  SDHCI_MAX_CURRENT_180_MASK) >>
+                                  SDHCI_MAX_CURRENT_180_SHIFT) *
+                                  SDHCI_MAX_CURRENT_MULTIPLIER;
+
+               if (max_current_180 > 150)
+                       mmc->caps |= MMC_CAP_SET_XPC_180;
+
+               /* Maximum current capabilities of the host at 1.8V */
+               if (max_current_180 >= 800)
+                       mmc->caps |= MMC_CAP_MAX_CURRENT_800;
+               else if (max_current_180 >= 600)
+                       mmc->caps |= MMC_CAP_MAX_CURRENT_600;
+               else if (max_current_180 >= 400)
+                       mmc->caps |= MMC_CAP_MAX_CURRENT_400;
+               else
+                       mmc->caps |= MMC_CAP_MAX_CURRENT_200;
+       }
+
        mmc->ocr_avail = ocr_avail;
        mmc->ocr_avail_sdio = ocr_avail;
        if (host->ocr_avail_sdio)
@@ -1972,7 +2679,7 @@ int sdhci_add_host(struct sdhci_host *host)
        if (host->quirks & SDHCI_QUIRK_FORCE_BLK_SZ_2048) {
                mmc->max_blk_size = 2;
        } else {
-               mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >>
+               mmc->max_blk_size = (caps[0] & SDHCI_MAX_BLOCK_MASK) >>
                                SDHCI_MAX_BLOCK_SHIFT;
                if (mmc->max_blk_size >= 3) {
                        printk(KERN_WARNING "%s: Invalid maximum block size, "
@@ -1998,6 +2705,15 @@ int sdhci_add_host(struct sdhci_host *host)
 
        setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
 
+       if (host->version >= SDHCI_SPEC_300) {
+               init_waitqueue_head(&host->buf_ready_int);
+
+               /* Initialize re-tuning timer */
+               init_timer(&host->tuning_timer);
+               host->tuning_timer.data = (unsigned long)host;
+               host->tuning_timer.function = sdhci_tuning_timer;
+       }
+
        ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
                mmc_hostname(mmc), host);
        if (ret)
@@ -2091,6 +2807,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
        free_irq(host->irq, host);
 
        del_timer_sync(&host->timer);
+       if (host->version >= SDHCI_SPEC_300)
+               del_timer_sync(&host->tuning_timer);
 
        tasklet_kill(&host->card_tasklet);
        tasklet_kill(&host->finish_tasklet);
index 25e8bde600d1e839a3b44caf77558ec8a52d381c..745c42fa41ed5fb85cfc45ff9238e37b222ae2b1 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #define SDHCI_DMA_ADDRESS      0x00
+#define SDHCI_ARGUMENT2                SDHCI_DMA_ADDRESS
 
 #define SDHCI_BLOCK_SIZE       0x04
 #define  SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
@@ -36,7 +37,8 @@
 #define SDHCI_TRANSFER_MODE    0x0C
 #define  SDHCI_TRNS_DMA                0x01
 #define  SDHCI_TRNS_BLK_CNT_EN 0x02
-#define  SDHCI_TRNS_ACMD12     0x04
+#define  SDHCI_TRNS_AUTO_CMD12 0x04
+#define  SDHCI_TRNS_AUTO_CMD23 0x08
 #define  SDHCI_TRNS_READ       0x10
 #define  SDHCI_TRNS_MULTI      0x20
 
 #define  SDHCI_DATA_AVAILABLE  0x00000800
 #define  SDHCI_CARD_PRESENT    0x00010000
 #define  SDHCI_WRITE_PROTECT   0x00080000
+#define  SDHCI_DATA_LVL_MASK   0x00F00000
+#define   SDHCI_DATA_LVL_SHIFT 20
 
-#define SDHCI_HOST_CONTROL     0x28
+#define SDHCI_HOST_CONTROL     0x28
 #define  SDHCI_CTRL_LED                0x01
 #define  SDHCI_CTRL_4BITBUS    0x02
 #define  SDHCI_CTRL_HISPD      0x04
 #define  SDHCI_DIV_MASK        0xFF
 #define  SDHCI_DIV_MASK_LEN    8
 #define  SDHCI_DIV_HI_MASK     0x300
+#define  SDHCI_PROG_CLOCK_MODE 0x0020
 #define  SDHCI_CLOCK_CARD_EN   0x0004
 #define  SDHCI_CLOCK_INT_STABLE        0x0002
 #define  SDHCI_CLOCK_INT_EN    0x0001
 
 #define SDHCI_ACMD12_ERR       0x3C
 
-/* 3E-3F reserved */
+#define SDHCI_HOST_CONTROL2            0x3E
+#define  SDHCI_CTRL_UHS_MASK           0x0007
+#define   SDHCI_CTRL_UHS_SDR12         0x0000
+#define   SDHCI_CTRL_UHS_SDR25         0x0001
+#define   SDHCI_CTRL_UHS_SDR50         0x0002
+#define   SDHCI_CTRL_UHS_SDR104                0x0003
+#define   SDHCI_CTRL_UHS_DDR50         0x0004
+#define  SDHCI_CTRL_VDD_180            0x0008
+#define  SDHCI_CTRL_DRV_TYPE_MASK      0x0030
+#define   SDHCI_CTRL_DRV_TYPE_B                0x0000
+#define   SDHCI_CTRL_DRV_TYPE_A                0x0010
+#define   SDHCI_CTRL_DRV_TYPE_C                0x0020
+#define   SDHCI_CTRL_DRV_TYPE_D                0x0030
+#define  SDHCI_CTRL_EXEC_TUNING                0x0040
+#define  SDHCI_CTRL_TUNED_CLK          0x0080
+#define  SDHCI_CTRL_PRESET_VAL_ENABLE  0x8000
 
 #define SDHCI_CAPABILITIES     0x40
 #define  SDHCI_TIMEOUT_CLK_MASK        0x0000003F
 #define  SDHCI_CAN_VDD_180     0x04000000
 #define  SDHCI_CAN_64BIT       0x10000000
 
+#define  SDHCI_SUPPORT_SDR50   0x00000001
+#define  SDHCI_SUPPORT_SDR104  0x00000002
+#define  SDHCI_SUPPORT_DDR50   0x00000004
+#define  SDHCI_DRIVER_TYPE_A   0x00000010
+#define  SDHCI_DRIVER_TYPE_C   0x00000020
+#define  SDHCI_DRIVER_TYPE_D   0x00000040
+#define  SDHCI_RETUNING_TIMER_COUNT_MASK       0x00000F00
+#define  SDHCI_RETUNING_TIMER_COUNT_SHIFT      8
+#define  SDHCI_USE_SDR50_TUNING                        0x00002000
+#define  SDHCI_RETUNING_MODE_MASK              0x0000C000
+#define  SDHCI_RETUNING_MODE_SHIFT             14
+#define  SDHCI_CLOCK_MUL_MASK  0x00FF0000
+#define  SDHCI_CLOCK_MUL_SHIFT 16
+
 #define SDHCI_CAPABILITIES_1   0x44
 
-#define SDHCI_MAX_CURRENT      0x48
+#define SDHCI_MAX_CURRENT              0x48
+#define  SDHCI_MAX_CURRENT_330_MASK    0x0000FF
+#define  SDHCI_MAX_CURRENT_330_SHIFT   0
+#define  SDHCI_MAX_CURRENT_300_MASK    0x00FF00
+#define  SDHCI_MAX_CURRENT_300_SHIFT   8
+#define  SDHCI_MAX_CURRENT_180_MASK    0xFF0000
+#define  SDHCI_MAX_CURRENT_180_SHIFT   16
+#define   SDHCI_MAX_CURRENT_MULTIPLIER 4
 
 /* 4C-4F reserved for more max current */
 
 #define SDHCI_MAX_DIV_SPEC_200 256
 #define SDHCI_MAX_DIV_SPEC_300 2046
 
+/*
+ * Host SDMA buffer boundary. Valid values from 4K to 512K in powers of 2.
+ */
+#define SDHCI_DEFAULT_BOUNDARY_SIZE  (512 * 1024)
+#define SDHCI_DEFAULT_BOUNDARY_ARG   (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12)
+
 struct sdhci_ops {
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
        u32             (*read_l)(struct sdhci_host *host, int reg);
@@ -223,6 +270,10 @@ struct sdhci_ops {
        void (*platform_send_init_74_clocks)(struct sdhci_host *host,
                                             u8 power_mode);
        unsigned int    (*get_ro)(struct sdhci_host *host);
+       void    (*platform_reset_enter)(struct sdhci_host *host, u8 mask);
+       void    (*platform_reset_exit)(struct sdhci_host *host, u8 mask);
+       int     (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
+
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
index bbc298fd2a1550b2a8de727d389273b47e82694a..496b7efbc6b079976646a7e9c593d652003cad0f 100644 (file)
@@ -76,7 +76,7 @@ static unsigned int switchlocked;
 #define BUSY_TIMEOUT      32767
 
 /* list of supported pcmcia devices */
-static struct pcmcia_device_id pcmcia_ids[] = {
+static const struct pcmcia_device_id pcmcia_ids[] = {
        /* vendor and device strings followed by their crc32 hashes */
        PCMCIA_DEVICE_PROD_ID12("RICOH", "Bay1Controller", 0xd9f522ed,
                                0xc3901202),
index af97015a2fc7f57b216992a2032869f40cbf5e59..14f8edbaa19551d3d4c72abae3e2cb4f51e24c3f 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/mmc/sh_mmcif.h>
 #include <linux/pagemap.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/spinlock.h>
 
 #define DRIVER_NAME    "sh_mmcif"
 #define DRIVER_VERSION "2010-04-28"
 #define CLKDEV_MMC_DATA                20000000 /* 20MHz */
 #define CLKDEV_INIT            400000   /* 400 KHz */
 
+enum mmcif_state {
+       STATE_IDLE,
+       STATE_REQUEST,
+       STATE_IOS,
+};
+
 struct sh_mmcif_host {
        struct mmc_host *mmc;
        struct mmc_data *data;
@@ -164,6 +172,9 @@ struct sh_mmcif_host {
        long timeout;
        void __iomem *addr;
        struct completion intr_wait;
+       enum mmcif_state state;
+       spinlock_t lock;
+       bool power;
 
        /* DMA support */
        struct dma_chan         *chan_rx;
@@ -798,17 +809,31 @@ static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
 static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
        struct sh_mmcif_host *host = mmc_priv(mmc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+       if (host->state != STATE_IDLE) {
+               spin_unlock_irqrestore(&host->lock, flags);
+               mrq->cmd->error = -EAGAIN;
+               mmc_request_done(mmc, mrq);
+               return;
+       }
+
+       host->state = STATE_REQUEST;
+       spin_unlock_irqrestore(&host->lock, flags);
 
        switch (mrq->cmd->opcode) {
        /* MMCIF does not support SD/SDIO command */
        case SD_IO_SEND_OP_COND:
        case MMC_APP_CMD:
+               host->state = STATE_IDLE;
                mrq->cmd->error = -ETIMEDOUT;
                mmc_request_done(mmc, mrq);
                return;
        case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
                if (!mrq->data) {
                        /* send_if_cond cmd (not support) */
+                       host->state = STATE_IDLE;
                        mrq->cmd->error = -ETIMEDOUT;
                        mmc_request_done(mmc, mrq);
                        return;
@@ -830,12 +855,9 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
        sh_mmcif_start_cmd(host, mrq, mrq->cmd);
        host->data = NULL;
 
-       if (mrq->cmd->error != 0) {
-               mmc_request_done(mmc, mrq);
-               return;
-       }
-       if (mrq->stop)
+       if (!mrq->cmd->error && mrq->stop)
                sh_mmcif_stop_cmd(host, mrq, mrq->stop);
+       host->state = STATE_IDLE;
        mmc_request_done(mmc, mrq);
 }
 
@@ -843,15 +865,39 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct sh_mmcif_host *host = mmc_priv(mmc);
        struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+       if (host->state != STATE_IDLE) {
+               spin_unlock_irqrestore(&host->lock, flags);
+               return;
+       }
+
+       host->state = STATE_IOS;
+       spin_unlock_irqrestore(&host->lock, flags);
 
        if (ios->power_mode == MMC_POWER_UP) {
                if (p->set_pwr)
                        p->set_pwr(host->pd, ios->power_mode);
+               if (!host->power) {
+                       /* See if we also get DMA */
+                       sh_mmcif_request_dma(host, host->pd->dev.platform_data);
+                       pm_runtime_get_sync(&host->pd->dev);
+                       host->power = true;
+               }
        } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) {
                /* clock stop */
                sh_mmcif_clock_control(host, 0);
-               if (ios->power_mode == MMC_POWER_OFF && p->down_pwr)
-                       p->down_pwr(host->pd);
+               if (ios->power_mode == MMC_POWER_OFF) {
+                       if (host->power) {
+                               pm_runtime_put(&host->pd->dev);
+                               sh_mmcif_release_dma(host);
+                               host->power = false;
+                       }
+                       if (p->down_pwr)
+                               p->down_pwr(host->pd);
+               }
+               host->state = STATE_IDLE;
                return;
        }
 
@@ -859,6 +905,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                sh_mmcif_clock_control(host, ios->clock);
 
        host->bus_width = ios->bus_width;
+       host->state = STATE_IDLE;
 }
 
 static int sh_mmcif_get_cd(struct mmc_host *mmc)
@@ -925,7 +972,7 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
                sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
                err = 1;
        } else {
-               dev_dbg(&host->pd->dev, "Not support int\n");
+               dev_dbg(&host->pd->dev, "Unsupported interrupt: 0x%x\n", state);
                sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
                sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
                err = 1;
@@ -996,6 +1043,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
        host->pd = pdev;
 
        init_completion(&host->intr_wait);
+       spin_lock_init(&host->lock);
 
        mmc->ops = &sh_mmcif_ops;
        mmc->f_max = host->clk;
@@ -1020,24 +1068,29 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
        sh_mmcif_sync_reset(host);
        platform_set_drvdata(pdev, host);
 
-       /* See if we also get DMA */
-       sh_mmcif_request_dma(host, pd);
+       pm_runtime_enable(&pdev->dev);
+       host->power = false;
+
+       ret = pm_runtime_resume(&pdev->dev);
+       if (ret < 0)
+               goto clean_up2;
 
        mmc_add_host(mmc);
 
+       sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
+
        ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host);
        if (ret) {
                dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n");
-               goto clean_up2;
+               goto clean_up3;
        }
        ret = request_irq(irq[1], sh_mmcif_intr, 0, "sh_mmc:int", host);
        if (ret) {
                free_irq(irq[0], host);
                dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n");
-               goto clean_up2;
+               goto clean_up3;
        }
 
-       sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
        sh_mmcif_detect(host->mmc);
 
        dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION);
@@ -1045,7 +1098,11 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
                sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff);
        return ret;
 
+clean_up3:
+       mmc_remove_host(mmc);
+       pm_runtime_suspend(&pdev->dev);
 clean_up2:
+       pm_runtime_disable(&pdev->dev);
        clk_disable(host->hclk);
 clean_up1:
        mmc_free_host(mmc);
@@ -1060,14 +1117,14 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
        struct sh_mmcif_host *host = platform_get_drvdata(pdev);
        int irq[2];
 
+       pm_runtime_get_sync(&pdev->dev);
+
        mmc_remove_host(host->mmc);
-       sh_mmcif_release_dma(host);
+       sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
 
        if (host->addr)
                iounmap(host->addr);
 
-       sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
-
        irq[0] = platform_get_irq(pdev, 0);
        irq[1] = platform_get_irq(pdev, 1);
 
@@ -1078,15 +1135,52 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
 
        clk_disable(host->hclk);
        mmc_free_host(host->mmc);
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
 
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int sh_mmcif_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct sh_mmcif_host *host = platform_get_drvdata(pdev);
+       int ret = mmc_suspend_host(host->mmc);
+
+       if (!ret) {
+               sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
+               clk_disable(host->hclk);
+       }
+
+       return ret;
+}
+
+static int sh_mmcif_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct sh_mmcif_host *host = platform_get_drvdata(pdev);
+
+       clk_enable(host->hclk);
+
+       return mmc_resume_host(host->mmc);
+}
+#else
+#define sh_mmcif_suspend       NULL
+#define sh_mmcif_resume                NULL
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops sh_mmcif_dev_pm_ops = {
+       .suspend = sh_mmcif_suspend,
+       .resume = sh_mmcif_resume,
+};
+
 static struct platform_driver sh_mmcif_driver = {
        .probe          = sh_mmcif_probe,
        .remove         = sh_mmcif_remove,
        .driver         = {
                .name   = DRIVER_NAME,
+               .pm     = &sh_mmcif_dev_pm_ops,
        },
 };
 
index cc701236d16f126895c72d360c4e836582d536fa..b3654293017bca33d4de5b77d0f654e07fb92031 100644 (file)
@@ -62,7 +62,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
        struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
        struct tmio_mmc_host *host;
        char clk_name[8];
-       int ret;
+       int i, irq, ret;
 
        priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL);
        if (priv == NULL) {
@@ -71,6 +71,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
        }
 
        mmc_data = &priv->mmc_data;
+       p->pdata = mmc_data;
 
        snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
        priv->clk = clk_get(&pdev->dev, clk_name);
@@ -116,11 +117,36 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
        if (ret < 0)
                goto eprobe;
 
-       pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
-               (unsigned long)host->ctl, host->irq);
+       for (i = 0; i < 3; i++) {
+               irq = platform_get_irq(pdev, i);
+               if (irq < 0) {
+                       if (i) {
+                               continue;
+                       } else {
+                               ret = irq;
+                               goto eirq;
+                       }
+               }
+               ret = request_irq(irq, tmio_mmc_irq, 0,
+                                 dev_name(&pdev->dev), host);
+               if (ret) {
+                       while (i--) {
+                               irq = platform_get_irq(pdev, i);
+                               if (irq >= 0)
+                                       free_irq(irq, host);
+                       }
+                       goto eirq;
+               }
+       }
+       dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
+                mmc_hostname(host->mmc), (unsigned long)
+                (platform_get_resource(pdev,IORESOURCE_MEM, 0)->start),
+                mmc_data->hclk / 1000000);
 
        return ret;
 
+eirq:
+       tmio_mmc_host_remove(host);
 eprobe:
        clk_disable(priv->clk);
        clk_put(priv->clk);
@@ -134,6 +160,16 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
        struct mmc_host *mmc = platform_get_drvdata(pdev);
        struct tmio_mmc_host *host = mmc_priv(mmc);
        struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
+       struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
+       int i, irq;
+
+       p->pdata = NULL;
+
+       for (i = 0; i < 3; i++) {
+               irq = platform_get_irq(pdev, i);
+               if (irq >= 0)
+                       free_irq(irq, host);
+       }
 
        tmio_mmc_host_remove(host);
        clk_disable(priv->clk);
@@ -143,10 +179,18 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
+       .suspend = tmio_mmc_host_suspend,
+       .resume = tmio_mmc_host_resume,
+       .runtime_suspend = tmio_mmc_host_runtime_suspend,
+       .runtime_resume = tmio_mmc_host_runtime_resume,
+};
+
 static struct platform_driver sh_mobile_sdhi_driver = {
        .driver         = {
                .name   = "sh_mobile_sdhi",
                .owner  = THIS_MODULE,
+               .pm     = &tmio_mmc_dev_pm_ops,
        },
        .probe          = sh_mobile_sdhi_probe,
        .remove         = __devexit_p(sh_mobile_sdhi_remove),
index 79c568461d59565b587627237ba6bb6de8950005..8d185de90d207ded1a256b32cdd69ae11d6ec2c6 100644 (file)
@@ -30,7 +30,7 @@ static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
        struct mmc_host *mmc = platform_get_drvdata(dev);
        int ret;
 
-       ret = mmc_suspend_host(mmc);
+       ret = tmio_mmc_host_suspend(&dev->dev);
 
        /* Tell MFD core it can disable us now.*/
        if (!ret && cell->disable)
@@ -46,15 +46,12 @@ static int tmio_mmc_resume(struct platform_device *dev)
        int ret = 0;
 
        /* Tell the MFD core we are ready to be enabled */
-       if (cell->resume) {
+       if (cell->resume)
                ret = cell->resume(dev);
-               if (ret)
-                       goto out;
-       }
 
-       mmc_resume_host(mmc);
+       if (!ret)
+               ret = tmio_mmc_host_resume(&dev->dev);
 
-out:
        return ret;
 }
 #else
@@ -67,15 +64,21 @@ static int __devinit tmio_mmc_probe(struct platform_device *pdev)
        const struct mfd_cell *cell = mfd_get_cell(pdev);
        struct tmio_mmc_data *pdata;
        struct tmio_mmc_host *host;
-       int ret = -EINVAL;
+       int ret = -EINVAL, irq;
 
        if (pdev->num_resources != 2)
                goto out;
 
-       pdata = mfd_get_data(pdev);
+       pdata = pdev->dev.platform_data;
        if (!pdata || !pdata->hclk)
                goto out;
 
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               ret = irq;
+               goto out;
+       }
+
        /* Tell the MFD core we are ready to be enabled */
        if (cell->enable) {
                ret = cell->enable(pdev);
@@ -87,11 +90,18 @@ static int __devinit tmio_mmc_probe(struct platform_device *pdev)
        if (ret)
                goto cell_disable;
 
+       ret = request_irq(irq, tmio_mmc_irq, IRQF_DISABLED |
+                         IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), host);
+       if (ret)
+               goto host_remove;
+
        pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
-               (unsigned long)host->ctl, host->irq);
+               (unsigned long)host->ctl, irq);
 
        return 0;
 
+host_remove:
+       tmio_mmc_host_remove(host);
 cell_disable:
        if (cell->disable)
                cell->disable(pdev);
@@ -107,7 +117,9 @@ static int __devexit tmio_mmc_remove(struct platform_device *pdev)
        platform_set_drvdata(pdev, NULL);
 
        if (mmc) {
-               tmio_mmc_host_remove(mmc_priv(mmc));
+               struct tmio_mmc_host *host = mmc_priv(mmc);
+               free_irq(platform_get_irq(pdev, 0), host);
+               tmio_mmc_host_remove(host);
                if (cell->disable)
                        cell->disable(pdev);
        }
index 099ed49a259b17971dcecf72b5db6d03f28e9de3..8260bc2c34e38ee325b1a864c6ad7f6f756a3bcf 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/highmem.h>
 #include <linux/mmc/tmio.h>
 #include <linux/pagemap.h>
+#include <linux/spinlock.h>
 
 /* Definitions for values the CTRL_SDIO_STATUS register can take. */
 #define TMIO_SDIO_STAT_IOIRQ   0x0001
@@ -44,13 +45,14 @@ struct tmio_mmc_host {
        struct mmc_request      *mrq;
        struct mmc_data         *data;
        struct mmc_host         *mmc;
-       int                     irq;
        unsigned int            sdio_irq_enabled;
 
        /* Callbacks for clock / power control */
        void (*set_pwr)(struct platform_device *host, int state);
        void (*set_clk_div)(struct platform_device *host, int state);
 
+       int                     pm_error;
+
        /* pio related stuff */
        struct scatterlist      *sg_ptr;
        struct scatterlist      *sg_orig;
@@ -83,6 +85,7 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host);
 
 void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
 void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
+irqreturn_t tmio_mmc_irq(int irq, void *devid);
 
 static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
                                         unsigned long *flags)
@@ -120,4 +123,15 @@ static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host)
 }
 #endif
 
+#ifdef CONFIG_PM
+int tmio_mmc_host_suspend(struct device *dev);
+int tmio_mmc_host_resume(struct device *dev);
+#else
+#define tmio_mmc_host_suspend NULL
+#define tmio_mmc_host_resume NULL
+#endif
+
+int tmio_mmc_host_runtime_suspend(struct device *dev);
+int tmio_mmc_host_runtime_resume(struct device *dev);
+
 #endif
index d3de74ab633e73fe9146eb5ceddf14bd08b78b69..25f1ad6cbe098a9d4cd2b270423eade6d6cb4326 100644 (file)
@@ -256,7 +256,10 @@ static bool tmio_mmc_filter(struct dma_chan *chan, void *arg)
 void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata)
 {
        /* We can only either use DMA for both Tx and Rx or not use it at all */
-       if (pdata->dma) {
+       if (!pdata->dma)
+               return;
+
+       if (!host->chan_tx && !host->chan_rx) {
                dma_cap_mask_t mask;
 
                dma_cap_zero(mask);
@@ -284,18 +287,18 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat
 
                tasklet_init(&host->dma_complete, tmio_mmc_tasklet_fn, (unsigned long)host);
                tasklet_init(&host->dma_issue, tmio_mmc_issue_tasklet_fn, (unsigned long)host);
+       }
 
-               tmio_mmc_enable_dma(host, true);
+       tmio_mmc_enable_dma(host, true);
+
+       return;
 
-               return;
 ebouncebuf:
-               dma_release_channel(host->chan_rx);
-               host->chan_rx = NULL;
+       dma_release_channel(host->chan_rx);
+       host->chan_rx = NULL;
 ereqrx:
-               dma_release_channel(host->chan_tx);
-               host->chan_tx = NULL;
-               return;
-       }
+       dma_release_channel(host->chan_tx);
+       host->chan_tx = NULL;
 }
 
 void tmio_mmc_release_dma(struct tmio_mmc_host *host)
index 710339a85c84676d9c72e2105f24108344248da2..ad6347bb02ddd9ee20a6085185fb6ca03924d666 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/module.h>
 #include <linux/pagemap.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/scatterlist.h>
 #include <linux/workqueue.h>
 #include <linux/spinlock.h>
@@ -243,8 +244,12 @@ static void tmio_mmc_reset_work(struct work_struct *work)
        spin_lock_irqsave(&host->lock, flags);
        mrq = host->mrq;
 
-       /* request already finished */
-       if (!mrq
+       /*
+        * is request already finished? Since we use a non-blocking
+        * cancel_delayed_work(), it can happen, that a .set_ios() call preempts
+        * us, so, have to check for IS_ERR(host->mrq)
+        */
+       if (IS_ERR_OR_NULL(mrq)
            || time_is_after_jiffies(host->last_req_ts +
                msecs_to_jiffies(2000))) {
                spin_unlock_irqrestore(&host->lock, flags);
@@ -264,16 +269,19 @@ static void tmio_mmc_reset_work(struct work_struct *work)
 
        host->cmd = NULL;
        host->data = NULL;
-       host->mrq = NULL;
        host->force_pio = false;
 
        spin_unlock_irqrestore(&host->lock, flags);
 
        tmio_mmc_reset(host);
 
+       /* Ready for new calls */
+       host->mrq = NULL;
+
        mmc_request_done(host->mmc, mrq);
 }
 
+/* called with host->lock held, interrupts disabled */
 static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
 {
        struct mmc_request *mrq = host->mrq;
@@ -281,13 +289,15 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
        if (!mrq)
                return;
 
-       host->mrq = NULL;
        host->cmd = NULL;
        host->data = NULL;
        host->force_pio = false;
 
        cancel_delayed_work(&host->delayed_reset_work);
 
+       host->mrq = NULL;
+
+       /* FIXME: mmc_request_done() can schedule! */
        mmc_request_done(host->mmc, mrq);
 }
 
@@ -554,7 +564,7 @@ out:
        spin_unlock(&host->lock);
 }
 
-static irqreturn_t tmio_mmc_irq(int irq, void *devid)
+irqreturn_t tmio_mmc_irq(int irq, void *devid)
 {
        struct tmio_mmc_host *host = devid;
        struct tmio_mmc_data *pdata = host->pdata;
@@ -649,6 +659,7 @@ static irqreturn_t tmio_mmc_irq(int irq, void *devid)
 out:
        return IRQ_HANDLED;
 }
+EXPORT_SYMBOL(tmio_mmc_irq);
 
 static int tmio_mmc_start_data(struct tmio_mmc_host *host,
        struct mmc_data *data)
@@ -685,15 +696,27 @@ static int tmio_mmc_start_data(struct tmio_mmc_host *host,
 static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
        struct tmio_mmc_host *host = mmc_priv(mmc);
+       unsigned long flags;
        int ret;
 
-       if (host->mrq)
+       spin_lock_irqsave(&host->lock, flags);
+
+       if (host->mrq) {
                pr_debug("request not null\n");
+               if (IS_ERR(host->mrq)) {
+                       spin_unlock_irqrestore(&host->lock, flags);
+                       mrq->cmd->error = -EAGAIN;
+                       mmc_request_done(mmc, mrq);
+                       return;
+               }
+       }
 
        host->last_req_ts = jiffies;
        wmb();
        host->mrq = mrq;
 
+       spin_unlock_irqrestore(&host->lock, flags);
+
        if (mrq->data) {
                ret = tmio_mmc_start_data(host, mrq->data);
                if (ret)
@@ -708,8 +731,8 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
        }
 
 fail:
-       host->mrq = NULL;
        host->force_pio = false;
+       host->mrq = NULL;
        mrq->cmd->error = ret;
        mmc_request_done(mmc, mrq);
 }
@@ -723,19 +746,54 @@ fail:
 static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct tmio_mmc_host *host = mmc_priv(mmc);
+       struct tmio_mmc_data *pdata = host->pdata;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+       if (host->mrq) {
+               if (IS_ERR(host->mrq)) {
+                       dev_dbg(&host->pdev->dev,
+                               "%s.%d: concurrent .set_ios(), clk %u, mode %u\n",
+                               current->comm, task_pid_nr(current),
+                               ios->clock, ios->power_mode);
+                       host->mrq = ERR_PTR(-EINTR);
+               } else {
+                       dev_dbg(&host->pdev->dev,
+                               "%s.%d: CMD%u active since %lu, now %lu!\n",
+                               current->comm, task_pid_nr(current),
+                               host->mrq->cmd->opcode, host->last_req_ts, jiffies);
+               }
+               spin_unlock_irqrestore(&host->lock, flags);
+               return;
+       }
+
+       host->mrq = ERR_PTR(-EBUSY);
+
+       spin_unlock_irqrestore(&host->lock, flags);
 
        if (ios->clock)
                tmio_mmc_set_clock(host, ios->clock);
 
        /* Power sequence - OFF -> UP -> ON */
        if (ios->power_mode == MMC_POWER_UP) {
+               if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) && !pdata->power) {
+                       pm_runtime_get_sync(&host->pdev->dev);
+                       pdata->power = true;
+               }
                /* power up SD bus */
                if (host->set_pwr)
                        host->set_pwr(host->pdev, 1);
        } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) {
                /* power down SD bus */
-               if (ios->power_mode == MMC_POWER_OFF && host->set_pwr)
-                       host->set_pwr(host->pdev, 0);
+               if (ios->power_mode == MMC_POWER_OFF) {
+                       if (host->set_pwr)
+                               host->set_pwr(host->pdev, 0);
+                       if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) &&
+                           pdata->power) {
+                               pdata->power = false;
+                               pm_runtime_put(&host->pdev->dev);
+                       }
+               }
                tmio_mmc_clk_stop(host);
        } else {
                /* start bus clock */
@@ -753,6 +811,12 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
        /* Let things settle. delay taken from winCE driver */
        udelay(140);
+       if (PTR_ERR(host->mrq) == -EINTR)
+               dev_dbg(&host->pdev->dev,
+                       "%s.%d: IOS interrupted: clk %u, mode %u",
+                       current->comm, task_pid_nr(current),
+                       ios->clock, ios->power_mode);
+       host->mrq = NULL;
 }
 
 static int tmio_mmc_get_ro(struct mmc_host *mmc)
@@ -801,6 +865,7 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
        if (!mmc)
                return -ENOMEM;
 
+       pdata->dev = &pdev->dev;
        _host = mmc_priv(mmc);
        _host->pdata = pdata;
        _host->mmc = mmc;
@@ -834,24 +899,19 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
        else
                mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 
-       tmio_mmc_clk_stop(_host);
-       tmio_mmc_reset(_host);
-
-       ret = platform_get_irq(pdev, 0);
+       pdata->power = false;
+       pm_runtime_enable(&pdev->dev);
+       ret = pm_runtime_resume(&pdev->dev);
        if (ret < 0)
-               goto unmap_ctl;
+               goto pm_disable;
 
-       _host->irq = ret;
+       tmio_mmc_clk_stop(_host);
+       tmio_mmc_reset(_host);
 
        tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL);
        if (pdata->flags & TMIO_MMC_SDIO_IRQ)
                tmio_mmc_enable_sdio_irq(mmc, 0);
 
-       ret = request_irq(_host->irq, tmio_mmc_irq, IRQF_DISABLED |
-               IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), _host);
-       if (ret)
-               goto unmap_ctl;
-
        spin_lock_init(&_host->lock);
 
        /* Init delayed work for request timeouts */
@@ -860,6 +920,10 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
        /* See if we also get DMA */
        tmio_mmc_request_dma(_host, pdata);
 
+       /* We have to keep the device powered for its card detection to work */
+       if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD))
+               pm_runtime_get_noresume(&pdev->dev);
+
        mmc_add_host(mmc);
 
        /* Unmask the IRQs we want to know about */
@@ -874,7 +938,8 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
 
        return 0;
 
-unmap_ctl:
+pm_disable:
+       pm_runtime_disable(&pdev->dev);
        iounmap(_host->ctl);
 host_free:
        mmc_free_host(mmc);
@@ -885,13 +950,88 @@ EXPORT_SYMBOL(tmio_mmc_host_probe);
 
 void tmio_mmc_host_remove(struct tmio_mmc_host *host)
 {
+       struct platform_device *pdev = host->pdev;
+
+       /*
+        * We don't have to manipulate pdata->power here: if there is a card in
+        * the slot, the runtime PM is active and our .runtime_resume() will not
+        * be run. If there is no card in the slot and the platform can suspend
+        * the controller, the runtime PM is suspended and pdata->power == false,
+        * so, our .runtime_resume() will not try to detect a card in the slot.
+        */
+       if (host->pdata->flags & TMIO_MMC_HAS_COLD_CD)
+               pm_runtime_get_sync(&pdev->dev);
+
        mmc_remove_host(host->mmc);
        cancel_delayed_work_sync(&host->delayed_reset_work);
        tmio_mmc_release_dma(host);
-       free_irq(host->irq, host);
+
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+
        iounmap(host->ctl);
        mmc_free_host(host->mmc);
 }
 EXPORT_SYMBOL(tmio_mmc_host_remove);
 
+#ifdef CONFIG_PM
+int tmio_mmc_host_suspend(struct device *dev)
+{
+       struct mmc_host *mmc = dev_get_drvdata(dev);
+       struct tmio_mmc_host *host = mmc_priv(mmc);
+       int ret = mmc_suspend_host(mmc);
+
+       if (!ret)
+               tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL);
+
+       host->pm_error = pm_runtime_put_sync(dev);
+
+       return ret;
+}
+EXPORT_SYMBOL(tmio_mmc_host_suspend);
+
+int tmio_mmc_host_resume(struct device *dev)
+{
+       struct mmc_host *mmc = dev_get_drvdata(dev);
+       struct tmio_mmc_host *host = mmc_priv(mmc);
+
+       /* The MMC core will perform the complete set up */
+       host->pdata->power = false;
+
+       if (!host->pm_error)
+               pm_runtime_get_sync(dev);
+
+       tmio_mmc_reset(mmc_priv(mmc));
+       tmio_mmc_request_dma(host, host->pdata);
+
+       return mmc_resume_host(mmc);
+}
+EXPORT_SYMBOL(tmio_mmc_host_resume);
+
+#endif /* CONFIG_PM */
+
+int tmio_mmc_host_runtime_suspend(struct device *dev)
+{
+       return 0;
+}
+EXPORT_SYMBOL(tmio_mmc_host_runtime_suspend);
+
+int tmio_mmc_host_runtime_resume(struct device *dev)
+{
+       struct mmc_host *mmc = dev_get_drvdata(dev);
+       struct tmio_mmc_host *host = mmc_priv(mmc);
+       struct tmio_mmc_data *pdata = host->pdata;
+
+       tmio_mmc_reset(host);
+
+       if (pdata->power) {
+               /* Only entered after a card-insert interrupt */
+               tmio_mmc_set_ios(mmc, &mmc->ios);
+               mmc_detect_change(mmc, msecs_to_jiffies(100));
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(tmio_mmc_host_runtime_resume);
+
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
new file mode 100644 (file)
index 0000000..cbb0330
--- /dev/null
@@ -0,0 +1,2506 @@
+/*
+ * Remote VUB300 SDIO/SDmem Host Controller Driver
+ *
+ * Copyright (C) 2010 Elan Digital Systems Limited
+ *
+ * based on USB Skeleton driver - 2.2
+ *
+ * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.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
+ *
+ * VUB300: is a USB 2.0 client device with a single SDIO/SDmem/MMC slot
+ *         Any SDIO/SDmem/MMC device plugged into the VUB300 will appear,
+ *         by virtue of this driver, to have been plugged into a local
+ *         SDIO host controller, similar to, say, a PCI Ricoh controller
+ *         This is because this kernel device driver is both a USB 2.0
+ *         client device driver AND an MMC host controller driver. Thus
+ *         if there is an existing driver for the inserted SDIO/SDmem/MMC
+ *         device then that driver will be used by the kernel to manage
+ *         the device in exactly the same fashion as if it had been
+ *         directly plugged into, say, a local pci bus Ricoh controller
+ *
+ * RANT: this driver was written using a display 128x48 - converting it
+ *       to a line width of 80 makes it very difficult to support. In
+ *       particular functions have been broken down into sub functions
+ *       and the original meaningful names have been shortened into
+ *       cryptic ones.
+ *       The problem is that executing a fragment of code subject to
+ *       two conditions means an indentation of 24, thus leaving only
+ *       56 characters for a C statement. And that is quite ridiculous!
+ *
+ * Data types: data passed to/from the VUB300 is fixed to a number of
+ *             bits and driver data fields reflect that limit by using
+ *             u8, u16, u32
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/workqueue.h>
+#include <linux/ctype.h>
+#include <linux/firmware.h>
+#include <linux/scatterlist.h>
+
+struct host_controller_info {
+       u8 info_size;
+       u16 firmware_version;
+       u8 number_of_ports;
+} __packed;
+
+#define FIRMWARE_BLOCK_BOUNDARY 1024
+struct sd_command_header {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+       u8 command_type; /* Bit7 - Rd/Wr */
+       u8 command_index;
+       u8 transfer_size[4]; /* ReadSize + ReadSize */
+       u8 response_type;
+       u8 arguments[4];
+       u8 block_count[2];
+       u8 block_size[2];
+       u8 block_boundary[2];
+       u8 reserved[44]; /* to pad out to 64 bytes */
+} __packed;
+
+struct sd_irqpoll_header {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+       u8 command_type; /* Bit7 - Rd/Wr */
+       u8 padding[16]; /* don't ask why !! */
+       u8 poll_timeout_msb;
+       u8 poll_timeout_lsb;
+       u8 reserved[42]; /* to pad out to 64 bytes */
+} __packed;
+
+struct sd_common_header {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+} __packed;
+
+struct sd_response_header {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+       u8 command_type;
+       u8 command_index;
+       u8 command_response[0];
+} __packed;
+
+struct sd_status_header {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+       u16 port_flags;
+       u32 sdio_clock;
+       u16 host_header_size;
+       u16 func_header_size;
+       u16 ctrl_header_size;
+} __packed;
+
+struct sd_error_header {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+       u8 error_code;
+} __packed;
+
+struct sd_interrupt_header {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+} __packed;
+
+struct offload_registers_access {
+       u8 command_byte[4];
+       u8 Respond_Byte[4];
+} __packed;
+
+#define INTERRUPT_REGISTER_ACCESSES 15
+struct sd_offloaded_interrupt {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+       struct offload_registers_access reg[INTERRUPT_REGISTER_ACCESSES];
+} __packed;
+
+struct sd_register_header {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+       u8 command_type;
+       u8 command_index;
+       u8 command_response[6];
+} __packed;
+
+#define PIGGYBACK_REGISTER_ACCESSES 14
+struct sd_offloaded_piggyback {
+       struct sd_register_header sdio;
+       struct offload_registers_access reg[PIGGYBACK_REGISTER_ACCESSES];
+} __packed;
+
+union sd_response {
+       struct sd_common_header common;
+       struct sd_status_header status;
+       struct sd_error_header error;
+       struct sd_interrupt_header interrupt;
+       struct sd_response_header response;
+       struct sd_offloaded_interrupt irq;
+       struct sd_offloaded_piggyback pig;
+} __packed;
+
+union sd_command {
+       struct sd_command_header head;
+       struct sd_irqpoll_header poll;
+} __packed;
+
+enum SD_RESPONSE_TYPE {
+       SDRT_UNSPECIFIED = 0,
+       SDRT_NONE,
+       SDRT_1,
+       SDRT_1B,
+       SDRT_2,
+       SDRT_3,
+       SDRT_4,
+       SDRT_5,
+       SDRT_5B,
+       SDRT_6,
+       SDRT_7,
+};
+
+#define RESPONSE_INTERRUPT                     0x01
+#define RESPONSE_ERROR                         0x02
+#define RESPONSE_STATUS                                0x03
+#define RESPONSE_IRQ_DISABLED                  0x05
+#define RESPONSE_IRQ_ENABLED                   0x06
+#define RESPONSE_PIGGYBACKED                   0x07
+#define RESPONSE_NO_INTERRUPT                  0x08
+#define RESPONSE_PIG_DISABLED                  0x09
+#define RESPONSE_PIG_ENABLED                   0x0A
+#define SD_ERROR_1BIT_TIMEOUT                  0x01
+#define SD_ERROR_4BIT_TIMEOUT                  0x02
+#define SD_ERROR_1BIT_CRC_WRONG                        0x03
+#define SD_ERROR_4BIT_CRC_WRONG                        0x04
+#define SD_ERROR_1BIT_CRC_ERROR                        0x05
+#define SD_ERROR_4BIT_CRC_ERROR                        0x06
+#define SD_ERROR_NO_CMD_ENDBIT                 0x07
+#define SD_ERROR_NO_1BIT_DATEND                        0x08
+#define SD_ERROR_NO_4BIT_DATEND                        0x09
+#define SD_ERROR_1BIT_UNEXPECTED_TIMEOUT       0x0A
+#define SD_ERROR_4BIT_UNEXPECTED_TIMEOUT       0x0B
+#define SD_ERROR_ILLEGAL_COMMAND               0x0C
+#define SD_ERROR_NO_DEVICE                     0x0D
+#define SD_ERROR_TRANSFER_LENGTH               0x0E
+#define SD_ERROR_1BIT_DATA_TIMEOUT             0x0F
+#define SD_ERROR_4BIT_DATA_TIMEOUT             0x10
+#define SD_ERROR_ILLEGAL_STATE                 0x11
+#define SD_ERROR_UNKNOWN_ERROR                 0x12
+#define SD_ERROR_RESERVED_ERROR                        0x13
+#define SD_ERROR_INVALID_FUNCTION              0x14
+#define SD_ERROR_OUT_OF_RANGE                  0x15
+#define SD_ERROR_STAT_CMD                      0x16
+#define SD_ERROR_STAT_DATA                     0x17
+#define SD_ERROR_STAT_CMD_TIMEOUT              0x18
+#define SD_ERROR_SDCRDY_STUCK                  0x19
+#define SD_ERROR_UNHANDLED                     0x1A
+#define SD_ERROR_OVERRUN                       0x1B
+#define SD_ERROR_PIO_TIMEOUT                   0x1C
+
+#define FUN(c) (0x000007 & (c->arg>>28))
+#define REG(c) (0x01FFFF & (c->arg>>9))
+
+static int limit_speed_to_24_MHz;
+module_param(limit_speed_to_24_MHz, bool, 0644);
+MODULE_PARM_DESC(limit_speed_to_24_MHz, "Limit Max SDIO Clock Speed to 24 MHz");
+
+static int pad_input_to_usb_pkt;
+module_param(pad_input_to_usb_pkt, bool, 0644);
+MODULE_PARM_DESC(pad_input_to_usb_pkt,
+                "Pad USB data input transfers to whole USB Packet");
+
+static int disable_offload_processing;
+module_param(disable_offload_processing, bool, 0644);
+MODULE_PARM_DESC(disable_offload_processing, "Disable Offload Processing");
+
+static int force_1_bit_data_xfers;
+module_param(force_1_bit_data_xfers, bool, 0644);
+MODULE_PARM_DESC(force_1_bit_data_xfers,
+                "Force SDIO Data Transfers to 1-bit Mode");
+
+static int force_polling_for_irqs;
+module_param(force_polling_for_irqs, bool, 0644);
+MODULE_PARM_DESC(force_polling_for_irqs, "Force Polling for SDIO interrupts");
+
+static int firmware_irqpoll_timeout = 1024;
+module_param(firmware_irqpoll_timeout, int, 0644);
+MODULE_PARM_DESC(firmware_irqpoll_timeout, "VUB300 firmware irqpoll timeout");
+
+static int force_max_req_size = 128;
+module_param(force_max_req_size, int, 0644);
+MODULE_PARM_DESC(force_max_req_size, "set max request size in kBytes");
+
+#ifdef SMSC_DEVELOPMENT_BOARD
+static int firmware_rom_wait_states = 0x04;
+#else
+static int firmware_rom_wait_states = 0x1C;
+#endif
+
+module_param(firmware_rom_wait_states, bool, 0644);
+MODULE_PARM_DESC(firmware_rom_wait_states,
+                "ROM wait states byte=RRRIIEEE (Reserved Internal External)");
+
+#define ELAN_VENDOR_ID         0x2201
+#define VUB300_VENDOR_ID       0x0424
+#define VUB300_PRODUCT_ID      0x012C
+static struct usb_device_id vub300_table[] = {
+       {USB_DEVICE(ELAN_VENDOR_ID, VUB300_PRODUCT_ID)},
+       {USB_DEVICE(VUB300_VENDOR_ID, VUB300_PRODUCT_ID)},
+       {} /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, vub300_table);
+
+static struct workqueue_struct *cmndworkqueue;
+static struct workqueue_struct *pollworkqueue;
+static struct workqueue_struct *deadworkqueue;
+
+static inline int interface_to_InterfaceNumber(struct usb_interface *interface)
+{
+       if (!interface)
+               return -1;
+       if (!interface->cur_altsetting)
+               return -1;
+       return interface->cur_altsetting->desc.bInterfaceNumber;
+}
+
+struct sdio_register {
+       unsigned func_num:3;
+       unsigned sdio_reg:17;
+       unsigned activate:1;
+       unsigned prepared:1;
+       unsigned regvalue:8;
+       unsigned response:8;
+       unsigned sparebit:26;
+};
+
+struct vub300_mmc_host {
+       struct usb_device *udev;
+       struct usb_interface *interface;
+       struct kref kref;
+       struct mutex cmd_mutex;
+       struct mutex irq_mutex;
+       char vub_name[3 + (9 * 8) + 4 + 1]; /* max of 7 sdio fn's */
+       u8 cmnd_out_ep; /* EndPoint for commands */
+       u8 cmnd_res_ep; /* EndPoint for responses */
+       u8 data_out_ep; /* EndPoint for out data */
+       u8 data_inp_ep; /* EndPoint for inp data */
+       bool card_powered;
+       bool card_present;
+       bool read_only;
+       bool large_usb_packets;
+       bool app_spec; /* ApplicationSpecific */
+       bool irq_enabled; /* by the MMC CORE */
+       bool irq_disabled; /* in the firmware */
+       unsigned bus_width:4;
+       u8 total_offload_count;
+       u8 dynamic_register_count;
+       u8 resp_len;
+       u32 datasize;
+       int errors;
+       int usb_transport_fail;
+       int usb_timed_out;
+       int irqs_queued;
+       struct sdio_register sdio_register[16];
+       struct offload_interrupt_function_register {
+#define MAXREGBITS 4
+#define MAXREGS (1<<MAXREGBITS)
+#define MAXREGMASK (MAXREGS-1)
+               u8 offload_count;
+               u32 offload_point;
+               struct offload_registers_access reg[MAXREGS];
+       } fn[8];
+       u16 fbs[8]; /* Function Block Size */
+       struct mmc_command *cmd;
+       struct mmc_request *req;
+       struct mmc_data *data;
+       struct mmc_host *mmc;
+       struct urb *urb;
+       struct urb *command_out_urb;
+       struct urb *command_res_urb;
+       struct completion command_complete;
+       struct completion irqpoll_complete;
+       union sd_command cmnd;
+       union sd_response resp;
+       struct timer_list sg_transfer_timer;
+       struct usb_sg_request sg_request;
+       struct timer_list inactivity_timer;
+       struct work_struct deadwork;
+       struct work_struct cmndwork;
+       struct delayed_work pollwork;
+       struct host_controller_info hc_info;
+       struct sd_status_header system_port_status;
+       u8 padded_buffer[64];
+};
+
+#define kref_to_vub300_mmc_host(d) container_of(d, struct vub300_mmc_host, kref)
+#define SET_TRANSFER_PSEUDOCODE                21
+#define SET_INTERRUPT_PSEUDOCODE       20
+#define SET_FAILURE_MODE               18
+#define SET_ROM_WAIT_STATES            16
+#define SET_IRQ_ENABLE                 13
+#define SET_CLOCK_SPEED                        11
+#define SET_FUNCTION_BLOCK_SIZE                9
+#define SET_SD_DATA_MODE               6
+#define SET_SD_POWER                   4
+#define ENTER_DFU_MODE                 3
+#define GET_HC_INF0                    1
+#define GET_SYSTEM_PORT_STATUS         0
+
+static void vub300_delete(struct kref *kref)
+{                              /* kref callback - softirq */
+       struct vub300_mmc_host *vub300 = kref_to_vub300_mmc_host(kref);
+       struct mmc_host *mmc = vub300->mmc;
+       usb_free_urb(vub300->command_out_urb);
+       vub300->command_out_urb = NULL;
+       usb_free_urb(vub300->command_res_urb);
+       vub300->command_res_urb = NULL;
+       usb_put_dev(vub300->udev);
+       mmc_free_host(mmc);
+       /*
+        * and hence also frees vub300
+        * which is contained at the end of struct mmc
+        */
+}
+
+static void vub300_queue_cmnd_work(struct vub300_mmc_host *vub300)
+{
+       kref_get(&vub300->kref);
+       if (queue_work(cmndworkqueue, &vub300->cmndwork)) {
+               /*
+                * then the cmndworkqueue was not previously
+                * running and the above get ref is obvious
+                * required and will be put when the thread
+                * terminates by a specific call
+                */
+       } else {
+               /*
+                * the cmndworkqueue was already running from
+                * a previous invocation and thus to keep the
+                * kref counts correct we must undo the get
+                */
+               kref_put(&vub300->kref, vub300_delete);
+       }
+}
+
+static void vub300_queue_poll_work(struct vub300_mmc_host *vub300, int delay)
+{
+       kref_get(&vub300->kref);
+       if (queue_delayed_work(pollworkqueue, &vub300->pollwork, delay)) {
+               /*
+                * then the pollworkqueue was not previously
+                * running and the above get ref is obvious
+                * required and will be put when the thread
+                * terminates by a specific call
+                */
+       } else {
+               /*
+                * the pollworkqueue was already running from
+                * a previous invocation and thus to keep the
+                * kref counts correct we must undo the get
+                */
+               kref_put(&vub300->kref, vub300_delete);
+       }
+}
+
+static void vub300_queue_dead_work(struct vub300_mmc_host *vub300)
+{
+       kref_get(&vub300->kref);
+       if (queue_work(deadworkqueue, &vub300->deadwork)) {
+               /*
+                * then the deadworkqueue was not previously
+                * running and the above get ref is obvious
+                * required and will be put when the thread
+                * terminates by a specific call
+                */
+       } else {
+               /*
+                * the deadworkqueue was already running from
+                * a previous invocation and thus to keep the
+                * kref counts correct we must undo the get
+                */
+               kref_put(&vub300->kref, vub300_delete);
+       }
+}
+
+static void irqpoll_res_completed(struct urb *urb)
+{                              /* urb completion handler - hardirq */
+       struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
+       if (urb->status)
+               vub300->usb_transport_fail = urb->status;
+       complete(&vub300->irqpoll_complete);
+}
+
+static void irqpoll_out_completed(struct urb *urb)
+{                              /* urb completion handler - hardirq */
+       struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
+       if (urb->status) {
+               vub300->usb_transport_fail = urb->status;
+               complete(&vub300->irqpoll_complete);
+               return;
+       } else {
+               int ret;
+               unsigned int pipe =
+                       usb_rcvbulkpipe(vub300->udev, vub300->cmnd_res_ep);
+               usb_fill_bulk_urb(vub300->command_res_urb, vub300->udev, pipe,
+                                 &vub300->resp, sizeof(vub300->resp),
+                                 irqpoll_res_completed, vub300);
+               vub300->command_res_urb->actual_length = 0;
+               ret = usb_submit_urb(vub300->command_res_urb, GFP_ATOMIC);
+               if (ret) {
+                       vub300->usb_transport_fail = ret;
+                       complete(&vub300->irqpoll_complete);
+               }
+               return;
+       }
+}
+
+static void send_irqpoll(struct vub300_mmc_host *vub300)
+{
+       /* cmd_mutex is held by vub300_pollwork_thread */
+       int retval;
+       int timeout = 0xFFFF & (0x0001FFFF - firmware_irqpoll_timeout);
+       vub300->cmnd.poll.header_size = 22;
+       vub300->cmnd.poll.header_type = 1;
+       vub300->cmnd.poll.port_number = 0;
+       vub300->cmnd.poll.command_type = 2;
+       vub300->cmnd.poll.poll_timeout_lsb = 0xFF & (unsigned)timeout;
+       vub300->cmnd.poll.poll_timeout_msb = 0xFF & (unsigned)(timeout >> 8);
+       usb_fill_bulk_urb(vub300->command_out_urb, vub300->udev,
+                         usb_sndbulkpipe(vub300->udev, vub300->cmnd_out_ep)
+                         , &vub300->cmnd, sizeof(vub300->cmnd)
+                         , irqpoll_out_completed, vub300);
+       retval = usb_submit_urb(vub300->command_out_urb, GFP_KERNEL);
+       if (0 > retval) {
+               vub300->usb_transport_fail = retval;
+               vub300_queue_poll_work(vub300, 1);
+               complete(&vub300->irqpoll_complete);
+               return;
+       } else {
+               return;
+       }
+}
+
+static void new_system_port_status(struct vub300_mmc_host *vub300)
+{
+       int old_card_present = vub300->card_present;
+       int new_card_present =
+               (0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
+       vub300->read_only =
+               (0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
+       if (new_card_present && !old_card_present) {
+               dev_info(&vub300->udev->dev, "card just inserted\n");
+               vub300->card_present = 1;
+               vub300->bus_width = 0;
+               if (disable_offload_processing)
+                       strncpy(vub300->vub_name, "EMPTY Processing Disabled",
+                               sizeof(vub300->vub_name));
+               else
+                       vub300->vub_name[0] = 0;
+               mmc_detect_change(vub300->mmc, 1);
+       } else if (!new_card_present && old_card_present) {
+               dev_info(&vub300->udev->dev, "card just ejected\n");
+               vub300->card_present = 0;
+               mmc_detect_change(vub300->mmc, 0);
+       } else {
+               /* no change */
+       }
+}
+
+static void __add_offloaded_reg_to_fifo(struct vub300_mmc_host *vub300,
+                                       struct offload_registers_access
+                                       *register_access, u8 func)
+{
+       u8 r = vub300->fn[func].offload_point + vub300->fn[func].offload_count;
+       memcpy(&vub300->fn[func].reg[MAXREGMASK & r], register_access,
+              sizeof(struct offload_registers_access));
+       vub300->fn[func].offload_count += 1;
+       vub300->total_offload_count += 1;
+}
+
+static void add_offloaded_reg(struct vub300_mmc_host *vub300,
+                             struct offload_registers_access *register_access)
+{
+       u32 Register = ((0x03 & register_access->command_byte[0]) << 15)
+                       | ((0xFF & register_access->command_byte[1]) << 7)
+                       | ((0xFE & register_access->command_byte[2]) >> 1);
+       u8 func = ((0x70 & register_access->command_byte[0]) >> 4);
+       u8 regs = vub300->dynamic_register_count;
+       u8 i = 0;
+       while (0 < regs-- && 1 == vub300->sdio_register[i].activate) {
+               if (vub300->sdio_register[i].func_num == func &&
+                   vub300->sdio_register[i].sdio_reg == Register) {
+                       if (vub300->sdio_register[i].prepared == 0)
+                               vub300->sdio_register[i].prepared = 1;
+                       vub300->sdio_register[i].response =
+                               register_access->Respond_Byte[2];
+                       vub300->sdio_register[i].regvalue =
+                               register_access->Respond_Byte[3];
+                       return;
+               } else {
+                       i += 1;
+                       continue;
+               }
+       };
+       __add_offloaded_reg_to_fifo(vub300, register_access, func);
+}
+
+static void check_vub300_port_status(struct vub300_mmc_host *vub300)
+{
+       /*
+        * cmd_mutex is held by vub300_pollwork_thread,
+        * vub300_deadwork_thread or vub300_cmndwork_thread
+        */
+       int retval;
+       retval =
+               usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
+                               GET_SYSTEM_PORT_STATUS,
+                               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               0x0000, 0x0000, &vub300->system_port_status,
+                               sizeof(vub300->system_port_status), HZ);
+       if (sizeof(vub300->system_port_status) == retval)
+               new_system_port_status(vub300);
+}
+
+static void __vub300_irqpoll_response(struct vub300_mmc_host *vub300)
+{
+       /* cmd_mutex is held by vub300_pollwork_thread */
+       if (vub300->command_res_urb->actual_length == 0)
+               return;
+
+       switch (vub300->resp.common.header_type) {
+       case RESPONSE_INTERRUPT:
+               mutex_lock(&vub300->irq_mutex);
+               if (vub300->irq_enabled)
+                       mmc_signal_sdio_irq(vub300->mmc);
+               else
+                       vub300->irqs_queued += 1;
+               vub300->irq_disabled = 1;
+               mutex_unlock(&vub300->irq_mutex);
+               break;
+       case RESPONSE_ERROR:
+               if (vub300->resp.error.error_code == SD_ERROR_NO_DEVICE)
+                       check_vub300_port_status(vub300);
+               break;
+       case RESPONSE_STATUS:
+               vub300->system_port_status = vub300->resp.status;
+               new_system_port_status(vub300);
+               if (!vub300->card_present)
+                       vub300_queue_poll_work(vub300, HZ / 5);
+               break;
+       case RESPONSE_IRQ_DISABLED:
+       {
+               int offloaded_data_length = vub300->resp.common.header_size - 3;
+               int register_count = offloaded_data_length >> 3;
+               int ri = 0;
+               while (register_count--) {
+                       add_offloaded_reg(vub300, &vub300->resp.irq.reg[ri]);
+                       ri += 1;
+               }
+               mutex_lock(&vub300->irq_mutex);
+               if (vub300->irq_enabled)
+                       mmc_signal_sdio_irq(vub300->mmc);
+               else
+                       vub300->irqs_queued += 1;
+               vub300->irq_disabled = 1;
+               mutex_unlock(&vub300->irq_mutex);
+               break;
+       }
+       case RESPONSE_IRQ_ENABLED:
+       {
+               int offloaded_data_length = vub300->resp.common.header_size - 3;
+               int register_count = offloaded_data_length >> 3;
+               int ri = 0;
+               while (register_count--) {
+                       add_offloaded_reg(vub300, &vub300->resp.irq.reg[ri]);
+                       ri += 1;
+               }
+               mutex_lock(&vub300->irq_mutex);
+               if (vub300->irq_enabled)
+                       mmc_signal_sdio_irq(vub300->mmc);
+               else if (vub300->irqs_queued)
+                       vub300->irqs_queued += 1;
+               else
+                       vub300->irqs_queued += 1;
+               vub300->irq_disabled = 0;
+               mutex_unlock(&vub300->irq_mutex);
+               break;
+       }
+       case RESPONSE_NO_INTERRUPT:
+               vub300_queue_poll_work(vub300, 1);
+               break;
+       default:
+               break;
+       }
+}
+
+static void __do_poll(struct vub300_mmc_host *vub300)
+{
+       /* cmd_mutex is held by vub300_pollwork_thread */
+       long commretval;
+       mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+       init_completion(&vub300->irqpoll_complete);
+       send_irqpoll(vub300);
+       commretval = wait_for_completion_timeout(&vub300->irqpoll_complete,
+                                                msecs_to_jiffies(500));
+       if (vub300->usb_transport_fail) {
+               /* no need to do anything */
+       } else if (commretval == 0) {
+               vub300->usb_timed_out = 1;
+               usb_kill_urb(vub300->command_out_urb);
+               usb_kill_urb(vub300->command_res_urb);
+       } else if (commretval < 0) {
+               vub300_queue_poll_work(vub300, 1);
+       } else { /* commretval > 0 */
+               __vub300_irqpoll_response(vub300);
+       }
+}
+
+/* this thread runs only when the driver
+ * is trying to poll the device for an IRQ
+ */
+static void vub300_pollwork_thread(struct work_struct *work)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 = container_of(work,
+                             struct vub300_mmc_host, pollwork.work);
+       if (!vub300->interface) {
+               kref_put(&vub300->kref, vub300_delete);
+               return;
+       }
+       mutex_lock(&vub300->cmd_mutex);
+       if (vub300->cmd) {
+               vub300_queue_poll_work(vub300, 1);
+       } else if (!vub300->card_present) {
+               /* no need to do anything */
+       } else { /* vub300->card_present */
+               mutex_lock(&vub300->irq_mutex);
+               if (!vub300->irq_enabled) {
+                       mutex_unlock(&vub300->irq_mutex);
+               } else if (vub300->irqs_queued) {
+                       vub300->irqs_queued -= 1;
+                       mmc_signal_sdio_irq(vub300->mmc);
+                       mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+                       mutex_unlock(&vub300->irq_mutex);
+               } else { /* NOT vub300->irqs_queued */
+                       mutex_unlock(&vub300->irq_mutex);
+                       __do_poll(vub300);
+               }
+       }
+       mutex_unlock(&vub300->cmd_mutex);
+       kref_put(&vub300->kref, vub300_delete);
+}
+
+static void vub300_deadwork_thread(struct work_struct *work)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 =
+               container_of(work, struct vub300_mmc_host, deadwork);
+       if (!vub300->interface) {
+               kref_put(&vub300->kref, vub300_delete);
+               return;
+       }
+       mutex_lock(&vub300->cmd_mutex);
+       if (vub300->cmd) {
+               /*
+                * a command got in as the inactivity
+                * timer expired - so we just let the
+                * processing of the command show if
+                * the device is dead
+                */
+       } else if (vub300->card_present) {
+               check_vub300_port_status(vub300);
+       } else if (vub300->mmc && vub300->mmc->card &&
+                  mmc_card_present(vub300->mmc->card)) {
+               /*
+                * the MMC core must not have responded
+                * to the previous indication - lets
+                * hope that it eventually does so we
+                * will just ignore this for now
+                */
+       } else {
+               check_vub300_port_status(vub300);
+       }
+       mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+       mutex_unlock(&vub300->cmd_mutex);
+       kref_put(&vub300->kref, vub300_delete);
+}
+
+static void vub300_inactivity_timer_expired(unsigned long data)
+{                              /* softirq */
+       struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)data;
+       if (!vub300->interface) {
+               kref_put(&vub300->kref, vub300_delete);
+       } else if (vub300->cmd) {
+               mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+       } else {
+               vub300_queue_dead_work(vub300);
+               mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+       }
+}
+
+static int vub300_response_error(u8 error_code)
+{
+       switch (error_code) {
+       case SD_ERROR_PIO_TIMEOUT:
+       case SD_ERROR_1BIT_TIMEOUT:
+       case SD_ERROR_4BIT_TIMEOUT:
+               return -ETIMEDOUT;
+       case SD_ERROR_STAT_DATA:
+       case SD_ERROR_OVERRUN:
+       case SD_ERROR_STAT_CMD:
+       case SD_ERROR_STAT_CMD_TIMEOUT:
+       case SD_ERROR_SDCRDY_STUCK:
+       case SD_ERROR_UNHANDLED:
+       case SD_ERROR_1BIT_CRC_WRONG:
+       case SD_ERROR_4BIT_CRC_WRONG:
+       case SD_ERROR_1BIT_CRC_ERROR:
+       case SD_ERROR_4BIT_CRC_ERROR:
+       case SD_ERROR_NO_CMD_ENDBIT:
+       case SD_ERROR_NO_1BIT_DATEND:
+       case SD_ERROR_NO_4BIT_DATEND:
+       case SD_ERROR_1BIT_DATA_TIMEOUT:
+       case SD_ERROR_4BIT_DATA_TIMEOUT:
+       case SD_ERROR_1BIT_UNEXPECTED_TIMEOUT:
+       case SD_ERROR_4BIT_UNEXPECTED_TIMEOUT:
+               return -EILSEQ;
+       case 33:
+               return -EILSEQ;
+       case SD_ERROR_ILLEGAL_COMMAND:
+               return -EINVAL;
+       case SD_ERROR_NO_DEVICE:
+               return -ENOMEDIUM;
+       default:
+               return -ENODEV;
+       }
+}
+
+static void command_res_completed(struct urb *urb)
+{                              /* urb completion handler - hardirq */
+       struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
+       if (urb->status) {
+               /* we have to let the initiator handle the error */
+       } else if (vub300->command_res_urb->actual_length == 0) {
+               /*
+                * we have seen this happen once or twice and
+                * we suspect a buggy USB host controller
+                */
+       } else if (!vub300->data) {
+               /* this means that the command (typically CMD52) suceeded */
+       } else if (vub300->resp.common.header_type != 0x02) {
+               /*
+                * this is an error response from the VUB300 chip
+                * and we let the initiator handle it
+                */
+       } else if (vub300->urb) {
+               vub300->cmd->error =
+                       vub300_response_error(vub300->resp.error.error_code);
+               usb_unlink_urb(vub300->urb);
+       } else {
+               vub300->cmd->error =
+                       vub300_response_error(vub300->resp.error.error_code);
+               usb_sg_cancel(&vub300->sg_request);
+       }
+       complete(&vub300->command_complete);    /* got_response_in */
+}
+
+static void command_out_completed(struct urb *urb)
+{                              /* urb completion handler - hardirq */
+       struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
+       if (urb->status) {
+               complete(&vub300->command_complete);
+       } else {
+               int ret;
+               unsigned int pipe =
+                       usb_rcvbulkpipe(vub300->udev, vub300->cmnd_res_ep);
+               usb_fill_bulk_urb(vub300->command_res_urb, vub300->udev, pipe,
+                                 &vub300->resp, sizeof(vub300->resp),
+                                 command_res_completed, vub300);
+               vub300->command_res_urb->actual_length = 0;
+               ret = usb_submit_urb(vub300->command_res_urb, GFP_ATOMIC);
+               if (ret == 0) {
+                       /*
+                        * the urb completion handler will call
+                        * our completion handler
+                        */
+               } else {
+                       /*
+                        * and thus we only call it directly
+                        * when it will not be called
+                        */
+                       complete(&vub300->command_complete);
+               }
+       }
+}
+
+/*
+ * the STUFF bits are masked out for the comparisons
+ */
+static void snoop_block_size_and_bus_width(struct vub300_mmc_host *vub300,
+                                          u32 cmd_arg)
+{
+       if ((0xFBFFFE00 & cmd_arg) == 0x80022200)
+               vub300->fbs[1] = (cmd_arg << 8) | (0x00FF & vub300->fbs[1]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x80022000)
+               vub300->fbs[1] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[1]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x80042200)
+               vub300->fbs[2] = (cmd_arg << 8) | (0x00FF & vub300->fbs[2]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x80042000)
+               vub300->fbs[2] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[2]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x80062200)
+               vub300->fbs[3] = (cmd_arg << 8) | (0x00FF & vub300->fbs[3]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x80062000)
+               vub300->fbs[3] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[3]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x80082200)
+               vub300->fbs[4] = (cmd_arg << 8) | (0x00FF & vub300->fbs[4]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x80082000)
+               vub300->fbs[4] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[4]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x800A2200)
+               vub300->fbs[5] = (cmd_arg << 8) | (0x00FF & vub300->fbs[5]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x800A2000)
+               vub300->fbs[5] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[5]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x800C2200)
+               vub300->fbs[6] = (cmd_arg << 8) | (0x00FF & vub300->fbs[6]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x800C2000)
+               vub300->fbs[6] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[6]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x800E2200)
+               vub300->fbs[7] = (cmd_arg << 8) | (0x00FF & vub300->fbs[7]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x800E2000)
+               vub300->fbs[7] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[7]);
+       else if ((0xFBFFFE03 & cmd_arg) == 0x80000E00)
+               vub300->bus_width = 1;
+       else if ((0xFBFFFE03 & cmd_arg) == 0x80000E02)
+               vub300->bus_width = 4;
+}
+
+static void send_command(struct vub300_mmc_host *vub300)
+{
+       /* cmd_mutex is held by vub300_cmndwork_thread */
+       struct mmc_command *cmd = vub300->cmd;
+       struct mmc_data *data = vub300->data;
+       int retval;
+       int i;
+       u8 response_type;
+       if (vub300->app_spec) {
+               switch (cmd->opcode) {
+               case 6:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       if (0x00000000 == (0x00000003 & cmd->arg))
+                               vub300->bus_width = 1;
+                       else if (0x00000002 == (0x00000003 & cmd->arg))
+                               vub300->bus_width = 4;
+                       else
+                               dev_err(&vub300->udev->dev,
+                                       "unexpected ACMD6 bus_width=%d\n",
+                                       0x00000003 & cmd->arg);
+                       break;
+               case 13:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 22:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 23:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 41:
+                       response_type = SDRT_3;
+                       vub300->resp_len = 6;
+                       break;
+               case 42:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 51:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 55:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               default:
+                       vub300->resp_len = 0;
+                       cmd->error = -EINVAL;
+                       complete(&vub300->command_complete);
+                       return;
+               }
+               vub300->app_spec = 0;
+       } else {
+               switch (cmd->opcode) {
+               case 0:
+                       response_type = SDRT_NONE;
+                       vub300->resp_len = 0;
+                       break;
+               case 1:
+                       response_type = SDRT_3;
+                       vub300->resp_len = 6;
+                       break;
+               case 2:
+                       response_type = SDRT_2;
+                       vub300->resp_len = 17;
+                       break;
+               case 3:
+                       response_type = SDRT_6;
+                       vub300->resp_len = 6;
+                       break;
+               case 4:
+                       response_type = SDRT_NONE;
+                       vub300->resp_len = 0;
+                       break;
+               case 5:
+                       response_type = SDRT_4;
+                       vub300->resp_len = 6;
+                       break;
+               case 6:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 7:
+                       response_type = SDRT_1B;
+                       vub300->resp_len = 6;
+                       break;
+               case 8:
+                       response_type = SDRT_7;
+                       vub300->resp_len = 6;
+                       break;
+               case 9:
+                       response_type = SDRT_2;
+                       vub300->resp_len = 17;
+                       break;
+               case 10:
+                       response_type = SDRT_2;
+                       vub300->resp_len = 17;
+                       break;
+               case 12:
+                       response_type = SDRT_1B;
+                       vub300->resp_len = 6;
+                       break;
+               case 13:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 15:
+                       response_type = SDRT_NONE;
+                       vub300->resp_len = 0;
+                       break;
+               case 16:
+                       for (i = 0; i < ARRAY_SIZE(vub300->fbs); i++)
+                               vub300->fbs[i] = 0xFFFF & cmd->arg;
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 17:
+               case 18:
+               case 24:
+               case 25:
+               case 27:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 28:
+               case 29:
+                       response_type = SDRT_1B;
+                       vub300->resp_len = 6;
+                       break;
+               case 30:
+               case 32:
+               case 33:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 38:
+                       response_type = SDRT_1B;
+                       vub300->resp_len = 6;
+                       break;
+               case 42:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 52:
+                       response_type = SDRT_5;
+                       vub300->resp_len = 6;
+                       snoop_block_size_and_bus_width(vub300, cmd->arg);
+                       break;
+               case 53:
+                       response_type = SDRT_5;
+                       vub300->resp_len = 6;
+                       break;
+               case 55:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       vub300->app_spec = 1;
+                       break;
+               case 56:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               default:
+                       vub300->resp_len = 0;
+                       cmd->error = -EINVAL;
+                       complete(&vub300->command_complete);
+                       return;
+               }
+       }
+       /*
+        * it is a shame that we can not use "sizeof(struct sd_command_header)"
+        * this is because the packet _must_ be padded to 64 bytes
+        */
+       vub300->cmnd.head.header_size = 20;
+       vub300->cmnd.head.header_type = 0x00;
+       vub300->cmnd.head.port_number = 0; /* "0" means port 1 */
+       vub300->cmnd.head.command_type = 0x00; /* standard read command */
+       vub300->cmnd.head.response_type = response_type;
+       vub300->cmnd.head.command_index = cmd->opcode;
+       vub300->cmnd.head.arguments[0] = cmd->arg >> 24;
+       vub300->cmnd.head.arguments[1] = cmd->arg >> 16;
+       vub300->cmnd.head.arguments[2] = cmd->arg >> 8;
+       vub300->cmnd.head.arguments[3] = cmd->arg >> 0;
+       if (cmd->opcode == 52) {
+               int fn = 0x7 & (cmd->arg >> 28);
+               vub300->cmnd.head.block_count[0] = 0;
+               vub300->cmnd.head.block_count[1] = 0;
+               vub300->cmnd.head.block_size[0] = (vub300->fbs[fn] >> 8) & 0xFF;
+               vub300->cmnd.head.block_size[1] = (vub300->fbs[fn] >> 0) & 0xFF;
+               vub300->cmnd.head.command_type = 0x00;
+               vub300->cmnd.head.transfer_size[0] = 0;
+               vub300->cmnd.head.transfer_size[1] = 0;
+               vub300->cmnd.head.transfer_size[2] = 0;
+               vub300->cmnd.head.transfer_size[3] = 0;
+       } else if (!data) {
+               vub300->cmnd.head.block_count[0] = 0;
+               vub300->cmnd.head.block_count[1] = 0;
+               vub300->cmnd.head.block_size[0] = (vub300->fbs[0] >> 8) & 0xFF;
+               vub300->cmnd.head.block_size[1] = (vub300->fbs[0] >> 0) & 0xFF;
+               vub300->cmnd.head.command_type = 0x00;
+               vub300->cmnd.head.transfer_size[0] = 0;
+               vub300->cmnd.head.transfer_size[1] = 0;
+               vub300->cmnd.head.transfer_size[2] = 0;
+               vub300->cmnd.head.transfer_size[3] = 0;
+       } else if (cmd->opcode == 53) {
+               int fn = 0x7 & (cmd->arg >> 28);
+               if (0x08 & vub300->cmnd.head.arguments[0]) { /* BLOCK MODE */
+                       vub300->cmnd.head.block_count[0] =
+                               (data->blocks >> 8) & 0xFF;
+                       vub300->cmnd.head.block_count[1] =
+                               (data->blocks >> 0) & 0xFF;
+                       vub300->cmnd.head.block_size[0] =
+                               (data->blksz >> 8) & 0xFF;
+                       vub300->cmnd.head.block_size[1] =
+                               (data->blksz >> 0) & 0xFF;
+               } else {        /* BYTE MODE */
+                       vub300->cmnd.head.block_count[0] = 0;
+                       vub300->cmnd.head.block_count[1] = 0;
+                       vub300->cmnd.head.block_size[0] =
+                               (vub300->datasize >> 8) & 0xFF;
+                       vub300->cmnd.head.block_size[1] =
+                               (vub300->datasize >> 0) & 0xFF;
+               }
+               vub300->cmnd.head.command_type =
+                       (MMC_DATA_READ & data->flags) ? 0x00 : 0x80;
+               vub300->cmnd.head.transfer_size[0] =
+                       (vub300->datasize >> 24) & 0xFF;
+               vub300->cmnd.head.transfer_size[1] =
+                       (vub300->datasize >> 16) & 0xFF;
+               vub300->cmnd.head.transfer_size[2] =
+                       (vub300->datasize >> 8) & 0xFF;
+               vub300->cmnd.head.transfer_size[3] =
+                       (vub300->datasize >> 0) & 0xFF;
+               if (vub300->datasize < vub300->fbs[fn]) {
+                       vub300->cmnd.head.block_count[0] = 0;
+                       vub300->cmnd.head.block_count[1] = 0;
+               }
+       } else {
+               vub300->cmnd.head.block_count[0] = (data->blocks >> 8) & 0xFF;
+               vub300->cmnd.head.block_count[1] = (data->blocks >> 0) & 0xFF;
+               vub300->cmnd.head.block_size[0] = (data->blksz >> 8) & 0xFF;
+               vub300->cmnd.head.block_size[1] = (data->blksz >> 0) & 0xFF;
+               vub300->cmnd.head.command_type =
+                       (MMC_DATA_READ & data->flags) ? 0x00 : 0x80;
+               vub300->cmnd.head.transfer_size[0] =
+                       (vub300->datasize >> 24) & 0xFF;
+               vub300->cmnd.head.transfer_size[1] =
+                       (vub300->datasize >> 16) & 0xFF;
+               vub300->cmnd.head.transfer_size[2] =
+                       (vub300->datasize >> 8) & 0xFF;
+               vub300->cmnd.head.transfer_size[3] =
+                       (vub300->datasize >> 0) & 0xFF;
+               if (vub300->datasize < vub300->fbs[0]) {
+                       vub300->cmnd.head.block_count[0] = 0;
+                       vub300->cmnd.head.block_count[1] = 0;
+               }
+       }
+       if (vub300->cmnd.head.block_size[0] || vub300->cmnd.head.block_size[1]) {
+               u16 block_size = vub300->cmnd.head.block_size[1] |
+                       (vub300->cmnd.head.block_size[0] << 8);
+               u16 block_boundary = FIRMWARE_BLOCK_BOUNDARY -
+                       (FIRMWARE_BLOCK_BOUNDARY % block_size);
+               vub300->cmnd.head.block_boundary[0] =
+                       (block_boundary >> 8) & 0xFF;
+               vub300->cmnd.head.block_boundary[1] =
+                       (block_boundary >> 0) & 0xFF;
+       } else {
+               vub300->cmnd.head.block_boundary[0] = 0;
+               vub300->cmnd.head.block_boundary[1] = 0;
+       }
+       usb_fill_bulk_urb(vub300->command_out_urb, vub300->udev,
+                         usb_sndbulkpipe(vub300->udev, vub300->cmnd_out_ep),
+                         &vub300->cmnd, sizeof(vub300->cmnd),
+                         command_out_completed, vub300);
+       retval = usb_submit_urb(vub300->command_out_urb, GFP_KERNEL);
+       if (retval < 0) {
+               cmd->error = retval;
+               complete(&vub300->command_complete);
+               return;
+       } else {
+               return;
+       }
+}
+
+/*
+ * timer callback runs in atomic mode
+ *       so it cannot call usb_kill_urb()
+ */
+static void vub300_sg_timed_out(unsigned long data)
+{
+       struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)data;
+       vub300->usb_timed_out = 1;
+       usb_sg_cancel(&vub300->sg_request);
+       usb_unlink_urb(vub300->command_out_urb);
+       usb_unlink_urb(vub300->command_res_urb);
+}
+
+static u16 roundup_to_multiple_of_64(u16 number)
+{
+       return 0xFFC0 & (0x3F + number);
+}
+
+/*
+ * this is a separate function to solve the 80 column width restriction
+ */
+static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
+                                         const struct firmware *fw)
+{
+       u8 register_count = 0;
+       u16 ts = 0;
+       u16 interrupt_size = 0;
+       const u8 *data = fw->data;
+       int size = fw->size;
+       u8 c;
+       dev_info(&vub300->udev->dev, "using %s for SDIO offload processing\n",
+                vub300->vub_name);
+       do {
+               c = *data++;
+       } while (size-- && c); /* skip comment */
+       dev_info(&vub300->udev->dev, "using offload firmware %s %s\n", fw->data,
+                vub300->vub_name);
+       if (size < 4) {
+               dev_err(&vub300->udev->dev,
+                       "corrupt offload pseudocode in firmware %s\n",
+                       vub300->vub_name);
+               strncpy(vub300->vub_name, "corrupt offload pseudocode",
+                       sizeof(vub300->vub_name));
+               return;
+       }
+       interrupt_size += *data++;
+       size -= 1;
+       interrupt_size <<= 8;
+       interrupt_size += *data++;
+       size -= 1;
+       if (interrupt_size < size) {
+               u16 xfer_length = roundup_to_multiple_of_64(interrupt_size);
+               u8 *xfer_buffer = kmalloc(xfer_length, GFP_KERNEL);
+               if (xfer_buffer) {
+                       int retval;
+                       memcpy(xfer_buffer, data, interrupt_size);
+                       memset(xfer_buffer + interrupt_size, 0,
+                              xfer_length - interrupt_size);
+                       size -= interrupt_size;
+                       data += interrupt_size;
+                       retval =
+                               usb_control_msg(vub300->udev,
+                                               usb_sndctrlpipe(vub300->udev, 0),
+                                               SET_INTERRUPT_PSEUDOCODE,
+                                               USB_DIR_OUT | USB_TYPE_VENDOR |
+                                               USB_RECIP_DEVICE, 0x0000, 0x0000,
+                                               xfer_buffer, xfer_length, HZ);
+                       kfree(xfer_buffer);
+                       if (retval < 0) {
+                               strncpy(vub300->vub_name,
+                                       "SDIO pseudocode download failed",
+                                       sizeof(vub300->vub_name));
+                               return;
+                       }
+               } else {
+                       dev_err(&vub300->udev->dev,
+                               "not enough memory for xfer buffer to send"
+                               " INTERRUPT_PSEUDOCODE for %s %s\n", fw->data,
+                               vub300->vub_name);
+                       strncpy(vub300->vub_name,
+                               "SDIO interrupt pseudocode download failed",
+                               sizeof(vub300->vub_name));
+                       return;
+               }
+       } else {
+               dev_err(&vub300->udev->dev,
+                       "corrupt interrupt pseudocode in firmware %s %s\n",
+                       fw->data, vub300->vub_name);
+               strncpy(vub300->vub_name, "corrupt interrupt pseudocode",
+                       sizeof(vub300->vub_name));
+               return;
+       }
+       ts += *data++;
+       size -= 1;
+       ts <<= 8;
+       ts += *data++;
+       size -= 1;
+       if (ts < size) {
+               u16 xfer_length = roundup_to_multiple_of_64(ts);
+               u8 *xfer_buffer = kmalloc(xfer_length, GFP_KERNEL);
+               if (xfer_buffer) {
+                       int retval;
+                       memcpy(xfer_buffer, data, ts);
+                       memset(xfer_buffer + ts, 0,
+                              xfer_length - ts);
+                       size -= ts;
+                       data += ts;
+                       retval =
+                               usb_control_msg(vub300->udev,
+                                               usb_sndctrlpipe(vub300->udev, 0),
+                                               SET_TRANSFER_PSEUDOCODE,
+                                               USB_DIR_OUT | USB_TYPE_VENDOR |
+                                               USB_RECIP_DEVICE, 0x0000, 0x0000,
+                                               xfer_buffer, xfer_length, HZ);
+                       kfree(xfer_buffer);
+                       if (retval < 0) {
+                               strncpy(vub300->vub_name,
+                                       "SDIO pseudocode download failed",
+                                       sizeof(vub300->vub_name));
+                               return;
+                       }
+               } else {
+                       dev_err(&vub300->udev->dev,
+                               "not enough memory for xfer buffer to send"
+                               " TRANSFER_PSEUDOCODE for %s %s\n", fw->data,
+                               vub300->vub_name);
+                       strncpy(vub300->vub_name,
+                               "SDIO transfer pseudocode download failed",
+                               sizeof(vub300->vub_name));
+                       return;
+               }
+       } else {
+               dev_err(&vub300->udev->dev,
+                       "corrupt transfer pseudocode in firmware %s %s\n",
+                       fw->data, vub300->vub_name);
+               strncpy(vub300->vub_name, "corrupt transfer pseudocode",
+                       sizeof(vub300->vub_name));
+               return;
+       }
+       register_count += *data++;
+       size -= 1;
+       if (register_count * 4 == size) {
+               int I = vub300->dynamic_register_count = register_count;
+               int i = 0;
+               while (I--) {
+                       unsigned int func_num = 0;
+                       vub300->sdio_register[i].func_num = *data++;
+                       size -= 1;
+                       func_num += *data++;
+                       size -= 1;
+                       func_num <<= 8;
+                       func_num += *data++;
+                       size -= 1;
+                       func_num <<= 8;
+                       func_num += *data++;
+                       size -= 1;
+                       vub300->sdio_register[i].sdio_reg = func_num;
+                       vub300->sdio_register[i].activate = 1;
+                       vub300->sdio_register[i].prepared = 0;
+                       i += 1;
+               }
+               dev_info(&vub300->udev->dev,
+                        "initialized %d dynamic pseudocode registers\n",
+                        vub300->dynamic_register_count);
+               return;
+       } else {
+               dev_err(&vub300->udev->dev,
+                       "corrupt dynamic registers in firmware %s\n",
+                       vub300->vub_name);
+               strncpy(vub300->vub_name, "corrupt dynamic registers",
+                       sizeof(vub300->vub_name));
+               return;
+       }
+}
+
+/*
+ * if the binary containing the EMPTY PseudoCode can not be found
+ * vub300->vub_name is set anyway in order to prevent an automatic retry
+ */
+static void download_offload_pseudocode(struct vub300_mmc_host *vub300)
+{
+       struct mmc_card *card = vub300->mmc->card;
+       int sdio_funcs = card->sdio_funcs;
+       const struct firmware *fw = NULL;
+       int l = snprintf(vub300->vub_name, sizeof(vub300->vub_name),
+                        "vub_%04X%04X", card->cis.vendor, card->cis.device);
+       int n = 0;
+       int retval;
+       for (n = 0; n < sdio_funcs; n++) {
+               struct sdio_func *sf = card->sdio_func[n];
+               l += snprintf(vub300->vub_name + l,
+                             sizeof(vub300->vub_name) - l, "_%04X%04X",
+                             sf->vendor, sf->device);
+       };
+       snprintf(vub300->vub_name + l, sizeof(vub300->vub_name) - l, ".bin");
+       dev_info(&vub300->udev->dev, "requesting offload firmware %s\n",
+                vub300->vub_name);
+       retval = request_firmware(&fw, vub300->vub_name, &card->dev);
+       if (retval < 0) {
+               strncpy(vub300->vub_name, "vub_default.bin",
+                       sizeof(vub300->vub_name));
+               retval = request_firmware(&fw, vub300->vub_name, &card->dev);
+               if (retval < 0) {
+                       strncpy(vub300->vub_name,
+                               "no SDIO offload firmware found",
+                               sizeof(vub300->vub_name));
+               } else {
+                       __download_offload_pseudocode(vub300, fw);
+                       release_firmware(fw);
+               }
+       } else {
+               __download_offload_pseudocode(vub300, fw);
+               release_firmware(fw);
+       }
+}
+
+static void vub300_usb_bulk_msg_completion(struct urb *urb)
+{                              /* urb completion handler - hardirq */
+       complete((struct completion *)urb->context);
+}
+
+static int vub300_usb_bulk_msg(struct vub300_mmc_host *vub300,
+                              unsigned int pipe, void *data, int len,
+                              int *actual_length, int timeout_msecs)
+{
+       /* cmd_mutex is held by vub300_cmndwork_thread */
+       struct usb_device *usb_dev = vub300->udev;
+       struct completion done;
+       int retval;
+       vub300->urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!vub300->urb)
+               return -ENOMEM;
+       usb_fill_bulk_urb(vub300->urb, usb_dev, pipe, data, len,
+                         vub300_usb_bulk_msg_completion, NULL);
+       init_completion(&done);
+       vub300->urb->context = &done;
+       vub300->urb->actual_length = 0;
+       retval = usb_submit_urb(vub300->urb, GFP_KERNEL);
+       if (unlikely(retval))
+               goto out;
+       if (!wait_for_completion_timeout
+           (&done, msecs_to_jiffies(timeout_msecs))) {
+               retval = -ETIMEDOUT;
+               usb_kill_urb(vub300->urb);
+       } else {
+               retval = vub300->urb->status;
+       }
+out:
+       *actual_length = vub300->urb->actual_length;
+       usb_free_urb(vub300->urb);
+       vub300->urb = NULL;
+       return retval;
+}
+
+static int __command_read_data(struct vub300_mmc_host *vub300,
+                              struct mmc_command *cmd, struct mmc_data *data)
+{
+       /* cmd_mutex is held by vub300_cmndwork_thread */
+       int linear_length = vub300->datasize;
+       int padded_length = vub300->large_usb_packets ?
+               ((511 + linear_length) >> 9) << 9 :
+               ((63 + linear_length) >> 6) << 6;
+       if ((padded_length == linear_length) || !pad_input_to_usb_pkt) {
+               int result;
+               unsigned pipe;
+               pipe = usb_rcvbulkpipe(vub300->udev, vub300->data_inp_ep);
+               result = usb_sg_init(&vub300->sg_request, vub300->udev,
+                                    pipe, 0, data->sg,
+                                    data->sg_len, 0, GFP_KERNEL);
+               if (result < 0) {
+                       usb_unlink_urb(vub300->command_out_urb);
+                       usb_unlink_urb(vub300->command_res_urb);
+                       cmd->error = result;
+                       data->bytes_xfered = 0;
+                       return 0;
+               } else {
+                       vub300->sg_transfer_timer.expires =
+                               jiffies + msecs_to_jiffies(2000 +
+                                                 (linear_length / 16384));
+                       add_timer(&vub300->sg_transfer_timer);
+                       usb_sg_wait(&vub300->sg_request);
+                       del_timer(&vub300->sg_transfer_timer);
+                       if (vub300->sg_request.status < 0) {
+                               cmd->error = vub300->sg_request.status;
+                               data->bytes_xfered = 0;
+                               return 0;
+                       } else {
+                               data->bytes_xfered = vub300->datasize;
+                               return linear_length;
+                       }
+               }
+       } else {
+               u8 *buf = kmalloc(padded_length, GFP_KERNEL);
+               if (buf) {
+                       int result;
+                       unsigned pipe = usb_rcvbulkpipe(vub300->udev,
+                                                       vub300->data_inp_ep);
+                       int actual_length = 0;
+                       result = vub300_usb_bulk_msg(vub300, pipe, buf,
+                                            padded_length, &actual_length,
+                                            2000 + (padded_length / 16384));
+                       if (result < 0) {
+                               cmd->error = result;
+                               data->bytes_xfered = 0;
+                               kfree(buf);
+                               return 0;
+                       } else if (actual_length < linear_length) {
+                               cmd->error = -EREMOTEIO;
+                               data->bytes_xfered = 0;
+                               kfree(buf);
+                               return 0;
+                       } else {
+                               sg_copy_from_buffer(data->sg, data->sg_len, buf,
+                                                   linear_length);
+                               kfree(buf);
+                               data->bytes_xfered = vub300->datasize;
+                               return linear_length;
+                       }
+               } else {
+                       cmd->error = -ENOMEM;
+                       data->bytes_xfered = 0;
+                       return 0;
+               }
+       }
+}
+
+static int __command_write_data(struct vub300_mmc_host *vub300,
+                               struct mmc_command *cmd, struct mmc_data *data)
+{
+       /* cmd_mutex is held by vub300_cmndwork_thread */
+       unsigned pipe = usb_sndbulkpipe(vub300->udev, vub300->data_out_ep);
+       int linear_length = vub300->datasize;
+       int modulo_64_length = linear_length & 0x003F;
+       int modulo_512_length = linear_length & 0x01FF;
+       if (linear_length < 64) {
+               int result;
+               int actual_length;
+               sg_copy_to_buffer(data->sg, data->sg_len,
+                                 vub300->padded_buffer,
+                                 sizeof(vub300->padded_buffer));
+               memset(vub300->padded_buffer + linear_length, 0,
+                      sizeof(vub300->padded_buffer) - linear_length);
+               result = vub300_usb_bulk_msg(vub300, pipe, vub300->padded_buffer,
+                                            sizeof(vub300->padded_buffer),
+                                            &actual_length, 2000 +
+                                            (sizeof(vub300->padded_buffer) /
+                                             16384));
+               if (result < 0) {
+                       cmd->error = result;
+                       data->bytes_xfered = 0;
+               } else {
+                       data->bytes_xfered = vub300->datasize;
+               }
+       } else if ((!vub300->large_usb_packets && (0 < modulo_64_length)) ||
+                   (vub300->large_usb_packets && (64 > modulo_512_length))
+               ) {             /* don't you just love these work-rounds */
+               int padded_length = ((63 + linear_length) >> 6) << 6;
+               u8 *buf = kmalloc(padded_length, GFP_KERNEL);
+               if (buf) {
+                       int result;
+                       int actual_length;
+                       sg_copy_to_buffer(data->sg, data->sg_len, buf,
+                                         padded_length);
+                       memset(buf + linear_length, 0,
+                              padded_length - linear_length);
+                       result =
+                               vub300_usb_bulk_msg(vub300, pipe, buf,
+                                                   padded_length, &actual_length,
+                                                   2000 + padded_length / 16384);
+                       kfree(buf);
+                       if (result < 0) {
+                               cmd->error = result;
+                               data->bytes_xfered = 0;
+                       } else {
+                               data->bytes_xfered = vub300->datasize;
+                       }
+               } else {
+                       cmd->error = -ENOMEM;
+                       data->bytes_xfered = 0;
+               }
+       } else {                /* no data padding required */
+               int result;
+               unsigned char buf[64 * 4];
+               sg_copy_to_buffer(data->sg, data->sg_len, buf, sizeof(buf));
+               result = usb_sg_init(&vub300->sg_request, vub300->udev,
+                                    pipe, 0, data->sg,
+                                    data->sg_len, 0, GFP_KERNEL);
+               if (result < 0) {
+                       usb_unlink_urb(vub300->command_out_urb);
+                       usb_unlink_urb(vub300->command_res_urb);
+                       cmd->error = result;
+                       data->bytes_xfered = 0;
+               } else {
+                       vub300->sg_transfer_timer.expires =
+                               jiffies + msecs_to_jiffies(2000 +
+                                                          linear_length / 16384);
+                       add_timer(&vub300->sg_transfer_timer);
+                       usb_sg_wait(&vub300->sg_request);
+                       if (cmd->error) {
+                               data->bytes_xfered = 0;
+                       } else {
+                               del_timer(&vub300->sg_transfer_timer);
+                               if (vub300->sg_request.status < 0) {
+                                       cmd->error = vub300->sg_request.status;
+                                       data->bytes_xfered = 0;
+                               } else {
+                                       data->bytes_xfered = vub300->datasize;
+                               }
+                       }
+               }
+       }
+       return linear_length;
+}
+
+static void __vub300_command_response(struct vub300_mmc_host *vub300,
+                                     struct mmc_command *cmd,
+                                     struct mmc_data *data, int data_length)
+{
+       /* cmd_mutex is held by vub300_cmndwork_thread */
+       long respretval;
+       int msec_timeout = 1000 + data_length / 4;
+       respretval =
+               wait_for_completion_timeout(&vub300->command_complete,
+                                           msecs_to_jiffies(msec_timeout));
+       if (respretval == 0) { /* TIMED OUT */
+               /* we don't know which of "out" and "res" if any failed */
+               int result;
+               vub300->usb_timed_out = 1;
+               usb_kill_urb(vub300->command_out_urb);
+               usb_kill_urb(vub300->command_res_urb);
+               cmd->error = -ETIMEDOUT;
+               result = usb_lock_device_for_reset(vub300->udev,
+                                                  vub300->interface);
+               if (result == 0) {
+                       result = usb_reset_device(vub300->udev);
+                       usb_unlock_device(vub300->udev);
+               }
+       } else if (respretval < 0) {
+               /* we don't know which of "out" and "res" if any failed */
+               usb_kill_urb(vub300->command_out_urb);
+               usb_kill_urb(vub300->command_res_urb);
+               cmd->error = respretval;
+       } else if (cmd->error) {
+               /*
+                * the error occured sending the command
+                * or recieving the response
+                */
+       } else if (vub300->command_out_urb->status) {
+               vub300->usb_transport_fail = vub300->command_out_urb->status;
+               cmd->error = -EPROTO == vub300->command_out_urb->status ?
+                       -ESHUTDOWN : vub300->command_out_urb->status;
+       } else if (vub300->command_res_urb->status) {
+               vub300->usb_transport_fail = vub300->command_res_urb->status;
+               cmd->error = -EPROTO == vub300->command_res_urb->status ?
+                       -ESHUTDOWN : vub300->command_res_urb->status;
+       } else if (vub300->resp.common.header_type == 0x00) {
+               /*
+                * the command completed successfully
+                * and there was no piggybacked data
+                */
+       } else if (vub300->resp.common.header_type == RESPONSE_ERROR) {
+               cmd->error =
+                       vub300_response_error(vub300->resp.error.error_code);
+               if (vub300->data)
+                       usb_sg_cancel(&vub300->sg_request);
+       } else if (vub300->resp.common.header_type == RESPONSE_PIGGYBACKED) {
+               int offloaded_data_length =
+                       vub300->resp.common.header_size -
+                       sizeof(struct sd_register_header);
+               int register_count = offloaded_data_length >> 3;
+               int ri = 0;
+               while (register_count--) {
+                       add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
+                       ri += 1;
+               }
+               vub300->resp.common.header_size =
+                       sizeof(struct sd_register_header);
+               vub300->resp.common.header_type = 0x00;
+               cmd->error = 0;
+       } else if (vub300->resp.common.header_type == RESPONSE_PIG_DISABLED) {
+               int offloaded_data_length =
+                       vub300->resp.common.header_size -
+                       sizeof(struct sd_register_header);
+               int register_count = offloaded_data_length >> 3;
+               int ri = 0;
+               while (register_count--) {
+                       add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
+                       ri += 1;
+               }
+               mutex_lock(&vub300->irq_mutex);
+               if (vub300->irqs_queued) {
+                       vub300->irqs_queued += 1;
+               } else if (vub300->irq_enabled) {
+                       vub300->irqs_queued += 1;
+                       vub300_queue_poll_work(vub300, 0);
+               } else {
+                       vub300->irqs_queued += 1;
+               }
+               vub300->irq_disabled = 1;
+               mutex_unlock(&vub300->irq_mutex);
+               vub300->resp.common.header_size =
+                       sizeof(struct sd_register_header);
+               vub300->resp.common.header_type = 0x00;
+               cmd->error = 0;
+       } else if (vub300->resp.common.header_type == RESPONSE_PIG_ENABLED) {
+               int offloaded_data_length =
+                       vub300->resp.common.header_size -
+                       sizeof(struct sd_register_header);
+               int register_count = offloaded_data_length >> 3;
+               int ri = 0;
+               while (register_count--) {
+                       add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
+                       ri += 1;
+               }
+               mutex_lock(&vub300->irq_mutex);
+               if (vub300->irqs_queued) {
+                       vub300->irqs_queued += 1;
+               } else if (vub300->irq_enabled) {
+                       vub300->irqs_queued += 1;
+                       vub300_queue_poll_work(vub300, 0);
+               } else {
+                       vub300->irqs_queued += 1;
+               }
+               vub300->irq_disabled = 0;
+               mutex_unlock(&vub300->irq_mutex);
+               vub300->resp.common.header_size =
+                       sizeof(struct sd_register_header);
+               vub300->resp.common.header_type = 0x00;
+               cmd->error = 0;
+       } else {
+               cmd->error = -EINVAL;
+       }
+}
+
+static void construct_request_response(struct vub300_mmc_host *vub300,
+                                      struct mmc_command *cmd)
+{
+       int resp_len = vub300->resp_len;
+       int less_cmd = (17 == resp_len) ? resp_len : resp_len - 1;
+       int bytes = 3 & less_cmd;
+       int words = less_cmd >> 2;
+       u8 *r = vub300->resp.response.command_response;
+       if (bytes == 3) {
+               cmd->resp[words] = (r[1 + (words << 2)] << 24)
+                       | (r[2 + (words << 2)] << 16)
+                       | (r[3 + (words << 2)] << 8);
+       } else if (bytes == 2) {
+               cmd->resp[words] = (r[1 + (words << 2)] << 24)
+                       | (r[2 + (words << 2)] << 16);
+       } else if (bytes == 1) {
+               cmd->resp[words] = (r[1 + (words << 2)] << 24);
+       }
+       while (words-- > 0) {
+               cmd->resp[words] = (r[1 + (words << 2)] << 24)
+                       | (r[2 + (words << 2)] << 16)
+                       | (r[3 + (words << 2)] << 8)
+                       | (r[4 + (words << 2)] << 0);
+       }
+       if ((cmd->opcode == 53) && (0x000000FF & cmd->resp[0]))
+               cmd->resp[0] &= 0xFFFFFF00;
+}
+
+/* this thread runs only when there is an upper level command req outstanding */
+static void vub300_cmndwork_thread(struct work_struct *work)
+{
+       struct vub300_mmc_host *vub300 =
+               container_of(work, struct vub300_mmc_host, cmndwork);
+       if (!vub300->interface) {
+               kref_put(&vub300->kref, vub300_delete);
+               return;
+       } else {
+               struct mmc_request *req = vub300->req;
+               struct mmc_command *cmd = vub300->cmd;
+               struct mmc_data *data = vub300->data;
+               int data_length;
+               mutex_lock(&vub300->cmd_mutex);
+               init_completion(&vub300->command_complete);
+               if (likely(vub300->vub_name[0]) || !vub300->mmc->card ||
+                   !mmc_card_present(vub300->mmc->card)) {
+                       /*
+                        * the name of the EMPTY Pseudo firmware file
+                        * is used as a flag to indicate that the file
+                        * has been already downloaded to the VUB300 chip
+                        */
+               } else if (0 == vub300->mmc->card->sdio_funcs) {
+                       strncpy(vub300->vub_name, "SD memory device",
+                               sizeof(vub300->vub_name));
+               } else {
+                       download_offload_pseudocode(vub300);
+               }
+               send_command(vub300);
+               if (!data)
+                       data_length = 0;
+               else if (MMC_DATA_READ & data->flags)
+                       data_length = __command_read_data(vub300, cmd, data);
+               else
+                       data_length = __command_write_data(vub300, cmd, data);
+               __vub300_command_response(vub300, cmd, data, data_length);
+               vub300->req = NULL;
+               vub300->cmd = NULL;
+               vub300->data = NULL;
+               if (cmd->error) {
+                       if (cmd->error == -ENOMEDIUM)
+                               check_vub300_port_status(vub300);
+                       mutex_unlock(&vub300->cmd_mutex);
+                       mmc_request_done(vub300->mmc, req);
+                       kref_put(&vub300->kref, vub300_delete);
+                       return;
+               } else {
+                       construct_request_response(vub300, cmd);
+                       vub300->resp_len = 0;
+                       mutex_unlock(&vub300->cmd_mutex);
+                       kref_put(&vub300->kref, vub300_delete);
+                       mmc_request_done(vub300->mmc, req);
+                       return;
+               }
+       }
+}
+
+static int examine_cyclic_buffer(struct vub300_mmc_host *vub300,
+                                struct mmc_command *cmd, u8 Function)
+{
+       /* cmd_mutex is held by vub300_mmc_request */
+       u8 cmd0 = 0xFF & (cmd->arg >> 24);
+       u8 cmd1 = 0xFF & (cmd->arg >> 16);
+       u8 cmd2 = 0xFF & (cmd->arg >> 8);
+       u8 cmd3 = 0xFF & (cmd->arg >> 0);
+       int first = MAXREGMASK & vub300->fn[Function].offload_point;
+       struct offload_registers_access *rf = &vub300->fn[Function].reg[first];
+       if (cmd0 == rf->command_byte[0] &&
+           cmd1 == rf->command_byte[1] &&
+           cmd2 == rf->command_byte[2] &&
+           cmd3 == rf->command_byte[3]) {
+               u8 checksum = 0x00;
+               cmd->resp[1] = checksum << 24;
+               cmd->resp[0] = (rf->Respond_Byte[0] << 24)
+                       | (rf->Respond_Byte[1] << 16)
+                       | (rf->Respond_Byte[2] << 8)
+                       | (rf->Respond_Byte[3] << 0);
+               vub300->fn[Function].offload_point += 1;
+               vub300->fn[Function].offload_count -= 1;
+               vub300->total_offload_count -= 1;
+               return 1;
+       } else {
+               int delta = 1;  /* because it does not match the first one */
+               u8 register_count = vub300->fn[Function].offload_count - 1;
+               u32 register_point = vub300->fn[Function].offload_point + 1;
+               while (0 < register_count) {
+                       int point = MAXREGMASK & register_point;
+                       struct offload_registers_access *r =
+                               &vub300->fn[Function].reg[point];
+                       if (cmd0 == r->command_byte[0] &&
+                           cmd1 == r->command_byte[1] &&
+                           cmd2 == r->command_byte[2] &&
+                           cmd3 == r->command_byte[3]) {
+                               u8 checksum = 0x00;
+                               cmd->resp[1] = checksum << 24;
+                               cmd->resp[0] = (r->Respond_Byte[0] << 24)
+                                       | (r->Respond_Byte[1] << 16)
+                                       | (r->Respond_Byte[2] << 8)
+                                       | (r->Respond_Byte[3] << 0);
+                               vub300->fn[Function].offload_point += delta;
+                               vub300->fn[Function].offload_count -= delta;
+                               vub300->total_offload_count -= delta;
+                               return 1;
+                       } else {
+                               register_point += 1;
+                               register_count -= 1;
+                               delta += 1;
+                               continue;
+                       }
+               }
+               return 0;
+       }
+}
+
+static int satisfy_request_from_offloaded_data(struct vub300_mmc_host *vub300,
+                                              struct mmc_command *cmd)
+{
+       /* cmd_mutex is held by vub300_mmc_request */
+       u8 regs = vub300->dynamic_register_count;
+       u8 i = 0;
+       u8 func = FUN(cmd);
+       u32 reg = REG(cmd);
+       while (0 < regs--) {
+               if ((vub300->sdio_register[i].func_num == func) &&
+                   (vub300->sdio_register[i].sdio_reg == reg)) {
+                       if (!vub300->sdio_register[i].prepared) {
+                               return 0;
+                       } else if ((0x80000000 & cmd->arg) == 0x80000000) {
+                               /*
+                                * a write to a dynamic register
+                                * nullifies our offloaded value
+                                */
+                               vub300->sdio_register[i].prepared = 0;
+                               return 0;
+                       } else {
+                               u8 checksum = 0x00;
+                               u8 rsp0 = 0x00;
+                               u8 rsp1 = 0x00;
+                               u8 rsp2 = vub300->sdio_register[i].response;
+                               u8 rsp3 = vub300->sdio_register[i].regvalue;
+                               vub300->sdio_register[i].prepared = 0;
+                               cmd->resp[1] = checksum << 24;
+                               cmd->resp[0] = (rsp0 << 24)
+                                       | (rsp1 << 16)
+                                       | (rsp2 << 8)
+                                       | (rsp3 << 0);
+                               return 1;
+                       }
+               } else {
+                       i += 1;
+                       continue;
+               }
+       };
+       if (vub300->total_offload_count == 0)
+               return 0;
+       else if (vub300->fn[func].offload_count == 0)
+               return 0;
+       else
+               return examine_cyclic_buffer(vub300, cmd, func);
+}
+
+static void vub300_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
+{                              /* NOT irq */
+       struct mmc_command *cmd = req->cmd;
+       struct vub300_mmc_host *vub300 = mmc_priv(mmc);
+       if (!vub300->interface) {
+               cmd->error = -ESHUTDOWN;
+               mmc_request_done(mmc, req);
+               return;
+       } else {
+               struct mmc_data *data = req->data;
+               if (!vub300->card_powered) {
+                       cmd->error = -ENOMEDIUM;
+                       mmc_request_done(mmc, req);
+                       return;
+               }
+               if (!vub300->card_present) {
+                       cmd->error = -ENOMEDIUM;
+                       mmc_request_done(mmc, req);
+                       return;
+               }
+               if (vub300->usb_transport_fail) {
+                       cmd->error = vub300->usb_transport_fail;
+                       mmc_request_done(mmc, req);
+                       return;
+               }
+               if (!vub300->interface) {
+                       cmd->error = -ENODEV;
+                       mmc_request_done(mmc, req);
+                       return;
+               }
+               kref_get(&vub300->kref);
+               mutex_lock(&vub300->cmd_mutex);
+               mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+               /*
+                * for performance we have to return immediately
+                * if the requested data has been offloaded
+                */
+               if (cmd->opcode == 52 &&
+                   satisfy_request_from_offloaded_data(vub300, cmd)) {
+                       cmd->error = 0;
+                       mutex_unlock(&vub300->cmd_mutex);
+                       kref_put(&vub300->kref, vub300_delete);
+                       mmc_request_done(mmc, req);
+                       return;
+               } else {
+                       vub300->cmd = cmd;
+                       vub300->req = req;
+                       vub300->data = data;
+                       if (data)
+                               vub300->datasize = data->blksz * data->blocks;
+                       else
+                               vub300->datasize = 0;
+                       vub300_queue_cmnd_work(vub300);
+                       mutex_unlock(&vub300->cmd_mutex);
+                       kref_put(&vub300->kref, vub300_delete);
+                       /*
+                        * the kernel lock diagnostics complain
+                        * if the cmd_mutex * is "passed on"
+                        * to the cmndwork thread,
+                        * so we must release it now
+                        * and re-acquire it in the cmndwork thread
+                        */
+               }
+       }
+}
+
+static void __set_clock_speed(struct vub300_mmc_host *vub300, u8 buf[8],
+                             struct mmc_ios *ios)
+{
+       int buf_array_size = 8; /* ARRAY_SIZE(buf) does not work !!! */
+       int retval;
+       u32 kHzClock;
+       if (ios->clock >= 48000000)
+               kHzClock = 48000;
+       else if (ios->clock >= 24000000)
+               kHzClock = 24000;
+       else if (ios->clock >= 20000000)
+               kHzClock = 20000;
+       else if (ios->clock >= 15000000)
+               kHzClock = 15000;
+       else if (ios->clock >= 200000)
+               kHzClock = 200;
+       else
+               kHzClock = 0;
+       {
+               int i;
+               u64 c = kHzClock;
+               for (i = 0; i < buf_array_size; i++) {
+                       buf[i] = c;
+                       c >>= 8;
+               }
+       }
+       retval =
+               usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
+                               SET_CLOCK_SPEED,
+                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               0x00, 0x00, buf, buf_array_size, HZ);
+       if (retval != 8) {
+               dev_err(&vub300->udev->dev, "SET_CLOCK_SPEED"
+                       " %dkHz failed with retval=%d\n", kHzClock, retval);
+       } else {
+               dev_dbg(&vub300->udev->dev, "SET_CLOCK_SPEED"
+                       " %dkHz\n", kHzClock);
+       }
+}
+
+static void vub300_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 = mmc_priv(mmc);
+       if (!vub300->interface)
+               return;
+       kref_get(&vub300->kref);
+       mutex_lock(&vub300->cmd_mutex);
+       if ((ios->power_mode == MMC_POWER_OFF) && vub300->card_powered) {
+               vub300->card_powered = 0;
+               usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
+                               SET_SD_POWER,
+                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               0x0000, 0x0000, NULL, 0, HZ);
+               /* must wait for the VUB300 u-proc to boot up */
+               msleep(600);
+       } else if ((ios->power_mode == MMC_POWER_UP) && !vub300->card_powered) {
+               usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
+                               SET_SD_POWER,
+                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               0x0001, 0x0000, NULL, 0, HZ);
+               msleep(600);
+               vub300->card_powered = 1;
+       } else if (ios->power_mode == MMC_POWER_ON) {
+               u8 *buf = kmalloc(8, GFP_KERNEL);
+               if (buf) {
+                       __set_clock_speed(vub300, buf, ios);
+                       kfree(buf);
+               }
+       } else {
+               /* this should mean no change of state */
+       }
+       mutex_unlock(&vub300->cmd_mutex);
+       kref_put(&vub300->kref, vub300_delete);
+}
+
+static int vub300_mmc_get_ro(struct mmc_host *mmc)
+{
+       struct vub300_mmc_host *vub300 = mmc_priv(mmc);
+       return vub300->read_only;
+}
+
+static void vub300_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 = mmc_priv(mmc);
+       if (!vub300->interface)
+               return;
+       kref_get(&vub300->kref);
+       if (enable) {
+               mutex_lock(&vub300->irq_mutex);
+               if (vub300->irqs_queued) {
+                       vub300->irqs_queued -= 1;
+                       mmc_signal_sdio_irq(vub300->mmc);
+               } else if (vub300->irq_disabled) {
+                       vub300->irq_disabled = 0;
+                       vub300->irq_enabled = 1;
+                       vub300_queue_poll_work(vub300, 0);
+               } else if (vub300->irq_enabled) {
+                       /* this should not happen, so we will just ignore it */
+               } else {
+                       vub300->irq_enabled = 1;
+                       vub300_queue_poll_work(vub300, 0);
+               }
+               mutex_unlock(&vub300->irq_mutex);
+       } else {
+               vub300->irq_enabled = 0;
+       }
+       kref_put(&vub300->kref, vub300_delete);
+}
+
+void vub300_init_card(struct mmc_host *mmc, struct mmc_card *card)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 = mmc_priv(mmc);
+       dev_info(&vub300->udev->dev, "NO host QUIRKS for this card\n");
+}
+
+static struct mmc_host_ops vub300_mmc_ops = {
+       .request = vub300_mmc_request,
+       .set_ios = vub300_mmc_set_ios,
+       .get_ro = vub300_mmc_get_ro,
+       .enable_sdio_irq = vub300_enable_sdio_irq,
+       .init_card = vub300_init_card,
+};
+
+static int vub300_probe(struct usb_interface *interface,
+                       const struct usb_device_id *id)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 = NULL;
+       struct usb_host_interface *iface_desc;
+       struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface));
+       int i;
+       int retval = -ENOMEM;
+       struct urb *command_out_urb;
+       struct urb *command_res_urb;
+       struct mmc_host *mmc;
+       char manufacturer[48];
+       char product[32];
+       char serial_number[32];
+       usb_string(udev, udev->descriptor.iManufacturer, manufacturer,
+                  sizeof(manufacturer));
+       usb_string(udev, udev->descriptor.iProduct, product, sizeof(product));
+       usb_string(udev, udev->descriptor.iSerialNumber, serial_number,
+                  sizeof(serial_number));
+       dev_info(&udev->dev, "probing VID:PID(%04X:%04X) %s %s %s\n",
+                udev->descriptor.idVendor, udev->descriptor.idProduct,
+                manufacturer, product, serial_number);
+       command_out_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!command_out_urb) {
+               retval = -ENOMEM;
+               dev_err(&vub300->udev->dev,
+                       "not enough memory for the command_out_urb\n");
+               goto error0;
+       }
+       command_res_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!command_res_urb) {
+               retval = -ENOMEM;
+               dev_err(&vub300->udev->dev,
+                       "not enough memory for the command_res_urb\n");
+               goto error1;
+       }
+       /* this also allocates memory for our VUB300 mmc host device */
+       mmc = mmc_alloc_host(sizeof(struct vub300_mmc_host), &udev->dev);
+       if (!mmc) {
+               retval = -ENOMEM;
+               dev_err(&vub300->udev->dev,
+                       "not enough memory for the mmc_host\n");
+               goto error4;
+       }
+       /* MMC core transfer sizes tunable parameters */
+       mmc->caps = 0;
+       if (!force_1_bit_data_xfers)
+               mmc->caps |= MMC_CAP_4_BIT_DATA;
+       if (!force_polling_for_irqs)
+               mmc->caps |= MMC_CAP_SDIO_IRQ;
+       mmc->caps &= ~MMC_CAP_NEEDS_POLL;
+       /*
+        * MMC_CAP_NEEDS_POLL causes core.c:mmc_rescan() to poll
+        * for devices which results in spurious CMD7's being
+        * issued which stops some SDIO cards from working
+        */
+       if (limit_speed_to_24_MHz) {
+               mmc->caps |= MMC_CAP_MMC_HIGHSPEED;
+               mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+               mmc->f_max = 24000000;
+               dev_info(&udev->dev, "limiting SDIO speed to 24_MHz\n");
+       } else {
+               mmc->caps |= MMC_CAP_MMC_HIGHSPEED;
+               mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+               mmc->f_max = 48000000;
+       }
+       mmc->f_min = 200000;
+       mmc->max_blk_count = 511;
+       mmc->max_blk_size = 512;
+       mmc->max_segs = 128;
+       if (force_max_req_size)
+               mmc->max_req_size = force_max_req_size * 1024;
+       else
+               mmc->max_req_size = 64 * 1024;
+       mmc->max_seg_size = mmc->max_req_size;
+       mmc->ocr_avail = 0;
+       mmc->ocr_avail |= MMC_VDD_165_195;
+       mmc->ocr_avail |= MMC_VDD_20_21;
+       mmc->ocr_avail |= MMC_VDD_21_22;
+       mmc->ocr_avail |= MMC_VDD_22_23;
+       mmc->ocr_avail |= MMC_VDD_23_24;
+       mmc->ocr_avail |= MMC_VDD_24_25;
+       mmc->ocr_avail |= MMC_VDD_25_26;
+       mmc->ocr_avail |= MMC_VDD_26_27;
+       mmc->ocr_avail |= MMC_VDD_27_28;
+       mmc->ocr_avail |= MMC_VDD_28_29;
+       mmc->ocr_avail |= MMC_VDD_29_30;
+       mmc->ocr_avail |= MMC_VDD_30_31;
+       mmc->ocr_avail |= MMC_VDD_31_32;
+       mmc->ocr_avail |= MMC_VDD_32_33;
+       mmc->ocr_avail |= MMC_VDD_33_34;
+       mmc->ocr_avail |= MMC_VDD_34_35;
+       mmc->ocr_avail |= MMC_VDD_35_36;
+       mmc->ops = &vub300_mmc_ops;
+       vub300 = mmc_priv(mmc);
+       vub300->mmc = mmc;
+       vub300->card_powered = 0;
+       vub300->bus_width = 0;
+       vub300->cmnd.head.block_size[0] = 0x00;
+       vub300->cmnd.head.block_size[1] = 0x00;
+       vub300->app_spec = 0;
+       mutex_init(&vub300->cmd_mutex);
+       mutex_init(&vub300->irq_mutex);
+       vub300->command_out_urb = command_out_urb;
+       vub300->command_res_urb = command_res_urb;
+       vub300->usb_timed_out = 0;
+       vub300->dynamic_register_count = 0;
+
+       for (i = 0; i < ARRAY_SIZE(vub300->fn); i++) {
+               vub300->fn[i].offload_point = 0;
+               vub300->fn[i].offload_count = 0;
+       }
+
+       vub300->total_offload_count = 0;
+       vub300->irq_enabled = 0;
+       vub300->irq_disabled = 0;
+       vub300->irqs_queued = 0;
+
+       for (i = 0; i < ARRAY_SIZE(vub300->sdio_register); i++)
+               vub300->sdio_register[i++].activate = 0;
+
+       vub300->udev = udev;
+       vub300->interface = interface;
+       vub300->cmnd_res_ep = 0;
+       vub300->cmnd_out_ep = 0;
+       vub300->data_inp_ep = 0;
+       vub300->data_out_ep = 0;
+
+       for (i = 0; i < ARRAY_SIZE(vub300->fbs); i++)
+               vub300->fbs[i] = 512;
+
+       /*
+        *      set up the endpoint information
+        *
+        * use the first pair of bulk-in and bulk-out
+        *     endpoints for Command/Response+Interrupt
+        *
+        * use the second pair of bulk-in and bulk-out
+        *     endpoints for Data In/Out
+        */
+       vub300->large_usb_packets = 0;
+       iface_desc = interface->cur_altsetting;
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+               struct usb_endpoint_descriptor *endpoint =
+                       &iface_desc->endpoint[i].desc;
+               dev_info(&vub300->udev->dev,
+                        "vub300 testing %s EndPoint(%d) %02X\n",
+                        usb_endpoint_is_bulk_in(endpoint) ? "BULK IN" :
+                        usb_endpoint_is_bulk_out(endpoint) ? "BULK OUT" :
+                        "UNKNOWN", i, endpoint->bEndpointAddress);
+               if (endpoint->wMaxPacketSize > 64)
+                       vub300->large_usb_packets = 1;
+               if (usb_endpoint_is_bulk_in(endpoint)) {
+                       if (!vub300->cmnd_res_ep) {
+                               vub300->cmnd_res_ep =
+                                       endpoint->bEndpointAddress;
+                       } else if (!vub300->data_inp_ep) {
+                               vub300->data_inp_ep =
+                                       endpoint->bEndpointAddress;
+                       } else {
+                               dev_warn(&vub300->udev->dev,
+                                        "ignoring"
+                                        " unexpected bulk_in endpoint");
+                       }
+               } else if (usb_endpoint_is_bulk_out(endpoint)) {
+                       if (!vub300->cmnd_out_ep) {
+                               vub300->cmnd_out_ep =
+                                       endpoint->bEndpointAddress;
+                       } else if (!vub300->data_out_ep) {
+                               vub300->data_out_ep =
+                                       endpoint->bEndpointAddress;
+                       } else {
+                               dev_warn(&vub300->udev->dev,
+                                        "ignoring"
+                                        " unexpected bulk_out endpoint");
+                       }
+               } else {
+                       dev_warn(&vub300->udev->dev,
+                                "vub300 ignoring EndPoint(%d) %02X", i,
+                                endpoint->bEndpointAddress);
+               }
+       }
+       if (vub300->cmnd_res_ep && vub300->cmnd_out_ep &&
+           vub300->data_inp_ep && vub300->data_out_ep) {
+               dev_info(&vub300->udev->dev,
+                        "vub300 %s packets"
+                        " using EndPoints %02X %02X %02X %02X\n",
+                        vub300->large_usb_packets ? "LARGE" : "SMALL",
+                        vub300->cmnd_out_ep, vub300->cmnd_res_ep,
+                        vub300->data_out_ep, vub300->data_inp_ep);
+               /* we have the expected EndPoints */
+       } else {
+               dev_err(&vub300->udev->dev,
+                   "Could not find two sets of bulk-in/out endpoint pairs\n");
+               retval = -EINVAL;
+               goto error5;
+       }
+       retval =
+               usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
+                               GET_HC_INF0,
+                               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               0x0000, 0x0000, &vub300->hc_info,
+                               sizeof(vub300->hc_info), HZ);
+       if (retval < 0)
+               goto error5;
+       retval =
+               usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
+                               SET_ROM_WAIT_STATES,
+                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               firmware_rom_wait_states, 0x0000, NULL, 0, HZ);
+       if (retval < 0)
+               goto error5;
+       dev_info(&vub300->udev->dev,
+                "operating_mode = %s %s %d MHz %s %d byte USB packets\n",
+                (mmc->caps & MMC_CAP_SDIO_IRQ) ? "IRQs" : "POLL",
+                (mmc->caps & MMC_CAP_4_BIT_DATA) ? "4-bit" : "1-bit",
+                mmc->f_max / 1000000,
+                pad_input_to_usb_pkt ? "padding input data to" : "with",
+                vub300->large_usb_packets ? 512 : 64);
+       retval =
+               usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
+                               GET_SYSTEM_PORT_STATUS,
+                               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               0x0000, 0x0000, &vub300->system_port_status,
+                               sizeof(vub300->system_port_status), HZ);
+       if (retval < 0) {
+               goto error4;
+       } else if (sizeof(vub300->system_port_status) == retval) {
+               vub300->card_present =
+                       (0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
+               vub300->read_only =
+                       (0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
+       } else {
+               goto error4;
+       }
+       usb_set_intfdata(interface, vub300);
+       INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread);
+       INIT_WORK(&vub300->cmndwork, vub300_cmndwork_thread);
+       INIT_WORK(&vub300->deadwork, vub300_deadwork_thread);
+       kref_init(&vub300->kref);
+       init_timer(&vub300->sg_transfer_timer);
+       vub300->sg_transfer_timer.data = (unsigned long)vub300;
+       vub300->sg_transfer_timer.function = vub300_sg_timed_out;
+       kref_get(&vub300->kref);
+       init_timer(&vub300->inactivity_timer);
+       vub300->inactivity_timer.data = (unsigned long)vub300;
+       vub300->inactivity_timer.function = vub300_inactivity_timer_expired;
+       vub300->inactivity_timer.expires = jiffies + HZ;
+       add_timer(&vub300->inactivity_timer);
+       if (vub300->card_present)
+               dev_info(&vub300->udev->dev,
+                        "USB vub300 remote SDIO host controller[%d]"
+                        "connected with SD/SDIO card inserted\n",
+                        interface_to_InterfaceNumber(interface));
+       else
+               dev_info(&vub300->udev->dev,
+                        "USB vub300 remote SDIO host controller[%d]"
+                        "connected with no SD/SDIO card inserted\n",
+                        interface_to_InterfaceNumber(interface));
+       mmc_add_host(mmc);
+       return 0;
+error5:
+       mmc_free_host(mmc);
+       /*
+        * and hence also frees vub300
+        * which is contained at the end of struct mmc
+        */
+error4:
+       usb_free_urb(command_out_urb);
+error1:
+       usb_free_urb(command_res_urb);
+error0:
+       return retval;
+}
+
+static void vub300_disconnect(struct usb_interface *interface)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 = usb_get_intfdata(interface);
+       if (!vub300 || !vub300->mmc) {
+               return;
+       } else {
+               struct mmc_host *mmc = vub300->mmc;
+               if (!vub300->mmc) {
+                       return;
+               } else {
+                       int ifnum = interface_to_InterfaceNumber(interface);
+                       usb_set_intfdata(interface, NULL);
+                       /* prevent more I/O from starting */
+                       vub300->interface = NULL;
+                       kref_put(&vub300->kref, vub300_delete);
+                       mmc_remove_host(mmc);
+                       pr_info("USB vub300 remote SDIO host controller[%d]"
+                               " now disconnected", ifnum);
+                       return;
+               }
+       }
+}
+
+#ifdef CONFIG_PM
+static int vub300_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
+       if (!vub300 || !vub300->mmc) {
+               return 0;
+       } else {
+               struct mmc_host *mmc = vub300->mmc;
+               mmc_suspend_host(mmc);
+               return 0;
+       }
+}
+
+static int vub300_resume(struct usb_interface *intf)
+{
+       struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
+       if (!vub300 || !vub300->mmc) {
+               return 0;
+       } else {
+               struct mmc_host *mmc = vub300->mmc;
+               mmc_resume_host(mmc);
+               return 0;
+       }
+}
+#else
+#define vub300_suspend NULL
+#define vub300_resume NULL
+#endif
+static int vub300_pre_reset(struct usb_interface *intf)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
+       mutex_lock(&vub300->cmd_mutex);
+       return 0;
+}
+
+static int vub300_post_reset(struct usb_interface *intf)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
+       /* we are sure no URBs are active - no locking needed */
+       vub300->errors = -EPIPE;
+       mutex_unlock(&vub300->cmd_mutex);
+       return 0;
+}
+
+static struct usb_driver vub300_driver = {
+       .name = "vub300",
+       .probe = vub300_probe,
+       .disconnect = vub300_disconnect,
+       .suspend = vub300_suspend,
+       .resume = vub300_resume,
+       .pre_reset = vub300_pre_reset,
+       .post_reset = vub300_post_reset,
+       .id_table = vub300_table,
+       .supports_autosuspend = 1,
+};
+
+static int __init vub300_init(void)
+{                              /* NOT irq */
+       int result;
+
+       pr_info("VUB300 Driver rom wait states = %02X irqpoll timeout = %04X",
+               firmware_rom_wait_states, 0x0FFFF & firmware_irqpoll_timeout);
+       cmndworkqueue = create_singlethread_workqueue("kvub300c");
+       if (!cmndworkqueue) {
+               pr_err("not enough memory for the REQUEST workqueue");
+               result = -ENOMEM;
+               goto out1;
+       }
+       pollworkqueue = create_singlethread_workqueue("kvub300p");
+       if (!pollworkqueue) {
+               pr_err("not enough memory for the IRQPOLL workqueue");
+               result = -ENOMEM;
+               goto out2;
+       }
+       deadworkqueue = create_singlethread_workqueue("kvub300d");
+       if (!deadworkqueue) {
+               pr_err("not enough memory for the EXPIRED workqueue");
+               result = -ENOMEM;
+               goto out3;
+       }
+       result = usb_register(&vub300_driver);
+       if (result) {
+               pr_err("usb_register failed. Error number %d", result);
+               goto out4;
+       }
+       return 0;
+out4:
+       destroy_workqueue(deadworkqueue);
+out3:
+       destroy_workqueue(pollworkqueue);
+out2:
+       destroy_workqueue(cmndworkqueue);
+out1:
+       return result;
+}
+
+static void __exit vub300_exit(void)
+{
+       usb_deregister(&vub300_driver);
+       flush_workqueue(cmndworkqueue);
+       flush_workqueue(pollworkqueue);
+       flush_workqueue(deadworkqueue);
+       destroy_workqueue(cmndworkqueue);
+       destroy_workqueue(pollworkqueue);
+       destroy_workqueue(deadworkqueue);
+}
+
+module_init(vub300_init);
+module_exit(vub300_exit);
+
+MODULE_AUTHOR("Tony Olech <tony.olech@elandigitalsystems.com>");
+MODULE_DESCRIPTION("VUB300 USB to SD/MMC/SDIO adapter driver");
+MODULE_LICENSE("GPL");
index bc50d5ea5534e5775a70f4da6e91fe717b3c5d2d..4be8373d43e5c6af542c8a5a609fc8402e9b1dc0 100644 (file)
@@ -33,20 +33,6 @@ config MTD_TESTS
          should normally be compiled as kernel modules. The modules perform
          various checks and verifications when loaded.
 
-config MTD_PARTITIONS
-       bool "MTD partitioning support"
-       help
-         If you have a device which needs to divide its flash chip(s) up
-         into multiple 'partitions', each of which appears to the user as
-         a separate MTD device, you require this option to be enabled. If
-         unsure, say 'Y'.
-
-         Note, however, that you don't need this option for the DiskOnChip
-         devices. Partitioning on NFTL 'devices' is a different - that's the
-         'normal' form of partitioning used on a block device.
-
-if MTD_PARTITIONS
-
 config MTD_REDBOOT_PARTS
        tristate "RedBoot partition table parsing"
        ---help---
@@ -99,7 +85,7 @@ endif # MTD_REDBOOT_PARTS
 
 config MTD_CMDLINE_PARTS
        bool "Command line partition table parsing"
-       depends on MTD_PARTITIONS = "y" && MTD = "y"
+       depends on MTD = "y"
        ---help---
          Allow generic configuration of the MTD partition tables via the kernel
          command line. Multiple flash resources are supported for hardware where
@@ -163,8 +149,6 @@ config MTD_AR7_PARTS
        ---help---
          TI AR7 partitioning support
 
-endif # MTD_PARTITIONS
-
 comment "User Modules And Translation Layers"
 
 config MTD_CHAR
index d578095fb25595a5856a72be137dde75372b9c4d..39664c4229ff5139293dc63d27e09837d2a7696b 100644 (file)
@@ -4,8 +4,7 @@
 
 # Core functionality.
 obj-$(CONFIG_MTD)              += mtd.o
-mtd-y                          := mtdcore.o mtdsuper.o mtdconcat.o
-mtd-$(CONFIG_MTD_PARTITIONS)   += mtdpart.o
+mtd-y                          := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o
 mtd-$(CONFIG_MTD_OF_PARTS)     += ofpart.o
 
 obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
index 09cb7c8d93b48d80dc874319d8672b680871b42e..e1e122f2f92912bcc71d2418ffea1f3e77aeb3fa 100644 (file)
@@ -812,12 +812,9 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long
                                break;
 
                        if (time_after(jiffies, timeo)) {
-                               /* Urgh. Resume and pretend we weren't here.  */
-                               map_write(map, CMD(0xd0), adr);
-                               /* Make sure we're in 'read status' mode if it had finished */
-                               map_write(map, CMD(0x70), adr);
-                               chip->state = FL_ERASING;
-                               chip->oldstate = FL_READY;
+                               /* Urgh. Resume and pretend we weren't here.
+                                * Make sure we're in 'read status' mode if it had finished */
+                               put_chip(map, chip, adr);
                                printk(KERN_ERR "%s: Chip not ready after erase "
                                       "suspended: status = 0x%lx\n", map->name, status.x[0]);
                                return -EIO;
@@ -997,7 +994,6 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
 
        switch(chip->oldstate) {
        case FL_ERASING:
-               chip->state = chip->oldstate;
                /* What if one interleaved chip has finished and the
                   other hasn't? The old code would leave the finished
                   one in READY mode. That's bad, and caused -EROFS
index 0b49266840b94407eb53ba0aad9b17ad531f0997..23175edd5634ff16190b4d7be6ca74d3392e5e80 100644 (file)
@@ -462,13 +462,14 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
                        cfi_fixup_major_minor(cfi, extp);
 
                        /*
-                        * Valid primary extension versions are: 1.0, 1.1, 1.2, 1.3, 1.4
+                        * Valid primary extension versions are: 1.0, 1.1, 1.2, 1.3, 1.4, 1.5
                         * see: http://cs.ozerki.net/zap/pub/axim-x5/docs/cfi_r20.pdf, page 19 
                         *      http://www.spansion.com/Support/AppNotes/cfi_100_20011201.pdf
                         *      http://www.spansion.com/Support/Datasheets/s29ws-p_00_a12_e.pdf
+                        *      http://www.spansion.com/Support/Datasheets/S29GL_128S_01GS_00_02_e.pdf
                         */
                        if (extp->MajorVersion != '1' ||
-                           (extp->MajorVersion == '1' && (extp->MinorVersion < '0' || extp->MinorVersion > '4'))) {
+                           (extp->MajorVersion == '1' && (extp->MinorVersion < '0' || extp->MinorVersion > '5'))) {
                                printk(KERN_ERR "  Unknown Amd/Fujitsu Extended Query "
                                       "version %c.%c (%#02x/%#02x).\n",
                                       extp->MajorVersion, extp->MinorVersion,
@@ -710,9 +711,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                                 * there was an error (so leave the erase
                                 * routine to recover from it) or we trying to
                                 * use the erase-in-progress sector. */
-                               map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr);
-                               chip->state = FL_ERASING;
-                               chip->oldstate = FL_READY;
+                               put_chip(map, chip, adr);
                                printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__);
                                return -EIO;
                        }
@@ -762,7 +761,6 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
 
        switch(chip->oldstate) {
        case FL_ERASING:
-               chip->state = chip->oldstate;
                map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr);
                chip->oldstate = FL_READY;
                chip->state = FL_ERASING;
index ed56ad3884fbc5d88ef97c46e046da4d7afab3a8..179814a95f3ac73bf0cfd6110a201f651a8c0647 100644 (file)
@@ -296,6 +296,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
                                /* make sure we're in 'read status' mode */
                                map_write(map, CMD(0x70), cmd_addr);
                                chip->state = FL_ERASING;
+                               wake_up(&chip->wq);
                                mutex_unlock(&chip->mutex);
                                printk(KERN_ERR "Chip not ready after erase "
                                       "suspended: status = 0x%lx\n", status.x[0]);
index 97183c8c9e338cc22bc8979d91f4a32cd3723447..b78f23169d4e7dce23848eba02b7cf9b8f6cd43f 100644 (file)
@@ -294,7 +294,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
        dev->mtd.priv = dev;
        dev->mtd.owner = THIS_MODULE;
 
-       if (add_mtd_device(&dev->mtd)) {
+       if (mtd_device_register(&dev->mtd, NULL, 0)) {
                /* Device didn't get added, so free the entry */
                goto devinit_err;
        }
@@ -465,7 +465,7 @@ static void __devexit block2mtd_exit(void)
        list_for_each_safe(pos, next, &blkmtd_device_list) {
                struct block2mtd_dev *dev = list_entry(pos, typeof(*dev), list);
                block2mtd_sync(&dev->mtd);
-               del_mtd_device(&dev->mtd);
+               mtd_device_unregister(&dev->mtd);
                INFO("mtd%d: [%s] removed", dev->mtd.index,
                                dev->mtd.name + strlen("block2mtd: "));
                list_del(&dev->list);
index 5bf5f460e1327828c203710ffee7041044fb14b2..f7fbf6025ef286de5f7fc61c1d3eada86695073f 100644 (file)
@@ -597,7 +597,7 @@ void DoC2k_init(struct mtd_info *mtd)
                doc2klist = mtd;
                mtd->size = this->totlen;
                mtd->erasesize = this->erasesize;
-               add_mtd_device(mtd);
+               mtd_device_register(mtd, NULL, 0);
                return;
        }
 }
@@ -1185,7 +1185,7 @@ static void __exit cleanup_doc2000(void)
                this = mtd->priv;
                doc2klist = this->nextdoc;
 
-               del_mtd_device(mtd);
+               mtd_device_unregister(mtd);
 
                iounmap(this->virtadr);
                kfree(this->chips);
index 0990f7803628605fba21b083c0e426ae2697628c..241192f05bc8d2cb8bcc601f2c61b06cd815274e 100644 (file)
@@ -376,7 +376,7 @@ void DoCMil_init(struct mtd_info *mtd)
                this->nextdoc = docmillist;
                docmillist = mtd;
                mtd->size  = this->totlen;
-               add_mtd_device(mtd);
+               mtd_device_register(mtd, NULL, 0);
                return;
        }
 }
@@ -826,7 +826,7 @@ static void __exit cleanup_doc2001(void)
                this = mtd->priv;
                docmillist = this->nextdoc;
 
-               del_mtd_device(mtd);
+               mtd_device_unregister(mtd);
 
                iounmap(this->virtadr);
                kfree(this->chips);
index 8b36fa77a195840f273062e355b4c1706340133e..09ae0adc3ad07be984d9b936d9eda7fe24e0e86d 100644 (file)
@@ -499,7 +499,7 @@ void DoCMilPlus_init(struct mtd_info *mtd)
                docmilpluslist = mtd;
                mtd->size  = this->totlen;
                mtd->erasesize = this->erasesize;
-               add_mtd_device(mtd);
+               mtd_device_register(mtd, NULL, 0);
                return;
        }
 }
@@ -1091,7 +1091,7 @@ static void __exit cleanup_doc2001plus(void)
                this = mtd->priv;
                docmilpluslist = this->nextdoc;
 
-               del_mtd_device(mtd);
+               mtd_device_unregister(mtd);
 
                iounmap(this->virtadr);
                kfree(this->chips);
index 4b829f97d56cfe313292d68480ea5eabb675a28d..772a0ff89e0f7e316279d82632d0893ad89b0f64 100644 (file)
@@ -684,9 +684,10 @@ static int __init lart_flash_init (void)
 #endif
 
 #ifndef HAVE_PARTITIONS
-   result = add_mtd_device (&mtd);
+   result = mtd_device_register(&mtd, NULL, 0);
 #else
-   result = add_mtd_partitions (&mtd,lart_partitions, ARRAY_SIZE(lart_partitions));
+   result = mtd_device_register(&mtd, lart_partitions,
+                                ARRAY_SIZE(lart_partitions));
 #endif
 
    return (result);
@@ -695,9 +696,9 @@ static int __init lart_flash_init (void)
 static void __exit lart_flash_exit (void)
 {
 #ifndef HAVE_PARTITIONS
-   del_mtd_device (&mtd);
+   mtd_device_unregister(&mtd);
 #else
-   del_mtd_partitions (&mtd);
+   mtd_device_unregister(&mtd);
 #endif
 }
 
index 3fb981d4bb51071563ceb99805b9c4361033c12c..35180e475c4c565fded31dc91d6fe05c91aec805 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/sched.h>
 #include <linux/mod_devicetable.h>
 
+#include <linux/mtd/cfi.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
@@ -55,6 +56,9 @@
 #define        OPCODE_EN4B             0xb7    /* Enter 4-byte mode */
 #define        OPCODE_EX4B             0xe9    /* Exit 4-byte mode */
 
+/* Used for Spansion flashes only. */
+#define        OPCODE_BRWR             0x17    /* Bank register write */
+
 /* Status Register bits. */
 #define        SR_WIP                  1       /* Write in progress */
 #define        SR_WEL                  2       /* Write enable latch */
@@ -76,6 +80,8 @@
 #define FAST_READ_DUMMY_BYTE 0
 #endif
 
+#define JEDEC_MFR(_jedec_id)   ((_jedec_id) >> 16)
+
 /****************************************************************************/
 
 struct m25p {
@@ -158,11 +164,18 @@ static inline int write_disable(struct m25p *flash)
 /*
  * Enable/disable 4-byte addressing mode.
  */
-static inline int set_4byte(struct m25p *flash, int enable)
+static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable)
 {
-       u8      code = enable ? OPCODE_EN4B : OPCODE_EX4B;
-
-       return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
+       switch (JEDEC_MFR(jedec_id)) {
+       case CFI_MFR_MACRONIX:
+               flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B;
+               return spi_write(flash->spi, flash->command, 1);
+       default:
+               /* Spansion style */
+               flash->command[0] = OPCODE_BRWR;
+               flash->command[1] = enable << 7;
+               return spi_write(flash->spi, flash->command, 2);
+       }
 }
 
 /*
@@ -668,6 +681,7 @@ static const struct spi_device_id m25p_ids[] = {
        /* Macronix */
        { "mx25l4005a",  INFO(0xc22013, 0, 64 * 1024,   8, SECT_4K) },
        { "mx25l8005",   INFO(0xc22014, 0, 64 * 1024,  16, 0) },
+       { "mx25l1606e",  INFO(0xc22015, 0, 64 * 1024,  32, SECT_4K) },
        { "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, 0) },
        { "mx25l6405d",  INFO(0xc22017, 0, 64 * 1024, 128, 0) },
        { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
@@ -684,6 +698,10 @@ static const struct spi_device_id m25p_ids[] = {
        { "s25sl032a",  INFO(0x010215,      0,  64 * 1024,  64, 0) },
        { "s25sl032p",  INFO(0x010215, 0x4d00,  64 * 1024,  64, SECT_4K) },
        { "s25sl064a",  INFO(0x010216,      0,  64 * 1024, 128, 0) },
+       { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) },
+       { "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512, 0) },
+       { "s25fl512s",  INFO(0x010220, 0x4d00, 256 * 1024, 256, 0) },
+       { "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
        { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64, 0) },
        { "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256, 0) },
        { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024,  64, 0) },
@@ -729,7 +747,10 @@ static const struct spi_device_id m25p_ids[] = {
        { "m25pe80", INFO(0x208014,  0, 64 * 1024, 16,       0) },
        { "m25pe16", INFO(0x208015,  0, 64 * 1024, 32, SECT_4K) },
 
-       { "m25px64", INFO(0x207117,  0, 64 * 1024, 128, 0) },
+       { "m25px32",    INFO(0x207116,  0, 64 * 1024, 64, SECT_4K) },
+       { "m25px32-s0", INFO(0x207316,  0, 64 * 1024, 64, SECT_4K) },
+       { "m25px32-s1", INFO(0x206316,  0, 64 * 1024, 64, SECT_4K) },
+       { "m25px64",    INFO(0x207117,  0, 64 * 1024, 128, 0) },
 
        /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
        { "w25x10", INFO(0xef3011, 0, 64 * 1024,  2,  SECT_4K) },
@@ -804,6 +825,8 @@ static int __devinit m25p_probe(struct spi_device *spi)
        struct m25p                     *flash;
        struct flash_info               *info;
        unsigned                        i;
+       struct mtd_partition            *parts = NULL;
+       int                             nr_parts = 0;
 
        /* Platform data helps sort out which chip type we have, as
         * well as how this board partitions it.  If we don't have
@@ -868,9 +891,9 @@ static int __devinit m25p_probe(struct spi_device *spi)
         * up with the software protection bits set
         */
 
-       if (info->jedec_id >> 16 == 0x1f ||
-           info->jedec_id >> 16 == 0x89 ||
-           info->jedec_id >> 16 == 0xbf) {
+       if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ATMEL ||
+           JEDEC_MFR(info->jedec_id) == CFI_MFR_INTEL ||
+           JEDEC_MFR(info->jedec_id) == CFI_MFR_SST) {
                write_enable(flash);
                write_sr(flash, 0);
        }
@@ -888,7 +911,7 @@ static int __devinit m25p_probe(struct spi_device *spi)
        flash->mtd.read = m25p80_read;
 
        /* sst flash chips use AAI word program */
-       if (info->jedec_id >> 16 == 0xbf)
+       if (JEDEC_MFR(info->jedec_id) == CFI_MFR_SST)
                flash->mtd.write = sst_write;
        else
                flash->mtd.write = m25p80_write;
@@ -914,7 +937,7 @@ static int __devinit m25p_probe(struct spi_device *spi)
                /* enable 4-byte addressing if the device exceeds 16MiB */
                if (flash->mtd.size > 0x1000000) {
                        flash->addr_width = 4;
-                       set_4byte(flash, 1);
+                       set_4byte(flash, info->jedec_id, 1);
                } else
                        flash->addr_width = 3;
        }
@@ -945,48 +968,41 @@ static int __devinit m25p_probe(struct spi_device *spi)
        /* partitions should match sector boundaries; and it may be good to
         * use readonly partitions for writeprotected sectors (BP2..BP0).
         */
-       if (mtd_has_partitions()) {
-               struct mtd_partition    *parts = NULL;
-               int                     nr_parts = 0;
-
-               if (mtd_has_cmdlinepart()) {
-                       static const char *part_probes[]
-                                       = { "cmdlinepart", NULL, };
+       if (mtd_has_cmdlinepart()) {
+               static const char *part_probes[]
+                       = { "cmdlinepart", NULL, };
 
-                       nr_parts = parse_mtd_partitions(&flash->mtd,
-                                       part_probes, &parts, 0);
-               }
+               nr_parts = parse_mtd_partitions(&flash->mtd,
+                                               part_probes, &parts, 0);
+       }
 
-               if (nr_parts <= 0 && data && data->parts) {
-                       parts = data->parts;
-                       nr_parts = data->nr_parts;
-               }
+       if (nr_parts <= 0 && data && data->parts) {
+               parts = data->parts;
+               nr_parts = data->nr_parts;
+       }
 
 #ifdef CONFIG_MTD_OF_PARTS
-               if (nr_parts <= 0 && spi->dev.of_node) {
-                       nr_parts = of_mtd_parse_partitions(&spi->dev,
-                                       spi->dev.of_node, &parts);
-               }
+       if (nr_parts <= 0 && spi->dev.of_node) {
+               nr_parts = of_mtd_parse_partitions(&spi->dev,
+                                                  spi->dev.of_node, &parts);
+       }
 #endif
 
-               if (nr_parts > 0) {
-                       for (i = 0; i < nr_parts; i++) {
-                               DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
-                                       "{.name = %s, .offset = 0x%llx, "
-                                               ".size = 0x%llx (%lldKiB) }\n",
-                                       i, parts[i].name,
-                                       (long long)parts[i].offset,
-                                       (long long)parts[i].size,
-                                       (long long)(parts[i].size >> 10));
-                       }
-                       flash->partitioned = 1;
-                       return add_mtd_partitions(&flash->mtd, parts, nr_parts);
+       if (nr_parts > 0) {
+               for (i = 0; i < nr_parts; i++) {
+                       DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
+                             "{.name = %s, .offset = 0x%llx, "
+                             ".size = 0x%llx (%lldKiB) }\n",
+                             i, parts[i].name,
+                             (long long)parts[i].offset,
+                             (long long)parts[i].size,
+                             (long long)(parts[i].size >> 10));
                }
-       } else if (data && data->nr_parts)
-               dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
-                               data->nr_parts, data->name);
+               flash->partitioned = 1;
+       }
 
-       return add_mtd_device(&flash->mtd) == 1 ? -ENODEV : 0;
+       return mtd_device_register(&flash->mtd, parts, nr_parts) == 1 ?
+               -ENODEV : 0;
 }
 
 
@@ -996,10 +1012,7 @@ static int __devexit m25p_remove(struct spi_device *spi)
        int             status;
 
        /* Clean up MTD stuff. */
-       if (mtd_has_partitions() && flash->partitioned)
-               status = del_mtd_partitions(&flash->mtd);
-       else
-               status = del_mtd_device(&flash->mtd);
+       status = mtd_device_unregister(&flash->mtd);
        if (status == 0) {
                kfree(flash->command);
                kfree(flash);
index 6a9a24a80a6d206a573fea039a8a0274b389db4d..8423fb6d4f26b05df635ee14608e654599627fc7 100644 (file)
@@ -220,7 +220,7 @@ static int __init ms02nv_init_one(ulong addr)
        mtd->writesize = 1;
 
        ret = -EIO;
-       if (add_mtd_device(mtd)) {
+       if (mtd_device_register(mtd, NULL, 0)) {
                printk(KERN_ERR
                        "ms02-nv: Unable to register MTD device, aborting!\n");
                goto err_out_csr_res;
@@ -262,7 +262,7 @@ static void __exit ms02nv_remove_one(void)
 
        root_ms02nv_mtd = mp->next;
 
-       del_mtd_device(mtd);
+       mtd_device_unregister(mtd);
 
        release_resource(mp->resource.csr);
        kfree(mp->resource.csr);
index c5015cc721d50d7f02f1994999810a2a150c01d4..13749d458a313297fed127f39399b3432e3be1ff 100644 (file)
@@ -637,6 +637,8 @@ add_dataflash_otp(struct spi_device *spi, char *name,
        struct flash_platform_data      *pdata = spi->dev.platform_data;
        char                            *otp_tag = "";
        int                             err = 0;
+       struct mtd_partition            *parts;
+       int                             nr_parts = 0;
 
        priv = kzalloc(sizeof *priv, GFP_KERNEL);
        if (!priv)
@@ -675,33 +677,25 @@ add_dataflash_otp(struct spi_device *spi, char *name,
                        pagesize, otp_tag);
        dev_set_drvdata(&spi->dev, priv);
 
-       if (mtd_has_partitions()) {
-               struct mtd_partition    *parts;
-               int                     nr_parts = 0;
+       if (mtd_has_cmdlinepart()) {
+               static const char *part_probes[] = { "cmdlinepart", NULL, };
 
-               if (mtd_has_cmdlinepart()) {
-                       static const char *part_probes[]
-                                       = { "cmdlinepart", NULL, };
-
-                       nr_parts = parse_mtd_partitions(device,
-                                       part_probes, &parts, 0);
-               }
+               nr_parts = parse_mtd_partitions(device, part_probes, &parts,
+                                               0);
+       }
 
-               if (nr_parts <= 0 && pdata && pdata->parts) {
-                       parts = pdata->parts;
-                       nr_parts = pdata->nr_parts;
-               }
+       if (nr_parts <= 0 && pdata && pdata->parts) {
+               parts = pdata->parts;
+               nr_parts = pdata->nr_parts;
+       }
 
-               if (nr_parts > 0) {
-                       priv->partitioned = 1;
-                       err = add_mtd_partitions(device, parts, nr_parts);
-                       goto out;
-               }
-       } else if (pdata && pdata->nr_parts)
-               dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
-                               pdata->nr_parts, device->name);
+       if (nr_parts > 0) {
+               priv->partitioned = 1;
+               err = mtd_device_register(device, parts, nr_parts);
+               goto out;
+       }
 
-       if (add_mtd_device(device) == 1)
+       if (mtd_device_register(device, NULL, 0) == 1)
                err = -ENODEV;
 
 out:
@@ -939,10 +933,7 @@ static int __devexit dataflash_remove(struct spi_device *spi)
 
        DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", dev_name(&spi->dev));
 
-       if (mtd_has_partitions() && flash->partitioned)
-               status = del_mtd_partitions(&flash->mtd);
-       else
-               status = del_mtd_device(&flash->mtd);
+       status = mtd_device_unregister(&flash->mtd);
        if (status == 0) {
                dev_set_drvdata(&spi->dev, NULL);
                kfree(flash);
index 1483e18971cef934b0c713fe9e5ab5727561cf12..2562689ba6b47d185edd5c3ba862af50a8ae97a8 100644 (file)
@@ -104,7 +104,7 @@ static int ram_write(struct mtd_info *mtd, loff_t to, size_t len,
 static void __exit cleanup_mtdram(void)
 {
        if (mtd_info) {
-               del_mtd_device(mtd_info);
+               mtd_device_unregister(mtd_info);
                vfree(mtd_info->priv);
                kfree(mtd_info);
        }
@@ -133,9 +133,8 @@ int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
        mtd->read = ram_read;
        mtd->write = ram_write;
 
-       if (add_mtd_device(mtd)) {
+       if (mtd_device_register(mtd, NULL, 0))
                return -EIO;
-       }
 
        return 0;
 }
index 8d28fa02a5a2f13d342c196be185ba4e88b68452..23423bd00b069da5266d72cbfa6353f21ec775dd 100644 (file)
@@ -115,7 +115,7 @@ static void unregister_devices(void)
        struct phram_mtd_list *this, *safe;
 
        list_for_each_entry_safe(this, safe, &phram_list, list) {
-               del_mtd_device(&this->mtd);
+               mtd_device_unregister(&this->mtd);
                iounmap(this->mtd.priv);
                kfree(this->mtd.name);
                kfree(this);
@@ -153,7 +153,7 @@ static int register_device(char *name, unsigned long start, unsigned long len)
        new->mtd.writesize = 1;
 
        ret = -EAGAIN;
-       if (add_mtd_device(&new->mtd)) {
+       if (mtd_device_register(&new->mtd, NULL, 0)) {
                pr_err("Failed to register new device\n");
                goto out2;
        }
index 41b8cdcc64cbf4184bf7d9bfb4b16b14cb7b9356..ecff765579dd395bbb73bacecd8b54bf375c7ee6 100644 (file)
@@ -798,7 +798,7 @@ static int __init init_pmc551(void)
                mtd->writesize = 1;
                mtd->owner = THIS_MODULE;
 
-               if (add_mtd_device(mtd)) {
+               if (mtd_device_register(mtd, NULL, 0)) {
                        printk(KERN_NOTICE "pmc551: Failed to register new device\n");
                        pci_iounmap(PCI_Device, priv->start);
                        kfree(mtd->priv);
@@ -806,7 +806,7 @@ static int __init init_pmc551(void)
                        break;
                }
 
-               /* Keep a reference as the add_mtd_device worked */
+               /* Keep a reference as the mtd_device_register worked */
                pci_dev_get(PCI_Device);
 
                printk(KERN_NOTICE "Registered pmc551 memory device.\n");
@@ -856,7 +856,7 @@ static void __exit cleanup_pmc551(void)
                pci_dev_put(priv->dev);
 
                kfree(mtd->priv);
-               del_mtd_device(mtd);
+               mtd_device_unregister(mtd);
                kfree(mtd);
                found++;
        }
index 592016a0668f9d9672393b48fa8cd3d9cb5f4443..e585263161b949ee1b863725ae627f6a4595fc7f 100644 (file)
@@ -210,7 +210,7 @@ static int register_device(char *name, unsigned long start, unsigned long length
        (*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ;
        (*curmtd)->mtdinfo->writesize = 1;
 
-       if (add_mtd_device((*curmtd)->mtdinfo)) {
+       if (mtd_device_register((*curmtd)->mtdinfo, NULL, 0))   {
                E("slram: Failed to register new device\n");
                iounmap(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start);
                kfree((*curmtd)->mtdinfo->priv);
@@ -231,7 +231,7 @@ static void unregister_devices(void)
 
        while (slram_mtdlist) {
                nextitem = slram_mtdlist->next;
-               del_mtd_device(slram_mtdlist->mtdinfo);
+               mtd_device_unregister(slram_mtdlist->mtdinfo);
                iounmap(((slram_priv_t *)slram_mtdlist->mtdinfo->priv)->start);
                kfree(slram_mtdlist->mtdinfo->priv);
                kfree(slram_mtdlist->mtdinfo);
index c163e619abc90647d38b45ba0e9799931c1abdd5..1e2c430aaad241b112d4c33a3c90d1db1e3b3efe 100644 (file)
@@ -66,7 +66,7 @@ struct flash_info {
 
 #define to_sst25l_flash(x) container_of(x, struct sst25l_flash, mtd)
 
-static struct flash_info __initdata sst25l_flash_info[] = {
+static struct flash_info __devinitdata sst25l_flash_info[] = {
        {"sst25lf020a", 0xbf43, 256, 1024, 4096},
        {"sst25lf040a", 0xbf44, 256, 2048, 4096},
 };
@@ -381,6 +381,8 @@ static int __devinit sst25l_probe(struct spi_device *spi)
        struct sst25l_flash *flash;
        struct flash_platform_data *data;
        int ret, i;
+       struct mtd_partition *parts = NULL;
+       int nr_parts = 0;
 
        flash_info = sst25l_match_device(spi);
        if (!flash_info)
@@ -420,46 +422,37 @@ static int __devinit sst25l_probe(struct spi_device *spi)
              flash->mtd.erasesize, flash->mtd.erasesize / 1024,
              flash->mtd.numeraseregions);
 
-       if (mtd_has_partitions()) {
-               struct mtd_partition *parts = NULL;
-               int nr_parts = 0;
 
-               if (mtd_has_cmdlinepart()) {
-                       static const char *part_probes[] =
-                               {"cmdlinepart", NULL};
+       if (mtd_has_cmdlinepart()) {
+               static const char *part_probes[] = {"cmdlinepart", NULL};
 
-                       nr_parts = parse_mtd_partitions(&flash->mtd,
-                                                       part_probes,
-                                                       &parts, 0);
-               }
+               nr_parts = parse_mtd_partitions(&flash->mtd,
+                                               part_probes,
+                                               &parts, 0);
+       }
 
-               if (nr_parts <= 0 && data && data->parts) {
-                       parts = data->parts;
-                       nr_parts = data->nr_parts;
-               }
+       if (nr_parts <= 0 && data && data->parts) {
+               parts = data->parts;
+               nr_parts = data->nr_parts;
+       }
 
-               if (nr_parts > 0) {
-                       for (i = 0; i < nr_parts; i++) {
-                               DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
-                                     "{.name = %s, .offset = 0x%llx, "
-                                     ".size = 0x%llx (%lldKiB) }\n",
-                                     i, parts[i].name,
-                                     (long long)parts[i].offset,
-                                     (long long)parts[i].size,
-                                     (long long)(parts[i].size >> 10));
-                       }
-
-                       flash->partitioned = 1;
-                       return add_mtd_partitions(&flash->mtd,
-                                                 parts, nr_parts);
+       if (nr_parts > 0) {
+               for (i = 0; i < nr_parts; i++) {
+                       DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
+                             "{.name = %s, .offset = 0x%llx, "
+                             ".size = 0x%llx (%lldKiB) }\n",
+                             i, parts[i].name,
+                             (long long)parts[i].offset,
+                             (long long)parts[i].size,
+                             (long long)(parts[i].size >> 10));
                }
 
-       } else if (data && data->nr_parts) {
-               dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
-                        data->nr_parts, data->name);
+               flash->partitioned = 1;
+               return mtd_device_register(&flash->mtd, parts,
+                                          nr_parts);
        }
 
-       ret = add_mtd_device(&flash->mtd);
+       ret = mtd_device_register(&flash->mtd, NULL, 0);
        if (ret == 1) {
                kfree(flash);
                dev_set_drvdata(&spi->dev, NULL);
@@ -469,15 +462,12 @@ static int __devinit sst25l_probe(struct spi_device *spi)
        return 0;
 }
 
-static int __exit sst25l_remove(struct spi_device *spi)
+static int __devexit sst25l_remove(struct spi_device *spi)
 {
        struct sst25l_flash *flash = dev_get_drvdata(&spi->dev);
        int ret;
 
-       if (mtd_has_partitions() && flash->partitioned)
-               ret = del_mtd_partitions(&flash->mtd);
-       else
-               ret = del_mtd_device(&flash->mtd);
+       ret = mtd_device_unregister(&flash->mtd);
        if (ret == 0)
                kfree(flash);
        return ret;
@@ -490,7 +480,7 @@ static struct spi_driver sst25l_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = sst25l_probe,
-       .remove         = __exit_p(sst25l_remove),
+       .remove         = __devexit_p(sst25l_remove),
 };
 
 static int __init sst25l_init(void)
index 12679925b420abd2c06b50f86162149f053b3b24..65655dd59e1f9e5948ac5bb138bd332abfa2cd05 100644 (file)
@@ -313,12 +313,7 @@ static int chip_ready(struct map_info *map, struct flchip *chip, int mode)
                if (ret) {
                        /* Oops. something got wrong. */
                        /* Resume and pretend we weren't here.  */
-                       map_write(map, CMD(LPDDR_RESUME),
-                               map->pfow_base + PFOW_COMMAND_CODE);
-                       map_write(map, CMD(LPDDR_START_EXECUTION),
-                               map->pfow_base + PFOW_COMMAND_EXECUTE);
-                       chip->state = FL_ERASING;
-                       chip->oldstate = FL_READY;
+                       put_chip(map, chip);
                        printk(KERN_ERR "%s: suspend operation failed."
                                        "State may be wrong \n", map->name);
                        return -EIO;
@@ -383,7 +378,6 @@ static void put_chip(struct map_info *map, struct flchip *chip)
 
        switch (chip->oldstate) {
        case FL_ERASING:
-               chip->state = chip->oldstate;
                map_write(map, CMD(LPDDR_RESUME),
                                map->pfow_base + PFOW_COMMAND_CODE);
                map_write(map, CMD(LPDDR_START_EXECUTION),
index 5069111c81cca9511c0f016cfd20705bf2c723a6..c0c328c5b133ccf51785a19385ae7a48a747aeaf 100644 (file)
@@ -82,7 +82,6 @@ config MTD_PHYSMAP_OF
 config MTD_PMC_MSP_EVM
        tristate "CFI Flash device mapped on PMC-Sierra MSP"
        depends on PMC_MSP && MTD_CFI
-       select MTD_PARTITIONS
        help
          This provides a 'mapping' driver which supports the way
          in which user-programmable flash chips are connected on the
@@ -122,7 +121,7 @@ config MTD_SC520CDP
 
 config MTD_NETSC520
        tristate "CFI Flash device mapped on AMD NetSc520"
-       depends on X86 && MTD_CFI && MTD_PARTITIONS
+       depends on X86 && MTD_CFI
        help
          This enables access routines for the flash chips on the AMD NetSc520
          demonstration board. If you have one of these boards and would like
@@ -131,7 +130,6 @@ config MTD_NETSC520
 config MTD_TS5500
        tristate "JEDEC Flash device mapped on Technologic Systems TS-5500"
        depends on X86
-       select MTD_PARTITIONS
        select MTD_JEDECPROBE
        select MTD_CFI_AMDSTD
        help
@@ -149,7 +147,7 @@ config MTD_TS5500
 
 config MTD_SBC_GXX
        tristate "CFI Flash device mapped on Arcom SBC-GXx boards"
-       depends on X86 && MTD_CFI_INTELEXT && MTD_PARTITIONS && MTD_COMPLEX_MAPPINGS
+       depends on X86 && MTD_CFI_INTELEXT && MTD_COMPLEX_MAPPINGS
        help
          This provides a driver for the on-board flash of Arcom Control
          Systems' SBC-GXn family of boards, formerly known as SBC-MediaGX.
@@ -161,7 +159,6 @@ config MTD_SBC_GXX
 config MTD_PXA2XX
        tristate "CFI Flash device mapped on Intel XScale PXA2xx based boards"
        depends on (PXA25x || PXA27x) && MTD_CFI_INTELEXT
-       select MTD_PARTITIONS
        help
          This provides a driver for the NOR flash attached to a PXA2xx chip.
 
@@ -185,7 +182,7 @@ config MTD_VMAX
 
 config MTD_SCx200_DOCFLASH
        tristate "Flash device mapped with DOCCS on NatSemi SCx200"
-       depends on SCx200 && MTD_CFI && MTD_PARTITIONS
+       depends on SCx200 && MTD_CFI
        help
          Enable support for a flash chip mapped using the DOCCS signal on a
          National Semiconductor SCx200 processor.
@@ -247,7 +244,7 @@ config MTD_TSUNAMI
 
 config MTD_NETtel
        tristate "CFI flash device on SnapGear/SecureEdge"
-       depends on X86 && MTD_PARTITIONS && MTD_JEDECPROBE
+       depends on X86 && MTD_JEDECPROBE
        help
          Support for flash chips on NETtel/SecureEdge/SnapGear boards.
 
@@ -269,7 +266,7 @@ config MTD_LANTIQ
 
 config MTD_DILNETPC
        tristate "CFI Flash device mapped on DIL/Net PC"
-       depends on X86 && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN
+       depends on X86 && MTD_CFI_INTELEXT && BROKEN
        help
          MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP".
          For details, see <http://www.ssv-embedded.de/ssv/pc104/p169.htm>
@@ -355,7 +352,7 @@ config MTD_CDB89712
 
 config MTD_SA1100
        tristate "CFI Flash device mapped on StrongARM SA11x0"
-       depends on MTD_CFI && ARCH_SA1100 && MTD_PARTITIONS
+       depends on MTD_CFI && ARCH_SA1100
        help
          This enables access to the flash chips on most platforms based on
          the SA1100 and SA1110, including the Assabet and the Compaq iPAQ.
@@ -389,7 +386,7 @@ config MTD_IXP2000
 
 config MTD_FORTUNET
        tristate "CFI Flash device mapped on the FortuNet board"
-       depends on MTD_CFI && MTD_PARTITIONS && SA1100_FORTUNET
+       depends on MTD_CFI && SA1100_FORTUNET
        help
          This enables access to the Flash on the FortuNet board.  If you
          have such a board, say 'Y'.
@@ -461,7 +458,6 @@ config MTD_PCMCIA_ANONYMOUS
 config MTD_BFIN_ASYNC
        tristate "Blackfin BF533-STAMP Flash Chip Support"
        depends on BFIN533_STAMP && MTD_CFI && MTD_COMPLEX_MAPPINGS
-       select MTD_PARTITIONS
        default y
        help
          Map driver which allows for simultaneous utilization of
@@ -473,7 +469,6 @@ config MTD_GPIO_ADDR
        tristate "GPIO-assisted Flash Chip Support"
        depends on GENERIC_GPIO || GPIOLIB
        depends on MTD_COMPLEX_MAPPINGS
-       select MTD_PARTITIONS
        help
          Map driver which allows flashes to be partially physically addressed
          and assisted by GPIOs.
@@ -482,14 +477,13 @@ config MTD_GPIO_ADDR
 
 config MTD_UCLINUX
        bool "Generic uClinux RAM/ROM filesystem support"
-       depends on MTD_PARTITIONS && MTD_RAM=y && !MMU
+       depends on MTD_RAM=y && !MMU
        help
          Map driver to support image based filesystems for uClinux.
 
 config MTD_WRSBC8260
        tristate "Map driver for WindRiver PowerQUICC II MPC82xx board"
        depends on (SBC82xx || SBC8560)
-       select MTD_PARTITIONS
        select MTD_MAP_BANK_WIDTH_4
        select MTD_MAP_BANK_WIDTH_1
        select MTD_CFI_I1
@@ -502,7 +496,6 @@ config MTD_WRSBC8260
 config MTD_DMV182
         tristate "Map driver for Dy-4 SVME/DMV-182 board."
         depends on DMV182
-        select MTD_PARTITIONS
        select MTD_MAP_BANK_WIDTH_32
        select MTD_CFI_I8
        select MTD_CFI_AMDSTD
index 92de7e3a49a5e3b1c6c0590c8c3687cdebd1c132..e2875d6fe129d81645e449e5fc685f5e4a60b3c8 100644 (file)
@@ -82,7 +82,7 @@ static void amd76xrom_cleanup(struct amd76xrom_window *window)
                if (map->rsrc.parent) {
                        release_resource(&map->rsrc);
                }
-               del_mtd_device(map->mtd);
+               mtd_device_unregister(map->mtd);
                map_destroy(map->mtd);
                list_del(&map->list);
                kfree(map);
@@ -262,7 +262,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
 
                /* Now that the mtd devices is complete claim and export it */
                map->mtd->owner = THIS_MODULE;
-               if (add_mtd_device(map->mtd)) {
+               if (mtd_device_register(map->mtd, NULL, 0)) {
                        map_destroy(map->mtd);
                        map->mtd = NULL;
                        goto out;
index 53664188fc471c1ecd03952abc7b044129ea16cb..e5bfd0e093bb1e20e0336f84e69eb7058dc7a822 100644 (file)
@@ -88,7 +88,7 @@ map:
        sram_mtd->owner = THIS_MODULE;
        sram_mtd->erasesize = 16;
 
-       if (add_mtd_device(sram_mtd)) {
+       if (mtd_device_register(sram_mtd, NULL, 0)) {
                printk("NV-RAM device addition failed\n");
                err = -ENOMEM;
                goto out_probe;
@@ -111,7 +111,7 @@ out:
 static void __exit cleanup_autcpu12_maps(void)
 {
        if (sram_mtd) {
-               del_mtd_device(sram_mtd);
+               mtd_device_unregister(sram_mtd);
                map_destroy(sram_mtd);
                iounmap((void *)autcpu12_sram_map.virt);
        }
index 1f3049590d9e0b80c6296c835c13b45224cb17dc..608967fe74c63b73c74268bed8306b1bba6a2079 100644 (file)
@@ -224,8 +224,8 @@ probe_ok:
                goto err_probe;
        }
 
-       return add_mtd_partitions(bcm963xx_mtd_info, parsed_parts,
-                                               parsed_nr_parts);
+       return mtd_device_register(bcm963xx_mtd_info, parsed_parts,
+                                  parsed_nr_parts);
 
 err_probe:
        iounmap(bcm963xx_map.virt);
@@ -235,7 +235,7 @@ err_probe:
 static int bcm963xx_remove(struct platform_device *pdev)
 {
        if (bcm963xx_mtd_info) {
-               del_mtd_partitions(bcm963xx_mtd_info);
+               mtd_device_unregister(bcm963xx_mtd_info);
                map_destroy(bcm963xx_mtd_info);
        }
 
index 85dd18193cf27a7deb18f24cc85273f6e3f2465a..d4297a97e1002d73769c6d7d7829a0fee12c17b9 100644 (file)
@@ -41,9 +41,7 @@ struct async_state {
        uint32_t flash_ambctl0, flash_ambctl1;
        uint32_t save_ambctl0, save_ambctl1;
        unsigned long irq_flags;
-#ifdef CONFIG_MTD_PARTITIONS
        struct mtd_partition *parts;
-#endif
 };
 
 static void switch_to_flash(struct async_state *state)
@@ -124,9 +122,7 @@ static void bfin_flash_copy_to(struct map_info *map, unsigned long to, const voi
        switch_back(state);
 }
 
-#ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
-#endif
 
 static int __devinit bfin_flash_probe(struct platform_device *pdev)
 {
@@ -169,22 +165,17 @@ static int __devinit bfin_flash_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-#ifdef CONFIG_MTD_PARTITIONS
        ret = parse_mtd_partitions(state->mtd, part_probe_types, &pdata->parts, 0);
        if (ret > 0) {
                pr_devinit(KERN_NOTICE DRIVER_NAME ": Using commandline partition definition\n");
-               add_mtd_partitions(state->mtd, pdata->parts, ret);
+               mtd_device_register(state->mtd, pdata->parts, ret);
                state->parts = pdata->parts;
-
        } else if (pdata->nr_parts) {
                pr_devinit(KERN_NOTICE DRIVER_NAME ": Using board partition definition\n");
-               add_mtd_partitions(state->mtd, pdata->parts, pdata->nr_parts);
-
-       } else
-#endif
-       {
+               mtd_device_register(state->mtd, pdata->parts, pdata->nr_parts);
+       } else {
                pr_devinit(KERN_NOTICE DRIVER_NAME ": no partition info available, registering whole flash at once\n");
-               add_mtd_device(state->mtd);
+               mtd_device_register(state->mtd, NULL, 0);
        }
 
        platform_set_drvdata(pdev, state);
@@ -196,10 +187,8 @@ static int __devexit bfin_flash_remove(struct platform_device *pdev)
 {
        struct async_state *state = platform_get_drvdata(pdev);
        gpio_free(state->enet_flash_pin);
-#ifdef CONFIG_MTD_PARTITIONS
-       del_mtd_partitions(state->mtd);
+       mtd_device_unregister(state->mtd);
        kfree(state->parts);
-#endif
        map_destroy(state->mtd);
        kfree(state);
        return 0;
index 8d92d8db9a98c0a3c5625ce74fd27a4268070ba4..c29cbf87ea0c9ea3279161c76bd0ee254cb5fd50 100644 (file)
@@ -75,7 +75,7 @@ static int __init init_cdb89712_flash (void)
 
        flash_mtd->owner = THIS_MODULE;
 
-       if (add_mtd_device(flash_mtd)) {
+       if (mtd_device_register(flash_mtd, NULL, 0)) {
                printk("FLASH device addition failed\n");
                err = -ENOMEM;
                goto out_probe;
@@ -141,7 +141,7 @@ static int __init init_cdb89712_sram (void)
        sram_mtd->owner = THIS_MODULE;
        sram_mtd->erasesize = 16;
 
-       if (add_mtd_device(sram_mtd)) {
+       if (mtd_device_register(sram_mtd, NULL, 0)) {
                printk("SRAM device addition failed\n");
                err = -ENOMEM;
                goto out_probe;
@@ -209,7 +209,7 @@ static int __init init_cdb89712_bootrom (void)
        bootrom_mtd->owner = THIS_MODULE;
        bootrom_mtd->erasesize = 0x10000;
 
-       if (add_mtd_device(bootrom_mtd)) {
+       if (mtd_device_register(bootrom_mtd, NULL, 0)) {
                printk("BootROM device addition failed\n");
                err = -ENOMEM;
                goto out_probe;
@@ -249,21 +249,21 @@ static int __init init_cdb89712_maps(void)
 static void __exit cleanup_cdb89712_maps(void)
 {
        if (sram_mtd) {
-               del_mtd_device(sram_mtd);
+               mtd_device_unregister(sram_mtd);
                map_destroy(sram_mtd);
                iounmap((void *)cdb89712_sram_map.virt);
                release_resource (&cdb89712_sram_resource);
        }
 
        if (flash_mtd) {
-               del_mtd_device(flash_mtd);
+               mtd_device_unregister(flash_mtd);
                map_destroy(flash_mtd);
                iounmap((void *)cdb89712_flash_map.virt);
                release_resource (&cdb89712_flash_resource);
        }
 
        if (bootrom_mtd) {
-               del_mtd_device(bootrom_mtd);
+               mtd_device_unregister(bootrom_mtd);
                map_destroy(bootrom_mtd);
                iounmap((void *)cdb89712_bootrom_map.virt);
                release_resource (&cdb89712_bootrom_resource);
index 23f551dc8ca8f14c2c6751b50eb068d569c7d0af..06f9c98157204c4994fff3528d4da2296500eb49 100644 (file)
@@ -224,7 +224,7 @@ static void __exit clps_destroy_mtd(struct clps_info *clps, struct mtd_info *mtd
 {
        int i;
 
-       del_mtd_partitions(mtd);
+       mtd_device_unregister(mtd);
 
        if (mtd != clps[0].mtd)
                mtd_concat_destroy(mtd);
@@ -292,11 +292,11 @@ static void __init clps_locate_partitions(struct mtd_info *mtd)
        if (nr_parts == 0) {
                printk(KERN_NOTICE "clps flash: no partition info "
                        "available, registering whole flash\n");
-               add_mtd_device(mtd);
+               mtd_device_register(mtd, NULL, 0);
        } else {
                printk(KERN_NOTICE "clps flash: using %s partition "
                        "definition\n", part_type);
-               add_mtd_partitions(mtd, parsed_parts, nr_parts);
+               mtd_device_register(mtd, parsed_parts, nr_parts);
        }
 
        /* Always succeeds. */
index f71343cd77cca60f1eef6a46e8088ee1779bba1c..d16fc9d3b8cd5bd58dae35c7f5e579e289ac9083 100644 (file)
@@ -107,7 +107,7 @@ static int __init init_flagadm(void)
        mymtd = do_map_probe("cfi_probe", &flagadm_map);
        if (mymtd) {
                mymtd->owner = THIS_MODULE;
-               add_mtd_partitions(mymtd, flagadm_parts, PARTITION_COUNT);
+               mtd_device_register(mymtd, flagadm_parts, PARTITION_COUNT);
                printk(KERN_NOTICE "FlagaDM flash device initialized\n");
                return 0;
        }
@@ -119,7 +119,7 @@ static int __init init_flagadm(void)
 static void __exit cleanup_flagadm(void)
 {
        if (mymtd) {
-               del_mtd_partitions(mymtd);
+               mtd_device_unregister(mymtd);
                map_destroy(mymtd);
        }
        if (flagadm_map.virt) {
index 5fdb7b26cea3e836e517dda937ab92fb72f6e0e4..3d0e762fa5f2ed5b0c306cdb3fb22373fa565962 100644 (file)
@@ -94,7 +94,7 @@ static void ck804xrom_cleanup(struct ck804xrom_window *window)
                if (map->rsrc.parent)
                        release_resource(&map->rsrc);
 
-               del_mtd_device(map->mtd);
+               mtd_device_unregister(map->mtd);
                map_destroy(map->mtd);
                list_del(&map->list);
                kfree(map);
@@ -291,7 +291,7 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev,
 
                /* Now that the mtd devices is complete claim and export it */
                map->mtd->owner = THIS_MODULE;
-               if (add_mtd_device(map->mtd)) {
+               if (mtd_device_register(map->mtd, NULL, 0)) {
                        map_destroy(map->mtd);
                        map->mtd = NULL;
                        goto out;
index cfacfa6f45ddd8708801765b5a35aff10dabec45..85bdece6ab3f281788e11f81fb9822c4b02e1fef 100644 (file)
@@ -93,7 +93,7 @@ static int __init init_dbox2_flash(void)
                mymtd->owner = THIS_MODULE;
 
                 /* Create MTD devices for each partition. */
-               add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
+               mtd_device_register(mymtd, partition_info, NUM_PARTITIONS);
 
                return 0;
        }
@@ -105,7 +105,7 @@ static int __init init_dbox2_flash(void)
 static void __exit cleanup_dbox2_flash(void)
 {
        if (mymtd) {
-               del_mtd_partitions(mymtd);
+               mtd_device_unregister(mymtd);
                map_destroy(mymtd);
        }
        if (dbox2_flash_map.virt) {
index b3cb3a18380995a250cf3c4614f7a5bfe3115cf1..7a9e1989c977a1c77694daead3cfd5b62013cb0d 100644 (file)
@@ -145,17 +145,13 @@ static struct map_info dc21285_map = {
 
 
 /* Partition stuff */
-#ifdef CONFIG_MTD_PARTITIONS
 static struct mtd_partition *dc21285_parts;
 static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-#endif
 
 static int __init init_dc21285(void)
 {
 
-#ifdef CONFIG_MTD_PARTITIONS
        int nrparts;
-#endif
 
        /* Determine bankwidth */
        switch (*CSR_SA110_CNTL & (3<<14)) {
@@ -204,13 +200,8 @@ static int __init init_dc21285(void)
 
        dc21285_mtd->owner = THIS_MODULE;
 
-#ifdef CONFIG_MTD_PARTITIONS
        nrparts = parse_mtd_partitions(dc21285_mtd, probes, &dc21285_parts, 0);
-       if (nrparts > 0)
-               add_mtd_partitions(dc21285_mtd, dc21285_parts, nrparts);
-       else
-#endif
-               add_mtd_device(dc21285_mtd);
+       mtd_device_register(dc21285_mtd, dc21285_parts, nrparts);
 
        if(machine_is_ebsa285()) {
                /*
@@ -232,14 +223,9 @@ static int __init init_dc21285(void)
 
 static void __exit cleanup_dc21285(void)
 {
-#ifdef CONFIG_MTD_PARTITIONS
-       if (dc21285_parts) {
-               del_mtd_partitions(dc21285_mtd);
+       mtd_device_unregister(dc21285_mtd);
+       if (dc21285_parts)
                kfree(dc21285_parts);
-       } else
-#endif
-               del_mtd_device(dc21285_mtd);
-
        map_destroy(dc21285_mtd);
        iounmap(dc21285_map.virt);
 }
index 0713e3a5a22cb4b4bf1baa1db4c5d57d01259e13..3e393f0da823cada1906598f31187e177c89479d 100644 (file)
@@ -450,7 +450,7 @@ static int __init init_dnpc(void)
        partition_info[2].mtdp = &lowlvl_parts[1];
        partition_info[3].mtdp = &lowlvl_parts[3];
 
-       add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
+       mtd_device_register(mymtd, partition_info, NUM_PARTITIONS);
 
        /*
        ** now create a virtual MTD device by concatenating the for partitions
@@ -463,7 +463,8 @@ static int __init init_dnpc(void)
                ** we do not supply mtd pointers in higlvl_partition_info, so
                ** add_mtd_partitions() will register the devices.
                */
-               add_mtd_partitions(merged_mtd, higlvl_partition_info, NUM_HIGHLVL_PARTITIONS);
+               mtd_device_register(merged_mtd, higlvl_partition_info,
+                                   NUM_HIGHLVL_PARTITIONS);
        }
 
        return 0;
@@ -472,12 +473,12 @@ static int __init init_dnpc(void)
 static void __exit cleanup_dnpc(void)
 {
        if(merged_mtd) {
-               del_mtd_partitions(merged_mtd);
+               mtd_device_unregister(merged_mtd);
                mtd_concat_destroy(merged_mtd);
        }
 
        if (mymtd) {
-               del_mtd_partitions(mymtd);
+               mtd_device_unregister(mymtd);
                map_destroy(mymtd);
        }
        if (dnpc_map.virt) {
index d171674eb2ed1ec17ee73a0c63a4bdb034e576d7..6538ac675e008b9dbd2c41436e5273763d5354b6 100644 (file)
@@ -120,7 +120,7 @@ static int __init init_svme182(void)
                   this_mtd->size >> 20, FLASH_BASE_ADDR);
 
        this_mtd->owner = THIS_MODULE;
-       add_mtd_partitions(this_mtd, partitions, num_parts);
+       mtd_device_register(this_mtd, partitions, num_parts);
 
        return 0;
 }
@@ -129,7 +129,7 @@ static void __exit cleanup_svme182(void)
 {
        if (this_mtd)
        {
-               del_mtd_partitions(this_mtd);
+               mtd_device_unregister(this_mtd);
                map_destroy(this_mtd);
        }
 
index be9e90b44587a45c7fce5be7659de52f7613dca9..fe42a212bb3ebfdc170dcdb5cee1e14f384849dd 100644 (file)
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
-
-#ifdef CONFIG_MTD_PARTITIONS
 #include <linux/mtd/partitions.h>
-#endif
 
 #define WINDOW_ADDR 0x00000000      /* physical properties of flash */
 #define WINDOW_SIZE 0x01000000
@@ -40,8 +37,6 @@ struct map_info edb7312nor_map = {
        .phys = WINDOW_ADDR,
 };
 
-#ifdef CONFIG_MTD_PARTITIONS
-
 /*
  * MTD partitioning stuff
  */
@@ -66,8 +61,6 @@ static struct mtd_partition static_partitions[3] =
 
 static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
 
-#endif
-
 static int                   mtd_parts_nb = 0;
 static struct mtd_partition *mtd_parts    = 0;
 
@@ -96,27 +89,24 @@ static int __init init_edb7312nor(void)
        if (mymtd) {
                mymtd->owner = THIS_MODULE;
 
-#ifdef CONFIG_MTD_PARTITIONS
                mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, MTDID);
                if (mtd_parts_nb > 0)
-                 part_type = "detected";
+                       part_type = "detected";
 
-               if (mtd_parts_nb == 0)
-               {
+               if (mtd_parts_nb == 0) {
                        mtd_parts = static_partitions;
                        mtd_parts_nb = ARRAY_SIZE(static_partitions);
                        part_type = "static";
                }
-#endif
-               add_mtd_device(mymtd);
+
                if (mtd_parts_nb == 0)
-                 printk(KERN_NOTICE MSG_PREFIX "no partition info available\n");
+                       printk(KERN_NOTICE MSG_PREFIX "no partition info available\n");
                else
-               {
                        printk(KERN_NOTICE MSG_PREFIX
                               "using %s partition definition\n", part_type);
-                       add_mtd_partitions(mymtd, mtd_parts, mtd_parts_nb);
-               }
+               /* Register the whole device first. */
+               mtd_device_register(mymtd, NULL, 0);
+               mtd_device_register(mymtd, mtd_parts, mtd_parts_nb);
                return 0;
        }
 
@@ -127,7 +117,7 @@ static int __init init_edb7312nor(void)
 static void __exit cleanup_edb7312nor(void)
 {
        if (mymtd) {
-               del_mtd_device(mymtd);
+               mtd_device_unregister(mymtd);
                map_destroy(mymtd);
        }
        if (edb7312nor_map.virt) {
index 4feb7507ab7c9a4906f66a735a176668e665656a..08322b1c3e8149220de252005ed477e624f60e5d 100644 (file)
@@ -128,7 +128,7 @@ static void esb2rom_cleanup(struct esb2rom_window *window)
        list_for_each_entry_safe(map, scratch, &window->maps, list) {
                if (map->rsrc.parent)
                        release_resource(&map->rsrc);
-               del_mtd_device(map->mtd);
+               mtd_device_unregister(map->mtd);
                map_destroy(map->mtd);
                list_del(&map->list);
                kfree(map);
@@ -352,7 +352,7 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev,
 
                /* Now that the mtd devices is complete claim and export it */
                map->mtd->owner = THIS_MODULE;
-               if (add_mtd_device(map->mtd)) {
+               if (mtd_device_register(map->mtd, NULL, 0)) {
                        map_destroy(map->mtd);
                        map->mtd = NULL;
                        goto out;
index 1e43124d498bc1cd2a685ad099db3713f136394f..956e2e4f30ea687b666fd4e41dd8225142c8d144 100644 (file)
@@ -243,8 +243,9 @@ static int __init init_fortunet(void)
                                        &map_regions[ix].map_info);
                        }
                        map_regions[ix].mymtd->owner = THIS_MODULE;
-                       add_mtd_partitions(map_regions[ix].mymtd,
-                               map_regions[ix].parts,map_regions_parts[ix]);
+                       mtd_device_register(map_regions[ix].mymtd,
+                                           map_regions[ix].parts,
+                                           map_regions_parts[ix]);
                }
        }
        if(iy)
@@ -261,7 +262,7 @@ static void __exit cleanup_fortunet(void)
                {
                        if( map_regions[ix].mymtd )
                        {
-                               del_mtd_partitions( map_regions[ix].mymtd );
+                               mtd_device_unregister(map_regions[ix].mymtd);
                                map_destroy( map_regions[ix].mymtd );
                        }
                        iounmap((void *)map_regions[ix].map_info.virt);
index af5707a80205c34985b2cba5cf2ceffce91cca76..7568c5f8b8ae648cb88754e94b34e03ec19c2d65 100644 (file)
@@ -155,9 +155,7 @@ static void gf_copy_to(struct map_info *map, unsigned long to, const void *from,
        memcpy_toio(map->virt + (to % state->win_size), from, len);
 }
 
-#ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
-#endif
 
 /**
  * gpio_flash_probe() - setup a mapping for a GPIO assisted flash
@@ -189,7 +187,7 @@ static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
  */
 static int __devinit gpio_flash_probe(struct platform_device *pdev)
 {
-       int ret;
+       int nr_parts;
        size_t i, arr_size;
        struct physmap_flash_data *pdata;
        struct resource *memory;
@@ -254,24 +252,21 @@ static int __devinit gpio_flash_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-#ifdef CONFIG_MTD_PARTITIONS
-       ret = parse_mtd_partitions(state->mtd, part_probe_types, &pdata->parts, 0);
-       if (ret > 0) {
+       nr_parts = parse_mtd_partitions(state->mtd, part_probe_types,
+                                       &pdata->parts, 0);
+       if (nr_parts > 0) {
                pr_devinit(KERN_NOTICE PFX "Using commandline partition definition\n");
-               add_mtd_partitions(state->mtd, pdata->parts, ret);
                kfree(pdata->parts);
-
        } else if (pdata->nr_parts) {
                pr_devinit(KERN_NOTICE PFX "Using board partition definition\n");
-               add_mtd_partitions(state->mtd, pdata->parts, pdata->nr_parts);
-
-       } else
-#endif
-       {
+               nr_parts = pdata->nr_parts;
+       } else {
                pr_devinit(KERN_NOTICE PFX "no partition info available, registering whole flash at once\n");
-               add_mtd_device(state->mtd);
+               nr_parts = 0;
        }
 
+       mtd_device_register(state->mtd, pdata->parts, nr_parts);
+
        return 0;
 }
 
@@ -282,9 +277,7 @@ static int __devexit gpio_flash_remove(struct platform_device *pdev)
        do {
                gpio_free(state->gpio_addrs[i]);
        } while (++i < state->gpio_count);
-#ifdef CONFIG_MTD_PARTITIONS
-       del_mtd_partitions(state->mtd);
-#endif
+       mtd_device_unregister(state->mtd);
        map_destroy(state->mtd);
        kfree(state);
        return 0;
index 72c724fa8c276a3c6e6698e7d31eb4f60f9cc3bb..7f035860a36bd43b8683945804fee50690f32351 100644 (file)
@@ -92,18 +92,16 @@ static int __init h720x_mtd_init(void)
        if (mymtd) {
                mymtd->owner = THIS_MODULE;
 
-#ifdef CONFIG_MTD_PARTITIONS
                nr_mtd_parts = parse_mtd_partitions(mymtd, probes, &mtd_parts, 0);
                if (nr_mtd_parts > 0)
                        part_type = "command line";
-#endif
                if (nr_mtd_parts <= 0) {
                        mtd_parts = h720x_partitions;
                        nr_mtd_parts = NUM_PARTITIONS;
                        part_type = "builtin";
                }
                printk(KERN_INFO "Using %s partition table\n", part_type);
-               add_mtd_partitions(mymtd, mtd_parts, nr_mtd_parts);
+               mtd_device_register(mymtd, mtd_parts, nr_mtd_parts);
                return 0;
        }
 
@@ -118,7 +116,7 @@ static void __exit h720x_mtd_cleanup(void)
 {
 
        if (mymtd) {
-               del_mtd_partitions(mymtd);
+               mtd_device_unregister(mymtd);
                map_destroy(mymtd);
        }
 
index 1337a4191a0cc3a8086049c308d14abab25622a3..6689dcb3124d5d30cca8c1c2554fc4b40c8c485e 100644 (file)
@@ -67,7 +67,7 @@ static void ichxrom_cleanup(struct ichxrom_window *window)
        list_for_each_entry_safe(map, scratch, &window->maps, list) {
                if (map->rsrc.parent)
                        release_resource(&map->rsrc);
-               del_mtd_device(map->mtd);
+               mtd_device_unregister(map->mtd);
                map_destroy(map->mtd);
                list_del(&map->list);
                kfree(map);
@@ -287,7 +287,7 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
 
                /* Now that the mtd devices is complete claim and export it */
                map->mtd->owner = THIS_MODULE;
-               if (add_mtd_device(map->mtd)) {
+               if (mtd_device_register(map->mtd, NULL, 0)) {
                        map_destroy(map->mtd);
                        map->mtd = NULL;
                        goto out;
index 998a27da97f315bf77f91e670fef6fd5905f68d3..404a50cbafa0596ef7ea8d2e0d760607d90bf3df 100644 (file)
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
-
-#ifdef CONFIG_MTD_PARTITIONS
 #include <linux/mtd/partitions.h>
-#endif
 
 #define WINDOW_ADDR0 0x00000000      /* physical properties of flash */
 #define WINDOW_SIZE0 0x00800000
@@ -49,8 +46,6 @@ static struct map_info impa7_map[NUM_FLASHBANKS] = {
        },
 };
 
-#ifdef CONFIG_MTD_PARTITIONS
-
 /*
  * MTD partitioning stuff
  */
@@ -66,8 +61,6 @@ static struct mtd_partition static_partitions[] =
 static int mtd_parts_nb[NUM_FLASHBANKS];
 static struct mtd_partition *mtd_parts[NUM_FLASHBANKS];
 
-#endif
-
 static const char *probes[] = { "cmdlinepart", NULL };
 
 static int __init init_impa7(void)
@@ -104,7 +97,6 @@ static int __init init_impa7(void)
                if (impa7_mtd[i]) {
                        impa7_mtd[i]->owner = THIS_MODULE;
                        devicesfound++;
-#ifdef CONFIG_MTD_PARTITIONS
                        mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i],
                                                               probes,
                                                               &mtd_parts[i],
@@ -120,12 +112,8 @@ static int __init init_impa7(void)
                        printk(KERN_NOTICE MSG_PREFIX
                               "using %s partition definition\n",
                               part_type);
-                       add_mtd_partitions(impa7_mtd[i],
-                                          mtd_parts[i], mtd_parts_nb[i]);
-#else
-                       add_mtd_device(impa7_mtd[i]);
-
-#endif
+                       mtd_device_register(impa7_mtd[i],
+                                           mtd_parts[i], mtd_parts_nb[i]);
                }
                else
                        iounmap((void *)impa7_map[i].virt);
@@ -138,11 +126,7 @@ static void __exit cleanup_impa7(void)
        int i;
        for (i=0; i<NUM_FLASHBANKS; i++) {
                if (impa7_mtd[i]) {
-#ifdef CONFIG_MTD_PARTITIONS
-                       del_mtd_partitions(impa7_mtd[i]);
-#else
-                       del_mtd_device(impa7_mtd[i]);
-#endif
+                       mtd_device_unregister(impa7_mtd[i]);
                        map_destroy(impa7_mtd[i]);
                        iounmap((void *)impa7_map[i].virt);
                        impa7_map[i].virt = 0;
index fc1998512eb407bd26e9cf235cbf8a2f92ecfa26..d2f47be8754b211392c0841fd32685396878481a 100644 (file)
@@ -66,33 +66,18 @@ struct vr_nor_mtd {
 
 static void __devexit vr_nor_destroy_partitions(struct vr_nor_mtd *p)
 {
-       if (p->nr_parts > 0) {
-#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
-               del_mtd_partitions(p->info);
-#endif
-       } else
-               del_mtd_device(p->info);
+       mtd_device_unregister(p->info);
 }
 
 static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p)
 {
-       int err = 0;
-#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
        struct mtd_partition *parts;
        static const char *part_probes[] = { "cmdlinepart", NULL };
-#endif
 
        /* register the flash bank */
-#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
        /* partition the flash bank */
        p->nr_parts = parse_mtd_partitions(p->info, part_probes, &parts, 0);
-       if (p->nr_parts > 0)
-               err = add_mtd_partitions(p->info, parts, p->nr_parts);
-#endif
-       if (p->nr_parts <= 0)
-               err = add_mtd_device(p->info);
-
-       return err;
+       return mtd_device_register(p->info, parts, p->nr_parts);
 }
 
 static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)
index 9639d83a9d6c9303b123ba39a399f3c9594154c5..c00b9175ba9e7c3a747a0ecba02c17486419d106 100644 (file)
@@ -119,7 +119,7 @@ static int ixp2000_flash_remove(struct platform_device *dev)
                return 0;
 
        if (info->mtd) {
-               del_mtd_partitions(info->mtd);
+               mtd_device_unregister(info->mtd);
                map_destroy(info->mtd);
        }
        if (info->map.map_priv_1)
@@ -230,7 +230,7 @@ static int ixp2000_flash_probe(struct platform_device *dev)
 
        err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0);
        if (err > 0) {
-               err = add_mtd_partitions(info->mtd, info->partitions, err);
+               err = mtd_device_register(info->mtd, info->partitions, err);
                if(err)
                        dev_err(&dev->dev, "Could not parse partitions\n");
        }
index 1f9fde0dad35c95b95cbe4a66b30a4ec0c33e4ad..155b21942f4777a1aea10a8a22b04778ca82ec33 100644 (file)
@@ -162,7 +162,7 @@ static int ixp4xx_flash_remove(struct platform_device *dev)
                return 0;
 
        if (info->mtd) {
-               del_mtd_partitions(info->mtd);
+               mtd_device_unregister(info->mtd);
                map_destroy(info->mtd);
        }
        if (info->map.virt)
@@ -252,10 +252,8 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
        /* Use the fast version */
        info->map.write = ixp4xx_write16;
 
-#ifdef CONFIG_MTD_PARTITIONS
        nr_parts = parse_mtd_partitions(info->mtd, probes, &info->partitions,
                                        dev->resource->start);
-#endif
        if (nr_parts > 0) {
                part_type = "dynamic";
        } else {
@@ -263,18 +261,16 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
                nr_parts = plat->nr_parts;
                part_type = "static";
        }
-       if (nr_parts == 0) {
+       if (nr_parts == 0)
                printk(KERN_NOTICE "IXP4xx flash: no partition info "
                        "available, registering whole flash\n");
-               err = add_mtd_device(info->mtd);
-       } else {
+       else
                printk(KERN_NOTICE "IXP4xx flash: using %s partition "
                        "definition\n", part_type);
-               err = add_mtd_partitions(info->mtd, info->partitions, nr_parts);
 
-               if(err)
-                       printk(KERN_ERR "Could not parse partitions\n");
-       }
+       err = mtd_device_register(info->mtd, info->partitions, nr_parts);
+       if (err)
+               printk(KERN_ERR "Could not parse partitions\n");
 
        if (err)
                goto Error;
index 9e054503c4cf2920e23c7fded7d2bd39741c4166..dd0360ba2412b646e27dd05fd11fbe29c37e211a 100644 (file)
@@ -138,7 +138,7 @@ static int __init init_l440gx(void)
        if (mymtd) {
                mymtd->owner = THIS_MODULE;
 
-               add_mtd_device(mymtd);
+               mtd_device_register(mymtd, NULL, 0);
                return 0;
        }
 
@@ -148,7 +148,7 @@ static int __init init_l440gx(void)
 
 static void __exit cleanup_l440gx(void)
 {
-       del_mtd_device(mymtd);
+       mtd_device_unregister(mymtd);
        map_destroy(mymtd);
 
        iounmap(l440gx_map.virt);
index ee25480853346acaf180c8fe3e412e7e7b73b8d3..5936c466e901369be6b0d7a9a13c4330fe78fcdc 100644 (file)
@@ -112,18 +112,9 @@ static int latch_addr_flash_remove(struct platform_device *dev)
        latch_addr_data = dev->dev.platform_data;
 
        if (info->mtd != NULL) {
-               if (mtd_has_partitions()) {
-                       if (info->nr_parts) {
-                               del_mtd_partitions(info->mtd);
-                               kfree(info->parts);
-                       } else if (latch_addr_data->nr_parts) {
-                               del_mtd_partitions(info->mtd);
-                       } else {
-                               del_mtd_device(info->mtd);
-                       }
-               } else {
-                       del_mtd_device(info->mtd);
-               }
+               if (info->nr_parts)
+                       kfree(info->parts);
+               mtd_device_unregister(info->mtd);
                map_destroy(info->mtd);
        }
 
@@ -215,23 +206,21 @@ static int __devinit latch_addr_flash_probe(struct platform_device *dev)
        }
        info->mtd->owner = THIS_MODULE;
 
-       if (mtd_has_partitions()) {
-
-               err = parse_mtd_partitions(info->mtd,
-                                          (const char **)part_probe_types,
-                                          &info->parts, 0);
-               if (err > 0) {
-                       add_mtd_partitions(info->mtd, info->parts, err);
-                       return 0;
-               }
-               if (latch_addr_data->nr_parts) {
-                       pr_notice("Using latch-addr-flash partition information\n");
-                       add_mtd_partitions(info->mtd, latch_addr_data->parts,
-                                       latch_addr_data->nr_parts);
-                       return 0;
-               }
+       err = parse_mtd_partitions(info->mtd, (const char **)part_probe_types,
+                                  &info->parts, 0);
+       if (err > 0) {
+               mtd_device_register(info->mtd, info->parts, err);
+               return 0;
+       }
+       if (latch_addr_data->nr_parts) {
+               pr_notice("Using latch-addr-flash partition information\n");
+               mtd_device_register(info->mtd,
+                                   latch_addr_data->parts,
+                                   latch_addr_data->nr_parts);
+               return 0;
        }
-       add_mtd_device(info->mtd);
+
+       mtd_device_register(info->mtd, NULL, 0);
        return 0;
 
 iounmap:
index 0eb5a7c853806147092f990162faa2926a60344f..93fa56c33003bf162eeb29b1a351cbe320c7c2fa 100644 (file)
@@ -69,8 +69,8 @@ static int __init init_mbx(void)
        mymtd = do_map_probe("jedec_probe", &mbx_map);
        if (mymtd) {
                mymtd->owner = THIS_MODULE;
-               add_mtd_device(mymtd);
-                add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
+               mtd_device_register(mymtd, NULL, 0);
+               mtd_device_register(mymtd, partition_info, NUM_PARTITIONS);
                return 0;
        }
 
@@ -81,7 +81,7 @@ static int __init init_mbx(void)
 static void __exit cleanup_mbx(void)
 {
        if (mymtd) {
-               del_mtd_device(mymtd);
+               mtd_device_unregister(mymtd);
                map_destroy(mymtd);
        }
        if (mbx_map.virt) {
index c0cb319b2b70e26f38f6c9133263098ff245bad0..81dc2598bc0ac9085cadf7b332543e7752be5ade 100644 (file)
@@ -116,14 +116,14 @@ static int __init init_netsc520(void)
        }
 
        mymtd->owner = THIS_MODULE;
-       add_mtd_partitions( mymtd, partition_info, NUM_PARTITIONS );
+       mtd_device_register(mymtd, partition_info, NUM_PARTITIONS);
        return 0;
 }
 
 static void __exit cleanup_netsc520(void)
 {
        if (mymtd) {
-               del_mtd_partitions(mymtd);
+               mtd_device_unregister(mymtd);
                map_destroy(mymtd);
        }
        if (netsc520_map.virt) {
index a97133eb9d70ec8356e991d3a63fb888000d4c31..eadcfffc4f9cae70018c695df0bfae713eae5250 100644 (file)
@@ -383,13 +383,13 @@ static int __init nettel_init(void)
                /* No BIOS regions when AMD boot */
                num_intel_partitions -= 2;
        }
-       rc = add_mtd_partitions(intel_mtd, nettel_intel_partitions,
-               num_intel_partitions);
+       rc = mtd_device_register(intel_mtd, nettel_intel_partitions,
+                                num_intel_partitions);
 #endif
 
        if (amd_mtd) {
-               rc = add_mtd_partitions(amd_mtd, nettel_amd_partitions,
-                       num_amd_partitions);
+               rc = mtd_device_register(amd_mtd, nettel_amd_partitions,
+                                        num_amd_partitions);
        }
 
 #ifdef CONFIG_MTD_CFI_INTELEXT
@@ -419,7 +419,7 @@ static void __exit nettel_cleanup(void)
        unregister_reboot_notifier(&nettel_notifier_block);
 #endif
        if (amd_mtd) {
-               del_mtd_partitions(amd_mtd);
+               mtd_device_unregister(amd_mtd);
                map_destroy(amd_mtd);
        }
        if (nettel_mmcrp) {
@@ -432,7 +432,7 @@ static void __exit nettel_cleanup(void)
        }
 #ifdef CONFIG_MTD_CFI_INTELEXT
        if (intel_mtd) {
-               del_mtd_partitions(intel_mtd);
+               mtd_device_unregister(intel_mtd);
                map_destroy(intel_mtd);
        }
        if (nettel_intel_map.virt) {
index 23fe1786770f140c686215cc05925a5d4f6c2d8d..807ac2a2e686e0b3ecd5e12df39eaa62847c20c4 100644 (file)
@@ -175,7 +175,7 @@ void cleanup_oct5066(void)
        int i;
        for (i=0; i<2; i++) {
                if (oct5066_mtd[i]) {
-                       del_mtd_device(oct5066_mtd[i]);
+                       mtd_device_unregister(oct5066_mtd[i]);
                        map_destroy(oct5066_mtd[i]);
                }
        }
@@ -220,7 +220,7 @@ static int __init init_oct5066(void)
                        oct5066_mtd[i] = do_map_probe("map_rom", &oct5066_map[i]);
                if (oct5066_mtd[i]) {
                        oct5066_mtd[i]->owner = THIS_MODULE;
-                       add_mtd_device(oct5066_mtd[i]);
+                       mtd_device_register(oct5066_mtd[i], NULL, 0);
                }
        }
 
index 48f4cf5cb9d1d8f18a31c9f80af75b703d933b21..1d005a3e9b41603856c40a60fee6de972771634f 100644 (file)
@@ -313,7 +313,7 @@ mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
                goto release;
 
        mtd->owner = THIS_MODULE;
-       add_mtd_device(mtd);
+       mtd_device_register(mtd, NULL, 0);
 
        pci_set_drvdata(dev, mtd);
 
@@ -336,7 +336,7 @@ mtd_pci_remove(struct pci_dev *dev)
        struct mtd_info *mtd = pci_get_drvdata(dev);
        struct map_pci_info *map = mtd->priv;
 
-       del_mtd_device(mtd);
+       mtd_device_unregister(mtd);
        map_destroy(mtd);
        map->exit(dev, map);
        kfree(map);
index 6799e75d74e0387c251200a7e266506a8c59704d..bbe168b65c26a392e09bc8bdb4783b2d5c7ab06f 100644 (file)
@@ -630,7 +630,7 @@ static int pcmciamtd_config(struct pcmcia_device *link)
                dev->pcmcia_map.copy_to = pcmcia_copy_to;
        }
 
-       if(add_mtd_device(mtd)) {
+       if (mtd_device_register(mtd, NULL, 0)) {
                map_destroy(mtd);
                dev->mtd_info = NULL;
                dev_err(&dev->p_dev->dev,
@@ -669,7 +669,7 @@ static void pcmciamtd_detach(struct pcmcia_device *link)
        DEBUG(3, "link=0x%p", link);
 
        if(dev->mtd_info) {
-               del_mtd_device(dev->mtd_info);
+               mtd_device_unregister(dev->mtd_info);
                dev_info(&dev->p_dev->dev, "mtd%d: Removing\n",
                         dev->mtd_info->index);
                map_destroy(dev->mtd_info);
@@ -694,7 +694,7 @@ static int pcmciamtd_probe(struct pcmcia_device *link)
        return pcmciamtd_config(link);
 }
 
-static struct pcmcia_device_id pcmciamtd_ids[] = {
+static const struct pcmcia_device_id pcmciamtd_ids[] = {
        PCMCIA_DEVICE_FUNC_ID(1),
        PCMCIA_DEVICE_PROD_ID123("IO DATA", "PCS-2M", "2MB SRAM", 0x547e66dc, 0x1fed36cd, 0x36eadd21),
        PCMCIA_DEVICE_PROD_ID12("IBM", "2MB SRAM", 0xb569a6e5, 0x36eadd21),
index 1a9b94f0ee54fb3fab12975cc6fcad08235b61fe..f64cee4a3bfbeba9674fea84c4465e645d925594 100644 (file)
@@ -27,10 +27,8 @@ struct physmap_flash_info {
        struct mtd_info         *mtd[MAX_RESOURCES];
        struct mtd_info         *cmtd;
        struct map_info         map[MAX_RESOURCES];
-#ifdef CONFIG_MTD_PARTITIONS
        int                     nr_parts;
        struct mtd_partition    *parts;
-#endif
 };
 
 static int physmap_flash_remove(struct platform_device *dev)
@@ -47,18 +45,9 @@ static int physmap_flash_remove(struct platform_device *dev)
        physmap_data = dev->dev.platform_data;
 
        if (info->cmtd) {
-#ifdef CONFIG_MTD_PARTITIONS
-               if (info->nr_parts || physmap_data->nr_parts) {
-                       del_mtd_partitions(info->cmtd);
-
-                       if (info->nr_parts)
-                               kfree(info->parts);
-               } else {
-                       del_mtd_device(info->cmtd);
-               }
-#else
-               del_mtd_device(info->cmtd);
-#endif
+               mtd_device_unregister(info->cmtd);
+               if (info->nr_parts)
+                       kfree(info->parts);
                if (info->cmtd != info->mtd[0])
                        mtd_concat_destroy(info->cmtd);
        }
@@ -92,10 +81,8 @@ static const char *rom_probe_types[] = {
                                        "qinfo_probe",
                                        "map_rom",
                                        NULL };
-#ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", "afs",
                                          NULL };
-#endif
 
 static int physmap_flash_probe(struct platform_device *dev)
 {
@@ -188,24 +175,23 @@ static int physmap_flash_probe(struct platform_device *dev)
        if (err)
                goto err_out;
 
-#ifdef CONFIG_MTD_PARTITIONS
        err = parse_mtd_partitions(info->cmtd, part_probe_types,
-                               &info->parts, 0);
+                                  &info->parts, 0);
        if (err > 0) {
-               add_mtd_partitions(info->cmtd, info->parts, err);
+               mtd_device_register(info->cmtd, info->parts, err);
                info->nr_parts = err;
                return 0;
        }
 
        if (physmap_data->nr_parts) {
                printk(KERN_NOTICE "Using physmap partition information\n");
-               add_mtd_partitions(info->cmtd, physmap_data->parts,
-                                  physmap_data->nr_parts);
+               mtd_device_register(info->cmtd, physmap_data->parts,
+                                   physmap_data->nr_parts);
                return 0;
        }
-#endif
 
-       add_mtd_device(info->cmtd);
+       mtd_device_register(info->cmtd, NULL, 0);
+
        return 0;
 
 err_out:
@@ -269,14 +255,12 @@ void physmap_configure(unsigned long addr, unsigned long size,
        physmap_flash_data.set_vpp = set_vpp;
 }
 
-#ifdef CONFIG_MTD_PARTITIONS
 void physmap_set_partitions(struct mtd_partition *parts, int num_parts)
 {
        physmap_flash_data.nr_parts = num_parts;
        physmap_flash_data.parts = parts;
 }
 #endif
-#endif
 
 static int __init physmap_init(void)
 {
index c1d33464aee8926e66afcccc23dbbbacdb718ba8..d251d1db129b3fd81391302b1add42b0052e869d 100644 (file)
@@ -34,16 +34,12 @@ struct of_flash_list {
 
 struct of_flash {
        struct mtd_info         *cmtd;
-#ifdef CONFIG_MTD_PARTITIONS
        struct mtd_partition    *parts;
-#endif
        int list_size; /* number of elements in of_flash_list */
        struct of_flash_list    list[0];
 };
 
-#ifdef CONFIG_MTD_PARTITIONS
 #define OF_FLASH_PARTS(info)   ((info)->parts)
-
 static int parse_obsolete_partitions(struct platform_device *dev,
                                     struct of_flash *info,
                                     struct device_node *dp)
@@ -89,10 +85,6 @@ static int parse_obsolete_partitions(struct platform_device *dev,
 
        return nr_parts;
 }
-#else /* MTD_PARTITIONS */
-#define        OF_FLASH_PARTS(info)            (0)
-#define parse_partitions(info, dev)    (0)
-#endif /* MTD_PARTITIONS */
 
 static int of_flash_remove(struct platform_device *dev)
 {
@@ -105,17 +97,14 @@ static int of_flash_remove(struct platform_device *dev)
        dev_set_drvdata(&dev->dev, NULL);
 
        if (info->cmtd != info->list[0].mtd) {
-               del_mtd_device(info->cmtd);
+               mtd_device_unregister(info->cmtd);
                mtd_concat_destroy(info->cmtd);
        }
 
        if (info->cmtd) {
-               if (OF_FLASH_PARTS(info)) {
-                       del_mtd_partitions(info->cmtd);
+               if (OF_FLASH_PARTS(info))
                        kfree(OF_FLASH_PARTS(info));
-               } else {
-                       del_mtd_device(info->cmtd);
-               }
+               mtd_device_unregister(info->cmtd);
        }
 
        for (i = 0; i < info->list_size; i++) {
@@ -172,7 +161,6 @@ static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,
        }
 }
 
-#ifdef CONFIG_MTD_PARTITIONS
 /* When partitions are set we look for a linux,part-probe property which
    specifies the list of partition probers to use. If none is given then the
    default is use. These take precedence over other device tree
@@ -212,14 +200,11 @@ static void __devinit of_free_probes(const char **probes)
        if (probes != part_probe_types_def)
                kfree(probes);
 }
-#endif
 
 static struct of_device_id of_flash_match[];
 static int __devinit of_flash_probe(struct platform_device *dev)
 {
-#ifdef CONFIG_MTD_PARTITIONS
        const char **part_probe_types;
-#endif
        const struct of_device_id *match;
        struct device_node *dp = dev->dev.of_node;
        struct resource res;
@@ -346,7 +331,6 @@ static int __devinit of_flash_probe(struct platform_device *dev)
        if (err)
                goto err_out;
 
-#ifdef CONFIG_MTD_PARTITIONS
        part_probe_types = of_get_probes(dp);
        err = parse_mtd_partitions(info->cmtd, part_probe_types,
                                   &info->parts, 0);
@@ -356,13 +340,11 @@ static int __devinit of_flash_probe(struct platform_device *dev)
        }
        of_free_probes(part_probe_types);
 
-#ifdef CONFIG_MTD_OF_PARTS
        if (err == 0) {
                err = of_mtd_parse_partitions(&dev->dev, dp, &info->parts);
                if (err < 0)
                        goto err_out;
        }
-#endif
 
        if (err == 0) {
                err = parse_obsolete_partitions(dev, info, dp);
@@ -370,11 +352,7 @@ static int __devinit of_flash_probe(struct platform_device *dev)
                        goto err_out;
        }
 
-       if (err > 0)
-               add_mtd_partitions(info->cmtd, info->parts, err);
-       else
-#endif
-               add_mtd_device(info->cmtd);
+       mtd_device_register(info->cmtd, info->parts, err);
 
        kfree(mtd_list);
 
index 76a76be5a7bd7fec98e698b0a83ab264633d5a3a..9ca1eccba4bc2e70b0d5e7ea6c3be5d014f6da5e 100644 (file)
@@ -94,14 +94,11 @@ static int platram_remove(struct platform_device *pdev)
                return 0;
 
        if (info->mtd) {
-#ifdef CONFIG_MTD_PARTITIONS
+               mtd_device_unregister(info->mtd);
                if (info->partitions) {
-                       del_mtd_partitions(info->mtd);
                        if (info->free_partitions)
                                kfree(info->partitions);
                }
-#endif
-               del_mtd_device(info->mtd);
                map_destroy(info->mtd);
        }
 
@@ -231,7 +228,6 @@ static int platram_probe(struct platform_device *pdev)
        /* check to see if there are any available partitions, or wether
         * to add this device whole */
 
-#ifdef CONFIG_MTD_PARTITIONS
        if (!pdata->nr_partitions) {
                /* try to probe using the supplied probe type */
                if (pdata->probes) {
@@ -239,24 +235,22 @@ static int platram_probe(struct platform_device *pdev)
                                           &info->partitions, 0);
                        info->free_partitions = 1;
                        if (err > 0)
-                               err = add_mtd_partitions(info->mtd,
+                               err = mtd_device_register(info->mtd,
                                        info->partitions, err);
                }
        }
        /* use the static mapping */
        else
-               err = add_mtd_partitions(info->mtd, pdata->partitions,
-                               pdata->nr_partitions);
-#endif /* CONFIG_MTD_PARTITIONS */
-
-       if (add_mtd_device(info->mtd)) {
-               dev_err(&pdev->dev, "add_mtd_device() failed\n");
-               err = -ENOMEM;
-       }
-
+               err = mtd_device_register(info->mtd, pdata->partitions,
+                                         pdata->nr_partitions);
        if (!err)
                dev_info(&pdev->dev, "registered mtd device\n");
 
+       /* add the whole device. */
+       err = mtd_device_register(info->mtd, NULL, 0);
+       if (err)
+               dev_err(&pdev->dev, "failed to register the entire device\n");
+
        return err;
 
  exit_free:
index 64aea6acd48e5f173e6bd5d628e1d97a3cf1e7d4..744ca5cacc9b2e8b6f10189dc169f29426cad9e9 100644 (file)
@@ -173,7 +173,7 @@ static int __init init_msp_flash(void)
                msp_flash[i] = do_map_probe("cfi_probe", &msp_maps[i]);
                if (msp_flash[i]) {
                        msp_flash[i]->owner = THIS_MODULE;
-                       add_mtd_partitions(msp_flash[i], msp_parts[i], pcnt);
+                       mtd_device_register(msp_flash[i], msp_parts[i], pcnt);
                } else {
                        printk(KERN_ERR "map probe failed for flash\n");
                        ret = -ENXIO;
@@ -188,7 +188,7 @@ static int __init init_msp_flash(void)
 
 cleanup_loop:
        while (i--) {
-               del_mtd_partitions(msp_flash[i]);
+               mtd_device_unregister(msp_flash[i]);
                map_destroy(msp_flash[i]);
                kfree(msp_maps[i].name);
                iounmap(msp_maps[i].virt);
@@ -207,7 +207,7 @@ static void __exit cleanup_msp_flash(void)
        int i;
 
        for (i = 0; i < fcnt; i++) {
-               del_mtd_partitions(msp_flash[i]);
+               mtd_device_unregister(msp_flash[i]);
                map_destroy(msp_flash[i]);
                iounmap((void *)msp_maps[i].virt);
 
index d8ae634d347ebc4262704188adb1dea943c909e6..f59d62f74d44a39ed9ccea62358ed64e57361f56 100644 (file)
@@ -104,23 +104,18 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev)
        }
        info->mtd->owner = THIS_MODULE;
 
-#ifdef CONFIG_MTD_PARTITIONS
        ret = parse_mtd_partitions(info->mtd, probes, &parts, 0);
 
        if (ret > 0) {
                info->nr_parts = ret;
                info->parts = parts;
        }
-#endif
 
-       if (info->nr_parts) {
-               add_mtd_partitions(info->mtd, info->parts,
-                                  info->nr_parts);
-       } else {
+       if (!info->nr_parts)
                printk("Registering %s as whole device\n",
                       info->map.name);
-               add_mtd_device(info->mtd);
-       }
+
+       mtd_device_register(info->mtd, info->parts, info->nr_parts);
 
        platform_set_drvdata(pdev, info);
        return 0;
@@ -132,12 +127,7 @@ static int __devexit pxa2xx_flash_remove(struct platform_device *dev)
 
        platform_set_drvdata(dev, NULL);
 
-#ifdef CONFIG_MTD_PARTITIONS
-       if (info->nr_parts)
-               del_mtd_partitions(info->mtd);
-       else
-#endif
-               del_mtd_device(info->mtd);
+       mtd_device_unregister(info->mtd);
 
        map_destroy(info->mtd);
        iounmap(info->map.virt);
index 83ed64512c5e6f076192abf097cb9aacde1c2ab6..761fb459d2c74179105fb9ded586681c66ae6aae 100644 (file)
 struct rbtx4939_flash_info {
        struct mtd_info *mtd;
        struct map_info map;
-#ifdef CONFIG_MTD_PARTITIONS
        int nr_parts;
        struct mtd_partition *parts;
-#endif
 };
 
 static int rbtx4939_flash_remove(struct platform_device *dev)
@@ -41,28 +39,18 @@ static int rbtx4939_flash_remove(struct platform_device *dev)
        platform_set_drvdata(dev, NULL);
 
        if (info->mtd) {
-#ifdef CONFIG_MTD_PARTITIONS
                struct rbtx4939_flash_data *pdata = dev->dev.platform_data;
 
-               if (info->nr_parts) {
-                       del_mtd_partitions(info->mtd);
+               if (info->nr_parts)
                        kfree(info->parts);
-               } else if (pdata->nr_parts)
-                       del_mtd_partitions(info->mtd);
-               else
-                       del_mtd_device(info->mtd);
-#else
-               del_mtd_device(info->mtd);
-#endif
+               mtd_device_unregister(info->mtd);
                map_destroy(info->mtd);
        }
        return 0;
 }
 
 static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
-#ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probe_types[] = { "cmdlinepart", NULL };
-#endif
 
 static int rbtx4939_flash_probe(struct platform_device *dev)
 {
@@ -120,23 +108,21 @@ static int rbtx4939_flash_probe(struct platform_device *dev)
        if (err)
                goto err_out;
 
-#ifdef CONFIG_MTD_PARTITIONS
        err = parse_mtd_partitions(info->mtd, part_probe_types,
                                &info->parts, 0);
        if (err > 0) {
-               add_mtd_partitions(info->mtd, info->parts, err);
+               mtd_device_register(info->mtd, info->parts, err);
                info->nr_parts = err;
                return 0;
        }
 
        if (pdata->nr_parts) {
                pr_notice("Using rbtx4939 partition information\n");
-               add_mtd_partitions(info->mtd, pdata->parts, pdata->nr_parts);
+               mtd_device_register(info->mtd, pdata->parts, pdata->nr_parts);
                return 0;
        }
-#endif
 
-       add_mtd_device(info->mtd);
+       mtd_device_register(info->mtd, NULL, 0);
        return 0;
 
 err_out:
index 3e3ef53d4fd4cba637d9d378daca278c021809f4..ed88225bf66707aba6412793f3419b055aff19b3 100644 (file)
@@ -36,7 +36,7 @@ static int __init init_rpxlite(void)
        mymtd = do_map_probe("cfi_probe", &rpxlite_map);
        if (mymtd) {
                mymtd->owner = THIS_MODULE;
-               add_mtd_device(mymtd);
+               mtd_device_register(mymtd, NULL, 0);
                return 0;
        }
 
@@ -47,7 +47,7 @@ static int __init init_rpxlite(void)
 static void __exit cleanup_rpxlite(void)
 {
        if (mymtd) {
-               del_mtd_device(mymtd);
+               mtd_device_unregister(mymtd);
                map_destroy(mymtd);
        }
        if (rpxlite_map.virt) {
index da875908ea8e04e20e08edb2785ecac37ef96a31..a9b5e0e5c4c559b059842468d5c15a70f0bfc7c3 100644 (file)
@@ -226,12 +226,7 @@ static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *pla
        int i;
 
        if (info->mtd) {
-               if (info->nr_parts == 0)
-                       del_mtd_device(info->mtd);
-#ifdef CONFIG_MTD_PARTITIONS
-               else
-                       del_mtd_partitions(info->mtd);
-#endif
+               mtd_device_unregister(info->mtd);
                if (info->mtd != info->subdev[0].mtd)
                        mtd_concat_destroy(info->mtd);
        }
@@ -363,28 +358,24 @@ static int __devinit sa1100_mtd_probe(struct platform_device *pdev)
        /*
         * Partition selection stuff.
         */
-#ifdef CONFIG_MTD_PARTITIONS
        nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
        if (nr_parts > 0) {
                info->parts = parts;
                part_type = "dynamic";
-       } else
-#endif
-       {
+       } else {
                parts = plat->parts;
                nr_parts = plat->nr_parts;
                part_type = "static";
        }
 
-       if (nr_parts == 0) {
+       if (nr_parts == 0)
                printk(KERN_NOTICE "SA1100 flash: no partition info "
                        "available, registering whole flash\n");
-               add_mtd_device(info->mtd);
-       } else {
+       else
                printk(KERN_NOTICE "SA1100 flash: using %s partition "
                        "definition\n", part_type);
-               add_mtd_partitions(info->mtd, parts, nr_parts);
-       }
+
+       mtd_device_register(info->mtd, parts, nr_parts);
 
        info->nr_parts = nr_parts;
 
index 04b2781fc6278ba852b47f4e7208f3dc228e6209..556a2dfe94c586e03b363f5c2056992346df72b1 100644 (file)
@@ -182,7 +182,7 @@ static struct mtd_info *all_mtd;
 static void cleanup_sbc_gxx(void)
 {
        if( all_mtd ) {
-               del_mtd_partitions( all_mtd );
+               mtd_device_unregister(all_mtd);
                map_destroy( all_mtd );
        }
 
@@ -223,7 +223,7 @@ static int __init init_sbc_gxx(void)
        all_mtd->owner = THIS_MODULE;
 
        /* Create MTD devices for each partition. */
-       add_mtd_partitions(all_mtd, partition_info, NUM_PARTITIONS );
+       mtd_device_register(all_mtd, partition_info, NUM_PARTITIONS);
 
        return 0;
 }
index 4d8aaaf4bb761a3325a059e927bab9769ec4a0c4..8fead8e46bce6bad5a72f74c80bda4c592a15cf0 100644 (file)
@@ -266,10 +266,10 @@ static int __init init_sc520cdp(void)
                /* Combine the two flash banks into a single MTD device & register it: */
                merged_mtd = mtd_concat_create(mymtd, 2, "SC520CDP Flash Banks #0 and #1");
                if(merged_mtd)
-                       add_mtd_device(merged_mtd);
+                       mtd_device_register(merged_mtd, NULL, 0);
        }
        if(devices_found == 3) /* register the third (DIL-Flash) device */
-               add_mtd_device(mymtd[2]);
+               mtd_device_register(mymtd[2], NULL, 0);
        return(devices_found ? 0 : -ENXIO);
 }
 
@@ -278,11 +278,11 @@ static void __exit cleanup_sc520cdp(void)
        int i;
 
        if (merged_mtd) {
-               del_mtd_device(merged_mtd);
+               mtd_device_unregister(merged_mtd);
                mtd_concat_destroy(merged_mtd);
        }
        if (mymtd[2])
-               del_mtd_device(mymtd[2]);
+               mtd_device_unregister(mymtd[2]);
 
        for (i = 0; i < NUM_FLASH_BANKS; i++) {
                if (mymtd[i])
index 7e329f09a548f06bb83c36c1281d65db2278ef7c..d88c8426bb0fe7a4032fbdd8d3cee879542c59d2 100644 (file)
@@ -180,7 +180,7 @@ scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent)
 
        scb2_mtd->owner = THIS_MODULE;
        if (scb2_fixup_mtd(scb2_mtd) < 0) {
-               del_mtd_device(scb2_mtd);
+               mtd_device_unregister(scb2_mtd);
                map_destroy(scb2_mtd);
                iounmap(scb2_ioaddr);
                if (!region_fail)
@@ -192,7 +192,7 @@ scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent)
               (unsigned long long)scb2_mtd->size,
               (unsigned long long)(SCB2_WINDOW - scb2_mtd->size));
 
-       add_mtd_device(scb2_mtd);
+       mtd_device_register(scb2_mtd, NULL, 0);
 
        return 0;
 }
@@ -207,7 +207,7 @@ scb2_flash_remove(struct pci_dev *dev)
        if (scb2_mtd->lock)
                scb2_mtd->lock(scb2_mtd, 0, scb2_mtd->size);
 
-       del_mtd_device(scb2_mtd);
+       mtd_device_unregister(scb2_mtd);
        map_destroy(scb2_mtd);
 
        iounmap(scb2_ioaddr);
index 027e628a4f1d912791668f21d2e1787e6a4523f5..f1c1f737d0d7ebdece52d97ac6590bacd7edb1b8 100644 (file)
@@ -44,7 +44,6 @@ static struct resource docmem = {
 
 static struct mtd_info *mymtd;
 
-#ifdef CONFIG_MTD_PARTITIONS
 static struct mtd_partition partition_info[] = {
        {
                .name   = "DOCCS Boot kernel",
@@ -68,8 +67,6 @@ static struct mtd_partition partition_info[] = {
        },
 };
 #define NUM_PARTITIONS ARRAY_SIZE(partition_info)
-#endif
-
 
 static struct map_info scx200_docflash_map = {
        .name      = "NatSemi SCx200 DOCCS Flash",
@@ -198,24 +195,17 @@ static int __init init_scx200_docflash(void)
 
        mymtd->owner = THIS_MODULE;
 
-#ifdef CONFIG_MTD_PARTITIONS
        partition_info[3].offset = mymtd->size-partition_info[3].size;
        partition_info[2].size = partition_info[3].offset-partition_info[2].offset;
-       add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
-#else
-       add_mtd_device(mymtd);
-#endif
+       mtd_device_register(mymtd, partition_info, NUM_PARTITIONS);
+
        return 0;
 }
 
 static void __exit cleanup_scx200_docflash(void)
 {
        if (mymtd) {
-#ifdef CONFIG_MTD_PARTITIONS
-               del_mtd_partitions(mymtd);
-#else
-               del_mtd_device(mymtd);
-#endif
+               mtd_device_unregister(mymtd);
                map_destroy(mymtd);
        }
        if (scx200_docflash_map.virt) {
index 0eb41d9c67867fb90280ba0570408e1536b4760e..cbf6bade9354681164e707b2e43924b21a833578 100644 (file)
@@ -89,7 +89,7 @@ static int __init init_soleng_maps(void)
        eprom_mtd = do_map_probe("map_rom", &soleng_eprom_map);
        if (eprom_mtd) {
                eprom_mtd->owner = THIS_MODULE;
-               add_mtd_device(eprom_mtd);
+               mtd_device_register(eprom_mtd, NULL, 0);
        }
 
        nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0);
@@ -104,9 +104,9 @@ static int __init init_soleng_maps(void)
 #endif /* CONFIG_MTD_SUPERH_RESERVE */
 
        if (nr_parts > 0)
-               add_mtd_partitions(flash_mtd, parsed_parts, nr_parts);
+               mtd_device_register(flash_mtd, parsed_parts, nr_parts);
        else
-               add_mtd_device(flash_mtd);
+               mtd_device_register(flash_mtd, NULL, 0);
 
        return 0;
 }
@@ -114,14 +114,14 @@ static int __init init_soleng_maps(void)
 static void __exit cleanup_soleng_maps(void)
 {
        if (eprom_mtd) {
-               del_mtd_device(eprom_mtd);
+               mtd_device_unregister(eprom_mtd);
                map_destroy(eprom_mtd);
        }
 
        if (parsed_parts)
-               del_mtd_partitions(flash_mtd);
+               mtd_device_unregister(flash_mtd);
        else
-               del_mtd_device(flash_mtd);
+               mtd_device_unregister(flash_mtd);
        map_destroy(flash_mtd);
 }
 
index 3f1cb328a574dd6e7e01cf47a1c12509f3fc2630..2d66234f57cb471e3c9700b5fc35ad1e1c9b6e5f 100644 (file)
@@ -101,7 +101,7 @@ int uflash_devinit(struct platform_device *op, struct device_node *dp)
 
        up->mtd->owner = THIS_MODULE;
 
-       add_mtd_device(up->mtd);
+       mtd_device_register(up->mtd, NULL, 0);
 
        dev_set_drvdata(&op->dev, up);
 
@@ -126,7 +126,7 @@ static int __devexit uflash_remove(struct platform_device *op)
        struct uflash_dev *up = dev_get_drvdata(&op->dev);
 
        if (up->mtd) {
-               del_mtd_device(up->mtd);
+               mtd_device_unregister(up->mtd);
                map_destroy(up->mtd);
        }
        if (up->map.virt) {
index 0718dfb3ee6476d64634e8cfd89472936f80e1a8..d78587990e7e9e3a57b3f1230dd9f8b23a42cc40 100644 (file)
@@ -62,7 +62,6 @@ static void __iomem *start_scan_addr;
  * "struct map_desc *_io_desc" for the corresponding machine.
  */
 
-#ifdef CONFIG_MTD_PARTITIONS
 /* Currently, TQM8xxL has up to 8MiB flash */
 static unsigned long tqm8xxl_max_flash_size = 0x00800000;
 
@@ -107,7 +106,6 @@ static struct mtd_partition tqm8xxl_fs_partitions[] = {
          //.size = MTDPART_SIZ_FULL,
        }
 };
-#endif
 
 static int __init init_tqm_mtd(void)
 {
@@ -188,7 +186,6 @@ static int __init init_tqm_mtd(void)
                goto error_mem;
        }
 
-#ifdef CONFIG_MTD_PARTITIONS
        /*
         * Select Static partition definitions
         */
@@ -201,21 +198,14 @@ static int __init init_tqm_mtd(void)
        part_banks[1].nums = ARRAY_SIZE(tqm8xxl_fs_partitions);
 
        for(idx = 0; idx < num_banks ; idx++) {
-               if (part_banks[idx].nums == 0) {
+               if (part_banks[idx].nums == 0)
                        printk(KERN_NOTICE "TQM flash%d: no partition info available, registering whole flash at once\n", idx);
-                       add_mtd_device(mtd_banks[idx]);
-               } else {
+               else
                        printk(KERN_NOTICE "TQM flash%d: Using %s partition definition\n",
                                        idx, part_banks[idx].type);
-                       add_mtd_partitions(mtd_banks[idx], part_banks[idx].mtd_part,
-                                                               part_banks[idx].nums);
-               }
+               mtd_device_register(mtd_banks[idx], part_banks[idx].mtd_part,
+               part_banks[idx].nums);
        }
-#else
-       printk(KERN_NOTICE "TQM flash: registering %d whole flash banks at once\n", num_banks);
-       for(idx = 0 ; idx < num_banks ; idx++)
-               add_mtd_device(mtd_banks[idx]);
-#endif
        return 0;
 error_mem:
        for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
@@ -237,7 +227,7 @@ static void __exit cleanup_tqm_mtd(void)
        for(idx = 0 ; idx < num_banks ; idx++) {
                /* destroy mtd_info previously allocated */
                if (mtd_banks[idx]) {
-                       del_mtd_partitions(mtd_banks[idx]);
+                       mtd_device_unregister(mtd_banks[idx]);
                        map_destroy(mtd_banks[idx]);
                }
                /* release map_info not used anymore */
index e02dfa9d4ddd8279890ec3daf1c91c0a0af90190..d1d671daf2356862374691b5a5977754d6828384 100644 (file)
@@ -89,7 +89,7 @@ static int __init init_ts5500_map(void)
        }
 
        mymtd->owner = THIS_MODULE;
-       add_mtd_partitions(mymtd, ts5500_partitions, NUM_PARTITIONS);
+       mtd_device_register(mymtd, ts5500_partitions, NUM_PARTITIONS);
 
        return 0;
 
@@ -102,7 +102,7 @@ err2:
 static void __exit cleanup_ts5500_map(void)
 {
        if (mymtd) {
-               del_mtd_partitions(mymtd);
+               mtd_device_unregister(mymtd);
                map_destroy(mymtd);
        }
 
index 77a8bfc025770b657ae404b814d7e718ea3da005..1de390e1c2fb3039b98100014e21ac2e6563ba4c 100644 (file)
@@ -76,7 +76,7 @@ static void __exit  cleanup_tsunami_flash(void)
        struct mtd_info *mtd;
        mtd = tsunami_flash_mtd;
        if (mtd) {
-               del_mtd_device(mtd);
+               mtd_device_unregister(mtd);
                map_destroy(mtd);
        }
        tsunami_flash_mtd = 0;
@@ -97,7 +97,7 @@ static int __init init_tsunami_flash(void)
        }
        if (tsunami_flash_mtd) {
                tsunami_flash_mtd->owner = THIS_MODULE;
-               add_mtd_device(tsunami_flash_mtd);
+               mtd_device_register(tsunami_flash_mtd, NULL, 0);
                return 0;
        }
        return -ENXIO;
index 35009294b435f33a62c0dbb4496ffe5c8b189174..6793074f3f40aff0eacb4d4e94eb6c8e960e51e7 100644 (file)
@@ -89,11 +89,7 @@ static int __init uclinux_mtd_init(void)
        mtd->priv = mapp;
 
        uclinux_ram_mtdinfo = mtd;
-#ifdef CONFIG_MTD_PARTITIONS
-       add_mtd_partitions(mtd, uclinux_romfs, NUM_PARTITIONS);
-#else
-       add_mtd_device(mtd);
-#endif
+       mtd_device_register(mtd, uclinux_romfs, NUM_PARTITIONS);
 
        return(0);
 }
@@ -103,11 +99,7 @@ static int __init uclinux_mtd_init(void)
 static void __exit uclinux_mtd_cleanup(void)
 {
        if (uclinux_ram_mtdinfo) {
-#ifdef CONFIG_MTD_PARTITIONS
-               del_mtd_partitions(uclinux_ram_mtdinfo);
-#else
-               del_mtd_device(uclinux_ram_mtdinfo);
-#endif
+               mtd_device_unregister(uclinux_ram_mtdinfo);
                map_destroy(uclinux_ram_mtdinfo);
                uclinux_ram_mtdinfo = NULL;
        }
index 6adaa6acc1936716ad74e063613c84abe7c5d856..5e68de73eabc9b94fce43255806994f5a8f9baaa 100644 (file)
@@ -138,7 +138,7 @@ static void __exit cleanup_vmax301(void)
 
        for (i=0; i<2; i++) {
                if (vmax_mtd[i]) {
-                       del_mtd_device(vmax_mtd[i]);
+                       mtd_device_unregister(vmax_mtd[i]);
                        map_destroy(vmax_mtd[i]);
                }
        }
@@ -176,7 +176,7 @@ static int __init init_vmax301(void)
                        vmax_mtd[i] = do_map_probe("map_rom", &vmax_map[i]);
                if (vmax_mtd[i]) {
                        vmax_mtd[i]->owner = THIS_MODULE;
-                       add_mtd_device(vmax_mtd[i]);
+                       mtd_device_register(vmax_mtd[i], NULL, 0);
                }
        }
 
index 4afc167731ef5e980383d0f442c9417ab58494f4..3a04b078576a0aa04ee07afa4fec48c56fe3f43b 100644 (file)
@@ -563,7 +563,7 @@ static void vmu_queryblocks(struct mapleq *mq)
                goto fail_cache_create;
        part_cur->pcache = pcache;
 
-       error = add_mtd_device(mtd_cur);
+       error = mtd_device_register(mtd_cur, NULL, 0);
        if (error)
                goto fail_mtd_register;
 
@@ -709,7 +709,7 @@ static void __devexit vmu_disconnect(struct maple_device *mdev)
        for (x = 0; x < card->partitions; x++) {
                mpart = ((card->mtd)[x]).priv;
                mpart->mdev = NULL;
-               del_mtd_device(&((card->mtd)[x]));
+               mtd_device_unregister(&((card->mtd)[x]));
                kfree(((card->parts)[x]).name);
        }
        kfree(card->parts);
index 933a2b6598b46fe44f1935afe3f55ed49f35f521..901ce968efaebc11acf9e9c4e5460dfec7fc3e3d 100644 (file)
@@ -132,17 +132,20 @@ static int __init init_sbc82xx_flash(void)
                nr_parts = parse_mtd_partitions(sbcmtd[i], part_probes,
                                                &sbcmtd_parts[i], 0);
                if (nr_parts > 0) {
-                       add_mtd_partitions (sbcmtd[i], sbcmtd_parts[i], nr_parts);
+                       mtd_device_register(sbcmtd[i], sbcmtd_parts[i],
+                                           nr_parts);
                        continue;
                }
 
                /* No partitioning detected. Use default */
                if (i == 2) {
-                       add_mtd_device(sbcmtd[i]);
+                       mtd_device_register(sbcmtd[i], NULL, 0);
                } else if (i == bigflash) {
-                       add_mtd_partitions (sbcmtd[i], bigflash_parts, ARRAY_SIZE(bigflash_parts));
+                       mtd_device_register(sbcmtd[i], bigflash_parts,
+                                           ARRAY_SIZE(bigflash_parts));
                } else {
-                       add_mtd_partitions (sbcmtd[i], smallflash_parts, ARRAY_SIZE(smallflash_parts));
+                       mtd_device_register(sbcmtd[i], smallflash_parts,
+                                           ARRAY_SIZE(smallflash_parts));
                }
        }
        return 0;
@@ -157,9 +160,9 @@ static void __exit cleanup_sbc82xx_flash(void)
                        continue;
 
                if (i<2 || sbcmtd_parts[i])
-                       del_mtd_partitions(sbcmtd[i]);
+                       mtd_device_unregister(sbcmtd[i]);
                else
-                       del_mtd_device(sbcmtd[i]);
+                       mtd_device_unregister(sbcmtd[i]);
 
                kfree(sbcmtd_parts[i]);
                map_destroy(sbcmtd[i]);
index a534e1f0c34844b39c0fd03ce9ee070f88438a9b..ca385697446ece7ebfe387a4cd99b41cbca9ebbc 100644 (file)
@@ -221,15 +221,33 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode)
        kref_get(&dev->ref);
        __module_get(dev->tr->owner);
 
-       if (dev->mtd) {
-               ret = dev->tr->open ? dev->tr->open(dev) : 0;
-               __get_mtd_device(dev->mtd);
+       if (!dev->mtd)
+               goto unlock;
+
+       if (dev->tr->open) {
+               ret = dev->tr->open(dev);
+               if (ret)
+                       goto error_put;
        }
 
+       ret = __get_mtd_device(dev->mtd);
+       if (ret)
+               goto error_release;
+
 unlock:
        mutex_unlock(&dev->lock);
        blktrans_dev_put(dev);
        return ret;
+
+error_release:
+       if (dev->tr->release)
+               dev->tr->release(dev);
+error_put:
+       module_put(dev->tr->owner);
+       kref_put(&dev->ref, blktrans_dev_release);
+       mutex_unlock(&dev->lock);
+       blktrans_dev_put(dev);
+       return ret;
 }
 
 static int blktrans_release(struct gendisk *disk, fmode_t mode)
index 4c36ef66a46b907962ae01ccb420895355d592fe..3f92731a5b9ebf288ed83602c36972e5d32dee8d 100644 (file)
@@ -166,10 +166,23 @@ static int mtd_close(struct inode *inode, struct file *file)
        return 0;
 } /* mtd_close */
 
-/* FIXME: This _really_ needs to die. In 2.5, we should lock the
-   userspace buffer down and use it directly with readv/writev.
-*/
-#define MAX_KMALLOC_SIZE 0x20000
+/* Back in June 2001, dwmw2 wrote:
+ *
+ *   FIXME: This _really_ needs to die. In 2.5, we should lock the
+ *   userspace buffer down and use it directly with readv/writev.
+ *
+ * The implementation below, using mtd_kmalloc_up_to, mitigates
+ * allocation failures when the system is under low-memory situations
+ * or if memory is highly fragmented at the cost of reducing the
+ * performance of the requested transfer due to a smaller buffer size.
+ *
+ * A more complex but more memory-efficient implementation based on
+ * get_user_pages and iovecs to cover extents of those pages is a
+ * longer-term goal, as intimated by dwmw2 above. However, for the
+ * write case, this requires yet more complex head and tail transfer
+ * handling when those head and tail offsets and sizes are such that
+ * alignment requirements are not met in the NAND subdriver.
+ */
 
 static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)
 {
@@ -179,6 +192,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
        size_t total_retlen=0;
        int ret=0;
        int len;
+       size_t size = count;
        char *kbuf;
 
        DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n");
@@ -189,23 +203,12 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
        if (!count)
                return 0;
 
-       /* FIXME: Use kiovec in 2.5 to lock down the user's buffers
-          and pass them directly to the MTD functions */
-
-       if (count > MAX_KMALLOC_SIZE)
-               kbuf=kmalloc(MAX_KMALLOC_SIZE, GFP_KERNEL);
-       else
-               kbuf=kmalloc(count, GFP_KERNEL);
-
+       kbuf = mtd_kmalloc_up_to(mtd, &size);
        if (!kbuf)
                return -ENOMEM;
 
        while (count) {
-
-               if (count > MAX_KMALLOC_SIZE)
-                       len = MAX_KMALLOC_SIZE;
-               else
-                       len = count;
+               len = min_t(size_t, count, size);
 
                switch (mfi->mode) {
                case MTD_MODE_OTP_FACTORY:
@@ -268,6 +271,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
 {
        struct mtd_file_info *mfi = file->private_data;
        struct mtd_info *mtd = mfi->mtd;
+       size_t size = count;
        char *kbuf;
        size_t retlen;
        size_t total_retlen=0;
@@ -285,20 +289,12 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
        if (!count)
                return 0;
 
-       if (count > MAX_KMALLOC_SIZE)
-               kbuf=kmalloc(MAX_KMALLOC_SIZE, GFP_KERNEL);
-       else
-               kbuf=kmalloc(count, GFP_KERNEL);
-
+       kbuf = mtd_kmalloc_up_to(mtd, &size);
        if (!kbuf)
                return -ENOMEM;
 
        while (count) {
-
-               if (count > MAX_KMALLOC_SIZE)
-                       len = MAX_KMALLOC_SIZE;
-               else
-                       len = count;
+               len = min_t(size_t, count, size);
 
                if (copy_from_user(kbuf, buf, len)) {
                        kfree(kbuf);
@@ -512,7 +508,6 @@ static int shrink_ecclayout(const struct nand_ecclayout *from,
        return 0;
 }
 
-#ifdef CONFIG_MTD_PARTITIONS
 static int mtd_blkpg_ioctl(struct mtd_info *mtd,
                           struct blkpg_ioctl_arg __user *arg)
 {
@@ -548,8 +543,6 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd,
                return -EINVAL;
        }
 }
-#endif
-
 
 static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
 {
@@ -941,7 +934,6 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
                break;
        }
 
-#ifdef CONFIG_MTD_PARTITIONS
        case BLKPG:
        {
                ret = mtd_blkpg_ioctl(mtd,
@@ -955,7 +947,6 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
                ret = 0;
                break;
        }
-#endif
 
        default:
                ret = -ENOTTY;
index 5060e608ea5d40a1fc6307829c31922abb5199a9..e601672a53050900d3d0b8cf084829db6d10d9bd 100644 (file)
@@ -319,7 +319,7 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
        if (!(mtd->flags & MTD_WRITEABLE))
                return -EROFS;
 
-       ops->retlen = 0;
+       ops->retlen = ops->oobretlen = 0;
 
        for (i = 0; i < concat->num_subdev; i++) {
                struct mtd_info *subdev = concat->subdev[i];
@@ -334,7 +334,7 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
                        devops.len = subdev->size - to;
 
                err = subdev->write_oob(subdev, to, &devops);
-               ops->retlen += devops.retlen;
+               ops->retlen += devops.oobretlen;
                if (err)
                        return err;
 
index da69bc8a5a7d6f92c313fe2df32c644b9a0614f6..c510aff289a88d077d9e42c6854bfdcd1533e3be 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/ptrace.h>
+#include <linux/seq_file.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/major.h>
@@ -37,6 +38,7 @@
 #include <linux/gfp.h>
 
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
 
 #include "mtdcore.h"
 /*
@@ -391,7 +393,7 @@ fail_locked:
  *     if the requested device does not appear to be present in the list.
  */
 
-int del_mtd_device (struct mtd_info *mtd)
+int del_mtd_device(struct mtd_info *mtd)
 {
        int ret;
        struct mtd_notifier *not;
@@ -426,6 +428,50 @@ out_error:
        return ret;
 }
 
+/**
+ * mtd_device_register - register an MTD device.
+ *
+ * @master: the MTD device to register
+ * @parts: the partitions to register - only valid if nr_parts > 0
+ * @nr_parts: the number of partitions in parts.  If zero then the full MTD
+ *            device is registered
+ *
+ * Register an MTD device with the system and optionally, a number of
+ * partitions.  If nr_parts is 0 then the whole device is registered, otherwise
+ * only the partitions are registered.  To register both the full device *and*
+ * the partitions, call mtd_device_register() twice, once with nr_parts == 0
+ * and once equal to the number of partitions.
+ */
+int mtd_device_register(struct mtd_info *master,
+                       const struct mtd_partition *parts,
+                       int nr_parts)
+{
+       return parts ? add_mtd_partitions(master, parts, nr_parts) :
+               add_mtd_device(master);
+}
+EXPORT_SYMBOL_GPL(mtd_device_register);
+
+/**
+ * mtd_device_unregister - unregister an existing MTD device.
+ *
+ * @master: the MTD device to unregister.  This will unregister both the master
+ *          and any partitions if registered.
+ */
+int mtd_device_unregister(struct mtd_info *master)
+{
+       int err;
+
+       err = del_mtd_partitions(master);
+       if (err)
+               return err;
+
+       if (!device_is_registered(&master->dev))
+               return 0;
+
+       return del_mtd_device(master);
+}
+EXPORT_SYMBOL_GPL(mtd_device_unregister);
+
 /**
  *     register_mtd_user - register a 'user' of MTD devices.
  *     @new: pointer to notifier info structure
@@ -443,7 +489,7 @@ void register_mtd_user (struct mtd_notifier *new)
 
        list_add(&new->list, &mtd_notifiers);
 
-       __module_get(THIS_MODULE);
+       __module_get(THIS_MODULE);
 
        mtd_for_each_device(mtd)
                new->add(mtd);
@@ -532,7 +578,6 @@ int __get_mtd_device(struct mtd_info *mtd)
                return -ENODEV;
 
        if (mtd->get_device) {
-
                err = mtd->get_device(mtd);
 
                if (err) {
@@ -570,21 +615,13 @@ struct mtd_info *get_mtd_device_nm(const char *name)
        if (!mtd)
                goto out_unlock;
 
-       if (!try_module_get(mtd->owner))
+       err = __get_mtd_device(mtd);
+       if (err)
                goto out_unlock;
 
-       if (mtd->get_device) {
-               err = mtd->get_device(mtd);
-               if (err)
-                       goto out_put;
-       }
-
-       mtd->usecount++;
        mutex_unlock(&mtd_table_mutex);
        return mtd;
 
-out_put:
-       module_put(mtd->owner);
 out_unlock:
        mutex_unlock(&mtd_table_mutex);
        return ERR_PTR(err);
@@ -638,8 +675,54 @@ int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
        return ret;
 }
 
-EXPORT_SYMBOL_GPL(add_mtd_device);
-EXPORT_SYMBOL_GPL(del_mtd_device);
+/**
+ * mtd_kmalloc_up_to - allocate a contiguous buffer up to the specified size
+ * @size: A pointer to the ideal or maximum size of the allocation. Points
+ *        to the actual allocation size on success.
+ *
+ * This routine attempts to allocate a contiguous kernel buffer up to
+ * the specified size, backing off the size of the request exponentially
+ * until the request succeeds or until the allocation size falls below
+ * the system page size. This attempts to make sure it does not adversely
+ * impact system performance, so when allocating more than one page, we
+ * ask the memory allocator to avoid re-trying, swapping, writing back
+ * or performing I/O.
+ *
+ * Note, this function also makes sure that the allocated buffer is aligned to
+ * the MTD device's min. I/O unit, i.e. the "mtd->writesize" value.
+ *
+ * This is called, for example by mtd_{read,write} and jffs2_scan_medium,
+ * to handle smaller (i.e. degraded) buffer allocations under low- or
+ * fragmented-memory situations where such reduced allocations, from a
+ * requested ideal, are allowed.
+ *
+ * Returns a pointer to the allocated buffer on success; otherwise, NULL.
+ */
+void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size)
+{
+       gfp_t flags = __GFP_NOWARN | __GFP_WAIT |
+                      __GFP_NORETRY | __GFP_NO_KSWAPD;
+       size_t min_alloc = max_t(size_t, mtd->writesize, PAGE_SIZE);
+       void *kbuf;
+
+       *size = min_t(size_t, *size, KMALLOC_MAX_SIZE);
+
+       while (*size > min_alloc) {
+               kbuf = kmalloc(*size, flags);
+               if (kbuf)
+                       return kbuf;
+
+               *size >>= 1;
+               *size = ALIGN(*size, mtd->writesize);
+       }
+
+       /*
+        * For the last resort allocation allow 'kmalloc()' to do all sorts of
+        * things (write-back, dropping caches, etc) by using GFP_KERNEL.
+        */
+       return kmalloc(*size, GFP_KERNEL);
+}
+
 EXPORT_SYMBOL_GPL(get_mtd_device);
 EXPORT_SYMBOL_GPL(get_mtd_device_nm);
 EXPORT_SYMBOL_GPL(__get_mtd_device);
@@ -648,6 +731,7 @@ EXPORT_SYMBOL_GPL(__put_mtd_device);
 EXPORT_SYMBOL_GPL(register_mtd_user);
 EXPORT_SYMBOL_GPL(unregister_mtd_user);
 EXPORT_SYMBOL_GPL(default_mtd_writev);
+EXPORT_SYMBOL_GPL(mtd_kmalloc_up_to);
 
 #ifdef CONFIG_PROC_FS
 
@@ -656,44 +740,32 @@ EXPORT_SYMBOL_GPL(default_mtd_writev);
 
 static struct proc_dir_entry *proc_mtd;
 
-static inline int mtd_proc_info(char *buf, struct mtd_info *this)
-{
-       return sprintf(buf, "mtd%d: %8.8llx %8.8x \"%s\"\n", this->index,
-                      (unsigned long long)this->size,
-                      this->erasesize, this->name);
-}
-
-static int mtd_read_proc (char *page, char **start, off_t off, int count,
-                         int *eof, void *data_unused)
+static int mtd_proc_show(struct seq_file *m, void *v)
 {
        struct mtd_info *mtd;
-       int len, l;
-        off_t   begin = 0;
 
+       seq_puts(m, "dev:    size   erasesize  name\n");
        mutex_lock(&mtd_table_mutex);
-
-       len = sprintf(page, "dev:    size   erasesize  name\n");
        mtd_for_each_device(mtd) {
-               l = mtd_proc_info(page + len, mtd);
-                len += l;
-                if (len+begin > off+count)
-                        goto done;
-                if (len+begin < off) {
-                        begin += len;
-                        len = 0;
-                }
-        }
-
-        *eof = 1;
-
-done:
+               seq_printf(m, "mtd%d: %8.8llx %8.8x \"%s\"\n",
+                          mtd->index, (unsigned long long)mtd->size,
+                          mtd->erasesize, mtd->name);
+       }
        mutex_unlock(&mtd_table_mutex);
-        if (off >= len+begin)
-                return 0;
-        *start = page + (off-begin);
-        return ((count < begin+len-off) ? count : begin+len-off);
+       return 0;
+}
+
+static int mtd_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, mtd_proc_show, NULL);
 }
 
+static const struct file_operations mtd_proc_ops = {
+       .open           = mtd_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 #endif /* CONFIG_PROC_FS */
 
 /*====================================================================*/
@@ -734,8 +806,7 @@ static int __init init_mtd(void)
                goto err_bdi3;
 
 #ifdef CONFIG_PROC_FS
-       if ((proc_mtd = create_proc_entry( "mtd", 0, NULL )))
-               proc_mtd->read_proc = mtd_read_proc;
+       proc_mtd = proc_create("mtd", 0, NULL, &mtd_proc_ops);
 #endif /* CONFIG_PROC_FS */
        return 0;
 
@@ -753,7 +824,7 @@ err_reg:
 static void __exit cleanup_mtd(void)
 {
 #ifdef CONFIG_PROC_FS
-        if (proc_mtd)
+       if (proc_mtd)
                remove_proc_entry( "mtd", NULL);
 #endif /* CONFIG_PROC_FS */
        class_unregister(&mtd_class);
index 6a64fdebc898f04a0ff250c698509c77fc6a54f5..0ed6126b4c1ffb0cc40c7f161926daf20d14bb0b 100644 (file)
 extern struct mutex mtd_table_mutex;
 extern struct mtd_info *__mtd_next_device(int i);
 
+extern int add_mtd_device(struct mtd_info *mtd);
+extern int del_mtd_device(struct mtd_info *mtd);
+extern int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *,
+                             int);
+extern int del_mtd_partitions(struct mtd_info *);
+
 #define mtd_for_each_device(mtd)                       \
        for ((mtd) = __mtd_next_device(0);              \
             (mtd) != NULL;                             \
index 0a476017478277a925014d36f13ea0ea77c872ee..630be3e7da04f2eed1ab628c21004ba077d4522c 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/mtd/partitions.h>
 #include <linux/err.h>
 
+#include "mtdcore.h"
+
 /* Our partition linked list */
 static LIST_HEAD(mtd_partitions);
 static DEFINE_MUTEX(mtd_partitions_mutex);
@@ -376,7 +378,6 @@ int del_mtd_partitions(struct mtd_info *master)
 
        return err;
 }
-EXPORT_SYMBOL(del_mtd_partitions);
 
 static struct mtd_part *allocate_partition(struct mtd_info *master,
                        const struct mtd_partition *part, int partno,
@@ -671,7 +672,6 @@ int add_mtd_partitions(struct mtd_info *master,
 
        return 0;
 }
-EXPORT_SYMBOL(add_mtd_partitions);
 
 static DEFINE_SPINLOCK(part_parser_lock);
 static LIST_HEAD(part_parsers);
@@ -722,11 +722,8 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types,
                parser = get_partition_parser(*types);
                if (!parser && !request_module("%s", *types))
                                parser = get_partition_parser(*types);
-               if (!parser) {
-                       printk(KERN_NOTICE "%s partition parsing not available\n",
-                              *types);
+               if (!parser)
                        continue;
-               }
                ret = (*parser->parse_fn)(master, pparts, origin);
                if (ret > 0) {
                        printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
index fed215c4cfa19a3676666dbef17c1e4ce8b8d8bc..fd7885327611d75d68a25e788fa7a44950109513 100644 (file)
@@ -1450,7 +1450,13 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
        }
 
        oinfo = mtd->ecclayout;
-       if (!mtd->oobsize || !oinfo || oinfo->oobavail < MTDSWAP_OOBSIZE) {
+       if (!oinfo) {
+               printk(KERN_ERR "%s: mtd%d does not have OOB\n",
+                       MTDSWAP_PREFIX, mtd->index);
+               return;
+       }
+
+       if (!mtd->oobsize || oinfo->oobavail < MTDSWAP_OOBSIZE) {
                printk(KERN_ERR "%s: Not enough free bytes in OOB, "
                        "%d available, %zu needed.\n",
                        MTDSWAP_PREFIX, oinfo->oobavail, MTDSWAP_OOBSIZE);
index edec457d361d4b12a8f2a419d2330c54b2f6ddd8..4c3425235adc573edbbd2a77ee6efc661c81f75b 100644 (file)
@@ -92,7 +92,7 @@ config MTD_NAND_EDB7312
 
 config MTD_NAND_H1900
        tristate "iPAQ H1900 flash"
-       depends on ARCH_PXA && MTD_PARTITIONS
+       depends on ARCH_PXA
        help
          This enables the driver for the iPAQ h1900 flash.
 
@@ -419,7 +419,6 @@ config MTD_NAND_TMIO
 
 config MTD_NAND_NANDSIM
        tristate "Support for NAND Flash Simulator"
-       depends on MTD_PARTITIONS
        help
          The simulator may simulate various NAND flash chips for the
          MTD nand layer.
@@ -513,7 +512,7 @@ config MTD_NAND_SOCRATES
 
 config MTD_NAND_NUC900
        tristate "Support for NAND on Nuvoton NUC9xx/w90p910 evaluation boards."
-       depends on ARCH_W90X900 && MTD_PARTITIONS
+       depends on ARCH_W90X900
        help
          This enables the driver for the NAND Flash on evaluation board based
          on w90p910 / NUC9xx.
index 8691e0482ed28b8886e976c0bee3e1e48cd02c75..eb40ea829ab282b0418d68efd1c8a0f6c0347c9a 100644 (file)
@@ -120,7 +120,7 @@ static void alauda_delete(struct kref *kref)
        struct alauda *al = container_of(kref, struct alauda, kref);
 
        if (al->mtd) {
-               del_mtd_device(al->mtd);
+               mtd_device_unregister(al->mtd);
                kfree(al->mtd);
        }
        usb_put_dev(al->dev);
@@ -592,7 +592,7 @@ static int alauda_init_media(struct alauda *al)
        mtd->priv = al;
        mtd->owner = THIS_MODULE;
 
-       err = add_mtd_device(mtd);
+       err = mtd_device_register(mtd, NULL, 0);
        if (err) {
                err = -ENFILE;
                goto error;
index bc65bf71e1a240798f2be57a8668bc971249c5fb..78017eb9318ebc7dbbf4c8269b83b3d0ca924e34 100644 (file)
@@ -235,8 +235,8 @@ static int __devinit ams_delta_init(struct platform_device *pdev)
        }
 
        /* Register the partitions */
-       add_mtd_partitions(ams_delta_mtd, partition_info,
-                          ARRAY_SIZE(partition_info));
+       mtd_device_register(ams_delta_mtd, partition_info,
+                           ARRAY_SIZE(partition_info));
 
        goto out;
 
index 950646aa4c4b004a174c1951f08397ab808956c0..b300705d41cb67ce432023f003b2ee63904d59ab 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 
+#include <linux/dmaengine.h>
 #include <linux/gpio.h>
 #include <linux/io.h>
 
@@ -494,11 +495,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
        struct resource *regs;
        struct resource *mem;
        int res;
-
-#ifdef CONFIG_MTD_PARTITIONS
        struct mtd_partition *partitions = NULL;
        int num_partitions = 0;
-#endif
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!mem) {
@@ -656,7 +654,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
                goto err_scan_tail;
        }
 
-#ifdef CONFIG_MTD_PARTITIONS
 #ifdef CONFIG_MTD_CMDLINE_PARTS
        mtd->name = "atmel_nand";
        num_partitions = parse_mtd_partitions(mtd, part_probes,
@@ -672,17 +669,11 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
                goto err_no_partitions;
        }
 
-       res = add_mtd_partitions(mtd, partitions, num_partitions);
-#else
-       res = add_mtd_device(mtd);
-#endif
-
+       res = mtd_device_register(mtd, partitions, num_partitions);
        if (!res)
                return res;
 
-#ifdef CONFIG_MTD_PARTITIONS
 err_no_partitions:
-#endif
        nand_release(mtd);
 err_scan_tail:
 err_scan_ident:
index 5d513b54a7d7cd688711007145fa93d8d0b400ab..e7767eef4505665279142ba57e13a43e6ac4b35b 100644 (file)
@@ -581,7 +581,8 @@ static int __init au1xxx_nand_init(void)
        }
 
        /* Register the partitions */
-       add_mtd_partitions(au1550_mtd, partition_info, ARRAY_SIZE(partition_info));
+       mtd_device_register(au1550_mtd, partition_info,
+                           ARRAY_SIZE(partition_info));
 
        return 0;
 
index 0911cf03db806bcaa33e5469732e3158f7eaff77..eddc9a2249859efe157dac13f8042da3afaf26e6 100644 (file)
@@ -185,20 +185,20 @@ static int __init autcpu12_init(void)
        /* Register the partitions */
        switch (autcpu12_mtd->size) {
                case SZ_16M:
-                       add_mtd_partitions(autcpu12_mtd, partition_info16k,
-                                          NUM_PARTITIONS16K);
+                       mtd_device_register(autcpu12_mtd, partition_info16k,
+                                           NUM_PARTITIONS16K);
                        break;
                case SZ_32M:
-                       add_mtd_partitions(autcpu12_mtd, partition_info32k,
-                                          NUM_PARTITIONS32K);
+                       mtd_device_register(autcpu12_mtd, partition_info32k,
+                                           NUM_PARTITIONS32K);
                        break;
                case SZ_64M:
-                       add_mtd_partitions(autcpu12_mtd, partition_info64k,
-                                          NUM_PARTITIONS64K);
+                       mtd_device_register(autcpu12_mtd, partition_info64k,
+                                           NUM_PARTITIONS64K);
                        break;
                case SZ_128M:
-                       add_mtd_partitions(autcpu12_mtd, partition_info128k,
-                                          NUM_PARTITIONS128K);
+                       mtd_device_register(autcpu12_mtd, partition_info128k,
+                                           NUM_PARTITIONS128K);
                        break;
                default:
                        printk("Unsupported SmartMedia device\n");
index dfe262c726fb8292d7861ea23715a4e6f968134e..9ec280738a9a51f3b22519e76103328445ae3954 100644 (file)
@@ -52,9 +52,7 @@
 static const __devinitconst char gBanner[] = KERN_INFO \
        "BCM UMI MTD NAND Driver: 1.00\n";
 
-#ifdef CONFIG_MTD_PARTITIONS
 const char *part_probes[] = { "cmdlinepart", NULL };
-#endif
 
 #if NAND_ECC_BCH
 static uint8_t scan_ff_pattern[] = { 0xff };
@@ -509,7 +507,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev)
                        kfree(board_mtd);
                        return -EIO;
                }
-               add_mtd_partitions(board_mtd, partition_info, nr_partitions);
+               mtd_device_register(board_mtd, partition_info, nr_partitions);
        }
 
        /* Return happy */
index 79947bea4d57aa7b075c766ab3038c9996cfb391..dd899cb5d366e4de044ec16129000bb99c6fcc58 100644 (file)
@@ -659,15 +659,10 @@ static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)
 static int __devinit bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
 {
        struct mtd_info *mtd = &info->mtd;
-
-#ifdef CONFIG_MTD_PARTITIONS
        struct mtd_partition *parts = info->platform->partitions;
        int nr = info->platform->nr_partitions;
 
-       return add_mtd_partitions(mtd, parts, nr);
-#else
-       return add_mtd_device(mtd);
-#endif
+       return mtd_device_register(mtd, parts, nr);
 }
 
 static int __devexit bf5xx_nand_remove(struct platform_device *pdev)
index e06c8983978ebd82ec376d74eac64aed1d12b80c..87ebb4e5b0c3b97949050ec10ff2a62b081c9bac 100644 (file)
@@ -90,9 +90,7 @@ static unsigned int numtimings;
 static int timing[3];
 module_param_array(timing, int, &numtimings, 0644);
 
-#ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probes[] = { "cmdlinepart", "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)
@@ -632,10 +630,8 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
        struct cafe_priv *cafe;
        uint32_t ctrl;
        int err = 0;
-#ifdef CONFIG_MTD_PARTITIONS
        struct mtd_partition *parts;
        int nr_parts;
-#endif
 
        /* Very old versions shared the same PCI ident for all three
           functions on the chip. Verify the class too... */
@@ -804,9 +800,8 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
        pci_set_drvdata(pdev, mtd);
 
        /* We register the whole device first, separate from the partitions */
-       add_mtd_device(mtd);
+       mtd_device_register(mtd, NULL, 0);
 
-#ifdef CONFIG_MTD_PARTITIONS
 #ifdef CONFIG_MTD_CMDLINE_PARTS
        mtd->name = "cafe_nand";
 #endif
@@ -814,9 +809,8 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
        if (nr_parts > 0) {
                cafe->parts = parts;
                dev_info(&cafe->pdev->dev, "%d partitions found\n", nr_parts);
-               add_mtd_partitions(mtd, parts, nr_parts);
+               mtd_device_register(mtd, parts, nr_parts);
        }
-#endif
        goto out;
 
  out_irq:
@@ -838,7 +832,6 @@ static void __devexit cafe_nand_remove(struct pci_dev *pdev)
        struct mtd_info *mtd = pci_get_drvdata(pdev);
        struct cafe_priv *cafe = mtd->priv;
 
-       del_mtd_device(mtd);
        /* Disable NAND IRQ in global IRQ mask register */
        cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
        free_irq(pdev->irq, mtd);
index 6e6495278258f040e51bcfc1e41f6b0f6d45f1d2..6fc043a30d1e20809dccb6d3555ee1603823415e 100644 (file)
@@ -238,7 +238,7 @@ static int __init cmx270_init(void)
 
        /* Register the partitions */
        pr_notice("Using %s partition definition\n", part_type);
-       ret = add_mtd_partitions(cmx270_nand_mtd, mtd_parts, mtd_parts_nb);
+       ret = mtd_device_register(cmx270_nand_mtd, mtd_parts, mtd_parts_nb);
        if (ret)
                goto err_scan;
 
index 71c35a0b9826972f164ea728f9d89af54a789b88..f59ad1f2d5dbe7e23fa10a7762332ff2ee44e3cb 100644 (file)
@@ -277,22 +277,15 @@ static int is_geode(void)
        return 0;
 }
 
-
-#ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probes[] = { "cmdlinepart", NULL };
-#endif
-
 
 static int __init cs553x_init(void)
 {
        int err = -ENXIO;
        int i;
        uint64_t val;
-
-#ifdef CONFIG_MTD_PARTITIONS
        int mtd_parts_nb = 0;
        struct mtd_partition *mtd_parts = NULL;
-#endif
 
        /* If the CPU isn't a Geode GX or LX, abort */
        if (!is_geode())
@@ -324,17 +317,11 @@ static int __init cs553x_init(void)
                if (cs553x_mtd[i]) {
 
                        /* If any devices registered, return success. Else the last error. */
-#ifdef CONFIG_MTD_PARTITIONS
                        mtd_parts_nb = parse_mtd_partitions(cs553x_mtd[i], part_probes, &mtd_parts, 0);
-                       if (mtd_parts_nb > 0) {
+                       if (mtd_parts_nb > 0)
                                printk(KERN_NOTICE "Using command line partition definition\n");
-                               add_mtd_partitions(cs553x_mtd[i], mtd_parts, mtd_parts_nb);
-                       } else {
-                               add_mtd_device(cs553x_mtd[i]);
-                       }
-#else
-                       add_mtd_device(cs553x_mtd[i]);
-#endif
+                       mtd_device_register(cs553x_mtd[i], mtd_parts,
+                                           mtd_parts_nb);
                        err = 0;
                }
        }
index aff3468867ac056cb81054fa4c17bfdb50022803..1f34951ae1a7426f0344a7327c56a5b1105c7bc8 100644 (file)
@@ -530,6 +530,8 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
        int                             ret;
        uint32_t                        val;
        nand_ecc_modes_t                ecc_mode;
+       struct mtd_partition            *mtd_parts = NULL;
+       int                             mtd_parts_nb = 0;
 
        /* insist on board-specific configuration */
        if (!pdata)
@@ -749,41 +751,33 @@ syndrome_done:
        if (ret < 0)
                goto err_scan;
 
-       if (mtd_has_partitions()) {
-               struct mtd_partition    *mtd_parts = NULL;
-               int                     mtd_parts_nb = 0;
+       if (mtd_has_cmdlinepart()) {
+               static const char *probes[] __initconst = {
+                       "cmdlinepart", NULL
+               };
 
-               if (mtd_has_cmdlinepart()) {
-                       static const char *probes[] __initconst =
-                               { "cmdlinepart", NULL };
-
-                       mtd_parts_nb = parse_mtd_partitions(&info->mtd, probes,
-                                                           &mtd_parts, 0);
-               }
-
-               if (mtd_parts_nb <= 0) {
-                       mtd_parts = pdata->parts;
-                       mtd_parts_nb = pdata->nr_parts;
-               }
+               mtd_parts_nb = parse_mtd_partitions(&info->mtd, probes,
+                                                   &mtd_parts, 0);
+       }
 
-               /* Register any partitions */
-               if (mtd_parts_nb > 0) {
-                       ret = add_mtd_partitions(&info->mtd,
-                                       mtd_parts, mtd_parts_nb);
-                       if (ret == 0)
-                               info->partitioned = true;
-               }
+       if (mtd_parts_nb <= 0) {
+               mtd_parts = pdata->parts;
+               mtd_parts_nb = pdata->nr_parts;
+       }
 
-       } else if (pdata->nr_parts) {
-               dev_warn(&pdev->dev, "ignoring %d default partitions on %s\n",
-                               pdata->nr_parts, info->mtd.name);
+       /* Register any partitions */
+       if (mtd_parts_nb > 0) {
+               ret = mtd_device_register(&info->mtd, mtd_parts,
+                                         mtd_parts_nb);
+               if (ret == 0)
+                       info->partitioned = true;
        }
 
        /* If there's no partition info, just package the whole chip
         * as a single MTD device.
         */
        if (!info->partitioned)
-               ret = add_mtd_device(&info->mtd) ? -ENODEV : 0;
+               ret = mtd_device_register(&info->mtd, NULL, 0) ? -ENODEV : 0;
 
        if (ret < 0)
                goto err_scan;
@@ -824,10 +818,7 @@ static int __exit nand_davinci_remove(struct platform_device *pdev)
        struct davinci_nand_info *info = platform_get_drvdata(pdev);
        int status;
 
-       if (mtd_has_partitions() && info->partitioned)
-               status = del_mtd_partitions(&info->mtd);
-       else
-               status = del_mtd_device(&info->mtd);
+       status = mtd_device_unregister(&info->mtd);
 
        spin_lock_irq(&davinci_nand_lock);
        if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
index 4633f094c51019a8405e2573cdada5b7c51997b8..d5276218945fe296cb1c1b8c29cb8f21929dfb42 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/wait.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
@@ -44,16 +45,16 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting."
 
 /* We define a macro here that combines all interrupts this driver uses into
  * a single constant value, for convenience. */
-#define DENALI_IRQ_ALL (INTR_STATUS0__DMA_CMD_COMP | \
-                       INTR_STATUS0__ECC_TRANSACTION_DONE | \
-                       INTR_STATUS0__ECC_ERR | \
-                       INTR_STATUS0__PROGRAM_FAIL | \
-                       INTR_STATUS0__LOAD_COMP | \
-                       INTR_STATUS0__PROGRAM_COMP | \
-                       INTR_STATUS0__TIME_OUT | \
-                       INTR_STATUS0__ERASE_FAIL | \
-                       INTR_STATUS0__RST_COMP | \
-                       INTR_STATUS0__ERASE_COMP)
+#define DENALI_IRQ_ALL (INTR_STATUS__DMA_CMD_COMP | \
+                       INTR_STATUS__ECC_TRANSACTION_DONE | \
+                       INTR_STATUS__ECC_ERR | \
+                       INTR_STATUS__PROGRAM_FAIL | \
+                       INTR_STATUS__LOAD_COMP | \
+                       INTR_STATUS__PROGRAM_COMP | \
+                       INTR_STATUS__TIME_OUT | \
+                       INTR_STATUS__ERASE_FAIL | \
+                       INTR_STATUS__RST_COMP | \
+                       INTR_STATUS__ERASE_COMP)
 
 /* indicates whether or not the internal value for the flash bank is
  * valid or not */
@@ -95,30 +96,6 @@ static const struct pci_device_id denali_pci_ids[] = {
        { /* end: all zeroes */ }
 };
 
-
-/* these are static lookup tables that give us easy access to
- * registers in the NAND controller.
- */
-static const uint32_t intr_status_addresses[4] = {INTR_STATUS0,
-                                                 INTR_STATUS1,
-                                                 INTR_STATUS2,
-                                                 INTR_STATUS3};
-
-static const uint32_t device_reset_banks[4] = {DEVICE_RESET__BANK0,
-                                                       DEVICE_RESET__BANK1,
-                                                       DEVICE_RESET__BANK2,
-                                                       DEVICE_RESET__BANK3};
-
-static const uint32_t operation_timeout[4] = {INTR_STATUS0__TIME_OUT,
-                                                       INTR_STATUS1__TIME_OUT,
-                                                       INTR_STATUS2__TIME_OUT,
-                                                       INTR_STATUS3__TIME_OUT};
-
-static const uint32_t reset_complete[4] = {INTR_STATUS0__RST_COMP,
-                                                       INTR_STATUS1__RST_COMP,
-                                                       INTR_STATUS2__RST_COMP,
-                                                       INTR_STATUS3__RST_COMP};
-
 /* forward declarations */
 static void clear_interrupts(struct denali_nand_info *denali);
 static uint32_t wait_for_irq(struct denali_nand_info *denali,
@@ -180,19 +157,17 @@ static void read_status(struct denali_nand_info *denali)
 static void reset_bank(struct denali_nand_info *denali)
 {
        uint32_t irq_status = 0;
-       uint32_t irq_mask = reset_complete[denali->flash_bank] |
-                           operation_timeout[denali->flash_bank];
-       int bank = 0;
+       uint32_t irq_mask = INTR_STATUS__RST_COMP |
+                           INTR_STATUS__TIME_OUT;
 
        clear_interrupts(denali);
 
-       bank = device_reset_banks[denali->flash_bank];
-       iowrite32(bank, denali->flash_reg + DEVICE_RESET);
+       iowrite32(1 << denali->flash_bank, denali->flash_reg + DEVICE_RESET);
 
        irq_status = wait_for_irq(denali, irq_mask);
 
-       if (irq_status & operation_timeout[denali->flash_bank])
-               dev_err(&denali->dev->dev, "reset bank failed.\n");
+       if (irq_status & INTR_STATUS__TIME_OUT)
+               dev_err(denali->dev, "reset bank failed.\n");
 }
 
 /* Reset the flash controller */
@@ -200,29 +175,28 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali)
 {
        uint32_t i;
 
-       dev_dbg(&denali->dev->dev, "%s, Line %d, Function: %s\n",
+       dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
                       __FILE__, __LINE__, __func__);
 
-       for (i = 0 ; i < LLD_MAX_FLASH_BANKS; i++)
-               iowrite32(reset_complete[i] | operation_timeout[i],
-               denali->flash_reg + intr_status_addresses[i]);
+       for (i = 0 ; i < denali->max_banks; i++)
+               iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT,
+               denali->flash_reg + INTR_STATUS(i));
 
-       for (i = 0 ; i < LLD_MAX_FLASH_BANKS; i++) {
-               iowrite32(device_reset_banks[i],
-                               denali->flash_reg + DEVICE_RESET);
+       for (i = 0 ; i < denali->max_banks; i++) {
+               iowrite32(1 << i, denali->flash_reg + DEVICE_RESET);
                while (!(ioread32(denali->flash_reg +
-                               intr_status_addresses[i]) &
-                       (reset_complete[i] | operation_timeout[i])))
+                               INTR_STATUS(i)) &
+                       (INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT)))
                        cpu_relax();
-               if (ioread32(denali->flash_reg + intr_status_addresses[i]) &
-                       operation_timeout[i])
-                       dev_dbg(&denali->dev->dev,
+               if (ioread32(denali->flash_reg + INTR_STATUS(i)) &
+                       INTR_STATUS__TIME_OUT)
+                       dev_dbg(denali->dev,
                        "NAND Reset operation timed out on bank %d\n", i);
        }
 
-       for (i = 0; i < LLD_MAX_FLASH_BANKS; i++)
-               iowrite32(reset_complete[i] | operation_timeout[i],
-                       denali->flash_reg + intr_status_addresses[i]);
+       for (i = 0; i < denali->max_banks; i++)
+               iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT,
+                       denali->flash_reg + INTR_STATUS(i));
 
        return PASS;
 }
@@ -254,7 +228,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali,
        uint16_t acc_clks;
        uint16_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt;
 
-       dev_dbg(&denali->dev->dev, "%s, Line %d, Function: %s\n",
+       dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
                       __FILE__, __LINE__, __func__);
 
        en_lo = CEIL_DIV(Trp[mode], CLK_X);
@@ -291,7 +265,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali,
                acc_clks++;
 
        if ((data_invalid - acc_clks * CLK_X) < 2)
-               dev_warn(&denali->dev->dev, "%s, Line %d: Warning!\n",
+               dev_warn(denali->dev, "%s, Line %d: Warning!\n",
                        __FILE__, __LINE__);
 
        addr_2_data = CEIL_DIV(Tadl[mode], CLK_X);
@@ -419,7 +393,7 @@ static void get_hynix_nand_para(struct denali_nand_info *denali,
 #endif
                break;
        default:
-               dev_warn(&denali->dev->dev,
+               dev_warn(denali->dev,
                        "Spectra: Unknown Hynix NAND (Device ID: 0x%x)."
                        "Will use default parameter values instead.\n",
                        device_id);
@@ -431,17 +405,17 @@ static void get_hynix_nand_para(struct denali_nand_info *denali,
  */
 static void find_valid_banks(struct denali_nand_info *denali)
 {
-       uint32_t id[LLD_MAX_FLASH_BANKS];
+       uint32_t id[denali->max_banks];
        int i;
 
        denali->total_used_banks = 1;
-       for (i = 0; i < LLD_MAX_FLASH_BANKS; i++) {
+       for (i = 0; i < denali->max_banks; i++) {
                index_addr(denali, (uint32_t)(MODE_11 | (i << 24) | 0), 0x90);
                index_addr(denali, (uint32_t)(MODE_11 | (i << 24) | 1), 0);
                index_addr_read_data(denali,
                                (uint32_t)(MODE_11 | (i << 24) | 2), &id[i]);
 
-               dev_dbg(&denali->dev->dev,
+               dev_dbg(denali->dev,
                        "Return 1st ID for bank[%d]: %x\n", i, id[i]);
 
                if (i == 0) {
@@ -461,16 +435,27 @@ static void find_valid_banks(struct denali_nand_info *denali)
                 * Multichip support is not enabled.
                 */
                if (denali->total_used_banks != 1) {
-                       dev_err(&denali->dev->dev,
+                       dev_err(denali->dev,
                                        "Sorry, Intel CE4100 only supports "
                                        "a single NAND device.\n");
                        BUG();
                }
        }
-       dev_dbg(&denali->dev->dev,
+       dev_dbg(denali->dev,
                "denali->total_used_banks: %d\n", denali->total_used_banks);
 }
 
+/*
+ * Use the configuration feature register to determine the maximum number of
+ * banks that the hardware supports.
+ */
+static void detect_max_banks(struct denali_nand_info *denali)
+{
+       uint32_t features = ioread32(denali->flash_reg + FEATURES);
+
+       denali->max_banks = 2 << (features & FEATURES__N_BANKS);
+}
+
 static void detect_partition_feature(struct denali_nand_info *denali)
 {
        /* For MRST platform, denali->fwblks represent the
@@ -480,15 +465,15 @@ static void detect_partition_feature(struct denali_nand_info *denali)
         * blocks it can't touch.
         * */
        if (ioread32(denali->flash_reg + FEATURES) & FEATURES__PARTITION) {
-               if ((ioread32(denali->flash_reg + PERM_SRC_ID_1) &
-                       PERM_SRC_ID_1__SRCID) == SPECTRA_PARTITION_ID) {
+               if ((ioread32(denali->flash_reg + PERM_SRC_ID(1)) &
+                       PERM_SRC_ID__SRCID) == SPECTRA_PARTITION_ID) {
                        denali->fwblks =
-                           ((ioread32(denali->flash_reg + MIN_MAX_BANK_1) &
-                             MIN_MAX_BANK_1__MIN_VALUE) *
+                           ((ioread32(denali->flash_reg + MIN_MAX_BANK(1)) &
+                             MIN_MAX_BANK__MIN_VALUE) *
                             denali->blksperchip)
                            +
-                           (ioread32(denali->flash_reg + MIN_BLK_ADDR_1) &
-                           MIN_BLK_ADDR_1__VALUE);
+                           (ioread32(denali->flash_reg + MIN_BLK_ADDR(1)) &
+                           MIN_BLK_ADDR__VALUE);
                } else
                        denali->fwblks = SPECTRA_START_BLOCK;
        } else
@@ -501,7 +486,7 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
        uint32_t id_bytes[5], addr;
        uint8_t i, maf_id, device_id;
 
-       dev_dbg(&denali->dev->dev,
+       dev_dbg(denali->dev,
                        "%s, Line %d, Function: %s\n",
                        __FILE__, __LINE__, __func__);
 
@@ -530,7 +515,7 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
                get_hynix_nand_para(denali, device_id);
        }
 
-       dev_info(&denali->dev->dev,
+       dev_info(denali->dev,
                        "Dump timing register values:"
                        "acc_clks: %d, re_2_we: %d, re_2_re: %d\n"
                        "we_2_re: %d, addr_2_data: %d, rdwr_en_lo_cnt: %d\n"
@@ -560,7 +545,7 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
 static void denali_set_intr_modes(struct denali_nand_info *denali,
                                        uint16_t INT_ENABLE)
 {
-       dev_dbg(&denali->dev->dev, "%s, Line %d, Function: %s\n",
+       dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
                       __FILE__, __LINE__, __func__);
 
        if (INT_ENABLE)
@@ -580,6 +565,7 @@ static inline bool is_flash_bank_valid(int flash_bank)
 static void denali_irq_init(struct denali_nand_info *denali)
 {
        uint32_t int_mask = 0;
+       int i;
 
        /* Disable global interrupts */
        denali_set_intr_modes(denali, false);
@@ -587,10 +573,8 @@ static void denali_irq_init(struct denali_nand_info *denali)
        int_mask = DENALI_IRQ_ALL;
 
        /* Clear all status bits */
-       iowrite32(0xFFFF, denali->flash_reg + INTR_STATUS0);
-       iowrite32(0xFFFF, denali->flash_reg + INTR_STATUS1);
-       iowrite32(0xFFFF, denali->flash_reg + INTR_STATUS2);
-       iowrite32(0xFFFF, denali->flash_reg + INTR_STATUS3);
+       for (i = 0; i < denali->max_banks; ++i)
+               iowrite32(0xFFFF, denali->flash_reg + INTR_STATUS(i));
 
        denali_irq_enable(denali, int_mask);
 }
@@ -604,10 +588,10 @@ static void denali_irq_cleanup(int irqnum, struct denali_nand_info *denali)
 static void denali_irq_enable(struct denali_nand_info *denali,
                                                        uint32_t int_mask)
 {
-       iowrite32(int_mask, denali->flash_reg + INTR_EN0);
-       iowrite32(int_mask, denali->flash_reg + INTR_EN1);
-       iowrite32(int_mask, denali->flash_reg + INTR_EN2);
-       iowrite32(int_mask, denali->flash_reg + INTR_EN3);
+       int i;
+
+       for (i = 0; i < denali->max_banks; ++i)
+               iowrite32(int_mask, denali->flash_reg + INTR_EN(i));
 }
 
 /* This function only returns when an interrupt that this driver cares about
@@ -624,7 +608,7 @@ static inline void clear_interrupt(struct denali_nand_info *denali,
 {
        uint32_t intr_status_reg = 0;
 
-       intr_status_reg = intr_status_addresses[denali->flash_bank];
+       intr_status_reg = INTR_STATUS(denali->flash_bank);
 
        iowrite32(irq_mask, denali->flash_reg + intr_status_reg);
 }
@@ -645,7 +629,7 @@ static uint32_t read_interrupt_status(struct denali_nand_info *denali)
 {
        uint32_t intr_status_reg = 0;
 
-       intr_status_reg = intr_status_addresses[denali->flash_bank];
+       intr_status_reg = INTR_STATUS(denali->flash_bank);
 
        return ioread32(denali->flash_reg + intr_status_reg);
 }
@@ -754,7 +738,7 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali,
                 irq_mask = 0;
 
        if (op == DENALI_READ)
-               irq_mask = INTR_STATUS0__LOAD_COMP;
+               irq_mask = INTR_STATUS__LOAD_COMP;
        else if (op == DENALI_WRITE)
                irq_mask = 0;
        else
@@ -800,7 +784,7 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali,
                        irq_status = wait_for_irq(denali, irq_mask);
 
                        if (irq_status == 0) {
-                               dev_err(&denali->dev->dev,
+                               dev_err(denali->dev,
                                                "cmd, page, addr on timeout "
                                                "(0x%x, 0x%x, 0x%x)\n",
                                                cmd, denali->page, addr);
@@ -861,8 +845,8 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
        uint32_t irq_status = 0;
-       uint32_t irq_mask = INTR_STATUS0__PROGRAM_COMP |
-                                               INTR_STATUS0__PROGRAM_FAIL;
+       uint32_t irq_mask = INTR_STATUS__PROGRAM_COMP |
+                                               INTR_STATUS__PROGRAM_FAIL;
        int status = 0;
 
        denali->page = page;
@@ -875,11 +859,11 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
                irq_status = wait_for_irq(denali, irq_mask);
 
                if (irq_status == 0) {
-                       dev_err(&denali->dev->dev, "OOB write failed\n");
+                       dev_err(denali->dev, "OOB write failed\n");
                        status = -EIO;
                }
        } else {
-               dev_err(&denali->dev->dev, "unable to send pipeline command\n");
+               dev_err(denali->dev, "unable to send pipeline command\n");
                status = -EIO;
        }
        return status;
@@ -889,7 +873,7 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
 static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
-       uint32_t irq_mask = INTR_STATUS0__LOAD_COMP,
+       uint32_t irq_mask = INTR_STATUS__LOAD_COMP,
                         irq_status = 0, addr = 0x0, cmd = 0x0;
 
        denali->page = page;
@@ -904,7 +888,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
                irq_status = wait_for_irq(denali, irq_mask);
 
                if (irq_status == 0)
-                       dev_err(&denali->dev->dev, "page on OOB timeout %d\n",
+                       dev_err(denali->dev, "page on OOB timeout %d\n",
                                        denali->page);
 
                /* We set the device back to MAIN_ACCESS here as I observed
@@ -944,7 +928,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
 {
        bool check_erased_page = false;
 
-       if (irq_status & INTR_STATUS0__ECC_ERR) {
+       if (irq_status & INTR_STATUS__ECC_ERR) {
                /* read the ECC errors. we'll ignore them for now */
                uint32_t err_address = 0, err_correction_info = 0;
                uint32_t err_byte = 0, err_sector = 0, err_device = 0;
@@ -995,7 +979,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
                 * for a while for this interrupt
                 * */
                while (!(read_interrupt_status(denali) &
-                               INTR_STATUS0__ECC_TRANSACTION_DONE))
+                               INTR_STATUS__ECC_TRANSACTION_DONE))
                        cpu_relax();
                clear_interrupts(denali);
                denali_set_intr_modes(denali, true);
@@ -1045,14 +1029,13 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *chip,
                        const uint8_t *buf, bool raw_xfer)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
-       struct pci_dev *pci_dev = denali->dev;
 
        dma_addr_t addr = denali->buf.dma_buf;
        size_t size = denali->mtd.writesize + denali->mtd.oobsize;
 
        uint32_t irq_status = 0;
-       uint32_t irq_mask = INTR_STATUS0__DMA_CMD_COMP |
-                                               INTR_STATUS0__PROGRAM_FAIL;
+       uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP |
+                                               INTR_STATUS__PROGRAM_FAIL;
 
        /* if it is a raw xfer, we want to disable ecc, and send
         * the spare area.
@@ -1071,7 +1054,7 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *chip,
                        mtd->oobsize);
        }
 
-       pci_dma_sync_single_for_device(pci_dev, addr, size, PCI_DMA_TODEVICE);
+       dma_sync_single_for_device(denali->dev, addr, size, DMA_TO_DEVICE);
 
        clear_interrupts(denali);
        denali_enable_dma(denali, true);
@@ -1082,16 +1065,16 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *chip,
        irq_status = wait_for_irq(denali, irq_mask);
 
        if (irq_status == 0) {
-               dev_err(&denali->dev->dev,
+               dev_err(denali->dev,
                                "timeout on write_page (type = %d)\n",
                                raw_xfer);
                denali->status =
-                       (irq_status & INTR_STATUS0__PROGRAM_FAIL) ?
+                       (irq_status & INTR_STATUS__PROGRAM_FAIL) ?
                        NAND_STATUS_FAIL : PASS;
        }
 
        denali_enable_dma(denali, false);
-       pci_dma_sync_single_for_cpu(pci_dev, addr, size, PCI_DMA_TODEVICE);
+       dma_sync_single_for_cpu(denali->dev, addr, size, DMA_TO_DEVICE);
 }
 
 /* NAND core entry points */
@@ -1139,18 +1122,17 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
                            uint8_t *buf, int page)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
-       struct pci_dev *pci_dev = denali->dev;
 
        dma_addr_t addr = denali->buf.dma_buf;
        size_t size = denali->mtd.writesize + denali->mtd.oobsize;
 
        uint32_t irq_status = 0;
-       uint32_t irq_mask = INTR_STATUS0__ECC_TRANSACTION_DONE |
-                           INTR_STATUS0__ECC_ERR;
+       uint32_t irq_mask = INTR_STATUS__ECC_TRANSACTION_DONE |
+                           INTR_STATUS__ECC_ERR;
        bool check_erased_page = false;
 
        if (page != denali->page) {
-               dev_err(&denali->dev->dev, "IN %s: page %d is not"
+               dev_err(denali->dev, "IN %s: page %d is not"
                                " equal to denali->page %d, investigate!!",
                                __func__, page, denali->page);
                BUG();
@@ -1159,7 +1141,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
        setup_ecc_for_xfer(denali, true, false);
 
        denali_enable_dma(denali, true);
-       pci_dma_sync_single_for_device(pci_dev, addr, size, PCI_DMA_FROMDEVICE);
+       dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE);
 
        clear_interrupts(denali);
        denali_setup_dma(denali, DENALI_READ);
@@ -1167,7 +1149,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
        /* wait for operation to complete */
        irq_status = wait_for_irq(denali, irq_mask);
 
-       pci_dma_sync_single_for_cpu(pci_dev, addr, size, PCI_DMA_FROMDEVICE);
+       dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE);
 
        memcpy(buf, denali->buf.buf, mtd->writesize);
 
@@ -1192,16 +1174,15 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
                                uint8_t *buf, int page)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
-       struct pci_dev *pci_dev = denali->dev;
 
        dma_addr_t addr = denali->buf.dma_buf;
        size_t size = denali->mtd.writesize + denali->mtd.oobsize;
 
        uint32_t irq_status = 0;
-       uint32_t irq_mask = INTR_STATUS0__DMA_CMD_COMP;
+       uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP;
 
        if (page != denali->page) {
-               dev_err(&denali->dev->dev, "IN %s: page %d is not"
+               dev_err(denali->dev, "IN %s: page %d is not"
                                " equal to denali->page %d, investigate!!",
                                __func__, page, denali->page);
                BUG();
@@ -1210,7 +1191,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
        setup_ecc_for_xfer(denali, false, true);
        denali_enable_dma(denali, true);
 
-       pci_dma_sync_single_for_device(pci_dev, addr, size, PCI_DMA_FROMDEVICE);
+       dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE);
 
        clear_interrupts(denali);
        denali_setup_dma(denali, DENALI_READ);
@@ -1218,7 +1199,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
        /* wait for operation to complete */
        irq_status = wait_for_irq(denali, irq_mask);
 
-       pci_dma_sync_single_for_cpu(pci_dev, addr, size, PCI_DMA_FROMDEVICE);
+       dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE);
 
        denali_enable_dma(denali, false);
 
@@ -1271,10 +1252,10 @@ static void denali_erase(struct mtd_info *mtd, int page)
        index_addr(denali, (uint32_t)cmd, 0x1);
 
        /* wait for erase to complete or failure to occur */
-       irq_status = wait_for_irq(denali, INTR_STATUS0__ERASE_COMP |
-                                       INTR_STATUS0__ERASE_FAIL);
+       irq_status = wait_for_irq(denali, INTR_STATUS__ERASE_COMP |
+                                       INTR_STATUS__ERASE_FAIL);
 
-       denali->status = (irq_status & INTR_STATUS0__ERASE_FAIL) ?
+       denali->status = (irq_status & INTR_STATUS__ERASE_FAIL) ?
                                                NAND_STATUS_FAIL : PASS;
 }
 
@@ -1330,7 +1311,7 @@ static int denali_ecc_calculate(struct mtd_info *mtd, const uint8_t *data,
                                uint8_t *ecc_code)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
-       dev_err(&denali->dev->dev,
+       dev_err(denali->dev,
                        "denali_ecc_calculate called unexpectedly\n");
        BUG();
        return -EIO;
@@ -1340,7 +1321,7 @@ static int denali_ecc_correct(struct mtd_info *mtd, uint8_t *data,
                                uint8_t *read_ecc, uint8_t *calc_ecc)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
-       dev_err(&denali->dev->dev,
+       dev_err(denali->dev,
                        "denali_ecc_correct called unexpectedly\n");
        BUG();
        return -EIO;
@@ -1349,7 +1330,7 @@ static int denali_ecc_correct(struct mtd_info *mtd, uint8_t *data,
 static void denali_ecc_hwctl(struct mtd_info *mtd, int mode)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
-       dev_err(&denali->dev->dev,
+       dev_err(denali->dev,
                        "denali_ecc_hwctl called unexpectedly\n");
        BUG();
 }
@@ -1375,6 +1356,7 @@ static void denali_hw_init(struct denali_nand_info *denali)
        /* Should set value for these registers when init */
        iowrite32(0, denali->flash_reg + TWO_ROW_ADDR_CYCLES);
        iowrite32(1, denali->flash_reg + ECC_ENABLE);
+       detect_max_banks(denali);
        denali_nand_timing_set(denali);
        denali_irq_init(denali);
 }
@@ -1484,24 +1466,22 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        }
 
        /* Is 32-bit DMA supported? */
-       ret = pci_set_dma_mask(dev, DMA_BIT_MASK(32));
-
+       ret = dma_set_mask(&dev->dev, DMA_BIT_MASK(32));
        if (ret) {
                printk(KERN_ERR "Spectra: no usable DMA configuration\n");
                goto failed_enable_dev;
        }
-       denali->buf.dma_buf =
-               pci_map_single(dev, denali->buf.buf,
-                                               DENALI_BUF_SIZE,
-                                               PCI_DMA_BIDIRECTIONAL);
+       denali->buf.dma_buf = dma_map_single(&dev->dev, denali->buf.buf,
+                                            DENALI_BUF_SIZE,
+                                            DMA_BIDIRECTIONAL);
 
-       if (pci_dma_mapping_error(dev, denali->buf.dma_buf)) {
+       if (dma_mapping_error(&dev->dev, denali->buf.dma_buf)) {
                dev_err(&dev->dev, "Spectra: failed to map DMA buffer\n");
                goto failed_enable_dev;
        }
 
        pci_set_master(dev);
-       denali->dev = dev;
+       denali->dev = &dev->dev;
        denali->mtd.dev.parent = &dev->dev;
 
        ret = pci_request_regions(dev, DENALI_NAND_NAME);
@@ -1554,7 +1534,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        /* scan for NAND devices attached to the controller
         * this is the first stage in a two step process to register
         * with the nand subsystem */
-       if (nand_scan_ident(&denali->mtd, LLD_MAX_FLASH_BANKS, NULL)) {
+       if (nand_scan_ident(&denali->mtd, denali->max_banks, NULL)) {
                ret = -ENXIO;
                goto failed_req_irq;
        }
@@ -1664,7 +1644,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
                goto failed_req_irq;
        }
 
-       ret = add_mtd_device(&denali->mtd);
+       ret = mtd_device_register(&denali->mtd, NULL, 0);
        if (ret) {
                dev_err(&dev->dev, "Spectra: Failed to register MTD: %d\n",
                                ret);
@@ -1681,8 +1661,8 @@ failed_remap_reg:
 failed_req_regions:
        pci_release_regions(dev);
 failed_dma_map:
-       pci_unmap_single(dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
-                                                       PCI_DMA_BIDIRECTIONAL);
+       dma_unmap_single(&dev->dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
+                        DMA_BIDIRECTIONAL);
 failed_enable_dev:
        pci_disable_device(dev);
 failed_alloc_memery:
@@ -1696,7 +1676,7 @@ static void denali_pci_remove(struct pci_dev *dev)
        struct denali_nand_info *denali = pci_get_drvdata(dev);
 
        nand_release(&denali->mtd);
-       del_mtd_device(&denali->mtd);
+       mtd_device_unregister(&denali->mtd);
 
        denali_irq_cleanup(dev->irq, denali);
 
@@ -1704,8 +1684,8 @@ static void denali_pci_remove(struct pci_dev *dev)
        iounmap(denali->flash_mem);
        pci_release_regions(dev);
        pci_disable_device(dev);
-       pci_unmap_single(dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
-                                                       PCI_DMA_BIDIRECTIONAL);
+       dma_unmap_single(&dev->dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
+                        DMA_BIDIRECTIONAL);
        pci_set_drvdata(dev, NULL);
        kfree(denali);
 }
@@ -1721,8 +1701,7 @@ static struct pci_driver denali_pci_driver = {
 
 static int __devinit denali_init(void)
 {
-       printk(KERN_INFO "Spectra MTD driver built on %s @ %s\n",
-                       __DATE__, __TIME__);
+       printk(KERN_INFO "Spectra MTD driver\n");
        return pci_register_driver(&denali_pci_driver);
 }
 
index 3918bcb1561e4d7d474d27bfb6624eed6b7b36f9..fabb9d56b39e0d7adf14337abcd5c448320610dd 100644 (file)
 #define TRANSFER_MODE                          0x400
 #define     TRANSFER_MODE__VALUE                       0x0003
 
-#define INTR_STATUS0                           0x410
-#define     INTR_STATUS0__ECC_TRANSACTION_DONE         0x0001
-#define     INTR_STATUS0__ECC_ERR                      0x0002
-#define     INTR_STATUS0__DMA_CMD_COMP                 0x0004
-#define     INTR_STATUS0__TIME_OUT                     0x0008
-#define     INTR_STATUS0__PROGRAM_FAIL                 0x0010
-#define     INTR_STATUS0__ERASE_FAIL                   0x0020
-#define     INTR_STATUS0__LOAD_COMP                    0x0040
-#define     INTR_STATUS0__PROGRAM_COMP                 0x0080
-#define     INTR_STATUS0__ERASE_COMP                   0x0100
-#define     INTR_STATUS0__PIPE_CPYBCK_CMD_COMP         0x0200
-#define     INTR_STATUS0__LOCKED_BLK                   0x0400
-#define     INTR_STATUS0__UNSUP_CMD                    0x0800
-#define     INTR_STATUS0__INT_ACT                      0x1000
-#define     INTR_STATUS0__RST_COMP                     0x2000
-#define     INTR_STATUS0__PIPE_CMD_ERR                 0x4000
-#define     INTR_STATUS0__PAGE_XFER_INC                        0x8000
-
-#define INTR_EN0                                       0x420
-#define     INTR_EN0__ECC_TRANSACTION_DONE             0x0001
-#define     INTR_EN0__ECC_ERR                          0x0002
-#define     INTR_EN0__DMA_CMD_COMP                     0x0004
-#define     INTR_EN0__TIME_OUT                         0x0008
-#define     INTR_EN0__PROGRAM_FAIL                     0x0010
-#define     INTR_EN0__ERASE_FAIL                       0x0020
-#define     INTR_EN0__LOAD_COMP                                0x0040
-#define     INTR_EN0__PROGRAM_COMP                     0x0080
-#define     INTR_EN0__ERASE_COMP                       0x0100
-#define     INTR_EN0__PIPE_CPYBCK_CMD_COMP             0x0200
-#define     INTR_EN0__LOCKED_BLK                       0x0400
-#define     INTR_EN0__UNSUP_CMD                                0x0800
-#define     INTR_EN0__INT_ACT                          0x1000
-#define     INTR_EN0__RST_COMP                         0x2000
-#define     INTR_EN0__PIPE_CMD_ERR                     0x4000
-#define     INTR_EN0__PAGE_XFER_INC                    0x8000
-
-#define PAGE_CNT0                              0x430
-#define     PAGE_CNT0__VALUE                           0x00ff
-
-#define ERR_PAGE_ADDR0                         0x440
-#define     ERR_PAGE_ADDR0__VALUE                      0xffff
-
-#define ERR_BLOCK_ADDR0                                0x450
-#define     ERR_BLOCK_ADDR0__VALUE                     0xffff
-
-#define INTR_STATUS1                           0x460
-#define     INTR_STATUS1__ECC_TRANSACTION_DONE         0x0001
-#define     INTR_STATUS1__ECC_ERR                      0x0002
-#define     INTR_STATUS1__DMA_CMD_COMP                 0x0004
-#define     INTR_STATUS1__TIME_OUT                     0x0008
-#define     INTR_STATUS1__PROGRAM_FAIL                 0x0010
-#define     INTR_STATUS1__ERASE_FAIL                   0x0020
-#define     INTR_STATUS1__LOAD_COMP                    0x0040
-#define     INTR_STATUS1__PROGRAM_COMP                 0x0080
-#define     INTR_STATUS1__ERASE_COMP                   0x0100
-#define     INTR_STATUS1__PIPE_CPYBCK_CMD_COMP         0x0200
-#define     INTR_STATUS1__LOCKED_BLK                   0x0400
-#define     INTR_STATUS1__UNSUP_CMD                    0x0800
-#define     INTR_STATUS1__INT_ACT                      0x1000
-#define     INTR_STATUS1__RST_COMP                     0x2000
-#define     INTR_STATUS1__PIPE_CMD_ERR                 0x4000
-#define     INTR_STATUS1__PAGE_XFER_INC                        0x8000
-
-#define INTR_EN1                                       0x470
-#define     INTR_EN1__ECC_TRANSACTION_DONE             0x0001
-#define     INTR_EN1__ECC_ERR                          0x0002
-#define     INTR_EN1__DMA_CMD_COMP                     0x0004
-#define     INTR_EN1__TIME_OUT                         0x0008
-#define     INTR_EN1__PROGRAM_FAIL                     0x0010
-#define     INTR_EN1__ERASE_FAIL                       0x0020
-#define     INTR_EN1__LOAD_COMP                                0x0040
-#define     INTR_EN1__PROGRAM_COMP                     0x0080
-#define     INTR_EN1__ERASE_COMP                       0x0100
-#define     INTR_EN1__PIPE_CPYBCK_CMD_COMP             0x0200
-#define     INTR_EN1__LOCKED_BLK                       0x0400
-#define     INTR_EN1__UNSUP_CMD                                0x0800
-#define     INTR_EN1__INT_ACT                          0x1000
-#define     INTR_EN1__RST_COMP                         0x2000
-#define     INTR_EN1__PIPE_CMD_ERR                     0x4000
-#define     INTR_EN1__PAGE_XFER_INC                    0x8000
-
-#define PAGE_CNT1                              0x480
-#define     PAGE_CNT1__VALUE                           0x00ff
-
-#define ERR_PAGE_ADDR1                         0x490
-#define     ERR_PAGE_ADDR1__VALUE                      0xffff
-
-#define ERR_BLOCK_ADDR1                                0x4a0
-#define     ERR_BLOCK_ADDR1__VALUE                     0xffff
-
-#define INTR_STATUS2                           0x4b0
-#define     INTR_STATUS2__ECC_TRANSACTION_DONE         0x0001
-#define     INTR_STATUS2__ECC_ERR                      0x0002
-#define     INTR_STATUS2__DMA_CMD_COMP                 0x0004
-#define     INTR_STATUS2__TIME_OUT                     0x0008
-#define     INTR_STATUS2__PROGRAM_FAIL                 0x0010
-#define     INTR_STATUS2__ERASE_FAIL                   0x0020
-#define     INTR_STATUS2__LOAD_COMP                    0x0040
-#define     INTR_STATUS2__PROGRAM_COMP                 0x0080
-#define     INTR_STATUS2__ERASE_COMP                   0x0100
-#define     INTR_STATUS2__PIPE_CPYBCK_CMD_COMP         0x0200
-#define     INTR_STATUS2__LOCKED_BLK                   0x0400
-#define     INTR_STATUS2__UNSUP_CMD                    0x0800
-#define     INTR_STATUS2__INT_ACT                      0x1000
-#define     INTR_STATUS2__RST_COMP                     0x2000
-#define     INTR_STATUS2__PIPE_CMD_ERR                 0x4000
-#define     INTR_STATUS2__PAGE_XFER_INC                        0x8000
-
-#define INTR_EN2                                       0x4c0
-#define     INTR_EN2__ECC_TRANSACTION_DONE             0x0001
-#define     INTR_EN2__ECC_ERR                          0x0002
-#define     INTR_EN2__DMA_CMD_COMP                     0x0004
-#define     INTR_EN2__TIME_OUT                         0x0008
-#define     INTR_EN2__PROGRAM_FAIL                     0x0010
-#define     INTR_EN2__ERASE_FAIL                       0x0020
-#define     INTR_EN2__LOAD_COMP                                0x0040
-#define     INTR_EN2__PROGRAM_COMP                     0x0080
-#define     INTR_EN2__ERASE_COMP                       0x0100
-#define     INTR_EN2__PIPE_CPYBCK_CMD_COMP             0x0200
-#define     INTR_EN2__LOCKED_BLK                       0x0400
-#define     INTR_EN2__UNSUP_CMD                                0x0800
-#define     INTR_EN2__INT_ACT                          0x1000
-#define     INTR_EN2__RST_COMP                         0x2000
-#define     INTR_EN2__PIPE_CMD_ERR                     0x4000
-#define     INTR_EN2__PAGE_XFER_INC                    0x8000
-
-#define PAGE_CNT2                              0x4d0
-#define     PAGE_CNT2__VALUE                           0x00ff
-
-#define ERR_PAGE_ADDR2                         0x4e0
-#define     ERR_PAGE_ADDR2__VALUE                      0xffff
-
-#define ERR_BLOCK_ADDR2                                0x4f0
-#define     ERR_BLOCK_ADDR2__VALUE                     0xffff
-
-#define INTR_STATUS3                           0x500
-#define     INTR_STATUS3__ECC_TRANSACTION_DONE         0x0001
-#define     INTR_STATUS3__ECC_ERR                      0x0002
-#define     INTR_STATUS3__DMA_CMD_COMP                 0x0004
-#define     INTR_STATUS3__TIME_OUT                     0x0008
-#define     INTR_STATUS3__PROGRAM_FAIL                 0x0010
-#define     INTR_STATUS3__ERASE_FAIL                   0x0020
-#define     INTR_STATUS3__LOAD_COMP                    0x0040
-#define     INTR_STATUS3__PROGRAM_COMP                 0x0080
-#define     INTR_STATUS3__ERASE_COMP                   0x0100
-#define     INTR_STATUS3__PIPE_CPYBCK_CMD_COMP         0x0200
-#define     INTR_STATUS3__LOCKED_BLK                   0x0400
-#define     INTR_STATUS3__UNSUP_CMD                    0x0800
-#define     INTR_STATUS3__INT_ACT                      0x1000
-#define     INTR_STATUS3__RST_COMP                     0x2000
-#define     INTR_STATUS3__PIPE_CMD_ERR                 0x4000
-#define     INTR_STATUS3__PAGE_XFER_INC                        0x8000
-
-#define INTR_EN3                                       0x510
-#define     INTR_EN3__ECC_TRANSACTION_DONE             0x0001
-#define     INTR_EN3__ECC_ERR                          0x0002
-#define     INTR_EN3__DMA_CMD_COMP                     0x0004
-#define     INTR_EN3__TIME_OUT                         0x0008
-#define     INTR_EN3__PROGRAM_FAIL                     0x0010
-#define     INTR_EN3__ERASE_FAIL                       0x0020
-#define     INTR_EN3__LOAD_COMP                                0x0040
-#define     INTR_EN3__PROGRAM_COMP                     0x0080
-#define     INTR_EN3__ERASE_COMP                       0x0100
-#define     INTR_EN3__PIPE_CPYBCK_CMD_COMP             0x0200
-#define     INTR_EN3__LOCKED_BLK                       0x0400
-#define     INTR_EN3__UNSUP_CMD                                0x0800
-#define     INTR_EN3__INT_ACT                          0x1000
-#define     INTR_EN3__RST_COMP                         0x2000
-#define     INTR_EN3__PIPE_CMD_ERR                     0x4000
-#define     INTR_EN3__PAGE_XFER_INC                    0x8000
-
-#define PAGE_CNT3                              0x520
-#define     PAGE_CNT3__VALUE                           0x00ff
-
-#define ERR_PAGE_ADDR3                         0x530
-#define     ERR_PAGE_ADDR3__VALUE                      0xffff
-
-#define ERR_BLOCK_ADDR3                                0x540
-#define     ERR_BLOCK_ADDR3__VALUE                     0xffff
+#define INTR_STATUS(__bank)    (0x410 + ((__bank) * 0x50))
+#define INTR_EN(__bank)                (0x420 + ((__bank) * 0x50))
+
+#define     INTR_STATUS__ECC_TRANSACTION_DONE          0x0001
+#define     INTR_STATUS__ECC_ERR                       0x0002
+#define     INTR_STATUS__DMA_CMD_COMP                  0x0004
+#define     INTR_STATUS__TIME_OUT                      0x0008
+#define     INTR_STATUS__PROGRAM_FAIL                  0x0010
+#define     INTR_STATUS__ERASE_FAIL                    0x0020
+#define     INTR_STATUS__LOAD_COMP                     0x0040
+#define     INTR_STATUS__PROGRAM_COMP                  0x0080
+#define     INTR_STATUS__ERASE_COMP                    0x0100
+#define     INTR_STATUS__PIPE_CPYBCK_CMD_COMP          0x0200
+#define     INTR_STATUS__LOCKED_BLK                    0x0400
+#define     INTR_STATUS__UNSUP_CMD                     0x0800
+#define     INTR_STATUS__INT_ACT                       0x1000
+#define     INTR_STATUS__RST_COMP                      0x2000
+#define     INTR_STATUS__PIPE_CMD_ERR                  0x4000
+#define     INTR_STATUS__PAGE_XFER_INC                 0x8000
+
+#define     INTR_EN__ECC_TRANSACTION_DONE              0x0001
+#define     INTR_EN__ECC_ERR                           0x0002
+#define     INTR_EN__DMA_CMD_COMP                      0x0004
+#define     INTR_EN__TIME_OUT                          0x0008
+#define     INTR_EN__PROGRAM_FAIL                      0x0010
+#define     INTR_EN__ERASE_FAIL                                0x0020
+#define     INTR_EN__LOAD_COMP                         0x0040
+#define     INTR_EN__PROGRAM_COMP                      0x0080
+#define     INTR_EN__ERASE_COMP                                0x0100
+#define     INTR_EN__PIPE_CPYBCK_CMD_COMP              0x0200
+#define     INTR_EN__LOCKED_BLK                                0x0400
+#define     INTR_EN__UNSUP_CMD                         0x0800
+#define     INTR_EN__INT_ACT                           0x1000
+#define     INTR_EN__RST_COMP                          0x2000
+#define     INTR_EN__PIPE_CMD_ERR                      0x4000
+#define     INTR_EN__PAGE_XFER_INC                     0x8000
+
+#define PAGE_CNT(__bank)       (0x430 + ((__bank) * 0x50))
+#define ERR_PAGE_ADDR(__bank)  (0x440 + ((__bank) * 0x50))
+#define ERR_BLOCK_ADDR(__bank) (0x450 + ((__bank) * 0x50))
 
 #define DATA_INTR                              0x550
 #define     DATA_INTR__WRITE_SPACE_AV                  0x0001
 #define     PTN_INTR_EN__ACCESS_ERROR_BANK3            0x0010
 #define     PTN_INTR_EN__REG_ACCESS_ERROR              0x0020
 
-#define PERM_SRC_ID_0                          0x830
-#define     PERM_SRC_ID_0__SRCID                       0x00ff
-#define     PERM_SRC_ID_0__DIRECT_ACCESS_ACTIVE                0x0800
-#define     PERM_SRC_ID_0__WRITE_ACTIVE                        0x2000
-#define     PERM_SRC_ID_0__READ_ACTIVE                 0x4000
-#define     PERM_SRC_ID_0__PARTITION_VALID             0x8000
-
-#define MIN_BLK_ADDR_0                         0x840
-#define     MIN_BLK_ADDR_0__VALUE                      0xffff
-
-#define MAX_BLK_ADDR_0                         0x850
-#define     MAX_BLK_ADDR_0__VALUE                      0xffff
-
-#define MIN_MAX_BANK_0                         0x860
-#define     MIN_MAX_BANK_0__MIN_VALUE                  0x0003
-#define     MIN_MAX_BANK_0__MAX_VALUE                  0x000c
-
-#define PERM_SRC_ID_1                          0x870
-#define     PERM_SRC_ID_1__SRCID                       0x00ff
-#define     PERM_SRC_ID_1__DIRECT_ACCESS_ACTIVE                0x0800
-#define     PERM_SRC_ID_1__WRITE_ACTIVE                        0x2000
-#define     PERM_SRC_ID_1__READ_ACTIVE                 0x4000
-#define     PERM_SRC_ID_1__PARTITION_VALID             0x8000
-
-#define MIN_BLK_ADDR_1                         0x880
-#define     MIN_BLK_ADDR_1__VALUE                      0xffff
-
-#define MAX_BLK_ADDR_1                         0x890
-#define     MAX_BLK_ADDR_1__VALUE                      0xffff
-
-#define MIN_MAX_BANK_1                         0x8a0
-#define     MIN_MAX_BANK_1__MIN_VALUE                  0x0003
-#define     MIN_MAX_BANK_1__MAX_VALUE                  0x000c
-
-#define PERM_SRC_ID_2                          0x8b0
-#define     PERM_SRC_ID_2__SRCID                       0x00ff
-#define     PERM_SRC_ID_2__DIRECT_ACCESS_ACTIVE                0x0800
-#define     PERM_SRC_ID_2__WRITE_ACTIVE                        0x2000
-#define     PERM_SRC_ID_2__READ_ACTIVE                 0x4000
-#define     PERM_SRC_ID_2__PARTITION_VALID             0x8000
-
-#define MIN_BLK_ADDR_2                         0x8c0
-#define     MIN_BLK_ADDR_2__VALUE                      0xffff
-
-#define MAX_BLK_ADDR_2                         0x8d0
-#define     MAX_BLK_ADDR_2__VALUE                      0xffff
-
-#define MIN_MAX_BANK_2                         0x8e0
-#define     MIN_MAX_BANK_2__MIN_VALUE                  0x0003
-#define     MIN_MAX_BANK_2__MAX_VALUE                  0x000c
-
-#define PERM_SRC_ID_3                          0x8f0
-#define     PERM_SRC_ID_3__SRCID                       0x00ff
-#define     PERM_SRC_ID_3__DIRECT_ACCESS_ACTIVE                0x0800
-#define     PERM_SRC_ID_3__WRITE_ACTIVE                        0x2000
-#define     PERM_SRC_ID_3__READ_ACTIVE                 0x4000
-#define     PERM_SRC_ID_3__PARTITION_VALID             0x8000
-
-#define MIN_BLK_ADDR_3                         0x900
-#define     MIN_BLK_ADDR_3__VALUE                      0xffff
-
-#define MAX_BLK_ADDR_3                         0x910
-#define     MAX_BLK_ADDR_3__VALUE                      0xffff
-
-#define MIN_MAX_BANK_3                         0x920
-#define     MIN_MAX_BANK_3__MIN_VALUE                  0x0003
-#define     MIN_MAX_BANK_3__MAX_VALUE                  0x000c
-
-#define PERM_SRC_ID_4                          0x930
-#define     PERM_SRC_ID_4__SRCID                       0x00ff
-#define     PERM_SRC_ID_4__DIRECT_ACCESS_ACTIVE                0x0800
-#define     PERM_SRC_ID_4__WRITE_ACTIVE                        0x2000
-#define     PERM_SRC_ID_4__READ_ACTIVE                 0x4000
-#define     PERM_SRC_ID_4__PARTITION_VALID             0x8000
-
-#define MIN_BLK_ADDR_4                         0x940
-#define     MIN_BLK_ADDR_4__VALUE                      0xffff
-
-#define MAX_BLK_ADDR_4                         0x950
-#define     MAX_BLK_ADDR_4__VALUE                      0xffff
-
-#define MIN_MAX_BANK_4                         0x960
-#define     MIN_MAX_BANK_4__MIN_VALUE                  0x0003
-#define     MIN_MAX_BANK_4__MAX_VALUE                  0x000c
-
-#define PERM_SRC_ID_5                          0x970
-#define     PERM_SRC_ID_5__SRCID                       0x00ff
-#define     PERM_SRC_ID_5__DIRECT_ACCESS_ACTIVE                0x0800
-#define     PERM_SRC_ID_5__WRITE_ACTIVE                        0x2000
-#define     PERM_SRC_ID_5__READ_ACTIVE                 0x4000
-#define     PERM_SRC_ID_5__PARTITION_VALID             0x8000
-
-#define MIN_BLK_ADDR_5                         0x980
-#define     MIN_BLK_ADDR_5__VALUE                      0xffff
-
-#define MAX_BLK_ADDR_5                         0x990
-#define     MAX_BLK_ADDR_5__VALUE                      0xffff
-
-#define MIN_MAX_BANK_5                         0x9a0
-#define     MIN_MAX_BANK_5__MIN_VALUE                  0x0003
-#define     MIN_MAX_BANK_5__MAX_VALUE                  0x000c
-
-#define PERM_SRC_ID_6                          0x9b0
-#define     PERM_SRC_ID_6__SRCID                       0x00ff
-#define     PERM_SRC_ID_6__DIRECT_ACCESS_ACTIVE                0x0800
-#define     PERM_SRC_ID_6__WRITE_ACTIVE                        0x2000
-#define     PERM_SRC_ID_6__READ_ACTIVE                 0x4000
-#define     PERM_SRC_ID_6__PARTITION_VALID             0x8000
-
-#define MIN_BLK_ADDR_6                         0x9c0
-#define     MIN_BLK_ADDR_6__VALUE                      0xffff
-
-#define MAX_BLK_ADDR_6                         0x9d0
-#define     MAX_BLK_ADDR_6__VALUE                      0xffff
-
-#define MIN_MAX_BANK_6                         0x9e0
-#define     MIN_MAX_BANK_6__MIN_VALUE                  0x0003
-#define     MIN_MAX_BANK_6__MAX_VALUE                  0x000c
-
-#define PERM_SRC_ID_7                          0x9f0
-#define     PERM_SRC_ID_7__SRCID                       0x00ff
-#define     PERM_SRC_ID_7__DIRECT_ACCESS_ACTIVE                0x0800
-#define     PERM_SRC_ID_7__WRITE_ACTIVE                        0x2000
-#define     PERM_SRC_ID_7__READ_ACTIVE                 0x4000
-#define     PERM_SRC_ID_7__PARTITION_VALID             0x8000
+#define PERM_SRC_ID(__bank)    (0x830 + ((__bank) * 0x40))
+#define     PERM_SRC_ID__SRCID                         0x00ff
+#define     PERM_SRC_ID__DIRECT_ACCESS_ACTIVE          0x0800
+#define     PERM_SRC_ID__WRITE_ACTIVE                  0x2000
+#define     PERM_SRC_ID__READ_ACTIVE                   0x4000
+#define     PERM_SRC_ID__PARTITION_VALID               0x8000
+
+#define MIN_BLK_ADDR(__bank)   (0x840 + ((__bank) * 0x40))
+#define     MIN_BLK_ADDR__VALUE                                0xffff
+
+#define MAX_BLK_ADDR(__bank)   (0x850 + ((__bank) * 0x40))
+#define     MAX_BLK_ADDR__VALUE                                0xffff
+
+#define MIN_MAX_BANK(__bank)   (0x860 + ((__bank) * 0x40))
+#define     MIN_MAX_BANK__MIN_VALUE                    0x0003
+#define     MIN_MAX_BANK__MAX_VALUE                    0x000c
 
-#define MIN_BLK_ADDR_7                         0xa00
-#define     MIN_BLK_ADDR_7__VALUE                      0xffff
-
-#define MAX_BLK_ADDR_7                         0xa10
-#define     MAX_BLK_ADDR_7__VALUE                      0xffff
-
-#define MIN_MAX_BANK_7                         0xa20
-#define     MIN_MAX_BANK_7__MIN_VALUE                  0x0003
-#define     MIN_MAX_BANK_7__MAX_VALUE                  0x000c
 
 /* ffsdefs.h */
 #define CLEAR 0                 /*use this to clear a field instead of "fail"*/
 #define READ_WRITE_ENABLE_HIGH_COUNT    22
 
 #define ECC_SECTOR_SIZE     512
-#define LLD_MAX_FLASH_BANKS     4
 
 #define DENALI_BUF_SIZE                (NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE)
 
@@ -732,7 +474,7 @@ struct denali_nand_info {
        int status;
        int platform;
        struct nand_buf buf;
-       struct pci_dev *dev;
+       struct device *dev;
        int total_used_banks;
        uint32_t block;  /* stored for future use */
        uint16_t page;
@@ -751,6 +493,7 @@ struct denali_nand_info {
        uint32_t totalblks;
        uint32_t blksperchip;
        uint32_t bbtskipbytes;
+       uint32_t max_banks;
 };
 
 #endif /*_LLD_NAND_*/
index 657b9f4b6f9ba288ad4dbd5f7f1450e440e84360..7837728d02ff4c15987d6275d593d3464b6cf073 100644 (file)
@@ -1360,11 +1360,9 @@ static int __init nftl_scan_bbt(struct mtd_info *mtd)
           At least as nand_bbt.c is currently written. */
        if ((ret = nand_scan_bbt(mtd, NULL)))
                return ret;
-       add_mtd_device(mtd);
-#ifdef CONFIG_MTD_PARTITIONS
+       mtd_device_register(mtd, NULL, 0);
        if (!no_autopart)
-               add_mtd_partitions(mtd, parts, numparts);
-#endif
+               mtd_device_register(mtd, parts, numparts);
        return 0;
 }
 
@@ -1419,11 +1417,9 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
           autopartitioning, but I want to give it more thought. */
        if (!numparts)
                return -EIO;
-       add_mtd_device(mtd);
-#ifdef CONFIG_MTD_PARTITIONS
+       mtd_device_register(mtd, NULL, 0);
        if (!no_autopart)
-               add_mtd_partitions(mtd, parts, numparts);
-#endif
+               mtd_device_register(mtd, parts, numparts);
        return 0;
 }
 
@@ -1678,9 +1674,9 @@ static int __init doc_probe(unsigned long physadr)
                /* DBB note: i believe nand_release is necessary here, as
                   buffers may have been allocated in nand_base.  Check with
                   Thomas. FIX ME! */
-               /* nand_release will call del_mtd_device, but we haven't yet
-                  added it.  This is handled without incident by
-                  del_mtd_device, as far as I can tell. */
+               /* nand_release will call mtd_device_unregister, but we
+                  haven't yet added it.  This is handled without incident by
+                  mtd_device_unregister, as far as I can tell. */
                nand_release(mtd);
                kfree(mtd);
                goto fail;
index 86366bfba9f8866d17f87585379ef84e5b749734..8400d0f6dada730b6d56463c72a8e9926a0a7663 100644 (file)
@@ -55,7 +55,6 @@ static unsigned long ep7312_fio_pbase = EP7312_FIO_PBASE;
 static void __iomem *ep7312_pxdr = (void __iomem *)EP7312_PXDR;
 static void __iomem *ep7312_pxddr = (void __iomem *)EP7312_PXDDR;
 
-#ifdef CONFIG_MTD_PARTITIONS
 /*
  * Define static partitions for flash device
  */
@@ -67,8 +66,6 @@ static struct mtd_partition partition_info[] = {
 
 #define NUM_PARTITIONS 1
 
-#endif
-
 /*
  *     hardware specific access to control-lines
  *
@@ -101,9 +98,7 @@ static int ep7312_device_ready(struct mtd_info *mtd)
        return 1;
 }
 
-#ifdef CONFIG_MTD_PARTITIONS
 const char *part_probes[] = { "cmdlinepart", NULL };
-#endif
 
 /*
  * Main initialization routine
@@ -162,14 +157,12 @@ static int __init ep7312_init(void)
                kfree(ep7312_mtd);
                return -ENXIO;
        }
-#ifdef CONFIG_MTD_PARTITIONS
        ep7312_mtd->name = "edb7312-nand";
        mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes, &mtd_parts, 0);
        if (mtd_parts_nb > 0)
                part_type = "command line";
        else
                mtd_parts_nb = 0;
-#endif
        if (mtd_parts_nb == 0) {
                mtd_parts = partition_info;
                mtd_parts_nb = NUM_PARTITIONS;
@@ -178,7 +171,7 @@ static int __init ep7312_init(void)
 
        /* Register the partitions */
        printk(KERN_NOTICE "Using %s partition definition\n", part_type);
-       add_mtd_partitions(ep7312_mtd, mtd_parts, mtd_parts_nb);
+       mtd_device_register(ep7312_mtd, mtd_parts, mtd_parts_nb);
 
        /* Return happy */
        return 0;
index 537e380b8dcb3fb3eb403a6c5c8a094016309afc..0bb254c7d2b1288b5716ca54b578438453c2ef80 100644 (file)
@@ -841,12 +841,9 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev)
        struct fsl_elbc_mtd *priv;
        struct resource res;
        struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl;
-
-#ifdef CONFIG_MTD_PARTITIONS
        static const char *part_probe_types[]
                = { "cmdlinepart", "RedBoot", NULL };
        struct mtd_partition *parts;
-#endif
        int ret;
        int bank;
        struct device *dev;
@@ -935,26 +932,19 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev)
        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, 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);
+       mtd_device_register(&priv->mtd, parts, ret);
 
        printk(KERN_INFO "eLBC NAND device at 0x%llx, bank %d\n",
               (unsigned long long)res.start, priv->bank);
index 073ee026a17c21d775d86cdfe3f66875bbefda3c..23752fd5bc590d40e7ac5fb15ad93af05d9e6882 100644 (file)
@@ -33,10 +33,7 @@ struct fsl_upm_nand {
        struct mtd_info mtd;
        struct nand_chip chip;
        int last_ctrl;
-#ifdef CONFIG_MTD_PARTITIONS
        struct mtd_partition *parts;
-#endif
-
        struct fsl_upm upm;
        uint8_t upm_addr_offset;
        uint8_t upm_cmd_offset;
@@ -161,9 +158,7 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun,
 {
        int ret;
        struct device_node *flash_np;
-#ifdef CONFIG_MTD_PARTITIONS
        static const char *part_types[] = { "cmdlinepart", NULL, };
-#endif
 
        fun->chip.IO_ADDR_R = fun->io_base;
        fun->chip.IO_ADDR_W = fun->io_base;
@@ -197,7 +192,6 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun,
        if (ret)
                goto err;
 
-#ifdef CONFIG_MTD_PARTITIONS
        ret = parse_mtd_partitions(&fun->mtd, part_types, &fun->parts, 0);
 
 #ifdef CONFIG_MTD_OF_PARTS
@@ -207,11 +201,7 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun,
                        goto err;
        }
 #endif
-       if (ret > 0)
-               ret = add_mtd_partitions(&fun->mtd, fun->parts, ret);
-       else
-#endif
-               ret = add_mtd_device(&fun->mtd);
+       ret = mtd_device_register(&fun->mtd, fun->parts, ret);
 err:
        of_node_put(flash_np);
        return ret;
index 0d45ef3883e821ba63aa29d2e189948a129cfc30..e9b275ac381ce89fd53f6d5fbb1895d205ce2462 100644 (file)
@@ -120,8 +120,6 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = {
        }
 };
 
-
-#ifdef CONFIG_MTD_PARTITIONS
 /*
  * Default partition tables to be used if the partition information not
  * provided through platform data.
@@ -182,7 +180,6 @@ static struct mtd_partition partition_info_128KB_blk[] = {
 #ifdef CONFIG_MTD_CMDLINE_PARTS
 const char *part_probes[] = { "cmdlinepart", NULL };
 #endif
-#endif
 
 /**
  * struct fsmc_nand_data - structure for FSMC NAND device state
@@ -719,7 +716,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
         * platform data,
         * default partition information present in driver.
         */
-#ifdef CONFIG_MTD_PARTITIONS
 #ifdef CONFIG_MTD_CMDLINE_PARTS
        /*
         * Check if partition info passed via command line
@@ -777,19 +773,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
        }
 #endif
 
-       if (host->partitions) {
-               ret = add_mtd_partitions(&host->mtd, host->partitions,
-                               host->nr_partitions);
-               if (ret)
-                       goto err_probe;
-       }
-#else
-       dev_info(&pdev->dev, "Registering %s as whole device\n", mtd->name);
-       if (!add_mtd_device(mtd)) {
-               ret = -ENXIO;
+       ret = mtd_device_register(&host->mtd, host->partitions,
+                                 host->nr_partitions);
+       if (ret)
                goto err_probe;
-       }
-#endif
 
        platform_set_drvdata(pdev, host);
        dev_info(&pdev->dev, "FSMC NAND driver registration successful\n");
@@ -835,11 +822,7 @@ static int fsmc_nand_remove(struct platform_device *pdev)
        platform_set_drvdata(pdev, NULL);
 
        if (host) {
-#ifdef CONFIG_MTD_PARTITIONS
-               del_mtd_partitions(&host->mtd);
-#else
-               del_mtd_device(&host->mtd);
-#endif
+               mtd_device_unregister(&host->mtd);
                clk_disable(host->clk);
                clk_put(host->clk);
 
index 0cde618bcc1e15022612ee0177e02fada244c873..2c2060b2800e38b61252a07c2c417b5069302868 100644 (file)
@@ -316,8 +316,8 @@ static int __devinit gpio_nand_probe(struct platform_device *dev)
                gpiomtd->plat.adjust_parts(&gpiomtd->plat,
                                           gpiomtd->mtd_info.size);
 
-       add_mtd_partitions(&gpiomtd->mtd_info, gpiomtd->plat.parts,
-                          gpiomtd->plat.num_parts);
+       mtd_device_register(&gpiomtd->mtd_info, gpiomtd->plat.parts,
+                           gpiomtd->plat.num_parts);
        platform_set_drvdata(dev, gpiomtd);
 
        return 0;
index f8ce79b446ed8278a20bab97ec1160eca2f2b52d..02a03e67109c90ce2534757b4053ada8e8469956 100644 (file)
@@ -38,7 +38,6 @@ static struct mtd_info *h1910_nand_mtd = NULL;
  * Module stuff
  */
 
-#ifdef CONFIG_MTD_PARTITIONS
 /*
  * Define static partitions for flash device
  */
@@ -50,8 +49,6 @@ static struct mtd_partition partition_info[] = {
 
 #define NUM_PARTITIONS 1
 
-#endif
-
 /*
  *     hardware specific access to control-lines
  *
@@ -154,7 +151,7 @@ static int __init h1910_init(void)
 
        /* Register the partitions */
        printk(KERN_NOTICE "Using %s partition definition\n", part_type);
-       add_mtd_partitions(h1910_nand_mtd, mtd_parts, mtd_parts_nb);
+       mtd_device_register(h1910_nand_mtd, mtd_parts, mtd_parts_nb);
 
        /* Return happy */
        return 0;
index cea38a5d4ac52ba51eba9b550be9fcc5e20604ef..6e813daed068d359f66f3c2ffb65abf46d924a44 100644 (file)
@@ -299,10 +299,8 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
        struct nand_chip *chip;
        struct mtd_info *mtd;
        struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
-#ifdef CONFIG_MTD_PARTITIONS
        struct mtd_partition *partition_info;
        int num_partitions = 0;
-#endif
 
        nand = kzalloc(sizeof(*nand), GFP_KERNEL);
        if (!nand) {
@@ -375,7 +373,6 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
                goto err_gpio_free;
        }
 
-#ifdef CONFIG_MTD_PARTITIONS
 #ifdef CONFIG_MTD_CMDLINE_PARTS
        num_partitions = parse_mtd_partitions(mtd, part_probes,
                                                &partition_info, 0);
@@ -384,12 +381,7 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
                num_partitions = pdata->num_partitions;
                partition_info = pdata->partitions;
        }
-
-       if (num_partitions > 0)
-               ret = add_mtd_partitions(mtd, partition_info, num_partitions);
-       else
-#endif
-       ret = add_mtd_device(mtd);
+       ret = mtd_device_register(mtd, partition_info, num_partitions);
 
        if (ret) {
                dev_err(&pdev->dev, "Failed to add mtd device\n");
index 0b81b5b499d1b434c2c09f02a22ec39887543668..2f7c930872f9b5715bcd0313e0251f93010ef3a6 100644 (file)
@@ -131,9 +131,7 @@ struct mpc5121_nfc_prv {
 
 static void mpc5121_nfc_done(struct mtd_info *mtd);
 
-#ifdef CONFIG_MTD_PARTITIONS
 static const char *mpc5121_nfc_pprobes[] = { "cmdlinepart", NULL };
-#endif
 
 /* Read NFC register */
 static inline u16 nfc_read(struct mtd_info *mtd, uint reg)
@@ -658,9 +656,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op)
        struct mpc5121_nfc_prv *prv;
        struct resource res;
        struct mtd_info *mtd;
-#ifdef CONFIG_MTD_PARTITIONS
        struct mtd_partition *parts;
-#endif
        struct nand_chip *chip;
        unsigned long regs_paddr, regs_size;
        const __be32 *chips_no;
@@ -841,7 +837,6 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op)
        dev_set_drvdata(dev, mtd);
 
        /* Register device in MTD */
-#ifdef CONFIG_MTD_PARTITIONS
        retval = parse_mtd_partitions(mtd, mpc5121_nfc_pprobes, &parts, 0);
 #ifdef CONFIG_MTD_OF_PARTS
        if (retval == 0)
@@ -854,12 +849,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op)
                goto error;
        }
 
-       if (retval > 0)
-               retval = add_mtd_partitions(mtd, parts, retval);
-       else
-#endif
-               retval = add_mtd_device(mtd);
-
+       retval = mtd_device_register(mtd, parts, retval);
        if (retval) {
                dev_err(dev, "Error adding MTD device!\n");
                devm_free_irq(dev, prv->irq, mtd);
index 42a95fb415047d37ed15e7b1df5a989cbd9af017..90df34c4d26cae887454de88099fa6c672c6b88d 100644 (file)
 #define NFC_V1_V2_WRPROT               (host->regs + 0x12)
 #define NFC_V1_UNLOCKSTART_BLKADDR     (host->regs + 0x14)
 #define NFC_V1_UNLOCKEND_BLKADDR       (host->regs + 0x16)
-#define NFC_V21_UNLOCKSTART_BLKADDR    (host->regs + 0x20)
-#define NFC_V21_UNLOCKEND_BLKADDR      (host->regs + 0x22)
+#define NFC_V21_UNLOCKSTART_BLKADDR0   (host->regs + 0x20)
+#define NFC_V21_UNLOCKSTART_BLKADDR1   (host->regs + 0x24)
+#define NFC_V21_UNLOCKSTART_BLKADDR2   (host->regs + 0x28)
+#define NFC_V21_UNLOCKSTART_BLKADDR3   (host->regs + 0x2c)
+#define NFC_V21_UNLOCKEND_BLKADDR0     (host->regs + 0x22)
+#define NFC_V21_UNLOCKEND_BLKADDR1     (host->regs + 0x26)
+#define NFC_V21_UNLOCKEND_BLKADDR2     (host->regs + 0x2a)
+#define NFC_V21_UNLOCKEND_BLKADDR3     (host->regs + 0x2e)
 #define NFC_V1_V2_NF_WRPRST            (host->regs + 0x18)
 #define NFC_V1_V2_CONFIG1              (host->regs + 0x1a)
 #define NFC_V1_V2_CONFIG2              (host->regs + 0x1c)
@@ -152,6 +158,7 @@ struct mxc_nand_host {
        int                     clk_act;
        int                     irq;
        int                     eccsize;
+       int                     active_cs;
 
        struct completion       op_completion;
 
@@ -236,9 +243,7 @@ static struct nand_ecclayout nandv2_hw_eccoob_4k = {
        }
 };
 
-#ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL };
-#endif
 
 static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
 {
@@ -445,7 +450,7 @@ static void send_page_v1_v2(struct mtd_info *mtd, unsigned int ops)
        for (i = 0; i < bufs; i++) {
 
                /* NANDFC buffer 0 is used for page read/write */
-               writew(i, NFC_V1_V2_BUF_ADDR);
+               writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR);
 
                writew(ops, NFC_V1_V2_CONFIG2);
 
@@ -470,7 +475,7 @@ static void send_read_id_v1_v2(struct mxc_nand_host *host)
        struct nand_chip *this = &host->nand;
 
        /* NANDFC buffer 0 is used for device ID output */
-       writew(0x0, NFC_V1_V2_BUF_ADDR);
+       writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
 
        writew(NFC_ID, NFC_V1_V2_CONFIG2);
 
@@ -505,7 +510,7 @@ static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host)
        uint32_t store;
        uint16_t ret;
 
-       writew(0x0, NFC_V1_V2_BUF_ADDR);
+       writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
 
        /*
         * The device status is stored in main_area0. To
@@ -686,24 +691,24 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
        struct nand_chip *nand_chip = mtd->priv;
        struct mxc_nand_host *host = nand_chip->priv;
 
-       switch (chip) {
-       case -1:
+       if (chip == -1) {
                /* Disable the NFC clock */
                if (host->clk_act) {
                        clk_disable(host->clk);
                        host->clk_act = 0;
                }
-               break;
-       case 0:
+               return;
+       }
+
+       if (!host->clk_act) {
                /* Enable the NFC clock */
-               if (!host->clk_act) {
-                       clk_enable(host->clk);
-                       host->clk_act = 1;
-               }
-               break;
+               clk_enable(host->clk);
+               host->clk_act = 1;
+       }
 
-       default:
-               break;
+       if (nfc_is_v21()) {
+               host->active_cs = chip;
+               writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
        }
 }
 
@@ -834,8 +839,14 @@ static void preset_v1_v2(struct mtd_info *mtd)
 
        /* Blocks to be unlocked */
        if (nfc_is_v21()) {
-               writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR);
-               writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR);
+               writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR0);
+               writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR1);
+               writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR2);
+               writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR3);
+               writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR0);
+               writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR1);
+               writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR2);
+               writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3);
        } else if (nfc_is_v1()) {
                writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR);
                writew(0x4000, NFC_V1_UNLOCKEND_BLKADDR);
@@ -1200,7 +1211,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
                irq_control_v1_v2(host, 1);
 
        /* first scan to find the device and get the page size */
-       if (nand_scan_ident(mtd, 1, NULL)) {
+       if (nand_scan_ident(mtd, nfc_is_v21() ? 4 : 1, NULL)) {
                err = -ENXIO;
                goto escan;
        }
@@ -1220,18 +1231,15 @@ static int __init mxcnd_probe(struct platform_device *pdev)
        }
 
        /* Register the partitions */
-#ifdef CONFIG_MTD_PARTITIONS
        nr_parts =
            parse_mtd_partitions(mtd, part_probes, &host->parts, 0);
        if (nr_parts > 0)
-               add_mtd_partitions(mtd, host->parts, nr_parts);
+               mtd_device_register(mtd, host->parts, nr_parts);
        else if (pdata->parts)
-               add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts);
-       else
-#endif
-       {
+               mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
+       else {
                pr_info("Registering %s as whole device\n", mtd->name);
-               add_mtd_device(mtd);
+               mtd_device_register(mtd, NULL, 0);
        }
 
        platform_set_drvdata(pdev, host);
index c54a4cbac6bc036f90496d65364e04e846ec7e18..a46e9bb847bd0ac52743f14ab07133cc9a98b231 100644 (file)
 #include <linux/bitops.h>
 #include <linux/leds.h>
 #include <linux/io.h>
-
-#ifdef CONFIG_MTD_PARTITIONS
 #include <linux/mtd/partitions.h>
-#endif
 
 /* Define default oob placement schemes for large and small page devices */
 static struct nand_ecclayout nand_oob_8 = {
@@ -976,9 +973,6 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        ret = __nand_unlock(mtd, ofs, len, 0);
 
 out:
-       /* de-select the NAND device */
-       chip->select_chip(mtd, -1);
-
        nand_release_device(mtd);
 
        return ret;
@@ -1046,9 +1040,6 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        ret = __nand_unlock(mtd, ofs, len, 0x1);
 
 out:
-       /* de-select the NAND device */
-       chip->select_chip(mtd, -1);
-
        nand_release_device(mtd);
 
        return ret;
@@ -3112,6 +3103,8 @@ ident_done:
                chip->chip_shift += 32 - 1;
        }
 
+       chip->badblockbits = 8;
+
        /* Set the bad block position */
        if (mtd->writesize > 512 || (busw & NAND_BUSWIDTH_16))
                chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
@@ -3539,12 +3532,7 @@ void nand_release(struct mtd_info *mtd)
        if (chip->ecc.mode == NAND_ECC_SOFT_BCH)
                nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
 
-#ifdef CONFIG_MTD_PARTITIONS
-       /* Deregister partitions */
-       del_mtd_partitions(mtd);
-#endif
-       /* Deregister the device */
-       del_mtd_device(mtd);
+       mtd_device_unregister(mtd);
 
        /* Free bad block table memory */
        kfree(chip->bbt);
index af46428286fefc63cb67b1181770976509934782..ccbeaa1e4a8ed42ccddac88f2780915dc3407736 100644 (file)
@@ -1276,20 +1276,6 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
  * while scanning a device for factory marked good / bad blocks. */
 static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
 
-static struct nand_bbt_descr smallpage_flashbased = {
-       .options = NAND_BBT_SCAN2NDPAGE,
-       .offs = NAND_SMALL_BADBLOCK_POS,
-       .len = 1,
-       .pattern = scan_ff_pattern
-};
-
-static struct nand_bbt_descr largepage_flashbased = {
-       .options = NAND_BBT_SCAN2NDPAGE,
-       .offs = NAND_LARGE_BADBLOCK_POS,
-       .len = 2,
-       .pattern = scan_ff_pattern
-};
-
 static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 };
 
 static struct nand_bbt_descr agand_flashbased = {
@@ -1355,10 +1341,6 @@ static struct nand_bbt_descr bbt_mirror_no_bbt_descr = {
  * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when
  * passed to this function.
  *
- * TODO: Handle other flags, replace other static structs
- *        (e.g. handle NAND_BBT_FLASH for flash-based BBT,
- *             replace smallpage_flashbased)
- *
  */
 static int nand_create_default_bbt_descr(struct nand_chip *this)
 {
@@ -1422,15 +1404,14 @@ int nand_default_bbt(struct mtd_info *mtd)
                                this->bbt_md = &bbt_mirror_descr;
                        }
                }
-               if (!this->badblock_pattern) {
-                       this->badblock_pattern = (mtd->writesize > 512) ? &largepage_flashbased : &smallpage_flashbased;
-               }
        } else {
                this->bbt_td = NULL;
                this->bbt_md = NULL;
-               if (!this->badblock_pattern)
-                       nand_create_default_bbt_descr(this);
        }
+
+       if (!this->badblock_pattern)
+               nand_create_default_bbt_descr(this);
+
        return nand_scan_bbt(mtd, this->badblock_pattern);
 }
 
index 893d95bfea481ad9c568a83cea316eb9f06472b8..357e8c5252a8c38df3d8ba3885a7fc948b34303c 100644 (file)
@@ -2383,7 +2383,9 @@ static int __init ns_init_module(void)
                goto err_exit;
 
        /* Register NAND partitions */
-       if ((retval = add_mtd_partitions(nsmtd, &nand->partitions[0], nand->nbparts)) != 0)
+       retval = mtd_device_register(nsmtd, &nand->partitions[0],
+                                    nand->nbparts);
+       if (retval != 0)
                goto err_exit;
 
         return 0;
index bbe6d451290d93d4824a58bdf0966666caef6283..ea2dea8a9c88b6f72e8b59fcd724b085617abfca 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/of_platform.h>
 #include <asm/io.h>
 
+#define NDFC_MAX_CS    4
 
 struct ndfc_controller {
        struct platform_device *ofdev;
@@ -41,17 +42,16 @@ struct ndfc_controller {
        struct nand_chip chip;
        int chip_select;
        struct nand_hw_control ndfc_control;
-#ifdef CONFIG_MTD_PARTITIONS
        struct mtd_partition *parts;
-#endif
 };
 
-static struct ndfc_controller ndfc_ctrl;
+static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS];
 
 static void ndfc_select_chip(struct mtd_info *mtd, int chip)
 {
        uint32_t ccr;
-       struct ndfc_controller *ndfc = &ndfc_ctrl;
+       struct nand_chip *nchip = mtd->priv;
+       struct ndfc_controller *ndfc = nchip->priv;
 
        ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
        if (chip >= 0) {
@@ -64,7 +64,8 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
 
 static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
-       struct ndfc_controller *ndfc = &ndfc_ctrl;
+       struct nand_chip *chip = mtd->priv;
+       struct ndfc_controller *ndfc = chip->priv;
 
        if (cmd == NAND_CMD_NONE)
                return;
@@ -77,7 +78,8 @@ static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 
 static int ndfc_ready(struct mtd_info *mtd)
 {
-       struct ndfc_controller *ndfc = &ndfc_ctrl;
+       struct nand_chip *chip = mtd->priv;
+       struct ndfc_controller *ndfc = chip->priv;
 
        return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
 }
@@ -85,7 +87,8 @@ static int ndfc_ready(struct mtd_info *mtd)
 static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
 {
        uint32_t ccr;
-       struct ndfc_controller *ndfc = &ndfc_ctrl;
+       struct nand_chip *chip = mtd->priv;
+       struct ndfc_controller *ndfc = chip->priv;
 
        ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
        ccr |= NDFC_CCR_RESET_ECC;
@@ -96,7 +99,8 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
 static int ndfc_calculate_ecc(struct mtd_info *mtd,
                              const u_char *dat, u_char *ecc_code)
 {
-       struct ndfc_controller *ndfc = &ndfc_ctrl;
+       struct nand_chip *chip = mtd->priv;
+       struct ndfc_controller *ndfc = chip->priv;
        uint32_t ecc;
        uint8_t *p = (uint8_t *)&ecc;
 
@@ -119,7 +123,8 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd,
  */
 static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-       struct ndfc_controller *ndfc = &ndfc_ctrl;
+       struct nand_chip *chip = mtd->priv;
+       struct ndfc_controller *ndfc = chip->priv;
        uint32_t *p = (uint32_t *) buf;
 
        for(;len > 0; len -= 4)
@@ -128,7 +133,8 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 
 static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
-       struct ndfc_controller *ndfc = &ndfc_ctrl;
+       struct nand_chip *chip = mtd->priv;
+       struct ndfc_controller *ndfc = chip->priv;
        uint32_t *p = (uint32_t *) buf;
 
        for(;len > 0; len -= 4)
@@ -137,7 +143,8 @@ static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 
 static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
-       struct ndfc_controller *ndfc = &ndfc_ctrl;
+       struct nand_chip *chip = mtd->priv;
+       struct ndfc_controller *ndfc = chip->priv;
        uint32_t *p = (uint32_t *) buf;
 
        for(;len > 0; len -= 4)
@@ -152,12 +159,10 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 static int ndfc_chip_init(struct ndfc_controller *ndfc,
                          struct device_node *node)
 {
-#ifdef CONFIG_MTD_PARTITIONS
 #ifdef CONFIG_MTD_CMDLINE_PARTS
        static const char *part_types[] = { "cmdlinepart", NULL };
 #else
        static const char *part_types[] = { NULL };
-#endif
 #endif
        struct device_node *flash_np;
        struct nand_chip *chip = &ndfc->chip;
@@ -179,6 +184,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
        chip->ecc.mode = NAND_ECC_HW;
        chip->ecc.size = 256;
        chip->ecc.bytes = 3;
+       chip->priv = ndfc;
 
        ndfc->mtd.priv = chip;
        ndfc->mtd.owner = THIS_MODULE;
@@ -198,25 +204,18 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
        if (ret)
                goto err;
 
-#ifdef CONFIG_MTD_PARTITIONS
        ret = parse_mtd_partitions(&ndfc->mtd, part_types, &ndfc->parts, 0);
        if (ret < 0)
                goto err;
 
-#ifdef CONFIG_MTD_OF_PARTS
        if (ret == 0) {
                ret = of_mtd_parse_partitions(&ndfc->ofdev->dev, flash_np,
                                              &ndfc->parts);
                if (ret < 0)
                        goto err;
        }
-#endif
 
-       if (ret > 0)
-               ret = add_mtd_partitions(&ndfc->mtd, ndfc->parts, ret);
-       else
-#endif
-               ret = add_mtd_device(&ndfc->mtd);
+       ret = mtd_device_register(&ndfc->mtd, ndfc->parts, ret);
 
 err:
        of_node_put(flash_np);
@@ -227,15 +226,10 @@ err:
 
 static int __devinit ndfc_probe(struct platform_device *ofdev)
 {
-       struct ndfc_controller *ndfc = &ndfc_ctrl;
+       struct ndfc_controller *ndfc;
        const __be32 *reg;
        u32 ccr;
-       int err, len;
-
-       spin_lock_init(&ndfc->ndfc_control.lock);
-       init_waitqueue_head(&ndfc->ndfc_control.wq);
-       ndfc->ofdev = ofdev;
-       dev_set_drvdata(&ofdev->dev, ndfc);
+       int err, len, cs;
 
        /* Read the reg property to get the chip select */
        reg = of_get_property(ofdev->dev.of_node, "reg", &len);
@@ -243,7 +237,20 @@ static int __devinit ndfc_probe(struct platform_device *ofdev)
                dev_err(&ofdev->dev, "unable read reg property (%d)\n", len);
                return -ENOENT;
        }
-       ndfc->chip_select = be32_to_cpu(reg[0]);
+
+       cs = be32_to_cpu(reg[0]);
+       if (cs >= NDFC_MAX_CS) {
+               dev_err(&ofdev->dev, "invalid CS number (%d)\n", cs);
+               return -EINVAL;
+       }
+
+       ndfc = &ndfc_ctrl[cs];
+       ndfc->chip_select = cs;
+
+       spin_lock_init(&ndfc->ndfc_control.lock);
+       init_waitqueue_head(&ndfc->ndfc_control.wq);
+       ndfc->ofdev = ofdev;
+       dev_set_drvdata(&ofdev->dev, ndfc);
 
        ndfc->ndfcbase = of_iomap(ofdev->dev.of_node, 0);
        if (!ndfc->ndfcbase) {
index a045a4a581b62240ddc69aa43b465f0a026b0b84..b6a5c86ab31e922e1ddcf81dc88257012d61ad08 100644 (file)
@@ -158,12 +158,7 @@ static int nomadik_nand_probe(struct platform_device *pdev)
                goto err_unmap;
        }
 
-#ifdef CONFIG_MTD_PARTITIONS
-       add_mtd_partitions(&host->mtd, pdata->parts, pdata->nparts);
-#else
-       pr_info("Registering %s as whole device\n", mtd->name);
-       add_mtd_device(mtd);
-#endif
+       mtd_device_register(&host->mtd, pdata->parts, pdata->nparts);
 
        platform_set_drvdata(pdev, host);
        return 0;
index 6eddf7361ed7c74dd709f51b408a5a976e580832..9c30a0b031715f5d8a26dfd3fb3abbb7418adb6f 100644 (file)
@@ -321,8 +321,8 @@ static int __devinit nuc900_nand_probe(struct platform_device *pdev)
                goto fail3;
        }
 
-       add_mtd_partitions(&(nuc900_nand->mtd), partitions,
-                                               ARRAY_SIZE(partitions));
+       mtd_device_register(&(nuc900_nand->mtd), partitions,
+                           ARRAY_SIZE(partitions));
 
        platform_set_drvdata(pdev, nuc900_nand);
 
index da9a351c9d79f55b1dae9afa7b8cbd9ba117da9c..0db2c0e7656ae7abbde5536ca8c842a465482696 100644 (file)
@@ -94,9 +94,7 @@
 #define P4e_s(a)       (TF(a & NAND_Ecc_P4e)           << 0)
 #define P4o_s(a)       (TF(a & NAND_Ecc_P4o)           << 1)
 
-#ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probes[] = { "cmdlinepart", NULL };
-#endif
 
 /* oob info generated runtime depending on ecc algorithm and layout selected */
 static struct nand_ecclayout omap_oobinfo;
@@ -263,11 +261,10 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
        if (ret) {
                /* PFPW engine is busy, use cpu copy method */
                if (info->nand.options & NAND_BUSWIDTH_16)
-                       omap_read_buf16(mtd, buf, len);
+                       omap_read_buf16(mtd, (u_char *)p, len);
                else
-                       omap_read_buf8(mtd, buf, len);
+                       omap_read_buf8(mtd, (u_char *)p, len);
        } else {
-               p = (u32 *) buf;
                do {
                        r_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT);
                        r_count = r_count >> 2;
@@ -293,7 +290,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
                                                struct omap_nand_info, mtd);
        uint32_t w_count = 0;
        int i = 0, ret = 0;
-       u16 *p;
+       u16 *p = (u16 *)buf;
        unsigned long tim, limit;
 
        /* take care of subpage writes */
@@ -309,11 +306,10 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
        if (ret) {
                /* PFPW engine is busy, use cpu copy method */
                if (info->nand.options & NAND_BUSWIDTH_16)
-                       omap_write_buf16(mtd, buf, len);
+                       omap_write_buf16(mtd, (u_char *)p, len);
                else
-                       omap_write_buf8(mtd, buf, len);
+                       omap_write_buf8(mtd, (u_char *)p, len);
        } else {
-               p = (u16 *) buf;
                while (len) {
                        w_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT);
                        w_count = w_count >> 1;
@@ -1073,9 +1069,9 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
        /* DIP switches on some boards change between 8 and 16 bit
         * bus widths for flash.  Try the other width if the first try fails.
         */
-       if (nand_scan(&info->mtd, 1)) {
+       if (nand_scan_ident(&info->mtd, 1, NULL)) {
                info->nand.options ^= NAND_BUSWIDTH_16;
-               if (nand_scan(&info->mtd, 1)) {
+               if (nand_scan_ident(&info->mtd, 1, NULL)) {
                        err = -ENXIO;
                        goto out_release_mem_region;
                }
@@ -1101,15 +1097,19 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
                info->nand.ecc.layout = &omap_oobinfo;
        }
 
-#ifdef CONFIG_MTD_PARTITIONS
+       /* second phase scan */
+       if (nand_scan_tail(&info->mtd)) {
+               err = -ENXIO;
+               goto out_release_mem_region;
+       }
+
        err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);
        if (err > 0)
-               add_mtd_partitions(&info->mtd, info->parts, err);
+               mtd_device_register(&info->mtd, info->parts, err);
        else if (pdata->parts)
-               add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts);
+               mtd_device_register(&info->mtd, pdata->parts, pdata->nr_parts);
        else
-#endif
-               add_mtd_device(&info->mtd);
+               mtd_device_register(&info->mtd, NULL, 0);
 
        platform_set_drvdata(pdev, &info->mtd);
 
index da6e7534305259e83e140d308e57ef0d110cdf47..7794d0680f913b87932ba28d20729e642db382fb 100644 (file)
@@ -21,9 +21,7 @@
 #include <mach/hardware.h>
 #include <plat/orion_nand.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)
 {
@@ -83,10 +81,8 @@ static int __init orion_nand_probe(struct platform_device *pdev)
        struct resource *res;
        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) {
@@ -136,7 +132,6 @@ static int __init orion_nand_probe(struct platform_device *pdev)
                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);
@@ -147,14 +142,7 @@ static int __init orion_nand_probe(struct platform_device *pdev)
                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
-
+       ret = mtd_device_register(mtd, partitions, num_part);
        if (ret) {
                nand_release(mtd);
                goto no_dev;
index 20bfe5f15afdcaf7cd93c19d1a296013a0d694f8..b1aa41b8a4eb6cd0d660d7c38eef8d1be00c0190 100644 (file)
@@ -163,7 +163,7 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev)
                goto out_lpc;
        }
 
-       if (add_mtd_device(pasemi_nand_mtd)) {
+       if (mtd_device_register(pasemi_nand_mtd, NULL, 0)) {
                printk(KERN_ERR "pasemi_nand: Unable to register MTD device\n");
                err = -ENODEV;
                goto out_lpc;
index caf5a736340a90af135259fbcab695b2145b606e..633c04bf76f6c158aa4029ab83dc6a3d7f3ddca9 100644 (file)
@@ -21,10 +21,8 @@ struct plat_nand_data {
        struct nand_chip        chip;
        struct mtd_info         mtd;
        void __iomem            *io_base;
-#ifdef CONFIG_MTD_PARTITIONS
        int                     nr_parts;
        struct mtd_partition    *parts;
-#endif
 };
 
 /*
@@ -101,13 +99,12 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)
                goto out;
        }
 
-#ifdef CONFIG_MTD_PARTITIONS
        if (pdata->chip.part_probe_types) {
                err = parse_mtd_partitions(&data->mtd,
                                        pdata->chip.part_probe_types,
                                        &data->parts, 0);
                if (err > 0) {
-                       add_mtd_partitions(&data->mtd, data->parts, err);
+                       mtd_device_register(&data->mtd, data->parts, err);
                        return 0;
                }
        }
@@ -115,11 +112,10 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)
                pdata->chip.set_parts(data->mtd.size, &pdata->chip);
        if (pdata->chip.partitions) {
                data->parts = pdata->chip.partitions;
-               err = add_mtd_partitions(&data->mtd, data->parts,
+               err = mtd_device_register(&data->mtd, data->parts,
                        pdata->chip.nr_partitions);
        } else
-#endif
-       err = add_mtd_device(&data->mtd);
+               err = mtd_device_register(&data->mtd, NULL, 0);
 
        if (!err)
                return err;
@@ -149,10 +145,8 @@ static int __devexit plat_nand_remove(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
        nand_release(&data->mtd);
-#ifdef CONFIG_MTD_PARTITIONS
        if (data->parts && data->parts != pdata->chip.partitions)
                kfree(data->parts);
-#endif
        if (pdata->ctrl.remove)
                pdata->ctrl.remove(pdev);
        iounmap(data->io_base);
index cc86584318512acc1b00547d3d87404bf95a98a0..3bbb796b451c7994ab754610c433333308329a88 100644 (file)
@@ -73,7 +73,6 @@ __setup("ppchameleon_fio_pbase=", ppchameleon_fio_pbase);
 __setup("ppchameleonevb_fio_pbase=", ppchameleonevb_fio_pbase);
 #endif
 
-#ifdef CONFIG_MTD_PARTITIONS
 /*
  * Define static partitions for flash devices
  */
@@ -101,7 +100,6 @@ static struct mtd_partition partition_info_evb[] = {
 #define NUM_PARTITIONS 1
 
 extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, const char *mtd_id);
-#endif
 
 /*
  *     hardware specific access to control-lines
@@ -189,10 +187,8 @@ static int ppchameleonevb_device_ready(struct mtd_info *minfo)
 }
 #endif
 
-#ifdef CONFIG_MTD_PARTITIONS
 const char *part_probes[] = { "cmdlinepart", NULL };
 const char *part_probes_evb[] = { "cmdlinepart", NULL };
-#endif
 
 /*
  * Main initialization routine
@@ -284,14 +280,13 @@ static int __init ppchameleonevb_init(void)
                this->chip_delay = NAND_SMALL_DELAY_US;
 #endif
 
-#ifdef CONFIG_MTD_PARTITIONS
        ppchameleon_mtd->name = "ppchameleon-nand";
        mtd_parts_nb = parse_mtd_partitions(ppchameleon_mtd, part_probes, &mtd_parts, 0);
        if (mtd_parts_nb > 0)
                part_type = "command line";
        else
                mtd_parts_nb = 0;
-#endif
+
        if (mtd_parts_nb == 0) {
                if (ppchameleon_mtd->size == NAND_SMALL_SIZE)
                        mtd_parts = partition_info_me;
@@ -303,7 +298,7 @@ static int __init ppchameleonevb_init(void)
 
        /* Register the partitions */
        printk(KERN_NOTICE "Using %s partition definition\n", part_type);
-       add_mtd_partitions(ppchameleon_mtd, mtd_parts, mtd_parts_nb);
+       mtd_device_register(ppchameleon_mtd, mtd_parts, mtd_parts_nb);
 
  nand_evb_init:
        /****************************
@@ -385,14 +380,14 @@ static int __init ppchameleonevb_init(void)
                        iounmap(ppchameleon_fio_base);
                return -ENXIO;
        }
-#ifdef CONFIG_MTD_PARTITIONS
+
        ppchameleonevb_mtd->name = NAND_EVB_MTD_NAME;
        mtd_parts_nb = parse_mtd_partitions(ppchameleonevb_mtd, part_probes_evb, &mtd_parts, 0);
        if (mtd_parts_nb > 0)
                part_type = "command line";
        else
                mtd_parts_nb = 0;
-#endif
+
        if (mtd_parts_nb == 0) {
                mtd_parts = partition_info_evb;
                mtd_parts_nb = NUM_PARTITIONS;
@@ -401,7 +396,7 @@ static int __init ppchameleonevb_init(void)
 
        /* Register the partitions */
        printk(KERN_NOTICE "Using %s partition definition\n", part_type);
-       add_mtd_partitions(ppchameleonevb_mtd, mtd_parts, mtd_parts_nb);
+       mtd_device_register(ppchameleonevb_mtd, mtd_parts, mtd_parts_nb);
 
        /* Return happy */
        return 0;
index ff0701276d654bc7f9653c53ece3f6b0152a84e3..1fb3b3a805818edca37ed2e07bfd8bd90b3d0f4b 100644 (file)
@@ -1119,10 +1119,7 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
        clk_put(info->clk);
 
        if (mtd) {
-               del_mtd_device(mtd);
-#ifdef CONFIG_MTD_PARTITIONS
-               del_mtd_partitions(mtd);
-#endif
+               mtd_device_unregister(mtd);
                kfree(mtd);
        }
        return 0;
@@ -1149,7 +1146,6 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-#ifdef CONFIG_MTD_PARTITIONS
        if (mtd_has_cmdlinepart()) {
                const char *probes[] = { "cmdlinepart", NULL };
                struct mtd_partition *parts;
@@ -1158,13 +1154,10 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
                nr_parts = parse_mtd_partitions(info->mtd, probes, &parts, 0);
 
                if (nr_parts)
-                       return add_mtd_partitions(info->mtd, parts, nr_parts);
+                       return mtd_device_register(info->mtd, parts, nr_parts);
        }
 
-       return add_mtd_partitions(info->mtd, pdata->parts, pdata->nr_parts);
-#else
-       return 0;
-#endif
+       return mtd_device_register(info->mtd, pdata->parts, pdata->nr_parts);
 }
 
 #ifdef CONFIG_PM
index 67440b5beef8c7f12567b1f48240d621b66d324f..c9f9127ff7708ee06fae1bd6e159f8e0619f20e5 100644 (file)
@@ -580,7 +580,8 @@ static int __init rtc_from4_init(void)
 #endif
 
        /* Register the partitions */
-       ret = add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS);
+       ret = mtd_device_register(rtc_from4_mtd, partition_info,
+                                 NUM_PARTITIONS);
        if (ret)
                goto err_3;
 
index 33d832dddfdd178ff2d9e986eada8dd0ec387c6d..4405468f196b076c6b97fb1366ec8fff55d684a8 100644 (file)
@@ -55,7 +55,7 @@ static int hardware_ecc = 0;
 #endif
 
 #ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP
-static int clock_stop = 1;
+static const int clock_stop = 1;
 #else
 static const int clock_stop = 0;
 #endif
@@ -96,6 +96,12 @@ enum s3c_cpu_type {
        TYPE_S3C2440,
 };
 
+enum s3c_nand_clk_state {
+       CLOCK_DISABLE   = 0,
+       CLOCK_ENABLE,
+       CLOCK_SUSPEND,
+};
+
 /* overview of the s3c2410 nand state */
 
 /**
@@ -111,6 +117,7 @@ enum s3c_cpu_type {
  * @mtd_count: The number of MTDs created from this controller.
  * @save_sel: The contents of @sel_reg to be saved over suspend.
  * @clk_rate: The clock rate from @clk.
+ * @clk_state: The current clock state.
  * @cpu_type: The exact type of this controller.
  */
 struct s3c2410_nand_info {
@@ -129,6 +136,7 @@ struct s3c2410_nand_info {
        int                             mtd_count;
        unsigned long                   save_sel;
        unsigned long                   clk_rate;
+       enum s3c_nand_clk_state         clk_state;
 
        enum s3c_cpu_type               cpu_type;
 
@@ -159,11 +167,33 @@ static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)
        return dev->dev.platform_data;
 }
 
-static inline int allow_clk_stop(struct s3c2410_nand_info *info)
+static inline int allow_clk_suspend(struct s3c2410_nand_info *info)
 {
        return clock_stop;
 }
 
+/**
+ * s3c2410_nand_clk_set_state - Enable, disable or suspend NAND clock.
+ * @info: The controller instance.
+ * @new_state: State to which clock should be set.
+ */
+static void s3c2410_nand_clk_set_state(struct s3c2410_nand_info *info,
+               enum s3c_nand_clk_state new_state)
+{
+       if (!allow_clk_suspend(info) && new_state == CLOCK_SUSPEND)
+               return;
+
+       if (info->clk_state == CLOCK_ENABLE) {
+               if (new_state != CLOCK_ENABLE)
+                       clk_disable(info->clk);
+       } else {
+               if (new_state == CLOCK_ENABLE)
+                       clk_enable(info->clk);
+       }
+
+       info->clk_state = new_state;
+}
+
 /* timing calculations */
 
 #define NS_IN_KHZ 1000000
@@ -333,8 +363,8 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
        nmtd = this->priv;
        info = nmtd->info;
 
-       if (chip != -1 && allow_clk_stop(info))
-               clk_enable(info->clk);
+       if (chip != -1)
+               s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
 
        cur = readl(info->sel_reg);
 
@@ -356,8 +386,8 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
 
        writel(cur, info->sel_reg);
 
-       if (chip == -1 && allow_clk_stop(info))
-               clk_disable(info->clk);
+       if (chip == -1)
+               s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
 }
 
 /* s3c2410_nand_hwcontrol
@@ -694,8 +724,7 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
        /* free the common resources */
 
        if (info->clk != NULL && !IS_ERR(info->clk)) {
-               if (!allow_clk_stop(info))
-                       clk_disable(info->clk);
+               s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
                clk_put(info->clk);
        }
 
@@ -715,7 +744,6 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_MTD_PARTITIONS
 const char *part_probes[] = { "cmdlinepart", NULL };
 static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
                                      struct s3c2410_nand_mtd *mtd,
@@ -725,7 +753,7 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
        int nr_part = 0;
 
        if (set == NULL)
-               return add_mtd_device(&mtd->mtd);
+               return mtd_device_register(&mtd->mtd, NULL, 0);
 
        mtd->mtd.name = set->name;
        nr_part = parse_mtd_partitions(&mtd->mtd, part_probes, &part_info, 0);
@@ -735,19 +763,8 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
                part_info = set->partitions;
        }
 
-       if (nr_part > 0 && part_info)
-               return add_mtd_partitions(&mtd->mtd, part_info, nr_part);
-
-       return add_mtd_device(&mtd->mtd);
-}
-#else
-static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
-                                     struct s3c2410_nand_mtd *mtd,
-                                     struct s3c2410_nand_set *set)
-{
-       return add_mtd_device(&mtd->mtd);
+       return mtd_device_register(&mtd->mtd, part_info, nr_part);
 }
-#endif
 
 /**
  * s3c2410_nand_init_chip - initialise a single instance of an chip
@@ -947,7 +964,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
                goto exit_error;
        }
 
-       clk_enable(info->clk);
+       s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
 
        /* allocate and map the resource */
 
@@ -1026,9 +1043,9 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
                goto exit_error;
        }
 
-       if (allow_clk_stop(info)) {
+       if (allow_clk_suspend(info)) {
                dev_info(&pdev->dev, "clock idle support enabled\n");
-               clk_disable(info->clk);
+               s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
        }
 
        pr_debug("initialised ok\n");
@@ -1059,8 +1076,7 @@ static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
 
                writel(info->save_sel | info->sel_bit, info->sel_reg);
 
-               if (!allow_clk_stop(info))
-                       clk_disable(info->clk);
+               s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
        }
 
        return 0;
@@ -1072,7 +1088,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
        unsigned long sel;
 
        if (info) {
-               clk_enable(info->clk);
+               s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
                s3c2410_nand_inithw(info);
 
                /* Restore the state of the nFCE line. */
@@ -1082,8 +1098,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
                sel |= info->save_sel & info->sel_bit;
                writel(sel, info->sel_reg);
 
-               if (allow_clk_stop(info))
-                       clk_disable(info->clk);
+               s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
        }
 
        return 0;
index 81bbb5ee148d49da8a9ca792338f60b2c7324b1d..93b1f74321c2a9e7793b8a867a1a02af15638278 100644 (file)
@@ -867,7 +867,7 @@ static int __devinit flctl_probe(struct platform_device *pdev)
        if (ret)
                goto err;
 
-       add_mtd_partitions(flctl_mtd, pdata->parts, pdata->nr_parts);
+       mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
 
        return 0;
 
index 54ec7542a7b77590b4a3b961fef310d6aed2a9b7..19e24ed089ea9dd05d1bc9b4ea25dc406d5ede90 100644 (file)
@@ -103,9 +103,7 @@ static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat,
        return readb(sharpsl->io + ECCCNTR) != 0;
 }
 
-#ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probes[] = { "cmdlinepart", NULL };
-#endif
 
 /*
  * Main initialization routine
@@ -113,10 +111,8 @@ static const char *part_probes[] = { "cmdlinepart", NULL };
 static int __devinit sharpsl_nand_probe(struct platform_device *pdev)
 {
        struct nand_chip *this;
-#ifdef CONFIG_MTD_PARTITIONS
        struct mtd_partition *sharpsl_partition_info;
        int nr_partitions;
-#endif
        struct resource *r;
        int err = 0;
        struct sharpsl_nand *sharpsl;
@@ -188,18 +184,14 @@ static int __devinit sharpsl_nand_probe(struct platform_device *pdev)
 
        /* Register the partitions */
        sharpsl->mtd.name = "sharpsl-nand";
-#ifdef CONFIG_MTD_PARTITIONS
        nr_partitions = parse_mtd_partitions(&sharpsl->mtd, part_probes, &sharpsl_partition_info, 0);
        if (nr_partitions <= 0) {
                nr_partitions = data->nr_partitions;
                sharpsl_partition_info = data->partitions;
        }
 
-       if (nr_partitions > 0)
-               err = add_mtd_partitions(&sharpsl->mtd, sharpsl_partition_info, nr_partitions);
-       else
-#endif
-       err = add_mtd_device(&sharpsl->mtd);
+       err = mtd_device_register(&sharpsl->mtd, sharpsl_partition_info,
+                                 nr_partitions);
        if (err)
                goto err_add;
 
index 57cc80cd01a33e8749eaad0201ae561f964339ec..b6332e83b2895e798fc5220dd914b1e1a1e99602 100644 (file)
@@ -139,7 +139,7 @@ int sm_register_device(struct mtd_info *mtd, int smartmedia)
        if (ret)
                return ret;
 
-       return add_mtd_device(mtd);
+       return mtd_device_register(mtd, NULL, 0);
 }
 EXPORT_SYMBOL_GPL(sm_register_device);
 
index a853548986f0ebdb69d20756b20a04f400f0d8f9..ca2d0555729e466b43940043c9d044334f3719d4 100644 (file)
@@ -155,9 +155,7 @@ static int socrates_nand_device_ready(struct mtd_info *mtd)
        return 1;
 }
 
-#ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probes[] = { "cmdlinepart", NULL };
-#endif
 
 /*
  * Probe for the NAND device.
@@ -168,11 +166,8 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev)
        struct mtd_info *mtd;
        struct nand_chip *nand_chip;
        int res;
-
-#ifdef CONFIG_MTD_PARTITIONS
        struct mtd_partition *partitions = NULL;
        int num_partitions = 0;
-#endif
 
        /* Allocate memory for the device structure (and zero it) */
        host = kzalloc(sizeof(struct socrates_nand_host), GFP_KERNEL);
@@ -230,7 +225,6 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev)
                goto out;
        }
 
-#ifdef CONFIG_MTD_PARTITIONS
 #ifdef CONFIG_MTD_CMDLINE_PARTS
        num_partitions = parse_mtd_partitions(mtd, part_probes,
                                              &partitions, 0);
@@ -240,7 +234,6 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev)
        }
 #endif
 
-#ifdef CONFIG_MTD_OF_PARTS
        if (num_partitions == 0) {
                num_partitions = of_mtd_parse_partitions(&ofdev->dev,
                                                         ofdev->dev.of_node,
@@ -250,19 +243,12 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev)
                        goto release;
                }
        }
-#endif
-       if (partitions && (num_partitions > 0))
-               res = add_mtd_partitions(mtd, partitions, num_partitions);
-       else
-#endif
-               res = add_mtd_device(mtd);
 
+       res = mtd_device_register(mtd, partitions, num_partitions);
        if (!res)
                return res;
 
-#ifdef CONFIG_MTD_PARTITIONS
 release:
-#endif
        nand_release(mtd);
 
 out:
index 0cc6d0acb8febdcde011545e5022bb950e3ccf0e..bef76cd7c24c08ab7431756017a739c09cd692f9 100644 (file)
@@ -149,7 +149,7 @@ static int __init spia_init(void)
        }
 
        /* Register the partitions */
-       add_mtd_partitions(spia_mtd, partition_info, NUM_PARTITIONS);
+       mtd_device_register(spia_mtd, partition_info, NUM_PARTITIONS);
 
        /* Return happy */
        return 0;
index 14c578707824b5e598ce5216da991ac52183e64f..11e8371b56834e8b0c79f64fe4d54393be849630 100644 (file)
@@ -372,7 +372,7 @@ static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio)
 
 static int tmio_probe(struct platform_device *dev)
 {
-       struct tmio_nand_data *data = mfd_get_data(dev);
+       struct tmio_nand_data *data = dev->dev.platform_data;
        struct resource *fcr = platform_get_resource(dev,
                        IORESOURCE_MEM, 0);
        struct resource *ccr = platform_get_resource(dev,
@@ -381,10 +381,8 @@ static int tmio_probe(struct platform_device *dev)
        struct tmio_nand *tmio;
        struct mtd_info *mtd;
        struct nand_chip *nand_chip;
-#ifdef CONFIG_MTD_PARTITIONS
        struct mtd_partition *parts;
        int nbparts = 0;
-#endif
        int retval;
 
        if (data == NULL)
@@ -463,7 +461,6 @@ static int tmio_probe(struct platform_device *dev)
                goto err_scan;
        }
        /* Register the partitions */
-#ifdef CONFIG_MTD_PARTITIONS
 #ifdef CONFIG_MTD_CMDLINE_PARTS
        nbparts = parse_mtd_partitions(mtd, part_probes, &parts, 0);
 #endif
@@ -472,12 +469,7 @@ static int tmio_probe(struct platform_device *dev)
                nbparts = data->num_partitions;
        }
 
-       if (nbparts)
-               retval = add_mtd_partitions(mtd, parts, nbparts);
-       else
-#endif
-       retval = add_mtd_device(mtd);
-
+       retval = mtd_device_register(mtd, parts, nbparts);
        if (!retval)
                return retval;
 
index ca270a4881a47c2acf42e7bf6a6270a332c59060..bfba4e39a6c5cd5866d95b0fd114896489935a62 100644 (file)
@@ -74,9 +74,7 @@ struct txx9ndfmc_drvdata {
        unsigned char hold;     /* in gbusclock */
        unsigned char spw;      /* in gbusclock */
        struct nand_hw_control hw_control;
-#ifdef CONFIG_MTD_PARTITIONS
        struct mtd_partition *parts[MAX_TXX9NDFMC_DEV];
-#endif
 };
 
 static struct platform_device *mtd_to_platdev(struct mtd_info *mtd)
@@ -289,9 +287,7 @@ static int txx9ndfmc_nand_scan(struct mtd_info *mtd)
 static int __init txx9ndfmc_probe(struct platform_device *dev)
 {
        struct txx9ndfmc_platform_data *plat = dev->dev.platform_data;
-#ifdef CONFIG_MTD_PARTITIONS
        static const char *probes[] = { "cmdlinepart", NULL };
-#endif
        int hold, spw;
        int i;
        struct txx9ndfmc_drvdata *drvdata;
@@ -337,9 +333,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
                struct txx9ndfmc_priv *txx9_priv;
                struct nand_chip *chip;
                struct mtd_info *mtd;
-#ifdef CONFIG_MTD_PARTITIONS
                int nr_parts;
-#endif
 
                if (!(plat->ch_mask & (1 << i)))
                        continue;
@@ -399,13 +393,9 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
                }
                mtd->name = txx9_priv->mtdname;
 
-#ifdef CONFIG_MTD_PARTITIONS
                nr_parts = parse_mtd_partitions(mtd, probes,
                                                &drvdata->parts[i], 0);
-               if (nr_parts > 0)
-                       add_mtd_partitions(mtd, drvdata->parts[i], nr_parts);
-#endif
-               add_mtd_device(mtd);
+               mtd_device_register(mtd, drvdata->parts[i], nr_parts);
                drvdata->mtds[i] = mtd;
        }
 
@@ -431,9 +421,7 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev)
                txx9_priv = chip->priv;
 
                nand_release(mtd);
-#ifdef CONFIG_MTD_PARTITIONS
                kfree(drvdata->parts[i]);
-#endif
                kfree(txx9_priv->mtdname);
                kfree(txx9_priv);
        }
index 4f426195f8dbf5b3f78b5da6fd59f3d8f7515485..772ad2966619ed56053a07b6e9329556edafe245 100644 (file)
@@ -1,7 +1,6 @@
 menuconfig MTD_ONENAND
        tristate "OneNAND Device Support"
        depends on MTD
-       select MTD_PARTITIONS
        help
          This enables support for accessing all type of OneNAND flash
          devices. For further information see
index ac08750748a351ec3e70dd32825b5385f2a8966e..2d70d354d846b6d36efb334434533445c0e21270 100644 (file)
@@ -30,9 +30,7 @@
  */
 #define DRIVER_NAME    "onenand-flash"
 
-#ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probes[] = { "cmdlinepart", NULL,  };
-#endif
 
 struct onenand_info {
        struct mtd_info         mtd;
@@ -75,15 +73,13 @@ static int __devinit generic_onenand_probe(struct platform_device *pdev)
                goto out_iounmap;
        }
 
-#ifdef CONFIG_MTD_PARTITIONS
        err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);
        if (err > 0)
-               add_mtd_partitions(&info->mtd, info->parts, err);
+               mtd_device_register(&info->mtd, info->parts, err);
        else if (err <= 0 && pdata && pdata->parts)
-               add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts);
+               mtd_device_register(&info->mtd, pdata->parts, pdata->nr_parts);
        else
-#endif
-               err = add_mtd_device(&info->mtd);
+               err = mtd_device_register(&info->mtd, NULL, 0);
 
        platform_set_drvdata(pdev, info);
 
@@ -108,11 +104,7 @@ static int __devexit generic_onenand_remove(struct platform_device *pdev)
        platform_set_drvdata(pdev, NULL);
 
        if (info) {
-               if (info->parts)
-                       del_mtd_partitions(&info->mtd);
-               else
-                       del_mtd_device(&info->mtd);
-
+               mtd_device_unregister(&info->mtd);
                onenand_release(&info->mtd);
                release_mem_region(res->start, size);
                iounmap(info->onenand.base);
index 1fcb41adab072006e4f3081242efef06b01844af..a916dec292156a524438b117400837fd7d9f6145 100644 (file)
@@ -67,9 +67,7 @@ struct omap2_onenand {
        struct regulator *regulator;
 };
 
-#ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probes[] = { "cmdlinepart", NULL,  };
-#endif
 
 static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data)
 {
@@ -755,15 +753,13 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
        if ((r = onenand_scan(&c->mtd, 1)) < 0)
                goto err_release_regulator;
 
-#ifdef CONFIG_MTD_PARTITIONS
        r = parse_mtd_partitions(&c->mtd, part_probes, &c->parts, 0);
        if (r > 0)
-               r = add_mtd_partitions(&c->mtd, c->parts, r);
+               r = mtd_device_register(&c->mtd, c->parts, r);
        else if (pdata->parts != NULL)
-               r = add_mtd_partitions(&c->mtd, pdata->parts, pdata->nr_parts);
+               r = mtd_device_register(&c->mtd, pdata->parts, pdata->nr_parts);
        else
-#endif
-               r = add_mtd_device(&c->mtd);
+               r = mtd_device_register(&c->mtd, NULL, 0);
        if (r)
                goto err_release_onenand;
 
index 56a8b2005bdace6eb51fe500a040dc13f38c24b8..ac9e959802a7b113e838ecb8d6e24aee5b7df524 100644 (file)
@@ -65,11 +65,11 @@ MODULE_PARM_DESC(otp,       "Corresponding behaviour of OneNAND in OTP"
                        "          : 2 -> 1st Block lock"
                        "          : 3 -> BOTH OTP Block and 1st Block lock");
 
-/**
- *  onenand_oob_128 - oob info for Flex-Onenand with 4KB page
- *  For now, we expose only 64 out of 80 ecc bytes
+/*
+ * flexonenand_oob_128 - oob info for Flex-Onenand with 4KB page
+ * For now, we expose only 64 out of 80 ecc bytes
  */
-static struct nand_ecclayout onenand_oob_128 = {
+static struct nand_ecclayout flexonenand_oob_128 = {
        .eccbytes       = 64,
        .eccpos         = {
                6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
@@ -86,6 +86,35 @@ static struct nand_ecclayout onenand_oob_128 = {
        }
 };
 
+/*
+ * onenand_oob_128 - oob info for OneNAND with 4KB page
+ *
+ * Based on specification:
+ * 4Gb M-die OneNAND Flash (KFM4G16Q4M, KFN8G16Q4M). Rev. 1.3, Apr. 2010
+ *
+ * For eccpos we expose only 64 bytes out of 72 (see struct nand_ecclayout)
+ *
+ * oobfree uses the spare area fields marked as
+ * "Managed by internal ECC logic for Logical Sector Number area"
+ */
+static struct nand_ecclayout onenand_oob_128 = {
+       .eccbytes       = 64,
+       .eccpos         = {
+               7, 8, 9, 10, 11, 12, 13, 14, 15,
+               23, 24, 25, 26, 27, 28, 29, 30, 31,
+               39, 40, 41, 42, 43, 44, 45, 46, 47,
+               55, 56, 57, 58, 59, 60, 61, 62, 63,
+               71, 72, 73, 74, 75, 76, 77, 78, 79,
+               87, 88, 89, 90, 91, 92, 93, 94, 95,
+               103, 104, 105, 106, 107, 108, 109, 110, 111,
+               119
+       },
+       .oobfree        = {
+               {2, 3}, {18, 3}, {34, 3}, {50, 3},
+               {66, 3}, {82, 3}, {98, 3}, {114, 3}
+       }
+};
+
 /**
  * onenand_oob_64 - oob info for large (2KB) page
  */
@@ -2424,7 +2453,7 @@ static int onenand_block_by_block_erase(struct mtd_info *mtd,
                len -= block_size;
                addr += block_size;
 
-               if (addr == region_end) {
+               if (region && addr == region_end) {
                        if (!len)
                                break;
                        region++;
@@ -4018,8 +4047,13 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
         */
        switch (mtd->oobsize) {
        case 128:
-               this->ecclayout = &onenand_oob_128;
-               mtd->subpage_sft = 0;
+               if (FLEXONENAND(this)) {
+                       this->ecclayout = &flexonenand_oob_128;
+                       mtd->subpage_sft = 0;
+               } else {
+                       this->ecclayout = &onenand_oob_128;
+                       mtd->subpage_sft = 2;
+               }
                break;
        case 64:
                this->ecclayout = &onenand_oob_64;
@@ -4108,12 +4142,8 @@ void onenand_release(struct mtd_info *mtd)
 {
        struct onenand_chip *this = mtd->priv;
 
-#ifdef CONFIG_MTD_PARTITIONS
        /* Deregister partitions */
-       del_mtd_partitions (mtd);
-#endif
-       /* Deregister the device */
-       del_mtd_device (mtd);
+       mtd_device_unregister(mtd);
 
        /* Free bad block table memory, if allocated */
        if (this->bbm) {
index 5ef3bd5477723dabf1c5b405ceb45b1ae1f2dff6..85399e3accda56205c07211853284cfe70317495 100644 (file)
@@ -539,7 +539,8 @@ static int __init onenand_sim_init(void)
                return -ENXIO;
        }
 
-       add_mtd_partitions(&info->mtd, info->parts, ARRAY_SIZE(os_partitions));
+       mtd_device_register(&info->mtd, info->parts,
+                           ARRAY_SIZE(os_partitions));
 
        return 0;
 }
index a4c74a9ba430de20716eddbbd23b24f8fef9a8b5..3306b5b3c736b82206cd1e56ee5afd9e11bd5dfa 100644 (file)
@@ -147,9 +147,7 @@ struct s3c_onenand {
        struct resource *dma_res;
        unsigned long   phys_base;
        struct completion       complete;
-#ifdef CONFIG_MTD_PARTITIONS
        struct mtd_partition *parts;
-#endif
 };
 
 #define CMD_MAP_00(dev, addr)          (dev->cmd_map(MAP_00, ((addr) << 1)))
@@ -159,9 +157,7 @@ struct s3c_onenand {
 
 static struct s3c_onenand *onenand;
 
-#ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probes[] = { "cmdlinepart", NULL, };
-#endif
 
 static inline int s3c_read_reg(int offset)
 {
@@ -1021,15 +1017,13 @@ static int s3c_onenand_probe(struct platform_device *pdev)
        if (s3c_read_reg(MEM_CFG_OFFSET) & ONENAND_SYS_CFG1_SYNC_READ)
                dev_info(&onenand->pdev->dev, "OneNAND Sync. Burst Read enabled\n");
 
-#ifdef CONFIG_MTD_PARTITIONS
        err = parse_mtd_partitions(mtd, part_probes, &onenand->parts, 0);
        if (err > 0)
-               add_mtd_partitions(mtd, onenand->parts, err);
+               mtd_device_register(mtd, onenand->parts, err);
        else if (err <= 0 && pdata && pdata->parts)
-               add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts);
+               mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
        else
-#endif
-               err = add_mtd_device(mtd);
+               err = mtd_device_register(mtd, NULL, 0);
 
        platform_set_drvdata(pdev, mtd);
 
index af9fb0ff8210d5b3d34c3a2e788123b2a7745aaf..191f3bb3c41a7440a6cf831655c6431f31ec55f6 100644 (file)
@@ -115,7 +115,7 @@ static int vol_cdev_open(struct inode *inode, struct file *file)
                mode = UBI_READONLY;
 
        dbg_gen("open device %d, volume %d, mode %d",
-               ubi_num, vol_id, mode);
+               ubi_num, vol_id, mode);
 
        desc = ubi_open_volume(ubi_num, vol_id, mode);
        if (IS_ERR(desc))
@@ -158,7 +158,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
        loff_t new_offset;
 
        if (vol->updating) {
-                /* Update is in progress, seeking is prohibited */
+               /* Update is in progress, seeking is prohibited */
                dbg_err("updating");
                return -EBUSY;
        }
@@ -561,18 +561,18 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
        }
 
        /* Set volume property command */
-       case UBI_IOCSETPROP:
+       case UBI_IOCSETVOLPROP:
        {
-               struct ubi_set_prop_req req;
+               struct ubi_set_vol_prop_req req;
 
                err = copy_from_user(&req, argp,
-                               sizeof(struct ubi_set_prop_req));
+                                    sizeof(struct ubi_set_vol_prop_req));
                if (err) {
                        err = -EFAULT;
                        break;
                }
                switch (req.property) {
-               case UBI_PROP_DIRECT_WRITE:
+               case UBI_VOL_PROP_DIRECT_WRITE:
                        mutex_lock(&ubi->device_mutex);
                        desc->vol->direct_writes = !!req.value;
                        mutex_unlock(&ubi->device_mutex);
@@ -1100,5 +1100,5 @@ const struct file_operations ubi_ctrl_cdev_operations = {
        .owner          = THIS_MODULE,
        .unlocked_ioctl = ctrl_cdev_ioctl,
        .compat_ioctl   = ctrl_cdev_compat_ioctl,
-       .llseek         = noop_llseek,
+       .llseek         = no_llseek,
 };
index d4d07e5f138f2ccdd4267d5166ee93647a71873f..2224cbe41ddf5cdab3b67c3dcd1c418c1a691f0b 100644 (file)
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 
-unsigned int ubi_msg_flags;
 unsigned int ubi_chk_flags;
 unsigned int ubi_tst_flags;
 
-module_param_named(debug_msgs, ubi_msg_flags, uint, S_IRUGO | S_IWUSR);
 module_param_named(debug_chks, ubi_chk_flags, uint, S_IRUGO | S_IWUSR);
 module_param_named(debug_tsts, ubi_chk_flags, uint, S_IRUGO | S_IWUSR);
 
-MODULE_PARM_DESC(debug_msgs, "Debug message type flags");
 MODULE_PARM_DESC(debug_chks, "Debug check flags");
 MODULE_PARM_DESC(debug_tsts, "Debug special test flags");
 
@@ -75,15 +72,15 @@ void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
 {
        printk(KERN_DEBUG "Volume identifier header dump:\n");
        printk(KERN_DEBUG "\tmagic     %08x\n", be32_to_cpu(vid_hdr->magic));
-       printk(KERN_DEBUG "\tversion   %d\n",   (int)vid_hdr->version);
-       printk(KERN_DEBUG "\tvol_type  %d\n",   (int)vid_hdr->vol_type);
-       printk(KERN_DEBUG "\tcopy_flag %d\n",   (int)vid_hdr->copy_flag);
-       printk(KERN_DEBUG "\tcompat    %d\n",   (int)vid_hdr->compat);
-       printk(KERN_DEBUG "\tvol_id    %d\n",   be32_to_cpu(vid_hdr->vol_id));
-       printk(KERN_DEBUG "\tlnum      %d\n",   be32_to_cpu(vid_hdr->lnum));
-       printk(KERN_DEBUG "\tdata_size %d\n",   be32_to_cpu(vid_hdr->data_size));
-       printk(KERN_DEBUG "\tused_ebs  %d\n",   be32_to_cpu(vid_hdr->used_ebs));
-       printk(KERN_DEBUG "\tdata_pad  %d\n",   be32_to_cpu(vid_hdr->data_pad));
+       printk(KERN_DEBUG "\tversion   %d\n",  (int)vid_hdr->version);
+       printk(KERN_DEBUG "\tvol_type  %d\n",  (int)vid_hdr->vol_type);
+       printk(KERN_DEBUG "\tcopy_flag %d\n",  (int)vid_hdr->copy_flag);
+       printk(KERN_DEBUG "\tcompat    %d\n",  (int)vid_hdr->compat);
+       printk(KERN_DEBUG "\tvol_id    %d\n",  be32_to_cpu(vid_hdr->vol_id));
+       printk(KERN_DEBUG "\tlnum      %d\n",  be32_to_cpu(vid_hdr->lnum));
+       printk(KERN_DEBUG "\tdata_size %d\n",  be32_to_cpu(vid_hdr->data_size));
+       printk(KERN_DEBUG "\tused_ebs  %d\n",  be32_to_cpu(vid_hdr->used_ebs));
+       printk(KERN_DEBUG "\tdata_pad  %d\n",  be32_to_cpu(vid_hdr->data_pad));
        printk(KERN_DEBUG "\tsqnum     %llu\n",
                (unsigned long long)be64_to_cpu(vid_hdr->sqnum));
        printk(KERN_DEBUG "\thdr_crc   %08x\n", be32_to_cpu(vid_hdr->hdr_crc));
index 0b0c2888c65694e4ca2782340c41da7c1f91cc5d..3f1a09c5c438dde93c11e48529cc2a3cec5d93a7 100644 (file)
 #ifndef __UBI_DEBUG_H__
 #define __UBI_DEBUG_H__
 
+struct ubi_ec_hdr;
+struct ubi_vid_hdr;
+struct ubi_volume;
+struct ubi_vtbl_record;
+struct ubi_scan_volume;
+struct ubi_scan_leb;
+struct ubi_mkvol_req;
+
 #ifdef CONFIG_MTD_UBI_DEBUG
 #include <linux/random.h>
 
-#define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__)
-
 #define ubi_assert(expr)  do {                                               \
        if (unlikely(!(expr))) {                                             \
                printk(KERN_CRIT "UBI assert failed in %s at %u (pid %d)\n", \
        }                                                                    \
 } while (0)
 
-#define dbg_msg(fmt, ...)                                    \
-       printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \
-              current->pid, __func__, ##__VA_ARGS__)
-
-#define dbg_do_msg(typ, fmt, ...) do {                       \
-       if (ubi_msg_flags & typ)                             \
-               dbg_msg(fmt, ##__VA_ARGS__);                 \
-} while (0)
+#define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__)
 
 #define ubi_dbg_dump_stack() dump_stack()
 
-struct ubi_ec_hdr;
-struct ubi_vid_hdr;
-struct ubi_volume;
-struct ubi_vtbl_record;
-struct ubi_scan_volume;
-struct ubi_scan_leb;
-struct ubi_mkvol_req;
+#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a)  \
+               print_hex_dump(l, ps, pt, r, g, b, len, a)
+
+#define ubi_dbg_msg(type, fmt, ...) \
+       pr_debug("UBI DBG " type ": " fmt "\n", ##__VA_ARGS__)
+
+/* Just a debugging messages not related to any specific UBI subsystem */
+#define dbg_msg(fmt, ...) ubi_dbg_msg("msg", fmt, ##__VA_ARGS__)
+/* General debugging messages */
+#define dbg_gen(fmt, ...) ubi_dbg_msg("gen", fmt, ##__VA_ARGS__)
+/* Messages from the eraseblock association sub-system */
+#define dbg_eba(fmt, ...) ubi_dbg_msg("eba", fmt, ##__VA_ARGS__)
+/* Messages from the wear-leveling sub-system */
+#define dbg_wl(fmt, ...)  ubi_dbg_msg("wl", fmt, ##__VA_ARGS__)
+/* Messages from the input/output sub-system */
+#define dbg_io(fmt, ...)  ubi_dbg_msg("io", fmt, ##__VA_ARGS__)
+/* Initialization and build messages */
+#define dbg_bld(fmt, ...) ubi_dbg_msg("bld", fmt, ##__VA_ARGS__)
 
 void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
 void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
@@ -62,43 +72,6 @@ void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
 void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
 void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
 
-extern unsigned int ubi_msg_flags;
-
-/*
- * Debugging message type flags (must match msg_type_names in debug.c).
- *
- * UBI_MSG_GEN: general messages
- * UBI_MSG_EBA: journal messages
- * UBI_MSG_WL: mount messages
- * UBI_MSG_IO: commit messages
- * UBI_MSG_BLD: LEB find messages
- */
-enum {
-       UBI_MSG_GEN  = 0x1,
-       UBI_MSG_EBA  = 0x2,
-       UBI_MSG_WL   = 0x4,
-       UBI_MSG_IO   = 0x8,
-       UBI_MSG_BLD  = 0x10,
-};
-
-#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a)  \
-               print_hex_dump(l, ps, pt, r, g, b, len, a)
-
-/* General debugging messages */
-#define dbg_gen(fmt, ...) dbg_do_msg(UBI_MSG_GEN, fmt, ##__VA_ARGS__)
-
-/* Messages from the eraseblock association sub-system */
-#define dbg_eba(fmt, ...) dbg_do_msg(UBI_MSG_EBA, fmt, ##__VA_ARGS__)
-
-/* Messages from the wear-leveling sub-system */
-#define dbg_wl(fmt, ...) dbg_do_msg(UBI_MSG_WL, fmt, ##__VA_ARGS__)
-
-/* Messages from the input/output sub-system */
-#define dbg_io(fmt, ...) dbg_do_msg(UBI_MSG_IO, fmt, ##__VA_ARGS__)
-
-/* Initialization and build messages */
-#define dbg_bld(fmt, ...) dbg_do_msg(UBI_MSG_BLD, fmt, ##__VA_ARGS__)
-
 extern unsigned int ubi_chk_flags;
 
 /*
@@ -184,31 +157,61 @@ static inline int ubi_dbg_is_erase_failure(void)
 
 #else
 
-#define ubi_assert(expr)                 ({})
-#define dbg_err(fmt, ...)                ({})
-#define dbg_msg(fmt, ...)                ({})
-#define dbg_gen(fmt, ...)                ({})
-#define dbg_eba(fmt, ...)                ({})
-#define dbg_wl(fmt, ...)                 ({})
-#define dbg_io(fmt, ...)                 ({})
-#define dbg_bld(fmt, ...)                ({})
-#define ubi_dbg_dump_stack()             ({})
-#define ubi_dbg_dump_ec_hdr(ec_hdr)      ({})
-#define ubi_dbg_dump_vid_hdr(vid_hdr)    ({})
-#define ubi_dbg_dump_vol_info(vol)       ({})
-#define ubi_dbg_dump_vtbl_record(r, idx) ({})
-#define ubi_dbg_dump_sv(sv)              ({})
-#define ubi_dbg_dump_seb(seb, type)      ({})
-#define ubi_dbg_dump_mkvol_req(req)      ({})
-#define ubi_dbg_dump_flash(ubi, pnum, offset, len) ({})
-#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a)  ({})
-
-#define ubi_dbg_is_bgt_disabled()  0
-#define ubi_dbg_is_bitflip()       0
-#define ubi_dbg_is_write_failure() 0
-#define ubi_dbg_is_erase_failure() 0
-#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
-#define ubi_dbg_check_write(ubi, buf, pnum, offset, len) 0
+/* Use "if (0)" to make compiler check arguments even if debugging is off */
+#define ubi_assert(expr)  do {                                               \
+       if (0) {                                                             \
+               printk(KERN_CRIT "UBI assert failed in %s at %u (pid %d)\n", \
+                      __func__, __LINE__, current->pid);                    \
+       }                                                                    \
+} while (0)
+
+#define dbg_err(fmt, ...) do {                                               \
+       if (0)                                                               \
+               ubi_err(fmt, ##__VA_ARGS__);                                 \
+} while (0)
+
+#define ubi_dbg_msg(fmt, ...) do {                                           \
+       if (0)                                                               \
+               pr_debug(fmt "\n", ##__VA_ARGS__);                           \
+} while (0)
+
+#define dbg_msg(fmt, ...)  ubi_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_gen(fmt, ...)  ubi_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_eba(fmt, ...)  ubi_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_wl(fmt, ...)   ubi_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_io(fmt, ...)   ubi_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_bld(fmt, ...)  ubi_dbg_msg(fmt, ##__VA_ARGS__)
+
+static inline void ubi_dbg_dump_stack(void)                          { return; }
+static inline void
+ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)                 { return; }
+static inline void
+ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)              { return; }
+static inline void
+ubi_dbg_dump_vol_info(const struct ubi_volume *vol)                  { return; }
+static inline void
+ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)   { return; }
+static inline void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv) { return; }
+static inline void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb,
+                                   int type)                        { return; }
+static inline void
+ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)              { return; }
+static inline void ubi_dbg_dump_flash(struct ubi_device *ubi,
+                                     int pnum, int offset, int len) { return; }
+static inline void
+ubi_dbg_print_hex_dump(const char *l, const char *ps, int pt, int r,
+                      int g, const void *b, size_t len, bool a)     { return; }
+
+static inline int ubi_dbg_is_bgt_disabled(void)                    { return 0; }
+static inline int ubi_dbg_is_bitflip(void)                         { return 0; }
+static inline int ubi_dbg_is_write_failure(void)                   { return 0; }
+static inline int ubi_dbg_is_erase_failure(void)                   { return 0; }
+static inline int ubi_dbg_check_all_ff(struct ubi_device *ubi,
+                                      int pnum, int offset,
+                                      int len)                    { return 0; }
+static inline int ubi_dbg_check_write(struct ubi_device *ubi,
+                                     const void *buf, int pnum,
+                                     int offset, int len)         { return 0; }
 
 #endif /* !CONFIG_MTD_UBI_DEBUG */
 #endif /* !__UBI_DEBUG_H__ */
index 9aa81584c8a29dc4afbbba437613c85b51f60ca8..941bc3c05d6e51232eabfbdd6db08a0248bb4328 100644 (file)
@@ -365,7 +365,7 @@ static int gluebi_create(struct ubi_device_info *di,
                        vi->vol_id);
        mutex_unlock(&devices_mutex);
 
-       if (add_mtd_device(mtd)) {
+       if (mtd_device_register(mtd, NULL, 0)) {
                err_msg("cannot add MTD device");
                kfree(mtd->name);
                kfree(gluebi);
@@ -407,7 +407,7 @@ static int gluebi_remove(struct ubi_volume_info *vi)
                return err;
 
        mtd = &gluebi->mtd;
-       err = del_mtd_device(mtd);
+       err = mtd_device_unregister(mtd);
        if (err) {
                err_msg("cannot remove fake MTD device %d, UBI device %d, "
                        "volume %d, error %d", mtd->index, gluebi->ubi_num,
@@ -524,7 +524,7 @@ static void __exit ubi_gluebi_exit(void)
                int err;
                struct mtd_info *mtd = &gluebi->mtd;
 
-               err = del_mtd_device(mtd);
+               err = mtd_device_unregister(mtd);
                if (err)
                        err_msg("error %d while removing gluebi MTD device %d, "
                                "UBI device %d, volume %d - ignoring", err,
index e347cc4388edd5cad5e96d471458a642450f4271..8c1b1c7bc4a7dca93d75ccd2067f1094169b7783 100644 (file)
@@ -189,8 +189,8 @@ retry:
                }
 
                if (retries++ < UBI_IO_RETRIES) {
-                       dbg_io("error %d%s while reading %d bytes from PEB %d:%d,"
-                              " read only %zd bytes, retry",
+                       dbg_io("error %d%s while reading %d bytes from PEB "
+                              "%d:%d, read only %zd bytes, retry",
                               err, errstr, len, pnum, offset, read);
                        yield();
                        goto retry;
@@ -465,7 +465,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
        }
 
        err = patt_count;
-       ubi_msg("PEB %d passed torture test, do not mark it a bad", pnum);
+       ubi_msg("PEB %d passed torture test, do not mark it as bad", pnum);
 
 out:
        mutex_unlock(&ubi->buf_mutex);
index d2d12ab7def427c22cb6303d986ae3206575cb39..2135a53732ffce0dc0b4b7806637449f7ddec1f6 100644 (file)
@@ -1103,7 +1103,7 @@ static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si)
                 * otherwise, only print a warning.
                 */
                if (si->corr_peb_count >= max_corr) {
-                       ubi_err("too many corrupted PEBs, refusing this device");
+                       ubi_err("too many corrupted PEBs, refusing");
                        return -EINVAL;
                }
        }
index 503ea9b273094670d0933baafbfbfb04ae6d88cd..6fb8ec2174a53cd96b1e2646442e7e311d018cc5 100644 (file)
@@ -164,7 +164,7 @@ struct ubi_ec_hdr {
        __be32  image_seq;
        __u8    padding2[32];
        __be32  hdr_crc;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubi_vid_hdr - on-flash UBI volume identifier header.
@@ -292,7 +292,7 @@ struct ubi_vid_hdr {
        __be64  sqnum;
        __u8    padding3[12];
        __be32  hdr_crc;
-} __attribute__ ((packed));
+} __packed;
 
 /* Internal UBI volumes count */
 #define UBI_INT_VOL_COUNT 1
@@ -373,6 +373,6 @@ struct ubi_vtbl_record {
        __u8    flags;
        __u8    padding[23];
        __be32  crc;
-} __attribute__ ((packed));
+} __packed;
 
 #endif /* !__UBI_MEDIA_H__ */
index f1be8b79663cbfc3a5d87828cf8b12c2cd7d4c28..c6c22295898e97ef3fdbfa16fd4171ec650fb55a 100644 (file)
@@ -341,8 +341,8 @@ struct ubi_wl_entry;
  *      protected from the wear-leveling worker)
  * @pq_head: protection queue head
  * @wl_lock: protects the @used, @free, @pq, @pq_head, @lookuptbl, @move_from,
- *          @move_to, @move_to_put @erase_pending, @wl_scheduled, @works,
- *          @erroneous, and @erroneous_peb_count fields
+ *          @move_to, @move_to_put @erase_pending, @wl_scheduled, @works,
+ *          @erroneous, and @erroneous_peb_count fields
  * @move_mutex: serializes eraseblock moves
  * @work_sem: synchronizes the WL worker with use tasks
  * @wl_scheduled: non-zero if the wear-leveling was scheduled
index b4cf57db25561c8323ba97dbccdbc53a50d51306..ff2c4956eeff0aa08bbe0e528151104dd04fba68 100644 (file)
@@ -1570,7 +1570,8 @@ void ubi_wl_close(struct ubi_device *ubi)
  * @ec: the erase counter to check
  *
  * This function returns zero if the erase counter of physical eraseblock @pnum
- * is equivalent to @ec, and a negative error code if not or if an error occurred.
+ * is equivalent to @ec, and a negative error code if not or if an error
+ * occurred.
  */
 static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
 {
index d84f6e8903a58f6334acd9e67d1811823c73ee86..5b732988d49389c9811ae2d5c19c87ebdda92807 100644 (file)
@@ -412,7 +412,7 @@ el2_open(struct net_device *dev)
                outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR);
                outb_p(0x00, E33G_IDCFR);
                msleep(1);
-               free_irq(*irqp, el2_probe_interrupt);
+               free_irq(*irqp, &seen);
                if (!seen)
                        continue;
 
@@ -422,6 +422,7 @@ el2_open(struct net_device *dev)
                        continue;
                if (retval < 0)
                        goto err_disable;
+               break;
        } while (*++irqp);
 
        if (*irqp == 0) {
index 5f25889e27efdafee0941407ab0c39c9f7b1ee36..44b28b2d70039e959811a4c9cfa173ed5c6b7b43 100644 (file)
@@ -185,7 +185,7 @@ static int max_interrupt_work = 10;
 static int nopnp;
 #endif
 
-static int el3_common_init(struct net_device *dev);
+static int __devinit el3_common_init(struct net_device *dev);
 static void el3_common_remove(struct net_device *dev);
 static ushort id_read_eeprom(int index);
 static ushort read_eeprom(int ioaddr, int index);
@@ -395,7 +395,7 @@ static struct isa_driver el3_isa_driver = {
 static int isa_registered;
 
 #ifdef CONFIG_PNP
-static const struct pnp_device_id el3_pnp_ids[] __devinitconst = {
+static struct pnp_device_id el3_pnp_ids[] = {
        { .id = "TCM5090" }, /* 3Com Etherlink III (TP) */
        { .id = "TCM5091" }, /* 3Com Etherlink III */
        { .id = "TCM5094" }, /* 3Com Etherlink III (combo) */
@@ -478,7 +478,7 @@ static int pnp_registered;
 #endif /* CONFIG_PNP */
 
 #ifdef CONFIG_EISA
-static const struct eisa_device_id el3_eisa_ids[] __devinitconst = {
+static struct eisa_device_id el3_eisa_ids[] = {
                { "TCM5090" },
                { "TCM5091" },
                { "TCM5092" },
@@ -508,7 +508,7 @@ static int eisa_registered;
 #ifdef CONFIG_MCA
 static int el3_mca_probe(struct device *dev);
 
-static const short el3_mca_adapter_ids[] __devinitconst = {
+static short el3_mca_adapter_ids[] __initdata = {
                0x627c,
                0x627d,
                0x62db,
@@ -517,7 +517,7 @@ static const short el3_mca_adapter_ids[] __devinitconst = {
                0x0000
 };
 
-static const char *const el3_mca_adapter_names[] __devinitconst = {
+static char *el3_mca_adapter_names[] __initdata = {
                "3Com 3c529 EtherLink III (10base2)",
                "3Com 3c529 EtherLink III (10baseT)",
                "3Com 3c529 EtherLink III (test mode)",
@@ -601,7 +601,7 @@ static void el3_common_remove (struct net_device *dev)
 }
 
 #ifdef CONFIG_MCA
-static int __devinit el3_mca_probe(struct device *device)
+static int __init el3_mca_probe(struct device *device)
 {
        /* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch,
         * heavily modified by Chris Beauregard
@@ -671,7 +671,7 @@ static int __devinit el3_mca_probe(struct device *device)
 #endif /* CONFIG_MCA */
 
 #ifdef CONFIG_EISA
-static int __devinit el3_eisa_probe (struct device *device)
+static int __init el3_eisa_probe (struct device *device)
 {
        short i;
        int ioaddr, irq, if_port;
index 99f43d275442f793e117cc6064d3f894eee6f928..8cc22568ebd3429282b8674b912cb8fe80eb7a03 100644 (file)
@@ -901,14 +901,14 @@ static const struct dev_pm_ops vortex_pm_ops = {
 #endif /* !CONFIG_PM */
 
 #ifdef CONFIG_EISA
-static const struct eisa_device_id vortex_eisa_ids[] __devinitconst = {
+static struct eisa_device_id vortex_eisa_ids[] = {
        { "TCM5920", CH_3C592 },
        { "TCM5970", CH_3C597 },
        { "" }
 };
 MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids);
 
-static int __devinit vortex_eisa_probe(struct device *device)
+static int __init vortex_eisa_probe(struct device *device)
 {
        void __iomem *ioaddr;
        struct eisa_device *edev;
index 209fbb70619b8be9e5f6d6c871b82a88d86833fa..776a478e6296e3bd92656fcd1bc6729288b5dc77 100644 (file)
@@ -31,6 +31,7 @@ obj-$(CONFIG_ATL2) += atlx/
 obj-$(CONFIG_ATL1E) += atl1e/
 obj-$(CONFIG_ATL1C) += atl1c/
 obj-$(CONFIG_GIANFAR) += gianfar_driver.o
+obj-$(CONFIG_PTP_1588_CLOCK_GIANFAR) += gianfar_ptp.o
 obj-$(CONFIG_TEHUTI) += tehuti.o
 obj-$(CONFIG_ENIC) += enic/
 obj-$(CONFIG_JME) += jme.o
index 0c9217f48b72060d77c6ac20eaa592011cb4a009..7b3e23f38913657896b833a73d7c679b1723558a 100644 (file)
@@ -50,7 +50,7 @@ static const char version[] =
 #ifdef __arm__
 static void write_rreg(u_long base, u_int reg, u_int val)
 {
-       __asm__(
+       asm volatile(
        "str%?h %1, [%2]        @ NET_RAP\n\t"
        "str%?h %0, [%2, #-4]   @ NET_RDP"
        :
@@ -60,7 +60,7 @@ static void write_rreg(u_long base, u_int reg, u_int val)
 static inline unsigned short read_rreg(u_long base_addr, u_int reg)
 {
        unsigned short v;
-       __asm__(
+       asm volatile(
        "str%?h %1, [%2]        @ NET_RAP\n\t"
        "ldr%?h %0, [%2, #-4]   @ NET_RDP"
        : "=r" (v)
@@ -70,7 +70,7 @@ static inline unsigned short read_rreg(u_long base_addr, u_int reg)
 
 static inline void write_ireg(u_long base, u_int reg, u_int val)
 {
-       __asm__(
+       asm volatile(
        "str%?h %1, [%2]        @ NET_RAP\n\t"
        "str%?h %0, [%2, #8]    @ NET_IDP"
        :
@@ -80,7 +80,7 @@ static inline void write_ireg(u_long base, u_int reg, u_int val)
 static inline unsigned short read_ireg(u_long base_addr, u_int reg)
 {
        u_short v;
-       __asm__(
+       asm volatile(
        "str%?h %1, [%2]        @ NAT_RAP\n\t"
        "ldr%?h %0, [%2, #8]    @ NET_IDP\n\t"
        : "=r" (v)
@@ -91,47 +91,48 @@ static inline unsigned short read_ireg(u_long base_addr, u_int reg)
 #define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1))
 #define am_readword(dev,off)      __raw_readw(ISAMEM_BASE + ((off) << 1))
 
-static inline void
+static void
 am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
 {
        offset = ISAMEM_BASE + (offset << 1);
        length = (length + 1) & ~1;
        if ((int)buf & 2) {
-               __asm__ __volatile__("str%?h    %2, [%0], #4"
+               asm volatile("str%?h    %2, [%0], #4"
                 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
                buf += 2;
                length -= 2;
        }
        while (length > 8) {
-               unsigned int tmp, tmp2;
-               __asm__ __volatile__(
-                       "ldm%?ia        %1!, {%2, %3}\n\t"
+               register unsigned int tmp asm("r2"), tmp2 asm("r3");
+               asm volatile(
+                       "ldm%?ia        %0!, {%1, %2}"
+                       : "+r" (buf), "=&r" (tmp), "=&r" (tmp2));
+               length -= 8;
+               asm volatile(
+                       "str%?h %1, [%0], #4\n\t"
+                       "mov%?  %1, %1, lsr #16\n\t"
+                       "str%?h %1, [%0], #4\n\t"
                        "str%?h %2, [%0], #4\n\t"
                        "mov%?  %2, %2, lsr #16\n\t"
-                       "str%?h %2, [%0], #4\n\t"
-                       "str%?h %3, [%0], #4\n\t"
-                       "mov%?  %3, %3, lsr #16\n\t"
-                       "str%?h %3, [%0], #4"
-               : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2)
-               : "0" (offset), "1" (buf));
-               length -= 8;
+                       "str%?h %2, [%0], #4"
+               : "+r" (offset), "=&r" (tmp), "=&r" (tmp2));
        }
        while (length > 0) {
-               __asm__ __volatile__("str%?h    %2, [%0], #4"
+               asm volatile("str%?h    %2, [%0], #4"
                 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
                buf += 2;
                length -= 2;
        }
 }
 
-static inline void
+static void
 am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
 {
        offset = ISAMEM_BASE + (offset << 1);
        length = (length + 1) & ~1;
        if ((int)buf & 2) {
                unsigned int tmp;
-               __asm__ __volatile__(
+               asm volatile(
                        "ldr%?h %2, [%0], #4\n\t"
                        "str%?b %2, [%1], #1\n\t"
                        "mov%?  %2, %2, lsr #8\n\t"
@@ -140,12 +141,12 @@ am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned
                length -= 2;
        }
        while (length > 8) {
-               unsigned int tmp, tmp2, tmp3;
-               __asm__ __volatile__(
+               register unsigned int tmp asm("r2"), tmp2 asm("r3"), tmp3;
+               asm volatile(
                        "ldr%?h %2, [%0], #4\n\t"
+                       "ldr%?h %4, [%0], #4\n\t"
                        "ldr%?h %3, [%0], #4\n\t"
-                       "orr%?  %2, %2, %3, lsl #16\n\t"
-                       "ldr%?h %3, [%0], #4\n\t"
+                       "orr%?  %2, %2, %4, lsl #16\n\t"
                        "ldr%?h %4, [%0], #4\n\t"
                        "orr%?  %3, %3, %4, lsl #16\n\t"
                        "stm%?ia        %1!, {%2, %3}"
@@ -155,7 +156,7 @@ am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned
        }
        while (length > 0) {
                unsigned int tmp;
-               __asm__ __volatile__(
+               asm volatile(
                        "ldr%?h %2, [%0], #4\n\t"
                        "str%?b %2, [%1], #1\n\t"
                        "mov%?  %2, %2, lsr #8\n\t"
@@ -196,6 +197,42 @@ am79c961_ramtest(struct net_device *dev, unsigned int val)
        return errorcount;
 }
 
+static void am79c961_mc_hash(char *addr, u16 *hash)
+{
+       if (addr[0] & 0x01) {
+               int idx, bit;
+               u32 crc;
+
+               crc = ether_crc_le(ETH_ALEN, addr);
+
+               idx = crc >> 30;
+               bit = (crc >> 26) & 15;
+
+               hash[idx] |= 1 << bit;
+       }
+}
+
+static unsigned int am79c961_get_rx_mode(struct net_device *dev, u16 *hash)
+{
+       unsigned int mode = MODE_PORT_10BT;
+
+       if (dev->flags & IFF_PROMISC) {
+               mode |= MODE_PROMISC;
+               memset(hash, 0xff, 4 * sizeof(*hash));
+       } else if (dev->flags & IFF_ALLMULTI) {
+               memset(hash, 0xff, 4 * sizeof(*hash));
+       } else {
+               struct netdev_hw_addr *ha;
+
+               memset(hash, 0, 4 * sizeof(*hash));
+
+               netdev_for_each_mc_addr(ha, dev)
+                       am79c961_mc_hash(ha->addr, hash);
+       }
+
+       return mode;
+}
+
 static void
 am79c961_init_for_open(struct net_device *dev)
 {
@@ -203,6 +240,7 @@ am79c961_init_for_open(struct net_device *dev)
        unsigned long flags;
        unsigned char *p;
        u_int hdr_addr, first_free_addr;
+       u16 multi_hash[4], mode = am79c961_get_rx_mode(dev, multi_hash);
        int i;
 
        /*
@@ -218,16 +256,12 @@ am79c961_init_for_open(struct net_device *dev)
        write_ireg (dev->base_addr, 2, 0x0000); /* MODE register selects media */
 
        for (i = LADRL; i <= LADRH; i++)
-               write_rreg (dev->base_addr, i, 0);
+               write_rreg (dev->base_addr, i, multi_hash[i - LADRL]);
 
        for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2)
                write_rreg (dev->base_addr, i, p[0] | (p[1] << 8));
 
-       i = MODE_PORT_10BT;
-       if (dev->flags & IFF_PROMISC)
-               i |= MODE_PROMISC;
-
-       write_rreg (dev->base_addr, MODE, i);
+       write_rreg (dev->base_addr, MODE, mode);
        write_rreg (dev->base_addr, POLLINT, 0);
        write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS);
        write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS);
@@ -340,21 +374,6 @@ am79c961_close(struct net_device *dev)
        return 0;
 }
 
-static void am79c961_mc_hash(char *addr, unsigned short *hash)
-{
-       if (addr[0] & 0x01) {
-               int idx, bit;
-               u32 crc;
-
-               crc = ether_crc_le(ETH_ALEN, addr);
-
-               idx = crc >> 30;
-               bit = (crc >> 26) & 15;
-
-               hash[idx] |= 1 << bit;
-       }
-}
-
 /*
  * Set or clear promiscuous/multicast mode filter for this adapter.
  */
@@ -362,24 +381,9 @@ static void am79c961_setmulticastlist (struct net_device *dev)
 {
        struct dev_priv *priv = netdev_priv(dev);
        unsigned long flags;
-       unsigned short multi_hash[4], mode;
+       u16 multi_hash[4], mode = am79c961_get_rx_mode(dev, multi_hash);
        int i, stopped;
 
-       mode = MODE_PORT_10BT;
-
-       if (dev->flags & IFF_PROMISC) {
-               mode |= MODE_PROMISC;
-       } else if (dev->flags & IFF_ALLMULTI) {
-               memset(multi_hash, 0xff, sizeof(multi_hash));
-       } else {
-               struct netdev_hw_addr *ha;
-
-               memset(multi_hash, 0x00, sizeof(multi_hash));
-
-               netdev_for_each_mc_addr(ha, dev)
-                       am79c961_mc_hash(ha->addr, multi_hash);
-       }
-
        spin_lock_irqsave(&priv->chip_lock, flags);
 
        stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP;
index 5a77001b6d1053d4898b4635b0f1b9d1357e5868..0b46b8ea0e8006fa1456125752a006cd0e9dba8c 100644 (file)
@@ -283,10 +283,14 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget)
 
                skb = dev_alloc_skb(length + 2);
                if (likely(skb != NULL)) {
+                       struct ep93xx_rdesc *rxd = &ep->descs->rdesc[entry];
                        skb_reserve(skb, 2);
-                       dma_sync_single_for_cpu(NULL, ep->descs->rdesc[entry].buf_addr,
+                       dma_sync_single_for_cpu(dev->dev.parent, rxd->buf_addr,
                                                length, DMA_FROM_DEVICE);
                        skb_copy_to_linear_data(skb, ep->rx_buf[entry], length);
+                       dma_sync_single_for_device(dev->dev.parent,
+                                                  rxd->buf_addr, length,
+                                                  DMA_FROM_DEVICE);
                        skb_put(skb, length);
                        skb->protocol = eth_type_trans(skb, dev);
 
@@ -348,6 +352,7 @@ poll_some_more:
 static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ep93xx_priv *ep = netdev_priv(dev);
+       struct ep93xx_tdesc *txd;
        int entry;
 
        if (unlikely(skb->len > MAX_PKT_SIZE)) {
@@ -359,11 +364,14 @@ static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev)
        entry = ep->tx_pointer;
        ep->tx_pointer = (ep->tx_pointer + 1) & (TX_QUEUE_ENTRIES - 1);
 
-       ep->descs->tdesc[entry].tdesc1 =
-               TDESC1_EOF | (entry << 16) | (skb->len & 0xfff);
+       txd = &ep->descs->tdesc[entry];
+
+       txd->tdesc1 = TDESC1_EOF | (entry << 16) | (skb->len & 0xfff);
+       dma_sync_single_for_cpu(dev->dev.parent, txd->buf_addr, skb->len,
+                               DMA_TO_DEVICE);
        skb_copy_and_csum_dev(skb, ep->tx_buf[entry]);
-       dma_sync_single_for_cpu(NULL, ep->descs->tdesc[entry].buf_addr,
-                               skb->len, DMA_TO_DEVICE);
+       dma_sync_single_for_device(dev->dev.parent, txd->buf_addr, skb->len,
+                                  DMA_TO_DEVICE);
        dev_kfree_skb(skb);
 
        spin_lock_irq(&ep->tx_pending_lock);
@@ -457,89 +465,80 @@ static irqreturn_t ep93xx_irq(int irq, void *dev_id)
 
 static void ep93xx_free_buffers(struct ep93xx_priv *ep)
 {
+       struct device *dev = ep->dev->dev.parent;
        int i;
 
-       for (i = 0; i < RX_QUEUE_ENTRIES; i += 2) {
+       for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
                dma_addr_t d;
 
                d = ep->descs->rdesc[i].buf_addr;
                if (d)
-                       dma_unmap_single(NULL, d, PAGE_SIZE, DMA_FROM_DEVICE);
+                       dma_unmap_single(dev, d, PKT_BUF_SIZE, DMA_FROM_DEVICE);
 
                if (ep->rx_buf[i] != NULL)
-                       free_page((unsigned long)ep->rx_buf[i]);
+                       kfree(ep->rx_buf[i]);
        }
 
-       for (i = 0; i < TX_QUEUE_ENTRIES; i += 2) {
+       for (i = 0; i < TX_QUEUE_ENTRIES; i++) {
                dma_addr_t d;
 
                d = ep->descs->tdesc[i].buf_addr;
                if (d)
-                       dma_unmap_single(NULL, d, PAGE_SIZE, DMA_TO_DEVICE);
+                       dma_unmap_single(dev, d, PKT_BUF_SIZE, DMA_TO_DEVICE);
 
                if (ep->tx_buf[i] != NULL)
-                       free_page((unsigned long)ep->tx_buf[i]);
+                       kfree(ep->tx_buf[i]);
        }
 
-       dma_free_coherent(NULL, sizeof(struct ep93xx_descs), ep->descs,
+       dma_free_coherent(dev, sizeof(struct ep93xx_descs), ep->descs,
                                                        ep->descs_dma_addr);
 }
 
-/*
- * The hardware enforces a sub-2K maximum packet size, so we put
- * two buffers on every hardware page.
- */
 static int ep93xx_alloc_buffers(struct ep93xx_priv *ep)
 {
+       struct device *dev = ep->dev->dev.parent;
        int i;
 
-       ep->descs = dma_alloc_coherent(NULL, sizeof(struct ep93xx_descs),
-                               &ep->descs_dma_addr, GFP_KERNEL | GFP_DMA);
+       ep->descs = dma_alloc_coherent(dev, sizeof(struct ep93xx_descs),
+                               &ep->descs_dma_addr, GFP_KERNEL);
        if (ep->descs == NULL)
                return 1;
 
-       for (i = 0; i < RX_QUEUE_ENTRIES; i += 2) {
-               void *page;
+       for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
+               void *buf;
                dma_addr_t d;
 
-               page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
-               if (page == NULL)
+               buf = kmalloc(PKT_BUF_SIZE, GFP_KERNEL);
+               if (buf == NULL)
                        goto err;
 
-               d = dma_map_single(NULL, page, PAGE_SIZE, DMA_FROM_DEVICE);
-               if (dma_mapping_error(NULL, d)) {
-                       free_page((unsigned long)page);
+               d = dma_map_single(dev, buf, PKT_BUF_SIZE, DMA_FROM_DEVICE);
+               if (dma_mapping_error(dev, d)) {
+                       kfree(buf);
                        goto err;
                }
 
-               ep->rx_buf[i] = page;
+               ep->rx_buf[i] = buf;
                ep->descs->rdesc[i].buf_addr = d;
                ep->descs->rdesc[i].rdesc1 = (i << 16) | PKT_BUF_SIZE;
-
-               ep->rx_buf[i + 1] = page + PKT_BUF_SIZE;
-               ep->descs->rdesc[i + 1].buf_addr = d + PKT_BUF_SIZE;
-               ep->descs->rdesc[i + 1].rdesc1 = ((i + 1) << 16) | PKT_BUF_SIZE;
        }
 
-       for (i = 0; i < TX_QUEUE_ENTRIES; i += 2) {
-               void *page;
+       for (i = 0; i < TX_QUEUE_ENTRIES; i++) {
+               void *buf;
                dma_addr_t d;
 
-               page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
-               if (page == NULL)
+               buf = kmalloc(PKT_BUF_SIZE, GFP_KERNEL);
+               if (buf == NULL)
                        goto err;
 
-               d = dma_map_single(NULL, page, PAGE_SIZE, DMA_TO_DEVICE);
-               if (dma_mapping_error(NULL, d)) {
-                       free_page((unsigned long)page);
+               d = dma_map_single(dev, buf, PKT_BUF_SIZE, DMA_TO_DEVICE);
+               if (dma_mapping_error(dev, d)) {
+                       kfree(buf);
                        goto err;
                }
 
-               ep->tx_buf[i] = page;
+               ep->tx_buf[i] = buf;
                ep->descs->tdesc[i].buf_addr = d;
-
-               ep->tx_buf[i + 1] = page + PKT_BUF_SIZE;
-               ep->descs->tdesc[i + 1].buf_addr = d + PKT_BUF_SIZE;
        }
 
        return 0;
@@ -829,6 +828,7 @@ static int ep93xx_eth_probe(struct platform_device *pdev)
        }
        ep = netdev_priv(dev);
        ep->dev = dev;
+       SET_NETDEV_DEV(dev, &pdev->dev);
        netif_napi_add(dev, &ep->napi, ep93xx_poll, 64);
 
        platform_set_drvdata(pdev, dev);
index 9eb9b98a7ae3fd81f208b7495857db73ebb1f94d..de51e8453c133700a6c1e06087c7f00625cf1d07 100644 (file)
 #include <linux/etherdevice.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
+#include <linux/net_tstamp.h>
 #include <linux/phy.h>
 #include <linux/platform_device.h>
+#include <linux/ptp_classify.h>
 #include <linux/slab.h>
+#include <mach/ixp46x_ts.h>
 #include <mach/npe.h>
 #include <mach/qmgr.h>
 
 #define RXFREE_QUEUE(port_id)  (NPE_ID(port_id) + 26)
 #define TXDONE_QUEUE           31
 
+#define PTP_SLAVE_MODE         1
+#define PTP_MASTER_MODE                2
+#define PORT2CHANNEL(p)                NPE_ID(p->id)
+
 /* TX Control Registers */
 #define TX_CNTRL0_TX_EN                0x01
 #define TX_CNTRL0_HALFDUPLEX   0x02
@@ -171,6 +178,8 @@ struct port {
        int id;                 /* logical port ID */
        int speed, duplex;
        u8 firmware[4];
+       int hwts_tx_en;
+       int hwts_rx_en;
 };
 
 /* NPE message structure */
@@ -246,6 +255,172 @@ static int ports_open;
 static struct port *npe_port_tab[MAX_NPES];
 static struct dma_pool *dma_pool;
 
+static struct sock_filter ptp_filter[] = {
+       PTP_FILTER
+};
+
+static int ixp_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
+{
+       u8 *data = skb->data;
+       unsigned int offset;
+       u16 *hi, *id;
+       u32 lo;
+
+       if (sk_run_filter(skb, ptp_filter) != PTP_CLASS_V1_IPV4)
+               return 0;
+
+       offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
+
+       if (skb->len < offset + OFF_PTP_SEQUENCE_ID + sizeof(seqid))
+               return 0;
+
+       hi = (u16 *)(data + offset + OFF_PTP_SOURCE_UUID);
+       id = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID);
+
+       memcpy(&lo, &hi[1], sizeof(lo));
+
+       return (uid_hi == ntohs(*hi) &&
+               uid_lo == ntohl(lo) &&
+               seqid  == ntohs(*id));
+}
+
+static void ixp_rx_timestamp(struct port *port, struct sk_buff *skb)
+{
+       struct skb_shared_hwtstamps *shhwtstamps;
+       struct ixp46x_ts_regs *regs;
+       u64 ns;
+       u32 ch, hi, lo, val;
+       u16 uid, seq;
+
+       if (!port->hwts_rx_en)
+               return;
+
+       ch = PORT2CHANNEL(port);
+
+       regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
+
+       val = __raw_readl(&regs->channel[ch].ch_event);
+
+       if (!(val & RX_SNAPSHOT_LOCKED))
+               return;
+
+       lo = __raw_readl(&regs->channel[ch].src_uuid_lo);
+       hi = __raw_readl(&regs->channel[ch].src_uuid_hi);
+
+       uid = hi & 0xffff;
+       seq = (hi >> 16) & 0xffff;
+
+       if (!ixp_ptp_match(skb, htons(uid), htonl(lo), htons(seq)))
+               goto out;
+
+       lo = __raw_readl(&regs->channel[ch].rx_snap_lo);
+       hi = __raw_readl(&regs->channel[ch].rx_snap_hi);
+       ns = ((u64) hi) << 32;
+       ns |= lo;
+       ns <<= TICKS_NS_SHIFT;
+
+       shhwtstamps = skb_hwtstamps(skb);
+       memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+       shhwtstamps->hwtstamp = ns_to_ktime(ns);
+out:
+       __raw_writel(RX_SNAPSHOT_LOCKED, &regs->channel[ch].ch_event);
+}
+
+static void ixp_tx_timestamp(struct port *port, struct sk_buff *skb)
+{
+       struct skb_shared_hwtstamps shhwtstamps;
+       struct ixp46x_ts_regs *regs;
+       struct skb_shared_info *shtx;
+       u64 ns;
+       u32 ch, cnt, hi, lo, val;
+
+       shtx = skb_shinfo(skb);
+       if (unlikely(shtx->tx_flags & SKBTX_HW_TSTAMP && port->hwts_tx_en))
+               shtx->tx_flags |= SKBTX_IN_PROGRESS;
+       else
+               return;
+
+       ch = PORT2CHANNEL(port);
+
+       regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
+
+       /*
+        * This really stinks, but we have to poll for the Tx time stamp.
+        * Usually, the time stamp is ready after 4 to 6 microseconds.
+        */
+       for (cnt = 0; cnt < 100; cnt++) {
+               val = __raw_readl(&regs->channel[ch].ch_event);
+               if (val & TX_SNAPSHOT_LOCKED)
+                       break;
+               udelay(1);
+       }
+       if (!(val & TX_SNAPSHOT_LOCKED)) {
+               shtx->tx_flags &= ~SKBTX_IN_PROGRESS;
+               return;
+       }
+
+       lo = __raw_readl(&regs->channel[ch].tx_snap_lo);
+       hi = __raw_readl(&regs->channel[ch].tx_snap_hi);
+       ns = ((u64) hi) << 32;
+       ns |= lo;
+       ns <<= TICKS_NS_SHIFT;
+
+       memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+       shhwtstamps.hwtstamp = ns_to_ktime(ns);
+       skb_tstamp_tx(skb, &shhwtstamps);
+
+       __raw_writel(TX_SNAPSHOT_LOCKED, &regs->channel[ch].ch_event);
+}
+
+static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+       struct hwtstamp_config cfg;
+       struct ixp46x_ts_regs *regs;
+       struct port *port = netdev_priv(netdev);
+       int ch;
+
+       if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
+               return -EFAULT;
+
+       if (cfg.flags) /* reserved for future extensions */
+               return -EINVAL;
+
+       ch = PORT2CHANNEL(port);
+       regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
+
+       switch (cfg.tx_type) {
+       case HWTSTAMP_TX_OFF:
+               port->hwts_tx_en = 0;
+               break;
+       case HWTSTAMP_TX_ON:
+               port->hwts_tx_en = 1;
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       switch (cfg.rx_filter) {
+       case HWTSTAMP_FILTER_NONE:
+               port->hwts_rx_en = 0;
+               break;
+       case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+               port->hwts_rx_en = PTP_SLAVE_MODE;
+               __raw_writel(0, &regs->channel[ch].ch_control);
+               break;
+       case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+               port->hwts_rx_en = PTP_MASTER_MODE;
+               __raw_writel(MASTER_MODE, &regs->channel[ch].ch_control);
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       /* Clear out any old time stamps. */
+       __raw_writel(TX_SNAPSHOT_LOCKED | RX_SNAPSHOT_LOCKED,
+                    &regs->channel[ch].ch_event);
+
+       return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+}
 
 static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location,
                           int write, u16 cmd)
@@ -573,6 +748,7 @@ static int eth_poll(struct napi_struct *napi, int budget)
 
                debug_pkt(dev, "eth_poll", skb->data, skb->len);
 
+               ixp_rx_timestamp(port, skb);
                skb->protocol = eth_type_trans(skb, dev);
                dev->stats.rx_packets++;
                dev->stats.rx_bytes += skb->len;
@@ -679,14 +855,12 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
                return NETDEV_TX_OK;
        }
        memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4);
-       dev_kfree_skb(skb);
 #endif
 
        phys = dma_map_single(&dev->dev, mem, bytes, DMA_TO_DEVICE);
        if (dma_mapping_error(&dev->dev, phys)) {
-#ifdef __ARMEB__
                dev_kfree_skb(skb);
-#else
+#ifndef __ARMEB__
                kfree(mem);
 #endif
                dev->stats.tx_dropped++;
@@ -728,6 +902,13 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
 #if DEBUG_TX
        printk(KERN_DEBUG "%s: eth_xmit end\n", dev->name);
 #endif
+
+       ixp_tx_timestamp(port, skb);
+       skb_tx_timestamp(skb);
+
+#ifndef __ARMEB__
+       dev_kfree_skb(skb);
+#endif
        return NETDEV_TX_OK;
 }
 
@@ -783,6 +964,9 @@ static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
        if (!netif_running(dev))
                return -EINVAL;
 
+       if (cpu_is_ixp46x() && cmd == SIOCSHWTSTAMP)
+               return hwtstamp_ioctl(dev, req, cmd);
+
        return phy_mii_ioctl(port->phydev, req, cmd);
 }
 
@@ -1171,6 +1355,11 @@ static int __devinit eth_init_one(struct platform_device *pdev)
        char phy_id[MII_BUS_ID_SIZE + 3];
        int err;
 
+       if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) {
+               pr_err("ixp4xx_eth: bad ptp filter\n");
+               return -EINVAL;
+       }
+
        if (!(dev = alloc_etherdev(sizeof(struct port))))
                return -ENOMEM;
 
index 2463b1c979227b5c5320ba3c788728a5325f7c2f..81654ae16c63b99627046b4836e25ab0b1a05115 100644 (file)
@@ -1703,7 +1703,8 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_rss_config *req;
-       u32 myhash[10];
+       u32 myhash[10] = {0x0123, 0x4567, 0x89AB, 0xCDEF, 0x01EF,
+                       0x0123, 0x4567, 0x89AB, 0xCDEF, 0x01EF};
        int status;
 
        if (mutex_lock_interruptible(&adapter->mbox_lock))
index 68d45ba2d9b9a0844c0c1691a31e07bf7374168b..6c019e14854691ab70ebece126dcf0e8cf0d4195 100644 (file)
@@ -52,13 +52,13 @@ MODULE_DESCRIPTION(DRV_DESC);
 MODULE_ALIAS("platform:bfin_mac");
 
 #if defined(CONFIG_BFIN_MAC_USE_L1)
-# define bfin_mac_alloc(dma_handle, size)  l1_data_sram_zalloc(size)
-# define bfin_mac_free(dma_handle, ptr)    l1_data_sram_free(ptr)
+# define bfin_mac_alloc(dma_handle, size, num)  l1_data_sram_zalloc(size*num)
+# define bfin_mac_free(dma_handle, ptr, num)    l1_data_sram_free(ptr)
 #else
-# define bfin_mac_alloc(dma_handle, size) \
-       dma_alloc_coherent(NULL, size, dma_handle, GFP_KERNEL)
-# define bfin_mac_free(dma_handle, ptr) \
-       dma_free_coherent(NULL, sizeof(*ptr), ptr, dma_handle)
+# define bfin_mac_alloc(dma_handle, size, num) \
+       dma_alloc_coherent(NULL, size*num, dma_handle, GFP_KERNEL)
+# define bfin_mac_free(dma_handle, ptr, num) \
+       dma_free_coherent(NULL, sizeof(*ptr)*num, ptr, dma_handle)
 #endif
 
 #define PKT_BUF_SZ 1580
@@ -95,7 +95,7 @@ static void desc_list_free(void)
                                t = t->next;
                        }
                }
-               bfin_mac_free(dma_handle, tx_desc);
+               bfin_mac_free(dma_handle, tx_desc, CONFIG_BFIN_TX_DESC_NUM);
        }
 
        if (rx_desc) {
@@ -109,7 +109,7 @@ static void desc_list_free(void)
                                r = r->next;
                        }
                }
-               bfin_mac_free(dma_handle, rx_desc);
+               bfin_mac_free(dma_handle, rx_desc, CONFIG_BFIN_RX_DESC_NUM);
        }
 }
 
@@ -126,13 +126,13 @@ static int desc_list_init(void)
 #endif
 
        tx_desc = bfin_mac_alloc(&dma_handle,
-                               sizeof(struct net_dma_desc_tx) *
+                               sizeof(struct net_dma_desc_tx),
                                CONFIG_BFIN_TX_DESC_NUM);
        if (tx_desc == NULL)
                goto init_error;
 
        rx_desc = bfin_mac_alloc(&dma_handle,
-                               sizeof(struct net_dma_desc_rx) *
+                               sizeof(struct net_dma_desc_rx),
                                CONFIG_BFIN_RX_DESC_NUM);
        if (rx_desc == NULL)
                goto init_error;
index d5bd35b7f2e1c9e14925239c94adea1021083680..289044332ed8127f27990341114777dfd1376344 100644 (file)
@@ -2675,7 +2675,7 @@ alloc_mem_err:
         * Min size diferent for TPA and non-TPA queues
         */
        if (ring_size < (fp->disable_tpa ?
-                               MIN_RX_SIZE_TPA : MIN_RX_SIZE_NONTPA)) {
+                               MIN_RX_SIZE_NONTPA : MIN_RX_SIZE_TPA)) {
                        /* release memory allocated for this queue */
                        bnx2x_free_fp_mem_at(bp, index);
                        return -ENOMEM;
index a97d9be331d10e1b4d0b8c3c464e58abfd2b1cc5..4b70311a11ef9f4a3ff5b631585f0d8bded19984 100644 (file)
@@ -2222,12 +2222,13 @@ static void bnx2x_pmf_update(struct bnx2x *bp)
 u32 bnx2x_fw_command(struct bnx2x *bp, u32 command, u32 param)
 {
        int mb_idx = BP_FW_MB_IDX(bp);
-       u32 seq = ++bp->fw_seq;
+       u32 seq;
        u32 rc = 0;
        u32 cnt = 1;
        u8 delay = CHIP_REV_IS_SLOW(bp) ? 100 : 10;
 
        mutex_lock(&bp->fw_mb_mutex);
+       seq = ++bp->fw_seq;
        SHMEM_WR(bp, func_mb[mb_idx].drv_mb_param, param);
        SHMEM_WR(bp, func_mb[mb_idx].drv_mb_header, (command | seq));
 
index 8f2d2e7c70e5d2d24ff36a864f528eb6da5f6bc5..2df9276720a0be47f27f909518fd270e531bd535 100644 (file)
@@ -163,8 +163,6 @@ static int tlb_initialize(struct bonding *bond)
        struct tlb_client_info *new_hashtbl;
        int i;
 
-       spin_lock_init(&(bond_info->tx_hashtbl_lock));
-
        new_hashtbl = kzalloc(size, GFP_KERNEL);
        if (!new_hashtbl) {
                pr_err("%s: Error: Failed to allocate TLB hash table\n",
@@ -747,8 +745,6 @@ static int rlb_initialize(struct bonding *bond)
        int size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info);
        int i;
 
-       spin_lock_init(&(bond_info->rx_hashtbl_lock));
-
        new_hashtbl = kmalloc(size, GFP_KERNEL);
        if (!new_hashtbl) {
                pr_err("%s: Error: Failed to allocate RLB hash table\n",
index 6dc4284615419d289a98bd1769108461d0c1ddcd..eafe44a528ac015c8edddec6b0650a9eb526449c 100644 (file)
@@ -113,9 +113,11 @@ MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
 module_param(tx_queues, int, 0);
 MODULE_PARM_DESC(tx_queues, "Max number of transmit queues (default = 16)");
 module_param_named(num_grat_arp, num_peer_notif, int, 0644);
-MODULE_PARM_DESC(num_grat_arp, "Number of peer notifications to send on failover event (alias of num_unsol_na)");
+MODULE_PARM_DESC(num_grat_arp, "Number of peer notifications to send on "
+                              "failover event (alias of num_unsol_na)");
 module_param_named(num_unsol_na, num_peer_notif, int, 0644);
-MODULE_PARM_DESC(num_unsol_na, "Number of peer notifications to send on failover event (alias of num_grat_arp)");
+MODULE_PARM_DESC(num_unsol_na, "Number of peer notifications to send on "
+                              "failover event (alias of num_grat_arp)");
 module_param(miimon, int, 0);
 MODULE_PARM_DESC(miimon, "Link check interval in milliseconds");
 module_param(updelay, int, 0);
@@ -127,7 +129,7 @@ module_param(use_carrier, int, 0);
 MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; "
                              "0 for off, 1 for on (default)");
 module_param(mode, charp, 0);
-MODULE_PARM_DESC(mode, "Mode of operation : 0 for balance-rr, "
+MODULE_PARM_DESC(mode, "Mode of operation; 0 for balance-rr, "
                       "1 for active-backup, 2 for balance-xor, "
                       "3 for broadcast, 4 for 802.3ad, 5 for balance-tlb, "
                       "6 for balance-alb");
@@ -142,27 +144,35 @@ MODULE_PARM_DESC(primary_reselect, "Reselect primary slave "
                                   "2 for only on active slave "
                                   "failure");
 module_param(lacp_rate, charp, 0);
-MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner "
-                           "(slow/fast)");
+MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner; "
+                           "0 for slow, 1 for fast");
 module_param(ad_select, charp, 0);
-MODULE_PARM_DESC(ad_select, "803.ad aggregation selection logic: stable (0, default), bandwidth (1), count (2)");
+MODULE_PARM_DESC(ad_select, "803.ad aggregation selection logic; "
+                           "0 for stable (default), 1 for bandwidth, "
+                           "2 for count");
 module_param(xmit_hash_policy, charp, 0);
-MODULE_PARM_DESC(xmit_hash_policy, "XOR hashing method: 0 for layer 2 (default)"
-                                  ", 1 for layer 3+4");
+MODULE_PARM_DESC(xmit_hash_policy, "balance-xor and 802.3ad hashing method; "
+                                  "0 for layer 2 (default), 1 for layer 3+4, "
+                                  "2 for layer 2+3");
 module_param(arp_interval, int, 0);
 MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");
 module_param_array(arp_ip_target, charp, NULL, 0);
 MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
 module_param(arp_validate, charp, 0);
-MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all");
+MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes; "
+                              "0 for none (default), 1 for active, "
+                              "2 for backup, 3 for all");
 module_param(fail_over_mac, charp, 0);
-MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC.  none (default), active or follow");
+MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to "
+                               "the same MAC; 0 for none (default), "
+                               "1 for active, 2 for follow");
 module_param(all_slaves_active, int, 0);
 MODULE_PARM_DESC(all_slaves_active, "Keep all frames received on an interface"
-                                    "by setting active flag for all slaves "
+                                    "by setting active flag for all slaves; "
                                     "0 for never (default), 1 for always.");
 module_param(resend_igmp, int, 0);
-MODULE_PARM_DESC(resend_igmp, "Number of IGMP membership reports to send on link failure");
+MODULE_PARM_DESC(resend_igmp, "Number of IGMP membership reports to send on "
+                             "link failure");
 
 /*----------------------------- Global variables ----------------------------*/
 
@@ -378,6 +388,8 @@ struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr)
        return next;
 }
 
+#define bond_queue_mapping(skb) (*(u16 *)((skb)->cb))
+
 /**
  * bond_dev_queue_xmit - Prepare skb for xmit.
  *
@@ -390,6 +402,9 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,
 {
        skb->dev = slave_dev;
        skb->priority = 1;
+
+       skb->queue_mapping = bond_queue_mapping(skb);
+
        if (unlikely(netpoll_tx_running(slave_dev)))
                bond_netpoll_send_skb(bond_get_slave_by_dev(bond, slave_dev), skb);
        else
@@ -852,7 +867,7 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
 static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
 {
        struct bonding *bond = container_of(work, struct bonding,
-                                                       mcast_work.work);
+                                           mcast_work.work);
        bond_resend_igmp_join_requests(bond);
 }
 
@@ -1172,10 +1187,12 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
        }
 
        /* resend IGMP joins since active slave has changed or
-        * all were sent on curr_active_slave */
-       if (((USES_PRIMARY(bond->params.mode) && new_active) ||
-            bond->params.mode == BOND_MODE_ROUNDROBIN) &&
-           netif_running(bond->dev)) {
+        * all were sent on curr_active_slave.
+        * resend only if bond is brought up with the affected
+        * bonding modes and the retransmission is enabled */
+       if (netif_running(bond->dev) && (bond->params.resend_igmp > 0) &&
+           ((USES_PRIMARY(bond->params.mode) && new_active) ||
+            bond->params.mode == BOND_MODE_ROUNDROBIN)) {
                bond->igmp_retrans = bond->params.resend_igmp;
                queue_delayed_work(bond->wq, &bond->mcast_work, 0);
        }
@@ -1280,6 +1297,7 @@ static inline int slave_enable_netpoll(struct slave *slave)
                goto out;
 
        np->dev = slave->dev;
+       strlcpy(np->dev_name, slave->dev->name, IFNAMSIZ);
        err = __netpoll_setup(np);
        if (err) {
                kfree(np);
@@ -1542,12 +1560,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                           bond_dev->name, slave_dev->name);
        }
 
-       /* bond must be initialized by bond_open() before enslaving */
-       if (!(bond_dev->flags & IFF_UP)) {
-               pr_warning("%s: master_dev is not up in bond_enslave\n",
-                          bond_dev->name);
-       }
-
        /* already enslaved */
        if (slave_dev->flags & IFF_SLAVE) {
                pr_debug("Error, Device was already enslaved\n");
@@ -4200,6 +4212,7 @@ static inline int bond_slave_override(struct bonding *bond,
        return res;
 }
 
+
 static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb)
 {
        /*
@@ -4210,6 +4223,11 @@ static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb)
         */
        u16 txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0;
 
+       /*
+        * Save the original txq to restore before passing to the driver
+        */
+       bond_queue_mapping(skb) = skb->queue_mapping;
+
        if (unlikely(txq >= dev->real_num_tx_queues)) {
                do {
                        txq -= dev->real_num_tx_queues;
@@ -4834,9 +4852,19 @@ static int bond_init(struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct bond_net *bn = net_generic(dev_net(bond_dev), bond_net_id);
+       struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
 
        pr_debug("Begin bond_init for %s\n", bond_dev->name);
 
+       /*
+        * Initialize locks that may be required during
+        * en/deslave operations.  All of the bond_open work
+        * (of which this is part) should really be moved to
+        * a phase prior to dev_open
+        */
+       spin_lock_init(&(bond_info->tx_hashtbl_lock));
+       spin_lock_init(&(bond_info->rx_hashtbl_lock));
+
        bond->wq = create_singlethread_workqueue(bond_dev->name);
        if (!bond->wq)
                return -ENOMEM;
index 4059bfc73dbf531d3e7c7df946c6615b611c51a5..88fcb25e554a1f92205246771040149e3fce6967 100644 (file)
@@ -227,12 +227,6 @@ static ssize_t bonding_store_slaves(struct device *d,
        struct net_device *dev;
        struct bonding *bond = to_bond(d);
 
-       /* Quick sanity check -- is the bond interface up? */
-       if (!(bond->dev->flags & IFF_UP)) {
-               pr_warning("%s: doing slave updates when interface is down.\n",
-                          bond->dev->name);
-       }
-
        if (!rtnl_trylock())
                return restart_syscall();
 
@@ -1539,8 +1533,8 @@ static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR,
  * Show and set the number of IGMP membership reports to send on link failure
  */
 static ssize_t bonding_show_resend_igmp(struct device *d,
-                                        struct device_attribute *attr,
-                                        char *buf)
+                                       struct device_attribute *attr,
+                                       char *buf)
 {
        struct bonding *bond = to_bond(d);
 
@@ -1548,8 +1542,8 @@ static ssize_t bonding_show_resend_igmp(struct device *d,
 }
 
 static ssize_t bonding_store_resend_igmp(struct device *d,
-                                         struct device_attribute *attr,
-                                         const char *buf, size_t count)
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
 {
        int new_value, ret = count;
        struct bonding *bond = to_bond(d);
@@ -1561,7 +1555,7 @@ static ssize_t bonding_store_resend_igmp(struct device *d,
                goto out;
        }
 
-       if (new_value < 0) {
+       if (new_value < 0 || new_value > 255) {
                pr_err("%s: Invalid resend_igmp value %d not in range 0-255; rejected.\n",
                       bond->dev->name, new_value);
                ret = -EINVAL;
index 73c7e03617ecc52313af4335f8b245d46b7eecb4..3df0c0f8b8bf93ca98a8829e7c09162a70f384c4 100644 (file)
@@ -167,8 +167,8 @@ static inline void debugfs_tx(struct ser_device *ser, const u8 *data, int size)
 
 #endif
 
-static unsigned int ldisc_receive(struct tty_struct *tty,
-               const u8 *data, char *flags, int count)
+static void ldisc_receive(struct tty_struct *tty, const u8 *data,
+                       char *flags, int count)
 {
        struct sk_buff *skb = NULL;
        struct ser_device *ser;
@@ -215,8 +215,6 @@ static unsigned int ldisc_receive(struct tty_struct *tty,
        } else
                ++ser->dev->stats.rx_dropped;
        update_tty_status(ser);
-
-       return count;
 }
 
 static int handle_tx(struct ser_device *ser)
index d4990568baee071cd5ceaaac9a91c6bc5d6cf7c9..17678117ed69dba42d02339ec76b962bf25f1695 100644 (file)
@@ -923,7 +923,7 @@ static int __devinit flexcan_probe(struct platform_device *pdev)
        mem_size = resource_size(mem);
        if (!request_mem_region(mem->start, mem_size, pdev->name)) {
                err = -EBUSY;
-               goto failed_req;
+               goto failed_get;
        }
 
        base = ioremap(mem->start, mem_size);
@@ -977,9 +977,8 @@ static int __devinit flexcan_probe(struct platform_device *pdev)
        iounmap(base);
  failed_map:
        release_mem_region(mem->start, mem_size);
- failed_req:
-       clk_put(clk);
  failed_get:
+       clk_put(clk);
  failed_clock:
        return err;
 }
index 587fba48cdd9594af60827a4626196ee1483a695..f1942cab35f65cbc237cffe9c797690d7ad5b6ac 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 
 #include <linux/netdevice.h>
 #include <linux/can.h>
@@ -1644,7 +1643,7 @@ static int __devinit ican3_probe(struct platform_device *pdev)
        struct device *dev;
        int ret;
 
-       pdata = mfd_get_data(pdev);
+       pdata = pdev->dev.platform_data;
        if (!pdata)
                return -ENXIO;
 
index 75622d54581f15f87ea3ca4b893e7f37cbf34e9e..1b49df6b2470874b0cb76cf45214f247c6d3bf29 100644 (file)
@@ -425,17 +425,16 @@ static void slc_setup(struct net_device *dev)
  * in parallel
  */
 
-static unsigned int slcan_receive_buf(struct tty_struct *tty,
+static void slcan_receive_buf(struct tty_struct *tty,
                              const unsigned char *cp, char *fp, int count)
 {
        struct slcan *sl = (struct slcan *) tty->disc_data;
-       int bytes = count;
 
        if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev))
-               return -ENODEV;
+               return;
 
        /* Read the characters out of the buffer */
-       while (bytes--) {
+       while (count--) {
                if (fp && *fp++) {
                        if (!test_and_set_bit(SLF_ERROR, &sl->flags))
                                sl->dev->stats.rx_errors++;
@@ -444,8 +443,6 @@ static unsigned int slcan_receive_buf(struct tty_struct *tty,
                }
                slcan_unesc(sl, *cp++);
        }
-
-       return count;
 }
 
 /************************************
index c11bb4de86308171dcd8241eda70ff3eaa5aaf98..c0e1b1eb87a9d5ffa4b37bea76359472e2122075 100644 (file)
@@ -315,7 +315,7 @@ pcmcia_failed:
        return ret ?: -ENODEV;
 }
 
-static /*const*/ struct pcmcia_device_id softingcs_ids[] = {
+static const struct pcmcia_device_id softingcs_ids[] = {
        /* softing */
        PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0001),
        PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0002),
index 807b6bb200eb28da5658b7cf8497dba7b8ab4821..dcc4a170b0f397ed5362341a8d5a62fb07d411a4 100644 (file)
@@ -1772,7 +1772,7 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
        /* obtain emac clock from kernel */
        emac_clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(emac_clk)) {
-               printk(KERN_ERR "DaVinci EMAC: Failed to get EMAC clock\n");
+               dev_err(&pdev->dev, "failed to get EMAC clock\n");
                return -EBUSY;
        }
        emac_bus_frequency = clk_get_rate(emac_clk);
@@ -1780,9 +1780,9 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
 
        ndev = alloc_etherdev(sizeof(struct emac_priv));
        if (!ndev) {
-               printk(KERN_ERR "DaVinci EMAC: Error allocating net_device\n");
-               clk_put(emac_clk);
-               return -ENOMEM;
+               dev_err(&pdev->dev, "error allocating net_device\n");
+               rc = -ENOMEM;
+               goto free_clk;
        }
 
        platform_set_drvdata(pdev, ndev);
@@ -1795,8 +1795,9 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
 
        pdata = pdev->dev.platform_data;
        if (!pdata) {
-               printk(KERN_ERR "DaVinci EMAC: No platform data\n");
-               return -ENODEV;
+               dev_err(&pdev->dev, "no platform data\n");
+               rc = -ENODEV;
+               goto probe_quit;
        }
 
        /* MAC addr and PHY mask , RMII enable info from platform_data */
@@ -1814,7 +1815,7 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
        /* Get EMAC platform data */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
-               dev_err(emac_dev, "DaVinci EMAC: Error getting res\n");
+               dev_err(&pdev->dev,"error getting res\n");
                rc = -ENOENT;
                goto probe_quit;
        }
@@ -1822,14 +1823,14 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
        priv->emac_base_phys = res->start + pdata->ctrl_reg_offset;
        size = res->end - res->start + 1;
        if (!request_mem_region(res->start, size, ndev->name)) {
-               dev_err(emac_dev, "DaVinci EMAC: failed request_mem_region() for regs\n");
+               dev_err(&pdev->dev, "failed request_mem_region() for regs\n");
                rc = -ENXIO;
                goto probe_quit;
        }
 
        priv->remap_addr = ioremap(res->start, size);
        if (!priv->remap_addr) {
-               dev_err(emac_dev, "Unable to map IO\n");
+               dev_err(&pdev->dev, "unable to map IO\n");
                rc = -ENOMEM;
                release_mem_region(res->start, size);
                goto probe_quit;
@@ -1863,7 +1864,7 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
 
        priv->dma = cpdma_ctlr_create(&dma_params);
        if (!priv->dma) {
-               dev_err(emac_dev, "DaVinci EMAC: Error initializing DMA\n");
+               dev_err(&pdev->dev, "error initializing DMA\n");
                rc = -ENOMEM;
                goto no_dma;
        }
@@ -1879,7 +1880,7 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
-               dev_err(emac_dev, "DaVinci EMAC: Error getting irq res\n");
+               dev_err(&pdev->dev, "error getting irq res\n");
                rc = -ENOENT;
                goto no_irq_res;
        }
@@ -1888,8 +1889,8 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
        if (!is_valid_ether_addr(priv->mac_addr)) {
                /* Use random MAC if none passed */
                random_ether_addr(priv->mac_addr);
-               printk(KERN_WARNING "%s: using random MAC addr: %pM\n",
-                               __func__, priv->mac_addr);
+               dev_warn(&pdev->dev, "using random MAC addr: %pM\n",
+                                                       priv->mac_addr);
        }
 
        ndev->netdev_ops = &emac_netdev_ops;
@@ -1902,7 +1903,7 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
        SET_NETDEV_DEV(ndev, &pdev->dev);
        rc = register_netdev(ndev);
        if (rc) {
-               dev_err(emac_dev, "DaVinci EMAC: Error in register_netdev\n");
+               dev_err(&pdev->dev, "error in register_netdev\n");
                rc = -ENODEV;
                goto netdev_reg_err;
        }
@@ -1929,8 +1930,9 @@ no_dma:
        iounmap(priv->remap_addr);
 
 probe_quit:
-       clk_put(emac_clk);
        free_netdev(ndev);
+free_clk:
+       clk_put(emac_clk);
        return rc;
 }
 
index 17654059922de988574f7c888d7367164265fda8..8b0084d17c8c82f1a6c30a273614a0689999661c 100644 (file)
@@ -331,18 +331,18 @@ static struct {
                          "DE422",\
                          ""}
 
-static const char* const depca_signature[] __devinitconst = DEPCA_SIGNATURE;
+static char* __initdata depca_signature[] = DEPCA_SIGNATURE;
 
 enum depca_type {
        DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown
 };
 
-static const char depca_string[] = "depca";
+static char depca_string[] = "depca";
 
 static int depca_device_remove (struct device *device);
 
 #ifdef CONFIG_EISA
-static const struct eisa_device_id depca_eisa_ids[] __devinitconst = {
+static struct eisa_device_id depca_eisa_ids[] = {
        { "DEC4220", de422 },
        { "" }
 };
@@ -367,19 +367,19 @@ static struct eisa_driver depca_eisa_driver = {
 #define DE210_ID 0x628d
 #define DE212_ID 0x6def
 
-static const short depca_mca_adapter_ids[] __devinitconst = {
+static short depca_mca_adapter_ids[] = {
        DE210_ID,
        DE212_ID,
        0x0000
 };
 
-static const char *depca_mca_adapter_name[] = {
+static char *depca_mca_adapter_name[] = {
        "DEC EtherWORKS MC Adapter (DE210)",
        "DEC EtherWORKS MC Adapter (DE212)",
        NULL
 };
 
-static const enum depca_type depca_mca_adapter_type[] = {
+static enum depca_type depca_mca_adapter_type[] = {
        de210,
        de212,
        0
@@ -541,9 +541,10 @@ static void SetMulticastFilter(struct net_device *dev);
 static int load_packet(struct net_device *dev, struct sk_buff *skb);
 static void depca_dbg_open(struct net_device *dev);
 
-static const u_char de1xx_irq[] __devinitconst = { 2, 3, 4, 5, 7, 9, 0 };
-static const u_char de2xx_irq[] __devinitconst = { 5, 9, 10, 11, 15, 0 };
-static const u_char de422_irq[] __devinitconst = { 5, 9, 10, 11, 0 };
+static u_char de1xx_irq[] __initdata = { 2, 3, 4, 5, 7, 9, 0 };
+static u_char de2xx_irq[] __initdata = { 5, 9, 10, 11, 15, 0 };
+static u_char de422_irq[] __initdata = { 5, 9, 10, 11, 0 };
+static u_char *depca_irq;
 
 static int irq;
 static int io;
@@ -579,7 +580,7 @@ static const struct net_device_ops depca_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
 };
 
-static int __devinit depca_hw_init (struct net_device *dev, struct device *device)
+static int __init depca_hw_init (struct net_device *dev, struct device *device)
 {
        struct depca_private *lp;
        int i, j, offset, netRAM, mem_len, status = 0;
@@ -747,7 +748,6 @@ static int __devinit depca_hw_init (struct net_device *dev, struct device *devic
        if (dev->irq < 2) {
                unsigned char irqnum;
                unsigned long irq_mask, delay;
-               const u_char *depca_irq;
 
                irq_mask = probe_irq_on();
 
@@ -770,7 +770,6 @@ static int __devinit depca_hw_init (struct net_device *dev, struct device *devic
                        break;
 
                default:
-                       depca_irq = NULL;
                        break;  /* Not reached */
                }
 
@@ -1303,7 +1302,7 @@ static void SetMulticastFilter(struct net_device *dev)
        }
 }
 
-static int __devinit depca_common_init (u_long ioaddr, struct net_device **devp)
+static int __init depca_common_init (u_long ioaddr, struct net_device **devp)
 {
        int status = 0;
 
@@ -1334,7 +1333,7 @@ static int __devinit depca_common_init (u_long ioaddr, struct net_device **devp)
 /*
 ** Microchannel bus I/O device probe
 */
-static int __devinit depca_mca_probe(struct device *device)
+static int __init depca_mca_probe(struct device *device)
 {
        unsigned char pos[2];
        unsigned char where;
@@ -1458,7 +1457,7 @@ static int __devinit depca_mca_probe(struct device *device)
 ** ISA bus I/O device probe
 */
 
-static void __devinit depca_platform_probe (void)
+static void __init depca_platform_probe (void)
 {
        int i;
        struct platform_device *pldev;
@@ -1498,7 +1497,7 @@ static void __devinit depca_platform_probe (void)
        }
 }
 
-static enum depca_type __devinit depca_shmem_probe (ulong *mem_start)
+static enum depca_type __init depca_shmem_probe (ulong *mem_start)
 {
        u_long mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
        enum depca_type adapter = unknown;
@@ -1559,7 +1558,7 @@ static int __devinit depca_isa_probe (struct platform_device *device)
 */
 
 #ifdef CONFIG_EISA
-static int __devinit depca_eisa_probe (struct device *device)
+static int __init depca_eisa_probe (struct device *device)
 {
        enum depca_type adapter = unknown;
        struct eisa_device *edev;
@@ -1630,7 +1629,7 @@ static int __devexit depca_device_remove (struct device *device)
 ** and Boot (readb) ROM. This will also give us a clue to the network RAM
 ** base address.
 */
-static int __devinit DepcaSignature(char *name, u_long base_addr)
+static int __init DepcaSignature(char *name, u_long base_addr)
 {
        u_int i, j, k;
        void __iomem *ptr;
index c445457b66d53df856564a2d88895680249f49bf..23179dbcedd260ccd6b401f21c859bbdeb753675 100644 (file)
@@ -346,7 +346,7 @@ parse_eeprom (struct net_device *dev)
        if (np->pdev->vendor == PCI_VENDOR_ID_DLINK) {  /* D-Link Only */
                /* Check CRC */
                crc = ~ether_crc_le (256 - 4, sromdata);
-               if (psrom->crc != crc) {
+               if (psrom->crc != cpu_to_le32(crc)) {
                        printk (KERN_ERR "%s: EEPROM data CRC error.\n",
                                        dev->name);
                        return -1;
index fbaff3584bd4982e5c3f72c6079d86f6d12b5f22..ee597e676ee500235f7dace13c570ad92e20724f 100644 (file)
@@ -1157,9 +1157,6 @@ dm9000_open(struct net_device *dev)
 
        irqflags |= IRQF_SHARED;
 
-       if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
-               return -EAGAIN;
-
        /* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */
        iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
        mdelay(1); /* delay needs by DM9000B */
@@ -1168,6 +1165,9 @@ dm9000_open(struct net_device *dev)
        dm9000_reset(db);
        dm9000_init_dm9000(dev);
 
+       if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
+               return -EAGAIN;
+
        /* Init driver variable */
        db->dbug_cnt = 0;
 
index 6a0a8fca62bc58aeaa8354abc1f2c6d67175e659..3fd5a240034840d223cf43095bc76599811755e6 100644 (file)
@@ -2083,7 +2083,7 @@ static void ehea_set_multicast_list(struct net_device *dev)
        struct netdev_hw_addr *ha;
        int ret;
 
-       if (dev->flags & IFF_PROMISC) {
+       if (port->promisc) {
                ehea_promiscuous(dev, 1);
                return;
        }
index 7a84e45487e83ba184dcccf4def37529c4607ba9..7583a9572bcc5a55c1d4fc87378f0d1475bccc45 100644 (file)
@@ -105,7 +105,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
                goto out_ep;
 
        fep->fcc.mem = (void __iomem *)cpm2_immr;
-       fpi->dpram_offset = cpm_dpalloc(128, 8);
+       fpi->dpram_offset = cpm_dpalloc(128, 32);
        if (IS_ERR_VALUE(fpi->dpram_offset)) {
                ret = fpi->dpram_offset;
                goto out_fcccp;
index ff60b23a5b7429b99fc06e5c138a643d5b804dd3..2dfcc8047847b12ade17da7c324a717133398680 100644 (file)
@@ -10,7 +10,7 @@
  * Maintainer: Kumar Gala
  * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com>
  *
- * Copyright 2002-2009 Freescale Semiconductor, Inc.
+ * Copyright 2002-2009, 2011 Freescale Semiconductor, Inc.
  * Copyright 2007 MontaVista Software, Inc.
  *
  * This program is free software; you can redistribute  it and/or modify it
@@ -476,9 +476,6 @@ static const struct net_device_ops gfar_netdev_ops = {
 #endif
 };
 
-unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
-unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
-
 void lock_rx_qs(struct gfar_private *priv)
 {
        int i = 0x0;
@@ -868,28 +865,28 @@ static u32 cluster_entry_per_class(struct gfar_private *priv, u32 rqfar,
 
        rqfar--;
        rqfcr = RQFCR_CLE | RQFCR_PID_MASK | RQFCR_CMP_EXACT;
-       ftp_rqfpr[rqfar] = rqfpr;
-       ftp_rqfcr[rqfar] = rqfcr;
+       priv->ftp_rqfpr[rqfar] = rqfpr;
+       priv->ftp_rqfcr[rqfar] = rqfcr;
        gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
 
        rqfar--;
        rqfcr = RQFCR_CMP_NOMATCH;
-       ftp_rqfpr[rqfar] = rqfpr;
-       ftp_rqfcr[rqfar] = rqfcr;
+       priv->ftp_rqfpr[rqfar] = rqfpr;
+       priv->ftp_rqfcr[rqfar] = rqfcr;
        gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
 
        rqfar--;
        rqfcr = RQFCR_CMP_EXACT | RQFCR_PID_PARSE | RQFCR_CLE | RQFCR_AND;
        rqfpr = class;
-       ftp_rqfcr[rqfar] = rqfcr;
-       ftp_rqfpr[rqfar] = rqfpr;
+       priv->ftp_rqfcr[rqfar] = rqfcr;
+       priv->ftp_rqfpr[rqfar] = rqfpr;
        gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
 
        rqfar--;
        rqfcr = RQFCR_CMP_EXACT | RQFCR_PID_MASK | RQFCR_AND;
        rqfpr = class;
-       ftp_rqfcr[rqfar] = rqfcr;
-       ftp_rqfpr[rqfar] = rqfpr;
+       priv->ftp_rqfcr[rqfar] = rqfcr;
+       priv->ftp_rqfpr[rqfar] = rqfpr;
        gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
 
        return rqfar;
@@ -904,8 +901,8 @@ static void gfar_init_filer_table(struct gfar_private *priv)
 
        /* Default rule */
        rqfcr = RQFCR_CMP_MATCH;
-       ftp_rqfcr[rqfar] = rqfcr;
-       ftp_rqfpr[rqfar] = rqfpr;
+       priv->ftp_rqfcr[rqfar] = rqfcr;
+       priv->ftp_rqfpr[rqfar] = rqfpr;
        gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
 
        rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6);
@@ -921,8 +918,8 @@ static void gfar_init_filer_table(struct gfar_private *priv)
        /* Rest are masked rules */
        rqfcr = RQFCR_CMP_NOMATCH;
        for (i = 0; i < rqfar; i++) {
-               ftp_rqfcr[i] = rqfcr;
-               ftp_rqfpr[i] = rqfpr;
+               priv->ftp_rqfcr[i] = rqfcr;
+               priv->ftp_rqfpr[i] = rqfpr;
                gfar_write_filer(priv, i, rqfcr, rqfpr);
        }
 }
index fc86f51954456e5ddcec1c6ba2e40f17e612bc01..ba36dc7a34356c0fac622cbd2de682201049d5eb 100644 (file)
@@ -9,7 +9,7 @@
  * Maintainer: Kumar Gala
  * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com>
  *
- * Copyright 2002-2009 Freescale Semiconductor, Inc.
+ * Copyright 2002-2009, 2011 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
@@ -1107,10 +1107,12 @@ struct gfar_private {
        /* HW time stamping enabled flag */
        int hwts_rx_en;
        int hwts_tx_en;
+
+       /*Filer table*/
+       unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
+       unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
 };
 
-extern unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
-extern unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
 
 static inline int gfar_has_errata(struct gfar_private *priv,
                                  enum gfar_errata err)
index 493d743839d977f035f36be50de59d2e5744b2e6..239e3330495fb4fc9b96063d8fbf2438e429a6df 100644 (file)
@@ -9,7 +9,7 @@
  *  Maintainer: Kumar Gala
  *  Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com>
  *
- *  Copyright 2003-2006, 2008-2009 Freescale Semiconductor, Inc.
+ *  Copyright 2003-2006, 2008-2009, 2011 Freescale Semiconductor, Inc.
  *
  *  This software may be used and distributed according to
  *  the terms of the GNU Public License, Version 2, incorporated herein
@@ -609,15 +609,15 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
        if (ethflow & RXH_L2DA) {
                fcr = RQFCR_PID_DAH |RQFCR_CMP_NOMATCH |
                        RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0;
-               ftp_rqfpr[priv->cur_filer_idx] = fpr;
-               ftp_rqfcr[priv->cur_filer_idx] = fcr;
+               priv->ftp_rqfpr[priv->cur_filer_idx] = fpr;
+               priv->ftp_rqfcr[priv->cur_filer_idx] = fcr;
                gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
                priv->cur_filer_idx = priv->cur_filer_idx - 1;
 
                fcr = RQFCR_PID_DAL | RQFCR_AND | RQFCR_CMP_NOMATCH |
                                RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0;
-               ftp_rqfpr[priv->cur_filer_idx] = fpr;
-               ftp_rqfcr[priv->cur_filer_idx] = fcr;
+               priv->ftp_rqfpr[priv->cur_filer_idx] = fpr;
+               priv->ftp_rqfcr[priv->cur_filer_idx] = fcr;
                gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
                priv->cur_filer_idx = priv->cur_filer_idx - 1;
        }
@@ -626,16 +626,16 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
                fcr = RQFCR_PID_VID | RQFCR_CMP_NOMATCH | RQFCR_HASH |
                                RQFCR_AND | RQFCR_HASHTBL_0;
                gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
-               ftp_rqfpr[priv->cur_filer_idx] = fpr;
-               ftp_rqfcr[priv->cur_filer_idx] = fcr;
+               priv->ftp_rqfpr[priv->cur_filer_idx] = fpr;
+               priv->ftp_rqfcr[priv->cur_filer_idx] = fcr;
                priv->cur_filer_idx = priv->cur_filer_idx - 1;
        }
 
        if (ethflow & RXH_IP_SRC) {
                fcr = RQFCR_PID_SIA | RQFCR_CMP_NOMATCH | RQFCR_HASH |
                        RQFCR_AND | RQFCR_HASHTBL_0;
-               ftp_rqfpr[priv->cur_filer_idx] = fpr;
-               ftp_rqfcr[priv->cur_filer_idx] = fcr;
+               priv->ftp_rqfpr[priv->cur_filer_idx] = fpr;
+               priv->ftp_rqfcr[priv->cur_filer_idx] = fcr;
                gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
                priv->cur_filer_idx = priv->cur_filer_idx - 1;
        }
@@ -643,8 +643,8 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
        if (ethflow & (RXH_IP_DST)) {
                fcr = RQFCR_PID_DIA | RQFCR_CMP_NOMATCH | RQFCR_HASH |
                        RQFCR_AND | RQFCR_HASHTBL_0;
-               ftp_rqfpr[priv->cur_filer_idx] = fpr;
-               ftp_rqfcr[priv->cur_filer_idx] = fcr;
+               priv->ftp_rqfpr[priv->cur_filer_idx] = fpr;
+               priv->ftp_rqfcr[priv->cur_filer_idx] = fcr;
                gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
                priv->cur_filer_idx = priv->cur_filer_idx - 1;
        }
@@ -652,8 +652,8 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
        if (ethflow & RXH_L3_PROTO) {
                fcr = RQFCR_PID_L4P | RQFCR_CMP_NOMATCH | RQFCR_HASH |
                        RQFCR_AND | RQFCR_HASHTBL_0;
-               ftp_rqfpr[priv->cur_filer_idx] = fpr;
-               ftp_rqfcr[priv->cur_filer_idx] = fcr;
+               priv->ftp_rqfpr[priv->cur_filer_idx] = fpr;
+               priv->ftp_rqfcr[priv->cur_filer_idx] = fcr;
                gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
                priv->cur_filer_idx = priv->cur_filer_idx - 1;
        }
@@ -661,8 +661,8 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
        if (ethflow & RXH_L4_B_0_1) {
                fcr = RQFCR_PID_SPT | RQFCR_CMP_NOMATCH | RQFCR_HASH |
                        RQFCR_AND | RQFCR_HASHTBL_0;
-               ftp_rqfpr[priv->cur_filer_idx] = fpr;
-               ftp_rqfcr[priv->cur_filer_idx] = fcr;
+               priv->ftp_rqfpr[priv->cur_filer_idx] = fpr;
+               priv->ftp_rqfcr[priv->cur_filer_idx] = fcr;
                gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
                priv->cur_filer_idx = priv->cur_filer_idx - 1;
        }
@@ -670,8 +670,8 @@ static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
        if (ethflow & RXH_L4_B_2_3) {
                fcr = RQFCR_PID_DPT | RQFCR_CMP_NOMATCH | RQFCR_HASH |
                        RQFCR_AND | RQFCR_HASHTBL_0;
-               ftp_rqfpr[priv->cur_filer_idx] = fpr;
-               ftp_rqfcr[priv->cur_filer_idx] = fcr;
+               priv->ftp_rqfpr[priv->cur_filer_idx] = fpr;
+               priv->ftp_rqfcr[priv->cur_filer_idx] = fcr;
                gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
                priv->cur_filer_idx = priv->cur_filer_idx - 1;
        }
@@ -705,12 +705,12 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u
        }
 
        for (i = 0; i < MAX_FILER_IDX + 1; i++) {
-               local_rqfpr[j] = ftp_rqfpr[i];
-               local_rqfcr[j] = ftp_rqfcr[i];
+               local_rqfpr[j] = priv->ftp_rqfpr[i];
+               local_rqfcr[j] = priv->ftp_rqfcr[i];
                j--;
-               if ((ftp_rqfcr[i] == (RQFCR_PID_PARSE |
+               if ((priv->ftp_rqfcr[i] == (RQFCR_PID_PARSE |
                        RQFCR_CLE |RQFCR_AND)) &&
-                       (ftp_rqfpr[i] == cmp_rqfpr))
+                       (priv->ftp_rqfpr[i] == cmp_rqfpr))
                        break;
        }
 
@@ -724,20 +724,22 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u
         * if it was already programmed, we need to overwrite these rules
         */
        for (l = i+1; l < MAX_FILER_IDX; l++) {
-               if ((ftp_rqfcr[l] & RQFCR_CLE) &&
-                       !(ftp_rqfcr[l] & RQFCR_AND)) {
-                       ftp_rqfcr[l] = RQFCR_CLE | RQFCR_CMP_EXACT |
+               if ((priv->ftp_rqfcr[l] & RQFCR_CLE) &&
+                       !(priv->ftp_rqfcr[l] & RQFCR_AND)) {
+                       priv->ftp_rqfcr[l] = RQFCR_CLE | RQFCR_CMP_EXACT |
                                RQFCR_HASHTBL_0 | RQFCR_PID_MASK;
-                       ftp_rqfpr[l] = FPR_FILER_MASK;
-                       gfar_write_filer(priv, l, ftp_rqfcr[l], ftp_rqfpr[l]);
+                       priv->ftp_rqfpr[l] = FPR_FILER_MASK;
+                       gfar_write_filer(priv, l, priv->ftp_rqfcr[l],
+                               priv->ftp_rqfpr[l]);
                        break;
                }
 
-               if (!(ftp_rqfcr[l] & RQFCR_CLE) && (ftp_rqfcr[l] & RQFCR_AND))
+               if (!(priv->ftp_rqfcr[l] & RQFCR_CLE) &&
+                       (priv->ftp_rqfcr[l] & RQFCR_AND))
                        continue;
                else {
-                       local_rqfpr[j] = ftp_rqfpr[l];
-                       local_rqfcr[j] = ftp_rqfcr[l];
+                       local_rqfpr[j] = priv->ftp_rqfpr[l];
+                       local_rqfcr[j] = priv->ftp_rqfcr[l];
                        j--;
                }
        }
@@ -750,8 +752,8 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u
 
        /* Write back the popped out rules again */
        for (k = j+1; k < MAX_FILER_IDX; k++) {
-               ftp_rqfpr[priv->cur_filer_idx] = local_rqfpr[k];
-               ftp_rqfcr[priv->cur_filer_idx] = local_rqfcr[k];
+               priv->ftp_rqfpr[priv->cur_filer_idx] = local_rqfpr[k];
+               priv->ftp_rqfcr[priv->cur_filer_idx] = local_rqfcr[k];
                gfar_write_filer(priv, priv->cur_filer_idx,
                                local_rqfcr[k], local_rqfpr[k]);
                if (!priv->cur_filer_idx)
diff --git a/drivers/net/gianfar_ptp.c b/drivers/net/gianfar_ptp.c
new file mode 100644 (file)
index 0000000..d8e1753
--- /dev/null
@@ -0,0 +1,588 @@
+/*
+ * PTP 1588 clock using the eTSEC
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/device.h>
+#include <linux/hrtimer.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/timex.h>
+#include <linux/io.h>
+
+#include <linux/ptp_clock_kernel.h>
+
+#include "gianfar.h"
+
+/*
+ * gianfar ptp registers
+ * Generated by regen.tcl on Thu May 13 01:38:57 PM CEST 2010
+ */
+struct gianfar_ptp_registers {
+       u32 tmr_ctrl;     /* Timer control register */
+       u32 tmr_tevent;   /* Timestamp event register */
+       u32 tmr_temask;   /* Timer event mask register */
+       u32 tmr_pevent;   /* Timestamp event register */
+       u32 tmr_pemask;   /* Timer event mask register */
+       u32 tmr_stat;     /* Timestamp status register */
+       u32 tmr_cnt_h;    /* Timer counter high register */
+       u32 tmr_cnt_l;    /* Timer counter low register */
+       u32 tmr_add;      /* Timer drift compensation addend register */
+       u32 tmr_acc;      /* Timer accumulator register */
+       u32 tmr_prsc;     /* Timer prescale */
+       u8  res1[4];
+       u32 tmroff_h;     /* Timer offset high */
+       u32 tmroff_l;     /* Timer offset low */
+       u8  res2[8];
+       u32 tmr_alarm1_h; /* Timer alarm 1 high register */
+       u32 tmr_alarm1_l; /* Timer alarm 1 high register */
+       u32 tmr_alarm2_h; /* Timer alarm 2 high register */
+       u32 tmr_alarm2_l; /* Timer alarm 2 high register */
+       u8  res3[48];
+       u32 tmr_fiper1;   /* Timer fixed period interval */
+       u32 tmr_fiper2;   /* Timer fixed period interval */
+       u32 tmr_fiper3;   /* Timer fixed period interval */
+       u8  res4[20];
+       u32 tmr_etts1_h;  /* Timestamp of general purpose external trigger */
+       u32 tmr_etts1_l;  /* Timestamp of general purpose external trigger */
+       u32 tmr_etts2_h;  /* Timestamp of general purpose external trigger */
+       u32 tmr_etts2_l;  /* Timestamp of general purpose external trigger */
+};
+
+/* Bit definitions for the TMR_CTRL register */
+#define ALM1P                 (1<<31) /* Alarm1 output polarity */
+#define ALM2P                 (1<<30) /* Alarm2 output polarity */
+#define FS                    (1<<28) /* FIPER start indication */
+#define PP1L                  (1<<27) /* Fiper1 pulse loopback mode enabled. */
+#define PP2L                  (1<<26) /* Fiper2 pulse loopback mode enabled. */
+#define TCLK_PERIOD_SHIFT     (16) /* 1588 timer reference clock period. */
+#define TCLK_PERIOD_MASK      (0x3ff)
+#define RTPE                  (1<<15) /* Record Tx Timestamp to PAL Enable. */
+#define FRD                   (1<<14) /* FIPER Realignment Disable */
+#define ESFDP                 (1<<11) /* External Tx/Rx SFD Polarity. */
+#define ESFDE                 (1<<10) /* External Tx/Rx SFD Enable. */
+#define ETEP2                 (1<<9) /* External trigger 2 edge polarity */
+#define ETEP1                 (1<<8) /* External trigger 1 edge polarity */
+#define COPH                  (1<<7) /* Generated clock output phase. */
+#define CIPH                  (1<<6) /* External oscillator input clock phase */
+#define TMSR                  (1<<5) /* Timer soft reset. */
+#define BYP                   (1<<3) /* Bypass drift compensated clock */
+#define TE                    (1<<2) /* 1588 timer enable. */
+#define CKSEL_SHIFT           (0)    /* 1588 Timer reference clock source */
+#define CKSEL_MASK            (0x3)
+
+/* Bit definitions for the TMR_TEVENT register */
+#define ETS2                  (1<<25) /* External trigger 2 timestamp sampled */
+#define ETS1                  (1<<24) /* External trigger 1 timestamp sampled */
+#define ALM2                  (1<<17) /* Current time = alarm time register 2 */
+#define ALM1                  (1<<16) /* Current time = alarm time register 1 */
+#define PP1                   (1<<7)  /* periodic pulse generated on FIPER1 */
+#define PP2                   (1<<6)  /* periodic pulse generated on FIPER2 */
+#define PP3                   (1<<5)  /* periodic pulse generated on FIPER3 */
+
+/* Bit definitions for the TMR_TEMASK register */
+#define ETS2EN                (1<<25) /* External trigger 2 timestamp enable */
+#define ETS1EN                (1<<24) /* External trigger 1 timestamp enable */
+#define ALM2EN                (1<<17) /* Timer ALM2 event enable */
+#define ALM1EN                (1<<16) /* Timer ALM1 event enable */
+#define PP1EN                 (1<<7) /* Periodic pulse event 1 enable */
+#define PP2EN                 (1<<6) /* Periodic pulse event 2 enable */
+
+/* Bit definitions for the TMR_PEVENT register */
+#define TXP2                  (1<<9) /* PTP transmitted timestamp im TXTS2 */
+#define TXP1                  (1<<8) /* PTP transmitted timestamp in TXTS1 */
+#define RXP                   (1<<0) /* PTP frame has been received */
+
+/* Bit definitions for the TMR_PEMASK register */
+#define TXP2EN                (1<<9) /* Transmit PTP packet event 2 enable */
+#define TXP1EN                (1<<8) /* Transmit PTP packet event 1 enable */
+#define RXPEN                 (1<<0) /* Receive PTP packet event enable */
+
+/* Bit definitions for the TMR_STAT register */
+#define STAT_VEC_SHIFT        (0) /* Timer general purpose status vector */
+#define STAT_VEC_MASK         (0x3f)
+
+/* Bit definitions for the TMR_PRSC register */
+#define PRSC_OCK_SHIFT        (0) /* Output clock division/prescale factor. */
+#define PRSC_OCK_MASK         (0xffff)
+
+
+#define DRIVER         "gianfar_ptp"
+#define DEFAULT_CKSEL  1
+#define N_ALARM                1 /* first alarm is used internally to reset fipers */
+#define N_EXT_TS       2
+#define REG_SIZE       sizeof(struct gianfar_ptp_registers)
+
+struct etsects {
+       struct gianfar_ptp_registers *regs;
+       spinlock_t lock; /* protects regs */
+       struct ptp_clock *clock;
+       struct ptp_clock_info caps;
+       struct resource *rsrc;
+       int irq;
+       u64 alarm_interval; /* for periodic alarm */
+       u64 alarm_value;
+       u32 tclk_period;  /* nanoseconds */
+       u32 tmr_prsc;
+       u32 tmr_add;
+       u32 cksel;
+       u32 tmr_fiper1;
+       u32 tmr_fiper2;
+};
+
+/*
+ * Register access functions
+ */
+
+/* Caller must hold etsects->lock. */
+static u64 tmr_cnt_read(struct etsects *etsects)
+{
+       u64 ns;
+       u32 lo, hi;
+
+       lo = gfar_read(&etsects->regs->tmr_cnt_l);
+       hi = gfar_read(&etsects->regs->tmr_cnt_h);
+       ns = ((u64) hi) << 32;
+       ns |= lo;
+       return ns;
+}
+
+/* Caller must hold etsects->lock. */
+static void tmr_cnt_write(struct etsects *etsects, u64 ns)
+{
+       u32 hi = ns >> 32;
+       u32 lo = ns & 0xffffffff;
+
+       gfar_write(&etsects->regs->tmr_cnt_l, lo);
+       gfar_write(&etsects->regs->tmr_cnt_h, hi);
+}
+
+/* Caller must hold etsects->lock. */
+static void set_alarm(struct etsects *etsects)
+{
+       u64 ns;
+       u32 lo, hi;
+
+       ns = tmr_cnt_read(etsects) + 1500000000ULL;
+       ns = div_u64(ns, 1000000000UL) * 1000000000ULL;
+       ns -= etsects->tclk_period;
+       hi = ns >> 32;
+       lo = ns & 0xffffffff;
+       gfar_write(&etsects->regs->tmr_alarm1_l, lo);
+       gfar_write(&etsects->regs->tmr_alarm1_h, hi);
+}
+
+/* Caller must hold etsects->lock. */
+static void set_fipers(struct etsects *etsects)
+{
+       u32 tmr_ctrl = gfar_read(&etsects->regs->tmr_ctrl);
+
+       gfar_write(&etsects->regs->tmr_ctrl,   tmr_ctrl & (~TE));
+       gfar_write(&etsects->regs->tmr_prsc,   etsects->tmr_prsc);
+       gfar_write(&etsects->regs->tmr_fiper1, etsects->tmr_fiper1);
+       gfar_write(&etsects->regs->tmr_fiper2, etsects->tmr_fiper2);
+       set_alarm(etsects);
+       gfar_write(&etsects->regs->tmr_ctrl,   tmr_ctrl|TE);
+}
+
+/*
+ * Interrupt service routine
+ */
+
+static irqreturn_t isr(int irq, void *priv)
+{
+       struct etsects *etsects = priv;
+       struct ptp_clock_event event;
+       u64 ns;
+       u32 ack = 0, lo, hi, mask, val;
+
+       val = gfar_read(&etsects->regs->tmr_tevent);
+
+       if (val & ETS1) {
+               ack |= ETS1;
+               hi = gfar_read(&etsects->regs->tmr_etts1_h);
+               lo = gfar_read(&etsects->regs->tmr_etts1_l);
+               event.type = PTP_CLOCK_EXTTS;
+               event.index = 0;
+               event.timestamp = ((u64) hi) << 32;
+               event.timestamp |= lo;
+               ptp_clock_event(etsects->clock, &event);
+       }
+
+       if (val & ETS2) {
+               ack |= ETS2;
+               hi = gfar_read(&etsects->regs->tmr_etts2_h);
+               lo = gfar_read(&etsects->regs->tmr_etts2_l);
+               event.type = PTP_CLOCK_EXTTS;
+               event.index = 1;
+               event.timestamp = ((u64) hi) << 32;
+               event.timestamp |= lo;
+               ptp_clock_event(etsects->clock, &event);
+       }
+
+       if (val & ALM2) {
+               ack |= ALM2;
+               if (etsects->alarm_value) {
+                       event.type = PTP_CLOCK_ALARM;
+                       event.index = 0;
+                       event.timestamp = etsects->alarm_value;
+                       ptp_clock_event(etsects->clock, &event);
+               }
+               if (etsects->alarm_interval) {
+                       ns = etsects->alarm_value + etsects->alarm_interval;
+                       hi = ns >> 32;
+                       lo = ns & 0xffffffff;
+                       spin_lock(&etsects->lock);
+                       gfar_write(&etsects->regs->tmr_alarm2_l, lo);
+                       gfar_write(&etsects->regs->tmr_alarm2_h, hi);
+                       spin_unlock(&etsects->lock);
+                       etsects->alarm_value = ns;
+               } else {
+                       gfar_write(&etsects->regs->tmr_tevent, ALM2);
+                       spin_lock(&etsects->lock);
+                       mask = gfar_read(&etsects->regs->tmr_temask);
+                       mask &= ~ALM2EN;
+                       gfar_write(&etsects->regs->tmr_temask, mask);
+                       spin_unlock(&etsects->lock);
+                       etsects->alarm_value = 0;
+                       etsects->alarm_interval = 0;
+               }
+       }
+
+       if (val & PP1) {
+               ack |= PP1;
+               event.type = PTP_CLOCK_PPS;
+               ptp_clock_event(etsects->clock, &event);
+       }
+
+       if (ack) {
+               gfar_write(&etsects->regs->tmr_tevent, ack);
+               return IRQ_HANDLED;
+       } else
+               return IRQ_NONE;
+}
+
+/*
+ * PTP clock operations
+ */
+
+static int ptp_gianfar_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+       u64 adj;
+       u32 diff, tmr_add;
+       int neg_adj = 0;
+       struct etsects *etsects = container_of(ptp, struct etsects, caps);
+
+       if (ppb < 0) {
+               neg_adj = 1;
+               ppb = -ppb;
+       }
+       tmr_add = etsects->tmr_add;
+       adj = tmr_add;
+       adj *= ppb;
+       diff = div_u64(adj, 1000000000ULL);
+
+       tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff;
+
+       gfar_write(&etsects->regs->tmr_add, tmr_add);
+
+       return 0;
+}
+
+static int ptp_gianfar_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+       s64 now;
+       unsigned long flags;
+       struct etsects *etsects = container_of(ptp, struct etsects, caps);
+
+       spin_lock_irqsave(&etsects->lock, flags);
+
+       now = tmr_cnt_read(etsects);
+       now += delta;
+       tmr_cnt_write(etsects, now);
+
+       spin_unlock_irqrestore(&etsects->lock, flags);
+
+       set_fipers(etsects);
+
+       return 0;
+}
+
+static int ptp_gianfar_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+       u64 ns;
+       u32 remainder;
+       unsigned long flags;
+       struct etsects *etsects = container_of(ptp, struct etsects, caps);
+
+       spin_lock_irqsave(&etsects->lock, flags);
+
+       ns = tmr_cnt_read(etsects);
+
+       spin_unlock_irqrestore(&etsects->lock, flags);
+
+       ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
+       ts->tv_nsec = remainder;
+       return 0;
+}
+
+static int ptp_gianfar_settime(struct ptp_clock_info *ptp,
+                              const struct timespec *ts)
+{
+       u64 ns;
+       unsigned long flags;
+       struct etsects *etsects = container_of(ptp, struct etsects, caps);
+
+       ns = ts->tv_sec * 1000000000ULL;
+       ns += ts->tv_nsec;
+
+       spin_lock_irqsave(&etsects->lock, flags);
+
+       tmr_cnt_write(etsects, ns);
+       set_fipers(etsects);
+
+       spin_unlock_irqrestore(&etsects->lock, flags);
+
+       return 0;
+}
+
+static int ptp_gianfar_enable(struct ptp_clock_info *ptp,
+                             struct ptp_clock_request *rq, int on)
+{
+       struct etsects *etsects = container_of(ptp, struct etsects, caps);
+       unsigned long flags;
+       u32 bit, mask;
+
+       switch (rq->type) {
+       case PTP_CLK_REQ_EXTTS:
+               switch (rq->extts.index) {
+               case 0:
+                       bit = ETS1EN;
+                       break;
+               case 1:
+                       bit = ETS2EN;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               spin_lock_irqsave(&etsects->lock, flags);
+               mask = gfar_read(&etsects->regs->tmr_temask);
+               if (on)
+                       mask |= bit;
+               else
+                       mask &= ~bit;
+               gfar_write(&etsects->regs->tmr_temask, mask);
+               spin_unlock_irqrestore(&etsects->lock, flags);
+               return 0;
+
+       case PTP_CLK_REQ_PPS:
+               spin_lock_irqsave(&etsects->lock, flags);
+               mask = gfar_read(&etsects->regs->tmr_temask);
+               if (on)
+                       mask |= PP1EN;
+               else
+                       mask &= ~PP1EN;
+               gfar_write(&etsects->regs->tmr_temask, mask);
+               spin_unlock_irqrestore(&etsects->lock, flags);
+               return 0;
+
+       default:
+               break;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static struct ptp_clock_info ptp_gianfar_caps = {
+       .owner          = THIS_MODULE,
+       .name           = "gianfar clock",
+       .max_adj        = 512000,
+       .n_alarm        = N_ALARM,
+       .n_ext_ts       = N_EXT_TS,
+       .n_per_out      = 0,
+       .pps            = 1,
+       .adjfreq        = ptp_gianfar_adjfreq,
+       .adjtime        = ptp_gianfar_adjtime,
+       .gettime        = ptp_gianfar_gettime,
+       .settime        = ptp_gianfar_settime,
+       .enable         = ptp_gianfar_enable,
+};
+
+/* OF device tree */
+
+static int get_of_u32(struct device_node *node, char *str, u32 *val)
+{
+       int plen;
+       const u32 *prop = of_get_property(node, str, &plen);
+
+       if (!prop || plen != sizeof(*prop))
+               return -1;
+       *val = *prop;
+       return 0;
+}
+
+static int gianfar_ptp_probe(struct platform_device *dev)
+{
+       struct device_node *node = dev->dev.of_node;
+       struct etsects *etsects;
+       struct timespec now;
+       int err = -ENOMEM;
+       u32 tmr_ctrl;
+       unsigned long flags;
+
+       etsects = kzalloc(sizeof(*etsects), GFP_KERNEL);
+       if (!etsects)
+               goto no_memory;
+
+       err = -ENODEV;
+
+       etsects->caps = ptp_gianfar_caps;
+       etsects->cksel = DEFAULT_CKSEL;
+
+       if (get_of_u32(node, "fsl,tclk-period", &etsects->tclk_period) ||
+           get_of_u32(node, "fsl,tmr-prsc", &etsects->tmr_prsc) ||
+           get_of_u32(node, "fsl,tmr-add", &etsects->tmr_add) ||
+           get_of_u32(node, "fsl,tmr-fiper1", &etsects->tmr_fiper1) ||
+           get_of_u32(node, "fsl,tmr-fiper2", &etsects->tmr_fiper2) ||
+           get_of_u32(node, "fsl,max-adj", &etsects->caps.max_adj)) {
+               pr_err("device tree node missing required elements\n");
+               goto no_node;
+       }
+
+       etsects->irq = platform_get_irq(dev, 0);
+
+       if (etsects->irq == NO_IRQ) {
+               pr_err("irq not in device tree\n");
+               goto no_node;
+       }
+       if (request_irq(etsects->irq, isr, 0, DRIVER, etsects)) {
+               pr_err("request_irq failed\n");
+               goto no_node;
+       }
+
+       etsects->rsrc = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!etsects->rsrc) {
+               pr_err("no resource\n");
+               goto no_resource;
+       }
+       if (request_resource(&ioport_resource, etsects->rsrc)) {
+               pr_err("resource busy\n");
+               goto no_resource;
+       }
+
+       spin_lock_init(&etsects->lock);
+
+       etsects->regs = ioremap(etsects->rsrc->start,
+                               1 + etsects->rsrc->end - etsects->rsrc->start);
+       if (!etsects->regs) {
+               pr_err("ioremap ptp registers failed\n");
+               goto no_ioremap;
+       }
+       getnstimeofday(&now);
+       ptp_gianfar_settime(&etsects->caps, &now);
+
+       tmr_ctrl =
+         (etsects->tclk_period & TCLK_PERIOD_MASK) << TCLK_PERIOD_SHIFT |
+         (etsects->cksel & CKSEL_MASK) << CKSEL_SHIFT;
+
+       spin_lock_irqsave(&etsects->lock, flags);
+
+       gfar_write(&etsects->regs->tmr_ctrl,   tmr_ctrl);
+       gfar_write(&etsects->regs->tmr_add,    etsects->tmr_add);
+       gfar_write(&etsects->regs->tmr_prsc,   etsects->tmr_prsc);
+       gfar_write(&etsects->regs->tmr_fiper1, etsects->tmr_fiper1);
+       gfar_write(&etsects->regs->tmr_fiper2, etsects->tmr_fiper2);
+       set_alarm(etsects);
+       gfar_write(&etsects->regs->tmr_ctrl,   tmr_ctrl|FS|RTPE|TE);
+
+       spin_unlock_irqrestore(&etsects->lock, flags);
+
+       etsects->clock = ptp_clock_register(&etsects->caps);
+       if (IS_ERR(etsects->clock)) {
+               err = PTR_ERR(etsects->clock);
+               goto no_clock;
+       }
+
+       dev_set_drvdata(&dev->dev, etsects);
+
+       return 0;
+
+no_clock:
+no_ioremap:
+       release_resource(etsects->rsrc);
+no_resource:
+       free_irq(etsects->irq, etsects);
+no_node:
+       kfree(etsects);
+no_memory:
+       return err;
+}
+
+static int gianfar_ptp_remove(struct platform_device *dev)
+{
+       struct etsects *etsects = dev_get_drvdata(&dev->dev);
+
+       gfar_write(&etsects->regs->tmr_temask, 0);
+       gfar_write(&etsects->regs->tmr_ctrl,   0);
+
+       ptp_clock_unregister(etsects->clock);
+       iounmap(etsects->regs);
+       release_resource(etsects->rsrc);
+       free_irq(etsects->irq, etsects);
+       kfree(etsects);
+
+       return 0;
+}
+
+static struct of_device_id match_table[] = {
+       { .compatible = "fsl,etsec-ptp" },
+       {},
+};
+
+static struct platform_driver gianfar_ptp_driver = {
+       .driver = {
+               .name           = "gianfar_ptp",
+               .of_match_table = match_table,
+               .owner          = THIS_MODULE,
+       },
+       .probe       = gianfar_ptp_probe,
+       .remove      = gianfar_ptp_remove,
+};
+
+/* module operations */
+
+static int __init ptp_gianfar_init(void)
+{
+       return platform_driver_register(&gianfar_ptp_driver);
+}
+
+module_init(ptp_gianfar_init);
+
+static void __exit ptp_gianfar_exit(void)
+{
+       platform_driver_unregister(&gianfar_ptp_driver);
+}
+
+module_exit(ptp_gianfar_exit);
+
+MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>");
+MODULE_DESCRIPTION("PTP clock using the eTSEC");
+MODULE_LICENSE("GPL");
index 992089639ea4824404f42d53e5362eab2c2fb586..3e5d0b6b6516133039192fa5dfd1fdf88660d81b 100644 (file)
@@ -456,7 +456,7 @@ out:
  * a block of 6pack data has been received, which can now be decapsulated
  * and sent on to some IP layer for further processing.
  */
-static unsigned int sixpack_receive_buf(struct tty_struct *tty,
+static void sixpack_receive_buf(struct tty_struct *tty,
        const unsigned char *cp, char *fp, int count)
 {
        struct sixpack *sp;
@@ -464,11 +464,11 @@ static unsigned int sixpack_receive_buf(struct tty_struct *tty,
        int count1;
 
        if (!count)
-               return 0;
+               return;
 
        sp = sp_get(tty);
        if (!sp)
-               return -ENODEV;
+               return;
 
        memcpy(buf, cp, count < sizeof(buf) ? count : sizeof(buf));
 
@@ -487,8 +487,6 @@ static unsigned int sixpack_receive_buf(struct tty_struct *tty,
 
        sp_put(sp);
        tty_unthrottle(tty);
-
-       return count1;
 }
 
 /*
index a3c0dc9d8b98305ecbeda73f2bf61eb5a2c82b8c..9537aaa50c2f5f9633922b582ea4e9d6d67f3572 100644 (file)
@@ -69,7 +69,7 @@ static const char paranoia_str[] = KERN_ERR
 
 static const char bc_drvname[] = "baycom_epp";
 static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-"baycom_epp: version 0.7 compiled " __TIME__ " " __DATE__ "\n";
+"baycom_epp: version 0.7\n";
 
 /* --------------------------------------------------------------------- */
 
index 5f5af9a606f8aaddbb4b8724a651db14e5ecee05..279d2296290a46d5567eb0647dcca528ca3d18f4 100644 (file)
 
 static const char bc_drvname[] = "baycom_par";
 static const char bc_drvinfo[] = KERN_INFO "baycom_par: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-"baycom_par: version 0.9 compiled " __TIME__ " " __DATE__ "\n";
+"baycom_par: version 0.9\n";
 
 /* --------------------------------------------------------------------- */
 
index 3e25f10cabd60e9c93bc0898d23dfe1bf5f0351a..99cdce33df8b944b4575085b0327315460cf67da 100644 (file)
@@ -92,7 +92,7 @@
 
 static const char bc_drvname[] = "baycom_ser_fdx";
 static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-"baycom_ser_fdx: version 0.10 compiled " __TIME__ " " __DATE__ "\n";
+"baycom_ser_fdx: version 0.10\n";
 
 /* --------------------------------------------------------------------- */
 
index 1686f6dcbbce849525968a57152009faa24e2b63..d92fe6ca788f902dfa5b40cb47a1fcb65c6c9ab7 100644 (file)
@@ -80,7 +80,7 @@
 
 static const char bc_drvname[] = "baycom_ser_hdx";
 static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-"baycom_ser_hdx: version 0.10 compiled " __TIME__ " " __DATE__ "\n";
+"baycom_ser_hdx: version 0.10\n";
 
 /* --------------------------------------------------------------------- */
 
index 5b37579e84b788952988ce5f4b5d48738e16e472..a4a3516b6bbf87d05545a48d8e46627a5f81ee7c 100644 (file)
@@ -749,7 +749,7 @@ EXPORT_SYMBOL(hdlcdrv_unregister);
 static int __init hdlcdrv_init_driver(void)
 {
        printk(KERN_INFO "hdlcdrv: (C) 1996-2000 Thomas Sailer HB9JNX/AE4WA\n");
-       printk(KERN_INFO "hdlcdrv: version 0.8 compiled " __TIME__ " " __DATE__ "\n");
+       printk(KERN_INFO "hdlcdrv: version 0.8\n");
        return 0;
 }
 
index 0e4f23531140c8ca6f938447f145351c39b93a37..4c628393c8b157cbc09de52d902b5fa8c3d370a3 100644 (file)
@@ -923,14 +923,13 @@ static long mkiss_compat_ioctl(struct tty_struct *tty, struct file *file,
  * a block of data has been received, which can now be decapsulated
  * and sent on to the AX.25 layer for further processing.
  */
-static unsigned int mkiss_receive_buf(struct tty_struct *tty,
-               const unsigned char *cp, char *fp, int count)
+static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+       char *fp, int count)
 {
        struct mkiss *ax = mkiss_get(tty);
-       int bytes = count;
 
        if (!ax)
-               return -ENODEV;
+               return;
 
        /*
         * Argh! mtu change time! - costs us the packet part received
@@ -940,7 +939,7 @@ static unsigned int mkiss_receive_buf(struct tty_struct *tty,
                ax_changedmtu(ax);
 
        /* Read the characters out of the buffer */
-       while (bytes--) {
+       while (count--) {
                if (fp != NULL && *fp++) {
                        if (!test_and_set_bit(AXF_ERROR, &ax->flags))
                                ax->dev->stats.rx_errors++;
@@ -953,8 +952,6 @@ static unsigned int mkiss_receive_buf(struct tty_struct *tty,
 
        mkiss_put(ax);
        tty_unthrottle(tty);
-
-       return count;
 }
 
 /*
index c52a1df5d922b0e0e22bced1d0d0d046003acddc..c3ecb118c1df39f925e40f023f6e2f8a63ec763f 100644 (file)
@@ -188,14 +188,14 @@ struct hp100_private {
  *  variables
  */
 #ifdef CONFIG_ISA
-static const char *const hp100_isa_tbl[] __devinitconst = {
+static const char *hp100_isa_tbl[] = {
        "HWPF150", /* HP J2573 rev A */
        "HWP1950", /* HP J2573 */
 };
 #endif
 
 #ifdef CONFIG_EISA
-static const struct eisa_device_id hp100_eisa_tbl[] __devinitconst = {
+static struct eisa_device_id hp100_eisa_tbl[] = {
        { "HWPF180" }, /* HP J2577 rev A */
        { "HWP1920" }, /* HP 27248B */
        { "HWP1940" }, /* HP J2577 */
@@ -336,7 +336,7 @@ static __devinit const char *hp100_read_id(int ioaddr)
 }
 
 #ifdef CONFIG_ISA
-static __devinit int hp100_isa_probe1(struct net_device *dev, int ioaddr)
+static __init int hp100_isa_probe1(struct net_device *dev, int ioaddr)
 {
        const char *sig;
        int i;
@@ -372,7 +372,7 @@ static __devinit int hp100_isa_probe1(struct net_device *dev, int ioaddr)
  * EISA and PCI are handled by device infrastructure.
  */
 
-static int  __devinit hp100_isa_probe(struct net_device *dev, int addr)
+static int  __init hp100_isa_probe(struct net_device *dev, int addr)
 {
        int err = -ENODEV;
 
@@ -396,7 +396,7 @@ static int  __devinit hp100_isa_probe(struct net_device *dev, int addr)
 #endif /* CONFIG_ISA */
 
 #if !defined(MODULE) && defined(CONFIG_ISA)
-struct net_device * __devinit hp100_probe(int unit)
+struct net_device * __init hp100_probe(int unit)
 {
        struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private));
        int err;
@@ -1580,12 +1580,12 @@ static netdev_tx_t hp100_start_xmit_bm(struct sk_buff *skb,
        hp100_outl(ringptr->pdl_paddr, TX_PDA_L);       /* Low Prio. Queue */
 
        lp->txrcommit++;
-       spin_unlock_irqrestore(&lp->lock, flags);
 
-       /* Update statistics */
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += skb->len;
 
+       spin_unlock_irqrestore(&lp->lock, flags);
+
        return NETDEV_TX_OK;
 
 drop:
@@ -2843,7 +2843,7 @@ static void cleanup_dev(struct net_device *d)
 }
 
 #ifdef CONFIG_EISA
-static int __devinit hp100_eisa_probe (struct device *gendev)
+static int __init hp100_eisa_probe (struct device *gendev)
 {
        struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private));
        struct eisa_device *edev = to_eisa_device(gendev);
index b6060f7538dfc42d250ef9bbd59bb93221fd6fd7..a900d5bf294889578df802c280ca4388bce57631 100644 (file)
@@ -135,7 +135,7 @@ static void __devexit hplance_remove_one(struct dio_dev *d)
 }
 
 /* Initialise a single lance board at the given DIO device */
-static void __init hplance_init(struct net_device *dev, struct dio_dev *d)
+static void __devinit hplance_init(struct net_device *dev, struct dio_dev *d)
 {
         unsigned long va = (d->resource.start + DIO_VIRADDRBASE);
         struct hplance_private *lp;
index 136d7544cc33331c735684b56b44cffb27ef8b94..a7d6cad3295368a85f5720965746930141f51ac6 100644 (file)
@@ -895,12 +895,12 @@ static int ibmlana_irq;
 static int ibmlana_io;
 static int startslot;          /* counts through slots when probing multiple devices */
 
-static const short ibmlana_adapter_ids[] __devinitconst = {
+static short ibmlana_adapter_ids[] __initdata = {
        IBM_LANA_ID,
        0x0000
 };
 
-static const char *const ibmlana_adapter_names[] __devinitconst = {
+static char *ibmlana_adapter_names[] __devinitdata = {
        "IBM LAN Adapter/A",
        NULL
 };
index 18fccf913635e671fbca0d321c73aa4c484e2f42..2c28621eb30b5aa02e0e7fe6d214f5e4c0b60f72 100644 (file)
@@ -2373,6 +2373,9 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
        }
 #endif /* CONFIG_PCI_IOV */
        adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES, num_online_cpus());
+       /* i350 cannot do RSS and SR-IOV at the same time */
+       if (hw->mac.type == e1000_i350 && adapter->vfs_allocated_count)
+               adapter->rss_queues = 1;
 
        /*
         * if rss_queues > 4 or vfs are going to be allocated with rss_queues
index 96c95617195f6b18baf79c73f0f33beff21e14fd..32f07f868d8914e58020860af796944a00f195b4 100644 (file)
@@ -915,7 +915,7 @@ static void ioc3_alloc_rings(struct net_device *dev)
 
                        skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
                        if (!skb) {
-                               show_free_areas();
+                               show_free_areas(0);
                                continue;
                        }
 
index f940dfa1f7f84e713033057605bfb069618ec0bb..9d4ce1aba10c1fdbc2ae6a8b1a20b40ee2134fb9 100644 (file)
@@ -67,27 +67,27 @@ static void bfin_sir_stop_tx(struct bfin_sir_port *port)
        disable_dma(port->tx_dma_channel);
 #endif
 
-       while (!(SIR_UART_GET_LSR(port) & THRE)) {
+       while (!(UART_GET_LSR(port) & THRE)) {
                cpu_relax();
                continue;
        }
 
-       SIR_UART_STOP_TX(port);
+       UART_CLEAR_IER(port, ETBEI);
 }
 
 static void bfin_sir_enable_tx(struct bfin_sir_port *port)
 {
-       SIR_UART_ENABLE_TX(port);
+       UART_SET_IER(port, ETBEI);
 }
 
 static void bfin_sir_stop_rx(struct bfin_sir_port *port)
 {
-       SIR_UART_STOP_RX(port);
+       UART_CLEAR_IER(port, ERBFI);
 }
 
 static void bfin_sir_enable_rx(struct bfin_sir_port *port)
 {
-       SIR_UART_ENABLE_RX(port);
+       UART_SET_IER(port, ERBFI);
 }
 
 static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed)
@@ -116,7 +116,7 @@ static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed)
 
                do {
                        udelay(utime);
-                       lsr = SIR_UART_GET_LSR(port);
+                       lsr = UART_GET_LSR(port);
                } while (!(lsr & TEMT) && count--);
 
                /* The useconds for 1 bits to transmit */
@@ -125,27 +125,27 @@ static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed)
                /* Clear UCEN bit to reset the UART state machine
                 * and control registers
                 */
-               val = SIR_UART_GET_GCTL(port);
+               val = UART_GET_GCTL(port);
                val &= ~UCEN;
-               SIR_UART_PUT_GCTL(port, val);
+               UART_PUT_GCTL(port, val);
 
                /* Set DLAB in LCR to Access THR RBR IER */
-               SIR_UART_SET_DLAB(port);
+               UART_SET_DLAB(port);
                SSYNC();
 
-               SIR_UART_PUT_DLL(port, quot & 0xFF);
-               SIR_UART_PUT_DLH(port, (quot >> 8) & 0xFF);
+               UART_PUT_DLL(port, quot & 0xFF);
+               UART_PUT_DLH(port, (quot >> 8) & 0xFF);
                SSYNC();
 
                /* Clear DLAB in LCR */
-               SIR_UART_CLEAR_DLAB(port);
+               UART_CLEAR_DLAB(port);
                SSYNC();
 
-               SIR_UART_PUT_LCR(port, lcr);
+               UART_PUT_LCR(port, lcr);
 
-               val = SIR_UART_GET_GCTL(port);
+               val = UART_GET_GCTL(port);
                val |= UCEN;
-               SIR_UART_PUT_GCTL(port, val);
+               UART_PUT_GCTL(port, val);
 
                ret = 0;
                break;
@@ -154,12 +154,12 @@ static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed)
                break;
        }
 
-       val = SIR_UART_GET_GCTL(port);
+       val = UART_GET_GCTL(port);
        /* If not add the 'RPOLC', we can't catch the receive interrupt.
         * It's related with the HW layout and the IR transiver.
         */
        val |= IREN | RPOLC;
-       SIR_UART_PUT_GCTL(port, val);
+       UART_PUT_GCTL(port, val);
        return ret;
 }
 
@@ -168,7 +168,7 @@ static int bfin_sir_is_receiving(struct net_device *dev)
        struct bfin_sir_self *self = netdev_priv(dev);
        struct bfin_sir_port *port = self->sir_port;
 
-       if (!(SIR_UART_GET_IER(port) & ERBFI))
+       if (!(UART_GET_IER(port) & ERBFI))
                return 0;
        return self->rx_buff.state != OUTSIDE_FRAME;
 }
@@ -182,7 +182,7 @@ static void bfin_sir_tx_chars(struct net_device *dev)
 
        if (self->tx_buff.len != 0) {
                chr = *(self->tx_buff.data);
-               SIR_UART_PUT_CHAR(port, chr);
+               UART_PUT_CHAR(port, chr);
                self->tx_buff.data++;
                self->tx_buff.len--;
        } else {
@@ -206,8 +206,8 @@ static void bfin_sir_rx_chars(struct net_device *dev)
        struct bfin_sir_port *port = self->sir_port;
        unsigned char ch;
 
-       SIR_UART_CLEAR_LSR(port);
-       ch = SIR_UART_GET_CHAR(port);
+       UART_CLEAR_LSR(port);
+       ch = UART_GET_CHAR(port);
        async_unwrap_char(dev, &self->stats, &self->rx_buff, ch);
        dev->last_rx = jiffies;
 }
@@ -219,7 +219,7 @@ static irqreturn_t bfin_sir_rx_int(int irq, void *dev_id)
        struct bfin_sir_port *port = self->sir_port;
 
        spin_lock(&self->lock);
-       while ((SIR_UART_GET_LSR(port) & DR))
+       while ((UART_GET_LSR(port) & DR))
                bfin_sir_rx_chars(dev);
        spin_unlock(&self->lock);
 
@@ -233,7 +233,7 @@ static irqreturn_t bfin_sir_tx_int(int irq, void *dev_id)
        struct bfin_sir_port *port = self->sir_port;
 
        spin_lock(&self->lock);
-       if (SIR_UART_GET_LSR(port) & THRE)
+       if (UART_GET_LSR(port) & THRE)
                bfin_sir_tx_chars(dev);
        spin_unlock(&self->lock);
 
@@ -312,7 +312,7 @@ static void bfin_sir_dma_rx_chars(struct net_device *dev)
        struct bfin_sir_port *port = self->sir_port;
        int i;
 
-       SIR_UART_CLEAR_LSR(port);
+       UART_CLEAR_LSR(port);
 
        for (i = port->rx_dma_buf.head; i < port->rx_dma_buf.tail; i++)
                async_unwrap_char(dev, &self->stats, &self->rx_buff, port->rx_dma_buf.buf[i]);
@@ -430,11 +430,10 @@ static void bfin_sir_shutdown(struct bfin_sir_port *port, struct net_device *dev
        unsigned short val;
 
        bfin_sir_stop_rx(port);
-       SIR_UART_DISABLE_INTS(port);
 
-       val = SIR_UART_GET_GCTL(port);
+       val = UART_GET_GCTL(port);
        val &= ~(UCEN | IREN | RPOLC);
-       SIR_UART_PUT_GCTL(port, val);
+       UART_PUT_GCTL(port, val);
 
 #ifdef CONFIG_SIR_BFIN_DMA
        disable_dma(port->tx_dma_channel);
@@ -518,12 +517,12 @@ static void bfin_sir_send_work(struct work_struct *work)
         * sending data. We also can set the speed, which will
         * reset all the UART.
         */
-       val = SIR_UART_GET_GCTL(port);
+       val = UART_GET_GCTL(port);
        val &= ~(IREN | RPOLC);
-       SIR_UART_PUT_GCTL(port, val);
+       UART_PUT_GCTL(port, val);
        SSYNC();
        val |= IREN | RPOLC;
-       SIR_UART_PUT_GCTL(port, val);
+       UART_PUT_GCTL(port, val);
        SSYNC();
        /* bfin_sir_set_speed(port, self->speed); */
 
index e3b285a677348f1c39f4f6a4cff0fbe77c3af46b..29cbde8501ed8e09750f771204dfe9fc38503d34 100644 (file)
@@ -26,7 +26,6 @@
 #include <asm/cacheflush.h>
 #include <asm/dma.h>
 #include <asm/portmux.h>
-#include <mach/bfin_serial_5xx.h>
 #undef DRIVER_NAME
 
 #ifdef CONFIG_SIR_BFIN_DMA
@@ -83,64 +82,10 @@ struct bfin_sir_self {
 
 #define DRIVER_NAME "bfin_sir"
 
-#define SIR_UART_GET_CHAR(port)    bfin_read16((port)->membase + OFFSET_RBR)
-#define SIR_UART_GET_DLL(port)     bfin_read16((port)->membase + OFFSET_DLL)
-#define SIR_UART_GET_DLH(port)     bfin_read16((port)->membase + OFFSET_DLH)
-#define SIR_UART_GET_LCR(port)     bfin_read16((port)->membase + OFFSET_LCR)
-#define SIR_UART_GET_GCTL(port)    bfin_read16((port)->membase + OFFSET_GCTL)
-
-#define SIR_UART_PUT_CHAR(port, v) bfin_write16(((port)->membase + OFFSET_THR), v)
-#define SIR_UART_PUT_DLL(port, v)  bfin_write16(((port)->membase + OFFSET_DLL), v)
-#define SIR_UART_PUT_DLH(port, v)  bfin_write16(((port)->membase + OFFSET_DLH), v)
-#define SIR_UART_PUT_LCR(port, v)  bfin_write16(((port)->membase + OFFSET_LCR), v)
-#define SIR_UART_PUT_GCTL(port, v) bfin_write16(((port)->membase + OFFSET_GCTL), v)
-
-#ifdef CONFIG_BF54x
-#define SIR_UART_GET_LSR(port)     bfin_read16((port)->membase + OFFSET_LSR)
-#define SIR_UART_GET_IER(port)     bfin_read16((port)->membase + OFFSET_IER_SET)
-#define SIR_UART_SET_IER(port, v)  bfin_write16(((port)->membase + OFFSET_IER_SET), v)
-#define SIR_UART_CLEAR_IER(port, v) bfin_write16(((port)->membase + OFFSET_IER_CLEAR), v)
-#define SIR_UART_PUT_LSR(port, v)  bfin_write16(((port)->membase + OFFSET_LSR), v)
-#define SIR_UART_CLEAR_LSR(port)   bfin_write16(((port)->membase + OFFSET_LSR), -1)
-
-#define SIR_UART_SET_DLAB(port)
-#define SIR_UART_CLEAR_DLAB(port)
-
-#define SIR_UART_ENABLE_INTS(port, v) SIR_UART_SET_IER(port, v)
-#define SIR_UART_DISABLE_INTS(port)   SIR_UART_CLEAR_IER(port, 0xF)
-#define SIR_UART_STOP_TX(port)     do { SIR_UART_PUT_LSR(port, TFI); SIR_UART_CLEAR_IER(port, ETBEI); } while (0)
-#define SIR_UART_ENABLE_TX(port)   do { SIR_UART_SET_IER(port, ETBEI); } while (0)
-#define SIR_UART_STOP_RX(port)     do { SIR_UART_CLEAR_IER(port, ERBFI); } while (0)
-#define SIR_UART_ENABLE_RX(port)   do { SIR_UART_SET_IER(port, ERBFI); } while (0)
-#else
-
-#define SIR_UART_GET_IIR(port)     bfin_read16((port)->membase + OFFSET_IIR)
-#define SIR_UART_GET_IER(port)     bfin_read16((port)->membase + OFFSET_IER)
-#define SIR_UART_PUT_IER(port, v)  bfin_write16(((port)->membase + OFFSET_IER), v)
-
-#define SIR_UART_SET_DLAB(port)    do { SIR_UART_PUT_LCR(port, SIR_UART_GET_LCR(port) | DLAB); } while (0)
-#define SIR_UART_CLEAR_DLAB(port)  do { SIR_UART_PUT_LCR(port, SIR_UART_GET_LCR(port) & ~DLAB); } while (0)
-
-#define SIR_UART_ENABLE_INTS(port, v) SIR_UART_PUT_IER(port, v)
-#define SIR_UART_DISABLE_INTS(port)   SIR_UART_PUT_IER(port, 0)
-#define SIR_UART_STOP_TX(port)     do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) & ~ETBEI); } while (0)
-#define SIR_UART_ENABLE_TX(port)   do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) | ETBEI); } while (0)
-#define SIR_UART_STOP_RX(port)     do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) & ~ERBFI); } while (0)
-#define SIR_UART_ENABLE_RX(port)   do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) | ERBFI); } while (0)
-
-static inline unsigned int SIR_UART_GET_LSR(struct bfin_sir_port *port)
-{
-       unsigned int lsr = bfin_read16(port->membase + OFFSET_LSR);
-       port->lsr |= (lsr & (BI|FE|PE|OE));
-       return lsr | port->lsr;
-}
-
-static inline void SIR_UART_CLEAR_LSR(struct bfin_sir_port *port)
-{
-       port->lsr = 0;
-       bfin_read16(port->membase + OFFSET_LSR);
-}
-#endif
+#define port_membase(port)     (((struct bfin_sir_port *)(port))->membase)
+#define get_lsr_cache(port)    (((struct bfin_sir_port *)(port))->lsr)
+#define put_lsr_cache(port, v) (((struct bfin_sir_port *)(port))->lsr = (v))
+#include <asm/bfin_serial.h>
 
 static const unsigned short per[][4] = {
        /* rx pin      tx pin     NULL  uart_number */
index 035861d8acb157f47d080b074c1de9a73a2988e1..3352b2443e58eb1ca0a45856c628850c08092be6 100644 (file)
@@ -216,23 +216,23 @@ static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t
  * usbserial:  urb-complete-interrupt / softint
  */
 
-static unsigned int irtty_receive_buf(struct tty_struct *tty,
-               const unsigned char *cp, char *fp, int count)
+static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                             char *fp, int count) 
 {
        struct sir_dev *dev;
        struct sirtty_cb *priv = tty->disc_data;
        int     i;
 
-       IRDA_ASSERT(priv != NULL, return -ENODEV;);
-       IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -EINVAL;);
+       IRDA_ASSERT(priv != NULL, return;);
+       IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
 
        if (unlikely(count==0))         /* yes, this happens */
-               return 0;
+               return;
 
        dev = priv->dev;
        if (!dev) {
                IRDA_WARNING("%s(), not ready yet!\n", __func__);
-               return -ENODEV;
+               return;
        }
 
        for (i = 0; i < count; i++) {
@@ -242,13 +242,11 @@ static unsigned int irtty_receive_buf(struct tty_struct *tty,
                if (fp && *fp++) { 
                        IRDA_DEBUG(0, "Framing or parity error!\n");
                        sirdev_receive(dev, NULL, 0);   /* notify sir_dev (updating stats) */
-                       return -EINVAL;
+                       return;
                }
        }
 
        sirdev_receive(dev, cp, count);
-
-       return count;
 }
 
 /*
index 69b5707db369e3dfdcbde140b5aa69e60803e47b..8800e1fe4129a84a41b2a6d5da495b5e807b8301 100644 (file)
@@ -222,19 +222,19 @@ static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 s
 static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self);
 
 /* Probing */
-static int smsc_ircc_look_for_chips(void);
-static const struct smsc_chip * smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type);
-static int smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
-static int smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
-static int smsc_superio_fdc(unsigned short cfg_base);
-static int smsc_superio_lpc(unsigned short cfg_base);
+static int __init smsc_ircc_look_for_chips(void);
+static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type);
+static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
+static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
+static int __init smsc_superio_fdc(unsigned short cfg_base);
+static int __init smsc_superio_lpc(unsigned short cfg_base);
 #ifdef CONFIG_PCI
-static int preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf);
-static int preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
-static void preconfigure_ali_port(struct pci_dev *dev,
+static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf);
+static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
+static void __init preconfigure_ali_port(struct pci_dev *dev,
                                         unsigned short port);
-static int preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
-static int smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
+static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
+static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
                                                    unsigned short ircc_fir,
                                                    unsigned short ircc_sir,
                                                    unsigned char ircc_dma,
@@ -366,7 +366,7 @@ static inline void register_bank(int iobase, int bank)
 }
 
 /* PNP hotplug support */
-static const struct pnp_device_id smsc_ircc_pnp_table[] __devinitconst = {
+static const struct pnp_device_id smsc_ircc_pnp_table[] = {
        { .id = "SMCf010", .driver_data = 0 },
        /* and presumably others */
        { }
@@ -515,7 +515,7 @@ static const struct net_device_ops smsc_ircc_netdev_ops = {
  *    Try to open driver instance
  *
  */
-static int __devinit smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq)
+static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq)
 {
        struct smsc_ircc_cb *self;
        struct net_device *dev;
@@ -2273,7 +2273,7 @@ static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned sho
 }
 
 
-static int __devinit smsc_access(unsigned short cfg_base, unsigned char reg)
+static int __init smsc_access(unsigned short cfg_base, unsigned char reg)
 {
        IRDA_DEBUG(1, "%s\n", __func__);
 
@@ -2281,7 +2281,7 @@ static int __devinit smsc_access(unsigned short cfg_base, unsigned char reg)
        return inb(cfg_base) != reg ? -1 : 0;
 }
 
-static const struct smsc_chip * __devinit smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type)
+static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type)
 {
        u8 devid, xdevid, rev;
 
@@ -2406,7 +2406,7 @@ static int __init smsc_superio_lpc(unsigned short cfg_base)
 #ifdef CONFIG_PCI
 #define PCIID_VENDOR_INTEL 0x8086
 #define PCIID_VENDOR_ALI 0x10b9
-static const struct smsc_ircc_subsystem_configuration subsystem_configurations[] __devinitconst = {
+static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = {
        /*
         * Subsystems needing entries:
         * 0x10b9:0x1533 0x103c:0x0850 HP nx9010 family
@@ -2532,7 +2532,7 @@ static const struct smsc_ircc_subsystem_configuration subsystem_configurations[]
  * (FIR port, SIR port, FIR DMA, FIR IRQ)
  * through the chip configuration port.
  */
-static int __devinit preconfigure_smsc_chip(struct
+static int __init preconfigure_smsc_chip(struct
                                         smsc_ircc_subsystem_configuration
                                         *conf)
 {
@@ -2633,7 +2633,7 @@ static int __devinit preconfigure_smsc_chip(struct
  * or Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge.
  * They all work the same way!
  */
-static int __devinit preconfigure_through_82801(struct pci_dev *dev,
+static int __init preconfigure_through_82801(struct pci_dev *dev,
                                             struct
                                             smsc_ircc_subsystem_configuration
                                             *conf)
@@ -2786,7 +2786,7 @@ static int __devinit preconfigure_through_82801(struct pci_dev *dev,
  * This is based on reverse-engineering since ALi does not
  * provide any data sheet for the 1533 chip.
  */
-static void __devinit preconfigure_ali_port(struct pci_dev *dev,
+static void __init preconfigure_ali_port(struct pci_dev *dev,
                                         unsigned short port)
 {
        unsigned char reg;
@@ -2824,7 +2824,7 @@ static void __devinit preconfigure_ali_port(struct pci_dev *dev,
        IRDA_MESSAGE("Activated ALi 1533 ISA bridge port 0x%04x.\n", port);
 }
 
-static int __devinit preconfigure_through_ali(struct pci_dev *dev,
+static int __init preconfigure_through_ali(struct pci_dev *dev,
                                           struct
                                           smsc_ircc_subsystem_configuration
                                           *conf)
@@ -2837,7 +2837,7 @@ static int __devinit preconfigure_through_ali(struct pci_dev *dev,
        return preconfigure_smsc_chip(conf);
 }
 
-static int __devinit smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
+static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
                                                    unsigned short ircc_fir,
                                                    unsigned short ircc_sir,
                                                    unsigned char ircc_dma,
@@ -2849,7 +2849,7 @@ static int __devinit smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
        int ret = 0;
 
        for_each_pci_dev(dev) {
-               const struct smsc_ircc_subsystem_configuration *conf;
+               struct smsc_ircc_subsystem_configuration *conf;
 
                /*
                 * Cache the subsystem vendor/device:
index f0d8346d0fa5d2d3dcf62c402a4d65d5dc9729d6..fc12ac0d9f2e55012d202a44acfca9e8d432c6bd 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
@@ -662,7 +661,7 @@ static void ks8842_rx_frame(struct net_device *netdev,
 
        /* check the status */
        if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) {
-               struct sk_buff *skb = netdev_alloc_skb_ip_align(netdev, len);
+               struct sk_buff *skb = netdev_alloc_skb_ip_align(netdev, len + 3);
 
                if (skb) {
 
@@ -1146,7 +1145,7 @@ static int __devinit ks8842_probe(struct platform_device *pdev)
        struct resource *iomem;
        struct net_device *netdev;
        struct ks8842_adapter *adapter;
-       struct ks8842_platform_data *pdata = mfd_get_data(pdev);
+       struct ks8842_platform_data *pdata = pdev->dev.platform_data;
        u16 id;
        unsigned i;
 
index e8984b0ca52104c08e9bddf4eafeec8630a5d167..243ed2aee88e35e801a2c6582f8a80d4e287ba7b 100644 (file)
@@ -80,20 +80,17 @@ static void ne3210_block_output(struct net_device *dev, int count, const unsigne
 
 #define NE3210_DEBUG   0x0
 
-static const unsigned char irq_map[] __devinitconst =
-       { 15, 12, 11, 10, 9, 7, 5, 3 };
-static const unsigned int shmem_map[] __devinitconst =
-       { 0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0 };
-static const char *const ifmap[] __devinitconst =
-       { "UTP", "?", "BNC", "AUI" };
-static const int ifmap_val[] __devinitconst = {
+static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
+static unsigned int shmem_map[] __initdata = {0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0};
+static const char *ifmap[] __initdata = {"UTP", "?", "BNC", "AUI"};
+static int ifmap_val[] __initdata = {
                IF_PORT_10BASET,
                IF_PORT_UNKNOWN,
                IF_PORT_10BASE2,
                IF_PORT_AUI,
 };
 
-static int __devinit ne3210_eisa_probe (struct device *device)
+static int __init ne3210_eisa_probe (struct device *device)
 {
        unsigned long ioaddr, phys_mem;
        int i, retval, port_index;
@@ -316,7 +313,7 @@ static void ne3210_block_output(struct net_device *dev, int count,
        memcpy_toio(shmem, buf, count);
 }
 
-static const struct eisa_device_id ne3210_ids[] __devinitconst = {
+static struct eisa_device_id ne3210_ids[] = {
        { "EGL0101" },
        { "NVL1801" },
        { "" },
index b644383017f91eba49e845048dde1e51d3241796..c0788a31ff0f4a8c0ee8b637ba335e69b7cd3056 100644 (file)
@@ -1965,11 +1965,11 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        netxen_tso_check(netdev, tx_ring, first_desc, skb);
 
-       netxen_nic_update_cmd_producer(adapter, tx_ring);
-
        adapter->stats.txbytes += skb->len;
        adapter->stats.xmitcalled++;
 
+       netxen_nic_update_cmd_producer(adapter, tx_ring);
+
        return NETDEV_TX_OK;
 
 drop_packet:
index 81ac330f931d67b6b15eab36faa415b20fbbca9f..34c5e1cbf65d30aa2f7491be4eb493375ac6482c 100644 (file)
@@ -1150,7 +1150,7 @@ static int el3_close(struct net_device *dev)
        return 0;
 }
 
-static struct pcmcia_device_id tc574_ids[] = {
+static const struct pcmcia_device_id tc574_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0574),
        PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "cis/3CCFEM556.cis"),
        PCMCIA_DEVICE_NULL,
index 79b9ca0dbdb4351f3c7182833fae229e1b765222..4a1a358098075341d27d6e8de596bfb6428ba193 100644 (file)
@@ -908,7 +908,7 @@ static int el3_close(struct net_device *dev)
     return 0;
 }
 
-static struct pcmcia_device_id tc589_ids[] = {
+static const struct pcmcia_device_id tc589_ids[] = {
        PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0101, 0x0562),
        PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77),
        PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589),
index 3077d72e8222b6fd78a6f6b2a8c08fd5c66eca85..9953db71196993c9eb6d7515a131a5d370e657c6 100644 (file)
@@ -687,7 +687,7 @@ static void block_output(struct net_device *dev, int count,
     outsw(nic_base + AXNET_DATAPORT, buf, count>>1);
 }
 
-static struct pcmcia_device_id axnet_ids[] = {
+static const struct pcmcia_device_id axnet_ids[] = {
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x016c, 0x0081),
        PCMCIA_DEVICE_MANF_CARD(0x018a, 0x0301),
        PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328),
index 27bfad76fc4077bdaa74187a79c2f0beb53c4ffc..980e65c14936e28957ac29187853b555a0d60a09 100644 (file)
@@ -316,7 +316,7 @@ static int com20020_resume(struct pcmcia_device *link)
        return 0;
 }
 
-static struct pcmcia_device_id com20020_ids[] = {
+static const struct pcmcia_device_id com20020_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
                        "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
        PCMCIA_DEVICE_PROD_ID12("SoHard AG",
index 530ab5a10bd3a8395e0ff4ef68b9732d21fda100..723815e7a9973e77116d6a089871449dddb93f2c 100644 (file)
@@ -667,7 +667,7 @@ static int fmvj18x_resume(struct pcmcia_device *link)
 
 /*====================================================================*/
 
-static struct pcmcia_device_id fmvj18x_ids[] = {
+static const struct pcmcia_device_id fmvj18x_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0004, 0x0004),
        PCMCIA_DEVICE_PROD_ID12("EAGLE Technology", "NE200 ETHERNET LAN MBH10302 04", 0x528c88c4, 0x74f91e59),
        PCMCIA_DEVICE_PROD_ID12("Eiger Labs,Inc", "EPX-10BT PC Card Ethernet 10BT", 0x53af556e, 0x877f9922),
index 15d57f5b6f2967b0eadb3335b1ec835230ec7f1b..6006d5488fbed8e07c17076a6630f7ccdb4aa680 100644 (file)
@@ -340,7 +340,7 @@ static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
     outb(0x40, dev->base_addr);
 }
 
-static struct pcmcia_device_id ibmtr_ids[] = {
+static const struct pcmcia_device_id ibmtr_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e),
        PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47),
        PCMCIA_DEVICE_NULL,
index 76683d97d83b11504a0cc2049aae45383659d79f..9d70b65952201c646d90f0e21bd9658d34ad2502 100644 (file)
@@ -1494,7 +1494,7 @@ static void set_multicast_list(struct net_device *dev)
 
 } /* set_multicast_list */
 
-static struct pcmcia_device_id nmclan_ids[] = {
+static const struct pcmcia_device_id nmclan_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Ethernet", 0x085a850b, 0x00b2e941),
        PCMCIA_DEVICE_PROD_ID12("Portable Add-ons", "Ethernet+", 0xebf1d60, 0xad673aaf),
        PCMCIA_DEVICE_NULL,
index e953793a33fffab32fe71a315e338c35f5b8fa5f..b4fd7c3ed07792dc6a88816c72946ee9c424f1ca 100644 (file)
@@ -1463,7 +1463,7 @@ failed:
 
 /*====================================================================*/
 
-static struct pcmcia_device_id pcnet_ids[] = {
+static const struct pcmcia_device_id pcnet_ids[] = {
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0057, 0x0021),
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0104, 0x000a),
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0xea15),
index 288e4f1317ee71943e417c55d6141cb3e0b5bf73..1cd9394c33598eb500796e9e6921ad5128d14cd9 100644 (file)
@@ -2014,7 +2014,7 @@ static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
        return rc;
 }
 
-static struct pcmcia_device_id smc91c92_ids[] = {
+static const struct pcmcia_device_id smc91c92_ids[] = {
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501),
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a),
        PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
index a46b7fd6c0f5483f4a117f4c3c9a7e00b7b93e81..e33b190d716fc7f7cf0c56a8ca0783110e999c47 100644 (file)
@@ -1738,7 +1738,7 @@ do_stop(struct net_device *dev)
     return 0;
 }
 
-static struct pcmcia_device_id xirc2ps_ids[] = {
+static const struct pcmcia_device_id xirc2ps_ids[] = {
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0089, 0x110a),
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0138, 0x110a),
        PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
index 392a6c4b72e5e4decda29324c4b82708311ec7dd..a70244306c9462830c4ebde0b87334ef7667fa0e 100644 (file)
@@ -58,6 +58,7 @@ config BROADCOM_PHY
 
 config BCM63XX_PHY
        tristate "Drivers for Broadcom 63xx SOCs internal PHY"
+       depends on BCM63XX
        ---help---
          Currently supports the 6348 and 6358 PHYs.
 
index 13bebab65d027c9a9c3c3c6aef2a823d1033859a..2333215bbb322e0ba7bce5705c34cc810f07eb7a 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_FIXED_PHY)               += fixed.o
 obj-$(CONFIG_MDIO_BITBANG)     += mdio-bitbang.o
 obj-$(CONFIG_MDIO_GPIO)                += mdio-gpio.o
 obj-$(CONFIG_NATIONAL_PHY)     += national.o
+obj-$(CONFIG_DP83640_PHY)      += dp83640.o
 obj-$(CONFIG_STE10XP)          += ste10Xp.o
 obj-$(CONFIG_MICREL_PHY)       += micrel.o
 obj-$(CONFIG_MDIO_OCTEON)      += mdio-octeon.o
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
new file mode 100644 (file)
index 0000000..2cd8dc5
--- /dev/null
@@ -0,0 +1,1110 @@
+/*
+ * Driver for the National Semiconductor DP83640 PHYTER
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/ethtool.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/net_tstamp.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/ptp_classify.h>
+#include <linux/ptp_clock_kernel.h>
+
+#include "dp83640_reg.h"
+
+#define DP83640_PHY_ID 0x20005ce1
+#define PAGESEL                0x13
+#define LAYER4         0x02
+#define LAYER2         0x01
+#define MAX_RXTS       4
+#define MAX_TXTS       4
+#define N_EXT_TS       1
+#define PSF_PTPVER     2
+#define PSF_EVNT       0x4000
+#define PSF_RX         0x2000
+#define PSF_TX         0x1000
+#define EXT_EVENT      1
+#define EXT_GPIO       1
+#define CAL_EVENT      2
+#define CAL_GPIO       9
+#define CAL_TRIGGER    2
+
+/* phyter seems to miss the mark by 16 ns */
+#define ADJTIME_FIX    16
+
+#if defined(__BIG_ENDIAN)
+#define ENDIAN_FLAG    0
+#elif defined(__LITTLE_ENDIAN)
+#define ENDIAN_FLAG    PSF_ENDIAN
+#endif
+
+#define SKB_PTP_TYPE(__skb) (*(unsigned int *)((__skb)->cb))
+
+struct phy_rxts {
+       u16 ns_lo;   /* ns[15:0] */
+       u16 ns_hi;   /* overflow[1:0], ns[29:16] */
+       u16 sec_lo;  /* sec[15:0] */
+       u16 sec_hi;  /* sec[31:16] */
+       u16 seqid;   /* sequenceId[15:0] */
+       u16 msgtype; /* messageType[3:0], hash[11:0] */
+};
+
+struct phy_txts {
+       u16 ns_lo;   /* ns[15:0] */
+       u16 ns_hi;   /* overflow[1:0], ns[29:16] */
+       u16 sec_lo;  /* sec[15:0] */
+       u16 sec_hi;  /* sec[31:16] */
+};
+
+struct rxts {
+       struct list_head list;
+       unsigned long tmo;
+       u64 ns;
+       u16 seqid;
+       u8  msgtype;
+       u16 hash;
+};
+
+struct dp83640_clock;
+
+struct dp83640_private {
+       struct list_head list;
+       struct dp83640_clock *clock;
+       struct phy_device *phydev;
+       struct work_struct ts_work;
+       int hwts_tx_en;
+       int hwts_rx_en;
+       int layer;
+       int version;
+       /* remember state of cfg0 during calibration */
+       int cfg0;
+       /* remember the last event time stamp */
+       struct phy_txts edata;
+       /* list of rx timestamps */
+       struct list_head rxts;
+       struct list_head rxpool;
+       struct rxts rx_pool_data[MAX_RXTS];
+       /* protects above three fields from concurrent access */
+       spinlock_t rx_lock;
+       /* queues of incoming and outgoing packets */
+       struct sk_buff_head rx_queue;
+       struct sk_buff_head tx_queue;
+};
+
+struct dp83640_clock {
+       /* keeps the instance in the 'phyter_clocks' list */
+       struct list_head list;
+       /* we create one clock instance per MII bus */
+       struct mii_bus *bus;
+       /* protects extended registers from concurrent access */
+       struct mutex extreg_lock;
+       /* remembers which page was last selected */
+       int page;
+       /* our advertised capabilities */
+       struct ptp_clock_info caps;
+       /* protects the three fields below from concurrent access */
+       struct mutex clock_lock;
+       /* the one phyter from which we shall read */
+       struct dp83640_private *chosen;
+       /* list of the other attached phyters, not chosen */
+       struct list_head phylist;
+       /* reference to our PTP hardware clock */
+       struct ptp_clock *ptp_clock;
+};
+
+/* globals */
+
+static int chosen_phy = -1;
+static ushort cal_gpio = 4;
+
+module_param(chosen_phy, int, 0444);
+module_param(cal_gpio, ushort, 0444);
+
+MODULE_PARM_DESC(chosen_phy, \
+       "The address of the PHY to use for the ancillary clock features");
+MODULE_PARM_DESC(cal_gpio, \
+       "Which GPIO line to use for synchronizing multiple PHYs");
+
+/* a list of clocks and a mutex to protect it */
+static LIST_HEAD(phyter_clocks);
+static DEFINE_MUTEX(phyter_clocks_lock);
+
+static void rx_timestamp_work(struct work_struct *work);
+
+/* extended register access functions */
+
+#define BROADCAST_ADDR 31
+
+static inline int broadcast_write(struct mii_bus *bus, u32 regnum, u16 val)
+{
+       return mdiobus_write(bus, BROADCAST_ADDR, regnum, val);
+}
+
+/* Caller must hold extreg_lock. */
+static int ext_read(struct phy_device *phydev, int page, u32 regnum)
+{
+       struct dp83640_private *dp83640 = phydev->priv;
+       int val;
+
+       if (dp83640->clock->page != page) {
+               broadcast_write(phydev->bus, PAGESEL, page);
+               dp83640->clock->page = page;
+       }
+       val = phy_read(phydev, regnum);
+
+       return val;
+}
+
+/* Caller must hold extreg_lock. */
+static void ext_write(int broadcast, struct phy_device *phydev,
+                     int page, u32 regnum, u16 val)
+{
+       struct dp83640_private *dp83640 = phydev->priv;
+
+       if (dp83640->clock->page != page) {
+               broadcast_write(phydev->bus, PAGESEL, page);
+               dp83640->clock->page = page;
+       }
+       if (broadcast)
+               broadcast_write(phydev->bus, regnum, val);
+       else
+               phy_write(phydev, regnum, val);
+}
+
+/* Caller must hold extreg_lock. */
+static int tdr_write(int bc, struct phy_device *dev,
+                    const struct timespec *ts, u16 cmd)
+{
+       ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_nsec & 0xffff);/* ns[15:0]  */
+       ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_nsec >> 16);   /* ns[31:16] */
+       ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_sec & 0xffff); /* sec[15:0] */
+       ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_sec >> 16);    /* sec[31:16]*/
+
+       ext_write(bc, dev, PAGE4, PTP_CTL, cmd);
+
+       return 0;
+}
+
+/* convert phy timestamps into driver timestamps */
+
+static void phy2rxts(struct phy_rxts *p, struct rxts *rxts)
+{
+       u32 sec;
+
+       sec = p->sec_lo;
+       sec |= p->sec_hi << 16;
+
+       rxts->ns = p->ns_lo;
+       rxts->ns |= (p->ns_hi & 0x3fff) << 16;
+       rxts->ns += ((u64)sec) * 1000000000ULL;
+       rxts->seqid = p->seqid;
+       rxts->msgtype = (p->msgtype >> 12) & 0xf;
+       rxts->hash = p->msgtype & 0x0fff;
+       rxts->tmo = jiffies + HZ;
+}
+
+static u64 phy2txts(struct phy_txts *p)
+{
+       u64 ns;
+       u32 sec;
+
+       sec = p->sec_lo;
+       sec |= p->sec_hi << 16;
+
+       ns = p->ns_lo;
+       ns |= (p->ns_hi & 0x3fff) << 16;
+       ns += ((u64)sec) * 1000000000ULL;
+
+       return ns;
+}
+
+/* ptp clock methods */
+
+static int ptp_dp83640_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+       struct dp83640_clock *clock =
+               container_of(ptp, struct dp83640_clock, caps);
+       struct phy_device *phydev = clock->chosen->phydev;
+       u64 rate;
+       int neg_adj = 0;
+       u16 hi, lo;
+
+       if (ppb < 0) {
+               neg_adj = 1;
+               ppb = -ppb;
+       }
+       rate = ppb;
+       rate <<= 26;
+       rate = div_u64(rate, 1953125);
+
+       hi = (rate >> 16) & PTP_RATE_HI_MASK;
+       if (neg_adj)
+               hi |= PTP_RATE_DIR;
+
+       lo = rate & 0xffff;
+
+       mutex_lock(&clock->extreg_lock);
+
+       ext_write(1, phydev, PAGE4, PTP_RATEH, hi);
+       ext_write(1, phydev, PAGE4, PTP_RATEL, lo);
+
+       mutex_unlock(&clock->extreg_lock);
+
+       return 0;
+}
+
+static int ptp_dp83640_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+       struct dp83640_clock *clock =
+               container_of(ptp, struct dp83640_clock, caps);
+       struct phy_device *phydev = clock->chosen->phydev;
+       struct timespec ts;
+       int err;
+
+       delta += ADJTIME_FIX;
+
+       ts = ns_to_timespec(delta);
+
+       mutex_lock(&clock->extreg_lock);
+
+       err = tdr_write(1, phydev, &ts, PTP_STEP_CLK);
+
+       mutex_unlock(&clock->extreg_lock);
+
+       return err;
+}
+
+static int ptp_dp83640_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+       struct dp83640_clock *clock =
+               container_of(ptp, struct dp83640_clock, caps);
+       struct phy_device *phydev = clock->chosen->phydev;
+       unsigned int val[4];
+
+       mutex_lock(&clock->extreg_lock);
+
+       ext_write(0, phydev, PAGE4, PTP_CTL, PTP_RD_CLK);
+
+       val[0] = ext_read(phydev, PAGE4, PTP_TDR); /* ns[15:0] */
+       val[1] = ext_read(phydev, PAGE4, PTP_TDR); /* ns[31:16] */
+       val[2] = ext_read(phydev, PAGE4, PTP_TDR); /* sec[15:0] */
+       val[3] = ext_read(phydev, PAGE4, PTP_TDR); /* sec[31:16] */
+
+       mutex_unlock(&clock->extreg_lock);
+
+       ts->tv_nsec = val[0] | (val[1] << 16);
+       ts->tv_sec  = val[2] | (val[3] << 16);
+
+       return 0;
+}
+
+static int ptp_dp83640_settime(struct ptp_clock_info *ptp,
+                              const struct timespec *ts)
+{
+       struct dp83640_clock *clock =
+               container_of(ptp, struct dp83640_clock, caps);
+       struct phy_device *phydev = clock->chosen->phydev;
+       int err;
+
+       mutex_lock(&clock->extreg_lock);
+
+       err = tdr_write(1, phydev, ts, PTP_LOAD_CLK);
+
+       mutex_unlock(&clock->extreg_lock);
+
+       return err;
+}
+
+static int ptp_dp83640_enable(struct ptp_clock_info *ptp,
+                             struct ptp_clock_request *rq, int on)
+{
+       struct dp83640_clock *clock =
+               container_of(ptp, struct dp83640_clock, caps);
+       struct phy_device *phydev = clock->chosen->phydev;
+       u16 evnt;
+
+       switch (rq->type) {
+       case PTP_CLK_REQ_EXTTS:
+               if (rq->extts.index != 0)
+                       return -EINVAL;
+               evnt = EVNT_WR | (EXT_EVENT & EVNT_SEL_MASK) << EVNT_SEL_SHIFT;
+               if (on) {
+                       evnt |= (EXT_GPIO & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT;
+                       evnt |= EVNT_RISE;
+               }
+               ext_write(0, phydev, PAGE5, PTP_EVNT, evnt);
+               return 0;
+       default:
+               break;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static u8 status_frame_dst[6] = { 0x01, 0x1B, 0x19, 0x00, 0x00, 0x00 };
+static u8 status_frame_src[6] = { 0x08, 0x00, 0x17, 0x0B, 0x6B, 0x0F };
+
+static void enable_status_frames(struct phy_device *phydev, bool on)
+{
+       u16 cfg0 = 0, ver;
+
+       if (on)
+               cfg0 = PSF_EVNT_EN | PSF_RXTS_EN | PSF_TXTS_EN | ENDIAN_FLAG;
+
+       ver = (PSF_PTPVER & VERSIONPTP_MASK) << VERSIONPTP_SHIFT;
+
+       ext_write(0, phydev, PAGE5, PSF_CFG0, cfg0);
+       ext_write(0, phydev, PAGE6, PSF_CFG1, ver);
+
+       if (!phydev->attached_dev) {
+               pr_warning("dp83640: expected to find an attached netdevice\n");
+               return;
+       }
+
+       if (on) {
+               if (dev_mc_add(phydev->attached_dev, status_frame_dst))
+                       pr_warning("dp83640: failed to add mc address\n");
+       } else {
+               if (dev_mc_del(phydev->attached_dev, status_frame_dst))
+                       pr_warning("dp83640: failed to delete mc address\n");
+       }
+}
+
+static bool is_status_frame(struct sk_buff *skb, int type)
+{
+       struct ethhdr *h = eth_hdr(skb);
+
+       if (PTP_CLASS_V2_L2 == type &&
+           !memcmp(h->h_source, status_frame_src, sizeof(status_frame_src)))
+               return true;
+       else
+               return false;
+}
+
+static int expired(struct rxts *rxts)
+{
+       return time_after(jiffies, rxts->tmo);
+}
+
+/* Caller must hold rx_lock. */
+static void prune_rx_ts(struct dp83640_private *dp83640)
+{
+       struct list_head *this, *next;
+       struct rxts *rxts;
+
+       list_for_each_safe(this, next, &dp83640->rxts) {
+               rxts = list_entry(this, struct rxts, list);
+               if (expired(rxts)) {
+                       list_del_init(&rxts->list);
+                       list_add(&rxts->list, &dp83640->rxpool);
+               }
+       }
+}
+
+/* synchronize the phyters so they act as one clock */
+
+static void enable_broadcast(struct phy_device *phydev, int init_page, int on)
+{
+       int val;
+       phy_write(phydev, PAGESEL, 0);
+       val = phy_read(phydev, PHYCR2);
+       if (on)
+               val |= BC_WRITE;
+       else
+               val &= ~BC_WRITE;
+       phy_write(phydev, PHYCR2, val);
+       phy_write(phydev, PAGESEL, init_page);
+}
+
+static void recalibrate(struct dp83640_clock *clock)
+{
+       s64 now, diff;
+       struct phy_txts event_ts;
+       struct timespec ts;
+       struct list_head *this;
+       struct dp83640_private *tmp;
+       struct phy_device *master = clock->chosen->phydev;
+       u16 cfg0, evnt, ptp_trig, trigger, val;
+
+       trigger = CAL_TRIGGER;
+
+       mutex_lock(&clock->extreg_lock);
+
+       /*
+        * enable broadcast, disable status frames, enable ptp clock
+        */
+       list_for_each(this, &clock->phylist) {
+               tmp = list_entry(this, struct dp83640_private, list);
+               enable_broadcast(tmp->phydev, clock->page, 1);
+               tmp->cfg0 = ext_read(tmp->phydev, PAGE5, PSF_CFG0);
+               ext_write(0, tmp->phydev, PAGE5, PSF_CFG0, 0);
+               ext_write(0, tmp->phydev, PAGE4, PTP_CTL, PTP_ENABLE);
+       }
+       enable_broadcast(master, clock->page, 1);
+       cfg0 = ext_read(master, PAGE5, PSF_CFG0);
+       ext_write(0, master, PAGE5, PSF_CFG0, 0);
+       ext_write(0, master, PAGE4, PTP_CTL, PTP_ENABLE);
+
+       /*
+        * enable an event timestamp
+        */
+       evnt = EVNT_WR | EVNT_RISE | EVNT_SINGLE;
+       evnt |= (CAL_EVENT & EVNT_SEL_MASK) << EVNT_SEL_SHIFT;
+       evnt |= (cal_gpio & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT;
+
+       list_for_each(this, &clock->phylist) {
+               tmp = list_entry(this, struct dp83640_private, list);
+               ext_write(0, tmp->phydev, PAGE5, PTP_EVNT, evnt);
+       }
+       ext_write(0, master, PAGE5, PTP_EVNT, evnt);
+
+       /*
+        * configure a trigger
+        */
+       ptp_trig = TRIG_WR | TRIG_IF_LATE | TRIG_PULSE;
+       ptp_trig |= (trigger  & TRIG_CSEL_MASK) << TRIG_CSEL_SHIFT;
+       ptp_trig |= (cal_gpio & TRIG_GPIO_MASK) << TRIG_GPIO_SHIFT;
+       ext_write(0, master, PAGE5, PTP_TRIG, ptp_trig);
+
+       /* load trigger */
+       val = (trigger & TRIG_SEL_MASK) << TRIG_SEL_SHIFT;
+       val |= TRIG_LOAD;
+       ext_write(0, master, PAGE4, PTP_CTL, val);
+
+       /* enable trigger */
+       val &= ~TRIG_LOAD;
+       val |= TRIG_EN;
+       ext_write(0, master, PAGE4, PTP_CTL, val);
+
+       /* disable trigger */
+       val = (trigger & TRIG_SEL_MASK) << TRIG_SEL_SHIFT;
+       val |= TRIG_DIS;
+       ext_write(0, master, PAGE4, PTP_CTL, val);
+
+       /*
+        * read out and correct offsets
+        */
+       val = ext_read(master, PAGE4, PTP_STS);
+       pr_info("master PTP_STS  0x%04hx", val);
+       val = ext_read(master, PAGE4, PTP_ESTS);
+       pr_info("master PTP_ESTS 0x%04hx", val);
+       event_ts.ns_lo  = ext_read(master, PAGE4, PTP_EDATA);
+       event_ts.ns_hi  = ext_read(master, PAGE4, PTP_EDATA);
+       event_ts.sec_lo = ext_read(master, PAGE4, PTP_EDATA);
+       event_ts.sec_hi = ext_read(master, PAGE4, PTP_EDATA);
+       now = phy2txts(&event_ts);
+
+       list_for_each(this, &clock->phylist) {
+               tmp = list_entry(this, struct dp83640_private, list);
+               val = ext_read(tmp->phydev, PAGE4, PTP_STS);
+               pr_info("slave  PTP_STS  0x%04hx", val);
+               val = ext_read(tmp->phydev, PAGE4, PTP_ESTS);
+               pr_info("slave  PTP_ESTS 0x%04hx", val);
+               event_ts.ns_lo  = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
+               event_ts.ns_hi  = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
+               event_ts.sec_lo = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
+               event_ts.sec_hi = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
+               diff = now - (s64) phy2txts(&event_ts);
+               pr_info("slave offset %lld nanoseconds\n", diff);
+               diff += ADJTIME_FIX;
+               ts = ns_to_timespec(diff);
+               tdr_write(0, tmp->phydev, &ts, PTP_STEP_CLK);
+       }
+
+       /*
+        * restore status frames
+        */
+       list_for_each(this, &clock->phylist) {
+               tmp = list_entry(this, struct dp83640_private, list);
+               ext_write(0, tmp->phydev, PAGE5, PSF_CFG0, tmp->cfg0);
+       }
+       ext_write(0, master, PAGE5, PSF_CFG0, cfg0);
+
+       mutex_unlock(&clock->extreg_lock);
+}
+
+/* time stamping methods */
+
+static int decode_evnt(struct dp83640_private *dp83640,
+                      void *data, u16 ests)
+{
+       struct phy_txts *phy_txts;
+       struct ptp_clock_event event;
+       int words = (ests >> EVNT_TS_LEN_SHIFT) & EVNT_TS_LEN_MASK;
+       u16 ext_status = 0;
+
+       if (ests & MULT_EVNT) {
+               ext_status = *(u16 *) data;
+               data += sizeof(ext_status);
+       }
+
+       phy_txts = data;
+
+       switch (words) { /* fall through in every case */
+       case 3:
+               dp83640->edata.sec_hi = phy_txts->sec_hi;
+       case 2:
+               dp83640->edata.sec_lo = phy_txts->sec_lo;
+       case 1:
+               dp83640->edata.ns_hi = phy_txts->ns_hi;
+       case 0:
+               dp83640->edata.ns_lo = phy_txts->ns_lo;
+       }
+
+       event.type = PTP_CLOCK_EXTTS;
+       event.index = 0;
+       event.timestamp = phy2txts(&dp83640->edata);
+
+       ptp_clock_event(dp83640->clock->ptp_clock, &event);
+
+       words = ext_status ? words + 2 : words + 1;
+       return words * sizeof(u16);
+}
+
+static void decode_rxts(struct dp83640_private *dp83640,
+                       struct phy_rxts *phy_rxts)
+{
+       struct rxts *rxts;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dp83640->rx_lock, flags);
+
+       prune_rx_ts(dp83640);
+
+       if (list_empty(&dp83640->rxpool)) {
+               pr_warning("dp83640: rx timestamp pool is empty\n");
+               goto out;
+       }
+       rxts = list_first_entry(&dp83640->rxpool, struct rxts, list);
+       list_del_init(&rxts->list);
+       phy2rxts(phy_rxts, rxts);
+       list_add_tail(&rxts->list, &dp83640->rxts);
+out:
+       spin_unlock_irqrestore(&dp83640->rx_lock, flags);
+}
+
+static void decode_txts(struct dp83640_private *dp83640,
+                       struct phy_txts *phy_txts)
+{
+       struct skb_shared_hwtstamps shhwtstamps;
+       struct sk_buff *skb;
+       u64 ns;
+
+       /* We must already have the skb that triggered this. */
+
+       skb = skb_dequeue(&dp83640->tx_queue);
+
+       if (!skb) {
+               pr_warning("dp83640: have timestamp but tx_queue empty\n");
+               return;
+       }
+       ns = phy2txts(phy_txts);
+       memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+       shhwtstamps.hwtstamp = ns_to_ktime(ns);
+       skb_complete_tx_timestamp(skb, &shhwtstamps);
+}
+
+static void decode_status_frame(struct dp83640_private *dp83640,
+                               struct sk_buff *skb)
+{
+       struct phy_rxts *phy_rxts;
+       struct phy_txts *phy_txts;
+       u8 *ptr;
+       int len, size;
+       u16 ests, type;
+
+       ptr = skb->data + 2;
+
+       for (len = skb_headlen(skb) - 2; len > sizeof(type); len -= size) {
+
+               type = *(u16 *)ptr;
+               ests = type & 0x0fff;
+               type = type & 0xf000;
+               len -= sizeof(type);
+               ptr += sizeof(type);
+
+               if (PSF_RX == type && len >= sizeof(*phy_rxts)) {
+
+                       phy_rxts = (struct phy_rxts *) ptr;
+                       decode_rxts(dp83640, phy_rxts);
+                       size = sizeof(*phy_rxts);
+
+               } else if (PSF_TX == type && len >= sizeof(*phy_txts)) {
+
+                       phy_txts = (struct phy_txts *) ptr;
+                       decode_txts(dp83640, phy_txts);
+                       size = sizeof(*phy_txts);
+
+               } else if (PSF_EVNT == type && len >= sizeof(*phy_txts)) {
+
+                       size = decode_evnt(dp83640, ptr, ests);
+
+               } else {
+                       size = 0;
+                       break;
+               }
+               ptr += size;
+       }
+}
+
+static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts)
+{
+       u16 *seqid;
+       unsigned int offset;
+       u8 *msgtype, *data = skb_mac_header(skb);
+
+       /* check sequenceID, messageType, 12 bit hash of offset 20-29 */
+
+       switch (type) {
+       case PTP_CLASS_V1_IPV4:
+       case PTP_CLASS_V2_IPV4:
+               offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
+               break;
+       case PTP_CLASS_V1_IPV6:
+       case PTP_CLASS_V2_IPV6:
+               offset = OFF_PTP6;
+               break;
+       case PTP_CLASS_V2_L2:
+               offset = ETH_HLEN;
+               break;
+       case PTP_CLASS_V2_VLAN:
+               offset = ETH_HLEN + VLAN_HLEN;
+               break;
+       default:
+               return 0;
+       }
+
+       if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID + sizeof(*seqid))
+               return 0;
+
+       if (unlikely(type & PTP_CLASS_V1))
+               msgtype = data + offset + OFF_PTP_CONTROL;
+       else
+               msgtype = data + offset;
+
+       seqid = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID);
+
+       return (rxts->msgtype == (*msgtype & 0xf) &&
+               rxts->seqid   == ntohs(*seqid));
+}
+
+static void dp83640_free_clocks(void)
+{
+       struct dp83640_clock *clock;
+       struct list_head *this, *next;
+
+       mutex_lock(&phyter_clocks_lock);
+
+       list_for_each_safe(this, next, &phyter_clocks) {
+               clock = list_entry(this, struct dp83640_clock, list);
+               if (!list_empty(&clock->phylist)) {
+                       pr_warning("phy list non-empty while unloading");
+                       BUG();
+               }
+               list_del(&clock->list);
+               mutex_destroy(&clock->extreg_lock);
+               mutex_destroy(&clock->clock_lock);
+               put_device(&clock->bus->dev);
+               kfree(clock);
+       }
+
+       mutex_unlock(&phyter_clocks_lock);
+}
+
+static void dp83640_clock_init(struct dp83640_clock *clock, struct mii_bus *bus)
+{
+       INIT_LIST_HEAD(&clock->list);
+       clock->bus = bus;
+       mutex_init(&clock->extreg_lock);
+       mutex_init(&clock->clock_lock);
+       INIT_LIST_HEAD(&clock->phylist);
+       clock->caps.owner = THIS_MODULE;
+       sprintf(clock->caps.name, "dp83640 timer");
+       clock->caps.max_adj     = 1953124;
+       clock->caps.n_alarm     = 0;
+       clock->caps.n_ext_ts    = N_EXT_TS;
+       clock->caps.n_per_out   = 0;
+       clock->caps.pps         = 0;
+       clock->caps.adjfreq     = ptp_dp83640_adjfreq;
+       clock->caps.adjtime     = ptp_dp83640_adjtime;
+       clock->caps.gettime     = ptp_dp83640_gettime;
+       clock->caps.settime     = ptp_dp83640_settime;
+       clock->caps.enable      = ptp_dp83640_enable;
+       /*
+        * Get a reference to this bus instance.
+        */
+       get_device(&bus->dev);
+}
+
+static int choose_this_phy(struct dp83640_clock *clock,
+                          struct phy_device *phydev)
+{
+       if (chosen_phy == -1 && !clock->chosen)
+               return 1;
+
+       if (chosen_phy == phydev->addr)
+               return 1;
+
+       return 0;
+}
+
+static struct dp83640_clock *dp83640_clock_get(struct dp83640_clock *clock)
+{
+       if (clock)
+               mutex_lock(&clock->clock_lock);
+       return clock;
+}
+
+/*
+ * Look up and lock a clock by bus instance.
+ * If there is no clock for this bus, then create it first.
+ */
+static struct dp83640_clock *dp83640_clock_get_bus(struct mii_bus *bus)
+{
+       struct dp83640_clock *clock = NULL, *tmp;
+       struct list_head *this;
+
+       mutex_lock(&phyter_clocks_lock);
+
+       list_for_each(this, &phyter_clocks) {
+               tmp = list_entry(this, struct dp83640_clock, list);
+               if (tmp->bus == bus) {
+                       clock = tmp;
+                       break;
+               }
+       }
+       if (clock)
+               goto out;
+
+       clock = kzalloc(sizeof(struct dp83640_clock), GFP_KERNEL);
+       if (!clock)
+               goto out;
+
+       dp83640_clock_init(clock, bus);
+       list_add_tail(&phyter_clocks, &clock->list);
+out:
+       mutex_unlock(&phyter_clocks_lock);
+
+       return dp83640_clock_get(clock);
+}
+
+static void dp83640_clock_put(struct dp83640_clock *clock)
+{
+       mutex_unlock(&clock->clock_lock);
+}
+
+static int dp83640_probe(struct phy_device *phydev)
+{
+       struct dp83640_clock *clock;
+       struct dp83640_private *dp83640;
+       int err = -ENOMEM, i;
+
+       if (phydev->addr == BROADCAST_ADDR)
+               return 0;
+
+       clock = dp83640_clock_get_bus(phydev->bus);
+       if (!clock)
+               goto no_clock;
+
+       dp83640 = kzalloc(sizeof(struct dp83640_private), GFP_KERNEL);
+       if (!dp83640)
+               goto no_memory;
+
+       dp83640->phydev = phydev;
+       INIT_WORK(&dp83640->ts_work, rx_timestamp_work);
+
+       INIT_LIST_HEAD(&dp83640->rxts);
+       INIT_LIST_HEAD(&dp83640->rxpool);
+       for (i = 0; i < MAX_RXTS; i++)
+               list_add(&dp83640->rx_pool_data[i].list, &dp83640->rxpool);
+
+       phydev->priv = dp83640;
+
+       spin_lock_init(&dp83640->rx_lock);
+       skb_queue_head_init(&dp83640->rx_queue);
+       skb_queue_head_init(&dp83640->tx_queue);
+
+       dp83640->clock = clock;
+
+       if (choose_this_phy(clock, phydev)) {
+               clock->chosen = dp83640;
+               clock->ptp_clock = ptp_clock_register(&clock->caps);
+               if (IS_ERR(clock->ptp_clock)) {
+                       err = PTR_ERR(clock->ptp_clock);
+                       goto no_register;
+               }
+       } else
+               list_add_tail(&dp83640->list, &clock->phylist);
+
+       if (clock->chosen && !list_empty(&clock->phylist))
+               recalibrate(clock);
+       else
+               enable_broadcast(dp83640->phydev, clock->page, 1);
+
+       dp83640_clock_put(clock);
+       return 0;
+
+no_register:
+       clock->chosen = NULL;
+       kfree(dp83640);
+no_memory:
+       dp83640_clock_put(clock);
+no_clock:
+       return err;
+}
+
+static void dp83640_remove(struct phy_device *phydev)
+{
+       struct dp83640_clock *clock;
+       struct list_head *this, *next;
+       struct dp83640_private *tmp, *dp83640 = phydev->priv;
+
+       if (phydev->addr == BROADCAST_ADDR)
+               return;
+
+       enable_status_frames(phydev, false);
+       cancel_work_sync(&dp83640->ts_work);
+
+       clock = dp83640_clock_get(dp83640->clock);
+
+       if (dp83640 == clock->chosen) {
+               ptp_clock_unregister(clock->ptp_clock);
+               clock->chosen = NULL;
+       } else {
+               list_for_each_safe(this, next, &clock->phylist) {
+                       tmp = list_entry(this, struct dp83640_private, list);
+                       if (tmp == dp83640) {
+                               list_del_init(&tmp->list);
+                               break;
+                       }
+               }
+       }
+
+       dp83640_clock_put(clock);
+       kfree(dp83640);
+}
+
+static int dp83640_hwtstamp(struct phy_device *phydev, struct ifreq *ifr)
+{
+       struct dp83640_private *dp83640 = phydev->priv;
+       struct hwtstamp_config cfg;
+       u16 txcfg0, rxcfg0;
+
+       if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
+               return -EFAULT;
+
+       if (cfg.flags) /* reserved for future extensions */
+               return -EINVAL;
+
+       switch (cfg.tx_type) {
+       case HWTSTAMP_TX_OFF:
+               dp83640->hwts_tx_en = 0;
+               break;
+       case HWTSTAMP_TX_ON:
+               dp83640->hwts_tx_en = 1;
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       switch (cfg.rx_filter) {
+       case HWTSTAMP_FILTER_NONE:
+               dp83640->hwts_rx_en = 0;
+               dp83640->layer = 0;
+               dp83640->version = 0;
+               break;
+       case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+               dp83640->hwts_rx_en = 1;
+               dp83640->layer = LAYER4;
+               dp83640->version = 1;
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+               dp83640->hwts_rx_en = 1;
+               dp83640->layer = LAYER4;
+               dp83640->version = 2;
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+               dp83640->hwts_rx_en = 1;
+               dp83640->layer = LAYER2;
+               dp83640->version = 2;
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+               dp83640->hwts_rx_en = 1;
+               dp83640->layer = LAYER4|LAYER2;
+               dp83640->version = 2;
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       txcfg0 = (dp83640->version & TX_PTP_VER_MASK) << TX_PTP_VER_SHIFT;
+       rxcfg0 = (dp83640->version & TX_PTP_VER_MASK) << TX_PTP_VER_SHIFT;
+
+       if (dp83640->layer & LAYER2) {
+               txcfg0 |= TX_L2_EN;
+               rxcfg0 |= RX_L2_EN;
+       }
+       if (dp83640->layer & LAYER4) {
+               txcfg0 |= TX_IPV6_EN | TX_IPV4_EN;
+               rxcfg0 |= RX_IPV6_EN | RX_IPV4_EN;
+       }
+
+       if (dp83640->hwts_tx_en)
+               txcfg0 |= TX_TS_EN;
+
+       if (dp83640->hwts_rx_en)
+               rxcfg0 |= RX_TS_EN;
+
+       mutex_lock(&dp83640->clock->extreg_lock);
+
+       if (dp83640->hwts_tx_en || dp83640->hwts_rx_en) {
+               enable_status_frames(phydev, true);
+               ext_write(0, phydev, PAGE4, PTP_CTL, PTP_ENABLE);
+       }
+
+       ext_write(0, phydev, PAGE5, PTP_TXCFG0, txcfg0);
+       ext_write(0, phydev, PAGE5, PTP_RXCFG0, rxcfg0);
+
+       mutex_unlock(&dp83640->clock->extreg_lock);
+
+       return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+}
+
+static void rx_timestamp_work(struct work_struct *work)
+{
+       struct dp83640_private *dp83640 =
+               container_of(work, struct dp83640_private, ts_work);
+       struct list_head *this, *next;
+       struct rxts *rxts;
+       struct skb_shared_hwtstamps *shhwtstamps;
+       struct sk_buff *skb;
+       unsigned int type;
+       unsigned long flags;
+
+       /* Deliver each deferred packet, with or without a time stamp. */
+
+       while ((skb = skb_dequeue(&dp83640->rx_queue)) != NULL) {
+               type = SKB_PTP_TYPE(skb);
+               spin_lock_irqsave(&dp83640->rx_lock, flags);
+               list_for_each_safe(this, next, &dp83640->rxts) {
+                       rxts = list_entry(this, struct rxts, list);
+                       if (match(skb, type, rxts)) {
+                               shhwtstamps = skb_hwtstamps(skb);
+                               memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+                               shhwtstamps->hwtstamp = ns_to_ktime(rxts->ns);
+                               list_del_init(&rxts->list);
+                               list_add(&rxts->list, &dp83640->rxpool);
+                               break;
+                       }
+               }
+               spin_unlock_irqrestore(&dp83640->rx_lock, flags);
+               netif_rx(skb);
+       }
+
+       /* Clear out expired time stamps. */
+
+       spin_lock_irqsave(&dp83640->rx_lock, flags);
+       prune_rx_ts(dp83640);
+       spin_unlock_irqrestore(&dp83640->rx_lock, flags);
+}
+
+static bool dp83640_rxtstamp(struct phy_device *phydev,
+                            struct sk_buff *skb, int type)
+{
+       struct dp83640_private *dp83640 = phydev->priv;
+
+       if (!dp83640->hwts_rx_en)
+               return false;
+
+       if (is_status_frame(skb, type)) {
+               decode_status_frame(dp83640, skb);
+               kfree_skb(skb);
+               return true;
+       }
+
+       SKB_PTP_TYPE(skb) = type;
+       skb_queue_tail(&dp83640->rx_queue, skb);
+       schedule_work(&dp83640->ts_work);
+
+       return true;
+}
+
+static void dp83640_txtstamp(struct phy_device *phydev,
+                            struct sk_buff *skb, int type)
+{
+       struct dp83640_private *dp83640 = phydev->priv;
+
+       if (!dp83640->hwts_tx_en) {
+               kfree_skb(skb);
+               return;
+       }
+       skb_queue_tail(&dp83640->tx_queue, skb);
+       schedule_work(&dp83640->ts_work);
+}
+
+static struct phy_driver dp83640_driver = {
+       .phy_id         = DP83640_PHY_ID,
+       .phy_id_mask    = 0xfffffff0,
+       .name           = "NatSemi DP83640",
+       .features       = PHY_BASIC_FEATURES,
+       .flags          = 0,
+       .probe          = dp83640_probe,
+       .remove         = dp83640_remove,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .hwtstamp       = dp83640_hwtstamp,
+       .rxtstamp       = dp83640_rxtstamp,
+       .txtstamp       = dp83640_txtstamp,
+       .driver         = {.owner = THIS_MODULE,}
+};
+
+static int __init dp83640_init(void)
+{
+       return phy_driver_register(&dp83640_driver);
+}
+
+static void __exit dp83640_exit(void)
+{
+       dp83640_free_clocks();
+       phy_driver_unregister(&dp83640_driver);
+}
+
+MODULE_DESCRIPTION("National Semiconductor DP83640 PHY driver");
+MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>");
+MODULE_LICENSE("GPL");
+
+module_init(dp83640_init);
+module_exit(dp83640_exit);
+
+static struct mdio_device_id __maybe_unused dp83640_tbl[] = {
+       { DP83640_PHY_ID, 0xfffffff0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, dp83640_tbl);
diff --git a/drivers/net/phy/dp83640_reg.h b/drivers/net/phy/dp83640_reg.h
new file mode 100644 (file)
index 0000000..e7fe411
--- /dev/null
@@ -0,0 +1,267 @@
+/* dp83640_reg.h
+ * Generated by regen.tcl on Thu Feb 17 10:02:48 AM CET 2011
+ */
+#ifndef HAVE_DP83640_REGISTERS
+#define HAVE_DP83640_REGISTERS
+
+#define PAGE0                     0x0000
+#define PHYCR2                    0x001c /* PHY Control Register 2 */
+
+#define PAGE4                     0x0004
+#define PTP_CTL                   0x0014 /* PTP Control Register */
+#define PTP_TDR                   0x0015 /* PTP Time Data Register */
+#define PTP_STS                   0x0016 /* PTP Status Register */
+#define PTP_TSTS                  0x0017 /* PTP Trigger Status Register */
+#define PTP_RATEL                 0x0018 /* PTP Rate Low Register */
+#define PTP_RATEH                 0x0019 /* PTP Rate High Register */
+#define PTP_RDCKSUM               0x001a /* PTP Read Checksum */
+#define PTP_WRCKSUM               0x001b /* PTP Write Checksum */
+#define PTP_TXTS                  0x001c /* PTP Transmit Timestamp Register, in four 16-bit reads */
+#define PTP_RXTS                  0x001d /* PTP Receive Timestamp Register, in six? 16-bit reads */
+#define PTP_ESTS                  0x001e /* PTP Event Status Register */
+#define PTP_EDATA                 0x001f /* PTP Event Data Register */
+
+#define PAGE5                     0x0005
+#define PTP_TRIG                  0x0014 /* PTP Trigger Configuration Register */
+#define PTP_EVNT                  0x0015 /* PTP Event Configuration Register */
+#define PTP_TXCFG0                0x0016 /* PTP Transmit Configuration Register 0 */
+#define PTP_TXCFG1                0x0017 /* PTP Transmit Configuration Register 1 */
+#define PSF_CFG0                  0x0018 /* PHY Status Frame Configuration Register 0 */
+#define PTP_RXCFG0                0x0019 /* PTP Receive Configuration Register 0 */
+#define PTP_RXCFG1                0x001a /* PTP Receive Configuration Register 1 */
+#define PTP_RXCFG2                0x001b /* PTP Receive Configuration Register 2 */
+#define PTP_RXCFG3                0x001c /* PTP Receive Configuration Register 3 */
+#define PTP_RXCFG4                0x001d /* PTP Receive Configuration Register 4 */
+#define PTP_TRDL                  0x001e /* PTP Temporary Rate Duration Low Register */
+#define PTP_TRDH                  0x001f /* PTP Temporary Rate Duration High Register */
+
+#define PAGE6                     0x0006
+#define PTP_COC                   0x0014 /* PTP Clock Output Control Register */
+#define PSF_CFG1                  0x0015 /* PHY Status Frame Configuration Register 1 */
+#define PSF_CFG2                  0x0016 /* PHY Status Frame Configuration Register 2 */
+#define PSF_CFG3                  0x0017 /* PHY Status Frame Configuration Register 3 */
+#define PSF_CFG4                  0x0018 /* PHY Status Frame Configuration Register 4 */
+#define PTP_SFDCFG                0x0019 /* PTP SFD Configuration Register */
+#define PTP_INTCTL                0x001a /* PTP Interrupt Control Register */
+#define PTP_CLKSRC                0x001b /* PTP Clock Source Register */
+#define PTP_ETR                   0x001c /* PTP Ethernet Type Register */
+#define PTP_OFF                   0x001d /* PTP Offset Register */
+#define PTP_GPIOMON               0x001e /* PTP GPIO Monitor Register */
+#define PTP_RXHASH                0x001f /* PTP Receive Hash Register */
+
+/* Bit definitions for the PHYCR2 register */
+#define BC_WRITE                  (1<<11) /* Broadcast Write Enable */
+
+/* Bit definitions for the PTP_CTL register */
+#define TRIG_SEL_SHIFT            (10)    /* PTP Trigger Select */
+#define TRIG_SEL_MASK             (0x7)
+#define TRIG_DIS                  (1<<9)  /* Disable PTP Trigger */
+#define TRIG_EN                   (1<<8)  /* Enable PTP Trigger */
+#define TRIG_READ                 (1<<7)  /* Read PTP Trigger */
+#define TRIG_LOAD                 (1<<6)  /* Load PTP Trigger */
+#define PTP_RD_CLK                (1<<5)  /* Read PTP Clock */
+#define PTP_LOAD_CLK              (1<<4)  /* Load PTP Clock */
+#define PTP_STEP_CLK              (1<<3)  /* Step PTP Clock */
+#define PTP_ENABLE                (1<<2)  /* Enable PTP Clock */
+#define PTP_DISABLE               (1<<1)  /* Disable PTP Clock */
+#define PTP_RESET                 (1<<0)  /* Reset PTP Clock */
+
+/* Bit definitions for the PTP_STS register */
+#define TXTS_RDY                  (1<<11) /* Transmit Timestamp Ready */
+#define RXTS_RDY                  (1<<10) /* Receive Timestamp Ready */
+#define TRIG_DONE                 (1<<9)  /* PTP Trigger Done */
+#define EVENT_RDY                 (1<<8)  /* PTP Event Timestamp Ready */
+#define TXTS_IE                   (1<<3)  /* Transmit Timestamp Interrupt Enable */
+#define RXTS_IE                   (1<<2)  /* Receive Timestamp Interrupt Enable */
+#define TRIG_IE                   (1<<1)  /* Trigger Interrupt Enable */
+#define EVENT_IE                  (1<<0)  /* Event Interrupt Enable */
+
+/* Bit definitions for the PTP_TSTS register */
+#define TRIG7_ERROR               (1<<15) /* Trigger 7 Error */
+#define TRIG7_ACTIVE              (1<<14) /* Trigger 7 Active */
+#define TRIG6_ERROR               (1<<13) /* Trigger 6 Error */
+#define TRIG6_ACTIVE              (1<<12) /* Trigger 6 Active */
+#define TRIG5_ERROR               (1<<11) /* Trigger 5 Error */
+#define TRIG5_ACTIVE              (1<<10) /* Trigger 5 Active */
+#define TRIG4_ERROR               (1<<9)  /* Trigger 4 Error */
+#define TRIG4_ACTIVE              (1<<8)  /* Trigger 4 Active */
+#define TRIG3_ERROR               (1<<7)  /* Trigger 3 Error */
+#define TRIG3_ACTIVE              (1<<6)  /* Trigger 3 Active */
+#define TRIG2_ERROR               (1<<5)  /* Trigger 2 Error */
+#define TRIG2_ACTIVE              (1<<4)  /* Trigger 2 Active */
+#define TRIG1_ERROR               (1<<3)  /* Trigger 1 Error */
+#define TRIG1_ACTIVE              (1<<2)  /* Trigger 1 Active */
+#define TRIG0_ERROR               (1<<1)  /* Trigger 0 Error */
+#define TRIG0_ACTIVE              (1<<0)  /* Trigger 0 Active */
+
+/* Bit definitions for the PTP_RATEH register */
+#define PTP_RATE_DIR              (1<<15) /* PTP Rate Direction */
+#define PTP_TMP_RATE              (1<<14) /* PTP Temporary Rate */
+#define PTP_RATE_HI_SHIFT         (0)     /* PTP Rate High 10-bits */
+#define PTP_RATE_HI_MASK          (0x3ff)
+
+/* Bit definitions for the PTP_ESTS register */
+#define EVNTS_MISSED_SHIFT        (8)     /* Indicates number of events missed */
+#define EVNTS_MISSED_MASK         (0x7)
+#define EVNT_TS_LEN_SHIFT         (6)     /* Indicates length of the Timestamp field in 16-bit words minus 1 */
+#define EVNT_TS_LEN_MASK          (0x3)
+#define EVNT_RF                   (1<<5)  /* Indicates whether the event is a rise or falling event */
+#define EVNT_NUM_SHIFT            (2)     /* Indicates Event Timestamp Unit which detected an event */
+#define EVNT_NUM_MASK             (0x7)
+#define MULT_EVNT                 (1<<1)  /* Indicates multiple events were detected at the same time */
+#define EVENT_DET                 (1<<0)  /* PTP Event Detected */
+
+/* Bit definitions for the PTP_EDATA register */
+#define E7_RISE                   (1<<15) /* Indicates direction of Event 7 */
+#define E7_DET                    (1<<14) /* Indicates Event 7 detected */
+#define E6_RISE                   (1<<13) /* Indicates direction of Event 6 */
+#define E6_DET                    (1<<12) /* Indicates Event 6 detected */
+#define E5_RISE                   (1<<11) /* Indicates direction of Event 5 */
+#define E5_DET                    (1<<10) /* Indicates Event 5 detected */
+#define E4_RISE                   (1<<9)  /* Indicates direction of Event 4 */
+#define E4_DET                    (1<<8)  /* Indicates Event 4 detected */
+#define E3_RISE                   (1<<7)  /* Indicates direction of Event 3 */
+#define E3_DET                    (1<<6)  /* Indicates Event 3 detected */
+#define E2_RISE                   (1<<5)  /* Indicates direction of Event 2 */
+#define E2_DET                    (1<<4)  /* Indicates Event 2 detected */
+#define E1_RISE                   (1<<3)  /* Indicates direction of Event 1 */
+#define E1_DET                    (1<<2)  /* Indicates Event 1 detected */
+#define E0_RISE                   (1<<1)  /* Indicates direction of Event 0 */
+#define E0_DET                    (1<<0)  /* Indicates Event 0 detected */
+
+/* Bit definitions for the PTP_TRIG register */
+#define TRIG_PULSE                (1<<15) /* generate a Pulse rather than a single edge */
+#define TRIG_PER                  (1<<14) /* generate a periodic signal */
+#define TRIG_IF_LATE              (1<<13) /* trigger immediately if already past */
+#define TRIG_NOTIFY               (1<<12) /* Trigger Notification Enable */
+#define TRIG_GPIO_SHIFT           (8)     /* Trigger GPIO Connection, value 1-12 */
+#define TRIG_GPIO_MASK            (0xf)
+#define TRIG_TOGGLE               (1<<7)  /* Trigger Toggle Mode Enable */
+#define TRIG_CSEL_SHIFT           (1)     /* Trigger Configuration Select */
+#define TRIG_CSEL_MASK            (0x7)
+#define TRIG_WR                   (1<<0)  /* Trigger Configuration Write */
+
+/* Bit definitions for the PTP_EVNT register */
+#define EVNT_RISE                 (1<<14) /* Event Rise Detect Enable */
+#define EVNT_FALL                 (1<<13) /* Event Fall Detect Enable */
+#define EVNT_SINGLE               (1<<12) /* enable single event capture operation */
+#define EVNT_GPIO_SHIFT           (8)     /* Event GPIO Connection, value 1-12 */
+#define EVNT_GPIO_MASK            (0xf)
+#define EVNT_SEL_SHIFT            (1)     /* Event Select */
+#define EVNT_SEL_MASK             (0x7)
+#define EVNT_WR                   (1<<0)  /* Event Configuration Write */
+
+/* Bit definitions for the PTP_TXCFG0 register */
+#define SYNC_1STEP                (1<<15) /* insert timestamp into transmit Sync Messages */
+#define DR_INSERT                 (1<<13) /* Insert Delay_Req Timestamp in Delay_Resp (dangerous) */
+#define NTP_TS_EN                 (1<<12) /* Enable Timestamping of NTP Packets */
+#define IGNORE_2STEP              (1<<11) /* Ignore Two_Step flag for One-Step operation */
+#define CRC_1STEP                 (1<<10) /* Disable checking of CRC for One-Step operation */
+#define CHK_1STEP                 (1<<9)  /* Enable UDP Checksum correction for One-Step Operation */
+#define IP1588_EN                 (1<<8)  /* Enable IEEE 1588 defined IP address filter */
+#define TX_L2_EN                  (1<<7)  /* Layer2 Timestamp Enable */
+#define TX_IPV6_EN                (1<<6)  /* IPv6 Timestamp Enable */
+#define TX_IPV4_EN                (1<<5)  /* IPv4 Timestamp Enable */
+#define TX_PTP_VER_SHIFT          (1)     /* Enable Timestamp capture for IEEE 1588 version X */
+#define TX_PTP_VER_MASK           (0xf)
+#define TX_TS_EN                  (1<<0)  /* Transmit Timestamp Enable */
+
+/* Bit definitions for the PTP_TXCFG1 register */
+#define BYTE0_MASK_SHIFT          (8)     /* Bit mask to be used for matching Byte0 of the PTP Message */
+#define BYTE0_MASK_MASK           (0xff)
+#define BYTE0_DATA_SHIFT          (0)     /* Data to be used for matching Byte0 of the PTP Message */
+#define BYTE0_DATA_MASK           (0xff)
+
+/* Bit definitions for the PSF_CFG0 register */
+#define MAC_SRC_ADD_SHIFT         (11)    /* Status Frame Mac Source Address */
+#define MAC_SRC_ADD_MASK          (0x3)
+#define MIN_PRE_SHIFT             (8)     /* Status Frame Minimum Preamble */
+#define MIN_PRE_MASK              (0x7)
+#define PSF_ENDIAN                (1<<7)  /* Status Frame Endian Control */
+#define PSF_IPV4                  (1<<6)  /* Status Frame IPv4 Enable */
+#define PSF_PCF_RD                (1<<5)  /* Control Frame Read PHY Status Frame Enable */
+#define PSF_ERR_EN                (1<<4)  /* Error PHY Status Frame Enable */
+#define PSF_TXTS_EN               (1<<3)  /* Transmit Timestamp PHY Status Frame Enable */
+#define PSF_RXTS_EN               (1<<2)  /* Receive Timestamp PHY Status Frame Enable */
+#define PSF_TRIG_EN               (1<<1)  /* Trigger PHY Status Frame Enable */
+#define PSF_EVNT_EN               (1<<0)  /* Event PHY Status Frame Enable */
+
+/* Bit definitions for the PTP_RXCFG0 register */
+#define DOMAIN_EN                 (1<<15) /* Domain Match Enable */
+#define ALT_MAST_DIS              (1<<14) /* Alternate Master Timestamp Disable */
+#define USER_IP_SEL               (1<<13) /* Selects portion of IP address accessible thru PTP_RXCFG2 */
+#define USER_IP_EN                (1<<12) /* Enable User-programmed IP address filter */
+#define RX_SLAVE                  (1<<11) /* Receive Slave Only */
+#define IP1588_EN_SHIFT           (8)     /* Enable IEEE 1588 defined IP address filters */
+#define IP1588_EN_MASK            (0xf)
+#define RX_L2_EN                  (1<<7)  /* Layer2 Timestamp Enable */
+#define RX_IPV6_EN                (1<<6)  /* IPv6 Timestamp Enable */
+#define RX_IPV4_EN                (1<<5)  /* IPv4 Timestamp Enable */
+#define RX_PTP_VER_SHIFT          (1)     /* Enable Timestamp capture for IEEE 1588 version X */
+#define RX_PTP_VER_MASK           (0xf)
+#define RX_TS_EN                  (1<<0)  /* Receive Timestamp Enable */
+
+/* Bit definitions for the PTP_RXCFG1 register */
+#define BYTE0_MASK_SHIFT          (8)     /* Bit mask to be used for matching Byte0 of the PTP Message */
+#define BYTE0_MASK_MASK           (0xff)
+#define BYTE0_DATA_SHIFT          (0)     /* Data to be used for matching Byte0 of the PTP Message */
+#define BYTE0_DATA_MASK           (0xff)
+
+/* Bit definitions for the PTP_RXCFG3 register */
+#define TS_MIN_IFG_SHIFT          (12)    /* Minimum Inter-frame Gap */
+#define TS_MIN_IFG_MASK           (0xf)
+#define ACC_UDP                   (1<<11) /* Record Timestamp if UDP Checksum Error */
+#define ACC_CRC                   (1<<10) /* Record Timestamp if CRC Error */
+#define TS_APPEND                 (1<<9)  /* Append Timestamp for L2 */
+#define TS_INSERT                 (1<<8)  /* Enable Timestamp Insertion */
+#define PTP_DOMAIN_SHIFT          (0)     /* PTP Message domainNumber field */
+#define PTP_DOMAIN_MASK           (0xff)
+
+/* Bit definitions for the PTP_RXCFG4 register */
+#define IPV4_UDP_MOD              (1<<15) /* Enable IPV4 UDP Modification */
+#define TS_SEC_EN                 (1<<14) /* Enable Timestamp Seconds */
+#define TS_SEC_LEN_SHIFT          (12)    /* Inserted Timestamp Seconds Length */
+#define TS_SEC_LEN_MASK           (0x3)
+#define RXTS_NS_OFF_SHIFT         (6)     /* Receive Timestamp Nanoseconds offset */
+#define RXTS_NS_OFF_MASK          (0x3f)
+#define RXTS_SEC_OFF_SHIFT        (0)     /* Receive Timestamp Seconds offset */
+#define RXTS_SEC_OFF_MASK         (0x3f)
+
+/* Bit definitions for the PTP_COC register */
+#define PTP_CLKOUT_EN             (1<<15) /* PTP Clock Output Enable */
+#define PTP_CLKOUT_SEL            (1<<14) /* PTP Clock Output Source Select */
+#define PTP_CLKOUT_SPEEDSEL       (1<<13) /* PTP Clock Output I/O Speed Select */
+#define PTP_CLKDIV_SHIFT          (0)     /* PTP Clock Divide-by Value */
+#define PTP_CLKDIV_MASK           (0xff)
+
+/* Bit definitions for the PSF_CFG1 register */
+#define PTPRESERVED_SHIFT         (12)    /* PTP v2 reserved field */
+#define PTPRESERVED_MASK          (0xf)
+#define VERSIONPTP_SHIFT          (8)     /* PTP v2 versionPTP field */
+#define VERSIONPTP_MASK           (0xf)
+#define TRANSPORT_SPECIFIC_SHIFT  (4)     /* PTP v2 Header transportSpecific field */
+#define TRANSPORT_SPECIFIC_MASK   (0xf)
+#define MESSAGETYPE_SHIFT         (0)     /* PTP v2 messageType field */
+#define MESSAGETYPE_MASK          (0xf)
+
+/* Bit definitions for the PTP_SFDCFG register */
+#define TX_SFD_GPIO_SHIFT         (4)     /* TX SFD GPIO Select, value 1-12 */
+#define TX_SFD_GPIO_MASK          (0xf)
+#define RX_SFD_GPIO_SHIFT         (0)     /* RX SFD GPIO Select, value 1-12 */
+#define RX_SFD_GPIO_MASK          (0xf)
+
+/* Bit definitions for the PTP_INTCTL register */
+#define PTP_INT_GPIO_SHIFT        (0)     /* PTP Interrupt GPIO Select */
+#define PTP_INT_GPIO_MASK         (0xf)
+
+/* Bit definitions for the PTP_CLKSRC register */
+#define CLK_SRC_SHIFT             (14)    /* PTP Clock Source Select */
+#define CLK_SRC_MASK              (0x3)
+#define CLK_SRC_PER_SHIFT         (0)     /* PTP Clock Source Period */
+#define CLK_SRC_PER_MASK          (0x7f)
+
+/* Bit definitions for the PTP_OFF register */
+#define PTP_OFFSET_SHIFT          (0)     /* PTP Message offset from preceding header */
+#define PTP_OFFSET_MASK           (0xff)
+
+#endif
index 53872d7d738219968a0f433beb0ac128bdb67d6d..c554a397e558c2b0fbd5ac0ff2d94523612f8a42 100644 (file)
@@ -340,7 +340,7 @@ ppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
 }
 
 /* May sleep, don't call from interrupt level or with interrupts disabled */
-static unsigned int
+static void
 ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
                  char *cflags, int count)
 {
@@ -348,7 +348,7 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
        unsigned long flags;
 
        if (!ap)
-               return -ENODEV;
+               return;
        spin_lock_irqsave(&ap->recv_lock, flags);
        ppp_async_input(ap, buf, cflags, count);
        spin_unlock_irqrestore(&ap->recv_lock, flags);
@@ -356,8 +356,6 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
                tasklet_schedule(&ap->tsk);
        ap_put(ap);
        tty_unthrottle(tty);
-
-       return count;
 }
 
 static void
@@ -525,7 +523,7 @@ static void ppp_async_process(unsigned long arg)
 #define PUT_BYTE(ap, buf, c, islcp)    do {            \
        if ((islcp && c < 0x20) || (ap->xaccm[c >> 5] & (1 << (c & 0x1f)))) {\
                *buf++ = PPP_ESCAPE;                    \
-               *buf++ = c ^ 0x20;                      \
+               *buf++ = c ^ PPP_TRANS;                 \
        } else                                          \
                *buf++ = c;                             \
 } while (0)
@@ -898,7 +896,7 @@ ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
                                sp = skb_put(skb, n);
                                memcpy(sp, buf, n);
                                if (ap->state & SC_ESCAPE) {
-                                       sp[0] ^= 0x20;
+                                       sp[0] ^= PPP_TRANS;
                                        ap->state &= ~SC_ESCAPE;
                                }
                        }
index 0815790a5cf9930c017f490ae5d52e1d3ea67ecb..2573f525f11c31ced737e750fefc66807bbbfc65 100644 (file)
@@ -381,7 +381,7 @@ ppp_sync_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
 }
 
 /* May sleep, don't call from interrupt level or with interrupts disabled */
-static unsigned int
+static void
 ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
                  char *cflags, int count)
 {
@@ -389,7 +389,7 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
        unsigned long flags;
 
        if (!ap)
-               return -ENODEV;
+               return;
        spin_lock_irqsave(&ap->recv_lock, flags);
        ppp_sync_input(ap, buf, cflags, count);
        spin_unlock_irqrestore(&ap->recv_lock, flags);
@@ -397,8 +397,6 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
                tasklet_schedule(&ap->tsk);
        sp_put(ap);
        tty_unthrottle(tty);
-
-       return count;
 }
 
 static void
index 89f7540d90f909708fa318dbe9ecf6458252a922..5f597ca592bb8bf94a80861de3d315bc1b3c2026 100644 (file)
@@ -1273,7 +1273,7 @@ static int pxa168_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
        wmb();
        wrl(pep, SDMA_CMD, SDMA_CMD_TXDH | SDMA_CMD_ERD);
 
-       stats->tx_bytes += skb->len;
+       stats->tx_bytes += length;
        stats->tx_packets++;
        dev->trans_start = jiffies;
        if (pep->tx_ring_size - pep->tx_desc_count <= 1) {
index e9656616f2a256cfe16adde971ce53f63e0d98ab..a5d9fbf9d816a325d91adb79007a617922d7bf48 100644 (file)
@@ -1406,6 +1406,7 @@ qlcnic_dump_que(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
 
        for (loop = 0; loop < que->no_ops; loop++) {
                QLCNIC_WR_DUMP_REG(que->sel_addr, base, que_id);
+               addr = que->read_addr;
                for (i = 0; i < cnt; i++) {
                        QLCNIC_RD_DUMP_REG(addr, base, &data);
                        *buffer++ = cpu_to_le32(data);
index 3ab7d2c7baf20f2fb3ae3407b7eda7f113d6136a..0f6af5c61a7ca98b2cf5e0a5a44e5ff41eb9360a 100644 (file)
@@ -2159,6 +2159,7 @@ qlcnic_unmap_buffers(struct pci_dev *pdev, struct sk_buff *skb,
 
        nf = &pbuf->frag_array[0];
        pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE);
+       pbuf->skb = NULL;
 }
 
 static inline void
index ef1ce2ebeb4a6784ecca5d3c10f7ca084308ab9a..05d81780d1fdc5becc895e15fbcf86b695ce7392 100644 (file)
@@ -1621,7 +1621,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
         *
         * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
         */
-       static const struct {
+       static const struct rtl_mac_info {
                u32 mask;
                u32 val;
                int mac_version;
@@ -1689,7 +1689,8 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
 
                /* Catch-all */
                { 0x00000000, 0x00000000,       RTL_GIGA_MAC_NONE   }
-       }, *p = mac_info;
+       };
+       const struct rtl_mac_info *p = mac_info;
        u32 reg;
 
        reg = RTL_R32(TxConfig);
@@ -3681,7 +3682,7 @@ static void rtl_set_rx_max_size(void __iomem *ioaddr, unsigned int rx_buf_sz)
 
 static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version)
 {
-       static const struct {
+       static const struct rtl_cfg2_info {
                u32 mac_version;
                u32 clk;
                u32 val;
@@ -3690,7 +3691,8 @@ static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version)
                { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff },
                { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe
                { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff }
-       }, *p = cfg2_info;
+       };
+       const struct rtl_cfg2_info *p = cfg2_info;
        unsigned int i;
        u32 clk;
 
index e646bfce2d84933f8f1d43df8344c3d1d3bdc5b8..b6304486f2449437b5825169e06b77ad70ae6a97 100644 (file)
@@ -216,7 +216,7 @@ static void efx_mtd_remove_partition(struct efx_mtd_partition *part)
        int rc;
 
        for (;;) {
-               rc = del_mtd_device(&part->mtd);
+               rc = mtd_device_unregister(&part->mtd);
                if (rc != -EBUSY)
                        break;
                ssleep(1);
@@ -268,7 +268,7 @@ static int efx_mtd_probe_device(struct efx_nic *efx, struct efx_mtd *efx_mtd)
                part->mtd.write = efx_mtd->ops->write;
                part->mtd.sync = efx_mtd_sync;
 
-               if (add_mtd_device(&part->mtd))
+               if (mtd_device_register(&part->mtd, NULL, 0))
                        goto fail;
        }
 
@@ -280,7 +280,7 @@ fail:
                --part;
                efx_mtd_remove_partition(part);
        }
-       /* add_mtd_device() returns 1 if the MTD table is full */
+       /* mtd_device_register() returns 1 if the MTD table is full */
        return -ENOMEM;
 }
 
index 584809c656d5aaecda43d638fcaba1f48c929c89..8ec1a9a0bb9ae007c69865b2599f07d3f23c99c8 100644 (file)
@@ -670,17 +670,16 @@ static void sl_setup(struct net_device *dev)
  * in parallel
  */
 
-static unsigned int slip_receive_buf(struct tty_struct *tty,
-               const unsigned char *cp, char *fp, int count)
+static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                                                       char *fp, int count)
 {
        struct slip *sl = tty->disc_data;
-       int bytes = count;
 
        if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
-               return -ENODEV;
+               return;
 
        /* Read the characters out of the buffer */
-       while (bytes--) {
+       while (count--) {
                if (fp && *fp++) {
                        if (!test_and_set_bit(SLF_ERROR, &sl->flags))
                                sl->dev->stats.rx_errors++;
@@ -694,8 +693,6 @@ static unsigned int slip_receive_buf(struct tty_struct *tty,
 #endif
                        slip_unesc(sl, *cp++);
        }
-
-       return count;
 }
 
 /************************************
index 0f29f261fcfeb9b7658bbdb862b6676e1d1b5cb0..d07c39cb4daf59ae1e765b927d5156e816b80a9b 100644 (file)
@@ -156,7 +156,7 @@ static const struct {
    { 14, 15 }
 };
 
-static const short smc_mca_adapter_ids[] __devinitconst = {
+static short smc_mca_adapter_ids[] __initdata = {
        0x61c8,
        0x61c9,
        0x6fc0,
@@ -168,7 +168,7 @@ static const short smc_mca_adapter_ids[] __devinitconst = {
        0x0000
 };
 
-static const char *const smc_mca_adapter_names[] __devinitconst = {
+static char *smc_mca_adapter_names[] __initdata = {
        "SMC Ethercard PLUS Elite/A BNC/AUI (WD8013EP/A)",
        "SMC Ethercard PLUS Elite/A UTP/AUI (WD8013WP/A)",
        "WD Ethercard PLUS/A (WD8003E/A or WD8003ET/A)",
@@ -199,7 +199,7 @@ static const struct net_device_ops ultramca_netdev_ops = {
 #endif
 };
 
-static int __devinit ultramca_probe(struct device *gen_dev)
+static int __init ultramca_probe(struct device *gen_dev)
 {
        unsigned short ioaddr;
        struct net_device *dev;
index dc4805f473e33ee439ea00b884b4ab656b0b0c7b..f6285748bd3c0bd82bd8a6cba684527378ad2874 100644 (file)
@@ -2400,8 +2400,10 @@ static const struct of_device_id smc91x_match[] = {
        { .compatible = "smsc,lan91c94", },
        { .compatible = "smsc,lan91c111", },
        {},
-}
+};
 MODULE_DEVICE_TABLE(of, smc91x_match);
+#else
+#define smc91x_match NULL
 #endif
 
 static struct dev_pm_ops smc_drv_pm_ops = {
@@ -2416,9 +2418,7 @@ static struct platform_driver smc_driver = {
                .name   = CARDNAME,
                .owner  = THIS_MODULE,
                .pm     = &smc_drv_pm_ops,
-#ifdef CONFIG_OF
                .of_match_table = smc91x_match,
-#endif
        },
 };
 
index db19332a7d87ae69ef2268b7c25901ec6f3aca5d..a1f9f9eef37d3b04b8d1344c964eec0a57c56eb2 100644 (file)
@@ -292,6 +292,7 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1003)},
        {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100)},
        {PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_TIGON3)},
+       {PCI_DEVICE(0x10cf, 0x11a2)}, /* Fujitsu 1000base-SX with BCM5703SKHB */
        {}
 };
 
@@ -5773,7 +5774,7 @@ static void tg3_skb_error_unmap(struct tg3_napi *tnapi,
                         dma_unmap_addr(txb, mapping),
                         skb_headlen(skb),
                         PCI_DMA_TODEVICE);
-       for (i = 0; i <= last; i++) {
+       for (i = 0; i < last; i++) {
                skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
                entry = NEXT_TX(entry);
index 1e980fdd9d777a883131689d025eb401187f64fb..1e2af96fc29cf17d640f72d3bbbbd6aebe351647 100644 (file)
@@ -1658,11 +1658,9 @@ static int tile_net_stop(struct net_device *dev)
        while (tile_net_lepp_free_comps(dev, true))
                /* loop */;
 
-       /* Wipe the EPP queue. */
+       /* Wipe the EPP queue, and wait till the stores hit the EPP. */
        memset(priv->eq, 0, sizeof(lepp_queue_t));
-
-       /* Evict the EPP queue. */
-       finv_buffer(priv->eq, EQ_SIZE);
+       mb();
 
        return 0;
 }
@@ -2398,7 +2396,7 @@ static void tile_net_cleanup(void)
                        struct net_device *dev = tile_net_devs[i];
                        struct tile_net_priv *priv = netdev_priv(dev);
                        unregister_netdev(dev);
-                       finv_buffer(priv->eq, EQ_SIZE);
+                       finv_buffer_remote(priv->eq, EQ_SIZE, 0);
                        __free_pages(priv->eq_pages, EQ_ORDER);
                        free_netdev(dev);
                }
index 1313aa1315f01bcc241dbb41276831d2931b005d..2bedc0ace812ac2b5bfbf4ec05a54acc7f7c1ed5 100644 (file)
@@ -727,7 +727,7 @@ static int __devexit madgemc_remove(struct device *device)
        return 0;
 }
 
-static const short madgemc_adapter_ids[] __devinitconst = {
+static short madgemc_adapter_ids[] __initdata = {
        0x002d,
        0x0000
 };
index 45144d5bd11b26f6f86bd5db3e127239c2b0675c..efaa1d69b72082b5a0729710d0e86647b96bcc1e 100644 (file)
@@ -1995,7 +1995,7 @@ SetMulticastFilter(struct net_device *dev)
 
 static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
 
-static int __devinit de4x5_eisa_probe (struct device *gendev)
+static int __init de4x5_eisa_probe (struct device *gendev)
 {
        struct eisa_device *edev;
        u_long iobase;
@@ -2097,7 +2097,7 @@ static int __devexit de4x5_eisa_remove (struct device *device)
        return 0;
 }
 
-static const struct eisa_device_id de4x5_eisa_ids[] __devinitconst = {
+static struct eisa_device_id de4x5_eisa_ids[] = {
         { "DEC4250", 0 },      /* 0 is the board name index... */
         { "" }
 };
index 74e94054ab1a29d41828c7b9358518733eba0754..5235f48be1be677b7ca57fd275c21392fb846762 100644 (file)
@@ -460,7 +460,23 @@ static u32 tun_net_fix_features(struct net_device *dev, u32 features)
 
        return (features & tun->set_features) | (features & ~TUN_USER_FEATURES);
 }
-
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void tun_poll_controller(struct net_device *dev)
+{
+       /*
+        * Tun only receives frames when:
+        * 1) the char device endpoint gets data from user space
+        * 2) the tun socket gets a sendmsg call from user space
+        * Since both of those are syncronous operations, we are guaranteed
+        * never to have pending data when we poll for it
+        * so theres nothing to do here but return.
+        * We need this though so netpoll recognizes us as an interface that
+        * supports polling, which enables bridge devices in virt setups to
+        * still use netconsole
+        */
+       return;
+}
+#endif
 static const struct net_device_ops tun_netdev_ops = {
        .ndo_uninit             = tun_net_uninit,
        .ndo_open               = tun_net_open,
@@ -468,6 +484,9 @@ static const struct net_device_ops tun_netdev_ops = {
        .ndo_start_xmit         = tun_net_xmit,
        .ndo_change_mtu         = tun_net_change_mtu,
        .ndo_fix_features       = tun_net_fix_features,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = tun_poll_controller,
+#endif
 };
 
 static const struct net_device_ops tap_netdev_ops = {
@@ -480,6 +499,9 @@ static const struct net_device_ops tap_netdev_ops = {
        .ndo_set_multicast_list = tun_net_mclist,
        .ndo_set_mac_address    = eth_mac_addr,
        .ndo_validate_addr      = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = tun_poll_controller,
+#endif
 };
 
 /* Initialize net device. */
index 9d4f9117260f0a613c7d72e86867f724f107f5ae..84d4608153c992556a2d14a4a6bab37160abbf1b 100644 (file)
@@ -385,6 +385,16 @@ config USB_NET_CX82310_ETH
          router with USB ethernet port. This driver is for routers only,
          it will not work with ADSL modems (use cxacru driver instead).
 
+config USB_NET_KALMIA
+       tristate "Samsung Kalmia based LTE USB modem"
+       depends on USB_USBNET
+       help
+         Choose this option if you have a Samsung Kalmia based USB modem
+         as Samsung GT-B3730.
+
+         To compile this driver as a module, choose M here: the
+         module will be called kalmia.
+
 config USB_HSO
        tristate "Option USB High Speed Mobile Devices"
        depends on USB && RFKILL
index c7ec8a5f0a90d46fffcaa5a34e72468584086dd0..c203fa21f6b12473faa7efe3f6e851ab6af94954 100644 (file)
@@ -23,6 +23,7 @@ obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o
 obj-$(CONFIG_USB_USBNET)       += usbnet.o
 obj-$(CONFIG_USB_NET_INT51X1)  += int51x1.o
 obj-$(CONFIG_USB_CDC_PHONET)   += cdc-phonet.o
+obj-$(CONFIG_USB_NET_KALMIA)   += kalmia.o
 obj-$(CONFIG_USB_IPHETH)       += ipheth.o
 obj-$(CONFIG_USB_SIERRA_NET)   += sierra_net.o
 obj-$(CONFIG_USB_NET_CX82310_ETH)      += cx82310_eth.o
index d7221c4a5dcf97973b97ee50d93aec593a90b434..8056f8a27c6a0695f660648875dfeb0f60e7ee7e 100644 (file)
@@ -495,7 +495,7 @@ static void catc_ctrl_run(struct catc *catc)
        if (!q->dir && q->buf && q->len)
                memcpy(catc->ctrl_buf, q->buf, q->len);
 
-       if ((status = usb_submit_urb(catc->ctrl_urb, GFP_KERNEL)))
+       if ((status = usb_submit_urb(catc->ctrl_urb, GFP_ATOMIC)))
                err("submit(ctrl_urb) status %d", status);
 }
 
index 4ab557d0287de5abd269dc9be29ed6148742d393..f33ca6aa29e9cb95a8277891298317ca810cefa7 100644 (file)
@@ -54,7 +54,7 @@
 #include <linux/usb/usbnet.h>
 #include <linux/usb/cdc.h>
 
-#define        DRIVER_VERSION                          "06-May-2011"
+#define        DRIVER_VERSION                          "01-June-2011"
 
 /* CDC NCM subclass 3.2.1 */
 #define USB_CDC_NCM_NDP16_LENGTH_MIN           0x10
@@ -134,8 +134,6 @@ struct cdc_ncm_ctx {
        u16 tx_ndp_modulus;
        u16 tx_seq;
        u16 connected;
-       u8 data_claimed;
-       u8 control_claimed;
 };
 
 static void cdc_ncm_tx_timeout(unsigned long arg);
@@ -460,17 +458,6 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx)
 
        del_timer_sync(&ctx->tx_timer);
 
-       if (ctx->data_claimed) {
-               usb_set_intfdata(ctx->data, NULL);
-               usb_driver_release_interface(driver_of(ctx->intf), ctx->data);
-       }
-
-       if (ctx->control_claimed) {
-               usb_set_intfdata(ctx->control, NULL);
-               usb_driver_release_interface(driver_of(ctx->intf),
-                                                               ctx->control);
-       }
-
        if (ctx->tx_rem_skb != NULL) {
                dev_kfree_skb_any(ctx->tx_rem_skb);
                ctx->tx_rem_skb = NULL;
@@ -495,7 +482,7 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
 
        ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
        if (ctx == NULL)
-               goto error;
+               return -ENODEV;
 
        memset(ctx, 0, sizeof(*ctx));
 
@@ -568,46 +555,36 @@ advance:
 
        /* check if we got everything */
        if ((ctx->control == NULL) || (ctx->data == NULL) ||
-           (ctx->ether_desc == NULL))
+           (ctx->ether_desc == NULL) || (ctx->control != intf))
                goto error;
 
        /* claim interfaces, if any */
-       if (ctx->data != intf) {
-               temp = usb_driver_claim_interface(driver, ctx->data, dev);
-               if (temp)
-                       goto error;
-               ctx->data_claimed = 1;
-       }
-
-       if (ctx->control != intf) {
-               temp = usb_driver_claim_interface(driver, ctx->control, dev);
-               if (temp)
-                       goto error;
-               ctx->control_claimed = 1;
-       }
+       temp = usb_driver_claim_interface(driver, ctx->data, dev);
+       if (temp)
+               goto error;
 
        iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
 
        /* reset data interface */
        temp = usb_set_interface(dev->udev, iface_no, 0);
        if (temp)
-               goto error;
+               goto error2;
 
        /* initialize data interface */
        if (cdc_ncm_setup(ctx))
-               goto error;
+               goto error2;
 
        /* configure data interface */
        temp = usb_set_interface(dev->udev, iface_no, 1);
        if (temp)
-               goto error;
+               goto error2;
 
        cdc_ncm_find_endpoints(ctx, ctx->data);
        cdc_ncm_find_endpoints(ctx, ctx->control);
 
        if ((ctx->in_ep == NULL) || (ctx->out_ep == NULL) ||
            (ctx->status_ep == NULL))
-               goto error;
+               goto error2;
 
        dev->net->ethtool_ops = &cdc_ncm_ethtool_ops;
 
@@ -617,7 +594,7 @@ advance:
 
        temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress);
        if (temp)
-               goto error;
+               goto error2;
 
        dev_info(&dev->udev->dev, "MAC-Address: "
                                "0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
@@ -642,38 +619,38 @@ advance:
        ctx->tx_speed = ctx->rx_speed = 0;
        return 0;
 
+error2:
+       usb_set_intfdata(ctx->control, NULL);
+       usb_set_intfdata(ctx->data, NULL);
+       usb_driver_release_interface(driver, ctx->data);
 error:
        cdc_ncm_free((struct cdc_ncm_ctx *)dev->data[0]);
        dev->data[0] = 0;
-       dev_info(&dev->udev->dev, "Descriptor failure\n");
+       dev_info(&dev->udev->dev, "bind() failure\n");
        return -ENODEV;
 }
 
 static void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf)
 {
        struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
-       struct usb_driver *driver;
+       struct usb_driver *driver = driver_of(intf);
 
        if (ctx == NULL)
                return;         /* no setup */
 
-       driver = driver_of(intf);
-
-       usb_set_intfdata(ctx->data, NULL);
-       usb_set_intfdata(ctx->control, NULL);
-       usb_set_intfdata(ctx->intf, NULL);
-
-       /* release interfaces, if any */
-       if (ctx->data_claimed) {
+       /* disconnect master --> disconnect slave */
+       if (intf == ctx->control && ctx->data) {
+               usb_set_intfdata(ctx->data, NULL);
                usb_driver_release_interface(driver, ctx->data);
-               ctx->data_claimed = 0;
-       }
+               ctx->data = NULL;
 
-       if (ctx->control_claimed) {
+       } else if (intf == ctx->data && ctx->control) {
+               usb_set_intfdata(ctx->control, NULL);
                usb_driver_release_interface(driver, ctx->control);
-               ctx->control_claimed = 0;
+               ctx->control = NULL;
        }
 
+       usb_set_intfdata(ctx->intf, NULL);
        cdc_ncm_free(ctx);
 }
 
@@ -1257,6 +1234,7 @@ static struct usb_driver cdc_ncm_driver = {
        .disconnect = cdc_ncm_disconnect,
        .suspend = usbnet_suspend,
        .resume = usbnet_resume,
+       .reset_resume = usbnet_resume,
        .supports_autosuspend = 1,
 };
 
diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c
new file mode 100644 (file)
index 0000000..d965fb1
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * USB network interface driver for Samsung Kalmia based LTE USB modem like the
+ * Samsung GT-B3730 and GT-B3710.
+ *
+ * Copyright (C) 2011 Marius Bjoernstad Kotsbak <marius@kotsbak.com>
+ *
+ * Sponsored by Quicklink Video Distribution Services Ltd.
+ *
+ * Based on the cdc_eem module.
+ *
+ * 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/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ctype.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/usbnet.h>
+#include <linux/gfp.h>
+
+/*
+ * The Samsung Kalmia based LTE USB modems have a CDC ACM port for modem control
+ * handled by the "option" module and an ethernet data port handled by this
+ * module.
+ *
+ * The stick must first be switched into modem mode by usb_modeswitch
+ * or similar tool. Then the modem gets sent two initialization packets by
+ * this module, which gives the MAC address of the device. User space can then
+ * connect the modem using AT commands through the ACM port and then use
+ * DHCP on the network interface exposed by this module. Network packets are
+ * sent to and from the modem in a proprietary format discovered after watching
+ * the behavior of the windows driver for the modem.
+ *
+ * More information about the use of the modem is available in usb_modeswitch
+ * forum and the project page:
+ *
+ * http://www.draisberghof.de/usb_modeswitch/bb/viewtopic.php?t=465
+ * https://github.com/mkotsbak/Samsung-GT-B3730-linux-driver
+ */
+
+/* #define     DEBUG */
+/* #define     VERBOSE */
+
+#define KALMIA_HEADER_LENGTH 6
+#define KALMIA_ALIGN_SIZE 4
+#define KALMIA_USB_TIMEOUT 10000
+
+/*-------------------------------------------------------------------------*/
+
+static int
+kalmia_send_init_packet(struct usbnet *dev, u8 *init_msg, u8 init_msg_len,
+       u8 *buffer, u8 expected_len)
+{
+       int act_len;
+       int status;
+
+       netdev_dbg(dev->net, "Sending init packet");
+
+       status = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 0x02),
+               init_msg, init_msg_len, &act_len, KALMIA_USB_TIMEOUT);
+       if (status != 0) {
+               netdev_err(dev->net,
+                       "Error sending init packet. Status %i, length %i\n",
+                       status, act_len);
+               return status;
+       }
+       else if (act_len != init_msg_len) {
+               netdev_err(dev->net,
+                       "Did not send all of init packet. Bytes sent: %i",
+                       act_len);
+       }
+       else {
+               netdev_dbg(dev->net, "Successfully sent init packet.");
+       }
+
+       status = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, 0x81),
+               buffer, expected_len, &act_len, KALMIA_USB_TIMEOUT);
+
+       if (status != 0)
+               netdev_err(dev->net,
+                       "Error receiving init result. Status %i, length %i\n",
+                       status, act_len);
+       else if (act_len != expected_len)
+               netdev_err(dev->net, "Unexpected init result length: %i\n",
+                       act_len);
+
+       return status;
+}
+
+static int
+kalmia_init_and_get_ethernet_addr(struct usbnet *dev, u8 *ethernet_addr)
+{
+       char init_msg_1[] =
+               { 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+               0x00, 0x00 };
+       char init_msg_2[] =
+               { 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xf4,
+               0x00, 0x00 };
+       char receive_buf[28];
+       int status;
+
+       status = kalmia_send_init_packet(dev, init_msg_1, sizeof(init_msg_1)
+               / sizeof(init_msg_1[0]), receive_buf, 24);
+       if (status != 0)
+               return status;
+
+       status = kalmia_send_init_packet(dev, init_msg_2, sizeof(init_msg_2)
+               / sizeof(init_msg_2[0]), receive_buf, 28);
+       if (status != 0)
+               return status;
+
+       memcpy(ethernet_addr, receive_buf + 10, ETH_ALEN);
+
+       return status;
+}
+
+static int
+kalmia_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+       u8 status;
+       u8 ethernet_addr[ETH_ALEN];
+
+       /* Don't bind to AT command interface */
+       if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
+               return -EINVAL;
+
+       dev->in = usb_rcvbulkpipe(dev->udev, 0x81 & USB_ENDPOINT_NUMBER_MASK);
+       dev->out = usb_sndbulkpipe(dev->udev, 0x02 & USB_ENDPOINT_NUMBER_MASK);
+       dev->status = NULL;
+
+       dev->net->hard_header_len += KALMIA_HEADER_LENGTH;
+       dev->hard_mtu = 1400;
+       dev->rx_urb_size = dev->hard_mtu * 10; // Found as optimal after testing
+
+       status = kalmia_init_and_get_ethernet_addr(dev, ethernet_addr);
+
+       if (status < 0) {
+               usb_set_intfdata(intf, NULL);
+               usb_driver_release_interface(driver_of(intf), intf);
+               return status;
+       }
+
+       memcpy(dev->net->dev_addr, ethernet_addr, ETH_ALEN);
+       memcpy(dev->net->perm_addr, ethernet_addr, ETH_ALEN);
+
+       return status;
+}
+
+static struct sk_buff *
+kalmia_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+{
+       struct sk_buff *skb2 = NULL;
+       u16 content_len;
+       unsigned char *header_start;
+       unsigned char ether_type_1, ether_type_2;
+       u8 remainder, padlen = 0;
+
+       if (!skb_cloned(skb)) {
+               int headroom = skb_headroom(skb);
+               int tailroom = skb_tailroom(skb);
+
+               if ((tailroom >= KALMIA_ALIGN_SIZE) && (headroom
+                       >= KALMIA_HEADER_LENGTH))
+                       goto done;
+
+               if ((headroom + tailroom) > (KALMIA_HEADER_LENGTH
+                       + KALMIA_ALIGN_SIZE)) {
+                       skb->data = memmove(skb->head + KALMIA_HEADER_LENGTH,
+                               skb->data, skb->len);
+                       skb_set_tail_pointer(skb, skb->len);
+                       goto done;
+               }
+       }
+
+       skb2 = skb_copy_expand(skb, KALMIA_HEADER_LENGTH,
+               KALMIA_ALIGN_SIZE, flags);
+       if (!skb2)
+               return NULL;
+
+       dev_kfree_skb_any(skb);
+       skb = skb2;
+
+       done: header_start = skb_push(skb, KALMIA_HEADER_LENGTH);
+       ether_type_1 = header_start[KALMIA_HEADER_LENGTH + 12];
+       ether_type_2 = header_start[KALMIA_HEADER_LENGTH + 13];
+
+       netdev_dbg(dev->net, "Sending etherType: %02x%02x", ether_type_1,
+               ether_type_2);
+
+       /* According to empiric data for data packages */
+       header_start[0] = 0x57;
+       header_start[1] = 0x44;
+       content_len = skb->len - KALMIA_HEADER_LENGTH;
+       header_start[2] = (content_len & 0xff); /* low byte */
+       header_start[3] = (content_len >> 8); /* high byte */
+
+       header_start[4] = ether_type_1;
+       header_start[5] = ether_type_2;
+
+       /* Align to 4 bytes by padding with zeros */
+       remainder = skb->len % KALMIA_ALIGN_SIZE;
+       if (remainder > 0) {
+               padlen = KALMIA_ALIGN_SIZE - remainder;
+               memset(skb_put(skb, padlen), 0, padlen);
+       }
+
+       netdev_dbg(
+               dev->net,
+               "Sending package with length %i and padding %i. Header: %02x:%02x:%02x:%02x:%02x:%02x.",
+               content_len, padlen, header_start[0], header_start[1],
+               header_start[2], header_start[3], header_start[4],
+               header_start[5]);
+
+       return skb;
+}
+
+static int
+kalmia_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+       /*
+        * Our task here is to strip off framing, leaving skb with one
+        * data frame for the usbnet framework code to process.
+        */
+       const u8 HEADER_END_OF_USB_PACKET[] =
+               { 0x57, 0x5a, 0x00, 0x00, 0x08, 0x00 };
+       const u8 EXPECTED_UNKNOWN_HEADER_1[] =
+               { 0x57, 0x43, 0x1e, 0x00, 0x15, 0x02 };
+       const u8 EXPECTED_UNKNOWN_HEADER_2[] =
+               { 0x57, 0x50, 0x0e, 0x00, 0x00, 0x00 };
+       u8 i = 0;
+
+       /* incomplete header? */
+       if (skb->len < KALMIA_HEADER_LENGTH)
+               return 0;
+
+       do {
+               struct sk_buff *skb2 = NULL;
+               u8 *header_start;
+               u16 usb_packet_length, ether_packet_length;
+               int is_last;
+
+               header_start = skb->data;
+
+               if (unlikely(header_start[0] != 0x57 || header_start[1] != 0x44)) {
+                       if (!memcmp(header_start, EXPECTED_UNKNOWN_HEADER_1,
+                               sizeof(EXPECTED_UNKNOWN_HEADER_1)) || !memcmp(
+                               header_start, EXPECTED_UNKNOWN_HEADER_2,
+                               sizeof(EXPECTED_UNKNOWN_HEADER_2))) {
+                               netdev_dbg(
+                                       dev->net,
+                                       "Received expected unknown frame header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n",
+                                       header_start[0], header_start[1],
+                                       header_start[2], header_start[3],
+                                       header_start[4], header_start[5],
+                                       skb->len - KALMIA_HEADER_LENGTH);
+                       }
+                       else {
+                               netdev_err(
+                                       dev->net,
+                                       "Received unknown frame header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n",
+                                       header_start[0], header_start[1],
+                                       header_start[2], header_start[3],
+                                       header_start[4], header_start[5],
+                                       skb->len - KALMIA_HEADER_LENGTH);
+                               return 0;
+                       }
+               }
+               else
+                       netdev_dbg(
+                               dev->net,
+                               "Received header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n",
+                               header_start[0], header_start[1], header_start[2],
+                               header_start[3], header_start[4], header_start[5],
+                               skb->len - KALMIA_HEADER_LENGTH);
+
+               /* subtract start header and end header */
+               usb_packet_length = skb->len - (2 * KALMIA_HEADER_LENGTH);
+               ether_packet_length = header_start[2] + (header_start[3] << 8);
+               skb_pull(skb, KALMIA_HEADER_LENGTH);
+
+               /* Some small packets misses end marker */
+               if (usb_packet_length < ether_packet_length) {
+                       ether_packet_length = usb_packet_length
+                               + KALMIA_HEADER_LENGTH;
+                       is_last = true;
+               }
+               else {
+                       netdev_dbg(dev->net, "Correct package length #%i", i
+                               + 1);
+
+                       is_last = (memcmp(skb->data + ether_packet_length,
+                               HEADER_END_OF_USB_PACKET,
+                               sizeof(HEADER_END_OF_USB_PACKET)) == 0);
+                       if (!is_last) {
+                               header_start = skb->data + ether_packet_length;
+                               netdev_dbg(
+                                       dev->net,
+                                       "End header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n",
+                                       header_start[0], header_start[1],
+                                       header_start[2], header_start[3],
+                                       header_start[4], header_start[5],
+                                       skb->len - KALMIA_HEADER_LENGTH);
+                       }
+               }
+
+               if (is_last) {
+                       skb2 = skb;
+               }
+               else {
+                       skb2 = skb_clone(skb, GFP_ATOMIC);
+                       if (unlikely(!skb2))
+                               return 0;
+               }
+
+               skb_trim(skb2, ether_packet_length);
+
+               if (is_last) {
+                       return 1;
+               }
+               else {
+                       usbnet_skb_return(dev, skb2);
+                       skb_pull(skb, ether_packet_length);
+               }
+
+               i++;
+       }
+       while (skb->len);
+
+       return 1;
+}
+
+static const struct driver_info kalmia_info = {
+       .description = "Samsung Kalmia LTE USB dongle",
+       .flags = FLAG_WWAN,
+       .bind = kalmia_bind,
+       .rx_fixup = kalmia_rx_fixup,
+       .tx_fixup = kalmia_tx_fixup
+};
+
+/*-------------------------------------------------------------------------*/
+
+static const struct usb_device_id products[] = {
+       /* The unswitched USB ID, to get the module auto loaded: */
+       { USB_DEVICE(0x04e8, 0x689a) },
+       /* The stick swithed into modem (by e.g. usb_modeswitch): */
+       { USB_DEVICE(0x04e8, 0x6889),
+               .driver_info = (unsigned long) &kalmia_info, },
+       { /* EMPTY == end of list */} };
+MODULE_DEVICE_TABLE( usb, products);
+
+static struct usb_driver kalmia_driver = {
+       .name = "kalmia",
+       .id_table = products,
+       .probe = usbnet_probe,
+       .disconnect = usbnet_disconnect,
+       .suspend = usbnet_suspend,
+       .resume = usbnet_resume
+};
+
+static int __init kalmia_init(void)
+{
+       return usb_register(&kalmia_driver);
+}
+module_init( kalmia_init);
+
+static void __exit kalmia_exit(void)
+{
+       usb_deregister(&kalmia_driver);
+}
+module_exit( kalmia_exit);
+
+MODULE_AUTHOR("Marius Bjoernstad Kotsbak <marius@kotsbak.com>");
+MODULE_DESCRIPTION("Samsung Kalmia USB network driver");
+MODULE_LICENSE("GPL");
index d7227539484e3d5dae53b4077109d38844d32b00..0f1f05f6c4f8a3e644d8e9dd1c75cb7da4d2c2c1 100644 (file)
@@ -1096,7 +1096,7 @@ struct mac_regs {
 
        volatile __le16 PatternCRC[8];  /* 0xB0 */
        volatile __le32 ByteMask[4][4]; /* 0xC0 */
-} __packed;
+};
 
 
 enum hw_mib {
index 0cb0b0632672ac877c927195bde052a2d38f9ecf..f6853247a620046a12e9dab53c9e4f3adcf4d2b2 100644 (file)
@@ -609,7 +609,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
         * before it gets out of hand.  Naturally, this wastes entries. */
        if (capacity < 2+MAX_SKB_FRAGS) {
                netif_stop_queue(dev);
-               if (unlikely(!virtqueue_enable_cb(vi->svq))) {
+               if (unlikely(!virtqueue_enable_cb_delayed(vi->svq))) {
                        /* More just got used, free them then recheck. */
                        capacity += free_old_xmit_skbs(vi);
                        if (capacity >= 2+MAX_SKB_FRAGS) {
index e050bd65e0378cbdd6643d893c01a4462a2dea2f..777d1a4e81b2cb0c43599e146e16d774e47abe66 100644 (file)
@@ -2203,8 +2203,10 @@ fst_open(struct net_device *dev)
 
        if (port->mode != FST_RAW) {
                err = hdlc_open(dev);
-               if (err)
+               if (err) {
+                       module_put(THIS_MODULE);
                        return err;
+               }
        }
 
        fst_openport(port);
index 737b59f1a8dc4a28f535434ca207128fad1d4f76..9617d3d0ee39e055a94150d6ee0cf8b2014cf0e1 100644 (file)
@@ -3242,8 +3242,7 @@ static inline void show_version(void)
        rcsdate++;
        tmp = strrchr(rcsdate, ' ');
        *tmp = '\0';
-       printk(KERN_INFO "Cyclades-PC300 driver %s %s (built %s %s)\n", 
-               rcsvers, rcsdate, __DATE__, __TIME__);
+       printk(KERN_INFO "Cyclades-PC300 driver %s %s\n", rcsvers, rcsdate);
 }                              /* show_version */
 
 static const struct net_device_ops cpc_netdev_ops = {
index 40398bf7d036fca1d1b56047f638375fdfd6f796..24297b274cd475ac855114394784c7eeaab2bcd0 100644 (file)
@@ -517,18 +517,17 @@ static int x25_asy_close(struct net_device *dev)
  * and sent on to some IP layer for further processing.
  */
 
-static unsigned int x25_asy_receive_buf(struct tty_struct *tty,
+static void x25_asy_receive_buf(struct tty_struct *tty,
                                const unsigned char *cp, char *fp, int count)
 {
        struct x25_asy *sl = tty->disc_data;
-       int bytes = count;
 
        if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev))
                return;
 
 
        /* Read the characters out of the buffer */
-       while (bytes--) {
+       while (count--) {
                if (fp && *fp++) {
                        if (!test_and_set_bit(SLF_ERROR, &sl->flags))
                                sl->dev->stats.rx_errors++;
@@ -537,8 +536,6 @@ static unsigned int x25_asy_receive_buf(struct tty_struct *tty,
                }
                x25_asy_unesc(sl, *cp++);
        }
-
-       return count;
 }
 
 /*
index a70c512f05d2ef9924298da3b87647a0b13866d0..55cf71fbffe32125d9bdbbbe429b98ed0acea35e 100644 (file)
@@ -4501,17 +4501,15 @@ static int setup_proc_entry( struct net_device *dev,
        struct proc_dir_entry *entry;
        /* First setup the device directory */
        strcpy(apriv->proc_name,dev->name);
-       apriv->proc_entry = create_proc_entry(apriv->proc_name,
-                                             S_IFDIR|airo_perm,
-                                             airo_entry);
+       apriv->proc_entry = proc_mkdir_mode(apriv->proc_name, airo_perm,
+                                           airo_entry);
        if (!apriv->proc_entry)
                goto fail;
        apriv->proc_entry->uid = proc_uid;
        apriv->proc_entry->gid = proc_gid;
 
        /* Setup the StatsDelta */
-       entry = proc_create_data("StatsDelta",
-                                S_IFREG | (S_IRUGO&proc_perm),
+       entry = proc_create_data("StatsDelta", S_IRUGO & proc_perm,
                                 apriv->proc_entry, &proc_statsdelta_ops, dev);
        if (!entry)
                goto fail_stats_delta;
@@ -4519,8 +4517,7 @@ static int setup_proc_entry( struct net_device *dev,
        entry->gid = proc_gid;
 
        /* Setup the Stats */
-       entry = proc_create_data("Stats",
-                                S_IFREG | (S_IRUGO&proc_perm),
+       entry = proc_create_data("Stats", S_IRUGO & proc_perm,
                                 apriv->proc_entry, &proc_stats_ops, dev);
        if (!entry)
                goto fail_stats;
@@ -4528,8 +4525,7 @@ static int setup_proc_entry( struct net_device *dev,
        entry->gid = proc_gid;
 
        /* Setup the Status */
-       entry = proc_create_data("Status",
-                                S_IFREG | (S_IRUGO&proc_perm),
+       entry = proc_create_data("Status", S_IRUGO & proc_perm,
                                 apriv->proc_entry, &proc_status_ops, dev);
        if (!entry)
                goto fail_status;
@@ -4537,8 +4533,7 @@ static int setup_proc_entry( struct net_device *dev,
        entry->gid = proc_gid;
 
        /* Setup the Config */
-       entry = proc_create_data("Config",
-                                S_IFREG | proc_perm,
+       entry = proc_create_data("Config", proc_perm,
                                 apriv->proc_entry, &proc_config_ops, dev);
        if (!entry)
                goto fail_config;
@@ -4546,8 +4541,7 @@ static int setup_proc_entry( struct net_device *dev,
        entry->gid = proc_gid;
 
        /* Setup the SSID */
-       entry = proc_create_data("SSID",
-                                S_IFREG | proc_perm,
+       entry = proc_create_data("SSID", proc_perm,
                                 apriv->proc_entry, &proc_SSID_ops, dev);
        if (!entry)
                goto fail_ssid;
@@ -4555,8 +4549,7 @@ static int setup_proc_entry( struct net_device *dev,
        entry->gid = proc_gid;
 
        /* Setup the APList */
-       entry = proc_create_data("APList",
-                                S_IFREG | proc_perm,
+       entry = proc_create_data("APList", proc_perm,
                                 apriv->proc_entry, &proc_APList_ops, dev);
        if (!entry)
                goto fail_aplist;
@@ -4564,8 +4557,7 @@ static int setup_proc_entry( struct net_device *dev,
        entry->gid = proc_gid;
 
        /* Setup the BSSList */
-       entry = proc_create_data("BSSList",
-                                S_IFREG | proc_perm,
+       entry = proc_create_data("BSSList", proc_perm,
                                 apriv->proc_entry, &proc_BSSList_ops, dev);
        if (!entry)
                goto fail_bsslist;
@@ -4573,8 +4565,7 @@ static int setup_proc_entry( struct net_device *dev,
        entry->gid = proc_gid;
 
        /* Setup the WepKey */
-       entry = proc_create_data("WepKey",
-                                S_IFREG | proc_perm,
+       entry = proc_create_data("WepKey", proc_perm,
                                 apriv->proc_entry, &proc_wepkey_ops, dev);
        if (!entry)
                goto fail_wepkey;
@@ -5706,9 +5697,7 @@ static int __init airo_init_module( void )
 {
        int i;
 
-       airo_entry = create_proc_entry("driver/aironet",
-                                      S_IFDIR | airo_perm,
-                                      NULL);
+       airo_entry = proc_mkdir_mode("driver/aironet", airo_perm, NULL);
 
        if (airo_entry) {
                airo_entry->uid = proc_uid;
index df2484d4547489c64404c0a8ab3e8579fb7cceba..c983c10e0f6a8336b855dc810f237172cf1c6ef2 100644 (file)
@@ -164,7 +164,7 @@ static int airo_resume(struct pcmcia_device *link)
        return 0;
 }
 
-static struct pcmcia_device_id airo_ids[] = {
+static const struct pcmcia_device_id airo_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x015f, 0x000a),
        PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0005),
        PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0007),
index 22047628ccfa83bbd59242c511192e52ab04a12e..b6c5d3715b963e73f6b962070f6e78256449d107 100644 (file)
@@ -72,6 +72,11 @@ static int modparam_all_channels;
 module_param_named(all_channels, modparam_all_channels, bool, S_IRUGO);
 MODULE_PARM_DESC(all_channels, "Expose all channels the device can use.");
 
+static int modparam_fastchanswitch;
+module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO);
+MODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios.");
+
+
 /* Module info */
 MODULE_AUTHOR("Jiri Slaby");
 MODULE_AUTHOR("Nick Kossifidis");
@@ -2686,6 +2691,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
        struct ath5k_hw *ah = sc->ah;
        struct ath_common *common = ath5k_hw_common(ah);
        int ret, ani_mode;
+       bool fast;
 
        ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n");
 
@@ -2705,7 +2711,10 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
        ath5k_drain_tx_buffs(sc);
        if (chan)
                sc->curchan = chan;
-       ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL,
+
+       fast = ((chan != NULL) && modparam_fastchanswitch) ? 1 : 0;
+
+       ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, fast,
                                                                skip_pcu);
        if (ret) {
                ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
index 3510de2cf6224c6ec11b091cfb3f50dd1fccf6b9..126a4eab35f39d7a10995f0f20ff814a87def88c 100644 (file)
@@ -1124,8 +1124,11 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
                        /* Non fatal, can happen eg.
                         * on mode change */
                        ret = 0;
-               } else
+               } else {
+                       ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_RESET,
+                               "fast chan change successful\n");
                        return 0;
+               }
        }
 
        /*
index d9ff8413ab9af4e6e9634277cec7e58752c833b0..d9c08c619a3ab045fe7950aff6dc6f50d1f08b49 100644 (file)
@@ -26,7 +26,6 @@ config ATH9K
 config ATH9K_PCI
        bool "Atheros ath9k PCI/PCIe bus support"
        depends on ATH9K && PCI
-       default PCI
        ---help---
          This option enables the PCI bus support in ath9k.
 
index 61956392f2da44c3b8dd86b0f84c5a6e6675c5ed..5b49cd03bfdfcaa09d130c07fed1d0bab0607afe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
  * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
  *
index 5a1f4f511bc152df2e033380e666c45a0bb9cc5b..bfb6481f01f9ba9d06aa92fecf9c6ccd4e9c0757 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 0cd6783de883668d2f433bfb07f5ffe0c47863cb..dbab5b9ce4948a3174a4a6e1bb4c74b800f3eb90 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 36f7d0639db333d51e904ab6a2871909d06937d1..234617c948a1d8589e4b1a56f30e758ffb597993 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 4bf9dab4f2b38b776d25d5226222be1f7bd36474..441bb33f17adb705af53f5a04f764a6cfa911f46 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 69a94c7e45cb3df2b9b4ce79d5f89f0bdbe09b9d..6d2e2f3303f9125db9f4b7b3fcf47388b61223c7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index cb611b287b35a4459bdce1fa4c179b72b64aef94..2d4c0910295bd39b08cb4abdc845c140d6bc22de 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -829,7 +829,7 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
        if (AR_SREV_9271(ah)) {
                if (!ar9285_hw_cl_cal(ah, chan))
                        return false;
-       } else if (AR_SREV_9285_12_OR_LATER(ah)) {
+       } else if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) {
                if (!ar9285_hw_clc(ah, chan))
                        return false;
        } else {
index f44c84ab5dceddae414dfdec5f877e98bc0013e6..f344cc2b3d5966827eb352cb5761d14b13833568 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 6203eed860ddc1c31fd2ba0ed10d4151a7e843b5..7573257731b6d7e865f97f50b2f41adbf860dec5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 7a332f16b79af9b83ad7764b45577342e64384e0..077e8a6983fab5637fb8bdc9a949f38a018d7d09 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index a57e963cf0dc19dd6b7ad51180657f63c65b6b9d..2fe0a34cbabcba3750446f5b33e57d80878c5fbf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 47780ef1c892e56317d48e4fdc500bf34fc7c17f..453af6dc514b5f700a16a615d1f2ea3104191026 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index f915a3dbfcad106737b4fc803c814a6ae63e067f..e8ac70da5ac70d2ec0fc585c556017ce51b6b90e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index f276cb922b4d5d96bf16703bd67b75ac40aecb55..f48051c50092f0d85a5babf97160621862c24b36 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index d985841ff4014ef966acede1906db98e71acaf88..ff8150e46f0e969a159d3b481cee5752432fcace 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -4645,10 +4645,16 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
        case 1:
                break;
        case 2:
-               scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+               if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN)
+                       scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+               else
+                       scaledPower = 0;
                break;
        case 3:
-               scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+               if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN)
+                       scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+               else
+                       scaledPower = 0;
                break;
        }
 
index afb0b5ee1865c3c10481b5d6a8fac4c932f97af2..ab21a49159811c8ccaa587aef294e37dd95e84cd 100644 (file)
@@ -1,3 +1,19 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
 #ifndef AR9003_EEPROM_H
 #define AR9003_EEPROM_H
 
index a55eddbb258923aaf85a35966fb35a3974fa15f0..392bf0f8ff1687678ff01816a0177a99c303e4c5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index be6adec33ddbb0d9c9d655f8b1ca4b5a3f6fc852..10d71f7d3fc22b7ed71bb8f5ad7f9097d910e82e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 45cc7e80436c067430e140dd5dfb36b671afe62f..c50449387bf163144a0ad8491296ca87cc08dfc8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 356d2fd78822279245b0d4a2669a5d6aa6dd731d..e4d6a87ec53830bf70126f29090a2349dea5cfef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 25f3c2fdf2bcf15010d550cfb167294acc45781f..892c48b15434569c7b74d12d426e4cdb1c15dcfb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -1381,3 +1381,25 @@ void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah)
                "==== BB update: done ====\n\n");
 }
 EXPORT_SYMBOL(ar9003_hw_bb_watchdog_dbg_info);
+
+void ar9003_hw_disable_phy_restart(struct ath_hw *ah)
+{
+       u32 val;
+
+       /* While receiving unsupported rate frame rx state machine
+        * gets into a state 0xb and if phy_restart happens in that
+        * state, BB would go hang. If RXSM is in 0xb state after
+        * first bb panic, ensure to disable the phy_restart.
+        */
+       if (!((MS(ah->bb_watchdog_last_status,
+                 AR_PHY_WATCHDOG_RX_OFDM_SM) == 0xb) ||
+           ah->bb_hang_rx_ofdm))
+               return;
+
+       ah->bb_hang_rx_ofdm = true;
+       val = REG_READ(ah, AR_PHY_RESTART);
+       val &= ~AR_PHY_RESTART_ENA;
+
+       REG_WRITE(ah, AR_PHY_RESTART, val);
+}
+EXPORT_SYMBOL(ar9003_hw_disable_phy_restart);
index c7505b48e5c0b3ede5ff22de98f0f2edd1afc7b5..443090d278e33234e432085fdb97657ce974afd9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2010 Atheros Communications, Inc.
+ * Copyright (c) 2010-2011 Atheros Communications, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index fbdde29f0ab8d4e9349d3320e923eeef262d4432..611ea6ce8508dfb760a1172ea46793e6716c48e3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 03b37d7be1c3bac7cb5276d71fb55019869ac6fe..f75068b4b310e2383c2b30e79a2e88c59c0a0622 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -397,6 +397,9 @@ struct ath_beacon {
        struct ath_descdma bdma;
        struct ath_txq *cabq;
        struct list_head bbuf;
+
+       bool tx_processed;
+       bool tx_last;
 };
 
 void ath_beacon_tasklet(unsigned long data);
index 637dbc5f7b67478e975e81a33a33ab5785fc5d84..d4d8ceced89b754c1babef1ba41d11cfe456efcc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 
 #define FUDGE 2
 
+static void ath9k_reset_beacon_status(struct ath_softc *sc)
+{
+       sc->beacon.tx_processed = false;
+       sc->beacon.tx_last = false;
+}
+
 /*
  *  This function will modify certain transmit queue properties depending on
  *  the operating mode of the station (AP or AdHoc).  Parameters are AIFS
@@ -72,6 +78,8 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
        struct ieee80211_supported_band *sband;
        u8 rate = 0;
 
+       ath9k_reset_beacon_status(sc);
+
        ds = bf->bf_desc;
        flags = ATH9K_TXDESC_NOACK;
 
@@ -134,6 +142,8 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
        struct ieee80211_tx_info *info;
        int cabq_depth;
 
+       ath9k_reset_beacon_status(sc);
+
        avp = (void *)vif->drv_priv;
        cabq = sc->beacon.cabq;
 
@@ -351,9 +361,7 @@ void ath_beacon_tasklet(unsigned long data)
        struct ath_buf *bf = NULL;
        struct ieee80211_vif *vif;
        int slot;
-       u32 bfaddr, bc = 0, tsftu;
-       u64 tsf;
-       u16 intval;
+       u32 bfaddr, bc = 0;
 
        /*
         * Check if the previous beacon has gone out.  If
@@ -388,17 +396,27 @@ void ath_beacon_tasklet(unsigned long data)
         * on the tsf to safeguard against missing an swba.
         */
 
-       intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
 
-       tsf = ath9k_hw_gettsf64(ah);
-       tsf += TU_TO_USEC(ah->config.sw_beacon_response_time);
-       tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
-       slot = (tsftu % (intval * ATH_BCBUF)) / intval;
-       vif = sc->beacon.bslot[slot];
+       if (ah->opmode == NL80211_IFTYPE_AP) {
+               u16 intval;
+               u32 tsftu;
+               u64 tsf;
+
+               intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
+               tsf = ath9k_hw_gettsf64(ah);
+               tsf += TU_TO_USEC(ah->config.sw_beacon_response_time);
+               tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
+               slot = (tsftu % (intval * ATH_BCBUF)) / intval;
+               vif = sc->beacon.bslot[slot];
+
+               ath_dbg(common, ATH_DBG_BEACON,
+                       "slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
+                       slot, tsf, tsftu / ATH_BCBUF, intval, vif);
+       } else {
+               slot = 0;
+               vif = sc->beacon.bslot[slot];
+       }
 
-       ath_dbg(common, ATH_DBG_BEACON,
-               "slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
-               slot, tsf, tsftu / ATH_BCBUF, intval, vif);
 
        bfaddr = 0;
        if (vif) {
@@ -636,6 +654,8 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
        struct ath_common *common = ath9k_hw_common(ah);
        u32 tsf, delta, intval, nexttbtt;
 
+       ath9k_reset_beacon_status(sc);
+
        tsf = ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE);
        intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD);
 
@@ -646,7 +666,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
                        delta = (tsf - sc->beacon.bc_tstamp);
                else
                        delta = (tsf + 1 + (~0U - sc->beacon.bc_tstamp));
-               nexttbtt = tsf + roundup(delta, intval);
+               nexttbtt = tsf + intval - (delta % intval);
        }
 
        ath_dbg(common, ATH_DBG_BEACON,
index 23f15a7ca7f128a364ddc32d4ed5cee3fa66834d..41ce0b1398868eeab8c954af9b493913d05c5772 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 Atheros Communications Inc.
+ * Copyright (c) 2009-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index a9efca83d676dc08de3ca884004a886e5ec9824b..234f77689b144715d51372d6da5e1f038b37e78a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 Atheros Communications Inc.
+ * Copyright (c) 2009-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 558b228a717fe06c35ac66a4e78962a23be97473..a1250c586e40884989a853845e1c68230434f6c2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 4420780fa3b86d2a7fbbfb173e0f2fefc7026e05..1bef41d1b1ffb250d38f490a395d6c79e033b019 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 74535e6dfb82a024538caf059c6545f701ba3606..fa6bd2d189e573516e2ab7cac919ab3109dbe52f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 Atheros Communications Inc.
+ * Copyright (c) 2009-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 5124f1420b3ae404cbcc80dfdf7732c3c0a06d91..77ec288b5a70557efc233e53c03b31b95d822bb4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 Atheros Communications Inc.
+ * Copyright (c) 2009-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index bad1a87249b6011898027cce7300cea8358dbc49..d55ffd7d4bd28565df7d93b5e1ed65c010b99ba5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -435,6 +435,7 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
                        conf->channel_type,
                        channel_type_str(conf->channel_type));
 
+       ath9k_ps_wakeup(sc);
        put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr);
        put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
        len += snprintf(buf + len, sizeof(buf) - len,
@@ -444,6 +445,7 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
        len += snprintf(buf + len, sizeof(buf) - len,
                        "addrmask: %pM\n", addr);
        tmp = ath9k_hw_getrxfilter(sc->sc_ah);
+       ath9k_ps_restore(sc);
        len += snprintf(buf + len, sizeof(buf) - len,
                        "rfilt: 0x%x", tmp);
        if (tmp & ATH9K_RX_FILTER_UCAST)
@@ -725,6 +727,7 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
                break;
        }
 
+       ath9k_ps_wakeup(sc);
        len += snprintf(buf + len, size - len,
                        "curbssid: %pM\n"
                        "OP-Mode: %s(%i)\n"
@@ -734,6 +737,7 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
                        REG_READ(ah, AR_BEACON_PERIOD));
 
        reg = REG_READ(ah, AR_TIMER_MODE);
+       ath9k_ps_restore(sc);
        len += snprintf(buf + len, size - len, "Timer-Mode-Register: 0x%x (",
                        reg);
        if (reg & AR_TBTT_TIMER_EN)
@@ -1050,7 +1054,9 @@ static ssize_t read_file_regval(struct file *file, char __user *user_buf,
        unsigned int len;
        u32 regval;
 
+       ath9k_ps_wakeup(sc);
        regval = REG_READ_D(ah, sc->debug.regidx);
+       ath9k_ps_restore(sc);
        len = sprintf(buf, "0x%08x\n", regval);
        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
@@ -1072,7 +1078,9 @@ static ssize_t write_file_regval(struct file *file, const char __user *user_buf,
        if (strict_strtoul(buf, 0, &regval))
                return -EINVAL;
 
+       ath9k_ps_wakeup(sc);
        REG_WRITE_D(ah, sc->debug.regidx, regval);
+       ath9k_ps_restore(sc);
        return count;
 }
 
index 5488a324cc100b142ed1871a9ce493f18b893543..8ce6ad80f4e208461469ecbb7b90172ae460a044 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 8c18bed3a55890e3fbc9195bc37802aaab2a9015..e61404dda8c59b36be9766dada75b3c16ae3560e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 3e316133f114c9b6765b9002d168e157fbccdaba..de99c0da52e4e33c412086f346673d1d49211015 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 6f714dd723653032c0622b8821852749b4254f38..5b1e894f3d679aa7d43fe52707d731e7aaec6032 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index b87db4763098bad950f78824102d2626b598aa38..343fc9f946dbc7dcb6b613cad3cff3b2bb12e84e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -524,10 +524,16 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
        case 1:
                break;
        case 2:
-               scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+               if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN)
+                       scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+               else
+                       scaledPower = 0;
                break;
        case 3:
-               scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+               if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN)
+                       scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+               else
+                       scaledPower = 0;
                break;
        }
        scaledPower = max((u16)0, scaledPower);
index c031854b569fe0a5c3c145724ec3373c802b68e2..17f0a6806207bca7936c4bd6fdbe8271d04e54f3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 0349b3a1cc58c8dcb29729f0237f9d4137e8de46..bc713fc28191b2baf4e1992365902cfbce25fd07 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 2e3a33a53406a85d08c4266d90e33462a1a8208b..260f1f37a60e486446394f71043c9ce5c0255dec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 2bdcdbc14b1ea899c687170522e6c3ced11475e2..794f63094e5d66db28189cc248e106474358497e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,7 @@
 #define HTC_USB_H
 
 #define MAJOR_VERSION_REQ 1
-#define MINOR_VERSION_REQ 2
+#define MINOR_VERSION_REQ 3
 
 #define IS_AR7010_DEVICE(_v) (((_v) == AR9280_USB) || ((_v) == AR9287_USB))
 
index dfc7a982fc7eb265e263e524926603ba631574fc..5bc022087e651e8be0a8097ca17af1257c1b4f45 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -46,15 +46,8 @@ extern struct ieee80211_ops ath9k_htc_ops;
 extern int htc_modparam_nohwcrypt;
 
 enum htc_phymode {
-       HTC_MODE_AUTO           = 0,
-       HTC_MODE_11A            = 1,
-       HTC_MODE_11B            = 2,
-       HTC_MODE_11G            = 3,
-       HTC_MODE_FH             = 4,
-       HTC_MODE_TURBO_A        = 5,
-       HTC_MODE_TURBO_G        = 6,
-       HTC_MODE_11NA           = 7,
-       HTC_MODE_11NG           = 8
+       HTC_MODE_11NA           = 0,
+       HTC_MODE_11NG           = 1
 };
 
 enum htc_opmode {
@@ -123,18 +116,13 @@ struct ath9k_htc_target_vif {
        u8 pad;
 } __packed;
 
-#define ATH_HTC_STA_AUTH  0x0001
-#define ATH_HTC_STA_QOS   0x0002
-#define ATH_HTC_STA_ERP   0x0004
-#define ATH_HTC_STA_HT    0x0008
-
 struct ath9k_htc_target_sta {
        u8 macaddr[ETH_ALEN];
        u8 bssid[ETH_ALEN];
        u8 sta_index;
        u8 vif_index;
        u8 is_vif_sta;
-       __be16 flags; /* ATH_HTC_STA_* */
+       __be16 flags;
        __be16 htcap;
        __be16 maxampdu;
        u8 pad;
@@ -285,9 +273,9 @@ struct ath9k_htc_rx {
 };
 
 #define ATH9K_HTC_TX_CLEANUP_INTERVAL 50 /* ms */
-#define ATH9K_HTC_TX_TIMEOUT_INTERVAL 2500 /* ms */
+#define ATH9K_HTC_TX_TIMEOUT_INTERVAL 3000 /* ms */
 #define ATH9K_HTC_TX_RESERVE 10
-#define ATH9K_HTC_TX_TIMEOUT_COUNT 20
+#define ATH9K_HTC_TX_TIMEOUT_COUNT 40
 #define ATH9K_HTC_TX_THRESHOLD (MAX_TX_BUF_NUM - ATH9K_HTC_TX_RESERVE)
 
 #define ATH9K_HTC_OP_TX_QUEUES_STOP BIT(0)
@@ -450,6 +438,7 @@ struct ath9k_htc_priv {
        u8 vif_sta_pos[ATH9K_HTC_MAX_VIF];
        u8 num_ibss_vif;
        u8 num_sta_vif;
+       u8 num_sta_assoc_vif;
        u8 num_ap_vif;
 
        u16 op_flags;
index 0ded2c66d5ffdd13fe38607794cf65b291d90f32..aa6a73118706753d6d70ac608f8473f7c218c780 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index af57fe5aab98848f52bcd129184181a84c773033..db2352e5cc0d5e660d005ac09204e7c0cc46e8c3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index bfdc8a8871830b5ccb63aa848d69d8121d3745b0..61e6d39507182feda2bc6d02351803f7c5a51e2a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -258,7 +258,7 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid,
         */
 
        if (IS_AR7010_DEVICE(drv_info))
-               priv->htc->credits = 48;
+               priv->htc->credits = 45;
        else
                priv->htc->credits = 33;
 
@@ -769,11 +769,6 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
        hw->channel_change_time = 5000;
        hw->max_listen_interval = 10;
 
-       if (AR_SREV_9271(priv->ah))
-               hw->max_tx_aggregation_subframes = MAX_TX_AMPDU_SUBFRAMES_9271;
-       else
-               hw->max_tx_aggregation_subframes = MAX_TX_AMPDU_SUBFRAMES_7010;
-
        hw->vif_data_size = sizeof(struct ath9k_htc_vif);
        hw->sta_data_size = sizeof(struct ath9k_htc_sta);
 
index 5aa104fe7eebf26e44d60eee2efcfc21d5129ed0..7b779689543223cb7c110b64cd9e1fc819a25bf6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -26,7 +26,7 @@ static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv,
 {
        enum htc_phymode mode;
 
-       mode = HTC_MODE_AUTO;
+       mode = -EINVAL;
 
        switch (ichan->chanmode) {
        case CHANNEL_G:
@@ -45,6 +45,8 @@ static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv,
                break;
        }
 
+       WARN_ON(mode < 0);
+
        return mode;
 }
 
@@ -500,9 +502,6 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
                tsta.maxampdu = cpu_to_be16(maxampdu);
        }
 
-       if (sta && sta->ht_cap.ht_supported)
-               tsta.flags = cpu_to_be16(ATH_HTC_STA_HT);
-
        WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
        if (ret) {
                if (sta)
@@ -582,7 +581,7 @@ int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv,
        memset(&tcap, 0, sizeof(struct ath9k_htc_cap_target));
 
        tcap.ampdu_limit = cpu_to_be32(0xffff);
-       tcap.ampdu_subframes = priv->hw->max_tx_aggregation_subframes;
+       tcap.ampdu_subframes = 0xff;
        tcap.enable_coex = enable_coex;
        tcap.tx_chainmask = priv->ah->caps.tx_chainmask;
 
@@ -1165,6 +1164,8 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
 
        ath9k_htc_set_opmode(priv);
 
+       ath9k_htc_set_bssid_mask(priv, vif);
+
        /*
         * Stop ANI only if there are no associated station interfaces.
         */
@@ -1435,6 +1436,37 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw,
        return ret;
 }
 
+static void ath9k_htc_set_bssid(struct ath9k_htc_priv *priv)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+
+       ath9k_hw_write_associd(priv->ah);
+       ath_dbg(common, ATH_DBG_CONFIG,
+               "BSSID: %pM aid: 0x%x\n",
+               common->curbssid, common->curaid);
+}
+
+static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+{
+       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+
+       if ((vif->type == NL80211_IFTYPE_STATION) && bss_conf->assoc) {
+               common->curaid = bss_conf->aid;
+               memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
+       }
+}
+
+static void ath9k_htc_choose_set_bssid(struct ath9k_htc_priv *priv)
+{
+       if (priv->num_sta_assoc_vif == 1) {
+               ieee80211_iterate_active_interfaces_atomic(priv->hw,
+                                                          ath9k_htc_bss_iter, priv);
+               ath9k_htc_set_bssid(priv);
+       }
+}
+
 static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
                                       struct ieee80211_vif *vif,
                                       struct ieee80211_bss_conf *bss_conf,
@@ -1443,43 +1475,32 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
        struct ath9k_htc_priv *priv = hw->priv;
        struct ath_hw *ah = priv->ah;
        struct ath_common *common = ath9k_hw_common(ah);
-       bool set_assoc;
 
        mutex_lock(&priv->mutex);
        ath9k_htc_ps_wakeup(priv);
 
-       /*
-        * Set the HW AID/BSSID only for the first station interface
-        * or in IBSS mode.
-        */
-       set_assoc = !!((priv->ah->opmode == NL80211_IFTYPE_ADHOC) ||
-                      ((priv->ah->opmode == NL80211_IFTYPE_STATION) &&
-                       (priv->num_sta_vif == 1)));
-
-
        if (changed & BSS_CHANGED_ASSOC) {
-               if (set_assoc) {
-                       ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
-                               bss_conf->assoc);
+               ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
+                       bss_conf->assoc);
 
-                       common->curaid = bss_conf->assoc ?
-                               bss_conf->aid : 0;
+               bss_conf->assoc ?
+                       priv->num_sta_assoc_vif++ : priv->num_sta_assoc_vif--;
 
-                       if (bss_conf->assoc)
+               if (priv->ah->opmode == NL80211_IFTYPE_STATION) {
+                       if (bss_conf->assoc && (priv->num_sta_assoc_vif == 1))
                                ath9k_htc_start_ani(priv);
-                       else
+                       else if (priv->num_sta_assoc_vif == 0)
                                ath9k_htc_stop_ani(priv);
                }
        }
 
        if (changed & BSS_CHANGED_BSSID) {
-               if (set_assoc) {
+               if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) {
+                       common->curaid = bss_conf->aid;
                        memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
-                       ath9k_hw_write_associd(ah);
-
-                       ath_dbg(common, ATH_DBG_CONFIG,
-                               "BSSID: %pM aid: 0x%x\n",
-                               common->curbssid, common->curaid);
+                       ath9k_htc_set_bssid(priv);
+               } else if (priv->ah->opmode == NL80211_IFTYPE_STATION) {
+                       ath9k_htc_choose_set_bssid(priv);
                }
        }
 
index a898dac22337e559cf46b7f53d2743f2a1341904..2d81c700e201cd4fa3b87cb1414a0b820785c7fc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -875,6 +875,7 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
                rfilt |= ATH9K_RX_FILTER_CONTROL;
 
        if ((ah->opmode == NL80211_IFTYPE_STATION) &&
+           (priv->nvifs <= 1) &&
            !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC))
                rfilt |= ATH9K_RX_FILTER_MYBEACON;
        else
@@ -888,6 +889,9 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
        if (priv->rxfilter & FIF_PSPOLL)
                rfilt |= ATH9K_RX_FILTER_PSPOLL;
 
+       if (priv->nvifs > 1)
+               rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
+
        return rfilt;
 
 #undef RX_FILTER_PRESERVE
index cee970fdf65256c5124d358b674b977d9201c9b5..1b90ed8795c345a087d59a88a4715a873c3ebf90 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 91a5305db95a317eced836e417c9e601de8abdf8..e1ffbb6bd636049686b3181705b236862004d29f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 8b8f0445aef817fc2395bdb5c33a90847cc3e415..2f3e07263fcbaae598b5be8b6c77760e3c566358 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index b75b5dca4e2905dfc020846d1939a01ff47f3d57..1be7c8bbef842f5cef15e10f60e47eb46d7d9aa7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -1555,9 +1555,12 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (ah->btcoex_hw.enabled)
                ath9k_hw_btcoex_enable(ah);
 
-       if (AR_SREV_9300_20_OR_LATER(ah))
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
                ar9003_hw_bb_watchdog_config(ah);
 
+               ar9003_hw_disable_phy_restart(ah);
+       }
+
        ath9k_hw_apply_gpio_override(ah);
 
        return 0;
index 7af2773d2bfc38766ec77480aace1f205cb045d2..4b157c53d1a8da11ec217a498c5bdf94b12d3e93 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -842,6 +842,7 @@ struct ath_hw {
 
        u32 bb_watchdog_last_status;
        u32 bb_watchdog_timeout_ms; /* in ms, 0 to disable */
+       u8 bb_hang_rx_ofdm; /* true if bb hang due to rx_ofdm */
 
        unsigned int paprd_target_power;
        unsigned int paprd_training_power;
@@ -990,6 +991,7 @@ void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah);
 void ar9003_hw_bb_watchdog_config(struct ath_hw *ah);
 void ar9003_hw_bb_watchdog_read(struct ath_hw *ah);
 void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah);
+void ar9003_hw_disable_phy_restart(struct ath_hw *ah);
 void ar9003_paprd_enable(struct ath_hw *ah, bool val);
 void ar9003_paprd_populate_single_table(struct ath_hw *ah,
                                        struct ath9k_hw_cal_data *caldata,
index b172d1509515e97881eb9a14945df7cb1830a207..45c585a337e9885b336f1ae50731170f6f63344c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index bd6d2b9d736fbb7b2649bdc3311971f5c9f1a8e0..c2091f1f409616cf6a3d131a19b2f3c2dd341980 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index b60c130917f7e959a356381757c852934c2ada17..8e848c4d16baf536834231633795e3c1c9382abe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 17ebdf1e8b7bc567c20644eb150eec9058012a72..2ca351fe6d3c0b056d4ecb8be14388aac195e85b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -670,7 +670,8 @@ void ath9k_tasklet(unsigned long data)
        u32 status = sc->intrstatus;
        u32 rxmask;
 
-       if (status & ATH9K_INT_FATAL) {
+       if ((status & ATH9K_INT_FATAL) ||
+           (status & ATH9K_INT_BB_WATCHDOG)) {
                ath_reset(sc, true);
                return;
        }
@@ -737,6 +738,7 @@ irqreturn_t ath_isr(int irq, void *dev)
 {
 #define SCHED_INTR (                           \
                ATH9K_INT_FATAL |               \
+               ATH9K_INT_BB_WATCHDOG |         \
                ATH9K_INT_RXORN |               \
                ATH9K_INT_RXEOL |               \
                ATH9K_INT_RX |                  \
@@ -2332,6 +2334,45 @@ static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
        return false;
 }
 
+int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
+{
+       struct ath_softc *sc = hw->priv;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ieee80211_vif *vif;
+       struct ath_vif *avp;
+       struct ath_buf *bf;
+       struct ath_tx_status ts;
+       int status;
+
+       vif = sc->beacon.bslot[0];
+       if (!vif)
+               return 0;
+
+       avp = (void *)vif->drv_priv;
+       if (!avp->is_bslot_active)
+               return 0;
+
+       if (!sc->beacon.tx_processed) {
+               tasklet_disable(&sc->bcon_tasklet);
+
+               bf = avp->av_bcbuf;
+               if (!bf || !bf->bf_mpdu)
+                       goto skip;
+
+               status = ath9k_hw_txprocdesc(ah, bf->bf_desc, &ts);
+               if (status == -EINPROGRESS)
+                       goto skip;
+
+               sc->beacon.tx_processed = true;
+               sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
+
+skip:
+               tasklet_enable(&sc->bcon_tasklet);
+       }
+
+       return sc->beacon.tx_last;
+}
+
 struct ieee80211_ops ath9k_ops = {
        .tx                 = ath9k_tx,
        .start              = ath9k_start,
@@ -2356,4 +2397,5 @@ struct ieee80211_ops ath9k_ops = {
        .set_coverage_class = ath9k_set_coverage_class,
        .flush              = ath9k_flush,
        .tx_frames_pending  = ath9k_tx_frames_pending,
+       .tx_last_beacon = ath9k_tx_last_beacon,
 };
index 9c65459be100585e243bb3a3e65c23dab0c6d556..b8cbfc7072137064f443ad0f137b9ccba99c85f4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 9441bf8ca2fd6cf003331d04898e96551a184d6f..8b380305b0fc1acf8c2593acd474daa52f7eb6c9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 4ccbf2ddb5535c27c0699418f723b9314c5e7191..ba7f36ab0a74231eb82731e9292ffcd737601852 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2004 Video54 Technologies, Inc.
- * Copyright (c) 2004-2009 Atheros Communications, Inc.
+ * Copyright (c) 2004-2011 Atheros Communications, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -689,7 +689,8 @@ static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table,
 
        if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) {
                rate->flags |= IEEE80211_TX_RC_MCS;
-               if (WLAN_RC_PHY_40(rate_table->info[rix].phy))
+               if (WLAN_RC_PHY_40(rate_table->info[rix].phy) &&
+                   conf_is_ht40(&txrc->hw->conf))
                        rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
                if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy))
                        rate->flags |= IEEE80211_TX_RC_SHORT_GI;
index 5d984b8acdb12540fc531a74186d6b7021f2759c..c3d850207bee0375c9f806cc37fea898e1985bd1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2004 Sam Leffler, Errno Consulting
  * Copyright (c) 2004 Video54 Technologies, Inc.
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 4f52e0429f996718ad1630a597541f803f256079..07e35e59c9e31fa8d9dbb1c6b086c4027e13e2c6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 456f3ec20fef94235ccb724c66419b6a7012d260..c18ee9921fb19ef9000122c21d1da887c5731094 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index f9b1eb4853c4a93a1f964e239a41349e5e7fa0cf..35422fc1f2ce1a566ce11cb0a0d740880531badd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 6095eeb6e025fdd08f971da826e0a5680b3a2f98..fde6da619f30f96e146c00b017e5f37a9df0e80d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 97dd1fac98b6390591a3baa89f0943e9e50eb92c..3779b8977d4709a9ce68d85a8b2458d472deaea4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index bb578690935e7f88327bcedf94231219d27cc973..4da01a9f5680feef4726f9a9fbff56914b396045 100644 (file)
@@ -286,6 +286,10 @@ struct ar9170 {
                unsigned int tx_seq_table;
        } fw;
 
+       /* interface configuration combinations */
+       struct ieee80211_iface_limit if_comb_limits[1];
+       struct ieee80211_iface_combination if_combs[1];
+
        /* reset / stuck frames/queue detection */
        struct work_struct restart_work;
        struct work_struct ping_work;
index 9517ede9e2dfdbb104042c3f520e9cb36a18c778..221957c5d37370830eef6c74ae3aacddcbb62f89 100644 (file)
@@ -151,6 +151,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
        const struct carl9170fw_chk_desc *chk_desc;
        const struct carl9170fw_last_desc *last_desc;
        const struct carl9170fw_txsq_desc *txsq_desc;
+       u16 if_comb_types;
 
        last_desc = carl9170_fw_find_desc(ar, LAST_MAGIC,
                sizeof(*last_desc), CARL9170FW_LAST_DESC_CUR_VER);
@@ -268,6 +269,9 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
        if (SUPP(CARL9170FW_WOL))
                device_set_wakeup_enable(&ar->udev->dev, true);
 
+       if_comb_types = BIT(NL80211_IFTYPE_STATION) |
+                       BIT(NL80211_IFTYPE_P2P_CLIENT);
+
        ar->fw.vif_num = otus_desc->vif_num;
        ar->fw.cmd_bufs = otus_desc->cmd_bufs;
        ar->fw.address = le32_to_cpu(otus_desc->fw_address);
@@ -294,12 +298,25 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
                ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
 
                if (SUPP(CARL9170FW_WLANTX_CAB)) {
-                       ar->hw->wiphy->interface_modes |=
+                       if_comb_types |=
                                BIT(NL80211_IFTYPE_AP) |
                                BIT(NL80211_IFTYPE_P2P_GO);
                }
        }
 
+       ar->if_comb_limits[0].max = ar->fw.vif_num;
+       ar->if_comb_limits[0].types = if_comb_types;
+
+       ar->if_combs[0].num_different_channels = 1;
+       ar->if_combs[0].max_interfaces = ar->fw.vif_num;
+       ar->if_combs[0].limits = ar->if_comb_limits;
+       ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits);
+
+       ar->hw->wiphy->iface_combinations = ar->if_combs;
+       ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs);
+
+       ar->hw->wiphy->interface_modes |= if_comb_types;
+
        txsq_desc = carl9170_fw_find_desc(ar, TXSQ_MAGIC,
                sizeof(*txsq_desc), CARL9170FW_TXSQ_DESC_CUR_VER);
 
index 7d5c65ea94e6213723ecb7a98f8222d6fa727daf..54d093c2ab44f956b5988d73ae819ed9b398a58b 100644 (file)
@@ -1570,14 +1570,8 @@ void *carl9170_alloc(size_t priv_size)
        INIT_LIST_HEAD(&ar->vif_list);
        init_completion(&ar->tx_flush);
 
-       /*
-        * Note:
-        * IBSS/ADHOC and AP mode are only enabled, if the firmware
-        * supports these modes. The code which will add the
-        * additional interface_modes is in fw.c.
-        */
-       hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
-                                    BIT(NL80211_IFTYPE_P2P_CLIENT);
+       /* firmware decides which modes we support */
+       hw->wiphy->interface_modes = 0;
 
        hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS |
                     IEEE80211_HW_REPORTS_TX_ACK_STATUS |
index cc11d66f15bcc69fd02110ae5eb87b02f5f3948d..3f508e59f146b412246f34becab5862117bfd765 100644 (file)
@@ -43,7 +43,7 @@
  * set of  ~ ( MAC XOR BSSID ) for all bssids we handle.
  *
  * When you do this you are essentially computing the common bits of all your
- * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with
+ * BSSes. Later it is assumed the hardware will "and" (&) the BSSID mask with
  * the MAC address to obtain the relevant bits and compare the result with
  * (frame's BSSID & mask) to see if they match.
  *
@@ -71,8 +71,8 @@
  *             On loop iteration for BSSID-02:
  *             bssid_mask &= ~(0001   ^   1001)
  *             bssid_mask =   (1010)  & ~(0001 ^ 1001)
- *             bssid_mask =   (1010)  & ~(1001)
- *             bssid_mask =   (1010)  &  (0110)
+ *             bssid_mask =   (1010)  & ~(1000)
+ *             bssid_mask =   (1010)  &  (0111)
  *             bssid_mask =   0010
  *
  * A bssid_mask of 0010 means "only pay attention to the second least
  *
  * IFRAME-02:  0001 (we should allow)
  *
- *     allow = (0001 & 1010) == 1010
- *
  *     allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
  *  --> allow = (0001 & 0010) ==  (0010 & 0001) ? 1 :0;
- *  --> allow = (0010) == (0010)
+ *  --> allow = (0000) == (0000)
  *  --> allow = 1
  *
  * Other examples:
index 05263516c113f50cfcbff36e3ec94998832f203a..ec295c4f677d583876a92351638b0e15c31578a7 100644 (file)
@@ -122,7 +122,7 @@ static int atmel_config(struct pcmcia_device *link)
 {
        local_info_t *dev;
        int ret;
-       struct pcmcia_device_id *did;
+       const struct pcmcia_device_id *did;
 
        dev = link->priv;
        did = dev_get_drvdata(&link->dev);
@@ -211,7 +211,7 @@ static int atmel_resume(struct pcmcia_device *link)
        .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
         .driver_info = (kernel_ulong_t)(info), }
 
-static struct pcmcia_device_id atmel_ids[] = {
+static const struct pcmcia_device_id atmel_ids[] = {
        PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0620, ATMEL_FW_TYPE_502_3COM),
        PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0696, ATMEL_FW_TYPE_502_3COM),
        PCMCIA_DEVICE_MANF_CARD_INFO(0x01bf, 0x3302, ATMEL_FW_TYPE_502E),
index ebc93c1bb5e7819b4a275a0c6b1d2de8300312bb..25a78cfb7d15ebb7119264e2ea05e6afb188f7eb 100644 (file)
@@ -567,6 +567,8 @@ struct b43_dma {
        struct b43_dmaring *tx_ring_mcast; /* Multicast */
 
        struct b43_dmaring *rx_ring;
+
+       u32 translation; /* Routing bits */
 };
 
 struct b43_pio_txqueue;
@@ -705,7 +707,7 @@ enum {
 
 /* Data structure for one wireless device (802.11 core) */
 struct b43_wldev {
-       struct ssb_device *dev;
+       struct ssb_device *sdev;
        struct b43_wl *wl;
 
        /* The device initialization status.
@@ -879,22 +881,34 @@ static inline enum ieee80211_band b43_current_band(struct b43_wl *wl)
 
 static inline u16 b43_read16(struct b43_wldev *dev, u16 offset)
 {
-       return ssb_read16(dev->dev, offset);
+       return ssb_read16(dev->sdev, offset);
 }
 
 static inline void b43_write16(struct b43_wldev *dev, u16 offset, u16 value)
 {
-       ssb_write16(dev->dev, offset, value);
+       ssb_write16(dev->sdev, offset, value);
 }
 
 static inline u32 b43_read32(struct b43_wldev *dev, u16 offset)
 {
-       return ssb_read32(dev->dev, offset);
+       return ssb_read32(dev->sdev, offset);
 }
 
 static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value)
 {
-       ssb_write32(dev->dev, offset, value);
+       ssb_write32(dev->sdev, offset, value);
+}
+
+static inline void b43_block_read(struct b43_wldev *dev, void *buffer,
+                                size_t count, u16 offset, u8 reg_width)
+{
+       ssb_block_read(dev->sdev, buffer, count, offset, reg_width);
+}
+
+static inline void b43_block_write(struct b43_wldev *dev, const void *buffer,
+                                  size_t count, u16 offset, u8 reg_width)
+{
+       ssb_block_write(dev->sdev, buffer, count, offset, reg_width);
 }
 
 static inline bool b43_using_pio_transfers(struct b43_wldev *dev)
index ff0f5ba14b2cfb60223a19455772fddca719951b..47d44bcff37dccb73705e4a2575470010650f83b 100644 (file)
@@ -80,7 +80,7 @@ static void op32_fill_descriptor(struct b43_dmaring *ring,
        addr = (u32) (dmaaddr & ~SSB_DMA_TRANSLATION_MASK);
        addrext = (u32) (dmaaddr & SSB_DMA_TRANSLATION_MASK)
            >> SSB_DMA_TRANSLATION_SHIFT;
-       addr |= ssb_dma_translation(ring->dev->dev);
+       addr |= ring->dev->dma.translation;
        ctl = bufsize & B43_DMA32_DCTL_BYTECNT;
        if (slot == ring->nr_slots - 1)
                ctl |= B43_DMA32_DCTL_DTABLEEND;
@@ -174,7 +174,7 @@ static void op64_fill_descriptor(struct b43_dmaring *ring,
        addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
        addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
            >> SSB_DMA_TRANSLATION_SHIFT;
-       addrhi |= (ssb_dma_translation(ring->dev->dev) << 1);
+       addrhi |= (ring->dev->dma.translation << 1);
        if (slot == ring->nr_slots - 1)
                ctl0 |= B43_DMA64_DCTL0_DTABLEEND;
        if (start)
@@ -333,10 +333,10 @@ static inline
        dma_addr_t dmaaddr;
 
        if (tx) {
-               dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
+               dmaaddr = dma_map_single(ring->dev->sdev->dma_dev,
                                         buf, len, DMA_TO_DEVICE);
        } else {
-               dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
+               dmaaddr = dma_map_single(ring->dev->sdev->dma_dev,
                                         buf, len, DMA_FROM_DEVICE);
        }
 
@@ -348,10 +348,10 @@ static inline
                          dma_addr_t addr, size_t len, int tx)
 {
        if (tx) {
-               dma_unmap_single(ring->dev->dev->dma_dev,
+               dma_unmap_single(ring->dev->sdev->dma_dev,
                                 addr, len, DMA_TO_DEVICE);
        } else {
-               dma_unmap_single(ring->dev->dev->dma_dev,
+               dma_unmap_single(ring->dev->sdev->dma_dev,
                                 addr, len, DMA_FROM_DEVICE);
        }
 }
@@ -361,7 +361,7 @@ static inline
                                 dma_addr_t addr, size_t len)
 {
        B43_WARN_ON(ring->tx);
-       dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
+       dma_sync_single_for_cpu(ring->dev->sdev->dma_dev,
                                    addr, len, DMA_FROM_DEVICE);
 }
 
@@ -370,7 +370,7 @@ static inline
                                    dma_addr_t addr, size_t len)
 {
        B43_WARN_ON(ring->tx);
-       dma_sync_single_for_device(ring->dev->dev->dma_dev,
+       dma_sync_single_for_device(ring->dev->sdev->dma_dev,
                                   addr, len, DMA_FROM_DEVICE);
 }
 
@@ -401,7 +401,7 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
         */
        if (ring->type == B43_DMA_64BIT)
                flags |= GFP_DMA;
-       ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev,
+       ring->descbase = dma_alloc_coherent(ring->dev->sdev->dma_dev,
                                            B43_DMA_RINGMEMSIZE,
                                            &(ring->dmabase), flags);
        if (!ring->descbase) {
@@ -415,7 +415,7 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
 
 static void free_ringmemory(struct b43_dmaring *ring)
 {
-       dma_free_coherent(ring->dev->dev->dma_dev, B43_DMA_RINGMEMSIZE,
+       dma_free_coherent(ring->dev->sdev->dma_dev, B43_DMA_RINGMEMSIZE,
                          ring->descbase, ring->dmabase);
 }
 
@@ -523,7 +523,7 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
                                  dma_addr_t addr,
                                  size_t buffersize, bool dma_to_device)
 {
-       if (unlikely(dma_mapping_error(ring->dev->dev->dma_dev, addr)))
+       if (unlikely(dma_mapping_error(ring->dev->sdev->dma_dev, addr)))
                return 1;
 
        switch (ring->type) {
@@ -658,7 +658,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
        int err = 0;
        u32 value;
        u32 addrext;
-       u32 trans = ssb_dma_translation(ring->dev->dev);
+       u32 trans = ring->dev->dma.translation;
 
        if (ring->tx) {
                if (ring->type == B43_DMA_64BIT) {
@@ -869,7 +869,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                        goto err_kfree_meta;
 
                /* test for ability to dma to txhdr_cache */
-               dma_test = dma_map_single(dev->dev->dma_dev,
+               dma_test = dma_map_single(dev->sdev->dma_dev,
                                          ring->txhdr_cache,
                                          b43_txhdr_size(dev),
                                          DMA_TO_DEVICE);
@@ -884,7 +884,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                        if (!ring->txhdr_cache)
                                goto err_kfree_meta;
 
-                       dma_test = dma_map_single(dev->dev->dma_dev,
+                       dma_test = dma_map_single(dev->sdev->dma_dev,
                                                  ring->txhdr_cache,
                                                  b43_txhdr_size(dev),
                                                  DMA_TO_DEVICE);
@@ -898,7 +898,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                        }
                }
 
-               dma_unmap_single(dev->dev->dma_dev,
+               dma_unmap_single(dev->sdev->dma_dev,
                                 dma_test, b43_txhdr_size(dev),
                                 DMA_TO_DEVICE);
        }
@@ -1013,9 +1013,9 @@ static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask)
        /* Try to set the DMA mask. If it fails, try falling back to a
         * lower mask, as we can always also support a lower one. */
        while (1) {
-               err = dma_set_mask(dev->dev->dma_dev, mask);
+               err = dma_set_mask(dev->sdev->dma_dev, mask);
                if (!err) {
-                       err = dma_set_coherent_mask(dev->dev->dma_dev, mask);
+                       err = dma_set_coherent_mask(dev->sdev->dma_dev, mask);
                        if (!err)
                                break;
                }
@@ -1055,6 +1055,7 @@ int b43_dma_init(struct b43_wldev *dev)
        err = b43_dma_set_mask(dev, dmamask);
        if (err)
                return err;
+       dma->translation = ssb_dma_translation(dev->sdev);
 
        err = -ENOMEM;
        /* setup TX DMA channels. */
@@ -1084,7 +1085,7 @@ int b43_dma_init(struct b43_wldev *dev)
                goto err_destroy_mcast;
 
        /* No support for the TX status DMA ring. */
-       B43_WARN_ON(dev->dev->id.revision < 5);
+       B43_WARN_ON(dev->sdev->id.revision < 5);
 
        b43dbg(dev->wl, "%u-bit DMA initialized\n",
               (unsigned int)type);
index c587115dd2b9685175e7449ebb0cd118d870488a..0cafafe368af0467f16fd7eb4072010466ce0184 100644 (file)
@@ -138,7 +138,7 @@ static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
        led->led_dev.default_trigger = default_trigger;
        led->led_dev.brightness_set = b43_led_brightness_set;
 
-       err = led_classdev_register(dev->dev->dev, &led->led_dev);
+       err = led_classdev_register(dev->sdev->dev, &led->led_dev);
        if (err) {
                b43warn(dev->wl, "LEDs: Failed to register %s\n", name);
                led->wl = NULL;
@@ -215,7 +215,7 @@ static void b43_led_get_sprominfo(struct b43_wldev *dev,
                                  enum b43_led_behaviour *behaviour,
                                  bool *activelow)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        u8 sprom[4];
 
        sprom[0] = bus->sprom.gpio0;
index 94e4f1378fc3c5660bd42b008c3e6384768d798d..2ef7d4b3854021fbfcec018225c309efa3d39daa 100644 (file)
@@ -98,7 +98,7 @@ static u16 lo_measure_feedthrough(struct b43_wldev *dev,
                rfover |= pga;
                rfover |= lna;
                rfover |= trsw_rx;
-               if ((dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA)
+               if ((dev->sdev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA)
                    && phy->rev > 6)
                        rfover |= B43_PHY_RFOVERVAL_EXTLNA;
 
@@ -387,7 +387,7 @@ struct lo_g_saved_values {
 static void lo_measure_setup(struct b43_wldev *dev,
                             struct lo_g_saved_values *sav)
 {
-       struct ssb_sprom *sprom = &dev->dev->bus->sprom;
+       struct ssb_sprom *sprom = &dev->sdev->bus->sprom;
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_g *gphy = phy->g;
        struct b43_txpower_lo_control *lo = gphy->lo_control;
index 5a43984bdcea8e2f63294d3dbdd5690cf83caa5e..eb415968698502c597d866ff5a6e3b4f8e36b761 100644 (file)
@@ -548,7 +548,7 @@ void b43_tsf_read(struct b43_wldev *dev, u64 *tsf)
 {
        u32 low, high;
 
-       B43_WARN_ON(dev->dev->id.revision < 3);
+       B43_WARN_ON(dev->sdev->id.revision < 3);
 
        /* The hardware guarantees us an atomic read, if we
         * read the low register first. */
@@ -586,7 +586,7 @@ static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf)
 {
        u32 low, high;
 
-       B43_WARN_ON(dev->dev->id.revision < 3);
+       B43_WARN_ON(dev->sdev->id.revision < 3);
 
        low = tsf;
        high = (tsf >> 32);
@@ -714,7 +714,7 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on)
                b43_ram_write(dev, i * 4, buffer[i]);
 
        b43_write16(dev, 0x0568, 0x0000);
-       if (dev->dev->id.revision < 11)
+       if (dev->sdev->id.revision < 11)
                b43_write16(dev, 0x07C0, 0x0000);
        else
                b43_write16(dev, 0x07C0, 0x0100);
@@ -1132,7 +1132,7 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
        b43_write32(dev, B43_MMIO_MACCTL, macctl);
        /* Commit write */
        b43_read32(dev, B43_MMIO_MACCTL);
-       if (awake && dev->dev->id.revision >= 5) {
+       if (awake && dev->sdev->id.revision >= 5) {
                /* Wait for the microcode to wake up. */
                for (i = 0; i < 100; i++) {
                        ucstat = b43_shm_read16(dev, B43_SHM_SHARED,
@@ -1144,29 +1144,35 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
        }
 }
 
-void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
+static void b43_ssb_wireless_core_reset(struct b43_wldev *dev, u32 flags)
 {
        u32 tmslow;
-       u32 macctl;
 
        flags |= B43_TMSLOW_PHYCLKEN;
        flags |= B43_TMSLOW_PHYRESET;
        if (dev->phy.type == B43_PHYTYPE_N)
                flags |= B43_TMSLOW_PHY_BANDWIDTH_20MHZ; /* Make 20 MHz def */
-       ssb_device_enable(dev->dev, flags);
+       ssb_device_enable(dev->sdev, flags);
        msleep(2);              /* Wait for the PLL to turn on. */
 
        /* Now take the PHY out of Reset again */
-       tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+       tmslow = ssb_read32(dev->sdev, SSB_TMSLOW);
        tmslow |= SSB_TMSLOW_FGC;
        tmslow &= ~B43_TMSLOW_PHYRESET;
-       ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
-       ssb_read32(dev->dev, SSB_TMSLOW);       /* flush */
+       ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
+       ssb_read32(dev->sdev, SSB_TMSLOW);      /* flush */
        msleep(1);
        tmslow &= ~SSB_TMSLOW_FGC;
-       ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
-       ssb_read32(dev->dev, SSB_TMSLOW);       /* flush */
+       ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
+       ssb_read32(dev->sdev, SSB_TMSLOW);      /* flush */
        msleep(1);
+}
+
+void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
+{
+       u32 macctl;
+
+       b43_ssb_wireless_core_reset(dev, flags);
 
        /* Turn Analog ON, but only if we already know the PHY-type.
         * This protects against very early setup where we don't know the
@@ -1215,7 +1221,7 @@ static void drain_txstatus_queue(struct b43_wldev *dev)
 {
        u32 dummy;
 
-       if (dev->dev->id.revision < 5)
+       if (dev->sdev->id.revision < 5)
                return;
        /* Read all entries from the microcode TXstatus FIFO
         * and throw them away.
@@ -1421,9 +1427,9 @@ u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
 
        /* Get the mask of available antennas. */
        if (dev->phy.gmode)
-               antenna_mask = dev->dev->bus->sprom.ant_available_bg;
+               antenna_mask = dev->sdev->bus->sprom.ant_available_bg;
        else
-               antenna_mask = dev->dev->bus->sprom.ant_available_a;
+               antenna_mask = dev->sdev->bus->sprom.ant_available_a;
 
        if (!(antenna_mask & (1 << (antenna_nr - 1)))) {
                /* This antenna is not available. Fall back to default. */
@@ -1638,7 +1644,7 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
        mutex_lock(&wl->mutex);
        dev = wl->current_dev;
        if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
-               if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
+               if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
                        /* wl->mutex is enough. */
                        b43_do_beacon_update_trigger_work(dev);
                        mmiowb();
@@ -1683,7 +1689,7 @@ static void b43_update_templates(struct b43_wl *wl)
 static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
 {
        b43_time_lock(dev);
-       if (dev->dev->id.revision >= 3) {
+       if (dev->sdev->id.revision >= 3) {
                b43_write32(dev, B43_MMIO_TSF_CFP_REP, (beacon_int << 16));
                b43_write32(dev, B43_MMIO_TSF_CFP_START, (beacon_int << 10));
        } else {
@@ -2057,7 +2063,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
                B43_WARN_ON(1);
                return -ENOSYS;
        }
-       err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev);
+       err = request_firmware(&blob, ctx->fwname, ctx->dev->sdev->dev);
        if (err == -ENOENT) {
                snprintf(ctx->errors[ctx->req_type],
                         sizeof(ctx->errors[ctx->req_type]),
@@ -2107,13 +2113,12 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
 {
        struct b43_wldev *dev = ctx->dev;
        struct b43_firmware *fw = &ctx->dev->fw;
-       const u8 rev = ctx->dev->dev->id.revision;
+       const u8 rev = ctx->dev->sdev->id.revision;
        const char *filename;
        u32 tmshigh;
        int err;
 
        /* Get microcode */
-       tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
        if ((rev >= 5) && (rev <= 10))
                filename = "ucode5";
        else if ((rev >= 11) && (rev <= 12))
@@ -2152,6 +2157,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
        switch (dev->phy.type) {
        case B43_PHYTYPE_A:
                if ((rev >= 5) && (rev <= 10)) {
+                       tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
                        if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
                                filename = "a0g1initvals5";
                        else
@@ -2196,6 +2202,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
        switch (dev->phy.type) {
        case B43_PHYTYPE_A:
                if ((rev >= 5) && (rev <= 10)) {
+                       tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
                        if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
                                filename = "a0g1bsinitvals5";
                        else
@@ -2441,7 +2448,7 @@ static int b43_upload_microcode(struct b43_wldev *dev)
 
        snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "%u.%u",
                        dev->fw.rev, dev->fw.patch);
-       wiphy->hw_version = dev->dev->id.coreid;
+       wiphy->hw_version = dev->sdev->id.coreid;
 
        if (b43_is_old_txhdr_format(dev)) {
                /* We're over the deadline, but we keep support for old fw
@@ -2557,10 +2564,20 @@ out:
 /* Initialize the GPIOs
  * http://bcm-specs.sipsolutions.net/GPIO
  */
+static struct ssb_device *b43_ssb_gpio_dev(struct b43_wldev *dev)
+{
+       struct ssb_bus *bus = dev->sdev->bus;
+
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+       return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev);
+#else
+       return bus->chipco.dev;
+#endif
+}
+
 static int b43_gpio_init(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
-       struct ssb_device *gpiodev, *pcidev = NULL;
+       struct ssb_device *gpiodev;
        u32 mask, set;
 
        b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
@@ -2571,7 +2588,7 @@ static int b43_gpio_init(struct b43_wldev *dev)
 
        mask = 0x0000001F;
        set = 0x0000000F;
-       if (dev->dev->bus->chip_id == 0x4301) {
+       if (dev->sdev->bus->chip_id == 0x4301) {
                mask |= 0x0060;
                set |= 0x0060;
        }
@@ -2582,25 +2599,21 @@ static int b43_gpio_init(struct b43_wldev *dev)
                mask |= 0x0180;
                set |= 0x0180;
        }
-       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) {
+       if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) {
                b43_write16(dev, B43_MMIO_GPIO_MASK,
                            b43_read16(dev, B43_MMIO_GPIO_MASK)
                            | 0x0200);
                mask |= 0x0200;
                set |= 0x0200;
        }
-       if (dev->dev->id.revision >= 2)
+       if (dev->sdev->id.revision >= 2)
                mask |= 0x0010; /* FIXME: This is redundant. */
 
-#ifdef CONFIG_SSB_DRIVER_PCICORE
-       pcidev = bus->pcicore.dev;
-#endif
-       gpiodev = bus->chipco.dev ? : pcidev;
-       if (!gpiodev)
-               return 0;
-       ssb_write32(gpiodev, B43_GPIO_CONTROL,
-                   (ssb_read32(gpiodev, B43_GPIO_CONTROL)
-                    & mask) | set);
+       gpiodev = b43_ssb_gpio_dev(dev);
+       if (gpiodev)
+               ssb_write32(gpiodev, B43_GPIO_CONTROL,
+                           (ssb_read32(gpiodev, B43_GPIO_CONTROL)
+                            & mask) | set);
 
        return 0;
 }
@@ -2608,16 +2621,11 @@ static int b43_gpio_init(struct b43_wldev *dev)
 /* Turn off all GPIO stuff. Call this on module unload, for example. */
 static void b43_gpio_cleanup(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
-       struct ssb_device *gpiodev, *pcidev = NULL;
+       struct ssb_device *gpiodev;
 
-#ifdef CONFIG_SSB_DRIVER_PCICORE
-       pcidev = bus->pcicore.dev;
-#endif
-       gpiodev = bus->chipco.dev ? : pcidev;
-       if (!gpiodev)
-               return;
-       ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
+       gpiodev = b43_ssb_gpio_dev(dev);
+       if (gpiodev)
+               ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
 }
 
 /* http://bcm-specs.sipsolutions.net/EnableMac */
@@ -2689,12 +2697,12 @@ out:
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */
 void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on)
 {
-       u32 tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+       u32 tmslow = ssb_read32(dev->sdev, SSB_TMSLOW);
        if (on)
                tmslow |= B43_TMSLOW_MACPHYCLKEN;
        else
                tmslow &= ~B43_TMSLOW_MACPHYCLKEN;
-       ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+       ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
 }
 
 static void b43_adjust_opmode(struct b43_wldev *dev)
@@ -2733,15 +2741,15 @@ static void b43_adjust_opmode(struct b43_wldev *dev)
        /* Workaround: On old hardware the HW-MAC-address-filter
         * doesn't work properly, so always run promisc in filter
         * it in software. */
-       if (dev->dev->id.revision <= 4)
+       if (dev->sdev->id.revision <= 4)
                ctl |= B43_MACCTL_PROMISC;
 
        b43_write32(dev, B43_MMIO_MACCTL, ctl);
 
        cfp_pretbtt = 2;
        if ((ctl & B43_MACCTL_INFRA) && !(ctl & B43_MACCTL_AP)) {
-               if (dev->dev->bus->chip_id == 0x4306 &&
-                   dev->dev->bus->chip_rev == 3)
+               if (dev->sdev->bus->chip_id == 0x4306 &&
+                   dev->sdev->bus->chip_rev == 3)
                        cfp_pretbtt = 100;
                else
                        cfp_pretbtt = 50;
@@ -2899,7 +2907,7 @@ static int b43_chip_init(struct b43_wldev *dev)
                b43_write16(dev, 0x005E, value16);
        }
        b43_write32(dev, 0x0100, 0x01000000);
-       if (dev->dev->id.revision < 5)
+       if (dev->sdev->id.revision < 5)
                b43_write32(dev, 0x010C, 0x01000000);
 
        b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
@@ -2914,7 +2922,7 @@ static int b43_chip_init(struct b43_wldev *dev)
        /* Initially set the wireless operation mode. */
        b43_adjust_opmode(dev);
 
-       if (dev->dev->id.revision < 3) {
+       if (dev->sdev->id.revision < 3) {
                b43_write16(dev, 0x060E, 0x0000);
                b43_write16(dev, 0x0610, 0x8000);
                b43_write16(dev, 0x0604, 0x0000);
@@ -2934,7 +2942,7 @@ static int b43_chip_init(struct b43_wldev *dev)
        b43_mac_phy_clock_set(dev, true);
 
        b43_write16(dev, B43_MMIO_POWERUP_DELAY,
-                   dev->dev->bus->chipco.fast_pwrup_delay);
+                   dev->sdev->bus->chipco.fast_pwrup_delay);
 
        err = 0;
        b43dbg(dev->wl, "Chip initialized\n");
@@ -3097,7 +3105,7 @@ static int b43_validate_chipaccess(struct b43_wldev *dev)
        b43_shm_write32(dev, B43_SHM_SHARED, 0, backup0);
        b43_shm_write32(dev, B43_SHM_SHARED, 4, backup4);
 
-       if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) {
+       if ((dev->sdev->id.revision >= 3) && (dev->sdev->id.revision <= 10)) {
                /* The 32bit register shadows the two 16bit registers
                 * with update sideeffects. Validate this. */
                b43_write16(dev, B43_MMIO_TSF_CFP_START, 0xAAAA);
@@ -3450,7 +3458,7 @@ static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
 
 static void b43_put_phy_into_reset(struct b43_wldev *dev)
 {
-       struct ssb_device *sdev = dev->dev;
+       struct ssb_device *sdev = dev->sdev;
        u32 tmslow;
 
        tmslow = ssb_read32(sdev, SSB_TMSLOW);
@@ -3946,7 +3954,7 @@ redo:
 
        /* Disable interrupts on the device. */
        b43_set_status(dev, B43_STAT_INITIALIZED);
-       if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
+       if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
                /* wl->mutex is locked. That is enough. */
                b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
                b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
@@ -3959,11 +3967,11 @@ redo:
        /* Synchronize and free the interrupt handlers. Unlock to avoid deadlocks. */
        orig_dev = dev;
        mutex_unlock(&wl->mutex);
-       if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
+       if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
                b43_sdio_free_irq(dev);
        } else {
-               synchronize_irq(dev->dev->irq);
-               free_irq(dev->dev->irq, dev);
+               synchronize_irq(dev->sdev->irq);
+               free_irq(dev->sdev->irq, dev);
        }
        mutex_lock(&wl->mutex);
        dev = wl->current_dev;
@@ -3996,18 +4004,19 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
        B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED);
 
        drain_txstatus_queue(dev);
-       if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
+       if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
                err = b43_sdio_request_irq(dev, b43_sdio_interrupt_handler);
                if (err) {
                        b43err(dev->wl, "Cannot request SDIO IRQ\n");
                        goto out;
                }
        } else {
-               err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler,
+               err = request_threaded_irq(dev->sdev->irq, b43_interrupt_handler,
                                           b43_interrupt_thread_handler,
                                           IRQF_SHARED, KBUILD_MODNAME, dev);
                if (err) {
-                       b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq);
+                       b43err(dev->wl, "Cannot request IRQ-%d\n",
+                              dev->sdev->irq);
                        goto out;
                }
        }
@@ -4087,10 +4096,10 @@ static int b43_phy_versioning(struct b43_wldev *dev)
               analog_type, phy_type, phy_rev);
 
        /* Get RADIO versioning */
-       if (dev->dev->bus->chip_id == 0x4317) {
-               if (dev->dev->bus->chip_rev == 0)
+       if (dev->sdev->bus->chip_id == 0x4317) {
+               if (dev->sdev->bus->chip_rev == 0)
                        tmp = 0x3205017F;
-               else if (dev->dev->bus->chip_rev == 1)
+               else if (dev->sdev->bus->chip_rev == 1)
                        tmp = 0x4205017F;
                else
                        tmp = 0x5205017F;
@@ -4195,7 +4204,7 @@ static void setup_struct_wldev_for_init(struct b43_wldev *dev)
 
 static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
 {
-       struct ssb_sprom *sprom = &dev->dev->bus->sprom;
+       struct ssb_sprom *sprom = &dev->sdev->bus->sprom;
        u64 hf;
 
        if (!modparam_btcoex)
@@ -4222,16 +4231,16 @@ static void b43_bluetooth_coext_disable(struct b43_wldev *dev)
 
 static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        u32 tmp;
 
        if ((bus->chip_id == 0x4311 && bus->chip_rev == 2) ||
            (bus->chip_id == 0x4312)) {
-               tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
+               tmp = ssb_read32(dev->sdev, SSB_IMCFGLO);
                tmp &= ~SSB_IMCFGLO_REQTO;
                tmp &= ~SSB_IMCFGLO_SERTO;
                tmp |= 0x3;
-               ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
+               ssb_write32(dev->sdev, SSB_IMCFGLO, tmp);
                ssb_commit_settings(bus);
        }
 }
@@ -4301,14 +4310,14 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
                dev->wl->current_beacon = NULL;
        }
 
-       ssb_device_disable(dev->dev, 0);
-       ssb_bus_may_powerdown(dev->dev->bus);
+       ssb_device_disable(dev->sdev, 0);
+       ssb_bus_may_powerdown(dev->sdev->bus);
 }
 
 /* Initialize a wireless core */
 static int b43_wireless_core_init(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct ssb_sprom *sprom = &bus->sprom;
        struct b43_phy *phy = &dev->phy;
        int err;
@@ -4320,7 +4329,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        err = ssb_bus_powerup(bus, 0);
        if (err)
                goto out;
-       if (!ssb_device_is_enabled(dev->dev)) {
+       if (!ssb_device_is_enabled(dev->sdev)) {
                tmp = phy->gmode ? B43_TMSLOW_GMODE : 0;
                b43_wireless_core_reset(dev, tmp);
        }
@@ -4330,7 +4339,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        phy->ops->prepare_structs(dev);
 
        /* Enable IRQ routing to this device. */
-       ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
+       ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->sdev);
 
        b43_imcfglo_timeouts_workaround(dev);
        b43_bluetooth_coext_disable(dev);
@@ -4343,7 +4352,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        if (err)
                goto err_busdown;
        b43_shm_write16(dev, B43_SHM_SHARED,
-                       B43_SHM_SH_WLCOREREV, dev->dev->id.revision);
+                       B43_SHM_SH_WLCOREREV, dev->sdev->id.revision);
        hf = b43_hf_read(dev);
        if (phy->type == B43_PHYTYPE_G) {
                hf |= B43_HF_SYMW;
@@ -4390,8 +4399,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        /* Maximum Contention Window */
        b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
 
-       if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
-           (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) ||
+       if ((dev->sdev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
+           (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) ||
            dev->use_pio) {
                dev->__using_pio_transfers = 1;
                err = b43_pio_init(dev);
@@ -4728,7 +4737,7 @@ static void b43_wireless_core_detach(struct b43_wldev *dev)
 static int b43_wireless_core_attach(struct b43_wldev *dev)
 {
        struct b43_wl *wl = dev->wl;
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL;
        int err;
        bool have_2ghz_phy = 0, have_5ghz_phy = 0;
@@ -4747,10 +4756,10 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
                goto out;
        }
        /* Get the PHY type. */
-       if (dev->dev->id.revision >= 5) {
+       if (dev->sdev->id.revision >= 5) {
                u32 tmshigh;
 
-               tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
+               tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
                have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY);
                have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY);
        } else
@@ -4823,7 +4832,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
        INIT_WORK(&dev->restart_work, b43_chip_reset);
 
        dev->phy.ops->switch_analog(dev, 0);
-       ssb_device_disable(dev->dev, 0);
+       ssb_device_disable(dev->sdev, 0);
        ssb_bus_may_powerdown(bus);
 
 out:
@@ -4864,7 +4873,7 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
                goto out;
 
        wldev->use_pio = b43_modparam_pio;
-       wldev->dev = dev;
+       wldev->sdev = dev;
        wldev->wl = wl;
        b43_set_status(wldev, B43_STAT_UNINIT);
        wldev->bad_frames_preempt = modparam_bad_frames_preempt;
@@ -4925,19 +4934,16 @@ static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl)
        ieee80211_free_hw(hw);
 }
 
-static int b43_wireless_init(struct ssb_device *dev)
+static struct b43_wl *b43_wireless_init(struct ssb_device *dev)
 {
        struct ssb_sprom *sprom = &dev->bus->sprom;
        struct ieee80211_hw *hw;
        struct b43_wl *wl;
-       int err = -ENOMEM;
-
-       b43_sprom_fixup(dev->bus);
 
        hw = ieee80211_alloc_hw(sizeof(*wl), &b43_hw_ops);
        if (!hw) {
                b43err(NULL, "Could not allocate ieee80211 device\n");
-               goto out;
+               return ERR_PTR(-ENOMEM);
        }
        wl = hw_to_b43_wl(hw);
 
@@ -4971,12 +4977,9 @@ static int b43_wireless_init(struct ssb_device *dev)
        INIT_WORK(&wl->tx_work, b43_tx_work);
        skb_queue_head_init(&wl->tx_queue);
 
-       ssb_set_devtypedata(dev, wl);
        b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n",
                dev->bus->chip_id, dev->id.revision);
-       err = 0;
-out:
-       return err;
+       return wl;
 }
 
 static int b43_ssb_probe(struct ssb_device *dev, const struct ssb_device_id *id)
@@ -4989,11 +4992,14 @@ static int b43_ssb_probe(struct ssb_device *dev, const struct ssb_device_id *id)
        if (!wl) {
                /* Probing the first core. Must setup common struct b43_wl */
                first = 1;
-               err = b43_wireless_init(dev);
-               if (err)
+               b43_sprom_fixup(dev->bus);
+               wl = b43_wireless_init(dev);
+               if (IS_ERR(wl)) {
+                       err = PTR_ERR(wl);
                        goto out;
-               wl = ssb_get_devtypedata(dev);
-               B43_WARN_ON(!wl);
+               }
+               ssb_set_devtypedata(dev, wl);
+               B43_WARN_ON(ssb_get_devtypedata(dev) != wl);
        }
        err = b43_one_core_attach(dev, wl);
        if (err)
index 7dcba5fafdc7fe04820bde7a10571f327fd6796d..2c8461dcf1b0b8f39df2c179a38f4200f4d4b46d 100644 (file)
@@ -32,7 +32,7 @@
 #include <pcmcia/cisreg.h>
 
 
-static /*const */ struct pcmcia_device_id b43_pcmcia_tbl[] = {
+static const struct pcmcia_device_id b43_pcmcia_tbl[] = {
        PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
        PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476),
        PCMCIA_DEVICE_NULL,
index b6428ec16dd638faf0fe167616ab2c9efb21d91a..b01c8ced57c3938099990b46220431108f521943 100644 (file)
@@ -265,7 +265,7 @@ static void hardware_pctl_init_aphy(struct b43_wldev *dev)
 
 void b43_phy_inita(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy *phy = &dev->phy;
 
        /* This lowlevel A-PHY init is also called from G-PHY init.
@@ -311,7 +311,7 @@ void b43_phy_inita(struct b43_wldev *dev)
        }
 
        if ((phy->type == B43_PHYTYPE_G) &&
-           (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) {
+           (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) {
                b43_phy_maskset(dev, B43_PHY_OFDM(0x6E), 0xE000, 0x3CF);
        }
 }
@@ -323,17 +323,17 @@ static int b43_aphy_init_tssi2dbm_table(struct b43_wldev *dev)
        struct b43_phy_a *aphy = phy->a;
        s16 pab0, pab1, pab2;
 
-       pab0 = (s16) (dev->dev->bus->sprom.pa1b0);
-       pab1 = (s16) (dev->dev->bus->sprom.pa1b1);
-       pab2 = (s16) (dev->dev->bus->sprom.pa1b2);
+       pab0 = (s16) (dev->sdev->bus->sprom.pa1b0);
+       pab1 = (s16) (dev->sdev->bus->sprom.pa1b1);
+       pab2 = (s16) (dev->sdev->bus->sprom.pa1b2);
 
        if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
            pab0 != -1 && pab1 != -1 && pab2 != -1) {
                /* The pabX values are set in SPROM. Use them. */
-               if ((s8) dev->dev->bus->sprom.itssi_a != 0 &&
-                   (s8) dev->dev->bus->sprom.itssi_a != -1)
+               if ((s8) dev->sdev->bus->sprom.itssi_a != 0 &&
+                   (s8) dev->sdev->bus->sprom.itssi_a != -1)
                        aphy->tgt_idle_tssi =
-                           (s8) (dev->dev->bus->sprom.itssi_a);
+                           (s8) (dev->sdev->bus->sprom.itssi_a);
                else
                        aphy->tgt_idle_tssi = 62;
                aphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0,
index b5c5ce94d3fd8607c9d06b20d351cd8345a3c7b0..e46b2f4f0920d0ce202dc2b21678603148a5baa8 100644 (file)
@@ -168,7 +168,7 @@ void b43_phy_lock(struct b43_wldev *dev)
        B43_WARN_ON(dev->phy.phy_locked);
        dev->phy.phy_locked = 1;
 #endif
-       B43_WARN_ON(dev->dev->id.revision < 3);
+       B43_WARN_ON(dev->sdev->id.revision < 3);
 
        if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))
                b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
@@ -180,7 +180,7 @@ void b43_phy_unlock(struct b43_wldev *dev)
        B43_WARN_ON(!dev->phy.phy_locked);
        dev->phy.phy_locked = 0;
 #endif
-       B43_WARN_ON(dev->dev->id.revision < 3);
+       B43_WARN_ON(dev->sdev->id.revision < 3);
 
        if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))
                b43_power_saving_ctl_bits(dev, 0);
@@ -368,8 +368,8 @@ void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags)
        /* The next check will be needed in two seconds, or later. */
        phy->next_txpwr_check_time = round_jiffies(now + (HZ * 2));
 
-       if ((dev->dev->bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
-           (dev->dev->bus->boardinfo.type == SSB_BOARD_BU4306))
+       if ((dev->sdev->bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+           (dev->sdev->bus->boardinfo.type == SSB_BOARD_BU4306))
                return; /* No software txpower adjustment needed */
 
        result = phy->ops->recalc_txpower(dev, !!(flags & B43_TXPWR_IGNORE_TSSI));
index be4828167012d0703f7ebe60d501e9b0f6fd8b6c..1758a282f913548403ee0a6b55dacac832ac92f5 100644 (file)
@@ -718,7 +718,7 @@ static void b43_calc_nrssi_threshold(struct b43_wldev *dev)
        B43_WARN_ON(phy->type != B43_PHYTYPE_G);
 
        if (!phy->gmode ||
-           !(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
+           !(dev->sdev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
                tmp16 = b43_nrssi_hw_read(dev, 0x20);
                if (tmp16 >= 0x20)
                        tmp16 -= 0x40;
@@ -1114,7 +1114,7 @@ static u16 radio2050_rfover_val(struct b43_wldev *dev,
 {
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_g *gphy = phy->g;
-       struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+       struct ssb_sprom *sprom = &(dev->sdev->bus->sprom);
 
        if (!phy->gmode)
                return 0;
@@ -1491,7 +1491,7 @@ static u16 b43_radio_init2050(struct b43_wldev *dev)
 
 static void b43_phy_initb5(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_g *gphy = phy->g;
        u16 offset, value;
@@ -1620,7 +1620,7 @@ static void b43_phy_initb6(struct b43_wldev *dev)
                b43_radio_write16(dev, 0x5A, 0x88);
                b43_radio_write16(dev, 0x5B, 0x6B);
                b43_radio_write16(dev, 0x5C, 0x0F);
-               if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) {
+               if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) {
                        b43_radio_write16(dev, 0x5D, 0xFA);
                        b43_radio_write16(dev, 0x5E, 0xD8);
                } else {
@@ -1787,7 +1787,7 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
        b43_phy_set(dev, B43_PHY_RFOVER, 0x0100);
        b43_phy_mask(dev, B43_PHY_RFOVERVAL, 0xCFFF);
 
-       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) {
+       if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) {
                if (phy->rev >= 7) {
                        b43_phy_set(dev, B43_PHY_RFOVER, 0x0800);
                        b43_phy_set(dev, B43_PHY_RFOVERVAL, 0x8000);
@@ -1922,7 +1922,7 @@ static void b43_hardware_pctl_init_gphy(struct b43_wldev *dev)
 /* Initialize B/G PHY power control */
 static void b43_phy_init_pctl(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_g *gphy = phy->g;
        struct b43_rfatt old_rfatt;
@@ -2053,7 +2053,7 @@ static void b43_phy_initg(struct b43_wldev *dev)
        if (phy->rev >= 6) {
                b43_phy_maskset(dev, B43_PHY_CCK(0x36), 0x0FFF, (gphy->lo_control->tx_bias << 12));
        }
-       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
+       if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
                b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
        else
                b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
@@ -2066,7 +2066,7 @@ static void b43_phy_initg(struct b43_wldev *dev)
                b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
        }
 
-       if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
+       if (!(dev->sdev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
                /* The specs state to update the NRSSI LT with
                 * the value 0x7FFFFFFF here. I think that is some weird
                 * compiler optimization in the original driver.
@@ -2088,8 +2088,8 @@ static void b43_phy_initg(struct b43_wldev *dev)
        /* FIXME: The spec says in the following if, the 0 should be replaced
           'if OFDM may not be used in the current locale'
           but OFDM is legal everywhere */
-       if ((dev->dev->bus->chip_id == 0x4306
-            && dev->dev->bus->chip_package == 2) || 0) {
+       if ((dev->sdev->bus->chip_id == 0x4306
+            && dev->sdev->bus->chip_package == 2) || 0) {
                b43_phy_mask(dev, B43_PHY_CRS0, 0xBFFF);
                b43_phy_mask(dev, B43_PHY_OFDM(0xC3), 0x7FFF);
        }
@@ -2105,7 +2105,7 @@ void b43_gphy_channel_switch(struct b43_wldev *dev,
        b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
 
        if (channel == 14) {
-               if (dev->dev->bus->sprom.country_code ==
+               if (dev->sdev->bus->sprom.country_code ==
                    SSB_SPROM1CCODE_JAPAN)
                        b43_hf_write(dev,
                                     b43_hf_read(dev) & ~B43_HF_ACPR);
@@ -2136,7 +2136,7 @@ static void default_baseband_attenuation(struct b43_wldev *dev,
 static void default_radio_attenuation(struct b43_wldev *dev,
                                      struct b43_rfatt *rf)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy *phy = &dev->phy;
 
        rf->with_padmix = 0;
@@ -2384,11 +2384,11 @@ static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev)
        struct b43_phy_g *gphy = phy->g;
        s16 pab0, pab1, pab2;
 
-       pab0 = (s16) (dev->dev->bus->sprom.pa0b0);
-       pab1 = (s16) (dev->dev->bus->sprom.pa0b1);
-       pab2 = (s16) (dev->dev->bus->sprom.pa0b2);
+       pab0 = (s16) (dev->sdev->bus->sprom.pa0b0);
+       pab1 = (s16) (dev->sdev->bus->sprom.pa0b1);
+       pab2 = (s16) (dev->sdev->bus->sprom.pa0b2);
 
-       B43_WARN_ON((dev->dev->bus->chip_id == 0x4301) &&
+       B43_WARN_ON((dev->sdev->bus->chip_id == 0x4301) &&
                    (phy->radio_ver != 0x2050)); /* Not supported anymore */
 
        gphy->dyn_tssi_tbl = 0;
@@ -2396,10 +2396,10 @@ static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev)
        if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
            pab0 != -1 && pab1 != -1 && pab2 != -1) {
                /* The pabX values are set in SPROM. Use them. */
-               if ((s8) dev->dev->bus->sprom.itssi_bg != 0 &&
-                   (s8) dev->dev->bus->sprom.itssi_bg != -1) {
+               if ((s8) dev->sdev->bus->sprom.itssi_bg != 0 &&
+                   (s8) dev->sdev->bus->sprom.itssi_bg != -1) {
                        gphy->tgt_idle_tssi =
-                               (s8) (dev->dev->bus->sprom.itssi_bg);
+                               (s8) (dev->sdev->bus->sprom.itssi_bg);
                } else
                        gphy->tgt_idle_tssi = 62;
                gphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0,
@@ -2840,7 +2840,7 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
                                    B43_TXCTL_TXMIX;
                                rfatt += 2;
                                bbatt += 2;
-                       } else if (dev->dev->bus->sprom.
+                       } else if (dev->sdev->bus->sprom.
                                   boardflags_lo &
                                   B43_BFL_PACTRL) {
                                bbatt += 4 * (rfatt - 2);
@@ -2914,14 +2914,14 @@ static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev,
        estimated_pwr = b43_gphy_estimate_power_out(dev, average_tssi);
 
        B43_WARN_ON(phy->type != B43_PHYTYPE_G);
-       max_pwr = dev->dev->bus->sprom.maxpwr_bg;
-       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
+       max_pwr = dev->sdev->bus->sprom.maxpwr_bg;
+       if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
                max_pwr -= 3; /* minus 0.75 */
        if (unlikely(max_pwr >= INT_TO_Q52(30/*dBm*/))) {
                b43warn(dev->wl,
                        "Invalid max-TX-power value in SPROM.\n");
                max_pwr = INT_TO_Q52(20); /* fake it */
-               dev->dev->bus->sprom.maxpwr_bg = max_pwr;
+               dev->sdev->bus->sprom.maxpwr_bg = max_pwr;
        }
 
        /* Get desired power (in Q5.2) */
@@ -3014,7 +3014,7 @@ static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
 
-       if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI))
+       if (!(dev->sdev->bus->sprom.boardflags_lo & B43_BFL_RSSI))
                return;
 
        b43_mac_suspend(dev);
index fd50eb116243487f532bca9ac24623cdb1e81c93..012c8da2f9447eec120b5c3bd8d97021f4eb3c01 100644 (file)
@@ -86,7 +86,7 @@ static void b43_lpphy_op_free(struct b43_wldev *dev)
 static void lpphy_read_band_sprom(struct b43_wldev *dev)
 {
        struct b43_phy_lp *lpphy = dev->phy.lp;
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        u16 cckpo, maxpwr;
        u32 ofdmpo;
        int i;
@@ -214,7 +214,7 @@ static void lpphy_table_init(struct b43_wldev *dev)
 
 static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy_lp *lpphy = dev->phy.lp;
        u16 tmp, tmp2;
 
@@ -412,7 +412,7 @@ static void lpphy_restore_dig_flt_state(struct b43_wldev *dev)
 
 static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy_lp *lpphy = dev->phy.lp;
 
        b43_phy_write(dev, B43_LPPHY_AFE_DAC_CTL, 0x50);
@@ -519,7 +519,7 @@ struct b2062_freqdata {
 static void lpphy_2062_init(struct b43_wldev *dev)
 {
        struct b43_phy_lp *lpphy = dev->phy.lp;
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        u32 crystalfreq, tmp, ref;
        unsigned int i;
        const struct b2062_freqdata *fd = NULL;
@@ -697,7 +697,7 @@ static void lpphy_radio_init(struct b43_wldev *dev)
                lpphy_sync_stx(dev);
                b43_phy_write(dev, B43_PHY_OFDM(0xF0), 0x5F80);
                b43_phy_write(dev, B43_PHY_OFDM(0xF1), 0);
-               if (dev->dev->bus->chip_id == 0x4325) {
+               if (dev->sdev->bus->chip_id == 0x4325) {
                        // TODO SSB PMU recalibration
                }
        }
@@ -1289,7 +1289,7 @@ finish:
 
 static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
        u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF;
        int i;
@@ -1840,7 +1840,7 @@ static void lpphy_papd_cal(struct b43_wldev *dev, struct lpphy_tx_gains gains,
 static void lpphy_papd_cal_txpwr(struct b43_wldev *dev)
 {
        struct b43_phy_lp *lpphy = dev->phy.lp;
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct lpphy_tx_gains gains, oldgains;
        int old_txpctl, old_afe_ovr, old_rf, old_bbmult;
 
@@ -1870,7 +1870,7 @@ static int lpphy_rx_iq_cal(struct b43_wldev *dev, bool noise, bool tx,
                            bool rx, bool pa, struct lpphy_tx_gains *gains)
 {
        struct b43_phy_lp *lpphy = dev->phy.lp;
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        const struct lpphy_rx_iq_comp *iqcomp = NULL;
        struct lpphy_tx_gains nogains, oldgains;
        u16 tmp;
@@ -2408,7 +2408,7 @@ static const struct b206x_channel b2063_chantbl[] = {
 
 static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
 
        b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0xFF);
        udelay(20);
@@ -2432,7 +2432,7 @@ static int lpphy_b2062_tune(struct b43_wldev *dev,
                            unsigned int channel)
 {
        struct b43_phy_lp *lpphy = dev->phy.lp;
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        const struct b206x_channel *chandata = NULL;
        u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
        u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9;
@@ -2522,7 +2522,7 @@ static void lpphy_b2063_vco_calib(struct b43_wldev *dev)
 static int lpphy_b2063_tune(struct b43_wldev *dev,
                            unsigned int channel)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
 
        static const struct b206x_channel *chandata = NULL;
        u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
index b075a3f82a43377e9c22a8f54bd4c43854e0c168..05960ddde24ee4fef9eb12801522eb95ea3e4825 100644 (file)
@@ -299,7 +299,7 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
 static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
 {
        struct b43_phy_n *nphy = dev->phy.n;
-       struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+       struct ssb_sprom *sprom = &(dev->sdev->bus->sprom);
 
        u8 txpi[2], bbmult, i;
        u16 tmp, radio_gain, dac_gain;
@@ -423,8 +423,8 @@ static void b43_radio_init2055_pre(struct b43_wldev *dev)
 static void b43_radio_init2055_post(struct b43_wldev *dev)
 {
        struct b43_phy_n *nphy = dev->phy.n;
-       struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
-       struct ssb_boardinfo *binfo = &(dev->dev->bus->boardinfo);
+       struct ssb_sprom *sprom = &(dev->sdev->bus->sprom);
+       struct ssb_boardinfo *binfo = &(dev->sdev->bus->boardinfo);
        int i;
        u16 val;
        bool workaround = false;
@@ -609,12 +609,12 @@ static void b43_nphy_bmac_clock_fgc(struct b43_wldev *dev, bool force)
        if (dev->phy.type != B43_PHYTYPE_N)
                return;
 
-       tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+       tmslow = ssb_read32(dev->sdev, SSB_TMSLOW);
        if (force)
                tmslow |= SSB_TMSLOW_FGC;
        else
                tmslow &= ~SSB_TMSLOW_FGC;
-       ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+       ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
 }
 
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */
@@ -959,7 +959,7 @@ static void b43_nphy_superswitch_init(struct b43_wldev *dev, bool init)
                b43_phy_write(dev, B43_NPHY_GPIO_LOOEN, 0);
                b43_phy_write(dev, B43_NPHY_GPIO_HIOEN, 0);
 
-               ssb_chipco_gpio_control(&dev->dev->bus->chipco, 0xFC00,
+               ssb_chipco_gpio_control(&dev->sdev->bus->chipco, 0xFC00,
                                        0xFC00);
                b43_write32(dev, B43_MMIO_MACCTL,
                        b43_read32(dev, B43_MMIO_MACCTL) &
@@ -983,7 +983,7 @@ static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val)
 {
        u16 tmp;
 
-       if (dev->dev->id.revision == 16)
+       if (dev->sdev->id.revision == 16)
                b43_mac_suspend(dev);
 
        tmp = b43_phy_read(dev, B43_NPHY_CLASSCTL);
@@ -993,7 +993,7 @@ static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val)
        tmp |= (val & mask);
        b43_phy_maskset(dev, B43_NPHY_CLASSCTL, 0xFFF8, tmp);
 
-       if (dev->dev->id.revision == 16)
+       if (dev->sdev->id.revision == 16)
                b43_mac_enable(dev);
 
        return tmp;
@@ -1168,7 +1168,7 @@ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev)
 static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
 {
        struct b43_phy_n *nphy = dev->phy.n;
-       struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+       struct ssb_sprom *sprom = &(dev->sdev->bus->sprom);
 
        /* PHY rev 0, 1, 2 */
        u8 i, j;
@@ -1373,7 +1373,7 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */
 static void b43_nphy_workarounds(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_n *nphy = phy->n;
 
@@ -3093,7 +3093,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
        int freq;
        bool avoid = false;
        u8 length;
-       u16 tmp, core, type, count, max, numb, last, cmd;
+       u16 tmp, core, type, count, max, numb, last = 0, cmd;
        const u16 *table;
        bool phy6or5x;
 
@@ -3586,7 +3586,7 @@ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask)
  */
 int b43_phy_initn(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_n *nphy = phy->n;
        u8 tx_pwr_state;
@@ -3601,7 +3601,7 @@ int b43_phy_initn(struct b43_wldev *dev)
        if ((dev->phy.rev >= 3) &&
           (bus->sprom.boardflags_lo & B43_BFL_EXTLNA) &&
           (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) {
-               chipco_set32(&dev->dev->bus->chipco, SSB_CHIPCO_CHIPCTL, 0x40);
+               chipco_set32(&dev->sdev->bus->chipco, SSB_CHIPCO_CHIPCTL, 0x40);
        }
        nphy->deaf_count = 0;
        b43_nphy_tables_init(dev);
index aa12273ae716482544f71f0733beb8d70c45ff84..72ab94df7569e79696e475470a33978c3c49c834 100644 (file)
@@ -111,7 +111,7 @@ static u16 index_to_pioqueue_base(struct b43_wldev *dev,
                B43_MMIO_PIO11_BASE5,
        };
 
-       if (dev->dev->id.revision >= 11) {
+       if (dev->sdev->id.revision >= 11) {
                B43_WARN_ON(index >= ARRAY_SIZE(bases_rev11));
                return bases_rev11[index];
        }
@@ -121,14 +121,14 @@ static u16 index_to_pioqueue_base(struct b43_wldev *dev,
 
 static u16 pio_txqueue_offset(struct b43_wldev *dev)
 {
-       if (dev->dev->id.revision >= 11)
+       if (dev->sdev->id.revision >= 11)
                return 0x18;
        return 0;
 }
 
 static u16 pio_rxqueue_offset(struct b43_wldev *dev)
 {
-       if (dev->dev->id.revision >= 11)
+       if (dev->sdev->id.revision >= 11)
                return 0x38;
        return 8;
 }
@@ -144,7 +144,7 @@ static struct b43_pio_txqueue *b43_setup_pioqueue_tx(struct b43_wldev *dev,
        if (!q)
                return NULL;
        q->dev = dev;
-       q->rev = dev->dev->id.revision;
+       q->rev = dev->sdev->id.revision;
        q->mmio_base = index_to_pioqueue_base(dev, index) +
                       pio_txqueue_offset(dev);
        q->index = index;
@@ -178,7 +178,7 @@ static struct b43_pio_rxqueue *b43_setup_pioqueue_rx(struct b43_wldev *dev,
        if (!q)
                return NULL;
        q->dev = dev;
-       q->rev = dev->dev->id.revision;
+       q->rev = dev->sdev->id.revision;
        q->mmio_base = index_to_pioqueue_base(dev, index) +
                       pio_rxqueue_offset(dev);
 
@@ -339,7 +339,7 @@ static u16 tx_write_2byte_queue(struct b43_pio_txqueue *q,
        ctl |= B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI;
        b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
 
-       ssb_block_write(dev->dev, data, (data_len & ~1),
+       b43_block_write(dev, data, (data_len & ~1),
                        q->mmio_base + B43_PIO_TXDATA,
                        sizeof(u16));
        if (data_len & 1) {
@@ -351,7 +351,7 @@ static u16 tx_write_2byte_queue(struct b43_pio_txqueue *q,
                b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
                tail[0] = data[data_len - 1];
                tail[1] = 0;
-               ssb_block_write(dev->dev, tail, 2,
+               b43_block_write(dev, tail, 2,
                                q->mmio_base + B43_PIO_TXDATA,
                                sizeof(u16));
        }
@@ -393,7 +393,7 @@ static u32 tx_write_4byte_queue(struct b43_pio_txqueue *q,
               B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_24_31;
        b43_piotx_write32(q, B43_PIO8_TXCTL, ctl);
 
-       ssb_block_write(dev->dev, data, (data_len & ~3),
+       b43_block_write(dev, data, (data_len & ~3),
                        q->mmio_base + B43_PIO8_TXDATA,
                        sizeof(u32));
        if (data_len & 3) {
@@ -421,7 +421,7 @@ static u32 tx_write_4byte_queue(struct b43_pio_txqueue *q,
                        break;
                }
                b43_piotx_write32(q, B43_PIO8_TXCTL, ctl);
-               ssb_block_write(dev->dev, tail, 4,
+               b43_block_write(dev, tail, 4,
                                q->mmio_base + B43_PIO8_TXDATA,
                                sizeof(u32));
        }
@@ -657,11 +657,11 @@ data_ready:
 
        /* Get the preamble (RX header) */
        if (q->rev >= 8) {
-               ssb_block_read(dev->dev, rxhdr, sizeof(*rxhdr),
+               b43_block_read(dev, rxhdr, sizeof(*rxhdr),
                               q->mmio_base + B43_PIO8_RXDATA,
                               sizeof(u32));
        } else {
-               ssb_block_read(dev->dev, rxhdr, sizeof(*rxhdr),
+               b43_block_read(dev, rxhdr, sizeof(*rxhdr),
                               q->mmio_base + B43_PIO_RXDATA,
                               sizeof(u16));
        }
@@ -697,7 +697,7 @@ data_ready:
        skb_reserve(skb, 2);
        skb_put(skb, len + padding);
        if (q->rev >= 8) {
-               ssb_block_read(dev->dev, skb->data + padding, (len & ~3),
+               b43_block_read(dev, skb->data + padding, (len & ~3),
                               q->mmio_base + B43_PIO8_RXDATA,
                               sizeof(u32));
                if (len & 3) {
@@ -705,7 +705,7 @@ data_ready:
                        BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 4);
 
                        /* Read the last few bytes. */
-                       ssb_block_read(dev->dev, tail, 4,
+                       b43_block_read(dev, tail, 4,
                                       q->mmio_base + B43_PIO8_RXDATA,
                                       sizeof(u32));
                        switch (len & 3) {
@@ -724,7 +724,7 @@ data_ready:
                        }
                }
        } else {
-               ssb_block_read(dev->dev, skb->data + padding, (len & ~1),
+               b43_block_read(dev, skb->data + padding, (len & ~1),
                               q->mmio_base + B43_PIO_RXDATA,
                               sizeof(u16));
                if (len & 1) {
@@ -732,7 +732,7 @@ data_ready:
                        BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 2);
 
                        /* Read the last byte. */
-                       ssb_block_read(dev->dev, tail, 2,
+                       b43_block_read(dev, tail, 2,
                                       q->mmio_base + B43_PIO_RXDATA,
                                       sizeof(u16));
                        skb->data[len + padding - 1] = tail[0];
index 86bc0a0f735cf63fd0218b3628af061a238b77bc..a617efe38289d1157ccccc78fca85dda73b52e5a 100644 (file)
@@ -37,7 +37,7 @@ void b43_rfkill_poll(struct ieee80211_hw *hw)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        bool enabled;
        bool brought_up = false;
 
@@ -47,7 +47,7 @@ void b43_rfkill_poll(struct ieee80211_hw *hw)
                        mutex_unlock(&wl->mutex);
                        return;
                }
-               ssb_device_enable(dev->dev, 0);
+               ssb_device_enable(dev->sdev, 0);
                brought_up = true;
        }
 
@@ -63,7 +63,7 @@ void b43_rfkill_poll(struct ieee80211_hw *hw)
        }
 
        if (brought_up) {
-               ssb_device_disable(dev->dev, 0);
+               ssb_device_disable(dev->sdev, 0);
                ssb_bus_may_powerdown(bus);
        }
 
index 09e2dfd7b175a74534de12fe240761f7a3138302..808e25b79703a0151cab0bd46317523768ca160b 100644 (file)
@@ -66,7 +66,7 @@ static void b43_sdio_interrupt_dispatcher(struct sdio_func *func)
 int b43_sdio_request_irq(struct b43_wldev *dev,
                         void (*handler)(struct b43_wldev *dev))
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct sdio_func *func = bus->host_sdio;
        struct b43_sdio *sdio = sdio_get_drvdata(func);
        int err;
@@ -82,7 +82,7 @@ int b43_sdio_request_irq(struct b43_wldev *dev,
 
 void b43_sdio_free_irq(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct sdio_func *func = bus->host_sdio;
        struct b43_sdio *sdio = sdio_get_drvdata(func);
 
index f1ae4e05a32cf3b77b356dbf2ea97b56b6e72c68..57af619725c3e12c3716cae0e0fd7369ae8bcd8a 100644 (file)
@@ -140,7 +140,7 @@ static DEVICE_ATTR(interference, 0644,
 
 int b43_sysfs_register(struct b43_wldev *wldev)
 {
-       struct device *dev = wldev->dev->dev;
+       struct device *dev = wldev->sdev->dev;
 
        B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED);
 
@@ -149,7 +149,7 @@ int b43_sysfs_register(struct b43_wldev *wldev)
 
 void b43_sysfs_unregister(struct b43_wldev *wldev)
 {
-       struct device *dev = wldev->dev->dev;
+       struct device *dev = wldev->sdev->dev;
 
        device_remove_file(dev, &dev_attr_interference);
 }
index 61027ee84fb537dd2e0276ef518ac66d180907e1..59df3c64af6339e69684a3f048622abac960472f 100644 (file)
@@ -2304,7 +2304,7 @@ void lpphy_rev0_1_table_init(struct b43_wldev *dev)
 
 void lpphy_rev2plus_table_init(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        int i;
 
        B43_WARN_ON(dev->phy.rev < 2);
@@ -2416,7 +2416,7 @@ void lpphy_write_gain_table_bulk(struct b43_wldev *dev, int offset, int count,
 
 void lpphy_init_tx_gain_table(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
 
        switch (dev->phy.rev) {
        case 0:
index 9a335da65b423129c54c8245dcdbf890fd531701..8f4db448ec3308a1e6f2ccad03a1277f59e6f610 100644 (file)
@@ -458,7 +458,7 @@ static void b43_wa_rssi_adc(struct b43_wldev *dev)
 
 static void b43_wa_boards_a(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
 
        if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
            bus->boardinfo.type == SSB_BOARD_BU4306 &&
@@ -486,7 +486,7 @@ static void b43_wa_boards_a(struct b43_wldev *dev)
 
 static void b43_wa_boards_g(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy *phy = &dev->phy;
 
        if (bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM ||
index e5be381c17bce02ff4e43269f56c80feb787a8b4..c8f99aebe01f6565a798ef67952bb7cc9c4722c7 100644 (file)
@@ -547,7 +547,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev,
                        else
                                tmp -= 3;
                } else {
-                       if (dev->dev->bus->sprom.
+                       if (dev->sdev->bus->sprom.
                            boardflags_lo & B43_BFL_RSSI) {
                                if (in_rssi > 63)
                                        in_rssi = 63;
index 2176edede39b78db45e337e313c860802b92f66b..c052a0d5cbdd909b68d0641aaed990065d1ea981 100644 (file)
@@ -620,7 +620,7 @@ static int hostap_cs_resume(struct pcmcia_device *link)
        return 0;
 }
 
-static struct pcmcia_device_id hostap_cs_ids[] = {
+static const struct pcmcia_device_id hostap_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100),
        PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
        PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777),
index 7e5e85a017b5c0f9da0435f84cf94965b72a6ee3..a7a4739880dc91d7075b5eb6e1ee309e2dd16049 100644 (file)
@@ -628,11 +628,11 @@ void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 
        /* rx_status carries information about the packet to mac80211 */
        rx_status.mactime = le64_to_cpu(phy_res->timestamp);
+       rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
+                               IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
        rx_status.freq =
                ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel),
                                                        rx_status.band);
-       rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
-                               IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
        rx_status.rate_idx =
                iwl4965_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band);
        rx_status.flag = 0;
index f5433c74b845d54e6ac2869eb9664feb64bcd6bc..facc94e74b07991fa723b7144177beb4cc4bba93 100644 (file)
@@ -1218,10 +1218,10 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *c
         * receive commit_rxon request
         * abort any previous channel switch if still in process
         */
-       if (priv->switch_rxon.switch_in_progress &&
-           (priv->switch_rxon.channel != ctx->staging.channel)) {
+       if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status) &&
+           (priv->switch_channel != ctx->staging.channel)) {
                IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
-                     le16_to_cpu(priv->switch_rxon.channel));
+                     le16_to_cpu(priv->switch_channel));
                iwl_legacy_chswitch_done(priv, false);
        }
 
@@ -1237,7 +1237,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *c
 
                memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
                iwl_legacy_print_rx_config_cmd(priv, ctx);
-               return 0;
+               goto set_tx_power;
        }
 
        /* If we are currently associated and the new config requires
@@ -1317,6 +1317,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *c
 
        iwl4965_init_sensitivity(priv);
 
+set_tx_power:
        /* If we issue a new RXON command which required a tune then we must
         * send a new TXPOWER command or we won't be able to Tx any frames */
        ret = iwl_legacy_set_tx_power(priv, priv->tx_power_next, true);
@@ -1403,9 +1404,6 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv,
                return rc;
        }
 
-       priv->switch_rxon.channel = cmd.channel;
-       priv->switch_rxon.switch_in_progress = true;
-
        return iwl_legacy_send_cmd_pdu(priv,
                         REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
 }
@@ -1543,7 +1541,7 @@ static void iwl4965_temperature_calib(struct iwl_priv *priv)
        s32 temp;
 
        temp = iwl4965_hw_get_temperature(priv);
-       if (temp < 0)
+       if (IWL_TX_POWER_TEMPERATURE_OUT_OF_RANGE(temp))
                return;
 
        if (priv->temperature != temp) {
index 42df8321dae807ffc616e3d48f19ce4e45323584..3be76bd5499a960f5e7685953a18074c44504525 100644 (file)
@@ -859,12 +859,8 @@ void iwl_legacy_chswitch_done(struct iwl_priv *priv, bool is_success)
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       if (priv->switch_rxon.switch_in_progress) {
+       if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
                ieee80211_chswitch_done(ctx->vif, is_success);
-               mutex_lock(&priv->mutex);
-               priv->switch_rxon.switch_in_progress = false;
-               mutex_unlock(&priv->mutex);
-       }
 }
 EXPORT_SYMBOL(iwl_legacy_chswitch_done);
 
@@ -876,19 +872,19 @@ void iwl_legacy_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        struct iwl_legacy_rxon_cmd *rxon = (void *)&ctx->active;
 
-       if (priv->switch_rxon.switch_in_progress) {
-               if (!le32_to_cpu(csa->status) &&
-                   (csa->channel == priv->switch_rxon.channel)) {
-                       rxon->channel = csa->channel;
-                       ctx->staging.channel = csa->channel;
-                       IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
-                             le16_to_cpu(csa->channel));
-                       iwl_legacy_chswitch_done(priv, true);
-               } else {
-                       IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
+       if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
+               return;
+
+       if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) {
+               rxon->channel = csa->channel;
+               ctx->staging.channel = csa->channel;
+               IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
                              le16_to_cpu(csa->channel));
-                       iwl_legacy_chswitch_done(priv, false);
-               }
+               iwl_legacy_chswitch_done(priv, true);
+       } else {
+               IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
+                       le16_to_cpu(csa->channel));
+               iwl_legacy_chswitch_done(priv, false);
        }
 }
 EXPORT_SYMBOL(iwl_legacy_rx_csa);
index bc66c604106cb990e79b73a337395523c1d60973..c5fbda0760dea06c28f9a6c5411c87428defad07 100644 (file)
@@ -560,7 +560,7 @@ void iwl_legacy_free_geos(struct iwl_priv *priv);
 #define STATUS_SCAN_HW         15
 #define STATUS_POWER_PMI       16
 #define STATUS_FW_ERROR                17
-
+#define STATUS_CHANNEL_SWITCH_PENDING 18
 
 static inline int iwl_legacy_is_ready(struct iwl_priv *priv)
 {
index be0106c6a2daad00486a6e6fac360172c5943e8c..ea30122669ee718906991ec53de2b9a50a1fb21d 100644 (file)
@@ -854,17 +854,6 @@ struct traffic_stats {
 #endif
 };
 
-/*
- * iwl_switch_rxon: "channel switch" structure
- *
- * @ switch_in_progress: channel switch in progress
- * @ channel: new channel
- */
-struct iwl_switch_rxon {
-       bool switch_in_progress;
-       __le16 channel;
-};
-
 /*
  * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds
  * to perform continuous uCode event logging operation if enabled
@@ -1115,7 +1104,7 @@ struct iwl_priv {
 
        struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX];
 
-       struct iwl_switch_rxon switch_rxon;
+       __le16 switch_channel;
 
        /* 1st responses from initialize and runtime uCode images.
         * _4965's initialize alive response contains some calibration data. */
index af2ae22fcfd32c22ab0b28f1bddcc64b7f873c46..7157ba52968033642953a3af849d4cd706b1694c 100644 (file)
@@ -2861,16 +2861,13 @@ void iwl4965_mac_channel_switch(struct ieee80211_hw *hw,
                goto out;
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
-           test_bit(STATUS_SCANNING, &priv->status))
+           test_bit(STATUS_SCANNING, &priv->status) ||
+           test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
                goto out;
 
        if (!iwl_legacy_is_associated_ctx(ctx))
                goto out;
 
-       /* channel switch in progress */
-       if (priv->switch_rxon.switch_in_progress == true)
-               goto out;
-
        if (priv->cfg->ops->lib->set_channel_switch) {
 
                ch = channel->hw_value;
@@ -2919,15 +2916,18 @@ void iwl4965_mac_channel_switch(struct ieee80211_hw *hw,
                         * at this point, staging_rxon has the
                         * configuration for channel switch
                         */
-                       if (priv->cfg->ops->lib->set_channel_switch(priv,
-                                                                   ch_switch))
-                               priv->switch_rxon.switch_in_progress = false;
+                       set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
+                       priv->switch_channel = cpu_to_le16(ch);
+                       if (priv->cfg->ops->lib->set_channel_switch(priv, ch_switch)) {
+                               clear_bit(STATUS_CHANNEL_SWITCH_PENDING,
+                                         &priv->status);
+                               priv->switch_channel = 0;
+                               ieee80211_chswitch_done(ctx->vif, false);
+                       }
                }
        }
 out:
        mutex_unlock(&priv->mutex);
-       if (!priv->switch_rxon.switch_in_progress)
-               ieee80211_chswitch_done(ctx->vif, false);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
index b4c81931e136b376c8fa3ec5b1634c719591106e..61d4a11f566b4f9e9864f1109369eade4634c50a 100644 (file)
@@ -171,10 +171,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
 
 static struct iwl_lib_ops iwl1000_lib = {
        .set_hw_params = iwl1000_hw_set_hw_params,
-       .txq_set_sched = iwlagn_txq_set_sched,
-       .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
-       .txq_free_tfd = iwl_hw_txq_free_tfd,
-       .txq_init = iwl_hw_tx_queue_init,
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_setup_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
index 89b8da7a6c8bc9ce2d5811a6dd075448ee1237e6..2282279cffc454c5089277a6cb1f279a60ad2dab 100644 (file)
@@ -177,92 +177,14 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv)
        return 0;
 }
 
-static int iwl2030_hw_channel_switch(struct iwl_priv *priv,
-                                    struct ieee80211_channel_switch *ch_switch)
-{
-       /*
-        * MULTI-FIXME
-        * See iwl_mac_channel_switch.
-        */
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct iwl6000_channel_switch_cmd cmd;
-       const struct iwl_channel_info *ch_info;
-       u32 switch_time_in_usec, ucode_switch_time;
-       u16 ch;
-       u32 tsf_low;
-       u8 switch_count;
-       u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
-       struct ieee80211_vif *vif = ctx->vif;
-       struct iwl_host_cmd hcmd = {
-               .id = REPLY_CHANNEL_SWITCH,
-               .len = sizeof(cmd),
-               .flags = CMD_SYNC,
-               .data = &cmd,
-       };
-
-       cmd.band = priv->band == IEEE80211_BAND_2GHZ;
-       ch = ch_switch->channel->hw_value;
-       IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
-               ctx->active.channel, ch);
-       cmd.channel = cpu_to_le16(ch);
-       cmd.rxon_flags = ctx->staging.flags;
-       cmd.rxon_filter_flags = ctx->staging.filter_flags;
-       switch_count = ch_switch->count;
-       tsf_low = ch_switch->timestamp & 0x0ffffffff;
-       /*
-        * calculate the ucode channel switch time
-        * adding TSF as one of the factor for when to switch
-        */
-       if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
-               if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
-                   beacon_interval)) {
-                       switch_count -= (priv->ucode_beacon_time -
-                               tsf_low) / beacon_interval;
-               } else
-                       switch_count = 0;
-       }
-       if (switch_count <= 1)
-               cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
-       else {
-               switch_time_in_usec =
-                       vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
-               ucode_switch_time = iwl_usecs_to_beacons(priv,
-                                               switch_time_in_usec,
-                                               beacon_interval);
-               cmd.switch_time = iwl_add_beacon_time(priv,
-                                               priv->ucode_beacon_time,
-                                               ucode_switch_time,
-                                               beacon_interval);
-       }
-       IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
-                     cmd.switch_time);
-       ch_info = iwl_get_channel_info(priv, priv->band, ch);
-       if (ch_info)
-               cmd.expect_beacon = is_channel_radar(ch_info);
-       else {
-               IWL_ERR(priv, "invalid channel switch from %u to %u\n",
-                       ctx->active.channel, ch);
-               return -EFAULT;
-       }
-       priv->switch_rxon.channel = cmd.channel;
-       priv->switch_rxon.switch_in_progress = true;
-
-       return iwl_send_cmd_sync(priv, &hcmd);
-}
-
 static struct iwl_lib_ops iwl2000_lib = {
        .set_hw_params = iwl2000_hw_set_hw_params,
-       .txq_set_sched = iwlagn_txq_set_sched,
-       .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
-       .txq_free_tfd = iwl_hw_txq_free_tfd,
-       .txq_init = iwl_hw_tx_queue_init,
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_bt_setup_deferred_work,
        .cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
        .send_tx_power = iwlagn_send_tx_power,
        .update_chain_flags = iwl_update_chain_flags,
-       .set_channel_switch = iwl2030_hw_channel_switch,
        .apm_ops = {
                .init = iwl_apm_init,
                .config = iwl2000_nic_config,
index 98f81df166e399ecbf674d53e603c7f00db2fd47..f99f9c1933524e6d06af64f191341fd67057dbce 100644 (file)
@@ -282,9 +282,9 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
        struct ieee80211_vif *vif = ctx->vif;
        struct iwl_host_cmd hcmd = {
                .id = REPLY_CHANNEL_SWITCH,
-               .len = sizeof(cmd),
+               .len = { sizeof(cmd), },
                .flags = CMD_SYNC,
-               .data = &cmd,
+               .data = { &cmd, },
        };
 
        cmd.band = priv->band == IEEE80211_BAND_2GHZ;
@@ -331,18 +331,12 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
                        ctx->active.channel, ch);
                return -EFAULT;
        }
-       priv->switch_rxon.channel = cmd.channel;
-       priv->switch_rxon.switch_in_progress = true;
 
        return iwl_send_cmd_sync(priv, &hcmd);
 }
 
 static struct iwl_lib_ops iwl5000_lib = {
        .set_hw_params = iwl5000_hw_set_hw_params,
-       .txq_set_sched = iwlagn_txq_set_sched,
-       .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
-       .txq_free_tfd = iwl_hw_txq_free_tfd,
-       .txq_init = iwl_hw_tx_queue_init,
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_setup_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
@@ -374,10 +368,6 @@ static struct iwl_lib_ops iwl5000_lib = {
 
 static struct iwl_lib_ops iwl5150_lib = {
        .set_hw_params = iwl5150_hw_set_hw_params,
-       .txq_set_sched = iwlagn_txq_set_sched,
-       .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
-       .txq_free_tfd = iwl_hw_txq_free_tfd,
-       .txq_init = iwl_hw_tx_queue_init,
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_setup_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
@@ -433,7 +423,6 @@ static struct iwl_base_params iwl5000_base_params = {
 };
 static struct iwl_ht_params iwl5000_ht_params = {
        .ht_greenfield_support = true,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
 };
 
 #define IWL_DEVICE_5000                                                \
index a7921f9a03c62488475ee76234918ced431b01b6..fbe565c816e32ce367c09dad8ef5762e4c819d86 100644 (file)
@@ -221,9 +221,9 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
        struct ieee80211_vif *vif = ctx->vif;
        struct iwl_host_cmd hcmd = {
                .id = REPLY_CHANNEL_SWITCH,
-               .len = sizeof(cmd),
+               .len = { sizeof(cmd), },
                .flags = CMD_SYNC,
-               .data = &cmd,
+               .data = { &cmd, },
        };
 
        cmd.band = priv->band == IEEE80211_BAND_2GHZ;
@@ -270,18 +270,12 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
                        ctx->active.channel, ch);
                return -EFAULT;
        }
-       priv->switch_rxon.channel = cmd.channel;
-       priv->switch_rxon.switch_in_progress = true;
 
        return iwl_send_cmd_sync(priv, &hcmd);
 }
 
 static struct iwl_lib_ops iwl6000_lib = {
        .set_hw_params = iwl6000_hw_set_hw_params,
-       .txq_set_sched = iwlagn_txq_set_sched,
-       .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
-       .txq_free_tfd = iwl_hw_txq_free_tfd,
-       .txq_init = iwl_hw_tx_queue_init,
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_setup_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
@@ -314,10 +308,6 @@ static struct iwl_lib_ops iwl6000_lib = {
 
 static struct iwl_lib_ops iwl6030_lib = {
        .set_hw_params = iwl6000_hw_set_hw_params,
-       .txq_set_sched = iwlagn_txq_set_sched,
-       .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
-       .txq_free_tfd = iwl_hw_txq_free_tfd,
-       .txq_init = iwl_hw_tx_queue_init,
        .rx_handler_setup = iwlagn_bt_rx_handler_setup,
        .setup_deferred_work = iwlagn_bt_setup_deferred_work,
        .cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
@@ -611,19 +601,27 @@ struct iwl_cfg iwl6050_2abg_cfg = {
        IWL_DEVICE_6050,
 };
 
+#define IWL_DEVICE_6150                                                \
+       .fw_name_pre = IWL6050_FW_PRE,                          \
+       .ucode_api_max = IWL6050_UCODE_API_MAX,                 \
+       .ucode_api_min = IWL6050_UCODE_API_MIN,                 \
+       .ops = &iwl6150_ops,                                    \
+       .eeprom_ver = EEPROM_6150_EEPROM_VERSION,               \
+       .eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION,       \
+       .base_params = &iwl6050_base_params,                    \
+       .need_dc_calib = true,                                  \
+       .led_mode = IWL_LED_BLINK,                              \
+       .internal_wimax_coex = true
+
 struct iwl_cfg iwl6150_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN",
-       .fw_name_pre = IWL6050_FW_PRE,
-       .ucode_api_max = IWL6050_UCODE_API_MAX,
-       .ucode_api_min = IWL6050_UCODE_API_MIN,
-       .eeprom_ver = EEPROM_6150_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION,
-       .ops = &iwl6150_ops,
-       .base_params = &iwl6050_base_params,
+       IWL_DEVICE_6150,
        .ht_params = &iwl6000_ht_params,
-       .need_dc_calib = true,
-       .led_mode = IWL_LED_RF_STATE,
-       .internal_wimax_coex = true,
+};
+
+struct iwl_cfg iwl6150_bg_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BG",
+       IWL_DEVICE_6150,
 };
 
 struct iwl_cfg iwl6000_3agn_cfg = {
index 39d1e47a0978dc15bcb1687f7b63f9aa0e8e2ed1..c9255def10801ca5c320ec255d296d991ddfa834 100644 (file)
@@ -87,14 +87,14 @@ int iwl_send_calib_results(struct iwl_priv *priv)
 
        struct iwl_host_cmd hcmd = {
                .id = REPLY_PHY_CALIBRATION_CMD,
-               .flags = CMD_SIZE_HUGE,
        };
 
        for (i = 0; i < IWL_CALIB_MAX; i++) {
                if ((BIT(i) & priv->hw_params.calib_init_cfg) &&
                    priv->calib_results[i].buf) {
-                       hcmd.len = priv->calib_results[i].buf_len;
-                       hcmd.data = priv->calib_results[i].buf;
+                       hcmd.len[0] = priv->calib_results[i].buf_len;
+                       hcmd.data[0] = priv->calib_results[i].buf;
+                       hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
                        ret = iwl_send_cmd_sync(priv, &hcmd);
                        if (ret) {
                                IWL_ERR(priv, "Error %d iteration %d\n",
@@ -456,9 +456,9 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
        struct iwl_sensitivity_data *data = NULL;
        struct iwl_host_cmd cmd_out = {
                .id = SENSITIVITY_CMD,
-               .len = sizeof(struct iwl_sensitivity_cmd),
+               .len = { sizeof(struct iwl_sensitivity_cmd), },
                .flags = CMD_ASYNC,
-               .data = &cmd,
+               .data = { &cmd, },
        };
 
        data = &(priv->sensitivity_data);
@@ -491,9 +491,9 @@ static int iwl_enhance_sensitivity_write(struct iwl_priv *priv)
        struct iwl_sensitivity_data *data = NULL;
        struct iwl_host_cmd cmd_out = {
                .id = SENSITIVITY_CMD,
-               .len = sizeof(struct iwl_enhance_sensitivity_cmd),
+               .len = { sizeof(struct iwl_enhance_sensitivity_cmd), },
                .flags = CMD_ASYNC,
-               .data = &cmd,
+               .data = { &cmd, },
        };
 
        data = &(priv->sensitivity_data);
index b12c72d63ccb94fd0e2628667ed8b1bbb3b2d5fd..23fa93deae96cce98916a467f68954845cc19759 100644 (file)
@@ -163,17 +163,9 @@ static void iwlagn_tx_cmd_protection(struct iwl_priv *priv,
                                     __le16 fc, __le32 *tx_flags)
 {
        if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS ||
-           info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+           info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT ||
+           info->flags & IEEE80211_TX_CTL_AMPDU)
                *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
-               return;
-       }
-
-       if (priv->cfg->ht_params &&
-           priv->cfg->ht_params->use_rts_for_aggregation &&
-           info->flags & IEEE80211_TX_CTL_AMPDU) {
-               *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
-               return;
-       }
 }
 
 /* Calc max signal level (dBm) among 3 possible receivers */
index 8e79653aed9aa799eb169713d2cde2843e920ec7..f803fb62f8bc0abee7a41d3d09ec3bdd35895cbe 100644 (file)
@@ -1140,8 +1140,7 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        struct iwl_host_cmd cmd = {
                .id = REPLY_SCAN_CMD,
-               .len = sizeof(struct iwl_scan_cmd),
-               .flags = CMD_SIZE_HUGE,
+               .len = { sizeof(struct iwl_scan_cmd), },
        };
        struct iwl_scan_cmd *scan;
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
@@ -1425,10 +1424,11 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
                return -EIO;
        }
 
-       cmd.len += le16_to_cpu(scan->tx_cmd.len) +
+       cmd.len[0] += le16_to_cpu(scan->tx_cmd.len) +
            scan->channel_count * sizeof(struct iwl_scan_channel);
-       cmd.data = scan;
-       scan->len = cpu_to_le16(cmd.len);
+       cmd.data[0] = scan;
+       cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
+       scan->len = cpu_to_le16(cmd.len[0]);
 
        /* set scan bit here for PAN params */
        set_bit(STATUS_SCAN_HW, &priv->status);
@@ -1520,9 +1520,9 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
        struct iwl_txfifo_flush_cmd flush_cmd;
        struct iwl_host_cmd cmd = {
                .id = REPLY_TXFIFO_FLUSH,
-               .len = sizeof(struct iwl_txfifo_flush_cmd),
+               .len = { sizeof(struct iwl_txfifo_flush_cmd), },
                .flags = CMD_SYNC,
-               .data = &flush_cmd,
+               .data = { &flush_cmd, },
        };
 
        might_sleep();
index 91f26556ac23880ca98461d5fa9b1975f1688d18..592b0cfcf717a7a9f76af9515ae77481dfda47bb 100644 (file)
@@ -335,6 +335,32 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
        return tid;
 }
 
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_program_fix_rate(struct iwl_priv *priv,
+                               struct iwl_lq_sta *lq_sta)
+{
+       struct iwl_station_priv *sta_priv =
+               container_of(lq_sta, struct iwl_station_priv, lq_sta);
+       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+
+       lq_sta->active_legacy_rate = 0x0FFF;    /* 1 - 54 MBits, includes CCK */
+       lq_sta->active_siso_rate   = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
+       lq_sta->active_mimo2_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
+       lq_sta->active_mimo3_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
+
+       lq_sta->dbg_fixed_rate = priv->dbg_fixed_rate;
+
+       IWL_DEBUG_RATE(priv, "sta_id %d rate 0x%X\n",
+               lq_sta->lq.sta_id, priv->dbg_fixed_rate);
+
+       if (priv->dbg_fixed_rate) {
+               rs_fill_link_cmd(NULL, lq_sta, priv->dbg_fixed_rate);
+               iwl_send_lq_cmd(lq_sta->drv, ctx, &lq_sta->lq, CMD_ASYNC,
+                               false);
+       }
+}
+#endif
+
 /*
        get the traffic load value for tid
 */
@@ -1046,7 +1072,10 @@ done:
        /* See if there's a better rate or modulation mode to try. */
        if (sta && sta->supp_rates[sband->band])
                rs_rate_scale_perform(priv, skb, sta, lq_sta);
-
+#ifdef CONFIG_MAC80211_DEBUGFS
+       if (priv->dbg_fixed_rate != lq_sta->dbg_fixed_rate)
+               rs_program_fix_rate(priv, lq_sta);
+#endif
        if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist)
                rs_bt_update_lq(priv, ctx, lq_sta);
 }
@@ -2170,11 +2199,11 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
  * setup rate table in uCode
  * return rate_n_flags as used in the table
  */
-static u32 rs_update_rate_tbl(struct iwl_priv *priv,
-                             struct iwl_rxon_context *ctx,
-                               struct iwl_lq_sta *lq_sta,
-                               struct iwl_scale_tbl_info *tbl,
-                               int index, u8 is_green)
+static void rs_update_rate_tbl(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx,
+                              struct iwl_lq_sta *lq_sta,
+                              struct iwl_scale_tbl_info *tbl,
+                              int index, u8 is_green)
 {
        u32 rate;
 
@@ -2182,8 +2211,6 @@ static u32 rs_update_rate_tbl(struct iwl_priv *priv,
        rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
        rs_fill_link_cmd(priv, lq_sta, rate);
        iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
-
-       return rate;
 }
 
 /*
@@ -2212,7 +2239,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        u8 update_lq = 0;
        struct iwl_scale_tbl_info *tbl, *tbl1;
        u16 rate_scale_index_msk = 0;
-       u32 rate;
        u8 is_green = 0;
        u8 active_tbl = 0;
        u8 done_search = 0;
@@ -2299,8 +2325,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
                        tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
                        /* get "active" rate info */
                        index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
-                       rate = rs_update_rate_tbl(priv, ctx, lq_sta,
-                                                 tbl, index, is_green);
+                       rs_update_rate_tbl(priv, ctx, lq_sta, tbl,
+                                          index, is_green);
                }
                return;
        }
@@ -2541,8 +2567,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 lq_update:
        /* Replace uCode's rate table for the destination station. */
        if (update_lq)
-               rate = rs_update_rate_tbl(priv, ctx, lq_sta,
-                                         tbl, index, is_green);
+               rs_update_rate_tbl(priv, ctx, lq_sta, tbl, index, is_green);
 
        if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI) {
                /* Should we stay with this modulation mode,
@@ -2871,6 +2896,7 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i
                lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
        lq_sta->is_agg = 0;
 
+       priv->dbg_fixed_rate = 0;
 #ifdef CONFIG_MAC80211_DEBUGFS
        lq_sta->dbg_fixed_rate = 0;
 #endif
@@ -3045,7 +3071,6 @@ static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
        IWL_DEBUG_RATE(priv, "leave\n");
 }
 
-
 #ifdef CONFIG_MAC80211_DEBUGFS
 static int open_file_generic(struct inode *inode, struct file *file)
 {
@@ -3070,6 +3095,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
                        IWL_DEBUG_RATE(priv, "Fixed rate ON\n");
                } else {
                        lq_sta->dbg_fixed_rate = 0;
+                       priv->dbg_fixed_rate = 0;
                        IWL_ERR(priv,
                            "Invalid antenna selection 0x%X, Valid is 0x%X\n",
                            ant_sel_tx, valid_tx_ant);
@@ -3088,9 +3114,7 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
        char buf[64];
        size_t buf_size;
        u32 parsed_rate;
-       struct iwl_station_priv *sta_priv =
-               container_of(lq_sta, struct iwl_station_priv, lq_sta);
-       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+
 
        priv = lq_sta->drv;
        memset(buf, 0, sizeof(buf));
@@ -3099,23 +3123,11 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
                return -EFAULT;
 
        if (sscanf(buf, "%x", &parsed_rate) == 1)
-               lq_sta->dbg_fixed_rate = parsed_rate;
+               priv->dbg_fixed_rate = lq_sta->dbg_fixed_rate = parsed_rate;
        else
-               lq_sta->dbg_fixed_rate = 0;
+               priv->dbg_fixed_rate = lq_sta->dbg_fixed_rate = 0;
 
-       lq_sta->active_legacy_rate = 0x0FFF;    /* 1 - 54 MBits, includes CCK */
-       lq_sta->active_siso_rate   = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
-       lq_sta->active_mimo2_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
-       lq_sta->active_mimo3_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
-
-       IWL_DEBUG_RATE(priv, "sta_id %d rate 0x%X\n",
-               lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
-
-       if (lq_sta->dbg_fixed_rate) {
-               rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
-               iwl_send_lq_cmd(lq_sta->drv, ctx, &lq_sta->lq, CMD_ASYNC,
-                               false);
-       }
+       rs_program_fix_rate(priv, lq_sta);
 
        return count;
 }
@@ -3143,7 +3155,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
                        lq_sta->total_failed, lq_sta->total_success,
                        lq_sta->active_legacy_rate);
        desc += sprintf(buff+desc, "fixed rate 0x%X\n",
-                       lq_sta->dbg_fixed_rate);
+                       priv->dbg_fixed_rate);
        desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
            (priv->hw_params.valid_tx_ant & ANT_A) ? "ANT_A," : "",
            (priv->hw_params.valid_tx_ant & ANT_B) ? "ANT_B," : "",
@@ -3254,14 +3266,10 @@ static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
 static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file,
                        char __user *user_buf, size_t count, loff_t *ppos)
 {
-       char buff[120];
-       int desc = 0;
-
        struct iwl_lq_sta *lq_sta = file->private_data;
-       struct iwl_priv *priv;
        struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl];
-
-       priv = lq_sta->drv;
+       char buff[120];
+       int desc = 0;
 
        if (is_Ht(tbl->lq_type))
                desc += sprintf(buff+desc,
index 02387430f7fe0dddae5006aa80e59301c19ecaec..09f679d6046f94ddc4ed8be2ae9b5fd12e1b64a4 100644 (file)
@@ -289,7 +289,6 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
        /* cast away the const for active_rxon in this function */
        struct iwl_rxon_cmd *active = (void *)&ctx->active;
        bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
-       bool old_assoc = !!(ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK);
        int ret;
 
        lockdep_assert_held(&priv->mutex);
@@ -326,6 +325,14 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
                        return 0;
        }
 
+       /*
+        * force CTS-to-self frames protection if RTS-CTS is not preferred
+        * one aggregation protection method
+        */
+       if (!(priv->cfg->ht_params &&
+             priv->cfg->ht_params->use_rts_for_aggregation))
+               ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
+
        if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) ||
            !(ctx->staging.flags & RXON_FLG_BAND_24G_MSK))
                ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
@@ -343,10 +350,10 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
         * receive commit_rxon request
         * abort any previous channel switch if still in process
         */
-       if (priv->switch_rxon.switch_in_progress &&
-           (priv->switch_rxon.channel != ctx->staging.channel)) {
+       if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status) &&
+           (priv->switch_channel != ctx->staging.channel)) {
                IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
-                     le16_to_cpu(priv->switch_rxon.channel));
+                             le16_to_cpu(priv->switch_channel));
                iwl_chswitch_done(priv, false);
        }
 
@@ -363,6 +370,11 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
                }
 
                memcpy(active, &ctx->staging, sizeof(*active));
+               /*
+                * We do not commit tx power settings while channel changing,
+                * do it now if after settings changed.
+                */
+               iwl_set_tx_power(priv, priv->tx_power_next, false);
                return 0;
        }
 
@@ -389,11 +401,9 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
         * AP station must be done after the BSSID is set to correctly
         * set up filters in the device.
         */
-       if ((old_assoc && new_assoc) || !new_assoc) {
-               ret = iwlagn_rxon_disconn(priv, ctx);
-               if (ret)
-                       return ret;
-       }
+       ret = iwlagn_rxon_disconn(priv, ctx);
+       if (ret)
+               return ret;
 
        if (new_assoc)
                return iwlagn_rxon_connect(priv, ctx);
index 079275f2c64d919102b40c97ad3900ba79899265..0bd722cee5ae0cf3a3f2c8429fa07aa118bfbacf 100644 (file)
@@ -144,7 +144,7 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv,
        size_t cmd_size  = sizeof(struct iwl_wep_cmd);
        struct iwl_host_cmd cmd = {
                .id = ctx->wep_key_cmd,
-               .data = wep_cmd,
+               .data = { wep_cmd, },
                .flags = CMD_SYNC,
        };
 
@@ -172,7 +172,7 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv,
 
        cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX;
 
-       cmd.len = cmd_size;
+       cmd.len[0] = cmd_size;
 
        if (not_empty || send_if_empty)
                return iwl_send_cmd(priv, &cmd);
index 342de780a3661dd08f8c41e79eaacfa0f3dbe356..4974cd7837cbecb92a40f6d757eaa42a75235024 100644 (file)
@@ -755,12 +755,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        spin_unlock(&priv->sta_lock);
 
        /* Attach buffers to TFD */
-       priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
-                                                  txcmd_phys, firstlen, 1, 0);
+       iwlagn_txq_attach_buf_to_tfd(priv, txq, txcmd_phys, firstlen, 1);
        if (secondlen > 0)
-               priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
-                                                          phys_addr, secondlen,
-                                                          0, 0);
+               iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr,
+                                            secondlen, 0);
 
        scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
                                offsetof(struct iwl_tx_cmd, scratch);
@@ -916,7 +914,7 @@ int iwlagn_txq_ctx_alloc(struct iwl_priv *priv)
        spin_lock_irqsave(&priv->lock, flags);
 
        /* Turn off all Tx DMA fifos */
-       priv->cfg->ops->lib->txq_set_sched(priv, 0);
+       iwlagn_txq_set_sched(priv, 0);
 
        /* Tell NIC where to find the "keep warm" buffer */
        iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
@@ -954,7 +952,7 @@ void iwlagn_txq_ctx_reset(struct iwl_priv *priv)
        spin_lock_irqsave(&priv->lock, flags);
 
        /* Turn off all Tx DMA fifos */
-       priv->cfg->ops->lib->txq_set_sched(priv, 0);
+       iwlagn_txq_set_sched(priv, 0);
 
        /* Tell NIC where to find the "keep warm" buffer */
        iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
@@ -980,7 +978,7 @@ void iwlagn_txq_ctx_stop(struct iwl_priv *priv)
        /* Turn off all Tx DMA fifos */
        spin_lock_irqsave(&priv->lock, flags);
 
-       priv->cfg->ops->lib->txq_set_sched(priv, 0);
+       iwlagn_txq_set_sched(priv, 0);
 
        /* Stop each Tx DMA channel, and wait for it to be idle */
        for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) {
@@ -1263,7 +1261,7 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
 
                iwlagn_txq_inval_byte_cnt_tbl(priv, txq);
 
-               priv->cfg->ops->lib->txq_free_tfd(priv, txq);
+               iwlagn_txq_free_tfd(priv, txq);
        }
        return nfreed;
 }
index 8bda0e8d666184ab58322cabef88e8424ec47e12..97de5d9de67b5421582ee9c60f9f555f141f3684 100644 (file)
@@ -217,8 +217,8 @@ static int iwlagn_send_calib_cfg(struct iwl_priv *priv)
        struct iwl_calib_cfg_cmd calib_cfg_cmd;
        struct iwl_host_cmd cmd = {
                .id = CALIBRATION_CFG_CMD,
-               .len = sizeof(struct iwl_calib_cfg_cmd),
-               .data = &calib_cfg_cmd,
+               .len = { sizeof(struct iwl_calib_cfg_cmd), },
+               .data = { &calib_cfg_cmd, },
        };
 
        memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
@@ -440,7 +440,7 @@ static int iwlagn_alive_notify(struct iwl_priv *priv)
                        IWL_MASK(0, priv->hw_params.max_txq_num));
 
        /* Activate all Tx DMA/FIFO channels */
-       priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
+       iwlagn_txq_set_sched(priv, IWL_MASK(0, 7));
 
        /* map queues to FIFOs */
        if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
index 08e3cae4fa5a1a128fd15af1d8bddbe15b1338fe..8e1942ebd9a07aedc7c5e4c69a04b4ff690070a6 100644 (file)
@@ -134,12 +134,10 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
        struct iwl_tx_beacon_cmd *tx_beacon_cmd;
        struct iwl_host_cmd cmd = {
                .id = REPLY_TX_BEACON,
-               .flags = CMD_SIZE_HUGE,
        };
        u32 frame_size;
        u32 rate_flags;
        u32 rate;
-       int err;
 
        /*
         * We have to set up the TX command, the TX Beacon command, and the
@@ -156,17 +154,15 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
        if (WARN_ON(!priv->beacon_skb))
                return -EINVAL;
 
-       /* Allocate beacon memory */
-       tx_beacon_cmd = kzalloc(sizeof(*tx_beacon_cmd) + priv->beacon_skb->len,
-                               GFP_KERNEL);
+       /* Allocate beacon command */
+       if (!priv->beacon_cmd)
+               priv->beacon_cmd = kzalloc(sizeof(*tx_beacon_cmd), GFP_KERNEL);
+       tx_beacon_cmd = priv->beacon_cmd;
        if (!tx_beacon_cmd)
                return -ENOMEM;
 
        frame_size = priv->beacon_skb->len;
 
-       /* Set up TX beacon contents */
-       memcpy(tx_beacon_cmd->frame, priv->beacon_skb->data, frame_size);
-
        /* Set up TX command fields */
        tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
        tx_beacon_cmd->tx.sta_id = priv->beacon_ctx->bcast_sta_id;
@@ -175,7 +171,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
                TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK;
 
        /* Set up TX beacon command fields */
-       iwl_set_beacon_tim(priv, tx_beacon_cmd, (u8 *)tx_beacon_cmd->frame,
+       iwl_set_beacon_tim(priv, tx_beacon_cmd, priv->beacon_skb->data,
                           frame_size);
 
        /* Set up packet rate and flags */
@@ -189,164 +185,14 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
                        rate_flags);
 
        /* Submit command */
-       cmd.len = sizeof(*tx_beacon_cmd) + frame_size;
-       cmd.data = tx_beacon_cmd;
-
-       err = iwl_send_cmd_sync(priv, &cmd);
-
-       /* Free temporary storage */
-       kfree(tx_beacon_cmd);
-
-       return err;
-}
-
-static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
-{
-       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
-
-       dma_addr_t addr = get_unaligned_le32(&tb->lo);
-       if (sizeof(dma_addr_t) > sizeof(u32))
-               addr |=
-               ((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16;
-
-       return addr;
-}
-
-static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
-{
-       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
-
-       return le16_to_cpu(tb->hi_n_len) >> 4;
-}
-
-static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx,
-                                 dma_addr_t addr, u16 len)
-{
-       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
-       u16 hi_n_len = len << 4;
-
-       put_unaligned_le32(addr, &tb->lo);
-       if (sizeof(dma_addr_t) > sizeof(u32))
-               hi_n_len |= ((addr >> 16) >> 16) & 0xF;
-
-       tb->hi_n_len = cpu_to_le16(hi_n_len);
-
-       tfd->num_tbs = idx + 1;
-}
-
-static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd)
-{
-       return tfd->num_tbs & 0x1f;
-}
-
-/**
- * iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
- * @priv - driver private data
- * @txq - tx queue
- *
- * Does NOT advance any TFD circular buffer read/write indexes
- * Does NOT free the TFD itself (which is within circular buffer)
- */
-void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
-{
-       struct iwl_tfd *tfd_tmp = (struct iwl_tfd *)txq->tfds;
-       struct iwl_tfd *tfd;
-       struct pci_dev *dev = priv->pci_dev;
-       int index = txq->q.read_ptr;
-       int i;
-       int num_tbs;
-
-       tfd = &tfd_tmp[index];
-
-       /* Sanity check on number of chunks */
-       num_tbs = iwl_tfd_get_num_tbs(tfd);
-
-       if (num_tbs >= IWL_NUM_OF_TBS) {
-               IWL_ERR(priv, "Too many chunks: %i\n", num_tbs);
-               /* @todo issue fatal error, it is quite serious situation */
-               return;
-       }
+       cmd.len[0] = sizeof(*tx_beacon_cmd);
+       cmd.data[0] = tx_beacon_cmd;
+       cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
+       cmd.len[1] = frame_size;
+       cmd.data[1] = priv->beacon_skb->data;
+       cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY;
 
-       /* Unmap tx_cmd */
-       if (num_tbs)
-               pci_unmap_single(dev,
-                               dma_unmap_addr(&txq->meta[index], mapping),
-                               dma_unmap_len(&txq->meta[index], len),
-                               PCI_DMA_BIDIRECTIONAL);
-
-       /* Unmap chunks, if any. */
-       for (i = 1; i < num_tbs; i++)
-               pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i),
-                               iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE);
-
-       /* free SKB */
-       if (txq->txb) {
-               struct sk_buff *skb;
-
-               skb = txq->txb[txq->q.read_ptr].skb;
-
-               /* can be called from irqs-disabled context */
-               if (skb) {
-                       dev_kfree_skb_any(skb);
-                       txq->txb[txq->q.read_ptr].skb = NULL;
-               }
-       }
-}
-
-int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
-                                struct iwl_tx_queue *txq,
-                                dma_addr_t addr, u16 len,
-                                u8 reset, u8 pad)
-{
-       struct iwl_queue *q;
-       struct iwl_tfd *tfd, *tfd_tmp;
-       u32 num_tbs;
-
-       q = &txq->q;
-       tfd_tmp = (struct iwl_tfd *)txq->tfds;
-       tfd = &tfd_tmp[q->write_ptr];
-
-       if (reset)
-               memset(tfd, 0, sizeof(*tfd));
-
-       num_tbs = iwl_tfd_get_num_tbs(tfd);
-
-       /* Each TFD can point to a maximum 20 Tx buffers */
-       if (num_tbs >= IWL_NUM_OF_TBS) {
-               IWL_ERR(priv, "Error can not send more than %d chunks\n",
-                         IWL_NUM_OF_TBS);
-               return -EINVAL;
-       }
-
-       if (WARN_ON(addr & ~DMA_BIT_MASK(36)))
-               return -EINVAL;
-
-       if (unlikely(addr & ~IWL_TX_DMA_MASK))
-               IWL_ERR(priv, "Unaligned address = %llx\n",
-                         (unsigned long long)addr);
-
-       iwl_tfd_set_tb(tfd, num_tbs, addr, len);
-
-       return 0;
-}
-
-/*
- * Tell nic where to find circular buffer of Tx Frame Descriptors for
- * given Tx queue, and enable the DMA channel used for that queue.
- *
- * supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
- * channels supported in hardware.
- */
-int iwl_hw_tx_queue_init(struct iwl_priv *priv,
-                        struct iwl_tx_queue *txq)
-{
-       int txq_id = txq->q.id;
-
-       /* Circular buffer (TFD queue in DRAM) physical base address */
-       iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
-                            txq->q.dma_addr >> 8);
-
-       return 0;
+       return iwl_send_cmd_sync(priv, &cmd);
 }
 
 static void iwl_bg_beacon_update(struct work_struct *work)
@@ -1776,10 +1622,7 @@ static const char *desc_lookup(u32 num)
 
 void iwl_dump_nic_error_log(struct iwl_priv *priv)
 {
-       u32 data2, line;
-       u32 desc, time, count, base, data1;
-       u32 blink1, blink2, ilink1, ilink2;
-       u32 pc, hcmd;
+       u32 base;
        struct iwl_error_event_table table;
 
        base = priv->device_pointers.error_event_table;
@@ -1802,37 +1645,40 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
 
        iwl_read_targ_mem_words(priv, base, &table, sizeof(table));
 
-       count = table.valid;
-
-       if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+       if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
                IWL_ERR(priv, "Start IWL Error Log Dump:\n");
                IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
-                       priv->status, count);
-       }
-
-       desc = table.error_id;
-       priv->isr_stats.err_code = desc;
-       pc = table.pc;
-       blink1 = table.blink1;
-       blink2 = table.blink2;
-       ilink1 = table.ilink1;
-       ilink2 = table.ilink2;
-       data1 = table.data1;
-       data2 = table.data2;
-       line = table.line;
-       time = table.tsf_low;
-       hcmd = table.hcmd;
-
-       trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line,
-                                     blink1, blink2, ilink1, ilink2);
-
-       IWL_ERR(priv, "Desc                                  Time       "
-               "data1      data2      line\n");
-       IWL_ERR(priv, "%-28s (0x%04X) %010u 0x%08X 0x%08X %u\n",
-               desc_lookup(desc), desc, time, data1, data2, line);
-       IWL_ERR(priv, "pc      blink1  blink2  ilink1  ilink2  hcmd\n");
-       IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X 0x%05X 0x%05X\n",
-               pc, blink1, blink2, ilink1, ilink2, hcmd);
+                       priv->status, table.valid);
+       }
+
+       priv->isr_stats.err_code = table.error_id;
+
+       trace_iwlwifi_dev_ucode_error(priv, table.error_id, table.tsf_low,
+                                     table.data1, table.data2, table.line,
+                                     table.blink1, table.blink2, table.ilink1,
+                                     table.ilink2, table.bcon_time, table.gp1,
+                                     table.gp2, table.gp3, table.ucode_ver,
+                                     table.hw_ver, table.brd_ver);
+       IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id,
+               desc_lookup(table.error_id));
+       IWL_ERR(priv, "0x%08X | uPc\n", table.pc);
+       IWL_ERR(priv, "0x%08X | branchlink1\n", table.blink1);
+       IWL_ERR(priv, "0x%08X | branchlink2\n", table.blink2);
+       IWL_ERR(priv, "0x%08X | interruptlink1\n", table.ilink1);
+       IWL_ERR(priv, "0x%08X | interruptlink2\n", table.ilink2);
+       IWL_ERR(priv, "0x%08X | data1\n", table.data1);
+       IWL_ERR(priv, "0x%08X | data2\n", table.data2);
+       IWL_ERR(priv, "0x%08X | line\n", table.line);
+       IWL_ERR(priv, "0x%08X | beacon time\n", table.bcon_time);
+       IWL_ERR(priv, "0x%08X | tsf low\n", table.tsf_low);
+       IWL_ERR(priv, "0x%08X | tsf hi\n", table.tsf_hi);
+       IWL_ERR(priv, "0x%08X | time gp1\n", table.gp1);
+       IWL_ERR(priv, "0x%08X | time gp2\n", table.gp2);
+       IWL_ERR(priv, "0x%08X | time gp3\n", table.gp3);
+       IWL_ERR(priv, "0x%08X | uCode version\n", table.ucode_ver);
+       IWL_ERR(priv, "0x%08X | hw version\n", table.hw_ver);
+       IWL_ERR(priv, "0x%08X | board version\n", table.brd_ver);
+       IWL_ERR(priv, "0x%08X | hcmd\n", table.hcmd);
 }
 
 #define EVENT_START_OFFSET  (4 * sizeof(u32))
@@ -2114,8 +1960,8 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg)
        struct iwl_calib_cfg_cmd calib_cfg_cmd;
        struct iwl_host_cmd cmd = {
                .id = CALIBRATION_CFG_CMD,
-               .len = sizeof(struct iwl_calib_cfg_cmd),
-               .data = &calib_cfg_cmd,
+               .len = { sizeof(struct iwl_calib_cfg_cmd), },
+               .data = { &calib_cfg_cmd, },
        };
 
        memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
@@ -2997,16 +2843,13 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
                goto out;
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
-           test_bit(STATUS_SCANNING, &priv->status))
+           test_bit(STATUS_SCANNING, &priv->status) ||
+           test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
                goto out;
 
        if (!iwl_is_associated_ctx(ctx))
                goto out;
 
-       /* channel switch in progress */
-       if (priv->switch_rxon.switch_in_progress == true)
-               goto out;
-
        if (priv->cfg->ops->lib->set_channel_switch) {
 
                ch = channel->hw_value;
@@ -3055,15 +2898,19 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
                         * at this point, staging_rxon has the
                         * configuration for channel switch
                         */
+                       set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
+                       priv->switch_channel = cpu_to_le16(ch);
                        if (priv->cfg->ops->lib->set_channel_switch(priv,
-                                                                   ch_switch))
-                               priv->switch_rxon.switch_in_progress = false;
+                                                                   ch_switch)) {
+                               clear_bit(STATUS_CHANNEL_SWITCH_PENDING,
+                                         &priv->status);
+                               priv->switch_channel = 0;
+                               ieee80211_chswitch_done(ctx->vif, false);
+                       }
                }
        }
 out:
        mutex_unlock(&priv->mutex);
-       if (!priv->switch_rxon.switch_in_progress)
-               ieee80211_chswitch_done(ctx->vif, false);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
@@ -3395,6 +3242,7 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
        iwlcore_free_geos(priv);
        iwl_free_channel_map(priv);
        kfree(priv->scan_cmd);
+       kfree(priv->beacon_cmd);
 }
 
 struct ieee80211_ops iwlagn_hw_ops = {
@@ -3812,6 +3660,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
         */
        set_bit(STATUS_EXIT_PENDING, &priv->status);
 
+       iwl_testmode_cleanup(priv);
        iwl_leds_exit(priv);
 
        if (priv->mac80211_registered) {
@@ -3983,11 +3832,11 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
 
 /* 6150 WiFi/WiMax Series */
        {IWL_PCI_DEVICE(0x0885, 0x1305, iwl6150_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0885, 0x1306, iwl6150_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0885, 0x1307, iwl6150_bg_cfg)},
        {IWL_PCI_DEVICE(0x0885, 0x1325, iwl6150_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0885, 0x1326, iwl6150_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0885, 0x1327, iwl6150_bg_cfg)},
        {IWL_PCI_DEVICE(0x0886, 0x1315, iwl6150_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0886, 0x1316, iwl6150_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0886, 0x1317, iwl6150_bg_cfg)},
 
 /* 1000 Series WiFi */
        {IWL_PCI_DEVICE(0x0083, 0x1205, iwl1000_bgn_cfg)},
index fe33fe8aa4185ed0a47bb668048745df7cd32e0b..d1716844002eae2ea5ded5e2fe9724317964ffb8 100644 (file)
@@ -89,6 +89,7 @@ extern struct iwl_cfg iwl6000_3agn_cfg;
 extern struct iwl_cfg iwl6050_2agn_cfg;
 extern struct iwl_cfg iwl6050_2abg_cfg;
 extern struct iwl_cfg iwl6150_bgn_cfg;
+extern struct iwl_cfg iwl6150_bg_cfg;
 extern struct iwl_cfg iwl1000_bgn_cfg;
 extern struct iwl_cfg iwl1000_bg_cfg;
 extern struct iwl_cfg iwl100_bgn_cfg;
@@ -191,12 +192,10 @@ int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
 void iwl_setup_rx_handlers(struct iwl_priv *priv);
 
 /* tx */
-void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
-int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
+void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv,
                                 struct iwl_tx_queue *txq,
-                                dma_addr_t addr, u16 len, u8 reset, u8 pad);
-int iwl_hw_tx_queue_init(struct iwl_priv *priv,
-                        struct iwl_tx_queue *txq);
+                                dma_addr_t addr, u16 len, u8 reset);
 void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
                              struct ieee80211_tx_info *info);
 int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
@@ -345,6 +344,7 @@ extern int iwl_alive_start(struct iwl_priv *priv);
 #ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
 extern int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len);
 extern void iwl_testmode_init(struct iwl_priv *priv);
+extern void iwl_testmode_cleanup(struct iwl_priv *priv);
 #else
 static inline
 int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
@@ -355,6 +355,10 @@ static inline
 void iwl_testmode_init(struct iwl_priv *priv)
 {
 }
+static inline
+void iwl_testmode_cleanup(struct iwl_priv *priv)
+{
+}
 #endif
 
 #endif /* __iwl_agn_h__ */
index 5fdad6532118884aebdbf9854597cbf2e0928ad6..6ee5f1aa555ca76af578642459fc178189f62db3 100644 (file)
@@ -205,7 +205,6 @@ enum {
 #define QUEUE_TO_SEQ(q)        (((q) & 0x1f) << 8)
 #define SEQ_TO_INDEX(s)        ((s) & 0xff)
 #define INDEX_TO_SEQ(i)        ((i) & 0xff)
-#define SEQ_HUGE_FRAME cpu_to_le16(0x4000)
 #define SEQ_RX_FRAME   cpu_to_le16(0x8000)
 
 /**
@@ -234,9 +233,7 @@ struct iwl_cmd_header {
         *
         *  0:7         tfd index - position within TX queue
         *  8:12        TX queue id
-        *  13          reserved
-        *  14          huge - driver sets this to indicate command is in the
-        *              'huge' storage at the end of the command buffers
+        *  13:14       reserved
         *  15          unsolicited RX or uCode-originated notification
         */
        __le16 sequence;
index 4653deada05b48b1383f1cda6b33c7477a1717d3..213c80c6a6682d000efff4b0d356cb5bafa691d4 100644 (file)
@@ -843,12 +843,8 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       if (priv->switch_rxon.switch_in_progress) {
+       if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
                ieee80211_chswitch_done(ctx->vif, is_success);
-               mutex_lock(&priv->mutex);
-               priv->switch_rxon.switch_in_progress = false;
-               mutex_unlock(&priv->mutex);
-       }
 }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
index 5b5b0cce4a54e7c85d89fb5e45e4b9c7c2853b97..a54d416ec345ce1b71d657de3ec92d4c5efb8ea6 100644 (file)
@@ -127,16 +127,6 @@ struct iwl_temp_ops {
 struct iwl_lib_ops {
        /* set hw dependent parameters */
        int (*set_hw_params)(struct iwl_priv *priv);
-       /* Handling TX */
-       void (*txq_set_sched)(struct iwl_priv *priv, u32 mask);
-       int (*txq_attach_buf_to_tfd)(struct iwl_priv *priv,
-                                    struct iwl_tx_queue *txq,
-                                    dma_addr_t addr,
-                                    u16 len, u8 reset, u8 pad);
-       void (*txq_free_tfd)(struct iwl_priv *priv,
-                            struct iwl_tx_queue *txq);
-       int (*txq_init)(struct iwl_priv *priv,
-                       struct iwl_tx_queue *txq);
        /* setup Rx handler */
        void (*rx_handler_setup)(struct iwl_priv *priv);
        /* setup deferred work */
@@ -570,6 +560,7 @@ void iwlcore_free_geos(struct iwl_priv *priv);
 #define STATUS_POWER_PMI       16
 #define STATUS_FW_ERROR                17
 #define STATUS_DEVICE_ENABLED  18
+#define STATUS_CHANNEL_SWITCH_PENDING 19
 
 
 static inline int iwl_is_ready(struct iwl_priv *priv)
index 214e4658c4951ffaff35ddc379b2dec5ffcb0f3e..c8de236c141be303d7ff6db5d058f4bfb093687f 100644 (file)
@@ -48,8 +48,6 @@
 #include "iwl-agn-rs.h"
 #include "iwl-agn-tt.h"
 
-#define U32_PAD(n)             ((4-(n))&0x3)
-
 struct iwl_tx_queue;
 
 /* CT-KILL constants */
@@ -83,7 +81,7 @@ struct iwl_tx_queue;
 #define MAX_RTS_THRESHOLD         2347U
 #define MAX_MSDU_SIZE            2304U
 #define MAX_MPDU_SIZE            2346U
-#define DEFAULT_BEACON_INTERVAL   100U
+#define DEFAULT_BEACON_INTERVAL   200U
 #define        DEFAULT_SHORT_RETRY_LIMIT 7U
 #define        DEFAULT_LONG_RETRY_LIMIT  4U
 
@@ -112,8 +110,6 @@ struct iwl_cmd_meta {
                         struct iwl_device_cmd *cmd,
                         struct iwl_rx_packet *pkt);
 
-       /* The CMD_SIZE_HUGE flag bit indicates that the command
-        * structure is stored at the end of the shared queue memory. */
        u32 flags;
 
        DEFINE_DMA_UNMAP_ADDR(mapping);
@@ -123,7 +119,23 @@ struct iwl_cmd_meta {
 /*
  * Generic queue structure
  *
- * Contains common data for Rx and Tx queues
+ * Contains common data for Rx and Tx queues.
+ *
+ * Note the difference between n_bd and n_window: the hardware
+ * always assumes 256 descriptors, so n_bd is always 256 (unless
+ * there might be HW changes in the future). For the normal TX
+ * queues, n_window, which is the size of the software queue data
+ * is also 256; however, for the command queue, n_window is only
+ * 32 since we don't need so many commands pending. Since the HW
+ * still uses 256 BDs for DMA though, n_bd stays 256. As a result,
+ * the software buffers (in the variables @meta, @txb in struct
+ * iwl_tx_queue) only have 32 entries, while the HW buffers (@tfds
+ * in the same struct) have 256.
+ * This means that we end up with the following:
+ *  HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 |
+ *  SW entries:           | 0      | ... | 31          |
+ * where N is a number between 0 and 7. This means that the SW
+ * data is a window overlayed over the HW queue.
  */
 struct iwl_queue {
        int n_bd;              /* number of BDs in this queue */
@@ -165,7 +177,7 @@ struct iwl_tx_info {
 
 struct iwl_tx_queue {
        struct iwl_queue q;
-       void *tfds;
+       struct iwl_tfd *tfds;
        struct iwl_device_cmd **cmd;
        struct iwl_cmd_meta *meta;
        struct iwl_tx_info *txb;
@@ -247,7 +259,6 @@ enum {
        CMD_SYNC = 0,
        CMD_SIZE_NORMAL = 0,
        CMD_NO_SKB = 0,
-       CMD_SIZE_HUGE = (1 << 0),
        CMD_ASYNC = (1 << 1),
        CMD_WANT_SKB = (1 << 2),
        CMD_MAPPED = (1 << 3),
@@ -259,8 +270,8 @@ enum {
  * struct iwl_device_cmd
  *
  * For allocation of the command and tx queues, this establishes the overall
- * size of the largest command we send to uCode, except for a scan command
- * (which is relatively huge; space is allocated separately).
+ * size of the largest command we send to uCode, except for commands that
+ * aren't fully copied and use other TFD space.
  */
 struct iwl_device_cmd {
        struct iwl_cmd_header hdr;      /* uCode API */
@@ -277,15 +288,21 @@ struct iwl_device_cmd {
 
 #define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
 
+#define IWL_MAX_CMD_TFDS       2
+
+enum iwl_hcmd_dataflag {
+       IWL_HCMD_DFL_NOCOPY     = BIT(0),
+};
 
 struct iwl_host_cmd {
-       const void *data;
+       const void *data[IWL_MAX_CMD_TFDS];
        unsigned long reply_page;
        void (*callback)(struct iwl_priv *priv,
                         struct iwl_device_cmd *cmd,
                         struct iwl_rx_packet *pkt);
        u32 flags;
-       u16 len;
+       u16 len[IWL_MAX_CMD_TFDS];
+       u8 dataflags[IWL_MAX_CMD_TFDS];
        u8 id;
 };
 
@@ -688,17 +705,8 @@ static inline int iwl_queue_used(const struct iwl_queue *q, int i)
 }
 
 
-static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
+static inline u8 get_cmd_index(struct iwl_queue *q, u32 index)
 {
-       /*
-        * This is for init calibration result and scan command which
-        * required buffer > TFD_MAX_PAYLOAD_SIZE,
-        * the big buffer at end of command array
-        */
-       if (is_huge)
-               return q->n_window;     /* must be power of 2 */
-
-       /* Otherwise, use normal size buffers */
        return index & (q->n_window - 1);
 }
 
@@ -973,17 +981,6 @@ struct traffic_stats {
 #endif
 };
 
-/*
- * iwl_switch_rxon: "channel switch" structure
- *
- * @ switch_in_progress: channel switch in progress
- * @ channel: new channel
- */
-struct iwl_switch_rxon {
-       bool switch_in_progress;
-       __le16 channel;
-};
-
 /*
  * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds
  * to perform continuous uCode event logging operation if enabled
@@ -1171,6 +1168,14 @@ enum iwl_scan_type {
        IWL_SCAN_OFFCH_TX,
 };
 
+#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
+struct iwl_testmode_trace {
+       u8 *cpu_addr;
+       u8 *trace_addr;
+       dma_addr_t dma_addr;
+       bool trace_enabled;
+};
+#endif
 struct iwl_priv {
 
        /* ieee device used by generic ieee processing code */
@@ -1271,7 +1276,7 @@ struct iwl_priv {
 
        struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX];
 
-       struct iwl_switch_rxon switch_rxon;
+       __le16 switch_channel;
 
        struct {
                u32 error_event_table;
@@ -1452,6 +1457,7 @@ struct iwl_priv {
        struct work_struct beacon_update;
        struct iwl_rxon_context *beacon_ctx;
        struct sk_buff *beacon_skb;
+       void *beacon_cmd;
 
        struct work_struct tt_work;
        struct work_struct ct_enter;
@@ -1501,6 +1507,11 @@ struct iwl_priv {
        struct led_classdev led;
        unsigned long blink_on, blink_off;
        bool led_registered;
+#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
+       struct iwl_testmode_trace testmode_trace;
+#endif
+       u32 dbg_fixed_rate;
+
 }; /*iwl_priv */
 
 static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
index f00172cb8a6dda1bc8975dbb6838954bc3f923d4..2c84ba95afca77f70cbdc9171552dacfa7853fcc 100644 (file)
@@ -137,20 +137,27 @@ TRACE_EVENT(iwlwifi_dev_ucode_wrap_event,
 #define TRACE_SYSTEM iwlwifi
 
 TRACE_EVENT(iwlwifi_dev_hcmd,
-       TP_PROTO(struct iwl_priv *priv, void *hcmd, size_t len, u32 flags),
-       TP_ARGS(priv, hcmd, len, flags),
+       TP_PROTO(struct iwl_priv *priv, u32 flags,
+                const void *hcmd0, size_t len0,
+                const void *hcmd1, size_t len1,
+                const void *hcmd2, size_t len2),
+       TP_ARGS(priv, flags, hcmd0, len0, hcmd1, len1, hcmd2, len2),
        TP_STRUCT__entry(
                PRIV_ENTRY
-               __dynamic_array(u8, hcmd, len)
+               __dynamic_array(u8, hcmd0, len0)
+               __dynamic_array(u8, hcmd1, len1)
+               __dynamic_array(u8, hcmd2, len2)
                __field(u32, flags)
        ),
        TP_fast_assign(
                PRIV_ASSIGN;
-               memcpy(__get_dynamic_array(hcmd), hcmd, len);
+               memcpy(__get_dynamic_array(hcmd0), hcmd0, len0);
+               memcpy(__get_dynamic_array(hcmd1), hcmd1, len1);
+               memcpy(__get_dynamic_array(hcmd2), hcmd2, len2);
                __entry->flags = flags;
        ),
        TP_printk("[%p] hcmd %#.2x (%ssync)",
-                 __entry->priv, ((u8 *)__get_dynamic_array(hcmd))[0],
+                 __entry->priv, ((u8 *)__get_dynamic_array(hcmd0))[0],
                  __entry->flags & CMD_ASYNC ? "a" : "")
 );
 
@@ -202,15 +209,18 @@ TRACE_EVENT(iwlwifi_dev_tx,
 );
 
 TRACE_EVENT(iwlwifi_dev_ucode_error,
-       TP_PROTO(struct iwl_priv *priv, u32 desc, u32 time,
+       TP_PROTO(struct iwl_priv *priv, u32 desc, u32 tsf_low,
                 u32 data1, u32 data2, u32 line, u32 blink1,
-                u32 blink2, u32 ilink1, u32 ilink2),
-       TP_ARGS(priv, desc, time, data1, data2, line,
-               blink1, blink2, ilink1, ilink2),
+                u32 blink2, u32 ilink1, u32 ilink2, u32 bcon_time,
+                u32 gp1, u32 gp2, u32 gp3, u32 ucode_ver, u32 hw_ver,
+                u32 brd_ver),
+       TP_ARGS(priv, desc, tsf_low, data1, data2, line,
+               blink1, blink2, ilink1, ilink2, bcon_time, gp1, gp2,
+               gp3, ucode_ver, hw_ver, brd_ver),
        TP_STRUCT__entry(
                PRIV_ENTRY
                __field(u32, desc)
-               __field(u32, time)
+               __field(u32, tsf_low)
                __field(u32, data1)
                __field(u32, data2)
                __field(u32, line)
@@ -218,11 +228,18 @@ TRACE_EVENT(iwlwifi_dev_ucode_error,
                __field(u32, blink2)
                __field(u32, ilink1)
                __field(u32, ilink2)
+               __field(u32, bcon_time)
+               __field(u32, gp1)
+               __field(u32, gp2)
+               __field(u32, gp3)
+               __field(u32, ucode_ver)
+               __field(u32, hw_ver)
+               __field(u32, brd_ver)
        ),
        TP_fast_assign(
                PRIV_ASSIGN;
                __entry->desc = desc;
-               __entry->time = time;
+               __entry->tsf_low = tsf_low;
                __entry->data1 = data1;
                __entry->data2 = data2;
                __entry->line = line;
@@ -230,12 +247,25 @@ TRACE_EVENT(iwlwifi_dev_ucode_error,
                __entry->blink2 = blink2;
                __entry->ilink1 = ilink1;
                __entry->ilink2 = ilink2;
+               __entry->bcon_time = bcon_time;
+               __entry->gp1 = gp1;
+               __entry->gp2 = gp2;
+               __entry->gp3 = gp3;
+               __entry->ucode_ver = ucode_ver;
+               __entry->hw_ver = hw_ver;
+               __entry->brd_ver = brd_ver;
        ),
        TP_printk("[%p] #%02d %010u data 0x%08X 0x%08X line %u, "
-                 "blink 0x%05X 0x%05X ilink 0x%05X 0x%05X",
-                 __entry->priv, __entry->desc, __entry->time, __entry->data1,
+                 "blink 0x%05X 0x%05X ilink 0x%05X 0x%05X "
+                 "bcon_tm %010u gp 0x%08X 0x%08X 0x%08X uCode 0x%08X "
+                 "hw 0x%08X brd 0x%08X",
+                 __entry->priv, __entry->desc, __entry->tsf_low,
+                 __entry->data1,
                  __entry->data2, __entry->line, __entry->blink1,
-                 __entry->blink2, __entry->ilink1, __entry->ilink2)
+                 __entry->blink2, __entry->ilink1, __entry->ilink2,
+                 __entry->bcon_time, __entry->gp1, __entry->gp2,
+                 __entry->gp3, __entry->ucode_ver, __entry->hw_ver,
+                 __entry->brd_ver)
 );
 
 TRACE_EVENT(iwlwifi_dev_ucode_event,
index c8397962632c97f2a830205390a0c7350c54a48e..47a56bc1cd12e063bd556c1f19095cda9fabcfcb 100644 (file)
@@ -216,15 +216,14 @@ static int iwl_eeprom_verify_signature(struct iwl_priv *priv)
 
 static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode)
 {
-       u32 otpgp;
+       iwl_read32(priv, CSR_OTP_GP_REG);
 
-       otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
        if (mode == IWL_OTP_ACCESS_ABSOLUTE)
                iwl_clear_bit(priv, CSR_OTP_GP_REG,
-                               CSR_OTP_GP_REG_OTP_ACCESS_MODE);
+                             CSR_OTP_GP_REG_OTP_ACCESS_MODE);
        else
                iwl_set_bit(priv, CSR_OTP_GP_REG,
-                               CSR_OTP_GP_REG_OTP_ACCESS_MODE);
+                           CSR_OTP_GP_REG_OTP_ACCESS_MODE);
 }
 
 static int iwlcore_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
index 8f0beb992ccfb3f0bcf11baa83d92f7cbcf0d431..76f9966231405bf50a97e89ece9381300e30c4d1 100644 (file)
@@ -188,6 +188,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        cmd_idx = iwl_enqueue_hcmd(priv, cmd);
        if (cmd_idx < 0) {
                ret = cmd_idx;
+               clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
                IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n",
                          get_cmd_string(cmd->id), ret);
                return ret;
@@ -264,8 +265,8 @@ int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data)
 {
        struct iwl_host_cmd cmd = {
                .id = id,
-               .len = len,
-               .data = data,
+               .len = { len, },
+               .data = { data, },
        };
 
        return iwl_send_cmd_sync(priv, &cmd);
@@ -279,8 +280,8 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
 {
        struct iwl_host_cmd cmd = {
                .id = id,
-               .len = len,
-               .data = data,
+               .len = { len, },
+               .data = { data, },
        };
 
        cmd.flags |= CMD_ASYNC;
index 439187f903c9f10f46c0e9f75bc9083624df0e05..7c23beb49d7cd8ba66ef4e4d767c8e77386758df 100644 (file)
@@ -107,8 +107,8 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
 {
        struct iwl_host_cmd cmd = {
                .id = REPLY_LEDS_CMD,
-               .len = sizeof(struct iwl_led_cmd),
-               .data = led_cmd,
+               .len = { sizeof(struct iwl_led_cmd), },
+               .data = { led_cmd, },
                .flags = CMD_ASYNC,
                .callback = NULL,
        };
index 0053e9ea9021a433b98025701fcc1e9d703ea1f3..b774517aa9fa11dbe95c2f666ab88df0b915b1d9 100644 (file)
@@ -250,19 +250,19 @@ static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        struct iwl_rxon_cmd *rxon = (void *)&ctx->active;
 
-       if (priv->switch_rxon.switch_in_progress) {
-               if (!le32_to_cpu(csa->status) &&
-                   (csa->channel == priv->switch_rxon.channel)) {
-                       rxon->channel = csa->channel;
-                       ctx->staging.channel = csa->channel;
-                       IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
-                             le16_to_cpu(csa->channel));
-                       iwl_chswitch_done(priv, true);
-               } else {
-                       IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
+       if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
+               return;
+
+       if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) {
+               rxon->channel = csa->channel;
+               ctx->staging.channel = csa->channel;
+               IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
                              le16_to_cpu(csa->channel));
-                       iwl_chswitch_done(priv, false);
-               }
+               iwl_chswitch_done(priv, true);
+       } else {
+               IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
+                       le16_to_cpu(csa->channel));
+               iwl_chswitch_done(priv, false);
        }
 }
 
index 3c8cebde16cc6608facbf2d28dd0b97100b6b637..7df2814fd4f8cf6724e9282641784f5d46f97241 100644 (file)
@@ -141,7 +141,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
        struct iwl_host_cmd cmd = {
                .id = REPLY_ADD_STA,
                .flags = flags,
-               .data = data,
+               .data = { data, },
        };
        u8 sta_id __maybe_unused = sta->sta.sta_id;
 
@@ -155,7 +155,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
                might_sleep();
        }
 
-       cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
+       cmd.len[0] = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
        ret = iwl_send_cmd(priv, &cmd);
 
        if (ret || (flags & CMD_ASYNC))
@@ -401,9 +401,9 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
 
        struct iwl_host_cmd cmd = {
                .id = REPLY_REMOVE_STA,
-               .len = sizeof(struct iwl_rem_sta_cmd),
+               .len = { sizeof(struct iwl_rem_sta_cmd), },
                .flags = CMD_SYNC,
-               .data = &rm_sta_cmd,
+               .data = { &rm_sta_cmd, },
        };
 
        memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
@@ -760,9 +760,9 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
 
        struct iwl_host_cmd cmd = {
                .id = REPLY_TX_LINK_QUALITY_CMD,
-               .len = sizeof(struct iwl_link_quality_cmd),
+               .len = { sizeof(struct iwl_link_quality_cmd), },
                .flags = flags,
-               .data = lq,
+               .data = { lq, },
        };
 
        if (WARN_ON(lq->sta_id == IWL_INVALID_STATION))
index 89b6696622c1883ba12cbbbf70a9965aba59b173..69b7e6bf2d6f40adfd1a1a6ab98795730da338f2 100644 (file)
@@ -97,6 +97,13 @@ struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
 
        [IWL_TM_ATTR_SYNC_RSP] = { .type = NLA_UNSPEC, },
        [IWL_TM_ATTR_UCODE_RX_PKT] = { .type = NLA_UNSPEC, },
+
+       [IWL_TM_ATTR_EEPROM] = { .type = NLA_UNSPEC, },
+
+       [IWL_TM_ATTR_TRACE_ADDR] = { .type = NLA_UNSPEC, },
+       [IWL_TM_ATTR_TRACE_DATA] = { .type = NLA_UNSPEC, },
+
+       [IWL_TM_ATTR_FIXRATE] = { .type = NLA_U32, },
 };
 
 /*
@@ -167,6 +174,31 @@ nla_put_failure:
 void iwl_testmode_init(struct iwl_priv *priv)
 {
        priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
+       priv->testmode_trace.trace_enabled = false;
+}
+
+static void iwl_trace_cleanup(struct iwl_priv *priv)
+{
+       struct device *dev = &priv->pci_dev->dev;
+
+       if (priv->testmode_trace.trace_enabled) {
+               if (priv->testmode_trace.cpu_addr &&
+                   priv->testmode_trace.dma_addr)
+                       dma_free_coherent(dev,
+                                       TRACE_TOTAL_SIZE,
+                                       priv->testmode_trace.cpu_addr,
+                                       priv->testmode_trace.dma_addr);
+               priv->testmode_trace.trace_enabled = false;
+               priv->testmode_trace.cpu_addr = NULL;
+               priv->testmode_trace.trace_addr = NULL;
+               priv->testmode_trace.dma_addr = 0;
+       }
+}
+
+
+void iwl_testmode_cleanup(struct iwl_priv *priv)
+{
+       iwl_trace_cleanup(priv);
 }
 
 /*
@@ -198,10 +230,11 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
        }
 
        cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]);
-       cmd.data = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
-       cmd.len = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
+       cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
+       cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
+       cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
        IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x,"
-                               " len %d\n", cmd.id, cmd.flags, cmd.len);
+                               " len %d\n", cmd.id, cmd.flags, cmd.len[0]);
        /* ok, let's submit the command to ucode */
        return iwl_send_cmd(priv, &cmd);
 }
@@ -388,6 +421,38 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
                                "Error starting the device: %d\n", status);
                break;
 
+       case IWL_TM_CMD_APP2DEV_GET_EEPROM:
+               if (priv->eeprom) {
+                       skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+                               priv->cfg->base_params->eeprom_size + 20);
+                       if (!skb) {
+                               IWL_DEBUG_INFO(priv,
+                                      "Error allocating memory\n");
+                               return -ENOMEM;
+                       }
+                       NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
+                               IWL_TM_CMD_DEV2APP_EEPROM_RSP);
+                       NLA_PUT(skb, IWL_TM_ATTR_EEPROM,
+                               priv->cfg->base_params->eeprom_size,
+                               priv->eeprom);
+                       status = cfg80211_testmode_reply(skb);
+                       if (status < 0)
+                               IWL_DEBUG_INFO(priv,
+                                              "Error sending msg : %d\n",
+                                              status);
+               } else
+                       return -EFAULT;
+               break;
+
+       case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
+               if (!tb[IWL_TM_ATTR_FIXRATE]) {
+                       IWL_DEBUG_INFO(priv,
+                                      "Error finding fixrate setting\n");
+                       return -ENOMSG;
+               }
+               priv->dbg_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]);
+               break;
+
        default:
                IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n");
                return -ENOSYS;
@@ -399,6 +464,102 @@ nla_put_failure:
        return -EMSGSIZE;
 }
 
+
+/*
+ * This function handles the user application commands for uCode trace
+ *
+ * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
+ * handlers respectively.
+ *
+ * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
+ * value of the actual command execution is replied to the user application.
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @tb: gnl message fields from the user space
+ */
+static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct sk_buff *skb;
+       int status = 0;
+       struct device *dev = &priv->pci_dev->dev;
+
+       switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
+       case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
+               if (priv->testmode_trace.trace_enabled)
+                       return -EBUSY;
+
+               priv->testmode_trace.cpu_addr =
+                       dma_alloc_coherent(dev,
+                                          TRACE_TOTAL_SIZE,
+                                          &priv->testmode_trace.dma_addr,
+                                          GFP_KERNEL);
+               if (!priv->testmode_trace.cpu_addr)
+                       return -ENOMEM;
+               priv->testmode_trace.trace_enabled = true;
+               priv->testmode_trace.trace_addr = (u8 *)PTR_ALIGN(
+                       priv->testmode_trace.cpu_addr, 0x100);
+               memset(priv->testmode_trace.trace_addr, 0x03B,
+                       TRACE_BUFF_SIZE);
+               skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+                       sizeof(priv->testmode_trace.dma_addr) + 20);
+               if (!skb) {
+                       IWL_DEBUG_INFO(priv,
+                               "Error allocating memory\n");
+                       iwl_trace_cleanup(priv);
+                       return -ENOMEM;
+               }
+               NLA_PUT(skb, IWL_TM_ATTR_TRACE_ADDR,
+                       sizeof(priv->testmode_trace.dma_addr),
+                       (u64 *)&priv->testmode_trace.dma_addr);
+               status = cfg80211_testmode_reply(skb);
+               if (status < 0) {
+                       IWL_DEBUG_INFO(priv,
+                                      "Error sending msg : %d\n",
+                                      status);
+               }
+               break;
+
+       case IWL_TM_CMD_APP2DEV_END_TRACE:
+               iwl_trace_cleanup(priv);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_READ_TRACE:
+               if (priv->testmode_trace.trace_enabled &&
+                   priv->testmode_trace.trace_addr) {
+                       skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+                               20 + TRACE_BUFF_SIZE);
+                       if (skb == NULL) {
+                               IWL_DEBUG_INFO(priv,
+                                       "Error allocating memory\n");
+                               return -ENOMEM;
+                       }
+                       NLA_PUT(skb, IWL_TM_ATTR_TRACE_DATA,
+                               TRACE_BUFF_SIZE,
+                               priv->testmode_trace.trace_addr);
+                       status = cfg80211_testmode_reply(skb);
+                       if (status < 0) {
+                               IWL_DEBUG_INFO(priv,
+                                      "Error sending msg : %d\n", status);
+                       }
+               } else
+                       return -EFAULT;
+               break;
+
+       default:
+               IWL_DEBUG_INFO(priv, "Unknown testmode mem command ID\n");
+               return -ENOSYS;
+       }
+       return status;
+
+nla_put_failure:
+       kfree_skb(skb);
+       if (nla_get_u32(tb[IWL_TM_ATTR_COMMAND]) ==
+           IWL_TM_CMD_APP2DEV_BEGIN_TRACE)
+               iwl_trace_cleanup(priv);
+       return -EMSGSIZE;
+}
+
 /* The testmode gnl message handler that takes the gnl message from the
  * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
  * invoke the corresponding handlers.
@@ -455,9 +616,19 @@ int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
        case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
        case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
        case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
+       case IWL_TM_CMD_APP2DEV_GET_EEPROM:
+       case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
                IWL_DEBUG_INFO(priv, "testmode cmd to driver\n");
                result = iwl_testmode_driver(hw, tb);
                break;
+
+       case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
+       case IWL_TM_CMD_APP2DEV_END_TRACE:
+       case IWL_TM_CMD_APP2DEV_READ_TRACE:
+               IWL_DEBUG_INFO(priv, "testmode uCode trace cmd to driver\n");
+               result = iwl_testmode_trace(hw, tb);
+               break;
+
        default:
                IWL_DEBUG_INFO(priv, "Unknown testmode command\n");
                result = -ENOSYS;
index 31f8949f2801b701cf409f93ffd68d726deb4115..a88085e9b3615e9739cb021cdfc85adff5e4aed4 100644 (file)
@@ -88,9 +88,15 @@ enum iwl_tm_cmd_t {
        IWL_TM_CMD_APP2DEV_LOAD_INIT_FW,
        IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB,
        IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW,
+       IWL_TM_CMD_APP2DEV_GET_EEPROM,
+       IWL_TM_CMD_APP2DEV_FIXRATE_REQ,
        /* if there is other new command for the driver layer operation,
         * append them here */
 
+       /* commands fom user space for uCode trace operations */
+       IWL_TM_CMD_APP2DEV_BEGIN_TRACE,
+       IWL_TM_CMD_APP2DEV_END_TRACE,
+       IWL_TM_CMD_APP2DEV_READ_TRACE,
 
        /* commands from kernel space to carry the synchronous response
         * to user application */
@@ -99,6 +105,11 @@ enum iwl_tm_cmd_t {
        /* commands from kernel space to multicast the spontaneous messages
         * to user application */
        IWL_TM_CMD_DEV2APP_UCODE_RX_PKT,
+
+       /* commands from kernel space to carry the eeprom response
+        * to user application */
+       IWL_TM_CMD_DEV2APP_EEPROM_RSP,
+
        IWL_TM_CMD_MAX,
 };
 
@@ -144,8 +155,31 @@ enum iwl_tm_attr_t {
         * application */
        IWL_TM_ATTR_UCODE_RX_PKT,
 
+       /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_EEPROM,
+        * The mandatory fields are:
+        * IWL_TM_ATTR_EEPROM for the data content responging to the user
+        * application */
+       IWL_TM_ATTR_EEPROM,
+
+       /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_XXX_TRACE,
+        * The mandatory fields are:
+        * IWL_TM_ATTR_MEM_TRACE_ADDR for the trace address
+        */
+       IWL_TM_ATTR_TRACE_ADDR,
+       IWL_TM_ATTR_TRACE_DATA,
+
+       /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_FIXRATE_REQ,
+        * The mandatory fields are:
+        * IWL_TM_ATTR_FIXRATE for the fixed rate
+        */
+       IWL_TM_ATTR_FIXRATE,
+
        IWL_TM_ATTR_MAX,
 };
 
+/* uCode trace buffer */
+#define TRACE_BUFF_SIZE                0x20000
+#define TRACE_BUFF_PADD                0x2000
+#define TRACE_TOTAL_SIZE       (TRACE_BUFF_SIZE + TRACE_BUFF_PADD)
 
 #endif
index e69597ea43e28e1c6ebde79655557e77c23b92d8..686e176b5ebdeb80c992860b49e2e64150892ca0 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/slab.h>
 #include <net/mac80211.h>
 #include "iwl-eeprom.h"
+#include "iwl-agn.h"
 #include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-sta.h"
@@ -85,6 +86,158 @@ void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
        txq->need_update = 0;
 }
 
+static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
+{
+       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+
+       dma_addr_t addr = get_unaligned_le32(&tb->lo);
+       if (sizeof(dma_addr_t) > sizeof(u32))
+               addr |=
+               ((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16;
+
+       return addr;
+}
+
+static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
+{
+       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+
+       return le16_to_cpu(tb->hi_n_len) >> 4;
+}
+
+static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx,
+                                 dma_addr_t addr, u16 len)
+{
+       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+       u16 hi_n_len = len << 4;
+
+       put_unaligned_le32(addr, &tb->lo);
+       if (sizeof(dma_addr_t) > sizeof(u32))
+               hi_n_len |= ((addr >> 16) >> 16) & 0xF;
+
+       tb->hi_n_len = cpu_to_le16(hi_n_len);
+
+       tfd->num_tbs = idx + 1;
+}
+
+static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd)
+{
+       return tfd->num_tbs & 0x1f;
+}
+
+static void iwlagn_unmap_tfd(struct iwl_priv *priv, struct iwl_cmd_meta *meta,
+                            struct iwl_tfd *tfd)
+{
+       struct pci_dev *dev = priv->pci_dev;
+       int i;
+       int num_tbs;
+
+       /* Sanity check on number of chunks */
+       num_tbs = iwl_tfd_get_num_tbs(tfd);
+
+       if (num_tbs >= IWL_NUM_OF_TBS) {
+               IWL_ERR(priv, "Too many chunks: %i\n", num_tbs);
+               /* @todo issue fatal error, it is quite serious situation */
+               return;
+       }
+
+       /* Unmap tx_cmd */
+       if (num_tbs)
+               pci_unmap_single(dev,
+                               dma_unmap_addr(meta, mapping),
+                               dma_unmap_len(meta, len),
+                               PCI_DMA_BIDIRECTIONAL);
+
+       /* Unmap chunks, if any. */
+       for (i = 1; i < num_tbs; i++)
+               pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i),
+                               iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE);
+}
+
+/**
+ * iwlagn_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
+ * @priv - driver private data
+ * @txq - tx queue
+ *
+ * Does NOT advance any TFD circular buffer read/write indexes
+ * Does NOT free the TFD itself (which is within circular buffer)
+ */
+void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+       struct iwl_tfd *tfd_tmp = txq->tfds;
+       int index = txq->q.read_ptr;
+
+       iwlagn_unmap_tfd(priv, &txq->meta[index], &tfd_tmp[index]);
+
+       /* free SKB */
+       if (txq->txb) {
+               struct sk_buff *skb;
+
+               skb = txq->txb[txq->q.read_ptr].skb;
+
+               /* can be called from irqs-disabled context */
+               if (skb) {
+                       dev_kfree_skb_any(skb);
+                       txq->txb[txq->q.read_ptr].skb = NULL;
+               }
+       }
+}
+
+int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv,
+                                struct iwl_tx_queue *txq,
+                                dma_addr_t addr, u16 len,
+                                u8 reset)
+{
+       struct iwl_queue *q;
+       struct iwl_tfd *tfd, *tfd_tmp;
+       u32 num_tbs;
+
+       q = &txq->q;
+       tfd_tmp = txq->tfds;
+       tfd = &tfd_tmp[q->write_ptr];
+
+       if (reset)
+               memset(tfd, 0, sizeof(*tfd));
+
+       num_tbs = iwl_tfd_get_num_tbs(tfd);
+
+       /* Each TFD can point to a maximum 20 Tx buffers */
+       if (num_tbs >= IWL_NUM_OF_TBS) {
+               IWL_ERR(priv, "Error can not send more than %d chunks\n",
+                         IWL_NUM_OF_TBS);
+               return -EINVAL;
+       }
+
+       if (WARN_ON(addr & ~DMA_BIT_MASK(36)))
+               return -EINVAL;
+
+       if (unlikely(addr & ~IWL_TX_DMA_MASK))
+               IWL_ERR(priv, "Unaligned address = %llx\n",
+                         (unsigned long long)addr);
+
+       iwl_tfd_set_tb(tfd, num_tbs, addr, len);
+
+       return 0;
+}
+
+/*
+ * Tell nic where to find circular buffer of Tx Frame Descriptors for
+ * given Tx queue, and enable the DMA channel used for that queue.
+ *
+ * supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
+ * channels supported in hardware.
+ */
+static int iwlagn_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+       int txq_id = txq->q.id;
+
+       /* Circular buffer (TFD queue in DRAM) physical base address */
+       iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
+                            txq->q.dma_addr >> 8);
+
+       return 0;
+}
+
 /**
  * iwl_tx_queue_unmap -  Unmap any remaining DMA mappings and free skb's
  */
@@ -97,7 +250,7 @@ void iwl_tx_queue_unmap(struct iwl_priv *priv, int txq_id)
                return;
 
         while (q->write_ptr != q->read_ptr) {
-               priv->cfg->ops->lib->txq_free_tfd(priv, txq);
+               iwlagn_txq_free_tfd(priv, txq);
                q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
        }
 }
@@ -154,7 +307,7 @@ void iwl_cmd_queue_unmap(struct iwl_priv *priv)
                return;
 
        while (q->read_ptr != q->write_ptr) {
-               i = get_cmd_index(q, q->read_ptr, 0);
+               i = get_cmd_index(q, q->read_ptr);
 
                if (txq->meta[i].flags & CMD_MAPPED) {
                        pci_unmap_single(priv->pci_dev,
@@ -166,15 +319,6 @@ void iwl_cmd_queue_unmap(struct iwl_priv *priv)
 
                q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
        }
-
-       i = q->n_window;
-       if (txq->meta[i].flags & CMD_MAPPED) {
-               pci_unmap_single(priv->pci_dev,
-                                dma_unmap_addr(&txq->meta[i], mapping),
-                                dma_unmap_len(&txq->meta[i], len),
-                                PCI_DMA_BIDIRECTIONAL);
-               txq->meta[i].flags = 0;
-       }
 }
 
 /**
@@ -194,7 +338,7 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
        iwl_cmd_queue_unmap(priv);
 
        /* De-alloc array of command/tx buffers */
-       for (i = 0; i <= TFD_CMD_SLOTS; i++)
+       for (i = 0; i < TFD_CMD_SLOTS; i++)
                kfree(txq->cmd[i]);
 
        /* De-alloc circular buffer of TFDs */
@@ -334,33 +478,17 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
 {
        int i, len;
        int ret;
-       int actual_slots = slots_num;
-
-       /*
-        * Alloc buffer array for commands (Tx or other types of commands).
-        * For the command queue (#4/#9), allocate command space + one big
-        * command for scan, since scan command is very huge; the system will
-        * not have two scans at the same time, so only one is needed.
-        * For normal Tx queues (all other queues), no super-size command
-        * space is needed.
-        */
-       if (txq_id == priv->cmd_queue)
-               actual_slots++;
 
-       txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * actual_slots,
+       txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * slots_num,
                            GFP_KERNEL);
-       txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * actual_slots,
+       txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * slots_num,
                           GFP_KERNEL);
 
        if (!txq->meta || !txq->cmd)
                goto out_free_arrays;
 
        len = sizeof(struct iwl_device_cmd);
-       for (i = 0; i < actual_slots; i++) {
-               /* only happens for cmd queue */
-               if (i == slots_num)
-                       len = IWL_MAX_CMD_SIZE;
-
+       for (i = 0; i < slots_num; i++) {
                txq->cmd[i] = kmalloc(len, GFP_KERNEL);
                if (!txq->cmd[i])
                        goto err;
@@ -391,11 +519,11 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
                return ret;
 
        /* Tell device where to find queue */
-       priv->cfg->ops->lib->txq_init(priv, txq);
+       iwlagn_tx_queue_init(priv, txq);
 
        return 0;
 err:
-       for (i = 0; i < actual_slots; i++)
+       for (i = 0; i < slots_num; i++)
                kfree(txq->cmd[i]);
 out_free_arrays:
        kfree(txq->meta);
@@ -420,7 +548,7 @@ void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
        iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
 
        /* Tell device where to find queue */
-       priv->cfg->ops->lib->txq_init(priv, txq);
+       iwlagn_tx_queue_init(priv, txq);
 }
 
 /*************** HOST COMMAND QUEUE FUNCTIONS   *****/
@@ -443,23 +571,49 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        dma_addr_t phys_addr;
        unsigned long flags;
        u32 idx;
-       u16 fix_size;
+       u16 copy_size, cmd_size;
        bool is_ct_kill = false;
+       bool had_nocopy = false;
+       int i;
+       u8 *cmd_dest;
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+       const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {};
+       int trace_lens[IWL_MAX_CMD_TFDS + 1] = {};
+       int trace_idx;
+#endif
+
+       if (test_bit(STATUS_FW_ERROR, &priv->status)) {
+               IWL_WARN(priv, "fw recovery, no hcmd send\n");
+               return -EIO;
+       }
 
-       fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
+       copy_size = sizeof(out_cmd->hdr);
+       cmd_size = sizeof(out_cmd->hdr);
+
+       /* need one for the header if the first is NOCOPY */
+       BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1);
+
+       for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
+               if (!cmd->len[i])
+                       continue;
+               if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) {
+                       had_nocopy = true;
+               } else {
+                       /* NOCOPY must not be followed by normal! */
+                       if (WARN_ON(had_nocopy))
+                               return -EINVAL;
+                       copy_size += cmd->len[i];
+               }
+               cmd_size += cmd->len[i];
+       }
 
        /*
         * If any of the command structures end up being larger than
-        * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
-        * we will need to increase the size of the TFD entries
-        * Also, check to see if command buffer should not exceed the size
-        * of device_cmd and max_cmd_size.
+        * the TFD_MAX_PAYLOAD_SIZE and they aren't dynamically
+        * allocated into separate TFDs, then we will need to
+        * increase the size of the buffers.
         */
-       if (WARN_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
-                   !(cmd->flags & CMD_SIZE_HUGE)))
-               return -EINVAL;
-
-       if (WARN_ON(fix_size > IWL_MAX_CMD_SIZE))
+       if (WARN_ON(copy_size > TFD_MAX_PAYLOAD_SIZE))
                return -EINVAL;
 
        if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
@@ -468,14 +622,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
                return -EIO;
        }
 
-       /*
-        * As we only have a single huge buffer, check that the command
-        * is synchronous (otherwise buffers could end up being reused).
-        */
-
-       if (WARN_ON((cmd->flags & CMD_ASYNC) && (cmd->flags & CMD_SIZE_HUGE)))
-               return -EINVAL;
-
        spin_lock_irqsave(&priv->hcmd_lock, flags);
 
        if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
@@ -490,7 +636,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
                return -ENOSPC;
        }
 
-       idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE);
+       idx = get_cmd_index(q, q->write_ptr);
        out_cmd = txq->cmd[idx];
        out_meta = &txq->meta[idx];
 
@@ -505,57 +651,84 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        if (cmd->flags & CMD_ASYNC)
                out_meta->callback = cmd->callback;
 
-       out_cmd->hdr.cmd = cmd->id;
-       memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
-
-       /* At this point, the out_cmd now has all of the incoming cmd
-        * information */
+       /* set up the header */
 
+       out_cmd->hdr.cmd = cmd->id;
        out_cmd->hdr.flags = 0;
        out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(priv->cmd_queue) |
-                       INDEX_TO_SEQ(q->write_ptr));
-       if (cmd->flags & CMD_SIZE_HUGE)
-               out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       switch (out_cmd->hdr.cmd) {
-       case REPLY_TX_LINK_QUALITY_CMD:
-       case SENSITIVITY_CMD:
-               IWL_DEBUG_HC_DUMP(priv, "Sending command %s (#%x), seq: 0x%04X, "
-                               "%d bytes at %d[%d]:%d\n",
-                               get_cmd_string(out_cmd->hdr.cmd),
-                               out_cmd->hdr.cmd,
-                               le16_to_cpu(out_cmd->hdr.sequence), fix_size,
-                               q->write_ptr, idx, priv->cmd_queue);
-               break;
-       default:
-               IWL_DEBUG_HC(priv, "Sending command %s (#%x), seq: 0x%04X, "
-                               "%d bytes at %d[%d]:%d\n",
-                               get_cmd_string(out_cmd->hdr.cmd),
-                               out_cmd->hdr.cmd,
-                               le16_to_cpu(out_cmd->hdr.sequence), fix_size,
-                               q->write_ptr, idx, priv->cmd_queue);
+                                           INDEX_TO_SEQ(q->write_ptr));
+
+       /* and copy the data that needs to be copied */
+
+       cmd_dest = &out_cmd->cmd.payload[0];
+       for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
+               if (!cmd->len[i])
+                       continue;
+               if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)
+                       break;
+               memcpy(cmd_dest, cmd->data[i], cmd->len[i]);
+               cmd_dest += cmd->len[i];
        }
-#endif
+
+       IWL_DEBUG_HC(priv, "Sending command %s (#%x), seq: 0x%04X, "
+                       "%d bytes at %d[%d]:%d\n",
+                       get_cmd_string(out_cmd->hdr.cmd),
+                       out_cmd->hdr.cmd,
+                       le16_to_cpu(out_cmd->hdr.sequence), cmd_size,
+                       q->write_ptr, idx, priv->cmd_queue);
+
        phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr,
-                                  fix_size, PCI_DMA_BIDIRECTIONAL);
+                                  copy_size, PCI_DMA_BIDIRECTIONAL);
        if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) {
                idx = -ENOMEM;
                goto out;
        }
 
        dma_unmap_addr_set(out_meta, mapping, phys_addr);
-       dma_unmap_len_set(out_meta, len, fix_size);
+       dma_unmap_len_set(out_meta, len, copy_size);
+
+       iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr, copy_size, 1);
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+       trace_bufs[0] = &out_cmd->hdr;
+       trace_lens[0] = copy_size;
+       trace_idx = 1;
+#endif
+
+       for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
+               if (!cmd->len[i])
+                       continue;
+               if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY))
+                       continue;
+               phys_addr = pci_map_single(priv->pci_dev, (void *)cmd->data[i],
+                                          cmd->len[i], PCI_DMA_TODEVICE);
+               if (pci_dma_mapping_error(priv->pci_dev, phys_addr)) {
+                       iwlagn_unmap_tfd(priv, out_meta,
+                                        &txq->tfds[q->write_ptr]);
+                       idx = -ENOMEM;
+                       goto out;
+               }
+
+               iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr,
+                                            cmd->len[i], 0);
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+               trace_bufs[trace_idx] = cmd->data[i];
+               trace_lens[trace_idx] = cmd->len[i];
+               trace_idx++;
+#endif
+       }
 
        out_meta->flags = cmd->flags | CMD_MAPPED;
 
        txq->need_update = 1;
 
-       trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags);
-
-       priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
-                                                  phys_addr, fix_size, 1,
-                                                  U32_PAD(cmd->len));
+       /* check that tracing gets all possible blocks */
+       BUILD_BUG_ON(IWL_MAX_CMD_TFDS + 1 != 3);
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+       trace_iwlwifi_dev_hcmd(priv, cmd->flags,
+                              trace_bufs[0], trace_lens[0],
+                              trace_bufs[1], trace_lens[1],
+                              trace_bufs[2], trace_lens[2]);
+#endif
 
        /* Increment and update queue's write index */
        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
@@ -573,8 +746,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
  * need to be reclaimed. As result, some free space forms.  If there is
  * enough free space (> low mark), wake the stack that feeds us.
  */
-static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
-                                  int idx, int cmd_idx)
+static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int idx)
 {
        struct iwl_tx_queue *txq = &priv->txq[txq_id];
        struct iwl_queue *q = &txq->q;
@@ -614,7 +786,6 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
        int txq_id = SEQ_TO_QUEUE(sequence);
        int index = SEQ_TO_INDEX(sequence);
        int cmd_index;
-       bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
        struct iwl_device_cmd *cmd;
        struct iwl_cmd_meta *meta;
        struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
@@ -632,14 +803,11 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
                return;
        }
 
-       cmd_index = get_cmd_index(&txq->q, index, huge);
+       cmd_index = get_cmd_index(&txq->q, index);
        cmd = txq->cmd[cmd_index];
        meta = &txq->meta[cmd_index];
 
-       pci_unmap_single(priv->pci_dev,
-                        dma_unmap_addr(meta, mapping),
-                        dma_unmap_len(meta, len),
-                        PCI_DMA_BIDIRECTIONAL);
+       iwlagn_unmap_tfd(priv, meta, &txq->tfds[index]);
 
        /* Input error checking is done when commands are added to queue. */
        if (meta->flags & CMD_WANT_SKB) {
@@ -650,7 +818,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 
        spin_lock_irqsave(&priv->hcmd_lock, flags);
 
-       iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
+       iwl_hcmd_queue_reclaim(priv, txq_id, index);
 
        if (!(meta->flags & CMD_ASYNC)) {
                clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
index 5665a1a9b99ef0ac511e5bafe68d3f7d19f1333f..a414768f40f11e7e002beae44d292972547cfbde 100644 (file)
@@ -565,7 +565,7 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
                if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)
                    && iwm->conf.mode == UMAC_MODE_BSS) {
                        cancel_delayed_work(&iwm->disconnect);
-                       cfg80211_roamed(iwm_to_ndev(iwm),
+                       cfg80211_roamed(iwm_to_ndev(iwm), NULL,
                                        complete->bssid,
                                        iwm->req_ie, iwm->req_ie_len,
                                        iwm->resp_ie, iwm->resp_ie_len,
@@ -586,7 +586,7 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
                                                WLAN_STATUS_SUCCESS,
                                                GFP_KERNEL);
                else
-                       cfg80211_roamed(iwm_to_ndev(iwm),
+                       cfg80211_roamed(iwm_to_ndev(iwm), NULL,
                                        complete->bssid,
                                        iwm->req_ie, iwm->req_ie_len,
                                        iwm->resp_ie, iwm->resp_ie_len,
index 84566db486d21291196c353327a68fec6fd05dba..71c8f3fccfa1474b3dfe196b3785b75a0d8417eb 100644 (file)
@@ -994,6 +994,8 @@ static void lbs_submit_command(struct lbs_private *priv,
        cmd = cmdnode->cmdbuf;
 
        spin_lock_irqsave(&priv->driver_lock, flags);
+       priv->seqnum++;
+       cmd->seqnum = cpu_to_le16(priv->seqnum);
        priv->cur_cmd = cmdnode;
        spin_unlock_irqrestore(&priv->driver_lock, flags);
 
@@ -1621,11 +1623,9 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
        /* Copy the incoming command to the buffer */
        memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
 
-       /* Set sequence number, clean result, move to buffer */
-       priv->seqnum++;
+       /* Set command, clean result, move to buffer */
        cmdnode->cmdbuf->command = cpu_to_le16(command);
        cmdnode->cmdbuf->size    = cpu_to_le16(in_cmd_size);
-       cmdnode->cmdbuf->seqnum  = cpu_to_le16(priv->seqnum);
        cmdnode->cmdbuf->result  = 0;
 
        lbs_deb_host("PREP_CMD: command 0x%04x\n", command);
index 63ed5798365c217669be46c7152a6b86f623b01d..e269351798611b501f05a459fc28f5e59b563cc2 100644 (file)
@@ -983,7 +983,7 @@ static void if_cs_detach(struct pcmcia_device *p_dev)
 /* Module initialization                                            */
 /********************************************************************/
 
-static struct pcmcia_device_id if_cs_ids[] = {
+static const struct pcmcia_device_id if_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID),
        PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
        PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
index a7b5cb0c2753845a581543e2ccca7963993592b0..224e9853c480605400a129fdda30b8298ca2d2bf 100644 (file)
@@ -907,7 +907,7 @@ static void if_sdio_interrupt(struct sdio_func *func)
        card = sdio_get_drvdata(func);
 
        cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret);
-       if (ret)
+       if (ret || !cause)
                goto out;
 
        lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
@@ -1008,10 +1008,6 @@ static int if_sdio_probe(struct sdio_func *func,
        if (ret)
                goto release;
 
-       ret = sdio_claim_irq(func, if_sdio_interrupt);
-       if (ret)
-               goto disable;
-
        /* For 1-bit transfers to the 8686 model, we need to enable the
         * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
         * bit to allow access to non-vendor registers. */
@@ -1082,6 +1078,21 @@ static int if_sdio_probe(struct sdio_func *func,
        else
                card->rx_unit = 0;
 
+       /*
+        * Set up the interrupt handler late.
+        *
+        * If we set it up earlier, the (buggy) hardware generates a spurious
+        * interrupt, even before the interrupt has been enabled, with
+        * CCCR_INTx = 0.
+        *
+        * We register the interrupt handler late so that we can handle any
+        * spurious interrupts, and also to avoid generation of that known
+        * spurious interrupt in the first place.
+        */
+       ret = sdio_claim_irq(func, if_sdio_interrupt);
+       if (ret)
+               goto disable;
+
        /*
         * Enable interrupts now that everything is set up
         */
index d3d5e0853c45822b8b58fa131732d7aca55d7e7c..f807447e4d993cf1fae0befdd13e57b4aa25f764 100644 (file)
@@ -196,6 +196,8 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
                if (skb_src)
                        pra_list->total_pkts_size -= skb_src->len;
 
+               atomic_dec(&priv->wmm.tx_pkts_queued);
+
                spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
                                       ra_list_flags);
                mwifiex_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad);
@@ -257,6 +259,8 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
 
                pra_list->total_pkts_size += skb_aggr->len;
 
+               atomic_inc(&priv->wmm.tx_pkts_queued);
+
                tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
                spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
                                       ra_list_flags);
index 660831ce293cf771dcd268bc5c9e8614d5b07923..687c1f223497e440939607e38303ca33e6fc9bcc 100644 (file)
@@ -1288,6 +1288,8 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac,
 
        *(unsigned long *) wdev_priv = (unsigned long) priv;
 
+       set_wiphy_dev(wdev->wiphy, (struct device *) priv->adapter->dev);
+
        ret = wiphy_register(wdev->wiphy);
        if (ret < 0) {
                dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n",
index 672701dc2721b56575dc6ba11e1964c494aebf9a..8316b3cd92cdf421975c96ffd9955cc62ae49483 100644 (file)
@@ -69,7 +69,8 @@ struct mwifiex_drv_mode {
 #define MWIFIEX_TIMER_10S                      10000
 #define MWIFIEX_TIMER_1S                       1000
 
-#define MAX_TX_PENDING      60
+#define MAX_TX_PENDING      100
+#define LOW_TX_PENDING      80
 
 #define MWIFIEX_UPLD_SIZE               (2312)
 
@@ -202,6 +203,7 @@ struct mwifiex_tid_tbl {
 #define WMM_HIGHEST_PRIORITY           7
 #define HIGH_PRIO_TID                          7
 #define LOW_PRIO_TID                           0
+#define NO_PKT_PRIO_TID                                (-1)
 
 struct mwifiex_wmm_desc {
        struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID];
@@ -213,7 +215,10 @@ struct mwifiex_wmm_desc {
        u32 drv_pkt_delay_max;
        u8 queue_priority[IEEE80211_MAX_QUEUES];
        u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1];     /* UP: 0 to 7 */
-
+       /* Number of transmit packets queued */
+       atomic_t tx_pkts_queued;
+       /* Tracks highest priority with a packet queued */
+       atomic_t highest_queued_prio;
 };
 
 struct mwifiex_802_11_security {
index a0e9bc5253e06dd8001dd2733d3c85f0e34046a0..4e97e90aa3994cacc80cadbd034caa581549011e 100644 (file)
 /* Rx unit register */
 #define CARD_RX_UNIT_REG               0x63
 
-/* Event header Len*/
-#define MWIFIEX_EVENT_HEADER_LEN           8
+/* Event header len w/o 4 bytes of interface header */
+#define MWIFIEX_EVENT_HEADER_LEN           4
 
 /* Max retry number of CMD53 write */
 #define MAX_WRITE_IOMEM_RETRY          2
index 210120889dfe446c86b000d8f66e5d6e528a6847..aaa50c0741965c4bd7f3f39748a6ba856b1afb07 100644 (file)
@@ -140,7 +140,9 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
        } else {
                priv->stats.tx_errors++;
        }
-       atomic_dec(&adapter->tx_pending);
+
+       if (atomic_dec_return(&adapter->tx_pending) >= LOW_TX_PENDING)
+               goto done;
 
        for (i = 0; i < adapter->priv_num; i++) {
 
index faa09e32902eb140344da184af90a2fdf4e54afe..91634daec306c093928a7718c176d734b7bf07aa 100644 (file)
@@ -177,14 +177,20 @@ static void mwifiex_wmm_default_queue_priorities(struct mwifiex_private *priv)
  * This function map ACs to TIDs.
  */
 static void
-mwifiex_wmm_queue_priorities_tid(u8 queue_priority[])
+mwifiex_wmm_queue_priorities_tid(struct mwifiex_wmm_desc *wmm)
 {
+       u8 *queue_priority = wmm->queue_priority;
        int i;
 
        for (i = 0; i < 4; ++i) {
                tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1];
                tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0];
        }
+
+       for (i = 0; i < MAX_NUM_TID; ++i)
+               tos_to_tid_inv[tos_to_tid[i]] = (u8)i;
+
+       atomic_set(&wmm->highest_queued_prio, HIGH_PRIO_TID);
 }
 
 /*
@@ -246,7 +252,7 @@ mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
                }
        }
 
-       mwifiex_wmm_queue_priorities_tid(priv->wmm.queue_priority);
+       mwifiex_wmm_queue_priorities_tid(&priv->wmm);
 }
 
 /*
@@ -399,6 +405,9 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
                priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT;
                priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE;
                priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE;
+
+               atomic_set(&priv->wmm.tx_pkts_queued, 0);
+               atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID);
        }
 }
 
@@ -408,17 +417,13 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
 int
 mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter)
 {
-       int i, j;
+       int i;
        struct mwifiex_private *priv;
 
-       for (j = 0; j < adapter->priv_num; ++j) {
-               priv = adapter->priv[j];
-               if (priv) {
-                       for (i = 0; i < MAX_NUM_TID; i++)
-                               if (!mwifiex_wmm_is_ra_list_empty(
-                                            &priv->wmm.tid_tbl_ptr[i].ra_list))
-                                       return false;
-               }
+       for (i = 0; i < adapter->priv_num; ++i) {
+               priv = adapter->priv[i];
+               if (priv && atomic_read(&priv->wmm.tx_pkts_queued))
+                               return false;
        }
 
        return true;
@@ -468,6 +473,9 @@ static void mwifiex_wmm_cleanup_queues(struct mwifiex_private *priv)
        for (i = 0; i < MAX_NUM_TID; i++)
                mwifiex_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i].
                                                     ra_list);
+
+       atomic_set(&priv->wmm.tx_pkts_queued, 0);
+       atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID);
 }
 
 /*
@@ -638,6 +646,13 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter,
 
        ra_list->total_pkts_size += skb->len;
 
+       atomic_inc(&priv->wmm.tx_pkts_queued);
+
+       if (atomic_read(&priv->wmm.highest_queued_prio) <
+                                               tos_to_tid_inv[tid_down])
+               atomic_set(&priv->wmm.highest_queued_prio,
+                                               tos_to_tid_inv[tid_down]);
+
        spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
 }
 
@@ -863,9 +878,14 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
                }
 
                do {
+                       atomic_t *hqp;
+                       spinlock_t *lock;
+
                        priv_tmp = bssprio_node->priv;
+                       hqp = &priv_tmp->wmm.highest_queued_prio;
+                       lock = &priv_tmp->wmm.ra_list_spinlock;
 
-                       for (i = HIGH_PRIO_TID; i >= LOW_PRIO_TID; --i) {
+                       for (i = atomic_read(hqp); i >= LOW_PRIO_TID; --i) {
 
                                tid_ptr = &(priv_tmp)->wmm.
                                        tid_tbl_ptr[tos_to_tid[i]];
@@ -903,6 +923,11 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
                                        is_list_empty =
                                                skb_queue_empty(&ptr->skb_head);
                                        if (!is_list_empty) {
+                                               spin_lock_irqsave(lock, flags);
+                                               if (atomic_read(hqp) > i)
+                                                       atomic_set(hqp, i);
+                                               spin_unlock_irqrestore(lock,
+                                                                       flags);
                                                *priv = priv_tmp;
                                                *tid = tos_to_tid[i];
                                                return ptr;
@@ -921,6 +946,12 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
                                } while (ptr != head);
                        }
 
+                       /* No packet at any TID for this priv. Mark as such
+                        * to skip checking TIDs for this priv (until pkt is
+                        * added).
+                        */
+                       atomic_set(hqp, NO_PKT_PRIO_TID);
+
                        /* Get next bss priority node */
                        bssprio_node = list_first_entry(&bssprio_node->list,
                                                struct mwifiex_bss_prio_node,
@@ -1028,6 +1059,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
                                .bss_prio_cur->list,
                                struct mwifiex_bss_prio_node,
                                list);
+               atomic_dec(&priv->wmm.tx_pkts_queued);
                spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
                                       ra_list_flags);
        }
@@ -1134,6 +1166,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
                                .bss_prio_cur->list,
                                struct mwifiex_bss_prio_node,
                                list);
+               atomic_dec(&priv->wmm.tx_pkts_queued);
                spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
                                       ra_list_flags);
        }
@@ -1227,5 +1260,5 @@ mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter)
 
                if (mwifiex_dequeue_tx_packet(adapter))
                        break;
-       } while (true);
+       } while (!mwifiex_wmm_lists_empty(adapter));
 }
index 32261189bcef9065eac5cf14b961497a79a58f93..aeac3cc4dbe45d6df570a636ffafbfcc3ce104cf 100644 (file)
@@ -2474,6 +2474,7 @@ struct mwl8k_cmd_set_hw_spec {
  * faster client.
  */
 #define MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY 0x00000400
+#define MWL8K_SET_HW_SPEC_FLAG_GENERATE_CCMP_HDR       0x00000200
 #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT          0x00000080
 #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP      0x00000020
 #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON         0x00000010
@@ -2510,7 +2511,8 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw)
        cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT |
                                 MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP |
                                 MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON |
-                                MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY);
+                                MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY |
+                                MWL8K_SET_HW_SPEC_FLAG_GENERATE_CCMP_HDR);
        cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS);
        cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS);
 
index 32954c4b243a9dc70bbb0fd350c6c79ff67875d3..88e3c0ebcaadb119f92e33eacd23f4abc1950735 100644 (file)
@@ -237,7 +237,7 @@ static int orinoco_cs_resume(struct pcmcia_device *link)
 /* Module initialization                                           */
 /********************************************************************/
 
-static struct pcmcia_device_id orinoco_cs_ids[] = {
+static const struct pcmcia_device_id orinoco_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */
        PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */
        PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */
index db34c282e59b39340a9bf7c6c51f529bf020a1c0..81f3673d31d43c9f856076719a0ee5b8cf95feed 100644 (file)
@@ -301,7 +301,7 @@ spectrum_cs_resume(struct pcmcia_device *link)
 /* Module initialization                                           */
 /********************************************************************/
 
-static struct pcmcia_device_id spectrum_cs_ids[] = {
+static const struct pcmcia_device_id spectrum_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */
        PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */
        PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */
index e18358725b69813077de8d9e55f8a98d5fa7a021..a8f3bc740dfaf8354abff344f5ab7665bd8faf58 100644 (file)
@@ -82,6 +82,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
        {USB_DEVICE(0x06b9, 0x0121)},   /* Thomson SpeedTouch 121g */
        {USB_DEVICE(0x0707, 0xee13)},   /* SMC 2862W-G version 2 */
        {USB_DEVICE(0x083a, 0x4521)},   /* Siemens Gigaset USB Adapter 54 version 2 */
+       {USB_DEVICE(0x083a, 0xc501)},   /* Zoom Wireless-G 4410 */
        {USB_DEVICE(0x083a, 0xf503)},   /* Accton FD7050E ver 1010ec  */
        {USB_DEVICE(0x0846, 0x4240)},   /* Netgear WG111 (v2) */
        {USB_DEVICE(0x0915, 0x2000)},   /* Cohiba Proto board */
index 0764d1a30d13f2637ae624d43446e26a07f6ffd9..2a06ebcd67c5cd1f24beba30df18de1d79cc3c12 100644 (file)
@@ -2781,7 +2781,7 @@ static const struct file_operations int_proc_fops = {
 };
 #endif
 
-static struct pcmcia_device_id ray_ids[] = {
+static const struct pcmcia_device_id ray_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x01a6, 0x0000),
        PCMCIA_DEVICE_NULL,
 };
index 518542b4bf9e87a0571431d4374842b72ef62faa..29f938930667d3696efd82f5d45fc9c98c15ac39 100644 (file)
@@ -2830,7 +2830,8 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
                                                req_ie_len, resp_ie,
                                                resp_ie_len, 0, GFP_KERNEL);
                else
-                       cfg80211_roamed(usbdev->net, bssid, req_ie, req_ie_len,
+                       cfg80211_roamed(usbdev->net, NULL, bssid,
+                                       req_ie, req_ie_len,
                                        resp_ie, resp_ie_len, GFP_KERNEL);
        } else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
                cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL);
index 9def1e5369a1c9dcfcbbee164444902efd16884b..b2f8b8fd4d2dc911dbb4f590430f8caa60dc70ab 100644 (file)
@@ -166,7 +166,6 @@ config RT2800USB_RT35XX
 config RT2800USB_RT53XX
        bool "rt2800usb - Include support for rt53xx devices (EXPERIMENTAL)"
        depends on EXPERIMENTAL
-       default y
        ---help---
          This adds support for rt53xx wireless chipset family to the
          rt2800pci driver.
index 555180d8f4aa7055aa77a417b75fa894898964a8..b704e5b183d0bc539e8bec6d08776774854d5479 100644 (file)
@@ -250,7 +250,8 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
        if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL)
                rt2x00link_reset_tuner(rt2x00dev, false);
 
-       if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) &&
+       if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
+           test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) &&
            (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) &&
            (conf->flags & IEEE80211_CONF_PS)) {
                beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon;
index c018d67aab8e40b7a5c719d04f14eb52a4853d9b..939821b4af2ff5b768913cc0809b05695801285c 100644 (file)
@@ -146,6 +146,9 @@ static void rt2x00lib_autowakeup(struct work_struct *work)
        struct rt2x00_dev *rt2x00dev =
            container_of(work, struct rt2x00_dev, autowakeup_work.work);
 
+       if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+               return;
+
        if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
                ERROR(rt2x00dev, "Device failed to wakeup.\n");
        clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
@@ -1160,6 +1163,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
         * Stop all work.
         */
        cancel_work_sync(&rt2x00dev->intf_work);
+       cancel_delayed_work_sync(&rt2x00dev->autowakeup_work);
        if (rt2x00_is_usb(rt2x00dev)) {
                del_timer_sync(&rt2x00dev->txstatus_timer);
                cancel_work_sync(&rt2x00dev->rxdone_work);
index a4095284543677d28fc39852361ede477546f654..9f8ccae93317d92cf353cb595a189df0aa1960e9 100644 (file)
@@ -669,6 +669,14 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
                                                         &rx_status,
                                                         (u8 *) pdesc, skb);
 
+                       new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
+                       if (unlikely(!new_skb)) {
+                               RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
+                                        DBG_DMESG,
+                                        ("can't alloc skb for rx\n"));
+                               goto done;
+                       }
+
                        pci_unmap_single(rtlpci->pdev,
                                         *((dma_addr_t *) skb->cb),
                                         rtlpci->rxbuffersize,
@@ -690,7 +698,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
                        hdr = rtl_get_hdr(skb);
                        fc = rtl_get_fc(skb);
 
-                       if (!stats.crc || !stats.hwerror) {
+                       if (!stats.crc && !stats.hwerror) {
                                memcpy(IEEE80211_SKB_RXCB(skb), &rx_status,
                                       sizeof(rx_status));
 
@@ -758,15 +766,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
                                rtl_lps_leave(hw);
                        }
 
-                       new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
-                       if (unlikely(!new_skb)) {
-                               RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
-                                        DBG_DMESG,
-                                        ("can't alloc skb for rx\n"));
-                               goto done;
-                       }
                        skb = new_skb;
-                       /*skb->dev = dev; */
 
                        rtlpci->rx_ring[rx_queue_idx].rx_buf[rtlpci->
                                                             rx_ring
@@ -1113,6 +1113,13 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
 
                rtlpci->rx_ring[rx_queue_idx].idx = 0;
 
+               /* If amsdu_8k is disabled, set buffersize to 4096. This
+                * change will reduce memory fragmentation.
+                */
+               if (rtlpci->rxbuffersize > 4096 &&
+                   rtlpriv->rtlhal.disable_amsdu_8k)
+                       rtlpci->rxbuffersize = 4096;
+
                for (i = 0; i < rtlpci->rxringcount; i++) {
                        struct sk_buff *skb =
                            dev_alloc_skb(rtlpci->rxbuffersize);
index 2bb71195e97658c98a39494d6190e3ce745b6344..39b0297ce925d6625291c91873d2948f42432a4c 100644 (file)
@@ -190,7 +190,7 @@ static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
 
        ppsc->swrf_processing = true;
 
-       if (ppsc->inactive_pwrstate == ERFOFF &&
+       if (ppsc->inactive_pwrstate == ERFON &&
            rtlhal->interface == INTF_PCI) {
                if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
                    RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
index c5424cad43cb578ea57d8d095dfba92a4b23c772..d2cc81586a6a9c95a4b1660b0a377a024ac7fee9 100644 (file)
@@ -728,7 +728,7 @@ void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw,
                return;
        rtlphy->set_bwmode_inprogress = true;
        if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
-               rtlphy->set_bwmode_inprogress = false;
+               rtlpriv->cfg->ops->phy_set_bw_mode_callback(hw);
        } else {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
                         ("FALSE driver sleep or unload\n"));
index 73ae8a431848693818e55fcd76cceb6717031284..abe0fcc753686fc9ac888bb3b64a176fcd530382 100644 (file)
@@ -366,6 +366,75 @@ bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
        return true;
 }
 
+void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       u8 reg_bw_opmode;
+       u8 reg_prsr_rsc;
+
+       RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+                ("Switch to %s bandwidth\n",
+                 rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
+                 "20MHz" : "40MHz"))
+
+       if (is_hal_stop(rtlhal)) {
+               rtlphy->set_bwmode_inprogress = false;
+               return;
+       }
+
+       reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE);
+       reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2);
+
+       switch (rtlphy->current_chan_bw) {
+       case HT_CHANNEL_WIDTH_20:
+               reg_bw_opmode |= BW_OPMODE_20MHZ;
+               rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+               break;
+       case HT_CHANNEL_WIDTH_20_40:
+               reg_bw_opmode &= ~BW_OPMODE_20MHZ;
+               rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+               reg_prsr_rsc =
+                   (reg_prsr_rsc & 0x90) | (mac->cur_40_prime_sc << 5);
+               rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc);
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw));
+               break;
+       }
+
+       switch (rtlphy->current_chan_bw) {
+       case HT_CHANNEL_WIDTH_20:
+               rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0);
+               rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0);
+               rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1);
+               break;
+       case HT_CHANNEL_WIDTH_20_40:
+               rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1);
+               rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1);
+
+               rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND,
+                             (mac->cur_40_prime_sc >> 1));
+               rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc);
+               rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 0);
+
+               rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)),
+                             (mac->cur_40_prime_sc ==
+                              HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw));
+               break;
+       }
+       rtl92ce_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
+       rtlphy->set_bwmode_inprogress = false;
+       RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n"));
+}
+
 void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
 {
        u8 tmpreg;
index ad580852cc76284f28c64d7fbea52c344deaf9fe..be2c92adef33d293e1579a78f57c4eb56e8574de 100644 (file)
@@ -257,5 +257,6 @@ bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
                                            u8 configtype);
 bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
                                              u8 configtype);
+void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
 
 #endif
index 390bbb5ee11d425a4da2672e4b0895288c9e2076..373dc78af1dcaef05f5511de4e509a87f06add03 100644 (file)
@@ -232,6 +232,7 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = {
        .config_bb_with_headerfile = _rtl92ce_phy_config_bb_with_headerfile,
        .config_bb_with_pgheaderfile = _rtl92ce_phy_config_bb_with_pgheaderfile,
        .phy_lc_calibrate = _rtl92ce_phy_lc_calibrate,
+       .phy_set_bw_mode_callback = rtl92ce_phy_set_bw_mode_callback,
        .dm_dynamic_txpower = rtl92ce_dm_dynamic_txpower,
 };
 
index 1ab6c86aac40d201d8f973c85367edf30831feba..c83fefb6662f3a2a433294c01e210098241e3c00 100644 (file)
@@ -1157,6 +1157,9 @@ struct conf_sched_scan_settings {
        /* time to wait on the channel for passive scans (in TUs) */
        u32 dwell_time_passive;
 
+       /* time to wait on the channel for DFS scans (in TUs) */
+       u32 dwell_time_dfs;
+
        /* number of probe requests to send on each channel in active scans */
        u8 num_probe_reqs;
 
index bc00e52f6445daec57326299829eee976d62a4bf..e6497dc669df096a57bc914e515b9212c18784c8 100644 (file)
@@ -311,6 +311,7 @@ static struct conf_drv_settings default_conf = {
                .min_dwell_time_active = 8,
                .max_dwell_time_active = 30,
                .dwell_time_passive    = 100,
+               .dwell_time_dfs        = 150,
                .num_probe_reqs        = 2,
                .rssi_threshold        = -90,
                .snr_threshold         = 0,
index f37e5a3919763b45f5b2f96f4f9b9d6d54e3f9ad..56f76abc754d170b8982961df3013a64ebd24ba0 100644 (file)
@@ -331,16 +331,22 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
        struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
        int i, j;
        u32 flags;
+       bool force_passive = !req->n_ssids;
 
        for (i = 0, j = start;
             i < req->n_channels && j < MAX_CHANNELS_ALL_BANDS;
             i++) {
                flags = req->channels[i]->flags;
 
-               if (!(flags & IEEE80211_CHAN_DISABLED) &&
-                   ((flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive) &&
-                   ((flags & IEEE80211_CHAN_RADAR) == radar) &&
-                   (req->channels[i]->band == band)) {
+               if (force_passive)
+                       flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+
+               if ((req->channels[i]->band == band) &&
+                   !(flags & IEEE80211_CHAN_DISABLED) &&
+                   (!!(flags & IEEE80211_CHAN_RADAR) == radar) &&
+                   /* if radar is set, we ignore the passive flag */
+                   (radar ||
+                    !!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) {
                        wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
                                     req->channels[i]->band,
                                     req->channels[i]->center_freq);
@@ -350,7 +356,12 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
                        wl1271_debug(DEBUG_SCAN, "max_power %d",
                                     req->channels[i]->max_power);
 
-                       if (flags & IEEE80211_CHAN_PASSIVE_SCAN) {
+                       if (flags & IEEE80211_CHAN_RADAR) {
+                               channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS;
+                               channels[j].passive_duration =
+                                       cpu_to_le16(c->dwell_time_dfs);
+                       }
+                       else if (flags & IEEE80211_CHAN_PASSIVE_SCAN) {
                                channels[j].passive_duration =
                                        cpu_to_le16(c->dwell_time_passive);
                        } else {
@@ -359,7 +370,7 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
                                channels[j].max_duration =
                                        cpu_to_le16(c->max_dwell_time_active);
                        }
-                       channels[j].tx_power_att = req->channels[j]->max_power;
+                       channels[j].tx_power_att = req->channels[i]->max_power;
                        channels[j].channel = req->channels[i]->hw_value;
 
                        j++;
@@ -386,7 +397,11 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
                                                    IEEE80211_BAND_2GHZ,
                                                    false, false, idx);
-       idx += cfg->active[0];
+       /*
+        * 5GHz channels always start at position 14, not immediately
+        * after the last 2.4GHz channel
+        */
+       idx = 14;
 
        cfg->passive[1] =
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
@@ -394,22 +409,23 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
                                                    false, true, idx);
        idx += cfg->passive[1];
 
-       cfg->active[1] =
+       cfg->dfs =
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
                                                    IEEE80211_BAND_5GHZ,
-                                                   false, false, 14);
-       idx += cfg->active[1];
+                                                   true, true, idx);
+       idx += cfg->dfs;
 
-       cfg->dfs =
+       cfg->active[1] =
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
                                                    IEEE80211_BAND_5GHZ,
-                                                   true, false, idx);
-       idx += cfg->dfs;
+                                                   false, false, idx);
+       idx += cfg->active[1];
 
        wl1271_debug(DEBUG_SCAN, "    2.4GHz: active %d passive %d",
                     cfg->active[0], cfg->passive[0]);
        wl1271_debug(DEBUG_SCAN, "    5GHz: active %d passive %d",
                     cfg->active[1], cfg->passive[1]);
+       wl1271_debug(DEBUG_SCAN, "    DFS: %d", cfg->dfs);
 
        return idx;
 }
@@ -421,6 +437,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
        struct wl1271_cmd_sched_scan_config *cfg = NULL;
        struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
        int i, total_channels, ret;
+       bool force_passive = !req->n_ssids;
 
        wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
 
@@ -444,7 +461,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
        for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++)
                cfg->intervals[i] = cpu_to_le32(req->interval);
 
-       if (req->ssids[0].ssid_len && req->ssids[0].ssid) {
+       if (!force_passive && req->ssids[0].ssid_len && req->ssids[0].ssid) {
                cfg->filter_type = SCAN_SSID_FILTER_SPECIFIC;
                cfg->ssid_len = req->ssids[0].ssid_len;
                memcpy(cfg->ssid, req->ssids[0].ssid,
@@ -461,7 +478,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
                goto out;
        }
 
-       if (cfg->active[0]) {
+       if (!force_passive && cfg->active[0]) {
                ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid,
                                                 req->ssids[0].ssid_len,
                                                 ies->ie[IEEE80211_BAND_2GHZ],
@@ -473,7 +490,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
                }
        }
 
-       if (cfg->active[1]) {
+       if (!force_passive && cfg->active[1]) {
                ret = wl1271_cmd_build_probe_req(wl,  req->ssids[0].ssid,
                                                 req->ssids[0].ssid_len,
                                                 ies->ie[IEEE80211_BAND_5GHZ],
index c83319579ca33a4a9e4f6f5767ceb0c546a87040..a0b6c5d67b0745218bb99396115c4386c0048b4e 100644 (file)
@@ -137,6 +137,9 @@ enum {
        SCAN_BSS_TYPE_ANY,
 };
 
+#define SCAN_CHANNEL_FLAGS_DFS         BIT(0)
+#define SCAN_CHANNEL_FLAGS_DFS_ENABLED BIT(1)
+
 struct conn_scan_ch_params {
        __le16 min_duration;
        __le16 max_duration;
index fc08f36fe1f512697423990015df2ca0f049ac11..6bc7c92fbff73b580c5f0fc334f21407322aebad 100644 (file)
@@ -2000,7 +2000,7 @@ static int wl3501_resume(struct pcmcia_device *link)
 }
 
 
-static struct pcmcia_device_id wl3501_ids[] = {
+static const struct pcmcia_device_id wl3501_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001),
        PCMCIA_DEVICE_NULL
 };
index 0e819943b9e479879dae4fc3f368760346feabfe..631194d498288aecff07f190cb76500ae107cd3f 100644 (file)
@@ -1533,6 +1533,31 @@ static void __exit usb_exit(void)
 module_init(usb_init);
 module_exit(usb_exit);
 
+static int zd_ep_regs_out_msg(struct usb_device *udev, void *data, int len,
+                             int *actual_length, int timeout)
+{
+       /* In USB 2.0 mode EP_REGS_OUT endpoint is interrupt type. However in
+        * USB 1.1 mode endpoint is bulk. Select correct type URB by endpoint
+        * descriptor.
+        */
+       struct usb_host_endpoint *ep;
+       unsigned int pipe;
+
+       pipe = usb_sndintpipe(udev, EP_REGS_OUT);
+       ep = usb_pipe_endpoint(udev, pipe);
+       if (!ep)
+               return -EINVAL;
+
+       if (usb_endpoint_xfer_int(&ep->desc)) {
+               return usb_interrupt_msg(udev, pipe, data, len,
+                                        actual_length, timeout);
+       } else {
+               pipe = usb_sndbulkpipe(udev, EP_REGS_OUT);
+               return usb_bulk_msg(udev, pipe, data, len, actual_length,
+                                   timeout);
+       }
+}
+
 static int usb_int_regs_length(unsigned int count)
 {
        return sizeof(struct usb_int_regs) + count * sizeof(struct reg_data);
@@ -1648,15 +1673,14 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
 
        udev = zd_usb_to_usbdev(usb);
        prepare_read_regs_int(usb);
-       r = usb_interrupt_msg(udev, usb_sndintpipe(udev, EP_REGS_OUT),
-                             req, req_len, &actual_req_len, 50 /* ms */);
+       r = zd_ep_regs_out_msg(udev, req, req_len, &actual_req_len, 50 /*ms*/);
        if (r) {
                dev_dbg_f(zd_usb_dev(usb),
-                       "error in usb_interrupt_msg(). Error number %d\n", r);
+                       "error in zd_ep_regs_out_msg(). Error number %d\n", r);
                goto error;
        }
        if (req_len != actual_req_len) {
-               dev_dbg_f(zd_usb_dev(usb), "error in usb_interrupt_msg()\n"
+               dev_dbg_f(zd_usb_dev(usb), "error in zd_ep_regs_out_msg()\n"
                        " req_len %d != actual_req_len %d\n",
                        req_len, actual_req_len);
                r = -EIO;
@@ -1818,9 +1842,17 @@ int zd_usb_iowrite16v_async(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
                rw->value = cpu_to_le16(ioreqs[i].value);
        }
 
-       usb_fill_int_urb(urb, udev, usb_sndintpipe(udev, EP_REGS_OUT),
-                        req, req_len, iowrite16v_urb_complete, usb,
-                        ep->desc.bInterval);
+       /* In USB 2.0 mode endpoint is interrupt type. However in USB 1.1 mode
+        * endpoint is bulk. Select correct type URB by endpoint descriptor.
+        */
+       if (usb_endpoint_xfer_int(&ep->desc))
+               usb_fill_int_urb(urb, udev, usb_sndintpipe(udev, EP_REGS_OUT),
+                                req, req_len, iowrite16v_urb_complete, usb,
+                                ep->desc.bInterval);
+       else
+               usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
+                                 req, req_len, iowrite16v_urb_complete, usb);
+
        urb->transfer_flags |= URB_FREE_BUFFER;
 
        /* Submit previous URB */
@@ -1924,15 +1956,14 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits)
        }
 
        udev = zd_usb_to_usbdev(usb);
-       r = usb_interrupt_msg(udev, usb_sndintpipe(udev, EP_REGS_OUT),
-                             req, req_len, &actual_req_len, 50 /* ms */);
+       r = zd_ep_regs_out_msg(udev, req, req_len, &actual_req_len, 50 /*ms*/);
        if (r) {
                dev_dbg_f(zd_usb_dev(usb),
-                       "error in usb_interrupt_msg(). Error number %d\n", r);
+                       "error in zd_ep_regs_out_msg(). Error number %d\n", r);
                goto out;
        }
        if (req_len != actual_req_len) {
-               dev_dbg_f(zd_usb_dev(usb), "error in usb_interrupt_msg()"
+               dev_dbg_f(zd_usb_dev(usb), "error in zd_ep_regs_out_msg()"
                        " req_len %d != actual_req_len %d\n",
                        req_len, actual_req_len);
                r = -EIO;
index db9a763aaa7fd0cbce405c681bd6ad9ac910c558..d29365a232a1e2a9a0a55b1b258eea8d550a8d7e 100644 (file)
@@ -1581,7 +1581,9 @@ static int xennet_connect(struct net_device *dev)
        if (err)
                return err;
 
+       rtnl_lock();
        netdev_update_features(dev);
+       rtnl_unlock();
 
        spin_lock_bh(&np->rx_lock);
        spin_lock_irq(&np->tx_lock);
index 8b63a691a9ed2d8ec06cb1b137e301fa46f8050d..65200af29c5242644dcd0221e67bbe7b0ace99b2 100644 (file)
@@ -670,7 +670,7 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
 
        pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
 
-       if (depth != 1 ||
+       if (depth != 1 || !data ||
            (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
                return 0;
 
@@ -679,16 +679,16 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
        /* Retrieve command line */
        p = of_get_flat_dt_prop(node, "bootargs", &l);
        if (p != NULL && l > 0)
-               strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE));
+               strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
 
 #ifdef CONFIG_CMDLINE
 #ifndef CONFIG_CMDLINE_FORCE
        if (p == NULL || l == 0 || (l == 1 && (*p) == 0))
 #endif
-               strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
+               strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
 #endif /* CONFIG_CMDLINE */
 
-       pr_debug("Command line is: %s\n", cmd_line);
+       pr_debug("Command line is: %s\n", (char*)data);
 
        /* break now */
        return 1;
index a3984f4ef192a1807ed4714d70babb6702a175d8..f34b5b29fb955cb3129dd38f15296583ce64ff5e 100644 (file)
@@ -141,6 +141,13 @@ static struct notifier_block module_load_nb = {
        .notifier_call = module_load_notify,
 };
 
+static void free_all_tasks(void)
+{
+       /* make sure we don't leak task structs */
+       process_task_mortuary();
+       process_task_mortuary();
+}
+
 int sync_start(void)
 {
        int err;
@@ -148,8 +155,6 @@ int sync_start(void)
        if (!zalloc_cpumask_var(&marked_cpus, GFP_KERNEL))
                return -ENOMEM;
 
-       mutex_lock(&buffer_mutex);
-
        err = task_handoff_register(&task_free_nb);
        if (err)
                goto out1;
@@ -166,7 +171,6 @@ int sync_start(void)
        start_cpu_work();
 
 out:
-       mutex_unlock(&buffer_mutex);
        return err;
 out4:
        profile_event_unregister(PROFILE_MUNMAP, &munmap_nb);
@@ -174,6 +178,7 @@ out3:
        profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb);
 out2:
        task_handoff_unregister(&task_free_nb);
+       free_all_tasks();
 out1:
        free_cpumask_var(marked_cpus);
        goto out;
@@ -182,20 +187,16 @@ out1:
 
 void sync_stop(void)
 {
-       /* flush buffers */
-       mutex_lock(&buffer_mutex);
        end_cpu_work();
        unregister_module_notifier(&module_load_nb);
        profile_event_unregister(PROFILE_MUNMAP, &munmap_nb);
        profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb);
        task_handoff_unregister(&task_free_nb);
-       mutex_unlock(&buffer_mutex);
-       flush_cpu_work();
+       barrier();                      /* do all of the above first */
 
-       /* make sure we don't leak task structs */
-       process_task_mortuary();
-       process_task_mortuary();
+       flush_cpu_work();
 
+       free_all_tasks();
        free_cpumask_var(marked_cpus);
 }
 
index 4e70749f8d16e122a0fab36fa065889e018ef954..a8d5bb3cba89a9f7b3e770b2b6af2765764648b8 100644 (file)
@@ -11,7 +11,7 @@
 #define EVENT_BUFFER_H
 
 #include <linux/types.h>
-#include <asm/mutex.h>
+#include <linux/mutex.h>
 
 int alloc_event_buffer(void);
 
index f9bda64fcd1b62771880d5d823b53f797cb9c7f0..dccd8636095cb361e2e0e1e2bb8fb7fdd57ecee2 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/moduleparam.h>
 #include <linux/workqueue.h>
 #include <linux/time.h>
-#include <asm/mutex.h>
+#include <linux/mutex.h>
 
 #include "oprof.h"
 #include "event_buffer.h"
index 787ebdeae31032b853e6e2fce73750f4bf5e4e91..067ad517c1f51eae3ca4e0adbe5dc705d39066aa 100644 (file)
@@ -178,7 +178,7 @@ static void parport_cs_release(struct pcmcia_device *link)
 } /* parport_cs_release */
 
 
-static struct pcmcia_device_id parport_ids[] = {
+static const struct pcmcia_device_id parport_ids[] = {
        PCMCIA_DEVICE_FUNC_ID(3),
        PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
        PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003),
index d3d7809af8bf5287653ebe4b3e968489eba2c4cd..0dc34f12f92e5865f22ad503c582f8cf6ba4f88a 100644 (file)
@@ -2203,7 +2203,6 @@ static __exit void parport_ip32_unregister_port(struct parport *p)
 static int __init parport_ip32_init(void)
 {
        pr_info(PPIP32 "SGI IP32 built-in parallel port driver v0.6\n");
-       pr_debug1(PPIP32 "Compiled on %s, %s\n", __DATE__, __TIME__);
        this_port = parport_ip32_probe_port();
        return IS_ERR(this_port) ? PTR_ERR(this_port) : 0;
 }
index c85f744270a56664cb91a720624cfc97dc29c6ee..094308e41be558b525a2198b3c7ee98cddc82359 100644 (file)
@@ -51,6 +51,7 @@ obj-$(CONFIG_X86_VISWS) += setup-irq.o
 obj-$(CONFIG_MN10300) += setup-bus.o
 obj-$(CONFIG_MICROBLAZE) += setup-bus.o
 obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o
+obj-$(CONFIG_SPARC_LEON) += setup-bus.o setup-irq.o
 
 #
 # ACPI Related PCI FW Functions
index 12e02bf92c4ac81f8fce8b8c18e96dc298e05b2d..3dc9befa5aec06343691474420ad203963119bdb 100644 (file)
@@ -698,12 +698,7 @@ int __init detect_intel_iommu(void)
        {
 #ifdef CONFIG_INTR_REMAP
                struct acpi_table_dmar *dmar;
-               /*
-                * for now we will disable dma-remapping when interrupt
-                * remapping is enabled.
-                * When support for queued invalidation for IOTLB invalidation
-                * is added, we will not need this any more.
-                */
+
                dmar = (struct acpi_table_dmar *) dmar_tbl;
                if (ret && cpu_has_x2apic && dmar->flags & 0x1)
                        printk(KERN_INFO
index 6af6b628175b459f03c2f0969f9b2be6d65dba48..f02c34d26d1b08226599cfa4c183da703b9486ed 100644 (file)
@@ -47,6 +47,8 @@
 #define ROOT_SIZE              VTD_PAGE_SIZE
 #define CONTEXT_SIZE           VTD_PAGE_SIZE
 
+#define IS_BRIDGE_HOST_DEVICE(pdev) \
+                           ((pdev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
 #define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
 #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
 #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
@@ -116,6 +118,11 @@ static inline unsigned long align_to_level(unsigned long pfn, int level)
        return (pfn + level_size(level) - 1) & level_mask(level);
 }
 
+static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
+{
+       return  1 << ((lvl - 1) * LEVEL_STRIDE);
+}
+
 /* VT-d pages must always be _smaller_ than MM pages. Otherwise things
    are never going to work. */
 static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn)
@@ -142,6 +149,12 @@ static struct intel_iommu **g_iommus;
 static void __init check_tylersburg_isoch(void);
 static int rwbf_quirk;
 
+/*
+ * set to 1 to panic kernel if can't successfully enable VT-d
+ * (used when kernel is launched w/ TXT)
+ */
+static int force_on = 0;
+
 /*
  * 0: Present
  * 1-11: Reserved
@@ -338,6 +351,9 @@ struct dmar_domain {
        int             iommu_coherency;/* indicate coherency of iommu access */
        int             iommu_snooping; /* indicate snooping control feature*/
        int             iommu_count;    /* reference count of iommu */
+       int             iommu_superpage;/* Level of superpages supported:
+                                          0 == 4KiB (no superpages), 1 == 2MiB,
+                                          2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
        spinlock_t      iommu_lock;     /* protect iommu set in domain */
        u64             max_addr;       /* maximum mapped address */
 };
@@ -387,6 +403,7 @@ int dmar_disabled = 1;
 static int dmar_map_gfx = 1;
 static int dmar_forcedac;
 static int intel_iommu_strict;
+static int intel_iommu_superpage = 1;
 
 #define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
 static DEFINE_SPINLOCK(device_domain_lock);
@@ -417,6 +434,10 @@ static int __init intel_iommu_setup(char *str)
                        printk(KERN_INFO
                                "Intel-IOMMU: disable batched IOTLB flush\n");
                        intel_iommu_strict = 1;
+               } else if (!strncmp(str, "sp_off", 6)) {
+                       printk(KERN_INFO
+                               "Intel-IOMMU: disable supported super page\n");
+                       intel_iommu_superpage = 0;
                }
 
                str += strcspn(str, ",");
@@ -555,11 +576,32 @@ static void domain_update_iommu_snooping(struct dmar_domain *domain)
        }
 }
 
+static void domain_update_iommu_superpage(struct dmar_domain *domain)
+{
+       int i, mask = 0xf;
+
+       if (!intel_iommu_superpage) {
+               domain->iommu_superpage = 0;
+               return;
+       }
+
+       domain->iommu_superpage = 4; /* 1TiB */
+
+       for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) {
+               mask |= cap_super_page_val(g_iommus[i]->cap);
+               if (!mask) {
+                       break;
+               }
+       }
+       domain->iommu_superpage = fls(mask);
+}
+
 /* Some capabilities may be different across iommus */
 static void domain_update_iommu_cap(struct dmar_domain *domain)
 {
        domain_update_iommu_coherency(domain);
        domain_update_iommu_snooping(domain);
+       domain_update_iommu_superpage(domain);
 }
 
 static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
@@ -689,23 +731,31 @@ out:
 }
 
 static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
-                                     unsigned long pfn)
+                                     unsigned long pfn, int large_level)
 {
        int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
        struct dma_pte *parent, *pte = NULL;
        int level = agaw_to_level(domain->agaw);
-       int offset;
+       int offset, target_level;
 
        BUG_ON(!domain->pgd);
        BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width);
        parent = domain->pgd;
 
+       /* Search pte */
+       if (!large_level)
+               target_level = 1;
+       else
+               target_level = large_level;
+
        while (level > 0) {
                void *tmp_page;
 
                offset = pfn_level_offset(pfn, level);
                pte = &parent[offset];
-               if (level == 1)
+               if (!large_level && (pte->val & DMA_PTE_LARGE_PAGE))
+                       break;
+               if (level == target_level)
                        break;
 
                if (!dma_pte_present(pte)) {
@@ -733,10 +783,11 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
        return pte;
 }
 
+
 /* return address's pte at specific level */
 static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
                                         unsigned long pfn,
-                                        int level)
+                                        int level, int *large_page)
 {
        struct dma_pte *parent, *pte = NULL;
        int total = agaw_to_level(domain->agaw);
@@ -749,8 +800,16 @@ static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
                if (level == total)
                        return pte;
 
-               if (!dma_pte_present(pte))
+               if (!dma_pte_present(pte)) {
+                       *large_page = total;
                        break;
+               }
+
+               if (pte->val & DMA_PTE_LARGE_PAGE) {
+                       *large_page = total;
+                       return pte;
+               }
+
                parent = phys_to_virt(dma_pte_addr(pte));
                total--;
        }
@@ -763,6 +822,7 @@ static void dma_pte_clear_range(struct dmar_domain *domain,
                                unsigned long last_pfn)
 {
        int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
+       unsigned int large_page = 1;
        struct dma_pte *first_pte, *pte;
 
        BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
@@ -771,14 +831,15 @@ static void dma_pte_clear_range(struct dmar_domain *domain,
 
        /* we don't need lock here; nobody else touches the iova range */
        do {
-               first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1);
+               large_page = 1;
+               first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1, &large_page);
                if (!pte) {
-                       start_pfn = align_to_level(start_pfn + 1, 2);
+                       start_pfn = align_to_level(start_pfn + 1, large_page + 1);
                        continue;
                }
-               do { 
+               do {
                        dma_clear_pte(pte);
-                       start_pfn++;
+                       start_pfn += lvl_to_nr_pages(large_page);
                        pte++;
                } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
 
@@ -798,6 +859,7 @@ static void dma_pte_free_pagetable(struct dmar_domain *domain,
        int total = agaw_to_level(domain->agaw);
        int level;
        unsigned long tmp;
+       int large_page = 2;
 
        BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
        BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
@@ -813,7 +875,10 @@ static void dma_pte_free_pagetable(struct dmar_domain *domain,
                        return;
 
                do {
-                       first_pte = pte = dma_pfn_level_pte(domain, tmp, level);
+                       large_page = level;
+                       first_pte = pte = dma_pfn_level_pte(domain, tmp, level, &large_page);
+                       if (large_page > level)
+                               level = large_page + 1;
                        if (!pte) {
                                tmp = align_to_level(tmp + 1, level + 1);
                                continue;
@@ -1397,6 +1462,7 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
        else
                domain->iommu_snooping = 0;
 
+       domain->iommu_superpage = fls(cap_super_page_val(iommu->cap));
        domain->iommu_count = 1;
        domain->nid = iommu->node;
 
@@ -1417,6 +1483,10 @@ static void domain_exit(struct dmar_domain *domain)
        if (!domain)
                return;
 
+       /* Flush any lazy unmaps that may reference this domain */
+       if (!intel_iommu_strict)
+               flush_unmaps_timeout(0);
+
        domain_remove_dev_info(domain);
        /* destroy iovas */
        put_iova_domain(&domain->iovad);
@@ -1648,6 +1718,34 @@ static inline unsigned long aligned_nrpages(unsigned long host_addr,
        return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
 }
 
+/* Return largest possible superpage level for a given mapping */
+static inline int hardware_largepage_caps(struct dmar_domain *domain,
+                                         unsigned long iov_pfn,
+                                         unsigned long phy_pfn,
+                                         unsigned long pages)
+{
+       int support, level = 1;
+       unsigned long pfnmerge;
+
+       support = domain->iommu_superpage;
+
+       /* To use a large page, the virtual *and* physical addresses
+          must be aligned to 2MiB/1GiB/etc. Lower bits set in either
+          of them will mean we have to use smaller pages. So just
+          merge them and check both at once. */
+       pfnmerge = iov_pfn | phy_pfn;
+
+       while (support && !(pfnmerge & ~VTD_STRIDE_MASK)) {
+               pages >>= VTD_STRIDE_SHIFT;
+               if (!pages)
+                       break;
+               pfnmerge >>= VTD_STRIDE_SHIFT;
+               level++;
+               support--;
+       }
+       return level;
+}
+
 static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
                            struct scatterlist *sg, unsigned long phys_pfn,
                            unsigned long nr_pages, int prot)
@@ -1656,6 +1754,8 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
        phys_addr_t uninitialized_var(pteval);
        int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
        unsigned long sg_res;
+       unsigned int largepage_lvl = 0;
+       unsigned long lvl_pages = 0;
 
        BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
 
@@ -1671,7 +1771,7 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
                pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
        }
 
-       while (nr_pages--) {
+       while (nr_pages > 0) {
                uint64_t tmp;
 
                if (!sg_res) {
@@ -1679,11 +1779,21 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
                        sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
                        sg->dma_length = sg->length;
                        pteval = page_to_phys(sg_page(sg)) | prot;
+                       phys_pfn = pteval >> VTD_PAGE_SHIFT;
                }
+
                if (!pte) {
-                       first_pte = pte = pfn_to_dma_pte(domain, iov_pfn);
+                       largepage_lvl = hardware_largepage_caps(domain, iov_pfn, phys_pfn, sg_res);
+
+                       first_pte = pte = pfn_to_dma_pte(domain, iov_pfn, largepage_lvl);
                        if (!pte)
                                return -ENOMEM;
+                       /* It is large page*/
+                       if (largepage_lvl > 1)
+                               pteval |= DMA_PTE_LARGE_PAGE;
+                       else
+                               pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
+
                }
                /* We don't need lock here, nobody else
                 * touches the iova range
@@ -1699,16 +1809,38 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
                        }
                        WARN_ON(1);
                }
+
+               lvl_pages = lvl_to_nr_pages(largepage_lvl);
+
+               BUG_ON(nr_pages < lvl_pages);
+               BUG_ON(sg_res < lvl_pages);
+
+               nr_pages -= lvl_pages;
+               iov_pfn += lvl_pages;
+               phys_pfn += lvl_pages;
+               pteval += lvl_pages * VTD_PAGE_SIZE;
+               sg_res -= lvl_pages;
+
+               /* If the next PTE would be the first in a new page, then we
+                  need to flush the cache on the entries we've just written.
+                  And then we'll need to recalculate 'pte', so clear it and
+                  let it get set again in the if (!pte) block above.
+
+                  If we're done (!nr_pages) we need to flush the cache too.
+
+                  Also if we've been setting superpages, we may need to
+                  recalculate 'pte' and switch back to smaller pages for the
+                  end of the mapping, if the trailing size is not enough to
+                  use another superpage (i.e. sg_res < lvl_pages). */
                pte++;
-               if (!nr_pages || first_pte_in_page(pte)) {
+               if (!nr_pages || first_pte_in_page(pte) ||
+                   (largepage_lvl > 1 && sg_res < lvl_pages)) {
                        domain_flush_cache(domain, first_pte,
                                           (void *)pte - (void *)first_pte);
                        pte = NULL;
                }
-               iov_pfn++;
-               pteval += VTD_PAGE_SIZE;
-               sg_res--;
-               if (!sg_res)
+
+               if (!sg_res && nr_pages)
                        sg = sg_next(sg);
        }
        return 0;
@@ -2016,7 +2148,7 @@ static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
        if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
                return 0;
        return iommu_prepare_identity_map(pdev, rmrr->base_address,
-               rmrr->end_address + 1);
+               rmrr->end_address);
 }
 
 #ifdef CONFIG_DMAR_FLOPPY_WA
@@ -2030,7 +2162,7 @@ static inline void iommu_prepare_isa(void)
                return;
 
        printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
-       ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024);
+       ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024 - 1);
 
        if (ret)
                printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
@@ -2106,10 +2238,10 @@ static int identity_mapping(struct pci_dev *pdev)
        if (likely(!iommu_identity_mapping))
                return 0;
 
+       info = pdev->dev.archdata.iommu;
+       if (info && info != DUMMY_DEVICE_DOMAIN_INFO)
+               return (info->domain == si_domain);
 
-       list_for_each_entry(info, &si_domain->devices, link)
-               if (info->dev == pdev)
-                       return 1;
        return 0;
 }
 
@@ -2187,8 +2319,19 @@ static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
         * Assume that they will -- if they turn out not to be, then we can 
         * take them out of the 1:1 domain later.
         */
-       if (!startup)
-               return pdev->dma_mask > DMA_BIT_MASK(32);
+       if (!startup) {
+               /*
+                * If the device's dma_mask is less than the system's memory
+                * size then this is not a candidate for identity mapping.
+                */
+               u64 dma_mask = pdev->dma_mask;
+
+               if (pdev->dev.coherent_dma_mask &&
+                   pdev->dev.coherent_dma_mask < dma_mask)
+                       dma_mask = pdev->dev.coherent_dma_mask;
+
+               return dma_mask >= dma_get_required_mask(&pdev->dev);
+       }
 
        return 1;
 }
@@ -2203,6 +2346,9 @@ static int __init iommu_prepare_static_identity_mapping(int hw)
                return -EFAULT;
 
        for_each_pci_dev(pdev) {
+               /* Skip Host/PCI Bridge devices */
+               if (IS_BRIDGE_HOST_DEVICE(pdev))
+                       continue;
                if (iommu_should_identity_map(pdev, 1)) {
                        printk(KERN_INFO "IOMMU: %s identity mapping for device %s\n",
                               hw ? "hardware" : "software", pci_name(pdev));
@@ -2218,7 +2364,7 @@ static int __init iommu_prepare_static_identity_mapping(int hw)
        return 0;
 }
 
-static int __init init_dmars(int force_on)
+static int __init init_dmars(void)
 {
        struct dmar_drhd_unit *drhd;
        struct dmar_rmrr_unit *rmrr;
@@ -2592,8 +2738,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
        iommu = domain_get_iommu(domain);
        size = aligned_nrpages(paddr, size);
 
-       iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
-                               pdev->dma_mask);
+       iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size), dma_mask);
        if (!iova)
                goto error;
 
@@ -3118,7 +3263,17 @@ static int init_iommu_hw(void)
                if (iommu->qi)
                        dmar_reenable_qi(iommu);
 
-       for_each_active_iommu(iommu, drhd) {
+       for_each_iommu(iommu, drhd) {
+               if (drhd->ignored) {
+                       /*
+                        * we always have to disable PMRs or DMA may fail on
+                        * this device
+                        */
+                       if (force_on)
+                               iommu_disable_protect_mem_regions(iommu);
+                       continue;
+               }
+       
                iommu_flush_write_buffer(iommu);
 
                iommu_set_root_entry(iommu);
@@ -3127,7 +3282,8 @@ static int init_iommu_hw(void)
                                           DMA_CCMD_GLOBAL_INVL);
                iommu->flush.flush_iotlb(iommu, 0, 0, 0,
                                         DMA_TLB_GLOBAL_FLUSH);
-               iommu_enable_translation(iommu);
+               if (iommu_enable_translation(iommu))
+                       return 1;
                iommu_disable_protect_mem_regions(iommu);
        }
 
@@ -3194,7 +3350,10 @@ static void iommu_resume(void)
        unsigned long flag;
 
        if (init_iommu_hw()) {
-               WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
+               if (force_on)
+                       panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
+               else
+                       WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
                return;
        }
 
@@ -3229,7 +3388,7 @@ static void __init init_iommu_pm_ops(void)
 }
 
 #else
-static inline int init_iommu_pm_ops(void) { }
+static inline void init_iommu_pm_ops(void) {}
 #endif /* CONFIG_PM */
 
 /*
@@ -3271,7 +3430,6 @@ static struct notifier_block device_nb = {
 int __init intel_iommu_init(void)
 {
        int ret = 0;
-       int force_on = 0;
 
        /* VT-d is required for a TXT/tboot launch, so enforce that */
        force_on = tboot_force_iommu();
@@ -3309,7 +3467,7 @@ int __init intel_iommu_init(void)
 
        init_no_remapping_devices();
 
-       ret = init_dmars(force_on);
+       ret = init_dmars();
        if (ret) {
                if (force_on)
                        panic("tboot: Failed to initialize DMARs\n");
@@ -3380,8 +3538,8 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain,
        spin_lock_irqsave(&device_domain_lock, flags);
        list_for_each_safe(entry, tmp, &domain->devices) {
                info = list_entry(entry, struct device_domain_info, link);
-               /* No need to compare PCI domain; it has to be the same */
-               if (info->bus == pdev->bus->number &&
+               if (info->segment == pci_domain_nr(pdev->bus) &&
+                   info->bus == pdev->bus->number &&
                    info->devfn == pdev->devfn) {
                        list_del(&info->link);
                        list_del(&info->global);
@@ -3419,10 +3577,13 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain,
                domain_update_iommu_cap(domain);
                spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
 
-               spin_lock_irqsave(&iommu->lock, tmp_flags);
-               clear_bit(domain->id, iommu->domain_ids);
-               iommu->domains[domain->id] = NULL;
-               spin_unlock_irqrestore(&iommu->lock, tmp_flags);
+               if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
+                   !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)) {
+                       spin_lock_irqsave(&iommu->lock, tmp_flags);
+                       clear_bit(domain->id, iommu->domain_ids);
+                       iommu->domains[domain->id] = NULL;
+                       spin_unlock_irqrestore(&iommu->lock, tmp_flags);
+               }
        }
 
        spin_unlock_irqrestore(&device_domain_lock, flags);
@@ -3505,6 +3666,7 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width)
        domain->iommu_count = 0;
        domain->iommu_coherency = 0;
        domain->iommu_snooping = 0;
+       domain->iommu_superpage = 0;
        domain->max_addr = 0;
        domain->nid = -1;
 
@@ -3720,7 +3882,7 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
        struct dma_pte *pte;
        u64 phys = 0;
 
-       pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT);
+       pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, 0);
        if (pte)
                phys = dma_pte_addr(pte);
 
index 9606e599a47552f9119425c077f62a0c807d3b9f..c5c274ab5c5a034abe91fb1f1f5dcf6380c9315e 100644 (file)
@@ -63,8 +63,16 @@ __cached_rbnode_delete_update(struct iova_domain *iovad, struct iova *free)
        curr = iovad->cached32_node;
        cached_iova = container_of(curr, struct iova, node);
 
-       if (free->pfn_lo >= cached_iova->pfn_lo)
-               iovad->cached32_node = rb_next(&free->node);
+       if (free->pfn_lo >= cached_iova->pfn_lo) {
+               struct rb_node *node = rb_next(&free->node);
+               struct iova *iova = container_of(node, struct iova, node);
+
+               /* only cache if it's below 32bit pfn */
+               if (node && iova->pfn_lo < iovad->dma_32bit_pfn)
+                       iovad->cached32_node = node;
+               else
+                       iovad->cached32_node = NULL;
+       }
 }
 
 /* Computes the padding size required, to make the
index 7c3b18e78cee148d889a8a63ccc2fd4785eab81a..d36f41ea8cbfb9ccd61ebfc9c68700b98cb31136 100644 (file)
@@ -195,6 +195,8 @@ static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev)
                return PCI_D2;
        case ACPI_STATE_D3:
                return PCI_D3hot;
+       case ACPI_STATE_D3_COLD:
+               return PCI_D3cold;
        }
        return PCI_POWER_ERROR;
 }
index 135df164a4c1e897e4d36a7d5a49336518669480..46767c53917a5e28ee8fcec10d92de6c39609eba 100644 (file)
@@ -624,7 +624,7 @@ static int pci_pm_prepare(struct device *dev)
         * system from the sleep state, we'll have to prevent it from signaling
         * wake-up.
         */
-       pm_runtime_resume(dev);
+       pm_runtime_get_sync(dev);
 
        if (drv && drv->pm && drv->pm->prepare)
                error = drv->pm->prepare(dev);
@@ -638,6 +638,8 @@ static void pci_pm_complete(struct device *dev)
 
        if (drv && drv->pm && drv->pm->complete)
                drv->pm->complete(dev);
+
+       pm_runtime_put_sync(dev);
 }
 
 #else /* !CONFIG_PM_SLEEP */
index 22c9b27fdd8d8bd0bc9790416cd2ef883f5b67e9..2c5b9b9912795c880faa882bbf4a8d9523037530 100644 (file)
@@ -3271,11 +3271,11 @@ void __init pci_register_set_vga_state(arch_set_vga_state_t func)
 }
 
 static int pci_set_vga_state_arch(struct pci_dev *dev, bool decode,
-                     unsigned int command_bits, bool change_bridge)
+                     unsigned int command_bits, u32 flags)
 {
        if (arch_set_vga_state)
                return arch_set_vga_state(dev, decode, command_bits,
-                                               change_bridge);
+                                               flags);
        return 0;
 }
 
@@ -3284,31 +3284,34 @@ static int pci_set_vga_state_arch(struct pci_dev *dev, bool decode,
  * @dev: the PCI device
  * @decode: true = enable decoding, false = disable decoding
  * @command_bits: PCI_COMMAND_IO and/or PCI_COMMAND_MEMORY
- * @change_bridge: traverse ancestors and change bridges
+ * @flags: traverse ancestors and change bridges
+ * CHANGE_BRIDGE_ONLY / CHANGE_BRIDGE
  */
 int pci_set_vga_state(struct pci_dev *dev, bool decode,
-                     unsigned int command_bits, bool change_bridge)
+                     unsigned int command_bits, u32 flags)
 {
        struct pci_bus *bus;
        struct pci_dev *bridge;
        u16 cmd;
        int rc;
 
-       WARN_ON(command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
+       WARN_ON((flags & PCI_VGA_STATE_CHANGE_DECODES) & (command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY)));
 
        /* ARCH specific VGA enables */
-       rc = pci_set_vga_state_arch(dev, decode, command_bits, change_bridge);
+       rc = pci_set_vga_state_arch(dev, decode, command_bits, flags);
        if (rc)
                return rc;
 
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
-       if (decode == true)
-               cmd |= command_bits;
-       else
-               cmd &= ~command_bits;
-       pci_write_config_word(dev, PCI_COMMAND, cmd);
+       if (flags & PCI_VGA_STATE_CHANGE_DECODES) {
+               pci_read_config_word(dev, PCI_COMMAND, &cmd);
+               if (decode == true)
+                       cmd |= command_bits;
+               else
+                       cmd &= ~command_bits;
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
 
-       if (change_bridge == false)
+       if (!(flags & PCI_VGA_STATE_CHANGE_BRIDGE))
                return 0;
 
        bus = dev->bus;
index 48849ffdd67214265693c92076970e00ab329d2a..bafb3c3d4a8963e6a635d94a414e290e4998af40 100644 (file)
@@ -168,7 +168,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN;
                if (type == pci_bar_io) {
                        l &= PCI_BASE_ADDRESS_IO_MASK;
-                       mask = PCI_BASE_ADDRESS_IO_MASK & IO_SPACE_LIMIT;
+                       mask = PCI_BASE_ADDRESS_IO_MASK & (u32) IO_SPACE_LIMIT;
                } else {
                        l &= PCI_BASE_ADDRESS_MEM_MASK;
                        mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
index 100c4412457de1357348c9e9eb5b3c29ae8bbdd8..749c2a16012c582bca165db93f14cf4c21ec5293 100644 (file)
@@ -45,7 +45,7 @@ MODULE_LICENSE("GPL");
 
 static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
 {
-       struct pcmcia_device_id *did = p_drv->id_table;
+       const struct pcmcia_device_id *did = p_drv->id_table;
        unsigned int i;
        u32 hash;
 
@@ -784,7 +784,7 @@ static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filenam
 
 
 static inline int pcmcia_devmatch(struct pcmcia_device *dev,
-                                 struct pcmcia_device_id *did)
+                                 const struct pcmcia_device_id *did)
 {
        if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) {
                if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id))
@@ -890,7 +890,7 @@ static int pcmcia_bus_match(struct device *dev, struct device_driver *drv)
 {
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
        struct pcmcia_driver *p_drv = to_pcmcia_drv(drv);
-       struct pcmcia_device_id *did = p_drv->id_table;
+       const struct pcmcia_device_id *did = p_drv->id_table;
        struct pcmcia_dynid *dynid;
 
        /* match dynamic devices first */
index 435002dfc3caef7a418944e9e967af8a27c6b822..712baab3c83d58147237384fb168a4a6c3ceba1c 100644 (file)
@@ -11,6 +11,7 @@
  *
  */
 
+#include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
index fb9740d3e9a76e5b30317860ebafee954eef0a6c..2eea664bc079665823804114d9aa4e82af9885fc 100644 (file)
@@ -43,7 +43,7 @@
 
 int __init pcmcia_collie_init(struct device *dev);
 
-static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = {
+static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) __devinitdata = {
 #ifdef CONFIG_SA1100_ASSABET
        pcmcia_assabet_init,
 #endif
index 485c09eef424eeb3d1b2e4f06c191cc33722a4f3..45e0191c35ddff9f977af6d07a6876e47e0f1bce 100644 (file)
@@ -39,7 +39,7 @@ config ACER_WMI
 
 config ACERHDF
        tristate "Acer Aspire One temperature and fan driver"
-       depends on THERMAL && THERMAL_HWMON && ACPI
+       depends on THERMAL && ACPI
        ---help---
          This is a driver for Acer Aspire One netbooks. It allows to access
          the temperature sensor and to control the fan.
@@ -753,4 +753,20 @@ config SAMSUNG_LAPTOP
          To compile this driver as a module, choose M here: the module
          will be called samsung-laptop.
 
+config MXM_WMI
+       tristate "WMI support for MXM Laptop Graphics"
+       depends on ACPI_WMI
+       ---help---
+          MXM is a standard for laptop graphics cards, the WMI interface
+         is required for switchable nvidia graphics machines
+
+config INTEL_OAKTRAIL
+       tristate "Intel Oaktrail Platform Extras"
+       depends on ACPI
+       depends on RFKILL && BACKLIGHT_CLASS_DEVICE && ACPI
+       ---help---
+         Intel Oaktrail platform need this driver to provide interfaces to
+         enable/disable the Camera, WiFi, BT etc. devices. If in doubt, say Y
+         here; it will only load on supported platforms.
+
 endif # X86_PLATFORM_DEVICES
index 029e8861d086d19cbc5c28bafb15a449717a0af4..afc1f832aa67df8639131835bbd2416bb5ac7774 100644 (file)
@@ -41,4 +41,6 @@ obj-$(CONFIG_XO1_RFKILL)      += xo1-rfkill.o
 obj-$(CONFIG_XO15_EBOOK)       += xo15-ebook.o
 obj-$(CONFIG_IBM_RTL)          += ibm_rtl.o
 obj-$(CONFIG_SAMSUNG_LAPTOP)   += samsung-laptop.o
-obj-$(CONFIG_INTEL_MFLD_THERMAL)       += intel_mid_thermal.o
+obj-$(CONFIG_MXM_WMI)          += mxm-wmi.o
+obj-$(CONFIG_INTEL_MID_POWER_BUTTON)   += intel_mid_powerbtn.o
+obj-$(CONFIG_INTEL_OAKTRAIL)   += intel_oaktrail.o
index ac4e7f83ce6c8a4914af0e2df7080bd956b26f6f..005417bd429e815f24cce88c23b4f53ef46afc74 100644 (file)
@@ -98,13 +98,26 @@ enum acer_wmi_event_ids {
 
 static const struct key_entry acer_wmi_keymap[] = {
        {KE_KEY, 0x01, {KEY_WLAN} },     /* WiFi */
+       {KE_KEY, 0x03, {KEY_WLAN} },     /* WiFi */
        {KE_KEY, 0x12, {KEY_BLUETOOTH} },       /* BT */
        {KE_KEY, 0x21, {KEY_PROG1} },    /* Backup */
        {KE_KEY, 0x22, {KEY_PROG2} },    /* Arcade */
        {KE_KEY, 0x23, {KEY_PROG3} },    /* P_Key */
        {KE_KEY, 0x24, {KEY_PROG4} },    /* Social networking_Key */
+       {KE_IGNORE, 0x41, {KEY_MUTE} },
+       {KE_IGNORE, 0x42, {KEY_PREVIOUSSONG} },
+       {KE_IGNORE, 0x43, {KEY_NEXTSONG} },
+       {KE_IGNORE, 0x44, {KEY_PLAYPAUSE} },
+       {KE_IGNORE, 0x45, {KEY_STOP} },
+       {KE_IGNORE, 0x48, {KEY_VOLUMEUP} },
+       {KE_IGNORE, 0x49, {KEY_VOLUMEDOWN} },
+       {KE_IGNORE, 0x61, {KEY_SWITCHVIDEOMODE} },
+       {KE_IGNORE, 0x62, {KEY_BRIGHTNESSUP} },
+       {KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} },
        {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */
+       {KE_IGNORE, 0x81, {KEY_SLEEP} },
        {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad On/Off */
+       {KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} },
        {KE_END, 0}
 };
 
@@ -122,6 +135,7 @@ struct event_return_value {
  */
 #define ACER_WMID3_GDS_WIRELESS                (1<<0)  /* WiFi */
 #define ACER_WMID3_GDS_THREEG          (1<<6)  /* 3G */
+#define ACER_WMID3_GDS_WIMAX           (1<<7)  /* WiMAX */
 #define ACER_WMID3_GDS_BLUETOOTH       (1<<11) /* BT */
 
 struct lm_input_params {
@@ -737,8 +751,11 @@ WMI_execute_u32(u32 method_id, u32 in, u32 *out)
 
        obj = (union acpi_object *) result.pointer;
        if (obj && obj->type == ACPI_TYPE_BUFFER &&
-               obj->buffer.length == sizeof(u32)) {
+               (obj->buffer.length == sizeof(u32) ||
+               obj->buffer.length == sizeof(u64))) {
                tmp = *((u32 *) obj->buffer.pointer);
+       } else if (obj->type == ACPI_TYPE_INTEGER) {
+               tmp = (u32) obj->integer.value;
        } else {
                tmp = 0;
        }
@@ -866,8 +883,11 @@ static acpi_status WMID_set_capabilities(void)
 
        obj = (union acpi_object *) out.pointer;
        if (obj && obj->type == ACPI_TYPE_BUFFER &&
-               obj->buffer.length == sizeof(u32)) {
+               (obj->buffer.length == sizeof(u32) ||
+               obj->buffer.length == sizeof(u64))) {
                devices = *((u32 *) obj->buffer.pointer);
+       } else if (obj->type == ACPI_TYPE_INTEGER) {
+               devices = (u32) obj->integer.value;
        } else {
                kfree(out.pointer);
                return AE_ERROR;
@@ -876,7 +896,8 @@ static acpi_status WMID_set_capabilities(void)
        dmi_walk(type_aa_dmi_decode, NULL);
        if (!has_type_aa) {
                interface->capability |= ACER_CAP_WIRELESS;
-               interface->capability |= ACER_CAP_THREEG;
+               if (devices & 0x40)
+                       interface->capability |= ACER_CAP_THREEG;
                if (devices & 0x10)
                        interface->capability |= ACER_CAP_BLUETOOTH;
        }
@@ -961,10 +982,12 @@ 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);
-       if (!has_type_aa)
+       if (mailled >= 0)
+               set_u32(mailled, ACER_CAP_MAILLED);
+       if (!has_type_aa && threeg >= 0)
                set_u32(threeg, ACER_CAP_THREEG);
-       set_u32(brightness, ACER_CAP_BRIGHTNESS);
+       if (brightness >= 0)
+               set_u32(brightness, ACER_CAP_BRIGHTNESS);
 }
 
 /*
@@ -1081,7 +1104,7 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device)
                return AE_ERROR;
        }
        if (obj->buffer.length != 8) {
-               pr_warning("Unknown buffer length %d\n", obj->buffer.length);
+               pr_warn("Unknown buffer length %d\n", obj->buffer.length);
                kfree(obj);
                return AE_ERROR;
        }
@@ -1090,8 +1113,8 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device)
        kfree(obj);
 
        if (return_value.error_code || return_value.ec_return_value)
-               pr_warning("Get Device Status failed: "
-                       "0x%x - 0x%x\n", return_value.error_code,
+               pr_warn("Get Device Status failed: 0x%x - 0x%x\n",
+                       return_value.error_code,
                        return_value.ec_return_value);
        else
                *value = !!(return_value.devices & device);
@@ -1124,6 +1147,114 @@ static acpi_status get_device_status(u32 *value, u32 cap)
        }
 }
 
+static acpi_status wmid3_set_device_status(u32 value, u16 device)
+{
+       struct wmid3_gds_return_value return_value;
+       acpi_status status;
+       union acpi_object *obj;
+       u16 devices;
+       struct wmid3_gds_input_param params = {
+               .function_num = 0x1,
+               .hotkey_number = 0x01,
+               .devices = ACER_WMID3_GDS_WIRELESS &
+                               ACER_WMID3_GDS_THREEG &
+                               ACER_WMID3_GDS_WIMAX &
+                               ACER_WMID3_GDS_BLUETOOTH,
+       };
+       struct acpi_buffer input = {
+               sizeof(struct wmid3_gds_input_param),
+               &params
+       };
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
+
+       status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = output.pointer;
+
+       if (!obj)
+               return AE_ERROR;
+       else if (obj->type != ACPI_TYPE_BUFFER) {
+               kfree(obj);
+               return AE_ERROR;
+       }
+       if (obj->buffer.length != 8) {
+               pr_warning("Unknown buffer length %d\n", obj->buffer.length);
+               kfree(obj);
+               return AE_ERROR;
+       }
+
+       return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
+       kfree(obj);
+
+       if (return_value.error_code || return_value.ec_return_value) {
+               pr_warning("Get Current Device Status failed: "
+                       "0x%x - 0x%x\n", return_value.error_code,
+                       return_value.ec_return_value);
+               return status;
+       }
+
+       devices = return_value.devices;
+       params.function_num = 0x2;
+       params.hotkey_number = 0x01;
+       params.devices = (value) ? (devices | device) : (devices & ~device);
+
+       status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output2);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = output2.pointer;
+
+       if (!obj)
+               return AE_ERROR;
+       else if (obj->type != ACPI_TYPE_BUFFER) {
+               kfree(obj);
+               return AE_ERROR;
+       }
+       if (obj->buffer.length != 4) {
+               pr_warning("Unknown buffer length %d\n", obj->buffer.length);
+               kfree(obj);
+               return AE_ERROR;
+       }
+
+       return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
+       kfree(obj);
+
+       if (return_value.error_code || return_value.ec_return_value)
+               pr_warning("Set Device Status failed: "
+                       "0x%x - 0x%x\n", return_value.error_code,
+                       return_value.ec_return_value);
+
+       return status;
+}
+
+static acpi_status set_device_status(u32 value, u32 cap)
+{
+       if (wmi_has_guid(WMID_GUID3)) {
+               u16 device;
+
+               switch (cap) {
+               case ACER_CAP_WIRELESS:
+                       device = ACER_WMID3_GDS_WIRELESS;
+                       break;
+               case ACER_CAP_BLUETOOTH:
+                       device = ACER_WMID3_GDS_BLUETOOTH;
+                       break;
+               case ACER_CAP_THREEG:
+                       device = ACER_WMID3_GDS_THREEG;
+                       break;
+               default:
+                       return AE_ERROR;
+               }
+               return wmid3_set_device_status(value, device);
+
+       } else {
+               return set_u32(value, cap);
+       }
+}
+
 /*
  * Rfkill devices
  */
@@ -1160,7 +1291,7 @@ static int acer_rfkill_set(void *data, bool blocked)
        u32 cap = (unsigned long)data;
 
        if (rfkill_inited) {
-               status = set_u32(!blocked, cap);
+               status = set_device_status(!blocked, cap);
                if (ACPI_FAILURE(status))
                        return -ENODEV;
        }
@@ -1317,7 +1448,7 @@ static void acer_wmi_notify(u32 value, void *context)
 
        status = wmi_get_event_data(value, &response);
        if (status != AE_OK) {
-               pr_warning("bad event status 0x%x\n", status);
+               pr_warn("bad event status 0x%x\n", status);
                return;
        }
 
@@ -1326,12 +1457,12 @@ static void acer_wmi_notify(u32 value, void *context)
        if (!obj)
                return;
        if (obj->type != ACPI_TYPE_BUFFER) {
-               pr_warning("Unknown response received %d\n", obj->type);
+               pr_warn("Unknown response received %d\n", obj->type);
                kfree(obj);
                return;
        }
        if (obj->buffer.length != 8) {
-               pr_warning("Unknown buffer length %d\n", obj->buffer.length);
+               pr_warn("Unknown buffer length %d\n", obj->buffer.length);
                kfree(obj);
                return;
        }
@@ -1343,7 +1474,7 @@ static void acer_wmi_notify(u32 value, void *context)
        case WMID_HOTKEY_EVENT:
                if (return_value.device_state) {
                        u16 device_state = return_value.device_state;
-                       pr_debug("deivces states: 0x%x\n", device_state);
+                       pr_debug("device state: 0x%x\n", device_state);
                        if (has_cap(ACER_CAP_WIRELESS))
                                rfkill_set_sw_state(wireless_rfkill,
                                !(device_state & ACER_WMID3_GDS_WIRELESS));
@@ -1356,11 +1487,11 @@ static void acer_wmi_notify(u32 value, void *context)
                }
                if (!sparse_keymap_report_event(acer_wmi_input_dev,
                                return_value.key_num, 1, true))
-                       pr_warning("Unknown key number - 0x%x\n",
+                       pr_warn("Unknown key number - 0x%x\n",
                                return_value.key_num);
                break;
        default:
-               pr_warning("Unknown function number - %d - %d\n",
+               pr_warn("Unknown function number - %d - %d\n",
                        return_value.function, return_value.key_num);
                break;
        }
@@ -1389,7 +1520,7 @@ wmid3_set_lm_mode(struct lm_input_params *params,
                return AE_ERROR;
        }
        if (obj->buffer.length != 4) {
-               pr_warning("Unknown buffer length %d\n", obj->buffer.length);
+               pr_warn("Unknown buffer length %d\n", obj->buffer.length);
                kfree(obj);
                return AE_ERROR;
        }
@@ -1414,11 +1545,11 @@ static int acer_wmi_enable_ec_raw(void)
        status = wmid3_set_lm_mode(&params, &return_value);
 
        if (return_value.error_code || return_value.ec_return_value)
-               pr_warning("Enabling EC raw mode failed: "
-                      "0x%x - 0x%x\n", return_value.error_code,
-                      return_value.ec_return_value);
+               pr_warn("Enabling EC raw mode failed: 0x%x - 0x%x\n",
+                       return_value.error_code,
+                       return_value.ec_return_value);
        else
-               pr_info("Enabled EC raw mode");
+               pr_info("Enabled EC raw mode\n");
 
        return status;
 }
@@ -1437,9 +1568,9 @@ static int acer_wmi_enable_lm(void)
        status = wmid3_set_lm_mode(&params, &return_value);
 
        if (return_value.error_code || return_value.ec_return_value)
-               pr_warning("Enabling Launch Manager failed: "
-                      "0x%x - 0x%x\n", return_value.error_code,
-                      return_value.ec_return_value);
+               pr_warn("Enabling Launch Manager failed: 0x%x - 0x%x\n",
+                       return_value.error_code,
+                       return_value.ec_return_value);
 
        return status;
 }
@@ -1506,8 +1637,11 @@ static u32 get_wmid_devices(void)
 
        obj = (union acpi_object *) out.pointer;
        if (obj && obj->type == ACPI_TYPE_BUFFER &&
-               obj->buffer.length == sizeof(u32)) {
+               (obj->buffer.length == sizeof(u32) ||
+               obj->buffer.length == sizeof(u64))) {
                devices = *((u32 *) obj->buffer.pointer);
+       } else if (obj->type == ACPI_TYPE_INTEGER) {
+               devices = (u32) obj->integer.value;
        }
 
        kfree(out.pointer);
index 60f9cfcac93ff83e36c730eb555a5c65a066a12b..fca3489218b76b0c48a08fb5ef2cc0e0ad3250ed 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/fs.h>
 #include <linux/dmi.h>
-#include <acpi/acpi_drivers.h>
-#include <linux/sched.h>
+#include <linux/acpi.h>
 #include <linux/thermal.h>
 #include <linux/platform_device.h>
 
index c53b3ff7978a52cd339db953f65a307c128f66a7..d65df92e2acc63fb9eea85d82434c359ed8654fd 100644 (file)
@@ -318,7 +318,7 @@ static int acpi_check_handle(acpi_handle handle, const char *method,
 
        if (status != AE_OK) {
                if (ret)
-                       pr_warning("Error finding %s\n", method);
+                       pr_warn("Error finding %s\n", method);
                return -ENODEV;
        }
        return 0;
@@ -383,7 +383,7 @@ static int asus_kled_lvl(struct asus_laptop *asus)
        rv = acpi_evaluate_integer(asus->handle, METHOD_KBD_LIGHT_GET,
                                   &params, &kblv);
        if (ACPI_FAILURE(rv)) {
-               pr_warning("Error reading kled level\n");
+               pr_warn("Error reading kled level\n");
                return -ENODEV;
        }
        return kblv;
@@ -397,7 +397,7 @@ static int asus_kled_set(struct asus_laptop *asus, int kblv)
                kblv = 0;
 
        if (write_acpi_int(asus->handle, METHOD_KBD_LIGHT_SET, kblv)) {
-               pr_warning("Keyboard LED display write failed\n");
+               pr_warn("Keyboard LED display write failed\n");
                return -EINVAL;
        }
        return 0;
@@ -531,7 +531,7 @@ static int asus_read_brightness(struct backlight_device *bd)
        rv = acpi_evaluate_integer(asus->handle, METHOD_BRIGHTNESS_GET,
                                   NULL, &value);
        if (ACPI_FAILURE(rv))
-               pr_warning("Error reading brightness\n");
+               pr_warn("Error reading brightness\n");
 
        return value;
 }
@@ -541,7 +541,7 @@ static int asus_set_brightness(struct backlight_device *bd, int value)
        struct asus_laptop *asus = bl_get_data(bd);
 
        if (write_acpi_int(asus->handle, METHOD_BRIGHTNESS_SET, value)) {
-               pr_warning("Error changing brightness\n");
+               pr_warn("Error changing brightness\n");
                return -EIO;
        }
        return 0;
@@ -730,7 +730,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(asus->handle, METHOD_LEDD, value)) {
-                       pr_warning("LED display write failed\n");
+                       pr_warn("LED display write failed\n");
                        return -ENODEV;
                }
                asus->ledd_status = (u32) value;
@@ -752,7 +752,7 @@ static int asus_wireless_status(struct asus_laptop *asus, int mask)
        rv = acpi_evaluate_integer(asus->handle, METHOD_WL_STATUS,
                                   NULL, &status);
        if (ACPI_FAILURE(rv)) {
-               pr_warning("Error reading Wireless status\n");
+               pr_warn("Error reading Wireless status\n");
                return -EINVAL;
        }
        return !!(status & mask);
@@ -764,7 +764,7 @@ static int asus_wireless_status(struct asus_laptop *asus, int mask)
 static int asus_wlan_set(struct asus_laptop *asus, int status)
 {
        if (write_acpi_int(asus->handle, METHOD_WLAN, !!status)) {
-               pr_warning("Error setting wlan status to %d", status);
+               pr_warn("Error setting wlan status to %d\n", status);
                return -EIO;
        }
        return 0;
@@ -792,7 +792,7 @@ static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
 static int asus_bluetooth_set(struct asus_laptop *asus, int status)
 {
        if (write_acpi_int(asus->handle, METHOD_BLUETOOTH, !!status)) {
-               pr_warning("Error setting bluetooth status to %d", status);
+               pr_warn("Error setting bluetooth status to %d\n", status);
                return -EIO;
        }
        return 0;
@@ -821,7 +821,7 @@ static ssize_t store_bluetooth(struct device *dev,
 static int asus_wimax_set(struct asus_laptop *asus, int status)
 {
        if (write_acpi_int(asus->handle, METHOD_WIMAX, !!status)) {
-               pr_warning("Error setting wimax status to %d", status);
+               pr_warn("Error setting wimax status to %d\n", status);
                return -EIO;
        }
        return 0;
@@ -850,7 +850,7 @@ static ssize_t store_wimax(struct device *dev,
 static int asus_wwan_set(struct asus_laptop *asus, int status)
 {
        if (write_acpi_int(asus->handle, METHOD_WWAN, !!status)) {
-               pr_warning("Error setting wwan status to %d", status);
+               pr_warn("Error setting wwan status to %d\n", status);
                return -EIO;
        }
        return 0;
@@ -880,7 +880,7 @@ static void asus_set_display(struct asus_laptop *asus, int value)
 {
        /* no sanity check needed for now */
        if (write_acpi_int(asus->handle, METHOD_SWITCH_DISPLAY, value))
-               pr_warning("Error setting display\n");
+               pr_warn("Error setting display\n");
        return;
 }
 
@@ -909,7 +909,7 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
 static void asus_als_switch(struct asus_laptop *asus, int value)
 {
        if (write_acpi_int(asus->handle, METHOD_ALS_CONTROL, value))
-               pr_warning("Error setting light sensor switch\n");
+               pr_warn("Error setting light sensor switch\n");
        asus->light_switch = value;
 }
 
@@ -937,7 +937,7 @@ static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
 static void asus_als_level(struct asus_laptop *asus, int value)
 {
        if (write_acpi_int(asus->handle, METHOD_ALS_LEVEL, value))
-               pr_warning("Error setting light sensor level\n");
+               pr_warn("Error setting light sensor level\n");
        asus->light_level = value;
 }
 
@@ -976,7 +976,7 @@ static int asus_gps_status(struct asus_laptop *asus)
        rv = acpi_evaluate_integer(asus->handle, METHOD_GPS_STATUS,
                                   NULL, &status);
        if (ACPI_FAILURE(rv)) {
-               pr_warning("Error reading GPS status\n");
+               pr_warn("Error reading GPS status\n");
                return -ENODEV;
        }
        return !!status;
@@ -1284,7 +1284,7 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
         */
        status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus->dsdt_info);
        if (ACPI_FAILURE(status))
-               pr_warning("Couldn't get the DSDT table header\n");
+               pr_warn("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_ret(asus->handle, "INIT", 0, &buffer)) {
@@ -1296,7 +1296,7 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
        status =
            acpi_evaluate_integer(asus->handle, "BSTS", NULL, &bsts_result);
        if (ACPI_FAILURE(status))
-               pr_warning("Error calling BSTS\n");
+               pr_warn("Error calling BSTS\n");
        else if (bsts_result)
                pr_notice("BSTS called, 0x%02x returned\n",
                       (uint) bsts_result);
index 832a3fd7c1c8538ef77fd26c628e0ddd2c1644d6..00460cb9587b753119696647844759200a1bc8c8 100644 (file)
@@ -425,7 +425,7 @@ static void asus_rfkill_hotplug(struct asus_wmi *asus)
        if (asus->hotplug_slot) {
                bus = pci_find_bus(0, 1);
                if (!bus) {
-                       pr_warning("Unable to find PCI bus 1?\n");
+                       pr_warn("Unable to find PCI bus 1?\n");
                        goto out_unlock;
                }
 
@@ -436,12 +436,12 @@ static void asus_rfkill_hotplug(struct asus_wmi *asus)
                absent = (l == 0xffffffff);
 
                if (blocked != absent) {
-                       pr_warning("BIOS says wireless lan is %s, "
-                                  "but the pci device is %s\n",
-                                  blocked ? "blocked" : "unblocked",
-                                  absent ? "absent" : "present");
-                       pr_warning("skipped wireless hotplug as probably "
-                                  "inappropriate for this model\n");
+                       pr_warn("BIOS says wireless lan is %s, "
+                               "but the pci device is %s\n",
+                               blocked ? "blocked" : "unblocked",
+                               absent ? "absent" : "present");
+                       pr_warn("skipped wireless hotplug as probably "
+                               "inappropriate for this model\n");
                        goto out_unlock;
                }
 
@@ -500,7 +500,7 @@ static int asus_register_rfkill_notifier(struct asus_wmi *asus, char *node)
                                                     ACPI_SYSTEM_NOTIFY,
                                                     asus_rfkill_notify, asus);
                if (ACPI_FAILURE(status))
-                       pr_warning("Failed to register notify on %s\n", node);
+                       pr_warn("Failed to register notify on %s\n", node);
        } else
                return -ENODEV;
 
@@ -1223,7 +1223,7 @@ static int asus_wmi_sysfs_init(struct platform_device *device)
 /*
  * Platform device
  */
-static int __init asus_wmi_platform_init(struct asus_wmi *asus)
+static int asus_wmi_platform_init(struct asus_wmi *asus)
 {
        int rv;
 
@@ -1583,12 +1583,12 @@ static int asus_wmi_probe(struct platform_device *pdev)
        int ret;
 
        if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) {
-               pr_warning("Management GUID not found\n");
+               pr_warn("Management GUID not found\n");
                return -ENODEV;
        }
 
        if (wdrv->event_guid && !wmi_has_guid(wdrv->event_guid)) {
-               pr_warning("Event GUID not found\n");
+               pr_warn("Event GUID not found\n");
                return -ENODEV;
        }
 
index f503607c0645b015e46fdc963f22fa6e3ba8725c..d9312b3073e5f31f87a36530f07afac51b7264ca 100644 (file)
@@ -30,6 +30,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -581,8 +583,7 @@ static int read_led(const char *ledname, int ledmask)
                if (read_acpi_int(NULL, ledname, &led_status))
                        return led_status;
                else
-                       printk(KERN_WARNING "Asus ACPI: Error reading LED "
-                              "status\n");
+                       pr_warn("Error reading LED status\n");
        }
        return (hotk->status & ledmask) ? 1 : 0;
 }
@@ -621,8 +622,7 @@ write_led(const char __user *buffer, unsigned long count,
                led_out = !led_out;
 
        if (!write_acpi_int(hotk->handle, ledname, led_out, NULL))
-               printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n",
-                      ledname);
+               pr_warn("LED (%s) write failed\n", ledname);
 
        return rv;
 }
@@ -679,8 +679,7 @@ static ssize_t ledd_proc_write(struct file *file, const char __user *buffer,
        if (rv > 0) {
                if (!write_acpi_int
                    (hotk->handle, hotk->methods->mt_ledd, value, NULL))
-                       printk(KERN_WARNING
-                              "Asus ACPI: LED display write failed\n");
+                       pr_warn("LED display write failed\n");
                else
                        hotk->ledd_status = (u32) value;
        }
@@ -838,8 +837,7 @@ static int get_lcd_state(void)
        } 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");
+                       pr_warn("Error reading LCD status\n");
 
                if (hotk->model == L2D)
                        lcd = ~lcd;
@@ -871,7 +869,7 @@ static int set_lcd_state(int value)
                           the exact behaviour is simulated here */
                }
                if (ACPI_FAILURE(status))
-                       printk(KERN_WARNING "Asus ACPI: Error switching LCD\n");
+                       pr_warn("Error switching LCD\n");
        }
        return 0;
 
@@ -915,13 +913,11 @@ static int read_brightness(struct backlight_device *bd)
        if (hotk->methods->brightness_get) {    /* SPLV/GPLV laptop */
                if (!read_acpi_int(hotk->handle, hotk->methods->brightness_get,
                                   &value))
-                       printk(KERN_WARNING
-                              "Asus ACPI: Error reading brightness\n");
+                       pr_warn("Error reading brightness\n");
        } else if (hotk->methods->brightness_status) {  /* For D1 for example */
                if (!read_acpi_int(NULL, hotk->methods->brightness_status,
                                   &value))
-                       printk(KERN_WARNING
-                              "Asus ACPI: Error reading brightness\n");
+                       pr_warn("Error reading brightness\n");
        } else                  /* No GPLV method */
                value = hotk->brightness;
        return value;
@@ -939,8 +935,7 @@ static int set_brightness(int value)
        if (hotk->methods->brightness_set) {
                if (!write_acpi_int(hotk->handle, hotk->methods->brightness_set,
                                    value, NULL)) {
-                       printk(KERN_WARNING
-                              "Asus ACPI: Error changing brightness\n");
+                       pr_warn("Error changing brightness\n");
                        ret = -EIO;
                }
                goto out;
@@ -955,8 +950,7 @@ static int set_brightness(int value)
                                              NULL, NULL);
                (value > 0) ? value-- : value++;
                if (ACPI_FAILURE(status)) {
-                       printk(KERN_WARNING
-                              "Asus ACPI: Error changing brightness\n");
+                       pr_warn("Error changing brightness\n");
                        ret = -EIO;
                }
        }
@@ -1008,7 +1002,7 @@ static void set_display(int value)
        /* no sanity check needed for now */
        if (!write_acpi_int(hotk->handle, hotk->methods->display_set,
                            value, NULL))
-               printk(KERN_WARNING "Asus ACPI: Error setting display\n");
+               pr_warn("Error setting display\n");
        return;
 }
 
@@ -1021,8 +1015,7 @@ static int disp_proc_show(struct seq_file *m, void *v)
        int value = 0;
 
        if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value))
-               printk(KERN_WARNING
-                      "Asus ACPI: Error reading display status\n");
+               pr_warn("Error reading display status\n");
        value &= 0x07;  /* needed for some models, shouldn't hurt others */
        seq_printf(m, "%d\n", value);
        return 0;
@@ -1068,7 +1061,7 @@ asus_proc_add(char *name, const struct file_operations *proc_fops, mode_t mode,
        proc = proc_create_data(name, mode, acpi_device_dir(device),
                                proc_fops, acpi_driver_data(device));
        if (!proc) {
-               printk(KERN_WARNING "  Unable to create %s fs entry\n", name);
+               pr_warn("  Unable to create %s fs entry\n", name);
                return -1;
        }
        proc->uid = asus_uid;
@@ -1085,8 +1078,8 @@ static int asus_hotk_add_fs(struct acpi_device *device)
                mode = S_IFREG | S_IRUGO | S_IWUSR | S_IWGRP;
        } else {
                mode = S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP;
-               printk(KERN_WARNING "  asus_uid and asus_gid parameters are "
-                      "deprecated, use chown and chmod instead!\n");
+               pr_warn("  asus_uid and asus_gid parameters are "
+                       "deprecated, use chown and chmod instead!\n");
        }
 
        acpi_device_dir(device) = asus_proc_dir;
@@ -1099,8 +1092,7 @@ static int asus_hotk_add_fs(struct acpi_device *device)
                proc->uid = asus_uid;
                proc->gid = asus_gid;
        } else {
-               printk(KERN_WARNING "  Unable to create " PROC_INFO
-                      " fs entry\n");
+               pr_warn("  Unable to create " PROC_INFO " fs entry\n");
        }
 
        if (hotk->methods->mt_wled) {
@@ -1283,20 +1275,19 @@ static int asus_hotk_get_info(void)
         */
        status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
        if (ACPI_FAILURE(status))
-               printk(KERN_WARNING "  Couldn't get the DSDT table header\n");
+               pr_warn("  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)) {
-               printk(KERN_ERR "  Hotkey initialization failed\n");
+               pr_err("  Hotkey initialization failed\n");
                return -ENODEV;
        }
 
        /* This needs to be called for some laptops to init properly */
        if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result))
-               printk(KERN_WARNING "  Error calling BSTS\n");
+               pr_warn("  Error calling BSTS\n");
        else if (bsts_result)
-               printk(KERN_NOTICE "  BSTS called, 0x%02x returned\n",
-                      bsts_result);
+               pr_notice("  BSTS called, 0x%02x returned\n", bsts_result);
 
        /*
         * Try to match the object returned by INIT to the specific model.
@@ -1324,23 +1315,21 @@ static int asus_hotk_get_info(void)
                if (asus_info &&
                    strncmp(asus_info->oem_table_id, "ODEM", 4) == 0) {
                        hotk->model = P30;
-                       printk(KERN_NOTICE
-                              "  Samsung P30 detected, supported\n");
+                       pr_notice("  Samsung P30 detected, supported\n");
                        hotk->methods = &model_conf[hotk->model];
                        kfree(model);
                        return 0;
                } else {
                        hotk->model = M2E;
-                       printk(KERN_NOTICE "  unsupported model %s, trying "
-                              "default values\n", string);
-                       printk(KERN_NOTICE
-                              "  send /proc/acpi/dsdt to the developers\n");
+                       pr_notice("  unsupported model %s, trying default values\n",
+                                 string);
+                       pr_notice("  send /proc/acpi/dsdt to the developers\n");
                        kfree(model);
                        return -ENODEV;
                }
        }
        hotk->methods = &model_conf[hotk->model];
-       printk(KERN_NOTICE "  %s model detected, supported\n", string);
+       pr_notice("  %s model detected, supported\n", string);
 
        /* Sort of per-model blacklist */
        if (strncmp(string, "L2B", 3) == 0)
@@ -1385,7 +1374,7 @@ static int asus_hotk_check(void)
        if (hotk->device->status.present) {
                result = asus_hotk_get_info();
        } else {
-               printk(KERN_ERR "  Hotkey device not present, aborting\n");
+               pr_err("  Hotkey device not present, aborting\n");
                return -EINVAL;
        }
 
@@ -1399,8 +1388,7 @@ static int asus_hotk_add(struct acpi_device *device)
        acpi_status status = AE_OK;
        int result;
 
-       printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n",
-              ASUS_ACPI_VERSION);
+       pr_notice("Asus Laptop ACPI Extras version %s\n", ASUS_ACPI_VERSION);
 
        hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
        if (!hotk)
@@ -1428,15 +1416,14 @@ static int asus_hotk_add(struct acpi_device *device)
                    acpi_evaluate_object(NULL, hotk->methods->brightness_down,
                                         NULL, NULL);
                if (ACPI_FAILURE(status))
-                       printk(KERN_WARNING "  Error changing brightness\n");
+                       pr_warn("  Error changing brightness\n");
                else {
                        status =
                            acpi_evaluate_object(NULL,
                                                 hotk->methods->brightness_up,
                                                 NULL, NULL);
                        if (ACPI_FAILURE(status))
-                               printk(KERN_WARNING "  Strange, error changing"
-                                      " brightness\n");
+                               pr_warn("  Strange, error changing brightness\n");
                }
        }
 
@@ -1488,7 +1475,7 @@ static int __init asus_acpi_init(void)
 
        asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir);
        if (!asus_proc_dir) {
-               printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n");
+               pr_err("Unable to create /proc entry\n");
                acpi_bus_unregister_driver(&asus_hotk_driver);
                return -ENODEV;
        }
@@ -1513,7 +1500,7 @@ static int __init asus_acpi_init(void)
                                                          &asus_backlight_data,
                                                          &props);
        if (IS_ERR(asus_backlight_device)) {
-               printk(KERN_ERR "Could not register asus backlight device\n");
+               pr_err("Could not register asus backlight device\n");
                asus_backlight_device = NULL;
                asus_acpi_exit();
                return -ENODEV;
index c16a27641cedc57888fcc88b160aabec098520fd..3f204fde1b029e6433df6ad7e4fc0e6d26ab363a 100644 (file)
@@ -68,6 +68,8 @@
  * only enabled on a JHL90 board until it is verified that they work on the
  * other boards too.  See the extra_features variable. */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -200,8 +202,8 @@ static bool extra_features;
  * watching the output of address 0x4F (do an ec_transaction writing 0x33
  * into 0x4F and read a few bytes from the output, like so:
  *     u8 writeData = 0x33;
- *     ec_transaction(0x4F, &writeData, 1, buffer, 32, 0);
- * That address is labelled "fan1 table information" in the service manual.
+ *     ec_transaction(0x4F, &writeData, 1, buffer, 32);
+ * That address is labeled "fan1 table information" in the service manual.
  * It should be clear which value in 'buffer' changes). This seems to be
  * related to fan speed. It isn't a proper 'realtime' fan speed value
  * though, because physically stopping or speeding up the fan doesn't
@@ -286,7 +288,7 @@ static int get_backlight_level(void)
 static void set_backlight_state(bool on)
 {
        u8 data = on ? BACKLIGHT_STATE_ON_DATA : BACKLIGHT_STATE_OFF_DATA;
-       ec_transaction(BACKLIGHT_STATE_ADDR, &data, 1, NULL, 0, 0);
+       ec_transaction(BACKLIGHT_STATE_ADDR, &data, 1, NULL, 0);
 }
 
 
@@ -294,24 +296,24 @@ static void set_backlight_state(bool on)
 static void pwm_enable_control(void)
 {
        unsigned char writeData = PWM_ENABLE_DATA;
-       ec_transaction(PWM_ENABLE_ADDR, &writeData, 1, NULL, 0, 0);
+       ec_transaction(PWM_ENABLE_ADDR, &writeData, 1, NULL, 0);
 }
 
 static void pwm_disable_control(void)
 {
        unsigned char writeData = PWM_DISABLE_DATA;
-       ec_transaction(PWM_DISABLE_ADDR, &writeData, 1, NULL, 0, 0);
+       ec_transaction(PWM_DISABLE_ADDR, &writeData, 1, NULL, 0);
 }
 
 static void set_pwm(int pwm)
 {
-       ec_transaction(PWM_ADDRESS, &pwm_lookup_table[pwm], 1, NULL, 0, 0);
+       ec_transaction(PWM_ADDRESS, &pwm_lookup_table[pwm], 1, NULL, 0);
 }
 
 static int get_fan_rpm(void)
 {
        u8 value, data = FAN_DATA;
-       ec_transaction(FAN_ADDRESS, &data, 1, &value, 1, 0);
+       ec_transaction(FAN_ADDRESS, &data, 1, &value, 1);
        return 100 * (int)value;
 }
 
@@ -760,16 +762,14 @@ static struct rfkill *bt_rfkill;
 
 static int dmi_check_cb(const struct dmi_system_id *id)
 {
-       printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s'\n",
-               id->ident);
+       pr_info("Identified laptop model '%s'\n", id->ident);
        extra_features = false;
        return 1;
 }
 
 static int dmi_check_cb_extra(const struct dmi_system_id *id)
 {
-       printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s', "
-               "enabling extra features\n",
+       pr_info("Identified laptop model '%s', enabling extra features\n",
                id->ident);
        extra_features = true;
        return 1;
@@ -956,14 +956,12 @@ static int __init compal_init(void)
        int ret;
 
        if (acpi_disabled) {
-               printk(KERN_ERR DRIVER_NAME": ACPI needs to be enabled for "
-                                               "this driver to work!\n");
+               pr_err("ACPI needs to be enabled for this driver to work!\n");
                return -ENODEV;
        }
 
        if (!force && !dmi_check_system(compal_dmi_table)) {
-               printk(KERN_ERR DRIVER_NAME": Motherboard not recognized (You "
-                               "could try the module's force-parameter)");
+               pr_err("Motherboard not recognized (You could try the module's force-parameter)\n");
                return -ENODEV;
        }
 
@@ -998,8 +996,7 @@ static int __init compal_init(void)
        if (ret)
                goto err_rfkill;
 
-       printk(KERN_INFO DRIVER_NAME": Driver "DRIVER_VERSION
-                                               " successfully loaded\n");
+       pr_info("Driver " DRIVER_VERSION " successfully loaded\n");
        return 0;
 
 err_rfkill:
@@ -1064,7 +1061,7 @@ static void __exit compal_cleanup(void)
        rfkill_destroy(wifi_rfkill);
        rfkill_destroy(bt_rfkill);
 
-       printk(KERN_INFO DRIVER_NAME": Driver unloaded\n");
+       pr_info("Driver unloaded\n");
 }
 
 static int __devexit compal_remove(struct platform_device *pdev)
@@ -1074,8 +1071,7 @@ static int __devexit compal_remove(struct platform_device *pdev)
        if (!extra_features)
                return 0;
 
-       printk(KERN_INFO DRIVER_NAME": Unloading: resetting fan control "
-                                                       "to motherboard\n");
+       pr_info("Unloading: resetting fan control to motherboard\n");
        pwm_disable_control();
 
        data = platform_get_drvdata(pdev);
index de301aa8e5c3799620ff5a06372b5e1942c2dab2..d3841de6a8cf199ec08b24bd85f50a0af0490d37 100644 (file)
@@ -11,6 +11,8 @@
  *  published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -434,8 +436,7 @@ static int __init dell_setup_rfkill(void)
        int ret;
 
        if (dmi_check_system(dell_blacklist)) {
-               printk(KERN_INFO "dell-laptop: Blacklisted hardware detected - "
-                               "not enabling rfkill\n");
+               pr_info("Blacklisted hardware detected - not enabling rfkill\n");
                return 0;
        }
 
@@ -606,7 +607,7 @@ static int __init dell_init(void)
        dmi_walk(find_tokens, NULL);
 
        if (!da_tokens)  {
-               printk(KERN_INFO "dell-laptop: Unable to find dmi tokens\n");
+               pr_info("Unable to find dmi tokens\n");
                return -ENODEV;
        }
 
@@ -636,14 +637,13 @@ static int __init dell_init(void)
        ret = dell_setup_rfkill();
 
        if (ret) {
-               printk(KERN_WARNING "dell-laptop: Unable to setup rfkill\n");
+               pr_warn("Unable to setup rfkill\n");
                goto fail_rfkill;
        }
 
        ret = i8042_install_filter(dell_laptop_i8042_filter);
        if (ret) {
-               printk(KERN_WARNING
-                      "dell-laptop: Unable to install key filter\n");
+               pr_warn("Unable to install key filter\n");
                goto fail_filter;
        }
 
index 0ed84573ae1fb625663ed00755a316669649be27..3f945457f71c218116e7f8eb9d4a7400fcdc8b62 100644 (file)
@@ -15,6 +15,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
@@ -138,7 +139,7 @@ static int __init dell_wmi_aio_init(void)
 
        guid = dell_wmi_aio_find();
        if (!guid) {
-               pr_warning("No known WMI GUID found\n");
+               pr_warn("No known WMI GUID found\n");
                return -ENXIO;
        }
 
index 77f1d55414c670b126f41cce7356dbbd14b1cd13..ce790827e199ab4d4d9784850023ac4321c7bcc2 100644 (file)
@@ -23,6 +23,8 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -141,7 +143,7 @@ static void dell_wmi_notify(u32 value, void *context)
 
        status = wmi_get_event_data(value, &response);
        if (status != AE_OK) {
-               printk(KERN_INFO "dell-wmi: bad event status 0x%x\n", status);
+               pr_info("bad event status 0x%x\n", status);
                return;
        }
 
@@ -153,8 +155,8 @@ static void dell_wmi_notify(u32 value, void *context)
                u16 *buffer_entry = (u16 *)obj->buffer.pointer;
 
                if (dell_new_hk_type && (buffer_entry[1] != 0x10)) {
-                       printk(KERN_INFO "dell-wmi: Received unknown WMI event"
-                                        " (0x%x)\n", buffer_entry[1]);
+                       pr_info("Received unknown WMI event (0x%x)\n",
+                               buffer_entry[1]);
                        kfree(obj);
                        return;
                }
@@ -167,8 +169,7 @@ static void dell_wmi_notify(u32 value, void *context)
                key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev,
                                                        reported_key);
                if (!key) {
-                       printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n",
-                               reported_key);
+                       pr_info("Unknown key %x pressed\n", reported_key);
                } else if ((key->keycode == KEY_BRIGHTNESSUP ||
                            key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video) {
                        /* Don't report brightness notifications that will also
@@ -275,7 +276,7 @@ static int __init dell_wmi_init(void)
        acpi_status status;
 
        if (!wmi_has_guid(DELL_EVENT_GUID)) {
-               printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n");
+               pr_warn("No known WMI GUID found\n");
                return -ENODEV;
        }
 
@@ -290,9 +291,7 @@ static int __init dell_wmi_init(void)
                                         dell_wmi_notify, NULL);
        if (ACPI_FAILURE(status)) {
                dell_wmi_input_destroy();
-               printk(KERN_ERR
-                       "dell-wmi: Unable to register notify handler - %d\n",
-                       status);
+               pr_err("Unable to register notify handler - %d\n", status);
                return -ENODEV;
        }
 
index 2c1abf63957f23d0353c209af843f8e8bcf3c50c..1c45d92e21638230728a1f2919b1cc776360c937 100644 (file)
@@ -228,7 +228,7 @@ static int set_acpi(struct eeepc_laptop *eeepc, int cm, int value)
                return -ENODEV;
 
        if (write_acpi_int(eeepc->handle, method, value))
-               pr_warning("Error writing %s\n", method);
+               pr_warn("Error writing %s\n", method);
        return 0;
 }
 
@@ -243,7 +243,7 @@ static int get_acpi(struct eeepc_laptop *eeepc, int cm)
                return -ENODEV;
 
        if (read_acpi_int(eeepc->handle, method, &value))
-               pr_warning("Error reading %s\n", method);
+               pr_warn("Error reading %s\n", method);
        return value;
 }
 
@@ -261,7 +261,7 @@ static int acpi_setter_handle(struct eeepc_laptop *eeepc, int cm,
        status = acpi_get_handle(eeepc->handle, (char *)method,
                                 handle);
        if (status != AE_OK) {
-               pr_warning("Error finding %s\n", method);
+               pr_warn("Error finding %s\n", method);
                return -ENODEV;
        }
        return 0;
@@ -417,7 +417,7 @@ static ssize_t store_cpufv_disabled(struct device *dev,
        switch (value) {
        case 0:
                if (eeepc->cpufv_disabled)
-                       pr_warning("cpufv enabled (not officially supported "
+                       pr_warn("cpufv enabled (not officially supported "
                                "on this model)\n");
                eeepc->cpufv_disabled = false;
                return rv;
@@ -609,7 +609,7 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
                bus = port->subordinate;
 
                if (!bus) {
-                       pr_warning("Unable to find PCI bus?\n");
+                       pr_warn("Unable to find PCI bus 1?\n");
                        goto out_unlock;
                }
 
@@ -621,12 +621,12 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
                absent = (l == 0xffffffff);
 
                if (blocked != absent) {
-                       pr_warning("BIOS says wireless lan is %s, "
-                                       "but the pci device is %s\n",
+                       pr_warn("BIOS says wireless lan is %s, "
+                               "but the pci device is %s\n",
                                blocked ? "blocked" : "unblocked",
                                absent ? "absent" : "present");
-                       pr_warning("skipped wireless hotplug as probably "
-                                       "inappropriate for this model\n");
+                       pr_warn("skipped wireless hotplug as probably "
+                               "inappropriate for this model\n");
                        goto out_unlock;
                }
 
@@ -691,7 +691,8 @@ static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc,
                                                     eeepc_rfkill_notify,
                                                     eeepc);
                if (ACPI_FAILURE(status))
-                       pr_warning("Failed to register notify on %s\n", node);
+                       pr_warn("Failed to register notify on %s\n", node);
+
                /*
                 * Refresh pci hotplug in case the rfkill state was
                 * changed during setup.
index 649dcadd8ea372973cd45db1b5b8274847baff36..4aa867a9b88b8411f5231e9ac7a4298ffc9b8860 100644 (file)
@@ -84,7 +84,7 @@ static const struct key_entry eeepc_wmi_keymap[] = {
 static acpi_status eeepc_wmi_parse_device(acpi_handle handle, u32 level,
                                                 void *context, void **retval)
 {
-       pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID);
+       pr_warn("Found legacy ATKD device (%s)\n", EEEPC_ACPI_HID);
        *(bool *)context = true;
        return AE_CTRL_TERMINATE;
 }
@@ -105,12 +105,12 @@ static int eeepc_wmi_check_atkd(void)
 static int eeepc_wmi_probe(struct platform_device *pdev)
 {
        if (eeepc_wmi_check_atkd()) {
-               pr_warning("WMI device present, but legacy ATKD device is also "
-                          "present and enabled.");
-               pr_warning("You probably booted with acpi_osi=\"Linux\" or "
-                          "acpi_osi=\"!Windows 2009\"");
-               pr_warning("Can't load eeepc-wmi, use default acpi_osi "
-                          "(preferred) or eeepc-laptop");
+               pr_warn("WMI device present, but legacy ATKD device is also "
+                       "present and enabled\n");
+               pr_warn("You probably booted with acpi_osi=\"Linux\" or "
+                       "acpi_osi=\"!Windows 2009\"\n");
+               pr_warn("Can't load eeepc-wmi, use default acpi_osi "
+                       "(preferred) or eeepc-laptop\n");
                return -EBUSY;
        }
        return 0;
index 493054c2dbe15ec114922ce6446ad5f75b21beaa..6b26666b37f21d63665d20724fdba709f5523973 100644 (file)
@@ -56,6 +56,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -585,8 +587,7 @@ static struct platform_driver fujitsupf_driver = {
 static void dmi_check_cb_common(const struct dmi_system_id *id)
 {
        acpi_handle handle;
-       printk(KERN_INFO "fujitsu-laptop: Identified laptop model '%s'.\n",
-              id->ident);
+       pr_info("Identified laptop model '%s'\n", id->ident);
        if (use_alt_lcd_levels == -1) {
                if (ACPI_SUCCESS(acpi_get_handle(NULL,
                                "\\_SB.PCI0.LPCB.FJEX.SBL2", &handle)))
@@ -691,11 +692,11 @@ static int acpi_fujitsu_add(struct acpi_device *device)
 
        result = acpi_bus_update_power(fujitsu->acpi_handle, &state);
        if (result) {
-               printk(KERN_ERR "Error reading power state\n");
+               pr_err("Error reading power state\n");
                goto err_unregister_input_dev;
        }
 
-       printk(KERN_INFO "ACPI: %s [%s] (%s)\n",
+       pr_info("ACPI: %s [%s] (%s)\n",
               acpi_device_name(device), acpi_device_bid(device),
               !device->power.state ? "on" : "off");
 
@@ -707,7 +708,7 @@ static int acpi_fujitsu_add(struct acpi_device *device)
                if (ACPI_FAILURE
                    (acpi_evaluate_object
                     (device->handle, METHOD_NAME__INI, NULL, NULL)))
-                       printk(KERN_ERR "_INI Method failed\n");
+                       pr_err("_INI Method failed\n");
        }
 
        /* do config (detect defaults) */
@@ -827,7 +828,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
        error = kfifo_alloc(&fujitsu_hotkey->fifo, RINGBUFFERSIZE * sizeof(int),
                        GFP_KERNEL);
        if (error) {
-               printk(KERN_ERR "kfifo_alloc failed\n");
+               pr_err("kfifo_alloc failed\n");
                goto err_stop;
        }
 
@@ -859,13 +860,13 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
 
        result = acpi_bus_update_power(fujitsu_hotkey->acpi_handle, &state);
        if (result) {
-               printk(KERN_ERR "Error reading power state\n");
+               pr_err("Error reading power state\n");
                goto err_unregister_input_dev;
        }
 
-       printk(KERN_INFO "ACPI: %s [%s] (%s)\n",
-              acpi_device_name(device), acpi_device_bid(device),
-              !device->power.state ? "on" : "off");
+       pr_info("ACPI: %s [%s] (%s)\n",
+               acpi_device_name(device), acpi_device_bid(device),
+               !device->power.state ? "on" : "off");
 
        fujitsu_hotkey->dev = device;
 
@@ -875,7 +876,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
                if (ACPI_FAILURE
                    (acpi_evaluate_object
                     (device->handle, METHOD_NAME__INI, NULL, NULL)))
-                       printk(KERN_ERR "_INI Method failed\n");
+                       pr_err("_INI Method failed\n");
        }
 
        i = 0;
@@ -897,8 +898,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
                        call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
 
        /* Suspect this is a keymap of the application panel, print it */
-       printk(KERN_INFO "fujitsu-laptop: BTNI: [0x%x]\n",
-               call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0));
+       pr_info("BTNI: [0x%x]\n", call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0));
 
 #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
        if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
@@ -907,8 +907,8 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
                if (result == 0) {
                        fujitsu_hotkey->logolamp_registered = 1;
                } else {
-                       printk(KERN_ERR "fujitsu-laptop: Could not register "
-                       "LED handler for logo lamp, error %i\n", result);
+                       pr_err("Could not register LED handler for logo lamp, error %i\n",
+                              result);
                }
        }
 
@@ -919,8 +919,8 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
                if (result == 0) {
                        fujitsu_hotkey->kblamps_registered = 1;
                } else {
-                       printk(KERN_ERR "fujitsu-laptop: Could not register "
-                       "LED handler for keyboard lamps, error %i\n", result);
+                       pr_err("Could not register LED handler for keyboard lamps, error %i\n",
+                              result);
                }
        }
 #endif
@@ -1169,8 +1169,7 @@ static int __init fujitsu_init(void)
                        fujitsu->bl_device->props.power = 0;
        }
 
-       printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION
-              " successfully loaded.\n");
+       pr_info("driver " FUJITSU_DRIVER_VERSION " successfully loaded\n");
 
        return 0;
 
@@ -1216,7 +1215,7 @@ static void __exit fujitsu_cleanup(void)
 
        kfree(fujitsu);
 
-       printk(KERN_INFO "fujitsu-laptop: driver unloaded.\n");
+       pr_info("driver unloaded\n");
 }
 
 module_init(fujitsu_init);
index 067bf36d32f31087f7e59ce12851a156b7196773..5a34973dc16486aeb701cd5dd0e0cc59372a0eb5 100644 (file)
@@ -26,6 +26,8 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/input-polldev.h>
@@ -238,7 +240,7 @@ static int hdaps_device_init(void)
                     __check_latch(0x1611, 0x01))
                goto out;
 
-       printk(KERN_DEBUG "hdaps: initial latch check good (0x%02x).\n",
+       printk(KERN_DEBUG "hdaps: initial latch check good (0x%02x)\n",
               __get_latch(0x1611));
 
        outb(0x17, 0x1610);
@@ -299,7 +301,7 @@ static int hdaps_probe(struct platform_device *dev)
        if (ret)
                return ret;
 
-       printk(KERN_INFO "hdaps: device successfully initialized.\n");
+       pr_info("device successfully initialized\n");
        return 0;
 }
 
@@ -480,7 +482,7 @@ static struct attribute_group hdaps_attribute_group = {
 /* hdaps_dmi_match - found a match.  return one, short-circuiting the hunt. */
 static int __init hdaps_dmi_match(const struct dmi_system_id *id)
 {
-       printk(KERN_INFO "hdaps: %s detected.\n", id->ident);
+       pr_info("%s detected\n", id->ident);
        return 1;
 }
 
@@ -488,8 +490,7 @@ static int __init hdaps_dmi_match(const struct dmi_system_id *id)
 static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id)
 {
        hdaps_invert = (unsigned long)id->driver_data;
-       printk(KERN_INFO "hdaps: inverting axis (%u) readings.\n",
-              hdaps_invert);
+       pr_info("inverting axis (%u) readings\n", hdaps_invert);
        return hdaps_dmi_match(id);
 }
 
@@ -543,7 +544,7 @@ static int __init hdaps_init(void)
        int ret;
 
        if (!dmi_check_system(hdaps_whitelist)) {
-               printk(KERN_WARNING "hdaps: supported laptop not found!\n");
+               pr_warn("supported laptop not found!\n");
                ret = -ENODEV;
                goto out;
        }
@@ -595,7 +596,7 @@ static int __init hdaps_init(void)
        if (ret)
                goto out_idev;
 
-       printk(KERN_INFO "hdaps: driver successfully loaded.\n");
+       pr_info("driver successfully loaded\n");
        return 0;
 
 out_idev:
@@ -609,7 +610,7 @@ out_driver:
 out_region:
        release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS);
 out:
-       printk(KERN_WARNING "hdaps: driver init failed (ret=%d)!\n", ret);
+       pr_warn("driver init failed (ret=%d)!\n", ret);
        return ret;
 }
 
@@ -622,7 +623,7 @@ static void __exit hdaps_exit(void)
        platform_driver_unregister(&hdaps_driver);
        release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS);
 
-       printk(KERN_INFO "hdaps: driver unloaded.\n");
+       pr_info("driver unloaded\n");
 }
 
 module_init(hdaps_init);
index 1bc4a7539ba93f9b9f9cbdd74244b90a67302435..f94017bcdd6e9c8b10d80c70f7fd56ed27788d83 100644 (file)
@@ -24,6 +24,8 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -54,9 +56,6 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
 #define HPWMI_HOTKEY_QUERY 0xc
 #define HPWMI_WIRELESS2_QUERY 0x1b
 
-#define PREFIX "HP WMI: "
-#define UNIMP "Unimplemented "
-
 enum hp_wmi_radio {
        HPWMI_WIFI = 0,
        HPWMI_BLUETOOTH = 1,
@@ -228,9 +227,8 @@ static int hp_wmi_perform_query(int query, int write, void *buffer,
 
        if (bios_return->return_code) {
                if (bios_return->return_code != HPWMI_RET_UNKNOWN_CMDTYPE)
-                       printk(KERN_WARNING PREFIX "query 0x%x returned "
-                                                  "error 0x%x\n",
-                              query, bios_return->return_code);
+                       pr_warn("query 0x%x returned error 0x%x\n",
+                               query, bios_return->return_code);
                kfree(obj);
                return bios_return->return_code;
        }
@@ -384,8 +382,7 @@ static int hp_wmi_rfkill2_refresh(void)
 
                if (num >= state.count ||
                    devstate->rfkill_id != rfkill2[i].id) {
-                       printk(KERN_WARNING PREFIX "power configuration of "
-                              "the wireless devices unexpectedly changed\n");
+                       pr_warn("power configuration of the wireless devices unexpectedly changed\n");
                        continue;
                }
 
@@ -471,7 +468,7 @@ static void hp_wmi_notify(u32 value, void *context)
 
        status = wmi_get_event_data(value, &response);
        if (status != AE_OK) {
-               printk(KERN_INFO PREFIX "bad event status 0x%x\n", status);
+               pr_info("bad event status 0x%x\n", status);
                return;
        }
 
@@ -480,8 +477,7 @@ static void hp_wmi_notify(u32 value, void *context)
        if (!obj)
                return;
        if (obj->type != ACPI_TYPE_BUFFER) {
-               printk(KERN_INFO "hp-wmi: Unknown response received %d\n",
-                      obj->type);
+               pr_info("Unknown response received %d\n", obj->type);
                kfree(obj);
                return;
        }
@@ -498,8 +494,7 @@ static void hp_wmi_notify(u32 value, void *context)
                event_id = *location;
                event_data = *(location + 2);
        } else {
-               printk(KERN_INFO "hp-wmi: Unknown buffer length %d\n",
-                      obj->buffer.length);
+               pr_info("Unknown buffer length %d\n", obj->buffer.length);
                kfree(obj);
                return;
        }
@@ -527,8 +522,7 @@ static void hp_wmi_notify(u32 value, void *context)
 
                if (!sparse_keymap_report_event(hp_wmi_input_dev,
                                                key_code, 1, true))
-                       printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n",
-                              key_code);
+                       pr_info("Unknown key code - 0x%x\n", key_code);
                break;
        case HPWMI_WIRELESS:
                if (rfkill2_count) {
@@ -550,14 +544,12 @@ static void hp_wmi_notify(u32 value, void *context)
                                          hp_wmi_get_hw_state(HPWMI_WWAN));
                break;
        case HPWMI_CPU_BATTERY_THROTTLE:
-               printk(KERN_INFO PREFIX UNIMP "CPU throttle because of 3 Cell"
-                      " battery event detected\n");
+               pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n");
                break;
        case HPWMI_LOCK_SWITCH:
                break;
        default:
-               printk(KERN_INFO PREFIX "Unknown event_id - %d - 0x%x\n",
-                      event_id, event_data);
+               pr_info("Unknown event_id - %d - 0x%x\n", event_id, event_data);
                break;
        }
 }
@@ -705,7 +697,7 @@ static int __devinit hp_wmi_rfkill2_setup(struct platform_device *device)
                return err;
 
        if (state.count > HPWMI_MAX_RFKILL2_DEVICES) {
-               printk(KERN_WARNING PREFIX "unable to parse 0x1b query output\n");
+               pr_warn("unable to parse 0x1b query output\n");
                return -EINVAL;
        }
 
@@ -727,14 +719,14 @@ static int __devinit hp_wmi_rfkill2_setup(struct platform_device *device)
                        name = "hp-wwan";
                        break;
                default:
-                       printk(KERN_WARNING PREFIX "unknown device type 0x%x\n",
-                                state.device[i].radio_type);
+                       pr_warn("unknown device type 0x%x\n",
+                               state.device[i].radio_type);
                        continue;
                }
 
                if (!state.device[i].vendor_id) {
-                       printk(KERN_WARNING PREFIX "zero device %d while %d "
-                              "reported\n", i, state.count);
+                       pr_warn("zero device %d while %d reported\n",
+                               i, state.count);
                        continue;
                }
 
@@ -755,8 +747,7 @@ static int __devinit hp_wmi_rfkill2_setup(struct platform_device *device)
                                    IS_HWBLOCKED(state.device[i].power));
 
                if (!(state.device[i].power & HPWMI_POWER_BIOS))
-                       printk(KERN_INFO PREFIX "device %s blocked by BIOS\n",
-                              name);
+                       pr_info("device %s blocked by BIOS\n", name);
 
                err = rfkill_register(rfkill);
                if (err) {
index 94a114aa8e286fd5fc91f97d8c7b416204c19ea2..811d436cd677a0c1bab06cc7caa1e3d7ce317d67 100644 (file)
@@ -22,6 +22,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/module.h>
@@ -69,9 +71,10 @@ struct ibm_rtl_table {
 #define RTL_SIGNATURE 0x0000005f4c54525fULL
 #define RTL_MASK      0x000000ffffffffffULL
 
-#define RTL_DEBUG(A, ...) do { \
-       if (debug) \
-               pr_info("ibm-rtl: " A, ##__VA_ARGS__ ); \
+#define RTL_DEBUG(fmt, ...)                            \
+do {                                                   \
+       if (debug)                                      \
+               pr_info(fmt, ##__VA_ARGS__);            \
 } while (0)
 
 static DEFINE_MUTEX(rtl_lock);
@@ -81,6 +84,19 @@ static void __iomem *rtl_cmd_addr;
 static u8 rtl_cmd_type;
 static u8 rtl_cmd_width;
 
+#ifndef readq
+static inline __u64 readq(const volatile void __iomem *addr)
+{
+       const volatile u32 __iomem *p = addr;
+       u32 low, high;
+
+       low = readl(p);
+       high = readl(p + 1);
+
+       return low + ((u64)high << 32);
+}
+#endif
+
 static void __iomem *rtl_port_map(phys_addr_t addr, unsigned long len)
 {
        if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
@@ -101,7 +117,7 @@ static int ibm_rtl_write(u8 value)
        int ret = 0, count = 0;
        static u32 cmd_port_val;
 
-       RTL_DEBUG("%s(%d)\n", __FUNCTION__, value);
+       RTL_DEBUG("%s(%d)\n", __func__, value);
 
        value = value == 1 ? RTL_CMD_ENTER_PRTM : RTL_CMD_EXIT_PRTM;
 
@@ -131,8 +147,8 @@ static int ibm_rtl_write(u8 value)
                while (ioread8(&rtl_table->command)) {
                        msleep(10);
                        if (count++ > 500) {
-                               pr_err("ibm-rtl: Hardware not responding to "
-                                       "mode switch request\n");
+                               pr_err("Hardware not responding to "
+                                      "mode switch request\n");
                                ret = -EIO;
                                break;
                        }
@@ -237,7 +253,7 @@ static int __init ibm_rtl_init(void) {
        int ret = -ENODEV, i;
 
        if (force)
-               pr_warning("ibm-rtl: module loaded by force\n");
+               pr_warn("module loaded by force\n");
        /* first ensure that we are running on IBM HW */
        else if (efi_enabled || !dmi_check_system(ibm_rtl_dmi_table))
                return -ENODEV;
@@ -275,19 +291,19 @@ static int __init ibm_rtl_init(void) {
                if ((readq(&tmp->signature) & RTL_MASK) == RTL_SIGNATURE) {
                        phys_addr_t addr;
                        unsigned int plen;
-                       RTL_DEBUG("found RTL_SIGNATURE at %#llx\n", (u64)tmp);
+                       RTL_DEBUG("found RTL_SIGNATURE at %p\n", tmp);
                        rtl_table = tmp;
                        /* The address, value, width and offset are platform
                         * dependent and found in the ibm_rtl_table */
                        rtl_cmd_width = ioread8(&rtl_table->cmd_granularity);
                        rtl_cmd_type = ioread8(&rtl_table->cmd_address_type);
                        RTL_DEBUG("rtl_cmd_width = %u, rtl_cmd_type = %u\n",
-                             rtl_cmd_width, rtl_cmd_type);
+                                 rtl_cmd_width, rtl_cmd_type);
                        addr = ioread32(&rtl_table->cmd_port_address);
                        RTL_DEBUG("addr = %#llx\n", (unsigned long long)addr);
                        plen = rtl_cmd_width/sizeof(char);
                        rtl_cmd_addr = rtl_port_map(addr, plen);
-                       RTL_DEBUG("rtl_cmd_addr = %#llx\n", (u64)rtl_cmd_addr);
+                       RTL_DEBUG("rtl_cmd_addr = %p\n", rtl_cmd_addr);
                        if (!rtl_cmd_addr) {
                                ret = -ENOMEM;
                                break;
index 21b101899baeeb76e718c80c089caa2c8553c848..bfdda33feb26547dea8a5187543bb4b58de38f01 100644 (file)
@@ -20,6 +20,8 @@
  *  02110-1301, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
index 85c8ad43c0c5821f1e38ca2572ff02799324f014..5ffe7c3981482f7076ea95172cd0e960a04e465f 100644 (file)
@@ -344,6 +344,19 @@ struct ips_driver {
 static bool
 ips_gpu_turbo_enabled(struct ips_driver *ips);
 
+#ifndef readq
+static inline __u64 readq(const volatile void __iomem *addr)
+{
+       const volatile u32 __iomem *p = addr;
+       u32 low, high;
+
+       low = readl(p);
+       high = readl(p + 1);
+
+       return low + ((u64)high << 32);
+}
+#endif
+
 /**
  * ips_cpu_busy - is CPU busy?
  * @ips: IPS driver struct
index eacd5da7dd2434b8475b6e4cc89d9ee6d6145b20..809adea4965f96a8fca6f703fd94b40523d33072 100644 (file)
@@ -27,6 +27,8 @@
  *  to get/set bandwidth.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -135,8 +137,7 @@ static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
            acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list,
                                  &temp);
 
-       printk(KERN_INFO
-              "Bandwidth value was %ld: status is %d\n", state, status);
+       pr_info("Bandwidth value was %ld: status is %d\n", state, status);
        if (ACPI_FAILURE(status))
                return -EFAULT;
 
index 213e79ba68d517299ede2cb5702201f1da6476f6..f1ae5078b7ecfef330909061dc3e7c1f66c4183a 100644 (file)
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/input.h>
+
 #include <asm/intel_scu_ipc.h>
 
 #define DRIVER_NAME "msic_power_btn"
 
-#define MSIC_IRQ_STAT  0x02
-  #define MSIC_IRQ_PB  (1 << 0)
-#define MSIC_PB_CONFIG 0x3e
 #define MSIC_PB_STATUS 0x3f
-  #define MSIC_PB_LEVEL (1 << 3) /* 1 - release, 0 - press */
-
-struct mfld_pb_priv {
-       struct input_dev *input;
-       unsigned int irq;
-};
+#define MSIC_PB_LEVEL  (1 << 3) /* 1 - release, 0 - press */
 
 static irqreturn_t mfld_pb_isr(int irq, void *dev_id)
 {
-       struct mfld_pb_priv *priv = dev_id;
+       struct input_dev *input = dev_id;
        int ret;
        u8 pbstat;
 
        ret = intel_scu_ipc_ioread8(MSIC_PB_STATUS, &pbstat);
-       if (ret < 0)
-               return IRQ_HANDLED;
-
-       input_event(priv->input, EV_KEY, KEY_POWER, !(pbstat & MSIC_PB_LEVEL));
-       input_sync(priv->input);
+       if (ret < 0) {
+               dev_err(input->dev.parent, "Read error %d while reading"
+                              " MSIC_PB_STATUS\n", ret);
+       } else {
+               input_event(input, EV_KEY, KEY_POWER,
+                              !(pbstat & MSIC_PB_LEVEL));
+               input_sync(input);
+       }
 
        return IRQ_HANDLED;
 }
 
 static int __devinit mfld_pb_probe(struct platform_device *pdev)
 {
-       struct mfld_pb_priv *priv;
        struct input_dev *input;
-       int irq;
+       int irq = platform_get_irq(pdev, 0);
        int error;
 
-       irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return -EINVAL;
 
-       priv = kzalloc(sizeof(struct mfld_pb_priv), GFP_KERNEL);
        input = input_allocate_device();
-       if (!priv || !input) {
-               error = -ENOMEM;
-               goto err_free_mem;
+       if (!input) {
+               dev_err(&pdev->dev, "Input device allocation error\n");
+               return -ENOMEM;
        }
 
-       priv->input = input;
-       priv->irq = irq;
-
        input->name = pdev->name;
        input->phys = "power-button/input0";
        input->id.bustype = BUS_HOST;
@@ -82,42 +72,40 @@ static int __devinit mfld_pb_probe(struct platform_device *pdev)
 
        input_set_capability(input, EV_KEY, KEY_POWER);
 
-       error = request_threaded_irq(priv->irq, NULL, mfld_pb_isr,
-                                    0, DRIVER_NAME, priv);
+       error = request_threaded_irq(irq, NULL, mfld_pb_isr, 0,
+                       DRIVER_NAME, input);
        if (error) {
-               dev_err(&pdev->dev,
-                       "unable to request irq %d for mfld power button\n",
-                       irq);
-               goto err_free_mem;
+               dev_err(&pdev->dev, "Unable to request irq %d for mfld power"
+                               "button\n", irq);
+               goto err_free_input;
        }
 
        error = input_register_device(input);
        if (error) {
-               dev_err(&pdev->dev,
-                       "unable to register input dev, error %d\n", error);
+               dev_err(&pdev->dev, "Unable to register input dev, error "
+                               "%d\n", error);
                goto err_free_irq;
        }
 
-       platform_set_drvdata(pdev, priv);
+       platform_set_drvdata(pdev, input);
        return 0;
 
 err_free_irq:
-       free_irq(priv->irq, priv);
-err_free_mem:
+       free_irq(irq, input);
+err_free_input:
        input_free_device(input);
-       kfree(priv);
        return error;
 }
 
 static int __devexit mfld_pb_remove(struct platform_device *pdev)
 {
-       struct mfld_pb_priv *priv = platform_get_drvdata(pdev);
-
-       free_irq(priv->irq, priv);
-       input_unregister_device(priv->input);
-       kfree(priv);
+       struct input_dev *input = platform_get_drvdata(pdev);
+       int irq = platform_get_irq(pdev, 0);
 
+       free_irq(irq, input);
+       input_unregister_device(input);
        platform_set_drvdata(pdev, NULL);
+
        return 0;
 }
 
index c2f4bd8013b520a549c418e7c72644030fa560f4..3a578323122b7b18750de7d31ecb570b878cef43 100644 (file)
 #include <asm/intel_scu_ipc.h>
 
 /* Number of thermal sensors */
-#define MSIC_THERMAL_SENSORS   4
+#define MSIC_THERMAL_SENSORS   4
 
 /* ADC1 - thermal registers */
-#define MSIC_THERM_ADC1CNTL1   0x1C0
-#define MSIC_ADC_ENBL          0x10
-#define MSIC_ADC_START         0x08
+#define MSIC_THERM_ADC1CNTL1   0x1C0
+#define MSIC_ADC_ENBL          0x10
+#define MSIC_ADC_START         0x08
 
-#define MSIC_THERM_ADC1CNTL3   0x1C2
-#define MSIC_ADCTHERM_ENBL     0x04
-#define MSIC_ADCRRDATA_ENBL    0x05
-#define MSIC_CHANL_MASK_VAL    0x0F
+#define MSIC_THERM_ADC1CNTL3   0x1C2
+#define MSIC_ADCTHERM_ENBL     0x04
+#define MSIC_ADCRRDATA_ENBL    0x05
+#define MSIC_CHANL_MASK_VAL    0x0F
 
-#define MSIC_STOPBIT_MASK      16
-#define MSIC_ADCTHERM_MASK     4
-#define ADC_CHANLS_MAX         15 /* Number of ADC channels */
-#define ADC_LOOP_MAX           (ADC_CHANLS_MAX - MSIC_THERMAL_SENSORS)
+#define MSIC_STOPBIT_MASK      16
+#define MSIC_ADCTHERM_MASK     4
+/* Number of ADC channels */
+#define ADC_CHANLS_MAX         15
+#define ADC_LOOP_MAX           (ADC_CHANLS_MAX - MSIC_THERMAL_SENSORS)
 
 /* ADC channel code values */
-#define SKIN_SENSOR0_CODE      0x08
-#define SKIN_SENSOR1_CODE      0x09
-#define SYS_SENSOR_CODE                0x0A
-#define MSIC_DIE_SENSOR_CODE   0x03
+#define SKIN_SENSOR0_CODE      0x08
+#define SKIN_SENSOR1_CODE      0x09
+#define SYS_SENSOR_CODE                0x0A
+#define MSIC_DIE_SENSOR_CODE   0x03
 
-#define SKIN_THERM_SENSOR0     0
-#define SKIN_THERM_SENSOR1     1
-#define SYS_THERM_SENSOR2      2
-#define MSIC_DIE_THERM_SENSOR3 3
+#define SKIN_THERM_SENSOR0     0
+#define SKIN_THERM_SENSOR1     1
+#define SYS_THERM_SENSOR2      2
+#define MSIC_DIE_THERM_SENSOR3 3
 
 /* ADC code range */
-#define ADC_MAX                        977
-#define ADC_MIN                        162
-#define ADC_VAL0C              887
-#define ADC_VAL20C             720
-#define ADC_VAL40C             508
-#define ADC_VAL60C             315
+#define ADC_MAX                        977
+#define ADC_MIN                        162
+#define ADC_VAL0C              887
+#define ADC_VAL20C             720
+#define ADC_VAL40C             508
+#define ADC_VAL60C             315
 
 /* ADC base addresses */
-#define ADC_CHNL_START_ADDR    0x1C5   /* increments by 1 */
-#define ADC_DATA_START_ADDR     0x1D4   /* increments by 2 */
+#define ADC_CHNL_START_ADDR    0x1C5   /* increments by 1 */
+#define ADC_DATA_START_ADDR    0x1D4   /* increments by 2 */
 
 /* MSIC die attributes */
-#define MSIC_DIE_ADC_MIN       488
-#define MSIC_DIE_ADC_MAX       1004
+#define MSIC_DIE_ADC_MIN       488
+#define MSIC_DIE_ADC_MAX       1004
 
 /* This holds the address of the first free ADC channel,
  * among the 15 channels
 static int channel_index;
 
 struct platform_info {
-       struct platform_device *pdev;
-       struct thermal_zone_device *tzd[MSIC_THERMAL_SENSORS];
+       struct platform_device *pdev;
+       struct thermal_zone_device *tzd[MSIC_THERMAL_SENSORS];
 };
 
 struct thermal_device_info {
-       unsigned int chnl_addr;
-       int direct;
-       /* This holds the current temperature in millidegree celsius */
-       long curr_temp;
+       unsigned int chnl_addr;
+       int direct;
+       /* This holds the current temperature in millidegree celsius */
+       long curr_temp;
 };
 
 /**
@@ -106,7 +107,7 @@ struct thermal_device_info {
  */
 static int to_msic_die_temp(uint16_t adc_val)
 {
-       return (368 * (adc_val) / 1000) - 220;
+       return (368 * (adc_val) / 1000) - 220;
 }
 
 /**
@@ -118,7 +119,7 @@ static int to_msic_die_temp(uint16_t adc_val)
  */
 static int is_valid_adc(uint16_t adc_val, uint16_t min, uint16_t max)
 {
-       return (adc_val >= min) && (adc_val <= max);
+       return (adc_val >= min) && (adc_val <= max);
 }
 
 /**
@@ -136,35 +137,35 @@ static int is_valid_adc(uint16_t adc_val, uint16_t min, uint16_t max)
  */
 static int adc_to_temp(int direct, uint16_t adc_val, unsigned long *tp)
 {
-       int temp;
-
-       /* Direct conversion for die temperature */
-       if (direct) {
-               if (is_valid_adc(adc_val, MSIC_DIE_ADC_MIN, MSIC_DIE_ADC_MAX)) {
-                       *tp = to_msic_die_temp(adc_val) * 1000;
-                       return 0;
-               }
-               return -ERANGE;
-       }
-
-       if (!is_valid_adc(adc_val, ADC_MIN, ADC_MAX))
-               return -ERANGE;
-
-       /* Linear approximation for skin temperature */
-       if (adc_val > ADC_VAL0C)
-               temp = 177 - (adc_val/5);
-       else if ((adc_val <= ADC_VAL0C) && (adc_val > ADC_VAL20C))
-               temp = 111 - (adc_val/8);
-       else if ((adc_val <= ADC_VAL20C) && (adc_val > ADC_VAL40C))
-               temp = 92 - (adc_val/10);
-       else if ((adc_val <= ADC_VAL40C) && (adc_val > ADC_VAL60C))
-               temp = 91 - (adc_val/10);
-       else
-               temp = 112 - (adc_val/6);
-
-       /* Convert temperature in celsius to milli degree celsius */
-       *tp = temp * 1000;
-       return 0;
+       int temp;
+
+       /* Direct conversion for die temperature */
+       if (direct) {
+               if (is_valid_adc(adc_val, MSIC_DIE_ADC_MIN, MSIC_DIE_ADC_MAX)) {
+                       *tp = to_msic_die_temp(adc_val) * 1000;
+                       return 0;
+               }
+               return -ERANGE;
+       }
+
+       if (!is_valid_adc(adc_val, ADC_MIN, ADC_MAX))
+               return -ERANGE;
+
+       /* Linear approximation for skin temperature */
+       if (adc_val > ADC_VAL0C)
+               temp = 177 - (adc_val/5);
+       else if ((adc_val <= ADC_VAL0C) && (adc_val > ADC_VAL20C))
+               temp = 111 - (adc_val/8);
+       else if ((adc_val <= ADC_VAL20C) && (adc_val > ADC_VAL40C))
+               temp = 92 - (adc_val/10);
+       else if ((adc_val <= ADC_VAL40C) && (adc_val > ADC_VAL60C))
+               temp = 91 - (adc_val/10);
+       else
+               temp = 112 - (adc_val/6);
+
+       /* Convert temperature in celsius to milli degree celsius */
+       *tp = temp * 1000;
+       return 0;
 }
 
 /**
@@ -178,47 +179,47 @@ static int adc_to_temp(int direct, uint16_t adc_val, unsigned long *tp)
  */
 static int mid_read_temp(struct thermal_zone_device *tzd, unsigned long *temp)
 {
-       struct thermal_device_info *td_info = tzd->devdata;
-       uint16_t adc_val, addr;
-       uint8_t data = 0;
-       int ret;
-       unsigned long curr_temp;
-
-
-       addr = td_info->chnl_addr;
-
-       /* Enable the msic for conversion before reading */
-       ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCRRDATA_ENBL);
-       if (ret)
-               return ret;
-
-       /* Re-toggle the RRDATARD bit (temporary workaround) */
-       ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCTHERM_ENBL);
-       if (ret)
-               return ret;
-
-       /* Read the higher bits of data */
-       ret = intel_scu_ipc_ioread8(addr, &data);
-       if (ret)
-               return ret;
-
-       /* Shift bits to accommodate the lower two data bits */
-       adc_val = (data << 2);
-       addr++;
-
-       ret = intel_scu_ipc_ioread8(addr, &data);/* Read lower bits */
-       if (ret)
-               return ret;
-
-       /* Adding lower two bits to the higher bits */
-       data &= 03;
-       adc_val += data;
-
-       /* Convert ADC value to temperature */
-       ret = adc_to_temp(td_info->direct, adc_val, &curr_temp);
-       if (ret == 0)
-               *temp = td_info->curr_temp = curr_temp;
-       return ret;
+       struct thermal_device_info *td_info = tzd->devdata;
+       uint16_t adc_val, addr;
+       uint8_t data = 0;
+       int ret;
+       unsigned long curr_temp;
+
+
+       addr = td_info->chnl_addr;
+
+       /* Enable the msic for conversion before reading */
+       ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCRRDATA_ENBL);
+       if (ret)
+               return ret;
+
+       /* Re-toggle the RRDATARD bit (temporary workaround) */
+       ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCTHERM_ENBL);
+       if (ret)
+               return ret;
+
+       /* Read the higher bits of data */
+       ret = intel_scu_ipc_ioread8(addr, &data);
+       if (ret)
+               return ret;
+
+       /* Shift bits to accommodate the lower two data bits */
+       adc_val = (data << 2);
+       addr++;
+
+       ret = intel_scu_ipc_ioread8(addr, &data);/* Read lower bits */
+       if (ret)
+               return ret;
+
+       /* Adding lower two bits to the higher bits */
+       data &= 03;
+       adc_val += data;
+
+       /* Convert ADC value to temperature */
+       ret = adc_to_temp(td_info->direct, adc_val, &curr_temp);
+       if (ret == 0)
+               *temp = td_info->curr_temp = curr_temp;
+       return ret;
 }
 
 /**
@@ -231,22 +232,21 @@ static int mid_read_temp(struct thermal_zone_device *tzd, unsigned long *temp)
  */
 static int configure_adc(int val)
 {
-       int ret;
-       uint8_t data;
-
-       ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data);
-       if (ret)
-               return ret;
-
-       if (val) {
-               /* Enable and start the ADC */
-               data |= (MSIC_ADC_ENBL | MSIC_ADC_START);
-       } else {
-               /* Just stop the ADC */
-               data &= (~MSIC_ADC_START);
-       }
-
-       return intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL1, data);
+       int ret;
+       uint8_t data;
+
+       ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data);
+       if (ret)
+               return ret;
+
+       if (val) {
+               /* Enable and start the ADC */
+               data |= (MSIC_ADC_ENBL | MSIC_ADC_START);
+       } else {
+               /* Just stop the ADC */
+               data &= (~MSIC_ADC_START);
+       }
+       return intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL1, data);
 }
 
 /**
@@ -259,30 +259,30 @@ static int configure_adc(int val)
  */
 static int set_up_therm_channel(u16 base_addr)
 {
-       int ret;
-
-       /* Enable all the sensor channels */
-       ret = intel_scu_ipc_iowrite8(base_addr, SKIN_SENSOR0_CODE);
-       if (ret)
-               return ret;
-
-       ret = intel_scu_ipc_iowrite8(base_addr + 1, SKIN_SENSOR1_CODE);
-       if (ret)
-               return ret;
-
-       ret = intel_scu_ipc_iowrite8(base_addr + 2, SYS_SENSOR_CODE);
-       if (ret)
-               return ret;
-
-       /* Since this is the last channel, set the stop bit
-          to 1 by ORing the DIE_SENSOR_CODE with 0x10 */
-       ret = intel_scu_ipc_iowrite8(base_addr + 3,
-                                       (MSIC_DIE_SENSOR_CODE | 0x10));
-       if (ret)
-               return ret;
-
-       /* Enable ADC and start it */
-       return configure_adc(1);
+       int ret;
+
+       /* Enable all the sensor channels */
+       ret = intel_scu_ipc_iowrite8(base_addr, SKIN_SENSOR0_CODE);
+       if (ret)
+               return ret;
+
+       ret = intel_scu_ipc_iowrite8(base_addr + 1, SKIN_SENSOR1_CODE);
+       if (ret)
+               return ret;
+
+       ret = intel_scu_ipc_iowrite8(base_addr + 2, SYS_SENSOR_CODE);
+       if (ret)
+               return ret;
+
+       /* Since this is the last channel, set the stop bit
+        * to 1 by ORing the DIE_SENSOR_CODE with 0x10 */
+       ret = intel_scu_ipc_iowrite8(base_addr + 3,
+                       (MSIC_DIE_SENSOR_CODE | 0x10));
+       if (ret)
+               return ret;
+
+       /* Enable ADC and start it */
+       return configure_adc(1);
 }
 
 /**
@@ -293,13 +293,13 @@ static int set_up_therm_channel(u16 base_addr)
  */
 static int reset_stopbit(uint16_t addr)
 {
-       int ret;
-       uint8_t data;
-       ret = intel_scu_ipc_ioread8(addr, &data);
-       if (ret)
-               return ret;
-       /* Set the stop bit to zero */
-       return intel_scu_ipc_iowrite8(addr, (data & 0xEF));
+       int ret;
+       uint8_t data;
+       ret = intel_scu_ipc_ioread8(addr, &data);
+       if (ret)
+               return ret;
+       /* Set the stop bit to zero */
+       return intel_scu_ipc_iowrite8(addr, (data & 0xEF));
 }
 
 /**
@@ -317,30 +317,30 @@ static int reset_stopbit(uint16_t addr)
  */
 static int find_free_channel(void)
 {
-       int ret;
-       int i;
-       uint8_t data;
-
-       /* check whether ADC is enabled */
-       ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data);
-       if (ret)
-               return ret;
-
-       if ((data & MSIC_ADC_ENBL) == 0)
-               return 0;
-
-       /* ADC is already enabled; Looking for an empty channel */
-       for (i = 0; i < ADC_CHANLS_MAX; i++) {
-               ret = intel_scu_ipc_ioread8(ADC_CHNL_START_ADDR + i, &data);
-               if (ret)
-                       return ret;
-
-               if (data & MSIC_STOPBIT_MASK) {
-                       ret = i;
-                       break;
-               }
-       }
-       return (ret > ADC_LOOP_MAX) ? (-EINVAL) : ret;
+       int ret;
+       int i;
+       uint8_t data;
+
+       /* check whether ADC is enabled */
+       ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data);
+       if (ret)
+               return ret;
+
+       if ((data & MSIC_ADC_ENBL) == 0)
+               return 0;
+
+       /* ADC is already enabled; Looking for an empty channel */
+       for (i = 0; i < ADC_CHANLS_MAX; i++) {
+               ret = intel_scu_ipc_ioread8(ADC_CHNL_START_ADDR + i, &data);
+               if (ret)
+                       return ret;
+
+               if (data & MSIC_STOPBIT_MASK) {
+                       ret = i;
+                       break;
+               }
+       }
+       return (ret > ADC_LOOP_MAX) ? (-EINVAL) : ret;
 }
 
 /**
@@ -351,48 +351,48 @@ static int find_free_channel(void)
  */
 static int mid_initialize_adc(struct device *dev)
 {
-       u8  data;
-       u16 base_addr;
-       int ret;
-
-       /*
-        * Ensure that adctherm is disabled before we
-        * initialize the ADC
-        */
-       ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL3, &data);
-       if (ret)
-               return ret;
-
-       if (data & MSIC_ADCTHERM_MASK)
-               dev_warn(dev, "ADCTHERM already set");
-
-       /* Index of the first channel in which the stop bit is set */
-       channel_index = find_free_channel();
-       if (channel_index < 0) {
-               dev_err(dev, "No free ADC channels");
-               return channel_index;
-       }
-
-       base_addr = ADC_CHNL_START_ADDR + channel_index;
-
-       if (!(channel_index == 0 || channel_index == ADC_LOOP_MAX)) {
-               /* Reset stop bit for channels other than 0 and 12 */
-               ret = reset_stopbit(base_addr);
-               if (ret)
-                       return ret;
-
-               /* Index of the first free channel */
-               base_addr++;
-               channel_index++;
-       }
-
-       ret = set_up_therm_channel(base_addr);
-       if (ret) {
-               dev_err(dev, "unable to enable ADC");
-               return ret;
-       }
-       dev_dbg(dev, "ADC initialization successful");
-       return ret;
+       u8  data;
+       u16 base_addr;
+       int ret;
+
+       /*
+        * Ensure that adctherm is disabled before we
+        * initialize the ADC
+        */
+       ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL3, &data);
+       if (ret)
+               return ret;
+
+       if (data & MSIC_ADCTHERM_MASK)
+               dev_warn(dev, "ADCTHERM already set");
+
+       /* Index of the first channel in which the stop bit is set */
+       channel_index = find_free_channel();
+       if (channel_index < 0) {
+               dev_err(dev, "No free ADC channels");
+               return channel_index;
+       }
+
+       base_addr = ADC_CHNL_START_ADDR + channel_index;
+
+       if (!(channel_index == 0 || channel_index == ADC_LOOP_MAX)) {
+               /* Reset stop bit for channels other than 0 and 12 */
+               ret = reset_stopbit(base_addr);
+               if (ret)
+                       return ret;
+
+               /* Index of the first free channel */
+               base_addr++;
+               channel_index++;
+       }
+
+       ret = set_up_therm_channel(base_addr);
+       if (ret) {
+               dev_err(dev, "unable to enable ADC");
+               return ret;
+       }
+       dev_dbg(dev, "ADC initialization successful");
+       return ret;
 }
 
 /**
@@ -403,18 +403,18 @@ static int mid_initialize_adc(struct device *dev)
  */
 static struct thermal_device_info *initialize_sensor(int index)
 {
-       struct thermal_device_info *td_info =
-               kzalloc(sizeof(struct thermal_device_info), GFP_KERNEL);
-
-       if (!td_info)
-               return NULL;
-
-       /* Set the base addr of the channel for this sensor */
-       td_info->chnl_addr = ADC_DATA_START_ADDR + 2 * (channel_index + index);
-       /* Sensor 3 is direct conversion */
-       if (index == 3)
-               td_info->direct = 1;
-       return td_info;
+       struct thermal_device_info *td_info =
+               kzalloc(sizeof(struct thermal_device_info), GFP_KERNEL);
+
+       if (!td_info)
+               return NULL;
+
+       /* Set the base addr of the channel for this sensor */
+       td_info->chnl_addr = ADC_DATA_START_ADDR + 2 * (channel_index + index);
+       /* Sensor 3 is direct conversion */
+       if (index == 3)
+               td_info->direct = 1;
+       return td_info;
 }
 
 /**
@@ -425,7 +425,7 @@ static struct thermal_device_info *initialize_sensor(int index)
  */
 static int mid_thermal_resume(struct platform_device *pdev)
 {
-       return mid_initialize_adc(&pdev->dev);
+       return mid_initialize_adc(&pdev->dev);
 }
 
 /**
@@ -437,12 +437,12 @@ static int mid_thermal_resume(struct platform_device *pdev)
  */
 static int mid_thermal_suspend(struct platform_device *pdev, pm_message_t mesg)
 {
-       /*
-        * This just stops the ADC and does not disable it.
-        * temporary workaround until we have a generic ADC driver.
-        * If 0 is passed, it disables the ADC.
-        */
-       return configure_adc(0);
+       /*
+        * This just stops the ADC and does not disable it.
+        * temporary workaround until we have a generic ADC driver.
+        * If 0 is passed, it disables the ADC.
+        */
+       return configure_adc(0);
 }
 
 /**
@@ -453,16 +453,15 @@ static int mid_thermal_suspend(struct platform_device *pdev, pm_message_t mesg)
  */
 static int read_curr_temp(struct thermal_zone_device *tzd, unsigned long *temp)
 {
-       WARN_ON(tzd == NULL);
-       return mid_read_temp(tzd, temp);
+       WARN_ON(tzd == NULL);
+       return mid_read_temp(tzd, temp);
 }
 
 /* Can't be const */
 static struct thermal_zone_device_ops tzd_ops = {
-       .get_temp = read_curr_temp,
+       .get_temp = read_curr_temp,
 };
 
-
 /**
  * mid_thermal_probe - mfld thermal initialize
  * @pdev: platform device structure
@@ -472,46 +471,45 @@ static struct thermal_zone_device_ops tzd_ops = {
  */
 static int mid_thermal_probe(struct platform_device *pdev)
 {
-       static char *name[MSIC_THERMAL_SENSORS] = {
-               "skin0", "skin1", "sys", "msicdie"
-       };
-
-       int ret;
-       int i;
-       struct platform_info *pinfo;
-
-       pinfo = kzalloc(sizeof(struct platform_info), GFP_KERNEL);
-       if (!pinfo)
-               return -ENOMEM;
-
-       /* Initializing the hardware */
-       ret = mid_initialize_adc(&pdev->dev);
-       if (ret) {
-               dev_err(&pdev->dev, "ADC init failed");
-               kfree(pinfo);
-               return ret;
-       }
-
-       /* Register each sensor with the generic thermal framework*/
-       for (i = 0; i < MSIC_THERMAL_SENSORS; i++) {
-               pinfo->tzd[i] = thermal_zone_device_register(name[i],
-                                       0, initialize_sensor(i),
-                                       &tzd_ops, 0, 0, 0, 0);
-               if (IS_ERR(pinfo->tzd[i]))
-                       goto reg_fail;
-       }
-
-       pinfo->pdev = pdev;
-       platform_set_drvdata(pdev, pinfo);
-       return 0;
+       static char *name[MSIC_THERMAL_SENSORS] = {
+               "skin0", "skin1", "sys", "msicdie"
+       };
+
+       int ret;
+       int i;
+       struct platform_info *pinfo;
+
+       pinfo = kzalloc(sizeof(struct platform_info), GFP_KERNEL);
+       if (!pinfo)
+               return -ENOMEM;
+
+       /* Initializing the hardware */
+       ret = mid_initialize_adc(&pdev->dev);
+       if (ret) {
+               dev_err(&pdev->dev, "ADC init failed");
+               kfree(pinfo);
+               return ret;
+       }
+
+       /* Register each sensor with the generic thermal framework*/
+       for (i = 0; i < MSIC_THERMAL_SENSORS; i++) {
+               pinfo->tzd[i] = thermal_zone_device_register(name[i],
+                               0, initialize_sensor(i), &tzd_ops, 0, 0, 0, 0);
+               if (IS_ERR(pinfo->tzd[i]))
+                       goto reg_fail;
+       }
+
+       pinfo->pdev = pdev;
+       platform_set_drvdata(pdev, pinfo);
+       return 0;
 
 reg_fail:
-       ret = PTR_ERR(pinfo->tzd[i]);
-       while (--i >= 0)
-               thermal_zone_device_unregister(pinfo->tzd[i]);
-       configure_adc(0);
-       kfree(pinfo);
-       return ret;
+       ret = PTR_ERR(pinfo->tzd[i]);
+       while (--i >= 0)
+               thermal_zone_device_unregister(pinfo->tzd[i]);
+       configure_adc(0);
+       kfree(pinfo);
+       return ret;
 }
 
 /**
@@ -523,49 +521,46 @@ reg_fail:
  */
 static int mid_thermal_remove(struct platform_device *pdev)
 {
-       int i;
-       struct platform_info *pinfo = platform_get_drvdata(pdev);
+       int i;
+       struct platform_info *pinfo = platform_get_drvdata(pdev);
 
-       for (i = 0; i < MSIC_THERMAL_SENSORS; i++)
-               thermal_zone_device_unregister(pinfo->tzd[i]);
+       for (i = 0; i < MSIC_THERMAL_SENSORS; i++)
+               thermal_zone_device_unregister(pinfo->tzd[i]);
 
-       platform_set_drvdata(pdev, NULL);
+       kfree(pinfo);
+       platform_set_drvdata(pdev, NULL);
 
-       /* Stop the ADC */
-       return configure_adc(0);
+       /* Stop the ADC */
+       return configure_adc(0);
 }
 
-/*********************************************************************
- *             Driver initialisation and finalization
- *********************************************************************/
-
 #define DRIVER_NAME "msic_sensor"
 
 static const struct platform_device_id therm_id_table[] = {
-       { DRIVER_NAME, 1 },
-       { }
+       { DRIVER_NAME, 1 },
+       { }
 };
 
 static struct platform_driver mid_thermal_driver = {
-       .driver = {
-               .name = DRIVER_NAME,
-               .owner = THIS_MODULE,
-       },
-       .probe = mid_thermal_probe,
-       .suspend = mid_thermal_suspend,
-       .resume = mid_thermal_resume,
-       .remove = __devexit_p(mid_thermal_remove),
-       .id_table = therm_id_table,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = mid_thermal_probe,
+       .suspend = mid_thermal_suspend,
+       .resume = mid_thermal_resume,
+       .remove = __devexit_p(mid_thermal_remove),
+       .id_table = therm_id_table,
 };
 
 static int __init mid_thermal_module_init(void)
 {
-       return platform_driver_register(&mid_thermal_driver);
+       return platform_driver_register(&mid_thermal_driver);
 }
 
 static void __exit mid_thermal_module_exit(void)
 {
-       platform_driver_unregister(&mid_thermal_driver);
+       platform_driver_unregister(&mid_thermal_driver);
 }
 
 module_init(mid_thermal_module_init);
diff --git a/drivers/platform/x86/intel_oaktrail.c b/drivers/platform/x86/intel_oaktrail.c
new file mode 100644 (file)
index 0000000..e936364
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * intel_oaktrail.c - Intel OakTrail Platform support.
+ *
+ * Copyright (C) 2010-2011 Intel Corporation
+ * Author: Yin Kangkai (kangkai.yin@intel.com)
+ *
+ * based on Compal driver, Copyright (C) 2008 Cezary Jackiewicz
+ * <cezary.jackiewicz (at) gmail.com>, based on MSI driver
+ * Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) de>
+ *
+ *  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.
+ *
+ * This driver does below things:
+ * 1. registers itself in the Linux backlight control in
+ *    /sys/class/backlight/intel_oaktrail/
+ *
+ * 2. registers in the rfkill subsystem here: /sys/class/rfkill/rfkillX/
+ *    for these components: wifi, bluetooth, wwan (3g), gps
+ *
+ * This driver might work on other products based on Oaktrail. If you
+ * want to try it you can pass force=1 as argument to the module which
+ * will force it to load even when the DMI data doesn't identify the
+ * product as compatible.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/fb.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/backlight.h>
+#include <linux/platform_device.h>
+#include <linux/dmi.h>
+#include <linux/rfkill.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+
+#define DRIVER_NAME    "intel_oaktrail"
+#define DRIVER_VERSION "0.4ac1"
+
+/*
+ * This is the devices status address in EC space, and the control bits
+ * definition:
+ *
+ * (1 << 0):   Camera enable/disable, RW.
+ * (1 << 1):   Bluetooth enable/disable, RW.
+ * (1 << 2):   GPS enable/disable, RW.
+ * (1 << 3):   WiFi enable/disable, RW.
+ * (1 << 4):   WWAN (3G) enable/disalbe, RW.
+ * (1 << 5):   Touchscreen enable/disable, Read Only.
+ */
+#define OT_EC_DEVICE_STATE_ADDRESS     0xD6
+
+#define OT_EC_CAMERA_MASK      (1 << 0)
+#define OT_EC_BT_MASK          (1 << 1)
+#define OT_EC_GPS_MASK         (1 << 2)
+#define OT_EC_WIFI_MASK                (1 << 3)
+#define OT_EC_WWAN_MASK                (1 << 4)
+#define OT_EC_TS_MASK          (1 << 5)
+
+/*
+ * This is the address in EC space and commands used to control LCD backlight:
+ *
+ * Two steps needed to change the LCD backlight:
+ *   1. write the backlight percentage into OT_EC_BL_BRIGHTNESS_ADDRESS;
+ *   2. write OT_EC_BL_CONTROL_ON_DATA into OT_EC_BL_CONTROL_ADDRESS.
+ *
+ * To read the LCD back light, just read out the value from
+ * OT_EC_BL_BRIGHTNESS_ADDRESS.
+ *
+ * LCD backlight brightness range: 0 - 100 (OT_EC_BL_BRIGHTNESS_MAX)
+ */
+#define OT_EC_BL_BRIGHTNESS_ADDRESS    0x44
+#define OT_EC_BL_BRIGHTNESS_MAX                100
+#define OT_EC_BL_CONTROL_ADDRESS       0x3A
+#define OT_EC_BL_CONTROL_ON_DATA       0x1A
+
+
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
+
+static struct platform_device *oaktrail_device;
+static struct backlight_device *oaktrail_bl_device;
+static struct rfkill *bt_rfkill;
+static struct rfkill *gps_rfkill;
+static struct rfkill *wifi_rfkill;
+static struct rfkill *wwan_rfkill;
+
+
+/* rfkill */
+static int oaktrail_rfkill_set(void *data, bool blocked)
+{
+       u8 value;
+       u8 result;
+       unsigned long radio = (unsigned long) data;
+
+       ec_read(OT_EC_DEVICE_STATE_ADDRESS, &result);
+
+       if (!blocked)
+               value = (u8) (result | radio);
+       else
+               value = (u8) (result & ~radio);
+
+       ec_write(OT_EC_DEVICE_STATE_ADDRESS, value);
+
+       return 0;
+}
+
+static const struct rfkill_ops oaktrail_rfkill_ops = {
+       .set_block = oaktrail_rfkill_set,
+};
+
+static struct rfkill *oaktrail_rfkill_new(char *name, enum rfkill_type type,
+                                         unsigned long mask)
+{
+       struct rfkill *rfkill_dev;
+       u8 value;
+       int err;
+
+       rfkill_dev = rfkill_alloc(name, &oaktrail_device->dev, type,
+                                 &oaktrail_rfkill_ops, (void *)mask);
+       if (!rfkill_dev)
+               return ERR_PTR(-ENOMEM);
+
+       ec_read(OT_EC_DEVICE_STATE_ADDRESS, &value);
+       rfkill_init_sw_state(rfkill_dev, (value & mask) != 1);
+
+       err = rfkill_register(rfkill_dev);
+       if (err) {
+               rfkill_destroy(rfkill_dev);
+               return ERR_PTR(err);
+       }
+
+       return rfkill_dev;
+}
+
+static inline void __oaktrail_rfkill_cleanup(struct rfkill *rf)
+{
+       if (rf) {
+               rfkill_unregister(rf);
+               rfkill_destroy(rf);
+       }
+}
+
+static void oaktrail_rfkill_cleanup(void)
+{
+       __oaktrail_rfkill_cleanup(wifi_rfkill);
+       __oaktrail_rfkill_cleanup(bt_rfkill);
+       __oaktrail_rfkill_cleanup(gps_rfkill);
+       __oaktrail_rfkill_cleanup(wwan_rfkill);
+}
+
+static int oaktrail_rfkill_init(void)
+{
+       int ret;
+
+       wifi_rfkill = oaktrail_rfkill_new("oaktrail-wifi",
+                                         RFKILL_TYPE_WLAN,
+                                         OT_EC_WIFI_MASK);
+       if (IS_ERR(wifi_rfkill)) {
+               ret = PTR_ERR(wifi_rfkill);
+               wifi_rfkill = NULL;
+               goto cleanup;
+       }
+
+       bt_rfkill = oaktrail_rfkill_new("oaktrail-bluetooth",
+                                       RFKILL_TYPE_BLUETOOTH,
+                                       OT_EC_BT_MASK);
+       if (IS_ERR(bt_rfkill)) {
+               ret = PTR_ERR(bt_rfkill);
+               bt_rfkill = NULL;
+               goto cleanup;
+       }
+
+       gps_rfkill = oaktrail_rfkill_new("oaktrail-gps",
+                                        RFKILL_TYPE_GPS,
+                                        OT_EC_GPS_MASK);
+       if (IS_ERR(gps_rfkill)) {
+               ret = PTR_ERR(gps_rfkill);
+               gps_rfkill = NULL;
+               goto cleanup;
+       }
+
+       wwan_rfkill = oaktrail_rfkill_new("oaktrail-wwan",
+                                         RFKILL_TYPE_WWAN,
+                                         OT_EC_WWAN_MASK);
+       if (IS_ERR(wwan_rfkill)) {
+               ret = PTR_ERR(wwan_rfkill);
+               wwan_rfkill = NULL;
+               goto cleanup;
+       }
+
+       return 0;
+
+cleanup:
+       oaktrail_rfkill_cleanup();
+       return ret;
+}
+
+
+/* backlight */
+static int get_backlight_brightness(struct backlight_device *b)
+{
+       u8 value;
+       ec_read(OT_EC_BL_BRIGHTNESS_ADDRESS, &value);
+
+       return value;
+}
+
+static int set_backlight_brightness(struct backlight_device *b)
+{
+       u8 percent = (u8) b->props.brightness;
+       if (percent < 0 || percent > OT_EC_BL_BRIGHTNESS_MAX)
+               return -EINVAL;
+
+       ec_write(OT_EC_BL_BRIGHTNESS_ADDRESS, percent);
+       ec_write(OT_EC_BL_CONTROL_ADDRESS, OT_EC_BL_CONTROL_ON_DATA);
+
+       return 0;
+}
+
+static const struct backlight_ops oaktrail_bl_ops = {
+       .get_brightness = get_backlight_brightness,
+       .update_status  = set_backlight_brightness,
+};
+
+static int oaktrail_backlight_init(void)
+{
+       struct backlight_device *bd;
+       struct backlight_properties props;
+
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = OT_EC_BL_BRIGHTNESS_MAX;
+       bd = backlight_device_register(DRIVER_NAME,
+                                      &oaktrail_device->dev, NULL,
+                                      &oaktrail_bl_ops,
+                                      &props);
+
+       if (IS_ERR(bd)) {
+               oaktrail_bl_device = NULL;
+               pr_warning("Unable to register backlight device\n");
+               return PTR_ERR(bd);
+       }
+
+       oaktrail_bl_device = bd;
+
+       bd->props.brightness = get_backlight_brightness(bd);
+       bd->props.power = FB_BLANK_UNBLANK;
+       backlight_update_status(bd);
+
+       return 0;
+}
+
+static void oaktrail_backlight_exit(void)
+{
+       if (oaktrail_bl_device)
+               backlight_device_unregister(oaktrail_bl_device);
+}
+
+static int __devinit oaktrail_probe(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int __devexit oaktrail_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static struct platform_driver oaktrail_driver = {
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe  = oaktrail_probe,
+       .remove = __devexit_p(oaktrail_remove)
+};
+
+static int dmi_check_cb(const struct dmi_system_id *id)
+{
+       pr_info("Identified model '%s'\n", id->ident);
+       return 0;
+}
+
+static struct dmi_system_id __initdata oaktrail_dmi_table[] = {
+       {
+               .ident = "OakTrail platform",
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "OakTrail platform"),
+               },
+               .callback = dmi_check_cb
+       },
+       { }
+};
+
+static int __init oaktrail_init(void)
+{
+       int ret;
+
+       if (acpi_disabled) {
+               pr_err("ACPI needs to be enabled for this driver to work!\n");
+               return -ENODEV;
+       }
+
+       if (!force && !dmi_check_system(oaktrail_dmi_table)) {
+               pr_err("Platform not recognized (You could try the module's force-parameter)");
+               return -ENODEV;
+       }
+
+       ret = platform_driver_register(&oaktrail_driver);
+       if (ret) {
+               pr_warning("Unable to register platform driver\n");
+               goto err_driver_reg;
+       }
+
+       oaktrail_device = platform_device_alloc(DRIVER_NAME, -1);
+       if (!oaktrail_device) {
+               pr_warning("Unable to allocate platform device\n");
+               ret = -ENOMEM;
+               goto err_device_alloc;
+       }
+
+       ret = platform_device_add(oaktrail_device);
+       if (ret) {
+               pr_warning("Unable to add platform device\n");
+               goto err_device_add;
+       }
+
+       if (!acpi_video_backlight_support()) {
+               ret = oaktrail_backlight_init();
+               if (ret)
+                       goto err_backlight;
+
+       } else
+               pr_info("Backlight controlled by ACPI video driver\n");
+
+       ret = oaktrail_rfkill_init();
+       if (ret) {
+               pr_warning("Setup rfkill failed\n");
+               goto err_rfkill;
+       }
+
+       pr_info("Driver "DRIVER_VERSION" successfully loaded\n");
+       return 0;
+
+err_rfkill:
+       oaktrail_backlight_exit();
+err_backlight:
+       platform_device_del(oaktrail_device);
+err_device_add:
+       platform_device_put(oaktrail_device);
+err_device_alloc:
+       platform_driver_unregister(&oaktrail_driver);
+err_driver_reg:
+
+       return ret;
+}
+
+static void __exit oaktrail_cleanup(void)
+{
+       oaktrail_backlight_exit();
+       oaktrail_rfkill_cleanup();
+       platform_device_unregister(oaktrail_device);
+       platform_driver_unregister(&oaktrail_driver);
+
+       pr_info("Driver unloaded\n");
+}
+
+module_init(oaktrail_init);
+module_exit(oaktrail_cleanup);
+
+MODULE_AUTHOR("Yin Kangkai (kangkai.yin@intel.com)");
+MODULE_DESCRIPTION("Intel Oaktrail Platform ACPI Extras");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("dmi:*:svnIntelCorporation:pnOakTrailplatform:*");
index 464bb3fc4d88b1c7d8fc9583b48fee3fec610a4f..1686c1e07d5d250c03d27fe24077f0c3f43b00d7 100644 (file)
@@ -19,6 +19,8 @@
  * Moorestown platform PMIC chip
  */
 
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
@@ -90,8 +92,7 @@ static void pmic_program_irqtype(int gpio, int type)
 static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
        if (offset > 8) {
-               printk(KERN_ERR
-                       "%s: only pin 0-7 support input\n", __func__);
+               pr_err("only pin 0-7 support input\n");
                return -1;/* we only have 8 GPIO can use as input */
        }
        return intel_scu_ipc_update_register(GPIO0 + offset,
@@ -116,8 +117,7 @@ static int pmic_gpio_direction_output(struct gpio_chip *chip,
                                value ? 1 << (offset - 16) : 0,
                                1 << (offset - 16));
        else {
-               printk(KERN_ERR
-                       "%s: invalid PMIC GPIO pin %d!\n", __func__, offset);
+               pr_err("invalid PMIC GPIO pin %d!\n", offset);
                WARN_ON(1);
        }
 
@@ -260,7 +260,7 @@ static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev)
        /* setting up SRAM mapping for GPIOINT register */
        pg->gpiointr = ioremap_nocache(pdata->gpiointr, 8);
        if (!pg->gpiointr) {
-               printk(KERN_ERR "%s: Can not map GPIOINT.\n", __func__);
+               pr_err("Can not map GPIOINT\n");
                retval = -EINVAL;
                goto err2;
        }
@@ -281,13 +281,13 @@ static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev)
        pg->chip.dev = dev;
        retval = gpiochip_add(&pg->chip);
        if (retval) {
-               printk(KERN_ERR "%s: Can not add pmic gpio chip.\n", __func__);
+               pr_err("Can not add pmic gpio chip\n");
                goto err;
        }
 
        retval = request_irq(pg->irq, pmic_irq_handler, 0, "pmic", pg);
        if (retval) {
-               printk(KERN_WARNING "pmic: Interrupt request failed\n");
+               pr_warn("Interrupt request failed\n");
                goto err;
        }
 
index 23fb2afda00b0c600dd5ca515a85023d7f0b4792..3ff629df9f01b0b1a0a6ff2be71115d922c71b88 100644 (file)
@@ -135,7 +135,7 @@ static int set_lcd_level(int level)
        buf[1] = (u8) (level*31);
 
        return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf),
-                             NULL, 0, 1);
+                             NULL, 0);
 }
 
 static int get_lcd_level(void)
@@ -144,7 +144,7 @@ static int get_lcd_level(void)
        int result;
 
        result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1,
-                               &rdata, 1, 1);
+                               &rdata, 1);
        if (result < 0)
                return result;
 
@@ -157,7 +157,7 @@ static int get_auto_brightness(void)
        int result;
 
        result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1,
-                               &rdata, 1, 1);
+                               &rdata, 1);
        if (result < 0)
                return result;
 
@@ -172,7 +172,7 @@ static int set_auto_brightness(int enable)
        wdata[0] = 4;
 
        result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1,
-                               &rdata, 1, 1);
+                               &rdata, 1);
        if (result < 0)
                return result;
 
@@ -180,7 +180,7 @@ static int set_auto_brightness(int enable)
        wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0);
 
        return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2,
-                             NULL, 0, 1);
+                             NULL, 0);
 }
 
 static ssize_t set_device_state(const char *buf, size_t count, u8 mask)
@@ -217,7 +217,7 @@ static int get_wireless_state(int *wlan, int *bluetooth)
        u8 wdata = 0, rdata;
        int result;
 
-       result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1, 1);
+       result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1);
        if (result < 0)
                return -1;
 
@@ -447,7 +447,7 @@ static struct platform_device *msipf_device;
 
 static int dmi_check_cb(const struct dmi_system_id *id)
 {
-       pr_info("Identified laptop model '%s'.\n", id->ident);
+       pr_info("Identified laptop model '%s'\n", id->ident);
        return 1;
 }
 
@@ -800,7 +800,7 @@ static void msi_laptop_input_destroy(void)
        input_unregister_device(msi_laptop_input_dev);
 }
 
-static int load_scm_model_init(struct platform_device *sdev)
+static int __init load_scm_model_init(struct platform_device *sdev)
 {
        u8 data;
        int result;
@@ -875,8 +875,7 @@ static int __init msi_init(void)
        /* Register backlight stuff */
 
        if (acpi_video_backlight_support()) {
-               pr_info("Brightness ignored, must be controlled "
-                      "by ACPI video driver\n");
+               pr_info("Brightness ignored, must be controlled by ACPI video driver\n");
        } else {
                struct backlight_properties props;
                memset(&props, 0, sizeof(struct backlight_properties));
@@ -930,7 +929,7 @@ static int __init msi_init(void)
        if (auto_brightness != 2)
                set_auto_brightness(auto_brightness);
 
-       pr_info("driver "MSI_DRIVER_VERSION" successfully loaded.\n");
+       pr_info("driver " MSI_DRIVER_VERSION " successfully loaded\n");
 
        return 0;
 
@@ -978,7 +977,7 @@ static void __exit msi_cleanup(void)
        if (auto_brightness != 2)
                set_auto_brightness(1);
 
-       pr_info("driver unloaded.\n");
+       pr_info("driver unloaded\n");
 }
 
 module_init(msi_init);
index d5419c9ec07a39e34ebc49d7698d39cb933a0da9..c832e3356cd61f03036ad8802919285add489466 100644 (file)
@@ -20,6 +20,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
 #include <linux/input.h>
@@ -36,13 +37,10 @@ MODULE_ALIAS("wmi:551A1F84-FBDD-4125-91DB-3EA8F44F1D45");
 MODULE_ALIAS("wmi:B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2");
 
 #define DRV_NAME "msi-wmi"
-#define DRV_PFX DRV_NAME ": "
 
 #define MSIWMI_BIOS_GUID "551A1F84-FBDD-4125-91DB-3EA8F44F1D45"
 #define MSIWMI_EVENT_GUID "B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2"
 
-#define dprintk(msg...) pr_debug(DRV_PFX msg)
-
 #define SCANCODE_BASE 0xD0
 #define MSI_WMI_BRIGHTNESSUP   SCANCODE_BASE
 #define MSI_WMI_BRIGHTNESSDOWN (SCANCODE_BASE + 1)
@@ -78,7 +76,7 @@ static int msi_wmi_query_block(int instance, int *ret)
 
        if (!obj || obj->type != ACPI_TYPE_INTEGER) {
                if (obj) {
-                       printk(KERN_ERR DRV_PFX "query block returned object "
+                       pr_err("query block returned object "
                               "type: %d - buffer length:%d\n", obj->type,
                               obj->type == ACPI_TYPE_BUFFER ?
                               obj->buffer.length : 0);
@@ -97,8 +95,8 @@ static int msi_wmi_set_block(int instance, int value)
 
        struct acpi_buffer input = { sizeof(int), &value };
 
-       dprintk("Going to set block of instance: %d - value: %d\n",
-               instance, value);
+       pr_debug("Going to set block of instance: %d - value: %d\n",
+                instance, value);
 
        status = wmi_set_block(MSIWMI_BIOS_GUID, instance, &input);
 
@@ -112,20 +110,19 @@ static int bl_get(struct backlight_device *bd)
        /* Instance 1 is "get backlight", cmp with DSDT */
        err = msi_wmi_query_block(1, &ret);
        if (err) {
-               printk(KERN_ERR DRV_PFX "Could not query backlight: %d\n", err);
+               pr_err("Could not query backlight: %d\n", err);
                return -EINVAL;
        }
-       dprintk("Get: Query block returned: %d\n", ret);
+       pr_debug("Get: Query block returned: %d\n", ret);
        for (level = 0; level < ARRAY_SIZE(backlight_map); level++) {
                if (backlight_map[level] == ret) {
-                       dprintk("Current backlight level: 0x%X - index: %d\n",
-                               backlight_map[level], level);
+                       pr_debug("Current backlight level: 0x%X - index: %d\n",
+                                backlight_map[level], level);
                        break;
                }
        }
        if (level == ARRAY_SIZE(backlight_map)) {
-               printk(KERN_ERR DRV_PFX "get: Invalid brightness value: 0x%X\n",
-                      ret);
+               pr_err("get: Invalid brightness value: 0x%X\n", ret);
                return -EINVAL;
        }
        return level;
@@ -156,7 +153,7 @@ static void msi_wmi_notify(u32 value, void *context)
 
        status = wmi_get_event_data(value, &response);
        if (status != AE_OK) {
-               printk(KERN_INFO DRV_PFX "bad event status 0x%x\n", status);
+               pr_info("bad event status 0x%x\n", status);
                return;
        }
 
@@ -164,7 +161,7 @@ static void msi_wmi_notify(u32 value, void *context)
 
        if (obj && obj->type == ACPI_TYPE_INTEGER) {
                int eventcode = obj->integer.value;
-               dprintk("Eventcode: 0x%x\n", eventcode);
+               pr_debug("Eventcode: 0x%x\n", eventcode);
                key = sparse_keymap_entry_from_scancode(msi_wmi_input_dev,
                                eventcode);
                if (key) {
@@ -175,8 +172,8 @@ static void msi_wmi_notify(u32 value, void *context)
                        /* Ignore event if the same event happened in a 50 ms
                           timeframe -> Key press may result in 10-20 GPEs */
                        if (ktime_to_us(diff) < 1000 * 50) {
-                               dprintk("Suppressed key event 0x%X - "
-                                       "Last press was %lld us ago\n",
+                               pr_debug("Suppressed key event 0x%X - "
+                                        "Last press was %lld us ago\n",
                                         key->code, ktime_to_us(diff));
                                return;
                        }
@@ -187,17 +184,16 @@ static void msi_wmi_notify(u32 value, void *context)
                        (!acpi_video_backlight_support() ||
                        (key->code != MSI_WMI_BRIGHTNESSUP &&
                        key->code != MSI_WMI_BRIGHTNESSDOWN))) {
-                               dprintk("Send key: 0x%X - "
-                                       "Input layer keycode: %d\n", key->code,
-                                        key->keycode);
+                               pr_debug("Send key: 0x%X - "
+                                        "Input layer keycode: %d\n",
+                                        key->code, key->keycode);
                                sparse_keymap_report_entry(msi_wmi_input_dev,
                                                key, 1, true);
                        }
                } else
-                       printk(KERN_INFO "Unknown key pressed - %x\n",
-                              eventcode);
+                       pr_info("Unknown key pressed - %x\n", eventcode);
        } else
-               printk(KERN_INFO DRV_PFX "Unknown event received\n");
+               pr_info("Unknown event received\n");
        kfree(response.pointer);
 }
 
@@ -238,8 +234,7 @@ static int __init msi_wmi_init(void)
        int err;
 
        if (!wmi_has_guid(MSIWMI_EVENT_GUID)) {
-               printk(KERN_ERR
-                      "This machine doesn't have MSI-hotkeys through WMI\n");
+               pr_err("This machine doesn't have MSI-hotkeys through WMI\n");
                return -ENODEV;
        }
        err = wmi_install_notify_handler(MSIWMI_EVENT_GUID,
@@ -270,7 +265,7 @@ static int __init msi_wmi_init(void)
 
                backlight->props.brightness = err;
        }
-       dprintk("Event handler installed\n");
+       pr_debug("Event handler installed\n");
 
        return 0;
 
diff --git a/drivers/platform/x86/mxm-wmi.c b/drivers/platform/x86/mxm-wmi.c
new file mode 100644 (file)
index 0000000..0aea63b
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * MXM WMI driver
+ *
+ * Copyright(C) 2010 Red Hat.
+ *
+ *  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 <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+MODULE_AUTHOR("Dave Airlie");
+MODULE_DESCRIPTION("MXM WMI Driver");
+MODULE_LICENSE("GPL");
+
+#define MXM_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0"
+
+MODULE_ALIAS("wmi:"MXM_WMMX_GUID);
+
+#define MXM_WMMX_FUNC_MXDS 0x5344584D /* "MXDS" */
+#define MXM_WMMX_FUNC_MXMX 0x53445344 /* "MXMX" */
+
+struct mxds_args {
+       u32 func;
+       u32 args;
+       u32 xarg;
+};
+
+int mxm_wmi_call_mxds(int adapter)
+{
+       struct mxds_args args = {
+               .func = MXM_WMMX_FUNC_MXDS,
+               .args = 0,
+               .xarg = 1,
+       };
+       struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       acpi_status status;
+
+       printk("calling mux switch %d\n", adapter);
+
+       status = wmi_evaluate_method(MXM_WMMX_GUID, 0x1, adapter, &input,
+                                    &output);
+
+       if (ACPI_FAILURE(status))
+               return status;
+
+       printk("mux switched %d\n", status);
+       return 0;
+                           
+}
+EXPORT_SYMBOL_GPL(mxm_wmi_call_mxds);
+
+int mxm_wmi_call_mxmx(int adapter)
+{
+       struct mxds_args args = {
+               .func = MXM_WMMX_FUNC_MXMX,
+               .args = 0,
+               .xarg = 1,
+       };
+       struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       acpi_status status;
+
+       printk("calling mux switch %d\n", adapter);
+
+       status = wmi_evaluate_method(MXM_WMMX_GUID, 0x1, adapter, &input,
+                                    &output);
+
+       if (ACPI_FAILURE(status))
+               return status;
+
+       printk("mux mutex set switched %d\n", status);
+       return 0;
+                           
+}
+EXPORT_SYMBOL_GPL(mxm_wmi_call_mxmx);
+
+bool mxm_wmi_supported(void)
+{
+       bool guid_valid;
+       guid_valid = wmi_has_guid(MXM_WMMX_GUID);
+       return guid_valid;
+}
+EXPORT_SYMBOL_GPL(mxm_wmi_supported);
+
+static int __init mxm_wmi_init(void)
+{
+       return 0;
+}
+
+static void __exit mxm_wmi_exit(void)
+{
+}
+
+module_init(mxm_wmi_init);
+module_exit(mxm_wmi_exit);
index 6fe8cd6e23b5f89fd1efc1145796a9e6c530aa8e..bbd182e178cb65682b7ed47684467184da4c9a03 100644 (file)
@@ -42,6 +42,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/miscdevice.h>
 #endif
 
-#define DRV_PFX                        "sony-laptop: "
-#define dprintk(msg...)                do {    \
-       if (debug)                      \
-               pr_warn(DRV_PFX msg);   \
+#define dprintk(fmt, ...)                      \
+do {                                           \
+       if (debug)                              \
+               pr_warn(fmt, ##__VA_ARGS__);    \
 } while (0)
 
 #define SONY_LAPTOP_DRIVER_VERSION     "0.6"
@@ -418,7 +420,7 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
        error = kfifo_alloc(&sony_laptop_input.fifo,
                            SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
        if (error) {
-               pr_err(DRV_PFX "kfifo_alloc failed\n");
+               pr_err("kfifo_alloc failed\n");
                goto err_dec_users;
        }
 
@@ -702,7 +704,7 @@ static int acpi_callgetfunc(acpi_handle handle, char *name, int *result)
                return 0;
        }
 
-       pr_warn(DRV_PFX "acpi_callreadfunc failed\n");
+       pr_warn("acpi_callreadfunc failed\n");
 
        return -1;
 }
@@ -728,8 +730,7 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
        if (status == AE_OK) {
                if (result != NULL) {
                        if (out_obj.type != ACPI_TYPE_INTEGER) {
-                               pr_warn(DRV_PFX "acpi_evaluate_object bad "
-                                      "return type\n");
+                               pr_warn("acpi_evaluate_object bad return type\n");
                                return -1;
                        }
                        *result = out_obj.integer.value;
@@ -737,7 +738,7 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
                return 0;
        }
 
-       pr_warn(DRV_PFX "acpi_evaluate_object failed\n");
+       pr_warn("acpi_evaluate_object failed\n");
 
        return -1;
 }
@@ -961,7 +962,6 @@ static int sony_backlight_get_brightness(struct backlight_device *bd)
 static int sony_nc_get_brightness_ng(struct backlight_device *bd)
 {
        int result;
-       int *handle = (int *)bl_get_data(bd);
        struct sony_backlight_props *sdev =
                (struct sony_backlight_props *)bl_get_data(bd);
 
@@ -973,7 +973,6 @@ static int sony_nc_get_brightness_ng(struct backlight_device *bd)
 static int sony_nc_update_status_ng(struct backlight_device *bd)
 {
        int value, result;
-       int *handle = (int *)bl_get_data(bd);
        struct sony_backlight_props *sdev =
                (struct sony_backlight_props *)bl_get_data(bd);
 
@@ -1104,10 +1103,8 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
                                }
 
                                if (!key_event->data)
-                                       pr_info(DRV_PFX
-                                                       "Unknown event: 0x%x 0x%x\n",
-                                                       key_handle,
-                                                       ev);
+                                       pr_info("Unknown event: 0x%x 0x%x\n",
+                                               key_handle, ev);
                                else
                                        sony_laptop_report_input_event(ev);
                        }
@@ -1128,7 +1125,7 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
        struct acpi_device_info *info;
 
        if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) {
-               pr_warn(DRV_PFX "method: name: %4.4s, args %X\n",
+               pr_warn("method: name: %4.4s, args %X\n",
                        (char *)&info->name, info->param_count);
 
                kfree(info);
@@ -1169,7 +1166,7 @@ static int sony_nc_resume(struct acpi_device *device)
                ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
                                       item->value, NULL);
                if (ret < 0) {
-                       pr_err(DRV_PFX "%s: %d\n", __func__, ret);
+                       pr_err("%s: %d\n", __func__, ret);
                        break;
                }
        }
@@ -1336,12 +1333,12 @@ static void sony_nc_rfkill_setup(struct acpi_device *device)
 
        device_enum = (union acpi_object *) buffer.pointer;
        if (!device_enum) {
-               pr_err(DRV_PFX "No SN06 return object.");
+               pr_err("No SN06 return object\n");
                goto out_no_enum;
        }
        if (device_enum->type != ACPI_TYPE_BUFFER) {
-               pr_err(DRV_PFX "Invalid SN06 return object 0x%.2x\n",
-                               device_enum->type);
+               pr_err("Invalid SN06 return object 0x%.2x\n",
+                      device_enum->type);
                goto out_no_enum;
        }
 
@@ -1662,7 +1659,7 @@ static void sony_nc_backlight_setup(void)
                                                      ops, &props);
 
        if (IS_ERR(sony_bl_props.dev)) {
-               pr_warn(DRV_PFX "unable to register backlight device\n");
+               pr_warn("unable to register backlight device\n");
                sony_bl_props.dev = NULL;
        } else
                sony_bl_props.dev->props.brightness =
@@ -1682,8 +1679,7 @@ static int sony_nc_add(struct acpi_device *device)
        acpi_handle handle;
        struct sony_nc_value *item;
 
-       pr_info(DRV_PFX "%s v%s.\n", SONY_NC_DRIVER_NAME,
-                       SONY_LAPTOP_DRIVER_VERSION);
+       pr_info("%s v%s\n", SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
 
        sony_nc_acpi_device = device;
        strcpy(acpi_device_class(device), "sony/hotkey");
@@ -1708,7 +1704,7 @@ static int sony_nc_add(struct acpi_device *device)
                                sony_nc_acpi_handle, 1, sony_walk_callback,
                                NULL, NULL, NULL);
                if (ACPI_FAILURE(status)) {
-                       pr_warn(DRV_PFX "unable to walk acpi resources\n");
+                       pr_warn("unable to walk acpi resources\n");
                        result = -ENODEV;
                        goto outpresent;
                }
@@ -1736,13 +1732,12 @@ static int sony_nc_add(struct acpi_device *device)
        /* setup input devices and helper fifo */
        result = sony_laptop_setup_input(device);
        if (result) {
-               pr_err(DRV_PFX "Unable to create input devices.\n");
+               pr_err("Unable to create input devices\n");
                goto outkbdbacklight;
        }
 
        if (acpi_video_backlight_support()) {
-               pr_info(DRV_PFX "brightness ignored, must be "
-                      "controlled by ACPI video driver\n");
+               pr_info("brightness ignored, must be controlled by ACPI video driver\n");
        } else {
                sony_nc_backlight_setup();
        }
@@ -2265,9 +2260,9 @@ out:
        if (pcidev)
                pci_dev_put(pcidev);
 
-       pr_info(DRV_PFX "detected Type%d model\n",
-                       dev->model == SONYPI_DEVICE_TYPE1 ? 1 :
-                       dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
+       pr_info("detected Type%d model\n",
+               dev->model == SONYPI_DEVICE_TYPE1 ? 1 :
+               dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
 }
 
 /* camera tests and poweron/poweroff */
@@ -2313,7 +2308,7 @@ static int __sony_pic_camera_ready(void)
 static int __sony_pic_camera_off(void)
 {
        if (!camera) {
-               pr_warn(DRV_PFX "camera control not enabled\n");
+               pr_warn("camera control not enabled\n");
                return -ENODEV;
        }
 
@@ -2333,7 +2328,7 @@ static int __sony_pic_camera_on(void)
        int i, j, x;
 
        if (!camera) {
-               pr_warn(DRV_PFX "camera control not enabled\n");
+               pr_warn("camera control not enabled\n");
                return -ENODEV;
        }
 
@@ -2356,7 +2351,7 @@ static int __sony_pic_camera_on(void)
        }
 
        if (j == 0) {
-               pr_warn(DRV_PFX "failed to power on camera\n");
+               pr_warn("failed to power on camera\n");
                return -ENODEV;
        }
 
@@ -2412,8 +2407,7 @@ int sony_pic_camera_command(int command, u8 value)
                                ITERATIONS_SHORT);
                break;
        default:
-               pr_err(DRV_PFX "sony_pic_camera_command invalid: %d\n",
-                      command);
+               pr_err("sony_pic_camera_command invalid: %d\n", command);
                break;
        }
        mutex_unlock(&spic_dev.lock);
@@ -2819,7 +2813,7 @@ static int sonypi_compat_init(void)
        error =
         kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
        if (error) {
-               pr_err(DRV_PFX "kfifo_alloc failed\n");
+               pr_err("kfifo_alloc failed\n");
                return error;
        }
 
@@ -2829,12 +2823,12 @@ static int sonypi_compat_init(void)
                sonypi_misc_device.minor = minor;
        error = misc_register(&sonypi_misc_device);
        if (error) {
-               pr_err(DRV_PFX "misc_register failed\n");
+               pr_err("misc_register failed\n");
                goto err_free_kfifo;
        }
        if (minor == -1)
-               pr_info(DRV_PFX "device allocated minor is %d\n",
-                      sonypi_misc_device.minor);
+               pr_info("device allocated minor is %d\n",
+                       sonypi_misc_device.minor);
 
        return 0;
 
@@ -2893,8 +2887,8 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
                        }
                        for (i = 0; i < p->interrupt_count; i++) {
                                if (!p->interrupts[i]) {
-                                       pr_warn(DRV_PFX "Invalid IRQ %d\n",
-                                                       p->interrupts[i]);
+                                       pr_warn("Invalid IRQ %d\n",
+                                               p->interrupts[i]);
                                        continue;
                                }
                                interrupt = kzalloc(sizeof(*interrupt),
@@ -2932,14 +2926,14 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
                                                ioport->io2.address_length);
                        }
                        else {
-                               pr_err(DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n");
+                               pr_err("Unknown SPIC Type, more than 2 IO Ports\n");
                                return AE_ERROR;
                        }
                        return AE_OK;
                }
        default:
                dprintk("Resource %d isn't an IRQ nor an IO port\n",
-                               resource->type);
+                       resource->type);
 
        case ACPI_RESOURCE_TYPE_END_TAG:
                return AE_OK;
@@ -2960,7 +2954,7 @@ static int sony_pic_possible_resources(struct acpi_device *device)
        dprintk("Evaluating _STA\n");
        result = acpi_bus_get_status(device);
        if (result) {
-               pr_warn(DRV_PFX "Unable to read status\n");
+               pr_warn("Unable to read status\n");
                goto end;
        }
 
@@ -2976,8 +2970,7 @@ static int sony_pic_possible_resources(struct acpi_device *device)
        status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,
                        sony_pic_read_possible_resource, &spic_dev);
        if (ACPI_FAILURE(status)) {
-               pr_warn(DRV_PFX "Failure evaluating %s\n",
-                               METHOD_NAME__PRS);
+               pr_warn("Failure evaluating %s\n", METHOD_NAME__PRS);
                result = -ENODEV;
        }
 end:
@@ -3090,7 +3083,7 @@ static int sony_pic_enable(struct acpi_device *device,
 
        /* check for total failure */
        if (ACPI_FAILURE(status)) {
-               pr_err(DRV_PFX "Error evaluating _SRS\n");
+               pr_err("Error evaluating _SRS\n");
                result = -ENODEV;
                goto end;
        }
@@ -3182,7 +3175,7 @@ static int sony_pic_remove(struct acpi_device *device, int type)
        struct sony_pic_irq *irq, *tmp_irq;
 
        if (sony_pic_disable(device)) {
-               pr_err(DRV_PFX "Couldn't disable device.\n");
+               pr_err("Couldn't disable device\n");
                return -ENXIO;
        }
 
@@ -3222,8 +3215,7 @@ static int sony_pic_add(struct acpi_device *device)
        struct sony_pic_ioport *io, *tmp_io;
        struct sony_pic_irq *irq, *tmp_irq;
 
-       pr_info(DRV_PFX "%s v%s.\n", SONY_PIC_DRIVER_NAME,
-                       SONY_LAPTOP_DRIVER_VERSION);
+       pr_info("%s v%s\n", SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
 
        spic_dev.acpi_dev = device;
        strcpy(acpi_device_class(device), "sony/hotkey");
@@ -3233,14 +3225,14 @@ static int sony_pic_add(struct acpi_device *device)
        /* read _PRS resources */
        result = sony_pic_possible_resources(device);
        if (result) {
-               pr_err(DRV_PFX "Unable to read possible resources.\n");
+               pr_err("Unable to read possible resources\n");
                goto err_free_resources;
        }
 
        /* setup input devices and helper fifo */
        result = sony_laptop_setup_input(device);
        if (result) {
-               pr_err(DRV_PFX "Unable to create input devices.\n");
+               pr_err("Unable to create input devices\n");
                goto err_free_resources;
        }
 
@@ -3281,7 +3273,7 @@ static int sony_pic_add(struct acpi_device *device)
                }
        }
        if (!spic_dev.cur_ioport) {
-               pr_err(DRV_PFX "Failed to request_region.\n");
+               pr_err("Failed to request_region\n");
                result = -ENODEV;
                goto err_remove_compat;
        }
@@ -3301,7 +3293,7 @@ static int sony_pic_add(struct acpi_device *device)
                }
        }
        if (!spic_dev.cur_irq) {
-               pr_err(DRV_PFX "Failed to request_irq.\n");
+               pr_err("Failed to request_irq\n");
                result = -ENODEV;
                goto err_release_region;
        }
@@ -3309,7 +3301,7 @@ static int sony_pic_add(struct acpi_device *device)
        /* set resource status _SRS */
        result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
        if (result) {
-               pr_err(DRV_PFX "Couldn't enable device.\n");
+               pr_err("Couldn't enable device\n");
                goto err_free_irq;
        }
 
@@ -3418,7 +3410,7 @@ static int __init sony_laptop_init(void)
        if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
                result = acpi_bus_register_driver(&sony_pic_driver);
                if (result) {
-                       pr_err(DRV_PFX "Unable to register SPIC driver.");
+                       pr_err("Unable to register SPIC driver\n");
                        goto out;
                }
                spic_drv_registered = 1;
@@ -3426,7 +3418,7 @@ static int __init sony_laptop_init(void)
 
        result = acpi_bus_register_driver(&sony_nc_driver);
        if (result) {
-               pr_err(DRV_PFX "Unable to register SNC driver.");
+               pr_err("Unable to register SNC driver\n");
                goto out_unregister_pic;
        }
 
index 865ef78d6f1a7c0593758fd73777bc35a502d5b4..e24f5ae475af019815b10a07e2febaabd29135c6 100644 (file)
@@ -25,6 +25,8 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -40,9 +42,6 @@
 #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");
@@ -264,7 +263,7 @@ static int __init tc1100_init(void)
        if (error)
                goto err_device_del;
 
-       printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras loaded\n");
+       pr_info("HP Compaq TC1100 Tablet WMI Extras loaded\n");
        return 0;
 
  err_device_del:
index 562fcf0dd2b5b083b7d45aeeb7e78a7c6809425f..77f6e707a2a9a43d4c08777f1a97e42dd49a11a0 100644 (file)
@@ -21,6 +21,8 @@
  *  02110-1301, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define TPACPI_VERSION "0.24"
 #define TPACPI_SYSFS_VERSION 0x020700
 
@@ -224,17 +226,6 @@ enum tpacpi_hkey_event_t {
 
 #define TPACPI_MAX_ACPI_ARGS 3
 
-/* printk headers */
-#define TPACPI_LOG TPACPI_FILE ": "
-#define TPACPI_EMERG   KERN_EMERG      TPACPI_LOG
-#define TPACPI_ALERT   KERN_ALERT      TPACPI_LOG
-#define TPACPI_CRIT    KERN_CRIT       TPACPI_LOG
-#define TPACPI_ERR     KERN_ERR        TPACPI_LOG
-#define TPACPI_WARN    KERN_WARNING    TPACPI_LOG
-#define TPACPI_NOTICE  KERN_NOTICE     TPACPI_LOG
-#define TPACPI_INFO    KERN_INFO       TPACPI_LOG
-#define TPACPI_DEBUG   KERN_DEBUG      TPACPI_LOG
-
 /* Debugging printk groups */
 #define TPACPI_DBG_ALL         0xffff
 #define TPACPI_DBG_DISCLOSETASK        0x8000
@@ -389,34 +380,36 @@ static int tpacpi_uwb_emulstate;
  *  Debugging helpers
  */
 
-#define dbg_printk(a_dbg_level, format, arg...) \
-       do { if (dbg_level & (a_dbg_level)) \
-               printk(TPACPI_DEBUG "%s: " format, __func__ , ## arg); \
-       } while (0)
+#define dbg_printk(a_dbg_level, format, arg...)                                \
+do {                                                                   \
+       if (dbg_level & (a_dbg_level))                                  \
+               printk(KERN_DEBUG pr_fmt("%s: " format),                \
+                      __func__, ##arg);                                \
+} while (0)
 
 #ifdef CONFIG_THINKPAD_ACPI_DEBUG
 #define vdbg_printk dbg_printk
 static const char *str_supported(int is_supported);
 #else
-#define vdbg_printk(a_dbg_level, format, arg...) \
-       do { } while (0)
+static inline const char *str_supported(int is_supported) { return ""; }
+#define vdbg_printk(a_dbg_level, format, arg...)       \
+       no_printk(format, ##arg)
 #endif
 
 static void tpacpi_log_usertask(const char * const what)
 {
-       printk(TPACPI_DEBUG "%s: access by process with PID %d\n",
-               what, task_tgid_vnr(current));
+       printk(KERN_DEBUG pr_fmt("%s: access by process with PID %d\n"),
+              what, task_tgid_vnr(current));
 }
 
-#define tpacpi_disclose_usertask(what, format, arg...) \
-       do { \
-               if (unlikely( \
-                   (dbg_level & TPACPI_DBG_DISCLOSETASK) && \
-                   (tpacpi_lifecycle == TPACPI_LIFE_RUNNING))) { \
-                       printk(TPACPI_DEBUG "%s: PID %d: " format, \
-                               what, task_tgid_vnr(current), ## arg); \
-               } \
-       } while (0)
+#define tpacpi_disclose_usertask(what, format, arg...)                 \
+do {                                                                   \
+       if (unlikely((dbg_level & TPACPI_DBG_DISCLOSETASK) &&           \
+                    (tpacpi_lifecycle == TPACPI_LIFE_RUNNING))) {      \
+               printk(KERN_DEBUG pr_fmt("%s: PID %d: " format),        \
+                      what, task_tgid_vnr(current), ## arg);           \
+       }                                                               \
+} while (0)
 
 /*
  * Quirk handling helpers
@@ -535,15 +528,6 @@ TPACPI_HANDLE(hkey, ec, "\\_SB.HKEY",      /* 600e/x, 770e, 770x */
           "HKEY",              /* all others */
           );                   /* 570 */
 
-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.VGA",        /* X100e and a few others */
-          "\\_SB.PCI0.AGP.VID",        /* all others */
-          );                           /* R30, R31 */
-
-
 /*************************************************************************
  * ACPI helpers
  */
@@ -563,7 +547,7 @@ static int acpi_evalf(acpi_handle handle,
        int quiet;
 
        if (!*fmt) {
-               printk(TPACPI_ERR "acpi_evalf() called with empty format\n");
+               pr_err("acpi_evalf() called with empty format\n");
                return 0;
        }
 
@@ -588,7 +572,7 @@ static int acpi_evalf(acpi_handle handle,
                        break;
                        /* add more types as needed */
                default:
-                       printk(TPACPI_ERR "acpi_evalf() called "
+                       pr_err("acpi_evalf() called "
                               "with invalid format character '%c'\n", c);
                        va_end(ap);
                        return 0;
@@ -617,13 +601,13 @@ static int acpi_evalf(acpi_handle handle,
                break;
                /* add more types as needed */
        default:
-               printk(TPACPI_ERR "acpi_evalf() called "
+               pr_err("acpi_evalf() called "
                       "with invalid format character '%c'\n", res_type);
                return 0;
        }
 
        if (!success && !quiet)
-               printk(TPACPI_ERR "acpi_evalf(%s, %s, ...) failed: %s\n",
+               pr_err("acpi_evalf(%s, %s, ...) failed: %s\n",
                       method, fmt0, acpi_format_exception(status));
 
        return success;
@@ -767,8 +751,7 @@ 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(TPACPI_ERR "acpi_bus_get_device(%s) failed: %d\n",
-                       ibm->name, rc);
+               pr_err("acpi_bus_get_device(%s) failed: %d\n", ibm->name, rc);
                return -ENODEV;
        }
 
@@ -781,12 +764,10 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm)
                        ibm->acpi->type, dispatch_acpi_notify, ibm);
        if (ACPI_FAILURE(status)) {
                if (status == AE_ALREADY_EXISTS) {
-                       printk(TPACPI_NOTICE
-                              "another device driver is already "
-                              "handling %s events\n", ibm->name);
+                       pr_notice("another device driver is already "
+                                 "handling %s events\n", ibm->name);
                } else {
-                       printk(TPACPI_ERR
-                              "acpi_install_notify_handler(%s) failed: %s\n",
+                       pr_err("acpi_install_notify_handler(%s) failed: %s\n",
                               ibm->name, acpi_format_exception(status));
                }
                return -ENODEV;
@@ -811,8 +792,7 @@ 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(TPACPI_ERR
-                      "failed to allocate memory for ibm->acpi->driver\n");
+               pr_err("failed to allocate memory for ibm->acpi->driver\n");
                return -ENOMEM;
        }
 
@@ -823,7 +803,7 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
 
        rc = acpi_bus_register_driver(ibm->acpi->driver);
        if (rc < 0) {
-               printk(TPACPI_ERR "acpi_bus_register_driver(%s) failed: %d\n",
+               pr_err("acpi_bus_register_driver(%s) failed: %d\n",
                       ibm->name, rc);
                kfree(ibm->acpi->driver);
                ibm->acpi->driver = NULL;
@@ -1081,15 +1061,14 @@ static int parse_strtoul(const char *buf,
 static void tpacpi_disable_brightness_delay(void)
 {
        if (acpi_evalf(hkey_handle, NULL, "PWMS", "qvd", 0))
-               printk(TPACPI_NOTICE
-                       "ACPI backlight control delay disabled\n");
+               pr_notice("ACPI backlight control delay disabled\n");
 }
 
 static void printk_deprecated_attribute(const char * const what,
                                        const char * const details)
 {
        tpacpi_log_usertask("deprecated sysfs attribute");
-       printk(TPACPI_WARN "WARNING: sysfs attribute %s is deprecated and "
+       pr_warn("WARNING: sysfs attribute %s is deprecated and "
                "will be removed. %s\n",
                what, details);
 }
@@ -1264,8 +1243,7 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id,
                                                &tpacpi_rfk_rfkill_ops,
                                                atp_rfk);
        if (!atp_rfk || !atp_rfk->rfkill) {
-               printk(TPACPI_ERR
-                       "failed to allocate memory for rfkill class\n");
+               pr_err("failed to allocate memory for rfkill class\n");
                kfree(atp_rfk);
                return -ENOMEM;
        }
@@ -1275,9 +1253,8 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id,
 
        sw_status = (tp_rfkops->get_status)();
        if (sw_status < 0) {
-               printk(TPACPI_ERR
-                       "failed to read initial state for %s, error %d\n",
-                       name, sw_status);
+               pr_err("failed to read initial state for %s, error %d\n",
+                      name, sw_status);
        } else {
                sw_state = (sw_status == TPACPI_RFK_RADIO_OFF);
                if (set_default) {
@@ -1291,9 +1268,7 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id,
 
        res = rfkill_register(atp_rfk->rfkill);
        if (res < 0) {
-               printk(TPACPI_ERR
-                       "failed to register %s rfkill switch: %d\n",
-                       name, res);
+               pr_err("failed to register %s rfkill switch: %d\n", name, res);
                rfkill_destroy(atp_rfk->rfkill);
                kfree(atp_rfk);
                return res;
@@ -1301,7 +1276,7 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id,
 
        tpacpi_rfkill_switches[id] = atp_rfk;
 
-       printk(TPACPI_INFO "rfkill switch %s: radio is %sblocked\n",
+       pr_info("rfkill switch %s: radio is %sblocked\n",
                name, (sw_state || hw_state) ? "" : "un");
        return 0;
 }
@@ -1825,10 +1800,8 @@ static void __init tpacpi_check_outdated_fw(void)
                 * broken, or really stable to begin with, so it is
                 * best if the user upgrades the firmware anyway.
                 */
-               printk(TPACPI_WARN
-                       "WARNING: Outdated ThinkPad BIOS/EC firmware\n");
-               printk(TPACPI_WARN
-                       "WARNING: This firmware may be missing critical bug "
+               pr_warn("WARNING: Outdated ThinkPad BIOS/EC firmware\n");
+               pr_warn("WARNING: This firmware may be missing critical bug "
                        "fixes and/or important features\n");
        }
 }
@@ -2117,9 +2090,7 @@ void static hotkey_mask_warn_incomplete_mask(void)
                (hotkey_all_mask | TPACPI_HKEY_NVRAM_KNOWN_MASK);
 
        if (wantedmask)
-               printk(TPACPI_NOTICE
-                       "required events 0x%08x not enabled!\n",
-                       wantedmask);
+               pr_notice("required events 0x%08x not enabled!\n", wantedmask);
 }
 
 /*
@@ -2157,10 +2128,9 @@ static int hotkey_mask_set(u32 mask)
         * a given event.
         */
        if (!hotkey_mask_get() && !rc && (fwmask & ~hotkey_acpi_mask)) {
-               printk(TPACPI_NOTICE
-                      "asked for hotkey mask 0x%08x, but "
-                      "firmware forced it to 0x%08x\n",
-                      fwmask, hotkey_acpi_mask);
+               pr_notice("asked for hotkey mask 0x%08x, but "
+                         "firmware forced it to 0x%08x\n",
+                         fwmask, hotkey_acpi_mask);
        }
 
        if (tpacpi_lifecycle != TPACPI_LIFE_EXITING)
@@ -2184,13 +2154,11 @@ static int hotkey_user_mask_set(const u32 mask)
            (mask == 0xffff || mask == 0xffffff ||
             mask == 0xffffffff)) {
                tp_warned.hotkey_mask_ff = 1;
-               printk(TPACPI_NOTICE
-                      "setting the hotkey mask to 0x%08x is likely "
-                      "not the best way to go about it\n", mask);
-               printk(TPACPI_NOTICE
-                      "please consider using the driver defaults, "
-                      "and refer to up-to-date thinkpad-acpi "
-                      "documentation\n");
+               pr_notice("setting the hotkey mask to 0x%08x is likely "
+                         "not the best way to go about it\n", mask);
+               pr_notice("please consider using the driver defaults, "
+                         "and refer to up-to-date thinkpad-acpi "
+                         "documentation\n");
        }
 
        /* Try to enable what the user asked for, plus whatever we need.
@@ -2574,8 +2542,7 @@ static void hotkey_poll_setup(const bool may_warn)
                                        NULL, TPACPI_NVRAM_KTHREAD_NAME);
                        if (IS_ERR(tpacpi_hotkey_task)) {
                                tpacpi_hotkey_task = NULL;
-                               printk(TPACPI_ERR
-                                      "could not create kernel thread "
+                               pr_err("could not create kernel thread "
                                       "for hotkey polling\n");
                        }
                }
@@ -2583,11 +2550,10 @@ static void hotkey_poll_setup(const bool may_warn)
                hotkey_poll_stop_sync();
                if (may_warn && (poll_driver_mask || poll_user_mask) &&
                    hotkey_poll_freq == 0) {
-                       printk(TPACPI_NOTICE
-                               "hot keys 0x%08x and/or events 0x%08x "
-                               "require polling, which is currently "
-                               "disabled\n",
-                               poll_user_mask, poll_driver_mask);
+                       pr_notice("hot keys 0x%08x and/or events 0x%08x "
+                                 "require polling, which is currently "
+                                 "disabled\n",
+                                 poll_user_mask, poll_driver_mask);
                }
        }
 }
@@ -2811,13 +2777,13 @@ static ssize_t hotkey_source_mask_store(struct device *dev,
        mutex_unlock(&hotkey_mutex);
 
        if (rc < 0)
-               printk(TPACPI_ERR "hotkey_source_mask: failed to update the"
-                       "firmware event mask!\n");
+               pr_err("hotkey_source_mask: "
+                      "failed to update the firmware event mask!\n");
 
        if (r_ev)
-               printk(TPACPI_NOTICE "hotkey_source_mask: "
-                       "some important events were disabled: "
-                       "0x%04x\n", r_ev);
+               pr_notice("hotkey_source_mask: "
+                         "some important events were disabled: 0x%04x\n",
+                         r_ev);
 
        tpacpi_disclose_usertask("hotkey_source_mask", "set to 0x%08lx\n", t);
 
@@ -3048,8 +3014,7 @@ static void hotkey_exit(void)
        if (((tp_features.hotkey_mask &&
              hotkey_mask_set(hotkey_orig_mask)) |
             hotkey_status_set(false)) != 0)
-               printk(TPACPI_ERR
-                      "failed to restore hot key mask "
+               pr_err("failed to restore hot key mask "
                       "to BIOS defaults\n");
 }
 
@@ -3288,10 +3253,9 @@ 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(TPACPI_ERR "unknown version of the "
-                              "HKEY interface: 0x%x\n", hkeyv);
-                       printk(TPACPI_ERR "please report this to %s\n",
-                              TPACPI_MAIL);
+                       pr_err("unknown version of the HKEY interface: 0x%x\n",
+                              hkeyv);
+                       pr_err("please report this to %s\n", TPACPI_MAIL);
                } else {
                        /*
                         * MHKV 0x100 in A31, R40, R40e,
@@ -3304,8 +3268,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                        /* Paranoia check AND init hotkey_all_mask */
                        if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
                                        "MHKA", "qd")) {
-                               printk(TPACPI_ERR
-                                      "missing MHKA handler, "
+                               pr_err("missing MHKA handler, "
                                       "please report this to %s\n",
                                       TPACPI_MAIL);
                                /* Fallback: pre-init for FN+F3,F4,F12 */
@@ -3343,16 +3306,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
        if (dbg_wlswemul) {
                tp_features.hotkey_wlsw = 1;
                radiosw_state = !!tpacpi_wlsw_emulstate;
-               printk(TPACPI_INFO
-                       "radio switch emulation enabled\n");
+               pr_info("radio switch emulation enabled\n");
        } else
 #endif
        /* Not all thinkpads have a hardware radio switch */
        if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
                tp_features.hotkey_wlsw = 1;
                radiosw_state = !!status;
-               printk(TPACPI_INFO
-                       "radio switch found; radios are %s\n",
+               pr_info("radio switch found; radios are %s\n",
                        enabled(status, 0));
        }
        if (tp_features.hotkey_wlsw)
@@ -3363,8 +3324,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
        if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) {
                tp_features.hotkey_tablet = 1;
                tabletsw_state = !!(status & TP_HOTKEY_TABLET_MASK);
-               printk(TPACPI_INFO
-                       "possible tablet mode switch found; "
+               pr_info("possible tablet mode switch found; "
                        "ThinkPad in %s mode\n",
                        (tabletsw_state) ? "tablet" : "laptop");
                res = add_to_attr_set(hotkey_dev_attributes,
@@ -3382,8 +3342,7 @@ 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(TPACPI_ERR
-                       "failed to allocate memory for key map\n");
+               pr_err("failed to allocate memory for key map\n");
                res = -ENOMEM;
                goto err_exit;
        }
@@ -3426,13 +3385,11 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
         * userspace. tpacpi_detect_brightness_capabilities() must have
         * been called before this point  */
        if (tp_features.bright_acpimode && acpi_video_backlight_support()) {
-               printk(TPACPI_INFO
-                      "This ThinkPad has standard ACPI backlight "
-                      "brightness control, supported by the ACPI "
-                      "video driver\n");
-               printk(TPACPI_NOTICE
-                      "Disabling thinkpad-acpi brightness events "
-                      "by default...\n");
+               pr_info("This ThinkPad has standard ACPI backlight "
+                       "brightness control, supported by the ACPI "
+                       "video driver\n");
+               pr_notice("Disabling thinkpad-acpi brightness events "
+                         "by default...\n");
 
                /* Disable brightness up/down on Lenovo thinkpads when
                 * ACPI is handling them, otherwise it is plain impossible
@@ -3539,8 +3496,7 @@ static bool hotkey_notify_wakeup(const u32 hkey,
 
        case TP_HKEY_EV_WKUP_S3_BATLOW: /* Battery on critical low level/S3 */
        case TP_HKEY_EV_WKUP_S4_BATLOW: /* Battery on critical low level/S4 */
-               printk(TPACPI_ALERT
-                       "EMERGENCY WAKEUP: battery almost empty\n");
+               pr_alert("EMERGENCY WAKEUP: battery almost empty\n");
                /* how to auto-heal: */
                /* 2313: woke up from S3, go to S4/S5 */
                /* 2413: woke up from S4, go to S5 */
@@ -3551,9 +3507,7 @@ static bool hotkey_notify_wakeup(const u32 hkey,
        }
 
        if (hotkey_wakeup_reason != TP_ACPI_WAKEUP_NONE) {
-               printk(TPACPI_INFO
-                      "woke up due to a hot-unplug "
-                      "request...\n");
+               pr_info("woke up due to a hot-unplug request...\n");
                hotkey_wakeup_reason_notify_change();
        }
        return true;
@@ -3605,37 +3559,31 @@ static bool hotkey_notify_thermal(const u32 hkey,
 
        switch (hkey) {
        case TP_HKEY_EV_THM_TABLE_CHANGED:
-               printk(TPACPI_INFO
-                       "EC reports that Thermal Table has changed\n");
+               pr_info("EC reports that Thermal Table has changed\n");
                /* recommended action: do nothing, we don't have
                 * Lenovo ATM information */
                return true;
        case TP_HKEY_EV_ALARM_BAT_HOT:
-               printk(TPACPI_CRIT
-                       "THERMAL ALARM: battery is too hot!\n");
+               pr_crit("THERMAL ALARM: battery is too hot!\n");
                /* recommended action: warn user through gui */
                break;
        case TP_HKEY_EV_ALARM_BAT_XHOT:
-               printk(TPACPI_ALERT
-                       "THERMAL EMERGENCY: battery is extremely hot!\n");
+               pr_alert("THERMAL EMERGENCY: battery is extremely hot!\n");
                /* recommended action: immediate sleep/hibernate */
                break;
        case TP_HKEY_EV_ALARM_SENSOR_HOT:
-               printk(TPACPI_CRIT
-                       "THERMAL ALARM: "
+               pr_crit("THERMAL ALARM: "
                        "a sensor reports something is too hot!\n");
                /* recommended action: warn user through gui, that */
                /* some internal component is too hot */
                break;
        case TP_HKEY_EV_ALARM_SENSOR_XHOT:
-               printk(TPACPI_ALERT
-                       "THERMAL EMERGENCY: "
-                       "a sensor reports something is extremely hot!\n");
+               pr_alert("THERMAL EMERGENCY: "
+                        "a sensor reports something is extremely hot!\n");
                /* recommended action: immediate sleep/hibernate */
                break;
        default:
-               printk(TPACPI_ALERT
-                        "THERMAL ALERT: unknown thermal alarm received\n");
+               pr_alert("THERMAL ALERT: unknown thermal alarm received\n");
                known = false;
        }
 
@@ -3652,8 +3600,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
        bool known_ev;
 
        if (event != 0x80) {
-               printk(TPACPI_ERR
-                      "unknown HKEY notification event %d\n", event);
+               pr_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,
@@ -3664,7 +3611,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
 
        while (1) {
                if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
-                       printk(TPACPI_ERR "failed to retrieve HKEY event\n");
+                       pr_err("failed to retrieve HKEY event\n");
                        return;
                }
 
@@ -3692,8 +3639,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
                        switch (hkey) {
                        case TP_HKEY_EV_BAYEJ_ACK:
                                hotkey_autosleep_ack = 1;
-                               printk(TPACPI_INFO
-                                      "bay ejected\n");
+                               pr_info("bay ejected\n");
                                hotkey_wakeup_hotunplug_complete_notify_change();
                                known_ev = true;
                                break;
@@ -3709,8 +3655,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
                        /* 0x4000-0x4FFF: dock-related wakeups */
                        if (hkey == TP_HKEY_EV_UNDOCK_ACK) {
                                hotkey_autosleep_ack = 1;
-                               printk(TPACPI_INFO
-                                      "undocked\n");
+                               pr_info("undocked\n");
                                hotkey_wakeup_hotunplug_complete_notify_change();
                                known_ev = true;
                        } else {
@@ -3741,11 +3686,9 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
                        known_ev = false;
                }
                if (!known_ev) {
-                       printk(TPACPI_NOTICE
-                              "unhandled HKEY event 0x%04x\n", hkey);
-                       printk(TPACPI_NOTICE
-                              "please report the conditions when this "
-                              "event happened to %s\n", TPACPI_MAIL);
+                       pr_notice("unhandled HKEY event 0x%04x\n", hkey);
+                       pr_notice("please report the conditions when this "
+                                 "event happened to %s\n", TPACPI_MAIL);
                }
 
                /* Legacy events */
@@ -3778,8 +3721,7 @@ static void hotkey_resume(void)
 
        if (hotkey_status_set(true) < 0 ||
            hotkey_mask_set(hotkey_acpi_mask) < 0)
-               printk(TPACPI_ERR
-                      "error while attempting to reset the event "
+               pr_err("error while attempting to reset the event "
                       "firmware interface\n");
 
        tpacpi_send_radiosw_update();
@@ -3824,14 +3766,12 @@ static void hotkey_enabledisable_warn(bool enable)
 {
        tpacpi_log_usertask("procfs hotkey enable/disable");
        if (!WARN((tpacpi_lifecycle == TPACPI_LIFE_RUNNING || !enable),
-                       TPACPI_WARN
-                       "hotkey enable/disable functionality has been "
-                       "removed from the driver.  Hotkeys are always "
-                       "enabled\n"))
-               printk(TPACPI_ERR
-                       "Please remove the hotkey=enable module "
-                       "parameter, it is deprecated.  Hotkeys are always "
-                       "enabled\n");
+                 pr_fmt("hotkey enable/disable functionality has been "
+                        "removed from the driver.  "
+                        "Hotkeys are always enabled.\n")))
+               pr_err("Please remove the hotkey=enable module "
+                      "parameter, it is deprecated.  "
+                      "Hotkeys are always enabled.\n");
 }
 
 static int hotkey_write(char *buf)
@@ -4011,8 +3951,7 @@ static void bluetooth_shutdown(void)
        /* Order firmware to save current state to NVRAM */
        if (!acpi_evalf(NULL, NULL, "\\BLTH", "vd",
                        TP_ACPI_BLTH_SAVE_STATE))
-               printk(TPACPI_NOTICE
-                       "failed to save bluetooth state to NVRAM\n");
+               pr_notice("failed to save bluetooth state to NVRAM\n");
        else
                vdbg_printk(TPACPI_DBG_RFKILL,
                        "bluestooth state saved to NVRAM\n");
@@ -4051,8 +3990,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
        if (dbg_bluetoothemul) {
                tp_features.bluetooth = 1;
-               printk(TPACPI_INFO
-                       "bluetooth switch emulation enabled\n");
+               pr_info("bluetooth switch emulation enabled\n");
        } else
 #endif
        if (tp_features.bluetooth &&
@@ -4203,8 +4141,7 @@ static void wan_shutdown(void)
        /* Order firmware to save current state to NVRAM */
        if (!acpi_evalf(NULL, NULL, "\\WGSV", "vd",
                        TP_ACPI_WGSV_SAVE_STATE))
-               printk(TPACPI_NOTICE
-                       "failed to save WWAN state to NVRAM\n");
+               pr_notice("failed to save WWAN state to NVRAM\n");
        else
                vdbg_printk(TPACPI_DBG_RFKILL,
                        "WWAN state saved to NVRAM\n");
@@ -4241,8 +4178,7 @@ static int __init wan_init(struct ibm_init_struct *iibm)
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
        if (dbg_wwanemul) {
                tp_features.wan = 1;
-               printk(TPACPI_INFO
-                       "wwan switch emulation enabled\n");
+               pr_info("wwan switch emulation enabled\n");
        } else
 #endif
        if (tp_features.wan &&
@@ -4382,8 +4318,7 @@ static int __init uwb_init(struct ibm_init_struct *iibm)
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
        if (dbg_uwbemul) {
                tp_features.uwb = 1;
-               printk(TPACPI_INFO
-                       "uwb switch emulation enabled\n");
+               pr_info("uwb switch emulation enabled\n");
        } else
 #endif
        if (tp_features.uwb &&
@@ -4444,6 +4379,15 @@ static int video_orig_autosw;
 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.VGA",     /* X100e and a few others */
+             "\\_SB.PCI0.AGP.VID",     /* all others */
+       );                              /* R30, R31 */
+
 TPACPI_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID");      /* G41 */
 
 static int __init video_init(struct ibm_init_struct *iibm)
@@ -4487,7 +4431,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(TPACPI_ERR "error while trying to restore original "
+               pr_err("error while trying to restore original "
                        "video autoswitch mode\n");
 }
 
@@ -4560,8 +4504,7 @@ 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(TPACPI_ERR
-                              "video auto-switch left enabled due to error\n");
+                       pr_err("video auto-switch left enabled due to error\n");
                        return -EIO;
                }
                break;
@@ -4630,8 +4573,7 @@ static int video_outputsw_cycle(void)
                return -ENOSYS;
        }
        if (!autosw && video_autosw_set(autosw)) {
-               printk(TPACPI_ERR
-                      "video auto-switch left enabled due to error\n");
+               pr_err("video auto-switch left enabled due to error\n");
                return -EIO;
        }
 
@@ -5348,7 +5290,7 @@ static int __init led_init(struct ibm_init_struct *iibm)
        tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS,
                              GFP_KERNEL);
        if (!tpacpi_leds) {
-               printk(TPACPI_ERR "Out of memory for LED data\n");
+               pr_err("Out of memory for LED data\n");
                return -ENOMEM;
        }
 
@@ -5367,9 +5309,8 @@ static int __init led_init(struct ibm_init_struct *iibm)
        }
 
 #ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS
-       printk(TPACPI_NOTICE
-               "warning: userspace override of important "
-               "firmware LEDs is enabled\n");
+       pr_notice("warning: userspace override of important "
+                 "firmware LEDs is enabled\n");
 #endif
        return 0;
 }
@@ -5639,17 +5580,16 @@ static void thermal_dump_all_sensors(void)
        if (n <= 0)
                return;
 
-       printk(TPACPI_NOTICE
-               "temperatures (Celsius):");
+       pr_notice("temperatures (Celsius):");
 
        for (i = 0; i < n; i++) {
                if (t.temp[i] != TPACPI_THERMAL_SENSOR_NA)
-                       printk(KERN_CONT " %d", (int)(t.temp[i] / 1000));
+                       pr_cont(" %d", (int)(t.temp[i] / 1000));
                else
-                       printk(KERN_CONT " N/A");
+                       pr_cont(" N/A");
        }
 
-       printk(KERN_CONT "\n");
+       pr_cont("\n");
 }
 
 /* sysfs temp##_input -------------------------------------------------- */
@@ -5769,14 +5709,12 @@ 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(TPACPI_ERR
-                                      "ThinkPad ACPI EC access misbehaving, "
+                               pr_err("ThinkPad ACPI EC access misbehaving, "
                                       "falling back to ACPI TMPx access "
                                       "mode\n");
                                thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
                        } else {
-                               printk(TPACPI_ERR
-                                      "ThinkPad ACPI EC access misbehaving, "
+                               pr_err("ThinkPad ACPI EC access misbehaving, "
                                       "disabling thermal sensors access\n");
                                thermal_read_mode = TPACPI_THERMAL_NONE;
                        }
@@ -6129,8 +6067,8 @@ static int __init tpacpi_query_bcl_levels(acpi_handle handle)
        if (ACPI_SUCCESS(acpi_evaluate_object(handle, "_BCL", NULL, &buffer))) {
                obj = (union acpi_object *)buffer.pointer;
                if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
-                       printk(TPACPI_ERR "Unknown _BCL data, "
-                              "please report this to %s\n", TPACPI_MAIL);
+                       pr_err("Unknown _BCL data, please report this to %s\n",
+                              TPACPI_MAIL);
                        rc = 0;
                } else {
                        rc = obj->package.count;
@@ -6214,18 +6152,15 @@ static void __init tpacpi_detect_brightness_capabilities(void)
        switch (b) {
        case 16:
                bright_maxlvl = 15;
-               printk(TPACPI_INFO
-                      "detected a 16-level brightness capable ThinkPad\n");
+               pr_info("detected a 16-level brightness capable ThinkPad\n");
                break;
        case 8:
        case 0:
                bright_maxlvl = 7;
-               printk(TPACPI_INFO
-                      "detected a 8-level brightness capable ThinkPad\n");
+               pr_info("detected a 8-level brightness capable ThinkPad\n");
                break;
        default:
-               printk(TPACPI_ERR
-                      "Unsupported brightness interface, "
+               pr_err("Unsupported brightness interface, "
                       "please contact %s\n", TPACPI_MAIL);
                tp_features.bright_unkfw = 1;
                bright_maxlvl = b - 1;
@@ -6260,22 +6195,19 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
 
        if (acpi_video_backlight_support()) {
                if (brightness_enable > 1) {
-                       printk(TPACPI_INFO
-                              "Standard ACPI backlight interface "
-                              "available, not loading native one.\n");
+                       pr_info("Standard ACPI backlight interface "
+                               "available, not loading native one\n");
                        return 1;
                } else if (brightness_enable == 1) {
-                       printk(TPACPI_WARN
-                               "Cannot enable backlight brightness support, "
+                       pr_warn("Cannot enable backlight brightness support, "
                                "ACPI is already handling it.  Refer to the "
-                               "acpi_backlight kernel parameter\n");
+                               "acpi_backlight kernel parameter.\n");
                        return 1;
                }
        } else if (tp_features.bright_acpimode && brightness_enable > 1) {
-               printk(TPACPI_NOTICE
-                       "Standard ACPI backlight interface not "
-                       "available, thinkpad_acpi native "
-                       "brightness control enabled\n");
+               pr_notice("Standard ACPI backlight interface not "
+                         "available, thinkpad_acpi native "
+                         "brightness control enabled\n");
        }
 
        /*
@@ -6319,19 +6251,17 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
        if (IS_ERR(ibm_backlight_device)) {
                int rc = PTR_ERR(ibm_backlight_device);
                ibm_backlight_device = NULL;
-               printk(TPACPI_ERR "Could not register backlight device\n");
+               pr_err("Could not register backlight device\n");
                return rc;
        }
        vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
                        "brightness is supported\n");
 
        if (quirks & TPACPI_BRGHT_Q_ASK) {
-               printk(TPACPI_NOTICE
-                       "brightness: will use unverified default: "
-                       "brightness_mode=%d\n", brightness_mode);
-               printk(TPACPI_NOTICE
-                       "brightness: please report to %s whether it works well "
-                       "or not on your ThinkPad\n", TPACPI_MAIL);
+               pr_notice("brightness: will use unverified default: "
+                         "brightness_mode=%d\n", brightness_mode);
+               pr_notice("brightness: please report to %s whether it works well "
+                         "or not on your ThinkPad\n", TPACPI_MAIL);
        }
 
        /* Added by mistake in early 2007.  Probably useless, but it could
@@ -6804,8 +6734,7 @@ static int __init volume_create_alsa_mixer(void)
        rc = snd_card_create(alsa_index, alsa_id, THIS_MODULE,
                            sizeof(struct tpacpi_alsa_data), &card);
        if (rc < 0 || !card) {
-               printk(TPACPI_ERR
-                       "Failed to create ALSA card structures: %d\n", rc);
+               pr_err("Failed to create ALSA card structures: %d\n", rc);
                return 1;
        }
 
@@ -6839,9 +6768,8 @@ static int __init volume_create_alsa_mixer(void)
                ctl_vol = snd_ctl_new1(&volume_alsa_control_vol, NULL);
                rc = snd_ctl_add(card, ctl_vol);
                if (rc < 0) {
-                       printk(TPACPI_ERR
-                               "Failed to create ALSA volume control: %d\n",
-                               rc);
+                       pr_err("Failed to create ALSA volume control: %d\n",
+                              rc);
                        goto err_exit;
                }
                data->ctl_vol_id = &ctl_vol->id;
@@ -6850,8 +6778,7 @@ static int __init volume_create_alsa_mixer(void)
        ctl_mute = snd_ctl_new1(&volume_alsa_control_mute, NULL);
        rc = snd_ctl_add(card, ctl_mute);
        if (rc < 0) {
-               printk(TPACPI_ERR "Failed to create ALSA mute control: %d\n",
-                       rc);
+               pr_err("Failed to create ALSA mute control: %d\n", rc);
                goto err_exit;
        }
        data->ctl_mute_id = &ctl_mute->id;
@@ -6859,7 +6786,7 @@ static int __init volume_create_alsa_mixer(void)
        snd_card_set_dev(card, &tpacpi_pdev->dev);
        rc = snd_card_register(card);
        if (rc < 0) {
-               printk(TPACPI_ERR "Failed to register ALSA card: %d\n", rc);
+               pr_err("Failed to register ALSA card: %d\n", rc);
                goto err_exit;
        }
 
@@ -6915,9 +6842,8 @@ static int __init volume_init(struct ibm_init_struct *iibm)
                return -EINVAL;
 
        if (volume_mode == TPACPI_VOL_MODE_UCMS_STEP) {
-               printk(TPACPI_ERR
-                       "UCMS step volume mode not implemented, "
-                       "please contact %s\n", TPACPI_MAIL);
+               pr_err("UCMS step volume mode not implemented, "
+                      "please contact %s\n", TPACPI_MAIL);
                return 1;
        }
 
@@ -6981,13 +6907,11 @@ static int __init volume_init(struct ibm_init_struct *iibm)
 
        rc = volume_create_alsa_mixer();
        if (rc) {
-               printk(TPACPI_ERR
-                       "Could not create the ALSA mixer interface\n");
+               pr_err("Could not create the ALSA mixer interface\n");
                return rc;
        }
 
-       printk(TPACPI_INFO
-               "Console audio control enabled, mode: %s\n",
+       pr_info("Console audio control enabled, mode: %s\n",
                (volume_control_allowed) ?
                        "override (read/write)" :
                        "monitor (read only)");
@@ -7049,12 +6973,10 @@ static int volume_write(char *buf)
        if (!volume_control_allowed && tpacpi_lifecycle != TPACPI_LIFE_INIT) {
                if (unlikely(!tp_warned.volume_ctrl_forbidden)) {
                        tp_warned.volume_ctrl_forbidden = 1;
-                       printk(TPACPI_NOTICE
-                               "Console audio control in monitor mode, "
-                               "changes are not allowed.\n");
-                       printk(TPACPI_NOTICE
-                               "Use the volume_control=1 module parameter "
-                               "to enable volume control\n");
+                       pr_notice("Console audio control in monitor mode, "
+                                 "changes are not allowed\n");
+                       pr_notice("Use the volume_control=1 module parameter "
+                                 "to enable volume control\n");
                }
                return -EPERM;
        }
@@ -7129,8 +7051,7 @@ static void inline volume_alsa_notify_change(void)
 
 static int __init volume_init(struct ibm_init_struct *iibm)
 {
-       printk(TPACPI_INFO
-               "volume: disabled as there is no ALSA support in this kernel\n");
+       pr_info("volume: disabled as there is no ALSA support in this kernel\n");
 
        return 1;
 }
@@ -7337,9 +7258,8 @@ TPACPI_HANDLE(sfan, ec, "SFAN",   /* 570 */
 static void fan_quirk1_setup(void)
 {
        if (fan_control_initial_status == 0x07) {
-               printk(TPACPI_NOTICE
-                      "fan_init: initial fan status is unknown, "
-                      "assuming it is in auto mode\n");
+               pr_notice("fan_init: initial fan status is unknown, "
+                         "assuming it is in auto mode\n");
                tp_features.fan_ctrl_status_undef = 1;
        }
 }
@@ -7726,8 +7646,7 @@ static void fan_watchdog_reset(void)
                if (!queue_delayed_work(tpacpi_wq, &fan_watchdog_task,
                                msecs_to_jiffies(fan_watchdog_maxinterval
                                                 * 1000))) {
-                       printk(TPACPI_ERR
-                              "failed to queue the fan watchdog, "
+                       pr_err("failed to queue the fan watchdog, "
                               "watchdog will not trigger\n");
                }
        } else
@@ -7741,11 +7660,11 @@ static void fan_watchdog_fire(struct work_struct *ignored)
        if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
                return;
 
-       printk(TPACPI_NOTICE "fan watchdog: enabling fan\n");
+       pr_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);
+               pr_err("fan watchdog: error %d while enabling fan, "
+                      "will try again later...\n", -rc);
                /* reschedule for later */
                fan_watchdog_reset();
        }
@@ -8049,8 +7968,7 @@ static int __init fan_init(struct ibm_init_struct *iibm)
                                        "secondary fan support enabled\n");
                        }
                } else {
-                       printk(TPACPI_ERR
-                              "ThinkPad ACPI EC access misbehaving, "
+                       pr_err("ThinkPad ACPI EC access misbehaving, "
                               "fan status and control unavailable\n");
                        return 1;
                }
@@ -8150,9 +8068,8 @@ static void fan_suspend(pm_message_t state)
        fan_control_resume_level = 0;
        rc = fan_get_status_safe(&fan_control_resume_level);
        if (rc < 0)
-               printk(TPACPI_NOTICE
-                       "failed to read fan level for later "
-                       "restore during resume: %d\n", rc);
+               pr_notice("failed to read fan level for later "
+                         "restore during resume: %d\n", rc);
 
        /* if it is undefined, don't attempt to restore it.
         * KEEP THIS LAST */
@@ -8207,13 +8124,11 @@ static void fan_resume(void)
                return;
        }
        if (do_set) {
-               printk(TPACPI_NOTICE
-                       "restoring fan level to 0x%02x\n",
-                       fan_control_resume_level);
+               pr_notice("restoring fan level to 0x%02x\n",
+                         fan_control_resume_level);
                rc = fan_set_level_safe(fan_control_resume_level);
                if (rc < 0)
-                       printk(TPACPI_NOTICE
-                               "failed to restore fan level: %d\n", rc);
+                       pr_notice("failed to restore fan level: %d\n", rc);
        }
 }
 
@@ -8305,8 +8220,8 @@ static int fan_write_cmd_level(const char *cmd, int *rc)
 
        *rc = fan_set_level_safe(level);
        if (*rc == -ENXIO)
-               printk(TPACPI_ERR "level command accepted for unsupported "
-                      "access mode %d", fan_control_access_mode);
+               pr_err("level command accepted for unsupported access mode %d\n",
+                      fan_control_access_mode);
        else if (!*rc)
                tpacpi_disclose_usertask("procfs fan",
                        "set level to %d\n", level);
@@ -8321,8 +8236,8 @@ static int fan_write_cmd_enable(const char *cmd, int *rc)
 
        *rc = fan_set_enable();
        if (*rc == -ENXIO)
-               printk(TPACPI_ERR "enable command accepted for unsupported "
-                      "access mode %d", fan_control_access_mode);
+               pr_err("enable command accepted for unsupported access mode %d\n",
+                      fan_control_access_mode);
        else if (!*rc)
                tpacpi_disclose_usertask("procfs fan", "enable\n");
 
@@ -8336,8 +8251,8 @@ static int fan_write_cmd_disable(const char *cmd, int *rc)
 
        *rc = fan_set_disable();
        if (*rc == -ENXIO)
-               printk(TPACPI_ERR "disable command accepted for unsupported "
-                      "access mode %d", fan_control_access_mode);
+               pr_err("disable command accepted for unsupported access mode %d\n",
+                      fan_control_access_mode);
        else if (!*rc)
                tpacpi_disclose_usertask("procfs fan", "disable\n");
 
@@ -8356,8 +8271,8 @@ static int fan_write_cmd_speed(const char *cmd, int *rc)
 
        *rc = fan_set_speed(speed);
        if (*rc == -ENXIO)
-               printk(TPACPI_ERR "speed command accepted for unsupported "
-                      "access mode %d", fan_control_access_mode);
+               pr_err("speed command accepted for unsupported access mode %d\n",
+                      fan_control_access_mode);
        else if (!*rc)
                tpacpi_disclose_usertask("procfs fan",
                        "set speed to %d\n", speed);
@@ -8560,8 +8475,8 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
                if (ibm->acpi->notify) {
                        ret = setup_acpi_notify(ibm);
                        if (ret == -ENODEV) {
-                               printk(TPACPI_NOTICE "disabling subdriver %s\n",
-                                       ibm->name);
+                               pr_notice("disabling subdriver %s\n",
+                                         ibm->name);
                                ret = 0;
                                goto err_out;
                        }
@@ -8583,8 +8498,7 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
                entry = proc_create_data(ibm->name, mode, proc_dir,
                                         &dispatch_proc_fops, ibm);
                if (!entry) {
-                       printk(TPACPI_ERR "unable to create proc entry %s\n",
-                              ibm->name);
+                       pr_err("unable to create proc entry %s\n", ibm->name);
                        ret = -ENODEV;
                        goto err_out;
                }
@@ -8683,13 +8597,11 @@ static int __must_check __init get_thinkpad_model_data(
                                tp->ec_release = (ec_fw_string[4] << 8)
                                                | ec_fw_string[5];
                        } else {
-                               printk(TPACPI_NOTICE
-                                       "ThinkPad firmware release %s "
-                                       "doesn't match the known patterns\n",
-                                       ec_fw_string);
-                               printk(TPACPI_NOTICE
-                                       "please report this to %s\n",
-                                       TPACPI_MAIL);
+                               pr_notice("ThinkPad firmware release %s "
+                                         "doesn't match the known patterns\n",
+                                         ec_fw_string);
+                               pr_notice("please report this to %s\n",
+                                         TPACPI_MAIL);
                        }
                        break;
                }
@@ -8733,8 +8645,7 @@ static int __init probe_for_thinkpad(void)
        tpacpi_acpi_handle_locate("ec", TPACPI_ACPI_EC_HID, &ec_handle);
        if (!ec_handle) {
                if (is_thinkpad)
-                       printk(TPACPI_ERR
-                               "Not yet supported ThinkPad detected!\n");
+                       pr_err("Not yet supported ThinkPad detected!\n");
                return -ENODEV;
        }
 
@@ -8746,10 +8657,10 @@ static int __init probe_for_thinkpad(void)
 
 static void __init thinkpad_acpi_init_banner(void)
 {
-       printk(TPACPI_INFO "%s v%s\n", TPACPI_DESC, TPACPI_VERSION);
-       printk(TPACPI_INFO "%s\n", TPACPI_URL);
+       pr_info("%s v%s\n", TPACPI_DESC, TPACPI_VERSION);
+       pr_info("%s\n", TPACPI_URL);
 
-       printk(TPACPI_INFO "ThinkPad BIOS %s, EC %s\n",
+       pr_info("ThinkPad BIOS %s, EC %s\n",
                (thinkpad_id.bios_version_str) ?
                        thinkpad_id.bios_version_str : "unknown",
                (thinkpad_id.ec_version_str) ?
@@ -8758,7 +8669,7 @@ static void __init thinkpad_acpi_init_banner(void)
        BUG_ON(!thinkpad_id.vendor);
 
        if (thinkpad_id.model_str)
-               printk(TPACPI_INFO "%s %s, model %s\n",
+               pr_info("%s %s, model %s\n",
                        (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
                                "IBM" : ((thinkpad_id.vendor ==
                                                PCI_VENDOR_ID_LENOVO) ?
@@ -9024,8 +8935,7 @@ static int __init thinkpad_acpi_module_init(void)
 
        ret = get_thinkpad_model_data(&thinkpad_id);
        if (ret) {
-               printk(TPACPI_ERR
-                       "unable to get DMI data: %d\n", ret);
+               pr_err("unable to get DMI data: %d\n", ret);
                thinkpad_acpi_module_exit();
                return ret;
        }
@@ -9051,16 +8961,14 @@ static int __init thinkpad_acpi_module_init(void)
 
        proc_dir = proc_mkdir(TPACPI_PROC_DIR, acpi_root_dir);
        if (!proc_dir) {
-               printk(TPACPI_ERR
-                      "unable to create proc dir " TPACPI_PROC_DIR);
+               pr_err("unable to create proc dir " TPACPI_PROC_DIR "\n");
                thinkpad_acpi_module_exit();
                return -ENODEV;
        }
 
        ret = platform_driver_register(&tpacpi_pdriver);
        if (ret) {
-               printk(TPACPI_ERR
-                      "unable to register main platform driver\n");
+               pr_err("unable to register main platform driver\n");
                thinkpad_acpi_module_exit();
                return ret;
        }
@@ -9068,8 +8976,7 @@ static int __init thinkpad_acpi_module_init(void)
 
        ret = platform_driver_register(&tpacpi_hwmon_pdriver);
        if (ret) {
-               printk(TPACPI_ERR
-                      "unable to register hwmon platform driver\n");
+               pr_err("unable to register hwmon platform driver\n");
                thinkpad_acpi_module_exit();
                return ret;
        }
@@ -9082,8 +8989,7 @@ static int __init thinkpad_acpi_module_init(void)
                                        &tpacpi_hwmon_pdriver.driver);
        }
        if (ret) {
-               printk(TPACPI_ERR
-                      "unable to create sysfs driver attributes\n");
+               pr_err("unable to create sysfs driver attributes\n");
                thinkpad_acpi_module_exit();
                return ret;
        }
@@ -9096,7 +9002,7 @@ static int __init thinkpad_acpi_module_init(void)
        if (IS_ERR(tpacpi_pdev)) {
                ret = PTR_ERR(tpacpi_pdev);
                tpacpi_pdev = NULL;
-               printk(TPACPI_ERR "unable to register platform device\n");
+               pr_err("unable to register platform device\n");
                thinkpad_acpi_module_exit();
                return ret;
        }
@@ -9106,16 +9012,14 @@ static int __init thinkpad_acpi_module_init(void)
        if (IS_ERR(tpacpi_sensors_pdev)) {
                ret = PTR_ERR(tpacpi_sensors_pdev);
                tpacpi_sensors_pdev = NULL;
-               printk(TPACPI_ERR
-                      "unable to register hwmon platform device\n");
+               pr_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(TPACPI_ERR
-                      "unable to create sysfs hwmon device attributes\n");
+               pr_err("unable to create sysfs hwmon device attributes\n");
                thinkpad_acpi_module_exit();
                return ret;
        }
@@ -9124,14 +9028,14 @@ static int __init thinkpad_acpi_module_init(void)
        if (IS_ERR(tpacpi_hwmon)) {
                ret = PTR_ERR(tpacpi_hwmon);
                tpacpi_hwmon = NULL;
-               printk(TPACPI_ERR "unable to register hwmon device\n");
+               pr_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(TPACPI_ERR "unable to allocate input device\n");
+               pr_err("unable to allocate input device\n");
                thinkpad_acpi_module_exit();
                return -ENOMEM;
        } else {
@@ -9163,7 +9067,7 @@ static int __init thinkpad_acpi_module_init(void)
 
        ret = input_register_device(tpacpi_inputdev);
        if (ret < 0) {
-               printk(TPACPI_ERR "unable to register input device\n");
+               pr_err("unable to register input device\n");
                thinkpad_acpi_module_exit();
                return ret;
        } else {
index 1d07d6d09f27a4f94c67de17b9c3cead101b0e84..4c20447ddbb73cfc572e7668f2fd6da431f34275 100644 (file)
@@ -194,7 +194,7 @@ static int __init topstar_laptop_init(void)
        if (ret < 0)
                return ret;
 
-       printk(KERN_INFO "Topstar Laptop ACPI extras driver loaded\n");
+       pr_info("ACPI extras driver loaded\n");
 
        return 0;
 }
index 63f42a22e10240a32d58c6f4bd1ce7ddc87428b6..cb009b2629eef532c444bf71ce1372106cfd9327 100644 (file)
@@ -35,6 +35,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define TOSHIBA_ACPI_VERSION   "0.19"
 #define PROC_INTERFACE_VERSION 1
 
@@ -60,11 +62,6 @@ MODULE_AUTHOR("John Belmonte");
 MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
 MODULE_LICENSE("GPL");
 
-#define MY_LOGPREFIX "toshiba_acpi: "
-#define MY_ERR KERN_ERR MY_LOGPREFIX
-#define MY_NOTICE KERN_NOTICE MY_LOGPREFIX
-#define MY_INFO KERN_INFO MY_LOGPREFIX
-
 /* Toshiba ACPI method paths */
 #define METHOD_LCD_BRIGHTNESS  "\\_SB_.PCI0.VGA_.LCD_._BCM"
 #define TOSH_INTERFACE_1       "\\_SB_.VALD"
@@ -301,7 +298,7 @@ static int toshiba_illumination_available(void)
        in[0] = 0xf100;
        status = hci_raw(in, out);
        if (ACPI_FAILURE(status)) {
-               printk(MY_INFO "Illumination device not available\n");
+               pr_info("Illumination device not available\n");
                return 0;
        }
        in[0] = 0xf400;
@@ -320,7 +317,7 @@ static void toshiba_illumination_set(struct led_classdev *cdev,
        in[0] = 0xf100;
        status = hci_raw(in, out);
        if (ACPI_FAILURE(status)) {
-               printk(MY_INFO "Illumination device not available\n");
+               pr_info("Illumination device not available\n");
                return;
        }
 
@@ -331,7 +328,7 @@ static void toshiba_illumination_set(struct led_classdev *cdev,
                in[2] = 1;
                status = hci_raw(in, out);
                if (ACPI_FAILURE(status)) {
-                       printk(MY_INFO "ACPI call for illumination failed.\n");
+                       pr_info("ACPI call for illumination failed\n");
                        return;
                }
        } else {
@@ -341,7 +338,7 @@ static void toshiba_illumination_set(struct led_classdev *cdev,
                in[2] = 0;
                status = hci_raw(in, out);
                if (ACPI_FAILURE(status)) {
-                       printk(MY_INFO "ACPI call for illumination failed.\n");
+                       pr_info("ACPI call for illumination failed.\n");
                        return;
                }
        }
@@ -364,7 +361,7 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
        in[0] = 0xf100;
        status = hci_raw(in, out);
        if (ACPI_FAILURE(status)) {
-               printk(MY_INFO "Illumination device not available\n");
+               pr_info("Illumination device not available\n");
                return LED_OFF;
        }
 
@@ -373,7 +370,7 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
        in[1] = 0x14e;
        status = hci_raw(in, out);
        if (ACPI_FAILURE(status)) {
-               printk(MY_INFO "ACPI call for illumination failed.\n");
+               pr_info("ACPI call for illumination failed.\n");
                return LED_OFF;
        }
 
@@ -517,7 +514,7 @@ static int lcd_proc_show(struct seq_file *m, void *v)
                seq_printf(m, "brightness_levels:       %d\n",
                             HCI_LCD_BRIGHTNESS_LEVELS);
        } else {
-               printk(MY_ERR "Error reading LCD brightness\n");
+               pr_err("Error reading LCD brightness\n");
        }
 
        return 0;
@@ -592,7 +589,7 @@ static int video_proc_show(struct seq_file *m, void *v)
                seq_printf(m, "crt_out:                 %d\n", is_crt);
                seq_printf(m, "tv_out:                  %d\n", is_tv);
        } else {
-               printk(MY_ERR "Error reading video out status\n");
+               pr_err("Error reading video out status\n");
        }
 
        return 0;
@@ -686,7 +683,7 @@ static int fan_proc_show(struct seq_file *m, void *v)
                seq_printf(m, "running:                 %d\n", (value > 0));
                seq_printf(m, "force_on:                %d\n", force_fan);
        } else {
-               printk(MY_ERR "Error reading fan status\n");
+               pr_err("Error reading fan status\n");
        }
 
        return 0;
@@ -750,9 +747,9 @@ static int keys_proc_show(struct seq_file *m, void *v)
                         * some machines where system events sporadically
                         * become disabled. */
                        hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
-                       printk(MY_NOTICE "Re-enabled hotkeys\n");
+                       pr_notice("Re-enabled hotkeys\n");
                } else {
-                       printk(MY_ERR "Error reading hotkey status\n");
+                       pr_err("Error reading hotkey status\n");
                        goto end;
                }
        }
@@ -863,7 +860,7 @@ static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
 
                        if (!sparse_keymap_report_event(toshiba_acpi.hotkey_dev,
                                                        value, 1, true)) {
-                               printk(MY_INFO "Unknown key %x\n",
+                               pr_info("Unknown key %x\n",
                                       value);
                        }
                } else if (hci_result == HCI_NOT_SUPPORTED) {
@@ -871,7 +868,7 @@ static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
                         * some machines where system events sporadically
                         * become disabled. */
                        hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
-                       printk(MY_NOTICE "Re-enabled hotkeys\n");
+                       pr_notice("Re-enabled hotkeys\n");
                }
        } while (hci_result != HCI_EMPTY);
 }
@@ -883,13 +880,13 @@ static int __init toshiba_acpi_setup_keyboard(char *device)
 
        status = acpi_get_handle(NULL, device, &toshiba_acpi.handle);
        if (ACPI_FAILURE(status)) {
-               printk(MY_INFO "Unable to get notification device\n");
+               pr_info("Unable to get notification device\n");
                return -ENODEV;
        }
 
        toshiba_acpi.hotkey_dev = input_allocate_device();
        if (!toshiba_acpi.hotkey_dev) {
-               printk(MY_INFO "Unable to register input device\n");
+               pr_info("Unable to register input device\n");
                return -ENOMEM;
        }
 
@@ -905,21 +902,21 @@ static int __init toshiba_acpi_setup_keyboard(char *device)
        status = acpi_install_notify_handler(toshiba_acpi.handle,
                                ACPI_DEVICE_NOTIFY, toshiba_acpi_notify, NULL);
        if (ACPI_FAILURE(status)) {
-               printk(MY_INFO "Unable to install hotkey notification\n");
+               pr_info("Unable to install hotkey notification\n");
                error = -ENODEV;
                goto err_free_keymap;
        }
 
        status = acpi_evaluate_object(toshiba_acpi.handle, "ENAB", NULL, NULL);
        if (ACPI_FAILURE(status)) {
-               printk(MY_INFO "Unable to enable hotkeys\n");
+               pr_info("Unable to enable hotkeys\n");
                error = -ENODEV;
                goto err_remove_notify;
        }
 
        error = input_register_device(toshiba_acpi.hotkey_dev);
        if (error) {
-               printk(MY_INFO "Unable to register input device\n");
+               pr_info("Unable to register input device\n");
                goto err_remove_notify;
        }
 
@@ -980,17 +977,17 @@ static int __init toshiba_acpi_init(void)
        if (is_valid_acpi_path(TOSH_INTERFACE_1 GHCI_METHOD)) {
                method_hci = TOSH_INTERFACE_1 GHCI_METHOD;
                if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_1))
-                       printk(MY_INFO "Unable to activate hotkeys\n");
+                       pr_info("Unable to activate hotkeys\n");
        } else if (is_valid_acpi_path(TOSH_INTERFACE_2 GHCI_METHOD)) {
                method_hci = TOSH_INTERFACE_2 GHCI_METHOD;
                if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_2))
-                       printk(MY_INFO "Unable to activate hotkeys\n");
+                       pr_info("Unable to activate hotkeys\n");
        } else
                return -ENODEV;
 
-       printk(MY_INFO "Toshiba Laptop ACPI Extras version %s\n",
+       pr_info("Toshiba Laptop ACPI Extras version %s\n",
               TOSHIBA_ACPI_VERSION);
-       printk(MY_INFO "    HCI method: %s\n", method_hci);
+       pr_info("    HCI method: %s\n", method_hci);
 
        mutex_init(&toshiba_acpi.mutex);
 
@@ -998,7 +995,7 @@ static int __init toshiba_acpi_init(void)
                                                              -1, NULL, 0);
        if (IS_ERR(toshiba_acpi.p_dev)) {
                ret = PTR_ERR(toshiba_acpi.p_dev);
-               printk(MY_ERR "unable to register platform device\n");
+               pr_err("unable to register platform device\n");
                toshiba_acpi.p_dev = NULL;
                toshiba_acpi_exit();
                return ret;
@@ -1028,7 +1025,7 @@ static int __init toshiba_acpi_init(void)
         if (IS_ERR(toshiba_backlight_device)) {
                ret = PTR_ERR(toshiba_backlight_device);
 
-               printk(KERN_ERR "Could not register toshiba backlight device\n");
+               pr_err("Could not register toshiba backlight device\n");
                toshiba_backlight_device = NULL;
                toshiba_acpi_exit();
                return ret;
@@ -1042,14 +1039,14 @@ static int __init toshiba_acpi_init(void)
                                                   &toshiba_rfk_ops,
                                                   &toshiba_acpi);
                if (!toshiba_acpi.bt_rfk) {
-                       printk(MY_ERR "unable to allocate rfkill device\n");
+                       pr_err("unable to allocate rfkill device\n");
                        toshiba_acpi_exit();
                        return -ENOMEM;
                }
 
                ret = rfkill_register(toshiba_acpi.bt_rfk);
                if (ret) {
-                       printk(MY_ERR "unable to register rfkill device\n");
+                       pr_err("unable to register rfkill device\n");
                        rfkill_destroy(toshiba_acpi.bt_rfk);
                        toshiba_acpi_exit();
                        return ret;
index 944068611919394eaa42c6337e96b2e1e02b9fee..5fb7186694df034f85d47fd6c3d5e8a03ac5a51b 100644 (file)
@@ -17,6 +17,8 @@
  * delivered.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -70,14 +72,13 @@ static int toshiba_bluetooth_enable(acpi_handle handle)
        if (!(result & 0x01))
                return 0;
 
-       printk(KERN_INFO "toshiba_bluetooth: Re-enabling Toshiba Bluetooth\n");
+       pr_info("Re-enabling Toshiba Bluetooth\n");
        res1 = acpi_evaluate_object(handle, "AUSB", NULL, NULL);
        res2 = acpi_evaluate_object(handle, "BTPO", NULL, NULL);
        if (!ACPI_FAILURE(res1) || !ACPI_FAILURE(res2))
                return 0;
 
-       printk(KERN_WARNING "toshiba_bluetooth: Failed to re-enable "
-              "Toshiba Bluetooth\n");
+       pr_warn("Failed to re-enable Toshiba Bluetooth\n");
 
        return -ENODEV;
 }
@@ -107,8 +108,8 @@ static int toshiba_bt_rfkill_add(struct acpi_device *device)
                                       &bt_present);
 
        if (!ACPI_FAILURE(status) && bt_present) {
-               printk(KERN_INFO "Detected Toshiba ACPI Bluetooth device - "
-                     "installing RFKill handler\n");
+               pr_info("Detected Toshiba ACPI Bluetooth device - "
+                       "installing RFKill handler\n");
                result = toshiba_bluetooth_enable(device->handle);
        }
 
index 05cc79672a8baf3e32b79db9400a950e4c6dcd81..f23d5a84e7b1b61108bdb651b5a240bed3ee4ed0 100644 (file)
@@ -486,16 +486,16 @@ static void wmi_dump_wdg(const struct guid_block *g)
        pr_info("\tnotify_id: %02X\n", g->notify_id);
        pr_info("\treserved: %02X\n", g->reserved);
        pr_info("\tinstance_count: %d\n", g->instance_count);
-       pr_info("\tflags: %#x ", g->flags);
+       pr_info("\tflags: %#x", g->flags);
        if (g->flags) {
                if (g->flags & ACPI_WMI_EXPENSIVE)
-                       pr_cont("ACPI_WMI_EXPENSIVE ");
+                       pr_cont(" ACPI_WMI_EXPENSIVE");
                if (g->flags & ACPI_WMI_METHOD)
-                       pr_cont("ACPI_WMI_METHOD ");
+                       pr_cont(" ACPI_WMI_METHOD");
                if (g->flags & ACPI_WMI_STRING)
-                       pr_cont("ACPI_WMI_STRING ");
+                       pr_cont(" ACPI_WMI_STRING");
                if (g->flags & ACPI_WMI_EVENT)
-                       pr_cont("ACPI_WMI_EVENT ");
+                       pr_cont(" ACPI_WMI_EVENT");
        }
        pr_cont("\n");
 
index c1372ed9d2e95c1744c161f50ae6ce92bc27797c..fad153dc0355e33db828fe6d3e12ef97bea2b429 100644 (file)
@@ -11,6 +11,8 @@
  *  your option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -20,7 +22,6 @@
 #include <acpi/acpi_drivers.h>
 
 #define MODULE_NAME "xo15-ebook"
-#define PREFIX MODULE_NAME ": "
 
 #define XO15_EBOOK_CLASS               MODULE_NAME
 #define XO15_EBOOK_TYPE_UNKNOWN        0x00
@@ -105,7 +106,7 @@ static int ebook_switch_add(struct acpi_device *device)
        class = acpi_device_class(device);
 
        if (strcmp(hid, XO15_EBOOK_HID)) {
-               printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", hid);
+               pr_err("Unsupported hid [%s]\n", hid);
                error = -ENODEV;
                goto err_free_input;
        }
index 52a462fc6b84467f3aafca8d09cf5630b7d500bd..e57b50b385655d24eb5aeb94866a68cef42813e2 100644 (file)
@@ -68,6 +68,13 @@ config BATTERY_DS2760
        help
          Say Y here to enable support for batteries with ds2760 chip.
 
+config BATTERY_DS2780
+       tristate "DS2780 battery driver"
+       select W1
+       select W1_SLAVE_DS2780
+       help
+         Say Y here to enable support for batteries with ds2780 chip.
+
 config BATTERY_DS2782
        tristate "DS2782/DS2786 standalone gas-gauge"
        depends on I2C
@@ -203,6 +210,15 @@ config CHARGER_ISP1704
          Say Y to enable support for USB Charger Detection with
          ISP1707/ISP1704 USB transceivers.
 
+config CHARGER_MAX8903
+       tristate "MAX8903 Battery DC-DC Charger for USB and Adapter Power"
+       depends on GENERIC_HARDIRQS
+       help
+         Say Y to enable support for the MAX8903 DC-DC charger and sysfs.
+         The driver supports controlling charger-enable and current-limit
+         pins based on the status of charger connections with interrupt
+         handlers.
+
 config CHARGER_TWL4030
        tristate "OMAP TWL4030 BCI charger driver"
        depends on TWL4030_CORE
index 8385bfae872836bf367e937b1f627cbe82c39421..009a90fa8ac9538e320ec1f0f9196b44e87054f1 100644 (file)
@@ -15,6 +15,7 @@ obj-$(CONFIG_WM8350_POWER)    += wm8350_power.o
 obj-$(CONFIG_TEST_POWER)       += test_power.o
 
 obj-$(CONFIG_BATTERY_DS2760)   += ds2760_battery.o
+obj-$(CONFIG_BATTERY_DS2780)   += ds2780_battery.o
 obj-$(CONFIG_BATTERY_DS2782)   += ds2782_battery.o
 obj-$(CONFIG_BATTERY_PMU)      += pmu_battery.o
 obj-$(CONFIG_BATTERY_OLPC)     += olpc_battery.o
@@ -32,5 +33,6 @@ obj-$(CONFIG_CHARGER_PCF50633)        += pcf50633-charger.o
 obj-$(CONFIG_BATTERY_JZ4740)   += jz4740-battery.o
 obj-$(CONFIG_BATTERY_INTEL_MID)        += intel_mid_battery.o
 obj-$(CONFIG_CHARGER_ISP1704)  += isp1704_charger.o
+obj-$(CONFIG_CHARGER_MAX8903)  += max8903_charger.o
 obj-$(CONFIG_CHARGER_TWL4030)  += twl4030_charger.o
 obj-$(CONFIG_CHARGER_GPIO)     += gpio-charger.o
index 59e68dbd028b31e4bf8e17f5e33bc19e0deb7492..bb16f5b7e167490519d2793cbaa1546192e447f5 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it>
  * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it>
  * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de>
+ * Copyright (C) 2011 Pali Rohár <pali.rohar@gmail.com>
  *
  * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc.
  *
@@ -76,7 +77,7 @@ struct bq27x00_reg_cache {
        int time_to_empty_avg;
        int time_to_full;
        int charge_full;
-       int charge_counter;
+       int cycle_count;
        int capacity;
        int flags;
 
@@ -115,7 +116,7 @@ static enum power_supply_property bq27x00_battery_props[] = {
        POWER_SUPPLY_PROP_CHARGE_FULL,
        POWER_SUPPLY_PROP_CHARGE_NOW,
        POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
-       POWER_SUPPLY_PROP_CHARGE_COUNTER,
+       POWER_SUPPLY_PROP_CYCLE_COUNT,
        POWER_SUPPLY_PROP_ENERGY_NOW,
 };
 
@@ -267,7 +268,7 @@ static void bq27x00_update(struct bq27x00_device_info *di)
                cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP);
                cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF);
                cache.charge_full = bq27x00_battery_read_lmd(di);
-               cache.charge_counter = bq27x00_battery_read_cyct(di);
+               cache.cycle_count = bq27x00_battery_read_cyct(di);
 
                if (!is_bq27500)
                        cache.current_now = bq27x00_read(di, BQ27x00_REG_AI, false);
@@ -496,8 +497,8 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
                ret = bq27x00_simple_value(di->charge_design_full, val);
                break;
-       case POWER_SUPPLY_PROP_CHARGE_COUNTER:
-               ret = bq27x00_simple_value(di->cache.charge_counter, val);
+       case POWER_SUPPLY_PROP_CYCLE_COUNT:
+               ret = bq27x00_simple_value(di->cache.cycle_count, val);
                break;
        case POWER_SUPPLY_PROP_ENERGY_NOW:
                ret = bq27x00_battery_energy(di, val);
index e534290f32561d6d8322375f6baccf086f0c6de1..f2c9cc33c0f9f795a81125368c1dc758c2dd81c8 100644 (file)
@@ -86,7 +86,11 @@ static int rated_capacities[] = {
        920,    /* NEC */
        1440,   /* Samsung */
        1440,   /* BYD */
+#ifdef CONFIG_MACH_H4700
+       1800,   /* HP iPAQ hx4700 3.7V 1800mAh (359113-001) */
+#else
        1440,   /* Lishen */
+#endif
        1440,   /* NEC */
        2880,   /* Samsung */
        2880,   /* BYD */
@@ -186,7 +190,7 @@ static int ds2760_battery_read_status(struct ds2760_device_info *di)
 
        scale[0] = di->full_active_uAh;
        for (i = 1; i < 5; i++)
-               scale[i] = scale[i - 1] + di->raw[DS2760_ACTIVE_FULL + 2 + i];
+               scale[i] = scale[i - 1] + di->raw[DS2760_ACTIVE_FULL + 1 + i];
 
        di->full_active_uAh = battery_interpolate(scale, di->temp_C / 10);
        di->full_active_uAh *= 1000; /* convert to ÂµAh */
diff --git a/drivers/power/ds2780_battery.c b/drivers/power/ds2780_battery.c
new file mode 100644 (file)
index 0000000..1fefe82
--- /dev/null
@@ -0,0 +1,853 @@
+/*
+ * 1-wire client/driver for the Maxim/Dallas DS2780 Stand-Alone Fuel Gauge IC
+ *
+ * Copyright (C) 2010 Indesign, LLC
+ *
+ * Author: Clifton Barnes <cabarnes@indesign-llc.com>
+ *
+ * Based on ds2760_battery and ds2782_battery drivers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/param.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/idr.h>
+
+#include "../w1/w1.h"
+#include "../w1/slaves/w1_ds2780.h"
+
+/* Current unit measurement in uA for a 1 milli-ohm sense resistor */
+#define DS2780_CURRENT_UNITS   1563
+/* Charge unit measurement in uAh for a 1 milli-ohm sense resistor */
+#define DS2780_CHARGE_UNITS            6250
+/* Number of bytes in user EEPROM space */
+#define DS2780_USER_EEPROM_SIZE                (DS2780_EEPROM_BLOCK0_END - \
+                                       DS2780_EEPROM_BLOCK0_START + 1)
+/* Number of bytes in parameter EEPROM space */
+#define DS2780_PARAM_EEPROM_SIZE       (DS2780_EEPROM_BLOCK1_END - \
+                                       DS2780_EEPROM_BLOCK1_START + 1)
+
+struct ds2780_device_info {
+       struct device *dev;
+       struct power_supply bat;
+       struct device *w1_dev;
+};
+
+enum current_types {
+       CURRENT_NOW,
+       CURRENT_AVG,
+};
+
+static const char model[] = "DS2780";
+static const char manufacturer[] = "Maxim/Dallas";
+
+static inline struct ds2780_device_info *to_ds2780_device_info(
+       struct power_supply *psy)
+{
+       return container_of(psy, struct ds2780_device_info, bat);
+}
+
+static inline struct power_supply *to_power_supply(struct device *dev)
+{
+       return dev_get_drvdata(dev);
+}
+
+static inline int ds2780_read8(struct device *dev, u8 *val, int addr)
+{
+       return w1_ds2780_io(dev, val, addr, sizeof(u8), 0);
+}
+
+static int ds2780_read16(struct device *dev, s16 *val, int addr)
+{
+       int ret;
+       u8 raw[2];
+
+       ret = w1_ds2780_io(dev, raw, addr, sizeof(u8) * 2, 0);
+       if (ret < 0)
+               return ret;
+
+       *val = (raw[0] << 8) | raw[1];
+
+       return 0;
+}
+
+static inline int ds2780_read_block(struct device *dev, u8 *val, int addr,
+       size_t count)
+{
+       return w1_ds2780_io(dev, val, addr, count, 0);
+}
+
+static inline int ds2780_write(struct device *dev, u8 *val, int addr,
+       size_t count)
+{
+       return w1_ds2780_io(dev, val, addr, count, 1);
+}
+
+static inline int ds2780_store_eeprom(struct device *dev, int addr)
+{
+       return w1_ds2780_eeprom_cmd(dev, addr, W1_DS2780_COPY_DATA);
+}
+
+static inline int ds2780_recall_eeprom(struct device *dev, int addr)
+{
+       return w1_ds2780_eeprom_cmd(dev, addr, W1_DS2780_RECALL_DATA);
+}
+
+static int ds2780_save_eeprom(struct ds2780_device_info *dev_info, int reg)
+{
+       int ret;
+
+       ret = ds2780_store_eeprom(dev_info->w1_dev, reg);
+       if (ret < 0)
+               return ret;
+
+       ret = ds2780_recall_eeprom(dev_info->w1_dev, reg);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+/* Set sense resistor value in mhos */
+static int ds2780_set_sense_register(struct ds2780_device_info *dev_info,
+       u8 conductance)
+{
+       int ret;
+
+       ret = ds2780_write(dev_info->w1_dev, &conductance,
+                               DS2780_RSNSP_REG, sizeof(u8));
+       if (ret < 0)
+               return ret;
+
+       return ds2780_save_eeprom(dev_info, DS2780_RSNSP_REG);
+}
+
+/* Get RSGAIN value from 0 to 1.999 in steps of 0.001 */
+static int ds2780_get_rsgain_register(struct ds2780_device_info *dev_info,
+       u16 *rsgain)
+{
+       return ds2780_read16(dev_info->w1_dev, rsgain, DS2780_RSGAIN_MSB_REG);
+}
+
+/* Set RSGAIN value from 0 to 1.999 in steps of 0.001 */
+static int ds2780_set_rsgain_register(struct ds2780_device_info *dev_info,
+       u16 rsgain)
+{
+       int ret;
+       u8 raw[] = {rsgain >> 8, rsgain & 0xFF};
+
+       ret = ds2780_write(dev_info->w1_dev, raw,
+                               DS2780_RSGAIN_MSB_REG, sizeof(u8) * 2);
+       if (ret < 0)
+               return ret;
+
+       return ds2780_save_eeprom(dev_info, DS2780_RSGAIN_MSB_REG);
+}
+
+static int ds2780_get_voltage(struct ds2780_device_info *dev_info,
+       int *voltage_uV)
+{
+       int ret;
+       s16 voltage_raw;
+
+       /*
+        * The voltage value is located in 10 bits across the voltage MSB
+        * and LSB registers in two's compliment form
+        * Sign bit of the voltage value is in bit 7 of the voltage MSB register
+        * Bits 9 - 3 of the voltage value are in bits 6 - 0 of the
+        * voltage MSB register
+        * Bits 2 - 0 of the voltage value are in bits 7 - 5 of the
+        * voltage LSB register
+        */
+       ret = ds2780_read16(dev_info->w1_dev, &voltage_raw,
+                               DS2780_VOLT_MSB_REG);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * DS2780 reports voltage in units of 4.88mV, but the battery class
+        * reports in units of uV, so convert by multiplying by 4880.
+        */
+       *voltage_uV = (voltage_raw / 32) * 4880;
+       return 0;
+}
+
+static int ds2780_get_temperature(struct ds2780_device_info *dev_info,
+       int *temperature)
+{
+       int ret;
+       s16 temperature_raw;
+
+       /*
+        * The temperature value is located in 10 bits across the temperature
+        * MSB and LSB registers in two's compliment form
+        * Sign bit of the temperature value is in bit 7 of the temperature
+        * MSB register
+        * Bits 9 - 3 of the temperature value are in bits 6 - 0 of the
+        * temperature MSB register
+        * Bits 2 - 0 of the temperature value are in bits 7 - 5 of the
+        * temperature LSB register
+        */
+       ret = ds2780_read16(dev_info->w1_dev, &temperature_raw,
+                               DS2780_TEMP_MSB_REG);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Temperature is measured in units of 0.125 degrees celcius, the
+        * power_supply class measures temperature in tenths of degrees
+        * celsius. The temperature value is stored as a 10 bit number, plus
+        * sign in the upper bits of a 16 bit register.
+        */
+       *temperature = ((temperature_raw / 32) * 125) / 100;
+       return 0;
+}
+
+static int ds2780_get_current(struct ds2780_device_info *dev_info,
+       enum current_types type, int *current_uA)
+{
+       int ret, sense_res;
+       s16 current_raw;
+       u8 sense_res_raw, reg_msb;
+
+       /*
+        * The units of measurement for current are dependent on the value of
+        * the sense resistor.
+        */
+       ret = ds2780_read8(dev_info->w1_dev, &sense_res_raw, DS2780_RSNSP_REG);
+       if (ret < 0)
+               return ret;
+
+       if (sense_res_raw == 0) {
+               dev_err(dev_info->dev, "sense resistor value is 0\n");
+               return -ENXIO;
+       }
+       sense_res = 1000 / sense_res_raw;
+
+       if (type == CURRENT_NOW)
+               reg_msb = DS2780_CURRENT_MSB_REG;
+       else if (type == CURRENT_AVG)
+               reg_msb = DS2780_IAVG_MSB_REG;
+       else
+               return -EINVAL;
+
+       /*
+        * The current value is located in 16 bits across the current MSB
+        * and LSB registers in two's compliment form
+        * Sign bit of the current value is in bit 7 of the current MSB register
+        * Bits 14 - 8 of the current value are in bits 6 - 0 of the current
+        * MSB register
+        * Bits 7 - 0 of the current value are in bits 7 - 0 of the current
+        * LSB register
+        */
+       ret = ds2780_read16(dev_info->w1_dev, &current_raw, reg_msb);
+       if (ret < 0)
+               return ret;
+
+       *current_uA = current_raw * (DS2780_CURRENT_UNITS / sense_res);
+       return 0;
+}
+
+static int ds2780_get_accumulated_current(struct ds2780_device_info *dev_info,
+       int *accumulated_current)
+{
+       int ret, sense_res;
+       s16 current_raw;
+       u8 sense_res_raw;
+
+       /*
+        * The units of measurement for accumulated current are dependent on
+        * the value of the sense resistor.
+        */
+       ret = ds2780_read8(dev_info->w1_dev, &sense_res_raw, DS2780_RSNSP_REG);
+       if (ret < 0)
+               return ret;
+
+       if (sense_res_raw == 0) {
+               dev_err(dev_info->dev, "sense resistor value is 0\n");
+               return -ENXIO;
+       }
+       sense_res = 1000 / sense_res_raw;
+
+       /*
+        * The ACR value is located in 16 bits across the ACR MSB and
+        * LSB registers
+        * Bits 15 - 8 of the ACR value are in bits 7 - 0 of the ACR
+        * MSB register
+        * Bits 7 - 0 of the ACR value are in bits 7 - 0 of the ACR
+        * LSB register
+        */
+       ret = ds2780_read16(dev_info->w1_dev, &current_raw, DS2780_ACR_MSB_REG);
+       if (ret < 0)
+               return ret;
+
+       *accumulated_current = current_raw * (DS2780_CHARGE_UNITS / sense_res);
+       return 0;
+}
+
+static int ds2780_get_capacity(struct ds2780_device_info *dev_info,
+       int *capacity)
+{
+       int ret;
+       u8 raw;
+
+       ret = ds2780_read8(dev_info->w1_dev, &raw, DS2780_RARC_REG);
+       if (ret < 0)
+               return ret;
+
+       *capacity = raw;
+       return raw;
+}
+
+static int ds2780_get_status(struct ds2780_device_info *dev_info, int *status)
+{
+       int ret, current_uA, capacity;
+
+       ret = ds2780_get_current(dev_info, CURRENT_NOW, &current_uA);
+       if (ret < 0)
+               return ret;
+
+       ret = ds2780_get_capacity(dev_info, &capacity);
+       if (ret < 0)
+               return ret;
+
+       if (capacity == 100)
+               *status = POWER_SUPPLY_STATUS_FULL;
+       else if (current_uA == 0)
+               *status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+       else if (current_uA < 0)
+               *status = POWER_SUPPLY_STATUS_DISCHARGING;
+       else
+               *status = POWER_SUPPLY_STATUS_CHARGING;
+
+       return 0;
+}
+
+static int ds2780_get_charge_now(struct ds2780_device_info *dev_info,
+       int *charge_now)
+{
+       int ret;
+       u16 charge_raw;
+
+       /*
+        * The RAAC value is located in 16 bits across the RAAC MSB and
+        * LSB registers
+        * Bits 15 - 8 of the RAAC value are in bits 7 - 0 of the RAAC
+        * MSB register
+        * Bits 7 - 0 of the RAAC value are in bits 7 - 0 of the RAAC
+        * LSB register
+        */
+       ret = ds2780_read16(dev_info->w1_dev, &charge_raw, DS2780_RAAC_MSB_REG);
+       if (ret < 0)
+               return ret;
+
+       *charge_now = charge_raw * 1600;
+       return 0;
+}
+
+static int ds2780_get_control_register(struct ds2780_device_info *dev_info,
+       u8 *control_reg)
+{
+       return ds2780_read8(dev_info->w1_dev, control_reg, DS2780_CONTROL_REG);
+}
+
+static int ds2780_set_control_register(struct ds2780_device_info *dev_info,
+       u8 control_reg)
+{
+       int ret;
+
+       ret = ds2780_write(dev_info->w1_dev, &control_reg,
+                               DS2780_CONTROL_REG, sizeof(u8));
+       if (ret < 0)
+               return ret;
+
+       return ds2780_save_eeprom(dev_info, DS2780_CONTROL_REG);
+}
+
+static int ds2780_battery_get_property(struct power_supply *psy,
+       enum power_supply_property psp,
+       union power_supply_propval *val)
+{
+       int ret = 0;
+       struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               ret = ds2780_get_voltage(dev_info, &val->intval);
+               break;
+
+       case POWER_SUPPLY_PROP_TEMP:
+               ret = ds2780_get_temperature(dev_info, &val->intval);
+               break;
+
+       case POWER_SUPPLY_PROP_MODEL_NAME:
+               val->strval = model;
+               break;
+
+       case POWER_SUPPLY_PROP_MANUFACTURER:
+               val->strval = manufacturer;
+               break;
+
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+               ret = ds2780_get_current(dev_info, CURRENT_NOW, &val->intval);
+               break;
+
+       case POWER_SUPPLY_PROP_CURRENT_AVG:
+               ret = ds2780_get_current(dev_info, CURRENT_AVG, &val->intval);
+               break;
+
+       case POWER_SUPPLY_PROP_STATUS:
+               ret = ds2780_get_status(dev_info, &val->intval);
+               break;
+
+       case POWER_SUPPLY_PROP_CAPACITY:
+               ret = ds2780_get_capacity(dev_info, &val->intval);
+               break;
+
+       case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+               ret = ds2780_get_accumulated_current(dev_info, &val->intval);
+               break;
+
+       case POWER_SUPPLY_PROP_CHARGE_NOW:
+               ret = ds2780_get_charge_now(dev_info, &val->intval);
+               break;
+
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static enum power_supply_property ds2780_battery_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_TEMP,
+       POWER_SUPPLY_PROP_MODEL_NAME,
+       POWER_SUPPLY_PROP_MANUFACTURER,
+       POWER_SUPPLY_PROP_CURRENT_NOW,
+       POWER_SUPPLY_PROP_CURRENT_AVG,
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_CHARGE_COUNTER,
+       POWER_SUPPLY_PROP_CHARGE_NOW,
+};
+
+static ssize_t ds2780_get_pmod_enabled(struct device *dev,
+       struct device_attribute *attr,
+       char *buf)
+{
+       int ret;
+       u8 control_reg;
+       struct power_supply *psy = to_power_supply(dev);
+       struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+       /* Get power mode */
+       ret = ds2780_get_control_register(dev_info, &control_reg);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%d\n",
+                !!(control_reg & DS2780_CONTROL_REG_PMOD));
+}
+
+static ssize_t ds2780_set_pmod_enabled(struct device *dev,
+       struct device_attribute *attr,
+       const char *buf,
+       size_t count)
+{
+       int ret;
+       u8 control_reg, new_setting;
+       struct power_supply *psy = to_power_supply(dev);
+       struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+       /* Set power mode */
+       ret = ds2780_get_control_register(dev_info, &control_reg);
+       if (ret < 0)
+               return ret;
+
+       ret = kstrtou8(buf, 0, &new_setting);
+       if (ret < 0)
+               return ret;
+
+       if ((new_setting != 0) && (new_setting != 1)) {
+               dev_err(dev_info->dev, "Invalid pmod setting (0 or 1)\n");
+               return -EINVAL;
+       }
+
+       if (new_setting)
+               control_reg |= DS2780_CONTROL_REG_PMOD;
+       else
+               control_reg &= ~DS2780_CONTROL_REG_PMOD;
+
+       ret = ds2780_set_control_register(dev_info, control_reg);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static ssize_t ds2780_get_sense_resistor_value(struct device *dev,
+       struct device_attribute *attr,
+       char *buf)
+{
+       int ret;
+       u8 sense_resistor;
+       struct power_supply *psy = to_power_supply(dev);
+       struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+       ret = ds2780_read8(dev_info->w1_dev, &sense_resistor, DS2780_RSNSP_REG);
+       if (ret < 0)
+               return ret;
+
+       ret = sprintf(buf, "%d\n", sense_resistor);
+       return ret;
+}
+
+static ssize_t ds2780_set_sense_resistor_value(struct device *dev,
+       struct device_attribute *attr,
+       const char *buf,
+       size_t count)
+{
+       int ret;
+       u8 new_setting;
+       struct power_supply *psy = to_power_supply(dev);
+       struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+       ret = kstrtou8(buf, 0, &new_setting);
+       if (ret < 0)
+               return ret;
+
+       ret = ds2780_set_sense_register(dev_info, new_setting);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static ssize_t ds2780_get_rsgain_setting(struct device *dev,
+       struct device_attribute *attr,
+       char *buf)
+{
+       int ret;
+       u16 rsgain;
+       struct power_supply *psy = to_power_supply(dev);
+       struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+       ret = ds2780_get_rsgain_register(dev_info, &rsgain);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%d\n", rsgain);
+}
+
+static ssize_t ds2780_set_rsgain_setting(struct device *dev,
+       struct device_attribute *attr,
+       const char *buf,
+       size_t count)
+{
+       int ret;
+       u16 new_setting;
+       struct power_supply *psy = to_power_supply(dev);
+       struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+       ret = kstrtou16(buf, 0, &new_setting);
+       if (ret < 0)
+               return ret;
+
+       /* Gain can only be from 0 to 1.999 in steps of .001 */
+       if (new_setting > 1999) {
+               dev_err(dev_info->dev, "Invalid rsgain setting (0 - 1999)\n");
+               return -EINVAL;
+       }
+
+       ret = ds2780_set_rsgain_register(dev_info, new_setting);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static ssize_t ds2780_get_pio_pin(struct device *dev,
+       struct device_attribute *attr,
+       char *buf)
+{
+       int ret;
+       u8 sfr;
+       struct power_supply *psy = to_power_supply(dev);
+       struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+       ret = ds2780_read8(dev_info->w1_dev, &sfr, DS2780_SFR_REG);
+       if (ret < 0)
+               return ret;
+
+       ret = sprintf(buf, "%d\n", sfr & DS2780_SFR_REG_PIOSC);
+       return ret;
+}
+
+static ssize_t ds2780_set_pio_pin(struct device *dev,
+       struct device_attribute *attr,
+       const char *buf,
+       size_t count)
+{
+       int ret;
+       u8 new_setting;
+       struct power_supply *psy = to_power_supply(dev);
+       struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+       ret = kstrtou8(buf, 0, &new_setting);
+       if (ret < 0)
+               return ret;
+
+       if ((new_setting != 0) && (new_setting != 1)) {
+               dev_err(dev_info->dev, "Invalid pio_pin setting (0 or 1)\n");
+               return -EINVAL;
+       }
+
+       ret = ds2780_write(dev_info->w1_dev, &new_setting,
+                               DS2780_SFR_REG, sizeof(u8));
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static ssize_t ds2780_read_param_eeprom_bin(struct file *filp,
+                               struct kobject *kobj,
+                               struct bin_attribute *bin_attr,
+                               char *buf, loff_t off, size_t count)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct power_supply *psy = to_power_supply(dev);
+       struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+       count = min_t(loff_t, count,
+               DS2780_EEPROM_BLOCK1_END -
+               DS2780_EEPROM_BLOCK1_START + 1 - off);
+
+       return ds2780_read_block(dev_info->w1_dev, buf,
+                               DS2780_EEPROM_BLOCK1_START + off, count);
+}
+
+static ssize_t ds2780_write_param_eeprom_bin(struct file *filp,
+                               struct kobject *kobj,
+                               struct bin_attribute *bin_attr,
+                               char *buf, loff_t off, size_t count)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct power_supply *psy = to_power_supply(dev);
+       struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+       int ret;
+
+       count = min_t(loff_t, count,
+               DS2780_EEPROM_BLOCK1_END -
+               DS2780_EEPROM_BLOCK1_START + 1 - off);
+
+       ret = ds2780_write(dev_info->w1_dev, buf,
+                               DS2780_EEPROM_BLOCK1_START + off, count);
+       if (ret < 0)
+               return ret;
+
+       ret = ds2780_save_eeprom(dev_info, DS2780_EEPROM_BLOCK1_START);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static struct bin_attribute ds2780_param_eeprom_bin_attr = {
+       .attr = {
+               .name = "param_eeprom",
+               .mode = S_IRUGO | S_IWUSR,
+       },
+       .size = DS2780_EEPROM_BLOCK1_END - DS2780_EEPROM_BLOCK1_START + 1,
+       .read = ds2780_read_param_eeprom_bin,
+       .write = ds2780_write_param_eeprom_bin,
+};
+
+static ssize_t ds2780_read_user_eeprom_bin(struct file *filp,
+                               struct kobject *kobj,
+                               struct bin_attribute *bin_attr,
+                               char *buf, loff_t off, size_t count)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct power_supply *psy = to_power_supply(dev);
+       struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+       count = min_t(loff_t, count,
+               DS2780_EEPROM_BLOCK0_END -
+               DS2780_EEPROM_BLOCK0_START + 1 - off);
+
+       return ds2780_read_block(dev_info->w1_dev, buf,
+                               DS2780_EEPROM_BLOCK0_START + off, count);
+
+}
+
+static ssize_t ds2780_write_user_eeprom_bin(struct file *filp,
+                               struct kobject *kobj,
+                               struct bin_attribute *bin_attr,
+                               char *buf, loff_t off, size_t count)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct power_supply *psy = to_power_supply(dev);
+       struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+       int ret;
+
+       count = min_t(loff_t, count,
+               DS2780_EEPROM_BLOCK0_END -
+               DS2780_EEPROM_BLOCK0_START + 1 - off);
+
+       ret = ds2780_write(dev_info->w1_dev, buf,
+                               DS2780_EEPROM_BLOCK0_START + off, count);
+       if (ret < 0)
+               return ret;
+
+       ret = ds2780_save_eeprom(dev_info, DS2780_EEPROM_BLOCK0_START);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static struct bin_attribute ds2780_user_eeprom_bin_attr = {
+       .attr = {
+               .name = "user_eeprom",
+               .mode = S_IRUGO | S_IWUSR,
+       },
+       .size = DS2780_EEPROM_BLOCK0_END - DS2780_EEPROM_BLOCK0_START + 1,
+       .read = ds2780_read_user_eeprom_bin,
+       .write = ds2780_write_user_eeprom_bin,
+};
+
+static DEVICE_ATTR(pmod_enabled, S_IRUGO | S_IWUSR, ds2780_get_pmod_enabled,
+       ds2780_set_pmod_enabled);
+static DEVICE_ATTR(sense_resistor_value, S_IRUGO | S_IWUSR,
+       ds2780_get_sense_resistor_value, ds2780_set_sense_resistor_value);
+static DEVICE_ATTR(rsgain_setting, S_IRUGO | S_IWUSR, ds2780_get_rsgain_setting,
+       ds2780_set_rsgain_setting);
+static DEVICE_ATTR(pio_pin, S_IRUGO | S_IWUSR, ds2780_get_pio_pin,
+       ds2780_set_pio_pin);
+
+
+static struct attribute *ds2780_attributes[] = {
+       &dev_attr_pmod_enabled.attr,
+       &dev_attr_sense_resistor_value.attr,
+       &dev_attr_rsgain_setting.attr,
+       &dev_attr_pio_pin.attr,
+       NULL
+};
+
+static const struct attribute_group ds2780_attr_group = {
+       .attrs = ds2780_attributes,
+};
+
+static int __devinit ds2780_battery_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct ds2780_device_info *dev_info;
+
+       dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL);
+       if (!dev_info) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       platform_set_drvdata(pdev, dev_info);
+
+       dev_info->dev                   = &pdev->dev;
+       dev_info->w1_dev                = pdev->dev.parent;
+       dev_info->bat.name              = dev_name(&pdev->dev);
+       dev_info->bat.type              = POWER_SUPPLY_TYPE_BATTERY;
+       dev_info->bat.properties        = ds2780_battery_props;
+       dev_info->bat.num_properties    = ARRAY_SIZE(ds2780_battery_props);
+       dev_info->bat.get_property      = ds2780_battery_get_property;
+
+       ret = power_supply_register(&pdev->dev, &dev_info->bat);
+       if (ret) {
+               dev_err(dev_info->dev, "failed to register battery\n");
+               goto fail_free_info;
+       }
+
+       ret = sysfs_create_group(&dev_info->bat.dev->kobj, &ds2780_attr_group);
+       if (ret) {
+               dev_err(dev_info->dev, "failed to create sysfs group\n");
+               goto fail_unregister;
+       }
+
+       ret = sysfs_create_bin_file(&dev_info->bat.dev->kobj,
+                                       &ds2780_param_eeprom_bin_attr);
+       if (ret) {
+               dev_err(dev_info->dev,
+                               "failed to create param eeprom bin file");
+               goto fail_remove_group;
+       }
+
+       ret = sysfs_create_bin_file(&dev_info->bat.dev->kobj,
+                                       &ds2780_user_eeprom_bin_attr);
+       if (ret) {
+               dev_err(dev_info->dev,
+                               "failed to create user eeprom bin file");
+               goto fail_remove_bin_file;
+       }
+
+       return 0;
+
+fail_remove_bin_file:
+       sysfs_remove_bin_file(&dev_info->bat.dev->kobj,
+                               &ds2780_param_eeprom_bin_attr);
+fail_remove_group:
+       sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2780_attr_group);
+fail_unregister:
+       power_supply_unregister(&dev_info->bat);
+fail_free_info:
+       kfree(dev_info);
+fail:
+       return ret;
+}
+
+static int __devexit ds2780_battery_remove(struct platform_device *pdev)
+{
+       struct ds2780_device_info *dev_info = platform_get_drvdata(pdev);
+
+       /* remove attributes */
+       sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2780_attr_group);
+
+       power_supply_unregister(&dev_info->bat);
+
+       kfree(dev_info);
+       return 0;
+}
+
+MODULE_ALIAS("platform:ds2780-battery");
+
+static struct platform_driver ds2780_battery_driver = {
+       .driver = {
+               .name = "ds2780-battery",
+       },
+       .probe    = ds2780_battery_probe,
+       .remove   = ds2780_battery_remove,
+};
+
+static int __init ds2780_battery_init(void)
+{
+       return platform_driver_register(&ds2780_battery_driver);
+}
+
+static void __exit ds2780_battery_exit(void)
+{
+       platform_driver_unregister(&ds2780_battery_driver);
+}
+
+module_init(ds2780_battery_init);
+module_exit(ds2780_battery_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Clifton Barnes <cabarnes@indesign-llc.com>");
+MODULE_DESCRIPTION("Maxim/Dallas DS2780 Stand-Alone Fuel Gauage IC driver");
index 25b88ac1d44c78eb3ff5258b05f0c68965dabdcb..718f2c537827a5a38ae90617bc91efb3eba9c8e0 100644 (file)
@@ -161,12 +161,27 @@ static int __devexit gpio_charger_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int gpio_charger_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct gpio_charger *gpio_charger = platform_get_drvdata(pdev);
+
+       power_supply_changed(&gpio_charger->charger);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(gpio_charger_pm_ops, NULL, gpio_charger_resume);
+
 static struct platform_driver gpio_charger_driver = {
        .probe = gpio_charger_probe,
        .remove = __devexit_p(gpio_charger_remove),
        .driver = {
                .name = "gpio-charger",
                .owner = THIS_MODULE,
+               .pm = &gpio_charger_pm_ops,
        },
 };
 
index 2ad9b14a5ce37c4ec15f8cb8b319c7845e982c4f..f6d72b402a8e3dc48d37319f6ebac236df71d60a 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/usb/ulpi.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/power/isp1704_charger.h>
 
 /* Vendor specific Power Control register */
 #define ISP1704_PWR_CTRL               0x3d
@@ -70,6 +71,18 @@ struct isp1704_charger {
        unsigned                max_power;
 };
 
+/*
+ * Disable/enable the power from the isp1704 if a function for it
+ * has been provided with platform data.
+ */
+static void isp1704_charger_set_power(struct isp1704_charger *isp, bool on)
+{
+       struct isp1704_charger_data     *board = isp->dev->platform_data;
+
+       if (board->set_power)
+               board->set_power(on);
+}
+
 /*
  * Determine is the charging port DCP (dedicated charger) or CDP (Host/HUB
  * chargers).
@@ -222,6 +235,9 @@ static void isp1704_charger_work(struct work_struct *data)
 
        mutex_lock(&lock);
 
+       if (event != USB_EVENT_NONE)
+               isp1704_charger_set_power(isp, 1);
+
        switch (event) {
        case USB_EVENT_VBUS:
                isp->online = true;
@@ -269,6 +285,8 @@ static void isp1704_charger_work(struct work_struct *data)
                 */
                if (isp->otg->gadget)
                        usb_gadget_disconnect(isp->otg->gadget);
+
+               isp1704_charger_set_power(isp, 0);
                break;
        case USB_EVENT_ENUMERATED:
                if (isp->present)
@@ -394,6 +412,8 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
        isp->dev = &pdev->dev;
        platform_set_drvdata(pdev, isp);
 
+       isp1704_charger_set_power(isp, 1);
+
        ret = isp1704_test_ulpi(isp);
        if (ret < 0)
                goto fail1;
@@ -434,6 +454,7 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
 
        /* Detect charger if VBUS is valid (the cable was already plugged). */
        ret = otg_io_read(isp->otg, ULPI_USB_INT_STS);
+       isp1704_charger_set_power(isp, 0);
        if ((ret & ULPI_INT_VBUS_VALID) && !isp->otg->default_a) {
                isp->event = USB_EVENT_VBUS;
                schedule_work(&isp->work);
@@ -459,6 +480,7 @@ static int __devexit isp1704_charger_remove(struct platform_device *pdev)
        otg_unregister_notifier(isp->otg, &isp->nb);
        power_supply_unregister(&isp->psy);
        otg_put_transceiver(isp->otg);
+       isp1704_charger_set_power(isp, 0);
        kfree(isp);
 
        return 0;
diff --git a/drivers/power/max8903_charger.c b/drivers/power/max8903_charger.c
new file mode 100644 (file)
index 0000000..33ff0e3
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * max8903_charger.c - Maxim 8903 USB/Adapter Charger Driver
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@samsung.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/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <linux/power/max8903_charger.h>
+
+struct max8903_data {
+       struct max8903_pdata *pdata;
+       struct device *dev;
+       struct power_supply psy;
+       bool fault;
+       bool usb_in;
+       bool ta_in;
+};
+
+static enum power_supply_property max8903_charger_props[] = {
+       POWER_SUPPLY_PROP_STATUS, /* Charger status output */
+       POWER_SUPPLY_PROP_ONLINE, /* External power source */
+       POWER_SUPPLY_PROP_HEALTH, /* Fault or OK */
+};
+
+static int max8903_get_property(struct power_supply *psy,
+               enum power_supply_property psp,
+               union power_supply_propval *val)
+{
+       struct max8903_data *data = container_of(psy,
+                       struct max8903_data, psy);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+               if (data->pdata->chg) {
+                       if (gpio_get_value(data->pdata->chg) == 0)
+                               val->intval = POWER_SUPPLY_STATUS_CHARGING;
+                       else if (data->usb_in || data->ta_in)
+                               val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                       else
+                               val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+               }
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = 0;
+               if (data->usb_in || data->ta_in)
+                       val->intval = 1;
+               break;
+       case POWER_SUPPLY_PROP_HEALTH:
+               val->intval = POWER_SUPPLY_HEALTH_GOOD;
+               if (data->fault)
+                       val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static irqreturn_t max8903_dcin(int irq, void *_data)
+{
+       struct max8903_data *data = _data;
+       struct max8903_pdata *pdata = data->pdata;
+       bool ta_in;
+       enum power_supply_type old_type;
+
+       ta_in = gpio_get_value(pdata->dok) ? false : true;
+
+       if (ta_in == data->ta_in)
+               return IRQ_HANDLED;
+
+       data->ta_in = ta_in;
+
+       /* Set Current-Limit-Mode 1:DC 0:USB */
+       if (pdata->dcm)
+               gpio_set_value(pdata->dcm, ta_in ? 1 : 0);
+
+       /* Charger Enable / Disable (cen is negated) */
+       if (pdata->cen)
+               gpio_set_value(pdata->cen, ta_in ? 0 :
+                               (data->usb_in ? 0 : 1));
+
+       dev_dbg(data->dev, "TA(DC-IN) Charger %s.\n", ta_in ?
+                       "Connected" : "Disconnected");
+
+       old_type = data->psy.type;
+
+       if (data->ta_in)
+               data->psy.type = POWER_SUPPLY_TYPE_MAINS;
+       else if (data->usb_in)
+               data->psy.type = POWER_SUPPLY_TYPE_USB;
+       else
+               data->psy.type = POWER_SUPPLY_TYPE_BATTERY;
+
+       if (old_type != data->psy.type)
+               power_supply_changed(&data->psy);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t max8903_usbin(int irq, void *_data)
+{
+       struct max8903_data *data = _data;
+       struct max8903_pdata *pdata = data->pdata;
+       bool usb_in;
+       enum power_supply_type old_type;
+
+       usb_in = gpio_get_value(pdata->uok) ? false : true;
+
+       if (usb_in == data->usb_in)
+               return IRQ_HANDLED;
+
+       data->usb_in = usb_in;
+
+       /* Do not touch Current-Limit-Mode */
+
+       /* Charger Enable / Disable (cen is negated) */
+       if (pdata->cen)
+               gpio_set_value(pdata->cen, usb_in ? 0 :
+                               (data->ta_in ? 0 : 1));
+
+       dev_dbg(data->dev, "USB Charger %s.\n", usb_in ?
+                       "Connected" : "Disconnected");
+
+       old_type = data->psy.type;
+
+       if (data->ta_in)
+               data->psy.type = POWER_SUPPLY_TYPE_MAINS;
+       else if (data->usb_in)
+               data->psy.type = POWER_SUPPLY_TYPE_USB;
+       else
+               data->psy.type = POWER_SUPPLY_TYPE_BATTERY;
+
+       if (old_type != data->psy.type)
+               power_supply_changed(&data->psy);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t max8903_fault(int irq, void *_data)
+{
+       struct max8903_data *data = _data;
+       struct max8903_pdata *pdata = data->pdata;
+       bool fault;
+
+       fault = gpio_get_value(pdata->flt) ? false : true;
+
+       if (fault == data->fault)
+               return IRQ_HANDLED;
+
+       data->fault = fault;
+
+       if (fault)
+               dev_err(data->dev, "Charger suffers a fault and stops.\n");
+       else
+               dev_err(data->dev, "Charger recovered from a fault.\n");
+
+       return IRQ_HANDLED;
+}
+
+static __devinit int max8903_probe(struct platform_device *pdev)
+{
+       struct max8903_data *data;
+       struct device *dev = &pdev->dev;
+       struct max8903_pdata *pdata = pdev->dev.platform_data;
+       int ret = 0;
+       int gpio;
+       int ta_in = 0;
+       int usb_in = 0;
+
+       data = kzalloc(sizeof(struct max8903_data), GFP_KERNEL);
+       if (data == NULL) {
+               dev_err(dev, "Cannot allocate memory.\n");
+               return -ENOMEM;
+       }
+       data->pdata = pdata;
+       data->dev = dev;
+       platform_set_drvdata(pdev, data);
+
+       if (pdata->dc_valid == false && pdata->usb_valid == false) {
+               dev_err(dev, "No valid power sources.\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       if (pdata->dc_valid) {
+               if (pdata->dok && gpio_is_valid(pdata->dok) &&
+                               pdata->dcm && gpio_is_valid(pdata->dcm)) {
+                       gpio = pdata->dok; /* PULL_UPed Interrupt */
+                       ta_in = gpio_get_value(gpio) ? 0 : 1;
+
+                       gpio = pdata->dcm; /* Output */
+                       gpio_set_value(gpio, ta_in);
+               } else {
+                       dev_err(dev, "When DC is wired, DOK and DCM should"
+                                       " be wired as well.\n");
+                       ret = -EINVAL;
+                       goto err;
+               }
+       } else {
+               if (pdata->dcm) {
+                       if (gpio_is_valid(pdata->dcm))
+                               gpio_set_value(pdata->dcm, 0);
+                       else {
+                               dev_err(dev, "Invalid pin: dcm.\n");
+                               ret = -EINVAL;
+                               goto err;
+                       }
+               }
+       }
+
+       if (pdata->usb_valid) {
+               if (pdata->uok && gpio_is_valid(pdata->uok)) {
+                       gpio = pdata->uok;
+                       usb_in = gpio_get_value(gpio) ? 0 : 1;
+               } else {
+                       dev_err(dev, "When USB is wired, UOK should be wired."
+                                       "as well.\n");
+                       ret = -EINVAL;
+                       goto err;
+               }
+       }
+
+       if (pdata->cen) {
+               if (gpio_is_valid(pdata->cen)) {
+                       gpio_set_value(pdata->cen, (ta_in || usb_in) ? 0 : 1);
+               } else {
+                       dev_err(dev, "Invalid pin: cen.\n");
+                       ret = -EINVAL;
+                       goto err;
+               }
+       }
+
+       if (pdata->chg) {
+               if (!gpio_is_valid(pdata->chg)) {
+                       dev_err(dev, "Invalid pin: chg.\n");
+                       ret = -EINVAL;
+                       goto err;
+               }
+       }
+
+       if (pdata->flt) {
+               if (!gpio_is_valid(pdata->flt)) {
+                       dev_err(dev, "Invalid pin: flt.\n");
+                       ret = -EINVAL;
+                       goto err;
+               }
+       }
+
+       if (pdata->usus) {
+               if (!gpio_is_valid(pdata->usus)) {
+                       dev_err(dev, "Invalid pin: usus.\n");
+                       ret = -EINVAL;
+                       goto err;
+               }
+       }
+
+       data->fault = false;
+       data->ta_in = ta_in;
+       data->usb_in = usb_in;
+
+       data->psy.name = "max8903_charger";
+       data->psy.type = (ta_in) ? POWER_SUPPLY_TYPE_MAINS :
+                       ((usb_in) ? POWER_SUPPLY_TYPE_USB :
+                        POWER_SUPPLY_TYPE_BATTERY);
+       data->psy.get_property = max8903_get_property;
+       data->psy.properties = max8903_charger_props;
+       data->psy.num_properties = ARRAY_SIZE(max8903_charger_props);
+
+       ret = power_supply_register(dev, &data->psy);
+       if (ret) {
+               dev_err(dev, "failed: power supply register.\n");
+               goto err;
+       }
+
+       if (pdata->dc_valid) {
+               ret = request_threaded_irq(gpio_to_irq(pdata->dok),
+                               NULL, max8903_dcin,
+                               IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+                               "MAX8903 DC IN", data);
+               if (ret) {
+                       dev_err(dev, "Cannot request irq %d for DC (%d)\n",
+                                       gpio_to_irq(pdata->dok), ret);
+                       goto err_psy;
+               }
+       }
+
+       if (pdata->usb_valid) {
+               ret = request_threaded_irq(gpio_to_irq(pdata->uok),
+                               NULL, max8903_usbin,
+                               IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+                               "MAX8903 USB IN", data);
+               if (ret) {
+                       dev_err(dev, "Cannot request irq %d for USB (%d)\n",
+                                       gpio_to_irq(pdata->uok), ret);
+                       goto err_dc_irq;
+               }
+       }
+
+       if (pdata->flt) {
+               ret = request_threaded_irq(gpio_to_irq(pdata->flt),
+                               NULL, max8903_fault,
+                               IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+                               "MAX8903 Fault", data);
+               if (ret) {
+                       dev_err(dev, "Cannot request irq %d for Fault (%d)\n",
+                                       gpio_to_irq(pdata->flt), ret);
+                       goto err_usb_irq;
+               }
+       }
+
+       return 0;
+
+err_usb_irq:
+       if (pdata->usb_valid)
+               free_irq(gpio_to_irq(pdata->uok), data);
+err_dc_irq:
+       if (pdata->dc_valid)
+               free_irq(gpio_to_irq(pdata->dok), data);
+err_psy:
+       power_supply_unregister(&data->psy);
+err:
+       kfree(data);
+       return ret;
+}
+
+static __devexit int max8903_remove(struct platform_device *pdev)
+{
+       struct max8903_data *data = platform_get_drvdata(pdev);
+
+       if (data) {
+               struct max8903_pdata *pdata = data->pdata;
+
+               if (pdata->flt)
+                       free_irq(gpio_to_irq(pdata->flt), data);
+               if (pdata->usb_valid)
+                       free_irq(gpio_to_irq(pdata->uok), data);
+               if (pdata->dc_valid)
+                       free_irq(gpio_to_irq(pdata->dok), data);
+               power_supply_unregister(&data->psy);
+               kfree(data);
+       }
+
+       return 0;
+}
+
+static struct platform_driver max8903_driver = {
+       .probe  = max8903_probe,
+       .remove = __devexit_p(max8903_remove),
+       .driver = {
+               .name   = "max8903-charger",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init max8903_init(void)
+{
+       return platform_driver_register(&max8903_driver);
+}
+module_init(max8903_init);
+
+static void __exit max8903_exit(void)
+{
+       platform_driver_unregister(&max8903_driver);
+}
+module_exit(max8903_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MAX8903 Charger Driver");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_ALIAS("max8903-charger");
index 8e5aec26086681c03908a91cfd3e3ea4a314e9f5..a70e16d3a3dc1d31942ccf6cf788d06b1c0ea3b1 100644 (file)
@@ -425,16 +425,11 @@ static __devexit int max8925_deinit_charger(struct max8925_power_info *info)
 static __devinit int max8925_power_probe(struct platform_device *pdev)
 {
        struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
-       struct max8925_platform_data *max8925_pdata;
        struct max8925_power_pdata *pdata = NULL;
        struct max8925_power_info *info;
        int ret;
 
-       if (pdev->dev.parent->platform_data) {
-               max8925_pdata = pdev->dev.parent->platform_data;
-               pdata = max8925_pdata->power;
-       }
-
+       pdata = pdev->dev.platform_data;
        if (!pdata) {
                dev_err(&pdev->dev, "platform data isn't assigned to "
                        "power supply\n");
@@ -447,6 +442,7 @@ static __devinit int max8925_power_probe(struct platform_device *pdev)
        info->chip = chip;
        info->gpm = chip->i2c;
        info->adc = chip->adc;
+       platform_set_drvdata(pdev, info);
 
        info->ac.name = "max8925-ac";
        info->ac.type = POWER_SUPPLY_TYPE_MAINS;
@@ -482,8 +478,6 @@ static __devinit int max8925_power_probe(struct platform_device *pdev)
        info->topoff_threshold = pdata->topoff_threshold;
        info->fast_charge = pdata->fast_charge;
        info->set_charger = pdata->set_charger;
-       dev_set_drvdata(&pdev->dev, info);
-       platform_set_drvdata(pdev, info);
 
        max8925_init_charger(chip, info);
        return 0;
index 0cd9f67d33e543a0e0a06cea9a2496e12211adff..b527c93bf2f3fbb11869333aa0cb36cad22ffea5 100644 (file)
@@ -3,6 +3,12 @@
  *
  * Copyright 2010  Anton Vorontsov <cbouatmailru@gmail.com>
  *
+ * Dynamic module parameter code from the Virtual Battery Driver
+ * Copyright (C) 2008 Pylone, Inc.
+ * By: Masashi YOKOTA <yokota@pylone.jp>
+ * Originally found here:
+ * http://downloads.pylone.jp/src/virtual_battery/virtual_battery-0.0.1.tar.bz2
+ *
  * 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/delay.h>
 #include <linux/vermagic.h>
 
-static int test_power_ac_online = 1;
-static int test_power_battery_status = POWER_SUPPLY_STATUS_CHARGING;
+static int ac_online                   = 1;
+static int battery_status              = POWER_SUPPLY_STATUS_DISCHARGING;
+static int battery_health              = POWER_SUPPLY_HEALTH_GOOD;
+static int battery_present             = 1; /* true */
+static int battery_technology          = POWER_SUPPLY_TECHNOLOGY_LION;
+static int battery_capacity            = 50;
 
 static int test_power_get_ac_property(struct power_supply *psy,
                                      enum power_supply_property psp,
@@ -24,7 +34,7 @@ static int test_power_get_ac_property(struct power_supply *psy,
 {
        switch (psp) {
        case POWER_SUPPLY_PROP_ONLINE:
-               val->intval = test_power_ac_online;
+               val->intval = ac_online;
                break;
        default:
                return -EINVAL;
@@ -47,22 +57,30 @@ static int test_power_get_battery_property(struct power_supply *psy,
                val->strval = UTS_RELEASE;
                break;
        case POWER_SUPPLY_PROP_STATUS:
-               val->intval = test_power_battery_status;
+               val->intval = battery_status;
                break;
        case POWER_SUPPLY_PROP_CHARGE_TYPE:
                val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
                break;
        case POWER_SUPPLY_PROP_HEALTH:
-               val->intval = POWER_SUPPLY_HEALTH_GOOD;
+               val->intval = battery_health;
+               break;
+       case POWER_SUPPLY_PROP_PRESENT:
+               val->intval = battery_present;
                break;
        case POWER_SUPPLY_PROP_TECHNOLOGY:
-               val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+               val->intval = battery_technology;
                break;
        case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
                val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
                break;
        case POWER_SUPPLY_PROP_CAPACITY:
-               val->intval = 50;
+       case POWER_SUPPLY_PROP_CHARGE_NOW:
+               val->intval = battery_capacity;
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+       case POWER_SUPPLY_PROP_CHARGE_FULL:
+               val->intval = 100;
                break;
        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
        case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
@@ -84,9 +102,11 @@ static enum power_supply_property test_power_battery_props[] = {
        POWER_SUPPLY_PROP_STATUS,
        POWER_SUPPLY_PROP_CHARGE_TYPE,
        POWER_SUPPLY_PROP_HEALTH,
+       POWER_SUPPLY_PROP_PRESENT,
        POWER_SUPPLY_PROP_TECHNOLOGY,
+       POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
        POWER_SUPPLY_PROP_CHARGE_FULL,
-       POWER_SUPPLY_PROP_CHARGE_EMPTY,
+       POWER_SUPPLY_PROP_CHARGE_NOW,
        POWER_SUPPLY_PROP_CAPACITY,
        POWER_SUPPLY_PROP_CAPACITY_LEVEL,
        POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
@@ -118,6 +138,7 @@ static struct power_supply test_power_supplies[] = {
        },
 };
 
+
 static int __init test_power_init(void)
 {
        int i;
@@ -145,8 +166,8 @@ static void __exit test_power_exit(void)
        int i;
 
        /* Let's see how we handle changes... */
-       test_power_ac_online = 0;
-       test_power_battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
+       ac_online = 0;
+       battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
        for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++)
                power_supply_changed(&test_power_supplies[i]);
        pr_info("%s: 'changed' event sent, sleeping for 10 seconds...\n",
@@ -158,6 +179,241 @@ static void __exit test_power_exit(void)
 }
 module_exit(test_power_exit);
 
+
+
+#define MAX_KEYLENGTH 256
+struct battery_property_map {
+       int value;
+       char const *key;
+};
+
+static struct battery_property_map map_ac_online[] = {
+       { 0,  "on"  },
+       { 1,  "off" },
+       { -1, NULL  },
+};
+
+static struct battery_property_map map_status[] = {
+       { POWER_SUPPLY_STATUS_CHARGING,     "charging"     },
+       { POWER_SUPPLY_STATUS_DISCHARGING,  "discharging"  },
+       { POWER_SUPPLY_STATUS_NOT_CHARGING, "not-charging" },
+       { POWER_SUPPLY_STATUS_FULL,         "full"         },
+       { -1,                               NULL           },
+};
+
+static struct battery_property_map map_health[] = {
+       { POWER_SUPPLY_HEALTH_GOOD,           "good"        },
+       { POWER_SUPPLY_HEALTH_OVERHEAT,       "overheat"    },
+       { POWER_SUPPLY_HEALTH_DEAD,           "dead"        },
+       { POWER_SUPPLY_HEALTH_OVERVOLTAGE,    "overvoltage" },
+       { POWER_SUPPLY_HEALTH_UNSPEC_FAILURE, "failure"     },
+       { -1,                                 NULL          },
+};
+
+static struct battery_property_map map_present[] = {
+       { 0,  "false" },
+       { 1,  "true"  },
+       { -1, NULL    },
+};
+
+static struct battery_property_map map_technology[] = {
+       { POWER_SUPPLY_TECHNOLOGY_NiMH, "NiMH" },
+       { POWER_SUPPLY_TECHNOLOGY_LION, "LION" },
+       { POWER_SUPPLY_TECHNOLOGY_LIPO, "LIPO" },
+       { POWER_SUPPLY_TECHNOLOGY_LiFe, "LiFe" },
+       { POWER_SUPPLY_TECHNOLOGY_NiCd, "NiCd" },
+       { POWER_SUPPLY_TECHNOLOGY_LiMn, "LiMn" },
+       { -1,                           NULL   },
+};
+
+
+static int map_get_value(struct battery_property_map *map, const char *key,
+                               int def_val)
+{
+       char buf[MAX_KEYLENGTH];
+       int cr;
+
+       strncpy(buf, key, MAX_KEYLENGTH);
+       buf[MAX_KEYLENGTH-1] = '\0';
+
+       cr = strnlen(buf, MAX_KEYLENGTH) - 1;
+       if (buf[cr] == '\n')
+               buf[cr] = '\0';
+
+       while (map->key) {
+               if (strncasecmp(map->key, buf, MAX_KEYLENGTH) == 0)
+                       return map->value;
+               map++;
+       }
+
+       return def_val;
+}
+
+
+static const char *map_get_key(struct battery_property_map *map, int value,
+                               const char *def_key)
+{
+       while (map->key) {
+               if (map->value == value)
+                       return map->key;
+               map++;
+       }
+
+       return def_key;
+}
+
+static int param_set_ac_online(const char *key, const struct kernel_param *kp)
+{
+       ac_online = map_get_value(map_ac_online, key, ac_online);
+       power_supply_changed(&test_power_supplies[0]);
+       return 0;
+}
+
+static int param_get_ac_online(char *buffer, const struct kernel_param *kp)
+{
+       strcpy(buffer, map_get_key(map_ac_online, ac_online, "unknown"));
+       return strlen(buffer);
+}
+
+static int param_set_battery_status(const char *key,
+                                       const struct kernel_param *kp)
+{
+       battery_status = map_get_value(map_status, key, battery_status);
+       power_supply_changed(&test_power_supplies[1]);
+       return 0;
+}
+
+static int param_get_battery_status(char *buffer, const struct kernel_param *kp)
+{
+       strcpy(buffer, map_get_key(map_status, battery_status, "unknown"));
+       return strlen(buffer);
+}
+
+static int param_set_battery_health(const char *key,
+                                       const struct kernel_param *kp)
+{
+       battery_health = map_get_value(map_health, key, battery_health);
+       power_supply_changed(&test_power_supplies[1]);
+       return 0;
+}
+
+static int param_get_battery_health(char *buffer, const struct kernel_param *kp)
+{
+       strcpy(buffer, map_get_key(map_health, battery_health, "unknown"));
+       return strlen(buffer);
+}
+
+static int param_set_battery_present(const char *key,
+                                       const struct kernel_param *kp)
+{
+       battery_present = map_get_value(map_present, key, battery_present);
+       power_supply_changed(&test_power_supplies[0]);
+       return 0;
+}
+
+static int param_get_battery_present(char *buffer,
+                                       const struct kernel_param *kp)
+{
+       strcpy(buffer, map_get_key(map_present, battery_present, "unknown"));
+       return strlen(buffer);
+}
+
+static int param_set_battery_technology(const char *key,
+                                       const struct kernel_param *kp)
+{
+       battery_technology = map_get_value(map_technology, key,
+                                               battery_technology);
+       power_supply_changed(&test_power_supplies[1]);
+       return 0;
+}
+
+static int param_get_battery_technology(char *buffer,
+                                       const struct kernel_param *kp)
+{
+       strcpy(buffer,
+               map_get_key(map_technology, battery_technology, "unknown"));
+       return strlen(buffer);
+}
+
+static int param_set_battery_capacity(const char *key,
+                                       const struct kernel_param *kp)
+{
+       int tmp;
+
+       if (1 != sscanf(key, "%d", &tmp))
+               return -EINVAL;
+
+       battery_capacity = tmp;
+       power_supply_changed(&test_power_supplies[1]);
+       return 0;
+}
+
+#define param_get_battery_capacity param_get_int
+
+
+
+static struct kernel_param_ops param_ops_ac_online = {
+       .set = param_set_ac_online,
+       .get = param_get_ac_online,
+};
+
+static struct kernel_param_ops param_ops_battery_status = {
+       .set = param_set_battery_status,
+       .get = param_get_battery_status,
+};
+
+static struct kernel_param_ops param_ops_battery_present = {
+       .set = param_set_battery_present,
+       .get = param_get_battery_present,
+};
+
+static struct kernel_param_ops param_ops_battery_technology = {
+       .set = param_set_battery_technology,
+       .get = param_get_battery_technology,
+};
+
+static struct kernel_param_ops param_ops_battery_health = {
+       .set = param_set_battery_health,
+       .get = param_get_battery_health,
+};
+
+static struct kernel_param_ops param_ops_battery_capacity = {
+       .set = param_set_battery_capacity,
+       .get = param_get_battery_capacity,
+};
+
+
+#define param_check_ac_online(name, p) __param_check(name, p, void);
+#define param_check_battery_status(name, p) __param_check(name, p, void);
+#define param_check_battery_present(name, p) __param_check(name, p, void);
+#define param_check_battery_technology(name, p) __param_check(name, p, void);
+#define param_check_battery_health(name, p) __param_check(name, p, void);
+#define param_check_battery_capacity(name, p) __param_check(name, p, void);
+
+
+module_param(ac_online, ac_online, 0644);
+MODULE_PARM_DESC(ac_online, "AC charging state <on|off>");
+
+module_param(battery_status, battery_status, 0644);
+MODULE_PARM_DESC(battery_status,
+       "battery status <charging|discharging|not-charging|full>");
+
+module_param(battery_present, battery_present, 0644);
+MODULE_PARM_DESC(battery_present,
+       "battery presence state <good|overheat|dead|overvoltage|failure>");
+
+module_param(battery_technology, battery_technology, 0644);
+MODULE_PARM_DESC(battery_technology,
+       "battery technology <NiMH|LION|LIPO|LiFe|NiCd|LiMn>");
+
+module_param(battery_health, battery_health, 0644);
+MODULE_PARM_DESC(battery_health,
+       "battery health state <good|overheat|dead|overvoltage|failure>");
+
+module_param(battery_capacity, battery_capacity, 0644);
+MODULE_PARM_DESC(battery_capacity, "battery capacity (percentage)");
+
+
 MODULE_DESCRIPTION("Power supply driver for testing");
 MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");
 MODULE_LICENSE("GPL");
index e5ced3a4c1ed9a8ad4b38467cfe199a15e472bc3..d119c38b3ff632ef158f66a971799c522202c6a3 100644 (file)
@@ -271,24 +271,33 @@ static int __devexit z2_batt_remove(struct i2c_client *client)
 }
 
 #ifdef CONFIG_PM
-static int z2_batt_suspend(struct i2c_client *client, pm_message_t state)
+static int z2_batt_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct z2_charger *charger = i2c_get_clientdata(client);
 
        flush_work_sync(&charger->bat_work);
        return 0;
 }
 
-static int z2_batt_resume(struct i2c_client *client)
+static int z2_batt_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct z2_charger *charger = i2c_get_clientdata(client);
 
        schedule_work(&charger->bat_work);
        return 0;
 }
+
+static const struct dev_pm_ops z2_battery_pm_ops = {
+       .suspend        = z2_batt_suspend,
+       .resume         = z2_batt_resume,
+};
+
+#define        Z2_BATTERY_PM_OPS       (&z2_battery_pm_ops)
+
 #else
-#define z2_batt_suspend NULL
-#define z2_batt_resume NULL
+#define        Z2_BATTERY_PM_OPS       (NULL)
 #endif
 
 static const struct i2c_device_id z2_batt_id[] = {
@@ -301,11 +310,10 @@ static struct i2c_driver z2_batt_driver = {
        .driver = {
                .name   = "z2-battery",
                .owner  = THIS_MODULE,
+               .pm     = Z2_BATTERY_PM_OPS
        },
        .probe          = z2_batt_probe,
        .remove         = z2_batt_remove,
-       .suspend        = z2_batt_suspend,
-       .resume         = z2_batt_resume,
        .id_table       = z2_batt_id,
 };
 
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
new file mode 100644 (file)
index 0000000..68d7201
--- /dev/null
@@ -0,0 +1,75 @@
+#
+# PTP clock support configuration
+#
+
+menu "PTP clock support"
+
+comment "Enable Device Drivers -> PPS to see the PTP clock options."
+       depends on PPS=n
+
+config PTP_1588_CLOCK
+       tristate "PTP clock support"
+       depends on EXPERIMENTAL
+       depends on PPS
+       help
+         The IEEE 1588 standard defines a method to precisely
+         synchronize distributed clocks over Ethernet networks. The
+         standard defines a Precision Time Protocol (PTP), which can
+         be used to achieve synchronization within a few dozen
+         microseconds. In addition, with the help of special hardware
+         time stamping units, it can be possible to achieve
+         synchronization to within a few hundred nanoseconds.
+
+         This driver adds support for PTP clocks as character
+         devices. If you want to use a PTP clock, then you should
+         also enable at least one clock driver as well.
+
+         To compile this driver as a module, choose M here: the module
+         will be called ptp.
+
+config PTP_1588_CLOCK_GIANFAR
+       tristate "Freescale eTSEC as PTP clock"
+       depends on PTP_1588_CLOCK
+       depends on GIANFAR
+       help
+         This driver adds support for using the eTSEC as a PTP
+         clock. This clock is only useful if your PTP programs are
+         getting hardware time stamps on the PTP Ethernet packets
+         using the SO_TIMESTAMPING API.
+
+         To compile this driver as a module, choose M here: the module
+         will be called gianfar_ptp.
+
+config PTP_1588_CLOCK_IXP46X
+       tristate "Intel IXP46x as PTP clock"
+       depends on PTP_1588_CLOCK
+       depends on IXP4XX_ETH
+       help
+         This driver adds support for using the IXP46X as a PTP
+         clock. This clock is only useful if your PTP programs are
+         getting hardware time stamps on the PTP Ethernet packets
+         using the SO_TIMESTAMPING API.
+
+         To compile this driver as a module, choose M here: the module
+         will be called ptp_ixp46x.
+
+comment "Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks."
+       depends on PTP_1588_CLOCK && (PHYLIB=n || NETWORK_PHY_TIMESTAMPING=n)
+
+config DP83640_PHY
+       tristate "Driver for the National Semiconductor DP83640 PHYTER"
+       depends on PTP_1588_CLOCK
+       depends on NETWORK_PHY_TIMESTAMPING
+       depends on PHYLIB
+       ---help---
+         Supports the DP83640 PHYTER with IEEE 1588 features.
+
+         This driver adds support for using the DP83640 as a PTP
+         clock. This clock is only useful if your PTP programs are
+         getting hardware time stamps on the PTP Ethernet packets
+         using the SO_TIMESTAMPING API.
+
+         In order for this to work, your MAC driver must also
+         implement the skb_tx_timetamp() function.
+
+endmenu
diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile
new file mode 100644 (file)
index 0000000..f6933e8
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for PTP 1588 clock support.
+#
+
+ptp-y                                  := ptp_clock.o ptp_chardev.o ptp_sysfs.o
+obj-$(CONFIG_PTP_1588_CLOCK)           += ptp.o
+obj-$(CONFIG_PTP_1588_CLOCK_IXP46X)    += ptp_ixp46x.o
diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c
new file mode 100644 (file)
index 0000000..e7f301d
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * PTP 1588 clock support - character device implementation.
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/module.h>
+#include <linux/posix-clock.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+
+#include "ptp_private.h"
+
+int ptp_open(struct posix_clock *pc, fmode_t fmode)
+{
+       return 0;
+}
+
+long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
+{
+       struct ptp_clock_caps caps;
+       struct ptp_clock_request req;
+       struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+       struct ptp_clock_info *ops = ptp->info;
+       int enable, err = 0;
+
+       switch (cmd) {
+
+       case PTP_CLOCK_GETCAPS:
+               memset(&caps, 0, sizeof(caps));
+               caps.max_adj = ptp->info->max_adj;
+               caps.n_alarm = ptp->info->n_alarm;
+               caps.n_ext_ts = ptp->info->n_ext_ts;
+               caps.n_per_out = ptp->info->n_per_out;
+               caps.pps = ptp->info->pps;
+               if (copy_to_user((void __user *)arg, &caps, sizeof(caps)))
+                       err = -EFAULT;
+               break;
+
+       case PTP_EXTTS_REQUEST:
+               if (copy_from_user(&req.extts, (void __user *)arg,
+                                  sizeof(req.extts))) {
+                       err = -EFAULT;
+                       break;
+               }
+               if (req.extts.index >= ops->n_ext_ts) {
+                       err = -EINVAL;
+                       break;
+               }
+               req.type = PTP_CLK_REQ_EXTTS;
+               enable = req.extts.flags & PTP_ENABLE_FEATURE ? 1 : 0;
+               err = ops->enable(ops, &req, enable);
+               break;
+
+       case PTP_PEROUT_REQUEST:
+               if (copy_from_user(&req.perout, (void __user *)arg,
+                                  sizeof(req.perout))) {
+                       err = -EFAULT;
+                       break;
+               }
+               if (req.perout.index >= ops->n_per_out) {
+                       err = -EINVAL;
+                       break;
+               }
+               req.type = PTP_CLK_REQ_PEROUT;
+               enable = req.perout.period.sec || req.perout.period.nsec;
+               err = ops->enable(ops, &req, enable);
+               break;
+
+       case PTP_ENABLE_PPS:
+               if (!capable(CAP_SYS_TIME))
+                       return -EPERM;
+               req.type = PTP_CLK_REQ_PPS;
+               enable = arg ? 1 : 0;
+               err = ops->enable(ops, &req, enable);
+               break;
+
+       default:
+               err = -ENOTTY;
+               break;
+       }
+       return err;
+}
+
+unsigned int ptp_poll(struct posix_clock *pc, struct file *fp, poll_table *wait)
+{
+       struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+
+       poll_wait(fp, &ptp->tsev_wq, wait);
+
+       return queue_cnt(&ptp->tsevq) ? POLLIN : 0;
+}
+
+ssize_t ptp_read(struct posix_clock *pc,
+                uint rdflags, char __user *buf, size_t cnt)
+{
+       struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+       struct timestamp_event_queue *queue = &ptp->tsevq;
+       struct ptp_extts_event event[PTP_BUF_TIMESTAMPS];
+       unsigned long flags;
+       size_t qcnt, i;
+
+       if (cnt % sizeof(struct ptp_extts_event) != 0)
+               return -EINVAL;
+
+       if (cnt > sizeof(event))
+               cnt = sizeof(event);
+
+       cnt = cnt / sizeof(struct ptp_extts_event);
+
+       if (mutex_lock_interruptible(&ptp->tsevq_mux))
+               return -ERESTARTSYS;
+
+       if (wait_event_interruptible(ptp->tsev_wq,
+                                    ptp->defunct || queue_cnt(queue))) {
+               mutex_unlock(&ptp->tsevq_mux);
+               return -ERESTARTSYS;
+       }
+
+       if (ptp->defunct) {
+               mutex_unlock(&ptp->tsevq_mux);
+               return -ENODEV;
+       }
+
+       spin_lock_irqsave(&queue->lock, flags);
+
+       qcnt = queue_cnt(queue);
+
+       if (cnt > qcnt)
+               cnt = qcnt;
+
+       for (i = 0; i < cnt; i++) {
+               event[i] = queue->buf[queue->head];
+               queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS;
+       }
+
+       spin_unlock_irqrestore(&queue->lock, flags);
+
+       cnt = cnt * sizeof(struct ptp_extts_event);
+
+       mutex_unlock(&ptp->tsevq_mux);
+
+       if (copy_to_user(buf, event, cnt))
+               return -EFAULT;
+
+       return cnt;
+}
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
new file mode 100644 (file)
index 0000000..cf3f999
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * PTP 1588 clock support
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/posix-clock.h>
+#include <linux/pps_kernel.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+
+#include "ptp_private.h"
+
+#define PTP_MAX_ALARMS 4
+#define PTP_MAX_CLOCKS 8
+#define PTP_PPS_DEFAULTS (PPS_CAPTUREASSERT | PPS_OFFSETASSERT)
+#define PTP_PPS_EVENT PPS_CAPTUREASSERT
+#define PTP_PPS_MODE (PTP_PPS_DEFAULTS | PPS_CANWAIT | PPS_TSFMT_TSPEC)
+
+/* private globals */
+
+static dev_t ptp_devt;
+static struct class *ptp_class;
+
+static DECLARE_BITMAP(ptp_clocks_map, PTP_MAX_CLOCKS);
+static DEFINE_MUTEX(ptp_clocks_mutex); /* protects 'ptp_clocks_map' */
+
+/* time stamp event queue operations */
+
+static inline int queue_free(struct timestamp_event_queue *q)
+{
+       return PTP_MAX_TIMESTAMPS - queue_cnt(q) - 1;
+}
+
+static void enqueue_external_timestamp(struct timestamp_event_queue *queue,
+                                      struct ptp_clock_event *src)
+{
+       struct ptp_extts_event *dst;
+       unsigned long flags;
+       s64 seconds;
+       u32 remainder;
+
+       seconds = div_u64_rem(src->timestamp, 1000000000, &remainder);
+
+       spin_lock_irqsave(&queue->lock, flags);
+
+       dst = &queue->buf[queue->tail];
+       dst->index = src->index;
+       dst->t.sec = seconds;
+       dst->t.nsec = remainder;
+
+       if (!queue_free(queue))
+               queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS;
+
+       queue->tail = (queue->tail + 1) % PTP_MAX_TIMESTAMPS;
+
+       spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+static s32 scaled_ppm_to_ppb(long ppm)
+{
+       /*
+        * The 'freq' field in the 'struct timex' is in parts per
+        * million, but with a 16 bit binary fractional field.
+        *
+        * We want to calculate
+        *
+        *    ppb = scaled_ppm * 1000 / 2^16
+        *
+        * which simplifies to
+        *
+        *    ppb = scaled_ppm * 125 / 2^13
+        */
+       s64 ppb = 1 + ppm;
+       ppb *= 125;
+       ppb >>= 13;
+       return (s32) ppb;
+}
+
+/* posix clock implementation */
+
+static int ptp_clock_getres(struct posix_clock *pc, struct timespec *tp)
+{
+       return 1; /* always round timer functions to one nanosecond */
+}
+
+static int ptp_clock_settime(struct posix_clock *pc, const struct timespec *tp)
+{
+       struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+       return ptp->info->settime(ptp->info, tp);
+}
+
+static int ptp_clock_gettime(struct posix_clock *pc, struct timespec *tp)
+{
+       struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+       return ptp->info->gettime(ptp->info, tp);
+}
+
+static int ptp_clock_adjtime(struct posix_clock *pc, struct timex *tx)
+{
+       struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+       struct ptp_clock_info *ops;
+       int err = -EOPNOTSUPP;
+
+       ops = ptp->info;
+
+       if (tx->modes & ADJ_SETOFFSET) {
+               struct timespec ts;
+               ktime_t kt;
+               s64 delta;
+
+               ts.tv_sec  = tx->time.tv_sec;
+               ts.tv_nsec = tx->time.tv_usec;
+
+               if (!(tx->modes & ADJ_NANO))
+                       ts.tv_nsec *= 1000;
+
+               if ((unsigned long) ts.tv_nsec >= NSEC_PER_SEC)
+                       return -EINVAL;
+
+               kt = timespec_to_ktime(ts);
+               delta = ktime_to_ns(kt);
+               err = ops->adjtime(ops, delta);
+
+       } else if (tx->modes & ADJ_FREQUENCY) {
+
+               err = ops->adjfreq(ops, scaled_ppm_to_ppb(tx->freq));
+       }
+
+       return err;
+}
+
+static struct posix_clock_operations ptp_clock_ops = {
+       .owner          = THIS_MODULE,
+       .clock_adjtime  = ptp_clock_adjtime,
+       .clock_gettime  = ptp_clock_gettime,
+       .clock_getres   = ptp_clock_getres,
+       .clock_settime  = ptp_clock_settime,
+       .ioctl          = ptp_ioctl,
+       .open           = ptp_open,
+       .poll           = ptp_poll,
+       .read           = ptp_read,
+};
+
+static void delete_ptp_clock(struct posix_clock *pc)
+{
+       struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+
+       mutex_destroy(&ptp->tsevq_mux);
+
+       /* Remove the clock from the bit map. */
+       mutex_lock(&ptp_clocks_mutex);
+       clear_bit(ptp->index, ptp_clocks_map);
+       mutex_unlock(&ptp_clocks_mutex);
+
+       kfree(ptp);
+}
+
+/* public interface */
+
+struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info)
+{
+       struct ptp_clock *ptp;
+       int err = 0, index, major = MAJOR(ptp_devt);
+
+       if (info->n_alarm > PTP_MAX_ALARMS)
+               return ERR_PTR(-EINVAL);
+
+       /* Find a free clock slot and reserve it. */
+       err = -EBUSY;
+       mutex_lock(&ptp_clocks_mutex);
+       index = find_first_zero_bit(ptp_clocks_map, PTP_MAX_CLOCKS);
+       if (index < PTP_MAX_CLOCKS)
+               set_bit(index, ptp_clocks_map);
+       else
+               goto no_slot;
+
+       /* Initialize a clock structure. */
+       err = -ENOMEM;
+       ptp = kzalloc(sizeof(struct ptp_clock), GFP_KERNEL);
+       if (ptp == NULL)
+               goto no_memory;
+
+       ptp->clock.ops = ptp_clock_ops;
+       ptp->clock.release = delete_ptp_clock;
+       ptp->info = info;
+       ptp->devid = MKDEV(major, index);
+       ptp->index = index;
+       spin_lock_init(&ptp->tsevq.lock);
+       mutex_init(&ptp->tsevq_mux);
+       init_waitqueue_head(&ptp->tsev_wq);
+
+       /* Create a new device in our class. */
+       ptp->dev = device_create(ptp_class, NULL, ptp->devid, ptp,
+                                "ptp%d", ptp->index);
+       if (IS_ERR(ptp->dev))
+               goto no_device;
+
+       dev_set_drvdata(ptp->dev, ptp);
+
+       err = ptp_populate_sysfs(ptp);
+       if (err)
+               goto no_sysfs;
+
+       /* Register a new PPS source. */
+       if (info->pps) {
+               struct pps_source_info pps;
+               memset(&pps, 0, sizeof(pps));
+               snprintf(pps.name, PPS_MAX_NAME_LEN, "ptp%d", index);
+               pps.mode = PTP_PPS_MODE;
+               pps.owner = info->owner;
+               ptp->pps_source = pps_register_source(&pps, PTP_PPS_DEFAULTS);
+               if (!ptp->pps_source) {
+                       pr_err("failed to register pps source\n");
+                       goto no_pps;
+               }
+       }
+
+       /* Create a posix clock. */
+       err = posix_clock_register(&ptp->clock, ptp->devid);
+       if (err) {
+               pr_err("failed to create posix clock\n");
+               goto no_clock;
+       }
+
+       mutex_unlock(&ptp_clocks_mutex);
+       return ptp;
+
+no_clock:
+       if (ptp->pps_source)
+               pps_unregister_source(ptp->pps_source);
+no_pps:
+       ptp_cleanup_sysfs(ptp);
+no_sysfs:
+       device_destroy(ptp_class, ptp->devid);
+no_device:
+       mutex_destroy(&ptp->tsevq_mux);
+       kfree(ptp);
+no_memory:
+       clear_bit(index, ptp_clocks_map);
+no_slot:
+       mutex_unlock(&ptp_clocks_mutex);
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL(ptp_clock_register);
+
+int ptp_clock_unregister(struct ptp_clock *ptp)
+{
+       ptp->defunct = 1;
+       wake_up_interruptible(&ptp->tsev_wq);
+
+       /* Release the clock's resources. */
+       if (ptp->pps_source)
+               pps_unregister_source(ptp->pps_source);
+       ptp_cleanup_sysfs(ptp);
+       device_destroy(ptp_class, ptp->devid);
+
+       posix_clock_unregister(&ptp->clock);
+       return 0;
+}
+EXPORT_SYMBOL(ptp_clock_unregister);
+
+void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event)
+{
+       struct pps_event_time evt;
+
+       switch (event->type) {
+
+       case PTP_CLOCK_ALARM:
+               break;
+
+       case PTP_CLOCK_EXTTS:
+               enqueue_external_timestamp(&ptp->tsevq, event);
+               wake_up_interruptible(&ptp->tsev_wq);
+               break;
+
+       case PTP_CLOCK_PPS:
+               pps_get_ts(&evt);
+               pps_event(ptp->pps_source, &evt, PTP_PPS_EVENT, NULL);
+               break;
+       }
+}
+EXPORT_SYMBOL(ptp_clock_event);
+
+/* module operations */
+
+static void __exit ptp_exit(void)
+{
+       class_destroy(ptp_class);
+       unregister_chrdev_region(ptp_devt, PTP_MAX_CLOCKS);
+}
+
+static int __init ptp_init(void)
+{
+       int err;
+
+       ptp_class = class_create(THIS_MODULE, "ptp");
+       if (IS_ERR(ptp_class)) {
+               pr_err("ptp: failed to allocate class\n");
+               return PTR_ERR(ptp_class);
+       }
+
+       err = alloc_chrdev_region(&ptp_devt, 0, PTP_MAX_CLOCKS, "ptp");
+       if (err < 0) {
+               pr_err("ptp: failed to allocate device region\n");
+               goto no_region;
+       }
+
+       ptp_class->dev_attrs = ptp_dev_attrs;
+       pr_info("PTP clock support registered\n");
+       return 0;
+
+no_region:
+       class_destroy(ptp_class);
+       return err;
+}
+
+subsys_initcall(ptp_init);
+module_exit(ptp_exit);
+
+MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>");
+MODULE_DESCRIPTION("PTP clocks support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ptp/ptp_ixp46x.c b/drivers/ptp/ptp_ixp46x.c
new file mode 100644 (file)
index 0000000..803d665
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * PTP 1588 clock using the IXP46X
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/ptp_clock_kernel.h>
+#include <mach/ixp46x_ts.h>
+
+#define DRIVER         "ptp_ixp46x"
+#define N_EXT_TS       2
+#define MASTER_GPIO    8
+#define MASTER_IRQ     25
+#define SLAVE_GPIO     7
+#define SLAVE_IRQ      24
+
+struct ixp_clock {
+       struct ixp46x_ts_regs *regs;
+       struct ptp_clock *ptp_clock;
+       struct ptp_clock_info caps;
+       int exts0_enabled;
+       int exts1_enabled;
+};
+
+DEFINE_SPINLOCK(register_lock);
+
+/*
+ * Register access functions
+ */
+
+static u64 ixp_systime_read(struct ixp46x_ts_regs *regs)
+{
+       u64 ns;
+       u32 lo, hi;
+
+       lo = __raw_readl(&regs->systime_lo);
+       hi = __raw_readl(&regs->systime_hi);
+
+       ns = ((u64) hi) << 32;
+       ns |= lo;
+       ns <<= TICKS_NS_SHIFT;
+
+       return ns;
+}
+
+static void ixp_systime_write(struct ixp46x_ts_regs *regs, u64 ns)
+{
+       u32 hi, lo;
+
+       ns >>= TICKS_NS_SHIFT;
+       hi = ns >> 32;
+       lo = ns & 0xffffffff;
+
+       __raw_writel(lo, &regs->systime_lo);
+       __raw_writel(hi, &regs->systime_hi);
+}
+
+/*
+ * Interrupt service routine
+ */
+
+static irqreturn_t isr(int irq, void *priv)
+{
+       struct ixp_clock *ixp_clock = priv;
+       struct ixp46x_ts_regs *regs = ixp_clock->regs;
+       struct ptp_clock_event event;
+       u32 ack = 0, lo, hi, val;
+
+       val = __raw_readl(&regs->event);
+
+       if (val & TSER_SNS) {
+               ack |= TSER_SNS;
+               if (ixp_clock->exts0_enabled) {
+                       hi = __raw_readl(&regs->asms_hi);
+                       lo = __raw_readl(&regs->asms_lo);
+                       event.type = PTP_CLOCK_EXTTS;
+                       event.index = 0;
+                       event.timestamp = ((u64) hi) << 32;
+                       event.timestamp |= lo;
+                       event.timestamp <<= TICKS_NS_SHIFT;
+                       ptp_clock_event(ixp_clock->ptp_clock, &event);
+               }
+       }
+
+       if (val & TSER_SNM) {
+               ack |= TSER_SNM;
+               if (ixp_clock->exts1_enabled) {
+                       hi = __raw_readl(&regs->amms_hi);
+                       lo = __raw_readl(&regs->amms_lo);
+                       event.type = PTP_CLOCK_EXTTS;
+                       event.index = 1;
+                       event.timestamp = ((u64) hi) << 32;
+                       event.timestamp |= lo;
+                       event.timestamp <<= TICKS_NS_SHIFT;
+                       ptp_clock_event(ixp_clock->ptp_clock, &event);
+               }
+       }
+
+       if (val & TTIPEND)
+               ack |= TTIPEND; /* this bit seems to be always set */
+
+       if (ack) {
+               __raw_writel(ack, &regs->event);
+               return IRQ_HANDLED;
+       } else
+               return IRQ_NONE;
+}
+
+/*
+ * PTP clock operations
+ */
+
+static int ptp_ixp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+       u64 adj;
+       u32 diff, addend;
+       int neg_adj = 0;
+       struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
+       struct ixp46x_ts_regs *regs = ixp_clock->regs;
+
+       if (ppb < 0) {
+               neg_adj = 1;
+               ppb = -ppb;
+       }
+       addend = DEFAULT_ADDEND;
+       adj = addend;
+       adj *= ppb;
+       diff = div_u64(adj, 1000000000ULL);
+
+       addend = neg_adj ? addend - diff : addend + diff;
+
+       __raw_writel(addend, &regs->addend);
+
+       return 0;
+}
+
+static int ptp_ixp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+       s64 now;
+       unsigned long flags;
+       struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
+       struct ixp46x_ts_regs *regs = ixp_clock->regs;
+
+       spin_lock_irqsave(&register_lock, flags);
+
+       now = ixp_systime_read(regs);
+       now += delta;
+       ixp_systime_write(regs, now);
+
+       spin_unlock_irqrestore(&register_lock, flags);
+
+       return 0;
+}
+
+static int ptp_ixp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+       u64 ns;
+       u32 remainder;
+       unsigned long flags;
+       struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
+       struct ixp46x_ts_regs *regs = ixp_clock->regs;
+
+       spin_lock_irqsave(&register_lock, flags);
+
+       ns = ixp_systime_read(regs);
+
+       spin_unlock_irqrestore(&register_lock, flags);
+
+       ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
+       ts->tv_nsec = remainder;
+       return 0;
+}
+
+static int ptp_ixp_settime(struct ptp_clock_info *ptp,
+                          const struct timespec *ts)
+{
+       u64 ns;
+       unsigned long flags;
+       struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
+       struct ixp46x_ts_regs *regs = ixp_clock->regs;
+
+       ns = ts->tv_sec * 1000000000ULL;
+       ns += ts->tv_nsec;
+
+       spin_lock_irqsave(&register_lock, flags);
+
+       ixp_systime_write(regs, ns);
+
+       spin_unlock_irqrestore(&register_lock, flags);
+
+       return 0;
+}
+
+static int ptp_ixp_enable(struct ptp_clock_info *ptp,
+                         struct ptp_clock_request *rq, int on)
+{
+       struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
+
+       switch (rq->type) {
+       case PTP_CLK_REQ_EXTTS:
+               switch (rq->extts.index) {
+               case 0:
+                       ixp_clock->exts0_enabled = on ? 1 : 0;
+                       break;
+               case 1:
+                       ixp_clock->exts1_enabled = on ? 1 : 0;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               return 0;
+       default:
+               break;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static struct ptp_clock_info ptp_ixp_caps = {
+       .owner          = THIS_MODULE,
+       .name           = "IXP46X timer",
+       .max_adj        = 66666655,
+       .n_ext_ts       = N_EXT_TS,
+       .pps            = 0,
+       .adjfreq        = ptp_ixp_adjfreq,
+       .adjtime        = ptp_ixp_adjtime,
+       .gettime        = ptp_ixp_gettime,
+       .settime        = ptp_ixp_settime,
+       .enable         = ptp_ixp_enable,
+};
+
+/* module operations */
+
+static struct ixp_clock ixp_clock;
+
+static int setup_interrupt(int gpio)
+{
+       int irq;
+
+       gpio_line_config(gpio, IXP4XX_GPIO_IN);
+
+       irq = gpio_to_irq(gpio);
+
+       if (NO_IRQ == irq)
+               return NO_IRQ;
+
+       if (irq_set_irq_type(irq, IRQF_TRIGGER_FALLING)) {
+               pr_err("cannot set trigger type for irq %d\n", irq);
+               return NO_IRQ;
+       }
+
+       if (request_irq(irq, isr, 0, DRIVER, &ixp_clock)) {
+               pr_err("request_irq failed for irq %d\n", irq);
+               return NO_IRQ;
+       }
+
+       return irq;
+}
+
+static void __exit ptp_ixp_exit(void)
+{
+       free_irq(MASTER_IRQ, &ixp_clock);
+       free_irq(SLAVE_IRQ, &ixp_clock);
+       ptp_clock_unregister(ixp_clock.ptp_clock);
+}
+
+static int __init ptp_ixp_init(void)
+{
+       if (!cpu_is_ixp46x())
+               return -ENODEV;
+
+       ixp_clock.regs =
+               (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
+
+       ixp_clock.caps = ptp_ixp_caps;
+
+       ixp_clock.ptp_clock = ptp_clock_register(&ixp_clock.caps);
+
+       if (IS_ERR(ixp_clock.ptp_clock))
+               return PTR_ERR(ixp_clock.ptp_clock);
+
+       __raw_writel(DEFAULT_ADDEND, &ixp_clock.regs->addend);
+       __raw_writel(1, &ixp_clock.regs->trgt_lo);
+       __raw_writel(0, &ixp_clock.regs->trgt_hi);
+       __raw_writel(TTIPEND, &ixp_clock.regs->event);
+
+       if (MASTER_IRQ != setup_interrupt(MASTER_GPIO)) {
+               pr_err("failed to setup gpio %d as irq\n", MASTER_GPIO);
+               goto no_master;
+       }
+       if (SLAVE_IRQ != setup_interrupt(SLAVE_GPIO)) {
+               pr_err("failed to setup gpio %d as irq\n", SLAVE_GPIO);
+               goto no_slave;
+       }
+
+       return 0;
+no_slave:
+       free_irq(MASTER_IRQ, &ixp_clock);
+no_master:
+       ptp_clock_unregister(ixp_clock.ptp_clock);
+       return -ENODEV;
+}
+
+module_init(ptp_ixp_init);
+module_exit(ptp_ixp_exit);
+
+MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>");
+MODULE_DESCRIPTION("PTP clock using the IXP46X timer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h
new file mode 100644 (file)
index 0000000..4d5b508
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * PTP 1588 clock support - private declarations for the core module.
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  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.
+ */
+#ifndef _PTP_PRIVATE_H_
+#define _PTP_PRIVATE_H_
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/posix-clock.h>
+#include <linux/ptp_clock.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/time.h>
+
+#define PTP_MAX_TIMESTAMPS 128
+#define PTP_BUF_TIMESTAMPS 30
+
+struct timestamp_event_queue {
+       struct ptp_extts_event buf[PTP_MAX_TIMESTAMPS];
+       int head;
+       int tail;
+       spinlock_t lock;
+};
+
+struct ptp_clock {
+       struct posix_clock clock;
+       struct device *dev;
+       struct ptp_clock_info *info;
+       dev_t devid;
+       int index; /* index into clocks.map */
+       struct pps_device *pps_source;
+       struct timestamp_event_queue tsevq; /* simple fifo for time stamps */
+       struct mutex tsevq_mux; /* one process at a time reading the fifo */
+       wait_queue_head_t tsev_wq;
+       int defunct; /* tells readers to go away when clock is being removed */
+};
+
+/*
+ * The function queue_cnt() is safe for readers to call without
+ * holding q->lock. Readers use this function to verify that the queue
+ * is nonempty before proceeding with a dequeue operation. The fact
+ * that a writer might concurrently increment the tail does not
+ * matter, since the queue remains nonempty nonetheless.
+ */
+static inline int queue_cnt(struct timestamp_event_queue *q)
+{
+       int cnt = q->tail - q->head;
+       return cnt < 0 ? PTP_MAX_TIMESTAMPS + cnt : cnt;
+}
+
+/*
+ * see ptp_chardev.c
+ */
+
+long ptp_ioctl(struct posix_clock *pc,
+              unsigned int cmd, unsigned long arg);
+
+int ptp_open(struct posix_clock *pc, fmode_t fmode);
+
+ssize_t ptp_read(struct posix_clock *pc,
+                uint flags, char __user *buf, size_t cnt);
+
+uint ptp_poll(struct posix_clock *pc,
+             struct file *fp, poll_table *wait);
+
+/*
+ * see ptp_sysfs.c
+ */
+
+extern struct device_attribute ptp_dev_attrs[];
+
+int ptp_cleanup_sysfs(struct ptp_clock *ptp);
+
+int ptp_populate_sysfs(struct ptp_clock *ptp);
+
+#endif
diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c
new file mode 100644 (file)
index 0000000..2f93926
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * PTP 1588 clock support - sysfs interface.
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/capability.h>
+
+#include "ptp_private.h"
+
+static ssize_t clock_name_show(struct device *dev,
+                              struct device_attribute *attr, char *page)
+{
+       struct ptp_clock *ptp = dev_get_drvdata(dev);
+       return snprintf(page, PAGE_SIZE-1, "%s\n", ptp->info->name);
+}
+
+#define PTP_SHOW_INT(name)                                             \
+static ssize_t name##_show(struct device *dev,                         \
+                          struct device_attribute *attr, char *page)   \
+{                                                                      \
+       struct ptp_clock *ptp = dev_get_drvdata(dev);                   \
+       return snprintf(page, PAGE_SIZE-1, "%d\n", ptp->info->name);    \
+}
+
+PTP_SHOW_INT(max_adj);
+PTP_SHOW_INT(n_alarm);
+PTP_SHOW_INT(n_ext_ts);
+PTP_SHOW_INT(n_per_out);
+PTP_SHOW_INT(pps);
+
+#define PTP_RO_ATTR(_var, _name) {                             \
+       .attr   = { .name = __stringify(_name), .mode = 0444 }, \
+       .show   = _var##_show,                                  \
+}
+
+struct device_attribute ptp_dev_attrs[] = {
+       PTP_RO_ATTR(clock_name, clock_name),
+       PTP_RO_ATTR(max_adj,    max_adjustment),
+       PTP_RO_ATTR(n_alarm,    n_alarms),
+       PTP_RO_ATTR(n_ext_ts,   n_external_timestamps),
+       PTP_RO_ATTR(n_per_out,  n_periodic_outputs),
+       PTP_RO_ATTR(pps,        pps_available),
+       __ATTR_NULL,
+};
+
+static ssize_t extts_enable_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct ptp_clock *ptp = dev_get_drvdata(dev);
+       struct ptp_clock_info *ops = ptp->info;
+       struct ptp_clock_request req = { .type = PTP_CLK_REQ_EXTTS };
+       int cnt, enable;
+       int err = -EINVAL;
+
+       cnt = sscanf(buf, "%u %d", &req.extts.index, &enable);
+       if (cnt != 2)
+               goto out;
+       if (req.extts.index >= ops->n_ext_ts)
+               goto out;
+
+       err = ops->enable(ops, &req, enable ? 1 : 0);
+       if (err)
+               goto out;
+
+       return count;
+out:
+       return err;
+}
+
+static ssize_t extts_fifo_show(struct device *dev,
+                              struct device_attribute *attr, char *page)
+{
+       struct ptp_clock *ptp = dev_get_drvdata(dev);
+       struct timestamp_event_queue *queue = &ptp->tsevq;
+       struct ptp_extts_event event;
+       unsigned long flags;
+       size_t qcnt;
+       int cnt = 0;
+
+       memset(&event, 0, sizeof(event));
+
+       if (mutex_lock_interruptible(&ptp->tsevq_mux))
+               return -ERESTARTSYS;
+
+       spin_lock_irqsave(&queue->lock, flags);
+       qcnt = queue_cnt(queue);
+       if (qcnt) {
+               event = queue->buf[queue->head];
+               queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS;
+       }
+       spin_unlock_irqrestore(&queue->lock, flags);
+
+       if (!qcnt)
+               goto out;
+
+       cnt = snprintf(page, PAGE_SIZE, "%u %lld %u\n",
+                      event.index, event.t.sec, event.t.nsec);
+out:
+       mutex_unlock(&ptp->tsevq_mux);
+       return cnt;
+}
+
+static ssize_t period_store(struct device *dev,
+                           struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       struct ptp_clock *ptp = dev_get_drvdata(dev);
+       struct ptp_clock_info *ops = ptp->info;
+       struct ptp_clock_request req = { .type = PTP_CLK_REQ_PEROUT };
+       int cnt, enable, err = -EINVAL;
+
+       cnt = sscanf(buf, "%u %lld %u %lld %u", &req.perout.index,
+                    &req.perout.start.sec, &req.perout.start.nsec,
+                    &req.perout.period.sec, &req.perout.period.nsec);
+       if (cnt != 5)
+               goto out;
+       if (req.perout.index >= ops->n_per_out)
+               goto out;
+
+       enable = req.perout.period.sec || req.perout.period.nsec;
+       err = ops->enable(ops, &req, enable);
+       if (err)
+               goto out;
+
+       return count;
+out:
+       return err;
+}
+
+static ssize_t pps_enable_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct ptp_clock *ptp = dev_get_drvdata(dev);
+       struct ptp_clock_info *ops = ptp->info;
+       struct ptp_clock_request req = { .type = PTP_CLK_REQ_PPS };
+       int cnt, enable;
+       int err = -EINVAL;
+
+       if (!capable(CAP_SYS_TIME))
+               return -EPERM;
+
+       cnt = sscanf(buf, "%d", &enable);
+       if (cnt != 1)
+               goto out;
+
+       err = ops->enable(ops, &req, enable ? 1 : 0);
+       if (err)
+               goto out;
+
+       return count;
+out:
+       return err;
+}
+
+static DEVICE_ATTR(extts_enable, 0220, NULL, extts_enable_store);
+static DEVICE_ATTR(fifo,         0444, extts_fifo_show, NULL);
+static DEVICE_ATTR(period,       0220, NULL, period_store);
+static DEVICE_ATTR(pps_enable,   0220, NULL, pps_enable_store);
+
+int ptp_cleanup_sysfs(struct ptp_clock *ptp)
+{
+       struct device *dev = ptp->dev;
+       struct ptp_clock_info *info = ptp->info;
+
+       if (info->n_ext_ts) {
+               device_remove_file(dev, &dev_attr_extts_enable);
+               device_remove_file(dev, &dev_attr_fifo);
+       }
+       if (info->n_per_out)
+               device_remove_file(dev, &dev_attr_period);
+
+       if (info->pps)
+               device_remove_file(dev, &dev_attr_pps_enable);
+
+       return 0;
+}
+
+int ptp_populate_sysfs(struct ptp_clock *ptp)
+{
+       struct device *dev = ptp->dev;
+       struct ptp_clock_info *info = ptp->info;
+       int err;
+
+       if (info->n_ext_ts) {
+               err = device_create_file(dev, &dev_attr_extts_enable);
+               if (err)
+                       goto out1;
+               err = device_create_file(dev, &dev_attr_fifo);
+               if (err)
+                       goto out2;
+       }
+       if (info->n_per_out) {
+               err = device_create_file(dev, &dev_attr_period);
+               if (err)
+                       goto out3;
+       }
+       if (info->pps) {
+               err = device_create_file(dev, &dev_attr_pps_enable);
+               if (err)
+                       goto out4;
+       }
+       return 0;
+out4:
+       if (info->n_per_out)
+               device_remove_file(dev, &dev_attr_period);
+out3:
+       if (info->n_ext_ts)
+               device_remove_file(dev, &dev_attr_fifo);
+out2:
+       if (info->n_ext_ts)
+               device_remove_file(dev, &dev_attr_extts_enable);
+out1:
+       return err;
+}
index 859251250b55bb400d548924711e665ebb26b5f2..d63fddb0fbb0d5ead8cadb323bfbff49b2a3e00f 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
-#include <linux/mfd/core.h>
 #include <linux/mfd/88pm860x.h>
 
 struct pm8607_regulator_info {
@@ -399,36 +398,33 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
 {
        struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
        struct pm8607_regulator_info *info = NULL;
-       struct regulator_init_data *pdata;
-       struct mfd_cell *cell;
+       struct regulator_init_data *pdata = pdev->dev.platform_data;
+       struct resource *res;
        int i;
 
-       cell = pdev->dev.platform_data;
-       if (cell == NULL)
-               return -ENODEV;
-       pdata = cell->mfd_data;
-       if (pdata == NULL)
+       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "No I/O resource!\n");
                return -EINVAL;
-
+       }
        for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
                info = &pm8607_regulator_info[i];
-               if (!strcmp(info->desc.name, pdata->constraints.name))
+               if (info->desc.id == res->start)
                        break;
        }
-       if (i > ARRAY_SIZE(pm8607_regulator_info)) {
-               dev_err(&pdev->dev, "Failed to find regulator %s\n",
-                       pdata->constraints.name);
+       if ((i < 0) || (i > PM8607_ID_RG_MAX)) {
+               dev_err(&pdev->dev, "Failed to find regulator %llu\n",
+                       (unsigned long long)res->start);
                return -EINVAL;
        }
-
        info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
        info->chip = chip;
 
        /* check DVC ramp slope double */
-       if (!strcmp(info->desc.name, "BUCK3"))
-               if (info->chip->buck3_double)
-                       info->slope_double = 1;
+       if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double)
+               info->slope_double = 1;
 
+       /* replace driver_data with info */
        info->regulator = regulator_register(&info->desc, &pdev->dev,
                                             pdata, info);
        if (IS_ERR(info->regulator)) {
index b9f29e0d4295b0f1031b151a8e03efde7e974a40..d7ed20f293d7f4af578d8d8098fae6bc609fb8b7 100644 (file)
@@ -274,6 +274,13 @@ config REGULATOR_AB8500
          This driver supports the regulators found on the ST-Ericsson mixed
          signal AB8500 PMIC
 
+config REGULATOR_DB8500_PRCMU
+       bool "ST-Ericsson DB8500 Voltage Domain Regulators"
+       depends on MFD_DB8500_PRCMU
+       help
+         This driver supports the voltage domain regulators controlled by the
+         DB8500 PRCMU
+
 config REGULATOR_TPS6586X
        tristate "TI TPS6586X Power regulators"
        depends on MFD_TPS6586X
@@ -290,5 +297,11 @@ config REGULATOR_TPS6524X
          serial interface currently supported on the sequencer serial
          port controller.
 
+config REGULATOR_TPS65910
+       tristate "TI TPS65910 Power Regulator"
+       depends on MFD_TPS65910
+       help
+         This driver supports TPS65910 voltage regulator chips.
+
 endif
 
index d72a427567786eade1a87fb05c2a83284757ba01..3932d2ec38f36f08ea209dfd50f0a32ba1b75121 100644 (file)
@@ -41,5 +41,7 @@ obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
 obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
 obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
 obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
+obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
+obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
 
 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
index b1d77946e9c64dd69aed6f840fcaf2c685846e92..585e4946fe0a7157b6ccaf6ae59465f788505a38 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/mfd/abx500.h>
-#include <linux/mfd/core.h>
 
 /* LDO registers and some handy masking definitions for AB3100 */
 #define AB3100_LDO_A           0x40
@@ -582,7 +581,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
 
 static int __devinit ab3100_regulators_probe(struct platform_device *pdev)
 {
-       struct ab3100_platform_data *plfdata = mfd_get_data(pdev);
+       struct ab3100_platform_data *plfdata = pdev->dev.platform_data;
        int err = 0;
        u8 data;
        int i;
index 0fae51c4845a3cf703f220c11d313be6a8ee099c..d3e38790906ed889de2b78454516ec1410eb6466 100644 (file)
@@ -158,6 +158,13 @@ static int regulator_check_consumers(struct regulator_dev *rdev,
        struct regulator *regulator;
 
        list_for_each_entry(regulator, &rdev->consumer_list, list) {
+               /*
+                * Assume consumers that didn't say anything are OK
+                * with anything in the constraint range.
+                */
+               if (!regulator->min_uV && !regulator->max_uV)
+                       continue;
+
                if (*max_uV > regulator->max_uV)
                        *max_uV = regulator->max_uV;
                if (*min_uV < regulator->min_uV)
@@ -197,9 +204,9 @@ static int regulator_check_current_limit(struct regulator_dev *rdev,
 }
 
 /* operating mode constraint check */
-static int regulator_check_mode(struct regulator_dev *rdev, int mode)
+static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode)
 {
-       switch (mode) {
+       switch (*mode) {
        case REGULATOR_MODE_FAST:
        case REGULATOR_MODE_NORMAL:
        case REGULATOR_MODE_IDLE:
@@ -217,11 +224,17 @@ static int regulator_check_mode(struct regulator_dev *rdev, int mode)
                rdev_err(rdev, "operation not allowed\n");
                return -EPERM;
        }
-       if (!(rdev->constraints->valid_modes_mask & mode)) {
-               rdev_err(rdev, "invalid mode %x\n", mode);
-               return -EINVAL;
+
+       /* The modes are bitmasks, the most power hungry modes having
+        * the lowest values. If the requested mode isn't supported
+        * try higher modes. */
+       while (*mode) {
+               if (rdev->constraints->valid_modes_mask & *mode)
+                       return 0;
+               *mode /= 2;
        }
-       return 0;
+
+       return -EINVAL;
 }
 
 /* dynamic regulator mode switching constraint check */
@@ -612,7 +625,7 @@ static void drms_uA_update(struct regulator_dev *rdev)
                                                  output_uV, current_uA);
 
        /* check the new mode is allowed */
-       err = regulator_check_mode(rdev, mode);
+       err = regulator_mode_constrain(rdev, &mode);
        if (err == 0)
                rdev->desc->ops->set_mode(rdev, mode);
 }
@@ -718,6 +731,10 @@ static void print_constraints(struct regulator_dev *rdev)
                        count += sprintf(buf + count, "at %d mV ", ret / 1000);
        }
 
+       if (constraints->uV_offset)
+               count += sprintf(buf, "%dmV offset ",
+                                constraints->uV_offset / 1000);
+
        if (constraints->min_uA && constraints->max_uA) {
                if (constraints->min_uA == constraints->max_uA)
                        count += sprintf(buf + count, "%d mA ",
@@ -1498,13 +1515,14 @@ static int _regulator_force_disable(struct regulator_dev *rdev,
  */
 int regulator_force_disable(struct regulator *regulator)
 {
+       struct regulator_dev *rdev = regulator->rdev;
        struct regulator_dev *supply_rdev = NULL;
        int ret;
 
-       mutex_lock(&regulator->rdev->mutex);
+       mutex_lock(&rdev->mutex);
        regulator->uA_load = 0;
-       ret = _regulator_force_disable(regulator->rdev, &supply_rdev);
-       mutex_unlock(&regulator->rdev->mutex);
+       ret = _regulator_force_disable(rdev, &supply_rdev);
+       mutex_unlock(&rdev->mutex);
 
        if (supply_rdev)
                regulator_disable(get_device_regulator(rdev_get_dev(supply_rdev)));
@@ -1634,6 +1652,9 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 
        trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV);
 
+       min_uV += rdev->constraints->uV_offset;
+       max_uV += rdev->constraints->uV_offset;
+
        if (rdev->desc->ops->set_voltage) {
                ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV,
                                                   &selector);
@@ -1858,18 +1879,22 @@ EXPORT_SYMBOL_GPL(regulator_sync_voltage);
 
 static int _regulator_get_voltage(struct regulator_dev *rdev)
 {
-       int sel;
+       int sel, ret;
 
        if (rdev->desc->ops->get_voltage_sel) {
                sel = rdev->desc->ops->get_voltage_sel(rdev);
                if (sel < 0)
                        return sel;
-               return rdev->desc->ops->list_voltage(rdev, sel);
-       }
-       if (rdev->desc->ops->get_voltage)
-               return rdev->desc->ops->get_voltage(rdev);
-       else
+               ret = rdev->desc->ops->list_voltage(rdev, sel);
+       } else if (rdev->desc->ops->get_voltage) {
+               ret = rdev->desc->ops->get_voltage(rdev);
+       } else {
                return -EINVAL;
+       }
+
+       if (ret < 0)
+               return ret;
+       return ret - rdev->constraints->uV_offset;
 }
 
 /**
@@ -2005,7 +2030,7 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode)
        }
 
        /* constraints check */
-       ret = regulator_check_mode(rdev, mode);
+       ret = regulator_mode_constrain(rdev, &mode);
        if (ret < 0)
                goto out;
 
@@ -2081,16 +2106,26 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
 
        mutex_lock(&rdev->mutex);
 
+       /*
+        * first check to see if we can set modes at all, otherwise just
+        * tell the consumer everything is OK.
+        */
        regulator->uA_load = uA_load;
        ret = regulator_check_drms(rdev);
-       if (ret < 0)
+       if (ret < 0) {
+               ret = 0;
                goto out;
-       ret = -EINVAL;
+       }
 
-       /* sanity check */
        if (!rdev->desc->ops->get_optimum_mode)
                goto out;
 
+       /*
+        * we can actually do this so any errors are indicators of
+        * potential real failure.
+        */
+       ret = -EINVAL;
+
        /* get output voltage */
        output_uV = _regulator_get_voltage(rdev);
        if (output_uV <= 0) {
@@ -2116,7 +2151,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
        mode = rdev->desc->ops->get_optimum_mode(rdev,
                                                 input_uV, output_uV,
                                                 total_uA_load);
-       ret = regulator_check_mode(rdev, mode);
+       ret = regulator_mode_constrain(rdev, &mode);
        if (ret < 0) {
                rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n",
                         total_uA_load, input_uV, output_uV);
@@ -2589,14 +2624,6 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
        if (ret < 0)
                goto scrub;
 
-       /* set supply regulator if it exists */
-       if (init_data->supply_regulator && init_data->supply_regulator_dev) {
-               dev_err(dev,
-                       "Supply regulator specified by both name and dev\n");
-               ret = -EINVAL;
-               goto scrub;
-       }
-
        if (init_data->supply_regulator) {
                struct regulator_dev *r;
                int found = 0;
@@ -2621,14 +2648,6 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
                        goto scrub;
        }
 
-       if (init_data->supply_regulator_dev) {
-               dev_warn(dev, "Uses supply_regulator_dev instead of regulator_supply\n");
-               ret = set_supply(rdev,
-                       dev_get_drvdata(init_data->supply_regulator_dev));
-               if (ret < 0)
-                       goto scrub;
-       }
-
        /* add consumers devices */
        for (i = 0; i < init_data->num_consumer_supplies; i++) {
                ret = set_consumer_device_supply(rdev,
diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c
new file mode 100644 (file)
index 0000000..e5f7b8f
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *          Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ *
+ * Power domain regulators on DB8500
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/db8500-prcmu.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/db8500-prcmu.h>
+
+/*
+ * power state reference count
+ */
+static int power_state_active_cnt; /* will initialize to zero */
+static DEFINE_SPINLOCK(power_state_active_lock);
+
+static void power_state_active_enable(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&power_state_active_lock, flags);
+       power_state_active_cnt++;
+       spin_unlock_irqrestore(&power_state_active_lock, flags);
+}
+
+static int power_state_active_disable(void)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&power_state_active_lock, flags);
+       if (power_state_active_cnt <= 0) {
+               pr_err("power state: unbalanced enable/disable calls\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       power_state_active_cnt--;
+out:
+       spin_unlock_irqrestore(&power_state_active_lock, flags);
+       return ret;
+}
+
+/*
+ * Exported interface for CPUIdle only. This function is called when interrupts
+ * are turned off. Hence, no locking.
+ */
+int power_state_active_is_enabled(void)
+{
+       return (power_state_active_cnt > 0);
+}
+
+/**
+ * struct db8500_regulator_info - db8500 regulator information
+ * @dev: device pointer
+ * @desc: regulator description
+ * @rdev: regulator device pointer
+ * @is_enabled: status of the regulator
+ * @epod_id: id for EPOD (power domain)
+ * @is_ramret: RAM retention switch for EPOD (power domain)
+ * @operating_point: operating point (only for vape, to be removed)
+ *
+ */
+struct db8500_regulator_info {
+       struct device *dev;
+       struct regulator_desc desc;
+       struct regulator_dev *rdev;
+       bool is_enabled;
+       u16 epod_id;
+       bool is_ramret;
+       bool exclude_from_power_state;
+       unsigned int operating_point;
+};
+
+static int db8500_regulator_enable(struct regulator_dev *rdev)
+{
+       struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+       if (info == NULL)
+               return -EINVAL;
+
+       dev_vdbg(rdev_get_dev(rdev), "regulator-%s-enable\n",
+               info->desc.name);
+
+       info->is_enabled = true;
+       if (!info->exclude_from_power_state)
+               power_state_active_enable();
+
+       return 0;
+}
+
+static int db8500_regulator_disable(struct regulator_dev *rdev)
+{
+       struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret = 0;
+
+       if (info == NULL)
+               return -EINVAL;
+
+       dev_vdbg(rdev_get_dev(rdev), "regulator-%s-disable\n",
+               info->desc.name);
+
+       info->is_enabled = false;
+       if (!info->exclude_from_power_state)
+               ret = power_state_active_disable();
+
+       return ret;
+}
+
+static int db8500_regulator_is_enabled(struct regulator_dev *rdev)
+{
+       struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+       if (info == NULL)
+               return -EINVAL;
+
+       dev_vdbg(rdev_get_dev(rdev), "regulator-%s-is_enabled (is_enabled):"
+               " %i\n", info->desc.name, info->is_enabled);
+
+       return info->is_enabled;
+}
+
+/* db8500 regulator operations */
+static struct regulator_ops db8500_regulator_ops = {
+       .enable                 = db8500_regulator_enable,
+       .disable                = db8500_regulator_disable,
+       .is_enabled             = db8500_regulator_is_enabled,
+};
+
+/*
+ * EPOD control
+ */
+static bool epod_on[NUM_EPOD_ID];
+static bool epod_ramret[NUM_EPOD_ID];
+
+static int enable_epod(u16 epod_id, bool ramret)
+{
+       int ret;
+
+       if (ramret) {
+               if (!epod_on[epod_id]) {
+                       ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
+                       if (ret < 0)
+                               return ret;
+               }
+               epod_ramret[epod_id] = true;
+       } else {
+               ret = prcmu_set_epod(epod_id, EPOD_STATE_ON);
+               if (ret < 0)
+                       return ret;
+               epod_on[epod_id] = true;
+       }
+
+       return 0;
+}
+
+static int disable_epod(u16 epod_id, bool ramret)
+{
+       int ret;
+
+       if (ramret) {
+               if (!epod_on[epod_id]) {
+                       ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
+                       if (ret < 0)
+                               return ret;
+               }
+               epod_ramret[epod_id] = false;
+       } else {
+               if (epod_ramret[epod_id]) {
+                       ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
+                       if (ret < 0)
+                               return ret;
+               } else {
+                       ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
+                       if (ret < 0)
+                               return ret;
+               }
+               epod_on[epod_id] = false;
+       }
+
+       return 0;
+}
+
+/*
+ * Regulator switch
+ */
+static int db8500_regulator_switch_enable(struct regulator_dev *rdev)
+{
+       struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret;
+
+       if (info == NULL)
+               return -EINVAL;
+
+       dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-enable\n",
+               info->desc.name);
+
+       ret = enable_epod(info->epod_id, info->is_ramret);
+       if (ret < 0) {
+               dev_err(rdev_get_dev(rdev),
+                       "regulator-switch-%s-enable: prcmu call failed\n",
+                       info->desc.name);
+               goto out;
+       }
+
+       info->is_enabled = true;
+out:
+       return ret;
+}
+
+static int db8500_regulator_switch_disable(struct regulator_dev *rdev)
+{
+       struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret;
+
+       if (info == NULL)
+               return -EINVAL;
+
+       dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-disable\n",
+               info->desc.name);
+
+       ret = disable_epod(info->epod_id, info->is_ramret);
+       if (ret < 0) {
+               dev_err(rdev_get_dev(rdev),
+                       "regulator_switch-%s-disable: prcmu call failed\n",
+                       info->desc.name);
+               goto out;
+       }
+
+       info->is_enabled = 0;
+out:
+       return ret;
+}
+
+static int db8500_regulator_switch_is_enabled(struct regulator_dev *rdev)
+{
+       struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+       if (info == NULL)
+               return -EINVAL;
+
+       dev_vdbg(rdev_get_dev(rdev),
+               "regulator-switch-%s-is_enabled (is_enabled): %i\n",
+               info->desc.name, info->is_enabled);
+
+       return info->is_enabled;
+}
+
+static struct regulator_ops db8500_regulator_switch_ops = {
+       .enable                 = db8500_regulator_switch_enable,
+       .disable                = db8500_regulator_switch_disable,
+       .is_enabled             = db8500_regulator_switch_is_enabled,
+};
+
+/*
+ * Regulator information
+ */
+static struct db8500_regulator_info
+               db8500_regulator_info[DB8500_NUM_REGULATORS] = {
+       [DB8500_REGULATOR_VAPE] = {
+               .desc = {
+                       .name   = "db8500-vape",
+                       .id     = DB8500_REGULATOR_VAPE,
+                       .ops    = &db8500_regulator_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+       },
+       [DB8500_REGULATOR_VARM] = {
+               .desc = {
+                       .name   = "db8500-varm",
+                       .id     = DB8500_REGULATOR_VARM,
+                       .ops    = &db8500_regulator_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+       },
+       [DB8500_REGULATOR_VMODEM] = {
+               .desc = {
+                       .name   = "db8500-vmodem",
+                       .id     = DB8500_REGULATOR_VMODEM,
+                       .ops    = &db8500_regulator_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+       },
+       [DB8500_REGULATOR_VPLL] = {
+               .desc = {
+                       .name   = "db8500-vpll",
+                       .id     = DB8500_REGULATOR_VPLL,
+                       .ops    = &db8500_regulator_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+       },
+       [DB8500_REGULATOR_VSMPS1] = {
+               .desc = {
+                       .name   = "db8500-vsmps1",
+                       .id     = DB8500_REGULATOR_VSMPS1,
+                       .ops    = &db8500_regulator_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+       },
+       [DB8500_REGULATOR_VSMPS2] = {
+               .desc = {
+                       .name   = "db8500-vsmps2",
+                       .id     = DB8500_REGULATOR_VSMPS2,
+                       .ops    = &db8500_regulator_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .exclude_from_power_state = true,
+       },
+       [DB8500_REGULATOR_VSMPS3] = {
+               .desc = {
+                       .name   = "db8500-vsmps3",
+                       .id     = DB8500_REGULATOR_VSMPS3,
+                       .ops    = &db8500_regulator_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+       },
+       [DB8500_REGULATOR_VRF1] = {
+               .desc = {
+                       .name   = "db8500-vrf1",
+                       .id     = DB8500_REGULATOR_VRF1,
+                       .ops    = &db8500_regulator_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
+               .desc = {
+                       .name   = "db8500-sva-mmdsp",
+                       .id     = DB8500_REGULATOR_SWITCH_SVAMMDSP,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_SVAMMDSP,
+       },
+       [DB8500_REGULATOR_SWITCH_SVAMMDSPRET] = {
+               .desc = {
+                       .name   = "db8500-sva-mmdsp-ret",
+                       .id     = DB8500_REGULATOR_SWITCH_SVAMMDSPRET,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_SVAMMDSP,
+               .is_ramret = true,
+       },
+       [DB8500_REGULATOR_SWITCH_SVAPIPE] = {
+               .desc = {
+                       .name   = "db8500-sva-pipe",
+                       .id     = DB8500_REGULATOR_SWITCH_SVAPIPE,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_SVAPIPE,
+       },
+       [DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
+               .desc = {
+                       .name   = "db8500-sia-mmdsp",
+                       .id     = DB8500_REGULATOR_SWITCH_SIAMMDSP,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_SIAMMDSP,
+       },
+       [DB8500_REGULATOR_SWITCH_SIAMMDSPRET] = {
+               .desc = {
+                       .name   = "db8500-sia-mmdsp-ret",
+                       .id     = DB8500_REGULATOR_SWITCH_SIAMMDSPRET,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_SIAMMDSP,
+               .is_ramret = true,
+       },
+       [DB8500_REGULATOR_SWITCH_SIAPIPE] = {
+               .desc = {
+                       .name   = "db8500-sia-pipe",
+                       .id     = DB8500_REGULATOR_SWITCH_SIAPIPE,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_SIAPIPE,
+       },
+       [DB8500_REGULATOR_SWITCH_SGA] = {
+               .desc = {
+                       .name   = "db8500-sga",
+                       .id     = DB8500_REGULATOR_SWITCH_SGA,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_SGA,
+       },
+       [DB8500_REGULATOR_SWITCH_B2R2_MCDE] = {
+               .desc = {
+                       .name   = "db8500-b2r2-mcde",
+                       .id     = DB8500_REGULATOR_SWITCH_B2R2_MCDE,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_B2R2_MCDE,
+       },
+       [DB8500_REGULATOR_SWITCH_ESRAM12] = {
+               .desc = {
+                       .name   = "db8500-esram12",
+                       .id     = DB8500_REGULATOR_SWITCH_ESRAM12,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id        = EPOD_ID_ESRAM12,
+               .is_enabled     = true,
+       },
+       [DB8500_REGULATOR_SWITCH_ESRAM12RET] = {
+               .desc = {
+                       .name   = "db8500-esram12-ret",
+                       .id     = DB8500_REGULATOR_SWITCH_ESRAM12RET,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_ESRAM12,
+               .is_ramret = true,
+       },
+       [DB8500_REGULATOR_SWITCH_ESRAM34] = {
+               .desc = {
+                       .name   = "db8500-esram34",
+                       .id     = DB8500_REGULATOR_SWITCH_ESRAM34,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id        = EPOD_ID_ESRAM34,
+               .is_enabled     = true,
+       },
+       [DB8500_REGULATOR_SWITCH_ESRAM34RET] = {
+               .desc = {
+                       .name   = "db8500-esram34-ret",
+                       .id     = DB8500_REGULATOR_SWITCH_ESRAM34RET,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_ESRAM34,
+               .is_ramret = true,
+       },
+};
+
+static int __devinit db8500_regulator_probe(struct platform_device *pdev)
+{
+       struct regulator_init_data *db8500_init_data =
+                                       dev_get_platdata(&pdev->dev);
+       int i, err;
+
+       /* register all regulators */
+       for (i = 0; i < ARRAY_SIZE(db8500_regulator_info); i++) {
+               struct db8500_regulator_info *info;
+               struct regulator_init_data *init_data = &db8500_init_data[i];
+
+               /* assign per-regulator data */
+               info = &db8500_regulator_info[i];
+               info->dev = &pdev->dev;
+
+               /* register with the regulator framework */
+               info->rdev = regulator_register(&info->desc, &pdev->dev,
+                               init_data, info);
+               if (IS_ERR(info->rdev)) {
+                       err = PTR_ERR(info->rdev);
+                       dev_err(&pdev->dev, "failed to register %s: err %i\n",
+                               info->desc.name, err);
+
+                       /* if failing, unregister all earlier regulators */
+                       i--;
+                       while (i >= 0) {
+                               info = &db8500_regulator_info[i];
+                               regulator_unregister(info->rdev);
+                               i--;
+                       }
+                       return err;
+               }
+
+               dev_dbg(rdev_get_dev(info->rdev),
+                       "regulator-%s-probed\n", info->desc.name);
+       }
+
+       return 0;
+}
+
+static int __exit db8500_regulator_remove(struct platform_device *pdev)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(db8500_regulator_info); i++) {
+               struct db8500_regulator_info *info;
+               info = &db8500_regulator_info[i];
+
+               dev_vdbg(rdev_get_dev(info->rdev),
+                       "regulator-%s-remove\n", info->desc.name);
+
+               regulator_unregister(info->rdev);
+       }
+
+       return 0;
+}
+
+static struct platform_driver db8500_regulator_driver = {
+       .driver = {
+               .name = "db8500-prcmu-regulators",
+               .owner = THIS_MODULE,
+       },
+       .probe = db8500_regulator_probe,
+       .remove = __exit_p(db8500_regulator_remove),
+};
+
+static int __init db8500_regulator_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&db8500_regulator_driver);
+       if (ret < 0)
+               return -ENODEV;
+
+       return 0;
+}
+
+static void __exit db8500_regulator_exit(void)
+{
+       platform_driver_unregister(&db8500_regulator_driver);
+}
+
+arch_initcall(db8500_regulator_init);
+module_exit(db8500_regulator_exit);
+
+MODULE_AUTHOR("STMicroelectronics/ST-Ericsson");
+MODULE_DESCRIPTION("DB8500 regulator driver");
+MODULE_LICENSE("GPL v2");
index 8ae147549c6aabb2c65b9fd60f8aec8bb6f67a26..e4dbd667c043577b2cfe250df38fbbdcf3869eb1 100644 (file)
 #define SD1_DVM_SHIFT          5               /* SDCTL1 bit5 */
 #define SD1_DVM_EN             6               /* SDV1 bit 6 */
 
+/* bit definitions in SD & LDO control registers */
+#define OUT_ENABLE             0x1f            /* Power U/D sequence as I2C */
+#define OUT_DISABLE            0x1e            /* Power U/D sequence as I2C */
+
 struct max8925_regulator_info {
        struct regulator_desc   desc;
        struct regulator_dev    *regulator;
@@ -93,8 +97,8 @@ static int max8925_enable(struct regulator_dev *rdev)
        struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
 
        return max8925_set_bits(info->i2c, info->enable_reg,
-                               1 << info->enable_bit,
-                               1 << info->enable_bit);
+                               OUT_ENABLE << info->enable_bit,
+                               OUT_ENABLE << info->enable_bit);
 }
 
 static int max8925_disable(struct regulator_dev *rdev)
@@ -102,7 +106,8 @@ static int max8925_disable(struct regulator_dev *rdev)
        struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
 
        return max8925_set_bits(info->i2c, info->enable_reg,
-                               1 << info->enable_bit, 0);
+                               OUT_ENABLE << info->enable_bit,
+                               OUT_DISABLE << info->enable_bit);
 }
 
 static int max8925_is_enabled(struct regulator_dev *rdev)
index 77e0cfb30b23fcc5ff274cf66ac96b94a532a62d..10d5a1d9768e3fd973ea4f8ea6ab388d9a24eaaa 100644 (file)
@@ -267,7 +267,6 @@ static int max8997_get_enable_register(struct regulator_dev *rdev,
        default:
                /* Not controllable or not exists */
                return -EINVAL;
-               break;
        }
 
        return 0;
@@ -1033,11 +1032,11 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
 
        /* For the safety, set max voltage before setting up */
        for (i = 0; i < 8; i++) {
-               max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS(i + 1),
+               max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i,
                                max_buck1, 0x3f);
-               max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS(i + 1),
+               max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i,
                                max_buck2, 0x3f);
-               max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS(i + 1),
+               max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i,
                                max_buck5, 0x3f);
        }
 
@@ -1114,13 +1113,13 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
 
        /* Initialize all the DVS related BUCK registers */
        for (i = 0; i < 8; i++) {
-               max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS(i + 1),
+               max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i,
                                max8997->buck1_vol[i],
                                0x3f);
-               max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS(i + 1),
+               max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i,
                                max8997->buck2_vol[i],
                                0x3f);
-               max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS(i + 1),
+               max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i,
                                max8997->buck5_vol[i],
                                0x3f);
        }
index f57e9c42fdb4e2957ee767d68897ca36e57ae219..41a1495eec2bc28c5d58a9b68b8c2ef2f7b558a3 100644 (file)
@@ -732,13 +732,15 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
                if (!pdata->buck1_set1) {
                        printk(KERN_ERR "MAX8998 SET1 GPIO defined as 0 !\n");
                        WARN_ON(!pdata->buck1_set1);
-                       return -EIO;
+                       ret = -EIO;
+                       goto err_free_mem;
                }
                /* Check if SET2 is not equal to 0 */
                if (!pdata->buck1_set2) {
                        printk(KERN_ERR "MAX8998 SET2 GPIO defined as 0 !\n");
                        WARN_ON(!pdata->buck1_set2);
-                       return -EIO;
+                       ret = -EIO;
+                       goto err_free_mem;
                }
 
                gpio_request(pdata->buck1_set1, "MAX8998 BUCK1_SET1");
@@ -758,7 +760,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
                max8998->buck1_vol[0] = i;
                ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i);
                if (ret)
-                       return ret;
+                       goto err_free_mem;
 
                /* Set predefined value for BUCK1 register 2 */
                i = 0;
@@ -770,7 +772,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
                max8998->buck1_vol[1] = i;
                ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i);
                if (ret)
-                       return ret;
+                       goto err_free_mem;
 
                /* Set predefined value for BUCK1 register 3 */
                i = 0;
@@ -782,7 +784,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
                max8998->buck1_vol[2] = i;
                ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE3, i);
                if (ret)
-                       return ret;
+                       goto err_free_mem;
 
                /* Set predefined value for BUCK1 register 4 */
                i = 0;
@@ -794,7 +796,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
                max8998->buck1_vol[3] = i;
                ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE4, i);
                if (ret)
-                       return ret;
+                       goto err_free_mem;
 
        }
 
@@ -803,7 +805,8 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
                if (!pdata->buck2_set3) {
                        printk(KERN_ERR "MAX8998 SET3 GPIO defined as 0 !\n");
                        WARN_ON(!pdata->buck2_set3);
-                       return -EIO;
+                       ret = -EIO;
+                       goto err_free_mem;
                }
                gpio_request(pdata->buck2_set3, "MAX8998 BUCK2_SET3");
                gpio_direction_output(pdata->buck2_set3,
@@ -818,7 +821,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
                max8998->buck2_vol[0] = i;
                ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i);
                if (ret)
-                       return ret;
+                       goto err_free_mem;
 
                /* BUCK2 register 2 */
                i = 0;
@@ -830,7 +833,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
                max8998->buck2_vol[1] = i;
                ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i);
                if (ret)
-                       return ret;
+                       goto err_free_mem;
        }
 
        for (i = 0; i < pdata->num_regulators; i++) {
@@ -860,6 +863,7 @@ err:
                if (rdev[i])
                        regulator_unregister(rdev[i]);
 
+err_free_mem:
        kfree(max8998->rdev);
        kfree(max8998);
 
index b8a00c7fa4418719c26e8760d61fcd6b561e6def..730f43ad415b11fb83803f84577eb1e5d7c4c738 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/regulator/driver.h>
 #include <linux/platform_device.h>
 #include <linux/kernel.h>
-#include <linux/mfd/core.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/err.h>
@@ -337,7 +336,8 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
 {
        struct mc13xxx_regulator_priv *priv;
        struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
-       struct mc13783_regulator_platform_data *pdata = mfd_get_data(pdev);
+       struct mc13783_regulator_platform_data *pdata =
+               dev_get_platdata(&pdev->dev);
        struct mc13783_regulator_init_data *init_data;
        int i, ret;
 
@@ -381,7 +381,8 @@ err:
 static int __devexit mc13783_regulator_remove(struct platform_device *pdev)
 {
        struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
-       struct mc13783_regulator_platform_data *pdata = mfd_get_data(pdev);
+       struct mc13783_regulator_platform_data *pdata =
+               dev_get_platdata(&pdev->dev);
        int i;
 
        platform_set_drvdata(pdev, NULL);
index 6f15168e5ed494e04cbc4d38a9589bdc0847c97c..3285d41842f281d4433cbab2e5752d5b50c1632c 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/regulator/driver.h>
 #include <linux/platform_device.h>
 #include <linux/kernel.h>
-#include <linux/mfd/core.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/err.h>
@@ -432,7 +431,8 @@ static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev,
                int min_uV, int max_uV, unsigned *selector)
 {
        struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
-       int hi, value, val, mask, id = rdev_get_id(rdev);
+       int hi, value, mask, id = rdev_get_id(rdev);
+       u32 valread;
        int ret;
 
        dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
@@ -448,15 +448,16 @@ static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev,
 
        mc13xxx_lock(priv->mc13xxx);
        ret = mc13xxx_reg_read(priv->mc13xxx,
-               mc13892_regulators[id].vsel_reg, &val);
+               mc13892_regulators[id].vsel_reg, &valread);
        if (ret)
                goto err;
 
-       hi  = val & MC13892_SWITCHERS0_SWxHI;
-       if (value > 1375)
+       if (value > 1375000)
                hi = 1;
-       if (value < 1100)
+       else if (value < 1100000)
                hi = 0;
+       else
+               hi = valread & MC13892_SWITCHERS0_SWxHI;
 
        if (hi) {
                value = (value - 1100000) / 25000;
@@ -465,8 +466,10 @@ static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev,
                value = (value - 600000) / 25000;
 
        mask = mc13892_regulators[id].vsel_mask | MC13892_SWITCHERS0_SWxHI;
-       ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].vsel_reg,
-                       mask, value << mc13892_regulators[id].vsel_shift);
+       valread = (valread & ~mask) |
+                       (value << mc13892_regulators[id].vsel_shift);
+       ret = mc13xxx_reg_write(priv->mc13xxx, mc13892_regulators[id].vsel_reg,
+                       valread);
 err:
        mc13xxx_unlock(priv->mc13xxx);
 
@@ -521,7 +524,8 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev)
 {
        struct mc13xxx_regulator_priv *priv;
        struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent);
-       struct mc13xxx_regulator_platform_data *pdata = mfd_get_data(pdev);
+       struct mc13xxx_regulator_platform_data *pdata =
+               dev_get_platdata(&pdev->dev);
        struct mc13xxx_regulator_init_data *init_data;
        int i, ret;
        u32 val;
@@ -595,7 +599,8 @@ err_free:
 static int __devexit mc13892_regulator_remove(struct platform_device *pdev)
 {
        struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
-       struct mc13xxx_regulator_platform_data *pdata = mfd_get_data(pdev);
+       struct mc13xxx_regulator_platform_data *pdata =
+               dev_get_platdata(&pdev->dev);
        int i;
 
        platform_set_drvdata(pdev, NULL);
index 2bb5de1f2421283013e512ab6e643f4b9f05f38a..bc27ab1363784db2788dc6e158a6c68f63b9362c 100644 (file)
@@ -174,7 +174,7 @@ static int mc13xxx_regulator_get_voltage(struct regulator_dev *rdev)
 
        dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
 
-       BUG_ON(val > mc13xxx_regulators[id].desc.n_voltages);
+       BUG_ON(val >= mc13xxx_regulators[id].desc.n_voltages);
 
        return mc13xxx_regulators[id].voltages[val];
 }
index 1661499feda4ea59ae3965290faca158218731a1..1011873896dc9205b4844aed9531de8cd9051531 100644 (file)
@@ -137,7 +137,7 @@ static struct regulator_desc tps6105x_regulator_desc = {
  */
 static int __devinit tps6105x_regulator_probe(struct platform_device *pdev)
 {
-       struct tps6105x *tps6105x = mfd_get_data(pdev);
+       struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev);
        struct tps6105x_platform_data *pdata = tps6105x->pdata;
        int ret;
 
@@ -158,13 +158,14 @@ static int __devinit tps6105x_regulator_probe(struct platform_device *pdev)
                        "failed to register regulator\n");
                return ret;
        }
+       platform_set_drvdata(pdev, tps6105x);
 
        return 0;
 }
 
 static int __devexit tps6105x_regulator_remove(struct platform_device *pdev)
 {
-       struct tps6105x *tps6105x = platform_get_drvdata(pdev);
+       struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev);
        regulator_unregister(tps6105x->regulator);
        return 0;
 }
index 60a7ca5409e9766bfe829c0d581d4dca910acc98..fbddc15e1811fefdec139965a425f45a5c05d473 100644 (file)
@@ -466,7 +466,6 @@ static struct regulator_ops tps65023_ldo_ops = {
 static int __devinit tps_65023_probe(struct i2c_client *client,
                                     const struct i2c_device_id *id)
 {
-       static int desc_id;
        const struct tps_info *info = (void *)id->driver_data;
        struct regulator_init_data *init_data;
        struct regulator_dev *rdev;
@@ -499,7 +498,7 @@ static int __devinit tps_65023_probe(struct i2c_client *client,
                tps->info[i] = info;
 
                tps->desc[i].name = info->name;
-               tps->desc[i].id = desc_id++;
+               tps->desc[i].id = i;
                tps->desc[i].n_voltages = num_voltages[i];
                tps->desc[i].ops = (i > TPS65023_DCDC_3 ?
                                        &tps65023_ldo_ops : &tps65023_dcdc_ops);
index 0647552905992348652bc6316e7bec23e3257892..bfffabc21edabdffe051466b9d11b9fd60890400 100644 (file)
@@ -553,7 +553,6 @@ static __devinit
 int tps6507x_pmic_probe(struct platform_device *pdev)
 {
        struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
-       static int desc_id;
        struct tps_info *info = &tps6507x_pmic_regs[0];
        struct regulator_init_data *init_data;
        struct regulator_dev *rdev;
@@ -598,7 +597,7 @@ int tps6507x_pmic_probe(struct platform_device *pdev)
                }
 
                tps->desc[i].name = info->name;
-               tps->desc[i].id = desc_id++;
+               tps->desc[i].id = i;
                tps->desc[i].n_voltages = num_voltages[i];
                tps->desc[i].ops = (i > TPS6507X_DCDC_3 ?
                &tps6507x_pmic_ldo_ops : &tps6507x_pmic_dcdc_ops);
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
new file mode 100644 (file)
index 0000000..55dd4e6
--- /dev/null
@@ -0,0 +1,993 @@
+/*
+ * tps65910.c  --  TI tps65910
+ *
+ * Copyright 2010 Texas Instruments Inc.
+ *
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
+ *
+ *  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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/mfd/tps65910.h>
+
+#define TPS65910_REG_VRTC              0
+#define TPS65910_REG_VIO               1
+#define TPS65910_REG_VDD1              2
+#define TPS65910_REG_VDD2              3
+#define TPS65910_REG_VDD3              4
+#define TPS65910_REG_VDIG1             5
+#define TPS65910_REG_VDIG2             6
+#define TPS65910_REG_VPLL              7
+#define TPS65910_REG_VDAC              8
+#define TPS65910_REG_VAUX1             9
+#define TPS65910_REG_VAUX2             10
+#define TPS65910_REG_VAUX33            11
+#define TPS65910_REG_VMMC              12
+
+#define TPS65911_REG_VDDCTRL           4
+#define TPS65911_REG_LDO1              5
+#define TPS65911_REG_LDO2              6
+#define TPS65911_REG_LDO3              7
+#define TPS65911_REG_LDO4              8
+#define TPS65911_REG_LDO5              9
+#define TPS65911_REG_LDO6              10
+#define TPS65911_REG_LDO7              11
+#define TPS65911_REG_LDO8              12
+
+#define TPS65910_NUM_REGULATOR         13
+#define TPS65910_SUPPLY_STATE_ENABLED  0x1
+
+/* supported VIO voltages in milivolts */
+static const u16 VIO_VSEL_table[] = {
+       1500, 1800, 2500, 3300,
+};
+
+/* VSEL tables for TPS65910 specific LDOs and dcdc's */
+
+/* supported VDD3 voltages in milivolts */
+static const u16 VDD3_VSEL_table[] = {
+       5000,
+};
+
+/* supported VDIG1 voltages in milivolts */
+static const u16 VDIG1_VSEL_table[] = {
+       1200, 1500, 1800, 2700,
+};
+
+/* supported VDIG2 voltages in milivolts */
+static const u16 VDIG2_VSEL_table[] = {
+       1000, 1100, 1200, 1800,
+};
+
+/* supported VPLL voltages in milivolts */
+static const u16 VPLL_VSEL_table[] = {
+       1000, 1100, 1800, 2500,
+};
+
+/* supported VDAC voltages in milivolts */
+static const u16 VDAC_VSEL_table[] = {
+       1800, 2600, 2800, 2850,
+};
+
+/* supported VAUX1 voltages in milivolts */
+static const u16 VAUX1_VSEL_table[] = {
+       1800, 2500, 2800, 2850,
+};
+
+/* supported VAUX2 voltages in milivolts */
+static const u16 VAUX2_VSEL_table[] = {
+       1800, 2800, 2900, 3300,
+};
+
+/* supported VAUX33 voltages in milivolts */
+static const u16 VAUX33_VSEL_table[] = {
+       1800, 2000, 2800, 3300,
+};
+
+/* supported VMMC voltages in milivolts */
+static const u16 VMMC_VSEL_table[] = {
+       1800, 2800, 3000, 3300,
+};
+
+struct tps_info {
+       const char *name;
+       unsigned min_uV;
+       unsigned max_uV;
+       u8 table_len;
+       const u16 *table;
+};
+
+static struct tps_info tps65910_regs[] = {
+       {
+               .name = "VRTC",
+       },
+       {
+               .name = "VIO",
+               .min_uV = 1500000,
+               .max_uV = 3300000,
+               .table_len = ARRAY_SIZE(VIO_VSEL_table),
+               .table = VIO_VSEL_table,
+       },
+       {
+               .name = "VDD1",
+               .min_uV = 600000,
+               .max_uV = 4500000,
+       },
+       {
+               .name = "VDD2",
+               .min_uV = 600000,
+               .max_uV = 4500000,
+       },
+       {
+               .name = "VDD3",
+               .min_uV = 5000000,
+               .max_uV = 5000000,
+               .table_len = ARRAY_SIZE(VDD3_VSEL_table),
+               .table = VDD3_VSEL_table,
+       },
+       {
+               .name = "VDIG1",
+               .min_uV = 1200000,
+               .max_uV = 2700000,
+               .table_len = ARRAY_SIZE(VDIG1_VSEL_table),
+               .table = VDIG1_VSEL_table,
+       },
+       {
+               .name = "VDIG2",
+               .min_uV = 1000000,
+               .max_uV = 1800000,
+               .table_len = ARRAY_SIZE(VDIG2_VSEL_table),
+               .table = VDIG2_VSEL_table,
+       },
+       {
+               .name = "VPLL",
+               .min_uV = 1000000,
+               .max_uV = 2500000,
+               .table_len = ARRAY_SIZE(VPLL_VSEL_table),
+               .table = VPLL_VSEL_table,
+       },
+       {
+               .name = "VDAC",
+               .min_uV = 1800000,
+               .max_uV = 2850000,
+               .table_len = ARRAY_SIZE(VDAC_VSEL_table),
+               .table = VDAC_VSEL_table,
+       },
+       {
+               .name = "VAUX1",
+               .min_uV = 1800000,
+               .max_uV = 2850000,
+               .table_len = ARRAY_SIZE(VAUX1_VSEL_table),
+               .table = VAUX1_VSEL_table,
+       },
+       {
+               .name = "VAUX2",
+               .min_uV = 1800000,
+               .max_uV = 3300000,
+               .table_len = ARRAY_SIZE(VAUX2_VSEL_table),
+               .table = VAUX2_VSEL_table,
+       },
+       {
+               .name = "VAUX33",
+               .min_uV = 1800000,
+               .max_uV = 3300000,
+               .table_len = ARRAY_SIZE(VAUX33_VSEL_table),
+               .table = VAUX33_VSEL_table,
+       },
+       {
+               .name = "VMMC",
+               .min_uV = 1800000,
+               .max_uV = 3300000,
+               .table_len = ARRAY_SIZE(VMMC_VSEL_table),
+               .table = VMMC_VSEL_table,
+       },
+};
+
+static struct tps_info tps65911_regs[] = {
+       {
+               .name = "VIO",
+               .min_uV = 1500000,
+               .max_uV = 3300000,
+               .table_len = ARRAY_SIZE(VIO_VSEL_table),
+               .table = VIO_VSEL_table,
+       },
+       {
+               .name = "VDD1",
+               .min_uV = 600000,
+               .max_uV = 4500000,
+       },
+       {
+               .name = "VDD2",
+               .min_uV = 600000,
+               .max_uV = 4500000,
+       },
+       {
+               .name = "VDDCTRL",
+               .min_uV = 600000,
+               .max_uV = 1400000,
+       },
+       {
+               .name = "LDO1",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+       },
+       {
+               .name = "LDO2",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+       },
+       {
+               .name = "LDO3",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+       },
+       {
+               .name = "LDO4",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+       },
+       {
+               .name = "LDO5",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+       },
+       {
+               .name = "LDO6",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+       },
+       {
+               .name = "LDO7",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+       },
+       {
+               .name = "LDO8",
+               .min_uV = 1000000,
+               .max_uV = 3300000,
+       },
+};
+
+struct tps65910_reg {
+       struct regulator_desc desc[TPS65910_NUM_REGULATOR];
+       struct tps65910 *mfd;
+       struct regulator_dev *rdev[TPS65910_NUM_REGULATOR];
+       struct tps_info *info[TPS65910_NUM_REGULATOR];
+       struct mutex mutex;
+       int mode;
+       int  (*get_ctrl_reg)(int);
+};
+
+static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg)
+{
+       u8 val;
+       int err;
+
+       err = pmic->mfd->read(pmic->mfd, reg, 1, &val);
+       if (err)
+               return err;
+
+       return val;
+}
+
+static inline int tps65910_write(struct tps65910_reg *pmic, u8 reg, u8 val)
+{
+       return pmic->mfd->write(pmic->mfd, reg, 1, &val);
+}
+
+static int tps65910_modify_bits(struct tps65910_reg *pmic, u8 reg,
+                                       u8 set_mask, u8 clear_mask)
+{
+       int err, data;
+
+       mutex_lock(&pmic->mutex);
+
+       data = tps65910_read(pmic, reg);
+       if (data < 0) {
+               dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg);
+               err = data;
+               goto out;
+       }
+
+       data &= ~clear_mask;
+       data |= set_mask;
+       err = tps65910_write(pmic, reg, data);
+       if (err)
+               dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg);
+
+out:
+       mutex_unlock(&pmic->mutex);
+       return err;
+}
+
+static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg)
+{
+       int data;
+
+       mutex_lock(&pmic->mutex);
+
+       data = tps65910_read(pmic, reg);
+       if (data < 0)
+               dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg);
+
+       mutex_unlock(&pmic->mutex);
+       return data;
+}
+
+static int tps65910_reg_write(struct tps65910_reg *pmic, u8 reg, u8 val)
+{
+       int err;
+
+       mutex_lock(&pmic->mutex);
+
+       err = tps65910_write(pmic, reg, val);
+       if (err < 0)
+               dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg);
+
+       mutex_unlock(&pmic->mutex);
+       return err;
+}
+
+static int tps65910_get_ctrl_register(int id)
+{
+       switch (id) {
+       case TPS65910_REG_VRTC:
+               return TPS65910_VRTC;
+       case TPS65910_REG_VIO:
+               return TPS65910_VIO;
+       case TPS65910_REG_VDD1:
+               return TPS65910_VDD1;
+       case TPS65910_REG_VDD2:
+               return TPS65910_VDD2;
+       case TPS65910_REG_VDD3:
+               return TPS65910_VDD3;
+       case TPS65910_REG_VDIG1:
+               return TPS65910_VDIG1;
+       case TPS65910_REG_VDIG2:
+               return TPS65910_VDIG2;
+       case TPS65910_REG_VPLL:
+               return TPS65910_VPLL;
+       case TPS65910_REG_VDAC:
+               return TPS65910_VDAC;
+       case TPS65910_REG_VAUX1:
+               return TPS65910_VAUX1;
+       case TPS65910_REG_VAUX2:
+               return TPS65910_VAUX2;
+       case TPS65910_REG_VAUX33:
+               return TPS65910_VAUX33;
+       case TPS65910_REG_VMMC:
+               return TPS65910_VMMC;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int tps65911_get_ctrl_register(int id)
+{
+       switch (id) {
+       case TPS65910_REG_VRTC:
+               return TPS65910_VRTC;
+       case TPS65910_REG_VIO:
+               return TPS65910_VIO;
+       case TPS65910_REG_VDD1:
+               return TPS65910_VDD1;
+       case TPS65910_REG_VDD2:
+               return TPS65910_VDD2;
+       case TPS65911_REG_VDDCTRL:
+               return TPS65911_VDDCTRL;
+       case TPS65911_REG_LDO1:
+               return TPS65911_LDO1;
+       case TPS65911_REG_LDO2:
+               return TPS65911_LDO2;
+       case TPS65911_REG_LDO3:
+               return TPS65911_LDO3;
+       case TPS65911_REG_LDO4:
+               return TPS65911_LDO4;
+       case TPS65911_REG_LDO5:
+               return TPS65911_LDO5;
+       case TPS65911_REG_LDO6:
+               return TPS65911_LDO6;
+       case TPS65911_REG_LDO7:
+               return TPS65911_LDO7;
+       case TPS65911_REG_LDO8:
+               return TPS65911_LDO8;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int tps65910_is_enabled(struct regulator_dev *dev)
+{
+       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+       int reg, value, id = rdev_get_id(dev);
+
+       reg = pmic->get_ctrl_reg(id);
+       if (reg < 0)
+               return reg;
+
+       value = tps65910_reg_read(pmic, reg);
+       if (value < 0)
+               return value;
+
+       return value & TPS65910_SUPPLY_STATE_ENABLED;
+}
+
+static int tps65910_enable(struct regulator_dev *dev)
+{
+       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65910 *mfd = pmic->mfd;
+       int reg, id = rdev_get_id(dev);
+
+       reg = pmic->get_ctrl_reg(id);
+       if (reg < 0)
+               return reg;
+
+       return tps65910_set_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED);
+}
+
+static int tps65910_disable(struct regulator_dev *dev)
+{
+       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65910 *mfd = pmic->mfd;
+       int reg, id = rdev_get_id(dev);
+
+       reg = pmic->get_ctrl_reg(id);
+       if (reg < 0)
+               return reg;
+
+       return tps65910_clear_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED);
+}
+
+
+static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode)
+{
+       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65910 *mfd = pmic->mfd;
+       int reg, value, id = rdev_get_id(dev);
+
+       reg = pmic->get_ctrl_reg(id);
+       if (reg < 0)
+               return reg;
+
+       switch (mode) {
+       case REGULATOR_MODE_NORMAL:
+               return tps65910_modify_bits(pmic, reg, LDO_ST_ON_BIT,
+                                                       LDO_ST_MODE_BIT);
+       case REGULATOR_MODE_IDLE:
+               value = LDO_ST_ON_BIT | LDO_ST_MODE_BIT;
+               return tps65910_set_bits(mfd, reg, value);
+       case REGULATOR_MODE_STANDBY:
+               return tps65910_clear_bits(mfd, reg, LDO_ST_ON_BIT);
+       }
+
+       return -EINVAL;
+}
+
+static unsigned int tps65910_get_mode(struct regulator_dev *dev)
+{
+       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+       int reg, value, id = rdev_get_id(dev);
+
+       reg = pmic->get_ctrl_reg(id);
+       if (reg < 0)
+               return reg;
+
+       value = tps65910_reg_read(pmic, reg);
+       if (value < 0)
+               return value;
+
+       if (value & LDO_ST_ON_BIT)
+               return REGULATOR_MODE_STANDBY;
+       else if (value & LDO_ST_MODE_BIT)
+               return REGULATOR_MODE_IDLE;
+       else
+               return REGULATOR_MODE_NORMAL;
+}
+
+static int tps65910_get_voltage_dcdc(struct regulator_dev *dev)
+{
+       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+       int id = rdev_get_id(dev), voltage = 0;
+       int opvsel = 0, srvsel = 0, vselmax = 0, mult = 0, sr = 0;
+
+       switch (id) {
+       case TPS65910_REG_VDD1:
+               opvsel = tps65910_reg_read(pmic, TPS65910_VDD1_OP);
+               mult = tps65910_reg_read(pmic, TPS65910_VDD1);
+               mult = (mult & VDD1_VGAIN_SEL_MASK) >> VDD1_VGAIN_SEL_SHIFT;
+               srvsel = tps65910_reg_read(pmic, TPS65910_VDD1_SR);
+               sr = opvsel & VDD1_OP_CMD_MASK;
+               opvsel &= VDD1_OP_SEL_MASK;
+               srvsel &= VDD1_SR_SEL_MASK;
+               vselmax = 75;
+               break;
+       case TPS65910_REG_VDD2:
+               opvsel = tps65910_reg_read(pmic, TPS65910_VDD2_OP);
+               mult = tps65910_reg_read(pmic, TPS65910_VDD2);
+               mult = (mult & VDD2_VGAIN_SEL_MASK) >> VDD2_VGAIN_SEL_SHIFT;
+               srvsel = tps65910_reg_read(pmic, TPS65910_VDD2_SR);
+               sr = opvsel & VDD2_OP_CMD_MASK;
+               opvsel &= VDD2_OP_SEL_MASK;
+               srvsel &= VDD2_SR_SEL_MASK;
+               vselmax = 75;
+               break;
+       case TPS65911_REG_VDDCTRL:
+               opvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_OP);
+               srvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_SR);
+               sr = opvsel & VDDCTRL_OP_CMD_MASK;
+               opvsel &= VDDCTRL_OP_SEL_MASK;
+               srvsel &= VDDCTRL_SR_SEL_MASK;
+               vselmax = 64;
+               break;
+       }
+
+       /* multiplier 0 == 1 but 2,3 normal */
+       if (!mult)
+               mult=1;
+
+       if (sr) {
+               /* normalise to valid range */
+               if (srvsel < 3)
+                       srvsel = 3;
+               if (srvsel > vselmax)
+                       srvsel = vselmax;
+               srvsel -= 3;
+
+               voltage = (srvsel * VDD1_2_OFFSET + VDD1_2_MIN_VOLT) * 100;
+       } else {
+
+               /* normalise to valid range*/
+               if (opvsel < 3)
+                       opvsel = 3;
+               if (opvsel > vselmax)
+                       opvsel = vselmax;
+               opvsel -= 3;
+
+               voltage = (opvsel * VDD1_2_OFFSET + VDD1_2_MIN_VOLT) * 100;
+       }
+
+       voltage *= mult;
+
+       return voltage;
+}
+
+static int tps65910_get_voltage(struct regulator_dev *dev)
+{
+       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+       int reg, value, id = rdev_get_id(dev), voltage = 0;
+
+       reg = pmic->get_ctrl_reg(id);
+       if (reg < 0)
+               return reg;
+
+       value = tps65910_reg_read(pmic, reg);
+       if (value < 0)
+               return value;
+
+       switch (id) {
+       case TPS65910_REG_VIO:
+       case TPS65910_REG_VDIG1:
+       case TPS65910_REG_VDIG2:
+       case TPS65910_REG_VPLL:
+       case TPS65910_REG_VDAC:
+       case TPS65910_REG_VAUX1:
+       case TPS65910_REG_VAUX2:
+       case TPS65910_REG_VAUX33:
+       case TPS65910_REG_VMMC:
+               value &= LDO_SEL_MASK;
+               value >>= LDO_SEL_SHIFT;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       voltage = pmic->info[id]->table[value] * 1000;
+
+       return voltage;
+}
+
+static int tps65910_get_voltage_vdd3(struct regulator_dev *dev)
+{
+       return 5 * 1000 * 1000;
+}
+
+static int tps65911_get_voltage(struct regulator_dev *dev)
+{
+       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+       int step_mv, id = rdev_get_id(dev);
+       u8 value, reg;
+
+       reg = pmic->get_ctrl_reg(id);
+
+       value = tps65910_reg_read(pmic, reg);
+
+       switch (id) {
+       case TPS65911_REG_LDO1:
+       case TPS65911_REG_LDO2:
+       case TPS65911_REG_LDO4:
+               value &= LDO1_SEL_MASK;
+               value >>= LDO_SEL_SHIFT;
+               /* The first 5 values of the selector correspond to 1V */
+               if (value < 5)
+                       value = 0;
+               else
+                       value -= 4;
+
+               step_mv = 50;
+               break;
+       case TPS65911_REG_LDO3:
+       case TPS65911_REG_LDO5:
+       case TPS65911_REG_LDO6:
+       case TPS65911_REG_LDO7:
+       case TPS65911_REG_LDO8:
+               value &= LDO3_SEL_MASK;
+               value >>= LDO_SEL_SHIFT;
+               /* The first 3 values of the selector correspond to 1V */
+               if (value < 3)
+                       value = 0;
+               else
+                       value -= 2;
+
+               step_mv = 100;
+               break;
+       case TPS65910_REG_VIO:
+               return pmic->info[id]->table[value] * 1000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return (LDO_MIN_VOLT + value * step_mv) * 1000;
+}
+
+static int tps65910_set_voltage_dcdc(struct regulator_dev *dev,
+                               unsigned selector)
+{
+       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+       int id = rdev_get_id(dev), vsel;
+       int dcdc_mult = 0;
+
+       switch (id) {
+       case TPS65910_REG_VDD1:
+               dcdc_mult = (selector / VDD1_2_NUM_VOLTS) + 1;
+               if (dcdc_mult == 1)
+                       dcdc_mult--;
+               vsel = (selector % VDD1_2_NUM_VOLTS) + 3;
+
+               tps65910_modify_bits(pmic, TPS65910_VDD1,
+                               (dcdc_mult << VDD1_VGAIN_SEL_SHIFT),
+                                               VDD1_VGAIN_SEL_MASK);
+               tps65910_reg_write(pmic, TPS65910_VDD1_OP, vsel);
+               break;
+       case TPS65910_REG_VDD2:
+               dcdc_mult = (selector / VDD1_2_NUM_VOLTS) + 1;
+               if (dcdc_mult == 1)
+                       dcdc_mult--;
+               vsel = (selector % VDD1_2_NUM_VOLTS) + 3;
+
+               tps65910_modify_bits(pmic, TPS65910_VDD2,
+                               (dcdc_mult << VDD2_VGAIN_SEL_SHIFT),
+                                               VDD1_VGAIN_SEL_MASK);
+               tps65910_reg_write(pmic, TPS65910_VDD2_OP, vsel);
+               break;
+       case TPS65911_REG_VDDCTRL:
+               vsel = selector;
+               tps65910_reg_write(pmic, TPS65911_VDDCTRL_OP, vsel);
+       }
+
+       return 0;
+}
+
+static int tps65910_set_voltage(struct regulator_dev *dev, unsigned selector)
+{
+       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+       int reg, id = rdev_get_id(dev);
+
+       reg = pmic->get_ctrl_reg(id);
+       if (reg < 0)
+               return reg;
+
+       switch (id) {
+       case TPS65910_REG_VIO:
+       case TPS65910_REG_VDIG1:
+       case TPS65910_REG_VDIG2:
+       case TPS65910_REG_VPLL:
+       case TPS65910_REG_VDAC:
+       case TPS65910_REG_VAUX1:
+       case TPS65910_REG_VAUX2:
+       case TPS65910_REG_VAUX33:
+       case TPS65910_REG_VMMC:
+               return tps65910_modify_bits(pmic, reg,
+                               (selector << LDO_SEL_SHIFT), LDO_SEL_MASK);
+       }
+
+       return -EINVAL;
+}
+
+static int tps65911_set_voltage(struct regulator_dev *dev, unsigned selector)
+{
+       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+       int reg, id = rdev_get_id(dev);
+
+       reg = pmic->get_ctrl_reg(id);
+       if (reg < 0)
+               return reg;
+
+       switch (id) {
+       case TPS65911_REG_LDO1:
+       case TPS65911_REG_LDO2:
+       case TPS65911_REG_LDO4:
+               return tps65910_modify_bits(pmic, reg,
+                               (selector << LDO_SEL_SHIFT), LDO1_SEL_MASK);
+       case TPS65911_REG_LDO3:
+       case TPS65911_REG_LDO5:
+       case TPS65911_REG_LDO6:
+       case TPS65911_REG_LDO7:
+       case TPS65911_REG_LDO8:
+       case TPS65910_REG_VIO:
+               return tps65910_modify_bits(pmic, reg,
+                               (selector << LDO_SEL_SHIFT), LDO3_SEL_MASK);
+       }
+
+       return -EINVAL;
+}
+
+
+static int tps65910_list_voltage_dcdc(struct regulator_dev *dev,
+                                       unsigned selector)
+{
+       int volt, mult = 1, id = rdev_get_id(dev);
+
+       switch (id) {
+       case TPS65910_REG_VDD1:
+       case TPS65910_REG_VDD2:
+               mult = (selector / VDD1_2_NUM_VOLTS) + 1;
+               volt = VDD1_2_MIN_VOLT +
+                               (selector % VDD1_2_NUM_VOLTS) * VDD1_2_OFFSET;
+       case TPS65911_REG_VDDCTRL:
+               volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET);
+       }
+
+       return  volt * 100 * mult;
+}
+
+static int tps65910_list_voltage(struct regulator_dev *dev,
+                                       unsigned selector)
+{
+       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+       int id = rdev_get_id(dev), voltage;
+
+       if (id < TPS65910_REG_VIO || id > TPS65910_REG_VMMC)
+               return -EINVAL;
+
+       if (selector >= pmic->info[id]->table_len)
+               return -EINVAL;
+       else
+               voltage = pmic->info[id]->table[selector] * 1000;
+
+       return voltage;
+}
+
+static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector)
+{
+       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+       int step_mv = 0, id = rdev_get_id(dev);
+
+       switch(id) {
+       case TPS65911_REG_LDO1:
+       case TPS65911_REG_LDO2:
+       case TPS65911_REG_LDO4:
+               /* The first 5 values of the selector correspond to 1V */
+               if (selector < 5)
+                       selector = 0;
+               else
+                       selector -= 4;
+
+               step_mv = 50;
+               break;
+       case TPS65911_REG_LDO3:
+       case TPS65911_REG_LDO5:
+       case TPS65911_REG_LDO6:
+       case TPS65911_REG_LDO7:
+       case TPS65911_REG_LDO8:
+               /* The first 3 values of the selector correspond to 1V */
+               if (selector < 3)
+                       selector = 0;
+               else
+                       selector -= 2;
+
+               step_mv = 100;
+               break;
+       case TPS65910_REG_VIO:
+               return pmic->info[id]->table[selector] * 1000;
+       default:
+               return -EINVAL;
+       }
+
+       return (LDO_MIN_VOLT + selector * step_mv) * 1000;
+}
+
+/* Regulator ops (except VRTC) */
+static struct regulator_ops tps65910_ops_dcdc = {
+       .is_enabled             = tps65910_is_enabled,
+       .enable                 = tps65910_enable,
+       .disable                = tps65910_disable,
+       .set_mode               = tps65910_set_mode,
+       .get_mode               = tps65910_get_mode,
+       .get_voltage            = tps65910_get_voltage_dcdc,
+       .set_voltage_sel        = tps65910_set_voltage_dcdc,
+       .list_voltage           = tps65910_list_voltage_dcdc,
+};
+
+static struct regulator_ops tps65910_ops_vdd3 = {
+       .is_enabled             = tps65910_is_enabled,
+       .enable                 = tps65910_enable,
+       .disable                = tps65910_disable,
+       .set_mode               = tps65910_set_mode,
+       .get_mode               = tps65910_get_mode,
+       .get_voltage            = tps65910_get_voltage_vdd3,
+       .list_voltage           = tps65910_list_voltage,
+};
+
+static struct regulator_ops tps65910_ops = {
+       .is_enabled             = tps65910_is_enabled,
+       .enable                 = tps65910_enable,
+       .disable                = tps65910_disable,
+       .set_mode               = tps65910_set_mode,
+       .get_mode               = tps65910_get_mode,
+       .get_voltage            = tps65910_get_voltage,
+       .set_voltage_sel        = tps65910_set_voltage,
+       .list_voltage           = tps65910_list_voltage,
+};
+
+static struct regulator_ops tps65911_ops = {
+       .is_enabled             = tps65910_is_enabled,
+       .enable                 = tps65910_enable,
+       .disable                = tps65910_disable,
+       .set_mode               = tps65910_set_mode,
+       .get_mode               = tps65910_get_mode,
+       .get_voltage            = tps65911_get_voltage,
+       .set_voltage_sel        = tps65911_set_voltage,
+       .list_voltage           = tps65911_list_voltage,
+};
+
+static __devinit int tps65910_probe(struct platform_device *pdev)
+{
+       struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
+       struct tps_info *info;
+       struct regulator_init_data *reg_data;
+       struct regulator_dev *rdev;
+       struct tps65910_reg *pmic;
+       struct tps65910_board *pmic_plat_data;
+       int i, err;
+
+       pmic_plat_data = dev_get_platdata(tps65910->dev);
+       if (!pmic_plat_data)
+               return -EINVAL;
+
+       reg_data = pmic_plat_data->tps65910_pmic_init_data;
+
+       pmic = kzalloc(sizeof(*pmic), GFP_KERNEL);
+       if (!pmic)
+               return -ENOMEM;
+
+       mutex_init(&pmic->mutex);
+       pmic->mfd = tps65910;
+       platform_set_drvdata(pdev, pmic);
+
+       /* Give control of all register to control port */
+       tps65910_set_bits(pmic->mfd, TPS65910_DEVCTRL,
+                               DEVCTRL_SR_CTL_I2C_SEL_MASK);
+
+       switch(tps65910_chip_id(tps65910)) {
+       case TPS65910:
+               pmic->get_ctrl_reg = &tps65910_get_ctrl_register;
+               info = tps65910_regs;
+       case TPS65911:
+               pmic->get_ctrl_reg = &tps65911_get_ctrl_register;
+               info = tps65911_regs;
+       default:
+               pr_err("Invalid tps chip version\n");
+               return -ENODEV;
+       }
+
+       for (i = 0; i < TPS65910_NUM_REGULATOR; i++, info++, reg_data++) {
+               /* Register the regulators */
+               pmic->info[i] = info;
+
+               pmic->desc[i].name = info->name;
+               pmic->desc[i].id = i;
+               pmic->desc[i].n_voltages = info->table_len;
+
+               if (i == TPS65910_REG_VDD1 || i == TPS65910_REG_VDD2) {
+                       pmic->desc[i].ops = &tps65910_ops_dcdc;
+               } else if (i == TPS65910_REG_VDD3) {
+                       if (tps65910_chip_id(tps65910) == TPS65910)
+                               pmic->desc[i].ops = &tps65910_ops_vdd3;
+                       else
+                               pmic->desc[i].ops = &tps65910_ops_dcdc;
+               } else {
+                       if (tps65910_chip_id(tps65910) == TPS65910)
+                               pmic->desc[i].ops = &tps65910_ops;
+                       else
+                               pmic->desc[i].ops = &tps65911_ops;
+               }
+
+               pmic->desc[i].type = REGULATOR_VOLTAGE;
+               pmic->desc[i].owner = THIS_MODULE;
+
+               rdev = regulator_register(&pmic->desc[i],
+                               tps65910->dev, reg_data, pmic);
+               if (IS_ERR(rdev)) {
+                       dev_err(tps65910->dev,
+                               "failed to register %s regulator\n",
+                               pdev->name);
+                       err = PTR_ERR(rdev);
+                       goto err;
+               }
+
+               /* Save regulator for cleanup */
+               pmic->rdev[i] = rdev;
+       }
+       return 0;
+
+err:
+       while (--i >= 0)
+               regulator_unregister(pmic->rdev[i]);
+
+       kfree(pmic);
+       return err;
+}
+
+static int __devexit tps65910_remove(struct platform_device *pdev)
+{
+       struct tps65910_reg *tps65910_reg = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < TPS65910_NUM_REGULATOR; i++)
+               regulator_unregister(tps65910_reg->rdev[i]);
+
+       kfree(tps65910_reg);
+       return 0;
+}
+
+static struct platform_driver tps65910_driver = {
+       .driver = {
+               .name = "tps65910-pmic",
+               .owner = THIS_MODULE,
+       },
+       .probe = tps65910_probe,
+       .remove = __devexit_p(tps65910_remove),
+};
+
+static int __init tps65910_init(void)
+{
+       return platform_driver_register(&tps65910_driver);
+}
+subsys_initcall(tps65910_init);
+
+static void __exit tps65910_cleanup(void)
+{
+       platform_driver_unregister(&tps65910_driver);
+}
+module_exit(tps65910_cleanup);
+
+MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
+MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tps65910-pmic");
index 6a292852a3583899a1d1c1a2c3236e76aea6d118..87fe0f75a56eed01375e0e2a393dbea6c1cd98b2 100644 (file)
@@ -51,8 +51,13 @@ struct twlreg_info {
        u16                     min_mV;
        u16                     max_mV;
 
+       u8                      flags;
+
        /* used by regulator core */
        struct regulator_desc   desc;
+
+       /* chip specific features */
+       unsigned long           features;
 };
 
 
@@ -70,12 +75,35 @@ struct twlreg_info {
 #define VREG_TRANS             1
 #define VREG_STATE             2
 #define VREG_VOLTAGE           3
+#define VREG_VOLTAGE_SMPS      4
 /* TWL6030 Misc register offsets */
 #define VREG_BC_ALL            1
 #define VREG_BC_REF            2
 #define VREG_BC_PROC           3
 #define VREG_BC_CLK_RST                4
 
+/* TWL6030 LDO register values for CFG_STATE */
+#define TWL6030_CFG_STATE_OFF  0x00
+#define TWL6030_CFG_STATE_ON   0x01
+#define TWL6030_CFG_STATE_OFF2 0x02
+#define TWL6030_CFG_STATE_SLEEP        0x03
+#define TWL6030_CFG_STATE_GRP_SHIFT    5
+#define TWL6030_CFG_STATE_APP_SHIFT    2
+#define TWL6030_CFG_STATE_APP_MASK     (0x03 << TWL6030_CFG_STATE_APP_SHIFT)
+#define TWL6030_CFG_STATE_APP(v)       (((v) & TWL6030_CFG_STATE_APP_MASK) >>\
+                                               TWL6030_CFG_STATE_APP_SHIFT)
+
+/* Flags for SMPS Voltage reading */
+#define SMPS_OFFSET_EN         BIT(0)
+#define SMPS_EXTENDED_EN       BIT(1)
+
+/* twl6025 SMPS EPROM values */
+#define TWL6030_SMPS_OFFSET            0xB0
+#define TWL6030_SMPS_MULT              0xB3
+#define SMPS_MULTOFFSET_SMPS4  BIT(0)
+#define SMPS_MULTOFFSET_VIO    BIT(1)
+#define SMPS_MULTOFFSET_SMPS3  BIT(6)
+
 static inline int
 twlreg_read(struct twlreg_info *info, unsigned slave_subgp, unsigned offset)
 {
@@ -118,21 +146,38 @@ static int twlreg_grp(struct regulator_dev *rdev)
 #define P2_GRP_6030    BIT(1)          /* "peripherals" */
 #define P1_GRP_6030    BIT(0)          /* CPU/Linux */
 
-static int twlreg_is_enabled(struct regulator_dev *rdev)
+static int twl4030reg_is_enabled(struct regulator_dev *rdev)
 {
        int     state = twlreg_grp(rdev);
 
        if (state < 0)
                return state;
 
-       if (twl_class_is_4030())
-               state &= P1_GRP_4030;
+       return state & P1_GRP_4030;
+}
+
+static int twl6030reg_is_enabled(struct regulator_dev *rdev)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     grp = 0, val;
+
+       if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+               grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+       if (grp < 0)
+               return grp;
+
+       if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+               grp &= P1_GRP_6030;
        else
-               state &= P1_GRP_6030;
-       return state;
+               grp = 1;
+
+       val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
+       val = TWL6030_CFG_STATE_APP(val);
+
+       return grp && (val == TWL6030_CFG_STATE_ON);
 }
 
-static int twlreg_enable(struct regulator_dev *rdev)
+static int twl4030reg_enable(struct regulator_dev *rdev)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
        int                     grp;
@@ -142,10 +187,7 @@ static int twlreg_enable(struct regulator_dev *rdev)
        if (grp < 0)
                return grp;
 
-       if (twl_class_is_4030())
-               grp |= P1_GRP_4030;
-       else
-               grp |= P1_GRP_6030;
+       grp |= P1_GRP_4030;
 
        ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
 
@@ -154,29 +196,63 @@ static int twlreg_enable(struct regulator_dev *rdev)
        return ret;
 }
 
-static int twlreg_disable(struct regulator_dev *rdev)
+static int twl6030reg_enable(struct regulator_dev *rdev)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     grp = 0;
+       int                     ret;
+
+       if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+               grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+       if (grp < 0)
+               return grp;
+
+       ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE,
+                       grp << TWL6030_CFG_STATE_GRP_SHIFT |
+                       TWL6030_CFG_STATE_ON);
+
+       udelay(info->delay);
+
+       return ret;
+}
+
+static int twl4030reg_disable(struct regulator_dev *rdev)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
        int                     grp;
+       int                     ret;
 
        grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
        if (grp < 0)
                return grp;
 
-       if (twl_class_is_4030())
-               grp &= ~(P1_GRP_4030 | P2_GRP_4030 | P3_GRP_4030);
-       else
-               grp &= ~(P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030);
+       grp &= ~(P1_GRP_4030 | P2_GRP_4030 | P3_GRP_4030);
 
-       return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
+       ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
+
+       return ret;
 }
 
-static int twlreg_get_status(struct regulator_dev *rdev)
+static int twl6030reg_disable(struct regulator_dev *rdev)
 {
-       int     state = twlreg_grp(rdev);
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     grp = 0;
+       int                     ret;
+
+       if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+               grp = P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030;
+
+       /* For 6030, set the off state for all grps enabled */
+       ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE,
+                       (grp) << TWL6030_CFG_STATE_GRP_SHIFT |
+                       TWL6030_CFG_STATE_OFF);
+
+       return ret;
+}
 
-       if (twl_class_is_6030())
-               return 0; /* FIXME return for 6030 regulator */
+static int twl4030reg_get_status(struct regulator_dev *rdev)
+{
+       int     state = twlreg_grp(rdev);
 
        if (state < 0)
                return state;
@@ -190,15 +266,39 @@ static int twlreg_get_status(struct regulator_dev *rdev)
                : REGULATOR_STATUS_STANDBY;
 }
 
-static int twlreg_set_mode(struct regulator_dev *rdev, unsigned mode)
+static int twl6030reg_get_status(struct regulator_dev *rdev)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int                     val;
+
+       val = twlreg_grp(rdev);
+       if (val < 0)
+               return val;
+
+       val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
+
+       switch (TWL6030_CFG_STATE_APP(val)) {
+       case TWL6030_CFG_STATE_ON:
+               return REGULATOR_STATUS_NORMAL;
+
+       case TWL6030_CFG_STATE_SLEEP:
+               return REGULATOR_STATUS_STANDBY;
+
+       case TWL6030_CFG_STATE_OFF:
+       case TWL6030_CFG_STATE_OFF2:
+       default:
+               break;
+       }
+
+       return REGULATOR_STATUS_OFF;
+}
+
+static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
        unsigned                message;
        int                     status;
 
-       if (twl_class_is_6030())
-               return 0; /* FIXME return for 6030 regulator */
-
        /* We can only set the mode through state machine commands... */
        switch (mode) {
        case REGULATOR_MODE_NORMAL:
@@ -227,6 +327,36 @@ static int twlreg_set_mode(struct regulator_dev *rdev, unsigned mode)
                        message & 0xff, TWL4030_PM_MASTER_PB_WORD_LSB);
 }
 
+static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int grp = 0;
+       int val;
+
+       if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+               grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+
+       if (grp < 0)
+               return grp;
+
+       /* Compose the state register settings */
+       val = grp << TWL6030_CFG_STATE_GRP_SHIFT;
+       /* We can only set the mode through state machine commands... */
+       switch (mode) {
+       case REGULATOR_MODE_NORMAL:
+               val |= TWL6030_CFG_STATE_ON;
+               break;
+       case REGULATOR_MODE_STANDBY:
+               val |= TWL6030_CFG_STATE_SLEEP;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, val);
+}
+
 /*----------------------------------------------------------------------*/
 
 /*
@@ -375,13 +505,13 @@ static struct regulator_ops twl4030ldo_ops = {
        .set_voltage    = twl4030ldo_set_voltage,
        .get_voltage    = twl4030ldo_get_voltage,
 
-       .enable         = twlreg_enable,
-       .disable        = twlreg_disable,
-       .is_enabled     = twlreg_is_enabled,
+       .enable         = twl4030reg_enable,
+       .disable        = twl4030reg_disable,
+       .is_enabled     = twl4030reg_is_enabled,
 
-       .set_mode       = twlreg_set_mode,
+       .set_mode       = twl4030reg_set_mode,
 
-       .get_status     = twlreg_get_status,
+       .get_status     = twl4030reg_get_status,
 };
 
 static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
@@ -433,13 +563,13 @@ static struct regulator_ops twl6030ldo_ops = {
        .set_voltage    = twl6030ldo_set_voltage,
        .get_voltage    = twl6030ldo_get_voltage,
 
-       .enable         = twlreg_enable,
-       .disable        = twlreg_disable,
-       .is_enabled     = twlreg_is_enabled,
+       .enable         = twl6030reg_enable,
+       .disable        = twl6030reg_disable,
+       .is_enabled     = twl6030reg_is_enabled,
 
-       .set_mode       = twlreg_set_mode,
+       .set_mode       = twl6030reg_set_mode,
 
-       .get_status     = twlreg_get_status,
+       .get_status     = twl6030reg_get_status,
 };
 
 /*----------------------------------------------------------------------*/
@@ -461,25 +591,242 @@ static int twlfixed_get_voltage(struct regulator_dev *rdev)
        return info->min_mV * 1000;
 }
 
-static struct regulator_ops twlfixed_ops = {
+static struct regulator_ops twl4030fixed_ops = {
+       .list_voltage   = twlfixed_list_voltage,
+
+       .get_voltage    = twlfixed_get_voltage,
+
+       .enable         = twl4030reg_enable,
+       .disable        = twl4030reg_disable,
+       .is_enabled     = twl4030reg_is_enabled,
+
+       .set_mode       = twl4030reg_set_mode,
+
+       .get_status     = twl4030reg_get_status,
+};
+
+static struct regulator_ops twl6030fixed_ops = {
        .list_voltage   = twlfixed_list_voltage,
 
        .get_voltage    = twlfixed_get_voltage,
 
-       .enable         = twlreg_enable,
-       .disable        = twlreg_disable,
-       .is_enabled     = twlreg_is_enabled,
+       .enable         = twl6030reg_enable,
+       .disable        = twl6030reg_disable,
+       .is_enabled     = twl6030reg_is_enabled,
 
-       .set_mode       = twlreg_set_mode,
+       .set_mode       = twl6030reg_set_mode,
 
-       .get_status     = twlreg_get_status,
+       .get_status     = twl6030reg_get_status,
 };
 
 static struct regulator_ops twl6030_fixed_resource = {
-       .enable         = twlreg_enable,
-       .disable        = twlreg_disable,
-       .is_enabled     = twlreg_is_enabled,
-       .get_status     = twlreg_get_status,
+       .enable         = twl6030reg_enable,
+       .disable        = twl6030reg_disable,
+       .is_enabled     = twl6030reg_is_enabled,
+       .get_status     = twl6030reg_get_status,
+};
+
+/*
+ * SMPS status and control
+ */
+
+static int twl6030smps_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+
+       int voltage = 0;
+
+       switch (info->flags) {
+       case SMPS_OFFSET_EN:
+               voltage = 100000;
+               /* fall through */
+       case 0:
+               switch (index) {
+               case 0:
+                       voltage = 0;
+                       break;
+               case 58:
+                       voltage = 1350 * 1000;
+                       break;
+               case 59:
+                       voltage = 1500 * 1000;
+                       break;
+               case 60:
+                       voltage = 1800 * 1000;
+                       break;
+               case 61:
+                       voltage = 1900 * 1000;
+                       break;
+               case 62:
+                       voltage = 2100 * 1000;
+                       break;
+               default:
+                       voltage += (600000 + (12500 * (index - 1)));
+               }
+               break;
+       case SMPS_EXTENDED_EN:
+               switch (index) {
+               case 0:
+                       voltage = 0;
+                       break;
+               case 58:
+                       voltage = 2084 * 1000;
+                       break;
+               case 59:
+                       voltage = 2315 * 1000;
+                       break;
+               case 60:
+                       voltage = 2778 * 1000;
+                       break;
+               case 61:
+                       voltage = 2932 * 1000;
+                       break;
+               case 62:
+                       voltage = 3241 * 1000;
+                       break;
+               default:
+                       voltage = (1852000 + (38600 * (index - 1)));
+               }
+               break;
+       case SMPS_OFFSET_EN | SMPS_EXTENDED_EN:
+               switch (index) {
+               case 0:
+                       voltage = 0;
+                       break;
+               case 58:
+                       voltage = 4167 * 1000;
+                       break;
+               case 59:
+                       voltage = 2315 * 1000;
+                       break;
+               case 60:
+                       voltage = 2778 * 1000;
+                       break;
+               case 61:
+                       voltage = 2932 * 1000;
+                       break;
+               case 62:
+                       voltage = 3241 * 1000;
+                       break;
+               default:
+                       voltage = (2161000 + (38600 * (index - 1)));
+               }
+               break;
+       }
+
+       return voltage;
+}
+
+static int
+twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
+                       unsigned int *selector)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       int     vsel = 0;
+
+       switch (info->flags) {
+       case 0:
+               if (min_uV == 0)
+                       vsel = 0;
+               else if ((min_uV >= 600000) && (max_uV <= 1300000)) {
+                       vsel = (min_uV - 600000) / 125;
+                       if (vsel % 100)
+                               vsel += 100;
+                       vsel /= 100;
+                       vsel++;
+               }
+               /* Values 1..57 for vsel are linear and can be calculated
+                * values 58..62 are non linear.
+                */
+               else if ((min_uV > 1900000) && (max_uV >= 2100000))
+                       vsel = 62;
+               else if ((min_uV > 1800000) && (max_uV >= 1900000))
+                       vsel = 61;
+               else if ((min_uV > 1500000) && (max_uV >= 1800000))
+                       vsel = 60;
+               else if ((min_uV > 1350000) && (max_uV >= 1500000))
+                       vsel = 59;
+               else if ((min_uV > 1300000) && (max_uV >= 1350000))
+                       vsel = 58;
+               else
+                       return -EINVAL;
+               break;
+       case SMPS_OFFSET_EN:
+               if (min_uV == 0)
+                       vsel = 0;
+               else if ((min_uV >= 700000) && (max_uV <= 1420000)) {
+                       vsel = (min_uV - 700000) / 125;
+                       if (vsel % 100)
+                               vsel += 100;
+                       vsel /= 100;
+                       vsel++;
+               }
+               /* Values 1..57 for vsel are linear and can be calculated
+                * values 58..62 are non linear.
+                */
+               else if ((min_uV > 1900000) && (max_uV >= 2100000))
+                       vsel = 62;
+               else if ((min_uV > 1800000) && (max_uV >= 1900000))
+                       vsel = 61;
+               else if ((min_uV > 1350000) && (max_uV >= 1800000))
+                       vsel = 60;
+               else if ((min_uV > 1350000) && (max_uV >= 1500000))
+                       vsel = 59;
+               else if ((min_uV > 1300000) && (max_uV >= 1350000))
+                       vsel = 58;
+               else
+                       return -EINVAL;
+               break;
+       case SMPS_EXTENDED_EN:
+               if (min_uV == 0)
+                       vsel = 0;
+               else if ((min_uV >= 1852000) && (max_uV <= 4013600)) {
+                       vsel = (min_uV - 1852000) / 386;
+                       if (vsel % 100)
+                               vsel += 100;
+                       vsel /= 100;
+                       vsel++;
+               }
+               break;
+       case SMPS_OFFSET_EN|SMPS_EXTENDED_EN:
+               if (min_uV == 0)
+                       vsel = 0;
+               else if ((min_uV >= 2161000) && (max_uV <= 4321000)) {
+                       vsel = (min_uV - 1852000) / 386;
+                       if (vsel % 100)
+                               vsel += 100;
+                       vsel /= 100;
+                       vsel++;
+               }
+               break;
+       }
+
+       *selector = vsel;
+
+       return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS,
+                                                       vsel);
+}
+
+static int twl6030smps_get_voltage_sel(struct regulator_dev *rdev)
+{
+       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+
+       return twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS);
+}
+
+static struct regulator_ops twlsmps_ops = {
+       .list_voltage           = twl6030smps_list_voltage,
+
+       .set_voltage            = twl6030smps_set_voltage,
+       .get_voltage_sel        = twl6030smps_get_voltage_sel,
+
+       .enable                 = twl6030reg_enable,
+       .disable                = twl6030reg_disable,
+       .is_enabled             = twl6030reg_is_enabled,
+
+       .set_mode               = twl6030reg_set_mode,
+
+       .get_status             = twl6030reg_get_status,
 };
 
 /*----------------------------------------------------------------------*/
@@ -487,11 +834,10 @@ static struct regulator_ops twl6030_fixed_resource = {
 #define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
                        remap_conf) \
                TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
-                       remap_conf, TWL4030)
-#define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
-                       remap_conf) \
+                       remap_conf, TWL4030, twl4030fixed_ops)
+#define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay) \
                TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
-                       remap_conf, TWL6030)
+                       0x0, TWL6030, twl6030fixed_ops)
 
 #define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) { \
        .base = offset, \
@@ -510,13 +856,11 @@ static struct regulator_ops twl6030_fixed_resource = {
                }, \
        }
 
-#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num, \
-               remap_conf) { \
+#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \
        .base = offset, \
        .id = num, \
        .min_mV = min_mVolts, \
        .max_mV = max_mVolts, \
-       .remap = remap_conf, \
        .desc = { \
                .name = #label, \
                .id = TWL6030_REG_##label, \
@@ -527,9 +871,23 @@ static struct regulator_ops twl6030_fixed_resource = {
                }, \
        }
 
+#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \
+       .base = offset, \
+       .id = num, \
+       .min_mV = min_mVolts, \
+       .max_mV = max_mVolts, \
+       .desc = { \
+               .name = #label, \
+               .id = TWL6025_REG_##label, \
+               .n_voltages = ((max_mVolts - min_mVolts)/100) + 1, \
+               .ops = &twl6030ldo_ops, \
+               .type = REGULATOR_VOLTAGE, \
+               .owner = THIS_MODULE, \
+               }, \
+       }
 
 #define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \
-               family) { \
+               family, operations) { \
        .base = offset, \
        .id = num, \
        .min_mV = mVolts, \
@@ -539,17 +897,16 @@ static struct regulator_ops twl6030_fixed_resource = {
                .name = #label, \
                .id = family##_REG_##label, \
                .n_voltages = 1, \
-               .ops = &twlfixed_ops, \
+               .ops = &operations, \
                .type = REGULATOR_VOLTAGE, \
                .owner = THIS_MODULE, \
                }, \
        }
 
-#define TWL6030_FIXED_RESOURCE(label, offset, num, turnon_delay, remap_conf) { \
+#define TWL6030_FIXED_RESOURCE(label, offset, num, turnon_delay) { \
        .base = offset, \
        .id = num, \
        .delay = turnon_delay, \
-       .remap = remap_conf, \
        .desc = { \
                .name = #label, \
                .id = TWL6030_REG_##label, \
@@ -559,6 +916,21 @@ static struct regulator_ops twl6030_fixed_resource = {
                }, \
        }
 
+#define TWL6025_ADJUSTABLE_SMPS(label, offset, num) { \
+       .base = offset, \
+       .id = num, \
+       .min_mV = 600, \
+       .max_mV = 2100, \
+       .desc = { \
+               .name = #label, \
+               .id = TWL6025_REG_##label, \
+               .n_voltages = 63, \
+               .ops = &twlsmps_ops, \
+               .type = REGULATOR_VOLTAGE, \
+               .owner = THIS_MODULE, \
+               }, \
+       }
+
 /*
  * We list regulators here if systems need some level of
  * software control over them after boot.
@@ -589,19 +961,52 @@ static struct twlreg_info twl_regs[] = {
        /* 6030 REG with base as PMC Slave Misc : 0x0030 */
        /* Turnon-delay and remap configuration values for 6030 are not
           verified since the specification is not public */
-       TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300, 1, 0x21),
-       TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300, 2, 0x21),
-       TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300, 3, 0x21),
-       TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300, 4, 0x21),
-       TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300, 5, 0x21),
-       TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300, 7, 0x21),
-       TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0, 0x21),
-       TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0, 0x21),
-       TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0, 0x21),
-       TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x21),
-       TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0, 0x21),
+       TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300, 1),
+       TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300, 2),
+       TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300, 3),
+       TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300, 4),
+       TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300, 5),
+       TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300, 7),
+       TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0),
+       TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0),
+       TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0),
+       TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0),
+       TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0),
+
+       /* 6025 are renamed compared to 6030 versions */
+       TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300, 1),
+       TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300, 2),
+       TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300, 3),
+       TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300, 4),
+       TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300, 5),
+       TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300, 7),
+       TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300, 16),
+       TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300, 17),
+       TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300, 18),
+
+       TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34, 1),
+       TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10, 2),
+       TWL6025_ADJUSTABLE_SMPS(VIO, 0x16, 3),
 };
 
+static u8 twl_get_smps_offset(void)
+{
+       u8 value;
+
+       twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value,
+                       TWL6030_SMPS_OFFSET);
+       return value;
+}
+
+static u8 twl_get_smps_mult(void)
+{
+       u8 value;
+
+       twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value,
+                       TWL6030_SMPS_MULT);
+       return value;
+}
+
 static int __devinit twlreg_probe(struct platform_device *pdev)
 {
        int                             i;
@@ -623,6 +1028,9 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
        if (!initdata)
                return -EINVAL;
 
+       /* copy the features into regulator data */
+       info->features = (unsigned long)initdata->driver_data;
+
        /* Constrain board-specific capabilities according to what
         * this driver and the chip itself can actually do.
         */
@@ -645,6 +1053,27 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
                break;
        }
 
+       switch (pdev->id) {
+       case TWL6025_REG_SMPS3:
+               if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS3)
+                       info->flags |= SMPS_EXTENDED_EN;
+               if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS3)
+                       info->flags |= SMPS_OFFSET_EN;
+               break;
+       case TWL6025_REG_SMPS4:
+               if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS4)
+                       info->flags |= SMPS_EXTENDED_EN;
+               if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS4)
+                       info->flags |= SMPS_OFFSET_EN;
+               break;
+       case TWL6025_REG_VIO:
+               if (twl_get_smps_mult() & SMPS_MULTOFFSET_VIO)
+                       info->flags |= SMPS_EXTENDED_EN;
+               if (twl_get_smps_offset() & SMPS_MULTOFFSET_VIO)
+                       info->flags |= SMPS_OFFSET_EN;
+               break;
+       }
+
        rdev = regulator_register(&info->desc, &pdev->dev, initdata, info);
        if (IS_ERR(rdev)) {
                dev_err(&pdev->dev, "can't register %s, %ld\n",
@@ -653,7 +1082,8 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
        }
        platform_set_drvdata(pdev, rdev);
 
-       twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_REMAP,
+       if (twl_class_is_4030())
+               twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_REMAP,
                                                info->remap);
 
        /* NOTE:  many regulators support short-circuit IRQs (presentable
index e93453b1b9788020646ca8e1a81964567d99710d..a0982e80985198004ae990218c38718d8616eec6 100644 (file)
@@ -600,7 +600,6 @@ err:
 static __devexit int wm831x_buckv_remove(struct platform_device *pdev)
 {
        struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
-       struct wm831x *wm831x = dcdc->wm831x;
 
        platform_set_drvdata(pdev, NULL);
 
@@ -776,7 +775,6 @@ err:
 static __devexit int wm831x_buckp_remove(struct platform_device *pdev)
 {
        struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
-       struct wm831x *wm831x = dcdc->wm831x;
 
        platform_set_drvdata(pdev, NULL);
 
index b42d01cef35a62b87bfcbb5c5cd12d2b65d659cb..0f12c70bebc9cd49ec51dc5f6e64997e0366aaff 100644 (file)
@@ -55,7 +55,7 @@ static int wm8400_ldo_list_voltage(struct regulator_dev *dev,
                return 1600000 + ((selector - 14) * 100000);
 }
 
-static int wm8400_ldo_get_voltage(struct regulator_dev *dev)
+static int wm8400_ldo_get_voltage_sel(struct regulator_dev *dev)
 {
        struct wm8400 *wm8400 = rdev_get_drvdata(dev);
        u16 val;
@@ -63,7 +63,7 @@ static int wm8400_ldo_get_voltage(struct regulator_dev *dev)
        val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
        val &= WM8400_LDO1_VSEL_MASK;
 
-       return wm8400_ldo_list_voltage(dev, val);
+       return val;
 }
 
 static int wm8400_ldo_set_voltage(struct regulator_dev *dev,
@@ -104,7 +104,7 @@ static struct regulator_ops wm8400_ldo_ops = {
        .enable = wm8400_ldo_enable,
        .disable = wm8400_ldo_disable,
        .list_voltage = wm8400_ldo_list_voltage,
-       .get_voltage = wm8400_ldo_get_voltage,
+       .get_voltage_sel = wm8400_ldo_get_voltage_sel,
        .set_voltage = wm8400_ldo_set_voltage,
 };
 
@@ -145,7 +145,7 @@ static int wm8400_dcdc_list_voltage(struct regulator_dev *dev,
        return 850000 + (selector * 25000);
 }
 
-static int wm8400_dcdc_get_voltage(struct regulator_dev *dev)
+static int wm8400_dcdc_get_voltage_sel(struct regulator_dev *dev)
 {
        struct wm8400 *wm8400 = rdev_get_drvdata(dev);
        u16 val;
@@ -154,7 +154,7 @@ static int wm8400_dcdc_get_voltage(struct regulator_dev *dev)
        val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset);
        val &= WM8400_DC1_VSEL_MASK;
 
-       return 850000 + (25000 * val);
+       return val;
 }
 
 static int wm8400_dcdc_set_voltage(struct regulator_dev *dev,
@@ -261,7 +261,7 @@ static struct regulator_ops wm8400_dcdc_ops = {
        .enable = wm8400_dcdc_enable,
        .disable = wm8400_dcdc_disable,
        .list_voltage = wm8400_dcdc_list_voltage,
-       .get_voltage = wm8400_dcdc_get_voltage,
+       .get_voltage_sel = wm8400_dcdc_get_voltage_sel,
        .set_voltage = wm8400_dcdc_set_voltage,
        .get_mode = wm8400_dcdc_get_mode,
        .set_mode = wm8400_dcdc_set_mode,
index 42891726ea7296ef867453e4423b9d4f0909fdad..ce2aabf5c550a2706bc39dd17ac2b1c5a94142e8 100644 (file)
@@ -125,6 +125,16 @@ comment "I2C RTC drivers"
 
 if I2C
 
+config RTC_DRV_88PM860X
+       tristate "Marvell 88PM860x"
+       depends on RTC_CLASS && I2C && MFD_88PM860X
+       help
+         If you say yes here you get support for RTC function in Marvell
+         88PM860x chips.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-88pm860x.
+
 config RTC_DRV_DS1307
        tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025"
        help
@@ -351,12 +361,39 @@ config RTC_DRV_RX8025
          This driver can also be built as a module. If so, the module
          will be called rtc-rx8025.
 
+config RTC_DRV_EM3027
+       tristate "EM Microelectronic EM3027"
+       help
+         If you say yes here you get support for the EM
+         Microelectronic EM3027 RTC chips.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-em3027.
+
+config RTC_DRV_RV3029C2
+       tristate "Micro Crystal RTC"
+       help
+         If you say yes here you get support for the Micro Crystal
+         RV3029-C2 RTC chips.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-rv3029c2.
+
 endif # I2C
 
 comment "SPI RTC drivers"
 
 if SPI_MASTER
 
+config RTC_DRV_M41T93
+        tristate "ST M41T93"
+        help
+          If you say yes here you will get support for the
+          ST M41T93 SPI RTC chip.
+
+          This driver can also be built as a module. If so, the module
+          will be called rtc-m41t93.
+
 config RTC_DRV_M41T94
        tristate "ST M41T94"
        help
@@ -645,6 +682,14 @@ config RTC_DRV_WM8350
          This driver can also be built as a module. If so, the module
          will be called "rtc-wm8350".
 
+config RTC_DRV_SPEAR
+       tristate "SPEAR ST RTC"
+       depends on PLAT_SPEAR
+       default y
+       help
+        If you say Y here you will get support for the RTC found on
+        spear
+
 config RTC_DRV_PCF50633
        depends on MFD_PCF50633
        tristate "NXP PCF50633 RTC"
@@ -874,6 +919,13 @@ config RTC_DRV_PXA
          This RTC driver uses PXA RTC registers available since pxa27x
          series (RDxR, RYxR) instead of legacy RCNR, RTAR.
 
+config RTC_DRV_VT8500
+       tristate "VIA/WonderMedia 85xx SoC RTC"
+       depends on ARCH_VT8500
+       help
+         If you say Y here you will get access to the real time clock
+         built into your VIA VT8500 SoC or its relatives.
+
 
 config RTC_DRV_SUN4V
        bool "SUN4V Hypervisor RTC"
@@ -992,4 +1044,20 @@ config RTC_DRV_TEGRA
          This drive can also be built as a module. If so, the module
          will be called rtc-tegra.
 
+config RTC_DRV_TILE
+       tristate "Tilera hypervisor RTC support"
+       depends on TILE
+       help
+         Enable support for the Linux driver side of the Tilera
+         hypervisor's real-time clock interface.
+
+config RTC_DRV_PUV3
+       tristate "PKUnity v3 RTC support"
+       depends on ARCH_PUV3
+       help
+         This enables support for the RTC in the PKUnity-v3 SoCs.
+
+         This drive can also be built as a module. If so, the module
+         will be called rtc-puv3.
+
 endif # RTC_CLASS
index ca91c3c42e98f6f7effa5ce95463f26e11d34a74..0ffefe877bfadca0fcf1730beaff016adc268ea2 100644 (file)
@@ -15,6 +15,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
 
 # Keep the list ordered.
 
+obj-$(CONFIG_RTC_DRV_88PM860X)  += rtc-88pm860x.o
 obj-$(CONFIG_RTC_DRV_AB3100)   += rtc-ab3100.o
 obj-$(CONFIG_RTC_DRV_AB8500)   += rtc-ab8500.o
 obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
@@ -43,6 +44,7 @@ obj-$(CONFIG_RTC_DRV_DS1742)  += rtc-ds1742.o
 obj-$(CONFIG_RTC_DRV_DS3232)   += rtc-ds3232.o
 obj-$(CONFIG_RTC_DRV_DS3234)   += rtc-ds3234.o
 obj-$(CONFIG_RTC_DRV_EFI)      += rtc-efi.o
+obj-$(CONFIG_RTC_DRV_EM3027)   += rtc-em3027.o
 obj-$(CONFIG_RTC_DRV_EP93XX)   += rtc-ep93xx.o
 obj-$(CONFIG_RTC_DRV_FM3130)   += rtc-fm3130.o
 obj-$(CONFIG_RTC_DRV_GENERIC)  += rtc-generic.o
@@ -52,6 +54,7 @@ obj-$(CONFIG_RTC_DRV_ISL12022)        += rtc-isl12022.o
 obj-$(CONFIG_RTC_DRV_JZ4740)   += rtc-jz4740.o
 obj-$(CONFIG_RTC_DRV_LPC32XX)  += rtc-lpc32xx.o
 obj-$(CONFIG_RTC_DRV_M41T80)   += rtc-m41t80.o
+obj-$(CONFIG_RTC_DRV_M41T93)   += rtc-m41t93.o
 obj-$(CONFIG_RTC_DRV_M41T94)   += rtc-m41t94.o
 obj-$(CONFIG_RTC_DRV_M48T35)   += rtc-m48t35.o
 obj-$(CONFIG_RTC_DRV_M48T59)   += rtc-m48t59.o
@@ -75,28 +78,33 @@ obj-$(CONFIG_RTC_DRV_PCF50633)      += rtc-pcf50633.o
 obj-$(CONFIG_RTC_DRV_PL030)    += rtc-pl030.o
 obj-$(CONFIG_RTC_DRV_PL031)    += rtc-pl031.o
 obj-$(CONFIG_RTC_DRV_PS3)      += rtc-ps3.o
+obj-$(CONFIG_RTC_DRV_PUV3)     += rtc-puv3.o
 obj-$(CONFIG_RTC_DRV_PXA)      += rtc-pxa.o
 obj-$(CONFIG_RTC_DRV_R9701)    += rtc-r9701.o
 obj-$(CONFIG_RTC_DRV_RP5C01)   += rtc-rp5c01.o
 obj-$(CONFIG_RTC_DRV_RS5C313)  += rtc-rs5c313.o
 obj-$(CONFIG_RTC_DRV_RS5C348)  += rtc-rs5c348.o
 obj-$(CONFIG_RTC_DRV_RS5C372)  += rtc-rs5c372.o
+obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o
 obj-$(CONFIG_RTC_DRV_RX8025)   += rtc-rx8025.o
 obj-$(CONFIG_RTC_DRV_RX8581)   += rtc-rx8581.o
 obj-$(CONFIG_RTC_DRV_S35390A)  += rtc-s35390a.o
 obj-$(CONFIG_RTC_DRV_S3C)      += rtc-s3c.o
 obj-$(CONFIG_RTC_DRV_SA1100)   += rtc-sa1100.o
 obj-$(CONFIG_RTC_DRV_SH)       += rtc-sh.o
+obj-$(CONFIG_RTC_DRV_SPEAR)    += rtc-spear.o
 obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
 obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
 obj-$(CONFIG_RTC_DRV_STMP)     += rtc-stmp3xxx.o
 obj-$(CONFIG_RTC_DRV_SUN4V)    += rtc-sun4v.o
 obj-$(CONFIG_RTC_DRV_TEGRA)    += rtc-tegra.o
 obj-$(CONFIG_RTC_DRV_TEST)     += rtc-test.o
+obj-$(CONFIG_RTC_DRV_TILE)     += rtc-tile.o
 obj-$(CONFIG_RTC_DRV_TWL4030)  += rtc-twl.o
 obj-$(CONFIG_RTC_DRV_TX4939)   += rtc-tx4939.o
 obj-$(CONFIG_RTC_DRV_V3020)    += rtc-v3020.o
 obj-$(CONFIG_RTC_DRV_VR41XX)   += rtc-vr41xx.o
+obj-$(CONFIG_RTC_DRV_VT8500)   += rtc-vt8500.o
 obj-$(CONFIG_RTC_DRV_WM831X)   += rtc-wm831x.o
 obj-$(CONFIG_RTC_DRV_WM8350)   += rtc-wm8350.o
 obj-$(CONFIG_RTC_DRV_X1205)    += rtc-x1205.o
index ef6316acec43a3312c00c6d8ca27b5ec8314f526..df68618f6dbb53f60f1f743f1425e2060e104854 100644 (file)
@@ -318,7 +318,7 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 }
 EXPORT_SYMBOL_GPL(rtc_read_alarm);
 
-int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
+static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 {
        struct rtc_time tm;
        long now, scheduled;
diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c
new file mode 100644 (file)
index 0000000..64b847b
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ * Real Time Clock driver for Marvell 88PM860x PMIC
+ *
+ * Copyright (c) 2010 Marvell International Ltd.
+ * Author:     Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/rtc.h>
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/88pm860x.h>
+
+#define VRTC_CALIBRATION
+
+struct pm860x_rtc_info {
+       struct pm860x_chip      *chip;
+       struct i2c_client       *i2c;
+       struct rtc_device       *rtc_dev;
+       struct device           *dev;
+       struct delayed_work     calib_work;
+
+       int                     irq;
+       int                     vrtc;
+       int                     (*sync)(unsigned int ticks);
+};
+
+#define REG_VRTC_MEAS1         0x7D
+
+#define REG0_ADDR              0xB0
+#define REG1_ADDR              0xB2
+#define REG2_ADDR              0xB4
+#define REG3_ADDR              0xB6
+
+#define REG0_DATA              0xB1
+#define REG1_DATA              0xB3
+#define REG2_DATA              0xB5
+#define REG3_DATA              0xB7
+
+/* bit definitions of Measurement Enable Register 2 (0x51) */
+#define MEAS2_VRTC             (1 << 0)
+
+/* bit definitions of RTC Register 1 (0xA0) */
+#define ALARM_EN               (1 << 3)
+#define ALARM_WAKEUP           (1 << 4)
+#define ALARM                  (1 << 5)
+#define RTC1_USE_XO            (1 << 7)
+
+#define VRTC_CALIB_INTERVAL    (HZ * 60 * 10)          /* 10 minutes */
+
+static irqreturn_t rtc_update_handler(int irq, void *data)
+{
+       struct pm860x_rtc_info *info = (struct pm860x_rtc_info *)data;
+       int mask;
+
+       mask = ALARM | ALARM_WAKEUP;
+       pm860x_set_bits(info->i2c, PM8607_RTC1, mask | ALARM_EN, mask);
+       rtc_update_irq(info->rtc_dev, 1, RTC_AF);
+       return IRQ_HANDLED;
+}
+
+static int pm860x_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct pm860x_rtc_info *info = dev_get_drvdata(dev);
+
+       if (enabled)
+               pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, ALARM);
+       else
+               pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, 0);
+       return 0;
+}
+
+/*
+ * Calculate the next alarm time given the requested alarm time mask
+ * and the current time.
+ */
+static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now,
+                               struct rtc_time *alrm)
+{
+       unsigned long next_time;
+       unsigned long now_time;
+
+       next->tm_year = now->tm_year;
+       next->tm_mon = now->tm_mon;
+       next->tm_mday = now->tm_mday;
+       next->tm_hour = alrm->tm_hour;
+       next->tm_min = alrm->tm_min;
+       next->tm_sec = alrm->tm_sec;
+
+       rtc_tm_to_time(now, &now_time);
+       rtc_tm_to_time(next, &next_time);
+
+       if (next_time < now_time) {
+               /* Advance one day */
+               next_time += 60 * 60 * 24;
+               rtc_time_to_tm(next_time, next);
+       }
+}
+
+static int pm860x_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct pm860x_rtc_info *info = dev_get_drvdata(dev);
+       unsigned char buf[8];
+       unsigned long ticks, base, data;
+
+       pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
+       dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
+               buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+       base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7];
+
+       /* load 32-bit read-only counter */
+       pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
+       data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+       ticks = base + data;
+       dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+               base, data, ticks);
+
+       rtc_time_to_tm(ticks, tm);
+
+       return 0;
+}
+
+static int pm860x_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct pm860x_rtc_info *info = dev_get_drvdata(dev);
+       unsigned char buf[4];
+       unsigned long ticks, base, data;
+
+       if ((tm->tm_year < 70) || (tm->tm_year > 138)) {
+               dev_dbg(info->dev, "Set time %d out of range. "
+                       "Please set time between 1970 to 2038.\n",
+                       1900 + tm->tm_year);
+               return -EINVAL;
+       }
+       rtc_tm_to_time(tm, &ticks);
+
+       /* load 32-bit read-only counter */
+       pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
+       data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+       base = ticks - data;
+       dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+               base, data, ticks);
+
+       pm860x_page_reg_write(info->i2c, REG0_DATA, (base >> 24) & 0xFF);
+       pm860x_page_reg_write(info->i2c, REG1_DATA, (base >> 16) & 0xFF);
+       pm860x_page_reg_write(info->i2c, REG2_DATA, (base >> 8) & 0xFF);
+       pm860x_page_reg_write(info->i2c, REG3_DATA, base & 0xFF);
+
+       if (info->sync)
+               info->sync(ticks);
+       return 0;
+}
+
+static int pm860x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct pm860x_rtc_info *info = dev_get_drvdata(dev);
+       unsigned char buf[8];
+       unsigned long ticks, base, data;
+       int ret;
+
+       pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
+       dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
+               buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+       base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7];
+
+       pm860x_bulk_read(info->i2c, PM8607_RTC_EXPIRE1, 4, buf);
+       data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+       ticks = base + data;
+       dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+               base, data, ticks);
+
+       rtc_time_to_tm(ticks, &alrm->time);
+       ret = pm860x_reg_read(info->i2c, PM8607_RTC1);
+       alrm->enabled = (ret & ALARM_EN) ? 1 : 0;
+       alrm->pending = (ret & (ALARM | ALARM_WAKEUP)) ? 1 : 0;
+       return 0;
+}
+
+static int pm860x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct pm860x_rtc_info *info = dev_get_drvdata(dev);
+       struct rtc_time now_tm, alarm_tm;
+       unsigned long ticks, base, data;
+       unsigned char buf[8];
+       int mask;
+
+       pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM_EN, 0);
+
+       pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
+       dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
+               buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+       base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7];
+
+       /* load 32-bit read-only counter */
+       pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
+       data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+       ticks = base + data;
+       dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+               base, data, ticks);
+
+       rtc_time_to_tm(ticks, &now_tm);
+       rtc_next_alarm_time(&alarm_tm, &now_tm, &alrm->time);
+       /* get new ticks for alarm in 24 hours */
+       rtc_tm_to_time(&alarm_tm, &ticks);
+       data = ticks - base;
+
+       buf[0] = data & 0xff;
+       buf[1] = (data >> 8) & 0xff;
+       buf[2] = (data >> 16) & 0xff;
+       buf[3] = (data >> 24) & 0xff;
+       pm860x_bulk_write(info->i2c, PM8607_RTC_EXPIRE1, 4, buf);
+       if (alrm->enabled) {
+               mask = ALARM | ALARM_WAKEUP | ALARM_EN;
+               pm860x_set_bits(info->i2c, PM8607_RTC1, mask, mask);
+       } else {
+               mask = ALARM | ALARM_WAKEUP | ALARM_EN;
+               pm860x_set_bits(info->i2c, PM8607_RTC1, mask,
+                               ALARM | ALARM_WAKEUP);
+       }
+       return 0;
+}
+
+static const struct rtc_class_ops pm860x_rtc_ops = {
+       .read_time      = pm860x_rtc_read_time,
+       .set_time       = pm860x_rtc_set_time,
+       .read_alarm     = pm860x_rtc_read_alarm,
+       .set_alarm      = pm860x_rtc_set_alarm,
+       .alarm_irq_enable = pm860x_rtc_alarm_irq_enable,
+};
+
+#ifdef VRTC_CALIBRATION
+static void calibrate_vrtc_work(struct work_struct *work)
+{
+       struct pm860x_rtc_info *info = container_of(work,
+               struct pm860x_rtc_info, calib_work.work);
+       unsigned char buf[2];
+       unsigned int sum, data, mean, vrtc_set;
+       int i;
+
+       for (i = 0, sum = 0; i < 16; i++) {
+               msleep(100);
+               pm860x_bulk_read(info->i2c, REG_VRTC_MEAS1, 2, buf);
+               data = (buf[0] << 4) | buf[1];
+               data = (data * 5400) >> 12;     /* convert to mv */
+               sum += data;
+       }
+       mean = sum >> 4;
+       vrtc_set = 2700 + (info->vrtc & 0x3) * 200;
+       dev_dbg(info->dev, "mean:%d, vrtc_set:%d\n", mean, vrtc_set);
+
+       sum = pm860x_reg_read(info->i2c, PM8607_RTC_MISC1);
+       data = sum & 0x3;
+       if ((mean + 200) < vrtc_set) {
+               /* try higher voltage */
+               if (++data == 4)
+                       goto out;
+               data = (sum & 0xf8) | (data & 0x3);
+               pm860x_reg_write(info->i2c, PM8607_RTC_MISC1, data);
+       } else if ((mean - 200) > vrtc_set) {
+               /* try lower voltage */
+               if (data-- == 0)
+                       goto out;
+               data = (sum & 0xf8) | (data & 0x3);
+               pm860x_reg_write(info->i2c, PM8607_RTC_MISC1, data);
+       } else
+               goto out;
+       dev_dbg(info->dev, "set 0x%x to RTC_MISC1\n", data);
+       /* trigger next calibration since VRTC is updated */
+       schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL);
+       return;
+out:
+       /* disable measurement */
+       pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0);
+       dev_dbg(info->dev, "finish VRTC calibration\n");
+       return;
+}
+#endif
+
+static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
+{
+       struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct pm860x_rtc_pdata *pdata = NULL;
+       struct pm860x_rtc_info *info;
+       struct rtc_time tm;
+       unsigned long ticks = 0;
+       int ret;
+
+       pdata = pdev->dev.platform_data;
+       if (pdata == NULL)
+               dev_warn(&pdev->dev, "No platform data!\n");
+
+       info = kzalloc(sizeof(struct pm860x_rtc_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       info->irq = platform_get_irq(pdev, 0);
+       if (info->irq < 0) {
+               dev_err(&pdev->dev, "No IRQ resource!\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       info->chip = chip;
+       info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
+       info->dev = &pdev->dev;
+       dev_set_drvdata(&pdev->dev, info);
+
+       ret = request_threaded_irq(info->irq, NULL, rtc_update_handler,
+                                  IRQF_ONESHOT, "rtc", info);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
+                       info->irq, ret);
+               goto out;
+       }
+
+       /* set addresses of 32-bit base value for RTC time */
+       pm860x_page_reg_write(info->i2c, REG0_ADDR, REG0_DATA);
+       pm860x_page_reg_write(info->i2c, REG1_ADDR, REG1_DATA);
+       pm860x_page_reg_write(info->i2c, REG2_ADDR, REG2_DATA);
+       pm860x_page_reg_write(info->i2c, REG3_ADDR, REG3_DATA);
+
+       ret = pm860x_rtc_read_time(&pdev->dev, &tm);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to read initial time.\n");
+               goto out_rtc;
+       }
+       if ((tm.tm_year < 70) || (tm.tm_year > 138)) {
+               tm.tm_year = 70;
+               tm.tm_mon = 0;
+               tm.tm_mday = 1;
+               tm.tm_hour = 0;
+               tm.tm_min = 0;
+               tm.tm_sec = 0;
+               ret = pm860x_rtc_set_time(&pdev->dev, &tm);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "Failed to set initial time.\n");
+                       goto out_rtc;
+               }
+       }
+       rtc_tm_to_time(&tm, &ticks);
+       if (pdata && pdata->sync) {
+               pdata->sync(ticks);
+               info->sync = pdata->sync;
+       }
+
+       info->rtc_dev = rtc_device_register("88pm860x-rtc", &pdev->dev,
+                                           &pm860x_rtc_ops, THIS_MODULE);
+       ret = PTR_ERR(info->rtc_dev);
+       if (IS_ERR(info->rtc_dev)) {
+               dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
+               goto out_rtc;
+       }
+
+       /*
+        * enable internal XO instead of internal 3.25MHz clock since it can
+        * free running in PMIC power-down state.
+        */
+       pm860x_set_bits(info->i2c, PM8607_RTC1, RTC1_USE_XO, RTC1_USE_XO);
+
+#ifdef VRTC_CALIBRATION
+       /* <00> -- 2.7V, <01> -- 2.9V, <10> -- 3.1V, <11> -- 3.3V */
+       if (pdata && pdata->vrtc)
+               info->vrtc = pdata->vrtc & 0x3;
+       else
+               info->vrtc = 1;
+       pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, MEAS2_VRTC);
+
+       /* calibrate VRTC */
+       INIT_DELAYED_WORK(&info->calib_work, calibrate_vrtc_work);
+       schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL);
+#endif /* VRTC_CALIBRATION */
+       return 0;
+out_rtc:
+       free_irq(info->irq, info);
+out:
+       kfree(info);
+       return ret;
+}
+
+static int __devexit pm860x_rtc_remove(struct platform_device *pdev)
+{
+       struct pm860x_rtc_info *info = platform_get_drvdata(pdev);
+
+#ifdef VRTC_CALIBRATION
+       flush_scheduled_work();
+       /* disable measurement */
+       pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0);
+#endif /* VRTC_CALIBRATION */
+
+       platform_set_drvdata(pdev, NULL);
+       rtc_device_unregister(info->rtc_dev);
+       free_irq(info->irq, info);
+       kfree(info);
+       return 0;
+}
+
+static struct platform_driver pm860x_rtc_driver = {
+       .driver         = {
+               .name   = "88pm860x-rtc",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = pm860x_rtc_probe,
+       .remove         = __devexit_p(pm860x_rtc_remove),
+};
+
+static int __init pm860x_rtc_init(void)
+{
+       return platform_driver_register(&pm860x_rtc_driver);
+}
+module_init(pm860x_rtc_init);
+
+static void __exit pm860x_rtc_exit(void)
+{
+       platform_driver_unregister(&pm860x_rtc_driver);
+}
+module_exit(pm860x_rtc_exit);
+
+MODULE_DESCRIPTION("Marvell 88PM860x RTC driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
index d0e06edb14c5157890079b08c4dcfab65b0ec66c..cace6d3aed9a59261bba613af9649b34699fb7a8 100644 (file)
@@ -421,7 +421,8 @@ static long rtc_dev_ioctl(struct file *file,
                        err = ops->ioctl(rtc->dev.parent, cmd, arg);
                        if (err == -ENOIOCTLCMD)
                                err = -ENOTTY;
-               }
+               } else
+                       err = -ENOTTY;
                break;
        }
 
diff --git a/drivers/rtc/rtc-em3027.c b/drivers/rtc/rtc-em3027.c
new file mode 100644 (file)
index 0000000..d8e1c25
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * An rtc/i2c driver for the EM Microelectronic EM3027
+ * Copyright 2011 CompuLab, Ltd.
+ *
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on rtc-ds1672.c by Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * 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/i2c.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+/* Registers */
+#define EM3027_REG_ON_OFF_CTRL 0x00
+#define EM3027_REG_IRQ_CTRL    0x01
+#define EM3027_REG_IRQ_FLAGS   0x02
+#define EM3027_REG_STATUS      0x03
+#define EM3027_REG_RST_CTRL    0x04
+
+#define EM3027_REG_WATCH_SEC   0x08
+#define EM3027_REG_WATCH_MIN   0x09
+#define EM3027_REG_WATCH_HOUR  0x0a
+#define EM3027_REG_WATCH_DATE  0x0b
+#define EM3027_REG_WATCH_DAY   0x0c
+#define EM3027_REG_WATCH_MON   0x0d
+#define EM3027_REG_WATCH_YEAR  0x0e
+
+#define EM3027_REG_ALARM_SEC   0x10
+#define EM3027_REG_ALARM_MIN   0x11
+#define EM3027_REG_ALARM_HOUR  0x12
+#define EM3027_REG_ALARM_DATE  0x13
+#define EM3027_REG_ALARM_DAY   0x14
+#define EM3027_REG_ALARM_MON   0x15
+#define EM3027_REG_ALARM_YEAR  0x16
+
+static struct i2c_driver em3027_driver;
+
+static int em3027_get_time(struct device *dev, struct rtc_time *tm)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       unsigned char addr = EM3027_REG_WATCH_SEC;
+       unsigned char buf[7];
+
+       struct i2c_msg msgs[] = {
+               {client->addr, 0, 1, &addr},            /* setup read addr */
+               {client->addr, I2C_M_RD, 7, buf},       /* read time/date */
+       };
+
+       /* read time/date registers */
+       if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+               dev_err(&client->dev, "%s: read error\n", __func__);
+               return -EIO;
+       }
+
+       tm->tm_sec      = bcd2bin(buf[0]);
+       tm->tm_min      = bcd2bin(buf[1]);
+       tm->tm_hour     = bcd2bin(buf[2]);
+       tm->tm_mday     = bcd2bin(buf[3]);
+       tm->tm_wday     = bcd2bin(buf[4]);
+       tm->tm_mon      = bcd2bin(buf[5]);
+       tm->tm_year     = bcd2bin(buf[6]) + 100;
+
+       return 0;
+}
+
+static int em3027_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       unsigned char buf[8];
+
+       struct i2c_msg msg = {
+               client->addr, 0, 8, buf,        /* write time/date */
+       };
+
+       buf[0] = EM3027_REG_WATCH_SEC;
+       buf[1] = bin2bcd(tm->tm_sec);
+       buf[2] = bin2bcd(tm->tm_min);
+       buf[3] = bin2bcd(tm->tm_hour);
+       buf[4] = bin2bcd(tm->tm_mday);
+       buf[5] = bin2bcd(tm->tm_wday);
+       buf[6] = bin2bcd(tm->tm_mon);
+       buf[7] = bin2bcd(tm->tm_year % 100);
+
+       /* write time/date registers */
+       if ((i2c_transfer(client->adapter, &msg, 1)) != 1) {
+               dev_err(&client->dev, "%s: write error\n", __func__);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static const struct rtc_class_ops em3027_rtc_ops = {
+       .read_time = em3027_get_time,
+       .set_time = em3027_set_time,
+};
+
+static int em3027_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct rtc_device *rtc;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+               return -ENODEV;
+
+       rtc = rtc_device_register(em3027_driver.driver.name, &client->dev,
+                                 &em3027_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       i2c_set_clientdata(client, rtc);
+
+       return 0;
+}
+
+static int em3027_remove(struct i2c_client *client)
+{
+       struct rtc_device *rtc = i2c_get_clientdata(client);
+
+       if (rtc)
+               rtc_device_unregister(rtc);
+
+       return 0;
+}
+
+static struct i2c_device_id em3027_id[] = {
+       { "em3027", 0 },
+       { }
+};
+
+static struct i2c_driver em3027_driver = {
+       .driver = {
+                  .name = "rtc-em3027",
+       },
+       .probe = &em3027_probe,
+       .remove = &em3027_remove,
+       .id_table = em3027_id,
+};
+
+static int __init em3027_init(void)
+{
+       return i2c_add_driver(&em3027_driver);
+}
+
+static void __exit em3027_exit(void)
+{
+       i2c_del_driver(&em3027_driver);
+}
+
+MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("EM Microelectronic EM3027 RTC driver");
+MODULE_LICENSE("GPL");
+
+module_init(em3027_init);
+module_exit(em3027_exit);
diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c
new file mode 100644 (file)
index 0000000..7317d3b
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ *
+ * Driver for ST M41T93 SPI RTC
+ *
+ * (c) 2010 Nikolaus Voss, Weinmann Medical GmbH
+ *
+ * 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/bcd.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+
+#define M41T93_REG_SSEC                        0
+#define M41T93_REG_ST_SEC              1
+#define M41T93_REG_MIN                 2
+#define M41T93_REG_CENT_HOUR           3
+#define M41T93_REG_WDAY                        4
+#define M41T93_REG_DAY                 5
+#define M41T93_REG_MON                 6
+#define M41T93_REG_YEAR                        7
+
+
+#define M41T93_REG_ALM_HOUR_HT         0xc
+#define M41T93_REG_FLAGS               0xf
+
+#define M41T93_FLAG_ST                 (1 << 7)
+#define M41T93_FLAG_OF                 (1 << 2)
+#define M41T93_FLAG_BL                 (1 << 4)
+#define M41T93_FLAG_HT                 (1 << 6)
+
+static inline int m41t93_set_reg(struct spi_device *spi, u8 addr, u8 data)
+{
+       u8 buf[2];
+
+       /* MSB must be '1' to write */
+       buf[0] = addr | 0x80;
+       buf[1] = data;
+
+       return spi_write(spi, buf, sizeof(buf));
+}
+
+static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       u8 buf[9] = {0x80};        /* write cmd + 8 data bytes */
+       u8 * const data = &buf[1]; /* ptr to first data byte */
+
+       dev_dbg(dev, "%s secs=%d, mins=%d, "
+               "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+               "write", tm->tm_sec, tm->tm_min,
+               tm->tm_hour, tm->tm_mday,
+               tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+       if (tm->tm_year < 100) {
+               dev_warn(&spi->dev, "unsupported date (before 2000-01-01).\n");
+               return -EINVAL;
+       }
+
+       data[M41T93_REG_SSEC]           = 0;
+       data[M41T93_REG_ST_SEC]         = bin2bcd(tm->tm_sec);
+       data[M41T93_REG_MIN]            = bin2bcd(tm->tm_min);
+       data[M41T93_REG_CENT_HOUR]      = bin2bcd(tm->tm_hour) |
+                                               ((tm->tm_year/100-1) << 6);
+       data[M41T93_REG_DAY]            = bin2bcd(tm->tm_mday);
+       data[M41T93_REG_WDAY]           = bin2bcd(tm->tm_wday + 1);
+       data[M41T93_REG_MON]            = bin2bcd(tm->tm_mon + 1);
+       data[M41T93_REG_YEAR]           = bin2bcd(tm->tm_year % 100);
+
+       return spi_write(spi, buf, sizeof(buf));
+}
+
+
+static int m41t93_get_time(struct device *dev, struct rtc_time *tm)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       const u8 start_addr = 0;
+       u8 buf[8];
+       int century_after_1900;
+       int tmp;
+       int ret = 0;
+
+       /* Check status of clock. Two states must be considered:
+          1. halt bit (HT) is set: the clock is running but update of readout
+             registers has been disabled due to power failure. This is normal
+             case after poweron. Time is valid after resetting HT bit.
+          2. oscillator fail bit (OF) is set. Oscillator has be stopped and
+             time is invalid:
+             a) OF can be immeditely reset.
+             b) OF cannot be immediately reset: oscillator has to be restarted.
+       */
+       tmp = spi_w8r8(spi, M41T93_REG_ALM_HOUR_HT);
+       if (tmp < 0)
+               return tmp;
+
+       if (tmp & M41T93_FLAG_HT) {
+               dev_dbg(&spi->dev, "HT bit is set, reenable clock update.\n");
+               m41t93_set_reg(spi, M41T93_REG_ALM_HOUR_HT,
+                              tmp & ~M41T93_FLAG_HT);
+       }
+
+       tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
+       if (tmp < 0)
+               return tmp;
+
+       if (tmp & M41T93_FLAG_OF) {
+               ret = -EINVAL;
+               dev_warn(&spi->dev, "OF bit is set, resetting.\n");
+               m41t93_set_reg(spi, M41T93_REG_FLAGS, tmp & ~M41T93_FLAG_OF);
+
+               tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
+               if (tmp < 0)
+                       return tmp;
+               else if (tmp & M41T93_FLAG_OF) {
+                       u8 reset_osc = buf[M41T93_REG_ST_SEC] | M41T93_FLAG_ST;
+
+                       dev_warn(&spi->dev,
+                                "OF bit is still set, kickstarting clock.\n");
+                       m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
+                       reset_osc &= ~M41T93_FLAG_ST;
+                       m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
+               }
+       }
+
+       if (tmp & M41T93_FLAG_BL)
+               dev_warn(&spi->dev, "BL bit is set, replace battery.\n");
+
+       /* read actual time/date */
+       tmp = spi_write_then_read(spi, &start_addr, 1, buf, sizeof(buf));
+       if (tmp < 0)
+               return tmp;
+
+       tm->tm_sec      = bcd2bin(buf[M41T93_REG_ST_SEC]);
+       tm->tm_min      = bcd2bin(buf[M41T93_REG_MIN]);
+       tm->tm_hour     = bcd2bin(buf[M41T93_REG_CENT_HOUR] & 0x3f);
+       tm->tm_mday     = bcd2bin(buf[M41T93_REG_DAY]);
+       tm->tm_mon      = bcd2bin(buf[M41T93_REG_MON]) - 1;
+       tm->tm_wday     = bcd2bin(buf[M41T93_REG_WDAY] & 0x0f) - 1;
+
+       century_after_1900 = (buf[M41T93_REG_CENT_HOUR] >> 6) + 1;
+       tm->tm_year = bcd2bin(buf[M41T93_REG_YEAR]) + century_after_1900 * 100;
+
+       dev_dbg(dev, "%s secs=%d, mins=%d, "
+               "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+               "read", tm->tm_sec, tm->tm_min,
+               tm->tm_hour, tm->tm_mday,
+               tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+       return ret < 0 ? ret : rtc_valid_tm(tm);
+}
+
+
+static const struct rtc_class_ops m41t93_rtc_ops = {
+       .read_time      = m41t93_get_time,
+       .set_time       = m41t93_set_time,
+};
+
+static struct spi_driver m41t93_driver;
+
+static int __devinit m41t93_probe(struct spi_device *spi)
+{
+       struct rtc_device *rtc;
+       int res;
+
+       spi->bits_per_word = 8;
+       spi_setup(spi);
+
+       res = spi_w8r8(spi, M41T93_REG_WDAY);
+       if (res < 0 || (res & 0xf8) != 0) {
+               dev_err(&spi->dev, "not found 0x%x.\n", res);
+               return -ENODEV;
+       }
+
+       rtc = rtc_device_register(m41t93_driver.driver.name,
+               &spi->dev, &m41t93_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       dev_set_drvdata(&spi->dev, rtc);
+
+       return 0;
+}
+
+
+static int __devexit m41t93_remove(struct spi_device *spi)
+{
+       struct rtc_device *rtc = spi_get_drvdata(spi);
+
+       if (rtc)
+               rtc_device_unregister(rtc);
+
+       return 0;
+}
+
+static struct spi_driver m41t93_driver = {
+       .driver = {
+               .name   = "rtc-m41t93",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe  = m41t93_probe,
+       .remove = __devexit_p(m41t93_remove),
+};
+
+static __init int m41t93_init(void)
+{
+       return spi_register_driver(&m41t93_driver);
+}
+module_init(m41t93_init);
+
+static __exit void m41t93_exit(void)
+{
+       spi_unregister_driver(&m41t93_driver);
+}
+module_exit(m41t93_exit);
+
+MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>");
+MODULE_DESCRIPTION("Driver for ST M41T93 SPI RTC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:rtc-m41t93");
index b2f096871a97cc5157dbbe75ee80738a941134b1..0cec5650d56a3d03e7ed1c50fb3a3f46a90043bf 100644 (file)
@@ -380,7 +380,7 @@ cleanup1:
 cleanup0:
        dev_set_drvdata(dev, NULL);
        mrst_rtc.dev = NULL;
-       release_region(iomem->start, iomem->end + 1 - iomem->start);
+       release_mem_region(iomem->start, resource_size(iomem));
        dev_err(dev, "rtc-mrst: unable to initialise\n");
        return retval;
 }
@@ -406,7 +406,7 @@ static void __devexit rtc_mrst_do_remove(struct device *dev)
        mrst->rtc = NULL;
 
        iomem = mrst->iomem;
-       release_region(iomem->start, iomem->end + 1 - iomem->start);
+       release_mem_region(iomem->start, resource_size(iomem));
        mrst->iomem = NULL;
 
        mrst->dev = NULL;
index d814417bee8c08b68224fafcbeb39e7ca405fd5d..39e41fbdf08ba6de6259347feb0cc5dee76803d7 100644 (file)
@@ -55,12 +55,6 @@ static const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = {
        { MAX_PIE_FREQ, RTC_SAM7_BIT },
 };
 
-/* Those are the bits from a classic RTC we want to mimic */
-#define RTC_IRQF       0x80    /* any of the following 3 is active */
-#define RTC_PF         0x40    /* Periodic interrupt */
-#define RTC_AF         0x20    /* Alarm interrupt */
-#define RTC_UF         0x10    /* Update interrupt for 1Hz RTC */
-
 #define MXC_RTC_TIME   0
 #define MXC_RTC_ALARM  1
 
index f90c574f9d055a8cffb8398c03b51c83327c0d50..0c423892923c99f7ed04a4d9a2d0e387de7e7b57 100644 (file)
@@ -58,7 +58,6 @@ struct pcf50633_time {
 
 struct pcf50633_rtc {
        int alarm_enabled;
-       int second_enabled;
        int alarm_pending;
 
        struct pcf50633 *pcf;
@@ -143,7 +142,7 @@ static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
        struct pcf50633_rtc *rtc;
        struct pcf50633_time pcf_tm;
-       int second_masked, alarm_masked, ret = 0;
+       int alarm_masked, ret = 0;
 
        rtc = dev_get_drvdata(dev);
 
@@ -162,11 +161,8 @@ static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm)
                pcf_tm.time[PCF50633_TI_SEC]);
 
 
-       second_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_SECOND);
        alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM);
 
-       if (!second_masked)
-               pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_SECOND);
        if (!alarm_masked)
                pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM);
 
@@ -175,8 +171,6 @@ static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm)
                                             PCF50633_TI_EXTENT,
                                             &pcf_tm.time[0]);
 
-       if (!second_masked)
-               pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_SECOND);
        if (!alarm_masked)
                pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
 
@@ -250,15 +244,8 @@ static void pcf50633_rtc_irq(int irq, void *data)
 {
        struct pcf50633_rtc *rtc = data;
 
-       switch (irq) {
-       case PCF50633_IRQ_ALARM:
-               rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
-               rtc->alarm_pending = 1;
-               break;
-       case PCF50633_IRQ_SECOND:
-               rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF);
-               break;
-       }
+       rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
+       rtc->alarm_pending = 1;
 }
 
 static int __devinit pcf50633_rtc_probe(struct platform_device *pdev)
@@ -282,9 +269,6 @@ static int __devinit pcf50633_rtc_probe(struct platform_device *pdev)
 
        pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_ALARM,
                                        pcf50633_rtc_irq, rtc);
-       pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_SECOND,
-                                       pcf50633_rtc_irq, rtc);
-
        return 0;
 }
 
@@ -295,7 +279,6 @@ static int __devexit pcf50633_rtc_remove(struct platform_device *pdev)
        rtc = platform_get_drvdata(pdev);
 
        pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_ALARM);
-       pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_SECOND);
 
        rtc_device_unregister(rtc->rtc_dev);
        kfree(rtc);
similarity index 98%
rename from arch/unicore32/kernel/rtc.c
rename to drivers/rtc/rtc-puv3.c
index 8cad70b3302c86e08c8189e7c926b34c3ab78f2c..46f14b82f3ab6e987efef66d90181414e34d475c 100644 (file)
@@ -1,7 +1,5 @@
 /*
- * linux/arch/unicore32/kernel/rtc.c
- *
- * Code specific to PKUnity SoC and UniCore ISA
+ * RTC driver code specific to PKUnity SoC and UniCore ISA
  *
  *     Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
  *     Copyright (C) 2001-2010 Guan Xuetao
@@ -36,7 +34,6 @@ static int puv3_rtc_tickno  = IRQ_RTC;
 static DEFINE_SPINLOCK(puv3_rtc_pie_lock);
 
 /* IRQ Handlers */
-
 static irqreturn_t puv3_rtc_alarmirq(int irq, void *id)
 {
        struct rtc_device *rdev = id;
@@ -89,7 +86,6 @@ static int puv3_rtc_setpie(struct device *dev, int enabled)
 }
 
 /* Time read/write */
-
 static int puv3_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
 {
        rtc_time_to_tm(readl(RTC_RCNR), rtc_tm);
@@ -196,7 +192,6 @@ static void puv3_rtc_release(struct device *dev)
        struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
 
        /* do not clear AIE here, it may be needed for wake */
-
        puv3_rtc_setpie(dev, 0);
        free_irq(puv3_rtc_alarmno, rtc_dev);
        free_irq(puv3_rtc_tickno, rtc_dev);
@@ -218,7 +213,6 @@ static void puv3_rtc_enable(struct platform_device *pdev, int en)
                writel(readl(RTC_RTSR) & ~RTC_RTSR_HZE, RTC_RTSR);
        } else {
                /* re-enable the device, and check it is ok */
-
                if ((readl(RTC_RTSR) & RTC_RTSR_HZE) == 0) {
                        dev_info(&pdev->dev, "rtc disabled, re-enabling\n");
                        writel(readl(RTC_RTSR) | RTC_RTSR_HZE, RTC_RTSR);
@@ -251,7 +245,6 @@ static int puv3_rtc_probe(struct platform_device *pdev)
        pr_debug("%s: probe=%p\n", __func__, pdev);
 
        /* find the IRQs */
-
        puv3_rtc_tickno = platform_get_irq(pdev, 1);
        if (puv3_rtc_tickno < 0) {
                dev_err(&pdev->dev, "no irq for rtc tick\n");
@@ -268,7 +261,6 @@ static int puv3_rtc_probe(struct platform_device *pdev)
                 puv3_rtc_tickno, puv3_rtc_alarmno);
 
        /* get the memory region */
-
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
                dev_err(&pdev->dev, "failed to get memory region resource\n");
@@ -288,7 +280,6 @@ static int puv3_rtc_probe(struct platform_device *pdev)
        puv3_rtc_enable(pdev, 1);
 
        /* register RTC and exit */
-
        rtc = rtc_device_register("pkunity", &pdev->dev, &puv3_rtcops,
                                  THIS_MODULE);
 
@@ -315,8 +306,6 @@ static int puv3_rtc_probe(struct platform_device *pdev)
 
 #ifdef CONFIG_PM
 
-/* RTC Power management control */
-
 static int ticnt_save;
 
 static int puv3_rtc_suspend(struct platform_device *pdev, pm_message_t state)
@@ -368,4 +357,3 @@ module_exit(puv3_rtc_exit);
 MODULE_DESCRIPTION("RTC Driver for the PKUnity v3 chip");
 MODULE_AUTHOR("Hu Dongliang");
 MODULE_LICENSE("GPL v2");
-
diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c
new file mode 100644 (file)
index 0000000..ea09ff2
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * Micro Crystal RV-3029C2 rtc class driver
+ *
+ * Author: Gregory Hermant <gregory.hermant@calao-systems.com>
+ *
+ * based on previously existing rtc class drivers
+ *
+ * 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.
+ *
+ * NOTE: Currently this driver only supports the bare minimum for read
+ * and write the RTC and alarms. The extra features provided by this chip
+ * (trickle charger, eeprom, T° compensation) are unavailable.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+
+/* Register map */
+/* control section */
+#define RV3029C2_ONOFF_CTRL            0x00
+#define RV3029C2_IRQ_CTRL              0x01
+#define RV3029C2_IRQ_CTRL_AIE          (1 << 0)
+#define RV3029C2_IRQ_FLAGS             0x02
+#define RV3029C2_IRQ_FLAGS_AF          (1 << 0)
+#define RV3029C2_STATUS                        0x03
+#define RV3029C2_STATUS_VLOW1          (1 << 2)
+#define RV3029C2_STATUS_VLOW2          (1 << 3)
+#define RV3029C2_STATUS_SR             (1 << 4)
+#define RV3029C2_STATUS_PON            (1 << 5)
+#define RV3029C2_STATUS_EEBUSY         (1 << 7)
+#define RV3029C2_RST_CTRL              0x04
+#define RV3029C2_CONTROL_SECTION_LEN   0x05
+
+/* watch section */
+#define RV3029C2_W_SEC                 0x08
+#define RV3029C2_W_MINUTES             0x09
+#define RV3029C2_W_HOURS               0x0A
+#define RV3029C2_REG_HR_12_24          (1<<6)  /* 24h/12h mode */
+#define RV3029C2_REG_HR_PM             (1<<5)  /* PM/AM bit in 12h mode */
+#define RV3029C2_W_DATE                        0x0B
+#define RV3029C2_W_DAYS                        0x0C
+#define RV3029C2_W_MONTHS              0x0D
+#define RV3029C2_W_YEARS               0x0E
+#define RV3029C2_WATCH_SECTION_LEN     0x07
+
+/* alarm section */
+#define RV3029C2_A_SC                  0x10
+#define RV3029C2_A_MN                  0x11
+#define RV3029C2_A_HR                  0x12
+#define RV3029C2_A_DT                  0x13
+#define RV3029C2_A_DW                  0x14
+#define RV3029C2_A_MO                  0x15
+#define RV3029C2_A_YR                  0x16
+#define RV3029C2_ALARM_SECTION_LEN     0x07
+
+/* timer section */
+#define RV3029C2_TIMER_LOW             0x18
+#define RV3029C2_TIMER_HIGH            0x19
+
+/* temperature section */
+#define RV3029C2_TEMP_PAGE             0x20
+
+/* eeprom data section */
+#define RV3029C2_E2P_EEDATA1           0x28
+#define RV3029C2_E2P_EEDATA2           0x29
+
+/* eeprom control section */
+#define RV3029C2_CONTROL_E2P_EECTRL    0x30
+#define RV3029C2_TRICKLE_1K            (1<<0)  /*  1K resistance */
+#define RV3029C2_TRICKLE_5K            (1<<1)  /*  5K resistance */
+#define RV3029C2_TRICKLE_20K           (1<<2)  /* 20K resistance */
+#define RV3029C2_TRICKLE_80K           (1<<3)  /* 80K resistance */
+#define RV3029C2_CONTROL_E2P_XTALOFFSET        0x31
+#define RV3029C2_CONTROL_E2P_QCOEF     0x32
+#define RV3029C2_CONTROL_E2P_TURNOVER  0x33
+
+/* user ram section */
+#define RV3029C2_USR1_RAM_PAGE         0x38
+#define RV3029C2_USR1_SECTION_LEN      0x04
+#define RV3029C2_USR2_RAM_PAGE         0x3C
+#define RV3029C2_USR2_SECTION_LEN      0x04
+
+static int
+rv3029c2_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf,
+       unsigned len)
+{
+       int ret;
+
+       if ((reg > RV3029C2_USR1_RAM_PAGE + 7) ||
+               (reg + len > RV3029C2_USR1_RAM_PAGE + 8))
+               return -EINVAL;
+
+       ret = i2c_smbus_read_i2c_block_data(client, reg, len, buf);
+       if (ret < 0)
+               return ret;
+       if (ret < len)
+               return -EIO;
+       return 0;
+}
+
+static int
+rv3029c2_i2c_write_regs(struct i2c_client *client, u8 reg, u8 const buf[],
+                       unsigned len)
+{
+       if ((reg > RV3029C2_USR1_RAM_PAGE + 7) ||
+               (reg + len > RV3029C2_USR1_RAM_PAGE + 8))
+               return -EINVAL;
+
+       return i2c_smbus_write_i2c_block_data(client, reg, len, buf);
+}
+
+static int
+rv3029c2_i2c_get_sr(struct i2c_client *client, u8 *buf)
+{
+       int ret = rv3029c2_i2c_read_regs(client, RV3029C2_STATUS, buf, 1);
+
+       if (ret < 0)
+               return -EIO;
+       dev_dbg(&client->dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]);
+       return 0;
+}
+
+static int
+rv3029c2_i2c_set_sr(struct i2c_client *client, u8 val)
+{
+       u8 buf[1];
+       int sr;
+
+       buf[0] = val;
+       sr = rv3029c2_i2c_write_regs(client, RV3029C2_STATUS, buf, 1);
+       dev_dbg(&client->dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]);
+       if (sr < 0)
+               return -EIO;
+       return 0;
+}
+
+static int
+rv3029c2_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
+{
+       u8 buf[1];
+       int ret;
+       u8 regs[RV3029C2_WATCH_SECTION_LEN] = { 0, };
+
+       ret = rv3029c2_i2c_get_sr(client, buf);
+       if (ret < 0) {
+               dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+               return -EIO;
+       }
+
+       ret = rv3029c2_i2c_read_regs(client, RV3029C2_W_SEC , regs,
+                                       RV3029C2_WATCH_SECTION_LEN);
+       if (ret < 0) {
+               dev_err(&client->dev, "%s: reading RTC section failed\n",
+                       __func__);
+               return ret;
+       }
+
+       tm->tm_sec = bcd2bin(regs[RV3029C2_W_SEC-RV3029C2_W_SEC]);
+       tm->tm_min = bcd2bin(regs[RV3029C2_W_MINUTES-RV3029C2_W_SEC]);
+
+       /* HR field has a more complex interpretation */
+       {
+               const u8 _hr = regs[RV3029C2_W_HOURS-RV3029C2_W_SEC];
+               if (_hr & RV3029C2_REG_HR_12_24) {
+                       /* 12h format */
+                       tm->tm_hour = bcd2bin(_hr & 0x1f);
+                       if (_hr & RV3029C2_REG_HR_PM)   /* PM flag set */
+                               tm->tm_hour += 12;
+               } else /* 24h format */
+                       tm->tm_hour = bcd2bin(_hr & 0x3f);
+       }
+
+       tm->tm_mday = bcd2bin(regs[RV3029C2_W_DATE-RV3029C2_W_SEC]);
+       tm->tm_mon = bcd2bin(regs[RV3029C2_W_MONTHS-RV3029C2_W_SEC]) - 1;
+       tm->tm_year = bcd2bin(regs[RV3029C2_W_YEARS-RV3029C2_W_SEC]) + 100;
+       tm->tm_wday = bcd2bin(regs[RV3029C2_W_DAYS-RV3029C2_W_SEC]) - 1;
+
+       return 0;
+}
+
+static int rv3029c2_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       return rv3029c2_i2c_read_time(to_i2c_client(dev), tm);
+}
+
+static int
+rv3029c2_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
+{
+       struct rtc_time *const tm = &alarm->time;
+       int ret;
+       u8 regs[8];
+
+       ret = rv3029c2_i2c_get_sr(client, regs);
+       if (ret < 0) {
+               dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+               return -EIO;
+       }
+
+       ret = rv3029c2_i2c_read_regs(client, RV3029C2_A_SC, regs,
+                                       RV3029C2_ALARM_SECTION_LEN);
+
+       if (ret < 0) {
+               dev_err(&client->dev, "%s: reading alarm section failed\n",
+                       __func__);
+               return ret;
+       }
+
+       tm->tm_sec = bcd2bin(regs[RV3029C2_A_SC-RV3029C2_A_SC] & 0x7f);
+       tm->tm_min = bcd2bin(regs[RV3029C2_A_MN-RV3029C2_A_SC] & 0x7f);
+       tm->tm_hour = bcd2bin(regs[RV3029C2_A_HR-RV3029C2_A_SC] & 0x3f);
+       tm->tm_mday = bcd2bin(regs[RV3029C2_A_DT-RV3029C2_A_SC] & 0x3f);
+       tm->tm_mon = bcd2bin(regs[RV3029C2_A_MO-RV3029C2_A_SC] & 0x1f) - 1;
+       tm->tm_year = bcd2bin(regs[RV3029C2_A_YR-RV3029C2_A_SC] & 0x7f) + 100;
+       tm->tm_wday = bcd2bin(regs[RV3029C2_A_DW-RV3029C2_A_SC] & 0x07) - 1;
+
+       return 0;
+}
+
+static int
+rv3029c2_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       return rv3029c2_i2c_read_alarm(to_i2c_client(dev), alarm);
+}
+
+static int rv3029c2_rtc_i2c_alarm_set_irq(struct i2c_client *client,
+                                       int enable)
+{
+       int ret;
+       u8 buf[1];
+
+       /* enable AIE irq */
+       ret = rv3029c2_i2c_read_regs(client, RV3029C2_IRQ_CTRL, buf, 1);
+       if (ret < 0) {
+               dev_err(&client->dev, "can't read INT reg\n");
+               return ret;
+       }
+       if (enable)
+               buf[0] |= RV3029C2_IRQ_CTRL_AIE;
+       else
+               buf[0] &= ~RV3029C2_IRQ_CTRL_AIE;
+
+       ret = rv3029c2_i2c_write_regs(client, RV3029C2_IRQ_CTRL, buf, 1);
+       if (ret < 0) {
+               dev_err(&client->dev, "can't set INT reg\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client,
+                                       struct rtc_wkalrm *alarm)
+{
+       struct rtc_time *const tm = &alarm->time;
+       int ret;
+       u8 regs[8];
+
+       /*
+        * The clock has an 8 bit wide bcd-coded register (they never learn)
+        * for the year. tm_year is an offset from 1900 and we are interested
+        * in the 2000-2099 range, so any value less than 100 is invalid.
+       */
+       if (tm->tm_year < 100)
+               return -EINVAL;
+
+       ret = rv3029c2_i2c_get_sr(client, regs);
+       if (ret < 0) {
+               dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+               return -EIO;
+       }
+       regs[RV3029C2_A_SC-RV3029C2_A_SC] = bin2bcd(tm->tm_sec & 0x7f);
+       regs[RV3029C2_A_MN-RV3029C2_A_SC] = bin2bcd(tm->tm_min & 0x7f);
+       regs[RV3029C2_A_HR-RV3029C2_A_SC] = bin2bcd(tm->tm_hour & 0x3f);
+       regs[RV3029C2_A_DT-RV3029C2_A_SC] = bin2bcd(tm->tm_mday & 0x3f);
+       regs[RV3029C2_A_MO-RV3029C2_A_SC] = bin2bcd((tm->tm_mon & 0x1f) - 1);
+       regs[RV3029C2_A_DW-RV3029C2_A_SC] = bin2bcd((tm->tm_wday & 7) - 1);
+       regs[RV3029C2_A_YR-RV3029C2_A_SC] = bin2bcd((tm->tm_year & 0x7f) - 100);
+
+       ret = rv3029c2_i2c_write_regs(client, RV3029C2_A_SC, regs,
+                                       RV3029C2_ALARM_SECTION_LEN);
+       if (ret < 0)
+               return ret;
+
+       if (alarm->enabled) {
+               u8 buf[1];
+
+               /* clear AF flag */
+               ret = rv3029c2_i2c_read_regs(client, RV3029C2_IRQ_FLAGS,
+                                               buf, 1);
+               if (ret < 0) {
+                       dev_err(&client->dev, "can't read alarm flag\n");
+                       return ret;
+               }
+               buf[0] &= ~RV3029C2_IRQ_FLAGS_AF;
+               ret = rv3029c2_i2c_write_regs(client, RV3029C2_IRQ_FLAGS,
+                                               buf, 1);
+               if (ret < 0) {
+                       dev_err(&client->dev, "can't set alarm flag\n");
+                       return ret;
+               }
+               /* enable AIE irq */
+               ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 1);
+               if (ret)
+                       return ret;
+
+               dev_dbg(&client->dev, "alarm IRQ armed\n");
+       } else {
+               /* disable AIE irq */
+               ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 1);
+               if (ret)
+                       return ret;
+
+               dev_dbg(&client->dev, "alarm IRQ disabled\n");
+       }
+
+       return 0;
+}
+
+static int rv3029c2_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       return rv3029c2_rtc_i2c_set_alarm(to_i2c_client(dev), alarm);
+}
+
+static int
+rv3029c2_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
+{
+       u8 regs[8];
+       int ret;
+
+       /*
+        * The clock has an 8 bit wide bcd-coded register (they never learn)
+        * for the year. tm_year is an offset from 1900 and we are interested
+        * in the 2000-2099 range, so any value less than 100 is invalid.
+       */
+       if (tm->tm_year < 100)
+               return -EINVAL;
+
+       regs[RV3029C2_W_SEC-RV3029C2_W_SEC] = bin2bcd(tm->tm_sec);
+       regs[RV3029C2_W_MINUTES-RV3029C2_W_SEC] = bin2bcd(tm->tm_min);
+       regs[RV3029C2_W_HOURS-RV3029C2_W_SEC] = bin2bcd(tm->tm_hour);
+       regs[RV3029C2_W_DATE-RV3029C2_W_SEC] = bin2bcd(tm->tm_mday);
+       regs[RV3029C2_W_MONTHS-RV3029C2_W_SEC] = bin2bcd(tm->tm_mon+1);
+       regs[RV3029C2_W_DAYS-RV3029C2_W_SEC] = bin2bcd((tm->tm_wday & 7)+1);
+       regs[RV3029C2_W_YEARS-RV3029C2_W_SEC] = bin2bcd(tm->tm_year - 100);
+
+       ret = rv3029c2_i2c_write_regs(client, RV3029C2_W_SEC, regs,
+                                       RV3029C2_WATCH_SECTION_LEN);
+       if (ret < 0)
+               return ret;
+
+       ret = rv3029c2_i2c_get_sr(client, regs);
+       if (ret < 0) {
+               dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+               return ret;
+       }
+       /* clear PON bit */
+       ret = rv3029c2_i2c_set_sr(client, (regs[0] & ~RV3029C2_STATUS_PON));
+       if (ret < 0) {
+               dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rv3029c2_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       return rv3029c2_i2c_set_time(to_i2c_client(dev), tm);
+}
+
+static const struct rtc_class_ops rv3029c2_rtc_ops = {
+       .read_time      = rv3029c2_rtc_read_time,
+       .set_time       = rv3029c2_rtc_set_time,
+       .read_alarm     = rv3029c2_rtc_read_alarm,
+       .set_alarm      = rv3029c2_rtc_set_alarm,
+};
+
+static struct i2c_device_id rv3029c2_id[] = {
+       { "rv3029c2", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, rv3029c2_id);
+
+static int __devinit
+rv3029c2_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       struct rtc_device *rtc;
+       int rc = 0;
+       u8 buf[1];
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_EMUL))
+               return -ENODEV;
+
+       rtc = rtc_device_register(client->name,
+                               &client->dev, &rv3029c2_rtc_ops,
+                               THIS_MODULE);
+
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       i2c_set_clientdata(client, rtc);
+
+       rc = rv3029c2_i2c_get_sr(client, buf);
+       if (rc < 0) {
+               dev_err(&client->dev, "reading status failed\n");
+               goto exit_unregister;
+       }
+
+       return 0;
+
+exit_unregister:
+       rtc_device_unregister(rtc);
+
+       return rc;
+}
+
+static int __devexit rv3029c2_remove(struct i2c_client *client)
+{
+       struct rtc_device *rtc = i2c_get_clientdata(client);
+
+       rtc_device_unregister(rtc);
+
+       return 0;
+}
+
+static struct i2c_driver rv3029c2_driver = {
+       .driver = {
+               .name = "rtc-rv3029c2",
+       },
+       .probe = rv3029c2_probe,
+       .remove = __devexit_p(rv3029c2_remove),
+       .id_table = rv3029c2_id,
+};
+
+static int __init rv3029c2_init(void)
+{
+       return i2c_add_driver(&rv3029c2_driver);
+}
+
+static void __exit rv3029c2_exit(void)
+{
+       i2c_del_driver(&rv3029c2_driver);
+}
+
+module_init(rv3029c2_init);
+module_exit(rv3029c2_exit);
+
+MODULE_AUTHOR("Gregory Hermant <gregory.hermant@calao-systems.com>");
+MODULE_DESCRIPTION("Micro Crystal RV3029C2 RTC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c
new file mode 100644 (file)
index 0000000..893bac2
--- /dev/null
@@ -0,0 +1,534 @@
+/*
+ * drivers/rtc/rtc-spear.c
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Rajeev Kumar<rajeev-dlh.kumar@st.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/bcd.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+/* RTC registers */
+#define TIME_REG               0x00
+#define DATE_REG               0x04
+#define ALARM_TIME_REG         0x08
+#define ALARM_DATE_REG         0x0C
+#define CTRL_REG               0x10
+#define STATUS_REG             0x14
+
+/* TIME_REG & ALARM_TIME_REG */
+#define SECONDS_UNITS          (0xf<<0)        /* seconds units position */
+#define SECONDS_TENS           (0x7<<4)        /* seconds tens position */
+#define MINUTES_UNITS          (0xf<<8)        /* minutes units position */
+#define MINUTES_TENS           (0x7<<12)       /* minutes tens position */
+#define HOURS_UNITS            (0xf<<16)       /* hours units position */
+#define HOURS_TENS             (0x3<<20)       /* hours tens position */
+
+/* DATE_REG & ALARM_DATE_REG */
+#define DAYS_UNITS             (0xf<<0)        /* days units position */
+#define DAYS_TENS              (0x3<<4)        /* days tens position */
+#define MONTHS_UNITS           (0xf<<8)        /* months units position */
+#define MONTHS_TENS            (0x1<<12)       /* months tens position */
+#define YEARS_UNITS            (0xf<<16)       /* years units position */
+#define YEARS_TENS             (0xf<<20)       /* years tens position */
+#define YEARS_HUNDREDS         (0xf<<24)       /* years hundereds position */
+#define YEARS_MILLENIUMS       (0xf<<28)       /* years millenium position */
+
+/* MASK SHIFT TIME_REG & ALARM_TIME_REG*/
+#define SECOND_SHIFT           0x00            /* seconds units */
+#define MINUTE_SHIFT           0x08            /* minutes units position */
+#define HOUR_SHIFT             0x10            /* hours units position */
+#define MDAY_SHIFT             0x00            /* Month day shift */
+#define MONTH_SHIFT            0x08            /* Month shift */
+#define YEAR_SHIFT             0x10            /* Year shift */
+
+#define SECOND_MASK            0x7F
+#define MIN_MASK               0x7F
+#define HOUR_MASK              0x3F
+#define DAY_MASK               0x3F
+#define MONTH_MASK             0x7F
+#define YEAR_MASK              0xFFFF
+
+/* date reg equal to time reg, for debug only */
+#define TIME_BYP               (1<<9)
+#define INT_ENABLE             (1<<31)         /* interrupt enable */
+
+/* STATUS_REG */
+#define CLK_UNCONNECTED                (1<<0)
+#define PEND_WR_TIME           (1<<2)
+#define PEND_WR_DATE           (1<<3)
+#define LOST_WR_TIME           (1<<4)
+#define LOST_WR_DATE           (1<<5)
+#define RTC_INT_MASK           (1<<31)
+#define STATUS_BUSY            (PEND_WR_TIME | PEND_WR_DATE)
+#define STATUS_FAIL            (LOST_WR_TIME | LOST_WR_DATE)
+
+struct spear_rtc_config {
+       struct clk *clk;
+       spinlock_t lock;
+       void __iomem *ioaddr;
+};
+
+static inline void spear_rtc_clear_interrupt(struct spear_rtc_config *config)
+{
+       unsigned int val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&config->lock, flags);
+       val = readl(config->ioaddr + STATUS_REG);
+       val |= RTC_INT_MASK;
+       writel(val, config->ioaddr + STATUS_REG);
+       spin_unlock_irqrestore(&config->lock, flags);
+}
+
+static inline void spear_rtc_enable_interrupt(struct spear_rtc_config *config)
+{
+       unsigned int val;
+
+       val = readl(config->ioaddr + CTRL_REG);
+       if (!(val & INT_ENABLE)) {
+               spear_rtc_clear_interrupt(config);
+               val |= INT_ENABLE;
+               writel(val, config->ioaddr + CTRL_REG);
+       }
+}
+
+static inline void spear_rtc_disable_interrupt(struct spear_rtc_config *config)
+{
+       unsigned int val;
+
+       val = readl(config->ioaddr + CTRL_REG);
+       if (val & INT_ENABLE) {
+               val &= ~INT_ENABLE;
+               writel(val, config->ioaddr + CTRL_REG);
+       }
+}
+
+static inline int is_write_complete(struct spear_rtc_config *config)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&config->lock, flags);
+       if ((readl(config->ioaddr + STATUS_REG)) & STATUS_FAIL)
+               ret = -EIO;
+       spin_unlock_irqrestore(&config->lock, flags);
+
+       return ret;
+}
+
+static void rtc_wait_not_busy(struct spear_rtc_config *config)
+{
+       int status, count = 0;
+       unsigned long flags;
+
+       /* Assuming BUSY may stay active for 80 msec) */
+       for (count = 0; count < 80; count++) {
+               spin_lock_irqsave(&config->lock, flags);
+               status = readl(config->ioaddr + STATUS_REG);
+               spin_unlock_irqrestore(&config->lock, flags);
+               if ((status & STATUS_BUSY) == 0)
+                       break;
+               /* check status busy, after each msec */
+               msleep(1);
+       }
+}
+
+static irqreturn_t spear_rtc_irq(int irq, void *dev_id)
+{
+       struct rtc_device *rtc = (struct rtc_device *)dev_id;
+       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       unsigned long flags, events = 0;
+       unsigned int irq_data;
+
+       spin_lock_irqsave(&config->lock, flags);
+       irq_data = readl(config->ioaddr + STATUS_REG);
+       spin_unlock_irqrestore(&config->lock, flags);
+
+       if ((irq_data & RTC_INT_MASK)) {
+               spear_rtc_clear_interrupt(config);
+               events = RTC_IRQF | RTC_AF;
+               rtc_update_irq(rtc, 1, events);
+               return IRQ_HANDLED;
+       } else
+               return IRQ_NONE;
+
+}
+
+static int tm2bcd(struct rtc_time *tm)
+{
+       if (rtc_valid_tm(tm) != 0)
+               return -EINVAL;
+       tm->tm_sec = bin2bcd(tm->tm_sec);
+       tm->tm_min = bin2bcd(tm->tm_min);
+       tm->tm_hour = bin2bcd(tm->tm_hour);
+       tm->tm_mday = bin2bcd(tm->tm_mday);
+       tm->tm_mon = bin2bcd(tm->tm_mon + 1);
+       tm->tm_year = bin2bcd(tm->tm_year);
+
+       return 0;
+}
+
+static void bcd2tm(struct rtc_time *tm)
+{
+       tm->tm_sec = bcd2bin(tm->tm_sec);
+       tm->tm_min = bcd2bin(tm->tm_min);
+       tm->tm_hour = bcd2bin(tm->tm_hour);
+       tm->tm_mday = bcd2bin(tm->tm_mday);
+       tm->tm_mon = bcd2bin(tm->tm_mon) - 1;
+       /* epoch == 1900 */
+       tm->tm_year = bcd2bin(tm->tm_year);
+}
+
+/*
+ * spear_rtc_read_time - set the time
+ * @dev: rtc device in use
+ * @tm: holds date and time
+ *
+ * This function read time and date. On success it will return 0
+ * otherwise -ve error is returned.
+ */
+static int spear_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_device *rtc = platform_get_drvdata(pdev);
+       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       unsigned int time, date;
+
+       /* we don't report wday/yday/isdst ... */
+       rtc_wait_not_busy(config);
+
+       time = readl(config->ioaddr + TIME_REG);
+       date = readl(config->ioaddr + DATE_REG);
+       tm->tm_sec = (time >> SECOND_SHIFT) & SECOND_MASK;
+       tm->tm_min = (time >> MINUTE_SHIFT) & MIN_MASK;
+       tm->tm_hour = (time >> HOUR_SHIFT) & HOUR_MASK;
+       tm->tm_mday = (date >> MDAY_SHIFT) & DAY_MASK;
+       tm->tm_mon = (date >> MONTH_SHIFT) & MONTH_MASK;
+       tm->tm_year = (date >> YEAR_SHIFT) & YEAR_MASK;
+
+       bcd2tm(tm);
+       return 0;
+}
+
+/*
+ * spear_rtc_set_time - set the time
+ * @dev: rtc device in use
+ * @tm: holds date and time
+ *
+ * This function set time and date. On success it will return 0
+ * otherwise -ve error is returned.
+ */
+static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_device *rtc = platform_get_drvdata(pdev);
+       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       unsigned int time, date, err = 0;
+
+       if (tm2bcd(tm) < 0)
+               return -EINVAL;
+
+       rtc_wait_not_busy(config);
+       time = (tm->tm_sec << SECOND_SHIFT) | (tm->tm_min << MINUTE_SHIFT) |
+               (tm->tm_hour << HOUR_SHIFT);
+       date = (tm->tm_mday << MDAY_SHIFT) | (tm->tm_mon << MONTH_SHIFT) |
+               (tm->tm_year << YEAR_SHIFT);
+       writel(time, config->ioaddr + TIME_REG);
+       writel(date, config->ioaddr + DATE_REG);
+       err = is_write_complete(config);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+/*
+ * spear_rtc_read_alarm - read the alarm time
+ * @dev: rtc device in use
+ * @alm: holds alarm date and time
+ *
+ * This function read alarm time and date. On success it will return 0
+ * otherwise -ve error is returned.
+ */
+static int spear_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_device *rtc = platform_get_drvdata(pdev);
+       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       unsigned int time, date;
+
+       rtc_wait_not_busy(config);
+
+       time = readl(config->ioaddr + ALARM_TIME_REG);
+       date = readl(config->ioaddr + ALARM_DATE_REG);
+       alm->time.tm_sec = (time >> SECOND_SHIFT) & SECOND_MASK;
+       alm->time.tm_min = (time >> MINUTE_SHIFT) & MIN_MASK;
+       alm->time.tm_hour = (time >> HOUR_SHIFT) & HOUR_MASK;
+       alm->time.tm_mday = (date >> MDAY_SHIFT) & DAY_MASK;
+       alm->time.tm_mon = (date >> MONTH_SHIFT) & MONTH_MASK;
+       alm->time.tm_year = (date >> YEAR_SHIFT) & YEAR_MASK;
+
+       bcd2tm(&alm->time);
+       alm->enabled = readl(config->ioaddr + CTRL_REG) & INT_ENABLE;
+
+       return 0;
+}
+
+/*
+ * spear_rtc_set_alarm - set the alarm time
+ * @dev: rtc device in use
+ * @alm: holds alarm date and time
+ *
+ * This function set alarm time and date. On success it will return 0
+ * otherwise -ve error is returned.
+ */
+static int spear_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_device *rtc = platform_get_drvdata(pdev);
+       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       unsigned int time, date, err = 0;
+
+       if (tm2bcd(&alm->time) < 0)
+               return -EINVAL;
+
+       rtc_wait_not_busy(config);
+
+       time = (alm->time.tm_sec << SECOND_SHIFT) | (alm->time.tm_min <<
+                       MINUTE_SHIFT) | (alm->time.tm_hour << HOUR_SHIFT);
+       date = (alm->time.tm_mday << MDAY_SHIFT) | (alm->time.tm_mon <<
+                       MONTH_SHIFT) | (alm->time.tm_year << YEAR_SHIFT);
+
+       writel(time, config->ioaddr + ALARM_TIME_REG);
+       writel(date, config->ioaddr + ALARM_DATE_REG);
+       err = is_write_complete(config);
+       if (err < 0)
+               return err;
+
+       if (alm->enabled)
+               spear_rtc_enable_interrupt(config);
+       else
+               spear_rtc_disable_interrupt(config);
+
+       return 0;
+}
+static struct rtc_class_ops spear_rtc_ops = {
+       .read_time = spear_rtc_read_time,
+       .set_time = spear_rtc_set_time,
+       .read_alarm = spear_rtc_read_alarm,
+       .set_alarm = spear_rtc_set_alarm,
+};
+
+static int __devinit spear_rtc_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct rtc_device *rtc;
+       struct spear_rtc_config *config;
+       unsigned int status = 0;
+       int irq;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "no resource defined\n");
+               return -EBUSY;
+       }
+       if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+               dev_err(&pdev->dev, "rtc region already claimed\n");
+               return -EBUSY;
+       }
+
+       config = kzalloc(sizeof(*config), GFP_KERNEL);
+       if (!config) {
+               dev_err(&pdev->dev, "out of memory\n");
+               status = -ENOMEM;
+               goto err_release_region;
+       }
+
+       config->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(config->clk)) {
+               status = PTR_ERR(config->clk);
+               goto err_kfree;
+       }
+
+       status = clk_enable(config->clk);
+       if (status < 0)
+               goto err_clk_put;
+
+       config->ioaddr = ioremap(res->start, resource_size(res));
+       if (!config->ioaddr) {
+               dev_err(&pdev->dev, "ioremap fail\n");
+               status = -ENOMEM;
+               goto err_disable_clock;
+       }
+
+       spin_lock_init(&config->lock);
+
+       rtc = rtc_device_register(pdev->name, &pdev->dev, &spear_rtc_ops,
+                       THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
+                               PTR_ERR(rtc));
+               status = PTR_ERR(rtc);
+               goto err_iounmap;
+       }
+
+       platform_set_drvdata(pdev, rtc);
+       dev_set_drvdata(&rtc->dev, config);
+
+       /* alarm irqs */
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "no update irq?\n");
+               status = irq;
+               goto err_clear_platdata;
+       }
+
+       status = request_irq(irq, spear_rtc_irq, 0, pdev->name, rtc);
+       if (status) {
+               dev_err(&pdev->dev, "Alarm interrupt IRQ%d already \
+                               claimed\n", irq);
+               goto err_clear_platdata;
+       }
+
+       if (!device_can_wakeup(&pdev->dev))
+               device_init_wakeup(&pdev->dev, 1);
+
+       return 0;
+
+err_clear_platdata:
+       platform_set_drvdata(pdev, NULL);
+       dev_set_drvdata(&rtc->dev, NULL);
+       rtc_device_unregister(rtc);
+err_iounmap:
+       iounmap(config->ioaddr);
+err_disable_clock:
+       clk_disable(config->clk);
+err_clk_put:
+       clk_put(config->clk);
+err_kfree:
+       kfree(config);
+err_release_region:
+       release_mem_region(res->start, resource_size(res));
+
+       return status;
+}
+
+static int __devexit spear_rtc_remove(struct platform_device *pdev)
+{
+       struct rtc_device *rtc = platform_get_drvdata(pdev);
+       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       int irq;
+       struct resource *res;
+
+       /* leave rtc running, but disable irqs */
+       spear_rtc_disable_interrupt(config);
+       device_init_wakeup(&pdev->dev, 0);
+       irq = platform_get_irq(pdev, 0);
+       if (irq)
+               free_irq(irq, pdev);
+       clk_disable(config->clk);
+       clk_put(config->clk);
+       iounmap(config->ioaddr);
+       kfree(config);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res)
+               release_mem_region(res->start, resource_size(res));
+       platform_set_drvdata(pdev, NULL);
+       dev_set_drvdata(&rtc->dev, NULL);
+       rtc_device_unregister(rtc);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int spear_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct rtc_device *rtc = platform_get_drvdata(pdev);
+       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       int irq;
+
+       irq = platform_get_irq(pdev, 0);
+       if (device_may_wakeup(&pdev->dev))
+               enable_irq_wake(irq);
+       else {
+               spear_rtc_disable_interrupt(config);
+               clk_disable(config->clk);
+       }
+
+       return 0;
+}
+
+static int spear_rtc_resume(struct platform_device *pdev)
+{
+       struct rtc_device *rtc = platform_get_drvdata(pdev);
+       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       int irq;
+
+       irq = platform_get_irq(pdev, 0);
+
+       if (device_may_wakeup(&pdev->dev))
+               disable_irq_wake(irq);
+       else {
+               clk_enable(config->clk);
+               spear_rtc_enable_interrupt(config);
+       }
+
+       return 0;
+}
+
+#else
+#define spear_rtc_suspend      NULL
+#define spear_rtc_resume       NULL
+#endif
+
+static void spear_rtc_shutdown(struct platform_device *pdev)
+{
+       struct rtc_device *rtc = platform_get_drvdata(pdev);
+       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+
+       spear_rtc_disable_interrupt(config);
+       clk_disable(config->clk);
+}
+
+static struct platform_driver spear_rtc_driver = {
+       .probe = spear_rtc_probe,
+       .remove = __devexit_p(spear_rtc_remove),
+       .suspend = spear_rtc_suspend,
+       .resume = spear_rtc_resume,
+       .shutdown = spear_rtc_shutdown,
+       .driver = {
+               .name = "rtc-spear",
+       },
+};
+
+static int __init rtc_init(void)
+{
+       return platform_driver_register(&spear_rtc_driver);
+}
+module_init(rtc_init);
+
+static void __exit rtc_exit(void)
+{
+       platform_driver_unregister(&spear_rtc_driver);
+}
+module_exit(rtc_exit);
+
+MODULE_ALIAS("platform:rtc-spear");
+MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
+MODULE_DESCRIPTION("ST SPEAr Realtime Clock Driver (RTC)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-tile.c b/drivers/rtc/rtc-tile.c
new file mode 100644 (file)
index 0000000..eb65daf
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * Tilera-specific RTC driver.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+/* Platform device pointer. */
+static struct platform_device *tile_rtc_platform_device;
+
+/*
+ * RTC read routine.  Gets time info from RTC chip via hypervisor syscall.
+ */
+static int read_rtc_time(struct device *dev, struct rtc_time *tm)
+{
+       HV_RTCTime hvtm = hv_get_rtc();
+
+       tm->tm_sec = hvtm.tm_sec;
+       tm->tm_min = hvtm.tm_min;
+       tm->tm_hour = hvtm.tm_hour;
+       tm->tm_mday = hvtm.tm_mday;
+       tm->tm_mon = hvtm.tm_mon;
+       tm->tm_year = hvtm.tm_year;
+       tm->tm_wday = 0;
+       tm->tm_yday = 0;
+       tm->tm_isdst = 0;
+
+       if (rtc_valid_tm(tm) < 0)
+               dev_warn(dev, "Read invalid date/time from RTC\n");
+
+       return 0;
+}
+
+/*
+ * RTC write routine.  Sends time info to hypervisor via syscall, to be
+ * written to RTC chip.
+ */
+static int set_rtc_time(struct device *dev, struct rtc_time *tm)
+{
+       HV_RTCTime hvtm;
+
+       hvtm.tm_sec = tm->tm_sec;
+       hvtm.tm_min = tm->tm_min;
+       hvtm.tm_hour = tm->tm_hour;
+       hvtm.tm_mday = tm->tm_mday;
+       hvtm.tm_mon = tm->tm_mon;
+       hvtm.tm_year = tm->tm_year;
+
+       hv_set_rtc(hvtm);
+
+       return 0;
+}
+
+/*
+ * RTC read/write ops.
+ */
+static const struct rtc_class_ops tile_rtc_ops = {
+       .read_time      = read_rtc_time,
+       .set_time       = set_rtc_time,
+};
+
+/*
+ * Device probe routine.
+ */
+static int __devinit tile_rtc_probe(struct platform_device *dev)
+{
+       struct rtc_device *rtc;
+
+       rtc = rtc_device_register("tile",
+                                 &dev->dev, &tile_rtc_ops, THIS_MODULE);
+
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       platform_set_drvdata(dev, rtc);
+
+       return 0;
+}
+
+/*
+ * Device cleanup routine.
+ */
+static int __devexit tile_rtc_remove(struct platform_device *dev)
+{
+       struct rtc_device *rtc = platform_get_drvdata(dev);
+
+       if (rtc)
+               rtc_device_unregister(rtc);
+
+       platform_set_drvdata(dev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver tile_rtc_platform_driver = {
+       .driver         = {
+               .name   = "rtc-tile",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = tile_rtc_probe,
+       .remove         = __devexit_p(tile_rtc_remove),
+};
+
+/*
+ * Driver init routine.
+ */
+static int __init tile_rtc_driver_init(void)
+{
+       int err;
+
+       err = platform_driver_register(&tile_rtc_platform_driver);
+       if (err)
+               return err;
+
+       tile_rtc_platform_device = platform_device_alloc("rtc-tile", 0);
+       if (tile_rtc_platform_device == NULL) {
+               err = -ENOMEM;
+               goto exit_driver_unregister;
+       }
+
+       err = platform_device_add(tile_rtc_platform_device);
+       if (err)
+               goto exit_device_put;
+
+       return 0;
+
+exit_device_put:
+       platform_device_put(tile_rtc_platform_device);
+
+exit_driver_unregister:
+       platform_driver_unregister(&tile_rtc_platform_driver);
+       return err;
+}
+
+/*
+ * Driver cleanup routine.
+ */
+static void __exit tile_rtc_driver_exit(void)
+{
+       platform_driver_unregister(&tile_rtc_platform_driver);
+}
+
+module_init(tile_rtc_driver_init);
+module_exit(tile_rtc_driver_exit);
+
+MODULE_DESCRIPTION("Tilera-specific Real Time Clock Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rtc-tile");
diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c
new file mode 100644 (file)
index 0000000..efd6066
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * drivers/rtc/rtc-vt8500.c
+ *
+ *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * Based on rtc-pxa.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/module.h>
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/bcd.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/*
+ * Register definitions
+ */
+#define VT8500_RTC_TS          0x00    /* Time set */
+#define VT8500_RTC_DS          0x04    /* Date set */
+#define VT8500_RTC_AS          0x08    /* Alarm set */
+#define VT8500_RTC_CR          0x0c    /* Control */
+#define VT8500_RTC_TR          0x10    /* Time read */
+#define VT8500_RTC_DR          0x14    /* Date read */
+#define VT8500_RTC_WS          0x18    /* Write status */
+#define VT8500_RTC_CL          0x20    /* Calibration */
+#define VT8500_RTC_IS          0x24    /* Interrupt status */
+#define VT8500_RTC_ST          0x28    /* Status */
+
+#define INVALID_TIME_BIT       (1 << 31)
+
+#define DATE_CENTURY_S         19
+#define DATE_YEAR_S            11
+#define DATE_YEAR_MASK         (0xff << DATE_YEAR_S)
+#define DATE_MONTH_S           6
+#define DATE_MONTH_MASK                (0x1f << DATE_MONTH_S)
+#define DATE_DAY_MASK          0x3f
+
+#define TIME_DOW_S             20
+#define TIME_DOW_MASK          (0x07 << TIME_DOW_S)
+#define TIME_HOUR_S            14
+#define TIME_HOUR_MASK         (0x3f << TIME_HOUR_S)
+#define TIME_MIN_S             7
+#define TIME_MIN_MASK          (0x7f << TIME_MIN_S)
+#define TIME_SEC_MASK          0x7f
+
+#define ALARM_DAY_S            20
+#define ALARM_DAY_MASK         (0x3f << ALARM_DAY_S)
+
+#define ALARM_DAY_BIT          (1 << 29)
+#define ALARM_HOUR_BIT         (1 << 28)
+#define ALARM_MIN_BIT          (1 << 27)
+#define ALARM_SEC_BIT          (1 << 26)
+
+#define ALARM_ENABLE_MASK      (ALARM_DAY_BIT \
+                               | ALARM_HOUR_BIT \
+                               | ALARM_MIN_BIT \
+                               | ALARM_SEC_BIT)
+
+#define VT8500_RTC_CR_ENABLE   (1 << 0)        /* Enable RTC */
+#define VT8500_RTC_CR_24H      (1 << 1)        /* 24h time format */
+#define VT8500_RTC_CR_SM_ENABLE        (1 << 2)        /* Enable periodic irqs */
+#define VT8500_RTC_CR_SM_SEC   (1 << 3)        /* 0: 1Hz/60, 1: 1Hz */
+#define VT8500_RTC_CR_CALIB    (1 << 4)        /* Enable calibration */
+
+struct vt8500_rtc {
+       void __iomem            *regbase;
+       struct resource         *res;
+       int                     irq_alarm;
+       struct rtc_device       *rtc;
+       spinlock_t              lock;           /* Protects this structure */
+};
+
+static irqreturn_t vt8500_rtc_irq(int irq, void *dev_id)
+{
+       struct vt8500_rtc *vt8500_rtc = dev_id;
+       u32 isr;
+       unsigned long events = 0;
+
+       spin_lock(&vt8500_rtc->lock);
+
+       /* clear interrupt sources */
+       isr = readl(vt8500_rtc->regbase + VT8500_RTC_IS);
+       writel(isr, vt8500_rtc->regbase + VT8500_RTC_IS);
+
+       spin_unlock(&vt8500_rtc->lock);
+
+       if (isr & 1)
+               events |= RTC_AF | RTC_IRQF;
+
+       rtc_update_irq(vt8500_rtc->rtc, 1, events);
+
+       return IRQ_HANDLED;
+}
+
+static int vt8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
+       u32 date, time;
+
+       date = readl(vt8500_rtc->regbase + VT8500_RTC_DR);
+       time = readl(vt8500_rtc->regbase + VT8500_RTC_TR);
+
+       tm->tm_sec = bcd2bin(time & TIME_SEC_MASK);
+       tm->tm_min = bcd2bin((time & TIME_MIN_MASK) >> TIME_MIN_S);
+       tm->tm_hour = bcd2bin((time & TIME_HOUR_MASK) >> TIME_HOUR_S);
+       tm->tm_mday = bcd2bin(date & DATE_DAY_MASK);
+       tm->tm_mon = bcd2bin((date & DATE_MONTH_MASK) >> DATE_MONTH_S);
+       tm->tm_year = bcd2bin((date & DATE_YEAR_MASK) >> DATE_YEAR_S)
+                       + ((date >> DATE_CENTURY_S) & 1 ? 200 : 100);
+       tm->tm_wday = (time & TIME_DOW_MASK) >> TIME_DOW_S;
+
+       return 0;
+}
+
+static int vt8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
+
+       if (tm->tm_year < 100) {
+               dev_warn(dev, "Only years 2000-2199 are supported by the "
+                             "hardware!\n");
+               return -EINVAL;
+       }
+
+       writel((bin2bcd(tm->tm_year - 100) << DATE_YEAR_S)
+               | (bin2bcd(tm->tm_mon) << DATE_MONTH_S)
+               | (bin2bcd(tm->tm_mday)),
+               vt8500_rtc->regbase + VT8500_RTC_DS);
+       writel((bin2bcd(tm->tm_wday) << TIME_DOW_S)
+               | (bin2bcd(tm->tm_hour) << TIME_HOUR_S)
+               | (bin2bcd(tm->tm_min) << TIME_MIN_S)
+               | (bin2bcd(tm->tm_sec)),
+               vt8500_rtc->regbase + VT8500_RTC_TS);
+
+       return 0;
+}
+
+static int vt8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
+       u32 isr, alarm;
+
+       alarm = readl(vt8500_rtc->regbase + VT8500_RTC_AS);
+       isr = readl(vt8500_rtc->regbase + VT8500_RTC_IS);
+
+       alrm->time.tm_mday = bcd2bin((alarm & ALARM_DAY_MASK) >> ALARM_DAY_S);
+       alrm->time.tm_hour = bcd2bin((alarm & TIME_HOUR_MASK) >> TIME_HOUR_S);
+       alrm->time.tm_min = bcd2bin((alarm & TIME_MIN_MASK) >> TIME_MIN_S);
+       alrm->time.tm_sec = bcd2bin((alarm & TIME_SEC_MASK));
+
+       alrm->enabled = (alarm & ALARM_ENABLE_MASK) ? 1 : 0;
+
+       alrm->pending = (isr & 1) ? 1 : 0;
+       return rtc_valid_tm(&alrm->time);
+}
+
+static int vt8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
+
+       writel((alrm->enabled ? ALARM_ENABLE_MASK : 0)
+               | (bin2bcd(alrm->time.tm_mday) << ALARM_DAY_S)
+               | (bin2bcd(alrm->time.tm_hour) << TIME_HOUR_S)
+               | (bin2bcd(alrm->time.tm_min) << TIME_MIN_S)
+               | (bin2bcd(alrm->time.tm_sec)),
+               vt8500_rtc->regbase + VT8500_RTC_AS);
+
+       return 0;
+}
+
+static int vt8500_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
+       unsigned long tmp = readl(vt8500_rtc->regbase + VT8500_RTC_AS);
+
+       if (enabled)
+               tmp |= ALARM_ENABLE_MASK;
+       else
+               tmp &= ~ALARM_ENABLE_MASK;
+
+       writel(tmp, vt8500_rtc->regbase + VT8500_RTC_AS);
+       return 0;
+}
+
+static const struct rtc_class_ops vt8500_rtc_ops = {
+       .read_time = vt8500_rtc_read_time,
+       .set_time = vt8500_rtc_set_time,
+       .read_alarm = vt8500_rtc_read_alarm,
+       .set_alarm = vt8500_rtc_set_alarm,
+       .alarm_irq_enable = vt8500_alarm_irq_enable,
+};
+
+static int __devinit vt8500_rtc_probe(struct platform_device *pdev)
+{
+       struct vt8500_rtc *vt8500_rtc;
+       int ret;
+
+       vt8500_rtc = kzalloc(sizeof(struct vt8500_rtc), GFP_KERNEL);
+       if (!vt8500_rtc)
+               return -ENOMEM;
+
+       spin_lock_init(&vt8500_rtc->lock);
+       platform_set_drvdata(pdev, vt8500_rtc);
+
+       vt8500_rtc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!vt8500_rtc->res) {
+               dev_err(&pdev->dev, "No I/O memory resource defined\n");
+               ret = -ENXIO;
+               goto err_free;
+       }
+
+       vt8500_rtc->irq_alarm = platform_get_irq(pdev, 0);
+       if (vt8500_rtc->irq_alarm < 0) {
+               dev_err(&pdev->dev, "No alarm IRQ resource defined\n");
+               ret = -ENXIO;
+               goto err_free;
+       }
+
+       vt8500_rtc->res = request_mem_region(vt8500_rtc->res->start,
+                                            resource_size(vt8500_rtc->res),
+                                            "vt8500-rtc");
+       if (vt8500_rtc->res == NULL) {
+               dev_err(&pdev->dev, "failed to request I/O memory\n");
+               ret = -EBUSY;
+               goto err_free;
+       }
+
+       vt8500_rtc->regbase = ioremap(vt8500_rtc->res->start,
+                                     resource_size(vt8500_rtc->res));
+       if (!vt8500_rtc->regbase) {
+               dev_err(&pdev->dev, "Unable to map RTC I/O memory\n");
+               ret = -EBUSY;
+               goto err_release;
+       }
+
+       /* Enable RTC and set it to 24-hour mode */
+       writel(VT8500_RTC_CR_ENABLE | VT8500_RTC_CR_24H,
+              vt8500_rtc->regbase + VT8500_RTC_CR);
+
+       vt8500_rtc->rtc = rtc_device_register("vt8500-rtc", &pdev->dev,
+                                             &vt8500_rtc_ops, THIS_MODULE);
+       if (IS_ERR(vt8500_rtc->rtc)) {
+               ret = PTR_ERR(vt8500_rtc->rtc);
+               dev_err(&pdev->dev,
+                       "Failed to register RTC device -> %d\n", ret);
+               goto err_unmap;
+       }
+
+       ret = request_irq(vt8500_rtc->irq_alarm, vt8500_rtc_irq, 0,
+                         "rtc alarm", vt8500_rtc);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "can't get irq %i, err %d\n",
+                       vt8500_rtc->irq_alarm, ret);
+               goto err_unreg;
+       }
+
+       return 0;
+
+err_unreg:
+       rtc_device_unregister(vt8500_rtc->rtc);
+err_unmap:
+       iounmap(vt8500_rtc->regbase);
+err_release:
+       release_mem_region(vt8500_rtc->res->start,
+                          resource_size(vt8500_rtc->res));
+err_free:
+       kfree(vt8500_rtc);
+       return ret;
+}
+
+static int __devexit vt8500_rtc_remove(struct platform_device *pdev)
+{
+       struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev);
+
+       free_irq(vt8500_rtc->irq_alarm, vt8500_rtc);
+
+       rtc_device_unregister(vt8500_rtc->rtc);
+
+       /* Disable alarm matching */
+       writel(0, vt8500_rtc->regbase + VT8500_RTC_IS);
+       iounmap(vt8500_rtc->regbase);
+       release_mem_region(vt8500_rtc->res->start,
+                          resource_size(vt8500_rtc->res));
+
+       kfree(vt8500_rtc);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver vt8500_rtc_driver = {
+       .probe          = vt8500_rtc_probe,
+       .remove         = __devexit_p(vt8500_rtc_remove),
+       .driver         = {
+               .name   = "vt8500-rtc",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init vt8500_rtc_init(void)
+{
+       return platform_driver_register(&vt8500_rtc_driver);
+}
+module_init(vt8500_rtc_init);
+
+static void __exit vt8500_rtc_exit(void)
+{
+       platform_driver_unregister(&vt8500_rtc_driver);
+}
+module_exit(vt8500_rtc_exit);
+
+MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>");
+MODULE_DESCRIPTION("VIA VT8500 SoC Realtime Clock Driver (RTC)");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:vt8500-rtc");
index 2b771f18d1adc836f36c6c509060af409f9f1bed..c388eda1e2b195943200e4af7308ee1c69935083 100644 (file)
@@ -253,13 +253,11 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
  */
 void dasd_alias_lcu_setup_complete(struct dasd_device *device)
 {
-       struct dasd_eckd_private *private;
        unsigned long flags;
        struct alias_server *server;
        struct alias_lcu *lcu;
        struct dasd_uid uid;
 
-       private = (struct dasd_eckd_private *) device->private;
        device->discipline->get_uid(device, &uid);
        lcu = NULL;
        spin_lock_irqsave(&aliastree.lock, flags);
@@ -279,13 +277,11 @@ void dasd_alias_lcu_setup_complete(struct dasd_device *device)
 
 void dasd_alias_wait_for_lcu_setup(struct dasd_device *device)
 {
-       struct dasd_eckd_private *private;
        unsigned long flags;
        struct alias_server *server;
        struct alias_lcu *lcu;
        struct dasd_uid uid;
 
-       private = (struct dasd_eckd_private *) device->private;
        device->discipline->get_uid(device, &uid);
        lcu = NULL;
        spin_lock_irqsave(&aliastree.lock, flags);
index 85dddb1e4126be512d843ceef08123fd86cc1b0d..46784b83c5c4e1a4fcac2184dcebd6e37d014da3 100644 (file)
@@ -24,7 +24,7 @@
 #include <asm/debug.h>
 #include <asm/ebcdic.h>
 #include <asm/io.h>
-#include <asm/s390_ext.h>
+#include <asm/irq.h>
 #include <asm/vtoc.h>
 #include <asm/diag.h>
 
@@ -642,7 +642,7 @@ dasd_diag_init(void)
        }
        ASCEBC(dasd_diag_discipline.ebcname, 4);
 
-       ctl_set_bit(0, 9);
+       service_subclass_irq_register();
        register_external_interrupt(0x2603, dasd_ext_handler);
        dasd_diag_discipline_pointer = &dasd_diag_discipline;
        return 0;
@@ -652,7 +652,7 @@ static void __exit
 dasd_diag_cleanup(void)
 {
        unregister_external_interrupt(0x2603, dasd_ext_handler);
-       ctl_clear_bit(0, 9);
+       service_subclass_irq_unregister();
        dasd_diag_discipline_pointer = NULL;
 }
 
index 3ebdf5f92f8f945fabad2e9744fa82f106b8a33b..30fb979d684d0043d2b1f6b0aff2fda6ebe8cfcd 100644 (file)
@@ -1611,10 +1611,8 @@ static void dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr,
 
 static int dasd_eckd_start_analysis(struct dasd_block *block)
 {
-       struct dasd_eckd_private *private;
        struct dasd_ccw_req *init_cqr;
 
-       private = (struct dasd_eckd_private *) block->base->private;
        init_cqr = dasd_eckd_analysis_ccw(block->base);
        if (IS_ERR(init_cqr))
                return PTR_ERR(init_cqr);
@@ -2264,7 +2262,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
                                               unsigned int blk_per_trk,
                                               unsigned int blksize)
 {
-       struct dasd_eckd_private *private;
        unsigned long *idaws;
        struct dasd_ccw_req *cqr;
        struct ccw1 *ccw;
@@ -2283,7 +2280,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
        unsigned int recoffs;
 
        basedev = block->base;
-       private = (struct dasd_eckd_private *) basedev->private;
        if (rq_data_dir(req) == READ)
                cmd = DASD_ECKD_CCW_READ_TRACK_DATA;
        else if (rq_data_dir(req) == WRITE)
@@ -2556,8 +2552,7 @@ static int prepare_itcw(struct itcw *itcw,
 
        dcw = itcw_add_dcw(itcw, pfx_cmd, 0,
                     &pfxdata, sizeof(pfxdata), total_data_size);
-
-       return rc;
+       return IS_ERR(dcw) ? PTR_ERR(dcw) : 0;
 }
 
 static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
@@ -2573,7 +2568,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
                                               unsigned int blk_per_trk,
                                               unsigned int blksize)
 {
-       struct dasd_eckd_private *private;
        struct dasd_ccw_req *cqr;
        struct req_iterator iter;
        struct bio_vec *bv;
@@ -2594,7 +2588,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
        unsigned int count, count_to_trk_end;
 
        basedev = block->base;
-       private = (struct dasd_eckd_private *) basedev->private;
        if (rq_data_dir(req) == READ) {
                cmd = DASD_ECKD_CCW_READ_TRACK_DATA;
                itcw_op = ITCW_OP_READ;
@@ -2801,7 +2794,6 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
                                               struct dasd_block *block,
                                               struct request *req)
 {
-       struct dasd_eckd_private *private;
        unsigned long *idaws;
        struct dasd_device *basedev;
        struct dasd_ccw_req *cqr;
@@ -2836,7 +2828,6 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
        trkcount = last_trk - first_trk + 1;
        first_offs = 0;
        basedev = block->base;
-       private = (struct dasd_eckd_private *) basedev->private;
 
        if (rq_data_dir(req) == READ)
                cmd = DASD_ECKD_CCW_READ_TRACK;
index dcee3c5c89543db8c8cdddc77b50841341b353c7..a4f117d9fdc6aa0bcc10c9741293b6a862c128c0 100644 (file)
@@ -119,18 +119,6 @@ config S390_TAPE
 comment "S/390 tape interface support"
        depends on S390_TAPE
 
-config S390_TAPE_BLOCK
-       def_bool y
-       prompt "Support for tape block devices"
-       depends on S390_TAPE && BLOCK
-       help
-         Select this option if you want to access your channel-attached tape
-         devices using the block device interface.  This interface is similar
-         to CD-ROM devices on other platforms.  The tapes can only be
-         accessed read-only when using this interface.  Have a look at
-         <file:Documentation/s390/TAPE> for further information about creating
-         volumes for and using this interface.  It is safe to say "Y" here.
-
 comment "S/390 tape hardware support"
        depends on S390_TAPE
 
index efb500ab66c07d84c79176328d6596d92aa8ca00..f3c325207445513c5aca471d413845b6a90980d3 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
-        sclp_cmd.o sclp_config.o sclp_cpi_sys.o
+        sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o
 
 obj-$(CONFIG_TN3270) += raw3270.o
 obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
@@ -22,7 +22,6 @@ obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o
 obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o
 obj-$(CONFIG_VMCP) += vmcp.o
 
-tape-$(CONFIG_S390_TAPE_BLOCK) += tape_block.o
 tape-$(CONFIG_PROC_FS) += tape_proc.o
 tape-objs := tape_core.o tape_std.o tape_char.o $(tape-y)
 obj-$(CONFIG_S390_TAPE) += tape.o tape_class.o
index e0702d3ea33ba669223b5237f3a60acba8cfa35e..4600aa10a1c6c5824f36168fb83b414d2e4e915b 100644 (file)
@@ -97,7 +97,7 @@ static int monwrite_new_hdr(struct mon_private *monpriv)
 {
        struct monwrite_hdr *monhdr = &monpriv->hdr;
        struct mon_buf *monbuf;
-       int rc;
+       int rc = 0;
 
        if (monhdr->datalen > MONWRITE_MAX_DATALEN ||
            monhdr->mon_function > MONWRITE_START_CONFIG ||
@@ -135,7 +135,7 @@ static int monwrite_new_hdr(struct mon_private *monpriv)
                        mon_buf_count++;
        }
        monpriv->current_buf = monbuf;
-       return 0;
+       return rc;
 }
 
 static int monwrite_new_data(struct mon_private *monpriv)
index e21a5c39ef20f2f29609ee989eb75213e6f99f84..810ac38631c35ac919ba7fb110c80d38d75b260f 100644 (file)
@@ -598,7 +598,6 @@ __raw3270_size_device(struct raw3270 *rp)
        static const unsigned char wbuf[] =
                { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
        struct raw3270_ua *uap;
-       unsigned short count;
        int rc;
 
        /*
@@ -653,7 +652,6 @@ __raw3270_size_device(struct raw3270 *rp)
        if (rc)
                return rc;
        /* Got a Query Reply */
-       count = sizeof(rp->init_data) - rp->init_request.rescnt;
        uap = (struct raw3270_ua *) (rp->init_data + 1);
        /* Paranoia check. */
        if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81)
index b76c61f824857d4ed05d3a38e9657f078098ef90..eaa7e78186f969f0176a4c9f067688e1bf981bab 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/suspend.h>
 #include <linux/completion.h>
 #include <linux/platform_device.h>
-#include <asm/s390_ext.h>
 #include <asm/types.h>
 #include <asm/irq.h>
 
@@ -885,12 +884,12 @@ sclp_check_interface(void)
                spin_unlock_irqrestore(&sclp_lock, flags);
                /* Enable service-signal interruption - needs to happen
                 * with IRQs enabled. */
-               ctl_set_bit(0, 9);
+               service_subclass_irq_register();
                /* Wait for signal from interrupt or timeout */
                sclp_sync_wait();
                /* Disable service-signal interruption - needs to happen
                 * with IRQs enabled. */
-               ctl_clear_bit(0,9);
+               service_subclass_irq_unregister();
                spin_lock_irqsave(&sclp_lock, flags);
                del_timer(&sclp_request_timer);
                if (sclp_init_req.status == SCLP_REQ_DONE &&
@@ -1070,7 +1069,7 @@ sclp_init(void)
        spin_unlock_irqrestore(&sclp_lock, flags);
        /* Enable service-signal external interruption - needs to happen with
         * IRQs enabled. */
-       ctl_set_bit(0, 9);
+       service_subclass_irq_register();
        sclp_init_mask(1);
        return 0;
 
index 6bb5a6bdfab52a6d7e66dbcd872b0b2ed9d9ed37..49a1bb52bc87a378b44bc169931377a1290c5225 100644 (file)
@@ -28,6 +28,7 @@
 #define EVTYP_CONFMGMDATA      0x04
 #define EVTYP_SDIAS            0x1C
 #define EVTYP_ASYNC            0x0A
+#define EVTYP_OCF              0x1E
 
 #define EVTYP_OPCMD_MASK       0x80000000
 #define EVTYP_MSG_MASK         0x40000000
@@ -40,6 +41,7 @@
 #define EVTYP_CONFMGMDATA_MASK 0x10000000
 #define EVTYP_SDIAS_MASK       0x00000010
 #define EVTYP_ASYNC_MASK       0x00400000
+#define EVTYP_OCF_MASK         0x00000004
 
 #define GNRLMSGFLGS_DOM                0x8000
 #define GNRLMSGFLGS_SNDALRM    0x4000
@@ -186,4 +188,26 @@ sclp_ascebc_str(unsigned char *str, int nr)
        (MACHINE_IS_VM) ? ASCEBC(str, nr) : ASCEBC_500(str, nr);
 }
 
+static inline struct gds_vector *
+sclp_find_gds_vector(void *start, void *end, u16 id)
+{
+       struct gds_vector *v;
+
+       for (v = start; (void *) v < end; v = (void *) v + v->length)
+               if (v->gds_id == id)
+                       return v;
+       return NULL;
+}
+
+static inline struct gds_subvector *
+sclp_find_gds_subvector(void *start, void *end, u8 key)
+{
+       struct gds_subvector *sv;
+
+       for (sv = start; (void *) sv < end; sv = (void *) sv + sv->length)
+               if (sv->key == key)
+                       return sv;
+       return NULL;
+}
+
 #endif  /* __SCLP_H__ */
index 16e232a99fb7f09150f9e6ecac15c171bc9575f1..95b909ac2b73bf4359b4ea1903db8a817d802e18 100644 (file)
@@ -71,21 +71,9 @@ static struct sclp_register sclp_conf_register =
 
 static int __init sclp_conf_init(void)
 {
-       int rc;
-
        INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify);
        INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify);
-
-       rc = sclp_register(&sclp_conf_register);
-       if (rc)
-               return rc;
-
-       if (!(sclp_conf_register.sclp_send_mask & EVTYP_CONFMGMDATA_MASK)) {
-               pr_warning("no configuration management.\n");
-               sclp_unregister(&sclp_conf_register);
-               rc = -ENOSYS;
-       }
-       return rc;
+       return sclp_register(&sclp_conf_register);
 }
 
 __initcall(sclp_conf_init);
diff --git a/drivers/s390/char/sclp_ocf.c b/drivers/s390/char/sclp_ocf.c
new file mode 100644 (file)
index 0000000..ab294d5
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ *  drivers/s390/char/sclp_ocf.c
+ *    SCLP OCF communication parameters sysfs interface
+ *
+ *    Copyright IBM Corp. 2011
+ *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#define KMSG_COMPONENT "sclp_ocf"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/kmod.h>
+#include <linux/timer.h>
+#include <linux/err.h>
+#include <asm/ebcdic.h>
+#include <asm/sclp.h>
+
+#include "sclp.h"
+
+#define OCF_LENGTH_HMC_NETWORK 8UL
+#define OCF_LENGTH_CPC_NAME 8UL
+
+static char hmc_network[OCF_LENGTH_HMC_NETWORK + 1];
+static char cpc_name[OCF_LENGTH_CPC_NAME + 1];
+
+static DEFINE_SPINLOCK(sclp_ocf_lock);
+static struct work_struct sclp_ocf_change_work;
+
+static struct kset *ocf_kset;
+
+static void sclp_ocf_change_notify(struct work_struct *work)
+{
+       kobject_uevent(&ocf_kset->kobj, KOBJ_CHANGE);
+}
+
+/* Handler for OCF event. Look for the CPC image name. */
+static void sclp_ocf_handler(struct evbuf_header *evbuf)
+{
+       struct gds_vector *v;
+       struct gds_subvector *sv, *netid, *cpc;
+       size_t size;
+
+       /* Find the 0x9f00 block. */
+       v = sclp_find_gds_vector(evbuf + 1, (void *) evbuf + evbuf->length,
+                                0x9f00);
+       if (!v)
+               return;
+       /* Find the 0x9f22 block inside the 0x9f00 block. */
+       v = sclp_find_gds_vector(v + 1, (void *) v + v->length, 0x9f22);
+       if (!v)
+               return;
+       /* Find the 0x81 block inside the 0x9f22 block. */
+       sv = sclp_find_gds_subvector(v + 1, (void *) v + v->length, 0x81);
+       if (!sv)
+               return;
+       /* Find the 0x01 block inside the 0x81 block. */
+       netid = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 1);
+       /* Find the 0x02 block inside the 0x81 block. */
+       cpc = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 2);
+       /* Copy network name and cpc name. */
+       spin_lock(&sclp_ocf_lock);
+       if (netid) {
+               size = min(OCF_LENGTH_HMC_NETWORK, (size_t) netid->length);
+               memcpy(hmc_network, netid + 1, size);
+               EBCASC(hmc_network, size);
+               hmc_network[size] = 0;
+       }
+       if (cpc) {
+               size = min(OCF_LENGTH_CPC_NAME, (size_t) cpc->length);
+               memcpy(cpc_name, cpc + 1, size);
+               EBCASC(cpc_name, size);
+               cpc_name[size] = 0;
+       }
+       spin_unlock(&sclp_ocf_lock);
+       schedule_work(&sclp_ocf_change_work);
+}
+
+static struct sclp_register sclp_ocf_event = {
+       .receive_mask = EVTYP_OCF_MASK,
+       .receiver_fn = sclp_ocf_handler,
+};
+
+static ssize_t cpc_name_show(struct kobject *kobj,
+                            struct kobj_attribute *attr, char *page)
+{
+       int rc;
+
+       spin_lock_irq(&sclp_ocf_lock);
+       rc = snprintf(page, PAGE_SIZE, "%s\n", cpc_name);
+       spin_unlock_irq(&sclp_ocf_lock);
+       return rc;
+}
+
+static struct kobj_attribute cpc_name_attr =
+       __ATTR(cpc_name, 0444, cpc_name_show, NULL);
+
+static ssize_t hmc_network_show(struct kobject *kobj,
+                               struct kobj_attribute *attr, char *page)
+{
+       int rc;
+
+       spin_lock_irq(&sclp_ocf_lock);
+       rc = snprintf(page, PAGE_SIZE, "%s\n", hmc_network);
+       spin_unlock_irq(&sclp_ocf_lock);
+       return rc;
+}
+
+static struct kobj_attribute hmc_network_attr =
+       __ATTR(hmc_network, 0444, hmc_network_show, NULL);
+
+static struct attribute *ocf_attrs[] = {
+       &cpc_name_attr.attr,
+       &hmc_network_attr.attr,
+       NULL,
+};
+
+static struct attribute_group ocf_attr_group = {
+       .attrs = ocf_attrs,
+};
+
+static int __init ocf_init(void)
+{
+       int rc;
+
+       INIT_WORK(&sclp_ocf_change_work, sclp_ocf_change_notify);
+       ocf_kset = kset_create_and_add("ocf", NULL, firmware_kobj);
+       if (!ocf_kset)
+               return -ENOMEM;
+
+       rc = sysfs_create_group(&ocf_kset->kobj, &ocf_attr_group);
+       if (rc) {
+               kset_unregister(ocf_kset);
+               return rc;
+       }
+
+       return sclp_register(&sclp_ocf_event);
+}
+
+device_initcall(ocf_init);
index 6a1c58dc61a78e920c4e626ab61b04f1747c3418..fa733ecd3d70fe8c21915dc915d2c058a000eefa 100644 (file)
@@ -69,9 +69,6 @@ static DEFINE_MUTEX(sdias_mutex);
 
 static void sdias_callback(struct sclp_req *request, void *data)
 {
-       struct sdias_sccb *cbsccb;
-
-       cbsccb = (struct sdias_sccb *) request->sccb;
        sclp_req_done = 1;
        wake_up(&sdias_wq); /* Inform caller, that request is complete */
        TRACE("callback done\n");
index 8258d590505f1444e9a4a4ed8cab036fe400b72e..a879c139926ac0deb7ed012684813ca90f934113 100644 (file)
@@ -408,118 +408,72 @@ static int sclp_switch_cases(unsigned char *buf, int count)
        return op - buf;
 }
 
-static void
-sclp_get_input(unsigned char *start, unsigned char *end)
+static void sclp_get_input(struct gds_subvector *sv)
 {
+       unsigned char *str;
        int count;
 
-       count = end - start;
+       str = (unsigned char *) (sv + 1);
+       count = sv->length - sizeof(*sv);
        if (sclp_tty_tolower)
-               EBC_TOLOWER(start, count);
-       count = sclp_switch_cases(start, count);
+               EBC_TOLOWER(str, count);
+       count = sclp_switch_cases(str, count);
        /* convert EBCDIC to ASCII (modify original input in SCCB) */
-       sclp_ebcasc_str(start, count);
+       sclp_ebcasc_str(str, count);
 
        /* transfer input to high level driver */
-       sclp_tty_input(start, count);
-}
-
-static inline struct gds_vector *
-find_gds_vector(struct gds_vector *start, struct gds_vector *end, u16 id)
-{
-       struct gds_vector *vec;
-
-       for (vec = start; vec < end; vec = (void *) vec + vec->length)
-               if (vec->gds_id == id)
-                       return vec;
-       return NULL;
+       sclp_tty_input(str, count);
 }
 
-static inline struct gds_subvector *
-find_gds_subvector(struct gds_subvector *start,
-                  struct gds_subvector *end, u8 key)
+static inline void sclp_eval_selfdeftextmsg(struct gds_subvector *sv)
 {
-       struct gds_subvector *subvec;
+       void *end;
 
-       for (subvec = start; subvec < end;
-            subvec = (void *) subvec + subvec->length)
-               if (subvec->key == key)
-                       return subvec;
-       return NULL;
+       end = (void *) sv + sv->length;
+       for (sv = sv + 1; (void *) sv < end; sv = (void *) sv + sv->length)
+               if (sv->key == 0x30)
+                       sclp_get_input(sv);
 }
 
-static inline void
-sclp_eval_selfdeftextmsg(struct gds_subvector *start,
-                        struct gds_subvector *end)
+static inline void sclp_eval_textcmd(struct gds_vector *v)
 {
-       struct gds_subvector *subvec;
-
-       subvec = start;
-       while (subvec < end) {
-               subvec = find_gds_subvector(subvec, end, 0x30);
-               if (!subvec)
-                       break;
-               sclp_get_input((unsigned char *)(subvec + 1),
-                              (unsigned char *) subvec + subvec->length);
-               subvec = (void *) subvec + subvec->length;
-       }
-}
+       struct gds_subvector *sv;
+       void *end;
 
-static inline void
-sclp_eval_textcmd(struct gds_subvector *start,
-                 struct gds_subvector *end)
-{
-       struct gds_subvector *subvec;
+       end = (void *) v + v->length;
+       for (sv = (struct gds_subvector *) (v + 1);
+            (void *) sv < end; sv = (void *) sv + sv->length)
+               if (sv->key == GDS_KEY_SELFDEFTEXTMSG)
+                       sclp_eval_selfdeftextmsg(sv);
 
-       subvec = start;
-       while (subvec < end) {
-               subvec = find_gds_subvector(subvec, end,
-                                           GDS_KEY_SELFDEFTEXTMSG);
-               if (!subvec)
-                       break;
-               sclp_eval_selfdeftextmsg((struct gds_subvector *)(subvec + 1),
-                                        (void *)subvec + subvec->length);
-               subvec = (void *) subvec + subvec->length;
-       }
 }
 
-static inline void
-sclp_eval_cpmsu(struct gds_vector *start, struct gds_vector *end)
+static inline void sclp_eval_cpmsu(struct gds_vector *v)
 {
-       struct gds_vector *vec;
+       void *end;
 
-       vec = start;
-       while (vec < end) {
-               vec = find_gds_vector(vec, end, GDS_ID_TEXTCMD);
-               if (!vec)
-                       break;
-               sclp_eval_textcmd((struct gds_subvector *)(vec + 1),
-                                 (void *) vec + vec->length);
-               vec = (void *) vec + vec->length;
-       }
+       end = (void *) v + v->length;
+       for (v = v + 1; (void *) v < end; v = (void *) v + v->length)
+               if (v->gds_id == GDS_ID_TEXTCMD)
+                       sclp_eval_textcmd(v);
 }
 
 
-static inline void
-sclp_eval_mdsmu(struct gds_vector *start, void *end)
+static inline void sclp_eval_mdsmu(struct gds_vector *v)
 {
-       struct gds_vector *vec;
-
-       vec = find_gds_vector(start, end, GDS_ID_CPMSU);
-       if (vec)
-               sclp_eval_cpmsu(vec + 1, (void *) vec + vec->length);
+       v = sclp_find_gds_vector(v + 1, (void *) v + v->length, GDS_ID_CPMSU);
+       if (v)
+               sclp_eval_cpmsu(v);
 }
 
-static void
-sclp_tty_receiver(struct evbuf_header *evbuf)
+static void sclp_tty_receiver(struct evbuf_header *evbuf)
 {
-       struct gds_vector *start, *end, *vec;
+       struct gds_vector *v;
 
-       start = (struct gds_vector *)(evbuf + 1);
-       end = (void *) evbuf + evbuf->length;
-       vec = find_gds_vector(start, end, GDS_ID_MDSMU);
-       if (vec)
-               sclp_eval_mdsmu(vec + 1, (void *) vec + vec->length);
+       v = sclp_find_gds_vector(evbuf + 1, (void *) evbuf + evbuf->length,
+                                GDS_ID_MDSMU);
+       if (v)
+               sclp_eval_mdsmu(v);
 }
 
 static void
index b98dcbd16711e7978d8c1fc58394f4797d851fe8..a7d570728882cae1ce2443baa44044e1f824f00e 100644 (file)
@@ -796,10 +796,8 @@ static void tape_3590_med_state_set(struct tape_device *device,
 static int
 tape_3590_done(struct tape_device *device, struct tape_request *request)
 {
-       struct tape_3590_disc_data *disc_data;
 
        DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]);
-       disc_data = device->discdata;
 
        switch (request->op) {
        case TO_BSB:
@@ -1394,17 +1392,12 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb)
 static int tape_3590_crypt_error(struct tape_device *device,
                                 struct tape_request *request, struct irb *irb)
 {
-       u8 cu_rc, ekm_rc1;
+       u8 cu_rc;
        u16 ekm_rc2;
-       u32 drv_rc;
-       const char *bus_id;
        char *sense;
 
        sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data;
-       bus_id = dev_name(&device->cdev->dev);
        cu_rc = sense[0];
-       drv_rc = *((u32*) &sense[5]) & 0xffffff;
-       ekm_rc1 = sense[9];
        ekm_rc2 = *((u16*) &sense[10]);
        if ((cu_rc == 0) && (ekm_rc2 == 0xee31))
                /* key not defined on EKM */
@@ -1429,7 +1422,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
                     struct irb *irb)
 {
        struct tape_3590_sense *sense;
-       int rc;
 
 #ifdef CONFIG_S390_TAPE_BLOCK
        if (request->op == TO_BLOCK) {
@@ -1454,7 +1446,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
         *   - "break":     basic error recovery is done
         *   - "goto out:": just print error message if available
         */
-       rc = -EIO;
        switch (sense->rc_rqc) {
 
        case 0x1110:
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
deleted file mode 100644 (file)
index 1b3924c..0000000
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- *  drivers/s390/char/tape_block.c
- *    block device frontend for tape device driver
- *
- *  S390 and zSeries version
- *    Copyright (C) 2001,2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Carsten Otte <cotte@de.ibm.com>
- *              Tuan Ngo-Anh <ngoanh@de.ibm.com>
- *              Martin Schwidefsky <schwidefsky@de.ibm.com>
- *              Stefan Bader <shbader@de.ibm.com>
- */
-
-#define KMSG_COMPONENT "tape"
-#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
-
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/blkdev.h>
-#include <linux/mutex.h>
-#include <linux/interrupt.h>
-#include <linux/buffer_head.h>
-#include <linux/kernel.h>
-
-#include <asm/debug.h>
-
-#define TAPE_DBF_AREA  tape_core_dbf
-
-#include "tape.h"
-
-#define TAPEBLOCK_MAX_SEC      100
-#define TAPEBLOCK_MIN_REQUEUE  3
-
-/*
- * 2003/11/25  Stefan Bader <shbader@de.ibm.com>
- *
- * In 2.5/2.6 the block device request function is very likely to be called
- * with disabled interrupts (e.g. generic_unplug_device). So the driver can't
- * just call any function that tries to allocate CCW requests from that con-
- * text since it might sleep. There are two choices to work around this:
- *     a) do not allocate with kmalloc but use its own memory pool
- *      b) take requests from the queue outside that context, knowing that
- *         allocation might sleep
- */
-
-/*
- * file operation structure for tape block frontend
- */
-static DEFINE_MUTEX(tape_block_mutex);
-static int tapeblock_open(struct block_device *, fmode_t);
-static int tapeblock_release(struct gendisk *, fmode_t);
-static unsigned int tapeblock_check_events(struct gendisk *, unsigned int);
-static int tapeblock_revalidate_disk(struct gendisk *);
-
-static const struct block_device_operations tapeblock_fops = {
-       .owner           = THIS_MODULE,
-       .open            = tapeblock_open,
-       .release         = tapeblock_release,
-       .check_events    = tapeblock_check_events,
-       .revalidate_disk = tapeblock_revalidate_disk,
-};
-
-static int tapeblock_major = 0;
-
-static void
-tapeblock_trigger_requeue(struct tape_device *device)
-{
-       /* Protect against rescheduling. */
-       if (atomic_cmpxchg(&device->blk_data.requeue_scheduled, 0, 1) != 0)
-               return;
-       schedule_work(&device->blk_data.requeue_task);
-}
-
-/*
- * Post finished request.
- */
-static void
-__tapeblock_end_request(struct tape_request *ccw_req, void *data)
-{
-       struct tape_device *device;
-       struct request *req;
-
-       DBF_LH(6, "__tapeblock_end_request()\n");
-
-       device = ccw_req->device;
-       req = (struct request *) data;
-       blk_end_request_all(req, (ccw_req->rc == 0) ? 0 : -EIO);
-       if (ccw_req->rc == 0)
-               /* Update position. */
-               device->blk_data.block_position =
-                 (blk_rq_pos(req) + blk_rq_sectors(req)) >> TAPEBLOCK_HSEC_S2B;
-       else
-               /* We lost the position information due to an error. */
-               device->blk_data.block_position = -1;
-       device->discipline->free_bread(ccw_req);
-       if (!list_empty(&device->req_queue) ||
-           blk_peek_request(device->blk_data.request_queue))
-               tapeblock_trigger_requeue(device);
-}
-
-/*
- * Feed the tape device CCW queue with requests supplied in a list.
- */
-static int
-tapeblock_start_request(struct tape_device *device, struct request *req)
-{
-       struct tape_request *   ccw_req;
-       int                     rc;
-
-       DBF_LH(6, "tapeblock_start_request(%p, %p)\n", device, req);
-
-       ccw_req = device->discipline->bread(device, req);
-       if (IS_ERR(ccw_req)) {
-               DBF_EVENT(1, "TBLOCK: bread failed\n");
-               blk_end_request_all(req, -EIO);
-               return PTR_ERR(ccw_req);
-       }
-       ccw_req->callback = __tapeblock_end_request;
-       ccw_req->callback_data = (void *) req;
-       ccw_req->retries = TAPEBLOCK_RETRIES;
-
-       rc = tape_do_io_async(device, ccw_req);
-       if (rc) {
-               /*
-                * Start/enqueueing failed. No retries in
-                * this case.
-                */
-               blk_end_request_all(req, -EIO);
-               device->discipline->free_bread(ccw_req);
-       }
-
-       return rc;
-}
-
-/*
- * Move requests from the block device request queue to the tape device ccw
- * queue.
- */
-static void
-tapeblock_requeue(struct work_struct *work) {
-       struct tape_blk_data *  blkdat;
-       struct tape_device *    device;
-       struct request_queue *  queue;
-       int                     nr_queued;
-       struct request *        req;
-       struct list_head *      l;
-       int                     rc;
-
-       blkdat = container_of(work, struct tape_blk_data, requeue_task);
-       device = blkdat->device;
-       if (!device)
-               return;
-
-       spin_lock_irq(get_ccwdev_lock(device->cdev));
-       queue  = device->blk_data.request_queue;
-
-       /* Count number of requests on ccw queue. */
-       nr_queued = 0;
-       list_for_each(l, &device->req_queue)
-               nr_queued++;
-       spin_unlock(get_ccwdev_lock(device->cdev));
-
-       spin_lock_irq(&device->blk_data.request_queue_lock);
-       while (
-               blk_peek_request(queue) &&
-               nr_queued < TAPEBLOCK_MIN_REQUEUE
-       ) {
-               req = blk_fetch_request(queue);
-               if (rq_data_dir(req) == WRITE) {
-                       DBF_EVENT(1, "TBLOCK: Rejecting write request\n");
-                       spin_unlock_irq(&device->blk_data.request_queue_lock);
-                       blk_end_request_all(req, -EIO);
-                       spin_lock_irq(&device->blk_data.request_queue_lock);
-                       continue;
-               }
-               nr_queued++;
-               spin_unlock_irq(&device->blk_data.request_queue_lock);
-               rc = tapeblock_start_request(device, req);
-               spin_lock_irq(&device->blk_data.request_queue_lock);
-       }
-       spin_unlock_irq(&device->blk_data.request_queue_lock);
-       atomic_set(&device->blk_data.requeue_scheduled, 0);
-}
-
-/*
- * Tape request queue function. Called from ll_rw_blk.c
- */
-static void
-tapeblock_request_fn(struct request_queue *queue)
-{
-       struct tape_device *device;
-
-       device = (struct tape_device *) queue->queuedata;
-       DBF_LH(6, "tapeblock_request_fn(device=%p)\n", device);
-       BUG_ON(device == NULL);
-       tapeblock_trigger_requeue(device);
-}
-
-/*
- * This function is called for every new tapedevice
- */
-int
-tapeblock_setup_device(struct tape_device * device)
-{
-       struct tape_blk_data *  blkdat;
-       struct gendisk *        disk;
-       int                     rc;
-
-       blkdat = &device->blk_data;
-       blkdat->device = device;
-       spin_lock_init(&blkdat->request_queue_lock);
-       atomic_set(&blkdat->requeue_scheduled, 0);
-
-       blkdat->request_queue = blk_init_queue(
-               tapeblock_request_fn,
-               &blkdat->request_queue_lock
-       );
-       if (!blkdat->request_queue)
-               return -ENOMEM;
-
-       rc = elevator_change(blkdat->request_queue, "noop");
-       if (rc)
-               goto cleanup_queue;
-
-       blk_queue_logical_block_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE);
-       blk_queue_max_hw_sectors(blkdat->request_queue, TAPEBLOCK_MAX_SEC);
-       blk_queue_max_segments(blkdat->request_queue, -1L);
-       blk_queue_max_segment_size(blkdat->request_queue, -1L);
-       blk_queue_segment_boundary(blkdat->request_queue, -1L);
-
-       disk = alloc_disk(1);
-       if (!disk) {
-               rc = -ENOMEM;
-               goto cleanup_queue;
-       }
-
-       disk->major = tapeblock_major;
-       disk->first_minor = device->first_minor;
-       disk->fops = &tapeblock_fops;
-       disk->private_data = tape_get_device(device);
-       disk->queue = blkdat->request_queue;
-       set_capacity(disk, 0);
-       sprintf(disk->disk_name, "btibm%d",
-               device->first_minor / TAPE_MINORS_PER_DEV);
-
-       blkdat->disk = disk;
-       blkdat->medium_changed = 1;
-       blkdat->request_queue->queuedata = tape_get_device(device);
-
-       add_disk(disk);
-
-       tape_get_device(device);
-       INIT_WORK(&blkdat->requeue_task, tapeblock_requeue);
-
-       return 0;
-
-cleanup_queue:
-       blk_cleanup_queue(blkdat->request_queue);
-       blkdat->request_queue = NULL;
-
-       return rc;
-}
-
-void
-tapeblock_cleanup_device(struct tape_device *device)
-{
-       flush_work_sync(&device->blk_data.requeue_task);
-       tape_put_device(device);
-
-       if (!device->blk_data.disk) {
-               goto cleanup_queue;
-       }
-
-       del_gendisk(device->blk_data.disk);
-       device->blk_data.disk->private_data = NULL;
-       tape_put_device(device);
-       put_disk(device->blk_data.disk);
-
-       device->blk_data.disk = NULL;
-cleanup_queue:
-       device->blk_data.request_queue->queuedata = NULL;
-       tape_put_device(device);
-
-       blk_cleanup_queue(device->blk_data.request_queue);
-       device->blk_data.request_queue = NULL;
-}
-
-/*
- * Detect number of blocks of the tape.
- * FIXME: can we extent this to detect the blocks size as well ?
- */
-static int
-tapeblock_revalidate_disk(struct gendisk *disk)
-{
-       struct tape_device *    device;
-       unsigned int            nr_of_blks;
-       int                     rc;
-
-       device = (struct tape_device *) disk->private_data;
-       BUG_ON(!device);
-
-       if (!device->blk_data.medium_changed)
-               return 0;
-
-       rc = tape_mtop(device, MTFSFM, 1);
-       if (rc)
-               return rc;
-
-       rc = tape_mtop(device, MTTELL, 1);
-       if (rc < 0)
-               return rc;
-
-       pr_info("%s: Determining the size of the recorded area...\n",
-               dev_name(&device->cdev->dev));
-       DBF_LH(3, "Image file ends at %d\n", rc);
-       nr_of_blks = rc;
-
-       /* This will fail for the first file. Catch the error by checking the
-        * position. */
-       tape_mtop(device, MTBSF, 1);
-
-       rc = tape_mtop(device, MTTELL, 1);
-       if (rc < 0)
-               return rc;
-
-       if (rc > nr_of_blks)
-               return -EINVAL;
-
-       DBF_LH(3, "Image file starts at %d\n", rc);
-       device->bof = rc;
-       nr_of_blks -= rc;
-
-       pr_info("%s: The size of the recorded area is %i blocks\n",
-               dev_name(&device->cdev->dev), nr_of_blks);
-       set_capacity(device->blk_data.disk,
-               nr_of_blks*(TAPEBLOCK_HSEC_SIZE/512));
-
-       device->blk_data.block_position = 0;
-       device->blk_data.medium_changed = 0;
-       return 0;
-}
-
-static unsigned int
-tapeblock_check_events(struct gendisk *disk, unsigned int clearing)
-{
-       struct tape_device *device;
-
-       device = (struct tape_device *) disk->private_data;
-       DBF_LH(6, "tapeblock_medium_changed(%p) = %d\n",
-               device, device->blk_data.medium_changed);
-
-       return device->blk_data.medium_changed ? DISK_EVENT_MEDIA_CHANGE : 0;
-}
-
-/*
- * Block frontend tape device open function.
- */
-static int
-tapeblock_open(struct block_device *bdev, fmode_t mode)
-{
-       struct gendisk *        disk = bdev->bd_disk;
-       struct tape_device *    device;
-       int                     rc;
-
-       mutex_lock(&tape_block_mutex);
-       device = tape_get_device(disk->private_data);
-
-       if (device->required_tapemarks) {
-               DBF_EVENT(2, "TBLOCK: missing tapemarks\n");
-               pr_warning("%s: Opening the tape failed because of missing "
-                          "end-of-file marks\n", dev_name(&device->cdev->dev));
-               rc = -EPERM;
-               goto put_device;
-       }
-
-       rc = tape_open(device);
-       if (rc)
-               goto put_device;
-
-       rc = tapeblock_revalidate_disk(disk);
-       if (rc)
-               goto release;
-
-       /*
-        * Note: The reference to <device> is hold until the release function
-        *       is called.
-        */
-       tape_state_set(device, TS_BLKUSE);
-       mutex_unlock(&tape_block_mutex);
-       return 0;
-
-release:
-       tape_release(device);
- put_device:
-       tape_put_device(device);
-       mutex_unlock(&tape_block_mutex);
-       return rc;
-}
-
-/*
- * Block frontend tape device release function.
- *
- * Note: One reference to the tape device was made by the open function. So
- *       we just get the pointer here and release the reference.
- */
-static int
-tapeblock_release(struct gendisk *disk, fmode_t mode)
-{
-       struct tape_device *device = disk->private_data;
-       mutex_lock(&tape_block_mutex);
-       tape_state_set(device, TS_IN_USE);
-       tape_release(device);
-       tape_put_device(device);
-       mutex_unlock(&tape_block_mutex);
-
-       return 0;
-}
-
-/*
- * Initialize block device frontend.
- */
-int
-tapeblock_init(void)
-{
-       int rc;
-
-       /* Register the tape major number to the kernel */
-       rc = register_blkdev(tapeblock_major, "tBLK");
-       if (rc < 0)
-               return rc;
-
-       if (tapeblock_major == 0)
-               tapeblock_major = rc;
-       return 0;
-}
-
-/*
- * Deregister major for block device frontend
- */
-void
-tapeblock_exit(void)
-{
-       unregister_blkdev(tapeblock_major, "tBLK");
-}
index 3c3f342149ecd09d7b48334550047425fe42105c..e7650170274ac3e3ee12e6f1deca3bdd1e826b95 100644 (file)
@@ -564,7 +564,6 @@ int
 tape_std_mtreten(struct tape_device *device, int mt_count)
 {
        struct tape_request *request;
-       int rc;
 
        request = tape_alloc_request(4, 0);
        if (IS_ERR(request))
@@ -576,7 +575,7 @@ tape_std_mtreten(struct tape_device *device, int mt_count)
        tape_ccw_cc(request->cpaddr + 2, NOP, 0, NULL);
        tape_ccw_end(request->cpaddr + 3, CCW_CMD_TIC, 0, request->cpaddr);
        /* execute it, MTRETEN rc gets ignored */
-       rc = tape_do_io_interruptible(device, request);
+       tape_do_io_interruptible(device, request);
        tape_free_request(request);
        return tape_mtop(device, MTREW, 1);
 }
index 0689fcf23a118b0b8917bd3a16199ce6539107a1..75c3f1f8fd434301c3ba4a07a632e0ffefa6aac3 100644 (file)
@@ -326,6 +326,36 @@ static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
        s390_process_res_acc(&link);
 }
 
+static void chsc_process_sei_chp_avail(struct chsc_sei_area *sei_area)
+{
+       struct channel_path *chp;
+       struct chp_id chpid;
+       u8 *data;
+       int num;
+
+       CIO_CRW_EVENT(4, "chsc: channel path availability information\n");
+       if (sei_area->rs != 0)
+               return;
+       data = sei_area->ccdf;
+       chp_id_init(&chpid);
+       for (num = 0; num <= __MAX_CHPID; num++) {
+               if (!chp_test_bit(data, num))
+                       continue;
+               chpid.id = num;
+
+               CIO_CRW_EVENT(4, "Update information for channel path "
+                             "%x.%02x\n", chpid.cssid, chpid.id);
+               chp = chpid_to_chp(chpid);
+               if (!chp) {
+                       chp_new(chpid);
+                       continue;
+               }
+               mutex_lock(&chp->lock);
+               chsc_determine_base_channel_path_desc(chpid, &chp->desc);
+               mutex_unlock(&chp->lock);
+       }
+}
+
 struct chp_config_data {
        u8 map[32];
        u8 op;
@@ -376,9 +406,12 @@ static void chsc_process_sei(struct chsc_sei_area *sei_area)
        case 1: /* link incident*/
                chsc_process_sei_link_incident(sei_area);
                break;
-       case 2: /* i/o resource accessibiliy */
+       case 2: /* i/o resource accessibility */
                chsc_process_sei_res_acc(sei_area);
                break;
+       case 7: /* channel-path-availability information */
+               chsc_process_sei_chp_avail(sei_area);
+               break;
        case 8: /* channel-path-configuration notification */
                chsc_process_sei_chp_config(sei_area);
                break;
index 6084103672b5ee9df3732958cff89f8d78653ec0..52c233fa2b1281d14a2881618465606447bef365 100644 (file)
@@ -408,9 +408,10 @@ ccw_device_done(struct ccw_device *cdev, int state)
                CIO_MSG_EVENT(0, "Disconnected device %04x on subchannel "
                              "%04x\n", cdev->private->dev_id.devno,
                              sch->schid.sch_no);
-               if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK)
+               if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK) {
+                       cdev->private->state = DEV_STATE_NOT_OPER;
                        ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
-               else
+               else
                        ccw_device_set_disconnected(cdev);
                cdev->private->flags.donotify = 0;
                break;
@@ -840,9 +841,6 @@ call_handler:
 static void
 ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event)
 {
-       struct subchannel *sch;
-
-       sch = to_subchannel(cdev->dev.parent);
        ccw_device_set_timeout(cdev, 0);
        /* Start delayed path verification. */
        ccw_device_online_verify(cdev, 0);
index 651976b54af80395547d675f1c538580521e0644..f98698d5735e887e0fb6cc46f00a63012ecdccb5 100644 (file)
@@ -418,12 +418,9 @@ int ccw_device_resume(struct ccw_device *cdev)
 int
 ccw_device_call_handler(struct ccw_device *cdev)
 {
-       struct subchannel *sch;
        unsigned int stctl;
        int ending_status;
 
-       sch = to_subchannel(cdev->dev.parent);
-
        /*
         * we allow for the device action handler if .
         *  - we received ending status
index e8f267eb88873b2a65e8d0cb05bcce3dc5c2c33c..570d4da10696177e6a05ed78dbeb459617d8f49c 100644 (file)
@@ -416,7 +416,7 @@ static void process_buffer_error(struct qdio_q *q, int count)
 
        /* special handling for no target buffer empty */
        if ((!q->is_input_q &&
-           (q->sbal[q->first_to_check]->element[15].flags & 0xff) == 0x10)) {
+           (q->sbal[q->first_to_check]->element[15].sflags) == 0x10)) {
                qperf_inc(q, target_full);
                DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "OUTFULL FTC:%02x",
                              q->first_to_check);
@@ -427,8 +427,8 @@ static void process_buffer_error(struct qdio_q *q, int count)
        DBF_ERROR((q->is_input_q) ? "IN:%2d" : "OUT:%2d", q->nr);
        DBF_ERROR("FTC:%3d C:%3d", q->first_to_check, count);
        DBF_ERROR("F14:%2x F15:%2x",
-                 q->sbal[q->first_to_check]->element[14].flags & 0xff,
-                 q->sbal[q->first_to_check]->element[15].flags & 0xff);
+                 q->sbal[q->first_to_check]->element[14].sflags,
+                 q->sbal[q->first_to_check]->element[15].sflags);
 
        /*
         * Interrupts may be avoided as long as the error is present
@@ -1446,7 +1446,7 @@ set:
 static int handle_outbound(struct qdio_q *q, unsigned int callflags,
                           int bufnr, int count)
 {
-       unsigned char state;
+       unsigned char state = 0;
        int used, rc = 0;
 
        qperf_inc(q, outbound_call);
index 67302b944ab34e996364c60f849ea3961ad6b81e..16e4a25596e78a03e53adc88d6170008b1ef3f2a 100644 (file)
@@ -1183,8 +1183,12 @@ static void ap_scan_bus(struct work_struct *unused)
                INIT_LIST_HEAD(&ap_dev->list);
                setup_timer(&ap_dev->timeout, ap_request_timeout,
                            (unsigned long) ap_dev);
-               if (device_type == 0)
-                       ap_probe_device_type(ap_dev);
+               if (device_type == 0) {
+                       if (ap_probe_device_type(ap_dev)) {
+                               kfree(ap_dev);
+                               continue;
+                       }
+               }
                else
                        ap_dev->device_type = device_type;
 
index 607998f0b7d8580c05c4fec47cf672bfad9d3c14..aec60d55b10dc238e5b3529507fe9afc43db173e 100644 (file)
@@ -25,7 +25,6 @@
 #include <asm/kvm_para.h>
 #include <asm/kvm_virtio.h>
 #include <asm/setup.h>
-#include <asm/s390_ext.h>
 #include <asm/irq.h>
 
 #define VIRTIO_SUBCODE_64 0x0D00
@@ -441,7 +440,7 @@ static int __init kvm_devices_init(void)
 
        INIT_WORK(&hotplug_work, hotplug_devices);
 
-       ctl_set_bit(0, 9);
+       service_subclass_irq_register();
        register_external_interrupt(0x2603, kvm_extint_handler);
 
        scan_devices();
index 55c6aa1c9704f54e5c6f26e21a7b1f5c7610dbe0..d3cee33e554cace96b035b82c80ac87fc1485b01 100644 (file)
@@ -361,7 +361,7 @@ enum qeth_header_ids {
 
 static inline int qeth_is_last_sbale(struct qdio_buffer_element *sbale)
 {
-       return (sbale->flags & SBAL_FLAGS_LAST_ENTRY);
+       return (sbale->eflags & SBAL_EFLAGS_LAST_ENTRY);
 }
 
 enum qeth_qdio_buffer_states {
index 503678a30981f071f8e8ef9db25729817cc5d07a..dd08f7b42fb8ff26ebf91d943fa58d01376d6184 100644 (file)
@@ -890,7 +890,7 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
        struct sk_buff *skb;
 
        /* is PCI flag set on buffer? */
-       if (buf->buffer->element[0].flags & 0x40)
+       if (buf->buffer->element[0].sflags & SBAL_SFLAGS0_PCI_REQ)
                atomic_dec(&queue->set_pci_flags_count);
 
        skb = skb_dequeue(&buf->skb_list);
@@ -906,9 +906,11 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
                buf->is_header[i] = 0;
                buf->buffer->element[i].length = 0;
                buf->buffer->element[i].addr = NULL;
-               buf->buffer->element[i].flags = 0;
+               buf->buffer->element[i].eflags = 0;
+               buf->buffer->element[i].sflags = 0;
        }
-       buf->buffer->element[15].flags = 0;
+       buf->buffer->element[15].eflags = 0;
+       buf->buffer->element[15].sflags = 0;
        buf->next_element_to_fill = 0;
        atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY);
 }
@@ -2368,9 +2370,10 @@ static int qeth_init_input_buffer(struct qeth_card *card,
                buf->buffer->element[i].length = PAGE_SIZE;
                buf->buffer->element[i].addr =  pool_entry->elements[i];
                if (i == QETH_MAX_BUFFER_ELEMENTS(card) - 1)
-                       buf->buffer->element[i].flags = SBAL_FLAGS_LAST_ENTRY;
+                       buf->buffer->element[i].eflags = SBAL_EFLAGS_LAST_ENTRY;
                else
-                       buf->buffer->element[i].flags = 0;
+                       buf->buffer->element[i].eflags = 0;
+               buf->buffer->element[i].sflags = 0;
        }
        return 0;
 }
@@ -2718,11 +2721,11 @@ int qeth_check_qdio_errors(struct qeth_card *card, struct qdio_buffer *buf,
        if (qdio_error) {
                QETH_CARD_TEXT(card, 2, dbftext);
                QETH_CARD_TEXT_(card, 2, " F15=%02X",
-                              buf->element[15].flags & 0xff);
+                              buf->element[15].sflags);
                QETH_CARD_TEXT_(card, 2, " F14=%02X",
-                              buf->element[14].flags & 0xff);
+                              buf->element[14].sflags);
                QETH_CARD_TEXT_(card, 2, " qerr=%X", qdio_error);
-               if ((buf->element[15].flags & 0xff) == 0x12) {
+               if ((buf->element[15].sflags) == 0x12) {
                        card->stats.rx_dropped++;
                        return 0;
                } else
@@ -2798,7 +2801,7 @@ EXPORT_SYMBOL_GPL(qeth_queue_input_buffer);
 static int qeth_handle_send_error(struct qeth_card *card,
                struct qeth_qdio_out_buffer *buffer, unsigned int qdio_err)
 {
-       int sbalf15 = buffer->buffer->element[15].flags & 0xff;
+       int sbalf15 = buffer->buffer->element[15].sflags;
 
        QETH_CARD_TEXT(card, 6, "hdsnderr");
        if (card->info.type == QETH_CARD_TYPE_IQD) {
@@ -2907,8 +2910,8 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
 
        for (i = index; i < index + count; ++i) {
                buf = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
-               buf->buffer->element[buf->next_element_to_fill - 1].flags |=
-                               SBAL_FLAGS_LAST_ENTRY;
+               buf->buffer->element[buf->next_element_to_fill - 1].eflags |=
+                               SBAL_EFLAGS_LAST_ENTRY;
 
                if (queue->card->info.type == QETH_CARD_TYPE_IQD)
                        continue;
@@ -2921,7 +2924,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
                                /* it's likely that we'll go to packing
                                 * mode soon */
                                atomic_inc(&queue->set_pci_flags_count);
-                               buf->buffer->element[0].flags |= 0x40;
+                               buf->buffer->element[0].sflags |= SBAL_SFLAGS0_PCI_REQ;
                        }
                } else {
                        if (!atomic_read(&queue->set_pci_flags_count)) {
@@ -2934,7 +2937,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
                                 * further send was requested by the stack
                                 */
                                atomic_inc(&queue->set_pci_flags_count);
-                               buf->buffer->element[0].flags |= 0x40;
+                               buf->buffer->element[0].sflags |= SBAL_SFLAGS0_PCI_REQ;
                        }
                }
        }
@@ -3180,20 +3183,20 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb,
                if (!length) {
                        if (first_lap)
                                if (skb_shinfo(skb)->nr_frags)
-                                       buffer->element[element].flags =
-                                               SBAL_FLAGS_FIRST_FRAG;
+                                       buffer->element[element].eflags =
+                                               SBAL_EFLAGS_FIRST_FRAG;
                                else
-                                       buffer->element[element].flags = 0;
+                                       buffer->element[element].eflags = 0;
                        else
-                               buffer->element[element].flags =
-                                   SBAL_FLAGS_MIDDLE_FRAG;
+                               buffer->element[element].eflags =
+                                   SBAL_EFLAGS_MIDDLE_FRAG;
                } else {
                        if (first_lap)
-                               buffer->element[element].flags =
-                                   SBAL_FLAGS_FIRST_FRAG;
+                               buffer->element[element].eflags =
+                                   SBAL_EFLAGS_FIRST_FRAG;
                        else
-                               buffer->element[element].flags =
-                                   SBAL_FLAGS_MIDDLE_FRAG;
+                               buffer->element[element].eflags =
+                                   SBAL_EFLAGS_MIDDLE_FRAG;
                }
                data += length_here;
                element++;
@@ -3205,12 +3208,12 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb,
                buffer->element[element].addr = (char *)page_to_phys(frag->page)
                        + frag->page_offset;
                buffer->element[element].length = frag->size;
-               buffer->element[element].flags = SBAL_FLAGS_MIDDLE_FRAG;
+               buffer->element[element].eflags = SBAL_EFLAGS_MIDDLE_FRAG;
                element++;
        }
 
-       if (buffer->element[element - 1].flags)
-               buffer->element[element - 1].flags = SBAL_FLAGS_LAST_FRAG;
+       if (buffer->element[element - 1].eflags)
+               buffer->element[element - 1].eflags = SBAL_EFLAGS_LAST_FRAG;
        *next_element_to_fill = element;
 }
 
@@ -3234,7 +3237,7 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
                /*fill first buffer entry only with header information */
                buffer->element[element].addr = skb->data;
                buffer->element[element].length = hdr_len;
-               buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG;
+               buffer->element[element].eflags = SBAL_EFLAGS_FIRST_FRAG;
                buf->next_element_to_fill++;
                skb->data += hdr_len;
                skb->len  -= hdr_len;
@@ -3246,7 +3249,7 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
                buffer->element[element].addr = hdr;
                buffer->element[element].length = sizeof(struct qeth_hdr) +
                                                        hd_len;
-               buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG;
+               buffer->element[element].eflags = SBAL_EFLAGS_FIRST_FRAG;
                buf->is_header[element] = 1;
                buf->next_element_to_fill++;
        }
index 8512b5c0ef82868d0a5ac87b0d813b84abacff81..022fb6a8cb8339a6a8854b69ffc7021a3bdce1cf 100644 (file)
@@ -640,7 +640,7 @@ static struct fsf_qtcb *zfcp_qtcb_alloc(mempool_t *pool)
 }
 
 static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,
-                                               u32 fsf_cmd, u32 sbtype,
+                                               u32 fsf_cmd, u8 sbtype,
                                                mempool_t *pool)
 {
        struct zfcp_adapter *adapter = qdio->adapter;
@@ -841,7 +841,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *scmnd)
        if (zfcp_qdio_sbal_get(qdio))
                goto out;
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_ABORT_FCP_CMND,
-                                 SBAL_FLAGS0_TYPE_READ,
+                                 SBAL_SFLAGS0_TYPE_READ,
                                  qdio->adapter->pool.scsi_abort);
        if (IS_ERR(req)) {
                req = NULL;
@@ -1012,7 +1012,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_GENERIC,
-                                 SBAL_FLAGS0_TYPE_WRITE_READ, pool);
+                                 SBAL_SFLAGS0_TYPE_WRITE_READ, pool);
 
        if (IS_ERR(req)) {
                ret = PTR_ERR(req);
@@ -1110,7 +1110,7 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_ELS,
-                                 SBAL_FLAGS0_TYPE_WRITE_READ, NULL);
+                                 SBAL_SFLAGS0_TYPE_WRITE_READ, NULL);
 
        if (IS_ERR(req)) {
                ret = PTR_ERR(req);
@@ -1156,7 +1156,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA,
-                                 SBAL_FLAGS0_TYPE_READ,
+                                 SBAL_SFLAGS0_TYPE_READ,
                                  qdio->adapter->pool.erp_req);
 
        if (IS_ERR(req)) {
@@ -1198,7 +1198,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio,
                goto out_unlock;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA,
-                                 SBAL_FLAGS0_TYPE_READ, NULL);
+                                 SBAL_SFLAGS0_TYPE_READ, NULL);
 
        if (IS_ERR(req)) {
                retval = PTR_ERR(req);
@@ -1250,7 +1250,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA,
-                                 SBAL_FLAGS0_TYPE_READ,
+                                 SBAL_SFLAGS0_TYPE_READ,
                                  qdio->adapter->pool.erp_req);
 
        if (IS_ERR(req)) {
@@ -1296,7 +1296,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
                goto out_unlock;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA,
-                                 SBAL_FLAGS0_TYPE_READ, NULL);
+                                 SBAL_SFLAGS0_TYPE_READ, NULL);
 
        if (IS_ERR(req)) {
                retval = PTR_ERR(req);
@@ -1412,7 +1412,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID,
-                                 SBAL_FLAGS0_TYPE_READ,
+                                 SBAL_SFLAGS0_TYPE_READ,
                                  qdio->adapter->pool.erp_req);
 
        if (IS_ERR(req)) {
@@ -1478,7 +1478,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT,
-                                 SBAL_FLAGS0_TYPE_READ,
+                                 SBAL_SFLAGS0_TYPE_READ,
                                  qdio->adapter->pool.erp_req);
 
        if (IS_ERR(req)) {
@@ -1553,7 +1553,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID,
-                                 SBAL_FLAGS0_TYPE_READ,
+                                 SBAL_SFLAGS0_TYPE_READ,
                                  qdio->adapter->pool.erp_req);
 
        if (IS_ERR(req)) {
@@ -1606,7 +1606,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT,
-                                 SBAL_FLAGS0_TYPE_READ,
+                                 SBAL_SFLAGS0_TYPE_READ,
                                  qdio->adapter->pool.erp_req);
 
        if (IS_ERR(req)) {
@@ -1698,7 +1698,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PHYSICAL_PORT,
-                                 SBAL_FLAGS0_TYPE_READ,
+                                 SBAL_SFLAGS0_TYPE_READ,
                                  qdio->adapter->pool.erp_req);
 
        if (IS_ERR(req)) {
@@ -1812,7 +1812,7 @@ int zfcp_fsf_open_lun(struct zfcp_erp_action *erp_action)
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_LUN,
-                                 SBAL_FLAGS0_TYPE_READ,
+                                 SBAL_SFLAGS0_TYPE_READ,
                                  adapter->pool.erp_req);
 
        if (IS_ERR(req)) {
@@ -1901,7 +1901,7 @@ int zfcp_fsf_close_lun(struct zfcp_erp_action *erp_action)
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_LUN,
-                                 SBAL_FLAGS0_TYPE_READ,
+                                 SBAL_SFLAGS0_TYPE_READ,
                                  qdio->adapter->pool.erp_req);
 
        if (IS_ERR(req)) {
@@ -2161,7 +2161,7 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd)
 {
        struct zfcp_fsf_req *req;
        struct fcp_cmnd *fcp_cmnd;
-       unsigned int sbtype = SBAL_FLAGS0_TYPE_READ;
+       u8 sbtype = SBAL_SFLAGS0_TYPE_READ;
        int real_bytes, retval = -EIO, dix_bytes = 0;
        struct scsi_device *sdev = scsi_cmnd->device;
        struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
@@ -2181,7 +2181,7 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd)
        }
 
        if (scsi_cmnd->sc_data_direction == DMA_TO_DEVICE)
-               sbtype = SBAL_FLAGS0_TYPE_WRITE;
+               sbtype = SBAL_SFLAGS0_TYPE_WRITE;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND,
                                  sbtype, adapter->pool.scsi_req);
@@ -2280,7 +2280,7 @@ struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *scmnd,
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND,
-                                 SBAL_FLAGS0_TYPE_WRITE,
+                                 SBAL_SFLAGS0_TYPE_WRITE,
                                  qdio->adapter->pool.scsi_req);
 
        if (IS_ERR(req)) {
@@ -2328,17 +2328,18 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
        struct zfcp_qdio *qdio = adapter->qdio;
        struct zfcp_fsf_req *req = NULL;
        struct fsf_qtcb_bottom_support *bottom;
-       int direction, retval = -EIO, bytes;
+       int retval = -EIO, bytes;
+       u8 direction;
 
        if (!(adapter->adapter_features & FSF_FEATURE_CFDC))
                return ERR_PTR(-EOPNOTSUPP);
 
        switch (fsf_cfdc->command) {
        case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
-               direction = SBAL_FLAGS0_TYPE_WRITE;
+               direction = SBAL_SFLAGS0_TYPE_WRITE;
                break;
        case FSF_QTCB_UPLOAD_CONTROL_FILE:
-               direction = SBAL_FLAGS0_TYPE_READ;
+               direction = SBAL_SFLAGS0_TYPE_READ;
                break;
        default:
                return ERR_PTR(-EINVAL);
@@ -2413,7 +2414,7 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
                fsf_req->qdio_req.sbal_response = sbal_idx;
                zfcp_fsf_req_complete(fsf_req);
 
-               if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY))
+               if (likely(sbale->eflags & SBAL_EFLAGS_LAST_ENTRY))
                        break;
        }
 }
index 98e97d90835b673e770af3911e876537644073b7..d9c40ea73eef4864e6a477d2803b61309e037a1a 100644 (file)
@@ -124,7 +124,7 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
 
        /* set last entry flag in current SBALE of current SBAL */
        sbale = zfcp_qdio_sbale_curr(qdio, q_req);
-       sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
+       sbale->eflags |= SBAL_EFLAGS_LAST_ENTRY;
 
        /* don't exceed last allowed SBAL */
        if (q_req->sbal_last == q_req->sbal_limit)
@@ -132,7 +132,7 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
 
        /* set chaining flag in first SBALE of current SBAL */
        sbale = zfcp_qdio_sbale_req(qdio, q_req);
-       sbale->flags |= SBAL_FLAGS0_MORE_SBALS;
+       sbale->sflags |= SBAL_SFLAGS0_MORE_SBALS;
 
        /* calculate index of next SBAL */
        q_req->sbal_last++;
@@ -147,7 +147,7 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
 
        /* set storage-block type for new SBAL */
        sbale = zfcp_qdio_sbale_curr(qdio, q_req);
-       sbale->flags |= q_req->sbtype;
+       sbale->sflags |= q_req->sbtype;
 
        return sbale;
 }
@@ -177,7 +177,7 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
 
        /* set storage-block type for this request */
        sbale = zfcp_qdio_sbale_req(qdio, q_req);
-       sbale->flags |= q_req->sbtype;
+       sbale->sflags |= q_req->sbtype;
 
        for (; sg; sg = sg_next(sg)) {
                sbale = zfcp_qdio_sbale_next(qdio, q_req);
@@ -384,7 +384,8 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio)
        for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) {
                sbale = &(qdio->res_q[cc]->element[0]);
                sbale->length = 0;
-               sbale->flags = SBAL_FLAGS_LAST_ENTRY;
+               sbale->eflags = SBAL_EFLAGS_LAST_ENTRY;
+               sbale->sflags = 0;
                sbale->addr = NULL;
        }
 
index 2297d8d3e947b0aa16ba1d4c0d68251c6eade33d..54e22ace012b601f5a3cc8dd3cc33505458b8cfd 100644 (file)
@@ -67,7 +67,7 @@ struct zfcp_qdio {
  * @qdio_outb_usage: usage of outbound queue
  */
 struct zfcp_qdio_req {
-       u32     sbtype;
+       u     sbtype;
        u8      sbal_number;
        u8      sbal_first;
        u8      sbal_last;
@@ -116,7 +116,7 @@ zfcp_qdio_sbale_curr(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
  */
 static inline
 void zfcp_qdio_req_init(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
-                       unsigned long req_id, u32 sbtype, void *data, u32 len)
+                       unsigned long req_id, u8 sbtype, void *data, u32 len)
 {
        struct qdio_buffer_element *sbale;
        int count = min(atomic_read(&qdio->req_q_free),
@@ -131,7 +131,8 @@ void zfcp_qdio_req_init(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
 
        sbale = zfcp_qdio_sbale_req(qdio, q_req);
        sbale->addr = (void *) req_id;
-       sbale->flags = SBAL_FLAGS0_COMMAND | sbtype;
+       sbale->eflags = 0;
+       sbale->sflags = SBAL_SFLAGS0_COMMAND | sbtype;
 
        if (unlikely(!data))
                return;
@@ -173,7 +174,7 @@ void zfcp_qdio_set_sbale_last(struct zfcp_qdio *qdio,
        struct qdio_buffer_element *sbale;
 
        sbale = zfcp_qdio_sbale_curr(qdio, q_req);
-       sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
+       sbale->eflags |= SBAL_EFLAGS_LAST_ENTRY;
 }
 
 /**
index 4ff26521d75fe7982797b995319438a7eacd297f..3382475dc22dcf1ac4167aed67da6056539b2131 100644 (file)
@@ -59,7 +59,6 @@
 #ifndef AAC_DRIVER_BRANCH
 #define AAC_DRIVER_BRANCH              ""
 #endif
-#define AAC_DRIVER_BUILD_DATE          __DATE__ " " __TIME__
 #define AAC_DRIVERNAME                 "aacraid"
 
 #ifdef AAC_DRIVER_BUILD
@@ -67,7 +66,7 @@
 #define str(x) _str(x)
 #define AAC_DRIVER_FULL_VERSION        AAC_DRIVER_VERSION "[" str(AAC_DRIVER_BUILD) "]" AAC_DRIVER_BRANCH
 #else
-#define AAC_DRIVER_FULL_VERSION        AAC_DRIVER_VERSION AAC_DRIVER_BRANCH " " AAC_DRIVER_BUILD_DATE
+#define AAC_DRIVER_FULL_VERSION        AAC_DRIVER_VERSION AAC_DRIVER_BRANCH
 #endif
 
 MODULE_AUTHOR("Red Hat Inc and Adaptec");
index 3b7e83d2dab4f1b491cc35523628e6532ce27fdb..d5ff142c93a2c9a0bdac1e768fb9748be657ca09 100644 (file)
@@ -486,7 +486,7 @@ static ssize_t asd_show_update_bios(struct device *dev,
                        flash_error_table[i].reason);
 }
 
-static DEVICE_ATTR(update_bios, S_IRUGO|S_IWUGO,
+static DEVICE_ATTR(update_bios, S_IRUGO|S_IWUSR,
        asd_show_update_bios, asd_store_update_bios);
 
 static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
index c1f72c49196f64e6f3e1498ca88802fb68754c23..6c7e0339dda44d0d7029cd83bd2700950e1c49d2 100644 (file)
@@ -56,6 +56,8 @@ BFA_TRC_FILE(CNA, IOC);
 #define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc))
 #define bfa_ioc_notify_fail(__ioc)              \
                        ((__ioc)->ioc_hwif->ioc_notify_fail(__ioc))
+#define bfa_ioc_sync_start(__ioc)               \
+                       ((__ioc)->ioc_hwif->ioc_sync_start(__ioc))
 #define bfa_ioc_sync_join(__ioc)                \
                        ((__ioc)->ioc_hwif->ioc_sync_join(__ioc))
 #define bfa_ioc_sync_leave(__ioc)               \
@@ -647,7 +649,7 @@ bfa_iocpf_sm_fwcheck(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
        switch (event) {
        case IOCPF_E_SEMLOCKED:
                if (bfa_ioc_firmware_lock(ioc)) {
-                       if (bfa_ioc_sync_complete(ioc)) {
+                       if (bfa_ioc_sync_start(ioc)) {
                                iocpf->retry_count = 0;
                                bfa_ioc_sync_join(ioc);
                                bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
index ec9cf08b0e7f57696e183689b2c6defb6b6808e2..c85182a704fb5d8adaebc6e11b2d0279c8fd0c0e 100644 (file)
@@ -263,6 +263,7 @@ struct bfa_ioc_hwif_s {
                                        bfa_boolean_t msix);
        void            (*ioc_notify_fail)      (struct bfa_ioc_s *ioc);
        void            (*ioc_ownership_reset)  (struct bfa_ioc_s *ioc);
+       bfa_boolean_t   (*ioc_sync_start)       (struct bfa_ioc_s *ioc);
        void            (*ioc_sync_join)        (struct bfa_ioc_s *ioc);
        void            (*ioc_sync_leave)       (struct bfa_ioc_s *ioc);
        void            (*ioc_sync_ack)         (struct bfa_ioc_s *ioc);
index e4a0713185b6747838be59357ceff512ea94c6ef..89ae4c8f95a2bc9506f7cf902b28a331f69b0bfa 100644 (file)
@@ -32,6 +32,7 @@ static void bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc);
 static void bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix);
 static void bfa_ioc_cb_notify_fail(struct bfa_ioc_s *ioc);
 static void bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc);
+static bfa_boolean_t bfa_ioc_cb_sync_start(struct bfa_ioc_s *ioc);
 static void bfa_ioc_cb_sync_join(struct bfa_ioc_s *ioc);
 static void bfa_ioc_cb_sync_leave(struct bfa_ioc_s *ioc);
 static void bfa_ioc_cb_sync_ack(struct bfa_ioc_s *ioc);
@@ -53,6 +54,7 @@ bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc)
        hwif_cb.ioc_isr_mode_set = bfa_ioc_cb_isr_mode_set;
        hwif_cb.ioc_notify_fail = bfa_ioc_cb_notify_fail;
        hwif_cb.ioc_ownership_reset = bfa_ioc_cb_ownership_reset;
+       hwif_cb.ioc_sync_start = bfa_ioc_cb_sync_start;
        hwif_cb.ioc_sync_join = bfa_ioc_cb_sync_join;
        hwif_cb.ioc_sync_leave = bfa_ioc_cb_sync_leave;
        hwif_cb.ioc_sync_ack = bfa_ioc_cb_sync_ack;
@@ -194,6 +196,15 @@ bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix)
 {
 }
 
+/*
+ * Synchronized IOC failure processing routines
+ */
+static bfa_boolean_t
+bfa_ioc_cb_sync_start(struct bfa_ioc_s *ioc)
+{
+       return bfa_ioc_cb_sync_complete(ioc);
+}
+
 /*
  * Cleanup hw semaphore and usecnt registers
  */
index 008d129ddfcd9d9d59a84b410d5a26596e9decf6..93612520f0d2bf3ca1810f3c9a48d93016484098 100644 (file)
@@ -41,6 +41,7 @@ static void bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc);
 static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix);
 static void bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc);
 static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc);
+static bfa_boolean_t bfa_ioc_ct_sync_start(struct bfa_ioc_s *ioc);
 static void bfa_ioc_ct_sync_join(struct bfa_ioc_s *ioc);
 static void bfa_ioc_ct_sync_leave(struct bfa_ioc_s *ioc);
 static void bfa_ioc_ct_sync_ack(struct bfa_ioc_s *ioc);
@@ -62,6 +63,7 @@ bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc)
        hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set;
        hwif_ct.ioc_notify_fail = bfa_ioc_ct_notify_fail;
        hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset;
+       hwif_ct.ioc_sync_start = bfa_ioc_ct_sync_start;
        hwif_ct.ioc_sync_join = bfa_ioc_ct_sync_join;
        hwif_ct.ioc_sync_leave = bfa_ioc_ct_sync_leave;
        hwif_ct.ioc_sync_ack = bfa_ioc_ct_sync_ack;
@@ -351,6 +353,30 @@ bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc)
        writel(1, ioc->ioc_regs.ioc_sem_reg);
 }
 
+static bfa_boolean_t
+bfa_ioc_ct_sync_start(struct bfa_ioc_s *ioc)
+{
+       uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+       uint32_t sync_reqd = bfa_ioc_ct_get_sync_reqd(r32);
+
+       /*
+        * Driver load time.  If the sync required bit for this PCI fn
+        * is set, it is due to an unclean exit by the driver for this
+        * PCI fn in the previous incarnation. Whoever comes here first
+        * should clean it up, no matter which PCI fn.
+        */
+
+       if (sync_reqd & bfa_ioc_ct_sync_pos(ioc)) {
+               writel(0, ioc->ioc_regs.ioc_fail_sync);
+               writel(1, ioc->ioc_regs.ioc_usage_reg);
+               writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate);
+               writel(BFI_IOC_UNINIT, ioc->ioc_regs.alt_ioc_fwstate);
+               return BFA_TRUE;
+       }
+
+       return bfa_ioc_ct_sync_complete(ioc);
+}
+
 /*
  * Synchronized IOC failure processing routines
  */
index cfd59023227b649116b24ea1c5938b9fe5ed6c8c..6bdd25a93db96878be48dd0014cf85e0e479a611 100644 (file)
 #define BD_SPLIT_SIZE                  32768
 
 /* min, max & default values for SQ/RQ/CQ size, configurable via' modparam */
-#define BNX2I_SQ_WQES_MIN              16
-#define BNX2I_570X_SQ_WQES_MAX                 128
-#define BNX2I_5770X_SQ_WQES_MAX        512
-#define BNX2I_570X_SQ_WQES_DEFAULT     128
-#define BNX2I_5770X_SQ_WQES_DEFAULT    256
+#define BNX2I_SQ_WQES_MIN              16
+#define BNX2I_570X_SQ_WQES_MAX         128
+#define BNX2I_5770X_SQ_WQES_MAX                512
+#define BNX2I_570X_SQ_WQES_DEFAULT     128
+#define BNX2I_5770X_SQ_WQES_DEFAULT    128
 
 #define BNX2I_570X_CQ_WQES_MAX                 128
 #define BNX2I_5770X_CQ_WQES_MAX        512
 #define BNX2X_MAX_CQS                  8
 
 #define CNIC_ARM_CQE                   1
+#define CNIC_ARM_CQE_FP                        2
 #define CNIC_DISARM_CQE                        0
 
 #define REG_RD(__hba, offset)                          \
@@ -666,7 +667,9 @@ enum {
  *                      after HBA reset is completed by bnx2i/cnic/bnx2
  *                      modules
  * @state:              tracks offload connection state machine
- * @teardown_mode:      indicates if conn teardown is abortive or orderly
+ * @timestamp:          tracks the start time when the ep begins to connect
+ * @num_active_cmds:    tracks the number of outstanding commands for this ep
+ * @ec_shift:           the amount of shift as part of the event coal calc
  * @qp:                 QP information
  * @ids:                contains chip allocated *context id* & driver assigned
  *                      *iscsi cid*
@@ -685,6 +688,7 @@ struct bnx2i_endpoint {
        u32 state;
        unsigned long timestamp;
        int num_active_cmds;
+       u32 ec_shift;
 
        struct qp_info qp;
        struct ep_handles ids;
index f0b89513faed35704cb6c6ff02d1beb5ffc64407..5c54a2d9b83424d002c81bf7990a9dbe25acb501 100644 (file)
@@ -138,7 +138,6 @@ void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action)
        u16 next_index;
        u32 num_active_cmds;
 
-
        /* Coalesce CQ entries only on 10G devices */
        if (!test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
                return;
@@ -148,16 +147,19 @@ void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action)
         * interrupts and other unwanted results
         */
        cq_db = (struct bnx2i_5771x_cq_db *) ep->qp.cq_pgtbl_virt;
-       if (cq_db->sqn[0] && cq_db->sqn[0] != 0xFFFF)
-               return;
 
-       if (action == CNIC_ARM_CQE) {
+       if (action != CNIC_ARM_CQE_FP)
+               if (cq_db->sqn[0] && cq_db->sqn[0] != 0xFFFF)
+                       return;
+
+       if (action == CNIC_ARM_CQE || action == CNIC_ARM_CQE_FP) {
                num_active_cmds = ep->num_active_cmds;
                if (num_active_cmds <= event_coal_min)
                        next_index = 1;
                else
                        next_index = event_coal_min +
-                               (num_active_cmds - event_coal_min) / event_coal_div;
+                                    ((num_active_cmds - event_coal_min) >>
+                                    ep->ec_shift);
                if (!next_index)
                        next_index = 1;
                cq_index = ep->qp.cqe_exp_seq_sn + next_index - 1;
@@ -1274,6 +1276,7 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
        iscsi_init.dummy_buffer_addr_hi =
                (u32) ((u64) hba->dummy_buf_dma >> 32);
 
+       hba->num_ccell = hba->max_sqes >> 1;
        hba->ctx_ccell_tasks =
                        ((hba->num_ccell & 0xFFFF) | (hba->max_sqes << 16));
        iscsi_init.num_ccells_per_conn = hba->num_ccell;
@@ -1934,7 +1937,6 @@ cqe_out:
                        qp->cq_cons_idx++;
                }
        }
-       bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE);
 }
 
 /**
@@ -1948,22 +1950,23 @@ cqe_out:
 static void bnx2i_fastpath_notification(struct bnx2i_hba *hba,
                                        struct iscsi_kcqe *new_cqe_kcqe)
 {
-       struct bnx2i_conn *conn;
+       struct bnx2i_conn *bnx2i_conn;
        u32 iscsi_cid;
 
        iscsi_cid = new_cqe_kcqe->iscsi_conn_id;
-       conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
+       bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
 
-       if (!conn) {
+       if (!bnx2i_conn) {
                printk(KERN_ALERT "cid #%x not valid\n", iscsi_cid);
                return;
        }
-       if (!conn->ep) {
+       if (!bnx2i_conn->ep) {
                printk(KERN_ALERT "cid #%x - ep not bound\n", iscsi_cid);
                return;
        }
-
-       bnx2i_process_new_cqes(conn);
+       bnx2i_process_new_cqes(bnx2i_conn);
+       bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE_FP);
+       bnx2i_process_new_cqes(bnx2i_conn);
 }
 
 
index 1d24a28197361d737261127cece158fb93a66d65..6adbdc34a9a5727c877b56f0fe58b564413a0370 100644 (file)
@@ -244,7 +244,7 @@ void bnx2i_stop(void *handle)
        wait_event_interruptible_timeout(hba->eh_wait,
                                         (list_empty(&hba->ep_ofld_list) &&
                                         list_empty(&hba->ep_destroy_list)),
-                                        10 * HZ);
+                                        2 * HZ);
        /* Wait for all endpoints to be torn down, Chip will be reset once
         *  control returns to network driver. So it is required to cleanup and
         * release all connection resources before returning from this routine.
index 1809f9ccc4ce0c53d28d93504edbd5305ab1b9a1..041928b23cb0803017306e16327b707216bedb1b 100644 (file)
@@ -379,6 +379,7 @@ static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba)
 {
        struct iscsi_endpoint *ep;
        struct bnx2i_endpoint *bnx2i_ep;
+       u32 ec_div;
 
        ep = iscsi_create_endpoint(sizeof(*bnx2i_ep));
        if (!ep) {
@@ -393,6 +394,11 @@ static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba)
        bnx2i_ep->ep_iscsi_cid = (u16) -1;
        bnx2i_ep->hba = hba;
        bnx2i_ep->hba_age = hba->age;
+
+       ec_div = event_coal_div;
+       while (ec_div >>= 1)
+               bnx2i_ep->ec_shift += 1;
+
        hba->ofld_conns_active++;
        init_waitqueue_head(&bnx2i_ep->ofld_wait);
        return ep;
@@ -858,7 +864,7 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
        mutex_init(&hba->net_dev_lock);
        init_waitqueue_head(&hba->eh_wait);
        if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
-               hba->hba_shutdown_tmo = 20 * HZ;
+               hba->hba_shutdown_tmo = 30 * HZ;
                hba->conn_teardown_tmo = 20 * HZ;
                hba->conn_ctx_destroy_tmo = 6 * HZ;
        } else {        /* 5706/5708/5709 */
@@ -1208,6 +1214,9 @@ static int bnx2i_task_xmit(struct iscsi_task *task)
        struct bnx2i_cmd *cmd = task->dd_data;
        struct iscsi_cmd *hdr = (struct iscsi_cmd *) task->hdr;
 
+       if (bnx2i_conn->ep->num_active_cmds + 1 > hba->max_sqes)
+               return -ENOMEM;
+
        /*
         * If there is no scsi_cmnd this must be a mgmt task
         */
@@ -2156,7 +2165,7 @@ static struct scsi_host_template bnx2i_host_template = {
        .change_queue_depth     = iscsi_change_queue_depth,
        .can_queue              = 1024,
        .max_sectors            = 127,
-       .cmd_per_lun            = 32,
+       .cmd_per_lun            = 24,
        .this_id                = -1,
        .use_clustering         = ENABLE_CLUSTERING,
        .sg_tablesize           = ISCSI_MAX_BDS_PER_CMD,
index cc23bd9480b2580eaa1c4eae3a40fb1d57c11585..155d7b9bdeae656409250182c8fb9e97788c6a60 100644 (file)
@@ -137,6 +137,7 @@ static int fcoe_vport_create(struct fc_vport *, bool disabled);
 static int fcoe_vport_disable(struct fc_vport *, bool disable);
 static void fcoe_set_vport_symbolic_name(struct fc_vport *);
 static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *);
+static int fcoe_validate_vport_create(struct fc_vport *);
 
 static struct libfc_function_template fcoe_libfc_fcn_templ = {
        .frame_send = fcoe_xmit,
@@ -2351,6 +2352,17 @@ static int fcoe_vport_create(struct fc_vport *vport, bool disabled)
        struct fcoe_interface *fcoe = port->priv;
        struct net_device *netdev = fcoe->netdev;
        struct fc_lport *vn_port;
+       int rc;
+       char buf[32];
+
+       rc = fcoe_validate_vport_create(vport);
+       if (rc) {
+               wwn_to_str(vport->port_name, buf, sizeof(buf));
+               printk(KERN_ERR "fcoe: Failed to create vport, "
+                       "WWPN (0x%s) already exists\n",
+                       buf);
+               return rc;
+       }
 
        mutex_lock(&fcoe_config_mutex);
        vn_port = fcoe_if_create(fcoe, &vport->dev, 1);
@@ -2497,3 +2509,49 @@ static void fcoe_set_port_id(struct fc_lport *lport,
        if (fp && fc_frame_payload_op(fp) == ELS_FLOGI)
                fcoe_ctlr_recv_flogi(&fcoe->ctlr, lport, fp);
 }
+
+/**
+ * fcoe_validate_vport_create() - Validate a vport before creating it
+ * @vport: NPIV port to be created
+ *
+ * This routine is meant to add validation for a vport before creating it
+ * via fcoe_vport_create().
+ * Current validations are:
+ *      - WWPN supplied is unique for given lport
+ *
+ *
+*/
+static int fcoe_validate_vport_create(struct fc_vport *vport)
+{
+       struct Scsi_Host *shost = vport_to_shost(vport);
+       struct fc_lport *n_port = shost_priv(shost);
+       struct fc_lport *vn_port;
+       int rc = 0;
+       char buf[32];
+
+       mutex_lock(&n_port->lp_mutex);
+
+       wwn_to_str(vport->port_name, buf, sizeof(buf));
+       /* Check if the wwpn is not same as that of the lport */
+       if (!memcmp(&n_port->wwpn, &vport->port_name, sizeof(u64))) {
+               FCOE_DBG("vport WWPN 0x%s is same as that of the "
+                       "base port WWPN\n", buf);
+               rc = -EINVAL;
+               goto out;
+       }
+
+       /* Check if there is any existing vport with same wwpn */
+       list_for_each_entry(vn_port, &n_port->vports, list) {
+               if (!memcmp(&vn_port->wwpn, &vport->port_name, sizeof(u64))) {
+                       FCOE_DBG("vport with given WWPN 0x%s already "
+                       "exists\n", buf);
+                       rc = -EINVAL;
+                       break;
+               }
+       }
+
+out:
+       mutex_unlock(&n_port->lp_mutex);
+
+       return rc;
+}
index 408a6fd78fb43b77834246044d065da1b4cdde65..c4a93993c0cfd5f943be8fb36fad466941523356 100644 (file)
@@ -99,4 +99,14 @@ static inline struct net_device *fcoe_netdev(const struct fc_lport *lport)
                        ((struct fcoe_port *)lport_priv(lport))->priv)->netdev;
 }
 
+static inline void wwn_to_str(u64 wwn, char *buf, int len)
+{
+       u8 wwpn[8];
+
+       u64_to_wwn(wwn, wwpn);
+       snprintf(buf, len, "%02x%02x%02x%02x%02x%02x%02x%02x",
+               wwpn[0], wwpn[1], wwpn[2], wwpn[3],
+               wwpn[4], wwpn[5], wwpn[6], wwpn[7]);
+}
+
 #endif /* _FCOE_H_ */
index 229e4af5508a272b4f9a0c43b3a8d3929361f2f0..c74c4b8e71ef03c0c8a8111efe1152bb5586e26a 100644 (file)
@@ -1173,7 +1173,9 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
        struct fc_lport *lport = fip->lp;
        struct fc_lport *vn_port = NULL;
        u32 desc_mask;
-       int is_vn_port = 0;
+       int num_vlink_desc;
+       int reset_phys_port = 0;
+       struct fip_vn_desc **vlink_desc_arr = NULL;
 
        LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n");
 
@@ -1183,70 +1185,73 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
        /*
         * mask of required descriptors.  Validating each one clears its bit.
         */
-       desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) | BIT(FIP_DT_VN_ID);
+       desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME);
 
        rlen = ntohs(fh->fip_dl_len) * FIP_BPW;
        desc = (struct fip_desc *)(fh + 1);
+
+       /*
+        * Actually need to subtract 'sizeof(*mp) - sizeof(*wp)' from 'rlen'
+        * before determining max Vx_Port descriptor but a buggy FCF could have
+        * omited either or both MAC Address and Name Identifier descriptors
+        */
+       num_vlink_desc = rlen / sizeof(*vp);
+       if (num_vlink_desc)
+               vlink_desc_arr = kmalloc(sizeof(vp) * num_vlink_desc,
+                                        GFP_ATOMIC);
+       if (!vlink_desc_arr)
+               return;
+       num_vlink_desc = 0;
+
        while (rlen >= sizeof(*desc)) {
                dlen = desc->fip_dlen * FIP_BPW;
                if (dlen > rlen)
-                       return;
+                       goto err;
                /* Drop CVL if there are duplicate critical descriptors */
                if ((desc->fip_dtype < 32) &&
+                   (desc->fip_dtype != FIP_DT_VN_ID) &&
                    !(desc_mask & 1U << desc->fip_dtype)) {
                        LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
                                        "Descriptors in FIP CVL\n");
-                       return;
+                       goto err;
                }
                switch (desc->fip_dtype) {
                case FIP_DT_MAC:
                        mp = (struct fip_mac_desc *)desc;
                        if (dlen < sizeof(*mp))
-                               return;
+                               goto err;
                        if (compare_ether_addr(mp->fd_mac, fcf->fcf_mac))
-                               return;
+                               goto err;
                        desc_mask &= ~BIT(FIP_DT_MAC);
                        break;
                case FIP_DT_NAME:
                        wp = (struct fip_wwn_desc *)desc;
                        if (dlen < sizeof(*wp))
-                               return;
+                               goto err;
                        if (get_unaligned_be64(&wp->fd_wwn) != fcf->switch_name)
-                               return;
+                               goto err;
                        desc_mask &= ~BIT(FIP_DT_NAME);
                        break;
                case FIP_DT_VN_ID:
                        vp = (struct fip_vn_desc *)desc;
                        if (dlen < sizeof(*vp))
-                               return;
-                       if (compare_ether_addr(vp->fd_mac,
-                                              fip->get_src_addr(lport)) == 0 &&
-                           get_unaligned_be64(&vp->fd_wwpn) == lport->wwpn &&
-                           ntoh24(vp->fd_fc_id) == lport->port_id) {
-                               desc_mask &= ~BIT(FIP_DT_VN_ID);
-                               break;
+                               goto err;
+                       vlink_desc_arr[num_vlink_desc++] = vp;
+                       vn_port = fc_vport_id_lookup(lport,
+                                                     ntoh24(vp->fd_fc_id));
+                       if (vn_port && (vn_port == lport)) {
+                               mutex_lock(&fip->ctlr_mutex);
+                               per_cpu_ptr(lport->dev_stats,
+                                           get_cpu())->VLinkFailureCount++;
+                               put_cpu();
+                               fcoe_ctlr_reset(fip);
+                               mutex_unlock(&fip->ctlr_mutex);
                        }
-                       /* check if clr_vlink is for NPIV port */
-                       mutex_lock(&lport->lp_mutex);
-                       list_for_each_entry(vn_port, &lport->vports, list) {
-                               if (compare_ether_addr(vp->fd_mac,
-                                   fip->get_src_addr(vn_port)) == 0 &&
-                                   (get_unaligned_be64(&vp->fd_wwpn)
-                                                       == vn_port->wwpn) &&
-                                   (ntoh24(vp->fd_fc_id) ==
-                                           fc_host_port_id(vn_port->host))) {
-                                       desc_mask &= ~BIT(FIP_DT_VN_ID);
-                                       is_vn_port = 1;
-                                       break;
-                               }
-                       }
-                       mutex_unlock(&lport->lp_mutex);
-
                        break;
                default:
                        /* standard says ignore unknown descriptors >= 128 */
                        if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
-                               return;
+                               goto err;
                        break;
                }
                desc = (struct fip_desc *)((char *)desc + dlen);
@@ -1256,26 +1261,68 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
        /*
         * reset only if all required descriptors were present and valid.
         */
-       if (desc_mask) {
+       if (desc_mask)
                LIBFCOE_FIP_DBG(fip, "missing descriptors mask %x\n",
                                desc_mask);
+       else if (!num_vlink_desc) {
+               LIBFCOE_FIP_DBG(fip, "CVL: no Vx_Port descriptor found\n");
+               /*
+                * No Vx_Port description. Clear all NPIV ports,
+                * followed by physical port
+                */
+               mutex_lock(&lport->lp_mutex);
+               list_for_each_entry(vn_port, &lport->vports, list)
+                       fc_lport_reset(vn_port);
+               mutex_unlock(&lport->lp_mutex);
+
+               mutex_lock(&fip->ctlr_mutex);
+               per_cpu_ptr(lport->dev_stats,
+                           get_cpu())->VLinkFailureCount++;
+               put_cpu();
+               fcoe_ctlr_reset(fip);
+               mutex_unlock(&fip->ctlr_mutex);
+
+               fc_lport_reset(fip->lp);
+               fcoe_ctlr_solicit(fip, NULL);
        } else {
-               LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n");
+               int i;
 
-               if (is_vn_port)
-                       fc_lport_reset(vn_port);
-               else {
-                       mutex_lock(&fip->ctlr_mutex);
-                       per_cpu_ptr(lport->dev_stats,
-                                   get_cpu())->VLinkFailureCount++;
-                       put_cpu();
-                       fcoe_ctlr_reset(fip);
-                       mutex_unlock(&fip->ctlr_mutex);
+               LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n");
+               for (i = 0; i < num_vlink_desc; i++) {
+                       vp = vlink_desc_arr[i];
+                       vn_port = fc_vport_id_lookup(lport,
+                                                    ntoh24(vp->fd_fc_id));
+                       if (!vn_port)
+                               continue;
+
+                       /*
+                        * 'port_id' is already validated, check MAC address and
+                        * wwpn
+                        */
+                       if (compare_ether_addr(fip->get_src_addr(vn_port),
+                                               vp->fd_mac) != 0 ||
+                               get_unaligned_be64(&vp->fd_wwpn) !=
+                                                       vn_port->wwpn)
+                               continue;
+
+                       if (vn_port == lport)
+                               /*
+                                * Physical port, defer processing till all
+                                * listed NPIV ports are cleared
+                                */
+                               reset_phys_port = 1;
+                       else    /* NPIV port */
+                               fc_lport_reset(vn_port);
+               }
 
+               if (reset_phys_port) {
                        fc_lport_reset(fip->lp);
                        fcoe_ctlr_solicit(fip, NULL);
                }
        }
+
+err:
+       kfree(vlink_desc_arr);
 }
 
 /**
index f81f77c8569e58e156bc4b011e2aaed0f7cebf05..41068e8748e74201059552acb8609c8ab7712c0b 100644 (file)
@@ -544,16 +544,6 @@ static int fcoe_transport_create(const char *buffer, struct kernel_param *kp)
        struct fcoe_transport *ft = NULL;
        enum fip_state fip_mode = (enum fip_state)(long)kp->arg;
 
-#ifdef CONFIG_LIBFCOE_MODULE
-       /*
-        * Make sure the module has been initialized, and is not about to be
-        * removed.  Module parameter sysfs files are writable before the
-        * module_init function is called and after module_exit.
-        */
-       if (THIS_MODULE->state != MODULE_STATE_LIVE)
-               goto out_nodev;
-#endif
-
        mutex_lock(&ft_mutex);
 
        netdev = fcoe_if_to_netdev(buffer);
@@ -618,16 +608,6 @@ static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp)
        struct net_device *netdev = NULL;
        struct fcoe_transport *ft = NULL;
 
-#ifdef CONFIG_LIBFCOE_MODULE
-       /*
-        * Make sure the module has been initialized, and is not about to be
-        * removed.  Module parameter sysfs files are writable before the
-        * module_init function is called and after module_exit.
-        */
-       if (THIS_MODULE->state != MODULE_STATE_LIVE)
-               goto out_nodev;
-#endif
-
        mutex_lock(&ft_mutex);
 
        netdev = fcoe_if_to_netdev(buffer);
@@ -672,16 +652,6 @@ static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp)
        struct net_device *netdev = NULL;
        struct fcoe_transport *ft = NULL;
 
-#ifdef CONFIG_LIBFCOE_MODULE
-       /*
-        * Make sure the module has been initialized, and is not about to be
-        * removed.  Module parameter sysfs files are writable before the
-        * module_init function is called and after module_exit.
-        */
-       if (THIS_MODULE->state != MODULE_STATE_LIVE)
-               goto out_nodev;
-#endif
-
        mutex_lock(&ft_mutex);
 
        netdev = fcoe_if_to_netdev(buffer);
@@ -720,16 +690,6 @@ static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp)
        struct net_device *netdev = NULL;
        struct fcoe_transport *ft = NULL;
 
-#ifdef CONFIG_LIBFCOE_MODULE
-       /*
-        * Make sure the module has been initialized, and is not about to be
-        * removed.  Module parameter sysfs files are writable before the
-        * module_init function is called and after module_exit.
-        */
-       if (THIS_MODULE->state != MODULE_STATE_LIVE)
-               goto out_nodev;
-#endif
-
        mutex_lock(&ft_mutex);
 
        netdev = fcoe_if_to_netdev(buffer);
index 92109b126391ded6206c5d80dabd457ec03891e3..112f1bec7756d4ac2da9ed16790a746d8104a110 100644 (file)
@@ -2227,7 +2227,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start,
        bp = buf;
        *bp = '\0';
        if (hd->proc & PR_VERSION) {
-               sprintf(tbuf, "\nVersion %s - %s. Compiled %s %s", IN2000_VERSION, IN2000_DATE, __DATE__, __TIME__);
+               sprintf(tbuf, "\nVersion %s - %s.", IN2000_VERSION, IN2000_DATE);
                strcat(bp, tbuf);
        }
        if (hd->proc & PR_INFO) {
index 12868ca461108547d2eafdbc1e9c5e1d95219501..888086c4e709497e6d8c7ae9e02dcf06b5bbca18 100644 (file)
@@ -5149,21 +5149,21 @@ static irqreturn_t ipr_isr(int irq, void *devp)
 
                if (ipr_cmd != NULL) {
                        /* Clear the PCI interrupt */
+                       num_hrrq = 0;
                        do {
                                writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32);
                                int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32);
                        } while (int_reg & IPR_PCII_HRRQ_UPDATED &&
                                        num_hrrq++ < IPR_MAX_HRRQ_RETRIES);
 
-                       if (int_reg & IPR_PCII_HRRQ_UPDATED) {
-                               ipr_isr_eh(ioa_cfg, "Error clearing HRRQ");
-                               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
-                               return IRQ_HANDLED;
-                       }
-
                } else if (rc == IRQ_NONE && irq_none == 0) {
                        int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32);
                        irq_none++;
+               } else if (num_hrrq == IPR_MAX_HRRQ_RETRIES &&
+                          int_reg & IPR_PCII_HRRQ_UPDATED) {
+                       ipr_isr_eh(ioa_cfg, "Error clearing HRRQ");
+                       spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+                       return IRQ_HANDLED;
                } else
                        break;
        }
index 911b2736cafae204379b8db7f18767b788d79bc3..b9cb8140b398220c384820029dc5cac3efdae393 100644 (file)
@@ -205,6 +205,7 @@ static void fc_disc_recv_req(struct fc_lport *lport, struct fc_frame *fp)
        default:
                FC_DISC_DBG(disc, "Received an unsupported request, "
                            "the opcode is (%x)\n", op);
+               fc_frame_free(fp);
                break;
        }
 }
index 77035a746f6027e5f232140349e7339c5901f2e9..3b8a6451ea283ec5093307a774f32d92e7d90878 100644 (file)
@@ -1434,6 +1434,7 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
            (f_ctl & (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) ==
            (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) {
                spin_lock_bh(&ep->ex_lock);
+               resp = ep->resp;
                rc = fc_exch_done_locked(ep);
                WARN_ON(fc_seq_exch(sp) != ep);
                spin_unlock_bh(&ep->ex_lock);
@@ -1978,6 +1979,7 @@ static struct fc_seq *fc_exch_seq_send(struct fc_lport *lport,
        spin_unlock_bh(&ep->ex_lock);
        return sp;
 err:
+       fc_fcp_ddp_done(fr_fsp(fp));
        rc = fc_exch_done_locked(ep);
        spin_unlock_bh(&ep->ex_lock);
        if (!rc)
index 2a3a4720a771c26c4f67343f8b720ac005e1100f..9cd2149519ace23d9dbbff8fa7d28b1c5e2acdf5 100644 (file)
@@ -312,7 +312,7 @@ void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid)
  *                    DDP related resources for a fcp_pkt
  * @fsp: The FCP packet that DDP had been used on
  */
-static void fc_fcp_ddp_done(struct fc_fcp_pkt *fsp)
+void fc_fcp_ddp_done(struct fc_fcp_pkt *fsp)
 {
        struct fc_lport *lport;
 
@@ -681,8 +681,7 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
                error = lport->tt.seq_send(lport, seq, fp);
                if (error) {
                        WARN_ON(1);             /* send error should be rare */
-                       fc_fcp_retry_cmd(fsp);
-                       return 0;
+                       return error;
                }
                fp = NULL;
        }
@@ -1673,7 +1672,8 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset)
                       FC_FCTL_REQ, 0);
 
        rec_tov = get_fsp_rec_tov(fsp);
-       seq = lport->tt.exch_seq_send(lport, fp, fc_fcp_srr_resp, NULL,
+       seq = lport->tt.exch_seq_send(lport, fp, fc_fcp_srr_resp,
+                                     fc_fcp_pkt_destroy,
                                      fsp, jiffies_to_msecs(rec_tov));
        if (!seq)
                goto retry;
@@ -1720,7 +1720,6 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
                return;
        }
 
-       fsp->recov_seq = NULL;
        switch (fc_frame_payload_op(fp)) {
        case ELS_LS_ACC:
                fsp->recov_retry = 0;
@@ -1732,10 +1731,9 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
                break;
        }
        fc_fcp_unlock_pkt(fsp);
-       fsp->lp->tt.exch_done(seq);
 out:
+       fsp->lp->tt.exch_done(seq);
        fc_frame_free(fp);
-       fc_fcp_pkt_release(fsp);        /* drop hold for outstanding SRR */
 }
 
 /**
@@ -1747,8 +1745,6 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
 {
        if (fc_fcp_lock_pkt(fsp))
                goto out;
-       fsp->lp->tt.exch_done(fsp->recov_seq);
-       fsp->recov_seq = NULL;
        switch (PTR_ERR(fp)) {
        case -FC_EX_TIMEOUT:
                if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
@@ -1764,7 +1760,7 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
        }
        fc_fcp_unlock_pkt(fsp);
 out:
-       fc_fcp_pkt_release(fsp);        /* drop hold for outstanding SRR */
+       fsp->lp->tt.exch_done(fsp->recov_seq);
 }
 
 /**
index fedc819d70c0259db4dceb8b04e797dd4c5fbd0b..c7d071289af5ac34320759d8ba0aa415fc644b64 100644 (file)
@@ -108,6 +108,7 @@ extern struct fc4_prov fc_rport_fcp_init;   /* FCP initiator provider */
  * Set up direct-data placement for this I/O request
  */
 void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid);
+void fc_fcp_ddp_done(struct fc_fcp_pkt *fsp);
 
 /*
  * Module setup functions
index 31fc21f4d831781c2844ab584abbeab576709bb1..db9238f2ecb8b7596dda9c2d4132000af0910bd7 100644 (file)
@@ -99,19 +99,29 @@ static void sas_ata_task_done(struct sas_task *task)
        struct sas_ha_struct *sas_ha;
        enum ata_completion_errors ac;
        unsigned long flags;
+       struct ata_link *link;
 
        if (!qc)
                goto qc_already_gone;
 
        dev = qc->ap->private_data;
        sas_ha = dev->port->ha;
+       link = &dev->sata_dev.ap->link;
 
        spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
        if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD ||
            ((stat->stat == SAM_STAT_CHECK_CONDITION &&
              dev->sata_dev.command_set == ATAPI_COMMAND_SET))) {
                ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf);
-               qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command);
+
+               if (!link->sactive) {
+                       qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command);
+               } else {
+                       link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.tf.command);
+                       if (unlikely(link->eh_info.err_mask))
+                               qc->flags |= ATA_QCFLAG_FAILED;
+               }
+
                dev->sata_dev.sstatus = resp->sstatus;
                dev->sata_dev.serror = resp->serror;
                dev->sata_dev.scontrol = resp->scontrol;
@@ -121,7 +131,13 @@ static void sas_ata_task_done(struct sas_task *task)
                        SAS_DPRINTK("%s: SAS error %x\n", __func__,
                                    stat->stat);
                        /* We saw a SAS error. Send a vague error. */
-                       qc->err_mask = ac;
+                       if (!link->sactive) {
+                               qc->err_mask = ac;
+                       } else {
+                               link->eh_info.err_mask |= AC_ERR_DEV;
+                               qc->flags |= ATA_QCFLAG_FAILED;
+                       }
+
                        dev->sata_dev.tf.feature = 0x04; /* status err */
                        dev->sata_dev.tf.command = ATA_ERR;
                }
@@ -279,6 +295,44 @@ static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class,
        return ret;
 }
 
+static int sas_ata_soft_reset(struct ata_link *link, unsigned int *class,
+                              unsigned long deadline)
+{
+       struct ata_port *ap = link->ap;
+       struct domain_device *dev = ap->private_data;
+       struct sas_internal *i =
+               to_sas_internal(dev->port->ha->core.shost->transportt);
+       int res = TMF_RESP_FUNC_FAILED;
+       int ret = 0;
+
+       if (i->dft->lldd_ata_soft_reset)
+               res = i->dft->lldd_ata_soft_reset(dev);
+
+       if (res != TMF_RESP_FUNC_COMPLETE) {
+               SAS_DPRINTK("%s: Unable to soft reset\n", __func__);
+               ret = -EAGAIN;
+       }
+
+       switch (dev->sata_dev.command_set) {
+       case ATA_COMMAND_SET:
+               SAS_DPRINTK("%s: Found ATA device.\n", __func__);
+               *class = ATA_DEV_ATA;
+               break;
+       case ATAPI_COMMAND_SET:
+               SAS_DPRINTK("%s: Found ATAPI device.\n", __func__);
+               *class = ATA_DEV_ATAPI;
+               break;
+       default:
+               SAS_DPRINTK("%s: Unknown SATA command set: %d.\n",
+                           __func__, dev->sata_dev.command_set);
+               *class = ATA_DEV_UNKNOWN;
+               break;
+       }
+
+       ap->cbl = ATA_CBL_SATA;
+       return ret;
+}
+
 static void sas_ata_post_internal(struct ata_queued_cmd *qc)
 {
        if (qc->flags & ATA_QCFLAG_FAILED)
@@ -309,7 +363,7 @@ static void sas_ata_post_internal(struct ata_queued_cmd *qc)
 
 static struct ata_port_operations sas_sata_ops = {
        .prereset               = ata_std_prereset,
-       .softreset              = NULL,
+       .softreset              = sas_ata_soft_reset,
        .hardreset              = sas_ata_hard_reset,
        .postreset              = ata_std_postreset,
        .error_handler          = ata_std_error_handler,
index 8b538bd1ff2bbcc3e5967b8369d03068856fa1c8..14e21b5fb8ba77b972b6052abb2adc59052d2b1e 100644 (file)
@@ -57,7 +57,7 @@ int  sas_init_queue(struct sas_ha_struct *sas_ha);
 int  sas_init_events(struct sas_ha_struct *sas_ha);
 void sas_shutdown_queue(struct sas_ha_struct *sas_ha);
 
-void sas_deform_port(struct asd_sas_phy *phy);
+void sas_deform_port(struct asd_sas_phy *phy, int gone);
 
 void sas_porte_bytes_dmaed(struct work_struct *work);
 void sas_porte_broadcast_rcvd(struct work_struct *work);
index b459c4b635b1b73dfe5e1ed5304f6bad5a6ee588..e0f5018e90718db91a4c20d30d08734775e40e43 100644 (file)
@@ -39,7 +39,7 @@ static void sas_phye_loss_of_signal(struct work_struct *work)
        sas_begin_event(PHYE_LOSS_OF_SIGNAL, &phy->ha->event_lock,
                        &phy->phy_events_pending);
        phy->error = 0;
-       sas_deform_port(phy);
+       sas_deform_port(phy, 1);
 }
 
 static void sas_phye_oob_done(struct work_struct *work)
@@ -66,7 +66,7 @@ static void sas_phye_oob_error(struct work_struct *work)
        sas_begin_event(PHYE_OOB_ERROR, &phy->ha->event_lock,
                        &phy->phy_events_pending);
 
-       sas_deform_port(phy);
+       sas_deform_port(phy, 1);
 
        if (!port && phy->enabled && i->dft->lldd_control_phy) {
                phy->error++;
index 5257fdfe699ae6d1c853d0de0a68f2f51986e054..42fd1f25b664a382e5848865041838055796f256 100644 (file)
@@ -57,7 +57,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
 
        if (port) {
                if (!phy_is_wideport_member(port, phy))
-                       sas_deform_port(phy);
+                       sas_deform_port(phy, 0);
                else {
                        SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
                                    __func__, phy->id, phy->port->id,
@@ -153,28 +153,31 @@ static void sas_form_port(struct asd_sas_phy *phy)
  * This is called when the physical link to the other phy has been
  * lost (on this phy), in Event thread context. We cannot delay here.
  */
-void sas_deform_port(struct asd_sas_phy *phy)
+void sas_deform_port(struct asd_sas_phy *phy, int gone)
 {
        struct sas_ha_struct *sas_ha = phy->ha;
        struct asd_sas_port *port = phy->port;
        struct sas_internal *si =
                to_sas_internal(sas_ha->core.shost->transportt);
+       struct domain_device *dev;
        unsigned long flags;
 
        if (!port)
                return;           /* done by a phy event */
 
-       if (port->port_dev)
-               port->port_dev->pathways--;
+       dev = port->port_dev;
+       if (dev)
+               dev->pathways--;
 
        if (port->num_phys == 1) {
+               if (dev && gone)
+                       dev->gone = 1;
                sas_unregister_domain_devices(port);
                sas_port_delete(port->port);
                port->port = NULL;
        } else
                sas_port_delete_phy(port->port, phy->phy);
 
-
        if (si->dft->lldd_port_deformed)
                si->dft->lldd_port_deformed(phy);
 
@@ -244,7 +247,7 @@ void sas_porte_link_reset_err(struct work_struct *work)
        sas_begin_event(PORTE_LINK_RESET_ERR, &phy->ha->event_lock,
                        &phy->port_events_pending);
 
-       sas_deform_port(phy);
+       sas_deform_port(phy, 1);
 }
 
 void sas_porte_timer_event(struct work_struct *work)
@@ -256,7 +259,7 @@ void sas_porte_timer_event(struct work_struct *work)
        sas_begin_event(PORTE_TIMER_EVENT, &phy->ha->event_lock,
                        &phy->port_events_pending);
 
-       sas_deform_port(phy);
+       sas_deform_port(phy, 1);
 }
 
 void sas_porte_hard_reset(struct work_struct *work)
@@ -268,7 +271,7 @@ void sas_porte_hard_reset(struct work_struct *work)
        sas_begin_event(PORTE_HARD_RESET, &phy->ha->event_lock,
                        &phy->port_events_pending);
 
-       sas_deform_port(phy);
+       sas_deform_port(phy, 1);
 }
 
 /* ---------- SAS port registration ---------- */
@@ -306,6 +309,6 @@ void sas_unregister_ports(struct sas_ha_struct *sas_ha)
 
        for (i = 0; i < sas_ha->num_phys; i++)
                if (sas_ha->sas_phy[i]->port)
-                       sas_deform_port(sas_ha->sas_phy[i]);
+                       sas_deform_port(sas_ha->sas_phy[i], 0);
 
 }
index f6e189f40917fabcb0e4a72c960c937754299fc6..eeba76cdf7746c518c49f680d3d2ab9f3a9b863a 100644 (file)
@@ -207,6 +207,13 @@ static int sas_queuecommand_lck(struct scsi_cmnd *cmd,
                struct sas_ha_struct *sas_ha = dev->port->ha;
                struct sas_task *task;
 
+               /* If the device fell off, no sense in issuing commands */
+               if (dev->gone) {
+                       cmd->result = DID_BAD_TARGET << 16;
+                       scsi_done(cmd);
+                       goto out;
+               }
+
                if (dev_is_sata(dev)) {
                        unsigned long flags;
 
@@ -216,13 +223,6 @@ static int sas_queuecommand_lck(struct scsi_cmnd *cmd,
                        goto out;
                }
 
-               /* If the device fell off, no sense in issuing commands */
-               if (dev->gone) {
-                       cmd->result = DID_BAD_TARGET << 16;
-                       scsi_done(cmd);
-                       goto out;
-               }
-
                res = -ENOMEM;
                task = sas_create_task(cmd, dev, GFP_ATOMIC);
                if (!task)
index 02d53d89534f3c9681e88611f6ff7f6b4da533e3..8ec2c86a49d42fa3661b71875bcbe1f20c9ed37f 100644 (file)
@@ -41,6 +41,7 @@ struct lpfc_sli2_slim;
                downloads using bsg */
 #define LPFC_DEFAULT_PROT_SG_SEG_CNT 4096 /* sg protection elements count */
 #define LPFC_MAX_SG_SEG_CNT    4096    /* sg element count per scsi cmnd */
+#define LPFC_MAX_SGE_SIZE       0x80000000 /* Maximum data allowed in a SGE */
 #define LPFC_MAX_PROT_SG_SEG_CNT 4096  /* prot sg element count per scsi cmd*/
 #define LPFC_IOCB_LIST_CNT     2250    /* list of IOCBs for fast-path usage. */
 #define LPFC_Q_RAMP_UP_INTERVAL 120     /* lun q_depth ramp up interval */
@@ -486,6 +487,42 @@ struct unsol_rcv_ct_ctx {
                                     (1 << LPFC_USER_LINK_SPEED_AUTO))
 #define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8, 10, 16"
 
+enum nemb_type {
+       nemb_mse = 1,
+       nemb_hbd
+};
+
+enum mbox_type {
+       mbox_rd = 1,
+       mbox_wr
+};
+
+enum dma_type {
+       dma_mbox = 1,
+       dma_ebuf
+};
+
+enum sta_type {
+       sta_pre_addr = 1,
+       sta_pos_addr
+};
+
+struct lpfc_mbox_ext_buf_ctx {
+       uint32_t state;
+#define LPFC_BSG_MBOX_IDLE             0
+#define LPFC_BSG_MBOX_HOST              1
+#define LPFC_BSG_MBOX_PORT             2
+#define LPFC_BSG_MBOX_DONE             3
+#define LPFC_BSG_MBOX_ABTS             4
+       enum nemb_type nembType;
+       enum mbox_type mboxType;
+       uint32_t numBuf;
+       uint32_t mbxTag;
+       uint32_t seqNum;
+       struct lpfc_dmabuf *mbx_dmabuf;
+       struct list_head ext_dmabuf_list;
+};
+
 struct lpfc_hba {
        /* SCSI interface function jump table entries */
        int (*lpfc_new_scsi_buf)
@@ -589,6 +626,7 @@ struct lpfc_hba {
 
        MAILBOX_t *mbox;
        uint32_t *mbox_ext;
+       struct lpfc_mbox_ext_buf_ctx mbox_ext_buf_ctx;
        uint32_t ha_copy;
        struct _PCB *pcb;
        struct _IOCB *IOCBs;
@@ -659,6 +697,7 @@ struct lpfc_hba {
        uint32_t cfg_hostmem_hgp;
        uint32_t cfg_log_verbose;
        uint32_t cfg_aer_support;
+       uint32_t cfg_sriov_nr_virtfn;
        uint32_t cfg_iocb_cnt;
        uint32_t cfg_suppress_link_up;
 #define LPFC_INITIALIZE_LINK              0    /* do normal init_link mbox */
@@ -706,7 +745,6 @@ struct lpfc_hba {
        uint32_t          *hbq_get;     /* Host mem address of HBQ get ptrs */
 
        int brd_no;                     /* FC board number */
-
        char SerialNumber[32];          /* adapter Serial Number */
        char OptionROMVersion[32];      /* adapter BIOS / Fcode version */
        char ModelDesc[256];            /* Model Description */
@@ -778,6 +816,9 @@ struct lpfc_hba {
        uint16_t vpi_base;
        uint16_t vfi_base;
        unsigned long *vpi_bmask;       /* vpi allocation table */
+       uint16_t *vpi_ids;
+       uint16_t vpi_count;
+       struct list_head lpfc_vpi_blk_list;
 
        /* Data structure used by fabric iocb scheduler */
        struct list_head fabric_iocb_list;
index 8dcbf8fff673d6412f13420e8482eba841dee9e8..135a53baa735177513f6dfcc7f7fd85afb9d8ea1 100644 (file)
@@ -754,6 +754,73 @@ lpfc_issue_reset(struct device *dev, struct device_attribute *attr,
                return status;
 }
 
+/**
+ * lpfc_sli4_pdev_reg_request - Request physical dev to perform a register acc
+ * @phba: lpfc_hba pointer.
+ *
+ * Description:
+ * Request SLI4 interface type-2 device to perform a physical register set
+ * access.
+ *
+ * Returns:
+ * zero for success
+ **/
+static ssize_t
+lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode)
+{
+       struct completion online_compl;
+       uint32_t reg_val;
+       int status = 0;
+       int rc;
+
+       if (!phba->cfg_enable_hba_reset)
+               return -EIO;
+
+       if ((phba->sli_rev < LPFC_SLI_REV4) ||
+           (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+            LPFC_SLI_INTF_IF_TYPE_2))
+               return -EPERM;
+
+       status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
+
+       if (status != 0)
+               return status;
+
+       /* wait for the device to be quiesced before firmware reset */
+       msleep(100);
+
+       reg_val = readl(phba->sli4_hba.conf_regs_memmap_p +
+                       LPFC_CTL_PDEV_CTL_OFFSET);
+
+       if (opcode == LPFC_FW_DUMP)
+               reg_val |= LPFC_FW_DUMP_REQUEST;
+       else if (opcode == LPFC_FW_RESET)
+               reg_val |= LPFC_CTL_PDEV_CTL_FRST;
+       else if (opcode == LPFC_DV_RESET)
+               reg_val |= LPFC_CTL_PDEV_CTL_DRST;
+
+       writel(reg_val, phba->sli4_hba.conf_regs_memmap_p +
+              LPFC_CTL_PDEV_CTL_OFFSET);
+       /* flush */
+       readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET);
+
+       /* delay driver action following IF_TYPE_2 reset */
+       msleep(100);
+
+       init_completion(&online_compl);
+       rc = lpfc_workq_post_event(phba, &status, &online_compl,
+                                  LPFC_EVT_ONLINE);
+       if (rc == 0)
+               return -ENOMEM;
+
+       wait_for_completion(&online_compl);
+
+       if (status != 0)
+               return -EIO;
+
+       return 0;
+}
+
 /**
  * lpfc_nport_evt_cnt_show - Return the number of nport events
  * @dev: class device that is converted into a Scsi_host.
@@ -848,6 +915,12 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr,
                        return -EINVAL;
                else
                        status = lpfc_do_offline(phba, LPFC_EVT_KILL);
+       else if (strncmp(buf, "dump", sizeof("dump") - 1) == 0)
+               status = lpfc_sli4_pdev_reg_request(phba, LPFC_FW_DUMP);
+       else if (strncmp(buf, "fw_reset", sizeof("fw_reset") - 1) == 0)
+               status = lpfc_sli4_pdev_reg_request(phba, LPFC_FW_RESET);
+       else if (strncmp(buf, "dv_reset", sizeof("dv_reset") - 1) == 0)
+               status = lpfc_sli4_pdev_reg_request(phba, LPFC_DV_RESET);
        else
                return -EINVAL;
 
@@ -1321,6 +1394,102 @@ lpfc_dss_show(struct device *dev, struct device_attribute *attr,
                                "" : "Not ");
 }
 
+/**
+ * lpfc_sriov_hw_max_virtfn_show - Return maximum number of virtual functions
+ * @dev: class converted to a Scsi_host structure.
+ * @attr: device attribute, not used.
+ * @buf: on return contains the formatted support level.
+ *
+ * Description:
+ * Returns the maximum number of virtual functions a physical function can
+ * support, 0 will be returned if called on virtual function.
+ *
+ * Returns: size of formatted string.
+ **/
+static ssize_t
+lpfc_sriov_hw_max_virtfn_show(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+       struct lpfc_hba *phba = vport->phba;
+       struct pci_dev *pdev = phba->pcidev;
+       union  lpfc_sli4_cfg_shdr *shdr;
+       uint32_t shdr_status, shdr_add_status;
+       LPFC_MBOXQ_t *mboxq;
+       struct lpfc_mbx_get_prof_cfg *get_prof_cfg;
+       struct lpfc_rsrc_desc_pcie *desc;
+       uint32_t max_nr_virtfn;
+       uint32_t desc_count;
+       int length, rc, i;
+
+       if ((phba->sli_rev < LPFC_SLI_REV4) ||
+           (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+            LPFC_SLI_INTF_IF_TYPE_2))
+               return -EPERM;
+
+       if (!pdev->is_physfn)
+               return snprintf(buf, PAGE_SIZE, "%d\n", 0);
+
+       mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq)
+               return -ENOMEM;
+
+       /* get the maximum number of virtfn support by physfn */
+       length = (sizeof(struct lpfc_mbx_get_prof_cfg) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
+                        LPFC_MBOX_OPCODE_GET_PROFILE_CONFIG,
+                        length, LPFC_SLI4_MBX_EMBED);
+       shdr = (union lpfc_sli4_cfg_shdr *)
+               &mboxq->u.mqe.un.sli4_config.header.cfg_shdr;
+       bf_set(lpfc_mbox_hdr_pf_num, &shdr->request,
+              phba->sli4_hba.iov.pf_number + 1);
+
+       get_prof_cfg = &mboxq->u.mqe.un.get_prof_cfg;
+       bf_set(lpfc_mbx_get_prof_cfg_prof_tp, &get_prof_cfg->u.request,
+              LPFC_CFG_TYPE_CURRENT_ACTIVE);
+
+       rc = lpfc_sli_issue_mbox_wait(phba, mboxq,
+                               lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG));
+
+       if (rc != MBX_TIMEOUT) {
+               /* check return status */
+               shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+               shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
+                                        &shdr->response);
+               if (shdr_status || shdr_add_status || rc)
+                       goto error_out;
+
+       } else
+               goto error_out;
+
+       desc_count = get_prof_cfg->u.response.prof_cfg.rsrc_desc_count;
+
+       for (i = 0; i < LPFC_RSRC_DESC_MAX_NUM; i++) {
+               desc = (struct lpfc_rsrc_desc_pcie *)
+                       &get_prof_cfg->u.response.prof_cfg.desc[i];
+               if (LPFC_RSRC_DESC_TYPE_PCIE ==
+                   bf_get(lpfc_rsrc_desc_pcie_type, desc)) {
+                       max_nr_virtfn = bf_get(lpfc_rsrc_desc_pcie_nr_virtfn,
+                                              desc);
+                       break;
+               }
+       }
+
+       if (i < LPFC_RSRC_DESC_MAX_NUM) {
+               if (rc != MBX_TIMEOUT)
+                       mempool_free(mboxq, phba->mbox_mem_pool);
+               return snprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn);
+       }
+
+error_out:
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mboxq, phba->mbox_mem_pool);
+       return -EIO;
+}
+
 /**
  * lpfc_param_show - Return a cfg attribute value in decimal
  *
@@ -1762,6 +1931,8 @@ static DEVICE_ATTR(lpfc_temp_sensor, S_IRUGO, lpfc_temp_sensor_show, NULL);
 static DEVICE_ATTR(lpfc_fips_level, S_IRUGO, lpfc_fips_level_show, NULL);
 static DEVICE_ATTR(lpfc_fips_rev, S_IRUGO, lpfc_fips_rev_show, NULL);
 static DEVICE_ATTR(lpfc_dss, S_IRUGO, lpfc_dss_show, NULL);
+static DEVICE_ATTR(lpfc_sriov_hw_max_virtfn, S_IRUGO,
+                  lpfc_sriov_hw_max_virtfn_show, NULL);
 
 static char *lpfc_soft_wwn_key = "C99G71SL8032A";
 
@@ -3014,7 +3185,7 @@ static DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR,
  *
  * @dev: class device that is converted into a Scsi_host.
  * @attr: device attribute, not used.
- * @buf: containing the string "selective".
+ * @buf: containing enable or disable aer flag.
  * @count: unused variable.
  *
  * Description:
@@ -3098,7 +3269,7 @@ lpfc_param_show(aer_support)
 /**
  * lpfc_aer_support_init - Set the initial adapters aer support flag
  * @phba: lpfc_hba pointer.
- * @val: link speed value.
+ * @val: enable aer or disable aer flag.
  *
  * Description:
  * If val is in a valid range [0,1], then set the adapter's initial
@@ -3137,7 +3308,7 @@ static DEVICE_ATTR(lpfc_aer_support, S_IRUGO | S_IWUSR,
  * lpfc_aer_cleanup_state - Clean up aer state to the aer enabled device
  * @dev: class device that is converted into a Scsi_host.
  * @attr: device attribute, not used.
- * @buf: containing the string "selective".
+ * @buf: containing flag 1 for aer cleanup state.
  * @count: unused variable.
  *
  * Description:
@@ -3180,6 +3351,136 @@ lpfc_aer_cleanup_state(struct device *dev, struct device_attribute *attr,
 static DEVICE_ATTR(lpfc_aer_state_cleanup, S_IWUSR, NULL,
                   lpfc_aer_cleanup_state);
 
+/**
+ * lpfc_sriov_nr_virtfn_store - Enable the adapter for sr-iov virtual functions
+ *
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: containing the string the number of vfs to be enabled.
+ * @count: unused variable.
+ *
+ * Description:
+ * When this api is called either through user sysfs, the driver shall
+ * try to enable or disable SR-IOV virtual functions according to the
+ * following:
+ *
+ * If zero virtual function has been enabled to the physical function,
+ * the driver shall invoke the pci enable virtual function api trying
+ * to enable the virtual functions. If the nr_vfn provided is greater
+ * than the maximum supported, the maximum virtual function number will
+ * be used for invoking the api; otherwise, the nr_vfn provided shall
+ * be used for invoking the api. If the api call returned success, the
+ * actual number of virtual functions enabled will be set to the driver
+ * cfg_sriov_nr_virtfn; otherwise, -EINVAL shall be returned and driver
+ * cfg_sriov_nr_virtfn remains zero.
+ *
+ * If none-zero virtual functions have already been enabled to the
+ * physical function, as reflected by the driver's cfg_sriov_nr_virtfn,
+ * -EINVAL will be returned and the driver does nothing;
+ *
+ * If the nr_vfn provided is zero and none-zero virtual functions have
+ * been enabled, as indicated by the driver's cfg_sriov_nr_virtfn, the
+ * disabling virtual function api shall be invoded to disable all the
+ * virtual functions and driver's cfg_sriov_nr_virtfn shall be set to
+ * zero. Otherwise, if zero virtual function has been enabled, do
+ * nothing.
+ *
+ * Returns:
+ * length of the buf on success if val is in range the intended mode
+ * is supported.
+ * -EINVAL if val out of range or intended mode is not supported.
+ **/
+static ssize_t
+lpfc_sriov_nr_virtfn_store(struct device *dev, struct device_attribute *attr,
+                        const char *buf, size_t count)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
+       struct lpfc_hba *phba = vport->phba;
+       struct pci_dev *pdev = phba->pcidev;
+       int val = 0, rc = -EINVAL;
+
+       /* Sanity check on user data */
+       if (!isdigit(buf[0]))
+               return -EINVAL;
+       if (sscanf(buf, "%i", &val) != 1)
+               return -EINVAL;
+       if (val < 0)
+               return -EINVAL;
+
+       /* Request disabling virtual functions */
+       if (val == 0) {
+               if (phba->cfg_sriov_nr_virtfn > 0) {
+                       pci_disable_sriov(pdev);
+                       phba->cfg_sriov_nr_virtfn = 0;
+               }
+               return strlen(buf);
+       }
+
+       /* Request enabling virtual functions */
+       if (phba->cfg_sriov_nr_virtfn > 0) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3018 There are %d virtual functions "
+                               "enabled on physical function.\n",
+                               phba->cfg_sriov_nr_virtfn);
+               return -EEXIST;
+       }
+
+       if (val <= LPFC_MAX_VFN_PER_PFN)
+               phba->cfg_sriov_nr_virtfn = val;
+       else {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3019 Enabling %d virtual functions is not "
+                               "allowed.\n", val);
+               return -EINVAL;
+       }
+
+       rc = lpfc_sli_probe_sriov_nr_virtfn(phba, phba->cfg_sriov_nr_virtfn);
+       if (rc) {
+               phba->cfg_sriov_nr_virtfn = 0;
+               rc = -EPERM;
+       } else
+               rc = strlen(buf);
+
+       return rc;
+}
+
+static int lpfc_sriov_nr_virtfn = LPFC_DEF_VFN_PER_PFN;
+module_param(lpfc_sriov_nr_virtfn, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(lpfc_sriov_nr_virtfn, "Enable PCIe device SR-IOV virtual fn");
+lpfc_param_show(sriov_nr_virtfn)
+
+/**
+ * lpfc_sriov_nr_virtfn_init - Set the initial sr-iov virtual function enable
+ * @phba: lpfc_hba pointer.
+ * @val: link speed value.
+ *
+ * Description:
+ * If val is in a valid range [0,255], then set the adapter's initial
+ * cfg_sriov_nr_virtfn field. If it's greater than the maximum, the maximum
+ * number shall be used instead. It will be up to the driver's probe_one
+ * routine to determine whether the device's SR-IOV is supported or not.
+ *
+ * Returns:
+ * zero if val saved.
+ * -EINVAL val out of range
+ **/
+static int
+lpfc_sriov_nr_virtfn_init(struct lpfc_hba *phba, int val)
+{
+       if (val >= 0 && val <= LPFC_MAX_VFN_PER_PFN) {
+               phba->cfg_sriov_nr_virtfn = val;
+               return 0;
+       }
+
+       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       "3017 Enabling %d virtual functions is not "
+                       "allowed.\n", val);
+       return -EINVAL;
+}
+static DEVICE_ATTR(lpfc_sriov_nr_virtfn, S_IRUGO | S_IWUSR,
+                  lpfc_sriov_nr_virtfn_show, lpfc_sriov_nr_virtfn_store);
+
 /*
 # lpfc_fcp_class:  Determines FC class to use for the FCP protocol.
 # Value range is [2,3]. Default value is 3.
@@ -3497,6 +3798,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_lpfc_prot_sg_seg_cnt,
        &dev_attr_lpfc_aer_support,
        &dev_attr_lpfc_aer_state_cleanup,
+       &dev_attr_lpfc_sriov_nr_virtfn,
        &dev_attr_lpfc_suppress_link_up,
        &dev_attr_lpfc_iocb_cnt,
        &dev_attr_iocb_hw,
@@ -3505,6 +3807,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_lpfc_fips_level,
        &dev_attr_lpfc_fips_rev,
        &dev_attr_lpfc_dss,
+       &dev_attr_lpfc_sriov_hw_max_virtfn,
        NULL,
 };
 
@@ -3961,7 +4264,7 @@ static struct bin_attribute sysfs_mbox_attr = {
                .name = "mbox",
                .mode = S_IRUSR | S_IWUSR,
        },
-       .size = MAILBOX_CMD_SIZE,
+       .size = MAILBOX_SYSFS_MAX,
        .read = sysfs_mbox_read,
        .write = sysfs_mbox_write,
 };
@@ -4705,6 +5008,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
        lpfc_hba_log_verbose_init(phba, lpfc_log_verbose);
        lpfc_aer_support_init(phba, lpfc_aer_support);
+       lpfc_sriov_nr_virtfn_init(phba, lpfc_sriov_nr_virtfn);
        lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up);
        lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt);
        phba->cfg_enable_dss = 1;
index 853e5042f39c6ebd6a6a239084d99ec25914896b..7fb0ba4cbfa7048661bb616e5b8c5bdad5a09252 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/list.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
@@ -79,8 +80,7 @@ struct lpfc_bsg_iocb {
 struct lpfc_bsg_mbox {
        LPFC_MBOXQ_t *pmboxq;
        MAILBOX_t *mb;
-       struct lpfc_dmabuf *rxbmp; /* for BIU diags */
-       struct lpfc_dmabufext *dmp; /* for BIU diags */
+       struct lpfc_dmabuf *dmabuffers; /* for BIU diags */
        uint8_t *ext; /* extended mailbox data */
        uint32_t mbOffset; /* from app */
        uint32_t inExtWLen; /* from app */
@@ -332,6 +332,8 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
        cmd->ulpLe = 1;
        cmd->ulpClass = CLASS3;
        cmd->ulpContext = ndlp->nlp_rpi;
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               cmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
        cmd->ulpOwner = OWN_CHIP;
        cmdiocbq->vport = phba->pport;
        cmdiocbq->context3 = bmp;
@@ -1336,6 +1338,10 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
                }
 
                icmd->un.ulpWord[3] = ndlp->nlp_rpi;
+               if (phba->sli_rev == LPFC_SLI_REV4)
+                       icmd->ulpContext =
+                               phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
+
                /* The exchange is done, mark the entry as invalid */
                phba->ct_ctx[tag].flags &= ~UNSOL_VALID;
        } else
@@ -1463,11 +1469,91 @@ send_mgmt_rsp_exit:
 }
 
 /**
- * lpfc_bsg_diag_mode - process a LPFC_BSG_VENDOR_DIAG_MODE bsg vendor command
+ * lpfc_bsg_diag_mode_enter - process preparing into device diag loopback mode
+ * @phba: Pointer to HBA context object.
+ * @job: LPFC_BSG_VENDOR_DIAG_MODE
+ *
+ * This function is responsible for preparing driver for diag loopback
+ * on device.
+ */
+static int
+lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba, struct fc_bsg_job *job)
+{
+       struct lpfc_vport **vports;
+       struct Scsi_Host *shost;
+       struct lpfc_sli *psli;
+       struct lpfc_sli_ring *pring;
+       int i = 0;
+
+       psli = &phba->sli;
+       if (!psli)
+               return -ENODEV;
+
+       pring = &psli->ring[LPFC_FCP_RING];
+       if (!pring)
+               return -ENODEV;
+
+       if ((phba->link_state == LPFC_HBA_ERROR) ||
+           (psli->sli_flag & LPFC_BLOCK_MGMT_IO) ||
+           (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
+               return -EACCES;
+
+       vports = lpfc_create_vport_work_array(phba);
+       if (vports) {
+               for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+                       shost = lpfc_shost_from_vport(vports[i]);
+                       scsi_block_requests(shost);
+               }
+               lpfc_destroy_vport_work_array(phba, vports);
+       } else {
+               shost = lpfc_shost_from_vport(phba->pport);
+               scsi_block_requests(shost);
+       }
+
+       while (pring->txcmplq_cnt) {
+               if (i++ > 500)  /* wait up to 5 seconds */
+                       break;
+               msleep(10);
+       }
+       return 0;
+}
+
+/**
+ * lpfc_bsg_diag_mode_exit - exit process from device diag loopback mode
+ * @phba: Pointer to HBA context object.
+ * @job: LPFC_BSG_VENDOR_DIAG_MODE
+ *
+ * This function is responsible for driver exit processing of setting up
+ * diag loopback mode on device.
+ */
+static void
+lpfc_bsg_diag_mode_exit(struct lpfc_hba *phba)
+{
+       struct Scsi_Host *shost;
+       struct lpfc_vport **vports;
+       int i;
+
+       vports = lpfc_create_vport_work_array(phba);
+       if (vports) {
+               for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+                       shost = lpfc_shost_from_vport(vports[i]);
+                       scsi_unblock_requests(shost);
+               }
+               lpfc_destroy_vport_work_array(phba, vports);
+       } else {
+               shost = lpfc_shost_from_vport(phba->pport);
+               scsi_unblock_requests(shost);
+       }
+       return;
+}
+
+/**
+ * lpfc_sli3_bsg_diag_loopback_mode - process an sli3 bsg vendor command
+ * @phba: Pointer to HBA context object.
  * @job: LPFC_BSG_VENDOR_DIAG_MODE
  *
- * This function is responsible for placing a port into diagnostic loopback
- * mode in order to perform a diagnostic loopback test.
+ * This function is responsible for placing an sli3  port into diagnostic
+ * loopback mode in order to perform a diagnostic loopback test.
  * All new scsi requests are blocked, a small delay is used to allow the
  * scsi requests to complete then the link is brought down. If the link is
  * is placed in loopback mode then scsi requests are again allowed
@@ -1475,17 +1561,11 @@ send_mgmt_rsp_exit:
  * All of this is done in-line.
  */
 static int
-lpfc_bsg_diag_mode(struct fc_bsg_job *job)
+lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)
 {
-       struct Scsi_Host *shost = job->shost;
-       struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
-       struct lpfc_hba *phba = vport->phba;
        struct diag_mode_set *loopback_mode;
-       struct lpfc_sli *psli = &phba->sli;
-       struct lpfc_sli_ring *pring = &psli->ring[LPFC_FCP_RING];
        uint32_t link_flags;
        uint32_t timeout;
-       struct lpfc_vport **vports;
        LPFC_MBOXQ_t *pmboxq;
        int mbxstatus;
        int i = 0;
@@ -1494,53 +1574,33 @@ lpfc_bsg_diag_mode(struct fc_bsg_job *job)
        /* no data to return just the return code */
        job->reply->reply_payload_rcv_len = 0;
 
-       if (job->request_len <
-           sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_set)) {
+       if (job->request_len < sizeof(struct fc_bsg_request) +
+           sizeof(struct diag_mode_set)) {
                lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
-                               "2738 Received DIAG MODE request below minimum "
-                               "size\n");
+                               "2738 Received DIAG MODE request size:%d "
+                               "below the minimum size:%d\n",
+                               job->request_len,
+                               (int)(sizeof(struct fc_bsg_request) +
+                               sizeof(struct diag_mode_set)));
                rc = -EINVAL;
                goto job_error;
        }
 
+       rc = lpfc_bsg_diag_mode_enter(phba, job);
+       if (rc)
+               goto job_error;
+
+       /* bring the link to diagnostic mode */
        loopback_mode = (struct diag_mode_set *)
                job->request->rqst_data.h_vendor.vendor_cmd;
        link_flags = loopback_mode->type;
        timeout = loopback_mode->timeout * 100;
 
-       if ((phba->link_state == LPFC_HBA_ERROR) ||
-           (psli->sli_flag & LPFC_BLOCK_MGMT_IO) ||
-           (!(psli->sli_flag & LPFC_SLI_ACTIVE))) {
-               rc = -EACCES;
-               goto job_error;
-       }
-
        pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!pmboxq) {
                rc = -ENOMEM;
-               goto job_error;
-       }
-
-       vports = lpfc_create_vport_work_array(phba);
-       if (vports) {
-               for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
-                       shost = lpfc_shost_from_vport(vports[i]);
-                       scsi_block_requests(shost);
-               }
-
-               lpfc_destroy_vport_work_array(phba, vports);
-       } else {
-               shost = lpfc_shost_from_vport(phba->pport);
-               scsi_block_requests(shost);
-       }
-
-       while (pring->txcmplq_cnt) {
-               if (i++ > 500)  /* wait up to 5 seconds */
-                       break;
-
-               msleep(10);
+               goto loopback_mode_exit;
        }
-
        memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t));
        pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK;
        pmboxq->u.mb.mbxOwner = OWN_HOST;
@@ -1594,17 +1654,7 @@ lpfc_bsg_diag_mode(struct fc_bsg_job *job)
                rc = -ENODEV;
 
 loopback_mode_exit:
-       vports = lpfc_create_vport_work_array(phba);
-       if (vports) {
-               for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
-                       shost = lpfc_shost_from_vport(vports[i]);
-                       scsi_unblock_requests(shost);
-               }
-               lpfc_destroy_vport_work_array(phba, vports);
-       } else {
-               shost = lpfc_shost_from_vport(phba->pport);
-               scsi_unblock_requests(shost);
-       }
+       lpfc_bsg_diag_mode_exit(phba);
 
        /*
         * Let SLI layer release mboxq if mbox command completed after timeout.
@@ -1622,1000 +1672,2430 @@ job_error:
 }
 
 /**
- * lpfcdiag_loop_self_reg - obtains a remote port login id
- * @phba: Pointer to HBA context object
- * @rpi: Pointer to a remote port login id
+ * lpfc_sli4_bsg_set_link_diag_state - set sli4 link diag state
+ * @phba: Pointer to HBA context object.
+ * @diag: Flag for set link to diag or nomral operation state.
  *
- * This function obtains a remote port login id so the diag loopback test
- * can send and receive its own unsolicited CT command.
- **/
-static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi)
+ * This function is responsible for issuing a sli4 mailbox command for setting
+ * link to either diag state or normal operation state.
+ */
+static int
+lpfc_sli4_bsg_set_link_diag_state(struct lpfc_hba *phba, uint32_t diag)
 {
-       LPFC_MBOXQ_t *mbox;
-       struct lpfc_dmabuf *dmabuff;
-       int status;
+       LPFC_MBOXQ_t *pmboxq;
+       struct lpfc_mbx_set_link_diag_state *link_diag_state;
+       uint32_t req_len, alloc_len;
+       int mbxstatus = MBX_SUCCESS, rc;
 
-       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-       if (!mbox)
+       pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!pmboxq)
                return -ENOMEM;
 
-       if (phba->sli_rev == LPFC_SLI_REV4)
-               *rpi = lpfc_sli4_alloc_rpi(phba);
-       status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID,
-                             (uint8_t *)&phba->pport->fc_sparam, mbox, *rpi);
-       if (status) {
-               mempool_free(mbox, phba->mbox_mem_pool);
-               if (phba->sli_rev == LPFC_SLI_REV4)
-                       lpfc_sli4_free_rpi(phba, *rpi);
-               return -ENOMEM;
+       req_len = (sizeof(struct lpfc_mbx_set_link_diag_state) -
+                  sizeof(struct lpfc_sli4_cfg_mhdr));
+       alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
+                               LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE,
+                               req_len, LPFC_SLI4_MBX_EMBED);
+       if (alloc_len != req_len) {
+               rc = -ENOMEM;
+               goto link_diag_state_set_out;
        }
+       link_diag_state = &pmboxq->u.mqe.un.link_diag_state;
+       bf_set(lpfc_mbx_set_diag_state_link_num, &link_diag_state->u.req,
+              phba->sli4_hba.link_state.number);
+       bf_set(lpfc_mbx_set_diag_state_link_type, &link_diag_state->u.req,
+              phba->sli4_hba.link_state.type);
+       if (diag)
+               bf_set(lpfc_mbx_set_diag_state_diag,
+                      &link_diag_state->u.req, 1);
+       else
+               bf_set(lpfc_mbx_set_diag_state_diag,
+                      &link_diag_state->u.req, 0);
 
-       dmabuff = (struct lpfc_dmabuf *) mbox->context1;
-       mbox->context1 = NULL;
-       mbox->context2 = NULL;
-       status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
+       mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO);
 
-       if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) {
-               lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys);
-               kfree(dmabuff);
-               if (status != MBX_TIMEOUT)
-                       mempool_free(mbox, phba->mbox_mem_pool);
-               if (phba->sli_rev == LPFC_SLI_REV4)
-                       lpfc_sli4_free_rpi(phba, *rpi);
-               return -ENODEV;
-       }
+       if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0))
+               rc = 0;
+       else
+               rc = -ENODEV;
 
-       *rpi = mbox->u.mb.un.varWords[0];
+link_diag_state_set_out:
+       if (pmboxq && (mbxstatus != MBX_TIMEOUT))
+               mempool_free(pmboxq, phba->mbox_mem_pool);
 
-       lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys);
-       kfree(dmabuff);
-       mempool_free(mbox, phba->mbox_mem_pool);
-       return 0;
+       return rc;
 }
 
 /**
- * lpfcdiag_loop_self_unreg - unregs from the rpi
- * @phba: Pointer to HBA context object
- * @rpi: Remote port login id
+ * lpfc_sli4_bsg_diag_loopback_mode - process an sli4 bsg vendor command
+ * @phba: Pointer to HBA context object.
+ * @job: LPFC_BSG_VENDOR_DIAG_MODE
  *
- * This function unregisters the rpi obtained in lpfcdiag_loop_self_reg
- **/
-static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi)
+ * This function is responsible for placing an sli4 port into diagnostic
+ * loopback mode in order to perform a diagnostic loopback test.
+ */
+static int
+lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)
 {
-       LPFC_MBOXQ_t *mbox;
-       int status;
-
-       /* Allocate mboxq structure */
-       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-       if (mbox == NULL)
-               return -ENOMEM;
+       struct diag_mode_set *loopback_mode;
+       uint32_t link_flags, timeout, req_len, alloc_len;
+       struct lpfc_mbx_set_link_diag_loopback *link_diag_loopback;
+       LPFC_MBOXQ_t *pmboxq = NULL;
+       int mbxstatus, i, rc = 0;
 
-       lpfc_unreg_login(phba, 0, rpi, mbox);
-       status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
+       /* no data to return just the return code */
+       job->reply->reply_payload_rcv_len = 0;
 
-       if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) {
-               if (status != MBX_TIMEOUT)
-                       mempool_free(mbox, phba->mbox_mem_pool);
-               return -EIO;
+       if (job->request_len < sizeof(struct fc_bsg_request) +
+           sizeof(struct diag_mode_set)) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+                               "3011 Received DIAG MODE request size:%d "
+                               "below the minimum size:%d\n",
+                               job->request_len,
+                               (int)(sizeof(struct fc_bsg_request) +
+                               sizeof(struct diag_mode_set)));
+               rc = -EINVAL;
+               goto job_error;
        }
-       mempool_free(mbox, phba->mbox_mem_pool);
-       if (phba->sli_rev == LPFC_SLI_REV4)
-               lpfc_sli4_free_rpi(phba, rpi);
-       return 0;
-}
 
-/**
- * lpfcdiag_loop_get_xri - obtains the transmit and receive ids
- * @phba: Pointer to HBA context object
- * @rpi: Remote port login id
- * @txxri: Pointer to transmit exchange id
- * @rxxri: Pointer to response exchabge id
- *
- * This function obtains the transmit and receive ids required to send
- * an unsolicited ct command with a payload. A special lpfc FsType and CmdRsp
- * flags are used to the unsolicted response handler is able to process
- * the ct command sent on the same port.
- **/
-static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi,
-                        uint16_t *txxri, uint16_t * rxxri)
-{
-       struct lpfc_bsg_event *evt;
-       struct lpfc_iocbq *cmdiocbq, *rspiocbq;
-       IOCB_t *cmd, *rsp;
-       struct lpfc_dmabuf *dmabuf;
-       struct ulp_bde64 *bpl = NULL;
-       struct lpfc_sli_ct_request *ctreq = NULL;
-       int ret_val = 0;
-       int time_left;
-       int iocb_stat = 0;
-       unsigned long flags;
+       rc = lpfc_bsg_diag_mode_enter(phba, job);
+       if (rc)
+               goto job_error;
 
-       *txxri = 0;
-       *rxxri = 0;
-       evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid,
-                               SLI_CT_ELX_LOOPBACK);
-       if (!evt)
-               return -ENOMEM;
+       /* bring the link to diagnostic mode */
+       loopback_mode = (struct diag_mode_set *)
+               job->request->rqst_data.h_vendor.vendor_cmd;
+       link_flags = loopback_mode->type;
+       timeout = loopback_mode->timeout * 100;
 
-       spin_lock_irqsave(&phba->ct_ev_lock, flags);
-       list_add(&evt->node, &phba->ct_ev_waiters);
-       lpfc_bsg_event_ref(evt);
-       spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+       rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1);
+       if (rc)
+               goto loopback_mode_exit;
 
-       cmdiocbq = lpfc_sli_get_iocbq(phba);
-       rspiocbq = lpfc_sli_get_iocbq(phba);
+       /* wait for link down before proceeding */
+       i = 0;
+       while (phba->link_state != LPFC_LINK_DOWN) {
+               if (i++ > timeout) {
+                       rc = -ETIMEDOUT;
+                       goto loopback_mode_exit;
+               }
+               msleep(10);
+       }
+       /* set up loopback mode */
+       pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!pmboxq) {
+               rc = -ENOMEM;
+               goto loopback_mode_exit;
+       }
+       req_len = (sizeof(struct lpfc_mbx_set_link_diag_loopback) -
+                  sizeof(struct lpfc_sli4_cfg_mhdr));
+       alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
+                               LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK,
+                               req_len, LPFC_SLI4_MBX_EMBED);
+       if (alloc_len != req_len) {
+               rc = -ENOMEM;
+               goto loopback_mode_exit;
+       }
+       link_diag_loopback = &pmboxq->u.mqe.un.link_diag_loopback;
+       bf_set(lpfc_mbx_set_diag_state_link_num,
+              &link_diag_loopback->u.req, phba->sli4_hba.link_state.number);
+       bf_set(lpfc_mbx_set_diag_state_link_type,
+              &link_diag_loopback->u.req, phba->sli4_hba.link_state.type);
+       if (link_flags == INTERNAL_LOOP_BACK)
+               bf_set(lpfc_mbx_set_diag_lpbk_type,
+                      &link_diag_loopback->u.req,
+                      LPFC_DIAG_LOOPBACK_TYPE_INTERNAL);
+       else
+               bf_set(lpfc_mbx_set_diag_lpbk_type,
+                      &link_diag_loopback->u.req,
+                      LPFC_DIAG_LOOPBACK_TYPE_EXTERNAL);
 
-       dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
-       if (dmabuf) {
-               dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys);
-               if (dmabuf->virt) {
-                       INIT_LIST_HEAD(&dmabuf->list);
-                       bpl = (struct ulp_bde64 *) dmabuf->virt;
-                       memset(bpl, 0, sizeof(*bpl));
-                       ctreq = (struct lpfc_sli_ct_request *)(bpl + 1);
-                       bpl->addrHigh =
-                               le32_to_cpu(putPaddrHigh(dmabuf->phys +
-                                       sizeof(*bpl)));
-                       bpl->addrLow =
-                               le32_to_cpu(putPaddrLow(dmabuf->phys +
-                                       sizeof(*bpl)));
-                       bpl->tus.f.bdeFlags = 0;
-                       bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ;
-                       bpl->tus.w = le32_to_cpu(bpl->tus.w);
+       mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO);
+       if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus))
+               rc = -ENODEV;
+       else {
+               phba->link_flag |= LS_LOOPBACK_MODE;
+               /* wait for the link attention interrupt */
+               msleep(100);
+               i = 0;
+               while (phba->link_state != LPFC_HBA_READY) {
+                       if (i++ > timeout) {
+                               rc = -ETIMEDOUT;
+                               break;
+                       }
+                       msleep(10);
                }
        }
 
-       if (cmdiocbq == NULL || rspiocbq == NULL ||
-           dmabuf == NULL || bpl == NULL || ctreq == NULL ||
-               dmabuf->virt == NULL) {
-               ret_val = -ENOMEM;
-               goto err_get_xri_exit;
-       }
+loopback_mode_exit:
+       lpfc_bsg_diag_mode_exit(phba);
 
-       cmd = &cmdiocbq->iocb;
-       rsp = &rspiocbq->iocb;
+       /*
+        * Let SLI layer release mboxq if mbox command completed after timeout.
+        */
+       if (pmboxq && (mbxstatus != MBX_TIMEOUT))
+               mempool_free(pmboxq, phba->mbox_mem_pool);
 
-       memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ);
+job_error:
+       /* make error code available to userspace */
+       job->reply->result = rc;
+       /* complete the job back to userspace if no error */
+       if (rc == 0)
+               job->job_done(job);
+       return rc;
+}
 
-       ctreq->RevisionId.bits.Revision = SLI_CT_REVISION;
-       ctreq->RevisionId.bits.InId = 0;
-       ctreq->FsType = SLI_CT_ELX_LOOPBACK;
-       ctreq->FsSubType = 0;
-       ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_XRI_SETUP;
-       ctreq->CommandResponse.bits.Size = 0;
+/**
+ * lpfc_bsg_diag_loopback_mode - bsg vendor command for diag loopback mode
+ * @job: LPFC_BSG_VENDOR_DIAG_MODE
+ *
+ * This function is responsible for responding to check and dispatch bsg diag
+ * command from the user to proper driver action routines.
+ */
+static int
+lpfc_bsg_diag_loopback_mode(struct fc_bsg_job *job)
+{
+       struct Scsi_Host *shost;
+       struct lpfc_vport *vport;
+       struct lpfc_hba *phba;
+       int rc;
 
+       shost = job->shost;
+       if (!shost)
+               return -ENODEV;
+       vport = (struct lpfc_vport *)job->shost->hostdata;
+       if (!vport)
+               return -ENODEV;
+       phba = vport->phba;
+       if (!phba)
+               return -ENODEV;
 
-       cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(dmabuf->phys);
-       cmd->un.xseq64.bdl.addrLow = putPaddrLow(dmabuf->phys);
-       cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
-       cmd->un.xseq64.bdl.bdeSize = sizeof(*bpl);
+       if (phba->sli_rev < LPFC_SLI_REV4)
+               rc = lpfc_sli3_bsg_diag_loopback_mode(phba, job);
+       else if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+                LPFC_SLI_INTF_IF_TYPE_2)
+               rc = lpfc_sli4_bsg_diag_loopback_mode(phba, job);
+       else
+               rc = -ENODEV;
 
-       cmd->un.xseq64.w5.hcsw.Fctl = LA;
-       cmd->un.xseq64.w5.hcsw.Dfctl = 0;
-       cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL;
-       cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT;
+       return rc;
 
-       cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CR;
-       cmd->ulpBdeCount = 1;
-       cmd->ulpLe = 1;
-       cmd->ulpClass = CLASS3;
-       cmd->ulpContext = rpi;
+}
 
-       cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
-       cmdiocbq->vport = phba->pport;
+/**
+ * lpfc_sli4_bsg_diag_mode_end - sli4 bsg vendor command for ending diag mode
+ * @job: LPFC_BSG_VENDOR_DIAG_MODE_END
+ *
+ * This function is responsible for responding to check and dispatch bsg diag
+ * command from the user to proper driver action routines.
+ */
+static int
+lpfc_sli4_bsg_diag_mode_end(struct fc_bsg_job *job)
+{
+       struct Scsi_Host *shost;
+       struct lpfc_vport *vport;
+       struct lpfc_hba *phba;
+       int rc;
 
-       iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
-                               rspiocbq,
-                               (phba->fc_ratov * 2)
-                               + LPFC_DRVR_TIMEOUT);
-       if (iocb_stat) {
-               ret_val = -EIO;
-               goto err_get_xri_exit;
-       }
-       *txxri =  rsp->ulpContext;
+       shost = job->shost;
+       if (!shost)
+               return -ENODEV;
+       vport = (struct lpfc_vport *)job->shost->hostdata;
+       if (!vport)
+               return -ENODEV;
+       phba = vport->phba;
+       if (!phba)
+               return -ENODEV;
 
-       evt->waiting = 1;
-       evt->wait_time_stamp = jiffies;
-       time_left = wait_event_interruptible_timeout(
-               evt->wq, !list_empty(&evt->events_to_see),
-               ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ);
-       if (list_empty(&evt->events_to_see))
-               ret_val = (time_left) ? -EINTR : -ETIMEDOUT;
-       else {
-               spin_lock_irqsave(&phba->ct_ev_lock, flags);
-               list_move(evt->events_to_see.prev, &evt->events_to_get);
-               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
-               *rxxri = (list_entry(evt->events_to_get.prev,
-                                    typeof(struct event_data),
-                                    node))->immed_dat;
-       }
-       evt->waiting = 0;
+       if (phba->sli_rev < LPFC_SLI_REV4)
+               return -ENODEV;
+       if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+           LPFC_SLI_INTF_IF_TYPE_2)
+               return -ENODEV;
 
-err_get_xri_exit:
-       spin_lock_irqsave(&phba->ct_ev_lock, flags);
-       lpfc_bsg_event_unref(evt); /* release ref */
-       lpfc_bsg_event_unref(evt); /* delete */
-       spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+       rc = lpfc_sli4_bsg_set_link_diag_state(phba, 0);
 
-       if (dmabuf) {
-               if (dmabuf->virt)
-                       lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
-               kfree(dmabuf);
-       }
+       if (!rc)
+               rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT);
 
-       if (cmdiocbq && (iocb_stat != IOCB_TIMEDOUT))
-               lpfc_sli_release_iocbq(phba, cmdiocbq);
-       if (rspiocbq)
-               lpfc_sli_release_iocbq(phba, rspiocbq);
-       return ret_val;
+       return rc;
 }
 
 /**
- * diag_cmd_data_alloc - fills in a bde struct with dma buffers
- * @phba: Pointer to HBA context object
- * @bpl: Pointer to 64 bit bde structure
- * @size: Number of bytes to process
- * @nocopydata: Flag to copy user data into the allocated buffer
+ * lpfc_sli4_bsg_link_diag_test - sli4 bsg vendor command for diag link test
+ * @job: LPFC_BSG_VENDOR_DIAG_LINK_TEST
  *
- * This function allocates page size buffers and populates an lpfc_dmabufext.
- * If allowed the user data pointed to with indataptr is copied into the kernel
- * memory. The chained list of page size buffers is returned.
- **/
-static struct lpfc_dmabufext *
-diag_cmd_data_alloc(struct lpfc_hba *phba,
-                  struct ulp_bde64 *bpl, uint32_t size,
-                  int nocopydata)
+ * This function is to perform SLI4 diag link test request from the user
+ * applicaiton.
+ */
+static int
+lpfc_sli4_bsg_link_diag_test(struct fc_bsg_job *job)
 {
-       struct lpfc_dmabufext *mlist = NULL;
-       struct lpfc_dmabufext *dmp;
-       int cnt, offset = 0, i = 0;
-       struct pci_dev *pcidev;
+       struct Scsi_Host *shost;
+       struct lpfc_vport *vport;
+       struct lpfc_hba *phba;
+       LPFC_MBOXQ_t *pmboxq;
+       struct sli4_link_diag *link_diag_test_cmd;
+       uint32_t req_len, alloc_len;
+       uint32_t timeout;
+       struct lpfc_mbx_run_link_diag_test *run_link_diag_test;
+       union lpfc_sli4_cfg_shdr *shdr;
+       uint32_t shdr_status, shdr_add_status;
+       struct diag_status *diag_status_reply;
+       int mbxstatus, rc = 0;
+
+       shost = job->shost;
+       if (!shost) {
+               rc = -ENODEV;
+               goto job_error;
+       }
+       vport = (struct lpfc_vport *)job->shost->hostdata;
+       if (!vport) {
+               rc = -ENODEV;
+               goto job_error;
+       }
+       phba = vport->phba;
+       if (!phba) {
+               rc = -ENODEV;
+               goto job_error;
+       }
 
-       pcidev = phba->pcidev;
+       if (phba->sli_rev < LPFC_SLI_REV4) {
+               rc = -ENODEV;
+               goto job_error;
+       }
+       if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+           LPFC_SLI_INTF_IF_TYPE_2) {
+               rc = -ENODEV;
+               goto job_error;
+       }
 
-       while (size) {
-               /* We get chunks of 4K */
-               if (size > BUF_SZ_4K)
-                       cnt = BUF_SZ_4K;
-               else
-                       cnt = size;
+       if (job->request_len < sizeof(struct fc_bsg_request) +
+           sizeof(struct sli4_link_diag)) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+                               "3013 Received LINK DIAG TEST request "
+                               " size:%d below the minimum size:%d\n",
+                               job->request_len,
+                               (int)(sizeof(struct fc_bsg_request) +
+                               sizeof(struct sli4_link_diag)));
+               rc = -EINVAL;
+               goto job_error;
+       }
 
-               /* allocate struct lpfc_dmabufext buffer header */
-               dmp = kmalloc(sizeof(struct lpfc_dmabufext), GFP_KERNEL);
-               if (!dmp)
-                       goto out;
+       rc = lpfc_bsg_diag_mode_enter(phba, job);
+       if (rc)
+               goto job_error;
 
-               INIT_LIST_HEAD(&dmp->dma.list);
+       link_diag_test_cmd = (struct sli4_link_diag *)
+                        job->request->rqst_data.h_vendor.vendor_cmd;
+       timeout = link_diag_test_cmd->timeout * 100;
 
-               /* Queue it to a linked list */
-               if (mlist)
-                       list_add_tail(&dmp->dma.list, &mlist->dma.list);
-               else
-                       mlist = dmp;
+       rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1);
 
-               /* allocate buffer */
-               dmp->dma.virt = dma_alloc_coherent(&pcidev->dev,
-                                                  cnt,
-                                                  &(dmp->dma.phys),
-                                                  GFP_KERNEL);
+       if (rc)
+               goto job_error;
 
-               if (!dmp->dma.virt)
-                       goto out;
+       pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!pmboxq) {
+               rc = -ENOMEM;
+               goto link_diag_test_exit;
+       }
 
-               dmp->size = cnt;
+       req_len = (sizeof(struct lpfc_mbx_set_link_diag_state) -
+                  sizeof(struct lpfc_sli4_cfg_mhdr));
+       alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
+                                    LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE,
+                                    req_len, LPFC_SLI4_MBX_EMBED);
+       if (alloc_len != req_len) {
+               rc = -ENOMEM;
+               goto link_diag_test_exit;
+       }
+       run_link_diag_test = &pmboxq->u.mqe.un.link_diag_test;
+       bf_set(lpfc_mbx_run_diag_test_link_num, &run_link_diag_test->u.req,
+              phba->sli4_hba.link_state.number);
+       bf_set(lpfc_mbx_run_diag_test_link_type, &run_link_diag_test->u.req,
+              phba->sli4_hba.link_state.type);
+       bf_set(lpfc_mbx_run_diag_test_test_id, &run_link_diag_test->u.req,
+              link_diag_test_cmd->test_id);
+       bf_set(lpfc_mbx_run_diag_test_loops, &run_link_diag_test->u.req,
+              link_diag_test_cmd->loops);
+       bf_set(lpfc_mbx_run_diag_test_test_ver, &run_link_diag_test->u.req,
+              link_diag_test_cmd->test_version);
+       bf_set(lpfc_mbx_run_diag_test_err_act, &run_link_diag_test->u.req,
+              link_diag_test_cmd->error_action);
+
+       mbxstatus = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
+
+       shdr = (union lpfc_sli4_cfg_shdr *)
+               &pmboxq->u.mqe.un.sli4_config.header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (shdr_status || shdr_add_status || mbxstatus) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+                               "3010 Run link diag test mailbox failed with "
+                               "mbx_status x%x status x%x, add_status x%x\n",
+                               mbxstatus, shdr_status, shdr_add_status);
+       }
 
-               if (nocopydata) {
-                       bpl->tus.f.bdeFlags = 0;
-                       pci_dma_sync_single_for_device(phba->pcidev,
-                               dmp->dma.phys, LPFC_BPL_SIZE, PCI_DMA_TODEVICE);
+       diag_status_reply = (struct diag_status *)
+                           job->reply->reply_data.vendor_reply.vendor_rsp;
 
-               } else {
-                       memset((uint8_t *)dmp->dma.virt, 0, cnt);
-                       bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
-               }
+       if (job->reply_len <
+           sizeof(struct fc_bsg_request) + sizeof(struct diag_status)) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+                               "3012 Received Run link diag test reply "
+                               "below minimum size (%d): reply_len:%d\n",
+                               (int)(sizeof(struct fc_bsg_request) +
+                               sizeof(struct diag_status)),
+                               job->reply_len);
+               rc = -EINVAL;
+               goto job_error;
+       }
 
-               /* build buffer ptr list for IOCB */
-               bpl->addrLow = le32_to_cpu(putPaddrLow(dmp->dma.phys));
-               bpl->addrHigh = le32_to_cpu(putPaddrHigh(dmp->dma.phys));
-               bpl->tus.f.bdeSize = (ushort) cnt;
-               bpl->tus.w = le32_to_cpu(bpl->tus.w);
-               bpl++;
+       diag_status_reply->mbox_status = mbxstatus;
+       diag_status_reply->shdr_status = shdr_status;
+       diag_status_reply->shdr_add_status = shdr_add_status;
 
-               i++;
-               offset += cnt;
-               size -= cnt;
-       }
+link_diag_test_exit:
+       rc = lpfc_sli4_bsg_set_link_diag_state(phba, 0);
 
-       mlist->flag = i;
-       return mlist;
-out:
-       diag_cmd_data_free(phba, mlist);
-       return NULL;
+       if (pmboxq)
+               mempool_free(pmboxq, phba->mbox_mem_pool);
+
+       lpfc_bsg_diag_mode_exit(phba);
+
+job_error:
+       /* make error code available to userspace */
+       job->reply->result = rc;
+       /* complete the job back to userspace if no error */
+       if (rc == 0)
+               job->job_done(job);
+       return rc;
 }
 
 /**
- * lpfcdiag_loop_post_rxbufs - post the receive buffers for an unsol CT cmd
+ * lpfcdiag_loop_self_reg - obtains a remote port login id
  * @phba: Pointer to HBA context object
- * @rxxri: Receive exchange id
- * @len: Number of data bytes
+ * @rpi: Pointer to a remote port login id
  *
- * This function allocates and posts a data buffer of sufficient size to receive
- * an unsolicted CT command.
+ * This function obtains a remote port login id so the diag loopback test
+ * can send and receive its own unsolicited CT command.
  **/
-static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri,
-                            size_t len)
+static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi)
 {
-       struct lpfc_sli *psli = &phba->sli;
-       struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
-       struct lpfc_iocbq *cmdiocbq;
-       IOCB_t *cmd = NULL;
-       struct list_head head, *curr, *next;
-       struct lpfc_dmabuf *rxbmp;
-       struct lpfc_dmabuf *dmp;
-       struct lpfc_dmabuf *mp[2] = {NULL, NULL};
-       struct ulp_bde64 *rxbpl = NULL;
-       uint32_t num_bde;
-       struct lpfc_dmabufext *rxbuffer = NULL;
+       LPFC_MBOXQ_t *mbox;
+       struct lpfc_dmabuf *dmabuff;
+       int status;
+
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               *rpi = lpfc_sli4_alloc_rpi(phba);
+       status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID,
+                             (uint8_t *)&phba->pport->fc_sparam, mbox, *rpi);
+       if (status) {
+               mempool_free(mbox, phba->mbox_mem_pool);
+               if (phba->sli_rev == LPFC_SLI_REV4)
+                       lpfc_sli4_free_rpi(phba, *rpi);
+               return -ENOMEM;
+       }
+
+       dmabuff = (struct lpfc_dmabuf *) mbox->context1;
+       mbox->context1 = NULL;
+       mbox->context2 = NULL;
+       status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
+
+       if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) {
+               lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys);
+               kfree(dmabuff);
+               if (status != MBX_TIMEOUT)
+                       mempool_free(mbox, phba->mbox_mem_pool);
+               if (phba->sli_rev == LPFC_SLI_REV4)
+                       lpfc_sli4_free_rpi(phba, *rpi);
+               return -ENODEV;
+       }
+
+       *rpi = mbox->u.mb.un.varWords[0];
+
+       lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys);
+       kfree(dmabuff);
+       mempool_free(mbox, phba->mbox_mem_pool);
+       return 0;
+}
+
+/**
+ * lpfcdiag_loop_self_unreg - unregs from the rpi
+ * @phba: Pointer to HBA context object
+ * @rpi: Remote port login id
+ *
+ * This function unregisters the rpi obtained in lpfcdiag_loop_self_reg
+ **/
+static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi)
+{
+       LPFC_MBOXQ_t *mbox;
+       int status;
+
+       /* Allocate mboxq structure */
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (mbox == NULL)
+               return -ENOMEM;
+
+       lpfc_unreg_login(phba, 0, rpi, mbox);
+       status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
+
+       if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) {
+               if (status != MBX_TIMEOUT)
+                       mempool_free(mbox, phba->mbox_mem_pool);
+               return -EIO;
+       }
+       mempool_free(mbox, phba->mbox_mem_pool);
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               lpfc_sli4_free_rpi(phba, rpi);
+       return 0;
+}
+
+/**
+ * lpfcdiag_loop_get_xri - obtains the transmit and receive ids
+ * @phba: Pointer to HBA context object
+ * @rpi: Remote port login id
+ * @txxri: Pointer to transmit exchange id
+ * @rxxri: Pointer to response exchabge id
+ *
+ * This function obtains the transmit and receive ids required to send
+ * an unsolicited ct command with a payload. A special lpfc FsType and CmdRsp
+ * flags are used to the unsolicted response handler is able to process
+ * the ct command sent on the same port.
+ **/
+static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi,
+                        uint16_t *txxri, uint16_t * rxxri)
+{
+       struct lpfc_bsg_event *evt;
+       struct lpfc_iocbq *cmdiocbq, *rspiocbq;
+       IOCB_t *cmd, *rsp;
+       struct lpfc_dmabuf *dmabuf;
+       struct ulp_bde64 *bpl = NULL;
+       struct lpfc_sli_ct_request *ctreq = NULL;
        int ret_val = 0;
-       int iocb_stat;
-       int i = 0;
+       int time_left;
+       int iocb_stat = 0;
+       unsigned long flags;
+
+       *txxri = 0;
+       *rxxri = 0;
+       evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid,
+                               SLI_CT_ELX_LOOPBACK);
+       if (!evt)
+               return -ENOMEM;
+
+       spin_lock_irqsave(&phba->ct_ev_lock, flags);
+       list_add(&evt->node, &phba->ct_ev_waiters);
+       lpfc_bsg_event_ref(evt);
+       spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
 
        cmdiocbq = lpfc_sli_get_iocbq(phba);
-       rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
-       if (rxbmp != NULL) {
-               rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
-               if (rxbmp->virt) {
-                       INIT_LIST_HEAD(&rxbmp->list);
-                       rxbpl = (struct ulp_bde64 *) rxbmp->virt;
-                       rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0);
+       rspiocbq = lpfc_sli_get_iocbq(phba);
+
+       dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+       if (dmabuf) {
+               dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys);
+               if (dmabuf->virt) {
+                       INIT_LIST_HEAD(&dmabuf->list);
+                       bpl = (struct ulp_bde64 *) dmabuf->virt;
+                       memset(bpl, 0, sizeof(*bpl));
+                       ctreq = (struct lpfc_sli_ct_request *)(bpl + 1);
+                       bpl->addrHigh =
+                               le32_to_cpu(putPaddrHigh(dmabuf->phys +
+                                       sizeof(*bpl)));
+                       bpl->addrLow =
+                               le32_to_cpu(putPaddrLow(dmabuf->phys +
+                                       sizeof(*bpl)));
+                       bpl->tus.f.bdeFlags = 0;
+                       bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ;
+                       bpl->tus.w = le32_to_cpu(bpl->tus.w);
                }
        }
 
-       if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer) {
+       if (cmdiocbq == NULL || rspiocbq == NULL ||
+           dmabuf == NULL || bpl == NULL || ctreq == NULL ||
+               dmabuf->virt == NULL) {
                ret_val = -ENOMEM;
-               goto err_post_rxbufs_exit;
+               goto err_get_xri_exit;
        }
 
-       /* Queue buffers for the receive exchange */
-       num_bde = (uint32_t)rxbuffer->flag;
-       dmp = &rxbuffer->dma;
-
        cmd = &cmdiocbq->iocb;
-       i = 0;
+       rsp = &rspiocbq->iocb;
 
-       INIT_LIST_HEAD(&head);
-       list_add_tail(&head, &dmp->list);
-       list_for_each_safe(curr, next, &head) {
-               mp[i] = list_entry(curr, struct lpfc_dmabuf, list);
-               list_del(curr);
+       memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ);
 
-               if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
-                       mp[i]->buffer_tag = lpfc_sli_get_buffer_tag(phba);
-                       cmd->un.quexri64cx.buff.bde.addrHigh =
-                               putPaddrHigh(mp[i]->phys);
-                       cmd->un.quexri64cx.buff.bde.addrLow =
-                               putPaddrLow(mp[i]->phys);
-                       cmd->un.quexri64cx.buff.bde.tus.f.bdeSize =
-                               ((struct lpfc_dmabufext *)mp[i])->size;
-                       cmd->un.quexri64cx.buff.buffer_tag = mp[i]->buffer_tag;
-                       cmd->ulpCommand = CMD_QUE_XRI64_CX;
-                       cmd->ulpPU = 0;
-                       cmd->ulpLe = 1;
-                       cmd->ulpBdeCount = 1;
-                       cmd->unsli3.que_xri64cx_ext_words.ebde_count = 0;
+       ctreq->RevisionId.bits.Revision = SLI_CT_REVISION;
+       ctreq->RevisionId.bits.InId = 0;
+       ctreq->FsType = SLI_CT_ELX_LOOPBACK;
+       ctreq->FsSubType = 0;
+       ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_XRI_SETUP;
+       ctreq->CommandResponse.bits.Size = 0;
 
-               } else {
-                       cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys);
-                       cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys);
-                       cmd->un.cont64[i].tus.f.bdeSize =
-                               ((struct lpfc_dmabufext *)mp[i])->size;
-                                       cmd->ulpBdeCount = ++i;
 
-                       if ((--num_bde > 0) && (i < 2))
-                               continue;
+       cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(dmabuf->phys);
+       cmd->un.xseq64.bdl.addrLow = putPaddrLow(dmabuf->phys);
+       cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
+       cmd->un.xseq64.bdl.bdeSize = sizeof(*bpl);
 
-                       cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX;
-                       cmd->ulpLe = 1;
-               }
+       cmd->un.xseq64.w5.hcsw.Fctl = LA;
+       cmd->un.xseq64.w5.hcsw.Dfctl = 0;
+       cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL;
+       cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT;
 
-               cmd->ulpClass = CLASS3;
-               cmd->ulpContext = rxxri;
+       cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CR;
+       cmd->ulpBdeCount = 1;
+       cmd->ulpLe = 1;
+       cmd->ulpClass = CLASS3;
+       cmd->ulpContext = rpi;
 
-               iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq,
-                                               0);
-               if (iocb_stat == IOCB_ERROR) {
-                       diag_cmd_data_free(phba,
-                               (struct lpfc_dmabufext *)mp[0]);
-                       if (mp[1])
-                               diag_cmd_data_free(phba,
-                                         (struct lpfc_dmabufext *)mp[1]);
-                       dmp = list_entry(next, struct lpfc_dmabuf, list);
-                       ret_val = -EIO;
-                       goto err_post_rxbufs_exit;
-               }
+       cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
+       cmdiocbq->vport = phba->pport;
+
+       iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
+                               rspiocbq,
+                               (phba->fc_ratov * 2)
+                               + LPFC_DRVR_TIMEOUT);
+       if (iocb_stat) {
+               ret_val = -EIO;
+               goto err_get_xri_exit;
+       }
+       *txxri =  rsp->ulpContext;
+
+       evt->waiting = 1;
+       evt->wait_time_stamp = jiffies;
+       time_left = wait_event_interruptible_timeout(
+               evt->wq, !list_empty(&evt->events_to_see),
+               ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ);
+       if (list_empty(&evt->events_to_see))
+               ret_val = (time_left) ? -EINTR : -ETIMEDOUT;
+       else {
+               spin_lock_irqsave(&phba->ct_ev_lock, flags);
+               list_move(evt->events_to_see.prev, &evt->events_to_get);
+               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+               *rxxri = (list_entry(evt->events_to_get.prev,
+                                    typeof(struct event_data),
+                                    node))->immed_dat;
+       }
+       evt->waiting = 0;
+
+err_get_xri_exit:
+       spin_lock_irqsave(&phba->ct_ev_lock, flags);
+       lpfc_bsg_event_unref(evt); /* release ref */
+       lpfc_bsg_event_unref(evt); /* delete */
+       spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+       if (dmabuf) {
+               if (dmabuf->virt)
+                       lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+               kfree(dmabuf);
+       }
+
+       if (cmdiocbq && (iocb_stat != IOCB_TIMEDOUT))
+               lpfc_sli_release_iocbq(phba, cmdiocbq);
+       if (rspiocbq)
+               lpfc_sli_release_iocbq(phba, rspiocbq);
+       return ret_val;
+}
+
+/**
+ * lpfc_bsg_dma_page_alloc - allocate a bsg mbox page sized dma buffers
+ * @phba: Pointer to HBA context object
+ *
+ * This function allocates BSG_MBOX_SIZE (4KB) page size dma buffer and.
+ * retruns the pointer to the buffer.
+ **/
+static struct lpfc_dmabuf *
+lpfc_bsg_dma_page_alloc(struct lpfc_hba *phba)
+{
+       struct lpfc_dmabuf *dmabuf;
+       struct pci_dev *pcidev = phba->pcidev;
+
+       /* allocate dma buffer struct */
+       dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+       if (!dmabuf)
+               return NULL;
+
+       INIT_LIST_HEAD(&dmabuf->list);
+
+       /* now, allocate dma buffer */
+       dmabuf->virt = dma_alloc_coherent(&pcidev->dev, BSG_MBOX_SIZE,
+                                         &(dmabuf->phys), GFP_KERNEL);
+
+       if (!dmabuf->virt) {
+               kfree(dmabuf);
+               return NULL;
+       }
+       memset((uint8_t *)dmabuf->virt, 0, BSG_MBOX_SIZE);
+
+       return dmabuf;
+}
+
+/**
+ * lpfc_bsg_dma_page_free - free a bsg mbox page sized dma buffer
+ * @phba: Pointer to HBA context object.
+ * @dmabuf: Pointer to the bsg mbox page sized dma buffer descriptor.
+ *
+ * This routine just simply frees a dma buffer and its associated buffer
+ * descriptor referred by @dmabuf.
+ **/
+static void
+lpfc_bsg_dma_page_free(struct lpfc_hba *phba, struct lpfc_dmabuf *dmabuf)
+{
+       struct pci_dev *pcidev = phba->pcidev;
+
+       if (!dmabuf)
+               return;
+
+       if (dmabuf->virt)
+               dma_free_coherent(&pcidev->dev, BSG_MBOX_SIZE,
+                                 dmabuf->virt, dmabuf->phys);
+       kfree(dmabuf);
+       return;
+}
+
+/**
+ * lpfc_bsg_dma_page_list_free - free a list of bsg mbox page sized dma buffers
+ * @phba: Pointer to HBA context object.
+ * @dmabuf_list: Pointer to a list of bsg mbox page sized dma buffer descs.
+ *
+ * This routine just simply frees all dma buffers and their associated buffer
+ * descriptors referred by @dmabuf_list.
+ **/
+static void
+lpfc_bsg_dma_page_list_free(struct lpfc_hba *phba,
+                           struct list_head *dmabuf_list)
+{
+       struct lpfc_dmabuf *dmabuf, *next_dmabuf;
+
+       if (list_empty(dmabuf_list))
+               return;
+
+       list_for_each_entry_safe(dmabuf, next_dmabuf, dmabuf_list, list) {
+               list_del_init(&dmabuf->list);
+               lpfc_bsg_dma_page_free(phba, dmabuf);
+       }
+       return;
+}
+
+/**
+ * diag_cmd_data_alloc - fills in a bde struct with dma buffers
+ * @phba: Pointer to HBA context object
+ * @bpl: Pointer to 64 bit bde structure
+ * @size: Number of bytes to process
+ * @nocopydata: Flag to copy user data into the allocated buffer
+ *
+ * This function allocates page size buffers and populates an lpfc_dmabufext.
+ * If allowed the user data pointed to with indataptr is copied into the kernel
+ * memory. The chained list of page size buffers is returned.
+ **/
+static struct lpfc_dmabufext *
+diag_cmd_data_alloc(struct lpfc_hba *phba,
+                  struct ulp_bde64 *bpl, uint32_t size,
+                  int nocopydata)
+{
+       struct lpfc_dmabufext *mlist = NULL;
+       struct lpfc_dmabufext *dmp;
+       int cnt, offset = 0, i = 0;
+       struct pci_dev *pcidev;
+
+       pcidev = phba->pcidev;
+
+       while (size) {
+               /* We get chunks of 4K */
+               if (size > BUF_SZ_4K)
+                       cnt = BUF_SZ_4K;
+               else
+                       cnt = size;
+
+               /* allocate struct lpfc_dmabufext buffer header */
+               dmp = kmalloc(sizeof(struct lpfc_dmabufext), GFP_KERNEL);
+               if (!dmp)
+                       goto out;
+
+               INIT_LIST_HEAD(&dmp->dma.list);
+
+               /* Queue it to a linked list */
+               if (mlist)
+                       list_add_tail(&dmp->dma.list, &mlist->dma.list);
+               else
+                       mlist = dmp;
+
+               /* allocate buffer */
+               dmp->dma.virt = dma_alloc_coherent(&pcidev->dev,
+                                                  cnt,
+                                                  &(dmp->dma.phys),
+                                                  GFP_KERNEL);
+
+               if (!dmp->dma.virt)
+                       goto out;
+
+               dmp->size = cnt;
+
+               if (nocopydata) {
+                       bpl->tus.f.bdeFlags = 0;
+                       pci_dma_sync_single_for_device(phba->pcidev,
+                               dmp->dma.phys, LPFC_BPL_SIZE, PCI_DMA_TODEVICE);
+
+               } else {
+                       memset((uint8_t *)dmp->dma.virt, 0, cnt);
+                       bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
+               }
+
+               /* build buffer ptr list for IOCB */
+               bpl->addrLow = le32_to_cpu(putPaddrLow(dmp->dma.phys));
+               bpl->addrHigh = le32_to_cpu(putPaddrHigh(dmp->dma.phys));
+               bpl->tus.f.bdeSize = (ushort) cnt;
+               bpl->tus.w = le32_to_cpu(bpl->tus.w);
+               bpl++;
+
+               i++;
+               offset += cnt;
+               size -= cnt;
+       }
+
+       mlist->flag = i;
+       return mlist;
+out:
+       diag_cmd_data_free(phba, mlist);
+       return NULL;
+}
+
+/**
+ * lpfcdiag_loop_post_rxbufs - post the receive buffers for an unsol CT cmd
+ * @phba: Pointer to HBA context object
+ * @rxxri: Receive exchange id
+ * @len: Number of data bytes
+ *
+ * This function allocates and posts a data buffer of sufficient size to receive
+ * an unsolicted CT command.
+ **/
+static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri,
+                            size_t len)
+{
+       struct lpfc_sli *psli = &phba->sli;
+       struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
+       struct lpfc_iocbq *cmdiocbq;
+       IOCB_t *cmd = NULL;
+       struct list_head head, *curr, *next;
+       struct lpfc_dmabuf *rxbmp;
+       struct lpfc_dmabuf *dmp;
+       struct lpfc_dmabuf *mp[2] = {NULL, NULL};
+       struct ulp_bde64 *rxbpl = NULL;
+       uint32_t num_bde;
+       struct lpfc_dmabufext *rxbuffer = NULL;
+       int ret_val = 0;
+       int iocb_stat;
+       int i = 0;
+
+       cmdiocbq = lpfc_sli_get_iocbq(phba);
+       rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+       if (rxbmp != NULL) {
+               rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
+               if (rxbmp->virt) {
+                       INIT_LIST_HEAD(&rxbmp->list);
+                       rxbpl = (struct ulp_bde64 *) rxbmp->virt;
+                       rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0);
+               }
+       }
+
+       if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer) {
+               ret_val = -ENOMEM;
+               goto err_post_rxbufs_exit;
+       }
+
+       /* Queue buffers for the receive exchange */
+       num_bde = (uint32_t)rxbuffer->flag;
+       dmp = &rxbuffer->dma;
+
+       cmd = &cmdiocbq->iocb;
+       i = 0;
+
+       INIT_LIST_HEAD(&head);
+       list_add_tail(&head, &dmp->list);
+       list_for_each_safe(curr, next, &head) {
+               mp[i] = list_entry(curr, struct lpfc_dmabuf, list);
+               list_del(curr);
+
+               if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+                       mp[i]->buffer_tag = lpfc_sli_get_buffer_tag(phba);
+                       cmd->un.quexri64cx.buff.bde.addrHigh =
+                               putPaddrHigh(mp[i]->phys);
+                       cmd->un.quexri64cx.buff.bde.addrLow =
+                               putPaddrLow(mp[i]->phys);
+                       cmd->un.quexri64cx.buff.bde.tus.f.bdeSize =
+                               ((struct lpfc_dmabufext *)mp[i])->size;
+                       cmd->un.quexri64cx.buff.buffer_tag = mp[i]->buffer_tag;
+                       cmd->ulpCommand = CMD_QUE_XRI64_CX;
+                       cmd->ulpPU = 0;
+                       cmd->ulpLe = 1;
+                       cmd->ulpBdeCount = 1;
+                       cmd->unsli3.que_xri64cx_ext_words.ebde_count = 0;
+
+               } else {
+                       cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys);
+                       cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys);
+                       cmd->un.cont64[i].tus.f.bdeSize =
+                               ((struct lpfc_dmabufext *)mp[i])->size;
+                                       cmd->ulpBdeCount = ++i;
+
+                       if ((--num_bde > 0) && (i < 2))
+                               continue;
+
+                       cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX;
+                       cmd->ulpLe = 1;
+               }
+
+               cmd->ulpClass = CLASS3;
+               cmd->ulpContext = rxxri;
+
+               iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq,
+                                               0);
+               if (iocb_stat == IOCB_ERROR) {
+                       diag_cmd_data_free(phba,
+                               (struct lpfc_dmabufext *)mp[0]);
+                       if (mp[1])
+                               diag_cmd_data_free(phba,
+                                         (struct lpfc_dmabufext *)mp[1]);
+                       dmp = list_entry(next, struct lpfc_dmabuf, list);
+                       ret_val = -EIO;
+                       goto err_post_rxbufs_exit;
+               }
+
+               lpfc_sli_ringpostbuf_put(phba, pring, mp[0]);
+               if (mp[1]) {
+                       lpfc_sli_ringpostbuf_put(phba, pring, mp[1]);
+                       mp[1] = NULL;
+               }
+
+               /* The iocb was freed by lpfc_sli_issue_iocb */
+               cmdiocbq = lpfc_sli_get_iocbq(phba);
+               if (!cmdiocbq) {
+                       dmp = list_entry(next, struct lpfc_dmabuf, list);
+                       ret_val = -EIO;
+                       goto err_post_rxbufs_exit;
+               }
+
+               cmd = &cmdiocbq->iocb;
+               i = 0;
+       }
+       list_del(&head);
+
+err_post_rxbufs_exit:
+
+       if (rxbmp) {
+               if (rxbmp->virt)
+                       lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys);
+               kfree(rxbmp);
+       }
+
+       if (cmdiocbq)
+               lpfc_sli_release_iocbq(phba, cmdiocbq);
+       return ret_val;
+}
+
+/**
+ * lpfc_bsg_diag_loopback_run - run loopback on a port by issue ct cmd to itself
+ * @job: LPFC_BSG_VENDOR_DIAG_TEST fc_bsg_job
+ *
+ * This function receives a user data buffer to be transmitted and received on
+ * the same port, the link must be up and in loopback mode prior
+ * to being called.
+ * 1. A kernel buffer is allocated to copy the user data into.
+ * 2. The port registers with "itself".
+ * 3. The transmit and receive exchange ids are obtained.
+ * 4. The receive exchange id is posted.
+ * 5. A new els loopback event is created.
+ * 6. The command and response iocbs are allocated.
+ * 7. The cmd iocb FsType is set to elx loopback and the CmdRsp to looppback.
+ *
+ * This function is meant to be called n times while the port is in loopback
+ * so it is the apps responsibility to issue a reset to take the port out
+ * of loopback mode.
+ **/
+static int
+lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
+{
+       struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
+       struct lpfc_hba *phba = vport->phba;
+       struct diag_mode_test *diag_mode;
+       struct lpfc_bsg_event *evt;
+       struct event_data *evdat;
+       struct lpfc_sli *psli = &phba->sli;
+       uint32_t size;
+       uint32_t full_size;
+       size_t segment_len = 0, segment_offset = 0, current_offset = 0;
+       uint16_t rpi = 0;
+       struct lpfc_iocbq *cmdiocbq, *rspiocbq;
+       IOCB_t *cmd, *rsp;
+       struct lpfc_sli_ct_request *ctreq;
+       struct lpfc_dmabuf *txbmp;
+       struct ulp_bde64 *txbpl = NULL;
+       struct lpfc_dmabufext *txbuffer = NULL;
+       struct list_head head;
+       struct lpfc_dmabuf  *curr;
+       uint16_t txxri, rxxri;
+       uint32_t num_bde;
+       uint8_t *ptr = NULL, *rx_databuf = NULL;
+       int rc = 0;
+       int time_left;
+       int iocb_stat;
+       unsigned long flags;
+       void *dataout = NULL;
+       uint32_t total_mem;
+
+       /* in case no data is returned return just the return code */
+       job->reply->reply_payload_rcv_len = 0;
+
+       if (job->request_len <
+           sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_test)) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+                               "2739 Received DIAG TEST request below minimum "
+                               "size\n");
+               rc = -EINVAL;
+               goto loopback_test_exit;
+       }
+
+       if (job->request_payload.payload_len !=
+               job->reply_payload.payload_len) {
+               rc = -EINVAL;
+               goto loopback_test_exit;
+       }
+
+       diag_mode = (struct diag_mode_test *)
+               job->request->rqst_data.h_vendor.vendor_cmd;
+
+       if ((phba->link_state == LPFC_HBA_ERROR) ||
+           (psli->sli_flag & LPFC_BLOCK_MGMT_IO) ||
+           (!(psli->sli_flag & LPFC_SLI_ACTIVE))) {
+               rc = -EACCES;
+               goto loopback_test_exit;
+       }
+
+       if (!lpfc_is_link_up(phba) || !(phba->link_flag & LS_LOOPBACK_MODE)) {
+               rc = -EACCES;
+               goto loopback_test_exit;
+       }
+
+       size = job->request_payload.payload_len;
+       full_size = size + ELX_LOOPBACK_HEADER_SZ; /* plus the header */
+
+       if ((size == 0) || (size > 80 * BUF_SZ_4K)) {
+               rc = -ERANGE;
+               goto loopback_test_exit;
+       }
+
+       if (full_size >= BUF_SZ_4K) {
+               /*
+                * Allocate memory for ioctl data. If buffer is bigger than 64k,
+                * then we allocate 64k and re-use that buffer over and over to
+                * xfer the whole block. This is because Linux kernel has a
+                * problem allocating more than 120k of kernel space memory. Saw
+                * problem with GET_FCPTARGETMAPPING...
+                */
+               if (size <= (64 * 1024))
+                       total_mem = full_size;
+               else
+                       total_mem = 64 * 1024;
+       } else
+               /* Allocate memory for ioctl data */
+               total_mem = BUF_SZ_4K;
+
+       dataout = kmalloc(total_mem, GFP_KERNEL);
+       if (dataout == NULL) {
+               rc = -ENOMEM;
+               goto loopback_test_exit;
+       }
+
+       ptr = dataout;
+       ptr += ELX_LOOPBACK_HEADER_SZ;
+       sg_copy_to_buffer(job->request_payload.sg_list,
+                               job->request_payload.sg_cnt,
+                               ptr, size);
+       rc = lpfcdiag_loop_self_reg(phba, &rpi);
+       if (rc)
+               goto loopback_test_exit;
+
+       rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri);
+       if (rc) {
+               lpfcdiag_loop_self_unreg(phba, rpi);
+               goto loopback_test_exit;
+       }
+
+       rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size);
+       if (rc) {
+               lpfcdiag_loop_self_unreg(phba, rpi);
+               goto loopback_test_exit;
+       }
+
+       evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid,
+                               SLI_CT_ELX_LOOPBACK);
+       if (!evt) {
+               lpfcdiag_loop_self_unreg(phba, rpi);
+               rc = -ENOMEM;
+               goto loopback_test_exit;
+       }
+
+       spin_lock_irqsave(&phba->ct_ev_lock, flags);
+       list_add(&evt->node, &phba->ct_ev_waiters);
+       lpfc_bsg_event_ref(evt);
+       spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+       cmdiocbq = lpfc_sli_get_iocbq(phba);
+       rspiocbq = lpfc_sli_get_iocbq(phba);
+       txbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+
+       if (txbmp) {
+               txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys);
+               if (txbmp->virt) {
+                       INIT_LIST_HEAD(&txbmp->list);
+                       txbpl = (struct ulp_bde64 *) txbmp->virt;
+                       txbuffer = diag_cmd_data_alloc(phba,
+                                                       txbpl, full_size, 0);
+               }
+       }
+
+       if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer ||
+               !txbmp->virt) {
+               rc = -ENOMEM;
+               goto err_loopback_test_exit;
+       }
+
+       cmd = &cmdiocbq->iocb;
+       rsp = &rspiocbq->iocb;
+
+       INIT_LIST_HEAD(&head);
+       list_add_tail(&head, &txbuffer->dma.list);
+       list_for_each_entry(curr, &head, list) {
+               segment_len = ((struct lpfc_dmabufext *)curr)->size;
+               if (current_offset == 0) {
+                       ctreq = curr->virt;
+                       memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ);
+                       ctreq->RevisionId.bits.Revision = SLI_CT_REVISION;
+                       ctreq->RevisionId.bits.InId = 0;
+                       ctreq->FsType = SLI_CT_ELX_LOOPBACK;
+                       ctreq->FsSubType = 0;
+                       ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_DATA;
+                       ctreq->CommandResponse.bits.Size   = size;
+                       segment_offset = ELX_LOOPBACK_HEADER_SZ;
+               } else
+                       segment_offset = 0;
+
+               BUG_ON(segment_offset >= segment_len);
+               memcpy(curr->virt + segment_offset,
+                       ptr + current_offset,
+                       segment_len - segment_offset);
+
+               current_offset += segment_len - segment_offset;
+               BUG_ON(current_offset > size);
+       }
+       list_del(&head);
+
+       /* Build the XMIT_SEQUENCE iocb */
+
+       num_bde = (uint32_t)txbuffer->flag;
+
+       cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(txbmp->phys);
+       cmd->un.xseq64.bdl.addrLow = putPaddrLow(txbmp->phys);
+       cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
+       cmd->un.xseq64.bdl.bdeSize = (num_bde * sizeof(struct ulp_bde64));
+
+       cmd->un.xseq64.w5.hcsw.Fctl = (LS | LA);
+       cmd->un.xseq64.w5.hcsw.Dfctl = 0;
+       cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL;
+       cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT;
+
+       cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX;
+       cmd->ulpBdeCount = 1;
+       cmd->ulpLe = 1;
+       cmd->ulpClass = CLASS3;
+       cmd->ulpContext = txxri;
+
+       cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
+       cmdiocbq->vport = phba->pport;
+
+       iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
+                                            rspiocbq, (phba->fc_ratov * 2) +
+                                            LPFC_DRVR_TIMEOUT);
+
+       if ((iocb_stat != IOCB_SUCCESS) || (rsp->ulpStatus != IOCB_SUCCESS)) {
+               rc = -EIO;
+               goto err_loopback_test_exit;
+       }
+
+       evt->waiting = 1;
+       time_left = wait_event_interruptible_timeout(
+               evt->wq, !list_empty(&evt->events_to_see),
+               ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ);
+       evt->waiting = 0;
+       if (list_empty(&evt->events_to_see))
+               rc = (time_left) ? -EINTR : -ETIMEDOUT;
+       else {
+               spin_lock_irqsave(&phba->ct_ev_lock, flags);
+               list_move(evt->events_to_see.prev, &evt->events_to_get);
+               evdat = list_entry(evt->events_to_get.prev,
+                                  typeof(*evdat), node);
+               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+               rx_databuf = evdat->data;
+               if (evdat->len != full_size) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+                               "1603 Loopback test did not receive expected "
+                               "data length. actual length 0x%x expected "
+                               "length 0x%x\n",
+                               evdat->len, full_size);
+                       rc = -EIO;
+               } else if (rx_databuf == NULL)
+                       rc = -EIO;
+               else {
+                       rc = IOCB_SUCCESS;
+                       /* skip over elx loopback header */
+                       rx_databuf += ELX_LOOPBACK_HEADER_SZ;
+                       job->reply->reply_payload_rcv_len =
+                               sg_copy_from_buffer(job->reply_payload.sg_list,
+                                                   job->reply_payload.sg_cnt,
+                                                   rx_databuf, size);
+                       job->reply->reply_payload_rcv_len = size;
+               }
+       }
+
+err_loopback_test_exit:
+       lpfcdiag_loop_self_unreg(phba, rpi);
+
+       spin_lock_irqsave(&phba->ct_ev_lock, flags);
+       lpfc_bsg_event_unref(evt); /* release ref */
+       lpfc_bsg_event_unref(evt); /* delete */
+       spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+       if (cmdiocbq != NULL)
+               lpfc_sli_release_iocbq(phba, cmdiocbq);
+
+       if (rspiocbq != NULL)
+               lpfc_sli_release_iocbq(phba, rspiocbq);
+
+       if (txbmp != NULL) {
+               if (txbpl != NULL) {
+                       if (txbuffer != NULL)
+                               diag_cmd_data_free(phba, txbuffer);
+                       lpfc_mbuf_free(phba, txbmp->virt, txbmp->phys);
+               }
+               kfree(txbmp);
+       }
+
+loopback_test_exit:
+       kfree(dataout);
+       /* make error code available to userspace */
+       job->reply->result = rc;
+       job->dd_data = NULL;
+       /* complete the job back to userspace if no error */
+       if (rc == 0)
+               job->job_done(job);
+       return rc;
+}
+
+/**
+ * lpfc_bsg_get_dfc_rev - process a GET_DFC_REV bsg vendor command
+ * @job: GET_DFC_REV fc_bsg_job
+ **/
+static int
+lpfc_bsg_get_dfc_rev(struct fc_bsg_job *job)
+{
+       struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
+       struct lpfc_hba *phba = vport->phba;
+       struct get_mgmt_rev *event_req;
+       struct get_mgmt_rev_reply *event_reply;
+       int rc = 0;
+
+       if (job->request_len <
+           sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev)) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+                               "2740 Received GET_DFC_REV request below "
+                               "minimum size\n");
+               rc = -EINVAL;
+               goto job_error;
+       }
+
+       event_req = (struct get_mgmt_rev *)
+               job->request->rqst_data.h_vendor.vendor_cmd;
+
+       event_reply = (struct get_mgmt_rev_reply *)
+               job->reply->reply_data.vendor_reply.vendor_rsp;
+
+       if (job->reply_len <
+           sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev_reply)) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+                               "2741 Received GET_DFC_REV reply below "
+                               "minimum size\n");
+               rc = -EINVAL;
+               goto job_error;
+       }
+
+       event_reply->info.a_Major = MANAGEMENT_MAJOR_REV;
+       event_reply->info.a_Minor = MANAGEMENT_MINOR_REV;
+job_error:
+       job->reply->result = rc;
+       if (rc == 0)
+               job->job_done(job);
+       return rc;
+}
+
+/**
+ * lpfc_bsg_issue_mbox_cmpl - lpfc_bsg_issue_mbox mbox completion handler
+ * @phba: Pointer to HBA context object.
+ * @pmboxq: Pointer to mailbox command.
+ *
+ * This is completion handler function for mailbox commands issued from
+ * lpfc_bsg_issue_mbox function. This function is called by the
+ * mailbox event handler function with no lock held. This function
+ * will wake up thread waiting on the wait queue pointed by context1
+ * of the mailbox.
+ **/
+void
+lpfc_bsg_issue_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
+{
+       struct bsg_job_data *dd_data;
+       struct fc_bsg_job *job;
+       uint32_t size;
+       unsigned long flags;
+       uint8_t *pmb, *pmb_buf;
+
+       spin_lock_irqsave(&phba->ct_ev_lock, flags);
+       dd_data = pmboxq->context1;
+       /* job already timed out? */
+       if (!dd_data) {
+               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+               return;
+       }
+
+       /*
+        * The outgoing buffer is readily referred from the dma buffer,
+        * just need to get header part from mailboxq structure.
+        */
+       pmb = (uint8_t *)&pmboxq->u.mb;
+       pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb;
+       memcpy(pmb_buf, pmb, sizeof(MAILBOX_t));
+
+       job = dd_data->context_un.mbox.set_job;
+       if (job) {
+               size = job->reply_payload.payload_len;
+               job->reply->reply_payload_rcv_len =
+                       sg_copy_from_buffer(job->reply_payload.sg_list,
+                                           job->reply_payload.sg_cnt,
+                                           pmb_buf, size);
+               /* need to hold the lock until we set job->dd_data to NULL
+                * to hold off the timeout handler returning to the mid-layer
+                * while we are still processing the job.
+                */
+               job->dd_data = NULL;
+               dd_data->context_un.mbox.set_job = NULL;
+               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+       } else {
+               dd_data->context_un.mbox.set_job = NULL;
+               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+       }
+
+       mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool);
+       lpfc_bsg_dma_page_free(phba, dd_data->context_un.mbox.dmabuffers);
+       kfree(dd_data);
+
+       if (job) {
+               job->reply->result = 0;
+               job->job_done(job);
+       }
+       return;
+}
+
+/**
+ * lpfc_bsg_check_cmd_access - test for a supported mailbox command
+ * @phba: Pointer to HBA context object.
+ * @mb: Pointer to a mailbox object.
+ * @vport: Pointer to a vport object.
+ *
+ * Some commands require the port to be offline, some may not be called from
+ * the application.
+ **/
+static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,
+       MAILBOX_t *mb, struct lpfc_vport *vport)
+{
+       /* return negative error values for bsg job */
+       switch (mb->mbxCommand) {
+       /* Offline only */
+       case MBX_INIT_LINK:
+       case MBX_DOWN_LINK:
+       case MBX_CONFIG_LINK:
+       case MBX_CONFIG_RING:
+       case MBX_RESET_RING:
+       case MBX_UNREG_LOGIN:
+       case MBX_CLEAR_LA:
+       case MBX_DUMP_CONTEXT:
+       case MBX_RUN_DIAGS:
+       case MBX_RESTART:
+       case MBX_SET_MASK:
+               if (!(vport->fc_flag & FC_OFFLINE_MODE)) {
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+                               "2743 Command 0x%x is illegal in on-line "
+                               "state\n",
+                               mb->mbxCommand);
+                       return -EPERM;
+               }
+       case MBX_WRITE_NV:
+       case MBX_WRITE_VPARMS:
+       case MBX_LOAD_SM:
+       case MBX_READ_NV:
+       case MBX_READ_CONFIG:
+       case MBX_READ_RCONFIG:
+       case MBX_READ_STATUS:
+       case MBX_READ_XRI:
+       case MBX_READ_REV:
+       case MBX_READ_LNK_STAT:
+       case MBX_DUMP_MEMORY:
+       case MBX_DOWN_LOAD:
+       case MBX_UPDATE_CFG:
+       case MBX_KILL_BOARD:
+       case MBX_LOAD_AREA:
+       case MBX_LOAD_EXP_ROM:
+       case MBX_BEACON:
+       case MBX_DEL_LD_ENTRY:
+       case MBX_SET_DEBUG:
+       case MBX_WRITE_WWN:
+       case MBX_SLI4_CONFIG:
+       case MBX_READ_EVENT_LOG:
+       case MBX_READ_EVENT_LOG_STATUS:
+       case MBX_WRITE_EVENT_LOG:
+       case MBX_PORT_CAPABILITIES:
+       case MBX_PORT_IOV_CONTROL:
+       case MBX_RUN_BIU_DIAG64:
+               break;
+       case MBX_SET_VARIABLE:
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                       "1226 mbox: set_variable 0x%x, 0x%x\n",
+                       mb->un.varWords[0],
+                       mb->un.varWords[1]);
+               if ((mb->un.varWords[0] == SETVAR_MLOMNT)
+                       && (mb->un.varWords[1] == 1)) {
+                       phba->wait_4_mlo_maint_flg = 1;
+               } else if (mb->un.varWords[0] == SETVAR_MLORST) {
+                       phba->link_flag &= ~LS_LOOPBACK_MODE;
+                       phba->fc_topology = LPFC_TOPOLOGY_PT_PT;
+               }
+               break;
+       case MBX_READ_SPARM64:
+       case MBX_READ_TOPOLOGY:
+       case MBX_REG_LOGIN:
+       case MBX_REG_LOGIN64:
+       case MBX_CONFIG_PORT:
+       case MBX_RUN_BIU_DIAG:
+       default:
+               lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+                       "2742 Unknown Command 0x%x\n",
+                       mb->mbxCommand);
+               return -EPERM;
+       }
+
+       return 0; /* ok */
+}
+
+/**
+ * lpfc_bsg_mbox_ext_cleanup - clean up context of multi-buffer mbox session
+ * @phba: Pointer to HBA context object.
+ *
+ * This is routine clean up and reset BSG handling of multi-buffer mbox
+ * command session.
+ **/
+static void
+lpfc_bsg_mbox_ext_session_reset(struct lpfc_hba *phba)
+{
+       if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE)
+               return;
+
+       /* free all memory, including dma buffers */
+       lpfc_bsg_dma_page_list_free(phba,
+                                   &phba->mbox_ext_buf_ctx.ext_dmabuf_list);
+       lpfc_bsg_dma_page_free(phba, phba->mbox_ext_buf_ctx.mbx_dmabuf);
+       /* multi-buffer write mailbox command pass-through complete */
+       memset((char *)&phba->mbox_ext_buf_ctx, 0,
+              sizeof(struct lpfc_mbox_ext_buf_ctx));
+       INIT_LIST_HEAD(&phba->mbox_ext_buf_ctx.ext_dmabuf_list);
+
+       return;
+}
+
+/**
+ * lpfc_bsg_issue_mbox_ext_handle_job - job handler for multi-buffer mbox cmpl
+ * @phba: Pointer to HBA context object.
+ * @pmboxq: Pointer to mailbox command.
+ *
+ * This is routine handles BSG job for mailbox commands completions with
+ * multiple external buffers.
+ **/
+static struct fc_bsg_job *
+lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
+{
+       struct bsg_job_data *dd_data;
+       struct fc_bsg_job *job;
+       uint8_t *pmb, *pmb_buf;
+       unsigned long flags;
+       uint32_t size;
+       int rc = 0;
+
+       spin_lock_irqsave(&phba->ct_ev_lock, flags);
+       dd_data = pmboxq->context1;
+       /* has the job already timed out? */
+       if (!dd_data) {
+               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+               job = NULL;
+               goto job_done_out;
+       }
+
+       /*
+        * The outgoing buffer is readily referred from the dma buffer,
+        * just need to get header part from mailboxq structure.
+        */
+       pmb = (uint8_t *)&pmboxq->u.mb;
+       pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb;
+       memcpy(pmb_buf, pmb, sizeof(MAILBOX_t));
+
+       job = dd_data->context_un.mbox.set_job;
+       if (job) {
+               size = job->reply_payload.payload_len;
+               job->reply->reply_payload_rcv_len =
+                       sg_copy_from_buffer(job->reply_payload.sg_list,
+                                           job->reply_payload.sg_cnt,
+                                           pmb_buf, size);
+               /* result for successful */
+               job->reply->result = 0;
+               job->dd_data = NULL;
+               /* need to hold the lock util we set job->dd_data to NULL
+                * to hold off the timeout handler from midlayer to take
+                * any action.
+                */
+               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                               "2937 SLI_CONFIG ext-buffer maibox command "
+                               "(x%x/x%x) complete bsg job done, bsize:%d\n",
+                               phba->mbox_ext_buf_ctx.nembType,
+                               phba->mbox_ext_buf_ctx.mboxType, size);
+       } else
+               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+job_done_out:
+       if (!job)
+               lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+                               "2938 SLI_CONFIG ext-buffer maibox "
+                               "command (x%x/x%x) failure, rc:x%x\n",
+                               phba->mbox_ext_buf_ctx.nembType,
+                               phba->mbox_ext_buf_ctx.mboxType, rc);
+       /* state change */
+       phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_DONE;
+       kfree(dd_data);
+
+       return job;
+}
+
+/**
+ * lpfc_bsg_issue_read_mbox_ext_cmpl - compl handler for multi-buffer read mbox
+ * @phba: Pointer to HBA context object.
+ * @pmboxq: Pointer to mailbox command.
+ *
+ * This is completion handler function for mailbox read commands with multiple
+ * external buffers.
+ **/
+static void
+lpfc_bsg_issue_read_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
+{
+       struct fc_bsg_job *job;
+
+       /* handle the BSG job with mailbox command */
+       if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_ABTS)
+               pmboxq->u.mb.mbxStatus = MBXERR_ERROR;
 
-               lpfc_sli_ringpostbuf_put(phba, pring, mp[0]);
-               if (mp[1]) {
-                       lpfc_sli_ringpostbuf_put(phba, pring, mp[1]);
-                       mp[1] = NULL;
-               }
+       lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                       "2939 SLI_CONFIG ext-buffer rd maibox command "
+                       "complete, ctxState:x%x, mbxStatus:x%x\n",
+                       phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus);
 
-               /* The iocb was freed by lpfc_sli_issue_iocb */
-               cmdiocbq = lpfc_sli_get_iocbq(phba);
-               if (!cmdiocbq) {
-                       dmp = list_entry(next, struct lpfc_dmabuf, list);
-                       ret_val = -EIO;
-                       goto err_post_rxbufs_exit;
-               }
+       job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq);
 
-               cmd = &cmdiocbq->iocb;
-               i = 0;
-       }
-       list_del(&head);
+       if (pmboxq->u.mb.mbxStatus || phba->mbox_ext_buf_ctx.numBuf == 1)
+               lpfc_bsg_mbox_ext_session_reset(phba);
 
-err_post_rxbufs_exit:
+       /* free base driver mailbox structure memory */
+       mempool_free(pmboxq, phba->mbox_mem_pool);
 
-       if (rxbmp) {
-               if (rxbmp->virt)
-                       lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys);
-               kfree(rxbmp);
-       }
+       /* complete the bsg job if we have it */
+       if (job)
+               job->job_done(job);
 
-       if (cmdiocbq)
-               lpfc_sli_release_iocbq(phba, cmdiocbq);
-       return ret_val;
+       return;
 }
 
 /**
- * lpfc_bsg_diag_test - with a port in loopback issues a Ct cmd to itself
- * @job: LPFC_BSG_VENDOR_DIAG_TEST fc_bsg_job
- *
- * This function receives a user data buffer to be transmitted and received on
- * the same port, the link must be up and in loopback mode prior
- * to being called.
- * 1. A kernel buffer is allocated to copy the user data into.
- * 2. The port registers with "itself".
- * 3. The transmit and receive exchange ids are obtained.
- * 4. The receive exchange id is posted.
- * 5. A new els loopback event is created.
- * 6. The command and response iocbs are allocated.
- * 7. The cmd iocb FsType is set to elx loopback and the CmdRsp to looppback.
+ * lpfc_bsg_issue_write_mbox_ext_cmpl - cmpl handler for multi-buffer write mbox
+ * @phba: Pointer to HBA context object.
+ * @pmboxq: Pointer to mailbox command.
  *
- * This function is meant to be called n times while the port is in loopback
- * so it is the apps responsibility to issue a reset to take the port out
- * of loopback mode.
+ * This is completion handler function for mailbox write commands with multiple
+ * external buffers.
  **/
-static int
-lpfc_bsg_diag_test(struct fc_bsg_job *job)
+static void
+lpfc_bsg_issue_write_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
 {
-       struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
-       struct lpfc_hba *phba = vport->phba;
-       struct diag_mode_test *diag_mode;
-       struct lpfc_bsg_event *evt;
-       struct event_data *evdat;
-       struct lpfc_sli *psli = &phba->sli;
-       uint32_t size;
-       uint32_t full_size;
-       size_t segment_len = 0, segment_offset = 0, current_offset = 0;
-       uint16_t rpi = 0;
-       struct lpfc_iocbq *cmdiocbq, *rspiocbq;
-       IOCB_t *cmd, *rsp;
-       struct lpfc_sli_ct_request *ctreq;
-       struct lpfc_dmabuf *txbmp;
-       struct ulp_bde64 *txbpl = NULL;
-       struct lpfc_dmabufext *txbuffer = NULL;
-       struct list_head head;
-       struct lpfc_dmabuf  *curr;
-       uint16_t txxri, rxxri;
-       uint32_t num_bde;
-       uint8_t *ptr = NULL, *rx_databuf = NULL;
-       int rc = 0;
-       int time_left;
-       int iocb_stat;
-       unsigned long flags;
-       void *dataout = NULL;
-       uint32_t total_mem;
+       struct fc_bsg_job *job;
 
-       /* in case no data is returned return just the return code */
-       job->reply->reply_payload_rcv_len = 0;
+       /* handle the BSG job with the mailbox command */
+       if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_ABTS)
+               pmboxq->u.mb.mbxStatus = MBXERR_ERROR;
 
-       if (job->request_len <
-           sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_test)) {
-               lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
-                               "2739 Received DIAG TEST request below minimum "
-                               "size\n");
-               rc = -EINVAL;
-               goto loopback_test_exit;
-       }
+       lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                       "2940 SLI_CONFIG ext-buffer wr maibox command "
+                       "complete, ctxState:x%x, mbxStatus:x%x\n",
+                       phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus);
 
-       if (job->request_payload.payload_len !=
-               job->reply_payload.payload_len) {
-               rc = -EINVAL;
-               goto loopback_test_exit;
-       }
+       job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq);
 
-       diag_mode = (struct diag_mode_test *)
-               job->request->rqst_data.h_vendor.vendor_cmd;
+       /* free all memory, including dma buffers */
+       mempool_free(pmboxq, phba->mbox_mem_pool);
+       lpfc_bsg_mbox_ext_session_reset(phba);
 
-       if ((phba->link_state == LPFC_HBA_ERROR) ||
-           (psli->sli_flag & LPFC_BLOCK_MGMT_IO) ||
-           (!(psli->sli_flag & LPFC_SLI_ACTIVE))) {
-               rc = -EACCES;
-               goto loopback_test_exit;
-       }
+       /* complete the bsg job if we have it */
+       if (job)
+               job->job_done(job);
 
-       if (!lpfc_is_link_up(phba) || !(phba->link_flag & LS_LOOPBACK_MODE)) {
-               rc = -EACCES;
-               goto loopback_test_exit;
-       }
+       return;
+}
 
-       size = job->request_payload.payload_len;
-       full_size = size + ELX_LOOPBACK_HEADER_SZ; /* plus the header */
+static void
+lpfc_bsg_sli_cfg_dma_desc_setup(struct lpfc_hba *phba, enum nemb_type nemb_tp,
+                               uint32_t index, struct lpfc_dmabuf *mbx_dmabuf,
+                               struct lpfc_dmabuf *ext_dmabuf)
+{
+       struct lpfc_sli_config_mbox *sli_cfg_mbx;
+
+       /* pointer to the start of mailbox command */
+       sli_cfg_mbx = (struct lpfc_sli_config_mbox *)mbx_dmabuf->virt;
+
+       if (nemb_tp == nemb_mse) {
+               if (index == 0) {
+                       sli_cfg_mbx->un.sli_config_emb0_subsys.
+                               mse[index].pa_hi =
+                               putPaddrHigh(mbx_dmabuf->phys +
+                                            sizeof(MAILBOX_t));
+                       sli_cfg_mbx->un.sli_config_emb0_subsys.
+                               mse[index].pa_lo =
+                               putPaddrLow(mbx_dmabuf->phys +
+                                           sizeof(MAILBOX_t));
+                       lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                                       "2943 SLI_CONFIG(mse)[%d], "
+                                       "bufLen:%d, addrHi:x%x, addrLo:x%x\n",
+                                       index,
+                                       sli_cfg_mbx->un.sli_config_emb0_subsys.
+                                       mse[index].buf_len,
+                                       sli_cfg_mbx->un.sli_config_emb0_subsys.
+                                       mse[index].pa_hi,
+                                       sli_cfg_mbx->un.sli_config_emb0_subsys.
+                                       mse[index].pa_lo);
+               } else {
+                       sli_cfg_mbx->un.sli_config_emb0_subsys.
+                               mse[index].pa_hi =
+                               putPaddrHigh(ext_dmabuf->phys);
+                       sli_cfg_mbx->un.sli_config_emb0_subsys.
+                               mse[index].pa_lo =
+                               putPaddrLow(ext_dmabuf->phys);
+                       lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                                       "2944 SLI_CONFIG(mse)[%d], "
+                                       "bufLen:%d, addrHi:x%x, addrLo:x%x\n",
+                                       index,
+                                       sli_cfg_mbx->un.sli_config_emb0_subsys.
+                                       mse[index].buf_len,
+                                       sli_cfg_mbx->un.sli_config_emb0_subsys.
+                                       mse[index].pa_hi,
+                                       sli_cfg_mbx->un.sli_config_emb0_subsys.
+                                       mse[index].pa_lo);
+               }
+       } else {
+               if (index == 0) {
+                       sli_cfg_mbx->un.sli_config_emb1_subsys.
+                               hbd[index].pa_hi =
+                               putPaddrHigh(mbx_dmabuf->phys +
+                                            sizeof(MAILBOX_t));
+                       sli_cfg_mbx->un.sli_config_emb1_subsys.
+                               hbd[index].pa_lo =
+                               putPaddrLow(mbx_dmabuf->phys +
+                                           sizeof(MAILBOX_t));
+                       lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                                       "3007 SLI_CONFIG(hbd)[%d], "
+                                       "bufLen:%d, addrHi:x%x, addrLo:x%x\n",
+                               index,
+                               bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len,
+                               &sli_cfg_mbx->un.
+                               sli_config_emb1_subsys.hbd[index]),
+                               sli_cfg_mbx->un.sli_config_emb1_subsys.
+                               hbd[index].pa_hi,
+                               sli_cfg_mbx->un.sli_config_emb1_subsys.
+                               hbd[index].pa_lo);
 
-       if ((size == 0) || (size > 80 * BUF_SZ_4K)) {
-               rc = -ERANGE;
-               goto loopback_test_exit;
+               } else {
+                       sli_cfg_mbx->un.sli_config_emb1_subsys.
+                               hbd[index].pa_hi =
+                               putPaddrHigh(ext_dmabuf->phys);
+                       sli_cfg_mbx->un.sli_config_emb1_subsys.
+                               hbd[index].pa_lo =
+                               putPaddrLow(ext_dmabuf->phys);
+                       lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                                       "3008 SLI_CONFIG(hbd)[%d], "
+                                       "bufLen:%d, addrHi:x%x, addrLo:x%x\n",
+                               index,
+                               bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len,
+                               &sli_cfg_mbx->un.
+                               sli_config_emb1_subsys.hbd[index]),
+                               sli_cfg_mbx->un.sli_config_emb1_subsys.
+                               hbd[index].pa_hi,
+                               sli_cfg_mbx->un.sli_config_emb1_subsys.
+                               hbd[index].pa_lo);
+               }
        }
+       return;
+}
 
-       if (full_size >= BUF_SZ_4K) {
-               /*
-                * Allocate memory for ioctl data. If buffer is bigger than 64k,
-                * then we allocate 64k and re-use that buffer over and over to
-                * xfer the whole block. This is because Linux kernel has a
-                * problem allocating more than 120k of kernel space memory. Saw
-                * problem with GET_FCPTARGETMAPPING...
-                */
-               if (size <= (64 * 1024))
-                       total_mem = full_size;
-               else
-                       total_mem = 64 * 1024;
-       } else
-               /* Allocate memory for ioctl data */
-               total_mem = BUF_SZ_4K;
+/**
+ * lpfc_bsg_sli_cfg_mse_read_cmd_ext - sli_config non-embedded mailbox cmd read
+ * @phba: Pointer to HBA context object.
+ * @mb: Pointer to a BSG mailbox object.
+ * @nemb_tp: Enumerate of non-embedded mailbox command type.
+ * @dmabuff: Pointer to a DMA buffer descriptor.
+ *
+ * This routine performs SLI_CONFIG (0x9B) read mailbox command operation with
+ * non-embedded external bufffers.
+ **/
+static int
+lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
+                             enum nemb_type nemb_tp,
+                             struct lpfc_dmabuf *dmabuf)
+{
+       struct lpfc_sli_config_mbox *sli_cfg_mbx;
+       struct dfc_mbox_req *mbox_req;
+       struct lpfc_dmabuf *curr_dmabuf, *next_dmabuf;
+       uint32_t ext_buf_cnt, ext_buf_index;
+       struct lpfc_dmabuf *ext_dmabuf = NULL;
+       struct bsg_job_data *dd_data = NULL;
+       LPFC_MBOXQ_t *pmboxq = NULL;
+       MAILBOX_t *pmb;
+       uint8_t *pmbx;
+       int rc, i;
 
-       dataout = kmalloc(total_mem, GFP_KERNEL);
-       if (dataout == NULL) {
-               rc = -ENOMEM;
-               goto loopback_test_exit;
-       }
+       mbox_req =
+          (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd;
 
-       ptr = dataout;
-       ptr += ELX_LOOPBACK_HEADER_SZ;
-       sg_copy_to_buffer(job->request_payload.sg_list,
-                               job->request_payload.sg_cnt,
-                               ptr, size);
-       rc = lpfcdiag_loop_self_reg(phba, &rpi);
-       if (rc)
-               goto loopback_test_exit;
+       /* pointer to the start of mailbox command */
+       sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt;
 
-       rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri);
-       if (rc) {
-               lpfcdiag_loop_self_unreg(phba, rpi);
-               goto loopback_test_exit;
+       if (nemb_tp == nemb_mse) {
+               ext_buf_cnt = bsg_bf_get(lpfc_mbox_hdr_mse_cnt,
+                       &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr);
+               if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_MSE) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+                                       "2945 Handled SLI_CONFIG(mse) rd, "
+                                       "ext_buf_cnt(%d) out of range(%d)\n",
+                                       ext_buf_cnt,
+                                       LPFC_MBX_SLI_CONFIG_MAX_MSE);
+                       rc = -ERANGE;
+                       goto job_error;
+               }
+               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                               "2941 Handled SLI_CONFIG(mse) rd, "
+                               "ext_buf_cnt:%d\n", ext_buf_cnt);
+       } else {
+               /* sanity check on interface type for support */
+               if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+                   LPFC_SLI_INTF_IF_TYPE_2) {
+                       rc = -ENODEV;
+                       goto job_error;
+               }
+               /* nemb_tp == nemb_hbd */
+               ext_buf_cnt = sli_cfg_mbx->un.sli_config_emb1_subsys.hbd_count;
+               if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_HBD) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+                                       "2946 Handled SLI_CONFIG(hbd) rd, "
+                                       "ext_buf_cnt(%d) out of range(%d)\n",
+                                       ext_buf_cnt,
+                                       LPFC_MBX_SLI_CONFIG_MAX_HBD);
+                       rc = -ERANGE;
+                       goto job_error;
+               }
+               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                               "2942 Handled SLI_CONFIG(hbd) rd, "
+                               "ext_buf_cnt:%d\n", ext_buf_cnt);
        }
 
-       rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size);
-       if (rc) {
-               lpfcdiag_loop_self_unreg(phba, rpi);
-               goto loopback_test_exit;
+       /* reject non-embedded mailbox command with none external buffer */
+       if (ext_buf_cnt == 0) {
+               rc = -EPERM;
+               goto job_error;
+       } else if (ext_buf_cnt > 1) {
+               /* additional external read buffers */
+               for (i = 1; i < ext_buf_cnt; i++) {
+                       ext_dmabuf = lpfc_bsg_dma_page_alloc(phba);
+                       if (!ext_dmabuf) {
+                               rc = -ENOMEM;
+                               goto job_error;
+                       }
+                       list_add_tail(&ext_dmabuf->list,
+                                     &phba->mbox_ext_buf_ctx.ext_dmabuf_list);
+               }
        }
 
-       evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid,
-                               SLI_CT_ELX_LOOPBACK);
-       if (!evt) {
-               lpfcdiag_loop_self_unreg(phba, rpi);
+       /* bsg tracking structure */
+       dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
+       if (!dd_data) {
                rc = -ENOMEM;
-               goto loopback_test_exit;
+               goto job_error;
        }
 
-       spin_lock_irqsave(&phba->ct_ev_lock, flags);
-       list_add(&evt->node, &phba->ct_ev_waiters);
-       lpfc_bsg_event_ref(evt);
-       spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
-
-       cmdiocbq = lpfc_sli_get_iocbq(phba);
-       rspiocbq = lpfc_sli_get_iocbq(phba);
-       txbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+       /* mailbox command structure for base driver */
+       pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!pmboxq) {
+               rc = -ENOMEM;
+               goto job_error;
+       }
+       memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
 
-       if (txbmp) {
-               txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys);
-               if (txbmp->virt) {
-                       INIT_LIST_HEAD(&txbmp->list);
-                       txbpl = (struct ulp_bde64 *) txbmp->virt;
-                       txbuffer = diag_cmd_data_alloc(phba,
-                                                       txbpl, full_size, 0);
+       /* for the first external buffer */
+       lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 0, dmabuf, dmabuf);
+
+       /* for the rest of external buffer descriptors if any */
+       if (ext_buf_cnt > 1) {
+               ext_buf_index = 1;
+               list_for_each_entry_safe(curr_dmabuf, next_dmabuf,
+                               &phba->mbox_ext_buf_ctx.ext_dmabuf_list, list) {
+                       lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp,
+                                               ext_buf_index, dmabuf,
+                                               curr_dmabuf);
+                       ext_buf_index++;
                }
        }
 
-       if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer ||
-               !txbmp->virt) {
-               rc = -ENOMEM;
-               goto err_loopback_test_exit;
+       /* construct base driver mbox command */
+       pmb = &pmboxq->u.mb;
+       pmbx = (uint8_t *)dmabuf->virt;
+       memcpy(pmb, pmbx, sizeof(*pmb));
+       pmb->mbxOwner = OWN_HOST;
+       pmboxq->vport = phba->pport;
+
+       /* multi-buffer handling context */
+       phba->mbox_ext_buf_ctx.nembType = nemb_tp;
+       phba->mbox_ext_buf_ctx.mboxType = mbox_rd;
+       phba->mbox_ext_buf_ctx.numBuf = ext_buf_cnt;
+       phba->mbox_ext_buf_ctx.mbxTag = mbox_req->extMboxTag;
+       phba->mbox_ext_buf_ctx.seqNum = mbox_req->extSeqNum;
+       phba->mbox_ext_buf_ctx.mbx_dmabuf = dmabuf;
+
+       /* callback for multi-buffer read mailbox command */
+       pmboxq->mbox_cmpl = lpfc_bsg_issue_read_mbox_ext_cmpl;
+
+       /* context fields to callback function */
+       pmboxq->context1 = dd_data;
+       dd_data->type = TYPE_MBOX;
+       dd_data->context_un.mbox.pmboxq = pmboxq;
+       dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx;
+       dd_data->context_un.mbox.set_job = job;
+       job->dd_data = dd_data;
+
+       /* state change */
+       phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT;
+
+       rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
+       if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) {
+               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                               "2947 Issued SLI_CONFIG ext-buffer "
+                               "maibox command, rc:x%x\n", rc);
+               return 1;
        }
+       lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+                       "2948 Failed to issue SLI_CONFIG ext-buffer "
+                       "maibox command, rc:x%x\n", rc);
+       rc = -EPIPE;
 
-       cmd = &cmdiocbq->iocb;
-       rsp = &rspiocbq->iocb;
+job_error:
+       if (pmboxq)
+               mempool_free(pmboxq, phba->mbox_mem_pool);
+       lpfc_bsg_dma_page_list_free(phba,
+                                   &phba->mbox_ext_buf_ctx.ext_dmabuf_list);
+       kfree(dd_data);
+       phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_IDLE;
+       return rc;
+}
 
-       INIT_LIST_HEAD(&head);
-       list_add_tail(&head, &txbuffer->dma.list);
-       list_for_each_entry(curr, &head, list) {
-               segment_len = ((struct lpfc_dmabufext *)curr)->size;
-               if (current_offset == 0) {
-                       ctreq = curr->virt;
-                       memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ);
-                       ctreq->RevisionId.bits.Revision = SLI_CT_REVISION;
-                       ctreq->RevisionId.bits.InId = 0;
-                       ctreq->FsType = SLI_CT_ELX_LOOPBACK;
-                       ctreq->FsSubType = 0;
-                       ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_DATA;
-                       ctreq->CommandResponse.bits.Size   = size;
-                       segment_offset = ELX_LOOPBACK_HEADER_SZ;
-               } else
-                       segment_offset = 0;
+/**
+ * lpfc_bsg_sli_cfg_write_cmd_ext - sli_config non-embedded mailbox cmd write
+ * @phba: Pointer to HBA context object.
+ * @mb: Pointer to a BSG mailbox object.
+ * @dmabuff: Pointer to a DMA buffer descriptor.
+ *
+ * This routine performs SLI_CONFIG (0x9B) write mailbox command operation with
+ * non-embedded external bufffers.
+ **/
+static int
+lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
+                              enum nemb_type nemb_tp,
+                              struct lpfc_dmabuf *dmabuf)
+{
+       struct dfc_mbox_req *mbox_req;
+       struct lpfc_sli_config_mbox *sli_cfg_mbx;
+       uint32_t ext_buf_cnt;
+       struct bsg_job_data *dd_data = NULL;
+       LPFC_MBOXQ_t *pmboxq = NULL;
+       MAILBOX_t *pmb;
+       uint8_t *mbx;
+       int rc = 0, i;
+
+       mbox_req =
+          (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd;
 
-               BUG_ON(segment_offset >= segment_len);
-               memcpy(curr->virt + segment_offset,
-                       ptr + current_offset,
-                       segment_len - segment_offset);
+       /* pointer to the start of mailbox command */
+       sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt;
 
-               current_offset += segment_len - segment_offset;
-               BUG_ON(current_offset > size);
+       if (nemb_tp == nemb_mse) {
+               ext_buf_cnt = bsg_bf_get(lpfc_mbox_hdr_mse_cnt,
+                       &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr);
+               if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_MSE) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+                                       "2953 Handled SLI_CONFIG(mse) wr, "
+                                       "ext_buf_cnt(%d) out of range(%d)\n",
+                                       ext_buf_cnt,
+                                       LPFC_MBX_SLI_CONFIG_MAX_MSE);
+                       return -ERANGE;
+               }
+               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                               "2949 Handled SLI_CONFIG(mse) wr, "
+                               "ext_buf_cnt:%d\n", ext_buf_cnt);
+       } else {
+               /* sanity check on interface type for support */
+               if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+                   LPFC_SLI_INTF_IF_TYPE_2)
+                       return -ENODEV;
+               /* nemb_tp == nemb_hbd */
+               ext_buf_cnt = sli_cfg_mbx->un.sli_config_emb1_subsys.hbd_count;
+               if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_HBD) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+                                       "2954 Handled SLI_CONFIG(hbd) wr, "
+                                       "ext_buf_cnt(%d) out of range(%d)\n",
+                                       ext_buf_cnt,
+                                       LPFC_MBX_SLI_CONFIG_MAX_HBD);
+                       return -ERANGE;
+               }
+               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                               "2950 Handled SLI_CONFIG(hbd) wr, "
+                               "ext_buf_cnt:%d\n", ext_buf_cnt);
        }
-       list_del(&head);
 
-       /* Build the XMIT_SEQUENCE iocb */
-
-       num_bde = (uint32_t)txbuffer->flag;
+       if (ext_buf_cnt == 0)
+               return -EPERM;
 
-       cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(txbmp->phys);
-       cmd->un.xseq64.bdl.addrLow = putPaddrLow(txbmp->phys);
-       cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
-       cmd->un.xseq64.bdl.bdeSize = (num_bde * sizeof(struct ulp_bde64));
+       /* for the first external buffer */
+       lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 0, dmabuf, dmabuf);
 
-       cmd->un.xseq64.w5.hcsw.Fctl = (LS | LA);
-       cmd->un.xseq64.w5.hcsw.Dfctl = 0;
-       cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL;
-       cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT;
+       /* log for looking forward */
+       for (i = 1; i < ext_buf_cnt; i++) {
+               if (nemb_tp == nemb_mse)
+                       lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                               "2951 SLI_CONFIG(mse), buf[%d]-length:%d\n",
+                               i, sli_cfg_mbx->un.sli_config_emb0_subsys.
+                               mse[i].buf_len);
+               else
+                       lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                               "2952 SLI_CONFIG(hbd), buf[%d]-length:%d\n",
+                               i, bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len,
+                               &sli_cfg_mbx->un.sli_config_emb1_subsys.
+                               hbd[i]));
+       }
 
-       cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX;
-       cmd->ulpBdeCount = 1;
-       cmd->ulpLe = 1;
-       cmd->ulpClass = CLASS3;
-       cmd->ulpContext = txxri;
+       /* multi-buffer handling context */
+       phba->mbox_ext_buf_ctx.nembType = nemb_tp;
+       phba->mbox_ext_buf_ctx.mboxType = mbox_wr;
+       phba->mbox_ext_buf_ctx.numBuf = ext_buf_cnt;
+       phba->mbox_ext_buf_ctx.mbxTag = mbox_req->extMboxTag;
+       phba->mbox_ext_buf_ctx.seqNum = mbox_req->extSeqNum;
+       phba->mbox_ext_buf_ctx.mbx_dmabuf = dmabuf;
+
+       if (ext_buf_cnt == 1) {
+               /* bsg tracking structure */
+               dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
+               if (!dd_data) {
+                       rc = -ENOMEM;
+                       goto job_error;
+               }
 
-       cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
-       cmdiocbq->vport = phba->pport;
+               /* mailbox command structure for base driver */
+               pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+               if (!pmboxq) {
+                       rc = -ENOMEM;
+                       goto job_error;
+               }
+               memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
+               pmb = &pmboxq->u.mb;
+               mbx = (uint8_t *)dmabuf->virt;
+               memcpy(pmb, mbx, sizeof(*pmb));
+               pmb->mbxOwner = OWN_HOST;
+               pmboxq->vport = phba->pport;
+
+               /* callback for multi-buffer read mailbox command */
+               pmboxq->mbox_cmpl = lpfc_bsg_issue_write_mbox_ext_cmpl;
+
+               /* context fields to callback function */
+               pmboxq->context1 = dd_data;
+               dd_data->type = TYPE_MBOX;
+               dd_data->context_un.mbox.pmboxq = pmboxq;
+               dd_data->context_un.mbox.mb = (MAILBOX_t *)mbx;
+               dd_data->context_un.mbox.set_job = job;
+               job->dd_data = dd_data;
+
+               /* state change */
+               phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT;
+
+               rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
+               if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) {
+                       lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                                       "2955 Issued SLI_CONFIG ext-buffer "
+                                       "maibox command, rc:x%x\n", rc);
+                       return 1;
+               }
+               lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+                               "2956 Failed to issue SLI_CONFIG ext-buffer "
+                               "maibox command, rc:x%x\n", rc);
+               rc = -EPIPE;
+       }
 
-       iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
-                                            rspiocbq, (phba->fc_ratov * 2) +
-                                            LPFC_DRVR_TIMEOUT);
+job_error:
+       if (pmboxq)
+               mempool_free(pmboxq, phba->mbox_mem_pool);
+       kfree(dd_data);
 
-       if ((iocb_stat != IOCB_SUCCESS) || (rsp->ulpStatus != IOCB_SUCCESS)) {
-               rc = -EIO;
-               goto err_loopback_test_exit;
-       }
+       return rc;
+}
 
-       evt->waiting = 1;
-       time_left = wait_event_interruptible_timeout(
-               evt->wq, !list_empty(&evt->events_to_see),
-               ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ);
-       evt->waiting = 0;
-       if (list_empty(&evt->events_to_see))
-               rc = (time_left) ? -EINTR : -ETIMEDOUT;
-       else {
-               spin_lock_irqsave(&phba->ct_ev_lock, flags);
-               list_move(evt->events_to_see.prev, &evt->events_to_get);
-               evdat = list_entry(evt->events_to_get.prev,
-                                  typeof(*evdat), node);
-               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
-               rx_databuf = evdat->data;
-               if (evdat->len != full_size) {
-                       lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
-                               "1603 Loopback test did not receive expected "
-                               "data length. actual length 0x%x expected "
-                               "length 0x%x\n",
-                               evdat->len, full_size);
-                       rc = -EIO;
-               } else if (rx_databuf == NULL)
-                       rc = -EIO;
-               else {
-                       rc = IOCB_SUCCESS;
-                       /* skip over elx loopback header */
-                       rx_databuf += ELX_LOOPBACK_HEADER_SZ;
-                       job->reply->reply_payload_rcv_len =
-                               sg_copy_from_buffer(job->reply_payload.sg_list,
-                                                   job->reply_payload.sg_cnt,
-                                                   rx_databuf, size);
-                       job->reply->reply_payload_rcv_len = size;
+/**
+ * lpfc_bsg_handle_sli_cfg_mbox - handle sli-cfg mailbox cmd with ext buffer
+ * @phba: Pointer to HBA context object.
+ * @mb: Pointer to a BSG mailbox object.
+ * @dmabuff: Pointer to a DMA buffer descriptor.
+ *
+ * This routine handles SLI_CONFIG (0x9B) mailbox command with non-embedded
+ * external bufffers, including both 0x9B with non-embedded MSEs and 0x9B
+ * with embedded sussystem 0x1 and opcodes with external HBDs.
+ **/
+static int
+lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
+                            struct lpfc_dmabuf *dmabuf)
+{
+       struct lpfc_sli_config_mbox *sli_cfg_mbx;
+       uint32_t subsys;
+       uint32_t opcode;
+       int rc = SLI_CONFIG_NOT_HANDLED;
+
+       /* state change */
+       phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_HOST;
+
+       sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt;
+
+       if (!bsg_bf_get(lpfc_mbox_hdr_emb,
+           &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) {
+               subsys = bsg_bf_get(lpfc_emb0_subcmnd_subsys,
+                                   &sli_cfg_mbx->un.sli_config_emb0_subsys);
+               opcode = bsg_bf_get(lpfc_emb0_subcmnd_opcode,
+                                   &sli_cfg_mbx->un.sli_config_emb0_subsys);
+               if (subsys == SLI_CONFIG_SUBSYS_FCOE) {
+                       switch (opcode) {
+                       case FCOE_OPCODE_READ_FCF:
+                               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                                               "2957 Handled SLI_CONFIG "
+                                               "subsys_fcoe, opcode:x%x\n",
+                                               opcode);
+                               rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job,
+                                                       nemb_mse, dmabuf);
+                               break;
+                       case FCOE_OPCODE_ADD_FCF:
+                               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                                               "2958 Handled SLI_CONFIG "
+                                               "subsys_fcoe, opcode:x%x\n",
+                                               opcode);
+                               rc = lpfc_bsg_sli_cfg_write_cmd_ext(phba, job,
+                                                       nemb_mse, dmabuf);
+                               break;
+                       default:
+                               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                                               "2959 Not handled SLI_CONFIG "
+                                               "subsys_fcoe, opcode:x%x\n",
+                                               opcode);
+                               rc = SLI_CONFIG_NOT_HANDLED;
+                               break;
+                       }
+               } else {
+                       lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                                       "2977 Handled SLI_CONFIG "
+                                       "subsys:x%d, opcode:x%x\n",
+                                       subsys, opcode);
+                       rc = SLI_CONFIG_NOT_HANDLED;
+               }
+       } else {
+               subsys = bsg_bf_get(lpfc_emb1_subcmnd_subsys,
+                                   &sli_cfg_mbx->un.sli_config_emb1_subsys);
+               opcode = bsg_bf_get(lpfc_emb1_subcmnd_opcode,
+                                   &sli_cfg_mbx->un.sli_config_emb1_subsys);
+               if (subsys == SLI_CONFIG_SUBSYS_COMN) {
+                       switch (opcode) {
+                       case COMN_OPCODE_READ_OBJECT:
+                       case COMN_OPCODE_READ_OBJECT_LIST:
+                               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                                               "2960 Handled SLI_CONFIG "
+                                               "subsys_comn, opcode:x%x\n",
+                                               opcode);
+                               rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job,
+                                                       nemb_hbd, dmabuf);
+                               break;
+                       case COMN_OPCODE_WRITE_OBJECT:
+                               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                                               "2961 Handled SLI_CONFIG "
+                                               "subsys_comn, opcode:x%x\n",
+                                               opcode);
+                               rc = lpfc_bsg_sli_cfg_write_cmd_ext(phba, job,
+                                                       nemb_hbd, dmabuf);
+                               break;
+                       default:
+                               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                                               "2962 Not handled SLI_CONFIG "
+                                               "subsys_comn, opcode:x%x\n",
+                                               opcode);
+                               rc = SLI_CONFIG_NOT_HANDLED;
+                               break;
+                       }
+               } else {
+                       lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                                       "2978 Handled SLI_CONFIG "
+                                       "subsys:x%d, opcode:x%x\n",
+                                       subsys, opcode);
+                       rc = SLI_CONFIG_NOT_HANDLED;
                }
        }
+       return rc;
+}
 
-err_loopback_test_exit:
-       lpfcdiag_loop_self_unreg(phba, rpi);
+/**
+ * lpfc_bsg_mbox_ext_abort_req - request to abort mbox command with ext buffers
+ * @phba: Pointer to HBA context object.
+ *
+ * This routine is for requesting to abort a pass-through mailbox command with
+ * multiple external buffers due to error condition.
+ **/
+static void
+lpfc_bsg_mbox_ext_abort(struct lpfc_hba *phba)
+{
+       if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_PORT)
+               phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_ABTS;
+       else
+               lpfc_bsg_mbox_ext_session_reset(phba);
+       return;
+}
 
-       spin_lock_irqsave(&phba->ct_ev_lock, flags);
-       lpfc_bsg_event_unref(evt); /* release ref */
-       lpfc_bsg_event_unref(evt); /* delete */
-       spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+/**
+ * lpfc_bsg_read_ebuf_get - get the next mailbox read external buffer
+ * @phba: Pointer to HBA context object.
+ * @dmabuf: Pointer to a DMA buffer descriptor.
+ *
+ * This routine extracts the next mailbox read external buffer back to
+ * user space through BSG.
+ **/
+static int
+lpfc_bsg_read_ebuf_get(struct lpfc_hba *phba, struct fc_bsg_job *job)
+{
+       struct lpfc_sli_config_mbox *sli_cfg_mbx;
+       struct lpfc_dmabuf *dmabuf;
+       uint8_t *pbuf;
+       uint32_t size;
+       uint32_t index;
 
-       if (cmdiocbq != NULL)
-               lpfc_sli_release_iocbq(phba, cmdiocbq);
+       index = phba->mbox_ext_buf_ctx.seqNum;
+       phba->mbox_ext_buf_ctx.seqNum++;
 
-       if (rspiocbq != NULL)
-               lpfc_sli_release_iocbq(phba, rspiocbq);
+       sli_cfg_mbx = (struct lpfc_sli_config_mbox *)
+                       phba->mbox_ext_buf_ctx.mbx_dmabuf->virt;
 
-       if (txbmp != NULL) {
-               if (txbpl != NULL) {
-                       if (txbuffer != NULL)
-                               diag_cmd_data_free(phba, txbuffer);
-                       lpfc_mbuf_free(phba, txbmp->virt, txbmp->phys);
-               }
-               kfree(txbmp);
+       if (phba->mbox_ext_buf_ctx.nembType == nemb_mse) {
+               size = bsg_bf_get(lpfc_mbox_sli_config_mse_len,
+                       &sli_cfg_mbx->un.sli_config_emb0_subsys.mse[index]);
+               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                               "2963 SLI_CONFIG (mse) ext-buffer rd get "
+                               "buffer[%d], size:%d\n", index, size);
+       } else {
+               size = bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len,
+                       &sli_cfg_mbx->un.sli_config_emb1_subsys.hbd[index]);
+               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                               "2964 SLI_CONFIG (hbd) ext-buffer rd get "
+                               "buffer[%d], size:%d\n", index, size);
+       }
+       if (list_empty(&phba->mbox_ext_buf_ctx.ext_dmabuf_list))
+               return -EPIPE;
+       dmabuf = list_first_entry(&phba->mbox_ext_buf_ctx.ext_dmabuf_list,
+                                 struct lpfc_dmabuf, list);
+       list_del_init(&dmabuf->list);
+       pbuf = (uint8_t *)dmabuf->virt;
+       job->reply->reply_payload_rcv_len =
+               sg_copy_from_buffer(job->reply_payload.sg_list,
+                                   job->reply_payload.sg_cnt,
+                                   pbuf, size);
+
+       lpfc_bsg_dma_page_free(phba, dmabuf);
+
+       if (phba->mbox_ext_buf_ctx.seqNum == phba->mbox_ext_buf_ctx.numBuf) {
+               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                               "2965 SLI_CONFIG (hbd) ext-buffer rd mbox "
+                               "command session done\n");
+               lpfc_bsg_mbox_ext_session_reset(phba);
        }
 
-loopback_test_exit:
-       kfree(dataout);
-       /* make error code available to userspace */
-       job->reply->result = rc;
-       job->dd_data = NULL;
-       /* complete the job back to userspace if no error */
-       if (rc == 0)
-               job->job_done(job);
-       return rc;
+       job->reply->result = 0;
+       job->job_done(job);
+
+       return SLI_CONFIG_HANDLED;
 }
 
 /**
- * lpfc_bsg_get_dfc_rev - process a GET_DFC_REV bsg vendor command
- * @job: GET_DFC_REV fc_bsg_job
+ * lpfc_bsg_write_ebuf_set - set the next mailbox write external buffer
+ * @phba: Pointer to HBA context object.
+ * @dmabuf: Pointer to a DMA buffer descriptor.
+ *
+ * This routine sets up the next mailbox read external buffer obtained
+ * from user space through BSG.
  **/
 static int
-lpfc_bsg_get_dfc_rev(struct fc_bsg_job *job)
+lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct fc_bsg_job *job,
+                       struct lpfc_dmabuf *dmabuf)
 {
-       struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
-       struct lpfc_hba *phba = vport->phba;
-       struct get_mgmt_rev *event_req;
-       struct get_mgmt_rev_reply *event_reply;
-       int rc = 0;
+       struct lpfc_sli_config_mbox *sli_cfg_mbx;
+       struct bsg_job_data *dd_data = NULL;
+       LPFC_MBOXQ_t *pmboxq = NULL;
+       MAILBOX_t *pmb;
+       enum nemb_type nemb_tp;
+       uint8_t *pbuf;
+       uint32_t size;
+       uint32_t index;
+       int rc;
 
-       if (job->request_len <
-           sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev)) {
-               lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
-                               "2740 Received GET_DFC_REV request below "
-                               "minimum size\n");
-               rc = -EINVAL;
+       index = phba->mbox_ext_buf_ctx.seqNum;
+       phba->mbox_ext_buf_ctx.seqNum++;
+       nemb_tp = phba->mbox_ext_buf_ctx.nembType;
+
+       sli_cfg_mbx = (struct lpfc_sli_config_mbox *)
+                       phba->mbox_ext_buf_ctx.mbx_dmabuf->virt;
+
+       dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
+       if (!dd_data) {
+               rc = -ENOMEM;
                goto job_error;
        }
 
-       event_req = (struct get_mgmt_rev *)
-               job->request->rqst_data.h_vendor.vendor_cmd;
+       pbuf = (uint8_t *)dmabuf->virt;
+       size = job->request_payload.payload_len;
+       sg_copy_to_buffer(job->request_payload.sg_list,
+                         job->request_payload.sg_cnt,
+                         pbuf, size);
 
-       event_reply = (struct get_mgmt_rev_reply *)
-               job->reply->reply_data.vendor_reply.vendor_rsp;
+       if (phba->mbox_ext_buf_ctx.nembType == nemb_mse) {
+               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                               "2966 SLI_CONFIG (mse) ext-buffer wr set "
+                               "buffer[%d], size:%d\n",
+                               phba->mbox_ext_buf_ctx.seqNum, size);
 
-       if (job->reply_len <
-           sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev_reply)) {
-               lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
-                               "2741 Received GET_DFC_REV reply below "
-                               "minimum size\n");
-               rc = -EINVAL;
+       } else {
+               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                               "2967 SLI_CONFIG (hbd) ext-buffer wr set "
+                               "buffer[%d], size:%d\n",
+                               phba->mbox_ext_buf_ctx.seqNum, size);
+
+       }
+
+       /* set up external buffer descriptor and add to external buffer list */
+       lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, index,
+                                       phba->mbox_ext_buf_ctx.mbx_dmabuf,
+                                       dmabuf);
+       list_add_tail(&dmabuf->list, &phba->mbox_ext_buf_ctx.ext_dmabuf_list);
+
+       if (phba->mbox_ext_buf_ctx.seqNum == phba->mbox_ext_buf_ctx.numBuf) {
+               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                               "2968 SLI_CONFIG ext-buffer wr all %d "
+                               "ebuffers received\n",
+                               phba->mbox_ext_buf_ctx.numBuf);
+               /* mailbox command structure for base driver */
+               pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+               if (!pmboxq) {
+                       rc = -ENOMEM;
+                       goto job_error;
+               }
+               memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
+               pbuf = (uint8_t *)phba->mbox_ext_buf_ctx.mbx_dmabuf->virt;
+               pmb = &pmboxq->u.mb;
+               memcpy(pmb, pbuf, sizeof(*pmb));
+               pmb->mbxOwner = OWN_HOST;
+               pmboxq->vport = phba->pport;
+
+               /* callback for multi-buffer write mailbox command */
+               pmboxq->mbox_cmpl = lpfc_bsg_issue_write_mbox_ext_cmpl;
+
+               /* context fields to callback function */
+               pmboxq->context1 = dd_data;
+               dd_data->type = TYPE_MBOX;
+               dd_data->context_un.mbox.pmboxq = pmboxq;
+               dd_data->context_un.mbox.mb = (MAILBOX_t *)pbuf;
+               dd_data->context_un.mbox.set_job = job;
+               job->dd_data = dd_data;
+
+               /* state change */
+               phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT;
+
+               rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
+               if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) {
+                       lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                                       "2969 Issued SLI_CONFIG ext-buffer "
+                                       "maibox command, rc:x%x\n", rc);
+                       return 1;
+               }
+               lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+                               "2970 Failed to issue SLI_CONFIG ext-buffer "
+                               "maibox command, rc:x%x\n", rc);
+               rc = -EPIPE;
                goto job_error;
        }
 
-       event_reply->info.a_Major = MANAGEMENT_MAJOR_REV;
-       event_reply->info.a_Minor = MANAGEMENT_MINOR_REV;
+       /* wait for additoinal external buffers */
+       job->reply->result = 0;
+       job->job_done(job);
+       return SLI_CONFIG_HANDLED;
+
 job_error:
-       job->reply->result = rc;
-       if (rc == 0)
-               job->job_done(job);
+       lpfc_bsg_dma_page_free(phba, dmabuf);
+       kfree(dd_data);
+
        return rc;
 }
 
 /**
- * lpfc_bsg_wake_mbox_wait - lpfc_bsg_issue_mbox mbox completion handler
+ * lpfc_bsg_handle_sli_cfg_ebuf - handle ext buffer with sli-cfg mailbox cmd
  * @phba: Pointer to HBA context object.
- * @pmboxq: Pointer to mailbox command.
+ * @mb: Pointer to a BSG mailbox object.
+ * @dmabuff: Pointer to a DMA buffer descriptor.
  *
- * This is completion handler function for mailbox commands issued from
- * lpfc_bsg_issue_mbox function. This function is called by the
- * mailbox event handler function with no lock held. This function
- * will wake up thread waiting on the wait queue pointed by context1
- * of the mailbox.
+ * This routine handles the external buffer with SLI_CONFIG (0x9B) mailbox
+ * command with multiple non-embedded external buffers.
  **/
-void
-lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
+static int
+lpfc_bsg_handle_sli_cfg_ebuf(struct lpfc_hba *phba, struct fc_bsg_job *job,
+                            struct lpfc_dmabuf *dmabuf)
 {
-       struct bsg_job_data *dd_data;
-       struct fc_bsg_job *job;
-       struct lpfc_mbx_nembed_cmd *nembed_sge;
-       uint32_t size;
-       unsigned long flags;
-       uint8_t *to;
-       uint8_t *from;
+       int rc;
 
-       spin_lock_irqsave(&phba->ct_ev_lock, flags);
-       dd_data = pmboxq->context1;
-       /* job already timed out? */
-       if (!dd_data) {
-               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
-               return;
-       }
+       lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                       "2971 SLI_CONFIG buffer (type:x%x)\n",
+                       phba->mbox_ext_buf_ctx.mboxType);
 
-       /* build the outgoing buffer to do an sg copy
-        * the format is the response mailbox followed by any extended
-        * mailbox data
-        */
-       from = (uint8_t *)&pmboxq->u.mb;
-       to = (uint8_t *)dd_data->context_un.mbox.mb;
-       memcpy(to, from, sizeof(MAILBOX_t));
-       if (pmboxq->u.mb.mbxStatus == MBX_SUCCESS) {
-               /* copy the extended data if any, count is in words */
-               if (dd_data->context_un.mbox.outExtWLen) {
-                       from = (uint8_t *)dd_data->context_un.mbox.ext;
-                       to += sizeof(MAILBOX_t);
-                       size = dd_data->context_un.mbox.outExtWLen *
-                                       sizeof(uint32_t);
-                       memcpy(to, from, size);
-               } else if (pmboxq->u.mb.mbxCommand == MBX_RUN_BIU_DIAG64) {
-                       from = (uint8_t *)dd_data->context_un.mbox.
-                                               dmp->dma.virt;
-                       to += sizeof(MAILBOX_t);
-                       size = dd_data->context_un.mbox.dmp->size;
-                       memcpy(to, from, size);
-               } else if ((phba->sli_rev == LPFC_SLI_REV4) &&
-                       (pmboxq->u.mb.mbxCommand == MBX_DUMP_MEMORY)) {
-                       from = (uint8_t *)dd_data->context_un.mbox.dmp->dma.
-                                               virt;
-                       to += sizeof(MAILBOX_t);
-                       size = pmboxq->u.mb.un.varWords[5];
-                       memcpy(to, from, size);
-               } else if ((phba->sli_rev == LPFC_SLI_REV4) &&
-                       (pmboxq->u.mb.mbxCommand == MBX_SLI4_CONFIG)) {
-                       nembed_sge = (struct lpfc_mbx_nembed_cmd *)
-                                       &pmboxq->u.mb.un.varWords[0];
-
-                       from = (uint8_t *)dd_data->context_un.mbox.dmp->dma.
-                                               virt;
-                       to += sizeof(MAILBOX_t);
-                       size = nembed_sge->sge[0].length;
-                       memcpy(to, from, size);
-               } else if (pmboxq->u.mb.mbxCommand == MBX_READ_EVENT_LOG) {
-                       from = (uint8_t *)dd_data->context_un.
-                                               mbox.dmp->dma.virt;
-                       to += sizeof(MAILBOX_t);
-                       size = dd_data->context_un.mbox.dmp->size;
-                       memcpy(to, from, size);
+       if (phba->mbox_ext_buf_ctx.mboxType == mbox_rd) {
+               if (phba->mbox_ext_buf_ctx.state != LPFC_BSG_MBOX_DONE) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+                                       "2972 SLI_CONFIG rd buffer state "
+                                       "mismatch:x%x\n",
+                                       phba->mbox_ext_buf_ctx.state);
+                       lpfc_bsg_mbox_ext_abort(phba);
+                       return -EPIPE;
                }
+               rc = lpfc_bsg_read_ebuf_get(phba, job);
+               if (rc == SLI_CONFIG_HANDLED)
+                       lpfc_bsg_dma_page_free(phba, dmabuf);
+       } else { /* phba->mbox_ext_buf_ctx.mboxType == mbox_wr */
+               if (phba->mbox_ext_buf_ctx.state != LPFC_BSG_MBOX_HOST) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+                                       "2973 SLI_CONFIG wr buffer state "
+                                       "mismatch:x%x\n",
+                                       phba->mbox_ext_buf_ctx.state);
+                       lpfc_bsg_mbox_ext_abort(phba);
+                       return -EPIPE;
+               }
+               rc = lpfc_bsg_write_ebuf_set(phba, job, dmabuf);
        }
-
-       from = (uint8_t *)dd_data->context_un.mbox.mb;
-       job = dd_data->context_un.mbox.set_job;
-       if (job) {
-               size = job->reply_payload.payload_len;
-               job->reply->reply_payload_rcv_len =
-                       sg_copy_from_buffer(job->reply_payload.sg_list,
-                                       job->reply_payload.sg_cnt,
-                                       from, size);
-               job->reply->result = 0;
-               /* need to hold the lock until we set job->dd_data to NULL
-                * to hold off the timeout handler returning to the mid-layer
-                * while we are still processing the job.
-                */
-               job->dd_data = NULL;
-               dd_data->context_un.mbox.set_job = NULL;
-               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
-               job->job_done(job);
-       } else {
-               dd_data->context_un.mbox.set_job = NULL;
-               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
-       }
-
-       kfree(dd_data->context_un.mbox.mb);
-       mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool);
-       kfree(dd_data->context_un.mbox.ext);
-       if (dd_data->context_un.mbox.dmp) {
-               dma_free_coherent(&phba->pcidev->dev,
-                       dd_data->context_un.mbox.dmp->size,
-                       dd_data->context_un.mbox.dmp->dma.virt,
-                       dd_data->context_un.mbox.dmp->dma.phys);
-               kfree(dd_data->context_un.mbox.dmp);
-       }
-       if (dd_data->context_un.mbox.rxbmp) {
-               lpfc_mbuf_free(phba, dd_data->context_un.mbox.rxbmp->virt,
-                       dd_data->context_un.mbox.rxbmp->phys);
-               kfree(dd_data->context_un.mbox.rxbmp);
-       }
-       kfree(dd_data);
-       return;
+       return rc;
 }
 
 /**
- * lpfc_bsg_check_cmd_access - test for a supported mailbox command
+ * lpfc_bsg_handle_sli_cfg_ext - handle sli-cfg mailbox with external buffer
  * @phba: Pointer to HBA context object.
- * @mb: Pointer to a mailbox object.
- * @vport: Pointer to a vport object.
+ * @mb: Pointer to a BSG mailbox object.
+ * @dmabuff: Pointer to a DMA buffer descriptor.
  *
- * Some commands require the port to be offline, some may not be called from
- * the application.
+ * This routine checkes and handles non-embedded multi-buffer SLI_CONFIG
+ * (0x9B) mailbox commands and external buffers.
  **/
-static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,
-       MAILBOX_t *mb, struct lpfc_vport *vport)
+static int
+lpfc_bsg_handle_sli_cfg_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
+                           struct lpfc_dmabuf *dmabuf)
 {
-       /* return negative error values for bsg job */
-       switch (mb->mbxCommand) {
-       /* Offline only */
-       case MBX_INIT_LINK:
-       case MBX_DOWN_LINK:
-       case MBX_CONFIG_LINK:
-       case MBX_CONFIG_RING:
-       case MBX_RESET_RING:
-       case MBX_UNREG_LOGIN:
-       case MBX_CLEAR_LA:
-       case MBX_DUMP_CONTEXT:
-       case MBX_RUN_DIAGS:
-       case MBX_RESTART:
-       case MBX_SET_MASK:
-               if (!(vport->fc_flag & FC_OFFLINE_MODE)) {
-                       lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
-                               "2743 Command 0x%x is illegal in on-line "
-                               "state\n",
-                               mb->mbxCommand);
-                       return -EPERM;
-               }
-       case MBX_WRITE_NV:
-       case MBX_WRITE_VPARMS:
-       case MBX_LOAD_SM:
-       case MBX_READ_NV:
-       case MBX_READ_CONFIG:
-       case MBX_READ_RCONFIG:
-       case MBX_READ_STATUS:
-       case MBX_READ_XRI:
-       case MBX_READ_REV:
-       case MBX_READ_LNK_STAT:
-       case MBX_DUMP_MEMORY:
-       case MBX_DOWN_LOAD:
-       case MBX_UPDATE_CFG:
-       case MBX_KILL_BOARD:
-       case MBX_LOAD_AREA:
-       case MBX_LOAD_EXP_ROM:
-       case MBX_BEACON:
-       case MBX_DEL_LD_ENTRY:
-       case MBX_SET_DEBUG:
-       case MBX_WRITE_WWN:
-       case MBX_SLI4_CONFIG:
-       case MBX_READ_EVENT_LOG:
-       case MBX_READ_EVENT_LOG_STATUS:
-       case MBX_WRITE_EVENT_LOG:
-       case MBX_PORT_CAPABILITIES:
-       case MBX_PORT_IOV_CONTROL:
-       case MBX_RUN_BIU_DIAG64:
-               break;
-       case MBX_SET_VARIABLE:
-               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-                       "1226 mbox: set_variable 0x%x, 0x%x\n",
-                       mb->un.varWords[0],
-                       mb->un.varWords[1]);
-               if ((mb->un.varWords[0] == SETVAR_MLOMNT)
-                       && (mb->un.varWords[1] == 1)) {
-                       phba->wait_4_mlo_maint_flg = 1;
-               } else if (mb->un.varWords[0] == SETVAR_MLORST) {
-                       phba->link_flag &= ~LS_LOOPBACK_MODE;
-                       phba->fc_topology = LPFC_TOPOLOGY_PT_PT;
-               }
-               break;
-       case MBX_READ_SPARM64:
-       case MBX_READ_TOPOLOGY:
-       case MBX_REG_LOGIN:
-       case MBX_REG_LOGIN64:
-       case MBX_CONFIG_PORT:
-       case MBX_RUN_BIU_DIAG:
-       default:
-               lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
-                       "2742 Unknown Command 0x%x\n",
-                       mb->mbxCommand);
-               return -EPERM;
+       struct dfc_mbox_req *mbox_req;
+       int rc;
+
+       mbox_req =
+          (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd;
+
+       /* mbox command with/without single external buffer */
+       if (mbox_req->extMboxTag == 0 && mbox_req->extSeqNum == 0)
+               return SLI_CONFIG_NOT_HANDLED;
+
+       /* mbox command and first external buffer */
+       if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE) {
+               if (mbox_req->extSeqNum == 1) {
+                       lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                                       "2974 SLI_CONFIG mailbox: tag:%d, "
+                                       "seq:%d\n", mbox_req->extMboxTag,
+                                       mbox_req->extSeqNum);
+                       rc = lpfc_bsg_handle_sli_cfg_mbox(phba, job, dmabuf);
+                       return rc;
+               } else
+                       goto sli_cfg_ext_error;
        }
 
-       return 0; /* ok */
+       /*
+        * handle additional external buffers
+        */
+
+       /* check broken pipe conditions */
+       if (mbox_req->extMboxTag != phba->mbox_ext_buf_ctx.mbxTag)
+               goto sli_cfg_ext_error;
+       if (mbox_req->extSeqNum > phba->mbox_ext_buf_ctx.numBuf)
+               goto sli_cfg_ext_error;
+       if (mbox_req->extSeqNum != phba->mbox_ext_buf_ctx.seqNum + 1)
+               goto sli_cfg_ext_error;
+
+       lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                       "2975 SLI_CONFIG mailbox external buffer: "
+                       "extSta:x%x, tag:%d, seq:%d\n",
+                       phba->mbox_ext_buf_ctx.state, mbox_req->extMboxTag,
+                       mbox_req->extSeqNum);
+       rc = lpfc_bsg_handle_sli_cfg_ebuf(phba, job, dmabuf);
+       return rc;
+
+sli_cfg_ext_error:
+       /* all other cases, broken pipe */
+       lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+                       "2976 SLI_CONFIG mailbox broken pipe: "
+                       "ctxSta:x%x, ctxNumBuf:%d "
+                       "ctxTag:%d, ctxSeq:%d, tag:%d, seq:%d\n",
+                       phba->mbox_ext_buf_ctx.state,
+                       phba->mbox_ext_buf_ctx.numBuf,
+                       phba->mbox_ext_buf_ctx.mbxTag,
+                       phba->mbox_ext_buf_ctx.seqNum,
+                       mbox_req->extMboxTag, mbox_req->extSeqNum);
+
+       lpfc_bsg_mbox_ext_session_reset(phba);
+
+       return -EPIPE;
 }
 
 /**
@@ -2638,22 +4118,21 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
        LPFC_MBOXQ_t *pmboxq = NULL; /* internal mailbox queue */
        MAILBOX_t *pmb; /* shortcut to the pmboxq mailbox */
        /* a 4k buffer to hold the mb and extended data from/to the bsg */
-       MAILBOX_t *mb = NULL;
+       uint8_t *pmbx = NULL;
        struct bsg_job_data *dd_data = NULL; /* bsg data tracking structure */
-       uint32_t size;
-       struct lpfc_dmabuf *rxbmp = NULL; /* for biu diag */
-       struct lpfc_dmabufext *dmp = NULL; /* for biu diag */
-       struct ulp_bde64 *rxbpl = NULL;
-       struct dfc_mbox_req *mbox_req = (struct dfc_mbox_req *)
-               job->request->rqst_data.h_vendor.vendor_cmd;
+       struct lpfc_dmabuf *dmabuf = NULL;
+       struct dfc_mbox_req *mbox_req;
        struct READ_EVENT_LOG_VAR *rdEventLog;
        uint32_t transmit_length, receive_length, mode;
+       struct lpfc_mbx_sli4_config *sli4_config;
        struct lpfc_mbx_nembed_cmd *nembed_sge;
        struct mbox_header *header;
        struct ulp_bde64 *bde;
        uint8_t *ext = NULL;
        int rc = 0;
        uint8_t *from;
+       uint32_t size;
+
 
        /* in case no data is transferred */
        job->reply->reply_payload_rcv_len = 0;
@@ -2665,6 +4144,18 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                goto job_done;
        }
 
+       /*
+        * Don't allow mailbox commands to be sent when blocked or when in
+        * the middle of discovery
+        */
+        if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) {
+               rc = -EAGAIN;
+               goto job_done;
+       }
+
+       mbox_req =
+           (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd;
+
        /* check if requested extended data lengths are valid */
        if ((mbox_req->inExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t)) ||
            (mbox_req->outExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t))) {
@@ -2672,6 +4163,32 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                goto job_done;
        }
 
+       dmabuf = lpfc_bsg_dma_page_alloc(phba);
+       if (!dmabuf || !dmabuf->virt) {
+               rc = -ENOMEM;
+               goto job_done;
+       }
+
+       /* Get the mailbox command or external buffer from BSG */
+       pmbx = (uint8_t *)dmabuf->virt;
+       size = job->request_payload.payload_len;
+       sg_copy_to_buffer(job->request_payload.sg_list,
+                         job->request_payload.sg_cnt, pmbx, size);
+
+       /* Handle possible SLI_CONFIG with non-embedded payloads */
+       if (phba->sli_rev == LPFC_SLI_REV4) {
+               rc = lpfc_bsg_handle_sli_cfg_ext(phba, job, dmabuf);
+               if (rc == SLI_CONFIG_HANDLED)
+                       goto job_cont;
+               if (rc)
+                       goto job_done;
+               /* SLI_CONFIG_NOT_HANDLED for other mailbox commands */
+       }
+
+       rc = lpfc_bsg_check_cmd_access(phba, (MAILBOX_t *)pmbx, vport);
+       if (rc != 0)
+               goto job_done; /* must be negative */
+
        /* allocate our bsg tracking structure */
        dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
        if (!dd_data) {
@@ -2681,12 +4198,6 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                goto job_done;
        }
 
-       mb = kzalloc(BSG_MBOX_SIZE, GFP_KERNEL);
-       if (!mb) {
-               rc = -ENOMEM;
-               goto job_done;
-       }
-
        pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!pmboxq) {
                rc = -ENOMEM;
@@ -2694,17 +4205,8 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
        }
        memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
 
-       size = job->request_payload.payload_len;
-       sg_copy_to_buffer(job->request_payload.sg_list,
-                       job->request_payload.sg_cnt,
-                       mb, size);
-
-       rc = lpfc_bsg_check_cmd_access(phba, mb, vport);
-       if (rc != 0)
-               goto job_done; /* must be negative */
-
        pmb = &pmboxq->u.mb;
-       memcpy(pmb, mb, sizeof(*pmb));
+       memcpy(pmb, pmbx, sizeof(*pmb));
        pmb->mbxOwner = OWN_HOST;
        pmboxq->vport = vport;
 
@@ -2721,30 +4223,13 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                                "0x%x while in stopped state.\n",
                                pmb->mbxCommand);
 
-       /* Don't allow mailbox commands to be sent when blocked
-        * or when in the middle of discovery
-        */
-       if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) {
-               rc = -EAGAIN;
-               goto job_done;
-       }
-
        /* extended mailbox commands will need an extended buffer */
        if (mbox_req->inExtWLen || mbox_req->outExtWLen) {
-               ext = kzalloc(MAILBOX_EXT_SIZE, GFP_KERNEL);
-               if (!ext) {
-                       rc = -ENOMEM;
-                       goto job_done;
-               }
-
                /* any data for the device? */
                if (mbox_req->inExtWLen) {
-                       from = (uint8_t *)mb;
-                       from += sizeof(MAILBOX_t);
-                       memcpy((uint8_t *)ext, from,
-                               mbox_req->inExtWLen * sizeof(uint32_t));
+                       from = pmbx;
+                       ext = from + sizeof(MAILBOX_t);
                }
-
                pmboxq->context2 = ext;
                pmboxq->in_ext_byte_len =
                        mbox_req->inExtWLen * sizeof(uint32_t);
@@ -2768,46 +4253,17 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                        rc = -ERANGE;
                        goto job_done;
                }
-
-               rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
-               if (!rxbmp) {
-                       rc = -ENOMEM;
-                       goto job_done;
-               }
-
-               rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
-               if (!rxbmp->virt) {
-                       rc = -ENOMEM;
-                       goto job_done;
-               }
-
-               INIT_LIST_HEAD(&rxbmp->list);
-               rxbpl = (struct ulp_bde64 *) rxbmp->virt;
-               dmp = diag_cmd_data_alloc(phba, rxbpl, transmit_length, 0);
-               if (!dmp) {
-                       rc = -ENOMEM;
-                       goto job_done;
-               }
-
-               INIT_LIST_HEAD(&dmp->dma.list);
                pmb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh =
-                       putPaddrHigh(dmp->dma.phys);
+                       putPaddrHigh(dmabuf->phys + sizeof(MAILBOX_t));
                pmb->un.varBIUdiag.un.s2.xmit_bde64.addrLow =
-                       putPaddrLow(dmp->dma.phys);
+                       putPaddrLow(dmabuf->phys + sizeof(MAILBOX_t));
 
                pmb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh =
-                       putPaddrHigh(dmp->dma.phys +
-                               pmb->un.varBIUdiag.un.s2.
-                                       xmit_bde64.tus.f.bdeSize);
+                       putPaddrHigh(dmabuf->phys + sizeof(MAILBOX_t)
+                         + pmb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize);
                pmb->un.varBIUdiag.un.s2.rcv_bde64.addrLow =
-                       putPaddrLow(dmp->dma.phys +
-                               pmb->un.varBIUdiag.un.s2.
-                                       xmit_bde64.tus.f.bdeSize);
-
-               /* copy the transmit data found in the mailbox extension area */
-               from = (uint8_t *)mb;
-               from += sizeof(MAILBOX_t);
-               memcpy((uint8_t *)dmp->dma.virt, from, transmit_length);
+                       putPaddrLow(dmabuf->phys + sizeof(MAILBOX_t)
+                         + pmb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize);
        } else if (pmb->mbxCommand == MBX_READ_EVENT_LOG) {
                rdEventLog = &pmb->un.varRdEventLog;
                receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize;
@@ -2823,33 +4279,10 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
 
                /* mode zero uses a bde like biu diags command */
                if (mode == 0) {
-
-                       /* rebuild the command for sli4 using our own buffers
-                       * like we do for biu diags
-                       */
-
-                       rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
-                       if (!rxbmp) {
-                               rc = -ENOMEM;
-                               goto job_done;
-                       }
-
-                       rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
-                       rxbpl = (struct ulp_bde64 *) rxbmp->virt;
-                       if (rxbpl) {
-                               INIT_LIST_HEAD(&rxbmp->list);
-                               dmp = diag_cmd_data_alloc(phba, rxbpl,
-                                       receive_length, 0);
-                       }
-
-                       if (!dmp) {
-                               rc = -ENOMEM;
-                               goto job_done;
-                       }
-
-                       INIT_LIST_HEAD(&dmp->dma.list);
-                       pmb->un.varWords[3] = putPaddrLow(dmp->dma.phys);
-                       pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys);
+                       pmb->un.varWords[3] = putPaddrLow(dmabuf->phys
+                                                       + sizeof(MAILBOX_t));
+                       pmb->un.varWords[4] = putPaddrHigh(dmabuf->phys
+                                                       + sizeof(MAILBOX_t));
                }
        } else if (phba->sli_rev == LPFC_SLI_REV4) {
                if (pmb->mbxCommand == MBX_DUMP_MEMORY) {
@@ -2860,36 +4293,14 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                        /* receive length cannot be greater than mailbox
                         * extension size
                         */
-                       if ((receive_length == 0) ||
-                               (receive_length > MAILBOX_EXT_SIZE)) {
+                       if (receive_length == 0) {
                                rc = -ERANGE;
                                goto job_done;
                        }
-
-                       rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
-                       if (!rxbmp) {
-                               rc = -ENOMEM;
-                               goto job_done;
-                       }
-
-                       rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
-                       if (!rxbmp->virt) {
-                               rc = -ENOMEM;
-                               goto job_done;
-                       }
-
-                       INIT_LIST_HEAD(&rxbmp->list);
-                       rxbpl = (struct ulp_bde64 *) rxbmp->virt;
-                       dmp = diag_cmd_data_alloc(phba, rxbpl, receive_length,
-                                               0);
-                       if (!dmp) {
-                               rc = -ENOMEM;
-                               goto job_done;
-                       }
-
-                       INIT_LIST_HEAD(&dmp->dma.list);
-                       pmb->un.varWords[3] = putPaddrLow(dmp->dma.phys);
-                       pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys);
+                       pmb->un.varWords[3] = putPaddrLow(dmabuf->phys
+                                               + sizeof(MAILBOX_t));
+                       pmb->un.varWords[4] = putPaddrHigh(dmabuf->phys
+                                               + sizeof(MAILBOX_t));
                } else if ((pmb->mbxCommand == MBX_UPDATE_CFG) &&
                        pmb->un.varUpdateCfg.co) {
                        bde = (struct ulp_bde64 *)&pmb->un.varWords[4];
@@ -2899,102 +4310,53 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                                rc = -ERANGE;
                                goto job_done;
                        }
-
-                       rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
-                       if (!rxbmp) {
-                               rc = -ENOMEM;
-                               goto job_done;
-                       }
-
-                       rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
-                       if (!rxbmp->virt) {
-                               rc = -ENOMEM;
-                               goto job_done;
-                       }
-
-                       INIT_LIST_HEAD(&rxbmp->list);
-                       rxbpl = (struct ulp_bde64 *) rxbmp->virt;
-                       dmp = diag_cmd_data_alloc(phba, rxbpl,
-                                       bde->tus.f.bdeSize, 0);
-                       if (!dmp) {
-                               rc = -ENOMEM;
-                               goto job_done;
-                       }
-
-                       INIT_LIST_HEAD(&dmp->dma.list);
-                       bde->addrHigh = putPaddrHigh(dmp->dma.phys);
-                       bde->addrLow = putPaddrLow(dmp->dma.phys);
-
-                       /* copy the transmit data found in the mailbox
-                        * extension area
-                        */
-                       from = (uint8_t *)mb;
-                       from += sizeof(MAILBOX_t);
-                       memcpy((uint8_t *)dmp->dma.virt, from,
-                               bde->tus.f.bdeSize);
+                       bde->addrHigh = putPaddrHigh(dmabuf->phys
+                                               + sizeof(MAILBOX_t));
+                       bde->addrLow = putPaddrLow(dmabuf->phys
+                                               + sizeof(MAILBOX_t));
                } else if (pmb->mbxCommand == MBX_SLI4_CONFIG) {
-                       /* rebuild the command for sli4 using our own buffers
-                       * like we do for biu diags
-                       */
-                       header = (struct mbox_header *)&pmb->un.varWords[0];
-                       nembed_sge = (struct lpfc_mbx_nembed_cmd *)
-                               &pmb->un.varWords[0];
-                       receive_length = nembed_sge->sge[0].length;
-
-                       /* receive length cannot be greater than mailbox
-                        * extension size
-                        */
-                       if ((receive_length == 0) ||
-                               (receive_length > MAILBOX_EXT_SIZE)) {
-                               rc = -ERANGE;
-                               goto job_done;
-                       }
-
-                       rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
-                       if (!rxbmp) {
-                               rc = -ENOMEM;
-                               goto job_done;
-                       }
-
-                       rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
-                       if (!rxbmp->virt) {
-                               rc = -ENOMEM;
-                               goto job_done;
-                       }
+                       /* Handling non-embedded SLI_CONFIG mailbox command */
+                       sli4_config = &pmboxq->u.mqe.un.sli4_config;
+                       if (!bf_get(lpfc_mbox_hdr_emb,
+                           &sli4_config->header.cfg_mhdr)) {
+                               /* rebuild the command for sli4 using our
+                                * own buffers like we do for biu diags
+                                */
+                               header = (struct mbox_header *)
+                                               &pmb->un.varWords[0];
+                               nembed_sge = (struct lpfc_mbx_nembed_cmd *)
+                                               &pmb->un.varWords[0];
+                               receive_length = nembed_sge->sge[0].length;
+
+                               /* receive length cannot be greater than
+                                * mailbox extension size
+                                */
+                               if ((receive_length == 0) ||
+                                   (receive_length > MAILBOX_EXT_SIZE)) {
+                                       rc = -ERANGE;
+                                       goto job_done;
+                               }
 
-                       INIT_LIST_HEAD(&rxbmp->list);
-                       rxbpl = (struct ulp_bde64 *) rxbmp->virt;
-                       dmp = diag_cmd_data_alloc(phba, rxbpl, receive_length,
-                                               0);
-                       if (!dmp) {
-                               rc = -ENOMEM;
-                               goto job_done;
+                               nembed_sge->sge[0].pa_hi =
+                                               putPaddrHigh(dmabuf->phys
+                                                  + sizeof(MAILBOX_t));
+                               nembed_sge->sge[0].pa_lo =
+                                               putPaddrLow(dmabuf->phys
+                                                  + sizeof(MAILBOX_t));
                        }
-
-                       INIT_LIST_HEAD(&dmp->dma.list);
-                       nembed_sge->sge[0].pa_hi = putPaddrHigh(dmp->dma.phys);
-                       nembed_sge->sge[0].pa_lo = putPaddrLow(dmp->dma.phys);
-                       /* copy the transmit data found in the mailbox
-                        * extension area
-                        */
-                       from = (uint8_t *)mb;
-                       from += sizeof(MAILBOX_t);
-                       memcpy((uint8_t *)dmp->dma.virt, from,
-                               header->cfg_mhdr.payload_length);
                }
        }
 
-       dd_data->context_un.mbox.rxbmp = rxbmp;
-       dd_data->context_un.mbox.dmp = dmp;
+       dd_data->context_un.mbox.dmabuffers = dmabuf;
 
        /* setup wake call as IOCB callback */
-       pmboxq->mbox_cmpl = lpfc_bsg_wake_mbox_wait;
+       pmboxq->mbox_cmpl = lpfc_bsg_issue_mbox_cmpl;
 
        /* setup context field to pass wait_queue pointer to wake function */
        pmboxq->context1 = dd_data;
        dd_data->type = TYPE_MBOX;
        dd_data->context_un.mbox.pmboxq = pmboxq;
-       dd_data->context_un.mbox.mb = mb;
+       dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx;
        dd_data->context_un.mbox.set_job = job;
        dd_data->context_un.mbox.ext = ext;
        dd_data->context_un.mbox.mbOffset = mbox_req->mbOffset;
@@ -3011,11 +4373,11 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                }
 
                /* job finished, copy the data */
-               memcpy(mb, pmb, sizeof(*pmb));
+               memcpy(pmbx, pmb, sizeof(*pmb));
                job->reply->reply_payload_rcv_len =
                        sg_copy_from_buffer(job->reply_payload.sg_list,
-                                       job->reply_payload.sg_cnt,
-                                       mb, size);
+                                           job->reply_payload.sg_cnt,
+                                           pmbx, size);
                /* not waiting mbox already done */
                rc = 0;
                goto job_done;
@@ -3027,22 +4389,12 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
 
 job_done:
        /* common exit for error or job completed inline */
-       kfree(mb);
        if (pmboxq)
                mempool_free(pmboxq, phba->mbox_mem_pool);
-       kfree(ext);
-       if (dmp) {
-               dma_free_coherent(&phba->pcidev->dev,
-                       dmp->size, dmp->dma.virt,
-                               dmp->dma.phys);
-               kfree(dmp);
-       }
-       if (rxbmp) {
-               lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys);
-               kfree(rxbmp);
-       }
+       lpfc_bsg_dma_page_free(phba, dmabuf);
        kfree(dd_data);
 
+job_cont:
        return rc;
 }
 
@@ -3055,37 +4407,28 @@ lpfc_bsg_mbox_cmd(struct fc_bsg_job *job)
 {
        struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
        struct lpfc_hba *phba = vport->phba;
+       struct dfc_mbox_req *mbox_req;
        int rc = 0;
 
-       /* in case no data is transferred */
+       /* mix-and-match backward compatibility */
        job->reply->reply_payload_rcv_len = 0;
        if (job->request_len <
            sizeof(struct fc_bsg_request) + sizeof(struct dfc_mbox_req)) {
-               lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
-                               "2737 Received MBOX_REQ request below "
-                               "minimum size\n");
-               rc = -EINVAL;
-               goto job_error;
-       }
-
-       if (job->request_payload.payload_len != BSG_MBOX_SIZE) {
-               rc = -EINVAL;
-               goto job_error;
-       }
-
-       if (job->reply_payload.payload_len != BSG_MBOX_SIZE) {
-               rc = -EINVAL;
-               goto job_error;
-       }
-
-       if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) {
-               rc = -EAGAIN;
-               goto job_error;
+               lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
+                               "2737 Mix-and-match backward compability "
+                               "between MBOX_REQ old size:%d and "
+                               "new request size:%d\n",
+                               (int)(job->request_len -
+                                     sizeof(struct fc_bsg_request)),
+                               (int)sizeof(struct dfc_mbox_req));
+               mbox_req = (struct dfc_mbox_req *)
+                               job->request->rqst_data.h_vendor.vendor_cmd;
+               mbox_req->extMboxTag = 0;
+               mbox_req->extSeqNum = 0;
        }
 
        rc = lpfc_bsg_issue_mbox(phba, job, vport);
 
-job_error:
        if (rc == 0) {
                /* job done */
                job->reply->result = 0;
@@ -3416,10 +4759,16 @@ lpfc_bsg_hst_vendor(struct fc_bsg_job *job)
                rc = lpfc_bsg_send_mgmt_rsp(job);
                break;
        case LPFC_BSG_VENDOR_DIAG_MODE:
-               rc = lpfc_bsg_diag_mode(job);
+               rc = lpfc_bsg_diag_loopback_mode(job);
+               break;
+       case LPFC_BSG_VENDOR_DIAG_MODE_END:
+               rc = lpfc_sli4_bsg_diag_mode_end(job);
+               break;
+       case LPFC_BSG_VENDOR_DIAG_RUN_LOOPBACK:
+               rc = lpfc_bsg_diag_loopback_run(job);
                break;
-       case LPFC_BSG_VENDOR_DIAG_TEST:
-               rc = lpfc_bsg_diag_test(job);
+       case LPFC_BSG_VENDOR_LINK_DIAG_TEST:
+               rc = lpfc_sli4_bsg_link_diag_test(job);
                break;
        case LPFC_BSG_VENDOR_GET_MGMT_REV:
                rc = lpfc_bsg_get_dfc_rev(job);
@@ -3538,6 +4887,8 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
                /* the mbox completion handler can now be run */
                spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
                job->job_done(job);
+               if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_PORT)
+                       phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_ABTS;
                break;
        case TYPE_MENLO:
                menlo = &dd_data->context_un.menlo;
index b542aca6f5ae37e2698df0023c7bc13060d825d5..c8c2b47ea886f14cb992ec486108a8fafea2adf9 100644 (file)
  * These are the vendor unique structures passed in using the bsg
  * FC_BSG_HST_VENDOR message code type.
  */
-#define LPFC_BSG_VENDOR_SET_CT_EVENT   1
-#define LPFC_BSG_VENDOR_GET_CT_EVENT   2
-#define LPFC_BSG_VENDOR_SEND_MGMT_RESP 3
-#define LPFC_BSG_VENDOR_DIAG_MODE      4
-#define LPFC_BSG_VENDOR_DIAG_TEST      5
-#define LPFC_BSG_VENDOR_GET_MGMT_REV   6
-#define LPFC_BSG_VENDOR_MBOX           7
-#define LPFC_BSG_VENDOR_MENLO_CMD      8
-#define LPFC_BSG_VENDOR_MENLO_DATA     9
+#define LPFC_BSG_VENDOR_SET_CT_EVENT           1
+#define LPFC_BSG_VENDOR_GET_CT_EVENT           2
+#define LPFC_BSG_VENDOR_SEND_MGMT_RESP         3
+#define LPFC_BSG_VENDOR_DIAG_MODE              4
+#define LPFC_BSG_VENDOR_DIAG_RUN_LOOPBACK      5
+#define LPFC_BSG_VENDOR_GET_MGMT_REV           6
+#define LPFC_BSG_VENDOR_MBOX                   7
+#define LPFC_BSG_VENDOR_MENLO_CMD              8
+#define LPFC_BSG_VENDOR_MENLO_DATA             9
+#define LPFC_BSG_VENDOR_DIAG_MODE_END          10
+#define LPFC_BSG_VENDOR_LINK_DIAG_TEST         11
 
 struct set_ct_event {
        uint32_t command;
@@ -67,10 +69,25 @@ struct diag_mode_set {
        uint32_t timeout;
 };
 
+struct sli4_link_diag {
+       uint32_t command;
+       uint32_t timeout;
+       uint32_t test_id;
+       uint32_t loops;
+       uint32_t test_version;
+       uint32_t error_action;
+};
+
 struct diag_mode_test {
        uint32_t command;
 };
 
+struct diag_status {
+       uint32_t mbox_status;
+       uint32_t shdr_status;
+       uint32_t shdr_add_status;
+};
+
 #define LPFC_WWNN_TYPE         0
 #define LPFC_WWPN_TYPE         1
 
@@ -92,11 +109,15 @@ struct get_mgmt_rev_reply {
 };
 
 #define BSG_MBOX_SIZE 4096 /* mailbox command plus extended data */
+
+/* BSG mailbox request header */
 struct dfc_mbox_req {
        uint32_t command;
        uint32_t mbOffset;
        uint32_t inExtWLen;
        uint32_t outExtWLen;
+       uint32_t extMboxTag;
+       uint32_t extSeqNum;
 };
 
 /* Used for menlo command or menlo data. The xri is only used for menlo data */
@@ -171,7 +192,7 @@ struct lpfc_sli_config_mse {
 #define lpfc_mbox_sli_config_mse_len_WORD      buf_len
 };
 
-struct lpfc_sli_config_subcmd_hbd {
+struct lpfc_sli_config_hbd {
        uint32_t buf_len;
 #define lpfc_mbox_sli_config_ecmn_hbd_len_SHIFT        0
 #define lpfc_mbox_sli_config_ecmn_hbd_len_MASK 0xffffff
@@ -194,21 +215,39 @@ struct lpfc_sli_config_hdr {
        uint32_t reserved5;
 };
 
-struct lpfc_sli_config_generic {
+struct lpfc_sli_config_emb0_subsys {
        struct lpfc_sli_config_hdr      sli_config_hdr;
 #define LPFC_MBX_SLI_CONFIG_MAX_MSE     19
        struct lpfc_sli_config_mse      mse[LPFC_MBX_SLI_CONFIG_MAX_MSE];
+       uint32_t padding;
+       uint32_t word64;
+#define lpfc_emb0_subcmnd_opcode_SHIFT 0
+#define lpfc_emb0_subcmnd_opcode_MASK  0xff
+#define lpfc_emb0_subcmnd_opcode_WORD  word64
+#define lpfc_emb0_subcmnd_subsys_SHIFT 8
+#define lpfc_emb0_subcmnd_subsys_MASK  0xff
+#define lpfc_emb0_subcmnd_subsys_WORD  word64
+/* Subsystem FCOE (0x0C) OpCodes */
+#define SLI_CONFIG_SUBSYS_FCOE         0x0C
+#define FCOE_OPCODE_READ_FCF           0x08
+#define FCOE_OPCODE_ADD_FCF            0x09
 };
 
-struct lpfc_sli_config_subcmnd {
+struct lpfc_sli_config_emb1_subsys {
        struct lpfc_sli_config_hdr      sli_config_hdr;
        uint32_t word6;
-#define lpfc_subcmnd_opcode_SHIFT      0
-#define lpfc_subcmnd_opcode_MASK       0xff
-#define lpfc_subcmnd_opcode_WORD       word6
-#define lpfc_subcmnd_subsys_SHIFT      8
-#define lpfc_subcmnd_subsys_MASK       0xff
-#define lpfc_subcmnd_subsys_WORD       word6
+#define lpfc_emb1_subcmnd_opcode_SHIFT 0
+#define lpfc_emb1_subcmnd_opcode_MASK  0xff
+#define lpfc_emb1_subcmnd_opcode_WORD  word6
+#define lpfc_emb1_subcmnd_subsys_SHIFT 8
+#define lpfc_emb1_subcmnd_subsys_MASK  0xff
+#define lpfc_emb1_subcmnd_subsys_WORD  word6
+/* Subsystem COMN (0x01) OpCodes */
+#define SLI_CONFIG_SUBSYS_COMN         0x01
+#define COMN_OPCODE_READ_OBJECT                0xAB
+#define COMN_OPCODE_WRITE_OBJECT       0xAC
+#define COMN_OPCODE_READ_OBJECT_LIST   0xAD
+#define COMN_OPCODE_DELETE_OBJECT      0xAE
        uint32_t timeout;
        uint32_t request_length;
        uint32_t word9;
@@ -222,8 +261,8 @@ struct lpfc_sli_config_subcmnd {
        uint32_t rd_offset;
        uint32_t obj_name[26];
        uint32_t hbd_count;
-#define LPFC_MBX_SLI_CONFIG_MAX_HBD    10
-       struct lpfc_sli_config_subcmd_hbd   hbd[LPFC_MBX_SLI_CONFIG_MAX_HBD];
+#define LPFC_MBX_SLI_CONFIG_MAX_HBD    8
+       struct lpfc_sli_config_hbd      hbd[LPFC_MBX_SLI_CONFIG_MAX_HBD];
 };
 
 struct lpfc_sli_config_mbox {
@@ -235,7 +274,11 @@ struct lpfc_sli_config_mbox {
 #define lpfc_mqe_command_MASK          0x000000FF
 #define lpfc_mqe_command_WORD          word0
        union {
-               struct lpfc_sli_config_generic  sli_config_generic;
-               struct lpfc_sli_config_subcmnd  sli_config_subcmnd;
+               struct lpfc_sli_config_emb0_subsys sli_config_emb0_subsys;
+               struct lpfc_sli_config_emb1_subsys sli_config_emb1_subsys;
        } un;
 };
+
+/* driver only */
+#define SLI_CONFIG_NOT_HANDLED         0
+#define SLI_CONFIG_HANDLED             1
index f0b332f4eedb1135825a18cd0bfcc526bbe92829..fc20c247f36b7242b1643d0debef3785f1e95d3d 100644 (file)
@@ -55,6 +55,8 @@ void lpfc_request_features(struct lpfc_hba *, struct lpfcMboxq *);
 void lpfc_supported_pages(struct lpfcMboxq *);
 void lpfc_pc_sli4_params(struct lpfcMboxq *);
 int lpfc_pc_sli4_params_get(struct lpfc_hba *, LPFC_MBOXQ_t *);
+int lpfc_sli4_mbox_rsrc_extent(struct lpfc_hba *, struct lpfcMboxq *,
+                          uint16_t, uint16_t, bool);
 int lpfc_get_sli4_parameters(struct lpfc_hba *, LPFC_MBOXQ_t *);
 struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
 void lpfc_cleanup_rcv_buffers(struct lpfc_vport *);
@@ -171,6 +173,7 @@ void lpfc_delayed_disc_tmo(unsigned long);
 void lpfc_delayed_disc_timeout_handler(struct lpfc_vport *);
 
 int lpfc_config_port_prep(struct lpfc_hba *);
+void lpfc_update_vport_wwn(struct lpfc_vport *vport);
 int lpfc_config_port_post(struct lpfc_hba *);
 int lpfc_hba_down_prep(struct lpfc_hba *);
 int lpfc_hba_down_post(struct lpfc_hba *);
@@ -365,6 +368,10 @@ extern void lpfc_debugfs_slow_ring_trc(struct lpfc_hba *, char *, uint32_t,
        uint32_t, uint32_t);
 extern struct lpfc_hbq_init *lpfc_hbq_defs[];
 
+/* SLI4 if_type 2 externs. */
+int lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *);
+int lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *);
+
 /* externs BlockGuard */
 extern char *_dump_buf_data;
 extern unsigned long _dump_buf_data_order;
@@ -429,3 +436,6 @@ void lpfc_cleanup_wt_rrqs(struct lpfc_hba *);
 void lpfc_cleanup_vports_rrqs(struct lpfc_vport *, struct lpfc_nodelist *);
 struct lpfc_node_rrq *lpfc_get_active_rrq(struct lpfc_vport *, uint16_t,
        uint32_t);
+int lpfc_wr_object(struct lpfc_hba *, struct list_head *, uint32_t, uint32_t *);
+/* functions to support SR-IOV */
+int lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *, int);
index d9edfd90d7ffc5705abd816d6a14ff21bf349a7b..779b88e1469d01a8d2bcf8dbe28d2faeb7070161 100644 (file)
@@ -352,6 +352,8 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
        icmd->ulpLe = 1;
        icmd->ulpClass = CLASS3;
        icmd->ulpContext = ndlp->nlp_rpi;
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               icmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
 
        if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
                /* For GEN_REQUEST64_CR, use the RPI */
index c93fca058603447c10208f30659b628d77f0da27..ffe82d169b404b16dd7eb1c81d6d774a8fedafbe 100644 (file)
@@ -1665,7 +1665,8 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes,
        /* Get fast-path complete queue information */
        len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
                        "Fast-path FCP CQ information:\n");
-       for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) {
+       fcp_qidx = 0;
+       do {
                len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
                                "Associated EQID[%02d]:\n",
                                phba->sli4_hba.fcp_cq[fcp_qidx]->assoc_qid);
@@ -1678,7 +1679,7 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes,
                                phba->sli4_hba.fcp_cq[fcp_qidx]->entry_size,
                                phba->sli4_hba.fcp_cq[fcp_qidx]->host_index,
                                phba->sli4_hba.fcp_cq[fcp_qidx]->hba_index);
-       }
+       } while (++fcp_qidx < phba->cfg_fcp_eq_count);
        len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n");
 
        /* Get mailbox queue information */
@@ -2012,7 +2013,8 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf,
                        goto pass_check;
                }
                /* FCP complete queue */
-               for (qidx = 0; qidx < phba->cfg_fcp_eq_count; qidx++) {
+               qidx = 0;
+               do {
                        if (phba->sli4_hba.fcp_cq[qidx]->queue_id == queid) {
                                /* Sanity check */
                                rc = lpfc_idiag_que_param_check(
@@ -2024,7 +2026,7 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf,
                                                phba->sli4_hba.fcp_cq[qidx];
                                goto pass_check;
                        }
-               }
+               } while (++qidx < phba->cfg_fcp_eq_count);
                goto error_out;
                break;
        case LPFC_IDIAG_MQ:
index e2c452467c8bdb4582fc0487905bcf08b02753ec..32a084534f3e08898259d0360a9002acf121e8b1 100644 (file)
@@ -250,7 +250,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
                icmd->un.elsreq64.myID = vport->fc_myDID;
 
                /* For ELS_REQUEST64_CR, use the VPI by default */
-               icmd->ulpContext = vport->vpi + phba->vpi_base;
+               icmd->ulpContext = phba->vpi_ids[vport->vpi];
                icmd->ulpCt_h = 0;
                /* The CT field must be 0=INVALID_RPI for the ECHO cmd */
                if (elscmd == ELS_CMD_ECHO)
@@ -454,6 +454,7 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
                rc = -ENOMEM;
                goto fail_free_dmabuf;
        }
+
        mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!mboxq) {
                rc = -ENOMEM;
@@ -6585,6 +6586,26 @@ lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
 {
        struct lpfc_vport *vport;
        unsigned long flags;
+       int i;
+
+       /* The physical ports are always vpi 0 - translate is unnecessary. */
+       if (vpi > 0) {
+               /*
+                * Translate the physical vpi to the logical vpi.  The
+                * vport stores the logical vpi.
+                */
+               for (i = 0; i < phba->max_vpi; i++) {
+                       if (vpi == phba->vpi_ids[i])
+                               break;
+               }
+
+               if (i >= phba->max_vpi) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+                                        "2936 Could not find Vport mapped "
+                                        "to vpi %d\n", vpi);
+                       return NULL;
+               }
+       }
 
        spin_lock_irqsave(&phba->hbalock, flags);
        list_for_each_entry(vport, &phba->port_list, listentry) {
@@ -6641,8 +6662,9 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                        vport = phba->pport;
                else
                        vport = lpfc_find_vport_by_vpid(phba,
-                               icmd->unsli3.rcvsli3.vpi - phba->vpi_base);
+                                               icmd->unsli3.rcvsli3.vpi);
        }
+
        /* If there are no BDEs associated
         * with this IOCB, there is nothing to do.
         */
@@ -7222,7 +7244,7 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                elsiocb->iocb.ulpCt_h = (SLI4_CT_VPI >> 1) & 1;
                elsiocb->iocb.ulpCt_l = SLI4_CT_VPI & 1 ;
                /* Set the ulpContext to the vpi */
-               elsiocb->iocb.ulpContext = vport->vpi + phba->vpi_base;
+               elsiocb->iocb.ulpContext = phba->vpi_ids[vport->vpi];
        } else {
                /* For FDISC, Let FDISC rsp set the NPortID for this VPI */
                icmd->ulpCt_h = 1;
index 7a35df5e2038c003c3447e112df873beb25afa33..18d0dbfda2bcf8100b2dc5af25bc8dc5bc778370 100644 (file)
@@ -881,7 +881,7 @@ lpfc_linkdown(struct lpfc_hba *phba)
        /* Clean up any firmware default rpi's */
        mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (mb) {
-               lpfc_unreg_did(phba, 0xffff, 0xffffffff, mb);
+               lpfc_unreg_did(phba, 0xffff, LPFC_UNREG_ALL_DFLT_RPIS, mb);
                mb->vport = vport;
                mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
                if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT)
@@ -2690,16 +2690,7 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 
        memcpy((uint8_t *) &vport->fc_sparam, (uint8_t *) mp->virt,
               sizeof (struct serv_parm));
-       if (phba->cfg_soft_wwnn)
-               u64_to_wwn(phba->cfg_soft_wwnn,
-                          vport->fc_sparam.nodeName.u.wwn);
-       if (phba->cfg_soft_wwpn)
-               u64_to_wwn(phba->cfg_soft_wwpn,
-                          vport->fc_sparam.portName.u.wwn);
-       memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName,
-              sizeof(vport->fc_nodename));
-       memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
-              sizeof(vport->fc_portname));
+       lpfc_update_vport_wwn(vport);
        if (vport->port_type == LPFC_PHYSICAL_PORT) {
                memcpy(&phba->wwnn, &vport->fc_nodename, sizeof(phba->wwnn));
                memcpy(&phba->wwpn, &vport->fc_portname, sizeof(phba->wwnn));
@@ -3430,7 +3421,8 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                return;
        }
 
-       ndlp->nlp_rpi = mb->un.varWords[0];
+       if (phba->sli_rev < LPFC_SLI_REV4)
+               ndlp->nlp_rpi = mb->un.varWords[0];
        ndlp->nlp_flag |= NLP_RPI_REGISTERED;
        ndlp->nlp_type |= NLP_FABRIC;
        lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
@@ -3504,7 +3496,8 @@ out:
                return;
        }
 
-       ndlp->nlp_rpi = mb->un.varWords[0];
+       if (phba->sli_rev < LPFC_SLI_REV4)
+               ndlp->nlp_rpi = mb->un.varWords[0];
        ndlp->nlp_flag |= NLP_RPI_REGISTERED;
        ndlp->nlp_type |= NLP_FABRIC;
        lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
@@ -3591,7 +3584,6 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
        if (ndlp->nlp_type & NLP_FCP_INITIATOR)
                rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
 
-
        if (rport_ids.roles !=  FC_RPORT_ROLE_UNKNOWN)
                fc_remote_port_rolechg(rport, rport_ids.roles);
 
@@ -4106,11 +4098,16 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
        struct lpfc_hba *phba = vport->phba;
        LPFC_MBOXQ_t    *mbox;
        int rc;
+       uint16_t rpi;
 
        if (ndlp->nlp_flag & NLP_RPI_REGISTERED) {
                mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
                if (mbox) {
-                       lpfc_unreg_login(phba, vport->vpi, ndlp->nlp_rpi, mbox);
+                       /* SLI4 ports require the physical rpi value. */
+                       rpi = ndlp->nlp_rpi;
+                       if (phba->sli_rev == LPFC_SLI_REV4)
+                               rpi = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
+                       lpfc_unreg_login(phba, vport->vpi, rpi, mbox);
                        mbox->vport = vport;
                        mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
                        rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
@@ -4179,7 +4176,8 @@ lpfc_unreg_all_rpis(struct lpfc_vport *vport)
 
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (mbox) {
-               lpfc_unreg_login(phba, vport->vpi, 0xffff, mbox);
+               lpfc_unreg_login(phba, vport->vpi, LPFC_UNREG_ALL_RPIS_VPORT,
+                                mbox);
                mbox->vport = vport;
                mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
                mbox->context1 = NULL;
@@ -4203,7 +4201,8 @@ lpfc_unreg_default_rpis(struct lpfc_vport *vport)
 
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (mbox) {
-               lpfc_unreg_did(phba, vport->vpi, 0xffffffff, mbox);
+               lpfc_unreg_did(phba, vport->vpi, LPFC_UNREG_ALL_DFLT_RPIS,
+                              mbox);
                mbox->vport = vport;
                mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
                mbox->context1 = NULL;
@@ -4653,10 +4652,7 @@ lpfc_disc_start(struct lpfc_vport *vport)
        if (num_sent)
                return;
 
-       /*
-        * For SLI3, cmpl_reg_vpi will set port_state to READY, and
-        * continue discovery.
-        */
+       /* Register the VPI for SLI3, NON-NPIV only. */
        if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
            !(vport->fc_flag & FC_PT2PT) &&
            !(vport->fc_flag & FC_RSCN_MODE) &&
@@ -4943,7 +4939,7 @@ restart_disc:
                if (phba->sli_rev < LPFC_SLI_REV4) {
                        if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
                                lpfc_issue_reg_vpi(phba, vport);
-                       else  { /* NPIV Not enabled */
+                       else  {
                                lpfc_issue_clear_la(phba, vport);
                                vport->port_state = LPFC_VPORT_READY;
                        }
@@ -5069,7 +5065,8 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        pmb->context1 = NULL;
        pmb->context2 = NULL;
 
-       ndlp->nlp_rpi = mb->un.varWords[0];
+       if (phba->sli_rev < LPFC_SLI_REV4)
+               ndlp->nlp_rpi = mb->un.varWords[0];
        ndlp->nlp_flag |= NLP_RPI_REGISTERED;
        ndlp->nlp_type |= NLP_FABRIC;
        lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
@@ -5354,6 +5351,17 @@ lpfc_fcf_inuse(struct lpfc_hba *phba)
        for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
                shost = lpfc_shost_from_vport(vports[i]);
                spin_lock_irq(shost->host_lock);
+               /*
+                * IF the CVL_RCVD bit is not set then we have sent the
+                * flogi.
+                * If dev_loss fires while we are waiting we do not want to
+                * unreg the fcf.
+                */
+               if (!(vports[i]->fc_flag & FC_VPORT_CVL_RCVD)) {
+                       spin_unlock_irq(shost->host_lock);
+                       ret =  1;
+                       goto out;
+               }
                list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) {
                        if (NLP_CHK_NODE_ACT(ndlp) && ndlp->rport &&
                          (ndlp->rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
index 86b6f7e6686a9b7c370e9cddd2e43c6aaacdec27..9059524cf225410d71041a0555c3432ba2e0d734 100644 (file)
@@ -64,6 +64,8 @@
 #define SLI3_IOCB_CMD_SIZE     128
 #define SLI3_IOCB_RSP_SIZE     64
 
+#define LPFC_UNREG_ALL_RPIS_VPORT      0xffff
+#define LPFC_UNREG_ALL_DFLT_RPIS       0xffffffff
 
 /* vendor ID used in SCSI netlink calls */
 #define LPFC_NL_VENDOR_ID (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX)
@@ -903,6 +905,8 @@ struct RRQ {                        /* Structure is in Big Endian format */
 #define rrq_rxid_WORD          rrq_exchg
 };
 
+#define LPFC_MAX_VFN_PER_PFN   255 /* Maximum VFs allowed per ARI */
+#define LPFC_DEF_VFN_PER_PFN   0   /* Default VFs due to platform limitation*/
 
 struct RTV_RSP {               /* Structure is in Big Endian format */
        uint32_t ratov;
@@ -1199,7 +1203,9 @@ typedef struct {
 #define PCI_DEVICE_ID_BALIUS        0xe131
 #define PCI_DEVICE_ID_PROTEUS_PF    0xe180
 #define PCI_DEVICE_ID_LANCER_FC     0xe200
+#define PCI_DEVICE_ID_LANCER_FC_VF  0xe208
 #define PCI_DEVICE_ID_LANCER_FCOE   0xe260
+#define PCI_DEVICE_ID_LANCER_FCOE_VF 0xe268
 #define PCI_DEVICE_ID_SAT_SMB       0xf011
 #define PCI_DEVICE_ID_SAT_MID       0xf015
 #define PCI_DEVICE_ID_RFLY          0xf095
@@ -3021,7 +3027,7 @@ typedef struct {
 #define MAILBOX_EXT_SIZE       (MAILBOX_EXT_WSIZE * sizeof(uint32_t))
 #define MAILBOX_HBA_EXT_OFFSET  0x100
 /* max mbox xmit size is a page size for sysfs IO operations */
-#define MAILBOX_MAX_XMIT_SIZE   PAGE_SIZE
+#define MAILBOX_SYSFS_MAX      4096
 
 typedef union {
        uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; /* first word is type/
index 4dff668ebdadbc556abb8e4365546188dade41a7..11e26a26b5d1cd6bb3dc34675c0243a01ffe8a95 100644 (file)
@@ -170,6 +170,25 @@ struct lpfc_sli_intf {
 #define LPFC_PCI_FUNC3         3
 #define LPFC_PCI_FUNC4         4
 
+/* SLI4 interface type-2 control register offsets */
+#define LPFC_CTL_PORT_SEM_OFFSET       0x400
+#define LPFC_CTL_PORT_STA_OFFSET       0x404
+#define LPFC_CTL_PORT_CTL_OFFSET       0x408
+#define LPFC_CTL_PORT_ER1_OFFSET       0x40C
+#define LPFC_CTL_PORT_ER2_OFFSET       0x410
+#define LPFC_CTL_PDEV_CTL_OFFSET       0x414
+
+/* Some SLI4 interface type-2 PDEV_CTL register bits */
+#define LPFC_CTL_PDEV_CTL_DRST         0x00000001
+#define LPFC_CTL_PDEV_CTL_FRST         0x00000002
+#define LPFC_CTL_PDEV_CTL_DD           0x00000004
+#define LPFC_CTL_PDEV_CTL_LC           0x00000008
+#define LPFC_CTL_PDEV_CTL_FRL_ALL      0x00
+#define LPFC_CTL_PDEV_CTL_FRL_FC_FCOE  0x10
+#define LPFC_CTL_PDEV_CTL_FRL_NIC      0x20
+
+#define LPFC_FW_DUMP_REQUEST    (LPFC_CTL_PDEV_CTL_DD | LPFC_CTL_PDEV_CTL_FRST)
+
 /* Active interrupt test count */
 #define LPFC_ACT_INTR_CNT      4
 
@@ -210,9 +229,26 @@ struct ulp_bde64 {
 
 struct lpfc_sli4_flags {
        uint32_t word0;
-#define lpfc_fip_flag_SHIFT 0
-#define lpfc_fip_flag_MASK 0x00000001
-#define lpfc_fip_flag_WORD word0
+#define lpfc_idx_rsrc_rdy_SHIFT                0
+#define lpfc_idx_rsrc_rdy_MASK         0x00000001
+#define lpfc_idx_rsrc_rdy_WORD         word0
+#define LPFC_IDX_RSRC_RDY              1
+#define lpfc_xri_rsrc_rdy_SHIFT                1
+#define lpfc_xri_rsrc_rdy_MASK         0x00000001
+#define lpfc_xri_rsrc_rdy_WORD         word0
+#define LPFC_XRI_RSRC_RDY              1
+#define lpfc_rpi_rsrc_rdy_SHIFT                2
+#define lpfc_rpi_rsrc_rdy_MASK         0x00000001
+#define lpfc_rpi_rsrc_rdy_WORD         word0
+#define LPFC_RPI_RSRC_RDY              1
+#define lpfc_vpi_rsrc_rdy_SHIFT                3
+#define lpfc_vpi_rsrc_rdy_MASK         0x00000001
+#define lpfc_vpi_rsrc_rdy_WORD         word0
+#define LPFC_VPI_RSRC_RDY              1
+#define lpfc_vfi_rsrc_rdy_SHIFT                4
+#define lpfc_vfi_rsrc_rdy_MASK         0x00000001
+#define lpfc_vfi_rsrc_rdy_WORD         word0
+#define LPFC_VFI_RSRC_RDY              1
 };
 
 struct sli4_bls_rsp {
@@ -739,6 +775,12 @@ union lpfc_sli4_cfg_shdr {
 #define lpfc_mbox_hdr_version_SHIFT    0
 #define lpfc_mbox_hdr_version_MASK     0x000000FF
 #define lpfc_mbox_hdr_version_WORD     word9
+#define lpfc_mbox_hdr_pf_num_SHIFT     16
+#define lpfc_mbox_hdr_pf_num_MASK      0x000000FF
+#define lpfc_mbox_hdr_pf_num_WORD      word9
+#define lpfc_mbox_hdr_vh_num_SHIFT     24
+#define lpfc_mbox_hdr_vh_num_MASK      0x000000FF
+#define lpfc_mbox_hdr_vh_num_WORD      word9
 #define LPFC_Q_CREATE_VERSION_2        2
 #define LPFC_Q_CREATE_VERSION_1        1
 #define LPFC_Q_CREATE_VERSION_0        0
@@ -766,12 +808,22 @@ union lpfc_sli4_cfg_shdr {
        } response;
 };
 
-/* Mailbox structures */
+/* Mailbox Header structures.
+ * struct mbox_header is defined for first generation SLI4_CFG mailbox
+ * calls deployed for BE-based ports.
+ *
+ * struct sli4_mbox_header is defined for second generation SLI4
+ * ports that don't deploy the SLI4_CFG mechanism.
+ */
 struct mbox_header {
        struct lpfc_sli4_cfg_mhdr cfg_mhdr;
        union  lpfc_sli4_cfg_shdr cfg_shdr;
 };
 
+#define LPFC_EXTENT_LOCAL              0
+#define LPFC_TIMEOUT_DEFAULT           0
+#define LPFC_EXTENT_VERSION_DEFAULT    0
+
 /* Subsystem Definitions */
 #define LPFC_MBOX_SUBSYSTEM_COMMON     0x1
 #define LPFC_MBOX_SUBSYSTEM_FCOE       0xC
@@ -794,6 +846,13 @@ struct mbox_header {
 #define LPFC_MBOX_OPCODE_QUERY_FW_CFG          0x3A
 #define LPFC_MBOX_OPCODE_FUNCTION_RESET                0x3D
 #define LPFC_MBOX_OPCODE_MQ_CREATE_EXT         0x5A
+#define LPFC_MBOX_OPCODE_GET_RSRC_EXTENT_INFO  0x9A
+#define LPFC_MBOX_OPCODE_GET_ALLOC_RSRC_EXTENT 0x9B
+#define LPFC_MBOX_OPCODE_ALLOC_RSRC_EXTENT     0x9C
+#define LPFC_MBOX_OPCODE_DEALLOC_RSRC_EXTENT   0x9D
+#define LPFC_MBOX_OPCODE_GET_FUNCTION_CONFIG    0xA0
+#define LPFC_MBOX_OPCODE_GET_PROFILE_CONFIG    0xA4
+#define LPFC_MBOX_OPCODE_WRITE_OBJECT          0xAC
 #define LPFC_MBOX_OPCODE_GET_SLI4_PARAMETERS   0xB5
 
 /* FCoE Opcodes */
@@ -808,6 +867,8 @@ struct mbox_header {
 #define LPFC_MBOX_OPCODE_FCOE_DELETE_FCF               0x0A
 #define LPFC_MBOX_OPCODE_FCOE_POST_HDR_TEMPLATE                0x0B
 #define LPFC_MBOX_OPCODE_FCOE_REDISCOVER_FCF           0x10
+#define LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE          0x22
+#define LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK       0x23
 
 /* Mailbox command structures */
 struct eq_context {
@@ -1210,6 +1271,187 @@ struct lpfc_mbx_mq_destroy {
        } u;
 };
 
+/* Start Gen 2 SLI4 Mailbox definitions: */
+
+/* Define allocate-ready Gen 2 SLI4 FCoE Resource Extent Types. */
+#define LPFC_RSC_TYPE_FCOE_VFI 0x20
+#define LPFC_RSC_TYPE_FCOE_VPI 0x21
+#define LPFC_RSC_TYPE_FCOE_RPI 0x22
+#define LPFC_RSC_TYPE_FCOE_XRI 0x23
+
+struct lpfc_mbx_get_rsrc_extent_info {
+       struct mbox_header header;
+       union {
+               struct {
+                       uint32_t word4;
+#define lpfc_mbx_get_rsrc_extent_info_type_SHIFT       0
+#define lpfc_mbx_get_rsrc_extent_info_type_MASK                0x0000FFFF
+#define lpfc_mbx_get_rsrc_extent_info_type_WORD                word4
+               } req;
+               struct {
+                       uint32_t word4;
+#define lpfc_mbx_get_rsrc_extent_info_cnt_SHIFT                0
+#define lpfc_mbx_get_rsrc_extent_info_cnt_MASK         0x0000FFFF
+#define lpfc_mbx_get_rsrc_extent_info_cnt_WORD         word4
+#define lpfc_mbx_get_rsrc_extent_info_size_SHIFT       16
+#define lpfc_mbx_get_rsrc_extent_info_size_MASK                0x0000FFFF
+#define lpfc_mbx_get_rsrc_extent_info_size_WORD                word4
+               } rsp;
+       } u;
+};
+
+struct lpfc_id_range {
+       uint32_t word5;
+#define lpfc_mbx_rsrc_id_word4_0_SHIFT 0
+#define lpfc_mbx_rsrc_id_word4_0_MASK  0x0000FFFF
+#define lpfc_mbx_rsrc_id_word4_0_WORD  word5
+#define lpfc_mbx_rsrc_id_word4_1_SHIFT 16
+#define lpfc_mbx_rsrc_id_word4_1_MASK  0x0000FFFF
+#define lpfc_mbx_rsrc_id_word4_1_WORD  word5
+};
+
+struct lpfc_mbx_set_link_diag_state {
+       struct mbox_header header;
+       union {
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_set_diag_state_diag_SHIFT     0
+#define lpfc_mbx_set_diag_state_diag_MASK      0x00000001
+#define lpfc_mbx_set_diag_state_diag_WORD      word0
+#define lpfc_mbx_set_diag_state_link_num_SHIFT 16
+#define lpfc_mbx_set_diag_state_link_num_MASK  0x0000003F
+#define lpfc_mbx_set_diag_state_link_num_WORD  word0
+#define lpfc_mbx_set_diag_state_link_type_SHIFT 22
+#define lpfc_mbx_set_diag_state_link_type_MASK 0x00000003
+#define lpfc_mbx_set_diag_state_link_type_WORD word0
+               } req;
+               struct {
+                       uint32_t word0;
+               } rsp;
+       } u;
+};
+
+struct lpfc_mbx_set_link_diag_loopback {
+       struct mbox_header header;
+       union {
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_set_diag_lpbk_type_SHIFT      0
+#define lpfc_mbx_set_diag_lpbk_type_MASK       0x00000001
+#define lpfc_mbx_set_diag_lpbk_type_WORD       word0
+#define LPFC_DIAG_LOOPBACK_TYPE_DISABLE                0x0
+#define LPFC_DIAG_LOOPBACK_TYPE_INTERNAL       0x1
+#define LPFC_DIAG_LOOPBACK_TYPE_EXTERNAL       0x2
+#define lpfc_mbx_set_diag_lpbk_link_num_SHIFT  16
+#define lpfc_mbx_set_diag_lpbk_link_num_MASK   0x0000003F
+#define lpfc_mbx_set_diag_lpbk_link_num_WORD   word0
+#define lpfc_mbx_set_diag_lpbk_link_type_SHIFT 22
+#define lpfc_mbx_set_diag_lpbk_link_type_MASK  0x00000003
+#define lpfc_mbx_set_diag_lpbk_link_type_WORD  word0
+               } req;
+               struct {
+                       uint32_t word0;
+               } rsp;
+       } u;
+};
+
+struct lpfc_mbx_run_link_diag_test {
+       struct mbox_header header;
+       union {
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_run_diag_test_link_num_SHIFT  16
+#define lpfc_mbx_run_diag_test_link_num_MASK   0x0000003F
+#define lpfc_mbx_run_diag_test_link_num_WORD   word0
+#define lpfc_mbx_run_diag_test_link_type_SHIFT 22
+#define lpfc_mbx_run_diag_test_link_type_MASK  0x00000003
+#define lpfc_mbx_run_diag_test_link_type_WORD  word0
+                       uint32_t word1;
+#define lpfc_mbx_run_diag_test_test_id_SHIFT   0
+#define lpfc_mbx_run_diag_test_test_id_MASK    0x0000FFFF
+#define lpfc_mbx_run_diag_test_test_id_WORD    word1
+#define lpfc_mbx_run_diag_test_loops_SHIFT     16
+#define lpfc_mbx_run_diag_test_loops_MASK      0x0000FFFF
+#define lpfc_mbx_run_diag_test_loops_WORD      word1
+                       uint32_t word2;
+#define lpfc_mbx_run_diag_test_test_ver_SHIFT  0
+#define lpfc_mbx_run_diag_test_test_ver_MASK   0x0000FFFF
+#define lpfc_mbx_run_diag_test_test_ver_WORD   word2
+#define lpfc_mbx_run_diag_test_err_act_SHIFT   16
+#define lpfc_mbx_run_diag_test_err_act_MASK    0x000000FF
+#define lpfc_mbx_run_diag_test_err_act_WORD    word2
+               } req;
+               struct {
+                       uint32_t word0;
+               } rsp;
+       } u;
+};
+
+/*
+ * struct lpfc_mbx_alloc_rsrc_extents:
+ * A mbox is generically 256 bytes long. An SLI4_CONFIG mailbox requires
+ * 6 words of header + 4 words of shared subcommand header +
+ * 1 words of Extent-Opcode-specific header = 11 words or 44 bytes total.
+ *
+ * An embedded version of SLI4_CONFIG therefore has 256 - 44 = 212 bytes
+ * for extents payload.
+ *
+ * 212/2 (bytes per extent) = 106 extents.
+ * 106/2 (extents per word) = 53 words.
+ * lpfc_id_range id is statically size to 53.
+ *
+ * This mailbox definition is used for ALLOC or GET_ALLOCATED
+ * extent ranges.  For ALLOC, the type and cnt are required.
+ * For GET_ALLOCATED, only the type is required.
+ */
+struct lpfc_mbx_alloc_rsrc_extents {
+       struct mbox_header header;
+       union {
+               struct {
+                       uint32_t word4;
+#define lpfc_mbx_alloc_rsrc_extents_type_SHIFT 0
+#define lpfc_mbx_alloc_rsrc_extents_type_MASK  0x0000FFFF
+#define lpfc_mbx_alloc_rsrc_extents_type_WORD  word4
+#define lpfc_mbx_alloc_rsrc_extents_cnt_SHIFT  16
+#define lpfc_mbx_alloc_rsrc_extents_cnt_MASK   0x0000FFFF
+#define lpfc_mbx_alloc_rsrc_extents_cnt_WORD   word4
+               } req;
+               struct {
+                       uint32_t word4;
+#define lpfc_mbx_rsrc_cnt_SHIFT        0
+#define lpfc_mbx_rsrc_cnt_MASK 0x0000FFFF
+#define lpfc_mbx_rsrc_cnt_WORD word4
+                       struct lpfc_id_range id[53];
+               } rsp;
+       } u;
+};
+
+/*
+ * This is the non-embedded version of ALLOC or GET RSRC_EXTENTS. Word4 in this
+ * structure shares the same SHIFT/MASK/WORD defines provided in the
+ * mbx_alloc_rsrc_extents and mbx_get_alloc_rsrc_extents, word4, provided in
+ * the structures defined above.  This non-embedded structure provides for the
+ * maximum number of extents supported by the port.
+ */
+struct lpfc_mbx_nembed_rsrc_extent {
+       union  lpfc_sli4_cfg_shdr cfg_shdr;
+       uint32_t word4;
+       struct lpfc_id_range id;
+};
+
+struct lpfc_mbx_dealloc_rsrc_extents {
+       struct mbox_header header;
+       struct {
+               uint32_t word4;
+#define lpfc_mbx_dealloc_rsrc_extents_type_SHIFT       0
+#define lpfc_mbx_dealloc_rsrc_extents_type_MASK                0x0000FFFF
+#define lpfc_mbx_dealloc_rsrc_extents_type_WORD                word4
+       } req;
+
+};
+
+/* Start SLI4 FCoE specific mbox structures. */
+
 struct lpfc_mbx_post_hdr_tmpl {
        struct mbox_header header;
        uint32_t word10;
@@ -1229,7 +1471,7 @@ struct sli4_sge { /* SLI-4 */
 
        uint32_t word2;
 #define lpfc_sli4_sge_offset_SHIFT     0 /* Offset of buffer - Not used*/
-#define lpfc_sli4_sge_offset_MASK      0x00FFFFFF
+#define lpfc_sli4_sge_offset_MASK      0x1FFFFFFF
 #define lpfc_sli4_sge_offset_WORD      word2
 #define lpfc_sli4_sge_last_SHIFT       31 /* Last SEG in the SGL sets
                                                this  flag !! */
@@ -1773,61 +2015,31 @@ struct lpfc_mbx_read_rev {
 
 struct lpfc_mbx_read_config {
        uint32_t word1;
-#define lpfc_mbx_rd_conf_max_bbc_SHIFT         0
-#define lpfc_mbx_rd_conf_max_bbc_MASK          0x000000FF
-#define lpfc_mbx_rd_conf_max_bbc_WORD          word1
-#define lpfc_mbx_rd_conf_init_bbc_SHIFT                8
-#define lpfc_mbx_rd_conf_init_bbc_MASK         0x000000FF
-#define lpfc_mbx_rd_conf_init_bbc_WORD         word1
+#define lpfc_mbx_rd_conf_extnts_inuse_SHIFT    31
+#define lpfc_mbx_rd_conf_extnts_inuse_MASK     0x00000001
+#define lpfc_mbx_rd_conf_extnts_inuse_WORD     word1
        uint32_t word2;
-#define lpfc_mbx_rd_conf_nport_did_SHIFT       0
-#define lpfc_mbx_rd_conf_nport_did_MASK                0x00FFFFFF
-#define lpfc_mbx_rd_conf_nport_did_WORD                word2
 #define lpfc_mbx_rd_conf_topology_SHIFT                24
 #define lpfc_mbx_rd_conf_topology_MASK         0x000000FF
 #define lpfc_mbx_rd_conf_topology_WORD         word2
-       uint32_t word3;
-#define lpfc_mbx_rd_conf_ao_SHIFT              0
-#define lpfc_mbx_rd_conf_ao_MASK               0x00000001
-#define lpfc_mbx_rd_conf_ao_WORD               word3
-#define lpfc_mbx_rd_conf_bb_scn_SHIFT          8
-#define lpfc_mbx_rd_conf_bb_scn_MASK           0x0000000F
-#define lpfc_mbx_rd_conf_bb_scn_WORD           word3
-#define lpfc_mbx_rd_conf_cbb_scn_SHIFT         12
-#define lpfc_mbx_rd_conf_cbb_scn_MASK          0x0000000F
-#define lpfc_mbx_rd_conf_cbb_scn_WORD          word3
-#define lpfc_mbx_rd_conf_mc_SHIFT              29
-#define lpfc_mbx_rd_conf_mc_MASK               0x00000001
-#define lpfc_mbx_rd_conf_mc_WORD               word3
+       uint32_t rsvd_3;
        uint32_t word4;
 #define lpfc_mbx_rd_conf_e_d_tov_SHIFT         0
 #define lpfc_mbx_rd_conf_e_d_tov_MASK          0x0000FFFF
 #define lpfc_mbx_rd_conf_e_d_tov_WORD          word4
-       uint32_t word5;
-#define lpfc_mbx_rd_conf_lp_tov_SHIFT          0
-#define lpfc_mbx_rd_conf_lp_tov_MASK           0x0000FFFF
-#define lpfc_mbx_rd_conf_lp_tov_WORD           word5
+       uint32_t rsvd_5;
        uint32_t word6;
 #define lpfc_mbx_rd_conf_r_a_tov_SHIFT         0
 #define lpfc_mbx_rd_conf_r_a_tov_MASK          0x0000FFFF
 #define lpfc_mbx_rd_conf_r_a_tov_WORD          word6
-       uint32_t word7;
-#define lpfc_mbx_rd_conf_r_t_tov_SHIFT         0
-#define lpfc_mbx_rd_conf_r_t_tov_MASK          0x000000FF
-#define lpfc_mbx_rd_conf_r_t_tov_WORD          word7
-       uint32_t word8;
-#define lpfc_mbx_rd_conf_al_tov_SHIFT          0
-#define lpfc_mbx_rd_conf_al_tov_MASK           0x0000000F
-#define lpfc_mbx_rd_conf_al_tov_WORD           word8
+       uint32_t rsvd_7;
+       uint32_t rsvd_8;
        uint32_t word9;
 #define lpfc_mbx_rd_conf_lmt_SHIFT             0
 #define lpfc_mbx_rd_conf_lmt_MASK              0x0000FFFF
 #define lpfc_mbx_rd_conf_lmt_WORD              word9
-       uint32_t word10;
-#define lpfc_mbx_rd_conf_max_alpa_SHIFT                0
-#define lpfc_mbx_rd_conf_max_alpa_MASK         0x000000FF
-#define lpfc_mbx_rd_conf_max_alpa_WORD         word10
-       uint32_t word11_rsvd;
+       uint32_t rsvd_10;
+       uint32_t rsvd_11;
        uint32_t word12;
 #define lpfc_mbx_rd_conf_xri_base_SHIFT                0
 #define lpfc_mbx_rd_conf_xri_base_MASK         0x0000FFFF
@@ -1857,9 +2069,6 @@ struct lpfc_mbx_read_config {
 #define lpfc_mbx_rd_conf_vfi_count_MASK         0x0000FFFF
 #define lpfc_mbx_rd_conf_vfi_count_WORD         word15
        uint32_t word16;
-#define lpfc_mbx_rd_conf_fcfi_base_SHIFT       0
-#define lpfc_mbx_rd_conf_fcfi_base_MASK                0x0000FFFF
-#define lpfc_mbx_rd_conf_fcfi_base_WORD                word16
 #define lpfc_mbx_rd_conf_fcfi_count_SHIFT      16
 #define lpfc_mbx_rd_conf_fcfi_count_MASK       0x0000FFFF
 #define lpfc_mbx_rd_conf_fcfi_count_WORD       word16
@@ -2169,6 +2378,12 @@ struct lpfc_sli4_parameters {
 #define cfg_fcoe_SHIFT                         0
 #define cfg_fcoe_MASK                          0x00000001
 #define cfg_fcoe_WORD                          word12
+#define cfg_ext_SHIFT                          1
+#define cfg_ext_MASK                           0x00000001
+#define cfg_ext_WORD                           word12
+#define cfg_hdrr_SHIFT                         2
+#define cfg_hdrr_MASK                          0x00000001
+#define cfg_hdrr_WORD                          word12
 #define cfg_phwq_SHIFT                         15
 #define cfg_phwq_MASK                          0x00000001
 #define cfg_phwq_WORD                          word12
@@ -2198,6 +2413,145 @@ struct lpfc_mbx_get_sli4_parameters {
        struct lpfc_sli4_parameters sli4_parameters;
 };
 
+struct lpfc_rscr_desc_generic {
+#define LPFC_RSRC_DESC_WSIZE                   18
+       uint32_t desc[LPFC_RSRC_DESC_WSIZE];
+};
+
+struct lpfc_rsrc_desc_pcie {
+       uint32_t word0;
+#define lpfc_rsrc_desc_pcie_type_SHIFT         0
+#define lpfc_rsrc_desc_pcie_type_MASK          0x000000ff
+#define lpfc_rsrc_desc_pcie_type_WORD          word0
+#define LPFC_RSRC_DESC_TYPE_PCIE               0x40
+       uint32_t word1;
+#define lpfc_rsrc_desc_pcie_pfnum_SHIFT                0
+#define lpfc_rsrc_desc_pcie_pfnum_MASK         0x000000ff
+#define lpfc_rsrc_desc_pcie_pfnum_WORD         word1
+       uint32_t reserved;
+       uint32_t word3;
+#define lpfc_rsrc_desc_pcie_sriov_sta_SHIFT    0
+#define lpfc_rsrc_desc_pcie_sriov_sta_MASK     0x000000ff
+#define lpfc_rsrc_desc_pcie_sriov_sta_WORD     word3
+#define lpfc_rsrc_desc_pcie_pf_sta_SHIFT       8
+#define lpfc_rsrc_desc_pcie_pf_sta_MASK                0x000000ff
+#define lpfc_rsrc_desc_pcie_pf_sta_WORD                word3
+#define lpfc_rsrc_desc_pcie_pf_type_SHIFT      16
+#define lpfc_rsrc_desc_pcie_pf_type_MASK       0x000000ff
+#define lpfc_rsrc_desc_pcie_pf_type_WORD       word3
+       uint32_t word4;
+#define lpfc_rsrc_desc_pcie_nr_virtfn_SHIFT    0
+#define lpfc_rsrc_desc_pcie_nr_virtfn_MASK     0x0000ffff
+#define lpfc_rsrc_desc_pcie_nr_virtfn_WORD     word4
+};
+
+struct lpfc_rsrc_desc_fcfcoe {
+       uint32_t word0;
+#define lpfc_rsrc_desc_fcfcoe_type_SHIFT       0
+#define lpfc_rsrc_desc_fcfcoe_type_MASK                0x000000ff
+#define lpfc_rsrc_desc_fcfcoe_type_WORD                word0
+#define LPFC_RSRC_DESC_TYPE_FCFCOE             0x43
+       uint32_t word1;
+#define lpfc_rsrc_desc_fcfcoe_vfnum_SHIFT      0
+#define lpfc_rsrc_desc_fcfcoe_vfnum_MASK       0x000000ff
+#define lpfc_rsrc_desc_fcfcoe_vfnum_WORD       word1
+#define lpfc_rsrc_desc_fcfcoe_pfnum_SHIFT      16
+#define lpfc_rsrc_desc_fcfcoe_pfnum_MASK        0x000007ff
+#define lpfc_rsrc_desc_fcfcoe_pfnum_WORD        word1
+       uint32_t word2;
+#define lpfc_rsrc_desc_fcfcoe_rpi_cnt_SHIFT    0
+#define lpfc_rsrc_desc_fcfcoe_rpi_cnt_MASK     0x0000ffff
+#define lpfc_rsrc_desc_fcfcoe_rpi_cnt_WORD     word2
+#define lpfc_rsrc_desc_fcfcoe_xri_cnt_SHIFT    16
+#define lpfc_rsrc_desc_fcfcoe_xri_cnt_MASK     0x0000ffff
+#define lpfc_rsrc_desc_fcfcoe_xri_cnt_WORD     word2
+       uint32_t word3;
+#define lpfc_rsrc_desc_fcfcoe_wq_cnt_SHIFT     0
+#define lpfc_rsrc_desc_fcfcoe_wq_cnt_MASK      0x0000ffff
+#define lpfc_rsrc_desc_fcfcoe_wq_cnt_WORD      word3
+#define lpfc_rsrc_desc_fcfcoe_rq_cnt_SHIFT     16
+#define lpfc_rsrc_desc_fcfcoe_rq_cnt_MASK      0x0000ffff
+#define lpfc_rsrc_desc_fcfcoe_rq_cnt_WORD      word3
+       uint32_t word4;
+#define lpfc_rsrc_desc_fcfcoe_cq_cnt_SHIFT     0
+#define lpfc_rsrc_desc_fcfcoe_cq_cnt_MASK      0x0000ffff
+#define lpfc_rsrc_desc_fcfcoe_cq_cnt_WORD      word4
+#define lpfc_rsrc_desc_fcfcoe_vpi_cnt_SHIFT    16
+#define lpfc_rsrc_desc_fcfcoe_vpi_cnt_MASK     0x0000ffff
+#define lpfc_rsrc_desc_fcfcoe_vpi_cnt_WORD     word4
+       uint32_t word5;
+#define lpfc_rsrc_desc_fcfcoe_fcfi_cnt_SHIFT   0
+#define lpfc_rsrc_desc_fcfcoe_fcfi_cnt_MASK    0x0000ffff
+#define lpfc_rsrc_desc_fcfcoe_fcfi_cnt_WORD    word5
+#define lpfc_rsrc_desc_fcfcoe_vfi_cnt_SHIFT    16
+#define lpfc_rsrc_desc_fcfcoe_vfi_cnt_MASK     0x0000ffff
+#define lpfc_rsrc_desc_fcfcoe_vfi_cnt_WORD     word5
+       uint32_t word6;
+       uint32_t word7;
+       uint32_t word8;
+       uint32_t word9;
+       uint32_t word10;
+       uint32_t word11;
+       uint32_t word12;
+       uint32_t word13;
+#define lpfc_rsrc_desc_fcfcoe_lnk_nr_SHIFT     0
+#define lpfc_rsrc_desc_fcfcoe_lnk_nr_MASK      0x0000003f
+#define lpfc_rsrc_desc_fcfcoe_lnk_nr_WORD      word13
+#define lpfc_rsrc_desc_fcfcoe_lnk_tp_SHIFT      6
+#define lpfc_rsrc_desc_fcfcoe_lnk_tp_MASK      0x00000003
+#define lpfc_rsrc_desc_fcfcoe_lnk_tp_WORD      word13
+#define lpfc_rsrc_desc_fcfcoe_lmc_SHIFT                8
+#define lpfc_rsrc_desc_fcfcoe_lmc_MASK         0x00000001
+#define lpfc_rsrc_desc_fcfcoe_lmc_WORD         word13
+#define lpfc_rsrc_desc_fcfcoe_lld_SHIFT                9
+#define lpfc_rsrc_desc_fcfcoe_lld_MASK         0x00000001
+#define lpfc_rsrc_desc_fcfcoe_lld_WORD         word13
+#define lpfc_rsrc_desc_fcfcoe_eq_cnt_SHIFT     16
+#define lpfc_rsrc_desc_fcfcoe_eq_cnt_MASK      0x0000ffff
+#define lpfc_rsrc_desc_fcfcoe_eq_cnt_WORD      word13
+};
+
+struct lpfc_func_cfg {
+#define LPFC_RSRC_DESC_MAX_NUM                 2
+       uint32_t rsrc_desc_count;
+       struct lpfc_rscr_desc_generic desc[LPFC_RSRC_DESC_MAX_NUM];
+};
+
+struct lpfc_mbx_get_func_cfg {
+       struct mbox_header header;
+#define LPFC_CFG_TYPE_PERSISTENT_OVERRIDE      0x0
+#define LPFC_CFG_TYPE_FACTURY_DEFAULT          0x1
+#define LPFC_CFG_TYPE_CURRENT_ACTIVE           0x2
+       struct lpfc_func_cfg func_cfg;
+};
+
+struct lpfc_prof_cfg {
+#define LPFC_RSRC_DESC_MAX_NUM                 2
+       uint32_t rsrc_desc_count;
+       struct lpfc_rscr_desc_generic desc[LPFC_RSRC_DESC_MAX_NUM];
+};
+
+struct lpfc_mbx_get_prof_cfg {
+       struct mbox_header header;
+#define LPFC_CFG_TYPE_PERSISTENT_OVERRIDE      0x0
+#define LPFC_CFG_TYPE_FACTURY_DEFAULT          0x1
+#define LPFC_CFG_TYPE_CURRENT_ACTIVE           0x2
+       union {
+               struct {
+                       uint32_t word10;
+#define lpfc_mbx_get_prof_cfg_prof_id_SHIFT    0
+#define lpfc_mbx_get_prof_cfg_prof_id_MASK     0x000000ff
+#define lpfc_mbx_get_prof_cfg_prof_id_WORD     word10
+#define lpfc_mbx_get_prof_cfg_prof_tp_SHIFT    8
+#define lpfc_mbx_get_prof_cfg_prof_tp_MASK     0x00000003
+#define lpfc_mbx_get_prof_cfg_prof_tp_WORD     word10
+               } request;
+               struct {
+                       struct lpfc_prof_cfg prof_cfg;
+               } response;
+       } u;
+};
+
 /* Mailbox Completion Queue Error Messages */
 #define MB_CQE_STATUS_SUCCESS                  0x0
 #define MB_CQE_STATUS_INSUFFICIENT_PRIVILEGES  0x1
@@ -2206,6 +2560,29 @@ struct lpfc_mbx_get_sli4_parameters {
 #define MB_CEQ_STATUS_QUEUE_FLUSHING           0x4
 #define MB_CQE_STATUS_DMA_FAILED               0x5
 
+#define LPFC_MBX_WR_CONFIG_MAX_BDE             8
+struct lpfc_mbx_wr_object {
+       struct mbox_header header;
+       union {
+               struct {
+                       uint32_t word4;
+#define lpfc_wr_object_eof_SHIFT               31
+#define lpfc_wr_object_eof_MASK                        0x00000001
+#define lpfc_wr_object_eof_WORD                        word4
+#define lpfc_wr_object_write_length_SHIFT      0
+#define lpfc_wr_object_write_length_MASK       0x00FFFFFF
+#define lpfc_wr_object_write_length_WORD       word4
+                       uint32_t write_offset;
+                       uint32_t object_name[26];
+                       uint32_t bde_count;
+                       struct ulp_bde64 bde[LPFC_MBX_WR_CONFIG_MAX_BDE];
+               } request;
+               struct {
+                       uint32_t actual_write_length;
+               } response;
+       } u;
+};
+
 /* mailbox queue entry structure */
 struct lpfc_mqe {
        uint32_t word0;
@@ -2241,6 +2618,9 @@ struct lpfc_mqe {
                struct lpfc_mbx_cq_destroy cq_destroy;
                struct lpfc_mbx_wq_destroy wq_destroy;
                struct lpfc_mbx_rq_destroy rq_destroy;
+               struct lpfc_mbx_get_rsrc_extent_info rsrc_extent_info;
+               struct lpfc_mbx_alloc_rsrc_extents alloc_rsrc_extents;
+               struct lpfc_mbx_dealloc_rsrc_extents dealloc_rsrc_extents;
                struct lpfc_mbx_post_sgl_pages post_sgl_pages;
                struct lpfc_mbx_nembed_cmd nembed_cmd;
                struct lpfc_mbx_read_rev read_rev;
@@ -2252,7 +2632,13 @@ struct lpfc_mqe {
                struct lpfc_mbx_supp_pages supp_pages;
                struct lpfc_mbx_pc_sli4_params sli4_params;
                struct lpfc_mbx_get_sli4_parameters get_sli4_parameters;
+               struct lpfc_mbx_set_link_diag_state link_diag_state;
+               struct lpfc_mbx_set_link_diag_loopback link_diag_loopback;
+               struct lpfc_mbx_run_link_diag_test link_diag_test;
+               struct lpfc_mbx_get_func_cfg get_func_cfg;
+               struct lpfc_mbx_get_prof_cfg get_prof_cfg;
                struct lpfc_mbx_nop nop;
+               struct lpfc_mbx_wr_object wr_object;
        } un;
 };
 
@@ -2458,7 +2844,7 @@ struct lpfc_bmbx_create {
 #define SGL_ALIGN_SZ 64
 #define SGL_PAGE_SIZE 4096
 /* align SGL addr on a size boundary - adjust address up */
-#define NO_XRI  ((uint16_t)-1)
+#define NO_XRI  0xffff
 
 struct wqe_common {
        uint32_t word6;
@@ -2798,9 +3184,28 @@ union lpfc_wqe {
        struct gen_req64_wqe gen_req;
 };
 
+#define LPFC_GROUP_OJECT_MAGIC_NUM             0xfeaa0001
+#define LPFC_FILE_TYPE_GROUP                   0xf7
+#define LPFC_FILE_ID_GROUP                     0xa2
+struct lpfc_grp_hdr {
+       uint32_t size;
+       uint32_t magic_number;
+       uint32_t word2;
+#define lpfc_grp_hdr_file_type_SHIFT   24
+#define lpfc_grp_hdr_file_type_MASK    0x000000FF
+#define lpfc_grp_hdr_file_type_WORD    word2
+#define lpfc_grp_hdr_id_SHIFT          16
+#define lpfc_grp_hdr_id_MASK           0x000000FF
+#define lpfc_grp_hdr_id_WORD           word2
+       uint8_t rev_name[128];
+};
+
 #define FCP_COMMAND 0x0
 #define FCP_COMMAND_DATA_OUT 0x1
 #define ELS_COMMAND_NON_FIP 0xC
 #define ELS_COMMAND_FIP 0xD
 #define OTHER_COMMAND 0x8
 
+#define LPFC_FW_DUMP   1
+#define LPFC_FW_RESET  2
+#define LPFC_DV_RESET  3
index 7dda036a1af38a89e9afff7bbf1804d91c01b3c5..148b98ddbb1d9ed17103c25f9cf5d5d50fd60342 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/ctype.h>
 #include <linux/aer.h>
 #include <linux/slab.h>
+#include <linux/firmware.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
@@ -211,7 +212,6 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
        lpfc_vpd_data = kmalloc(DMP_VPD_SIZE, GFP_KERNEL);
        if (!lpfc_vpd_data)
                goto out_free_mbox;
-
        do {
                lpfc_dump_mem(phba, pmb, offset, DMP_REGION_VPD);
                rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
@@ -308,6 +308,45 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
        return;
 }
 
+/**
+ * lpfc_update_vport_wwn - Updates the fc_nodename, fc_portname,
+ *     cfg_soft_wwnn, cfg_soft_wwpn
+ * @vport: pointer to lpfc vport data structure.
+ *
+ *
+ * Return codes
+ *   None.
+ **/
+void
+lpfc_update_vport_wwn(struct lpfc_vport *vport)
+{
+       /* If the soft name exists then update it using the service params */
+       if (vport->phba->cfg_soft_wwnn)
+               u64_to_wwn(vport->phba->cfg_soft_wwnn,
+                          vport->fc_sparam.nodeName.u.wwn);
+       if (vport->phba->cfg_soft_wwpn)
+               u64_to_wwn(vport->phba->cfg_soft_wwpn,
+                          vport->fc_sparam.portName.u.wwn);
+
+       /*
+        * If the name is empty or there exists a soft name
+        * then copy the service params name, otherwise use the fc name
+        */
+       if (vport->fc_nodename.u.wwn[0] == 0 || vport->phba->cfg_soft_wwnn)
+               memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName,
+                       sizeof(struct lpfc_name));
+       else
+               memcpy(&vport->fc_sparam.nodeName, &vport->fc_nodename,
+                       sizeof(struct lpfc_name));
+
+       if (vport->fc_portname.u.wwn[0] == 0 || vport->phba->cfg_soft_wwpn)
+               memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
+                       sizeof(struct lpfc_name));
+       else
+               memcpy(&vport->fc_sparam.portName, &vport->fc_portname,
+                       sizeof(struct lpfc_name));
+}
+
 /**
  * lpfc_config_port_post - Perform lpfc initialization after config port
  * @phba: pointer to lpfc hba data structure.
@@ -377,17 +416,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
        pmb->context1 = NULL;
-
-       if (phba->cfg_soft_wwnn)
-               u64_to_wwn(phba->cfg_soft_wwnn,
-                          vport->fc_sparam.nodeName.u.wwn);
-       if (phba->cfg_soft_wwpn)
-               u64_to_wwn(phba->cfg_soft_wwpn,
-                          vport->fc_sparam.portName.u.wwn);
-       memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName,
-              sizeof (struct lpfc_name));
-       memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
-              sizeof (struct lpfc_name));
+       lpfc_update_vport_wwn(vport);
 
        /* Update the fc_host data structures with new wwn. */
        fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn);
@@ -573,7 +602,6 @@ lpfc_config_port_post(struct lpfc_hba *phba)
                        /* Clear all pending interrupts */
                        writel(0xffffffff, phba->HAregaddr);
                        readl(phba->HAregaddr); /* flush */
-
                        phba->link_state = LPFC_HBA_ERROR;
                        if (rc != MBX_BUSY)
                                mempool_free(pmb, phba->mbox_mem_pool);
@@ -1755,7 +1783,9 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
                && descp && descp[0] != '\0')
                return;
 
-       if (phba->lmt & LMT_10Gb)
+       if (phba->lmt & LMT_16Gb)
+               max_speed = 16;
+       else if (phba->lmt & LMT_10Gb)
                max_speed = 10;
        else if (phba->lmt & LMT_8Gb)
                max_speed = 8;
@@ -1922,12 +1952,13 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
                                "Fibre Channel Adapter"};
                break;
        case PCI_DEVICE_ID_LANCER_FC:
-               oneConnect = 1;
-               m = (typeof(m)){"Undefined", "PCIe", "Fibre Channel Adapter"};
+       case PCI_DEVICE_ID_LANCER_FC_VF:
+               m = (typeof(m)){"LPe16000", "PCIe", "Fibre Channel Adapter"};
                break;
        case PCI_DEVICE_ID_LANCER_FCOE:
+       case PCI_DEVICE_ID_LANCER_FCOE_VF:
                oneConnect = 1;
-               m = (typeof(m)){"Undefined", "PCIe", "FCoE"};
+               m = (typeof(m)){"OCe50100", "PCIe", "FCoE"};
                break;
        default:
                m = (typeof(m)){"Unknown", "", ""};
@@ -1936,7 +1967,8 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
 
        if (mdp && mdp[0] == '\0')
                snprintf(mdp, 79,"%s", m.name);
-       /* oneConnect hba requires special processing, they are all initiators
+       /*
+        * oneConnect hba requires special processing, they are all initiators
         * and we put the port number on the end
         */
        if (descp && descp[0] == '\0') {
@@ -2656,6 +2688,7 @@ lpfc_scsi_free(struct lpfc_hba *phba)
                kfree(io);
                phba->total_iocbq_bufs--;
        }
+
        spin_unlock_irq(&phba->hbalock);
        return 0;
 }
@@ -3612,6 +3645,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
                lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
                        "2718 Clear Virtual Link Received for VPI 0x%x"
                        " tag 0x%x\n", acqe_fip->index, acqe_fip->event_tag);
+
                vport = lpfc_find_vport_by_vpid(phba,
                                acqe_fip->index - phba->vpi_base);
                ndlp = lpfc_sli4_perform_vport_cvl(vport);
@@ -3935,6 +3969,10 @@ lpfc_enable_pci_dev(struct lpfc_hba *phba)
        pci_try_set_mwi(pdev);
        pci_save_state(pdev);
 
+       /* PCIe EEH recovery on powerpc platforms needs fundamental reset */
+       if (pci_find_capability(pdev, PCI_CAP_ID_EXP))
+               pdev->needs_freset = 1;
+
        return 0;
 
 out_disable_device:
@@ -3996,6 +4034,36 @@ lpfc_reset_hba(struct lpfc_hba *phba)
        lpfc_unblock_mgmt_io(phba);
 }
 
+/**
+ * lpfc_sli_probe_sriov_nr_virtfn - Enable a number of sr-iov virtual functions
+ * @phba: pointer to lpfc hba data structure.
+ * @nr_vfn: number of virtual functions to be enabled.
+ *
+ * This function enables the PCI SR-IOV virtual functions to a physical
+ * function. It invokes the PCI SR-IOV api with the @nr_vfn provided to
+ * enable the number of virtual functions to the physical function. As
+ * not all devices support SR-IOV, the return code from the pci_enable_sriov()
+ * API call does not considered as an error condition for most of the device.
+ **/
+int
+lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *phba, int nr_vfn)
+{
+       struct pci_dev *pdev = phba->pcidev;
+       int rc;
+
+       rc = pci_enable_sriov(pdev, nr_vfn);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "2806 Failed to enable sriov on this device "
+                               "with vfn number nr_vf:%d, rc:%d\n",
+                               nr_vfn, rc);
+       } else
+               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "2807 Successful enable sriov on this device "
+                               "with vfn number nr_vf:%d\n", nr_vfn);
+       return rc;
+}
+
 /**
  * lpfc_sli_driver_resource_setup - Setup driver internal resources for SLI3 dev.
  * @phba: pointer to lpfc hba data structure.
@@ -4011,6 +4079,7 @@ static int
 lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)
 {
        struct lpfc_sli *psli;
+       int rc;
 
        /*
         * Initialize timers used by driver
@@ -4085,6 +4154,23 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)
        if (lpfc_mem_alloc(phba, BPL_ALIGN_SZ))
                return -ENOMEM;
 
+       /*
+        * Enable sr-iov virtual functions if supported and configured
+        * through the module parameter.
+        */
+       if (phba->cfg_sriov_nr_virtfn > 0) {
+               rc = lpfc_sli_probe_sriov_nr_virtfn(phba,
+                                                phba->cfg_sriov_nr_virtfn);
+               if (rc) {
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                                       "2808 Requested number of SR-IOV "
+                                       "virtual functions (%d) is not "
+                                       "supported\n",
+                                       phba->cfg_sriov_nr_virtfn);
+                       phba->cfg_sriov_nr_virtfn = 0;
+               }
+       }
+
        return 0;
 }
 
@@ -4160,6 +4246,14 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
        phba->fcf.redisc_wait.function = lpfc_sli4_fcf_redisc_wait_tmo;
        phba->fcf.redisc_wait.data = (unsigned long)phba;
 
+       /*
+        * Control structure for handling external multi-buffer mailbox
+        * command pass-through.
+        */
+       memset((uint8_t *)&phba->mbox_ext_buf_ctx, 0,
+               sizeof(struct lpfc_mbox_ext_buf_ctx));
+       INIT_LIST_HEAD(&phba->mbox_ext_buf_ctx.ext_dmabuf_list);
+
        /*
         * We need to do a READ_CONFIG mailbox command here before
         * calling lpfc_get_cfgparam. For VFs this will report the
@@ -4233,7 +4327,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
        spin_lock_init(&phba->sli4_hba.abts_sgl_list_lock);
 
        /*
-        * Initialize dirver internal slow-path work queues
+        * Initialize driver internal slow-path work queues
         */
 
        /* Driver internel slow-path CQ Event pool */
@@ -4249,6 +4343,12 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
        /* Receive queue CQ Event work queue list */
        INIT_LIST_HEAD(&phba->sli4_hba.sp_unsol_work_queue);
 
+       /* Initialize extent block lists. */
+       INIT_LIST_HEAD(&phba->sli4_hba.lpfc_rpi_blk_list);
+       INIT_LIST_HEAD(&phba->sli4_hba.lpfc_xri_blk_list);
+       INIT_LIST_HEAD(&phba->sli4_hba.lpfc_vfi_blk_list);
+       INIT_LIST_HEAD(&phba->lpfc_vpi_blk_list);
+
        /* Initialize the driver internal SLI layer lists. */
        lpfc_sli_setup(phba);
        lpfc_sli_queue_setup(phba);
@@ -4323,9 +4423,19 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
        }
        /*
         * Get sli4 parameters that override parameters from Port capabilities.
-        * If this call fails it is not a critical error so continue loading.
+        * If this call fails, it isn't critical unless the SLI4 parameters come
+        * back in conflict.
         */
-       lpfc_get_sli4_parameters(phba, mboxq);
+       rc = lpfc_get_sli4_parameters(phba, mboxq);
+       if (rc) {
+               if (phba->sli4_hba.extents_in_use &&
+                   phba->sli4_hba.rpi_hdrs_in_use) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2999 Unsupported SLI4 Parameters "
+                               "Extents and RPI headers enabled.\n");
+                       goto out_free_bsmbx;
+               }
+       }
        mempool_free(mboxq, phba->mbox_mem_pool);
        /* Create all the SLI4 queues */
        rc = lpfc_sli4_queue_create(phba);
@@ -4350,7 +4460,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                                "1430 Failed to initialize sgl list.\n");
                goto out_free_sgl_list;
        }
-
        rc = lpfc_sli4_init_rpi_hdrs(phba);
        if (rc) {
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -4366,6 +4475,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                "2759 Failed allocate memory for FCF round "
                                "robin failover bmask\n");
+               rc = -ENOMEM;
                goto out_remove_rpi_hdrs;
        }
 
@@ -4375,6 +4485,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                "2572 Failed allocate memory for fast-path "
                                "per-EQ handle array\n");
+               rc = -ENOMEM;
                goto out_free_fcf_rr_bmask;
        }
 
@@ -4384,9 +4495,27 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                "2573 Failed allocate memory for msi-x "
                                "interrupt vector entries\n");
+               rc = -ENOMEM;
                goto out_free_fcp_eq_hdl;
        }
 
+       /*
+        * Enable sr-iov virtual functions if supported and configured
+        * through the module parameter.
+        */
+       if (phba->cfg_sriov_nr_virtfn > 0) {
+               rc = lpfc_sli_probe_sriov_nr_virtfn(phba,
+                                                phba->cfg_sriov_nr_virtfn);
+               if (rc) {
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                                       "3020 Requested number of SR-IOV "
+                                       "virtual functions (%d) is not "
+                                       "supported\n",
+                                       phba->cfg_sriov_nr_virtfn);
+                       phba->cfg_sriov_nr_virtfn = 0;
+               }
+       }
+
        return rc;
 
 out_free_fcp_eq_hdl:
@@ -4449,6 +4578,9 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba)
        lpfc_sli4_cq_event_release_all(phba);
        lpfc_sli4_cq_event_pool_destroy(phba);
 
+       /* Release resource identifiers. */
+       lpfc_sli4_dealloc_resource_identifiers(phba);
+
        /* Free the bsmbx region. */
        lpfc_destroy_bootstrap_mbox(phba);
 
@@ -4649,6 +4781,7 @@ lpfc_init_iocb_list(struct lpfc_hba *phba, int iocb_count)
                                "Unloading driver.\n", __func__);
                        goto out_free_iocbq;
                }
+               iocbq_entry->sli4_lxritag = NO_XRI;
                iocbq_entry->sli4_xritag = NO_XRI;
 
                spin_lock_irq(&phba->hbalock);
@@ -4746,7 +4879,7 @@ lpfc_init_sgl_list(struct lpfc_hba *phba)
 
        els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba);
        lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-                               "2400 lpfc_init_sgl_list els %d.\n",
+                               "2400 ELS XRI count %d.\n",
                                els_xri_cnt);
        /* Initialize and populate the sglq list per host/VF. */
        INIT_LIST_HEAD(&phba->sli4_hba.lpfc_sgl_list);
@@ -4779,7 +4912,6 @@ lpfc_init_sgl_list(struct lpfc_hba *phba)
        phba->sli4_hba.scsi_xri_max =
                        phba->sli4_hba.max_cfg_param.max_xri - els_xri_cnt;
        phba->sli4_hba.scsi_xri_cnt = 0;
-
        phba->sli4_hba.lpfc_scsi_psb_array =
                        kzalloc((sizeof(struct lpfc_scsi_buf *) *
                        phba->sli4_hba.scsi_xri_max), GFP_KERNEL);
@@ -4802,13 +4934,6 @@ lpfc_init_sgl_list(struct lpfc_hba *phba)
                        goto out_free_mem;
                }
 
-               sglq_entry->sli4_xritag = lpfc_sli4_next_xritag(phba);
-               if (sglq_entry->sli4_xritag == NO_XRI) {
-                       kfree(sglq_entry);
-                       printk(KERN_ERR "%s: failed to allocate XRI.\n"
-                               "Unloading driver.\n", __func__);
-                       goto out_free_mem;
-               }
                sglq_entry->buff_type = GEN_BUFF_TYPE;
                sglq_entry->virt = lpfc_mbuf_alloc(phba, 0, &sglq_entry->phys);
                if (sglq_entry->virt == NULL) {
@@ -4857,24 +4982,20 @@ int
 lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *phba)
 {
        int rc = 0;
-       int longs;
-       uint16_t rpi_count;
        struct lpfc_rpi_hdr *rpi_hdr;
 
        INIT_LIST_HEAD(&phba->sli4_hba.lpfc_rpi_hdr_list);
-
        /*
-        * Provision an rpi bitmask range for discovery. The total count
-        * is the difference between max and base + 1.
+        * If the SLI4 port supports extents, posting the rpi header isn't
+        * required.  Set the expected maximum count and let the actual value
+        * get set when extents are fully allocated.
         */
-       rpi_count = phba->sli4_hba.max_cfg_param.rpi_base +
-                   phba->sli4_hba.max_cfg_param.max_rpi - 1;
-
-       longs = ((rpi_count) + BITS_PER_LONG - 1) / BITS_PER_LONG;
-       phba->sli4_hba.rpi_bmask = kzalloc(longs * sizeof(unsigned long),
-                                          GFP_KERNEL);
-       if (!phba->sli4_hba.rpi_bmask)
-               return -ENOMEM;
+       if (!phba->sli4_hba.rpi_hdrs_in_use) {
+               phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.max_rpi;
+               return rc;
+       }
+       if (phba->sli4_hba.extents_in_use)
+               return -EIO;
 
        rpi_hdr = lpfc_sli4_create_rpi_hdr(phba);
        if (!rpi_hdr) {
@@ -4908,11 +5029,28 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba)
        struct lpfc_rpi_hdr *rpi_hdr;
        uint32_t rpi_count;
 
+       /*
+        * If the SLI4 port supports extents, posting the rpi header isn't
+        * required.  Set the expected maximum count and let the actual value
+        * get set when extents are fully allocated.
+        */
+       if (!phba->sli4_hba.rpi_hdrs_in_use)
+               return NULL;
+       if (phba->sli4_hba.extents_in_use)
+               return NULL;
+
+       /* The limit on the logical index is just the max_rpi count. */
        rpi_limit = phba->sli4_hba.max_cfg_param.rpi_base +
-                   phba->sli4_hba.max_cfg_param.max_rpi - 1;
+       phba->sli4_hba.max_cfg_param.max_rpi - 1;
 
        spin_lock_irq(&phba->hbalock);
-       curr_rpi_range = phba->sli4_hba.next_rpi;
+       /*
+        * Establish the starting RPI in this header block.  The starting
+        * rpi is normalized to a zero base because the physical rpi is
+        * port based.
+        */
+       curr_rpi_range = phba->sli4_hba.next_rpi -
+               phba->sli4_hba.max_cfg_param.rpi_base;
        spin_unlock_irq(&phba->hbalock);
 
        /*
@@ -4925,6 +5063,8 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba)
        else
                rpi_count = LPFC_RPI_HDR_COUNT;
 
+       if (!rpi_count)
+               return NULL;
        /*
         * First allocate the protocol header region for the port.  The
         * port expects a 4KB DMA-mapped memory region that is 4K aligned.
@@ -4957,12 +5097,14 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba)
        rpi_hdr->len = LPFC_HDR_TEMPLATE_SIZE;
        rpi_hdr->page_count = 1;
        spin_lock_irq(&phba->hbalock);
-       rpi_hdr->start_rpi = phba->sli4_hba.next_rpi;
+
+       /* The rpi_hdr stores the logical index only. */
+       rpi_hdr->start_rpi = curr_rpi_range;
        list_add_tail(&rpi_hdr->list, &phba->sli4_hba.lpfc_rpi_hdr_list);
 
        /*
-        * The next_rpi stores the next module-64 rpi value to post
-        * in any subsequent rpi memory region postings.
+        * The next_rpi stores the next logical module-64 rpi value used
+        * to post physical rpis in subsequent rpi postings.
         */
        phba->sli4_hba.next_rpi += rpi_count;
        spin_unlock_irq(&phba->hbalock);
@@ -4981,15 +5123,18 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba)
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to remove all memory resources allocated
- * to support rpis. This routine presumes the caller has released all
- * rpis consumed by fabric or port logins and is prepared to have
- * the header pages removed.
+ * to support rpis for SLI4 ports not supporting extents. This routine
+ * presumes the caller has released all rpis consumed by fabric or port
+ * logins and is prepared to have the header pages removed.
  **/
 void
 lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *phba)
 {
        struct lpfc_rpi_hdr *rpi_hdr, *next_rpi_hdr;
 
+       if (!phba->sli4_hba.rpi_hdrs_in_use)
+               goto exit;
+
        list_for_each_entry_safe(rpi_hdr, next_rpi_hdr,
                                 &phba->sli4_hba.lpfc_rpi_hdr_list, list) {
                list_del(&rpi_hdr->list);
@@ -4998,9 +5143,9 @@ lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *phba)
                kfree(rpi_hdr->dmabuf);
                kfree(rpi_hdr);
        }
-
-       phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.rpi_base;
-       memset(phba->sli4_hba.rpi_bmask, 0, sizeof(*phba->sli4_hba.rpi_bmask));
+ exit:
+       /* There are no rpis available to the port now. */
+       phba->sli4_hba.next_rpi = 0;
 }
 
 /**
@@ -5487,7 +5632,8 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba)
                        /* Final checks.  The port status should be clean. */
                        if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
                                &reg_data.word0) ||
-                               bf_get(lpfc_sliport_status_err, &reg_data)) {
+                               (bf_get(lpfc_sliport_status_err, &reg_data) &&
+                                !bf_get(lpfc_sliport_status_rn, &reg_data))) {
                                phba->work_status[0] =
                                        readl(phba->sli4_hba.u.if_type2.
                                              ERR1regaddr);
@@ -5741,7 +5887,12 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
 {
        LPFC_MBOXQ_t *pmb;
        struct lpfc_mbx_read_config *rd_config;
-       uint32_t rc = 0;
+       union  lpfc_sli4_cfg_shdr *shdr;
+       uint32_t shdr_status, shdr_add_status;
+       struct lpfc_mbx_get_func_cfg *get_func_cfg;
+       struct lpfc_rsrc_desc_fcfcoe *desc;
+       uint32_t desc_count;
+       int length, i, rc = 0;
 
        pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!pmb) {
@@ -5763,6 +5914,8 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
                rc = -EIO;
        } else {
                rd_config = &pmb->u.mqe.un.rd_config;
+               phba->sli4_hba.extents_in_use =
+                       bf_get(lpfc_mbx_rd_conf_extnts_inuse, rd_config);
                phba->sli4_hba.max_cfg_param.max_xri =
                        bf_get(lpfc_mbx_rd_conf_xri_count, rd_config);
                phba->sli4_hba.max_cfg_param.xri_base =
@@ -5781,8 +5934,6 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
                        bf_get(lpfc_mbx_rd_conf_vfi_base, rd_config);
                phba->sli4_hba.max_cfg_param.max_fcfi =
                        bf_get(lpfc_mbx_rd_conf_fcfi_count, rd_config);
-               phba->sli4_hba.max_cfg_param.fcfi_base =
-                       bf_get(lpfc_mbx_rd_conf_fcfi_base, rd_config);
                phba->sli4_hba.max_cfg_param.max_eq =
                        bf_get(lpfc_mbx_rd_conf_eq_count, rd_config);
                phba->sli4_hba.max_cfg_param.max_rq =
@@ -5800,11 +5951,13 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
                                (phba->sli4_hba.max_cfg_param.max_vpi - 1) : 0;
                phba->max_vports = phba->max_vpi;
                lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-                               "2003 cfg params XRI(B:%d M:%d), "
+                               "2003 cfg params Extents? %d "
+                               "XRI(B:%d M:%d), "
                                "VPI(B:%d M:%d) "
                                "VFI(B:%d M:%d) "
                                "RPI(B:%d M:%d) "
-                               "FCFI(B:%d M:%d)\n",
+                               "FCFI(Count:%d)\n",
+                               phba->sli4_hba.extents_in_use,
                                phba->sli4_hba.max_cfg_param.xri_base,
                                phba->sli4_hba.max_cfg_param.max_xri,
                                phba->sli4_hba.max_cfg_param.vpi_base,
@@ -5813,10 +5966,11 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
                                phba->sli4_hba.max_cfg_param.max_vfi,
                                phba->sli4_hba.max_cfg_param.rpi_base,
                                phba->sli4_hba.max_cfg_param.max_rpi,
-                               phba->sli4_hba.max_cfg_param.fcfi_base,
                                phba->sli4_hba.max_cfg_param.max_fcfi);
        }
-       mempool_free(pmb, phba->mbox_mem_pool);
+
+       if (rc)
+               goto read_cfg_out;
 
        /* Reset the DFT_HBA_Q_DEPTH to the max xri  */
        if (phba->cfg_hba_queue_depth >
@@ -5825,6 +5979,65 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
                phba->cfg_hba_queue_depth =
                        phba->sli4_hba.max_cfg_param.max_xri -
                                lpfc_sli4_get_els_iocb_cnt(phba);
+
+       if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+           LPFC_SLI_INTF_IF_TYPE_2)
+               goto read_cfg_out;
+
+       /* get the pf# and vf# for SLI4 if_type 2 port */
+       length = (sizeof(struct lpfc_mbx_get_func_cfg) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, pmb, LPFC_MBOX_SUBSYSTEM_COMMON,
+                        LPFC_MBOX_OPCODE_GET_FUNCTION_CONFIG,
+                        length, LPFC_SLI4_MBX_EMBED);
+
+       rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
+       shdr = (union lpfc_sli4_cfg_shdr *)
+                               &pmb->u.mqe.un.sli4_config.header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (rc || shdr_status || shdr_add_status) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "3026 Mailbox failed , mbxCmd x%x "
+                               "GET_FUNCTION_CONFIG, mbxStatus x%x\n",
+                               bf_get(lpfc_mqe_command, &pmb->u.mqe),
+                               bf_get(lpfc_mqe_status, &pmb->u.mqe));
+               rc = -EIO;
+               goto read_cfg_out;
+       }
+
+       /* search for fc_fcoe resrouce descriptor */
+       get_func_cfg = &pmb->u.mqe.un.get_func_cfg;
+       desc_count = get_func_cfg->func_cfg.rsrc_desc_count;
+
+       for (i = 0; i < LPFC_RSRC_DESC_MAX_NUM; i++) {
+               desc = (struct lpfc_rsrc_desc_fcfcoe *)
+                       &get_func_cfg->func_cfg.desc[i];
+               if (LPFC_RSRC_DESC_TYPE_FCFCOE ==
+                   bf_get(lpfc_rsrc_desc_pcie_type, desc)) {
+                       phba->sli4_hba.iov.pf_number =
+                               bf_get(lpfc_rsrc_desc_fcfcoe_pfnum, desc);
+                       phba->sli4_hba.iov.vf_number =
+                               bf_get(lpfc_rsrc_desc_fcfcoe_vfnum, desc);
+                       break;
+               }
+       }
+
+       if (i < LPFC_RSRC_DESC_MAX_NUM)
+               lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                               "3027 GET_FUNCTION_CONFIG: pf_number:%d, "
+                               "vf_number:%d\n", phba->sli4_hba.iov.pf_number,
+                               phba->sli4_hba.iov.vf_number);
+       else {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "3028 GET_FUNCTION_CONFIG: failed to find "
+                               "Resrouce Descriptor:x%x\n",
+                               LPFC_RSRC_DESC_TYPE_FCFCOE);
+               rc = -EIO;
+       }
+
+read_cfg_out:
+       mempool_free(pmb, phba->mbox_mem_pool);
        return rc;
 }
 
@@ -6229,8 +6442,10 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba)
        phba->sli4_hba.mbx_cq = NULL;
 
        /* Release FCP response complete queue */
-       for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++)
+       fcp_qidx = 0;
+       do
                lpfc_sli4_queue_free(phba->sli4_hba.fcp_cq[fcp_qidx]);
+       while (++fcp_qidx < phba->cfg_fcp_eq_count);
        kfree(phba->sli4_hba.fcp_cq);
        phba->sli4_hba.fcp_cq = NULL;
 
@@ -6353,16 +6568,24 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
                        phba->sli4_hba.sp_eq->queue_id);
 
        /* Set up fast-path FCP Response Complete Queue */
-       for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) {
+       fcp_cqidx = 0;
+       do {
                if (!phba->sli4_hba.fcp_cq[fcp_cqidx]) {
                        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                        "0526 Fast-path FCP CQ (%d) not "
                                        "allocated\n", fcp_cqidx);
                        goto out_destroy_fcp_cq;
                }
-               rc = lpfc_cq_create(phba, phba->sli4_hba.fcp_cq[fcp_cqidx],
-                                   phba->sli4_hba.fp_eq[fcp_cqidx],
-                                   LPFC_WCQ, LPFC_FCP);
+               if (phba->cfg_fcp_eq_count)
+                       rc = lpfc_cq_create(phba,
+                                           phba->sli4_hba.fcp_cq[fcp_cqidx],
+                                           phba->sli4_hba.fp_eq[fcp_cqidx],
+                                           LPFC_WCQ, LPFC_FCP);
+               else
+                       rc = lpfc_cq_create(phba,
+                                           phba->sli4_hba.fcp_cq[fcp_cqidx],
+                                           phba->sli4_hba.sp_eq,
+                                           LPFC_WCQ, LPFC_FCP);
                if (rc) {
                        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                        "0527 Failed setup of fast-path FCP "
@@ -6371,12 +6594,15 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
                }
                lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
                                "2588 FCP CQ setup: cq[%d]-id=%d, "
-                               "parent eq[%d]-id=%d\n",
+                               "parent %seq[%d]-id=%d\n",
                                fcp_cqidx,
                                phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id,
+                               (phba->cfg_fcp_eq_count) ? "" : "sp_",
                                fcp_cqidx,
-                               phba->sli4_hba.fp_eq[fcp_cqidx]->queue_id);
-       }
+                               (phba->cfg_fcp_eq_count) ?
+                                  phba->sli4_hba.fp_eq[fcp_cqidx]->queue_id :
+                                  phba->sli4_hba.sp_eq->queue_id);
+       } while (++fcp_cqidx < phba->cfg_fcp_eq_count);
 
        /*
         * Set up all the Work Queues (WQs)
@@ -6445,7 +6671,9 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
                                fcp_cq_index,
                                phba->sli4_hba.fcp_cq[fcp_cq_index]->queue_id);
                /* Round robin FCP Work Queue's Completion Queue assignment */
-               fcp_cq_index = ((fcp_cq_index + 1) % phba->cfg_fcp_eq_count);
+               if (phba->cfg_fcp_eq_count)
+                       fcp_cq_index = ((fcp_cq_index + 1) %
+                                       phba->cfg_fcp_eq_count);
        }
 
        /*
@@ -6827,6 +7055,8 @@ lpfc_pci_function_reset(struct lpfc_hba *phba)
                        if (rdy_chk < 1000)
                                break;
                }
+               /* delay driver action following IF_TYPE_2 function reset */
+               msleep(100);
                break;
        case LPFC_SLI_INTF_IF_TYPE_1:
        default:
@@ -7419,11 +7649,15 @@ enable_msix_vectors:
        /*
         * Assign MSI-X vectors to interrupt handlers
         */
-
-       /* The first vector must associated to slow-path handler for MQ */
-       rc = request_irq(phba->sli4_hba.msix_entries[0].vector,
-                        &lpfc_sli4_sp_intr_handler, IRQF_SHARED,
-                        LPFC_SP_DRIVER_HANDLER_NAME, phba);
+       if (vectors > 1)
+               rc = request_irq(phba->sli4_hba.msix_entries[0].vector,
+                                &lpfc_sli4_sp_intr_handler, IRQF_SHARED,
+                                LPFC_SP_DRIVER_HANDLER_NAME, phba);
+       else
+               /* All Interrupts need to be handled by one EQ */
+               rc = request_irq(phba->sli4_hba.msix_entries[0].vector,
+                                &lpfc_sli4_intr_handler, IRQF_SHARED,
+                                LPFC_DRIVER_NAME, phba);
        if (rc) {
                lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
                                "0485 MSI-X slow-path request_irq failed "
@@ -7765,6 +7999,7 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba)
 {
        int wait_cnt = 0;
        LPFC_MBOXQ_t *mboxq;
+       struct pci_dev *pdev = phba->pcidev;
 
        lpfc_stop_hba_timers(phba);
        phba->sli4_hba.intr_enable = 0;
@@ -7804,6 +8039,10 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba)
        /* Disable PCI subsystem interrupt */
        lpfc_sli4_disable_intr(phba);
 
+       /* Disable SR-IOV if enabled */
+       if (phba->cfg_sriov_nr_virtfn)
+               pci_disable_sriov(pdev);
+
        /* Stop kthread signal shall trigger work_done one more time */
        kthread_stop(phba->worker_thread);
 
@@ -7878,6 +8117,11 @@ lpfc_pc_sli4_params_get(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
        sli4_params->hdr_pp_align = bf_get(hdr_pp_align, &mqe->un.sli4_params);
        sli4_params->sgl_pages_max = bf_get(sgl_pages, &mqe->un.sli4_params);
        sli4_params->sgl_pp_align = bf_get(sgl_pp_align, &mqe->un.sli4_params);
+
+       /* Make sure that sge_supp_len can be handled by the driver */
+       if (sli4_params->sge_supp_len > LPFC_MAX_SGE_SIZE)
+               sli4_params->sge_supp_len = LPFC_MAX_SGE_SIZE;
+
        return rc;
 }
 
@@ -7902,6 +8146,13 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
        int length;
        struct lpfc_sli4_parameters *mbx_sli4_parameters;
 
+       /*
+        * By default, the driver assumes the SLI4 port requires RPI
+        * header postings.  The SLI4_PARAM response will correct this
+        * assumption.
+        */
+       phba->sli4_hba.rpi_hdrs_in_use = 1;
+
        /* Read the port's SLI4 Config Parameters */
        length = (sizeof(struct lpfc_mbx_get_sli4_parameters) -
                  sizeof(struct lpfc_sli4_cfg_mhdr));
@@ -7938,6 +8189,13 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                                            mbx_sli4_parameters);
        sli4_params->sgl_pp_align = bf_get(cfg_sgl_pp_align,
                                           mbx_sli4_parameters);
+       phba->sli4_hba.extents_in_use = bf_get(cfg_ext, mbx_sli4_parameters);
+       phba->sli4_hba.rpi_hdrs_in_use = bf_get(cfg_hdrr, mbx_sli4_parameters);
+
+       /* Make sure that sge_supp_len can be handled by the driver */
+       if (sli4_params->sge_supp_len > LPFC_MAX_SGE_SIZE)
+               sli4_params->sge_supp_len = LPFC_MAX_SGE_SIZE;
+
        return 0;
 }
 
@@ -8173,6 +8431,10 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev)
 
        lpfc_debugfs_terminate(vport);
 
+       /* Disable SR-IOV if enabled */
+       if (phba->cfg_sriov_nr_virtfn)
+               pci_disable_sriov(pdev);
+
        /* Disable interrupt */
        lpfc_sli_disable_intr(phba);
 
@@ -8564,6 +8826,97 @@ lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba)
                return 0;
 }
 
+/**
+ * lpfc_write_firmware - attempt to write a firmware image to the port
+ * @phba: pointer to lpfc hba data structure.
+ * @fw: pointer to firmware image returned from request_firmware.
+ *
+ * returns the number of bytes written if write is successful.
+ * returns a negative error value if there were errors.
+ * returns 0 if firmware matches currently active firmware on port.
+ **/
+int
+lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw)
+{
+       char fwrev[32];
+       struct lpfc_grp_hdr *image = (struct lpfc_grp_hdr *)fw->data;
+       struct list_head dma_buffer_list;
+       int i, rc = 0;
+       struct lpfc_dmabuf *dmabuf, *next;
+       uint32_t offset = 0, temp_offset = 0;
+
+       INIT_LIST_HEAD(&dma_buffer_list);
+       if ((image->magic_number != LPFC_GROUP_OJECT_MAGIC_NUM) ||
+           (bf_get(lpfc_grp_hdr_file_type, image) != LPFC_FILE_TYPE_GROUP) ||
+           (bf_get(lpfc_grp_hdr_id, image) != LPFC_FILE_ID_GROUP) ||
+           (image->size != fw->size)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3022 Invalid FW image found. "
+                               "Magic:%d Type:%x ID:%x\n",
+                               image->magic_number,
+                               bf_get(lpfc_grp_hdr_file_type, image),
+                               bf_get(lpfc_grp_hdr_id, image));
+               return -EINVAL;
+       }
+       lpfc_decode_firmware_rev(phba, fwrev, 1);
+       if (strncmp(fwrev, image->rev_name, strnlen(fwrev, 16))) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3023 Updating Firmware. Current Version:%s "
+                               "New Version:%s\n",
+                               fwrev, image->rev_name);
+               for (i = 0; i < LPFC_MBX_WR_CONFIG_MAX_BDE; i++) {
+                       dmabuf = kzalloc(sizeof(struct lpfc_dmabuf),
+                                        GFP_KERNEL);
+                       if (!dmabuf) {
+                               rc = -ENOMEM;
+                               goto out;
+                       }
+                       dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev,
+                                                         SLI4_PAGE_SIZE,
+                                                         &dmabuf->phys,
+                                                         GFP_KERNEL);
+                       if (!dmabuf->virt) {
+                               kfree(dmabuf);
+                               rc = -ENOMEM;
+                               goto out;
+                       }
+                       list_add_tail(&dmabuf->list, &dma_buffer_list);
+               }
+               while (offset < fw->size) {
+                       temp_offset = offset;
+                       list_for_each_entry(dmabuf, &dma_buffer_list, list) {
+                               if (offset + SLI4_PAGE_SIZE > fw->size) {
+                                       temp_offset += fw->size - offset;
+                                       memcpy(dmabuf->virt,
+                                              fw->data + temp_offset,
+                                              fw->size - offset);
+                                       break;
+                               }
+                               temp_offset += SLI4_PAGE_SIZE;
+                               memcpy(dmabuf->virt, fw->data + temp_offset,
+                                      SLI4_PAGE_SIZE);
+                       }
+                       rc = lpfc_wr_object(phba, &dma_buffer_list,
+                                   (fw->size - offset), &offset);
+                       if (rc) {
+                               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                               "3024 Firmware update failed. "
+                                               "%d\n", rc);
+                               goto out;
+                       }
+               }
+               rc = offset;
+       }
+out:
+       list_for_each_entry_safe(dmabuf, next, &dma_buffer_list, list) {
+               list_del(&dmabuf->list);
+               dma_free_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE,
+                                 dmabuf->virt, dmabuf->phys);
+               kfree(dmabuf);
+       }
+       return rc;
+}
+
 /**
  * lpfc_pci_probe_one_s4 - PCI probe func to reg SLI-4 device to PCI subsys
  * @pdev: pointer to PCI device
@@ -8591,6 +8944,10 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
        int error;
        uint32_t cfg_mode, intr_mode;
        int mcnt;
+       int adjusted_fcp_eq_count;
+       int fcp_qidx;
+       const struct firmware *fw;
+       uint8_t file_name[16];
 
        /* Allocate memory for HBA structure */
        phba = lpfc_hba_alloc(pdev);
@@ -8688,11 +9045,25 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
                        error = -ENODEV;
                        goto out_free_sysfs_attr;
                }
-               /* Default to single FCP EQ for non-MSI-X */
+               /* Default to single EQ for non-MSI-X */
                if (phba->intr_type != MSIX)
-                       phba->cfg_fcp_eq_count = 1;
-               else if (phba->sli4_hba.msix_vec_nr < phba->cfg_fcp_eq_count)
-                       phba->cfg_fcp_eq_count = phba->sli4_hba.msix_vec_nr - 1;
+                       adjusted_fcp_eq_count = 0;
+               else if (phba->sli4_hba.msix_vec_nr <
+                                       phba->cfg_fcp_eq_count + 1)
+                       adjusted_fcp_eq_count = phba->sli4_hba.msix_vec_nr - 1;
+               else
+                       adjusted_fcp_eq_count = phba->cfg_fcp_eq_count;
+               /* Free unused EQs */
+               for (fcp_qidx = adjusted_fcp_eq_count;
+                    fcp_qidx < phba->cfg_fcp_eq_count;
+                    fcp_qidx++) {
+                       lpfc_sli4_queue_free(phba->sli4_hba.fp_eq[fcp_qidx]);
+                       /* do not delete the first fcp_cq */
+                       if (fcp_qidx)
+                               lpfc_sli4_queue_free(
+                                       phba->sli4_hba.fcp_cq[fcp_qidx]);
+               }
+               phba->cfg_fcp_eq_count = adjusted_fcp_eq_count;
                /* Set up SLI-4 HBA */
                if (lpfc_sli4_hba_setup(phba)) {
                        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -8731,6 +9102,14 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
        /* Perform post initialization setup */
        lpfc_post_init_setup(phba);
 
+       /* check for firmware upgrade or downgrade */
+       snprintf(file_name, 16, "%s.grp", phba->ModelName);
+       error = request_firmware(&fw, file_name, &phba->pcidev->dev);
+       if (!error) {
+               lpfc_write_firmware(phba, fw);
+               release_firmware(fw);
+       }
+
        /* Check if there are static vports to be created. */
        lpfc_create_static_vport(phba);
 
@@ -9498,6 +9877,10 @@ static struct pci_device_id lpfc_id_table[] = {
                PCI_ANY_ID, PCI_ANY_ID, },
        {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE,
                PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FC_VF,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE_VF,
+               PCI_ANY_ID, PCI_ANY_ID, },
        { 0 }
 };
 
index e6ce9033f85ebef15ed6524ef89c59e3637da1f0..55676702835357710470ebf65010f69b08813696 100644 (file)
@@ -610,7 +610,8 @@ lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi)
        mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm);
        mb->un.varRdSparm.un.sp64.addrHigh = putPaddrHigh(mp->phys);
        mb->un.varRdSparm.un.sp64.addrLow = putPaddrLow(mp->phys);
-       mb->un.varRdSparm.vpi = vpi + phba->vpi_base;
+       if (phba->sli_rev >= LPFC_SLI_REV3)
+               mb->un.varRdSparm.vpi = phba->vpi_ids[vpi];
 
        /* save address for completion */
        pmb->context1 = mp;
@@ -643,9 +644,10 @@ lpfc_unreg_did(struct lpfc_hba * phba, uint16_t vpi, uint32_t did,
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
        mb->un.varUnregDID.did = did;
-       if (vpi != 0xffff)
-               vpi += phba->vpi_base;
        mb->un.varUnregDID.vpi = vpi;
+       if ((vpi != 0xffff) &&
+           (phba->sli_rev == LPFC_SLI_REV4))
+               mb->un.varUnregDID.vpi = phba->vpi_ids[vpi];
 
        mb->mbxCommand = MBX_UNREG_D_ID;
        mb->mbxOwner = OWN_HOST;
@@ -738,12 +740,10 @@ lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
        mb->un.varRegLogin.rpi = 0;
-       if (phba->sli_rev == LPFC_SLI_REV4) {
-               mb->un.varRegLogin.rpi = rpi;
-               if (mb->un.varRegLogin.rpi == LPFC_RPI_ALLOC_ERROR)
-                       return 1;
-       }
-       mb->un.varRegLogin.vpi = vpi + phba->vpi_base;
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               mb->un.varRegLogin.rpi = phba->sli4_hba.rpi_ids[rpi];
+       if (phba->sli_rev >= LPFC_SLI_REV3)
+               mb->un.varRegLogin.vpi = phba->vpi_ids[vpi];
        mb->un.varRegLogin.did = did;
        mb->mbxOwner = OWN_HOST;
        /* Get a buffer to hold NPorts Service Parameters */
@@ -757,7 +757,7 @@ lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
                lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
                                "0302 REG_LOGIN: no buffers, VPI:%d DID:x%x, "
                                "rpi x%x\n", vpi, did, rpi);
-               return (1);
+               return 1;
        }
        INIT_LIST_HEAD(&mp->list);
        sparam = mp->virt;
@@ -773,7 +773,7 @@ lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
        mb->un.varRegLogin.un.sp64.addrHigh = putPaddrHigh(mp->phys);
        mb->un.varRegLogin.un.sp64.addrLow = putPaddrLow(mp->phys);
 
-       return (0);
+       return 0;
 }
 
 /**
@@ -789,6 +789,9 @@ lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
  *
  * This routine prepares the mailbox command for unregistering remote port
  * login.
+ *
+ * For SLI4 ports, the rpi passed to this function must be the physical
+ * rpi value, not the logical index.
  **/
 void
 lpfc_unreg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t rpi,
@@ -799,9 +802,10 @@ lpfc_unreg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t rpi,
        mb = &pmb->u.mb;
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
-       mb->un.varUnregLogin.rpi = (uint16_t) rpi;
+       mb->un.varUnregLogin.rpi = rpi;
        mb->un.varUnregLogin.rsvd1 = 0;
-       mb->un.varUnregLogin.vpi = vpi + phba->vpi_base;
+       if (phba->sli_rev >= LPFC_SLI_REV3)
+               mb->un.varUnregLogin.vpi = phba->vpi_ids[vpi];
 
        mb->mbxCommand = MBX_UNREG_LOGIN;
        mb->mbxOwner = OWN_HOST;
@@ -825,9 +829,16 @@ lpfc_sli4_unreg_all_rpis(struct lpfc_vport *vport)
 
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (mbox) {
-               lpfc_unreg_login(phba, vport->vpi,
-                       vport->vpi + phba->vpi_base, mbox);
-               mbox->u.mb.un.varUnregLogin.rsvd1 = 0x4000 ;
+               /*
+                * For SLI4 functions, the rpi field is overloaded for
+                * the vport context unreg all.  This routine passes
+                * 0 for the rpi field in lpfc_unreg_login for compatibility
+                * with SLI3 and then overrides the rpi field with the
+                * expected value for SLI4.
+                */
+               lpfc_unreg_login(phba, vport->vpi, phba->vpi_ids[vport->vpi],
+                                mbox);
+               mbox->u.mb.un.varUnregLogin.rsvd1 = 0x4000;
                mbox->vport = vport;
                mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
                mbox->context1 = NULL;
@@ -865,9 +876,13 @@ lpfc_reg_vpi(struct lpfc_vport *vport, LPFC_MBOXQ_t *pmb)
        if ((phba->sli_rev == LPFC_SLI_REV4) &&
                !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI))
                mb->un.varRegVpi.upd = 1;
-       mb->un.varRegVpi.vpi = vport->vpi + vport->phba->vpi_base;
+
+       mb->un.varRegVpi.vpi = phba->vpi_ids[vport->vpi];
        mb->un.varRegVpi.sid = vport->fc_myDID;
-       mb->un.varRegVpi.vfi = vport->vfi + vport->phba->vfi_base;
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               mb->un.varRegVpi.vfi = phba->sli4_hba.vfi_ids[vport->vfi];
+       else
+               mb->un.varRegVpi.vfi = vport->vfi + vport->phba->vfi_base;
        memcpy(mb->un.varRegVpi.wwn, &vport->fc_portname,
               sizeof(struct lpfc_name));
        mb->un.varRegVpi.wwn[0] = cpu_to_le32(mb->un.varRegVpi.wwn[0]);
@@ -901,10 +916,10 @@ lpfc_unreg_vpi(struct lpfc_hba *phba, uint16_t vpi, LPFC_MBOXQ_t *pmb)
        MAILBOX_t *mb = &pmb->u.mb;
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
-       if (phba->sli_rev < LPFC_SLI_REV4)
-               mb->un.varUnregVpi.vpi = vpi + phba->vpi_base;
-       else
-               mb->un.varUnregVpi.sli4_vpi = vpi + phba->vpi_base;
+       if (phba->sli_rev == LPFC_SLI_REV3)
+               mb->un.varUnregVpi.vpi = phba->vpi_ids[vpi];
+       else if (phba->sli_rev >= LPFC_SLI_REV4)
+               mb->un.varUnregVpi.sli4_vpi = phba->vpi_ids[vpi];
 
        mb->mbxCommand = MBX_UNREG_VPI;
        mb->mbxOwner = OWN_HOST;
@@ -1735,12 +1750,12 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox,
                return length;
        }
 
-       /* Setup for the none-embedded mbox command */
+       /* Setup for the non-embedded mbox command */
        pcount = (SLI4_PAGE_ALIGN(length))/SLI4_PAGE_SIZE;
        pcount = (pcount > LPFC_SLI4_MBX_SGE_MAX_PAGES) ?
                                LPFC_SLI4_MBX_SGE_MAX_PAGES : pcount;
        /* Allocate record for keeping SGE virtual addresses */
-       mbox->sge_array = kmalloc(sizeof(struct lpfc_mbx_nembed_sge_virt),
+       mbox->sge_array = kzalloc(sizeof(struct lpfc_mbx_nembed_sge_virt),
                                  GFP_KERNEL);
        if (!mbox->sge_array) {
                lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
@@ -1790,11 +1805,86 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox,
        /* The sub-header is in DMA memory, which needs endian converstion */
        if (cfg_shdr)
                lpfc_sli_pcimem_bcopy(cfg_shdr, cfg_shdr,
-                             sizeof(union  lpfc_sli4_cfg_shdr));
-
+                                     sizeof(union  lpfc_sli4_cfg_shdr));
        return alloc_len;
 }
 
+/**
+ * lpfc_sli4_mbox_rsrc_extent - Initialize the opcode resource extent.
+ * @phba: pointer to lpfc hba data structure.
+ * @mbox: pointer to an allocated lpfc mbox resource.
+ * @exts_count: the number of extents, if required, to allocate.
+ * @rsrc_type: the resource extent type.
+ * @emb: true if LPFC_SLI4_MBX_EMBED. false if LPFC_SLI4_MBX_NEMBED.
+ *
+ * This routine completes the subcommand header for SLI4 resource extent
+ * mailbox commands.  It is called after lpfc_sli4_config.  The caller must
+ * pass an allocated mailbox and the attributes required to initialize the
+ * mailbox correctly.
+ *
+ * Return: the actual length of the mbox command allocated.
+ **/
+int
+lpfc_sli4_mbox_rsrc_extent(struct lpfc_hba *phba, struct lpfcMboxq *mbox,
+                          uint16_t exts_count, uint16_t rsrc_type, bool emb)
+{
+       uint8_t opcode = 0;
+       struct lpfc_mbx_nembed_rsrc_extent *n_rsrc_extnt = NULL;
+       void *virtaddr = NULL;
+
+       /* Set up SLI4 ioctl command header fields */
+       if (emb == LPFC_SLI4_MBX_NEMBED) {
+               /* Get the first SGE entry from the non-embedded DMA memory */
+               virtaddr = mbox->sge_array->addr[0];
+               if (virtaddr == NULL)
+                       return 1;
+               n_rsrc_extnt = (struct lpfc_mbx_nembed_rsrc_extent *) virtaddr;
+       }
+
+       /*
+        * The resource type is common to all extent Opcodes and resides in the
+        * same position.
+        */
+       if (emb == LPFC_SLI4_MBX_EMBED)
+               bf_set(lpfc_mbx_alloc_rsrc_extents_type,
+                      &mbox->u.mqe.un.alloc_rsrc_extents.u.req,
+                      rsrc_type);
+       else {
+               /* This is DMA data.  Byteswap is required. */
+               bf_set(lpfc_mbx_alloc_rsrc_extents_type,
+                      n_rsrc_extnt, rsrc_type);
+               lpfc_sli_pcimem_bcopy(&n_rsrc_extnt->word4,
+                                     &n_rsrc_extnt->word4,
+                                     sizeof(uint32_t));
+       }
+
+       /* Complete the initialization for the particular Opcode. */
+       opcode = lpfc_sli4_mbox_opcode_get(phba, mbox);
+       switch (opcode) {
+       case LPFC_MBOX_OPCODE_ALLOC_RSRC_EXTENT:
+               if (emb == LPFC_SLI4_MBX_EMBED)
+                       bf_set(lpfc_mbx_alloc_rsrc_extents_cnt,
+                              &mbox->u.mqe.un.alloc_rsrc_extents.u.req,
+                              exts_count);
+               else
+                       bf_set(lpfc_mbx_alloc_rsrc_extents_cnt,
+                              n_rsrc_extnt, exts_count);
+               break;
+       case LPFC_MBOX_OPCODE_GET_ALLOC_RSRC_EXTENT:
+       case LPFC_MBOX_OPCODE_GET_RSRC_EXTENT_INFO:
+       case LPFC_MBOX_OPCODE_DEALLOC_RSRC_EXTENT:
+               /* Initialization is complete.*/
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+                               "2929 Resource Extent Opcode x%x is "
+                               "unsupported\n", opcode);
+               return 1;
+       }
+
+       return 0;
+}
+
 /**
  * lpfc_sli4_mbox_opcode_get - Get the opcode from a sli4 mailbox command
  * @phba: pointer to lpfc hba data structure.
@@ -1939,9 +2029,12 @@ lpfc_init_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport)
        bf_set(lpfc_init_vfi_vr, init_vfi, 1);
        bf_set(lpfc_init_vfi_vt, init_vfi, 1);
        bf_set(lpfc_init_vfi_vp, init_vfi, 1);
-       bf_set(lpfc_init_vfi_vfi, init_vfi, vport->vfi + vport->phba->vfi_base);
-       bf_set(lpfc_init_vpi_vpi, init_vfi, vport->vpi + vport->phba->vpi_base);
-       bf_set(lpfc_init_vfi_fcfi, init_vfi, vport->phba->fcf.fcfi);
+       bf_set(lpfc_init_vfi_vfi, init_vfi,
+              vport->phba->sli4_hba.vfi_ids[vport->vfi]);
+       bf_set(lpfc_init_vpi_vpi, init_vfi,
+              vport->phba->vpi_ids[vport->vpi]);
+       bf_set(lpfc_init_vfi_fcfi, init_vfi,
+              vport->phba->fcf.fcfi);
 }
 
 /**
@@ -1964,9 +2057,10 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)
        reg_vfi = &mbox->u.mqe.un.reg_vfi;
        bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_REG_VFI);
        bf_set(lpfc_reg_vfi_vp, reg_vfi, 1);
-       bf_set(lpfc_reg_vfi_vfi, reg_vfi, vport->vfi + vport->phba->vfi_base);
+       bf_set(lpfc_reg_vfi_vfi, reg_vfi,
+              vport->phba->sli4_hba.vfi_ids[vport->vfi]);
        bf_set(lpfc_reg_vfi_fcfi, reg_vfi, vport->phba->fcf.fcfi);
-       bf_set(lpfc_reg_vfi_vpi, reg_vfi, vport->vpi + vport->phba->vpi_base);
+       bf_set(lpfc_reg_vfi_vpi, reg_vfi, vport->phba->vpi_ids[vport->vpi]);
        memcpy(reg_vfi->wwn, &vport->fc_portname, sizeof(struct lpfc_name));
        reg_vfi->wwn[0] = cpu_to_le32(reg_vfi->wwn[0]);
        reg_vfi->wwn[1] = cpu_to_le32(reg_vfi->wwn[1]);
@@ -1997,9 +2091,9 @@ lpfc_init_vpi(struct lpfc_hba *phba, struct lpfcMboxq *mbox, uint16_t vpi)
        memset(mbox, 0, sizeof(*mbox));
        bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_INIT_VPI);
        bf_set(lpfc_init_vpi_vpi, &mbox->u.mqe.un.init_vpi,
-              vpi + phba->vpi_base);
+              phba->vpi_ids[vpi]);
        bf_set(lpfc_init_vpi_vfi, &mbox->u.mqe.un.init_vpi,
-              phba->pport->vfi + phba->vfi_base);
+              phba->sli4_hba.vfi_ids[phba->pport->vfi]);
 }
 
 /**
@@ -2019,7 +2113,7 @@ lpfc_unreg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport)
        memset(mbox, 0, sizeof(*mbox));
        bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_UNREG_VFI);
        bf_set(lpfc_unreg_vfi_vfi, &mbox->u.mqe.un.unreg_vfi,
-              vport->vfi + vport->phba->vfi_base);
+              vport->phba->sli4_hba.vfi_ids[vport->vfi]);
 }
 
 /**
@@ -2131,12 +2225,14 @@ lpfc_unreg_fcfi(struct lpfcMboxq *mbox, uint16_t fcfi)
 void
 lpfc_resume_rpi(struct lpfcMboxq *mbox, struct lpfc_nodelist *ndlp)
 {
+       struct lpfc_hba *phba = ndlp->phba;
        struct lpfc_mbx_resume_rpi *resume_rpi;
 
        memset(mbox, 0, sizeof(*mbox));
        resume_rpi = &mbox->u.mqe.un.resume_rpi;
        bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_RESUME_RPI);
-       bf_set(lpfc_resume_rpi_index, resume_rpi, ndlp->nlp_rpi);
+       bf_set(lpfc_resume_rpi_index, resume_rpi,
+              phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
        bf_set(lpfc_resume_rpi_ii, resume_rpi, RESUME_INDEX_RPI);
        resume_rpi->event_tag = ndlp->phba->fc_eventTag;
 }
index cbb48ee8b0bb05359fbed0afa6cdd2719b8ff00b..10d5b5e4149999aeb493028c2ad0b6fba9885654 100644 (file)
@@ -62,7 +62,6 @@ int
 lpfc_mem_alloc(struct lpfc_hba *phba, int align)
 {
        struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
-       int longs;
        int i;
 
        if (phba->sli_rev == LPFC_SLI_REV4)
@@ -138,17 +137,8 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align)
                phba->lpfc_hrb_pool = NULL;
                phba->lpfc_drb_pool = NULL;
        }
-       /* vpi zero is reserved for the physical port so add 1 to max */
-       longs = ((phba->max_vpi + 1) + BITS_PER_LONG - 1) / BITS_PER_LONG;
-       phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL);
-       if (!phba->vpi_bmask)
-               goto fail_free_dbq_pool;
 
        return 0;
-
- fail_free_dbq_pool:
-       pci_pool_destroy(phba->lpfc_drb_pool);
-       phba->lpfc_drb_pool = NULL;
  fail_free_hrb_pool:
        pci_pool_destroy(phba->lpfc_hrb_pool);
        phba->lpfc_hrb_pool = NULL;
@@ -191,9 +181,6 @@ lpfc_mem_free(struct lpfc_hba *phba)
        int i;
        struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
 
-       /* Free VPI bitmask memory */
-       kfree(phba->vpi_bmask);
-
        /* Free HBQ pools */
        lpfc_sli_hbqbuf_free_all(phba);
        if (phba->lpfc_drb_pool)
index 0d92d4205ea617908efad357da8ddf3aeb5229ae..2ddd02f7c60336130e90f8a0eb5f0ba230484451 100644 (file)
@@ -350,11 +350,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        ndlp->nlp_maxframe =
                ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
 
-       /*
-        * Need to unreg_login if we are already in one of these states and
-        * change to NPR state. This will block the port until after the ACC
-        * completes and the reg_login is issued and completed.
-        */
+       /* no need to reg_login if we are already in one of these states */
        switch (ndlp->nlp_state) {
        case  NLP_STE_NPR_NODE:
                if (!(ndlp->nlp_flag & NLP_NPR_ADISC))
@@ -363,9 +359,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        case  NLP_STE_PRLI_ISSUE:
        case  NLP_STE_UNMAPPED_NODE:
        case  NLP_STE_MAPPED_NODE:
-               lpfc_unreg_rpi(vport, ndlp);
-               ndlp->nlp_prev_state = ndlp->nlp_state;
-               lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+               lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
+               return 1;
        }
 
        if ((vport->fc_flag & FC_PT2PT) &&
@@ -657,6 +652,7 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
        lpfc_unreg_rpi(vport, ndlp);
        return 0;
 }
+
 /**
  * lpfc_release_rpi - Release a RPI by issuing unreg_login mailbox cmd.
  * @phba : Pointer to lpfc_hba structure.
@@ -1399,8 +1395,11 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
        if (mb->mbxStatus) {
                /* RegLogin failed */
                lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
-                               "0246 RegLogin failed Data: x%x x%x x%x\n",
-                               did, mb->mbxStatus, vport->port_state);
+                               "0246 RegLogin failed Data: x%x x%x x%x x%x "
+                                "x%x\n",
+                                did, mb->mbxStatus, vport->port_state,
+                                mb->un.varRegLogin.vpi,
+                                mb->un.varRegLogin.rpi);
                /*
                 * If RegLogin failed due to lack of HBA resources do not
                 * retry discovery.
@@ -1424,7 +1423,10 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
                return ndlp->nlp_state;
        }
 
-       ndlp->nlp_rpi = mb->un.varWords[0];
+       /* SLI4 ports have preallocated logical rpis. */
+       if (vport->phba->sli_rev < LPFC_SLI_REV4)
+               ndlp->nlp_rpi = mb->un.varWords[0];
+
        ndlp->nlp_flag |= NLP_RPI_REGISTERED;
 
        /* Only if we are not a fabric nport do we issue PRLI */
@@ -2025,7 +2027,9 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_vport *vport,
        MAILBOX_t    *mb = &pmb->u.mb;
 
        if (!mb->mbxStatus) {
-               ndlp->nlp_rpi = mb->un.varWords[0];
+               /* SLI4 ports have preallocated logical rpis. */
+               if (vport->phba->sli_rev < LPFC_SLI_REV4)
+                       ndlp->nlp_rpi = mb->un.varWords[0];
                ndlp->nlp_flag |= NLP_RPI_REGISTERED;
        } else {
                if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
index 84e4481b24062e21107cf770926bbdfe1d6610c5..3ccc97496ebfdb17c3aa63ce1fa0259dc497780c 100644 (file)
@@ -743,7 +743,14 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba)
                if (bcnt == 0)
                        continue;
                /* Now, post the SCSI buffer list sgls as a block */
-               status = lpfc_sli4_post_scsi_sgl_block(phba, &sblist, bcnt);
+               if (!phba->sli4_hba.extents_in_use)
+                       status = lpfc_sli4_post_scsi_sgl_block(phba,
+                                                       &sblist,
+                                                       bcnt);
+               else
+                       status = lpfc_sli4_post_scsi_sgl_blk_ext(phba,
+                                                       &sblist,
+                                                       bcnt);
                /* Reset SCSI buffer count for next round of posting */
                bcnt = 0;
                while (!list_empty(&sblist)) {
@@ -787,7 +794,7 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
        dma_addr_t pdma_phys_fcp_cmd;
        dma_addr_t pdma_phys_fcp_rsp;
        dma_addr_t pdma_phys_bpl, pdma_phys_bpl1;
-       uint16_t iotag, last_xritag = NO_XRI;
+       uint16_t iotag, last_xritag = NO_XRI, lxri = 0;
        int status = 0, index;
        int bcnt;
        int non_sequential_xri = 0;
@@ -823,13 +830,15 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
                        break;
                }
 
-               psb->cur_iocbq.sli4_xritag = lpfc_sli4_next_xritag(phba);
-               if (psb->cur_iocbq.sli4_xritag == NO_XRI) {
+               lxri = lpfc_sli4_next_xritag(phba);
+               if (lxri == NO_XRI) {
                        pci_pool_free(phba->lpfc_scsi_dma_buf_pool,
                              psb->data, psb->dma_handle);
                        kfree(psb);
                        break;
                }
+               psb->cur_iocbq.sli4_lxritag = lxri;
+               psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri];
                if (last_xritag != NO_XRI
                        && psb->cur_iocbq.sli4_xritag != (last_xritag+1)) {
                        non_sequential_xri = 1;
@@ -861,6 +870,7 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
                 */
                sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_cmd));
                sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_cmd));
+               sgl->word2 = le32_to_cpu(sgl->word2);
                bf_set(lpfc_sli4_sge_last, sgl, 0);
                sgl->word2 = cpu_to_le32(sgl->word2);
                sgl->sge_len = cpu_to_le32(sizeof(struct fcp_cmnd));
@@ -869,6 +879,7 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
                /* Setup the physical region for the FCP RSP */
                sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_rsp));
                sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_rsp));
+               sgl->word2 = le32_to_cpu(sgl->word2);
                bf_set(lpfc_sli4_sge_last, sgl, 1);
                sgl->word2 = cpu_to_le32(sgl->word2);
                sgl->sge_len = cpu_to_le32(sizeof(struct fcp_rsp));
@@ -914,7 +925,21 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
                }
        }
        if (bcnt) {
-               status = lpfc_sli4_post_scsi_sgl_block(phba, &sblist, bcnt);
+               if (!phba->sli4_hba.extents_in_use)
+                       status = lpfc_sli4_post_scsi_sgl_block(phba,
+                                                               &sblist,
+                                                               bcnt);
+               else
+                       status = lpfc_sli4_post_scsi_sgl_blk_ext(phba,
+                                                               &sblist,
+                                                               bcnt);
+
+               if (status) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                                       "3021 SCSI SGL post error %d\n",
+                                       status);
+                       bcnt = 0;
+               }
                /* Reset SCSI buffer count for next round of posting */
                while (!list_empty(&sblist)) {
                        list_remove_head(&sblist, psb, struct lpfc_scsi_buf,
@@ -2081,6 +2106,7 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
                        dma_len = sg_dma_len(sgel);
                        sgl->addr_lo = cpu_to_le32(putPaddrLow(physaddr));
                        sgl->addr_hi = cpu_to_le32(putPaddrHigh(physaddr));
+                       sgl->word2 = le32_to_cpu(sgl->word2);
                        if ((num_bde + 1) == nseg)
                                bf_set(lpfc_sli4_sge_last, sgl, 1);
                        else
@@ -2794,6 +2820,9 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
         * of the scsi_cmnd request_buffer
         */
        piocbq->iocb.ulpContext = pnode->nlp_rpi;
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               piocbq->iocb.ulpContext =
+                 phba->sli4_hba.rpi_ids[pnode->nlp_rpi];
        if (pnode->nlp_fcp_info & NLP_FCP_2_DEVICE)
                piocbq->iocb.ulpFCP2Rcvy = 1;
        else
@@ -2807,7 +2836,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 }
 
 /**
- * lpfc_scsi_prep_task_mgmt_cmnd - Convert SLI3 scsi TM cmd to FCP info unit
+ * lpfc_scsi_prep_task_mgmt_cmd - Convert SLI3 scsi TM cmd to FCP info unit
  * @vport: The virtual port for which this call is being executed.
  * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure.
  * @lun: Logical unit number.
@@ -2851,6 +2880,10 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport,
                lpfc_fcpcmd_to_iocb(piocb->unsli3.fcp_ext.icd, fcp_cmnd);
        piocb->ulpCommand = CMD_FCP_ICMND64_CR;
        piocb->ulpContext = ndlp->nlp_rpi;
+       if (vport->phba->sli_rev == LPFC_SLI_REV4) {
+               piocb->ulpContext =
+                 vport->phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
+       }
        if (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) {
                piocb->ulpFCP2Rcvy = 1;
        }
@@ -3405,9 +3438,10 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
 
        lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
                         "0702 Issue %s to TGT %d LUN %d "
-                        "rpi x%x nlp_flag x%x\n",
+                        "rpi x%x nlp_flag x%x Data: x%x x%x\n",
                         lpfc_taskmgmt_name(task_mgmt_cmd), tgt_id, lun_id,
-                        pnode->nlp_rpi, pnode->nlp_flag);
+                        pnode->nlp_rpi, pnode->nlp_flag, iocbq->sli4_xritag,
+                        iocbq->iocb_flag);
 
        status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING,
                                          iocbq, iocbqrsp, lpfc_cmd->timeout);
@@ -3419,10 +3453,12 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
                        ret = FAILED;
                lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
                lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
-                        "0727 TMF %s to TGT %d LUN %d failed (%d, %d)\n",
+                        "0727 TMF %s to TGT %d LUN %d failed (%d, %d) "
+                        "iocb_flag x%x\n",
                         lpfc_taskmgmt_name(task_mgmt_cmd),
                         tgt_id, lun_id, iocbqrsp->iocb.ulpStatus,
-                        iocbqrsp->iocb.un.ulpWord[4]);
+                        iocbqrsp->iocb.un.ulpWord[4],
+                        iocbq->iocb_flag);
        } else if (status == IOCB_BUSY)
                ret = FAILED;
        else
index fd5835e1c0395b93a387353b93fdddbf753c1f32..98999bbd8cbfee0dedefa49f90a85917c3cf2e33 100644 (file)
@@ -65,6 +65,9 @@ static struct lpfc_iocbq *lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *,
                                                         struct lpfc_iocbq *);
 static void lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *,
                                      struct hbq_dmabuf *);
+static int lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *, struct lpfc_queue *,
+                                   struct lpfc_cqe *);
+
 static IOCB_t *
 lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq)
 {
@@ -456,7 +459,6 @@ __lpfc_sli_get_iocbq(struct lpfc_hba *phba)
        struct lpfc_iocbq * iocbq = NULL;
 
        list_remove_head(lpfc_iocb_list, iocbq, struct lpfc_iocbq, list);
-
        if (iocbq)
                phba->iocb_cnt++;
        if (phba->iocb_cnt > phba->iocb_max)
@@ -479,13 +481,10 @@ __lpfc_sli_get_iocbq(struct lpfc_hba *phba)
 static struct lpfc_sglq *
 __lpfc_clear_active_sglq(struct lpfc_hba *phba, uint16_t xritag)
 {
-       uint16_t adj_xri;
        struct lpfc_sglq *sglq;
-       adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
-       if (adj_xri > phba->sli4_hba.max_cfg_param.max_xri)
-               return NULL;
-       sglq = phba->sli4_hba.lpfc_sglq_active_list[adj_xri];
-       phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = NULL;
+
+       sglq = phba->sli4_hba.lpfc_sglq_active_list[xritag];
+       phba->sli4_hba.lpfc_sglq_active_list[xritag] = NULL;
        return sglq;
 }
 
@@ -504,12 +503,9 @@ __lpfc_clear_active_sglq(struct lpfc_hba *phba, uint16_t xritag)
 struct lpfc_sglq *
 __lpfc_get_active_sglq(struct lpfc_hba *phba, uint16_t xritag)
 {
-       uint16_t adj_xri;
        struct lpfc_sglq *sglq;
-       adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
-       if (adj_xri > phba->sli4_hba.max_cfg_param.max_xri)
-               return NULL;
-       sglq =  phba->sli4_hba.lpfc_sglq_active_list[adj_xri];
+
+       sglq =  phba->sli4_hba.lpfc_sglq_active_list[xritag];
        return sglq;
 }
 
@@ -532,7 +528,6 @@ static int
 __lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
                uint16_t xritag, uint16_t rxid, uint16_t send_rrq)
 {
-       uint16_t adj_xri;
        struct lpfc_node_rrq *rrq;
        int empty;
        uint32_t did = 0;
@@ -553,21 +548,19 @@ __lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
        /*
         * set the active bit even if there is no mem available.
         */
-       adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
-
        if (NLP_CHK_FREE_REQ(ndlp))
                goto out;
 
        if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING))
                goto out;
 
-       if (test_and_set_bit(adj_xri, ndlp->active_rrqs.xri_bitmap))
+       if (test_and_set_bit(xritag, ndlp->active_rrqs.xri_bitmap))
                goto out;
 
        rrq = mempool_alloc(phba->rrq_pool, GFP_KERNEL);
        if (rrq) {
                rrq->send_rrq = send_rrq;
-               rrq->xritag = xritag;
+               rrq->xritag = phba->sli4_hba.xri_ids[xritag];
                rrq->rrq_stop_time = jiffies + HZ * (phba->fc_ratov + 1);
                rrq->ndlp = ndlp;
                rrq->nlp_DID = ndlp->nlp_DID;
@@ -603,7 +596,6 @@ lpfc_clr_rrq_active(struct lpfc_hba *phba,
                    uint16_t xritag,
                    struct lpfc_node_rrq *rrq)
 {
-       uint16_t adj_xri;
        struct lpfc_nodelist *ndlp = NULL;
 
        if ((rrq->vport) && NLP_CHK_NODE_ACT(rrq->ndlp))
@@ -619,8 +611,7 @@ lpfc_clr_rrq_active(struct lpfc_hba *phba,
        if (!ndlp)
                goto out;
 
-       adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
-       if (test_and_clear_bit(adj_xri, ndlp->active_rrqs.xri_bitmap)) {
+       if (test_and_clear_bit(xritag, ndlp->active_rrqs.xri_bitmap)) {
                rrq->send_rrq = 0;
                rrq->xritag = 0;
                rrq->rrq_stop_time = 0;
@@ -796,12 +787,9 @@ int
 lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
                        uint16_t  xritag)
 {
-       uint16_t adj_xri;
-
-       adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
        if (!ndlp)
                return 0;
-       if (test_bit(adj_xri, ndlp->active_rrqs.xri_bitmap))
+       if (test_bit(xritag, ndlp->active_rrqs.xri_bitmap))
                        return 1;
        else
                return 0;
@@ -841,7 +829,7 @@ lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
  * @piocb: Pointer to the iocbq.
  *
  * This function is called with hbalock held. This function
- * Gets a new driver sglq object from the sglq list. If the
+ * gets a new driver sglq object from the sglq list. If the
  * list is not empty then it is successful, it returns pointer to the newly
  * allocated sglq object else it returns NULL.
  **/
@@ -851,7 +839,6 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
        struct list_head *lpfc_sgl_list = &phba->sli4_hba.lpfc_sgl_list;
        struct lpfc_sglq *sglq = NULL;
        struct lpfc_sglq *start_sglq = NULL;
-       uint16_t adj_xri;
        struct lpfc_scsi_buf *lpfc_cmd;
        struct lpfc_nodelist *ndlp;
        int found = 0;
@@ -870,8 +857,6 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
        while (!found) {
                if (!sglq)
                        return NULL;
-               adj_xri = sglq->sli4_xritag -
-                               phba->sli4_hba.max_cfg_param.xri_base;
                if (lpfc_test_rrq_active(phba, ndlp, sglq->sli4_xritag)) {
                        /* This xri has an rrq outstanding for this DID.
                         * put it back in the list and get another xri.
@@ -888,7 +873,7 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
                }
                sglq->ndlp = ndlp;
                found = 1;
-               phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = sglq;
+               phba->sli4_hba.lpfc_sglq_active_list[sglq->sli4_lxritag] = sglq;
                sglq->state = SGL_ALLOCATED;
        }
        return sglq;
@@ -944,7 +929,8 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
        if (iocbq->sli4_xritag == NO_XRI)
                sglq = NULL;
        else
-               sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_xritag);
+               sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_lxritag);
+
        if (sglq)  {
                if ((iocbq->iocb_flag & LPFC_EXCHANGE_BUSY) &&
                        (sglq->state != SGL_XRI_ABORTED)) {
@@ -971,6 +957,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
         * Clean all volatile data fields, preserve iotag and node struct.
         */
        memset((char *)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean);
+       iocbq->sli4_lxritag = NO_XRI;
        iocbq->sli4_xritag = NO_XRI;
        list_add_tail(&iocbq->list, &phba->lpfc_iocb_list);
 }
@@ -2113,7 +2100,7 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
            pmb->u.mb.mbxCommand == MBX_REG_LOGIN64 &&
            !pmb->u.mb.mbxStatus) {
                rpi = pmb->u.mb.un.varWords[0];
-               vpi = pmb->u.mb.un.varRegLogin.vpi - phba->vpi_base;
+               vpi = pmb->u.mb.un.varRegLogin.vpi;
                lpfc_unreg_login(phba, vpi, rpi, pmb);
                pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
                rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
@@ -3881,8 +3868,10 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba)
        list_del_init(&phba->sli4_hba.els_cq->list);
        for (qindx = 0; qindx < phba->cfg_fcp_wq_count; qindx++)
                list_del_init(&phba->sli4_hba.fcp_wq[qindx]->list);
-       for (qindx = 0; qindx < phba->cfg_fcp_eq_count; qindx++)
+       qindx = 0;
+       do
                list_del_init(&phba->sli4_hba.fcp_cq[qindx]->list);
+       while (++qindx < phba->cfg_fcp_eq_count);
        spin_unlock_irq(&phba->hbalock);
 
        /* Now physically reset the device */
@@ -4318,6 +4307,7 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
                        continue;
                } else if (rc)
                        break;
+
                phba->link_state = LPFC_INIT_MBX_CMDS;
                lpfc_config_port(phba, pmb);
                rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
@@ -4421,7 +4411,8 @@ int
 lpfc_sli_hba_setup(struct lpfc_hba *phba)
 {
        uint32_t rc;
-       int  mode = 3;
+       int  mode = 3, i;
+       int longs;
 
        switch (lpfc_sli_mode) {
        case 2:
@@ -4491,6 +4482,35 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
        if (rc)
                goto lpfc_sli_hba_setup_error;
 
+       /* Initialize VPIs. */
+       if (phba->sli_rev == LPFC_SLI_REV3) {
+               /*
+                * The VPI bitmask and physical ID array are allocated
+                * and initialized once only - at driver load.  A port
+                * reset doesn't need to reinitialize this memory.
+                */
+               if ((phba->vpi_bmask == NULL) && (phba->vpi_ids == NULL)) {
+                       longs = (phba->max_vpi + BITS_PER_LONG) / BITS_PER_LONG;
+                       phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long),
+                                                 GFP_KERNEL);
+                       if (!phba->vpi_bmask) {
+                               rc = -ENOMEM;
+                               goto lpfc_sli_hba_setup_error;
+                       }
+
+                       phba->vpi_ids = kzalloc(
+                                       (phba->max_vpi+1) * sizeof(uint16_t),
+                                       GFP_KERNEL);
+                       if (!phba->vpi_ids) {
+                               kfree(phba->vpi_bmask);
+                               rc = -ENOMEM;
+                               goto lpfc_sli_hba_setup_error;
+                       }
+                       for (i = 0; i < phba->max_vpi; i++)
+                               phba->vpi_ids[i] = i;
+               }
+       }
+
        /* Init HBQs */
        if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
                rc = lpfc_sli_hbq_setup(phba);
@@ -4677,9 +4697,11 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
 
        lpfc_sli4_cq_release(phba->sli4_hba.mbx_cq, LPFC_QUEUE_REARM);
        lpfc_sli4_cq_release(phba->sli4_hba.els_cq, LPFC_QUEUE_REARM);
-       for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++)
+       fcp_eqidx = 0;
+       do
                lpfc_sli4_cq_release(phba->sli4_hba.fcp_cq[fcp_eqidx],
                                     LPFC_QUEUE_REARM);
+       while (++fcp_eqidx < phba->cfg_fcp_eq_count);
        lpfc_sli4_eq_release(phba->sli4_hba.sp_eq, LPFC_QUEUE_REARM);
        for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++)
                lpfc_sli4_eq_release(phba->sli4_hba.fp_eq[fcp_eqidx],
@@ -4687,174 +4709,967 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
 }
 
 /**
- * lpfc_sli4_hba_setup - SLI4 device intialization PCI function
+ * lpfc_sli4_get_avail_extnt_rsrc - Get available resource extent count.
  * @phba: Pointer to HBA context object.
+ * @type: The resource extent type.
  *
- * This function is the main SLI4 device intialization PCI function. This
- * function is called by the HBA intialization code, HBA reset code and
- * HBA error attention handler code. Caller is not required to hold any
- * locks.
+ * This function allocates all SLI4 resource identifiers.
  **/
-int
-lpfc_sli4_hba_setup(struct lpfc_hba *phba)
+static int
+lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type,
+                              uint16_t *extnt_count, uint16_t *extnt_size)
 {
-       int rc;
-       LPFC_MBOXQ_t *mboxq;
-       struct lpfc_mqe *mqe;
-       uint8_t *vpd;
-       uint32_t vpd_size;
-       uint32_t ftr_rsp = 0;
-       struct Scsi_Host *shost = lpfc_shost_from_vport(phba->pport);
-       struct lpfc_vport *vport = phba->pport;
-       struct lpfc_dmabuf *mp;
+       int rc = 0;
+       uint32_t length;
+       uint32_t mbox_tmo;
+       struct lpfc_mbx_get_rsrc_extent_info *rsrc_info;
+       LPFC_MBOXQ_t *mbox;
 
-       /*
-        * TODO:  Why does this routine execute these task in a different
-        * order from probe?
-        */
-       /* Perform a PCI function reset to start from clean */
-       rc = lpfc_pci_function_reset(phba);
-       if (unlikely(rc))
-               return -ENODEV;
+       mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
 
-       /* Check the HBA Host Status Register for readyness */
-       rc = lpfc_sli4_post_status_check(phba);
-       if (unlikely(rc))
-               return -ENODEV;
+       /* Find out how many extents are available for this resource type */
+       length = (sizeof(struct lpfc_mbx_get_rsrc_extent_info) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+                        LPFC_MBOX_OPCODE_GET_RSRC_EXTENT_INFO,
+                        length, LPFC_SLI4_MBX_EMBED);
+
+       /* Send an extents count of 0 - the GET doesn't use it. */
+       rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, 0, type,
+                                       LPFC_SLI4_MBX_EMBED);
+       if (unlikely(rc)) {
+               rc = -EIO;
+               goto err_exit;
+       }
+
+       if (!phba->sli4_hba.intr_enable)
+               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
        else {
-               spin_lock_irq(&phba->hbalock);
-               phba->sli.sli_flag |= LPFC_SLI_ACTIVE;
-               spin_unlock_irq(&phba->hbalock);
+               mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+               rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
+       }
+       if (unlikely(rc)) {
+               rc = -EIO;
+               goto err_exit;
+       }
+
+       rsrc_info = &mbox->u.mqe.un.rsrc_extent_info;
+       if (bf_get(lpfc_mbox_hdr_status,
+                  &rsrc_info->header.cfg_shdr.response)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT,
+                               "2930 Failed to get resource extents "
+                               "Status 0x%x Add'l Status 0x%x\n",
+                               bf_get(lpfc_mbox_hdr_status,
+                                      &rsrc_info->header.cfg_shdr.response),
+                               bf_get(lpfc_mbox_hdr_add_status,
+                                      &rsrc_info->header.cfg_shdr.response));
+               rc = -EIO;
+               goto err_exit;
+       }
+
+       *extnt_count = bf_get(lpfc_mbx_get_rsrc_extent_info_cnt,
+                             &rsrc_info->u.rsp);
+       *extnt_size = bf_get(lpfc_mbx_get_rsrc_extent_info_size,
+                            &rsrc_info->u.rsp);
+ err_exit:
+       mempool_free(mbox, phba->mbox_mem_pool);
+       return rc;
+}
+
+/**
+ * lpfc_sli4_chk_avail_extnt_rsrc - Check for available SLI4 resource extents.
+ * @phba: Pointer to HBA context object.
+ * @type: The extent type to check.
+ *
+ * This function reads the current available extents from the port and checks
+ * if the extent count or extent size has changed since the last access.
+ * Callers use this routine post port reset to understand if there is a
+ * extent reprovisioning requirement.
+ *
+ * Returns:
+ *   -Error: error indicates problem.
+ *   1: Extent count or size has changed.
+ *   0: No changes.
+ **/
+static int
+lpfc_sli4_chk_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type)
+{
+       uint16_t curr_ext_cnt, rsrc_ext_cnt;
+       uint16_t size_diff, rsrc_ext_size;
+       int rc = 0;
+       struct lpfc_rsrc_blks *rsrc_entry;
+       struct list_head *rsrc_blk_list = NULL;
+
+       size_diff = 0;
+       curr_ext_cnt = 0;
+       rc = lpfc_sli4_get_avail_extnt_rsrc(phba, type,
+                                           &rsrc_ext_cnt,
+                                           &rsrc_ext_size);
+       if (unlikely(rc))
+               return -EIO;
+
+       switch (type) {
+       case LPFC_RSC_TYPE_FCOE_RPI:
+               rsrc_blk_list = &phba->sli4_hba.lpfc_rpi_blk_list;
+               break;
+       case LPFC_RSC_TYPE_FCOE_VPI:
+               rsrc_blk_list = &phba->lpfc_vpi_blk_list;
+               break;
+       case LPFC_RSC_TYPE_FCOE_XRI:
+               rsrc_blk_list = &phba->sli4_hba.lpfc_xri_blk_list;
+               break;
+       case LPFC_RSC_TYPE_FCOE_VFI:
+               rsrc_blk_list = &phba->sli4_hba.lpfc_vfi_blk_list;
+               break;
+       default:
+               break;
+       }
+
+       list_for_each_entry(rsrc_entry, rsrc_blk_list, list) {
+               curr_ext_cnt++;
+               if (rsrc_entry->rsrc_size != rsrc_ext_size)
+                       size_diff++;
        }
 
+       if (curr_ext_cnt != rsrc_ext_cnt || size_diff != 0)
+               rc = 1;
+
+       return rc;
+}
+
+/**
+ * lpfc_sli4_cfg_post_extnts -
+ * @phba: Pointer to HBA context object.
+ * @extnt_cnt - number of available extents.
+ * @type - the extent type (rpi, xri, vfi, vpi).
+ * @emb - buffer to hold either MBX_EMBED or MBX_NEMBED operation.
+ * @mbox - pointer to the caller's allocated mailbox structure.
+ *
+ * This function executes the extents allocation request.  It also
+ * takes care of the amount of memory needed to allocate or get the
+ * allocated extents. It is the caller's responsibility to evaluate
+ * the response.
+ *
+ * Returns:
+ *   -Error:  Error value describes the condition found.
+ *   0: if successful
+ **/
+static int
+lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt,
+                         uint16_t type, bool *emb, LPFC_MBOXQ_t *mbox)
+{
+       int rc = 0;
+       uint32_t req_len;
+       uint32_t emb_len;
+       uint32_t alloc_len, mbox_tmo;
+
+       /* Calculate the total requested length of the dma memory */
+       req_len = *extnt_cnt * sizeof(uint16_t);
+
        /*
-        * Allocate a single mailbox container for initializing the
-        * port.
+        * Calculate the size of an embedded mailbox.  The uint32_t
+        * accounts for extents-specific word.
         */
-       mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-       if (!mboxq)
-               return -ENOMEM;
+       emb_len = sizeof(MAILBOX_t) - sizeof(struct mbox_header) -
+               sizeof(uint32_t);
 
        /*
-        * Continue initialization with default values even if driver failed
-        * to read FCoE param config regions
+        * Presume the allocation and response will fit into an embedded
+        * mailbox.  If not true, reconfigure to a non-embedded mailbox.
         */
-       if (lpfc_sli4_read_fcoe_params(phba, mboxq))
-               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT,
-                       "2570 Failed to read FCoE parameters\n");
-
-       /* Issue READ_REV to collect vpd and FW information. */
-       vpd_size = SLI4_PAGE_SIZE;
-       vpd = kzalloc(vpd_size, GFP_KERNEL);
-       if (!vpd) {
-               rc = -ENOMEM;
-               goto out_free_mbox;
+       *emb = LPFC_SLI4_MBX_EMBED;
+       if (req_len > emb_len) {
+               req_len = *extnt_cnt * sizeof(uint16_t) +
+                       sizeof(union lpfc_sli4_cfg_shdr) +
+                       sizeof(uint32_t);
+               *emb = LPFC_SLI4_MBX_NEMBED;
        }
 
-       rc = lpfc_sli4_read_rev(phba, mboxq, vpd, &vpd_size);
-       if (unlikely(rc)) {
-               kfree(vpd);
-               goto out_free_mbox;
+       alloc_len = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+                                    LPFC_MBOX_OPCODE_ALLOC_RSRC_EXTENT,
+                                    req_len, *emb);
+       if (alloc_len < req_len) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       "9000 Allocated DMA memory size (x%x) is "
+                       "less than the requested DMA memory "
+                       "size (x%x)\n", alloc_len, req_len);
+               return -ENOMEM;
        }
-       mqe = &mboxq->u.mqe;
-       phba->sli_rev = bf_get(lpfc_mbx_rd_rev_sli_lvl, &mqe->un.read_rev);
-       if (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev))
-               phba->hba_flag |= HBA_FCOE_MODE;
-       else
-               phba->hba_flag &= ~HBA_FCOE_MODE;
+       rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, *extnt_cnt, type, *emb);
+       if (unlikely(rc))
+               return -EIO;
 
-       if (bf_get(lpfc_mbx_rd_rev_cee_ver, &mqe->un.read_rev) ==
-               LPFC_DCBX_CEE_MODE)
-               phba->hba_flag |= HBA_FIP_SUPPORT;
-       else
-               phba->hba_flag &= ~HBA_FIP_SUPPORT;
+       if (!phba->sli4_hba.intr_enable)
+               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+       else {
+               mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+               rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
+       }
 
-       if (phba->sli_rev != LPFC_SLI_REV4) {
-               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
-                       "0376 READ_REV Error. SLI Level %d "
-                       "FCoE enabled %d\n",
-                       phba->sli_rev, phba->hba_flag & HBA_FCOE_MODE);
+       if (unlikely(rc))
                rc = -EIO;
-               kfree(vpd);
-               goto out_free_mbox;
-       }
-       /*
-        * Evaluate the read rev and vpd data. Populate the driver
-        * state with the results. If this routine fails, the failure
-        * is not fatal as the driver will use generic values.
-        */
-       rc = lpfc_parse_vpd(phba, vpd, vpd_size);
-       if (unlikely(!rc)) {
-               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
-                               "0377 Error %d parsing vpd. "
-                               "Using defaults.\n", rc);
-               rc = 0;
+       return rc;
+}
+
+/**
+ * lpfc_sli4_alloc_extent - Allocate an SLI4 resource extent.
+ * @phba: Pointer to HBA context object.
+ * @type:  The resource extent type to allocate.
+ *
+ * This function allocates the number of elements for the specified
+ * resource type.
+ **/
+static int
+lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type)
+{
+       bool emb = false;
+       uint16_t rsrc_id_cnt, rsrc_cnt, rsrc_size;
+       uint16_t rsrc_id, rsrc_start, j, k;
+       uint16_t *ids;
+       int i, rc;
+       unsigned long longs;
+       unsigned long *bmask;
+       struct lpfc_rsrc_blks *rsrc_blks;
+       LPFC_MBOXQ_t *mbox;
+       uint32_t length;
+       struct lpfc_id_range *id_array = NULL;
+       void *virtaddr = NULL;
+       struct lpfc_mbx_nembed_rsrc_extent *n_rsrc;
+       struct lpfc_mbx_alloc_rsrc_extents *rsrc_ext;
+       struct list_head *ext_blk_list;
+
+       rc = lpfc_sli4_get_avail_extnt_rsrc(phba, type,
+                                           &rsrc_cnt,
+                                           &rsrc_size);
+       if (unlikely(rc))
+               return -EIO;
+
+       if ((rsrc_cnt == 0) || (rsrc_size == 0)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT,
+                       "3009 No available Resource Extents "
+                       "for resource type 0x%x: Count: 0x%x, "
+                       "Size 0x%x\n", type, rsrc_cnt,
+                       rsrc_size);
+               return -ENOMEM;
        }
-       kfree(vpd);
 
-       /* Save information as VPD data */
-       phba->vpd.rev.biuRev = mqe->un.read_rev.first_hw_rev;
-       phba->vpd.rev.smRev = mqe->un.read_rev.second_hw_rev;
-       phba->vpd.rev.endecRev = mqe->un.read_rev.third_hw_rev;
-       phba->vpd.rev.fcphHigh = bf_get(lpfc_mbx_rd_rev_fcph_high,
-                                        &mqe->un.read_rev);
-       phba->vpd.rev.fcphLow = bf_get(lpfc_mbx_rd_rev_fcph_low,
-                                      &mqe->un.read_rev);
-       phba->vpd.rev.feaLevelHigh = bf_get(lpfc_mbx_rd_rev_ftr_lvl_high,
-                                           &mqe->un.read_rev);
-       phba->vpd.rev.feaLevelLow = bf_get(lpfc_mbx_rd_rev_ftr_lvl_low,
-                                          &mqe->un.read_rev);
-       phba->vpd.rev.sli1FwRev = mqe->un.read_rev.fw_id_rev;
-       memcpy(phba->vpd.rev.sli1FwName, mqe->un.read_rev.fw_name, 16);
-       phba->vpd.rev.sli2FwRev = mqe->un.read_rev.ulp_fw_id_rev;
-       memcpy(phba->vpd.rev.sli2FwName, mqe->un.read_rev.ulp_fw_name, 16);
-       phba->vpd.rev.opFwRev = mqe->un.read_rev.fw_id_rev;
-       memcpy(phba->vpd.rev.opFwName, mqe->un.read_rev.fw_name, 16);
-       lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
-                       "(%d):0380 READ_REV Status x%x "
-                       "fw_rev:%s fcphHi:%x fcphLo:%x flHi:%x flLo:%x\n",
-                       mboxq->vport ? mboxq->vport->vpi : 0,
-                       bf_get(lpfc_mqe_status, mqe),
-                       phba->vpd.rev.opFwName,
-                       phba->vpd.rev.fcphHigh, phba->vpd.rev.fcphLow,
-                       phba->vpd.rev.feaLevelHigh, phba->vpd.rev.feaLevelLow);
+       lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_INIT,
+                       "2903 Available Resource Extents "
+                       "for resource type 0x%x: Count: 0x%x, "
+                       "Size 0x%x\n", type, rsrc_cnt,
+                       rsrc_size);
 
-       /*
-        * Discover the port's supported feature set and match it against the
-        * hosts requests.
-        */
-       lpfc_request_features(phba, mboxq);
-       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+       mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+
+       rc = lpfc_sli4_cfg_post_extnts(phba, &rsrc_cnt, type, &emb, mbox);
        if (unlikely(rc)) {
                rc = -EIO;
-               goto out_free_mbox;
+               goto err_exit;
        }
 
        /*
-        * The port must support FCP initiator mode as this is the
-        * only mode running in the host.
+        * Figure out where the response is located.  Then get local pointers
+        * to the response data.  The port does not guarantee to respond to
+        * all extents counts request so update the local variable with the
+        * allocated count from the port.
         */
-       if (!(bf_get(lpfc_mbx_rq_ftr_rsp_fcpi, &mqe->un.req_ftrs))) {
-               lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
-                               "0378 No support for fcpi mode.\n");
-               ftr_rsp++;
+       if (emb == LPFC_SLI4_MBX_EMBED) {
+               rsrc_ext = &mbox->u.mqe.un.alloc_rsrc_extents;
+               id_array = &rsrc_ext->u.rsp.id[0];
+               rsrc_cnt = bf_get(lpfc_mbx_rsrc_cnt, &rsrc_ext->u.rsp);
+       } else {
+               virtaddr = mbox->sge_array->addr[0];
+               n_rsrc = (struct lpfc_mbx_nembed_rsrc_extent *) virtaddr;
+               rsrc_cnt = bf_get(lpfc_mbx_rsrc_cnt, n_rsrc);
+               id_array = &n_rsrc->id;
        }
-       if (bf_get(lpfc_mbx_rq_ftr_rsp_perfh, &mqe->un.req_ftrs))
-               phba->sli3_options |= LPFC_SLI4_PERFH_ENABLED;
-       else
-               phba->sli3_options &= ~LPFC_SLI4_PERFH_ENABLED;
+
+       longs = ((rsrc_cnt * rsrc_size) + BITS_PER_LONG - 1) / BITS_PER_LONG;
+       rsrc_id_cnt = rsrc_cnt * rsrc_size;
+
        /*
-        * If the port cannot support the host's requested features
-        * then turn off the global config parameters to disable the
-        * feature in the driver.  This is not a fatal error.
+        * Based on the resource size and count, correct the base and max
+        * resource values.
         */
-       if ((phba->cfg_enable_bg) &&
-           !(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs)))
-               ftr_rsp++;
+       length = sizeof(struct lpfc_rsrc_blks);
+       switch (type) {
+       case LPFC_RSC_TYPE_FCOE_RPI:
+               phba->sli4_hba.rpi_bmask = kzalloc(longs *
+                                                  sizeof(unsigned long),
+                                                  GFP_KERNEL);
+               if (unlikely(!phba->sli4_hba.rpi_bmask)) {
+                       rc = -ENOMEM;
+                       goto err_exit;
+               }
+               phba->sli4_hba.rpi_ids = kzalloc(rsrc_id_cnt *
+                                                sizeof(uint16_t),
+                                                GFP_KERNEL);
+               if (unlikely(!phba->sli4_hba.rpi_ids)) {
+                       kfree(phba->sli4_hba.rpi_bmask);
+                       rc = -ENOMEM;
+                       goto err_exit;
+               }
 
-       if (phba->max_vpi && phba->cfg_enable_npiv &&
-           !(bf_get(lpfc_mbx_rq_ftr_rsp_npiv, &mqe->un.req_ftrs)))
-               ftr_rsp++;
+               /*
+                * The next_rpi was initialized with the maximum available
+                * count but the port may allocate a smaller number.  Catch
+                * that case and update the next_rpi.
+                */
+               phba->sli4_hba.next_rpi = rsrc_id_cnt;
+
+               /* Initialize local ptrs for common extent processing later. */
+               bmask = phba->sli4_hba.rpi_bmask;
+               ids = phba->sli4_hba.rpi_ids;
+               ext_blk_list = &phba->sli4_hba.lpfc_rpi_blk_list;
+               break;
+       case LPFC_RSC_TYPE_FCOE_VPI:
+               phba->vpi_bmask = kzalloc(longs *
+                                         sizeof(unsigned long),
+                                         GFP_KERNEL);
+               if (unlikely(!phba->vpi_bmask)) {
+                       rc = -ENOMEM;
+                       goto err_exit;
+               }
+               phba->vpi_ids = kzalloc(rsrc_id_cnt *
+                                        sizeof(uint16_t),
+                                        GFP_KERNEL);
+               if (unlikely(!phba->vpi_ids)) {
+                       kfree(phba->vpi_bmask);
+                       rc = -ENOMEM;
+                       goto err_exit;
+               }
+
+               /* Initialize local ptrs for common extent processing later. */
+               bmask = phba->vpi_bmask;
+               ids = phba->vpi_ids;
+               ext_blk_list = &phba->lpfc_vpi_blk_list;
+               break;
+       case LPFC_RSC_TYPE_FCOE_XRI:
+               phba->sli4_hba.xri_bmask = kzalloc(longs *
+                                                  sizeof(unsigned long),
+                                                  GFP_KERNEL);
+               if (unlikely(!phba->sli4_hba.xri_bmask)) {
+                       rc = -ENOMEM;
+                       goto err_exit;
+               }
+               phba->sli4_hba.xri_ids = kzalloc(rsrc_id_cnt *
+                                                sizeof(uint16_t),
+                                                GFP_KERNEL);
+               if (unlikely(!phba->sli4_hba.xri_ids)) {
+                       kfree(phba->sli4_hba.xri_bmask);
+                       rc = -ENOMEM;
+                       goto err_exit;
+               }
+
+               /* Initialize local ptrs for common extent processing later. */
+               bmask = phba->sli4_hba.xri_bmask;
+               ids = phba->sli4_hba.xri_ids;
+               ext_blk_list = &phba->sli4_hba.lpfc_xri_blk_list;
+               break;
+       case LPFC_RSC_TYPE_FCOE_VFI:
+               phba->sli4_hba.vfi_bmask = kzalloc(longs *
+                                                  sizeof(unsigned long),
+                                                  GFP_KERNEL);
+               if (unlikely(!phba->sli4_hba.vfi_bmask)) {
+                       rc = -ENOMEM;
+                       goto err_exit;
+               }
+               phba->sli4_hba.vfi_ids = kzalloc(rsrc_id_cnt *
+                                                sizeof(uint16_t),
+                                                GFP_KERNEL);
+               if (unlikely(!phba->sli4_hba.vfi_ids)) {
+                       kfree(phba->sli4_hba.vfi_bmask);
+                       rc = -ENOMEM;
+                       goto err_exit;
+               }
+
+               /* Initialize local ptrs for common extent processing later. */
+               bmask = phba->sli4_hba.vfi_bmask;
+               ids = phba->sli4_hba.vfi_ids;
+               ext_blk_list = &phba->sli4_hba.lpfc_vfi_blk_list;
+               break;
+       default:
+               /* Unsupported Opcode.  Fail call. */
+               id_array = NULL;
+               bmask = NULL;
+               ids = NULL;
+               ext_blk_list = NULL;
+               goto err_exit;
+       }
+
+       /*
+        * Complete initializing the extent configuration with the
+        * allocated ids assigned to this function.  The bitmask serves
+        * as an index into the array and manages the available ids.  The
+        * array just stores the ids communicated to the port via the wqes.
+        */
+       for (i = 0, j = 0, k = 0; i < rsrc_cnt; i++) {
+               if ((i % 2) == 0)
+                       rsrc_id = bf_get(lpfc_mbx_rsrc_id_word4_0,
+                                        &id_array[k]);
+               else
+                       rsrc_id = bf_get(lpfc_mbx_rsrc_id_word4_1,
+                                        &id_array[k]);
+
+               rsrc_blks = kzalloc(length, GFP_KERNEL);
+               if (unlikely(!rsrc_blks)) {
+                       rc = -ENOMEM;
+                       kfree(bmask);
+                       kfree(ids);
+                       goto err_exit;
+               }
+               rsrc_blks->rsrc_start = rsrc_id;
+               rsrc_blks->rsrc_size = rsrc_size;
+               list_add_tail(&rsrc_blks->list, ext_blk_list);
+               rsrc_start = rsrc_id;
+               if ((type == LPFC_RSC_TYPE_FCOE_XRI) && (j == 0))
+                       phba->sli4_hba.scsi_xri_start = rsrc_start +
+                               lpfc_sli4_get_els_iocb_cnt(phba);
+
+               while (rsrc_id < (rsrc_start + rsrc_size)) {
+                       ids[j] = rsrc_id;
+                       rsrc_id++;
+                       j++;
+               }
+               /* Entire word processed.  Get next word.*/
+               if ((i % 2) == 1)
+                       k++;
+       }
+ err_exit:
+       lpfc_sli4_mbox_cmd_free(phba, mbox);
+       return rc;
+}
+
+/**
+ * lpfc_sli4_dealloc_extent - Deallocate an SLI4 resource extent.
+ * @phba: Pointer to HBA context object.
+ * @type: the extent's type.
+ *
+ * This function deallocates all extents of a particular resource type.
+ * SLI4 does not allow for deallocating a particular extent range.  It
+ * is the caller's responsibility to release all kernel memory resources.
+ **/
+static int
+lpfc_sli4_dealloc_extent(struct lpfc_hba *phba, uint16_t type)
+{
+       int rc;
+       uint32_t length, mbox_tmo = 0;
+       LPFC_MBOXQ_t *mbox;
+       struct lpfc_mbx_dealloc_rsrc_extents *dealloc_rsrc;
+       struct lpfc_rsrc_blks *rsrc_blk, *rsrc_blk_next;
+
+       mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+
+       /*
+        * This function sends an embedded mailbox because it only sends the
+        * the resource type.  All extents of this type are released by the
+        * port.
+        */
+       length = (sizeof(struct lpfc_mbx_dealloc_rsrc_extents) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+                        LPFC_MBOX_OPCODE_DEALLOC_RSRC_EXTENT,
+                        length, LPFC_SLI4_MBX_EMBED);
+
+       /* Send an extents count of 0 - the dealloc doesn't use it. */
+       rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, 0, type,
+                                       LPFC_SLI4_MBX_EMBED);
+       if (unlikely(rc)) {
+               rc = -EIO;
+               goto out_free_mbox;
+       }
+       if (!phba->sli4_hba.intr_enable)
+               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+       else {
+               mbox_tmo = lpfc_mbox_tmo_val(phba, mbox_tmo);
+               rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
+       }
+       if (unlikely(rc)) {
+               rc = -EIO;
+               goto out_free_mbox;
+       }
+
+       dealloc_rsrc = &mbox->u.mqe.un.dealloc_rsrc_extents;
+       if (bf_get(lpfc_mbox_hdr_status,
+                  &dealloc_rsrc->header.cfg_shdr.response)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT,
+                               "2919 Failed to release resource extents "
+                               "for type %d - Status 0x%x Add'l Status 0x%x. "
+                               "Resource memory not released.\n",
+                               type,
+                               bf_get(lpfc_mbox_hdr_status,
+                                   &dealloc_rsrc->header.cfg_shdr.response),
+                               bf_get(lpfc_mbox_hdr_add_status,
+                                   &dealloc_rsrc->header.cfg_shdr.response));
+               rc = -EIO;
+               goto out_free_mbox;
+       }
+
+       /* Release kernel memory resources for the specific type. */
+       switch (type) {
+       case LPFC_RSC_TYPE_FCOE_VPI:
+               kfree(phba->vpi_bmask);
+               kfree(phba->vpi_ids);
+               bf_set(lpfc_vpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
+               list_for_each_entry_safe(rsrc_blk, rsrc_blk_next,
+                                   &phba->lpfc_vpi_blk_list, list) {
+                       list_del_init(&rsrc_blk->list);
+                       kfree(rsrc_blk);
+               }
+               break;
+       case LPFC_RSC_TYPE_FCOE_XRI:
+               kfree(phba->sli4_hba.xri_bmask);
+               kfree(phba->sli4_hba.xri_ids);
+               bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
+               list_for_each_entry_safe(rsrc_blk, rsrc_blk_next,
+                                   &phba->sli4_hba.lpfc_xri_blk_list, list) {
+                       list_del_init(&rsrc_blk->list);
+                       kfree(rsrc_blk);
+               }
+               break;
+       case LPFC_RSC_TYPE_FCOE_VFI:
+               kfree(phba->sli4_hba.vfi_bmask);
+               kfree(phba->sli4_hba.vfi_ids);
+               bf_set(lpfc_vfi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
+               list_for_each_entry_safe(rsrc_blk, rsrc_blk_next,
+                                   &phba->sli4_hba.lpfc_vfi_blk_list, list) {
+                       list_del_init(&rsrc_blk->list);
+                       kfree(rsrc_blk);
+               }
+               break;
+       case LPFC_RSC_TYPE_FCOE_RPI:
+               /* RPI bitmask and physical id array are cleaned up earlier. */
+               list_for_each_entry_safe(rsrc_blk, rsrc_blk_next,
+                                   &phba->sli4_hba.lpfc_rpi_blk_list, list) {
+                       list_del_init(&rsrc_blk->list);
+                       kfree(rsrc_blk);
+               }
+               break;
+       default:
+               break;
+       }
+
+       bf_set(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
+
+ out_free_mbox:
+       mempool_free(mbox, phba->mbox_mem_pool);
+       return rc;
+}
+
+/**
+ * lpfc_sli4_alloc_resource_identifiers - Allocate all SLI4 resource extents.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function allocates all SLI4 resource identifiers.
+ **/
+int
+lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba)
+{
+       int i, rc, error = 0;
+       uint16_t count, base;
+       unsigned long longs;
+
+       if (phba->sli4_hba.extents_in_use) {
+               /*
+                * The port supports resource extents. The XRI, VPI, VFI, RPI
+                * resource extent count must be read and allocated before
+                * provisioning the resource id arrays.
+                */
+               if (bf_get(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags) ==
+                   LPFC_IDX_RSRC_RDY) {
+                       /*
+                        * Extent-based resources are set - the driver could
+                        * be in a port reset. Figure out if any corrective
+                        * actions need to be taken.
+                        */
+                       rc = lpfc_sli4_chk_avail_extnt_rsrc(phba,
+                                                LPFC_RSC_TYPE_FCOE_VFI);
+                       if (rc != 0)
+                               error++;
+                       rc = lpfc_sli4_chk_avail_extnt_rsrc(phba,
+                                                LPFC_RSC_TYPE_FCOE_VPI);
+                       if (rc != 0)
+                               error++;
+                       rc = lpfc_sli4_chk_avail_extnt_rsrc(phba,
+                                                LPFC_RSC_TYPE_FCOE_XRI);
+                       if (rc != 0)
+                               error++;
+                       rc = lpfc_sli4_chk_avail_extnt_rsrc(phba,
+                                                LPFC_RSC_TYPE_FCOE_RPI);
+                       if (rc != 0)
+                               error++;
+
+                       /*
+                        * It's possible that the number of resources
+                        * provided to this port instance changed between
+                        * resets.  Detect this condition and reallocate
+                        * resources.  Otherwise, there is no action.
+                        */
+                       if (error) {
+                               lpfc_printf_log(phba, KERN_INFO,
+                                               LOG_MBOX | LOG_INIT,
+                                               "2931 Detected extent resource "
+                                               "change.  Reallocating all "
+                                               "extents.\n");
+                               rc = lpfc_sli4_dealloc_extent(phba,
+                                                LPFC_RSC_TYPE_FCOE_VFI);
+                               rc = lpfc_sli4_dealloc_extent(phba,
+                                                LPFC_RSC_TYPE_FCOE_VPI);
+                               rc = lpfc_sli4_dealloc_extent(phba,
+                                                LPFC_RSC_TYPE_FCOE_XRI);
+                               rc = lpfc_sli4_dealloc_extent(phba,
+                                                LPFC_RSC_TYPE_FCOE_RPI);
+                       } else
+                               return 0;
+               }
+
+               rc = lpfc_sli4_alloc_extent(phba, LPFC_RSC_TYPE_FCOE_VFI);
+               if (unlikely(rc))
+                       goto err_exit;
+
+               rc = lpfc_sli4_alloc_extent(phba, LPFC_RSC_TYPE_FCOE_VPI);
+               if (unlikely(rc))
+                       goto err_exit;
+
+               rc = lpfc_sli4_alloc_extent(phba, LPFC_RSC_TYPE_FCOE_RPI);
+               if (unlikely(rc))
+                       goto err_exit;
+
+               rc = lpfc_sli4_alloc_extent(phba, LPFC_RSC_TYPE_FCOE_XRI);
+               if (unlikely(rc))
+                       goto err_exit;
+               bf_set(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags,
+                      LPFC_IDX_RSRC_RDY);
+               return rc;
+       } else {
+               /*
+                * The port does not support resource extents.  The XRI, VPI,
+                * VFI, RPI resource ids were determined from READ_CONFIG.
+                * Just allocate the bitmasks and provision the resource id
+                * arrays.  If a port reset is active, the resources don't
+                * need any action - just exit.
+                */
+               if (bf_get(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags) ==
+                   LPFC_IDX_RSRC_RDY)
+                       return 0;
+
+               /* RPIs. */
+               count = phba->sli4_hba.max_cfg_param.max_rpi;
+               base = phba->sli4_hba.max_cfg_param.rpi_base;
+               longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG;
+               phba->sli4_hba.rpi_bmask = kzalloc(longs *
+                                                  sizeof(unsigned long),
+                                                  GFP_KERNEL);
+               if (unlikely(!phba->sli4_hba.rpi_bmask)) {
+                       rc = -ENOMEM;
+                       goto err_exit;
+               }
+               phba->sli4_hba.rpi_ids = kzalloc(count *
+                                                sizeof(uint16_t),
+                                                GFP_KERNEL);
+               if (unlikely(!phba->sli4_hba.rpi_ids)) {
+                       rc = -ENOMEM;
+                       goto free_rpi_bmask;
+               }
+
+               for (i = 0; i < count; i++)
+                       phba->sli4_hba.rpi_ids[i] = base + i;
+
+               /* VPIs. */
+               count = phba->sli4_hba.max_cfg_param.max_vpi;
+               base = phba->sli4_hba.max_cfg_param.vpi_base;
+               longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG;
+               phba->vpi_bmask = kzalloc(longs *
+                                         sizeof(unsigned long),
+                                         GFP_KERNEL);
+               if (unlikely(!phba->vpi_bmask)) {
+                       rc = -ENOMEM;
+                       goto free_rpi_ids;
+               }
+               phba->vpi_ids = kzalloc(count *
+                                       sizeof(uint16_t),
+                                       GFP_KERNEL);
+               if (unlikely(!phba->vpi_ids)) {
+                       rc = -ENOMEM;
+                       goto free_vpi_bmask;
+               }
+
+               for (i = 0; i < count; i++)
+                       phba->vpi_ids[i] = base + i;
+
+               /* XRIs. */
+               count = phba->sli4_hba.max_cfg_param.max_xri;
+               base = phba->sli4_hba.max_cfg_param.xri_base;
+               longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG;
+               phba->sli4_hba.xri_bmask = kzalloc(longs *
+                                                  sizeof(unsigned long),
+                                                  GFP_KERNEL);
+               if (unlikely(!phba->sli4_hba.xri_bmask)) {
+                       rc = -ENOMEM;
+                       goto free_vpi_ids;
+               }
+               phba->sli4_hba.xri_ids = kzalloc(count *
+                                                sizeof(uint16_t),
+                                                GFP_KERNEL);
+               if (unlikely(!phba->sli4_hba.xri_ids)) {
+                       rc = -ENOMEM;
+                       goto free_xri_bmask;
+               }
+
+               for (i = 0; i < count; i++)
+                       phba->sli4_hba.xri_ids[i] = base + i;
+
+               /* VFIs. */
+               count = phba->sli4_hba.max_cfg_param.max_vfi;
+               base = phba->sli4_hba.max_cfg_param.vfi_base;
+               longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG;
+               phba->sli4_hba.vfi_bmask = kzalloc(longs *
+                                                  sizeof(unsigned long),
+                                                  GFP_KERNEL);
+               if (unlikely(!phba->sli4_hba.vfi_bmask)) {
+                       rc = -ENOMEM;
+                       goto free_xri_ids;
+               }
+               phba->sli4_hba.vfi_ids = kzalloc(count *
+                                                sizeof(uint16_t),
+                                                GFP_KERNEL);
+               if (unlikely(!phba->sli4_hba.vfi_ids)) {
+                       rc = -ENOMEM;
+                       goto free_vfi_bmask;
+               }
+
+               for (i = 0; i < count; i++)
+                       phba->sli4_hba.vfi_ids[i] = base + i;
+
+               /*
+                * Mark all resources ready.  An HBA reset doesn't need
+                * to reset the initialization.
+                */
+               bf_set(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags,
+                      LPFC_IDX_RSRC_RDY);
+               return 0;
+       }
+
+ free_vfi_bmask:
+       kfree(phba->sli4_hba.vfi_bmask);
+ free_xri_ids:
+       kfree(phba->sli4_hba.xri_ids);
+ free_xri_bmask:
+       kfree(phba->sli4_hba.xri_bmask);
+ free_vpi_ids:
+       kfree(phba->vpi_ids);
+ free_vpi_bmask:
+       kfree(phba->vpi_bmask);
+ free_rpi_ids:
+       kfree(phba->sli4_hba.rpi_ids);
+ free_rpi_bmask:
+       kfree(phba->sli4_hba.rpi_bmask);
+ err_exit:
+       return rc;
+}
+
+/**
+ * lpfc_sli4_dealloc_resource_identifiers - Deallocate all SLI4 resource extents.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function allocates the number of elements for the specified
+ * resource type.
+ **/
+int
+lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *phba)
+{
+       if (phba->sli4_hba.extents_in_use) {
+               lpfc_sli4_dealloc_extent(phba, LPFC_RSC_TYPE_FCOE_VPI);
+               lpfc_sli4_dealloc_extent(phba, LPFC_RSC_TYPE_FCOE_RPI);
+               lpfc_sli4_dealloc_extent(phba, LPFC_RSC_TYPE_FCOE_XRI);
+               lpfc_sli4_dealloc_extent(phba, LPFC_RSC_TYPE_FCOE_VFI);
+       } else {
+               kfree(phba->vpi_bmask);
+               kfree(phba->vpi_ids);
+               bf_set(lpfc_vpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
+               kfree(phba->sli4_hba.xri_bmask);
+               kfree(phba->sli4_hba.xri_ids);
+               bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
+               kfree(phba->sli4_hba.vfi_bmask);
+               kfree(phba->sli4_hba.vfi_ids);
+               bf_set(lpfc_vfi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
+               bf_set(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
+       }
+
+       return 0;
+}
+
+/**
+ * lpfc_sli4_hba_setup - SLI4 device intialization PCI function
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is the main SLI4 device intialization PCI function. This
+ * function is called by the HBA intialization code, HBA reset code and
+ * HBA error attention handler code. Caller is not required to hold any
+ * locks.
+ **/
+int
+lpfc_sli4_hba_setup(struct lpfc_hba *phba)
+{
+       int rc;
+       LPFC_MBOXQ_t *mboxq;
+       struct lpfc_mqe *mqe;
+       uint8_t *vpd;
+       uint32_t vpd_size;
+       uint32_t ftr_rsp = 0;
+       struct Scsi_Host *shost = lpfc_shost_from_vport(phba->pport);
+       struct lpfc_vport *vport = phba->pport;
+       struct lpfc_dmabuf *mp;
+
+       /* Perform a PCI function reset to start from clean */
+       rc = lpfc_pci_function_reset(phba);
+       if (unlikely(rc))
+               return -ENODEV;
+
+       /* Check the HBA Host Status Register for readyness */
+       rc = lpfc_sli4_post_status_check(phba);
+       if (unlikely(rc))
+               return -ENODEV;
+       else {
+               spin_lock_irq(&phba->hbalock);
+               phba->sli.sli_flag |= LPFC_SLI_ACTIVE;
+               spin_unlock_irq(&phba->hbalock);
+       }
+
+       /*
+        * Allocate a single mailbox container for initializing the
+        * port.
+        */
+       mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq)
+               return -ENOMEM;
+
+       /*
+        * Continue initialization with default values even if driver failed
+        * to read FCoE param config regions
+        */
+       if (lpfc_sli4_read_fcoe_params(phba, mboxq))
+               lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_INIT,
+                       "2570 Failed to read FCoE parameters\n");
+
+       /* Issue READ_REV to collect vpd and FW information. */
+       vpd_size = SLI4_PAGE_SIZE;
+       vpd = kzalloc(vpd_size, GFP_KERNEL);
+       if (!vpd) {
+               rc = -ENOMEM;
+               goto out_free_mbox;
+       }
+
+       rc = lpfc_sli4_read_rev(phba, mboxq, vpd, &vpd_size);
+       if (unlikely(rc)) {
+               kfree(vpd);
+               goto out_free_mbox;
+       }
+       mqe = &mboxq->u.mqe;
+       phba->sli_rev = bf_get(lpfc_mbx_rd_rev_sli_lvl, &mqe->un.read_rev);
+       if (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev))
+               phba->hba_flag |= HBA_FCOE_MODE;
+       else
+               phba->hba_flag &= ~HBA_FCOE_MODE;
+
+       if (bf_get(lpfc_mbx_rd_rev_cee_ver, &mqe->un.read_rev) ==
+               LPFC_DCBX_CEE_MODE)
+               phba->hba_flag |= HBA_FIP_SUPPORT;
+       else
+               phba->hba_flag &= ~HBA_FIP_SUPPORT;
+
+       if (phba->sli_rev != LPFC_SLI_REV4) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                       "0376 READ_REV Error. SLI Level %d "
+                       "FCoE enabled %d\n",
+                       phba->sli_rev, phba->hba_flag & HBA_FCOE_MODE);
+               rc = -EIO;
+               kfree(vpd);
+               goto out_free_mbox;
+       }
+       /*
+        * Evaluate the read rev and vpd data. Populate the driver
+        * state with the results. If this routine fails, the failure
+        * is not fatal as the driver will use generic values.
+        */
+       rc = lpfc_parse_vpd(phba, vpd, vpd_size);
+       if (unlikely(!rc)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                               "0377 Error %d parsing vpd. "
+                               "Using defaults.\n", rc);
+               rc = 0;
+       }
+       kfree(vpd);
+
+       /* Save information as VPD data */
+       phba->vpd.rev.biuRev = mqe->un.read_rev.first_hw_rev;
+       phba->vpd.rev.smRev = mqe->un.read_rev.second_hw_rev;
+       phba->vpd.rev.endecRev = mqe->un.read_rev.third_hw_rev;
+       phba->vpd.rev.fcphHigh = bf_get(lpfc_mbx_rd_rev_fcph_high,
+                                        &mqe->un.read_rev);
+       phba->vpd.rev.fcphLow = bf_get(lpfc_mbx_rd_rev_fcph_low,
+                                      &mqe->un.read_rev);
+       phba->vpd.rev.feaLevelHigh = bf_get(lpfc_mbx_rd_rev_ftr_lvl_high,
+                                           &mqe->un.read_rev);
+       phba->vpd.rev.feaLevelLow = bf_get(lpfc_mbx_rd_rev_ftr_lvl_low,
+                                          &mqe->un.read_rev);
+       phba->vpd.rev.sli1FwRev = mqe->un.read_rev.fw_id_rev;
+       memcpy(phba->vpd.rev.sli1FwName, mqe->un.read_rev.fw_name, 16);
+       phba->vpd.rev.sli2FwRev = mqe->un.read_rev.ulp_fw_id_rev;
+       memcpy(phba->vpd.rev.sli2FwName, mqe->un.read_rev.ulp_fw_name, 16);
+       phba->vpd.rev.opFwRev = mqe->un.read_rev.fw_id_rev;
+       memcpy(phba->vpd.rev.opFwName, mqe->un.read_rev.fw_name, 16);
+       lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+                       "(%d):0380 READ_REV Status x%x "
+                       "fw_rev:%s fcphHi:%x fcphLo:%x flHi:%x flLo:%x\n",
+                       mboxq->vport ? mboxq->vport->vpi : 0,
+                       bf_get(lpfc_mqe_status, mqe),
+                       phba->vpd.rev.opFwName,
+                       phba->vpd.rev.fcphHigh, phba->vpd.rev.fcphLow,
+                       phba->vpd.rev.feaLevelHigh, phba->vpd.rev.feaLevelLow);
+
+       /*
+        * Discover the port's supported feature set and match it against the
+        * hosts requests.
+        */
+       lpfc_request_features(phba, mboxq);
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+       if (unlikely(rc)) {
+               rc = -EIO;
+               goto out_free_mbox;
+       }
+
+       /*
+        * The port must support FCP initiator mode as this is the
+        * only mode running in the host.
+        */
+       if (!(bf_get(lpfc_mbx_rq_ftr_rsp_fcpi, &mqe->un.req_ftrs))) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
+                               "0378 No support for fcpi mode.\n");
+               ftr_rsp++;
+       }
+       if (bf_get(lpfc_mbx_rq_ftr_rsp_perfh, &mqe->un.req_ftrs))
+               phba->sli3_options |= LPFC_SLI4_PERFH_ENABLED;
+       else
+               phba->sli3_options &= ~LPFC_SLI4_PERFH_ENABLED;
+       /*
+        * If the port cannot support the host's requested features
+        * then turn off the global config parameters to disable the
+        * feature in the driver.  This is not a fatal error.
+        */
+       if ((phba->cfg_enable_bg) &&
+           !(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs)))
+               ftr_rsp++;
+
+       if (phba->max_vpi && phba->cfg_enable_npiv &&
+           !(bf_get(lpfc_mbx_rq_ftr_rsp_npiv, &mqe->un.req_ftrs)))
+               ftr_rsp++;
 
        if (ftr_rsp) {
                lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
@@ -4873,6 +5688,18 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
        phba->sli3_options |= (LPFC_SLI3_NPIV_ENABLED | LPFC_SLI3_HBQ_ENABLED);
        spin_unlock_irq(&phba->hbalock);
 
+       /*
+        * Allocate all resources (xri,rpi,vpi,vfi) now.  Subsequent
+        * calls depends on these resources to complete port setup.
+        */
+       rc = lpfc_sli4_alloc_resource_identifiers(phba);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                               "2920 Failed to alloc Resource IDs "
+                               "rc = x%x\n", rc);
+               goto out_free_mbox;
+       }
+
        /* Read the port's service parameters. */
        rc = lpfc_read_sparam(phba, mboxq, vport->vpi);
        if (rc) {
@@ -4906,35 +5733,37 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
                goto out_free_mbox;
        }
 
-       if (phba->cfg_soft_wwnn)
-               u64_to_wwn(phba->cfg_soft_wwnn,
-                          vport->fc_sparam.nodeName.u.wwn);
-       if (phba->cfg_soft_wwpn)
-               u64_to_wwn(phba->cfg_soft_wwpn,
-                          vport->fc_sparam.portName.u.wwn);
-       memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName,
-              sizeof(struct lpfc_name));
-       memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
-              sizeof(struct lpfc_name));
+       lpfc_update_vport_wwn(vport);
 
        /* Update the fc_host data structures with new wwn. */
        fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn);
        fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn);
 
        /* Register SGL pool to the device using non-embedded mailbox command */
-       rc = lpfc_sli4_post_sgl_list(phba);
-       if (unlikely(rc)) {
-               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
-                               "0582 Error %d during sgl post operation\n",
-                                       rc);
-               rc = -ENODEV;
-               goto out_free_mbox;
+       if (!phba->sli4_hba.extents_in_use) {
+               rc = lpfc_sli4_post_els_sgl_list(phba);
+               if (unlikely(rc)) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                                       "0582 Error %d during els sgl post "
+                                       "operation\n", rc);
+                       rc = -ENODEV;
+                       goto out_free_mbox;
+               }
+       } else {
+               rc = lpfc_sli4_post_els_sgl_list_ext(phba);
+               if (unlikely(rc)) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                                       "2560 Error %d during els sgl post "
+                                       "operation\n", rc);
+                       rc = -ENODEV;
+                       goto out_free_mbox;
+               }
        }
 
        /* Register SCSI SGL pool to the device */
        rc = lpfc_sli4_repost_scsi_sgl_list(phba);
        if (unlikely(rc)) {
-               lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
                                "0383 Error %d during scsi sgl post "
                                "operation\n", rc);
                /* Some Scsi buffers were moved to the abort scsi list */
@@ -5747,10 +6576,15 @@ lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
        lpfc_sli_pcimem_bcopy(&mbox_rgn->mcqe, &mboxq->mcqe,
                              sizeof(struct lpfc_mcqe));
        mcqe_status = bf_get(lpfc_mcqe_status, &mbox_rgn->mcqe);
-
-       /* Prefix the mailbox status with range x4000 to note SLI4 status. */
+       /*
+        * When the CQE status indicates a failure and the mailbox status
+        * indicates success then copy the CQE status into the mailbox status
+        * (and prefix it with x4000).
+        */
        if (mcqe_status != MB_CQE_STATUS_SUCCESS) {
-               bf_set(lpfc_mqe_status, mb, LPFC_MBX_ERROR_RANGE | mcqe_status);
+               if (bf_get(lpfc_mqe_status, mb) == MBX_SUCCESS)
+                       bf_set(lpfc_mqe_status, mb,
+                              (LPFC_MBX_ERROR_RANGE | mcqe_status));
                rc = MBXERR_ERROR;
        } else
                lpfc_sli4_swap_str(phba, mboxq);
@@ -5819,7 +6653,7 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
                else
                        rc = -EIO;
                if (rc != MBX_SUCCESS)
-                       lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
                                        "(%d):2541 Mailbox command x%x "
                                        "(x%x) cannot issue Data: x%x x%x\n",
                                        mboxq->vport ? mboxq->vport->vpi : 0,
@@ -6307,6 +7141,7 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
                        sgl->addr_hi = bpl->addrHigh;
                        sgl->addr_lo = bpl->addrLow;
 
+                       sgl->word2 = le32_to_cpu(sgl->word2);
                        if ((i+1) == numBdes)
                                bf_set(lpfc_sli4_sge_last, sgl, 1);
                        else
@@ -6343,6 +7178,7 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
                                cpu_to_le32(icmd->un.genreq64.bdl.addrHigh);
                        sgl->addr_lo =
                                cpu_to_le32(icmd->un.genreq64.bdl.addrLow);
+                       sgl->word2 = le32_to_cpu(sgl->word2);
                        bf_set(lpfc_sli4_sge_last, sgl, 1);
                        sgl->word2 = cpu_to_le32(sgl->word2);
                        sgl->sge_len =
@@ -6474,7 +7310,8 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                        els_id = ((iocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK)
                                        >> LPFC_FIP_ELS_ID_SHIFT);
                }
-               bf_set(wqe_temp_rpi, &wqe->els_req.wqe_com, ndlp->nlp_rpi);
+               bf_set(wqe_temp_rpi, &wqe->els_req.wqe_com,
+                      phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
                bf_set(wqe_els_id, &wqe->els_req.wqe_com, els_id);
                bf_set(wqe_dbde, &wqe->els_req.wqe_com, 1);
                bf_set(wqe_iod, &wqe->els_req.wqe_com, LPFC_WQE_IOD_READ);
@@ -6623,14 +7460,15 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                       iocbq->iocb.ulpContext);
                if (!iocbq->iocb.ulpCt_h && iocbq->iocb.ulpCt_l)
                        bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com,
-                              iocbq->vport->vpi + phba->vpi_base);
+                              phba->vpi_ids[iocbq->vport->vpi]);
                bf_set(wqe_dbde, &wqe->xmit_els_rsp.wqe_com, 1);
                bf_set(wqe_iod, &wqe->xmit_els_rsp.wqe_com, LPFC_WQE_IOD_WRITE);
                bf_set(wqe_qosd, &wqe->xmit_els_rsp.wqe_com, 1);
                bf_set(wqe_lenloc, &wqe->xmit_els_rsp.wqe_com,
                       LPFC_WQE_LENLOC_WORD3);
                bf_set(wqe_ebde_cnt, &wqe->xmit_els_rsp.wqe_com, 0);
-               bf_set(wqe_rsp_temp_rpi, &wqe->xmit_els_rsp, ndlp->nlp_rpi);
+               bf_set(wqe_rsp_temp_rpi, &wqe->xmit_els_rsp,
+                      phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
                command_type = OTHER_COMMAND;
        break;
        case CMD_CLOSE_XRI_CN:
@@ -6729,6 +7567,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                return IOCB_ERROR;
        break;
        }
+
        bf_set(wqe_xri_tag, &wqe->generic.wqe_com, xritag);
        bf_set(wqe_reqtag, &wqe->generic.wqe_com, iocbq->iotag);
        wqe->generic.wqe_com.abort_tag = abort_tag;
@@ -6776,7 +7615,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
                                        return IOCB_BUSY;
                                }
                        } else {
-                       sglq = __lpfc_sli_get_sglq(phba, piocb);
+                               sglq = __lpfc_sli_get_sglq(phba, piocb);
                                if (!sglq) {
                                        if (!(flag & SLI_IOCB_RET_IOCB)) {
                                                __lpfc_sli_ringtx_put(phba,
@@ -6789,11 +7628,11 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
                        }
                }
        } else if (piocb->iocb_flag &  LPFC_IO_FCP) {
-               sglq = NULL; /* These IO's already have an XRI and
-                             * a mapped sgl.
-                             */
+               /* These IO's already have an XRI and a mapped sgl. */
+               sglq = NULL;
        } else {
-               /* This is a continuation of a commandi,(CX) so this
+               /*
+                * This is a continuation of a commandi,(CX) so this
                 * sglq is on the active list
                 */
                sglq = __lpfc_get_active_sglq(phba, piocb->sli4_xritag);
@@ -6802,8 +7641,8 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
        }
 
        if (sglq) {
+               piocb->sli4_lxritag = sglq->sli4_lxritag;
                piocb->sli4_xritag = sglq->sli4_xritag;
-
                if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocb, sglq))
                        return IOCB_ERROR;
        }
@@ -9799,7 +10638,12 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe)
                break;
        case LPFC_WCQ:
                while ((cqe = lpfc_sli4_cq_get(cq))) {
-                       workposted |= lpfc_sli4_sp_handle_cqe(phba, cq, cqe);
+                       if (cq->subtype == LPFC_FCP)
+                               workposted |= lpfc_sli4_fp_handle_wcqe(phba, cq,
+                                                                      cqe);
+                       else
+                               workposted |= lpfc_sli4_sp_handle_cqe(phba, cq,
+                                                                     cqe);
                        if (!(++ecount % LPFC_GET_QE_REL_INT))
                                lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM);
                }
@@ -11446,6 +12290,7 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba,
        LPFC_MBOXQ_t *mbox;
        int rc;
        uint32_t shdr_status, shdr_add_status;
+       uint32_t mbox_tmo;
        union lpfc_sli4_cfg_shdr *shdr;
 
        if (xritag == NO_XRI) {
@@ -11479,8 +12324,10 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba,
                                cpu_to_le32(putPaddrHigh(pdma_phys_addr1));
        if (!phba->sli4_hba.intr_enable)
                rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
-       else
-               rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
+       else {
+               mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+               rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
+       }
        /* The IOCTL status is embedded in the mailbox subheader. */
        shdr = (union lpfc_sli4_cfg_shdr *) &post_sgl_pages->header.cfg_shdr;
        shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
@@ -11494,7 +12341,77 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba,
                                shdr_status, shdr_add_status, rc);
                rc = -ENXIO;
        }
-       return 0;
+       return 0;
+}
+
+/**
+ * lpfc_sli4_init_rpi_hdrs - Post the rpi header memory region to the port
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to post rpi header templates to the
+ * port for those SLI4 ports that do not support extents.  This routine
+ * posts a PAGE_SIZE memory region to the port to hold up to
+ * PAGE_SIZE modulo 64 rpi context headers.  This is an initialization routine
+ * and should be called only when interrupts are disabled.
+ *
+ * Return codes
+ *     0 - successful
+ *     -ERROR - otherwise.
+ */
+uint16_t
+lpfc_sli4_alloc_xri(struct lpfc_hba *phba)
+{
+       unsigned long xri;
+
+       /*
+        * Fetch the next logical xri.  Because this index is logical,
+        * the driver starts at 0 each time.
+        */
+       spin_lock_irq(&phba->hbalock);
+       xri = find_next_zero_bit(phba->sli4_hba.xri_bmask,
+                                phba->sli4_hba.max_cfg_param.max_xri, 0);
+       if (xri >= phba->sli4_hba.max_cfg_param.max_xri) {
+               spin_unlock_irq(&phba->hbalock);
+               return NO_XRI;
+       } else {
+               set_bit(xri, phba->sli4_hba.xri_bmask);
+               phba->sli4_hba.max_cfg_param.xri_used++;
+               phba->sli4_hba.xri_count++;
+       }
+
+       spin_unlock_irq(&phba->hbalock);
+       return xri;
+}
+
+/**
+ * lpfc_sli4_free_xri - Release an xri for reuse.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to release an xri to the pool of
+ * available rpis maintained by the driver.
+ **/
+void
+__lpfc_sli4_free_xri(struct lpfc_hba *phba, int xri)
+{
+       if (test_and_clear_bit(xri, phba->sli4_hba.xri_bmask)) {
+               phba->sli4_hba.xri_count--;
+               phba->sli4_hba.max_cfg_param.xri_used--;
+       }
+}
+
+/**
+ * lpfc_sli4_free_xri - Release an xri for reuse.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to release an xri to the pool of
+ * available rpis maintained by the driver.
+ **/
+void
+lpfc_sli4_free_xri(struct lpfc_hba *phba, int xri)
+{
+       spin_lock_irq(&phba->hbalock);
+       __lpfc_sli4_free_xri(phba, xri);
+       spin_unlock_irq(&phba->hbalock);
 }
 
 /**
@@ -11510,30 +12427,23 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba,
 uint16_t
 lpfc_sli4_next_xritag(struct lpfc_hba *phba)
 {
-       uint16_t xritag;
+       uint16_t xri_index;
 
-       spin_lock_irq(&phba->hbalock);
-       xritag = phba->sli4_hba.next_xri;
-       if ((xritag != (uint16_t) -1) && xritag <
-               (phba->sli4_hba.max_cfg_param.max_xri
-                       + phba->sli4_hba.max_cfg_param.xri_base)) {
-               phba->sli4_hba.next_xri++;
-               phba->sli4_hba.max_cfg_param.xri_used++;
-               spin_unlock_irq(&phba->hbalock);
-               return xritag;
-       }
-       spin_unlock_irq(&phba->hbalock);
-       lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+       xri_index = lpfc_sli4_alloc_xri(phba);
+       if (xri_index != NO_XRI)
+               return xri_index;
+
+       lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
                        "2004 Failed to allocate XRI.last XRITAG is %d"
                        " Max XRI is %d, Used XRI is %d\n",
-                       phba->sli4_hba.next_xri,
+                       xri_index,
                        phba->sli4_hba.max_cfg_param.max_xri,
                        phba->sli4_hba.max_cfg_param.xri_used);
-       return -1;
+       return NO_XRI;
 }
 
 /**
- * lpfc_sli4_post_sgl_list - post a block of sgl list to the firmware.
+ * lpfc_sli4_post_els_sgl_list - post a block of ELS sgls to the port.
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to post a block of driver's sgl pages to the
@@ -11542,7 +12452,7 @@ lpfc_sli4_next_xritag(struct lpfc_hba *phba)
  * stopped.
  **/
 int
-lpfc_sli4_post_sgl_list(struct lpfc_hba *phba)
+lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba)
 {
        struct lpfc_sglq *sglq_entry;
        struct lpfc_mbx_post_uembed_sgl_page1 *sgl;
@@ -11551,7 +12461,7 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba)
        LPFC_MBOXQ_t *mbox;
        uint32_t reqlen, alloclen, pg_pairs;
        uint32_t mbox_tmo;
-       uint16_t xritag_start = 0;
+       uint16_t xritag_start = 0, lxri = 0;
        int els_xri_cnt, rc = 0;
        uint32_t shdr_status, shdr_add_status;
        union lpfc_sli4_cfg_shdr *shdr;
@@ -11568,11 +12478,8 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba)
                return -ENOMEM;
        }
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-       if (!mbox) {
-               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                               "2560 Failed to allocate mbox cmd memory\n");
+       if (!mbox)
                return -ENOMEM;
-       }
 
        /* Allocate DMA memory and set up the non-embedded mailbox command */
        alloclen = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
@@ -11587,15 +12494,30 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba)
                lpfc_sli4_mbox_cmd_free(phba, mbox);
                return -ENOMEM;
        }
-       /* Get the first SGE entry from the non-embedded DMA memory */
-       viraddr = mbox->sge_array->addr[0];
-
        /* Set up the SGL pages in the non-embedded DMA pages */
+       viraddr = mbox->sge_array->addr[0];
        sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr;
        sgl_pg_pairs = &sgl->sgl_pg_pairs;
 
        for (pg_pairs = 0; pg_pairs < els_xri_cnt; pg_pairs++) {
                sglq_entry = phba->sli4_hba.lpfc_els_sgl_array[pg_pairs];
+
+               /*
+                * Assign the sglq a physical xri only if the driver has not
+                * initialized those resources.  A port reset only needs
+                * the sglq's posted.
+                */
+               if (bf_get(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags) !=
+                   LPFC_XRI_RSRC_RDY) {
+                       lxri = lpfc_sli4_next_xritag(phba);
+                       if (lxri == NO_XRI) {
+                               lpfc_sli4_mbox_cmd_free(phba, mbox);
+                               return -ENOMEM;
+                       }
+                       sglq_entry->sli4_lxritag = lxri;
+                       sglq_entry->sli4_xritag = phba->sli4_hba.xri_ids[lxri];
+               }
+
                /* Set up the sge entry */
                sgl_pg_pairs->sgl_pg0_addr_lo =
                                cpu_to_le32(putPaddrLow(sglq_entry->phys));
@@ -11605,16 +12527,17 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba)
                                cpu_to_le32(putPaddrLow(0));
                sgl_pg_pairs->sgl_pg1_addr_hi =
                                cpu_to_le32(putPaddrHigh(0));
+
                /* Keep the first xritag on the list */
                if (pg_pairs == 0)
                        xritag_start = sglq_entry->sli4_xritag;
                sgl_pg_pairs++;
        }
+
+       /* Complete initialization and perform endian conversion. */
        bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start);
        bf_set(lpfc_post_sgl_pages_xricnt, sgl, els_xri_cnt);
-       /* Perform endian conversion if necessary */
        sgl->word0 = cpu_to_le32(sgl->word0);
-
        if (!phba->sli4_hba.intr_enable)
                rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
        else {
@@ -11633,6 +12556,181 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba)
                                shdr_status, shdr_add_status, rc);
                rc = -ENXIO;
        }
+
+       if (rc == 0)
+               bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags,
+                      LPFC_XRI_RSRC_RDY);
+       return rc;
+}
+
+/**
+ * lpfc_sli4_post_els_sgl_list_ext - post a block of ELS sgls to the port.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to post a block of driver's sgl pages to the
+ * HBA using non-embedded mailbox command. No Lock is held. This routine
+ * is only called when the driver is loading and after all IO has been
+ * stopped.
+ **/
+int
+lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba)
+{
+       struct lpfc_sglq *sglq_entry;
+       struct lpfc_mbx_post_uembed_sgl_page1 *sgl;
+       struct sgl_page_pairs *sgl_pg_pairs;
+       void *viraddr;
+       LPFC_MBOXQ_t *mbox;
+       uint32_t reqlen, alloclen, index;
+       uint32_t mbox_tmo;
+       uint16_t rsrc_start, rsrc_size, els_xri_cnt;
+       uint16_t xritag_start = 0, lxri = 0;
+       struct lpfc_rsrc_blks *rsrc_blk;
+       int cnt, ttl_cnt, rc = 0;
+       int loop_cnt;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+
+       /* The number of sgls to be posted */
+       els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba);
+
+       reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) +
+                sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
+       if (reqlen > SLI4_PAGE_SIZE) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "2989 Block sgl registration required DMA "
+                               "size (%d) great than a page\n", reqlen);
+               return -ENOMEM;
+       }
+
+       cnt = 0;
+       ttl_cnt = 0;
+       list_for_each_entry(rsrc_blk, &phba->sli4_hba.lpfc_xri_blk_list,
+                           list) {
+               rsrc_start = rsrc_blk->rsrc_start;
+               rsrc_size = rsrc_blk->rsrc_size;
+
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "3014 Working ELS Extent start %d, cnt %d\n",
+                               rsrc_start, rsrc_size);
+
+               loop_cnt = min(els_xri_cnt, rsrc_size);
+               if (ttl_cnt + loop_cnt >= els_xri_cnt) {
+                       loop_cnt = els_xri_cnt - ttl_cnt;
+                       ttl_cnt = els_xri_cnt;
+               }
+
+               mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+               if (!mbox)
+                       return -ENOMEM;
+               /*
+                * Allocate DMA memory and set up the non-embedded mailbox
+                * command.
+                */
+               alloclen = lpfc_sli4_config(phba, mbox,
+                                       LPFC_MBOX_SUBSYSTEM_FCOE,
+                                       LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES,
+                                       reqlen, LPFC_SLI4_MBX_NEMBED);
+               if (alloclen < reqlen) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "2987 Allocated DMA memory size (%d) "
+                                       "is less than the requested DMA memory "
+                                       "size (%d)\n", alloclen, reqlen);
+                       lpfc_sli4_mbox_cmd_free(phba, mbox);
+                       return -ENOMEM;
+               }
+
+               /* Set up the SGL pages in the non-embedded DMA pages */
+               viraddr = mbox->sge_array->addr[0];
+               sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr;
+               sgl_pg_pairs = &sgl->sgl_pg_pairs;
+
+               /*
+                * The starting resource may not begin at zero. Control
+                * the loop variants via the block resource parameters,
+                * but handle the sge pointers with a zero-based index
+                * that doesn't get reset per loop pass.
+                */
+               for (index = rsrc_start;
+                    index < rsrc_start + loop_cnt;
+                    index++) {
+                       sglq_entry = phba->sli4_hba.lpfc_els_sgl_array[cnt];
+
+                       /*
+                        * Assign the sglq a physical xri only if the driver
+                        * has not initialized those resources.  A port reset
+                        * only needs the sglq's posted.
+                        */
+                       if (bf_get(lpfc_xri_rsrc_rdy,
+                                  &phba->sli4_hba.sli4_flags) !=
+                                  LPFC_XRI_RSRC_RDY) {
+                               lxri = lpfc_sli4_next_xritag(phba);
+                               if (lxri == NO_XRI) {
+                                       lpfc_sli4_mbox_cmd_free(phba, mbox);
+                                       rc = -ENOMEM;
+                                       goto err_exit;
+                               }
+                               sglq_entry->sli4_lxritag = lxri;
+                               sglq_entry->sli4_xritag =
+                                               phba->sli4_hba.xri_ids[lxri];
+                       }
+
+                       /* Set up the sge entry */
+                       sgl_pg_pairs->sgl_pg0_addr_lo =
+                               cpu_to_le32(putPaddrLow(sglq_entry->phys));
+                       sgl_pg_pairs->sgl_pg0_addr_hi =
+                               cpu_to_le32(putPaddrHigh(sglq_entry->phys));
+                       sgl_pg_pairs->sgl_pg1_addr_lo =
+                               cpu_to_le32(putPaddrLow(0));
+                       sgl_pg_pairs->sgl_pg1_addr_hi =
+                               cpu_to_le32(putPaddrHigh(0));
+
+                       /* Track the starting physical XRI for the mailbox. */
+                       if (index == rsrc_start)
+                               xritag_start = sglq_entry->sli4_xritag;
+                       sgl_pg_pairs++;
+                       cnt++;
+               }
+
+               /* Complete initialization and perform endian conversion. */
+               rsrc_blk->rsrc_used += loop_cnt;
+               bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start);
+               bf_set(lpfc_post_sgl_pages_xricnt, sgl, loop_cnt);
+               sgl->word0 = cpu_to_le32(sgl->word0);
+
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "3015 Post ELS Extent SGL, start %d, "
+                               "cnt %d, used %d\n",
+                               xritag_start, loop_cnt, rsrc_blk->rsrc_used);
+               if (!phba->sli4_hba.intr_enable)
+                       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+               else {
+                       mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+                       rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
+               }
+               shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr;
+               shdr_status = bf_get(lpfc_mbox_hdr_status,
+                                    &shdr->response);
+               shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
+                                        &shdr->response);
+               if (rc != MBX_TIMEOUT)
+                       lpfc_sli4_mbox_cmd_free(phba, mbox);
+               if (shdr_status || shdr_add_status || rc) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                                       "2988 POST_SGL_BLOCK mailbox "
+                                       "command failed status x%x "
+                                       "add_status x%x mbx status x%x\n",
+                                       shdr_status, shdr_add_status, rc);
+                       rc = -ENXIO;
+                       goto err_exit;
+               }
+               if (ttl_cnt >= els_xri_cnt)
+                       break;
+       }
+
+ err_exit:
+       if (rc == 0)
+               bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags,
+                      LPFC_XRI_RSRC_RDY);
        return rc;
 }
 
@@ -11693,6 +12791,7 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist,
                lpfc_sli4_mbox_cmd_free(phba, mbox);
                return -ENOMEM;
        }
+
        /* Get the first SGE entry from the non-embedded DMA memory */
        viraddr = mbox->sge_array->addr[0];
 
@@ -11747,6 +12846,169 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist,
        return rc;
 }
 
+/**
+ * lpfc_sli4_post_scsi_sgl_blk_ext - post a block of scsi sgls to the port.
+ * @phba: pointer to lpfc hba data structure.
+ * @sblist: pointer to scsi buffer list.
+ * @count: number of scsi buffers on the list.
+ *
+ * This routine is invoked to post a block of @count scsi sgl pages from a
+ * SCSI buffer list @sblist to the HBA using non-embedded mailbox command.
+ * No Lock is held.
+ *
+ **/
+int
+lpfc_sli4_post_scsi_sgl_blk_ext(struct lpfc_hba *phba, struct list_head *sblist,
+                               int cnt)
+{
+       struct lpfc_scsi_buf *psb = NULL;
+       struct lpfc_mbx_post_uembed_sgl_page1 *sgl;
+       struct sgl_page_pairs *sgl_pg_pairs;
+       void *viraddr;
+       LPFC_MBOXQ_t *mbox;
+       uint32_t reqlen, alloclen, pg_pairs;
+       uint32_t mbox_tmo;
+       uint16_t xri_start = 0, scsi_xri_start;
+       uint16_t rsrc_range;
+       int rc = 0, avail_cnt;
+       uint32_t shdr_status, shdr_add_status;
+       dma_addr_t pdma_phys_bpl1;
+       union lpfc_sli4_cfg_shdr *shdr;
+       struct lpfc_rsrc_blks *rsrc_blk;
+       uint32_t xri_cnt = 0;
+
+       /* Calculate the total requested length of the dma memory */
+       reqlen = cnt * sizeof(struct sgl_page_pairs) +
+                sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
+       if (reqlen > SLI4_PAGE_SIZE) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "2932 Block sgl registration required DMA "
+                               "size (%d) great than a page\n", reqlen);
+               return -ENOMEM;
+       }
+
+       /*
+        * The use of extents requires the driver to post the sgl headers
+        * in multiple postings to meet the contiguous resource assignment.
+        */
+       psb = list_prepare_entry(psb, sblist, list);
+       scsi_xri_start = phba->sli4_hba.scsi_xri_start;
+       list_for_each_entry(rsrc_blk, &phba->sli4_hba.lpfc_xri_blk_list,
+                           list) {
+               rsrc_range = rsrc_blk->rsrc_start + rsrc_blk->rsrc_size;
+               if (rsrc_range < scsi_xri_start)
+                       continue;
+               else if (rsrc_blk->rsrc_used >= rsrc_blk->rsrc_size)
+                       continue;
+               else
+                       avail_cnt = rsrc_blk->rsrc_size - rsrc_blk->rsrc_used;
+
+               reqlen = (avail_cnt * sizeof(struct sgl_page_pairs)) +
+                       sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
+               /*
+                * Allocate DMA memory and set up the non-embedded mailbox
+                * command. The mbox is used to post an SGL page per loop
+                * but the DMA memory has a use-once semantic so the mailbox
+                * is used and freed per loop pass.
+                */
+               mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+               if (!mbox) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "2933 Failed to allocate mbox cmd "
+                                       "memory\n");
+                       return -ENOMEM;
+               }
+               alloclen = lpfc_sli4_config(phba, mbox,
+                                       LPFC_MBOX_SUBSYSTEM_FCOE,
+                                       LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES,
+                                       reqlen,
+                                       LPFC_SLI4_MBX_NEMBED);
+               if (alloclen < reqlen) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "2934 Allocated DMA memory size (%d) "
+                                       "is less than the requested DMA memory "
+                                       "size (%d)\n", alloclen, reqlen);
+                       lpfc_sli4_mbox_cmd_free(phba, mbox);
+                       return -ENOMEM;
+               }
+
+               /* Get the first SGE entry from the non-embedded DMA memory */
+               viraddr = mbox->sge_array->addr[0];
+
+               /* Set up the SGL pages in the non-embedded DMA pages */
+               sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr;
+               sgl_pg_pairs = &sgl->sgl_pg_pairs;
+
+               /* pg_pairs tracks posted SGEs per loop iteration. */
+               pg_pairs = 0;
+               list_for_each_entry_continue(psb, sblist, list) {
+                       /* Set up the sge entry */
+                       sgl_pg_pairs->sgl_pg0_addr_lo =
+                               cpu_to_le32(putPaddrLow(psb->dma_phys_bpl));
+                       sgl_pg_pairs->sgl_pg0_addr_hi =
+                               cpu_to_le32(putPaddrHigh(psb->dma_phys_bpl));
+                       if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE)
+                               pdma_phys_bpl1 = psb->dma_phys_bpl +
+                                       SGL_PAGE_SIZE;
+                       else
+                               pdma_phys_bpl1 = 0;
+                       sgl_pg_pairs->sgl_pg1_addr_lo =
+                               cpu_to_le32(putPaddrLow(pdma_phys_bpl1));
+                       sgl_pg_pairs->sgl_pg1_addr_hi =
+                               cpu_to_le32(putPaddrHigh(pdma_phys_bpl1));
+                       /* Keep the first xri for this extent. */
+                       if (pg_pairs == 0)
+                               xri_start = psb->cur_iocbq.sli4_xritag;
+                       sgl_pg_pairs++;
+                       pg_pairs++;
+                       xri_cnt++;
+
+                       /*
+                        * Track two exit conditions - the loop has constructed
+                        * all of the caller's SGE pairs or all available
+                        * resource IDs in this extent are consumed.
+                        */
+                       if ((xri_cnt == cnt) || (pg_pairs >= avail_cnt))
+                               break;
+               }
+               rsrc_blk->rsrc_used += pg_pairs;
+               bf_set(lpfc_post_sgl_pages_xri, sgl, xri_start);
+               bf_set(lpfc_post_sgl_pages_xricnt, sgl, pg_pairs);
+
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "3016 Post SCSI Extent SGL, start %d, cnt %d "
+                               "blk use %d\n",
+                               xri_start, pg_pairs, rsrc_blk->rsrc_used);
+               /* Perform endian conversion if necessary */
+               sgl->word0 = cpu_to_le32(sgl->word0);
+               if (!phba->sli4_hba.intr_enable)
+                       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+               else {
+                       mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+                       rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
+               }
+               shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr;
+               shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+               shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
+                                        &shdr->response);
+               if (rc != MBX_TIMEOUT)
+                       lpfc_sli4_mbox_cmd_free(phba, mbox);
+               if (shdr_status || shdr_add_status || rc) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                                       "2935 POST_SGL_BLOCK mailbox command "
+                                       "failed status x%x add_status x%x "
+                                       "mbx status x%x\n",
+                                       shdr_status, shdr_add_status, rc);
+                       return -ENXIO;
+               }
+
+               /* Post only what is requested. */
+               if (xri_cnt >= cnt)
+                       break;
+       }
+       return rc;
+}
+
 /**
  * lpfc_fc_frame_check - Check that this frame is a valid frame to handle
  * @phba: pointer to lpfc_hba struct that the frame was received on
@@ -12136,6 +13398,28 @@ lpfc_sli4_seq_abort_rsp_cmpl(struct lpfc_hba *phba,
                lpfc_sli_release_iocbq(phba, cmd_iocbq);
 }
 
+/**
+ * lpfc_sli4_xri_inrange - check xri is in range of xris owned by driver.
+ * @phba: Pointer to HBA context object.
+ * @xri: xri id in transaction.
+ *
+ * This function validates the xri maps to the known range of XRIs allocated an
+ * used by the driver.
+ **/
+static uint16_t
+lpfc_sli4_xri_inrange(struct lpfc_hba *phba,
+                     uint16_t xri)
+{
+       int i;
+
+       for (i = 0; i < phba->sli4_hba.max_cfg_param.max_xri; i++) {
+               if (xri == phba->sli4_hba.xri_ids[i])
+                       return i;
+       }
+       return NO_XRI;
+}
+
+
 /**
  * lpfc_sli4_seq_abort_rsp - bls rsp to sequence abort
  * @phba: Pointer to HBA context object.
@@ -12169,9 +13453,7 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba,
                                "SID:x%x\n", oxid, sid);
                return;
        }
-       if (rxid >= phba->sli4_hba.max_cfg_param.xri_base
-               && rxid <= (phba->sli4_hba.max_cfg_param.max_xri
-               + phba->sli4_hba.max_cfg_param.xri_base))
+       if (lpfc_sli4_xri_inrange(phba, rxid))
                lpfc_set_rrq_active(phba, ndlp, rxid, oxid, 0);
 
        /* Allocate buffer for rsp iocb */
@@ -12194,12 +13476,13 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba,
        icmd->ulpBdeCount = 0;
        icmd->ulpLe = 1;
        icmd->ulpClass = CLASS3;
-       icmd->ulpContext = ndlp->nlp_rpi;
+       icmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
        ctiocb->context1 = ndlp;
 
        ctiocb->iocb_cmpl = NULL;
        ctiocb->vport = phba->pport;
        ctiocb->iocb_cmpl = lpfc_sli4_seq_abort_rsp_cmpl;
+       ctiocb->sli4_lxritag = NO_XRI;
        ctiocb->sli4_xritag = NO_XRI;
 
        /* If the oxid maps to the FCP XRI range or if it is out of range,
@@ -12380,8 +13663,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
                first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS;
                first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX;
                first_iocbq->iocb.ulpContext = be16_to_cpu(fc_hdr->fh_ox_id);
-               first_iocbq->iocb.unsli3.rcvsli3.vpi =
-                                       vport->vpi + vport->phba->vpi_base;
+               /* iocbq is prepped for internal consumption.  Logical vpi. */
+               first_iocbq->iocb.unsli3.rcvsli3.vpi = vport->vpi;
                /* put the first buffer into the first IOCBq */
                first_iocbq->context2 = &seq_dmabuf->dbuf;
                first_iocbq->context3 = NULL;
@@ -12461,7 +13744,7 @@ lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *vport,
                                      &phba->sli.ring[LPFC_ELS_RING],
                                      iocbq, fc_hdr->fh_r_ctl,
                                      fc_hdr->fh_type))
-               lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
                                "2540 Ring %d handler: unexpected Rctl "
                                "x%x Type x%x received\n",
                                LPFC_ELS_RING,
@@ -12558,9 +13841,24 @@ lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *phba)
 {
        struct lpfc_rpi_hdr *rpi_page;
        uint32_t rc = 0;
+       uint16_t lrpi = 0;
+
+       /* SLI4 ports that support extents do not require RPI headers. */
+       if (!phba->sli4_hba.rpi_hdrs_in_use)
+               goto exit;
+       if (phba->sli4_hba.extents_in_use)
+               return -EIO;
 
-       /* Post all rpi memory regions to the port. */
        list_for_each_entry(rpi_page, &phba->sli4_hba.lpfc_rpi_hdr_list, list) {
+               /*
+                * Assign the rpi headers a physical rpi only if the driver
+                * has not initialized those resources.  A port reset only
+                * needs the headers posted.
+                */
+               if (bf_get(lpfc_rpi_rsrc_rdy, &phba->sli4_hba.sli4_flags) !=
+                   LPFC_RPI_RSRC_RDY)
+                       rpi_page->start_rpi = phba->sli4_hba.rpi_ids[lrpi];
+
                rc = lpfc_sli4_post_rpi_hdr(phba, rpi_page);
                if (rc != MBX_SUCCESS) {
                        lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
@@ -12571,6 +13869,9 @@ lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *phba)
                }
        }
 
+ exit:
+       bf_set(lpfc_rpi_rsrc_rdy, &phba->sli4_hba.sli4_flags,
+              LPFC_RPI_RSRC_RDY);
        return rc;
 }
 
@@ -12594,10 +13895,15 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page)
        LPFC_MBOXQ_t *mboxq;
        struct lpfc_mbx_post_hdr_tmpl *hdr_tmpl;
        uint32_t rc = 0;
-       uint32_t mbox_tmo;
        uint32_t shdr_status, shdr_add_status;
        union lpfc_sli4_cfg_shdr *shdr;
 
+       /* SLI4 ports that support extents do not require RPI headers. */
+       if (!phba->sli4_hba.rpi_hdrs_in_use)
+               return rc;
+       if (phba->sli4_hba.extents_in_use)
+               return -EIO;
+
        /* The port is notified of the header region via a mailbox command. */
        mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!mboxq) {
@@ -12609,16 +13915,19 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page)
 
        /* Post all rpi memory regions to the port. */
        hdr_tmpl = &mboxq->u.mqe.un.hdr_tmpl;
-       mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
        lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
                         LPFC_MBOX_OPCODE_FCOE_POST_HDR_TEMPLATE,
                         sizeof(struct lpfc_mbx_post_hdr_tmpl) -
                         sizeof(struct lpfc_sli4_cfg_mhdr),
                         LPFC_SLI4_MBX_EMBED);
-       bf_set(lpfc_mbx_post_hdr_tmpl_page_cnt,
-              hdr_tmpl, rpi_page->page_count);
+
+
+       /* Post the physical rpi to the port for this rpi header. */
        bf_set(lpfc_mbx_post_hdr_tmpl_rpi_offset, hdr_tmpl,
               rpi_page->start_rpi);
+       bf_set(lpfc_mbx_post_hdr_tmpl_page_cnt,
+              hdr_tmpl, rpi_page->page_count);
+
        hdr_tmpl->rpi_paddr_lo = putPaddrLow(rpi_page->dmabuf->phys);
        hdr_tmpl->rpi_paddr_hi = putPaddrHigh(rpi_page->dmabuf->phys);
        rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
@@ -12653,22 +13962,21 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page)
 int
 lpfc_sli4_alloc_rpi(struct lpfc_hba *phba)
 {
-       int rpi;
-       uint16_t max_rpi, rpi_base, rpi_limit;
-       uint16_t rpi_remaining;
+       unsigned long rpi;
+       uint16_t max_rpi, rpi_limit;
+       uint16_t rpi_remaining, lrpi = 0;
        struct lpfc_rpi_hdr *rpi_hdr;
 
        max_rpi = phba->sli4_hba.max_cfg_param.max_rpi;
-       rpi_base = phba->sli4_hba.max_cfg_param.rpi_base;
        rpi_limit = phba->sli4_hba.next_rpi;
 
        /*
-        * The valid rpi range is not guaranteed to be zero-based.  Start
-        * the search at the rpi_base as reported by the port.
+        * Fetch the next logical rpi.  Because this index is logical,
+        * the  driver starts at 0 each time.
         */
        spin_lock_irq(&phba->hbalock);
-       rpi = find_next_zero_bit(phba->sli4_hba.rpi_bmask, rpi_limit, rpi_base);
-       if (rpi >= rpi_limit || rpi < rpi_base)
+       rpi = find_next_zero_bit(phba->sli4_hba.rpi_bmask, rpi_limit, 0);
+       if (rpi >= rpi_limit)
                rpi = LPFC_RPI_ALLOC_ERROR;
        else {
                set_bit(rpi, phba->sli4_hba.rpi_bmask);
@@ -12678,7 +13986,7 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba)
 
        /*
         * Don't try to allocate more rpi header regions if the device limit
-        * on available rpis max has been exhausted.
+        * has been exhausted.
         */
        if ((rpi == LPFC_RPI_ALLOC_ERROR) &&
            (phba->sli4_hba.rpi_count >= max_rpi)) {
@@ -12686,14 +13994,22 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba)
                return rpi;
        }
 
+       /*
+        * RPI header postings are not required for SLI4 ports capable of
+        * extents.
+        */
+       if (!phba->sli4_hba.rpi_hdrs_in_use) {
+               spin_unlock_irq(&phba->hbalock);
+               return rpi;
+       }
+
        /*
         * If the driver is running low on rpi resources, allocate another
         * page now.  Note that the next_rpi value is used because
         * it represents how many are actually in use whereas max_rpi notes
         * how many are supported max by the device.
         */
-       rpi_remaining = phba->sli4_hba.next_rpi - rpi_base -
-               phba->sli4_hba.rpi_count;
+       rpi_remaining = phba->sli4_hba.next_rpi - phba->sli4_hba.rpi_count;
        spin_unlock_irq(&phba->hbalock);
        if (rpi_remaining < LPFC_RPI_LOW_WATER_MARK) {
                rpi_hdr = lpfc_sli4_create_rpi_hdr(phba);
@@ -12702,6 +14018,8 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba)
                                        "2002 Error Could not grow rpi "
                                        "count\n");
                } else {
+                       lrpi = rpi_hdr->start_rpi;
+                       rpi_hdr->start_rpi = phba->sli4_hba.rpi_ids[lrpi];
                        lpfc_sli4_post_rpi_hdr(phba, rpi_hdr);
                }
        }
@@ -12751,6 +14069,8 @@ void
 lpfc_sli4_remove_rpis(struct lpfc_hba *phba)
 {
        kfree(phba->sli4_hba.rpi_bmask);
+       kfree(phba->sli4_hba.rpi_ids);
+       bf_set(lpfc_rpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0);
 }
 
 /**
@@ -13489,6 +14809,96 @@ out:
        return;
 }
 
+/**
+ * lpfc_wr_object - write an object to the firmware
+ * @phba: HBA structure that indicates port to create a queue on.
+ * @dmabuf_list: list of dmabufs to write to the port.
+ * @size: the total byte value of the objects to write to the port.
+ * @offset: the current offset to be used to start the transfer.
+ *
+ * This routine will create a wr_object mailbox command to send to the port.
+ * the mailbox command will be constructed using the dma buffers described in
+ * @dmabuf_list to create a list of BDEs. This routine will fill in as many
+ * BDEs that the imbedded mailbox can support. The @offset variable will be
+ * used to indicate the starting offset of the transfer and will also return
+ * the offset after the write object mailbox has completed. @size is used to
+ * determine the end of the object and whether the eof bit should be set.
+ *
+ * Return 0 is successful and offset will contain the the new offset to use
+ * for the next write.
+ * Return negative value for error cases.
+ **/
+int
+lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list,
+              uint32_t size, uint32_t *offset)
+{
+       struct lpfc_mbx_wr_object *wr_object;
+       LPFC_MBOXQ_t *mbox;
+       int rc = 0, i = 0;
+       uint32_t shdr_status, shdr_add_status;
+       uint32_t mbox_tmo;
+       union lpfc_sli4_cfg_shdr *shdr;
+       struct lpfc_dmabuf *dmabuf;
+       uint32_t written = 0;
+
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+                       LPFC_MBOX_OPCODE_WRITE_OBJECT,
+                       sizeof(struct lpfc_mbx_wr_object) -
+                       sizeof(struct lpfc_sli4_cfg_mhdr), LPFC_SLI4_MBX_EMBED);
+
+       wr_object = (struct lpfc_mbx_wr_object *)&mbox->u.mqe.un.wr_object;
+       wr_object->u.request.write_offset = *offset;
+       sprintf((uint8_t *)wr_object->u.request.object_name, "/");
+       wr_object->u.request.object_name[0] =
+               cpu_to_le32(wr_object->u.request.object_name[0]);
+       bf_set(lpfc_wr_object_eof, &wr_object->u.request, 0);
+       list_for_each_entry(dmabuf, dmabuf_list, list) {
+               if (i >= LPFC_MBX_WR_CONFIG_MAX_BDE || written >= size)
+                       break;
+               wr_object->u.request.bde[i].addrLow = putPaddrLow(dmabuf->phys);
+               wr_object->u.request.bde[i].addrHigh =
+                       putPaddrHigh(dmabuf->phys);
+               if (written + SLI4_PAGE_SIZE >= size) {
+                       wr_object->u.request.bde[i].tus.f.bdeSize =
+                               (size - written);
+                       written += (size - written);
+                       bf_set(lpfc_wr_object_eof, &wr_object->u.request, 1);
+               } else {
+                       wr_object->u.request.bde[i].tus.f.bdeSize =
+                               SLI4_PAGE_SIZE;
+                       written += SLI4_PAGE_SIZE;
+               }
+               i++;
+       }
+       wr_object->u.request.bde_count = i;
+       bf_set(lpfc_wr_object_write_length, &wr_object->u.request, written);
+       if (!phba->sli4_hba.intr_enable)
+               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+       else {
+               mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+               rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
+       }
+       /* The IOCTL status is embedded in the mailbox subheader. */
+       shdr = (union lpfc_sli4_cfg_shdr *) &wr_object->header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mbox, phba->mbox_mem_pool);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3025 Write Object mailbox failed with "
+                               "status x%x add_status x%x, mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               rc = -ENXIO;
+       } else
+               *offset += wr_object->u.response.actual_write_length;
+       return rc;
+}
+
 /**
  * lpfc_cleanup_pending_mbox - Free up vport discovery mailbox commands.
  * @vport: pointer to vport data structure.
@@ -13644,7 +15054,7 @@ lpfc_drain_txq(struct lpfc_hba *phba)
                                 * never happen
                                 */
                                sglq = __lpfc_clear_active_sglq(phba,
-                                                sglq->sli4_xritag);
+                                                sglq->sli4_lxritag);
                                spin_unlock_irqrestore(&phba->hbalock, iflags);
                                lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
                                        "2823 txq empty and txq_cnt is %d\n ",
@@ -13656,6 +15066,7 @@ lpfc_drain_txq(struct lpfc_hba *phba)
                /* The xri and iocb resources secured,
                 * attempt to issue request
                 */
+               piocbq->sli4_lxritag = sglq->sli4_lxritag;
                piocbq->sli4_xritag = sglq->sli4_xritag;
                if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocbq, sglq))
                        fail_msg = "to convert bpl to sgl";
index 453577c21c14b3ef04bfeb3029b875c9269e6ef3..a0075b0af1423d76fbe32081ff654f0bd2284c2e 100644 (file)
@@ -52,6 +52,7 @@ struct lpfc_iocbq {
        struct list_head clist;
        struct list_head dlist;
        uint16_t iotag;         /* pre-assigned IO tag */
+       uint16_t sli4_lxritag;  /* logical pre-assigned XRI. */
        uint16_t sli4_xritag;   /* pre-assigned XRI, (OXID) tag. */
        struct lpfc_cq_event cq_event;
 
index 1a3cbf88f2ce6fc5beebaca65d72855079291a9b..4b1703554a265f321cb4fb9c0eafd2b92632f299 100644 (file)
@@ -310,7 +310,6 @@ struct lpfc_max_cfg_param {
        uint16_t vfi_base;
        uint16_t vfi_used;
        uint16_t max_fcfi;
-       uint16_t fcfi_base;
        uint16_t fcfi_used;
        uint16_t max_eq;
        uint16_t max_rq;
@@ -365,6 +364,11 @@ struct lpfc_pc_sli4_params {
        uint8_t rqv;
 };
 
+struct lpfc_iov {
+       uint32_t pf_number;
+       uint32_t vf_number;
+};
+
 /* SLI4 HBA data structure entries */
 struct lpfc_sli4_hba {
        void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for
@@ -444,10 +448,13 @@ struct lpfc_sli4_hba {
        uint32_t intr_enable;
        struct lpfc_bmbx bmbx;
        struct lpfc_max_cfg_param max_cfg_param;
+       uint16_t extents_in_use; /* must allocate resource extents. */
+       uint16_t rpi_hdrs_in_use; /* must post rpi hdrs if set. */
        uint16_t next_xri; /* last_xri - max_cfg_param.xri_base = used */
        uint16_t next_rpi;
        uint16_t scsi_xri_max;
        uint16_t scsi_xri_cnt;
+       uint16_t scsi_xri_start;
        struct list_head lpfc_free_sgl_list;
        struct list_head lpfc_sgl_list;
        struct lpfc_sglq **lpfc_els_sgl_array;
@@ -458,7 +465,17 @@ struct lpfc_sli4_hba {
        struct lpfc_sglq **lpfc_sglq_active_list;
        struct list_head lpfc_rpi_hdr_list;
        unsigned long *rpi_bmask;
+       uint16_t *rpi_ids;
        uint16_t rpi_count;
+       struct list_head lpfc_rpi_blk_list;
+       unsigned long *xri_bmask;
+       uint16_t *xri_ids;
+       uint16_t xri_count;
+       struct list_head lpfc_xri_blk_list;
+       unsigned long *vfi_bmask;
+       uint16_t *vfi_ids;
+       uint16_t vfi_count;
+       struct list_head lpfc_vfi_blk_list;
        struct lpfc_sli4_flags sli4_flags;
        struct list_head sp_queue_event;
        struct list_head sp_cqe_event_pool;
@@ -467,6 +484,7 @@ struct lpfc_sli4_hba {
        struct list_head sp_els_xri_aborted_work_queue;
        struct list_head sp_unsol_work_queue;
        struct lpfc_sli4_link link_state;
+       struct lpfc_iov iov;
        spinlock_t abts_scsi_buf_list_lock; /* list of aborted SCSI IOs */
        spinlock_t abts_sgl_list_lock; /* list of aborted els IOs */
 };
@@ -490,6 +508,7 @@ struct lpfc_sglq {
        enum lpfc_sgl_state state;
        struct lpfc_nodelist *ndlp; /* ndlp associated with IO */
        uint16_t iotag;         /* pre-assigned IO tag */
+       uint16_t sli4_lxritag;  /* logical pre-assigned xri. */
        uint16_t sli4_xritag;   /* pre-assigned XRI, (OXID) tag. */
        struct sli4_sge *sgl;   /* pre-assigned SGL */
        void *virt;             /* virtual address. */
@@ -504,6 +523,13 @@ struct lpfc_rpi_hdr {
        uint32_t start_rpi;
 };
 
+struct lpfc_rsrc_blks {
+       struct list_head list;
+       uint16_t rsrc_start;
+       uint16_t rsrc_size;
+       uint16_t rsrc_used;
+};
+
 /*
  * SLI4 specific function prototypes
  */
@@ -543,8 +569,11 @@ int lpfc_sli4_post_sgl(struct lpfc_hba *, dma_addr_t, dma_addr_t, uint16_t);
 int lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *);
 uint16_t lpfc_sli4_next_xritag(struct lpfc_hba *);
 int lpfc_sli4_post_async_mbox(struct lpfc_hba *);
-int lpfc_sli4_post_sgl_list(struct lpfc_hba *phba);
+int lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba);
+int lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba);
 int lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *, struct list_head *, int);
+int lpfc_sli4_post_scsi_sgl_blk_ext(struct lpfc_hba *, struct list_head *,
+                                   int);
 struct lpfc_cq_event *__lpfc_sli4_cq_event_alloc(struct lpfc_hba *);
 struct lpfc_cq_event *lpfc_sli4_cq_event_alloc(struct lpfc_hba *);
 void __lpfc_sli4_cq_event_release(struct lpfc_hba *, struct lpfc_cq_event *);
index 30ba5440c67a7848e3f557eb1e564fb0ae8a0674..1feb551a57bce4cd8e8fe8cf0bb3c6522af3a154 100644 (file)
@@ -83,7 +83,7 @@ inline void lpfc_vport_set_state(struct lpfc_vport *vport,
 static int
 lpfc_alloc_vpi(struct lpfc_hba *phba)
 {
-       int  vpi;
+       unsigned long vpi;
 
        spin_lock_irq(&phba->hbalock);
        /* Start at bit 1 because vpi zero is reserved for the physical port */
index 046dcc672ec1a4ddcf3fddff1537422a44bae267..7370c084b17855a58f25b5b88faa4ee8ed13d631 100644 (file)
@@ -33,9 +33,9 @@
 /*
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION                                "00.00.05.34-rc1"
-#define MEGASAS_RELDATE                                "Feb. 24, 2011"
-#define MEGASAS_EXT_VERSION                    "Thu. Feb. 24 17:00:00 PDT 2011"
+#define MEGASAS_VERSION                                "00.00.05.38-rc1"
+#define MEGASAS_RELDATE                                "May. 11, 2011"
+#define MEGASAS_EXT_VERSION                    "Wed. May. 11 17:00:00 PDT 2011"
 
 /*
  * Device IDs
@@ -76,8 +76,8 @@
 #define MFI_STATE_READY                                0xB0000000
 #define MFI_STATE_OPERATIONAL                  0xC0000000
 #define MFI_STATE_FAULT                                0xF0000000
-#define  MFI_RESET_REQUIRED                    0x00000001
-
+#define MFI_RESET_REQUIRED                     0x00000001
+#define MFI_RESET_ADAPTER                      0x00000002
 #define MEGAMFI_FRAME_SIZE                     64
 
 /*
index 89c623ebadbc5c5a64acc40dd55ccea1d990e0fc..2d8cdce7b2f5af14355233424e7092c218821da1 100644 (file)
@@ -18,7 +18,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  *  FILE: megaraid_sas_base.c
- *  Version : v00.00.05.34-rc1
+ *  Version : v00.00.05.38-rc1
  *
  *  Authors: LSI Corporation
  *           Sreenivas Bagalkote
@@ -437,15 +437,18 @@ megasas_read_fw_status_reg_ppc(struct megasas_register_set __iomem * regs)
 static int
 megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
 {
-       u32 status;
+       u32 status, mfiStatus = 0;
+
        /*
         * Check if it is our interrupt
         */
        status = readl(&regs->outbound_intr_status);
 
-       if (!(status & MFI_REPLY_1078_MESSAGE_INTERRUPT)) {
-               return 0;
-       }
+       if (status & MFI_REPLY_1078_MESSAGE_INTERRUPT)
+               mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
+
+       if (status & MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT)
+               mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
 
        /*
         * Clear the interrupt by writing back the same value
@@ -455,8 +458,9 @@ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
        /* Dummy readl to force pci flush */
        readl(&regs->outbound_doorbell_clear);
 
-       return 1;
+       return mfiStatus;
 }
+
 /**
  * megasas_fire_cmd_ppc -      Sends command to the FW
  * @frame_phys_addr :          Physical address of cmd
@@ -476,17 +480,6 @@ megasas_fire_cmd_ppc(struct megasas_instance *instance,
        spin_unlock_irqrestore(&instance->hba_lock, flags);
 }
 
-/**
- * megasas_adp_reset_ppc -     For controller reset
- * @regs:                              MFI register set
- */
-static int
-megasas_adp_reset_ppc(struct megasas_instance *instance,
-                       struct megasas_register_set __iomem *regs)
-{
-       return 0;
-}
-
 /**
  * megasas_check_reset_ppc -   For controller reset check
  * @regs:                              MFI register set
@@ -495,8 +488,12 @@ static int
 megasas_check_reset_ppc(struct megasas_instance *instance,
                        struct megasas_register_set __iomem *regs)
 {
+       if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL)
+               return 1;
+
        return 0;
 }
+
 static struct megasas_instance_template megasas_instance_template_ppc = {
 
        .fire_cmd = megasas_fire_cmd_ppc,
@@ -504,7 +501,7 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
        .disable_intr = megasas_disable_intr_ppc,
        .clear_intr = megasas_clear_intr_ppc,
        .read_fw_status_reg = megasas_read_fw_status_reg_ppc,
-       .adp_reset = megasas_adp_reset_ppc,
+       .adp_reset = megasas_adp_reset_xscale,
        .check_reset = megasas_check_reset_ppc,
        .service_isr = megasas_isr,
        .tasklet = megasas_complete_cmd_dpc,
@@ -620,6 +617,9 @@ static int
 megasas_check_reset_skinny(struct megasas_instance *instance,
                                struct megasas_register_set __iomem *regs)
 {
+       if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL)
+               return 1;
+
        return 0;
 }
 
@@ -3454,7 +3454,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
 {
        u32 max_sectors_1;
        u32 max_sectors_2;
-       u32 tmp_sectors;
+       u32 tmp_sectors, msix_enable;
        struct megasas_register_set __iomem *reg_set;
        struct megasas_ctrl_info *ctrl_info;
        unsigned long bar_list;
@@ -3507,6 +3507,13 @@ static int megasas_init_fw(struct megasas_instance *instance)
        if (megasas_transition_to_ready(instance))
                goto fail_ready_state;
 
+       /* Check if MSI-X is supported while in ready state */
+       msix_enable = (instance->instancet->read_fw_status_reg(reg_set) &
+                      0x4000000) >> 0x1a;
+       if (msix_enable && !msix_disable &&
+           !pci_enable_msix(instance->pdev, &instance->msixentry, 1))
+               instance->msi_flag = 1;
+
        /* Get operational params, sge flags, send init cmd to controller */
        if (instance->instancet->init_adapter(instance))
                goto fail_init_adapter;
@@ -4076,14 +4083,6 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        else
                INIT_WORK(&instance->work_init, process_fw_state_change_wq);
 
-       /* Try to enable MSI-X */
-       if ((instance->pdev->device != PCI_DEVICE_ID_LSI_SAS1078R) &&
-           (instance->pdev->device != PCI_DEVICE_ID_LSI_SAS1078DE) &&
-           (instance->pdev->device != PCI_DEVICE_ID_LSI_VERDE_ZCR) &&
-           !msix_disable && !pci_enable_msix(instance->pdev,
-                                             &instance->msixentry, 1))
-               instance->msi_flag = 1;
-
        /*
         * Initialize MFI Firmware
         */
@@ -4115,6 +4114,14 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = instance;
        megasas_mgmt_info.max_index++;
 
+       /*
+        * Register with SCSI mid-layer
+        */
+       if (megasas_io_attach(instance))
+               goto fail_io_attach;
+
+       instance->unload = 0;
+
        /*
         * Initiate AEN (Asynchronous Event Notification)
         */
@@ -4123,13 +4130,6 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                goto fail_start_aen;
        }
 
-       /*
-        * Register with SCSI mid-layer
-        */
-       if (megasas_io_attach(instance))
-               goto fail_io_attach;
-
-       instance->unload = 0;
        return 0;
 
       fail_start_aen:
@@ -4332,10 +4332,6 @@ megasas_resume(struct pci_dev *pdev)
        if (megasas_set_dma_mask(pdev))
                goto fail_set_dma_mask;
 
-       /* Now re-enable MSI-X */
-       if (instance->msi_flag)
-               pci_enable_msix(instance->pdev, &instance->msixentry, 1);
-
        /*
         * Initialize MFI Firmware
         */
@@ -4348,6 +4344,10 @@ megasas_resume(struct pci_dev *pdev)
        if (megasas_transition_to_ready(instance))
                goto fail_ready_state;
 
+       /* Now re-enable MSI-X */
+       if (instance->msi_flag)
+               pci_enable_msix(instance->pdev, &instance->msixentry, 1);
+
        switch (instance->pdev->device) {
        case PCI_DEVICE_ID_LSI_FUSION:
        {
@@ -4384,12 +4384,6 @@ megasas_resume(struct pci_dev *pdev)
 
        instance->instancet->enable_intr(instance->reg_set);
 
-       /*
-        * Initiate AEN (Asynchronous Event Notification)
-        */
-       if (megasas_start_aen(instance))
-               printk(KERN_ERR "megasas: Start AEN failed\n");
-
        /* Initialize the cmd completion timer */
        if (poll_mode_io)
                megasas_start_timer(instance, &instance->io_completion_timer,
@@ -4397,6 +4391,12 @@ megasas_resume(struct pci_dev *pdev)
                                MEGASAS_COMPLETION_TIMER_INTERVAL);
        instance->unload = 0;
 
+       /*
+        * Initiate AEN (Asynchronous Event Notification)
+        */
+       if (megasas_start_aen(instance))
+               printk(KERN_ERR "megasas: Start AEN failed\n");
+
        return 0;
 
 fail_irq:
@@ -4527,6 +4527,11 @@ static void megasas_shutdown(struct pci_dev *pdev)
        instance->unload = 1;
        megasas_flush_cache(instance);
        megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
+       instance->instancet->disable_intr(instance->reg_set);
+       free_irq(instance->msi_flag ? instance->msixentry.vector :
+                instance->pdev->irq, instance);
+       if (instance->msi_flag)
+               pci_disable_msix(instance->pdev);
 }
 
 /**
index 145a8cffb1fa332191874ac4d5ea64abee5c4974..f13e7abd345a9b3956243fc5e047207f66d0dbe8 100644 (file)
@@ -695,22 +695,6 @@ fail_get_cmd:
        return ret;
 }
 
-/*
- * megasas_return_cmd_for_smid -       Returns a cmd_fusion for a SMID
- * @instance:                          Adapter soft state
- *
- */
-void
-megasas_return_cmd_for_smid(struct megasas_instance *instance, u16 smid)
-{
-       struct fusion_context *fusion;
-       struct megasas_cmd_fusion *cmd;
-
-       fusion = instance->ctrl_context;
-       cmd = fusion->cmd_list[smid - 1];
-       megasas_return_cmd_fusion(instance, cmd);
-}
-
 /*
  * megasas_get_ld_map_info -   Returns FW's ld_map structure
  * @instance:                          Adapter soft state
@@ -1153,7 +1137,7 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
        u64 start_blk = io_info->pdBlock;
        u8 *cdb = io_request->CDB.CDB32;
        u32 num_blocks = io_info->numBlocks;
-       u8 opcode, flagvals, groupnum, control;
+       u8 opcode = 0, flagvals = 0, groupnum = 0, control = 0;
 
        /* Check if T10 PI (DIF) is enabled for this LD */
        ld = MR_TargetIdToLdGet(io_info->ldTgtId, local_map_ptr);
@@ -1235,7 +1219,46 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
                        cdb[8] = (u8)(num_blocks & 0xff);
                        cdb[7] = (u8)((num_blocks >> 8) & 0xff);
 
+                       io_request->IoFlags = 10; /* Specify 10-byte cdb */
                        cdb_len = 10;
+               } else if ((cdb_len < 16) && (start_blk > 0xffffffff)) {
+                       /* Convert to 16 byte CDB for large LBA's */
+                       switch (cdb_len) {
+                       case 6:
+                               opcode = cdb[0] == READ_6 ? READ_16 : WRITE_16;
+                               control = cdb[5];
+                               break;
+                       case 10:
+                               opcode =
+                                       cdb[0] == READ_10 ? READ_16 : WRITE_16;
+                               flagvals = cdb[1];
+                               groupnum = cdb[6];
+                               control = cdb[9];
+                               break;
+                       case 12:
+                               opcode =
+                                       cdb[0] == READ_12 ? READ_16 : WRITE_16;
+                               flagvals = cdb[1];
+                               groupnum = cdb[10];
+                               control = cdb[11];
+                               break;
+                       }
+
+                       memset(cdb, 0, sizeof(io_request->CDB.CDB32));
+
+                       cdb[0] = opcode;
+                       cdb[1] = flagvals;
+                       cdb[14] = groupnum;
+                       cdb[15] = control;
+
+                       /* Transfer length */
+                       cdb[13] = (u8)(num_blocks & 0xff);
+                       cdb[12] = (u8)((num_blocks >> 8) & 0xff);
+                       cdb[11] = (u8)((num_blocks >> 16) & 0xff);
+                       cdb[10] = (u8)((num_blocks >> 24) & 0xff);
+
+                       io_request->IoFlags = 16; /* Specify 16-byte cdb */
+                       cdb_len = 16;
                }
 
                /* Normal case, just load LBA here */
@@ -2026,17 +2049,11 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
        struct fusion_context *fusion;
        struct megasas_cmd *cmd_mfi;
        union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
-       u32 host_diag, abs_state;
+       u32 host_diag, abs_state, status_reg, reset_adapter;
 
        instance = (struct megasas_instance *)shost->hostdata;
        fusion = instance->ctrl_context;
 
-       mutex_lock(&instance->reset_mutex);
-       set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
-       instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
-       instance->instancet->disable_intr(instance->reg_set);
-       msleep(1000);
-
        if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
                printk(KERN_WARNING "megaraid_sas: Hardware critical error, "
                       "returning FAILED.\n");
@@ -2044,6 +2061,12 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
                goto out;
        }
 
+       mutex_lock(&instance->reset_mutex);
+       set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
+       instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+       instance->instancet->disable_intr(instance->reg_set);
+       msleep(1000);
+
        /* First try waiting for commands to complete */
        if (megasas_wait_for_outstanding_fusion(instance)) {
                printk(KERN_WARNING "megaraid_sas: resetting fusion "
@@ -2060,7 +2083,12 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
                        }
                }
 
-               if (instance->disableOnlineCtrlReset == 1) {
+               status_reg = instance->instancet->read_fw_status_reg(
+                       instance->reg_set);
+               abs_state = status_reg & MFI_STATE_MASK;
+               reset_adapter = status_reg & MFI_RESET_ADAPTER;
+               if (instance->disableOnlineCtrlReset ||
+                   (abs_state == MFI_STATE_FAULT && !reset_adapter)) {
                        /* Reset not supported, kill adapter */
                        printk(KERN_WARNING "megaraid_sas: Reset not supported"
                               ", killing adapter.\n");
@@ -2089,6 +2117,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
 
                        /* Check that the diag write enable (DRWE) bit is on */
                        host_diag = readl(&instance->reg_set->fusion_host_diag);
+                       retry = 0;
                        while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) {
                                msleep(100);
                                host_diag =
@@ -2126,7 +2155,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
 
                        abs_state =
                                instance->instancet->read_fw_status_reg(
-                                       instance->reg_set);
+                                       instance->reg_set) & MFI_STATE_MASK;
                        retry = 0;
 
                        while ((abs_state <= MFI_STATE_FW_INIT) &&
@@ -2134,7 +2163,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
                                msleep(100);
                                abs_state =
                                instance->instancet->read_fw_status_reg(
-                                       instance->reg_set);
+                                       instance->reg_set) & MFI_STATE_MASK;
                        }
                        if (abs_state <= MFI_STATE_FW_INIT) {
                                printk(KERN_WARNING "megaraid_sas: firmware "
index 2a3c05f6db8bd34399aaa5718230cd6d77fc3152..dcc289c25459582dea14f55b40adeb04d676995d 100644 (file)
 #define MPT2SAS_DRIVER_NAME            "mpt2sas"
 #define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
 #define MPT2SAS_DESCRIPTION    "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION         "08.100.00.01"
+#define MPT2SAS_DRIVER_VERSION         "08.100.00.02"
 #define MPT2SAS_MAJOR_VERSION          08
 #define MPT2SAS_MINOR_VERSION          100
 #define MPT2SAS_BUILD_VERSION          00
-#define MPT2SAS_RELEASE_VERSION                01
+#define MPT2SAS_RELEASE_VERSION                02
 
 /*
  * Set MPT2SAS_SG_DEPTH value based on user input.
index f12e02358d6d4228713faae1e34ffac58b630f97..a7dbc6825f5f504bfcdf2b115ec3e10299dcdb9d 100644 (file)
@@ -113,6 +113,7 @@ struct sense_info {
 };
 
 
+#define MPT2SAS_TURN_ON_FAULT_LED (0xFFFC)
 #define MPT2SAS_RESCAN_AFTER_HOST_RESET (0xFFFF)
 
 /**
@@ -121,6 +122,7 @@ struct sense_info {
  * @work: work object (ioc->fault_reset_work_q)
  * @cancel_pending_work: flag set during reset handling
  * @ioc: per adapter object
+ * @device_handle: device handle
  * @VF_ID: virtual function id
  * @VP_ID: virtual port id
  * @ignore: flag meaning this event has been marked to ignore
@@ -134,6 +136,7 @@ struct fw_event_work {
        u8                      cancel_pending_work;
        struct delayed_work     delayed_work;
        struct MPT2SAS_ADAPTER *ioc;
+       u16                     device_handle;
        u8                      VF_ID;
        u8                      VP_ID;
        u8                      ignore;
@@ -3499,6 +3502,7 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
 
        switch (prot_type) {
        case SCSI_PROT_DIF_TYPE1:
+       case SCSI_PROT_DIF_TYPE2:
 
                /*
                * enable ref/guard checking
@@ -3511,13 +3515,6 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
                    cpu_to_be32(scsi_get_lba(scmd));
                break;
 
-       case SCSI_PROT_DIF_TYPE2:
-
-               eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
-                   MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
-                   MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
-               break;
-
        case SCSI_PROT_DIF_TYPE3:
 
                /*
@@ -4047,17 +4044,75 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
 #endif
 
 /**
- * _scsih_smart_predicted_fault - illuminate Fault LED
+ * _scsih_turn_on_fault_led - illuminate Fault LED
  * @ioc: per adapter object
  * @handle: device handle
+ * Context: process
  *
  * Return nothing.
  */
 static void
-_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+_scsih_turn_on_fault_led(struct MPT2SAS_ADAPTER *ioc, u16 handle)
 {
        Mpi2SepReply_t mpi_reply;
        Mpi2SepRequest_t mpi_request;
+
+       memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
+       mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
+       mpi_request.SlotStatus =
+           cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
+       mpi_request.DevHandle = cpu_to_le16(handle);
+       mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
+       if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
+           &mpi_request)) != 0) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name,
+               __FILE__, __LINE__, __func__);
+               return;
+       }
+
+       if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
+               dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "enclosure_processor: "
+                   "ioc_status (0x%04x), loginfo(0x%08x)\n", ioc->name,
+                   le16_to_cpu(mpi_reply.IOCStatus),
+                   le32_to_cpu(mpi_reply.IOCLogInfo)));
+               return;
+       }
+}
+
+/**
+ * _scsih_send_event_to_turn_on_fault_led - fire delayed event
+ * @ioc: per adapter object
+ * @handle: device handle
+ * Context: interrupt.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_send_event_to_turn_on_fault_led(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+       struct fw_event_work *fw_event;
+
+       fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
+       if (!fw_event)
+               return;
+       fw_event->event = MPT2SAS_TURN_ON_FAULT_LED;
+       fw_event->device_handle = handle;
+       fw_event->ioc = ioc;
+       _scsih_fw_event_add(ioc, fw_event);
+}
+
+/**
+ * _scsih_smart_predicted_fault - process smart errors
+ * @ioc: per adapter object
+ * @handle: device handle
+ * Context: interrupt.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
        struct scsi_target *starget;
        struct MPT2SAS_TARGET *sas_target_priv_data;
        Mpi2EventNotificationReply_t *event_reply;
@@ -4084,30 +4139,8 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
        starget_printk(KERN_WARNING, starget, "predicted fault\n");
        spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 
-       if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) {
-               memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
-               mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
-               mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
-               mpi_request.SlotStatus =
-                   cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
-               mpi_request.DevHandle = cpu_to_le16(handle);
-               mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
-               if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
-                   &mpi_request)) != 0) {
-                       printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
-                           ioc->name, __FILE__, __LINE__, __func__);
-                       return;
-               }
-
-               if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
-                       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
-                           "enclosure_processor: ioc_status (0x%04x), "
-                           "loginfo(0x%08x)\n", ioc->name,
-                           le16_to_cpu(mpi_reply.IOCStatus),
-                           le32_to_cpu(mpi_reply.IOCLogInfo)));
-                       return;
-               }
-       }
+       if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM)
+               _scsih_send_event_to_turn_on_fault_led(ioc, handle);
 
        /* insert into event log */
        sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
@@ -6753,6 +6786,9 @@ _firmware_event_work(struct work_struct *work)
        }
 
        switch (fw_event->event) {
+       case MPT2SAS_TURN_ON_FAULT_LED:
+               _scsih_turn_on_fault_led(ioc, fw_event->device_handle);
+               break;
        case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
                _scsih_sas_topology_change_event(ioc, fw_event);
                break;
index 58f5be4740e9af378c7eb44d2786ab8e28367f39..de0b1a704fb508d95fb6f7874bbe1433dcb92f4c 100644 (file)
@@ -4698,12 +4698,14 @@ static int __os_scsi_tape_open(struct inode * inode, struct file * filp)
                        break;
 
                        if ((SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) {
+                               int j;
+
                                STp->pos_unknown = 0;
                                STp->partition = STp->new_partition = 0;
                                if (STp->can_partitions)
                                        STp->nbr_partitions = 1;  /* This guess will be updated later if necessary */
-                               for (i=0; i < ST_NBR_PARTITIONS; i++) {
-                                       STps = &(STp->ps[i]);
+                               for (j = 0; j < ST_NBR_PARTITIONS; j++) {
+                                       STps = &(STp->ps[j]);
                                        STps->rw = ST_IDLE;
                                        STps->eof = ST_NOEOF;
                                        STps->at_sm = 0;
index e77dd02eccddcba823d2f7faec9f13a97237689d..7d1609fa233c118e10afdd58463b40dcaad3e56b 100644 (file)
@@ -202,7 +202,7 @@ static int aha152x_resume(struct pcmcia_device *link)
        return 0;
 }
 
-static struct pcmcia_device_id aha152x_ids[] = {
+static const struct pcmcia_device_id aha152x_ids[] = {
        PCMCIA_DEVICE_PROD_ID123("New Media", "SCSI", "Bus Toaster", 0xcdf7e4cc, 0x35f26476, 0xa8851d6e),
        PCMCIA_DEVICE_PROD_ID123("NOTEWORTHY", "SCSI", "Bus Toaster", 0xad89c6e8, 0x35f26476, 0xa8851d6e),
        PCMCIA_DEVICE_PROD_ID12("Adaptec, Inc.", "APA-1460 SCSI Host Adapter", 0x24ba9738, 0x3a3c3d20),
index cd69c2670f810dd7ca7a738a5a75ef0ba4b28a52..714b248f5d5e675bae69c9f4361db060dcce02a6 100644 (file)
@@ -178,7 +178,7 @@ static int fdomain_resume(struct pcmcia_device *link)
        return 0;
 }
 
-static struct pcmcia_device_id fdomain_ids[] = {
+static const struct pcmcia_device_id fdomain_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "SCSI PCMCIA Card", 0xe3736c88, 0x859cad20),
        PCMCIA_DEVICE_PROD_ID1("SCSI PCMCIA Adapter Card", 0x8dacb57e),
        PCMCIA_DEVICE_PROD_ID12(" SIMPLE TECHNOLOGY Corporation", "SCSI PCMCIA Credit Card Controller", 0x182bdafe, 0xc80d106f),
index 54bdf6d85c6d4e0346369fed960becdaa958216f..ca86721a71b94730b995b99a7c3e7aded4b1951f 100644 (file)
@@ -1752,7 +1752,7 @@ static int nsp_cs_resume(struct pcmcia_device *link)
 /*======================================================================*
  *     module entry point
  *====================================================================*/
-static struct pcmcia_device_id nsp_cs_ids[] = {
+static const struct pcmcia_device_id nsp_cs_ids[] = {
        PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16       ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a),
        PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a),
        PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-002", "1", 0x534c02bc, 0xcb09d5b2, 0x51de003a),
index 9c96ca889ec97ac03d9bdaec0329b3e967c2250e..bcaf89fe0c9ed886099925a53d1f2cc27b46f412 100644 (file)
@@ -270,7 +270,7 @@ static int qlogic_resume(struct pcmcia_device *link)
        return 0;
 }
 
-static struct pcmcia_device_id qlogic_ids[] = {
+static const struct pcmcia_device_id qlogic_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6),
        PCMCIA_DEVICE_PROD_ID12("EPSON", "SCSI-2 PC Card SC200", 0xd361772f, 0x299d1751),
        PCMCIA_DEVICE_PROD_ID12("MACNICA", "MIRACLE SCSI-II mPS110", 0x20841b68, 0xab3c3b6d),
index 8552296edaa1e8062504e4b8ee63d46cc19694e2..f5b52731abd946949f768c224f950fee2b6693f1 100644 (file)
@@ -865,7 +865,7 @@ MODULE_AUTHOR("Bob Tracy <rct@frus.com>");
 MODULE_DESCRIPTION("SYM53C500 PCMCIA SCSI driver");
 MODULE_LICENSE("GPL");
 
-static struct pcmcia_device_id sym53c500_ids[] = {
+static const struct pcmcia_device_id sym53c500_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("BASICS by New Media Corporation", "SCSI Sym53C500", 0x23c78a9d, 0x0099e7f7),
        PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "SCSI Bus Toaster Sym53C500", 0x085a850b, 0x45432eb8),
        PCMCIA_DEVICE_PROD_ID2("SCSI9000", 0x21648f44),
index 7f636b118287a7bb0f9e3ac7d1cdecb27ed0598d..fca6a895307093a4630530b83e03e66b7fd447cd 100644 (file)
@@ -4252,8 +4252,8 @@ static ssize_t pmcraid_show_drv_version(
        char *buf
 )
 {
-       return snprintf(buf, PAGE_SIZE, "version: %s, build date: %s\n",
-                       PMCRAID_DRIVER_VERSION, PMCRAID_DRIVER_DATE);
+       return snprintf(buf, PAGE_SIZE, "version: %s\n",
+                       PMCRAID_DRIVER_VERSION);
 }
 
 static struct device_attribute pmcraid_driver_version_attr = {
@@ -6096,9 +6096,8 @@ static int __init pmcraid_init(void)
        dev_t dev;
        int error;
 
-       pmcraid_info("%s Device Driver version: %s %s\n",
-                        PMCRAID_DRIVER_NAME,
-                        PMCRAID_DRIVER_VERSION, PMCRAID_DRIVER_DATE);
+       pmcraid_info("%s Device Driver version: %s\n",
+                        PMCRAID_DRIVER_NAME, PMCRAID_DRIVER_VERSION);
 
        error = alloc_chrdev_region(&dev, 0,
                                    PMCRAID_MAX_ADAPTERS,
index 34e4c915002ef37332afc6ea949e94d90a8b22b3..f920baf3ff24638f6c28a1ecf36bc2d70916f9c4 100644 (file)
@@ -43,7 +43,6 @@
 #define PMCRAID_DRIVER_NAME            "PMC MaxRAID"
 #define PMCRAID_DEVFILE                        "pmcsas"
 #define PMCRAID_DRIVER_VERSION         "1.0.3"
-#define PMCRAID_DRIVER_DATE            __DATE__
 
 #define PMCRAID_FW_VERSION_1           0x002
 
index 0339ff03a535b7facb7674ca810d5e321bb40db9..252523d7847ea60d6539090d90377f1fce6de9b3 100644 (file)
@@ -1,5 +1,5 @@
 qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \
-               ql4_nx.o ql4_nvram.o ql4_dbg.o
+               ql4_nx.o ql4_nvram.o ql4_dbg.o ql4_attr.o
 
 obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o
 
diff --git a/drivers/scsi/qla4xxx/ql4_attr.c b/drivers/scsi/qla4xxx/ql4_attr.c
new file mode 100644 (file)
index 0000000..864d018
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c)  2003-2011 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#include "ql4_def.h"
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+
+/* Scsi_Host attributes. */
+static ssize_t
+qla4xxx_fw_version_show(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
+
+       if (is_qla8022(ha))
+               return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n",
+                               ha->firmware_version[0],
+                               ha->firmware_version[1],
+                               ha->patch_number, ha->build_number);
+       else
+               return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d.%02d\n",
+                               ha->firmware_version[0],
+                               ha->firmware_version[1],
+                               ha->patch_number, ha->build_number);
+}
+
+static ssize_t
+qla4xxx_serial_num_show(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
+       return snprintf(buf, PAGE_SIZE, "%s\n", ha->serial_number);
+}
+
+static ssize_t
+qla4xxx_iscsi_version_show(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
+       return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->iscsi_major,
+                       ha->iscsi_minor);
+}
+
+static ssize_t
+qla4xxx_optrom_version_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
+       return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d.%02d\n",
+                       ha->bootload_major, ha->bootload_minor,
+                       ha->bootload_patch, ha->bootload_build);
+}
+
+static DEVICE_ATTR(fw_version, S_IRUGO, qla4xxx_fw_version_show, NULL);
+static DEVICE_ATTR(serial_num, S_IRUGO, qla4xxx_serial_num_show, NULL);
+static DEVICE_ATTR(iscsi_version, S_IRUGO, qla4xxx_iscsi_version_show, NULL);
+static DEVICE_ATTR(optrom_version, S_IRUGO, qla4xxx_optrom_version_show, NULL);
+
+struct device_attribute *qla4xxx_host_attrs[] = {
+       &dev_attr_fw_version,
+       &dev_attr_serial_num,
+       &dev_attr_iscsi_version,
+       &dev_attr_optrom_version,
+       NULL,
+};
index 4757878d59dd735395ebfb41ad9d444b0823c697..473c5c872b397e7f02c86485e7ba56f67bac9c7f 100644 (file)
 #define INVALID_ENTRY          0xFFFF
 #define MAX_CMDS_TO_RISC       1024
 #define MAX_SRBS               MAX_CMDS_TO_RISC
-#define MBOX_AEN_REG_COUNT     5
+#define MBOX_AEN_REG_COUNT     8
 #define MAX_INIT_RETRIES       5
 
 /*
@@ -368,7 +368,6 @@ struct scsi_qla_host {
 #define AF_INIT_DONE                   1 /* 0x00000002 */
 #define AF_MBOX_COMMAND                        2 /* 0x00000004 */
 #define AF_MBOX_COMMAND_DONE           3 /* 0x00000008 */
-#define AF_DPC_SCHEDULED               5 /* 0x00000020 */
 #define AF_INTERRUPTS_ON               6 /* 0x00000040 */
 #define AF_GET_CRASH_RECORD            7 /* 0x00000080 */
 #define AF_LINK_UP                     8 /* 0x00000100 */
@@ -584,6 +583,14 @@ struct scsi_qla_host {
        uint32_t nx_reset_timeout;
 
        struct completion mbx_intr_comp;
+
+       /* --- From About Firmware --- */
+       uint16_t iscsi_major;
+       uint16_t iscsi_minor;
+       uint16_t bootload_major;
+       uint16_t bootload_minor;
+       uint16_t bootload_patch;
+       uint16_t bootload_build;
 };
 
 static inline int is_ipv4_enabled(struct scsi_qla_host *ha)
index 31e2bf97198c5d8e1fd2a1dd632b86bc45c87bae..01082aa77098138dc9eed20a58b1725373420bae 100644 (file)
@@ -690,6 +690,29 @@ struct mbx_sys_info {
        uint8_t reserved[12];             /* 34-3f */
 };
 
+struct about_fw_info {
+       uint16_t fw_major;              /* 00 - 01 */
+       uint16_t fw_minor;              /* 02 - 03 */
+       uint16_t fw_patch;              /* 04 - 05 */
+       uint16_t fw_build;              /* 06 - 07 */
+       uint8_t fw_build_date[16];      /* 08 - 17 ASCII String */
+       uint8_t fw_build_time[16];      /* 18 - 27 ASCII String */
+       uint8_t fw_build_user[16];      /* 28 - 37 ASCII String */
+       uint16_t fw_load_source;        /* 38 - 39 */
+                                       /* 1 = Flash Primary,
+                                          2 = Flash Secondary,
+                                          3 = Host Download
+                                       */
+       uint8_t reserved1[6];           /* 3A - 3F */
+       uint16_t iscsi_major;           /* 40 - 41 */
+       uint16_t iscsi_minor;           /* 42 - 43 */
+       uint16_t bootload_major;        /* 44 - 45 */
+       uint16_t bootload_minor;        /* 46 - 47 */
+       uint16_t bootload_patch;        /* 48 - 49 */
+       uint16_t bootload_build;        /* 4A - 4B */
+       uint8_t reserved2[180];         /* 4C - FF */
+};
+
 struct crash_record {
        uint16_t fw_major_version;      /* 00 - 01 */
        uint16_t fw_minor_version;      /* 02 - 03 */
index cc53e3fbd78c3b445f369224f52ac5c8d2064207..a53a256c1f8d9e6443512456ba8243574307c46a 100644 (file)
@@ -61,7 +61,7 @@ struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha);
 int qla4xxx_add_sess(struct ddb_entry *);
 void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry);
 int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host *ha);
-int qla4xxx_get_fw_version(struct scsi_qla_host * ha);
+int qla4xxx_about_firmware(struct scsi_qla_host *ha);
 void qla4xxx_interrupt_service_routine(struct scsi_qla_host *ha,
                                       uint32_t intr_status);
 int qla4xxx_init_rings(struct scsi_qla_host *ha);
@@ -139,4 +139,5 @@ extern int ql4xextended_error_logging;
 extern int ql4xdontresethba;
 extern int ql4xenablemsix;
 
+extern struct device_attribute *qla4xxx_host_attrs[];
 #endif /* _QLA4x_GBL_H */
index 48e2241ddaf49ec37f3f8d4fe61ca545c52458f7..42ed5db2d530fafa47d96310f1eea49b8a169fc9 100644 (file)
@@ -1275,7 +1275,7 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
        if (ha->isp_ops->start_firmware(ha) == QLA_ERROR)
                goto exit_init_hba;
 
-       if (qla4xxx_get_fw_version(ha) == QLA_ERROR)
+       if (qla4xxx_about_firmware(ha) == QLA_ERROR)
                goto exit_init_hba;
 
        if (ha->isp_ops->get_sys_info(ha) == QLA_ERROR)
index 2f40ac761cd4bf42c5b01dc12d0e886a9eb34d7c..0e72921c752d497547e49e59e078aaf38d54bb36 100644 (file)
@@ -25,9 +25,14 @@ static void qla4xxx_copy_sense(struct scsi_qla_host *ha,
 
        memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
        sense_len = le16_to_cpu(sts_entry->senseDataByteCnt);
-       if (sense_len == 0)
+       if (sense_len == 0) {
+               DEBUG2(ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%d:%d: %s:"
+                                 " sense len 0\n", ha->host_no,
+                                 cmd->device->channel, cmd->device->id,
+                                 cmd->device->lun, __func__));
+               ha->status_srb = NULL;
                return;
-
+       }
        /* Save total available sense length,
         * not to exceed cmd's sense buffer size */
        sense_len = min_t(uint16_t, sense_len, SCSI_SENSE_BUFFERSIZE);
@@ -541,6 +546,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
                case MBOX_ASTS_UNSOLICITED_PDU_RECEIVED:  /* Connection mode */
                case MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR:
                case MBOX_ASTS_SUBNET_STATE_CHANGE:
+               case MBOX_ASTS_DUPLICATE_IP:
                        /* No action */
                        DEBUG2(printk("scsi%ld: AEN %04x\n", ha->host_no,
                                      mbox_status));
@@ -593,11 +599,13 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
                                            mbox_sts[i];
 
                                /* print debug message */
-                               DEBUG2(printk("scsi%ld: AEN[%d] %04x queued"
-                                   " mb1:0x%x mb2:0x%x mb3:0x%x mb4:0x%x\n",
-                                   ha->host_no, ha->aen_in, mbox_sts[0],
-                                   mbox_sts[1], mbox_sts[2],  mbox_sts[3],
-                                   mbox_sts[4]));
+                               DEBUG2(printk("scsi%ld: AEN[%d] %04x queued "
+                                             "mb1:0x%x mb2:0x%x mb3:0x%x "
+                                             "mb4:0x%x mb5:0x%x\n",
+                                             ha->host_no, ha->aen_in,
+                                             mbox_sts[0], mbox_sts[1],
+                                             mbox_sts[2], mbox_sts[3],
+                                             mbox_sts[4], mbox_sts[5]));
 
                                /* advance pointer */
                                ha->aen_in++;
index d78b58dc501169b1160c5dd669f165b2f7d1306a..fce8289e97525732a02857153b987f1928a2333e 100644 (file)
@@ -86,22 +86,8 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
                msleep(10);
        }
 
-       /* To prevent overwriting mailbox registers for a command that has
-        * not yet been serviced, check to see if an active command
-        * (AEN, IOCB, etc.) is interrupting, then service it.
-        * -----------------------------------------------------------------
-        */
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
-       if (!is_qla8022(ha)) {
-               intr_status = readl(&ha->reg->ctrl_status);
-               if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
-                       /* Service existing interrupt */
-                       ha->isp_ops->interrupt_service_routine(ha, intr_status);
-                       clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
-               }
-       }
-
        ha->mbox_status_count = outCount;
        for (i = 0; i < outCount; i++)
                ha->mbox_status[i] = 0;
@@ -1057,38 +1043,65 @@ int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
 }
 
 /**
- * qla4xxx_get_fw_version - gets firmware version
+ * qla4xxx_about_firmware - gets FW, iscsi draft and boot loader version
  * @ha: Pointer to host adapter structure.
  *
- * Retrieves the firmware version on HBA. In QLA4010, mailboxes 2 & 3 may
- * hold an address for data.  Make sure that we write 0 to those mailboxes,
- * if unused.
+ * Retrieves the FW version, iSCSI draft version & bootloader version of HBA.
+ * Mailboxes 2 & 3 may hold an address for data. Make sure that we write 0 to
+ * those mailboxes, if unused.
  **/
-int qla4xxx_get_fw_version(struct scsi_qla_host * ha)
+int qla4xxx_about_firmware(struct scsi_qla_host *ha)
 {
+       struct about_fw_info *about_fw = NULL;
+       dma_addr_t about_fw_dma;
        uint32_t mbox_cmd[MBOX_REG_COUNT];
        uint32_t mbox_sts[MBOX_REG_COUNT];
+       int status = QLA_ERROR;
+
+       about_fw = dma_alloc_coherent(&ha->pdev->dev,
+                                     sizeof(struct about_fw_info),
+                                     &about_fw_dma, GFP_KERNEL);
+       if (!about_fw) {
+               DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Unable to alloc memory "
+                                 "for about_fw\n", __func__));
+               return status;
+       }
 
-       /* Get firmware version. */
+       memset(about_fw, 0, sizeof(struct about_fw_info));
        memset(&mbox_cmd, 0, sizeof(mbox_cmd));
        memset(&mbox_sts, 0, sizeof(mbox_sts));
 
        mbox_cmd[0] = MBOX_CMD_ABOUT_FW;
-
-       if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) !=
-           QLA_SUCCESS) {
-               DEBUG2(printk("scsi%ld: %s: MBOX_CMD_ABOUT_FW failed w/ "
-                   "status %04X\n", ha->host_no, __func__, mbox_sts[0]));
-               return QLA_ERROR;
+       mbox_cmd[2] = LSDW(about_fw_dma);
+       mbox_cmd[3] = MSDW(about_fw_dma);
+       mbox_cmd[4] = sizeof(struct about_fw_info);
+
+       status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, MBOX_REG_COUNT,
+                                        &mbox_cmd[0], &mbox_sts[0]);
+       if (status != QLA_SUCCESS) {
+               DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_ABOUT_FW "
+                                 "failed w/ status %04X\n", __func__,
+                                 mbox_sts[0]));
+               goto exit_about_fw;
        }
 
-       /* Save firmware version information. */
-       ha->firmware_version[0] = mbox_sts[1];
-       ha->firmware_version[1] = mbox_sts[2];
-       ha->patch_number = mbox_sts[3];
-       ha->build_number = mbox_sts[4];
+       /* Save version information. */
+       ha->firmware_version[0] = le16_to_cpu(about_fw->fw_major);
+       ha->firmware_version[1] = le16_to_cpu(about_fw->fw_minor);
+       ha->patch_number = le16_to_cpu(about_fw->fw_patch);
+       ha->build_number = le16_to_cpu(about_fw->fw_build);
+       ha->iscsi_major = le16_to_cpu(about_fw->iscsi_major);
+       ha->iscsi_minor = le16_to_cpu(about_fw->iscsi_minor);
+       ha->bootload_major = le16_to_cpu(about_fw->bootload_major);
+       ha->bootload_minor = le16_to_cpu(about_fw->bootload_minor);
+       ha->bootload_patch = le16_to_cpu(about_fw->bootload_patch);
+       ha->bootload_build = le16_to_cpu(about_fw->bootload_build);
+       status = QLA_SUCCESS;
 
-       return QLA_SUCCESS;
+exit_about_fw:
+       dma_free_coherent(&ha->pdev->dev, sizeof(struct about_fw_info),
+                         about_fw, about_fw_dma);
+       return status;
 }
 
 static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha,
index 35381cb0936e751775f2e9e770f399577d810361..fdfe27b3869807289d98c4cf75afef678a4ecf4f 100644 (file)
@@ -655,6 +655,27 @@ static int qla4_8xxx_pci_is_same_window(struct scsi_qla_host *ha,
        return 0;
 }
 
+#ifndef readq
+static inline __u64 readq(const volatile void __iomem *addr)
+{
+       const volatile u32 __iomem *p = addr;
+       u32 low, high;
+
+       low = readl(p);
+       high = readl(p + 1);
+
+       return low + ((u64)high << 32);
+}
+#endif
+
+#ifndef writeq
+static inline void writeq(__u64 val, volatile void __iomem *addr)
+{
+       writel(val, addr);
+       writel(val >> 32, addr+4);
+}
+#endif
+
 static int qla4_8xxx_pci_mem_read_direct(struct scsi_qla_host *ha,
                u64 off, void *data, int size)
 {
@@ -943,12 +964,26 @@ qla4_8xxx_pinit_from_rom(struct scsi_qla_host *ha, int verbose)
        /* Halt all the indiviual PEGs and other blocks of the ISP */
        qla4_8xxx_rom_lock(ha);
 
-       /* mask all niu interrupts */
+       /* disable all I2Q */
+       qla4_8xxx_wr_32(ha, QLA82XX_CRB_I2Q + 0x10, 0x0);
+       qla4_8xxx_wr_32(ha, QLA82XX_CRB_I2Q + 0x14, 0x0);
+       qla4_8xxx_wr_32(ha, QLA82XX_CRB_I2Q + 0x18, 0x0);
+       qla4_8xxx_wr_32(ha, QLA82XX_CRB_I2Q + 0x1c, 0x0);
+       qla4_8xxx_wr_32(ha, QLA82XX_CRB_I2Q + 0x20, 0x0);
+       qla4_8xxx_wr_32(ha, QLA82XX_CRB_I2Q + 0x24, 0x0);
+
+       /* disable all niu interrupts */
        qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x40, 0xff);
        /* disable xge rx/tx */
        qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x70000, 0x00);
        /* disable xg1 rx/tx */
        qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x80000, 0x00);
+       /* disable sideband mac */
+       qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x90000, 0x00);
+       /* disable ap0 mac */
+       qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0xa0000, 0x00);
+       /* disable ap1 mac */
+       qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0xb0000, 0x00);
 
        /* halt sre */
        val = qla4_8xxx_rd_32(ha, QLA82XX_CRB_SRE + 0x1000);
@@ -963,6 +998,7 @@ qla4_8xxx_pinit_from_rom(struct scsi_qla_host *ha, int verbose)
        qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x10, 0x0);
        qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x18, 0x0);
        qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x100, 0x0);
+       qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x200, 0x0);
 
        /* halt pegs */
        qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x3c, 1);
@@ -970,9 +1006,9 @@ qla4_8xxx_pinit_from_rom(struct scsi_qla_host *ha, int verbose)
        qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_2 + 0x3c, 1);
        qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_3 + 0x3c, 1);
        qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c, 1);
+       msleep(5);
 
        /* big hammer */
-       msleep(1000);
        if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
                /* don't reset CAM block on reset */
                qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xfeffffff);
index c22f2a764d9d0f46a356e17973c745bec578ccaf..f2364ec59f0349e43950fd2a4585ba7f2c26838c 100644 (file)
@@ -124,6 +124,7 @@ static struct scsi_host_template qla4xxx_driver_template = {
        .sg_tablesize           = SG_ALL,
 
        .max_sectors            = 0xFFFF,
+       .shost_attrs            = qla4xxx_host_attrs,
 };
 
 static struct iscsi_transport qla4xxx_iscsi_transport = {
@@ -412,8 +413,7 @@ void qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha)
 
 static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
                                       struct ddb_entry *ddb_entry,
-                                      struct scsi_cmnd *cmd,
-                                      void (*done)(struct scsi_cmnd *))
+                                      struct scsi_cmnd *cmd)
 {
        struct srb *srb;
 
@@ -427,7 +427,6 @@ static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
        srb->cmd = cmd;
        srb->flags = 0;
        CMD_SP(cmd) = (void *)srb;
-       cmd->scsi_done = done;
 
        return srb;
 }
@@ -458,9 +457,8 @@ void qla4xxx_srb_compl(struct kref *ref)
 
 /**
  * qla4xxx_queuecommand - scsi layer issues scsi command to driver.
+ * @host: scsi host
  * @cmd: Pointer to Linux's SCSI command structure
- * @done_fn: Function that the driver calls to notify the SCSI mid-layer
- *     that the command has been processed.
  *
  * Remarks:
  * This routine is invoked by Linux to send a SCSI command to the driver.
@@ -470,10 +468,9 @@ void qla4xxx_srb_compl(struct kref *ref)
  * completion handling).   Unfortunely, it sometimes calls the scheduler
  * in interrupt context which is a big NO! NO!.
  **/
-static int qla4xxx_queuecommand_lck(struct scsi_cmnd *cmd,
-                               void (*done)(struct scsi_cmnd *))
+static int qla4xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
 {
-       struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
+       struct scsi_qla_host *ha = to_qla_host(host);
        struct ddb_entry *ddb_entry = cmd->device->hostdata;
        struct iscsi_cls_session *sess = ddb_entry->sess;
        struct srb *srb;
@@ -515,37 +512,29 @@ static int qla4xxx_queuecommand_lck(struct scsi_cmnd *cmd,
            test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))
                goto qc_host_busy;
 
-       spin_unlock_irq(ha->host->host_lock);
-
-       srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd, done);
+       srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd);
        if (!srb)
-               goto qc_host_busy_lock;
+               goto qc_host_busy;
 
        rval = qla4xxx_send_command_to_isp(ha, srb);
        if (rval != QLA_SUCCESS)
                goto qc_host_busy_free_sp;
 
-       spin_lock_irq(ha->host->host_lock);
        return 0;
 
 qc_host_busy_free_sp:
        qla4xxx_srb_free_dma(ha, srb);
        mempool_free(srb, ha->srb_mempool);
 
-qc_host_busy_lock:
-       spin_lock_irq(ha->host->host_lock);
-
 qc_host_busy:
        return SCSI_MLQUEUE_HOST_BUSY;
 
 qc_fail_command:
-       done(cmd);
+       cmd->scsi_done(cmd);
 
        return 0;
 }
 
-static DEF_SCSI_QCMD(qla4xxx_queuecommand)
-
 /**
  * qla4xxx_mem_free - frees memory allocated to adapter
  * @ha: Pointer to host adapter structure.
@@ -679,7 +668,27 @@ static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
                if (ha->seconds_since_last_heartbeat == 2) {
                        ha->seconds_since_last_heartbeat = 0;
                        halt_status = qla4_8xxx_rd_32(ha,
-                           QLA82XX_PEG_HALT_STATUS1);
+                                                     QLA82XX_PEG_HALT_STATUS1);
+
+                       ql4_printk(KERN_INFO, ha,
+                                  "scsi(%ld): %s, Dumping hw/fw registers:\n "
+                                  " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2:"
+                                  " 0x%x,\n PEG_NET_0_PC: 0x%x, PEG_NET_1_PC:"
+                                  " 0x%x,\n PEG_NET_2_PC: 0x%x, PEG_NET_3_PC:"
+                                  " 0x%x,\n PEG_NET_4_PC: 0x%x\n",
+                                  ha->host_no, __func__, halt_status,
+                                  qla4_8xxx_rd_32(ha,
+                                                  QLA82XX_PEG_HALT_STATUS2),
+                                  qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_0 +
+                                                  0x3c),
+                                  qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_1 +
+                                                  0x3c),
+                                  qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_2 +
+                                                  0x3c),
+                                  qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_3 +
+                                                  0x3c),
+                                  qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 +
+                                                  0x3c));
 
                        /* Since we cannot change dev_state in interrupt
                         * context, set appropriate DPC flag then wakeup
@@ -715,7 +724,7 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
        /* don't poll if reset is going on */
        if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
            test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
-           test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags))) {
+           test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags))) {
                if (dev_state == QLA82XX_DEV_NEED_RESET &&
                    !test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
                        if (!ql4xdontresethba) {
@@ -839,7 +848,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha)
        }
 
        /* Wakeup the dpc routine for this adapter, if needed. */
-       if ((start_dpc ||
+       if (start_dpc ||
             test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
             test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) ||
             test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) ||
@@ -849,9 +858,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha)
             test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) ||
             test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) ||
             test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) ||
-            test_bit(DPC_AEN, &ha->dpc_flags)) &&
-            !test_bit(AF_DPC_SCHEDULED, &ha->flags) &&
-            ha->dpc_thread) {
+            test_bit(DPC_AEN, &ha->dpc_flags)) {
                DEBUG2(printk("scsi%ld: %s: scheduling dpc routine"
                              " - dpc flags = 0x%lx\n",
                              ha->host_no, __func__, ha->dpc_flags));
@@ -1241,11 +1248,8 @@ static void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha)
 
 void qla4xxx_wake_dpc(struct scsi_qla_host *ha)
 {
-       if (ha->dpc_thread &&
-           !test_bit(AF_DPC_SCHEDULED, &ha->flags)) {
-               set_bit(AF_DPC_SCHEDULED, &ha->flags);
+       if (ha->dpc_thread)
                queue_work(ha->dpc_thread, &ha->dpc_work);
-       }
 }
 
 /**
@@ -1272,12 +1276,12 @@ static void qla4xxx_do_dpc(struct work_struct *work)
 
        /* Initialization not yet finished. Don't do anything yet. */
        if (!test_bit(AF_INIT_DONE, &ha->flags))
-               goto do_dpc_exit;
+               return;
 
        if (test_bit(AF_EEH_BUSY, &ha->flags)) {
                DEBUG2(printk(KERN_INFO "scsi%ld: %s: flags = %lx\n",
                    ha->host_no, __func__, ha->flags));
-               goto do_dpc_exit;
+               return;
        }
 
        if (is_qla8022(ha)) {
@@ -1384,8 +1388,6 @@ dpc_post_reset_ha:
                }
        }
 
-do_dpc_exit:
-       clear_bit(AF_DPC_SCHEDULED, &ha->flags);
 }
 
 /**
index 60315576940721a8e2ae435d9437277b15255606..610492877253a8771356acae5c54ad13d43126bb 100644 (file)
@@ -5,4 +5,4 @@
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
 
-#define QLA4XXX_DRIVER_VERSION "5.02.00-k6"
+#define QLA4XXX_DRIVER_VERSION "5.02.00-k7"
index abea2cf05c2e41cc1b7a7df581ae74cf0db56768..a4b9cdbaaa0b99d321a37e2fa1db8bf4063e2c86 100644 (file)
@@ -50,6 +50,8 @@
 #define BUS_RESET_SETTLE_TIME   (10)
 #define HOST_RESET_SETTLE_TIME  (10)
 
+static int scsi_eh_try_stu(struct scsi_cmnd *scmd);
+
 /* called with shost->host_lock held */
 void scsi_eh_wakeup(struct Scsi_Host *shost)
 {
@@ -946,6 +948,48 @@ retry_tur:
        }
 }
 
+/**
+ * scsi_eh_test_devices - check if devices are responding from error recovery.
+ * @cmd_list:  scsi commands in error recovery.
+ * @work_q:     queue for commands which still need more error recovery
+ * @done_q:     queue for commands which are finished
+ * @try_stu:    boolean on if a STU command should be tried in addition to TUR.
+ *
+ * Decription:
+ *    Tests if devices are in a working state.  Commands to devices now in
+ *    a working state are sent to the done_q while commands to devices which
+ *    are still failing to respond are returned to the work_q for more
+ *    processing.
+ **/
+static int scsi_eh_test_devices(struct list_head *cmd_list,
+                               struct list_head *work_q,
+                               struct list_head *done_q, int try_stu)
+{
+       struct scsi_cmnd *scmd, *next;
+       struct scsi_device *sdev;
+       int finish_cmds;
+
+       while (!list_empty(cmd_list)) {
+               scmd = list_entry(cmd_list->next, struct scsi_cmnd, eh_entry);
+               sdev = scmd->device;
+
+               finish_cmds = !scsi_device_online(scmd->device) ||
+                       (try_stu && !scsi_eh_try_stu(scmd) &&
+                        !scsi_eh_tur(scmd)) ||
+                       !scsi_eh_tur(scmd);
+
+               list_for_each_entry_safe(scmd, next, cmd_list, eh_entry)
+                       if (scmd->device == sdev) {
+                               if (finish_cmds)
+                                       scsi_eh_finish_cmd(scmd, done_q);
+                               else
+                                       list_move_tail(&scmd->eh_entry, work_q);
+                       }
+       }
+       return list_empty(work_q);
+}
+
+
 /**
  * scsi_eh_abort_cmds - abort pending commands.
  * @work_q:    &list_head for pending commands.
@@ -962,6 +1006,7 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,
                              struct list_head *done_q)
 {
        struct scsi_cmnd *scmd, *next;
+       LIST_HEAD(check_list);
        int rtn;
 
        list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
@@ -973,11 +1018,10 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,
                rtn = scsi_try_to_abort_cmd(scmd->device->host->hostt, scmd);
                if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
                        scmd->eh_eflags &= ~SCSI_EH_CANCEL_CMD;
-                       if (!scsi_device_online(scmd->device) ||
-                           rtn == FAST_IO_FAIL ||
-                           !scsi_eh_tur(scmd)) {
+                       if (rtn == FAST_IO_FAIL)
                                scsi_eh_finish_cmd(scmd, done_q);
-                       }
+                       else
+                               list_move_tail(&scmd->eh_entry, &check_list);
                } else
                        SCSI_LOG_ERROR_RECOVERY(3, printk("%s: aborting"
                                                          " cmd failed:"
@@ -986,7 +1030,7 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,
                                                          scmd));
        }
 
-       return list_empty(work_q);
+       return scsi_eh_test_devices(&check_list, work_q, done_q, 0);
 }
 
 /**
@@ -1137,6 +1181,7 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,
                                struct list_head *done_q)
 {
        LIST_HEAD(tmp_list);
+       LIST_HEAD(check_list);
 
        list_splice_init(work_q, &tmp_list);
 
@@ -1161,9 +1206,9 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,
                        if (scmd_id(scmd) != id)
                                continue;
 
-                       if ((rtn == SUCCESS || rtn == FAST_IO_FAIL)
-                           && (!scsi_device_online(scmd->device) ||
-                                rtn == FAST_IO_FAIL || !scsi_eh_tur(scmd)))
+                       if (rtn == SUCCESS)
+                               list_move_tail(&scmd->eh_entry, &check_list);
+                       else if (rtn == FAST_IO_FAIL)
                                scsi_eh_finish_cmd(scmd, done_q);
                        else
                                /* push back on work queue for further processing */
@@ -1171,7 +1216,7 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,
                }
        }
 
-       return list_empty(work_q);
+       return scsi_eh_test_devices(&check_list, work_q, done_q, 0);
 }
 
 /**
@@ -1185,6 +1230,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
                             struct list_head *done_q)
 {
        struct scsi_cmnd *scmd, *chan_scmd, *next;
+       LIST_HEAD(check_list);
        unsigned int channel;
        int rtn;
 
@@ -1216,12 +1262,14 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
                rtn = scsi_try_bus_reset(chan_scmd);
                if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
                        list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
-                               if (channel == scmd_channel(scmd))
-                                       if (!scsi_device_online(scmd->device) ||
-                                           rtn == FAST_IO_FAIL ||
-                                           !scsi_eh_tur(scmd))
+                               if (channel == scmd_channel(scmd)) {
+                                       if (rtn == FAST_IO_FAIL)
                                                scsi_eh_finish_cmd(scmd,
                                                                   done_q);
+                                       else
+                                               list_move_tail(&scmd->eh_entry,
+                                                              &check_list);
+                               }
                        }
                } else {
                        SCSI_LOG_ERROR_RECOVERY(3, printk("%s: BRST"
@@ -1230,7 +1278,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
                                                          channel));
                }
        }
-       return list_empty(work_q);
+       return scsi_eh_test_devices(&check_list, work_q, done_q, 0);
 }
 
 /**
@@ -1242,6 +1290,7 @@ static int scsi_eh_host_reset(struct list_head *work_q,
                              struct list_head *done_q)
 {
        struct scsi_cmnd *scmd, *next;
+       LIST_HEAD(check_list);
        int rtn;
 
        if (!list_empty(work_q)) {
@@ -1252,12 +1301,10 @@ static int scsi_eh_host_reset(struct list_head *work_q,
                                                  , current->comm));
 
                rtn = scsi_try_host_reset(scmd);
-               if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
+               if (rtn == SUCCESS) {
+                       list_splice_init(work_q, &check_list);
+               } else if (rtn == FAST_IO_FAIL) {
                        list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
-                               if (!scsi_device_online(scmd->device) ||
-                                   rtn == FAST_IO_FAIL ||
-                                   (!scsi_eh_try_stu(scmd) && !scsi_eh_tur(scmd)) ||
-                                   !scsi_eh_tur(scmd))
                                        scsi_eh_finish_cmd(scmd, done_q);
                        }
                } else {
@@ -1266,7 +1313,7 @@ static int scsi_eh_host_reset(struct list_head *work_q,
                                                          current->comm));
                }
        }
-       return list_empty(work_q);
+       return scsi_eh_test_devices(&check_list, work_q, done_q, 1);
 }
 
 /**
index f46855cd853dc167d50e341ee494f13f6b5d8c2f..ad747dc337da355315c9bb3f0f506e5d84b8f2ee 100644 (file)
@@ -381,11 +381,6 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
        return err;
 }
 
-/**
- * proc_scsi_show - show contents of /proc/scsi/scsi (attached devices)
- * @s: output goes here
- * @p: not used
- */
 static int always_match(struct device *dev, void *data)
 {
        return 1;
index 58584dc0724ade4fb4b2d5fc12d48b962d2b91bd..44e8ca398efa790083006131f5adb3bf37cd57aa 100644 (file)
@@ -297,7 +297,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
                kfree(sdev);
                goto out;
        }
-
+       blk_get_queue(sdev->request_queue);
        sdev->request_queue->queuedata = sdev;
        scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
 
index e63912510fb9349b31ede55df1c0b20011b6235e..e0bd3f790fca1bf50e4e66e3b2f30f9a130547f3 100644 (file)
@@ -322,6 +322,7 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
                kfree(evt);
        }
 
+       blk_put_queue(sdev->request_queue);
        /* NULL queue means the device can't be used */
        sdev->request_queue = NULL;
 
index b587289cfacb08cd7efa0461d08da31e7f9be41f..2bea4f0b684af120dc57a3f843d6b4c699a4a220 100644 (file)
@@ -59,6 +59,10 @@ scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len)
        trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
                         (unsigned long long)lba, (unsigned long long)txlen,
                         cdb[1] >> 5);
+
+       if (cdb[0] == WRITE_SAME)
+               trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);
+
        trace_seq_putc(p, 0);
 
        return ret;
index bd0806e64e857172a8af6061a87b0e4b52758836..953773cb26d9a6204a52d56e75884622632c4c0c 100644 (file)
@@ -490,7 +490,8 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode)
        unsigned int max_blocks = 0;
 
        q->limits.discard_zeroes_data = sdkp->lbprz;
-       q->limits.discard_alignment = sdkp->unmap_alignment;
+       q->limits.discard_alignment = sdkp->unmap_alignment *
+               logical_block_size;
        q->limits.discard_granularity =
                max(sdkp->physical_block_size,
                    sdkp->unmap_granularity * logical_block_size);
@@ -2021,16 +2022,26 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
 
        int dbd;
        int modepage;
+       int first_len;
        struct scsi_mode_data data;
        struct scsi_sense_hdr sshdr;
        int old_wce = sdkp->WCE;
        int old_rcd = sdkp->RCD;
        int old_dpofua = sdkp->DPOFUA;
 
-       if (sdp->skip_ms_page_8)
-               goto defaults;
-
-       if (sdp->type == TYPE_RBC) {
+       first_len = 4;
+       if (sdp->skip_ms_page_8) {
+               if (sdp->type == TYPE_RBC)
+                       goto defaults;
+               else {
+                       if (sdp->skip_ms_page_3f)
+                               goto defaults;
+                       modepage = 0x3F;
+                       if (sdp->use_192_bytes_for_3f)
+                               first_len = 192;
+                       dbd = 0;
+               }
+       } else if (sdp->type == TYPE_RBC) {
                modepage = 6;
                dbd = 8;
        } else {
@@ -2039,13 +2050,15 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
        }
 
        /* cautiously ask */
-       res = sd_do_mode_sense(sdp, dbd, modepage, buffer, 4, &data, &sshdr);
+       res = sd_do_mode_sense(sdp, dbd, modepage, buffer, first_len,
+                       &data, &sshdr);
 
        if (!scsi_status_is_good(res))
                goto bad_sense;
 
        if (!data.header_length) {
                modepage = 6;
+               first_len = 0;
                sd_printk(KERN_ERR, sdkp, "Missing header in MODE_SENSE response\n");
        }
 
@@ -2058,30 +2071,61 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
         */
        if (len < 3)
                goto bad_sense;
-       if (len > 20)
-               len = 20;
-
-       /* Take headers and block descriptors into account */
-       len += data.header_length + data.block_descriptor_length;
-       if (len > SD_BUF_SIZE)
-               goto bad_sense;
+       else if (len > SD_BUF_SIZE) {
+               sd_printk(KERN_NOTICE, sdkp, "Truncating mode parameter "
+                         "data from %d to %d bytes\n", len, SD_BUF_SIZE);
+               len = SD_BUF_SIZE;
+       }
+       if (modepage == 0x3F && sdp->use_192_bytes_for_3f)
+               len = 192;
 
        /* Get the data */
-       res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr);
+       if (len > first_len)
+               res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len,
+                               &data, &sshdr);
 
        if (scsi_status_is_good(res)) {
                int offset = data.header_length + data.block_descriptor_length;
 
-               if (offset >= SD_BUF_SIZE - 2) {
-                       sd_printk(KERN_ERR, sdkp, "Malformed MODE SENSE response\n");
-                       goto defaults;
+               while (offset < len) {
+                       u8 page_code = buffer[offset] & 0x3F;
+                       u8 spf       = buffer[offset] & 0x40;
+
+                       if (page_code == 8 || page_code == 6) {
+                               /* We're interested only in the first 3 bytes.
+                                */
+                               if (len - offset <= 2) {
+                                       sd_printk(KERN_ERR, sdkp, "Incomplete "
+                                                 "mode parameter data\n");
+                                       goto defaults;
+                               } else {
+                                       modepage = page_code;
+                                       goto Page_found;
+                               }
+                       } else {
+                               /* Go to the next page */
+                               if (spf && len - offset > 3)
+                                       offset += 4 + (buffer[offset+2] << 8) +
+                                               buffer[offset+3];
+                               else if (!spf && len - offset > 1)
+                                       offset += 2 + buffer[offset+1];
+                               else {
+                                       sd_printk(KERN_ERR, sdkp, "Incomplete "
+                                                 "mode parameter data\n");
+                                       goto defaults;
+                               }
+                       }
                }
 
-               if ((buffer[offset] & 0x3f) != modepage) {
+               if (modepage == 0x3F) {
+                       sd_printk(KERN_ERR, sdkp, "No Caching mode page "
+                                 "present\n");
+                       goto defaults;
+               } else if ((buffer[offset] & 0x3f) != modepage) {
                        sd_printk(KERN_ERR, sdkp, "Got wrong page\n");
                        goto defaults;
                }
-
+       Page_found:
                if (modepage == 8) {
                        sdkp->WCE = ((buffer[offset + 2] & 0x04) != 0);
                        sdkp->RCD = ((buffer[offset + 2] & 0x01) != 0);
index 95019c747cc17cad69ed22c9091c2228b914c23b..4778e27071689593ec4fdffdd1107018c2f7ebe6 100644 (file)
@@ -636,7 +636,7 @@ static int sr_probe(struct device *dev)
        disk->first_minor = minor;
        sprintf(disk->disk_name, "sr%d", minor);
        disk->fops = &sr_bdops;
-       disk->flags = GENHD_FL_CD;
+       disk->flags = GENHD_FL_CD | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
        disk->events = DISK_EVENT_MEDIA_CHANGE | DISK_EVENT_EJECT_REQUEST;
 
        blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT);
index 9f4b58b7daaded8801e2724a8fce3ecfd6441166..7e22b737dfd8ff4216f4eeddd015066b08ca2e0c 100644 (file)
@@ -307,7 +307,7 @@ static inline int find_and_clear_bit_16(unsigned long *field)
        "0: bsfw %1,%w0\n\t"
        "btr %0,%1\n\t"
        "jnc 0b"
-       : "=&r" (rv), "=m" (*field) :);
+       : "=&r" (rv), "+m" (*field) :);
 
   return rv;
 }
index 97ae716134d05fb1ae76732925e480e736592081..c0ee4ea28a19707896c3a74021c4e231bd5d4880 100644 (file)
@@ -2051,8 +2051,7 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs,
        for (i = 0; i < MAX_SETUP_ARGS; i++)
                printk("%s,", setup_args[i]);
        printk("\n");
-       printk("           Version %s - %s, Compiled %s at %s\n",
-              WD33C93_VERSION, WD33C93_DATE, __DATE__, __TIME__);
+       printk("           Version %s - %s\n", WD33C93_VERSION, WD33C93_DATE);
 }
 
 int
@@ -2132,8 +2131,8 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off
        bp = buf;
        *bp = '\0';
        if (hd->proc & PR_VERSION) {
-               sprintf(tbuf, "\nVersion %s - %s. Compiled %s %s",
-                       WD33C93_VERSION, WD33C93_DATE, __DATE__, __TIME__);
+               sprintf(tbuf, "\nVersion %s - %s.",
+                       WD33C93_VERSION, WD33C93_DATE);
                strcat(bp, tbuf);
        }
        if (hd->proc & PR_INFO) {
index 4f64183b27fa6283c80d4fa2d37aa61c61c127fe..7e9c39951ecb87c086c9ab439df893a5c0980752 100644 (file)
@@ -635,7 +635,7 @@ static void clks_core_resume(void)
        struct clk *clkp;
 
        list_for_each_entry(clkp, &clock_list, node) {
-               if (likely(clkp->ops)) {
+               if (likely(clkp->usecount && clkp->ops)) {
                        unsigned long rate = clkp->rate;
 
                        if (likely(clkp->ops->set_parent))
index fc14b8dea0d71daf1a72f0f17dd5228b07c7ba33..de35c3ad8a69a00e2e3f677d43864a16bfdba14b 100644 (file)
@@ -80,6 +80,15 @@ config SPI_BFIN
        help
          This is the SPI controller master driver for Blackfin 5xx processor.
 
+config SPI_BFIN_SPORT
+       tristate "SPI bus via Blackfin SPORT"
+       depends on BLACKFIN
+       help
+         Enable support for a SPI bus via the Blackfin SPORT peripheral.
+
+         This driver can also be built as a module.  If so, the module
+         will be called spi_bfin_sport.
+
 config SPI_AU1550
        tristate "Au1550/Au12x0 SPI Controller"
        depends on (SOC_AU1550 || SOC_AU1200) && EXPERIMENTAL
@@ -271,8 +280,8 @@ config SPI_ORION
          This enables using the SPI master controller on the Orion chips.
 
 config SPI_PL022
-       tristate "ARM AMBA PL022 SSP controller (EXPERIMENTAL)"
-       depends on ARM_AMBA && EXPERIMENTAL
+       tristate "ARM AMBA PL022 SSP controller"
+       depends on ARM_AMBA
        default y if MACH_U300
        default y if ARCH_REALVIEW
        default y if INTEGRATOR_IMPD1
index fd2fc5f6505f7e26e5e83dbb8371242086068814..0f8c69b6b19e87bfd34538118354e792cbcb5b13 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_SPI_ALTERA)              += spi_altera.o
 obj-$(CONFIG_SPI_ATMEL)                        += atmel_spi.o
 obj-$(CONFIG_SPI_ATH79)                        += ath79_spi.o
 obj-$(CONFIG_SPI_BFIN)                 += spi_bfin5xx.o
+obj-$(CONFIG_SPI_BFIN_SPORT)           += spi_bfin_sport.o
 obj-$(CONFIG_SPI_BITBANG)              += spi_bitbang.o
 obj-$(CONFIG_SPI_AU1550)               += au1550_spi.o
 obj-$(CONFIG_SPI_BUTTERFLY)            += spi_butterfly.o
index 08de58e7f59f7f6521ffb5122078103473c66117..d18ce9e946d8d085b9ecf0c8fefe9cc88cd99334 100644 (file)
  * GNU General Public License for more details.
  */
 
-/*
- * TODO:
- * - add timeout on polled transfers
- */
-
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/device.h>
 
 #define CLEAR_ALL_INTERRUPTS  0x3
 
+#define SPI_POLLING_TIMEOUT 1000
+
 
 /*
  * The type of reading going on on this chip
@@ -1063,7 +1060,7 @@ static int __init pl022_dma_probe(struct pl022 *pl022)
                                            pl022->master_info->dma_filter,
                                            pl022->master_info->dma_rx_param);
        if (!pl022->dma_rx_channel) {
-               dev_err(&pl022->adev->dev, "no RX DMA channel!\n");
+               dev_dbg(&pl022->adev->dev, "no RX DMA channel!\n");
                goto err_no_rxchan;
        }
 
@@ -1071,13 +1068,13 @@ static int __init pl022_dma_probe(struct pl022 *pl022)
                                            pl022->master_info->dma_filter,
                                            pl022->master_info->dma_tx_param);
        if (!pl022->dma_tx_channel) {
-               dev_err(&pl022->adev->dev, "no TX DMA channel!\n");
+               dev_dbg(&pl022->adev->dev, "no TX DMA channel!\n");
                goto err_no_txchan;
        }
 
        pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL);
        if (!pl022->dummypage) {
-               dev_err(&pl022->adev->dev, "no DMA dummypage!\n");
+               dev_dbg(&pl022->adev->dev, "no DMA dummypage!\n");
                goto err_no_dummypage;
        }
 
@@ -1093,6 +1090,8 @@ err_no_txchan:
        dma_release_channel(pl022->dma_rx_channel);
        pl022->dma_rx_channel = NULL;
 err_no_rxchan:
+       dev_err(&pl022->adev->dev,
+                       "Failed to work in dma mode, work without dma!\n");
        return -ENODEV;
 }
 
@@ -1378,6 +1377,7 @@ static void do_polling_transfer(struct pl022 *pl022)
        struct spi_transfer *transfer = NULL;
        struct spi_transfer *previous = NULL;
        struct chip_data *chip;
+       unsigned long time, timeout;
 
        chip = pl022->cur_chip;
        message = pl022->cur_msg;
@@ -1415,9 +1415,19 @@ static void do_polling_transfer(struct pl022 *pl022)
                       SSP_CR1(pl022->virtbase));
 
                dev_dbg(&pl022->adev->dev, "polling transfer ongoing ...\n");
-               /* FIXME: insert a timeout so we don't hang here indefinitely */
-               while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end)
+
+               timeout = jiffies + msecs_to_jiffies(SPI_POLLING_TIMEOUT);
+               while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end) {
+                       time = jiffies;
                        readwriter(pl022);
+                       if (time_after(time, timeout)) {
+                               dev_warn(&pl022->adev->dev,
+                               "%s: timeout!\n", __func__);
+                               message->state = STATE_ERROR;
+                               goto out;
+                       }
+                       cpu_relax();
+               }
 
                /* Update total byte transferred */
                message->actual_length += pl022->cur_transfer->len;
@@ -1426,7 +1436,7 @@ static void do_polling_transfer(struct pl022 *pl022)
                /* Move to next transfer */
                message->state = next_transfer(pl022);
        }
-
+out:
        /* Handle end of message */
        if (message->state == STATE_DONE)
                message->status = 0;
@@ -1851,6 +1861,7 @@ static int pl022_setup(struct spi_device *spi)
        }
        if ((clk_freq.cpsdvsr < CPSDVR_MIN)
            || (clk_freq.cpsdvsr > CPSDVR_MAX)) {
+               status = -EINVAL;
                dev_err(&spi->dev,
                        "cpsdvsr is configured incorrectly\n");
                goto err_config_params;
@@ -2107,7 +2118,7 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
        if (platform_info->enable_dma) {
                status = pl022_dma_probe(pl022);
                if (status != 0)
-                       goto err_no_dma;
+                       platform_info->enable_dma = 0;
        }
 
        /* Initialize and start queue */
@@ -2143,7 +2154,6 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
  err_init_queue:
        destroy_queue(pl022);
        pl022_dma_remove(pl022);
- err_no_dma:
        free_irq(adev->irq[0], pl022);
  err_no_irq:
        clk_put(pl022->clk);
index 8856bcca9d2933db4a8f98526bc716c6640bb075..ae2cd1c1fda8868d5febe3e151e7849045c571cd 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/spi/spi.h>
 
 #include <asm/coldfire.h>
+#include <asm/mcfsim.h>
 #include <asm/mcfqspi.h>
 
 #define        DRIVER_NAME "mcfqspi"
index 871e337c917fe7313621e651be0da62891545b05..919fa9d9e16bab34fef8af03a5a6286ac9fad394 100644 (file)
@@ -58,8 +58,6 @@ struct chip_data {
        u8 bits_per_word;
        u16 clk_div;            /* baud rate divider */
        u32 speed_hz;           /* baud rate */
-       int (*write)(struct dw_spi *dws);
-       int (*read)(struct dw_spi *dws);
        void (*cs_control)(u32 command);
 };
 
@@ -162,107 +160,70 @@ static inline void mrst_spi_debugfs_remove(struct dw_spi *dws)
 }
 #endif /* CONFIG_DEBUG_FS */
 
-static void wait_till_not_busy(struct dw_spi *dws)
+/* Return the max entries we can fill into tx fifo */
+static inline u32 tx_max(struct dw_spi *dws)
 {
-       unsigned long end = jiffies + 1 + usecs_to_jiffies(5000);
+       u32 tx_left, tx_room, rxtx_gap;
 
-       while (time_before(jiffies, end)) {
-               if (!(dw_readw(dws, sr) & SR_BUSY))
-                       return;
-               cpu_relax();
-       }
-       dev_err(&dws->master->dev,
-               "DW SPI: Status keeps busy for 5000us after a read/write!\n");
-}
-
-static void flush(struct dw_spi *dws)
-{
-       while (dw_readw(dws, sr) & SR_RF_NOT_EMPT) {
-               dw_readw(dws, dr);
-               cpu_relax();
-       }
-
-       wait_till_not_busy(dws);
-}
-
-static int null_writer(struct dw_spi *dws)
-{
-       u8 n_bytes = dws->n_bytes;
+       tx_left = (dws->tx_end - dws->tx) / dws->n_bytes;
+       tx_room = dws->fifo_len - dw_readw(dws, txflr);
 
-       if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL)
-               || (dws->tx == dws->tx_end))
-               return 0;
-       dw_writew(dws, dr, 0);
-       dws->tx += n_bytes;
+       /*
+        * Another concern is about the tx/rx mismatch, we
+        * though to use (dws->fifo_len - rxflr - txflr) as
+        * one maximum value for tx, but it doesn't cover the
+        * data which is out of tx/rx fifo and inside the
+        * shift registers. So a control from sw point of
+        * view is taken.
+        */
+       rxtx_gap =  ((dws->rx_end - dws->rx) - (dws->tx_end - dws->tx))
+                       / dws->n_bytes;
 
-       wait_till_not_busy(dws);
-       return 1;
+       return min3(tx_left, tx_room, (u32) (dws->fifo_len - rxtx_gap));
 }
 
-static int null_reader(struct dw_spi *dws)
+/* Return the max entries we should read out of rx fifo */
+static inline u32 rx_max(struct dw_spi *dws)
 {
-       u8 n_bytes = dws->n_bytes;
+       u32 rx_left = (dws->rx_end - dws->rx) / dws->n_bytes;
 
-       while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT)
-               && (dws->rx < dws->rx_end)) {
-               dw_readw(dws, dr);
-               dws->rx += n_bytes;
-       }
-       wait_till_not_busy(dws);
-       return dws->rx == dws->rx_end;
+       return min(rx_left, (u32)dw_readw(dws, rxflr));
 }
 
-static int u8_writer(struct dw_spi *dws)
+static void dw_writer(struct dw_spi *dws)
 {
-       if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL)
-               || (dws->tx == dws->tx_end))
-               return 0;
+       u32 max = tx_max(dws);
+       u16 txw = 0;
 
-       dw_writew(dws, dr, *(u8 *)(dws->tx));
-       ++dws->tx;
-
-       wait_till_not_busy(dws);
-       return 1;
-}
-
-static int u8_reader(struct dw_spi *dws)
-{
-       while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT)
-               && (dws->rx < dws->rx_end)) {
-               *(u8 *)(dws->rx) = dw_readw(dws, dr);
-               ++dws->rx;
+       while (max--) {
+               /* Set the tx word if the transfer's original "tx" is not null */
+               if (dws->tx_end - dws->len) {
+                       if (dws->n_bytes == 1)
+                               txw = *(u8 *)(dws->tx);
+                       else
+                               txw = *(u16 *)(dws->tx);
+               }
+               dw_writew(dws, dr, txw);
+               dws->tx += dws->n_bytes;
        }
-
-       wait_till_not_busy(dws);
-       return dws->rx == dws->rx_end;
 }
 
-static int u16_writer(struct dw_spi *dws)
+static void dw_reader(struct dw_spi *dws)
 {
-       if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL)
-               || (dws->tx == dws->tx_end))
-               return 0;
+       u32 max = rx_max(dws);
+       u16 rxw;
 
-       dw_writew(dws, dr, *(u16 *)(dws->tx));
-       dws->tx += 2;
-
-       wait_till_not_busy(dws);
-       return 1;
-}
-
-static int u16_reader(struct dw_spi *dws)
-{
-       u16 temp;
-
-       while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT)
-               && (dws->rx < dws->rx_end)) {
-               temp = dw_readw(dws, dr);
-               *(u16 *)(dws->rx) = temp;
-               dws->rx += 2;
+       while (max--) {
+               rxw = dw_readw(dws, dr);
+               /* Care rx only if the transfer's original "rx" is not null */
+               if (dws->rx_end - dws->len) {
+                       if (dws->n_bytes == 1)
+                               *(u8 *)(dws->rx) = rxw;
+                       else
+                               *(u16 *)(dws->rx) = rxw;
+               }
+               dws->rx += dws->n_bytes;
        }
-
-       wait_till_not_busy(dws);
-       return dws->rx == dws->rx_end;
 }
 
 static void *next_transfer(struct dw_spi *dws)
@@ -334,8 +295,7 @@ static void giveback(struct dw_spi *dws)
 
 static void int_error_stop(struct dw_spi *dws, const char *msg)
 {
-       /* Stop and reset hw */
-       flush(dws);
+       /* Stop the hw */
        spi_enable_chip(dws, 0);
 
        dev_err(&dws->master->dev, "%s\n", msg);
@@ -362,35 +322,28 @@ EXPORT_SYMBOL_GPL(dw_spi_xfer_done);
 
 static irqreturn_t interrupt_transfer(struct dw_spi *dws)
 {
-       u16 irq_status, irq_mask = 0x3f;
-       u32 int_level = dws->fifo_len / 2;
-       u32 left;
+       u16 irq_status = dw_readw(dws, isr);
 
-       irq_status = dw_readw(dws, isr) & irq_mask;
        /* Error handling */
        if (irq_status & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI)) {
                dw_readw(dws, txoicr);
                dw_readw(dws, rxoicr);
                dw_readw(dws, rxuicr);
-               int_error_stop(dws, "interrupt_transfer: fifo overrun");
+               int_error_stop(dws, "interrupt_transfer: fifo overrun/underrun");
                return IRQ_HANDLED;
        }
 
+       dw_reader(dws);
+       if (dws->rx_end == dws->rx) {
+               spi_mask_intr(dws, SPI_INT_TXEI);
+               dw_spi_xfer_done(dws);
+               return IRQ_HANDLED;
+       }
        if (irq_status & SPI_INT_TXEI) {
                spi_mask_intr(dws, SPI_INT_TXEI);
-
-               left = (dws->tx_end - dws->tx) / dws->n_bytes;
-               left = (left > int_level) ? int_level : left;
-
-               while (left--)
-                       dws->write(dws);
-               dws->read(dws);
-
-               /* Re-enable the IRQ if there is still data left to tx */
-               if (dws->tx_end > dws->tx)
-                       spi_umask_intr(dws, SPI_INT_TXEI);
-               else
-                       dw_spi_xfer_done(dws);
+               dw_writer(dws);
+               /* Enable TX irq always, it will be disabled when RX finished */
+               spi_umask_intr(dws, SPI_INT_TXEI);
        }
 
        return IRQ_HANDLED;
@@ -399,15 +352,13 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
 static irqreturn_t dw_spi_irq(int irq, void *dev_id)
 {
        struct dw_spi *dws = dev_id;
-       u16 irq_status, irq_mask = 0x3f;
+       u16 irq_status = dw_readw(dws, isr) & 0x3f;
 
-       irq_status = dw_readw(dws, isr) & irq_mask;
        if (!irq_status)
                return IRQ_NONE;
 
        if (!dws->cur_msg) {
                spi_mask_intr(dws, SPI_INT_TXEI);
-               /* Never fail */
                return IRQ_HANDLED;
        }
 
@@ -417,13 +368,11 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id)
 /* Must be called inside pump_transfers() */
 static void poll_transfer(struct dw_spi *dws)
 {
-       while (dws->write(dws))
-               dws->read(dws);
-       /*
-        * There is a possibility that the last word of a transaction
-        * will be lost if data is not ready. Re-read to solve this issue.
-        */
-       dws->read(dws);
+       do {
+               dw_writer(dws);
+               dw_reader(dws);
+               cpu_relax();
+       } while (dws->rx_end > dws->rx);
 
        dw_spi_xfer_done(dws);
 }
@@ -483,8 +432,6 @@ static void pump_transfers(unsigned long data)
        dws->tx_end = dws->tx + transfer->len;
        dws->rx = transfer->rx_buf;
        dws->rx_end = dws->rx + transfer->len;
-       dws->write = dws->tx ? chip->write : null_writer;
-       dws->read = dws->rx ? chip->read : null_reader;
        dws->cs_change = transfer->cs_change;
        dws->len = dws->cur_transfer->len;
        if (chip != dws->prev_chip)
@@ -518,20 +465,8 @@ static void pump_transfers(unsigned long data)
 
                switch (bits) {
                case 8:
-                       dws->n_bytes = 1;
-                       dws->dma_width = 1;
-                       dws->read = (dws->read != null_reader) ?
-                                       u8_reader : null_reader;
-                       dws->write = (dws->write != null_writer) ?
-                                       u8_writer : null_writer;
-                       break;
                case 16:
-                       dws->n_bytes = 2;
-                       dws->dma_width = 2;
-                       dws->read = (dws->read != null_reader) ?
-                                       u16_reader : null_reader;
-                       dws->write = (dws->write != null_writer) ?
-                                       u16_writer : null_writer;
+                       dws->n_bytes = dws->dma_width = bits >> 3;
                        break;
                default:
                        printk(KERN_ERR "MRST SPI0: unsupported bits:"
@@ -575,7 +510,7 @@ static void pump_transfers(unsigned long data)
                txint_level = dws->fifo_len / 2;
                txint_level = (templen > txint_level) ? txint_level : templen;
 
-               imask |= SPI_INT_TXEI;
+               imask |= SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI;
                dws->transfer_handler = interrupt_transfer;
        }
 
@@ -733,13 +668,9 @@ static int dw_spi_setup(struct spi_device *spi)
        if (spi->bits_per_word <= 8) {
                chip->n_bytes = 1;
                chip->dma_width = 1;
-               chip->read = u8_reader;
-               chip->write = u8_writer;
        } else if (spi->bits_per_word <= 16) {
                chip->n_bytes = 2;
                chip->dma_width = 2;
-               chip->read = u16_reader;
-               chip->write = u16_writer;
        } else {
                /* Never take >16b case for MRST SPIC */
                dev_err(&spi->dev, "invalid wordsize\n");
@@ -851,7 +782,6 @@ static void spi_hw_init(struct dw_spi *dws)
        spi_enable_chip(dws, 0);
        spi_mask_intr(dws, 0xff);
        spi_enable_chip(dws, 1);
-       flush(dws);
 
        /*
         * Try to detect the FIFO depth if not set by interface driver,
index b23e452adaf7d94cb09f255e5c745fdd0627500c..7a5e78d2a5cb98c1de9c04fbde849885e643dd4e 100644 (file)
@@ -137,8 +137,6 @@ struct dw_spi {
        u8                      max_bits_per_word;      /* maxim is 16b */
        u32                     dma_width;
        int                     cs_change;
-       int                     (*write)(struct dw_spi *dws);
-       int                     (*read)(struct dw_spi *dws);
        irqreturn_t             (*transfer_handler)(struct dw_spi *dws);
        void                    (*cs_control)(u32 command);
 
index 6f86ba0175ac9636e564f44cf23ff41223de6b8a..969cdd2fe124602d1e65c4218190ed3e7d78ccf6 100644 (file)
@@ -298,7 +298,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
        unsigned int            count, c;
        unsigned long           base, tx_reg, rx_reg;
        int                     word_len, data_type, element_count;
-       int                     elements;
+       int                     elements = 0;
        u32                     l;
        u8                      * rx;
        const u8                * tx;
index 82b9a428c323eab0a0ea2fa4d8f033ba67025ee5..2e13a14bba3fdd62a3ded1711de7dc75fe785dfc 100644 (file)
@@ -1047,8 +1047,8 @@ static u8 *buf;
  * spi_{async,sync}() calls with dma-safe buffers.
  */
 int spi_write_then_read(struct spi_device *spi,
-               const u8 *txbuf, unsigned n_tx,
-               u8 *rxbuf, unsigned n_rx)
+               const void *txbuf, unsigned n_tx,
+               void *rxbuf, unsigned n_rx)
 {
        static DEFINE_MUTEX(lock);
 
index f706dba165cf6812fc364271d3086424ce12aa36..cc880c95e7de7dfee978319ebfb7aecd74a4f355 100644 (file)
@@ -681,13 +681,14 @@ static void bfin_spi_pump_transfers(unsigned long data)
        drv_data->cs_change = transfer->cs_change;
 
        /* Bits per word setup */
-       bits_per_word = transfer->bits_per_word ? : message->spi->bits_per_word;
-       if ((bits_per_word > 0) && (bits_per_word % 16 == 0)) {
+       bits_per_word = transfer->bits_per_word ? :
+               message->spi->bits_per_word ? : 8;
+       if (bits_per_word % 16 == 0) {
                drv_data->n_bytes = bits_per_word/8;
                drv_data->len = (transfer->len) >> 1;
                cr_width = BIT_CTL_WORDSIZE;
                drv_data->ops = &bfin_bfin_spi_transfer_ops_u16;
-       } else if ((bits_per_word > 0) && (bits_per_word % 8 == 0)) {
+       } else if (bits_per_word % 8 == 0) {
                drv_data->n_bytes = bits_per_word/8;
                drv_data->len = transfer->len;
                cr_width = 0;
diff --git a/drivers/spi/spi_bfin_sport.c b/drivers/spi/spi_bfin_sport.c
new file mode 100644 (file)
index 0000000..e557ff6
--- /dev/null
@@ -0,0 +1,952 @@
+/*
+ * SPI bus via the Blackfin SPORT peripheral
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright 2009-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/workqueue.h>
+
+#include <asm/portmux.h>
+#include <asm/bfin5xx_spi.h>
+#include <asm/blackfin.h>
+#include <asm/bfin_sport.h>
+#include <asm/cacheflush.h>
+
+#define DRV_NAME       "bfin-sport-spi"
+#define DRV_DESC       "SPI bus via the Blackfin SPORT"
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:bfin-sport-spi");
+
+enum bfin_sport_spi_state {
+       START_STATE,
+       RUNNING_STATE,
+       DONE_STATE,
+       ERROR_STATE,
+};
+
+struct bfin_sport_spi_master_data;
+
+struct bfin_sport_transfer_ops {
+       void (*write) (struct bfin_sport_spi_master_data *);
+       void (*read) (struct bfin_sport_spi_master_data *);
+       void (*duplex) (struct bfin_sport_spi_master_data *);
+};
+
+struct bfin_sport_spi_master_data {
+       /* Driver model hookup */
+       struct device *dev;
+
+       /* SPI framework hookup */
+       struct spi_master *master;
+
+       /* Regs base of SPI controller */
+       struct sport_register __iomem *regs;
+       int err_irq;
+
+       /* Pin request list */
+       u16 *pin_req;
+
+       /* Driver message queue */
+       struct workqueue_struct *workqueue;
+       struct work_struct pump_messages;
+       spinlock_t lock;
+       struct list_head queue;
+       int busy;
+       bool run;
+
+       /* Message Transfer pump */
+       struct tasklet_struct pump_transfers;
+
+       /* Current message transfer state info */
+       enum bfin_sport_spi_state state;
+       struct spi_message *cur_msg;
+       struct spi_transfer *cur_transfer;
+       struct bfin_sport_spi_slave_data *cur_chip;
+       union {
+               void *tx;
+               u8 *tx8;
+               u16 *tx16;
+       };
+       void *tx_end;
+       union {
+               void *rx;
+               u8 *rx8;
+               u16 *rx16;
+       };
+       void *rx_end;
+
+       int cs_change;
+       struct bfin_sport_transfer_ops *ops;
+};
+
+struct bfin_sport_spi_slave_data {
+       u16 ctl_reg;
+       u16 baud;
+       u16 cs_chg_udelay;      /* Some devices require > 255usec delay */
+       u32 cs_gpio;
+       u16 idle_tx_val;
+       struct bfin_sport_transfer_ops *ops;
+};
+
+static void
+bfin_sport_spi_enable(struct bfin_sport_spi_master_data *drv_data)
+{
+       bfin_write_or(&drv_data->regs->tcr1, TSPEN);
+       bfin_write_or(&drv_data->regs->rcr1, TSPEN);
+       SSYNC();
+}
+
+static void
+bfin_sport_spi_disable(struct bfin_sport_spi_master_data *drv_data)
+{
+       bfin_write_and(&drv_data->regs->tcr1, ~TSPEN);
+       bfin_write_and(&drv_data->regs->rcr1, ~TSPEN);
+       SSYNC();
+}
+
+/* Caculate the SPI_BAUD register value based on input HZ */
+static u16
+bfin_sport_hz_to_spi_baud(u32 speed_hz)
+{
+       u_long clk, sclk = get_sclk();
+       int div = (sclk / (2 * speed_hz)) - 1;
+
+       if (div < 0)
+               div = 0;
+
+       clk = sclk / (2 * (div + 1));
+
+       if (clk > speed_hz)
+               div++;
+
+       return div;
+}
+
+/* Chip select operation functions for cs_change flag */
+static void
+bfin_sport_spi_cs_active(struct bfin_sport_spi_slave_data *chip)
+{
+       gpio_direction_output(chip->cs_gpio, 0);
+}
+
+static void
+bfin_sport_spi_cs_deactive(struct bfin_sport_spi_slave_data *chip)
+{
+       gpio_direction_output(chip->cs_gpio, 1);
+       /* Move delay here for consistency */
+       if (chip->cs_chg_udelay)
+               udelay(chip->cs_chg_udelay);
+}
+
+static void
+bfin_sport_spi_stat_poll_complete(struct bfin_sport_spi_master_data *drv_data)
+{
+       unsigned long timeout = jiffies + HZ;
+       while (!(bfin_read(&drv_data->regs->stat) & RXNE)) {
+               if (!time_before(jiffies, timeout))
+                       break;
+       }
+}
+
+static void
+bfin_sport_spi_u8_writer(struct bfin_sport_spi_master_data *drv_data)
+{
+       u16 dummy;
+
+       while (drv_data->tx < drv_data->tx_end) {
+               bfin_write(&drv_data->regs->tx16, *drv_data->tx8++);
+               bfin_sport_spi_stat_poll_complete(drv_data);
+               dummy = bfin_read(&drv_data->regs->rx16);
+       }
+}
+
+static void
+bfin_sport_spi_u8_reader(struct bfin_sport_spi_master_data *drv_data)
+{
+       u16 tx_val = drv_data->cur_chip->idle_tx_val;
+
+       while (drv_data->rx < drv_data->rx_end) {
+               bfin_write(&drv_data->regs->tx16, tx_val);
+               bfin_sport_spi_stat_poll_complete(drv_data);
+               *drv_data->rx8++ = bfin_read(&drv_data->regs->rx16);
+       }
+}
+
+static void
+bfin_sport_spi_u8_duplex(struct bfin_sport_spi_master_data *drv_data)
+{
+       while (drv_data->rx < drv_data->rx_end) {
+               bfin_write(&drv_data->regs->tx16, *drv_data->tx8++);
+               bfin_sport_spi_stat_poll_complete(drv_data);
+               *drv_data->rx8++ = bfin_read(&drv_data->regs->rx16);
+       }
+}
+
+static struct bfin_sport_transfer_ops bfin_sport_transfer_ops_u8 = {
+       .write  = bfin_sport_spi_u8_writer,
+       .read   = bfin_sport_spi_u8_reader,
+       .duplex = bfin_sport_spi_u8_duplex,
+};
+
+static void
+bfin_sport_spi_u16_writer(struct bfin_sport_spi_master_data *drv_data)
+{
+       u16 dummy;
+
+       while (drv_data->tx < drv_data->tx_end) {
+               bfin_write(&drv_data->regs->tx16, *drv_data->tx16++);
+               bfin_sport_spi_stat_poll_complete(drv_data);
+               dummy = bfin_read(&drv_data->regs->rx16);
+       }
+}
+
+static void
+bfin_sport_spi_u16_reader(struct bfin_sport_spi_master_data *drv_data)
+{
+       u16 tx_val = drv_data->cur_chip->idle_tx_val;
+
+       while (drv_data->rx < drv_data->rx_end) {
+               bfin_write(&drv_data->regs->tx16, tx_val);
+               bfin_sport_spi_stat_poll_complete(drv_data);
+               *drv_data->rx16++ = bfin_read(&drv_data->regs->rx16);
+       }
+}
+
+static void
+bfin_sport_spi_u16_duplex(struct bfin_sport_spi_master_data *drv_data)
+{
+       while (drv_data->rx < drv_data->rx_end) {
+               bfin_write(&drv_data->regs->tx16, *drv_data->tx16++);
+               bfin_sport_spi_stat_poll_complete(drv_data);
+               *drv_data->rx16++ = bfin_read(&drv_data->regs->rx16);
+       }
+}
+
+static struct bfin_sport_transfer_ops bfin_sport_transfer_ops_u16 = {
+       .write  = bfin_sport_spi_u16_writer,
+       .read   = bfin_sport_spi_u16_reader,
+       .duplex = bfin_sport_spi_u16_duplex,
+};
+
+/* stop controller and re-config current chip */
+static void
+bfin_sport_spi_restore_state(struct bfin_sport_spi_master_data *drv_data)
+{
+       struct bfin_sport_spi_slave_data *chip = drv_data->cur_chip;
+       unsigned int bits = (drv_data->ops == &bfin_sport_transfer_ops_u8 ? 7 : 15);
+
+       bfin_sport_spi_disable(drv_data);
+       dev_dbg(drv_data->dev, "restoring spi ctl state\n");
+
+       bfin_write(&drv_data->regs->tcr1, chip->ctl_reg);
+       bfin_write(&drv_data->regs->tcr2, bits);
+       bfin_write(&drv_data->regs->tclkdiv, chip->baud);
+       bfin_write(&drv_data->regs->tfsdiv, bits);
+       SSYNC();
+
+       bfin_write(&drv_data->regs->rcr1, chip->ctl_reg & ~(ITCLK | ITFS));
+       bfin_write(&drv_data->regs->rcr2, bits);
+       SSYNC();
+
+       bfin_sport_spi_cs_active(chip);
+}
+
+/* test if there is more transfer to be done */
+static enum bfin_sport_spi_state
+bfin_sport_spi_next_transfer(struct bfin_sport_spi_master_data *drv_data)
+{
+       struct spi_message *msg = drv_data->cur_msg;
+       struct spi_transfer *trans = drv_data->cur_transfer;
+
+       /* Move to next transfer */
+       if (trans->transfer_list.next != &msg->transfers) {
+               drv_data->cur_transfer =
+                   list_entry(trans->transfer_list.next,
+                              struct spi_transfer, transfer_list);
+               return RUNNING_STATE;
+       }
+
+       return DONE_STATE;
+}
+
+/*
+ * caller already set message->status;
+ * dma and pio irqs are blocked give finished message back
+ */
+static void
+bfin_sport_spi_giveback(struct bfin_sport_spi_master_data *drv_data)
+{
+       struct bfin_sport_spi_slave_data *chip = drv_data->cur_chip;
+       unsigned long flags;
+       struct spi_message *msg;
+
+       spin_lock_irqsave(&drv_data->lock, flags);
+       msg = drv_data->cur_msg;
+       drv_data->state = START_STATE;
+       drv_data->cur_msg = NULL;
+       drv_data->cur_transfer = NULL;
+       drv_data->cur_chip = NULL;
+       queue_work(drv_data->workqueue, &drv_data->pump_messages);
+       spin_unlock_irqrestore(&drv_data->lock, flags);
+
+       if (!drv_data->cs_change)
+               bfin_sport_spi_cs_deactive(chip);
+
+       if (msg->complete)
+               msg->complete(msg->context);
+}
+
+static irqreturn_t
+sport_err_handler(int irq, void *dev_id)
+{
+       struct bfin_sport_spi_master_data *drv_data = dev_id;
+       u16 status;
+
+       dev_dbg(drv_data->dev, "%s enter\n", __func__);
+       status = bfin_read(&drv_data->regs->stat) & (TOVF | TUVF | ROVF | RUVF);
+
+       if (status) {
+               bfin_write(&drv_data->regs->stat, status);
+               SSYNC();
+
+               bfin_sport_spi_disable(drv_data);
+               dev_err(drv_data->dev, "status error:%s%s%s%s\n",
+                       status & TOVF ? " TOVF" : "",
+                       status & TUVF ? " TUVF" : "",
+                       status & ROVF ? " ROVF" : "",
+                       status & RUVF ? " RUVF" : "");
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void
+bfin_sport_spi_pump_transfers(unsigned long data)
+{
+       struct bfin_sport_spi_master_data *drv_data = (void *)data;
+       struct spi_message *message = NULL;
+       struct spi_transfer *transfer = NULL;
+       struct spi_transfer *previous = NULL;
+       struct bfin_sport_spi_slave_data *chip = NULL;
+       unsigned int bits_per_word;
+       u32 tranf_success = 1;
+       u32 transfer_speed;
+       u8 full_duplex = 0;
+
+       /* Get current state information */
+       message = drv_data->cur_msg;
+       transfer = drv_data->cur_transfer;
+       chip = drv_data->cur_chip;
+
+       if (transfer->speed_hz)
+               transfer_speed = bfin_sport_hz_to_spi_baud(transfer->speed_hz);
+       else
+               transfer_speed = chip->baud;
+       bfin_write(&drv_data->regs->tclkdiv, transfer_speed);
+       SSYNC();
+
+       /*
+        * if msg is error or done, report it back using complete() callback
+        */
+
+        /* Handle for abort */
+       if (drv_data->state == ERROR_STATE) {
+               dev_dbg(drv_data->dev, "transfer: we've hit an error\n");
+               message->status = -EIO;
+               bfin_sport_spi_giveback(drv_data);
+               return;
+       }
+
+       /* Handle end of message */
+       if (drv_data->state == DONE_STATE) {
+               dev_dbg(drv_data->dev, "transfer: all done!\n");
+               message->status = 0;
+               bfin_sport_spi_giveback(drv_data);
+               return;
+       }
+
+       /* Delay if requested at end of transfer */
+       if (drv_data->state == RUNNING_STATE) {
+               dev_dbg(drv_data->dev, "transfer: still running ...\n");
+               previous = list_entry(transfer->transfer_list.prev,
+                                     struct spi_transfer, transfer_list);
+               if (previous->delay_usecs)
+                       udelay(previous->delay_usecs);
+       }
+
+       if (transfer->len == 0) {
+               /* Move to next transfer of this msg */
+               drv_data->state = bfin_sport_spi_next_transfer(drv_data);
+               /* Schedule next transfer tasklet */
+               tasklet_schedule(&drv_data->pump_transfers);
+       }
+
+       if (transfer->tx_buf != NULL) {
+               drv_data->tx = (void *)transfer->tx_buf;
+               drv_data->tx_end = drv_data->tx + transfer->len;
+               dev_dbg(drv_data->dev, "tx_buf is %p, tx_end is %p\n",
+                       transfer->tx_buf, drv_data->tx_end);
+       } else
+               drv_data->tx = NULL;
+
+       if (transfer->rx_buf != NULL) {
+               full_duplex = transfer->tx_buf != NULL;
+               drv_data->rx = transfer->rx_buf;
+               drv_data->rx_end = drv_data->rx + transfer->len;
+               dev_dbg(drv_data->dev, "rx_buf is %p, rx_end is %p\n",
+                       transfer->rx_buf, drv_data->rx_end);
+       } else
+               drv_data->rx = NULL;
+
+       drv_data->cs_change = transfer->cs_change;
+
+       /* Bits per word setup */
+       bits_per_word = transfer->bits_per_word ? : message->spi->bits_per_word;
+       if (bits_per_word == 8)
+               drv_data->ops = &bfin_sport_transfer_ops_u8;
+       else
+               drv_data->ops = &bfin_sport_transfer_ops_u16;
+
+       drv_data->state = RUNNING_STATE;
+
+       if (drv_data->cs_change)
+               bfin_sport_spi_cs_active(chip);
+
+       dev_dbg(drv_data->dev,
+               "now pumping a transfer: width is %d, len is %d\n",
+               bits_per_word, transfer->len);
+
+       /* PIO mode write then read */
+       dev_dbg(drv_data->dev, "doing IO transfer\n");
+
+       bfin_sport_spi_enable(drv_data);
+       if (full_duplex) {
+               /* full duplex mode */
+               BUG_ON((drv_data->tx_end - drv_data->tx) !=
+                      (drv_data->rx_end - drv_data->rx));
+               drv_data->ops->duplex(drv_data);
+
+               if (drv_data->tx != drv_data->tx_end)
+                       tranf_success = 0;
+       } else if (drv_data->tx != NULL) {
+               /* write only half duplex */
+
+               drv_data->ops->write(drv_data);
+
+               if (drv_data->tx != drv_data->tx_end)
+                       tranf_success = 0;
+       } else if (drv_data->rx != NULL) {
+               /* read only half duplex */
+
+               drv_data->ops->read(drv_data);
+               if (drv_data->rx != drv_data->rx_end)
+                       tranf_success = 0;
+       }
+       bfin_sport_spi_disable(drv_data);
+
+       if (!tranf_success) {
+               dev_dbg(drv_data->dev, "IO write error!\n");
+               drv_data->state = ERROR_STATE;
+       } else {
+               /* Update total byte transfered */
+               message->actual_length += transfer->len;
+               /* Move to next transfer of this msg */
+               drv_data->state = bfin_sport_spi_next_transfer(drv_data);
+               if (drv_data->cs_change)
+                       bfin_sport_spi_cs_deactive(chip);
+       }
+
+       /* Schedule next transfer tasklet */
+       tasklet_schedule(&drv_data->pump_transfers);
+}
+
+/* pop a msg from queue and kick off real transfer */
+static void
+bfin_sport_spi_pump_messages(struct work_struct *work)
+{
+       struct bfin_sport_spi_master_data *drv_data;
+       unsigned long flags;
+       struct spi_message *next_msg;
+
+       drv_data = container_of(work, struct bfin_sport_spi_master_data, pump_messages);
+
+       /* Lock queue and check for queue work */
+       spin_lock_irqsave(&drv_data->lock, flags);
+       if (list_empty(&drv_data->queue) || !drv_data->run) {
+               /* pumper kicked off but no work to do */
+               drv_data->busy = 0;
+               spin_unlock_irqrestore(&drv_data->lock, flags);
+               return;
+       }
+
+       /* Make sure we are not already running a message */
+       if (drv_data->cur_msg) {
+               spin_unlock_irqrestore(&drv_data->lock, flags);
+               return;
+       }
+
+       /* Extract head of queue */
+       next_msg = list_entry(drv_data->queue.next,
+               struct spi_message, queue);
+
+       drv_data->cur_msg = next_msg;
+
+       /* Setup the SSP using the per chip configuration */
+       drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
+
+       list_del_init(&drv_data->cur_msg->queue);
+
+       /* Initialize message state */
+       drv_data->cur_msg->state = START_STATE;
+       drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
+                                           struct spi_transfer, transfer_list);
+       bfin_sport_spi_restore_state(drv_data);
+       dev_dbg(drv_data->dev, "got a message to pump, "
+               "state is set to: baud %d, cs_gpio %i, ctl 0x%x\n",
+               drv_data->cur_chip->baud, drv_data->cur_chip->cs_gpio,
+               drv_data->cur_chip->ctl_reg);
+
+       dev_dbg(drv_data->dev,
+               "the first transfer len is %d\n",
+               drv_data->cur_transfer->len);
+
+       /* Mark as busy and launch transfers */
+       tasklet_schedule(&drv_data->pump_transfers);
+
+       drv_data->busy = 1;
+       spin_unlock_irqrestore(&drv_data->lock, flags);
+}
+
+/*
+ * got a msg to transfer, queue it in drv_data->queue.
+ * And kick off message pumper
+ */
+static int
+bfin_sport_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+       struct bfin_sport_spi_master_data *drv_data = spi_master_get_devdata(spi->master);
+       unsigned long flags;
+
+       spin_lock_irqsave(&drv_data->lock, flags);
+
+       if (!drv_data->run) {
+               spin_unlock_irqrestore(&drv_data->lock, flags);
+               return -ESHUTDOWN;
+       }
+
+       msg->actual_length = 0;
+       msg->status = -EINPROGRESS;
+       msg->state = START_STATE;
+
+       dev_dbg(&spi->dev, "adding an msg in transfer()\n");
+       list_add_tail(&msg->queue, &drv_data->queue);
+
+       if (drv_data->run && !drv_data->busy)
+               queue_work(drv_data->workqueue, &drv_data->pump_messages);
+
+       spin_unlock_irqrestore(&drv_data->lock, flags);
+
+       return 0;
+}
+
+/* Called every time common spi devices change state */
+static int
+bfin_sport_spi_setup(struct spi_device *spi)
+{
+       struct bfin_sport_spi_slave_data *chip, *first = NULL;
+       int ret;
+
+       /* Only alloc (or use chip_info) on first setup */
+       chip = spi_get_ctldata(spi);
+       if (chip == NULL) {
+               struct bfin5xx_spi_chip *chip_info;
+
+               chip = first = kzalloc(sizeof(*chip), GFP_KERNEL);
+               if (!chip)
+                       return -ENOMEM;
+
+               /* platform chip_info isn't required */
+               chip_info = spi->controller_data;
+               if (chip_info) {
+                       /*
+                        * DITFS and TDTYPE are only thing we don't set, but
+                        * they probably shouldn't be changed by people.
+                        */
+                       if (chip_info->ctl_reg || chip_info->enable_dma) {
+                               ret = -EINVAL;
+                               dev_err(&spi->dev, "don't set ctl_reg/enable_dma fields");
+                               goto error;
+                       }
+                       chip->cs_chg_udelay = chip_info->cs_chg_udelay;
+                       chip->idle_tx_val = chip_info->idle_tx_val;
+                       spi->bits_per_word = chip_info->bits_per_word;
+               }
+       }
+
+       if (spi->bits_per_word != 8 && spi->bits_per_word != 16) {
+               ret = -EINVAL;
+               goto error;
+       }
+
+       /* translate common spi framework into our register
+        * following configure contents are same for tx and rx.
+        */
+
+       if (spi->mode & SPI_CPHA)
+               chip->ctl_reg &= ~TCKFE;
+       else
+               chip->ctl_reg |= TCKFE;
+
+       if (spi->mode & SPI_LSB_FIRST)
+               chip->ctl_reg |= TLSBIT;
+       else
+               chip->ctl_reg &= ~TLSBIT;
+
+       /* Sport in master mode */
+       chip->ctl_reg |= ITCLK | ITFS | TFSR | LATFS | LTFS;
+
+       chip->baud = bfin_sport_hz_to_spi_baud(spi->max_speed_hz);
+
+       chip->cs_gpio = spi->chip_select;
+       ret = gpio_request(chip->cs_gpio, spi->modalias);
+       if (ret)
+               goto error;
+
+       dev_dbg(&spi->dev, "setup spi chip %s, width is %d\n",
+                       spi->modalias, spi->bits_per_word);
+       dev_dbg(&spi->dev, "ctl_reg is 0x%x, GPIO is %i\n",
+                       chip->ctl_reg, spi->chip_select);
+
+       spi_set_ctldata(spi, chip);
+
+       bfin_sport_spi_cs_deactive(chip);
+
+       return ret;
+
+ error:
+       kfree(first);
+       return ret;
+}
+
+/*
+ * callback for spi framework.
+ * clean driver specific data
+ */
+static void
+bfin_sport_spi_cleanup(struct spi_device *spi)
+{
+       struct bfin_sport_spi_slave_data *chip = spi_get_ctldata(spi);
+
+       if (!chip)
+               return;
+
+       gpio_free(chip->cs_gpio);
+
+       kfree(chip);
+}
+
+static int
+bfin_sport_spi_init_queue(struct bfin_sport_spi_master_data *drv_data)
+{
+       INIT_LIST_HEAD(&drv_data->queue);
+       spin_lock_init(&drv_data->lock);
+
+       drv_data->run = false;
+       drv_data->busy = 0;
+
+       /* init transfer tasklet */
+       tasklet_init(&drv_data->pump_transfers,
+                    bfin_sport_spi_pump_transfers, (unsigned long)drv_data);
+
+       /* init messages workqueue */
+       INIT_WORK(&drv_data->pump_messages, bfin_sport_spi_pump_messages);
+       drv_data->workqueue =
+           create_singlethread_workqueue(dev_name(drv_data->master->dev.parent));
+       if (drv_data->workqueue == NULL)
+               return -EBUSY;
+
+       return 0;
+}
+
+static int
+bfin_sport_spi_start_queue(struct bfin_sport_spi_master_data *drv_data)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&drv_data->lock, flags);
+
+       if (drv_data->run || drv_data->busy) {
+               spin_unlock_irqrestore(&drv_data->lock, flags);
+               return -EBUSY;
+       }
+
+       drv_data->run = true;
+       drv_data->cur_msg = NULL;
+       drv_data->cur_transfer = NULL;
+       drv_data->cur_chip = NULL;
+       spin_unlock_irqrestore(&drv_data->lock, flags);
+
+       queue_work(drv_data->workqueue, &drv_data->pump_messages);
+
+       return 0;
+}
+
+static inline int
+bfin_sport_spi_stop_queue(struct bfin_sport_spi_master_data *drv_data)
+{
+       unsigned long flags;
+       unsigned limit = 500;
+       int status = 0;
+
+       spin_lock_irqsave(&drv_data->lock, flags);
+
+       /*
+        * This is a bit lame, but is optimized for the common execution path.
+        * A wait_queue on the drv_data->busy could be used, but then the common
+        * execution path (pump_messages) would be required to call wake_up or
+        * friends on every SPI message. Do this instead
+        */
+       drv_data->run = false;
+       while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) {
+               spin_unlock_irqrestore(&drv_data->lock, flags);
+               msleep(10);
+               spin_lock_irqsave(&drv_data->lock, flags);
+       }
+
+       if (!list_empty(&drv_data->queue) || drv_data->busy)
+               status = -EBUSY;
+
+       spin_unlock_irqrestore(&drv_data->lock, flags);
+
+       return status;
+}
+
+static inline int
+bfin_sport_spi_destroy_queue(struct bfin_sport_spi_master_data *drv_data)
+{
+       int status;
+
+       status = bfin_sport_spi_stop_queue(drv_data);
+       if (status)
+               return status;
+
+       destroy_workqueue(drv_data->workqueue);
+
+       return 0;
+}
+
+static int __devinit
+bfin_sport_spi_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct bfin5xx_spi_master *platform_info;
+       struct spi_master *master;
+       struct resource *res, *ires;
+       struct bfin_sport_spi_master_data *drv_data;
+       int status;
+
+       platform_info = dev->platform_data;
+
+       /* Allocate master with space for drv_data */
+       master = spi_alloc_master(dev, sizeof(*master) + 16);
+       if (!master) {
+               dev_err(dev, "cannot alloc spi_master\n");
+               return -ENOMEM;
+       }
+
+       drv_data = spi_master_get_devdata(master);
+       drv_data->master = master;
+       drv_data->dev = dev;
+       drv_data->pin_req = platform_info->pin_req;
+
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+       master->bus_num = pdev->id;
+       master->num_chipselect = platform_info->num_chipselect;
+       master->cleanup = bfin_sport_spi_cleanup;
+       master->setup = bfin_sport_spi_setup;
+       master->transfer = bfin_sport_spi_transfer;
+
+       /* Find and map our resources */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(dev, "cannot get IORESOURCE_MEM\n");
+               status = -ENOENT;
+               goto out_error_get_res;
+       }
+
+       drv_data->regs = ioremap(res->start, resource_size(res));
+       if (drv_data->regs == NULL) {
+               dev_err(dev, "cannot map registers\n");
+               status = -ENXIO;
+               goto out_error_ioremap;
+       }
+
+       ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!ires) {
+               dev_err(dev, "cannot get IORESOURCE_IRQ\n");
+               status = -ENODEV;
+               goto out_error_get_ires;
+       }
+       drv_data->err_irq = ires->start;
+
+       /* Initial and start queue */
+       status = bfin_sport_spi_init_queue(drv_data);
+       if (status) {
+               dev_err(dev, "problem initializing queue\n");
+               goto out_error_queue_alloc;
+       }
+
+       status = bfin_sport_spi_start_queue(drv_data);
+       if (status) {
+               dev_err(dev, "problem starting queue\n");
+               goto out_error_queue_alloc;
+       }
+
+       status = request_irq(drv_data->err_irq, sport_err_handler,
+               0, "sport_spi_err", drv_data);
+       if (status) {
+               dev_err(dev, "unable to request sport err irq\n");
+               goto out_error_irq;
+       }
+
+       status = peripheral_request_list(drv_data->pin_req, DRV_NAME);
+       if (status) {
+               dev_err(dev, "requesting peripherals failed\n");
+               goto out_error_peripheral;
+       }
+
+       /* Register with the SPI framework */
+       platform_set_drvdata(pdev, drv_data);
+       status = spi_register_master(master);
+       if (status) {
+               dev_err(dev, "problem registering spi master\n");
+               goto out_error_master;
+       }
+
+       dev_info(dev, "%s, regs_base@%p\n", DRV_DESC, drv_data->regs);
+       return 0;
+
+ out_error_master:
+       peripheral_free_list(drv_data->pin_req);
+ out_error_peripheral:
+       free_irq(drv_data->err_irq, drv_data);
+ out_error_irq:
+ out_error_queue_alloc:
+       bfin_sport_spi_destroy_queue(drv_data);
+ out_error_get_ires:
+       iounmap(drv_data->regs);
+ out_error_ioremap:
+ out_error_get_res:
+       spi_master_put(master);
+
+       return status;
+}
+
+/* stop hardware and remove the driver */
+static int __devexit
+bfin_sport_spi_remove(struct platform_device *pdev)
+{
+       struct bfin_sport_spi_master_data *drv_data = platform_get_drvdata(pdev);
+       int status = 0;
+
+       if (!drv_data)
+               return 0;
+
+       /* Remove the queue */
+       status = bfin_sport_spi_destroy_queue(drv_data);
+       if (status)
+               return status;
+
+       /* Disable the SSP at the peripheral and SOC level */
+       bfin_sport_spi_disable(drv_data);
+
+       /* Disconnect from the SPI framework */
+       spi_unregister_master(drv_data->master);
+
+       peripheral_free_list(drv_data->pin_req);
+
+       /* Prevent double remove */
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int
+bfin_sport_spi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct bfin_sport_spi_master_data *drv_data = platform_get_drvdata(pdev);
+       int status;
+
+       status = bfin_sport_spi_stop_queue(drv_data);
+       if (status)
+               return status;
+
+       /* stop hardware */
+       bfin_sport_spi_disable(drv_data);
+
+       return status;
+}
+
+static int
+bfin_sport_spi_resume(struct platform_device *pdev)
+{
+       struct bfin_sport_spi_master_data *drv_data = platform_get_drvdata(pdev);
+       int status;
+
+       /* Enable the SPI interface */
+       bfin_sport_spi_enable(drv_data);
+
+       /* Start the queue running */
+       status = bfin_sport_spi_start_queue(drv_data);
+       if (status)
+               dev_err(drv_data->dev, "problem resuming queue\n");
+
+       return status;
+}
+#else
+# define bfin_sport_spi_suspend NULL
+# define bfin_sport_spi_resume  NULL
+#endif
+
+static struct platform_driver bfin_sport_spi_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe   = bfin_sport_spi_probe,
+       .remove  = __devexit_p(bfin_sport_spi_remove),
+       .suspend = bfin_sport_spi_suspend,
+       .resume  = bfin_sport_spi_resume,
+};
+
+static int __init bfin_sport_spi_init(void)
+{
+       return platform_driver_register(&bfin_sport_spi_driver);
+}
+module_init(bfin_sport_spi_init);
+
+static void __exit bfin_sport_spi_exit(void)
+{
+       platform_driver_unregister(&bfin_sport_spi_driver);
+}
+module_exit(bfin_sport_spi_exit);
index d5be18b3078c4e3440c45d1bd3fed1b66fc44491..3cd15f690f1667fcb8e274f74375ab7d28676599 100644 (file)
@@ -463,7 +463,7 @@ static int __devexit nuc900_spi_remove(struct platform_device *dev)
 
        platform_set_drvdata(dev, NULL);
 
-       spi_unregister_master(hw->master);
+       spi_bitbang_stop(&hw->bitbang);
 
        clk_disable(hw->clk);
        clk_put(hw->clk);
index 151a95e40653e8908e362968212abd182aeaa5ae..1a5fcabfd56502ad47786c41f219240d165e2589 100644 (file)
@@ -668,7 +668,7 @@ static int __exit s3c24xx_spi_remove(struct platform_device *dev)
 
        platform_set_drvdata(dev, NULL);
 
-       spi_unregister_master(hw->master);
+       spi_bitbang_stop(&hw->bitbang);
 
        clk_disable(hw->clk);
        clk_put(hw->clk);
index 869a07d375d6171e175e6eff5de1996acd29357a..9eedd71ad898c172f3bf34c57909530f55b91e19 100644 (file)
@@ -427,10 +427,10 @@ static int __devexit spi_sh_remove(struct platform_device *pdev)
 {
        struct spi_sh_data *ss = dev_get_drvdata(&pdev->dev);
 
+       spi_unregister_master(ss->master);
        destroy_workqueue(ss->workqueue);
        free_irq(ss->irq, ss);
        iounmap(ss->addr);
-       spi_master_put(ss->master);
 
        return 0;
 }
index 891e5909038c4e4dd20bd956b33dca8e317630ac..6c3aa6ecaade10fbf04fa7be2d29478977774cde 100644 (file)
@@ -578,6 +578,7 @@ static int __devexit spi_tegra_remove(struct platform_device *pdev)
        master = dev_get_drvdata(&pdev->dev);
        tspi = spi_master_get_devdata(master);
 
+       spi_unregister_master(master);
        tegra_dma_free_channel(tspi->rx_dma);
 
        dma_free_coherent(&pdev->dev, sizeof(u32) * BB_LEN,
@@ -586,7 +587,6 @@ static int __devexit spi_tegra_remove(struct platform_device *pdev)
        clk_put(tspi->clk);
        iounmap(tspi->base);
 
-       spi_master_put(master);
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(r->start, (r->end - r->start) + 1);
 
index a3938958147c887ecbf803c6c806d668735b62de..32a40876532fc499933bbf7fd1ac602f7228fd30 100644 (file)
@@ -283,7 +283,7 @@ static int __devinit tle62x0_probe(struct spi_device *spi)
        return 0;
 
  err_gpios:
-       for (; ptr > 0; ptr--)
+       while (--ptr >= 0)
                device_remove_file(&spi->dev, gpio_attrs[ptr]);
 
        device_remove_file(&spi->dev, &dev_attr_status_show);
@@ -301,6 +301,7 @@ static int __devexit tle62x0_remove(struct spi_device *spi)
        for (ptr = 0; ptr < st->nr_gpio; ptr++)
                device_remove_file(&spi->dev, gpio_attrs[ptr]);
 
+       device_remove_file(&spi->dev, &dev_attr_status_show);
        kfree(st);
        return 0;
 }
index c69c6f2c2c5ceeadae69afa2efc60c636517a0e3..4d2c75df886c88621e43a453db625e59e7876ccf 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/interrupt.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
 #include <linux/spi/xilinx_spi.h>
@@ -471,7 +470,7 @@ static int __devinit xilinx_spi_probe(struct platform_device *dev)
        struct spi_master *master;
        u8 i;
 
-       pdata = mfd_get_data(dev);
+       pdata = dev->dev.platform_data;
        if (pdata) {
                num_cs = pdata->num_chipselect;
                little_endian = pdata->little_endian;
index 82feb348c8bbf3762195aaf2cf07668792f72721..2a20dabec76d722d1c311aad9e1e34a13382b6d2 100644 (file)
@@ -539,10 +539,12 @@ void ssb_pcicore_init(struct ssb_pcicore *pc)
        if (!pc->hostmode)
                ssb_pcicore_init_clientmode(pc);
 
-       /* Additional always once-executed workarounds */
-       ssb_pcicore_serdes_workaround(pc);
-       /* TODO: ASPM */
-       /* TODO: Clock Request Update */
+       /* Additional PCIe always once-executed workarounds */
+       if (dev->id.coreid == SSB_DEV_PCIE) {
+               ssb_pcicore_serdes_workaround(pc);
+               /* TODO: ASPM */
+               /* TODO: Clock Request Update */
+       }
 }
 
 static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address)
index dfc16f955eb882765aef90c63003d01ce95927f9..196284dc2f36615520aff66bf8174625e2c4da44 100644 (file)
@@ -24,23 +24,6 @@ menuconfig STAGING
 
 if STAGING
 
-config STAGING_EXCLUDE_BUILD
-       bool "Exclude Staging drivers from being built" if STAGING
-       default y
-       ---help---
-         Are you sure you really want to build the staging drivers?
-         They taint your kernel, don't live up to the normal Linux
-         kernel quality standards, are a bit crufty around the edges,
-         and might go off and kick your dog when you aren't paying
-         attention.
-
-         Say N here to be able to select and build the Staging drivers.
-         This option is primarily here to prevent them from being built
-         when selecting 'make allyesconfg' and 'make allmodconfig' so
-         don't be all that put off, your dog will be just fine.
-
-if !STAGING_EXCLUDE_BUILD
-
 source "drivers/staging/tty/Kconfig"
 
 source "drivers/staging/generic_serial/Kconfig"
@@ -177,5 +160,4 @@ source "drivers/staging/mei/Kconfig"
 
 source "drivers/staging/nvec/Kconfig"
 
-endif # !STAGING_EXCLUDE_BUILD
 endif # STAGING
index 876308858b824c706770eda11e4038d1763da24a..8b1620b1b2d0b0f614004726a3814155d039c543 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/delay.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
-#include <staging/altera.h>
+#include "altera.h"
 #include "altera-exprt.h"
 #include "altera-jtag.h"
 
index 05aad351b120c40c7e7ee3bde5d2b622a3fdd441..9cd5e76880c0cfcb5f3cdaedac093f2897c52d87 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/string.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
-#include <staging/altera.h>
+#include "altera.h"
 #include "altera-exprt.h"
 #include "altera-jtag.h"
 
index 1f15e1fb1ab224b6ed0c925463d9e9fed30c0da2..afd6cc16a2b8cf8f3ac8a374e1968a97b2a1db0b 100644 (file)
@@ -1,6 +1,7 @@
 config ATH6K_LEGACY
        tristate "Atheros AR6003 support (non mac80211)"
         depends on MMC && WLAN
+       depends on CFG80211
         select WIRELESS_EXT
         select WEXT_PRIV
        help
index 31d7ba8299e7ab2df701d2d5d04c646140e6ce53..d3a774dbb7e8b3cec2faf25bde0270b0caad8772 100644 (file)
@@ -587,7 +587,7 @@ ar6k_cfg80211_connect_event(struct ar6_softc *ar, u16 channel,
                                 WLAN_STATUS_SUCCESS, GFP_KERNEL);
     } else {
         /* inform roam event to cfg80211 */
-        cfg80211_roamed(ar->arNetDev, bssid,
+       cfg80211_roamed(ar->arNetDev, ibss_channel, bssid,
                         assocReqIe, assocReqLen,
                         assocRespIe, assocRespLen,
                         GFP_KERNEL);
@@ -870,7 +870,8 @@ ar6k_cfg80211_scanComplete_event(struct ar6_softc *ar, int status)
     if(ar->scan_request)
     {
         /* Translate data to cfg80211 mgmt format */
-        wmi_iterate_nodes(ar->arWmi, ar6k_cfg80211_scan_node, ar->wdev->wiphy);
+       if (ar->arWmi)
+               wmi_iterate_nodes(ar->arWmi, ar6k_cfg80211_scan_node, ar->wdev->wiphy);
 
         cfg80211_scan_done(ar->scan_request,
             ((status & A_ECANCELED) || (status & A_EBUSY)) ? true : false);
index e3b409bb9847b708444ae03e88beda648630b5f4..1827b0bf9201e1b868f404172d4cf71ed1b93b59 100644 (file)
@@ -2869,7 +2869,7 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
        wl_update_prof(wl, NULL, &e->addr, WL_PROF_BSSID);
        wl_update_bss_info(wl);
 
-       cfg80211_roamed(ndev,
+       cfg80211_roamed(ndev, NULL,
                        (u8 *)wl_read_prof(wl, WL_PROF_BSSID),
                        conn_info->req_ie, conn_info->req_ie_len,
                        conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
index 929ceaf363bea7df2b8e51a4d114bcb1acaa5ff8..15e1b05ca92d2c835bcd3b16bb7f94ee5b1daab8 100644 (file)
@@ -64,8 +64,6 @@ wl_iw_extra_params_t g_wl_iw_params;
 extern bool wl_iw_conn_status_str(u32 event_type, u32 status,
                                  u32 reason, char *stringBuf, uint buflen);
 
-uint wl_msg_level = WL_ERROR_VAL;
-
 #define MAX_WLIW_IOCTL_LEN 1024
 
 #ifdef CONFIG_WIRELESS_EXT
index bb93685d8b93e9fbf8d9474069aa6945314738cf..8a1b8a7fa15fc67028ed9c089a87a06931e20444 100644 (file)
@@ -772,7 +772,7 @@ static int das16cs_pcmcia_resume(struct pcmcia_device *link)
 
 /*====================================================================*/
 
-static struct pcmcia_device_id das16cs_id_table[] = {
+static const struct pcmcia_device_id das16cs_id_table[] = {
        PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039),
        PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009),
        PCMCIA_DEVICE_NULL
index 0b32a2df776829c497274fd8074b3b34e05d726e..6d91d3028178c5ac61ae9d4e9eaf70f45d9f6924 100644 (file)
@@ -219,7 +219,7 @@ static int das08_pcmcia_resume(struct pcmcia_device *link)
 
 /*====================================================================*/
 
-static struct pcmcia_device_id das08_cs_id_table[] = {
+static const struct pcmcia_device_id das08_cs_id_table[] = {
        PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4001),
        PCMCIA_DEVICE_NULL
 };
index 6b7372eed90d639ecb0d475440be01857b1d9114..2672629e9ff92937bacca4e084b4be642391eeff 100644 (file)
@@ -552,7 +552,7 @@ static int dio700_cs_resume(struct pcmcia_device *link)
 
 /*====================================================================*/
 
-static struct pcmcia_device_id dio700_cs_ids[] = {
+static const struct pcmcia_device_id dio700_cs_ids[] = {
        /* N.B. These IDs should match those in dio700_boards */
        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4743),        /* daqcard-700 */
        PCMCIA_DEVICE_NULL
index c9c28584db67dbc910c0c1882a2e071d6198c2e4..49b824c7bd2eb2820df373a2aa1af3947074a76e 100644 (file)
@@ -304,7 +304,7 @@ static int dio24_cs_resume(struct pcmcia_device *link)
 
 /*====================================================================*/
 
-static struct pcmcia_device_id dio24_cs_ids[] = {
+static const struct pcmcia_device_id dio24_cs_ids[] = {
        /* N.B. These IDs should match those in dio24_boards */
        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x475c),        /* daqcard-dio24 */
        PCMCIA_DEVICE_NULL
index 6facbc8bf77660093b7b504cb65eb08c737589e1..832a5178b638e38c0ceff0335ce7758712c7a16d 100644 (file)
@@ -267,7 +267,7 @@ static int labpc_cs_resume(struct pcmcia_device *link)
        return 0;
 }                              /* labpc_cs_resume */
 
-static struct pcmcia_device_id labpc_cs_ids[] = {
+static const struct pcmcia_device_id labpc_cs_ids[] = {
        /* N.B. These IDs should match those in labpc_cs_boards (ni_labpc.c) */
        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0103),        /* daqcard-1200 */
        PCMCIA_DEVICE_NULL
index 49563273f605c659b05467f25d836d912291b796..53ec24bb6dcec06b7c89610d22d9178873b99467 100644 (file)
@@ -416,7 +416,7 @@ static int ni_getboardtype(struct comedi_device *dev,
 
 #ifdef MODULE
 
-static struct pcmcia_device_id ni_mio_cs_ids[] = {
+static const struct pcmcia_device_id ni_mio_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x010d),        /* DAQCard-ai-16xe-50 */
        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x010c),        /* DAQCard-ai-16e-4 */
        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x02c4),        /* DAQCard-6062E */
index 82942e5728a50cae765ee071ca789fd7b41753c5..e0bb73445dd80daf2ee8a50c48b14ba7a78fc32e 100644 (file)
@@ -1087,7 +1087,7 @@ static int daqp_cs_resume(struct pcmcia_device *link)
 
 #ifdef MODULE
 
-static struct pcmcia_device_id daqp_cs_id_table[] = {
+static const struct pcmcia_device_id daqp_cs_id_table[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0027),
        PCMCIA_DEVICE_NULL
 };
index 10af47700efb19aee2d4b8ec4bf53cf5713bcfd5..68ea035635f48bbcd794e28c4033de2c1050e72b 100644 (file)
@@ -284,7 +284,7 @@ static int ft1000_resume(struct pcmcia_device *link)
 
 /*====================================================================*/
 
-static struct pcmcia_device_id ft1000_ids[] = {
+static const struct pcmcia_device_id ft1000_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x02cc, 0x0100),
        PCMCIA_DEVICE_MANF_CARD(0x02cc, 0x1000),
        PCMCIA_DEVICE_MANF_CARD(0x02cc, 0x1300),
index 24a282bb89d4bd06fa2d0c82dd52333aad112c19..fb62b383f1de32079ef934986398c91052a0b88c 100644 (file)
@@ -381,7 +381,7 @@ struct rioVersion *RIOVersid(void)
 {
     strlcpy(stVersion.version, "RIO driver for linux V1.0",
            sizeof(stVersion.version));
-    strlcpy(stVersion.buildDate, __DATE__,
+    strlcpy(stVersion.buildDate, "Aug 15 2010",
            sizeof(stVersion.buildDate));
 
     return &stVersion;
index 1c45c11a774eaa60921f4ca0d69cec7e7481f8ea..aa87b1b6a44adea18ca675ba7962dcf512dd61f8 100644 (file)
@@ -542,6 +542,8 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
        unsigned long irqflags;
        int ret = -ENOMEM;
        uint32_t tt_pages;
+       struct drm_connector *connector;
+       struct psb_intel_output *psb_intel_output;
 
        dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
        if (dev_priv == NULL)
@@ -663,7 +665,18 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
                drm_kms_helper_poll_init(dev);
        }
 
-       ret = psb_backlight_init(dev);
+       /* Only add backlight support if we have LVDS output */
+       list_for_each_entry(connector, &dev->mode_config.connector_list,
+                           head) {
+               psb_intel_output = to_psb_intel_output(connector);
+
+               switch (psb_intel_output->type) {
+               case INTEL_OUTPUT_LVDS:
+                       ret = psb_backlight_init(dev);
+                       break;
+               }
+       }
+
        if (ret)
                return ret;
 #if 0
index 99c03a2e06bdb32e8a20f579be0f4c975314805c..084c36bbfe86997428b52158dbedaa48c7d69611 100644 (file)
@@ -441,6 +441,16 @@ static int psbfb_create(struct psb_fbdev *fbdev,
        info->screen_size = size;
        memset(info->screen_base, 0, size);
 
+       if (dev_priv->pg->stolen_size) {
+               info->apertures = alloc_apertures(1);
+               if (!info->apertures) {
+                       ret = -ENOMEM;
+                       goto out_err0;
+               }
+               info->apertures->ranges[0].base = dev->mode_config.fb_base;
+               info->apertures->ranges[0].size = dev_priv->pg->stolen_size;
+       }
+
        drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
        drm_fb_helper_fill_var(info, &fbdev->psb_fb_helper,
                                sizes->fb_width, sizes->fb_height);
index 48ac8ba7f40bc41d5e317ec14cf3f897073e0742..417965da5e240002769ad700c3ee4208da4aa529 100644 (file)
@@ -154,10 +154,15 @@ static void parse_lfp_panel_data(struct drm_psb_private *dev_priv,
 
        fill_detail_timing_data(panel_fixed_mode, dvo_timing);
 
-       dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode;
-
-       DRM_DEBUG("Found panel mode in BIOS VBT tables:\n");
-       drm_mode_debug_printmodeline(panel_fixed_mode);
+       if (panel_fixed_mode->htotal > 0 && panel_fixed_mode->vtotal > 0) {
+               dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode;
+               DRM_DEBUG("Found panel mode in BIOS VBT tables:\n");
+               drm_mode_debug_printmodeline(panel_fixed_mode);
+       } else {
+               DRM_DEBUG("Ignoring bogus LVDS VBT mode.\n");
+               dev_priv->lvds_vbt = 0;
+               kfree(panel_fixed_mode);
+       }
 
        return;
 }
index 0b9b85424dfaa1fdbe7b931e6fcf98f68ef9c9bf..4cc1a5bfab40c0705c31beca87757068a7b8487d 100644 (file)
@@ -81,7 +81,6 @@ struct adis16201_state {
 
 int adis16201_set_irq(struct iio_dev *indio_dev, bool enable);
 
-#ifdef CONFIG_IIO_RING_BUFFER
 enum adis16201_scan {
        ADIS16201_SCAN_SUPPLY,
        ADIS16201_SCAN_ACC_X,
@@ -92,6 +91,7 @@ enum adis16201_scan {
        ADIS16201_SCAN_INCLI_Y,
 };
 
+#ifdef CONFIG_IIO_RING_BUFFER
 void adis16201_remove_trigger(struct iio_dev *indio_dev);
 int adis16201_probe_trigger(struct iio_dev *indio_dev);
 
index 8bb8ce50c2483d339f584a2c83ad82c771ee2108..175e21bb9b403d79a0a2810c6730712791a1a62d 100644 (file)
@@ -76,7 +76,6 @@ struct adis16203_state {
 
 int adis16203_set_irq(struct iio_dev *indio_dev, bool enable);
 
-#ifdef CONFIG_IIO_RING_BUFFER
 enum adis16203_scan {
        ADIS16203_SCAN_SUPPLY,
        ADIS16203_SCAN_AUX_ADC,
@@ -85,6 +84,7 @@ enum adis16203_scan {
        ADIS16203_SCAN_INCLI_Y,
 };
 
+#ifdef CONFIG_IIO_RING_BUFFER
 void adis16203_remove_trigger(struct iio_dev *indio_dev);
 int adis16203_probe_trigger(struct iio_dev *indio_dev);
 
index 881768df47a6b813a417dcffe1a3f9cce2ecf898..2fe34d21b6aa2268658d4c6148ad07fa11087747 100644 (file)
@@ -195,7 +195,7 @@ static const struct iio_info max517_info = {
 };
 
 static const struct iio_info max518_info = {
-       .attrs = &max517_attribute_group,
+       .attrs = &max518_attribute_group,
        .driver_module = THIS_MODULE,
 };
 
index 2589a7e167e4e94772fe36e8b215ea904f0873ea..3612373ddede3ff90a642432d260f931c23729f1 100644 (file)
@@ -137,13 +137,13 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p)
                if (st->variant->flags & ADIS16400_NO_BURST) {
                        ret = adis16350_spi_read_all(&indio_dev->dev, st->rx);
                        if (ret < 0)
-                               return ret;
+                               goto err;
                        for (; i < ring->scan_count; i++)
                                data[i] = *(s16 *)(st->rx + i*2);
                } else {
                        ret = adis16400_spi_read_burst(&indio_dev->dev, st->rx);
                        if (ret < 0)
-                               return ret;
+                               goto err;
                        for (; i < indio_dev->ring->scan_count; i++) {
                                j = __ffs(mask);
                                mask &= ~(1 << j);
@@ -158,9 +158,13 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p)
        ring->access->store_to(indio_dev->ring, (u8 *) data, pf->timestamp);
 
        iio_trigger_notify_done(indio_dev->trig);
-       kfree(data);
 
+       kfree(data);
        return IRQ_HANDLED;
+
+err:
+       kfree(data);
+       return ret;
 }
 
 void adis16400_unconfigure_ring(struct iio_dev *indio_dev)
index 615902333fb0d9cb34b555c25a535362bb781042..d504aa251cedb5fe280224c6970ed94c137c7ecd 100644 (file)
@@ -294,6 +294,7 @@ struct iio_poll_func
        pf->h = h;
        pf->thread = thread;
        pf->type = type;
+       pf->private_data = private;
 
        return pf;
 }
index 2818851c07619288821dc6a48e73f7c72c903daa..d1ffa32cd141105b1f9fe4f064ef8b06a53b01e1 100644 (file)
@@ -205,10 +205,10 @@ int mei_hw_init(struct mei_device *dev)
                        "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
                        dev->host_hw_state, dev->me_hw_state);
 
-               if (!(dev->host_hw_state & H_RDY) != H_RDY)
+               if (!(dev->host_hw_state & H_RDY))
                        dev_dbg(&dev->pdev->dev, "host turn off H_RDY.\n");
 
-               if (!(dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
+               if (!(dev->me_hw_state & ME_RDY_HRA))
                        dev_dbg(&dev->pdev->dev, "ME turn off ME_RDY.\n");
 
                printk(KERN_ERR "mei: link layer initialization failed.\n");
index b05306766870d4f0f8410e5189eba2ace54f9185..fe40e0b6f6752b16b118ebc0940342d89bb559f9 100644 (file)
@@ -2,6 +2,7 @@ config FB_OLPC_DCON
        tristate "One Laptop Per Child Display CONtroller support"
        depends on OLPC && FB
        select I2C
+       select BACKLIGHT_CLASS_DEVICE
        ---help---
          Add support for the OLPC XO DCON controller.  This controller is
          only available on OLPC platforms.   Unless you have one of these
index bddb0312b31eb2543f2baa75751c6a6e5d5c6109..cdae497d54675dd2feefdec7628d1f645decc4e1 100644 (file)
@@ -2328,7 +2328,7 @@ Switch_Fail:
 
                        retval = sd_send_cmd_get_rsp(chip, IO_SEND_OP_COND, 0, SD_RSP_TYPE_R4, rsp, 5);
                        if (retval == STATUS_SUCCESS) {
-                               int func_num = (rsp[1] >> 4) && 0x07;
+                               int func_num = (rsp[1] >> 4) & 0x07;
                                if (func_num) {
                                        RTSX_DEBUGP("SD_IO card (Function number: %d)!\n", func_num);
                                        chip->sd_io = 1;
index 6e99ec87fee0b26505bdb81fc1f9147c463c049f..8cbea42b69bc75a87a61a60652c80e389eefa14b 100644 (file)
@@ -26,6 +26,8 @@
 static int stub_probe(struct usb_interface *interface,
                      const struct usb_device_id *id);
 static void stub_disconnect(struct usb_interface *interface);
+static int stub_pre_reset(struct usb_interface *interface);
+static int stub_post_reset(struct usb_interface *interface);
 
 /*
  * Define device IDs here if you want to explicitly limit exportable devices.
@@ -59,6 +61,8 @@ struct usb_driver stub_driver = {
        .probe          = stub_probe,
        .disconnect     = stub_disconnect,
        .id_table       = stub_table,
+       .pre_reset      = stub_pre_reset,
+       .post_reset     = stub_post_reset,
 };
 
 /*
@@ -541,3 +545,20 @@ static void stub_disconnect(struct usb_interface *interface)
                del_match_busid((char *)udev_busid);
        }
 }
+
+/* 
+ * Presence of pre_reset and post_reset prevents the driver from being unbound
+ * when the device is being reset
+ */
+int stub_pre_reset(struct usb_interface *interface)
+{
+       dev_dbg(&interface->dev, "pre_reset\n");
+       return 0;
+}
+
+int stub_post_reset(struct usb_interface *interface)
+{
+       dev_dbg(&interface->dev, "post_reset\n");
+       return 0;
+}
index a5c1fa1f0430c7d5a5b4921a55a212f347ae52ca..bc57844600b96ede1e0e0ee9da32819df1fc43a8 100644 (file)
@@ -175,16 +175,18 @@ static int tweak_reset_device_cmd(struct urb *urb)
        dev_info(&urb->dev->dev, "usb_queue_reset_device\n");
 
        /*
-        * usb_lock_device_for_reset caused a deadlock: it causes the driver
-        * to unbind. In the shutdown the rx thread is signalled to shut down
-        * but this thread is pending in the usb_lock_device_for_reset.
-        *
-        * Instead queue the reset.
-        *
-        * Unfortunatly an existing usbip connection will be dropped due to
-        * driver unbinding.
+        * With the implementation of pre_reset and post_reset the driver no 
+        * longer unbinds. This allows the use of synchronous reset.
         */
-       usb_queue_reset_device(sdev->interface);
+
+       if (usb_lock_device_for_reset(sdev->udev, sdev->interface)<0)
+       {
+               dev_err(&urb->dev->dev, "could not obtain lock to reset device\n");
+               return 0;
+       }
+       usb_reset_device(sdev->udev);
+       usb_unlock_device(sdev->udev);
+
        return 0;
 }
 
index 6555891e149c809c56a014f7f1511a063a3cb8df..a3a727c3b40f2a6a21fbb86e075e9ab6d802752e 100644 (file)
@@ -378,7 +378,7 @@ int wl_adapter_close(struct net_device *dev)
 } /* wl_adapter_close */
 /*============================================================================*/
 
-static struct pcmcia_device_id wl_adapter_ids[] = {
+static const struct pcmcia_device_id wl_adapter_ids[] = {
 #if !((HCF_TYPE) & HCF_TYPE_HII5)
        PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0003),
        PCMCIA_DEVICE_PROD_ID12("Agere Systems", "Wireless PC Card Model 0110",
index 76378397b763355c059ace7b5fe6bdd09abaf80c..fb466f4c92e00794085a6e628bb66a44b1ecf133 100644 (file)
@@ -695,7 +695,7 @@ void prism2_disconnected(wlandevice_t *wlandev)
 
 void prism2_roamed(wlandevice_t *wlandev)
 {
-       cfg80211_roamed(wlandev->netdev, wlandev->bssid,
+       cfg80211_roamed(wlandev->netdev, NULL, wlandev->bssid,
                NULL, 0, NULL, 0, GFP_KERNEL);
 }
 
index b8a2b30a157216f63506c4fbbd2cda539bd186f3..77ac2d4d3ef17dc72e9d2633f8f9846ff766c2c8 100644 (file)
@@ -1181,9 +1181,12 @@ static bool zcache_freeze;
 /*
  * zcache shrinker interface (only useful for ephemeral pages, so zbud only)
  */
-static int shrink_zcache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
+static int shrink_zcache_memory(struct shrinker *shrink,
+                               struct shrink_control *sc)
 {
        int ret = -1;
+       int nr = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
 
        if (nr >= 0) {
                if (!(gfp_mask & __GFP_FS))
index aed4e464d31cb27735e33c76e1eca789149598b0..70c2e7fa66643f7a7cdf040c62d74e977d7b9d1b 100644 (file)
@@ -31,7 +31,7 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_cmnd.h>
-#include <scsi/libsas.h> /* For TASK_ATTR_* */
+#include <scsi/scsi_tcq.h>
 
 #include <target/target_core_base.h>
 #include <target/target_core_transport.h>
@@ -95,17 +95,17 @@ static struct se_cmd *tcm_loop_allocate_core_cmd(
        if (sc->device->tagged_supported) {
                switch (sc->tag) {
                case HEAD_OF_QUEUE_TAG:
-                       sam_task_attr = TASK_ATTR_HOQ;
+                       sam_task_attr = MSG_HEAD_TAG;
                        break;
                case ORDERED_QUEUE_TAG:
-                       sam_task_attr = TASK_ATTR_ORDERED;
+                       sam_task_attr = MSG_ORDERED_TAG;
                        break;
                default:
-                       sam_task_attr = TASK_ATTR_SIMPLE;
+                       sam_task_attr = MSG_SIMPLE_TAG;
                        break;
                }
        } else
-               sam_task_attr = TASK_ATTR_SIMPLE;
+               sam_task_attr = MSG_SIMPLE_TAG;
 
        /*
         * Initialize struct se_cmd descriptor from target_core_mod infrastructure
@@ -379,14 +379,14 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc)
         * Initialize struct se_cmd descriptor from target_core_mod infrastructure
         */
        transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, 0,
-                               DMA_NONE, TASK_ATTR_SIMPLE,
+                               DMA_NONE, MSG_SIMPLE_TAG,
                                &tl_cmd->tl_sense_buf[0]);
        /*
         * Allocate the LUN_RESET TMR
         */
        se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd, (void *)tl_tmr,
                                TMR_LUN_RESET);
-       if (!se_cmd->se_tmr_req)
+       if (IS_ERR(se_cmd->se_tmr_req))
                goto release;
        /*
         * Locate the underlying TCM struct se_lun from sc->device->lun
@@ -939,18 +939,6 @@ static u16 tcm_loop_get_fabric_sense_len(void)
        return 0;
 }
 
-static u64 tcm_loop_pack_lun(unsigned int lun)
-{
-       u64 result;
-
-       /* LSB of lun into byte 1 big-endian */
-       result = ((lun & 0xff) << 8);
-       /* use flat space addressing method */
-       result |= 0x40 | ((lun >> 8) & 0x3f);
-
-       return cpu_to_le64(result);
-}
-
 static char *tcm_loop_dump_proto_id(struct tcm_loop_hba *tl_hba)
 {
        switch (tl_hba->tl_proto_id) {
@@ -1029,6 +1017,7 @@ static int tcm_loop_make_nexus(
        struct se_portal_group *se_tpg;
        struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba;
        struct tcm_loop_nexus *tl_nexus;
+       int ret = -ENOMEM;
 
        if (tl_tpg->tl_hba->tl_nexus) {
                printk(KERN_INFO "tl_tpg->tl_hba->tl_nexus already exists\n");
@@ -1045,8 +1034,10 @@ static int tcm_loop_make_nexus(
         * Initialize the struct se_session pointer
         */
        tl_nexus->se_sess = transport_init_session();
-       if (!tl_nexus->se_sess)
+       if (IS_ERR(tl_nexus->se_sess)) {
+               ret = PTR_ERR(tl_nexus->se_sess);
                goto out;
+       }
        /*
         * Since we are running in 'demo mode' this call with generate a
         * struct se_node_acl for the tcm_loop struct se_portal_group with the SCSI
@@ -1072,7 +1063,7 @@ static int tcm_loop_make_nexus(
 
 out:
        kfree(tl_nexus);
-       return -ENOMEM;
+       return ret;
 }
 
 static int tcm_loop_drop_nexus(
@@ -1152,7 +1143,7 @@ static ssize_t tcm_loop_tpg_store_nexus(
         * the fabric protocol_id set in tcm_loop_make_scsi_hba(), and call
         * tcm_loop_make_nexus()
         */
-       if (strlen(page) > TL_WWN_ADDR_LEN) {
+       if (strlen(page) >= TL_WWN_ADDR_LEN) {
                printk(KERN_ERR "Emulated NAA Sas Address: %s, exceeds"
                                " max: %d\n", page, TL_WWN_ADDR_LEN);
                return -EINVAL;
@@ -1333,7 +1324,7 @@ struct se_wwn *tcm_loop_make_scsi_hba(
        return ERR_PTR(-EINVAL);
 
 check_len:
-       if (strlen(name) > TL_WWN_ADDR_LEN) {
+       if (strlen(name) >= TL_WWN_ADDR_LEN) {
                printk(KERN_ERR "Emulated NAA %s Address: %s, exceeds"
                        " max: %d\n", name, tcm_loop_dump_proto_id(tl_hba),
                        TL_WWN_ADDR_LEN);
@@ -1481,7 +1472,6 @@ static int tcm_loop_register_configfs(void)
        fabric->tf_ops.set_fabric_sense_len = &tcm_loop_set_fabric_sense_len;
        fabric->tf_ops.get_fabric_sense_len = &tcm_loop_get_fabric_sense_len;
        fabric->tf_ops.is_state_remove = &tcm_loop_is_state_remove;
-       fabric->tf_ops.pack_lun = &tcm_loop_pack_lun;
 
        tf_cg = &fabric->tf_group;
        /*
index a5f44a6e6e1d62286ef81228cf4d014b3be03a9d..25c1f49a7d8bae7ee61f20df5830ba5a782277c7 100644 (file)
@@ -304,7 +304,7 @@ struct target_fabric_configfs *target_fabric_configfs_init(
                printk(KERN_ERR "Unable to locate passed fabric name\n");
                return NULL;
        }
-       if (strlen(name) > TARGET_FABRIC_NAME_SIZE) {
+       if (strlen(name) >= TARGET_FABRIC_NAME_SIZE) {
                printk(KERN_ERR "Passed name: %s exceeds TARGET_FABRIC"
                        "_NAME_SIZE\n", name);
                return NULL;
@@ -312,7 +312,7 @@ struct target_fabric_configfs *target_fabric_configfs_init(
 
        tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL);
        if (!(tf))
-               return ERR_PTR(-ENOMEM);
+               return NULL;
 
        INIT_LIST_HEAD(&tf->tf_list);
        atomic_set(&tf->tf_access_cnt, 0);
@@ -497,10 +497,6 @@ static int target_fabric_tf_ops_check(
                printk(KERN_ERR "Missing tfo->is_state_remove()\n");
                return -EINVAL;
        }
-       if (!(tfo->pack_lun)) {
-               printk(KERN_ERR "Missing tfo->pack_lun()\n");
-               return -EINVAL;
-       }
        /*
         * We at least require tfo->fabric_make_wwn(), tfo->fabric_drop_wwn()
         * tfo->fabric_make_tpg() and tfo->fabric_drop_tpg() in
@@ -855,7 +851,7 @@ static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial(
                return -EOPNOTSUPP;
        }
 
-       if ((strlen(page) + 1) > INQUIRY_VPD_SERIAL_LEN) {
+       if (strlen(page) >= INQUIRY_VPD_SERIAL_LEN) {
                printk(KERN_ERR "Emulated VPD Unit Serial exceeds"
                " INQUIRY_VPD_SERIAL_LEN: %d\n", INQUIRY_VPD_SERIAL_LEN);
                return -EOVERFLOW;
@@ -921,7 +917,7 @@ static ssize_t target_core_dev_wwn_show_attr_vpd_protocol_identifier(
 
                transport_dump_vpd_proto_id(vpd, buf, VPD_TMP_BUF_SIZE);
 
-               if ((len + strlen(buf) > PAGE_SIZE))
+               if ((len + strlen(buf) >= PAGE_SIZE))
                        break;
 
                len += sprintf(page+len, "%s", buf);
@@ -966,19 +962,19 @@ static ssize_t target_core_dev_wwn_show_attr_##_name(                     \
                                                                        \
                memset(buf, 0, VPD_TMP_BUF_SIZE);                       \
                transport_dump_vpd_assoc(vpd, buf, VPD_TMP_BUF_SIZE);   \
-               if ((len + strlen(buf) > PAGE_SIZE))                    \
+               if ((len + strlen(buf) >= PAGE_SIZE))                   \
                        break;                                          \
                len += sprintf(page+len, "%s", buf);                    \
                                                                        \
                memset(buf, 0, VPD_TMP_BUF_SIZE);                       \
                transport_dump_vpd_ident_type(vpd, buf, VPD_TMP_BUF_SIZE); \
-               if ((len + strlen(buf) > PAGE_SIZE))                    \
+               if ((len + strlen(buf) >= PAGE_SIZE))                   \
                        break;                                          \
                len += sprintf(page+len, "%s", buf);                    \
                                                                        \
                memset(buf, 0, VPD_TMP_BUF_SIZE);                       \
                transport_dump_vpd_ident(vpd, buf, VPD_TMP_BUF_SIZE); \
-               if ((len + strlen(buf) > PAGE_SIZE))                    \
+               if ((len + strlen(buf) >= PAGE_SIZE))                   \
                        break;                                          \
                len += sprintf(page+len, "%s", buf);                    \
        }                                                               \
@@ -1303,7 +1299,7 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(
                        &i_buf[0] : "", pr_reg->pr_res_key,
                        pr_reg->pr_res_generation);
 
-               if ((len + strlen(buf) > PAGE_SIZE))
+               if ((len + strlen(buf) >= PAGE_SIZE))
                        break;
 
                len += sprintf(page+len, "%s", buf);
@@ -1500,7 +1496,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
                                ret = -ENOMEM;
                                goto out;
                        }
-                       if (strlen(i_port) > PR_APTPL_MAX_IPORT_LEN) {
+                       if (strlen(i_port) >= PR_APTPL_MAX_IPORT_LEN) {
                                printk(KERN_ERR "APTPL metadata initiator_node="
                                        " exceeds PR_APTPL_MAX_IPORT_LEN: %d\n",
                                        PR_APTPL_MAX_IPORT_LEN);
@@ -1514,7 +1510,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
                                ret = -ENOMEM;
                                goto out;
                        }
-                       if (strlen(isid) > PR_REG_ISID_LEN) {
+                       if (strlen(isid) >= PR_REG_ISID_LEN) {
                                printk(KERN_ERR "APTPL metadata initiator_isid"
                                        "= exceeds PR_REG_ISID_LEN: %d\n",
                                        PR_REG_ISID_LEN);
@@ -1575,7 +1571,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
                                ret = -ENOMEM;
                                goto out;
                        }
-                       if (strlen(t_port) > PR_APTPL_MAX_TPORT_LEN) {
+                       if (strlen(t_port) >= PR_APTPL_MAX_TPORT_LEN) {
                                printk(KERN_ERR "APTPL metadata target_node="
                                        " exceeds PR_APTPL_MAX_TPORT_LEN: %d\n",
                                        PR_APTPL_MAX_TPORT_LEN);
@@ -3056,7 +3052,7 @@ static struct config_group *target_core_call_addhbatotarget(
        int ret;
 
        memset(buf, 0, TARGET_CORE_NAME_MAX_LEN);
-       if (strlen(name) > TARGET_CORE_NAME_MAX_LEN) {
+       if (strlen(name) >= TARGET_CORE_NAME_MAX_LEN) {
                printk(KERN_ERR "Passed *name strlen(): %d exceeds"
                        " TARGET_CORE_NAME_MAX_LEN: %d\n", (int)strlen(name),
                        TARGET_CORE_NAME_MAX_LEN);
index d25e20829012d61075ee470bf3fe5690ebd3afbe..ba698ea62bb2a52c19d87a6d1df7de10fcba9ecd 100644 (file)
@@ -38,6 +38,7 @@
 #include <net/sock.h>
 #include <net/tcp.h>
 #include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
 
 #include <target/target_core_base.h>
 #include <target/target_core_device.h>
@@ -150,13 +151,13 @@ out:
 
        {
        struct se_device *dev = se_lun->lun_se_dev;
-       spin_lock(&dev->stats_lock);
+       spin_lock_irq(&dev->stats_lock);
        dev->num_cmds++;
        if (se_cmd->data_direction == DMA_TO_DEVICE)
                dev->write_bytes += se_cmd->data_length;
        else if (se_cmd->data_direction == DMA_FROM_DEVICE)
                dev->read_bytes += se_cmd->data_length;
-       spin_unlock(&dev->stats_lock);
+       spin_unlock_irq(&dev->stats_lock);
        }
 
        /*
@@ -191,7 +192,7 @@ int transport_get_lun_for_tmr(
                        &SE_NODE_ACL(se_sess)->device_list[unpacked_lun];
        if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) {
                se_lun = se_cmd->se_lun = se_tmr->tmr_lun = deve->se_lun;
-               dev = se_tmr->tmr_dev = se_lun->lun_se_dev;
+               dev = se_lun->lun_se_dev;
                se_cmd->pr_res_key = deve->pr_res_key;
                se_cmd->orig_fe_lun = unpacked_lun;
                se_cmd->se_orig_obj_ptr = SE_LUN(se_cmd)->lun_se_dev;
@@ -215,6 +216,7 @@ int transport_get_lun_for_tmr(
                se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
                return -1;
        }
+       se_tmr->tmr_dev = dev;
 
        spin_lock(&dev->se_tmr_lock);
        list_add_tail(&se_tmr->tmr_list, &dev->dev_tmr_list);
@@ -658,8 +660,7 @@ int transport_core_report_lun_response(struct se_cmd *se_cmd)
        struct se_session *se_sess = SE_SESS(se_cmd);
        struct se_task *se_task;
        unsigned char *buf = (unsigned char *)T_TASK(se_cmd)->t_task_buf;
-       u32 cdb_offset = 0, lun_count = 0, offset = 8;
-       u64 i, lun;
+       u32 cdb_offset = 0, lun_count = 0, offset = 8, i;
 
        list_for_each_entry(se_task, &T_TASK(se_cmd)->t_task_list, t_list)
                break;
@@ -675,15 +676,7 @@ int transport_core_report_lun_response(struct se_cmd *se_cmd)
         * a $FABRIC_MOD.  In that case, report LUN=0 only.
         */
        if (!(se_sess)) {
-               lun = 0;
-               buf[offset++] = ((lun >> 56) & 0xff);
-               buf[offset++] = ((lun >> 48) & 0xff);
-               buf[offset++] = ((lun >> 40) & 0xff);
-               buf[offset++] = ((lun >> 32) & 0xff);
-               buf[offset++] = ((lun >> 24) & 0xff);
-               buf[offset++] = ((lun >> 16) & 0xff);
-               buf[offset++] = ((lun >> 8) & 0xff);
-               buf[offset++] = (lun & 0xff);
+               int_to_scsilun(0, (struct scsi_lun *)&buf[offset]);
                lun_count = 1;
                goto done;
        }
@@ -703,15 +696,8 @@ int transport_core_report_lun_response(struct se_cmd *se_cmd)
                if ((cdb_offset + 8) >= se_cmd->data_length)
                        continue;
 
-               lun = cpu_to_be64(CMD_TFO(se_cmd)->pack_lun(deve->mapped_lun));
-               buf[offset++] = ((lun >> 56) & 0xff);
-               buf[offset++] = ((lun >> 48) & 0xff);
-               buf[offset++] = ((lun >> 40) & 0xff);
-               buf[offset++] = ((lun >> 32) & 0xff);
-               buf[offset++] = ((lun >> 24) & 0xff);
-               buf[offset++] = ((lun >> 16) & 0xff);
-               buf[offset++] = ((lun >> 8) & 0xff);
-               buf[offset++] = (lun & 0xff);
+               int_to_scsilun(deve->mapped_lun, (struct scsi_lun *)&buf[offset]);
+               offset += 8;
                cdb_offset += 8;
        }
        spin_unlock_irq(&SE_NODE_ACL(se_sess)->device_list_lock);
@@ -1445,7 +1431,7 @@ struct se_lun_acl *core_dev_init_initiator_node_lun_acl(
        struct se_lun_acl *lacl;
        struct se_node_acl *nacl;
 
-       if (strlen(initiatorname) > TRANSPORT_IQN_LEN) {
+       if (strlen(initiatorname) >= TRANSPORT_IQN_LEN) {
                printk(KERN_ERR "%s InitiatorName exceeds maximum size.\n",
                        TPG_TFO(tpg)->get_fabric_name());
                *ret = -EOVERFLOW;
index a79f518ca6e2b76e12312d55f536cdb732640802..b662db3a320bb96f272cbf9a831c1c8813e89952 100644 (file)
@@ -1916,7 +1916,7 @@ static int __core_scsi3_update_aptpl_buf(
                                pr_reg->pr_res_mapped_lun);
                }
 
-               if ((len + strlen(tmp) > pr_aptpl_buf_len)) {
+               if ((len + strlen(tmp) >= pr_aptpl_buf_len)) {
                        printk(KERN_ERR "Unable to update renaming"
                                " APTPL metadata\n");
                        spin_unlock(&T10_RES(su_dev)->registration_lock);
@@ -1934,7 +1934,7 @@ static int __core_scsi3_update_aptpl_buf(
                        TPG_TFO(tpg)->tpg_get_tag(tpg),
                        lun->lun_sep->sep_rtpi, lun->unpacked_lun, reg_count);
 
-               if ((len + strlen(tmp) > pr_aptpl_buf_len)) {
+               if ((len + strlen(tmp) >= pr_aptpl_buf_len)) {
                        printk(KERN_ERR "Unable to update renaming"
                                " APTPL metadata\n");
                        spin_unlock(&T10_RES(su_dev)->registration_lock);
@@ -1986,7 +1986,7 @@ static int __core_scsi3_write_aptpl_to_file(
        memset(iov, 0, sizeof(struct iovec));
        memset(path, 0, 512);
 
-       if (strlen(&wwn->unit_serial[0]) > 512) {
+       if (strlen(&wwn->unit_serial[0]) >= 512) {
                printk(KERN_ERR "WWN value for struct se_device does not fit"
                        " into path buffer\n");
                return -1;
index 7ff6a35f26ac338e93e4867e8c8d9fd4de40e143..331d423fd0e085bbc65949201661ddbfd06fca91 100644 (file)
@@ -41,7 +41,7 @@
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_host.h>
-#include <scsi/libsas.h> /* For TASK_ATTR_* */
+#include <scsi/scsi_tcq.h>
 
 #include <target/target_core_base.h>
 #include <target/target_core_device.h>
@@ -911,7 +911,7 @@ static int pscsi_do_task(struct se_task *task)
         * descriptor
         */
        blk_execute_rq_nowait(pdv->pdv_sd->request_queue, NULL, pt->pscsi_req,
-                       (task->task_se_cmd->sam_task_attr == TASK_ATTR_HOQ),
+                       (task->task_se_cmd->sam_task_attr == MSG_HEAD_TAG),
                        pscsi_req_done);
 
        return PYX_TRANSPORT_SENT_TO_TRANSPORT;
index 4a109835e4203995bf8c4ea0784639321d7013f5..179063d81cdd6f30f1af19ef3cb20c2e12b923a4 100644 (file)
@@ -55,7 +55,8 @@ struct se_tmr_req *core_tmr_alloc_req(
 {
        struct se_tmr_req *tmr;
 
-       tmr = kmem_cache_zalloc(se_tmr_req_cache, GFP_KERNEL);
+       tmr = kmem_cache_zalloc(se_tmr_req_cache, (in_interrupt()) ?
+                                       GFP_ATOMIC : GFP_KERNEL);
        if (!(tmr)) {
                printk(KERN_ERR "Unable to allocate struct se_tmr_req\n");
                return ERR_PTR(-ENOMEM);
@@ -74,10 +75,16 @@ void core_tmr_release_req(
 {
        struct se_device *dev = tmr->tmr_dev;
 
+       if (!dev) {
+               kmem_cache_free(se_tmr_req_cache, tmr);
+               return;
+       }
+
        spin_lock(&dev->se_tmr_lock);
        list_del(&tmr->tmr_list);
-       kmem_cache_free(se_tmr_req_cache, tmr);
        spin_unlock(&dev->se_tmr_lock);
+
+       kmem_cache_free(se_tmr_req_cache, tmr);
 }
 
 static void core_tmr_handle_tas_abort(
@@ -398,9 +405,9 @@ int core_tmr_lun_reset(
                printk(KERN_INFO "LUN_RESET: SCSI-2 Released reservation\n");
        }
 
-       spin_lock(&dev->stats_lock);
+       spin_lock_irq(&dev->stats_lock);
        dev->num_resets++;
-       spin_unlock(&dev->stats_lock);
+       spin_unlock_irq(&dev->stats_lock);
 
        DEBUG_LR("LUN_RESET: %s for [%s] Complete\n",
                        (preempt_and_abort_list) ? "Preempt" : "TMR",
index b9d3501bdd91c820abd76f2192ce72faa4c5f14e..4b9b7169bdd96957d9a6054ea68ec99c897a2381 100644 (file)
@@ -42,7 +42,7 @@
 #include <net/tcp.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
-#include <scsi/libsas.h> /* For TASK_ATTR_* */
+#include <scsi/scsi_tcq.h>
 
 #include <target/target_core_base.h>
 #include <target/target_core_device.h>
@@ -536,13 +536,13 @@ EXPORT_SYMBOL(transport_register_session);
 void transport_deregister_session_configfs(struct se_session *se_sess)
 {
        struct se_node_acl *se_nacl;
-
+       unsigned long flags;
        /*
         * Used by struct se_node_acl's under ConfigFS to locate active struct se_session
         */
        se_nacl = se_sess->se_node_acl;
        if ((se_nacl)) {
-               spin_lock_irq(&se_nacl->nacl_sess_lock);
+               spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags);
                list_del(&se_sess->sess_acl_list);
                /*
                 * If the session list is empty, then clear the pointer.
@@ -556,7 +556,7 @@ void transport_deregister_session_configfs(struct se_session *se_sess)
                                        se_nacl->acl_sess_list.prev,
                                        struct se_session, sess_acl_list);
                }
-               spin_unlock_irq(&se_nacl->nacl_sess_lock);
+               spin_unlock_irqrestore(&se_nacl->nacl_sess_lock, flags);
        }
 }
 EXPORT_SYMBOL(transport_deregister_session_configfs);
@@ -762,7 +762,6 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd)
        transport_all_task_dev_remove_state(cmd);
        spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
 
-       transport_free_dev_tasks(cmd);
 
 check_lun:
        spin_lock_irqsave(&lun->lun_cmd_lock, flags);
@@ -1075,7 +1074,7 @@ static inline int transport_add_task_check_sam_attr(
         * head of the struct se_device->execute_task_list, and task_prev
         * after that for each subsequent task
         */
-       if (task->task_se_cmd->sam_task_attr == TASK_ATTR_HOQ) {
+       if (task->task_se_cmd->sam_task_attr == MSG_HEAD_TAG) {
                list_add(&task->t_execute_list,
                                (task_prev != NULL) ?
                                &task_prev->t_execute_list :
@@ -1195,6 +1194,7 @@ transport_get_task_from_execute_queue(struct se_device *dev)
                break;
 
        list_del(&task->t_execute_list);
+       atomic_set(&task->task_execute_queue, 0);
        atomic_dec(&dev->execute_tasks);
 
        return task;
@@ -1210,8 +1210,14 @@ void transport_remove_task_from_execute_queue(
 {
        unsigned long flags;
 
+       if (atomic_read(&task->task_execute_queue) == 0) {
+               dump_stack();
+               return;
+       }
+
        spin_lock_irqsave(&dev->execute_task_lock, flags);
        list_del(&task->t_execute_list);
+       atomic_set(&task->task_execute_queue, 0);
        atomic_dec(&dev->execute_tasks);
        spin_unlock_irqrestore(&dev->execute_task_lock, flags);
 }
@@ -1867,7 +1873,7 @@ static int transport_check_alloc_task_attr(struct se_cmd *cmd)
        if (SE_DEV(cmd)->dev_task_attr_type != SAM_TASK_ATTR_EMULATED)
                return 0;
 
-       if (cmd->sam_task_attr == TASK_ATTR_ACA) {
+       if (cmd->sam_task_attr == MSG_ACA_TAG) {
                DEBUG_STA("SAM Task Attribute ACA"
                        " emulation is not supported\n");
                return -1;
@@ -2058,6 +2064,13 @@ int transport_generic_handle_tmr(
 }
 EXPORT_SYMBOL(transport_generic_handle_tmr);
 
+void transport_generic_free_cmd_intr(
+       struct se_cmd *cmd)
+{
+       transport_add_cmd_to_queue(cmd, TRANSPORT_FREE_CMD_INTR);
+}
+EXPORT_SYMBOL(transport_generic_free_cmd_intr);
+
 static int transport_stop_tasks_for_cmd(struct se_cmd *cmd)
 {
        struct se_task *task, *task_tmp;
@@ -2504,7 +2517,7 @@ static inline int transport_execute_task_attr(struct se_cmd *cmd)
         * Check for the existence of HEAD_OF_QUEUE, and if true return 1
         * to allow the passed struct se_cmd list of tasks to the front of the list.
         */
-        if (cmd->sam_task_attr == TASK_ATTR_HOQ) {
+        if (cmd->sam_task_attr == MSG_HEAD_TAG) {
                atomic_inc(&SE_DEV(cmd)->dev_hoq_count);
                smp_mb__after_atomic_inc();
                DEBUG_STA("Added HEAD_OF_QUEUE for CDB:"
@@ -2512,7 +2525,7 @@ static inline int transport_execute_task_attr(struct se_cmd *cmd)
                        T_TASK(cmd)->t_task_cdb[0],
                        cmd->se_ordered_id);
                return 1;
-       } else if (cmd->sam_task_attr == TASK_ATTR_ORDERED) {
+       } else if (cmd->sam_task_attr == MSG_ORDERED_TAG) {
                spin_lock(&SE_DEV(cmd)->ordered_cmd_lock);
                list_add_tail(&cmd->se_ordered_list,
                                &SE_DEV(cmd)->ordered_cmd_list);
@@ -3411,7 +3424,7 @@ static int transport_generic_cmd_sequencer(
                 * See spc4r17 section 5.3
                 */
                if (SE_DEV(cmd)->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
-                       cmd->sam_task_attr = TASK_ATTR_HOQ;
+                       cmd->sam_task_attr = MSG_HEAD_TAG;
                cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
                break;
        case READ_BUFFER:
@@ -3619,7 +3632,7 @@ static int transport_generic_cmd_sequencer(
                 * See spc4r17 section 5.3
                 */
                if (SE_DEV(cmd)->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
-                       cmd->sam_task_attr = TASK_ATTR_HOQ;
+                       cmd->sam_task_attr = MSG_HEAD_TAG;
                cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
                break;
        default:
@@ -3777,21 +3790,21 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
        struct se_cmd *cmd_p, *cmd_tmp;
        int new_active_tasks = 0;
 
-       if (cmd->sam_task_attr == TASK_ATTR_SIMPLE) {
+       if (cmd->sam_task_attr == MSG_SIMPLE_TAG) {
                atomic_dec(&dev->simple_cmds);
                smp_mb__after_atomic_dec();
                dev->dev_cur_ordered_id++;
                DEBUG_STA("Incremented dev->dev_cur_ordered_id: %u for"
                        " SIMPLE: %u\n", dev->dev_cur_ordered_id,
                        cmd->se_ordered_id);
-       } else if (cmd->sam_task_attr == TASK_ATTR_HOQ) {
+       } else if (cmd->sam_task_attr == MSG_HEAD_TAG) {
                atomic_dec(&dev->dev_hoq_count);
                smp_mb__after_atomic_dec();
                dev->dev_cur_ordered_id++;
                DEBUG_STA("Incremented dev_cur_ordered_id: %u for"
                        " HEAD_OF_QUEUE: %u\n", dev->dev_cur_ordered_id,
                        cmd->se_ordered_id);
-       } else if (cmd->sam_task_attr == TASK_ATTR_ORDERED) {
+       } else if (cmd->sam_task_attr == MSG_ORDERED_TAG) {
                spin_lock(&dev->ordered_cmd_lock);
                list_del(&cmd->se_ordered_list);
                atomic_dec(&dev->dev_ordered_sync);
@@ -3824,7 +3837,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
                new_active_tasks++;
 
                spin_lock(&dev->delayed_cmd_lock);
-               if (cmd_p->sam_task_attr == TASK_ATTR_ORDERED)
+               if (cmd_p->sam_task_attr == MSG_ORDERED_TAG)
                        break;
        }
        spin_unlock(&dev->delayed_cmd_lock);
@@ -4776,18 +4789,20 @@ void transport_do_task_sg_chain(struct se_cmd *cmd)
                                sg_end_cur->page_link &= ~0x02;
 
                                sg_chain(sg_head, task_sg_num, sg_head_cur);
-                               sg_count += (task->task_sg_num + 1);
-                       } else
                                sg_count += task->task_sg_num;
+                               task_sg_num = (task->task_sg_num + 1);
+                       } else {
+                               sg_chain(sg_head, task_sg_num, sg_head_cur);
+                               sg_count += task->task_sg_num;
+                               task_sg_num = task->task_sg_num;
+                       }
 
                        sg_head = sg_head_cur;
                        sg_link = sg_link_cur;
-                       task_sg_num = task->task_sg_num;
                        continue;
                }
                sg_head = sg_first = &task->task_sg[0];
                sg_link = &task->task_sg[task->task_sg_num];
-               task_sg_num = task->task_sg_num;
                /*
                 * Check for single task..
                 */
@@ -4798,9 +4813,12 @@ void transport_do_task_sg_chain(struct se_cmd *cmd)
                         */
                        sg_end = &task->task_sg[task->task_sg_num - 1];
                        sg_end->page_link &= ~0x02;
-                       sg_count += (task->task_sg_num + 1);
-               } else
                        sg_count += task->task_sg_num;
+                       task_sg_num = (task->task_sg_num + 1);
+               } else {
+                       sg_count += task->task_sg_num;
+                       task_sg_num = task->task_sg_num;
+               }
        }
        /*
         * Setup the starting pointer and total t_tasks_sg_linked_no including
@@ -4809,21 +4827,20 @@ void transport_do_task_sg_chain(struct se_cmd *cmd)
        T_TASK(cmd)->t_tasks_sg_chained = sg_first;
        T_TASK(cmd)->t_tasks_sg_chained_no = sg_count;
 
-       DEBUG_CMD_M("Setup T_TASK(cmd)->t_tasks_sg_chained: %p and"
-               " t_tasks_sg_chained_no: %u\n", T_TASK(cmd)->t_tasks_sg_chained,
+       DEBUG_CMD_M("Setup cmd: %p T_TASK(cmd)->t_tasks_sg_chained: %p and"
+               " t_tasks_sg_chained_no: %u\n", cmd, T_TASK(cmd)->t_tasks_sg_chained,
                T_TASK(cmd)->t_tasks_sg_chained_no);
 
        for_each_sg(T_TASK(cmd)->t_tasks_sg_chained, sg,
                        T_TASK(cmd)->t_tasks_sg_chained_no, i) {
 
-               DEBUG_CMD_M("SG: %p page: %p length: %d offset: %d\n",
-                       sg, sg_page(sg), sg->length, sg->offset);
+               DEBUG_CMD_M("SG[%d]: %p page: %p length: %d offset: %d, magic: 0x%08x\n",
+                       i, sg, sg_page(sg), sg->length, sg->offset, sg->sg_magic);
                if (sg_is_chain(sg))
                        DEBUG_CMD_M("SG: %p sg_is_chain=1\n", sg);
                if (sg_is_last(sg))
                        DEBUG_CMD_M("SG: %p sg_is_last=1\n", sg);
        }
-
 }
 EXPORT_SYMBOL(transport_do_task_sg_chain);
 
@@ -5297,6 +5314,8 @@ void transport_generic_free_cmd(
                if (wait_for_tasks && cmd->transport_wait_for_tasks)
                        cmd->transport_wait_for_tasks(cmd, 0, 0);
 
+               transport_free_dev_tasks(cmd);
+
                transport_generic_remove(cmd, release_to_pool,
                                session_reinstatement);
        }
@@ -6132,6 +6151,9 @@ get_cmd:
                case TRANSPORT_REMOVE:
                        transport_generic_remove(cmd, 1, 0);
                        break;
+               case TRANSPORT_FREE_CMD_INTR:
+                       transport_generic_free_cmd(cmd, 0, 1, 0);
+                       break;
                case TRANSPORT_PROCESS_TMR:
                        transport_generic_do_tmr(cmd);
                        break;
index defff32b7880faf26c32732c4898a87ec6ba80f4..7b82f1b7fef814b595f8cc266f182baa3f031642 100644 (file)
@@ -144,7 +144,7 @@ enum ft_cmd_state {
  */
 struct ft_cmd {
        enum ft_cmd_state state;
-       u16 lun;                        /* LUN from request */
+       u32 lun;                        /* LUN from request */
        struct ft_sess *sess;           /* session held for cmd */
        struct fc_seq *seq;             /* sequence in exchange mgr */
        struct se_cmd se_cmd;           /* Local TCM I/O descriptor */
index 49e51778f7335a88bed41a39c410fc43f3d478a9..b2a106729d4914eca2c275adb956a944939d9b99 100644 (file)
@@ -35,6 +35,7 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_tcq.h>
 #include <scsi/libfc.h>
 #include <scsi/fc_encode.h>
 
@@ -93,29 +94,6 @@ void ft_dump_cmd(struct ft_cmd *cmd, const char *caller)
                16, 4, cmd->cdb, MAX_COMMAND_SIZE, 0);
 }
 
-/*
- * Get LUN from CDB.
- */
-static int ft_get_lun_for_cmd(struct ft_cmd *cmd, u8 *lunp)
-{
-       u64 lun;
-
-       lun = lunp[1];
-       switch (lunp[0] >> 6) {
-       case 0:
-               break;
-       case 1:
-               lun |= (lunp[0] & 0x3f) << 8;
-               break;
-       default:
-               return -1;
-       }
-       if (lun >= TRANSPORT_MAX_LUNS_PER_TPG)
-               return -1;
-       cmd->lun = lun;
-       return transport_get_lun_for_cmd(&cmd->se_cmd, NULL, lun);
-}
-
 static void ft_queue_cmd(struct ft_sess *sess, struct ft_cmd *cmd)
 {
        struct se_queue_obj *qobj;
@@ -417,6 +395,7 @@ static void ft_send_tm(struct ft_cmd *cmd)
 {
        struct se_tmr_req *tmr;
        struct fcp_cmnd *fcp;
+       struct ft_sess *sess;
        u8 tm_func;
 
        fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp));
@@ -424,13 +403,6 @@ static void ft_send_tm(struct ft_cmd *cmd)
        switch (fcp->fc_tm_flags) {
        case FCP_TMF_LUN_RESET:
                tm_func = TMR_LUN_RESET;
-               if (ft_get_lun_for_cmd(cmd, fcp->fc_lun) < 0) {
-                       ft_dump_cmd(cmd, __func__);
-                       transport_send_check_condition_and_sense(&cmd->se_cmd,
-                               cmd->se_cmd.scsi_sense_reason, 0);
-                       ft_sess_put(cmd->sess);
-                       return;
-               }
                break;
        case FCP_TMF_TGT_RESET:
                tm_func = TMR_TARGET_WARM_RESET;
@@ -462,6 +434,36 @@ static void ft_send_tm(struct ft_cmd *cmd)
                return;
        }
        cmd->se_cmd.se_tmr_req = tmr;
+
+       switch (fcp->fc_tm_flags) {
+       case FCP_TMF_LUN_RESET:
+               cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun);
+               if (transport_get_lun_for_tmr(&cmd->se_cmd, cmd->lun) < 0) {
+                       /*
+                        * Make sure to clean up newly allocated TMR request
+                        * since "unable to  handle TMR request because failed
+                        * to get to LUN"
+                        */
+                       FT_TM_DBG("Failed to get LUN for TMR func %d, "
+                                 "se_cmd %p, unpacked_lun %d\n",
+                                 tm_func, &cmd->se_cmd, cmd->lun);
+                       ft_dump_cmd(cmd, __func__);
+                       sess = cmd->sess;
+                       transport_send_check_condition_and_sense(&cmd->se_cmd,
+                               cmd->se_cmd.scsi_sense_reason, 0);
+                       transport_generic_free_cmd(&cmd->se_cmd, 0, 1, 0);
+                       ft_sess_put(sess);
+                       return;
+               }
+               break;
+       case FCP_TMF_TGT_RESET:
+       case FCP_TMF_CLR_TASK_SET:
+       case FCP_TMF_ABT_TASK_SET:
+       case FCP_TMF_CLR_ACA:
+               break;
+       default:
+               return;
+       }
        transport_generic_handle_tmr(&cmd->se_cmd);
 }
 
@@ -592,8 +594,25 @@ static void ft_send_cmd(struct ft_cmd *cmd)
                case FCP_CFL_WRDATA | FCP_CFL_RDDATA:
                        goto err;       /* TBD not supported by tcm_fc yet */
                }
+               /*
+                * Locate the SAM Task Attr from fc_pri_ta
+                */
+               switch (fcp->fc_pri_ta & FCP_PTA_MASK) {
+               case FCP_PTA_HEADQ:
+                       task_attr = MSG_HEAD_TAG;
+                       break;
+               case FCP_PTA_ORDERED:
+                       task_attr = MSG_ORDERED_TAG;
+                       break;
+               case FCP_PTA_ACA:
+                       task_attr = MSG_ACA_TAG;
+                       break;
+               case FCP_PTA_SIMPLE: /* Fallthrough */
+               default:
+                       task_attr = MSG_SIMPLE_TAG;
+               }
+
 
-               /* FCP_PTA_ maps 1:1 to TASK_ATTR_ */
                task_attr = fcp->fc_pri_ta & FCP_PTA_MASK;
                data_len = ntohl(fcp->fc_dl);
                cmd->cdb = fcp->fc_cdb;
@@ -617,7 +636,8 @@ static void ft_send_cmd(struct ft_cmd *cmd)
 
        fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd);
 
-       ret = ft_get_lun_for_cmd(cmd, fcp->fc_lun);
+       cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun);
+       ret = transport_get_lun_for_cmd(&cmd->se_cmd, NULL, cmd->lun);
        if (ret < 0) {
                ft_dump_cmd(cmd, __func__);
                transport_send_check_condition_and_sense(&cmd->se_cmd,
index fcdbbffe88ccd635c6e692d0631484a424e7f7fc..84e868c255dd1d24177dfcda58f3276cc5bfe7f6 100644 (file)
@@ -519,13 +519,6 @@ static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg)
        return tpg->index;
 }
 
-static u64 ft_pack_lun(unsigned int index)
-{
-       WARN_ON(index >= 256);
-       /* Caller wants this byte-swapped */
-       return cpu_to_le64((index & 0xff) << 8);
-}
-
 static struct target_core_fabric_ops ft_fabric_ops = {
        .get_fabric_name =              ft_get_fabric_name,
        .get_fabric_proto_ident =       fc_get_fabric_proto_ident,
@@ -564,7 +557,6 @@ static struct target_core_fabric_ops ft_fabric_ops = {
        .get_fabric_sense_len =         ft_get_fabric_sense_len,
        .set_fabric_sense_len =         ft_set_fabric_sense_len,
        .is_state_remove =              ft_is_state_remove,
-       .pack_lun =                     ft_pack_lun,
        /*
         * Setup function pointers for generic logic in
         * target_core_fabric_configfs.c
index 4c3c0efbe13f5b97158f92c51d17d46a5001ab40..8c4a24077d9d701fc6902501f9ad9f53775c24b2 100644 (file)
@@ -203,7 +203,7 @@ int ft_queue_data_in(struct se_cmd *se_cmd)
                        /* XXX For now, initiator will retry */
                        if (printk_ratelimit())
                                printk(KERN_ERR "%s: Failed to send frame %p, "
-                                               "xid <0x%x>, remaining <0x%x>, "
+                                               "xid <0x%x>, remaining %zu, "
                                                "lso_max <0x%x>\n",
                                                __func__, fp, ep->xid,
                                                remaining, lport->lso_max);
index a3bd57f2ea3204d5c079f38aba247f40aae47e25..7491e21cc6ae4c35629614b687a424ac2917d87a 100644 (file)
@@ -229,7 +229,7 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id,
                return NULL;
 
        sess->se_sess = transport_init_session();
-       if (!sess->se_sess) {
+       if (IS_ERR(sess->se_sess)) {
                kfree(sess);
                return NULL;
        }
@@ -332,7 +332,7 @@ void ft_sess_close(struct se_session *se_sess)
        lport = sess->tport->lport;
        port_id = sess->port_id;
        if (port_id == -1) {
-               mutex_lock(&ft_lport_lock);
+               mutex_unlock(&ft_lport_lock);
                return;
        }
        FT_SESS_DBG("port_id %x\n", port_id);
index d005b9eeebbcc1f751763c7ab039c9dea13333ca..05032e2cc95465dbc29949138b7f333272b91579 100644 (file)
@@ -157,7 +157,7 @@ static void ixj_cs_release(struct pcmcia_device *link)
        pcmcia_disable_device(link);
 }
 
-static struct pcmcia_device_id ixj_ids[] = {
+static const struct pcmcia_device_id ixj_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0257, 0x0600),
        PCMCIA_DEVICE_NULL
 };
index fc6f2a5bde01324675424b01da941e8718ccd259..0b1c82ad6805d2e0088840c4d2d17cff7e5dd109 100644 (file)
@@ -499,7 +499,7 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
        dev_set_drvdata(hwmon->device, hwmon);
        result = device_create_file(hwmon->device, &dev_attr_name);
        if (result)
-               goto unregister_hwmon_device;
+               goto free_mem;
 
  register_sys_interface:
        tz->hwmon = hwmon;
@@ -513,7 +513,7 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
        sysfs_attr_init(&tz->temp_input.attr.attr);
        result = device_create_file(hwmon->device, &tz->temp_input.attr);
        if (result)
-               goto unregister_hwmon_device;
+               goto unregister_name;
 
        if (tz->ops->get_crit_temp) {
                unsigned long temperature;
@@ -527,7 +527,7 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
                        result = device_create_file(hwmon->device,
                                                    &tz->temp_crit.attr);
                        if (result)
-                               goto unregister_hwmon_device;
+                               goto unregister_input;
                }
        }
 
@@ -539,9 +539,9 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
 
        return 0;
 
- unregister_hwmon_device:
-       device_remove_file(hwmon->device, &tz->temp_crit.attr);
+ unregister_input:
        device_remove_file(hwmon->device, &tz->temp_input.attr);
+ unregister_name:
        if (new_hwmon_device) {
                device_remove_file(hwmon->device, &dev_attr_name);
                hwmon_device_unregister(hwmon->device);
index bfa05e8018237bede822973a2029c40caf57c014..c0e8f2eeb88697b390787d1f210411ae6521c1cd 100644 (file)
@@ -4096,8 +4096,7 @@ static int __init cy_init(void)
        if (!cy_serial_driver)
                goto err;
 
-       printk(KERN_INFO "Cyclades driver " CY_VERSION " (built %s %s)\n",
-                       __DATE__, __TIME__);
+       printk(KERN_INFO "Cyclades driver " CY_VERSION "\n");
 
        /* Initialize the tty_driver structure */
 
index 444155a305ae1a3ad26d35a19b79ff83643167d6..655c7948261c79771ef7b788f1a0ca7559336408 100644 (file)
@@ -33,7 +33,7 @@
 #include <pcmcia/ss.h>
 #include <pcmcia/ds.h>
 
-static struct pcmcia_device_id ipw_ids[] = {
+static const struct pcmcia_device_id ipw_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0100),
        PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0200),
        PCMCIA_DEVICE_NULL
index a4c42a75a3bfea0f0143e8dd70454fde5dddf524..09e8c7d53af3e7d72ebfe25b45100789f4f5185a 100644 (file)
@@ -2128,8 +2128,8 @@ static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
        gsm->tty = NULL;
 }
 
-static unsigned int gsmld_receive_buf(struct tty_struct *tty,
-               const unsigned char *cp, char *fp, int count)
+static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                             char *fp, int count)
 {
        struct gsm_mux *gsm = tty->disc_data;
        const unsigned char *dp;
@@ -2162,8 +2162,6 @@ static unsigned int gsmld_receive_buf(struct tty_struct *tty,
        }
        /* FASYNC if needed ? */
        /* If clogged call tty_throttle(tty); */
-
-       return count;
 }
 
 /**
index cac666314aef4a5f453c5031caaa5b8fac4f0508..cea56033b34c2b490e796ae75df0fbea4e550a3f 100644 (file)
@@ -188,8 +188,8 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
                                    poll_table *wait);
 static int n_hdlc_tty_open(struct tty_struct *tty);
 static void n_hdlc_tty_close(struct tty_struct *tty);
-static unsigned int n_hdlc_tty_receive(struct tty_struct *tty,
-               const __u8 *cp, char *fp, int count);
+static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp,
+                              char *fp, int count);
 static void n_hdlc_tty_wakeup(struct tty_struct *tty);
 
 #define bset(p,b)      ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
@@ -509,8 +509,8 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty)
  * Called by tty low level driver when receive data is available. Data is
  * interpreted as one HDLC frame.
  */
-static unsigned int n_hdlc_tty_receive(struct tty_struct *tty,
-               const __u8 *data, char *flags, int count)
+static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
+                              char *flags, int count)
 {
        register struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
        register struct n_hdlc_buf *buf;
@@ -521,20 +521,20 @@ static unsigned int n_hdlc_tty_receive(struct tty_struct *tty,
                
        /* This can happen if stuff comes in on the backup tty */
        if (!n_hdlc || tty != n_hdlc->tty)
-               return -ENODEV;
+               return;
                
        /* verify line is using HDLC discipline */
        if (n_hdlc->magic != HDLC_MAGIC) {
                printk("%s(%d) line not using HDLC discipline\n",
                        __FILE__,__LINE__);
-               return -EINVAL;
+               return;
        }
        
        if ( count>maxframe ) {
                if (debuglevel >= DEBUG_LEVEL_INFO)     
                        printk("%s(%d) rx count>maxframesize, data discarded\n",
                               __FILE__,__LINE__);
-               return -EINVAL;
+               return;
        }
 
        /* get a free HDLC buffer */    
@@ -550,7 +550,7 @@ static unsigned int n_hdlc_tty_receive(struct tty_struct *tty,
                if (debuglevel >= DEBUG_LEVEL_INFO)     
                        printk("%s(%d) no more rx buffers, data discarded\n",
                               __FILE__,__LINE__);
-               return -EINVAL;
+               return;
        }
                
        /* copy received data to HDLC buffer */
@@ -565,8 +565,6 @@ static unsigned int n_hdlc_tty_receive(struct tty_struct *tty,
        if (n_hdlc->tty->fasync != NULL)
                kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN);
 
-       return count;
-
 }      /* end of n_hdlc_tty_receive() */
 
 /**
index a4bc39c21a436476b7ea8363f6c4d892882a5520..5c6c31459a2f6618cb7cf9d83c7100cf1a6d86ea 100644 (file)
@@ -139,8 +139,8 @@ static int r3964_ioctl(struct tty_struct *tty, struct file *file,
 static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old);
 static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
                struct poll_table_struct *wait);
-static unsigned int r3964_receive_buf(struct tty_struct *tty,
-               const unsigned char *cp, char *fp, int count);
+static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+               char *fp, int count);
 
 static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
        .owner = THIS_MODULE,
@@ -1239,8 +1239,8 @@ static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
        return result;
 }
 
-static unsigned int r3964_receive_buf(struct tty_struct *tty,
-               const unsigned char *cp, char *fp, int count)
+static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                       char *fp, int count)
 {
        struct r3964_info *pInfo = tty->disc_data;
        const unsigned char *p;
@@ -1257,8 +1257,6 @@ static unsigned int r3964_receive_buf(struct tty_struct *tty,
                }
 
        }
-
-       return count;
 }
 
 MODULE_LICENSE("GPL");
index 95d0a9c2dd13e3e625d8b287d911d327cebe2ee4..0ad32888091c16c1c27de4c032517df583ea4c9f 100644 (file)
@@ -81,6 +81,38 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
        return put_user(x, ptr);
 }
 
+/**
+ *     n_tty_set__room -       receive space
+ *     @tty: terminal
+ *
+ *     Called by the driver to find out how much data it is
+ *     permitted to feed to the line discipline without any being lost
+ *     and thus to manage flow control. Not serialized. Answers for the
+ *     "instant".
+ */
+
+static void n_tty_set_room(struct tty_struct *tty)
+{
+       /* tty->read_cnt is not read locked ? */
+       int     left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+       int old_left;
+
+       /*
+        * If we are doing input canonicalization, and there are no
+        * pending newlines, let characters through without limit, so
+        * that erase characters will be handled.  Other excess
+        * characters will be beeped.
+        */
+       if (left <= 0)
+               left = tty->icanon && !tty->canon_data;
+       old_left = tty->receive_room;
+       tty->receive_room = left;
+
+       /* Did this open up the receive buffer? We may need to flip */
+       if (left && !old_left)
+               schedule_work(&tty->buf.work);
+}
+
 static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
 {
        if (tty->read_cnt < N_TTY_BUF_SIZE) {
@@ -152,6 +184,7 @@ static void reset_buffer_flags(struct tty_struct *tty)
 
        tty->canon_head = tty->canon_data = tty->erasing = 0;
        memset(&tty->read_flags, 0, sizeof tty->read_flags);
+       n_tty_set_room(tty);
        check_unthrottle(tty);
 }
 
@@ -1327,19 +1360,17 @@ static void n_tty_write_wakeup(struct tty_struct *tty)
  *     calls one at a time and in order (or using flush_to_ldisc)
  */
 
-static unsigned int n_tty_receive_buf(struct tty_struct *tty,
-               const unsigned char *cp, char *fp, int count)
+static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                             char *fp, int count)
 {
        const unsigned char *p;
        char *f, flags = TTY_NORMAL;
        int     i;
        char    buf[64];
        unsigned long cpuflags;
-       int left;
-       int ret = 0;
 
        if (!tty->read_buf)
-               return 0;
+               return;
 
        if (tty->real_raw) {
                spin_lock_irqsave(&tty->read_lock, cpuflags);
@@ -1349,7 +1380,6 @@ static unsigned int n_tty_receive_buf(struct tty_struct *tty,
                memcpy(tty->read_buf + tty->read_head, cp, i);
                tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
                tty->read_cnt += i;
-               ret += i;
                cp += i;
                count -= i;
 
@@ -1359,10 +1389,8 @@ static unsigned int n_tty_receive_buf(struct tty_struct *tty,
                memcpy(tty->read_buf + tty->read_head, cp, i);
                tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
                tty->read_cnt += i;
-               ret += i;
                spin_unlock_irqrestore(&tty->read_lock, cpuflags);
        } else {
-               ret = count;
                for (i = count, p = cp, f = fp; i; i--, p++) {
                        if (f)
                                flags = *f++;
@@ -1390,6 +1418,8 @@ static unsigned int n_tty_receive_buf(struct tty_struct *tty,
                        tty->ops->flush_chars(tty);
        }
 
+       n_tty_set_room(tty);
+
        if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) ||
                L_EXTPROC(tty)) {
                kill_fasync(&tty->fasync, SIGIO, POLL_IN);
@@ -1402,12 +1432,8 @@ static unsigned int n_tty_receive_buf(struct tty_struct *tty,
         * mode.  We don't want to throttle the driver if we're in
         * canonical mode and don't have a newline yet!
         */
-       left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
-
-       if (left < TTY_THRESHOLD_THROTTLE)
+       if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
                tty_throttle(tty);
-
-       return ret;
 }
 
 int is_ignored(int sig)
@@ -1451,6 +1477,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
        if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
                tty->raw = 1;
                tty->real_raw = 1;
+               n_tty_set_room(tty);
                return;
        }
        if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
@@ -1503,6 +1530,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
                else
                        tty->real_raw = 0;
        }
+       n_tty_set_room(tty);
        /* The termios change make the tty ready for I/O */
        wake_up_interruptible(&tty->write_wait);
        wake_up_interruptible(&tty->read_wait);
@@ -1784,6 +1812,8 @@ do_it_again:
                                retval = -ERESTARTSYS;
                                break;
                        }
+                       /* FIXME: does n_tty_set_room need locking ? */
+                       n_tty_set_room(tty);
                        timeout = schedule_timeout(timeout);
                        continue;
                }
@@ -1855,8 +1885,10 @@ do_it_again:
                 * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
                 * we won't get any more characters.
                 */
-               if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE)
+               if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
+                       n_tty_set_room(tty);
                        check_unthrottle(tty);
+               }
 
                if (b - buf >= minimum)
                        break;
@@ -1878,6 +1910,7 @@ do_it_again:
        } else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
                 goto do_it_again;
 
+       n_tty_set_room(tty);
        return retval;
 }
 
index b1aecc7bb32a263fbdc75035f65f156e1f4f2549..fd347ff34d071dc14972faaa2d3e89ef9260475c 100644 (file)
@@ -61,8 +61,7 @@
 #include <linux/delay.h>
 
 
-#define VERSION_STRING DRIVER_DESC " 2.1d (build date: " \
-                                       __DATE__ " " __TIME__ ")"
+#define VERSION_STRING DRIVER_DESC " 2.1d"
 
 /*    Macros definitions */
 
index d5bfd41707e754c0c5803eb8d30c751927052c65..e0a77540b8ca39bbed2d4e771e18f443b1be8492 100644 (file)
@@ -281,7 +281,7 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx)
 #ifdef CONFIG_MAGIC_SYSRQ
                        } else if (ch == 0x10) { /* ^P */
                                show_state();
-                               show_free_areas();
+                               show_free_areas(0);
                                show_buffers();
 /*                             show_net_buffers(); */
                                return;
index 652bdac8ce8ec4a56e9cb99506d0d61744c9661b..6d5d6e679fc7f59c568a0a1afbac800e51f91e49 100644 (file)
@@ -1420,7 +1420,7 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
        port->flags             = UPF_BOOT_AUTOCONF;
        port->ops               = &atmel_pops;
        port->fifosize          = 1;
-       port->line              = pdev->id;
+       port->line              = data->num;
        port->dev               = &pdev->dev;
        port->mapbase   = pdev->resource[0].start;
        port->irq       = pdev->resource[1].start;
index bea5c215460c710901dcf18a00304d6d9be76f11..84db7321cce85e5d2be2a9cb3f7794c8f23ef0e3 100644 (file)
@@ -907,9 +907,10 @@ static int m32r_sio_request_port(struct uart_port *port)
        return ret;
 }
 
-static void m32r_sio_config_port(struct uart_port *port, int flags)
+static void m32r_sio_config_port(struct uart_port *port, int unused)
 {
        struct uart_sio_port *up = (struct uart_sio_port *)port;
+       unsigned long flags;
 
        spin_lock_irqsave(&up->port.lock, flags);
 
index 1bd28450ca40913f87503d7f75aa4ed5cd149904..a764bf99743b0b5c6be4d46fed2952cbca278d94 100644 (file)
@@ -421,7 +421,6 @@ static int max3110_main_thread(void *_max)
        int ret = 0;
        struct circ_buf *xmit = &max->con_xmit;
 
-       init_waitqueue_head(wq);
        pr_info(PR_FMT "start main thread\n");
 
        do {
@@ -823,7 +822,7 @@ static int __devinit serial_m3110_probe(struct spi_device *spi)
        res = RC_TAG;
        ret = max3110_write_then_read(max, (u8 *)&res, (u8 *)&res, 2, 0);
        if (ret < 0 || res == 0 || res == 0xffff) {
-               printk(KERN_ERR "MAX3111 deemed not present (conf reg %04x)",
+               dev_dbg(&spi->dev, "MAX3111 deemed not present (conf reg %04x)",
                                                                        res);
                ret = -ENODEV;
                goto err_get_page;
@@ -838,6 +837,8 @@ static int __devinit serial_m3110_probe(struct spi_device *spi)
        max->con_xmit.head = 0;
        max->con_xmit.tail = 0;
 
+       init_waitqueue_head(&max->wq);
+
        max->main_thread = kthread_run(max3110_main_thread,
                                        max, "max3110_main");
        if (IS_ERR(max->main_thread)) {
index c63d0d152af675fa15e78dee69844640309eabc8..465210930890b72ecdcaf1c70167b7211f43ed9e 100644 (file)
@@ -15,6 +15,7 @@
  *Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
  */
 #include <linux/serial_reg.h>
+#include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/serial_core.h>
@@ -1396,6 +1397,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
        int fifosize, base_baud;
        int port_type;
        struct pch_uart_driver_data *board;
+       const char *board_name;
 
        board = &drv_dat[id->driver_data];
        port_type = board->port_type;
@@ -1411,7 +1413,8 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
        base_baud = 1843200; /* 1.8432MHz */
 
        /* quirk for CM-iTC board */
-       if (strstr(dmi_get_system_info(DMI_BOARD_NAME), "CM-iTC"))
+       board_name = dmi_get_system_info(DMI_BOARD_NAME);
+       if (board_name && strstr(board_name, "CM-iTC"))
                base_baud = 192000000; /* 192.0MHz */
 
        switch (port_type) {
index 1ef4df9bf7e4f785bc609778a0819958ab9d1685..eef736ff810af9d03a5a5036b682b4ac479b6084 100644 (file)
@@ -670,7 +670,7 @@ failed:
        return -ENODEV;
 }
 
-static struct pcmcia_device_id serial_ids[] = {
+static const struct pcmcia_device_id serial_ids[] = {
        PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021),
        PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a),
        PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a),
index 46de2e075dacda019589cc5462a0d60f6eea8d51..6c9b7cd6778a9613542d739358f309a38fa56070 100644 (file)
@@ -413,10 +413,8 @@ static void flush_to_ldisc(struct work_struct *work)
        spin_lock_irqsave(&tty->buf.lock, flags);
 
        if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) {
-               struct tty_buffer *head, *tail = tty->buf.tail;
-               int seen_tail = 0;
+               struct tty_buffer *head;
                while ((head = tty->buf.head) != NULL) {
-                       int copied;
                        int count;
                        char *char_buf;
                        unsigned char *flag_buf;
@@ -425,15 +423,6 @@ static void flush_to_ldisc(struct work_struct *work)
                        if (!count) {
                                if (head->next == NULL)
                                        break;
-                               /*
-                                 There's a possibility tty might get new buffer
-                                 added during the unlock window below. We could
-                                 end up spinning in here forever hogging the CPU
-                                 completely. To avoid this let's have a rest each
-                                 time we processed the tail buffer.
-                               */
-                               if (tail == head)
-                                       seen_tail = 1;
                                tty->buf.head = head->next;
                                tty_buffer_free(tty, head);
                                continue;
@@ -443,19 +432,17 @@ static void flush_to_ldisc(struct work_struct *work)
                           line discipline as we want to empty the queue */
                        if (test_bit(TTY_FLUSHPENDING, &tty->flags))
                                break;
+                       if (!tty->receive_room)
+                               break;
+                       if (count > tty->receive_room)
+                               count = tty->receive_room;
                        char_buf = head->char_buf_ptr + head->read;
                        flag_buf = head->flag_buf_ptr + head->read;
+                       head->read += count;
                        spin_unlock_irqrestore(&tty->buf.lock, flags);
-                       copied = disc->ops->receive_buf(tty, char_buf,
+                       disc->ops->receive_buf(tty, char_buf,
                                                        flag_buf, count);
                        spin_lock_irqsave(&tty->buf.lock, flags);
-
-                       head->read += copied;
-
-                       if (copied == 0 || seen_tail) {
-                               schedule_work(&tty->buf.work);
-                               break;
-                       }
                }
                clear_bit(TTY_FLUSHING, &tty->flags);
        }
index 67b1d0d7c8acb924fdc481cfc75b36fa6c925de8..fb864e7fcd13f684e30108a02189f6b99c9315fc 100644 (file)
@@ -332,7 +332,8 @@ int paste_selection(struct tty_struct *tty)
                        continue;
                }
                count = sel_buffer_lth - pasted;
-               count = tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
+               count = min(count, tty->receive_room);
+               tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
                                                                NULL, count);
                pasted += count;
        }
index 395a347f2ebbea52d86b20cb97bec70548b6a34a..dac7676ce21bb6d9121d8fa4d178ea5cc0708438 100644 (file)
@@ -1530,6 +1530,8 @@ static const struct usb_device_id acm_ids[] = {
        { NOKIA_PCSUITE_ACM_INFO(0x04ce), }, /* Nokia E90 */
        { NOKIA_PCSUITE_ACM_INFO(0x01d4), }, /* Nokia E55 */
        { NOKIA_PCSUITE_ACM_INFO(0x0302), }, /* Nokia N8 */
+       { NOKIA_PCSUITE_ACM_INFO(0x0335), }, /* Nokia E7 */
+       { NOKIA_PCSUITE_ACM_INFO(0x03cd), }, /* Nokia C7 */
        { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */
 
        /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
index e35a17687c05f77b9ecc55b4002d0b13386081b6..aa3cc465a6017eab466710433b09acfecbdcaad2 100644 (file)
@@ -375,7 +375,7 @@ static int usb_unbind_interface(struct device *dev)
                 * Just re-enable it without affecting the endpoint toggles.
                 */
                usb_enable_interface(udev, intf, false);
-       } else if (!error && !intf->dev.power.in_suspend) {
+       } else if (!error && !intf->dev.power.is_prepared) {
                r = usb_set_interface(udev, intf->altsetting[0].
                                desc.bInterfaceNumber, 0);
                if (r < 0)
@@ -960,7 +960,7 @@ void usb_rebind_intf(struct usb_interface *intf)
        }
 
        /* Try to rebind the interface */
-       if (!intf->dev.power.in_suspend) {
+       if (!intf->dev.power.is_prepared) {
                intf->needs_binding = 0;
                rc = device_attach(&intf->dev);
                if (rc < 0)
@@ -1107,7 +1107,7 @@ static int usb_resume_interface(struct usb_device *udev,
        if (intf->condition == USB_INTERFACE_UNBOUND) {
 
                /* Carry out a deferred switch to altsetting 0 */
-               if (intf->needs_altsetting0 && !intf->dev.power.in_suspend) {
+               if (intf->needs_altsetting0 && !intf->dev.power.is_prepared) {
                        usb_set_interface(udev, intf->altsetting[0].
                                        desc.bInterfaceNumber, 0);
                        intf->needs_altsetting0 = 0;
index 79a58c3a2e2a3a254b48a9f2fb7ac78c5c3bd27e..90ae1753dda16bab13f0cebb759d961fb5598cbc 100644 (file)
@@ -339,7 +339,8 @@ static int get_hub_status(struct usb_device *hdev,
 {
        int i, status = -ETIMEDOUT;
 
-       for (i = 0; i < USB_STS_RETRIES && status == -ETIMEDOUT; i++) {
+       for (i = 0; i < USB_STS_RETRIES &&
+                       (status == -ETIMEDOUT || status == -EPIPE); i++) {
                status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
                        USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
                        data, sizeof(*data), USB_STS_TIMEOUT);
@@ -355,7 +356,8 @@ static int get_port_status(struct usb_device *hdev, int port1,
 {
        int i, status = -ETIMEDOUT;
 
-       for (i = 0; i < USB_STS_RETRIES && status == -ETIMEDOUT; i++) {
+       for (i = 0; i < USB_STS_RETRIES &&
+                       (status == -ETIMEDOUT || status == -EPIPE); i++) {
                status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
                        USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port1,
                        data, sizeof(*data), USB_STS_TIMEOUT);
index 1b125c224dcf8d4d73f5a094edb6f4417c8e88e4..2278dad886e2e8b028b2809eb39ccba8c09dff46 100644 (file)
@@ -389,7 +389,6 @@ static int usbfs_rmdir(struct inode *dir, struct dentry *dentry)
        mutex_unlock(&inode->i_mutex);
        if (!error)
                d_delete(dentry);
-       dput(dentry);
        return error;
 }
 
index 58456d1aec21611dcb395ef343ce80e4c9bc315e..029e288805b6c1ab1eeb99d6235093b0b4ee1058 100644 (file)
@@ -632,13 +632,10 @@ config USB_DUMMY_HCD
 
 endchoice
 
+# Selected by UDC drivers that support high-speed operation.
 config USB_GADGET_DUALSPEED
        bool
        depends on USB_GADGET
-       default n
-       help
-         Means that gadget drivers should include extra descriptors
-         and code to handle dual-speed controllers.
 
 #
 # USB Gadget Drivers
index 6e42aab75806e12c58e7b572e1dc953a13a32fa0..95e8138cd48fd9ff9be91f170777f562d3c88ede 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/device.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/prefetch.h>
 
 #include <asm/byteorder.h>
 #include <asm/system.h>
index 41dc093c0a1b943fa44a69629dbd19e8cc5f098c..f4690ffcb4890af84e0ba88a82dd929e3e2fab82 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/clk.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/prefetch.h>
 
 #include <asm/byteorder.h>
 #include <mach/hardware.h>
index 61ff927928ab9620231eddce21056a4160488e5f..d3dcabc1a5fca0e7ad221236285d4064b69abd0d 100644 (file)
@@ -1906,6 +1906,7 @@ static int dummy_hcd_probe(struct platform_device *pdev)
        if (!hcd)
                return -ENOMEM;
        the_controller = hcd_to_dummy (hcd);
+       hcd->has_tt = 1;
 
        retval = usb_add_hcd(hcd, 0, 0);
        if (retval != 0) {
index a01383f71f38639c5539f5b82431ef1186ee6b60..a56876aaf76cdc1dfbec0a331f70739a2a27b04f 100644 (file)
@@ -431,8 +431,10 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 
        /* halt any endpoint by doing a "wrong direction" i/o call */
        if (!usb_endpoint_dir_in(&data->desc)) {
-               if (usb_endpoint_xfer_isoc(&data->desc))
+               if (usb_endpoint_xfer_isoc(&data->desc)) {
+                       mutex_unlock(&data->lock);
                        return -EINVAL;
+               }
                DBG (data->dev, "%s halt\n", data->name);
                spin_lock_irq (&data->dev->lock);
                if (likely (data->ep != NULL))
index b62b2640deb0b7c9e6a0f9cf81f2c8242fdf37d1..b1a8146b9d50d4180ca762e9ab47c7f41899d736 100644 (file)
@@ -2083,7 +2083,7 @@ out:
 }
 
 #ifdef CONFIG_PM
-static int mv_udc_suspend(struct platform_device *_dev, pm_message_t state)
+static int mv_udc_suspend(struct device *_dev)
 {
        struct mv_udc *udc = the_controller;
 
@@ -2092,7 +2092,7 @@ static int mv_udc_suspend(struct platform_device *_dev, pm_message_t state)
        return 0;
 }
 
-static int mv_udc_resume(struct platform_device *_dev)
+static int mv_udc_resume(struct device *_dev)
 {
        struct mv_udc *udc = the_controller;
        int retval;
@@ -2100,7 +2100,7 @@ static int mv_udc_resume(struct platform_device *_dev)
        retval = mv_udc_phy_init(udc->phy_regs);
        if (retval) {
                dev_err(_dev, "phy initialization error %d\n", retval);
-               goto error;
+               return retval;
        }
        udc_reset(udc);
        ep0_reset(udc);
@@ -2122,7 +2122,7 @@ static struct platform_driver udc_driver = {
                .owner  = THIS_MODULE,
                .name   = "pxa-u2o",
 #ifdef CONFIG_PM
-               .pm     = mv_udc_pm_ops,
+               .pm     = &mv_udc_pm_ops,
 #endif
        },
 };
index 24696f7fa6a9a7a412c229f8667edd1895e1226d..476d88e1ae97daaaf67dd78b5e8565b9ff7d7e9e 100644 (file)
@@ -63,6 +63,7 @@
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/prefetch.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
index 365c02fc25fcf0f89668b79ce2a72933ada22a40..774545494cf222ed8515474f48d5d346317c5619 100644 (file)
@@ -2216,7 +2216,6 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
                if (retval != 0) {
                        pr_err("%s: can't get irq %i, err %d\n",
                                driver_name, LUBBOCK_USB_DISC_IRQ, retval);
-lubbock_fail0:
                        goto err_irq_lub;
                }
                retval = request_irq(LUBBOCK_USB_IRQ,
@@ -2226,7 +2225,6 @@ lubbock_fail0:
                if (retval != 0) {
                        pr_err("%s: can't get irq %i, err %d\n",
                                driver_name, LUBBOCK_USB_IRQ, retval);
-                       free_irq(LUBBOCK_USB_DISC_IRQ, dev);
                        goto lubbock_fail0;
                }
        } else
@@ -2236,10 +2234,11 @@ lubbock_fail0:
        return 0;
 
 #ifdef CONFIG_ARCH_LUBBOCK
+lubbock_fail0:
        free_irq(LUBBOCK_USB_DISC_IRQ, dev);
  err_irq_lub:
-#endif
        free_irq(irq, dev);
+#endif
  err_irq1:
        if (gpio_is_valid(dev->mach->gpio_pullup))
                gpio_free(dev->mach->gpio_pullup);
index acb9cc418df9a59b4db4ee57bdcbe68144475d6e..0dfee282878a86ef70fdd9b03bb09c1cf9823108 100644 (file)
@@ -2680,9 +2680,9 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 
        writel(0, hsotg->regs + S3C_DAINTMSK);
 
-       dev_info(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
-                readl(hsotg->regs + S3C_DIEPCTL0),
-                readl(hsotg->regs + S3C_DOEPCTL0));
+       dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
+               readl(hsotg->regs + S3C_DIEPCTL0),
+               readl(hsotg->regs + S3C_DOEPCTL0));
 
        /* enable in and out endpoint interrupts */
        s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt);
@@ -2701,7 +2701,7 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
        udelay(10);  /* see openiboot */
        __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_PWROnPrgDone);
 
-       dev_info(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + S3C_DCTL));
+       dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + S3C_DCTL));
 
        /* S3C_DxEPCTL_USBActEp says RO in manual, but seems to be set by
           writing to the EPCTL register.. */
@@ -2721,9 +2721,9 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 
        s3c_hsotg_enqueue_setup(hsotg);
 
-       dev_info(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
-                readl(hsotg->regs + S3C_DIEPCTL0),
-                readl(hsotg->regs + S3C_DOEPCTL0));
+       dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
+               readl(hsotg->regs + S3C_DIEPCTL0),
+               readl(hsotg->regs + S3C_DOEPCTL0));
 
        /* clear global NAKs */
        writel(S3C_DCTL_CGOUTNak | S3C_DCTL_CGNPInNAK,
@@ -2921,9 +2921,9 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
 
        /* setup fifos */
 
-       dev_info(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
-                readl(hsotg->regs + S3C_GRXFSIZ),
-                readl(hsotg->regs + S3C_GNPTXFSIZ));
+       dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
+               readl(hsotg->regs + S3C_GRXFSIZ),
+               readl(hsotg->regs + S3C_GNPTXFSIZ));
 
        s3c_hsotg_init_fifo(hsotg);
 
@@ -2945,6 +2945,7 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
 
 static void s3c_hsotg_dump(struct s3c_hsotg *hsotg)
 {
+#ifdef DEBUG
        struct device *dev = hsotg->dev;
        void __iomem *regs = hsotg->regs;
        u32 val;
@@ -2987,6 +2988,7 @@ static void s3c_hsotg_dump(struct s3c_hsotg *hsotg)
 
        dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n",
                 readl(regs + S3C_DVBUSDIS), readl(regs + S3C_DVBUSPULSE));
+#endif
 }
 
 
index cfe3cf56d6bd5e531682f928b02023b6c863660e..d5e3e1e586265c093a1002664af6f55cebb883bd 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/clk.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/prefetch.h>
 
 #include <mach/regs-s3c2443-clock.h>
 #include <plat/udc.h>
@@ -1301,7 +1302,8 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
        hsudc->uclk = clk_get(&pdev->dev, "usb-device");
        if (IS_ERR(hsudc->uclk)) {
                dev_err(dev, "failed to find usb-device clock source\n");
-               return PTR_ERR(hsudc->uclk);
+               ret = PTR_ERR(hsudc->uclk);
+               goto err_clk;
        }
        clk_enable(hsudc->uclk);
 
@@ -1310,7 +1312,8 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
        disable_irq(hsudc->irq);
        local_irq_enable();
        return 0;
-
+err_clk:
+       free_irq(hsudc->irq, hsudc);
 err_irq:
        iounmap(hsudc->regs);
 
index 6d8b04061d5d6772f076c9792315a8ee8c42499d..100f2635cf0a1d2ee3ef0a175c685e6f35a2b213 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/gpio.h>
+#include <linux/prefetch.h>
 
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
index 660b80a75cacc1e8953022e94819dea6eafa2382..1102ce65a3a9eff69fee9c612f65f4a6ead9c3a9 100644 (file)
@@ -348,11 +348,50 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
        return rc;
 }
 
+static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
+{
+       return pdev->class == PCI_CLASS_SERIAL_USB_EHCI &&
+               pdev->vendor == PCI_VENDOR_ID_INTEL &&
+               pdev->device == 0x1E26;
+}
+
+static void ehci_enable_xhci_companion(void)
+{
+       struct pci_dev          *companion = NULL;
+
+       /* The xHCI and EHCI controllers are not on the same PCI slot */
+       for_each_pci_dev(companion) {
+               if (!usb_is_intel_switchable_xhci(companion))
+                       continue;
+               usb_enable_xhci_ports(companion);
+               return;
+       }
+}
+
 static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
        struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
 
+       /* The BIOS on systems with the Intel Panther Point chipset may or may
+        * not support xHCI natively.  That means that during system resume, it
+        * may switch the ports back to EHCI so that users can use their
+        * keyboard to select a kernel from GRUB after resume from hibernate.
+        *
+        * The BIOS is supposed to remember whether the OS had xHCI ports
+        * enabled before resume, and switch the ports back to xHCI when the
+        * BIOS/OS semaphore is written, but we all know we can't trust BIOS
+        * writers.
+        *
+        * Unconditionally switch the ports back to xHCI after a system resume.
+        * We can't tell whether the EHCI or xHCI controller will be resumed
+        * first, so we have to do the port switchover in both drivers.  Writing
+        * a '1' to the port switchover registers should have no effect if the
+        * port was already switched over.
+        */
+       if (usb_is_intel_switchable_ehci(pdev))
+               ehci_enable_xhci_companion();
+
        // maybe restore FLADJ
 
        if (time_before(jiffies, ehci->next_statechange))
index afef7b0a419567ab92643d0809a1da5f1a4f13a9..80be5472783a4f30e8a791a205958f176ff2dbf1 100644 (file)
@@ -312,8 +312,10 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
                return PTR_ERR(usb_clk);
 
        hcd = usb_create_hcd (driver, &pdev->dev, "pxa27x");
-       if (!hcd)
-               return -ENOMEM;
+       if (!hcd) {
+               retval = -ENOMEM;
+               goto err0;
+       }
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!r) {
@@ -368,6 +370,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
  err1:
        usb_put_hcd(hcd);
+ err0:
        clk_put(usb_clk);
        return retval;
 }
index f16c59d5f48702cb4abb4c7bab1cc6e811ffda19..fd930618c28f2d250b1722b716502ba2327f4ae6 100644 (file)
@@ -69,6 +69,9 @@
 #define        NB_PIF0_PWRDOWN_0       0x01100012
 #define        NB_PIF0_PWRDOWN_1       0x01100013
 
+#define USB_INTEL_XUSB2PR      0xD0
+#define USB_INTEL_USB3_PSSEN   0xD8
+
 static struct amd_chipset_info {
        struct pci_dev  *nb_dev;
        struct pci_dev  *smbus_dev;
@@ -673,6 +676,64 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done,
        return -ETIMEDOUT;
 }
 
+bool usb_is_intel_switchable_xhci(struct pci_dev *pdev)
+{
+       return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
+               pdev->vendor == PCI_VENDOR_ID_INTEL &&
+               pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI;
+}
+EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci);
+
+/*
+ * Intel's Panther Point chipset has two host controllers (EHCI and xHCI) that
+ * share some number of ports.  These ports can be switched between either
+ * controller.  Not all of the ports under the EHCI host controller may be
+ * switchable.
+ *
+ * The ports should be switched over to xHCI before PCI probes for any device
+ * start.  This avoids active devices under EHCI being disconnected during the
+ * port switchover, which could cause loss of data on USB storage devices, or
+ * failed boot when the root file system is on a USB mass storage device and is
+ * enumerated under EHCI first.
+ *
+ * We write into the xHC's PCI configuration space in some Intel-specific
+ * registers to switch the ports over.  The USB 3.0 terminations and the USB
+ * 2.0 data wires are switched separately.  We want to enable the SuperSpeed
+ * terminations before switching the USB 2.0 wires over, so that USB 3.0
+ * devices connect at SuperSpeed, rather than at USB 2.0 speeds.
+ */
+void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
+{
+       u32             ports_available;
+
+       ports_available = 0xffffffff;
+       /* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable
+        * Register, to turn on SuperSpeed terminations for all
+        * available ports.
+        */
+       pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,
+                       cpu_to_le32(ports_available));
+
+       pci_read_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,
+                       &ports_available);
+       dev_dbg(&xhci_pdev->dev, "USB 3.0 ports that are now enabled "
+                       "under xHCI: 0x%x\n", ports_available);
+
+       ports_available = 0xffffffff;
+       /* Write XUSB2PR, the xHC USB 2.0 Port Routing Register, to
+        * switch the USB 2.0 power and data lines over to the xHCI
+        * host.
+        */
+       pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
+                       cpu_to_le32(ports_available));
+
+       pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
+                       &ports_available);
+       dev_dbg(&xhci_pdev->dev, "USB 2.0 ports that are now switched over "
+                       "to xHCI: 0x%x\n", ports_available);
+}
+EXPORT_SYMBOL_GPL(usb_enable_xhci_ports);
+
 /**
  * PCI Quirks for xHCI.
  *
@@ -732,6 +793,8 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
        writel(XHCI_LEGACY_DISABLE_SMI,
                        base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
 
+       if (usb_is_intel_switchable_xhci(pdev))
+               usb_enable_xhci_ports(pdev);
 hc_init:
        op_reg_base = base + XHCI_HC_LENGTH(readl(base));
 
index 6ae9f78e993876c384f6540263f6935b8bfcdd4e..b1002a8ef96f58fc46039d6c37b4bcca18d056cb 100644 (file)
@@ -8,6 +8,8 @@ int usb_amd_find_chipset_info(void);
 void usb_amd_dev_put(void);
 void usb_amd_quirk_pll_disable(void);
 void usb_amd_quirk_pll_enable(void);
+bool usb_is_intel_switchable_xhci(struct pci_dev *pdev);
+void usb_enable_xhci_ports(struct pci_dev *xhci_pdev);
 #else
 static inline void usb_amd_quirk_pll_disable(void) {}
 static inline void usb_amd_quirk_pll_enable(void) {}
index 3775c035a6c56c994078357e9f1a55c5b2b02312..3b6f50eaec9134f596cd15958464578fea8ae1e6 100644 (file)
@@ -187,7 +187,7 @@ static int sl811_cs_probe(struct pcmcia_device *link)
        return sl811_cs_config(link);
 }
 
-static struct pcmcia_device_id sl811_ids[] = {
+static const struct pcmcia_device_id sl811_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0xc015, 0x0001), /* RATOC USB HOST CF+ Card */
        PCMCIA_DEVICE_NULL,
 };
index 2e0486178dbe4c45dd984eab0663bd3a2d97f392..1f50b4468e87bfe90f7b14b1327187a7395609f3 100644 (file)
@@ -438,13 +438,13 @@ char *xhci_get_slot_state(struct xhci_hcd *xhci,
        struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx);
 
        switch (GET_SLOT_STATE(le32_to_cpu(slot_ctx->dev_state))) {
-       case 0:
+       case SLOT_STATE_ENABLED:
                return "enabled/disabled";
-       case 1:
+       case SLOT_STATE_DEFAULT:
                return "default";
-       case 2:
+       case SLOT_STATE_ADDRESSED:
                return "addressed";
-       case 3:
+       case SLOT_STATE_CONFIGURED:
                return "configured";
        default:
                return "reserved";
index 26caba4c1950a04dc71488d33fcca3328b7cb391..0f8e1d29a858e6c5e00e287a11f8ff1ba2b212e1 100644 (file)
@@ -985,9 +985,19 @@ static unsigned int xhci_parse_exponent_interval(struct usb_device *udev,
        interval = clamp_val(ep->desc.bInterval, 1, 16) - 1;
        if (interval != ep->desc.bInterval - 1)
                dev_warn(&udev->dev,
-                        "ep %#x - rounding interval to %d microframes\n",
+                        "ep %#x - rounding interval to %d %sframes\n",
                         ep->desc.bEndpointAddress,
-                        1 << interval);
+                        1 << interval,
+                        udev->speed == USB_SPEED_FULL ? "" : "micro");
+
+       if (udev->speed == USB_SPEED_FULL) {
+               /*
+                * Full speed isoc endpoints specify interval in frames,
+                * not microframes. We are using microframes everywhere,
+                * so adjust accordingly.
+                */
+               interval += 3;  /* 1 frame = 2^3 uframes */
+       }
 
        return interval;
 }
index cbc4d491e62677ada81e90b11320a3d746051749..17541d09eabbc9b867c5be1dcdeba349b45bfa82 100644 (file)
@@ -106,18 +106,34 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
 
        /* Look for vendor-specific quirks */
        if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
-                       pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK &&
-                       pdev->revision == 0x0) {
+                       pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK) {
+               if (pdev->revision == 0x0) {
                        xhci->quirks |= XHCI_RESET_EP_QUIRK;
                        xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure"
                                        " endpoint cmd after reset endpoint\n");
+               }
+               /* Fresco Logic confirms: all revisions of this chip do not
+                * support MSI, even though some of them claim to in their PCI
+                * capabilities.
+                */
+               xhci->quirks |= XHCI_BROKEN_MSI;
+               xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u "
+                               "has broken MSI implementation\n",
+                               pdev->revision);
        }
+
        if (pdev->vendor == PCI_VENDOR_ID_NEC)
                xhci->quirks |= XHCI_NEC_HOST;
 
        /* AMD PLL quirk */
        if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
                xhci->quirks |= XHCI_AMD_PLL_FIX;
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+                       pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) {
+               xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
+               xhci->quirks |= XHCI_EP_LIMIT_QUIRK;
+               xhci->limit_active_eps = 64;
+       }
 
        /* Make sure the HC is halted. */
        retval = xhci_halt(xhci);
@@ -242,8 +258,28 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
 static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
 {
        struct xhci_hcd         *xhci = hcd_to_xhci(hcd);
+       struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
        int                     retval = 0;
 
+       /* The BIOS on systems with the Intel Panther Point chipset may or may
+        * not support xHCI natively.  That means that during system resume, it
+        * may switch the ports back to EHCI so that users can use their
+        * keyboard to select a kernel from GRUB after resume from hibernate.
+        *
+        * The BIOS is supposed to remember whether the OS had xHCI ports
+        * enabled before resume, and switch the ports back to xHCI when the
+        * BIOS/OS semaphore is written, but we all know we can't trust BIOS
+        * writers.
+        *
+        * Unconditionally switch the ports back to xHCI after a system resume.
+        * We can't tell whether the EHCI or xHCI controller will be resumed
+        * first, so we have to do the port switchover in both drivers.  Writing
+        * a '1' to the port switchover registers should have no effect if the
+        * port was already switched over.
+        */
+       if (usb_is_intel_switchable_xhci(pdev))
+               usb_enable_xhci_ports(pdev);
+
        retval = xhci_resume(xhci, hibernated);
        return retval;
 }
index 237a765f8d187eb6312d35365f20bd9afae7c913..800f417c730900271a98ccf0410d7617afc3aa20 100644 (file)
@@ -167,12 +167,6 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
                next = ring->dequeue;
        }
        addr = (unsigned long long) xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue);
-       if (ring == xhci->event_ring)
-               xhci_dbg(xhci, "Event ring deq = 0x%llx (DMA)\n", addr);
-       else if (ring == xhci->cmd_ring)
-               xhci_dbg(xhci, "Command ring deq = 0x%llx (DMA)\n", addr);
-       else
-               xhci_dbg(xhci, "Ring deq = 0x%llx (DMA)\n", addr);
 }
 
 /*
@@ -248,12 +242,6 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
                next = ring->enqueue;
        }
        addr = (unsigned long long) xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue);
-       if (ring == xhci->event_ring)
-               xhci_dbg(xhci, "Event ring enq = 0x%llx (DMA)\n", addr);
-       else if (ring == xhci->cmd_ring)
-               xhci_dbg(xhci, "Command ring enq = 0x%llx (DMA)\n", addr);
-       else
-               xhci_dbg(xhci, "Ring enq = 0x%llx (DMA)\n", addr);
 }
 
 /*
@@ -636,13 +624,11 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci,
                        }
                }
                usb_hcd_unlink_urb_from_ep(hcd, urb);
-               xhci_dbg(xhci, "Giveback %s URB %p\n", adjective, urb);
 
                spin_unlock(&xhci->lock);
                usb_hcd_giveback_urb(hcd, urb, status);
                xhci_urb_free_priv(xhci, urb_priv);
                spin_lock(&xhci->lock);
-               xhci_dbg(xhci, "%s URB given back\n", adjective);
        }
 }
 
@@ -692,6 +678,8 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
 
        if (list_empty(&ep->cancelled_td_list)) {
                xhci_stop_watchdog_timer_in_irq(xhci, ep);
+               ep->stopped_td = NULL;
+               ep->stopped_trb = NULL;
                ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
                return;
        }
@@ -1093,8 +1081,13 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
                complete(&xhci->addr_dev);
                break;
        case TRB_TYPE(TRB_DISABLE_SLOT):
-               if (xhci->devs[slot_id])
+               if (xhci->devs[slot_id]) {
+                       if (xhci->quirks & XHCI_EP_LIMIT_QUIRK)
+                               /* Delete default control endpoint resources */
+                               xhci_free_device_endpoint_resources(xhci,
+                                               xhci->devs[slot_id], true);
                        xhci_free_virt_device(xhci, slot_id);
+               }
                break;
        case TRB_TYPE(TRB_CONFIG_EP):
                virt_dev = xhci->devs[slot_id];
@@ -1630,7 +1623,6 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
                                        "without IOC set??\n");
                        *status = -ESHUTDOWN;
                } else {
-                       xhci_dbg(xhci, "Successful control transfer!\n");
                        *status = 0;
                }
                break;
@@ -1727,7 +1719,6 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
        switch (trb_comp_code) {
        case COMP_SUCCESS:
                frame->status = 0;
-               xhci_dbg(xhci, "Successful isoc transfer!\n");
                break;
        case COMP_SHORT_TX:
                frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ?
@@ -1791,7 +1782,7 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
        struct usb_iso_packet_descriptor *frame;
        int idx;
 
-       ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
+       ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer));
        urb_priv = td->urb->hcpriv;
        idx = urb_priv->td_cnt;
        frame = &td->urb->iso_frame_desc[idx];
@@ -1837,12 +1828,6 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
                        else
                                *status = 0;
                } else {
-                       if (usb_endpoint_xfer_bulk(&td->urb->ep->desc))
-                               xhci_dbg(xhci, "Successful bulk "
-                                               "transfer!\n");
-                       else
-                               xhci_dbg(xhci, "Successful interrupt "
-                                               "transfer!\n");
                        *status = 0;
                }
                break;
@@ -1856,11 +1841,12 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
                /* Others already handled above */
                break;
        }
-       xhci_dbg(xhci, "ep %#x - asked for %d bytes, "
-                       "%d bytes untransferred\n",
-                       td->urb->ep->desc.bEndpointAddress,
-                       td->urb->transfer_buffer_length,
-                TRB_LEN(le32_to_cpu(event->transfer_len)));
+       if (trb_comp_code == COMP_SHORT_TX)
+               xhci_dbg(xhci, "ep %#x - asked for %d bytes, "
+                               "%d bytes untransferred\n",
+                               td->urb->ep->desc.bEndpointAddress,
+                               td->urb->transfer_buffer_length,
+                               TRB_LEN(le32_to_cpu(event->transfer_len)));
        /* Fast path - was this the last TRB in the TD for this URB? */
        if (event_trb == td->last_trb) {
                if (TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
@@ -1954,7 +1940,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
 
        /* Endpoint ID is 1 based, our index is zero based */
        ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
-       xhci_dbg(xhci, "%s - ep index = %d\n", __func__, ep_index);
        ep = &xdev->eps[ep_index];
        ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer));
        ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
@@ -2081,6 +2066,16 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                if (!event_seg) {
                        if (!ep->skip ||
                            !usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
+                               /* Some host controllers give a spurious
+                                * successful event after a short transfer.
+                                * Ignore it.
+                                */
+                               if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) && 
+                                               ep_ring->last_td_was_short) {
+                                       ep_ring->last_td_was_short = false;
+                                       ret = 0;
+                                       goto cleanup;
+                               }
                                /* HC is busted, give up! */
                                xhci_err(xhci,
                                        "ERROR Transfer event TRB DMA ptr not "
@@ -2091,6 +2086,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                        ret = skip_isoc_td(xhci, td, event, ep, &status);
                        goto cleanup;
                }
+               if (trb_comp_code == COMP_SHORT_TX)
+                       ep_ring->last_td_was_short = true;
+               else
+                       ep_ring->last_td_was_short = false;
 
                if (ep->skip) {
                        xhci_dbg(xhci, "Found td. Clear skip flag.\n");
@@ -2149,9 +2148,15 @@ cleanup:
                                xhci_urb_free_priv(xhci, urb_priv);
 
                        usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
-                       xhci_dbg(xhci, "Giveback URB %p, len = %d, "
-                                       "status = %d\n",
-                                       urb, urb->actual_length, status);
+                       if ((urb->actual_length != urb->transfer_buffer_length &&
+                                               (urb->transfer_flags &
+                                                URB_SHORT_NOT_OK)) ||
+                                       status != 0)
+                               xhci_dbg(xhci, "Giveback URB %p, len = %d, "
+                                               "expected = %x, status = %d\n",
+                                               urb, urb->actual_length,
+                                               urb->transfer_buffer_length,
+                                               status);
                        spin_unlock(&xhci->lock);
                        usb_hcd_giveback_urb(bus_to_hcd(urb->dev->bus), urb, status);
                        spin_lock(&xhci->lock);
@@ -2180,7 +2185,6 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
        int update_ptrs = 1;
        int ret;
 
-       xhci_dbg(xhci, "In %s\n", __func__);
        if (!xhci->event_ring || !xhci->event_ring->dequeue) {
                xhci->error_bitmask |= 1 << 1;
                return 0;
@@ -2193,7 +2197,6 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
                xhci->error_bitmask |= 1 << 2;
                return 0;
        }
-       xhci_dbg(xhci, "%s - OS owns TRB\n", __func__);
 
        /*
         * Barrier between reading the TRB_CYCLE (valid) flag above and any
@@ -2203,20 +2206,14 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
        /* FIXME: Handle more event types. */
        switch ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK)) {
        case TRB_TYPE(TRB_COMPLETION):
-               xhci_dbg(xhci, "%s - calling handle_cmd_completion\n", __func__);
                handle_cmd_completion(xhci, &event->event_cmd);
-               xhci_dbg(xhci, "%s - returned from handle_cmd_completion\n", __func__);
                break;
        case TRB_TYPE(TRB_PORT_STATUS):
-               xhci_dbg(xhci, "%s - calling handle_port_status\n", __func__);
                handle_port_status(xhci, event);
-               xhci_dbg(xhci, "%s - returned from handle_port_status\n", __func__);
                update_ptrs = 0;
                break;
        case TRB_TYPE(TRB_TRANSFER):
-               xhci_dbg(xhci, "%s - calling handle_tx_event\n", __func__);
                ret = handle_tx_event(xhci, &event->trans_event);
-               xhci_dbg(xhci, "%s - returned from handle_tx_event\n", __func__);
                if (ret < 0)
                        xhci->error_bitmask |= 1 << 9;
                else
@@ -2273,16 +2270,6 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
                spin_unlock(&xhci->lock);
                return IRQ_NONE;
        }
-       xhci_dbg(xhci, "op reg status = %08x\n", status);
-       xhci_dbg(xhci, "Event ring dequeue ptr:\n");
-       xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n",
-                (unsigned long long)
-                xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, trb),
-                lower_32_bits(le64_to_cpu(trb->link.segment_ptr)),
-                upper_32_bits(le64_to_cpu(trb->link.segment_ptr)),
-                (unsigned int) le32_to_cpu(trb->link.intr_target),
-                (unsigned int) le32_to_cpu(trb->link.control));
-
        if (status & STS_FATAL) {
                xhci_warn(xhci, "WARNING: Host System Error\n");
                xhci_halt(xhci);
@@ -2397,7 +2384,6 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
                u32 ep_state, unsigned int num_trbs, gfp_t mem_flags)
 {
        /* Make sure the endpoint has been added to xHC schedule */
-       xhci_dbg(xhci, "Endpoint state = 0x%x\n", ep_state);
        switch (ep_state) {
        case EP_STATE_DISABLED:
                /*
@@ -2434,7 +2420,6 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
                struct xhci_ring *ring = ep_ring;
                union xhci_trb *next;
 
-               xhci_dbg(xhci, "prepare_ring: pointing to link trb\n");
                next = ring->enqueue;
 
                while (last_trb(xhci, ring, ring->enq_seg, next)) {
index 8f2a56ece44f7add6b7cb79b453e9b42ca02d1f9..06e7023258d0f4e3e4b603d6c2ae68b1fbd38f4f 100644 (file)
@@ -430,12 +430,19 @@ int xhci_run(struct usb_hcd *hcd)
                free_irq(hcd->irq, hcd);
        hcd->irq = -1;
 
+       /* Some Fresco Logic host controllers advertise MSI, but fail to
+        * generate interrupts.  Don't even try to enable MSI.
+        */
+       if (xhci->quirks & XHCI_BROKEN_MSI)
+               goto legacy_irq;
+
        ret = xhci_setup_msix(xhci);
        if (ret)
                /* fall back to msi*/
                ret = xhci_setup_msi(xhci);
 
        if (ret) {
+legacy_irq:
                /* fall back to legacy interrupt*/
                ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,
                                        hcd->irq_descr, hcd);
@@ -1314,8 +1321,10 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
        if (ret <= 0)
                return ret;
        xhci = hcd_to_xhci(hcd);
-       xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
+       if (xhci->xhc_state & XHCI_STATE_DYING)
+               return -ENODEV;
 
+       xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
        drop_flag = xhci_get_endpoint_flag(&ep->desc);
        if (drop_flag == SLOT_FLAG || drop_flag == EP0_FLAG) {
                xhci_dbg(xhci, "xHCI %s - can't drop slot or ep 0 %#x\n",
@@ -1401,6 +1410,8 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
                return ret;
        }
        xhci = hcd_to_xhci(hcd);
+       if (xhci->xhc_state & XHCI_STATE_DYING)
+               return -ENODEV;
 
        added_ctxs = xhci_get_endpoint_flag(&ep->desc);
        last_ctx = xhci_last_valid_endpoint(added_ctxs);
@@ -1578,6 +1589,113 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
        return ret;
 }
 
+static u32 xhci_count_num_new_endpoints(struct xhci_hcd *xhci,
+               struct xhci_container_ctx *in_ctx)
+{
+       struct xhci_input_control_ctx *ctrl_ctx;
+       u32 valid_add_flags;
+       u32 valid_drop_flags;
+
+       ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
+       /* Ignore the slot flag (bit 0), and the default control endpoint flag
+        * (bit 1).  The default control endpoint is added during the Address
+        * Device command and is never removed until the slot is disabled.
+        */
+       valid_add_flags = ctrl_ctx->add_flags >> 2;
+       valid_drop_flags = ctrl_ctx->drop_flags >> 2;
+
+       /* Use hweight32 to count the number of ones in the add flags, or
+        * number of endpoints added.  Don't count endpoints that are changed
+        * (both added and dropped).
+        */
+       return hweight32(valid_add_flags) -
+               hweight32(valid_add_flags & valid_drop_flags);
+}
+
+static unsigned int xhci_count_num_dropped_endpoints(struct xhci_hcd *xhci,
+               struct xhci_container_ctx *in_ctx)
+{
+       struct xhci_input_control_ctx *ctrl_ctx;
+       u32 valid_add_flags;
+       u32 valid_drop_flags;
+
+       ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
+       valid_add_flags = ctrl_ctx->add_flags >> 2;
+       valid_drop_flags = ctrl_ctx->drop_flags >> 2;
+
+       return hweight32(valid_drop_flags) -
+               hweight32(valid_add_flags & valid_drop_flags);
+}
+
+/*
+ * We need to reserve the new number of endpoints before the configure endpoint
+ * command completes.  We can't subtract the dropped endpoints from the number
+ * of active endpoints until the command completes because we can oversubscribe
+ * the host in this case:
+ *
+ *  - the first configure endpoint command drops more endpoints than it adds
+ *  - a second configure endpoint command that adds more endpoints is queued
+ *  - the first configure endpoint command fails, so the config is unchanged
+ *  - the second command may succeed, even though there isn't enough resources
+ *
+ * Must be called with xhci->lock held.
+ */
+static int xhci_reserve_host_resources(struct xhci_hcd *xhci,
+               struct xhci_container_ctx *in_ctx)
+{
+       u32 added_eps;
+
+       added_eps = xhci_count_num_new_endpoints(xhci, in_ctx);
+       if (xhci->num_active_eps + added_eps > xhci->limit_active_eps) {
+               xhci_dbg(xhci, "Not enough ep ctxs: "
+                               "%u active, need to add %u, limit is %u.\n",
+                               xhci->num_active_eps, added_eps,
+                               xhci->limit_active_eps);
+               return -ENOMEM;
+       }
+       xhci->num_active_eps += added_eps;
+       xhci_dbg(xhci, "Adding %u ep ctxs, %u now active.\n", added_eps,
+                       xhci->num_active_eps);
+       return 0;
+}
+
+/*
+ * The configure endpoint was failed by the xHC for some other reason, so we
+ * need to revert the resources that failed configuration would have used.
+ *
+ * Must be called with xhci->lock held.
+ */
+static void xhci_free_host_resources(struct xhci_hcd *xhci,
+               struct xhci_container_ctx *in_ctx)
+{
+       u32 num_failed_eps;
+
+       num_failed_eps = xhci_count_num_new_endpoints(xhci, in_ctx);
+       xhci->num_active_eps -= num_failed_eps;
+       xhci_dbg(xhci, "Removing %u failed ep ctxs, %u now active.\n",
+                       num_failed_eps,
+                       xhci->num_active_eps);
+}
+
+/*
+ * Now that the command has completed, clean up the active endpoint count by
+ * subtracting out the endpoints that were dropped (but not changed).
+ *
+ * Must be called with xhci->lock held.
+ */
+static void xhci_finish_resource_reservation(struct xhci_hcd *xhci,
+               struct xhci_container_ctx *in_ctx)
+{
+       u32 num_dropped_eps;
+
+       num_dropped_eps = xhci_count_num_dropped_endpoints(xhci, in_ctx);
+       xhci->num_active_eps -= num_dropped_eps;
+       if (num_dropped_eps)
+               xhci_dbg(xhci, "Removing %u dropped ep ctxs, %u now active.\n",
+                               num_dropped_eps,
+                               xhci->num_active_eps);
+}
+
 /* Issue a configure endpoint command or evaluate context command
  * and wait for it to finish.
  */
@@ -1598,6 +1716,15 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
        virt_dev = xhci->devs[udev->slot_id];
        if (command) {
                in_ctx = command->in_ctx;
+               if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK) &&
+                               xhci_reserve_host_resources(xhci, in_ctx)) {
+                       spin_unlock_irqrestore(&xhci->lock, flags);
+                       xhci_warn(xhci, "Not enough host resources, "
+                                       "active endpoint contexts = %u\n",
+                                       xhci->num_active_eps);
+                       return -ENOMEM;
+               }
+
                cmd_completion = command->completion;
                cmd_status = &command->status;
                command->command_trb = xhci->cmd_ring->enqueue;
@@ -1613,6 +1740,14 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
                list_add_tail(&command->cmd_list, &virt_dev->cmd_list);
        } else {
                in_ctx = virt_dev->in_ctx;
+               if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK) &&
+                               xhci_reserve_host_resources(xhci, in_ctx)) {
+                       spin_unlock_irqrestore(&xhci->lock, flags);
+                       xhci_warn(xhci, "Not enough host resources, "
+                                       "active endpoint contexts = %u\n",
+                                       xhci->num_active_eps);
+                       return -ENOMEM;
+               }
                cmd_completion = &virt_dev->cmd_completion;
                cmd_status = &virt_dev->cmd_status;
        }
@@ -1627,6 +1762,8 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
        if (ret < 0) {
                if (command)
                        list_del(&command->cmd_list);
+               if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK))
+                       xhci_free_host_resources(xhci, in_ctx);
                spin_unlock_irqrestore(&xhci->lock, flags);
                xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
                return -ENOMEM;
@@ -1649,8 +1786,22 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
        }
 
        if (!ctx_change)
-               return xhci_configure_endpoint_result(xhci, udev, cmd_status);
-       return xhci_evaluate_context_result(xhci, udev, cmd_status);
+               ret = xhci_configure_endpoint_result(xhci, udev, cmd_status);
+       else
+               ret = xhci_evaluate_context_result(xhci, udev, cmd_status);
+
+       if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) {
+               spin_lock_irqsave(&xhci->lock, flags);
+               /* If the command failed, remove the reserved resources.
+                * Otherwise, clean up the estimate to include dropped eps.
+                */
+               if (ret)
+                       xhci_free_host_resources(xhci, in_ctx);
+               else
+                       xhci_finish_resource_reservation(xhci, in_ctx);
+               spin_unlock_irqrestore(&xhci->lock, flags);
+       }
+       return ret;
 }
 
 /* Called after one or more calls to xhci_add_endpoint() or
@@ -1676,6 +1827,8 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
        if (ret <= 0)
                return ret;
        xhci = hcd_to_xhci(hcd);
+       if (xhci->xhc_state & XHCI_STATE_DYING)
+               return -ENODEV;
 
        xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
        virt_dev = xhci->devs[udev->slot_id];
@@ -1703,8 +1856,8 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
 
        /* Free any rings that were dropped, but not changed. */
        for (i = 1; i < 31; ++i) {
-               if ((ctrl_ctx->drop_flags & (1 << (i + 1))) &&
-                               !(ctrl_ctx->add_flags & (1 << (i + 1))))
+               if ((le32_to_cpu(ctrl_ctx->drop_flags) & (1 << (i + 1))) &&
+                   !(le32_to_cpu(ctrl_ctx->add_flags) & (1 << (i + 1))))
                        xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
        }
        xhci_zero_in_ctx(xhci, virt_dev);
@@ -2265,6 +2418,34 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
        return 0;
 }
 
+/*
+ * Deletes endpoint resources for endpoints that were active before a Reset
+ * Device command, or a Disable Slot command.  The Reset Device command leaves
+ * the control endpoint intact, whereas the Disable Slot command deletes it.
+ *
+ * Must be called with xhci->lock held.
+ */
+void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci,
+       struct xhci_virt_device *virt_dev, bool drop_control_ep)
+{
+       int i;
+       unsigned int num_dropped_eps = 0;
+       unsigned int drop_flags = 0;
+
+       for (i = (drop_control_ep ? 0 : 1); i < 31; i++) {
+               if (virt_dev->eps[i].ring) {
+                       drop_flags |= 1 << i;
+                       num_dropped_eps++;
+               }
+       }
+       xhci->num_active_eps -= num_dropped_eps;
+       if (num_dropped_eps)
+               xhci_dbg(xhci, "Dropped %u ep ctxs, flags = 0x%x, "
+                               "%u now active.\n",
+                               num_dropped_eps, drop_flags,
+                               xhci->num_active_eps);
+}
+
 /*
  * This submits a Reset Device Command, which will set the device state to 0,
  * set the device address to 0, and disable all the endpoints except the default
@@ -2293,6 +2474,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
        struct xhci_command *reset_device_cmd;
        int timeleft;
        int last_freed_endpoint;
+       struct xhci_slot_ctx *slot_ctx;
 
        ret = xhci_check_args(hcd, udev, NULL, 0, false, __func__);
        if (ret <= 0)
@@ -2325,6 +2507,12 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
                        return -EINVAL;
        }
 
+       /* If device is not setup, there is no point in resetting it */
+       slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
+       if (GET_SLOT_STATE(le32_to_cpu(slot_ctx->dev_state)) ==
+                                               SLOT_STATE_DISABLED)
+               return 0;
+
        xhci_dbg(xhci, "Resetting device with slot ID %u\n", slot_id);
        /* Allocate the command structure that holds the struct completion.
         * Assume we're in process context, since the normal device reset
@@ -2406,6 +2594,14 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
                goto command_cleanup;
        }
 
+       /* Free up host controller endpoint resources */
+       if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) {
+               spin_lock_irqsave(&xhci->lock, flags);
+               /* Don't delete the default control endpoint resources */
+               xhci_free_device_endpoint_resources(xhci, virt_dev, false);
+               spin_unlock_irqrestore(&xhci->lock, flags);
+       }
+
        /* Everything but endpoint 0 is disabled, so free or cache the rings. */
        last_freed_endpoint = 1;
        for (i = 1; i < 31; ++i) {
@@ -2478,6 +2674,27 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
         */
 }
 
+/*
+ * Checks if we have enough host controller resources for the default control
+ * endpoint.
+ *
+ * Must be called with xhci->lock held.
+ */
+static int xhci_reserve_host_control_ep_resources(struct xhci_hcd *xhci)
+{
+       if (xhci->num_active_eps + 1 > xhci->limit_active_eps) {
+               xhci_dbg(xhci, "Not enough ep ctxs: "
+                               "%u active, need to add 1, limit is %u.\n",
+                               xhci->num_active_eps, xhci->limit_active_eps);
+               return -ENOMEM;
+       }
+       xhci->num_active_eps += 1;
+       xhci_dbg(xhci, "Adding 1 ep ctx, %u now active.\n",
+                       xhci->num_active_eps);
+       return 0;
+}
+
+
 /*
  * Returns 0 if the xHC ran out of device slots, the Enable Slot command
  * timed out, or allocating memory failed.  Returns 1 on success.
@@ -2513,24 +2730,39 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
                xhci_err(xhci, "Error while assigning device slot ID\n");
                return 0;
        }
-       /* xhci_alloc_virt_device() does not touch rings; no need to lock.
-        * Use GFP_NOIO, since this function can be called from
+
+       if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) {
+               spin_lock_irqsave(&xhci->lock, flags);
+               ret = xhci_reserve_host_control_ep_resources(xhci);
+               if (ret) {
+                       spin_unlock_irqrestore(&xhci->lock, flags);
+                       xhci_warn(xhci, "Not enough host resources, "
+                                       "active endpoint contexts = %u\n",
+                                       xhci->num_active_eps);
+                       goto disable_slot;
+               }
+               spin_unlock_irqrestore(&xhci->lock, flags);
+       }
+       /* Use GFP_NOIO, since this function can be called from
         * xhci_discover_or_reset_device(), which may be called as part of
         * mass storage driver error handling.
         */
        if (!xhci_alloc_virt_device(xhci, xhci->slot_id, udev, GFP_NOIO)) {
-               /* Disable slot, if we can do it without mem alloc */
                xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
-               spin_lock_irqsave(&xhci->lock, flags);
-               if (!xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id))
-                       xhci_ring_cmd_db(xhci);
-               spin_unlock_irqrestore(&xhci->lock, flags);
-               return 0;
+               goto disable_slot;
        }
        udev->slot_id = xhci->slot_id;
        /* Is this a LS or FS device under a HS hub? */
        /* Hub or peripherial? */
        return 1;
+
+disable_slot:
+       /* Disable slot, if we can do it without mem alloc */
+       spin_lock_irqsave(&xhci->lock, flags);
+       if (!xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id))
+               xhci_ring_cmd_db(xhci);
+       spin_unlock_irqrestore(&xhci->lock, flags);
+       return 0;
 }
 
 /*
index e12db7cfb9bb7b63f65e24d46ca51367abf0c754..7d1ea3bf5e1fa0187210f6c89ad87a9f53f1f8e2 100644 (file)
@@ -560,6 +560,11 @@ struct xhci_slot_ctx {
 #define SLOT_STATE     (0x1f << 27)
 #define GET_SLOT_STATE(p)      (((p) & (0x1f << 27)) >> 27)
 
+#define SLOT_STATE_DISABLED    0
+#define SLOT_STATE_ENABLED     SLOT_STATE_DISABLED
+#define SLOT_STATE_DEFAULT     1
+#define SLOT_STATE_ADDRESSED   2
+#define SLOT_STATE_CONFIGURED  3
 
 /**
  * struct xhci_ep_ctx
@@ -1123,6 +1128,7 @@ struct xhci_ring {
         */
        u32                     cycle_state;
        unsigned int            stream_id;
+       bool                    last_td_was_short;
 };
 
 struct xhci_erst_entry {
@@ -1290,6 +1296,20 @@ struct xhci_hcd {
 #define XHCI_RESET_EP_QUIRK    (1 << 1)
 #define XHCI_NEC_HOST          (1 << 2)
 #define XHCI_AMD_PLL_FIX       (1 << 3)
+#define XHCI_SPURIOUS_SUCCESS  (1 << 4)
+/*
+ * Certain Intel host controllers have a limit to the number of endpoint
+ * contexts they can handle.  Ideally, they would signal that they can't handle
+ * anymore endpoint contexts by returning a Resource Error for the Configure
+ * Endpoint command, but they don't.  Instead they expect software to keep track
+ * of the number of active endpoints for them, across configure endpoint
+ * commands, reset device commands, disable slot commands, and address device
+ * commands.
+ */
+#define XHCI_EP_LIMIT_QUIRK    (1 << 5)
+#define XHCI_BROKEN_MSI                (1 << 6)
+       unsigned int            num_active_eps;
+       unsigned int            limit_active_eps;
        /* There are two roothubs to keep track of bus suspend info for */
        struct xhci_bus_state   bus_state[2];
        /* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */
@@ -1338,9 +1358,6 @@ static inline unsigned int xhci_readl(const struct xhci_hcd *xhci,
 static inline void xhci_writel(struct xhci_hcd *xhci,
                const unsigned int val, __le32 __iomem *regs)
 {
-       xhci_dbg(xhci,
-                       "`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n",
-                       regs, val);
        writel(val, regs);
 }
 
@@ -1368,9 +1385,6 @@ static inline void xhci_write_64(struct xhci_hcd *xhci,
        u32 val_lo = lower_32_bits(val);
        u32 val_hi = upper_32_bits(val);
 
-       xhci_dbg(xhci,
-                       "`MEM_WRITE_DWORD(3'b000, 64'h%p, 64'h%0lx, 4'hf);\n",
-                       regs, (long unsigned int) val);
        writel(val_lo, ptr);
        writel(val_hi, ptr + 1);
 }
@@ -1439,6 +1453,8 @@ void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci,
 void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci,
                struct xhci_ep_ctx *ep_ctx,
                struct xhci_virt_ep *ep);
+void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci,
+       struct xhci_virt_device *virt_dev, bool drop_control_ep);
 struct xhci_ring *xhci_dma_to_transfer_ring(
                struct xhci_virt_ep *ep,
                u64 address);
index ab8e1001e5e288ae9fd06417567cc62b4d4897f5..c71b0372786e00482bf2f9fadf4bf6293721d27f 100644 (file)
@@ -96,6 +96,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/kobject.h>
+#include <linux/prefetch.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 
index 3f2e07011a48e533c00c9a23c0303e6ec6030490..cfb5aa72b1962916d87c6c873521d05112bda930 100644 (file)
@@ -100,6 +100,7 @@ struct twl6030_usb {
        u8                      linkstat;
        u8                      asleep;
        bool                    irq_enabled;
+       unsigned long           features;
 };
 
 #define xceiv_to_twl(x)                container_of((x), struct twl6030_usb, otg)
@@ -204,6 +205,12 @@ static int twl6030_start_srp(struct otg_transceiver *x)
 
 static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
 {
+       char *regulator_name;
+
+       if (twl->features & TWL6025_SUBCLASS)
+               regulator_name = "ldousb";
+       else
+               regulator_name = "vusb";
 
        /* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */
        twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG);
@@ -214,7 +221,7 @@ static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
        /* Program MISC2 register and set bit VUSB_IN_VBAT */
        twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, TWL6030_MISC2);
 
-       twl->usb3v3 = regulator_get(twl->dev, "vusb");
+       twl->usb3v3 = regulator_get(twl->dev, regulator_name);
        if (IS_ERR(twl->usb3v3))
                return -ENODEV;
 
@@ -409,6 +416,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
        twl->dev                = &pdev->dev;
        twl->irq1               = platform_get_irq(pdev, 0);
        twl->irq2               = platform_get_irq(pdev, 1);
+       twl->features           = pdata->features;
        twl->otg.dev            = twl->dev;
        twl->otg.label          = "twl6030";
        twl->otg.set_host       = twl6030_set_host;
index 206cfabc92863e0d409e8c76a32bf3129883eeda..547486ccd0592d21a2b2a5ca8bf4480192ffaf73 100644 (file)
@@ -1380,5 +1380,6 @@ void __devexit usbhs_mod_gadget_remove(struct usbhs_priv *priv)
 {
        struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv);
 
+       kfree(gpriv->uep);
        kfree(gpriv);
 }
index e8dbde55f6c51553216b53b7d0c973ac2059c41e..1627289775538eaa2b1967e2547c54717c82baa3 100644 (file)
@@ -647,6 +647,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
        { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_3_PID) },
        { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
        { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_1_PID) },
        { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_2_PID) },
index 1d946cd238ba2989da8bb197a3b0eb8c44f68570..ab1fcdf3c378e954882a8a7db9bc1e4cb672aed8 100644 (file)
  */
 #define FTDI_4N_GALAXY_DE_1_PID        0xF3C0
 #define FTDI_4N_GALAXY_DE_2_PID        0xF3C1
+#define FTDI_4N_GALAXY_DE_3_PID        0xF3C2
 
 /*
  * Linx Technologies product ids
index 318dd00040a3fdb28fbce657d7a3880d12ba505d..60b25d8ea0e2c14376ee4fad71d21a680f0502f7 100644 (file)
@@ -311,10 +311,6 @@ static void option_instat_callback(struct urb *urb);
 #define ZTE_PRODUCT_AC2726                     0xfff5
 #define ZTE_PRODUCT_AC8710T                    0xffff
 
-/* ZTE PRODUCTS -- alternate vendor ID */
-#define ZTE_VENDOR_ID2                         0x1d6b
-#define ZTE_PRODUCT_MF_330                     0x0002
-
 #define BENQ_VENDOR_ID                         0x04a5
 #define BENQ_PRODUCT_H10                       0x4068
 
@@ -340,11 +336,12 @@ static void option_instat_callback(struct urb *urb);
 #define TOSHIBA_PRODUCT_G450                   0x0d45
 
 #define ALINK_VENDOR_ID                                0x1e0e
+#define ALINK_PRODUCT_PH300                    0x9100
 #define ALINK_PRODUCT_3GU                      0x9200
 
 /* ALCATEL PRODUCTS */
 #define ALCATEL_VENDOR_ID                      0x1bbb
-#define ALCATEL_PRODUCT_X060S                  0x0000
+#define ALCATEL_PRODUCT_X060S_X200             0x0000
 
 #define PIRELLI_VENDOR_ID                      0x1266
 #define PIRELLI_PRODUCT_C100_1                 0x1002
@@ -379,6 +376,9 @@ static void option_instat_callback(struct urb *urb);
  * It seems to contain a Qualcomm QSC6240/6290 chipset            */
 #define FOUR_G_SYSTEMS_PRODUCT_W14             0x9603
 
+/* Zoom */
+#define ZOOM_PRODUCT_4597                      0x9607
+
 /* Haier products */
 #define HAIER_VENDOR_ID                                0x201e
 #define HAIER_PRODUCT_CE100                    0x2009
@@ -432,6 +432,20 @@ static const struct option_blacklist_info four_g_w14_blacklist = {
        .reason = OPTION_BLACKLIST_SENDSETUP
 };
 
+static const u8 alcatel_x200_no_sendsetup[] = { 0, 1 };
+static const struct option_blacklist_info alcatel_x200_blacklist = {
+       .infolen = ARRAY_SIZE(alcatel_x200_no_sendsetup),
+       .ifaceinfo = alcatel_x200_no_sendsetup,
+       .reason = OPTION_BLACKLIST_SENDSETUP
+};
+
+static const u8 zte_k3765_z_no_sendsetup[] = { 0, 1, 2 };
+static const struct option_blacklist_info zte_k3765_z_blacklist = {
+       .infolen = ARRAY_SIZE(zte_k3765_z_no_sendsetup),
+       .ifaceinfo = zte_k3765_z_no_sendsetup,
+       .reason = OPTION_BLACKLIST_SENDSETUP
+};
+
 static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -916,13 +930,13 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0073, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0130, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0141, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff,
+         0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710T, 0xff, 0xff, 0xff) },
-       { USB_DEVICE(ZTE_VENDOR_ID2, ZTE_PRODUCT_MF_330) },
        { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
        { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) },
        { USB_DEVICE(ALINK_VENDOR_ID, DLINK_PRODUCT_DWM_652_U5) }, /* Yes, ALINK_VENDOR_ID */
@@ -935,13 +949,17 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_G450) },
        { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */
        { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) },
+       { USB_DEVICE(ALINK_VENDOR_ID, ALINK_PRODUCT_PH300) },
        { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) },
-       { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) },
+       { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200),
+         .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist
+       },
        { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
        { USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) },
        { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14),
          .driver_info = (kernel_ulong_t)&four_g_w14_blacklist
        },
+       { USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) },
        { USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) },
        /* Pirelli  */
        { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_1)},
index 00418995d8e9e549c835ec209e1f1e5dbf7e5076..e8ae21b2d387c11a1a1038ae98855d9db1228dc1 100644 (file)
@@ -819,6 +819,35 @@ Retry_Sense:
                }
        }
 
+       /*
+        * Some devices don't work or return incorrect data the first
+        * time they get a READ(10) command, or for the first READ(10)
+        * after a media change.  If the INITIAL_READ10 flag is set,
+        * keep track of whether READ(10) commands succeed.  If the
+        * previous one succeeded and this one failed, set the REDO_READ10
+        * flag to force a retry.
+        */
+       if (unlikely((us->fflags & US_FL_INITIAL_READ10) &&
+                       srb->cmnd[0] == READ_10)) {
+               if (srb->result == SAM_STAT_GOOD) {
+                       set_bit(US_FLIDX_READ10_WORKED, &us->dflags);
+               } else if (test_bit(US_FLIDX_READ10_WORKED, &us->dflags)) {
+                       clear_bit(US_FLIDX_READ10_WORKED, &us->dflags);
+                       set_bit(US_FLIDX_REDO_READ10, &us->dflags);
+               }
+
+               /*
+                * Next, if the REDO_READ10 flag is set, return a result
+                * code that will cause the SCSI core to retry the READ(10)
+                * command immediately.
+                */
+               if (test_bit(US_FLIDX_REDO_READ10, &us->dflags)) {
+                       clear_bit(US_FLIDX_REDO_READ10, &us->dflags);
+                       srb->result = DID_IMM_RETRY << 16;
+                       srb->sense_buffer[0] = 0;
+               }
+       }
+
        /* Did we transfer less than the minimum amount required? */
        if ((srb->result == SAM_STAT_GOOD || srb->sense_buffer[2] == 0) &&
                        scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow)
index c1602b8c55949e0b5c1e4a99042d1409f953008f..ccff3483eebc87d0c82a562cbffa3f5ab36ab878 100644 (file)
@@ -1114,6 +1114,16 @@ UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_FIX_CAPACITY ),
 
+/* Reported by Paul Hartman <paul.hartman+linux@gmail.com>
+ * This card reader returns "Illegal Request, Logical Block Address
+ * Out of Range" for the first READ(10) after a new card is inserted.
+ */
+UNUSUAL_DEV(  0x090c, 0x6000, 0x0100, 0x0100,
+               "Feiya",
+               "SD/SDHC Card Reader",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_INITIAL_READ10 ),
+
 /* This Pentax still camera is not conformant
  * to the USB storage specification: -
  * - It does not like the INQUIRY command. So we must handle this command
@@ -1888,6 +1898,15 @@ UNUSUAL_DEV( 0x1908, 0x3335, 0x0200, 0x0200,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_READ_DISC_INFO ),
 
+/* Reported by Sven Geggus <sven-usbst@geggus.net>
+ * This encrypted pen drive returns bogus data for the initial READ(10).
+ */
+UNUSUAL_DEV(  0x1b1c, 0x1ab5, 0x0200, 0x0200,
+               "Corsair",
+               "Padlock v2",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_INITIAL_READ10 ),
+
 /* Patch by Richard Schütz <r.schtz@t-online.de>
  * This external hard drive enclosure uses a JMicron chip which
  * needs the US_FL_IGNORE_RESIDUE flag to work properly. */
index 5ee7ac42e08f3bddb892109d07e99d6a216e2509..0ca095820f3e7ca10c98e27a4eaeea728e5c533e 100644 (file)
@@ -440,7 +440,8 @@ static void adjust_quirks(struct us_data *us)
                        US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 |
                        US_FL_CAPACITY_OK | US_FL_IGNORE_RESIDUE |
                        US_FL_SINGLE_LUN | US_FL_NO_WP_DETECT |
-                       US_FL_NO_READ_DISC_INFO | US_FL_NO_READ_CAPACITY_16);
+                       US_FL_NO_READ_DISC_INFO | US_FL_NO_READ_CAPACITY_16 |
+                       US_FL_INITIAL_READ10);
 
        p = quirks;
        while (*p) {
@@ -490,6 +491,9 @@ static void adjust_quirks(struct us_data *us)
                case 'm':
                        f |= US_FL_MAX_SECTORS_64;
                        break;
+               case 'n':
+                       f |= US_FL_INITIAL_READ10;
+                       break;
                case 'o':
                        f |= US_FL_CAPACITY_OK;
                        break;
@@ -953,6 +957,13 @@ int usb_stor_probe2(struct us_data *us)
        if (result)
                goto BadDevice;
 
+       /*
+        * If the device returns invalid data for the first READ(10)
+        * command, indicate the command should be retried.
+        */
+       if (us->fflags & US_FL_INITIAL_READ10)
+               set_bit(US_FLIDX_REDO_READ10, &us->dflags);
+
        /* Acquire all the other resources and add the host */
        result = usb_stor_acquire_resources(us);
        if (result)
index 89d3bfff98df47d34b78b516aeaa19b101d572b5..7b0f2113632efb52ada464fc17dd83a74f34ea5a 100644 (file)
@@ -73,6 +73,8 @@ struct us_unusual_dev {
 #define US_FLIDX_RESETTING     4       /* device reset in progress */
 #define US_FLIDX_TIMED_OUT     5       /* SCSI midlayer timed out  */
 #define US_FLIDX_DONT_SCAN     6       /* don't scan (disconnect)  */
+#define US_FLIDX_REDO_READ10   7       /* redo READ(10) command    */
+#define US_FLIDX_READ10_WORKED 8       /* previous READ(10) succeeded */
 
 #define USB_STOR_STRING_LEN 32
 
index 2f7c76a85e532a658bf9652b0875887346ff374c..e224a92baa16c808b9f3d8c2baa4b449f210c214 100644 (file)
@@ -144,7 +144,7 @@ static void handle_tx(struct vhost_net *net)
        }
 
        mutex_lock(&vq->mutex);
-       vhost_disable_notify(vq);
+       vhost_disable_notify(&net->dev, vq);
 
        if (wmem < sock->sk->sk_sndbuf / 2)
                tx_poll_stop(net);
@@ -166,8 +166,8 @@ static void handle_tx(struct vhost_net *net)
                                set_bit(SOCK_ASYNC_NOSPACE, &sock->flags);
                                break;
                        }
-                       if (unlikely(vhost_enable_notify(vq))) {
-                               vhost_disable_notify(vq);
+                       if (unlikely(vhost_enable_notify(&net->dev, vq))) {
+                               vhost_disable_notify(&net->dev, vq);
                                continue;
                        }
                        break;
@@ -315,7 +315,7 @@ static void handle_rx(struct vhost_net *net)
                return;
 
        mutex_lock(&vq->mutex);
-       vhost_disable_notify(vq);
+       vhost_disable_notify(&net->dev, vq);
        vhost_hlen = vq->vhost_hlen;
        sock_hlen = vq->sock_hlen;
 
@@ -334,10 +334,10 @@ static void handle_rx(struct vhost_net *net)
                        break;
                /* OK, now we need to know about added descriptors. */
                if (!headcount) {
-                       if (unlikely(vhost_enable_notify(vq))) {
+                       if (unlikely(vhost_enable_notify(&net->dev, vq))) {
                                /* They have slipped one in as we were
                                 * doing that: check again. */
-                               vhost_disable_notify(vq);
+                               vhost_disable_notify(&net->dev, vq);
                                continue;
                        }
                        /* Nothing new?  Wait for eventfd to tell us
index 099f30230d0625a3d102da68c9236d9718993107..734e1d74ad805a1547ed867dd8363f09bcd9e2f8 100644 (file)
@@ -49,7 +49,7 @@ static void handle_vq(struct vhost_test *n)
                return;
 
        mutex_lock(&vq->mutex);
-       vhost_disable_notify(vq);
+       vhost_disable_notify(&n->dev, vq);
 
        for (;;) {
                head = vhost_get_vq_desc(&n->dev, vq, vq->iov,
@@ -61,8 +61,8 @@ static void handle_vq(struct vhost_test *n)
                        break;
                /* Nothing new?  Wait for eventfd to tell us they refilled. */
                if (head == vq->num) {
-                       if (unlikely(vhost_enable_notify(vq))) {
-                               vhost_disable_notify(vq);
+                       if (unlikely(vhost_enable_notify(&n->dev, vq))) {
+                               vhost_disable_notify(&n->dev, vq);
                                continue;
                        }
                        break;
index 7aa4eea930f1310077012eeab05a511bd1febdfe..ea966b356352084beaa9f491be2b57871c98482e 100644 (file)
@@ -37,6 +37,9 @@ enum {
        VHOST_MEMORY_F_LOG = 0x1,
 };
 
+#define vhost_used_event(vq) ((u16 __user *)&vq->avail->ring[vq->num])
+#define vhost_avail_event(vq) ((u16 __user *)&vq->used->ring[vq->num])
+
 static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh,
                            poll_table *pt)
 {
@@ -161,6 +164,8 @@ static void vhost_vq_reset(struct vhost_dev *dev,
        vq->last_avail_idx = 0;
        vq->avail_idx = 0;
        vq->last_used_idx = 0;
+       vq->signalled_used = 0;
+       vq->signalled_used_valid = false;
        vq->used_flags = 0;
        vq->log_used = false;
        vq->log_addr = -1ull;
@@ -489,16 +494,17 @@ static int memory_access_ok(struct vhost_dev *d, struct vhost_memory *mem,
        return 1;
 }
 
-static int vq_access_ok(unsigned int num,
+static int vq_access_ok(struct vhost_dev *d, unsigned int num,
                        struct vring_desc __user *desc,
                        struct vring_avail __user *avail,
                        struct vring_used __user *used)
 {
+       size_t s = vhost_has_feature(d, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
        return access_ok(VERIFY_READ, desc, num * sizeof *desc) &&
               access_ok(VERIFY_READ, avail,
-                        sizeof *avail + num * sizeof *avail->ring) &&
+                        sizeof *avail + num * sizeof *avail->ring + s) &&
               access_ok(VERIFY_WRITE, used,
-                       sizeof *used + num * sizeof *used->ring);
+                       sizeof *used + num * sizeof *used->ring + s);
 }
 
 /* Can we log writes? */
@@ -514,9 +520,11 @@ int vhost_log_access_ok(struct vhost_dev *dev)
 
 /* Verify access for write logging. */
 /* Caller should have vq mutex and device mutex */
-static int vq_log_access_ok(struct vhost_virtqueue *vq, void __user *log_base)
+static int vq_log_access_ok(struct vhost_dev *d, struct vhost_virtqueue *vq,
+                           void __user *log_base)
 {
        struct vhost_memory *mp;
+       size_t s = vhost_has_feature(d, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
 
        mp = rcu_dereference_protected(vq->dev->memory,
                                       lockdep_is_held(&vq->mutex));
@@ -524,15 +532,15 @@ static int vq_log_access_ok(struct vhost_virtqueue *vq, void __user *log_base)
                            vhost_has_feature(vq->dev, VHOST_F_LOG_ALL)) &&
                (!vq->log_used || log_access_ok(log_base, vq->log_addr,
                                        sizeof *vq->used +
-                                       vq->num * sizeof *vq->used->ring));
+                                       vq->num * sizeof *vq->used->ring + s));
 }
 
 /* Can we start vq? */
 /* Caller should have vq mutex and device mutex */
 int vhost_vq_access_ok(struct vhost_virtqueue *vq)
 {
-       return vq_access_ok(vq->num, vq->desc, vq->avail, vq->used) &&
-               vq_log_access_ok(vq, vq->log_base);
+       return vq_access_ok(vq->dev, vq->num, vq->desc, vq->avail, vq->used) &&
+               vq_log_access_ok(vq->dev, vq, vq->log_base);
 }
 
 static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
@@ -577,6 +585,7 @@ static int init_used(struct vhost_virtqueue *vq,
 
        if (r)
                return r;
+       vq->signalled_used_valid = false;
        return get_user(vq->last_used_idx, &used->idx);
 }
 
@@ -674,7 +683,7 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
                 * If it is not, we don't as size might not have been setup.
                 * We will verify when backend is configured. */
                if (vq->private_data) {
-                       if (!vq_access_ok(vq->num,
+                       if (!vq_access_ok(d, vq->num,
                                (void __user *)(unsigned long)a.desc_user_addr,
                                (void __user *)(unsigned long)a.avail_user_addr,
                                (void __user *)(unsigned long)a.used_user_addr)) {
@@ -818,7 +827,7 @@ long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg)
                        vq = d->vqs + i;
                        mutex_lock(&vq->mutex);
                        /* If ring is inactive, will check when it's enabled. */
-                       if (vq->private_data && !vq_log_access_ok(vq, base))
+                       if (vq->private_data && !vq_log_access_ok(d, vq, base))
                                r = -EFAULT;
                        else
                                vq->log_base = base;
@@ -1219,6 +1228,10 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
 
        /* On success, increment avail index. */
        vq->last_avail_idx++;
+
+       /* Assume notifications from guest are disabled at this point,
+        * if they aren't we would need to update avail_event index. */
+       BUG_ON(!(vq->used_flags & VRING_USED_F_NO_NOTIFY));
        return head;
 }
 
@@ -1267,6 +1280,12 @@ int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len)
                        eventfd_signal(vq->log_ctx, 1);
        }
        vq->last_used_idx++;
+       /* If the driver never bothers to signal in a very long while,
+        * used index might wrap around. If that happens, invalidate
+        * signalled_used index we stored. TODO: make sure driver
+        * signals at least once in 2^16 and remove this. */
+       if (unlikely(vq->last_used_idx == vq->signalled_used))
+               vq->signalled_used_valid = false;
        return 0;
 }
 
@@ -1275,6 +1294,7 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq,
                            unsigned count)
 {
        struct vring_used_elem __user *used;
+       u16 old, new;
        int start;
 
        start = vq->last_used_idx % vq->num;
@@ -1292,7 +1312,14 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq,
                           ((void __user *)used - (void __user *)vq->used),
                          count * sizeof *used);
        }
-       vq->last_used_idx += count;
+       old = vq->last_used_idx;
+       new = (vq->last_used_idx += count);
+       /* If the driver never bothers to signal in a very long while,
+        * used index might wrap around. If that happens, invalidate
+        * signalled_used index we stored. TODO: make sure driver
+        * signals at least once in 2^16 and remove this. */
+       if (unlikely((u16)(new - vq->signalled_used) < (u16)(new - old)))
+               vq->signalled_used_valid = false;
        return 0;
 }
 
@@ -1331,29 +1358,47 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
        return r;
 }
 
-/* This actually signals the guest, using eventfd. */
-void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
+static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 {
-       __u16 flags;
-
+       __u16 old, new, event;
+       bool v;
        /* Flush out used index updates. This is paired
         * with the barrier that the Guest executes when enabling
         * interrupts. */
        smp_mb();
 
-       if (__get_user(flags, &vq->avail->flags)) {
-               vq_err(vq, "Failed to get flags");
-               return;
+       if (vhost_has_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY) &&
+           unlikely(vq->avail_idx == vq->last_avail_idx))
+               return true;
+
+       if (!vhost_has_feature(dev, VIRTIO_RING_F_EVENT_IDX)) {
+               __u16 flags;
+               if (__get_user(flags, &vq->avail->flags)) {
+                       vq_err(vq, "Failed to get flags");
+                       return true;
+               }
+               return !(flags & VRING_AVAIL_F_NO_INTERRUPT);
        }
+       old = vq->signalled_used;
+       v = vq->signalled_used_valid;
+       new = vq->signalled_used = vq->last_used_idx;
+       vq->signalled_used_valid = true;
 
-       /* If they don't want an interrupt, don't signal, unless empty. */
-       if ((flags & VRING_AVAIL_F_NO_INTERRUPT) &&
-           (vq->avail_idx != vq->last_avail_idx ||
-            !vhost_has_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY)))
-               return;
+       if (unlikely(!v))
+               return true;
 
+       if (get_user(event, vhost_used_event(vq))) {
+               vq_err(vq, "Failed to get used event idx");
+               return true;
+       }
+       return vring_need_event(event, new, old);
+}
+
+/* This actually signals the guest, using eventfd. */
+void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
+{
        /* Signal the Guest tell them we used something up. */
-       if (vq->call_ctx)
+       if (vq->call_ctx && vhost_notify(dev, vq))
                eventfd_signal(vq->call_ctx, 1);
 }
 
@@ -1376,7 +1421,7 @@ void vhost_add_used_and_signal_n(struct vhost_dev *dev,
 }
 
 /* OK, now we need to know about added descriptors. */
-bool vhost_enable_notify(struct vhost_virtqueue *vq)
+bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 {
        u16 avail_idx;
        int r;
@@ -1384,11 +1429,34 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq)
        if (!(vq->used_flags & VRING_USED_F_NO_NOTIFY))
                return false;
        vq->used_flags &= ~VRING_USED_F_NO_NOTIFY;
-       r = put_user(vq->used_flags, &vq->used->flags);
-       if (r) {
-               vq_err(vq, "Failed to enable notification at %p: %d\n",
-                      &vq->used->flags, r);
-               return false;
+       if (!vhost_has_feature(dev, VIRTIO_RING_F_EVENT_IDX)) {
+               r = put_user(vq->used_flags, &vq->used->flags);
+               if (r) {
+                       vq_err(vq, "Failed to enable notification at %p: %d\n",
+                              &vq->used->flags, r);
+                       return false;
+               }
+       } else {
+               r = put_user(vq->avail_idx, vhost_avail_event(vq));
+               if (r) {
+                       vq_err(vq, "Failed to update avail event index at %p: %d\n",
+                              vhost_avail_event(vq), r);
+                       return false;
+               }
+       }
+       if (unlikely(vq->log_used)) {
+               void __user *used;
+               /* Make sure data is seen before log. */
+               smp_wmb();
+               used = vhost_has_feature(dev, VIRTIO_RING_F_EVENT_IDX) ?
+                       &vq->used->flags : vhost_avail_event(vq);
+               /* Log used flags or event index entry write. Both are 16 bit
+                * fields. */
+               log_write(vq->log_base, vq->log_addr +
+                          (used - (void __user *)vq->used),
+                         sizeof(u16));
+               if (vq->log_ctx)
+                       eventfd_signal(vq->log_ctx, 1);
        }
        /* They could have slipped one in as we were doing that: make
         * sure it's written, then check again. */
@@ -1404,15 +1472,17 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq)
 }
 
 /* We don't need to be notified again. */
-void vhost_disable_notify(struct vhost_virtqueue *vq)
+void vhost_disable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 {
        int r;
 
        if (vq->used_flags & VRING_USED_F_NO_NOTIFY)
                return;
        vq->used_flags |= VRING_USED_F_NO_NOTIFY;
-       r = put_user(vq->used_flags, &vq->used->flags);
-       if (r)
-               vq_err(vq, "Failed to enable notification at %p: %d\n",
-                      &vq->used->flags, r);
+       if (!vhost_has_feature(dev, VIRTIO_RING_F_EVENT_IDX)) {
+               r = put_user(vq->used_flags, &vq->used->flags);
+               if (r)
+                       vq_err(vq, "Failed to enable notification at %p: %d\n",
+                              &vq->used->flags, r);
+       }
 }
index b3363ae38518c56fad4de8b862918e54a3320b27..8e03379dd30f3abbe9ecabdbe5db8b6adc879d4e 100644 (file)
@@ -84,6 +84,12 @@ struct vhost_virtqueue {
        /* Used flags */
        u16 used_flags;
 
+       /* Last used index value we have signalled on */
+       u16 signalled_used;
+
+       /* Last used index value we have signalled on */
+       bool signalled_used_valid;
+
        /* Log writes to used structure. */
        bool log_used;
        u64 log_addr;
@@ -149,8 +155,8 @@ void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue *,
 void vhost_add_used_and_signal_n(struct vhost_dev *, struct vhost_virtqueue *,
                               struct vring_used_elem *heads, unsigned count);
 void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
-void vhost_disable_notify(struct vhost_virtqueue *);
-bool vhost_enable_notify(struct vhost_virtqueue *);
+void vhost_disable_notify(struct vhost_dev *, struct vhost_virtqueue *);
+bool vhost_enable_notify(struct vhost_dev *, struct vhost_virtqueue *);
 
 int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
                    unsigned int log_num, u64 len);
@@ -162,11 +168,12 @@ int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
        } while (0)
 
 enum {
-       VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
-                        (1 << VIRTIO_RING_F_INDIRECT_DESC) |
-                        (1 << VHOST_F_LOG_ALL) |
-                        (1 << VHOST_NET_F_VIRTIO_NET_HDR) |
-                        (1 << VIRTIO_NET_F_MRG_RXBUF),
+       VHOST_FEATURES = (1ULL << VIRTIO_F_NOTIFY_ON_EMPTY) |
+                        (1ULL << VIRTIO_RING_F_INDIRECT_DESC) |
+                        (1ULL << VIRTIO_RING_F_EVENT_IDX) |
+                        (1ULL << VHOST_F_LOG_ALL) |
+                        (1ULL << VHOST_NET_F_VIRTIO_NET_HDR) |
+                        (1ULL << VIRTIO_NET_F_MRG_RXBUF),
 };
 
 static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
index f9916ca5ca4d44a7fcac405f8329678526445164..549b960667c81b5bcbff1145550a28630038c374 100644 (file)
@@ -1460,6 +1460,14 @@ config FB_S3
        ---help---
          Driver for graphics boards with S3 Trio / S3 Virge chip.
 
+config FB_S3_DDC
+       bool "DDC for S3 support"
+       depends on FB_S3
+       select FB_DDC
+       default y
+       help
+         Say Y here if you want DDC support for your S3 graphics card.
+
 config FB_SAVAGE
        tristate "S3 Savage support"
        depends on FB && PCI && EXPERIMENTAL
@@ -1983,6 +1991,18 @@ config FB_SH_MOBILE_HDMI
        ---help---
          Driver for the on-chip SH-Mobile HDMI controller.
 
+config FB_SH_MOBILE_MERAM
+       tristate "SuperH Mobile MERAM read ahead support for LCDC"
+       depends on FB_SH_MOBILE_LCDC
+       default y
+       ---help---
+         Enable MERAM support for the SH-Mobile LCD controller.
+
+         This will allow for caching of the framebuffer to provide more
+         reliable access under heavy main memory bus traffic situations.
+         Up to 4 memory channels can be configured, allowing 4 RGB or
+         2 YCbCr framebuffers to be configured.
+
 config FB_TMIO
        tristate "Toshiba Mobile IO FrameBuffer support"
        depends on FB && MFD_CORE
@@ -2246,29 +2266,43 @@ config FB_METRONOME
 config FB_MB862XX
        tristate "Fujitsu MB862xx GDC support"
        depends on FB
+       depends on PCI || (OF && PPC)
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
        ---help---
          Frame buffer driver for Fujitsu Carmine/Coral-P(A)/Lime controllers.
 
+choice
+       prompt "GDC variant"
+       depends on FB_MB862XX
+
 config FB_MB862XX_PCI_GDC
        bool "Carmine/Coral-P(A) GDC"
-       depends on PCI && FB_MB862XX
+       depends on PCI
        ---help---
          This enables framebuffer support for Fujitsu Carmine/Coral-P(A)
          PCI graphics controller devices.
 
 config FB_MB862XX_LIME
        bool "Lime GDC"
-       depends on FB_MB862XX
-       depends on OF && !FB_MB862XX_PCI_GDC
-       depends on PPC
+       depends on OF && PPC
        select FB_FOREIGN_ENDIAN
        select FB_LITTLE_ENDIAN
        ---help---
          Framebuffer support for Fujitsu Lime GDC on host CPU bus.
 
+endchoice
+
+config FB_MB862XX_I2C
+       bool "Support I2C bus on MB862XX GDC"
+       depends on FB_MB862XX && I2C
+       default y
+       help
+         Selecting this option adds Coral-P(A)/Lime GDC I2C bus adapter
+         driver to support accessing I2C devices on controller's I2C bus.
+         These are usually some video decoder chips.
+
 config FB_EP93XX
        tristate "EP93XX frame buffer support"
        depends on FB && ARCH_EP93XX
index 2ea44b6625fef806296ee3a2c551b2cb58af730a..8b83129e209ca0f943a3d624e29930a679aec110 100644 (file)
@@ -130,6 +130,7 @@ obj-$(CONFIG_FB_UDL)                  += udlfb.o
 obj-$(CONFIG_FB_XILINX)           += xilinxfb.o
 obj-$(CONFIG_SH_MIPI_DSI)        += sh_mipi_dsi.o
 obj-$(CONFIG_FB_SH_MOBILE_HDMI)          += sh_mobile_hdmi.o
+obj-$(CONFIG_FB_SH_MOBILE_MERAM)  += sh_mobile_meram.o
 obj-$(CONFIG_FB_SH_MOBILE_LCDC)          += sh_mobile_lcdcfb.o
 obj-$(CONFIG_FB_OMAP)             += omap/
 obj-y                             += omap2/
index e5d6b56d4447e274d0db3f8eedf68cda99bfb53e..5ea6596dd824084971b49bdf2e9364df7832746c 100644 (file)
@@ -2224,22 +2224,23 @@ static int amifb_ioctl(struct fb_info *info,
         * Allocate, Clear and Align a Block of Chip Memory
         */
 
-static u_long unaligned_chipptr = 0;
+static void *aligned_chipptr;
 
 static inline u_long __init chipalloc(u_long size)
 {
-       size += PAGE_SIZE-1;
-       if (!(unaligned_chipptr = (u_long)amiga_chip_alloc(size,
-                                                          "amifb [RAM]")))
-               panic("No Chip RAM for frame buffer");
-       memset((void *)unaligned_chipptr, 0, size);
-       return PAGE_ALIGN(unaligned_chipptr);
+       aligned_chipptr = amiga_chip_alloc(size, "amifb [RAM]");
+       if (!aligned_chipptr) {
+               pr_err("amifb: No Chip RAM for frame buffer");
+               return 0;
+       }
+       memset(aligned_chipptr, 0, size);
+       return (u_long)aligned_chipptr;
 }
 
 static inline void chipfree(void)
 {
-       if (unaligned_chipptr)
-               amiga_chip_free((void *)unaligned_chipptr);
+       if (aligned_chipptr)
+               amiga_chip_free(aligned_chipptr);
 }
 
 
@@ -2295,7 +2296,7 @@ default_chipset:
                            defmode = amiga_vblank == 50 ? DEFMODE_PAL
                                                         : DEFMODE_NTSC;
                        if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
-                           VIDEOMEMSIZE_ECS_1M)
+                           VIDEOMEMSIZE_ECS_2M)
                                fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M;
                        else
                                fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M;
@@ -2312,7 +2313,7 @@ default_chipset:
                        maxfmode = TAG_FMODE_4;
                        defmode = DEFMODE_AGA;
                        if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
-                           VIDEOMEMSIZE_AGA_1M)
+                           VIDEOMEMSIZE_AGA_2M)
                                fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M;
                        else
                                fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M;
@@ -2385,6 +2386,10 @@ default_chipset:
                            DUMMYSPRITEMEMSIZE+
                            COPINITSIZE+
                            4*COPLISTSIZE);
+       if (!chipptr) {
+               err = -ENOMEM;
+               goto amifb_error;
+       }
 
        assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len);
        assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);
index 3ec4923c2d84e875eb27bc1119c1765ea7e73989..c22e8d39a2cb1371ff88bc6840cacbbbc8123c37 100644 (file)
@@ -515,11 +515,10 @@ static int __devinit arcfb_probe(struct platform_device *dev)
 
        /* We need a flat backing store for the Arc's
           less-flat actual paged framebuffer */
-       if (!(videomemory = vmalloc(videomemorysize)))
+       videomemory = vzalloc(videomemorysize);
+       if (!videomemory)
                return retval;
 
-       memset(videomemory, 0, videomemorysize);
-
        info = framebuffer_alloc(sizeof(struct arcfb_par), &dev->dev);
        if (!info)
                goto err;
index ebb893c49e9027b9d9cb3aa897e83db394026ff0..d7aaec5667bfd6ca1e1407e52c8c503577339405 100644 (file)
@@ -248,10 +248,6 @@ static int atyfb_sync(struct fb_info *info);
 
 static int aty_init(struct fb_info *info);
 
-#ifdef CONFIG_ATARI
-static int store_video_par(char *videopar, unsigned char m64_num);
-#endif
-
 static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc);
 
 static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc);
@@ -2268,11 +2264,13 @@ error:
        return;
 }
 
+#ifdef CONFIG_PCI
 static void aty_bl_exit(struct backlight_device *bd)
 {
        backlight_device_unregister(bd);
        printk("aty: Backlight unloaded\n");
 }
+#endif /* CONFIG_PCI */
 
 #endif /* CONFIG_FB_ATY_BACKLIGHT */
 
@@ -2789,7 +2787,7 @@ aty_init_exit:
        return ret;
 }
 
-#ifdef CONFIG_ATARI
+#if defined(CONFIG_ATARI) && !defined(MODULE)
 static int __devinit store_video_par(char *video_str, unsigned char m64_num)
 {
        char *p;
@@ -2818,7 +2816,7 @@ static int __devinit store_video_par(char *video_str, unsigned char m64_num)
        phys_vmembase[m64_num] = 0;
        return -1;
 }
-#endif /* CONFIG_ATARI */
+#endif /* CONFIG_ATARI && !MODULE */
 
 /*
  * Blank the display.
index c8b520e9a11ae3ec3005311eaae9550d1660cac9..c04b94da81f7544ff776507fd809ae09a6a98365 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/fb.h>
 #include <linux/i2c.h>
 #include <linux/backlight.h>
-#include <linux/mfd/core.h>
 #include <linux/mfd/88pm860x.h>
 
 #define MAX_BRIGHTNESS         (0xFF)
@@ -168,7 +167,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
        struct pm860x_backlight_pdata *pdata = NULL;
        struct pm860x_backlight_data *data;
        struct backlight_device *bl;
-       struct mfd_cell *cell;
        struct resource *res;
        struct backlight_properties props;
        unsigned char value;
@@ -181,10 +179,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       cell = pdev->dev.platform_data;
-       if (cell == NULL)
-               return -ENODEV;
-       pdata = cell->mfd_data;
+       pdata = pdev->dev.platform_data;
        if (pdata == NULL) {
                dev_err(&pdev->dev, "platform data isn't assigned to "
                        "backlight\n");
index 0c9373bedd1f39d61d8b391bcc54a630d6d981c8..2d93c8d61ad5e2aa9ea2cd48d30581aad7cf8fb4 100644 (file)
@@ -302,6 +302,18 @@ config BACKLIGHT_ADP8860
          To compile this driver as a module, choose M here: the module will
          be called adp8860_bl.
 
+config BACKLIGHT_ADP8870
+       tristate "Backlight Driver for ADP8870 using WLED"
+       depends on BACKLIGHT_CLASS_DEVICE && I2C
+       select NEW_LEDS
+       select LEDS_CLASS
+       help
+         If you have a LCD backlight connected to the ADP8870,
+         say Y here to enable this driver.
+
+         To compile this driver as a module, choose M here: the module will
+         be called adp8870_bl.
+
 config BACKLIGHT_88PM860X
        tristate "Backlight Driver for 88PM8606 using WLED"
        depends on MFD_88PM860X
index b9ca8490df87850dc746e5a4661b67f5294589a4..ee72adb8786ed2f9f71de431987f0f5e11da7fc5 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_BACKLIGHT_WM831X)        += wm831x_bl.o
 obj-$(CONFIG_BACKLIGHT_ADX)    += adx_bl.o
 obj-$(CONFIG_BACKLIGHT_ADP5520)        += adp5520_bl.o
 obj-$(CONFIG_BACKLIGHT_ADP8860)        += adp8860_bl.o
+obj-$(CONFIG_BACKLIGHT_ADP8870)        += adp8870_bl.o
 obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
 obj-$(CONFIG_BACKLIGHT_PCF50633)       += pcf50633-backlight.o
 
index af3119707dbfe2a65b4f9a9da2e9eadee6e5360d..d1aee730d7d80e7dd674dce346e27c812cc3e8d3 100644 (file)
@@ -211,8 +211,12 @@ static ssize_t adp5520_bl_daylight_max_store(struct device *dev,
                        const char *buf, size_t count)
 {
        struct adp5520_bl *data = dev_get_drvdata(dev);
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data->cached_daylight_max);
+       if (ret < 0)
+               return ret;
 
-       strict_strtoul(buf, 10, &data->cached_daylight_max);
        return adp5520_store(dev, buf, count, ADP5520_DAYLIGHT_MAX);
 }
 static DEVICE_ATTR(daylight_max, 0664, adp5520_bl_daylight_max_show,
diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c
new file mode 100644 (file)
index 0000000..05a8832
--- /dev/null
@@ -0,0 +1,1012 @@
+/*
+ * Backlight driver for Analog Devices ADP8870 Backlight Devices
+ *
+ * Copyright 2009-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+
+#include <linux/i2c/adp8870.h>
+#define ADP8870_EXT_FEATURES
+#define ADP8870_USE_LEDS
+
+
+#define ADP8870_MFDVID 0x00  /* Manufacturer and device ID */
+#define ADP8870_MDCR   0x01  /* Device mode and status */
+#define ADP8870_INT_STAT 0x02  /* Interrupts status */
+#define ADP8870_INT_EN 0x03  /* Interrupts enable */
+#define ADP8870_CFGR   0x04  /* Configuration register */
+#define ADP8870_BLSEL  0x05  /* Sink enable backlight or independent */
+#define ADP8870_PWMLED 0x06  /* PWM Enable Selection Register */
+#define ADP8870_BLOFF  0x07  /* Backlight off timeout */
+#define ADP8870_BLDIM  0x08  /* Backlight dim timeout */
+#define ADP8870_BLFR   0x09  /* Backlight fade in and out rates */
+#define ADP8870_BLMX1  0x0A  /* Backlight (Brightness Level 1-daylight) maximum current */
+#define ADP8870_BLDM1  0x0B  /* Backlight (Brightness Level 1-daylight) dim current */
+#define ADP8870_BLMX2  0x0C  /* Backlight (Brightness Level 2-bright) maximum current */
+#define ADP8870_BLDM2  0x0D  /* Backlight (Brightness Level 2-bright) dim current */
+#define ADP8870_BLMX3  0x0E  /* Backlight (Brightness Level 3-office) maximum current */
+#define ADP8870_BLDM3  0x0F  /* Backlight (Brightness Level 3-office) dim current */
+#define ADP8870_BLMX4  0x10  /* Backlight (Brightness Level 4-indoor) maximum current */
+#define ADP8870_BLDM4  0x11  /* Backlight (Brightness Level 4-indoor) dim current */
+#define ADP8870_BLMX5  0x12  /* Backlight (Brightness Level 5-dark) maximum current */
+#define ADP8870_BLDM5  0x13  /* Backlight (Brightness Level 5-dark) dim current */
+#define ADP8870_ISCLAW 0x1A  /* Independent sink current fade law register */
+#define ADP8870_ISCC   0x1B  /* Independent sink current control register */
+#define ADP8870_ISCT1  0x1C  /* Independent Sink Current Timer Register LED[7:5] */
+#define ADP8870_ISCT2  0x1D  /* Independent Sink Current Timer Register LED[4:1] */
+#define ADP8870_ISCF   0x1E  /* Independent sink current fade register */
+#define ADP8870_ISC1   0x1F  /* Independent Sink Current LED1 */
+#define ADP8870_ISC2   0x20  /* Independent Sink Current LED2 */
+#define ADP8870_ISC3   0x21  /* Independent Sink Current LED3 */
+#define ADP8870_ISC4   0x22  /* Independent Sink Current LED4 */
+#define ADP8870_ISC5   0x23  /* Independent Sink Current LED5 */
+#define ADP8870_ISC6   0x24  /* Independent Sink Current LED6 */
+#define ADP8870_ISC7   0x25  /* Independent Sink Current LED7 (Brightness Level 1-daylight) */
+#define ADP8870_ISC7_L2        0x26  /* Independent Sink Current LED7 (Brightness Level 2-bright) */
+#define ADP8870_ISC7_L3        0x27  /* Independent Sink Current LED7 (Brightness Level 3-office) */
+#define ADP8870_ISC7_L4        0x28  /* Independent Sink Current LED7 (Brightness Level 4-indoor) */
+#define ADP8870_ISC7_L5        0x29  /* Independent Sink Current LED7 (Brightness Level 5-dark) */
+#define ADP8870_CMP_CTL        0x2D  /* ALS Comparator Control Register */
+#define ADP8870_ALS1_EN        0x2E  /* Main ALS comparator level enable */
+#define ADP8870_ALS2_EN        0x2F  /* Second ALS comparator level enable */
+#define ADP8870_ALS1_STAT 0x30  /* Main ALS Comparator Status Register */
+#define ADP8870_ALS2_STAT 0x31  /* Second ALS Comparator Status Register */
+#define ADP8870_L2TRP  0x32  /* L2 comparator reference */
+#define ADP8870_L2HYS  0x33  /* L2 hysteresis */
+#define ADP8870_L3TRP  0x34  /* L3 comparator reference */
+#define ADP8870_L3HYS  0x35  /* L3 hysteresis */
+#define ADP8870_L4TRP  0x36  /* L4 comparator reference */
+#define ADP8870_L4HYS  0x37  /* L4 hysteresis */
+#define ADP8870_L5TRP  0x38  /* L5 comparator reference */
+#define ADP8870_L5HYS  0x39  /* L5 hysteresis */
+#define ADP8870_PH1LEVL        0x40  /* First phototransistor ambient light level-low byte register */
+#define ADP8870_PH1LEVH        0x41  /* First phototransistor ambient light level-high byte register */
+#define ADP8870_PH2LEVL        0x42  /* Second phototransistor ambient light level-low byte register */
+#define ADP8870_PH2LEVH        0x43  /* Second phototransistor ambient light level-high byte register */
+
+#define ADP8870_MANUFID                0x3  /* Analog Devices AD8870 Manufacturer and device ID */
+#define ADP8870_DEVID(x)       ((x) & 0xF)
+#define ADP8870_MANID(x)       ((x) >> 4)
+
+/* MDCR Device mode and status */
+#define D7ALSEN                        (1 << 7)
+#define INT_CFG                        (1 << 6)
+#define NSTBY                  (1 << 5)
+#define DIM_EN                 (1 << 4)
+#define GDWN_DIS               (1 << 3)
+#define SIS_EN                 (1 << 2)
+#define CMP_AUTOEN             (1 << 1)
+#define BLEN                   (1 << 0)
+
+/* ADP8870_ALS1_EN Main ALS comparator level enable */
+#define L5_EN                  (1 << 3)
+#define L4_EN                  (1 << 2)
+#define L3_EN                  (1 << 1)
+#define L2_EN                  (1 << 0)
+
+#define CFGR_BLV_SHIFT         3
+#define CFGR_BLV_MASK          0x7
+#define ADP8870_FLAG_LED_MASK  0xFF
+
+#define FADE_VAL(in, out)      ((0xF & (in)) | ((0xF & (out)) << 4))
+#define BL_CFGR_VAL(law, blv)  ((((blv) & CFGR_BLV_MASK) << CFGR_BLV_SHIFT) | ((0x3 & (law)) << 1))
+#define ALS_CMPR_CFG_VAL(filt) ((0x7 & (filt)) << 1)
+
+struct adp8870_bl {
+       struct i2c_client *client;
+       struct backlight_device *bl;
+       struct adp8870_led *led;
+       struct adp8870_backlight_platform_data *pdata;
+       struct mutex lock;
+       unsigned long cached_daylight_max;
+       int id;
+       int revid;
+       int current_brightness;
+};
+
+struct adp8870_led {
+       struct led_classdev     cdev;
+       struct work_struct      work;
+       struct i2c_client       *client;
+       enum led_brightness     new_brightness;
+       int                     id;
+       int                     flags;
+};
+
+static int adp8870_read(struct i2c_client *client, int reg, uint8_t *val)
+{
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(client, reg);
+       if (ret < 0) {
+               dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
+               return ret;
+       }
+
+       *val = ret;
+       return 0;
+}
+
+
+static int adp8870_write(struct i2c_client *client, u8 reg, u8 val)
+{
+       int ret = i2c_smbus_write_byte_data(client, reg, val);
+       if (ret)
+               dev_err(&client->dev, "failed to write\n");
+
+       return ret;
+}
+
+static int adp8870_set_bits(struct i2c_client *client, int reg, uint8_t bit_mask)
+{
+       struct adp8870_bl *data = i2c_get_clientdata(client);
+       uint8_t reg_val;
+       int ret;
+
+       mutex_lock(&data->lock);
+
+       ret = adp8870_read(client, reg, &reg_val);
+
+       if (!ret && ((reg_val & bit_mask) == 0)) {
+               reg_val |= bit_mask;
+               ret = adp8870_write(client, reg, reg_val);
+       }
+
+       mutex_unlock(&data->lock);
+       return ret;
+}
+
+static int adp8870_clr_bits(struct i2c_client *client, int reg, uint8_t bit_mask)
+{
+       struct adp8870_bl *data = i2c_get_clientdata(client);
+       uint8_t reg_val;
+       int ret;
+
+       mutex_lock(&data->lock);
+
+       ret = adp8870_read(client, reg, &reg_val);
+
+       if (!ret && (reg_val & bit_mask)) {
+               reg_val &= ~bit_mask;
+               ret = adp8870_write(client, reg, reg_val);
+       }
+
+       mutex_unlock(&data->lock);
+       return ret;
+}
+
+/*
+ * Independent sink / LED
+ */
+#if defined(ADP8870_USE_LEDS)
+static void adp8870_led_work(struct work_struct *work)
+{
+       struct adp8870_led *led = container_of(work, struct adp8870_led, work);
+       adp8870_write(led->client, ADP8870_ISC1 + led->id - 1,
+                        led->new_brightness >> 1);
+}
+
+static void adp8870_led_set(struct led_classdev *led_cdev,
+                          enum led_brightness value)
+{
+       struct adp8870_led *led;
+
+       led = container_of(led_cdev, struct adp8870_led, cdev);
+       led->new_brightness = value;
+       /*
+        * Use workqueue for IO since I2C operations can sleep.
+        */
+       schedule_work(&led->work);
+}
+
+static int adp8870_led_setup(struct adp8870_led *led)
+{
+       struct i2c_client *client = led->client;
+       int ret = 0;
+
+       ret = adp8870_write(client, ADP8870_ISC1 + led->id - 1, 0);
+       if (ret)
+               return ret;
+
+       ret = adp8870_set_bits(client, ADP8870_ISCC, 1 << (led->id - 1));
+       if (ret)
+               return ret;
+
+       if (led->id > 4)
+               ret = adp8870_set_bits(client, ADP8870_ISCT1,
+                               (led->flags & 0x3) << ((led->id - 5) * 2));
+       else
+               ret = adp8870_set_bits(client, ADP8870_ISCT2,
+                               (led->flags & 0x3) << ((led->id - 1) * 2));
+
+       return ret;
+}
+
+static int __devinit adp8870_led_probe(struct i2c_client *client)
+{
+       struct adp8870_backlight_platform_data *pdata =
+               client->dev.platform_data;
+       struct adp8870_bl *data = i2c_get_clientdata(client);
+       struct adp8870_led *led, *led_dat;
+       struct led_info *cur_led;
+       int ret, i;
+
+
+       led = kcalloc(pdata->num_leds, sizeof(*led), GFP_KERNEL);
+       if (led == NULL) {
+               dev_err(&client->dev, "failed to alloc memory\n");
+               return -ENOMEM;
+       }
+
+       ret = adp8870_write(client, ADP8870_ISCLAW, pdata->led_fade_law);
+       if (ret)
+               goto err_free;
+
+       ret = adp8870_write(client, ADP8870_ISCT1,
+                       (pdata->led_on_time & 0x3) << 6);
+       if (ret)
+               goto err_free;
+
+       ret = adp8870_write(client, ADP8870_ISCF,
+                       FADE_VAL(pdata->led_fade_in, pdata->led_fade_out));
+       if (ret)
+               goto err_free;
+
+       for (i = 0; i < pdata->num_leds; ++i) {
+               cur_led = &pdata->leds[i];
+               led_dat = &led[i];
+
+               led_dat->id = cur_led->flags & ADP8870_FLAG_LED_MASK;
+
+               if (led_dat->id > 7 || led_dat->id < 1) {
+                       dev_err(&client->dev, "Invalid LED ID %d\n",
+                               led_dat->id);
+                       goto err;
+               }
+
+               if (pdata->bl_led_assign & (1 << (led_dat->id - 1))) {
+                       dev_err(&client->dev, "LED %d used by Backlight\n",
+                               led_dat->id);
+                       goto err;
+               }
+
+               led_dat->cdev.name = cur_led->name;
+               led_dat->cdev.default_trigger = cur_led->default_trigger;
+               led_dat->cdev.brightness_set = adp8870_led_set;
+               led_dat->cdev.brightness = LED_OFF;
+               led_dat->flags = cur_led->flags >> FLAG_OFFT_SHIFT;
+               led_dat->client = client;
+               led_dat->new_brightness = LED_OFF;
+               INIT_WORK(&led_dat->work, adp8870_led_work);
+
+               ret = led_classdev_register(&client->dev, &led_dat->cdev);
+               if (ret) {
+                       dev_err(&client->dev, "failed to register LED %d\n",
+                               led_dat->id);
+                       goto err;
+               }
+
+               ret = adp8870_led_setup(led_dat);
+               if (ret) {
+                       dev_err(&client->dev, "failed to write\n");
+                       i++;
+                       goto err;
+               }
+       }
+
+       data->led = led;
+
+       return 0;
+
+ err:
+       for (i = i - 1; i >= 0; --i) {
+               led_classdev_unregister(&led[i].cdev);
+               cancel_work_sync(&led[i].work);
+       }
+
+ err_free:
+       kfree(led);
+
+       return ret;
+}
+
+static int __devexit adp8870_led_remove(struct i2c_client *client)
+{
+       struct adp8870_backlight_platform_data *pdata =
+               client->dev.platform_data;
+       struct adp8870_bl *data = i2c_get_clientdata(client);
+       int i;
+
+       for (i = 0; i < pdata->num_leds; i++) {
+               led_classdev_unregister(&data->led[i].cdev);
+               cancel_work_sync(&data->led[i].work);
+       }
+
+       kfree(data->led);
+       return 0;
+}
+#else
+static int __devinit adp8870_led_probe(struct i2c_client *client)
+{
+       return 0;
+}
+
+static int __devexit adp8870_led_remove(struct i2c_client *client)
+{
+       return 0;
+}
+#endif
+
+static int adp8870_bl_set(struct backlight_device *bl, int brightness)
+{
+       struct adp8870_bl *data = bl_get_data(bl);
+       struct i2c_client *client = data->client;
+       int ret = 0;
+
+       if (data->pdata->en_ambl_sens) {
+               if ((brightness > 0) && (brightness < ADP8870_MAX_BRIGHTNESS)) {
+                       /* Disable Ambient Light auto adjust */
+                       ret = adp8870_clr_bits(client, ADP8870_MDCR,
+                                       CMP_AUTOEN);
+                       if (ret)
+                               return ret;
+                       ret = adp8870_write(client, ADP8870_BLMX1, brightness);
+                       if (ret)
+                               return ret;
+               } else {
+                       /*
+                        * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust
+                        * restore daylight l1 sysfs brightness
+                        */
+                       ret = adp8870_write(client, ADP8870_BLMX1,
+                                        data->cached_daylight_max);
+                       if (ret)
+                               return ret;
+
+                       ret = adp8870_set_bits(client, ADP8870_MDCR,
+                                        CMP_AUTOEN);
+                       if (ret)
+                               return ret;
+               }
+       } else {
+               ret = adp8870_write(client, ADP8870_BLMX1, brightness);
+               if (ret)
+                       return ret;
+       }
+
+       if (data->current_brightness && brightness == 0)
+               ret = adp8870_set_bits(client,
+                               ADP8870_MDCR, DIM_EN);
+       else if (data->current_brightness == 0 && brightness)
+               ret = adp8870_clr_bits(client,
+                               ADP8870_MDCR, DIM_EN);
+
+       if (!ret)
+               data->current_brightness = brightness;
+
+       return ret;
+}
+
+static int adp8870_bl_update_status(struct backlight_device *bl)
+{
+       int brightness = bl->props.brightness;
+       if (bl->props.power != FB_BLANK_UNBLANK)
+               brightness = 0;
+
+       if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+               brightness = 0;
+
+       return adp8870_bl_set(bl, brightness);
+}
+
+static int adp8870_bl_get_brightness(struct backlight_device *bl)
+{
+       struct adp8870_bl *data = bl_get_data(bl);
+
+       return data->current_brightness;
+}
+
+static const struct backlight_ops adp8870_bl_ops = {
+       .update_status  = adp8870_bl_update_status,
+       .get_brightness = adp8870_bl_get_brightness,
+};
+
+static int adp8870_bl_setup(struct backlight_device *bl)
+{
+       struct adp8870_bl *data = bl_get_data(bl);
+       struct i2c_client *client = data->client;
+       struct adp8870_backlight_platform_data *pdata = data->pdata;
+       int ret = 0;
+
+       ret = adp8870_write(client, ADP8870_BLSEL, ~pdata->bl_led_assign);
+       if (ret)
+               return ret;
+
+       ret = adp8870_write(client, ADP8870_PWMLED, pdata->pwm_assign);
+       if (ret)
+               return ret;
+
+       ret = adp8870_write(client, ADP8870_BLMX1, pdata->l1_daylight_max);
+       if (ret)
+               return ret;
+
+       ret = adp8870_write(client, ADP8870_BLDM1, pdata->l1_daylight_dim);
+       if (ret)
+               return ret;
+
+       if (pdata->en_ambl_sens) {
+               data->cached_daylight_max = pdata->l1_daylight_max;
+               ret = adp8870_write(client, ADP8870_BLMX2,
+                                               pdata->l2_bright_max);
+               if (ret)
+                       return ret;
+               ret = adp8870_write(client, ADP8870_BLDM2,
+                                               pdata->l2_bright_dim);
+               if (ret)
+                       return ret;
+
+               ret = adp8870_write(client, ADP8870_BLMX3,
+                                               pdata->l3_office_max);
+               if (ret)
+                       return ret;
+               ret = adp8870_write(client, ADP8870_BLDM3,
+                                               pdata->l3_office_dim);
+               if (ret)
+                       return ret;
+
+               ret = adp8870_write(client, ADP8870_BLMX4,
+                                               pdata->l4_indoor_max);
+               if (ret)
+                       return ret;
+
+               ret = adp8870_write(client, ADP8870_BLDM4,
+                                               pdata->l4_indor_dim);
+               if (ret)
+                       return ret;
+
+               ret = adp8870_write(client, ADP8870_BLMX5,
+                                               pdata->l5_dark_max);
+               if (ret)
+                       return ret;
+
+               ret = adp8870_write(client, ADP8870_BLDM5,
+                                               pdata->l5_dark_dim);
+               if (ret)
+                       return ret;
+
+               ret = adp8870_write(client, ADP8870_L2TRP, pdata->l2_trip);
+               if (ret)
+                       return ret;
+
+               ret = adp8870_write(client, ADP8870_L2HYS, pdata->l2_hyst);
+               if (ret)
+                       return ret;
+
+               ret = adp8870_write(client, ADP8870_L3TRP, pdata->l3_trip);
+               if (ret)
+                       return ret;
+
+               ret = adp8870_write(client, ADP8870_L3HYS, pdata->l3_hyst);
+               if (ret)
+                       return ret;
+
+               ret = adp8870_write(client, ADP8870_L4TRP, pdata->l4_trip);
+               if (ret)
+                       return ret;
+
+               ret = adp8870_write(client, ADP8870_L4HYS, pdata->l4_hyst);
+               if (ret)
+                       return ret;
+
+               ret = adp8870_write(client, ADP8870_L5TRP, pdata->l5_trip);
+               if (ret)
+                       return ret;
+
+               ret = adp8870_write(client, ADP8870_L5HYS, pdata->l5_hyst);
+               if (ret)
+                       return ret;
+
+               ret = adp8870_write(client, ADP8870_ALS1_EN, L5_EN | L4_EN |
+                                               L3_EN | L2_EN);
+               if (ret)
+                       return ret;
+
+               ret = adp8870_write(client, ADP8870_CMP_CTL,
+                       ALS_CMPR_CFG_VAL(pdata->abml_filt));
+               if (ret)
+                       return ret;
+       }
+
+       ret = adp8870_write(client, ADP8870_CFGR,
+                       BL_CFGR_VAL(pdata->bl_fade_law, 0));
+       if (ret)
+               return ret;
+
+       ret = adp8870_write(client, ADP8870_BLFR, FADE_VAL(pdata->bl_fade_in,
+                       pdata->bl_fade_out));
+       if (ret)
+               return ret;
+       /*
+        * ADP8870 Rev0 requires GDWN_DIS bit set
+        */
+
+       ret = adp8870_set_bits(client, ADP8870_MDCR, BLEN | DIM_EN | NSTBY |
+                       (data->revid == 0 ? GDWN_DIS : 0));
+
+       return ret;
+}
+
+static ssize_t adp8870_show(struct device *dev, char *buf, int reg)
+{
+       struct adp8870_bl *data = dev_get_drvdata(dev);
+       int error;
+       uint8_t reg_val;
+
+       mutex_lock(&data->lock);
+       error = adp8870_read(data->client, reg, &reg_val);
+       mutex_unlock(&data->lock);
+
+       if (error < 0)
+               return error;
+
+       return sprintf(buf, "%u\n", reg_val);
+}
+
+static ssize_t adp8870_store(struct device *dev, const char *buf,
+                        size_t count, int reg)
+{
+       struct adp8870_bl *data = dev_get_drvdata(dev);
+       unsigned long val;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &val);
+       if (ret)
+               return ret;
+
+       mutex_lock(&data->lock);
+       adp8870_write(data->client, reg, val);
+       mutex_unlock(&data->lock);
+
+       return count;
+}
+
+static ssize_t adp8870_bl_l5_dark_max_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       return adp8870_show(dev, buf, ADP8870_BLMX5);
+}
+
+static ssize_t adp8870_bl_l5_dark_max_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       return adp8870_store(dev, buf, count, ADP8870_BLMX5);
+}
+static DEVICE_ATTR(l5_dark_max, 0664, adp8870_bl_l5_dark_max_show,
+                       adp8870_bl_l5_dark_max_store);
+
+
+static ssize_t adp8870_bl_l4_indoor_max_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       return adp8870_show(dev, buf, ADP8870_BLMX4);
+}
+
+static ssize_t adp8870_bl_l4_indoor_max_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       return adp8870_store(dev, buf, count, ADP8870_BLMX4);
+}
+static DEVICE_ATTR(l4_indoor_max, 0664, adp8870_bl_l4_indoor_max_show,
+                       adp8870_bl_l4_indoor_max_store);
+
+
+static ssize_t adp8870_bl_l3_office_max_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       return adp8870_show(dev, buf, ADP8870_BLMX3);
+}
+
+static ssize_t adp8870_bl_l3_office_max_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       return adp8870_store(dev, buf, count, ADP8870_BLMX3);
+}
+
+static DEVICE_ATTR(l3_office_max, 0664, adp8870_bl_l3_office_max_show,
+                       adp8870_bl_l3_office_max_store);
+
+static ssize_t adp8870_bl_l2_bright_max_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       return adp8870_show(dev, buf, ADP8870_BLMX2);
+}
+
+static ssize_t adp8870_bl_l2_bright_max_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       return adp8870_store(dev, buf, count, ADP8870_BLMX2);
+}
+static DEVICE_ATTR(l2_bright_max, 0664, adp8870_bl_l2_bright_max_show,
+                       adp8870_bl_l2_bright_max_store);
+
+static ssize_t adp8870_bl_l1_daylight_max_show(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       return adp8870_show(dev, buf, ADP8870_BLMX1);
+}
+
+static ssize_t adp8870_bl_l1_daylight_max_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct adp8870_bl *data = dev_get_drvdata(dev);
+       int ret = strict_strtoul(buf, 10, &data->cached_daylight_max);
+       if (ret)
+               return ret;
+
+       return adp8870_store(dev, buf, count, ADP8870_BLMX1);
+}
+static DEVICE_ATTR(l1_daylight_max, 0664, adp8870_bl_l1_daylight_max_show,
+                       adp8870_bl_l1_daylight_max_store);
+
+static ssize_t adp8870_bl_l5_dark_dim_show(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       return adp8870_show(dev, buf, ADP8870_BLDM5);
+}
+
+static ssize_t adp8870_bl_l5_dark_dim_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       return adp8870_store(dev, buf, count, ADP8870_BLDM5);
+}
+static DEVICE_ATTR(l5_dark_dim, 0664, adp8870_bl_l5_dark_dim_show,
+                       adp8870_bl_l5_dark_dim_store);
+
+static ssize_t adp8870_bl_l4_indoor_dim_show(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       return adp8870_show(dev, buf, ADP8870_BLDM4);
+}
+
+static ssize_t adp8870_bl_l4_indoor_dim_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       return adp8870_store(dev, buf, count, ADP8870_BLDM4);
+}
+static DEVICE_ATTR(l4_indoor_dim, 0664, adp8870_bl_l4_indoor_dim_show,
+                       adp8870_bl_l4_indoor_dim_store);
+
+
+static ssize_t adp8870_bl_l3_office_dim_show(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       return adp8870_show(dev, buf, ADP8870_BLDM3);
+}
+
+static ssize_t adp8870_bl_l3_office_dim_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       return adp8870_store(dev, buf, count, ADP8870_BLDM3);
+}
+static DEVICE_ATTR(l3_office_dim, 0664, adp8870_bl_l3_office_dim_show,
+                       adp8870_bl_l3_office_dim_store);
+
+static ssize_t adp8870_bl_l2_bright_dim_show(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       return adp8870_show(dev, buf, ADP8870_BLDM2);
+}
+
+static ssize_t adp8870_bl_l2_bright_dim_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       return adp8870_store(dev, buf, count, ADP8870_BLDM2);
+}
+static DEVICE_ATTR(l2_bright_dim, 0664, adp8870_bl_l2_bright_dim_show,
+                       adp8870_bl_l2_bright_dim_store);
+
+static ssize_t adp8870_bl_l1_daylight_dim_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       return adp8870_show(dev, buf, ADP8870_BLDM1);
+}
+
+static ssize_t adp8870_bl_l1_daylight_dim_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       return adp8870_store(dev, buf, count, ADP8870_BLDM1);
+}
+static DEVICE_ATTR(l1_daylight_dim, 0664, adp8870_bl_l1_daylight_dim_show,
+                       adp8870_bl_l1_daylight_dim_store);
+
+#ifdef ADP8870_EXT_FEATURES
+static ssize_t adp8870_bl_ambient_light_level_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct adp8870_bl *data = dev_get_drvdata(dev);
+       int error;
+       uint8_t reg_val;
+       uint16_t ret_val;
+
+       mutex_lock(&data->lock);
+       error = adp8870_read(data->client, ADP8870_PH1LEVL, &reg_val);
+       if (error < 0) {
+               mutex_unlock(&data->lock);
+               return error;
+       }
+       ret_val = reg_val;
+       error = adp8870_read(data->client, ADP8870_PH1LEVH, &reg_val);
+       mutex_unlock(&data->lock);
+
+       if (error < 0)
+               return error;
+
+       /* Return 13-bit conversion value for the first light sensor */
+       ret_val += (reg_val & 0x1F) << 8;
+
+       return sprintf(buf, "%u\n", ret_val);
+}
+static DEVICE_ATTR(ambient_light_level, 0444,
+               adp8870_bl_ambient_light_level_show, NULL);
+
+static ssize_t adp8870_bl_ambient_light_zone_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct adp8870_bl *data = dev_get_drvdata(dev);
+       int error;
+       uint8_t reg_val;
+
+       mutex_lock(&data->lock);
+       error = adp8870_read(data->client, ADP8870_CFGR, &reg_val);
+       mutex_unlock(&data->lock);
+
+       if (error < 0)
+               return error;
+
+       return sprintf(buf, "%u\n",
+               ((reg_val >> CFGR_BLV_SHIFT) & CFGR_BLV_MASK) + 1);
+}
+
+static ssize_t adp8870_bl_ambient_light_zone_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       struct adp8870_bl *data = dev_get_drvdata(dev);
+       unsigned long val;
+       uint8_t reg_val;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &val);
+       if (ret)
+               return ret;
+
+       if (val == 0) {
+               /* Enable automatic ambient light sensing */
+               adp8870_set_bits(data->client, ADP8870_MDCR, CMP_AUTOEN);
+       } else if ((val > 0) && (val < 6)) {
+               /* Disable automatic ambient light sensing */
+               adp8870_clr_bits(data->client, ADP8870_MDCR, CMP_AUTOEN);
+
+               /* Set user supplied ambient light zone */
+               mutex_lock(&data->lock);
+               adp8870_read(data->client, ADP8870_CFGR, &reg_val);
+               reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT);
+               reg_val |= (val - 1) << CFGR_BLV_SHIFT;
+               adp8870_write(data->client, ADP8870_CFGR, reg_val);
+               mutex_unlock(&data->lock);
+       }
+
+       return count;
+}
+static DEVICE_ATTR(ambient_light_zone, 0664,
+               adp8870_bl_ambient_light_zone_show,
+               adp8870_bl_ambient_light_zone_store);
+#endif
+
+static struct attribute *adp8870_bl_attributes[] = {
+       &dev_attr_l5_dark_max.attr,
+       &dev_attr_l5_dark_dim.attr,
+       &dev_attr_l4_indoor_max.attr,
+       &dev_attr_l4_indoor_dim.attr,
+       &dev_attr_l3_office_max.attr,
+       &dev_attr_l3_office_dim.attr,
+       &dev_attr_l2_bright_max.attr,
+       &dev_attr_l2_bright_dim.attr,
+       &dev_attr_l1_daylight_max.attr,
+       &dev_attr_l1_daylight_dim.attr,
+#ifdef ADP8870_EXT_FEATURES
+       &dev_attr_ambient_light_level.attr,
+       &dev_attr_ambient_light_zone.attr,
+#endif
+       NULL
+};
+
+static const struct attribute_group adp8870_bl_attr_group = {
+       .attrs = adp8870_bl_attributes,
+};
+
+static int __devinit adp8870_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       struct backlight_properties props;
+       struct backlight_device *bl;
+       struct adp8870_bl *data;
+       struct adp8870_backlight_platform_data *pdata =
+               client->dev.platform_data;
+       uint8_t reg_val;
+       int ret;
+
+       if (!i2c_check_functionality(client->adapter,
+                                       I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
+               return -EIO;
+       }
+
+       if (!pdata) {
+               dev_err(&client->dev, "no platform data?\n");
+               return -EINVAL;
+       }
+
+       ret = adp8870_read(client, ADP8870_MFDVID, &reg_val);
+       if (ret < 0)
+               return -EIO;
+
+       if (ADP8870_MANID(reg_val) != ADP8870_MANUFID) {
+               dev_err(&client->dev, "failed to probe\n");
+               return -ENODEV;
+       }
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (data == NULL)
+               return -ENOMEM;
+
+       data->revid = ADP8870_DEVID(reg_val);
+       data->client = client;
+       data->pdata = pdata;
+       data->id = id->driver_data;
+       data->current_brightness = 0;
+       i2c_set_clientdata(client, data);
+
+       mutex_init(&data->lock);
+
+       memset(&props, 0, sizeof(props));
+       props.type = BACKLIGHT_RAW;
+       props.max_brightness = props.brightness = ADP8870_MAX_BRIGHTNESS;
+       bl = backlight_device_register(dev_driver_string(&client->dev),
+                       &client->dev, data, &adp8870_bl_ops, &props);
+       if (IS_ERR(bl)) {
+               dev_err(&client->dev, "failed to register backlight\n");
+               ret = PTR_ERR(bl);
+               goto out2;
+       }
+
+       data->bl = bl;
+
+       if (pdata->en_ambl_sens)
+               ret = sysfs_create_group(&bl->dev.kobj,
+                       &adp8870_bl_attr_group);
+
+       if (ret) {
+               dev_err(&client->dev, "failed to register sysfs\n");
+               goto out1;
+       }
+
+       ret = adp8870_bl_setup(bl);
+       if (ret) {
+               ret = -EIO;
+               goto out;
+       }
+
+       backlight_update_status(bl);
+
+       dev_info(&client->dev, "Rev.%d Backlight\n", data->revid);
+
+       if (pdata->num_leds)
+               adp8870_led_probe(client);
+
+       return 0;
+
+out:
+       if (data->pdata->en_ambl_sens)
+               sysfs_remove_group(&data->bl->dev.kobj,
+                       &adp8870_bl_attr_group);
+out1:
+       backlight_device_unregister(bl);
+out2:
+       i2c_set_clientdata(client, NULL);
+       kfree(data);
+
+       return ret;
+}
+
+static int __devexit adp8870_remove(struct i2c_client *client)
+{
+       struct adp8870_bl *data = i2c_get_clientdata(client);
+
+       adp8870_clr_bits(client, ADP8870_MDCR, NSTBY);
+
+       if (data->led)
+               adp8870_led_remove(client);
+
+       if (data->pdata->en_ambl_sens)
+               sysfs_remove_group(&data->bl->dev.kobj,
+                       &adp8870_bl_attr_group);
+
+       backlight_device_unregister(data->bl);
+       i2c_set_clientdata(client, NULL);
+       kfree(data);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int adp8870_i2c_suspend(struct i2c_client *client, pm_message_t message)
+{
+       adp8870_clr_bits(client, ADP8870_MDCR, NSTBY);
+
+       return 0;
+}
+
+static int adp8870_i2c_resume(struct i2c_client *client)
+{
+       adp8870_set_bits(client, ADP8870_MDCR, NSTBY);
+
+       return 0;
+}
+#else
+#define adp8870_i2c_suspend NULL
+#define adp8870_i2c_resume NULL
+#endif
+
+static const struct i2c_device_id adp8870_id[] = {
+       { "adp8870", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adp8870_id);
+
+static struct i2c_driver adp8870_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+       },
+       .probe    = adp8870_probe,
+       .remove   = __devexit_p(adp8870_remove),
+       .suspend = adp8870_i2c_suspend,
+       .resume  = adp8870_i2c_resume,
+       .id_table = adp8870_id,
+};
+
+static int __init adp8870_init(void)
+{
+       return i2c_add_driver(&adp8870_driver);
+}
+module_init(adp8870_init);
+
+static void __exit adp8870_exit(void)
+{
+       i2c_del_driver(&adp8870_driver);
+}
+module_exit(adp8870_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADP8870 Backlight driver");
+MODULE_ALIAS("platform:adp8870-backlight");
index 47c21fb2c82fc50b2ac1329c30c1055b96874391..bea53c1a4950143d149a6694334dc8606f37fdd0 100644 (file)
@@ -789,6 +789,7 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev)
        i2c_add_driver(&ad5280_driver);
 
        memset(&props, 0, sizeof(props));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = MAX_BRIGHENESS;
        bl_dev = backlight_device_register("bf537-bl", NULL, NULL,
                                           &bfin_lq035fb_bl_ops, &props);
index ebda6876d3a9efe26c2883ac7e73f8fad020c4fc..377dde3d5bfc8954aaccfc643b9664408e0c9da1 100644 (file)
@@ -1101,12 +1101,10 @@ static int __devinit broadsheetfb_probe(struct platform_device *dev)
 
        videomemorysize = roundup((dpyw*dpyh), PAGE_SIZE);
 
-       videomemory = vmalloc(videomemorysize);
+       videomemory = vzalloc(videomemorysize);
        if (!videomemory)
                goto err_fb_rel;
 
-       memset(videomemory, 0, videomemorysize);
-
        info->screen_base = (char *)videomemory;
        info->fbops = &broadsheetfb_ops;
 
index 8b7d47386f3983d883e04bb26be5837a23c65437..fcdac872522d66702e0035bfda682ae189547eec 100644 (file)
@@ -899,7 +899,7 @@ static struct fb_ops da8xx_fb_ops = {
        .fb_blank = cfb_blank,
 };
 
-static int __init fb_probe(struct platform_device *device)
+static int __devinit fb_probe(struct platform_device *device)
 {
        struct da8xx_lcdc_platform_data *fb_pdata =
                                                device->dev.platform_data;
@@ -1165,7 +1165,7 @@ static int fb_resume(struct platform_device *dev)
 
 static struct platform_driver da8xx_fb_driver = {
        .probe = fb_probe,
-       .remove = fb_remove,
+       .remove = __devexit_p(fb_remove),
        .suspend = fb_suspend,
        .resume = fb_resume,
        .driver = {
index 4eb38db36e4b4a3c9d50e6a169cd71fd088ba8cb..784139aed0793cab282cf52f3f3c3503a85a9a5a 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/pci.h>
 #include <video/vga.h>
 
+static bool request_mem_succeeded = false;
+
 static struct fb_var_screeninfo efifb_defined __devinitdata = {
        .activate               = FB_ACTIVATE_NOW,
        .height                 = -1,
@@ -242,9 +244,9 @@ static int set_system(const struct dmi_system_id *id)
                return 0;
        }
 
-       printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p "
+       printk(KERN_INFO "efifb: dmi detected %s - framebuffer at 0x%08x "
                         "(%dx%d, stride %d)\n", id->ident,
-                        (void *)screen_info.lfb_base, screen_info.lfb_width,
+                        screen_info.lfb_base, screen_info.lfb_width,
                         screen_info.lfb_height, screen_info.lfb_linelength);
 
 
@@ -281,7 +283,9 @@ static void efifb_destroy(struct fb_info *info)
 {
        if (info->screen_base)
                iounmap(info->screen_base);
-       release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size);
+       if (request_mem_succeeded)
+               release_mem_region(info->apertures->ranges[0].base,
+                                  info->apertures->ranges[0].size);
        framebuffer_release(info);
 }
 
@@ -326,14 +330,13 @@ static int __init efifb_setup(char *options)
        return 0;
 }
 
-static int __devinit efifb_probe(struct platform_device *dev)
+static int __init efifb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
        int err;
        unsigned int size_vmode;
        unsigned int size_remap;
        unsigned int size_total;
-       int request_succeeded = 0;
 
        if (!screen_info.lfb_depth)
                screen_info.lfb_depth = 32;
@@ -387,7 +390,7 @@ static int __devinit efifb_probe(struct platform_device *dev)
        efifb_fix.smem_len = size_remap;
 
        if (request_mem_region(efifb_fix.smem_start, size_remap, "efifb")) {
-               request_succeeded = 1;
+               request_mem_succeeded = true;
        } else {
                /* We cannot make this fatal. Sometimes this comes from magic
                   spaces our resource handlers simply don't know about */
@@ -413,7 +416,7 @@ static int __devinit efifb_probe(struct platform_device *dev)
        info->apertures->ranges[0].base = efifb_fix.smem_start;
        info->apertures->ranges[0].size = size_remap;
 
-       info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len);
+       info->screen_base = ioremap_wc(efifb_fix.smem_start, efifb_fix.smem_len);
        if (!info->screen_base) {
                printk(KERN_ERR "efifb: abort, cannot ioremap video memory "
                                "0x%x @ 0x%lx\n",
@@ -491,13 +494,12 @@ err_unmap:
 err_release_fb:
        framebuffer_release(info);
 err_release_mem:
-       if (request_succeeded)
+       if (request_mem_succeeded)
                release_mem_region(efifb_fix.smem_start, size_total);
        return err;
 }
 
 static struct platform_driver efifb_driver = {
-       .probe  = efifb_probe,
        .driver = {
                .name   = "efifb",
        },
@@ -528,13 +530,21 @@ static int __init efifb_init(void)
        if (!screen_info.lfb_linelength)
                return -ENODEV;
 
-       ret = platform_driver_register(&efifb_driver);
+       ret = platform_device_register(&efifb_device);
+       if (ret)
+               return ret;
 
-       if (!ret) {
-               ret = platform_device_register(&efifb_device);
-               if (ret)
-                       platform_driver_unregister(&efifb_driver);
+       /*
+        * This is not just an optimization.  We will interfere
+        * with a real driver if we get reprobed, so don't allow
+        * it.
+        */
+       ret = platform_driver_probe(&efifb_driver, efifb_probe);
+       if (ret) {
+               platform_device_unregister(&efifb_device);
+               return ret;
        }
+
        return ret;
 }
 module_init(efifb_init);
index 1b94643ecbcfff4dd63eca7b52953ba2f702f21e..fbef15f7a21803051e778b89436cd08c2f0f0561 100644 (file)
@@ -231,11 +231,10 @@ static int __devinit hecubafb_probe(struct platform_device *dev)
 
        videomemorysize = (DPY_W*DPY_H)/8;
 
-       if (!(videomemory = vmalloc(videomemorysize)))
+       videomemory = vzalloc(videomemorysize);
+       if (!videomemory)
                return retval;
 
-       memset(videomemory, 0, videomemorysize);
-
        info = framebuffer_alloc(sizeof(struct hecubafb_par), &dev->dev);
        if (!info)
                goto err_fballoc;
index d2ccfd6e662cbe1fda2da5d766750e21793ebc4c..f135dbead07d8921068de3513dafb2c32ea10973 100644 (file)
@@ -856,10 +856,10 @@ failed_platform_init:
                dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu,
                        fbi->map_dma);
 failed_map:
-       clk_put(fbi->clk);
-failed_getclock:
        iounmap(fbi->regs);
 failed_ioremap:
+       clk_put(fbi->clk);
+failed_getclock:
        release_mem_region(res->start, resource_size(res));
 failed_req:
        kfree(info->pseudo_palette);
index d7777714166b89a5ac24e235d7b53b7bc1a0d81f..5707ed0e31a7378bd98ba8e53df736ce1e19f427 100644 (file)
@@ -2,4 +2,7 @@
 # Makefile for the MB862xx framebuffer driver
 #
 
-obj-$(CONFIG_FB_MB862XX)       := mb862xxfb.o mb862xxfb_accel.o
+obj-$(CONFIG_FB_MB862XX) += mb862xxfb.o
+
+mb862xxfb-y := mb862xxfbdrv.o mb862xxfb_accel.o
+mb862xxfb-$(CONFIG_FB_MB862XX_I2C) += mb862xx-i2c.o
diff --git a/drivers/video/mb862xx/mb862xx-i2c.c b/drivers/video/mb862xx/mb862xx-i2c.c
new file mode 100644 (file)
index 0000000..b953099
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Coral-P(A)/Lime I2C adapter driver
+ *
+ * (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de>
+ *
+ * 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/fb.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include "mb862xxfb.h"
+#include "mb862xx_reg.h"
+
+static int mb862xx_i2c_wait_event(struct i2c_adapter *adap)
+{
+       struct mb862xxfb_par *par = adap->algo_data;
+       u32 reg;
+
+       do {
+               udelay(1);
+               reg = inreg(i2c, GC_I2C_BCR);
+               if (reg & (I2C_INT | I2C_BER))
+                       break;
+       } while (1);
+
+       return (reg & I2C_BER) ? 0 : 1;
+}
+
+static int mb862xx_i2c_do_address(struct i2c_adapter *adap, int addr)
+{
+       struct mb862xxfb_par *par = adap->algo_data;
+
+       outreg(i2c, GC_I2C_DAR, addr);
+       outreg(i2c, GC_I2C_CCR, I2C_CLOCK_AND_ENABLE);
+       outreg(i2c, GC_I2C_BCR, par->i2c_rs ? I2C_REPEATED_START : I2C_START);
+       if (!mb862xx_i2c_wait_event(adap))
+               return -EIO;
+       par->i2c_rs = !(inreg(i2c, GC_I2C_BSR) & I2C_LRB);
+       return par->i2c_rs;
+}
+
+static int mb862xx_i2c_write_byte(struct i2c_adapter *adap, u8 byte)
+{
+       struct mb862xxfb_par *par = adap->algo_data;
+
+       outreg(i2c, GC_I2C_DAR, byte);
+       outreg(i2c, GC_I2C_BCR, I2C_START);
+       if (!mb862xx_i2c_wait_event(adap))
+               return -EIO;
+       return !(inreg(i2c, GC_I2C_BSR) & I2C_LRB);
+}
+
+static int mb862xx_i2c_read_byte(struct i2c_adapter *adap, u8 *byte, int last)
+{
+       struct mb862xxfb_par *par = adap->algo_data;
+
+       outreg(i2c, GC_I2C_BCR, I2C_START | (last ? 0 : I2C_ACK));
+       if (!mb862xx_i2c_wait_event(adap))
+               return 0;
+       *byte = inreg(i2c, GC_I2C_DAR);
+       return 1;
+}
+
+void mb862xx_i2c_stop(struct i2c_adapter *adap)
+{
+       struct mb862xxfb_par *par = adap->algo_data;
+
+       outreg(i2c, GC_I2C_BCR, I2C_STOP);
+       outreg(i2c, GC_I2C_CCR, I2C_DISABLE);
+       par->i2c_rs = 0;
+}
+
+static int mb862xx_i2c_read(struct i2c_adapter *adap, struct i2c_msg *m)
+{
+       int i, ret = 0;
+       int last = m->len - 1;
+
+       for (i = 0; i < m->len; i++) {
+               if (!mb862xx_i2c_read_byte(adap, &m->buf[i], i == last)) {
+                       ret = -EIO;
+                       break;
+               }
+       }
+       return ret;
+}
+
+static int mb862xx_i2c_write(struct i2c_adapter *adap, struct i2c_msg *m)
+{
+       int i, ret = 0;
+
+       for (i = 0; i < m->len; i++) {
+               if (!mb862xx_i2c_write_byte(adap, m->buf[i])) {
+                       ret = -EIO;
+                       break;
+               }
+       }
+       return ret;
+}
+
+static int mb862xx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+                       int num)
+{
+       struct mb862xxfb_par *par = adap->algo_data;
+       struct i2c_msg *m;
+       int addr;
+       int i = 0, err = 0;
+
+       dev_dbg(par->dev, "%s: %d msgs\n", __func__, num);
+
+       for (i = 0; i < num; i++) {
+               m = &msgs[i];
+               if (!m->len) {
+                       dev_dbg(par->dev, "%s: null msgs\n", __func__);
+                       continue;
+               }
+               addr = m->addr;
+               if (m->flags & I2C_M_RD)
+                       addr |= 1;
+
+               err = mb862xx_i2c_do_address(adap, addr);
+               if (err < 0)
+                       break;
+               if (m->flags & I2C_M_RD)
+                       err = mb862xx_i2c_read(adap, m);
+               else
+                       err = mb862xx_i2c_write(adap, m);
+       }
+
+       if (i)
+               mb862xx_i2c_stop(adap);
+
+       return (err < 0) ? err : i;
+}
+
+static u32 mb862xx_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_SMBUS_BYTE_DATA;
+}
+
+static const struct i2c_algorithm mb862xx_algo = {
+       .master_xfer    = mb862xx_xfer,
+       .functionality  = mb862xx_func,
+};
+
+static struct i2c_adapter mb862xx_i2c_adapter = {
+       .name           = "MB862xx I2C adapter",
+       .algo           = &mb862xx_algo,
+       .owner          = THIS_MODULE,
+};
+
+int mb862xx_i2c_init(struct mb862xxfb_par *par)
+{
+       int ret;
+
+       mb862xx_i2c_adapter.algo_data = par;
+       par->adap = &mb862xx_i2c_adapter;
+
+       ret = i2c_add_adapter(par->adap);
+       if (ret < 0) {
+               dev_err(par->dev, "failed to add %s\n",
+                       mb862xx_i2c_adapter.name);
+       }
+       return ret;
+}
+
+void mb862xx_i2c_exit(struct mb862xxfb_par *par)
+{
+       if (par->adap) {
+               i2c_del_adapter(par->adap);
+               par->adap = NULL;
+       }
+}
index 2ba65e118500e99b1874e47aa94f3ded12dd0493..9df48b8edc94f6e745391a6a8ab9e3f9bb3de764 100644 (file)
@@ -5,11 +5,8 @@
 #ifndef _MB862XX_REG_H
 #define _MB862XX_REG_H
 
-#ifdef MB862XX_MMIO_BOTTOM
-#define MB862XX_MMIO_BASE      0x03fc0000
-#else
 #define MB862XX_MMIO_BASE      0x01fc0000
-#endif
+#define MB862XX_MMIO_HIGH_BASE 0x03fc0000
 #define MB862XX_I2C_BASE       0x0000c000
 #define MB862XX_DISP_BASE      0x00010000
 #define MB862XX_CAP_BASE       0x00018000
@@ -23,6 +20,7 @@
 #define GC_IMASK               0x00000024
 #define GC_SRST                        0x0000002c
 #define GC_CCF                 0x00000038
+#define GC_RSW                 0x0000005c
 #define GC_CID                 0x000000f0
 #define GC_REVISION            0x00000084
 
 #define GC_L0OA0               0x00000024
 #define GC_L0DA0               0x00000028
 #define GC_L0DY_L0DX           0x0000002c
+#define GC_L1M                 0x00000030
+#define GC_L1DA                        0x00000034
 #define GC_DCM1                        0x00000100
 #define GC_L0EM                        0x00000110
 #define GC_L0WY_L0WX           0x00000114
 #define GC_L0WH_L0WW           0x00000118
+#define GC_L1EM                        0x00000120
+#define GC_L1WY_L1WX           0x00000124
+#define GC_L1WH_L1WW           0x00000128
+#define GC_DLS                 0x00000180
 #define GC_DCM2                        0x00000104
 #define GC_DCM3                        0x00000108
 #define GC_CPM_CUTC            0x000000a0
 
 #define GC_CPM_CEN0            0x00100000
 #define GC_CPM_CEN1            0x00200000
+#define GC_DCM1_DEN            0x80000000
+#define GC_DCM1_L1E            0x00020000
+#define GC_L1M_16              0x80000000
+#define GC_L1M_YC              0x40000000
+#define GC_L1M_CS              0x20000000
 
 #define GC_DCM01_ESY           0x00000004
 #define GC_DCM01_SC            0x00003f00
 #define GC_L0M_L0C_16          0x80000000
 #define GC_L0EM_L0EC_24                0x40000000
 #define GC_L0M_L0W_UNIT                64
+#define GC_L1EM_DM             0x02000000
 
 #define GC_DISP_REFCLK_400     400
 
+/* I2C */
+#define GC_I2C_BSR             0x00000000      /* BSR */
+#define GC_I2C_BCR             0x00000004      /* BCR */
+#define GC_I2C_CCR             0x00000008      /* CCR */
+#define GC_I2C_ADR             0x0000000C      /* ADR */
+#define GC_I2C_DAR             0x00000010      /* DAR */
+
+#define I2C_DISABLE            0x00000000
+#define I2C_STOP               0x00000000
+#define I2C_START              0x00000010
+#define I2C_REPEATED_START     0x00000030
+#define I2C_CLOCK_AND_ENABLE   0x0000003f
+#define I2C_READY              0x01
+#define I2C_INT                        0x01
+#define I2C_INTE               0x02
+#define I2C_ACK                        0x08
+#define I2C_BER                        0x80
+#define I2C_BEIE               0x40
+#define I2C_TRX                        0x80
+#define I2C_LRB                        0x10
+
+/* Capture registers and bits */
+#define GC_CAP_VCM             0x00000000
+#define GC_CAP_CSC             0x00000004
+#define GC_CAP_VCS             0x00000008
+#define GC_CAP_CBM             0x00000010
+#define GC_CAP_CBOA            0x00000014
+#define GC_CAP_CBLA            0x00000018
+#define GC_CAP_IMG_START       0x0000001C
+#define GC_CAP_IMG_END         0x00000020
+#define GC_CAP_CMSS            0x00000048
+#define GC_CAP_CMDS            0x0000004C
+
+#define GC_VCM_VIE             0x80000000
+#define GC_VCM_CM              0x03000000
+#define GC_VCM_VS_PAL          0x00000002
+#define GC_CBM_OO              0x80000000
+#define GC_CBM_HRV             0x00000010
+#define GC_CBM_CBST            0x00000001
+
 /* Carmine specific */
 #define MB86297_DRAW_BASE              0x00020000
 #define MB86297_DISP0_BASE             0x00100000
index d7e7cb76bbf2522dd05398cd6442da90e2ae7c56..8550630c1e01dc8ee71d64aee5a43755fef6115a 100644 (file)
@@ -1,6 +1,26 @@
 #ifndef __MB862XX_H__
 #define __MB862XX_H__
 
+struct mb862xx_l1_cfg {
+       unsigned short sx;
+       unsigned short sy;
+       unsigned short sw;
+       unsigned short sh;
+       unsigned short dx;
+       unsigned short dy;
+       unsigned short dw;
+       unsigned short dh;
+       int mirror;
+};
+
+#define MB862XX_BASE           'M'
+#define MB862XX_L1_GET_CFG     _IOR(MB862XX_BASE, 0, struct mb862xx_l1_cfg*)
+#define MB862XX_L1_SET_CFG     _IOW(MB862XX_BASE, 1, struct mb862xx_l1_cfg*)
+#define MB862XX_L1_ENABLE      _IOW(MB862XX_BASE, 2, int)
+#define MB862XX_L1_CAP_CTL     _IOW(MB862XX_BASE, 3, int)
+
+#ifdef __KERNEL__
+
 #define PCI_VENDOR_ID_FUJITSU_LIMITED  0x10cf
 #define PCI_DEVICE_ID_FUJITSU_CORALP   0x2019
 #define PCI_DEVICE_ID_FUJITSU_CORALPA  0x201e
@@ -38,6 +58,8 @@ struct mb862xxfb_par {
        void __iomem            *mmio_base;     /* remapped registers */
        size_t                  mapped_vram;    /* length of remapped vram */
        size_t                  mmio_len;       /* length of register region */
+       unsigned long           cap_buf;        /* capture buffers offset */
+       size_t                  cap_len;        /* length of capture buffers */
 
        void __iomem            *host;          /* relocatable reg. bases */
        void __iomem            *i2c;
@@ -57,11 +79,23 @@ struct mb862xxfb_par {
        unsigned int            refclk;         /* disp. reference clock */
        struct mb862xx_gc_mode  *gc_mode;       /* GDC mode init data */
        int                     pre_init;       /* don't init display if 1 */
+       struct i2c_adapter      *adap;          /* GDC I2C bus adapter */
+       int                     i2c_rs;
+
+       struct mb862xx_l1_cfg   l1_cfg;
+       int                     l1_stride;
 
        u32                     pseudo_palette[16];
 };
 
 extern void mb862xxfb_init_accel(struct fb_info *info, int xres);
+#ifdef CONFIG_FB_MB862XX_I2C
+extern int mb862xx_i2c_init(struct mb862xxfb_par *par);
+extern void mb862xx_i2c_exit(struct mb862xxfb_par *par);
+#else
+static inline int mb862xx_i2c_init(struct mb862xxfb_par *par) { return 0; }
+static inline void mb862xx_i2c_exit(struct mb862xxfb_par *par) { }
+#endif
 
 #if defined(CONFIG_FB_MB862XX_LIME) && defined(CONFIG_FB_MB862XX_PCI_GDC)
 #error "Select Lime GDC or CoralP/Carmine support, but not both together"
@@ -82,4 +116,6 @@ extern void mb862xxfb_init_accel(struct fb_info *info, int xres);
 
 #define pack(a, b)     (((a) << 16) | (b))
 
+#endif /* __KERNEL__ */
+
 #endif
similarity index 86%
rename from drivers/video/mb862xx/mb862xxfb.c
rename to drivers/video/mb862xx/mb862xxfbdrv.c
index c76e663a6cd41a6ab43721174bf5e08b0cb0f095..f70bd63b01871223d74a2930bdd4823c27a120d7 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/fb.h>
 #include <linux/delay.h>
+#include <linux/uaccess.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
@@ -27,7 +28,7 @@
 
 #define NR_PALETTE             256
 #define MB862XX_MEM_SIZE       0x1000000
-#define CORALP_MEM_SIZE                0x4000000
+#define CORALP_MEM_SIZE                0x2000000
 #define CARMINE_MEM_SIZE       0x8000000
 #define DRV_NAME               "mb862xxfb"
 
@@ -309,6 +310,97 @@ static int mb862xxfb_blank(int mode, struct fb_info *fbi)
        return 0;
 }
 
+static int mb862xxfb_ioctl(struct fb_info *fbi, unsigned int cmd,
+                          unsigned long arg)
+{
+       struct mb862xxfb_par *par = fbi->par;
+       struct mb862xx_l1_cfg *l1_cfg = &par->l1_cfg;
+       void __user *argp = (void __user *)arg;
+       int *enable;
+       u32 l1em = 0;
+
+       switch (cmd) {
+       case MB862XX_L1_GET_CFG:
+               if (copy_to_user(argp, l1_cfg, sizeof(*l1_cfg)))
+                       return -EFAULT;
+               break;
+       case MB862XX_L1_SET_CFG:
+               if (copy_from_user(l1_cfg, argp, sizeof(*l1_cfg)))
+                       return -EFAULT;
+               if ((l1_cfg->sw >= l1_cfg->dw) && (l1_cfg->sh >= l1_cfg->dh)) {
+                       /* downscaling */
+                       outreg(cap, GC_CAP_CSC,
+                               pack((l1_cfg->sh << 11) / l1_cfg->dh,
+                                    (l1_cfg->sw << 11) / l1_cfg->dw));
+                       l1em = inreg(disp, GC_L1EM);
+                       l1em &= ~GC_L1EM_DM;
+               } else if ((l1_cfg->sw <= l1_cfg->dw) &&
+                          (l1_cfg->sh <= l1_cfg->dh)) {
+                       /* upscaling */
+                       outreg(cap, GC_CAP_CSC,
+                               pack((l1_cfg->sh << 11) / l1_cfg->dh,
+                                    (l1_cfg->sw << 11) / l1_cfg->dw));
+                       outreg(cap, GC_CAP_CMSS,
+                               pack(l1_cfg->sw >> 1, l1_cfg->sh));
+                       outreg(cap, GC_CAP_CMDS,
+                               pack(l1_cfg->dw >> 1, l1_cfg->dh));
+                       l1em = inreg(disp, GC_L1EM);
+                       l1em |= GC_L1EM_DM;
+               }
+
+               if (l1_cfg->mirror) {
+                       outreg(cap, GC_CAP_CBM,
+                               inreg(cap, GC_CAP_CBM) | GC_CBM_HRV);
+                       l1em |= l1_cfg->dw * 2 - 8;
+               } else {
+                       outreg(cap, GC_CAP_CBM,
+                               inreg(cap, GC_CAP_CBM) & ~GC_CBM_HRV);
+                       l1em &= 0xffff0000;
+               }
+               outreg(disp, GC_L1EM, l1em);
+               break;
+       case MB862XX_L1_ENABLE:
+               enable = (int *)arg;
+               if (*enable) {
+                       outreg(disp, GC_L1DA, par->cap_buf);
+                       outreg(cap, GC_CAP_IMG_START,
+                               pack(l1_cfg->sy >> 1, l1_cfg->sx));
+                       outreg(cap, GC_CAP_IMG_END,
+                               pack(l1_cfg->sh, l1_cfg->sw));
+                       outreg(disp, GC_L1M, GC_L1M_16 | GC_L1M_YC | GC_L1M_CS |
+                                            (par->l1_stride << 16));
+                       outreg(disp, GC_L1WY_L1WX,
+                               pack(l1_cfg->dy, l1_cfg->dx));
+                       outreg(disp, GC_L1WH_L1WW,
+                               pack(l1_cfg->dh - 1, l1_cfg->dw));
+                       outreg(disp, GC_DLS, 1);
+                       outreg(cap, GC_CAP_VCM,
+                               GC_VCM_VIE | GC_VCM_CM | GC_VCM_VS_PAL);
+                       outreg(disp, GC_DCM1, inreg(disp, GC_DCM1) |
+                                             GC_DCM1_DEN | GC_DCM1_L1E);
+               } else {
+                       outreg(cap, GC_CAP_VCM,
+                               inreg(cap, GC_CAP_VCM) & ~GC_VCM_VIE);
+                       outreg(disp, GC_DCM1,
+                               inreg(disp, GC_DCM1) & ~GC_DCM1_L1E);
+               }
+               break;
+       case MB862XX_L1_CAP_CTL:
+               enable = (int *)arg;
+               if (*enable) {
+                       outreg(cap, GC_CAP_VCM,
+                               inreg(cap, GC_CAP_VCM) | GC_VCM_VIE);
+               } else {
+                       outreg(cap, GC_CAP_VCM,
+                               inreg(cap, GC_CAP_VCM) & ~GC_VCM_VIE);
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
 /* framebuffer ops */
 static struct fb_ops mb862xxfb_ops = {
        .owner          = THIS_MODULE,
@@ -320,6 +412,7 @@ static struct fb_ops mb862xxfb_ops = {
        .fb_fillrect    = cfb_fillrect,
        .fb_copyarea    = cfb_copyarea,
        .fb_imageblit   = cfb_imageblit,
+       .fb_ioctl       = mb862xxfb_ioctl,
 };
 
 /* initialize fb_info data */
@@ -328,6 +421,7 @@ static int mb862xxfb_init_fbinfo(struct fb_info *fbi)
        struct mb862xxfb_par *par = fbi->par;
        struct mb862xx_gc_mode *mode = par->gc_mode;
        unsigned long reg;
+       int stride;
 
        fbi->fbops = &mb862xxfb_ops;
        fbi->pseudo_palette = par->pseudo_palette;
@@ -336,7 +430,6 @@ static int mb862xxfb_init_fbinfo(struct fb_info *fbi)
 
        strcpy(fbi->fix.id, DRV_NAME);
        fbi->fix.smem_start = (unsigned long)par->fb_base_phys;
-       fbi->fix.smem_len = par->mapped_vram;
        fbi->fix.mmio_start = (unsigned long)par->mmio_base_phys;
        fbi->fix.mmio_len = par->mmio_len;
        fbi->fix.accel = FB_ACCEL_NONE;
@@ -420,6 +513,28 @@ static int mb862xxfb_init_fbinfo(struct fb_info *fbi)
                         FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
        fbi->fix.line_length = (fbi->var.xres_virtual *
                                fbi->var.bits_per_pixel) / 8;
+       fbi->fix.smem_len = fbi->fix.line_length * fbi->var.yres_virtual;
+
+       /*
+        * reserve space for capture buffers and two cursors
+        * at the end of vram: 720x576 * 2 * 2.2 + 64x64 * 16.
+        */
+       par->cap_buf = par->mapped_vram - 0x1bd800 - 0x10000;
+       par->cap_len = 0x1bd800;
+       par->l1_cfg.sx = 0;
+       par->l1_cfg.sy = 0;
+       par->l1_cfg.sw = 720;
+       par->l1_cfg.sh = 576;
+       par->l1_cfg.dx = 0;
+       par->l1_cfg.dy = 0;
+       par->l1_cfg.dw = 720;
+       par->l1_cfg.dh = 576;
+       stride = par->l1_cfg.sw * (fbi->var.bits_per_pixel / 8);
+       par->l1_stride = stride / 64 + ((stride % 64) ? 1 : 0);
+       outreg(cap, GC_CAP_CBM, GC_CBM_OO | GC_CBM_CBST |
+                               (par->l1_stride << 16));
+       outreg(cap, GC_CAP_CBOA, par->cap_buf);
+       outreg(cap, GC_CAP_CBLA, par->cap_buf + par->cap_len);
        return 0;
 }
 
@@ -742,22 +857,38 @@ static int coralp_init(struct mb862xxfb_par *par)
 
        par->refclk = GC_DISP_REFCLK_400;
 
+       if (par->mapped_vram >= 0x2000000) {
+               /* relocate gdc registers space */
+               writel(1, par->fb_base + MB862XX_MMIO_BASE + GC_RSW);
+               udelay(1); /* wait at least 20 bus cycles */
+       }
+
        ver = inreg(host, GC_CID);
        cn = (ver & GC_CID_CNAME_MSK) >> 8;
        ver = ver & GC_CID_VERSION_MSK;
        if (cn == 3) {
+               unsigned long reg;
+
                dev_info(par->dev, "Fujitsu Coral-%s GDC Rev.%d found\n",\
                         (ver == 6) ? "P" : (ver == 8) ? "PA" : "?",
                         par->pdev->revision);
-               outreg(host, GC_CCF, GC_CCF_CGE_166 | GC_CCF_COT_133);
-               udelay(200);
-               outreg(host, GC_MMR, GC_MMR_CORALP_EVB_VAL);
-               udelay(10);
+               reg = inreg(disp, GC_DCM1);
+               if (reg & GC_DCM01_DEN && reg & GC_DCM01_L0E)
+                       par->pre_init = 1;
+
+               if (!par->pre_init) {
+                       outreg(host, GC_CCF, GC_CCF_CGE_166 | GC_CCF_COT_133);
+                       udelay(200);
+                       outreg(host, GC_MMR, GC_MMR_CORALP_EVB_VAL);
+                       udelay(10);
+               }
                /* Clear interrupt status */
                outreg(host, GC_IST, 0);
        } else {
                return -ENODEV;
        }
+
+       mb862xx_i2c_init(par);
        return 0;
 }
 
@@ -899,7 +1030,13 @@ static int __devinit mb862xx_pci_probe(struct pci_dev *pdev,
        case PCI_DEVICE_ID_FUJITSU_CORALPA:
                par->fb_base_phys = pci_resource_start(par->pdev, 0);
                par->mapped_vram = CORALP_MEM_SIZE;
-               par->mmio_base_phys = par->fb_base_phys + MB862XX_MMIO_BASE;
+               if (par->mapped_vram >= 0x2000000) {
+                       par->mmio_base_phys = par->fb_base_phys +
+                                             MB862XX_MMIO_HIGH_BASE;
+               } else {
+                       par->mmio_base_phys = par->fb_base_phys +
+                                             MB862XX_MMIO_BASE;
+               }
                par->mmio_len = MB862XX_MMIO_SIZE;
                par->type = BT_CORALP;
                break;
@@ -1009,6 +1146,8 @@ static void __devexit mb862xx_pci_remove(struct pci_dev *pdev)
                outreg(host, GC_IMASK, 0);
        }
 
+       mb862xx_i2c_exit(par);
+
        device_remove_file(&pdev->dev, &dev_attr_dispregs);
 
        pci_set_drvdata(pdev, NULL);
index ed64edfd2c43b7a97e693ff30b6e26972caaf7f7..97d45e5115e254647454d7c5b7598053944c7273 100644 (file)
@@ -628,12 +628,10 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
        /* we need to add a spare page because our csum caching scheme walks
         * to the end of the page */
        videomemorysize = PAGE_SIZE + (fw * fh);
-       videomemory = vmalloc(videomemorysize);
+       videomemory = vzalloc(videomemorysize);
        if (!videomemory)
                goto err_fb_rel;
 
-       memset(videomemory, 0, videomemorysize);
-
        info->screen_base = (char __force __iomem *)videomemory;
        info->fbops = &metronomefb_ops;
 
index 48c3ea8652b66e0b7862a392c5d4a04b4df95f32..cb175fe7abc0829f65d7aeb3c54082bb80a8999a 100644 (file)
@@ -1128,3 +1128,4 @@ EXPORT_SYMBOL(fb_find_best_mode);
 EXPORT_SYMBOL(fb_find_nearest_mode);
 EXPORT_SYMBOL(fb_videomode_to_modelist);
 EXPORT_SYMBOL(fb_find_mode);
+EXPORT_SYMBOL(fb_find_mode_cvt);
index 49226a1b909ebfb57c488a2132cea7b55fab0d95..25db55696e142961dc814bdc4fe98ca40ea2d371 100644 (file)
@@ -30,7 +30,6 @@ objs-y$(CONFIG_MACH_OMAP_APOLLON) += lcd_apollon.o
 objs-y$(CONFIG_MACH_OMAP_2430SDP) += lcd_2430sdp.o
 objs-y$(CONFIG_MACH_OMAP_3430SDP) += lcd_2430sdp.o
 objs-y$(CONFIG_MACH_OMAP_LDP) += lcd_ldp.o
-objs-y$(CONFIG_MACH_OMAP2EVM) += lcd_omap2evm.o
 objs-y$(CONFIG_MACH_OMAP3EVM) += lcd_omap3evm.o
 objs-y$(CONFIG_MACH_OMAP3_BEAGLE) += lcd_omap3beagle.o
 objs-y$(CONFIG_FB_OMAP_LCD_MIPID) += lcd_mipid.o
index 529483467abf0254fbe6da582c938e57c8494e8a..0ccd7adf47bb2db54312287fb5191ac8ed4b2b94 100644 (file)
@@ -922,14 +922,14 @@ static int get_dss_clocks(void)
                return PTR_ERR(dispc.dss_ick);
        }
 
-       dispc.dss1_fck = clk_get(&dispc.fbdev->dssdev->dev, "dss1_fck");
+       dispc.dss1_fck = clk_get(&dispc.fbdev->dssdev->dev, "fck");
        if (IS_ERR(dispc.dss1_fck)) {
                dev_err(dispc.fbdev->dev, "can't get dss1_fck\n");
                clk_put(dispc.dss_ick);
                return PTR_ERR(dispc.dss1_fck);
        }
 
-       dispc.dss_54m_fck = clk_get(&dispc.fbdev->dssdev->dev, "tv_fck");
+       dispc.dss_54m_fck = clk_get(&dispc.fbdev->dssdev->dev, "tv_clk");
        if (IS_ERR(dispc.dss_54m_fck)) {
                dev_err(dispc.fbdev->dev, "can't get tv_fck\n");
                clk_put(dispc.dss_ick);
diff --git a/drivers/video/omap/lcd_omap2evm.c b/drivers/video/omap/lcd_omap2evm.c
deleted file mode 100644 (file)
index 7e7a65c..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * LCD panel support for the MISTRAL OMAP2EVM board
- *
- * Author: Arun C <arunedarath@mistralsolutions.com>
- *
- * Derived from drivers/video/omap/lcd_omap3evm.c
- * Derived from drivers/video/omap/lcd-apollon.c
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/i2c/twl.h>
-
-#include <plat/mux.h>
-#include <asm/mach-types.h>
-
-#include "omapfb.h"
-
-#define LCD_PANEL_ENABLE_GPIO  154
-#define LCD_PANEL_LR           128
-#define LCD_PANEL_UD           129
-#define LCD_PANEL_INI          152
-#define LCD_PANEL_QVGA         148
-#define LCD_PANEL_RESB         153
-
-#define TWL_LED_LEDEN          0x00
-#define TWL_PWMA_PWMAON                0x00
-#define TWL_PWMA_PWMAOFF       0x01
-
-static unsigned int bklight_level;
-
-static int omap2evm_panel_init(struct lcd_panel *panel,
-                               struct omapfb_device *fbdev)
-{
-       gpio_request(LCD_PANEL_ENABLE_GPIO, "LCD enable");
-       gpio_request(LCD_PANEL_LR, "LCD lr");
-       gpio_request(LCD_PANEL_UD, "LCD ud");
-       gpio_request(LCD_PANEL_INI, "LCD ini");
-       gpio_request(LCD_PANEL_QVGA, "LCD qvga");
-       gpio_request(LCD_PANEL_RESB, "LCD resb");
-
-       gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 1);
-       gpio_direction_output(LCD_PANEL_RESB, 1);
-       gpio_direction_output(LCD_PANEL_INI, 1);
-       gpio_direction_output(LCD_PANEL_QVGA, 0);
-       gpio_direction_output(LCD_PANEL_LR, 1);
-       gpio_direction_output(LCD_PANEL_UD, 1);
-
-       twl_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN);
-       twl_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON);
-       twl_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF);
-       bklight_level = 100;
-
-       return 0;
-}
-
-static void omap2evm_panel_cleanup(struct lcd_panel *panel)
-{
-       gpio_free(LCD_PANEL_RESB);
-       gpio_free(LCD_PANEL_QVGA);
-       gpio_free(LCD_PANEL_INI);
-       gpio_free(LCD_PANEL_UD);
-       gpio_free(LCD_PANEL_LR);
-       gpio_free(LCD_PANEL_ENABLE_GPIO);
-}
-
-static int omap2evm_panel_enable(struct lcd_panel *panel)
-{
-       gpio_set_value(LCD_PANEL_ENABLE_GPIO, 0);
-       return 0;
-}
-
-static void omap2evm_panel_disable(struct lcd_panel *panel)
-{
-       gpio_set_value(LCD_PANEL_ENABLE_GPIO, 1);
-}
-
-static unsigned long omap2evm_panel_get_caps(struct lcd_panel *panel)
-{
-       return 0;
-}
-
-static int omap2evm_bklight_setlevel(struct lcd_panel *panel,
-                                               unsigned int level)
-{
-       u8 c;
-       if ((level >= 0) && (level <= 100)) {
-               c = (125 * (100 - level)) / 100 + 2;
-               twl_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF);
-               bklight_level = level;
-       }
-       return 0;
-}
-
-static unsigned int omap2evm_bklight_getlevel(struct lcd_panel *panel)
-{
-       return bklight_level;
-}
-
-static unsigned int omap2evm_bklight_getmaxlevel(struct lcd_panel *panel)
-{
-       return 100;
-}
-
-struct lcd_panel omap2evm_panel = {
-       .name           = "omap2evm",
-       .config         = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
-                         OMAP_LCDC_INV_HSYNC,
-
-       .bpp            = 16,
-       .data_lines     = 18,
-       .x_res          = 480,
-       .y_res          = 640,
-       .hsw            = 3,
-       .hfp            = 0,
-       .hbp            = 28,
-       .vsw            = 2,
-       .vfp            = 1,
-       .vbp            = 0,
-
-       .pixel_clock    = 20000,
-
-       .init           = omap2evm_panel_init,
-       .cleanup        = omap2evm_panel_cleanup,
-       .enable         = omap2evm_panel_enable,
-       .disable        = omap2evm_panel_disable,
-       .get_caps       = omap2evm_panel_get_caps,
-       .set_bklight_level      = omap2evm_bklight_setlevel,
-       .get_bklight_level      = omap2evm_bklight_getlevel,
-       .get_bklight_max        = omap2evm_bklight_getmaxlevel,
-};
-
-static int omap2evm_panel_probe(struct platform_device *pdev)
-{
-       omapfb_register_panel(&omap2evm_panel);
-       return 0;
-}
-
-static int omap2evm_panel_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
-static int omap2evm_panel_suspend(struct platform_device *pdev,
-                                  pm_message_t mesg)
-{
-       return 0;
-}
-
-static int omap2evm_panel_resume(struct platform_device *pdev)
-{
-       return 0;
-}
-
-struct platform_driver omap2evm_panel_driver = {
-       .probe          = omap2evm_panel_probe,
-       .remove         = omap2evm_panel_remove,
-       .suspend        = omap2evm_panel_suspend,
-       .resume         = omap2evm_panel_resume,
-       .driver         = {
-               .name   = "omap2evm_lcd",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init omap2evm_panel_drv_init(void)
-{
-       return platform_driver_register(&omap2evm_panel_driver);
-}
-
-static void __exit omap2evm_panel_drv_exit(void)
-{
-       platform_driver_unregister(&omap2evm_panel_driver);
-}
-
-module_init(omap2evm_panel_drv_init);
-module_exit(omap2evm_panel_drv_exit);
index e264efd0278f24cf2fa9650e4002d25a0c7160c2..b3ddd743d8a6f59e5b7154ff1a6233202440b43d 100644 (file)
@@ -90,7 +90,7 @@ static void omapdss_release(struct device *dev)
 
 /* dummy device for clocks */
 static struct platform_device omapdss_device = {
-       .name           = "omapdss",
+       .name           = "omapdss_dss",
        .id             = -1,
        .dev            = {
                .release = omapdss_release,
index eada9f12efc767908c1c17f401e1ca0b925a1d37..0c6981f1a4a3dd5326a19cfefb9736a9f7c5adff 100644 (file)
@@ -90,7 +90,7 @@ static int rfbi_get_clocks(void)
                return PTR_ERR(rfbi.dss_ick);
        }
 
-       rfbi.dss1_fck = clk_get(&rfbi.fbdev->dssdev->dev, "dss1_fck");
+       rfbi.dss1_fck = clk_get(&rfbi.fbdev->dssdev->dev, "fck");
        if (IS_ERR(rfbi.dss1_fck)) {
                dev_err(rfbi.fbdev->dev, "can't get dss1_fck\n");
                clk_put(rfbi.dss_ick);
index d853d05dad312361b0d83aa4d4d351d47fd75140..5ddef129f79826e8fadda55cb052204b220cb041 100644 (file)
@@ -1,6 +1,6 @@
 obj-$(CONFIG_OMAP2_VRAM) += vram.o
 obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
 
-obj-y += dss/
-obj-y += omapfb/
+obj-$(CONFIG_OMAP2_DSS) += dss/
+obj-$(CONFIG_FB_OMAP2) += omapfb/
 obj-y += displays/
index d18ad6b2372af818671780c532700422c911f3e8..609a28073178678f87069909d950745a48000a0a 100644 (file)
@@ -3,6 +3,7 @@ menu "OMAP2/3 Display Device Drivers"
 
 config PANEL_GENERIC_DPI
         tristate "Generic DPI Panel"
+       depends on OMAP2_DSS_DPI
         help
          Generic DPI panel driver.
          Supports DVI output for Beagle and OMAP3 SDP.
@@ -11,20 +12,20 @@ config PANEL_GENERIC_DPI
 
 config PANEL_LGPHILIPS_LB035Q02
        tristate "LG.Philips LB035Q02 LCD Panel"
-       depends on OMAP2_DSS && SPI
+       depends on OMAP2_DSS_DPI && SPI
        help
          LCD Panel used on the Gumstix Overo Palo35
 
 config PANEL_SHARP_LS037V7DW01
         tristate "Sharp LS037V7DW01 LCD Panel"
-        depends on OMAP2_DSS
+        depends on OMAP2_DSS_DPI
         select BACKLIGHT_CLASS_DEVICE
         help
           LCD Panel used in TI's SDP3430 and EVM boards
 
 config PANEL_NEC_NL8048HL11_01B
        tristate "NEC NL8048HL11-01B Panel"
-       depends on OMAP2_DSS
+       depends on OMAP2_DSS_DPI
        help
                This NEC NL8048HL11-01B panel is TFT LCD
                used in the Zoom2/3/3630 sdp boards.
@@ -37,7 +38,7 @@ config PANEL_TAAL
 
 config PANEL_TPO_TD043MTEA1
         tristate "TPO TD043MTEA1 LCD Panel"
-        depends on OMAP2_DSS && SPI
+        depends on OMAP2_DSS_DPI && SPI
         help
           LCD Panel used in OMAP3 Pandora
 
index 7e04c921aa2a8585d4cb180776d9469c0b4d44ce..dbd59b8e5b36520e76c472c5621b35bb7c262415 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/backlight.h>
 #include <linux/fb.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define MIPID_CMD_READ_DISP_ID         0x04
 #define MIPID_CMD_READ_RED             0x06
index 4a9b9ff59467fa10c3c274432bb6c901334bd560..9c90f75653fb3d262489d3c9e78f04282bd8d7e2 100644 (file)
@@ -33,8 +33,9 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <video/omapdss.h>
 
-#include <plat/panel-generic-dpi.h>
+#include <video/omap-panel-generic-dpi.h>
 
 struct panel_config {
        struct omap_video_timings timings;
@@ -181,6 +182,56 @@ static struct panel_config generic_dpi_panels[] = {
                .power_off_delay        = 0,
                .name                   = "samsung_lte430wq_f0c",
        },
+
+       /* Seiko 70WVW1TZ3Z3 */
+       {
+               {
+                       .x_res          = 800,
+                       .y_res          = 480,
+
+                       .pixel_clock    = 33000,
+
+                       .hsw            = 128,
+                       .hfp            = 10,
+                       .hbp            = 10,
+
+                       .vsw            = 2,
+                       .vfp            = 4,
+                       .vbp            = 11,
+               },
+               .acbi                   = 0x0,
+               .acb                    = 0x0,
+               .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+                                               OMAP_DSS_LCD_IHS,
+               .power_on_delay         = 0,
+               .power_off_delay        = 0,
+               .name                   = "seiko_70wvw1tz3",
+       },
+
+       /* Powertip PH480272T */
+       {
+               {
+                       .x_res          = 480,
+                       .y_res          = 272,
+
+                       .pixel_clock    = 9000,
+
+                       .hsw            = 40,
+                       .hfp            = 2,
+                       .hbp            = 2,
+
+                       .vsw            = 10,
+                       .vfp            = 2,
+                       .vbp            = 2,
+               },
+               .acbi                   = 0x0,
+               .acb                    = 0x0,
+               .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+                                         OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO,
+               .power_on_delay         = 0,
+               .power_off_delay        = 0,
+               .name                   = "powertip_ph480272t",
+       },
 };
 
 struct panel_drv_data {
@@ -285,7 +336,7 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
        return 0;
 }
 
-static void generic_dpi_panel_remove(struct omap_dss_device *dssdev)
+static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev)
 {
        struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
 
@@ -358,7 +409,7 @@ static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
 
 static struct omap_dss_driver dpi_driver = {
        .probe          = generic_dpi_panel_probe,
-       .remove         = generic_dpi_panel_remove,
+       .remove         = __exit_p(generic_dpi_panel_remove),
 
        .enable         = generic_dpi_panel_enable,
        .disable        = generic_dpi_panel_disable,
index 271324db24366925ca26a1f89737b3cb4ec2a949..e0eb35be303e580ec2c93fc9cc37df6fed9ea784 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/spi/spi.h>
 #include <linux/mutex.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 struct lb035q02_data {
        struct mutex lock;
index 925e0fadff54130e9745645bd71c13f90f10041f..2ba9d0ca187c866f97ec1c56b725865adecde137 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/backlight.h>
 #include <linux/fb.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define LCD_XRES               800
 #define LCD_YRES               480
index d2b35d2df2a60ad03c29b3cf18b0ebae9cce65b7..ba38b3ad17d6d6c8dc8f3e0f2eb33a301f82d3eb 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 struct sharp_data {
        struct backlight_device *bl;
@@ -120,7 +120,7 @@ static int sharp_ls_panel_probe(struct omap_dss_device *dssdev)
        return 0;
 }
 
-static void sharp_ls_panel_remove(struct omap_dss_device *dssdev)
+static void __exit sharp_ls_panel_remove(struct omap_dss_device *dssdev)
 {
        struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
        struct backlight_device *bl = sd->bl;
@@ -205,7 +205,7 @@ static int sharp_ls_panel_resume(struct omap_dss_device *dssdev)
 
 static struct omap_dss_driver sharp_ls_driver = {
        .probe          = sharp_ls_panel_probe,
-       .remove         = sharp_ls_panel_remove,
+       .remove         = __exit_p(sharp_ls_panel_remove),
 
        .enable         = sharp_ls_panel_enable,
        .disable        = sharp_ls_panel_disable,
index adc9900458e1cd7b0e627bb9fb4e9bc16f0b7175..fdd5d4ae437df9e3901f3891e07f188e14596e67 100644 (file)
@@ -33,8 +33,8 @@
 #include <linux/regulator/consumer.h>
 #include <linux/mutex.h>
 
-#include <plat/display.h>
-#include <plat/nokia-dsi-panel.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-nokia-dsi.h>
 
 /* DSI Virtual channel. Hardcoded for now. */
 #define TCH 0
 #define DCS_GET_ID2            0xdb
 #define DCS_GET_ID3            0xdc
 
-#define TAAL_ESD_CHECK_PERIOD  msecs_to_jiffies(5000)
-
 static irqreturn_t taal_te_isr(int irq, void *data);
 static void taal_te_timeout_work_callback(struct work_struct *work);
 static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
 
+static int taal_panel_reset(struct omap_dss_device *dssdev);
+
 struct panel_regulator {
        struct regulator *regulator;
        const char *name;
@@ -229,8 +229,14 @@ struct taal_data {
 
        bool intro_printed;
 
-       struct workqueue_struct *esd_wq;
+       struct workqueue_struct *workqueue;
+
        struct delayed_work esd_work;
+       unsigned esd_interval;
+
+       bool ulps_enabled;
+       unsigned ulps_timeout;
+       struct delayed_work ulps_work;
 
        struct panel_config *panel_config;
 };
@@ -242,6 +248,7 @@ static inline struct nokia_dsi_panel_data
 }
 
 static void taal_esd_work(struct work_struct *work);
+static void taal_ulps_work(struct work_struct *work);
 
 static void hw_guard_start(struct taal_data *td, int guard_msec)
 {
@@ -264,7 +271,7 @@ static int taal_dcs_read_1(struct taal_data *td, u8 dcs_cmd, u8 *data)
        int r;
        u8 buf[1];
 
-       r = dsi_vc_dcs_read(td->channel, dcs_cmd, buf, 1);
+       r = dsi_vc_dcs_read(td->dssdev, td->channel, dcs_cmd, buf, 1);
 
        if (r < 0)
                return r;
@@ -276,7 +283,7 @@ static int taal_dcs_read_1(struct taal_data *td, u8 dcs_cmd, u8 *data)
 
 static int taal_dcs_write_0(struct taal_data *td, u8 dcs_cmd)
 {
-       return dsi_vc_dcs_write(td->channel, &dcs_cmd, 1);
+       return dsi_vc_dcs_write(td->dssdev, td->channel, &dcs_cmd, 1);
 }
 
 static int taal_dcs_write_1(struct taal_data *td, u8 dcs_cmd, u8 param)
@@ -284,7 +291,7 @@ static int taal_dcs_write_1(struct taal_data *td, u8 dcs_cmd, u8 param)
        u8 buf[2];
        buf[0] = dcs_cmd;
        buf[1] = param;
-       return dsi_vc_dcs_write(td->channel, buf, 2);
+       return dsi_vc_dcs_write(td->dssdev, td->channel, buf, 2);
 }
 
 static int taal_sleep_in(struct taal_data *td)
@@ -296,7 +303,7 @@ static int taal_sleep_in(struct taal_data *td)
        hw_guard_wait(td);
 
        cmd = DCS_SLEEP_IN;
-       r = dsi_vc_dcs_write_nosync(td->channel, &cmd, 1);
+       r = dsi_vc_dcs_write_nosync(td->dssdev, td->channel, &cmd, 1);
        if (r)
                return r;
 
@@ -402,7 +409,7 @@ static int taal_set_update_window(struct taal_data *td,
        buf[3] = (x2 >> 8) & 0xff;
        buf[4] = (x2 >> 0) & 0xff;
 
-       r = dsi_vc_dcs_write_nosync(td->channel, buf, sizeof(buf));
+       r = dsi_vc_dcs_write_nosync(td->dssdev, td->channel, buf, sizeof(buf));
        if (r)
                return r;
 
@@ -412,15 +419,132 @@ static int taal_set_update_window(struct taal_data *td,
        buf[3] = (y2 >> 8) & 0xff;
        buf[4] = (y2 >> 0) & 0xff;
 
-       r = dsi_vc_dcs_write_nosync(td->channel, buf, sizeof(buf));
+       r = dsi_vc_dcs_write_nosync(td->dssdev, td->channel, buf, sizeof(buf));
        if (r)
                return r;
 
-       dsi_vc_send_bta_sync(td->channel);
+       dsi_vc_send_bta_sync(td->dssdev, td->channel);
 
        return r;
 }
 
+static void taal_queue_esd_work(struct omap_dss_device *dssdev)
+{
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+       if (td->esd_interval > 0)
+               queue_delayed_work(td->workqueue, &td->esd_work,
+                               msecs_to_jiffies(td->esd_interval));
+}
+
+static void taal_cancel_esd_work(struct omap_dss_device *dssdev)
+{
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+       cancel_delayed_work(&td->esd_work);
+}
+
+static void taal_queue_ulps_work(struct omap_dss_device *dssdev)
+{
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+       if (td->ulps_timeout > 0)
+               queue_delayed_work(td->workqueue, &td->ulps_work,
+                               msecs_to_jiffies(td->ulps_timeout));
+}
+
+static void taal_cancel_ulps_work(struct omap_dss_device *dssdev)
+{
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+       cancel_delayed_work(&td->ulps_work);
+}
+
+static int taal_enter_ulps(struct omap_dss_device *dssdev)
+{
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+       struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
+       int r;
+
+       if (td->ulps_enabled)
+               return 0;
+
+       taal_cancel_ulps_work(dssdev);
+
+       r = _taal_enable_te(dssdev, false);
+       if (r)
+               goto err;
+
+       disable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+
+       omapdss_dsi_display_disable(dssdev, false, true);
+
+       td->ulps_enabled = true;
+
+       return 0;
+
+err:
+       dev_err(&dssdev->dev, "enter ULPS failed");
+       taal_panel_reset(dssdev);
+
+       td->ulps_enabled = false;
+
+       taal_queue_ulps_work(dssdev);
+
+       return r;
+}
+
+static int taal_exit_ulps(struct omap_dss_device *dssdev)
+{
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+       struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
+       int r;
+
+       if (!td->ulps_enabled)
+               return 0;
+
+       r = omapdss_dsi_display_enable(dssdev);
+       if (r)
+               goto err;
+
+       omapdss_dsi_vc_enable_hs(dssdev, td->channel, true);
+
+       r = _taal_enable_te(dssdev, true);
+       if (r)
+               goto err;
+
+       enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+
+       taal_queue_ulps_work(dssdev);
+
+       td->ulps_enabled = false;
+
+       return 0;
+
+err:
+       dev_err(&dssdev->dev, "exit ULPS failed");
+       r = taal_panel_reset(dssdev);
+
+       enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+       td->ulps_enabled = false;
+
+       taal_queue_ulps_work(dssdev);
+
+       return r;
+}
+
+static int taal_wake_up(struct omap_dss_device *dssdev)
+{
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+       if (td->ulps_enabled)
+               return taal_exit_ulps(dssdev);
+
+       taal_cancel_ulps_work(dssdev);
+       taal_queue_ulps_work(dssdev);
+       return 0;
+}
+
 static int taal_bl_update_status(struct backlight_device *dev)
 {
        struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
@@ -441,9 +565,13 @@ static int taal_bl_update_status(struct backlight_device *dev)
 
        if (td->use_dsi_bl) {
                if (td->enabled) {
-                       dsi_bus_lock();
-                       r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level);
-                       dsi_bus_unlock();
+                       dsi_bus_lock(dssdev);
+
+                       r = taal_wake_up(dssdev);
+                       if (!r)
+                               r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level);
+
+                       dsi_bus_unlock(dssdev);
                } else {
                        r = 0;
                }
@@ -504,9 +632,13 @@ static ssize_t taal_num_errors_show(struct device *dev,
        mutex_lock(&td->lock);
 
        if (td->enabled) {
-               dsi_bus_lock();
-               r = taal_dcs_read_1(td, DCS_READ_NUM_ERRORS, &errors);
-               dsi_bus_unlock();
+               dsi_bus_lock(dssdev);
+
+               r = taal_wake_up(dssdev);
+               if (!r)
+                       r = taal_dcs_read_1(td, DCS_READ_NUM_ERRORS, &errors);
+
+               dsi_bus_unlock(dssdev);
        } else {
                r = -ENODEV;
        }
@@ -530,9 +662,13 @@ static ssize_t taal_hw_revision_show(struct device *dev,
        mutex_lock(&td->lock);
 
        if (td->enabled) {
-               dsi_bus_lock();
-               r = taal_get_id(td, &id1, &id2, &id3);
-               dsi_bus_unlock();
+               dsi_bus_lock(dssdev);
+
+               r = taal_wake_up(dssdev);
+               if (!r)
+                       r = taal_get_id(td, &id1, &id2, &id3);
+
+               dsi_bus_unlock(dssdev);
        } else {
                r = -ENODEV;
        }
@@ -579,6 +715,7 @@ static ssize_t store_cabc_mode(struct device *dev,
        struct omap_dss_device *dssdev = to_dss_device(dev);
        struct taal_data *td = dev_get_drvdata(&dssdev->dev);
        int i;
+       int r;
 
        for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
                if (sysfs_streq(cabc_modes[i], buf))
@@ -591,10 +728,19 @@ static ssize_t store_cabc_mode(struct device *dev,
        mutex_lock(&td->lock);
 
        if (td->enabled) {
-               dsi_bus_lock();
-               if (!td->cabc_broken)
-                       taal_dcs_write_1(td, DCS_WRITE_CABC, i);
-               dsi_bus_unlock();
+               dsi_bus_lock(dssdev);
+
+               if (!td->cabc_broken) {
+                       r = taal_wake_up(dssdev);
+                       if (r)
+                               goto err;
+
+                       r = taal_dcs_write_1(td, DCS_WRITE_CABC, i);
+                       if (r)
+                               goto err;
+               }
+
+               dsi_bus_unlock(dssdev);
        }
 
        td->cabc_mode = i;
@@ -602,6 +748,10 @@ static ssize_t store_cabc_mode(struct device *dev,
        mutex_unlock(&td->lock);
 
        return count;
+err:
+       dsi_bus_unlock(dssdev);
+       mutex_unlock(&td->lock);
+       return r;
 }
 
 static ssize_t show_cabc_available_modes(struct device *dev,
@@ -620,18 +770,161 @@ static ssize_t show_cabc_available_modes(struct device *dev,
        return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
 }
 
+static ssize_t taal_store_esd_interval(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct omap_dss_device *dssdev = to_dss_device(dev);
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+       unsigned long t;
+       int r;
+
+       r = strict_strtoul(buf, 10, &t);
+       if (r)
+               return r;
+
+       mutex_lock(&td->lock);
+       taal_cancel_esd_work(dssdev);
+       td->esd_interval = t;
+       if (td->enabled)
+               taal_queue_esd_work(dssdev);
+       mutex_unlock(&td->lock);
+
+       return count;
+}
+
+static ssize_t taal_show_esd_interval(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct omap_dss_device *dssdev = to_dss_device(dev);
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+       unsigned t;
+
+       mutex_lock(&td->lock);
+       t = td->esd_interval;
+       mutex_unlock(&td->lock);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", t);
+}
+
+static ssize_t taal_store_ulps(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct omap_dss_device *dssdev = to_dss_device(dev);
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+       unsigned long t;
+       int r;
+
+       r = strict_strtoul(buf, 10, &t);
+       if (r)
+               return r;
+
+       mutex_lock(&td->lock);
+
+       if (td->enabled) {
+               dsi_bus_lock(dssdev);
+
+               if (t)
+                       r = taal_enter_ulps(dssdev);
+               else
+                       r = taal_wake_up(dssdev);
+
+               dsi_bus_unlock(dssdev);
+       }
+
+       mutex_unlock(&td->lock);
+
+       if (r)
+               return r;
+
+       return count;
+}
+
+static ssize_t taal_show_ulps(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct omap_dss_device *dssdev = to_dss_device(dev);
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+       unsigned t;
+
+       mutex_lock(&td->lock);
+       t = td->ulps_enabled;
+       mutex_unlock(&td->lock);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", t);
+}
+
+static ssize_t taal_store_ulps_timeout(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct omap_dss_device *dssdev = to_dss_device(dev);
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+       unsigned long t;
+       int r;
+
+       r = strict_strtoul(buf, 10, &t);
+       if (r)
+               return r;
+
+       mutex_lock(&td->lock);
+       td->ulps_timeout = t;
+
+       if (td->enabled) {
+               /* taal_wake_up will restart the timer */
+               dsi_bus_lock(dssdev);
+               r = taal_wake_up(dssdev);
+               dsi_bus_unlock(dssdev);
+       }
+
+       mutex_unlock(&td->lock);
+
+       if (r)
+               return r;
+
+       return count;
+}
+
+static ssize_t taal_show_ulps_timeout(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct omap_dss_device *dssdev = to_dss_device(dev);
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+       unsigned t;
+
+       mutex_lock(&td->lock);
+       t = td->ulps_timeout;
+       mutex_unlock(&td->lock);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", t);
+}
+
 static DEVICE_ATTR(num_dsi_errors, S_IRUGO, taal_num_errors_show, NULL);
 static DEVICE_ATTR(hw_revision, S_IRUGO, taal_hw_revision_show, NULL);
 static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
                show_cabc_mode, store_cabc_mode);
 static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
                show_cabc_available_modes, NULL);
+static DEVICE_ATTR(esd_interval, S_IRUGO | S_IWUSR,
+               taal_show_esd_interval, taal_store_esd_interval);
+static DEVICE_ATTR(ulps, S_IRUGO | S_IWUSR,
+               taal_show_ulps, taal_store_ulps);
+static DEVICE_ATTR(ulps_timeout, S_IRUGO | S_IWUSR,
+               taal_show_ulps_timeout, taal_store_ulps_timeout);
 
 static struct attribute *taal_attrs[] = {
        &dev_attr_num_dsi_errors.attr,
        &dev_attr_hw_revision.attr,
        &dev_attr_cabc_mode.attr,
        &dev_attr_cabc_available_modes.attr,
+       &dev_attr_esd_interval.attr,
+       &dev_attr_ulps.attr,
+       &dev_attr_ulps_timeout.attr,
        NULL,
 };
 
@@ -700,6 +993,9 @@ static int taal_probe(struct omap_dss_device *dssdev)
        }
        td->dssdev = dssdev;
        td->panel_config = panel_config;
+       td->esd_interval = panel_data->esd_interval;
+       td->ulps_enabled = false;
+       td->ulps_timeout = panel_data->ulps_timeout;
 
        mutex_init(&td->lock);
 
@@ -710,13 +1006,14 @@ static int taal_probe(struct omap_dss_device *dssdev)
        if (r)
                goto err_reg;
 
-       td->esd_wq = create_singlethread_workqueue("taal_esd");
-       if (td->esd_wq == NULL) {
+       td->workqueue = create_singlethread_workqueue("taal_esd");
+       if (td->workqueue == NULL) {
                dev_err(&dssdev->dev, "can't create ESD workqueue\n");
                r = -ENOMEM;
                goto err_wq;
        }
        INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work);
+       INIT_DELAYED_WORK(&td->ulps_work, taal_ulps_work);
 
        dev_set_drvdata(&dssdev->dev, td);
 
@@ -734,8 +1031,8 @@ static int taal_probe(struct omap_dss_device *dssdev)
                props.max_brightness = 127;
 
        props.type = BACKLIGHT_RAW;
-       bldev = backlight_device_register("taal", &dssdev->dev, dssdev,
-                                         &taal_bl_ops, &props);
+       bldev = backlight_device_register(dev_name(&dssdev->dev), &dssdev->dev,
+                                       dssdev, &taal_bl_ops, &props);
        if (IS_ERR(bldev)) {
                r = PTR_ERR(bldev);
                goto err_bl;
@@ -810,7 +1107,7 @@ err_irq:
 err_gpio:
        backlight_device_unregister(bldev);
 err_bl:
-       destroy_workqueue(td->esd_wq);
+       destroy_workqueue(td->workqueue);
 err_wq:
        free_regulators(panel_config->regulators, panel_config->num_regulators);
 err_reg:
@@ -819,7 +1116,7 @@ err:
        return r;
 }
 
-static void taal_remove(struct omap_dss_device *dssdev)
+static void __exit taal_remove(struct omap_dss_device *dssdev)
 {
        struct taal_data *td = dev_get_drvdata(&dssdev->dev);
        struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
@@ -841,8 +1138,9 @@ static void taal_remove(struct omap_dss_device *dssdev)
        taal_bl_update_status(bldev);
        backlight_device_unregister(bldev);
 
-       cancel_delayed_work(&td->esd_work);
-       destroy_workqueue(td->esd_wq);
+       taal_cancel_ulps_work(dssdev);
+       taal_cancel_esd_work(dssdev);
+       destroy_workqueue(td->workqueue);
 
        /* reset, to be sure that the panel is in a valid state */
        taal_hw_reset(dssdev);
@@ -867,7 +1165,7 @@ static int taal_power_on(struct omap_dss_device *dssdev)
 
        taal_hw_reset(dssdev);
 
-       omapdss_dsi_vc_enable_hs(td->channel, false);
+       omapdss_dsi_vc_enable_hs(dssdev, td->channel, false);
 
        r = taal_sleep_out(td);
        if (r)
@@ -924,7 +1222,7 @@ static int taal_power_on(struct omap_dss_device *dssdev)
                td->intro_printed = true;
        }
 
-       omapdss_dsi_vc_enable_hs(td->channel, true);
+       omapdss_dsi_vc_enable_hs(dssdev, td->channel, true);
 
        return 0;
 err:
@@ -932,7 +1230,7 @@ err:
 
        taal_hw_reset(dssdev);
 
-       omapdss_dsi_display_disable(dssdev);
+       omapdss_dsi_display_disable(dssdev, true, false);
 err0:
        return r;
 }
@@ -955,15 +1253,23 @@ static void taal_power_off(struct omap_dss_device *dssdev)
                taal_hw_reset(dssdev);
        }
 
-       omapdss_dsi_display_disable(dssdev);
+       omapdss_dsi_display_disable(dssdev, true, false);
 
        td->enabled = 0;
 }
 
+static int taal_panel_reset(struct omap_dss_device *dssdev)
+{
+       dev_err(&dssdev->dev, "performing LCD reset\n");
+
+       taal_power_off(dssdev);
+       taal_hw_reset(dssdev);
+       return taal_power_on(dssdev);
+}
+
 static int taal_enable(struct omap_dss_device *dssdev)
 {
        struct taal_data *td = dev_get_drvdata(&dssdev->dev);
-       struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
        int r;
 
        dev_dbg(&dssdev->dev, "enable\n");
@@ -975,18 +1281,16 @@ static int taal_enable(struct omap_dss_device *dssdev)
                goto err;
        }
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
 
        r = taal_power_on(dssdev);
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 
        if (r)
                goto err;
 
-       if (panel_data->use_esd_check)
-               queue_delayed_work(td->esd_wq, &td->esd_work,
-                               TAAL_ESD_CHECK_PERIOD);
+       taal_queue_esd_work(dssdev);
 
        dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
@@ -1007,14 +1311,17 @@ static void taal_disable(struct omap_dss_device *dssdev)
 
        mutex_lock(&td->lock);
 
-       cancel_delayed_work(&td->esd_work);
+       taal_cancel_ulps_work(dssdev);
+       taal_cancel_esd_work(dssdev);
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
 
-       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+               taal_wake_up(dssdev);
                taal_power_off(dssdev);
+       }
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 
        dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 
@@ -1035,13 +1342,16 @@ static int taal_suspend(struct omap_dss_device *dssdev)
                goto err;
        }
 
-       cancel_delayed_work(&td->esd_work);
+       taal_cancel_ulps_work(dssdev);
+       taal_cancel_esd_work(dssdev);
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
 
-       taal_power_off(dssdev);
+       r = taal_wake_up(dssdev);
+       if (!r)
+               taal_power_off(dssdev);
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 
        dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
 
@@ -1056,7 +1366,6 @@ err:
 static int taal_resume(struct omap_dss_device *dssdev)
 {
        struct taal_data *td = dev_get_drvdata(&dssdev->dev);
-       struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
        int r;
 
        dev_dbg(&dssdev->dev, "resume\n");
@@ -1068,19 +1377,17 @@ static int taal_resume(struct omap_dss_device *dssdev)
                goto err;
        }
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
 
        r = taal_power_on(dssdev);
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 
        if (r) {
                dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
        } else {
                dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-               if (panel_data->use_esd_check)
-                       queue_delayed_work(td->esd_wq, &td->esd_work,
-                                       TAAL_ESD_CHECK_PERIOD);
+               taal_queue_esd_work(dssdev);
        }
 
        mutex_unlock(&td->lock);
@@ -1095,7 +1402,7 @@ static void taal_framedone_cb(int err, void *data)
 {
        struct omap_dss_device *dssdev = data;
        dev_dbg(&dssdev->dev, "framedone, err %d\n", err);
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 }
 
 static irqreturn_t taal_te_isr(int irq, void *data)
@@ -1123,7 +1430,7 @@ static irqreturn_t taal_te_isr(int irq, void *data)
        return IRQ_HANDLED;
 err:
        dev_err(&dssdev->dev, "start update failed\n");
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
        return IRQ_HANDLED;
 }
 
@@ -1136,7 +1443,7 @@ static void taal_te_timeout_work_callback(struct work_struct *work)
        dev_err(&dssdev->dev, "TE not received for 250ms!\n");
 
        atomic_set(&td->do_update, 0);
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 }
 
 static int taal_update(struct omap_dss_device *dssdev,
@@ -1149,7 +1456,11 @@ static int taal_update(struct omap_dss_device *dssdev,
        dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
 
        mutex_lock(&td->lock);
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
+
+       r = taal_wake_up(dssdev);
+       if (r)
+               goto err;
 
        if (!td->enabled) {
                r = 0;
@@ -1184,7 +1495,7 @@ static int taal_update(struct omap_dss_device *dssdev,
        mutex_unlock(&td->lock);
        return 0;
 err:
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
        mutex_unlock(&td->lock);
        return r;
 }
@@ -1196,8 +1507,8 @@ static int taal_sync(struct omap_dss_device *dssdev)
        dev_dbg(&dssdev->dev, "sync\n");
 
        mutex_lock(&td->lock);
-       dsi_bus_lock();
-       dsi_bus_unlock();
+       dsi_bus_lock(dssdev);
+       dsi_bus_unlock(dssdev);
        mutex_unlock(&td->lock);
 
        dev_dbg(&dssdev->dev, "sync done\n");
@@ -1235,9 +1546,13 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
        if (td->te_enabled == enable)
                goto end;
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
 
        if (td->enabled) {
+               r = taal_wake_up(dssdev);
+               if (r)
+                       goto err;
+
                r = _taal_enable_te(dssdev, enable);
                if (r)
                        goto err;
@@ -1245,13 +1560,13 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
 
        td->te_enabled = enable;
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 end:
        mutex_unlock(&td->lock);
 
        return 0;
 err:
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
        mutex_unlock(&td->lock);
 
        return r;
@@ -1281,9 +1596,13 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
        if (td->rotate == rotate)
                goto end;
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
 
        if (td->enabled) {
+               r = taal_wake_up(dssdev);
+               if (r)
+                       goto err;
+
                r = taal_set_addr_mode(td, rotate, td->mirror);
                if (r)
                        goto err;
@@ -1291,12 +1610,12 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
 
        td->rotate = rotate;
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 end:
        mutex_unlock(&td->lock);
        return 0;
 err:
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
        mutex_unlock(&td->lock);
        return r;
 }
@@ -1325,8 +1644,12 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
        if (td->mirror == enable)
                goto end;
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
        if (td->enabled) {
+               r = taal_wake_up(dssdev);
+               if (r)
+                       goto err;
+
                r = taal_set_addr_mode(td, td->rotate, enable);
                if (r)
                        goto err;
@@ -1334,12 +1657,12 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
 
        td->mirror = enable;
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 end:
        mutex_unlock(&td->lock);
        return 0;
 err:
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
        mutex_unlock(&td->lock);
        return r;
 }
@@ -1369,7 +1692,11 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
                goto err1;
        }
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
+
+       r = taal_wake_up(dssdev);
+       if (r)
+               goto err2;
 
        r = taal_dcs_read_1(td, DCS_GET_ID1, &id1);
        if (r)
@@ -1381,11 +1708,11 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
        if (r)
                goto err2;
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
        mutex_unlock(&td->lock);
        return 0;
 err2:
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 err1:
        mutex_unlock(&td->lock);
        return r;
@@ -1415,7 +1742,11 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
                        dssdev->panel.timings.x_res *
                        dssdev->panel.timings.y_res * 3);
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
+
+       r = taal_wake_up(dssdev);
+       if (r)
+               goto err2;
 
        /* plen 1 or 2 goes into short packet. until checksum error is fixed,
         * use short packets. plen 32 works, but bigger packets seem to cause
@@ -1427,7 +1758,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
 
        taal_set_update_window(td, x, y, w, h);
 
-       r = dsi_vc_set_max_rx_packet_size(td->channel, plen);
+       r = dsi_vc_set_max_rx_packet_size(dssdev, td->channel, plen);
        if (r)
                goto err2;
 
@@ -1435,7 +1766,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
                u8 dcs_cmd = first ? 0x2e : 0x3e;
                first = 0;
 
-               r = dsi_vc_dcs_read(td->channel, dcs_cmd,
+               r = dsi_vc_dcs_read(dssdev, td->channel, dcs_cmd,
                                buf + buf_used, size - buf_used);
 
                if (r < 0) {
@@ -1461,14 +1792,35 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
        r = buf_used;
 
 err3:
-       dsi_vc_set_max_rx_packet_size(td->channel, 1);
+       dsi_vc_set_max_rx_packet_size(dssdev, td->channel, 1);
 err2:
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 err1:
        mutex_unlock(&td->lock);
        return r;
 }
 
+static void taal_ulps_work(struct work_struct *work)
+{
+       struct taal_data *td = container_of(work, struct taal_data,
+                       ulps_work.work);
+       struct omap_dss_device *dssdev = td->dssdev;
+
+       mutex_lock(&td->lock);
+
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || !td->enabled) {
+               mutex_unlock(&td->lock);
+               return;
+       }
+
+       dsi_bus_lock(dssdev);
+
+       taal_enter_ulps(dssdev);
+
+       dsi_bus_unlock(dssdev);
+       mutex_unlock(&td->lock);
+}
+
 static void taal_esd_work(struct work_struct *work)
 {
        struct taal_data *td = container_of(work, struct taal_data,
@@ -1485,7 +1837,13 @@ static void taal_esd_work(struct work_struct *work)
                return;
        }
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
+
+       r = taal_wake_up(dssdev);
+       if (r) {
+               dev_err(&dssdev->dev, "failed to exit ULPS\n");
+               goto err;
+       }
 
        r = taal_dcs_read_1(td, DCS_RDDSDR, &state1);
        if (r) {
@@ -1521,22 +1879,20 @@ static void taal_esd_work(struct work_struct *work)
                        goto err;
        }
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 
-       queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
+       taal_queue_esd_work(dssdev);
 
        mutex_unlock(&td->lock);
        return;
 err:
        dev_err(&dssdev->dev, "performing LCD reset\n");
 
-       taal_power_off(dssdev);
-       taal_hw_reset(dssdev);
-       taal_power_on(dssdev);
+       taal_panel_reset(dssdev);
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 
-       queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
+       taal_queue_esd_work(dssdev);
 
        mutex_unlock(&td->lock);
 }
@@ -1557,7 +1913,7 @@ static enum omap_dss_update_mode taal_get_update_mode(
 
 static struct omap_dss_driver taal_driver = {
        .probe          = taal_probe,
-       .remove         = taal_remove,
+       .remove         = __exit_p(taal_remove),
 
        .enable         = taal_enable,
        .disable        = taal_disable,
index dbe9d43b4850d80c7218719528ce3c57c473b944..2462b9ec66623f2fa33d6f0b4852a8938e5ac85a 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define TPO_R02_MODE(x)                ((x) & 7)
 #define TPO_R02_MODE_800x480   7
@@ -144,13 +144,15 @@ static ssize_t tpo_td043_vmirror_store(struct device *dev,
        struct device_attribute *attr, const char *buf, size_t count)
 {
        struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
-       long val;
+       int val;
        int ret;
 
-       ret = strict_strtol(buf, 0, &val);
+       ret = kstrtoint(buf, 0, &val);
        if (ret < 0)
                return ret;
 
+       val = !!val;
+
        ret = tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, val);
        if (ret < 0)
                return ret;
@@ -175,7 +177,7 @@ static ssize_t tpo_td043_mode_store(struct device *dev,
        long val;
        int ret;
 
-       ret = strict_strtol(buf, 0, &val);
+       ret = kstrtol(buf, 0, &val);
        if (ret != 0 || val & ~7)
                return -EINVAL;
 
index bfc5da0e9700b7dea404085f50ae56cfb774ba42..6b3e2da11419497687b0a4a9449a793aa338a09a 100644 (file)
@@ -80,7 +80,7 @@ config OMAP2_DSS_SDI
 
 config OMAP2_DSS_DSI
        bool "DSI support"
-       depends on ARCH_OMAP3
+       depends on ARCH_OMAP3 || ARCH_OMAP4
         default n
        help
          MIPI DSI (Display Serial Interface) support.
@@ -90,14 +90,6 @@ config OMAP2_DSS_DSI
 
          See http://www.mipi.org/ for DSI spesifications.
 
-config OMAP2_DSS_USE_DSI_PLL
-       bool "Use DSI PLL for PCLK (EXPERIMENTAL)"
-       default n
-       depends on OMAP2_DSS_DSI
-       help
-         Use DSI PLL to generate pixel clock.  Currently only for DPI output.
-         DSI PLL can be used to generate higher and more precise pixel clocks.
-
 config OMAP2_DSS_FAKE_VSYNC
        bool "Fake VSYNC irq from manual update displays"
        default n
@@ -125,4 +117,27 @@ config OMAP2_DSS_MIN_FCK_PER_PCK
          Max FCK is 173MHz, so this doesn't work if your PCK
          is very high.
 
+config OMAP2_DSS_SLEEP_BEFORE_RESET
+       bool "Sleep 50ms before DSS reset"
+       default y
+       help
+         For some unknown reason we may get SYNC_LOST errors from the display
+         subsystem at initialization time if we don't sleep before resetting
+         the DSS. See the source (dss.c) for more comments.
+
+         However, 50ms is quite long time to sleep, and with some
+         configurations the SYNC_LOST may never happen, so the sleep can
+         be disabled here.
+
+config OMAP2_DSS_SLEEP_AFTER_VENC_RESET
+       bool "Sleep 20ms after VENC reset"
+       default y
+       help
+         There is a 20ms sleep after VENC reset which seemed to fix the
+         reset. The reason for the bug is unclear, and it's also unclear
+         on what platforms this happens.
+
+         This option enables the sleep, and is enabled by default. You can
+         disable the sleep if it doesn't cause problems on your platform.
+
 endif
index 1aa2ed1e786e11cb2ae5f9d827d0b3b78791a504..3da426719dd6e50f9451a60d1a592a6ef79ef83d 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/device.h>
 #include <linux/regulator/consumer.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #include "dss.h"
 #include "dss_features.h"
@@ -54,6 +54,9 @@ unsigned int dss_debug;
 module_param_named(debug, dss_debug, bool, 0644);
 #endif
 
+static int omap_dss_register_device(struct omap_dss_device *);
+static void omap_dss_unregister_device(struct omap_dss_device *);
+
 /* REGULATORS */
 
 struct regulator *dss_get_vdds_dsi(void)
@@ -124,8 +127,7 @@ static int dss_initialize_debugfs(void)
 #endif
 
 #if defined(CONFIG_OMAP2_DSS_DSI) && defined(CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS)
-       debugfs_create_file("dsi_irq", S_IRUGO, dss_debugfs_dir,
-                       &dsi_dump_irqs, &dss_debug_fops);
+       dsi_create_debugfs_files_irq(dss_debugfs_dir, &dss_debug_fops);
 #endif
 
        debugfs_create_file("dss", S_IRUGO, dss_debugfs_dir,
@@ -137,8 +139,7 @@ static int dss_initialize_debugfs(void)
                        &rfbi_dump_regs, &dss_debug_fops);
 #endif
 #ifdef CONFIG_OMAP2_DSS_DSI
-       debugfs_create_file("dsi", S_IRUGO, dss_debugfs_dir,
-                       &dsi_dump_regs, &dss_debug_fops);
+       dsi_create_debugfs_files_reg(dss_debugfs_dir, &dss_debug_fops);
 #endif
 #ifdef CONFIG_OMAP2_DSS_VENC
        debugfs_create_file("venc", S_IRUGO, dss_debugfs_dir,
@@ -480,7 +481,7 @@ static void omap_dss_dev_release(struct device *dev)
        reset_device(dev, 0);
 }
 
-int omap_dss_register_device(struct omap_dss_device *dssdev)
+static int omap_dss_register_device(struct omap_dss_device *dssdev)
 {
        static int dev_num;
 
@@ -494,7 +495,7 @@ int omap_dss_register_device(struct omap_dss_device *dssdev)
        return device_register(&dssdev->dev);
 }
 
-void omap_dss_unregister_device(struct omap_dss_device *dssdev)
+static void omap_dss_unregister_device(struct omap_dss_device *dssdev)
 {
        device_unregister(&dssdev->dev);
 }
index 7804779c9da150bb2ddf431cc9ac1134ef901e89..7a9a2e7d968530f9bac3000d086e4a2eac531d7f 100644 (file)
 #include <plat/sram.h>
 #include <plat/clock.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #include "dss.h"
 #include "dss_features.h"
+#include "dispc.h"
 
 /* DISPC */
 #define DISPC_SZ_REGS                  SZ_4K
 
-struct dispc_reg { u16 idx; };
-
-#define DISPC_REG(idx)                 ((const struct dispc_reg) { idx })
-
-/*
- * DISPC common registers and
- * DISPC channel registers , ch = 0 for LCD, ch = 1 for
- * DIGIT, and ch = 2 for LCD2
- */
-#define DISPC_REVISION                 DISPC_REG(0x0000)
-#define DISPC_SYSCONFIG                        DISPC_REG(0x0010)
-#define DISPC_SYSSTATUS                        DISPC_REG(0x0014)
-#define DISPC_IRQSTATUS                        DISPC_REG(0x0018)
-#define DISPC_IRQENABLE                        DISPC_REG(0x001C)
-#define DISPC_CONTROL                  DISPC_REG(0x0040)
-#define DISPC_CONTROL2                 DISPC_REG(0x0238)
-#define DISPC_CONFIG                   DISPC_REG(0x0044)
-#define DISPC_CONFIG2                  DISPC_REG(0x0620)
-#define DISPC_CAPABLE                  DISPC_REG(0x0048)
-#define DISPC_DEFAULT_COLOR(ch)                DISPC_REG(ch == 0 ? 0x004C : \
-                                       (ch == 1 ? 0x0050 : 0x03AC))
-#define DISPC_TRANS_COLOR(ch)          DISPC_REG(ch == 0 ? 0x0054 : \
-                                       (ch == 1 ? 0x0058 : 0x03B0))
-#define DISPC_LINE_STATUS              DISPC_REG(0x005C)
-#define DISPC_LINE_NUMBER              DISPC_REG(0x0060)
-#define DISPC_TIMING_H(ch)             DISPC_REG(ch != 2 ? 0x0064 : 0x0400)
-#define DISPC_TIMING_V(ch)             DISPC_REG(ch != 2 ? 0x0068 : 0x0404)
-#define DISPC_POL_FREQ(ch)             DISPC_REG(ch != 2 ? 0x006C : 0x0408)
-#define DISPC_DIVISORo(ch)             DISPC_REG(ch != 2 ? 0x0070 : 0x040C)
-#define DISPC_GLOBAL_ALPHA             DISPC_REG(0x0074)
-#define DISPC_SIZE_DIG                 DISPC_REG(0x0078)
-#define DISPC_SIZE_LCD(ch)             DISPC_REG(ch != 2 ? 0x007C : 0x03CC)
-
-/* DISPC GFX plane */
-#define DISPC_GFX_BA0                  DISPC_REG(0x0080)
-#define DISPC_GFX_BA1                  DISPC_REG(0x0084)
-#define DISPC_GFX_POSITION             DISPC_REG(0x0088)
-#define DISPC_GFX_SIZE                 DISPC_REG(0x008C)
-#define DISPC_GFX_ATTRIBUTES           DISPC_REG(0x00A0)
-#define DISPC_GFX_FIFO_THRESHOLD       DISPC_REG(0x00A4)
-#define DISPC_GFX_FIFO_SIZE_STATUS     DISPC_REG(0x00A8)
-#define DISPC_GFX_ROW_INC              DISPC_REG(0x00AC)
-#define DISPC_GFX_PIXEL_INC            DISPC_REG(0x00B0)
-#define DISPC_GFX_WINDOW_SKIP          DISPC_REG(0x00B4)
-#define DISPC_GFX_TABLE_BA             DISPC_REG(0x00B8)
-
-#define DISPC_DATA_CYCLE1(ch)          DISPC_REG(ch != 2 ? 0x01D4 : 0x03C0)
-#define DISPC_DATA_CYCLE2(ch)          DISPC_REG(ch != 2 ? 0x01D8 : 0x03C4)
-#define DISPC_DATA_CYCLE3(ch)          DISPC_REG(ch != 2 ? 0x01DC : 0x03C8)
-#define DISPC_CPR_COEF_R(ch)           DISPC_REG(ch != 2 ? 0x0220 : 0x03BC)
-#define DISPC_CPR_COEF_G(ch)           DISPC_REG(ch != 2 ? 0x0224 : 0x03B8)
-#define DISPC_CPR_COEF_B(ch)           DISPC_REG(ch != 2 ? 0x0228 : 0x03B4)
-
-#define DISPC_GFX_PRELOAD              DISPC_REG(0x022C)
-
-/* DISPC Video plane, n = 0 for VID1 and n = 1 for VID2 */
-#define DISPC_VID_REG(n, idx)          DISPC_REG(0x00BC + (n)*0x90 + idx)
-
-#define DISPC_VID_BA0(n)               DISPC_VID_REG(n, 0x0000)
-#define DISPC_VID_BA1(n)               DISPC_VID_REG(n, 0x0004)
-#define DISPC_VID_POSITION(n)          DISPC_VID_REG(n, 0x0008)
-#define DISPC_VID_SIZE(n)              DISPC_VID_REG(n, 0x000C)
-#define DISPC_VID_ATTRIBUTES(n)                DISPC_VID_REG(n, 0x0010)
-#define DISPC_VID_FIFO_THRESHOLD(n)    DISPC_VID_REG(n, 0x0014)
-#define DISPC_VID_FIFO_SIZE_STATUS(n)  DISPC_VID_REG(n, 0x0018)
-#define DISPC_VID_ROW_INC(n)           DISPC_VID_REG(n, 0x001C)
-#define DISPC_VID_PIXEL_INC(n)         DISPC_VID_REG(n, 0x0020)
-#define DISPC_VID_FIR(n)               DISPC_VID_REG(n, 0x0024)
-#define DISPC_VID_PICTURE_SIZE(n)      DISPC_VID_REG(n, 0x0028)
-#define DISPC_VID_ACCU0(n)             DISPC_VID_REG(n, 0x002C)
-#define DISPC_VID_ACCU1(n)             DISPC_VID_REG(n, 0x0030)
-
-/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
-#define DISPC_VID_FIR_COEF_H(n, i)     DISPC_REG(0x00F0 + (n)*0x90 + (i)*0x8)
-/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
-#define DISPC_VID_FIR_COEF_HV(n, i)    DISPC_REG(0x00F4 + (n)*0x90 + (i)*0x8)
-/* coef index i = {0, 1, 2, 3, 4} */
-#define DISPC_VID_CONV_COEF(n, i)      DISPC_REG(0x0130 + (n)*0x90 + (i)*0x4)
-/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
-#define DISPC_VID_FIR_COEF_V(n, i)     DISPC_REG(0x01E0 + (n)*0x20 + (i)*0x4)
-
-#define DISPC_VID_PRELOAD(n)           DISPC_REG(0x230 + (n)*0x04)
-
-#define DISPC_DIVISOR                  DISPC_REG(0x0804)
-
 #define DISPC_IRQ_MASK_ERROR            (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
                                         DISPC_IRQ_OCP_ERR | \
                                         DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
@@ -167,10 +83,6 @@ struct dispc_v_coef {
 #define REG_FLD_MOD(idx, val, start, end)                              \
        dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
 
-static const struct dispc_reg dispc_reg_att[] = { DISPC_GFX_ATTRIBUTES,
-       DISPC_VID_ATTRIBUTES(0),
-       DISPC_VID_ATTRIBUTES(1) };
-
 struct dispc_irq_stats {
        unsigned long last_reset;
        unsigned irq_count;
@@ -198,25 +110,38 @@ static struct {
 #endif
 } dispc;
 
+enum omap_color_component {
+       /* used for all color formats for OMAP3 and earlier
+        * and for RGB and Y color component on OMAP4
+        */
+       DISPC_COLOR_COMPONENT_RGB_Y             = 1 << 0,
+       /* used for UV component for
+        * OMAP_DSS_COLOR_YUV2, OMAP_DSS_COLOR_UYVY, OMAP_DSS_COLOR_NV12
+        * color formats on OMAP4
+        */
+       DISPC_COLOR_COMPONENT_UV                = 1 << 1,
+};
+
 static void _omap_dispc_set_irqs(void);
 
-static inline void dispc_write_reg(const struct dispc_reg idx, u32 val)
+static inline void dispc_write_reg(const u16 idx, u32 val)
 {
-       __raw_writel(val, dispc.base + idx.idx);
+       __raw_writel(val, dispc.base + idx);
 }
 
-static inline u32 dispc_read_reg(const struct dispc_reg idx)
+static inline u32 dispc_read_reg(const u16 idx)
 {
-       return __raw_readl(dispc.base + idx.idx);
+       return __raw_readl(dispc.base + idx);
 }
 
 #define SR(reg) \
-       dispc.ctx[(DISPC_##reg).idx / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
+       dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
 #define RR(reg) \
-       dispc_write_reg(DISPC_##reg, dispc.ctx[(DISPC_##reg).idx / sizeof(u32)])
+       dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)])
 
 void dispc_save_context(void)
 {
+       int i;
        if (cpu_is_omap24xx())
                return;
 
@@ -224,157 +149,153 @@ void dispc_save_context(void)
        SR(IRQENABLE);
        SR(CONTROL);
        SR(CONFIG);
-       SR(DEFAULT_COLOR(0));
-       SR(DEFAULT_COLOR(1));
-       SR(TRANS_COLOR(0));
-       SR(TRANS_COLOR(1));
+       SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD));
+       SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT));
+       SR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD));
+       SR(TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT));
        SR(LINE_NUMBER);
-       SR(TIMING_H(0));
-       SR(TIMING_V(0));
-       SR(POL_FREQ(0));
-       SR(DIVISORo(0));
+       SR(TIMING_H(OMAP_DSS_CHANNEL_LCD));
+       SR(TIMING_V(OMAP_DSS_CHANNEL_LCD));
+       SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD));
+       SR(DIVISORo(OMAP_DSS_CHANNEL_LCD));
        SR(GLOBAL_ALPHA);
-       SR(SIZE_DIG);
-       SR(SIZE_LCD(0));
+       SR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
+       SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
                SR(CONTROL2);
-               SR(DEFAULT_COLOR(2));
-               SR(TRANS_COLOR(2));
-               SR(SIZE_LCD(2));
-               SR(TIMING_H(2));
-               SR(TIMING_V(2));
-               SR(POL_FREQ(2));
-               SR(DIVISORo(2));
+               SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2));
+               SR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2));
+               SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD2));
+               SR(TIMING_H(OMAP_DSS_CHANNEL_LCD2));
+               SR(TIMING_V(OMAP_DSS_CHANNEL_LCD2));
+               SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD2));
+               SR(DIVISORo(OMAP_DSS_CHANNEL_LCD2));
                SR(CONFIG2);
        }
 
-       SR(GFX_BA0);
-       SR(GFX_BA1);
-       SR(GFX_POSITION);
-       SR(GFX_SIZE);
-       SR(GFX_ATTRIBUTES);
-       SR(GFX_FIFO_THRESHOLD);
-       SR(GFX_ROW_INC);
-       SR(GFX_PIXEL_INC);
-       SR(GFX_WINDOW_SKIP);
-       SR(GFX_TABLE_BA);
-
-       SR(DATA_CYCLE1(0));
-       SR(DATA_CYCLE2(0));
-       SR(DATA_CYCLE3(0));
-
-       SR(CPR_COEF_R(0));
-       SR(CPR_COEF_G(0));
-       SR(CPR_COEF_B(0));
+       SR(OVL_BA0(OMAP_DSS_GFX));
+       SR(OVL_BA1(OMAP_DSS_GFX));
+       SR(OVL_POSITION(OMAP_DSS_GFX));
+       SR(OVL_SIZE(OMAP_DSS_GFX));
+       SR(OVL_ATTRIBUTES(OMAP_DSS_GFX));
+       SR(OVL_FIFO_THRESHOLD(OMAP_DSS_GFX));
+       SR(OVL_ROW_INC(OMAP_DSS_GFX));
+       SR(OVL_PIXEL_INC(OMAP_DSS_GFX));
+       SR(OVL_WINDOW_SKIP(OMAP_DSS_GFX));
+       SR(OVL_TABLE_BA(OMAP_DSS_GFX));
+
+       SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD));
+       SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
+       SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
+
+       SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
+       SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
+       SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
-               SR(CPR_COEF_B(2));
-               SR(CPR_COEF_G(2));
-               SR(CPR_COEF_R(2));
+               SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
+               SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
+               SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
 
-               SR(DATA_CYCLE1(2));
-               SR(DATA_CYCLE2(2));
-               SR(DATA_CYCLE3(2));
+               SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
+               SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
+               SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
        }
 
-       SR(GFX_PRELOAD);
+       SR(OVL_PRELOAD(OMAP_DSS_GFX));
 
        /* VID1 */
-       SR(VID_BA0(0));
-       SR(VID_BA1(0));
-       SR(VID_POSITION(0));
-       SR(VID_SIZE(0));
-       SR(VID_ATTRIBUTES(0));
-       SR(VID_FIFO_THRESHOLD(0));
-       SR(VID_ROW_INC(0));
-       SR(VID_PIXEL_INC(0));
-       SR(VID_FIR(0));
-       SR(VID_PICTURE_SIZE(0));
-       SR(VID_ACCU0(0));
-       SR(VID_ACCU1(0));
-
-       SR(VID_FIR_COEF_H(0, 0));
-       SR(VID_FIR_COEF_H(0, 1));
-       SR(VID_FIR_COEF_H(0, 2));
-       SR(VID_FIR_COEF_H(0, 3));
-       SR(VID_FIR_COEF_H(0, 4));
-       SR(VID_FIR_COEF_H(0, 5));
-       SR(VID_FIR_COEF_H(0, 6));
-       SR(VID_FIR_COEF_H(0, 7));
-
-       SR(VID_FIR_COEF_HV(0, 0));
-       SR(VID_FIR_COEF_HV(0, 1));
-       SR(VID_FIR_COEF_HV(0, 2));
-       SR(VID_FIR_COEF_HV(0, 3));
-       SR(VID_FIR_COEF_HV(0, 4));
-       SR(VID_FIR_COEF_HV(0, 5));
-       SR(VID_FIR_COEF_HV(0, 6));
-       SR(VID_FIR_COEF_HV(0, 7));
-
-       SR(VID_CONV_COEF(0, 0));
-       SR(VID_CONV_COEF(0, 1));
-       SR(VID_CONV_COEF(0, 2));
-       SR(VID_CONV_COEF(0, 3));
-       SR(VID_CONV_COEF(0, 4));
-
-       SR(VID_FIR_COEF_V(0, 0));
-       SR(VID_FIR_COEF_V(0, 1));
-       SR(VID_FIR_COEF_V(0, 2));
-       SR(VID_FIR_COEF_V(0, 3));
-       SR(VID_FIR_COEF_V(0, 4));
-       SR(VID_FIR_COEF_V(0, 5));
-       SR(VID_FIR_COEF_V(0, 6));
-       SR(VID_FIR_COEF_V(0, 7));
-
-       SR(VID_PRELOAD(0));
+       SR(OVL_BA0(OMAP_DSS_VIDEO1));
+       SR(OVL_BA1(OMAP_DSS_VIDEO1));
+       SR(OVL_POSITION(OMAP_DSS_VIDEO1));
+       SR(OVL_SIZE(OMAP_DSS_VIDEO1));
+       SR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO1));
+       SR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1));
+       SR(OVL_ROW_INC(OMAP_DSS_VIDEO1));
+       SR(OVL_PIXEL_INC(OMAP_DSS_VIDEO1));
+       SR(OVL_FIR(OMAP_DSS_VIDEO1));
+       SR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1));
+       SR(OVL_ACCU0(OMAP_DSS_VIDEO1));
+       SR(OVL_ACCU1(OMAP_DSS_VIDEO1));
+
+       for (i = 0; i < 8; i++)
+               SR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, i));
+
+       for (i = 0; i < 8; i++)
+               SR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, i));
+
+       for (i = 0; i < 5; i++)
+               SR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i));
+
+       for (i = 0; i < 8; i++)
+               SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
+
+       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+               SR(OVL_BA0_UV(OMAP_DSS_VIDEO1));
+               SR(OVL_BA1_UV(OMAP_DSS_VIDEO1));
+               SR(OVL_FIR2(OMAP_DSS_VIDEO1));
+               SR(OVL_ACCU2_0(OMAP_DSS_VIDEO1));
+               SR(OVL_ACCU2_1(OMAP_DSS_VIDEO1));
+
+               for (i = 0; i < 8; i++)
+                       SR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, i));
+
+               for (i = 0; i < 8; i++)
+                       SR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, i));
+
+               for (i = 0; i < 8; i++)
+                       SR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, i));
+       }
+       if (dss_has_feature(FEAT_ATTR2))
+               SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
+
+       SR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
 
        /* VID2 */
-       SR(VID_BA0(1));
-       SR(VID_BA1(1));
-       SR(VID_POSITION(1));
-       SR(VID_SIZE(1));
-       SR(VID_ATTRIBUTES(1));
-       SR(VID_FIFO_THRESHOLD(1));
-       SR(VID_ROW_INC(1));
-       SR(VID_PIXEL_INC(1));
-       SR(VID_FIR(1));
-       SR(VID_PICTURE_SIZE(1));
-       SR(VID_ACCU0(1));
-       SR(VID_ACCU1(1));
-
-       SR(VID_FIR_COEF_H(1, 0));
-       SR(VID_FIR_COEF_H(1, 1));
-       SR(VID_FIR_COEF_H(1, 2));
-       SR(VID_FIR_COEF_H(1, 3));
-       SR(VID_FIR_COEF_H(1, 4));
-       SR(VID_FIR_COEF_H(1, 5));
-       SR(VID_FIR_COEF_H(1, 6));
-       SR(VID_FIR_COEF_H(1, 7));
-
-       SR(VID_FIR_COEF_HV(1, 0));
-       SR(VID_FIR_COEF_HV(1, 1));
-       SR(VID_FIR_COEF_HV(1, 2));
-       SR(VID_FIR_COEF_HV(1, 3));
-       SR(VID_FIR_COEF_HV(1, 4));
-       SR(VID_FIR_COEF_HV(1, 5));
-       SR(VID_FIR_COEF_HV(1, 6));
-       SR(VID_FIR_COEF_HV(1, 7));
-
-       SR(VID_CONV_COEF(1, 0));
-       SR(VID_CONV_COEF(1, 1));
-       SR(VID_CONV_COEF(1, 2));
-       SR(VID_CONV_COEF(1, 3));
-       SR(VID_CONV_COEF(1, 4));
-
-       SR(VID_FIR_COEF_V(1, 0));
-       SR(VID_FIR_COEF_V(1, 1));
-       SR(VID_FIR_COEF_V(1, 2));
-       SR(VID_FIR_COEF_V(1, 3));
-       SR(VID_FIR_COEF_V(1, 4));
-       SR(VID_FIR_COEF_V(1, 5));
-       SR(VID_FIR_COEF_V(1, 6));
-       SR(VID_FIR_COEF_V(1, 7));
-
-       SR(VID_PRELOAD(1));
+       SR(OVL_BA0(OMAP_DSS_VIDEO2));
+       SR(OVL_BA1(OMAP_DSS_VIDEO2));
+       SR(OVL_POSITION(OMAP_DSS_VIDEO2));
+       SR(OVL_SIZE(OMAP_DSS_VIDEO2));
+       SR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO2));
+       SR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2));
+       SR(OVL_ROW_INC(OMAP_DSS_VIDEO2));
+       SR(OVL_PIXEL_INC(OMAP_DSS_VIDEO2));
+       SR(OVL_FIR(OMAP_DSS_VIDEO2));
+       SR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2));
+       SR(OVL_ACCU0(OMAP_DSS_VIDEO2));
+       SR(OVL_ACCU1(OMAP_DSS_VIDEO2));
+
+       for (i = 0; i < 8; i++)
+               SR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, i));
+
+       for (i = 0; i < 8; i++)
+               SR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, i));
+
+       for (i = 0; i < 5; i++)
+               SR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i));
+
+       for (i = 0; i < 8; i++)
+               SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
+
+       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+               SR(OVL_BA0_UV(OMAP_DSS_VIDEO2));
+               SR(OVL_BA1_UV(OMAP_DSS_VIDEO2));
+               SR(OVL_FIR2(OMAP_DSS_VIDEO2));
+               SR(OVL_ACCU2_0(OMAP_DSS_VIDEO2));
+               SR(OVL_ACCU2_1(OMAP_DSS_VIDEO2));
+
+               for (i = 0; i < 8; i++)
+                       SR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, i));
+
+               for (i = 0; i < 8; i++)
+                       SR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, i));
+
+               for (i = 0; i < 8; i++)
+                       SR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, i));
+       }
+       if (dss_has_feature(FEAT_ATTR2))
+               SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
+
+       SR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
 
        if (dss_has_feature(FEAT_CORE_CLK_DIV))
                SR(DIVISOR);
@@ -382,160 +303,158 @@ void dispc_save_context(void)
 
 void dispc_restore_context(void)
 {
+       int i;
        RR(SYSCONFIG);
        /*RR(IRQENABLE);*/
        /*RR(CONTROL);*/
        RR(CONFIG);
-       RR(DEFAULT_COLOR(0));
-       RR(DEFAULT_COLOR(1));
-       RR(TRANS_COLOR(0));
-       RR(TRANS_COLOR(1));
+       RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD));
+       RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT));
+       RR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD));
+       RR(TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT));
        RR(LINE_NUMBER);
-       RR(TIMING_H(0));
-       RR(TIMING_V(0));
-       RR(POL_FREQ(0));
-       RR(DIVISORo(0));
+       RR(TIMING_H(OMAP_DSS_CHANNEL_LCD));
+       RR(TIMING_V(OMAP_DSS_CHANNEL_LCD));
+       RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD));
+       RR(DIVISORo(OMAP_DSS_CHANNEL_LCD));
        RR(GLOBAL_ALPHA);
-       RR(SIZE_DIG);
-       RR(SIZE_LCD(0));
+       RR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
+       RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
-               RR(DEFAULT_COLOR(2));
-               RR(TRANS_COLOR(2));
-               RR(SIZE_LCD(2));
-               RR(TIMING_H(2));
-               RR(TIMING_V(2));
-               RR(POL_FREQ(2));
-               RR(DIVISORo(2));
+               RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2));
+               RR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2));
+               RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD2));
+               RR(TIMING_H(OMAP_DSS_CHANNEL_LCD2));
+               RR(TIMING_V(OMAP_DSS_CHANNEL_LCD2));
+               RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD2));
+               RR(DIVISORo(OMAP_DSS_CHANNEL_LCD2));
                RR(CONFIG2);
        }
 
-       RR(GFX_BA0);
-       RR(GFX_BA1);
-       RR(GFX_POSITION);
-       RR(GFX_SIZE);
-       RR(GFX_ATTRIBUTES);
-       RR(GFX_FIFO_THRESHOLD);
-       RR(GFX_ROW_INC);
-       RR(GFX_PIXEL_INC);
-       RR(GFX_WINDOW_SKIP);
-       RR(GFX_TABLE_BA);
-
-       RR(DATA_CYCLE1(0));
-       RR(DATA_CYCLE2(0));
-       RR(DATA_CYCLE3(0));
-
-       RR(CPR_COEF_R(0));
-       RR(CPR_COEF_G(0));
-       RR(CPR_COEF_B(0));
+       RR(OVL_BA0(OMAP_DSS_GFX));
+       RR(OVL_BA1(OMAP_DSS_GFX));
+       RR(OVL_POSITION(OMAP_DSS_GFX));
+       RR(OVL_SIZE(OMAP_DSS_GFX));
+       RR(OVL_ATTRIBUTES(OMAP_DSS_GFX));
+       RR(OVL_FIFO_THRESHOLD(OMAP_DSS_GFX));
+       RR(OVL_ROW_INC(OMAP_DSS_GFX));
+       RR(OVL_PIXEL_INC(OMAP_DSS_GFX));
+       RR(OVL_WINDOW_SKIP(OMAP_DSS_GFX));
+       RR(OVL_TABLE_BA(OMAP_DSS_GFX));
+
+
+       RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD));
+       RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
+       RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
+
+       RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
+       RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
+       RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
-               RR(DATA_CYCLE1(2));
-               RR(DATA_CYCLE2(2));
-               RR(DATA_CYCLE3(2));
+               RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
+               RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
+               RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
 
-               RR(CPR_COEF_B(2));
-               RR(CPR_COEF_G(2));
-               RR(CPR_COEF_R(2));
+               RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
+               RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
+               RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
        }
 
-       RR(GFX_PRELOAD);
+       RR(OVL_PRELOAD(OMAP_DSS_GFX));
 
        /* VID1 */
-       RR(VID_BA0(0));
-       RR(VID_BA1(0));
-       RR(VID_POSITION(0));
-       RR(VID_SIZE(0));
-       RR(VID_ATTRIBUTES(0));
-       RR(VID_FIFO_THRESHOLD(0));
-       RR(VID_ROW_INC(0));
-       RR(VID_PIXEL_INC(0));
-       RR(VID_FIR(0));
-       RR(VID_PICTURE_SIZE(0));
-       RR(VID_ACCU0(0));
-       RR(VID_ACCU1(0));
-
-       RR(VID_FIR_COEF_H(0, 0));
-       RR(VID_FIR_COEF_H(0, 1));
-       RR(VID_FIR_COEF_H(0, 2));
-       RR(VID_FIR_COEF_H(0, 3));
-       RR(VID_FIR_COEF_H(0, 4));
-       RR(VID_FIR_COEF_H(0, 5));
-       RR(VID_FIR_COEF_H(0, 6));
-       RR(VID_FIR_COEF_H(0, 7));
-
-       RR(VID_FIR_COEF_HV(0, 0));
-       RR(VID_FIR_COEF_HV(0, 1));
-       RR(VID_FIR_COEF_HV(0, 2));
-       RR(VID_FIR_COEF_HV(0, 3));
-       RR(VID_FIR_COEF_HV(0, 4));
-       RR(VID_FIR_COEF_HV(0, 5));
-       RR(VID_FIR_COEF_HV(0, 6));
-       RR(VID_FIR_COEF_HV(0, 7));
-
-       RR(VID_CONV_COEF(0, 0));
-       RR(VID_CONV_COEF(0, 1));
-       RR(VID_CONV_COEF(0, 2));
-       RR(VID_CONV_COEF(0, 3));
-       RR(VID_CONV_COEF(0, 4));
-
-       RR(VID_FIR_COEF_V(0, 0));
-       RR(VID_FIR_COEF_V(0, 1));
-       RR(VID_FIR_COEF_V(0, 2));
-       RR(VID_FIR_COEF_V(0, 3));
-       RR(VID_FIR_COEF_V(0, 4));
-       RR(VID_FIR_COEF_V(0, 5));
-       RR(VID_FIR_COEF_V(0, 6));
-       RR(VID_FIR_COEF_V(0, 7));
-
-       RR(VID_PRELOAD(0));
+       RR(OVL_BA0(OMAP_DSS_VIDEO1));
+       RR(OVL_BA1(OMAP_DSS_VIDEO1));
+       RR(OVL_POSITION(OMAP_DSS_VIDEO1));
+       RR(OVL_SIZE(OMAP_DSS_VIDEO1));
+       RR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO1));
+       RR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1));
+       RR(OVL_ROW_INC(OMAP_DSS_VIDEO1));
+       RR(OVL_PIXEL_INC(OMAP_DSS_VIDEO1));
+       RR(OVL_FIR(OMAP_DSS_VIDEO1));
+       RR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1));
+       RR(OVL_ACCU0(OMAP_DSS_VIDEO1));
+       RR(OVL_ACCU1(OMAP_DSS_VIDEO1));
+
+       for (i = 0; i < 8; i++)
+               RR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, i));
+
+       for (i = 0; i < 8; i++)
+               RR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, i));
+
+       for (i = 0; i < 5; i++)
+               RR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i));
+
+       for (i = 0; i < 8; i++)
+               RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
+
+       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+               RR(OVL_BA0_UV(OMAP_DSS_VIDEO1));
+               RR(OVL_BA1_UV(OMAP_DSS_VIDEO1));
+               RR(OVL_FIR2(OMAP_DSS_VIDEO1));
+               RR(OVL_ACCU2_0(OMAP_DSS_VIDEO1));
+               RR(OVL_ACCU2_1(OMAP_DSS_VIDEO1));
+
+               for (i = 0; i < 8; i++)
+                       RR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, i));
+
+               for (i = 0; i < 8; i++)
+                       RR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, i));
+
+               for (i = 0; i < 8; i++)
+                       RR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, i));
+       }
+       if (dss_has_feature(FEAT_ATTR2))
+               RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
+
+       RR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
 
        /* VID2 */
-       RR(VID_BA0(1));
-       RR(VID_BA1(1));
-       RR(VID_POSITION(1));
-       RR(VID_SIZE(1));
-       RR(VID_ATTRIBUTES(1));
-       RR(VID_FIFO_THRESHOLD(1));
-       RR(VID_ROW_INC(1));
-       RR(VID_PIXEL_INC(1));
-       RR(VID_FIR(1));
-       RR(VID_PICTURE_SIZE(1));
-       RR(VID_ACCU0(1));
-       RR(VID_ACCU1(1));
-
-       RR(VID_FIR_COEF_H(1, 0));
-       RR(VID_FIR_COEF_H(1, 1));
-       RR(VID_FIR_COEF_H(1, 2));
-       RR(VID_FIR_COEF_H(1, 3));
-       RR(VID_FIR_COEF_H(1, 4));
-       RR(VID_FIR_COEF_H(1, 5));
-       RR(VID_FIR_COEF_H(1, 6));
-       RR(VID_FIR_COEF_H(1, 7));
-
-       RR(VID_FIR_COEF_HV(1, 0));
-       RR(VID_FIR_COEF_HV(1, 1));
-       RR(VID_FIR_COEF_HV(1, 2));
-       RR(VID_FIR_COEF_HV(1, 3));
-       RR(VID_FIR_COEF_HV(1, 4));
-       RR(VID_FIR_COEF_HV(1, 5));
-       RR(VID_FIR_COEF_HV(1, 6));
-       RR(VID_FIR_COEF_HV(1, 7));
-
-       RR(VID_CONV_COEF(1, 0));
-       RR(VID_CONV_COEF(1, 1));
-       RR(VID_CONV_COEF(1, 2));
-       RR(VID_CONV_COEF(1, 3));
-       RR(VID_CONV_COEF(1, 4));
-
-       RR(VID_FIR_COEF_V(1, 0));
-       RR(VID_FIR_COEF_V(1, 1));
-       RR(VID_FIR_COEF_V(1, 2));
-       RR(VID_FIR_COEF_V(1, 3));
-       RR(VID_FIR_COEF_V(1, 4));
-       RR(VID_FIR_COEF_V(1, 5));
-       RR(VID_FIR_COEF_V(1, 6));
-       RR(VID_FIR_COEF_V(1, 7));
-
-       RR(VID_PRELOAD(1));
+       RR(OVL_BA0(OMAP_DSS_VIDEO2));
+       RR(OVL_BA1(OMAP_DSS_VIDEO2));
+       RR(OVL_POSITION(OMAP_DSS_VIDEO2));
+       RR(OVL_SIZE(OMAP_DSS_VIDEO2));
+       RR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO2));
+       RR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2));
+       RR(OVL_ROW_INC(OMAP_DSS_VIDEO2));
+       RR(OVL_PIXEL_INC(OMAP_DSS_VIDEO2));
+       RR(OVL_FIR(OMAP_DSS_VIDEO2));
+       RR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2));
+       RR(OVL_ACCU0(OMAP_DSS_VIDEO2));
+       RR(OVL_ACCU1(OMAP_DSS_VIDEO2));
+
+       for (i = 0; i < 8; i++)
+               RR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, i));
+
+       for (i = 0; i < 8; i++)
+               RR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, i));
+
+       for (i = 0; i < 5; i++)
+               RR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i));
+
+       for (i = 0; i < 8; i++)
+               RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
+
+       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+               RR(OVL_BA0_UV(OMAP_DSS_VIDEO2));
+               RR(OVL_BA1_UV(OMAP_DSS_VIDEO2));
+               RR(OVL_FIR2(OMAP_DSS_VIDEO2));
+               RR(OVL_ACCU2_0(OMAP_DSS_VIDEO2));
+               RR(OVL_ACCU2_1(OMAP_DSS_VIDEO2));
+
+               for (i = 0; i < 8; i++)
+                       RR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, i));
+
+               for (i = 0; i < 8; i++)
+                       RR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, i));
+
+               for (i = 0; i < 8; i++)
+                       RR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, i));
+       }
+       if (dss_has_feature(FEAT_ATTR2))
+               RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
+
+       RR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
 
        if (dss_has_feature(FEAT_CORE_CLK_DIV))
                RR(DIVISOR);
@@ -631,28 +550,44 @@ end:
 }
 
 static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value)
+{
+       dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value);
+}
+
+static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
+{
+       dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value);
+}
+
+static void _dispc_write_firv_reg(enum omap_plane plane, int reg, u32 value)
+{
+       dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane, reg), value);
+}
+
+static void _dispc_write_firh2_reg(enum omap_plane plane, int reg, u32 value)
 {
        BUG_ON(plane == OMAP_DSS_GFX);
 
-       dispc_write_reg(DISPC_VID_FIR_COEF_H(plane-1, reg), value);
+       dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value);
 }
 
-static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
+static void _dispc_write_firhv2_reg(enum omap_plane plane, int reg, u32 value)
 {
        BUG_ON(plane == OMAP_DSS_GFX);
 
-       dispc_write_reg(DISPC_VID_FIR_COEF_HV(plane-1, reg), value);
+       dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value);
 }
 
-static void _dispc_write_firv_reg(enum omap_plane plane, int reg, u32 value)
+static void _dispc_write_firv2_reg(enum omap_plane plane, int reg, u32 value)
 {
        BUG_ON(plane == OMAP_DSS_GFX);
 
-       dispc_write_reg(DISPC_VID_FIR_COEF_V(plane-1, reg), value);
+       dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value);
 }
 
 static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
-               int vscaleup, int five_taps)
+                                 int vscaleup, int five_taps,
+                                 enum omap_color_component color_comp)
 {
        /* Coefficients for horizontal up-sampling */
        static const struct dispc_h_coef coef_hup[8] = {
@@ -750,8 +685,14 @@ static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
                        | FLD_VAL(v_coef[i].vc1, 23, 16)
                        | FLD_VAL(v_coef[i].vc2, 31, 24);
 
-               _dispc_write_firh_reg(plane, i, h);
-               _dispc_write_firhv_reg(plane, i, hv);
+               if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
+                       _dispc_write_firh_reg(plane, i, h);
+                       _dispc_write_firhv_reg(plane, i, hv);
+               } else {
+                       _dispc_write_firh2_reg(plane, i, h);
+                       _dispc_write_firhv2_reg(plane, i, hv);
+               }
+
        }
 
        if (five_taps) {
@@ -759,7 +700,10 @@ static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
                        u32 v;
                        v = FLD_VAL(v_coef[i].vc00, 7, 0)
                                | FLD_VAL(v_coef[i].vc22, 15, 8);
-                       _dispc_write_firv_reg(plane, i, v);
+                       if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y)
+                               _dispc_write_firv_reg(plane, i, v);
+                       else
+                               _dispc_write_firv2_reg(plane, i, v);
                }
        }
 }
@@ -779,72 +723,83 @@ static void _dispc_setup_color_conv_coef(void)
 
        ct = &ctbl_bt601_5;
 
-       dispc_write_reg(DISPC_VID_CONV_COEF(0, 0), CVAL(ct->rcr, ct->ry));
-       dispc_write_reg(DISPC_VID_CONV_COEF(0, 1), CVAL(ct->gy,  ct->rcb));
-       dispc_write_reg(DISPC_VID_CONV_COEF(0, 2), CVAL(ct->gcb, ct->gcr));
-       dispc_write_reg(DISPC_VID_CONV_COEF(0, 3), CVAL(ct->bcr, ct->by));
-       dispc_write_reg(DISPC_VID_CONV_COEF(0, 4), CVAL(0,       ct->bcb));
-
-       dispc_write_reg(DISPC_VID_CONV_COEF(1, 0), CVAL(ct->rcr, ct->ry));
-       dispc_write_reg(DISPC_VID_CONV_COEF(1, 1), CVAL(ct->gy,  ct->rcb));
-       dispc_write_reg(DISPC_VID_CONV_COEF(1, 2), CVAL(ct->gcb, ct->gcr));
-       dispc_write_reg(DISPC_VID_CONV_COEF(1, 3), CVAL(ct->bcr, ct->by));
-       dispc_write_reg(DISPC_VID_CONV_COEF(1, 4), CVAL(0,       ct->bcb));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 0),
+               CVAL(ct->rcr, ct->ry));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 1),
+               CVAL(ct->gy,  ct->rcb));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2),
+               CVAL(ct->gcb, ct->gcr));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3),
+               CVAL(ct->bcr, ct->by));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4),
+               CVAL(0, ct->bcb));
+
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 0),
+               CVAL(ct->rcr, ct->ry));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 1),
+               CVAL(ct->gy, ct->rcb));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2),
+               CVAL(ct->gcb, ct->gcr));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3),
+               CVAL(ct->bcr, ct->by));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4),
+               CVAL(0, ct->bcb));
 
 #undef CVAL
 
-       REG_FLD_MOD(DISPC_VID_ATTRIBUTES(0), ct->full_range, 11, 11);
-       REG_FLD_MOD(DISPC_VID_ATTRIBUTES(1), ct->full_range, 11, 11);
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO1),
+               ct->full_range, 11, 11);
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO2),
+               ct->full_range, 11, 11);
 }
 
 
 static void _dispc_set_plane_ba0(enum omap_plane plane, u32 paddr)
 {
-       const struct dispc_reg ba0_reg[] = { DISPC_GFX_BA0,
-               DISPC_VID_BA0(0),
-               DISPC_VID_BA0(1) };
-
-       dispc_write_reg(ba0_reg[plane], paddr);
+       dispc_write_reg(DISPC_OVL_BA0(plane), paddr);
 }
 
 static void _dispc_set_plane_ba1(enum omap_plane plane, u32 paddr)
 {
-       const struct dispc_reg ba1_reg[] = { DISPC_GFX_BA1,
-                                     DISPC_VID_BA1(0),
-                                     DISPC_VID_BA1(1) };
+       dispc_write_reg(DISPC_OVL_BA1(plane), paddr);
+}
 
-       dispc_write_reg(ba1_reg[plane], paddr);
+static void _dispc_set_plane_ba0_uv(enum omap_plane plane, u32 paddr)
+{
+       dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr);
 }
 
-static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y)
+static void _dispc_set_plane_ba1_uv(enum omap_plane plane, u32 paddr)
 {
-       const struct dispc_reg pos_reg[] = { DISPC_GFX_POSITION,
-                                     DISPC_VID_POSITION(0),
-                                     DISPC_VID_POSITION(1) };
+       dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr);
+}
 
+static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y)
+{
        u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
-       dispc_write_reg(pos_reg[plane], val);
+
+       dispc_write_reg(DISPC_OVL_POSITION(plane), val);
 }
 
 static void _dispc_set_pic_size(enum omap_plane plane, int width, int height)
 {
-       const struct dispc_reg siz_reg[] = { DISPC_GFX_SIZE,
-                                     DISPC_VID_PICTURE_SIZE(0),
-                                     DISPC_VID_PICTURE_SIZE(1) };
        u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
-       dispc_write_reg(siz_reg[plane], val);
+
+       if (plane == OMAP_DSS_GFX)
+               dispc_write_reg(DISPC_OVL_SIZE(plane), val);
+       else
+               dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
 }
 
 static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
 {
        u32 val;
-       const struct dispc_reg vsi_reg[] = { DISPC_VID_SIZE(0),
-                                     DISPC_VID_SIZE(1) };
 
        BUG_ON(plane == OMAP_DSS_GFX);
 
        val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
-       dispc_write_reg(vsi_reg[plane-1], val);
+
+       dispc_write_reg(DISPC_OVL_SIZE(plane), val);
 }
 
 static void _dispc_set_pre_mult_alpha(enum omap_plane plane, bool enable)
@@ -856,7 +811,7 @@ static void _dispc_set_pre_mult_alpha(enum omap_plane plane, bool enable)
                plane == OMAP_DSS_VIDEO1)
                return;
 
-       REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 28, 28);
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28);
 }
 
 static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
@@ -876,61 +831,93 @@ static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
 
 static void _dispc_set_pix_inc(enum omap_plane plane, s32 inc)
 {
-       const struct dispc_reg ri_reg[] = { DISPC_GFX_PIXEL_INC,
-                                    DISPC_VID_PIXEL_INC(0),
-                                    DISPC_VID_PIXEL_INC(1) };
-
-       dispc_write_reg(ri_reg[plane], inc);
+       dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc);
 }
 
 static void _dispc_set_row_inc(enum omap_plane plane, s32 inc)
 {
-       const struct dispc_reg ri_reg[] = { DISPC_GFX_ROW_INC,
-                                    DISPC_VID_ROW_INC(0),
-                                    DISPC_VID_ROW_INC(1) };
-
-       dispc_write_reg(ri_reg[plane], inc);
+       dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc);
 }
 
 static void _dispc_set_color_mode(enum omap_plane plane,
                enum omap_color_mode color_mode)
 {
        u32 m = 0;
-
-       switch (color_mode) {
-       case OMAP_DSS_COLOR_CLUT1:
-               m = 0x0; break;
-       case OMAP_DSS_COLOR_CLUT2:
-               m = 0x1; break;
-       case OMAP_DSS_COLOR_CLUT4:
-               m = 0x2; break;
-       case OMAP_DSS_COLOR_CLUT8:
-               m = 0x3; break;
-       case OMAP_DSS_COLOR_RGB12U:
-               m = 0x4; break;
-       case OMAP_DSS_COLOR_ARGB16:
-               m = 0x5; break;
-       case OMAP_DSS_COLOR_RGB16:
-               m = 0x6; break;
-       case OMAP_DSS_COLOR_RGB24U:
-               m = 0x8; break;
-       case OMAP_DSS_COLOR_RGB24P:
-               m = 0x9; break;
-       case OMAP_DSS_COLOR_YUV2:
-               m = 0xa; break;
-       case OMAP_DSS_COLOR_UYVY:
-               m = 0xb; break;
-       case OMAP_DSS_COLOR_ARGB32:
-               m = 0xc; break;
-       case OMAP_DSS_COLOR_RGBA32:
-               m = 0xd; break;
-       case OMAP_DSS_COLOR_RGBX32:
-               m = 0xe; break;
-       default:
-               BUG(); break;
+       if (plane != OMAP_DSS_GFX) {
+               switch (color_mode) {
+               case OMAP_DSS_COLOR_NV12:
+                       m = 0x0; break;
+               case OMAP_DSS_COLOR_RGB12U:
+                       m = 0x1; break;
+               case OMAP_DSS_COLOR_RGBA16:
+                       m = 0x2; break;
+               case OMAP_DSS_COLOR_RGBX16:
+                       m = 0x4; break;
+               case OMAP_DSS_COLOR_ARGB16:
+                       m = 0x5; break;
+               case OMAP_DSS_COLOR_RGB16:
+                       m = 0x6; break;
+               case OMAP_DSS_COLOR_ARGB16_1555:
+                       m = 0x7; break;
+               case OMAP_DSS_COLOR_RGB24U:
+                       m = 0x8; break;
+               case OMAP_DSS_COLOR_RGB24P:
+                       m = 0x9; break;
+               case OMAP_DSS_COLOR_YUV2:
+                       m = 0xa; break;
+               case OMAP_DSS_COLOR_UYVY:
+                       m = 0xb; break;
+               case OMAP_DSS_COLOR_ARGB32:
+                       m = 0xc; break;
+               case OMAP_DSS_COLOR_RGBA32:
+                       m = 0xd; break;
+               case OMAP_DSS_COLOR_RGBX32:
+                       m = 0xe; break;
+               case OMAP_DSS_COLOR_XRGB16_1555:
+                       m = 0xf; break;
+               default:
+                       BUG(); break;
+               }
+       } else {
+               switch (color_mode) {
+               case OMAP_DSS_COLOR_CLUT1:
+                       m = 0x0; break;
+               case OMAP_DSS_COLOR_CLUT2:
+                       m = 0x1; break;
+               case OMAP_DSS_COLOR_CLUT4:
+                       m = 0x2; break;
+               case OMAP_DSS_COLOR_CLUT8:
+                       m = 0x3; break;
+               case OMAP_DSS_COLOR_RGB12U:
+                       m = 0x4; break;
+               case OMAP_DSS_COLOR_ARGB16:
+                       m = 0x5; break;
+               case OMAP_DSS_COLOR_RGB16:
+                       m = 0x6; break;
+               case OMAP_DSS_COLOR_ARGB16_1555:
+                       m = 0x7; break;
+               case OMAP_DSS_COLOR_RGB24U:
+                       m = 0x8; break;
+               case OMAP_DSS_COLOR_RGB24P:
+                       m = 0x9; break;
+               case OMAP_DSS_COLOR_YUV2:
+                       m = 0xa; break;
+               case OMAP_DSS_COLOR_UYVY:
+                       m = 0xb; break;
+               case OMAP_DSS_COLOR_ARGB32:
+                       m = 0xc; break;
+               case OMAP_DSS_COLOR_RGBA32:
+                       m = 0xd; break;
+               case OMAP_DSS_COLOR_RGBX32:
+                       m = 0xe; break;
+               case OMAP_DSS_COLOR_XRGB16_1555:
+                       m = 0xf; break;
+               default:
+                       BUG(); break;
+               }
        }
 
-       REG_FLD_MOD(dispc_reg_att[plane], m, 4, 1);
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
 }
 
 static void _dispc_set_channel_out(enum omap_plane plane,
@@ -953,7 +940,7 @@ static void _dispc_set_channel_out(enum omap_plane plane,
                return;
        }
 
-       val = dispc_read_reg(dispc_reg_att[plane]);
+       val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
                switch (channel) {
                case OMAP_DSS_CHANNEL_LCD:
@@ -977,7 +964,7 @@ static void _dispc_set_channel_out(enum omap_plane plane,
        } else {
                val = FLD_MOD(val, channel, shift, shift);
        }
-       dispc_write_reg(dispc_reg_att[plane], val);
+       dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
 }
 
 void dispc_set_burst_size(enum omap_plane plane,
@@ -1001,9 +988,9 @@ void dispc_set_burst_size(enum omap_plane plane,
                return;
        }
 
-       val = dispc_read_reg(dispc_reg_att[plane]);
+       val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
        val = FLD_MOD(val, burst_size, shift+1, shift);
-       dispc_write_reg(dispc_reg_att[plane], val);
+       dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
 
        enable_clocks(0);
 }
@@ -1028,9 +1015,9 @@ static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
 
        BUG_ON(plane == OMAP_DSS_GFX);
 
-       val = dispc_read_reg(dispc_reg_att[plane]);
+       val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
        val = FLD_MOD(val, enable, 9, 9);
-       dispc_write_reg(dispc_reg_att[plane], val);
+       dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
 }
 
 void dispc_enable_replication(enum omap_plane plane, bool enable)
@@ -1043,7 +1030,7 @@ void dispc_enable_replication(enum omap_plane plane, bool enable)
                bit = 10;
 
        enable_clocks(1);
-       REG_FLD_MOD(dispc_reg_att[plane], enable, bit, bit);
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit);
        enable_clocks(0);
 }
 
@@ -1053,7 +1040,7 @@ void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height)
        BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
        val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
        enable_clocks(1);
-       dispc_write_reg(DISPC_SIZE_LCD(channel), val);
+       dispc_write_reg(DISPC_SIZE_MGR(channel), val);
        enable_clocks(0);
 }
 
@@ -1063,15 +1050,12 @@ void dispc_set_digit_size(u16 width, u16 height)
        BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
        val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
        enable_clocks(1);
-       dispc_write_reg(DISPC_SIZE_DIG, val);
+       dispc_write_reg(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT), val);
        enable_clocks(0);
 }
 
 static void dispc_read_plane_fifo_sizes(void)
 {
-       const struct dispc_reg fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
-                                     DISPC_VID_FIFO_SIZE_STATUS(0),
-                                     DISPC_VID_FIFO_SIZE_STATUS(1) };
        u32 size;
        int plane;
        u8 start, end;
@@ -1081,7 +1065,8 @@ static void dispc_read_plane_fifo_sizes(void)
        dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
 
        for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
-               size = FLD_GET(dispc_read_reg(fsz_reg[plane]), start, end);
+               size = FLD_GET(dispc_read_reg(DISPC_OVL_FIFO_SIZE_STATUS(plane)),
+                       start, end);
                dispc.fifo_size[plane] = size;
        }
 
@@ -1095,23 +1080,22 @@ u32 dispc_get_plane_fifo_size(enum omap_plane plane)
 
 void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
 {
-       const struct dispc_reg ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
-                                      DISPC_VID_FIFO_THRESHOLD(0),
-                                      DISPC_VID_FIFO_THRESHOLD(1) };
        u8 hi_start, hi_end, lo_start, lo_end;
 
+       dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
+       dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
+
        enable_clocks(1);
 
        DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
                        plane,
-                       REG_GET(ftrs_reg[plane], 11, 0),
-                       REG_GET(ftrs_reg[plane], 27, 16),
+                       REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
+                               lo_start, lo_end),
+                       REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
+                               hi_start, hi_end),
                        low, high);
 
-       dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
-       dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
-
-       dispc_write_reg(ftrs_reg[plane],
+       dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane),
                        FLD_VAL(high, hi_start, hi_end) |
                        FLD_VAL(low, lo_start, lo_end));
 
@@ -1128,106 +1112,120 @@ void dispc_enable_fifomerge(bool enable)
        enable_clocks(0);
 }
 
-static void _dispc_set_fir(enum omap_plane plane, int hinc, int vinc)
+static void _dispc_set_fir(enum omap_plane plane,
+                               int hinc, int vinc,
+                               enum omap_color_component color_comp)
 {
        u32 val;
-       const struct dispc_reg fir_reg[] = { DISPC_VID_FIR(0),
-                                     DISPC_VID_FIR(1) };
-       u8 hinc_start, hinc_end, vinc_start, vinc_end;
-
-       BUG_ON(plane == OMAP_DSS_GFX);
 
-       dss_feat_get_reg_field(FEAT_REG_FIRHINC, &hinc_start, &hinc_end);
-       dss_feat_get_reg_field(FEAT_REG_FIRVINC, &vinc_start, &vinc_end);
+       if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
+               u8 hinc_start, hinc_end, vinc_start, vinc_end;
 
-       val = FLD_VAL(vinc, vinc_start, vinc_end) |
-                       FLD_VAL(hinc, hinc_start, hinc_end);
+               dss_feat_get_reg_field(FEAT_REG_FIRHINC,
+                                       &hinc_start, &hinc_end);
+               dss_feat_get_reg_field(FEAT_REG_FIRVINC,
+                                       &vinc_start, &vinc_end);
+               val = FLD_VAL(vinc, vinc_start, vinc_end) |
+                               FLD_VAL(hinc, hinc_start, hinc_end);
 
-       dispc_write_reg(fir_reg[plane-1], val);
+               dispc_write_reg(DISPC_OVL_FIR(plane), val);
+       } else {
+               val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
+               dispc_write_reg(DISPC_OVL_FIR2(plane), val);
+       }
 }
 
 static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
 {
        u32 val;
-       const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0),
-                                     DISPC_VID_ACCU0(1) };
        u8 hor_start, hor_end, vert_start, vert_end;
 
-       BUG_ON(plane == OMAP_DSS_GFX);
-
        dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
        dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
 
        val = FLD_VAL(vaccu, vert_start, vert_end) |
                        FLD_VAL(haccu, hor_start, hor_end);
 
-       dispc_write_reg(ac0_reg[plane-1], val);
+       dispc_write_reg(DISPC_OVL_ACCU0(plane), val);
 }
 
 static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
 {
        u32 val;
-       const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0),
-                                     DISPC_VID_ACCU1(1) };
        u8 hor_start, hor_end, vert_start, vert_end;
 
-       BUG_ON(plane == OMAP_DSS_GFX);
-
        dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
        dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
 
        val = FLD_VAL(vaccu, vert_start, vert_end) |
                        FLD_VAL(haccu, hor_start, hor_end);
 
-       dispc_write_reg(ac1_reg[plane-1], val);
+       dispc_write_reg(DISPC_OVL_ACCU1(plane), val);
+}
+
+static void _dispc_set_vid_accu2_0(enum omap_plane plane, int haccu, int vaccu)
+{
+       u32 val;
+
+       val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
+       dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val);
 }
 
+static void _dispc_set_vid_accu2_1(enum omap_plane plane, int haccu, int vaccu)
+{
+       u32 val;
 
-static void _dispc_set_scaling(enum omap_plane plane,
+       val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
+       dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val);
+}
+
+static void _dispc_set_scale_param(enum omap_plane plane,
                u16 orig_width, u16 orig_height,
                u16 out_width, u16 out_height,
-               bool ilace, bool five_taps,
-               bool fieldmode)
+               bool five_taps, u8 rotation,
+               enum omap_color_component color_comp)
 {
-       int fir_hinc;
-       int fir_vinc;
+       int fir_hinc, fir_vinc;
        int hscaleup, vscaleup;
-       int accu0 = 0;
-       int accu1 = 0;
-       u32 l;
-
-       BUG_ON(plane == OMAP_DSS_GFX);
 
        hscaleup = orig_width <= out_width;
        vscaleup = orig_height <= out_height;
 
-       _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps);
+       _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps, color_comp);
 
-       if (!orig_width || orig_width == out_width)
-               fir_hinc = 0;
-       else
-               fir_hinc = 1024 * orig_width / out_width;
+       fir_hinc = 1024 * orig_width / out_width;
+       fir_vinc = 1024 * orig_height / out_height;
 
-       if (!orig_height || orig_height == out_height)
-               fir_vinc = 0;
-       else
-               fir_vinc = 1024 * orig_height / out_height;
+       _dispc_set_fir(plane, fir_hinc, fir_vinc, color_comp);
+}
 
-       _dispc_set_fir(plane, fir_hinc, fir_vinc);
+static void _dispc_set_scaling_common(enum omap_plane plane,
+               u16 orig_width, u16 orig_height,
+               u16 out_width, u16 out_height,
+               bool ilace, bool five_taps,
+               bool fieldmode, enum omap_color_mode color_mode,
+               u8 rotation)
+{
+       int accu0 = 0;
+       int accu1 = 0;
+       u32 l;
 
-       l = dispc_read_reg(dispc_reg_att[plane]);
+       _dispc_set_scale_param(plane, orig_width, orig_height,
+                               out_width, out_height, five_taps,
+                               rotation, DISPC_COLOR_COMPONENT_RGB_Y);
+       l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
 
        /* RESIZEENABLE and VERTICALTAPS */
        l &= ~((0x3 << 5) | (0x1 << 21));
-       l |= fir_hinc ? (1 << 5) : 0;
-       l |= fir_vinc ? (1 << 6) : 0;
+       l |= (orig_width != out_width) ? (1 << 5) : 0;
+       l |= (orig_height != out_height) ? (1 << 6) : 0;
        l |= five_taps ? (1 << 21) : 0;
 
        /* VRESIZECONF and HRESIZECONF */
        if (dss_has_feature(FEAT_RESIZECONF)) {
                l &= ~(0x3 << 7);
-               l |= hscaleup ? 0 : (1 << 7);
-               l |= vscaleup ? 0 : (1 << 8);
+               l |= (orig_width <= out_width) ? 0 : (1 << 7);
+               l |= (orig_height <= out_height) ? 0 : (1 << 8);
        }
 
        /* LINEBUFFERSPLIT */
@@ -1236,7 +1234,7 @@ static void _dispc_set_scaling(enum omap_plane plane,
                l |= five_taps ? (1 << 22) : 0;
        }
 
-       dispc_write_reg(dispc_reg_att[plane], l);
+       dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
 
        /*
         * field 0 = even field = bottom field
@@ -1244,7 +1242,7 @@ static void _dispc_set_scaling(enum omap_plane plane,
         */
        if (ilace && !fieldmode) {
                accu1 = 0;
-               accu0 = (fir_vinc / 2) & 0x3ff;
+               accu0 = ((1024 * orig_height / out_height) / 2) & 0x3ff;
                if (accu0 >= 1024/2) {
                        accu1 = 1024/2;
                        accu0 -= accu1;
@@ -1255,6 +1253,93 @@ static void _dispc_set_scaling(enum omap_plane plane,
        _dispc_set_vid_accu1(plane, 0, accu1);
 }
 
+static void _dispc_set_scaling_uv(enum omap_plane plane,
+               u16 orig_width, u16 orig_height,
+               u16 out_width, u16 out_height,
+               bool ilace, bool five_taps,
+               bool fieldmode, enum omap_color_mode color_mode,
+               u8 rotation)
+{
+       int scale_x = out_width != orig_width;
+       int scale_y = out_height != orig_height;
+
+       if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE))
+               return;
+       if ((color_mode != OMAP_DSS_COLOR_YUV2 &&
+                       color_mode != OMAP_DSS_COLOR_UYVY &&
+                       color_mode != OMAP_DSS_COLOR_NV12)) {
+               /* reset chroma resampling for RGB formats  */
+               REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8);
+               return;
+       }
+       switch (color_mode) {
+       case OMAP_DSS_COLOR_NV12:
+               /* UV is subsampled by 2 vertically*/
+               orig_height >>= 1;
+               /* UV is subsampled by 2 horz.*/
+               orig_width >>= 1;
+               break;
+       case OMAP_DSS_COLOR_YUV2:
+       case OMAP_DSS_COLOR_UYVY:
+               /*For YUV422 with 90/270 rotation,
+                *we don't upsample chroma
+                */
+               if (rotation == OMAP_DSS_ROT_0 ||
+                       rotation == OMAP_DSS_ROT_180)
+                       /* UV is subsampled by 2 hrz*/
+                       orig_width >>= 1;
+               /* must use FIR for YUV422 if rotated */
+               if (rotation != OMAP_DSS_ROT_0)
+                       scale_x = scale_y = true;
+               break;
+       default:
+               BUG();
+       }
+
+       if (out_width != orig_width)
+               scale_x = true;
+       if (out_height != orig_height)
+               scale_y = true;
+
+       _dispc_set_scale_param(plane, orig_width, orig_height,
+                       out_width, out_height, five_taps,
+                               rotation, DISPC_COLOR_COMPONENT_UV);
+
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane),
+               (scale_x || scale_y) ? 1 : 0, 8, 8);
+       /* set H scaling */
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5);
+       /* set V scaling */
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6);
+
+       _dispc_set_vid_accu2_0(plane, 0x80, 0);
+       _dispc_set_vid_accu2_1(plane, 0x80, 0);
+}
+
+static void _dispc_set_scaling(enum omap_plane plane,
+               u16 orig_width, u16 orig_height,
+               u16 out_width, u16 out_height,
+               bool ilace, bool five_taps,
+               bool fieldmode, enum omap_color_mode color_mode,
+               u8 rotation)
+{
+       BUG_ON(plane == OMAP_DSS_GFX);
+
+       _dispc_set_scaling_common(plane,
+                       orig_width, orig_height,
+                       out_width, out_height,
+                       ilace, five_taps,
+                       fieldmode, color_mode,
+                       rotation);
+
+       _dispc_set_scaling_uv(plane,
+               orig_width, orig_height,
+               out_width, out_height,
+               ilace, five_taps,
+               fieldmode, color_mode,
+               rotation);
+}
+
 static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
                bool mirroring, enum omap_color_mode color_mode)
 {
@@ -1302,9 +1387,10 @@ static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
                        row_repeat = false;
        }
 
-       REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12);
        if (dss_has_feature(FEAT_ROWREPEATENABLE))
-               REG_FLD_MOD(dispc_reg_att[plane], row_repeat ? 1 : 0, 18, 18);
+               REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane),
+                       row_repeat ? 1 : 0, 18, 18);
 }
 
 static int color_mode_to_bpp(enum omap_color_mode color_mode)
@@ -1317,12 +1403,17 @@ static int color_mode_to_bpp(enum omap_color_mode color_mode)
        case OMAP_DSS_COLOR_CLUT4:
                return 4;
        case OMAP_DSS_COLOR_CLUT8:
+       case OMAP_DSS_COLOR_NV12:
                return 8;
        case OMAP_DSS_COLOR_RGB12U:
        case OMAP_DSS_COLOR_RGB16:
        case OMAP_DSS_COLOR_ARGB16:
        case OMAP_DSS_COLOR_YUV2:
        case OMAP_DSS_COLOR_UYVY:
+       case OMAP_DSS_COLOR_RGBA16:
+       case OMAP_DSS_COLOR_RGBX16:
+       case OMAP_DSS_COLOR_ARGB16_1555:
+       case OMAP_DSS_COLOR_XRGB16_1555:
                return 16;
        case OMAP_DSS_COLOR_RGB24P:
                return 24;
@@ -1655,7 +1746,7 @@ static int _dispc_setup_plane(enum omap_plane plane,
                enum omap_dss_rotation_type rotation_type,
                u8 rotation, int mirror,
                u8 global_alpha, u8 pre_mult_alpha,
-               enum omap_channel channel)
+               enum omap_channel channel, u32 puv_addr)
 {
        const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
        bool five_taps = 0;
@@ -1704,7 +1795,8 @@ static int _dispc_setup_plane(enum omap_plane plane,
                        return -EINVAL;
 
                if (color_mode == OMAP_DSS_COLOR_YUV2 ||
-                       color_mode == OMAP_DSS_COLOR_UYVY)
+                       color_mode == OMAP_DSS_COLOR_UYVY ||
+                       color_mode == OMAP_DSS_COLOR_NV12)
                        cconv = 1;
 
                /* Must use 5-tap filter? */
@@ -1778,6 +1870,12 @@ static int _dispc_setup_plane(enum omap_plane plane,
        _dispc_set_plane_ba0(plane, paddr + offset0);
        _dispc_set_plane_ba1(plane, paddr + offset1);
 
+       if (OMAP_DSS_COLOR_NV12 == color_mode) {
+               _dispc_set_plane_ba0_uv(plane, puv_addr + offset0);
+               _dispc_set_plane_ba1_uv(plane, puv_addr + offset1);
+       }
+
+
        _dispc_set_row_inc(plane, row_inc);
        _dispc_set_pix_inc(plane, pix_inc);
 
@@ -1791,7 +1889,8 @@ static int _dispc_setup_plane(enum omap_plane plane,
        if (plane != OMAP_DSS_GFX) {
                _dispc_set_scaling(plane, width, height,
                                   out_width, out_height,
-                                  ilace, five_taps, fieldmode);
+                                  ilace, five_taps, fieldmode,
+                                  color_mode, rotation);
                _dispc_set_vid_size(plane, out_width, out_height);
                _dispc_set_vid_color_conv(plane, cconv);
        }
@@ -1806,7 +1905,7 @@ static int _dispc_setup_plane(enum omap_plane plane,
 
 static void _dispc_enable_plane(enum omap_plane plane, bool enable)
 {
-       REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 0, 0);
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
 }
 
 static void dispc_disable_isr(void *data, u32 mask)
@@ -2353,14 +2452,20 @@ static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div,
 
 unsigned long dispc_fclk_rate(void)
 {
+       struct platform_device *dsidev;
        unsigned long r = 0;
 
        switch (dss_get_dispc_clk_source()) {
-       case DSS_CLK_SRC_FCK:
+       case OMAP_DSS_CLK_SRC_FCK:
                r = dss_clk_get_rate(DSS_CLK_FCK);
                break;
-       case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
-               r = dsi_get_pll_hsdiv_dispc_rate();
+       case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+               dsidev = dsi_get_dsidev_from_id(0);
+               r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
+               break;
+       case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
+               dsidev = dsi_get_dsidev_from_id(1);
+               r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
                break;
        default:
                BUG();
@@ -2371,6 +2476,7 @@ unsigned long dispc_fclk_rate(void)
 
 unsigned long dispc_lclk_rate(enum omap_channel channel)
 {
+       struct platform_device *dsidev;
        int lcd;
        unsigned long r;
        u32 l;
@@ -2380,11 +2486,16 @@ unsigned long dispc_lclk_rate(enum omap_channel channel)
        lcd = FLD_GET(l, 23, 16);
 
        switch (dss_get_lcd_clk_source(channel)) {
-       case DSS_CLK_SRC_FCK:
+       case OMAP_DSS_CLK_SRC_FCK:
                r = dss_clk_get_rate(DSS_CLK_FCK);
                break;
-       case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
-               r = dsi_get_pll_hsdiv_dispc_rate();
+       case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+               dsidev = dsi_get_dsidev_from_id(0);
+               r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
+               break;
+       case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
+               dsidev = dsi_get_dsidev_from_id(1);
+               r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
                break;
        default:
                BUG();
@@ -2412,8 +2523,8 @@ void dispc_dump_clocks(struct seq_file *s)
 {
        int lcd, pcd;
        u32 l;
-       enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
-       enum dss_clk_source lcd_clk_src;
+       enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
+       enum omap_dss_clk_source lcd_clk_src;
 
        enable_clocks(1);
 
@@ -2516,7 +2627,7 @@ void dispc_dump_irqs(struct seq_file *s)
 
 void dispc_dump_regs(struct seq_file *s)
 {
-#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r))
+#define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
 
        dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
@@ -2528,152 +2639,227 @@ void dispc_dump_regs(struct seq_file *s)
        DUMPREG(DISPC_CONTROL);
        DUMPREG(DISPC_CONFIG);
        DUMPREG(DISPC_CAPABLE);
-       DUMPREG(DISPC_DEFAULT_COLOR(0));
-       DUMPREG(DISPC_DEFAULT_COLOR(1));
-       DUMPREG(DISPC_TRANS_COLOR(0));
-       DUMPREG(DISPC_TRANS_COLOR(1));
+       DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT));
+       DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT));
        DUMPREG(DISPC_LINE_STATUS);
        DUMPREG(DISPC_LINE_NUMBER);
-       DUMPREG(DISPC_TIMING_H(0));
-       DUMPREG(DISPC_TIMING_V(0));
-       DUMPREG(DISPC_POL_FREQ(0));
-       DUMPREG(DISPC_DIVISORo(0));
+       DUMPREG(DISPC_TIMING_H(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD));
        DUMPREG(DISPC_GLOBAL_ALPHA);
-       DUMPREG(DISPC_SIZE_DIG);
-       DUMPREG(DISPC_SIZE_LCD(0));
+       DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
+       DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
                DUMPREG(DISPC_CONTROL2);
                DUMPREG(DISPC_CONFIG2);
-               DUMPREG(DISPC_DEFAULT_COLOR(2));
-               DUMPREG(DISPC_TRANS_COLOR(2));
-               DUMPREG(DISPC_TIMING_H(2));
-               DUMPREG(DISPC_TIMING_V(2));
-               DUMPREG(DISPC_POL_FREQ(2));
-               DUMPREG(DISPC_DIVISORo(2));
-               DUMPREG(DISPC_SIZE_LCD(2));
-       }
-
-       DUMPREG(DISPC_GFX_BA0);
-       DUMPREG(DISPC_GFX_BA1);
-       DUMPREG(DISPC_GFX_POSITION);
-       DUMPREG(DISPC_GFX_SIZE);
-       DUMPREG(DISPC_GFX_ATTRIBUTES);
-       DUMPREG(DISPC_GFX_FIFO_THRESHOLD);
-       DUMPREG(DISPC_GFX_FIFO_SIZE_STATUS);
-       DUMPREG(DISPC_GFX_ROW_INC);
-       DUMPREG(DISPC_GFX_PIXEL_INC);
-       DUMPREG(DISPC_GFX_WINDOW_SKIP);
-       DUMPREG(DISPC_GFX_TABLE_BA);
-
-       DUMPREG(DISPC_DATA_CYCLE1(0));
-       DUMPREG(DISPC_DATA_CYCLE2(0));
-       DUMPREG(DISPC_DATA_CYCLE3(0));
-
-       DUMPREG(DISPC_CPR_COEF_R(0));
-       DUMPREG(DISPC_CPR_COEF_G(0));
-       DUMPREG(DISPC_CPR_COEF_B(0));
+               DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_TIMING_H(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD2));
+       }
+
+       DUMPREG(DISPC_OVL_BA0(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_BA1(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_WINDOW_SKIP(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_TABLE_BA(OMAP_DSS_GFX));
+
+       DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
+
+       DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
-               DUMPREG(DISPC_DATA_CYCLE1(2));
-               DUMPREG(DISPC_DATA_CYCLE2(2));
-               DUMPREG(DISPC_DATA_CYCLE3(2));
-
-               DUMPREG(DISPC_CPR_COEF_R(2));
-               DUMPREG(DISPC_CPR_COEF_G(2));
-               DUMPREG(DISPC_CPR_COEF_B(2));
-       }
-
-       DUMPREG(DISPC_GFX_PRELOAD);
-
-       DUMPREG(DISPC_VID_BA0(0));
-       DUMPREG(DISPC_VID_BA1(0));
-       DUMPREG(DISPC_VID_POSITION(0));
-       DUMPREG(DISPC_VID_SIZE(0));
-       DUMPREG(DISPC_VID_ATTRIBUTES(0));
-       DUMPREG(DISPC_VID_FIFO_THRESHOLD(0));
-       DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(0));
-       DUMPREG(DISPC_VID_ROW_INC(0));
-       DUMPREG(DISPC_VID_PIXEL_INC(0));
-       DUMPREG(DISPC_VID_FIR(0));
-       DUMPREG(DISPC_VID_PICTURE_SIZE(0));
-       DUMPREG(DISPC_VID_ACCU0(0));
-       DUMPREG(DISPC_VID_ACCU1(0));
-
-       DUMPREG(DISPC_VID_BA0(1));
-       DUMPREG(DISPC_VID_BA1(1));
-       DUMPREG(DISPC_VID_POSITION(1));
-       DUMPREG(DISPC_VID_SIZE(1));
-       DUMPREG(DISPC_VID_ATTRIBUTES(1));
-       DUMPREG(DISPC_VID_FIFO_THRESHOLD(1));
-       DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(1));
-       DUMPREG(DISPC_VID_ROW_INC(1));
-       DUMPREG(DISPC_VID_PIXEL_INC(1));
-       DUMPREG(DISPC_VID_FIR(1));
-       DUMPREG(DISPC_VID_PICTURE_SIZE(1));
-       DUMPREG(DISPC_VID_ACCU0(1));
-       DUMPREG(DISPC_VID_ACCU1(1));
-
-       DUMPREG(DISPC_VID_FIR_COEF_H(0, 0));
-       DUMPREG(DISPC_VID_FIR_COEF_H(0, 1));
-       DUMPREG(DISPC_VID_FIR_COEF_H(0, 2));
-       DUMPREG(DISPC_VID_FIR_COEF_H(0, 3));
-       DUMPREG(DISPC_VID_FIR_COEF_H(0, 4));
-       DUMPREG(DISPC_VID_FIR_COEF_H(0, 5));
-       DUMPREG(DISPC_VID_FIR_COEF_H(0, 6));
-       DUMPREG(DISPC_VID_FIR_COEF_H(0, 7));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(0, 0));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(0, 1));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(0, 2));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(0, 3));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(0, 4));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(0, 5));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(0, 6));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(0, 7));
-       DUMPREG(DISPC_VID_CONV_COEF(0, 0));
-       DUMPREG(DISPC_VID_CONV_COEF(0, 1));
-       DUMPREG(DISPC_VID_CONV_COEF(0, 2));
-       DUMPREG(DISPC_VID_CONV_COEF(0, 3));
-       DUMPREG(DISPC_VID_CONV_COEF(0, 4));
-       DUMPREG(DISPC_VID_FIR_COEF_V(0, 0));
-       DUMPREG(DISPC_VID_FIR_COEF_V(0, 1));
-       DUMPREG(DISPC_VID_FIR_COEF_V(0, 2));
-       DUMPREG(DISPC_VID_FIR_COEF_V(0, 3));
-       DUMPREG(DISPC_VID_FIR_COEF_V(0, 4));
-       DUMPREG(DISPC_VID_FIR_COEF_V(0, 5));
-       DUMPREG(DISPC_VID_FIR_COEF_V(0, 6));
-       DUMPREG(DISPC_VID_FIR_COEF_V(0, 7));
-
-       DUMPREG(DISPC_VID_FIR_COEF_H(1, 0));
-       DUMPREG(DISPC_VID_FIR_COEF_H(1, 1));
-       DUMPREG(DISPC_VID_FIR_COEF_H(1, 2));
-       DUMPREG(DISPC_VID_FIR_COEF_H(1, 3));
-       DUMPREG(DISPC_VID_FIR_COEF_H(1, 4));
-       DUMPREG(DISPC_VID_FIR_COEF_H(1, 5));
-       DUMPREG(DISPC_VID_FIR_COEF_H(1, 6));
-       DUMPREG(DISPC_VID_FIR_COEF_H(1, 7));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(1, 0));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(1, 1));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(1, 2));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(1, 3));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(1, 4));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(1, 5));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(1, 6));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(1, 7));
-       DUMPREG(DISPC_VID_CONV_COEF(1, 0));
-       DUMPREG(DISPC_VID_CONV_COEF(1, 1));
-       DUMPREG(DISPC_VID_CONV_COEF(1, 2));
-       DUMPREG(DISPC_VID_CONV_COEF(1, 3));
-       DUMPREG(DISPC_VID_CONV_COEF(1, 4));
-       DUMPREG(DISPC_VID_FIR_COEF_V(1, 0));
-       DUMPREG(DISPC_VID_FIR_COEF_V(1, 1));
-       DUMPREG(DISPC_VID_FIR_COEF_V(1, 2));
-       DUMPREG(DISPC_VID_FIR_COEF_V(1, 3));
-       DUMPREG(DISPC_VID_FIR_COEF_V(1, 4));
-       DUMPREG(DISPC_VID_FIR_COEF_V(1, 5));
-       DUMPREG(DISPC_VID_FIR_COEF_V(1, 6));
-       DUMPREG(DISPC_VID_FIR_COEF_V(1, 7));
-
-       DUMPREG(DISPC_VID_PRELOAD(0));
-       DUMPREG(DISPC_VID_PRELOAD(1));
+               DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
+
+               DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
+       }
+
+       DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX));
+
+       DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_FIR(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_ACCU0(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_ACCU1(OMAP_DSS_VIDEO1));
+
+       DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_FIR(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_ACCU0(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_ACCU1(OMAP_DSS_VIDEO2));
+
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 0));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 1));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 2));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 3));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 4));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 5));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 6));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 7));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 0));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 1));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 2));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 3));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 4));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 5));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 6));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 7));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 0));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 1));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 3));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 4));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7));
+
+       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+               DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO1));
+               DUMPREG(DISPC_OVL_BA1_UV(OMAP_DSS_VIDEO1));
+               DUMPREG(DISPC_OVL_FIR2(OMAP_DSS_VIDEO1));
+               DUMPREG(DISPC_OVL_ACCU2_0(OMAP_DSS_VIDEO1));
+               DUMPREG(DISPC_OVL_ACCU2_1(OMAP_DSS_VIDEO1));
+
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 0));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 1));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 2));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 3));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 4));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 5));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 6));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 7));
+
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 0));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 1));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 2));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 3));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 4));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 5));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 6));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 7));
+
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 0));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 1));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 2));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 3));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 4));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 5));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 6));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 7));
+       }
+       if (dss_has_feature(FEAT_ATTR2))
+               DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
+
+
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 0));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 1));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 2));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 3));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 4));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 5));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 6));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 7));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 0));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 1));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 2));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 3));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 4));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 5));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 6));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 7));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 0));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 1));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 3));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 4));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7));
+
+       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+               DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO2));
+               DUMPREG(DISPC_OVL_BA1_UV(OMAP_DSS_VIDEO2));
+               DUMPREG(DISPC_OVL_FIR2(OMAP_DSS_VIDEO2));
+               DUMPREG(DISPC_OVL_ACCU2_0(OMAP_DSS_VIDEO2));
+               DUMPREG(DISPC_OVL_ACCU2_1(OMAP_DSS_VIDEO2));
+
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 0));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 1));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 2));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 3));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 4));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 5));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 6));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 7));
+
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 0));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 1));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 2));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 3));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 4));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 5));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 6));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 7));
+
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 0));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 1));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 2));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 3));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 4));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 5));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 6));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 7));
+       }
+       if (dss_has_feature(FEAT_ATTR2))
+               DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
+
+       DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2));
 
        dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 #undef DUMPREG
@@ -3388,11 +3574,12 @@ int dispc_setup_plane(enum omap_plane plane,
                       bool ilace,
                       enum omap_dss_rotation_type rotation_type,
                       u8 rotation, bool mirror, u8 global_alpha,
-                      u8 pre_mult_alpha, enum omap_channel channel)
+                      u8 pre_mult_alpha, enum omap_channel channel,
+                      u32 puv_addr)
 {
        int r = 0;
 
-       DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
+       DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d, %d, %dx%d -> "
               "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n",
               plane, paddr, screen_width, pos_x, pos_y,
               width, height,
@@ -3411,7 +3598,8 @@ int dispc_setup_plane(enum omap_plane plane,
                           rotation_type,
                           rotation, mirror,
                           global_alpha,
-                          pre_mult_alpha, channel);
+                          pre_mult_alpha,
+                          channel, puv_addr);
 
        enable_clocks(0);
 
diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h
new file mode 100644 (file)
index 0000000..6c9ee0a
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * linux/drivers/video/omap2/dss/dispc.h
+ *
+ * Copyright (C) 2011 Texas Instruments
+ * Author: Archit Taneja <archit@ti.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __OMAP2_DISPC_REG_H
+#define __OMAP2_DISPC_REG_H
+
+/* DISPC common registers */
+#define DISPC_REVISION                 0x0000
+#define DISPC_SYSCONFIG                        0x0010
+#define DISPC_SYSSTATUS                        0x0014
+#define DISPC_IRQSTATUS                        0x0018
+#define DISPC_IRQENABLE                        0x001C
+#define DISPC_CONTROL                  0x0040
+#define DISPC_CONFIG                   0x0044
+#define DISPC_CAPABLE                  0x0048
+#define DISPC_LINE_STATUS              0x005C
+#define DISPC_LINE_NUMBER              0x0060
+#define DISPC_GLOBAL_ALPHA             0x0074
+#define DISPC_CONTROL2                 0x0238
+#define DISPC_CONFIG2                  0x0620
+#define DISPC_DIVISOR                  0x0804
+
+/* DISPC overlay registers */
+#define DISPC_OVL_BA0(n)               (DISPC_OVL_BASE(n) + \
+                                       DISPC_BA0_OFFSET(n))
+#define DISPC_OVL_BA1(n)               (DISPC_OVL_BASE(n) + \
+                                       DISPC_BA1_OFFSET(n))
+#define DISPC_OVL_BA0_UV(n)            (DISPC_OVL_BASE(n) + \
+                                       DISPC_BA0_UV_OFFSET(n))
+#define DISPC_OVL_BA1_UV(n)            (DISPC_OVL_BASE(n) + \
+                                       DISPC_BA1_UV_OFFSET(n))
+#define DISPC_OVL_POSITION(n)          (DISPC_OVL_BASE(n) + \
+                                       DISPC_POS_OFFSET(n))
+#define DISPC_OVL_SIZE(n)              (DISPC_OVL_BASE(n) + \
+                                       DISPC_SIZE_OFFSET(n))
+#define DISPC_OVL_ATTRIBUTES(n)                (DISPC_OVL_BASE(n) + \
+                                       DISPC_ATTR_OFFSET(n))
+#define DISPC_OVL_ATTRIBUTES2(n)       (DISPC_OVL_BASE(n) + \
+                                       DISPC_ATTR2_OFFSET(n))
+#define DISPC_OVL_FIFO_THRESHOLD(n)    (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIFO_THRESH_OFFSET(n))
+#define DISPC_OVL_FIFO_SIZE_STATUS(n)  (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIFO_SIZE_STATUS_OFFSET(n))
+#define DISPC_OVL_ROW_INC(n)           (DISPC_OVL_BASE(n) + \
+                                       DISPC_ROW_INC_OFFSET(n))
+#define DISPC_OVL_PIXEL_INC(n)         (DISPC_OVL_BASE(n) + \
+                                       DISPC_PIX_INC_OFFSET(n))
+#define DISPC_OVL_WINDOW_SKIP(n)       (DISPC_OVL_BASE(n) + \
+                                       DISPC_WINDOW_SKIP_OFFSET(n))
+#define DISPC_OVL_TABLE_BA(n)          (DISPC_OVL_BASE(n) + \
+                                       DISPC_TABLE_BA_OFFSET(n))
+#define DISPC_OVL_FIR(n)               (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIR_OFFSET(n))
+#define DISPC_OVL_FIR2(n)              (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIR2_OFFSET(n))
+#define DISPC_OVL_PICTURE_SIZE(n)      (DISPC_OVL_BASE(n) + \
+                                       DISPC_PIC_SIZE_OFFSET(n))
+#define DISPC_OVL_ACCU0(n)             (DISPC_OVL_BASE(n) + \
+                                       DISPC_ACCU0_OFFSET(n))
+#define DISPC_OVL_ACCU1(n)             (DISPC_OVL_BASE(n) + \
+                                       DISPC_ACCU1_OFFSET(n))
+#define DISPC_OVL_ACCU2_0(n)           (DISPC_OVL_BASE(n) + \
+                                       DISPC_ACCU2_0_OFFSET(n))
+#define DISPC_OVL_ACCU2_1(n)           (DISPC_OVL_BASE(n) + \
+                                       DISPC_ACCU2_1_OFFSET(n))
+#define DISPC_OVL_FIR_COEF_H(n, i)     (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIR_COEF_H_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_HV(n, i)    (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIR_COEF_HV_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_H2(n, i)    (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIR_COEF_H2_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_HV2(n, i)   (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIR_COEF_HV2_OFFSET(n, i))
+#define DISPC_OVL_CONV_COEF(n, i)      (DISPC_OVL_BASE(n) + \
+                                       DISPC_CONV_COEF_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_V(n, i)     (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIR_COEF_V_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_V2(n, i)    (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIR_COEF_V2_OFFSET(n, i))
+#define DISPC_OVL_PRELOAD(n)           (DISPC_OVL_BASE(n) + \
+                                       DISPC_PRELOAD_OFFSET(n))
+
+/* DISPC manager/channel specific registers */
+static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x004C;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               return 0x0050;
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03AC;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_TRANS_COLOR(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x0054;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               return 0x0058;
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03B0;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_TIMING_H(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x0064;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x0400;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_TIMING_V(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x0068;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x0404;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_POL_FREQ(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x006C;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x0408;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_DIVISORo(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x0070;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x040C;
+       default:
+               BUG();
+       }
+}
+
+/* Named as DISPC_SIZE_LCD, DISPC_SIZE_DIGIT and DISPC_SIZE_LCD2 in TRM */
+static inline u16 DISPC_SIZE_MGR(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x007C;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               return 0x0078;
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03CC;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_DATA_CYCLE1(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x01D4;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03C0;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_DATA_CYCLE2(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x01D8;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03C4;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_DATA_CYCLE3(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x01DC;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03C8;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_CPR_COEF_R(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x0220;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03BC;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_CPR_COEF_G(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x0224;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03B8;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_CPR_COEF_B(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x0228;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03B4;
+       default:
+               BUG();
+       }
+}
+
+/* DISPC overlay register base addresses */
+static inline u16 DISPC_OVL_BASE(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x0080;
+       case OMAP_DSS_VIDEO1:
+               return 0x00BC;
+       case OMAP_DSS_VIDEO2:
+               return 0x014C;
+       default:
+               BUG();
+       }
+}
+
+/* DISPC overlay register offsets */
+static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0000;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0004;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x0544;
+       case OMAP_DSS_VIDEO2:
+               return 0x04BC;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x0548;
+       case OMAP_DSS_VIDEO2:
+               return 0x04C0;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_POS_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0008;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x000C;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x0020;
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0010;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x0568;
+       case OMAP_DSS_VIDEO2:
+               return 0x04DC;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x0024;
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0014;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x0028;
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0018;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x002C;
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x001C;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x0030;
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0020;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_WINDOW_SKIP_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x0034;
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               BUG();
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_TABLE_BA_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x0038;
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               BUG();
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0024;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x0580;
+       case OMAP_DSS_VIDEO2:
+               return 0x055C;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0028;
+       default:
+               BUG();
+       }
+}
+
+
+static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x002C;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x0584;
+       case OMAP_DSS_VIDEO2:
+               return 0x0560;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0030;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x0588;
+       case OMAP_DSS_VIDEO2:
+               return 0x0564;
+       default:
+               BUG();
+       }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0034 + i * 0x8;
+       default:
+               BUG();
+       }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x058C + i * 0x8;
+       case OMAP_DSS_VIDEO2:
+               return 0x0568 + i * 0x8;
+       default:
+               BUG();
+       }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0038 + i * 0x8;
+       default:
+               BUG();
+       }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x0590 + i * 8;
+       case OMAP_DSS_VIDEO2:
+               return 0x056C + i * 0x8;
+       default:
+               BUG();
+       }
+}
+
+/* coef index i = {0, 1, 2, 3, 4,} */
+static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0074 + i * 0x4;
+       default:
+               BUG();
+       }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x0124 + i * 0x4;
+       case OMAP_DSS_VIDEO2:
+               return 0x00B4 + i * 0x4;
+       default:
+               BUG();
+       }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x05CC + i * 0x4;
+       case OMAP_DSS_VIDEO2:
+               return 0x05A8 + i * 0x4;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_PRELOAD_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x01AC;
+       case OMAP_DSS_VIDEO1:
+               return 0x0174;
+       case OMAP_DSS_VIDEO2:
+               return 0x00E8;
+       default:
+               BUG();
+       }
+}
+#endif
index a85a6f38b40c126661e3cf9e61febef169d53fcc..c2dfc8c50057baad8be69900ba27f9a11434108b 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/jiffies.h>
 #include <linux/platform_device.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include "dss.h"
 
 static ssize_t display_enabled_show(struct device *dev,
@@ -44,9 +44,13 @@ static ssize_t display_enabled_store(struct device *dev,
                const char *buf, size_t size)
 {
        struct omap_dss_device *dssdev = to_dss_device(dev);
-       bool enabled, r;
+       int r, enabled;
 
-       enabled = simple_strtoul(buf, NULL, 10);
+       r = kstrtoint(buf, 0, &enabled);
+       if (r)
+               return r;
+
+       enabled = !!enabled;
 
        if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
                if (enabled) {
@@ -82,7 +86,9 @@ static ssize_t display_upd_mode_store(struct device *dev,
        if (!dssdev->driver->set_update_mode)
                return -EINVAL;
 
-       val = simple_strtoul(buf, NULL, 10);
+       r = kstrtoint(buf, 0, &val);
+       if (r)
+               return r;
 
        switch (val) {
        case OMAP_DSS_UPDATE_DISABLED:
@@ -114,13 +120,16 @@ static ssize_t display_tear_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
        struct omap_dss_device *dssdev = to_dss_device(dev);
-       unsigned long te;
-       int r;
+       int te, r;
 
        if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
                return -ENOENT;
 
-       te = simple_strtoul(buf, NULL, 0);
+       r = kstrtoint(buf, 0, &te);
+       if (r)
+               return r;
+
+       te = !!te;
 
        r = dssdev->driver->enable_te(dssdev, te);
        if (r)
@@ -196,13 +205,14 @@ static ssize_t display_rotate_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
        struct omap_dss_device *dssdev = to_dss_device(dev);
-       unsigned long rot;
-       int r;
+       int rot, r;
 
        if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
                return -ENOENT;
 
-       rot = simple_strtoul(buf, NULL, 0);
+       r = kstrtoint(buf, 0, &rot);
+       if (r)
+               return r;
 
        r = dssdev->driver->set_rotate(dssdev, rot);
        if (r)
@@ -226,13 +236,16 @@ static ssize_t display_mirror_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
        struct omap_dss_device *dssdev = to_dss_device(dev);
-       unsigned long mirror;
-       int r;
+       int mirror, r;
 
        if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
                return -ENOENT;
 
-       mirror = simple_strtoul(buf, NULL, 0);
+       r = kstrtoint(buf, 0, &mirror);
+       if (r)
+               return r;
+
+       mirror = !!mirror;
 
        r = dssdev->driver->set_mirror(dssdev, mirror);
        if (r)
@@ -259,14 +272,15 @@ static ssize_t display_wss_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
        struct omap_dss_device *dssdev = to_dss_device(dev);
-       unsigned long wss;
+       u32 wss;
        int r;
 
        if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
                return -ENOENT;
 
-       if (strict_strtoul(buf, 0, &wss))
-               return -EINVAL;
+       r = kstrtou32(buf, 0, &wss);
+       if (r)
+               return r;
 
        if (wss > 0xfffff)
                return -EINVAL;
index 2d3ca4ca4a05b14583b89f5cf9e622edef4a72cd..ff6bd30132df04da253f639ea9c8fe5fe221c87a 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 
 #include "dss.h"
 
 static struct {
        struct regulator *vdds_dsi_reg;
+       struct platform_device *dsidev;
 } dpi;
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk)
+{
+       int dsi_module;
+
+       dsi_module = clk == OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ? 0 : 1;
+
+       return dsi_get_dsidev_from_id(dsi_module);
+}
+
+static bool dpi_use_dsi_pll(struct omap_dss_device *dssdev)
+{
+       if (dssdev->clocks.dispc.dispc_fclk_src ==
+                       OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ||
+                       dssdev->clocks.dispc.dispc_fclk_src ==
+                       OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC ||
+                       dssdev->clocks.dispc.channel.lcd_clk_src ==
+                       OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ||
+                       dssdev->clocks.dispc.channel.lcd_clk_src ==
+                       OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC)
+               return true;
+       else
+               return false;
+}
+
 static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft,
                unsigned long pck_req, unsigned long *fck, int *lck_div,
                int *pck_div)
@@ -48,16 +72,16 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft,
        struct dispc_clock_info dispc_cinfo;
        int r;
 
-       r = dsi_pll_calc_clock_div_pck(is_tft, pck_req, &dsi_cinfo,
-                       &dispc_cinfo);
+       r = dsi_pll_calc_clock_div_pck(dpi.dsidev, is_tft, pck_req,
+                       &dsi_cinfo, &dispc_cinfo);
        if (r)
                return r;
 
-       r = dsi_pll_set_clock_div(&dsi_cinfo);
+       r = dsi_pll_set_clock_div(dpi.dsidev, &dsi_cinfo);
        if (r)
                return r;
 
-       dss_select_dispc_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC);
+       dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
 
        r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
        if (r)
@@ -69,7 +93,7 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft,
 
        return 0;
 }
-#else
+
 static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, bool is_tft,
                unsigned long pck_req, unsigned long *fck, int *lck_div,
                int *pck_div)
@@ -96,13 +120,12 @@ static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, bool is_tft,
 
        return 0;
 }
-#endif
 
 static int dpi_set_mode(struct omap_dss_device *dssdev)
 {
        struct omap_video_timings *t = &dssdev->panel.timings;
-       int lck_div, pck_div;
-       unsigned long fck;
+       int lck_div = 0, pck_div = 0;
+       unsigned long fck = 0;
        unsigned long pck;
        bool is_tft;
        int r = 0;
@@ -114,13 +137,12 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
 
        is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-       r = dpi_set_dsi_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck,
-                       &lck_div, &pck_div);
-#else
-       r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck,
-                       &lck_div, &pck_div);
-#endif
+       if (dpi_use_dsi_pll(dssdev))
+               r = dpi_set_dsi_clk(dssdev, is_tft, t->pixel_clock * 1000,
+                               &fck, &lck_div, &pck_div);
+       else
+               r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000,
+                               &fck, &lck_div, &pck_div);
        if (r)
                goto err0;
 
@@ -179,12 +201,13 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
        if (r)
                goto err2;
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-       dss_clk_enable(DSS_CLK_SYSCK);
-       r = dsi_pll_init(dssdev, 0, 1);
-       if (r)
-               goto err3;
-#endif
+       if (dpi_use_dsi_pll(dssdev)) {
+               dss_clk_enable(DSS_CLK_SYSCK);
+               r = dsi_pll_init(dpi.dsidev, 0, 1);
+               if (r)
+                       goto err3;
+       }
+
        r = dpi_set_mode(dssdev);
        if (r)
                goto err4;
@@ -196,11 +219,11 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
        return 0;
 
 err4:
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-       dsi_pll_uninit();
+       if (dpi_use_dsi_pll(dssdev))
+               dsi_pll_uninit(dpi.dsidev, true);
 err3:
-       dss_clk_disable(DSS_CLK_SYSCK);
-#endif
+       if (dpi_use_dsi_pll(dssdev))
+               dss_clk_disable(DSS_CLK_SYSCK);
 err2:
        dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
        if (cpu_is_omap34xx())
@@ -216,11 +239,11 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
 {
        dssdev->manager->disable(dssdev->manager);
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-       dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
-       dsi_pll_uninit();
-       dss_clk_disable(DSS_CLK_SYSCK);
-#endif
+       if (dpi_use_dsi_pll(dssdev)) {
+               dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
+               dsi_pll_uninit(dpi.dsidev, true);
+               dss_clk_disable(DSS_CLK_SYSCK);
+       }
 
        dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
@@ -251,6 +274,7 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
        int lck_div, pck_div;
        unsigned long fck;
        unsigned long pck;
+       struct dispc_clock_info dispc_cinfo;
 
        if (!dispc_lcd_timings_ok(timings))
                return -EINVAL;
@@ -260,11 +284,9 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
 
        is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-       {
+       if (dpi_use_dsi_pll(dssdev)) {
                struct dsi_clock_info dsi_cinfo;
-               struct dispc_clock_info dispc_cinfo;
-               r = dsi_pll_calc_clock_div_pck(is_tft,
+               r = dsi_pll_calc_clock_div_pck(dpi.dsidev, is_tft,
                                timings->pixel_clock * 1000,
                                &dsi_cinfo, &dispc_cinfo);
 
@@ -272,13 +294,8 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
                        return r;
 
                fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
-               lck_div = dispc_cinfo.lck_div;
-               pck_div = dispc_cinfo.pck_div;
-       }
-#else
-       {
+       } else {
                struct dss_clock_info dss_cinfo;
-               struct dispc_clock_info dispc_cinfo;
                r = dss_calc_clock_div(is_tft, timings->pixel_clock * 1000,
                                &dss_cinfo, &dispc_cinfo);
 
@@ -286,10 +303,10 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
                        return r;
 
                fck = dss_cinfo.fck;
-               lck_div = dispc_cinfo.lck_div;
-               pck_div = dispc_cinfo.pck_div;
        }
-#endif
+
+       lck_div = dispc_cinfo.lck_div;
+       pck_div = dispc_cinfo.pck_div;
 
        pck = fck / lck_div / pck_div / 1000;
 
@@ -316,6 +333,12 @@ int dpi_init_display(struct omap_dss_device *dssdev)
                dpi.vdds_dsi_reg = vdds_dsi;
        }
 
+       if (dpi_use_dsi_pll(dssdev)) {
+               enum omap_dss_clk_source dispc_fclk_src =
+                       dssdev->clocks.dispc.dispc_fclk_src;
+               dpi.dsidev = dpi_get_dsidev(dispc_fclk_src);
+       }
+
        return 0;
 }
 
index 0a7f1a47f8e3b5fb0b30c369f971dd77146490b4..345757cfcbee187cf90f7685b3bc1830ef2b783f 100644 (file)
 #include <linux/regulator/consumer.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/clock.h>
 
 #include "dss.h"
@@ -56,6 +59,7 @@ struct dsi_reg { u16 idx; };
 #define DSI_IRQSTATUS                  DSI_REG(0x0018)
 #define DSI_IRQENABLE                  DSI_REG(0x001C)
 #define DSI_CTRL                       DSI_REG(0x0040)
+#define DSI_GNQ                                DSI_REG(0x0044)
 #define DSI_COMPLEXIO_CFG1             DSI_REG(0x0048)
 #define DSI_COMPLEXIO_IRQ_STATUS       DSI_REG(0x004C)
 #define DSI_COMPLEXIO_IRQ_ENABLE       DSI_REG(0x0050)
@@ -90,6 +94,7 @@ struct dsi_reg { u16 idx; };
 #define DSI_DSIPHY_CFG1                        DSI_REG(0x200 + 0x0004)
 #define DSI_DSIPHY_CFG2                        DSI_REG(0x200 + 0x0008)
 #define DSI_DSIPHY_CFG5                        DSI_REG(0x200 + 0x0014)
+#define DSI_DSIPHY_CFG10               DSI_REG(0x200 + 0x0028)
 
 /* DSI_PLL_CTRL_SCP */
 
@@ -99,11 +104,11 @@ struct dsi_reg { u16 idx; };
 #define DSI_PLL_CONFIGURATION1         DSI_REG(0x300 + 0x000C)
 #define DSI_PLL_CONFIGURATION2         DSI_REG(0x300 + 0x0010)
 
-#define REG_GET(idx, start, end) \
-       FLD_GET(dsi_read_reg(idx), start, end)
+#define REG_GET(dsidev, idx, start, end) \
+       FLD_GET(dsi_read_reg(dsidev, idx), start, end)
 
-#define REG_FLD_MOD(idx, val, start, end) \
-       dsi_write_reg(idx, FLD_MOD(dsi_read_reg(idx), val, start, end))
+#define REG_FLD_MOD(dsidev, idx, val, start, end) \
+       dsi_write_reg(dsidev, idx, FLD_MOD(dsi_read_reg(dsidev, idx), val, start, end))
 
 /* Global interrupts */
 #define DSI_IRQ_VC0            (1 << 0)
@@ -147,31 +152,50 @@ struct dsi_reg { u16 idx; };
 #define DSI_CIO_IRQ_ERRSYNCESC1                (1 << 0)
 #define DSI_CIO_IRQ_ERRSYNCESC2                (1 << 1)
 #define DSI_CIO_IRQ_ERRSYNCESC3                (1 << 2)
+#define DSI_CIO_IRQ_ERRSYNCESC4                (1 << 3)
+#define DSI_CIO_IRQ_ERRSYNCESC5                (1 << 4)
 #define DSI_CIO_IRQ_ERRESC1            (1 << 5)
 #define DSI_CIO_IRQ_ERRESC2            (1 << 6)
 #define DSI_CIO_IRQ_ERRESC3            (1 << 7)
+#define DSI_CIO_IRQ_ERRESC4            (1 << 8)
+#define DSI_CIO_IRQ_ERRESC5            (1 << 9)
 #define DSI_CIO_IRQ_ERRCONTROL1                (1 << 10)
 #define DSI_CIO_IRQ_ERRCONTROL2                (1 << 11)
 #define DSI_CIO_IRQ_ERRCONTROL3                (1 << 12)
+#define DSI_CIO_IRQ_ERRCONTROL4                (1 << 13)
+#define DSI_CIO_IRQ_ERRCONTROL5                (1 << 14)
 #define DSI_CIO_IRQ_STATEULPS1         (1 << 15)
 #define DSI_CIO_IRQ_STATEULPS2         (1 << 16)
 #define DSI_CIO_IRQ_STATEULPS3         (1 << 17)
+#define DSI_CIO_IRQ_STATEULPS4         (1 << 18)
+#define DSI_CIO_IRQ_STATEULPS5         (1 << 19)
 #define DSI_CIO_IRQ_ERRCONTENTIONLP0_1 (1 << 20)
 #define DSI_CIO_IRQ_ERRCONTENTIONLP1_1 (1 << 21)
 #define DSI_CIO_IRQ_ERRCONTENTIONLP0_2 (1 << 22)
 #define DSI_CIO_IRQ_ERRCONTENTIONLP1_2 (1 << 23)
 #define DSI_CIO_IRQ_ERRCONTENTIONLP0_3 (1 << 24)
 #define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP0_4 (1 << 26)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP1_4 (1 << 27)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP0_5 (1 << 28)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP1_5 (1 << 29)
 #define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30)
 #define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31)
 #define DSI_CIO_IRQ_ERROR_MASK \
        (DSI_CIO_IRQ_ERRSYNCESC1 | DSI_CIO_IRQ_ERRSYNCESC2 | \
-        DSI_CIO_IRQ_ERRSYNCESC3 | DSI_CIO_IRQ_ERRESC1 | DSI_CIO_IRQ_ERRESC2 | \
-        DSI_CIO_IRQ_ERRESC3 | DSI_CIO_IRQ_ERRCONTROL1 | \
-        DSI_CIO_IRQ_ERRCONTROL2 | DSI_CIO_IRQ_ERRCONTROL3 | \
+        DSI_CIO_IRQ_ERRSYNCESC3 | DSI_CIO_IRQ_ERRSYNCESC4 | \
+        DSI_CIO_IRQ_ERRSYNCESC5 | \
+        DSI_CIO_IRQ_ERRESC1 | DSI_CIO_IRQ_ERRESC2 | \
+        DSI_CIO_IRQ_ERRESC3 | DSI_CIO_IRQ_ERRESC4 | \
+        DSI_CIO_IRQ_ERRESC5 | \
+        DSI_CIO_IRQ_ERRCONTROL1 | DSI_CIO_IRQ_ERRCONTROL2 | \
+        DSI_CIO_IRQ_ERRCONTROL3 | DSI_CIO_IRQ_ERRCONTROL4 | \
+        DSI_CIO_IRQ_ERRCONTROL5 | \
         DSI_CIO_IRQ_ERRCONTENTIONLP0_1 | DSI_CIO_IRQ_ERRCONTENTIONLP1_1 | \
         DSI_CIO_IRQ_ERRCONTENTIONLP0_2 | DSI_CIO_IRQ_ERRCONTENTIONLP1_2 | \
-        DSI_CIO_IRQ_ERRCONTENTIONLP0_3 | DSI_CIO_IRQ_ERRCONTENTIONLP1_3)
+        DSI_CIO_IRQ_ERRCONTENTIONLP0_3 | DSI_CIO_IRQ_ERRCONTENTIONLP1_3 | \
+        DSI_CIO_IRQ_ERRCONTENTIONLP0_4 | DSI_CIO_IRQ_ERRCONTENTIONLP1_4 | \
+        DSI_CIO_IRQ_ERRCONTENTIONLP0_5 | DSI_CIO_IRQ_ERRCONTENTIONLP1_5)
 
 #define DSI_DT_DCS_SHORT_WRITE_0       0x05
 #define DSI_DT_DCS_SHORT_WRITE_1       0x15
@@ -208,6 +232,19 @@ enum dsi_vc_mode {
        DSI_VC_MODE_VP,
 };
 
+enum dsi_lane {
+       DSI_CLK_P       = 1 << 0,
+       DSI_CLK_N       = 1 << 1,
+       DSI_DATA1_P     = 1 << 2,
+       DSI_DATA1_N     = 1 << 3,
+       DSI_DATA2_P     = 1 << 4,
+       DSI_DATA2_N     = 1 << 5,
+       DSI_DATA3_P     = 1 << 6,
+       DSI_DATA3_N     = 1 << 7,
+       DSI_DATA4_P     = 1 << 8,
+       DSI_DATA4_N     = 1 << 9,
+};
+
 struct dsi_update_region {
        u16 x, y, w, h;
        struct omap_dss_device *device;
@@ -227,14 +264,16 @@ struct dsi_isr_tables {
        struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS];
 };
 
-static struct
-{
+struct dsi_data {
        struct platform_device *pdev;
        void __iomem    *base;
        int irq;
 
+       void (*dsi_mux_pads)(bool enable);
+
        struct dsi_clock_info current_cinfo;
 
+       bool vdds_dsi_enabled;
        struct regulator *vdds_dsi_reg;
 
        struct {
@@ -258,8 +297,7 @@ static struct
        struct dsi_update_region update_region;
 
        bool te_enabled;
-
-       struct workqueue_struct *workqueue;
+       bool ulps_enabled;
 
        void (*framedone_callback)(int, void *);
        void *framedone_data;
@@ -292,21 +330,63 @@ static struct
        unsigned long  regm_dispc_max, regm_dsi_max;
        unsigned long  fint_min, fint_max;
        unsigned long lpdiv_max;
-} dsi;
+
+       int num_data_lanes;
+
+       unsigned scp_clk_refcount;
+};
+
+struct dsi_packet_sent_handler_data {
+       struct platform_device *dsidev;
+       struct completion *completion;
+};
+
+static struct platform_device *dsi_pdev_map[MAX_NUM_DSI];
 
 #ifdef DEBUG
 static unsigned int dsi_perf;
 module_param_named(dsi_perf, dsi_perf, bool, 0644);
 #endif
 
-static inline void dsi_write_reg(const struct dsi_reg idx, u32 val)
+static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dsidev)
 {
-       __raw_writel(val, dsi.base + idx.idx);
+       return dev_get_drvdata(&dsidev->dev);
 }
 
-static inline u32 dsi_read_reg(const struct dsi_reg idx)
+static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev)
 {
-       return __raw_readl(dsi.base + idx.idx);
+       return dsi_pdev_map[dssdev->phy.dsi.module];
+}
+
+struct platform_device *dsi_get_dsidev_from_id(int module)
+{
+       return dsi_pdev_map[module];
+}
+
+static int dsi_get_dsidev_id(struct platform_device *dsidev)
+{
+       /* TEMP: Pass 0 as the dsi module index till the time the dsi platform
+        * device names aren't changed to the form "omapdss_dsi.0",
+        * "omapdss_dsi.1" and so on */
+       BUG_ON(dsidev->id != -1);
+
+       return 0;
+}
+
+static inline void dsi_write_reg(struct platform_device *dsidev,
+               const struct dsi_reg idx, u32 val)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       __raw_writel(val, dsi->base + idx.idx);
+}
+
+static inline u32 dsi_read_reg(struct platform_device *dsidev,
+               const struct dsi_reg idx)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       return __raw_readl(dsi->base + idx.idx);
 }
 
 
@@ -318,21 +398,29 @@ void dsi_restore_context(void)
 {
 }
 
-void dsi_bus_lock(void)
+void dsi_bus_lock(struct omap_dss_device *dssdev)
 {
-       down(&dsi.bus_lock);
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       down(&dsi->bus_lock);
 }
 EXPORT_SYMBOL(dsi_bus_lock);
 
-void dsi_bus_unlock(void)
+void dsi_bus_unlock(struct omap_dss_device *dssdev)
 {
-       up(&dsi.bus_lock);
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       up(&dsi->bus_lock);
 }
 EXPORT_SYMBOL(dsi_bus_unlock);
 
-static bool dsi_bus_is_locked(void)
+static bool dsi_bus_is_locked(struct platform_device *dsidev)
 {
-       return dsi.bus_lock.count == 0;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       return dsi->bus_lock.count == 0;
 }
 
 static void dsi_completion_handler(void *data, u32 mask)
@@ -340,12 +428,12 @@ static void dsi_completion_handler(void *data, u32 mask)
        complete((struct completion *)data);
 }
 
-static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
-               int value)
+static inline int wait_for_bit_change(struct platform_device *dsidev,
+               const struct dsi_reg idx, int bitnum, int value)
 {
        int t = 100000;
 
-       while (REG_GET(idx, bitnum, bitnum) != value) {
+       while (REG_GET(dsidev, idx, bitnum, bitnum) != value) {
                if (--t == 0)
                        return !value;
        }
@@ -354,18 +442,21 @@ static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
 }
 
 #ifdef DEBUG
-static void dsi_perf_mark_setup(void)
+static void dsi_perf_mark_setup(struct platform_device *dsidev)
 {
-       dsi.perf_setup_time = ktime_get();
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       dsi->perf_setup_time = ktime_get();
 }
 
-static void dsi_perf_mark_start(void)
+static void dsi_perf_mark_start(struct platform_device *dsidev)
 {
-       dsi.perf_start_time = ktime_get();
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       dsi->perf_start_time = ktime_get();
 }
 
-static void dsi_perf_show(const char *name)
+static void dsi_perf_show(struct platform_device *dsidev, const char *name)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        ktime_t t, setup_time, trans_time;
        u32 total_bytes;
        u32 setup_us, trans_us, total_us;
@@ -375,21 +466,21 @@ static void dsi_perf_show(const char *name)
 
        t = ktime_get();
 
-       setup_time = ktime_sub(dsi.perf_start_time, dsi.perf_setup_time);
+       setup_time = ktime_sub(dsi->perf_start_time, dsi->perf_setup_time);
        setup_us = (u32)ktime_to_us(setup_time);
        if (setup_us == 0)
                setup_us = 1;
 
-       trans_time = ktime_sub(t, dsi.perf_start_time);
+       trans_time = ktime_sub(t, dsi->perf_start_time);
        trans_us = (u32)ktime_to_us(trans_time);
        if (trans_us == 0)
                trans_us = 1;
 
        total_us = setup_us + trans_us;
 
-       total_bytes = dsi.update_region.w *
-               dsi.update_region.h *
-               dsi.update_region.device->ctrl.pixel_size / 8;
+       total_bytes = dsi->update_region.w *
+               dsi->update_region.h *
+               dsi->update_region.device->ctrl.pixel_size / 8;
 
        printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
                        "%u bytes, %u kbytes/sec\n",
@@ -402,9 +493,9 @@ static void dsi_perf_show(const char *name)
                        total_bytes * 1000 / total_us);
 }
 #else
-#define dsi_perf_mark_setup()
-#define dsi_perf_mark_start()
-#define dsi_perf_show(x)
+#define dsi_perf_mark_setup(x)
+#define dsi_perf_mark_start(x)
+#define dsi_perf_show(x, y)
 #endif
 
 static void print_irq_status(u32 status)
@@ -510,38 +601,42 @@ static void print_irq_status_cio(u32 status)
 }
 
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-static void dsi_collect_irq_stats(u32 irqstatus, u32 *vcstatus, u32 ciostatus)
+static void dsi_collect_irq_stats(struct platform_device *dsidev, u32 irqstatus,
+               u32 *vcstatus, u32 ciostatus)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int i;
 
-       spin_lock(&dsi.irq_stats_lock);
+       spin_lock(&dsi->irq_stats_lock);
 
-       dsi.irq_stats.irq_count++;
-       dss_collect_irq_stats(irqstatus, dsi.irq_stats.dsi_irqs);
+       dsi->irq_stats.irq_count++;
+       dss_collect_irq_stats(irqstatus, dsi->irq_stats.dsi_irqs);
 
        for (i = 0; i < 4; ++i)
-               dss_collect_irq_stats(vcstatus[i], dsi.irq_stats.vc_irqs[i]);
+               dss_collect_irq_stats(vcstatus[i], dsi->irq_stats.vc_irqs[i]);
 
-       dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs);
+       dss_collect_irq_stats(ciostatus, dsi->irq_stats.cio_irqs);
 
-       spin_unlock(&dsi.irq_stats_lock);
+       spin_unlock(&dsi->irq_stats_lock);
 }
 #else
-#define dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus)
+#define dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus)
 #endif
 
 static int debug_irq;
 
-static void dsi_handle_irq_errors(u32 irqstatus, u32 *vcstatus, u32 ciostatus)
+static void dsi_handle_irq_errors(struct platform_device *dsidev, u32 irqstatus,
+               u32 *vcstatus, u32 ciostatus)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int i;
 
        if (irqstatus & DSI_IRQ_ERROR_MASK) {
                DSSERR("DSI error, irqstatus %x\n", irqstatus);
                print_irq_status(irqstatus);
-               spin_lock(&dsi.errors_lock);
-               dsi.errors |= irqstatus & DSI_IRQ_ERROR_MASK;
-               spin_unlock(&dsi.errors_lock);
+               spin_lock(&dsi->errors_lock);
+               dsi->errors |= irqstatus & DSI_IRQ_ERROR_MASK;
+               spin_unlock(&dsi->errors_lock);
        } else if (debug_irq) {
                print_irq_status(irqstatus);
        }
@@ -602,22 +697,27 @@ static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables,
 
 static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
 {
+       struct platform_device *dsidev;
+       struct dsi_data *dsi;
        u32 irqstatus, vcstatus[4], ciostatus;
        int i;
 
-       spin_lock(&dsi.irq_lock);
+       dsidev = (struct platform_device *) arg;
+       dsi = dsi_get_dsidrv_data(dsidev);
+
+       spin_lock(&dsi->irq_lock);
 
-       irqstatus = dsi_read_reg(DSI_IRQSTATUS);
+       irqstatus = dsi_read_reg(dsidev, DSI_IRQSTATUS);
 
        /* IRQ is not for us */
        if (!irqstatus) {
-               spin_unlock(&dsi.irq_lock);
+               spin_unlock(&dsi->irq_lock);
                return IRQ_NONE;
        }
 
-       dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
+       dsi_write_reg(dsidev, DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
        /* flush posted write */
-       dsi_read_reg(DSI_IRQSTATUS);
+       dsi_read_reg(dsidev, DSI_IRQSTATUS);
 
        for (i = 0; i < 4; ++i) {
                if ((irqstatus & (1 << i)) == 0) {
@@ -625,45 +725,47 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
                        continue;
                }
 
-               vcstatus[i] = dsi_read_reg(DSI_VC_IRQSTATUS(i));
+               vcstatus[i] = dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));
 
-               dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus[i]);
+               dsi_write_reg(dsidev, DSI_VC_IRQSTATUS(i), vcstatus[i]);
                /* flush posted write */
-               dsi_read_reg(DSI_VC_IRQSTATUS(i));
+               dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));
        }
 
        if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
-               ciostatus = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
+               ciostatus = dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);
 
-               dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
+               dsi_write_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
                /* flush posted write */
-               dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
+               dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);
        } else {
                ciostatus = 0;
        }
 
 #ifdef DSI_CATCH_MISSING_TE
        if (irqstatus & DSI_IRQ_TE_TRIGGER)
-               del_timer(&dsi.te_timer);
+               del_timer(&dsi->te_timer);
 #endif
 
        /* make a copy and unlock, so that isrs can unregister
         * themselves */
-       memcpy(&dsi.isr_tables_copy, &dsi.isr_tables, sizeof(dsi.isr_tables));
+       memcpy(&dsi->isr_tables_copy, &dsi->isr_tables,
+               sizeof(dsi->isr_tables));
 
-       spin_unlock(&dsi.irq_lock);
+       spin_unlock(&dsi->irq_lock);
 
-       dsi_handle_isrs(&dsi.isr_tables_copy, irqstatus, vcstatus, ciostatus);
+       dsi_handle_isrs(&dsi->isr_tables_copy, irqstatus, vcstatus, ciostatus);
 
-       dsi_handle_irq_errors(irqstatus, vcstatus, ciostatus);
+       dsi_handle_irq_errors(dsidev, irqstatus, vcstatus, ciostatus);
 
-       dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus);
+       dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus);
 
        return IRQ_HANDLED;
 }
 
-/* dsi.irq_lock has to be locked by the caller */
-static void _omap_dsi_configure_irqs(struct dsi_isr_data *isr_array,
+/* dsi->irq_lock has to be locked by the caller */
+static void _omap_dsi_configure_irqs(struct platform_device *dsidev,
+               struct dsi_isr_data *isr_array,
                unsigned isr_array_size, u32 default_mask,
                const struct dsi_reg enable_reg,
                const struct dsi_reg status_reg)
@@ -684,61 +786,67 @@ static void _omap_dsi_configure_irqs(struct dsi_isr_data *isr_array,
                mask |= isr_data->mask;
        }
 
-       old_mask = dsi_read_reg(enable_reg);
+       old_mask = dsi_read_reg(dsidev, enable_reg);
        /* clear the irqstatus for newly enabled irqs */
-       dsi_write_reg(status_reg, (mask ^ old_mask) & mask);
-       dsi_write_reg(enable_reg, mask);
+       dsi_write_reg(dsidev, status_reg, (mask ^ old_mask) & mask);
+       dsi_write_reg(dsidev, enable_reg, mask);
 
        /* flush posted writes */
-       dsi_read_reg(enable_reg);
-       dsi_read_reg(status_reg);
+       dsi_read_reg(dsidev, enable_reg);
+       dsi_read_reg(dsidev, status_reg);
 }
 
-/* dsi.irq_lock has to be locked by the caller */
-static void _omap_dsi_set_irqs(void)
+/* dsi->irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs(struct platform_device *dsidev)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        u32 mask = DSI_IRQ_ERROR_MASK;
 #ifdef DSI_CATCH_MISSING_TE
        mask |= DSI_IRQ_TE_TRIGGER;
 #endif
-       _omap_dsi_configure_irqs(dsi.isr_tables.isr_table,
-                       ARRAY_SIZE(dsi.isr_tables.isr_table), mask,
+       _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table,
+                       ARRAY_SIZE(dsi->isr_tables.isr_table), mask,
                        DSI_IRQENABLE, DSI_IRQSTATUS);
 }
 
-/* dsi.irq_lock has to be locked by the caller */
-static void _omap_dsi_set_irqs_vc(int vc)
+/* dsi->irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs_vc(struct platform_device *dsidev, int vc)
 {
-       _omap_dsi_configure_irqs(dsi.isr_tables.isr_table_vc[vc],
-                       ARRAY_SIZE(dsi.isr_tables.isr_table_vc[vc]),
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_vc[vc],
+                       ARRAY_SIZE(dsi->isr_tables.isr_table_vc[vc]),
                        DSI_VC_IRQ_ERROR_MASK,
                        DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc));
 }
 
-/* dsi.irq_lock has to be locked by the caller */
-static void _omap_dsi_set_irqs_cio(void)
+/* dsi->irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs_cio(struct platform_device *dsidev)
 {
-       _omap_dsi_configure_irqs(dsi.isr_tables.isr_table_cio,
-                       ARRAY_SIZE(dsi.isr_tables.isr_table_cio),
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_cio,
+                       ARRAY_SIZE(dsi->isr_tables.isr_table_cio),
                        DSI_CIO_IRQ_ERROR_MASK,
                        DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS);
 }
 
-static void _dsi_initialize_irq(void)
+static void _dsi_initialize_irq(struct platform_device *dsidev)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        int vc;
 
-       spin_lock_irqsave(&dsi.irq_lock, flags);
+       spin_lock_irqsave(&dsi->irq_lock, flags);
 
-       memset(&dsi.isr_tables, 0, sizeof(dsi.isr_tables));
+       memset(&dsi->isr_tables, 0, sizeof(dsi->isr_tables));
 
-       _omap_dsi_set_irqs();
+       _omap_dsi_set_irqs(dsidev);
        for (vc = 0; vc < 4; ++vc)
-               _omap_dsi_set_irqs_vc(vc);
-       _omap_dsi_set_irqs_cio();
+               _omap_dsi_set_irqs_vc(dsidev, vc);
+       _omap_dsi_set_irqs_cio(dsidev);
 
-       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+       spin_unlock_irqrestore(&dsi->irq_lock, flags);
 }
 
 static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
@@ -797,126 +905,137 @@ static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
        return -EINVAL;
 }
 
-static int dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask)
+static int dsi_register_isr(struct platform_device *dsidev, omap_dsi_isr_t isr,
+               void *arg, u32 mask)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        int r;
 
-       spin_lock_irqsave(&dsi.irq_lock, flags);
+       spin_lock_irqsave(&dsi->irq_lock, flags);
 
-       r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table,
-                       ARRAY_SIZE(dsi.isr_tables.isr_table));
+       r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table,
+                       ARRAY_SIZE(dsi->isr_tables.isr_table));
 
        if (r == 0)
-               _omap_dsi_set_irqs();
+               _omap_dsi_set_irqs(dsidev);
 
-       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+       spin_unlock_irqrestore(&dsi->irq_lock, flags);
 
        return r;
 }
 
-static int dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask)
+static int dsi_unregister_isr(struct platform_device *dsidev,
+               omap_dsi_isr_t isr, void *arg, u32 mask)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        int r;
 
-       spin_lock_irqsave(&dsi.irq_lock, flags);
+       spin_lock_irqsave(&dsi->irq_lock, flags);
 
-       r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table,
-                       ARRAY_SIZE(dsi.isr_tables.isr_table));
+       r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table,
+                       ARRAY_SIZE(dsi->isr_tables.isr_table));
 
        if (r == 0)
-               _omap_dsi_set_irqs();
+               _omap_dsi_set_irqs(dsidev);
 
-       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+       spin_unlock_irqrestore(&dsi->irq_lock, flags);
 
        return r;
 }
 
-static int dsi_register_isr_vc(int channel, omap_dsi_isr_t isr, void *arg,
-               u32 mask)
+static int dsi_register_isr_vc(struct platform_device *dsidev, int channel,
+               omap_dsi_isr_t isr, void *arg, u32 mask)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        int r;
 
-       spin_lock_irqsave(&dsi.irq_lock, flags);
+       spin_lock_irqsave(&dsi->irq_lock, flags);
 
        r = _dsi_register_isr(isr, arg, mask,
-                       dsi.isr_tables.isr_table_vc[channel],
-                       ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel]));
+                       dsi->isr_tables.isr_table_vc[channel],
+                       ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));
 
        if (r == 0)
-               _omap_dsi_set_irqs_vc(channel);
+               _omap_dsi_set_irqs_vc(dsidev, channel);
 
-       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+       spin_unlock_irqrestore(&dsi->irq_lock, flags);
 
        return r;
 }
 
-static int dsi_unregister_isr_vc(int channel, omap_dsi_isr_t isr, void *arg,
-               u32 mask)
+static int dsi_unregister_isr_vc(struct platform_device *dsidev, int channel,
+               omap_dsi_isr_t isr, void *arg, u32 mask)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        int r;
 
-       spin_lock_irqsave(&dsi.irq_lock, flags);
+       spin_lock_irqsave(&dsi->irq_lock, flags);
 
        r = _dsi_unregister_isr(isr, arg, mask,
-                       dsi.isr_tables.isr_table_vc[channel],
-                       ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel]));
+                       dsi->isr_tables.isr_table_vc[channel],
+                       ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));
 
        if (r == 0)
-               _omap_dsi_set_irqs_vc(channel);
+               _omap_dsi_set_irqs_vc(dsidev, channel);
 
-       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+       spin_unlock_irqrestore(&dsi->irq_lock, flags);
 
        return r;
 }
 
-static int dsi_register_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask)
+static int dsi_register_isr_cio(struct platform_device *dsidev,
+               omap_dsi_isr_t isr, void *arg, u32 mask)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        int r;
 
-       spin_lock_irqsave(&dsi.irq_lock, flags);
+       spin_lock_irqsave(&dsi->irq_lock, flags);
 
-       r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio,
-                       ARRAY_SIZE(dsi.isr_tables.isr_table_cio));
+       r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
+                       ARRAY_SIZE(dsi->isr_tables.isr_table_cio));
 
        if (r == 0)
-               _omap_dsi_set_irqs_cio();
+               _omap_dsi_set_irqs_cio(dsidev);
 
-       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+       spin_unlock_irqrestore(&dsi->irq_lock, flags);
 
        return r;
 }
 
-static int dsi_unregister_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask)
+static int dsi_unregister_isr_cio(struct platform_device *dsidev,
+               omap_dsi_isr_t isr, void *arg, u32 mask)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        int r;
 
-       spin_lock_irqsave(&dsi.irq_lock, flags);
+       spin_lock_irqsave(&dsi->irq_lock, flags);
 
-       r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio,
-                       ARRAY_SIZE(dsi.isr_tables.isr_table_cio));
+       r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
+                       ARRAY_SIZE(dsi->isr_tables.isr_table_cio));
 
        if (r == 0)
-               _omap_dsi_set_irqs_cio();
+               _omap_dsi_set_irqs_cio(dsidev);
 
-       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+       spin_unlock_irqrestore(&dsi->irq_lock, flags);
 
        return r;
 }
 
-static u32 dsi_get_errors(void)
+static u32 dsi_get_errors(struct platform_device *dsidev)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        u32 e;
-       spin_lock_irqsave(&dsi.errors_lock, flags);
-       e = dsi.errors;
-       dsi.errors = 0;
-       spin_unlock_irqrestore(&dsi.errors_lock, flags);
+       spin_lock_irqsave(&dsi->errors_lock, flags);
+       e = dsi->errors;
+       dsi->errors = 0;
+       spin_unlock_irqrestore(&dsi->errors_lock, flags);
        return e;
 }
 
@@ -930,23 +1049,27 @@ static inline void enable_clocks(bool enable)
 }
 
 /* source clock for DSI PLL. this could also be PCLKFREE */
-static inline void dsi_enable_pll_clock(bool enable)
+static inline void dsi_enable_pll_clock(struct platform_device *dsidev,
+               bool enable)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
        if (enable)
                dss_clk_enable(DSS_CLK_SYSCK);
        else
                dss_clk_disable(DSS_CLK_SYSCK);
 
-       if (enable && dsi.pll_locked) {
-               if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1)
+       if (enable && dsi->pll_locked) {
+               if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1)
                        DSSERR("cannot lock PLL when enabling clocks\n");
        }
 }
 
 #ifdef DEBUG
-static void _dsi_print_reset_status(void)
+static void _dsi_print_reset_status(struct platform_device *dsidev)
 {
        u32 l;
+       int b0, b1, b2;
 
        if (!dss_debug)
                return;
@@ -954,35 +1077,47 @@ static void _dsi_print_reset_status(void)
        /* A dummy read using the SCP interface to any DSIPHY register is
         * required after DSIPHY reset to complete the reset of the DSI complex
         * I/O. */
-       l = dsi_read_reg(DSI_DSIPHY_CFG5);
+       l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
 
        printk(KERN_DEBUG "DSI resets: ");
 
-       l = dsi_read_reg(DSI_PLL_STATUS);
+       l = dsi_read_reg(dsidev, DSI_PLL_STATUS);
        printk("PLL (%d) ", FLD_GET(l, 0, 0));
 
-       l = dsi_read_reg(DSI_COMPLEXIO_CFG1);
+       l = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1);
        printk("CIO (%d) ", FLD_GET(l, 29, 29));
 
-       l = dsi_read_reg(DSI_DSIPHY_CFG5);
-       printk("PHY (%x, %d, %d, %d)\n",
-                       FLD_GET(l, 28, 26),
+       if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) {
+               b0 = 28;
+               b1 = 27;
+               b2 = 26;
+       } else {
+               b0 = 24;
+               b1 = 25;
+               b2 = 26;
+       }
+
+       l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
+       printk("PHY (%x%x%x, %d, %d, %d)\n",
+                       FLD_GET(l, b0, b0),
+                       FLD_GET(l, b1, b1),
+                       FLD_GET(l, b2, b2),
                        FLD_GET(l, 29, 29),
                        FLD_GET(l, 30, 30),
                        FLD_GET(l, 31, 31));
 }
 #else
-#define _dsi_print_reset_status()
+#define _dsi_print_reset_status(x)
 #endif
 
-static inline int dsi_if_enable(bool enable)
+static inline int dsi_if_enable(struct platform_device *dsidev, bool enable)
 {
        DSSDBG("dsi_if_enable(%d)\n", enable);
 
        enable = enable ? 1 : 0;
-       REG_FLD_MOD(DSI_CTRL, enable, 0, 0); /* IF_EN */
+       REG_FLD_MOD(dsidev, DSI_CTRL, enable, 0, 0); /* IF_EN */
 
-       if (wait_for_bit_change(DSI_CTRL, 0, enable) != enable) {
+       if (wait_for_bit_change(dsidev, DSI_CTRL, 0, enable) != enable) {
                        DSSERR("Failed to set dsi_if_enable to %d\n", enable);
                        return -EIO;
        }
@@ -990,31 +1125,38 @@ static inline int dsi_if_enable(bool enable)
        return 0;
 }
 
-unsigned long dsi_get_pll_hsdiv_dispc_rate(void)
+unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
 {
-       return dsi.current_cinfo.dsi_pll_hsdiv_dispc_clk;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       return dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk;
 }
 
-static unsigned long dsi_get_pll_hsdiv_dsi_rate(void)
+static unsigned long dsi_get_pll_hsdiv_dsi_rate(struct platform_device *dsidev)
 {
-       return dsi.current_cinfo.dsi_pll_hsdiv_dsi_clk;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       return dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk;
 }
 
-static unsigned long dsi_get_txbyteclkhs(void)
+static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev)
 {
-       return dsi.current_cinfo.clkin4ddr / 16;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       return dsi->current_cinfo.clkin4ddr / 16;
 }
 
-static unsigned long dsi_fclk_rate(void)
+static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
 {
        unsigned long r;
+       int dsi_module = dsi_get_dsidev_id(dsidev);
 
-       if (dss_get_dsi_clk_source() == DSS_CLK_SRC_FCK) {
+       if (dss_get_dsi_clk_source(dsi_module) == OMAP_DSS_CLK_SRC_FCK) {
                /* DSI FCLK source is DSS_CLK_FCK */
                r = dss_clk_get_rate(DSS_CLK_FCK);
        } else {
                /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */
-               r = dsi_get_pll_hsdiv_dsi_rate();
+               r = dsi_get_pll_hsdiv_dsi_rate(dsidev);
        }
 
        return r;
@@ -1022,31 +1164,50 @@ static unsigned long dsi_fclk_rate(void)
 
 static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long dsi_fclk;
        unsigned lp_clk_div;
        unsigned long lp_clk;
 
-       lp_clk_div = dssdev->phy.dsi.div.lp_clk_div;
+       lp_clk_div = dssdev->clocks.dsi.lp_clk_div;
 
-       if (lp_clk_div == 0 || lp_clk_div > dsi.lpdiv_max)
+       if (lp_clk_div == 0 || lp_clk_div > dsi->lpdiv_max)
                return -EINVAL;
 
-       dsi_fclk = dsi_fclk_rate();
+       dsi_fclk = dsi_fclk_rate(dsidev);
 
        lp_clk = dsi_fclk / 2 / lp_clk_div;
 
        DSSDBG("LP_CLK_DIV %u, LP_CLK %lu\n", lp_clk_div, lp_clk);
-       dsi.current_cinfo.lp_clk = lp_clk;
-       dsi.current_cinfo.lp_clk_div = lp_clk_div;
+       dsi->current_cinfo.lp_clk = lp_clk;
+       dsi->current_cinfo.lp_clk_div = lp_clk_div;
 
-       REG_FLD_MOD(DSI_CLK_CTRL, lp_clk_div, 12, 0);   /* LP_CLK_DIVISOR */
+       /* LP_CLK_DIVISOR */
+       REG_FLD_MOD(dsidev, DSI_CLK_CTRL, lp_clk_div, 12, 0);
 
-       REG_FLD_MOD(DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0,
-                       21, 21);                /* LP_RX_SYNCHRO_ENABLE */
+       /* LP_RX_SYNCHRO_ENABLE */
+       REG_FLD_MOD(dsidev, DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0, 21, 21);
 
        return 0;
 }
 
+static void dsi_enable_scp_clk(struct platform_device *dsidev)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       if (dsi->scp_clk_refcount++ == 0)
+               REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 14, 14); /* CIO_CLK_ICG */
+}
+
+static void dsi_disable_scp_clk(struct platform_device *dsidev)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       WARN_ON(dsi->scp_clk_refcount == 0);
+       if (--dsi->scp_clk_refcount == 0)
+               REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 14, 14); /* CIO_CLK_ICG */
+}
 
 enum dsi_pll_power_state {
        DSI_PLL_POWER_OFF       = 0x0,
@@ -1055,14 +1216,21 @@ enum dsi_pll_power_state {
        DSI_PLL_POWER_ON_DIV    = 0x3,
 };
 
-static int dsi_pll_power(enum dsi_pll_power_state state)
+static int dsi_pll_power(struct platform_device *dsidev,
+               enum dsi_pll_power_state state)
 {
        int t = 0;
 
-       REG_FLD_MOD(DSI_CLK_CTRL, state, 31, 30);       /* PLL_PWR_CMD */
+       /* DSI-PLL power command 0x3 is not working */
+       if (dss_has_feature(FEAT_DSI_PLL_PWR_BUG) &&
+                       state == DSI_PLL_POWER_ON_DIV)
+               state = DSI_PLL_POWER_ON_ALL;
+
+       /* PLL_PWR_CMD */
+       REG_FLD_MOD(dsidev, DSI_CLK_CTRL, state, 31, 30);
 
        /* PLL_PWR_STATUS */
-       while (FLD_GET(dsi_read_reg(DSI_CLK_CTRL), 29, 28) != state) {
+       while (FLD_GET(dsi_read_reg(dsidev, DSI_CLK_CTRL), 29, 28) != state) {
                if (++t > 1000) {
                        DSSERR("Failed to set DSI PLL power mode to %d\n",
                                        state);
@@ -1078,16 +1246,19 @@ static int dsi_pll_power(enum dsi_pll_power_state state)
 static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
                struct dsi_clock_info *cinfo)
 {
-       if (cinfo->regn == 0 || cinfo->regn > dsi.regn_max)
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       if (cinfo->regn == 0 || cinfo->regn > dsi->regn_max)
                return -EINVAL;
 
-       if (cinfo->regm == 0 || cinfo->regm > dsi.regm_max)
+       if (cinfo->regm == 0 || cinfo->regm > dsi->regm_max)
                return -EINVAL;
 
-       if (cinfo->regm_dispc > dsi.regm_dispc_max)
+       if (cinfo->regm_dispc > dsi->regm_dispc_max)
                return -EINVAL;
 
-       if (cinfo->regm_dsi > dsi.regm_dsi_max)
+       if (cinfo->regm_dsi > dsi->regm_dsi_max)
                return -EINVAL;
 
        if (cinfo->use_sys_clk) {
@@ -1106,7 +1277,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
 
        cinfo->fint = cinfo->clkin / (cinfo->regn * (cinfo->highfreq ? 2 : 1));
 
-       if (cinfo->fint > dsi.fint_max || cinfo->fint < dsi.fint_min)
+       if (cinfo->fint > dsi->fint_max || cinfo->fint < dsi->fint_min)
                return -EINVAL;
 
        cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint;
@@ -1129,10 +1300,11 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
        return 0;
 }
 
-int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
-               struct dsi_clock_info *dsi_cinfo,
+int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft,
+               unsigned long req_pck, struct dsi_clock_info *dsi_cinfo,
                struct dispc_clock_info *dispc_cinfo)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        struct dsi_clock_info cur, best;
        struct dispc_clock_info best_dispc;
        int min_fck_per_pck;
@@ -1143,10 +1315,10 @@ int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
 
        max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
 
-       if (req_pck == dsi.cache_req_pck &&
-                       dsi.cache_cinfo.clkin == dss_sys_clk) {
+       if (req_pck == dsi->cache_req_pck &&
+                       dsi->cache_cinfo.clkin == dss_sys_clk) {
                DSSDBG("DSI clock info found from cache\n");
-               *dsi_cinfo = dsi.cache_cinfo;
+               *dsi_cinfo = dsi->cache_cinfo;
                dispc_find_clk_divs(is_tft, req_pck,
                        dsi_cinfo->dsi_pll_hsdiv_dispc_clk, dispc_cinfo);
                return 0;
@@ -1176,17 +1348,17 @@ retry:
        /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */
        /* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */
        /* To reduce PLL lock time, keep Fint high (around 2 MHz) */
-       for (cur.regn = 1; cur.regn < dsi.regn_max; ++cur.regn) {
+       for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
                if (cur.highfreq == 0)
                        cur.fint = cur.clkin / cur.regn;
                else
                        cur.fint = cur.clkin / (2 * cur.regn);
 
-               if (cur.fint > dsi.fint_max || cur.fint < dsi.fint_min)
+               if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min)
                        continue;
 
                /* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */
-               for (cur.regm = 1; cur.regm < dsi.regm_max; ++cur.regm) {
+               for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) {
                        unsigned long a, b;
 
                        a = 2 * cur.regm * (cur.clkin/1000);
@@ -1198,8 +1370,8 @@ retry:
 
                        /* dsi_pll_hsdiv_dispc_clk(MHz) =
                         * DSIPHY(MHz) / regm_dispc  < 173MHz/186Mhz */
-                       for (cur.regm_dispc = 1; cur.regm_dispc < dsi.regm_dispc_max;
-                                       ++cur.regm_dispc) {
+                       for (cur.regm_dispc = 1; cur.regm_dispc <
+                                       dsi->regm_dispc_max; ++cur.regm_dispc) {
                                struct dispc_clock_info cur_dispc;
                                cur.dsi_pll_hsdiv_dispc_clk =
                                        cur.clkin4ddr / cur.regm_dispc;
@@ -1259,34 +1431,39 @@ found:
        if (dispc_cinfo)
                *dispc_cinfo = best_dispc;
 
-       dsi.cache_req_pck = req_pck;
-       dsi.cache_clk_freq = 0;
-       dsi.cache_cinfo = best;
+       dsi->cache_req_pck = req_pck;
+       dsi->cache_clk_freq = 0;
+       dsi->cache_cinfo = best;
 
        return 0;
 }
 
-int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
+int dsi_pll_set_clock_div(struct platform_device *dsidev,
+               struct dsi_clock_info *cinfo)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int r = 0;
        u32 l;
-       int f;
+       int f = 0;
        u8 regn_start, regn_end, regm_start, regm_end;
        u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end;
 
        DSSDBGF();
 
-       dsi.current_cinfo.fint = cinfo->fint;
-       dsi.current_cinfo.clkin4ddr = cinfo->clkin4ddr;
-       dsi.current_cinfo.dsi_pll_hsdiv_dispc_clk =
+       dsi->current_cinfo.use_sys_clk = cinfo->use_sys_clk;
+       dsi->current_cinfo.highfreq = cinfo->highfreq;
+
+       dsi->current_cinfo.fint = cinfo->fint;
+       dsi->current_cinfo.clkin4ddr = cinfo->clkin4ddr;
+       dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk =
                        cinfo->dsi_pll_hsdiv_dispc_clk;
-       dsi.current_cinfo.dsi_pll_hsdiv_dsi_clk =
+       dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk =
                        cinfo->dsi_pll_hsdiv_dsi_clk;
 
-       dsi.current_cinfo.regn = cinfo->regn;
-       dsi.current_cinfo.regm = cinfo->regm;
-       dsi.current_cinfo.regm_dispc = cinfo->regm_dispc;
-       dsi.current_cinfo.regm_dsi = cinfo->regm_dsi;
+       dsi->current_cinfo.regn = cinfo->regn;
+       dsi->current_cinfo.regm = cinfo->regm;
+       dsi->current_cinfo.regm_dispc = cinfo->regm_dispc;
+       dsi->current_cinfo.regm_dsi = cinfo->regm_dsi;
 
        DSSDBG("DSI Fint %ld\n", cinfo->fint);
 
@@ -1309,12 +1486,12 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
        DSSDBG("Clock lane freq %ld Hz\n", cinfo->clkin4ddr / 4);
 
        DSSDBG("regm_dispc = %d, %s (%s) = %lu\n", cinfo->regm_dispc,
-               dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
-               dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
+               dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
+               dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
                cinfo->dsi_pll_hsdiv_dispc_clk);
        DSSDBG("regm_dsi = %d, %s (%s) = %lu\n", cinfo->regm_dsi,
-               dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
-               dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
+               dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
+               dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
                cinfo->dsi_pll_hsdiv_dsi_clk);
 
        dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGN, &regn_start, &regn_end);
@@ -1324,9 +1501,10 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
        dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DSI, &regm_dsi_start,
                        &regm_dsi_end);
 
-       REG_FLD_MOD(DSI_PLL_CONTROL, 0, 0, 0); /* DSI_PLL_AUTOMODE = manual */
+       /* DSI_PLL_AUTOMODE = manual */
+       REG_FLD_MOD(dsidev, DSI_PLL_CONTROL, 0, 0, 0);
 
-       l = dsi_read_reg(DSI_PLL_CONFIGURATION1);
+       l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION1);
        l = FLD_MOD(l, 1, 0, 0);                /* DSI_PLL_STOPMODE */
        /* DSI_PLL_REGN */
        l = FLD_MOD(l, cinfo->regn - 1, regn_start, regn_end);
@@ -1338,22 +1516,22 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
        /* DSIPROTO_CLOCK_DIV */
        l = FLD_MOD(l, cinfo->regm_dsi > 0 ? cinfo->regm_dsi - 1 : 0,
                        regm_dsi_start, regm_dsi_end);
-       dsi_write_reg(DSI_PLL_CONFIGURATION1, l);
-
-       BUG_ON(cinfo->fint < dsi.fint_min || cinfo->fint > dsi.fint_max);
-       if (cinfo->fint < 1000000)
-               f = 0x3;
-       else if (cinfo->fint < 1250000)
-               f = 0x4;
-       else if (cinfo->fint < 1500000)
-               f = 0x5;
-       else if (cinfo->fint < 1750000)
-               f = 0x6;
-       else
-               f = 0x7;
+       dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION1, l);
+
+       BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max);
+
+       if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) {
+               f = cinfo->fint < 1000000 ? 0x3 :
+                       cinfo->fint < 1250000 ? 0x4 :
+                       cinfo->fint < 1500000 ? 0x5 :
+                       cinfo->fint < 1750000 ? 0x6 :
+                       0x7;
+       }
+
+       l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
 
-       l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
-       l = FLD_MOD(l, f, 4, 1);                /* DSI_PLL_FREQSEL */
+       if (dss_has_feature(FEAT_DSI_PLL_FREQSEL))
+               l = FLD_MOD(l, f, 4, 1);        /* DSI_PLL_FREQSEL */
        l = FLD_MOD(l, cinfo->use_sys_clk ? 0 : 1,
                        11, 11);                /* DSI_PLL_CLKSEL */
        l = FLD_MOD(l, cinfo->highfreq,
@@ -1361,25 +1539,25 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
        l = FLD_MOD(l, 1, 13, 13);              /* DSI_PLL_REFEN */
        l = FLD_MOD(l, 0, 14, 14);              /* DSIPHY_CLKINEN */
        l = FLD_MOD(l, 1, 20, 20);              /* DSI_HSDIVBYPASS */
-       dsi_write_reg(DSI_PLL_CONFIGURATION2, l);
+       dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
 
-       REG_FLD_MOD(DSI_PLL_GO, 1, 0, 0);       /* DSI_PLL_GO */
+       REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0);       /* DSI_PLL_GO */
 
-       if (wait_for_bit_change(DSI_PLL_GO, 0, 0) != 0) {
+       if (wait_for_bit_change(dsidev, DSI_PLL_GO, 0, 0) != 0) {
                DSSERR("dsi pll go bit not going down.\n");
                r = -EIO;
                goto err;
        }
 
-       if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1) {
+       if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) {
                DSSERR("cannot lock PLL\n");
                r = -EIO;
                goto err;
        }
 
-       dsi.pll_locked = 1;
+       dsi->pll_locked = 1;
 
-       l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
+       l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
        l = FLD_MOD(l, 0, 0, 0);        /* DSI_PLL_IDLE */
        l = FLD_MOD(l, 0, 5, 5);        /* DSI_PLL_PLLLPMODE */
        l = FLD_MOD(l, 0, 6, 6);        /* DSI_PLL_LOWCURRSTBY */
@@ -1394,52 +1572,53 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
        l = FLD_MOD(l, 1, 18, 18);      /* DSI_PROTO_CLOCK_EN */
        l = FLD_MOD(l, 0, 19, 19);      /* DSI_PROTO_CLOCK_PWDN */
        l = FLD_MOD(l, 0, 20, 20);      /* DSI_HSDIVBYPASS */
-       dsi_write_reg(DSI_PLL_CONFIGURATION2, l);
+       dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
 
        DSSDBG("PLL config done\n");
 err:
        return r;
 }
 
-int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
+int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
                bool enable_hsdiv)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int r = 0;
        enum dsi_pll_power_state pwstate;
 
        DSSDBG("PLL init\n");
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-       /*
-        * HACK: this is just a quick hack to get the USE_DSI_PLL
-        * option working. USE_DSI_PLL is itself a big hack, and
-        * should be removed.
-        */
-       if (dsi.vdds_dsi_reg == NULL) {
+       if (dsi->vdds_dsi_reg == NULL) {
                struct regulator *vdds_dsi;
 
-               vdds_dsi = regulator_get(&dsi.pdev->dev, "vdds_dsi");
+               vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi");
 
                if (IS_ERR(vdds_dsi)) {
                        DSSERR("can't get VDDS_DSI regulator\n");
                        return PTR_ERR(vdds_dsi);
                }
 
-               dsi.vdds_dsi_reg = vdds_dsi;
+               dsi->vdds_dsi_reg = vdds_dsi;
        }
-#endif
 
        enable_clocks(1);
-       dsi_enable_pll_clock(1);
+       dsi_enable_pll_clock(dsidev, 1);
+       /*
+        * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4.
+        */
+       dsi_enable_scp_clk(dsidev);
 
-       r = regulator_enable(dsi.vdds_dsi_reg);
-       if (r)
-               goto err0;
+       if (!dsi->vdds_dsi_enabled) {
+               r = regulator_enable(dsi->vdds_dsi_reg);
+               if (r)
+                       goto err0;
+               dsi->vdds_dsi_enabled = true;
+       }
 
        /* XXX PLL does not come out of reset without this... */
        dispc_pck_free_enable(1);
 
-       if (wait_for_bit_change(DSI_PLL_STATUS, 0, 1) != 1) {
+       if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 0, 1) != 1) {
                DSSERR("PLL not coming out of reset.\n");
                r = -ENODEV;
                dispc_pck_free_enable(0);
@@ -1459,7 +1638,7 @@ int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
        else
                pwstate = DSI_PLL_POWER_OFF;
 
-       r = dsi_pll_power(pwstate);
+       r = dsi_pll_power(dsidev, pwstate);
 
        if (r)
                goto err1;
@@ -1468,42 +1647,53 @@ int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
 
        return 0;
 err1:
-       regulator_disable(dsi.vdds_dsi_reg);
+       if (dsi->vdds_dsi_enabled) {
+               regulator_disable(dsi->vdds_dsi_reg);
+               dsi->vdds_dsi_enabled = false;
+       }
 err0:
+       dsi_disable_scp_clk(dsidev);
        enable_clocks(0);
-       dsi_enable_pll_clock(0);
+       dsi_enable_pll_clock(dsidev, 0);
        return r;
 }
 
-void dsi_pll_uninit(void)
+void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       dsi->pll_locked = 0;
+       dsi_pll_power(dsidev, DSI_PLL_POWER_OFF);
+       if (disconnect_lanes) {
+               WARN_ON(!dsi->vdds_dsi_enabled);
+               regulator_disable(dsi->vdds_dsi_reg);
+               dsi->vdds_dsi_enabled = false;
+       }
+
+       dsi_disable_scp_clk(dsidev);
        enable_clocks(0);
-       dsi_enable_pll_clock(0);
+       dsi_enable_pll_clock(dsidev, 0);
 
-       dsi.pll_locked = 0;
-       dsi_pll_power(DSI_PLL_POWER_OFF);
-       regulator_disable(dsi.vdds_dsi_reg);
        DSSDBG("PLL uninit done\n");
 }
 
-void dsi_dump_clocks(struct seq_file *s)
+static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
+               struct seq_file *s)
 {
-       int clksel;
-       struct dsi_clock_info *cinfo = &dsi.current_cinfo;
-       enum dss_clk_source dispc_clk_src, dsi_clk_src;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       struct dsi_clock_info *cinfo = &dsi->current_cinfo;
+       enum omap_dss_clk_source dispc_clk_src, dsi_clk_src;
+       int dsi_module = dsi_get_dsidev_id(dsidev);
 
        dispc_clk_src = dss_get_dispc_clk_source();
-       dsi_clk_src = dss_get_dsi_clk_source();
+       dsi_clk_src = dss_get_dsi_clk_source(dsi_module);
 
        enable_clocks(1);
 
-       clksel = REG_GET(DSI_PLL_CONFIGURATION2, 11, 11);
-
-       seq_printf(s,   "- DSI PLL -\n");
+       seq_printf(s,   "- DSI%d PLL -\n", dsi_module + 1);
 
        seq_printf(s,   "dsi pll source = %s\n",
-                       clksel == 0 ?
-                       "dss_sys_clk" : "pclkfree");
+                       cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree");
 
        seq_printf(s,   "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);
 
@@ -1515,7 +1705,7 @@ void dsi_dump_clocks(struct seq_file *s)
                        dss_feat_get_clk_source_name(dispc_clk_src),
                        cinfo->dsi_pll_hsdiv_dispc_clk,
                        cinfo->regm_dispc,
-                       dispc_clk_src == DSS_CLK_SRC_FCK ?
+                       dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ?
                        "off" : "on");
 
        seq_printf(s,   "%s (%s)\t%-16luregm_dsi %u\t(%s)\n",
@@ -1523,45 +1713,55 @@ void dsi_dump_clocks(struct seq_file *s)
                        dss_feat_get_clk_source_name(dsi_clk_src),
                        cinfo->dsi_pll_hsdiv_dsi_clk,
                        cinfo->regm_dsi,
-                       dsi_clk_src == DSS_CLK_SRC_FCK ?
+                       dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ?
                        "off" : "on");
 
-       seq_printf(s,   "- DSI -\n");
+       seq_printf(s,   "- DSI%d -\n", dsi_module + 1);
 
        seq_printf(s,   "dsi fclk source = %s (%s)\n",
                        dss_get_generic_clk_source_name(dsi_clk_src),
                        dss_feat_get_clk_source_name(dsi_clk_src));
 
-       seq_printf(s,   "DSI_FCLK\t%lu\n", dsi_fclk_rate());
+       seq_printf(s,   "DSI_FCLK\t%lu\n", dsi_fclk_rate(dsidev));
 
        seq_printf(s,   "DDR_CLK\t\t%lu\n",
                        cinfo->clkin4ddr / 4);
 
-       seq_printf(s,   "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs());
+       seq_printf(s,   "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(dsidev));
 
        seq_printf(s,   "LP_CLK\t\t%lu\n", cinfo->lp_clk);
 
-       seq_printf(s,   "VP_CLK\t\t%lu\n"
-                       "VP_PCLK\t\t%lu\n",
-                       dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD),
-                       dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD));
-
        enable_clocks(0);
 }
 
+void dsi_dump_clocks(struct seq_file *s)
+{
+       struct platform_device *dsidev;
+       int i;
+
+       for  (i = 0; i < MAX_NUM_DSI; i++) {
+               dsidev = dsi_get_dsidev_from_id(i);
+               if (dsidev)
+                       dsi_dump_dsidev_clocks(dsidev, s);
+       }
+}
+
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-void dsi_dump_irqs(struct seq_file *s)
+static void dsi_dump_dsidev_irqs(struct platform_device *dsidev,
+               struct seq_file *s)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        struct dsi_irq_stats stats;
+       int dsi_module = dsi_get_dsidev_id(dsidev);
 
-       spin_lock_irqsave(&dsi.irq_stats_lock, flags);
+       spin_lock_irqsave(&dsi->irq_stats_lock, flags);
 
-       stats = dsi.irq_stats;
-       memset(&dsi.irq_stats, 0, sizeof(dsi.irq_stats));
-       dsi.irq_stats.last_reset = jiffies;
+       stats = dsi->irq_stats;
+       memset(&dsi->irq_stats, 0, sizeof(dsi->irq_stats));
+       dsi->irq_stats.last_reset = jiffies;
 
-       spin_unlock_irqrestore(&dsi.irq_stats_lock, flags);
+       spin_unlock_irqrestore(&dsi->irq_stats_lock, flags);
 
        seq_printf(s, "period %u ms\n",
                        jiffies_to_msecs(jiffies - stats.last_reset));
@@ -1570,7 +1770,7 @@ void dsi_dump_irqs(struct seq_file *s)
 #define PIS(x) \
        seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]);
 
-       seq_printf(s, "-- DSI interrupts --\n");
+       seq_printf(s, "-- DSI%d interrupts --\n", dsi_module + 1);
        PIS(VC0);
        PIS(VC1);
        PIS(VC2);
@@ -1636,13 +1836,45 @@ void dsi_dump_irqs(struct seq_file *s)
        PIS(ULPSACTIVENOT_ALL1);
 #undef PIS
 }
+
+static void dsi1_dump_irqs(struct seq_file *s)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_id(0);
+
+       dsi_dump_dsidev_irqs(dsidev, s);
+}
+
+static void dsi2_dump_irqs(struct seq_file *s)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_id(1);
+
+       dsi_dump_dsidev_irqs(dsidev, s);
+}
+
+void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir,
+               const struct file_operations *debug_fops)
+{
+       struct platform_device *dsidev;
+
+       dsidev = dsi_get_dsidev_from_id(0);
+       if (dsidev)
+               debugfs_create_file("dsi1_irqs", S_IRUGO, debugfs_dir,
+                       &dsi1_dump_irqs, debug_fops);
+
+       dsidev = dsi_get_dsidev_from_id(1);
+       if (dsidev)
+               debugfs_create_file("dsi2_irqs", S_IRUGO, debugfs_dir,
+                       &dsi2_dump_irqs, debug_fops);
+}
 #endif
 
-void dsi_dump_regs(struct seq_file *s)
+static void dsi_dump_dsidev_regs(struct platform_device *dsidev,
+               struct seq_file *s)
 {
-#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(r))
+#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsidev, r))
 
        dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       dsi_enable_scp_clk(dsidev);
 
        DUMPREG(DSI_REVISION);
        DUMPREG(DSI_SYSCONFIG);
@@ -1714,25 +1946,57 @@ void dsi_dump_regs(struct seq_file *s)
        DUMPREG(DSI_PLL_CONFIGURATION1);
        DUMPREG(DSI_PLL_CONFIGURATION2);
 
+       dsi_disable_scp_clk(dsidev);
        dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 #undef DUMPREG
 }
 
-enum dsi_complexio_power_state {
+static void dsi1_dump_regs(struct seq_file *s)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_id(0);
+
+       dsi_dump_dsidev_regs(dsidev, s);
+}
+
+static void dsi2_dump_regs(struct seq_file *s)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_id(1);
+
+       dsi_dump_dsidev_regs(dsidev, s);
+}
+
+void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir,
+               const struct file_operations *debug_fops)
+{
+       struct platform_device *dsidev;
+
+       dsidev = dsi_get_dsidev_from_id(0);
+       if (dsidev)
+               debugfs_create_file("dsi1_regs", S_IRUGO, debugfs_dir,
+                       &dsi1_dump_regs, debug_fops);
+
+       dsidev = dsi_get_dsidev_from_id(1);
+       if (dsidev)
+               debugfs_create_file("dsi2_regs", S_IRUGO, debugfs_dir,
+                       &dsi2_dump_regs, debug_fops);
+}
+enum dsi_cio_power_state {
        DSI_COMPLEXIO_POWER_OFF         = 0x0,
        DSI_COMPLEXIO_POWER_ON          = 0x1,
        DSI_COMPLEXIO_POWER_ULPS        = 0x2,
 };
 
-static int dsi_complexio_power(enum dsi_complexio_power_state state)
+static int dsi_cio_power(struct platform_device *dsidev,
+               enum dsi_cio_power_state state)
 {
        int t = 0;
 
        /* PWR_CMD */
-       REG_FLD_MOD(DSI_COMPLEXIO_CFG1, state, 28, 27);
+       REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG1, state, 28, 27);
 
        /* PWR_STATUS */
-       while (FLD_GET(dsi_read_reg(DSI_COMPLEXIO_CFG1), 26, 25) != state) {
+       while (FLD_GET(dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1),
+                       26, 25) != state) {
                if (++t > 1000) {
                        DSSERR("failed to set complexio power state to "
                                        "%d\n", state);
@@ -1744,9 +2008,70 @@ static int dsi_complexio_power(enum dsi_complexio_power_state state)
        return 0;
 }
 
-static void dsi_complexio_config(struct omap_dss_device *dssdev)
+/* Number of data lanes present on DSI interface */
+static inline int dsi_get_num_data_lanes(struct platform_device *dsidev)
 {
+       /* DSI on OMAP3 doesn't have register DSI_GNQ, set number
+        * of data lanes as 2 by default */
+       if (dss_has_feature(FEAT_DSI_GNQ))
+               return REG_GET(dsidev, DSI_GNQ, 11, 9); /* NB_DATA_LANES */
+       else
+               return 2;
+}
+
+/* Number of data lanes used by the dss device */
+static inline int dsi_get_num_data_lanes_dssdev(struct omap_dss_device *dssdev)
+{
+       int num_data_lanes = 0;
+
+       if (dssdev->phy.dsi.data1_lane != 0)
+               num_data_lanes++;
+       if (dssdev->phy.dsi.data2_lane != 0)
+               num_data_lanes++;
+       if (dssdev->phy.dsi.data3_lane != 0)
+               num_data_lanes++;
+       if (dssdev->phy.dsi.data4_lane != 0)
+               num_data_lanes++;
+
+       return num_data_lanes;
+}
+
+static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
+{
+       int val;
+
+       /* line buffer on OMAP3 is 1024 x 24bits */
+       /* XXX: for some reason using full buffer size causes
+        * considerable TX slowdown with update sizes that fill the
+        * whole buffer */
+       if (!dss_has_feature(FEAT_DSI_GNQ))
+               return 1023 * 3;
+
+       val = REG_GET(dsidev, DSI_GNQ, 14, 12); /* VP1_LINE_BUFFER_SIZE */
+
+       switch (val) {
+       case 1:
+               return 512 * 3;         /* 512x24 bits */
+       case 2:
+               return 682 * 3;         /* 682x24 bits */
+       case 3:
+               return 853 * 3;         /* 853x24 bits */
+       case 4:
+               return 1024 * 3;        /* 1024x24 bits */
+       case 5:
+               return 1194 * 3;        /* 1194x24 bits */
+       case 6:
+               return 1365 * 3;        /* 1365x24 bits */
+       default:
+               BUG();
+       }
+}
+
+static void dsi_set_lane_config(struct omap_dss_device *dssdev)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        u32 r;
+       int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev);
 
        int clk_lane   = dssdev->phy.dsi.clk_lane;
        int data1_lane = dssdev->phy.dsi.data1_lane;
@@ -1755,14 +2080,28 @@ static void dsi_complexio_config(struct omap_dss_device *dssdev)
        int data1_pol  = dssdev->phy.dsi.data1_pol;
        int data2_pol  = dssdev->phy.dsi.data2_pol;
 
-       r = dsi_read_reg(DSI_COMPLEXIO_CFG1);
+       r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1);
        r = FLD_MOD(r, clk_lane, 2, 0);
        r = FLD_MOD(r, clk_pol, 3, 3);
        r = FLD_MOD(r, data1_lane, 6, 4);
        r = FLD_MOD(r, data1_pol, 7, 7);
        r = FLD_MOD(r, data2_lane, 10, 8);
        r = FLD_MOD(r, data2_pol, 11, 11);
-       dsi_write_reg(DSI_COMPLEXIO_CFG1, r);
+       if (num_data_lanes_dssdev > 2) {
+               int data3_lane  = dssdev->phy.dsi.data3_lane;
+               int data3_pol  = dssdev->phy.dsi.data3_pol;
+
+               r = FLD_MOD(r, data3_lane, 14, 12);
+               r = FLD_MOD(r, data3_pol, 15, 15);
+       }
+       if (num_data_lanes_dssdev > 3) {
+               int data4_lane  = dssdev->phy.dsi.data4_lane;
+               int data4_pol  = dssdev->phy.dsi.data4_pol;
+
+               r = FLD_MOD(r, data4_lane, 18, 16);
+               r = FLD_MOD(r, data4_pol, 19, 19);
+       }
+       dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r);
 
        /* The configuration of the DSI complex I/O (number of data lanes,
           position, differential order) should not be changed while
@@ -1776,27 +2115,31 @@ static void dsi_complexio_config(struct omap_dss_device *dssdev)
           DSI complex I/O configuration is unknown. */
 
        /*
-       REG_FLD_MOD(DSI_CTRL, 1, 0, 0);
-       REG_FLD_MOD(DSI_CTRL, 0, 0, 0);
-       REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20);
-       REG_FLD_MOD(DSI_CTRL, 1, 0, 0);
+       REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0);
+       REG_FLD_MOD(dsidev, DSI_CTRL, 0, 0, 0);
+       REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20);
+       REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0);
        */
 }
 
-static inline unsigned ns2ddr(unsigned ns)
+static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
        /* convert time in ns to ddr ticks, rounding up */
-       unsigned long ddr_clk = dsi.current_cinfo.clkin4ddr / 4;
+       unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4;
        return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000;
 }
 
-static inline unsigned ddr2ns(unsigned ddr)
+static inline unsigned ddr2ns(struct platform_device *dsidev, unsigned ddr)
 {
-       unsigned long ddr_clk = dsi.current_cinfo.clkin4ddr / 4;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4;
        return ddr * 1000 * 1000 / (ddr_clk / 1000);
 }
 
-static void dsi_complexio_timings(void)
+static void dsi_cio_timings(struct platform_device *dsidev)
 {
        u32 r;
        u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit;
@@ -1808,139 +2151,323 @@ static void dsi_complexio_timings(void)
        /* 1 * DDR_CLK = 2 * UI */
 
        /* min 40ns + 4*UI      max 85ns + 6*UI */
-       ths_prepare = ns2ddr(70) + 2;
+       ths_prepare = ns2ddr(dsidev, 70) + 2;
 
        /* min 145ns + 10*UI */
-       ths_prepare_ths_zero = ns2ddr(175) + 2;
+       ths_prepare_ths_zero = ns2ddr(dsidev, 175) + 2;
 
        /* min max(8*UI, 60ns+4*UI) */
-       ths_trail = ns2ddr(60) + 5;
+       ths_trail = ns2ddr(dsidev, 60) + 5;
 
        /* min 100ns */
-       ths_exit = ns2ddr(145);
+       ths_exit = ns2ddr(dsidev, 145);
 
        /* tlpx min 50n */
-       tlpx_half = ns2ddr(25);
+       tlpx_half = ns2ddr(dsidev, 25);
 
        /* min 60ns */
-       tclk_trail = ns2ddr(60) + 2;
+       tclk_trail = ns2ddr(dsidev, 60) + 2;
 
        /* min 38ns, max 95ns */
-       tclk_prepare = ns2ddr(65);
+       tclk_prepare = ns2ddr(dsidev, 65);
 
        /* min tclk-prepare + tclk-zero = 300ns */
-       tclk_zero = ns2ddr(260);
+       tclk_zero = ns2ddr(dsidev, 260);
 
        DSSDBG("ths_prepare %u (%uns), ths_prepare_ths_zero %u (%uns)\n",
-               ths_prepare, ddr2ns(ths_prepare),
-               ths_prepare_ths_zero, ddr2ns(ths_prepare_ths_zero));
+               ths_prepare, ddr2ns(dsidev, ths_prepare),
+               ths_prepare_ths_zero, ddr2ns(dsidev, ths_prepare_ths_zero));
        DSSDBG("ths_trail %u (%uns), ths_exit %u (%uns)\n",
-                       ths_trail, ddr2ns(ths_trail),
-                       ths_exit, ddr2ns(ths_exit));
+                       ths_trail, ddr2ns(dsidev, ths_trail),
+                       ths_exit, ddr2ns(dsidev, ths_exit));
 
        DSSDBG("tlpx_half %u (%uns), tclk_trail %u (%uns), "
                        "tclk_zero %u (%uns)\n",
-                       tlpx_half, ddr2ns(tlpx_half),
-                       tclk_trail, ddr2ns(tclk_trail),
-                       tclk_zero, ddr2ns(tclk_zero));
+                       tlpx_half, ddr2ns(dsidev, tlpx_half),
+                       tclk_trail, ddr2ns(dsidev, tclk_trail),
+                       tclk_zero, ddr2ns(dsidev, tclk_zero));
        DSSDBG("tclk_prepare %u (%uns)\n",
-                       tclk_prepare, ddr2ns(tclk_prepare));
+                       tclk_prepare, ddr2ns(dsidev, tclk_prepare));
 
        /* program timings */
 
-       r = dsi_read_reg(DSI_DSIPHY_CFG0);
+       r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
        r = FLD_MOD(r, ths_prepare, 31, 24);
        r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16);
        r = FLD_MOD(r, ths_trail, 15, 8);
        r = FLD_MOD(r, ths_exit, 7, 0);
-       dsi_write_reg(DSI_DSIPHY_CFG0, r);
+       dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r);
 
-       r = dsi_read_reg(DSI_DSIPHY_CFG1);
+       r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
        r = FLD_MOD(r, tlpx_half, 22, 16);
        r = FLD_MOD(r, tclk_trail, 15, 8);
        r = FLD_MOD(r, tclk_zero, 7, 0);
-       dsi_write_reg(DSI_DSIPHY_CFG1, r);
+       dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r);
 
-       r = dsi_read_reg(DSI_DSIPHY_CFG2);
+       r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
        r = FLD_MOD(r, tclk_prepare, 7, 0);
-       dsi_write_reg(DSI_DSIPHY_CFG2, r);
+       dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r);
 }
 
+static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev,
+               enum dsi_lane lanes)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       int clk_lane   = dssdev->phy.dsi.clk_lane;
+       int data1_lane = dssdev->phy.dsi.data1_lane;
+       int data2_lane = dssdev->phy.dsi.data2_lane;
+       int data3_lane = dssdev->phy.dsi.data3_lane;
+       int data4_lane = dssdev->phy.dsi.data4_lane;
+       int clk_pol    = dssdev->phy.dsi.clk_pol;
+       int data1_pol  = dssdev->phy.dsi.data1_pol;
+       int data2_pol  = dssdev->phy.dsi.data2_pol;
+       int data3_pol  = dssdev->phy.dsi.data3_pol;
+       int data4_pol  = dssdev->phy.dsi.data4_pol;
+
+       u32 l = 0;
+       u8 lptxscp_start = dsi->num_data_lanes == 2 ? 22 : 26;
+
+       if (lanes & DSI_CLK_P)
+               l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 0 : 1));
+       if (lanes & DSI_CLK_N)
+               l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 1 : 0));
+
+       if (lanes & DSI_DATA1_P)
+               l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 0 : 1));
+       if (lanes & DSI_DATA1_N)
+               l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 1 : 0));
+
+       if (lanes & DSI_DATA2_P)
+               l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 0 : 1));
+       if (lanes & DSI_DATA2_N)
+               l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 1 : 0));
+
+       if (lanes & DSI_DATA3_P)
+               l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 0 : 1));
+       if (lanes & DSI_DATA3_N)
+               l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 1 : 0));
+
+       if (lanes & DSI_DATA4_P)
+               l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 0 : 1));
+       if (lanes & DSI_DATA4_N)
+               l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 1 : 0));
+       /*
+        * Bits in REGLPTXSCPDAT4TO0DXDY:
+        * 17: DY0 18: DX0
+        * 19: DY1 20: DX1
+        * 21: DY2 22: DX2
+        * 23: DY3 24: DX3
+        * 25: DY4 26: DX4
+        */
+
+       /* Set the lane override configuration */
+
+       /* REGLPTXSCPDAT4TO0DXDY */
+       REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, l, lptxscp_start, 17);
 
-static int dsi_complexio_init(struct omap_dss_device *dssdev)
+       /* Enable lane override */
+
+       /* ENLPTXSCPDAT */
+       REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 1, 27, 27);
+}
+
+static void dsi_cio_disable_lane_override(struct platform_device *dsidev)
 {
-       int r = 0;
+       /* Disable lane override */
+       REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 27, 27); /* ENLPTXSCPDAT */
+       /* Reset the lane override configuration */
+       /* REGLPTXSCPDAT4TO0DXDY */
+       REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17);
+}
+
+static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       int t;
+       int bits[3];
+       bool in_use[3];
+
+       if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) {
+               bits[0] = 28;
+               bits[1] = 27;
+               bits[2] = 26;
+       } else {
+               bits[0] = 24;
+               bits[1] = 25;
+               bits[2] = 26;
+       }
+
+       in_use[0] = false;
+       in_use[1] = false;
+       in_use[2] = false;
+
+       if (dssdev->phy.dsi.clk_lane != 0)
+               in_use[dssdev->phy.dsi.clk_lane - 1] = true;
+       if (dssdev->phy.dsi.data1_lane != 0)
+               in_use[dssdev->phy.dsi.data1_lane - 1] = true;
+       if (dssdev->phy.dsi.data2_lane != 0)
+               in_use[dssdev->phy.dsi.data2_lane - 1] = true;
+
+       t = 100000;
+       while (true) {
+               u32 l;
+               int i;
+               int ok;
+
+               l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
+
+               ok = 0;
+               for (i = 0; i < 3; ++i) {
+                       if (!in_use[i] || (l & (1 << bits[i])))
+                               ok++;
+               }
+
+               if (ok == 3)
+                       break;
+
+               if (--t == 0) {
+                       for (i = 0; i < 3; ++i) {
+                               if (!in_use[i] || (l & (1 << bits[i])))
+                                       continue;
+
+                               DSSERR("CIO TXCLKESC%d domain not coming " \
+                                               "out of reset\n", i);
+                       }
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+static int dsi_cio_init(struct omap_dss_device *dssdev)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       int r;
+       int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev);
+       u32 l;
 
-       DSSDBG("dsi_complexio_init\n");
+       DSSDBGF();
 
-       /* CIO_CLK_ICG, enable L3 clk to CIO */
-       REG_FLD_MOD(DSI_CLK_CTRL, 1, 14, 14);
+       if (dsi->dsi_mux_pads)
+               dsi->dsi_mux_pads(true);
+
+       dsi_enable_scp_clk(dsidev);
 
        /* A dummy read using the SCP interface to any DSIPHY register is
         * required after DSIPHY reset to complete the reset of the DSI complex
         * I/O. */
-       dsi_read_reg(DSI_DSIPHY_CFG5);
+       dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
 
-       if (wait_for_bit_change(DSI_DSIPHY_CFG5, 30, 1) != 1) {
-               DSSERR("ComplexIO PHY not coming out of reset.\n");
-               r = -ENODEV;
-               goto err;
+       if (wait_for_bit_change(dsidev, DSI_DSIPHY_CFG5, 30, 1) != 1) {
+               DSSERR("CIO SCP Clock domain not coming out of reset.\n");
+               r = -EIO;
+               goto err_scp_clk_dom;
        }
 
-       dsi_complexio_config(dssdev);
+       dsi_set_lane_config(dssdev);
+
+       /* set TX STOP MODE timer to maximum for this operation */
+       l = dsi_read_reg(dsidev, DSI_TIMING1);
+       l = FLD_MOD(l, 1, 15, 15);      /* FORCE_TX_STOP_MODE_IO */
+       l = FLD_MOD(l, 1, 14, 14);      /* STOP_STATE_X16_IO */
+       l = FLD_MOD(l, 1, 13, 13);      /* STOP_STATE_X4_IO */
+       l = FLD_MOD(l, 0x1fff, 12, 0);  /* STOP_STATE_COUNTER_IO */
+       dsi_write_reg(dsidev, DSI_TIMING1, l);
 
-       r = dsi_complexio_power(DSI_COMPLEXIO_POWER_ON);
+       if (dsi->ulps_enabled) {
+               u32 lane_mask = DSI_CLK_P | DSI_DATA1_P | DSI_DATA2_P;
 
+               DSSDBG("manual ulps exit\n");
+
+               /* ULPS is exited by Mark-1 state for 1ms, followed by
+                * stop state. DSS HW cannot do this via the normal
+                * ULPS exit sequence, as after reset the DSS HW thinks
+                * that we are not in ULPS mode, and refuses to send the
+                * sequence. So we need to send the ULPS exit sequence
+                * manually.
+                */
+
+               if (num_data_lanes_dssdev > 2)
+                       lane_mask |= DSI_DATA3_P;
+
+               if (num_data_lanes_dssdev > 3)
+                       lane_mask |= DSI_DATA4_P;
+
+               dsi_cio_enable_lane_override(dssdev, lane_mask);
+       }
+
+       r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON);
        if (r)
-               goto err;
+               goto err_cio_pwr;
 
-       if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
-               DSSERR("ComplexIO not coming out of reset.\n");
+       if (wait_for_bit_change(dsidev, DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
+               DSSERR("CIO PWR clock domain not coming out of reset.\n");
                r = -ENODEV;
-               goto err;
+               goto err_cio_pwr_dom;
        }
 
-       if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 21, 1) != 1) {
-               DSSERR("ComplexIO LDO power down.\n");
-               r = -ENODEV;
-               goto err;
+       dsi_if_enable(dsidev, true);
+       dsi_if_enable(dsidev, false);
+       REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
+
+       r = dsi_cio_wait_tx_clk_esc_reset(dssdev);
+       if (r)
+               goto err_tx_clk_esc_rst;
+
+       if (dsi->ulps_enabled) {
+               /* Keep Mark-1 state for 1ms (as per DSI spec) */
+               ktime_t wait = ns_to_ktime(1000 * 1000);
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
+
+               /* Disable the override. The lanes should be set to Mark-11
+                * state by the HW */
+               dsi_cio_disable_lane_override(dsidev);
        }
 
-       dsi_complexio_timings();
+       /* FORCE_TX_STOP_MODE_IO */
+       REG_FLD_MOD(dsidev, DSI_TIMING1, 0, 15, 15);
 
-       /*
-          The configuration of the DSI complex I/O (number of data lanes,
-          position, differential order) should not be changed while
-          DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. For the
-          hardware to recognize a new configuration of the complex I/O (done
-          in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to follow
-          this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1, next
-          reset the DSS.DSI_CTRL[0] IF_EN to 0, then set DSS.DSI_CLK_CTRL[20]
-          LP_CLK_ENABLE to 1, and finally, set again the DSS.DSI_CTRL[0] IF_EN
-          bit to 1. If the sequence is not followed, the DSi complex I/O
-          configuration is undetermined.
-          */
-       dsi_if_enable(1);
-       dsi_if_enable(0);
-       REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
-       dsi_if_enable(1);
-       dsi_if_enable(0);
+       dsi_cio_timings(dsidev);
+
+       dsi->ulps_enabled = false;
 
        DSSDBG("CIO init done\n");
-err:
+
+       return 0;
+
+err_tx_clk_esc_rst:
+       REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 20, 20); /* LP_CLK_ENABLE */
+err_cio_pwr_dom:
+       dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
+err_cio_pwr:
+       if (dsi->ulps_enabled)
+               dsi_cio_disable_lane_override(dsidev);
+err_scp_clk_dom:
+       dsi_disable_scp_clk(dsidev);
+       if (dsi->dsi_mux_pads)
+               dsi->dsi_mux_pads(false);
        return r;
 }
 
-static void dsi_complexio_uninit(void)
+static void dsi_cio_uninit(struct platform_device *dsidev)
 {
-       dsi_complexio_power(DSI_COMPLEXIO_POWER_OFF);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
+       dsi_disable_scp_clk(dsidev);
+       if (dsi->dsi_mux_pads)
+               dsi->dsi_mux_pads(false);
 }
 
-static int _dsi_wait_reset(void)
+static int _dsi_wait_reset(struct platform_device *dsidev)
 {
        int t = 0;
 
-       while (REG_GET(DSI_SYSSTATUS, 0, 0) == 0) {
+       while (REG_GET(dsidev, DSI_SYSSTATUS, 0, 0) == 0) {
                if (++t > 5) {
                        DSSERR("soft reset failed\n");
                        return -ENODEV;
@@ -1951,28 +2478,30 @@ static int _dsi_wait_reset(void)
        return 0;
 }
 
-static int _dsi_reset(void)
+static int _dsi_reset(struct platform_device *dsidev)
 {
        /* Soft reset */
-       REG_FLD_MOD(DSI_SYSCONFIG, 1, 1, 1);
-       return _dsi_wait_reset();
+       REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 1, 1);
+       return _dsi_wait_reset(dsidev);
 }
 
-static void dsi_config_tx_fifo(enum fifo_size size1, enum fifo_size size2,
+static void dsi_config_tx_fifo(struct platform_device *dsidev,
+               enum fifo_size size1, enum fifo_size size2,
                enum fifo_size size3, enum fifo_size size4)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        u32 r = 0;
        int add = 0;
        int i;
 
-       dsi.vc[0].fifo_size = size1;
-       dsi.vc[1].fifo_size = size2;
-       dsi.vc[2].fifo_size = size3;
-       dsi.vc[3].fifo_size = size4;
+       dsi->vc[0].fifo_size = size1;
+       dsi->vc[1].fifo_size = size2;
+       dsi->vc[2].fifo_size = size3;
+       dsi->vc[3].fifo_size = size4;
 
        for (i = 0; i < 4; i++) {
                u8 v;
-               int size = dsi.vc[i].fifo_size;
+               int size = dsi->vc[i].fifo_size;
 
                if (add + size > 4) {
                        DSSERR("Illegal FIFO configuration\n");
@@ -1985,24 +2514,26 @@ static void dsi_config_tx_fifo(enum fifo_size size1, enum fifo_size size2,
                add += size;
        }
 
-       dsi_write_reg(DSI_TX_FIFO_VC_SIZE, r);
+       dsi_write_reg(dsidev, DSI_TX_FIFO_VC_SIZE, r);
 }
 
-static void dsi_config_rx_fifo(enum fifo_size size1, enum fifo_size size2,
+static void dsi_config_rx_fifo(struct platform_device *dsidev,
+               enum fifo_size size1, enum fifo_size size2,
                enum fifo_size size3, enum fifo_size size4)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        u32 r = 0;
        int add = 0;
        int i;
 
-       dsi.vc[0].fifo_size = size1;
-       dsi.vc[1].fifo_size = size2;
-       dsi.vc[2].fifo_size = size3;
-       dsi.vc[3].fifo_size = size4;
+       dsi->vc[0].fifo_size = size1;
+       dsi->vc[1].fifo_size = size2;
+       dsi->vc[2].fifo_size = size3;
+       dsi->vc[3].fifo_size = size4;
 
        for (i = 0; i < 4; i++) {
                u8 v;
-               int size = dsi.vc[i].fifo_size;
+               int size = dsi->vc[i].fifo_size;
 
                if (add + size > 4) {
                        DSSERR("Illegal FIFO configuration\n");
@@ -2015,18 +2546,18 @@ static void dsi_config_rx_fifo(enum fifo_size size1, enum fifo_size size2,
                add += size;
        }
 
-       dsi_write_reg(DSI_RX_FIFO_VC_SIZE, r);
+       dsi_write_reg(dsidev, DSI_RX_FIFO_VC_SIZE, r);
 }
 
-static int dsi_force_tx_stop_mode_io(void)
+static int dsi_force_tx_stop_mode_io(struct platform_device *dsidev)
 {
        u32 r;
 
-       r = dsi_read_reg(DSI_TIMING1);
+       r = dsi_read_reg(dsidev, DSI_TIMING1);
        r = FLD_MOD(r, 1, 15, 15);      /* FORCE_TX_STOP_MODE_IO */
-       dsi_write_reg(DSI_TIMING1, r);
+       dsi_write_reg(dsidev, DSI_TIMING1, r);
 
-       if (wait_for_bit_change(DSI_TIMING1, 15, 0) != 0) {
+       if (wait_for_bit_change(dsidev, DSI_TIMING1, 15, 0) != 0) {
                DSSERR("TX_STOP bit not going down\n");
                return -EIO;
        }
@@ -2034,16 +2565,135 @@ static int dsi_force_tx_stop_mode_io(void)
        return 0;
 }
 
-static int dsi_vc_enable(int channel, bool enable)
+static bool dsi_vc_is_enabled(struct platform_device *dsidev, int channel)
+{
+       return REG_GET(dsidev, DSI_VC_CTRL(channel), 0, 0);
+}
+
+static void dsi_packet_sent_handler_vp(void *data, u32 mask)
+{
+       struct dsi_packet_sent_handler_data *vp_data =
+               (struct dsi_packet_sent_handler_data *) data;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(vp_data->dsidev);
+       const int channel = dsi->update_channel;
+       u8 bit = dsi->te_enabled ? 30 : 31;
+
+       if (REG_GET(vp_data->dsidev, DSI_VC_TE(channel), bit, bit) == 0)
+               complete(vp_data->completion);
+}
+
+static int dsi_sync_vc_vp(struct platform_device *dsidev, int channel)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       DECLARE_COMPLETION_ONSTACK(completion);
+       struct dsi_packet_sent_handler_data vp_data = { dsidev, &completion };
+       int r = 0;
+       u8 bit;
+
+       bit = dsi->te_enabled ? 30 : 31;
+
+       r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
+               &vp_data, DSI_VC_IRQ_PACKET_SENT);
+       if (r)
+               goto err0;
+
+       /* Wait for completion only if TE_EN/TE_START is still set */
+       if (REG_GET(dsidev, DSI_VC_TE(channel), bit, bit)) {
+               if (wait_for_completion_timeout(&completion,
+                               msecs_to_jiffies(10)) == 0) {
+                       DSSERR("Failed to complete previous frame transfer\n");
+                       r = -EIO;
+                       goto err1;
+               }
+       }
+
+       dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
+               &vp_data, DSI_VC_IRQ_PACKET_SENT);
+
+       return 0;
+err1:
+       dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
+               &vp_data, DSI_VC_IRQ_PACKET_SENT);
+err0:
+       return r;
+}
+
+static void dsi_packet_sent_handler_l4(void *data, u32 mask)
+{
+       struct dsi_packet_sent_handler_data *l4_data =
+               (struct dsi_packet_sent_handler_data *) data;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(l4_data->dsidev);
+       const int channel = dsi->update_channel;
+
+       if (REG_GET(l4_data->dsidev, DSI_VC_CTRL(channel), 5, 5) == 0)
+               complete(l4_data->completion);
+}
+
+static int dsi_sync_vc_l4(struct platform_device *dsidev, int channel)
+{
+       DECLARE_COMPLETION_ONSTACK(completion);
+       struct dsi_packet_sent_handler_data l4_data = { dsidev, &completion };
+       int r = 0;
+
+       r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
+               &l4_data, DSI_VC_IRQ_PACKET_SENT);
+       if (r)
+               goto err0;
+
+       /* Wait for completion only if TX_FIFO_NOT_EMPTY is still set */
+       if (REG_GET(dsidev, DSI_VC_CTRL(channel), 5, 5)) {
+               if (wait_for_completion_timeout(&completion,
+                               msecs_to_jiffies(10)) == 0) {
+                       DSSERR("Failed to complete previous l4 transfer\n");
+                       r = -EIO;
+                       goto err1;
+               }
+       }
+
+       dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
+               &l4_data, DSI_VC_IRQ_PACKET_SENT);
+
+       return 0;
+err1:
+       dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
+               &l4_data, DSI_VC_IRQ_PACKET_SENT);
+err0:
+       return r;
+}
+
+static int dsi_sync_vc(struct platform_device *dsidev, int channel)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       WARN_ON(!dsi_bus_is_locked(dsidev));
+
+       WARN_ON(in_interrupt());
+
+       if (!dsi_vc_is_enabled(dsidev, channel))
+               return 0;
+
+       switch (dsi->vc[channel].mode) {
+       case DSI_VC_MODE_VP:
+               return dsi_sync_vc_vp(dsidev, channel);
+       case DSI_VC_MODE_L4:
+               return dsi_sync_vc_l4(dsidev, channel);
+       default:
+               BUG();
+       }
+}
+
+static int dsi_vc_enable(struct platform_device *dsidev, int channel,
+               bool enable)
 {
        DSSDBG("dsi_vc_enable channel %d, enable %d\n",
                        channel, enable);
 
        enable = enable ? 1 : 0;
 
-       REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 0, 0);
+       REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 0, 0);
 
-       if (wait_for_bit_change(DSI_VC_CTRL(channel), 0, enable) != enable) {
+       if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel),
+               0, enable) != enable) {
                        DSSERR("Failed to set dsi_vc_enable to %d\n", enable);
                        return -EIO;
        }
@@ -2051,13 +2701,13 @@ static int dsi_vc_enable(int channel, bool enable)
        return 0;
 }
 
-static void dsi_vc_initial_config(int channel)
+static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
 {
        u32 r;
 
        DSSDBGF("%d", channel);
 
-       r = dsi_read_reg(DSI_VC_CTRL(channel));
+       r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel));
 
        if (FLD_GET(r, 15, 15)) /* VC_BUSY */
                DSSERR("VC(%d) busy when trying to configure it!\n",
@@ -2070,85 +2720,107 @@ static void dsi_vc_initial_config(int channel)
        r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */
        r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */
        r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */
+       if (dss_has_feature(FEAT_DSI_VC_OCP_WIDTH))
+               r = FLD_MOD(r, 3, 11, 10);      /* OCP_WIDTH = 32 bit */
 
        r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */
        r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
 
-       dsi_write_reg(DSI_VC_CTRL(channel), r);
+       dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r);
 }
 
-static int dsi_vc_config_l4(int channel)
+static int dsi_vc_config_l4(struct platform_device *dsidev, int channel)
 {
-       if (dsi.vc[channel].mode == DSI_VC_MODE_L4)
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       if (dsi->vc[channel].mode == DSI_VC_MODE_L4)
                return 0;
 
        DSSDBGF("%d", channel);
 
-       dsi_vc_enable(channel, 0);
+       dsi_sync_vc(dsidev, channel);
+
+       dsi_vc_enable(dsidev, channel, 0);
 
        /* VC_BUSY */
-       if (wait_for_bit_change(DSI_VC_CTRL(channel), 15, 0) != 0) {
+       if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) {
                DSSERR("vc(%d) busy when trying to config for L4\n", channel);
                return -EIO;
        }
 
-       REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */
+       REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */
+
+       /* DCS_CMD_ENABLE */
+       if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC))
+               REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 30, 30);
 
-       dsi_vc_enable(channel, 1);
+       dsi_vc_enable(dsidev, channel, 1);
 
-       dsi.vc[channel].mode = DSI_VC_MODE_L4;
+       dsi->vc[channel].mode = DSI_VC_MODE_L4;
 
        return 0;
 }
 
-static int dsi_vc_config_vp(int channel)
+static int dsi_vc_config_vp(struct platform_device *dsidev, int channel)
 {
-       if (dsi.vc[channel].mode == DSI_VC_MODE_VP)
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       if (dsi->vc[channel].mode == DSI_VC_MODE_VP)
                return 0;
 
        DSSDBGF("%d", channel);
 
-       dsi_vc_enable(channel, 0);
+       dsi_sync_vc(dsidev, channel);
+
+       dsi_vc_enable(dsidev, channel, 0);
 
        /* VC_BUSY */
-       if (wait_for_bit_change(DSI_VC_CTRL(channel), 15, 0) != 0) {
+       if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) {
                DSSERR("vc(%d) busy when trying to config for VP\n", channel);
                return -EIO;
        }
 
-       REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 1, 1); /* SOURCE, 1 = video port */
+       /* SOURCE, 1 = video port */
+       REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 1, 1);
+
+       /* DCS_CMD_ENABLE */
+       if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC))
+               REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 30, 30);
 
-       dsi_vc_enable(channel, 1);
+       dsi_vc_enable(dsidev, channel, 1);
 
-       dsi.vc[channel].mode = DSI_VC_MODE_VP;
+       dsi->vc[channel].mode = DSI_VC_MODE_VP;
 
        return 0;
 }
 
 
-void omapdss_dsi_vc_enable_hs(int channel, bool enable)
+void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
+               bool enable)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+
        DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
 
-       WARN_ON(!dsi_bus_is_locked());
+       WARN_ON(!dsi_bus_is_locked(dsidev));
 
-       dsi_vc_enable(channel, 0);
-       dsi_if_enable(0);
+       dsi_vc_enable(dsidev, channel, 0);
+       dsi_if_enable(dsidev, 0);
 
-       REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 9, 9);
+       REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 9, 9);
 
-       dsi_vc_enable(channel, 1);
-       dsi_if_enable(1);
+       dsi_vc_enable(dsidev, channel, 1);
+       dsi_if_enable(dsidev, 1);
 
-       dsi_force_tx_stop_mode_io();
+       dsi_force_tx_stop_mode_io(dsidev);
 }
 EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs);
 
-static void dsi_vc_flush_long_data(int channel)
+static void dsi_vc_flush_long_data(struct platform_device *dsidev, int channel)
 {
-       while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
+       while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
                u32 val;
-               val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
+               val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
                DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 %#02x\n",
                                (val >> 0) & 0xff,
                                (val >> 8) & 0xff,
@@ -2194,13 +2866,14 @@ static void dsi_show_rx_ack_with_err(u16 err)
                DSSERR("\t\tDSI Protocol Violation\n");
 }
 
-static u16 dsi_vc_flush_receive_data(int channel)
+static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev,
+               int channel)
 {
        /* RX_FIFO_NOT_EMPTY */
-       while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
+       while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
                u32 val;
                u8 dt;
-               val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
+               val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
                DSSERR("\trawval %#08x\n", val);
                dt = FLD_GET(val, 5, 0);
                if (dt == DSI_DT_RX_ACK_WITH_ERR) {
@@ -2215,7 +2888,7 @@ static u16 dsi_vc_flush_receive_data(int channel)
                } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
                        DSSERR("\tDCS long response, len %d\n",
                                        FLD_GET(val, 23, 8));
-                       dsi_vc_flush_long_data(channel);
+                       dsi_vc_flush_long_data(dsidev, channel);
                } else {
                        DSSERR("\tunknown datatype 0x%02x\n", dt);
                }
@@ -2223,40 +2896,44 @@ static u16 dsi_vc_flush_receive_data(int channel)
        return 0;
 }
 
-static int dsi_vc_send_bta(int channel)
+static int dsi_vc_send_bta(struct platform_device *dsidev, int channel)
 {
-       if (dsi.debug_write || dsi.debug_read)
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       if (dsi->debug_write || dsi->debug_read)
                DSSDBG("dsi_vc_send_bta %d\n", channel);
 
-       WARN_ON(!dsi_bus_is_locked());
+       WARN_ON(!dsi_bus_is_locked(dsidev));
 
-       if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {    /* RX_FIFO_NOT_EMPTY */
+       /* RX_FIFO_NOT_EMPTY */
+       if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
                DSSERR("rx fifo not empty when sending BTA, dumping data:\n");
-               dsi_vc_flush_receive_data(channel);
+               dsi_vc_flush_receive_data(dsidev, channel);
        }
 
-       REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
+       REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
 
        return 0;
 }
 
-int dsi_vc_send_bta_sync(int channel)
+int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        DECLARE_COMPLETION_ONSTACK(completion);
        int r = 0;
        u32 err;
 
-       r = dsi_register_isr_vc(channel, dsi_completion_handler,
+       r = dsi_register_isr_vc(dsidev, channel, dsi_completion_handler,
                        &completion, DSI_VC_IRQ_BTA);
        if (r)
                goto err0;
 
-       r = dsi_register_isr(dsi_completion_handler, &completion,
+       r = dsi_register_isr(dsidev, dsi_completion_handler, &completion,
                        DSI_IRQ_ERROR_MASK);
        if (r)
                goto err1;
 
-       r = dsi_vc_send_bta(channel);
+       r = dsi_vc_send_bta(dsidev, channel);
        if (r)
                goto err2;
 
@@ -2267,41 +2944,42 @@ int dsi_vc_send_bta_sync(int channel)
                goto err2;
        }
 
-       err = dsi_get_errors();
+       err = dsi_get_errors(dsidev);
        if (err) {
                DSSERR("Error while sending BTA: %x\n", err);
                r = -EIO;
                goto err2;
        }
 err2:
-       dsi_unregister_isr(dsi_completion_handler, &completion,
+       dsi_unregister_isr(dsidev, dsi_completion_handler, &completion,
                        DSI_IRQ_ERROR_MASK);
 err1:
-       dsi_unregister_isr_vc(channel, dsi_completion_handler,
+       dsi_unregister_isr_vc(dsidev, channel, dsi_completion_handler,
                        &completion, DSI_VC_IRQ_BTA);
 err0:
        return r;
 }
 EXPORT_SYMBOL(dsi_vc_send_bta_sync);
 
-static inline void dsi_vc_write_long_header(int channel, u8 data_type,
-               u16 len, u8 ecc)
+static inline void dsi_vc_write_long_header(struct platform_device *dsidev,
+               int channel, u8 data_type, u16 len, u8 ecc)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        u32 val;
        u8 data_id;
 
-       WARN_ON(!dsi_bus_is_locked());
+       WARN_ON(!dsi_bus_is_locked(dsidev));
 
-       data_id = data_type | dsi.vc[channel].vc_id << 6;
+       data_id = data_type | dsi->vc[channel].vc_id << 6;
 
        val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
                FLD_VAL(ecc, 31, 24);
 
-       dsi_write_reg(DSI_VC_LONG_PACKET_HEADER(channel), val);
+       dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_HEADER(channel), val);
 }
 
-static inline void dsi_vc_write_long_payload(int channel,
-               u8 b1, u8 b2, u8 b3, u8 b4)
+static inline void dsi_vc_write_long_payload(struct platform_device *dsidev,
+               int channel, u8 b1, u8 b2, u8 b3, u8 b4)
 {
        u32 val;
 
@@ -2310,34 +2988,35 @@ static inline void dsi_vc_write_long_payload(int channel,
 /*     DSSDBG("\twriting %02x, %02x, %02x, %02x (%#010x)\n",
                        b1, b2, b3, b4, val); */
 
-       dsi_write_reg(DSI_VC_LONG_PACKET_PAYLOAD(channel), val);
+       dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_PAYLOAD(channel), val);
 }
 
-static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len,
-               u8 ecc)
+static int dsi_vc_send_long(struct platform_device *dsidev, int channel,
+               u8 data_type, u8 *data, u16 len, u8 ecc)
 {
        /*u32 val; */
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int i;
        u8 *p;
        int r = 0;
        u8 b1, b2, b3, b4;
 
-       if (dsi.debug_write)
+       if (dsi->debug_write)
                DSSDBG("dsi_vc_send_long, %d bytes\n", len);
 
        /* len + header */
-       if (dsi.vc[channel].fifo_size * 32 * 4 < len + 4) {
+       if (dsi->vc[channel].fifo_size * 32 * 4 < len + 4) {
                DSSERR("unable to send long packet: packet too long.\n");
                return -EINVAL;
        }
 
-       dsi_vc_config_l4(channel);
+       dsi_vc_config_l4(dsidev, channel);
 
-       dsi_vc_write_long_header(channel, data_type, len, ecc);
+       dsi_vc_write_long_header(dsidev, channel, data_type, len, ecc);
 
        p = data;
        for (i = 0; i < len >> 2; i++) {
-               if (dsi.debug_write)
+               if (dsi->debug_write)
                        DSSDBG("\tsending full packet %d\n", i);
 
                b1 = *p++;
@@ -2345,14 +3024,14 @@ static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len,
                b3 = *p++;
                b4 = *p++;
 
-               dsi_vc_write_long_payload(channel, b1, b2, b3, b4);
+               dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, b4);
        }
 
        i = len % 4;
        if (i) {
                b1 = 0; b2 = 0; b3 = 0;
 
-               if (dsi.debug_write)
+               if (dsi->debug_write)
                        DSSDBG("\tsending remainder bytes %d\n", i);
 
                switch (i) {
@@ -2370,62 +3049,69 @@ static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len,
                        break;
                }
 
-               dsi_vc_write_long_payload(channel, b1, b2, b3, 0);
+               dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, 0);
        }
 
        return r;
 }
 
-static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc)
+static int dsi_vc_send_short(struct platform_device *dsidev, int channel,
+               u8 data_type, u16 data, u8 ecc)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        u32 r;
        u8 data_id;
 
-       WARN_ON(!dsi_bus_is_locked());
+       WARN_ON(!dsi_bus_is_locked(dsidev));
 
-       if (dsi.debug_write)
+       if (dsi->debug_write)
                DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n",
                                channel,
                                data_type, data & 0xff, (data >> 8) & 0xff);
 
-       dsi_vc_config_l4(channel);
+       dsi_vc_config_l4(dsidev, channel);
 
-       if (FLD_GET(dsi_read_reg(DSI_VC_CTRL(channel)), 16, 16)) {
+       if (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(channel)), 16, 16)) {
                DSSERR("ERROR FIFO FULL, aborting transfer\n");
                return -EINVAL;
        }
 
-       data_id = data_type | dsi.vc[channel].vc_id << 6;
+       data_id = data_type | dsi->vc[channel].vc_id << 6;
 
        r = (data_id << 0) | (data << 8) | (ecc << 24);
 
-       dsi_write_reg(DSI_VC_SHORT_PACKET_HEADER(channel), r);
+       dsi_write_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel), r);
 
        return 0;
 }
 
-int dsi_vc_send_null(int channel)
+int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        u8 nullpkg[] = {0, 0, 0, 0};
-       return dsi_vc_send_long(channel, DSI_DT_NULL_PACKET, nullpkg, 4, 0);
+
+       return dsi_vc_send_long(dsidev, channel, DSI_DT_NULL_PACKET, nullpkg,
+               4, 0);
 }
 EXPORT_SYMBOL(dsi_vc_send_null);
 
-int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len)
+int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
+               u8 *data, int len)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        int r;
 
        BUG_ON(len == 0);
 
        if (len == 1) {
-               r = dsi_vc_send_short(channel, DSI_DT_DCS_SHORT_WRITE_0,
+               r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_SHORT_WRITE_0,
                                data[0], 0);
        } else if (len == 2) {
-               r = dsi_vc_send_short(channel, DSI_DT_DCS_SHORT_WRITE_1,
+               r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_SHORT_WRITE_1,
                                data[0] | (data[1] << 8), 0);
        } else {
                /* 0x39 = DCS Long Write */
-               r = dsi_vc_send_long(channel, DSI_DT_DCS_LONG_WRITE,
+               r = dsi_vc_send_long(dsidev, channel, DSI_DT_DCS_LONG_WRITE,
                                data, len, 0);
        }
 
@@ -2433,21 +3119,24 @@ int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len)
 }
 EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
 
-int dsi_vc_dcs_write(int channel, u8 *data, int len)
+int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
+               int len)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        int r;
 
-       r = dsi_vc_dcs_write_nosync(channel, data, len);
+       r = dsi_vc_dcs_write_nosync(dssdev, channel, data, len);
        if (r)
                goto err;
 
-       r = dsi_vc_send_bta_sync(channel);
+       r = dsi_vc_send_bta_sync(dssdev, channel);
        if (r)
                goto err;
 
-       if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {    /* RX_FIFO_NOT_EMPTY */
+       /* RX_FIFO_NOT_EMPTY */
+       if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
                DSSERR("rx fifo not empty after write, dumping data:\n");
-               dsi_vc_flush_receive_data(channel);
+               dsi_vc_flush_receive_data(dsidev, channel);
                r = -EIO;
                goto err;
        }
@@ -2460,47 +3149,51 @@ err:
 }
 EXPORT_SYMBOL(dsi_vc_dcs_write);
 
-int dsi_vc_dcs_write_0(int channel, u8 dcs_cmd)
+int dsi_vc_dcs_write_0(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd)
 {
-       return dsi_vc_dcs_write(channel, &dcs_cmd, 1);
+       return dsi_vc_dcs_write(dssdev, channel, &dcs_cmd, 1);
 }
 EXPORT_SYMBOL(dsi_vc_dcs_write_0);
 
-int dsi_vc_dcs_write_1(int channel, u8 dcs_cmd, u8 param)
+int dsi_vc_dcs_write_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+               u8 param)
 {
        u8 buf[2];
        buf[0] = dcs_cmd;
        buf[1] = param;
-       return dsi_vc_dcs_write(channel, buf, 2);
+       return dsi_vc_dcs_write(dssdev, channel, buf, 2);
 }
 EXPORT_SYMBOL(dsi_vc_dcs_write_1);
 
-int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
+int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+               u8 *buf, int buflen)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        u32 val;
        u8 dt;
        int r;
 
-       if (dsi.debug_read)
+       if (dsi->debug_read)
                DSSDBG("dsi_vc_dcs_read(ch%d, dcs_cmd %x)\n", channel, dcs_cmd);
 
-       r = dsi_vc_send_short(channel, DSI_DT_DCS_READ, dcs_cmd, 0);
+       r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_READ, dcs_cmd, 0);
        if (r)
                goto err;
 
-       r = dsi_vc_send_bta_sync(channel);
+       r = dsi_vc_send_bta_sync(dssdev, channel);
        if (r)
                goto err;
 
        /* RX_FIFO_NOT_EMPTY */
-       if (REG_GET(DSI_VC_CTRL(channel), 20, 20) == 0) {
+       if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20) == 0) {
                DSSERR("RX fifo empty when trying to read.\n");
                r = -EIO;
                goto err;
        }
 
-       val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
-       if (dsi.debug_read)
+       val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
+       if (dsi->debug_read)
                DSSDBG("\theader: %08x\n", val);
        dt = FLD_GET(val, 5, 0);
        if (dt == DSI_DT_RX_ACK_WITH_ERR) {
@@ -2511,7 +3204,7 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
 
        } else if (dt == DSI_DT_RX_SHORT_READ_1) {
                u8 data = FLD_GET(val, 15, 8);
-               if (dsi.debug_read)
+               if (dsi->debug_read)
                        DSSDBG("\tDCS short response, 1 byte: %02x\n", data);
 
                if (buflen < 1) {
@@ -2524,7 +3217,7 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
                return 1;
        } else if (dt == DSI_DT_RX_SHORT_READ_2) {
                u16 data = FLD_GET(val, 23, 8);
-               if (dsi.debug_read)
+               if (dsi->debug_read)
                        DSSDBG("\tDCS short response, 2 byte: %04x\n", data);
 
                if (buflen < 2) {
@@ -2539,7 +3232,7 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
        } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
                int w;
                int len = FLD_GET(val, 23, 8);
-               if (dsi.debug_read)
+               if (dsi->debug_read)
                        DSSDBG("\tDCS long response, len %d\n", len);
 
                if (len > buflen) {
@@ -2550,8 +3243,9 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
                /* two byte checksum ends the packet, not included in len */
                for (w = 0; w < len + 2;) {
                        int b;
-                       val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
-                       if (dsi.debug_read)
+                       val = dsi_read_reg(dsidev,
+                               DSI_VC_SHORT_PACKET_HEADER(channel));
+                       if (dsi->debug_read)
                                DSSDBG("\t\t%02x %02x %02x %02x\n",
                                                (val >> 0) & 0xff,
                                                (val >> 8) & 0xff,
@@ -2582,11 +3276,12 @@ err:
 }
 EXPORT_SYMBOL(dsi_vc_dcs_read);
 
-int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data)
+int dsi_vc_dcs_read_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+               u8 *data)
 {
        int r;
 
-       r = dsi_vc_dcs_read(channel, dcs_cmd, data, 1);
+       r = dsi_vc_dcs_read(dssdev, channel, dcs_cmd, data, 1);
 
        if (r < 0)
                return r;
@@ -2598,12 +3293,13 @@ int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data)
 }
 EXPORT_SYMBOL(dsi_vc_dcs_read_1);
 
-int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u8 *data1, u8 *data2)
+int dsi_vc_dcs_read_2(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+               u8 *data1, u8 *data2)
 {
        u8 buf[2];
        int r;
 
-       r = dsi_vc_dcs_read(channel, dcs_cmd, buf, 2);
+       r = dsi_vc_dcs_read(dssdev, channel, dcs_cmd, buf, 2);
 
        if (r < 0)
                return r;
@@ -2618,14 +3314,94 @@ int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u8 *data1, u8 *data2)
 }
 EXPORT_SYMBOL(dsi_vc_dcs_read_2);
 
-int dsi_vc_set_max_rx_packet_size(int channel, u16 len)
+int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel,
+               u16 len)
 {
-       return dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE,
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+
+       return dsi_vc_send_short(dsidev, channel, DSI_DT_SET_MAX_RET_PKG_SIZE,
                        len, 0);
 }
 EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size);
 
-static void dsi_set_lp_rx_timeout(unsigned ticks, bool x4, bool x16)
+static int dsi_enter_ulps(struct platform_device *dsidev)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       DECLARE_COMPLETION_ONSTACK(completion);
+       int r;
+
+       DSSDBGF();
+
+       WARN_ON(!dsi_bus_is_locked(dsidev));
+
+       WARN_ON(dsi->ulps_enabled);
+
+       if (dsi->ulps_enabled)
+               return 0;
+
+       if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) {
+               DSSERR("DDR_CLK_ALWAYS_ON enabled when entering ULPS\n");
+               return -EIO;
+       }
+
+       dsi_sync_vc(dsidev, 0);
+       dsi_sync_vc(dsidev, 1);
+       dsi_sync_vc(dsidev, 2);
+       dsi_sync_vc(dsidev, 3);
+
+       dsi_force_tx_stop_mode_io(dsidev);
+
+       dsi_vc_enable(dsidev, 0, false);
+       dsi_vc_enable(dsidev, 1, false);
+       dsi_vc_enable(dsidev, 2, false);
+       dsi_vc_enable(dsidev, 3, false);
+
+       if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 16, 16)) {      /* HS_BUSY */
+               DSSERR("HS busy when enabling ULPS\n");
+               return -EIO;
+       }
+
+       if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 17, 17)) {      /* LP_BUSY */
+               DSSERR("LP busy when enabling ULPS\n");
+               return -EIO;
+       }
+
+       r = dsi_register_isr_cio(dsidev, dsi_completion_handler, &completion,
+                       DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
+       if (r)
+               return r;
+
+       /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */
+       /* LANEx_ULPS_SIG2 */
+       REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (1 << 0) | (1 << 1) | (1 << 2),
+               7, 5);
+
+       if (wait_for_completion_timeout(&completion,
+                               msecs_to_jiffies(1000)) == 0) {
+               DSSERR("ULPS enable timeout\n");
+               r = -EIO;
+               goto err;
+       }
+
+       dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
+                       DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
+
+       dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS);
+
+       dsi_if_enable(dsidev, false);
+
+       dsi->ulps_enabled = true;
+
+       return 0;
+
+err:
+       dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
+                       DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
+       return r;
+}
+
+static void dsi_set_lp_rx_timeout(struct platform_device *dsidev,
+               unsigned ticks, bool x4, bool x16)
 {
        unsigned long fck;
        unsigned long total_ticks;
@@ -2634,14 +3410,14 @@ static void dsi_set_lp_rx_timeout(unsigned ticks, bool x4, bool x16)
        BUG_ON(ticks > 0x1fff);
 
        /* ticks in DSI_FCK */
-       fck = dsi_fclk_rate();
+       fck = dsi_fclk_rate(dsidev);
 
-       r = dsi_read_reg(DSI_TIMING2);
+       r = dsi_read_reg(dsidev, DSI_TIMING2);
        r = FLD_MOD(r, 1, 15, 15);      /* LP_RX_TO */
        r = FLD_MOD(r, x16 ? 1 : 0, 14, 14);    /* LP_RX_TO_X16 */
        r = FLD_MOD(r, x4 ? 1 : 0, 13, 13);     /* LP_RX_TO_X4 */
        r = FLD_MOD(r, ticks, 12, 0);   /* LP_RX_COUNTER */
-       dsi_write_reg(DSI_TIMING2, r);
+       dsi_write_reg(dsidev, DSI_TIMING2, r);
 
        total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
 
@@ -2651,7 +3427,8 @@ static void dsi_set_lp_rx_timeout(unsigned ticks, bool x4, bool x16)
                        (total_ticks * 1000) / (fck / 1000 / 1000));
 }
 
-static void dsi_set_ta_timeout(unsigned ticks, bool x8, bool x16)
+static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks,
+               bool x8, bool x16)
 {
        unsigned long fck;
        unsigned long total_ticks;
@@ -2660,14 +3437,14 @@ static void dsi_set_ta_timeout(unsigned ticks, bool x8, bool x16)
        BUG_ON(ticks > 0x1fff);
 
        /* ticks in DSI_FCK */
-       fck = dsi_fclk_rate();
+       fck = dsi_fclk_rate(dsidev);
 
-       r = dsi_read_reg(DSI_TIMING1);
+       r = dsi_read_reg(dsidev, DSI_TIMING1);
        r = FLD_MOD(r, 1, 31, 31);      /* TA_TO */
        r = FLD_MOD(r, x16 ? 1 : 0, 30, 30);    /* TA_TO_X16 */
        r = FLD_MOD(r, x8 ? 1 : 0, 29, 29);     /* TA_TO_X8 */
        r = FLD_MOD(r, ticks, 28, 16);  /* TA_TO_COUNTER */
-       dsi_write_reg(DSI_TIMING1, r);
+       dsi_write_reg(dsidev, DSI_TIMING1, r);
 
        total_ticks = ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1);
 
@@ -2677,7 +3454,8 @@ static void dsi_set_ta_timeout(unsigned ticks, bool x8, bool x16)
                        (total_ticks * 1000) / (fck / 1000 / 1000));
 }
 
-static void dsi_set_stop_state_counter(unsigned ticks, bool x4, bool x16)
+static void dsi_set_stop_state_counter(struct platform_device *dsidev,
+               unsigned ticks, bool x4, bool x16)
 {
        unsigned long fck;
        unsigned long total_ticks;
@@ -2686,14 +3464,14 @@ static void dsi_set_stop_state_counter(unsigned ticks, bool x4, bool x16)
        BUG_ON(ticks > 0x1fff);
 
        /* ticks in DSI_FCK */
-       fck = dsi_fclk_rate();
+       fck = dsi_fclk_rate(dsidev);
 
-       r = dsi_read_reg(DSI_TIMING1);
+       r = dsi_read_reg(dsidev, DSI_TIMING1);
        r = FLD_MOD(r, 1, 15, 15);      /* FORCE_TX_STOP_MODE_IO */
        r = FLD_MOD(r, x16 ? 1 : 0, 14, 14);    /* STOP_STATE_X16_IO */
        r = FLD_MOD(r, x4 ? 1 : 0, 13, 13);     /* STOP_STATE_X4_IO */
        r = FLD_MOD(r, ticks, 12, 0);   /* STOP_STATE_COUNTER_IO */
-       dsi_write_reg(DSI_TIMING1, r);
+       dsi_write_reg(dsidev, DSI_TIMING1, r);
 
        total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
 
@@ -2703,7 +3481,8 @@ static void dsi_set_stop_state_counter(unsigned ticks, bool x4, bool x16)
                        (total_ticks * 1000) / (fck / 1000 / 1000));
 }
 
-static void dsi_set_hs_tx_timeout(unsigned ticks, bool x4, bool x16)
+static void dsi_set_hs_tx_timeout(struct platform_device *dsidev,
+               unsigned ticks, bool x4, bool x16)
 {
        unsigned long fck;
        unsigned long total_ticks;
@@ -2712,14 +3491,14 @@ static void dsi_set_hs_tx_timeout(unsigned ticks, bool x4, bool x16)
        BUG_ON(ticks > 0x1fff);
 
        /* ticks in TxByteClkHS */
-       fck = dsi_get_txbyteclkhs();
+       fck = dsi_get_txbyteclkhs(dsidev);
 
-       r = dsi_read_reg(DSI_TIMING2);
+       r = dsi_read_reg(dsidev, DSI_TIMING2);
        r = FLD_MOD(r, 1, 31, 31);      /* HS_TX_TO */
        r = FLD_MOD(r, x16 ? 1 : 0, 30, 30);    /* HS_TX_TO_X16 */
        r = FLD_MOD(r, x4 ? 1 : 0, 29, 29);     /* HS_TX_TO_X8 (4 really) */
        r = FLD_MOD(r, ticks, 28, 16);  /* HS_TX_TO_COUNTER */
-       dsi_write_reg(DSI_TIMING2, r);
+       dsi_write_reg(dsidev, DSI_TIMING2, r);
 
        total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
 
@@ -2730,24 +3509,25 @@ static void dsi_set_hs_tx_timeout(unsigned ticks, bool x4, bool x16)
 }
 static int dsi_proto_config(struct omap_dss_device *dssdev)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        u32 r;
        int buswidth = 0;
 
-       dsi_config_tx_fifo(DSI_FIFO_SIZE_32,
+       dsi_config_tx_fifo(dsidev, DSI_FIFO_SIZE_32,
                        DSI_FIFO_SIZE_32,
                        DSI_FIFO_SIZE_32,
                        DSI_FIFO_SIZE_32);
 
-       dsi_config_rx_fifo(DSI_FIFO_SIZE_32,
+       dsi_config_rx_fifo(dsidev, DSI_FIFO_SIZE_32,
                        DSI_FIFO_SIZE_32,
                        DSI_FIFO_SIZE_32,
                        DSI_FIFO_SIZE_32);
 
        /* XXX what values for the timeouts? */
-       dsi_set_stop_state_counter(0x1000, false, false);
-       dsi_set_ta_timeout(0x1fff, true, true);
-       dsi_set_lp_rx_timeout(0x1fff, true, true);
-       dsi_set_hs_tx_timeout(0x1fff, true, true);
+       dsi_set_stop_state_counter(dsidev, 0x1000, false, false);
+       dsi_set_ta_timeout(dsidev, 0x1fff, true, true);
+       dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true);
+       dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true);
 
        switch (dssdev->ctrl.pixel_size) {
        case 16:
@@ -2763,7 +3543,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
                BUG();
        }
 
-       r = dsi_read_reg(DSI_CTRL);
+       r = dsi_read_reg(dsidev, DSI_CTRL);
        r = FLD_MOD(r, 1, 1, 1);        /* CS_RX_EN */
        r = FLD_MOD(r, 1, 2, 2);        /* ECC_RX_EN */
        r = FLD_MOD(r, 1, 3, 3);        /* TX_FIFO_ARBITRATION */
@@ -2773,21 +3553,25 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
        r = FLD_MOD(r, 2, 13, 12);      /* LINE_BUFFER, 2 lines */
        r = FLD_MOD(r, 1, 14, 14);      /* TRIGGER_RESET_MODE */
        r = FLD_MOD(r, 1, 19, 19);      /* EOT_ENABLE */
-       r = FLD_MOD(r, 1, 24, 24);      /* DCS_CMD_ENABLE */
-       r = FLD_MOD(r, 0, 25, 25);      /* DCS_CMD_CODE, 1=start, 0=continue */
+       if (!dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) {
+               r = FLD_MOD(r, 1, 24, 24);      /* DCS_CMD_ENABLE */
+               /* DCS_CMD_CODE, 1=start, 0=continue */
+               r = FLD_MOD(r, 0, 25, 25);
+       }
 
-       dsi_write_reg(DSI_CTRL, r);
+       dsi_write_reg(dsidev, DSI_CTRL, r);
 
-       dsi_vc_initial_config(0);
-       dsi_vc_initial_config(1);
-       dsi_vc_initial_config(2);
-       dsi_vc_initial_config(3);
+       dsi_vc_initial_config(dsidev, 0);
+       dsi_vc_initial_config(dsidev, 1);
+       dsi_vc_initial_config(dsidev, 2);
+       dsi_vc_initial_config(dsidev, 3);
 
        return 0;
 }
 
 static void dsi_proto_timings(struct omap_dss_device *dssdev)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail;
        unsigned tclk_pre, tclk_post;
        unsigned ths_prepare, ths_prepare_ths_zero, ths_zero;
@@ -2797,32 +3581,27 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
        unsigned ths_eot;
        u32 r;
 
-       r = dsi_read_reg(DSI_DSIPHY_CFG0);
+       r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
        ths_prepare = FLD_GET(r, 31, 24);
        ths_prepare_ths_zero = FLD_GET(r, 23, 16);
        ths_zero = ths_prepare_ths_zero - ths_prepare;
        ths_trail = FLD_GET(r, 15, 8);
        ths_exit = FLD_GET(r, 7, 0);
 
-       r = dsi_read_reg(DSI_DSIPHY_CFG1);
+       r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
        tlpx = FLD_GET(r, 22, 16) * 2;
        tclk_trail = FLD_GET(r, 15, 8);
        tclk_zero = FLD_GET(r, 7, 0);
 
-       r = dsi_read_reg(DSI_DSIPHY_CFG2);
+       r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
        tclk_prepare = FLD_GET(r, 7, 0);
 
        /* min 8*UI */
        tclk_pre = 20;
        /* min 60ns + 52*UI */
-       tclk_post = ns2ddr(60) + 26;
+       tclk_post = ns2ddr(dsidev, 60) + 26;
 
-       /* ths_eot is 2 for 2 datalanes and 4 for 1 datalane */
-       if (dssdev->phy.dsi.data1_lane != 0 &&
-                       dssdev->phy.dsi.data2_lane != 0)
-               ths_eot = 2;
-       else
-               ths_eot = 4;
+       ths_eot = DIV_ROUND_UP(4, dsi_get_num_data_lanes_dssdev(dssdev));
 
        ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare,
                        4);
@@ -2831,10 +3610,10 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
        BUG_ON(ddr_clk_pre == 0 || ddr_clk_pre > 255);
        BUG_ON(ddr_clk_post == 0 || ddr_clk_post > 255);
 
-       r = dsi_read_reg(DSI_CLK_TIMING);
+       r = dsi_read_reg(dsidev, DSI_CLK_TIMING);
        r = FLD_MOD(r, ddr_clk_pre, 15, 8);
        r = FLD_MOD(r, ddr_clk_post, 7, 0);
-       dsi_write_reg(DSI_CLK_TIMING, r);
+       dsi_write_reg(dsidev, DSI_CLK_TIMING, r);
 
        DSSDBG("ddr_clk_pre %u, ddr_clk_post %u\n",
                        ddr_clk_pre,
@@ -2848,7 +3627,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
 
        r = FLD_VAL(enter_hs_mode_lat, 31, 16) |
                FLD_VAL(exit_hs_mode_lat, 15, 0);
-       dsi_write_reg(DSI_VM_TIMING7, r);
+       dsi_write_reg(dsidev, DSI_VM_TIMING7, r);
 
        DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
                        enter_hs_mode_lat, exit_hs_mode_lat);
@@ -2858,25 +3637,27 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
 #define DSI_DECL_VARS \
        int __dsi_cb = 0; u32 __dsi_cv = 0;
 
-#define DSI_FLUSH(ch) \
+#define DSI_FLUSH(dsidev, ch) \
        if (__dsi_cb > 0) { \
                /*DSSDBG("sending long packet %#010x\n", __dsi_cv);*/ \
-               dsi_write_reg(DSI_VC_LONG_PACKET_PAYLOAD(ch), __dsi_cv); \
+               dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_PAYLOAD(ch), __dsi_cv); \
                __dsi_cb = __dsi_cv = 0; \
        }
 
-#define DSI_PUSH(ch, data) \
+#define DSI_PUSH(dsidev, ch, data) \
        do { \
                __dsi_cv |= (data) << (__dsi_cb * 8); \
                /*DSSDBG("cv = %#010x, cb = %d\n", __dsi_cv, __dsi_cb);*/ \
                if (++__dsi_cb > 3) \
-                       DSI_FLUSH(ch); \
+                       DSI_FLUSH(dsidev, ch); \
        } while (0)
 
 static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
                        int x, int y, int w, int h)
 {
        /* Note: supports only 24bit colors in 32bit container */
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int first = 1;
        int fifo_stalls = 0;
        int max_dsi_packet_size;
@@ -2915,7 +3696,7 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
         * in fifo */
 
        /* When using CPU, max long packet size is TX buffer size */
-       max_dsi_packet_size = dsi.vc[0].fifo_size * 32 * 4;
+       max_dsi_packet_size = dsi->vc[0].fifo_size * 32 * 4;
 
        /* we seem to get better perf if we divide the tx fifo to half,
           and while the other half is being sent, we fill the other half
@@ -2944,35 +3725,36 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
 #if 1
                /* using fifo not empty */
                /* TX_FIFO_NOT_EMPTY */
-               while (FLD_GET(dsi_read_reg(DSI_VC_CTRL(0)), 5, 5)) {
+               while (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(0)), 5, 5)) {
                        fifo_stalls++;
                        if (fifo_stalls > 0xfffff) {
                                DSSERR("fifo stalls overflow, pixels left %d\n",
                                                pixels_left);
-                               dsi_if_enable(0);
+                               dsi_if_enable(dsidev, 0);
                                return -EIO;
                        }
                        udelay(1);
                }
 #elif 1
                /* using fifo emptiness */
-               while ((REG_GET(DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 <
+               while ((REG_GET(dsidev, DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 <
                                max_dsi_packet_size) {
                        fifo_stalls++;
                        if (fifo_stalls > 0xfffff) {
                                DSSERR("fifo stalls overflow, pixels left %d\n",
                                               pixels_left);
-                               dsi_if_enable(0);
+                               dsi_if_enable(dsidev, 0);
                                return -EIO;
                        }
                }
 #else
-               while ((REG_GET(DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 == 0) {
+               while ((REG_GET(dsidev, DSI_TX_FIFO_VC_EMPTINESS,
+                               7, 0) + 1) * 4 == 0) {
                        fifo_stalls++;
                        if (fifo_stalls > 0xfffff) {
                                DSSERR("fifo stalls overflow, pixels left %d\n",
                                               pixels_left);
-                               dsi_if_enable(0);
+                               dsi_if_enable(dsidev, 0);
                                return -EIO;
                        }
                }
@@ -2981,17 +3763,17 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
 
                pixels_left -= pixels;
 
-               dsi_vc_write_long_header(0, DSI_DT_DCS_LONG_WRITE,
+               dsi_vc_write_long_header(dsidev, 0, DSI_DT_DCS_LONG_WRITE,
                                1 + pixels * bytespp, 0);
 
-               DSI_PUSH(0, dcs_cmd);
+               DSI_PUSH(dsidev, 0, dcs_cmd);
 
                while (pixels-- > 0) {
                        u32 pix = __raw_readl(data++);
 
-                       DSI_PUSH(0, (pix >> 16) & 0xff);
-                       DSI_PUSH(0, (pix >> 8) & 0xff);
-                       DSI_PUSH(0, (pix >> 0) & 0xff);
+                       DSI_PUSH(dsidev, 0, (pix >> 16) & 0xff);
+                       DSI_PUSH(dsidev, 0, (pix >> 8) & 0xff);
+                       DSI_PUSH(dsidev, 0, (pix >> 0) & 0xff);
 
                        current_x++;
                        if (current_x == x+w) {
@@ -3000,7 +3782,7 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
                        }
                }
 
-               DSI_FLUSH(0);
+               DSI_FLUSH(dsidev, 0);
        }
 
        return 0;
@@ -3009,6 +3791,8 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
 static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
                u16 x, u16 y, u16 w, u16 h)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned bytespp;
        unsigned bytespl;
        unsigned bytespf;
@@ -3017,16 +3801,13 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
        unsigned packet_len;
        u32 l;
        int r;
-       const unsigned channel = dsi.update_channel;
-       /* line buffer is 1024 x 24bits */
-       /* XXX: for some reason using full buffer size causes considerable TX
-        * slowdown with update sizes that fill the whole buffer */
-       const unsigned line_buf_size = 1023 * 3;
+       const unsigned channel = dsi->update_channel;
+       const unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
 
        DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n",
                        x, y, w, h);
 
-       dsi_vc_config_vp(channel);
+       dsi_vc_config_vp(dsidev, channel);
 
        bytespp = dssdev->ctrl.pixel_size / 8;
        bytespl = w * bytespp;
@@ -3047,15 +3828,16 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
                total_len += (bytespf % packet_payload) + 1;
 
        l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */
-       dsi_write_reg(DSI_VC_TE(channel), l);
+       dsi_write_reg(dsidev, DSI_VC_TE(channel), l);
 
-       dsi_vc_write_long_header(channel, DSI_DT_DCS_LONG_WRITE, packet_len, 0);
+       dsi_vc_write_long_header(dsidev, channel, DSI_DT_DCS_LONG_WRITE,
+               packet_len, 0);
 
-       if (dsi.te_enabled)
+       if (dsi->te_enabled)
                l = FLD_MOD(l, 1, 30, 30); /* TE_EN */
        else
                l = FLD_MOD(l, 1, 31, 31); /* TE_START */
-       dsi_write_reg(DSI_VC_TE(channel), l);
+       dsi_write_reg(dsidev, DSI_VC_TE(channel), l);
 
        /* We put SIDLEMODE to no-idle for the duration of the transfer,
         * because DSS interrupts are not capable of waking up the CPU and the
@@ -3065,23 +3847,23 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
         */
        dispc_disable_sidle();
 
-       dsi_perf_mark_start();
+       dsi_perf_mark_start(dsidev);
 
-       r = queue_delayed_work(dsi.workqueue, &dsi.framedone_timeout_work,
-                       msecs_to_jiffies(250));
+       r = schedule_delayed_work(&dsi->framedone_timeout_work,
+               msecs_to_jiffies(250));
        BUG_ON(r == 0);
 
        dss_start_update(dssdev);
 
-       if (dsi.te_enabled) {
+       if (dsi->te_enabled) {
                /* disable LP_RX_TO, so that we can receive TE.  Time to wait
                 * for TE is longer than the timer allows */
-               REG_FLD_MOD(DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
+               REG_FLD_MOD(dsidev, DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
 
-               dsi_vc_send_bta(channel);
+               dsi_vc_send_bta(dsidev, channel);
 
 #ifdef DSI_CATCH_MISSING_TE
-               mod_timer(&dsi.te_timer, jiffies + msecs_to_jiffies(250));
+               mod_timer(&dsi->te_timer, jiffies + msecs_to_jiffies(250));
 #endif
        }
 }
@@ -3093,41 +3875,28 @@ static void dsi_te_timeout(unsigned long arg)
 }
 #endif
 
-static void dsi_framedone_bta_callback(void *data, u32 mask);
-
-static void dsi_handle_framedone(int error)
+static void dsi_handle_framedone(struct platform_device *dsidev, int error)
 {
-       const int channel = dsi.update_channel;
-
-       dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback,
-                       NULL, DSI_VC_IRQ_BTA);
-
-       cancel_delayed_work(&dsi.framedone_timeout_work);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
        /* SIDLEMODE back to smart-idle */
        dispc_enable_sidle();
 
-       if (dsi.te_enabled) {
+       if (dsi->te_enabled) {
                /* enable LP_RX_TO again after the TE */
-               REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
+               REG_FLD_MOD(dsidev, DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
        }
 
-       /* RX_FIFO_NOT_EMPTY */
-       if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
-               DSSERR("Received error during frame transfer:\n");
-               dsi_vc_flush_receive_data(channel);
-               if (!error)
-                       error = -EIO;
-       }
-
-       dsi.framedone_callback(error, dsi.framedone_data);
+       dsi->framedone_callback(error, dsi->framedone_data);
 
        if (!error)
-               dsi_perf_show("DISPC");
+               dsi_perf_show(dsidev, "DISPC");
 }
 
 static void dsi_framedone_timeout_work_callback(struct work_struct *work)
 {
+       struct dsi_data *dsi = container_of(work, struct dsi_data,
+                       framedone_timeout_work.work);
        /* XXX While extremely unlikely, we could get FRAMEDONE interrupt after
         * 250ms which would conflict with this timeout work. What should be
         * done is first cancel the transfer on the HW, and then cancel the
@@ -3137,70 +3906,34 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work)
 
        DSSERR("Framedone not received for 250ms!\n");
 
-       dsi_handle_framedone(-ETIMEDOUT);
-}
-
-static void dsi_framedone_bta_callback(void *data, u32 mask)
-{
-       dsi_handle_framedone(0);
-
-#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
-       dispc_fake_vsync_irq();
-#endif
+       dsi_handle_framedone(dsi->pdev, -ETIMEDOUT);
 }
 
 static void dsi_framedone_irq_callback(void *data, u32 mask)
 {
-       const int channel = dsi.update_channel;
-       int r;
+       struct omap_dss_device *dssdev = (struct omap_dss_device *) data;
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
        /* Note: We get FRAMEDONE when DISPC has finished sending pixels and
         * turns itself off. However, DSI still has the pixels in its buffers,
         * and is sending the data.
         */
 
-       if (dsi.te_enabled) {
-               /* enable LP_RX_TO again after the TE */
-               REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
-       }
-
-       /* Send BTA after the frame. We need this for the TE to work, as TE
-        * trigger is only sent for BTAs without preceding packet. Thus we need
-        * to BTA after the pixel packets so that next BTA will cause TE
-        * trigger.
-        *
-        * This is not needed when TE is not in use, but we do it anyway to
-        * make sure that the transfer has been completed. It would be more
-        * optimal, but more complex, to wait only just before starting next
-        * transfer.
-        *
-        * Also, as there's no interrupt telling when the transfer has been
-        * done and the channel could be reconfigured, the only way is to
-        * busyloop until TE_SIZE is zero. With BTA we can do this
-        * asynchronously.
-        * */
-
-       r = dsi_register_isr_vc(channel, dsi_framedone_bta_callback,
-                       NULL, DSI_VC_IRQ_BTA);
-       if (r) {
-               DSSERR("Failed to register BTA ISR\n");
-               dsi_handle_framedone(-EIO);
-               return;
-       }
+       __cancel_delayed_work(&dsi->framedone_timeout_work);
 
-       r = dsi_vc_send_bta(channel);
-       if (r) {
-               DSSERR("BTA after framedone failed\n");
-               dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback,
-                               NULL, DSI_VC_IRQ_BTA);
-               dsi_handle_framedone(-EIO);
-       }
+       dsi_handle_framedone(dsidev, 0);
+
+#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
+       dispc_fake_vsync_irq();
+#endif
 }
 
 int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
                                    u16 *x, u16 *y, u16 *w, u16 *h,
                                    bool enlarge_update_area)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        u16 dw, dh;
 
        dssdev->driver->get_resolution(dssdev, &dw, &dh);
@@ -3220,7 +3953,7 @@ int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
        if (*w == 0 || *h == 0)
                return -EINVAL;
 
-       dsi_perf_mark_setup();
+       dsi_perf_mark_setup(dsidev);
 
        if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
                dss_setup_partial_planes(dssdev, x, y, w, h,
@@ -3237,7 +3970,10 @@ int omap_dsi_update(struct omap_dss_device *dssdev,
                u16 x, u16 y, u16 w, u16 h,
                void (*callback)(int, void *), void *data)
 {
-       dsi.update_channel = channel;
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       dsi->update_channel = channel;
 
        /* OMAP DSS cannot send updates of odd widths.
         * omap_dsi_prepare_update() makes the widths even, but add a BUG_ON
@@ -3246,14 +3982,14 @@ int omap_dsi_update(struct omap_dss_device *dssdev,
        BUG_ON(x % 2 == 1);
 
        if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
-               dsi.framedone_callback = callback;
-               dsi.framedone_data = data;
+               dsi->framedone_callback = callback;
+               dsi->framedone_data = data;
 
-               dsi.update_region.x = x;
-               dsi.update_region.y = y;
-               dsi.update_region.w = w;
-               dsi.update_region.h = h;
-               dsi.update_region.device = dssdev;
+               dsi->update_region.x = x;
+               dsi->update_region.y = y;
+               dsi->update_region.w = w;
+               dsi->update_region.h = h;
+               dsi->update_region.device = dssdev;
 
                dsi_update_screen_dispc(dssdev, x, y, w, h);
        } else {
@@ -3263,7 +3999,7 @@ int omap_dsi_update(struct omap_dss_device *dssdev,
                if (r)
                        return r;
 
-               dsi_perf_show("L4");
+               dsi_perf_show(dsidev, "L4");
                callback(0, data);
        }
 
@@ -3276,9 +4012,13 @@ EXPORT_SYMBOL(omap_dsi_update);
 static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
 {
        int r;
+       u32 irq;
+
+       irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ?
+               DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2;
 
-       r = omap_dispc_register_isr(dsi_framedone_irq_callback, NULL,
-                       DISPC_IRQ_FRAMEDONE);
+       r = omap_dispc_register_isr(dsi_framedone_irq_callback, (void *) dssdev,
+                       irq);
        if (r) {
                DSSERR("can't get FRAMEDONE irq\n");
                return r;
@@ -3311,28 +4051,34 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
 
 static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
 {
-       omap_dispc_unregister_isr(dsi_framedone_irq_callback, NULL,
-                       DISPC_IRQ_FRAMEDONE);
+       u32 irq;
+
+       irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ?
+               DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2;
+
+       omap_dispc_unregister_isr(dsi_framedone_irq_callback, (void *) dssdev,
+                       irq);
 }
 
 static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_clock_info cinfo;
        int r;
 
        /* we always use DSS_CLK_SYSCK as input clock */
        cinfo.use_sys_clk = true;
-       cinfo.regn  = dssdev->phy.dsi.div.regn;
-       cinfo.regm  = dssdev->phy.dsi.div.regm;
-       cinfo.regm_dispc = dssdev->phy.dsi.div.regm_dispc;
-       cinfo.regm_dsi = dssdev->phy.dsi.div.regm_dsi;
+       cinfo.regn  = dssdev->clocks.dsi.regn;
+       cinfo.regm  = dssdev->clocks.dsi.regm;
+       cinfo.regm_dispc = dssdev->clocks.dsi.regm_dispc;
+       cinfo.regm_dsi = dssdev->clocks.dsi.regm_dsi;
        r = dsi_calc_clock_rates(dssdev, &cinfo);
        if (r) {
                DSSERR("Failed to calc dsi clocks\n");
                return r;
        }
 
-       r = dsi_pll_set_clock_div(&cinfo);
+       r = dsi_pll_set_clock_div(dsidev, &cinfo);
        if (r) {
                DSSERR("Failed to set dsi clocks\n");
                return r;
@@ -3343,14 +4089,15 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
 
 static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dispc_clock_info dispc_cinfo;
        int r;
        unsigned long long fck;
 
-       fck = dsi_get_pll_hsdiv_dispc_rate();
+       fck = dsi_get_pll_hsdiv_dispc_rate(dsidev);
 
-       dispc_cinfo.lck_div = dssdev->phy.dsi.div.lck_div;
-       dispc_cinfo.pck_div = dssdev->phy.dsi.div.pck_div;
+       dispc_cinfo.lck_div = dssdev->clocks.dispc.channel.lck_div;
+       dispc_cinfo.pck_div = dssdev->clocks.dispc.channel.pck_div;
 
        r = dispc_calc_clock_rates(fck, &dispc_cinfo);
        if (r) {
@@ -3369,11 +4116,11 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
 
 static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       int dsi_module = dsi_get_dsidev_id(dsidev);
        int r;
 
-       _dsi_print_reset_status();
-
-       r = dsi_pll_init(dssdev, true, true);
+       r = dsi_pll_init(dsidev, true, true);
        if (r)
                goto err0;
 
@@ -3381,8 +4128,10 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
        if (r)
                goto err1;
 
-       dss_select_dispc_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC);
-       dss_select_dsi_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI);
+       dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
+       dss_select_dsi_clk_source(dsi_module, dssdev->clocks.dsi.dsi_fclk_src);
+       dss_select_lcd_clk_source(dssdev->manager->id,
+                       dssdev->clocks.dispc.channel.lcd_clk_src);
 
        DSSDBG("PLL OK\n");
 
@@ -3390,82 +4139,92 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
        if (r)
                goto err2;
 
-       r = dsi_complexio_init(dssdev);
+       r = dsi_cio_init(dssdev);
        if (r)
                goto err2;
 
-       _dsi_print_reset_status();
+       _dsi_print_reset_status(dsidev);
 
        dsi_proto_timings(dssdev);
        dsi_set_lp_clk_divisor(dssdev);
 
        if (1)
-               _dsi_print_reset_status();
+               _dsi_print_reset_status(dsidev);
 
        r = dsi_proto_config(dssdev);
        if (r)
                goto err3;
 
        /* enable interface */
-       dsi_vc_enable(0, 1);
-       dsi_vc_enable(1, 1);
-       dsi_vc_enable(2, 1);
-       dsi_vc_enable(3, 1);
-       dsi_if_enable(1);
-       dsi_force_tx_stop_mode_io();
+       dsi_vc_enable(dsidev, 0, 1);
+       dsi_vc_enable(dsidev, 1, 1);
+       dsi_vc_enable(dsidev, 2, 1);
+       dsi_vc_enable(dsidev, 3, 1);
+       dsi_if_enable(dsidev, 1);
+       dsi_force_tx_stop_mode_io(dsidev);
 
        return 0;
 err3:
-       dsi_complexio_uninit();
+       dsi_cio_uninit(dsidev);
 err2:
-       dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
-       dss_select_dsi_clk_source(DSS_CLK_SRC_FCK);
+       dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
+       dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK);
 err1:
-       dsi_pll_uninit();
+       dsi_pll_uninit(dsidev, true);
 err0:
        return r;
 }
 
-static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev)
+static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
+               bool disconnect_lanes, bool enter_ulps)
 {
-       /* disable interface */
-       dsi_if_enable(0);
-       dsi_vc_enable(0, 0);
-       dsi_vc_enable(1, 0);
-       dsi_vc_enable(2, 0);
-       dsi_vc_enable(3, 0);
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       int dsi_module = dsi_get_dsidev_id(dsidev);
 
-       dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
-       dss_select_dsi_clk_source(DSS_CLK_SRC_FCK);
-       dsi_complexio_uninit();
-       dsi_pll_uninit();
+       if (enter_ulps && !dsi->ulps_enabled)
+               dsi_enter_ulps(dsidev);
+
+       /* disable interface */
+       dsi_if_enable(dsidev, 0);
+       dsi_vc_enable(dsidev, 0, 0);
+       dsi_vc_enable(dsidev, 1, 0);
+       dsi_vc_enable(dsidev, 2, 0);
+       dsi_vc_enable(dsidev, 3, 0);
+
+       dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
+       dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK);
+       dsi_cio_uninit(dsidev);
+       dsi_pll_uninit(dsidev, disconnect_lanes);
 }
 
-static int dsi_core_init(void)
+static int dsi_core_init(struct platform_device *dsidev)
 {
        /* Autoidle */
-       REG_FLD_MOD(DSI_SYSCONFIG, 1, 0, 0);
+       REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 0, 0);
 
        /* ENWAKEUP */
-       REG_FLD_MOD(DSI_SYSCONFIG, 1, 2, 2);
+       REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 2, 2);
 
        /* SIDLEMODE smart-idle */
-       REG_FLD_MOD(DSI_SYSCONFIG, 2, 4, 3);
+       REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 2, 4, 3);
 
-       _dsi_initialize_irq();
+       _dsi_initialize_irq(dsidev);
 
        return 0;
 }
 
 int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int r = 0;
 
        DSSDBG("dsi_display_enable\n");
 
-       WARN_ON(!dsi_bus_is_locked());
+       WARN_ON(!dsi_bus_is_locked(dsidev));
 
-       mutex_lock(&dsi.lock);
+       mutex_lock(&dsi->lock);
 
        r = omap_dss_start_device(dssdev);
        if (r) {
@@ -3474,13 +4233,13 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
        }
 
        enable_clocks(1);
-       dsi_enable_pll_clock(1);
+       dsi_enable_pll_clock(dsidev, 1);
 
-       r = _dsi_reset();
+       r = _dsi_reset(dsidev);
        if (r)
                goto err1;
 
-       dsi_core_init();
+       dsi_core_init(dsidev);
 
        r = dsi_display_init_dispc(dssdev);
        if (r)
@@ -3490,7 +4249,7 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
        if (r)
                goto err2;
 
-       mutex_unlock(&dsi.lock);
+       mutex_unlock(&dsi->lock);
 
        return 0;
 
@@ -3498,39 +4257,46 @@ err2:
        dsi_display_uninit_dispc(dssdev);
 err1:
        enable_clocks(0);
-       dsi_enable_pll_clock(0);
+       dsi_enable_pll_clock(dsidev, 0);
        omap_dss_stop_device(dssdev);
 err0:
-       mutex_unlock(&dsi.lock);
+       mutex_unlock(&dsi->lock);
        DSSDBG("dsi_display_enable FAILED\n");
        return r;
 }
 EXPORT_SYMBOL(omapdss_dsi_display_enable);
 
-void omapdss_dsi_display_disable(struct omap_dss_device *dssdev)
+void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
+               bool disconnect_lanes, bool enter_ulps)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
        DSSDBG("dsi_display_disable\n");
 
-       WARN_ON(!dsi_bus_is_locked());
+       WARN_ON(!dsi_bus_is_locked(dsidev));
 
-       mutex_lock(&dsi.lock);
+       mutex_lock(&dsi->lock);
 
        dsi_display_uninit_dispc(dssdev);
 
-       dsi_display_uninit_dsi(dssdev);
+       dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps);
 
        enable_clocks(0);
-       dsi_enable_pll_clock(0);
+       dsi_enable_pll_clock(dsidev, 0);
 
        omap_dss_stop_device(dssdev);
 
-       mutex_unlock(&dsi.lock);
+       mutex_unlock(&dsi->lock);
 }
 EXPORT_SYMBOL(omapdss_dsi_display_disable);
 
 int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
 {
-       dsi.te_enabled = enable;
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       dsi->te_enabled = enable;
        return 0;
 }
 EXPORT_SYMBOL(omapdss_dsi_enable_te);
@@ -3550,23 +4316,33 @@ void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
 
 int dsi_init_display(struct omap_dss_device *dssdev)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       int dsi_module = dsi_get_dsidev_id(dsidev);
+
        DSSDBG("DSI init\n");
 
        /* XXX these should be figured out dynamically */
        dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
                OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
 
-       if (dsi.vdds_dsi_reg == NULL) {
+       if (dsi->vdds_dsi_reg == NULL) {
                struct regulator *vdds_dsi;
 
-               vdds_dsi = regulator_get(&dsi.pdev->dev, "vdds_dsi");
+               vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi");
 
                if (IS_ERR(vdds_dsi)) {
                        DSSERR("can't get VDDS_DSI regulator\n");
                        return PTR_ERR(vdds_dsi);
                }
 
-               dsi.vdds_dsi_reg = vdds_dsi;
+               dsi->vdds_dsi_reg = vdds_dsi;
+       }
+
+       if (dsi_get_num_data_lanes_dssdev(dssdev) > dsi->num_data_lanes) {
+               DSSERR("DSI%d can't support more than %d data lanes\n",
+                       dsi_module + 1, dsi->num_data_lanes);
+               return -EINVAL;
        }
 
        return 0;
@@ -3574,11 +4350,13 @@ int dsi_init_display(struct omap_dss_device *dssdev)
 
 int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(dsi.vc); i++) {
-               if (!dsi.vc[i].dssdev) {
-                       dsi.vc[i].dssdev = dssdev;
+       for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
+               if (!dsi->vc[i].dssdev) {
+                       dsi->vc[i].dssdev = dssdev;
                        *channel = i;
                        return 0;
                }
@@ -3591,6 +4369,9 @@ EXPORT_SYMBOL(omap_dsi_request_vc);
 
 int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
        if (vc_id < 0 || vc_id > 3) {
                DSSERR("VC ID out of range\n");
                return -EINVAL;
@@ -3601,13 +4382,13 @@ int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id)
                return -EINVAL;
        }
 
-       if (dsi.vc[channel].dssdev != dssdev) {
+       if (dsi->vc[channel].dssdev != dssdev) {
                DSSERR("Virtual Channel not allocated to display %s\n",
                        dssdev->name);
                return -EINVAL;
        }
 
-       dsi.vc[channel].vc_id = vc_id;
+       dsi->vc[channel].vc_id = vc_id;
 
        return 0;
 }
@@ -3615,143 +4396,172 @@ EXPORT_SYMBOL(omap_dsi_set_vc_id);
 
 void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
        if ((channel >= 0 && channel <= 3) &&
-               dsi.vc[channel].dssdev == dssdev) {
-               dsi.vc[channel].dssdev = NULL;
-               dsi.vc[channel].vc_id = 0;
+               dsi->vc[channel].dssdev == dssdev) {
+               dsi->vc[channel].dssdev = NULL;
+               dsi->vc[channel].vc_id = 0;
        }
 }
 EXPORT_SYMBOL(omap_dsi_release_vc);
 
-void dsi_wait_pll_hsdiv_dispc_active(void)
+void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev)
 {
-       if (wait_for_bit_change(DSI_PLL_STATUS, 7, 1) != 1)
+       if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 7, 1) != 1)
                DSSERR("%s (%s) not active\n",
-                       dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
-                       dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC));
+                       dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
+                       dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC));
 }
 
-void dsi_wait_pll_hsdiv_dsi_active(void)
+void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
 {
-       if (wait_for_bit_change(DSI_PLL_STATUS, 8, 1) != 1)
+       if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 8, 1) != 1)
                DSSERR("%s (%s) not active\n",
-                       dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
-                       dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI));
+                       dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
+                       dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI));
 }
 
-static void dsi_calc_clock_param_ranges(void)
+static void dsi_calc_clock_param_ranges(struct platform_device *dsidev)
 {
-       dsi.regn_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGN);
-       dsi.regm_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM);
-       dsi.regm_dispc_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DISPC);
-       dsi.regm_dsi_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DSI);
-       dsi.fint_min = dss_feat_get_param_min(FEAT_PARAM_DSIPLL_FINT);
-       dsi.fint_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_FINT);
-       dsi.lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       dsi->regn_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGN);
+       dsi->regm_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM);
+       dsi->regm_dispc_max =
+               dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DISPC);
+       dsi->regm_dsi_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DSI);
+       dsi->fint_min = dss_feat_get_param_min(FEAT_PARAM_DSIPLL_FINT);
+       dsi->fint_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_FINT);
+       dsi->lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
 }
 
-static int dsi_init(struct platform_device *pdev)
+static int dsi_init(struct platform_device *dsidev)
 {
+       struct omap_display_platform_data *dss_plat_data;
+       struct omap_dss_board_info *board_info;
        u32 rev;
-       int r, i;
+       int r, i, dsi_module = dsi_get_dsidev_id(dsidev);
        struct resource *dsi_mem;
+       struct dsi_data *dsi;
+
+       dsi = kzalloc(sizeof(*dsi), GFP_KERNEL);
+       if (!dsi) {
+               r = -ENOMEM;
+               goto err0;
+       }
+
+       dsi->pdev = dsidev;
+       dsi_pdev_map[dsi_module] = dsidev;
+       dev_set_drvdata(&dsidev->dev, dsi);
+
+       dss_plat_data = dsidev->dev.platform_data;
+       board_info = dss_plat_data->board_data;
+       dsi->dsi_mux_pads = board_info->dsi_mux_pads;
 
-       spin_lock_init(&dsi.irq_lock);
-       spin_lock_init(&dsi.errors_lock);
-       dsi.errors = 0;
+       spin_lock_init(&dsi->irq_lock);
+       spin_lock_init(&dsi->errors_lock);
+       dsi->errors = 0;
 
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-       spin_lock_init(&dsi.irq_stats_lock);
-       dsi.irq_stats.last_reset = jiffies;
+       spin_lock_init(&dsi->irq_stats_lock);
+       dsi->irq_stats.last_reset = jiffies;
 #endif
 
-       mutex_init(&dsi.lock);
-       sema_init(&dsi.bus_lock, 1);
+       mutex_init(&dsi->lock);
+       sema_init(&dsi->bus_lock, 1);
 
-       dsi.workqueue = create_singlethread_workqueue("dsi");
-       if (dsi.workqueue == NULL)
-               return -ENOMEM;
-
-       INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work,
+       INIT_DELAYED_WORK_DEFERRABLE(&dsi->framedone_timeout_work,
                        dsi_framedone_timeout_work_callback);
 
 #ifdef DSI_CATCH_MISSING_TE
-       init_timer(&dsi.te_timer);
-       dsi.te_timer.function = dsi_te_timeout;
-       dsi.te_timer.data = 0;
+       init_timer(&dsi->te_timer);
+       dsi->te_timer.function = dsi_te_timeout;
+       dsi->te_timer.data = 0;
 #endif
-       dsi_mem = platform_get_resource(dsi.pdev, IORESOURCE_MEM, 0);
+       dsi_mem = platform_get_resource(dsi->pdev, IORESOURCE_MEM, 0);
        if (!dsi_mem) {
                DSSERR("can't get IORESOURCE_MEM DSI\n");
                r = -EINVAL;
                goto err1;
        }
-       dsi.base = ioremap(dsi_mem->start, resource_size(dsi_mem));
-       if (!dsi.base) {
+       dsi->base = ioremap(dsi_mem->start, resource_size(dsi_mem));
+       if (!dsi->base) {
                DSSERR("can't ioremap DSI\n");
                r = -ENOMEM;
                goto err1;
        }
-       dsi.irq = platform_get_irq(dsi.pdev, 0);
-       if (dsi.irq < 0) {
+       dsi->irq = platform_get_irq(dsi->pdev, 0);
+       if (dsi->irq < 0) {
                DSSERR("platform_get_irq failed\n");
                r = -ENODEV;
                goto err2;
        }
 
-       r = request_irq(dsi.irq, omap_dsi_irq_handler, IRQF_SHARED,
-               "OMAP DSI1", dsi.pdev);
+       r = request_irq(dsi->irq, omap_dsi_irq_handler, IRQF_SHARED,
+               dev_name(&dsidev->dev), dsi->pdev);
        if (r < 0) {
                DSSERR("request_irq failed\n");
                goto err2;
        }
 
        /* DSI VCs initialization */
-       for (i = 0; i < ARRAY_SIZE(dsi.vc); i++) {
-               dsi.vc[i].mode = DSI_VC_MODE_L4;
-               dsi.vc[i].dssdev = NULL;
-               dsi.vc[i].vc_id = 0;
+       for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
+               dsi->vc[i].mode = DSI_VC_MODE_L4;
+               dsi->vc[i].dssdev = NULL;
+               dsi->vc[i].vc_id = 0;
        }
 
-       dsi_calc_clock_param_ranges();
+       dsi_calc_clock_param_ranges(dsidev);
 
        enable_clocks(1);
 
-       rev = dsi_read_reg(DSI_REVISION);
-       dev_dbg(&pdev->dev, "OMAP DSI rev %d.%d\n",
+       rev = dsi_read_reg(dsidev, DSI_REVISION);
+       dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n",
               FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
 
+       dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev);
+
        enable_clocks(0);
 
        return 0;
 err2:
-       iounmap(dsi.base);
+       iounmap(dsi->base);
 err1:
-       destroy_workqueue(dsi.workqueue);
+       kfree(dsi);
+err0:
        return r;
 }
 
-static void dsi_exit(void)
+static void dsi_exit(struct platform_device *dsidev)
 {
-       if (dsi.vdds_dsi_reg != NULL) {
-               regulator_put(dsi.vdds_dsi_reg);
-               dsi.vdds_dsi_reg = NULL;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       if (dsi->vdds_dsi_reg != NULL) {
+               if (dsi->vdds_dsi_enabled) {
+                       regulator_disable(dsi->vdds_dsi_reg);
+                       dsi->vdds_dsi_enabled = false;
+               }
+
+               regulator_put(dsi->vdds_dsi_reg);
+               dsi->vdds_dsi_reg = NULL;
        }
 
-       free_irq(dsi.irq, dsi.pdev);
-       iounmap(dsi.base);
+       free_irq(dsi->irq, dsi->pdev);
+       iounmap(dsi->base);
 
-       destroy_workqueue(dsi.workqueue);
+       kfree(dsi);
 
        DSSDBG("omap_dsi_exit\n");
 }
 
 /* DSI1 HW IP initialisation */
-static int omap_dsi1hw_probe(struct platform_device *pdev)
+static int omap_dsi1hw_probe(struct platform_device *dsidev)
 {
        int r;
-       dsi.pdev = pdev;
-       r = dsi_init(pdev);
+
+       r = dsi_init(dsidev);
        if (r) {
                DSSERR("Failed to initialize DSI\n");
                goto err_dsi;
@@ -3760,9 +4570,12 @@ err_dsi:
        return r;
 }
 
-static int omap_dsi1hw_remove(struct platform_device *pdev)
+static int omap_dsi1hw_remove(struct platform_device *dsidev)
 {
-       dsi_exit();
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       dsi_exit(dsidev);
+       WARN_ON(dsi->scp_clk_refcount > 0);
        return 0;
 }
 
index 3f1fee63c67830d2e9778238d2040b865df6cbef..d9489d5c4f08d96c942676ee00dddc93d62f3208 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/seq_file.h>
 #include <linux/clk.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/clock.h>
 #include "dss.h"
 #include "dss_features.h"
@@ -45,7 +45,6 @@ struct dss_reg {
 #define DSS_REVISION                   DSS_REG(0x0000)
 #define DSS_SYSCONFIG                  DSS_REG(0x0010)
 #define DSS_SYSSTATUS                  DSS_REG(0x0014)
-#define DSS_IRQSTATUS                  DSS_REG(0x0018)
 #define DSS_CONTROL                    DSS_REG(0x0040)
 #define DSS_SDI_CONTROL                        DSS_REG(0x0044)
 #define DSS_PLL_CONTROL                        DSS_REG(0x0048)
@@ -75,17 +74,17 @@ static struct {
        struct dss_clock_info cache_dss_cinfo;
        struct dispc_clock_info cache_dispc_cinfo;
 
-       enum dss_clk_source dsi_clk_source;
-       enum dss_clk_source dispc_clk_source;
-       enum dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
+       enum omap_dss_clk_source dsi_clk_source[MAX_NUM_DSI];
+       enum omap_dss_clk_source dispc_clk_source;
+       enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
 
        u32             ctx[DSS_SZ_REGS / sizeof(u32)];
 } dss;
 
 static const char * const dss_generic_clk_source_names[] = {
-       [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]       = "DSI_PLL_HSDIV_DISPC",
-       [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]         = "DSI_PLL_HSDIV_DSI",
-       [DSS_CLK_SRC_FCK]                       = "DSS_FCK",
+       [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]  = "DSI_PLL_HSDIV_DISPC",
+       [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]    = "DSI_PLL_HSDIV_DSI",
+       [OMAP_DSS_CLK_SRC_FCK]                  = "DSS_FCK",
 };
 
 static void dss_clk_enable_all_no_ctx(void);
@@ -230,7 +229,7 @@ void dss_sdi_disable(void)
        REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
 }
 
-const char *dss_get_generic_clk_source_name(enum dss_clk_source clk_src)
+const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
 {
        return dss_generic_clk_source_names[clk_src];
 }
@@ -246,8 +245,8 @@ void dss_dump_clocks(struct seq_file *s)
 
        seq_printf(s, "- DSS -\n");
 
-       fclk_name = dss_get_generic_clk_source_name(DSS_CLK_SRC_FCK);
-       fclk_real_name = dss_feat_get_clk_source_name(DSS_CLK_SRC_FCK);
+       fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
+       fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
        fclk_rate = dss_clk_get_rate(DSS_CLK_FCK);
 
        if (dss.dpll4_m4_ck) {
@@ -286,7 +285,6 @@ void dss_dump_regs(struct seq_file *s)
        DUMPREG(DSS_REVISION);
        DUMPREG(DSS_SYSCONFIG);
        DUMPREG(DSS_SYSSTATUS);
-       DUMPREG(DSS_IRQSTATUS);
        DUMPREG(DSS_CONTROL);
 
        if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
@@ -300,18 +298,25 @@ void dss_dump_regs(struct seq_file *s)
 #undef DUMPREG
 }
 
-void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
+void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
 {
+       struct platform_device *dsidev;
        int b;
        u8 start, end;
 
        switch (clk_src) {
-       case DSS_CLK_SRC_FCK:
+       case OMAP_DSS_CLK_SRC_FCK:
                b = 0;
                break;
-       case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+       case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
                b = 1;
-               dsi_wait_pll_hsdiv_dispc_active();
+               dsidev = dsi_get_dsidev_from_id(0);
+               dsi_wait_pll_hsdiv_dispc_active(dsidev);
+               break;
+       case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
+               b = 2;
+               dsidev = dsi_get_dsidev_from_id(1);
+               dsi_wait_pll_hsdiv_dispc_active(dsidev);
                break;
        default:
                BUG();
@@ -324,17 +329,27 @@ void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
        dss.dispc_clk_source = clk_src;
 }
 
-void dss_select_dsi_clk_source(enum dss_clk_source clk_src)
+void dss_select_dsi_clk_source(int dsi_module,
+               enum omap_dss_clk_source clk_src)
 {
+       struct platform_device *dsidev;
        int b;
 
        switch (clk_src) {
-       case DSS_CLK_SRC_FCK:
+       case OMAP_DSS_CLK_SRC_FCK:
                b = 0;
                break;
-       case DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
+       case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
+               BUG_ON(dsi_module != 0);
+               b = 1;
+               dsidev = dsi_get_dsidev_from_id(0);
+               dsi_wait_pll_hsdiv_dsi_active(dsidev);
+               break;
+       case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
+               BUG_ON(dsi_module != 1);
                b = 1;
-               dsi_wait_pll_hsdiv_dsi_active();
+               dsidev = dsi_get_dsidev_from_id(1);
+               dsi_wait_pll_hsdiv_dsi_active(dsidev);
                break;
        default:
                BUG();
@@ -342,25 +357,33 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src)
 
        REG_FLD_MOD(DSS_CONTROL, b, 1, 1);      /* DSI_CLK_SWITCH */
 
-       dss.dsi_clk_source = clk_src;
+       dss.dsi_clk_source[dsi_module] = clk_src;
 }
 
 void dss_select_lcd_clk_source(enum omap_channel channel,
-               enum dss_clk_source clk_src)
+               enum omap_dss_clk_source clk_src)
 {
+       struct platform_device *dsidev;
        int b, ix, pos;
 
        if (!dss_has_feature(FEAT_LCD_CLK_SRC))
                return;
 
        switch (clk_src) {
-       case DSS_CLK_SRC_FCK:
+       case OMAP_DSS_CLK_SRC_FCK:
                b = 0;
                break;
-       case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+       case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
                BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
                b = 1;
-               dsi_wait_pll_hsdiv_dispc_active();
+               dsidev = dsi_get_dsidev_from_id(0);
+               dsi_wait_pll_hsdiv_dispc_active(dsidev);
+               break;
+       case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
+               BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2);
+               b = 1;
+               dsidev = dsi_get_dsidev_from_id(1);
+               dsi_wait_pll_hsdiv_dispc_active(dsidev);
                break;
        default:
                BUG();
@@ -373,20 +396,26 @@ void dss_select_lcd_clk_source(enum omap_channel channel,
        dss.lcd_clk_source[ix] = clk_src;
 }
 
-enum dss_clk_source dss_get_dispc_clk_source(void)
+enum omap_dss_clk_source dss_get_dispc_clk_source(void)
 {
        return dss.dispc_clk_source;
 }
 
-enum dss_clk_source dss_get_dsi_clk_source(void)
+enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module)
 {
-       return dss.dsi_clk_source;
+       return dss.dsi_clk_source[dsi_module];
 }
 
-enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
+enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
 {
-       int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
-       return dss.lcd_clk_source[ix];
+       if (dss_has_feature(FEAT_LCD_CLK_SRC)) {
+               int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
+               return dss.lcd_clk_source[ix];
+       } else {
+               /* LCD_CLK source is the same as DISPC_FCLK source for
+                * OMAP2 and OMAP3 */
+               return dss.dispc_clk_source;
+       }
 }
 
 /* calculate clock rates using dividers in cinfo */
@@ -659,13 +688,18 @@ static int dss_init(void)
         * the kernel resets it */
        omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
 
+#ifdef CONFIG_OMAP2_DSS_SLEEP_BEFORE_RESET
        /* We need to wait here a bit, otherwise we sometimes start to
         * get synclost errors, and after that only power cycle will
         * restore DSS functionality. I have no idea why this happens.
         * And we have to wait _before_ resetting the DSS, but after
         * enabling clocks.
+        *
+        * This bug was at least present on OMAP3430. It's unknown
+        * if it happens on OMAP2 or OMAP3630.
         */
        msleep(50);
+#endif
 
        _omap_dss_reset();
 
@@ -700,10 +734,11 @@ static int dss_init(void)
 
        dss.dpll4_m4_ck = dpll4_m4_ck;
 
-       dss.dsi_clk_source = DSS_CLK_SRC_FCK;
-       dss.dispc_clk_source = DSS_CLK_SRC_FCK;
-       dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK;
-       dss.lcd_clk_source[1] = DSS_CLK_SRC_FCK;
+       dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
+       dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
+       dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
+       dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
+       dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
 
        dss_save_context();
 
@@ -1015,6 +1050,14 @@ static void core_dump_clocks(struct seq_file *s)
                dss.dss_video_fck
        };
 
+       const char *names[5] = {
+               "ick",
+               "fck",
+               "sys_clk",
+               "tv_fck",
+               "video_fck"
+       };
+
        seq_printf(s, "- CORE -\n");
 
        seq_printf(s, "internal clk count\t\t%u\n", dss.num_clks_enabled);
@@ -1022,8 +1065,11 @@ static void core_dump_clocks(struct seq_file *s)
        for (i = 0; i < 5; i++) {
                if (!clocks[i])
                        continue;
-               seq_printf(s, "%-15s\t%lu\t%d\n",
+               seq_printf(s, "%s (%s)%*s\t%lu\t%d\n",
+                               names[i],
                                clocks[i]->name,
+                               24 - strlen(names[i]) - strlen(clocks[i]->name),
+                               "",
                                clk_get_rate(clocks[i]),
                                clocks[i]->usecount);
        }
index c2f582bb19c05f49f22c34e6bea1a1bd015a9cb1..8ab6d43329bb31af71feec89b876208e8ff4f054 100644 (file)
@@ -117,15 +117,6 @@ enum dss_clock {
        DSS_CLK_VIDFCK  = 1 << 4,       /* DSS_96M_FCLK*/
 };
 
-enum dss_clk_source {
-       DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC,        /* OMAP3: DSI1_PLL_FCLK
-                                                * OMAP4: PLL1_CLK1 */
-       DSS_CLK_SRC_DSI_PLL_HSDIV_DSI,          /* OMAP3: DSI2_PLL_FCLK
-                                                * OMAP4: PLL1_CLK2 */
-       DSS_CLK_SRC_FCK,                        /* OMAP2/3: DSS1_ALWON_FCLK
-                                                * OMAP4: DSS_FCLK */
-};
-
 enum dss_hdmi_venc_clk_source_select {
        DSS_VENC_TV_CLK = 0,
        DSS_HDMI_M_PCLK = 1,
@@ -236,7 +227,7 @@ void dss_clk_enable(enum dss_clock clks);
 void dss_clk_disable(enum dss_clock clks);
 unsigned long dss_clk_get_rate(enum dss_clock clk);
 int dss_need_ctx_restore(void);
-const char *dss_get_generic_clk_source_name(enum dss_clk_source clk_src);
+const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
 void dss_dump_clocks(struct seq_file *s);
 
 void dss_dump_regs(struct seq_file *s);
@@ -248,13 +239,14 @@ void dss_sdi_init(u8 datapairs);
 int dss_sdi_enable(void);
 void dss_sdi_disable(void);
 
-void dss_select_dispc_clk_source(enum dss_clk_source clk_src);
-void dss_select_dsi_clk_source(enum dss_clk_source clk_src);
+void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src);
+void dss_select_dsi_clk_source(int dsi_module,
+               enum omap_dss_clk_source clk_src);
 void dss_select_lcd_clk_source(enum omap_channel channel,
-               enum dss_clk_source clk_src);
-enum dss_clk_source dss_get_dispc_clk_source(void);
-enum dss_clk_source dss_get_dsi_clk_source(void);
-enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel);
+               enum omap_dss_clk_source clk_src);
+enum omap_dss_clk_source dss_get_dispc_clk_source(void);
+enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module);
+enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel);
 
 void dss_set_venc_output(enum omap_dss_venc_type type);
 void dss_set_dac_pwrdn_bgz(bool enable);
@@ -284,31 +276,39 @@ static inline void sdi_exit(void)
 
 /* DSI */
 #ifdef CONFIG_OMAP2_DSS_DSI
+
+struct dentry;
+struct file_operations;
+
 int dsi_init_platform_driver(void);
 void dsi_uninit_platform_driver(void);
 
 void dsi_dump_clocks(struct seq_file *s);
-void dsi_dump_irqs(struct seq_file *s);
-void dsi_dump_regs(struct seq_file *s);
+void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir,
+               const struct file_operations *debug_fops);
+void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir,
+               const struct file_operations *debug_fops);
 
 void dsi_save_context(void);
 void dsi_restore_context(void);
 
 int dsi_init_display(struct omap_dss_device *display);
 void dsi_irq_handler(void);
-unsigned long dsi_get_pll_hsdiv_dispc_rate(void);
-int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo);
-int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
-               struct dsi_clock_info *cinfo,
+unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
+int dsi_pll_set_clock_div(struct platform_device *dsidev,
+               struct dsi_clock_info *cinfo);
+int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft,
+               unsigned long req_pck, struct dsi_clock_info *cinfo,
                struct dispc_clock_info *dispc_cinfo);
-int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
+int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
                bool enable_hsdiv);
-void dsi_pll_uninit(void);
+void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
 void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
                u32 fifo_size, enum omap_burst_size *burst_size,
                u32 *fifo_low, u32 *fifo_high);
-void dsi_wait_pll_hsdiv_dispc_active(void);
-void dsi_wait_pll_hsdiv_dsi_active(void);
+void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev);
+void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev);
+struct platform_device *dsi_get_dsidev_from_id(int module);
 #else
 static inline int dsi_init_platform_driver(void)
 {
@@ -317,17 +317,47 @@ static inline int dsi_init_platform_driver(void)
 static inline void dsi_uninit_platform_driver(void)
 {
 }
-static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(void)
+static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
 {
        WARN("%s: DSI not compiled in, returning rate as 0\n", __func__);
        return 0;
 }
-static inline void dsi_wait_pll_hsdiv_dispc_active(void)
+static inline int dsi_pll_set_clock_div(struct platform_device *dsidev,
+               struct dsi_clock_info *cinfo)
+{
+       WARN("%s: DSI not compiled in\n", __func__);
+       return -ENODEV;
+}
+static inline int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,
+               bool is_tft, unsigned long req_pck,
+               struct dsi_clock_info *dsi_cinfo,
+               struct dispc_clock_info *dispc_cinfo)
+{
+       WARN("%s: DSI not compiled in\n", __func__);
+       return -ENODEV;
+}
+static inline int dsi_pll_init(struct platform_device *dsidev,
+               bool enable_hsclk, bool enable_hsdiv)
 {
+       WARN("%s: DSI not compiled in\n", __func__);
+       return -ENODEV;
 }
-static inline void dsi_wait_pll_hsdiv_dsi_active(void)
+static inline void dsi_pll_uninit(struct platform_device *dsidev,
+               bool disconnect_lanes)
 {
 }
+static inline void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev)
+{
+}
+static inline void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
+{
+}
+static inline struct platform_device *dsi_get_dsidev_from_id(int module)
+{
+       WARN("%s: DSI not compiled in, returning platform device as NULL\n",
+                       __func__);
+       return NULL;
+}
 #endif
 
 /* DPI */
@@ -391,7 +421,8 @@ int dispc_setup_plane(enum omap_plane plane,
                      enum omap_dss_rotation_type rotation_type,
                      u8 rotation, bool mirror,
                      u8 global_alpha, u8 pre_mult_alpha,
-                     enum omap_channel channel);
+                     enum omap_channel channel,
+                     u32 puv_addr);
 
 bool dispc_go_busy(enum omap_channel channel);
 void dispc_go(enum omap_channel channel);
@@ -485,13 +516,6 @@ void hdmi_panel_exit(void);
 int rfbi_init_platform_driver(void);
 void rfbi_uninit_platform_driver(void);
 void rfbi_dump_regs(struct seq_file *s);
-
-int rfbi_configure(int rfbi_module, int bpp, int lines);
-void rfbi_enable_rfbi(bool enable);
-void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
-               u16 height, void (callback)(void *data), void *data);
-void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t);
-unsigned long rfbi_get_max_tx_rate(void);
 int rfbi_init_display(struct omap_dss_device *display);
 #else
 static inline int rfbi_init_platform_driver(void)
index aa1622241d0d728612c57bda460951d251cf590d..1c18888e5df39a06548d5dbf210ddcaa4e6f2600 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 
 #include "dss.h"
@@ -52,7 +52,7 @@ struct omap_dss_features {
 };
 
 /* This struct is assigned to one of the below during initialization */
-static struct omap_dss_features *omap_current_dss_features;
+static const struct omap_dss_features *omap_current_dss_features;
 
 static const struct dss_reg_field omap2_dss_reg_fields[] = {
        [FEAT_REG_FIRHINC]                      = { 11, 0 },
@@ -177,22 +177,55 @@ static const enum omap_color_mode omap3_dss_supported_color_modes[] = {
        OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
 };
 
+static const enum omap_color_mode omap4_dss_supported_color_modes[] = {
+       /* OMAP_DSS_GFX */
+       OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
+       OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
+       OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
+       OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
+       OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
+       OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32 |
+       OMAP_DSS_COLOR_ARGB16_1555,
+
+       /* OMAP_DSS_VIDEO1 */
+       OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
+       OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
+       OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
+       OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
+       OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
+       OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
+       OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
+       OMAP_DSS_COLOR_RGBX32,
+
+       /* OMAP_DSS_VIDEO2 */
+       OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
+       OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
+       OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
+       OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
+       OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
+       OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
+       OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
+       OMAP_DSS_COLOR_RGBX32,
+};
+
 static const char * const omap2_dss_clk_source_names[] = {
-       [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]       = "N/A",
-       [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]         = "N/A",
-       [DSS_CLK_SRC_FCK]                       = "DSS_FCLK1",
+       [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]  = "N/A",
+       [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]    = "N/A",
+       [OMAP_DSS_CLK_SRC_FCK]                  = "DSS_FCLK1",
 };
 
 static const char * const omap3_dss_clk_source_names[] = {
-       [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]       = "DSI1_PLL_FCLK",
-       [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]         = "DSI2_PLL_FCLK",
-       [DSS_CLK_SRC_FCK]                       = "DSS1_ALWON_FCLK",
+       [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]  = "DSI1_PLL_FCLK",
+       [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]    = "DSI2_PLL_FCLK",
+       [OMAP_DSS_CLK_SRC_FCK]                  = "DSS1_ALWON_FCLK",
 };
 
 static const char * const omap4_dss_clk_source_names[] = {
-       [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]       = "PLL1_CLK1",
-       [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]         = "PLL1_CLK2",
-       [DSS_CLK_SRC_FCK]                       = "DSS_FCLK",
+       [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]  = "PLL1_CLK1",
+       [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]    = "PLL1_CLK2",
+       [OMAP_DSS_CLK_SRC_FCK]                  = "DSS_FCLK",
+       [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "PLL2_CLK1",
+       [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI]   = "PLL2_CLK2",
 };
 
 static const struct dss_param_range omap2_dss_param_range[] = {
@@ -226,7 +259,7 @@ static const struct dss_param_range omap4_dss_param_range[] = {
 };
 
 /* OMAP2 DSS Features */
-static struct omap_dss_features omap2_dss_features = {
+static const struct omap_dss_features omap2_dss_features = {
        .reg_fields = omap2_dss_reg_fields,
        .num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields),
 
@@ -244,7 +277,7 @@ static struct omap_dss_features omap2_dss_features = {
 };
 
 /* OMAP3 DSS Features */
-static struct omap_dss_features omap3430_dss_features = {
+static const struct omap_dss_features omap3430_dss_features = {
        .reg_fields = omap3_dss_reg_fields,
        .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
 
@@ -252,7 +285,8 @@ static struct omap_dss_features omap3430_dss_features = {
                FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
                FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
                FEAT_FUNCGATED | FEAT_ROWREPEATENABLE |
-               FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF,
+               FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF |
+               FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC,
 
        .num_mgrs = 2,
        .num_ovls = 3,
@@ -262,7 +296,7 @@ static struct omap_dss_features omap3430_dss_features = {
        .dss_params = omap3_dss_param_range,
 };
 
-static struct omap_dss_features omap3630_dss_features = {
+static const struct omap_dss_features omap3630_dss_features = {
        .reg_fields = omap3_dss_reg_fields,
        .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
 
@@ -271,7 +305,8 @@ static struct omap_dss_features omap3630_dss_features = {
                FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
                FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED |
                FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT |
-               FEAT_RESIZECONF,
+               FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG |
+               FEAT_DSI_PLL_FREQSEL,
 
        .num_mgrs = 2,
        .num_ovls = 3,
@@ -282,19 +317,43 @@ static struct omap_dss_features omap3630_dss_features = {
 };
 
 /* OMAP4 DSS Features */
-static struct omap_dss_features omap4_dss_features = {
+/* For OMAP4430 ES 1.0 revision */
+static const struct omap_dss_features omap4430_es1_0_dss_features  = {
        .reg_fields = omap4_dss_reg_fields,
        .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
 
        .has_feature    =
                FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA |
                FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 |
-               FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC,
+               FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
+               FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
+               FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2,
 
        .num_mgrs = 3,
        .num_ovls = 3,
        .supported_displays = omap4_dss_supported_displays,
-       .supported_color_modes = omap3_dss_supported_color_modes,
+       .supported_color_modes = omap4_dss_supported_color_modes,
+       .clksrc_names = omap4_dss_clk_source_names,
+       .dss_params = omap4_dss_param_range,
+};
+
+/* For all the other OMAP4 versions */
+static const struct omap_dss_features omap4_dss_features = {
+       .reg_fields = omap4_dss_reg_fields,
+       .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
+
+       .has_feature    =
+               FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA |
+               FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 |
+               FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
+               FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
+               FEAT_DSI_GNQ | FEAT_HDMI_CTS_SWMODE |
+               FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2,
+
+       .num_mgrs = 3,
+       .num_ovls = 3,
+       .supported_displays = omap4_dss_supported_displays,
+       .supported_color_modes = omap4_dss_supported_color_modes,
        .clksrc_names = omap4_dss_clk_source_names,
        .dss_params = omap4_dss_param_range,
 };
@@ -337,7 +396,7 @@ bool dss_feat_color_mode_supported(enum omap_plane plane,
                        color_mode;
 }
 
-const char *dss_feat_get_clk_source_name(enum dss_clk_source id)
+const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id)
 {
        return omap_current_dss_features->clksrc_names[id];
 }
@@ -365,6 +424,10 @@ void dss_features_init(void)
                omap_current_dss_features = &omap3630_dss_features;
        else if (cpu_is_omap34xx())
                omap_current_dss_features = &omap3430_dss_features;
-       else
+       else if (omap_rev() == OMAP4430_REV_ES1_0)
+               omap_current_dss_features = &omap4430_es1_0_dss_features;
+       else if (cpu_is_omap44xx())
                omap_current_dss_features = &omap4_dss_features;
+       else
+               DSSWARN("Unsupported OMAP version");
 }
index 12e9c4ef0dec4426fb0197c62559152f623ef703..07b346f7d916569d5c84d0d901b3f4d911dcf299 100644 (file)
 #define MAX_DSS_MANAGERS       3
 #define MAX_DSS_OVERLAYS       3
 #define MAX_DSS_LCD_MANAGERS   2
+#define MAX_NUM_DSI            2
 
 /* DSS has feature id */
 enum dss_feat_id {
-       FEAT_GLOBAL_ALPHA       = 1 << 0,
-       FEAT_GLOBAL_ALPHA_VID1  = 1 << 1,
-       FEAT_PRE_MULT_ALPHA     = 1 << 2,
-       FEAT_LCDENABLEPOL       = 1 << 3,
-       FEAT_LCDENABLESIGNAL    = 1 << 4,
-       FEAT_PCKFREEENABLE      = 1 << 5,
-       FEAT_FUNCGATED          = 1 << 6,
-       FEAT_MGR_LCD2           = 1 << 7,
-       FEAT_LINEBUFFERSPLIT    = 1 << 8,
-       FEAT_ROWREPEATENABLE    = 1 << 9,
-       FEAT_RESIZECONF         = 1 << 10,
+       FEAT_GLOBAL_ALPHA               = 1 << 0,
+       FEAT_GLOBAL_ALPHA_VID1          = 1 << 1,
+       FEAT_PRE_MULT_ALPHA             = 1 << 2,
+       FEAT_LCDENABLEPOL               = 1 << 3,
+       FEAT_LCDENABLESIGNAL            = 1 << 4,
+       FEAT_PCKFREEENABLE              = 1 << 5,
+       FEAT_FUNCGATED                  = 1 << 6,
+       FEAT_MGR_LCD2                   = 1 << 7,
+       FEAT_LINEBUFFERSPLIT            = 1 << 8,
+       FEAT_ROWREPEATENABLE            = 1 << 9,
+       FEAT_RESIZECONF                 = 1 << 10,
        /* Independent core clk divider */
-       FEAT_CORE_CLK_DIV       = 1 << 11,
-       FEAT_LCD_CLK_SRC        = 1 << 12,
+       FEAT_CORE_CLK_DIV               = 1 << 11,
+       FEAT_LCD_CLK_SRC                = 1 << 12,
+       /* DSI-PLL power command 0x3 is not working */
+       FEAT_DSI_PLL_PWR_BUG            = 1 << 13,
+       FEAT_DSI_PLL_FREQSEL            = 1 << 14,
+       FEAT_DSI_DCS_CMD_CONFIG_VC      = 1 << 15,
+       FEAT_DSI_VC_OCP_WIDTH           = 1 << 16,
+       FEAT_DSI_REVERSE_TXCLKESC       = 1 << 17,
+       FEAT_DSI_GNQ                    = 1 << 18,
+       FEAT_HDMI_CTS_SWMODE            = 1 << 19,
+       FEAT_HANDLE_UV_SEPARATE         = 1 << 20,
+       FEAT_ATTR2                      = 1 << 21,
 };
 
 /* DSS register field id */
@@ -77,7 +88,7 @@ enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel
 enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane);
 bool dss_feat_color_mode_supported(enum omap_plane plane,
                enum omap_color_mode color_mode);
-const char *dss_feat_get_clk_source_name(enum dss_clk_source id);
+const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id);
 
 bool dss_has_feature(enum dss_feat_id id);
 void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
index a981def8099ad99ef761a28392bd229de234750d..b0555f4f0a78b534c52cd427d871603d3424969f 100644 (file)
 #include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/string.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#endif
 
 #include "dss.h"
 #include "hdmi.h"
+#include "dss_features.h"
 
 static struct {
        struct mutex lock;
@@ -1052,25 +1058,26 @@ static void update_hdmi_timings(struct hdmi_config *cfg,
        cfg->timings.hsync_pol = cea_vesa_timings[code].hsync_pol;
 }
 
-static void hdmi_compute_pll(unsigned long clkin, int phy,
-       int n, struct hdmi_pll_info *pi)
+static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
+               struct hdmi_pll_info *pi)
 {
-       unsigned long refclk;
+       unsigned long clkin, refclk;
        u32 mf;
 
+       clkin = dss_clk_get_rate(DSS_CLK_SYSCK) / 10000;
        /*
         * Input clock is predivided by N + 1
         * out put of which is reference clk
         */
-       refclk = clkin / (n + 1);
-       pi->regn = n;
+       pi->regn = dssdev->clocks.hdmi.regn;
+       refclk = clkin / (pi->regn + 1);
 
        /*
         * multiplier is pixel_clk/ref_clk
         * Multiplying by 100 to avoid fractional part removal
         */
-       pi->regm = (phy * 100/(refclk))/100;
-       pi->regm2 = 1;
+       pi->regm = (phy * 100 / (refclk)) / 100;
+       pi->regm2 = dssdev->clocks.hdmi.regm2;
 
        /*
         * fractional multiplier is remainder of the difference between
@@ -1078,14 +1085,14 @@ static void hdmi_compute_pll(unsigned long clkin, int phy,
         * multiplied by 2^18(262144) divided by the reference clock
         */
        mf = (phy - pi->regm * refclk) * 262144;
-       pi->regmf = mf/(refclk);
+       pi->regmf = mf / (refclk);
 
        /*
         * Dcofreq should be set to 1 if required pixel clock
         * is greater than 1000MHz
         */
        pi->dcofreq = phy > 1000 * 100;
-       pi->regsd = ((pi->regm * clkin / 10) / ((n + 1) * 250) + 5) / 10;
+       pi->regsd = ((pi->regm * clkin / 10) / ((pi->regn + 1) * 250) + 5) / 10;
 
        DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
        DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
@@ -1106,7 +1113,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
        int r, code = 0;
        struct hdmi_pll_info pll_data;
        struct omap_video_timings *p;
-       int clkin, n, phy;
+       unsigned long phy;
 
        hdmi_enable_clocks(1);
 
@@ -1126,11 +1133,9 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
        dssdev->panel.timings = cea_vesa_timings[code].timings;
        update_hdmi_timings(&hdmi.cfg, p, code);
 
-       clkin = 3840; /* 38.4 MHz */
-       n = 15; /* this is a constant for our math */
        phy = p->pixel_clock;
 
-       hdmi_compute_pll(clkin, phy, n, &pll_data);
+       hdmi_compute_pll(dssdev, phy, &pll_data);
 
        hdmi_wp_video_start(0);
 
@@ -1160,7 +1165,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
         * dynamically by user. This can be moved to single location , say
         * Boardfile.
         */
-       dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
+       dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
 
        /* bypass TV gamma table */
        dispc_enable_gamma_table(0);
@@ -1275,10 +1280,420 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
        mutex_unlock(&hdmi.lock);
 }
 
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+static void hdmi_wp_audio_config_format(
+               struct hdmi_audio_format *aud_fmt)
+{
+       u32 r;
+
+       DSSDBG("Enter hdmi_wp_audio_config_format\n");
+
+       r = hdmi_read_reg(HDMI_WP_AUDIO_CFG);
+       r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
+       r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
+       r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
+       r = FLD_MOD(r, aud_fmt->type, 4, 4);
+       r = FLD_MOD(r, aud_fmt->justification, 3, 3);
+       r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);
+       r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1);
+       r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);
+       hdmi_write_reg(HDMI_WP_AUDIO_CFG, r);
+}
+
+static void hdmi_wp_audio_config_dma(struct hdmi_audio_dma *aud_dma)
+{
+       u32 r;
+
+       DSSDBG("Enter hdmi_wp_audio_config_dma\n");
+
+       r = hdmi_read_reg(HDMI_WP_AUDIO_CFG2);
+       r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);
+       r = FLD_MOD(r, aud_dma->block_size, 7, 0);
+       hdmi_write_reg(HDMI_WP_AUDIO_CFG2, r);
+
+       r = hdmi_read_reg(HDMI_WP_AUDIO_CTRL);
+       r = FLD_MOD(r, aud_dma->mode, 9, 9);
+       r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0);
+       hdmi_write_reg(HDMI_WP_AUDIO_CTRL, r);
+}
+
+static void hdmi_core_audio_config(struct hdmi_core_audio_config *cfg)
+{
+       u32 r;
+
+       /* audio clock recovery parameters */
+       r = hdmi_read_reg(HDMI_CORE_AV_ACR_CTRL);
+       r = FLD_MOD(r, cfg->use_mclk, 2, 2);
+       r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1);
+       r = FLD_MOD(r, cfg->cts_mode, 0, 0);
+       hdmi_write_reg(HDMI_CORE_AV_ACR_CTRL, r);
+
+       REG_FLD_MOD(HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0);
+       REG_FLD_MOD(HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0);
+       REG_FLD_MOD(HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0);
+
+       if (cfg->cts_mode == HDMI_AUDIO_CTS_MODE_SW) {
+               REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL1, cfg->cts, 7, 0);
+               REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL2, cfg->cts >> 8, 7, 0);
+               REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0);
+       } else {
+               /*
+                * HDMI IP uses this configuration to divide the MCLK to
+                * update CTS value.
+                */
+               REG_FLD_MOD(HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0);
+
+               /* Configure clock for audio packets */
+               REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_1,
+                       cfg->aud_par_busclk, 7, 0);
+               REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_2,
+                       (cfg->aud_par_busclk >> 8), 7, 0);
+               REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_3,
+                       (cfg->aud_par_busclk >> 16), 7, 0);
+       }
+
+       /* Override of SPDIF sample frequency with value in I2S_CHST4 */
+       REG_FLD_MOD(HDMI_CORE_AV_SPDIF_CTRL, cfg->fs_override, 1, 1);
+
+       /* I2S parameters */
+       REG_FLD_MOD(HDMI_CORE_AV_I2S_CHST4, cfg->freq_sample, 3, 0);
+
+       r = hdmi_read_reg(HDMI_CORE_AV_I2S_IN_CTRL);
+       r = FLD_MOD(r, cfg->i2s_cfg.en_high_bitrate_aud, 7, 7);
+       r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6);
+       r = FLD_MOD(r, cfg->i2s_cfg.cbit_order, 5, 5);
+       r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4);
+       r = FLD_MOD(r, cfg->i2s_cfg.ws_polarity, 3, 3);
+       r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2);
+       r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1);
+       r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0);
+       hdmi_write_reg(HDMI_CORE_AV_I2S_IN_CTRL, r);
+
+       r = hdmi_read_reg(HDMI_CORE_AV_I2S_CHST5);
+       r = FLD_MOD(r, cfg->freq_sample, 7, 4);
+       r = FLD_MOD(r, cfg->i2s_cfg.word_length, 3, 1);
+       r = FLD_MOD(r, cfg->i2s_cfg.word_max_length, 0, 0);
+       hdmi_write_reg(HDMI_CORE_AV_I2S_CHST5, r);
+
+       REG_FLD_MOD(HDMI_CORE_AV_I2S_IN_LEN, cfg->i2s_cfg.in_length_bits, 3, 0);
+
+       /* Audio channels and mode parameters */
+       REG_FLD_MOD(HDMI_CORE_AV_HDMI_CTRL, cfg->layout, 2, 1);
+       r = hdmi_read_reg(HDMI_CORE_AV_AUD_MODE);
+       r = FLD_MOD(r, cfg->i2s_cfg.active_sds, 7, 4);
+       r = FLD_MOD(r, cfg->en_dsd_audio, 3, 3);
+       r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2);
+       r = FLD_MOD(r, cfg->en_spdif, 1, 1);
+       hdmi_write_reg(HDMI_CORE_AV_AUD_MODE, r);
+}
+
+static void hdmi_core_audio_infoframe_config(
+               struct hdmi_core_infoframe_audio *info_aud)
+{
+       u8 val;
+       u8 sum = 0, checksum = 0;
+
+       /*
+        * Set audio info frame type, version and length as
+        * described in HDMI 1.4a Section 8.2.2 specification.
+        * Checksum calculation is defined in Section 5.3.5.
+        */
+       hdmi_write_reg(HDMI_CORE_AV_AUDIO_TYPE, 0x84);
+       hdmi_write_reg(HDMI_CORE_AV_AUDIO_VERS, 0x01);
+       hdmi_write_reg(HDMI_CORE_AV_AUDIO_LEN, 0x0a);
+       sum += 0x84 + 0x001 + 0x00a;
+
+       val = (info_aud->db1_coding_type << 4)
+                       | (info_aud->db1_channel_count - 1);
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(0), val);
+       sum += val;
+
+       val = (info_aud->db2_sample_freq << 2) | info_aud->db2_sample_size;
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(1), val);
+       sum += val;
+
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(2), 0x00);
+
+       val = info_aud->db4_channel_alloc;
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(3), val);
+       sum += val;
+
+       val = (info_aud->db5_downmix_inh << 7) | (info_aud->db5_lsv << 3);
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(4), val);
+       sum += val;
+
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(5), 0x00);
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(6), 0x00);
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(7), 0x00);
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(8), 0x00);
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(9), 0x00);
+
+       checksum = 0x100 - sum;
+       hdmi_write_reg(HDMI_CORE_AV_AUDIO_CHSUM, checksum);
+
+       /*
+        * TODO: Add MPEG and SPD enable and repeat cfg when EDID parsing
+        * is available.
+        */
+}
+
+static int hdmi_config_audio_acr(u32 sample_freq, u32 *n, u32 *cts)
+{
+       u32 r;
+       u32 deep_color = 0;
+       u32 pclk = hdmi.cfg.timings.timings.pixel_clock;
+
+       if (n == NULL || cts == NULL)
+               return -EINVAL;
+       /*
+        * Obtain current deep color configuration. This needed
+        * to calculate the TMDS clock based on the pixel clock.
+        */
+       r = REG_GET(HDMI_WP_VIDEO_CFG, 1, 0);
+       switch (r) {
+       case 1: /* No deep color selected */
+               deep_color = 100;
+               break;
+       case 2: /* 10-bit deep color selected */
+               deep_color = 125;
+               break;
+       case 3: /* 12-bit deep color selected */
+               deep_color = 150;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (sample_freq) {
+       case 32000:
+               if ((deep_color == 125) && ((pclk == 54054)
+                               || (pclk == 74250)))
+                       *n = 8192;
+               else
+                       *n = 4096;
+               break;
+       case 44100:
+               *n = 6272;
+               break;
+       case 48000:
+               if ((deep_color == 125) && ((pclk == 54054)
+                               || (pclk == 74250)))
+                       *n = 8192;
+               else
+                       *n = 6144;
+               break;
+       default:
+               *n = 0;
+               return -EINVAL;
+       }
+
+       /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
+       *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10);
+
+       return 0;
+}
+
+static int hdmi_audio_hw_params(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_hw_params *params,
+                                   struct snd_soc_dai *dai)
+{
+       struct hdmi_audio_format audio_format;
+       struct hdmi_audio_dma audio_dma;
+       struct hdmi_core_audio_config core_cfg;
+       struct hdmi_core_infoframe_audio aud_if_cfg;
+       int err, n, cts;
+       enum hdmi_core_audio_sample_freq sample_freq;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               core_cfg.i2s_cfg.word_max_length =
+                       HDMI_AUDIO_I2S_MAX_WORD_20BITS;
+               core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_16_BITS;
+               core_cfg.i2s_cfg.in_length_bits =
+                       HDMI_AUDIO_I2S_INPUT_LENGTH_16;
+               core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT;
+               audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES;
+               audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS;
+               audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT;
+               audio_dma.transfer_size = 0x10;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               core_cfg.i2s_cfg.word_max_length =
+                       HDMI_AUDIO_I2S_MAX_WORD_24BITS;
+               core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_24_BITS;
+               core_cfg.i2s_cfg.in_length_bits =
+                       HDMI_AUDIO_I2S_INPUT_LENGTH_24;
+               audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE;
+               audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS;
+               audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
+               core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
+               audio_dma.transfer_size = 0x20;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (params_rate(params)) {
+       case 32000:
+               sample_freq = HDMI_AUDIO_FS_32000;
+               break;
+       case 44100:
+               sample_freq = HDMI_AUDIO_FS_44100;
+               break;
+       case 48000:
+               sample_freq = HDMI_AUDIO_FS_48000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       err = hdmi_config_audio_acr(params_rate(params), &n, &cts);
+       if (err < 0)
+               return err;
+
+       /* Audio wrapper config */
+       audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL;
+       audio_format.active_chnnls_msk = 0x03;
+       audio_format.type = HDMI_AUDIO_TYPE_LPCM;
+       audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
+       /* Disable start/stop signals of IEC 60958 blocks */
+       audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF;
+
+       audio_dma.block_size = 0xC0;
+       audio_dma.mode = HDMI_AUDIO_TRANSF_DMA;
+       audio_dma.fifo_threshold = 0x20; /* in number of samples */
+
+       hdmi_wp_audio_config_dma(&audio_dma);
+       hdmi_wp_audio_config_format(&audio_format);
+
+       /*
+        * I2S config
+        */
+       core_cfg.i2s_cfg.en_high_bitrate_aud = false;
+       /* Only used with high bitrate audio */
+       core_cfg.i2s_cfg.cbit_order = false;
+       /* Serial data and word select should change on sck rising edge */
+       core_cfg.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING;
+       core_cfg.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM;
+       /* Set I2S word select polarity */
+       core_cfg.i2s_cfg.ws_polarity = HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT;
+       core_cfg.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST;
+       /* Set serial data to word select shift. See Phillips spec. */
+       core_cfg.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT;
+       /* Enable one of the four available serial data channels */
+       core_cfg.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN;
+
+       /* Core audio config */
+       core_cfg.freq_sample = sample_freq;
+       core_cfg.n = n;
+       core_cfg.cts = cts;
+       if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) {
+               core_cfg.aud_par_busclk = 0;
+               core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_SW;
+               core_cfg.use_mclk = false;
+       } else {
+               core_cfg.aud_par_busclk = (((128 * 31) - 1) << 8);
+               core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_HW;
+               core_cfg.use_mclk = true;
+               core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS;
+       }
+       core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH;
+       core_cfg.en_spdif = false;
+       /* Use sample frequency from channel status word */
+       core_cfg.fs_override = true;
+       /* Enable ACR packets */
+       core_cfg.en_acr_pkt = true;
+       /* Disable direct streaming digital audio */
+       core_cfg.en_dsd_audio = false;
+       /* Use parallel audio interface */
+       core_cfg.en_parallel_aud_input = true;
+
+       hdmi_core_audio_config(&core_cfg);
+
+       /*
+        * Configure packet
+        * info frame audio see doc CEA861-D page 74
+        */
+       aud_if_cfg.db1_coding_type = HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM;
+       aud_if_cfg.db1_channel_count = 2;
+       aud_if_cfg.db2_sample_freq = HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM;
+       aud_if_cfg.db2_sample_size = HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM;
+       aud_if_cfg.db4_channel_alloc = 0x00;
+       aud_if_cfg.db5_downmix_inh = false;
+       aud_if_cfg.db5_lsv = 0;
+
+       hdmi_core_audio_infoframe_config(&aud_if_cfg);
+       return 0;
+}
+
+static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd,
+                                 struct snd_soc_dai *dai)
+{
+       int err = 0;
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 1, 0, 0);
+               REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 31, 31);
+               REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 30, 30);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 0, 0, 0);
+               REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 30, 30);
+               REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 31, 31);
+               break;
+       default:
+               err = -EINVAL;
+       }
+       return err;
+}
+
+static int hdmi_audio_startup(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *dai)
+{
+       if (!hdmi.mode) {
+               pr_err("Current video settings do not support audio.\n");
+               return -EIO;
+       }
+       return 0;
+}
+
+static struct snd_soc_codec_driver hdmi_audio_codec_drv = {
+};
+
+static struct snd_soc_dai_ops hdmi_audio_codec_ops = {
+       .hw_params = hdmi_audio_hw_params,
+       .trigger = hdmi_audio_trigger,
+       .startup = hdmi_audio_startup,
+};
+
+static struct snd_soc_dai_driver hdmi_codec_dai_drv = {
+               .name = "hdmi-audio-codec",
+               .playback = {
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_32000 |
+                               SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                               SNDRV_PCM_FMTBIT_S24_LE,
+               },
+               .ops = &hdmi_audio_codec_ops,
+};
+#endif
+
 /* HDMI HW IP initialisation */
 static int omapdss_hdmihw_probe(struct platform_device *pdev)
 {
        struct resource *hdmi_mem;
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+       int ret;
+#endif
 
        hdmi.pdata = pdev->dev.platform_data;
        hdmi.pdev = pdev;
@@ -1300,6 +1715,17 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
 
        hdmi_panel_init();
 
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+
+       /* Register ASoC codec DAI */
+       ret = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv,
+                                       &hdmi_codec_dai_drv, 1);
+       if (ret) {
+               DSSERR("can't register ASoC HDMI audio codec\n");
+               return ret;
+       }
+#endif
        return 0;
 }
 
@@ -1307,6 +1733,11 @@ static int omapdss_hdmihw_remove(struct platform_device *pdev)
 {
        hdmi_panel_exit();
 
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+       snd_soc_unregister_codec(&pdev->dev);
+#endif
+
        iounmap(hdmi.base_wp);
 
        return 0;
index 9887ab96da3c563a908fa510441201c8c0d0b255..c885f9cb0659154b80b67f9a35e57004066b88f0 100644 (file)
@@ -22,7 +22,7 @@
 #define _OMAP4_DSS_HDMI_H_
 
 #include <linux/string.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define HDMI_WP                0x0
 #define HDMI_CORE_SYS          0x400
@@ -48,6 +48,10 @@ struct hdmi_reg { u16 idx; };
 #define HDMI_WP_VIDEO_TIMING_H                 HDMI_WP_REG(0x68)
 #define HDMI_WP_VIDEO_TIMING_V                 HDMI_WP_REG(0x6C)
 #define HDMI_WP_WP_CLK                         HDMI_WP_REG(0x70)
+#define HDMI_WP_AUDIO_CFG                      HDMI_WP_REG(0x80)
+#define HDMI_WP_AUDIO_CFG2                     HDMI_WP_REG(0x84)
+#define HDMI_WP_AUDIO_CTRL                     HDMI_WP_REG(0x88)
+#define HDMI_WP_AUDIO_DATA                     HDMI_WP_REG(0x8C)
 
 /* HDMI IP Core System */
 #define HDMI_CORE_SYS_REG(idx)                 HDMI_REG(HDMI_CORE_SYS + idx)
@@ -105,6 +109,8 @@ struct hdmi_reg { u16 idx; };
 #define HDMI_CORE_AV_AVI_DBYTE_NELEMS          HDMI_CORE_AV_REG(15)
 #define HDMI_CORE_AV_SPD_DBYTE                 HDMI_CORE_AV_REG(0x190)
 #define HDMI_CORE_AV_SPD_DBYTE_NELEMS          HDMI_CORE_AV_REG(27)
+#define HDMI_CORE_AV_AUD_DBYTE(n)              HDMI_CORE_AV_REG(n * 4 + 0x210)
+#define HDMI_CORE_AV_AUD_DBYTE_NELEMS          HDMI_CORE_AV_REG(10)
 #define HDMI_CORE_AV_MPEG_DBYTE                HDMI_CORE_AV_REG(0x290)
 #define HDMI_CORE_AV_MPEG_DBYTE_NELEMS         HDMI_CORE_AV_REG(27)
 #define HDMI_CORE_AV_GEN_DBYTE                 HDMI_CORE_AV_REG(0x300)
@@ -153,6 +159,10 @@ struct hdmi_reg { u16 idx; };
 #define HDMI_CORE_AV_SPD_VERS                  HDMI_CORE_AV_REG(0x184)
 #define HDMI_CORE_AV_SPD_LEN                   HDMI_CORE_AV_REG(0x188)
 #define HDMI_CORE_AV_SPD_CHSUM                 HDMI_CORE_AV_REG(0x18C)
+#define HDMI_CORE_AV_AUDIO_TYPE                HDMI_CORE_AV_REG(0x200)
+#define HDMI_CORE_AV_AUDIO_VERS                HDMI_CORE_AV_REG(0x204)
+#define HDMI_CORE_AV_AUDIO_LEN                 HDMI_CORE_AV_REG(0x208)
+#define HDMI_CORE_AV_AUDIO_CHSUM               HDMI_CORE_AV_REG(0x20C)
 #define HDMI_CORE_AV_MPEG_TYPE                 HDMI_CORE_AV_REG(0x280)
 #define HDMI_CORE_AV_MPEG_VERS                 HDMI_CORE_AV_REG(0x284)
 #define HDMI_CORE_AV_MPEG_LEN                  HDMI_CORE_AV_REG(0x288)
@@ -272,7 +282,7 @@ enum hdmi_core_packet_ctrl {
        HDMI_PACKETREPEATOFF = 0
 };
 
-/* INFOFRAME_AVI_ definitions */
+/* INFOFRAME_AVI_ and INFOFRAME_AUDIO_ definitions */
 enum hdmi_core_infoframe {
        HDMI_INFOFRAME_AVI_DB1Y_RGB = 0,
        HDMI_INFOFRAME_AVI_DB1Y_YUV422 = 1,
@@ -317,7 +327,36 @@ enum hdmi_core_infoframe {
        HDMI_INFOFRAME_AVI_DB5PR_7 = 6,
        HDMI_INFOFRAME_AVI_DB5PR_8 = 7,
        HDMI_INFOFRAME_AVI_DB5PR_9 = 8,
-       HDMI_INFOFRAME_AVI_DB5PR_10 = 9
+       HDMI_INFOFRAME_AVI_DB5PR_10 = 9,
+       HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM = 0,
+       HDMI_INFOFRAME_AUDIO_DB1CT_IEC60958 = 1,
+       HDMI_INFOFRAME_AUDIO_DB1CT_AC3 = 2,
+       HDMI_INFOFRAME_AUDIO_DB1CT_MPEG1 = 3,
+       HDMI_INFOFRAME_AUDIO_DB1CT_MP3 = 4,
+       HDMI_INFOFRAME_AUDIO_DB1CT_MPEG2_MULTICH = 5,
+       HDMI_INFOFRAME_AUDIO_DB1CT_AAC = 6,
+       HDMI_INFOFRAME_AUDIO_DB1CT_DTS = 7,
+       HDMI_INFOFRAME_AUDIO_DB1CT_ATRAC = 8,
+       HDMI_INFOFRAME_AUDIO_DB1CT_ONEBIT = 9,
+       HDMI_INFOFRAME_AUDIO_DB1CT_DOLBY_DIGITAL_PLUS = 10,
+       HDMI_INFOFRAME_AUDIO_DB1CT_DTS_HD = 11,
+       HDMI_INFOFRAME_AUDIO_DB1CT_MAT = 12,
+       HDMI_INFOFRAME_AUDIO_DB1CT_DST = 13,
+       HDMI_INFOFRAME_AUDIO_DB1CT_WMA_PRO = 14,
+       HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM = 0,
+       HDMI_INFOFRAME_AUDIO_DB2SF_32000 = 1,
+       HDMI_INFOFRAME_AUDIO_DB2SF_44100 = 2,
+       HDMI_INFOFRAME_AUDIO_DB2SF_48000 = 3,
+       HDMI_INFOFRAME_AUDIO_DB2SF_88200 = 4,
+       HDMI_INFOFRAME_AUDIO_DB2SF_96000 = 5,
+       HDMI_INFOFRAME_AUDIO_DB2SF_176400 = 6,
+       HDMI_INFOFRAME_AUDIO_DB2SF_192000 = 7,
+       HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM = 0,
+       HDMI_INFOFRAME_AUDIO_DB2SS_16BIT = 1,
+       HDMI_INFOFRAME_AUDIO_DB2SS_20BIT = 2,
+       HDMI_INFOFRAME_AUDIO_DB2SS_24BIT = 3,
+       HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PERMITTED = 0,
+       HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PROHIBITED = 1
 };
 
 enum hdmi_packing_mode {
@@ -327,6 +366,121 @@ enum hdmi_packing_mode {
        HDMI_PACK_ALREADYPACKED = 7
 };
 
+enum hdmi_core_audio_sample_freq {
+       HDMI_AUDIO_FS_32000 = 0x3,
+       HDMI_AUDIO_FS_44100 = 0x0,
+       HDMI_AUDIO_FS_48000 = 0x2,
+       HDMI_AUDIO_FS_88200 = 0x8,
+       HDMI_AUDIO_FS_96000 = 0xA,
+       HDMI_AUDIO_FS_176400 = 0xC,
+       HDMI_AUDIO_FS_192000 = 0xE,
+       HDMI_AUDIO_FS_NOT_INDICATED = 0x1
+};
+
+enum hdmi_core_audio_layout {
+       HDMI_AUDIO_LAYOUT_2CH = 0,
+       HDMI_AUDIO_LAYOUT_8CH = 1
+};
+
+enum hdmi_core_cts_mode {
+       HDMI_AUDIO_CTS_MODE_HW = 0,
+       HDMI_AUDIO_CTS_MODE_SW = 1
+};
+
+enum hdmi_stereo_channels {
+       HDMI_AUDIO_STEREO_NOCHANNELS = 0,
+       HDMI_AUDIO_STEREO_ONECHANNEL = 1,
+       HDMI_AUDIO_STEREO_TWOCHANNELS = 2,
+       HDMI_AUDIO_STEREO_THREECHANNELS = 3,
+       HDMI_AUDIO_STEREO_FOURCHANNELS = 4
+};
+
+enum hdmi_audio_type {
+       HDMI_AUDIO_TYPE_LPCM = 0,
+       HDMI_AUDIO_TYPE_IEC = 1
+};
+
+enum hdmi_audio_justify {
+       HDMI_AUDIO_JUSTIFY_LEFT = 0,
+       HDMI_AUDIO_JUSTIFY_RIGHT = 1
+};
+
+enum hdmi_audio_sample_order {
+       HDMI_AUDIO_SAMPLE_RIGHT_FIRST = 0,
+       HDMI_AUDIO_SAMPLE_LEFT_FIRST = 1
+};
+
+enum hdmi_audio_samples_perword {
+       HDMI_AUDIO_ONEWORD_ONESAMPLE = 0,
+       HDMI_AUDIO_ONEWORD_TWOSAMPLES = 1
+};
+
+enum hdmi_audio_sample_size {
+       HDMI_AUDIO_SAMPLE_16BITS = 0,
+       HDMI_AUDIO_SAMPLE_24BITS = 1
+};
+
+enum hdmi_audio_transf_mode {
+       HDMI_AUDIO_TRANSF_DMA = 0,
+       HDMI_AUDIO_TRANSF_IRQ = 1
+};
+
+enum hdmi_audio_blk_strt_end_sig {
+       HDMI_AUDIO_BLOCK_SIG_STARTEND_ON = 0,
+       HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF = 1
+};
+
+enum hdmi_audio_i2s_config {
+       HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT = 0,
+       HDMI_AUDIO_I2S_WS_POLARIT_YLOW_IS_RIGHT = 1,
+       HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0,
+       HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1,
+       HDMI_AUDIO_I2S_MAX_WORD_20BITS = 0,
+       HDMI_AUDIO_I2S_MAX_WORD_24BITS = 1,
+       HDMI_AUDIO_I2S_CHST_WORD_NOT_SPECIFIED = 0,
+       HDMI_AUDIO_I2S_CHST_WORD_16_BITS = 1,
+       HDMI_AUDIO_I2S_CHST_WORD_17_BITS = 6,
+       HDMI_AUDIO_I2S_CHST_WORD_18_BITS = 2,
+       HDMI_AUDIO_I2S_CHST_WORD_19_BITS = 4,
+       HDMI_AUDIO_I2S_CHST_WORD_20_BITS_20MAX = 5,
+       HDMI_AUDIO_I2S_CHST_WORD_20_BITS_24MAX = 1,
+       HDMI_AUDIO_I2S_CHST_WORD_21_BITS = 6,
+       HDMI_AUDIO_I2S_CHST_WORD_22_BITS = 2,
+       HDMI_AUDIO_I2S_CHST_WORD_23_BITS = 4,
+       HDMI_AUDIO_I2S_CHST_WORD_24_BITS = 5,
+       HDMI_AUDIO_I2S_SCK_EDGE_FALLING = 0,
+       HDMI_AUDIO_I2S_SCK_EDGE_RISING = 1,
+       HDMI_AUDIO_I2S_VBIT_FOR_PCM = 0,
+       HDMI_AUDIO_I2S_VBIT_FOR_COMPRESSED = 1,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_NA = 0,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_16 = 2,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_17 = 12,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_18 = 4,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_19 = 8,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_20 = 10,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_21 = 13,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_22 = 5,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_23 = 9,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_24 = 11,
+       HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0,
+       HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1,
+       HDMI_AUDIO_I2S_SD0_EN = 1,
+       HDMI_AUDIO_I2S_SD1_EN = 1 << 1,
+       HDMI_AUDIO_I2S_SD2_EN = 1 << 2,
+       HDMI_AUDIO_I2S_SD3_EN = 1 << 3,
+};
+
+enum hdmi_audio_mclk_mode {
+       HDMI_AUDIO_MCLK_128FS = 0,
+       HDMI_AUDIO_MCLK_256FS = 1,
+       HDMI_AUDIO_MCLK_384FS = 2,
+       HDMI_AUDIO_MCLK_512FS = 3,
+       HDMI_AUDIO_MCLK_768FS = 4,
+       HDMI_AUDIO_MCLK_1024FS = 5,
+       HDMI_AUDIO_MCLK_1152FS = 6,
+       HDMI_AUDIO_MCLK_192FS = 7
+};
+
 struct hdmi_core_video_config {
        enum hdmi_core_inputbus_width   ip_bus_width;
        enum hdmi_core_dither_trunc     op_dither_truc;
@@ -376,6 +530,19 @@ struct hdmi_core_infoframe_avi {
        u16     db12_13_pixel_sofright;
                /* Pixel number start of right bar */
 };
+/*
+ * Refer to section 8.2 in HDMI 1.3 specification for
+ * details about infoframe databytes
+ */
+struct hdmi_core_infoframe_audio {
+       u8 db1_coding_type;
+       u8 db1_channel_count;
+       u8 db2_sample_freq;
+       u8 db2_sample_size;
+       u8 db4_channel_alloc;
+       bool db5_downmix_inh;
+       u8 db5_lsv;     /* Level shift values for downmix */
+};
 
 struct hdmi_core_packet_enable_repeat {
        u32     audio_pkt;
@@ -412,4 +579,53 @@ struct hdmi_config {
        struct hdmi_cm cm;
 };
 
+struct hdmi_audio_format {
+       enum hdmi_stereo_channels               stereo_channels;
+       u8                                      active_chnnls_msk;
+       enum hdmi_audio_type                    type;
+       enum hdmi_audio_justify                 justification;
+       enum hdmi_audio_sample_order            sample_order;
+       enum hdmi_audio_samples_perword         samples_per_word;
+       enum hdmi_audio_sample_size             sample_size;
+       enum hdmi_audio_blk_strt_end_sig        en_sig_blk_strt_end;
+};
+
+struct hdmi_audio_dma {
+       u8                              transfer_size;
+       u8                              block_size;
+       enum hdmi_audio_transf_mode     mode;
+       u16                             fifo_threshold;
+};
+
+struct hdmi_core_audio_i2s_config {
+       u8 word_max_length;
+       u8 word_length;
+       u8 in_length_bits;
+       u8 justification;
+       u8 en_high_bitrate_aud;
+       u8 sck_edge_mode;
+       u8 cbit_order;
+       u8 vbit;
+       u8 ws_polarity;
+       u8 direction;
+       u8 shift;
+       u8 active_sds;
+};
+
+struct hdmi_core_audio_config {
+       struct hdmi_core_audio_i2s_config       i2s_cfg;
+       enum hdmi_core_audio_sample_freq        freq_sample;
+       bool                                    fs_override;
+       u32                                     n;
+       u32                                     cts;
+       u32                                     aud_par_busclk;
+       enum hdmi_core_audio_layout             layout;
+       enum hdmi_core_cts_mode                 cts_mode;
+       bool                                    use_mclk;
+       enum hdmi_audio_mclk_mode               mclk_mode;
+       bool                                    en_acr_pkt;
+       bool                                    en_dsd_audio;
+       bool                                    en_parallel_aud_input;
+       bool                                    en_spdif;
+};
 #endif
index ffb5de94131faa402c0ec5a33272918ac44fdda5..7d4f2bd7c50619591cbba2c6fb76bbafaa8ae6a5 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/io.h>
 #include <linux/mutex.h>
 #include <linux/module.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #include "dss.h"
 
index bcd37ec86952fae81d0327366833503717de520e..9aeea50e33ffd49f5fc6376746c76c950caffc92 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/spinlock.h>
 #include <linux/jiffies.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 
 #include "dss.h"
@@ -393,6 +393,7 @@ struct overlay_cache_data {
 
        u32 paddr;
        void __iomem *vaddr;
+       u32 p_uv_addr; /* relevant for NV12 format only */
        u16 screen_width;
        u16 width;
        u16 height;
@@ -775,10 +776,17 @@ static int configure_overlay(enum omap_plane plane)
                }
 
                switch (c->color_mode) {
+               case OMAP_DSS_COLOR_NV12:
+                       bpp = 8;
+                       break;
                case OMAP_DSS_COLOR_RGB16:
                case OMAP_DSS_COLOR_ARGB16:
                case OMAP_DSS_COLOR_YUV2:
                case OMAP_DSS_COLOR_UYVY:
+               case OMAP_DSS_COLOR_RGBA16:
+               case OMAP_DSS_COLOR_RGBX16:
+               case OMAP_DSS_COLOR_ARGB16_1555:
+               case OMAP_DSS_COLOR_XRGB16_1555:
                        bpp = 16;
                        break;
 
@@ -854,7 +862,8 @@ static int configure_overlay(enum omap_plane plane)
                        c->mirror,
                        c->global_alpha,
                        c->pre_mult_alpha,
-                       c->channel);
+                       c->channel,
+                       c->p_uv_addr);
 
        if (r) {
                /* this shouldn't happen */
@@ -1269,6 +1278,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
 
                oc->paddr = ovl->info.paddr;
                oc->vaddr = ovl->info.vaddr;
+               oc->p_uv_addr = ovl->info.p_uv_addr;
                oc->screen_width = ovl->info.screen_width;
                oc->width = ovl->info.width;
                oc->height = ovl->info.height;
index f1aca6d0401117c9858a4300b5dfe0748a7863e4..0f08025b1f0e95b9e65fb597d0fd63a16609f970 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 
 #include "dss.h"
@@ -201,12 +201,16 @@ static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
 static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
                size_t size)
 {
-       int r;
+       int r, enable;
        struct omap_overlay_info info;
 
        ovl->get_overlay_info(ovl, &info);
 
-       info.enabled = simple_strtoul(buf, NULL, 10);
+       r = kstrtoint(buf, 0, &enable);
+       if (r)
+               return r;
+
+       info.enabled = !!enable;
 
        r = ovl->set_overlay_info(ovl, &info);
        if (r)
@@ -231,8 +235,13 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
                const char *buf, size_t size)
 {
        int r;
+       u8 alpha;
        struct omap_overlay_info info;
 
+       r = kstrtou8(buf, 0, &alpha);
+       if (r)
+               return r;
+
        ovl->get_overlay_info(ovl, &info);
 
        /* Video1 plane does not support global alpha
@@ -242,7 +251,7 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
                        ovl->id == OMAP_DSS_VIDEO1)
                info.global_alpha = 255;
        else
-               info.global_alpha = simple_strtoul(buf, NULL, 10);
+               info.global_alpha = alpha;
 
        r = ovl->set_overlay_info(ovl, &info);
        if (r)
@@ -268,8 +277,13 @@ static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
                const char *buf, size_t size)
 {
        int r;
+       u8 alpha;
        struct omap_overlay_info info;
 
+       r = kstrtou8(buf, 0, &alpha);
+       if (r)
+               return r;
+
        ovl->get_overlay_info(ovl, &info);
 
        /* only GFX and Video2 plane support pre alpha multiplied
@@ -279,7 +293,7 @@ static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
                ovl->id == OMAP_DSS_VIDEO1)
                info.pre_mult_alpha = 0;
        else
-               info.pre_mult_alpha = simple_strtoul(buf, NULL, 10);
+               info.pre_mult_alpha = alpha;
 
        r = ovl->set_overlay_info(ovl, &info);
        if (r)
@@ -491,13 +505,18 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
        ovl->manager = mgr;
 
        dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
-       /* XXX: on manual update display, in auto update mode, a bug happens
-        * here. When an overlay is first enabled on LCD, then it's disabled,
-        * and the manager is changed to TV, we sometimes get SYNC_LOST_DIGIT
-        * errors. Waiting before changing the channel_out fixes it. I'm
-        * guessing that the overlay is still somehow being used for the LCD,
-        * but I don't understand how or why. */
-       msleep(40);
+       /* XXX: When there is an overlay on a DSI manual update display, and
+        * the overlay is first disabled, then moved to tv, and enabled, we
+        * seem to get SYNC_LOST_DIGIT error.
+        *
+        * Waiting doesn't seem to help, but updating the manual update display
+        * after disabling the overlay seems to fix this. This hints that the
+        * overlay is perhaps somehow tied to the LCD output until the output
+        * is updated.
+        *
+        * Userspace workaround for this is to update the LCD after disabling
+        * the overlay, but before moving the overlay to TV.
+        */
        dispc_set_channel_out(ovl->id, mgr->id);
        dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
index 5ea17f49c6110c3d3703c89b34e5f52e366f67ce..c06fbe0bc6789bee3c32a796b1b9efdb4efc763d 100644 (file)
@@ -32,8 +32,9 @@
 #include <linux/ktime.h>
 #include <linux/hrtimer.h>
 #include <linux/seq_file.h>
+#include <linux/semaphore.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include "dss.h"
 
 struct rfbi_reg { u16 idx; };
@@ -65,9 +66,6 @@ struct rfbi_reg { u16 idx; };
 #define REG_FLD_MOD(idx, val, start, end) \
        rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end))
 
-/* To work around an RFBI transfer rate limitation */
-#define OMAP_RFBI_RATE_LIMIT    1
-
 enum omap_rfbi_cycleformat {
        OMAP_DSS_RFBI_CYCLEFORMAT_1_1 = 0,
        OMAP_DSS_RFBI_CYCLEFORMAT_2_1 = 1,
@@ -89,11 +87,6 @@ enum omap_rfbi_parallelmode {
        OMAP_DSS_RFBI_PARALLELMODE_16 = 3,
 };
 
-enum update_cmd {
-       RFBI_CMD_UPDATE = 0,
-       RFBI_CMD_SYNC   = 1,
-};
-
 static int rfbi_convert_timings(struct rfbi_timings *t);
 static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
 
@@ -114,20 +107,9 @@ static struct {
 
        struct omap_dss_device *dssdev[2];
 
-       struct kfifo      cmd_fifo;
-       spinlock_t        cmd_lock;
-       struct completion cmd_done;
-       atomic_t          cmd_fifo_full;
-       atomic_t          cmd_pending;
+       struct semaphore bus_lock;
 } rfbi;
 
-struct update_region {
-       u16     x;
-       u16     y;
-       u16     w;
-       u16     h;
-};
-
 static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
 {
        __raw_writel(val, rfbi.base + idx.idx);
@@ -146,9 +128,20 @@ static void rfbi_enable_clocks(bool enable)
                dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 }
 
+void rfbi_bus_lock(void)
+{
+       down(&rfbi.bus_lock);
+}
+EXPORT_SYMBOL(rfbi_bus_lock);
+
+void rfbi_bus_unlock(void)
+{
+       up(&rfbi.bus_lock);
+}
+EXPORT_SYMBOL(rfbi_bus_unlock);
+
 void omap_rfbi_write_command(const void *buf, u32 len)
 {
-       rfbi_enable_clocks(1);
        switch (rfbi.parallelmode) {
        case OMAP_DSS_RFBI_PARALLELMODE_8:
        {
@@ -172,13 +165,11 @@ void omap_rfbi_write_command(const void *buf, u32 len)
        default:
                BUG();
        }
-       rfbi_enable_clocks(0);
 }
 EXPORT_SYMBOL(omap_rfbi_write_command);
 
 void omap_rfbi_read_data(void *buf, u32 len)
 {
-       rfbi_enable_clocks(1);
        switch (rfbi.parallelmode) {
        case OMAP_DSS_RFBI_PARALLELMODE_8:
        {
@@ -206,13 +197,11 @@ void omap_rfbi_read_data(void *buf, u32 len)
        default:
                BUG();
        }
-       rfbi_enable_clocks(0);
 }
 EXPORT_SYMBOL(omap_rfbi_read_data);
 
 void omap_rfbi_write_data(const void *buf, u32 len)
 {
-       rfbi_enable_clocks(1);
        switch (rfbi.parallelmode) {
        case OMAP_DSS_RFBI_PARALLELMODE_8:
        {
@@ -237,7 +226,6 @@ void omap_rfbi_write_data(const void *buf, u32 len)
                BUG();
 
        }
-       rfbi_enable_clocks(0);
 }
 EXPORT_SYMBOL(omap_rfbi_write_data);
 
@@ -249,8 +237,6 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
        int horiz_offset = scr_width - w;
        int i;
 
-       rfbi_enable_clocks(1);
-
        if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
           rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
                const u16 __iomem *pd = buf;
@@ -295,12 +281,10 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
        } else {
                BUG();
        }
-
-       rfbi_enable_clocks(0);
 }
 EXPORT_SYMBOL(omap_rfbi_write_pixels);
 
-void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
+static void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
                u16 height, void (*callback)(void *data), void *data)
 {
        u32 l;
@@ -317,8 +301,6 @@ void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
        rfbi.framedone_callback = callback;
        rfbi.framedone_callback_data = data;
 
-       rfbi_enable_clocks(1);
-
        rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
 
        l = rfbi_read_reg(RFBI_CONTROL);
@@ -337,15 +319,11 @@ static void framedone_callback(void *data, u32 mask)
 
        REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0);
 
-       rfbi_enable_clocks(0);
-
        callback = rfbi.framedone_callback;
        rfbi.framedone_callback = NULL;
 
        if (callback != NULL)
                callback(rfbi.framedone_callback_data);
-
-       atomic_set(&rfbi.cmd_pending, 0);
 }
 
 #if 1 /* VERBOSE */
@@ -435,7 +413,7 @@ static int calc_extif_timings(struct rfbi_timings *t)
 }
 
 
-void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
+static void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
 {
        int r;
 
@@ -447,7 +425,6 @@ void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
 
        BUG_ON(!t->converted);
 
-       rfbi_enable_clocks(1);
        rfbi_write_reg(RFBI_ONOFF_TIME(rfbi_module), t->tim[0]);
        rfbi_write_reg(RFBI_CYCLE_TIME(rfbi_module), t->tim[1]);
 
@@ -456,7 +433,6 @@ void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
                    (t->tim[2] ? 1 : 0), 4, 4);
 
        rfbi_print_timings();
-       rfbi_enable_clocks(0);
 }
 
 static int ps_to_rfbi_ticks(int time, int div)
@@ -472,59 +448,6 @@ static int ps_to_rfbi_ticks(int time, int div)
        return ret;
 }
 
-#ifdef OMAP_RFBI_RATE_LIMIT
-unsigned long rfbi_get_max_tx_rate(void)
-{
-       unsigned long   l4_rate, dss1_rate;
-       int             min_l4_ticks = 0;
-       int             i;
-
-       /* According to TI this can't be calculated so make the
-        * adjustments for a couple of known frequencies and warn for
-        * others.
-        */
-       static const struct {
-               unsigned long l4_clk;           /* HZ */
-               unsigned long dss1_clk;         /* HZ */
-               unsigned long min_l4_ticks;
-       } ftab[] = {
-               { 55,   132,    7, },           /* 7.86 MPix/s */
-               { 110,  110,    12, },          /* 9.16 MPix/s */
-               { 110,  132,    10, },          /* 11   Mpix/s */
-               { 120,  120,    10, },          /* 12   Mpix/s */
-               { 133,  133,    10, },          /* 13.3 Mpix/s */
-       };
-
-       l4_rate = rfbi.l4_khz / 1000;
-       dss1_rate = dss_clk_get_rate(DSS_CLK_FCK) / 1000000;
-
-       for (i = 0; i < ARRAY_SIZE(ftab); i++) {
-               /* Use a window instead of an exact match, to account
-                * for different DPLL multiplier / divider pairs.
-                */
-               if (abs(ftab[i].l4_clk - l4_rate) < 3 &&
-                   abs(ftab[i].dss1_clk - dss1_rate) < 3) {
-                       min_l4_ticks = ftab[i].min_l4_ticks;
-                       break;
-               }
-       }
-       if (i == ARRAY_SIZE(ftab)) {
-               /* Can't be sure, return anyway the maximum not
-                * rate-limited. This might cause a problem only for the
-                * tearing synchronisation.
-                */
-               DSSERR("can't determine maximum RFBI transfer rate\n");
-               return rfbi.l4_khz * 1000;
-       }
-       return rfbi.l4_khz * 1000 / min_l4_ticks;
-}
-#else
-int rfbi_get_max_tx_rate(void)
-{
-       return rfbi.l4_khz * 1000;
-}
-#endif
-
 static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
 {
        *clk_period = 1000000000 / rfbi.l4_khz;
@@ -644,7 +567,6 @@ int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
        DSSDBG("setup_te: mode %d hs %d vs %d hs_inv %d vs_inv %d\n",
                mode, hs, vs, hs_pol_inv, vs_pol_inv);
 
-       rfbi_enable_clocks(1);
        rfbi_write_reg(RFBI_HSYNC_WIDTH, hs);
        rfbi_write_reg(RFBI_VSYNC_WIDTH, vs);
 
@@ -657,7 +579,6 @@ int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
                l &= ~(1 << 20);
        else
                l |= 1 << 20;
-       rfbi_enable_clocks(0);
 
        return 0;
 }
@@ -672,7 +593,6 @@ int omap_rfbi_enable_te(bool enable, unsigned line)
        if (line > (1 << 11) - 1)
                return -EINVAL;
 
-       rfbi_enable_clocks(1);
        l = rfbi_read_reg(RFBI_CONFIG(0));
        l &= ~(0x3 << 2);
        if (enable) {
@@ -682,50 +602,12 @@ int omap_rfbi_enable_te(bool enable, unsigned line)
                rfbi.te_enabled = 0;
        rfbi_write_reg(RFBI_CONFIG(0), l);
        rfbi_write_reg(RFBI_LINE_NUMBER, line);
-       rfbi_enable_clocks(0);
 
        return 0;
 }
 EXPORT_SYMBOL(omap_rfbi_enable_te);
 
-#if 0
-static void rfbi_enable_config(int enable1, int enable2)
-{
-       u32 l;
-       int cs = 0;
-
-       if (enable1)
-               cs |= 1<<0;
-       if (enable2)
-               cs |= 1<<1;
-
-       rfbi_enable_clocks(1);
-
-       l = rfbi_read_reg(RFBI_CONTROL);
-
-       l = FLD_MOD(l, cs, 3, 2);
-       l = FLD_MOD(l, 0, 1, 1);
-
-       rfbi_write_reg(RFBI_CONTROL, l);
-
-
-       l = rfbi_read_reg(RFBI_CONFIG(0));
-       l = FLD_MOD(l, 0, 3, 2); /* TRIGGERMODE: ITE */
-       /*l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */
-       /*l |= FLD_VAL(0, 8, 7); */ /* L4FORMAT, 1pix/L4 */
-
-       l = FLD_MOD(l, 0, 16, 16); /* A0POLARITY */
-       l = FLD_MOD(l, 1, 20, 20); /* TE_VSYNC_POLARITY */
-       l = FLD_MOD(l, 1, 21, 21); /* HSYNCPOLARITY */
-
-       l = FLD_MOD(l, OMAP_DSS_RFBI_PARALLELMODE_8, 1, 0);
-       rfbi_write_reg(RFBI_CONFIG(0), l);
-
-       rfbi_enable_clocks(0);
-}
-#endif
-
-int rfbi_configure(int rfbi_module, int bpp, int lines)
+static int rfbi_configure(int rfbi_module, int bpp, int lines)
 {
        u32 l;
        int cycle1 = 0, cycle2 = 0, cycle3 = 0;
@@ -821,8 +703,6 @@ int rfbi_configure(int rfbi_module, int bpp, int lines)
                break;
        }
 
-       rfbi_enable_clocks(1);
-
        REG_FLD_MOD(RFBI_CONTROL, 0, 3, 2); /* clear CS */
 
        l = 0;
@@ -856,11 +736,15 @@ int rfbi_configure(int rfbi_module, int bpp, int lines)
        DSSDBG("RFBI config: bpp %d, lines %d, cycles: 0x%x 0x%x 0x%x\n",
               bpp, lines, cycle1, cycle2, cycle3);
 
-       rfbi_enable_clocks(0);
-
        return 0;
 }
-EXPORT_SYMBOL(rfbi_configure);
+
+int omap_rfbi_configure(struct omap_dss_device *dssdev, int pixel_size,
+               int data_lines)
+{
+       return rfbi_configure(dssdev->phy.rfbi.channel, pixel_size, data_lines);
+}
+EXPORT_SYMBOL(omap_rfbi_configure);
 
 int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
                u16 *x, u16 *y, u16 *w, u16 *h)
@@ -960,6 +844,8 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
 {
        int r;
 
+       rfbi_enable_clocks(1);
+
        r = omap_dss_start_device(dssdev);
        if (r) {
                DSSERR("failed to start device\n");
@@ -1002,6 +888,8 @@ void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev)
        omap_dispc_unregister_isr(framedone_callback, NULL,
                        DISPC_IRQ_FRAMEDONE);
        omap_dss_stop_device(dssdev);
+
+       rfbi_enable_clocks(0);
 }
 EXPORT_SYMBOL(omapdss_rfbi_display_disable);
 
@@ -1021,11 +909,7 @@ static int omap_rfbihw_probe(struct platform_device *pdev)
 
        rfbi.pdev = pdev;
 
-       spin_lock_init(&rfbi.cmd_lock);
-
-       init_completion(&rfbi.cmd_done);
-       atomic_set(&rfbi.cmd_fifo_full, 0);
-       atomic_set(&rfbi.cmd_pending, 0);
+       sema_init(&rfbi.bus_lock, 1);
 
        rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
        if (!rfbi_mem) {
index 54a53e648180e1e31fe830777d2302056f33b2fc..0bd4b0350f809cde6daede29823fc6dd7f0acf0c 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/err.h>
 #include <linux/regulator/consumer.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 #include "dss.h"
 
index 8e35a5bae429c8a858e0c6acf5ac3bca92c2ca79..980f919ed987609b1b646af56ba47dee10b81767 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 
 #include "dss.h"
@@ -373,8 +373,11 @@ static void venc_reset(void)
                }
        }
 
+#ifdef CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET
        /* the magical sleep that makes things work */
+       /* XXX more info? What bug this circumvents? */
        msleep(20);
+#endif
 }
 
 static void venc_enable_clocks(int enable)
@@ -473,6 +476,12 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
 
        mutex_lock(&venc.venc_lock);
 
+       r = omap_dss_start_device(dssdev);
+       if (r) {
+               DSSERR("failed to start device\n");
+               goto err0;
+       }
+
        if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
                r = -EINVAL;
                goto err1;
@@ -484,10 +493,11 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
 
        dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
-       /* wait couple of vsyncs until enabling the LCD */
-       msleep(50);
-
+       mutex_unlock(&venc.venc_lock);
+       return 0;
 err1:
+       omap_dss_stop_device(dssdev);
+err0:
        mutex_unlock(&venc.venc_lock);
 
        return r;
@@ -510,10 +520,9 @@ static void venc_panel_disable(struct omap_dss_device *dssdev)
 
        venc_power_off(dssdev);
 
-       /* wait at least 5 vsyncs after disabling the LCD */
-       msleep(100);
-
        dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+       omap_dss_stop_device(dssdev);
 end:
        mutex_unlock(&venc.venc_lock);
 }
index 6f435450987e7596d1e81963ea53bcc82bcd3f42..cff450392b797053ac7aff3acd5d5bc7a51d0030 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/omapfb.h>
 #include <linux/vmalloc.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/vrfb.h>
 #include <plat/vram.h>
 
@@ -895,8 +895,16 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
 
                p.display_info.xres = xres;
                p.display_info.yres = yres;
-               p.display_info.width = 0;
-               p.display_info.height = 0;
+
+               if (display->driver->get_dimensions) {
+                       u32 w, h;
+                       display->driver->get_dimensions(display, &w, &h);
+                       p.display_info.width = w;
+                       p.display_info.height = h;
+               } else {
+                       p.display_info.width = 0;
+                       p.display_info.height = 0;
+               }
 
                if (copy_to_user((void __user *)arg, &p.display_info,
                                        sizeof(p.display_info)))
index 505ec667204906130eb4457e6d96d75b885f670b..505bc12a3031a877ad5617a0259dce21f519f970 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/platform_device.h>
 #include <linux/omapfb.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/vram.h>
 #include <plat/vrfb.h>
 
@@ -702,8 +702,16 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
                        var->xres, var->yres,
                        var->xres_virtual, var->yres_virtual);
 
-       var->height             = -1;
-       var->width              = -1;
+       if (display && display->driver->get_dimensions) {
+               u32 w, h;
+               display->driver->get_dimensions(display, &w, &h);
+               var->width = DIV_ROUND_CLOSEST(w, 1000);
+               var->height = DIV_ROUND_CLOSEST(h, 1000);
+       } else {
+               var->height = -1;
+               var->width = -1;
+       }
+
        var->grayscale          = 0;
 
        if (display && display->driver->get_timings) {
@@ -749,35 +757,6 @@ static int omapfb_open(struct fb_info *fbi, int user)
 
 static int omapfb_release(struct fb_info *fbi, int user)
 {
-#if 0
-       struct omapfb_info *ofbi = FB2OFB(fbi);
-       struct omapfb2_device *fbdev = ofbi->fbdev;
-       struct omap_dss_device *display = fb2display(fbi);
-
-       DBG("Closing fb with plane index %d\n", ofbi->id);
-
-       omapfb_lock(fbdev);
-
-       if (display && display->get_update_mode && display->update) {
-               /* XXX this update should be removed, I think. But it's
-                * good for debugging */
-               if (display->get_update_mode(display) ==
-                               OMAP_DSS_UPDATE_MANUAL) {
-                       u16 w, h;
-
-                       if (display->sync)
-                               display->sync(display);
-
-                       display->get_resolution(display, &w, &h);
-                       display->update(display, 0, 0, w, h);
-               }
-       }
-
-       if (display && display->sync)
-               display->sync(display);
-
-       omapfb_unlock(fbdev);
-#endif
        return 0;
 }
 
@@ -1263,7 +1242,6 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
        struct omapfb_info *ofbi = FB2OFB(fbi);
        struct omapfb2_device *fbdev = ofbi->fbdev;
        struct omap_dss_device *display = fb2display(fbi);
-       int do_update = 0;
        int r = 0;
 
        if (!display)
@@ -1279,11 +1257,6 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
                if (display->driver->resume)
                        r = display->driver->resume(display);
 
-               if (r == 0 && display->driver->get_update_mode &&
-                               display->driver->get_update_mode(display) ==
-                               OMAP_DSS_UPDATE_MANUAL)
-                       do_update = 1;
-
                break;
 
        case FB_BLANK_NORMAL:
@@ -1307,13 +1280,6 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
 exit:
        omapfb_unlock(fbdev);
 
-       if (r == 0 && do_update && display->driver->update) {
-               u16 w, h;
-               display->driver->get_resolution(display, &w, &h);
-
-               r = display->driver->update(display, 0, 0, w, h);
-       }
-
        return r;
 }
 
@@ -2030,9 +1996,9 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
 static int omapfb_mode_to_timings(const char *mode_str,
                struct omap_video_timings *timings, u8 *bpp)
 {
-       struct fb_info fbi;
-       struct fb_var_screeninfo var;
-       struct fb_ops fbops;
+       struct fb_info *fbi;
+       struct fb_var_screeninfo *var;
+       struct fb_ops *fbops;
        int r;
 
 #ifdef CONFIG_OMAP2_DSS_VENC
@@ -2050,39 +2016,66 @@ static int omapfb_mode_to_timings(const char *mode_str,
        /* this is quite a hack, but I wanted to use the modedb and for
         * that we need fb_info and var, so we create dummy ones */
 
-       memset(&fbi, 0, sizeof(fbi));
-       memset(&var, 0, sizeof(var));
-       memset(&fbops, 0, sizeof(fbops));
-       fbi.fbops = &fbops;
-
-       r = fb_find_mode(&var, &fbi, mode_str, NULL, 0, NULL, 24);
-
-       if (r != 0) {
-               timings->pixel_clock = PICOS2KHZ(var.pixclock);
-               timings->hbp = var.left_margin;
-               timings->hfp = var.right_margin;
-               timings->vbp = var.upper_margin;
-               timings->vfp = var.lower_margin;
-               timings->hsw = var.hsync_len;
-               timings->vsw = var.vsync_len;
-               timings->x_res = var.xres;
-               timings->y_res = var.yres;
-
-               switch (var.bits_per_pixel) {
-               case 16:
-                       *bpp = 16;
-                       break;
-               case 24:
-               case 32:
-               default:
-                       *bpp = 24;
-                       break;
-               }
+       *bpp = 0;
+       fbi = NULL;
+       var = NULL;
+       fbops = NULL;
 
-               return 0;
-       } else {
-               return -EINVAL;
+       fbi = kzalloc(sizeof(*fbi), GFP_KERNEL);
+       if (fbi == NULL) {
+               r = -ENOMEM;
+               goto err;
+       }
+
+       var = kzalloc(sizeof(*var), GFP_KERNEL);
+       if (var == NULL) {
+               r = -ENOMEM;
+               goto err;
+       }
+
+       fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
+       if (fbops == NULL) {
+               r = -ENOMEM;
+               goto err;
+       }
+
+       fbi->fbops = fbops;
+
+       r = fb_find_mode(var, fbi, mode_str, NULL, 0, NULL, 24);
+       if (r == 0) {
+               r = -EINVAL;
+               goto err;
+       }
+
+       timings->pixel_clock = PICOS2KHZ(var->pixclock);
+       timings->hbp = var->left_margin;
+       timings->hfp = var->right_margin;
+       timings->vbp = var->upper_margin;
+       timings->vfp = var->lower_margin;
+       timings->hsw = var->hsync_len;
+       timings->vsw = var->vsync_len;
+       timings->x_res = var->xres;
+       timings->y_res = var->yres;
+
+       switch (var->bits_per_pixel) {
+       case 16:
+               *bpp = 16;
+               break;
+       case 24:
+       case 32:
+       default:
+               *bpp = 24;
+               break;
        }
+
+       r = 0;
+
+err:
+       kfree(fbi);
+       kfree(var);
+       kfree(fbops);
+
+       return r;
 }
 
 static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
@@ -2185,6 +2178,61 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
        return r;
 }
 
+static int omapfb_init_display(struct omapfb2_device *fbdev,
+               struct omap_dss_device *dssdev)
+{
+       struct omap_dss_driver *dssdrv = dssdev->driver;
+       int r;
+
+       r = dssdrv->enable(dssdev);
+       if (r) {
+               dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
+                               dssdev->name);
+               return r;
+       }
+
+       if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
+               u16 w, h;
+               if (dssdrv->enable_te) {
+                       r = dssdrv->enable_te(dssdev, 1);
+                       if (r) {
+                               dev_err(fbdev->dev, "Failed to set TE\n");
+                               return r;
+                       }
+               }
+
+               if (dssdrv->set_update_mode) {
+                       r = dssdrv->set_update_mode(dssdev,
+                                       OMAP_DSS_UPDATE_MANUAL);
+                       if (r) {
+                               dev_err(fbdev->dev,
+                                               "Failed to set update mode\n");
+                               return r;
+                       }
+               }
+
+               dssdrv->get_resolution(dssdev, &w, &h);
+               r = dssdrv->update(dssdev, 0, 0, w, h);
+               if (r) {
+                       dev_err(fbdev->dev,
+                                       "Failed to update display\n");
+                       return r;
+               }
+       } else {
+               if (dssdrv->set_update_mode) {
+                       r = dssdrv->set_update_mode(dssdev,
+                                       OMAP_DSS_UPDATE_AUTO);
+                       if (r) {
+                               dev_err(fbdev->dev,
+                                               "Failed to set update mode\n");
+                               return r;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 static int omapfb_probe(struct platform_device *pdev)
 {
        struct omapfb2_device *fbdev = NULL;
@@ -2284,30 +2332,13 @@ static int omapfb_probe(struct platform_device *pdev)
        }
 
        if (def_display) {
-               struct omap_dss_driver *dssdrv = def_display->driver;
-
-               r = def_display->driver->enable(def_display);
+               r = omapfb_init_display(fbdev, def_display);
                if (r) {
-                       dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
-                                       def_display->name);
+                       dev_err(fbdev->dev,
+                                       "failed to initialize default "
+                                       "display\n");
                        goto cleanup;
                }
-
-               if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
-                       u16 w, h;
-                       if (dssdrv->enable_te)
-                               dssdrv->enable_te(def_display, 1);
-                       if (dssdrv->set_update_mode)
-                               dssdrv->set_update_mode(def_display,
-                                               OMAP_DSS_UPDATE_MANUAL);
-
-                       dssdrv->get_resolution(def_display, &w, &h);
-                       def_display->driver->update(def_display, 0, 0, w, h);
-               } else {
-                       if (dssdrv->set_update_mode)
-                               dssdrv->set_update_mode(def_display,
-                                               OMAP_DSS_UPDATE_AUTO);
-               }
        }
 
        DBG("create sysfs for fbs\n");
index 6f9c72cd6bb0e52675375e4cd4c2bd168e175701..2f5e817b2a9a65904e4f41631036fb350c478784 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/mm.h>
 #include <linux/omapfb.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/vrfb.h>
 
 #include "omapfb.h"
@@ -50,10 +50,12 @@ static ssize_t store_rotate_type(struct device *dev,
        struct fb_info *fbi = dev_get_drvdata(dev);
        struct omapfb_info *ofbi = FB2OFB(fbi);
        struct omapfb2_mem_region *rg;
-       enum omap_dss_rotation_type rot_type;
+       int rot_type;
        int r;
 
-       rot_type = simple_strtoul(buf, NULL, 0);
+       r = kstrtoint(buf, 0, &rot_type);
+       if (r)
+               return r;
 
        if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
                return -EINVAL;
@@ -102,14 +104,15 @@ static ssize_t store_mirror(struct device *dev,
 {
        struct fb_info *fbi = dev_get_drvdata(dev);
        struct omapfb_info *ofbi = FB2OFB(fbi);
-       unsigned long mirror;
+       int mirror;
        int r;
        struct fb_var_screeninfo new_var;
 
-       mirror = simple_strtoul(buf, NULL, 0);
+       r = kstrtoint(buf, 0, &mirror);
+       if (r)
+               return r;
 
-       if (mirror != 0 && mirror != 1)
-               return -EINVAL;
+       mirror = !!mirror;
 
        if (!lock_fb_info(fbi))
                return -ENODEV;
@@ -445,7 +448,11 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
        int r;
        int i;
 
-       size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0));
+       r = kstrtoul(buf, 0, &size);
+       if (r)
+               return r;
+
+       size = PAGE_ALIGN(size);
 
        if (!lock_fb_info(fbi))
                return -ENODEV;
index 1305fc9880badaaf62699a7ee916cff62034658c..aa1b1d9742760e86507102da28635a2f84a65ca7 100644 (file)
 
 #include <linux/rwsem.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #ifdef DEBUG
 extern unsigned int omapfb_debug;
 #define DBG(format, ...) \
-       if (omapfb_debug) \
-               printk(KERN_DEBUG "OMAPFB: " format, ## __VA_ARGS__)
+       do { \
+               if (omapfb_debug) \
+                       printk(KERN_DEBUG "OMAPFB: " format, ## __VA_ARGS__); \
+       } while (0)
 #else
 #define DBG(format, ...)
 #endif
index 35f61dd0cb3a43f5a9e3f70ac0dc5a07136a91b1..bb95ec56d25d9943aef4150595c0f190c9bb0cbc 100644 (file)
@@ -623,19 +623,21 @@ static int __devinit pxa168fb_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
                dev_err(&pdev->dev, "no IO memory defined\n");
-               return -ENOENT;
+               ret = -ENOENT;
+               goto failed_put_clk;
        }
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                dev_err(&pdev->dev, "no IRQ defined\n");
-               return -ENOENT;
+               ret = -ENOENT;
+               goto failed_put_clk;
        }
 
        info = framebuffer_alloc(sizeof(struct pxa168fb_info), &pdev->dev);
        if (info == NULL) {
-               clk_put(clk);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto failed_put_clk;
        }
 
        /* Initialize private data */
@@ -671,7 +673,7 @@ static int __devinit pxa168fb_probe(struct platform_device *pdev)
        fbi->reg_base = ioremap_nocache(res->start, resource_size(res));
        if (fbi->reg_base == NULL) {
                ret = -ENOMEM;
-               goto failed;
+               goto failed_free_info;
        }
 
        /*
@@ -683,7 +685,7 @@ static int __devinit pxa168fb_probe(struct platform_device *pdev)
                                                &fbi->fb_start_dma, GFP_KERNEL);
        if (info->screen_base == NULL) {
                ret = -ENOMEM;
-               goto failed;
+               goto failed_free_info;
        }
 
        info->fix.smem_start = (unsigned long)fbi->fb_start_dma;
@@ -772,8 +774,9 @@ failed_free_clk:
 failed_free_fbmem:
        dma_free_coherent(fbi->dev, info->fix.smem_len,
                        info->screen_base, fbi->fb_start_dma);
-failed:
+failed_free_info:
        kfree(info);
+failed_put_clk:
        clk_put(clk);
 
        dev_err(&pdev->dev, "frame buffer device init failed with %d\n", ret);
index 3b6cdcac8f1a6a930dd49399dd4af97a9a835a8b..4aecf213c9be46cb1f37ee38d231aabcf9d089d3 100644 (file)
@@ -182,6 +182,7 @@ struct s3c_fb_vsync {
 
 /**
  * struct s3c_fb - overall hardware state of the hardware
+ * @slock: The spinlock protection for this data sturcture.
  * @dev: The device that we bound to, for printing, etc.
  * @regs_res: The resource we claimed for the IO registers.
  * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk.
@@ -195,6 +196,7 @@ struct s3c_fb_vsync {
  * @vsync_info: VSYNC-related information (count, queues...)
  */
 struct s3c_fb {
+       spinlock_t              slock;
        struct device           *dev;
        struct resource         *regs_res;
        struct clk              *bus_clk;
@@ -233,13 +235,12 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
                            struct fb_info *info)
 {
        struct s3c_fb_win *win = info->par;
-       struct s3c_fb_pd_win *windata = win->windata;
        struct s3c_fb *sfb = win->parent;
 
        dev_dbg(sfb->dev, "checking parameters\n");
 
-       var->xres_virtual = max((unsigned int)windata->virtual_x, var->xres);
-       var->yres_virtual = max((unsigned int)windata->virtual_y, var->yres);
+       var->xres_virtual = max(var->xres_virtual, var->xres);
+       var->yres_virtual = max(var->yres_virtual, var->yres);
 
        if (!s3c_fb_validate_win_bpp(win, var->bits_per_pixel)) {
                dev_dbg(sfb->dev, "win %d: unsupported bpp %d\n",
@@ -300,6 +301,7 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
                var->blue.length        = 5;
                break;
 
+       case 32:
        case 28:
        case 25:
                var->transp.length      = var->bits_per_pixel - 24;
@@ -308,7 +310,6 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
        case 24:
                /* our 24bpp is unpacked, so 32bpp */
                var->bits_per_pixel     = 32;
-       case 32:
                var->red.offset         = 16;
                var->red.length         = 8;
                var->green.offset       = 8;
@@ -556,6 +557,13 @@ static int s3c_fb_set_par(struct fb_info *info)
        vidosd_set_alpha(win, alpha);
        vidosd_set_size(win, data);
 
+       /* Enable DMA channel for this window */
+       if (sfb->variant.has_shadowcon) {
+               data = readl(sfb->regs + SHADOWCON);
+               data |= SHADOWCON_CHx_ENABLE(win_no);
+               writel(data, sfb->regs + SHADOWCON);
+       }
+
        data = WINCONx_ENWIN;
 
        /* note, since we have to round up the bits-per-pixel, we end up
@@ -635,13 +643,6 @@ static int s3c_fb_set_par(struct fb_info *info)
        writel(data, regs + sfb->variant.wincon + (win_no * 4));
        writel(0x0, regs + sfb->variant.winmap + (win_no * 4));
 
-       /* Enable DMA channel for this window */
-       if (sfb->variant.has_shadowcon) {
-               data = readl(sfb->regs + SHADOWCON);
-               data |= SHADOWCON_CHx_ENABLE(win_no);
-               writel(data, sfb->regs + SHADOWCON);
-       }
-
        shadow_protect_win(win, 0);
 
        return 0;
@@ -947,6 +948,8 @@ static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
        void __iomem  *regs = sfb->regs;
        u32 irq_sts_reg;
 
+       spin_lock(&sfb->slock);
+
        irq_sts_reg = readl(regs + VIDINTCON1);
 
        if (irq_sts_reg & VIDINTCON1_INT_FRAME) {
@@ -963,6 +966,7 @@ static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
         */
        s3c_fb_disable_irq(sfb);
 
+       spin_unlock(&sfb->slock);
        return IRQ_HANDLED;
 }
 
@@ -1339,6 +1343,8 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
        sfb->pdata = pd;
        sfb->variant = fbdrv->variant;
 
+       spin_lock_init(&sfb->slock);
+
        sfb->bus_clk = clk_get(dev, "lcd");
        if (IS_ERR(sfb->bus_clk)) {
                dev_err(dev, "failed to get bus clock\n");
@@ -1442,8 +1448,7 @@ err_ioremap:
        iounmap(sfb->regs);
 
 err_req_region:
-       release_resource(sfb->regs_res);
-       kfree(sfb->regs_res);
+       release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
 
 err_clk:
        clk_disable(sfb->bus_clk);
@@ -1479,14 +1484,12 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
        clk_disable(sfb->bus_clk);
        clk_put(sfb->bus_clk);
 
-       release_resource(sfb->regs_res);
-       kfree(sfb->regs_res);
-
-       kfree(sfb);
+       release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
 
        pm_runtime_put_sync(sfb->dev);
        pm_runtime_disable(sfb->dev);
 
+       kfree(sfb);
        return 0;
 }
 
@@ -1521,7 +1524,8 @@ static int s3c_fb_resume(struct device *dev)
 
        clk_enable(sfb->bus_clk);
 
-       /* setup registers */
+       /* setup gpio and output polarity controls */
+       pd->setup_gpio();
        writel(pd->vidcon1, sfb->regs + VIDCON1);
 
        /* zero all windows before we do anything */
@@ -1549,7 +1553,7 @@ static int s3c_fb_resume(struct device *dev)
        return 0;
 }
 
-int s3c_fb_runtime_suspend(struct device *dev)
+static int s3c_fb_runtime_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct s3c_fb *sfb = platform_get_drvdata(pdev);
@@ -1569,7 +1573,7 @@ int s3c_fb_runtime_suspend(struct device *dev)
        return 0;
 }
 
-int s3c_fb_runtime_resume(struct device *dev)
+static int s3c_fb_runtime_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct s3c_fb *sfb = platform_get_drvdata(pdev);
@@ -1579,7 +1583,8 @@ int s3c_fb_runtime_resume(struct device *dev)
 
        clk_enable(sfb->bus_clk);
 
-       /* setup registers */
+       /* setup gpio and output polarity controls */
+       pd->setup_gpio();
        writel(pd->vidcon1, sfb->regs + VIDCON1);
 
        /* zero all windows before we do anything */
@@ -1623,28 +1628,31 @@ static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = {
                .has_osd_c      = 1,
                .osd_size_off   = 0x8,
                .palette_sz     = 256,
-               .valid_bpp      = VALID_BPP1248 | VALID_BPP(16) | VALID_BPP(24),
+               .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
+                                  VALID_BPP(18) | VALID_BPP(24)),
        },
        [1] = {
                .has_osd_c      = 1,
                .has_osd_d      = 1,
-               .osd_size_off   = 0x12,
+               .osd_size_off   = 0xc,
                .has_osd_alpha  = 1,
                .palette_sz     = 256,
                .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
                                   VALID_BPP(18) | VALID_BPP(19) |
-                                  VALID_BPP(24) | VALID_BPP(25)),
+                                  VALID_BPP(24) | VALID_BPP(25) |
+                                  VALID_BPP(28)),
        },
        [2] = {
                .has_osd_c      = 1,
                .has_osd_d      = 1,
-               .osd_size_off   = 0x12,
+               .osd_size_off   = 0xc,
                .has_osd_alpha  = 1,
                .palette_sz     = 16,
                .palette_16bpp  = 1,
                .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
                                   VALID_BPP(18) | VALID_BPP(19) |
-                                  VALID_BPP(24) | VALID_BPP(25)),
+                                  VALID_BPP(24) | VALID_BPP(25) |
+                                  VALID_BPP(28)),
        },
        [3] = {
                .has_osd_c      = 1,
@@ -1653,7 +1661,8 @@ static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = {
                .palette_16bpp  = 1,
                .valid_bpp      = (VALID_BPP124  | VALID_BPP(16) |
                                   VALID_BPP(18) | VALID_BPP(19) |
-                                  VALID_BPP(24) | VALID_BPP(25)),
+                                  VALID_BPP(24) | VALID_BPP(25) |
+                                  VALID_BPP(28)),
        },
        [4] = {
                .has_osd_c      = 1,
@@ -1662,7 +1671,65 @@ static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = {
                .palette_16bpp  = 1,
                .valid_bpp      = (VALID_BPP(1) | VALID_BPP(2) |
                                   VALID_BPP(16) | VALID_BPP(18) |
-                                  VALID_BPP(24) | VALID_BPP(25)),
+                                  VALID_BPP(19) | VALID_BPP(24) |
+                                  VALID_BPP(25) | VALID_BPP(28)),
+       },
+};
+
+static struct s3c_fb_win_variant s3c_fb_data_s5p_wins[] = {
+       [0] = {
+               .has_osd_c      = 1,
+               .osd_size_off   = 0x8,
+               .palette_sz     = 256,
+               .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
+                                  VALID_BPP(15) | VALID_BPP(16) |
+                                  VALID_BPP(18) | VALID_BPP(19) |
+                                  VALID_BPP(24) | VALID_BPP(25) |
+                                  VALID_BPP(32)),
+       },
+       [1] = {
+               .has_osd_c      = 1,
+               .has_osd_d      = 1,
+               .osd_size_off   = 0xc,
+               .has_osd_alpha  = 1,
+               .palette_sz     = 256,
+               .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
+                                  VALID_BPP(15) | VALID_BPP(16) |
+                                  VALID_BPP(18) | VALID_BPP(19) |
+                                  VALID_BPP(24) | VALID_BPP(25) |
+                                  VALID_BPP(32)),
+       },
+       [2] = {
+               .has_osd_c      = 1,
+               .has_osd_d      = 1,
+               .osd_size_off   = 0xc,
+               .has_osd_alpha  = 1,
+               .palette_sz     = 256,
+               .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
+                                  VALID_BPP(15) | VALID_BPP(16) |
+                                  VALID_BPP(18) | VALID_BPP(19) |
+                                  VALID_BPP(24) | VALID_BPP(25) |
+                                  VALID_BPP(32)),
+       },
+       [3] = {
+               .has_osd_c      = 1,
+               .has_osd_alpha  = 1,
+               .palette_sz     = 256,
+               .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
+                                  VALID_BPP(15) | VALID_BPP(16) |
+                                  VALID_BPP(18) | VALID_BPP(19) |
+                                  VALID_BPP(24) | VALID_BPP(25) |
+                                  VALID_BPP(32)),
+       },
+       [4] = {
+               .has_osd_c      = 1,
+               .has_osd_alpha  = 1,
+               .palette_sz     = 256,
+               .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
+                                  VALID_BPP(15) | VALID_BPP(16) |
+                                  VALID_BPP(18) | VALID_BPP(19) |
+                                  VALID_BPP(24) | VALID_BPP(25) |
+                                  VALID_BPP(32)),
        },
 };
 
@@ -1719,11 +1786,11 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = {
 
                .has_prtcon     = 1,
        },
-       .win[0] = &s3c_fb_data_64xx_wins[0],
-       .win[1] = &s3c_fb_data_64xx_wins[1],
-       .win[2] = &s3c_fb_data_64xx_wins[2],
-       .win[3] = &s3c_fb_data_64xx_wins[3],
-       .win[4] = &s3c_fb_data_64xx_wins[4],
+       .win[0] = &s3c_fb_data_s5p_wins[0],
+       .win[1] = &s3c_fb_data_s5p_wins[1],
+       .win[2] = &s3c_fb_data_s5p_wins[2],
+       .win[3] = &s3c_fb_data_s5p_wins[3],
+       .win[4] = &s3c_fb_data_s5p_wins[4],
 };
 
 static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = {
@@ -1749,11 +1816,11 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = {
 
                .has_shadowcon  = 1,
        },
-       .win[0] = &s3c_fb_data_64xx_wins[0],
-       .win[1] = &s3c_fb_data_64xx_wins[1],
-       .win[2] = &s3c_fb_data_64xx_wins[2],
-       .win[3] = &s3c_fb_data_64xx_wins[3],
-       .win[4] = &s3c_fb_data_64xx_wins[4],
+       .win[0] = &s3c_fb_data_s5p_wins[0],
+       .win[1] = &s3c_fb_data_s5p_wins[1],
+       .win[2] = &s3c_fb_data_s5p_wins[2],
+       .win[3] = &s3c_fb_data_s5p_wins[3],
+       .win[4] = &s3c_fb_data_s5p_wins[4],
 };
 
 /* S3C2443/S3C2416 style hardware */
index 61c819e35f7f42b978838ff9c60dde28aade586a..0aa13761de6ec3168c38569dd2a9ee479689cdfb 100644 (file)
@@ -867,7 +867,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
                goto dealloc_fb;
        }
 
-       size = (res->end - res->start) + 1;
+       size = resource_size(res);
        info->mem = request_mem_region(res->start, size, pdev->name);
        if (info->mem == NULL) {
                dev_err(&pdev->dev, "failed to get memory region\n");
@@ -997,8 +997,7 @@ release_irq:
 release_regs:
        iounmap(info->io);
 release_mem:
-       release_resource(info->mem);
-       kfree(info->mem);
+       release_mem_region(res->start, size);
 dealloc_fb:
        platform_set_drvdata(pdev, NULL);
        framebuffer_release(fbinfo);
@@ -1044,8 +1043,7 @@ static int __devexit s3c2410fb_remove(struct platform_device *pdev)
 
        iounmap(info->io);
 
-       release_resource(info->mem);
-       kfree(info->mem);
+       release_mem_region(info->mem->start, resource_size(info->mem));
 
        platform_set_drvdata(pdev, NULL);
        framebuffer_release(fbinfo);
index c4482f2e5799130f946cb8daf80c63a295a83ee1..4ca5d0c8fe84a6501ca6ef4f31898c0babac2725 100644 (file)
@@ -25,6 +25,9 @@
 #include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */
 #include <video/vga.h>
 
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
 #endif
@@ -36,6 +39,12 @@ struct s3fb_info {
        struct mutex open_lock;
        unsigned int ref_count;
        u32 pseudo_palette[16];
+#ifdef CONFIG_FB_S3_DDC
+       u8 __iomem *mmio;
+       bool ddc_registered;
+       struct i2c_adapter ddc_adapter;
+       struct i2c_algo_bit_data ddc_algo;
+#endif
 };
 
 
@@ -105,6 +114,9 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",
 #define CHIP_UNDECIDED_FLAG    0x80
 #define CHIP_MASK              0xFF
 
+#define MMIO_OFFSET            0x1000000
+#define MMIO_SIZE              0x10000
+
 /* CRT timing register sets */
 
 static const struct vga_regset s3_h_total_regs[]        = {{0x00, 0, 7}, {0x5D, 0, 0}, VGA_REGSET_END};
@@ -140,7 +152,7 @@ static const struct svga_timing_regs s3_timing_regs     = {
 /* Module parameters */
 
 
-static char *mode_option __devinitdata = "640x480-8@60";
+static char *mode_option __devinitdata;
 
 #ifdef CONFIG_MTRR
 static int mtrr __devinitdata = 1;
@@ -167,6 +179,119 @@ module_param(fasttext, int, 0644);
 MODULE_PARM_DESC(fasttext, "Enable S3 fast text mode (1=enable, 0=disable, default=1)");
 
 
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_FB_S3_DDC
+
+#define DDC_REG                0xaa            /* Trio 3D/1X/2X */
+#define DDC_MMIO_REG   0xff20          /* all other chips */
+#define DDC_SCL_OUT    (1 << 0)
+#define DDC_SDA_OUT    (1 << 1)
+#define DDC_SCL_IN     (1 << 2)
+#define DDC_SDA_IN     (1 << 3)
+#define DDC_DRIVE_EN   (1 << 4)
+
+static bool s3fb_ddc_needs_mmio(int chip)
+{
+       return !(chip == CHIP_360_TRIO3D_1X  ||
+                chip == CHIP_362_TRIO3D_2X  ||
+                chip == CHIP_368_TRIO3D_2X);
+}
+
+static u8 s3fb_ddc_read(struct s3fb_info *par)
+{
+       if (s3fb_ddc_needs_mmio(par->chip))
+               return readb(par->mmio + DDC_MMIO_REG);
+       else
+               return vga_rcrt(par->state.vgabase, DDC_REG);
+}
+
+static void s3fb_ddc_write(struct s3fb_info *par, u8 val)
+{
+       if (s3fb_ddc_needs_mmio(par->chip))
+               writeb(val, par->mmio + DDC_MMIO_REG);
+       else
+               vga_wcrt(par->state.vgabase, DDC_REG, val);
+}
+
+static void s3fb_ddc_setscl(void *data, int val)
+{
+       struct s3fb_info *par = data;
+       unsigned char reg;
+
+       reg = s3fb_ddc_read(par) | DDC_DRIVE_EN;
+       if (val)
+               reg |= DDC_SCL_OUT;
+       else
+               reg &= ~DDC_SCL_OUT;
+       s3fb_ddc_write(par, reg);
+}
+
+static void s3fb_ddc_setsda(void *data, int val)
+{
+       struct s3fb_info *par = data;
+       unsigned char reg;
+
+       reg = s3fb_ddc_read(par) | DDC_DRIVE_EN;
+       if (val)
+               reg |= DDC_SDA_OUT;
+       else
+               reg &= ~DDC_SDA_OUT;
+       s3fb_ddc_write(par, reg);
+}
+
+static int s3fb_ddc_getscl(void *data)
+{
+       struct s3fb_info *par = data;
+
+       return !!(s3fb_ddc_read(par) & DDC_SCL_IN);
+}
+
+static int s3fb_ddc_getsda(void *data)
+{
+       struct s3fb_info *par = data;
+
+       return !!(s3fb_ddc_read(par) & DDC_SDA_IN);
+}
+
+static int __devinit s3fb_setup_ddc_bus(struct fb_info *info)
+{
+       struct s3fb_info *par = info->par;
+
+       strlcpy(par->ddc_adapter.name, info->fix.id,
+               sizeof(par->ddc_adapter.name));
+       par->ddc_adapter.owner          = THIS_MODULE;
+       par->ddc_adapter.class          = I2C_CLASS_DDC;
+       par->ddc_adapter.algo_data      = &par->ddc_algo;
+       par->ddc_adapter.dev.parent     = info->device;
+       par->ddc_algo.setsda            = s3fb_ddc_setsda;
+       par->ddc_algo.setscl            = s3fb_ddc_setscl;
+       par->ddc_algo.getsda            = s3fb_ddc_getsda;
+       par->ddc_algo.getscl            = s3fb_ddc_getscl;
+       par->ddc_algo.udelay            = 10;
+       par->ddc_algo.timeout           = 20;
+       par->ddc_algo.data              = par;
+
+       i2c_set_adapdata(&par->ddc_adapter, par);
+
+       /*
+        * some Virge cards have external MUX to switch chip I2C bus between
+        * DDC and extension pins - switch it do DDC
+        */
+/*     vga_wseq(par->state.vgabase, 0x08, 0x06); - not needed, already unlocked */
+       if (par->chip == CHIP_357_VIRGE_GX2 ||
+           par->chip == CHIP_359_VIRGE_GX2P)
+               svga_wseq_mask(par->state.vgabase, 0x0d, 0x01, 0x03);
+       else
+               svga_wseq_mask(par->state.vgabase, 0x0d, 0x00, 0x03);
+       /* some Virge need this or the DDC is ignored */
+       svga_wcrt_mask(par->state.vgabase, 0x5c, 0x03, 0x03);
+
+       return i2c_bit_add_bus(&par->ddc_adapter);
+}
+#endif /* CONFIG_FB_S3_DDC */
+
+
 /* ------------------------------------------------------------------------- */
 
 /* Set font in S3 fast text mode */
@@ -994,6 +1119,7 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
        struct s3fb_info *par;
        int rc;
        u8 regval, cr38, cr39;
+       bool found = false;
 
        /* Ignore secondary VGA device because there is no VGA arbitration */
        if (! svga_primary_device(dev)) {
@@ -1110,12 +1236,69 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
        info->fix.ypanstep = 0;
        info->fix.accel = FB_ACCEL_NONE;
        info->pseudo_palette = (void*) (par->pseudo_palette);
+       info->var.bits_per_pixel = 8;
+
+#ifdef CONFIG_FB_S3_DDC
+       /* Enable MMIO if needed */
+       if (s3fb_ddc_needs_mmio(par->chip)) {
+               par->mmio = ioremap(info->fix.smem_start + MMIO_OFFSET, MMIO_SIZE);
+               if (par->mmio)
+                       svga_wcrt_mask(par->state.vgabase, 0x53, 0x08, 0x08);   /* enable MMIO */
+               else
+                       dev_err(info->device, "unable to map MMIO at 0x%lx, disabling DDC",
+                               info->fix.smem_start + MMIO_OFFSET);
+       }
+       if (!s3fb_ddc_needs_mmio(par->chip) || par->mmio)
+               if (s3fb_setup_ddc_bus(info) == 0) {
+                       u8 *edid = fb_ddc_read(&par->ddc_adapter);
+                       par->ddc_registered = true;
+                       if (edid) {
+                               fb_edid_to_monspecs(edid, &info->monspecs);
+                               kfree(edid);
+                               if (!info->monspecs.modedb)
+                                       dev_err(info->device, "error getting mode database\n");
+                               else {
+                                       const struct fb_videomode *m;
+
+                                       fb_videomode_to_modelist(info->monspecs.modedb,
+                                                                info->monspecs.modedb_len,
+                                                                &info->modelist);
+                                       m = fb_find_best_display(&info->monspecs, &info->modelist);
+                                       if (m) {
+                                               fb_videomode_to_var(&info->var, m);
+                                               /* fill all other info->var's fields */
+                                               if (s3fb_check_var(&info->var, info) == 0)
+                                                       found = true;
+                                       }
+                               }
+                       }
+               }
+#endif
+       if (!mode_option && !found)
+               mode_option = "640x480-8@60";
 
        /* Prepare startup mode */
-       rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8);
-       if (! ((rc == 1) || (rc == 2))) {
-               rc = -EINVAL;
-               dev_err(info->device, "mode %s not found\n", mode_option);
+       if (mode_option) {
+               rc = fb_find_mode(&info->var, info, mode_option,
+                                  info->monspecs.modedb, info->monspecs.modedb_len,
+                                  NULL, info->var.bits_per_pixel);
+               if (!rc || rc == 4) {
+                       rc = -EINVAL;
+                       dev_err(info->device, "mode %s not found\n", mode_option);
+                       fb_destroy_modedb(info->monspecs.modedb);
+                       info->monspecs.modedb = NULL;
+                       goto err_find_mode;
+               }
+       }
+
+       fb_destroy_modedb(info->monspecs.modedb);
+       info->monspecs.modedb = NULL;
+
+       /* maximize virtual vertical size for fast scrolling */
+       info->var.yres_virtual = info->fix.smem_len * 8 /
+                       (info->var.bits_per_pixel * info->var.xres_virtual);
+       if (info->var.yres_virtual < info->var.yres) {
+               dev_err(info->device, "virtual vertical size smaller than real\n");
                goto err_find_mode;
        }
 
@@ -1164,6 +1347,12 @@ err_reg_fb:
        fb_dealloc_cmap(&info->cmap);
 err_alloc_cmap:
 err_find_mode:
+#ifdef CONFIG_FB_S3_DDC
+       if (par->ddc_registered)
+               i2c_del_adapter(&par->ddc_adapter);
+       if (par->mmio)
+               iounmap(par->mmio);
+#endif
        pci_iounmap(dev, info->screen_base);
 err_iomap:
        pci_release_regions(dev);
@@ -1180,12 +1369,11 @@ err_enable_device:
 static void __devexit s3_pci_remove(struct pci_dev *dev)
 {
        struct fb_info *info = pci_get_drvdata(dev);
+       struct s3fb_info __maybe_unused *par = info->par;
 
        if (info) {
 
 #ifdef CONFIG_MTRR
-               struct s3fb_info *par = info->par;
-
                if (par->mtrr_reg >= 0) {
                        mtrr_del(par->mtrr_reg, 0, 0);
                        par->mtrr_reg = -1;
@@ -1195,6 +1383,13 @@ static void __devexit s3_pci_remove(struct pci_dev *dev)
                unregister_framebuffer(info);
                fb_dealloc_cmap(&info->cmap);
 
+#ifdef CONFIG_FB_S3_DDC
+               if (par->ddc_registered)
+                       i2c_del_adapter(&par->ddc_adapter);
+               if (par->mmio)
+                       iounmap(par->mmio);
+#endif
+
                pci_iounmap(dev, info->screen_base);
                pci_release_regions(dev);
 /*             pci_disable_device(dev); */
index bb71fea07284e547cbf2632141748b8155691a74..80fa87e2ae2ff52eb188e2312c4fed2507df9425 100644 (file)
@@ -171,6 +171,8 @@ void savagefb_create_i2c_busses(struct fb_info *info)
 
        switch (par->chip) {
        case S3_PROSAVAGE:
+       case S3_PROSAVAGEDDR:
+       case S3_TWISTER:
                par->chan.reg         = CR_SERIAL2;
                par->chan.ioaddr      = par->mmio.vbase;
                par->chan.algo.setsda = prosavage_gpio_setsda;
index 4e9490c19d7d3a7a07a3a87360de200ff2fb808e..32549d177b198ae2f7f2b9a738d6b8a0cb9de049 100644 (file)
@@ -36,7 +36,6 @@
 #define PCI_CHIP_SAVAGE_IX    0x8c13
 #define PCI_CHIP_PROSAVAGE_PM 0x8a25
 #define PCI_CHIP_PROSAVAGE_KM 0x8a26
- /* Twister is a code name; hope I get the real name soon. */
 #define PCI_CHIP_S3TWISTER_P  0x8d01
 #define PCI_CHIP_S3TWISTER_K  0x8d02
 #define PCI_CHIP_PROSAVAGE_DDR          0x8d03
 #define PCI_CHIP_SUPSAV_IXCDDR         0x8c2f
 
 
+#define S3_SAVAGE_SERIES(chip)    ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000))
 
 #define S3_SAVAGE3D_SERIES(chip)  ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
 
-#define S3_SAVAGE4_SERIES(chip)   ((chip==S3_SAVAGE4) || (chip==S3_PROSAVAGE))
+#define S3_SAVAGE4_SERIES(chip)   ((chip>=S3_SAVAGE4) || (chip<=S3_PROSAVAGEDDR))
 
 #define S3_SAVAGE_MOBILE_SERIES(chip)  ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE))
 
-#define S3_SAVAGE_SERIES(chip)    ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000))
+#define S3_MOBILE_TWISTER_SERIES(chip) ((chip==S3_TWISTER) || (chip==S3_PROSAVAGEDDR))
 
 /* Chip tags.  These are used to group the adapters into
  * related families.
@@ -71,6 +71,8 @@ typedef enum {
   S3_SAVAGE_MX,
   S3_SAVAGE4,
   S3_PROSAVAGE,
+  S3_TWISTER,
+  S3_PROSAVAGEDDR,
   S3_SUPERSAVAGE,
   S3_SAVAGE2000,
   S3_LAST
index a2dc1a7ec7586bd3e5ae6d1689ccf71490317ed1..4de541ca9c52c14d38cb95762ba86034e71d59fd 100644 (file)
@@ -328,7 +328,9 @@ SavageSetup2DEngine(struct savagefb_par  *par)
                savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x0C, par);
                break;
        case S3_SAVAGE4:
+       case S3_TWISTER:
        case S3_PROSAVAGE:
+       case S3_PROSAVAGEDDR:
        case S3_SUPERSAVAGE:
                /* Disable BCI */
                savage_out32(0x48C18, savage_in32(0x48C18, par) & 0x3FF0, par);
@@ -1886,6 +1888,8 @@ static int savage_init_hw(struct savagefb_par *par)
                break;
 
        case S3_PROSAVAGE:
+       case S3_PROSAVAGEDDR:
+       case S3_TWISTER:
                videoRam = RamSavageNB[(config1 & 0xE0) >> 5] * 1024;
                break;
 
@@ -1963,7 +1967,8 @@ static int savage_init_hw(struct savagefb_par *par)
                }
        }
 
-       if (S3_SAVAGE_MOBILE_SERIES(par->chip) && !par->crtonly)
+       if ((S3_SAVAGE_MOBILE_SERIES(par->chip) ||
+            S3_MOBILE_TWISTER_SERIES(par->chip)) && !par->crtonly)
                par->display_type = DISP_LCD;
        else if (dvi || (par->chip == S3_SAVAGE4 && par->dvi))
                par->display_type = DISP_DFP;
@@ -2111,19 +2116,19 @@ static int __devinit savage_init_fb_info(struct fb_info *info,
                snprintf(info->fix.id, 16, "ProSavageKM");
                break;
        case FB_ACCEL_S3TWISTER_P:
-               par->chip = S3_PROSAVAGE;
+               par->chip = S3_TWISTER;
                snprintf(info->fix.id, 16, "TwisterP");
                break;
        case FB_ACCEL_S3TWISTER_K:
-               par->chip = S3_PROSAVAGE;
+               par->chip = S3_TWISTER;
                snprintf(info->fix.id, 16, "TwisterK");
                break;
        case FB_ACCEL_PROSAVAGE_DDR:
-               par->chip = S3_PROSAVAGE;
+               par->chip = S3_PROSAVAGEDDR;
                snprintf(info->fix.id, 16, "ProSavageDDR");
                break;
        case FB_ACCEL_PROSAVAGE_DDRK:
-               par->chip = S3_PROSAVAGE;
+               par->chip = S3_PROSAVAGEDDR;
                snprintf(info->fix.id, 16, "ProSavage8");
                break;
        }
@@ -2232,6 +2237,22 @@ static int __devinit savagefb_probe(struct pci_dev* dev,
                                 &info->modelist);
 #endif
        info->var = savagefb_var800x600x8;
+       /* if a panel was detected, default to a CVT mode instead */
+       if (par->SavagePanelWidth) {
+               struct fb_videomode cvt_mode;
+
+               memset(&cvt_mode, 0, sizeof(cvt_mode));
+               cvt_mode.xres = par->SavagePanelWidth;
+               cvt_mode.yres = par->SavagePanelHeight;
+               cvt_mode.refresh = 60;
+               /* FIXME: if we know there is only the panel
+                * we can enable reduced blanking as well */
+               if (fb_find_mode_cvt(&cvt_mode, 0, 0))
+                       printk(KERN_WARNING "No CVT mode found for panel\n");
+               else if (fb_find_mode(&info->var, info, NULL, NULL, 0,
+                                     &cvt_mode, 0) != 3)
+                       info->var = savagefb_var800x600x8;
+       }
 
        if (mode_option) {
                fb_find_mode(&info->var, info, mode_option,
index 8fe19582c4602f65badeb17fbccb930574e243dc..45e47d8471634d2bd9f57c2ef5e3da88cdc8494b 100644 (file)
@@ -551,8 +551,7 @@ out_unmap:
                free_irq(par->irq, &par->vsync);
        iounmap(par->base);
 out_res:
-       release_resource(par->ioarea);
-       kfree(par->ioarea);
+       release_mem_region(res->start, resource_size(res));
 out_fb:
        framebuffer_release(info);
        return ret;
@@ -570,8 +569,7 @@ static int __devexit sh7760fb_remove(struct platform_device *dev)
        if (par->irq >= 0)
                free_irq(par->irq, par);
        iounmap(par->base);
-       release_resource(par->ioarea);
-       kfree(par->ioarea);
+       release_mem_region(par->ioarea->start, resource_size(par->ioarea));
        framebuffer_release(info);
        platform_set_drvdata(dev, NULL);
 
index 2b9e56a6bde4780933d444b1f7e29aada38274eb..7d54e2c612f774c292088507d24bba47e8d4f605 100644 (file)
@@ -1127,9 +1127,6 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
                struct fb_info *info = hdmi->info;
                unsigned long parent_rate = 0, hdmi_rate;
 
-               /* A device has been plugged in */
-               pm_runtime_get_sync(hdmi->dev);
-
                ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate);
                if (ret < 0)
                        goto out;
@@ -1187,7 +1184,6 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
                fb_set_suspend(hdmi->info, 1);
 
                console_unlock();
-               pm_runtime_put(hdmi->dev);
        }
 
 out:
@@ -1308,7 +1304,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
        INIT_DELAYED_WORK(&hdmi->edid_work, sh_hdmi_edid_work_fn);
 
        pm_runtime_enable(&pdev->dev);
-       pm_runtime_resume(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
 
        /* Product and revision IDs are 0 in sh-mobile version */
        dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n",
@@ -1336,6 +1332,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
 ecodec:
        free_irq(irq, hdmi);
 ereqirq:
+       pm_runtime_put(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        iounmap(hdmi->base);
 emap:
@@ -1372,6 +1369,7 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
        free_irq(irq, hdmi);
        /* Wait for already scheduled work */
        cancel_delayed_work_sync(&hdmi->edid_work);
+       pm_runtime_put(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        clk_disable(hdmi->hdmi_clk);
        clk_put(hdmi->hdmi_clk);
index 9bcc61b4ef149a258e6159a9728ffebac2bd5daf..019dbd3f12b247d3fec1fb4836dd8f36cf5a3819 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/atomic.h>
 
 #include "sh_mobile_lcdcfb.h"
+#include "sh_mobile_meram.h"
 
 #define SIDE_B_OFFSET 0x1000
 #define MIRROR_OFFSET 0x2000
@@ -143,6 +144,7 @@ struct sh_mobile_lcdc_priv {
        unsigned long saved_shared_regs[NR_SHARED_REGS];
        int started;
        int forced_bpp; /* 2 channel LCDC must share bpp setting */
+       struct sh_mobile_meram_info *meram_dev;
 };
 
 static bool banked(int reg_nr)
@@ -468,8 +470,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
        unsigned long tmp;
        int bpp = 0;
        unsigned long ldddsr;
-       int k, m;
-       int ret = 0;
+       int k, m, ret;
 
        /* enable clocks before accessing the hardware */
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
@@ -538,11 +539,12 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
                lcdc_write_chan(ch, LDPMR, 0);
 
                board_cfg = &ch->cfg.board_cfg;
-               if (board_cfg->setup_sys)
-                       ret = board_cfg->setup_sys(board_cfg->board_data, ch,
-                                                  &sh_mobile_lcdc_sys_bus_ops);
-               if (ret)
-                       return ret;
+               if (board_cfg->setup_sys) {
+                       ret = board_cfg->setup_sys(board_cfg->board_data,
+                                               ch, &sh_mobile_lcdc_sys_bus_ops);
+                       if (ret)
+                               return ret;
+               }
        }
 
        /* word and long word swap */
@@ -564,6 +566,9 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
        }
 
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+               unsigned long base_addr_y;
+               unsigned long base_addr_c = 0;
+               int pitch;
                ch = &priv->ch[k];
 
                if (!priv->ch[k].enabled)
@@ -598,16 +603,68 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
                }
                lcdc_write_chan(ch, LDDFR, tmp);
 
+               base_addr_y = ch->info->fix.smem_start;
+               base_addr_c = base_addr_y +
+                               ch->info->var.xres *
+                               ch->info->var.yres_virtual;
+               pitch = ch->info->fix.line_length;
+
+               /* test if we can enable meram */
+               if (ch->cfg.meram_cfg && priv->meram_dev &&
+                               priv->meram_dev->ops) {
+                       struct sh_mobile_meram_cfg *cfg;
+                       struct sh_mobile_meram_info *mdev;
+                       unsigned long icb_addr_y, icb_addr_c;
+                       int icb_pitch;
+                       int pf;
+
+                       cfg = ch->cfg.meram_cfg;
+                       mdev = priv->meram_dev;
+                       /* we need to de-init configured ICBs before we
+                        * we can re-initialize them.
+                        */
+                       if (ch->meram_enabled)
+                               mdev->ops->meram_unregister(mdev, cfg);
+
+                       ch->meram_enabled = 0;
+
+                       if (ch->info->var.nonstd) {
+                               if (ch->info->var.bits_per_pixel == 24)
+                                       pf = SH_MOBILE_MERAM_PF_NV24;
+                               else
+                                       pf = SH_MOBILE_MERAM_PF_NV;
+                       } else {
+                               pf = SH_MOBILE_MERAM_PF_RGB;
+                       }
+
+                       ret = mdev->ops->meram_register(mdev, cfg, pitch,
+                                               ch->info->var.yres,
+                                               pf,
+                                               base_addr_y,
+                                               base_addr_c,
+                                               &icb_addr_y,
+                                               &icb_addr_c,
+                                               &icb_pitch);
+                       if (!ret)  {
+                               /* set LDSA1R value */
+                               base_addr_y = icb_addr_y;
+                               pitch = icb_pitch;
+
+                               /* set LDSA2R value if required */
+                               if (base_addr_c)
+                                       base_addr_c = icb_addr_c;
+
+                               ch->meram_enabled = 1;
+                       }
+               }
+
                /* point out our frame buffer */
-               lcdc_write_chan(ch, LDSA1R, ch->info->fix.smem_start);
+               lcdc_write_chan(ch, LDSA1R, base_addr_y);
                if (ch->info->var.nonstd)
-                       lcdc_write_chan(ch, LDSA2R,
-                               ch->info->fix.smem_start +
-                               ch->info->var.xres *
-                               ch->info->var.yres_virtual);
+                       lcdc_write_chan(ch, LDSA2R, base_addr_c);
 
                /* set line size */
-               lcdc_write_chan(ch, LDMLSR, ch->info->fix.line_length);
+               lcdc_write_chan(ch, LDMLSR, pitch);
 
                /* setup deferred io if SYS bus */
                tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
@@ -692,6 +749,17 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
                        board_cfg->display_off(board_cfg->board_data);
                        module_put(board_cfg->owner);
                }
+
+               /* disable the meram */
+               if (ch->meram_enabled) {
+                       struct sh_mobile_meram_cfg *cfg;
+                       struct sh_mobile_meram_info *mdev;
+                       cfg = ch->cfg.meram_cfg;
+                       mdev = priv->meram_dev;
+                       mdev->ops->meram_unregister(mdev, cfg);
+                       ch->meram_enabled = 0;
+               }
+
        }
 
        /* stop the lcdc */
@@ -875,9 +943,29 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
        } else
                base_addr_c = 0;
 
-       lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
-       if (base_addr_c)
-               lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
+       if (!ch->meram_enabled) {
+               lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
+               if (base_addr_c)
+                       lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
+       } else {
+               struct sh_mobile_meram_cfg *cfg;
+               struct sh_mobile_meram_info *mdev;
+               unsigned long icb_addr_y, icb_addr_c;
+               int ret;
+
+               cfg = ch->cfg.meram_cfg;
+               mdev = priv->meram_dev;
+               ret = mdev->ops->meram_update(mdev, cfg,
+                                       base_addr_y, base_addr_c,
+                                       &icb_addr_y, &icb_addr_c);
+               if (ret)
+                       return ret;
+
+               lcdc_write_chan_mirror(ch, LDSA1R, icb_addr_y);
+               if (icb_addr_c)
+                       lcdc_write_chan_mirror(ch, LDSA2R, icb_addr_c);
+
+       }
 
        if (lcdc_chan_is_sublcd(ch))
                lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);
@@ -1288,7 +1376,6 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
        struct fb_info *info = event->info;
        struct sh_mobile_lcdc_chan *ch = info->par;
        struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg;
-       int ret;
 
        if (&ch->lcdc->notifier != nb)
                return NOTIFY_DONE;
@@ -1302,7 +1389,6 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
                        board_cfg->display_off(board_cfg->board_data);
                        module_put(board_cfg->owner);
                }
-               pm_runtime_put(info->device);
                sh_mobile_lcdc_stop(ch->lcdc);
                break;
        case FB_EVENT_RESUME:
@@ -1316,9 +1402,7 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
                        module_put(board_cfg->owner);
                }
 
-               ret = sh_mobile_lcdc_start(ch->lcdc);
-               if (!ret)
-                       pm_runtime_get_sync(info->device);
+               sh_mobile_lcdc_start(ch->lcdc);
        }
 
        return NOTIFY_OK;
@@ -1420,6 +1504,8 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
                goto err1;
        }
 
+       priv->meram_dev = pdata->meram_dev;
+
        for (i = 0; i < j; i++) {
                struct fb_var_screeninfo *var;
                const struct fb_videomode *lcd_cfg, *max_cfg = NULL;
index f16cb5645a13fd12b8c95881dd51a5daab6352ad..aeed6687e6a737b9d51852380c48bea7e5ab0e6d 100644 (file)
@@ -39,6 +39,7 @@ struct sh_mobile_lcdc_chan {
        int use_count;
        int blank_status;
        struct mutex open_lock;         /* protects the use counter */
+       int meram_enabled;
 };
 
 #endif
diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c
new file mode 100644 (file)
index 0000000..9170c82
--- /dev/null
@@ -0,0 +1,567 @@
+/*
+ * SuperH Mobile MERAM Driver for SuperH Mobile LCDC Driver
+ *
+ * Copyright (c) 2011  Damian Hobson-Garcia <dhobsong@igel.co.jp>
+ *                      Takanari Hayama <taki@igel.co.jp>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include "sh_mobile_meram.h"
+
+/* meram registers */
+#define MExxCTL 0x0
+#define MExxBSIZE 0x4
+#define MExxMNCF 0x8
+#define MExxSARA 0x10
+#define MExxSARB 0x14
+#define MExxSBSIZE 0x18
+
+#define MERAM_MExxCTL_VAL(ctl, next_icb, addr) \
+       ((ctl) | (((next_icb) & 0x1f) << 11) | (((addr) & 0x7ff) << 16))
+#define        MERAM_MExxBSIZE_VAL(a, b, c) \
+       (((a) << 28) | ((b) << 16) | (c))
+
+#define MEVCR1 0x4
+#define MEACTS 0x10
+#define MEQSEL1 0x40
+#define MEQSEL2 0x44
+
+/* settings */
+#define MERAM_SEC_LINE 15
+#define MERAM_LINE_WIDTH 2048
+
+/*
+ * MERAM/ICB access functions
+ */
+
+#define MERAM_ICB_OFFSET(base, idx, off)       \
+       ((base) + (0x400 + ((idx) * 0x20) + (off)))
+
+static inline void meram_write_icb(void __iomem *base, int idx, int off,
+       unsigned long val)
+{
+       iowrite32(val, MERAM_ICB_OFFSET(base, idx, off));
+}
+
+static inline unsigned long meram_read_icb(void __iomem *base, int idx, int off)
+{
+       return ioread32(MERAM_ICB_OFFSET(base, idx, off));
+}
+
+static inline void meram_write_reg(void __iomem *base, int off,
+               unsigned long val)
+{
+       iowrite32(val, base + off);
+}
+
+static inline unsigned long meram_read_reg(void __iomem *base, int off)
+{
+       return ioread32(base + off);
+}
+
+/*
+ * register ICB
+ */
+
+#define MERAM_CACHE_START(p)    ((p) >> 16)
+#define MERAM_CACHE_END(p)      ((p) & 0xffff)
+#define MERAM_CACHE_SET(o, s)   ((((o) & 0xffff) << 16) | \
+                                 (((o) + (s) - 1) & 0xffff))
+
+/*
+ * check if there's no overlaps in MERAM allocation.
+ */
+
+static inline int meram_check_overlap(struct sh_mobile_meram_priv *priv,
+                                     struct sh_mobile_meram_icb *new)
+{
+       int i;
+       int used_start, used_end, meram_start, meram_end;
+
+       /* valid ICB? */
+       if (new->marker_icb & ~0x1f || new->cache_icb & ~0x1f)
+               return 1;
+
+       if (test_bit(new->marker_icb, &priv->used_icb) ||
+                       test_bit(new->cache_icb,  &priv->used_icb))
+               return  1;
+
+       for (i = 0; i < priv->used_meram_cache_regions; i++) {
+               used_start = MERAM_CACHE_START(priv->used_meram_cache[i]);
+               used_end   = MERAM_CACHE_END(priv->used_meram_cache[i]);
+               meram_start = new->meram_offset;
+               meram_end   = new->meram_offset + new->meram_size;
+
+               if ((meram_start >= used_start && meram_start < used_end) ||
+                       (meram_end > used_start && meram_end < used_end))
+                       return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * mark the specified ICB as used
+ */
+
+static inline void meram_mark(struct sh_mobile_meram_priv *priv,
+                             struct sh_mobile_meram_icb *new)
+{
+       int n;
+
+       if (new->marker_icb < 0 || new->cache_icb < 0)
+               return;
+
+       __set_bit(new->marker_icb, &priv->used_icb);
+       __set_bit(new->cache_icb, &priv->used_icb);
+
+       n = priv->used_meram_cache_regions;
+
+       priv->used_meram_cache[n] = MERAM_CACHE_SET(new->meram_offset,
+                                                   new->meram_size);
+
+       priv->used_meram_cache_regions++;
+}
+
+/*
+ * unmark the specified ICB as used
+ */
+
+static inline void meram_unmark(struct sh_mobile_meram_priv *priv,
+                               struct sh_mobile_meram_icb *icb)
+{
+       int i;
+       unsigned long pattern;
+
+       if (icb->marker_icb < 0 || icb->cache_icb < 0)
+               return;
+
+       __clear_bit(icb->marker_icb, &priv->used_icb);
+       __clear_bit(icb->cache_icb, &priv->used_icb);
+
+       pattern = MERAM_CACHE_SET(icb->meram_offset, icb->meram_size);
+       for (i = 0; i < priv->used_meram_cache_regions; i++) {
+               if (priv->used_meram_cache[i] == pattern) {
+                       while (i < priv->used_meram_cache_regions - 1) {
+                               priv->used_meram_cache[i] =
+                                       priv->used_meram_cache[i + 1] ;
+                               i++;
+                       }
+                       priv->used_meram_cache[i] = 0;
+                       priv->used_meram_cache_regions--;
+                       break;
+               }
+       }
+}
+
+/*
+ * is this a YCbCr(NV12, NV16 or NV24) colorspace
+ */
+static inline int is_nvcolor(int cspace)
+{
+       if (cspace == SH_MOBILE_MERAM_PF_NV ||
+                       cspace == SH_MOBILE_MERAM_PF_NV24)
+               return 1;
+       return 0;
+}
+
+/*
+ * set the next address to fetch
+ */
+static inline void meram_set_next_addr(struct sh_mobile_meram_priv *priv,
+                                      struct sh_mobile_meram_cfg *cfg,
+                                      unsigned long base_addr_y,
+                                      unsigned long base_addr_c)
+{
+       unsigned long target;
+
+       target = (cfg->current_reg) ? MExxSARA : MExxSARB;
+       cfg->current_reg ^= 1;
+
+       /* set the next address to fetch */
+       meram_write_icb(priv->base, cfg->icb[0].cache_icb,  target,
+                       base_addr_y);
+       meram_write_icb(priv->base, cfg->icb[0].marker_icb, target,
+                       base_addr_y + cfg->icb[0].cache_unit);
+
+       if (is_nvcolor(cfg->pixelformat)) {
+               meram_write_icb(priv->base, cfg->icb[1].cache_icb,  target,
+                               base_addr_c);
+               meram_write_icb(priv->base, cfg->icb[1].marker_icb, target,
+                               base_addr_c + cfg->icb[1].cache_unit);
+       }
+}
+
+/*
+ * get the next ICB address
+ */
+static inline void meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
+                                          struct sh_mobile_meram_cfg *cfg,
+                                          unsigned long *icb_addr_y,
+                                          unsigned long *icb_addr_c)
+{
+       unsigned long icb_offset;
+
+       if (pdata->addr_mode == SH_MOBILE_MERAM_MODE0)
+               icb_offset = 0x80000000 | (cfg->current_reg << 29);
+       else
+               icb_offset = 0xc0000000 | (cfg->current_reg << 23);
+
+       *icb_addr_y = icb_offset | (cfg->icb[0].marker_icb << 24);
+       if ((*icb_addr_c) && is_nvcolor(cfg->pixelformat))
+               *icb_addr_c = icb_offset | (cfg->icb[1].marker_icb << 24);
+}
+
+#define MERAM_CALC_BYTECOUNT(x, y) \
+       (((x) * (y) + (MERAM_LINE_WIDTH - 1)) & ~(MERAM_LINE_WIDTH - 1))
+
+/*
+ * initialize MERAM
+ */
+
+static int meram_init(struct sh_mobile_meram_priv *priv,
+                     struct sh_mobile_meram_icb *icb,
+                     int xres, int yres, int *out_pitch)
+{
+       unsigned long total_byte_count = MERAM_CALC_BYTECOUNT(xres, yres);
+       unsigned long bnm;
+       int lcdc_pitch, xpitch, line_cnt;
+       int save_lines;
+
+       /* adjust pitch to 1024, 2048, 4096 or 8192 */
+       lcdc_pitch = (xres - 1) | 1023;
+       lcdc_pitch = lcdc_pitch | (lcdc_pitch >> 1);
+       lcdc_pitch = lcdc_pitch | (lcdc_pitch >> 2);
+       lcdc_pitch += 1;
+
+       /* derive settings */
+       if (lcdc_pitch == 8192 && yres >= 1024) {
+               lcdc_pitch = xpitch = MERAM_LINE_WIDTH;
+               line_cnt = total_byte_count >> 11;
+               *out_pitch = xres;
+               save_lines = (icb->meram_size / 16 / MERAM_SEC_LINE);
+               save_lines *= MERAM_SEC_LINE;
+       } else {
+               xpitch = xres;
+               line_cnt = yres;
+               *out_pitch = lcdc_pitch;
+               save_lines = icb->meram_size / (lcdc_pitch >> 10) / 2;
+               save_lines &= 0xff;
+       }
+       bnm = (save_lines - 1) << 16;
+
+       /* TODO: we better to check if we have enough MERAM buffer size */
+
+       /* set up ICB */
+       meram_write_icb(priv->base, icb->cache_icb,  MExxBSIZE,
+                       MERAM_MExxBSIZE_VAL(0x0, line_cnt - 1, xpitch - 1));
+       meram_write_icb(priv->base, icb->marker_icb, MExxBSIZE,
+                       MERAM_MExxBSIZE_VAL(0xf, line_cnt - 1, xpitch - 1));
+
+       meram_write_icb(priv->base, icb->cache_icb,  MExxMNCF, bnm);
+       meram_write_icb(priv->base, icb->marker_icb, MExxMNCF, bnm);
+
+       meram_write_icb(priv->base, icb->cache_icb,  MExxSBSIZE, xpitch);
+       meram_write_icb(priv->base, icb->marker_icb, MExxSBSIZE, xpitch);
+
+       /* save a cache unit size */
+       icb->cache_unit = xres * save_lines;
+
+       /*
+        * Set MERAM for framebuffer
+        *
+        * 0x70f:  WD = 0x3, WS=0x1, CM=0x1, MD=FB mode
+        * we also chain the cache_icb and the marker_icb.
+        * we also split the allocated MERAM buffer between two ICBs.
+        */
+       meram_write_icb(priv->base, icb->cache_icb, MExxCTL,
+                       MERAM_MExxCTL_VAL(0x70f, icb->marker_icb,
+                                         icb->meram_offset));
+       meram_write_icb(priv->base, icb->marker_icb, MExxCTL,
+                       MERAM_MExxCTL_VAL(0x70f, icb->cache_icb,
+                                         icb->meram_offset +
+                                         icb->meram_size / 2));
+
+       return 0;
+}
+
+static void meram_deinit(struct sh_mobile_meram_priv *priv,
+                       struct sh_mobile_meram_icb *icb)
+{
+       /* disable ICB */
+       meram_write_icb(priv->base, icb->cache_icb,  MExxCTL, 0);
+       meram_write_icb(priv->base, icb->marker_icb, MExxCTL, 0);
+       icb->cache_unit = 0;
+}
+
+/*
+ * register the ICB
+ */
+
+static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
+                                   struct sh_mobile_meram_cfg *cfg,
+                                   int xres, int yres, int pixelformat,
+                                   unsigned long base_addr_y,
+                                   unsigned long base_addr_c,
+                                   unsigned long *icb_addr_y,
+                                   unsigned long *icb_addr_c,
+                                   int *pitch)
+{
+       struct platform_device *pdev;
+       struct sh_mobile_meram_priv *priv;
+       int n, out_pitch;
+       int error = 0;
+
+       if (!pdata || !pdata->priv || !pdata->pdev || !cfg)
+               return -EINVAL;
+
+       if (pixelformat != SH_MOBILE_MERAM_PF_NV &&
+           pixelformat != SH_MOBILE_MERAM_PF_NV24 &&
+           pixelformat != SH_MOBILE_MERAM_PF_RGB)
+               return -EINVAL;
+
+       priv = pdata->priv;
+       pdev = pdata->pdev;
+
+       dev_dbg(&pdev->dev, "registering %dx%d (%s) (y=%08lx, c=%08lx)",
+               xres, yres, (!pixelformat) ? "yuv" : "rgb",
+               base_addr_y, base_addr_c);
+
+       mutex_lock(&priv->lock);
+
+       /* we can't handle wider than 8192px */
+       if (xres > 8192) {
+               dev_err(&pdev->dev, "width exceeding the limit (> 8192).");
+               error = -EINVAL;
+               goto err;
+       }
+
+       if (priv->used_meram_cache_regions + 2 > SH_MOBILE_MERAM_ICB_NUM) {
+               dev_err(&pdev->dev, "no more ICB available.");
+               error = -EINVAL;
+               goto err;
+       }
+
+       /* do we have at least one ICB config? */
+       if (cfg->icb[0].marker_icb < 0 || cfg->icb[0].cache_icb < 0) {
+               dev_err(&pdev->dev, "at least one ICB is required.");
+               error = -EINVAL;
+               goto err;
+       }
+
+       /* make sure that there's no overlaps */
+       if (meram_check_overlap(priv, &cfg->icb[0])) {
+               dev_err(&pdev->dev, "conflicting config detected.");
+               error = -EINVAL;
+               goto err;
+       }
+       n = 1;
+
+       /* do the same if we have the second ICB set */
+       if (cfg->icb[1].marker_icb >= 0 && cfg->icb[1].cache_icb >= 0) {
+               if (meram_check_overlap(priv, &cfg->icb[1])) {
+                       dev_err(&pdev->dev, "conflicting config detected.");
+                       error = -EINVAL;
+                       goto err;
+               }
+               n = 2;
+       }
+
+       if (is_nvcolor(pixelformat) && n != 2) {
+               dev_err(&pdev->dev, "requires two ICB sets for planar Y/C.");
+               error =  -EINVAL;
+               goto err;
+       }
+
+       /* we now register the ICB */
+       cfg->pixelformat = pixelformat;
+       meram_mark(priv, &cfg->icb[0]);
+       if (is_nvcolor(pixelformat))
+               meram_mark(priv, &cfg->icb[1]);
+
+       /* initialize MERAM */
+       meram_init(priv, &cfg->icb[0], xres, yres, &out_pitch);
+       *pitch = out_pitch;
+       if (pixelformat == SH_MOBILE_MERAM_PF_NV)
+               meram_init(priv, &cfg->icb[1], xres, (yres + 1) / 2,
+                       &out_pitch);
+       else if (pixelformat == SH_MOBILE_MERAM_PF_NV24)
+               meram_init(priv, &cfg->icb[1], 2 * xres, (yres + 1) / 2,
+                       &out_pitch);
+
+       cfg->current_reg = 1;
+       meram_set_next_addr(priv, cfg, base_addr_y, base_addr_c);
+       meram_get_next_icb_addr(pdata, cfg, icb_addr_y, icb_addr_c);
+
+       dev_dbg(&pdev->dev, "registered - can access via y=%08lx, c=%08lx",
+               *icb_addr_y, *icb_addr_c);
+
+err:
+       mutex_unlock(&priv->lock);
+       return error;
+}
+
+static int sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata,
+                                     struct sh_mobile_meram_cfg *cfg)
+{
+       struct sh_mobile_meram_priv *priv;
+
+       if (!pdata || !pdata->priv || !cfg)
+               return -EINVAL;
+
+       priv = pdata->priv;
+
+       mutex_lock(&priv->lock);
+
+       /* deinit & unmark */
+       if (is_nvcolor(cfg->pixelformat)) {
+               meram_deinit(priv, &cfg->icb[1]);
+               meram_unmark(priv, &cfg->icb[1]);
+       }
+       meram_deinit(priv, &cfg->icb[0]);
+       meram_unmark(priv, &cfg->icb[0]);
+
+       mutex_unlock(&priv->lock);
+
+       return 0;
+}
+
+static int sh_mobile_meram_update(struct sh_mobile_meram_info *pdata,
+                                 struct sh_mobile_meram_cfg *cfg,
+                                 unsigned long base_addr_y,
+                                 unsigned long base_addr_c,
+                                 unsigned long *icb_addr_y,
+                                 unsigned long *icb_addr_c)
+{
+       struct sh_mobile_meram_priv *priv;
+
+       if (!pdata || !pdata->priv || !cfg)
+               return -EINVAL;
+
+       priv = pdata->priv;
+
+       mutex_lock(&priv->lock);
+
+       meram_set_next_addr(priv, cfg, base_addr_y, base_addr_c);
+       meram_get_next_icb_addr(pdata, cfg, icb_addr_y, icb_addr_c);
+
+       mutex_unlock(&priv->lock);
+
+       return 0;
+}
+
+static struct sh_mobile_meram_ops sh_mobile_meram_ops = {
+       .module                 = THIS_MODULE,
+       .meram_register         = sh_mobile_meram_register,
+       .meram_unregister       = sh_mobile_meram_unregister,
+       .meram_update           = sh_mobile_meram_update,
+};
+
+/*
+ * initialize MERAM
+ */
+
+static int sh_mobile_meram_remove(struct platform_device *pdev);
+
+static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
+{
+       struct sh_mobile_meram_priv *priv;
+       struct sh_mobile_meram_info *pdata = pdev->dev.platform_data;
+       struct resource *res;
+       int error;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "no platform data defined\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "cannot get platform resources\n");
+               return -ENOENT;
+       }
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(&pdev->dev, "cannot allocate device data\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, priv);
+
+       /* initialize private data */
+       mutex_init(&priv->lock);
+       priv->base = ioremap_nocache(res->start, resource_size(res));
+       if (!priv->base) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               error = -EFAULT;
+               goto err;
+       }
+       pdata->ops = &sh_mobile_meram_ops;
+       pdata->priv = priv;
+       pdata->pdev = pdev;
+
+       /* initialize ICB addressing mode */
+       if (pdata->addr_mode == SH_MOBILE_MERAM_MODE1)
+               meram_write_reg(priv->base, MEVCR1, 1 << 29);
+
+       dev_info(&pdev->dev, "sh_mobile_meram initialized.");
+
+       return 0;
+
+err:
+       sh_mobile_meram_remove(pdev);
+
+       return error;
+}
+
+
+static int sh_mobile_meram_remove(struct platform_device *pdev)
+{
+       struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
+
+       if (priv->base)
+               iounmap(priv->base);
+
+       mutex_destroy(&priv->lock);
+
+       kfree(priv);
+
+       return 0;
+}
+
+static struct platform_driver sh_mobile_meram_driver = {
+       .driver = {
+               .name           = "sh_mobile_meram",
+               .owner          = THIS_MODULE,
+       },
+       .probe          = sh_mobile_meram_probe,
+       .remove         = sh_mobile_meram_remove,
+};
+
+static int __init sh_mobile_meram_init(void)
+{
+       return platform_driver_register(&sh_mobile_meram_driver);
+}
+
+static void __exit sh_mobile_meram_exit(void)
+{
+       platform_driver_unregister(&sh_mobile_meram_driver);
+}
+
+module_init(sh_mobile_meram_init);
+module_exit(sh_mobile_meram_exit);
+
+MODULE_DESCRIPTION("SuperH Mobile MERAM driver");
+MODULE_AUTHOR("Damian Hobson-Garcia / Takanari Hayama");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/sh_mobile_meram.h b/drivers/video/sh_mobile_meram.h
new file mode 100644 (file)
index 0000000..82c54fb
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef __sh_mobile_meram_h__
+#define __sh_mobile_meram_h__
+
+#include <linux/mutex.h>
+#include <video/sh_mobile_meram.h>
+
+/*
+ * MERAM private
+ */
+
+#define MERAM_ICB_Y 0x1
+#define MERAM_ICB_C 0x2
+
+/* MERAM cache size */
+#define SH_MOBILE_MERAM_ICB_NUM                32
+
+#define SH_MOBILE_MERAM_CACHE_OFFSET(p)        ((p) >> 16)
+#define SH_MOBILE_MERAM_CACHE_SIZE(p)  ((p) & 0xffff)
+
+struct sh_mobile_meram_priv {
+       void __iomem    *base;
+       struct mutex    lock;
+       unsigned long   used_icb;
+       int             used_meram_cache_regions;
+       unsigned long   used_meram_cache[SH_MOBILE_MERAM_ICB_NUM];
+};
+
+int sh_mobile_meram_alloc_icb(const struct sh_mobile_meram_cfg *cfg,
+                  int xres,
+                  int yres,
+                  unsigned int base_addr,
+                  int yuv_mode,
+                  int *marker_icb,
+                  int *out_pitch);
+
+void sh_mobile_meram_free_icb(int marker_icb);
+
+#define SH_MOBILE_MERAM_START(ind, ab) \
+       (0xC0000000 | ((ab & 0x1) << 23) | ((ind & 0x1F) << 24))
+
+#endif /* !__sh_mobile_meram_h__ */
index 56ef6b3a9851ca6f26a41b7be16a4c9678dacc9c..87f0be1e78b555e52297ed7d399f3bfe9364a1a5 100644 (file)
@@ -1625,22 +1625,22 @@ static int sm501fb_start(struct sm501fb_info *info,
        return 0; /* everything is setup */
 
  err_mem_res:
-       release_resource(info->fbmem_res);
-       kfree(info->fbmem_res);
+       release_mem_region(info->fbmem_res->start,
+                          resource_size(info->fbmem_res));
 
  err_regs2d_map:
        iounmap(info->regs2d);
 
  err_regs2d_res:
-       release_resource(info->regs2d_res);
-       kfree(info->regs2d_res);
+       release_mem_region(info->regs2d_res->start,
+                          resource_size(info->regs2d_res));
 
  err_regs_map:
        iounmap(info->regs);
 
  err_regs_res:
-       release_resource(info->regs_res);
-       kfree(info->regs_res);
+       release_mem_region(info->regs_res->start,
+                          resource_size(info->regs_res));
 
  err_release:
        return ret;
@@ -1652,16 +1652,16 @@ static void sm501fb_stop(struct sm501fb_info *info)
        sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);
 
        iounmap(info->fbmem);
-       release_resource(info->fbmem_res);
-       kfree(info->fbmem_res);
+       release_mem_region(info->fbmem_res->start,
+                          resource_size(info->fbmem_res));
 
        iounmap(info->regs2d);
-       release_resource(info->regs2d_res);
-       kfree(info->regs2d_res);
+       release_mem_region(info->regs2d_res->start,
+                          resource_size(info->regs2d_res));
 
        iounmap(info->regs);
-       release_resource(info->regs_res);
-       kfree(info->regs_res);
+       release_mem_region(info->regs_res->start,
+                          resource_size(info->regs_res));
 }
 
 static int sm501fb_init_fb(struct fb_info *fb,
index 0c341d739604b8857c91e6a99db4a01cdac09ca5..cd1c4dcef8fdc0f0d79b1e33f7a84593416854fe 100644 (file)
@@ -250,7 +250,7 @@ static irqreturn_t tmiofb_irq(int irq, void *__info)
  */
 static int tmiofb_hw_stop(struct platform_device *dev)
 {
-       struct tmio_fb_data *data = mfd_get_data(dev);
+       struct tmio_fb_data *data = dev->dev.platform_data;
        struct fb_info *info = platform_get_drvdata(dev);
        struct tmiofb_par *par = info->par;
 
@@ -311,7 +311,7 @@ static int tmiofb_hw_init(struct platform_device *dev)
  */
 static void tmiofb_hw_mode(struct platform_device *dev)
 {
-       struct tmio_fb_data *data = mfd_get_data(dev);
+       struct tmio_fb_data *data = dev->dev.platform_data;
        struct fb_info *info = platform_get_drvdata(dev);
        struct fb_videomode *mode = info->mode;
        struct tmiofb_par *par = info->par;
@@ -557,8 +557,7 @@ static int tmiofb_ioctl(struct fb_info *fbi,
 static struct fb_videomode *
 tmiofb_find_mode(struct fb_info *info, struct fb_var_screeninfo *var)
 {
-       struct tmio_fb_data *data =
-                       mfd_get_data(to_platform_device(info->device));
+       struct tmio_fb_data *data = info->device->platform_data;
        struct fb_videomode *best = NULL;
        int i;
 
@@ -578,8 +577,7 @@ static int tmiofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
 
        struct fb_videomode *mode;
-       struct tmio_fb_data *data =
-                       mfd_get_data(to_platform_device(info->device));
+       struct tmio_fb_data *data = info->device->platform_data;
 
        mode = tmiofb_find_mode(info, var);
        if (!mode || var->bits_per_pixel > 16)
@@ -680,7 +678,7 @@ static struct fb_ops tmiofb_ops = {
 static int __devinit tmiofb_probe(struct platform_device *dev)
 {
        const struct mfd_cell *cell = mfd_get_cell(dev);
-       struct tmio_fb_data *data = mfd_get_data(dev);
+       struct tmio_fb_data *data = dev->dev.platform_data;
        struct resource *ccr = platform_get_resource(dev, IORESOURCE_MEM, 1);
        struct resource *lcr = platform_get_resource(dev, IORESOURCE_MEM, 0);
        struct resource *vram = platform_get_resource(dev, IORESOURCE_MEM, 2);
index 695066b5b2e6d628204695727c3afde94a0f6de7..52b0f3e8ccac694743aa4ba6b2d3db0c86448a0e 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/prefetch.h>
 #include <linux/delay.h>
+#include <linux/prefetch.h>
 #include <video/udlfb.h>
 #include "edid.h"
 
@@ -1587,10 +1588,19 @@ static int dlfb_usb_probe(struct usb_interface *interface,
                goto error;
        }
 
-       for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
-               device_create_file(info->dev, &fb_device_attrs[i]);
+       for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) {
+               retval = device_create_file(info->dev, &fb_device_attrs[i]);
+               if (retval) {
+                       pr_err("device_create_file failed %d\n", retval);
+                       goto err_del_attrs;
+               }
+       }
 
-       device_create_bin_file(info->dev, &edid_attr);
+       retval = device_create_bin_file(info->dev, &edid_attr);
+       if (retval) {
+               pr_err("device_create_bin_file failed %d\n", retval);
+               goto err_del_attrs;
+       }
 
        pr_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
                        " Using %dK framebuffer memory\n", info->node,
@@ -1599,6 +1609,10 @@ static int dlfb_usb_probe(struct usb_interface *interface,
                        info->fix.smem_len * 2 : info->fix.smem_len) >> 10);
        return 0;
 
+err_del_attrs:
+       for (i -= 1; i >= 0; i--)
+               device_remove_file(info->dev, &fb_device_attrs[i]);
+
 error:
        if (dev) {
 
index 53b2c5aae06791becfea4721a3d0ad702e24f109..305c975b1787ea0628d600d2ac89c89cd0afdee9 100644 (file)
@@ -1265,9 +1265,11 @@ static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image
 
 static void vga16fb_destroy(struct fb_info *info)
 {
+       struct platform_device *dev = container_of(info->device, struct platform_device, dev);
        iounmap(info->screen_base);
        fb_dealloc_cmap(&info->cmap);
        /* XXX unshare VGA regions */
+       platform_set_drvdata(dev, NULL);
        framebuffer_release(info);
 }
 
index c2a0a1cfd3b3fe6c9f2da44e8574fe9a20591be5..ab5341814c741af49674ca407f6dea0080776602 100644 (file)
@@ -145,7 +145,7 @@ static int via_gpio_get(struct gpio_chip *chip, unsigned int nr)
 }
 
 
-static struct viafb_gpio_cfg gpio_config = {
+static struct viafb_gpio_cfg viafb_gpio_config = {
        .gpio_chip = {
                .label = "VIAFB onboard GPIO",
                .owner = THIS_MODULE,
@@ -183,8 +183,8 @@ static int viafb_gpio_resume(void *private)
 {
        int i;
 
-       for (i = 0; i < gpio_config.gpio_chip.ngpio; i += 2)
-               viafb_gpio_enable(gpio_config.active_gpios[i]);
+       for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i += 2)
+               viafb_gpio_enable(viafb_gpio_config.active_gpios[i]);
        return 0;
 }
 
@@ -201,9 +201,9 @@ int viafb_gpio_lookup(const char *name)
 {
        int i;
 
-       for (i = 0; i < gpio_config.gpio_chip.ngpio; i++)
-               if (!strcmp(name, gpio_config.active_gpios[i]->vg_name))
-                       return gpio_config.gpio_chip.base + i;
+       for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i++)
+               if (!strcmp(name, viafb_gpio_config.active_gpios[i]->vg_name))
+                       return viafb_gpio_config.gpio_chip.base + i;
        return -1;
 }
 EXPORT_SYMBOL_GPL(viafb_gpio_lookup);
@@ -229,14 +229,15 @@ static __devinit int viafb_gpio_probe(struct platform_device *platdev)
                for (gpio = viafb_all_gpios;
                     gpio < viafb_all_gpios + VIAFB_NUM_GPIOS; gpio++)
                        if (gpio->vg_port_index == port_cfg[i].ioport_index) {
-                               gpio_config.active_gpios[ngpio] = gpio;
-                               gpio_config.gpio_names[ngpio] = gpio->vg_name;
+                               viafb_gpio_config.active_gpios[ngpio] = gpio;
+                               viafb_gpio_config.gpio_names[ngpio] =
+                                       gpio->vg_name;
                                ngpio++;
                        }
        }
-       gpio_config.gpio_chip.ngpio = ngpio;
-       gpio_config.gpio_chip.names = gpio_config.gpio_names;
-       gpio_config.vdev = vdev;
+       viafb_gpio_config.gpio_chip.ngpio = ngpio;
+       viafb_gpio_config.gpio_chip.names = viafb_gpio_config.gpio_names;
+       viafb_gpio_config.vdev = vdev;
        if (ngpio == 0) {
                printk(KERN_INFO "viafb: no GPIOs configured\n");
                return 0;
@@ -245,18 +246,18 @@ static __devinit int viafb_gpio_probe(struct platform_device *platdev)
         * Enable the ports.  They come in pairs, with a single
         * enable bit for both.
         */
-       spin_lock_irqsave(&gpio_config.vdev->reg_lock, flags);
+       spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags);
        for (i = 0; i < ngpio; i += 2)
-               viafb_gpio_enable(gpio_config.active_gpios[i]);
-       spin_unlock_irqrestore(&gpio_config.vdev->reg_lock, flags);
+               viafb_gpio_enable(viafb_gpio_config.active_gpios[i]);
+       spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags);
        /*
         * Get registered.
         */
-       gpio_config.gpio_chip.base = -1;  /* Dynamic */
-       ret = gpiochip_add(&gpio_config.gpio_chip);
+       viafb_gpio_config.gpio_chip.base = -1;  /* Dynamic */
+       ret = gpiochip_add(&viafb_gpio_config.gpio_chip);
        if (ret) {
                printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret);
-               gpio_config.gpio_chip.ngpio = 0;
+               viafb_gpio_config.gpio_chip.ngpio = 0;
        }
 #ifdef CONFIG_PM
        viafb_pm_register(&viafb_gpio_pm_hooks);
@@ -277,8 +278,8 @@ static int viafb_gpio_remove(struct platform_device *platdev)
        /*
         * Get unregistered.
         */
-       if (gpio_config.gpio_chip.ngpio > 0) {
-               ret = gpiochip_remove(&gpio_config.gpio_chip);
+       if (viafb_gpio_config.gpio_chip.ngpio > 0) {
+               ret = gpiochip_remove(&viafb_gpio_config.gpio_chip);
                if (ret) { /* Somebody still using it? */
                        printk(KERN_ERR "Viafb: GPIO remove failed\n");
                        return ret;
@@ -287,11 +288,11 @@ static int viafb_gpio_remove(struct platform_device *platdev)
        /*
         * Disable the ports.
         */
-       spin_lock_irqsave(&gpio_config.vdev->reg_lock, flags);
-       for (i = 0; i < gpio_config.gpio_chip.ngpio; i += 2)
-               viafb_gpio_disable(gpio_config.active_gpios[i]);
-       gpio_config.gpio_chip.ngpio = 0;
-       spin_unlock_irqrestore(&gpio_config.vdev->reg_lock, flags);
+       spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags);
+       for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i += 2)
+               viafb_gpio_disable(viafb_gpio_config.active_gpios[i]);
+       viafb_gpio_config.gpio_chip.ngpio = 0;
+       spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags);
        return ret;
 }
 
index a20218c2fda8be0a98b4a219bff743db2a0b5018..beac52fc1c0eea6c1cadf337983c3b2b5c78614d 100644 (file)
@@ -395,10 +395,9 @@ static int __devinit xenfb_probe(struct xenbus_device *dev,
        spin_lock_init(&info->dirty_lock);
        spin_lock_init(&info->resize_lock);
 
-       info->fb = vmalloc(fb_size);
+       info->fb = vzalloc(fb_size);
        if (info->fb == NULL)
                goto error_nomem;
-       memset(info->fb, 0, fb_size);
 
        info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 
index 0f1da45ba47dd8a917c38a797beca69a00f0a67c..e058ace2a4ad4af69b6ec198ad01fbe8f07362f8 100644 (file)
@@ -40,9 +40,6 @@ struct virtio_balloon
        /* Waiting for host to ack the pages we released. */
        struct completion acked;
 
-       /* Do we have to tell Host *before* we reuse pages? */
-       bool tell_host_first;
-
        /* The pages we've told the Host we're not using. */
        unsigned int num_pages;
        struct list_head pages;
@@ -151,13 +148,14 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num)
                vb->num_pages--;
        }
 
-       if (vb->tell_host_first) {
-               tell_host(vb, vb->deflate_vq);
-               release_pages_by_pfn(vb->pfns, vb->num_pfns);
-       } else {
-               release_pages_by_pfn(vb->pfns, vb->num_pfns);
-               tell_host(vb, vb->deflate_vq);
-       }
+
+       /*
+        * Note that if
+        * virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
+        * is true, we *have* to do it in this order
+        */
+       tell_host(vb, vb->deflate_vq);
+       release_pages_by_pfn(vb->pfns, vb->num_pfns);
 }
 
 static inline void update_stat(struct virtio_balloon *vb, int idx,
@@ -325,9 +323,6 @@ static int virtballoon_probe(struct virtio_device *vdev)
                goto out_del_vqs;
        }
 
-       vb->tell_host_first
-               = virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
-
        return 0;
 
 out_del_vqs:
index b0043fb26a4d5dd8fcc9a2b7b66a18b3b44053b0..68b9136847afb65687a426a0c16e6cca6760caf8 100644 (file)
@@ -82,6 +82,9 @@ struct vring_virtqueue
        /* Host supports indirect buffers */
        bool indirect;
 
+       /* Host publishes avail event idx */
+       bool event;
+
        /* Number of free buffers */
        unsigned int num_free;
        /* Head of free buffer list. */
@@ -237,18 +240,22 @@ EXPORT_SYMBOL_GPL(virtqueue_add_buf_gfp);
 void virtqueue_kick(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
+       u16 new, old;
        START_USE(vq);
        /* Descriptors and available array need to be set before we expose the
         * new available array entries. */
        virtio_wmb();
 
-       vq->vring.avail->idx += vq->num_added;
+       old = vq->vring.avail->idx;
+       new = vq->vring.avail->idx = old + vq->num_added;
        vq->num_added = 0;
 
        /* Need to update avail index before checking if we should notify */
        virtio_mb();
 
-       if (!(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY))
+       if (vq->event ?
+           vring_need_event(vring_avail_event(&vq->vring), new, old) :
+           !(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY))
                /* Prod other side to tell it about changes. */
                vq->notify(&vq->vq);
 
@@ -324,6 +331,14 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
        ret = vq->data[i];
        detach_buf(vq, i);
        vq->last_used_idx++;
+       /* If we expect an interrupt for the next entry, tell host
+        * by writing event index and flush out the write before
+        * the read in the next get_buf call. */
+       if (!(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) {
+               vring_used_event(&vq->vring) = vq->last_used_idx;
+               virtio_mb();
+       }
+
        END_USE(vq);
        return ret;
 }
@@ -345,7 +360,11 @@ bool virtqueue_enable_cb(struct virtqueue *_vq)
 
        /* We optimistically turn back on interrupts, then check if there was
         * more to do. */
+       /* Depending on the VIRTIO_RING_F_EVENT_IDX feature, we need to
+        * either clear the flags bit or point the event index at the next
+        * entry. Always do both to keep code simple. */
        vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
+       vring_used_event(&vq->vring) = vq->last_used_idx;
        virtio_mb();
        if (unlikely(more_used(vq))) {
                END_USE(vq);
@@ -357,6 +376,33 @@ bool virtqueue_enable_cb(struct virtqueue *_vq)
 }
 EXPORT_SYMBOL_GPL(virtqueue_enable_cb);
 
+bool virtqueue_enable_cb_delayed(struct virtqueue *_vq)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+       u16 bufs;
+
+       START_USE(vq);
+
+       /* We optimistically turn back on interrupts, then check if there was
+        * more to do. */
+       /* Depending on the VIRTIO_RING_F_USED_EVENT_IDX feature, we need to
+        * either clear the flags bit or point the event index at the next
+        * entry. Always do both to keep code simple. */
+       vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
+       /* TODO: tune this threshold */
+       bufs = (u16)(vq->vring.avail->idx - vq->last_used_idx) * 3 / 4;
+       vring_used_event(&vq->vring) = vq->last_used_idx + bufs;
+       virtio_mb();
+       if (unlikely((u16)(vq->vring.used->idx - vq->last_used_idx) > bufs)) {
+               END_USE(vq);
+               return false;
+       }
+
+       END_USE(vq);
+       return true;
+}
+EXPORT_SYMBOL_GPL(virtqueue_enable_cb_delayed);
+
 void *virtqueue_detach_unused_buf(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
@@ -438,6 +484,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
 #endif
 
        vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC);
+       vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX);
 
        /* No callback?  Tell other side not to bother us. */
        if (!callback)
@@ -472,6 +519,8 @@ void vring_transport_features(struct virtio_device *vdev)
                switch (i) {
                case VIRTIO_RING_F_INDIRECT_DESC:
                        break;
+               case VIRTIO_RING_F_EVENT_IDX:
+                       break;
                default:
                        /* We don't understand this bit. */
                        clear_bit(i, vdev->features);
index 7c608c5ccf84f856cf476d28c7b01f87c3f1c5f9..979d6eed9a0ff5178657ad5a36a1f203b87814b2 100644 (file)
@@ -42,7 +42,7 @@ config W1_MASTER_MXC
 
 config W1_MASTER_DS1WM
        tristate "Maxim DS1WM 1-wire busmaster"
-       depends on W1 && ARM && HAVE_CLK
+       depends on W1 && GENERIC_HARDIRQS
        help
          Say Y here to enable the DS1WM 1-wire driver, such as that
          in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like
index 2f4fa02744a5680673625f48192a7111008053a3..ad57593d224a1f3200a0ef818b36bcb22f6fdf75 100644 (file)
@@ -33,6 +33,7 @@
 #define DS1WM_INT      0x02    /* R/W interrupt status */
 #define DS1WM_INT_EN   0x03    /* R/W interrupt enable */
 #define DS1WM_CLKDIV   0x04    /* R/W 5 bits of divisor and pre-scale */
+#define DS1WM_CNTRL    0x05    /* R/W master control register (not used yet) */
 
 #define DS1WM_CMD_1W_RESET  (1 << 0)   /* force reset on 1-wire bus */
 #define DS1WM_CMD_SRA      (1 << 1)    /* enable Search ROM accelerator mode */
@@ -56,6 +57,7 @@
 #define DS1WM_INTEN_ERSRF   (1 << 5)   /* enable rx shift register full int */
 #define DS1WM_INTEN_DQO            (1 << 6)    /* enable direct bus driving ops */
 
+#define DS1WM_INTEN_NOT_IAS (~DS1WM_INTEN_IAS) /* all but INTR active state */
 
 #define DS1WM_TIMEOUT (HZ * 5)
 
@@ -63,41 +65,50 @@ static struct {
        unsigned long freq;
        unsigned long divisor;
 } freq[] = {
-       { 4000000, 0x8 },
-       { 5000000, 0x2 },
-       { 6000000, 0x5 },
-       { 7000000, 0x3 },
-       { 8000000, 0xc },
-       { 10000000, 0x6 },
-       { 12000000, 0x9 },
-       { 14000000, 0x7 },
-       { 16000000, 0x10 },
-       { 20000000, 0xa },
-       { 24000000, 0xd },
-       { 28000000, 0xb },
-       { 32000000, 0x14 },
-       { 40000000, 0xe },
-       { 48000000, 0x11 },
-       { 56000000, 0xf },
-       { 64000000, 0x18 },
-       { 80000000, 0x12 },
-       { 96000000, 0x15 },
-       { 112000000, 0x13 },
-       { 128000000, 0x1c },
+       {   1000000, 0x80 },
+       {   2000000, 0x84 },
+       {   3000000, 0x81 },
+       {   4000000, 0x88 },
+       {   5000000, 0x82 },
+       {   6000000, 0x85 },
+       {   7000000, 0x83 },
+       {   8000000, 0x8c },
+       {  10000000, 0x86 },
+       {  12000000, 0x89 },
+       {  14000000, 0x87 },
+       {  16000000, 0x90 },
+       {  20000000, 0x8a },
+       {  24000000, 0x8d },
+       {  28000000, 0x8b },
+       {  32000000, 0x94 },
+       {  40000000, 0x8e },
+       {  48000000, 0x91 },
+       {  56000000, 0x8f },
+       {  64000000, 0x98 },
+       {  80000000, 0x92 },
+       {  96000000, 0x95 },
+       { 112000000, 0x93 },
+       { 128000000, 0x9c },
+/* you can continue this table, consult the OPERATION - CLOCK DIVISOR
+   section of the ds1wm spec sheet. */
 };
 
 struct ds1wm_data {
-       void            __iomem *map;
-       int             bus_shift; /* # of shifts to calc register offsets */
+       void     __iomem *map;
+       int      bus_shift; /* # of shifts to calc register offsets */
        struct platform_device *pdev;
-       const struct mfd_cell *cell;
-       int             irq;
-       int             active_high;
-       int             slave_present;
-       void            *reset_complete;
-       void            *read_complete;
-       void            *write_complete;
-       u8              read_byte; /* last byte received */
+       const struct mfd_cell   *cell;
+       int      irq;
+       int      slave_present;
+       void     *reset_complete;
+       void     *read_complete;
+       void     *write_complete;
+       int      read_error;
+       /* last byte received */
+       u8       read_byte;
+       /* byte to write that makes all intr disabled, */
+       /* considering active_state (IAS) (optimization) */
+       u8       int_en_reg_none;
 };
 
 static inline void ds1wm_write_register(struct ds1wm_data *ds1wm_data, u32 reg,
@@ -115,23 +126,39 @@ static inline u8 ds1wm_read_register(struct ds1wm_data *ds1wm_data, u32 reg)
 static irqreturn_t ds1wm_isr(int isr, void *data)
 {
        struct ds1wm_data *ds1wm_data = data;
-       u8 intr = ds1wm_read_register(ds1wm_data, DS1WM_INT);
+       u8 intr;
+       u8 inten = ds1wm_read_register(ds1wm_data, DS1WM_INT_EN);
+       /* if no bits are set in int enable register (except the IAS)
+       than go no further, reading the regs below has side effects */
+       if (!(inten & DS1WM_INTEN_NOT_IAS))
+               return IRQ_NONE;
 
-       ds1wm_data->slave_present = (intr & DS1WM_INT_PDR) ? 0 : 1;
+       ds1wm_write_register(ds1wm_data,
+               DS1WM_INT_EN, ds1wm_data->int_en_reg_none);
 
-       if ((intr & DS1WM_INT_PD) && ds1wm_data->reset_complete)
-               complete(ds1wm_data->reset_complete);
+       /* this read action clears the INTR and certain flags in ds1wm */
+       intr = ds1wm_read_register(ds1wm_data, DS1WM_INT);
 
-       if ((intr & DS1WM_INT_TSRE) && ds1wm_data->write_complete)
-               complete(ds1wm_data->write_complete);
+       ds1wm_data->slave_present = (intr & DS1WM_INT_PDR) ? 0 : 1;
 
+       if ((intr & DS1WM_INT_TSRE) && ds1wm_data->write_complete) {
+               inten &= ~DS1WM_INTEN_ETMT;
+               complete(ds1wm_data->write_complete);
+       }
        if (intr & DS1WM_INT_RBF) {
+               /* this read clears the RBF flag */
                ds1wm_data->read_byte = ds1wm_read_register(ds1wm_data,
-                                                           DS1WM_DATA);
+               DS1WM_DATA);
+               inten &= ~DS1WM_INTEN_ERBF;
                if (ds1wm_data->read_complete)
                        complete(ds1wm_data->read_complete);
        }
+       if ((intr & DS1WM_INT_PD) && ds1wm_data->reset_complete) {
+               inten &= ~DS1WM_INTEN_EPD;
+               complete(ds1wm_data->reset_complete);
+       }
 
+       ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, inten);
        return IRQ_HANDLED;
 }
 
@@ -142,33 +169,19 @@ static int ds1wm_reset(struct ds1wm_data *ds1wm_data)
 
        ds1wm_data->reset_complete = &reset_done;
 
+       /* enable Presence detect only */
        ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, DS1WM_INTEN_EPD |
-               (ds1wm_data->active_high ? DS1WM_INTEN_IAS : 0));
+       ds1wm_data->int_en_reg_none);
 
        ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_1W_RESET);
 
        timeleft = wait_for_completion_timeout(&reset_done, DS1WM_TIMEOUT);
        ds1wm_data->reset_complete = NULL;
        if (!timeleft) {
-               dev_err(&ds1wm_data->pdev->dev, "reset failed\n");
+               dev_err(&ds1wm_data->pdev->dev, "reset failed, timed out\n");
                return 1;
        }
 
-       /* Wait for the end of the reset. According to the specs, the time
-        * from when the interrupt is asserted to the end of the reset is:
-        *     tRSTH  - tPDH  - tPDL - tPDI
-        *     625 us - 60 us - 240 us - 100 ns = 324.9 us
-        *
-        * We'll wait a bit longer just to be sure.
-        * Was udelay(500), but if it is going to busywait the cpu that long,
-        * might as well come back later.
-        */
-       msleep(1);
-
-       ds1wm_write_register(ds1wm_data, DS1WM_INT_EN,
-               DS1WM_INTEN_ERBF | DS1WM_INTEN_ETMT | DS1WM_INTEN_EPD |
-               (ds1wm_data->active_high ? DS1WM_INTEN_IAS : 0));
-
        if (!ds1wm_data->slave_present) {
                dev_dbg(&ds1wm_data->pdev->dev, "reset: no devices found\n");
                return 1;
@@ -179,26 +192,47 @@ static int ds1wm_reset(struct ds1wm_data *ds1wm_data)
 
 static int ds1wm_write(struct ds1wm_data *ds1wm_data, u8 data)
 {
+       unsigned long timeleft;
        DECLARE_COMPLETION_ONSTACK(write_done);
        ds1wm_data->write_complete = &write_done;
 
+       ds1wm_write_register(ds1wm_data, DS1WM_INT_EN,
+       ds1wm_data->int_en_reg_none | DS1WM_INTEN_ETMT);
+
        ds1wm_write_register(ds1wm_data, DS1WM_DATA, data);
 
-       wait_for_completion_timeout(&write_done, DS1WM_TIMEOUT);
+       timeleft = wait_for_completion_timeout(&write_done, DS1WM_TIMEOUT);
+
        ds1wm_data->write_complete = NULL;
+       if (!timeleft) {
+               dev_err(&ds1wm_data->pdev->dev, "write failed, timed out\n");
+               return -ETIMEDOUT;
+       }
 
        return 0;
 }
 
-static int ds1wm_read(struct ds1wm_data *ds1wm_data, unsigned char write_data)
+static u8 ds1wm_read(struct ds1wm_data *ds1wm_data, unsigned char write_data)
 {
+       unsigned long timeleft;
+       u8 intEnable = DS1WM_INTEN_ERBF | ds1wm_data->int_en_reg_none;
        DECLARE_COMPLETION_ONSTACK(read_done);
+
+       ds1wm_read_register(ds1wm_data, DS1WM_DATA);
+
        ds1wm_data->read_complete = &read_done;
+       ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, intEnable);
 
-       ds1wm_write(ds1wm_data, write_data);
-       wait_for_completion_timeout(&read_done, DS1WM_TIMEOUT);
-       ds1wm_data->read_complete = NULL;
+       ds1wm_write_register(ds1wm_data, DS1WM_DATA, write_data);
+       timeleft = wait_for_completion_timeout(&read_done, DS1WM_TIMEOUT);
 
+       ds1wm_data->read_complete = NULL;
+       if (!timeleft) {
+               dev_err(&ds1wm_data->pdev->dev, "read failed, timed out\n");
+               ds1wm_data->read_error = -ETIMEDOUT;
+               return 0xFF;
+       }
+       ds1wm_data->read_error = 0;
        return ds1wm_data->read_byte;
 }
 
@@ -206,8 +240,8 @@ static int ds1wm_find_divisor(int gclk)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(freq); i++)
-               if (gclk <= freq[i].freq)
+       for (i = ARRAY_SIZE(freq)-1; i >= 0; --i)
+               if (gclk >= freq[i].freq)
                        return freq[i].divisor;
 
        return 0;
@@ -216,12 +250,14 @@ static int ds1wm_find_divisor(int gclk)
 static void ds1wm_up(struct ds1wm_data *ds1wm_data)
 {
        int divisor;
-       struct ds1wm_driver_data *plat = mfd_get_data(ds1wm_data->pdev);
+       struct ds1wm_driver_data *plat = ds1wm_data->pdev->dev.platform_data;
 
        if (ds1wm_data->cell->enable)
                ds1wm_data->cell->enable(ds1wm_data->pdev);
 
        divisor = ds1wm_find_divisor(plat->clock_rate);
+       dev_dbg(&ds1wm_data->pdev->dev,
+               "found divisor 0x%x for clock %d\n", divisor, plat->clock_rate);
        if (divisor == 0) {
                dev_err(&ds1wm_data->pdev->dev,
                        "no suitable divisor for %dHz clock\n",
@@ -242,7 +278,7 @@ static void ds1wm_down(struct ds1wm_data *ds1wm_data)
 
        /* Disable interrupts. */
        ds1wm_write_register(ds1wm_data, DS1WM_INT_EN,
-                            ds1wm_data->active_high ? DS1WM_INTEN_IAS : 0);
+               ds1wm_data->int_en_reg_none);
 
        if (ds1wm_data->cell->disable)
                ds1wm_data->cell->disable(ds1wm_data->pdev);
@@ -279,41 +315,121 @@ static void ds1wm_search(void *data, struct w1_master *master_dev,
 {
        struct ds1wm_data *ds1wm_data = data;
        int i;
-       unsigned long long rom_id;
-
-       /* XXX We need to iterate for multiple devices per the DS1WM docs.
-        * See http://www.maxim-ic.com/appnotes.cfm/appnote_number/120. */
-       if (ds1wm_reset(ds1wm_data))
-               return;
-
-       ds1wm_write(ds1wm_data, search_type);
-       ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_SRA);
-
-       for (rom_id = 0, i = 0; i < 16; i++) {
-
-               unsigned char resp, r, d;
-
-               resp = ds1wm_read(ds1wm_data, 0x00);
-
-               r = ((resp & 0x02) >> 1) |
-                   ((resp & 0x08) >> 2) |
-                   ((resp & 0x20) >> 3) |
-                   ((resp & 0x80) >> 4);
-
-               d = ((resp & 0x01) >> 0) |
-                   ((resp & 0x04) >> 1) |
-                   ((resp & 0x10) >> 2) |
-                   ((resp & 0x40) >> 3);
-
-               rom_id |= (unsigned long long) r << (i * 4);
-
-       }
-       dev_dbg(&ds1wm_data->pdev->dev, "found 0x%08llX\n", rom_id);
-
-       ds1wm_write_register(ds1wm_data, DS1WM_CMD, ~DS1WM_CMD_SRA);
-       ds1wm_reset(ds1wm_data);
-
-       slave_found(master_dev, rom_id);
+       int ms_discrep_bit = -1;
+       u64 r = 0; /* holds the progress of the search */
+       u64 r_prime, d;
+       unsigned slaves_found = 0;
+       unsigned int pass = 0;
+
+       dev_dbg(&ds1wm_data->pdev->dev, "search begin\n");
+       while (true) {
+               ++pass;
+               if (pass > 100) {
+                       dev_dbg(&ds1wm_data->pdev->dev,
+                               "too many attempts (100), search aborted\n");
+                       return;
+               }
+
+               if (ds1wm_reset(ds1wm_data)) {
+                       dev_dbg(&ds1wm_data->pdev->dev,
+                               "pass: %d reset error (or no slaves)\n", pass);
+                       break;
+               }
+
+               dev_dbg(&ds1wm_data->pdev->dev,
+                       "pass: %d r : %0#18llx writing SEARCH_ROM\n", pass, r);
+               ds1wm_write(ds1wm_data, search_type);
+               dev_dbg(&ds1wm_data->pdev->dev,
+                       "pass: %d entering ASM\n", pass);
+               ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_SRA);
+               dev_dbg(&ds1wm_data->pdev->dev,
+                       "pass: %d begining nibble loop\n", pass);
+
+               r_prime = 0;
+               d = 0;
+               /* we work one nibble at a time */
+               /* each nibble is interleaved to form a byte */
+               for (i = 0; i < 16; i++) {
+
+                       unsigned char resp, _r, _r_prime, _d;
+
+                       _r = (r >> (4*i)) & 0xf;
+                       _r = ((_r & 0x1) << 1) |
+                       ((_r & 0x2) << 2) |
+                       ((_r & 0x4) << 3) |
+                       ((_r & 0x8) << 4);
+
+                       /* writes _r, then reads back: */
+                       resp = ds1wm_read(ds1wm_data, _r);
+
+                       if (ds1wm_data->read_error) {
+                               dev_err(&ds1wm_data->pdev->dev,
+                               "pass: %d nibble: %d read error\n", pass, i);
+                               break;
+                       }
+
+                       _r_prime = ((resp & 0x02) >> 1) |
+                       ((resp & 0x08) >> 2) |
+                       ((resp & 0x20) >> 3) |
+                       ((resp & 0x80) >> 4);
+
+                       _d = ((resp & 0x01) >> 0) |
+                       ((resp & 0x04) >> 1) |
+                       ((resp & 0x10) >> 2) |
+                       ((resp & 0x40) >> 3);
+
+                       r_prime |= (unsigned long long) _r_prime << (i * 4);
+                       d |= (unsigned long long) _d << (i * 4);
+
+               }
+               if (ds1wm_data->read_error) {
+                       dev_err(&ds1wm_data->pdev->dev,
+                               "pass: %d read error, retrying\n", pass);
+                       break;
+               }
+               dev_dbg(&ds1wm_data->pdev->dev,
+                       "pass: %d r\': %0#18llx d:%0#18llx\n",
+                       pass, r_prime, d);
+               dev_dbg(&ds1wm_data->pdev->dev,
+                       "pass: %d nibble loop complete, exiting ASM\n", pass);
+               ds1wm_write_register(ds1wm_data, DS1WM_CMD, ~DS1WM_CMD_SRA);
+               dev_dbg(&ds1wm_data->pdev->dev,
+                       "pass: %d resetting bus\n", pass);
+               ds1wm_reset(ds1wm_data);
+               if ((r_prime & ((u64)1 << 63)) && (d & ((u64)1 << 63))) {
+                       dev_err(&ds1wm_data->pdev->dev,
+                               "pass: %d bus error, retrying\n", pass);
+                       continue; /* start over */
+               }
+
+
+               dev_dbg(&ds1wm_data->pdev->dev,
+                       "pass: %d found %0#18llx\n", pass, r_prime);
+               slave_found(master_dev, r_prime);
+               ++slaves_found;
+               dev_dbg(&ds1wm_data->pdev->dev,
+                       "pass: %d complete, preparing next pass\n", pass);
+
+               /* any discrepency found which we already choose the
+                  '1' branch is now is now irrelevant we reveal the
+                  next branch with this: */
+               d &= ~r;
+               /* find last bit set, i.e. the most signif. bit set */
+               ms_discrep_bit = fls64(d) - 1;
+               dev_dbg(&ds1wm_data->pdev->dev,
+                       "pass: %d new d:%0#18llx MS discrep bit:%d\n",
+                       pass, d, ms_discrep_bit);
+
+               /* prev_ms_discrep_bit = ms_discrep_bit;
+                  prepare for next ROM search:             */
+               if (ms_discrep_bit == -1)
+                       break;
+
+               r = (r &  ~(~0ull << (ms_discrep_bit))) | 1 << ms_discrep_bit;
+       } /* end while true */
+       dev_dbg(&ds1wm_data->pdev->dev,
+               "pass: %d total: %d search done ms d bit pos: %d\n", pass,
+               slaves_found, ms_discrep_bit);
 }
 
 /* --------------------------------------------------------------------- */
@@ -351,13 +467,21 @@ static int ds1wm_probe(struct platform_device *pdev)
                ret = -ENOMEM;
                goto err0;
        }
-       plat = mfd_get_data(pdev);
 
        /* calculate bus shift from mem resource */
        ds1wm_data->bus_shift = resource_size(res) >> 3;
 
        ds1wm_data->pdev = pdev;
        ds1wm_data->cell = mfd_get_cell(pdev);
+       if (!ds1wm_data->cell) {
+               ret = -ENODEV;
+               goto err1;
+       }
+       plat = pdev->dev.platform_data;
+       if (!plat) {
+               ret = -ENODEV;
+               goto err1;
+       }
 
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
@@ -365,15 +489,15 @@ static int ds1wm_probe(struct platform_device *pdev)
                goto err1;
        }
        ds1wm_data->irq = res->start;
-       ds1wm_data->active_high = plat->active_high;
+       ds1wm_data->int_en_reg_none = (plat->active_high ? DS1WM_INTEN_IAS : 0);
 
        if (res->flags & IORESOURCE_IRQ_HIGHEDGE)
                irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_RISING);
        if (res->flags & IORESOURCE_IRQ_LOWEDGE)
                irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING);
 
-       ret = request_irq(ds1wm_data->irq, ds1wm_isr, IRQF_DISABLED,
-                         "ds1wm", ds1wm_data);
+       ret = request_irq(ds1wm_data->irq, ds1wm_isr,
+                       IRQF_DISABLED | IRQF_SHARED, "ds1wm", ds1wm_data);
        if (ret)
                goto err1;
 
@@ -460,5 +584,6 @@ module_exit(ds1wm_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, "
-             "Matt Reimer <mreimer@vpop.net>");
+       "Matt Reimer <mreimer@vpop.net>,"
+       "Jean-Francois Dagenais <dagenaisj@sonatest.com>");
 MODULE_DESCRIPTION("DS1WM w1 busmaster driver");
index f0c909625bd1246991af2b0cda78de80b1d504da..d0cb01b42012ff8adff7e60ede81779100172aa3 100644 (file)
@@ -16,6 +16,13 @@ config W1_SLAVE_SMEM
          Say Y here if you want to connect 1-wire
          simple 64bit memory rom(ds2401/ds2411/ds1990*) to your wire.
 
+config W1_SLAVE_DS2408
+        tristate "8-Channel Addressable Switch (IO Expander) 0x29 family support (DS2408)"
+        help
+          Say Y here if you want to use a 1-wire
+
+                 DS2408 8-Channel Addressable Switch device support
+
 config W1_SLAVE_DS2423
        tristate "Counter 1-wire device (DS2423)"
        select CRC16
@@ -61,6 +68,19 @@ config W1_SLAVE_DS2760
 
          If you are unsure, say N.
 
+config W1_SLAVE_DS2780
+       tristate "Dallas 2780 battery monitor chip"
+       depends on W1
+       help
+         If you enable this you will have the DS2780 battery monitor
+         chip support.
+
+         The battery monitor chip is used in many batteries/devices
+         as the one who is responsible for charging/discharging/monitoring
+         Li+ batteries.
+
+         If you are unsure, say N.
+
 config W1_SLAVE_BQ27000
        tristate "BQ27000 slave support"
        depends on W1
index 3c76350a24f7656097d6fde70673d50be4c4ca9c..1f31e9fb0b25bed05a08bbe7e9997bbabe74e817 100644 (file)
@@ -4,8 +4,10 @@
 
 obj-$(CONFIG_W1_SLAVE_THERM)   += w1_therm.o
 obj-$(CONFIG_W1_SLAVE_SMEM)    += w1_smem.o
+obj-$(CONFIG_W1_SLAVE_DS2408)   += w1_ds2408.o
 obj-$(CONFIG_W1_SLAVE_DS2423)  += w1_ds2423.o
 obj-$(CONFIG_W1_SLAVE_DS2431)  += w1_ds2431.o
 obj-$(CONFIG_W1_SLAVE_DS2433)  += w1_ds2433.o
 obj-$(CONFIG_W1_SLAVE_DS2760)  += w1_ds2760.o
+obj-$(CONFIG_W1_SLAVE_DS2780)  += w1_ds2780.o
 obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o
diff --git a/drivers/w1/slaves/w1_ds2408.c b/drivers/w1/slaves/w1_ds2408.c
new file mode 100644 (file)
index 0000000..c377818
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ *     w1_ds2408.c - w1 family 29 (DS2408) driver
+ *
+ * Copyright (c) 2010 Jean-Francois Dagenais <dagenaisj@sonatest.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jean-Francois Dagenais <dagenaisj@sonatest.com>");
+MODULE_DESCRIPTION("w1 family 29 driver for DS2408 8 Pin IO");
+
+
+#define W1_F29_RETRIES         3
+
+#define W1_F29_REG_LOGIG_STATE             0x88 /* R */
+#define W1_F29_REG_OUTPUT_LATCH_STATE      0x89 /* R */
+#define W1_F29_REG_ACTIVITY_LATCH_STATE    0x8A /* R */
+#define W1_F29_REG_COND_SEARCH_SELECT_MASK 0x8B /* RW */
+#define W1_F29_REG_COND_SEARCH_POL_SELECT  0x8C /* RW */
+#define W1_F29_REG_CONTROL_AND_STATUS      0x8D /* RW */
+
+#define W1_F29_FUNC_READ_PIO_REGS          0xF0
+#define W1_F29_FUNC_CHANN_ACCESS_READ      0xF5
+#define W1_F29_FUNC_CHANN_ACCESS_WRITE     0x5A
+/* also used to write the control/status reg (0x8D): */
+#define W1_F29_FUNC_WRITE_COND_SEARCH_REG  0xCC
+#define W1_F29_FUNC_RESET_ACTIVITY_LATCHES 0xC3
+
+#define W1_F29_SUCCESS_CONFIRM_BYTE        0xAA
+
+static int _read_reg(struct w1_slave *sl, u8 address, unsigned char* buf)
+{
+       u8 wrbuf[3];
+       dev_dbg(&sl->dev,
+                       "Reading with slave: %p, reg addr: %0#4x, buff addr: %p",
+                       sl, (unsigned int)address, buf);
+
+       if (!buf)
+               return -EINVAL;
+
+       mutex_lock(&sl->master->mutex);
+       dev_dbg(&sl->dev, "mutex locked");
+
+       if (w1_reset_select_slave(sl)) {
+               mutex_unlock(&sl->master->mutex);
+               return -EIO;
+       }
+
+       wrbuf[0] = W1_F29_FUNC_READ_PIO_REGS;
+       wrbuf[1] = address;
+       wrbuf[2] = 0;
+       w1_write_block(sl->master, wrbuf, 3);
+       *buf = w1_read_8(sl->master);
+
+       mutex_unlock(&sl->master->mutex);
+       dev_dbg(&sl->dev, "mutex unlocked");
+       return 1;
+}
+
+static ssize_t w1_f29_read_state(
+       struct file *filp, struct kobject *kobj,
+       struct bin_attribute *bin_attr,
+       char *buf, loff_t off, size_t count)
+{
+       dev_dbg(&kobj_to_w1_slave(kobj)->dev,
+               "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
+               bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
+       if (count != 1 || off != 0)
+               return -EFAULT;
+       return _read_reg(kobj_to_w1_slave(kobj), W1_F29_REG_LOGIG_STATE, buf);
+}
+
+static ssize_t w1_f29_read_output(
+       struct file *filp, struct kobject *kobj,
+       struct bin_attribute *bin_attr,
+       char *buf, loff_t off, size_t count)
+{
+       dev_dbg(&kobj_to_w1_slave(kobj)->dev,
+               "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
+               bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
+       if (count != 1 || off != 0)
+               return -EFAULT;
+       return _read_reg(kobj_to_w1_slave(kobj),
+                                        W1_F29_REG_OUTPUT_LATCH_STATE, buf);
+}
+
+static ssize_t w1_f29_read_activity(
+       struct file *filp, struct kobject *kobj,
+       struct bin_attribute *bin_attr,
+       char *buf, loff_t off, size_t count)
+{
+       dev_dbg(&kobj_to_w1_slave(kobj)->dev,
+               "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
+               bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
+       if (count != 1 || off != 0)
+               return -EFAULT;
+       return _read_reg(kobj_to_w1_slave(kobj),
+                                        W1_F29_REG_ACTIVITY_LATCH_STATE, buf);
+}
+
+static ssize_t w1_f29_read_cond_search_mask(
+       struct file *filp, struct kobject *kobj,
+       struct bin_attribute *bin_attr,
+       char *buf, loff_t off, size_t count)
+{
+       dev_dbg(&kobj_to_w1_slave(kobj)->dev,
+               "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
+               bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
+       if (count != 1 || off != 0)
+               return -EFAULT;
+       return _read_reg(kobj_to_w1_slave(kobj),
+               W1_F29_REG_COND_SEARCH_SELECT_MASK, buf);
+}
+
+static ssize_t w1_f29_read_cond_search_polarity(
+       struct file *filp, struct kobject *kobj,
+       struct bin_attribute *bin_attr,
+       char *buf, loff_t off, size_t count)
+{
+       if (count != 1 || off != 0)
+               return -EFAULT;
+       return _read_reg(kobj_to_w1_slave(kobj),
+               W1_F29_REG_COND_SEARCH_POL_SELECT, buf);
+}
+
+static ssize_t w1_f29_read_status_control(
+       struct file *filp, struct kobject *kobj,
+       struct bin_attribute *bin_attr,
+       char *buf, loff_t off, size_t count)
+{
+       if (count != 1 || off != 0)
+               return -EFAULT;
+       return _read_reg(kobj_to_w1_slave(kobj),
+               W1_F29_REG_CONTROL_AND_STATUS, buf);
+}
+
+
+
+
+static ssize_t w1_f29_write_output(
+       struct file *filp, struct kobject *kobj,
+       struct bin_attribute *bin_attr,
+       char *buf, loff_t off, size_t count)
+{
+       struct w1_slave *sl = kobj_to_w1_slave(kobj);
+       u8 w1_buf[3];
+       u8 readBack;
+       unsigned int retries = W1_F29_RETRIES;
+
+       if (count != 1 || off != 0)
+               return -EFAULT;
+
+       dev_dbg(&sl->dev, "locking mutex for write_output");
+       mutex_lock(&sl->master->mutex);
+       dev_dbg(&sl->dev, "mutex locked");
+
+       if (w1_reset_select_slave(sl))
+               goto error;
+
+       while (retries--) {
+               w1_buf[0] = W1_F29_FUNC_CHANN_ACCESS_WRITE;
+               w1_buf[1] = *buf;
+               w1_buf[2] = ~(*buf);
+               w1_write_block(sl->master, w1_buf, 3);
+
+               readBack = w1_read_8(sl->master);
+               /* here the master could read another byte which
+                  would be the PIO reg (the actual pin logic state)
+                  since in this driver we don't know which pins are
+                  in and outs, there's no value to read the state and
+                  compare. with (*buf) so end this command abruptly: */
+               if (w1_reset_resume_command(sl->master))
+                       goto error;
+
+               if (readBack != 0xAA) {
+                       /* try again, the slave is ready for a command */
+                       continue;
+               }
+
+               /* go read back the output latches */
+               /* (the direct effect of the write above) */
+               w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
+               w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE;
+               w1_buf[2] = 0;
+               w1_write_block(sl->master, w1_buf, 3);
+               /* read the result of the READ_PIO_REGS command */
+               if (w1_read_8(sl->master) == *buf) {
+                       /* success! */
+                       mutex_unlock(&sl->master->mutex);
+                       dev_dbg(&sl->dev,
+                               "mutex unlocked, retries:%d", retries);
+                       return 1;
+               }
+       }
+error:
+       mutex_unlock(&sl->master->mutex);
+       dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries);
+
+       return -EIO;
+}
+
+
+/**
+ * Writing to the activity file resets the activity latches.
+ */
+static ssize_t w1_f29_write_activity(
+       struct file *filp, struct kobject *kobj,
+       struct bin_attribute *bin_attr,
+       char *buf, loff_t off, size_t count)
+{
+       struct w1_slave *sl = kobj_to_w1_slave(kobj);
+       unsigned int retries = W1_F29_RETRIES;
+
+       if (count != 1 || off != 0)
+               return -EFAULT;
+
+       mutex_lock(&sl->master->mutex);
+
+       if (w1_reset_select_slave(sl))
+               goto error;
+
+       while (retries--) {
+               w1_write_8(sl->master, W1_F29_FUNC_RESET_ACTIVITY_LATCHES);
+               if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE) {
+                       mutex_unlock(&sl->master->mutex);
+                       return 1;
+               }
+               if (w1_reset_resume_command(sl->master))
+                       goto error;
+       }
+
+error:
+       mutex_unlock(&sl->master->mutex);
+       return -EIO;
+}
+
+static ssize_t w1_f29_write_status_control(
+       struct file *filp,
+       struct kobject *kobj,
+       struct bin_attribute *bin_attr,
+       char *buf,
+       loff_t off,
+       size_t count)
+{
+       struct w1_slave *sl = kobj_to_w1_slave(kobj);
+       u8 w1_buf[4];
+       unsigned int retries = W1_F29_RETRIES;
+
+       if (count != 1 || off != 0)
+               return -EFAULT;
+
+       mutex_lock(&sl->master->mutex);
+
+       if (w1_reset_select_slave(sl))
+               goto error;
+
+       while (retries--) {
+               w1_buf[0] = W1_F29_FUNC_WRITE_COND_SEARCH_REG;
+               w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
+               w1_buf[2] = 0;
+               w1_buf[3] = *buf;
+
+               w1_write_block(sl->master, w1_buf, 4);
+               if (w1_reset_resume_command(sl->master))
+                       goto error;
+
+               w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
+               w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
+               w1_buf[2] = 0;
+
+               w1_write_block(sl->master, w1_buf, 3);
+               if (w1_read_8(sl->master) == *buf) {
+                       /* success! */
+                       mutex_unlock(&sl->master->mutex);
+                       return 1;
+               }
+       }
+error:
+       mutex_unlock(&sl->master->mutex);
+
+       return -EIO;
+}
+
+
+
+#define NB_SYSFS_BIN_FILES 6
+static struct bin_attribute w1_f29_sysfs_bin_files[NB_SYSFS_BIN_FILES] = {
+       {
+               .attr = {
+                       .name = "state",
+                       .mode = S_IRUGO,
+               },
+               .size = 1,
+               .read = w1_f29_read_state,
+       },
+       {
+               .attr = {
+                       .name = "output",
+                       .mode = S_IRUGO | S_IWUSR | S_IWGRP,
+               },
+               .size = 1,
+               .read = w1_f29_read_output,
+               .write = w1_f29_write_output,
+       },
+       {
+               .attr = {
+                       .name = "activity",
+                       .mode = S_IRUGO,
+               },
+               .size = 1,
+               .read = w1_f29_read_activity,
+               .write = w1_f29_write_activity,
+       },
+       {
+               .attr = {
+                       .name = "cond_search_mask",
+                       .mode = S_IRUGO,
+               },
+               .size = 1,
+               .read = w1_f29_read_cond_search_mask,
+               .write = 0,
+       },
+       {
+               .attr = {
+                       .name = "cond_search_polarity",
+                       .mode = S_IRUGO,
+               },
+               .size = 1,
+               .read = w1_f29_read_cond_search_polarity,
+               .write = 0,
+       },
+       {
+               .attr = {
+                       .name = "status_control",
+                       .mode = S_IRUGO | S_IWUSR | S_IWGRP,
+               },
+               .size = 1,
+               .read = w1_f29_read_status_control,
+               .write = w1_f29_write_status_control,
+       }
+};
+
+static int w1_f29_add_slave(struct w1_slave *sl)
+{
+       int err = 0;
+       int i;
+
+       for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
+               err = sysfs_create_bin_file(
+                       &sl->dev.kobj,
+                       &(w1_f29_sysfs_bin_files[i]));
+       if (err)
+               while (--i >= 0)
+                       sysfs_remove_bin_file(&sl->dev.kobj,
+                               &(w1_f29_sysfs_bin_files[i]));
+       return err;
+}
+
+static void w1_f29_remove_slave(struct w1_slave *sl)
+{
+       int i;
+       for (i = NB_SYSFS_BIN_FILES; i <= 0; --i)
+               sysfs_remove_bin_file(&sl->dev.kobj,
+                       &(w1_f29_sysfs_bin_files[i]));
+}
+
+static struct w1_family_ops w1_f29_fops = {
+       .add_slave      = w1_f29_add_slave,
+       .remove_slave   = w1_f29_remove_slave,
+};
+
+static struct w1_family w1_family_29 = {
+       .fid = W1_FAMILY_DS2408,
+       .fops = &w1_f29_fops,
+};
+
+static int __init w1_f29_init(void)
+{
+       return w1_register_family(&w1_family_29);
+}
+
+static void __exit w1_f29_exit(void)
+{
+       w1_unregister_family(&w1_family_29);
+}
+
+module_init(w1_f29_init);
+module_exit(w1_f29_exit);
diff --git a/drivers/w1/slaves/w1_ds2780.c b/drivers/w1/slaves/w1_ds2780.c
new file mode 100644 (file)
index 0000000..274c8f3
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * 1-Wire implementation for the ds2780 chip
+ *
+ * Copyright (C) 2010 Indesign, LLC
+ *
+ * Author: Clifton Barnes <cabarnes@indesign-llc.com>
+ *
+ * Based on w1-ds2760 driver
+ *
+ * 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/module.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/idr.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+#include "w1_ds2780.h"
+
+int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
+                       int io)
+{
+       struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+
+       if (!dev)
+               return -ENODEV;
+
+       mutex_lock(&sl->master->mutex);
+
+       if (addr > DS2780_DATA_SIZE || addr < 0) {
+               count = 0;
+               goto out;
+       }
+       count = min_t(int, count, DS2780_DATA_SIZE - addr);
+
+       if (w1_reset_select_slave(sl) == 0) {
+               if (io) {
+                       w1_write_8(sl->master, W1_DS2780_WRITE_DATA);
+                       w1_write_8(sl->master, addr);
+                       w1_write_block(sl->master, buf, count);
+                       /* XXX w1_write_block returns void, not n_written */
+               } else {
+                       w1_write_8(sl->master, W1_DS2780_READ_DATA);
+                       w1_write_8(sl->master, addr);
+                       count = w1_read_block(sl->master, buf, count);
+               }
+       }
+
+out:
+       mutex_unlock(&sl->master->mutex);
+
+       return count;
+}
+EXPORT_SYMBOL(w1_ds2780_io);
+
+int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd)
+{
+       struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+
+       if (!dev)
+               return -EINVAL;
+
+       mutex_lock(&sl->master->mutex);
+
+       if (w1_reset_select_slave(sl) == 0) {
+               w1_write_8(sl->master, cmd);
+               w1_write_8(sl->master, addr);
+       }
+
+       mutex_unlock(&sl->master->mutex);
+       return 0;
+}
+EXPORT_SYMBOL(w1_ds2780_eeprom_cmd);
+
+static ssize_t w1_ds2780_read_bin(struct file *filp,
+                                 struct kobject *kobj,
+                                 struct bin_attribute *bin_attr,
+                                 char *buf, loff_t off, size_t count)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       return w1_ds2780_io(dev, buf, off, count, 0);
+}
+
+static struct bin_attribute w1_ds2780_bin_attr = {
+       .attr = {
+               .name = "w1_slave",
+               .mode = S_IRUGO,
+       },
+       .size = DS2780_DATA_SIZE,
+       .read = w1_ds2780_read_bin,
+};
+
+static DEFINE_IDR(bat_idr);
+static DEFINE_MUTEX(bat_idr_lock);
+
+static int new_bat_id(void)
+{
+       int ret;
+
+       while (1) {
+               int id;
+
+               ret = idr_pre_get(&bat_idr, GFP_KERNEL);
+               if (ret == 0)
+                       return -ENOMEM;
+
+               mutex_lock(&bat_idr_lock);
+               ret = idr_get_new(&bat_idr, NULL, &id);
+               mutex_unlock(&bat_idr_lock);
+
+               if (ret == 0) {
+                       ret = id & MAX_ID_MASK;
+                       break;
+               } else if (ret == -EAGAIN) {
+                       continue;
+               } else {
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+static void release_bat_id(int id)
+{
+       mutex_lock(&bat_idr_lock);
+       idr_remove(&bat_idr, id);
+       mutex_unlock(&bat_idr_lock);
+}
+
+static int w1_ds2780_add_slave(struct w1_slave *sl)
+{
+       int ret;
+       int id;
+       struct platform_device *pdev;
+
+       id = new_bat_id();
+       if (id < 0) {
+               ret = id;
+               goto noid;
+       }
+
+       pdev = platform_device_alloc("ds2780-battery", id);
+       if (!pdev) {
+               ret = -ENOMEM;
+               goto pdev_alloc_failed;
+       }
+       pdev->dev.parent = &sl->dev;
+
+       ret = platform_device_add(pdev);
+       if (ret)
+               goto pdev_add_failed;
+
+       ret = sysfs_create_bin_file(&sl->dev.kobj, &w1_ds2780_bin_attr);
+       if (ret)
+               goto bin_attr_failed;
+
+       dev_set_drvdata(&sl->dev, pdev);
+
+       return 0;
+
+bin_attr_failed:
+pdev_add_failed:
+       platform_device_unregister(pdev);
+pdev_alloc_failed:
+       release_bat_id(id);
+noid:
+       return ret;
+}
+
+static void w1_ds2780_remove_slave(struct w1_slave *sl)
+{
+       struct platform_device *pdev = dev_get_drvdata(&sl->dev);
+       int id = pdev->id;
+
+       platform_device_unregister(pdev);
+       release_bat_id(id);
+       sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2780_bin_attr);
+}
+
+static struct w1_family_ops w1_ds2780_fops = {
+       .add_slave    = w1_ds2780_add_slave,
+       .remove_slave = w1_ds2780_remove_slave,
+};
+
+static struct w1_family w1_ds2780_family = {
+       .fid = W1_FAMILY_DS2780,
+       .fops = &w1_ds2780_fops,
+};
+
+static int __init w1_ds2780_init(void)
+{
+       idr_init(&bat_idr);
+       return w1_register_family(&w1_ds2780_family);
+}
+
+static void __exit w1_ds2780_exit(void)
+{
+       w1_unregister_family(&w1_ds2780_family);
+       idr_destroy(&bat_idr);
+}
+
+module_init(w1_ds2780_init);
+module_exit(w1_ds2780_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Clifton Barnes <cabarnes@indesign-llc.com>");
+MODULE_DESCRIPTION("1-wire Driver for Maxim/Dallas DS2780 Stand-Alone Fuel Gauge IC");
diff --git a/drivers/w1/slaves/w1_ds2780.h b/drivers/w1/slaves/w1_ds2780.h
new file mode 100644 (file)
index 0000000..a1fba79
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 1-Wire implementation for the ds2780 chip
+ *
+ * Copyright (C) 2010 Indesign, LLC
+ *
+ * Author: Clifton Barnes <cabarnes@indesign-llc.com>
+ *
+ * Based on w1-ds2760 driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _W1_DS2780_H
+#define _W1_DS2780_H
+
+/* Function commands */
+#define W1_DS2780_READ_DATA            0x69
+#define W1_DS2780_WRITE_DATA           0x6C
+#define W1_DS2780_COPY_DATA            0x48
+#define W1_DS2780_RECALL_DATA          0xB8
+#define W1_DS2780_LOCK                 0x6A
+
+/* Register map */
+/* Register 0x00 Reserved */
+#define DS2780_STATUS_REG              0x01
+#define DS2780_RAAC_MSB_REG            0x02
+#define DS2780_RAAC_LSB_REG            0x03
+#define DS2780_RSAC_MSB_REG            0x04
+#define DS2780_RSAC_LSB_REG            0x05
+#define DS2780_RARC_REG                        0x06
+#define DS2780_RSRC_REG                        0x07
+#define DS2780_IAVG_MSB_REG            0x08
+#define DS2780_IAVG_LSB_REG            0x09
+#define DS2780_TEMP_MSB_REG            0x0A
+#define DS2780_TEMP_LSB_REG            0x0B
+#define DS2780_VOLT_MSB_REG            0x0C
+#define DS2780_VOLT_LSB_REG            0x0D
+#define DS2780_CURRENT_MSB_REG         0x0E
+#define DS2780_CURRENT_LSB_REG         0x0F
+#define DS2780_ACR_MSB_REG             0x10
+#define DS2780_ACR_LSB_REG             0x11
+#define DS2780_ACRL_MSB_REG            0x12
+#define DS2780_ACRL_LSB_REG            0x13
+#define DS2780_AS_REG                  0x14
+#define DS2780_SFR_REG                 0x15
+#define DS2780_FULL_MSB_REG            0x16
+#define DS2780_FULL_LSB_REG            0x17
+#define DS2780_AE_MSB_REG              0x18
+#define DS2780_AE_LSB_REG              0x19
+#define DS2780_SE_MSB_REG              0x1A
+#define DS2780_SE_LSB_REG              0x1B
+/* Register 0x1C - 0x1E Reserved */
+#define DS2780_EEPROM_REG              0x1F
+#define DS2780_EEPROM_BLOCK0_START     0x20
+/* Register 0x20 - 0x2F User EEPROM */
+#define DS2780_EEPROM_BLOCK0_END       0x2F
+/* Register 0x30 - 0x5F Reserved */
+#define DS2780_EEPROM_BLOCK1_START     0x60
+#define DS2780_CONTROL_REG             0x60
+#define DS2780_AB_REG                  0x61
+#define DS2780_AC_MSB_REG              0x62
+#define DS2780_AC_LSB_REG              0x63
+#define DS2780_VCHG_REG                        0x64
+#define DS2780_IMIN_REG                        0x65
+#define DS2780_VAE_REG                 0x66
+#define DS2780_IAE_REG                 0x67
+#define DS2780_AE_40_REG               0x68
+#define DS2780_RSNSP_REG               0x69
+#define DS2780_FULL_40_MSB_REG         0x6A
+#define DS2780_FULL_40_LSB_REG         0x6B
+#define DS2780_FULL_3040_SLOPE_REG     0x6C
+#define DS2780_FULL_2030_SLOPE_REG     0x6D
+#define DS2780_FULL_1020_SLOPE_REG     0x6E
+#define DS2780_FULL_0010_SLOPE_REG     0x6F
+#define DS2780_AE_3040_SLOPE_REG       0x70
+#define DS2780_AE_2030_SLOPE_REG       0x71
+#define DS2780_AE_1020_SLOPE_REG       0x72
+#define DS2780_AE_0010_SLOPE_REG       0x73
+#define DS2780_SE_3040_SLOPE_REG       0x74
+#define DS2780_SE_2030_SLOPE_REG       0x75
+#define DS2780_SE_1020_SLOPE_REG       0x76
+#define DS2780_SE_0010_SLOPE_REG       0x77
+#define DS2780_RSGAIN_MSB_REG          0x78
+#define DS2780_RSGAIN_LSB_REG          0x79
+#define DS2780_RSTC_REG                        0x7A
+#define DS2780_FRSGAIN_MSB_REG         0x7B
+#define DS2780_FRSGAIN_LSB_REG         0x7C
+#define DS2780_EEPROM_BLOCK1_END       0x7C
+/* Register 0x7D - 0xFF Reserved */
+
+/* Number of valid register addresses */
+#define DS2780_DATA_SIZE               0x80
+
+/* Status register bits */
+#define DS2780_STATUS_REG_CHGTF                (1 << 7)
+#define DS2780_STATUS_REG_AEF          (1 << 6)
+#define DS2780_STATUS_REG_SEF          (1 << 5)
+#define DS2780_STATUS_REG_LEARNF       (1 << 4)
+/* Bit 3 Reserved */
+#define DS2780_STATUS_REG_UVF          (1 << 2)
+#define DS2780_STATUS_REG_PORF         (1 << 1)
+/* Bit 0 Reserved */
+
+/* Control register bits */
+/* Bit 7 Reserved */
+#define DS2780_CONTROL_REG_UVEN                (1 << 6)
+#define DS2780_CONTROL_REG_PMOD                (1 << 5)
+#define DS2780_CONTROL_REG_RNAOP       (1 << 4)
+/* Bit 0 - 3 Reserved */
+
+/* Special feature register bits */
+/* Bit 1 - 7 Reserved */
+#define DS2780_SFR_REG_PIOSC           (1 << 0)
+
+/* EEPROM register bits */
+#define DS2780_EEPROM_REG_EEC          (1 << 7)
+#define DS2780_EEPROM_REG_LOCK         (1 << 6)
+/* Bit 2 - 6 Reserved */
+#define DS2780_EEPROM_REG_BL1          (1 << 1)
+#define DS2780_EEPROM_REG_BL0          (1 << 0)
+
+extern int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
+                       int io);
+extern int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd);
+
+#endif /* !_W1_DS2780_H */
index b7b5014ff7140262cbbcbe32d9530cb2936105e3..10606c822756a3c7ab9ba6de5923a263dab67150 100644 (file)
@@ -827,7 +827,7 @@ void w1_reconnect_slaves(struct w1_family *f, int attach)
        mutex_unlock(&w1_mlock);
 }
 
-static void w1_slave_found(struct w1_master *dev, u64 rn)
+void w1_slave_found(struct w1_master *dev, u64 rn)
 {
        struct w1_slave *sl;
        struct w1_reg_num *tmp;
@@ -933,14 +933,15 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb
        }
 }
 
-void w1_search_process(struct w1_master *dev, u8 search_type)
+void w1_search_process_cb(struct w1_master *dev, u8 search_type,
+       w1_slave_found_callback cb)
 {
        struct w1_slave *sl, *sln;
 
        list_for_each_entry(sl, &dev->slist, w1_slave_entry)
                clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
 
-       w1_search_devices(dev, search_type, w1_slave_found);
+       w1_search_devices(dev, search_type, cb);
 
        list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
                if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl)
@@ -953,6 +954,11 @@ void w1_search_process(struct w1_master *dev, u8 search_type)
                dev->search_count--;
 }
 
+static void w1_search_process(struct w1_master *dev, u8 search_type)
+{
+       w1_search_process_cb(dev, search_type, w1_slave_found);
+}
+
 int w1_process(void *data)
 {
        struct w1_master *dev = (struct w1_master *) data;
index d8a9709f3449159a2f8ada1c2ca328316414ed79..1ce23fc6186c36def2f0ed2608fb0b010ab32501 100644 (file)
@@ -55,6 +55,7 @@ struct w1_reg_num
 #define W1_READ_ROM            0x33
 #define W1_READ_PSUPPLY                0xB4
 #define W1_MATCH_ROM           0x55
+#define W1_RESUME_CMD          0xA5
 
 #define W1_SLAVE_ACTIVE                0
 
@@ -193,7 +194,9 @@ void w1_destroy_master_attributes(struct w1_master *master);
 void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb);
 void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb);
 struct w1_slave *w1_search_slave(struct w1_reg_num *id);
-void w1_search_process(struct w1_master *dev, u8 search_type);
+void w1_slave_found(struct w1_master *dev, u64 rn);
+void w1_search_process_cb(struct w1_master *dev, u8 search_type,
+       w1_slave_found_callback cb);
 struct w1_master *w1_search_master_id(u32 id);
 
 /* Disconnect and reconnect devices in the given family.  Used for finding
@@ -213,6 +216,7 @@ void w1_write_block(struct w1_master *, const u8 *, int);
 void w1_touch_block(struct w1_master *, u8 *, int);
 u8 w1_read_block(struct w1_master *, u8 *, int);
 int w1_reset_select_slave(struct w1_slave *sl);
+int w1_reset_resume_command(struct w1_master *);
 void w1_next_pullup(struct w1_master *, int);
 
 static inline struct w1_slave* dev_to_w1_slave(struct device *dev)
index f3b636d7cafe76360bf41e6be048eddb9da3c256..97479ae70b9cbb23da15189f4a2c69941a46d94b 100644 (file)
 #define W1_THERM_DS1822        0x22
 #define W1_EEPROM_DS2433       0x23
 #define W1_THERM_DS18B20       0x28
+#define W1_FAMILY_DS2408       0x29
 #define W1_EEPROM_DS2431       0x2D
 #define W1_FAMILY_DS2760       0x30
+#define W1_FAMILY_DS2780       0x32
 
 #define MAXNAMELEN             32
 
index 3ebe9726a9e55471ae9383fe262fc61de2727200..8e8b64cfafb69a417bded8e6f3f745ca3a7e44a1 100644 (file)
@@ -389,6 +389,32 @@ int w1_reset_select_slave(struct w1_slave *sl)
 }
 EXPORT_SYMBOL_GPL(w1_reset_select_slave);
 
+/**
+ * When the workflow with a slave amongst many requires several
+ * successive commands a reset between each, this function is similar
+ * to doing a reset then a match ROM for the last matched ROM. The
+ * advantage being that the matched ROM step is skipped in favor of the
+ * resume command. The slave must support the command of course.
+ *
+ * If the bus has only one slave, traditionnaly the match ROM is skipped
+ * and a "SKIP ROM" is done for efficiency. On multi-slave busses, this
+ * doesn't work of course, but the resume command is the next best thing.
+ *
+ * The w1 master lock must be held.
+ *
+ * @param dev     the master device
+ */
+int w1_reset_resume_command(struct w1_master *dev)
+{
+       if (w1_reset_bus(dev))
+               return -1;
+
+       /* This will make only the last matched slave perform a skip ROM. */
+       w1_write_8(dev, W1_RESUME_CMD);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(w1_reset_resume_command);
+
 /**
  * Put out a strong pull-up of the specified duration after the next write
  * operation.  Not all hardware supports strong pullups.  Hardware that
index 7e667bc77ef2d02649fbe32cd69b4ab94e06e9f6..55aabd927c60557e82c01a3eb11d92cd9bcd18c1 100644 (file)
@@ -55,6 +55,9 @@ static void w1_send_slave(struct w1_master *dev, u64 rn)
        struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1);
        int avail;
 
+       /* update kernel slave list */
+       w1_slave_found(dev, rn);
+
        avail = dev->priv_size - cmd->len;
 
        if (avail > 8) {
@@ -85,7 +88,7 @@ static int w1_process_search_command(struct w1_master *dev, struct cn_msg *msg,
        dev->priv = msg;
        dev->priv_size = avail;
 
-       w1_search_devices(dev, search_type, w1_send_slave);
+       w1_search_process_cb(dev, search_type, w1_send_slave);
 
        msg->ack = 0;
        cn_netlink_send(msg, 0, GFP_KERNEL);
index d8e725082fdc1c103d66f91eab6694e65af18c06..428f8a1583e8598ae69414f8171e21a3bbbf2ba8 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 #include <linux/mfd/rdc321x.h>
-#include <linux/mfd/core.h>
 
 #define RDC_WDT_MASK   0x80000000 /* Mask */
 #define RDC_WDT_EN     0x00800000 /* Enable bit */
@@ -232,7 +231,7 @@ static int __devinit rdc321x_wdt_probe(struct platform_device *pdev)
        struct resource *r;
        struct rdc321x_wdt_pdata *pdata;
 
-       pdata = mfd_get_data(pdev);
+       pdata = pdev->dev.platform_data;
        if (!pdata) {
                dev_err(&pdev->dev, "no platform data supplied\n");
                return -ENODEV;
index 4781f806701d93c1e1a81917cdb2130d79d491b4..bbc18258ecc5419ec2210b83684afc528fecd0da 100644 (file)
@@ -1,5 +1,6 @@
 obj-y  += grant-table.o features.o events.o manage.o balloon.o
 obj-y  += xenbus/
+obj-y  += tmem.o
 
 nostackp := $(call cc-option, -fno-stack-protector)
 CFLAGS_features.o                      := $(nostackp)
index 3ff822b481454847487b2c3eeaaa18d354f33721..30df85d8fca860d69a75079951feb9bb725944f1 100644 (file)
@@ -395,9 +395,9 @@ static void unmask_evtchn(int port)
 static void xen_irq_init(unsigned irq)
 {
        struct irq_info *info;
+#ifdef CONFIG_SMP
        struct irq_desc *desc = irq_to_desc(irq);
 
-#ifdef CONFIG_SMP
        /* By default all event channels notify CPU#0. */
        cpumask_copy(desc->irq_data.affinity, cpumask_of(0));
 #endif
@@ -626,6 +626,9 @@ int xen_allocate_pirq_gsi(unsigned gsi)
  *
  * Note: We don't assign an event channel until the irq actually started
  * up.  Return an existing irq if we've already got one for the gsi.
+ *
+ * Shareable implies level triggered, not shareable implies edge
+ * triggered here.
  */
 int xen_bind_pirq_gsi_to_irq(unsigned gsi,
                             unsigned pirq, int shareable, char *name)
@@ -664,16 +667,13 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
 
        pirq_query_unmask(irq);
        /* We try to use the handler with the appropriate semantic for the
-        * type of interrupt: if the interrupt doesn't need an eoi
-        * (pirq_needs_eoi returns false), we treat it like an edge
-        * triggered interrupt so we use handle_edge_irq.
-        * As a matter of fact this only happens when the corresponding
-        * physical interrupt is edge triggered or an msi.
+        * type of interrupt: if the interrupt is an edge triggered
+        * interrupt we use handle_edge_irq.
         *
-        * On the other hand if the interrupt needs an eoi (pirq_needs_eoi
-        * returns true) we treat it like a level triggered interrupt so we
-        * use handle_fasteoi_irq like the native code does for this kind of
+        * On the other hand if the interrupt is level triggered we use
+        * handle_fasteoi_irq like the native code does for this kind of
         * interrupts.
+        *
         * Depending on the Xen version, pirq_needs_eoi might return true
         * not only for level triggered interrupts but for edge triggered
         * interrupts too. In any case Xen always honors the eoi mechanism,
@@ -681,7 +681,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
         * hasn't received an eoi yet. Therefore using the fasteoi handler
         * is the right choice either way.
         */
-       if (pirq_needs_eoi(irq))
+       if (shareable)
                irq_set_chip_and_handler_name(irq, &xen_pirq_chip,
                                handle_fasteoi_irq, name);
        else
index 65ea21a974920f299afbaaa1c6e379930098f09b..6e8c15a23201a3a280948cf25142001347a0d6cb 100644 (file)
@@ -147,9 +147,15 @@ void __init xen_swiotlb_init(int verbose)
 {
        unsigned long bytes;
        int rc;
-
-       xen_io_tlb_nslabs = (64 * 1024 * 1024 >> IO_TLB_SHIFT);
-       xen_io_tlb_nslabs = ALIGN(xen_io_tlb_nslabs, IO_TLB_SEGSIZE);
+       unsigned long nr_tbl;
+
+       nr_tbl = swioltb_nr_tbl();
+       if (nr_tbl)
+               xen_io_tlb_nslabs = nr_tbl;
+       else {
+               xen_io_tlb_nslabs = (64 * 1024 * 1024 >> IO_TLB_SHIFT);
+               xen_io_tlb_nslabs = ALIGN(xen_io_tlb_nslabs, IO_TLB_SEGSIZE);
+       }
 
        bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT;
 
diff --git a/drivers/xen/tmem.c b/drivers/xen/tmem.c
new file mode 100644 (file)
index 0000000..816a449
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Xen implementation for transcendent memory (tmem)
+ *
+ * Copyright (C) 2009-2010 Oracle Corp.  All rights reserved.
+ * Author: Dan Magenheimer
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/pagemap.h>
+#include <linux/cleancache.h>
+
+#include <xen/xen.h>
+#include <xen/interface/xen.h>
+#include <asm/xen/hypercall.h>
+#include <asm/xen/page.h>
+#include <asm/xen/hypervisor.h>
+
+#define TMEM_CONTROL               0
+#define TMEM_NEW_POOL              1
+#define TMEM_DESTROY_POOL          2
+#define TMEM_NEW_PAGE              3
+#define TMEM_PUT_PAGE              4
+#define TMEM_GET_PAGE              5
+#define TMEM_FLUSH_PAGE            6
+#define TMEM_FLUSH_OBJECT          7
+#define TMEM_READ                  8
+#define TMEM_WRITE                 9
+#define TMEM_XCHG                 10
+
+/* Bits for HYPERVISOR_tmem_op(TMEM_NEW_POOL) */
+#define TMEM_POOL_PERSIST          1
+#define TMEM_POOL_SHARED           2
+#define TMEM_POOL_PAGESIZE_SHIFT   4
+#define TMEM_VERSION_SHIFT        24
+
+
+struct tmem_pool_uuid {
+       u64 uuid_lo;
+       u64 uuid_hi;
+};
+
+struct tmem_oid {
+       u64 oid[3];
+};
+
+#define TMEM_POOL_PRIVATE_UUID { 0, 0 }
+
+/* flags for tmem_ops.new_pool */
+#define TMEM_POOL_PERSIST          1
+#define TMEM_POOL_SHARED           2
+
+/* xen tmem foundation ops/hypercalls */
+
+static inline int xen_tmem_op(u32 tmem_cmd, u32 tmem_pool, struct tmem_oid oid,
+       u32 index, unsigned long gmfn, u32 tmem_offset, u32 pfn_offset, u32 len)
+{
+       struct tmem_op op;
+       int rc = 0;
+
+       op.cmd = tmem_cmd;
+       op.pool_id = tmem_pool;
+       op.u.gen.oid[0] = oid.oid[0];
+       op.u.gen.oid[1] = oid.oid[1];
+       op.u.gen.oid[2] = oid.oid[2];
+       op.u.gen.index = index;
+       op.u.gen.tmem_offset = tmem_offset;
+       op.u.gen.pfn_offset = pfn_offset;
+       op.u.gen.len = len;
+       set_xen_guest_handle(op.u.gen.gmfn, (void *)gmfn);
+       rc = HYPERVISOR_tmem_op(&op);
+       return rc;
+}
+
+static int xen_tmem_new_pool(struct tmem_pool_uuid uuid,
+                               u32 flags, unsigned long pagesize)
+{
+       struct tmem_op op;
+       int rc = 0, pageshift;
+
+       for (pageshift = 0; pagesize != 1; pageshift++)
+               pagesize >>= 1;
+       flags |= (pageshift - 12) << TMEM_POOL_PAGESIZE_SHIFT;
+       flags |= TMEM_SPEC_VERSION << TMEM_VERSION_SHIFT;
+       op.cmd = TMEM_NEW_POOL;
+       op.u.new.uuid[0] = uuid.uuid_lo;
+       op.u.new.uuid[1] = uuid.uuid_hi;
+       op.u.new.flags = flags;
+       rc = HYPERVISOR_tmem_op(&op);
+       return rc;
+}
+
+/* xen generic tmem ops */
+
+static int xen_tmem_put_page(u32 pool_id, struct tmem_oid oid,
+                            u32 index, unsigned long pfn)
+{
+       unsigned long gmfn = xen_pv_domain() ? pfn_to_mfn(pfn) : pfn;
+
+       return xen_tmem_op(TMEM_PUT_PAGE, pool_id, oid, index,
+               gmfn, 0, 0, 0);
+}
+
+static int xen_tmem_get_page(u32 pool_id, struct tmem_oid oid,
+                            u32 index, unsigned long pfn)
+{
+       unsigned long gmfn = xen_pv_domain() ? pfn_to_mfn(pfn) : pfn;
+
+       return xen_tmem_op(TMEM_GET_PAGE, pool_id, oid, index,
+               gmfn, 0, 0, 0);
+}
+
+static int xen_tmem_flush_page(u32 pool_id, struct tmem_oid oid, u32 index)
+{
+       return xen_tmem_op(TMEM_FLUSH_PAGE, pool_id, oid, index,
+               0, 0, 0, 0);
+}
+
+static int xen_tmem_flush_object(u32 pool_id, struct tmem_oid oid)
+{
+       return xen_tmem_op(TMEM_FLUSH_OBJECT, pool_id, oid, 0, 0, 0, 0, 0);
+}
+
+static int xen_tmem_destroy_pool(u32 pool_id)
+{
+       struct tmem_oid oid = { { 0 } };
+
+       return xen_tmem_op(TMEM_DESTROY_POOL, pool_id, oid, 0, 0, 0, 0, 0);
+}
+
+int tmem_enabled;
+
+static int __init enable_tmem(char *s)
+{
+       tmem_enabled = 1;
+       return 1;
+}
+
+__setup("tmem", enable_tmem);
+
+/* cleancache ops */
+
+static void tmem_cleancache_put_page(int pool, struct cleancache_filekey key,
+                                    pgoff_t index, struct page *page)
+{
+       u32 ind = (u32) index;
+       struct tmem_oid oid = *(struct tmem_oid *)&key;
+       unsigned long pfn = page_to_pfn(page);
+
+       if (pool < 0)
+               return;
+       if (ind != index)
+               return;
+       mb(); /* ensure page is quiescent; tmem may address it with an alias */
+       (void)xen_tmem_put_page((u32)pool, oid, ind, pfn);
+}
+
+static int tmem_cleancache_get_page(int pool, struct cleancache_filekey key,
+                                   pgoff_t index, struct page *page)
+{
+       u32 ind = (u32) index;
+       struct tmem_oid oid = *(struct tmem_oid *)&key;
+       unsigned long pfn = page_to_pfn(page);
+       int ret;
+
+       /* translate return values to linux semantics */
+       if (pool < 0)
+               return -1;
+       if (ind != index)
+               return -1;
+       ret = xen_tmem_get_page((u32)pool, oid, ind, pfn);
+       if (ret == 1)
+               return 0;
+       else
+               return -1;
+}
+
+static void tmem_cleancache_flush_page(int pool, struct cleancache_filekey key,
+                                      pgoff_t index)
+{
+       u32 ind = (u32) index;
+       struct tmem_oid oid = *(struct tmem_oid *)&key;
+
+       if (pool < 0)
+               return;
+       if (ind != index)
+               return;
+       (void)xen_tmem_flush_page((u32)pool, oid, ind);
+}
+
+static void tmem_cleancache_flush_inode(int pool, struct cleancache_filekey key)
+{
+       struct tmem_oid oid = *(struct tmem_oid *)&key;
+
+       if (pool < 0)
+               return;
+       (void)xen_tmem_flush_object((u32)pool, oid);
+}
+
+static void tmem_cleancache_flush_fs(int pool)
+{
+       if (pool < 0)
+               return;
+       (void)xen_tmem_destroy_pool((u32)pool);
+}
+
+static int tmem_cleancache_init_fs(size_t pagesize)
+{
+       struct tmem_pool_uuid uuid_private = TMEM_POOL_PRIVATE_UUID;
+
+       return xen_tmem_new_pool(uuid_private, 0, pagesize);
+}
+
+static int tmem_cleancache_init_shared_fs(char *uuid, size_t pagesize)
+{
+       struct tmem_pool_uuid shared_uuid;
+
+       shared_uuid.uuid_lo = *(u64 *)uuid;
+       shared_uuid.uuid_hi = *(u64 *)(&uuid[8]);
+       return xen_tmem_new_pool(shared_uuid, TMEM_POOL_SHARED, pagesize);
+}
+
+static int use_cleancache = 1;
+
+static int __init no_cleancache(char *s)
+{
+       use_cleancache = 0;
+       return 1;
+}
+
+__setup("nocleancache", no_cleancache);
+
+static struct cleancache_ops tmem_cleancache_ops = {
+       .put_page = tmem_cleancache_put_page,
+       .get_page = tmem_cleancache_get_page,
+       .flush_page = tmem_cleancache_flush_page,
+       .flush_inode = tmem_cleancache_flush_inode,
+       .flush_fs = tmem_cleancache_flush_fs,
+       .init_shared_fs = tmem_cleancache_init_shared_fs,
+       .init_fs = tmem_cleancache_init_fs
+};
+
+static int __init xen_tmem_init(void)
+{
+       struct cleancache_ops old_ops;
+
+       if (!xen_domain())
+               return 0;
+#ifdef CONFIG_CLEANCACHE
+       BUG_ON(sizeof(struct cleancache_filekey) != sizeof(struct tmem_oid));
+       if (tmem_enabled && use_cleancache) {
+               char *s = "";
+               old_ops = cleancache_register_ops(&tmem_cleancache_ops);
+               if (old_ops.init_fs != NULL)
+                       s = " (WARNING: cleancache_ops overridden)";
+               printk(KERN_INFO "cleancache enabled, RAM provided by "
+                                "Xen Transcendent Memory%s\n", s);
+       }
+#endif
+       return 0;
+}
+
+module_init(xen_tmem_init)
index 814ac4e213a8a2c37873f99a68a7d639d575e6cf..0a93dc1cb4ac92868d1ecd6cbe8da687b23a4001 100644 (file)
@@ -1,6 +1,6 @@
 config 9P_FS
-       tristate "Plan 9 Resource Sharing Support (9P2000) (Experimental)"
-       depends on INET && NET_9P && EXPERIMENTAL
+       tristate "Plan 9 Resource Sharing Support (9P2000)"
+       depends on INET && NET_9P
        help
          If you say Y here, you will get experimental support for
          Plan 9 resource sharing via the 9P2000 protocol.
@@ -10,7 +10,6 @@ config 9P_FS
          If unsure, say N.
 
 if 9P_FS
-
 config 9P_FSCACHE
        bool "Enable 9P client caching support (EXPERIMENTAL)"
        depends on EXPERIMENTAL
index 82a7c38ddad0dec0c9ecded6fcc4d3eb93a50350..691c78f58bef23eaeac32489399479d981397aed 100644 (file)
@@ -259,7 +259,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
                if (IS_ERR(inode_fid)) {
                        err = PTR_ERR(inode_fid);
                        mutex_unlock(&v9inode->v_mutex);
-                       goto error;
+                       goto err_clunk_old_fid;
                }
                v9inode->writeback_fid = (void *) inode_fid;
        }
@@ -267,8 +267,8 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
        /* Since we are opening a file, assign the open fid to the file */
        filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
        if (IS_ERR(filp)) {
-               p9_client_clunk(ofid);
-               return PTR_ERR(filp);
+               err = PTR_ERR(filp);
+               goto err_clunk_old_fid;
        }
        filp->private_data = ofid;
 #ifdef CONFIG_9P_FSCACHE
@@ -278,10 +278,11 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
        return 0;
 
 error:
-       if (ofid)
-               p9_client_clunk(ofid);
        if (fid)
                p9_client_clunk(fid);
+err_clunk_old_fid:
+       if (ofid)
+               p9_client_clunk(ofid);
        return err;
 }
 
index f3aa9b08b228b7287886f418d2291962cf8eef2c..19891aab9c6ed7255388f175eabfcd7e4f5bb253 100644 (file)
@@ -47,7 +47,7 @@ config FS_POSIX_ACL
        def_bool n
 
 config EXPORTFS
-       bool
+       tristate
 
 config FILE_LOCKING
        bool "Enable POSIX file locking API" if EXPERT
@@ -124,6 +124,7 @@ config TMPFS
 config TMPFS_POSIX_ACL
        bool "Tmpfs POSIX Access Control Lists"
        depends on TMPFS
+       select TMPFS_XATTR
        select GENERIC_ACL
        help
          POSIX Access Control Lists (ACLs) support permissions for users and
@@ -134,6 +135,22 @@ config TMPFS_POSIX_ACL
 
          If you don't know what Access Control Lists are, say N.
 
+config TMPFS_XATTR
+       bool "Tmpfs extended attributes"
+       depends on TMPFS
+       default n
+       help
+         Extended attributes are name:value pairs associated with inodes by
+         the kernel or by users (see the attr(5) manual page, or visit
+         <http://acl.bestbits.at/> for details).
+
+         Currently this enables support for the trusted.* and
+         security.* namespaces.
+
+         You need this for POSIX ACL support on tmpfs.
+
+         If unsure, say N.
+
 config HUGETLBFS
        bool "HugeTLB file system support"
        depends on X86 || IA64 || SPARC64 || (S390 && 64BIT) || \
index 20c106f2492740f7de1615ee7712207b74a33828..1b0b19550015d2f19949b5b85d84556ecf7adb36 100644 (file)
@@ -584,11 +584,11 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
 
 success:
        d_add(dentry, inode);
-       _leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%llu }",
+       _leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%u }",
               fid.vnode,
               fid.unique,
               dentry->d_inode->i_ino,
-              (unsigned long long)dentry->d_inode->i_version);
+              dentry->d_inode->i_generation);
 
        return NULL;
 }
@@ -671,10 +671,10 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
                 * been deleted and replaced, and the original vnode ID has
                 * been reused */
                if (fid.unique != vnode->fid.unique) {
-                       _debug("%s: file deleted (uq %u -> %u I:%llu)",
+                       _debug("%s: file deleted (uq %u -> %u I:%u)",
                               dentry->d_name.name, fid.unique,
                               vnode->fid.unique,
-                              (unsigned long long)dentry->d_inode->i_version);
+                              dentry->d_inode->i_generation);
                        spin_lock(&vnode->lock);
                        set_bit(AFS_VNODE_DELETED, &vnode->flags);
                        spin_unlock(&vnode->lock);
index 4bd0218473a9bb407a9c86be49f0400461621f24..346e3289abd70549987ce9f490e1d8b210b66bd1 100644 (file)
@@ -89,7 +89,7 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
                        i_size_write(&vnode->vfs_inode, size);
                        vnode->vfs_inode.i_uid = status->owner;
                        vnode->vfs_inode.i_gid = status->group;
-                       vnode->vfs_inode.i_version = vnode->fid.unique;
+                       vnode->vfs_inode.i_generation = vnode->fid.unique;
                        vnode->vfs_inode.i_nlink = status->nlink;
 
                        mode = vnode->vfs_inode.i_mode;
@@ -102,6 +102,7 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
                vnode->vfs_inode.i_ctime.tv_sec = status->mtime_server;
                vnode->vfs_inode.i_mtime        = vnode->vfs_inode.i_ctime;
                vnode->vfs_inode.i_atime        = vnode->vfs_inode.i_ctime;
+               vnode->vfs_inode.i_version      = data_version;
        }
 
        expected_version = status->data_version;
index db66c5201474dc9b380ab21419fa61f7ff26fa78..0fdab6e03d8781d60ea7968c5c9886b555178dcd 100644 (file)
@@ -75,7 +75,8 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
        inode->i_ctime.tv_nsec  = 0;
        inode->i_atime          = inode->i_mtime = inode->i_ctime;
        inode->i_blocks         = 0;
-       inode->i_version        = vnode->fid.unique;
+       inode->i_generation     = vnode->fid.unique;
+       inode->i_version        = vnode->status.data_version;
        inode->i_mapping->a_ops = &afs_fs_aops;
 
        /* check to see whether a symbolic link is really a mountpoint */
@@ -100,7 +101,7 @@ static int afs_iget5_test(struct inode *inode, void *opaque)
        struct afs_iget_data *data = opaque;
 
        return inode->i_ino == data->fid.vnode &&
-               inode->i_version == data->fid.unique;
+               inode->i_generation == data->fid.unique;
 }
 
 /*
@@ -122,7 +123,7 @@ static int afs_iget5_set(struct inode *inode, void *opaque)
        struct afs_vnode *vnode = AFS_FS_I(inode);
 
        inode->i_ino = data->fid.vnode;
-       inode->i_version = data->fid.unique;
+       inode->i_generation = data->fid.unique;
        vnode->fid = data->fid;
        vnode->volume = data->volume;
 
@@ -380,8 +381,7 @@ int afs_getattr(struct vfsmount *mnt, struct dentry *dentry,
 
        inode = dentry->d_inode;
 
-       _enter("{ ino=%lu v=%llu }", inode->i_ino,
-               (unsigned long long)inode->i_version);
+       _enter("{ ino=%lu v=%u }", inode->i_ino, inode->i_generation);
 
        generic_fillattr(inode, stat);
        return 0;
index fb240e8766d63f7178374c40594881609201cae4..356dcf0929e8f0de36a166a2054e34c5ef3396c3 100644 (file)
@@ -31,8 +31,8 @@
 static void afs_i_init_once(void *foo);
 static struct dentry *afs_mount(struct file_system_type *fs_type,
                      int flags, const char *dev_name, void *data);
+static void afs_kill_super(struct super_block *sb);
 static struct inode *afs_alloc_inode(struct super_block *sb);
-static void afs_put_super(struct super_block *sb);
 static void afs_destroy_inode(struct inode *inode);
 static int afs_statfs(struct dentry *dentry, struct kstatfs *buf);
 
@@ -40,7 +40,7 @@ struct file_system_type afs_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "afs",
        .mount          = afs_mount,
-       .kill_sb        = kill_anon_super,
+       .kill_sb        = afs_kill_super,
        .fs_flags       = 0,
 };
 
@@ -50,7 +50,6 @@ static const struct super_operations afs_super_ops = {
        .drop_inode     = afs_drop_inode,
        .destroy_inode  = afs_destroy_inode,
        .evict_inode    = afs_evict_inode,
-       .put_super      = afs_put_super,
        .show_options   = generic_show_options,
 };
 
@@ -282,19 +281,25 @@ static int afs_parse_device_name(struct afs_mount_params *params,
  */
 static int afs_test_super(struct super_block *sb, void *data)
 {
-       struct afs_mount_params *params = data;
+       struct afs_super_info *as1 = data;
        struct afs_super_info *as = sb->s_fs_info;
 
-       return as->volume == params->volume;
+       return as->volume == as1->volume;
+}
+
+static int afs_set_super(struct super_block *sb, void *data)
+{
+       sb->s_fs_info = data;
+       return set_anon_super(sb, NULL);
 }
 
 /*
  * fill in the superblock
  */
-static int afs_fill_super(struct super_block *sb, void *data)
+static int afs_fill_super(struct super_block *sb,
+                         struct afs_mount_params *params)
 {
-       struct afs_mount_params *params = data;
-       struct afs_super_info *as = NULL;
+       struct afs_super_info *as = sb->s_fs_info;
        struct afs_fid fid;
        struct dentry *root = NULL;
        struct inode *inode = NULL;
@@ -302,23 +307,13 @@ static int afs_fill_super(struct super_block *sb, void *data)
 
        _enter("");
 
-       /* allocate a superblock info record */
-       as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL);
-       if (!as) {
-               _leave(" = -ENOMEM");
-               return -ENOMEM;
-       }
-
-       afs_get_volume(params->volume);
-       as->volume = params->volume;
-
        /* fill in the superblock */
        sb->s_blocksize         = PAGE_CACHE_SIZE;
        sb->s_blocksize_bits    = PAGE_CACHE_SHIFT;
        sb->s_magic             = AFS_FS_MAGIC;
        sb->s_op                = &afs_super_ops;
-       sb->s_fs_info           = as;
        sb->s_bdi               = &as->volume->bdi;
+       strlcpy(sb->s_id, as->volume->vlocation->vldb.name, sizeof(sb->s_id));
 
        /* allocate the root inode and dentry */
        fid.vid         = as->volume->vid;
@@ -326,7 +321,7 @@ static int afs_fill_super(struct super_block *sb, void *data)
        fid.unique      = 1;
        inode = afs_iget(sb, params->key, &fid, NULL, NULL);
        if (IS_ERR(inode))
-               goto error_inode;
+               return PTR_ERR(inode);
 
        if (params->autocell)
                set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags);
@@ -342,16 +337,8 @@ static int afs_fill_super(struct super_block *sb, void *data)
        _leave(" = 0");
        return 0;
 
-error_inode:
-       ret = PTR_ERR(inode);
-       inode = NULL;
 error:
        iput(inode);
-       afs_put_volume(as->volume);
-       kfree(as);
-
-       sb->s_fs_info = NULL;
-
        _leave(" = %d", ret);
        return ret;
 }
@@ -367,6 +354,7 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
        struct afs_volume *vol;
        struct key *key;
        char *new_opts = kstrdup(options, GFP_KERNEL);
+       struct afs_super_info *as;
        int ret;
 
        _enter(",,%s,%p", dev_name, options);
@@ -399,12 +387,22 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
                ret = PTR_ERR(vol);
                goto error;
        }
-       params.volume = vol;
+
+       /* allocate a superblock info record */
+       as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL);
+       if (!as) {
+               ret = -ENOMEM;
+               afs_put_volume(vol);
+               goto error;
+       }
+       as->volume = vol;
 
        /* allocate a deviceless superblock */
-       sb = sget(fs_type, afs_test_super, set_anon_super, &params);
+       sb = sget(fs_type, afs_test_super, afs_set_super, as);
        if (IS_ERR(sb)) {
                ret = PTR_ERR(sb);
+               afs_put_volume(vol);
+               kfree(as);
                goto error;
        }
 
@@ -422,16 +420,16 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
        } else {
                _debug("reuse");
                ASSERTCMP(sb->s_flags, &, MS_ACTIVE);
+               afs_put_volume(vol);
+               kfree(as);
        }
 
-       afs_put_volume(params.volume);
        afs_put_cell(params.cell);
        kfree(new_opts);
        _leave(" = 0 [%p]", sb);
        return dget(sb->s_root);
 
 error:
-       afs_put_volume(params.volume);
        afs_put_cell(params.cell);
        key_put(params.key);
        kfree(new_opts);
@@ -439,18 +437,12 @@ error:
        return ERR_PTR(ret);
 }
 
-/*
- * finish the unmounting process on the superblock
- */
-static void afs_put_super(struct super_block *sb)
+static void afs_kill_super(struct super_block *sb)
 {
        struct afs_super_info *as = sb->s_fs_info;
-
-       _enter("");
-
+       kill_anon_super(sb);
        afs_put_volume(as->volume);
-
-       _leave("");
+       kfree(as);
 }
 
 /*
index 789b3afb342328dcfe551d39227a81f09ffb3470..b806285ff85304bf71032c4b64cc3fb3cf49dda0 100644 (file)
@@ -84,23 +84,21 @@ void afs_put_writeback(struct afs_writeback *wb)
  * partly or wholly fill a page that's under preparation for writing
  */
 static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
-                        loff_t pos, unsigned len, struct page *page)
+                        loff_t pos, struct page *page)
 {
        loff_t i_size;
-       unsigned eof;
        int ret;
+       int len;
 
-       _enter(",,%llu,%u", (unsigned long long)pos, len);
-
-       ASSERTCMP(len, <=, PAGE_CACHE_SIZE);
+       _enter(",,%llu", (unsigned long long)pos);
 
        i_size = i_size_read(&vnode->vfs_inode);
-       if (pos + len > i_size)
-               eof = i_size;
+       if (pos + PAGE_CACHE_SIZE > i_size)
+               len = i_size - pos;
        else
-               eof = PAGE_CACHE_SIZE;
+               len = PAGE_CACHE_SIZE;
 
-       ret = afs_vnode_fetch_data(vnode, key, 0, eof, page);
+       ret = afs_vnode_fetch_data(vnode, key, pos, len, page);
        if (ret < 0) {
                if (ret == -ENOENT) {
                        _debug("got NOENT from server"
@@ -153,9 +151,8 @@ int afs_write_begin(struct file *file, struct address_space *mapping,
        *pagep = page;
        /* page won't leak in error case: it eventually gets cleaned off LRU */
 
-       if (!PageUptodate(page)) {
-               _debug("not up to date");
-               ret = afs_fill_page(vnode, key, pos, len, page);
+       if (!PageUptodate(page) && len != PAGE_CACHE_SIZE) {
+               ret = afs_fill_page(vnode, key, index << PAGE_CACHE_SHIFT, page);
                if (ret < 0) {
                        kfree(candidate);
                        _leave(" = %d [prep]", ret);
index 91dbe2a107f2adef13f1141ad57794240a704334..caf2aa521e2b4101e29e288ed1ed4b5fb895f226 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -175,6 +175,13 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
                        return -EPERM;
        }
 
+       if ((ia_valid & ATTR_MODE)) {
+               mode_t amode = attr->ia_mode;
+               /* Flag setting protected by i_mutex */
+               if (is_sxid(amode))
+                       inode->i_flags &= ~S_NOSEC;
+       }
+
        now = current_fs_time(inode->i_sb);
 
        attr->ia_ctime = now;
index 9ad2369d9e35e0651885a78dc3648ef9dbe8c412..bfcb18feb1df32b91a9db144f3f74f5873c85866 100644 (file)
@@ -231,9 +231,6 @@ static int bad_inode_readlink(struct dentry *dentry, char __user *buffer,
 
 static int bad_inode_permission(struct inode *inode, int mask, unsigned int flags)
 {
-       if (flags & IPERM_FLAG_RCU)
-               return -ECHILD;
-
        return -EIO;
 }
 
index 397d3057d336a201b744a6ceadec16eaed651c0e..1bffbe0ed7787d96bd8b36cc25d2bd74a1c3572f 100644 (file)
@@ -820,6 +820,8 @@ static int load_flat_shared_library(int id, struct lib_info *libs)
        int res;
        char buf[16];
 
+       memset(&bprm, 0, sizeof(bprm));
+
        /* Create the file name */
        sprintf(buf, "/lib/lib%d.so", id);
 
@@ -835,6 +837,12 @@ static int load_flat_shared_library(int id, struct lib_info *libs)
        if (!bprm.cred)
                goto out;
 
+       /* We don't really care about recalculating credentials at this point
+        * as we're past the point of no return and are dealing with shared
+        * libraries.
+        */
+       bprm.cred_prepared = 1;
+
        res = prepare_binprm(&bprm);
 
        if (!IS_ERR_VALUE(res))
index 840a0d755248048cad3d65c47eed7ea91b514c45..9bfade8a609bfa33c9f78b9f2faa9d01dfea9176 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -638,10 +638,11 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
  *     @offset: vec entry offset
  *
  *     Attempt to add a page to the bio_vec maplist. This can fail for a
- *     number of reasons, such as the bio being full or target block
- *     device limitations. The target block device must allow bio's
- *      smaller than PAGE_SIZE, so it is always possible to add a single
- *      page to an empty bio. This should only be used by REQ_PC bios.
+ *     number of reasons, such as the bio being full or target block device
+ *     limitations. The target block device must allow bio's up to PAGE_SIZE,
+ *     so it is always possible to add a single page to an empty bio.
+ *
+ *     This should only be used by REQ_PC bios.
  */
 int bio_add_pc_page(struct request_queue *q, struct bio *bio, struct page *page,
                    unsigned int len, unsigned int offset)
@@ -659,10 +660,9 @@ EXPORT_SYMBOL(bio_add_pc_page);
  *     @offset: vec entry offset
  *
  *     Attempt to add a page to the bio_vec maplist. This can fail for a
- *     number of reasons, such as the bio being full or target block
- *     device limitations. The target block device must allow bio's
- *      smaller than PAGE_SIZE, so it is always possible to add a single
- *      page to an empty bio.
+ *     number of reasons, such as the bio being full or target block device
+ *     limitations. The target block device must allow bio's up to PAGE_SIZE,
+ *     so it is always possible to add a single page to an empty bio.
  */
 int bio_add_page(struct bio *bio, struct page *page, unsigned int len,
                 unsigned int offset)
index bf9c7a72037179c7ad524c439f1735a98ef5fda3..610e8e0b04b88946721eb58b78791bab0e72440b 100644 (file)
@@ -762,7 +762,19 @@ static struct block_device *bd_start_claiming(struct block_device *bdev,
        if (!disk)
                return ERR_PTR(-ENXIO);
 
-       whole = bdget_disk(disk, 0);
+       /*
+        * Normally, @bdev should equal what's returned from bdget_disk()
+        * if partno is 0; however, some drivers (floppy) use multiple
+        * bdev's for the same physical device and @bdev may be one of the
+        * aliases.  Keep @bdev if partno is 0.  This means claimer
+        * tracking is broken for those devices but it has always been that
+        * way.
+        */
+       if (partno)
+               whole = bdget_disk(disk, 0);
+       else
+               whole = bdgrab(bdev);
+
        module_put(disk->fops->owner);
        put_disk(disk);
        if (!whole)
@@ -1238,6 +1250,8 @@ int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder)
        res = __blkdev_get(bdev, mode, 0);
 
        if (whole) {
+               struct gendisk *disk = whole->bd_disk;
+
                /* finish claiming */
                mutex_lock(&bdev->bd_mutex);
                spin_lock(&bdev_lock);
@@ -1264,15 +1278,16 @@ int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder)
                spin_unlock(&bdev_lock);
 
                /*
-                * Block event polling for write claims.  Any write
-                * holder makes the write_holder state stick until all
-                * are released.  This is good enough and tracking
-                * individual writeable reference is too fragile given
-                * the way @mode is used in blkdev_get/put().
+                * Block event polling for write claims if requested.  Any
+                * write holder makes the write_holder state stick until
+                * all are released.  This is good enough and tracking
+                * individual writeable reference is too fragile given the
+                * way @mode is used in blkdev_get/put().
                 */
-               if (!res && (mode & FMODE_WRITE) && !bdev->bd_write_holder) {
+               if (!res && (mode & FMODE_WRITE) && !bdev->bd_write_holder &&
+                   (disk->flags & GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE)) {
                        bdev->bd_write_holder = true;
-                       disk_block_events(bdev->bd_disk);
+                       disk_block_events(disk);
                }
 
                mutex_unlock(&bdev->bd_mutex);
index 31610ea73aec2bff3410ec7c65b3b52e2c7a14ba..9b72dcf1cd258bd2e7733079b399ddd6413e2826 100644 (file)
@@ -7,4 +7,4 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
           extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
           extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
           export.o tree-log.o acl.o free-space-cache.o zlib.o lzo.o \
-          compression.o delayed-ref.o relocation.o
+          compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o
index 44ea5b92e1ba891181235a24ba53785ff7acbfa0..f66fc99597331383890ac4847329faf6a494ddb0 100644 (file)
@@ -288,7 +288,7 @@ int btrfs_acl_chmod(struct inode *inode)
                return 0;
 
        acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS);
-       if (IS_ERR(acl) || !acl)
+       if (IS_ERR_OR_NULL(acl))
                return PTR_ERR(acl);
 
        clone = posix_acl_clone(acl, GFP_KERNEL);
index 57c3bb2884ceabd2ea4be939557a6c273c9e8626..52d7eca8c7bfe9d599e60cd0918b36c7f5fefe42 100644 (file)
@@ -22,6 +22,7 @@
 #include "extent_map.h"
 #include "extent_io.h"
 #include "ordered-data.h"
+#include "delayed-inode.h"
 
 /* in memory btrfs inode */
 struct btrfs_inode {
@@ -120,9 +121,6 @@ struct btrfs_inode {
         */
        u64 index_cnt;
 
-       /* the start of block group preferred for allocations. */
-       u64 block_group;
-
        /* the fsync log has some corner cases that mean we have to check
         * directories to see if any unlinks have been done before
         * the directory was logged.  See tree-log.c for all the
@@ -152,20 +150,34 @@ struct btrfs_inode {
        unsigned ordered_data_close:1;
        unsigned orphan_meta_reserved:1;
        unsigned dummy_inode:1;
+       unsigned in_defrag:1;
 
        /*
         * always compress this one file
         */
        unsigned force_compress:4;
 
+       struct btrfs_delayed_node *delayed_node;
+
        struct inode vfs_inode;
 };
 
+extern unsigned char btrfs_filetype_table[];
+
 static inline struct btrfs_inode *BTRFS_I(struct inode *inode)
 {
        return container_of(inode, struct btrfs_inode, vfs_inode);
 }
 
+static inline u64 btrfs_ino(struct inode *inode)
+{
+       u64 ino = BTRFS_I(inode)->location.objectid;
+
+       if (ino <= BTRFS_FIRST_FREE_OBJECTID)
+               ino = inode->i_ino;
+       return ino;
+}
+
 static inline void btrfs_i_size_write(struct inode *inode, u64 size)
 {
        i_size_write(inode, size);
index 41d1d7c70e29d2aed3a347e5b9d74d2a810d7b46..bfe42b03eaf9b3cc0bdf14b3975300e9a30b8584 100644 (file)
@@ -125,9 +125,10 @@ static int check_compressed_csum(struct inode *inode,
                kunmap_atomic(kaddr, KM_USER0);
 
                if (csum != *cb_sum) {
-                       printk(KERN_INFO "btrfs csum failed ino %lu "
+                       printk(KERN_INFO "btrfs csum failed ino %llu "
                               "extent %llu csum %u "
-                              "wanted %u mirror %d\n", inode->i_ino,
+                              "wanted %u mirror %d\n",
+                              (unsigned long long)btrfs_ino(inode),
                               (unsigned long long)disk_start,
                               csum, *cb_sum, cb->mirror_num);
                        ret = -EIO;
@@ -332,7 +333,7 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
        struct compressed_bio *cb;
        unsigned long bytes_left;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
-       int page_index = 0;
+       int pg_index = 0;
        struct page *page;
        u64 first_byte = disk_start;
        struct block_device *bdev;
@@ -366,8 +367,8 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
 
        /* create and submit bios for the compressed pages */
        bytes_left = compressed_len;
-       for (page_index = 0; page_index < cb->nr_pages; page_index++) {
-               page = compressed_pages[page_index];
+       for (pg_index = 0; pg_index < cb->nr_pages; pg_index++) {
+               page = compressed_pages[pg_index];
                page->mapping = inode->i_mapping;
                if (bio->bi_size)
                        ret = io_tree->ops->merge_bio_hook(page, 0,
@@ -432,7 +433,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
                                     struct compressed_bio *cb)
 {
        unsigned long end_index;
-       unsigned long page_index;
+       unsigned long pg_index;
        u64 last_offset;
        u64 isize = i_size_read(inode);
        int ret;
@@ -456,13 +457,13 @@ static noinline int add_ra_bio_pages(struct inode *inode,
        end_index = (i_size_read(inode) - 1) >> PAGE_CACHE_SHIFT;
 
        while (last_offset < compressed_end) {
-               page_index = last_offset >> PAGE_CACHE_SHIFT;
+               pg_index = last_offset >> PAGE_CACHE_SHIFT;
 
-               if (page_index > end_index)
+               if (pg_index > end_index)
                        break;
 
                rcu_read_lock();
-               page = radix_tree_lookup(&mapping->page_tree, page_index);
+               page = radix_tree_lookup(&mapping->page_tree, pg_index);
                rcu_read_unlock();
                if (page) {
                        misses++;
@@ -476,7 +477,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
                if (!page)
                        break;
 
-               if (add_to_page_cache_lru(page, mapping, page_index,
+               if (add_to_page_cache_lru(page, mapping, pg_index,
                                                                GFP_NOFS)) {
                        page_cache_release(page);
                        goto next;
@@ -560,7 +561,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        unsigned long uncompressed_len = bio->bi_vcnt * PAGE_CACHE_SIZE;
        unsigned long compressed_len;
        unsigned long nr_pages;
-       unsigned long page_index;
+       unsigned long pg_index;
        struct page *page;
        struct block_device *bdev;
        struct bio *comp_bio;
@@ -613,10 +614,10 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
 
        bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
 
-       for (page_index = 0; page_index < nr_pages; page_index++) {
-               cb->compressed_pages[page_index] = alloc_page(GFP_NOFS |
+       for (pg_index = 0; pg_index < nr_pages; pg_index++) {
+               cb->compressed_pages[pg_index] = alloc_page(GFP_NOFS |
                                                              __GFP_HIGHMEM);
-               if (!cb->compressed_pages[page_index])
+               if (!cb->compressed_pages[pg_index])
                        goto fail2;
        }
        cb->nr_pages = nr_pages;
@@ -634,8 +635,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        comp_bio->bi_end_io = end_compressed_bio_read;
        atomic_inc(&cb->pending_bios);
 
-       for (page_index = 0; page_index < nr_pages; page_index++) {
-               page = cb->compressed_pages[page_index];
+       for (pg_index = 0; pg_index < nr_pages; pg_index++) {
+               page = cb->compressed_pages[pg_index];
                page->mapping = inode->i_mapping;
                page->index = em_start >> PAGE_CACHE_SHIFT;
 
@@ -702,8 +703,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        return 0;
 
 fail2:
-       for (page_index = 0; page_index < nr_pages; page_index++)
-               free_page((unsigned long)cb->compressed_pages[page_index]);
+       for (pg_index = 0; pg_index < nr_pages; pg_index++)
+               free_page((unsigned long)cb->compressed_pages[pg_index]);
 
        kfree(cb->compressed_pages);
 fail1:
@@ -945,7 +946,7 @@ void btrfs_exit_compress(void)
 int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
                              unsigned long total_out, u64 disk_start,
                              struct bio_vec *bvec, int vcnt,
-                             unsigned long *page_index,
+                             unsigned long *pg_index,
                              unsigned long *pg_offset)
 {
        unsigned long buf_offset;
@@ -954,7 +955,7 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
        unsigned long working_bytes = total_out - buf_start;
        unsigned long bytes;
        char *kaddr;
-       struct page *page_out = bvec[*page_index].bv_page;
+       struct page *page_out = bvec[*pg_index].bv_page;
 
        /*
         * start byte is the first byte of the page we're currently
@@ -995,11 +996,11 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
 
                /* check if we need to pick another page */
                if (*pg_offset == PAGE_CACHE_SIZE) {
-                       (*page_index)++;
-                       if (*page_index >= vcnt)
+                       (*pg_index)++;
+                       if (*pg_index >= vcnt)
                                return 0;
 
-                       page_out = bvec[*page_index].bv_page;
+                       page_out = bvec[*pg_index].bv_page;
                        *pg_offset = 0;
                        start_byte = page_offset(page_out) - disk_start;
 
index 51000174b9d7ba687f3fda58ab44e6479be24e82..a12059f4f0fd3c70fd6302abe4ab3e83fa5797fb 100644 (file)
@@ -37,7 +37,7 @@ int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page,
 int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
                              unsigned long total_out, u64 disk_start,
                              struct bio_vec *bvec, int vcnt,
-                             unsigned long *page_index,
+                             unsigned long *pg_index,
                              unsigned long *pg_offset);
 
 int btrfs_submit_compressed_write(struct inode *inode, u64 start,
index 84d7ca1fe0bac42a58c9115f2dccaa68efb6b3b6..2e667868e0d2b8b75649572d10602ac56679a0d0 100644 (file)
@@ -38,18 +38,11 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
                              struct extent_buffer *src_buf);
 static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                   struct btrfs_path *path, int level, int slot);
-static int setup_items_for_insert(struct btrfs_trans_handle *trans,
-                       struct btrfs_root *root, struct btrfs_path *path,
-                       struct btrfs_key *cpu_key, u32 *data_size,
-                       u32 total_data, u32 total_size, int nr);
-
 
 struct btrfs_path *btrfs_alloc_path(void)
 {
        struct btrfs_path *path;
        path = kmem_cache_zalloc(btrfs_path_cachep, GFP_NOFS);
-       if (path)
-               path->reada = 1;
        return path;
 }
 
@@ -107,7 +100,7 @@ void btrfs_free_path(struct btrfs_path *p)
 {
        if (!p)
                return;
-       btrfs_release_path(NULL, p);
+       btrfs_release_path(p);
        kmem_cache_free(btrfs_path_cachep, p);
 }
 
@@ -117,7 +110,7 @@ void btrfs_free_path(struct btrfs_path *p)
  *
  * It is safe to call this on paths that no locks or extent buffers held.
  */
-noinline void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p)
+noinline void btrfs_release_path(struct btrfs_path *p)
 {
        int i;
 
@@ -1229,11 +1222,13 @@ static void reada_for_search(struct btrfs_root *root,
        u64 search;
        u64 target;
        u64 nread = 0;
+       u64 gen;
        int direction = path->reada;
        struct extent_buffer *eb;
        u32 nr;
        u32 blocksize;
        u32 nscan = 0;
+       bool map = true;
 
        if (level != 1)
                return;
@@ -1255,7 +1250,19 @@ static void reada_for_search(struct btrfs_root *root,
 
        nritems = btrfs_header_nritems(node);
        nr = slot;
+       if (node->map_token || path->skip_locking)
+               map = false;
+
        while (1) {
+               if (map && !node->map_token) {
+                       unsigned long offset = btrfs_node_key_ptr_offset(nr);
+                       map_private_extent_buffer(node, offset,
+                                                 sizeof(struct btrfs_key_ptr),
+                                                 &node->map_token,
+                                                 &node->kaddr,
+                                                 &node->map_start,
+                                                 &node->map_len, KM_USER1);
+               }
                if (direction < 0) {
                        if (nr == 0)
                                break;
@@ -1273,14 +1280,23 @@ static void reada_for_search(struct btrfs_root *root,
                search = btrfs_node_blockptr(node, nr);
                if ((search <= target && target - search <= 65536) ||
                    (search > target && search - target <= 65536)) {
-                       readahead_tree_block(root, search, blocksize,
-                                    btrfs_node_ptr_generation(node, nr));
+                       gen = btrfs_node_ptr_generation(node, nr);
+                       if (map && node->map_token) {
+                               unmap_extent_buffer(node, node->map_token,
+                                                   KM_USER1);
+                               node->map_token = NULL;
+                       }
+                       readahead_tree_block(root, search, blocksize, gen);
                        nread += blocksize;
                }
                nscan++;
                if ((nread > 65536 || nscan > 32))
                        break;
        }
+       if (map && node->map_token) {
+               unmap_extent_buffer(node, node->map_token, KM_USER1);
+               node->map_token = NULL;
+       }
 }
 
 /*
@@ -1328,7 +1344,7 @@ static noinline int reada_for_balance(struct btrfs_root *root,
                ret = -EAGAIN;
 
                /* release the whole path */
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
 
                /* read the blocks */
                if (block1)
@@ -1475,7 +1491,7 @@ read_block_for_search(struct btrfs_trans_handle *trans,
                                return 0;
                        }
                        free_extent_buffer(tmp);
-                       btrfs_release_path(NULL, p);
+                       btrfs_release_path(p);
                        return -EIO;
                }
        }
@@ -1494,7 +1510,7 @@ read_block_for_search(struct btrfs_trans_handle *trans,
        if (p->reada)
                reada_for_search(root, p, level, slot, key->objectid);
 
-       btrfs_release_path(NULL, p);
+       btrfs_release_path(p);
 
        ret = -EAGAIN;
        tmp = read_tree_block(root, blocknr, blocksize, 0);
@@ -1563,7 +1579,7 @@ setup_nodes_for_search(struct btrfs_trans_handle *trans,
                }
                b = p->nodes[level];
                if (!b) {
-                       btrfs_release_path(NULL, p);
+                       btrfs_release_path(p);
                        goto again;
                }
                BUG_ON(btrfs_header_nritems(b) == 1);
@@ -1653,9 +1669,6 @@ again:
                }
 cow_done:
                BUG_ON(!cow && ins_len);
-               if (level != btrfs_header_level(b))
-                       WARN_ON(1);
-               level = btrfs_header_level(b);
 
                p->nodes[level] = b;
                if (!p->skip_locking)
@@ -1753,7 +1766,7 @@ done:
        if (!p->leave_spinning)
                btrfs_set_path_blocking(p);
        if (ret < 0)
-               btrfs_release_path(root, p);
+               btrfs_release_path(p);
        return ret;
 }
 
@@ -3026,7 +3039,7 @@ static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans,
                                    struct btrfs_file_extent_item);
                extent_len = btrfs_file_extent_num_bytes(leaf, fi);
        }
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        path->keep_locks = 1;
        path->search_for_split = 1;
@@ -3216,7 +3229,6 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans,
                        struct btrfs_path *path,
                        u32 new_size, int from_end)
 {
-       int ret = 0;
        int slot;
        struct extent_buffer *leaf;
        struct btrfs_item *item;
@@ -3314,12 +3326,11 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans,
        btrfs_set_item_size(leaf, item, new_size);
        btrfs_mark_buffer_dirty(leaf);
 
-       ret = 0;
        if (btrfs_leaf_free_space(root, leaf) < 0) {
                btrfs_print_leaf(root, leaf);
                BUG();
        }
-       return ret;
+       return 0;
 }
 
 /*
@@ -3329,7 +3340,6 @@ int btrfs_extend_item(struct btrfs_trans_handle *trans,
                      struct btrfs_root *root, struct btrfs_path *path,
                      u32 data_size)
 {
-       int ret = 0;
        int slot;
        struct extent_buffer *leaf;
        struct btrfs_item *item;
@@ -3394,12 +3404,11 @@ int btrfs_extend_item(struct btrfs_trans_handle *trans,
        btrfs_set_item_size(leaf, item, old_size + data_size);
        btrfs_mark_buffer_dirty(leaf);
 
-       ret = 0;
        if (btrfs_leaf_free_space(root, leaf) < 0) {
                btrfs_print_leaf(root, leaf);
                BUG();
        }
-       return ret;
+       return 0;
 }
 
 /*
@@ -3559,11 +3568,10 @@ out:
  * to save stack depth by doing the bulk of the work in a function
  * that doesn't call btrfs_search_slot
  */
-static noinline_for_stack int
-setup_items_for_insert(struct btrfs_trans_handle *trans,
-                     struct btrfs_root *root, struct btrfs_path *path,
-                     struct btrfs_key *cpu_key, u32 *data_size,
-                     u32 total_data, u32 total_size, int nr)
+int setup_items_for_insert(struct btrfs_trans_handle *trans,
+                          struct btrfs_root *root, struct btrfs_path *path,
+                          struct btrfs_key *cpu_key, u32 *data_size,
+                          u32 total_data, u32 total_size, int nr)
 {
        struct btrfs_item *item;
        int i;
@@ -3647,7 +3655,6 @@ setup_items_for_insert(struct btrfs_trans_handle *trans,
 
        ret = 0;
        if (slot == 0) {
-               struct btrfs_disk_key disk_key;
                btrfs_cpu_key_to_disk(&disk_key, cpu_key);
                ret = fixup_low_keys(trans, root, path, &disk_key, 1);
        }
@@ -3949,7 +3956,7 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
        else
                return 1;
 
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
        if (ret < 0)
                return ret;
@@ -4073,7 +4080,7 @@ find_next_key:
                        sret = btrfs_find_next_key(root, path, min_key, level,
                                                  cache_only, min_trans);
                        if (sret == 0) {
-                               btrfs_release_path(root, path);
+                               btrfs_release_path(path);
                                goto again;
                        } else {
                                goto out;
@@ -4152,7 +4159,7 @@ next:
                                btrfs_node_key_to_cpu(c, &cur_key, slot);
 
                        orig_lowest = path->lowest_level;
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        path->lowest_level = level;
                        ret = btrfs_search_slot(NULL, root, &cur_key, path,
                                                0, 0);
@@ -4229,7 +4236,7 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
 again:
        level = 1;
        next = NULL;
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        path->keep_locks = 1;
 
@@ -4285,7 +4292,7 @@ again:
                        goto again;
 
                if (ret < 0) {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        goto done;
                }
 
@@ -4324,7 +4331,7 @@ again:
                        goto again;
 
                if (ret < 0) {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        goto done;
                }
 
index 8f4b81de3ae2a0ffb21b57080de5649d9a3785ff..f30ac05dbda7d1a60048aee7422026754b49b885 100644 (file)
 #ifndef __BTRFS_CTREE__
 #define __BTRFS_CTREE__
 
-#include <linux/version.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
 #include <linux/fs.h>
+#include <linux/rwsem.h>
 #include <linux/completion.h>
 #include <linux/backing-dev.h>
 #include <linux/wait.h>
@@ -33,6 +33,7 @@
 #include "extent_io.h"
 #include "extent_map.h"
 #include "async-thread.h"
+#include "ioctl.h"
 
 struct btrfs_trans_handle;
 struct btrfs_transaction;
@@ -105,6 +106,12 @@ struct btrfs_ordered_sum;
 /* For storing free space cache */
 #define BTRFS_FREE_SPACE_OBJECTID -11ULL
 
+/*
+ * The inode number assigned to the special inode for sotring
+ * free ino cache
+ */
+#define BTRFS_FREE_INO_OBJECTID -12ULL
+
 /* dummy objectid represents multiple objectids */
 #define BTRFS_MULTIPLE_OBJECTIDS -255ULL
 
@@ -187,7 +194,6 @@ struct btrfs_mapping_tree {
        struct extent_map_tree map_tree;
 };
 
-#define BTRFS_UUID_SIZE 16
 struct btrfs_dev_item {
        /* the internal btrfs device id */
        __le64 devid;
@@ -294,7 +300,6 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes)
                sizeof(struct btrfs_stripe) * (num_stripes - 1);
 }
 
-#define BTRFS_FSID_SIZE 16
 #define BTRFS_HEADER_FLAG_WRITTEN      (1ULL << 0)
 #define BTRFS_HEADER_FLAG_RELOC                (1ULL << 1)
 
@@ -510,6 +515,12 @@ struct btrfs_extent_item_v0 {
 /* use full backrefs for extent pointers in the block */
 #define BTRFS_BLOCK_FLAG_FULL_BACKREF  (1ULL << 8)
 
+/*
+ * this flag is only used internally by scrub and may be changed at any time
+ * it is only declared here to avoid collisions
+ */
+#define BTRFS_EXTENT_FLAG_SUPER                (1ULL << 48)
+
 struct btrfs_tree_block_info {
        struct btrfs_disk_key key;
        u8 level;
@@ -740,12 +751,12 @@ struct btrfs_space_info {
         */
        unsigned long reservation_progress;
 
-       int full:1;             /* indicates that we cannot allocate any more
+       unsigned int full:1;    /* indicates that we cannot allocate any more
                                   chunks for this space */
-       int chunk_alloc:1;      /* set if we are allocating a chunk */
+       unsigned int chunk_alloc:1;     /* set if we are allocating a chunk */
 
-       int force_alloc;        /* set if we need to force a chunk alloc for
-                                  this space */
+       unsigned int force_alloc;       /* set if we need to force a chunk
+                                          alloc for this space */
 
        struct list_head list;
 
@@ -830,9 +841,6 @@ struct btrfs_block_group_cache {
        u64 bytes_super;
        u64 flags;
        u64 sectorsize;
-       int extents_thresh;
-       int free_extents;
-       int total_bitmaps;
        unsigned int ro:1;
        unsigned int dirty:1;
        unsigned int iref:1;
@@ -847,9 +855,7 @@ struct btrfs_block_group_cache {
        struct btrfs_space_info *space_info;
 
        /* free space cache stuff */
-       spinlock_t tree_lock;
-       struct rb_root free_space_offset;
-       u64 free_space;
+       struct btrfs_free_space_ctl *free_space_ctl;
 
        /* block group cache stuff */
        struct rb_node cache_node;
@@ -869,6 +875,7 @@ struct btrfs_block_group_cache {
 struct reloc_control;
 struct btrfs_device;
 struct btrfs_fs_devices;
+struct btrfs_delayed_root;
 struct btrfs_fs_info {
        u8 fsid[BTRFS_FSID_SIZE];
        u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
@@ -895,7 +902,10 @@ struct btrfs_fs_info {
        /* logical->physical extent mapping */
        struct btrfs_mapping_tree mapping_tree;
 
-       /* block reservation for extent, checksum and root tree */
+       /*
+        * block reservation for extent, checksum, root tree and
+        * delayed dir index item
+        */
        struct btrfs_block_rsv global_block_rsv;
        /* block reservation for delay allocation */
        struct btrfs_block_rsv delalloc_block_rsv;
@@ -919,7 +929,6 @@ struct btrfs_fs_info {
         * is required instead of the faster short fsync log commits
         */
        u64 last_trans_log_full_commit;
-       u64 open_ioctl_trans;
        unsigned long mount_opt:20;
        unsigned long compress_type:4;
        u64 max_inline;
@@ -936,7 +945,6 @@ struct btrfs_fs_info {
        struct super_block *sb;
        struct inode *btree_inode;
        struct backing_dev_info bdi;
-       struct mutex trans_mutex;
        struct mutex tree_log_mutex;
        struct mutex transaction_kthread_mutex;
        struct mutex cleaner_mutex;
@@ -957,6 +965,13 @@ struct btrfs_fs_info {
        struct rw_semaphore subvol_sem;
        struct srcu_struct subvol_srcu;
 
+       spinlock_t trans_lock;
+       /*
+        * the reloc mutex goes with the trans lock, it is taken
+        * during commit to protect us from the relocation code
+        */
+       struct mutex reloc_mutex;
+
        struct list_head trans_list;
        struct list_head hashers;
        struct list_head dead_roots;
@@ -969,6 +984,7 @@ struct btrfs_fs_info {
        atomic_t async_submit_draining;
        atomic_t nr_async_bios;
        atomic_t async_delalloc_pages;
+       atomic_t open_ioctl_trans;
 
        /*
         * this is used by the balancing code to wait for all the pending
@@ -1022,6 +1038,7 @@ struct btrfs_fs_info {
         * for the sys_munmap function call path
         */
        struct btrfs_workers fixup_workers;
+       struct btrfs_workers delayed_workers;
        struct task_struct *transaction_kthread;
        struct task_struct *cleaner_kthread;
        int thread_pool_size;
@@ -1032,6 +1049,7 @@ struct btrfs_fs_info {
        int closing;
        int log_root_recovering;
        int enospc_unlink;
+       int trans_no_join;
 
        u64 total_pinned;
 
@@ -1053,7 +1071,6 @@ struct btrfs_fs_info {
        struct reloc_control *reloc_ctl;
 
        spinlock_t delalloc_lock;
-       spinlock_t new_trans_lock;
        u64 delalloc_bytes;
 
        /* data_alloc_cluster is only used in ssd mode */
@@ -1062,6 +1079,11 @@ struct btrfs_fs_info {
        /* all metadata allocations go through this cluster */
        struct btrfs_free_cluster meta_alloc_cluster;
 
+       /* auto defrag inodes go here */
+       spinlock_t defrag_inodes_lock;
+       struct rb_root defrag_inodes;
+       atomic_t defrag_running;
+
        spinlock_t ref_cache_lock;
        u64 total_ref_cache_size;
 
@@ -1077,8 +1099,21 @@ struct btrfs_fs_info {
 
        void *bdev_holder;
 
+       /* private scrub information */
+       struct mutex scrub_lock;
+       atomic_t scrubs_running;
+       atomic_t scrub_pause_req;
+       atomic_t scrubs_paused;
+       atomic_t scrub_cancel_req;
+       wait_queue_head_t scrub_pause_wait;
+       struct rw_semaphore scrub_super_lock;
+       int scrub_workers_refcnt;
+       struct btrfs_workers scrub_workers;
+
        /* filesystem state */
        u64 fs_state;
+
+       struct btrfs_delayed_root *delayed_root;
 };
 
 /*
@@ -1088,9 +1123,6 @@ struct btrfs_fs_info {
 struct btrfs_root {
        struct extent_buffer *node;
 
-       /* the node lock is held while changing the node pointer */
-       spinlock_t node_lock;
-
        struct extent_buffer *commit_root;
        struct btrfs_root *log_root;
        struct btrfs_root *reloc_root;
@@ -1107,6 +1139,16 @@ struct btrfs_root {
        spinlock_t accounting_lock;
        struct btrfs_block_rsv *block_rsv;
 
+       /* free ino cache stuff */
+       struct mutex fs_commit_mutex;
+       struct btrfs_free_space_ctl *free_ino_ctl;
+       enum btrfs_caching_type cached;
+       spinlock_t cache_lock;
+       wait_queue_head_t cache_wait;
+       struct btrfs_free_space_ctl *free_ino_pinned;
+       u64 cache_progress;
+       struct inode *cache_inode;
+
        struct mutex log_mutex;
        wait_queue_head_t log_writer_wait;
        wait_queue_head_t log_commit_wait[2];
@@ -1135,6 +1177,14 @@ struct btrfs_root {
        u32 type;
 
        u64 highest_objectid;
+
+       /* btrfs_record_root_in_trans is a multi-step process,
+        * and it can race with the balancing code.   But the
+        * race is very small, and only the first time the root
+        * is added to each transaction.  So in_trans_setup
+        * is used to tell us when more checks are required
+        */
+       unsigned long in_trans_setup;
        int ref_cows;
        int track_dirty;
        int in_radix;
@@ -1144,7 +1194,6 @@ struct btrfs_root {
        struct btrfs_key defrag_max;
        int defrag_running;
        char *name;
-       int in_sysfs;
 
        /* the dirty list is only used by non-reference counted roots */
        struct list_head dirty_list;
@@ -1161,6 +1210,11 @@ struct btrfs_root {
        /* red-black tree that keeps track of in-memory inodes */
        struct rb_root inode_tree;
 
+       /*
+        * radix tree that keeps track of delayed nodes of every inode,
+        * protected by inode_lock
+        */
+       struct radix_tree_root delayed_nodes_tree;
        /*
         * right now this just gets used so that a root has its own devid
         * for stat.  It may be used for more later
@@ -1168,6 +1222,38 @@ struct btrfs_root {
        struct super_block anon_super;
 };
 
+struct btrfs_ioctl_defrag_range_args {
+       /* start of the defrag operation */
+       __u64 start;
+
+       /* number of bytes to defrag, use (u64)-1 to say all */
+       __u64 len;
+
+       /*
+        * flags for the operation, which can include turning
+        * on compression for this one defrag
+        */
+       __u64 flags;
+
+       /*
+        * any extent bigger than this will be considered
+        * already defragged.  Use 0 to take the kernel default
+        * Use 1 to say every single extent must be rewritten
+        */
+       __u32 extent_thresh;
+
+       /*
+        * which compression method to use if turning on compression
+        * for this defrag operation.  If unspecified, zlib will
+        * be used
+        */
+       __u32 compress_type;
+
+       /* spare for later */
+       __u32 unused[4];
+};
+
+
 /*
  * inode items have the data typically returned from stat and store other
  * info about object characteristics.  There is one for every file and dir in
@@ -1265,6 +1351,8 @@ struct btrfs_root {
 #define BTRFS_MOUNT_CLEAR_CACHE                (1 << 13)
 #define BTRFS_MOUNT_USER_SUBVOL_RM_ALLOWED (1 << 14)
 #define BTRFS_MOUNT_ENOSPC_DEBUG        (1 << 15)
+#define BTRFS_MOUNT_AUTO_DEFRAG                (1 << 16)
+#define BTRFS_MOUNT_INODE_MAP_CACHE    (1 << 17)
 
 #define btrfs_clear_opt(o, opt)                ((o) &= ~BTRFS_MOUNT_##opt)
 #define btrfs_set_opt(o, opt)          ((o) |= BTRFS_MOUNT_##opt)
@@ -1440,26 +1528,12 @@ static inline u64 btrfs_stripe_offset_nr(struct extent_buffer *eb,
        return btrfs_stripe_offset(eb, btrfs_stripe_nr(c, nr));
 }
 
-static inline void btrfs_set_stripe_offset_nr(struct extent_buffer *eb,
-                                            struct btrfs_chunk *c, int nr,
-                                            u64 val)
-{
-       btrfs_set_stripe_offset(eb, btrfs_stripe_nr(c, nr), val);
-}
-
 static inline u64 btrfs_stripe_devid_nr(struct extent_buffer *eb,
                                         struct btrfs_chunk *c, int nr)
 {
        return btrfs_stripe_devid(eb, btrfs_stripe_nr(c, nr));
 }
 
-static inline void btrfs_set_stripe_devid_nr(struct extent_buffer *eb,
-                                            struct btrfs_chunk *c, int nr,
-                                            u64 val)
-{
-       btrfs_set_stripe_devid(eb, btrfs_stripe_nr(c, nr), val);
-}
-
 /* struct btrfs_block_group_item */
 BTRFS_SETGET_STACK_FUNCS(block_group_used, struct btrfs_block_group_item,
                         used, 64);
@@ -1517,14 +1591,6 @@ btrfs_inode_ctime(struct btrfs_inode_item *inode_item)
        return (struct btrfs_timespec *)ptr;
 }
 
-static inline struct btrfs_timespec *
-btrfs_inode_otime(struct btrfs_inode_item *inode_item)
-{
-       unsigned long ptr = (unsigned long)inode_item;
-       ptr += offsetof(struct btrfs_inode_item, otime);
-       return (struct btrfs_timespec *)ptr;
-}
-
 BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_timespec, sec, 64);
 BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32);
 
@@ -1875,33 +1941,6 @@ static inline u8 *btrfs_header_chunk_tree_uuid(struct extent_buffer *eb)
        return (u8 *)ptr;
 }
 
-static inline u8 *btrfs_super_fsid(struct extent_buffer *eb)
-{
-       unsigned long ptr = offsetof(struct btrfs_super_block, fsid);
-       return (u8 *)ptr;
-}
-
-static inline u8 *btrfs_header_csum(struct extent_buffer *eb)
-{
-       unsigned long ptr = offsetof(struct btrfs_header, csum);
-       return (u8 *)ptr;
-}
-
-static inline struct btrfs_node *btrfs_buffer_node(struct extent_buffer *eb)
-{
-       return NULL;
-}
-
-static inline struct btrfs_leaf *btrfs_buffer_leaf(struct extent_buffer *eb)
-{
-       return NULL;
-}
-
-static inline struct btrfs_header *btrfs_buffer_header(struct extent_buffer *eb)
-{
-       return NULL;
-}
-
 static inline int btrfs_is_leaf(struct extent_buffer *eb)
 {
        return btrfs_header_level(eb) == 0;
@@ -2055,22 +2094,6 @@ static inline struct btrfs_root *btrfs_sb(struct super_block *sb)
        return sb->s_fs_info;
 }
 
-static inline int btrfs_set_root_name(struct btrfs_root *root,
-                                     const char *name, int len)
-{
-       /* if we already have a name just free it */
-       kfree(root->name);
-
-       root->name = kmalloc(len+1, GFP_KERNEL);
-       if (!root->name)
-               return -ENOMEM;
-
-       memcpy(root->name, name, len);
-       root->name[len] = '\0';
-
-       return 0;
-}
-
 static inline u32 btrfs_level_size(struct btrfs_root *root, int level)
 {
        if (level == 0)
@@ -2099,6 +2122,13 @@ static inline bool btrfs_mixed_space_info(struct btrfs_space_info *space_info)
 }
 
 /* extent-tree.c */
+static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_root *root,
+                                                int num_items)
+{
+       return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
+               3 * num_items;
+}
+
 void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
 int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root, unsigned long count);
@@ -2108,12 +2138,9 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
                             u64 num_bytes, u64 *refs, u64 *flags);
 int btrfs_pin_extent(struct btrfs_root *root,
                     u64 bytenr, u64 num, int reserved);
-int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
-                       struct btrfs_root *root, struct extent_buffer *leaf);
 int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root,
                          u64 objectid, u64 offset, u64 bytenr);
-int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy);
 struct btrfs_block_group_cache *btrfs_lookup_block_group(
                                                 struct btrfs_fs_info *info,
                                                 u64 bytenr);
@@ -2224,6 +2251,9 @@ int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
 void btrfs_block_rsv_release(struct btrfs_root *root,
                             struct btrfs_block_rsv *block_rsv,
                             u64 num_bytes);
+int btrfs_truncate_reserve_metadata(struct btrfs_trans_handle *trans,
+                                   struct btrfs_root *root,
+                                   struct btrfs_block_rsv *rsv);
 int btrfs_set_block_group_ro(struct btrfs_root *root,
                             struct btrfs_block_group_cache *cache);
 int btrfs_set_block_group_rw(struct btrfs_root *root,
@@ -2290,10 +2320,12 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
                       struct btrfs_root *root, struct extent_buffer *parent,
                       int start_slot, int cache_only, u64 *last_ret,
                       struct btrfs_key *progress);
-void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p);
+void btrfs_release_path(struct btrfs_path *p);
 struct btrfs_path *btrfs_alloc_path(void);
 void btrfs_free_path(struct btrfs_path *p);
 void btrfs_set_path_blocking(struct btrfs_path *p);
+void btrfs_clear_path_blocking(struct btrfs_path *p,
+                              struct extent_buffer *held);
 void btrfs_unlock_up_safe(struct btrfs_path *p, int level);
 
 int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
@@ -2305,13 +2337,12 @@ static inline int btrfs_del_item(struct btrfs_trans_handle *trans,
        return btrfs_del_items(trans, root, path, path->slots[0], 1);
 }
 
+int setup_items_for_insert(struct btrfs_trans_handle *trans,
+                          struct btrfs_root *root, struct btrfs_path *path,
+                          struct btrfs_key *cpu_key, u32 *data_size,
+                          u32 total_data, u32 total_size, int nr);
 int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
                      *root, struct btrfs_key *key, void *data, u32 data_size);
-int btrfs_insert_some_items(struct btrfs_trans_handle *trans,
-                           struct btrfs_root *root,
-                           struct btrfs_path *path,
-                           struct btrfs_key *cpu_key, u32 *data_size,
-                           int nr);
 int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             struct btrfs_path *path,
@@ -2335,6 +2366,15 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root,
                        struct extent_buffer *node,
                        struct extent_buffer *parent);
+static inline int btrfs_fs_closing(struct btrfs_fs_info *fs_info)
+{
+       /*
+        * Get synced with close_ctree()
+        */
+       smp_mb();
+       return fs_info->closing;
+}
+
 /* root-item.c */
 int btrfs_find_root_ref(struct btrfs_root *tree_root,
                        struct btrfs_path *path,
@@ -2357,8 +2397,6 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
                      *item);
 int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct
                         btrfs_root_item *item, struct btrfs_key *key);
-int btrfs_search_root(struct btrfs_root *root, u64 search_start,
-                     u64 *found_objectid);
 int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid);
 int btrfs_find_orphan_roots(struct btrfs_root *tree_root);
 int btrfs_set_root_node(struct btrfs_root_item *item,
@@ -2368,7 +2406,7 @@ void btrfs_check_and_init_root_item(struct btrfs_root_item *item);
 /* dir-item.c */
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root, const char *name,
-                         int name_len, u64 dir,
+                         int name_len, struct inode *dir,
                          struct btrfs_key *location, u8 type, u64 index);
 struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
                                             struct btrfs_root *root,
@@ -2413,12 +2451,6 @@ int btrfs_del_orphan_item(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root, u64 offset);
 int btrfs_find_orphan_item(struct btrfs_root *root, u64 offset);
 
-/* inode-map.c */
-int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
-                            struct btrfs_root *fs_root,
-                            u64 dirid, u64 *objectid);
-int btrfs_find_highest_inode(struct btrfs_root *fs_root, u64 *objectid);
-
 /* inode-item.c */
 int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root,
@@ -2463,8 +2495,6 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
                           struct btrfs_ordered_sum *sums);
 int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
                       struct bio *bio, u64 file_start, int contig);
-int btrfs_csum_file_bytes(struct btrfs_root *root, struct inode *inode,
-                         u64 start, unsigned long len);
 struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
                                          struct btrfs_root *root,
                                          struct btrfs_path *path,
@@ -2472,8 +2502,8 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
 int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root, struct btrfs_path *path,
                        u64 isize);
-int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start,
-                            u64 end, struct list_head *list);
+int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
+                            struct list_head *list, int search_commit);
 /* inode.c */
 
 /* RHEL and EL kernels have a patch that renames PG_checked to FsMisc */
@@ -2502,15 +2532,12 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
                               u32 min_type);
 
 int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput);
-int btrfs_start_one_delalloc_inode(struct btrfs_root *root, int delay_iput,
-                                  int sync);
 int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
                              struct extent_state **cached_state);
 int btrfs_writepages(struct address_space *mapping,
                     struct writeback_control *wbc);
 int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
-                            struct btrfs_root *new_root,
-                            u64 new_dirid, u64 alloc_hint);
+                            struct btrfs_root *new_root, u64 new_dirid);
 int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
                         size_t size, struct bio *bio, unsigned long bio_flags);
 
@@ -2520,9 +2547,8 @@ unsigned long btrfs_force_ra(struct address_space *mapping,
 int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
 int btrfs_readpage(struct file *file, struct page *page);
 void btrfs_evict_inode(struct inode *inode);
-void btrfs_put_inode(struct inode *inode);
 int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc);
-void btrfs_dirty_inode(struct inode *inode);
+void btrfs_dirty_inode(struct inode *inode, int flags);
 struct inode *btrfs_alloc_inode(struct super_block *sb);
 void btrfs_destroy_inode(struct inode *inode);
 int btrfs_drop_inode(struct inode *inode);
@@ -2531,10 +2557,8 @@ void btrfs_destroy_cachep(void);
 long btrfs_ioctl_trans_end(struct file *file);
 struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
                         struct btrfs_root *root, int *was_new);
-int btrfs_commit_write(struct file *file, struct page *page,
-                      unsigned from, unsigned to);
 struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
-                                   size_t page_offset, u64 start, u64 end,
+                                   size_t pg_offset, u64 start, u64 end,
                                    int create);
 int btrfs_update_inode(struct btrfs_trans_handle *trans,
                              struct btrfs_root *root,
@@ -2566,12 +2590,16 @@ extern const struct dentry_operations btrfs_dentry_operations;
 long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 void btrfs_update_iflags(struct inode *inode);
 void btrfs_inherit_iflags(struct inode *inode, struct inode *dir);
-
+int btrfs_defrag_file(struct inode *inode, struct file *file,
+                     struct btrfs_ioctl_defrag_range_args *range,
+                     u64 newer_than, unsigned long max_pages);
 /* file.c */
+int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
+                          struct inode *inode);
+int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info);
 int btrfs_sync_file(struct file *file, int datasync);
 int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                            int skip_pinned);
-int btrfs_check_file(struct btrfs_root *root, struct inode *inode);
 extern const struct file_operations btrfs_file_operations;
 int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
                       u64 start, u64 end, u64 *hint_byte, int drop_cache);
@@ -2591,10 +2619,6 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
 /* sysfs.c */
 int btrfs_init_sysfs(void);
 void btrfs_exit_sysfs(void);
-int btrfs_sysfs_add_super(struct btrfs_fs_info *fs);
-int btrfs_sysfs_add_root(struct btrfs_root *root);
-void btrfs_sysfs_del_root(struct btrfs_root *root);
-void btrfs_sysfs_del_super(struct btrfs_fs_info *root);
 
 /* xattr.c */
 ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
@@ -2637,4 +2661,18 @@ void btrfs_reloc_pre_snapshot(struct btrfs_trans_handle *trans,
                              u64 *bytes_to_reserve);
 void btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
                              struct btrfs_pending_snapshot *pending);
+
+/* scrub.c */
+int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end,
+                   struct btrfs_scrub_progress *progress, int readonly);
+int btrfs_scrub_pause(struct btrfs_root *root);
+int btrfs_scrub_pause_super(struct btrfs_root *root);
+int btrfs_scrub_continue(struct btrfs_root *root);
+int btrfs_scrub_continue_super(struct btrfs_root *root);
+int btrfs_scrub_cancel(struct btrfs_root *root);
+int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev);
+int btrfs_scrub_cancel_devid(struct btrfs_root *root, u64 devid);
+int btrfs_scrub_progress(struct btrfs_root *root, u64 devid,
+                        struct btrfs_scrub_progress *progress);
+
 #endif
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
new file mode 100644 (file)
index 0000000..f1cbd02
--- /dev/null
@@ -0,0 +1,1717 @@
+/*
+ * Copyright (C) 2011 Fujitsu.  All rights reserved.
+ * Written by Miao Xie <miaox@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 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 021110-1307, USA.
+ */
+
+#include <linux/slab.h>
+#include "delayed-inode.h"
+#include "disk-io.h"
+#include "transaction.h"
+
+#define BTRFS_DELAYED_WRITEBACK                400
+#define BTRFS_DELAYED_BACKGROUND       100
+
+static struct kmem_cache *delayed_node_cache;
+
+int __init btrfs_delayed_inode_init(void)
+{
+       delayed_node_cache = kmem_cache_create("delayed_node",
+                                       sizeof(struct btrfs_delayed_node),
+                                       0,
+                                       SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
+                                       NULL);
+       if (!delayed_node_cache)
+               return -ENOMEM;
+       return 0;
+}
+
+void btrfs_delayed_inode_exit(void)
+{
+       if (delayed_node_cache)
+               kmem_cache_destroy(delayed_node_cache);
+}
+
+static inline void btrfs_init_delayed_node(
+                               struct btrfs_delayed_node *delayed_node,
+                               struct btrfs_root *root, u64 inode_id)
+{
+       delayed_node->root = root;
+       delayed_node->inode_id = inode_id;
+       atomic_set(&delayed_node->refs, 0);
+       delayed_node->count = 0;
+       delayed_node->in_list = 0;
+       delayed_node->inode_dirty = 0;
+       delayed_node->ins_root = RB_ROOT;
+       delayed_node->del_root = RB_ROOT;
+       mutex_init(&delayed_node->mutex);
+       delayed_node->index_cnt = 0;
+       INIT_LIST_HEAD(&delayed_node->n_list);
+       INIT_LIST_HEAD(&delayed_node->p_list);
+       delayed_node->bytes_reserved = 0;
+}
+
+static inline int btrfs_is_continuous_delayed_item(
+                                       struct btrfs_delayed_item *item1,
+                                       struct btrfs_delayed_item *item2)
+{
+       if (item1->key.type == BTRFS_DIR_INDEX_KEY &&
+           item1->key.objectid == item2->key.objectid &&
+           item1->key.type == item2->key.type &&
+           item1->key.offset + 1 == item2->key.offset)
+               return 1;
+       return 0;
+}
+
+static inline struct btrfs_delayed_root *btrfs_get_delayed_root(
+                                                       struct btrfs_root *root)
+{
+       return root->fs_info->delayed_root;
+}
+
+static struct btrfs_delayed_node *btrfs_get_or_create_delayed_node(
+                                                       struct inode *inode)
+{
+       struct btrfs_delayed_node *node;
+       struct btrfs_inode *btrfs_inode = BTRFS_I(inode);
+       struct btrfs_root *root = btrfs_inode->root;
+       u64 ino = btrfs_ino(inode);
+       int ret;
+
+again:
+       node = ACCESS_ONCE(btrfs_inode->delayed_node);
+       if (node) {
+               atomic_inc(&node->refs);        /* can be accessed */
+               return node;
+       }
+
+       spin_lock(&root->inode_lock);
+       node = radix_tree_lookup(&root->delayed_nodes_tree, ino);
+       if (node) {
+               if (btrfs_inode->delayed_node) {
+                       spin_unlock(&root->inode_lock);
+                       goto again;
+               }
+               btrfs_inode->delayed_node = node;
+               atomic_inc(&node->refs);        /* can be accessed */
+               atomic_inc(&node->refs);        /* cached in the inode */
+               spin_unlock(&root->inode_lock);
+               return node;
+       }
+       spin_unlock(&root->inode_lock);
+
+       node = kmem_cache_alloc(delayed_node_cache, GFP_NOFS);
+       if (!node)
+               return ERR_PTR(-ENOMEM);
+       btrfs_init_delayed_node(node, root, ino);
+
+       atomic_inc(&node->refs);        /* cached in the btrfs inode */
+       atomic_inc(&node->refs);        /* can be accessed */
+
+       ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM);
+       if (ret) {
+               kmem_cache_free(delayed_node_cache, node);
+               return ERR_PTR(ret);
+       }
+
+       spin_lock(&root->inode_lock);
+       ret = radix_tree_insert(&root->delayed_nodes_tree, ino, node);
+       if (ret == -EEXIST) {
+               kmem_cache_free(delayed_node_cache, node);
+               spin_unlock(&root->inode_lock);
+               radix_tree_preload_end();
+               goto again;
+       }
+       btrfs_inode->delayed_node = node;
+       spin_unlock(&root->inode_lock);
+       radix_tree_preload_end();
+
+       return node;
+}
+
+/*
+ * Call it when holding delayed_node->mutex
+ *
+ * If mod = 1, add this node into the prepared list.
+ */
+static void btrfs_queue_delayed_node(struct btrfs_delayed_root *root,
+                                    struct btrfs_delayed_node *node,
+                                    int mod)
+{
+       spin_lock(&root->lock);
+       if (node->in_list) {
+               if (!list_empty(&node->p_list))
+                       list_move_tail(&node->p_list, &root->prepare_list);
+               else if (mod)
+                       list_add_tail(&node->p_list, &root->prepare_list);
+       } else {
+               list_add_tail(&node->n_list, &root->node_list);
+               list_add_tail(&node->p_list, &root->prepare_list);
+               atomic_inc(&node->refs);        /* inserted into list */
+               root->nodes++;
+               node->in_list = 1;
+       }
+       spin_unlock(&root->lock);
+}
+
+/* Call it when holding delayed_node->mutex */
+static void btrfs_dequeue_delayed_node(struct btrfs_delayed_root *root,
+                                      struct btrfs_delayed_node *node)
+{
+       spin_lock(&root->lock);
+       if (node->in_list) {
+               root->nodes--;
+               atomic_dec(&node->refs);        /* not in the list */
+               list_del_init(&node->n_list);
+               if (!list_empty(&node->p_list))
+                       list_del_init(&node->p_list);
+               node->in_list = 0;
+       }
+       spin_unlock(&root->lock);
+}
+
+struct btrfs_delayed_node *btrfs_first_delayed_node(
+                       struct btrfs_delayed_root *delayed_root)
+{
+       struct list_head *p;
+       struct btrfs_delayed_node *node = NULL;
+
+       spin_lock(&delayed_root->lock);
+       if (list_empty(&delayed_root->node_list))
+               goto out;
+
+       p = delayed_root->node_list.next;
+       node = list_entry(p, struct btrfs_delayed_node, n_list);
+       atomic_inc(&node->refs);
+out:
+       spin_unlock(&delayed_root->lock);
+
+       return node;
+}
+
+struct btrfs_delayed_node *btrfs_next_delayed_node(
+                                               struct btrfs_delayed_node *node)
+{
+       struct btrfs_delayed_root *delayed_root;
+       struct list_head *p;
+       struct btrfs_delayed_node *next = NULL;
+
+       delayed_root = node->root->fs_info->delayed_root;
+       spin_lock(&delayed_root->lock);
+       if (!node->in_list) {   /* not in the list */
+               if (list_empty(&delayed_root->node_list))
+                       goto out;
+               p = delayed_root->node_list.next;
+       } else if (list_is_last(&node->n_list, &delayed_root->node_list))
+               goto out;
+       else
+               p = node->n_list.next;
+
+       next = list_entry(p, struct btrfs_delayed_node, n_list);
+       atomic_inc(&next->refs);
+out:
+       spin_unlock(&delayed_root->lock);
+
+       return next;
+}
+
+static void __btrfs_release_delayed_node(
+                               struct btrfs_delayed_node *delayed_node,
+                               int mod)
+{
+       struct btrfs_delayed_root *delayed_root;
+
+       if (!delayed_node)
+               return;
+
+       delayed_root = delayed_node->root->fs_info->delayed_root;
+
+       mutex_lock(&delayed_node->mutex);
+       if (delayed_node->count)
+               btrfs_queue_delayed_node(delayed_root, delayed_node, mod);
+       else
+               btrfs_dequeue_delayed_node(delayed_root, delayed_node);
+       mutex_unlock(&delayed_node->mutex);
+
+       if (atomic_dec_and_test(&delayed_node->refs)) {
+               struct btrfs_root *root = delayed_node->root;
+               spin_lock(&root->inode_lock);
+               if (atomic_read(&delayed_node->refs) == 0) {
+                       radix_tree_delete(&root->delayed_nodes_tree,
+                                         delayed_node->inode_id);
+                       kmem_cache_free(delayed_node_cache, delayed_node);
+               }
+               spin_unlock(&root->inode_lock);
+       }
+}
+
+static inline void btrfs_release_delayed_node(struct btrfs_delayed_node *node)
+{
+       __btrfs_release_delayed_node(node, 0);
+}
+
+struct btrfs_delayed_node *btrfs_first_prepared_delayed_node(
+                                       struct btrfs_delayed_root *delayed_root)
+{
+       struct list_head *p;
+       struct btrfs_delayed_node *node = NULL;
+
+       spin_lock(&delayed_root->lock);
+       if (list_empty(&delayed_root->prepare_list))
+               goto out;
+
+       p = delayed_root->prepare_list.next;
+       list_del_init(p);
+       node = list_entry(p, struct btrfs_delayed_node, p_list);
+       atomic_inc(&node->refs);
+out:
+       spin_unlock(&delayed_root->lock);
+
+       return node;
+}
+
+static inline void btrfs_release_prepared_delayed_node(
+                                       struct btrfs_delayed_node *node)
+{
+       __btrfs_release_delayed_node(node, 1);
+}
+
+struct btrfs_delayed_item *btrfs_alloc_delayed_item(u32 data_len)
+{
+       struct btrfs_delayed_item *item;
+       item = kmalloc(sizeof(*item) + data_len, GFP_NOFS);
+       if (item) {
+               item->data_len = data_len;
+               item->ins_or_del = 0;
+               item->bytes_reserved = 0;
+               item->delayed_node = NULL;
+               atomic_set(&item->refs, 1);
+       }
+       return item;
+}
+
+/*
+ * __btrfs_lookup_delayed_item - look up the delayed item by key
+ * @delayed_node: pointer to the delayed node
+ * @key:         the key to look up
+ * @prev:        used to store the prev item if the right item isn't found
+ * @next:        used to store the next item if the right item isn't found
+ *
+ * Note: if we don't find the right item, we will return the prev item and
+ * the next item.
+ */
+static struct btrfs_delayed_item *__btrfs_lookup_delayed_item(
+                               struct rb_root *root,
+                               struct btrfs_key *key,
+                               struct btrfs_delayed_item **prev,
+                               struct btrfs_delayed_item **next)
+{
+       struct rb_node *node, *prev_node = NULL;
+       struct btrfs_delayed_item *delayed_item = NULL;
+       int ret = 0;
+
+       node = root->rb_node;
+
+       while (node) {
+               delayed_item = rb_entry(node, struct btrfs_delayed_item,
+                                       rb_node);
+               prev_node = node;
+               ret = btrfs_comp_cpu_keys(&delayed_item->key, key);
+               if (ret < 0)
+                       node = node->rb_right;
+               else if (ret > 0)
+                       node = node->rb_left;
+               else
+                       return delayed_item;
+       }
+
+       if (prev) {
+               if (!prev_node)
+                       *prev = NULL;
+               else if (ret < 0)
+                       *prev = delayed_item;
+               else if ((node = rb_prev(prev_node)) != NULL) {
+                       *prev = rb_entry(node, struct btrfs_delayed_item,
+                                        rb_node);
+               } else
+                       *prev = NULL;
+       }
+
+       if (next) {
+               if (!prev_node)
+                       *next = NULL;
+               else if (ret > 0)
+                       *next = delayed_item;
+               else if ((node = rb_next(prev_node)) != NULL) {
+                       *next = rb_entry(node, struct btrfs_delayed_item,
+                                        rb_node);
+               } else
+                       *next = NULL;
+       }
+       return NULL;
+}
+
+struct btrfs_delayed_item *__btrfs_lookup_delayed_insertion_item(
+                                       struct btrfs_delayed_node *delayed_node,
+                                       struct btrfs_key *key)
+{
+       struct btrfs_delayed_item *item;
+
+       item = __btrfs_lookup_delayed_item(&delayed_node->ins_root, key,
+                                          NULL, NULL);
+       return item;
+}
+
+struct btrfs_delayed_item *__btrfs_lookup_delayed_deletion_item(
+                                       struct btrfs_delayed_node *delayed_node,
+                                       struct btrfs_key *key)
+{
+       struct btrfs_delayed_item *item;
+
+       item = __btrfs_lookup_delayed_item(&delayed_node->del_root, key,
+                                          NULL, NULL);
+       return item;
+}
+
+struct btrfs_delayed_item *__btrfs_search_delayed_insertion_item(
+                                       struct btrfs_delayed_node *delayed_node,
+                                       struct btrfs_key *key)
+{
+       struct btrfs_delayed_item *item, *next;
+
+       item = __btrfs_lookup_delayed_item(&delayed_node->ins_root, key,
+                                          NULL, &next);
+       if (!item)
+               item = next;
+
+       return item;
+}
+
+struct btrfs_delayed_item *__btrfs_search_delayed_deletion_item(
+                                       struct btrfs_delayed_node *delayed_node,
+                                       struct btrfs_key *key)
+{
+       struct btrfs_delayed_item *item, *next;
+
+       item = __btrfs_lookup_delayed_item(&delayed_node->del_root, key,
+                                          NULL, &next);
+       if (!item)
+               item = next;
+
+       return item;
+}
+
+static int __btrfs_add_delayed_item(struct btrfs_delayed_node *delayed_node,
+                                   struct btrfs_delayed_item *ins,
+                                   int action)
+{
+       struct rb_node **p, *node;
+       struct rb_node *parent_node = NULL;
+       struct rb_root *root;
+       struct btrfs_delayed_item *item;
+       int cmp;
+
+       if (action == BTRFS_DELAYED_INSERTION_ITEM)
+               root = &delayed_node->ins_root;
+       else if (action == BTRFS_DELAYED_DELETION_ITEM)
+               root = &delayed_node->del_root;
+       else
+               BUG();
+       p = &root->rb_node;
+       node = &ins->rb_node;
+
+       while (*p) {
+               parent_node = *p;
+               item = rb_entry(parent_node, struct btrfs_delayed_item,
+                                rb_node);
+
+               cmp = btrfs_comp_cpu_keys(&item->key, &ins->key);
+               if (cmp < 0)
+                       p = &(*p)->rb_right;
+               else if (cmp > 0)
+                       p = &(*p)->rb_left;
+               else
+                       return -EEXIST;
+       }
+
+       rb_link_node(node, parent_node, p);
+       rb_insert_color(node, root);
+       ins->delayed_node = delayed_node;
+       ins->ins_or_del = action;
+
+       if (ins->key.type == BTRFS_DIR_INDEX_KEY &&
+           action == BTRFS_DELAYED_INSERTION_ITEM &&
+           ins->key.offset >= delayed_node->index_cnt)
+                       delayed_node->index_cnt = ins->key.offset + 1;
+
+       delayed_node->count++;
+       atomic_inc(&delayed_node->root->fs_info->delayed_root->items);
+       return 0;
+}
+
+static int __btrfs_add_delayed_insertion_item(struct btrfs_delayed_node *node,
+                                             struct btrfs_delayed_item *item)
+{
+       return __btrfs_add_delayed_item(node, item,
+                                       BTRFS_DELAYED_INSERTION_ITEM);
+}
+
+static int __btrfs_add_delayed_deletion_item(struct btrfs_delayed_node *node,
+                                            struct btrfs_delayed_item *item)
+{
+       return __btrfs_add_delayed_item(node, item,
+                                       BTRFS_DELAYED_DELETION_ITEM);
+}
+
+static void __btrfs_remove_delayed_item(struct btrfs_delayed_item *delayed_item)
+{
+       struct rb_root *root;
+       struct btrfs_delayed_root *delayed_root;
+
+       delayed_root = delayed_item->delayed_node->root->fs_info->delayed_root;
+
+       BUG_ON(!delayed_root);
+       BUG_ON(delayed_item->ins_or_del != BTRFS_DELAYED_DELETION_ITEM &&
+              delayed_item->ins_or_del != BTRFS_DELAYED_INSERTION_ITEM);
+
+       if (delayed_item->ins_or_del == BTRFS_DELAYED_INSERTION_ITEM)
+               root = &delayed_item->delayed_node->ins_root;
+       else
+               root = &delayed_item->delayed_node->del_root;
+
+       rb_erase(&delayed_item->rb_node, root);
+       delayed_item->delayed_node->count--;
+       atomic_dec(&delayed_root->items);
+       if (atomic_read(&delayed_root->items) < BTRFS_DELAYED_BACKGROUND &&
+           waitqueue_active(&delayed_root->wait))
+               wake_up(&delayed_root->wait);
+}
+
+static void btrfs_release_delayed_item(struct btrfs_delayed_item *item)
+{
+       if (item) {
+               __btrfs_remove_delayed_item(item);
+               if (atomic_dec_and_test(&item->refs))
+                       kfree(item);
+       }
+}
+
+struct btrfs_delayed_item *__btrfs_first_delayed_insertion_item(
+                                       struct btrfs_delayed_node *delayed_node)
+{
+       struct rb_node *p;
+       struct btrfs_delayed_item *item = NULL;
+
+       p = rb_first(&delayed_node->ins_root);
+       if (p)
+               item = rb_entry(p, struct btrfs_delayed_item, rb_node);
+
+       return item;
+}
+
+struct btrfs_delayed_item *__btrfs_first_delayed_deletion_item(
+                                       struct btrfs_delayed_node *delayed_node)
+{
+       struct rb_node *p;
+       struct btrfs_delayed_item *item = NULL;
+
+       p = rb_first(&delayed_node->del_root);
+       if (p)
+               item = rb_entry(p, struct btrfs_delayed_item, rb_node);
+
+       return item;
+}
+
+struct btrfs_delayed_item *__btrfs_next_delayed_item(
+                                               struct btrfs_delayed_item *item)
+{
+       struct rb_node *p;
+       struct btrfs_delayed_item *next = NULL;
+
+       p = rb_next(&item->rb_node);
+       if (p)
+               next = rb_entry(p, struct btrfs_delayed_item, rb_node);
+
+       return next;
+}
+
+static inline struct btrfs_delayed_node *btrfs_get_delayed_node(
+                                                       struct inode *inode)
+{
+       struct btrfs_inode *btrfs_inode = BTRFS_I(inode);
+       struct btrfs_delayed_node *delayed_node;
+
+       delayed_node = btrfs_inode->delayed_node;
+       if (delayed_node)
+               atomic_inc(&delayed_node->refs);
+
+       return delayed_node;
+}
+
+static inline struct btrfs_root *btrfs_get_fs_root(struct btrfs_root *root,
+                                                  u64 root_id)
+{
+       struct btrfs_key root_key;
+
+       if (root->objectid == root_id)
+               return root;
+
+       root_key.objectid = root_id;
+       root_key.type = BTRFS_ROOT_ITEM_KEY;
+       root_key.offset = (u64)-1;
+       return btrfs_read_fs_root_no_name(root->fs_info, &root_key);
+}
+
+static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans,
+                                              struct btrfs_root *root,
+                                              struct btrfs_delayed_item *item)
+{
+       struct btrfs_block_rsv *src_rsv;
+       struct btrfs_block_rsv *dst_rsv;
+       u64 num_bytes;
+       int ret;
+
+       if (!trans->bytes_reserved)
+               return 0;
+
+       src_rsv = trans->block_rsv;
+       dst_rsv = &root->fs_info->global_block_rsv;
+
+       num_bytes = btrfs_calc_trans_metadata_size(root, 1);
+       ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
+       if (!ret)
+               item->bytes_reserved = num_bytes;
+
+       return ret;
+}
+
+static void btrfs_delayed_item_release_metadata(struct btrfs_root *root,
+                                               struct btrfs_delayed_item *item)
+{
+       struct btrfs_block_rsv *rsv;
+
+       if (!item->bytes_reserved)
+               return;
+
+       rsv = &root->fs_info->global_block_rsv;
+       btrfs_block_rsv_release(root, rsv,
+                               item->bytes_reserved);
+}
+
+static int btrfs_delayed_inode_reserve_metadata(
+                                       struct btrfs_trans_handle *trans,
+                                       struct btrfs_root *root,
+                                       struct btrfs_delayed_node *node)
+{
+       struct btrfs_block_rsv *src_rsv;
+       struct btrfs_block_rsv *dst_rsv;
+       u64 num_bytes;
+       int ret;
+
+       if (!trans->bytes_reserved)
+               return 0;
+
+       src_rsv = trans->block_rsv;
+       dst_rsv = &root->fs_info->global_block_rsv;
+
+       num_bytes = btrfs_calc_trans_metadata_size(root, 1);
+       ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
+       if (!ret)
+               node->bytes_reserved = num_bytes;
+
+       return ret;
+}
+
+static void btrfs_delayed_inode_release_metadata(struct btrfs_root *root,
+                                               struct btrfs_delayed_node *node)
+{
+       struct btrfs_block_rsv *rsv;
+
+       if (!node->bytes_reserved)
+               return;
+
+       rsv = &root->fs_info->global_block_rsv;
+       btrfs_block_rsv_release(root, rsv,
+                               node->bytes_reserved);
+       node->bytes_reserved = 0;
+}
+
+/*
+ * This helper will insert some continuous items into the same leaf according
+ * to the free space of the leaf.
+ */
+static int btrfs_batch_insert_items(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root,
+                               struct btrfs_path *path,
+                               struct btrfs_delayed_item *item)
+{
+       struct btrfs_delayed_item *curr, *next;
+       int free_space;
+       int total_data_size = 0, total_size = 0;
+       struct extent_buffer *leaf;
+       char *data_ptr;
+       struct btrfs_key *keys;
+       u32 *data_size;
+       struct list_head head;
+       int slot;
+       int nitems;
+       int i;
+       int ret = 0;
+
+       BUG_ON(!path->nodes[0]);
+
+       leaf = path->nodes[0];
+       free_space = btrfs_leaf_free_space(root, leaf);
+       INIT_LIST_HEAD(&head);
+
+       next = item;
+       nitems = 0;
+
+       /*
+        * count the number of the continuous items that we can insert in batch
+        */
+       while (total_size + next->data_len + sizeof(struct btrfs_item) <=
+              free_space) {
+               total_data_size += next->data_len;
+               total_size += next->data_len + sizeof(struct btrfs_item);
+               list_add_tail(&next->tree_list, &head);
+               nitems++;
+
+               curr = next;
+               next = __btrfs_next_delayed_item(curr);
+               if (!next)
+                       break;
+
+               if (!btrfs_is_continuous_delayed_item(curr, next))
+                       break;
+       }
+
+       if (!nitems) {
+               ret = 0;
+               goto out;
+       }
+
+       /*
+        * we need allocate some memory space, but it might cause the task
+        * to sleep, so we set all locked nodes in the path to blocking locks
+        * first.
+        */
+       btrfs_set_path_blocking(path);
+
+       keys = kmalloc(sizeof(struct btrfs_key) * nitems, GFP_NOFS);
+       if (!keys) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       data_size = kmalloc(sizeof(u32) * nitems, GFP_NOFS);
+       if (!data_size) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       /* get keys of all the delayed items */
+       i = 0;
+       list_for_each_entry(next, &head, tree_list) {
+               keys[i] = next->key;
+               data_size[i] = next->data_len;
+               i++;
+       }
+
+       /* reset all the locked nodes in the patch to spinning locks. */
+       btrfs_clear_path_blocking(path, NULL);
+
+       /* insert the keys of the items */
+       ret = setup_items_for_insert(trans, root, path, keys, data_size,
+                                    total_data_size, total_size, nitems);
+       if (ret)
+               goto error;
+
+       /* insert the dir index items */
+       slot = path->slots[0];
+       list_for_each_entry_safe(curr, next, &head, tree_list) {
+               data_ptr = btrfs_item_ptr(leaf, slot, char);
+               write_extent_buffer(leaf, &curr->data,
+                                   (unsigned long)data_ptr,
+                                   curr->data_len);
+               slot++;
+
+               btrfs_delayed_item_release_metadata(root, curr);
+
+               list_del(&curr->tree_list);
+               btrfs_release_delayed_item(curr);
+       }
+
+error:
+       kfree(data_size);
+       kfree(keys);
+out:
+       return ret;
+}
+
+/*
+ * This helper can just do simple insertion that needn't extend item for new
+ * data, such as directory name index insertion, inode insertion.
+ */
+static int btrfs_insert_delayed_item(struct btrfs_trans_handle *trans,
+                                    struct btrfs_root *root,
+                                    struct btrfs_path *path,
+                                    struct btrfs_delayed_item *delayed_item)
+{
+       struct extent_buffer *leaf;
+       struct btrfs_item *item;
+       char *ptr;
+       int ret;
+
+       ret = btrfs_insert_empty_item(trans, root, path, &delayed_item->key,
+                                     delayed_item->data_len);
+       if (ret < 0 && ret != -EEXIST)
+               return ret;
+
+       leaf = path->nodes[0];
+
+       item = btrfs_item_nr(leaf, path->slots[0]);
+       ptr = btrfs_item_ptr(leaf, path->slots[0], char);
+
+       write_extent_buffer(leaf, delayed_item->data, (unsigned long)ptr,
+                           delayed_item->data_len);
+       btrfs_mark_buffer_dirty(leaf);
+
+       btrfs_delayed_item_release_metadata(root, delayed_item);
+       return 0;
+}
+
+/*
+ * we insert an item first, then if there are some continuous items, we try
+ * to insert those items into the same leaf.
+ */
+static int btrfs_insert_delayed_items(struct btrfs_trans_handle *trans,
+                                     struct btrfs_path *path,
+                                     struct btrfs_root *root,
+                                     struct btrfs_delayed_node *node)
+{
+       struct btrfs_delayed_item *curr, *prev;
+       int ret = 0;
+
+do_again:
+       mutex_lock(&node->mutex);
+       curr = __btrfs_first_delayed_insertion_item(node);
+       if (!curr)
+               goto insert_end;
+
+       ret = btrfs_insert_delayed_item(trans, root, path, curr);
+       if (ret < 0) {
+               btrfs_release_path(path);
+               goto insert_end;
+       }
+
+       prev = curr;
+       curr = __btrfs_next_delayed_item(prev);
+       if (curr && btrfs_is_continuous_delayed_item(prev, curr)) {
+               /* insert the continuous items into the same leaf */
+               path->slots[0]++;
+               btrfs_batch_insert_items(trans, root, path, curr);
+       }
+       btrfs_release_delayed_item(prev);
+       btrfs_mark_buffer_dirty(path->nodes[0]);
+
+       btrfs_release_path(path);
+       mutex_unlock(&node->mutex);
+       goto do_again;
+
+insert_end:
+       mutex_unlock(&node->mutex);
+       return ret;
+}
+
+static int btrfs_batch_delete_items(struct btrfs_trans_handle *trans,
+                                   struct btrfs_root *root,
+                                   struct btrfs_path *path,
+                                   struct btrfs_delayed_item *item)
+{
+       struct btrfs_delayed_item *curr, *next;
+       struct extent_buffer *leaf;
+       struct btrfs_key key;
+       struct list_head head;
+       int nitems, i, last_item;
+       int ret = 0;
+
+       BUG_ON(!path->nodes[0]);
+
+       leaf = path->nodes[0];
+
+       i = path->slots[0];
+       last_item = btrfs_header_nritems(leaf) - 1;
+       if (i > last_item)
+               return -ENOENT; /* FIXME: Is errno suitable? */
+
+       next = item;
+       INIT_LIST_HEAD(&head);
+       btrfs_item_key_to_cpu(leaf, &key, i);
+       nitems = 0;
+       /*
+        * count the number of the dir index items that we can delete in batch
+        */
+       while (btrfs_comp_cpu_keys(&next->key, &key) == 0) {
+               list_add_tail(&next->tree_list, &head);
+               nitems++;
+
+               curr = next;
+               next = __btrfs_next_delayed_item(curr);
+               if (!next)
+                       break;
+
+               if (!btrfs_is_continuous_delayed_item(curr, next))
+                       break;
+
+               i++;
+               if (i > last_item)
+                       break;
+               btrfs_item_key_to_cpu(leaf, &key, i);
+       }
+
+       if (!nitems)
+               return 0;
+
+       ret = btrfs_del_items(trans, root, path, path->slots[0], nitems);
+       if (ret)
+               goto out;
+
+       list_for_each_entry_safe(curr, next, &head, tree_list) {
+               btrfs_delayed_item_release_metadata(root, curr);
+               list_del(&curr->tree_list);
+               btrfs_release_delayed_item(curr);
+       }
+
+out:
+       return ret;
+}
+
+static int btrfs_delete_delayed_items(struct btrfs_trans_handle *trans,
+                                     struct btrfs_path *path,
+                                     struct btrfs_root *root,
+                                     struct btrfs_delayed_node *node)
+{
+       struct btrfs_delayed_item *curr, *prev;
+       int ret = 0;
+
+do_again:
+       mutex_lock(&node->mutex);
+       curr = __btrfs_first_delayed_deletion_item(node);
+       if (!curr)
+               goto delete_fail;
+
+       ret = btrfs_search_slot(trans, root, &curr->key, path, -1, 1);
+       if (ret < 0)
+               goto delete_fail;
+       else if (ret > 0) {
+               /*
+                * can't find the item which the node points to, so this node
+                * is invalid, just drop it.
+                */
+               prev = curr;
+               curr = __btrfs_next_delayed_item(prev);
+               btrfs_release_delayed_item(prev);
+               ret = 0;
+               btrfs_release_path(path);
+               if (curr)
+                       goto do_again;
+               else
+                       goto delete_fail;
+       }
+
+       btrfs_batch_delete_items(trans, root, path, curr);
+       btrfs_release_path(path);
+       mutex_unlock(&node->mutex);
+       goto do_again;
+
+delete_fail:
+       btrfs_release_path(path);
+       mutex_unlock(&node->mutex);
+       return ret;
+}
+
+static void btrfs_release_delayed_inode(struct btrfs_delayed_node *delayed_node)
+{
+       struct btrfs_delayed_root *delayed_root;
+
+       if (delayed_node && delayed_node->inode_dirty) {
+               BUG_ON(!delayed_node->root);
+               delayed_node->inode_dirty = 0;
+               delayed_node->count--;
+
+               delayed_root = delayed_node->root->fs_info->delayed_root;
+               atomic_dec(&delayed_root->items);
+               if (atomic_read(&delayed_root->items) <
+                   BTRFS_DELAYED_BACKGROUND &&
+                   waitqueue_active(&delayed_root->wait))
+                       wake_up(&delayed_root->wait);
+       }
+}
+
+static int btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
+                                     struct btrfs_root *root,
+                                     struct btrfs_path *path,
+                                     struct btrfs_delayed_node *node)
+{
+       struct btrfs_key key;
+       struct btrfs_inode_item *inode_item;
+       struct extent_buffer *leaf;
+       int ret;
+
+       mutex_lock(&node->mutex);
+       if (!node->inode_dirty) {
+               mutex_unlock(&node->mutex);
+               return 0;
+       }
+
+       key.objectid = node->inode_id;
+       btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
+       key.offset = 0;
+       ret = btrfs_lookup_inode(trans, root, path, &key, 1);
+       if (ret > 0) {
+               btrfs_release_path(path);
+               mutex_unlock(&node->mutex);
+               return -ENOENT;
+       } else if (ret < 0) {
+               mutex_unlock(&node->mutex);
+               return ret;
+       }
+
+       btrfs_unlock_up_safe(path, 1);
+       leaf = path->nodes[0];
+       inode_item = btrfs_item_ptr(leaf, path->slots[0],
+                                   struct btrfs_inode_item);
+       write_extent_buffer(leaf, &node->inode_item, (unsigned long)inode_item,
+                           sizeof(struct btrfs_inode_item));
+       btrfs_mark_buffer_dirty(leaf);
+       btrfs_release_path(path);
+
+       btrfs_delayed_inode_release_metadata(root, node);
+       btrfs_release_delayed_inode(node);
+       mutex_unlock(&node->mutex);
+
+       return 0;
+}
+
+/* Called when committing the transaction. */
+int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root)
+{
+       struct btrfs_delayed_root *delayed_root;
+       struct btrfs_delayed_node *curr_node, *prev_node;
+       struct btrfs_path *path;
+       struct btrfs_block_rsv *block_rsv;
+       int ret = 0;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+       path->leave_spinning = 1;
+
+       block_rsv = trans->block_rsv;
+       trans->block_rsv = &root->fs_info->global_block_rsv;
+
+       delayed_root = btrfs_get_delayed_root(root);
+
+       curr_node = btrfs_first_delayed_node(delayed_root);
+       while (curr_node) {
+               root = curr_node->root;
+               ret = btrfs_insert_delayed_items(trans, path, root,
+                                                curr_node);
+               if (!ret)
+                       ret = btrfs_delete_delayed_items(trans, path, root,
+                                                        curr_node);
+               if (!ret)
+                       ret = btrfs_update_delayed_inode(trans, root, path,
+                                                        curr_node);
+               if (ret) {
+                       btrfs_release_delayed_node(curr_node);
+                       break;
+               }
+
+               prev_node = curr_node;
+               curr_node = btrfs_next_delayed_node(curr_node);
+               btrfs_release_delayed_node(prev_node);
+       }
+
+       btrfs_free_path(path);
+       trans->block_rsv = block_rsv;
+       return ret;
+}
+
+static int __btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans,
+                                             struct btrfs_delayed_node *node)
+{
+       struct btrfs_path *path;
+       struct btrfs_block_rsv *block_rsv;
+       int ret;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+       path->leave_spinning = 1;
+
+       block_rsv = trans->block_rsv;
+       trans->block_rsv = &node->root->fs_info->global_block_rsv;
+
+       ret = btrfs_insert_delayed_items(trans, path, node->root, node);
+       if (!ret)
+               ret = btrfs_delete_delayed_items(trans, path, node->root, node);
+       if (!ret)
+               ret = btrfs_update_delayed_inode(trans, node->root, path, node);
+       btrfs_free_path(path);
+
+       trans->block_rsv = block_rsv;
+       return ret;
+}
+
+int btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans,
+                                    struct inode *inode)
+{
+       struct btrfs_delayed_node *delayed_node = btrfs_get_delayed_node(inode);
+       int ret;
+
+       if (!delayed_node)
+               return 0;
+
+       mutex_lock(&delayed_node->mutex);
+       if (!delayed_node->count) {
+               mutex_unlock(&delayed_node->mutex);
+               btrfs_release_delayed_node(delayed_node);
+               return 0;
+       }
+       mutex_unlock(&delayed_node->mutex);
+
+       ret = __btrfs_commit_inode_delayed_items(trans, delayed_node);
+       btrfs_release_delayed_node(delayed_node);
+       return ret;
+}
+
+void btrfs_remove_delayed_node(struct inode *inode)
+{
+       struct btrfs_delayed_node *delayed_node;
+
+       delayed_node = ACCESS_ONCE(BTRFS_I(inode)->delayed_node);
+       if (!delayed_node)
+               return;
+
+       BTRFS_I(inode)->delayed_node = NULL;
+       btrfs_release_delayed_node(delayed_node);
+}
+
+struct btrfs_async_delayed_node {
+       struct btrfs_root *root;
+       struct btrfs_delayed_node *delayed_node;
+       struct btrfs_work work;
+};
+
+static void btrfs_async_run_delayed_node_done(struct btrfs_work *work)
+{
+       struct btrfs_async_delayed_node *async_node;
+       struct btrfs_trans_handle *trans;
+       struct btrfs_path *path;
+       struct btrfs_delayed_node *delayed_node = NULL;
+       struct btrfs_root *root;
+       struct btrfs_block_rsv *block_rsv;
+       unsigned long nr = 0;
+       int need_requeue = 0;
+       int ret;
+
+       async_node = container_of(work, struct btrfs_async_delayed_node, work);
+
+       path = btrfs_alloc_path();
+       if (!path)
+               goto out;
+       path->leave_spinning = 1;
+
+       delayed_node = async_node->delayed_node;
+       root = delayed_node->root;
+
+       trans = btrfs_join_transaction(root);
+       if (IS_ERR(trans))
+               goto free_path;
+
+       block_rsv = trans->block_rsv;
+       trans->block_rsv = &root->fs_info->global_block_rsv;
+
+       ret = btrfs_insert_delayed_items(trans, path, root, delayed_node);
+       if (!ret)
+               ret = btrfs_delete_delayed_items(trans, path, root,
+                                                delayed_node);
+
+       if (!ret)
+               btrfs_update_delayed_inode(trans, root, path, delayed_node);
+
+       /*
+        * Maybe new delayed items have been inserted, so we need requeue
+        * the work. Besides that, we must dequeue the empty delayed nodes
+        * to avoid the race between delayed items balance and the worker.
+        * The race like this:
+        *      Task1                           Worker thread
+        *                                      count == 0, needn't requeue
+        *                                        also needn't insert the
+        *                                        delayed node into prepare
+        *                                        list again.
+        *      add lots of delayed items
+        *      queue the delayed node
+        *        already in the list,
+        *        and not in the prepare
+        *        list, it means the delayed
+        *        node is being dealt with
+        *        by the worker.
+        *      do delayed items balance
+        *        the delayed node is being
+        *        dealt with by the worker
+        *        now, just wait.
+        *                                      the worker goto idle.
+        * Task1 will sleep until the transaction is commited.
+        */
+       mutex_lock(&delayed_node->mutex);
+       if (delayed_node->count)
+               need_requeue = 1;
+       else
+               btrfs_dequeue_delayed_node(root->fs_info->delayed_root,
+                                          delayed_node);
+       mutex_unlock(&delayed_node->mutex);
+
+       nr = trans->blocks_used;
+
+       trans->block_rsv = block_rsv;
+       btrfs_end_transaction_dmeta(trans, root);
+       __btrfs_btree_balance_dirty(root, nr);
+free_path:
+       btrfs_free_path(path);
+out:
+       if (need_requeue)
+               btrfs_requeue_work(&async_node->work);
+       else {
+               btrfs_release_prepared_delayed_node(delayed_node);
+               kfree(async_node);
+       }
+}
+
+static int btrfs_wq_run_delayed_node(struct btrfs_delayed_root *delayed_root,
+                                    struct btrfs_root *root, int all)
+{
+       struct btrfs_async_delayed_node *async_node;
+       struct btrfs_delayed_node *curr;
+       int count = 0;
+
+again:
+       curr = btrfs_first_prepared_delayed_node(delayed_root);
+       if (!curr)
+               return 0;
+
+       async_node = kmalloc(sizeof(*async_node), GFP_NOFS);
+       if (!async_node) {
+               btrfs_release_prepared_delayed_node(curr);
+               return -ENOMEM;
+       }
+
+       async_node->root = root;
+       async_node->delayed_node = curr;
+
+       async_node->work.func = btrfs_async_run_delayed_node_done;
+       async_node->work.flags = 0;
+
+       btrfs_queue_worker(&root->fs_info->delayed_workers, &async_node->work);
+       count++;
+
+       if (all || count < 4)
+               goto again;
+
+       return 0;
+}
+
+void btrfs_assert_delayed_root_empty(struct btrfs_root *root)
+{
+       struct btrfs_delayed_root *delayed_root;
+       delayed_root = btrfs_get_delayed_root(root);
+       WARN_ON(btrfs_first_delayed_node(delayed_root));
+}
+
+void btrfs_balance_delayed_items(struct btrfs_root *root)
+{
+       struct btrfs_delayed_root *delayed_root;
+
+       delayed_root = btrfs_get_delayed_root(root);
+
+       if (atomic_read(&delayed_root->items) < BTRFS_DELAYED_BACKGROUND)
+               return;
+
+       if (atomic_read(&delayed_root->items) >= BTRFS_DELAYED_WRITEBACK) {
+               int ret;
+               ret = btrfs_wq_run_delayed_node(delayed_root, root, 1);
+               if (ret)
+                       return;
+
+               wait_event_interruptible_timeout(
+                               delayed_root->wait,
+                               (atomic_read(&delayed_root->items) <
+                                BTRFS_DELAYED_BACKGROUND),
+                               HZ);
+               return;
+       }
+
+       btrfs_wq_run_delayed_node(delayed_root, root, 0);
+}
+
+int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
+                                  struct btrfs_root *root, const char *name,
+                                  int name_len, struct inode *dir,
+                                  struct btrfs_disk_key *disk_key, u8 type,
+                                  u64 index)
+{
+       struct btrfs_delayed_node *delayed_node;
+       struct btrfs_delayed_item *delayed_item;
+       struct btrfs_dir_item *dir_item;
+       int ret;
+
+       delayed_node = btrfs_get_or_create_delayed_node(dir);
+       if (IS_ERR(delayed_node))
+               return PTR_ERR(delayed_node);
+
+       delayed_item = btrfs_alloc_delayed_item(sizeof(*dir_item) + name_len);
+       if (!delayed_item) {
+               ret = -ENOMEM;
+               goto release_node;
+       }
+
+       ret = btrfs_delayed_item_reserve_metadata(trans, root, delayed_item);
+       /*
+        * we have reserved enough space when we start a new transaction,
+        * so reserving metadata failure is impossible
+        */
+       BUG_ON(ret);
+
+       delayed_item->key.objectid = btrfs_ino(dir);
+       btrfs_set_key_type(&delayed_item->key, BTRFS_DIR_INDEX_KEY);
+       delayed_item->key.offset = index;
+
+       dir_item = (struct btrfs_dir_item *)delayed_item->data;
+       dir_item->location = *disk_key;
+       dir_item->transid = cpu_to_le64(trans->transid);
+       dir_item->data_len = 0;
+       dir_item->name_len = cpu_to_le16(name_len);
+       dir_item->type = type;
+       memcpy((char *)(dir_item + 1), name, name_len);
+
+       mutex_lock(&delayed_node->mutex);
+       ret = __btrfs_add_delayed_insertion_item(delayed_node, delayed_item);
+       if (unlikely(ret)) {
+               printk(KERN_ERR "err add delayed dir index item(name: %s) into "
+                               "the insertion tree of the delayed node"
+                               "(root id: %llu, inode id: %llu, errno: %d)\n",
+                               name,
+                               (unsigned long long)delayed_node->root->objectid,
+                               (unsigned long long)delayed_node->inode_id,
+                               ret);
+               BUG();
+       }
+       mutex_unlock(&delayed_node->mutex);
+
+release_node:
+       btrfs_release_delayed_node(delayed_node);
+       return ret;
+}
+
+static int btrfs_delete_delayed_insertion_item(struct btrfs_root *root,
+                                              struct btrfs_delayed_node *node,
+                                              struct btrfs_key *key)
+{
+       struct btrfs_delayed_item *item;
+
+       mutex_lock(&node->mutex);
+       item = __btrfs_lookup_delayed_insertion_item(node, key);
+       if (!item) {
+               mutex_unlock(&node->mutex);
+               return 1;
+       }
+
+       btrfs_delayed_item_release_metadata(root, item);
+       btrfs_release_delayed_item(item);
+       mutex_unlock(&node->mutex);
+       return 0;
+}
+
+int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
+                                  struct btrfs_root *root, struct inode *dir,
+                                  u64 index)
+{
+       struct btrfs_delayed_node *node;
+       struct btrfs_delayed_item *item;
+       struct btrfs_key item_key;
+       int ret;
+
+       node = btrfs_get_or_create_delayed_node(dir);
+       if (IS_ERR(node))
+               return PTR_ERR(node);
+
+       item_key.objectid = btrfs_ino(dir);
+       btrfs_set_key_type(&item_key, BTRFS_DIR_INDEX_KEY);
+       item_key.offset = index;
+
+       ret = btrfs_delete_delayed_insertion_item(root, node, &item_key);
+       if (!ret)
+               goto end;
+
+       item = btrfs_alloc_delayed_item(0);
+       if (!item) {
+               ret = -ENOMEM;
+               goto end;
+       }
+
+       item->key = item_key;
+
+       ret = btrfs_delayed_item_reserve_metadata(trans, root, item);
+       /*
+        * we have reserved enough space when we start a new transaction,
+        * so reserving metadata failure is impossible.
+        */
+       BUG_ON(ret);
+
+       mutex_lock(&node->mutex);
+       ret = __btrfs_add_delayed_deletion_item(node, item);
+       if (unlikely(ret)) {
+               printk(KERN_ERR "err add delayed dir index item(index: %llu) "
+                               "into the deletion tree of the delayed node"
+                               "(root id: %llu, inode id: %llu, errno: %d)\n",
+                               (unsigned long long)index,
+                               (unsigned long long)node->root->objectid,
+                               (unsigned long long)node->inode_id,
+                               ret);
+               BUG();
+       }
+       mutex_unlock(&node->mutex);
+end:
+       btrfs_release_delayed_node(node);
+       return ret;
+}
+
+int btrfs_inode_delayed_dir_index_count(struct inode *inode)
+{
+       struct btrfs_delayed_node *delayed_node = BTRFS_I(inode)->delayed_node;
+       int ret = 0;
+
+       if (!delayed_node)
+               return -ENOENT;
+
+       /*
+        * Since we have held i_mutex of this directory, it is impossible that
+        * a new directory index is added into the delayed node and index_cnt
+        * is updated now. So we needn't lock the delayed node.
+        */
+       if (!delayed_node->index_cnt)
+               return -EINVAL;
+
+       BTRFS_I(inode)->index_cnt = delayed_node->index_cnt;
+       return ret;
+}
+
+void btrfs_get_delayed_items(struct inode *inode, struct list_head *ins_list,
+                            struct list_head *del_list)
+{
+       struct btrfs_delayed_node *delayed_node;
+       struct btrfs_delayed_item *item;
+
+       delayed_node = btrfs_get_delayed_node(inode);
+       if (!delayed_node)
+               return;
+
+       mutex_lock(&delayed_node->mutex);
+       item = __btrfs_first_delayed_insertion_item(delayed_node);
+       while (item) {
+               atomic_inc(&item->refs);
+               list_add_tail(&item->readdir_list, ins_list);
+               item = __btrfs_next_delayed_item(item);
+       }
+
+       item = __btrfs_first_delayed_deletion_item(delayed_node);
+       while (item) {
+               atomic_inc(&item->refs);
+               list_add_tail(&item->readdir_list, del_list);
+               item = __btrfs_next_delayed_item(item);
+       }
+       mutex_unlock(&delayed_node->mutex);
+       /*
+        * This delayed node is still cached in the btrfs inode, so refs
+        * must be > 1 now, and we needn't check it is going to be freed
+        * or not.
+        *
+        * Besides that, this function is used to read dir, we do not
+        * insert/delete delayed items in this period. So we also needn't
+        * requeue or dequeue this delayed node.
+        */
+       atomic_dec(&delayed_node->refs);
+}
+
+void btrfs_put_delayed_items(struct list_head *ins_list,
+                            struct list_head *del_list)
+{
+       struct btrfs_delayed_item *curr, *next;
+
+       list_for_each_entry_safe(curr, next, ins_list, readdir_list) {
+               list_del(&curr->readdir_list);
+               if (atomic_dec_and_test(&curr->refs))
+                       kfree(curr);
+       }
+
+       list_for_each_entry_safe(curr, next, del_list, readdir_list) {
+               list_del(&curr->readdir_list);
+               if (atomic_dec_and_test(&curr->refs))
+                       kfree(curr);
+       }
+}
+
+int btrfs_should_delete_dir_index(struct list_head *del_list,
+                                 u64 index)
+{
+       struct btrfs_delayed_item *curr, *next;
+       int ret;
+
+       if (list_empty(del_list))
+               return 0;
+
+       list_for_each_entry_safe(curr, next, del_list, readdir_list) {
+               if (curr->key.offset > index)
+                       break;
+
+               list_del(&curr->readdir_list);
+               ret = (curr->key.offset == index);
+
+               if (atomic_dec_and_test(&curr->refs))
+                       kfree(curr);
+
+               if (ret)
+                       return 1;
+               else
+                       continue;
+       }
+       return 0;
+}
+
+/*
+ * btrfs_readdir_delayed_dir_index - read dir info stored in the delayed tree
+ *
+ */
+int btrfs_readdir_delayed_dir_index(struct file *filp, void *dirent,
+                                   filldir_t filldir,
+                                   struct list_head *ins_list)
+{
+       struct btrfs_dir_item *di;
+       struct btrfs_delayed_item *curr, *next;
+       struct btrfs_key location;
+       char *name;
+       int name_len;
+       int over = 0;
+       unsigned char d_type;
+
+       if (list_empty(ins_list))
+               return 0;
+
+       /*
+        * Changing the data of the delayed item is impossible. So
+        * we needn't lock them. And we have held i_mutex of the
+        * directory, nobody can delete any directory indexes now.
+        */
+       list_for_each_entry_safe(curr, next, ins_list, readdir_list) {
+               list_del(&curr->readdir_list);
+
+               if (curr->key.offset < filp->f_pos) {
+                       if (atomic_dec_and_test(&curr->refs))
+                               kfree(curr);
+                       continue;
+               }
+
+               filp->f_pos = curr->key.offset;
+
+               di = (struct btrfs_dir_item *)curr->data;
+               name = (char *)(di + 1);
+               name_len = le16_to_cpu(di->name_len);
+
+               d_type = btrfs_filetype_table[di->type];
+               btrfs_disk_key_to_cpu(&location, &di->location);
+
+               over = filldir(dirent, name, name_len, curr->key.offset,
+                              location.objectid, d_type);
+
+               if (atomic_dec_and_test(&curr->refs))
+                       kfree(curr);
+
+               if (over)
+                       return 1;
+       }
+       return 0;
+}
+
+BTRFS_SETGET_STACK_FUNCS(stack_inode_generation, struct btrfs_inode_item,
+                        generation, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_sequence, struct btrfs_inode_item,
+                        sequence, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_transid, struct btrfs_inode_item,
+                        transid, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_size, struct btrfs_inode_item, size, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_nbytes, struct btrfs_inode_item,
+                        nbytes, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_block_group, struct btrfs_inode_item,
+                        block_group, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_nlink, struct btrfs_inode_item, nlink, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_uid, struct btrfs_inode_item, uid, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_gid, struct btrfs_inode_item, gid, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_mode, struct btrfs_inode_item, mode, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_rdev, struct btrfs_inode_item, rdev, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_flags, struct btrfs_inode_item, flags, 64);
+
+BTRFS_SETGET_STACK_FUNCS(stack_timespec_sec, struct btrfs_timespec, sec, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_timespec_nsec, struct btrfs_timespec, nsec, 32);
+
+static void fill_stack_inode_item(struct btrfs_trans_handle *trans,
+                                 struct btrfs_inode_item *inode_item,
+                                 struct inode *inode)
+{
+       btrfs_set_stack_inode_uid(inode_item, inode->i_uid);
+       btrfs_set_stack_inode_gid(inode_item, inode->i_gid);
+       btrfs_set_stack_inode_size(inode_item, BTRFS_I(inode)->disk_i_size);
+       btrfs_set_stack_inode_mode(inode_item, inode->i_mode);
+       btrfs_set_stack_inode_nlink(inode_item, inode->i_nlink);
+       btrfs_set_stack_inode_nbytes(inode_item, inode_get_bytes(inode));
+       btrfs_set_stack_inode_generation(inode_item,
+                                        BTRFS_I(inode)->generation);
+       btrfs_set_stack_inode_sequence(inode_item, BTRFS_I(inode)->sequence);
+       btrfs_set_stack_inode_transid(inode_item, trans->transid);
+       btrfs_set_stack_inode_rdev(inode_item, inode->i_rdev);
+       btrfs_set_stack_inode_flags(inode_item, BTRFS_I(inode)->flags);
+       btrfs_set_stack_inode_block_group(inode_item, 0);
+
+       btrfs_set_stack_timespec_sec(btrfs_inode_atime(inode_item),
+                                    inode->i_atime.tv_sec);
+       btrfs_set_stack_timespec_nsec(btrfs_inode_atime(inode_item),
+                                     inode->i_atime.tv_nsec);
+
+       btrfs_set_stack_timespec_sec(btrfs_inode_mtime(inode_item),
+                                    inode->i_mtime.tv_sec);
+       btrfs_set_stack_timespec_nsec(btrfs_inode_mtime(inode_item),
+                                     inode->i_mtime.tv_nsec);
+
+       btrfs_set_stack_timespec_sec(btrfs_inode_ctime(inode_item),
+                                    inode->i_ctime.tv_sec);
+       btrfs_set_stack_timespec_nsec(btrfs_inode_ctime(inode_item),
+                                     inode->i_ctime.tv_nsec);
+}
+
+int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans,
+                              struct btrfs_root *root, struct inode *inode)
+{
+       struct btrfs_delayed_node *delayed_node;
+       int ret = 0;
+
+       delayed_node = btrfs_get_or_create_delayed_node(inode);
+       if (IS_ERR(delayed_node))
+               return PTR_ERR(delayed_node);
+
+       mutex_lock(&delayed_node->mutex);
+       if (delayed_node->inode_dirty) {
+               fill_stack_inode_item(trans, &delayed_node->inode_item, inode);
+               goto release_node;
+       }
+
+       ret = btrfs_delayed_inode_reserve_metadata(trans, root, delayed_node);
+       /*
+        * we must reserve enough space when we start a new transaction,
+        * so reserving metadata failure is impossible
+        */
+       BUG_ON(ret);
+
+       fill_stack_inode_item(trans, &delayed_node->inode_item, inode);
+       delayed_node->inode_dirty = 1;
+       delayed_node->count++;
+       atomic_inc(&root->fs_info->delayed_root->items);
+release_node:
+       mutex_unlock(&delayed_node->mutex);
+       btrfs_release_delayed_node(delayed_node);
+       return ret;
+}
+
+static void __btrfs_kill_delayed_node(struct btrfs_delayed_node *delayed_node)
+{
+       struct btrfs_root *root = delayed_node->root;
+       struct btrfs_delayed_item *curr_item, *prev_item;
+
+       mutex_lock(&delayed_node->mutex);
+       curr_item = __btrfs_first_delayed_insertion_item(delayed_node);
+       while (curr_item) {
+               btrfs_delayed_item_release_metadata(root, curr_item);
+               prev_item = curr_item;
+               curr_item = __btrfs_next_delayed_item(prev_item);
+               btrfs_release_delayed_item(prev_item);
+       }
+
+       curr_item = __btrfs_first_delayed_deletion_item(delayed_node);
+       while (curr_item) {
+               btrfs_delayed_item_release_metadata(root, curr_item);
+               prev_item = curr_item;
+               curr_item = __btrfs_next_delayed_item(prev_item);
+               btrfs_release_delayed_item(prev_item);
+       }
+
+       if (delayed_node->inode_dirty) {
+               btrfs_delayed_inode_release_metadata(root, delayed_node);
+               btrfs_release_delayed_inode(delayed_node);
+       }
+       mutex_unlock(&delayed_node->mutex);
+}
+
+void btrfs_kill_delayed_inode_items(struct inode *inode)
+{
+       struct btrfs_delayed_node *delayed_node;
+
+       delayed_node = btrfs_get_delayed_node(inode);
+       if (!delayed_node)
+               return;
+
+       __btrfs_kill_delayed_node(delayed_node);
+       btrfs_release_delayed_node(delayed_node);
+}
+
+void btrfs_kill_all_delayed_nodes(struct btrfs_root *root)
+{
+       u64 inode_id = 0;
+       struct btrfs_delayed_node *delayed_nodes[8];
+       int i, n;
+
+       while (1) {
+               spin_lock(&root->inode_lock);
+               n = radix_tree_gang_lookup(&root->delayed_nodes_tree,
+                                          (void **)delayed_nodes, inode_id,
+                                          ARRAY_SIZE(delayed_nodes));
+               if (!n) {
+                       spin_unlock(&root->inode_lock);
+                       break;
+               }
+
+               inode_id = delayed_nodes[n - 1]->inode_id + 1;
+
+               for (i = 0; i < n; i++)
+                       atomic_inc(&delayed_nodes[i]->refs);
+               spin_unlock(&root->inode_lock);
+
+               for (i = 0; i < n; i++) {
+                       __btrfs_kill_delayed_node(delayed_nodes[i]);
+                       btrfs_release_delayed_node(delayed_nodes[i]);
+               }
+       }
+}
diff --git a/fs/btrfs/delayed-inode.h b/fs/btrfs/delayed-inode.h
new file mode 100644 (file)
index 0000000..d1a6a29
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2011 Fujitsu.  All rights reserved.
+ * Written by Miao Xie <miaox@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 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 021110-1307, USA.
+ */
+
+#ifndef __DELAYED_TREE_OPERATION_H
+#define __DELAYED_TREE_OPERATION_H
+
+#include <linux/rbtree.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include "ctree.h"
+
+/* types of the delayed item */
+#define BTRFS_DELAYED_INSERTION_ITEM   1
+#define BTRFS_DELAYED_DELETION_ITEM    2
+
+struct btrfs_delayed_root {
+       spinlock_t lock;
+       struct list_head node_list;
+       /*
+        * Used for delayed nodes which is waiting to be dealt with by the
+        * worker. If the delayed node is inserted into the work queue, we
+        * drop it from this list.
+        */
+       struct list_head prepare_list;
+       atomic_t items;         /* for delayed items */
+       int nodes;              /* for delayed nodes */
+       wait_queue_head_t wait;
+};
+
+struct btrfs_delayed_node {
+       u64 inode_id;
+       u64 bytes_reserved;
+       struct btrfs_root *root;
+       /* Used to add the node into the delayed root's node list. */
+       struct list_head n_list;
+       /*
+        * Used to add the node into the prepare list, the nodes in this list
+        * is waiting to be dealt with by the async worker.
+        */
+       struct list_head p_list;
+       struct rb_root ins_root;
+       struct rb_root del_root;
+       struct mutex mutex;
+       struct btrfs_inode_item inode_item;
+       atomic_t refs;
+       u64 index_cnt;
+       bool in_list;
+       bool inode_dirty;
+       int count;
+};
+
+struct btrfs_delayed_item {
+       struct rb_node rb_node;
+       struct btrfs_key key;
+       struct list_head tree_list;     /* used for batch insert/delete items */
+       struct list_head readdir_list;  /* used for readdir items */
+       u64 bytes_reserved;
+       struct btrfs_delayed_node *delayed_node;
+       atomic_t refs;
+       int ins_or_del;
+       u32 data_len;
+       char data[0];
+};
+
+static inline void btrfs_init_delayed_root(
+                               struct btrfs_delayed_root *delayed_root)
+{
+       atomic_set(&delayed_root->items, 0);
+       delayed_root->nodes = 0;
+       spin_lock_init(&delayed_root->lock);
+       init_waitqueue_head(&delayed_root->wait);
+       INIT_LIST_HEAD(&delayed_root->node_list);
+       INIT_LIST_HEAD(&delayed_root->prepare_list);
+}
+
+int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
+                                  struct btrfs_root *root, const char *name,
+                                  int name_len, struct inode *dir,
+                                  struct btrfs_disk_key *disk_key, u8 type,
+                                  u64 index);
+
+int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
+                                  struct btrfs_root *root, struct inode *dir,
+                                  u64 index);
+
+int btrfs_inode_delayed_dir_index_count(struct inode *inode);
+
+int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root);
+
+void btrfs_balance_delayed_items(struct btrfs_root *root);
+
+int btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans,
+                                    struct inode *inode);
+/* Used for evicting the inode. */
+void btrfs_remove_delayed_node(struct inode *inode);
+void btrfs_kill_delayed_inode_items(struct inode *inode);
+
+
+int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans,
+                              struct btrfs_root *root, struct inode *inode);
+
+/* Used for drop dead root */
+void btrfs_kill_all_delayed_nodes(struct btrfs_root *root);
+
+/* Used for readdir() */
+void btrfs_get_delayed_items(struct inode *inode, struct list_head *ins_list,
+                            struct list_head *del_list);
+void btrfs_put_delayed_items(struct list_head *ins_list,
+                            struct list_head *del_list);
+int btrfs_should_delete_dir_index(struct list_head *del_list,
+                                 u64 index);
+int btrfs_readdir_delayed_dir_index(struct file *filp, void *dirent,
+                                   filldir_t filldir,
+                                   struct list_head *ins_list);
+
+/* for init */
+int __init btrfs_delayed_inode_init(void);
+void btrfs_delayed_inode_exit(void);
+
+/* for debugging */
+void btrfs_assert_delayed_root_empty(struct btrfs_root *root);
+
+#endif
index bce28f6538995bc908a6b2dee331e59aba91f651..125cf76fcd086803d35bd257bdb54168486e0e0b 100644 (file)
@@ -280,44 +280,6 @@ again:
        return 1;
 }
 
-/*
- * This checks to see if there are any delayed refs in the
- * btree for a given bytenr.  It returns one if it finds any
- * and zero otherwise.
- *
- * If it only finds a head node, it returns 0.
- *
- * The idea is to use this when deciding if you can safely delete an
- * extent from the extent allocation tree.  There may be a pending
- * ref in the rbtree that adds or removes references, so as long as this
- * returns one you need to leave the BTRFS_EXTENT_ITEM in the extent
- * allocation tree.
- */
-int btrfs_delayed_ref_pending(struct btrfs_trans_handle *trans, u64 bytenr)
-{
-       struct btrfs_delayed_ref_node *ref;
-       struct btrfs_delayed_ref_root *delayed_refs;
-       struct rb_node *prev_node;
-       int ret = 0;
-
-       delayed_refs = &trans->transaction->delayed_refs;
-       spin_lock(&delayed_refs->lock);
-
-       ref = find_ref_head(&delayed_refs->root, bytenr, NULL);
-       if (ref) {
-               prev_node = rb_prev(&ref->rb_node);
-               if (!prev_node)
-                       goto out;
-               ref = rb_entry(prev_node, struct btrfs_delayed_ref_node,
-                              rb_node);
-               if (ref->bytenr == bytenr)
-                       ret = 1;
-       }
-out:
-       spin_unlock(&delayed_refs->lock);
-       return ret;
-}
-
 /*
  * helper function to update an extent delayed ref in the
  * rbtree.  existing and update must both have the same
@@ -747,79 +709,3 @@ btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr)
                return btrfs_delayed_node_to_head(ref);
        return NULL;
 }
-
-/*
- * add a delayed ref to the tree.  This does all of the accounting required
- * to make sure the delayed ref is eventually processed before this
- * transaction commits.
- *
- * The main point of this call is to add and remove a backreference in a single
- * shot, taking the lock only once, and only searching for the head node once.
- *
- * It is the same as doing a ref add and delete in two separate calls.
- */
-#if 0
-int btrfs_update_delayed_ref(struct btrfs_trans_handle *trans,
-                         u64 bytenr, u64 num_bytes, u64 orig_parent,
-                         u64 parent, u64 orig_ref_root, u64 ref_root,
-                         u64 orig_ref_generation, u64 ref_generation,
-                         u64 owner_objectid, int pin)
-{
-       struct btrfs_delayed_ref *ref;
-       struct btrfs_delayed_ref *old_ref;
-       struct btrfs_delayed_ref_head *head_ref;
-       struct btrfs_delayed_ref_root *delayed_refs;
-       int ret;
-
-       ref = kmalloc(sizeof(*ref), GFP_NOFS);
-       if (!ref)
-               return -ENOMEM;
-
-       old_ref = kmalloc(sizeof(*old_ref), GFP_NOFS);
-       if (!old_ref) {
-               kfree(ref);
-               return -ENOMEM;
-       }
-
-       /*
-        * the parent = 0 case comes from cases where we don't actually
-        * know the parent yet.  It will get updated later via a add/drop
-        * pair.
-        */
-       if (parent == 0)
-               parent = bytenr;
-       if (orig_parent == 0)
-               orig_parent = bytenr;
-
-       head_ref = kmalloc(sizeof(*head_ref), GFP_NOFS);
-       if (!head_ref) {
-               kfree(ref);
-               kfree(old_ref);
-               return -ENOMEM;
-       }
-       delayed_refs = &trans->transaction->delayed_refs;
-       spin_lock(&delayed_refs->lock);
-
-       /*
-        * insert both the head node and the new ref without dropping
-        * the spin lock
-        */
-       ret = __btrfs_add_delayed_ref(trans, &head_ref->node, bytenr, num_bytes,
-                                     (u64)-1, 0, 0, 0,
-                                     BTRFS_UPDATE_DELAYED_HEAD, 0);
-       BUG_ON(ret);
-
-       ret = __btrfs_add_delayed_ref(trans, &ref->node, bytenr, num_bytes,
-                                     parent, ref_root, ref_generation,
-                                     owner_objectid, BTRFS_ADD_DELAYED_REF, 0);
-       BUG_ON(ret);
-
-       ret = __btrfs_add_delayed_ref(trans, &old_ref->node, bytenr, num_bytes,
-                                     orig_parent, orig_ref_root,
-                                     orig_ref_generation, owner_objectid,
-                                     BTRFS_DROP_DELAYED_REF, pin);
-       BUG_ON(ret);
-       spin_unlock(&delayed_refs->lock);
-       return 0;
-}
-#endif
index 50e3cf92fbdac1610261e02c314a580b71c2f9ab..e287e3b0eab0d970d37f0f4c70fd688b22f276ac 100644 (file)
@@ -166,12 +166,6 @@ int btrfs_add_delayed_extent_op(struct btrfs_trans_handle *trans,
 
 struct btrfs_delayed_ref_head *
 btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr);
-int btrfs_delayed_ref_pending(struct btrfs_trans_handle *trans, u64 bytenr);
-int btrfs_update_delayed_ref(struct btrfs_trans_handle *trans,
-                         u64 bytenr, u64 num_bytes, u64 orig_parent,
-                         u64 parent, u64 orig_ref_root, u64 ref_root,
-                         u64 orig_ref_generation, u64 ref_generation,
-                         u64 owner_objectid, int pin);
 int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
                           struct btrfs_delayed_ref_head *head);
 int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
index c62f02f6ae693728ce9286d963b78708428a86fb..685f2593c4f049559a087cec8b88daa04a0d357d 100644 (file)
@@ -50,7 +50,6 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
                if (di)
                        return ERR_PTR(-EEXIST);
                ret = btrfs_extend_item(trans, root, path, data_size);
-               WARN_ON(ret > 0);
        }
        if (ret < 0)
                return ERR_PTR(ret);
@@ -124,8 +123,9 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
  * to use for the second index (if one is created).
  */
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
-                         *root, const char *name, int name_len, u64 dir,
-                         struct btrfs_key *location, u8 type, u64 index)
+                         *root, const char *name, int name_len,
+                         struct inode *dir, struct btrfs_key *location,
+                         u8 type, u64 index)
 {
        int ret = 0;
        int ret2 = 0;
@@ -137,13 +137,17 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
        struct btrfs_disk_key disk_key;
        u32 data_size;
 
-       key.objectid = dir;
+       key.objectid = btrfs_ino(dir);
        btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
        key.offset = btrfs_name_hash(name, name_len);
 
        path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
        path->leave_spinning = 1;
 
+       btrfs_cpu_key_to_disk(&disk_key, location);
+
        data_size = sizeof(*dir_item) + name_len;
        dir_item = insert_with_overflow(trans, root, path, &key, data_size,
                                        name, name_len);
@@ -155,7 +159,6 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
        }
 
        leaf = path->nodes[0];
-       btrfs_cpu_key_to_disk(&disk_key, location);
        btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
        btrfs_set_dir_type(leaf, dir_item, type);
        btrfs_set_dir_data_len(leaf, dir_item, 0);
@@ -172,29 +175,11 @@ second_insert:
                ret = 0;
                goto out_free;
        }
-       btrfs_release_path(root, path);
-
-       btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
-       key.offset = index;
-       dir_item = insert_with_overflow(trans, root, path, &key, data_size,
-                                       name, name_len);
-       if (IS_ERR(dir_item)) {
-               ret2 = PTR_ERR(dir_item);
-               goto out_free;
-       }
-       leaf = path->nodes[0];
-       btrfs_cpu_key_to_disk(&disk_key, location);
-       btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
-       btrfs_set_dir_type(leaf, dir_item, type);
-       btrfs_set_dir_data_len(leaf, dir_item, 0);
-       btrfs_set_dir_name_len(leaf, dir_item, name_len);
-       btrfs_set_dir_transid(leaf, dir_item, trans->transid);
-       name_ptr = (unsigned long)(dir_item + 1);
-       write_extent_buffer(leaf, name, name_ptr, name_len);
-       btrfs_mark_buffer_dirty(leaf);
+       btrfs_release_path(path);
 
+       ret2 = btrfs_insert_delayed_dir_index(trans, root, name, name_len, dir,
+                                             &disk_key, type, index);
 out_free:
-
        btrfs_free_path(path);
        if (ret)
                return ret;
@@ -452,7 +437,7 @@ int verify_dir_item(struct btrfs_root *root,
                namelen = XATTR_NAME_MAX;
 
        if (btrfs_dir_name_len(leaf, dir_item) > namelen) {
-               printk(KERN_CRIT "btrfS: invalid dir item name len: %u\n",
+               printk(KERN_CRIT "btrfs: invalid dir item name len: %u\n",
                       (unsigned)btrfs_dir_data_len(leaf, dir_item));
                return 1;
        }
index 228cf36ece8351475d5075f74e15624e4276e112..1ac8db5dc0a31b9a742099956b121cd75ba0a1a6 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/crc32c.h>
 #include <linux/slab.h>
 #include <linux/migrate.h>
+#include <linux/ratelimit.h>
 #include <asm/unaligned.h>
 #include "compat.h"
 #include "ctree.h"
@@ -41,6 +42,7 @@
 #include "locking.h"
 #include "tree-log.h"
 #include "free-space-cache.h"
+#include "inode-map.h"
 
 static struct extent_io_ops btree_extent_io_ops;
 static void end_workqueue_fn(struct btrfs_work *work);
@@ -137,7 +139,7 @@ static const char *btrfs_eb_name[BTRFS_MAX_LEVEL + 1] = {
  * that covers the entire device
  */
 static struct extent_map *btree_get_extent(struct inode *inode,
-               struct page *page, size_t page_offset, u64 start, u64 len,
+               struct page *page, size_t pg_offset, u64 start, u64 len,
                int create)
 {
        struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
@@ -154,7 +156,7 @@ static struct extent_map *btree_get_extent(struct inode *inode,
        }
        read_unlock(&em_tree->lock);
 
-       em = alloc_extent_map(GFP_NOFS);
+       em = alloc_extent_map();
        if (!em) {
                em = ERR_PTR(-ENOMEM);
                goto out;
@@ -254,14 +256,12 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
                        memcpy(&found, result, csum_size);
 
                        read_extent_buffer(buf, &val, 0, csum_size);
-                       if (printk_ratelimit()) {
-                               printk(KERN_INFO "btrfs: %s checksum verify "
+                       printk_ratelimited(KERN_INFO "btrfs: %s checksum verify "
                                       "failed on %llu wanted %X found %X "
                                       "level %d\n",
                                       root->fs_info->sb->s_id,
                                       (unsigned long long)buf->start, val, found,
                                       btrfs_header_level(buf));
-                       }
                        if (result != (char *)&inline_result)
                                kfree(result);
                        return 1;
@@ -296,13 +296,11 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
                ret = 0;
                goto out;
        }
-       if (printk_ratelimit()) {
-               printk("parent transid verify failed on %llu wanted %llu "
+       printk_ratelimited("parent transid verify failed on %llu wanted %llu "
                       "found %llu\n",
                       (unsigned long long)eb->start,
                       (unsigned long long)parent_transid,
                       (unsigned long long)btrfs_header_generation(eb));
-       }
        ret = 1;
        clear_extent_buffer_uptodate(io_tree, eb, &cached_state);
 out:
@@ -380,7 +378,7 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
        len = page->private >> 2;
        WARN_ON(len == 0);
 
-       eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS);
+       eb = alloc_extent_buffer(tree, start, len, page);
        if (eb == NULL) {
                WARN_ON(1);
                goto out;
@@ -525,7 +523,7 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
        len = page->private >> 2;
        WARN_ON(len == 0);
 
-       eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS);
+       eb = alloc_extent_buffer(tree, start, len, page);
        if (eb == NULL) {
                ret = -EIO;
                goto out;
@@ -533,12 +531,10 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
 
        found_start = btrfs_header_bytenr(eb);
        if (found_start != start) {
-               if (printk_ratelimit()) {
-                       printk(KERN_INFO "btrfs bad tree block start "
+               printk_ratelimited(KERN_INFO "btrfs bad tree block start "
                               "%llu %llu\n",
                               (unsigned long long)found_start,
                               (unsigned long long)eb->start);
-               }
                ret = -EIO;
                goto err;
        }
@@ -550,10 +546,8 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
                goto err;
        }
        if (check_tree_block_fsid(root, eb)) {
-               if (printk_ratelimit()) {
-                       printk(KERN_INFO "btrfs bad fsid on block %llu\n",
+               printk_ratelimited(KERN_INFO "btrfs bad fsid on block %llu\n",
                               (unsigned long long)eb->start);
-               }
                ret = -EIO;
                goto err;
        }
@@ -650,12 +644,6 @@ unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info)
        return 256 * limit;
 }
 
-int btrfs_congested_async(struct btrfs_fs_info *info, int iodone)
-{
-       return atomic_read(&info->nr_async_bios) >
-               btrfs_async_submit_limit(info);
-}
-
 static void run_one_async_start(struct btrfs_work *work)
 {
        struct async_submit_bio *async;
@@ -963,7 +951,7 @@ struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
        struct inode *btree_inode = root->fs_info->btree_inode;
        struct extent_buffer *eb;
        eb = find_extent_buffer(&BTRFS_I(btree_inode)->io_tree,
-                               bytenr, blocksize, GFP_NOFS);
+                               bytenr, blocksize);
        return eb;
 }
 
@@ -974,7 +962,7 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
        struct extent_buffer *eb;
 
        eb = alloc_extent_buffer(&BTRFS_I(btree_inode)->io_tree,
-                                bytenr, blocksize, NULL, GFP_NOFS);
+                                bytenr, blocksize, NULL);
        return eb;
 }
 
@@ -1056,15 +1044,14 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
        root->last_trans = 0;
        root->highest_objectid = 0;
        root->name = NULL;
-       root->in_sysfs = 0;
        root->inode_tree = RB_ROOT;
+       INIT_RADIX_TREE(&root->delayed_nodes_tree, GFP_ATOMIC);
        root->block_rsv = NULL;
        root->orphan_block_rsv = NULL;
 
        INIT_LIST_HEAD(&root->dirty_list);
        INIT_LIST_HEAD(&root->orphan_list);
        INIT_LIST_HEAD(&root->root_list);
-       spin_lock_init(&root->node_lock);
        spin_lock_init(&root->orphan_lock);
        spin_lock_init(&root->inode_lock);
        spin_lock_init(&root->accounting_lock);
@@ -1080,7 +1067,7 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
        root->log_transid = 0;
        root->last_log_commit = 0;
        extent_io_tree_init(&root->dirty_log_pages,
-                            fs_info->btree_inode->i_mapping, GFP_NOFS);
+                            fs_info->btree_inode->i_mapping);
 
        memset(&root->root_key, 0, sizeof(root->root_key));
        memset(&root->root_item, 0, sizeof(root->root_item));
@@ -1283,21 +1270,6 @@ out:
        return root;
 }
 
-struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
-                                       u64 root_objectid)
-{
-       struct btrfs_root *root;
-
-       if (root_objectid == BTRFS_ROOT_TREE_OBJECTID)
-               return fs_info->tree_root;
-       if (root_objectid == BTRFS_EXTENT_TREE_OBJECTID)
-               return fs_info->extent_root;
-
-       root = radix_tree_lookup(&fs_info->fs_roots_radix,
-                                (unsigned long)root_objectid);
-       return root;
-}
-
 struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
                                              struct btrfs_key *location)
 {
@@ -1326,7 +1298,22 @@ again:
        if (IS_ERR(root))
                return root;
 
-       set_anon_super(&root->anon_super, NULL);
+       root->free_ino_ctl = kzalloc(sizeof(*root->free_ino_ctl), GFP_NOFS);
+       root->free_ino_pinned = kzalloc(sizeof(*root->free_ino_pinned),
+                                       GFP_NOFS);
+       if (!root->free_ino_pinned || !root->free_ino_ctl) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       btrfs_init_free_ino_ctl(root);
+       mutex_init(&root->fs_commit_mutex);
+       spin_lock_init(&root->cache_lock);
+       init_waitqueue_head(&root->cache_wait);
+
+       ret = set_anon_super(&root->anon_super, NULL);
+       if (ret)
+               goto fail;
 
        if (btrfs_root_refs(&root->root_item) == 0) {
                ret = -ENOENT;
@@ -1369,41 +1356,6 @@ fail:
        return ERR_PTR(ret);
 }
 
-struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
-                                     struct btrfs_key *location,
-                                     const char *name, int namelen)
-{
-       return btrfs_read_fs_root_no_name(fs_info, location);
-#if 0
-       struct btrfs_root *root;
-       int ret;
-
-       root = btrfs_read_fs_root_no_name(fs_info, location);
-       if (!root)
-               return NULL;
-
-       if (root->in_sysfs)
-               return root;
-
-       ret = btrfs_set_root_name(root, name, namelen);
-       if (ret) {
-               free_extent_buffer(root->node);
-               kfree(root);
-               return ERR_PTR(ret);
-       }
-
-       ret = btrfs_sysfs_add_root(root);
-       if (ret) {
-               free_extent_buffer(root->node);
-               kfree(root->name);
-               kfree(root);
-               return ERR_PTR(ret);
-       }
-       root->in_sysfs = 1;
-       return root;
-#endif
-}
-
 static int btrfs_congested_fn(void *congested_data, int bdi_bits)
 {
        struct btrfs_fs_info *info = (struct btrfs_fs_info *)congested_data;
@@ -1411,7 +1363,8 @@ static int btrfs_congested_fn(void *congested_data, int bdi_bits)
        struct btrfs_device *device;
        struct backing_dev_info *bdi;
 
-       list_for_each_entry(device, &info->fs_devices->devices, dev_list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(device, &info->fs_devices->devices, dev_list) {
                if (!device->bdev)
                        continue;
                bdi = blk_get_backing_dev_info(device->bdev);
@@ -1420,6 +1373,7 @@ static int btrfs_congested_fn(void *congested_data, int bdi_bits)
                        break;
                }
        }
+       rcu_read_unlock();
        return ret;
 }
 
@@ -1522,6 +1476,7 @@ static int cleaner_kthread(void *arg)
                        btrfs_run_delayed_iputs(root);
                        btrfs_clean_old_snapshots(root);
                        mutex_unlock(&root->fs_info->cleaner_mutex);
+                       btrfs_run_defrag_inodes(root->fs_info);
                }
 
                if (freezing(current)) {
@@ -1551,24 +1506,24 @@ static int transaction_kthread(void *arg)
                vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE);
                mutex_lock(&root->fs_info->transaction_kthread_mutex);
 
-               spin_lock(&root->fs_info->new_trans_lock);
+               spin_lock(&root->fs_info->trans_lock);
                cur = root->fs_info->running_transaction;
                if (!cur) {
-                       spin_unlock(&root->fs_info->new_trans_lock);
+                       spin_unlock(&root->fs_info->trans_lock);
                        goto sleep;
                }
 
                now = get_seconds();
                if (!cur->blocked &&
                    (now < cur->start_time || now - cur->start_time < 30)) {
-                       spin_unlock(&root->fs_info->new_trans_lock);
+                       spin_unlock(&root->fs_info->trans_lock);
                        delay = HZ * 5;
                        goto sleep;
                }
                transid = cur->transid;
-               spin_unlock(&root->fs_info->new_trans_lock);
+               spin_unlock(&root->fs_info->trans_lock);
 
-               trans = btrfs_join_transaction(root, 1);
+               trans = btrfs_join_transaction(root);
                BUG_ON(IS_ERR(trans));
                if (transid == trans->transid) {
                        ret = btrfs_commit_transaction(trans, root);
@@ -1611,7 +1566,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        struct btrfs_root *csum_root = kzalloc(sizeof(struct btrfs_root),
                                                 GFP_NOFS);
        struct btrfs_root *tree_root = btrfs_sb(sb);
-       struct btrfs_fs_info *fs_info = tree_root->fs_info;
+       struct btrfs_fs_info *fs_info = NULL;
        struct btrfs_root *chunk_root = kzalloc(sizeof(struct btrfs_root),
                                                GFP_NOFS);
        struct btrfs_root *dev_root = kzalloc(sizeof(struct btrfs_root),
@@ -1623,11 +1578,12 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 
        struct btrfs_super_block *disk_super;
 
-       if (!extent_root || !tree_root || !fs_info ||
+       if (!extent_root || !tree_root || !tree_root->fs_info ||
            !chunk_root || !dev_root || !csum_root) {
                err = -ENOMEM;
                goto fail;
        }
+       fs_info = tree_root->fs_info;
 
        ret = init_srcu_struct(&fs_info->subvol_srcu);
        if (ret) {
@@ -1658,10 +1614,12 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        INIT_LIST_HEAD(&fs_info->ordered_operations);
        INIT_LIST_HEAD(&fs_info->caching_block_groups);
        spin_lock_init(&fs_info->delalloc_lock);
-       spin_lock_init(&fs_info->new_trans_lock);
+       spin_lock_init(&fs_info->trans_lock);
        spin_lock_init(&fs_info->ref_cache_lock);
        spin_lock_init(&fs_info->fs_roots_radix_lock);
        spin_lock_init(&fs_info->delayed_iput_lock);
+       spin_lock_init(&fs_info->defrag_inodes_lock);
+       mutex_init(&fs_info->reloc_mutex);
 
        init_completion(&fs_info->kobj_unregister);
        fs_info->tree_root = tree_root;
@@ -1684,15 +1642,34 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        atomic_set(&fs_info->async_delalloc_pages, 0);
        atomic_set(&fs_info->async_submit_draining, 0);
        atomic_set(&fs_info->nr_async_bios, 0);
+       atomic_set(&fs_info->defrag_running, 0);
        fs_info->sb = sb;
        fs_info->max_inline = 8192 * 1024;
        fs_info->metadata_ratio = 0;
+       fs_info->defrag_inodes = RB_ROOT;
+       fs_info->trans_no_join = 0;
 
        fs_info->thread_pool_size = min_t(unsigned long,
                                          num_online_cpus() + 2, 8);
 
        INIT_LIST_HEAD(&fs_info->ordered_extents);
        spin_lock_init(&fs_info->ordered_extent_lock);
+       fs_info->delayed_root = kmalloc(sizeof(struct btrfs_delayed_root),
+                                       GFP_NOFS);
+       if (!fs_info->delayed_root) {
+               err = -ENOMEM;
+               goto fail_iput;
+       }
+       btrfs_init_delayed_root(fs_info->delayed_root);
+
+       mutex_init(&fs_info->scrub_lock);
+       atomic_set(&fs_info->scrubs_running, 0);
+       atomic_set(&fs_info->scrub_pause_req, 0);
+       atomic_set(&fs_info->scrubs_paused, 0);
+       atomic_set(&fs_info->scrub_cancel_req, 0);
+       init_waitqueue_head(&fs_info->scrub_pause_wait);
+       init_rwsem(&fs_info->scrub_super_lock);
+       fs_info->scrub_workers_refcnt = 0;
 
        sb->s_blocksize = 4096;
        sb->s_blocksize_bits = blksize_bits(4096);
@@ -1711,10 +1688,8 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 
        RB_CLEAR_NODE(&BTRFS_I(fs_info->btree_inode)->rb_node);
        extent_io_tree_init(&BTRFS_I(fs_info->btree_inode)->io_tree,
-                            fs_info->btree_inode->i_mapping,
-                            GFP_NOFS);
-       extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree,
-                            GFP_NOFS);
+                            fs_info->btree_inode->i_mapping);
+       extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree);
 
        BTRFS_I(fs_info->btree_inode)->io_tree.ops = &btree_extent_io_ops;
 
@@ -1728,14 +1703,13 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        fs_info->block_group_cache_tree = RB_ROOT;
 
        extent_io_tree_init(&fs_info->freed_extents[0],
-                            fs_info->btree_inode->i_mapping, GFP_NOFS);
+                            fs_info->btree_inode->i_mapping);
        extent_io_tree_init(&fs_info->freed_extents[1],
-                            fs_info->btree_inode->i_mapping, GFP_NOFS);
+                            fs_info->btree_inode->i_mapping);
        fs_info->pinned_extents = &fs_info->freed_extents[0];
        fs_info->do_barriers = 1;
 
 
-       mutex_init(&fs_info->trans_mutex);
        mutex_init(&fs_info->ordered_operations_mutex);
        mutex_init(&fs_info->tree_log_mutex);
        mutex_init(&fs_info->chunk_mutex);
@@ -1760,7 +1734,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        bh = btrfs_read_dev_super(fs_devices->latest_bdev);
        if (!bh) {
                err = -EINVAL;
-               goto fail_iput;
+               goto fail_alloc;
        }
 
        memcpy(&fs_info->super_copy, bh->b_data, sizeof(fs_info->super_copy));
@@ -1772,7 +1746,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 
        disk_super = &fs_info->super_copy;
        if (!btrfs_super_root(disk_super))
-               goto fail_iput;
+               goto fail_alloc;
 
        /* check FS state, whether FS is broken. */
        fs_info->fs_state |= btrfs_super_flags(disk_super);
@@ -1788,7 +1762,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        ret = btrfs_parse_options(tree_root, options);
        if (ret) {
                err = ret;
-               goto fail_iput;
+               goto fail_alloc;
        }
 
        features = btrfs_super_incompat_flags(disk_super) &
@@ -1798,7 +1772,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
                       "unsupported optional features (%Lx).\n",
                       (unsigned long long)features);
                err = -EINVAL;
-               goto fail_iput;
+               goto fail_alloc;
        }
 
        features = btrfs_super_incompat_flags(disk_super);
@@ -1814,7 +1788,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
                       "unsupported option features (%Lx).\n",
                       (unsigned long long)features);
                err = -EINVAL;
-               goto fail_iput;
+               goto fail_alloc;
        }
 
        btrfs_init_workers(&fs_info->generic_worker,
@@ -1861,6 +1835,9 @@ struct btrfs_root *open_ctree(struct super_block *sb,
                           &fs_info->generic_worker);
        btrfs_init_workers(&fs_info->endio_freespace_worker, "freespace-write",
                           1, &fs_info->generic_worker);
+       btrfs_init_workers(&fs_info->delayed_workers, "delayed-meta",
+                          fs_info->thread_pool_size,
+                          &fs_info->generic_worker);
 
        /*
         * endios are largely parallel and should have a very
@@ -1882,6 +1859,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        btrfs_start_workers(&fs_info->endio_meta_write_workers, 1);
        btrfs_start_workers(&fs_info->endio_write_workers, 1);
        btrfs_start_workers(&fs_info->endio_freespace_worker, 1);
+       btrfs_start_workers(&fs_info->delayed_workers, 1);
 
        fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super);
        fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages,
@@ -2138,6 +2116,9 @@ fail_sb_buffer:
        btrfs_stop_workers(&fs_info->endio_write_workers);
        btrfs_stop_workers(&fs_info->endio_freespace_worker);
        btrfs_stop_workers(&fs_info->submit_workers);
+       btrfs_stop_workers(&fs_info->delayed_workers);
+fail_alloc:
+       kfree(fs_info->delayed_root);
 fail_iput:
        invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
        iput(fs_info->btree_inode);
@@ -2165,11 +2146,9 @@ static void btrfs_end_buffer_write_sync(struct buffer_head *bh, int uptodate)
        if (uptodate) {
                set_buffer_uptodate(bh);
        } else {
-               if (printk_ratelimit()) {
-                       printk(KERN_WARNING "lost page write due to "
+               printk_ratelimited(KERN_WARNING "lost page write due to "
                                        "I/O error on %s\n",
                                       bdevname(bh->b_bdev, b));
-               }
                /* note, we dont' set_buffer_write_io_error because we have
                 * our own ways of dealing with the IO errors
                 */
@@ -2333,7 +2312,7 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors)
 
        mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
        head = &root->fs_info->fs_devices->devices;
-       list_for_each_entry(dev, head, dev_list) {
+       list_for_each_entry_rcu(dev, head, dev_list) {
                if (!dev->bdev) {
                        total_errors++;
                        continue;
@@ -2366,7 +2345,7 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors)
        }
 
        total_errors = 0;
-       list_for_each_entry(dev, head, dev_list) {
+       list_for_each_entry_rcu(dev, head, dev_list) {
                if (!dev->bdev)
                        continue;
                if (!dev->in_fs_metadata || !dev->writeable)
@@ -2404,12 +2383,15 @@ int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
        if (btrfs_root_refs(&root->root_item) == 0)
                synchronize_srcu(&fs_info->subvol_srcu);
 
+       __btrfs_remove_free_space_cache(root->free_ino_pinned);
+       __btrfs_remove_free_space_cache(root->free_ino_ctl);
        free_fs_root(root);
        return 0;
 }
 
 static void free_fs_root(struct btrfs_root *root)
 {
+       iput(root->cache_inode);
        WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree));
        if (root->anon_super.s_dev) {
                down_write(&root->anon_super.s_umount);
@@ -2417,6 +2399,8 @@ static void free_fs_root(struct btrfs_root *root)
        }
        free_extent_buffer(root->node);
        free_extent_buffer(root->commit_root);
+       kfree(root->free_ino_ctl);
+       kfree(root->free_ino_pinned);
        kfree(root->name);
        kfree(root);
 }
@@ -2495,13 +2479,13 @@ int btrfs_commit_super(struct btrfs_root *root)
        down_write(&root->fs_info->cleanup_work_sem);
        up_write(&root->fs_info->cleanup_work_sem);
 
-       trans = btrfs_join_transaction(root, 1);
+       trans = btrfs_join_transaction(root);
        if (IS_ERR(trans))
                return PTR_ERR(trans);
        ret = btrfs_commit_transaction(trans, root);
        BUG_ON(ret);
        /* run commit again to drop the original snapshot */
-       trans = btrfs_join_transaction(root, 1);
+       trans = btrfs_join_transaction(root);
        if (IS_ERR(trans))
                return PTR_ERR(trans);
        btrfs_commit_transaction(trans, root);
@@ -2520,6 +2504,15 @@ int close_ctree(struct btrfs_root *root)
        fs_info->closing = 1;
        smp_mb();
 
+       btrfs_scrub_cancel(root);
+
+       /* wait for any defraggers to finish */
+       wait_event(fs_info->transaction_wait,
+                  (atomic_read(&fs_info->defrag_running) == 0));
+
+       /* clear out the rbtree of defraggable inodes */
+       btrfs_run_defrag_inodes(root->fs_info);
+
        btrfs_put_block_group_cache(fs_info);
 
        /*
@@ -2578,6 +2571,7 @@ int close_ctree(struct btrfs_root *root)
        del_fs_roots(fs_info);
 
        iput(fs_info->btree_inode);
+       kfree(fs_info->delayed_root);
 
        btrfs_stop_workers(&fs_info->generic_worker);
        btrfs_stop_workers(&fs_info->fixup_workers);
@@ -2589,6 +2583,7 @@ int close_ctree(struct btrfs_root *root)
        btrfs_stop_workers(&fs_info->endio_write_workers);
        btrfs_stop_workers(&fs_info->endio_freespace_worker);
        btrfs_stop_workers(&fs_info->submit_workers);
+       btrfs_stop_workers(&fs_info->delayed_workers);
 
        btrfs_close_devices(fs_info->fs_devices);
        btrfs_mapping_tree_free(&fs_info->mapping_tree);
@@ -2662,6 +2657,29 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
        u64 num_dirty;
        unsigned long thresh = 32 * 1024 * 1024;
 
+       if (current->flags & PF_MEMALLOC)
+               return;
+
+       btrfs_balance_delayed_items(root);
+
+       num_dirty = root->fs_info->dirty_metadata_bytes;
+
+       if (num_dirty > thresh) {
+               balance_dirty_pages_ratelimited_nr(
+                                  root->fs_info->btree_inode->i_mapping, 1);
+       }
+       return;
+}
+
+void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
+{
+       /*
+        * looks as though older kernels can get into trouble with
+        * this code, they end up stuck in balance_dirty_pages forever
+        */
+       u64 num_dirty;
+       unsigned long thresh = 32 * 1024 * 1024;
+
        if (current->flags & PF_MEMALLOC)
                return;
 
@@ -2697,7 +2715,7 @@ int btree_lock_page_hook(struct page *page)
                goto out;
 
        len = page->private >> 2;
-       eb = find_extent_buffer(io_tree, bytenr, len, GFP_NOFS);
+       eb = find_extent_buffer(io_tree, bytenr, len);
        if (!eb)
                goto out;
 
@@ -2893,9 +2911,8 @@ static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
 
        INIT_LIST_HEAD(&splice);
 
-       list_splice_init(&root->fs_info->delalloc_inodes, &splice);
-
        spin_lock(&root->fs_info->delalloc_lock);
+       list_splice_init(&root->fs_info->delalloc_inodes, &splice);
 
        while (!list_empty(&splice)) {
                btrfs_inode = list_entry(splice.next, struct btrfs_inode,
@@ -3006,10 +3023,13 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root)
 
        WARN_ON(1);
 
-       mutex_lock(&root->fs_info->trans_mutex);
        mutex_lock(&root->fs_info->transaction_kthread_mutex);
 
+       spin_lock(&root->fs_info->trans_lock);
        list_splice_init(&root->fs_info->trans_list, &list);
+       root->fs_info->trans_no_join = 1;
+       spin_unlock(&root->fs_info->trans_lock);
+
        while (!list_empty(&list)) {
                t = list_entry(list.next, struct btrfs_transaction, list);
                if (!t)
@@ -3034,23 +3054,18 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root)
                t->blocked = 0;
                if (waitqueue_active(&root->fs_info->transaction_wait))
                        wake_up(&root->fs_info->transaction_wait);
-               mutex_unlock(&root->fs_info->trans_mutex);
 
-               mutex_lock(&root->fs_info->trans_mutex);
                t->commit_done = 1;
                if (waitqueue_active(&t->commit_wait))
                        wake_up(&t->commit_wait);
-               mutex_unlock(&root->fs_info->trans_mutex);
-
-               mutex_lock(&root->fs_info->trans_mutex);
 
                btrfs_destroy_pending_snapshots(t);
 
                btrfs_destroy_delalloc_inodes(root);
 
-               spin_lock(&root->fs_info->new_trans_lock);
+               spin_lock(&root->fs_info->trans_lock);
                root->fs_info->running_transaction = NULL;
-               spin_unlock(&root->fs_info->new_trans_lock);
+               spin_unlock(&root->fs_info->trans_lock);
 
                btrfs_destroy_marked_extents(root, &t->dirty_pages,
                                             EXTENT_DIRTY);
@@ -3064,8 +3079,10 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root)
                kmem_cache_free(btrfs_transaction_cachep, t);
        }
 
+       spin_lock(&root->fs_info->trans_lock);
+       root->fs_info->trans_no_join = 0;
+       spin_unlock(&root->fs_info->trans_lock);
        mutex_unlock(&root->fs_info->transaction_kthread_mutex);
-       mutex_unlock(&root->fs_info->trans_mutex);
 
        return 0;
 }
index 07b20dc2fd9560c0f497ecc3615cf8da747c4688..a0b610a67aaeadf1f564d03e218305997c021a85 100644 (file)
@@ -55,35 +55,20 @@ int btrfs_commit_super(struct btrfs_root *root);
 int btrfs_error_commit_super(struct btrfs_root *root);
 struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
                                            u64 bytenr, u32 blocksize);
-struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
-                                       u64 root_objectid);
-struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
-                                     struct btrfs_key *location,
-                                     const char *name, int namelen);
 struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
                                               struct btrfs_key *location);
 struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
                                              struct btrfs_key *location);
 int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info);
-int btrfs_insert_dev_radix(struct btrfs_root *root,
-                          struct block_device *bdev,
-                          u64 device_id,
-                          u64 block_start,
-                          u64 num_blocks);
 void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
+void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
 int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
 void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
-void btrfs_mark_buffer_dirty_nonblocking(struct extent_buffer *buf);
 int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid);
 int btrfs_set_buffer_uptodate(struct extent_buffer *buf);
-int wait_on_tree_block_writeback(struct btrfs_root *root,
-                                struct extent_buffer *buf);
 int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid);
 u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len);
 void btrfs_csum_final(u32 crc, char *result);
-int btrfs_open_device(struct btrfs_device *dev);
-int btrfs_verify_block_csum(struct btrfs_root *root,
-                           struct extent_buffer *buf);
 int btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio,
                        int metadata);
 int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode,
@@ -91,8 +76,6 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode,
                        unsigned long bio_flags, u64 bio_offset,
                        extent_submit_bio_hook_t *submit_bio_start,
                        extent_submit_bio_hook_t *submit_bio_done);
-
-int btrfs_congested_async(struct btrfs_fs_info *info, int iodone);
 unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info);
 int btrfs_write_tree_block(struct extent_buffer *buf);
 int btrfs_wait_tree_block_writeback(struct extent_buffer *buf);
index b4ffad859adb31a5ad5d8628a1fd6a10adae06ec..1b8dc33778f9c411206cc6ad9467546412431947 100644 (file)
@@ -32,7 +32,7 @@ static int btrfs_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
        len  = BTRFS_FID_SIZE_NON_CONNECTABLE;
        type = FILEID_BTRFS_WITHOUT_PARENT;
 
-       fid->objectid = inode->i_ino;
+       fid->objectid = btrfs_ino(inode);
        fid->root_objectid = BTRFS_I(inode)->root->objectid;
        fid->gen = inode->i_generation;
 
@@ -178,13 +178,13 @@ static struct dentry *btrfs_get_parent(struct dentry *child)
        if (!path)
                return ERR_PTR(-ENOMEM);
 
-       if (dir->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
+       if (btrfs_ino(dir) == BTRFS_FIRST_FREE_OBJECTID) {
                key.objectid = root->root_key.objectid;
                key.type = BTRFS_ROOT_BACKREF_KEY;
                key.offset = (u64)-1;
                root = root->fs_info->tree_root;
        } else {
-               key.objectid = dir->i_ino;
+               key.objectid = btrfs_ino(dir);
                key.type = BTRFS_INODE_REF_KEY;
                key.offset = (u64)-1;
        }
@@ -244,6 +244,7 @@ static int btrfs_get_name(struct dentry *parent, char *name,
        struct btrfs_key key;
        int name_len;
        int ret;
+       u64 ino;
 
        if (!dir || !inode)
                return -EINVAL;
@@ -251,19 +252,21 @@ static int btrfs_get_name(struct dentry *parent, char *name,
        if (!S_ISDIR(dir->i_mode))
                return -EINVAL;
 
+       ino = btrfs_ino(inode);
+
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
        path->leave_spinning = 1;
 
-       if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
+       if (ino == BTRFS_FIRST_FREE_OBJECTID) {
                key.objectid = BTRFS_I(inode)->root->root_key.objectid;
                key.type = BTRFS_ROOT_BACKREF_KEY;
                key.offset = (u64)-1;
                root = root->fs_info->tree_root;
        } else {
-               key.objectid = inode->i_ino;
-               key.offset = dir->i_ino;
+               key.objectid = ino;
+               key.offset = btrfs_ino(dir);
                key.type = BTRFS_INODE_REF_KEY;
        }
 
@@ -272,7 +275,7 @@ static int btrfs_get_name(struct dentry *parent, char *name,
                btrfs_free_path(path);
                return ret;
        } else if (ret > 0) {
-               if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
+               if (ino == BTRFS_FIRST_FREE_OBJECTID) {
                        path->slots[0]--;
                } else {
                        btrfs_free_path(path);
@@ -281,11 +284,11 @@ static int btrfs_get_name(struct dentry *parent, char *name,
        }
        leaf = path->nodes[0];
 
-       if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
-              rref = btrfs_item_ptr(leaf, path->slots[0],
+       if (ino == BTRFS_FIRST_FREE_OBJECTID) {
+               rref = btrfs_item_ptr(leaf, path->slots[0],
                                     struct btrfs_root_ref);
-              name_ptr = (unsigned long)(rref + 1);
-              name_len = btrfs_root_ref_name_len(leaf, rref);
+               name_ptr = (unsigned long)(rref + 1);
+               name_len = btrfs_root_ref_name_len(leaf, rref);
        } else {
                iref = btrfs_item_ptr(leaf, path->slots[0],
                                      struct btrfs_inode_ref);
index 9ee6bd55e16c5ea4cc9e2f1e31289ba6591730b1..1f61bf5b4960404b063ddc4ab0587970687321d0 100644 (file)
@@ -94,7 +94,7 @@ static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits)
        return (cache->flags & bits) == bits;
 }
 
-void btrfs_get_block_group(struct btrfs_block_group_cache *cache)
+static void btrfs_get_block_group(struct btrfs_block_group_cache *cache)
 {
        atomic_inc(&cache->count);
 }
@@ -105,6 +105,7 @@ void btrfs_put_block_group(struct btrfs_block_group_cache *cache)
                WARN_ON(cache->pinned > 0);
                WARN_ON(cache->reserved > 0);
                WARN_ON(cache->reserved_pinned > 0);
+               kfree(cache->free_space_ctl);
                kfree(cache);
        }
 }
@@ -347,7 +348,7 @@ static int caching_kthread(void *data)
         */
        path->skip_locking = 1;
        path->search_commit_root = 1;
-       path->reada = 2;
+       path->reada = 1;
 
        key.objectid = last;
        key.offset = 0;
@@ -365,8 +366,7 @@ again:
        nritems = btrfs_header_nritems(leaf);
 
        while (1) {
-               smp_mb();
-               if (fs_info->closing > 1) {
+               if (btrfs_fs_closing(fs_info) > 1) {
                        last = (u64)-1;
                        break;
                }
@@ -378,15 +378,18 @@ again:
                        if (ret)
                                break;
 
-                       caching_ctl->progress = last;
-                       btrfs_release_path(extent_root, path);
-                       up_read(&fs_info->extent_commit_sem);
-                       mutex_unlock(&caching_ctl->mutex);
-                       if (btrfs_transaction_in_commit(fs_info))
-                               schedule_timeout(1);
-                       else
+                       if (need_resched() ||
+                           btrfs_next_leaf(extent_root, path)) {
+                               caching_ctl->progress = last;
+                               btrfs_release_path(path);
+                               up_read(&fs_info->extent_commit_sem);
+                               mutex_unlock(&caching_ctl->mutex);
                                cond_resched();
-                       goto again;
+                               goto again;
+                       }
+                       leaf = path->nodes[0];
+                       nritems = btrfs_header_nritems(leaf);
+                       continue;
                }
 
                if (key.objectid < block_group->key.objectid) {
@@ -754,8 +757,12 @@ again:
                        atomic_inc(&head->node.refs);
                        spin_unlock(&delayed_refs->lock);
 
-                       btrfs_release_path(root->fs_info->extent_root, path);
+                       btrfs_release_path(path);
 
+                       /*
+                        * Mutex was contended, block until it's released and try
+                        * again
+                        */
                        mutex_lock(&head->mutex);
                        mutex_unlock(&head->mutex);
                        btrfs_put_delayed_ref(&head->node);
@@ -934,7 +941,7 @@ static int convert_extent_item_v0(struct btrfs_trans_handle *trans,
                        break;
                }
        }
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        if (owner < BTRFS_FIRST_FREE_OBJECTID)
                new_size += sizeof(*bi);
@@ -947,7 +954,6 @@ static int convert_extent_item_v0(struct btrfs_trans_handle *trans,
        BUG_ON(ret);
 
        ret = btrfs_extend_item(trans, root, path, new_size);
-       BUG_ON(ret);
 
        leaf = path->nodes[0];
        item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
@@ -1042,7 +1048,7 @@ again:
                        return 0;
 #ifdef BTRFS_COMPAT_EXTENT_TREE_V0
                key.type = BTRFS_EXTENT_REF_V0_KEY;
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
                if (ret < 0) {
                        err = ret;
@@ -1080,7 +1086,7 @@ again:
                if (match_extent_data_ref(leaf, ref, root_objectid,
                                          owner, offset)) {
                        if (recow) {
-                               btrfs_release_path(root, path);
+                               btrfs_release_path(path);
                                goto again;
                        }
                        err = 0;
@@ -1141,7 +1147,7 @@ static noinline int insert_extent_data_ref(struct btrfs_trans_handle *trans,
                        if (match_extent_data_ref(leaf, ref, root_objectid,
                                                  owner, offset))
                                break;
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        key.offset++;
                        ret = btrfs_insert_empty_item(trans, root, path, &key,
                                                      size);
@@ -1167,7 +1173,7 @@ static noinline int insert_extent_data_ref(struct btrfs_trans_handle *trans,
        btrfs_mark_buffer_dirty(leaf);
        ret = 0;
 fail:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        return ret;
 }
 
@@ -1293,7 +1299,7 @@ static noinline int lookup_tree_block_ref(struct btrfs_trans_handle *trans,
                ret = -ENOENT;
 #ifdef BTRFS_COMPAT_EXTENT_TREE_V0
        if (ret == -ENOENT && parent) {
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                key.type = BTRFS_EXTENT_REF_V0_KEY;
                ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
                if (ret > 0)
@@ -1322,7 +1328,7 @@ static noinline int insert_tree_block_ref(struct btrfs_trans_handle *trans,
        }
 
        ret = btrfs_insert_empty_item(trans, root, path, &key, 0);
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        return ret;
 }
 
@@ -1555,7 +1561,6 @@ int setup_inline_extent_backref(struct btrfs_trans_handle *trans,
        size = btrfs_extent_inline_ref_size(type);
 
        ret = btrfs_extend_item(trans, root, path, size);
-       BUG_ON(ret);
 
        ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
        refs = btrfs_extent_refs(leaf, ei);
@@ -1608,7 +1613,7 @@ static int lookup_extent_backref(struct btrfs_trans_handle *trans,
        if (ret != -ENOENT)
                return ret;
 
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        *ref_ret = NULL;
 
        if (owner < BTRFS_FIRST_FREE_OBJECTID) {
@@ -1684,7 +1689,6 @@ int update_inline_extent_backref(struct btrfs_trans_handle *trans,
                                              end - ptr - size);
                item_size -= size;
                ret = btrfs_truncate_item(trans, root, path, item_size, 1);
-               BUG_ON(ret);
        }
        btrfs_mark_buffer_dirty(leaf);
        return 0;
@@ -1862,7 +1866,7 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                __run_delayed_extent_op(extent_op, leaf, item);
 
        btrfs_mark_buffer_dirty(leaf);
-       btrfs_release_path(root->fs_info->extent_root, path);
+       btrfs_release_path(path);
 
        path->reada = 1;
        path->leave_spinning = 1;
@@ -2297,6 +2301,10 @@ again:
                                atomic_inc(&ref->refs);
 
                                spin_unlock(&delayed_refs->lock);
+                               /*
+                                * Mutex was contended, block until it's
+                                * released and try again
+                                */
                                mutex_lock(&head->mutex);
                                mutex_unlock(&head->mutex);
 
@@ -2361,8 +2369,12 @@ static noinline int check_delayed_ref(struct btrfs_trans_handle *trans,
                atomic_inc(&head->node.refs);
                spin_unlock(&delayed_refs->lock);
 
-               btrfs_release_path(root->fs_info->extent_root, path);
+               btrfs_release_path(path);
 
+               /*
+                * Mutex was contended, block until it's released and let
+                * caller try again
+                */
                mutex_lock(&head->mutex);
                mutex_unlock(&head->mutex);
                btrfs_put_delayed_ref(&head->node);
@@ -2510,126 +2522,6 @@ out:
        return ret;
 }
 
-#if 0
-int btrfs_cache_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                   struct extent_buffer *buf, u32 nr_extents)
-{
-       struct btrfs_key key;
-       struct btrfs_file_extent_item *fi;
-       u64 root_gen;
-       u32 nritems;
-       int i;
-       int level;
-       int ret = 0;
-       int shared = 0;
-
-       if (!root->ref_cows)
-               return 0;
-
-       if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) {
-               shared = 0;
-               root_gen = root->root_key.offset;
-       } else {
-               shared = 1;
-               root_gen = trans->transid - 1;
-       }
-
-       level = btrfs_header_level(buf);
-       nritems = btrfs_header_nritems(buf);
-
-       if (level == 0) {
-               struct btrfs_leaf_ref *ref;
-               struct btrfs_extent_info *info;
-
-               ref = btrfs_alloc_leaf_ref(root, nr_extents);
-               if (!ref) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-
-               ref->root_gen = root_gen;
-               ref->bytenr = buf->start;
-               ref->owner = btrfs_header_owner(buf);
-               ref->generation = btrfs_header_generation(buf);
-               ref->nritems = nr_extents;
-               info = ref->extents;
-
-               for (i = 0; nr_extents > 0 && i < nritems; i++) {
-                       u64 disk_bytenr;
-                       btrfs_item_key_to_cpu(buf, &key, i);
-                       if (btrfs_key_type(&key) != BTRFS_EXTENT_DATA_KEY)
-                               continue;
-                       fi = btrfs_item_ptr(buf, i,
-                                           struct btrfs_file_extent_item);
-                       if (btrfs_file_extent_type(buf, fi) ==
-                           BTRFS_FILE_EXTENT_INLINE)
-                               continue;
-                       disk_bytenr = btrfs_file_extent_disk_bytenr(buf, fi);
-                       if (disk_bytenr == 0)
-                               continue;
-
-                       info->bytenr = disk_bytenr;
-                       info->num_bytes =
-                               btrfs_file_extent_disk_num_bytes(buf, fi);
-                       info->objectid = key.objectid;
-                       info->offset = key.offset;
-                       info++;
-               }
-
-               ret = btrfs_add_leaf_ref(root, ref, shared);
-               if (ret == -EEXIST && shared) {
-                       struct btrfs_leaf_ref *old;
-                       old = btrfs_lookup_leaf_ref(root, ref->bytenr);
-                       BUG_ON(!old);
-                       btrfs_remove_leaf_ref(root, old);
-                       btrfs_free_leaf_ref(root, old);
-                       ret = btrfs_add_leaf_ref(root, ref, shared);
-               }
-               WARN_ON(ret);
-               btrfs_free_leaf_ref(root, ref);
-       }
-out:
-       return ret;
-}
-
-/* when a block goes through cow, we update the reference counts of
- * everything that block points to.  The internal pointers of the block
- * can be in just about any order, and it is likely to have clusters of
- * things that are close together and clusters of things that are not.
- *
- * To help reduce the seeks that come with updating all of these reference
- * counts, sort them by byte number before actual updates are done.
- *
- * struct refsort is used to match byte number to slot in the btree block.
- * we sort based on the byte number and then use the slot to actually
- * find the item.
- *
- * struct refsort is smaller than strcut btrfs_item and smaller than
- * struct btrfs_key_ptr.  Since we're currently limited to the page size
- * for a btree block, there's no way for a kmalloc of refsorts for a
- * single node to be bigger than a page.
- */
-struct refsort {
-       u64 bytenr;
-       u32 slot;
-};
-
-/*
- * for passing into sort()
- */
-static int refsort_cmp(const void *a_void, const void *b_void)
-{
-       const struct refsort *a = a_void;
-       const struct refsort *b = b_void;
-
-       if (a->bytenr < b->bytenr)
-               return -1;
-       if (a->bytenr > b->bytenr)
-               return 1;
-       return 0;
-}
-#endif
-
 static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root,
                           struct extent_buffer *buf,
@@ -2732,7 +2624,7 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
        bi = btrfs_item_ptr_offset(leaf, path->slots[0]);
        write_extent_buffer(leaf, &cache->item, bi, sizeof(cache->item));
        btrfs_mark_buffer_dirty(leaf);
-       btrfs_release_path(extent_root, path);
+       btrfs_release_path(path);
 fail:
        if (ret)
                return ret;
@@ -2785,7 +2677,7 @@ again:
        inode = lookup_free_space_inode(root, block_group, path);
        if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {
                ret = PTR_ERR(inode);
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                goto out;
        }
 
@@ -2854,7 +2746,7 @@ again:
 out_put:
        iput(inode);
 out_free:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 out:
        spin_lock(&block_group->lock);
        block_group->disk_cache_state = dcs;
@@ -3144,7 +3036,8 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes)
        /* make sure bytes are sectorsize aligned */
        bytes = (bytes + root->sectorsize - 1) & ~((u64)root->sectorsize - 1);
 
-       if (root == root->fs_info->tree_root) {
+       if (root == root->fs_info->tree_root ||
+           BTRFS_I(inode)->location.objectid == BTRFS_FREE_INO_OBJECTID) {
                alloc_chunk = 0;
                committed = 1;
        }
@@ -3174,7 +3067,7 @@ again:
                        spin_unlock(&data_sinfo->lock);
 alloc:
                        alloc_target = btrfs_get_alloc_profile(root, 1);
-                       trans = btrfs_join_transaction(root, 1);
+                       trans = btrfs_join_transaction(root);
                        if (IS_ERR(trans))
                                return PTR_ERR(trans);
 
@@ -3196,13 +3089,21 @@ alloc:
                        }
                        goto again;
                }
+
+               /*
+                * If we have less pinned bytes than we want to allocate then
+                * don't bother committing the transaction, it won't help us.
+                */
+               if (data_sinfo->bytes_pinned < bytes)
+                       committed = 1;
                spin_unlock(&data_sinfo->lock);
 
                /* commit the current transaction and try again */
 commit_trans:
-               if (!committed && !root->fs_info->open_ioctl_trans) {
+               if (!committed &&
+                   !atomic_read(&root->fs_info->open_ioctl_trans)) {
                        committed = 1;
-                       trans = btrfs_join_transaction(root, 1);
+                       trans = btrfs_join_transaction(root);
                        if (IS_ERR(trans))
                                return PTR_ERR(trans);
                        ret = btrfs_commit_transaction(trans, root);
@@ -3211,18 +3112,6 @@ commit_trans:
                        goto again;
                }
 
-#if 0 /* I hope we never need this code again, just in case */
-               printk(KERN_ERR "no space left, need %llu, %llu bytes_used, "
-                      "%llu bytes_reserved, " "%llu bytes_pinned, "
-                      "%llu bytes_readonly, %llu may use %llu total\n",
-                      (unsigned long long)bytes,
-                      (unsigned long long)data_sinfo->bytes_used,
-                      (unsigned long long)data_sinfo->bytes_reserved,
-                      (unsigned long long)data_sinfo->bytes_pinned,
-                      (unsigned long long)data_sinfo->bytes_readonly,
-                      (unsigned long long)data_sinfo->bytes_may_use,
-                      (unsigned long long)data_sinfo->total_bytes);
-#endif
                return -ENOSPC;
        }
        data_sinfo->bytes_may_use += bytes;
@@ -3589,7 +3478,7 @@ again:
                goto out;
 
        ret = -ENOSPC;
-       trans = btrfs_join_transaction(root, 1);
+       trans = btrfs_join_transaction(root);
        if (IS_ERR(trans))
                goto out;
        ret = btrfs_commit_transaction(trans, root);
@@ -3651,8 +3540,8 @@ static void block_rsv_add_bytes(struct btrfs_block_rsv *block_rsv,
        spin_unlock(&block_rsv->lock);
 }
 
-void block_rsv_release_bytes(struct btrfs_block_rsv *block_rsv,
-                            struct btrfs_block_rsv *dest, u64 num_bytes)
+static void block_rsv_release_bytes(struct btrfs_block_rsv *block_rsv,
+                                   struct btrfs_block_rsv *dest, u64 num_bytes)
 {
        struct btrfs_space_info *space_info = block_rsv->space_info;
 
@@ -3816,7 +3705,7 @@ int btrfs_block_rsv_check(struct btrfs_trans_handle *trans,
                if (trans)
                        return -EAGAIN;
 
-               trans = btrfs_join_transaction(root, 1);
+               trans = btrfs_join_transaction(root);
                BUG_ON(IS_ERR(trans));
                ret = btrfs_commit_transaction(trans, root);
                return 0;
@@ -3855,23 +3744,7 @@ static u64 calc_global_metadata_size(struct btrfs_fs_info *fs_info)
        u64 meta_used;
        u64 data_used;
        int csum_size = btrfs_super_csum_size(&fs_info->super_copy);
-#if 0
-       /*
-        * per tree used space accounting can be inaccuracy, so we
-        * can't rely on it.
-        */
-       spin_lock(&fs_info->extent_root->accounting_lock);
-       num_bytes = btrfs_root_used(&fs_info->extent_root->root_item);
-       spin_unlock(&fs_info->extent_root->accounting_lock);
 
-       spin_lock(&fs_info->csum_root->accounting_lock);
-       num_bytes += btrfs_root_used(&fs_info->csum_root->root_item);
-       spin_unlock(&fs_info->csum_root->accounting_lock);
-
-       spin_lock(&fs_info->tree_root->accounting_lock);
-       num_bytes += btrfs_root_used(&fs_info->tree_root->root_item);
-       spin_unlock(&fs_info->tree_root->accounting_lock);
-#endif
        sinfo = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_DATA);
        spin_lock(&sinfo->lock);
        data_used = sinfo->bytes_used;
@@ -3924,10 +3797,7 @@ static void update_global_block_rsv(struct btrfs_fs_info *fs_info)
                block_rsv->reserved = block_rsv->size;
                block_rsv->full = 1;
        }
-#if 0
-       printk(KERN_INFO"global block rsv size %llu reserved %llu\n",
-               block_rsv->size, block_rsv->reserved);
-#endif
+
        spin_unlock(&sinfo->lock);
        spin_unlock(&block_rsv->lock);
 }
@@ -3973,10 +3843,35 @@ static void release_global_block_rsv(struct btrfs_fs_info *fs_info)
        WARN_ON(fs_info->chunk_block_rsv.reserved > 0);
 }
 
-static u64 calc_trans_metadata_size(struct btrfs_root *root, int num_items)
+int btrfs_truncate_reserve_metadata(struct btrfs_trans_handle *trans,
+                                   struct btrfs_root *root,
+                                   struct btrfs_block_rsv *rsv)
 {
-       return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
-               3 * num_items;
+       struct btrfs_block_rsv *trans_rsv = &root->fs_info->trans_block_rsv;
+       u64 num_bytes;
+       int ret;
+
+       /*
+        * Truncate should be freeing data, but give us 2 items just in case it
+        * needs to use some space.  We may want to be smarter about this in the
+        * future.
+        */
+       num_bytes = btrfs_calc_trans_metadata_size(root, 2);
+
+       /* We already have enough bytes, just return */
+       if (rsv->reserved >= num_bytes)
+               return 0;
+
+       num_bytes -= rsv->reserved;
+
+       /*
+        * You should have reserved enough space before hand to do this, so this
+        * should not fail.
+        */
+       ret = block_rsv_migrate_bytes(trans_rsv, rsv, num_bytes);
+       BUG_ON(ret);
+
+       return 0;
 }
 
 int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
@@ -3989,7 +3884,7 @@ int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
        if (num_items == 0 || root->fs_info->chunk_root == root)
                return 0;
 
-       num_bytes = calc_trans_metadata_size(root, num_items);
+       num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
        ret = btrfs_block_rsv_add(trans, root, &root->fs_info->trans_block_rsv,
                                  num_bytes);
        if (!ret) {
@@ -4019,23 +3914,18 @@ int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
        struct btrfs_block_rsv *dst_rsv = root->orphan_block_rsv;
 
        /*
-        * one for deleting orphan item, one for updating inode and
-        * two for calling btrfs_truncate_inode_items.
-        *
-        * btrfs_truncate_inode_items is a delete operation, it frees
-        * more space than it uses in most cases. So two units of
-        * metadata space should be enough for calling it many times.
-        * If all of the metadata space is used, we can commit
-        * transaction and use space it freed.
+        * We need to hold space in order to delete our orphan item once we've
+        * added it, so this takes the reservation so we can release it later
+        * when we are truly done with the orphan item.
         */
-       u64 num_bytes = calc_trans_metadata_size(root, 4);
+       u64 num_bytes = btrfs_calc_trans_metadata_size(root, 1);
        return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
 }
 
 void btrfs_orphan_release_metadata(struct inode *inode)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
-       u64 num_bytes = calc_trans_metadata_size(root, 4);
+       u64 num_bytes = btrfs_calc_trans_metadata_size(root, 1);
        btrfs_block_rsv_release(root, root->orphan_block_rsv, num_bytes);
 }
 
@@ -4049,7 +3939,7 @@ int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans,
         * two for root back/forward refs, two for directory entries
         * and one for root of the snapshot.
         */
-       u64 num_bytes = calc_trans_metadata_size(root, 5);
+       u64 num_bytes = btrfs_calc_trans_metadata_size(root, 5);
        dst_rsv->space_info = src_rsv->space_info;
        return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
 }
@@ -4078,7 +3968,7 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
 
        if (nr_extents > reserved_extents) {
                nr_extents -= reserved_extents;
-               to_reserve = calc_trans_metadata_size(root, nr_extents);
+               to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents);
        } else {
                nr_extents = 0;
                to_reserve = 0;
@@ -4132,7 +4022,7 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
 
        to_free = calc_csum_metadata_size(inode, num_bytes);
        if (nr_extents > 0)
-               to_free += calc_trans_metadata_size(root, nr_extents);
+               to_free += btrfs_calc_trans_metadata_size(root, nr_extents);
 
        btrfs_block_rsv_release(root, &root->fs_info->delalloc_block_rsv,
                                to_free);
@@ -4541,7 +4431,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                                                    NULL, refs_to_drop,
                                                    is_data);
                        BUG_ON(ret);
-                       btrfs_release_path(extent_root, path);
+                       btrfs_release_path(path);
                        path->leave_spinning = 1;
 
                        key.objectid = bytenr;
@@ -4580,7 +4470,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                                             owner_objectid, 0);
                BUG_ON(ret < 0);
 
-               btrfs_release_path(extent_root, path);
+               btrfs_release_path(path);
                path->leave_spinning = 1;
 
                key.objectid = bytenr;
@@ -4650,7 +4540,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                ret = btrfs_del_items(trans, extent_root, path, path->slots[0],
                                      num_to_del);
                BUG_ON(ret);
-               btrfs_release_path(extent_root, path);
+               btrfs_release_path(path);
 
                if (is_data) {
                        ret = btrfs_del_csums(trans, root, bytenr, num_bytes);
@@ -4893,7 +4783,7 @@ wait_block_group_cache_progress(struct btrfs_block_group_cache *cache,
                return 0;
 
        wait_event(caching_ctl->wait, block_group_cache_done(cache) ||
-                  (cache->free_space >= num_bytes));
+                  (cache->free_space_ctl->free_space >= num_bytes));
 
        put_caching_control(caching_ctl);
        return 0;
@@ -5129,6 +5019,15 @@ have_block_group:
                if (unlikely(block_group->ro))
                        goto loop;
 
+               spin_lock(&block_group->free_space_ctl->tree_lock);
+               if (cached &&
+                   block_group->free_space_ctl->free_space <
+                   num_bytes + empty_size) {
+                       spin_unlock(&block_group->free_space_ctl->tree_lock);
+                       goto loop;
+               }
+               spin_unlock(&block_group->free_space_ctl->tree_lock);
+
                /*
                 * Ok we want to try and use the cluster allocator, so lets look
                 * there, unless we are on LOOP_NO_EMPTY_SIZE, since we will
@@ -5292,6 +5191,7 @@ checks:
                        btrfs_add_free_space(block_group, offset,
                                             search_start - offset);
                BUG_ON(offset > search_start);
+               btrfs_put_block_group(block_group);
                break;
 loop:
                failed_cluster_refill = false;
@@ -5314,9 +5214,7 @@ loop:
         * LOOP_NO_EMPTY_SIZE, set empty_size and empty_cluster to 0 and try
         *                      again
         */
-       if (!ins->objectid && loop < LOOP_NO_EMPTY_SIZE &&
-           (found_uncached_bg || empty_size || empty_cluster ||
-            allowed_chunk_alloc)) {
+       if (!ins->objectid && loop < LOOP_NO_EMPTY_SIZE) {
                index = 0;
                if (loop == LOOP_FIND_IDEAL && found_uncached_bg) {
                        found_uncached_bg = false;
@@ -5356,42 +5254,39 @@ loop:
                        goto search;
                }
 
-               if (loop < LOOP_CACHING_WAIT) {
-                       loop++;
-                       goto search;
-               }
+               loop++;
 
                if (loop == LOOP_ALLOC_CHUNK) {
-                       empty_size = 0;
-                       empty_cluster = 0;
-               }
+                      if (allowed_chunk_alloc) {
+                               ret = do_chunk_alloc(trans, root, num_bytes +
+                                                    2 * 1024 * 1024, data,
+                                                    CHUNK_ALLOC_LIMITED);
+                               allowed_chunk_alloc = 0;
+                               if (ret == 1)
+                                       done_chunk_alloc = 1;
+                       } else if (!done_chunk_alloc &&
+                                  space_info->force_alloc ==
+                                  CHUNK_ALLOC_NO_FORCE) {
+                               space_info->force_alloc = CHUNK_ALLOC_LIMITED;
+                       }
 
-               if (allowed_chunk_alloc) {
-                       ret = do_chunk_alloc(trans, root, num_bytes +
-                                            2 * 1024 * 1024, data,
-                                            CHUNK_ALLOC_LIMITED);
-                       allowed_chunk_alloc = 0;
-                       done_chunk_alloc = 1;
-               } else if (!done_chunk_alloc &&
-                          space_info->force_alloc == CHUNK_ALLOC_NO_FORCE) {
-                       space_info->force_alloc = CHUNK_ALLOC_LIMITED;
+                      /*
+                       * We didn't allocate a chunk, go ahead and drop the
+                       * empty size and loop again.
+                       */
+                      if (!done_chunk_alloc)
+                              loop = LOOP_NO_EMPTY_SIZE;
                }
 
-               if (loop < LOOP_NO_EMPTY_SIZE) {
-                       loop++;
-                       goto search;
+               if (loop == LOOP_NO_EMPTY_SIZE) {
+                       empty_size = 0;
+                       empty_cluster = 0;
                }
-               ret = -ENOSPC;
+
+               goto search;
        } else if (!ins->objectid) {
                ret = -ENOSPC;
-       }
-
-       /* we found what we needed */
-       if (ins->objectid) {
-               if (!(data & BTRFS_BLOCK_GROUP_DATA))
-                       trans->block_group = block_group->key.objectid;
-
-               btrfs_put_block_group(block_group);
+       } else if (ins->objectid) {
                ret = 0;
        }
 
@@ -6480,7 +6375,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
                                trans->block_rsv = block_rsv;
                }
        }
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        BUG_ON(err);
 
        ret = btrfs_del_root(trans, tree_root, &root->root_key);
@@ -6584,1619 +6479,111 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
        return ret;
 }
 
-#if 0
-static unsigned long calc_ra(unsigned long start, unsigned long last,
-                            unsigned long nr)
-{
-       return min(last, start + nr - 1);
-}
-
-static noinline int relocate_inode_pages(struct inode *inode, u64 start,
-                                        u64 len)
+static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
 {
-       u64 page_start;
-       u64 page_end;
-       unsigned long first_index;
-       unsigned long last_index;
-       unsigned long i;
-       struct page *page;
-       struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
-       struct file_ra_state *ra;
-       struct btrfs_ordered_extent *ordered;
-       unsigned int total_read = 0;
-       unsigned int total_dirty = 0;
-       int ret = 0;
-
-       ra = kzalloc(sizeof(*ra), GFP_NOFS);
-       if (!ra)
-               return -ENOMEM;
+       u64 num_devices;
+       u64 stripped = BTRFS_BLOCK_GROUP_RAID0 |
+               BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10;
 
-       mutex_lock(&inode->i_mutex);
-       first_index = start >> PAGE_CACHE_SHIFT;
-       last_index = (start + len - 1) >> PAGE_CACHE_SHIFT;
+       /*
+        * we add in the count of missing devices because we want
+        * to make sure that any RAID levels on a degraded FS
+        * continue to be honored.
+        */
+       num_devices = root->fs_info->fs_devices->rw_devices +
+               root->fs_info->fs_devices->missing_devices;
 
-       /* make sure the dirty trick played by the caller work */
-       ret = invalidate_inode_pages2_range(inode->i_mapping,
-                                           first_index, last_index);
-       if (ret)
-               goto out_unlock;
+       if (num_devices == 1) {
+               stripped |= BTRFS_BLOCK_GROUP_DUP;
+               stripped = flags & ~stripped;
 
-       file_ra_state_init(ra, inode->i_mapping);
+               /* turn raid0 into single device chunks */
+               if (flags & BTRFS_BLOCK_GROUP_RAID0)
+                       return stripped;
 
-       for (i = first_index ; i <= last_index; i++) {
-               if (total_read % ra->ra_pages == 0) {
-                       btrfs_force_ra(inode->i_mapping, ra, NULL, i,
-                                      calc_ra(i, last_index, ra->ra_pages));
-               }
-               total_read++;
-again:
-               if (((u64)i << PAGE_CACHE_SHIFT) > i_size_read(inode))
-                       BUG_ON(1);
-               page = grab_cache_page(inode->i_mapping, i);
-               if (!page) {
-                       ret = -ENOMEM;
-                       goto out_unlock;
-               }
-               if (!PageUptodate(page)) {
-                       btrfs_readpage(NULL, page);
-                       lock_page(page);
-                       if (!PageUptodate(page)) {
-                               unlock_page(page);
-                               page_cache_release(page);
-                               ret = -EIO;
-                               goto out_unlock;
-                       }
-               }
-               wait_on_page_writeback(page);
-
-               page_start = (u64)page->index << PAGE_CACHE_SHIFT;
-               page_end = page_start + PAGE_CACHE_SIZE - 1;
-               lock_extent(io_tree, page_start, page_end, GFP_NOFS);
-
-               ordered = btrfs_lookup_ordered_extent(inode, page_start);
-               if (ordered) {
-                       unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
-                       unlock_page(page);
-                       page_cache_release(page);
-                       btrfs_start_ordered_extent(inode, ordered, 1);
-                       btrfs_put_ordered_extent(ordered);
-                       goto again;
-               }
-               set_page_extent_mapped(page);
+               /* turn mirroring into duplication */
+               if (flags & (BTRFS_BLOCK_GROUP_RAID1 |
+                            BTRFS_BLOCK_GROUP_RAID10))
+                       return stripped | BTRFS_BLOCK_GROUP_DUP;
+               return flags;
+       } else {
+               /* they already had raid on here, just return */
+               if (flags & stripped)
+                       return flags;
 
-               if (i == first_index)
-                       set_extent_bits(io_tree, page_start, page_end,
-                                       EXTENT_BOUNDARY, GFP_NOFS);
-               btrfs_set_extent_delalloc(inode, page_start, page_end);
+               stripped |= BTRFS_BLOCK_GROUP_DUP;
+               stripped = flags & ~stripped;
 
-               set_page_dirty(page);
-               total_dirty++;
+               /* switch duplicated blocks with raid1 */
+               if (flags & BTRFS_BLOCK_GROUP_DUP)
+                       return stripped | BTRFS_BLOCK_GROUP_RAID1;
 
-               unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
-               unlock_page(page);
-               page_cache_release(page);
+               /* turn single device chunks into raid0 */
+               return stripped | BTRFS_BLOCK_GROUP_RAID0;
        }
-
-out_unlock:
-       kfree(ra);
-       mutex_unlock(&inode->i_mutex);
-       balance_dirty_pages_ratelimited_nr(inode->i_mapping, total_dirty);
-       return ret;
+       return flags;
 }
 
-static noinline int relocate_data_extent(struct inode *reloc_inode,
-                                        struct btrfs_key *extent_key,
-                                        u64 offset)
+static int set_block_group_ro(struct btrfs_block_group_cache *cache)
 {
-       struct btrfs_root *root = BTRFS_I(reloc_inode)->root;
-       struct extent_map_tree *em_tree = &BTRFS_I(reloc_inode)->extent_tree;
-       struct extent_map *em;
-       u64 start = extent_key->objectid - offset;
-       u64 end = start + extent_key->offset - 1;
+       struct btrfs_space_info *sinfo = cache->space_info;
+       u64 num_bytes;
+       int ret = -ENOSPC;
 
-       em = alloc_extent_map(GFP_NOFS);
-       BUG_ON(!em);
+       if (cache->ro)
+               return 0;
 
-       em->start = start;
-       em->len = extent_key->offset;
-       em->block_len = extent_key->offset;
-       em->block_start = extent_key->objectid;
-       em->bdev = root->fs_info->fs_devices->latest_bdev;
-       set_bit(EXTENT_FLAG_PINNED, &em->flags);
+       spin_lock(&sinfo->lock);
+       spin_lock(&cache->lock);
+       num_bytes = cache->key.offset - cache->reserved - cache->pinned -
+                   cache->bytes_super - btrfs_block_group_used(&cache->item);
 
-       /* setup extent map to cheat btrfs_readpage */
-       lock_extent(&BTRFS_I(reloc_inode)->io_tree, start, end, GFP_NOFS);
-       while (1) {
-               int ret;
-               write_lock(&em_tree->lock);
-               ret = add_extent_mapping(em_tree, em);
-               write_unlock(&em_tree->lock);
-               if (ret != -EEXIST) {
-                       free_extent_map(em);
-                       break;
-               }
-               btrfs_drop_extent_cache(reloc_inode, start, end, 0);
+       if (sinfo->bytes_used + sinfo->bytes_reserved + sinfo->bytes_pinned +
+           sinfo->bytes_may_use + sinfo->bytes_readonly +
+           cache->reserved_pinned + num_bytes <= sinfo->total_bytes) {
+               sinfo->bytes_readonly += num_bytes;
+               sinfo->bytes_reserved += cache->reserved_pinned;
+               cache->reserved_pinned = 0;
+               cache->ro = 1;
+               ret = 0;
        }
-       unlock_extent(&BTRFS_I(reloc_inode)->io_tree, start, end, GFP_NOFS);
 
-       return relocate_inode_pages(reloc_inode, start, extent_key->offset);
+       spin_unlock(&cache->lock);
+       spin_unlock(&sinfo->lock);
+       return ret;
 }
 
-struct btrfs_ref_path {
-       u64 extent_start;
-       u64 nodes[BTRFS_MAX_LEVEL];
-       u64 root_objectid;
-       u64 root_generation;
-       u64 owner_objectid;
-       u32 num_refs;
-       int lowest_level;
-       int current_level;
-       int shared_level;
-
-       struct btrfs_key node_keys[BTRFS_MAX_LEVEL];
-       u64 new_nodes[BTRFS_MAX_LEVEL];
-};
-
-struct disk_extent {
-       u64 ram_bytes;
-       u64 disk_bytenr;
-       u64 disk_num_bytes;
-       u64 offset;
-       u64 num_bytes;
-       u8 compression;
-       u8 encryption;
-       u16 other_encoding;
-};
-
-static int is_cowonly_root(u64 root_objectid)
-{
-       if (root_objectid == BTRFS_ROOT_TREE_OBJECTID ||
-           root_objectid == BTRFS_EXTENT_TREE_OBJECTID ||
-           root_objectid == BTRFS_CHUNK_TREE_OBJECTID ||
-           root_objectid == BTRFS_DEV_TREE_OBJECTID ||
-           root_objectid == BTRFS_TREE_LOG_OBJECTID ||
-           root_objectid == BTRFS_CSUM_TREE_OBJECTID)
-               return 1;
-       return 0;
-}
+int btrfs_set_block_group_ro(struct btrfs_root *root,
+                            struct btrfs_block_group_cache *cache)
 
-static noinline int __next_ref_path(struct btrfs_trans_handle *trans,
-                                   struct btrfs_root *extent_root,
-                                   struct btrfs_ref_path *ref_path,
-                                   int first_time)
 {
-       struct extent_buffer *leaf;
-       struct btrfs_path *path;
-       struct btrfs_extent_ref *ref;
-       struct btrfs_key key;
-       struct btrfs_key found_key;
-       u64 bytenr;
-       u32 nritems;
-       int level;
-       int ret = 1;
-
-       path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
-
-       if (first_time) {
-               ref_path->lowest_level = -1;
-               ref_path->current_level = -1;
-               ref_path->shared_level = -1;
-               goto walk_up;
-       }
-walk_down:
-       level = ref_path->current_level - 1;
-       while (level >= -1) {
-               u64 parent;
-               if (level < ref_path->lowest_level)
-                       break;
+       struct btrfs_trans_handle *trans;
+       u64 alloc_flags;
+       int ret;
 
-               if (level >= 0)
-                       bytenr = ref_path->nodes[level];
-               else
-                       bytenr = ref_path->extent_start;
-               BUG_ON(bytenr == 0);
+       BUG_ON(cache->ro);
 
-               parent = ref_path->nodes[level + 1];
-               ref_path->nodes[level + 1] = 0;
-               ref_path->current_level = level;
-               BUG_ON(parent == 0);
+       trans = btrfs_join_transaction(root);
+       BUG_ON(IS_ERR(trans));
 
-               key.objectid = bytenr;
-               key.offset = parent + 1;
-               key.type = BTRFS_EXTENT_REF_KEY;
+       alloc_flags = update_block_group_flags(root, cache->flags);
+       if (alloc_flags != cache->flags)
+               do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
+                              CHUNK_ALLOC_FORCE);
 
-               ret = btrfs_search_slot(trans, extent_root, &key, path, 0, 0);
-               if (ret < 0)
-                       goto out;
-               BUG_ON(ret == 0);
-
-               leaf = path->nodes[0];
-               nritems = btrfs_header_nritems(leaf);
-               if (path->slots[0] >= nritems) {
-                       ret = btrfs_next_leaf(extent_root, path);
-                       if (ret < 0)
-                               goto out;
-                       if (ret > 0)
-                               goto next;
-                       leaf = path->nodes[0];
-               }
-
-               btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
-               if (found_key.objectid == bytenr &&
-                   found_key.type == BTRFS_EXTENT_REF_KEY) {
-                       if (level < ref_path->shared_level)
-                               ref_path->shared_level = level;
-                       goto found;
-               }
-next:
-               level--;
-               btrfs_release_path(extent_root, path);
-               cond_resched();
-       }
-       /* reached lowest level */
-       ret = 1;
-       goto out;
-walk_up:
-       level = ref_path->current_level;
-       while (level < BTRFS_MAX_LEVEL - 1) {
-               u64 ref_objectid;
-
-               if (level >= 0)
-                       bytenr = ref_path->nodes[level];
-               else
-                       bytenr = ref_path->extent_start;
-
-               BUG_ON(bytenr == 0);
-
-               key.objectid = bytenr;
-               key.offset = 0;
-               key.type = BTRFS_EXTENT_REF_KEY;
-
-               ret = btrfs_search_slot(trans, extent_root, &key, path, 0, 0);
-               if (ret < 0)
-                       goto out;
-
-               leaf = path->nodes[0];
-               nritems = btrfs_header_nritems(leaf);
-               if (path->slots[0] >= nritems) {
-                       ret = btrfs_next_leaf(extent_root, path);
-                       if (ret < 0)
-                               goto out;
-                       if (ret > 0) {
-                               /* the extent was freed by someone */
-                               if (ref_path->lowest_level == level)
-                                       goto out;
-                               btrfs_release_path(extent_root, path);
-                               goto walk_down;
-                       }
-                       leaf = path->nodes[0];
-               }
-
-               btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
-               if (found_key.objectid != bytenr ||
-                               found_key.type != BTRFS_EXTENT_REF_KEY) {
-                       /* the extent was freed by someone */
-                       if (ref_path->lowest_level == level) {
-                               ret = 1;
-                               goto out;
-                       }
-                       btrfs_release_path(extent_root, path);
-                       goto walk_down;
-               }
-found:
-               ref = btrfs_item_ptr(leaf, path->slots[0],
-                               struct btrfs_extent_ref);
-               ref_objectid = btrfs_ref_objectid(leaf, ref);
-               if (ref_objectid < BTRFS_FIRST_FREE_OBJECTID) {
-                       if (first_time) {
-                               level = (int)ref_objectid;
-                               BUG_ON(level >= BTRFS_MAX_LEVEL);
-                               ref_path->lowest_level = level;
-                               ref_path->current_level = level;
-                               ref_path->nodes[level] = bytenr;
-                       } else {
-                               WARN_ON(ref_objectid != level);
-                       }
-               } else {
-                       WARN_ON(level != -1);
-               }
-               first_time = 0;
-
-               if (ref_path->lowest_level == level) {
-                       ref_path->owner_objectid = ref_objectid;
-                       ref_path->num_refs = btrfs_ref_num_refs(leaf, ref);
-               }
-
-               /*
-                * the block is tree root or the block isn't in reference
-                * counted tree.
-                */
-               if (found_key.objectid == found_key.offset ||
-                   is_cowonly_root(btrfs_ref_root(leaf, ref))) {
-                       ref_path->root_objectid = btrfs_ref_root(leaf, ref);
-                       ref_path->root_generation =
-                               btrfs_ref_generation(leaf, ref);
-                       if (level < 0) {
-                               /* special reference from the tree log */
-                               ref_path->nodes[0] = found_key.offset;
-                               ref_path->current_level = 0;
-                       }
-                       ret = 0;
-                       goto out;
-               }
-
-               level++;
-               BUG_ON(ref_path->nodes[level] != 0);
-               ref_path->nodes[level] = found_key.offset;
-               ref_path->current_level = level;
-
-               /*
-                * the reference was created in the running transaction,
-                * no need to continue walking up.
-                */
-               if (btrfs_ref_generation(leaf, ref) == trans->transid) {
-                       ref_path->root_objectid = btrfs_ref_root(leaf, ref);
-                       ref_path->root_generation =
-                               btrfs_ref_generation(leaf, ref);
-                       ret = 0;
-                       goto out;
-               }
-
-               btrfs_release_path(extent_root, path);
-               cond_resched();
-       }
-       /* reached max tree level, but no tree root found. */
-       BUG();
-out:
-       btrfs_free_path(path);
-       return ret;
-}
-
-static int btrfs_first_ref_path(struct btrfs_trans_handle *trans,
-                               struct btrfs_root *extent_root,
-                               struct btrfs_ref_path *ref_path,
-                               u64 extent_start)
-{
-       memset(ref_path, 0, sizeof(*ref_path));
-       ref_path->extent_start = extent_start;
-
-       return __next_ref_path(trans, extent_root, ref_path, 1);
-}
-
-static int btrfs_next_ref_path(struct btrfs_trans_handle *trans,
-                              struct btrfs_root *extent_root,
-                              struct btrfs_ref_path *ref_path)
-{
-       return __next_ref_path(trans, extent_root, ref_path, 0);
-}
-
-static noinline int get_new_locations(struct inode *reloc_inode,
-                                     struct btrfs_key *extent_key,
-                                     u64 offset, int no_fragment,
-                                     struct disk_extent **extents,
-                                     int *nr_extents)
-{
-       struct btrfs_root *root = BTRFS_I(reloc_inode)->root;
-       struct btrfs_path *path;
-       struct btrfs_file_extent_item *fi;
-       struct extent_buffer *leaf;
-       struct disk_extent *exts = *extents;
-       struct btrfs_key found_key;
-       u64 cur_pos;
-       u64 last_byte;
-       u32 nritems;
-       int nr = 0;
-       int max = *nr_extents;
-       int ret;
-
-       WARN_ON(!no_fragment && *extents);
-       if (!exts) {
-               max = 1;
-               exts = kmalloc(sizeof(*exts) * max, GFP_NOFS);
-               if (!exts)
-                       return -ENOMEM;
-       }
-
-       path = btrfs_alloc_path();
-       if (!path) {
-               if (exts != *extents)
-                       kfree(exts);
-               return -ENOMEM;
-       }
-
-       cur_pos = extent_key->objectid - offset;
-       last_byte = extent_key->objectid + extent_key->offset;
-       ret = btrfs_lookup_file_extent(NULL, root, path, reloc_inode->i_ino,
-                                      cur_pos, 0);
-       if (ret < 0)
-               goto out;
-       if (ret > 0) {
-               ret = -ENOENT;
-               goto out;
-       }
-
-       while (1) {
-               leaf = path->nodes[0];
-               nritems = btrfs_header_nritems(leaf);
-               if (path->slots[0] >= nritems) {
-                       ret = btrfs_next_leaf(root, path);
-                       if (ret < 0)
-                               goto out;
-                       if (ret > 0)
-                               break;
-                       leaf = path->nodes[0];
-               }
-
-               btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
-               if (found_key.offset != cur_pos ||
-                   found_key.type != BTRFS_EXTENT_DATA_KEY ||
-                   found_key.objectid != reloc_inode->i_ino)
-                       break;
-
-               fi = btrfs_item_ptr(leaf, path->slots[0],
-                                   struct btrfs_file_extent_item);
-               if (btrfs_file_extent_type(leaf, fi) !=
-                   BTRFS_FILE_EXTENT_REG ||
-                   btrfs_file_extent_disk_bytenr(leaf, fi) == 0)
-                       break;
-
-               if (nr == max) {
-                       struct disk_extent *old = exts;
-                       max *= 2;
-                       exts = kzalloc(sizeof(*exts) * max, GFP_NOFS);
-                       if (!exts) {
-                               ret = -ENOMEM;
-                               goto out;
-                       }
-                       memcpy(exts, old, sizeof(*exts) * nr);
-                       if (old != *extents)
-                               kfree(old);
-               }
-
-               exts[nr].disk_bytenr =
-                       btrfs_file_extent_disk_bytenr(leaf, fi);
-               exts[nr].disk_num_bytes =
-                       btrfs_file_extent_disk_num_bytes(leaf, fi);
-               exts[nr].offset = btrfs_file_extent_offset(leaf, fi);
-               exts[nr].num_bytes = btrfs_file_extent_num_bytes(leaf, fi);
-               exts[nr].ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi);
-               exts[nr].compression = btrfs_file_extent_compression(leaf, fi);
-               exts[nr].encryption = btrfs_file_extent_encryption(leaf, fi);
-               exts[nr].other_encoding = btrfs_file_extent_other_encoding(leaf,
-                                                                          fi);
-               BUG_ON(exts[nr].offset > 0);
-               BUG_ON(exts[nr].compression || exts[nr].encryption);
-               BUG_ON(exts[nr].num_bytes != exts[nr].disk_num_bytes);
-
-               cur_pos += exts[nr].num_bytes;
-               nr++;
-
-               if (cur_pos + offset >= last_byte)
-                       break;
-
-               if (no_fragment) {
-                       ret = 1;
-                       goto out;
-               }
-               path->slots[0]++;
-       }
-
-       BUG_ON(cur_pos + offset > last_byte);
-       if (cur_pos + offset < last_byte) {
-               ret = -ENOENT;
-               goto out;
-       }
-       ret = 0;
-out:
-       btrfs_free_path(path);
-       if (ret) {
-               if (exts != *extents)
-                       kfree(exts);
-       } else {
-               *extents = exts;
-               *nr_extents = nr;
-       }
-       return ret;
-}
-
-static noinline int replace_one_extent(struct btrfs_trans_handle *trans,
-                                       struct btrfs_root *root,
-                                       struct btrfs_path *path,
-                                       struct btrfs_key *extent_key,
-                                       struct btrfs_key *leaf_key,
-                                       struct btrfs_ref_path *ref_path,
-                                       struct disk_extent *new_extents,
-                                       int nr_extents)
-{
-       struct extent_buffer *leaf;
-       struct btrfs_file_extent_item *fi;
-       struct inode *inode = NULL;
-       struct btrfs_key key;
-       u64 lock_start = 0;
-       u64 lock_end = 0;
-       u64 num_bytes;
-       u64 ext_offset;
-       u64 search_end = (u64)-1;
-       u32 nritems;
-       int nr_scaned = 0;
-       int extent_locked = 0;
-       int extent_type;
-       int ret;
-
-       memcpy(&key, leaf_key, sizeof(key));
-       if (ref_path->owner_objectid != BTRFS_MULTIPLE_OBJECTIDS) {
-               if (key.objectid < ref_path->owner_objectid ||
-                   (key.objectid == ref_path->owner_objectid &&
-                    key.type < BTRFS_EXTENT_DATA_KEY)) {
-                       key.objectid = ref_path->owner_objectid;
-                       key.type = BTRFS_EXTENT_DATA_KEY;
-                       key.offset = 0;
-               }
-       }
-
-       while (1) {
-               ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
-               if (ret < 0)
-                       goto out;
-
-               leaf = path->nodes[0];
-               nritems = btrfs_header_nritems(leaf);
-next:
-               if (extent_locked && ret > 0) {
-                       /*
-                        * the file extent item was modified by someone
-                        * before the extent got locked.
-                        */
-                       unlock_extent(&BTRFS_I(inode)->io_tree, lock_start,
-                                     lock_end, GFP_NOFS);
-                       extent_locked = 0;
-               }
-
-               if (path->slots[0] >= nritems) {
-                       if (++nr_scaned > 2)
-                               break;
-
-                       BUG_ON(extent_locked);
-                       ret = btrfs_next_leaf(root, path);
-                       if (ret < 0)
-                               goto out;
-                       if (ret > 0)
-                               break;
-                       leaf = path->nodes[0];
-                       nritems = btrfs_header_nritems(leaf);
-               }
-
-               btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
-
-               if (ref_path->owner_objectid != BTRFS_MULTIPLE_OBJECTIDS) {
-                       if ((key.objectid > ref_path->owner_objectid) ||
-                           (key.objectid == ref_path->owner_objectid &&
-                            key.type > BTRFS_EXTENT_DATA_KEY) ||
-                           key.offset >= search_end)
-                               break;
-               }
-
-               if (inode && key.objectid != inode->i_ino) {
-                       BUG_ON(extent_locked);
-                       btrfs_release_path(root, path);
-                       mutex_unlock(&inode->i_mutex);
-                       iput(inode);
-                       inode = NULL;
-                       continue;
-               }
-
-               if (key.type != BTRFS_EXTENT_DATA_KEY) {
-                       path->slots[0]++;
-                       ret = 1;
-                       goto next;
-               }
-               fi = btrfs_item_ptr(leaf, path->slots[0],
-                                   struct btrfs_file_extent_item);
-               extent_type = btrfs_file_extent_type(leaf, fi);
-               if ((extent_type != BTRFS_FILE_EXTENT_REG &&
-                    extent_type != BTRFS_FILE_EXTENT_PREALLOC) ||
-                   (btrfs_file_extent_disk_bytenr(leaf, fi) !=
-                    extent_key->objectid)) {
-                       path->slots[0]++;
-                       ret = 1;
-                       goto next;
-               }
-
-               num_bytes = btrfs_file_extent_num_bytes(leaf, fi);
-               ext_offset = btrfs_file_extent_offset(leaf, fi);
-
-               if (search_end == (u64)-1) {
-                       search_end = key.offset - ext_offset +
-                               btrfs_file_extent_ram_bytes(leaf, fi);
-               }
-
-               if (!extent_locked) {
-                       lock_start = key.offset;
-                       lock_end = lock_start + num_bytes - 1;
-               } else {
-                       if (lock_start > key.offset ||
-                           lock_end + 1 < key.offset + num_bytes) {
-                               unlock_extent(&BTRFS_I(inode)->io_tree,
-                                             lock_start, lock_end, GFP_NOFS);
-                               extent_locked = 0;
-                       }
-               }
-
-               if (!inode) {
-                       btrfs_release_path(root, path);
-
-                       inode = btrfs_iget_locked(root->fs_info->sb,
-                                                 key.objectid, root);
-                       if (inode->i_state & I_NEW) {
-                               BTRFS_I(inode)->root = root;
-                               BTRFS_I(inode)->location.objectid =
-                                       key.objectid;
-                               BTRFS_I(inode)->location.type =
-                                       BTRFS_INODE_ITEM_KEY;
-                               BTRFS_I(inode)->location.offset = 0;
-                               btrfs_read_locked_inode(inode);
-                               unlock_new_inode(inode);
-                       }
-                       /*
-                        * some code call btrfs_commit_transaction while
-                        * holding the i_mutex, so we can't use mutex_lock
-                        * here.
-                        */
-                       if (is_bad_inode(inode) ||
-                           !mutex_trylock(&inode->i_mutex)) {
-                               iput(inode);
-                               inode = NULL;
-                               key.offset = (u64)-1;
-                               goto skip;
-                       }
-               }
-
-               if (!extent_locked) {
-                       struct btrfs_ordered_extent *ordered;
-
-                       btrfs_release_path(root, path);
-
-                       lock_extent(&BTRFS_I(inode)->io_tree, lock_start,
-                                   lock_end, GFP_NOFS);
-                       ordered = btrfs_lookup_first_ordered_extent(inode,
-                                                                   lock_end);
-                       if (ordered &&
-                           ordered->file_offset <= lock_end &&
-                           ordered->file_offset + ordered->len > lock_start) {
-                               unlock_extent(&BTRFS_I(inode)->io_tree,
-                                             lock_start, lock_end, GFP_NOFS);
-                               btrfs_start_ordered_extent(inode, ordered, 1);
-                               btrfs_put_ordered_extent(ordered);
-                               key.offset += num_bytes;
-                               goto skip;
-                       }
-                       if (ordered)
-                               btrfs_put_ordered_extent(ordered);
-
-                       extent_locked = 1;
-                       continue;
-               }
-
-               if (nr_extents == 1) {
-                       /* update extent pointer in place */
-                       btrfs_set_file_extent_disk_bytenr(leaf, fi,
-                                               new_extents[0].disk_bytenr);
-                       btrfs_set_file_extent_disk_num_bytes(leaf, fi,
-                                               new_extents[0].disk_num_bytes);
-                       btrfs_mark_buffer_dirty(leaf);
-
-                       btrfs_drop_extent_cache(inode, key.offset,
-                                               key.offset + num_bytes - 1, 0);
-
-                       ret = btrfs_inc_extent_ref(trans, root,
-                                               new_extents[0].disk_bytenr,
-                                               new_extents[0].disk_num_bytes,
-                                               leaf->start,
-                                               root->root_key.objectid,
-                                               trans->transid,
-                                               key.objectid);
-                       BUG_ON(ret);
-
-                       ret = btrfs_free_extent(trans, root,
-                                               extent_key->objectid,
-                                               extent_key->offset,
-                                               leaf->start,
-                                               btrfs_header_owner(leaf),
-                                               btrfs_header_generation(leaf),
-                                               key.objectid, 0);
-                       BUG_ON(ret);
-
-                       btrfs_release_path(root, path);
-                       key.offset += num_bytes;
-               } else {
-                       BUG_ON(1);
-#if 0
-                       u64 alloc_hint;
-                       u64 extent_len;
-                       int i;
-                       /*
-                        * drop old extent pointer at first, then insert the
-                        * new pointers one bye one
-                        */
-                       btrfs_release_path(root, path);
-                       ret = btrfs_drop_extents(trans, root, inode, key.offset,
-                                                key.offset + num_bytes,
-                                                key.offset, &alloc_hint);
-                       BUG_ON(ret);
-
-                       for (i = 0; i < nr_extents; i++) {
-                               if (ext_offset >= new_extents[i].num_bytes) {
-                                       ext_offset -= new_extents[i].num_bytes;
-                                       continue;
-                               }
-                               extent_len = min(new_extents[i].num_bytes -
-                                                ext_offset, num_bytes);
-
-                               ret = btrfs_insert_empty_item(trans, root,
-                                                             path, &key,
-                                                             sizeof(*fi));
-                               BUG_ON(ret);
-
-                               leaf = path->nodes[0];
-                               fi = btrfs_item_ptr(leaf, path->slots[0],
-                                               struct btrfs_file_extent_item);
-                               btrfs_set_file_extent_generation(leaf, fi,
-                                                       trans->transid);
-                               btrfs_set_file_extent_type(leaf, fi,
-                                                       BTRFS_FILE_EXTENT_REG);
-                               btrfs_set_file_extent_disk_bytenr(leaf, fi,
-                                               new_extents[i].disk_bytenr);
-                               btrfs_set_file_extent_disk_num_bytes(leaf, fi,
-                                               new_extents[i].disk_num_bytes);
-                               btrfs_set_file_extent_ram_bytes(leaf, fi,
-                                               new_extents[i].ram_bytes);
-
-                               btrfs_set_file_extent_compression(leaf, fi,
-                                               new_extents[i].compression);
-                               btrfs_set_file_extent_encryption(leaf, fi,
-                                               new_extents[i].encryption);
-                               btrfs_set_file_extent_other_encoding(leaf, fi,
-                                               new_extents[i].other_encoding);
-
-                               btrfs_set_file_extent_num_bytes(leaf, fi,
-                                                       extent_len);
-                               ext_offset += new_extents[i].offset;
-                               btrfs_set_file_extent_offset(leaf, fi,
-                                                       ext_offset);
-                               btrfs_mark_buffer_dirty(leaf);
-
-                               btrfs_drop_extent_cache(inode, key.offset,
-                                               key.offset + extent_len - 1, 0);
-
-                               ret = btrfs_inc_extent_ref(trans, root,
-                                               new_extents[i].disk_bytenr,
-                                               new_extents[i].disk_num_bytes,
-                                               leaf->start,
-                                               root->root_key.objectid,
-                                               trans->transid, key.objectid);
-                               BUG_ON(ret);
-                               btrfs_release_path(root, path);
-
-                               inode_add_bytes(inode, extent_len);
-
-                               ext_offset = 0;
-                               num_bytes -= extent_len;
-                               key.offset += extent_len;
-
-                               if (num_bytes == 0)
-                                       break;
-                       }
-                       BUG_ON(i >= nr_extents);
-#endif
-               }
-
-               if (extent_locked) {
-                       unlock_extent(&BTRFS_I(inode)->io_tree, lock_start,
-                                     lock_end, GFP_NOFS);
-                       extent_locked = 0;
-               }
-skip:
-               if (ref_path->owner_objectid != BTRFS_MULTIPLE_OBJECTIDS &&
-                   key.offset >= search_end)
-                       break;
-
-               cond_resched();
-       }
-       ret = 0;
-out:
-       btrfs_release_path(root, path);
-       if (inode) {
-               mutex_unlock(&inode->i_mutex);
-               if (extent_locked) {
-                       unlock_extent(&BTRFS_I(inode)->io_tree, lock_start,
-                                     lock_end, GFP_NOFS);
-               }
-               iput(inode);
-       }
-       return ret;
-}
-
-int btrfs_reloc_tree_cache_ref(struct btrfs_trans_handle *trans,
-                              struct btrfs_root *root,
-                              struct extent_buffer *buf, u64 orig_start)
-{
-       int level;
-       int ret;
-
-       BUG_ON(btrfs_header_generation(buf) != trans->transid);
-       BUG_ON(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID);
-
-       level = btrfs_header_level(buf);
-       if (level == 0) {
-               struct btrfs_leaf_ref *ref;
-               struct btrfs_leaf_ref *orig_ref;
-
-               orig_ref = btrfs_lookup_leaf_ref(root, orig_start);
-               if (!orig_ref)
-                       return -ENOENT;
-
-               ref = btrfs_alloc_leaf_ref(root, orig_ref->nritems);
-               if (!ref) {
-                       btrfs_free_leaf_ref(root, orig_ref);
-                       return -ENOMEM;
-               }
-
-               ref->nritems = orig_ref->nritems;
-               memcpy(ref->extents, orig_ref->extents,
-                       sizeof(ref->extents[0]) * ref->nritems);
-
-               btrfs_free_leaf_ref(root, orig_ref);
-
-               ref->root_gen = trans->transid;
-               ref->bytenr = buf->start;
-               ref->owner = btrfs_header_owner(buf);
-               ref->generation = btrfs_header_generation(buf);
-
-               ret = btrfs_add_leaf_ref(root, ref, 0);
-               WARN_ON(ret);
-               btrfs_free_leaf_ref(root, ref);
-       }
-       return 0;
-}
-
-static noinline int invalidate_extent_cache(struct btrfs_root *root,
-                                       struct extent_buffer *leaf,
-                                       struct btrfs_block_group_cache *group,
-                                       struct btrfs_root *target_root)
-{
-       struct btrfs_key key;
-       struct inode *inode = NULL;
-       struct btrfs_file_extent_item *fi;
-       struct extent_state *cached_state = NULL;
-       u64 num_bytes;
-       u64 skip_objectid = 0;
-       u32 nritems;
-       u32 i;
-
-       nritems = btrfs_header_nritems(leaf);
-       for (i = 0; i < nritems; i++) {
-               btrfs_item_key_to_cpu(leaf, &key, i);
-               if (key.objectid == skip_objectid ||
-                   key.type != BTRFS_EXTENT_DATA_KEY)
-                       continue;
-               fi = btrfs_item_ptr(leaf, i, struct btrfs_file_extent_item);
-               if (btrfs_file_extent_type(leaf, fi) ==
-                   BTRFS_FILE_EXTENT_INLINE)
-                       continue;
-               if (btrfs_file_extent_disk_bytenr(leaf, fi) == 0)
-                       continue;
-               if (!inode || inode->i_ino != key.objectid) {
-                       iput(inode);
-                       inode = btrfs_ilookup(target_root->fs_info->sb,
-                                             key.objectid, target_root, 1);
-               }
-               if (!inode) {
-                       skip_objectid = key.objectid;
-                       continue;
-               }
-               num_bytes = btrfs_file_extent_num_bytes(leaf, fi);
-
-               lock_extent_bits(&BTRFS_I(inode)->io_tree, key.offset,
-                                key.offset + num_bytes - 1, 0, &cached_state,
-                                GFP_NOFS);
-               btrfs_drop_extent_cache(inode, key.offset,
-                                       key.offset + num_bytes - 1, 1);
-               unlock_extent_cached(&BTRFS_I(inode)->io_tree, key.offset,
-                                    key.offset + num_bytes - 1, &cached_state,
-                                    GFP_NOFS);
-               cond_resched();
-       }
-       iput(inode);
-       return 0;
-}
-
-static noinline int replace_extents_in_leaf(struct btrfs_trans_handle *trans,
-                                       struct btrfs_root *root,
-                                       struct extent_buffer *leaf,
-                                       struct btrfs_block_group_cache *group,
-                                       struct inode *reloc_inode)
-{
-       struct btrfs_key key;
-       struct btrfs_key extent_key;
-       struct btrfs_file_extent_item *fi;
-       struct btrfs_leaf_ref *ref;
-       struct disk_extent *new_extent;
-       u64 bytenr;
-       u64 num_bytes;
-       u32 nritems;
-       u32 i;
-       int ext_index;
-       int nr_extent;
-       int ret;
-
-       new_extent = kmalloc(sizeof(*new_extent), GFP_NOFS);
-       if (!new_extent)
-               return -ENOMEM;
-
-       ref = btrfs_lookup_leaf_ref(root, leaf->start);
-       BUG_ON(!ref);
-
-       ext_index = -1;
-       nritems = btrfs_header_nritems(leaf);
-       for (i = 0; i < nritems; i++) {
-               btrfs_item_key_to_cpu(leaf, &key, i);
-               if (btrfs_key_type(&key) != BTRFS_EXTENT_DATA_KEY)
-                       continue;
-               fi = btrfs_item_ptr(leaf, i, struct btrfs_file_extent_item);
-               if (btrfs_file_extent_type(leaf, fi) ==
-                   BTRFS_FILE_EXTENT_INLINE)
-                       continue;
-               bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
-               num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi);
-               if (bytenr == 0)
-                       continue;
-
-               ext_index++;
-               if (bytenr >= group->key.objectid + group->key.offset ||
-                   bytenr + num_bytes <= group->key.objectid)
-                       continue;
-
-               extent_key.objectid = bytenr;
-               extent_key.offset = num_bytes;
-               extent_key.type = BTRFS_EXTENT_ITEM_KEY;
-               nr_extent = 1;
-               ret = get_new_locations(reloc_inode, &extent_key,
-                                       group->key.objectid, 1,
-                                       &new_extent, &nr_extent);
-               if (ret > 0)
-                       continue;
-               BUG_ON(ret < 0);
-
-               BUG_ON(ref->extents[ext_index].bytenr != bytenr);
-               BUG_ON(ref->extents[ext_index].num_bytes != num_bytes);
-               ref->extents[ext_index].bytenr = new_extent->disk_bytenr;
-               ref->extents[ext_index].num_bytes = new_extent->disk_num_bytes;
-
-               btrfs_set_file_extent_disk_bytenr(leaf, fi,
-                                               new_extent->disk_bytenr);
-               btrfs_set_file_extent_disk_num_bytes(leaf, fi,
-                                               new_extent->disk_num_bytes);
-               btrfs_mark_buffer_dirty(leaf);
-
-               ret = btrfs_inc_extent_ref(trans, root,
-                                       new_extent->disk_bytenr,
-                                       new_extent->disk_num_bytes,
-                                       leaf->start,
-                                       root->root_key.objectid,
-                                       trans->transid, key.objectid);
-               BUG_ON(ret);
-
-               ret = btrfs_free_extent(trans, root,
-                                       bytenr, num_bytes, leaf->start,
-                                       btrfs_header_owner(leaf),
-                                       btrfs_header_generation(leaf),
-                                       key.objectid, 0);
-               BUG_ON(ret);
-               cond_resched();
-       }
-       kfree(new_extent);
-       BUG_ON(ext_index + 1 != ref->nritems);
-       btrfs_free_leaf_ref(root, ref);
-       return 0;
-}
-
-int btrfs_free_reloc_root(struct btrfs_trans_handle *trans,
-                         struct btrfs_root *root)
-{
-       struct btrfs_root *reloc_root;
-       int ret;
-
-       if (root->reloc_root) {
-               reloc_root = root->reloc_root;
-               root->reloc_root = NULL;
-               list_add(&reloc_root->dead_list,
-                        &root->fs_info->dead_reloc_roots);
-
-               btrfs_set_root_bytenr(&reloc_root->root_item,
-                                     reloc_root->node->start);
-               btrfs_set_root_level(&root->root_item,
-                                    btrfs_header_level(reloc_root->node));
-               memset(&reloc_root->root_item.drop_progress, 0,
-                       sizeof(struct btrfs_disk_key));
-               reloc_root->root_item.drop_level = 0;
-
-               ret = btrfs_update_root(trans, root->fs_info->tree_root,
-                                       &reloc_root->root_key,
-                                       &reloc_root->root_item);
-               BUG_ON(ret);
-       }
-       return 0;
-}
-
-int btrfs_drop_dead_reloc_roots(struct btrfs_root *root)
-{
-       struct btrfs_trans_handle *trans;
-       struct btrfs_root *reloc_root;
-       struct btrfs_root *prev_root = NULL;
-       struct list_head dead_roots;
-       int ret;
-       unsigned long nr;
-
-       INIT_LIST_HEAD(&dead_roots);
-       list_splice_init(&root->fs_info->dead_reloc_roots, &dead_roots);
-
-       while (!list_empty(&dead_roots)) {
-               reloc_root = list_entry(dead_roots.prev,
-                                       struct btrfs_root, dead_list);
-               list_del_init(&reloc_root->dead_list);
-
-               BUG_ON(reloc_root->commit_root != NULL);
-               while (1) {
-                       trans = btrfs_join_transaction(root, 1);
-                       BUG_ON(IS_ERR(trans));
-
-                       mutex_lock(&root->fs_info->drop_mutex);
-                       ret = btrfs_drop_snapshot(trans, reloc_root);
-                       if (ret != -EAGAIN)
-                               break;
-                       mutex_unlock(&root->fs_info->drop_mutex);
-
-                       nr = trans->blocks_used;
-                       ret = btrfs_end_transaction(trans, root);
-                       BUG_ON(ret);
-                       btrfs_btree_balance_dirty(root, nr);
-               }
-
-               free_extent_buffer(reloc_root->node);
-
-               ret = btrfs_del_root(trans, root->fs_info->tree_root,
-                                    &reloc_root->root_key);
-               BUG_ON(ret);
-               mutex_unlock(&root->fs_info->drop_mutex);
-
-               nr = trans->blocks_used;
-               ret = btrfs_end_transaction(trans, root);
-               BUG_ON(ret);
-               btrfs_btree_balance_dirty(root, nr);
-
-               kfree(prev_root);
-               prev_root = reloc_root;
-       }
-       if (prev_root) {
-               btrfs_remove_leaf_refs(prev_root, (u64)-1, 0);
-               kfree(prev_root);
-       }
-       return 0;
-}
-
-int btrfs_add_dead_reloc_root(struct btrfs_root *root)
-{
-       list_add(&root->dead_list, &root->fs_info->dead_reloc_roots);
-       return 0;
-}
-
-int btrfs_cleanup_reloc_trees(struct btrfs_root *root)
-{
-       struct btrfs_root *reloc_root;
-       struct btrfs_trans_handle *trans;
-       struct btrfs_key location;
-       int found;
-       int ret;
-
-       mutex_lock(&root->fs_info->tree_reloc_mutex);
-       ret = btrfs_find_dead_roots(root, BTRFS_TREE_RELOC_OBJECTID, NULL);
-       BUG_ON(ret);
-       found = !list_empty(&root->fs_info->dead_reloc_roots);
-       mutex_unlock(&root->fs_info->tree_reloc_mutex);
-
-       if (found) {
-               trans = btrfs_start_transaction(root, 1);
-               BUG_ON(IS_ERR(trans));
-               ret = btrfs_commit_transaction(trans, root);
-               BUG_ON(ret);
-       }
-
-       location.objectid = BTRFS_DATA_RELOC_TREE_OBJECTID;
-       location.offset = (u64)-1;
-       location.type = BTRFS_ROOT_ITEM_KEY;
-
-       reloc_root = btrfs_read_fs_root_no_name(root->fs_info, &location);
-       BUG_ON(!reloc_root);
-       ret = btrfs_orphan_cleanup(reloc_root);
-       BUG_ON(ret);
-       return 0;
-}
-
-static noinline int init_reloc_tree(struct btrfs_trans_handle *trans,
-                                   struct btrfs_root *root)
-{
-       struct btrfs_root *reloc_root;
-       struct extent_buffer *eb;
-       struct btrfs_root_item *root_item;
-       struct btrfs_key root_key;
-       int ret;
-
-       BUG_ON(!root->ref_cows);
-       if (root->reloc_root)
-               return 0;
-
-       root_item = kmalloc(sizeof(*root_item), GFP_NOFS);
-       if (!root_item)
-               return -ENOMEM;
-
-       ret = btrfs_copy_root(trans, root, root->commit_root,
-                             &eb, BTRFS_TREE_RELOC_OBJECTID);
-       BUG_ON(ret);
-
-       root_key.objectid = BTRFS_TREE_RELOC_OBJECTID;
-       root_key.offset = root->root_key.objectid;
-       root_key.type = BTRFS_ROOT_ITEM_KEY;
-
-       memcpy(root_item, &root->root_item, sizeof(root_item));
-       btrfs_set_root_refs(root_item, 0);
-       btrfs_set_root_bytenr(root_item, eb->start);
-       btrfs_set_root_level(root_item, btrfs_header_level(eb));
-       btrfs_set_root_generation(root_item, trans->transid);
-
-       btrfs_tree_unlock(eb);
-       free_extent_buffer(eb);
-
-       ret = btrfs_insert_root(trans, root->fs_info->tree_root,
-                               &root_key, root_item);
-       BUG_ON(ret);
-       kfree(root_item);
-
-       reloc_root = btrfs_read_fs_root_no_radix(root->fs_info->tree_root,
-                                                &root_key);
-       BUG_ON(IS_ERR(reloc_root));
-       reloc_root->last_trans = trans->transid;
-       reloc_root->commit_root = NULL;
-       reloc_root->ref_tree = &root->fs_info->reloc_ref_tree;
-
-       root->reloc_root = reloc_root;
-       return 0;
-}
-
-/*
- * Core function of space balance.
- *
- * The idea is using reloc trees to relocate tree blocks in reference
- * counted roots. There is one reloc tree for each subvol, and all
- * reloc trees share same root key objectid. Reloc trees are snapshots
- * of the latest committed roots of subvols (root->commit_root).
- *
- * To relocate a tree block referenced by a subvol, there are two steps.
- * COW the block through subvol's reloc tree, then update block pointer
- * in the subvol to point to the new block. Since all reloc trees share
- * same root key objectid, doing special handing for tree blocks owned
- * by them is easy. Once a tree block has been COWed in one reloc tree,
- * we can use the resulting new block directly when the same block is
- * required to COW again through other reloc trees. By this way, relocated
- * tree blocks are shared between reloc trees, so they are also shared
- * between subvols.
- */
-static noinline int relocate_one_path(struct btrfs_trans_handle *trans,
-                                     struct btrfs_root *root,
-                                     struct btrfs_path *path,
-                                     struct btrfs_key *first_key,
-                                     struct btrfs_ref_path *ref_path,
-                                     struct btrfs_block_group_cache *group,
-                                     struct inode *reloc_inode)
-{
-       struct btrfs_root *reloc_root;
-       struct extent_buffer *eb = NULL;
-       struct btrfs_key *keys;
-       u64 *nodes;
-       int level;
-       int shared_level;
-       int lowest_level = 0;
-       int ret;
-
-       if (ref_path->owner_objectid < BTRFS_FIRST_FREE_OBJECTID)
-               lowest_level = ref_path->owner_objectid;
-
-       if (!root->ref_cows) {
-               path->lowest_level = lowest_level;
-               ret = btrfs_search_slot(trans, root, first_key, path, 0, 1);
-               BUG_ON(ret < 0);
-               path->lowest_level = 0;
-               btrfs_release_path(root, path);
-               return 0;
-       }
-
-       mutex_lock(&root->fs_info->tree_reloc_mutex);
-       ret = init_reloc_tree(trans, root);
-       BUG_ON(ret);
-       reloc_root = root->reloc_root;
-
-       shared_level = ref_path->shared_level;
-       ref_path->shared_level = BTRFS_MAX_LEVEL - 1;
-
-       keys = ref_path->node_keys;
-       nodes = ref_path->new_nodes;
-       memset(&keys[shared_level + 1], 0,
-              sizeof(*keys) * (BTRFS_MAX_LEVEL - shared_level - 1));
-       memset(&nodes[shared_level + 1], 0,
-              sizeof(*nodes) * (BTRFS_MAX_LEVEL - shared_level - 1));
-
-       if (nodes[lowest_level] == 0) {
-               path->lowest_level = lowest_level;
-               ret = btrfs_search_slot(trans, reloc_root, first_key, path,
-                                       0, 1);
-               BUG_ON(ret);
-               for (level = lowest_level; level < BTRFS_MAX_LEVEL; level++) {
-                       eb = path->nodes[level];
-                       if (!eb || eb == reloc_root->node)
-                               break;
-                       nodes[level] = eb->start;
-                       if (level == 0)
-                               btrfs_item_key_to_cpu(eb, &keys[level], 0);
-                       else
-                               btrfs_node_key_to_cpu(eb, &keys[level], 0);
-               }
-               if (nodes[0] &&
-                   ref_path->owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) {
-                       eb = path->nodes[0];
-                       ret = replace_extents_in_leaf(trans, reloc_root, eb,
-                                                     group, reloc_inode);
-                       BUG_ON(ret);
-               }
-               btrfs_release_path(reloc_root, path);
-       } else {
-               ret = btrfs_merge_path(trans, reloc_root, keys, nodes,
-                                      lowest_level);
-               BUG_ON(ret);
-       }
-
-       /*
-        * replace tree blocks in the fs tree with tree blocks in
-        * the reloc tree.
-        */
-       ret = btrfs_merge_path(trans, root, keys, nodes, lowest_level);
-       BUG_ON(ret < 0);
-
-       if (ref_path->owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) {
-               ret = btrfs_search_slot(trans, reloc_root, first_key, path,
-                                       0, 0);
-               BUG_ON(ret);
-               extent_buffer_get(path->nodes[0]);
-               eb = path->nodes[0];
-               btrfs_release_path(reloc_root, path);
-               ret = invalidate_extent_cache(reloc_root, eb, group, root);
-               BUG_ON(ret);
-               free_extent_buffer(eb);
-       }
-
-       mutex_unlock(&root->fs_info->tree_reloc_mutex);
-       path->lowest_level = 0;
-       return 0;
-}
-
-static noinline int relocate_tree_block(struct btrfs_trans_handle *trans,
-                                       struct btrfs_root *root,
-                                       struct btrfs_path *path,
-                                       struct btrfs_key *first_key,
-                                       struct btrfs_ref_path *ref_path)
-{
-       int ret;
-
-       ret = relocate_one_path(trans, root, path, first_key,
-                               ref_path, NULL, NULL);
-       BUG_ON(ret);
-
-       return 0;
-}
-
-static noinline int del_extent_zero(struct btrfs_trans_handle *trans,
-                                   struct btrfs_root *extent_root,
-                                   struct btrfs_path *path,
-                                   struct btrfs_key *extent_key)
-{
-       int ret;
-
-       ret = btrfs_search_slot(trans, extent_root, extent_key, path, -1, 1);
-       if (ret)
-               goto out;
-       ret = btrfs_del_item(trans, extent_root, path);
-out:
-       btrfs_release_path(extent_root, path);
-       return ret;
-}
-
-static noinline struct btrfs_root *read_ref_root(struct btrfs_fs_info *fs_info,
-                                               struct btrfs_ref_path *ref_path)
-{
-       struct btrfs_key root_key;
-
-       root_key.objectid = ref_path->root_objectid;
-       root_key.type = BTRFS_ROOT_ITEM_KEY;
-       if (is_cowonly_root(ref_path->root_objectid))
-               root_key.offset = 0;
-       else
-               root_key.offset = (u64)-1;
-
-       return btrfs_read_fs_root_no_name(fs_info, &root_key);
-}
-
-static noinline int relocate_one_extent(struct btrfs_root *extent_root,
-                                       struct btrfs_path *path,
-                                       struct btrfs_key *extent_key,
-                                       struct btrfs_block_group_cache *group,
-                                       struct inode *reloc_inode, int pass)
-{
-       struct btrfs_trans_handle *trans;
-       struct btrfs_root *found_root;
-       struct btrfs_ref_path *ref_path = NULL;
-       struct disk_extent *new_extents = NULL;
-       int nr_extents = 0;
-       int loops;
-       int ret;
-       int level;
-       struct btrfs_key first_key;
-       u64 prev_block = 0;
-
-
-       trans = btrfs_start_transaction(extent_root, 1);
-       BUG_ON(IS_ERR(trans));
-
-       if (extent_key->objectid == 0) {
-               ret = del_extent_zero(trans, extent_root, path, extent_key);
-               goto out;
-       }
-
-       ref_path = kmalloc(sizeof(*ref_path), GFP_NOFS);
-       if (!ref_path) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       for (loops = 0; ; loops++) {
-               if (loops == 0) {
-                       ret = btrfs_first_ref_path(trans, extent_root, ref_path,
-                                                  extent_key->objectid);
-               } else {
-                       ret = btrfs_next_ref_path(trans, extent_root, ref_path);
-               }
-               if (ret < 0)
-                       goto out;
-               if (ret > 0)
-                       break;
-
-               if (ref_path->root_objectid == BTRFS_TREE_LOG_OBJECTID ||
-                   ref_path->root_objectid == BTRFS_TREE_RELOC_OBJECTID)
-                       continue;
-
-               found_root = read_ref_root(extent_root->fs_info, ref_path);
-               BUG_ON(!found_root);
-               /*
-                * for reference counted tree, only process reference paths
-                * rooted at the latest committed root.
-                */
-               if (found_root->ref_cows &&
-                   ref_path->root_generation != found_root->root_key.offset)
-                       continue;
-
-               if (ref_path->owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) {
-                       if (pass == 0) {
-                               /*
-                                * copy data extents to new locations
-                                */
-                               u64 group_start = group->key.objectid;
-                               ret = relocate_data_extent(reloc_inode,
-                                                          extent_key,
-                                                          group_start);
-                               if (ret < 0)
-                                       goto out;
-                               break;
-                       }
-                       level = 0;
-               } else {
-                       level = ref_path->owner_objectid;
-               }
-
-               if (prev_block != ref_path->nodes[level]) {
-                       struct extent_buffer *eb;
-                       u64 block_start = ref_path->nodes[level];
-                       u64 block_size = btrfs_level_size(found_root, level);
-
-                       eb = read_tree_block(found_root, block_start,
-                                            block_size, 0);
-                       if (!eb) {
-                               ret = -EIO;
-                               goto out;
-                       }
-                       btrfs_tree_lock(eb);
-                       BUG_ON(level != btrfs_header_level(eb));
-
-                       if (level == 0)
-                               btrfs_item_key_to_cpu(eb, &first_key, 0);
-                       else
-                               btrfs_node_key_to_cpu(eb, &first_key, 0);
-
-                       btrfs_tree_unlock(eb);
-                       free_extent_buffer(eb);
-                       prev_block = block_start;
-               }
-
-               mutex_lock(&extent_root->fs_info->trans_mutex);
-               btrfs_record_root_in_trans(found_root);
-               mutex_unlock(&extent_root->fs_info->trans_mutex);
-               if (ref_path->owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) {
-                       /*
-                        * try to update data extent references while
-                        * keeping metadata shared between snapshots.
-                        */
-                       if (pass == 1) {
-                               ret = relocate_one_path(trans, found_root,
-                                               path, &first_key, ref_path,
-                                               group, reloc_inode);
-                               if (ret < 0)
-                                       goto out;
-                               continue;
-                       }
-                       /*
-                        * use fallback method to process the remaining
-                        * references.
-                        */
-                       if (!new_extents) {
-                               u64 group_start = group->key.objectid;
-                               new_extents = kmalloc(sizeof(*new_extents),
-                                                     GFP_NOFS);
-                               if (!new_extents) {
-                                       ret = -ENOMEM;
-                                       goto out;
-                               }
-                               nr_extents = 1;
-                               ret = get_new_locations(reloc_inode,
-                                                       extent_key,
-                                                       group_start, 1,
-                                                       &new_extents,
-                                                       &nr_extents);
-                               if (ret)
-                                       goto out;
-                       }
-                       ret = replace_one_extent(trans, found_root,
-                                               path, extent_key,
-                                               &first_key, ref_path,
-                                               new_extents, nr_extents);
-               } else {
-                       ret = relocate_tree_block(trans, found_root, path,
-                                                 &first_key, ref_path);
-               }
-               if (ret < 0)
-                       goto out;
-       }
-       ret = 0;
-out:
-       btrfs_end_transaction(trans, extent_root);
-       kfree(new_extents);
-       kfree(ref_path);
-       return ret;
-}
-#endif
-
-static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
-{
-       u64 num_devices;
-       u64 stripped = BTRFS_BLOCK_GROUP_RAID0 |
-               BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10;
-
-       /*
-        * we add in the count of missing devices because we want
-        * to make sure that any RAID levels on a degraded FS
-        * continue to be honored.
-        */
-       num_devices = root->fs_info->fs_devices->rw_devices +
-               root->fs_info->fs_devices->missing_devices;
-
-       if (num_devices == 1) {
-               stripped |= BTRFS_BLOCK_GROUP_DUP;
-               stripped = flags & ~stripped;
-
-               /* turn raid0 into single device chunks */
-               if (flags & BTRFS_BLOCK_GROUP_RAID0)
-                       return stripped;
-
-               /* turn mirroring into duplication */
-               if (flags & (BTRFS_BLOCK_GROUP_RAID1 |
-                            BTRFS_BLOCK_GROUP_RAID10))
-                       return stripped | BTRFS_BLOCK_GROUP_DUP;
-               return flags;
-       } else {
-               /* they already had raid on here, just return */
-               if (flags & stripped)
-                       return flags;
-
-               stripped |= BTRFS_BLOCK_GROUP_DUP;
-               stripped = flags & ~stripped;
-
-               /* switch duplicated blocks with raid1 */
-               if (flags & BTRFS_BLOCK_GROUP_DUP)
-                       return stripped | BTRFS_BLOCK_GROUP_RAID1;
-
-               /* turn single device chunks into raid0 */
-               return stripped | BTRFS_BLOCK_GROUP_RAID0;
-       }
-       return flags;
-}
-
-static int set_block_group_ro(struct btrfs_block_group_cache *cache)
-{
-       struct btrfs_space_info *sinfo = cache->space_info;
-       u64 num_bytes;
-       int ret = -ENOSPC;
-
-       if (cache->ro)
-               return 0;
-
-       spin_lock(&sinfo->lock);
-       spin_lock(&cache->lock);
-       num_bytes = cache->key.offset - cache->reserved - cache->pinned -
-                   cache->bytes_super - btrfs_block_group_used(&cache->item);
-
-       if (sinfo->bytes_used + sinfo->bytes_reserved + sinfo->bytes_pinned +
-           sinfo->bytes_may_use + sinfo->bytes_readonly +
-           cache->reserved_pinned + num_bytes <= sinfo->total_bytes) {
-               sinfo->bytes_readonly += num_bytes;
-               sinfo->bytes_reserved += cache->reserved_pinned;
-               cache->reserved_pinned = 0;
-               cache->ro = 1;
-               ret = 0;
-       }
-
-       spin_unlock(&cache->lock);
-       spin_unlock(&sinfo->lock);
-       return ret;
-}
-
-int btrfs_set_block_group_ro(struct btrfs_root *root,
-                            struct btrfs_block_group_cache *cache)
-
-{
-       struct btrfs_trans_handle *trans;
-       u64 alloc_flags;
-       int ret;
-
-       BUG_ON(cache->ro);
-
-       trans = btrfs_join_transaction(root, 1);
-       BUG_ON(IS_ERR(trans));
-
-       alloc_flags = update_block_group_flags(root, cache->flags);
-       if (alloc_flags != cache->flags)
-               do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
-                              CHUNK_ALLOC_FORCE);
-
-       ret = set_block_group_ro(cache);
-       if (!ret)
-               goto out;
-       alloc_flags = get_alloc_profile(root, cache->space_info->flags);
-       ret = do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
-                            CHUNK_ALLOC_FORCE);
-       if (ret < 0)
-               goto out;
-       ret = set_block_group_ro(cache);
-out:
-       btrfs_end_transaction(trans, root);
-       return ret;
-}
+       ret = set_block_group_ro(cache);
+       if (!ret)
+               goto out;
+       alloc_flags = get_alloc_profile(root, cache->space_info->flags);
+       ret = do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
+                            CHUNK_ALLOC_FORCE);
+       if (ret < 0)
+               goto out;
+       ret = set_block_group_ro(cache);
+out:
+       btrfs_end_transaction(trans, root);
+       return ret;
+}
 
 int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans,
                            struct btrfs_root *root, u64 type)
@@ -8532,6 +6919,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
+       path->reada = 1;
 
        cache_gen = btrfs_super_cache_generation(&root->fs_info->super_copy);
        if (cache_gen != 0 &&
@@ -8555,10 +6943,16 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                        ret = -ENOMEM;
                        goto error;
                }
+               cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl),
+                                               GFP_NOFS);
+               if (!cache->free_space_ctl) {
+                       kfree(cache);
+                       ret = -ENOMEM;
+                       goto error;
+               }
 
                atomic_set(&cache->count, 1);
                spin_lock_init(&cache->lock);
-               spin_lock_init(&cache->tree_lock);
                cache->fs_info = info;
                INIT_LIST_HEAD(&cache->list);
                INIT_LIST_HEAD(&cache->cluster_list);
@@ -8566,24 +6960,18 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                if (need_clear)
                        cache->disk_cache_state = BTRFS_DC_CLEAR;
 
-               /*
-                * we only want to have 32k of ram per block group for keeping
-                * track of free space, and if we pass 1/2 of that we want to
-                * start converting things over to using bitmaps
-                */
-               cache->extents_thresh = ((1024 * 32) / 2) /
-                       sizeof(struct btrfs_free_space);
-
                read_extent_buffer(leaf, &cache->item,
                                   btrfs_item_ptr_offset(leaf, path->slots[0]),
                                   sizeof(cache->item));
                memcpy(&cache->key, &found_key, sizeof(found_key));
 
                key.objectid = found_key.objectid + found_key.offset;
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                cache->flags = btrfs_block_group_flags(&cache->item);
                cache->sectorsize = root->sectorsize;
 
+               btrfs_init_free_space_ctl(cache);
+
                /*
                 * We need to exclude the super stripes now so that the space
                 * info has super bytes accounted for, otherwise we'll think
@@ -8670,6 +7058,12 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
        cache = kzalloc(sizeof(*cache), GFP_NOFS);
        if (!cache)
                return -ENOMEM;
+       cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl),
+                                       GFP_NOFS);
+       if (!cache->free_space_ctl) {
+               kfree(cache);
+               return -ENOMEM;
+       }
 
        cache->key.objectid = chunk_offset;
        cache->key.offset = size;
@@ -8677,19 +7071,13 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
        cache->sectorsize = root->sectorsize;
        cache->fs_info = root->fs_info;
 
-       /*
-        * we only want to have 32k of ram per block group for keeping track
-        * of free space, and if we pass 1/2 of that we want to start
-        * converting things over to using bitmaps
-        */
-       cache->extents_thresh = ((1024 * 32) / 2) /
-               sizeof(struct btrfs_free_space);
        atomic_set(&cache->count, 1);
        spin_lock_init(&cache->lock);
-       spin_lock_init(&cache->tree_lock);
        INIT_LIST_HEAD(&cache->list);
        INIT_LIST_HEAD(&cache->cluster_list);
 
+       btrfs_init_free_space_ctl(cache);
+
        btrfs_set_block_group_used(&cache->item, bytes_used);
        btrfs_set_block_group_chunk_objectid(&cache->item, chunk_objectid);
        cache->flags = type;
@@ -8802,12 +7190,12 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
        if (ret < 0)
                goto out;
        if (ret > 0)
-               btrfs_release_path(tree_root, path);
+               btrfs_release_path(path);
        if (ret == 0) {
                ret = btrfs_del_item(trans, tree_root, path);
                if (ret)
                        goto out;
-               btrfs_release_path(tree_root, path);
+               btrfs_release_path(path);
        }
 
        spin_lock(&root->fs_info->block_group_cache_lock);
index 96fcfa522dab72f837d991d5afaaacd4e73d8f74..7055d11c1efdd2efef6668b18e0dfcae802a9dd7 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/writeback.h>
 #include <linux/pagevec.h>
 #include <linux/prefetch.h>
+#include <linux/cleancache.h>
 #include "extent_io.h"
 #include "extent_map.h"
 #include "compat.h"
@@ -102,7 +103,7 @@ void extent_io_exit(void)
 }
 
 void extent_io_tree_init(struct extent_io_tree *tree,
-                         struct address_space *mapping, gfp_t mask)
+                        struct address_space *mapping)
 {
        tree->state = RB_ROOT;
        INIT_RADIX_TREE(&tree->buffer, GFP_ATOMIC);
@@ -440,6 +441,15 @@ static int clear_state_bit(struct extent_io_tree *tree,
        return ret;
 }
 
+static struct extent_state *
+alloc_extent_state_atomic(struct extent_state *prealloc)
+{
+       if (!prealloc)
+               prealloc = alloc_extent_state(GFP_ATOMIC);
+
+       return prealloc;
+}
+
 /*
  * clear some bits on a range in the tree.  This may require splitting
  * or inserting elements in the tree, so the gfp mask is used to
@@ -530,8 +540,8 @@ hit_next:
         */
 
        if (state->start < start) {
-               if (!prealloc)
-                       prealloc = alloc_extent_state(GFP_ATOMIC);
+               prealloc = alloc_extent_state_atomic(prealloc);
+               BUG_ON(!prealloc);
                err = split_state(tree, state, prealloc, start);
                BUG_ON(err == -EEXIST);
                prealloc = NULL;
@@ -552,8 +562,8 @@ hit_next:
         * on the first half
         */
        if (state->start <= end && state->end > end) {
-               if (!prealloc)
-                       prealloc = alloc_extent_state(GFP_ATOMIC);
+               prealloc = alloc_extent_state_atomic(prealloc);
+               BUG_ON(!prealloc);
                err = split_state(tree, state, prealloc, end + 1);
                BUG_ON(err == -EEXIST);
                if (wake)
@@ -726,8 +736,7 @@ int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
 again:
        if (!prealloc && (mask & __GFP_WAIT)) {
                prealloc = alloc_extent_state(mask);
-               if (!prealloc)
-                       return -ENOMEM;
+               BUG_ON(!prealloc);
        }
 
        spin_lock(&tree->lock);
@@ -744,6 +753,8 @@ again:
         */
        node = tree_search(tree, start);
        if (!node) {
+               prealloc = alloc_extent_state_atomic(prealloc);
+               BUG_ON(!prealloc);
                err = insert_state(tree, prealloc, start, end, &bits);
                prealloc = NULL;
                BUG_ON(err == -EEXIST);
@@ -772,20 +783,18 @@ hit_next:
                if (err)
                        goto out;
 
+               next_node = rb_next(node);
                cache_state(state, cached_state);
                merge_state(tree, state);
                if (last_end == (u64)-1)
                        goto out;
 
                start = last_end + 1;
-               if (start < end && prealloc && !need_resched()) {
-                       next_node = rb_next(node);
-                       if (next_node) {
-                               state = rb_entry(next_node, struct extent_state,
-                                                rb_node);
-                               if (state->start == start)
-                                       goto hit_next;
-                       }
+               if (next_node && start < end && prealloc && !need_resched()) {
+                       state = rb_entry(next_node, struct extent_state,
+                                        rb_node);
+                       if (state->start == start)
+                               goto hit_next;
                }
                goto search_again;
        }
@@ -812,6 +821,9 @@ hit_next:
                        err = -EEXIST;
                        goto out;
                }
+
+               prealloc = alloc_extent_state_atomic(prealloc);
+               BUG_ON(!prealloc);
                err = split_state(tree, state, prealloc, start);
                BUG_ON(err == -EEXIST);
                prealloc = NULL;
@@ -842,14 +854,25 @@ hit_next:
                        this_end = end;
                else
                        this_end = last_start - 1;
+
+               prealloc = alloc_extent_state_atomic(prealloc);
+               BUG_ON(!prealloc);
+
+               /*
+                * Avoid to free 'prealloc' if it can be merged with
+                * the later extent.
+                */
+               atomic_inc(&prealloc->refs);
                err = insert_state(tree, prealloc, start, this_end,
                                   &bits);
                BUG_ON(err == -EEXIST);
                if (err) {
+                       free_extent_state(prealloc);
                        prealloc = NULL;
                        goto out;
                }
                cache_state(prealloc, cached_state);
+               free_extent_state(prealloc);
                prealloc = NULL;
                start = this_end + 1;
                goto search_again;
@@ -866,6 +889,9 @@ hit_next:
                        err = -EEXIST;
                        goto out;
                }
+
+               prealloc = alloc_extent_state_atomic(prealloc);
+               BUG_ON(!prealloc);
                err = split_state(tree, state, prealloc, end + 1);
                BUG_ON(err == -EEXIST);
 
@@ -942,13 +968,6 @@ int set_extent_new(struct extent_io_tree *tree, u64 start, u64 end,
                              NULL, mask);
 }
 
-static int clear_extent_new(struct extent_io_tree *tree, u64 start, u64 end,
-                      gfp_t mask)
-{
-       return clear_extent_bit(tree, start, end, EXTENT_NEW, 0, 0,
-                               NULL, mask);
-}
-
 int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
                        struct extent_state **cached_state, gfp_t mask)
 {
@@ -964,11 +983,6 @@ static int clear_extent_uptodate(struct extent_io_tree *tree, u64 start,
                                cached_state, mask);
 }
 
-int wait_on_extent_writeback(struct extent_io_tree *tree, u64 start, u64 end)
-{
-       return wait_extent_bit(tree, start, end, EXTENT_WRITEBACK);
-}
-
 /*
  * either insert or lock state struct between start and end use mask to tell
  * us if waiting is desired.
@@ -1028,25 +1042,6 @@ int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask)
                                mask);
 }
 
-/*
- * helper function to set pages and extents in the tree dirty
- */
-int set_range_dirty(struct extent_io_tree *tree, u64 start, u64 end)
-{
-       unsigned long index = start >> PAGE_CACHE_SHIFT;
-       unsigned long end_index = end >> PAGE_CACHE_SHIFT;
-       struct page *page;
-
-       while (index <= end_index) {
-               page = find_get_page(tree->mapping, index);
-               BUG_ON(!page);
-               __set_page_dirty_nobuffers(page);
-               page_cache_release(page);
-               index++;
-       }
-       return 0;
-}
-
 /*
  * helper function to set both pages and extents in the tree writeback
  */
@@ -1481,7 +1476,7 @@ u64 count_range_bits(struct extent_io_tree *tree,
                        if (total_bytes >= max_bytes)
                                break;
                        if (!found) {
-                               *start = state->start;
+                               *start = max(cur_start, state->start);
                                found = 1;
                        }
                        last = state->end;
@@ -1820,46 +1815,6 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
        bio_put(bio);
 }
 
-/*
- * IO done from prepare_write is pretty simple, we just unlock
- * the structs in the extent tree when done, and set the uptodate bits
- * as appropriate.
- */
-static void end_bio_extent_preparewrite(struct bio *bio, int err)
-{
-       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
-       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
-       struct extent_io_tree *tree;
-       u64 start;
-       u64 end;
-
-       do {
-               struct page *page = bvec->bv_page;
-               struct extent_state *cached = NULL;
-               tree = &BTRFS_I(page->mapping->host)->io_tree;
-
-               start = ((u64)page->index << PAGE_CACHE_SHIFT) +
-                       bvec->bv_offset;
-               end = start + bvec->bv_len - 1;
-
-               if (--bvec >= bio->bi_io_vec)
-                       prefetchw(&bvec->bv_page->flags);
-
-               if (uptodate) {
-                       set_extent_uptodate(tree, start, end, &cached,
-                                           GFP_ATOMIC);
-               } else {
-                       ClearPageUptodate(page);
-                       SetPageError(page);
-               }
-
-               unlock_extent_cached(tree, start, end, &cached, GFP_ATOMIC);
-
-       } while (bvec >= bio->bi_io_vec);
-
-       bio_put(bio);
-}
-
 struct bio *
 btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
                gfp_t gfp_flags)
@@ -2008,7 +1963,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
        struct btrfs_ordered_extent *ordered;
        int ret;
        int nr = 0;
-       size_t page_offset = 0;
+       size_t pg_offset = 0;
        size_t iosize;
        size_t disk_io_size;
        size_t blocksize = inode->i_sb->s_blocksize;
@@ -2016,6 +1971,13 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
 
        set_page_extent_mapped(page);
 
+       if (!PageUptodate(page)) {
+               if (cleancache_get_page(page) == 0) {
+                       BUG_ON(blocksize != PAGE_SIZE);
+                       goto out;
+               }
+       }
+
        end = page_end;
        while (1) {
                lock_extent(tree, start, end, GFP_NOFS);
@@ -2044,9 +2006,9 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
                        char *userpage;
                        struct extent_state *cached = NULL;
 
-                       iosize = PAGE_CACHE_SIZE - page_offset;
+                       iosize = PAGE_CACHE_SIZE - pg_offset;
                        userpage = kmap_atomic(page, KM_USER0);
-                       memset(userpage + page_offset, 0, iosize);
+                       memset(userpage + pg_offset, 0, iosize);
                        flush_dcache_page(page);
                        kunmap_atomic(userpage, KM_USER0);
                        set_extent_uptodate(tree, cur, cur + iosize - 1,
@@ -2055,9 +2017,9 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
                                             &cached, GFP_NOFS);
                        break;
                }
-               em = get_extent(inode, page, page_offset, cur,
+               em = get_extent(inode, page, pg_offset, cur,
                                end - cur + 1, 0);
-               if (IS_ERR(em) || !em) {
+               if (IS_ERR_OR_NULL(em)) {
                        SetPageError(page);
                        unlock_extent(tree, cur, end, GFP_NOFS);
                        break;
@@ -2095,7 +2057,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
                        struct extent_state *cached = NULL;
 
                        userpage = kmap_atomic(page, KM_USER0);
-                       memset(userpage + page_offset, 0, iosize);
+                       memset(userpage + pg_offset, 0, iosize);
                        flush_dcache_page(page);
                        kunmap_atomic(userpage, KM_USER0);
 
@@ -2104,7 +2066,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
                        unlock_extent_cached(tree, cur, cur + iosize - 1,
                                             &cached, GFP_NOFS);
                        cur = cur + iosize;
-                       page_offset += iosize;
+                       pg_offset += iosize;
                        continue;
                }
                /* the get_extent function already copied into the page */
@@ -2113,7 +2075,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
                        check_page_uptodate(tree, page);
                        unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS);
                        cur = cur + iosize;
-                       page_offset += iosize;
+                       pg_offset += iosize;
                        continue;
                }
                /* we have an inline extent but it didn't get marked up
@@ -2123,7 +2085,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
                        SetPageError(page);
                        unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS);
                        cur = cur + iosize;
-                       page_offset += iosize;
+                       pg_offset += iosize;
                        continue;
                }
 
@@ -2136,7 +2098,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
                        unsigned long pnr = (last_byte >> PAGE_CACHE_SHIFT) + 1;
                        pnr -= page->index;
                        ret = submit_extent_page(READ, tree, page,
-                                        sector, disk_io_size, page_offset,
+                                        sector, disk_io_size, pg_offset,
                                         bdev, bio, pnr,
                                         end_bio_extent_readpage, mirror_num,
                                         *bio_flags,
@@ -2147,8 +2109,9 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
                if (ret)
                        SetPageError(page);
                cur = cur + iosize;
-               page_offset += iosize;
+               pg_offset += iosize;
        }
+out:
        if (!nr) {
                if (!PageError(page))
                        SetPageUptodate(page);
@@ -2342,7 +2305,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
                }
                em = epd->get_extent(inode, page, pg_offset, cur,
                                     end - cur + 1, 1);
-               if (IS_ERR(em) || !em) {
+               if (IS_ERR_OR_NULL(em)) {
                        SetPageError(page);
                        break;
                }
@@ -2720,128 +2683,6 @@ int extent_invalidatepage(struct extent_io_tree *tree,
        return 0;
 }
 
-/*
- * simple commit_write call, set_range_dirty is used to mark both
- * the pages and the extent records as dirty
- */
-int extent_commit_write(struct extent_io_tree *tree,
-                       struct inode *inode, struct page *page,
-                       unsigned from, unsigned to)
-{
-       loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
-
-       set_page_extent_mapped(page);
-       set_page_dirty(page);
-
-       if (pos > inode->i_size) {
-               i_size_write(inode, pos);
-               mark_inode_dirty(inode);
-       }
-       return 0;
-}
-
-int extent_prepare_write(struct extent_io_tree *tree,
-                        struct inode *inode, struct page *page,
-                        unsigned from, unsigned to, get_extent_t *get_extent)
-{
-       u64 page_start = (u64)page->index << PAGE_CACHE_SHIFT;
-       u64 page_end = page_start + PAGE_CACHE_SIZE - 1;
-       u64 block_start;
-       u64 orig_block_start;
-       u64 block_end;
-       u64 cur_end;
-       struct extent_map *em;
-       unsigned blocksize = 1 << inode->i_blkbits;
-       size_t page_offset = 0;
-       size_t block_off_start;
-       size_t block_off_end;
-       int err = 0;
-       int iocount = 0;
-       int ret = 0;
-       int isnew;
-
-       set_page_extent_mapped(page);
-
-       block_start = (page_start + from) & ~((u64)blocksize - 1);
-       block_end = (page_start + to - 1) | (blocksize - 1);
-       orig_block_start = block_start;
-
-       lock_extent(tree, page_start, page_end, GFP_NOFS);
-       while (block_start <= block_end) {
-               em = get_extent(inode, page, page_offset, block_start,
-                               block_end - block_start + 1, 1);
-               if (IS_ERR(em) || !em)
-                       goto err;
-
-               cur_end = min(block_end, extent_map_end(em) - 1);
-               block_off_start = block_start & (PAGE_CACHE_SIZE - 1);
-               block_off_end = block_off_start + blocksize;
-               isnew = clear_extent_new(tree, block_start, cur_end, GFP_NOFS);
-
-               if (!PageUptodate(page) && isnew &&
-                   (block_off_end > to || block_off_start < from)) {
-                       void *kaddr;
-
-                       kaddr = kmap_atomic(page, KM_USER0);
-                       if (block_off_end > to)
-                               memset(kaddr + to, 0, block_off_end - to);
-                       if (block_off_start < from)
-                               memset(kaddr + block_off_start, 0,
-                                      from - block_off_start);
-                       flush_dcache_page(page);
-                       kunmap_atomic(kaddr, KM_USER0);
-               }
-               if ((em->block_start != EXTENT_MAP_HOLE &&
-                    em->block_start != EXTENT_MAP_INLINE) &&
-                   !isnew && !PageUptodate(page) &&
-                   (block_off_end > to || block_off_start < from) &&
-                   !test_range_bit(tree, block_start, cur_end,
-                                   EXTENT_UPTODATE, 1, NULL)) {
-                       u64 sector;
-                       u64 extent_offset = block_start - em->start;
-                       size_t iosize;
-                       sector = (em->block_start + extent_offset) >> 9;
-                       iosize = (cur_end - block_start + blocksize) &
-                               ~((u64)blocksize - 1);
-                       /*
-                        * we've already got the extent locked, but we
-                        * need to split the state such that our end_bio
-                        * handler can clear the lock.
-                        */
-                       set_extent_bit(tree, block_start,
-                                      block_start + iosize - 1,
-                                      EXTENT_LOCKED, 0, NULL, NULL, GFP_NOFS);
-                       ret = submit_extent_page(READ, tree, page,
-                                        sector, iosize, page_offset, em->bdev,
-                                        NULL, 1,
-                                        end_bio_extent_preparewrite, 0,
-                                        0, 0);
-                       if (ret && !err)
-                               err = ret;
-                       iocount++;
-                       block_start = block_start + iosize;
-               } else {
-                       struct extent_state *cached = NULL;
-
-                       set_extent_uptodate(tree, block_start, cur_end, &cached,
-                                           GFP_NOFS);
-                       unlock_extent_cached(tree, block_start, cur_end,
-                                            &cached, GFP_NOFS);
-                       block_start = cur_end + 1;
-               }
-               page_offset = block_start & (PAGE_CACHE_SIZE - 1);
-               free_extent_map(em);
-       }
-       if (iocount) {
-               wait_extent_bit(tree, orig_block_start,
-                               block_end, EXTENT_LOCKED);
-       }
-       check_page_uptodate(tree, page);
-err:
-       /* FIXME, zero out newly allocated blocks on error */
-       return err;
-}
-
 /*
  * a helper for releasepage, this tests for areas of the page that
  * are locked or under IO and drops the related state bits if it is safe
@@ -2900,7 +2741,7 @@ int try_release_extent_mapping(struct extent_map_tree *map,
                        len = end - start + 1;
                        write_lock(&map->lock);
                        em = lookup_extent_mapping(map, start, len);
-                       if (!em || IS_ERR(em)) {
+                       if (IS_ERR_OR_NULL(em)) {
                                write_unlock(&map->lock);
                                break;
                        }
@@ -2928,33 +2769,6 @@ int try_release_extent_mapping(struct extent_map_tree *map,
        return try_release_extent_state(map, tree, page, mask);
 }
 
-sector_t extent_bmap(struct address_space *mapping, sector_t iblock,
-               get_extent_t *get_extent)
-{
-       struct inode *inode = mapping->host;
-       struct extent_state *cached_state = NULL;
-       u64 start = iblock << inode->i_blkbits;
-       sector_t sector = 0;
-       size_t blksize = (1 << inode->i_blkbits);
-       struct extent_map *em;
-
-       lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + blksize - 1,
-                        0, &cached_state, GFP_NOFS);
-       em = get_extent(inode, NULL, 0, start, blksize, 0);
-       unlock_extent_cached(&BTRFS_I(inode)->io_tree, start,
-                            start + blksize - 1, &cached_state, GFP_NOFS);
-       if (!em || IS_ERR(em))
-               return 0;
-
-       if (em->block_start > EXTENT_MAP_LAST_BYTE)
-               goto out;
-
-       sector = (em->block_start + start - em->start) >> inode->i_blkbits;
-out:
-       free_extent_map(em);
-       return sector;
-}
-
 /*
  * helper function for fiemap, which doesn't want to see any holes.
  * This maps until we find something past 'last'
@@ -2977,7 +2791,7 @@ static struct extent_map *get_extent_skip_holes(struct inode *inode,
                        break;
                len = (len + sectorsize - 1) & ~(sectorsize - 1);
                em = get_extent(inode, NULL, 0, offset, len, 0);
-               if (!em || IS_ERR(em))
+               if (IS_ERR_OR_NULL(em))
                        return em;
 
                /* if this isn't a hole return it */
@@ -3031,7 +2845,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
         * because there might be preallocation past i_size
         */
        ret = btrfs_lookup_file_extent(NULL, BTRFS_I(inode)->root,
-                                      path, inode->i_ino, -1, 0);
+                                      path, btrfs_ino(inode), -1, 0);
        if (ret < 0) {
                btrfs_free_path(path);
                return ret;
@@ -3044,7 +2858,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        found_type = btrfs_key_type(&found_key);
 
        /* No extents, but there might be delalloc bits */
-       if (found_key.objectid != inode->i_ino ||
+       if (found_key.objectid != btrfs_ino(inode) ||
            found_type != BTRFS_EXTENT_DATA_KEY) {
                /* have to trust i_size as the end */
                last = (u64)-1;
@@ -3267,8 +3081,7 @@ static inline void btrfs_release_extent_buffer(struct extent_buffer *eb)
 
 struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
                                          u64 start, unsigned long len,
-                                         struct page *page0,
-                                         gfp_t mask)
+                                         struct page *page0)
 {
        unsigned long num_pages = num_extent_pages(start, len);
        unsigned long i;
@@ -3289,7 +3102,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
        }
        rcu_read_unlock();
 
-       eb = __alloc_extent_buffer(tree, start, len, mask);
+       eb = __alloc_extent_buffer(tree, start, len, GFP_NOFS);
        if (!eb)
                return NULL;
 
@@ -3306,7 +3119,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
                i = 0;
        }
        for (; i < num_pages; i++, index++) {
-               p = find_or_create_page(mapping, index, mask | __GFP_HIGHMEM);
+               p = find_or_create_page(mapping, index, GFP_NOFS | __GFP_HIGHMEM);
                if (!p) {
                        WARN_ON(1);
                        goto free_eb;
@@ -3378,8 +3191,7 @@ free_eb:
 }
 
 struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree,
-                                        u64 start, unsigned long len,
-                                         gfp_t mask)
+                                        u64 start, unsigned long len)
 {
        struct extent_buffer *eb;
 
@@ -3440,13 +3252,6 @@ int clear_extent_buffer_dirty(struct extent_io_tree *tree,
        return 0;
 }
 
-int wait_on_extent_buffer_writeback(struct extent_io_tree *tree,
-                                   struct extent_buffer *eb)
-{
-       return wait_on_extent_writeback(tree, eb->start,
-                                       eb->start + eb->len - 1);
-}
-
 int set_extent_buffer_dirty(struct extent_io_tree *tree,
                             struct extent_buffer *eb)
 {
index af2d7179c37288f50371bfd2ffa5dd307b16af00..a11a92ee2d30a84ccf52284e704c5cc971f7126e 100644 (file)
@@ -126,9 +126,9 @@ struct extent_buffer {
        unsigned long map_len;
        struct page *first_page;
        unsigned long bflags;
-       atomic_t refs;
        struct list_head leak_list;
        struct rcu_head rcu_head;
+       atomic_t refs;
 
        /* the spinlock is used to protect most operations */
        spinlock_t lock;
@@ -153,23 +153,14 @@ static inline int extent_compress_type(unsigned long bio_flags)
 
 struct extent_map_tree;
 
-static inline struct extent_state *extent_state_next(struct extent_state *state)
-{
-       struct rb_node *node;
-       node = rb_next(&state->rb_node);
-       if (!node)
-               return NULL;
-       return rb_entry(node, struct extent_state, rb_node);
-}
-
 typedef struct extent_map *(get_extent_t)(struct inode *inode,
                                          struct page *page,
-                                         size_t page_offset,
+                                         size_t pg_offset,
                                          u64 start, u64 len,
                                          int create);
 
 void extent_io_tree_init(struct extent_io_tree *tree,
-                         struct address_space *mapping, gfp_t mask);
+                        struct address_space *mapping);
 int try_release_extent_mapping(struct extent_map_tree *map,
                               struct extent_io_tree *tree, struct page *page,
                               gfp_t mask);
@@ -215,14 +206,8 @@ int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
                     gfp_t mask);
 int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
                       gfp_t mask);
-int clear_extent_ordered(struct extent_io_tree *tree, u64 start, u64 end,
-                      gfp_t mask);
-int clear_extent_ordered_metadata(struct extent_io_tree *tree, u64 start,
-                                 u64 end, gfp_t mask);
 int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end,
                        struct extent_state **cached_state, gfp_t mask);
-int set_extent_ordered(struct extent_io_tree *tree, u64 start, u64 end,
-                    gfp_t mask);
 int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
                          u64 *start_ret, u64 *end_ret, int bits);
 struct extent_state *find_first_extent_bit_state(struct extent_io_tree *tree,
@@ -243,28 +228,17 @@ int extent_readpages(struct extent_io_tree *tree,
                     struct address_space *mapping,
                     struct list_head *pages, unsigned nr_pages,
                     get_extent_t get_extent);
-int extent_prepare_write(struct extent_io_tree *tree,
-                        struct inode *inode, struct page *page,
-                        unsigned from, unsigned to, get_extent_t *get_extent);
-int extent_commit_write(struct extent_io_tree *tree,
-                       struct inode *inode, struct page *page,
-                       unsigned from, unsigned to);
-sector_t extent_bmap(struct address_space *mapping, sector_t iblock,
-               get_extent_t *get_extent);
 int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                __u64 start, __u64 len, get_extent_t *get_extent);
-int set_range_dirty(struct extent_io_tree *tree, u64 start, u64 end);
 int set_state_private(struct extent_io_tree *tree, u64 start, u64 private);
 int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private);
 void set_page_extent_mapped(struct page *page);
 
 struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
                                          u64 start, unsigned long len,
-                                         struct page *page0,
-                                         gfp_t mask);
+                                         struct page *page0);
 struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree,
-                                        u64 start, unsigned long len,
-                                         gfp_t mask);
+                                        u64 start, unsigned long len);
 void free_extent_buffer(struct extent_buffer *eb);
 int read_extent_buffer_pages(struct extent_io_tree *tree,
                             struct extent_buffer *eb, u64 start, int wait,
@@ -292,16 +266,11 @@ void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
                           unsigned long src_offset, unsigned long len);
 void memset_extent_buffer(struct extent_buffer *eb, char c,
                          unsigned long start, unsigned long len);
-int wait_on_extent_buffer_writeback(struct extent_io_tree *tree,
-                                   struct extent_buffer *eb);
-int wait_on_extent_writeback(struct extent_io_tree *tree, u64 start, u64 end);
 int wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits);
 int clear_extent_buffer_dirty(struct extent_io_tree *tree,
                              struct extent_buffer *eb);
 int set_extent_buffer_dirty(struct extent_io_tree *tree,
                             struct extent_buffer *eb);
-int test_extent_buffer_dirty(struct extent_io_tree *tree,
-                            struct extent_buffer *eb);
 int set_extent_buffer_uptodate(struct extent_io_tree *tree,
                               struct extent_buffer *eb);
 int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
@@ -319,7 +288,6 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset,
                      unsigned long *map_start,
                      unsigned long *map_len, int km);
 void unmap_extent_buffer(struct extent_buffer *eb, char *token, int km);
-int release_extent_buffer_tail_pages(struct extent_buffer *eb);
 int extent_range_uptodate(struct extent_io_tree *tree,
                          u64 start, u64 end);
 int extent_clear_unlock_delalloc(struct inode *inode,
index a24a3f2fa13e6fe4a1670073933aa1de61490dc4..2d0410344ea3667a7d505b2c543e7ba212dd01ae 100644 (file)
@@ -28,12 +28,11 @@ void extent_map_exit(void)
 /**
  * extent_map_tree_init - initialize extent map tree
  * @tree:              tree to initialize
- * @mask:              flags for memory allocations during tree operations
  *
  * Initialize the extent tree @tree.  Should be called for each new inode
  * or other user of the extent_map interface.
  */
-void extent_map_tree_init(struct extent_map_tree *tree, gfp_t mask)
+void extent_map_tree_init(struct extent_map_tree *tree)
 {
        tree->map = RB_ROOT;
        rwlock_init(&tree->lock);
@@ -41,16 +40,15 @@ void extent_map_tree_init(struct extent_map_tree *tree, gfp_t mask)
 
 /**
  * alloc_extent_map - allocate new extent map structure
- * @mask:      memory allocation flags
  *
  * Allocate a new extent_map structure.  The new structure is
  * returned with a reference count of one and needs to be
  * freed using free_extent_map()
  */
-struct extent_map *alloc_extent_map(gfp_t mask)
+struct extent_map *alloc_extent_map(void)
 {
        struct extent_map *em;
-       em = kmem_cache_alloc(extent_map_cache, mask);
+       em = kmem_cache_alloc(extent_map_cache, GFP_NOFS);
        if (!em)
                return NULL;
        em->in_tree = 0;
index 28b44dbd1e3508c37bd30a1ef990fd071b1096d0..33a7890b1f4091479df52d7a13c1532ba911ce76 100644 (file)
@@ -49,14 +49,14 @@ static inline u64 extent_map_block_end(struct extent_map *em)
        return em->block_start + em->block_len;
 }
 
-void extent_map_tree_init(struct extent_map_tree *tree, gfp_t mask);
+void extent_map_tree_init(struct extent_map_tree *tree);
 struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,
                                         u64 start, u64 len);
 int add_extent_mapping(struct extent_map_tree *tree,
                       struct extent_map *em);
 int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em);
 
-struct extent_map *alloc_extent_map(gfp_t mask);
+struct extent_map *alloc_extent_map(void);
 void free_extent_map(struct extent_map *em);
 int __init extent_map_init(void);
 void extent_map_exit(void);
index a6a9d4e8b491eee488316c97f6f975e167bf13db..90d4ee52cd458ac9f7bf87dfe4a34c99be27bc30 100644 (file)
@@ -193,7 +193,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
                        u32 item_size;
 
                        if (item)
-                               btrfs_release_path(root, path);
+                               btrfs_release_path(path);
                        item = btrfs_lookup_csum(NULL, root->fs_info->csum_root,
                                                 path, disk_bytenr, 0);
                        if (IS_ERR(item)) {
@@ -208,12 +208,13 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
                                                EXTENT_NODATASUM, GFP_NOFS);
                                } else {
                                        printk(KERN_INFO "btrfs no csum found "
-                                              "for inode %lu start %llu\n",
-                                              inode->i_ino,
+                                              "for inode %llu start %llu\n",
+                                              (unsigned long long)
+                                              btrfs_ino(inode),
                                               (unsigned long long)offset);
                                }
                                item = NULL;
-                               btrfs_release_path(root, path);
+                               btrfs_release_path(path);
                                goto found;
                        }
                        btrfs_item_key_to_cpu(path->nodes[0], &found_key,
@@ -266,7 +267,7 @@ int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode,
 }
 
 int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
-                            struct list_head *list)
+                            struct list_head *list, int search_commit)
 {
        struct btrfs_key key;
        struct btrfs_path *path;
@@ -283,6 +284,12 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
        path = btrfs_alloc_path();
        BUG_ON(!path);
 
+       if (search_commit) {
+               path->skip_locking = 1;
+               path->reada = 2;
+               path->search_commit_root = 1;
+       }
+
        key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
        key.offset = start;
        key.type = BTRFS_EXTENT_CSUM_KEY;
@@ -495,7 +502,6 @@ static noinline int truncate_one_csum(struct btrfs_trans_handle *trans,
                u32 new_size = (bytenr - key->offset) >> blocksize_bits;
                new_size *= csum_size;
                ret = btrfs_truncate_item(trans, root, path, new_size, 1);
-               BUG_ON(ret);
        } else if (key->offset >= bytenr && csum_end > end_byte &&
                   end_byte > key->offset) {
                /*
@@ -508,7 +514,6 @@ static noinline int truncate_one_csum(struct btrfs_trans_handle *trans,
                new_size *= csum_size;
 
                ret = btrfs_truncate_item(trans, root, path, new_size, 0);
-               BUG_ON(ret);
 
                key->offset = end_byte;
                ret = btrfs_set_item_key_safe(trans, root, path, key);
@@ -551,10 +556,10 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
                ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
                if (ret > 0) {
                        if (path->slots[0] == 0)
-                               goto out;
+                               break;
                        path->slots[0]--;
                } else if (ret < 0) {
-                       goto out;
+                       break;
                }
 
                leaf = path->nodes[0];
@@ -579,7 +584,8 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
                /* delete the entire item, it is inside our range */
                if (key.offset >= bytenr && csum_end <= end_byte) {
                        ret = btrfs_del_item(trans, root, path);
-                       BUG_ON(ret);
+                       if (ret)
+                               goto out;
                        if (key.offset == bytenr)
                                break;
                } else if (key.offset < bytenr && csum_end > end_byte) {
@@ -631,11 +637,12 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
                        if (key.offset < bytenr)
                                break;
                }
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
        }
+       ret = 0;
 out:
        btrfs_free_path(path);
-       return 0;
+       return ret;
 }
 
 int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
@@ -722,7 +729,7 @@ again:
         * at this point, we know the tree has an item, but it isn't big
         * enough yet to put our csum in.  Grow it
         */
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        ret = btrfs_search_slot(trans, root, &file_key, path,
                                csum_size, 1);
        if (ret < 0)
@@ -761,12 +768,11 @@ again:
                        goto insert;
 
                ret = btrfs_extend_item(trans, root, path, diff);
-               BUG_ON(ret);
                goto csum;
        }
 
 insert:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        csum_offset = 0;
        if (found_next) {
                u64 tmp = total_bytes + root->sectorsize;
@@ -850,7 +856,7 @@ next_sector:
        }
        btrfs_mark_buffer_dirty(path->nodes[0]);
        if (total_bytes < sums->len) {
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                cond_resched();
                goto again;
        }
index 75899a01dded75042b4c99f15a44cc83882730a4..fa4ef18b66b150a975d4143288b1de699dc0ecf0 100644 (file)
 #include "locking.h"
 #include "compat.h"
 
+/*
+ * when auto defrag is enabled we
+ * queue up these defrag structs to remember which
+ * inodes need defragging passes
+ */
+struct inode_defrag {
+       struct rb_node rb_node;
+       /* objectid */
+       u64 ino;
+       /*
+        * transid where the defrag was added, we search for
+        * extents newer than this
+        */
+       u64 transid;
+
+       /* root objectid */
+       u64 root;
+
+       /* last offset we were able to defrag */
+       u64 last_offset;
+
+       /* if we've wrapped around back to zero once already */
+       int cycled;
+};
+
+/* pop a record for an inode into the defrag tree.  The lock
+ * must be held already
+ *
+ * If you're inserting a record for an older transid than an
+ * existing record, the transid already in the tree is lowered
+ *
+ * If an existing record is found the defrag item you
+ * pass in is freed
+ */
+static int __btrfs_add_inode_defrag(struct inode *inode,
+                                   struct inode_defrag *defrag)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct inode_defrag *entry;
+       struct rb_node **p;
+       struct rb_node *parent = NULL;
+
+       p = &root->fs_info->defrag_inodes.rb_node;
+       while (*p) {
+               parent = *p;
+               entry = rb_entry(parent, struct inode_defrag, rb_node);
+
+               if (defrag->ino < entry->ino)
+                       p = &parent->rb_left;
+               else if (defrag->ino > entry->ino)
+                       p = &parent->rb_right;
+               else {
+                       /* if we're reinserting an entry for
+                        * an old defrag run, make sure to
+                        * lower the transid of our existing record
+                        */
+                       if (defrag->transid < entry->transid)
+                               entry->transid = defrag->transid;
+                       if (defrag->last_offset > entry->last_offset)
+                               entry->last_offset = defrag->last_offset;
+                       goto exists;
+               }
+       }
+       BTRFS_I(inode)->in_defrag = 1;
+       rb_link_node(&defrag->rb_node, parent, p);
+       rb_insert_color(&defrag->rb_node, &root->fs_info->defrag_inodes);
+       return 0;
+
+exists:
+       kfree(defrag);
+       return 0;
+
+}
+
+/*
+ * insert a defrag record for this inode if auto defrag is
+ * enabled
+ */
+int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
+                          struct inode *inode)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct inode_defrag *defrag;
+       int ret = 0;
+       u64 transid;
+
+       if (!btrfs_test_opt(root, AUTO_DEFRAG))
+               return 0;
+
+       if (btrfs_fs_closing(root->fs_info))
+               return 0;
+
+       if (BTRFS_I(inode)->in_defrag)
+               return 0;
+
+       if (trans)
+               transid = trans->transid;
+       else
+               transid = BTRFS_I(inode)->root->last_trans;
+
+       defrag = kzalloc(sizeof(*defrag), GFP_NOFS);
+       if (!defrag)
+               return -ENOMEM;
+
+       defrag->ino = btrfs_ino(inode);
+       defrag->transid = transid;
+       defrag->root = root->root_key.objectid;
+
+       spin_lock(&root->fs_info->defrag_inodes_lock);
+       if (!BTRFS_I(inode)->in_defrag)
+               ret = __btrfs_add_inode_defrag(inode, defrag);
+       spin_unlock(&root->fs_info->defrag_inodes_lock);
+       return ret;
+}
+
+/*
+ * must be called with the defrag_inodes lock held
+ */
+struct inode_defrag *btrfs_find_defrag_inode(struct btrfs_fs_info *info, u64 ino,
+                                            struct rb_node **next)
+{
+       struct inode_defrag *entry = NULL;
+       struct rb_node *p;
+       struct rb_node *parent = NULL;
+
+       p = info->defrag_inodes.rb_node;
+       while (p) {
+               parent = p;
+               entry = rb_entry(parent, struct inode_defrag, rb_node);
+
+               if (ino < entry->ino)
+                       p = parent->rb_left;
+               else if (ino > entry->ino)
+                       p = parent->rb_right;
+               else
+                       return entry;
+       }
+
+       if (next) {
+               while (parent && ino > entry->ino) {
+                       parent = rb_next(parent);
+                       entry = rb_entry(parent, struct inode_defrag, rb_node);
+               }
+               *next = parent;
+       }
+       return NULL;
+}
+
+/*
+ * run through the list of inodes in the FS that need
+ * defragging
+ */
+int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info)
+{
+       struct inode_defrag *defrag;
+       struct btrfs_root *inode_root;
+       struct inode *inode;
+       struct rb_node *n;
+       struct btrfs_key key;
+       struct btrfs_ioctl_defrag_range_args range;
+       u64 first_ino = 0;
+       int num_defrag;
+       int defrag_batch = 1024;
+
+       memset(&range, 0, sizeof(range));
+       range.len = (u64)-1;
+
+       atomic_inc(&fs_info->defrag_running);
+       spin_lock(&fs_info->defrag_inodes_lock);
+       while(1) {
+               n = NULL;
+
+               /* find an inode to defrag */
+               defrag = btrfs_find_defrag_inode(fs_info, first_ino, &n);
+               if (!defrag) {
+                       if (n)
+                               defrag = rb_entry(n, struct inode_defrag, rb_node);
+                       else if (first_ino) {
+                               first_ino = 0;
+                               continue;
+                       } else {
+                               break;
+                       }
+               }
+
+               /* remove it from the rbtree */
+               first_ino = defrag->ino + 1;
+               rb_erase(&defrag->rb_node, &fs_info->defrag_inodes);
+
+               if (btrfs_fs_closing(fs_info))
+                       goto next_free;
+
+               spin_unlock(&fs_info->defrag_inodes_lock);
+
+               /* get the inode */
+               key.objectid = defrag->root;
+               btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
+               key.offset = (u64)-1;
+               inode_root = btrfs_read_fs_root_no_name(fs_info, &key);
+               if (IS_ERR(inode_root))
+                       goto next;
+
+               key.objectid = defrag->ino;
+               btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
+               key.offset = 0;
+
+               inode = btrfs_iget(fs_info->sb, &key, inode_root, NULL);
+               if (IS_ERR(inode))
+                       goto next;
+
+               /* do a chunk of defrag */
+               BTRFS_I(inode)->in_defrag = 0;
+               range.start = defrag->last_offset;
+               num_defrag = btrfs_defrag_file(inode, NULL, &range, defrag->transid,
+                                              defrag_batch);
+               /*
+                * if we filled the whole defrag batch, there
+                * must be more work to do.  Queue this defrag
+                * again
+                */
+               if (num_defrag == defrag_batch) {
+                       defrag->last_offset = range.start;
+                       __btrfs_add_inode_defrag(inode, defrag);
+                       /*
+                        * we don't want to kfree defrag, we added it back to
+                        * the rbtree
+                        */
+                       defrag = NULL;
+               } else if (defrag->last_offset && !defrag->cycled) {
+                       /*
+                        * we didn't fill our defrag batch, but
+                        * we didn't start at zero.  Make sure we loop
+                        * around to the start of the file.
+                        */
+                       defrag->last_offset = 0;
+                       defrag->cycled = 1;
+                       __btrfs_add_inode_defrag(inode, defrag);
+                       defrag = NULL;
+               }
+
+               iput(inode);
+next:
+               spin_lock(&fs_info->defrag_inodes_lock);
+next_free:
+               kfree(defrag);
+       }
+       spin_unlock(&fs_info->defrag_inodes_lock);
+
+       atomic_dec(&fs_info->defrag_running);
+
+       /*
+        * during unmount, we use the transaction_wait queue to
+        * wait for the defragger to stop
+        */
+       wake_up(&fs_info->transaction_wait);
+       return 0;
+}
 
 /* simple helper to fault in pages and copy.  This should go away
  * and be replaced with calls into generic code.
@@ -191,9 +448,9 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
        }
        while (1) {
                if (!split)
-                       split = alloc_extent_map(GFP_NOFS);
+                       split = alloc_extent_map();
                if (!split2)
-                       split2 = alloc_extent_map(GFP_NOFS);
+                       split2 = alloc_extent_map();
                BUG_ON(!split || !split2);
 
                write_lock(&em_tree->lock);
@@ -298,6 +555,7 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
        struct btrfs_path *path;
        struct btrfs_key key;
        struct btrfs_key new_key;
+       u64 ino = btrfs_ino(inode);
        u64 search_start = start;
        u64 disk_bytenr = 0;
        u64 num_bytes = 0;
@@ -318,14 +576,14 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
 
        while (1) {
                recow = 0;
-               ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino,
+               ret = btrfs_lookup_file_extent(trans, root, path, ino,
                                               search_start, -1);
                if (ret < 0)
                        break;
                if (ret > 0 && path->slots[0] > 0 && search_start == start) {
                        leaf = path->nodes[0];
                        btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1);
-                       if (key.objectid == inode->i_ino &&
+                       if (key.objectid == ino &&
                            key.type == BTRFS_EXTENT_DATA_KEY)
                                path->slots[0]--;
                }
@@ -346,7 +604,7 @@ next_slot:
                }
 
                btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
-               if (key.objectid > inode->i_ino ||
+               if (key.objectid > ino ||
                    key.type > BTRFS_EXTENT_DATA_KEY || key.offset >= end)
                        break;
 
@@ -376,7 +634,7 @@ next_slot:
 
                search_start = max(key.offset, start);
                if (recow) {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        continue;
                }
 
@@ -393,7 +651,7 @@ next_slot:
                        ret = btrfs_duplicate_item(trans, root, path,
                                                   &new_key);
                        if (ret == -EAGAIN) {
-                               btrfs_release_path(root, path);
+                               btrfs_release_path(path);
                                continue;
                        }
                        if (ret < 0)
@@ -516,7 +774,7 @@ next_slot:
                        del_nr = 0;
                        del_slot = 0;
 
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        continue;
                }
 
@@ -592,6 +850,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
        int del_slot = 0;
        int recow;
        int ret;
+       u64 ino = btrfs_ino(inode);
 
        btrfs_drop_extent_cache(inode, start, end - 1, 0);
 
@@ -600,7 +859,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
 again:
        recow = 0;
        split = start;
-       key.objectid = inode->i_ino;
+       key.objectid = ino;
        key.type = BTRFS_EXTENT_DATA_KEY;
        key.offset = split;
 
@@ -612,8 +871,7 @@ again:
 
        leaf = path->nodes[0];
        btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
-       BUG_ON(key.objectid != inode->i_ino ||
-              key.type != BTRFS_EXTENT_DATA_KEY);
+       BUG_ON(key.objectid != ino || key.type != BTRFS_EXTENT_DATA_KEY);
        fi = btrfs_item_ptr(leaf, path->slots[0],
                            struct btrfs_file_extent_item);
        BUG_ON(btrfs_file_extent_type(leaf, fi) !=
@@ -630,7 +888,7 @@ again:
                other_start = 0;
                other_end = start;
                if (extent_mergeable(leaf, path->slots[0] - 1,
-                                    inode->i_ino, bytenr, orig_offset,
+                                    ino, bytenr, orig_offset,
                                     &other_start, &other_end)) {
                        new_key.offset = end;
                        btrfs_set_item_key_safe(trans, root, path, &new_key);
@@ -653,7 +911,7 @@ again:
                other_start = end;
                other_end = 0;
                if (extent_mergeable(leaf, path->slots[0] + 1,
-                                    inode->i_ino, bytenr, orig_offset,
+                                    ino, bytenr, orig_offset,
                                     &other_start, &other_end)) {
                        fi = btrfs_item_ptr(leaf, path->slots[0],
                                            struct btrfs_file_extent_item);
@@ -681,7 +939,7 @@ again:
                new_key.offset = split;
                ret = btrfs_duplicate_item(trans, root, path, &new_key);
                if (ret == -EAGAIN) {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        goto again;
                }
                BUG_ON(ret < 0);
@@ -702,7 +960,7 @@ again:
 
                ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0,
                                           root->root_key.objectid,
-                                          inode->i_ino, orig_offset);
+                                          ino, orig_offset);
                BUG_ON(ret);
 
                if (split == start) {
@@ -718,10 +976,10 @@ again:
        other_start = end;
        other_end = 0;
        if (extent_mergeable(leaf, path->slots[0] + 1,
-                            inode->i_ino, bytenr, orig_offset,
+                            ino, bytenr, orig_offset,
                             &other_start, &other_end)) {
                if (recow) {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        goto again;
                }
                extent_end = other_end;
@@ -729,16 +987,16 @@ again:
                del_nr++;
                ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
                                        0, root->root_key.objectid,
-                                       inode->i_ino, orig_offset);
+                                       ino, orig_offset);
                BUG_ON(ret);
        }
        other_start = 0;
        other_end = start;
        if (extent_mergeable(leaf, path->slots[0] - 1,
-                            inode->i_ino, bytenr, orig_offset,
+                            ino, bytenr, orig_offset,
                             &other_start, &other_end)) {
                if (recow) {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        goto again;
                }
                key.offset = other_start;
@@ -746,7 +1004,7 @@ again:
                del_nr++;
                ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
                                        0, root->root_key.objectid,
-                                       inode->i_ino, orig_offset);
+                                       ino, orig_offset);
                BUG_ON(ret);
        }
        if (del_nr == 0) {
@@ -1222,14 +1480,12 @@ int btrfs_sync_file(struct file *file, int datasync)
         * the current transaction, we can bail out now without any
         * syncing
         */
-       mutex_lock(&root->fs_info->trans_mutex);
+       smp_mb();
        if (BTRFS_I(inode)->last_trans <=
            root->fs_info->last_trans_committed) {
                BTRFS_I(inode)->last_trans = 0;
-               mutex_unlock(&root->fs_info->trans_mutex);
                goto out;
        }
-       mutex_unlock(&root->fs_info->trans_mutex);
 
        /*
         * ok we haven't committed the transaction yet, lets do a commit
@@ -1375,7 +1631,7 @@ static long btrfs_fallocate(struct file *file, int mode,
        while (1) {
                em = btrfs_get_extent(inode, NULL, 0, cur_offset,
                                      alloc_end - cur_offset, 0);
-               BUG_ON(IS_ERR(em) || !em);
+               BUG_ON(IS_ERR_OR_NULL(em));
                last_byte = min(extent_map_end(em), alloc_end);
                last_byte = (last_byte + mask) & ~mask;
                if (em->block_start == EXTENT_MAP_HOLE ||
index 63731a1fb0a1f9004e892a31e121ae977a9eff3a..9f985a429877fdd5d04100514f3ff4a5f2abeb18 100644 (file)
 #include "transaction.h"
 #include "disk-io.h"
 #include "extent_io.h"
+#include "inode-map.h"
 
 #define BITS_PER_BITMAP                (PAGE_CACHE_SIZE * 8)
 #define MAX_CACHE_BYTES_PER_GIG        (32 * 1024)
 
-static void recalculate_thresholds(struct btrfs_block_group_cache
-                                  *block_group);
-static int link_free_space(struct btrfs_block_group_cache *block_group,
+static int link_free_space(struct btrfs_free_space_ctl *ctl,
                           struct btrfs_free_space *info);
 
-struct inode *lookup_free_space_inode(struct btrfs_root *root,
-                                     struct btrfs_block_group_cache
-                                     *block_group, struct btrfs_path *path)
+static struct inode *__lookup_free_space_inode(struct btrfs_root *root,
+                                              struct btrfs_path *path,
+                                              u64 offset)
 {
        struct btrfs_key key;
        struct btrfs_key location;
@@ -46,22 +45,15 @@ struct inode *lookup_free_space_inode(struct btrfs_root *root,
        struct inode *inode = NULL;
        int ret;
 
-       spin_lock(&block_group->lock);
-       if (block_group->inode)
-               inode = igrab(block_group->inode);
-       spin_unlock(&block_group->lock);
-       if (inode)
-               return inode;
-
        key.objectid = BTRFS_FREE_SPACE_OBJECTID;
-       key.offset = block_group->key.objectid;
+       key.offset = offset;
        key.type = 0;
 
        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
        if (ret < 0)
                return ERR_PTR(ret);
        if (ret > 0) {
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                return ERR_PTR(-ENOENT);
        }
 
@@ -70,7 +62,7 @@ struct inode *lookup_free_space_inode(struct btrfs_root *root,
                                struct btrfs_free_space_header);
        btrfs_free_space_key(leaf, header, &disk_key);
        btrfs_disk_key_to_cpu(&location, &disk_key);
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        inode = btrfs_iget(root->fs_info->sb, &location, root, NULL);
        if (!inode)
@@ -84,8 +76,29 @@ struct inode *lookup_free_space_inode(struct btrfs_root *root,
 
        inode->i_mapping->flags &= ~__GFP_FS;
 
+       return inode;
+}
+
+struct inode *lookup_free_space_inode(struct btrfs_root *root,
+                                     struct btrfs_block_group_cache
+                                     *block_group, struct btrfs_path *path)
+{
+       struct inode *inode = NULL;
+
        spin_lock(&block_group->lock);
-       if (!root->fs_info->closing) {
+       if (block_group->inode)
+               inode = igrab(block_group->inode);
+       spin_unlock(&block_group->lock);
+       if (inode)
+               return inode;
+
+       inode = __lookup_free_space_inode(root, path,
+                                         block_group->key.objectid);
+       if (IS_ERR(inode))
+               return inode;
+
+       spin_lock(&block_group->lock);
+       if (!btrfs_fs_closing(root->fs_info)) {
                block_group->inode = igrab(inode);
                block_group->iref = 1;
        }
@@ -94,24 +107,18 @@ struct inode *lookup_free_space_inode(struct btrfs_root *root,
        return inode;
 }
 
-int create_free_space_inode(struct btrfs_root *root,
-                           struct btrfs_trans_handle *trans,
-                           struct btrfs_block_group_cache *block_group,
-                           struct btrfs_path *path)
+int __create_free_space_inode(struct btrfs_root *root,
+                             struct btrfs_trans_handle *trans,
+                             struct btrfs_path *path, u64 ino, u64 offset)
 {
        struct btrfs_key key;
        struct btrfs_disk_key disk_key;
        struct btrfs_free_space_header *header;
        struct btrfs_inode_item *inode_item;
        struct extent_buffer *leaf;
-       u64 objectid;
        int ret;
 
-       ret = btrfs_find_free_objectid(trans, root, 0, &objectid);
-       if (ret < 0)
-               return ret;
-
-       ret = btrfs_insert_empty_inode(trans, root, path, objectid);
+       ret = btrfs_insert_empty_inode(trans, root, path, ino);
        if (ret)
                return ret;
 
@@ -131,19 +138,18 @@ int create_free_space_inode(struct btrfs_root *root,
                              BTRFS_INODE_PREALLOC | BTRFS_INODE_NODATASUM);
        btrfs_set_inode_nlink(leaf, inode_item, 1);
        btrfs_set_inode_transid(leaf, inode_item, trans->transid);
-       btrfs_set_inode_block_group(leaf, inode_item,
-                                   block_group->key.objectid);
+       btrfs_set_inode_block_group(leaf, inode_item, offset);
        btrfs_mark_buffer_dirty(leaf);
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        key.objectid = BTRFS_FREE_SPACE_OBJECTID;
-       key.offset = block_group->key.objectid;
+       key.offset = offset;
        key.type = 0;
 
        ret = btrfs_insert_empty_item(trans, root, path, &key,
                                      sizeof(struct btrfs_free_space_header));
        if (ret < 0) {
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                return ret;
        }
        leaf = path->nodes[0];
@@ -152,11 +158,27 @@ int create_free_space_inode(struct btrfs_root *root,
        memset_extent_buffer(leaf, 0, (unsigned long)header, sizeof(*header));
        btrfs_set_free_space_key(leaf, header, &disk_key);
        btrfs_mark_buffer_dirty(leaf);
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        return 0;
 }
 
+int create_free_space_inode(struct btrfs_root *root,
+                           struct btrfs_trans_handle *trans,
+                           struct btrfs_block_group_cache *block_group,
+                           struct btrfs_path *path)
+{
+       int ret;
+       u64 ino;
+
+       ret = btrfs_find_free_objectid(root, &ino);
+       if (ret < 0)
+               return ret;
+
+       return __create_free_space_inode(root, trans, path, ino,
+                                        block_group->key.objectid);
+}
+
 int btrfs_truncate_free_space_cache(struct btrfs_root *root,
                                    struct btrfs_trans_handle *trans,
                                    struct btrfs_path *path,
@@ -187,7 +209,8 @@ int btrfs_truncate_free_space_cache(struct btrfs_root *root,
                return ret;
        }
 
-       return btrfs_update_inode(trans, root, inode);
+       ret = btrfs_update_inode(trans, root, inode);
+       return ret;
 }
 
 static int readahead_cache(struct inode *inode)
@@ -209,15 +232,13 @@ static int readahead_cache(struct inode *inode)
        return 0;
 }
 
-int load_free_space_cache(struct btrfs_fs_info *fs_info,
-                         struct btrfs_block_group_cache *block_group)
+int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
+                           struct btrfs_free_space_ctl *ctl,
+                           struct btrfs_path *path, u64 offset)
 {
-       struct btrfs_root *root = fs_info->tree_root;
-       struct inode *inode;
        struct btrfs_free_space_header *header;
        struct extent_buffer *leaf;
        struct page *page;
-       struct btrfs_path *path;
        u32 *checksums = NULL, *crc;
        char *disk_crcs = NULL;
        struct btrfs_key key;
@@ -225,76 +246,47 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
        u64 num_entries;
        u64 num_bitmaps;
        u64 generation;
-       u64 used = btrfs_block_group_used(&block_group->item);
        u32 cur_crc = ~(u32)0;
        pgoff_t index = 0;
        unsigned long first_page_offset;
        int num_checksums;
        int ret = 0;
 
-       /*
-        * If we're unmounting then just return, since this does a search on the
-        * normal root and not the commit root and we could deadlock.
-        */
-       smp_mb();
-       if (fs_info->closing)
-               return 0;
-
-       /*
-        * If this block group has been marked to be cleared for one reason or
-        * another then we can't trust the on disk cache, so just return.
-        */
-       spin_lock(&block_group->lock);
-       if (block_group->disk_cache_state != BTRFS_DC_WRITTEN) {
-               spin_unlock(&block_group->lock);
-               return 0;
-       }
-       spin_unlock(&block_group->lock);
-
        INIT_LIST_HEAD(&bitmaps);
 
-       path = btrfs_alloc_path();
-       if (!path)
-               return 0;
-
-       inode = lookup_free_space_inode(root, block_group, path);
-       if (IS_ERR(inode)) {
-               btrfs_free_path(path);
-               return 0;
-       }
-
        /* Nothing in the space cache, goodbye */
-       if (!i_size_read(inode)) {
-               btrfs_free_path(path);
+       if (!i_size_read(inode))
                goto out;
-       }
 
        key.objectid = BTRFS_FREE_SPACE_OBJECTID;
-       key.offset = block_group->key.objectid;
+       key.offset = offset;
        key.type = 0;
 
        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
-       if (ret) {
-               btrfs_free_path(path);
+       if (ret < 0)
+               goto out;
+       else if (ret > 0) {
+               btrfs_release_path(path);
+               ret = 0;
                goto out;
        }
 
+       ret = -1;
+
        leaf = path->nodes[0];
        header = btrfs_item_ptr(leaf, path->slots[0],
                                struct btrfs_free_space_header);
        num_entries = btrfs_free_space_entries(leaf, header);
        num_bitmaps = btrfs_free_space_bitmaps(leaf, header);
        generation = btrfs_free_space_generation(leaf, header);
-       btrfs_free_path(path);
+       btrfs_release_path(path);
 
        if (BTRFS_I(inode)->generation != generation) {
                printk(KERN_ERR "btrfs: free space inode generation (%llu) did"
-                      " not match free space cache generation (%llu) for "
-                      "block group %llu\n",
+                      " not match free space cache generation (%llu)\n",
                       (unsigned long long)BTRFS_I(inode)->generation,
-                      (unsigned long long)generation,
-                      (unsigned long long)block_group->key.objectid);
-               goto free_cache;
+                      (unsigned long long)generation);
+               goto out;
        }
 
        if (!num_entries)
@@ -311,10 +303,8 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
                goto out;
 
        ret = readahead_cache(inode);
-       if (ret) {
-               ret = 0;
+       if (ret)
                goto out;
-       }
 
        while (1) {
                struct btrfs_free_space_entry *entry;
@@ -333,10 +323,8 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
                }
 
                page = grab_cache_page(inode->i_mapping, index);
-               if (!page) {
-                       ret = 0;
+               if (!page)
                        goto free_cache;
-               }
 
                if (!PageUptodate(page)) {
                        btrfs_readpage(NULL, page);
@@ -345,9 +333,7 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
                                unlock_page(page);
                                page_cache_release(page);
                                printk(KERN_ERR "btrfs: error reading free "
-                                      "space cache: %llu\n",
-                                      (unsigned long long)
-                                      block_group->key.objectid);
+                                      "space cache\n");
                                goto free_cache;
                        }
                }
@@ -360,13 +346,10 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
                        gen = addr + (sizeof(u32) * num_checksums);
                        if (*gen != BTRFS_I(inode)->generation) {
                                printk(KERN_ERR "btrfs: space cache generation"
-                                      " (%llu) does not match inode (%llu) "
-                                      "for block group %llu\n",
+                                      " (%llu) does not match inode (%llu)\n",
                                       (unsigned long long)*gen,
                                       (unsigned long long)
-                                      BTRFS_I(inode)->generation,
-                                      (unsigned long long)
-                                      block_group->key.objectid);
+                                      BTRFS_I(inode)->generation);
                                kunmap(page);
                                unlock_page(page);
                                page_cache_release(page);
@@ -382,9 +365,8 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
                                          PAGE_CACHE_SIZE - start_offset);
                btrfs_csum_final(cur_crc, (char *)&cur_crc);
                if (cur_crc != *crc) {
-                       printk(KERN_ERR "btrfs: crc mismatch for page %lu in "
-                              "block group %llu\n", index,
-                              (unsigned long long)block_group->key.objectid);
+                       printk(KERN_ERR "btrfs: crc mismatch for page %lu\n",
+                              index);
                        kunmap(page);
                        unlock_page(page);
                        page_cache_release(page);
@@ -417,10 +399,17 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
                        }
 
                        if (entry->type == BTRFS_FREE_SPACE_EXTENT) {
-                               spin_lock(&block_group->tree_lock);
-                               ret = link_free_space(block_group, e);
-                               spin_unlock(&block_group->tree_lock);
-                               BUG_ON(ret);
+                               spin_lock(&ctl->tree_lock);
+                               ret = link_free_space(ctl, e);
+                               spin_unlock(&ctl->tree_lock);
+                               if (ret) {
+                                       printk(KERN_ERR "Duplicate entries in "
+                                              "free space cache, dumping\n");
+                                       kunmap(page);
+                                       unlock_page(page);
+                                       page_cache_release(page);
+                                       goto free_cache;
+                               }
                        } else {
                                e->bitmap = kzalloc(PAGE_CACHE_SIZE, GFP_NOFS);
                                if (!e->bitmap) {
@@ -431,11 +420,19 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
                                        page_cache_release(page);
                                        goto free_cache;
                                }
-                               spin_lock(&block_group->tree_lock);
-                               ret = link_free_space(block_group, e);
-                               block_group->total_bitmaps++;
-                               recalculate_thresholds(block_group);
-                               spin_unlock(&block_group->tree_lock);
+                               spin_lock(&ctl->tree_lock);
+                               ret = link_free_space(ctl, e);
+                               ctl->total_bitmaps++;
+                               ctl->op->recalc_thresholds(ctl);
+                               spin_unlock(&ctl->tree_lock);
+                               if (ret) {
+                                       printk(KERN_ERR "Duplicate entries in "
+                                              "free space cache, dumping\n");
+                                       kunmap(page);
+                                       unlock_page(page);
+                                       page_cache_release(page);
+                                       goto free_cache;
+                               }
                                list_add_tail(&e->list, &bitmaps);
                        }
 
@@ -471,41 +468,96 @@ next:
                index++;
        }
 
-       spin_lock(&block_group->tree_lock);
-       if (block_group->free_space != (block_group->key.offset - used -
-                                       block_group->bytes_super)) {
-               spin_unlock(&block_group->tree_lock);
-               printk(KERN_ERR "block group %llu has an wrong amount of free "
-                      "space\n", block_group->key.objectid);
-               ret = 0;
-               goto free_cache;
-       }
-       spin_unlock(&block_group->tree_lock);
-
        ret = 1;
 out:
        kfree(checksums);
        kfree(disk_crcs);
-       iput(inode);
        return ret;
-
 free_cache:
-       /* This cache is bogus, make sure it gets cleared */
+       __btrfs_remove_free_space_cache(ctl);
+       goto out;
+}
+
+int load_free_space_cache(struct btrfs_fs_info *fs_info,
+                         struct btrfs_block_group_cache *block_group)
+{
+       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
+       struct btrfs_root *root = fs_info->tree_root;
+       struct inode *inode;
+       struct btrfs_path *path;
+       int ret;
+       bool matched;
+       u64 used = btrfs_block_group_used(&block_group->item);
+
+       /*
+        * If we're unmounting then just return, since this does a search on the
+        * normal root and not the commit root and we could deadlock.
+        */
+       if (btrfs_fs_closing(fs_info))
+               return 0;
+
+       /*
+        * If this block group has been marked to be cleared for one reason or
+        * another then we can't trust the on disk cache, so just return.
+        */
        spin_lock(&block_group->lock);
-       block_group->disk_cache_state = BTRFS_DC_CLEAR;
+       if (block_group->disk_cache_state != BTRFS_DC_WRITTEN) {
+               spin_unlock(&block_group->lock);
+               return 0;
+       }
        spin_unlock(&block_group->lock);
-       btrfs_remove_free_space_cache(block_group);
-       goto out;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return 0;
+
+       inode = lookup_free_space_inode(root, block_group, path);
+       if (IS_ERR(inode)) {
+               btrfs_free_path(path);
+               return 0;
+       }
+
+       ret = __load_free_space_cache(fs_info->tree_root, inode, ctl,
+                                     path, block_group->key.objectid);
+       btrfs_free_path(path);
+       if (ret <= 0)
+               goto out;
+
+       spin_lock(&ctl->tree_lock);
+       matched = (ctl->free_space == (block_group->key.offset - used -
+                                      block_group->bytes_super));
+       spin_unlock(&ctl->tree_lock);
+
+       if (!matched) {
+               __btrfs_remove_free_space_cache(ctl);
+               printk(KERN_ERR "block group %llu has an wrong amount of free "
+                      "space\n", block_group->key.objectid);
+               ret = -1;
+       }
+out:
+       if (ret < 0) {
+               /* This cache is bogus, make sure it gets cleared */
+               spin_lock(&block_group->lock);
+               block_group->disk_cache_state = BTRFS_DC_CLEAR;
+               spin_unlock(&block_group->lock);
+               ret = 0;
+
+               printk(KERN_ERR "btrfs: failed to load free space cache "
+                      "for block group %llu\n", block_group->key.objectid);
+       }
+
+       iput(inode);
+       return ret;
 }
 
-int btrfs_write_out_cache(struct btrfs_root *root,
-                         struct btrfs_trans_handle *trans,
-                         struct btrfs_block_group_cache *block_group,
-                         struct btrfs_path *path)
+int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
+                           struct btrfs_free_space_ctl *ctl,
+                           struct btrfs_block_group_cache *block_group,
+                           struct btrfs_trans_handle *trans,
+                           struct btrfs_path *path, u64 offset)
 {
        struct btrfs_free_space_header *header;
        struct extent_buffer *leaf;
-       struct inode *inode;
        struct rb_node *node;
        struct list_head *pos, *n;
        struct page **pages;
@@ -522,64 +574,53 @@ int btrfs_write_out_cache(struct btrfs_root *root,
        int index = 0, num_pages = 0;
        int entries = 0;
        int bitmaps = 0;
-       int ret = 0;
+       int ret = -1;
        bool next_page = false;
        bool out_of_space = false;
 
-       root = root->fs_info->tree_root;
-
        INIT_LIST_HEAD(&bitmap_list);
 
-       spin_lock(&block_group->lock);
-       if (block_group->disk_cache_state < BTRFS_DC_SETUP) {
-               spin_unlock(&block_group->lock);
-               return 0;
-       }
-       spin_unlock(&block_group->lock);
-
-       inode = lookup_free_space_inode(root, block_group, path);
-       if (IS_ERR(inode))
-               return 0;
-
-       if (!i_size_read(inode)) {
-               iput(inode);
+       node = rb_first(&ctl->free_space_offset);
+       if (!node)
                return 0;
-       }
 
-       node = rb_first(&block_group->free_space_offset);
-       if (!node) {
-               iput(inode);
-               return 0;
-       }
+       if (!i_size_read(inode))
+               return -1;
 
        num_pages = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
                PAGE_CACHE_SHIFT;
+
+       /* Since the first page has all of our checksums and our generation we
+        * need to calculate the offset into the page that we can start writing
+        * our entries.
+        */
+       first_page_offset = (sizeof(u32) * num_pages) + sizeof(u64);
+
        filemap_write_and_wait(inode->i_mapping);
        btrfs_wait_ordered_range(inode, inode->i_size &
                                 ~(root->sectorsize - 1), (u64)-1);
 
+       /* make sure we don't overflow that first page */
+       if (first_page_offset + sizeof(struct btrfs_free_space_entry) >= PAGE_CACHE_SIZE) {
+               /* this is really the same as running out of space, where we also return 0 */
+               printk(KERN_CRIT "Btrfs: free space cache was too big for the crc page\n");
+               ret = 0;
+               goto out_update;
+       }
+
        /* We need a checksum per page. */
        crc = checksums = kzalloc(sizeof(u32) * num_pages, GFP_NOFS);
-       if (!crc) {
-               iput(inode);
-               return 0;
-       }
+       if (!crc)
+               return -1;
 
        pages = kzalloc(sizeof(struct page *) * num_pages, GFP_NOFS);
        if (!pages) {
                kfree(crc);
-               iput(inode);
-               return 0;
+               return -1;
        }
 
-       /* Since the first page has all of our checksums and our generation we
-        * need to calculate the offset into the page that we can start writing
-        * our entries.
-        */
-       first_page_offset = (sizeof(u32) * num_pages) + sizeof(u64);
-
        /* Get the cluster for this block_group if it exists */
-       if (!list_empty(&block_group->cluster_list))
+       if (block_group && !list_empty(&block_group->cluster_list))
                cluster = list_entry(block_group->cluster_list.next,
                                     struct btrfs_free_cluster,
                                     block_group_list);
@@ -621,7 +662,8 @@ int btrfs_write_out_cache(struct btrfs_root *root,
         * When searching for pinned extents, we need to start at our start
         * offset.
         */
-       start = block_group->key.objectid;
+       if (block_group)
+               start = block_group->key.objectid;
 
        /* Write out the extent entries */
        do {
@@ -679,8 +721,9 @@ int btrfs_write_out_cache(struct btrfs_root *root,
                 * We want to add any pinned extents to our free space cache
                 * so we don't leak the space
                 */
-               while (!next_page && (start < block_group->key.objectid +
-                                     block_group->key.offset)) {
+               while (block_group && !next_page &&
+                      (start < block_group->key.objectid +
+                       block_group->key.offset)) {
                        ret = find_first_extent_bit(unpin, start, &start, &end,
                                                    EXTENT_DIRTY);
                        if (ret) {
@@ -798,12 +841,12 @@ int btrfs_write_out_cache(struct btrfs_root *root,
        filemap_write_and_wait(inode->i_mapping);
 
        key.objectid = BTRFS_FREE_SPACE_OBJECTID;
-       key.offset = block_group->key.objectid;
+       key.offset = offset;
        key.type = 0;
 
        ret = btrfs_search_slot(trans, root, &key, path, 1, 1);
        if (ret < 0) {
-               ret = 0;
+               ret = -1;
                clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, bytes - 1,
                                 EXTENT_DIRTY | EXTENT_DELALLOC |
                                 EXTENT_DO_ACCOUNTING, 0, 0, NULL, GFP_NOFS);
@@ -816,13 +859,13 @@ int btrfs_write_out_cache(struct btrfs_root *root,
                path->slots[0]--;
                btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
                if (found_key.objectid != BTRFS_FREE_SPACE_OBJECTID ||
-                   found_key.offset != block_group->key.objectid) {
-                       ret = 0;
+                   found_key.offset != offset) {
+                       ret = -1;
                        clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, bytes - 1,
                                         EXTENT_DIRTY | EXTENT_DELALLOC |
                                         EXTENT_DO_ACCOUNTING, 0, 0, NULL,
                                         GFP_NOFS);
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        goto out_free;
                }
        }
@@ -832,49 +875,85 @@ int btrfs_write_out_cache(struct btrfs_root *root,
        btrfs_set_free_space_bitmaps(leaf, header, bitmaps);
        btrfs_set_free_space_generation(leaf, header, trans->transid);
        btrfs_mark_buffer_dirty(leaf);
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        ret = 1;
 
 out_free:
-       if (ret == 0) {
+       kfree(checksums);
+       kfree(pages);
+
+out_update:
+       if (ret != 1) {
                invalidate_inode_pages2_range(inode->i_mapping, 0, index);
+               BTRFS_I(inode)->generation = 0;
+       }
+       btrfs_update_inode(trans, root, inode);
+       return ret;
+}
+
+int btrfs_write_out_cache(struct btrfs_root *root,
+                         struct btrfs_trans_handle *trans,
+                         struct btrfs_block_group_cache *block_group,
+                         struct btrfs_path *path)
+{
+       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
+       struct inode *inode;
+       int ret = 0;
+
+       root = root->fs_info->tree_root;
+
+       spin_lock(&block_group->lock);
+       if (block_group->disk_cache_state < BTRFS_DC_SETUP) {
+               spin_unlock(&block_group->lock);
+               return 0;
+       }
+       spin_unlock(&block_group->lock);
+
+       inode = lookup_free_space_inode(root, block_group, path);
+       if (IS_ERR(inode))
+               return 0;
+
+       ret = __btrfs_write_out_cache(root, inode, ctl, block_group, trans,
+                                     path, block_group->key.objectid);
+       if (ret < 0) {
                spin_lock(&block_group->lock);
                block_group->disk_cache_state = BTRFS_DC_ERROR;
                spin_unlock(&block_group->lock);
-               BTRFS_I(inode)->generation = 0;
+               ret = 0;
+
+               printk(KERN_ERR "btrfs: failed to write free space cace "
+                      "for block group %llu\n", block_group->key.objectid);
        }
-       kfree(checksums);
-       kfree(pages);
-       btrfs_update_inode(trans, root, inode);
+
        iput(inode);
        return ret;
 }
 
-static inline unsigned long offset_to_bit(u64 bitmap_start, u64 sectorsize,
+static inline unsigned long offset_to_bit(u64 bitmap_start, u32 unit,
                                          u64 offset)
 {
        BUG_ON(offset < bitmap_start);
        offset -= bitmap_start;
-       return (unsigned long)(div64_u64(offset, sectorsize));
+       return (unsigned long)(div_u64(offset, unit));
 }
 
-static inline unsigned long bytes_to_bits(u64 bytes, u64 sectorsize)
+static inline unsigned long bytes_to_bits(u64 bytes, u32 unit)
 {
-       return (unsigned long)(div64_u64(bytes, sectorsize));
+       return (unsigned long)(div_u64(bytes, unit));
 }
 
-static inline u64 offset_to_bitmap(struct btrfs_block_group_cache *block_group,
+static inline u64 offset_to_bitmap(struct btrfs_free_space_ctl *ctl,
                                   u64 offset)
 {
        u64 bitmap_start;
        u64 bytes_per_bitmap;
 
-       bytes_per_bitmap = BITS_PER_BITMAP * block_group->sectorsize;
-       bitmap_start = offset - block_group->key.objectid;
+       bytes_per_bitmap = BITS_PER_BITMAP * ctl->unit;
+       bitmap_start = offset - ctl->start;
        bitmap_start = div64_u64(bitmap_start, bytes_per_bitmap);
        bitmap_start *= bytes_per_bitmap;
-       bitmap_start += block_group->key.objectid;
+       bitmap_start += ctl->start;
 
        return bitmap_start;
 }
@@ -909,10 +988,16 @@ static int tree_insert_offset(struct rb_root *root, u64 offset,
                         * logically.
                         */
                        if (bitmap) {
-                               WARN_ON(info->bitmap);
+                               if (info->bitmap) {
+                                       WARN_ON_ONCE(1);
+                                       return -EEXIST;
+                               }
                                p = &(*p)->rb_right;
                        } else {
-                               WARN_ON(!info->bitmap);
+                               if (!info->bitmap) {
+                                       WARN_ON_ONCE(1);
+                                       return -EEXIST;
+                               }
                                p = &(*p)->rb_left;
                        }
                }
@@ -932,10 +1017,10 @@ static int tree_insert_offset(struct rb_root *root, u64 offset,
  * offset.
  */
 static struct btrfs_free_space *
-tree_search_offset(struct btrfs_block_group_cache *block_group,
+tree_search_offset(struct btrfs_free_space_ctl *ctl,
                   u64 offset, int bitmap_only, int fuzzy)
 {
-       struct rb_node *n = block_group->free_space_offset.rb_node;
+       struct rb_node *n = ctl->free_space_offset.rb_node;
        struct btrfs_free_space *entry, *prev = NULL;
 
        /* find entry that is closest to the 'offset' */
@@ -1031,8 +1116,7 @@ tree_search_offset(struct btrfs_block_group_cache *block_group,
                                break;
                        }
                }
-               if (entry->offset + BITS_PER_BITMAP *
-                   block_group->sectorsize > offset)
+               if (entry->offset + BITS_PER_BITMAP * ctl->unit > offset)
                        return entry;
        } else if (entry->offset + entry->bytes > offset)
                return entry;
@@ -1043,7 +1127,7 @@ tree_search_offset(struct btrfs_block_group_cache *block_group,
        while (1) {
                if (entry->bitmap) {
                        if (entry->offset + BITS_PER_BITMAP *
-                           block_group->sectorsize > offset)
+                           ctl->unit > offset)
                                break;
                } else {
                        if (entry->offset + entry->bytes > offset)
@@ -1059,42 +1143,47 @@ tree_search_offset(struct btrfs_block_group_cache *block_group,
 }
 
 static inline void
-__unlink_free_space(struct btrfs_block_group_cache *block_group,
+__unlink_free_space(struct btrfs_free_space_ctl *ctl,
                    struct btrfs_free_space *info)
 {
-       rb_erase(&info->offset_index, &block_group->free_space_offset);
-       block_group->free_extents--;
+       rb_erase(&info->offset_index, &ctl->free_space_offset);
+       ctl->free_extents--;
 }
 
-static void unlink_free_space(struct btrfs_block_group_cache *block_group,
+static void unlink_free_space(struct btrfs_free_space_ctl *ctl,
                              struct btrfs_free_space *info)
 {
-       __unlink_free_space(block_group, info);
-       block_group->free_space -= info->bytes;
+       __unlink_free_space(ctl, info);
+       ctl->free_space -= info->bytes;
 }
 
-static int link_free_space(struct btrfs_block_group_cache *block_group,
+static int link_free_space(struct btrfs_free_space_ctl *ctl,
                           struct btrfs_free_space *info)
 {
        int ret = 0;
 
        BUG_ON(!info->bitmap && !info->bytes);
-       ret = tree_insert_offset(&block_group->free_space_offset, info->offset,
+       ret = tree_insert_offset(&ctl->free_space_offset, info->offset,
                                 &info->offset_index, (info->bitmap != NULL));
        if (ret)
                return ret;
 
-       block_group->free_space += info->bytes;
-       block_group->free_extents++;
+       ctl->free_space += info->bytes;
+       ctl->free_extents++;
        return ret;
 }
 
-static void recalculate_thresholds(struct btrfs_block_group_cache *block_group)
+static void recalculate_thresholds(struct btrfs_free_space_ctl *ctl)
 {
+       struct btrfs_block_group_cache *block_group = ctl->private;
        u64 max_bytes;
        u64 bitmap_bytes;
        u64 extent_bytes;
        u64 size = block_group->key.offset;
+       u64 bytes_per_bg = BITS_PER_BITMAP * block_group->sectorsize;
+       int max_bitmaps = div64_u64(size + bytes_per_bg - 1, bytes_per_bg);
+
+       BUG_ON(ctl->total_bitmaps > max_bitmaps);
 
        /*
         * The goal is to keep the total amount of memory used per 1gb of space
@@ -1112,10 +1201,10 @@ static void recalculate_thresholds(struct btrfs_block_group_cache *block_group)
         * sure we don't go over our overall goal of MAX_CACHE_BYTES_PER_GIG as
         * we add more bitmaps.
         */
-       bitmap_bytes = (block_group->total_bitmaps + 1) * PAGE_CACHE_SIZE;
+       bitmap_bytes = (ctl->total_bitmaps + 1) * PAGE_CACHE_SIZE;
 
        if (bitmap_bytes >= max_bytes) {
-               block_group->extents_thresh = 0;
+               ctl->extents_thresh = 0;
                return;
        }
 
@@ -1126,47 +1215,43 @@ static void recalculate_thresholds(struct btrfs_block_group_cache *block_group)
        extent_bytes = max_bytes - bitmap_bytes;
        extent_bytes = min_t(u64, extent_bytes, div64_u64(max_bytes, 2));
 
-       block_group->extents_thresh =
+       ctl->extents_thresh =
                div64_u64(extent_bytes, (sizeof(struct btrfs_free_space)));
 }
 
-static void bitmap_clear_bits(struct btrfs_block_group_cache *block_group,
+static void bitmap_clear_bits(struct btrfs_free_space_ctl *ctl,
                              struct btrfs_free_space *info, u64 offset,
                              u64 bytes)
 {
-       unsigned long start, end;
-       unsigned long i;
+       unsigned long start, count;
 
-       start = offset_to_bit(info->offset, block_group->sectorsize, offset);
-       end = start + bytes_to_bits(bytes, block_group->sectorsize);
-       BUG_ON(end > BITS_PER_BITMAP);
+       start = offset_to_bit(info->offset, ctl->unit, offset);
+       count = bytes_to_bits(bytes, ctl->unit);
+       BUG_ON(start + count > BITS_PER_BITMAP);
 
-       for (i = start; i < end; i++)
-               clear_bit(i, info->bitmap);
+       bitmap_clear(info->bitmap, start, count);
 
        info->bytes -= bytes;
-       block_group->free_space -= bytes;
+       ctl->free_space -= bytes;
 }
 
-static void bitmap_set_bits(struct btrfs_block_group_cache *block_group,
+static void bitmap_set_bits(struct btrfs_free_space_ctl *ctl,
                            struct btrfs_free_space *info, u64 offset,
                            u64 bytes)
 {
-       unsigned long start, end;
-       unsigned long i;
+       unsigned long start, count;
 
-       start = offset_to_bit(info->offset, block_group->sectorsize, offset);
-       end = start + bytes_to_bits(bytes, block_group->sectorsize);
-       BUG_ON(end > BITS_PER_BITMAP);
+       start = offset_to_bit(info->offset, ctl->unit, offset);
+       count = bytes_to_bits(bytes, ctl->unit);
+       BUG_ON(start + count > BITS_PER_BITMAP);
 
-       for (i = start; i < end; i++)
-               set_bit(i, info->bitmap);
+       bitmap_set(info->bitmap, start, count);
 
        info->bytes += bytes;
-       block_group->free_space += bytes;
+       ctl->free_space += bytes;
 }
 
-static int search_bitmap(struct btrfs_block_group_cache *block_group,
+static int search_bitmap(struct btrfs_free_space_ctl *ctl,
                         struct btrfs_free_space *bitmap_info, u64 *offset,
                         u64 *bytes)
 {
@@ -1174,9 +1259,9 @@ static int search_bitmap(struct btrfs_block_group_cache *block_group,
        unsigned long bits, i;
        unsigned long next_zero;
 
-       i = offset_to_bit(bitmap_info->offset, block_group->sectorsize,
+       i = offset_to_bit(bitmap_info->offset, ctl->unit,
                          max_t(u64, *offset, bitmap_info->offset));
-       bits = bytes_to_bits(*bytes, block_group->sectorsize);
+       bits = bytes_to_bits(*bytes, ctl->unit);
 
        for (i = find_next_bit(bitmap_info->bitmap, BITS_PER_BITMAP, i);
             i < BITS_PER_BITMAP;
@@ -1191,29 +1276,25 @@ static int search_bitmap(struct btrfs_block_group_cache *block_group,
        }
 
        if (found_bits) {
-               *offset = (u64)(i * block_group->sectorsize) +
-                       bitmap_info->offset;
-               *bytes = (u64)(found_bits) * block_group->sectorsize;
+               *offset = (u64)(i * ctl->unit) + bitmap_info->offset;
+               *bytes = (u64)(found_bits) * ctl->unit;
                return 0;
        }
 
        return -1;
 }
 
-static struct btrfs_free_space *find_free_space(struct btrfs_block_group_cache
-                                               *block_group, u64 *offset,
-                                               u64 *bytes, int debug)
+static struct btrfs_free_space *
+find_free_space(struct btrfs_free_space_ctl *ctl, u64 *offset, u64 *bytes)
 {
        struct btrfs_free_space *entry;
        struct rb_node *node;
        int ret;
 
-       if (!block_group->free_space_offset.rb_node)
+       if (!ctl->free_space_offset.rb_node)
                return NULL;
 
-       entry = tree_search_offset(block_group,
-                                  offset_to_bitmap(block_group, *offset),
-                                  0, 1);
+       entry = tree_search_offset(ctl, offset_to_bitmap(ctl, *offset), 0, 1);
        if (!entry)
                return NULL;
 
@@ -1223,7 +1304,7 @@ static struct btrfs_free_space *find_free_space(struct btrfs_block_group_cache
                        continue;
 
                if (entry->bitmap) {
-                       ret = search_bitmap(block_group, entry, offset, bytes);
+                       ret = search_bitmap(ctl, entry, offset, bytes);
                        if (!ret)
                                return entry;
                        continue;
@@ -1237,33 +1318,28 @@ static struct btrfs_free_space *find_free_space(struct btrfs_block_group_cache
        return NULL;
 }
 
-static void add_new_bitmap(struct btrfs_block_group_cache *block_group,
+static void add_new_bitmap(struct btrfs_free_space_ctl *ctl,
                           struct btrfs_free_space *info, u64 offset)
 {
-       u64 bytes_per_bg = BITS_PER_BITMAP * block_group->sectorsize;
-       int max_bitmaps = (int)div64_u64(block_group->key.offset +
-                                        bytes_per_bg - 1, bytes_per_bg);
-       BUG_ON(block_group->total_bitmaps >= max_bitmaps);
-
-       info->offset = offset_to_bitmap(block_group, offset);
+       info->offset = offset_to_bitmap(ctl, offset);
        info->bytes = 0;
-       link_free_space(block_group, info);
-       block_group->total_bitmaps++;
+       link_free_space(ctl, info);
+       ctl->total_bitmaps++;
 
-       recalculate_thresholds(block_group);
+       ctl->op->recalc_thresholds(ctl);
 }
 
-static void free_bitmap(struct btrfs_block_group_cache *block_group,
+static void free_bitmap(struct btrfs_free_space_ctl *ctl,
                        struct btrfs_free_space *bitmap_info)
 {
-       unlink_free_space(block_group, bitmap_info);
+       unlink_free_space(ctl, bitmap_info);
        kfree(bitmap_info->bitmap);
        kmem_cache_free(btrfs_free_space_cachep, bitmap_info);
-       block_group->total_bitmaps--;
-       recalculate_thresholds(block_group);
+       ctl->total_bitmaps--;
+       ctl->op->recalc_thresholds(ctl);
 }
 
-static noinline int remove_from_bitmap(struct btrfs_block_group_cache *block_group,
+static noinline int remove_from_bitmap(struct btrfs_free_space_ctl *ctl,
                              struct btrfs_free_space *bitmap_info,
                              u64 *offset, u64 *bytes)
 {
@@ -1272,8 +1348,7 @@ static noinline int remove_from_bitmap(struct btrfs_block_group_cache *block_gro
        int ret;
 
 again:
-       end = bitmap_info->offset +
-               (u64)(BITS_PER_BITMAP * block_group->sectorsize) - 1;
+       end = bitmap_info->offset + (u64)(BITS_PER_BITMAP * ctl->unit) - 1;
 
        /*
         * XXX - this can go away after a few releases.
@@ -1288,24 +1363,22 @@ again:
        search_start = *offset;
        search_bytes = *bytes;
        search_bytes = min(search_bytes, end - search_start + 1);
-       ret = search_bitmap(block_group, bitmap_info, &search_start,
-                           &search_bytes);
+       ret = search_bitmap(ctl, bitmap_info, &search_start, &search_bytes);
        BUG_ON(ret < 0 || search_start != *offset);
 
        if (*offset > bitmap_info->offset && *offset + *bytes > end) {
-               bitmap_clear_bits(block_group, bitmap_info, *offset,
-                                 end - *offset + 1);
+               bitmap_clear_bits(ctl, bitmap_info, *offset, end - *offset + 1);
                *bytes -= end - *offset + 1;
                *offset = end + 1;
        } else if (*offset >= bitmap_info->offset && *offset + *bytes <= end) {
-               bitmap_clear_bits(block_group, bitmap_info, *offset, *bytes);
+               bitmap_clear_bits(ctl, bitmap_info, *offset, *bytes);
                *bytes = 0;
        }
 
        if (*bytes) {
                struct rb_node *next = rb_next(&bitmap_info->offset_index);
                if (!bitmap_info->bytes)
-                       free_bitmap(block_group, bitmap_info);
+                       free_bitmap(ctl, bitmap_info);
 
                /*
                 * no entry after this bitmap, but we still have bytes to
@@ -1332,31 +1405,45 @@ again:
                 */
                search_start = *offset;
                search_bytes = *bytes;
-               ret = search_bitmap(block_group, bitmap_info, &search_start,
+               ret = search_bitmap(ctl, bitmap_info, &search_start,
                                    &search_bytes);
                if (ret < 0 || search_start != *offset)
                        return -EAGAIN;
 
                goto again;
        } else if (!bitmap_info->bytes)
-               free_bitmap(block_group, bitmap_info);
+               free_bitmap(ctl, bitmap_info);
 
        return 0;
 }
 
-static int insert_into_bitmap(struct btrfs_block_group_cache *block_group,
-                             struct btrfs_free_space *info)
+static u64 add_bytes_to_bitmap(struct btrfs_free_space_ctl *ctl,
+                              struct btrfs_free_space *info, u64 offset,
+                              u64 bytes)
 {
-       struct btrfs_free_space *bitmap_info;
-       int added = 0;
-       u64 bytes, offset, end;
-       int ret;
+       u64 bytes_to_set = 0;
+       u64 end;
+
+       end = info->offset + (u64)(BITS_PER_BITMAP * ctl->unit);
+
+       bytes_to_set = min(end - offset, bytes);
+
+       bitmap_set_bits(ctl, info, offset, bytes_to_set);
+
+       return bytes_to_set;
+
+}
+
+static bool use_bitmap(struct btrfs_free_space_ctl *ctl,
+                     struct btrfs_free_space *info)
+{
+       struct btrfs_block_group_cache *block_group = ctl->private;
 
        /*
         * If we are below the extents threshold then we can add this as an
         * extent, and don't have to deal with the bitmap
         */
-       if (block_group->free_extents < block_group->extents_thresh) {
+       if (ctl->free_extents < ctl->extents_thresh) {
                /*
                 * If this block group has some small extents we don't want to
                 * use up all of our free slots in the cache with them, we want
@@ -1365,11 +1452,10 @@ static int insert_into_bitmap(struct btrfs_block_group_cache *block_group,
                 * the overhead of a bitmap if we don't have to.
                 */
                if (info->bytes <= block_group->sectorsize * 4) {
-                       if (block_group->free_extents * 2 <=
-                           block_group->extents_thresh)
-                               return 0;
+                       if (ctl->free_extents * 2 <= ctl->extents_thresh)
+                               return false;
                } else {
-                       return 0;
+                       return false;
                }
        }
 
@@ -1379,35 +1465,85 @@ static int insert_into_bitmap(struct btrfs_block_group_cache *block_group,
         */
        if (BITS_PER_BITMAP * block_group->sectorsize >
            block_group->key.offset)
-               return 0;
+               return false;
+
+       return true;
+}
+
+static struct btrfs_free_space_op free_space_op = {
+       .recalc_thresholds      = recalculate_thresholds,
+       .use_bitmap             = use_bitmap,
+};
+
+static int insert_into_bitmap(struct btrfs_free_space_ctl *ctl,
+                             struct btrfs_free_space *info)
+{
+       struct btrfs_free_space *bitmap_info;
+       struct btrfs_block_group_cache *block_group = NULL;
+       int added = 0;
+       u64 bytes, offset, bytes_added;
+       int ret;
 
        bytes = info->bytes;
        offset = info->offset;
 
+       if (!ctl->op->use_bitmap(ctl, info))
+               return 0;
+
+       if (ctl->op == &free_space_op)
+               block_group = ctl->private;
 again:
-       bitmap_info = tree_search_offset(block_group,
-                                        offset_to_bitmap(block_group, offset),
+       /*
+        * Since we link bitmaps right into the cluster we need to see if we
+        * have a cluster here, and if so and it has our bitmap we need to add
+        * the free space to that bitmap.
+        */
+       if (block_group && !list_empty(&block_group->cluster_list)) {
+               struct btrfs_free_cluster *cluster;
+               struct rb_node *node;
+               struct btrfs_free_space *entry;
+
+               cluster = list_entry(block_group->cluster_list.next,
+                                    struct btrfs_free_cluster,
+                                    block_group_list);
+               spin_lock(&cluster->lock);
+               node = rb_first(&cluster->root);
+               if (!node) {
+                       spin_unlock(&cluster->lock);
+                       goto no_cluster_bitmap;
+               }
+
+               entry = rb_entry(node, struct btrfs_free_space, offset_index);
+               if (!entry->bitmap) {
+                       spin_unlock(&cluster->lock);
+                       goto no_cluster_bitmap;
+               }
+
+               if (entry->offset == offset_to_bitmap(ctl, offset)) {
+                       bytes_added = add_bytes_to_bitmap(ctl, entry,
+                                                         offset, bytes);
+                       bytes -= bytes_added;
+                       offset += bytes_added;
+               }
+               spin_unlock(&cluster->lock);
+               if (!bytes) {
+                       ret = 1;
+                       goto out;
+               }
+       }
+
+no_cluster_bitmap:
+       bitmap_info = tree_search_offset(ctl, offset_to_bitmap(ctl, offset),
                                         1, 0);
        if (!bitmap_info) {
                BUG_ON(added);
                goto new_bitmap;
        }
 
-       end = bitmap_info->offset +
-               (u64)(BITS_PER_BITMAP * block_group->sectorsize);
-
-       if (offset >= bitmap_info->offset && offset + bytes > end) {
-               bitmap_set_bits(block_group, bitmap_info, offset,
-                               end - offset);
-               bytes -= end - offset;
-               offset = end;
-               added = 0;
-       } else if (offset >= bitmap_info->offset && offset + bytes <= end) {
-               bitmap_set_bits(block_group, bitmap_info, offset, bytes);
-               bytes = 0;
-       } else {
-               BUG();
-       }
+       bytes_added = add_bytes_to_bitmap(ctl, bitmap_info, offset, bytes);
+       bytes -= bytes_added;
+       offset += bytes_added;
+       added = 0;
 
        if (!bytes) {
                ret = 1;
@@ -1417,19 +1553,19 @@ again:
 
 new_bitmap:
        if (info && info->bitmap) {
-               add_new_bitmap(block_group, info, offset);
+               add_new_bitmap(ctl, info, offset);
                added = 1;
                info = NULL;
                goto again;
        } else {
-               spin_unlock(&block_group->tree_lock);
+               spin_unlock(&ctl->tree_lock);
 
                /* no pre-allocated info, allocate a new one */
                if (!info) {
                        info = kmem_cache_zalloc(btrfs_free_space_cachep,
                                                 GFP_NOFS);
                        if (!info) {
-                               spin_lock(&block_group->tree_lock);
+                               spin_lock(&ctl->tree_lock);
                                ret = -ENOMEM;
                                goto out;
                        }
@@ -1437,7 +1573,7 @@ new_bitmap:
 
                /* allocate the bitmap */
                info->bitmap = kzalloc(PAGE_CACHE_SIZE, GFP_NOFS);
-               spin_lock(&block_group->tree_lock);
+               spin_lock(&ctl->tree_lock);
                if (!info->bitmap) {
                        ret = -ENOMEM;
                        goto out;
@@ -1455,7 +1591,7 @@ out:
        return ret;
 }
 
-bool try_merge_free_space(struct btrfs_block_group_cache *block_group,
+static bool try_merge_free_space(struct btrfs_free_space_ctl *ctl,
                          struct btrfs_free_space *info, bool update_stat)
 {
        struct btrfs_free_space *left_info;
@@ -1469,18 +1605,18 @@ bool try_merge_free_space(struct btrfs_block_group_cache *block_group,
         * are adding, if there is remove that struct and add a new one to
         * cover the entire range
         */
-       right_info = tree_search_offset(block_group, offset + bytes, 0, 0);
+       right_info = tree_search_offset(ctl, offset + bytes, 0, 0);
        if (right_info && rb_prev(&right_info->offset_index))
                left_info = rb_entry(rb_prev(&right_info->offset_index),
                                     struct btrfs_free_space, offset_index);
        else
-               left_info = tree_search_offset(block_group, offset - 1, 0, 0);
+               left_info = tree_search_offset(ctl, offset - 1, 0, 0);
 
        if (right_info && !right_info->bitmap) {
                if (update_stat)
-                       unlink_free_space(block_group, right_info);
+                       unlink_free_space(ctl, right_info);
                else
-                       __unlink_free_space(block_group, right_info);
+                       __unlink_free_space(ctl, right_info);
                info->bytes += right_info->bytes;
                kmem_cache_free(btrfs_free_space_cachep, right_info);
                merged = true;
@@ -1489,9 +1625,9 @@ bool try_merge_free_space(struct btrfs_block_group_cache *block_group,
        if (left_info && !left_info->bitmap &&
            left_info->offset + left_info->bytes == offset) {
                if (update_stat)
-                       unlink_free_space(block_group, left_info);
+                       unlink_free_space(ctl, left_info);
                else
-                       __unlink_free_space(block_group, left_info);
+                       __unlink_free_space(ctl, left_info);
                info->offset = left_info->offset;
                info->bytes += left_info->bytes;
                kmem_cache_free(btrfs_free_space_cachep, left_info);
@@ -1501,8 +1637,8 @@ bool try_merge_free_space(struct btrfs_block_group_cache *block_group,
        return merged;
 }
 
-int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
-                        u64 offset, u64 bytes)
+int __btrfs_add_free_space(struct btrfs_free_space_ctl *ctl,
+                          u64 offset, u64 bytes)
 {
        struct btrfs_free_space *info;
        int ret = 0;
@@ -1514,9 +1650,9 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
        info->offset = offset;
        info->bytes = bytes;
 
-       spin_lock(&block_group->tree_lock);
+       spin_lock(&ctl->tree_lock);
 
-       if (try_merge_free_space(block_group, info, true))
+       if (try_merge_free_space(ctl, info, true))
                goto link;
 
        /*
@@ -1524,7 +1660,7 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
         * extent then we know we're going to have to allocate a new extent, so
         * before we do that see if we need to drop this into a bitmap
         */
-       ret = insert_into_bitmap(block_group, info);
+       ret = insert_into_bitmap(ctl, info);
        if (ret < 0) {
                goto out;
        } else if (ret) {
@@ -1532,11 +1668,11 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
                goto out;
        }
 link:
-       ret = link_free_space(block_group, info);
+       ret = link_free_space(ctl, info);
        if (ret)
                kmem_cache_free(btrfs_free_space_cachep, info);
 out:
-       spin_unlock(&block_group->tree_lock);
+       spin_unlock(&ctl->tree_lock);
 
        if (ret) {
                printk(KERN_CRIT "btrfs: unable to add free space :%d\n", ret);
@@ -1549,21 +1685,21 @@ out:
 int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
                            u64 offset, u64 bytes)
 {
+       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        struct btrfs_free_space *info;
        struct btrfs_free_space *next_info = NULL;
        int ret = 0;
 
-       spin_lock(&block_group->tree_lock);
+       spin_lock(&ctl->tree_lock);
 
 again:
-       info = tree_search_offset(block_group, offset, 0, 0);
+       info = tree_search_offset(ctl, offset, 0, 0);
        if (!info) {
                /*
                 * oops didn't find an extent that matched the space we wanted
                 * to remove, look for a bitmap instead
                 */
-               info = tree_search_offset(block_group,
-                                         offset_to_bitmap(block_group, offset),
+               info = tree_search_offset(ctl, offset_to_bitmap(ctl, offset),
                                          1, 0);
                if (!info) {
                        WARN_ON(1);
@@ -1578,8 +1714,8 @@ again:
                                             offset_index);
 
                if (next_info->bitmap)
-                       end = next_info->offset + BITS_PER_BITMAP *
-                               block_group->sectorsize - 1;
+                       end = next_info->offset +
+                             BITS_PER_BITMAP * ctl->unit - 1;
                else
                        end = next_info->offset + next_info->bytes;
 
@@ -1599,20 +1735,20 @@ again:
        }
 
        if (info->bytes == bytes) {
-               unlink_free_space(block_group, info);
+               unlink_free_space(ctl, info);
                if (info->bitmap) {
                        kfree(info->bitmap);
-                       block_group->total_bitmaps--;
+                       ctl->total_bitmaps--;
                }
                kmem_cache_free(btrfs_free_space_cachep, info);
                goto out_lock;
        }
 
        if (!info->bitmap && info->offset == offset) {
-               unlink_free_space(block_group, info);
+               unlink_free_space(ctl, info);
                info->offset += bytes;
                info->bytes -= bytes;
-               link_free_space(block_group, info);
+               link_free_space(ctl, info);
                goto out_lock;
        }
 
@@ -1626,13 +1762,13 @@ again:
                 * first unlink the old info and then
                 * insert it again after the hole we're creating
                 */
-               unlink_free_space(block_group, info);
+               unlink_free_space(ctl, info);
                if (offset + bytes < info->offset + info->bytes) {
                        u64 old_end = info->offset + info->bytes;
 
                        info->offset = offset + bytes;
                        info->bytes = old_end - info->offset;
-                       ret = link_free_space(block_group, info);
+                       ret = link_free_space(ctl, info);
                        WARN_ON(ret);
                        if (ret)
                                goto out_lock;
@@ -1642,7 +1778,7 @@ again:
                         */
                        kmem_cache_free(btrfs_free_space_cachep, info);
                }
-               spin_unlock(&block_group->tree_lock);
+               spin_unlock(&ctl->tree_lock);
 
                /* step two, insert a new info struct to cover
                 * anything before the hole
@@ -1653,12 +1789,12 @@ again:
                goto out;
        }
 
-       ret = remove_from_bitmap(block_group, info, &offset, &bytes);
+       ret = remove_from_bitmap(ctl, info, &offset, &bytes);
        if (ret == -EAGAIN)
                goto again;
        BUG_ON(ret);
 out_lock:
-       spin_unlock(&block_group->tree_lock);
+       spin_unlock(&ctl->tree_lock);
 out:
        return ret;
 }
@@ -1666,11 +1802,12 @@ out:
 void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
                           u64 bytes)
 {
+       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        struct btrfs_free_space *info;
        struct rb_node *n;
        int count = 0;
 
-       for (n = rb_first(&block_group->free_space_offset); n; n = rb_next(n)) {
+       for (n = rb_first(&ctl->free_space_offset); n; n = rb_next(n)) {
                info = rb_entry(n, struct btrfs_free_space, offset_index);
                if (info->bytes >= bytes)
                        count++;
@@ -1685,19 +1822,23 @@ void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
               "\n", count);
 }
 
-u64 btrfs_block_group_free_space(struct btrfs_block_group_cache *block_group)
+void btrfs_init_free_space_ctl(struct btrfs_block_group_cache *block_group)
 {
-       struct btrfs_free_space *info;
-       struct rb_node *n;
-       u64 ret = 0;
+       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
 
-       for (n = rb_first(&block_group->free_space_offset); n;
-            n = rb_next(n)) {
-               info = rb_entry(n, struct btrfs_free_space, offset_index);
-               ret += info->bytes;
-       }
+       spin_lock_init(&ctl->tree_lock);
+       ctl->unit = block_group->sectorsize;
+       ctl->start = block_group->key.objectid;
+       ctl->private = block_group;
+       ctl->op = &free_space_op;
 
-       return ret;
+       /*
+        * we only want to have 32k of ram per block group for keeping
+        * track of free space, and if we pass 1/2 of that we want to
+        * start converting things over to using bitmaps
+        */
+       ctl->extents_thresh = ((1024 * 32) / 2) /
+                               sizeof(struct btrfs_free_space);
 }
 
 /*
@@ -1711,6 +1852,7 @@ __btrfs_return_cluster_to_free_space(
                             struct btrfs_block_group_cache *block_group,
                             struct btrfs_free_cluster *cluster)
 {
+       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        struct btrfs_free_space *entry;
        struct rb_node *node;
 
@@ -1732,8 +1874,8 @@ __btrfs_return_cluster_to_free_space(
 
                bitmap = (entry->bitmap != NULL);
                if (!bitmap)
-                       try_merge_free_space(block_group, entry, false);
-               tree_insert_offset(&block_group->free_space_offset,
+                       try_merge_free_space(ctl, entry, false);
+               tree_insert_offset(&ctl->free_space_offset,
                                   entry->offset, &entry->offset_index, bitmap);
        }
        cluster->root = RB_ROOT;
@@ -1744,14 +1886,38 @@ out:
        return 0;
 }
 
-void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group)
+void __btrfs_remove_free_space_cache_locked(struct btrfs_free_space_ctl *ctl)
 {
        struct btrfs_free_space *info;
        struct rb_node *node;
+
+       while ((node = rb_last(&ctl->free_space_offset)) != NULL) {
+               info = rb_entry(node, struct btrfs_free_space, offset_index);
+               unlink_free_space(ctl, info);
+               kfree(info->bitmap);
+               kmem_cache_free(btrfs_free_space_cachep, info);
+               if (need_resched()) {
+                       spin_unlock(&ctl->tree_lock);
+                       cond_resched();
+                       spin_lock(&ctl->tree_lock);
+               }
+       }
+}
+
+void __btrfs_remove_free_space_cache(struct btrfs_free_space_ctl *ctl)
+{
+       spin_lock(&ctl->tree_lock);
+       __btrfs_remove_free_space_cache_locked(ctl);
+       spin_unlock(&ctl->tree_lock);
+}
+
+void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group)
+{
+       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        struct btrfs_free_cluster *cluster;
        struct list_head *head;
 
-       spin_lock(&block_group->tree_lock);
+       spin_lock(&ctl->tree_lock);
        while ((head = block_group->cluster_list.next) !=
               &block_group->cluster_list) {
                cluster = list_entry(head, struct btrfs_free_cluster,
@@ -1760,60 +1926,46 @@ void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group)
                WARN_ON(cluster->block_group != block_group);
                __btrfs_return_cluster_to_free_space(block_group, cluster);
                if (need_resched()) {
-                       spin_unlock(&block_group->tree_lock);
-                       cond_resched();
-                       spin_lock(&block_group->tree_lock);
-               }
-       }
-
-       while ((node = rb_last(&block_group->free_space_offset)) != NULL) {
-               info = rb_entry(node, struct btrfs_free_space, offset_index);
-               if (!info->bitmap) {
-                       unlink_free_space(block_group, info);
-                       kmem_cache_free(btrfs_free_space_cachep, info);
-               } else {
-                       free_bitmap(block_group, info);
-               }
-
-               if (need_resched()) {
-                       spin_unlock(&block_group->tree_lock);
+                       spin_unlock(&ctl->tree_lock);
                        cond_resched();
-                       spin_lock(&block_group->tree_lock);
+                       spin_lock(&ctl->tree_lock);
                }
        }
+       __btrfs_remove_free_space_cache_locked(ctl);
+       spin_unlock(&ctl->tree_lock);
 
-       spin_unlock(&block_group->tree_lock);
 }
 
 u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
                               u64 offset, u64 bytes, u64 empty_size)
 {
+       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        struct btrfs_free_space *entry = NULL;
        u64 bytes_search = bytes + empty_size;
        u64 ret = 0;
 
-       spin_lock(&block_group->tree_lock);
-       entry = find_free_space(block_group, &offset, &bytes_search, 0);
+       spin_lock(&ctl->tree_lock);
+       entry = find_free_space(ctl, &offset, &bytes_search);
        if (!entry)
                goto out;
 
        ret = offset;
        if (entry->bitmap) {
-               bitmap_clear_bits(block_group, entry, offset, bytes);
+               bitmap_clear_bits(ctl, entry, offset, bytes);
                if (!entry->bytes)
-                       free_bitmap(block_group, entry);
+                       free_bitmap(ctl, entry);
        } else {
-               unlink_free_space(block_group, entry);
+               unlink_free_space(ctl, entry);
                entry->offset += bytes;
                entry->bytes -= bytes;
                if (!entry->bytes)
                        kmem_cache_free(btrfs_free_space_cachep, entry);
                else
-                       link_free_space(block_group, entry);
+                       link_free_space(ctl, entry);
        }
 
 out:
-       spin_unlock(&block_group->tree_lock);
+       spin_unlock(&ctl->tree_lock);
 
        return ret;
 }
@@ -1830,6 +1982,7 @@ int btrfs_return_cluster_to_free_space(
                               struct btrfs_block_group_cache *block_group,
                               struct btrfs_free_cluster *cluster)
 {
+       struct btrfs_free_space_ctl *ctl;
        int ret;
 
        /* first, get a safe pointer to the block group */
@@ -1848,10 +2001,12 @@ int btrfs_return_cluster_to_free_space(
        atomic_inc(&block_group->count);
        spin_unlock(&cluster->lock);
 
+       ctl = block_group->free_space_ctl;
+
        /* now return any extents the cluster had on it */
-       spin_lock(&block_group->tree_lock);
+       spin_lock(&ctl->tree_lock);
        ret = __btrfs_return_cluster_to_free_space(block_group, cluster);
-       spin_unlock(&block_group->tree_lock);
+       spin_unlock(&ctl->tree_lock);
 
        /* finally drop our ref */
        btrfs_put_block_group(block_group);
@@ -1863,6 +2018,7 @@ static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group,
                                   struct btrfs_free_space *entry,
                                   u64 bytes, u64 min_start)
 {
+       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        int err;
        u64 search_start = cluster->window_start;
        u64 search_bytes = bytes;
@@ -1871,13 +2027,12 @@ static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group,
        search_start = min_start;
        search_bytes = bytes;
 
-       err = search_bitmap(block_group, entry, &search_start,
-                           &search_bytes);
+       err = search_bitmap(ctl, entry, &search_start, &search_bytes);
        if (err)
                return 0;
 
        ret = search_start;
-       bitmap_clear_bits(block_group, entry, ret, bytes);
+       bitmap_clear_bits(ctl, entry, ret, bytes);
 
        return ret;
 }
@@ -1891,6 +2046,7 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
                             struct btrfs_free_cluster *cluster, u64 bytes,
                             u64 min_start)
 {
+       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        struct btrfs_free_space *entry = NULL;
        struct rb_node *node;
        u64 ret = 0;
@@ -1910,8 +2066,6 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
        while(1) {
                if (entry->bytes < bytes ||
                    (!entry->bitmap && entry->offset < min_start)) {
-                       struct rb_node *node;
-
                        node = rb_next(&entry->offset_index);
                        if (!node)
                                break;
@@ -1925,7 +2079,6 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
                                                      cluster, entry, bytes,
                                                      min_start);
                        if (ret == 0) {
-                               struct rb_node *node;
                                node = rb_next(&entry->offset_index);
                                if (!node)
                                        break;
@@ -1951,20 +2104,20 @@ out:
        if (!ret)
                return 0;
 
-       spin_lock(&block_group->tree_lock);
+       spin_lock(&ctl->tree_lock);
 
-       block_group->free_space -= bytes;
+       ctl->free_space -= bytes;
        if (entry->bytes == 0) {
-               block_group->free_extents--;
+               ctl->free_extents--;
                if (entry->bitmap) {
                        kfree(entry->bitmap);
-                       block_group->total_bitmaps--;
-                       recalculate_thresholds(block_group);
+                       ctl->total_bitmaps--;
+                       ctl->op->recalc_thresholds(ctl);
                }
                kmem_cache_free(btrfs_free_space_cachep, entry);
        }
 
-       spin_unlock(&block_group->tree_lock);
+       spin_unlock(&ctl->tree_lock);
 
        return ret;
 }
@@ -1974,6 +2127,7 @@ static int btrfs_bitmap_cluster(struct btrfs_block_group_cache *block_group,
                                struct btrfs_free_cluster *cluster,
                                u64 offset, u64 bytes, u64 min_bytes)
 {
+       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        unsigned long next_zero;
        unsigned long i;
        unsigned long search_bits;
@@ -2028,7 +2182,7 @@ again:
 
        cluster->window_start = start * block_group->sectorsize +
                entry->offset;
-       rb_erase(&entry->offset_index, &block_group->free_space_offset);
+       rb_erase(&entry->offset_index, &ctl->free_space_offset);
        ret = tree_insert_offset(&cluster->root, entry->offset,
                                 &entry->offset_index, 1);
        BUG_ON(ret);
@@ -2039,10 +2193,13 @@ again:
 /*
  * This searches the block group for just extents to fill the cluster with.
  */
-static int setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group,
-                                  struct btrfs_free_cluster *cluster,
-                                  u64 offset, u64 bytes, u64 min_bytes)
+static noinline int
+setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group,
+                       struct btrfs_free_cluster *cluster,
+                       struct list_head *bitmaps, u64 offset, u64 bytes,
+                       u64 min_bytes)
 {
+       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        struct btrfs_free_space *first = NULL;
        struct btrfs_free_space *entry = NULL;
        struct btrfs_free_space *prev = NULL;
@@ -2053,7 +2210,7 @@ static int setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group,
        u64 max_extent;
        u64 max_gap = 128 * 1024;
 
-       entry = tree_search_offset(block_group, offset, 0, 1);
+       entry = tree_search_offset(ctl, offset, 0, 1);
        if (!entry)
                return -ENOSPC;
 
@@ -2062,6 +2219,8 @@ static int setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group,
         * extent entry.
         */
        while (entry->bitmap) {
+               if (list_empty(&entry->list))
+                       list_add_tail(&entry->list, bitmaps);
                node = rb_next(&entry->offset_index);
                if (!node)
                        return -ENOSPC;
@@ -2081,8 +2240,12 @@ static int setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group,
                        return -ENOSPC;
                entry = rb_entry(node, struct btrfs_free_space, offset_index);
 
-               if (entry->bitmap)
+               if (entry->bitmap) {
+                       if (list_empty(&entry->list))
+                               list_add_tail(&entry->list, bitmaps);
                        continue;
+               }
+
                /*
                 * we haven't filled the empty size and the window is
                 * very large.  reset and try again
@@ -2119,7 +2282,7 @@ static int setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group,
                if (entry->bitmap)
                        continue;
 
-               rb_erase(&entry->offset_index, &block_group->free_space_offset);
+               rb_erase(&entry->offset_index, &ctl->free_space_offset);
                ret = tree_insert_offset(&cluster->root, entry->offset,
                                         &entry->offset_index, 0);
                BUG_ON(ret);
@@ -2134,23 +2297,53 @@ static int setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group,
  * This specifically looks for bitmaps that may work in the cluster, we assume
  * that we have already failed to find extents that will work.
  */
-static int setup_cluster_bitmap(struct btrfs_block_group_cache *block_group,
-                               struct btrfs_free_cluster *cluster,
-                               u64 offset, u64 bytes, u64 min_bytes)
+static noinline int
+setup_cluster_bitmap(struct btrfs_block_group_cache *block_group,
+                    struct btrfs_free_cluster *cluster,
+                    struct list_head *bitmaps, u64 offset, u64 bytes,
+                    u64 min_bytes)
 {
+       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        struct btrfs_free_space *entry;
        struct rb_node *node;
        int ret = -ENOSPC;
 
-       if (block_group->total_bitmaps == 0)
+       if (ctl->total_bitmaps == 0)
                return -ENOSPC;
 
-       entry = tree_search_offset(block_group,
-                                  offset_to_bitmap(block_group, offset),
-                                  0, 1);
+       /*
+        * First check our cached list of bitmaps and see if there is an entry
+        * here that will work.
+        */
+       list_for_each_entry(entry, bitmaps, list) {
+               if (entry->bytes < min_bytes)
+                       continue;
+               ret = btrfs_bitmap_cluster(block_group, entry, cluster, offset,
+                                          bytes, min_bytes);
+               if (!ret)
+                       return 0;
+       }
+
+       /*
+        * If we do have entries on our list and we are here then we didn't find
+        * anything, so go ahead and get the next entry after the last entry in
+        * this list and start the search from there.
+        */
+       if (!list_empty(bitmaps)) {
+               entry = list_entry(bitmaps->prev, struct btrfs_free_space,
+                                  list);
+               node = rb_next(&entry->offset_index);
+               if (!node)
+                       return -ENOSPC;
+               entry = rb_entry(node, struct btrfs_free_space, offset_index);
+               goto search;
+       }
+
+       entry = tree_search_offset(ctl, offset_to_bitmap(ctl, offset), 0, 1);
        if (!entry)
                return -ENOSPC;
 
+search:
        node = &entry->offset_index;
        do {
                entry = rb_entry(node, struct btrfs_free_space, offset_index);
@@ -2180,6 +2373,9 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
                             struct btrfs_free_cluster *cluster,
                             u64 offset, u64 bytes, u64 empty_size)
 {
+       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
+       struct list_head bitmaps;
+       struct btrfs_free_space *entry, *tmp;
        u64 min_bytes;
        int ret;
 
@@ -2199,14 +2395,14 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
        } else
                min_bytes = max(bytes, (bytes + empty_size) >> 2);
 
-       spin_lock(&block_group->tree_lock);
+       spin_lock(&ctl->tree_lock);
 
        /*
         * If we know we don't have enough space to make a cluster don't even
         * bother doing all the work to try and find one.
         */
-       if (block_group->free_space < min_bytes) {
-               spin_unlock(&block_group->tree_lock);
+       if (ctl->free_space < min_bytes) {
+               spin_unlock(&ctl->tree_lock);
                return -ENOSPC;
        }
 
@@ -2218,11 +2414,16 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
                goto out;
        }
 
-       ret = setup_cluster_no_bitmap(block_group, cluster, offset, bytes,
-                                     min_bytes);
+       INIT_LIST_HEAD(&bitmaps);
+       ret = setup_cluster_no_bitmap(block_group, cluster, &bitmaps, offset,
+                                     bytes, min_bytes);
        if (ret)
-               ret = setup_cluster_bitmap(block_group, cluster, offset,
-                                          bytes, min_bytes);
+               ret = setup_cluster_bitmap(block_group, cluster, &bitmaps,
+                                          offset, bytes, min_bytes);
+
+       /* Clear our temporary list */
+       list_for_each_entry_safe(entry, tmp, &bitmaps, list)
+               list_del_init(&entry->list);
 
        if (!ret) {
                atomic_inc(&block_group->count);
@@ -2232,7 +2433,7 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
        }
 out:
        spin_unlock(&cluster->lock);
-       spin_unlock(&block_group->tree_lock);
+       spin_unlock(&ctl->tree_lock);
 
        return ret;
 }
@@ -2253,6 +2454,7 @@ void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster)
 int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
                           u64 *trimmed, u64 start, u64 end, u64 minlen)
 {
+       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        struct btrfs_free_space *entry = NULL;
        struct btrfs_fs_info *fs_info = block_group->fs_info;
        u64 bytes = 0;
@@ -2262,52 +2464,50 @@ int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
        *trimmed = 0;
 
        while (start < end) {
-               spin_lock(&block_group->tree_lock);
+               spin_lock(&ctl->tree_lock);
 
-               if (block_group->free_space < minlen) {
-                       spin_unlock(&block_group->tree_lock);
+               if (ctl->free_space < minlen) {
+                       spin_unlock(&ctl->tree_lock);
                        break;
                }
 
-               entry = tree_search_offset(block_group, start, 0, 1);
+               entry = tree_search_offset(ctl, start, 0, 1);
                if (!entry)
-                       entry = tree_search_offset(block_group,
-                                                  offset_to_bitmap(block_group,
-                                                                   start),
+                       entry = tree_search_offset(ctl,
+                                                  offset_to_bitmap(ctl, start),
                                                   1, 1);
 
                if (!entry || entry->offset >= end) {
-                       spin_unlock(&block_group->tree_lock);
+                       spin_unlock(&ctl->tree_lock);
                        break;
                }
 
                if (entry->bitmap) {
-                       ret = search_bitmap(block_group, entry, &start, &bytes);
+                       ret = search_bitmap(ctl, entry, &start, &bytes);
                        if (!ret) {
                                if (start >= end) {
-                                       spin_unlock(&block_group->tree_lock);
+                                       spin_unlock(&ctl->tree_lock);
                                        break;
                                }
                                bytes = min(bytes, end - start);
-                               bitmap_clear_bits(block_group, entry,
-                                                 start, bytes);
+                               bitmap_clear_bits(ctl, entry, start, bytes);
                                if (entry->bytes == 0)
-                                       free_bitmap(block_group, entry);
+                                       free_bitmap(ctl, entry);
                        } else {
                                start = entry->offset + BITS_PER_BITMAP *
                                        block_group->sectorsize;
-                               spin_unlock(&block_group->tree_lock);
+                               spin_unlock(&ctl->tree_lock);
                                ret = 0;
                                continue;
                        }
                } else {
                        start = entry->offset;
                        bytes = min(entry->bytes, end - start);
-                       unlink_free_space(block_group, entry);
+                       unlink_free_space(ctl, entry);
                        kmem_cache_free(btrfs_free_space_cachep, entry);
                }
 
-               spin_unlock(&block_group->tree_lock);
+               spin_unlock(&ctl->tree_lock);
 
                if (bytes >= minlen) {
                        int update_ret;
@@ -2319,8 +2519,7 @@ int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
                                                         bytes,
                                                         &actually_trimmed);
 
-                       btrfs_add_free_space(block_group,
-                                            start, bytes);
+                       btrfs_add_free_space(block_group, start, bytes);
                        if (!update_ret)
                                btrfs_update_reserved_bytes(block_group,
                                                            bytes, 0, 1);
@@ -2342,3 +2541,150 @@ int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
 
        return ret;
 }
+
+/*
+ * Find the left-most item in the cache tree, and then return the
+ * smallest inode number in the item.
+ *
+ * Note: the returned inode number may not be the smallest one in
+ * the tree, if the left-most item is a bitmap.
+ */
+u64 btrfs_find_ino_for_alloc(struct btrfs_root *fs_root)
+{
+       struct btrfs_free_space_ctl *ctl = fs_root->free_ino_ctl;
+       struct btrfs_free_space *entry = NULL;
+       u64 ino = 0;
+
+       spin_lock(&ctl->tree_lock);
+
+       if (RB_EMPTY_ROOT(&ctl->free_space_offset))
+               goto out;
+
+       entry = rb_entry(rb_first(&ctl->free_space_offset),
+                        struct btrfs_free_space, offset_index);
+
+       if (!entry->bitmap) {
+               ino = entry->offset;
+
+               unlink_free_space(ctl, entry);
+               entry->offset++;
+               entry->bytes--;
+               if (!entry->bytes)
+                       kmem_cache_free(btrfs_free_space_cachep, entry);
+               else
+                       link_free_space(ctl, entry);
+       } else {
+               u64 offset = 0;
+               u64 count = 1;
+               int ret;
+
+               ret = search_bitmap(ctl, entry, &offset, &count);
+               BUG_ON(ret);
+
+               ino = offset;
+               bitmap_clear_bits(ctl, entry, offset, 1);
+               if (entry->bytes == 0)
+                       free_bitmap(ctl, entry);
+       }
+out:
+       spin_unlock(&ctl->tree_lock);
+
+       return ino;
+}
+
+struct inode *lookup_free_ino_inode(struct btrfs_root *root,
+                                   struct btrfs_path *path)
+{
+       struct inode *inode = NULL;
+
+       spin_lock(&root->cache_lock);
+       if (root->cache_inode)
+               inode = igrab(root->cache_inode);
+       spin_unlock(&root->cache_lock);
+       if (inode)
+               return inode;
+
+       inode = __lookup_free_space_inode(root, path, 0);
+       if (IS_ERR(inode))
+               return inode;
+
+       spin_lock(&root->cache_lock);
+       if (!btrfs_fs_closing(root->fs_info))
+               root->cache_inode = igrab(inode);
+       spin_unlock(&root->cache_lock);
+
+       return inode;
+}
+
+int create_free_ino_inode(struct btrfs_root *root,
+                         struct btrfs_trans_handle *trans,
+                         struct btrfs_path *path)
+{
+       return __create_free_space_inode(root, trans, path,
+                                        BTRFS_FREE_INO_OBJECTID, 0);
+}
+
+int load_free_ino_cache(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
+{
+       struct btrfs_free_space_ctl *ctl = root->free_ino_ctl;
+       struct btrfs_path *path;
+       struct inode *inode;
+       int ret = 0;
+       u64 root_gen = btrfs_root_generation(&root->root_item);
+
+       if (!btrfs_test_opt(root, INODE_MAP_CACHE))
+               return 0;
+
+       /*
+        * If we're unmounting then just return, since this does a search on the
+        * normal root and not the commit root and we could deadlock.
+        */
+       if (btrfs_fs_closing(fs_info))
+               return 0;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return 0;
+
+       inode = lookup_free_ino_inode(root, path);
+       if (IS_ERR(inode))
+               goto out;
+
+       if (root_gen != BTRFS_I(inode)->generation)
+               goto out_put;
+
+       ret = __load_free_space_cache(root, inode, ctl, path, 0);
+
+       if (ret < 0)
+               printk(KERN_ERR "btrfs: failed to load free ino cache for "
+                      "root %llu\n", root->root_key.objectid);
+out_put:
+       iput(inode);
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
+int btrfs_write_out_ino_cache(struct btrfs_root *root,
+                             struct btrfs_trans_handle *trans,
+                             struct btrfs_path *path)
+{
+       struct btrfs_free_space_ctl *ctl = root->free_ino_ctl;
+       struct inode *inode;
+       int ret;
+
+       if (!btrfs_test_opt(root, INODE_MAP_CACHE))
+               return 0;
+
+       inode = lookup_free_ino_inode(root, path);
+       if (IS_ERR(inode))
+               return 0;
+
+       ret = __btrfs_write_out_cache(root, inode, ctl, NULL, trans, path, 0);
+       if (ret < 0)
+               printk(KERN_ERR "btrfs: failed to write free ino cache "
+                      "for root %llu\n", root->root_key.objectid);
+
+       iput(inode);
+       return ret;
+}
index 65c3b935289f3814747947e8967e091cf0e4b1a3..8f2613f779edc6bfb2dfcac1e6884f2d7ad156b7 100644 (file)
@@ -27,6 +27,25 @@ struct btrfs_free_space {
        struct list_head list;
 };
 
+struct btrfs_free_space_ctl {
+       spinlock_t tree_lock;
+       struct rb_root free_space_offset;
+       u64 free_space;
+       int extents_thresh;
+       int free_extents;
+       int total_bitmaps;
+       int unit;
+       u64 start;
+       struct btrfs_free_space_op *op;
+       void *private;
+};
+
+struct btrfs_free_space_op {
+       void (*recalc_thresholds)(struct btrfs_free_space_ctl *ctl);
+       bool (*use_bitmap)(struct btrfs_free_space_ctl *ctl,
+                          struct btrfs_free_space *info);
+};
+
 struct inode *lookup_free_space_inode(struct btrfs_root *root,
                                      struct btrfs_block_group_cache
                                      *block_group, struct btrfs_path *path);
@@ -45,17 +64,38 @@ int btrfs_write_out_cache(struct btrfs_root *root,
                          struct btrfs_trans_handle *trans,
                          struct btrfs_block_group_cache *block_group,
                          struct btrfs_path *path);
-int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
-                        u64 bytenr, u64 size);
+
+struct inode *lookup_free_ino_inode(struct btrfs_root *root,
+                                   struct btrfs_path *path);
+int create_free_ino_inode(struct btrfs_root *root,
+                         struct btrfs_trans_handle *trans,
+                         struct btrfs_path *path);
+int load_free_ino_cache(struct btrfs_fs_info *fs_info,
+                       struct btrfs_root *root);
+int btrfs_write_out_ino_cache(struct btrfs_root *root,
+                             struct btrfs_trans_handle *trans,
+                             struct btrfs_path *path);
+
+void btrfs_init_free_space_ctl(struct btrfs_block_group_cache *block_group);
+int __btrfs_add_free_space(struct btrfs_free_space_ctl *ctl,
+                          u64 bytenr, u64 size);
+static inline int
+btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
+                    u64 bytenr, u64 size)
+{
+       return __btrfs_add_free_space(block_group->free_space_ctl,
+                                     bytenr, size);
+}
 int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
                            u64 bytenr, u64 size);
+void __btrfs_remove_free_space_cache(struct btrfs_free_space_ctl *ctl);
 void btrfs_remove_free_space_cache(struct btrfs_block_group_cache
-                                  *block_group);
+                                    *block_group);
 u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
                               u64 offset, u64 bytes, u64 empty_size);
+u64 btrfs_find_ino_for_alloc(struct btrfs_root *fs_root);
 void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
                           u64 bytes);
-u64 btrfs_block_group_free_space(struct btrfs_block_group_cache *block_group);
 int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             struct btrfs_block_group_cache *block_group,
index 64f1150bb48d1fb1cd5b7c7d29742b3f9afff7cd..baa74f3db6911fb4ff6f2497964a2f69caef95a0 100644 (file)
@@ -130,7 +130,6 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
                              item_size - (ptr + sub_item_len - item_start));
        ret = btrfs_truncate_item(trans, root, path,
                                  item_size - sub_item_len, 1);
-       BUG_ON(ret);
 out:
        btrfs_free_path(path);
        return ret;
@@ -167,7 +166,6 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
 
                old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);
                ret = btrfs_extend_item(trans, root, path, ins_len);
-               BUG_ON(ret);
                ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
                                     struct btrfs_inode_ref);
                ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size);
index c05a08f4c4111fdfa4157e9447005523f256fb67..b4087e0fa8714bca45e5fc026caf3491e212dd14 100644 (file)
  * Boston, MA 021110-1307, USA.
  */
 
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/pagemap.h>
+
 #include "ctree.h"
 #include "disk-io.h"
+#include "free-space-cache.h"
+#include "inode-map.h"
 #include "transaction.h"
 
-int btrfs_find_highest_inode(struct btrfs_root *root, u64 *objectid)
+static int caching_kthread(void *data)
+{
+       struct btrfs_root *root = data;
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_free_space_ctl *ctl = root->free_ino_ctl;
+       struct btrfs_key key;
+       struct btrfs_path *path;
+       struct extent_buffer *leaf;
+       u64 last = (u64)-1;
+       int slot;
+       int ret;
+
+       if (!btrfs_test_opt(root, INODE_MAP_CACHE))
+               return 0;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       /* Since the commit root is read-only, we can safely skip locking. */
+       path->skip_locking = 1;
+       path->search_commit_root = 1;
+       path->reada = 2;
+
+       key.objectid = BTRFS_FIRST_FREE_OBJECTID;
+       key.offset = 0;
+       key.type = BTRFS_INODE_ITEM_KEY;
+again:
+       /* need to make sure the commit_root doesn't disappear */
+       mutex_lock(&root->fs_commit_mutex);
+
+       ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+       if (ret < 0)
+               goto out;
+
+       while (1) {
+               if (btrfs_fs_closing(fs_info))
+                       goto out;
+
+               leaf = path->nodes[0];
+               slot = path->slots[0];
+               if (slot >= btrfs_header_nritems(leaf)) {
+                       ret = btrfs_next_leaf(root, path);
+                       if (ret < 0)
+                               goto out;
+                       else if (ret > 0)
+                               break;
+
+                       if (need_resched() ||
+                           btrfs_transaction_in_commit(fs_info)) {
+                               leaf = path->nodes[0];
+
+                               if (btrfs_header_nritems(leaf) == 0) {
+                                       WARN_ON(1);
+                                       break;
+                               }
+
+                               /*
+                                * Save the key so we can advances forward
+                                * in the next search.
+                                */
+                               btrfs_item_key_to_cpu(leaf, &key, 0);
+                               btrfs_release_path(path);
+                               root->cache_progress = last;
+                               mutex_unlock(&root->fs_commit_mutex);
+                               schedule_timeout(1);
+                               goto again;
+                       } else
+                               continue;
+               }
+
+               btrfs_item_key_to_cpu(leaf, &key, slot);
+
+               if (key.type != BTRFS_INODE_ITEM_KEY)
+                       goto next;
+
+               if (key.objectid >= root->highest_objectid)
+                       break;
+
+               if (last != (u64)-1 && last + 1 != key.objectid) {
+                       __btrfs_add_free_space(ctl, last + 1,
+                                              key.objectid - last - 1);
+                       wake_up(&root->cache_wait);
+               }
+
+               last = key.objectid;
+next:
+               path->slots[0]++;
+       }
+
+       if (last < root->highest_objectid - 1) {
+               __btrfs_add_free_space(ctl, last + 1,
+                                      root->highest_objectid - last - 1);
+       }
+
+       spin_lock(&root->cache_lock);
+       root->cached = BTRFS_CACHE_FINISHED;
+       spin_unlock(&root->cache_lock);
+
+       root->cache_progress = (u64)-1;
+       btrfs_unpin_free_ino(root);
+out:
+       wake_up(&root->cache_wait);
+       mutex_unlock(&root->fs_commit_mutex);
+
+       btrfs_free_path(path);
+
+       return ret;
+}
+
+static void start_caching(struct btrfs_root *root)
+{
+       struct btrfs_free_space_ctl *ctl = root->free_ino_ctl;
+       struct task_struct *tsk;
+       int ret;
+       u64 objectid;
+
+       if (!btrfs_test_opt(root, INODE_MAP_CACHE))
+               return;
+
+       spin_lock(&root->cache_lock);
+       if (root->cached != BTRFS_CACHE_NO) {
+               spin_unlock(&root->cache_lock);
+               return;
+       }
+
+       root->cached = BTRFS_CACHE_STARTED;
+       spin_unlock(&root->cache_lock);
+
+       ret = load_free_ino_cache(root->fs_info, root);
+       if (ret == 1) {
+               spin_lock(&root->cache_lock);
+               root->cached = BTRFS_CACHE_FINISHED;
+               spin_unlock(&root->cache_lock);
+               return;
+       }
+
+       /*
+        * It can be quite time-consuming to fill the cache by searching
+        * through the extent tree, and this can keep ino allocation path
+        * waiting. Therefore at start we quickly find out the highest
+        * inode number and we know we can use inode numbers which fall in
+        * [highest_ino + 1, BTRFS_LAST_FREE_OBJECTID].
+        */
+       ret = btrfs_find_free_objectid(root, &objectid);
+       if (!ret && objectid <= BTRFS_LAST_FREE_OBJECTID) {
+               __btrfs_add_free_space(ctl, objectid,
+                                      BTRFS_LAST_FREE_OBJECTID - objectid + 1);
+       }
+
+       tsk = kthread_run(caching_kthread, root, "btrfs-ino-cache-%llu\n",
+                         root->root_key.objectid);
+       BUG_ON(IS_ERR(tsk));
+}
+
+int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid)
+{
+       if (!btrfs_test_opt(root, INODE_MAP_CACHE))
+               return btrfs_find_free_objectid(root, objectid);
+
+again:
+       *objectid = btrfs_find_ino_for_alloc(root);
+
+       if (*objectid != 0)
+               return 0;
+
+       start_caching(root);
+
+       wait_event(root->cache_wait,
+                  root->cached == BTRFS_CACHE_FINISHED ||
+                  root->free_ino_ctl->free_space > 0);
+
+       if (root->cached == BTRFS_CACHE_FINISHED &&
+           root->free_ino_ctl->free_space == 0)
+               return -ENOSPC;
+       else
+               goto again;
+}
+
+void btrfs_return_ino(struct btrfs_root *root, u64 objectid)
+{
+       struct btrfs_free_space_ctl *ctl = root->free_ino_ctl;
+       struct btrfs_free_space_ctl *pinned = root->free_ino_pinned;
+
+       if (!btrfs_test_opt(root, INODE_MAP_CACHE))
+               return;
+
+again:
+       if (root->cached == BTRFS_CACHE_FINISHED) {
+               __btrfs_add_free_space(ctl, objectid, 1);
+       } else {
+               /*
+                * If we are in the process of caching free ino chunks,
+                * to avoid adding the same inode number to the free_ino
+                * tree twice due to cross transaction, we'll leave it
+                * in the pinned tree until a transaction is committed
+                * or the caching work is done.
+                */
+
+               mutex_lock(&root->fs_commit_mutex);
+               spin_lock(&root->cache_lock);
+               if (root->cached == BTRFS_CACHE_FINISHED) {
+                       spin_unlock(&root->cache_lock);
+                       mutex_unlock(&root->fs_commit_mutex);
+                       goto again;
+               }
+               spin_unlock(&root->cache_lock);
+
+               start_caching(root);
+
+               if (objectid <= root->cache_progress ||
+                   objectid > root->highest_objectid)
+                       __btrfs_add_free_space(ctl, objectid, 1);
+               else
+                       __btrfs_add_free_space(pinned, objectid, 1);
+
+               mutex_unlock(&root->fs_commit_mutex);
+       }
+}
+
+/*
+ * When a transaction is committed, we'll move those inode numbers which
+ * are smaller than root->cache_progress from pinned tree to free_ino tree,
+ * and others will just be dropped, because the commit root we were
+ * searching has changed.
+ *
+ * Must be called with root->fs_commit_mutex held
+ */
+void btrfs_unpin_free_ino(struct btrfs_root *root)
+{
+       struct btrfs_free_space_ctl *ctl = root->free_ino_ctl;
+       struct rb_root *rbroot = &root->free_ino_pinned->free_space_offset;
+       struct btrfs_free_space *info;
+       struct rb_node *n;
+       u64 count;
+
+       if (!btrfs_test_opt(root, INODE_MAP_CACHE))
+               return;
+
+       while (1) {
+               n = rb_first(rbroot);
+               if (!n)
+                       break;
+
+               info = rb_entry(n, struct btrfs_free_space, offset_index);
+               BUG_ON(info->bitmap);
+
+               if (info->offset > root->cache_progress)
+                       goto free;
+               else if (info->offset + info->bytes > root->cache_progress)
+                       count = root->cache_progress - info->offset + 1;
+               else
+                       count = info->bytes;
+
+               __btrfs_add_free_space(ctl, info->offset, count);
+free:
+               rb_erase(&info->offset_index, rbroot);
+               kfree(info);
+       }
+}
+
+#define INIT_THRESHOLD (((1024 * 32) / 2) / sizeof(struct btrfs_free_space))
+#define INODES_PER_BITMAP (PAGE_CACHE_SIZE * 8)
+
+/*
+ * The goal is to keep the memory used by the free_ino tree won't
+ * exceed the memory if we use bitmaps only.
+ */
+static void recalculate_thresholds(struct btrfs_free_space_ctl *ctl)
+{
+       struct btrfs_free_space *info;
+       struct rb_node *n;
+       int max_ino;
+       int max_bitmaps;
+
+       n = rb_last(&ctl->free_space_offset);
+       if (!n) {
+               ctl->extents_thresh = INIT_THRESHOLD;
+               return;
+       }
+       info = rb_entry(n, struct btrfs_free_space, offset_index);
+
+       /*
+        * Find the maximum inode number in the filesystem. Note we
+        * ignore the fact that this can be a bitmap, because we are
+        * not doing precise calculation.
+        */
+       max_ino = info->bytes - 1;
+
+       max_bitmaps = ALIGN(max_ino, INODES_PER_BITMAP) / INODES_PER_BITMAP;
+       if (max_bitmaps <= ctl->total_bitmaps) {
+               ctl->extents_thresh = 0;
+               return;
+       }
+
+       ctl->extents_thresh = (max_bitmaps - ctl->total_bitmaps) *
+                               PAGE_CACHE_SIZE / sizeof(*info);
+}
+
+/*
+ * We don't fall back to bitmap, if we are below the extents threshold
+ * or this chunk of inode numbers is a big one.
+ */
+static bool use_bitmap(struct btrfs_free_space_ctl *ctl,
+                      struct btrfs_free_space *info)
+{
+       if (ctl->free_extents < ctl->extents_thresh ||
+           info->bytes > INODES_PER_BITMAP / 10)
+               return false;
+
+       return true;
+}
+
+static struct btrfs_free_space_op free_ino_op = {
+       .recalc_thresholds      = recalculate_thresholds,
+       .use_bitmap             = use_bitmap,
+};
+
+static void pinned_recalc_thresholds(struct btrfs_free_space_ctl *ctl)
+{
+}
+
+static bool pinned_use_bitmap(struct btrfs_free_space_ctl *ctl,
+                             struct btrfs_free_space *info)
+{
+       /*
+        * We always use extents for two reasons:
+        *
+        * - The pinned tree is only used during the process of caching
+        *   work.
+        * - Make code simpler. See btrfs_unpin_free_ino().
+        */
+       return false;
+}
+
+static struct btrfs_free_space_op pinned_free_ino_op = {
+       .recalc_thresholds      = pinned_recalc_thresholds,
+       .use_bitmap             = pinned_use_bitmap,
+};
+
+void btrfs_init_free_ino_ctl(struct btrfs_root *root)
+{
+       struct btrfs_free_space_ctl *ctl = root->free_ino_ctl;
+       struct btrfs_free_space_ctl *pinned = root->free_ino_pinned;
+
+       spin_lock_init(&ctl->tree_lock);
+       ctl->unit = 1;
+       ctl->start = 0;
+       ctl->private = NULL;
+       ctl->op = &free_ino_op;
+
+       /*
+        * Initially we allow to use 16K of ram to cache chunks of
+        * inode numbers before we resort to bitmaps. This is somewhat
+        * arbitrary, but it will be adjusted in runtime.
+        */
+       ctl->extents_thresh = INIT_THRESHOLD;
+
+       spin_lock_init(&pinned->tree_lock);
+       pinned->unit = 1;
+       pinned->start = 0;
+       pinned->private = NULL;
+       pinned->extents_thresh = 0;
+       pinned->op = &pinned_free_ino_op;
+}
+
+int btrfs_save_ino_cache(struct btrfs_root *root,
+                        struct btrfs_trans_handle *trans)
+{
+       struct btrfs_free_space_ctl *ctl = root->free_ino_ctl;
+       struct btrfs_path *path;
+       struct inode *inode;
+       u64 alloc_hint = 0;
+       int ret;
+       int prealloc;
+       bool retry = false;
+
+       /* only fs tree and subvol/snap needs ino cache */
+       if (root->root_key.objectid != BTRFS_FS_TREE_OBJECTID &&
+           (root->root_key.objectid < BTRFS_FIRST_FREE_OBJECTID ||
+            root->root_key.objectid > BTRFS_LAST_FREE_OBJECTID))
+               return 0;
+
+       /* Don't save inode cache if we are deleting this root */
+       if (btrfs_root_refs(&root->root_item) == 0 &&
+           root != root->fs_info->tree_root)
+               return 0;
+
+       if (!btrfs_test_opt(root, INODE_MAP_CACHE))
+               return 0;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+again:
+       inode = lookup_free_ino_inode(root, path);
+       if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {
+               ret = PTR_ERR(inode);
+               goto out;
+       }
+
+       if (IS_ERR(inode)) {
+               BUG_ON(retry);
+               retry = true;
+
+               ret = create_free_ino_inode(root, trans, path);
+               if (ret)
+                       goto out;
+               goto again;
+       }
+
+       BTRFS_I(inode)->generation = 0;
+       ret = btrfs_update_inode(trans, root, inode);
+       WARN_ON(ret);
+
+       if (i_size_read(inode) > 0) {
+               ret = btrfs_truncate_free_space_cache(root, trans, path, inode);
+               if (ret)
+                       goto out_put;
+       }
+
+       spin_lock(&root->cache_lock);
+       if (root->cached != BTRFS_CACHE_FINISHED) {
+               ret = -1;
+               spin_unlock(&root->cache_lock);
+               goto out_put;
+       }
+       spin_unlock(&root->cache_lock);
+
+       spin_lock(&ctl->tree_lock);
+       prealloc = sizeof(struct btrfs_free_space) * ctl->free_extents;
+       prealloc = ALIGN(prealloc, PAGE_CACHE_SIZE);
+       prealloc += ctl->total_bitmaps * PAGE_CACHE_SIZE;
+       spin_unlock(&ctl->tree_lock);
+
+       /* Just to make sure we have enough space */
+       prealloc += 8 * PAGE_CACHE_SIZE;
+
+       ret = btrfs_check_data_free_space(inode, prealloc);
+       if (ret)
+               goto out_put;
+
+       ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, prealloc,
+                                             prealloc, prealloc, &alloc_hint);
+       if (ret)
+               goto out_put;
+       btrfs_free_reserved_data_space(inode, prealloc);
+
+out_put:
+       iput(inode);
+out:
+       if (ret == 0)
+               ret = btrfs_write_out_ino_cache(root, trans, path);
+
+       btrfs_free_path(path);
+       return ret;
+}
+
+static int btrfs_find_highest_objectid(struct btrfs_root *root, u64 *objectid)
 {
        struct btrfs_path *path;
        int ret;
@@ -55,15 +520,14 @@ error:
        return ret;
 }
 
-int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
-                            struct btrfs_root *root,
-                            u64 dirid, u64 *objectid)
+int btrfs_find_free_objectid(struct btrfs_root *root, u64 *objectid)
 {
        int ret;
        mutex_lock(&root->objectid_mutex);
 
        if (unlikely(root->highest_objectid < BTRFS_FIRST_FREE_OBJECTID)) {
-               ret = btrfs_find_highest_inode(root, &root->highest_objectid);
+               ret = btrfs_find_highest_objectid(root,
+                                                 &root->highest_objectid);
                if (ret)
                        goto out;
        }
diff --git a/fs/btrfs/inode-map.h b/fs/btrfs/inode-map.h
new file mode 100644 (file)
index 0000000..ddb347b
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __BTRFS_INODE_MAP
+#define __BTRFS_INODE_MAP
+
+void btrfs_init_free_ino_ctl(struct btrfs_root *root);
+void btrfs_unpin_free_ino(struct btrfs_root *root);
+void btrfs_return_ino(struct btrfs_root *root, u64 objectid);
+int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid);
+int btrfs_save_ino_cache(struct btrfs_root *root,
+                        struct btrfs_trans_handle *trans);
+
+int btrfs_find_free_objectid(struct btrfs_root *root, u64 *objectid);
+
+#endif
index 7cd8ab0ef04d5b3e95ccd572f96ca858457e8c18..0a9b10c5b0a7458a6f2aca7a195c1980e1b88bb8 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/posix_acl.h>
 #include <linux/falloc.h>
 #include <linux/slab.h>
+#include <linux/ratelimit.h>
 #include "compat.h"
 #include "ctree.h"
 #include "disk-io.h"
@@ -51,6 +52,7 @@
 #include "compression.h"
 #include "locking.h"
 #include "free-space-cache.h"
+#include "inode-map.h"
 
 struct btrfs_iget_args {
        u64 ino;
@@ -136,9 +138,8 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
                return -ENOMEM;
 
        path->leave_spinning = 1;
-       btrfs_set_trans_block_group(trans, inode);
 
-       key.objectid = inode->i_ino;
+       key.objectid = btrfs_ino(inode);
        key.offset = start;
        btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
        datasize = btrfs_file_extent_calc_inline_size(cur_size);
@@ -340,6 +341,10 @@ static noinline int compress_file_range(struct inode *inode,
        int will_compress;
        int compress_type = root->fs_info->compress_type;
 
+       /* if this is a small write inside eof, kick off a defragbot */
+       if (end <= BTRFS_I(inode)->disk_i_size && (end - start + 1) < 16 * 1024)
+               btrfs_add_inode_defrag(NULL, inode);
+
        actual_end = min_t(u64, isize, end + 1);
 again:
        will_compress = 0;
@@ -420,9 +425,8 @@ again:
                }
        }
        if (start == 0) {
-               trans = btrfs_join_transaction(root, 1);
+               trans = btrfs_join_transaction(root);
                BUG_ON(IS_ERR(trans));
-               btrfs_set_trans_block_group(trans, inode);
                trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
                /* lets try to make an inline extent */
@@ -617,8 +621,9 @@ retry:
                            async_extent->start + async_extent->ram_size - 1,
                            GFP_NOFS);
 
-               trans = btrfs_join_transaction(root, 1);
+               trans = btrfs_join_transaction(root);
                BUG_ON(IS_ERR(trans));
+               trans->block_rsv = &root->fs_info->delalloc_block_rsv;
                ret = btrfs_reserve_extent(trans, root,
                                           async_extent->compressed_size,
                                           async_extent->compressed_size,
@@ -649,7 +654,7 @@ retry:
                                        async_extent->start +
                                        async_extent->ram_size - 1, 0);
 
-               em = alloc_extent_map(GFP_NOFS);
+               em = alloc_extent_map();
                BUG_ON(!em);
                em->start = async_extent->start;
                em->len = async_extent->ram_size;
@@ -745,6 +750,15 @@ static u64 get_extent_allocation_hint(struct inode *inode, u64 start,
        return alloc_hint;
 }
 
+static inline bool is_free_space_inode(struct btrfs_root *root,
+                                      struct inode *inode)
+{
+       if (root == root->fs_info->tree_root ||
+           BTRFS_I(inode)->location.objectid == BTRFS_FREE_INO_OBJECTID)
+               return true;
+       return false;
+}
+
 /*
  * when extent_io.c finds a delayed allocation range in the file,
  * the call backs end up in this code.  The basic idea is to
@@ -777,10 +791,9 @@ static noinline int cow_file_range(struct inode *inode,
        struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
        int ret = 0;
 
-       BUG_ON(root == root->fs_info->tree_root);
-       trans = btrfs_join_transaction(root, 1);
+       BUG_ON(is_free_space_inode(root, inode));
+       trans = btrfs_join_transaction(root);
        BUG_ON(IS_ERR(trans));
-       btrfs_set_trans_block_group(trans, inode);
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
        num_bytes = (end - start + blocksize) & ~(blocksize - 1);
@@ -788,6 +801,10 @@ static noinline int cow_file_range(struct inode *inode,
        disk_num_bytes = num_bytes;
        ret = 0;
 
+       /* if this is a small write inside eof, kick off defrag */
+       if (end <= BTRFS_I(inode)->disk_i_size && num_bytes < 64 * 1024)
+               btrfs_add_inode_defrag(trans, inode);
+
        if (start == 0) {
                /* lets try to make an inline extent */
                ret = cow_file_range_inline(trans, root, inode,
@@ -826,7 +843,7 @@ static noinline int cow_file_range(struct inode *inode,
                                           (u64)-1, &ins, 1);
                BUG_ON(ret);
 
-               em = alloc_extent_map(GFP_NOFS);
+               em = alloc_extent_map();
                BUG_ON(!em);
                em->start = start;
                em->orig_start = em->start;
@@ -1008,7 +1025,7 @@ static noinline int csum_exist_in_range(struct btrfs_root *root,
        LIST_HEAD(list);
 
        ret = btrfs_lookup_csums_range(root->fs_info->csum_root, bytenr,
-                                      bytenr + num_bytes - 1, &list);
+                                      bytenr + num_bytes - 1, &list, 0);
        if (ret == 0 && list_empty(&list))
                return 0;
 
@@ -1049,29 +1066,33 @@ static noinline int run_delalloc_nocow(struct inode *inode,
        int type;
        int nocow;
        int check_prev = 1;
-       bool nolock = false;
+       bool nolock;
+       u64 ino = btrfs_ino(inode);
 
        path = btrfs_alloc_path();
        BUG_ON(!path);
-       if (root == root->fs_info->tree_root) {
-               nolock = true;
-               trans = btrfs_join_transaction_nolock(root, 1);
-       } else {
-               trans = btrfs_join_transaction(root, 1);
-       }
+
+       nolock = is_free_space_inode(root, inode);
+
+       if (nolock)
+               trans = btrfs_join_transaction_nolock(root);
+       else
+               trans = btrfs_join_transaction(root);
+
        BUG_ON(IS_ERR(trans));
+       trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
        cow_start = (u64)-1;
        cur_offset = start;
        while (1) {
-               ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino,
+               ret = btrfs_lookup_file_extent(trans, root, path, ino,
                                               cur_offset, 0);
                BUG_ON(ret < 0);
                if (ret > 0 && path->slots[0] > 0 && check_prev) {
                        leaf = path->nodes[0];
                        btrfs_item_key_to_cpu(leaf, &found_key,
                                              path->slots[0] - 1);
-                       if (found_key.objectid == inode->i_ino &&
+                       if (found_key.objectid == ino &&
                            found_key.type == BTRFS_EXTENT_DATA_KEY)
                                path->slots[0]--;
                }
@@ -1092,7 +1113,7 @@ next_slot:
                num_bytes = 0;
                btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
 
-               if (found_key.objectid > inode->i_ino ||
+               if (found_key.objectid > ino ||
                    found_key.type > BTRFS_EXTENT_DATA_KEY ||
                    found_key.offset > end)
                        break;
@@ -1127,7 +1148,7 @@ next_slot:
                                goto out_check;
                        if (btrfs_extent_readonly(root, disk_bytenr))
                                goto out_check;
-                       if (btrfs_cross_ref_exist(trans, root, inode->i_ino,
+                       if (btrfs_cross_ref_exist(trans, root, ino,
                                                  found_key.offset -
                                                  extent_offset, disk_bytenr))
                                goto out_check;
@@ -1164,7 +1185,7 @@ out_check:
                        goto next_slot;
                }
 
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                if (cow_start != (u64)-1) {
                        ret = cow_file_range(inode, locked_page, cow_start,
                                        found_key.offset - 1, page_started,
@@ -1177,7 +1198,7 @@ out_check:
                        struct extent_map *em;
                        struct extent_map_tree *em_tree;
                        em_tree = &BTRFS_I(inode)->extent_tree;
-                       em = alloc_extent_map(GFP_NOFS);
+                       em = alloc_extent_map();
                        BUG_ON(!em);
                        em->start = cur_offset;
                        em->orig_start = em->start;
@@ -1222,7 +1243,7 @@ out_check:
                if (cur_offset > end)
                        break;
        }
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        if (cur_offset <= end && cow_start == (u64)-1)
                cow_start = cur_offset;
@@ -1310,14 +1331,13 @@ static int btrfs_set_bit_hook(struct inode *inode,
 
        /*
         * set_bit and clear bit hooks normally require _irqsave/restore
-        * but in this case, we are only testeing for the DELALLOC
+        * but in this case, we are only testing for the DELALLOC
         * bit, which is only set or cleared with irqs on
         */
        if (!(state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) {
                struct btrfs_root *root = BTRFS_I(inode)->root;
                u64 len = state->end + 1 - state->start;
-               int do_list = (root->root_key.objectid !=
-                              BTRFS_ROOT_TREE_OBJECTID);
+               bool do_list = !is_free_space_inode(root, inode);
 
                if (*bits & EXTENT_FIRST_DELALLOC)
                        *bits &= ~EXTENT_FIRST_DELALLOC;
@@ -1344,14 +1364,13 @@ static int btrfs_clear_bit_hook(struct inode *inode,
 {
        /*
         * set_bit and clear bit hooks normally require _irqsave/restore
-        * but in this case, we are only testeing for the DELALLOC
+        * but in this case, we are only testing for the DELALLOC
         * bit, which is only set or cleared with irqs on
         */
        if ((state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) {
                struct btrfs_root *root = BTRFS_I(inode)->root;
                u64 len = state->end + 1 - state->start;
-               int do_list = (root->root_key.objectid !=
-                              BTRFS_ROOT_TREE_OBJECTID);
+               bool do_list = !is_free_space_inode(root, inode);
 
                if (*bits & EXTENT_FIRST_DELALLOC)
                        *bits &= ~EXTENT_FIRST_DELALLOC;
@@ -1458,7 +1477,7 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
 
        skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
 
-       if (root == root->fs_info->tree_root)
+       if (is_free_space_inode(root, inode))
                ret = btrfs_bio_wq_end_io(root->fs_info, bio, 2);
        else
                ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
@@ -1500,8 +1519,6 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans,
 {
        struct btrfs_ordered_sum *sum;
 
-       btrfs_set_trans_block_group(trans, inode);
-
        list_for_each_entry(sum, list, list) {
                btrfs_csum_file_blocks(trans,
                       BTRFS_I(inode)->root->fs_info->csum_root, sum);
@@ -1644,7 +1661,7 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
                                 &hint, 0);
        BUG_ON(ret);
 
-       ins.objectid = inode->i_ino;
+       ins.objectid = btrfs_ino(inode);
        ins.offset = file_pos;
        ins.type = BTRFS_EXTENT_DATA_KEY;
        ret = btrfs_insert_empty_item(trans, root, path, &ins, sizeof(*fi));
@@ -1675,7 +1692,7 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
        ins.type = BTRFS_EXTENT_ITEM_KEY;
        ret = btrfs_alloc_reserved_file_extent(trans, root,
                                        root->root_key.objectid,
-                                       inode->i_ino, file_pos, &ins);
+                                       btrfs_ino(inode), file_pos, &ins);
        BUG_ON(ret);
        btrfs_free_path(path);
 
@@ -1701,7 +1718,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
        struct extent_state *cached_state = NULL;
        int compress_type = 0;
        int ret;
-       bool nolock = false;
+       bool nolock;
 
        ret = btrfs_dec_test_ordered_pending(inode, &ordered_extent, start,
                                             end - start + 1);
@@ -1709,18 +1726,17 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                return 0;
        BUG_ON(!ordered_extent);
 
-       nolock = (root == root->fs_info->tree_root);
+       nolock = is_free_space_inode(root, inode);
 
        if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) {
                BUG_ON(!list_empty(&ordered_extent->list));
                ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
                if (!ret) {
                        if (nolock)
-                               trans = btrfs_join_transaction_nolock(root, 1);
+                               trans = btrfs_join_transaction_nolock(root);
                        else
-                               trans = btrfs_join_transaction(root, 1);
+                               trans = btrfs_join_transaction(root);
                        BUG_ON(IS_ERR(trans));
-                       btrfs_set_trans_block_group(trans, inode);
                        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
                        ret = btrfs_update_inode(trans, root, inode);
                        BUG_ON(ret);
@@ -1733,11 +1749,10 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                         0, &cached_state, GFP_NOFS);
 
        if (nolock)
-               trans = btrfs_join_transaction_nolock(root, 1);
+               trans = btrfs_join_transaction_nolock(root);
        else
-               trans = btrfs_join_transaction(root, 1);
+               trans = btrfs_join_transaction(root);
        BUG_ON(IS_ERR(trans));
-       btrfs_set_trans_block_group(trans, inode);
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
        if (test_bit(BTRFS_ORDERED_COMPRESSED, &ordered_extent->flags))
@@ -1855,7 +1870,7 @@ static int btrfs_io_failed_hook(struct bio *failed_bio,
                }
                read_unlock(&em_tree->lock);
 
-               if (!em || IS_ERR(em)) {
+               if (IS_ERR_OR_NULL(em)) {
                        kfree(failrec);
                        return -EIO;
                }
@@ -1971,7 +1986,7 @@ static int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end,
        }
 
        if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)
-               return 0;
+               goto good;
 
        if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID &&
            test_range_bit(io_tree, start, end, EXTENT_NODATASUM, 1, NULL)) {
@@ -2004,12 +2019,11 @@ good:
        return 0;
 
 zeroit:
-       if (printk_ratelimit()) {
-               printk(KERN_INFO "btrfs csum failed ino %lu off %llu csum %u "
-                      "private %llu\n", page->mapping->host->i_ino,
+       printk_ratelimited(KERN_INFO "btrfs csum failed ino %llu off %llu csum %u "
+                      "private %llu\n",
+                      (unsigned long long)btrfs_ino(page->mapping->host),
                       (unsigned long long)start, csum,
                       (unsigned long long)private);
-       }
        memset(kaddr + offset, 1, end - start + 1);
        flush_dcache_page(page);
        kunmap_atomic(kaddr, KM_USER0);
@@ -2244,7 +2258,7 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode)
 
        /* insert an orphan item to track this unlinked/truncated file */
        if (insert >= 1) {
-               ret = btrfs_insert_orphan_item(trans, root, inode->i_ino);
+               ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode));
                BUG_ON(ret);
        }
 
@@ -2281,7 +2295,7 @@ int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode)
        spin_unlock(&root->orphan_lock);
 
        if (trans && delete_item) {
-               ret = btrfs_del_orphan_item(trans, root, inode->i_ino);
+               ret = btrfs_del_orphan_item(trans, root, btrfs_ino(inode));
                BUG_ON(ret);
        }
 
@@ -2346,7 +2360,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
                        break;
 
                /* release the path since we're done with it */
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
 
                /*
                 * this is where we are basically btrfs_lookup, without the
@@ -2413,7 +2427,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
                                        (u64)-1);
 
        if (root->orphan_block_rsv || root->orphan_item_inserted) {
-               trans = btrfs_join_transaction(root, 1);
+               trans = btrfs_join_transaction(root);
                if (!IS_ERR(trans))
                        btrfs_end_transaction(trans, root);
        }
@@ -2493,12 +2507,12 @@ static void btrfs_read_locked_inode(struct inode *inode)
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_key location;
        int maybe_acls;
-       u64 alloc_group_block;
        u32 rdev;
        int ret;
 
        path = btrfs_alloc_path();
        BUG_ON(!path);
+       path->leave_spinning = 1;
        memcpy(&location, &BTRFS_I(inode)->location, sizeof(location));
 
        ret = btrfs_lookup_inode(NULL, root, path, &location, 0);
@@ -2508,6 +2522,12 @@ static void btrfs_read_locked_inode(struct inode *inode)
        leaf = path->nodes[0];
        inode_item = btrfs_item_ptr(leaf, path->slots[0],
                                    struct btrfs_inode_item);
+       if (!leaf->map_token)
+               map_private_extent_buffer(leaf, (unsigned long)inode_item,
+                                         sizeof(struct btrfs_inode_item),
+                                         &leaf->map_token, &leaf->kaddr,
+                                         &leaf->map_start, &leaf->map_len,
+                                         KM_USER1);
 
        inode->i_mode = btrfs_inode_mode(leaf, inode_item);
        inode->i_nlink = btrfs_inode_nlink(leaf, inode_item);
@@ -2537,18 +2557,20 @@ static void btrfs_read_locked_inode(struct inode *inode)
        BTRFS_I(inode)->index_cnt = (u64)-1;
        BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item);
 
-       alloc_group_block = btrfs_inode_block_group(leaf, inode_item);
-
        /*
         * try to precache a NULL acl entry for files that don't have
         * any xattrs or acls
         */
-       maybe_acls = acls_after_inode_item(leaf, path->slots[0], inode->i_ino);
+       maybe_acls = acls_after_inode_item(leaf, path->slots[0],
+                                          btrfs_ino(inode));
        if (!maybe_acls)
                cache_no_acl(inode);
 
-       BTRFS_I(inode)->block_group = btrfs_find_block_group(root, 0,
-                                               alloc_group_block, 0);
+       if (leaf->map_token) {
+               unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
+               leaf->map_token = NULL;
+       }
+
        btrfs_free_path(path);
        inode_item = NULL;
 
@@ -2628,7 +2650,7 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
        btrfs_set_inode_transid(leaf, item, trans->transid);
        btrfs_set_inode_rdev(leaf, item, inode->i_rdev);
        btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags);
-       btrfs_set_inode_block_group(leaf, item, BTRFS_I(inode)->block_group);
+       btrfs_set_inode_block_group(leaf, item, 0);
 
        if (leaf->map_token) {
                unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
@@ -2647,11 +2669,26 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
        struct extent_buffer *leaf;
        int ret;
 
+       /*
+        * If root is tree root, it means this inode is used to
+        * store free space information. And these inodes are updated
+        * when committing the transaction, so they needn't delaye to
+        * be updated, or deadlock will occured.
+        */
+       if (!is_free_space_inode(root, inode)) {
+               ret = btrfs_delayed_update_inode(trans, root, inode);
+               if (!ret)
+                       btrfs_set_inode_last_trans(trans, inode);
+               return ret;
+       }
+
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               return -ENOMEM;
+
        path->leave_spinning = 1;
-       ret = btrfs_lookup_inode(trans, root, path,
-                                &BTRFS_I(inode)->location, 1);
+       ret = btrfs_lookup_inode(trans, root, path, &BTRFS_I(inode)->location,
+                                1);
        if (ret) {
                if (ret > 0)
                        ret = -ENOENT;
@@ -2661,7 +2698,7 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
        btrfs_unlock_up_safe(path, 1);
        leaf = path->nodes[0];
        inode_item = btrfs_item_ptr(leaf, path->slots[0],
-                                 struct btrfs_inode_item);
+                                   struct btrfs_inode_item);
 
        fill_inode_item(trans, leaf, inode_item, inode);
        btrfs_mark_buffer_dirty(leaf);
@@ -2672,7 +2709,6 @@ failed:
        return ret;
 }
 
-
 /*
  * unlink helper that gets used here in inode.c and in the tree logging
  * recovery code.  It remove a link in a directory with a given name, and
@@ -2689,6 +2725,8 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
        struct btrfs_dir_item *di;
        struct btrfs_key key;
        u64 index;
+       u64 ino = btrfs_ino(inode);
+       u64 dir_ino = btrfs_ino(dir);
 
        path = btrfs_alloc_path();
        if (!path) {
@@ -2697,7 +2735,7 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
        }
 
        path->leave_spinning = 1;
-       di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino,
+       di = btrfs_lookup_dir_item(trans, root, path, dir_ino,
                                    name, name_len, -1);
        if (IS_ERR(di)) {
                ret = PTR_ERR(di);
@@ -2712,33 +2750,23 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
        ret = btrfs_delete_one_dir_name(trans, root, path, di);
        if (ret)
                goto err;
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
-       ret = btrfs_del_inode_ref(trans, root, name, name_len,
-                                 inode->i_ino,
-                                 dir->i_ino, &index);
+       ret = btrfs_del_inode_ref(trans, root, name, name_len, ino,
+                                 dir_ino, &index);
        if (ret) {
                printk(KERN_INFO "btrfs failed to delete reference to %.*s, "
-                      "inode %lu parent %lu\n", name_len, name,
-                      inode->i_ino, dir->i_ino);
+                      "inode %llu parent %llu\n", name_len, name,
+                      (unsigned long long)ino, (unsigned long long)dir_ino);
                goto err;
        }
 
-       di = btrfs_lookup_dir_index_item(trans, root, path, dir->i_ino,
-                                        index, name, name_len, -1);
-       if (IS_ERR(di)) {
-               ret = PTR_ERR(di);
-               goto err;
-       }
-       if (!di) {
-               ret = -ENOENT;
+       ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
+       if (ret)
                goto err;
-       }
-       ret = btrfs_delete_one_dir_name(trans, root, path, di);
-       btrfs_release_path(root, path);
 
        ret = btrfs_del_inode_ref_in_log(trans, root, name, name_len,
-                                        inode, dir->i_ino);
+                                        inode, dir_ino);
        BUG_ON(ret != 0 && ret != -ENOENT);
 
        ret = btrfs_del_dir_entries_in_log(trans, root, name, name_len,
@@ -2816,12 +2844,14 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
        int check_link = 1;
        int err = -ENOSPC;
        int ret;
+       u64 ino = btrfs_ino(inode);
+       u64 dir_ino = btrfs_ino(dir);
 
        trans = btrfs_start_transaction(root, 10);
        if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC)
                return trans;
 
-       if (inode->i_ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)
+       if (ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)
                return ERR_PTR(-ENOSPC);
 
        /* check if there is someone else holds reference */
@@ -2862,7 +2892,7 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
        } else {
                check_link = 0;
        }
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        ret = btrfs_lookup_inode(trans, root, path,
                                &BTRFS_I(inode)->location, 0);
@@ -2876,11 +2906,11 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
        } else {
                check_link = 0;
        }
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        if (ret == 0 && S_ISREG(inode->i_mode)) {
                ret = btrfs_lookup_file_extent(trans, root, path,
-                                              inode->i_ino, (u64)-1, 0);
+                                              ino, (u64)-1, 0);
                if (ret < 0) {
                        err = ret;
                        goto out;
@@ -2888,7 +2918,7 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
                BUG_ON(ret == 0);
                if (check_path_shared(root, path))
                        goto out;
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
        }
 
        if (!check_link) {
@@ -2896,7 +2926,7 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
                goto out;
        }
 
-       di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino,
+       di = btrfs_lookup_dir_item(trans, root, path, dir_ino,
                                dentry->d_name.name, dentry->d_name.len, 0);
        if (IS_ERR(di)) {
                err = PTR_ERR(di);
@@ -2909,11 +2939,11 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
                err = 0;
                goto out;
        }
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        ref = btrfs_lookup_inode_ref(trans, root, path,
                                dentry->d_name.name, dentry->d_name.len,
-                               inode->i_ino, dir->i_ino, 0);
+                               ino, dir_ino, 0);
        if (IS_ERR(ref)) {
                err = PTR_ERR(ref);
                goto out;
@@ -2922,9 +2952,17 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
        if (check_path_shared(root, path))
                goto out;
        index = btrfs_inode_ref_index(path->nodes[0], ref);
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
-       di = btrfs_lookup_dir_index_item(trans, root, path, dir->i_ino, index,
+       /*
+        * This is a commit root search, if we can lookup inode item and other
+        * relative items in the commit root, it means the transaction of
+        * dir/file creation has been committed, and the dir index item that we
+        * delay to insert has also been inserted into the commit root. So
+        * we needn't worry about the delayed insertion of the dir index item
+        * here.
+        */
+       di = btrfs_lookup_dir_index_item(trans, root, path, dir_ino, index,
                                dentry->d_name.name, dentry->d_name.len, 0);
        if (IS_ERR(di)) {
                err = PTR_ERR(di);
@@ -2969,8 +3007,6 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
        if (IS_ERR(trans))
                return PTR_ERR(trans);
 
-       btrfs_set_trans_block_group(trans, dir);
-
        btrfs_record_unlink_dir(trans, dir, dentry->d_inode, 0);
 
        ret = btrfs_unlink_inode(trans, root, dir, dentry->d_inode,
@@ -2999,47 +3035,41 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
        struct btrfs_key key;
        u64 index;
        int ret;
+       u64 dir_ino = btrfs_ino(dir);
 
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
 
-       di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino,
+       di = btrfs_lookup_dir_item(trans, root, path, dir_ino,
                                   name, name_len, -1);
-       BUG_ON(!di || IS_ERR(di));
+       BUG_ON(IS_ERR_OR_NULL(di));
 
        leaf = path->nodes[0];
        btrfs_dir_item_key_to_cpu(leaf, di, &key);
        WARN_ON(key.type != BTRFS_ROOT_ITEM_KEY || key.objectid != objectid);
        ret = btrfs_delete_one_dir_name(trans, root, path, di);
        BUG_ON(ret);
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        ret = btrfs_del_root_ref(trans, root->fs_info->tree_root,
                                 objectid, root->root_key.objectid,
-                                dir->i_ino, &index, name, name_len);
+                                dir_ino, &index, name, name_len);
        if (ret < 0) {
                BUG_ON(ret != -ENOENT);
-               di = btrfs_search_dir_index_item(root, path, dir->i_ino,
+               di = btrfs_search_dir_index_item(root, path, dir_ino,
                                                 name, name_len);
-               BUG_ON(!di || IS_ERR(di));
+               BUG_ON(IS_ERR_OR_NULL(di));
 
                leaf = path->nodes[0];
                btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                index = key.offset;
        }
+       btrfs_release_path(path);
 
-       di = btrfs_lookup_dir_index_item(trans, root, path, dir->i_ino,
-                                        index, name, name_len, -1);
-       BUG_ON(!di || IS_ERR(di));
-
-       leaf = path->nodes[0];
-       btrfs_dir_item_key_to_cpu(leaf, di, &key);
-       WARN_ON(key.type != BTRFS_ROOT_ITEM_KEY || key.objectid != objectid);
-       ret = btrfs_delete_one_dir_name(trans, root, path, di);
+       ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
        BUG_ON(ret);
-       btrfs_release_path(root, path);
 
        btrfs_i_size_write(dir, dir->i_size - name_len * 2);
        dir->i_mtime = dir->i_ctime = CURRENT_TIME;
@@ -3059,16 +3089,14 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
        unsigned long nr = 0;
 
        if (inode->i_size > BTRFS_EMPTY_DIR_SIZE ||
-           inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)
+           btrfs_ino(inode) == BTRFS_FIRST_FREE_OBJECTID)
                return -ENOTEMPTY;
 
        trans = __unlink_start_trans(dir, dentry);
        if (IS_ERR(trans))
                return PTR_ERR(trans);
 
-       btrfs_set_trans_block_group(trans, dir);
-
-       if (unlikely(inode->i_ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) {
+       if (unlikely(btrfs_ino(inode) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) {
                err = btrfs_unlink_subvol(trans, root, dir,
                                          BTRFS_I(inode)->location.objectid,
                                          dentry->d_name.name,
@@ -3093,178 +3121,6 @@ out:
        return err;
 }
 
-#if 0
-/*
- * when truncating bytes in a file, it is possible to avoid reading
- * the leaves that contain only checksum items.  This can be the
- * majority of the IO required to delete a large file, but it must
- * be done carefully.
- *
- * The keys in the level just above the leaves are checked to make sure
- * the lowest key in a given leaf is a csum key, and starts at an offset
- * after the new  size.
- *
- * Then the key for the next leaf is checked to make sure it also has
- * a checksum item for the same file.  If it does, we know our target leaf
- * contains only checksum items, and it can be safely freed without reading
- * it.
- *
- * This is just an optimization targeted at large files.  It may do
- * nothing.  It will return 0 unless things went badly.
- */
-static noinline int drop_csum_leaves(struct btrfs_trans_handle *trans,
-                                    struct btrfs_root *root,
-                                    struct btrfs_path *path,
-                                    struct inode *inode, u64 new_size)
-{
-       struct btrfs_key key;
-       int ret;
-       int nritems;
-       struct btrfs_key found_key;
-       struct btrfs_key other_key;
-       struct btrfs_leaf_ref *ref;
-       u64 leaf_gen;
-       u64 leaf_start;
-
-       path->lowest_level = 1;
-       key.objectid = inode->i_ino;
-       key.type = BTRFS_CSUM_ITEM_KEY;
-       key.offset = new_size;
-again:
-       ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
-       if (ret < 0)
-               goto out;
-
-       if (path->nodes[1] == NULL) {
-               ret = 0;
-               goto out;
-       }
-       ret = 0;
-       btrfs_node_key_to_cpu(path->nodes[1], &found_key, path->slots[1]);
-       nritems = btrfs_header_nritems(path->nodes[1]);
-
-       if (!nritems)
-               goto out;
-
-       if (path->slots[1] >= nritems)
-               goto next_node;
-
-       /* did we find a key greater than anything we want to delete? */
-       if (found_key.objectid > inode->i_ino ||
-          (found_key.objectid == inode->i_ino && found_key.type > key.type))
-               goto out;
-
-       /* we check the next key in the node to make sure the leave contains
-        * only checksum items.  This comparison doesn't work if our
-        * leaf is the last one in the node
-        */
-       if (path->slots[1] + 1 >= nritems) {
-next_node:
-               /* search forward from the last key in the node, this
-                * will bring us into the next node in the tree
-                */
-               btrfs_node_key_to_cpu(path->nodes[1], &found_key, nritems - 1);
-
-               /* unlikely, but we inc below, so check to be safe */
-               if (found_key.offset == (u64)-1)
-                       goto out;
-
-               /* search_forward needs a path with locks held, do the
-                * search again for the original key.  It is possible
-                * this will race with a balance and return a path that
-                * we could modify, but this drop is just an optimization
-                * and is allowed to miss some leaves.
-                */
-               btrfs_release_path(root, path);
-               found_key.offset++;
-
-               /* setup a max key for search_forward */
-               other_key.offset = (u64)-1;
-               other_key.type = key.type;
-               other_key.objectid = key.objectid;
-
-               path->keep_locks = 1;
-               ret = btrfs_search_forward(root, &found_key, &other_key,
-                                          path, 0, 0);
-               path->keep_locks = 0;
-               if (ret || found_key.objectid != key.objectid ||
-                   found_key.type != key.type) {
-                       ret = 0;
-                       goto out;
-               }
-
-               key.offset = found_key.offset;
-               btrfs_release_path(root, path);
-               cond_resched();
-               goto again;
-       }
-
-       /* we know there's one more slot after us in the tree,
-        * read that key so we can verify it is also a checksum item
-        */
-       btrfs_node_key_to_cpu(path->nodes[1], &other_key, path->slots[1] + 1);
-
-       if (found_key.objectid < inode->i_ino)
-               goto next_key;
-
-       if (found_key.type != key.type || found_key.offset < new_size)
-               goto next_key;
-
-       /*
-        * if the key for the next leaf isn't a csum key from this objectid,
-        * we can't be sure there aren't good items inside this leaf.
-        * Bail out
-        */
-       if (other_key.objectid != inode->i_ino || other_key.type != key.type)
-               goto out;
-
-       leaf_start = btrfs_node_blockptr(path->nodes[1], path->slots[1]);
-       leaf_gen = btrfs_node_ptr_generation(path->nodes[1], path->slots[1]);
-       /*
-        * it is safe to delete this leaf, it contains only
-        * csum items from this inode at an offset >= new_size
-        */
-       ret = btrfs_del_leaf(trans, root, path, leaf_start);
-       BUG_ON(ret);
-
-       if (root->ref_cows && leaf_gen < trans->transid) {
-               ref = btrfs_alloc_leaf_ref(root, 0);
-               if (ref) {
-                       ref->root_gen = root->root_key.offset;
-                       ref->bytenr = leaf_start;
-                       ref->owner = 0;
-                       ref->generation = leaf_gen;
-                       ref->nritems = 0;
-
-                       btrfs_sort_leaf_ref(ref);
-
-                       ret = btrfs_add_leaf_ref(root, ref, 0);
-                       WARN_ON(ret);
-                       btrfs_free_leaf_ref(root, ref);
-               } else {
-                       WARN_ON(1);
-               }
-       }
-next_key:
-       btrfs_release_path(root, path);
-
-       if (other_key.objectid == inode->i_ino &&
-           other_key.type == key.type && other_key.offset > key.offset) {
-               key.offset = other_key.offset;
-               cond_resched();
-               goto again;
-       }
-       ret = 0;
-out:
-       /* fixup any changes we've made to the path */
-       path->lowest_level = 0;
-       path->keep_locks = 0;
-       btrfs_release_path(root, path);
-       return ret;
-}
-
-#endif
-
 /*
  * this can truncate away extent items, csum items and directory items.
  * It starts at a high offset and removes keys until it can't find
@@ -3300,17 +3156,27 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
        int encoding;
        int ret;
        int err = 0;
+       u64 ino = btrfs_ino(inode);
 
        BUG_ON(new_size > 0 && min_type != BTRFS_EXTENT_DATA_KEY);
 
        if (root->ref_cows || root == root->fs_info->tree_root)
                btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0);
 
+       /*
+        * This function is also used to drop the items in the log tree before
+        * we relog the inode, so if root != BTRFS_I(inode)->root, it means
+        * it is used to drop the loged items. So we shouldn't kill the delayed
+        * items.
+        */
+       if (min_type == 0 && root == BTRFS_I(inode)->root)
+               btrfs_kill_delayed_inode_items(inode);
+
        path = btrfs_alloc_path();
        BUG_ON(!path);
        path->reada = -1;
 
-       key.objectid = inode->i_ino;
+       key.objectid = ino;
        key.offset = (u64)-1;
        key.type = (u8)-1;
 
@@ -3338,7 +3204,7 @@ search_again:
                found_type = btrfs_key_type(&found_key);
                encoding = 0;
 
-               if (found_key.objectid != inode->i_ino)
+               if (found_key.objectid != ino)
                        break;
 
                if (found_type < min_type)
@@ -3428,7 +3294,6 @@ search_again:
                                    btrfs_file_extent_calc_inline_size(size);
                                ret = btrfs_truncate_item(trans, root, path,
                                                          size, 1);
-                               BUG_ON(ret);
                        } else if (root->ref_cows) {
                                inode_sub_bytes(inode, item_end + 1 -
                                                found_key.offset);
@@ -3457,7 +3322,7 @@ delete:
                        ret = btrfs_free_extent(trans, root, extent_start,
                                                extent_num_bytes, 0,
                                                btrfs_header_owner(leaf),
-                                               inode->i_ino, extent_offset);
+                                               ino, extent_offset);
                        BUG_ON(ret);
                }
 
@@ -3466,7 +3331,9 @@ delete:
 
                if (path->slots[0] == 0 ||
                    path->slots[0] != pending_del_slot) {
-                       if (root->ref_cows) {
+                       if (root->ref_cows &&
+                           BTRFS_I(inode)->location.objectid !=
+                                               BTRFS_FREE_INO_OBJECTID) {
                                err = -EAGAIN;
                                goto out;
                        }
@@ -3477,7 +3344,7 @@ delete:
                                BUG_ON(ret);
                                pending_del_nr = 0;
                        }
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        goto search_again;
                } else {
                        path->slots[0]--;
@@ -3635,7 +3502,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
        while (1) {
                em = btrfs_get_extent(inode, NULL, 0, cur_offset,
                                block_end - cur_offset, 0);
-               BUG_ON(IS_ERR(em) || !em);
+               BUG_ON(IS_ERR_OR_NULL(em));
                last_byte = min(extent_map_end(em), block_end);
                last_byte = (last_byte + mask) & ~mask;
                if (!test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) {
@@ -3647,7 +3514,6 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
                                err = PTR_ERR(trans);
                                break;
                        }
-                       btrfs_set_trans_block_group(trans, inode);
 
                        err = btrfs_drop_extents(trans, inode, cur_offset,
                                                 cur_offset + hole_size,
@@ -3656,7 +3522,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
                                break;
 
                        err = btrfs_insert_file_extent(trans, root,
-                                       inode->i_ino, cur_offset, 0,
+                                       btrfs_ino(inode), cur_offset, 0,
                                        0, hole_size, 0, hole_size,
                                        0, 0, 0);
                        if (err)
@@ -3758,7 +3624,7 @@ void btrfs_evict_inode(struct inode *inode)
 
        truncate_inode_pages(&inode->i_data, 0);
        if (inode->i_nlink && (btrfs_root_refs(&root->root_item) != 0 ||
-                              root == root->fs_info->tree_root))
+                              is_free_space_inode(root, inode)))
                goto no_delete;
 
        if (is_bad_inode(inode)) {
@@ -3781,9 +3647,8 @@ void btrfs_evict_inode(struct inode *inode)
        btrfs_i_size_write(inode, 0);
 
        while (1) {
-               trans = btrfs_start_transaction(root, 0);
+               trans = btrfs_join_transaction(root);
                BUG_ON(IS_ERR(trans));
-               btrfs_set_trans_block_group(trans, inode);
                trans->block_rsv = root->orphan_block_rsv;
 
                ret = btrfs_block_rsv_check(trans, root,
@@ -3811,6 +3676,10 @@ void btrfs_evict_inode(struct inode *inode)
                BUG_ON(ret);
        }
 
+       if (!(root == root->fs_info->tree_root ||
+             root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID))
+               btrfs_return_ino(root, btrfs_ino(inode));
+
        nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
        btrfs_btree_balance_dirty(root, nr);
@@ -3836,12 +3705,12 @@ static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry,
        path = btrfs_alloc_path();
        BUG_ON(!path);
 
-       di = btrfs_lookup_dir_item(NULL, root, path, dir->i_ino, name,
+       di = btrfs_lookup_dir_item(NULL, root, path, btrfs_ino(dir), name,
                                    namelen, 0);
        if (IS_ERR(di))
                ret = PTR_ERR(di);
 
-       if (!di || IS_ERR(di))
+       if (IS_ERR_OR_NULL(di))
                goto out_err;
 
        btrfs_dir_item_key_to_cpu(path->nodes[0], di, location);
@@ -3889,7 +3758,7 @@ static int fixup_tree_root_location(struct btrfs_root *root,
 
        leaf = path->nodes[0];
        ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref);
-       if (btrfs_root_ref_dirid(leaf, ref) != dir->i_ino ||
+       if (btrfs_root_ref_dirid(leaf, ref) != btrfs_ino(dir) ||
            btrfs_root_ref_name_len(leaf, ref) != dentry->d_name.len)
                goto out;
 
@@ -3899,7 +3768,7 @@ static int fixup_tree_root_location(struct btrfs_root *root,
        if (ret)
                goto out;
 
-       btrfs_release_path(root->fs_info->tree_root, path);
+       btrfs_release_path(path);
 
        new_root = btrfs_read_fs_root_no_name(root->fs_info, location);
        if (IS_ERR(new_root)) {
@@ -3928,6 +3797,7 @@ static void inode_tree_add(struct inode *inode)
        struct btrfs_inode *entry;
        struct rb_node **p;
        struct rb_node *parent;
+       u64 ino = btrfs_ino(inode);
 again:
        p = &root->inode_tree.rb_node;
        parent = NULL;
@@ -3940,9 +3810,9 @@ again:
                parent = *p;
                entry = rb_entry(parent, struct btrfs_inode, rb_node);
 
-               if (inode->i_ino < entry->vfs_inode.i_ino)
+               if (ino < btrfs_ino(&entry->vfs_inode))
                        p = &parent->rb_left;
-               else if (inode->i_ino > entry->vfs_inode.i_ino)
+               else if (ino > btrfs_ino(&entry->vfs_inode))
                        p = &parent->rb_right;
                else {
                        WARN_ON(!(entry->vfs_inode.i_state &
@@ -4006,9 +3876,9 @@ again:
                prev = node;
                entry = rb_entry(node, struct btrfs_inode, rb_node);
 
-               if (objectid < entry->vfs_inode.i_ino)
+               if (objectid < btrfs_ino(&entry->vfs_inode))
                        node = node->rb_left;
-               else if (objectid > entry->vfs_inode.i_ino)
+               else if (objectid > btrfs_ino(&entry->vfs_inode))
                        node = node->rb_right;
                else
                        break;
@@ -4016,7 +3886,7 @@ again:
        if (!node) {
                while (prev) {
                        entry = rb_entry(prev, struct btrfs_inode, rb_node);
-                       if (objectid <= entry->vfs_inode.i_ino) {
+                       if (objectid <= btrfs_ino(&entry->vfs_inode)) {
                                node = prev;
                                break;
                        }
@@ -4025,7 +3895,7 @@ again:
        }
        while (node) {
                entry = rb_entry(node, struct btrfs_inode, rb_node);
-               objectid = entry->vfs_inode.i_ino + 1;
+               objectid = btrfs_ino(&entry->vfs_inode) + 1;
                inode = igrab(&entry->vfs_inode);
                if (inode) {
                        spin_unlock(&root->inode_lock);
@@ -4063,7 +3933,7 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p)
 static int btrfs_find_actor(struct inode *inode, void *opaque)
 {
        struct btrfs_iget_args *args = opaque;
-       return args->ino == inode->i_ino &&
+       return args->ino == btrfs_ino(inode) &&
                args->root == BTRFS_I(inode)->root;
 }
 
@@ -4208,7 +4078,7 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
        return d_splice_alias(inode, dentry);
 }
 
-static unsigned char btrfs_filetype_table[] = {
+unsigned char btrfs_filetype_table[] = {
        DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
 };
 
@@ -4222,6 +4092,8 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
        struct btrfs_key key;
        struct btrfs_key found_key;
        struct btrfs_path *path;
+       struct list_head ins_list;
+       struct list_head del_list;
        int ret;
        struct extent_buffer *leaf;
        int slot;
@@ -4234,6 +4106,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
        char tmp_name[32];
        char *name_ptr;
        int name_len;
+       int is_curr = 0;        /* filp->f_pos points to the current index? */
 
        /* FIXME, use a real flag for deciding about the key type */
        if (root->fs_info->tree_root == root)
@@ -4241,9 +4114,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
 
        /* special case for "." */
        if (filp->f_pos == 0) {
-               over = filldir(dirent, ".", 1,
-                              1, inode->i_ino,
-                              DT_DIR);
+               over = filldir(dirent, ".", 1, 1, btrfs_ino(inode), DT_DIR);
                if (over)
                        return 0;
                filp->f_pos = 1;
@@ -4258,11 +4129,20 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
                filp->f_pos = 2;
        }
        path = btrfs_alloc_path();
-       path->reada = 2;
+       if (!path)
+               return -ENOMEM;
+
+       path->reada = 1;
+
+       if (key_type == BTRFS_DIR_INDEX_KEY) {
+               INIT_LIST_HEAD(&ins_list);
+               INIT_LIST_HEAD(&del_list);
+               btrfs_get_delayed_items(inode, &ins_list, &del_list);
+       }
 
        btrfs_set_key_type(&key, key_type);
        key.offset = filp->f_pos;
-       key.objectid = inode->i_ino;
+       key.objectid = btrfs_ino(inode);
 
        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
        if (ret < 0)
@@ -4289,8 +4169,13 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
                        break;
                if (found_key.offset < filp->f_pos)
                        goto next;
+               if (key_type == BTRFS_DIR_INDEX_KEY &&
+                   btrfs_should_delete_dir_index(&del_list,
+                                                 found_key.offset))
+                       goto next;
 
                filp->f_pos = found_key.offset;
+               is_curr = 1;
 
                di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
                di_cur = 0;
@@ -4345,6 +4230,15 @@ next:
                path->slots[0]++;
        }
 
+       if (key_type == BTRFS_DIR_INDEX_KEY) {
+               if (is_curr)
+                       filp->f_pos++;
+               ret = btrfs_readdir_delayed_dir_index(filp, dirent, filldir,
+                                                     &ins_list);
+               if (ret)
+                       goto nopos;
+       }
+
        /* Reached end of directory/root. Bump pos past the last item. */
        if (key_type == BTRFS_DIR_INDEX_KEY)
                /*
@@ -4357,6 +4251,8 @@ next:
 nopos:
        ret = 0;
 err:
+       if (key_type == BTRFS_DIR_INDEX_KEY)
+               btrfs_put_delayed_items(&ins_list, &del_list);
        btrfs_free_path(path);
        return ret;
 }
@@ -4371,17 +4267,16 @@ int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc)
        if (BTRFS_I(inode)->dummy_inode)
                return 0;
 
-       smp_mb();
-       nolock = (root->fs_info->closing && root == root->fs_info->tree_root);
+       if (btrfs_fs_closing(root->fs_info) && is_free_space_inode(root, inode))
+               nolock = true;
 
        if (wbc->sync_mode == WB_SYNC_ALL) {
                if (nolock)
-                       trans = btrfs_join_transaction_nolock(root, 1);
+                       trans = btrfs_join_transaction_nolock(root);
                else
-                       trans = btrfs_join_transaction(root, 1);
+                       trans = btrfs_join_transaction(root);
                if (IS_ERR(trans))
                        return PTR_ERR(trans);
-               btrfs_set_trans_block_group(trans, inode);
                if (nolock)
                        ret = btrfs_end_transaction_nolock(trans, root);
                else
@@ -4396,7 +4291,7 @@ int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc)
  * FIXME, needs more benchmarking...there are no reasons other than performance
  * to keep or drop this code.
  */
-void btrfs_dirty_inode(struct inode *inode)
+void btrfs_dirty_inode(struct inode *inode, int flags)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_trans_handle *trans;
@@ -4405,9 +4300,8 @@ void btrfs_dirty_inode(struct inode *inode)
        if (BTRFS_I(inode)->dummy_inode)
                return;
 
-       trans = btrfs_join_transaction(root, 1);
+       trans = btrfs_join_transaction(root);
        BUG_ON(IS_ERR(trans));
-       btrfs_set_trans_block_group(trans, inode);
 
        ret = btrfs_update_inode(trans, root, inode);
        if (ret && ret == -ENOSPC) {
@@ -4415,25 +4309,24 @@ void btrfs_dirty_inode(struct inode *inode)
                btrfs_end_transaction(trans, root);
                trans = btrfs_start_transaction(root, 1);
                if (IS_ERR(trans)) {
-                       if (printk_ratelimit()) {
-                               printk(KERN_ERR "btrfs: fail to "
-                                      "dirty  inode %lu error %ld\n",
-                                      inode->i_ino, PTR_ERR(trans));
-                       }
+                       printk_ratelimited(KERN_ERR "btrfs: fail to "
+                                      "dirty  inode %llu error %ld\n",
+                                      (unsigned long long)btrfs_ino(inode),
+                                      PTR_ERR(trans));
                        return;
                }
-               btrfs_set_trans_block_group(trans, inode);
 
                ret = btrfs_update_inode(trans, root, inode);
                if (ret) {
-                       if (printk_ratelimit()) {
-                               printk(KERN_ERR "btrfs: fail to "
-                                      "dirty  inode %lu error %d\n",
-                                      inode->i_ino, ret);
-                       }
+                       printk_ratelimited(KERN_ERR "btrfs: fail to "
+                                      "dirty  inode %llu error %d\n",
+                                      (unsigned long long)btrfs_ino(inode),
+                                      ret);
                }
        }
        btrfs_end_transaction(trans, root);
+       if (BTRFS_I(inode)->delayed_node)
+               btrfs_balance_delayed_items(root);
 }
 
 /*
@@ -4449,7 +4342,7 @@ static int btrfs_set_inode_index_count(struct inode *inode)
        struct extent_buffer *leaf;
        int ret;
 
-       key.objectid = inode->i_ino;
+       key.objectid = btrfs_ino(inode);
        btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
        key.offset = (u64)-1;
 
@@ -4481,7 +4374,7 @@ static int btrfs_set_inode_index_count(struct inode *inode)
        leaf = path->nodes[0];
        btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
 
-       if (found_key.objectid != inode->i_ino ||
+       if (found_key.objectid != btrfs_ino(inode) ||
            btrfs_key_type(&found_key) != BTRFS_DIR_INDEX_KEY) {
                BTRFS_I(inode)->index_cnt = 2;
                goto out;
@@ -4502,9 +4395,12 @@ int btrfs_set_inode_index(struct inode *dir, u64 *index)
        int ret = 0;
 
        if (BTRFS_I(dir)->index_cnt == (u64)-1) {
-               ret = btrfs_set_inode_index_count(dir);
-               if (ret)
-                       return ret;
+               ret = btrfs_inode_delayed_dir_index_count(dir);
+               if (ret) {
+                       ret = btrfs_set_inode_index_count(dir);
+                       if (ret)
+                               return ret;
+               }
        }
 
        *index = BTRFS_I(dir)->index_cnt;
@@ -4517,8 +4413,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root,
                                     struct inode *dir,
                                     const char *name, int name_len,
-                                    u64 ref_objectid, u64 objectid,
-                                    u64 alloc_hint, int mode, u64 *index)
+                                    u64 ref_objectid, u64 objectid, int mode,
+                                    u64 *index)
 {
        struct inode *inode;
        struct btrfs_inode_item *inode_item;
@@ -4540,6 +4436,12 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
                return ERR_PTR(-ENOMEM);
        }
 
+       /*
+        * we have to initialize this early, so we can reclaim the inode
+        * number if we fail afterwards in this function.
+        */
+       inode->i_ino = objectid;
+
        if (dir) {
                trace_btrfs_inode_request(dir);
 
@@ -4565,8 +4467,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
                owner = 0;
        else
                owner = 1;
-       BTRFS_I(inode)->block_group =
-                       btrfs_find_block_group(root, 0, alloc_hint, owner);
 
        key[0].objectid = objectid;
        btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY);
@@ -4585,7 +4485,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
                goto fail;
 
        inode_init_owner(inode, dir, mode);
-       inode->i_ino = objectid;
        inode_set_bytes(inode, 0);
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
@@ -4649,29 +4548,29 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
        int ret = 0;
        struct btrfs_key key;
        struct btrfs_root *root = BTRFS_I(parent_inode)->root;
+       u64 ino = btrfs_ino(inode);
+       u64 parent_ino = btrfs_ino(parent_inode);
 
-       if (unlikely(inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)) {
+       if (unlikely(ino == BTRFS_FIRST_FREE_OBJECTID)) {
                memcpy(&key, &BTRFS_I(inode)->root->root_key, sizeof(key));
        } else {
-               key.objectid = inode->i_ino;
+               key.objectid = ino;
                btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
                key.offset = 0;
        }
 
-       if (unlikely(inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)) {
+       if (unlikely(ino == BTRFS_FIRST_FREE_OBJECTID)) {
                ret = btrfs_add_root_ref(trans, root->fs_info->tree_root,
                                         key.objectid, root->root_key.objectid,
-                                        parent_inode->i_ino,
-                                        index, name, name_len);
+                                        parent_ino, index, name, name_len);
        } else if (add_backref) {
-               ret = btrfs_insert_inode_ref(trans, root,
-                                            name, name_len, inode->i_ino,
-                                            parent_inode->i_ino, index);
+               ret = btrfs_insert_inode_ref(trans, root, name, name_len, ino,
+                                            parent_ino, index);
        }
 
        if (ret == 0) {
                ret = btrfs_insert_dir_item(trans, root, name, name_len,
-                                           parent_inode->i_ino, &key,
+                                           parent_inode, &key,
                                            btrfs_inode_type(inode), index);
                BUG_ON(ret);
 
@@ -4714,10 +4613,6 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
        if (!new_valid_dev(rdev))
                return -EINVAL;
 
-       err = btrfs_find_free_objectid(NULL, root, dir->i_ino, &objectid);
-       if (err)
-               return err;
-
        /*
         * 2 for inode item and ref
         * 2 for dir items
@@ -4727,11 +4622,13 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
        if (IS_ERR(trans))
                return PTR_ERR(trans);
 
-       btrfs_set_trans_block_group(trans, dir);
+       err = btrfs_find_free_ino(root, &objectid);
+       if (err)
+               goto out_unlock;
 
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
-                               dentry->d_name.len, dir->i_ino, objectid,
-                               BTRFS_I(dir)->block_group, mode, &index);
+                               dentry->d_name.len, btrfs_ino(dir), objectid,
+                               mode, &index);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
                goto out_unlock;
@@ -4743,7 +4640,6 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
                goto out_unlock;
        }
 
-       btrfs_set_trans_block_group(trans, inode);
        err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
        if (err)
                drop_inode = 1;
@@ -4752,8 +4648,6 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
                init_special_inode(inode, inode->i_mode, rdev);
                btrfs_update_inode(trans, root, inode);
        }
-       btrfs_update_inode_block_group(trans, inode);
-       btrfs_update_inode_block_group(trans, dir);
 out_unlock:
        nr = trans->blocks_used;
        btrfs_end_transaction_throttle(trans, root);
@@ -4777,9 +4671,6 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
        u64 objectid;
        u64 index = 0;
 
-       err = btrfs_find_free_objectid(NULL, root, dir->i_ino, &objectid);
-       if (err)
-               return err;
        /*
         * 2 for inode item and ref
         * 2 for dir items
@@ -4789,11 +4680,13 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
        if (IS_ERR(trans))
                return PTR_ERR(trans);
 
-       btrfs_set_trans_block_group(trans, dir);
+       err = btrfs_find_free_ino(root, &objectid);
+       if (err)
+               goto out_unlock;
 
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
-                               dentry->d_name.len, dir->i_ino, objectid,
-                               BTRFS_I(dir)->block_group, mode, &index);
+                               dentry->d_name.len, btrfs_ino(dir), objectid,
+                               mode, &index);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
                goto out_unlock;
@@ -4805,7 +4698,6 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
                goto out_unlock;
        }
 
-       btrfs_set_trans_block_group(trans, inode);
        err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
        if (err)
                drop_inode = 1;
@@ -4816,8 +4708,6 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
                inode->i_op = &btrfs_file_inode_operations;
                BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
        }
-       btrfs_update_inode_block_group(trans, inode);
-       btrfs_update_inode_block_group(trans, dir);
 out_unlock:
        nr = trans->blocks_used;
        btrfs_end_transaction_throttle(trans, root);
@@ -4864,8 +4754,6 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
 
        btrfs_inc_nlink(inode);
        inode->i_ctime = CURRENT_TIME;
-
-       btrfs_set_trans_block_group(trans, dir);
        ihold(inode);
 
        err = btrfs_add_nondir(trans, dir, dentry, inode, 1, index);
@@ -4874,7 +4762,6 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
                drop_inode = 1;
        } else {
                struct dentry *parent = dget_parent(dentry);
-               btrfs_update_inode_block_group(trans, dir);
                err = btrfs_update_inode(trans, root, inode);
                BUG_ON(err);
                btrfs_log_new_name(trans, inode, NULL, parent);
@@ -4903,10 +4790,6 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        u64 index = 0;
        unsigned long nr = 1;
 
-       err = btrfs_find_free_objectid(NULL, root, dir->i_ino, &objectid);
-       if (err)
-               return err;
-
        /*
         * 2 items for inode and ref
         * 2 items for dir items
@@ -4915,12 +4798,14 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        trans = btrfs_start_transaction(root, 5);
        if (IS_ERR(trans))
                return PTR_ERR(trans);
-       btrfs_set_trans_block_group(trans, dir);
+
+       err = btrfs_find_free_ino(root, &objectid);
+       if (err)
+               goto out_fail;
 
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
-                               dentry->d_name.len, dir->i_ino, objectid,
-                               BTRFS_I(dir)->block_group, S_IFDIR | mode,
-                               &index);
+                               dentry->d_name.len, btrfs_ino(dir), objectid,
+                               S_IFDIR | mode, &index);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
                goto out_fail;
@@ -4934,7 +4819,6 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 
        inode->i_op = &btrfs_dir_inode_operations;
        inode->i_fop = &btrfs_dir_file_operations;
-       btrfs_set_trans_block_group(trans, inode);
 
        btrfs_i_size_write(inode, 0);
        err = btrfs_update_inode(trans, root, inode);
@@ -4948,8 +4832,6 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 
        d_instantiate(dentry, inode);
        drop_on_err = 0;
-       btrfs_update_inode_block_group(trans, inode);
-       btrfs_update_inode_block_group(trans, dir);
 
 out_fail:
        nr = trans->blocks_used;
@@ -5041,7 +4923,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
        u64 bytenr;
        u64 extent_start = 0;
        u64 extent_end = 0;
-       u64 objectid = inode->i_ino;
+       u64 objectid = btrfs_ino(inode);
        u32 found_type;
        struct btrfs_path *path = NULL;
        struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -5069,7 +4951,7 @@ again:
                else
                        goto out;
        }
-       em = alloc_extent_map(GFP_NOFS);
+       em = alloc_extent_map();
        if (!em) {
                err = -ENOMEM;
                goto out;
@@ -5082,7 +4964,15 @@ again:
 
        if (!path) {
                path = btrfs_alloc_path();
-               BUG_ON(!path);
+               if (!path) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+               /*
+                * Chances are we'll be called again, so go ahead and do
+                * readahead
+                */
+               path->reada = 1;
        }
 
        ret = btrfs_lookup_file_extent(trans, root, path,
@@ -5223,8 +5113,10 @@ again:
                                kunmap(page);
                                free_extent_map(em);
                                em = NULL;
-                               btrfs_release_path(root, path);
-                               trans = btrfs_join_transaction(root, 1);
+
+                               btrfs_release_path(path);
+                               trans = btrfs_join_transaction(root);
+
                                if (IS_ERR(trans))
                                        return ERR_CAST(trans);
                                goto again;
@@ -5249,7 +5141,7 @@ not_found_em:
        em->block_start = EXTENT_MAP_HOLE;
        set_bit(EXTENT_FLAG_VACANCY, &em->flags);
 insert:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        if (em->start > start || extent_map_end(em) <= start) {
                printk(KERN_ERR "Btrfs: bad extent! em: [%llu %llu] passed "
                       "[%llu %llu]\n", (unsigned long long)em->start,
@@ -5382,7 +5274,7 @@ struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *pag
                u64 hole_start = start;
                u64 hole_len = len;
 
-               em = alloc_extent_map(GFP_NOFS);
+               em = alloc_extent_map();
                if (!em) {
                        err = -ENOMEM;
                        goto out;
@@ -5468,10 +5360,13 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
                btrfs_drop_extent_cache(inode, start, start + len - 1, 0);
        }
 
-       trans = btrfs_join_transaction(root, 0);
+       trans = btrfs_join_transaction(root);
        if (IS_ERR(trans))
                return ERR_CAST(trans);
 
+       if (start <= BTRFS_I(inode)->disk_i_size && len < 64 * 1024)
+               btrfs_add_inode_defrag(trans, inode);
+
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
        alloc_hint = get_extent_allocation_hint(inode, start, len);
@@ -5483,7 +5378,7 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
        }
 
        if (!em) {
-               em = alloc_extent_map(GFP_NOFS);
+               em = alloc_extent_map();
                if (!em) {
                        em = ERR_PTR(-ENOMEM);
                        goto out;
@@ -5549,7 +5444,7 @@ static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans,
        if (!path)
                return -ENOMEM;
 
-       ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino,
+       ret = btrfs_lookup_file_extent(trans, root, path, btrfs_ino(inode),
                                       offset, 0);
        if (ret < 0)
                goto out;
@@ -5566,7 +5461,7 @@ static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans,
        ret = 0;
        leaf = path->nodes[0];
        btrfs_item_key_to_cpu(leaf, &key, slot);
-       if (key.objectid != inode->i_ino ||
+       if (key.objectid != btrfs_ino(inode) ||
            key.type != BTRFS_EXTENT_DATA_KEY) {
                /* not our file or wrong item type, must cow */
                goto out;
@@ -5600,7 +5495,7 @@ static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans,
         * look for other files referencing this extent, if we
         * find any we must cow
         */
-       if (btrfs_cross_ref_exist(trans, root, inode->i_ino,
+       if (btrfs_cross_ref_exist(trans, root, btrfs_ino(inode),
                                  key.offset - backref_offset, disk_bytenr))
                goto out;
 
@@ -5701,7 +5596,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
                 * to make sure the current transaction stays open
                 * while we look for nocow cross refs
                 */
-               trans = btrfs_join_transaction(root, 0);
+               trans = btrfs_join_transaction(root);
                if (IS_ERR(trans))
                        goto must_cow;
 
@@ -5790,9 +5685,10 @@ static void btrfs_endio_direct_read(struct bio *bio, int err)
 
                        flush_dcache_page(bvec->bv_page);
                        if (csum != *private) {
-                               printk(KERN_ERR "btrfs csum failed ino %lu off"
+                               printk(KERN_ERR "btrfs csum failed ino %llu off"
                                      " %llu csum %u private %u\n",
-                                     inode->i_ino, (unsigned long long)start,
+                                     (unsigned long long)btrfs_ino(inode),
+                                     (unsigned long long)start,
                                      csum, *private);
                                err = -EIO;
                        }
@@ -5839,7 +5735,7 @@ again:
 
        BUG_ON(!ordered);
 
-       trans = btrfs_join_transaction(root, 1);
+       trans = btrfs_join_transaction(root);
        if (IS_ERR(trans)) {
                err = -ENOMEM;
                goto out;
@@ -5939,9 +5835,9 @@ static void btrfs_end_dio_bio(struct bio *bio, int err)
        struct btrfs_dio_private *dip = bio->bi_private;
 
        if (err) {
-               printk(KERN_ERR "btrfs direct IO failed ino %lu rw %lu "
+               printk(KERN_ERR "btrfs direct IO failed ino %llu rw %lu "
                      "sector %#Lx len %u err no %d\n",
-                     dip->inode->i_ino, bio->bi_rw,
+                     (unsigned long long)btrfs_ino(dip->inode), bio->bi_rw,
                      (unsigned long long)bio->bi_sector, bio->bi_size, err);
                dip->errors = 1;
 
@@ -6589,6 +6485,7 @@ out:
 static int btrfs_truncate(struct inode *inode)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_block_rsv *rsv;
        int ret;
        int err = 0;
        struct btrfs_trans_handle *trans;
@@ -6602,28 +6499,80 @@ static int btrfs_truncate(struct inode *inode)
        btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1);
        btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
 
-       trans = btrfs_start_transaction(root, 5);
-       if (IS_ERR(trans))
-               return PTR_ERR(trans);
+       /*
+        * Yes ladies and gentelment, this is indeed ugly.  The fact is we have
+        * 3 things going on here
+        *
+        * 1) We need to reserve space for our orphan item and the space to
+        * delete our orphan item.  Lord knows we don't want to have a dangling
+        * orphan item because we didn't reserve space to remove it.
+        *
+        * 2) We need to reserve space to update our inode.
+        *
+        * 3) We need to have something to cache all the space that is going to
+        * be free'd up by the truncate operation, but also have some slack
+        * space reserved in case it uses space during the truncate (thank you
+        * very much snapshotting).
+        *
+        * And we need these to all be seperate.  The fact is we can use alot of
+        * space doing the truncate, and we have no earthly idea how much space
+        * we will use, so we need the truncate reservation to be seperate so it
+        * doesn't end up using space reserved for updating the inode or
+        * removing the orphan item.  We also need to be able to stop the
+        * transaction and start a new one, which means we need to be able to
+        * update the inode several times, and we have no idea of knowing how
+        * many times that will be, so we can't just reserve 1 item for the
+        * entirety of the opration, so that has to be done seperately as well.
+        * Then there is the orphan item, which does indeed need to be held on
+        * to for the whole operation, and we need nobody to touch this reserved
+        * space except the orphan code.
+        *
+        * So that leaves us with
+        *
+        * 1) root->orphan_block_rsv - for the orphan deletion.
+        * 2) rsv - for the truncate reservation, which we will steal from the
+        * transaction reservation.
+        * 3) fs_info->trans_block_rsv - this will have 1 items worth left for
+        * updating the inode.
+        */
+       rsv = btrfs_alloc_block_rsv(root);
+       if (!rsv)
+               return -ENOMEM;
+       btrfs_add_durable_block_rsv(root->fs_info, rsv);
 
-       btrfs_set_trans_block_group(trans, inode);
+       trans = btrfs_start_transaction(root, 4);
+       if (IS_ERR(trans)) {
+               err = PTR_ERR(trans);
+               goto out;
+       }
+
+       /*
+        * Reserve space for the truncate process.  Truncate should be adding
+        * space, but if there are snapshots it may end up using space.
+        */
+       ret = btrfs_truncate_reserve_metadata(trans, root, rsv);
+       BUG_ON(ret);
 
        ret = btrfs_orphan_add(trans, inode);
        if (ret) {
                btrfs_end_transaction(trans, root);
-               return ret;
+               goto out;
        }
 
        nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
        btrfs_btree_balance_dirty(root, nr);
 
-       /* Now start a transaction for the truncate */
-       trans = btrfs_start_transaction(root, 0);
-       if (IS_ERR(trans))
-               return PTR_ERR(trans);
-       btrfs_set_trans_block_group(trans, inode);
-       trans->block_rsv = root->orphan_block_rsv;
+       /*
+        * Ok so we've already migrated our bytes over for the truncate, so here
+        * just reserve the one slot we need for updating the inode.
+        */
+       trans = btrfs_start_transaction(root, 1);
+       if (IS_ERR(trans)) {
+               err = PTR_ERR(trans);
+               goto out;
+       }
+       trans->block_rsv = rsv;
 
        /*
         * setattr is responsible for setting the ordered_data_close flag,
@@ -6647,24 +6596,17 @@ static int btrfs_truncate(struct inode *inode)
 
        while (1) {
                if (!trans) {
-                       trans = btrfs_start_transaction(root, 0);
-                       if (IS_ERR(trans))
-                               return PTR_ERR(trans);
-                       btrfs_set_trans_block_group(trans, inode);
-                       trans->block_rsv = root->orphan_block_rsv;
-               }
+                       trans = btrfs_start_transaction(root, 3);
+                       if (IS_ERR(trans)) {
+                               err = PTR_ERR(trans);
+                               goto out;
+                       }
 
-               ret = btrfs_block_rsv_check(trans, root,
-                                           root->orphan_block_rsv, 0, 5);
-               if (ret == -EAGAIN) {
-                       ret = btrfs_commit_transaction(trans, root);
-                       if (ret)
-                               return ret;
-                       trans = NULL;
-                       continue;
-               } else if (ret) {
-                       err = ret;
-                       break;
+                       ret = btrfs_truncate_reserve_metadata(trans, root,
+                                                             rsv);
+                       BUG_ON(ret);
+
+                       trans->block_rsv = rsv;
                }
 
                ret = btrfs_truncate_inode_items(trans, root, inode,
@@ -6675,6 +6617,7 @@ static int btrfs_truncate(struct inode *inode)
                        break;
                }
 
+               trans->block_rsv = &root->fs_info->trans_block_rsv;
                ret = btrfs_update_inode(trans, root, inode);
                if (ret) {
                        err = ret;
@@ -6688,6 +6631,7 @@ static int btrfs_truncate(struct inode *inode)
        }
 
        if (ret == 0 && inode->i_nlink > 0) {
+               trans->block_rsv = root->orphan_block_rsv;
                ret = btrfs_orphan_del(trans, inode);
                if (ret)
                        err = ret;
@@ -6699,15 +6643,20 @@ static int btrfs_truncate(struct inode *inode)
                ret = btrfs_orphan_del(NULL, inode);
        }
 
+       trans->block_rsv = &root->fs_info->trans_block_rsv;
        ret = btrfs_update_inode(trans, root, inode);
        if (ret && !err)
                err = ret;
 
        nr = trans->blocks_used;
        ret = btrfs_end_transaction_throttle(trans, root);
+       btrfs_btree_balance_dirty(root, nr);
+
+out:
+       btrfs_free_block_rsv(root, rsv);
+
        if (ret && !err)
                err = ret;
-       btrfs_btree_balance_dirty(root, nr);
 
        return err;
 }
@@ -6716,15 +6665,14 @@ static int btrfs_truncate(struct inode *inode)
  * create a new subvolume directory/inode (helper for the ioctl).
  */
 int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
-                            struct btrfs_root *new_root,
-                            u64 new_dirid, u64 alloc_hint)
+                            struct btrfs_root *new_root, u64 new_dirid)
 {
        struct inode *inode;
        int err;
        u64 index = 0;
 
        inode = btrfs_new_inode(trans, new_root, NULL, "..", 2, new_dirid,
-                               new_dirid, alloc_hint, S_IFDIR | 0700, &index);
+                               new_dirid, S_IFDIR | 0700, &index);
        if (IS_ERR(inode))
                return PTR_ERR(inode);
        inode->i_op = &btrfs_dir_inode_operations;
@@ -6782,12 +6730,15 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
        ei->ordered_data_close = 0;
        ei->orphan_meta_reserved = 0;
        ei->dummy_inode = 0;
+       ei->in_defrag = 0;
        ei->force_compress = BTRFS_COMPRESS_NONE;
 
+       ei->delayed_node = NULL;
+
        inode = &ei->vfs_inode;
-       extent_map_tree_init(&ei->extent_tree, GFP_NOFS);
-       extent_io_tree_init(&ei->io_tree, &inode->i_data, GFP_NOFS);
-       extent_io_tree_init(&ei->io_failure_tree, &inode->i_data, GFP_NOFS);
+       extent_map_tree_init(&ei->extent_tree);
+       extent_io_tree_init(&ei->io_tree, &inode->i_data);
+       extent_io_tree_init(&ei->io_failure_tree, &inode->i_data);
        mutex_init(&ei->log_mutex);
        btrfs_ordered_inode_tree_init(&ei->ordered_tree);
        INIT_LIST_HEAD(&ei->i_orphan);
@@ -6834,25 +6785,10 @@ void btrfs_destroy_inode(struct inode *inode)
                spin_unlock(&root->fs_info->ordered_extent_lock);
        }
 
-       if (root == root->fs_info->tree_root) {
-               struct btrfs_block_group_cache *block_group;
-
-               block_group = btrfs_lookup_block_group(root->fs_info,
-                                               BTRFS_I(inode)->block_group);
-               if (block_group && block_group->inode == inode) {
-                       spin_lock(&block_group->lock);
-                       block_group->inode = NULL;
-                       spin_unlock(&block_group->lock);
-                       btrfs_put_block_group(block_group);
-               } else if (block_group) {
-                       btrfs_put_block_group(block_group);
-               }
-       }
-
        spin_lock(&root->orphan_lock);
        if (!list_empty(&BTRFS_I(inode)->i_orphan)) {
-               printk(KERN_INFO "BTRFS: inode %lu still on the orphan list\n",
-                      inode->i_ino);
+               printk(KERN_INFO "BTRFS: inode %llu still on the orphan list\n",
+                      (unsigned long long)btrfs_ino(inode));
                list_del_init(&BTRFS_I(inode)->i_orphan);
        }
        spin_unlock(&root->orphan_lock);
@@ -6874,6 +6810,7 @@ void btrfs_destroy_inode(struct inode *inode)
        inode_tree_del(inode);
        btrfs_drop_extent_cache(inode, 0, (u64)-1, 0);
 free:
+       btrfs_remove_delayed_node(inode);
        call_rcu(&inode->i_rcu, btrfs_i_callback);
 }
 
@@ -6882,7 +6819,7 @@ int btrfs_drop_inode(struct inode *inode)
        struct btrfs_root *root = BTRFS_I(inode)->root;
 
        if (btrfs_root_refs(&root->root_item) == 0 &&
-           root != root->fs_info->tree_root)
+           !is_free_space_inode(root, inode))
                return 1;
        else
                return generic_drop_inode(inode);
@@ -6991,16 +6928,17 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        u64 index = 0;
        u64 root_objectid;
        int ret;
+       u64 old_ino = btrfs_ino(old_inode);
 
-       if (new_dir->i_ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)
+       if (btrfs_ino(new_dir) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)
                return -EPERM;
 
        /* we only allow rename subvolume link between subvolumes */
-       if (old_inode->i_ino != BTRFS_FIRST_FREE_OBJECTID && root != dest)
+       if (old_ino != BTRFS_FIRST_FREE_OBJECTID && root != dest)
                return -EXDEV;
 
-       if (old_inode->i_ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID ||
-           (new_inode && new_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID))
+       if (old_ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID ||
+           (new_inode && btrfs_ino(new_inode) == BTRFS_FIRST_FREE_OBJECTID))
                return -ENOTEMPTY;
 
        if (S_ISDIR(old_inode->i_mode) && new_inode &&
@@ -7016,7 +6954,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                filemap_flush(old_inode->i_mapping);
 
        /* close the racy window with snapshot create/destroy ioctl */
-       if (old_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)
+       if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
                down_read(&root->fs_info->subvol_sem);
        /*
         * We want to reserve the absolute worst case amount of items.  So if
@@ -7032,8 +6970,6 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                 goto out_notrans;
         }
 
-       btrfs_set_trans_block_group(trans, new_dir);
-
        if (dest != root)
                btrfs_record_root_in_trans(trans, dest);
 
@@ -7041,15 +6977,15 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (ret)
                goto out_fail;
 
-       if (unlikely(old_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)) {
+       if (unlikely(old_ino == BTRFS_FIRST_FREE_OBJECTID)) {
                /* force full log commit if subvolume involved. */
                root->fs_info->last_trans_log_full_commit = trans->transid;
        } else {
                ret = btrfs_insert_inode_ref(trans, dest,
                                             new_dentry->d_name.name,
                                             new_dentry->d_name.len,
-                                            old_inode->i_ino,
-                                            new_dir->i_ino, index);
+                                            old_ino,
+                                            btrfs_ino(new_dir), index);
                if (ret)
                        goto out_fail;
                /*
@@ -7065,10 +7001,8 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
         * make sure the inode gets flushed if it is replacing
         * something.
         */
-       if (new_inode && new_inode->i_size &&
-           old_inode && S_ISREG(old_inode->i_mode)) {
+       if (new_inode && new_inode->i_size && S_ISREG(old_inode->i_mode))
                btrfs_add_ordered_operation(trans, root, old_inode);
-       }
 
        old_dir->i_ctime = old_dir->i_mtime = ctime;
        new_dir->i_ctime = new_dir->i_mtime = ctime;
@@ -7077,7 +7011,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (old_dentry->d_parent != new_dentry->d_parent)
                btrfs_record_unlink_dir(trans, old_dir, old_inode, 1);
 
-       if (unlikely(old_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)) {
+       if (unlikely(old_ino == BTRFS_FIRST_FREE_OBJECTID)) {
                root_objectid = BTRFS_I(old_inode)->root->root_key.objectid;
                ret = btrfs_unlink_subvol(trans, root, old_dir, root_objectid,
                                        old_dentry->d_name.name,
@@ -7094,7 +7028,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        if (new_inode) {
                new_inode->i_ctime = CURRENT_TIME;
-               if (unlikely(new_inode->i_ino ==
+               if (unlikely(btrfs_ino(new_inode) ==
                             BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) {
                        root_objectid = BTRFS_I(new_inode)->location.objectid;
                        ret = btrfs_unlink_subvol(trans, dest, new_dir,
@@ -7122,7 +7056,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                             new_dentry->d_name.len, 0, index);
        BUG_ON(ret);
 
-       if (old_inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) {
+       if (old_ino != BTRFS_FIRST_FREE_OBJECTID) {
                struct dentry *parent = dget_parent(new_dentry);
                btrfs_log_new_name(trans, old_inode, old_dir, parent);
                dput(parent);
@@ -7131,7 +7065,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 out_fail:
        btrfs_end_transaction_throttle(trans, root);
 out_notrans:
-       if (old_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)
+       if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
                up_read(&root->fs_info->subvol_sem);
 
        return ret;
@@ -7185,58 +7119,6 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput)
        return 0;
 }
 
-int btrfs_start_one_delalloc_inode(struct btrfs_root *root, int delay_iput,
-                                  int sync)
-{
-       struct btrfs_inode *binode;
-       struct inode *inode = NULL;
-
-       spin_lock(&root->fs_info->delalloc_lock);
-       while (!list_empty(&root->fs_info->delalloc_inodes)) {
-               binode = list_entry(root->fs_info->delalloc_inodes.next,
-                                   struct btrfs_inode, delalloc_inodes);
-               inode = igrab(&binode->vfs_inode);
-               if (inode) {
-                       list_move_tail(&binode->delalloc_inodes,
-                                      &root->fs_info->delalloc_inodes);
-                       break;
-               }
-
-               list_del_init(&binode->delalloc_inodes);
-               cond_resched_lock(&root->fs_info->delalloc_lock);
-       }
-       spin_unlock(&root->fs_info->delalloc_lock);
-
-       if (inode) {
-               if (sync) {
-                       filemap_write_and_wait(inode->i_mapping);
-                       /*
-                        * We have to do this because compression doesn't
-                        * actually set PG_writeback until it submits the pages
-                        * for IO, which happens in an async thread, so we could
-                        * race and not actually wait for any writeback pages
-                        * because they've not been submitted yet.  Technically
-                        * this could still be the case for the ordered stuff
-                        * since the async thread may not have started to do its
-                        * work yet.  If this becomes the case then we need to
-                        * figure out a way to make sure that in writepage we
-                        * wait for any async pages to be submitted before
-                        * returning so that fdatawait does what its supposed to
-                        * do.
-                        */
-                       btrfs_wait_ordered_range(inode, 0, (u64)-1);
-               } else {
-                       filemap_flush(inode->i_mapping);
-               }
-               if (delay_iput)
-                       btrfs_add_delayed_iput(inode);
-               else
-                       iput(inode);
-               return 1;
-       }
-       return 0;
-}
-
 static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
                         const char *symname)
 {
@@ -7260,9 +7142,6 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
        if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(root))
                return -ENAMETOOLONG;
 
-       err = btrfs_find_free_objectid(NULL, root, dir->i_ino, &objectid);
-       if (err)
-               return err;
        /*
         * 2 items for inode item and ref
         * 2 items for dir items
@@ -7272,12 +7151,13 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
        if (IS_ERR(trans))
                return PTR_ERR(trans);
 
-       btrfs_set_trans_block_group(trans, dir);
+       err = btrfs_find_free_ino(root, &objectid);
+       if (err)
+               goto out_unlock;
 
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
-                               dentry->d_name.len, dir->i_ino, objectid,
-                               BTRFS_I(dir)->block_group, S_IFLNK|S_IRWXUGO,
-                               &index);
+                               dentry->d_name.len, btrfs_ino(dir), objectid,
+                               S_IFLNK|S_IRWXUGO, &index);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
                goto out_unlock;
@@ -7289,7 +7169,6 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
                goto out_unlock;
        }
 
-       btrfs_set_trans_block_group(trans, inode);
        err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
        if (err)
                drop_inode = 1;
@@ -7300,14 +7179,12 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
                inode->i_op = &btrfs_file_inode_operations;
                BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
        }
-       btrfs_update_inode_block_group(trans, inode);
-       btrfs_update_inode_block_group(trans, dir);
        if (drop_inode)
                goto out_unlock;
 
        path = btrfs_alloc_path();
        BUG_ON(!path);
-       key.objectid = inode->i_ino;
+       key.objectid = btrfs_ino(inode);
        key.offset = 0;
        btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
        datasize = btrfs_file_extent_calc_inline_size(name_len);
@@ -7315,6 +7192,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
                                      datasize);
        if (err) {
                drop_inode = 1;
+               btrfs_free_path(path);
                goto out_unlock;
        }
        leaf = path->nodes[0];
index 2616f7ed47996a21df8b0c5de224c4b6c1aebf70..a3c4751e07db0d7704e8ac1aa3269d7c75e3c48a 100644 (file)
@@ -50,6 +50,7 @@
 #include "print-tree.h"
 #include "volumes.h"
 #include "locking.h"
+#include "inode-map.h"
 
 /* Mask out flags that are inappropriate for the given type of inode. */
 static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags)
@@ -242,7 +243,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
                ip->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS);
        }
 
-       trans = btrfs_join_transaction(root, 1);
+       trans = btrfs_join_transaction(root);
        BUG_ON(IS_ERR(trans));
 
        ret = btrfs_update_inode(trans, root, inode);
@@ -281,8 +282,9 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       mutex_lock(&fs_info->fs_devices->device_list_mutex);
-       list_for_each_entry(device, &fs_info->fs_devices->devices, dev_list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(device, &fs_info->fs_devices->devices,
+                               dev_list) {
                if (!device->bdev)
                        continue;
                q = bdev_get_queue(device->bdev);
@@ -292,7 +294,7 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
                                     minlen);
                }
        }
-       mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+       rcu_read_unlock();
        if (!num_devices)
                return -EOPNOTSUPP;
 
@@ -329,8 +331,7 @@ static noinline int create_subvol(struct btrfs_root *root,
        u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
        u64 index = 0;
 
-       ret = btrfs_find_free_objectid(NULL, root->fs_info->tree_root,
-                                      0, &objectid);
+       ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid);
        if (ret) {
                dput(parent);
                return ret;
@@ -413,8 +414,7 @@ static noinline int create_subvol(struct btrfs_root *root,
 
        btrfs_record_root_in_trans(trans, new_root);
 
-       ret = btrfs_create_subvol_root(trans, new_root, new_dirid,
-                                      BTRFS_I(dir)->block_group);
+       ret = btrfs_create_subvol_root(trans, new_root, new_dirid);
        /*
         * insert the directory item
         */
@@ -422,7 +422,7 @@ static noinline int create_subvol(struct btrfs_root *root,
        BUG_ON(ret);
 
        ret = btrfs_insert_dir_item(trans, root,
-                                   name, namelen, dir->i_ino, &key,
+                                   name, namelen, dir, &key,
                                    BTRFS_FT_DIR, index);
        if (ret)
                goto fail;
@@ -433,7 +433,7 @@ static noinline int create_subvol(struct btrfs_root *root,
 
        ret = btrfs_add_root_ref(trans, root->fs_info->tree_root,
                                 objectid, root->root_key.objectid,
-                                dir->i_ino, index, name, namelen);
+                                btrfs_ino(dir), index, name, namelen);
 
        BUG_ON(ret);
 
@@ -482,8 +482,10 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
        ret = btrfs_snap_reserve_metadata(trans, pending_snapshot);
        BUG_ON(ret);
 
+       spin_lock(&root->fs_info->trans_lock);
        list_add(&pending_snapshot->list,
                 &trans->transaction->pending_snapshots);
+       spin_unlock(&root->fs_info->trans_lock);
        if (async_transid) {
                *async_transid = trans->transid;
                ret = btrfs_commit_transaction_async(trans,
@@ -655,6 +657,107 @@ out_unlock:
        return error;
 }
 
+/*
+ * When we're defragging a range, we don't want to kick it off again
+ * if it is really just waiting for delalloc to send it down.
+ * If we find a nice big extent or delalloc range for the bytes in the
+ * file you want to defrag, we return 0 to let you know to skip this
+ * part of the file
+ */
+static int check_defrag_in_cache(struct inode *inode, u64 offset, int thresh)
+{
+       struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
+       struct extent_map *em = NULL;
+       struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
+       u64 end;
+
+       read_lock(&em_tree->lock);
+       em = lookup_extent_mapping(em_tree, offset, PAGE_CACHE_SIZE);
+       read_unlock(&em_tree->lock);
+
+       if (em) {
+               end = extent_map_end(em);
+               free_extent_map(em);
+               if (end - offset > thresh)
+                       return 0;
+       }
+       /* if we already have a nice delalloc here, just stop */
+       thresh /= 2;
+       end = count_range_bits(io_tree, &offset, offset + thresh,
+                              thresh, EXTENT_DELALLOC, 1);
+       if (end >= thresh)
+               return 0;
+       return 1;
+}
+
+/*
+ * helper function to walk through a file and find extents
+ * newer than a specific transid, and smaller than thresh.
+ *
+ * This is used by the defragging code to find new and small
+ * extents
+ */
+static int find_new_extents(struct btrfs_root *root,
+                           struct inode *inode, u64 newer_than,
+                           u64 *off, int thresh)
+{
+       struct btrfs_path *path;
+       struct btrfs_key min_key;
+       struct btrfs_key max_key;
+       struct extent_buffer *leaf;
+       struct btrfs_file_extent_item *extent;
+       int type;
+       int ret;
+       u64 ino = btrfs_ino(inode);
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       min_key.objectid = ino;
+       min_key.type = BTRFS_EXTENT_DATA_KEY;
+       min_key.offset = *off;
+
+       max_key.objectid = ino;
+       max_key.type = (u8)-1;
+       max_key.offset = (u64)-1;
+
+       path->keep_locks = 1;
+
+       while(1) {
+               ret = btrfs_search_forward(root, &min_key, &max_key,
+                                          path, 0, newer_than);
+               if (ret != 0)
+                       goto none;
+               if (min_key.objectid != ino)
+                       goto none;
+               if (min_key.type != BTRFS_EXTENT_DATA_KEY)
+                       goto none;
+
+               leaf = path->nodes[0];
+               extent = btrfs_item_ptr(leaf, path->slots[0],
+                                       struct btrfs_file_extent_item);
+
+               type = btrfs_file_extent_type(leaf, extent);
+               if (type == BTRFS_FILE_EXTENT_REG &&
+                   btrfs_file_extent_num_bytes(leaf, extent) < thresh &&
+                   check_defrag_in_cache(inode, min_key.offset, thresh)) {
+                       *off = min_key.offset;
+                       btrfs_free_path(path);
+                       return 0;
+               }
+
+               if (min_key.offset == (u64)-1)
+                       goto none;
+
+               min_key.offset++;
+               btrfs_release_path(path);
+       }
+none:
+       btrfs_free_path(path);
+       return -ENOENT;
+}
+
 static int should_defrag_range(struct inode *inode, u64 start, u64 len,
                               int thresh, u64 *last_len, u64 *skip,
                               u64 *defrag_end)
@@ -664,10 +767,6 @@ static int should_defrag_range(struct inode *inode, u64 start, u64 len,
        struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
        int ret = 1;
 
-
-       if (thresh == 0)
-               thresh = 256 * 1024;
-
        /*
         * make sure that once we start defragging and extent, we keep on
         * defragging it
@@ -726,27 +825,176 @@ static int should_defrag_range(struct inode *inode, u64 start, u64 len,
        return ret;
 }
 
-static int btrfs_defrag_file(struct file *file,
-                            struct btrfs_ioctl_defrag_range_args *range)
+/*
+ * it doesn't do much good to defrag one or two pages
+ * at a time.  This pulls in a nice chunk of pages
+ * to COW and defrag.
+ *
+ * It also makes sure the delalloc code has enough
+ * dirty data to avoid making new small extents as part
+ * of the defrag
+ *
+ * It's a good idea to start RA on this range
+ * before calling this.
+ */
+static int cluster_pages_for_defrag(struct inode *inode,
+                                   struct page **pages,
+                                   unsigned long start_index,
+                                   int num_pages)
 {
-       struct inode *inode = fdentry(file)->d_inode;
-       struct btrfs_root *root = BTRFS_I(inode)->root;
-       struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
+       unsigned long file_end;
+       u64 isize = i_size_read(inode);
+       u64 page_start;
+       u64 page_end;
+       int ret;
+       int i;
+       int i_done;
        struct btrfs_ordered_extent *ordered;
-       struct page *page;
+       struct extent_state *cached_state = NULL;
+
+       if (isize == 0)
+               return 0;
+       file_end = (isize - 1) >> PAGE_CACHE_SHIFT;
+
+       ret = btrfs_delalloc_reserve_space(inode,
+                                          num_pages << PAGE_CACHE_SHIFT);
+       if (ret)
+               return ret;
+again:
+       ret = 0;
+       i_done = 0;
+
+       /* step one, lock all the pages */
+       for (i = 0; i < num_pages; i++) {
+               struct page *page;
+               page = grab_cache_page(inode->i_mapping,
+                                           start_index + i);
+               if (!page)
+                       break;
+
+               if (!PageUptodate(page)) {
+                       btrfs_readpage(NULL, page);
+                       lock_page(page);
+                       if (!PageUptodate(page)) {
+                               unlock_page(page);
+                               page_cache_release(page);
+                               ret = -EIO;
+                               break;
+                       }
+               }
+               isize = i_size_read(inode);
+               file_end = (isize - 1) >> PAGE_CACHE_SHIFT;
+               if (!isize || page->index > file_end ||
+                   page->mapping != inode->i_mapping) {
+                       /* whoops, we blew past eof, skip this page */
+                       unlock_page(page);
+                       page_cache_release(page);
+                       break;
+               }
+               pages[i] = page;
+               i_done++;
+       }
+       if (!i_done || ret)
+               goto out;
+
+       if (!(inode->i_sb->s_flags & MS_ACTIVE))
+               goto out;
+
+       /*
+        * so now we have a nice long stream of locked
+        * and up to date pages, lets wait on them
+        */
+       for (i = 0; i < i_done; i++)
+               wait_on_page_writeback(pages[i]);
+
+       page_start = page_offset(pages[0]);
+       page_end = page_offset(pages[i_done - 1]) + PAGE_CACHE_SIZE;
+
+       lock_extent_bits(&BTRFS_I(inode)->io_tree,
+                        page_start, page_end - 1, 0, &cached_state,
+                        GFP_NOFS);
+       ordered = btrfs_lookup_first_ordered_extent(inode, page_end - 1);
+       if (ordered &&
+           ordered->file_offset + ordered->len > page_start &&
+           ordered->file_offset < page_end) {
+               btrfs_put_ordered_extent(ordered);
+               unlock_extent_cached(&BTRFS_I(inode)->io_tree,
+                                    page_start, page_end - 1,
+                                    &cached_state, GFP_NOFS);
+               for (i = 0; i < i_done; i++) {
+                       unlock_page(pages[i]);
+                       page_cache_release(pages[i]);
+               }
+               btrfs_wait_ordered_range(inode, page_start,
+                                        page_end - page_start);
+               goto again;
+       }
+       if (ordered)
+               btrfs_put_ordered_extent(ordered);
+
+       clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start,
+                         page_end - 1, EXTENT_DIRTY | EXTENT_DELALLOC |
+                         EXTENT_DO_ACCOUNTING, 0, 0, &cached_state,
+                         GFP_NOFS);
+
+       if (i_done != num_pages) {
+               atomic_inc(&BTRFS_I(inode)->outstanding_extents);
+               btrfs_delalloc_release_space(inode,
+                                    (num_pages - i_done) << PAGE_CACHE_SHIFT);
+       }
+
+
+       btrfs_set_extent_delalloc(inode, page_start, page_end - 1,
+                                 &cached_state);
+
+       unlock_extent_cached(&BTRFS_I(inode)->io_tree,
+                            page_start, page_end - 1, &cached_state,
+                            GFP_NOFS);
+
+       for (i = 0; i < i_done; i++) {
+               clear_page_dirty_for_io(pages[i]);
+               ClearPageChecked(pages[i]);
+               set_page_extent_mapped(pages[i]);
+               set_page_dirty(pages[i]);
+               unlock_page(pages[i]);
+               page_cache_release(pages[i]);
+       }
+       return i_done;
+out:
+       for (i = 0; i < i_done; i++) {
+               unlock_page(pages[i]);
+               page_cache_release(pages[i]);
+       }
+       btrfs_delalloc_release_space(inode, num_pages << PAGE_CACHE_SHIFT);
+       return ret;
+
+}
+
+int btrfs_defrag_file(struct inode *inode, struct file *file,
+                     struct btrfs_ioctl_defrag_range_args *range,
+                     u64 newer_than, unsigned long max_to_defrag)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_super_block *disk_super;
+       struct file_ra_state *ra = NULL;
        unsigned long last_index;
-       unsigned long ra_pages = root->fs_info->bdi.ra_pages;
-       unsigned long total_read = 0;
        u64 features;
-       u64 page_start;
-       u64 page_end;
        u64 last_len = 0;
        u64 skip = 0;
        u64 defrag_end = 0;
+       u64 newer_off = range->start;
+       int newer_left = 0;
        unsigned long i;
        int ret;
+       int defrag_count = 0;
        int compress_type = BTRFS_COMPRESS_ZLIB;
+       int extent_thresh = range->extent_thresh;
+       int newer_cluster = (256 * 1024) >> PAGE_CACHE_SHIFT;
+       u64 new_align = ~((u64)128 * 1024 - 1);
+       struct page **pages = NULL;
+
+       if (extent_thresh == 0)
+               extent_thresh = 256 * 1024;
 
        if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) {
                if (range->compress_type > BTRFS_COMPRESS_TYPES)
@@ -758,6 +1006,27 @@ static int btrfs_defrag_file(struct file *file,
        if (inode->i_size == 0)
                return 0;
 
+       /*
+        * if we were not given a file, allocate a readahead
+        * context
+        */
+       if (!file) {
+               ra = kzalloc(sizeof(*ra), GFP_NOFS);
+               if (!ra)
+                       return -ENOMEM;
+               file_ra_state_init(ra, inode->i_mapping);
+       } else {
+               ra = &file->f_ra;
+       }
+
+       pages = kmalloc(sizeof(struct page *) * newer_cluster,
+                       GFP_NOFS);
+       if (!pages) {
+               ret = -ENOMEM;
+               goto out_ra;
+       }
+
+       /* find the last page to defrag */
        if (range->start + range->len > range->start) {
                last_index = min_t(u64, inode->i_size - 1,
                         range->start + range->len - 1) >> PAGE_CACHE_SHIFT;
@@ -765,11 +1034,37 @@ static int btrfs_defrag_file(struct file *file,
                last_index = (inode->i_size - 1) >> PAGE_CACHE_SHIFT;
        }
 
-       i = range->start >> PAGE_CACHE_SHIFT;
-       while (i <= last_index) {
-               if (!should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT,
+       if (newer_than) {
+               ret = find_new_extents(root, inode, newer_than,
+                                      &newer_off, 64 * 1024);
+               if (!ret) {
+                       range->start = newer_off;
+                       /*
+                        * we always align our defrag to help keep
+                        * the extents in the file evenly spaced
+                        */
+                       i = (newer_off & new_align) >> PAGE_CACHE_SHIFT;
+                       newer_left = newer_cluster;
+               } else
+                       goto out_ra;
+       } else {
+               i = range->start >> PAGE_CACHE_SHIFT;
+       }
+       if (!max_to_defrag)
+               max_to_defrag = last_index - 1;
+
+       while (i <= last_index && defrag_count < max_to_defrag) {
+               /*
+                * make sure we stop running if someone unmounts
+                * the FS
+                */
+               if (!(inode->i_sb->s_flags & MS_ACTIVE))
+                       break;
+
+               if (!newer_than &&
+                   !should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT,
                                        PAGE_CACHE_SIZE,
-                                       range->extent_thresh,
+                                       extent_thresh,
                                        &last_len, &skip,
                                        &defrag_end)) {
                        unsigned long next;
@@ -781,92 +1076,39 @@ static int btrfs_defrag_file(struct file *file,
                        i = max(i + 1, next);
                        continue;
                }
-
-               if (total_read % ra_pages == 0) {
-                       btrfs_force_ra(inode->i_mapping, &file->f_ra, file, i,
-                                      min(last_index, i + ra_pages - 1));
-               }
-               total_read++;
-               mutex_lock(&inode->i_mutex);
                if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)
                        BTRFS_I(inode)->force_compress = compress_type;
 
-               ret  = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
-               if (ret)
-                       goto err_unlock;
-again:
-               if (inode->i_size == 0 ||
-                   i > ((inode->i_size - 1) >> PAGE_CACHE_SHIFT)) {
-                       ret = 0;
-                       goto err_reservations;
-               }
-
-               page = grab_cache_page(inode->i_mapping, i);
-               if (!page) {
-                       ret = -ENOMEM;
-                       goto err_reservations;
-               }
-
-               if (!PageUptodate(page)) {
-                       btrfs_readpage(NULL, page);
-                       lock_page(page);
-                       if (!PageUptodate(page)) {
-                               unlock_page(page);
-                               page_cache_release(page);
-                               ret = -EIO;
-                               goto err_reservations;
-                       }
-               }
-
-               if (page->mapping != inode->i_mapping) {
-                       unlock_page(page);
-                       page_cache_release(page);
-                       goto again;
-               }
+               btrfs_force_ra(inode->i_mapping, ra, file, i, newer_cluster);
 
-               wait_on_page_writeback(page);
+               ret = cluster_pages_for_defrag(inode, pages, i, newer_cluster);
+               if (ret < 0)
+                       goto out_ra;
 
-               if (PageDirty(page)) {
-                       btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
-                       goto loop_unlock;
-               }
+               defrag_count += ret;
+               balance_dirty_pages_ratelimited_nr(inode->i_mapping, ret);
+               i += ret;
 
-               page_start = (u64)page->index << PAGE_CACHE_SHIFT;
-               page_end = page_start + PAGE_CACHE_SIZE - 1;
-               lock_extent(io_tree, page_start, page_end, GFP_NOFS);
+               if (newer_than) {
+                       if (newer_off == (u64)-1)
+                               break;
 
-               ordered = btrfs_lookup_ordered_extent(inode, page_start);
-               if (ordered) {
-                       unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
-                       unlock_page(page);
-                       page_cache_release(page);
-                       btrfs_start_ordered_extent(inode, ordered, 1);
-                       btrfs_put_ordered_extent(ordered);
-                       goto again;
+                       newer_off = max(newer_off + 1,
+                                       (u64)i << PAGE_CACHE_SHIFT);
+
+                       ret = find_new_extents(root, inode,
+                                              newer_than, &newer_off,
+                                              64 * 1024);
+                       if (!ret) {
+                               range->start = newer_off;
+                               i = (newer_off & new_align) >> PAGE_CACHE_SHIFT;
+                               newer_left = newer_cluster;
+                       } else {
+                               break;
+                       }
+               } else {
+                       i++;
                }
-               set_page_extent_mapped(page);
-
-               /*
-                * this makes sure page_mkwrite is called on the
-                * page if it is dirtied again later
-                */
-               clear_page_dirty_for_io(page);
-               clear_extent_bits(&BTRFS_I(inode)->io_tree, page_start,
-                                 page_end, EXTENT_DIRTY | EXTENT_DELALLOC |
-                                 EXTENT_DO_ACCOUNTING, GFP_NOFS);
-
-               btrfs_set_extent_delalloc(inode, page_start, page_end, NULL);
-               ClearPageChecked(page);
-               set_page_dirty(page);
-               unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
-
-loop_unlock:
-               unlock_page(page);
-               page_cache_release(page);
-               mutex_unlock(&inode->i_mutex);
-
-               balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1);
-               i++;
        }
 
        if ((range->flags & BTRFS_DEFRAG_RANGE_START_IO))
@@ -898,12 +1140,14 @@ loop_unlock:
                btrfs_set_super_incompat_flags(disk_super, features);
        }
 
-       return 0;
+       if (!file)
+               kfree(ra);
+       return defrag_count;
 
-err_reservations:
-       btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
-err_unlock:
-       mutex_unlock(&inode->i_mutex);
+out_ra:
+       if (!file)
+               kfree(ra);
+       kfree(pages);
        return ret;
 }
 
@@ -1129,7 +1373,7 @@ static noinline int btrfs_ioctl_subvol_getflags(struct file *file,
        int ret = 0;
        u64 flags = 0;
 
-       if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID)
+       if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID)
                return -EINVAL;
 
        down_read(&root->fs_info->subvol_sem);
@@ -1156,7 +1400,7 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
        if (root->fs_info->sb->s_flags & MS_RDONLY)
                return -EROFS;
 
-       if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID)
+       if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID)
                return -EINVAL;
 
        if (copy_from_user(&flags, arg, sizeof(flags)))
@@ -1279,7 +1523,6 @@ static noinline int copy_to_sk(struct btrfs_root *root,
        int nritems;
        int i;
        int slot;
-       int found = 0;
        int ret = 0;
 
        leaf = path->nodes[0];
@@ -1326,7 +1569,7 @@ static noinline int copy_to_sk(struct btrfs_root *root,
                                           item_off, item_len);
                        *sk_offset += item_len;
                }
-               found++;
+               (*num_found)++;
 
                if (*num_found >= sk->nr_items)
                        break;
@@ -1345,7 +1588,6 @@ advance_key:
        } else
                ret = 1;
 overflow:
-       *num_found += found;
        return ret;
 }
 
@@ -1402,7 +1644,7 @@ static noinline int search_ioctl(struct inode *inode,
                }
                ret = copy_to_sk(root, path, &key, sk, args->buf,
                                 &sk_offset, &num_found);
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                if (ret || num_found >= sk->nr_items)
                        break;
 
@@ -1509,7 +1751,7 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
                if (key.offset == BTRFS_FIRST_FREE_OBJECTID)
                        break;
 
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                key.objectid = key.offset;
                key.offset = (u64)-1;
                dirid = key.objectid;
@@ -1639,7 +1881,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                        goto out_dput;
        }
 
-       if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) {
+       if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) {
                err = -EINVAL;
                goto out_dput;
        }
@@ -1757,7 +1999,10 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
                        /* the rest are all set to zero by kzalloc */
                        range->len = (u64)-1;
                }
-               ret = btrfs_defrag_file(file, range);
+               ret = btrfs_defrag_file(fdentry(file)->d_inode, file,
+                                       range, 0, 0);
+               if (ret > 0)
+                       ret = 0;
                kfree(range);
                break;
        default:
@@ -1809,6 +2054,80 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg)
        return ret;
 }
 
+static long btrfs_ioctl_fs_info(struct btrfs_root *root, void __user *arg)
+{
+       struct btrfs_ioctl_fs_info_args *fi_args;
+       struct btrfs_device *device;
+       struct btrfs_device *next;
+       struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
+       int ret = 0;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       fi_args = kzalloc(sizeof(*fi_args), GFP_KERNEL);
+       if (!fi_args)
+               return -ENOMEM;
+
+       fi_args->num_devices = fs_devices->num_devices;
+       memcpy(&fi_args->fsid, root->fs_info->fsid, sizeof(fi_args->fsid));
+
+       mutex_lock(&fs_devices->device_list_mutex);
+       list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
+               if (device->devid > fi_args->max_id)
+                       fi_args->max_id = device->devid;
+       }
+       mutex_unlock(&fs_devices->device_list_mutex);
+
+       if (copy_to_user(arg, fi_args, sizeof(*fi_args)))
+               ret = -EFAULT;
+
+       kfree(fi_args);
+       return ret;
+}
+
+static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg)
+{
+       struct btrfs_ioctl_dev_info_args *di_args;
+       struct btrfs_device *dev;
+       struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
+       int ret = 0;
+       char *s_uuid = NULL;
+       char empty_uuid[BTRFS_UUID_SIZE] = {0};
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       di_args = memdup_user(arg, sizeof(*di_args));
+       if (IS_ERR(di_args))
+               return PTR_ERR(di_args);
+
+       if (memcmp(empty_uuid, di_args->uuid, BTRFS_UUID_SIZE) != 0)
+               s_uuid = di_args->uuid;
+
+       mutex_lock(&fs_devices->device_list_mutex);
+       dev = btrfs_find_device(root, di_args->devid, s_uuid, NULL);
+       mutex_unlock(&fs_devices->device_list_mutex);
+
+       if (!dev) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       di_args->devid = dev->devid;
+       di_args->bytes_used = dev->bytes_used;
+       di_args->total_bytes = dev->total_bytes;
+       memcpy(di_args->uuid, dev->uuid, sizeof(di_args->uuid));
+       strncpy(di_args->path, dev->name, sizeof(di_args->path));
+
+out:
+       if (ret == 0 && copy_to_user(arg, di_args, sizeof(*di_args)))
+               ret = -EFAULT;
+
+       kfree(di_args);
+       return ret;
+}
+
 static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                                       u64 off, u64 olen, u64 destoff)
 {
@@ -1925,7 +2244,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
        }
 
        /* clone data */
-       key.objectid = src->i_ino;
+       key.objectid = btrfs_ino(src);
        key.type = BTRFS_EXTENT_DATA_KEY;
        key.offset = 0;
 
@@ -1952,7 +2271,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
 
                btrfs_item_key_to_cpu(leaf, &key, slot);
                if (btrfs_key_type(&key) > BTRFS_EXTENT_DATA_KEY ||
-                   key.objectid != src->i_ino)
+                   key.objectid != btrfs_ino(src))
                        break;
 
                if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) {
@@ -1988,14 +2307,14 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                                datal = btrfs_file_extent_ram_bytes(leaf,
                                                                    extent);
                        }
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
 
                        if (key.offset + datal <= off ||
                            key.offset >= off+len)
                                goto next;
 
                        memcpy(&new_key, &key, sizeof(new_key));
-                       new_key.objectid = inode->i_ino;
+                       new_key.objectid = btrfs_ino(inode);
                        if (off <= key.offset)
                                new_key.offset = key.offset + destoff - off;
                        else
@@ -2049,7 +2368,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                                        ret = btrfs_inc_extent_ref(trans, root,
                                                        disko, diskl, 0,
                                                        root->root_key.objectid,
-                                                       inode->i_ino,
+                                                       btrfs_ino(inode),
                                                        new_key.offset - datao);
                                        BUG_ON(ret);
                                }
@@ -2098,7 +2417,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                        }
 
                        btrfs_mark_buffer_dirty(leaf);
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
 
                        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 
@@ -2119,12 +2438,12 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                        btrfs_end_transaction(trans, root);
                }
 next:
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                key.offset++;
        }
        ret = 0;
 out:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        unlock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS);
 out_unlock:
        mutex_unlock(&src->i_mutex);
@@ -2177,12 +2496,10 @@ static long btrfs_ioctl_trans_start(struct file *file)
        if (ret)
                goto out;
 
-       mutex_lock(&root->fs_info->trans_mutex);
-       root->fs_info->open_ioctl_trans++;
-       mutex_unlock(&root->fs_info->trans_mutex);
+       atomic_inc(&root->fs_info->open_ioctl_trans);
 
        ret = -ENOMEM;
-       trans = btrfs_start_ioctl_transaction(root, 0);
+       trans = btrfs_start_ioctl_transaction(root);
        if (IS_ERR(trans))
                goto out_drop;
 
@@ -2190,9 +2507,7 @@ static long btrfs_ioctl_trans_start(struct file *file)
        return 0;
 
 out_drop:
-       mutex_lock(&root->fs_info->trans_mutex);
-       root->fs_info->open_ioctl_trans--;
-       mutex_unlock(&root->fs_info->trans_mutex);
+       atomic_dec(&root->fs_info->open_ioctl_trans);
        mnt_drop_write(file->f_path.mnt);
 out:
        return ret;
@@ -2426,9 +2741,7 @@ long btrfs_ioctl_trans_end(struct file *file)
 
        btrfs_end_transaction(trans, root);
 
-       mutex_lock(&root->fs_info->trans_mutex);
-       root->fs_info->open_ioctl_trans--;
-       mutex_unlock(&root->fs_info->trans_mutex);
+       atomic_dec(&root->fs_info->open_ioctl_trans);
 
        mnt_drop_write(file->f_path.mnt);
        return 0;
@@ -2471,6 +2784,58 @@ static noinline long btrfs_ioctl_wait_sync(struct file *file, void __user *argp)
        return btrfs_wait_for_commit(root, transid);
 }
 
+static long btrfs_ioctl_scrub(struct btrfs_root *root, void __user *arg)
+{
+       int ret;
+       struct btrfs_ioctl_scrub_args *sa;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       sa = memdup_user(arg, sizeof(*sa));
+       if (IS_ERR(sa))
+               return PTR_ERR(sa);
+
+       ret = btrfs_scrub_dev(root, sa->devid, sa->start, sa->end,
+                             &sa->progress, sa->flags & BTRFS_SCRUB_READONLY);
+
+       if (copy_to_user(arg, sa, sizeof(*sa)))
+               ret = -EFAULT;
+
+       kfree(sa);
+       return ret;
+}
+
+static long btrfs_ioctl_scrub_cancel(struct btrfs_root *root, void __user *arg)
+{
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       return btrfs_scrub_cancel(root);
+}
+
+static long btrfs_ioctl_scrub_progress(struct btrfs_root *root,
+                                      void __user *arg)
+{
+       struct btrfs_ioctl_scrub_args *sa;
+       int ret;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       sa = memdup_user(arg, sizeof(*sa));
+       if (IS_ERR(sa))
+               return PTR_ERR(sa);
+
+       ret = btrfs_scrub_progress(root, sa->devid, &sa->progress);
+
+       if (copy_to_user(arg, sa, sizeof(*sa)))
+               ret = -EFAULT;
+
+       kfree(sa);
+       return ret;
+}
+
 long btrfs_ioctl(struct file *file, unsigned int
                cmd, unsigned long arg)
 {
@@ -2510,6 +2875,10 @@ long btrfs_ioctl(struct file *file, unsigned int
                return btrfs_ioctl_add_dev(root, argp);
        case BTRFS_IOC_RM_DEV:
                return btrfs_ioctl_rm_dev(root, argp);
+       case BTRFS_IOC_FS_INFO:
+               return btrfs_ioctl_fs_info(root, argp);
+       case BTRFS_IOC_DEV_INFO:
+               return btrfs_ioctl_dev_info(root, argp);
        case BTRFS_IOC_BALANCE:
                return btrfs_balance(root->fs_info->dev_root);
        case BTRFS_IOC_CLONE:
@@ -2533,6 +2902,12 @@ long btrfs_ioctl(struct file *file, unsigned int
                return btrfs_ioctl_start_sync(file, argp);
        case BTRFS_IOC_WAIT_SYNC:
                return btrfs_ioctl_wait_sync(file, argp);
+       case BTRFS_IOC_SCRUB:
+               return btrfs_ioctl_scrub(root, argp);
+       case BTRFS_IOC_SCRUB_CANCEL:
+               return btrfs_ioctl_scrub_cancel(root, argp);
+       case BTRFS_IOC_SCRUB_PROGRESS:
+               return btrfs_ioctl_scrub_progress(root, argp);
        }
 
        return -ENOTTY;
index 8fb382167b13b55670e6411785f006defccc9d0d..ad1ea789fcb4d281dcd80398bd75bbec2b1e30d9 100644 (file)
@@ -32,6 +32,8 @@ struct btrfs_ioctl_vol_args {
 
 #define BTRFS_SUBVOL_CREATE_ASYNC      (1ULL << 0)
 #define BTRFS_SUBVOL_RDONLY            (1ULL << 1)
+#define BTRFS_FSID_SIZE 16
+#define BTRFS_UUID_SIZE 16
 
 #define BTRFS_SUBVOL_NAME_MAX 4039
 struct btrfs_ioctl_vol_args_v2 {
@@ -42,6 +44,71 @@ struct btrfs_ioctl_vol_args_v2 {
        char name[BTRFS_SUBVOL_NAME_MAX + 1];
 };
 
+/*
+ * structure to report errors and progress to userspace, either as a
+ * result of a finished scrub, a canceled scrub or a progress inquiry
+ */
+struct btrfs_scrub_progress {
+       __u64 data_extents_scrubbed;    /* # of data extents scrubbed */
+       __u64 tree_extents_scrubbed;    /* # of tree extents scrubbed */
+       __u64 data_bytes_scrubbed;      /* # of data bytes scrubbed */
+       __u64 tree_bytes_scrubbed;      /* # of tree bytes scrubbed */
+       __u64 read_errors;              /* # of read errors encountered (EIO) */
+       __u64 csum_errors;              /* # of failed csum checks */
+       __u64 verify_errors;            /* # of occurences, where the metadata
+                                        * of a tree block did not match the
+                                        * expected values, like generation or
+                                        * logical */
+       __u64 no_csum;                  /* # of 4k data block for which no csum
+                                        * is present, probably the result of
+                                        * data written with nodatasum */
+       __u64 csum_discards;            /* # of csum for which no data was found
+                                        * in the extent tree. */
+       __u64 super_errors;             /* # of bad super blocks encountered */
+       __u64 malloc_errors;            /* # of internal kmalloc errors. These
+                                        * will likely cause an incomplete
+                                        * scrub */
+       __u64 uncorrectable_errors;     /* # of errors where either no intact
+                                        * copy was found or the writeback
+                                        * failed */
+       __u64 corrected_errors;         /* # of errors corrected */
+       __u64 last_physical;            /* last physical address scrubbed. In
+                                        * case a scrub was aborted, this can
+                                        * be used to restart the scrub */
+       __u64 unverified_errors;        /* # of occurences where a read for a
+                                        * full (64k) bio failed, but the re-
+                                        * check succeeded for each 4k piece.
+                                        * Intermittent error. */
+};
+
+#define BTRFS_SCRUB_READONLY   1
+struct btrfs_ioctl_scrub_args {
+       __u64 devid;                            /* in */
+       __u64 start;                            /* in */
+       __u64 end;                              /* in */
+       __u64 flags;                            /* in */
+       struct btrfs_scrub_progress progress;   /* out */
+       /* pad to 1k */
+       __u64 unused[(1024-32-sizeof(struct btrfs_scrub_progress))/8];
+};
+
+#define BTRFS_DEVICE_PATH_NAME_MAX 1024
+struct btrfs_ioctl_dev_info_args {
+       __u64 devid;                            /* in/out */
+       __u8 uuid[BTRFS_UUID_SIZE];             /* in/out */
+       __u64 bytes_used;                       /* out */
+       __u64 total_bytes;                      /* out */
+       __u64 unused[379];                      /* pad to 4k */
+       __u8 path[BTRFS_DEVICE_PATH_NAME_MAX];  /* out */
+};
+
+struct btrfs_ioctl_fs_info_args {
+       __u64 max_id;                           /* out */
+       __u64 num_devices;                      /* out */
+       __u8 fsid[BTRFS_FSID_SIZE];             /* out */
+       __u64 reserved[124];                    /* pad to 1k */
+};
+
 #define BTRFS_INO_LOOKUP_PATH_MAX 4080
 struct btrfs_ioctl_ino_lookup_args {
        __u64 treeid;
@@ -114,37 +181,6 @@ struct btrfs_ioctl_clone_range_args {
 #define BTRFS_DEFRAG_RANGE_COMPRESS 1
 #define BTRFS_DEFRAG_RANGE_START_IO 2
 
-struct btrfs_ioctl_defrag_range_args {
-       /* start of the defrag operation */
-       __u64 start;
-
-       /* number of bytes to defrag, use (u64)-1 to say all */
-       __u64 len;
-
-       /*
-        * flags for the operation, which can include turning
-        * on compression for this one defrag
-        */
-       __u64 flags;
-
-       /*
-        * any extent bigger than this will be considered
-        * already defragged.  Use 0 to take the kernel default
-        * Use 1 to say every single extent must be rewritten
-        */
-       __u32 extent_thresh;
-
-       /*
-        * which compression method to use if turning on compression
-        * for this defrag operation.  If unspecified, zlib will
-        * be used
-        */
-       __u32 compress_type;
-
-       /* spare for later */
-       __u32 unused[4];
-};
-
 struct btrfs_ioctl_space_info {
        __u64 flags;
        __u64 total_bytes;
@@ -203,4 +239,13 @@ struct btrfs_ioctl_space_args {
                                   struct btrfs_ioctl_vol_args_v2)
 #define BTRFS_IOC_SUBVOL_GETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 25, __u64)
 #define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64)
+#define BTRFS_IOC_SCRUB _IOWR(BTRFS_IOCTL_MAGIC, 27, \
+                             struct btrfs_ioctl_scrub_args)
+#define BTRFS_IOC_SCRUB_CANCEL _IO(BTRFS_IOCTL_MAGIC, 28)
+#define BTRFS_IOC_SCRUB_PROGRESS _IOWR(BTRFS_IOCTL_MAGIC, 29, \
+                                      struct btrfs_ioctl_scrub_args)
+#define BTRFS_IOC_DEV_INFO _IOWR(BTRFS_IOCTL_MAGIC, 30, \
+                                struct btrfs_ioctl_dev_info_args)
+#define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \
+                              struct btrfs_ioctl_fs_info_args)
 #endif
index 6151f2ea38bb193eaeed1f45bc7f2d1f60c0b1d7..66fa43dc3f0f9ff8b5c67e5330120fd663bf4054 100644 (file)
@@ -185,31 +185,6 @@ sleep:
        return 0;
 }
 
-/*
- * Very quick trylock, this does not spin or schedule.  It returns
- * 1 with the spinlock held if it was able to take the lock, or it
- * returns zero if it was unable to take the lock.
- *
- * After this call, scheduling is not safe without first calling
- * btrfs_set_lock_blocking()
- */
-int btrfs_try_tree_lock(struct extent_buffer *eb)
-{
-       if (spin_trylock(&eb->lock)) {
-               if (test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags)) {
-                       /*
-                        * we've got the spinlock, but the real owner is
-                        * blocking.  Drop the spinlock and return failure
-                        */
-                       spin_unlock(&eb->lock);
-                       return 0;
-               }
-               return 1;
-       }
-       /* someone else has the spinlock giveup */
-       return 0;
-}
-
 int btrfs_tree_unlock(struct extent_buffer *eb)
 {
        /*
index 6c4ce457168cd41cc0b92a58453f5c8f2b2fe2f9..5c33a560a2f100c2454797d122875a76921403ab 100644 (file)
@@ -21,8 +21,6 @@
 
 int btrfs_tree_lock(struct extent_buffer *eb);
 int btrfs_tree_unlock(struct extent_buffer *eb);
-
-int btrfs_try_tree_lock(struct extent_buffer *eb);
 int btrfs_try_spin_lock(struct extent_buffer *eb);
 
 void btrfs_set_lock_blocking(struct extent_buffer *eb);
index a97314cf6bd6ef7ac44aa60a4485261a74e241a7..82d569cb62675c76947dfcc580db4bab8347e917 100644 (file)
 #include "ref-cache.h"
 #include "transaction.h"
 
-/*
- * leaf refs are used to cache the information about which extents
- * a given leaf has references on.  This allows us to process that leaf
- * in btrfs_drop_snapshot without needing to read it back from disk.
- */
-
-/*
- * kmalloc a leaf reference struct and update the counters for the
- * total ref cache size
- */
-struct btrfs_leaf_ref *btrfs_alloc_leaf_ref(struct btrfs_root *root,
-                                           int nr_extents)
-{
-       struct btrfs_leaf_ref *ref;
-       size_t size = btrfs_leaf_ref_size(nr_extents);
-
-       ref = kmalloc(size, GFP_NOFS);
-       if (ref) {
-               spin_lock(&root->fs_info->ref_cache_lock);
-               root->fs_info->total_ref_cache_size += size;
-               spin_unlock(&root->fs_info->ref_cache_lock);
-
-               memset(ref, 0, sizeof(*ref));
-               atomic_set(&ref->usage, 1);
-               INIT_LIST_HEAD(&ref->list);
-       }
-       return ref;
-}
-
-/*
- * free a leaf reference struct and update the counters for the
- * total ref cache size
- */
-void btrfs_free_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
-{
-       if (!ref)
-               return;
-       WARN_ON(atomic_read(&ref->usage) == 0);
-       if (atomic_dec_and_test(&ref->usage)) {
-               size_t size = btrfs_leaf_ref_size(ref->nritems);
-
-               BUG_ON(ref->in_tree);
-               kfree(ref);
-
-               spin_lock(&root->fs_info->ref_cache_lock);
-               root->fs_info->total_ref_cache_size -= size;
-               spin_unlock(&root->fs_info->ref_cache_lock);
-       }
-}
-
 static struct rb_node *tree_insert(struct rb_root *root, u64 bytenr,
                                   struct rb_node *node)
 {
@@ -116,117 +66,3 @@ static struct rb_node *tree_search(struct rb_root *root, u64 bytenr)
        }
        return NULL;
 }
-
-int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen,
-                          int shared)
-{
-       struct btrfs_leaf_ref *ref = NULL;
-       struct btrfs_leaf_ref_tree *tree = root->ref_tree;
-
-       if (shared)
-               tree = &root->fs_info->shared_ref_tree;
-       if (!tree)
-               return 0;
-
-       spin_lock(&tree->lock);
-       while (!list_empty(&tree->list)) {
-               ref = list_entry(tree->list.next, struct btrfs_leaf_ref, list);
-               BUG_ON(ref->tree != tree);
-               if (ref->root_gen > max_root_gen)
-                       break;
-               if (!xchg(&ref->in_tree, 0)) {
-                       cond_resched_lock(&tree->lock);
-                       continue;
-               }
-
-               rb_erase(&ref->rb_node, &tree->root);
-               list_del_init(&ref->list);
-
-               spin_unlock(&tree->lock);
-               btrfs_free_leaf_ref(root, ref);
-               cond_resched();
-               spin_lock(&tree->lock);
-       }
-       spin_unlock(&tree->lock);
-       return 0;
-}
-
-/*
- * find the leaf ref for a given extent.  This returns the ref struct with
- * a usage reference incremented
- */
-struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root,
-                                            u64 bytenr)
-{
-       struct rb_node *rb;
-       struct btrfs_leaf_ref *ref = NULL;
-       struct btrfs_leaf_ref_tree *tree = root->ref_tree;
-again:
-       if (tree) {
-               spin_lock(&tree->lock);
-               rb = tree_search(&tree->root, bytenr);
-               if (rb)
-                       ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node);
-               if (ref)
-                       atomic_inc(&ref->usage);
-               spin_unlock(&tree->lock);
-               if (ref)
-                       return ref;
-       }
-       if (tree != &root->fs_info->shared_ref_tree) {
-               tree = &root->fs_info->shared_ref_tree;
-               goto again;
-       }
-       return NULL;
-}
-
-/*
- * add a fully filled in leaf ref struct
- * remove all the refs older than a given root generation
- */
-int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref,
-                      int shared)
-{
-       int ret = 0;
-       struct rb_node *rb;
-       struct btrfs_leaf_ref_tree *tree = root->ref_tree;
-
-       if (shared)
-               tree = &root->fs_info->shared_ref_tree;
-
-       spin_lock(&tree->lock);
-       rb = tree_insert(&tree->root, ref->bytenr, &ref->rb_node);
-       if (rb) {
-               ret = -EEXIST;
-       } else {
-               atomic_inc(&ref->usage);
-               ref->tree = tree;
-               ref->in_tree = 1;
-               list_add_tail(&ref->list, &tree->list);
-       }
-       spin_unlock(&tree->lock);
-       return ret;
-}
-
-/*
- * remove a single leaf ref from the tree.  This drops the ref held by the tree
- * only
- */
-int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
-{
-       struct btrfs_leaf_ref_tree *tree;
-
-       if (!xchg(&ref->in_tree, 0))
-               return 0;
-
-       tree = ref->tree;
-       spin_lock(&tree->lock);
-
-       rb_erase(&ref->rb_node, &tree->root);
-       list_del_init(&ref->list);
-
-       spin_unlock(&tree->lock);
-
-       btrfs_free_leaf_ref(root, ref);
-       return 0;
-}
index e2a55cb2072bda576d6f30b6079b30b2e497d8e7..24f7001f6387d501f07ceb6a605074474b0a463d 100644 (file)
@@ -49,28 +49,4 @@ static inline size_t btrfs_leaf_ref_size(int nr_extents)
        return sizeof(struct btrfs_leaf_ref) +
               sizeof(struct btrfs_extent_info) * nr_extents;
 }
-
-static inline void btrfs_leaf_ref_tree_init(struct btrfs_leaf_ref_tree *tree)
-{
-       tree->root = RB_ROOT;
-       INIT_LIST_HEAD(&tree->list);
-       spin_lock_init(&tree->lock);
-}
-
-static inline int btrfs_leaf_ref_tree_empty(struct btrfs_leaf_ref_tree *tree)
-{
-       return RB_EMPTY_ROOT(&tree->root);
-}
-
-void btrfs_leaf_ref_tree_init(struct btrfs_leaf_ref_tree *tree);
-struct btrfs_leaf_ref *btrfs_alloc_leaf_ref(struct btrfs_root *root,
-                                           int nr_extents);
-void btrfs_free_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref);
-struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root,
-                                            u64 bytenr);
-int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref,
-                      int shared);
-int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen,
-                          int shared);
-int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref);
 #endif
index f340f7c99d09d2126ac20a40b6285fa031f84a63..5e0a3dc79a453f3930e9c749c1cf08c63e5c7c6a 100644 (file)
@@ -30,6 +30,7 @@
 #include "btrfs_inode.h"
 #include "async-thread.h"
 #include "free-space-cache.h"
+#include "inode-map.h"
 
 /*
  * backref_node, mapping_node and tree_block start with this
@@ -507,6 +508,7 @@ static int update_backref_cache(struct btrfs_trans_handle *trans,
        return 1;
 }
 
+
 static int should_ignore_root(struct btrfs_root *root)
 {
        struct btrfs_root *reloc_root;
@@ -529,7 +531,6 @@ static int should_ignore_root(struct btrfs_root *root)
         */
        return 1;
 }
-
 /*
  * find reloc tree by address of tree root
  */
@@ -676,6 +677,8 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
                err = -ENOMEM;
                goto out;
        }
+       path1->reada = 1;
+       path2->reada = 2;
 
        node = alloc_backref_node(cache);
        if (!node) {
@@ -961,7 +964,7 @@ again:
                        lower = upper;
                        upper = NULL;
                }
-               btrfs_release_path(root, path2);
+               btrfs_release_path(path2);
 next:
                if (ptr < end) {
                        ptr += btrfs_extent_inline_ref_size(key.type);
@@ -974,7 +977,7 @@ next:
                if (ptr >= end)
                        path1->slots[0]++;
        }
-       btrfs_release_path(rc->extent_root, path1);
+       btrfs_release_path(path1);
 
        cur->checked = 1;
        WARN_ON(exist);
@@ -1365,7 +1368,7 @@ int btrfs_update_reloc_root(struct btrfs_trans_handle *trans,
        int ret;
 
        if (!root->reloc_root)
-               return 0;
+               goto out;
 
        reloc_root = root->reloc_root;
        root_item = &reloc_root->root_item;
@@ -1387,6 +1390,8 @@ int btrfs_update_reloc_root(struct btrfs_trans_handle *trans,
        ret = btrfs_update_root(trans, root->fs_info->tree_root,
                                &reloc_root->root_key, root_item);
        BUG_ON(ret);
+
+out:
        return 0;
 }
 
@@ -1409,9 +1414,9 @@ again:
                prev = node;
                entry = rb_entry(node, struct btrfs_inode, rb_node);
 
-               if (objectid < entry->vfs_inode.i_ino)
+               if (objectid < btrfs_ino(&entry->vfs_inode))
                        node = node->rb_left;
-               else if (objectid > entry->vfs_inode.i_ino)
+               else if (objectid > btrfs_ino(&entry->vfs_inode))
                        node = node->rb_right;
                else
                        break;
@@ -1419,7 +1424,7 @@ again:
        if (!node) {
                while (prev) {
                        entry = rb_entry(prev, struct btrfs_inode, rb_node);
-                       if (objectid <= entry->vfs_inode.i_ino) {
+                       if (objectid <= btrfs_ino(&entry->vfs_inode)) {
                                node = prev;
                                break;
                        }
@@ -1434,7 +1439,7 @@ again:
                        return inode;
                }
 
-               objectid = entry->vfs_inode.i_ino + 1;
+               objectid = btrfs_ino(&entry->vfs_inode) + 1;
                if (cond_resched_lock(&root->inode_lock))
                        goto again;
 
@@ -1470,7 +1475,7 @@ static int get_new_location(struct inode *reloc_inode, u64 *new_bytenr,
                return -ENOMEM;
 
        bytenr -= BTRFS_I(reloc_inode)->index_cnt;
-       ret = btrfs_lookup_file_extent(NULL, root, path, reloc_inode->i_ino,
+       ret = btrfs_lookup_file_extent(NULL, root, path, btrfs_ino(reloc_inode),
                                       bytenr, 0);
        if (ret < 0)
                goto out;
@@ -1558,11 +1563,11 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
                        if (first) {
                                inode = find_next_inode(root, key.objectid);
                                first = 0;
-                       } else if (inode && inode->i_ino < key.objectid) {
+                       } else if (inode && btrfs_ino(inode) < key.objectid) {
                                btrfs_add_delayed_iput(inode);
                                inode = find_next_inode(root, key.objectid);
                        }
-                       if (inode && inode->i_ino == key.objectid) {
+                       if (inode && btrfs_ino(inode) == key.objectid) {
                                end = key.offset +
                                      btrfs_file_extent_num_bytes(leaf, fi);
                                WARN_ON(!IS_ALIGNED(key.offset,
@@ -1749,7 +1754,7 @@ again:
 
                btrfs_node_key_to_cpu(path->nodes[level], &key,
                                      path->slots[level]);
-               btrfs_release_path(src, path);
+               btrfs_release_path(path);
 
                path->lowest_level = level;
                ret = btrfs_search_slot(trans, src, &key, path, 0, 1);
@@ -1893,6 +1898,7 @@ static int invalidate_extent_cache(struct btrfs_root *root,
        struct inode *inode = NULL;
        u64 objectid;
        u64 start, end;
+       u64 ino;
 
        objectid = min_key->objectid;
        while (1) {
@@ -1905,17 +1911,18 @@ static int invalidate_extent_cache(struct btrfs_root *root,
                inode = find_next_inode(root, objectid);
                if (!inode)
                        break;
+               ino = btrfs_ino(inode);
 
-               if (inode->i_ino > max_key->objectid) {
+               if (ino > max_key->objectid) {
                        iput(inode);
                        break;
                }
 
-               objectid = inode->i_ino + 1;
+               objectid = ino + 1;
                if (!S_ISREG(inode->i_mode))
                        continue;
 
-               if (unlikely(min_key->objectid == inode->i_ino)) {
+               if (unlikely(min_key->objectid == ino)) {
                        if (min_key->type > BTRFS_EXTENT_DATA_KEY)
                                continue;
                        if (min_key->type < BTRFS_EXTENT_DATA_KEY)
@@ -1928,7 +1935,7 @@ static int invalidate_extent_cache(struct btrfs_root *root,
                        start = 0;
                }
 
-               if (unlikely(max_key->objectid == inode->i_ino)) {
+               if (unlikely(max_key->objectid == ino)) {
                        if (max_key->type < BTRFS_EXTENT_DATA_KEY)
                                continue;
                        if (max_key->type > BTRFS_EXTENT_DATA_KEY) {
@@ -1996,6 +2003,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
+       path->reada = 1;
 
        reloc_root = root->reloc_root;
        root_item = &reloc_root->root_item;
@@ -2136,10 +2144,11 @@ int prepare_to_merge(struct reloc_control *rc, int err)
        u64 num_bytes = 0;
        int ret;
 
-       mutex_lock(&root->fs_info->trans_mutex);
+       mutex_lock(&root->fs_info->reloc_mutex);
        rc->merging_rsv_size += root->nodesize * (BTRFS_MAX_LEVEL - 1) * 2;
        rc->merging_rsv_size += rc->nodes_relocated * 2;
-       mutex_unlock(&root->fs_info->trans_mutex);
+       mutex_unlock(&root->fs_info->reloc_mutex);
+
 again:
        if (!err) {
                num_bytes = rc->merging_rsv_size;
@@ -2149,7 +2158,7 @@ again:
                        err = ret;
        }
 
-       trans = btrfs_join_transaction(rc->extent_root, 1);
+       trans = btrfs_join_transaction(rc->extent_root);
        if (IS_ERR(trans)) {
                if (!err)
                        btrfs_block_rsv_release(rc->extent_root,
@@ -2208,9 +2217,16 @@ int merge_reloc_roots(struct reloc_control *rc)
        int ret;
 again:
        root = rc->extent_root;
-       mutex_lock(&root->fs_info->trans_mutex);
+
+       /*
+        * this serializes us with btrfs_record_root_in_transaction,
+        * we have to make sure nobody is in the middle of
+        * adding their roots to the list while we are
+        * doing this splice
+        */
+       mutex_lock(&root->fs_info->reloc_mutex);
        list_splice_init(&rc->reloc_roots, &reloc_roots);
-       mutex_unlock(&root->fs_info->trans_mutex);
+       mutex_unlock(&root->fs_info->reloc_mutex);
 
        while (!list_empty(&reloc_roots)) {
                found = 1;
@@ -2496,7 +2512,7 @@ static int do_relocation(struct btrfs_trans_handle *trans,
                        path->locks[upper->level] = 0;
 
                        slot = path->slots[upper->level];
-                       btrfs_release_path(NULL, path);
+                       btrfs_release_path(path);
                } else {
                        ret = btrfs_bin_search(upper->eb, key, upper->level,
                                               &slot);
@@ -2737,7 +2753,7 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans,
                } else {
                        path->lowest_level = node->level;
                        ret = btrfs_search_slot(trans, root, key, path, 0, 1);
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        if (ret > 0)
                                ret = 0;
                }
@@ -2870,7 +2886,7 @@ int setup_extent_mapping(struct inode *inode, u64 start, u64 end,
        struct extent_map *em;
        int ret = 0;
 
-       em = alloc_extent_map(GFP_NOFS);
+       em = alloc_extent_map();
        if (!em)
                return -ENOMEM;
 
@@ -3119,7 +3135,7 @@ static int add_tree_block(struct reloc_control *rc,
 #endif
        }
 
-       btrfs_release_path(rc->extent_root, path);
+       btrfs_release_path(path);
 
        BUG_ON(level == -1);
 
@@ -3220,7 +3236,7 @@ static int delete_block_group_cache(struct btrfs_fs_info *fs_info,
        key.offset = 0;
 
        inode = btrfs_iget(fs_info->sb, &key, root, NULL);
-       if (!inode || IS_ERR(inode) || is_bad_inode(inode)) {
+       if (IS_ERR_OR_NULL(inode) || is_bad_inode(inode)) {
                if (inode && !IS_ERR(inode))
                        iput(inode);
                return -ENOENT;
@@ -3233,7 +3249,7 @@ truncate:
                goto out;
        }
 
-       trans = btrfs_join_transaction(root, 0);
+       trans = btrfs_join_transaction(root);
        if (IS_ERR(trans)) {
                btrfs_free_path(path);
                ret = PTR_ERR(trans);
@@ -3297,6 +3313,7 @@ static int find_data_references(struct reloc_control *rc,
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
+       path->reada = 1;
 
        root = read_fs_root(rc->extent_root->fs_info, ref_root);
        if (IS_ERR(root)) {
@@ -3505,7 +3522,7 @@ int add_data_references(struct reloc_control *rc,
                }
                path->slots[0]++;
        }
-       btrfs_release_path(rc->extent_root, path);
+       btrfs_release_path(path);
        if (err)
                free_block_list(blocks);
        return err;
@@ -3568,7 +3585,7 @@ next:
                                            EXTENT_DIRTY);
 
                if (ret == 0 && start <= key.objectid) {
-                       btrfs_release_path(rc->extent_root, path);
+                       btrfs_release_path(path);
                        rc->search_start = end + 1;
                } else {
                        rc->search_start = key.objectid + key.offset;
@@ -3576,24 +3593,26 @@ next:
                        return 0;
                }
        }
-       btrfs_release_path(rc->extent_root, path);
+       btrfs_release_path(path);
        return ret;
 }
 
 static void set_reloc_control(struct reloc_control *rc)
 {
        struct btrfs_fs_info *fs_info = rc->extent_root->fs_info;
-       mutex_lock(&fs_info->trans_mutex);
+
+       mutex_lock(&fs_info->reloc_mutex);
        fs_info->reloc_ctl = rc;
-       mutex_unlock(&fs_info->trans_mutex);
+       mutex_unlock(&fs_info->reloc_mutex);
 }
 
 static void unset_reloc_control(struct reloc_control *rc)
 {
        struct btrfs_fs_info *fs_info = rc->extent_root->fs_info;
-       mutex_lock(&fs_info->trans_mutex);
+
+       mutex_lock(&fs_info->reloc_mutex);
        fs_info->reloc_ctl = NULL;
-       mutex_unlock(&fs_info->trans_mutex);
+       mutex_unlock(&fs_info->reloc_mutex);
 }
 
 static int check_extent_flags(u64 flags)
@@ -3642,7 +3661,7 @@ int prepare_to_relocate(struct reloc_control *rc)
        rc->create_reloc_tree = 1;
        set_reloc_control(rc);
 
-       trans = btrfs_join_transaction(rc->extent_root, 1);
+       trans = btrfs_join_transaction(rc->extent_root);
        BUG_ON(IS_ERR(trans));
        btrfs_commit_transaction(trans, rc->extent_root);
        return 0;
@@ -3665,6 +3684,7 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
+       path->reada = 1;
 
        ret = prepare_to_relocate(rc);
        if (ret) {
@@ -3713,7 +3733,7 @@ restart:
                                flags = BTRFS_EXTENT_FLAG_DATA;
 
                        if (path_change) {
-                               btrfs_release_path(rc->extent_root, path);
+                               btrfs_release_path(path);
 
                                path->search_commit_root = 1;
                                path->skip_locking = 1;
@@ -3736,7 +3756,7 @@ restart:
                           (flags & BTRFS_EXTENT_FLAG_DATA)) {
                        ret = add_data_references(rc, &key, path, &blocks);
                } else {
-                       btrfs_release_path(rc->extent_root, path);
+                       btrfs_release_path(path);
                        ret = 0;
                }
                if (ret < 0) {
@@ -3799,7 +3819,7 @@ restart:
                }
        }
 
-       btrfs_release_path(rc->extent_root, path);
+       btrfs_release_path(path);
        clear_extent_bits(&rc->processed_blocks, 0, (u64)-1, EXTENT_DIRTY,
                          GFP_NOFS);
 
@@ -3831,7 +3851,7 @@ restart:
        btrfs_block_rsv_release(rc->extent_root, rc->block_rsv, (u64)-1);
 
        /* get rid of pinned extents */
-       trans = btrfs_join_transaction(rc->extent_root, 1);
+       trans = btrfs_join_transaction(rc->extent_root);
        if (IS_ERR(trans))
                err = PTR_ERR(trans);
        else
@@ -3867,7 +3887,7 @@ static int __insert_orphan_inode(struct btrfs_trans_handle *trans,
        btrfs_set_inode_flags(leaf, item, BTRFS_INODE_NOCOMPRESS |
                                          BTRFS_INODE_PREALLOC);
        btrfs_mark_buffer_dirty(leaf);
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 out:
        btrfs_free_path(path);
        return ret;
@@ -3897,7 +3917,7 @@ struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info,
        if (IS_ERR(trans))
                return ERR_CAST(trans);
 
-       err = btrfs_find_free_objectid(trans, root, objectid, &objectid);
+       err = btrfs_find_free_objectid(root, &objectid);
        if (err)
                goto out;
 
@@ -3935,7 +3955,7 @@ static struct reloc_control *alloc_reloc_control(void)
        INIT_LIST_HEAD(&rc->reloc_roots);
        backref_cache_init(&rc->backref_cache);
        mapping_tree_init(&rc->reloc_root_tree);
-       extent_io_tree_init(&rc->processed_blocks, NULL, GFP_NOFS);
+       extent_io_tree_init(&rc->processed_blocks, NULL);
        return rc;
 }
 
@@ -4090,6 +4110,7 @@ int btrfs_recover_relocation(struct btrfs_root *root)
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
+       path->reada = -1;
 
        key.objectid = BTRFS_TREE_RELOC_OBJECTID;
        key.type = BTRFS_ROOT_ITEM_KEY;
@@ -4109,7 +4130,7 @@ int btrfs_recover_relocation(struct btrfs_root *root)
                }
                leaf = path->nodes[0];
                btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
-               btrfs_release_path(root->fs_info->tree_root, path);
+               btrfs_release_path(path);
 
                if (key.objectid != BTRFS_TREE_RELOC_OBJECTID ||
                    key.type != BTRFS_ROOT_ITEM_KEY)
@@ -4141,7 +4162,7 @@ int btrfs_recover_relocation(struct btrfs_root *root)
 
                key.offset--;
        }
-       btrfs_release_path(root->fs_info->tree_root, path);
+       btrfs_release_path(path);
 
        if (list_empty(&reloc_roots))
                goto out;
@@ -4156,7 +4177,7 @@ int btrfs_recover_relocation(struct btrfs_root *root)
 
        set_reloc_control(rc);
 
-       trans = btrfs_join_transaction(rc->extent_root, 1);
+       trans = btrfs_join_transaction(rc->extent_root);
        if (IS_ERR(trans)) {
                unset_reloc_control(rc);
                err = PTR_ERR(trans);
@@ -4190,7 +4211,7 @@ int btrfs_recover_relocation(struct btrfs_root *root)
 
        unset_reloc_control(rc);
 
-       trans = btrfs_join_transaction(rc->extent_root, 1);
+       trans = btrfs_join_transaction(rc->extent_root);
        if (IS_ERR(trans))
                err = PTR_ERR(trans);
        else
@@ -4242,7 +4263,7 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len)
 
        disk_bytenr = file_pos + BTRFS_I(inode)->index_cnt;
        ret = btrfs_lookup_csums_range(root->fs_info->csum_root, disk_bytenr,
-                                      disk_bytenr + len - 1, &list);
+                                      disk_bytenr + len - 1, &list, 0);
 
        while (!list_empty(&list)) {
                sums = list_entry(list.next, struct btrfs_ordered_sum, list);
index 6928bff62daa8370b4d9efce397fac35208c9611..ebe45443de064471fba64ae4e176b2f7a1b66f93 100644 (file)
 #include "disk-io.h"
 #include "print-tree.h"
 
-/*
- *  search forward for a root, starting with objectid 'search_start'
- *  if a root key is found, the objectid we find is filled into 'found_objectid'
- *  and 0 is returned.  < 0 is returned on error, 1 if there is nothing
- *  left in the tree.
- */
-int btrfs_search_root(struct btrfs_root *root, u64 search_start,
-                     u64 *found_objectid)
-{
-       struct btrfs_path *path;
-       struct btrfs_key search_key;
-       int ret;
-
-       root = root->fs_info->tree_root;
-       search_key.objectid = search_start;
-       search_key.type = (u8)-1;
-       search_key.offset = (u64)-1;
-
-       path = btrfs_alloc_path();
-       BUG_ON(!path);
-again:
-       ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
-       if (ret < 0)
-               goto out;
-       if (ret == 0) {
-               ret = 1;
-               goto out;
-       }
-       if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
-               ret = btrfs_next_leaf(root, path);
-               if (ret)
-                       goto out;
-       }
-       btrfs_item_key_to_cpu(path->nodes[0], &search_key, path->slots[0]);
-       if (search_key.type != BTRFS_ROOT_ITEM_KEY) {
-               search_key.offset++;
-               btrfs_release_path(root, path);
-               goto again;
-       }
-       ret = 0;
-       *found_objectid = search_key.objectid;
-
-out:
-       btrfs_free_path(path);
-       return ret;
-}
-
 /*
  * lookup the root with the highest offset for a given objectid.  The key we do
  * find is copied into 'key'.  If we find something return 0, otherwise 1, < 0
@@ -230,7 +183,7 @@ again:
 
                memcpy(&found_key, &key, sizeof(key));
                key.offset++;
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                dead_root =
                        btrfs_read_fs_root_no_radix(root->fs_info->tree_root,
                                                    &found_key);
@@ -292,7 +245,7 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
                }
 
                btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
-               btrfs_release_path(tree_root, path);
+               btrfs_release_path(path);
 
                if (key.objectid != BTRFS_ORPHAN_OBJECTID ||
                    key.type != BTRFS_ORPHAN_ITEM_KEY)
@@ -385,18 +338,22 @@ again:
                *sequence = btrfs_root_ref_sequence(leaf, ref);
 
                ret = btrfs_del_item(trans, tree_root, path);
-               BUG_ON(ret);
+               if (ret) {
+                       err = ret;
+                       goto out;
+               }
        } else
                err = -ENOENT;
 
        if (key.type == BTRFS_ROOT_BACKREF_KEY) {
-               btrfs_release_path(tree_root, path);
+               btrfs_release_path(path);
                key.objectid = ref_id;
                key.type = BTRFS_ROOT_REF_KEY;
                key.offset = root_id;
                goto again;
        }
 
+out:
        btrfs_free_path(path);
        return err;
 }
@@ -463,7 +420,7 @@ again:
        btrfs_mark_buffer_dirty(leaf);
 
        if (key.type == BTRFS_ROOT_BACKREF_KEY) {
-               btrfs_release_path(tree_root, path);
+               btrfs_release_path(path);
                key.objectid = ref_id;
                key.type = BTRFS_ROOT_REF_KEY;
                key.offset = root_id;
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
new file mode 100644 (file)
index 0000000..a8d03d5
--- /dev/null
@@ -0,0 +1,1395 @@
+/*
+ * Copyright (C) 2011 STRATO.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 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 021110-1307, USA.
+ */
+
+#include <linux/blkdev.h>
+#include "ctree.h"
+#include "volumes.h"
+#include "disk-io.h"
+#include "ordered-data.h"
+
+/*
+ * This is only the first step towards a full-features scrub. It reads all
+ * extent and super block and verifies the checksums. In case a bad checksum
+ * is found or the extent cannot be read, good data will be written back if
+ * any can be found.
+ *
+ * Future enhancements:
+ *  - To enhance the performance, better read-ahead strategies for the
+ *    extent-tree can be employed.
+ *  - In case an unrepairable extent is encountered, track which files are
+ *    affected and report them
+ *  - In case of a read error on files with nodatasum, map the file and read
+ *    the extent to trigger a writeback of the good copy
+ *  - track and record media errors, throw out bad devices
+ *  - add a mode to also read unallocated space
+ *  - make the prefetch cancellable
+ */
+
+struct scrub_bio;
+struct scrub_page;
+struct scrub_dev;
+static void scrub_bio_end_io(struct bio *bio, int err);
+static void scrub_checksum(struct btrfs_work *work);
+static int scrub_checksum_data(struct scrub_dev *sdev,
+                              struct scrub_page *spag, void *buffer);
+static int scrub_checksum_tree_block(struct scrub_dev *sdev,
+                                    struct scrub_page *spag, u64 logical,
+                                    void *buffer);
+static int scrub_checksum_super(struct scrub_bio *sbio, void *buffer);
+static int scrub_fixup_check(struct scrub_bio *sbio, int ix);
+static void scrub_fixup_end_io(struct bio *bio, int err);
+static int scrub_fixup_io(int rw, struct block_device *bdev, sector_t sector,
+                         struct page *page);
+static void scrub_fixup(struct scrub_bio *sbio, int ix);
+
+#define SCRUB_PAGES_PER_BIO    16      /* 64k per bio */
+#define SCRUB_BIOS_PER_DEV     16      /* 1 MB per device in flight */
+
+struct scrub_page {
+       u64                     flags;  /* extent flags */
+       u64                     generation;
+       u64                     mirror_num;
+       int                     have_csum;
+       u8                      csum[BTRFS_CSUM_SIZE];
+};
+
+struct scrub_bio {
+       int                     index;
+       struct scrub_dev        *sdev;
+       struct bio              *bio;
+       int                     err;
+       u64                     logical;
+       u64                     physical;
+       struct scrub_page       spag[SCRUB_PAGES_PER_BIO];
+       u64                     count;
+       int                     next_free;
+       struct btrfs_work       work;
+};
+
+struct scrub_dev {
+       struct scrub_bio        *bios[SCRUB_BIOS_PER_DEV];
+       struct btrfs_device     *dev;
+       int                     first_free;
+       int                     curr;
+       atomic_t                in_flight;
+       spinlock_t              list_lock;
+       wait_queue_head_t       list_wait;
+       u16                     csum_size;
+       struct list_head        csum_list;
+       atomic_t                cancel_req;
+       int                     readonly;
+       /*
+        * statistics
+        */
+       struct btrfs_scrub_progress stat;
+       spinlock_t              stat_lock;
+};
+
+static void scrub_free_csums(struct scrub_dev *sdev)
+{
+       while (!list_empty(&sdev->csum_list)) {
+               struct btrfs_ordered_sum *sum;
+               sum = list_first_entry(&sdev->csum_list,
+                                      struct btrfs_ordered_sum, list);
+               list_del(&sum->list);
+               kfree(sum);
+       }
+}
+
+static void scrub_free_bio(struct bio *bio)
+{
+       int i;
+       struct page *last_page = NULL;
+
+       if (!bio)
+               return;
+
+       for (i = 0; i < bio->bi_vcnt; ++i) {
+               if (bio->bi_io_vec[i].bv_page == last_page)
+                       continue;
+               last_page = bio->bi_io_vec[i].bv_page;
+               __free_page(last_page);
+       }
+       bio_put(bio);
+}
+
+static noinline_for_stack void scrub_free_dev(struct scrub_dev *sdev)
+{
+       int i;
+
+       if (!sdev)
+               return;
+
+       for (i = 0; i < SCRUB_BIOS_PER_DEV; ++i) {
+               struct scrub_bio *sbio = sdev->bios[i];
+
+               if (!sbio)
+                       break;
+
+               scrub_free_bio(sbio->bio);
+               kfree(sbio);
+       }
+
+       scrub_free_csums(sdev);
+       kfree(sdev);
+}
+
+static noinline_for_stack
+struct scrub_dev *scrub_setup_dev(struct btrfs_device *dev)
+{
+       struct scrub_dev *sdev;
+       int             i;
+       struct btrfs_fs_info *fs_info = dev->dev_root->fs_info;
+
+       sdev = kzalloc(sizeof(*sdev), GFP_NOFS);
+       if (!sdev)
+               goto nomem;
+       sdev->dev = dev;
+       for (i = 0; i < SCRUB_BIOS_PER_DEV; ++i) {
+               struct scrub_bio *sbio;
+
+               sbio = kzalloc(sizeof(*sbio), GFP_NOFS);
+               if (!sbio)
+                       goto nomem;
+               sdev->bios[i] = sbio;
+
+               sbio->index = i;
+               sbio->sdev = sdev;
+               sbio->count = 0;
+               sbio->work.func = scrub_checksum;
+
+               if (i != SCRUB_BIOS_PER_DEV-1)
+                       sdev->bios[i]->next_free = i + 1;
+                else
+                       sdev->bios[i]->next_free = -1;
+       }
+       sdev->first_free = 0;
+       sdev->curr = -1;
+       atomic_set(&sdev->in_flight, 0);
+       atomic_set(&sdev->cancel_req, 0);
+       sdev->csum_size = btrfs_super_csum_size(&fs_info->super_copy);
+       INIT_LIST_HEAD(&sdev->csum_list);
+
+       spin_lock_init(&sdev->list_lock);
+       spin_lock_init(&sdev->stat_lock);
+       init_waitqueue_head(&sdev->list_wait);
+       return sdev;
+
+nomem:
+       scrub_free_dev(sdev);
+       return ERR_PTR(-ENOMEM);
+}
+
+/*
+ * scrub_recheck_error gets called when either verification of the page
+ * failed or the bio failed to read, e.g. with EIO. In the latter case,
+ * recheck_error gets called for every page in the bio, even though only
+ * one may be bad
+ */
+static void scrub_recheck_error(struct scrub_bio *sbio, int ix)
+{
+       if (sbio->err) {
+               if (scrub_fixup_io(READ, sbio->sdev->dev->bdev,
+                                  (sbio->physical + ix * PAGE_SIZE) >> 9,
+                                  sbio->bio->bi_io_vec[ix].bv_page) == 0) {
+                       if (scrub_fixup_check(sbio, ix) == 0)
+                               return;
+               }
+       }
+
+       scrub_fixup(sbio, ix);
+}
+
+static int scrub_fixup_check(struct scrub_bio *sbio, int ix)
+{
+       int ret = 1;
+       struct page *page;
+       void *buffer;
+       u64 flags = sbio->spag[ix].flags;
+
+       page = sbio->bio->bi_io_vec[ix].bv_page;
+       buffer = kmap_atomic(page, KM_USER0);
+       if (flags & BTRFS_EXTENT_FLAG_DATA) {
+               ret = scrub_checksum_data(sbio->sdev,
+                                         sbio->spag + ix, buffer);
+       } else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
+               ret = scrub_checksum_tree_block(sbio->sdev,
+                                               sbio->spag + ix,
+                                               sbio->logical + ix * PAGE_SIZE,
+                                               buffer);
+       } else {
+               WARN_ON(1);
+       }
+       kunmap_atomic(buffer, KM_USER0);
+
+       return ret;
+}
+
+static void scrub_fixup_end_io(struct bio *bio, int err)
+{
+       complete((struct completion *)bio->bi_private);
+}
+
+static void scrub_fixup(struct scrub_bio *sbio, int ix)
+{
+       struct scrub_dev *sdev = sbio->sdev;
+       struct btrfs_fs_info *fs_info = sdev->dev->dev_root->fs_info;
+       struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
+       struct btrfs_multi_bio *multi = NULL;
+       u64 logical = sbio->logical + ix * PAGE_SIZE;
+       u64 length;
+       int i;
+       int ret;
+       DECLARE_COMPLETION_ONSTACK(complete);
+
+       if ((sbio->spag[ix].flags & BTRFS_EXTENT_FLAG_DATA) &&
+           (sbio->spag[ix].have_csum == 0)) {
+               /*
+                * nodatasum, don't try to fix anything
+                * FIXME: we can do better, open the inode and trigger a
+                * writeback
+                */
+               goto uncorrectable;
+       }
+
+       length = PAGE_SIZE;
+       ret = btrfs_map_block(map_tree, REQ_WRITE, logical, &length,
+                             &multi, 0);
+       if (ret || !multi || length < PAGE_SIZE) {
+               printk(KERN_ERR
+                      "scrub_fixup: btrfs_map_block failed us for %llu\n",
+                      (unsigned long long)logical);
+               WARN_ON(1);
+               return;
+       }
+
+       if (multi->num_stripes == 1)
+               /* there aren't any replicas */
+               goto uncorrectable;
+
+       /*
+        * first find a good copy
+        */
+       for (i = 0; i < multi->num_stripes; ++i) {
+               if (i == sbio->spag[ix].mirror_num)
+                       continue;
+
+               if (scrub_fixup_io(READ, multi->stripes[i].dev->bdev,
+                                  multi->stripes[i].physical >> 9,
+                                  sbio->bio->bi_io_vec[ix].bv_page)) {
+                       /* I/O-error, this is not a good copy */
+                       continue;
+               }
+
+               if (scrub_fixup_check(sbio, ix) == 0)
+                       break;
+       }
+       if (i == multi->num_stripes)
+               goto uncorrectable;
+
+       if (!sdev->readonly) {
+               /*
+                * bi_io_vec[ix].bv_page now contains good data, write it back
+                */
+               if (scrub_fixup_io(WRITE, sdev->dev->bdev,
+                                  (sbio->physical + ix * PAGE_SIZE) >> 9,
+                                  sbio->bio->bi_io_vec[ix].bv_page)) {
+                       /* I/O-error, writeback failed, give up */
+                       goto uncorrectable;
+               }
+       }
+
+       kfree(multi);
+       spin_lock(&sdev->stat_lock);
+       ++sdev->stat.corrected_errors;
+       spin_unlock(&sdev->stat_lock);
+
+       if (printk_ratelimit())
+               printk(KERN_ERR "btrfs: fixed up at %llu\n",
+                      (unsigned long long)logical);
+       return;
+
+uncorrectable:
+       kfree(multi);
+       spin_lock(&sdev->stat_lock);
+       ++sdev->stat.uncorrectable_errors;
+       spin_unlock(&sdev->stat_lock);
+
+       if (printk_ratelimit())
+               printk(KERN_ERR "btrfs: unable to fixup at %llu\n",
+                        (unsigned long long)logical);
+}
+
+static int scrub_fixup_io(int rw, struct block_device *bdev, sector_t sector,
+                        struct page *page)
+{
+       struct bio *bio = NULL;
+       int ret;
+       DECLARE_COMPLETION_ONSTACK(complete);
+
+       bio = bio_alloc(GFP_NOFS, 1);
+       bio->bi_bdev = bdev;
+       bio->bi_sector = sector;
+       bio_add_page(bio, page, PAGE_SIZE, 0);
+       bio->bi_end_io = scrub_fixup_end_io;
+       bio->bi_private = &complete;
+       submit_bio(rw, bio);
+
+       /* this will also unplug the queue */
+       wait_for_completion(&complete);
+
+       ret = !test_bit(BIO_UPTODATE, &bio->bi_flags);
+       bio_put(bio);
+       return ret;
+}
+
+static void scrub_bio_end_io(struct bio *bio, int err)
+{
+       struct scrub_bio *sbio = bio->bi_private;
+       struct scrub_dev *sdev = sbio->sdev;
+       struct btrfs_fs_info *fs_info = sdev->dev->dev_root->fs_info;
+
+       sbio->err = err;
+       sbio->bio = bio;
+
+       btrfs_queue_worker(&fs_info->scrub_workers, &sbio->work);
+}
+
+static void scrub_checksum(struct btrfs_work *work)
+{
+       struct scrub_bio *sbio = container_of(work, struct scrub_bio, work);
+       struct scrub_dev *sdev = sbio->sdev;
+       struct page *page;
+       void *buffer;
+       int i;
+       u64 flags;
+       u64 logical;
+       int ret;
+
+       if (sbio->err) {
+               for (i = 0; i < sbio->count; ++i)
+                       scrub_recheck_error(sbio, i);
+
+               sbio->bio->bi_flags &= ~(BIO_POOL_MASK - 1);
+               sbio->bio->bi_flags |= 1 << BIO_UPTODATE;
+               sbio->bio->bi_phys_segments = 0;
+               sbio->bio->bi_idx = 0;
+
+               for (i = 0; i < sbio->count; i++) {
+                       struct bio_vec *bi;
+                       bi = &sbio->bio->bi_io_vec[i];
+                       bi->bv_offset = 0;
+                       bi->bv_len = PAGE_SIZE;
+               }
+
+               spin_lock(&sdev->stat_lock);
+               ++sdev->stat.read_errors;
+               spin_unlock(&sdev->stat_lock);
+               goto out;
+       }
+       for (i = 0; i < sbio->count; ++i) {
+               page = sbio->bio->bi_io_vec[i].bv_page;
+               buffer = kmap_atomic(page, KM_USER0);
+               flags = sbio->spag[i].flags;
+               logical = sbio->logical + i * PAGE_SIZE;
+               ret = 0;
+               if (flags & BTRFS_EXTENT_FLAG_DATA) {
+                       ret = scrub_checksum_data(sdev, sbio->spag + i, buffer);
+               } else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
+                       ret = scrub_checksum_tree_block(sdev, sbio->spag + i,
+                                                       logical, buffer);
+               } else if (flags & BTRFS_EXTENT_FLAG_SUPER) {
+                       BUG_ON(i);
+                       (void)scrub_checksum_super(sbio, buffer);
+               } else {
+                       WARN_ON(1);
+               }
+               kunmap_atomic(buffer, KM_USER0);
+               if (ret)
+                       scrub_recheck_error(sbio, i);
+       }
+
+out:
+       scrub_free_bio(sbio->bio);
+       sbio->bio = NULL;
+       spin_lock(&sdev->list_lock);
+       sbio->next_free = sdev->first_free;
+       sdev->first_free = sbio->index;
+       spin_unlock(&sdev->list_lock);
+       atomic_dec(&sdev->in_flight);
+       wake_up(&sdev->list_wait);
+}
+
+static int scrub_checksum_data(struct scrub_dev *sdev,
+                              struct scrub_page *spag, void *buffer)
+{
+       u8 csum[BTRFS_CSUM_SIZE];
+       u32 crc = ~(u32)0;
+       int fail = 0;
+       struct btrfs_root *root = sdev->dev->dev_root;
+
+       if (!spag->have_csum)
+               return 0;
+
+       crc = btrfs_csum_data(root, buffer, crc, PAGE_SIZE);
+       btrfs_csum_final(crc, csum);
+       if (memcmp(csum, spag->csum, sdev->csum_size))
+               fail = 1;
+
+       spin_lock(&sdev->stat_lock);
+       ++sdev->stat.data_extents_scrubbed;
+       sdev->stat.data_bytes_scrubbed += PAGE_SIZE;
+       if (fail)
+               ++sdev->stat.csum_errors;
+       spin_unlock(&sdev->stat_lock);
+
+       return fail;
+}
+
+static int scrub_checksum_tree_block(struct scrub_dev *sdev,
+                                    struct scrub_page *spag, u64 logical,
+                                    void *buffer)
+{
+       struct btrfs_header *h;
+       struct btrfs_root *root = sdev->dev->dev_root;
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       u8 csum[BTRFS_CSUM_SIZE];
+       u32 crc = ~(u32)0;
+       int fail = 0;
+       int crc_fail = 0;
+
+       /*
+        * we don't use the getter functions here, as we
+        * a) don't have an extent buffer and
+        * b) the page is already kmapped
+        */
+       h = (struct btrfs_header *)buffer;
+
+       if (logical != le64_to_cpu(h->bytenr))
+               ++fail;
+
+       if (spag->generation != le64_to_cpu(h->generation))
+               ++fail;
+
+       if (memcmp(h->fsid, fs_info->fsid, BTRFS_UUID_SIZE))
+               ++fail;
+
+       if (memcmp(h->chunk_tree_uuid, fs_info->chunk_tree_uuid,
+                  BTRFS_UUID_SIZE))
+               ++fail;
+
+       crc = btrfs_csum_data(root, buffer + BTRFS_CSUM_SIZE, crc,
+                             PAGE_SIZE - BTRFS_CSUM_SIZE);
+       btrfs_csum_final(crc, csum);
+       if (memcmp(csum, h->csum, sdev->csum_size))
+               ++crc_fail;
+
+       spin_lock(&sdev->stat_lock);
+       ++sdev->stat.tree_extents_scrubbed;
+       sdev->stat.tree_bytes_scrubbed += PAGE_SIZE;
+       if (crc_fail)
+               ++sdev->stat.csum_errors;
+       if (fail)
+               ++sdev->stat.verify_errors;
+       spin_unlock(&sdev->stat_lock);
+
+       return fail || crc_fail;
+}
+
+static int scrub_checksum_super(struct scrub_bio *sbio, void *buffer)
+{
+       struct btrfs_super_block *s;
+       u64 logical;
+       struct scrub_dev *sdev = sbio->sdev;
+       struct btrfs_root *root = sdev->dev->dev_root;
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       u8 csum[BTRFS_CSUM_SIZE];
+       u32 crc = ~(u32)0;
+       int fail = 0;
+
+       s = (struct btrfs_super_block *)buffer;
+       logical = sbio->logical;
+
+       if (logical != le64_to_cpu(s->bytenr))
+               ++fail;
+
+       if (sbio->spag[0].generation != le64_to_cpu(s->generation))
+               ++fail;
+
+       if (memcmp(s->fsid, fs_info->fsid, BTRFS_UUID_SIZE))
+               ++fail;
+
+       crc = btrfs_csum_data(root, buffer + BTRFS_CSUM_SIZE, crc,
+                             PAGE_SIZE - BTRFS_CSUM_SIZE);
+       btrfs_csum_final(crc, csum);
+       if (memcmp(csum, s->csum, sbio->sdev->csum_size))
+               ++fail;
+
+       if (fail) {
+               /*
+                * if we find an error in a super block, we just report it.
+                * They will get written with the next transaction commit
+                * anyway
+                */
+               spin_lock(&sdev->stat_lock);
+               ++sdev->stat.super_errors;
+               spin_unlock(&sdev->stat_lock);
+       }
+
+       return fail;
+}
+
+static int scrub_submit(struct scrub_dev *sdev)
+{
+       struct scrub_bio *sbio;
+       struct bio *bio;
+       int i;
+
+       if (sdev->curr == -1)
+               return 0;
+
+       sbio = sdev->bios[sdev->curr];
+
+       bio = bio_alloc(GFP_NOFS, sbio->count);
+       if (!bio)
+               goto nomem;
+
+       bio->bi_private = sbio;
+       bio->bi_end_io = scrub_bio_end_io;
+       bio->bi_bdev = sdev->dev->bdev;
+       bio->bi_sector = sbio->physical >> 9;
+
+       for (i = 0; i < sbio->count; ++i) {
+               struct page *page;
+               int ret;
+
+               page = alloc_page(GFP_NOFS);
+               if (!page)
+                       goto nomem;
+
+               ret = bio_add_page(bio, page, PAGE_SIZE, 0);
+               if (!ret) {
+                       __free_page(page);
+                       goto nomem;
+               }
+       }
+
+       sbio->err = 0;
+       sdev->curr = -1;
+       atomic_inc(&sdev->in_flight);
+
+       submit_bio(READ, bio);
+
+       return 0;
+
+nomem:
+       scrub_free_bio(bio);
+
+       return -ENOMEM;
+}
+
+static int scrub_page(struct scrub_dev *sdev, u64 logical, u64 len,
+                     u64 physical, u64 flags, u64 gen, u64 mirror_num,
+                     u8 *csum, int force)
+{
+       struct scrub_bio *sbio;
+
+again:
+       /*
+        * grab a fresh bio or wait for one to become available
+        */
+       while (sdev->curr == -1) {
+               spin_lock(&sdev->list_lock);
+               sdev->curr = sdev->first_free;
+               if (sdev->curr != -1) {
+                       sdev->first_free = sdev->bios[sdev->curr]->next_free;
+                       sdev->bios[sdev->curr]->next_free = -1;
+                       sdev->bios[sdev->curr]->count = 0;
+                       spin_unlock(&sdev->list_lock);
+               } else {
+                       spin_unlock(&sdev->list_lock);
+                       wait_event(sdev->list_wait, sdev->first_free != -1);
+               }
+       }
+       sbio = sdev->bios[sdev->curr];
+       if (sbio->count == 0) {
+               sbio->physical = physical;
+               sbio->logical = logical;
+       } else if (sbio->physical + sbio->count * PAGE_SIZE != physical ||
+                  sbio->logical + sbio->count * PAGE_SIZE != logical) {
+               int ret;
+
+               ret = scrub_submit(sdev);
+               if (ret)
+                       return ret;
+               goto again;
+       }
+       sbio->spag[sbio->count].flags = flags;
+       sbio->spag[sbio->count].generation = gen;
+       sbio->spag[sbio->count].have_csum = 0;
+       sbio->spag[sbio->count].mirror_num = mirror_num;
+       if (csum) {
+               sbio->spag[sbio->count].have_csum = 1;
+               memcpy(sbio->spag[sbio->count].csum, csum, sdev->csum_size);
+       }
+       ++sbio->count;
+       if (sbio->count == SCRUB_PAGES_PER_BIO || force) {
+               int ret;
+
+               ret = scrub_submit(sdev);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int scrub_find_csum(struct scrub_dev *sdev, u64 logical, u64 len,
+                          u8 *csum)
+{
+       struct btrfs_ordered_sum *sum = NULL;
+       int ret = 0;
+       unsigned long i;
+       unsigned long num_sectors;
+       u32 sectorsize = sdev->dev->dev_root->sectorsize;
+
+       while (!list_empty(&sdev->csum_list)) {
+               sum = list_first_entry(&sdev->csum_list,
+                                      struct btrfs_ordered_sum, list);
+               if (sum->bytenr > logical)
+                       return 0;
+               if (sum->bytenr + sum->len > logical)
+                       break;
+
+               ++sdev->stat.csum_discards;
+               list_del(&sum->list);
+               kfree(sum);
+               sum = NULL;
+       }
+       if (!sum)
+               return 0;
+
+       num_sectors = sum->len / sectorsize;
+       for (i = 0; i < num_sectors; ++i) {
+               if (sum->sums[i].bytenr == logical) {
+                       memcpy(csum, &sum->sums[i].sum, sdev->csum_size);
+                       ret = 1;
+                       break;
+               }
+       }
+       if (ret && i == num_sectors - 1) {
+               list_del(&sum->list);
+               kfree(sum);
+       }
+       return ret;
+}
+
+/* scrub extent tries to collect up to 64 kB for each bio */
+static int scrub_extent(struct scrub_dev *sdev, u64 logical, u64 len,
+                       u64 physical, u64 flags, u64 gen, u64 mirror_num)
+{
+       int ret;
+       u8 csum[BTRFS_CSUM_SIZE];
+
+       while (len) {
+               u64 l = min_t(u64, len, PAGE_SIZE);
+               int have_csum = 0;
+
+               if (flags & BTRFS_EXTENT_FLAG_DATA) {
+                       /* push csums to sbio */
+                       have_csum = scrub_find_csum(sdev, logical, l, csum);
+                       if (have_csum == 0)
+                               ++sdev->stat.no_csum;
+               }
+               ret = scrub_page(sdev, logical, l, physical, flags, gen,
+                                mirror_num, have_csum ? csum : NULL, 0);
+               if (ret)
+                       return ret;
+               len -= l;
+               logical += l;
+               physical += l;
+       }
+       return 0;
+}
+
+static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev,
+       struct map_lookup *map, int num, u64 base, u64 length)
+{
+       struct btrfs_path *path;
+       struct btrfs_fs_info *fs_info = sdev->dev->dev_root->fs_info;
+       struct btrfs_root *root = fs_info->extent_root;
+       struct btrfs_root *csum_root = fs_info->csum_root;
+       struct btrfs_extent_item *extent;
+       struct blk_plug plug;
+       u64 flags;
+       int ret;
+       int slot;
+       int i;
+       u64 nstripes;
+       int start_stripe;
+       struct extent_buffer *l;
+       struct btrfs_key key;
+       u64 physical;
+       u64 logical;
+       u64 generation;
+       u64 mirror_num;
+
+       u64 increment = map->stripe_len;
+       u64 offset;
+
+       nstripes = length;
+       offset = 0;
+       do_div(nstripes, map->stripe_len);
+       if (map->type & BTRFS_BLOCK_GROUP_RAID0) {
+               offset = map->stripe_len * num;
+               increment = map->stripe_len * map->num_stripes;
+               mirror_num = 0;
+       } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
+               int factor = map->num_stripes / map->sub_stripes;
+               offset = map->stripe_len * (num / map->sub_stripes);
+               increment = map->stripe_len * factor;
+               mirror_num = num % map->sub_stripes;
+       } else if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
+               increment = map->stripe_len;
+               mirror_num = num % map->num_stripes;
+       } else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
+               increment = map->stripe_len;
+               mirror_num = num % map->num_stripes;
+       } else {
+               increment = map->stripe_len;
+               mirror_num = 0;
+       }
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       path->reada = 2;
+       path->search_commit_root = 1;
+       path->skip_locking = 1;
+
+       /*
+        * find all extents for each stripe and just read them to get
+        * them into the page cache
+        * FIXME: we can do better. build a more intelligent prefetching
+        */
+       logical = base + offset;
+       physical = map->stripes[num].physical;
+       ret = 0;
+       for (i = 0; i < nstripes; ++i) {
+               key.objectid = logical;
+               key.type = BTRFS_EXTENT_ITEM_KEY;
+               key.offset = (u64)0;
+
+               ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+               if (ret < 0)
+                       goto out_noplug;
+
+               /*
+                * we might miss half an extent here, but that doesn't matter,
+                * as it's only the prefetch
+                */
+               while (1) {
+                       l = path->nodes[0];
+                       slot = path->slots[0];
+                       if (slot >= btrfs_header_nritems(l)) {
+                               ret = btrfs_next_leaf(root, path);
+                               if (ret == 0)
+                                       continue;
+                               if (ret < 0)
+                                       goto out_noplug;
+
+                               break;
+                       }
+                       btrfs_item_key_to_cpu(l, &key, slot);
+
+                       if (key.objectid >= logical + map->stripe_len)
+                               break;
+
+                       path->slots[0]++;
+               }
+               btrfs_release_path(path);
+               logical += increment;
+               physical += map->stripe_len;
+               cond_resched();
+       }
+
+       /*
+        * collect all data csums for the stripe to avoid seeking during
+        * the scrub. This might currently (crc32) end up to be about 1MB
+        */
+       start_stripe = 0;
+       blk_start_plug(&plug);
+again:
+       logical = base + offset + start_stripe * increment;
+       for (i = start_stripe; i < nstripes; ++i) {
+               ret = btrfs_lookup_csums_range(csum_root, logical,
+                                              logical + map->stripe_len - 1,
+                                              &sdev->csum_list, 1);
+               if (ret)
+                       goto out;
+
+               logical += increment;
+               cond_resched();
+       }
+       /*
+        * now find all extents for each stripe and scrub them
+        */
+       logical = base + offset + start_stripe * increment;
+       physical = map->stripes[num].physical + start_stripe * map->stripe_len;
+       ret = 0;
+       for (i = start_stripe; i < nstripes; ++i) {
+               /*
+                * canceled?
+                */
+               if (atomic_read(&fs_info->scrub_cancel_req) ||
+                   atomic_read(&sdev->cancel_req)) {
+                       ret = -ECANCELED;
+                       goto out;
+               }
+               /*
+                * check to see if we have to pause
+                */
+               if (atomic_read(&fs_info->scrub_pause_req)) {
+                       /* push queued extents */
+                       scrub_submit(sdev);
+                       wait_event(sdev->list_wait,
+                                  atomic_read(&sdev->in_flight) == 0);
+                       atomic_inc(&fs_info->scrubs_paused);
+                       wake_up(&fs_info->scrub_pause_wait);
+                       mutex_lock(&fs_info->scrub_lock);
+                       while (atomic_read(&fs_info->scrub_pause_req)) {
+                               mutex_unlock(&fs_info->scrub_lock);
+                               wait_event(fs_info->scrub_pause_wait,
+                                  atomic_read(&fs_info->scrub_pause_req) == 0);
+                               mutex_lock(&fs_info->scrub_lock);
+                       }
+                       atomic_dec(&fs_info->scrubs_paused);
+                       mutex_unlock(&fs_info->scrub_lock);
+                       wake_up(&fs_info->scrub_pause_wait);
+                       scrub_free_csums(sdev);
+                       start_stripe = i;
+                       goto again;
+               }
+
+               key.objectid = logical;
+               key.type = BTRFS_EXTENT_ITEM_KEY;
+               key.offset = (u64)0;
+
+               ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+               if (ret < 0)
+                       goto out;
+               if (ret > 0) {
+                       ret = btrfs_previous_item(root, path, 0,
+                                                 BTRFS_EXTENT_ITEM_KEY);
+                       if (ret < 0)
+                               goto out;
+                       if (ret > 0) {
+                               /* there's no smaller item, so stick with the
+                                * larger one */
+                               btrfs_release_path(path);
+                               ret = btrfs_search_slot(NULL, root, &key,
+                                                       path, 0, 0);
+                               if (ret < 0)
+                                       goto out;
+                       }
+               }
+
+               while (1) {
+                       l = path->nodes[0];
+                       slot = path->slots[0];
+                       if (slot >= btrfs_header_nritems(l)) {
+                               ret = btrfs_next_leaf(root, path);
+                               if (ret == 0)
+                                       continue;
+                               if (ret < 0)
+                                       goto out;
+
+                               break;
+                       }
+                       btrfs_item_key_to_cpu(l, &key, slot);
+
+                       if (key.objectid + key.offset <= logical)
+                               goto next;
+
+                       if (key.objectid >= logical + map->stripe_len)
+                               break;
+
+                       if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY)
+                               goto next;
+
+                       extent = btrfs_item_ptr(l, slot,
+                                               struct btrfs_extent_item);
+                       flags = btrfs_extent_flags(l, extent);
+                       generation = btrfs_extent_generation(l, extent);
+
+                       if (key.objectid < logical &&
+                           (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)) {
+                               printk(KERN_ERR
+                                      "btrfs scrub: tree block %llu spanning "
+                                      "stripes, ignored. logical=%llu\n",
+                                      (unsigned long long)key.objectid,
+                                      (unsigned long long)logical);
+                               goto next;
+                       }
+
+                       /*
+                        * trim extent to this stripe
+                        */
+                       if (key.objectid < logical) {
+                               key.offset -= logical - key.objectid;
+                               key.objectid = logical;
+                       }
+                       if (key.objectid + key.offset >
+                           logical + map->stripe_len) {
+                               key.offset = logical + map->stripe_len -
+                                            key.objectid;
+                       }
+
+                       ret = scrub_extent(sdev, key.objectid, key.offset,
+                                          key.objectid - logical + physical,
+                                          flags, generation, mirror_num);
+                       if (ret)
+                               goto out;
+
+next:
+                       path->slots[0]++;
+               }
+               btrfs_release_path(path);
+               logical += increment;
+               physical += map->stripe_len;
+               spin_lock(&sdev->stat_lock);
+               sdev->stat.last_physical = physical;
+               spin_unlock(&sdev->stat_lock);
+       }
+       /* push queued extents */
+       scrub_submit(sdev);
+
+out:
+       blk_finish_plug(&plug);
+out_noplug:
+       btrfs_free_path(path);
+       return ret < 0 ? ret : 0;
+}
+
+static noinline_for_stack int scrub_chunk(struct scrub_dev *sdev,
+       u64 chunk_tree, u64 chunk_objectid, u64 chunk_offset, u64 length)
+{
+       struct btrfs_mapping_tree *map_tree =
+               &sdev->dev->dev_root->fs_info->mapping_tree;
+       struct map_lookup *map;
+       struct extent_map *em;
+       int i;
+       int ret = -EINVAL;
+
+       read_lock(&map_tree->map_tree.lock);
+       em = lookup_extent_mapping(&map_tree->map_tree, chunk_offset, 1);
+       read_unlock(&map_tree->map_tree.lock);
+
+       if (!em)
+               return -EINVAL;
+
+       map = (struct map_lookup *)em->bdev;
+       if (em->start != chunk_offset)
+               goto out;
+
+       if (em->len < length)
+               goto out;
+
+       for (i = 0; i < map->num_stripes; ++i) {
+               if (map->stripes[i].dev == sdev->dev) {
+                       ret = scrub_stripe(sdev, map, i, chunk_offset, length);
+                       if (ret)
+                               goto out;
+               }
+       }
+out:
+       free_extent_map(em);
+
+       return ret;
+}
+
+static noinline_for_stack
+int scrub_enumerate_chunks(struct scrub_dev *sdev, u64 start, u64 end)
+{
+       struct btrfs_dev_extent *dev_extent = NULL;
+       struct btrfs_path *path;
+       struct btrfs_root *root = sdev->dev->dev_root;
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       u64 length;
+       u64 chunk_tree;
+       u64 chunk_objectid;
+       u64 chunk_offset;
+       int ret;
+       int slot;
+       struct extent_buffer *l;
+       struct btrfs_key key;
+       struct btrfs_key found_key;
+       struct btrfs_block_group_cache *cache;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       path->reada = 2;
+       path->search_commit_root = 1;
+       path->skip_locking = 1;
+
+       key.objectid = sdev->dev->devid;
+       key.offset = 0ull;
+       key.type = BTRFS_DEV_EXTENT_KEY;
+
+
+       while (1) {
+               ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+               if (ret < 0)
+                       break;
+               if (ret > 0) {
+                       if (path->slots[0] >=
+                           btrfs_header_nritems(path->nodes[0])) {
+                               ret = btrfs_next_leaf(root, path);
+                               if (ret)
+                                       break;
+                       }
+               }
+
+               l = path->nodes[0];
+               slot = path->slots[0];
+
+               btrfs_item_key_to_cpu(l, &found_key, slot);
+
+               if (found_key.objectid != sdev->dev->devid)
+                       break;
+
+               if (btrfs_key_type(&found_key) != BTRFS_DEV_EXTENT_KEY)
+                       break;
+
+               if (found_key.offset >= end)
+                       break;
+
+               if (found_key.offset < key.offset)
+                       break;
+
+               dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
+               length = btrfs_dev_extent_length(l, dev_extent);
+
+               if (found_key.offset + length <= start) {
+                       key.offset = found_key.offset + length;
+                       btrfs_release_path(path);
+                       continue;
+               }
+
+               chunk_tree = btrfs_dev_extent_chunk_tree(l, dev_extent);
+               chunk_objectid = btrfs_dev_extent_chunk_objectid(l, dev_extent);
+               chunk_offset = btrfs_dev_extent_chunk_offset(l, dev_extent);
+
+               /*
+                * get a reference on the corresponding block group to prevent
+                * the chunk from going away while we scrub it
+                */
+               cache = btrfs_lookup_block_group(fs_info, chunk_offset);
+               if (!cache) {
+                       ret = -ENOENT;
+                       break;
+               }
+               ret = scrub_chunk(sdev, chunk_tree, chunk_objectid,
+                                 chunk_offset, length);
+               btrfs_put_block_group(cache);
+               if (ret)
+                       break;
+
+               key.offset = found_key.offset + length;
+               btrfs_release_path(path);
+       }
+
+       btrfs_free_path(path);
+
+       /*
+        * ret can still be 1 from search_slot or next_leaf,
+        * that's not an error
+        */
+       return ret < 0 ? ret : 0;
+}
+
+static noinline_for_stack int scrub_supers(struct scrub_dev *sdev)
+{
+       int     i;
+       u64     bytenr;
+       u64     gen;
+       int     ret;
+       struct btrfs_device *device = sdev->dev;
+       struct btrfs_root *root = device->dev_root;
+
+       gen = root->fs_info->last_trans_committed;
+
+       for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
+               bytenr = btrfs_sb_offset(i);
+               if (bytenr + BTRFS_SUPER_INFO_SIZE >= device->total_bytes)
+                       break;
+
+               ret = scrub_page(sdev, bytenr, PAGE_SIZE, bytenr,
+                                BTRFS_EXTENT_FLAG_SUPER, gen, i, NULL, 1);
+               if (ret)
+                       return ret;
+       }
+       wait_event(sdev->list_wait, atomic_read(&sdev->in_flight) == 0);
+
+       return 0;
+}
+
+/*
+ * get a reference count on fs_info->scrub_workers. start worker if necessary
+ */
+static noinline_for_stack int scrub_workers_get(struct btrfs_root *root)
+{
+       struct btrfs_fs_info *fs_info = root->fs_info;
+
+       mutex_lock(&fs_info->scrub_lock);
+       if (fs_info->scrub_workers_refcnt == 0) {
+               btrfs_init_workers(&fs_info->scrub_workers, "scrub",
+                          fs_info->thread_pool_size, &fs_info->generic_worker);
+               fs_info->scrub_workers.idle_thresh = 4;
+               btrfs_start_workers(&fs_info->scrub_workers, 1);
+       }
+       ++fs_info->scrub_workers_refcnt;
+       mutex_unlock(&fs_info->scrub_lock);
+
+       return 0;
+}
+
+static noinline_for_stack void scrub_workers_put(struct btrfs_root *root)
+{
+       struct btrfs_fs_info *fs_info = root->fs_info;
+
+       mutex_lock(&fs_info->scrub_lock);
+       if (--fs_info->scrub_workers_refcnt == 0)
+               btrfs_stop_workers(&fs_info->scrub_workers);
+       WARN_ON(fs_info->scrub_workers_refcnt < 0);
+       mutex_unlock(&fs_info->scrub_lock);
+}
+
+
+int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end,
+                   struct btrfs_scrub_progress *progress, int readonly)
+{
+       struct scrub_dev *sdev;
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       int ret;
+       struct btrfs_device *dev;
+
+       if (btrfs_fs_closing(root->fs_info))
+               return -EINVAL;
+
+       /*
+        * check some assumptions
+        */
+       if (root->sectorsize != PAGE_SIZE ||
+           root->sectorsize != root->leafsize ||
+           root->sectorsize != root->nodesize) {
+               printk(KERN_ERR "btrfs_scrub: size assumptions fail\n");
+               return -EINVAL;
+       }
+
+       ret = scrub_workers_get(root);
+       if (ret)
+               return ret;
+
+       mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
+       dev = btrfs_find_device(root, devid, NULL, NULL);
+       if (!dev || dev->missing) {
+               mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+               scrub_workers_put(root);
+               return -ENODEV;
+       }
+       mutex_lock(&fs_info->scrub_lock);
+
+       if (!dev->in_fs_metadata) {
+               mutex_unlock(&fs_info->scrub_lock);
+               mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+               scrub_workers_put(root);
+               return -ENODEV;
+       }
+
+       if (dev->scrub_device) {
+               mutex_unlock(&fs_info->scrub_lock);
+               mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+               scrub_workers_put(root);
+               return -EINPROGRESS;
+       }
+       sdev = scrub_setup_dev(dev);
+       if (IS_ERR(sdev)) {
+               mutex_unlock(&fs_info->scrub_lock);
+               mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+               scrub_workers_put(root);
+               return PTR_ERR(sdev);
+       }
+       sdev->readonly = readonly;
+       dev->scrub_device = sdev;
+
+       atomic_inc(&fs_info->scrubs_running);
+       mutex_unlock(&fs_info->scrub_lock);
+       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+
+       down_read(&fs_info->scrub_super_lock);
+       ret = scrub_supers(sdev);
+       up_read(&fs_info->scrub_super_lock);
+
+       if (!ret)
+               ret = scrub_enumerate_chunks(sdev, start, end);
+
+       wait_event(sdev->list_wait, atomic_read(&sdev->in_flight) == 0);
+
+       atomic_dec(&fs_info->scrubs_running);
+       wake_up(&fs_info->scrub_pause_wait);
+
+       if (progress)
+               memcpy(progress, &sdev->stat, sizeof(*progress));
+
+       mutex_lock(&fs_info->scrub_lock);
+       dev->scrub_device = NULL;
+       mutex_unlock(&fs_info->scrub_lock);
+
+       scrub_free_dev(sdev);
+       scrub_workers_put(root);
+
+       return ret;
+}
+
+int btrfs_scrub_pause(struct btrfs_root *root)
+{
+       struct btrfs_fs_info *fs_info = root->fs_info;
+
+       mutex_lock(&fs_info->scrub_lock);
+       atomic_inc(&fs_info->scrub_pause_req);
+       while (atomic_read(&fs_info->scrubs_paused) !=
+              atomic_read(&fs_info->scrubs_running)) {
+               mutex_unlock(&fs_info->scrub_lock);
+               wait_event(fs_info->scrub_pause_wait,
+                          atomic_read(&fs_info->scrubs_paused) ==
+                          atomic_read(&fs_info->scrubs_running));
+               mutex_lock(&fs_info->scrub_lock);
+       }
+       mutex_unlock(&fs_info->scrub_lock);
+
+       return 0;
+}
+
+int btrfs_scrub_continue(struct btrfs_root *root)
+{
+       struct btrfs_fs_info *fs_info = root->fs_info;
+
+       atomic_dec(&fs_info->scrub_pause_req);
+       wake_up(&fs_info->scrub_pause_wait);
+       return 0;
+}
+
+int btrfs_scrub_pause_super(struct btrfs_root *root)
+{
+       down_write(&root->fs_info->scrub_super_lock);
+       return 0;
+}
+
+int btrfs_scrub_continue_super(struct btrfs_root *root)
+{
+       up_write(&root->fs_info->scrub_super_lock);
+       return 0;
+}
+
+int btrfs_scrub_cancel(struct btrfs_root *root)
+{
+       struct btrfs_fs_info *fs_info = root->fs_info;
+
+       mutex_lock(&fs_info->scrub_lock);
+       if (!atomic_read(&fs_info->scrubs_running)) {
+               mutex_unlock(&fs_info->scrub_lock);
+               return -ENOTCONN;
+       }
+
+       atomic_inc(&fs_info->scrub_cancel_req);
+       while (atomic_read(&fs_info->scrubs_running)) {
+               mutex_unlock(&fs_info->scrub_lock);
+               wait_event(fs_info->scrub_pause_wait,
+                          atomic_read(&fs_info->scrubs_running) == 0);
+               mutex_lock(&fs_info->scrub_lock);
+       }
+       atomic_dec(&fs_info->scrub_cancel_req);
+       mutex_unlock(&fs_info->scrub_lock);
+
+       return 0;
+}
+
+int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev)
+{
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct scrub_dev *sdev;
+
+       mutex_lock(&fs_info->scrub_lock);
+       sdev = dev->scrub_device;
+       if (!sdev) {
+               mutex_unlock(&fs_info->scrub_lock);
+               return -ENOTCONN;
+       }
+       atomic_inc(&sdev->cancel_req);
+       while (dev->scrub_device) {
+               mutex_unlock(&fs_info->scrub_lock);
+               wait_event(fs_info->scrub_pause_wait,
+                          dev->scrub_device == NULL);
+               mutex_lock(&fs_info->scrub_lock);
+       }
+       mutex_unlock(&fs_info->scrub_lock);
+
+       return 0;
+}
+int btrfs_scrub_cancel_devid(struct btrfs_root *root, u64 devid)
+{
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_device *dev;
+       int ret;
+
+       /*
+        * we have to hold the device_list_mutex here so the device
+        * does not go away in cancel_dev. FIXME: find a better solution
+        */
+       mutex_lock(&fs_info->fs_devices->device_list_mutex);
+       dev = btrfs_find_device(root, devid, NULL, NULL);
+       if (!dev) {
+               mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+               return -ENODEV;
+       }
+       ret = btrfs_scrub_cancel_dev(root, dev);
+       mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+
+       return ret;
+}
+
+int btrfs_scrub_progress(struct btrfs_root *root, u64 devid,
+                        struct btrfs_scrub_progress *progress)
+{
+       struct btrfs_device *dev;
+       struct scrub_dev *sdev = NULL;
+
+       mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
+       dev = btrfs_find_device(root, devid, NULL, NULL);
+       if (dev)
+               sdev = dev->scrub_device;
+       if (sdev)
+               memcpy(progress, &sdev->stat, sizeof(*progress));
+       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+
+       return dev ? (sdev ? 0 : -ENOTCONN) : -ENODEV;
+}
index 0ac712efcdf293ac8e858fef443b57316b039037..0bb4ebbb71b7b0bf6861b7a5efde6f5cf2f5b97e 100644 (file)
@@ -39,7 +39,9 @@
 #include <linux/miscdevice.h>
 #include <linux/magic.h>
 #include <linux/slab.h>
+#include <linux/cleancache.h>
 #include "compat.h"
+#include "delayed-inode.h"
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
@@ -159,7 +161,8 @@ enum {
        Opt_compress_type, Opt_compress_force, Opt_compress_force_type,
        Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard,
        Opt_space_cache, Opt_clear_cache, Opt_user_subvol_rm_allowed,
-       Opt_enospc_debug, Opt_subvolrootid, Opt_err,
+       Opt_enospc_debug, Opt_subvolrootid, Opt_defrag,
+       Opt_inode_cache, Opt_err,
 };
 
 static match_table_t tokens = {
@@ -190,6 +193,8 @@ static match_table_t tokens = {
        {Opt_user_subvol_rm_allowed, "user_subvol_rm_allowed"},
        {Opt_enospc_debug, "enospc_debug"},
        {Opt_subvolrootid, "subvolrootid=%d"},
+       {Opt_defrag, "autodefrag"},
+       {Opt_inode_cache, "inode_cache"},
        {Opt_err, NULL},
 };
 
@@ -358,6 +363,10 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                        printk(KERN_INFO "btrfs: enabling disk space caching\n");
                        btrfs_set_opt(info->mount_opt, SPACE_CACHE);
                        break;
+               case Opt_inode_cache:
+                       printk(KERN_INFO "btrfs: enabling inode map caching\n");
+                       btrfs_set_opt(info->mount_opt, INODE_MAP_CACHE);
+                       break;
                case Opt_clear_cache:
                        printk(KERN_INFO "btrfs: force clearing of disk cache\n");
                        btrfs_set_opt(info->mount_opt, CLEAR_CACHE);
@@ -368,6 +377,10 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                case Opt_enospc_debug:
                        btrfs_set_opt(info->mount_opt, ENOSPC_DEBUG);
                        break;
+               case Opt_defrag:
+                       printk(KERN_INFO "btrfs: enabling auto defrag");
+                       btrfs_set_opt(info->mount_opt, AUTO_DEFRAG);
+                       break;
                case Opt_err:
                        printk(KERN_INFO "btrfs: unrecognized mount option "
                               "'%s'\n", p);
@@ -506,8 +519,10 @@ static struct dentry *get_default_root(struct super_block *sb,
         */
        dir_id = btrfs_super_root_dir(&root->fs_info->super_copy);
        di = btrfs_lookup_dir_item(NULL, root, path, dir_id, "default", 7, 0);
-       if (IS_ERR(di))
+       if (IS_ERR(di)) {
+               btrfs_free_path(path);
                return ERR_CAST(di);
+       }
        if (!di) {
                /*
                 * Ok the default dir item isn't there.  This is weird since
@@ -624,6 +639,7 @@ static int btrfs_fill_super(struct super_block *sb,
        sb->s_root = root_dentry;
 
        save_mount_options(sb, data);
+       cleancache_init_fs(sb);
        return 0;
 
 fail_close:
@@ -739,7 +755,7 @@ static int btrfs_set_super(struct super_block *s, void *data)
  *       for multiple device setup.  Make sure to keep it in sync.
  */
 static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
-               const char *dev_name, void *data)
+               const char *device_name, void *data)
 {
        struct block_device *bdev = NULL;
        struct super_block *s;
@@ -762,7 +778,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
        if (error)
                return ERR_PTR(error);
 
-       error = btrfs_scan_one_device(dev_name, mode, fs_type, &fs_devices);
+       error = btrfs_scan_one_device(device_name, mode, fs_type, &fs_devices);
        if (error)
                goto error_free_subvol_name;
 
@@ -809,7 +825,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
        } else {
                char b[BDEVNAME_SIZE];
 
-               s->s_flags = flags;
+               s->s_flags = flags | MS_NOSEC;
                strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
                error = btrfs_fill_super(s, fs_devices, data,
                                         flags & MS_SILENT ? 1 : 0);
@@ -913,6 +929,32 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
        return 0;
 }
 
+/* Used to sort the devices by max_avail(descending sort) */
+static int btrfs_cmp_device_free_bytes(const void *dev_info1,
+                                      const void *dev_info2)
+{
+       if (((struct btrfs_device_info *)dev_info1)->max_avail >
+           ((struct btrfs_device_info *)dev_info2)->max_avail)
+               return -1;
+       else if (((struct btrfs_device_info *)dev_info1)->max_avail <
+                ((struct btrfs_device_info *)dev_info2)->max_avail)
+               return 1;
+       else
+       return 0;
+}
+
+/*
+ * sort the devices by max_avail, in which max free extent size of each device
+ * is stored.(Descending Sort)
+ */
+static inline void btrfs_descending_sort_devices(
+                                       struct btrfs_device_info *devices,
+                                       size_t nr_devices)
+{
+       sort(devices, nr_devices, sizeof(struct btrfs_device_info),
+            btrfs_cmp_device_free_bytes, NULL);
+}
+
 /*
  * The helper to calc the free space on the devices that can be used to store
  * file data.
@@ -1206,10 +1248,14 @@ static int __init init_btrfs_fs(void)
        if (err)
                goto free_extent_io;
 
-       err = btrfs_interface_init();
+       err = btrfs_delayed_inode_init();
        if (err)
                goto free_extent_map;
 
+       err = btrfs_interface_init();
+       if (err)
+               goto free_delayed_inode;
+
        err = register_filesystem(&btrfs_fs_type);
        if (err)
                goto unregister_ioctl;
@@ -1219,6 +1265,8 @@ static int __init init_btrfs_fs(void)
 
 unregister_ioctl:
        btrfs_interface_exit();
+free_delayed_inode:
+       btrfs_delayed_inode_exit();
 free_extent_map:
        extent_map_exit();
 free_extent_io:
@@ -1235,6 +1283,7 @@ free_sysfs:
 static void __exit exit_btrfs_fs(void)
 {
        btrfs_destroy_cachep();
+       btrfs_delayed_inode_exit();
        extent_map_exit();
        extent_io_exit();
        btrfs_interface_exit();
index 4ce16ef702a3a9e7384ea9e1bc591c51a5f66c14..daac9ae6d7319b4f2cc68c0893a86c7d779e6516 100644 (file)
 #include "disk-io.h"
 #include "transaction.h"
 
-static ssize_t root_blocks_used_show(struct btrfs_root *root, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "%llu\n",
-               (unsigned long long)btrfs_root_used(&root->root_item));
-}
-
-static ssize_t root_block_limit_show(struct btrfs_root *root, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "%llu\n",
-               (unsigned long long)btrfs_root_limit(&root->root_item));
-}
-
-static ssize_t super_blocks_used_show(struct btrfs_fs_info *fs, char *buf)
-{
-
-       return snprintf(buf, PAGE_SIZE, "%llu\n",
-               (unsigned long long)btrfs_super_bytes_used(&fs->super_copy));
-}
-
-static ssize_t super_total_blocks_show(struct btrfs_fs_info *fs, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "%llu\n",
-               (unsigned long long)btrfs_super_total_bytes(&fs->super_copy));
-}
-
-static ssize_t super_blocksize_show(struct btrfs_fs_info *fs, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "%llu\n",
-               (unsigned long long)btrfs_super_sectorsize(&fs->super_copy));
-}
-
-/* this is for root attrs (subvols/snapshots) */
-struct btrfs_root_attr {
-       struct attribute attr;
-       ssize_t (*show)(struct btrfs_root *, char *);
-       ssize_t (*store)(struct btrfs_root *, const char *, size_t);
-};
-
-#define ROOT_ATTR(name, mode, show, store) \
-static struct btrfs_root_attr btrfs_root_attr_##name = __ATTR(name, mode, \
-                                                             show, store)
-
-ROOT_ATTR(blocks_used, 0444,   root_blocks_used_show,  NULL);
-ROOT_ATTR(block_limit, 0644,   root_block_limit_show,  NULL);
-
-static struct attribute *btrfs_root_attrs[] = {
-       &btrfs_root_attr_blocks_used.attr,
-       &btrfs_root_attr_block_limit.attr,
-       NULL,
-};
-
-/* this is for super attrs (actual full fs) */
-struct btrfs_super_attr {
-       struct attribute attr;
-       ssize_t (*show)(struct btrfs_fs_info *, char *);
-       ssize_t (*store)(struct btrfs_fs_info *, const char *, size_t);
-};
-
-#define SUPER_ATTR(name, mode, show, store) \
-static struct btrfs_super_attr btrfs_super_attr_##name = __ATTR(name, mode, \
-                                                               show, store)
-
-SUPER_ATTR(blocks_used,                0444,   super_blocks_used_show,         NULL);
-SUPER_ATTR(total_blocks,       0444,   super_total_blocks_show,        NULL);
-SUPER_ATTR(blocksize,          0444,   super_blocksize_show,           NULL);
-
-static struct attribute *btrfs_super_attrs[] = {
-       &btrfs_super_attr_blocks_used.attr,
-       &btrfs_super_attr_total_blocks.attr,
-       &btrfs_super_attr_blocksize.attr,
-       NULL,
-};
-
-static ssize_t btrfs_super_attr_show(struct kobject *kobj,
-                                   struct attribute *attr, char *buf)
-{
-       struct btrfs_fs_info *fs = container_of(kobj, struct btrfs_fs_info,
-                                               super_kobj);
-       struct btrfs_super_attr *a = container_of(attr,
-                                                 struct btrfs_super_attr,
-                                                 attr);
-
-       return a->show ? a->show(fs, buf) : 0;
-}
-
-static ssize_t btrfs_super_attr_store(struct kobject *kobj,
-                                    struct attribute *attr,
-                                    const char *buf, size_t len)
-{
-       struct btrfs_fs_info *fs = container_of(kobj, struct btrfs_fs_info,
-                                               super_kobj);
-       struct btrfs_super_attr *a = container_of(attr,
-                                                 struct btrfs_super_attr,
-                                                 attr);
-
-       return a->store ? a->store(fs, buf, len) : 0;
-}
-
-static ssize_t btrfs_root_attr_show(struct kobject *kobj,
-                                   struct attribute *attr, char *buf)
-{
-       struct btrfs_root *root = container_of(kobj, struct btrfs_root,
-                                               root_kobj);
-       struct btrfs_root_attr *a = container_of(attr,
-                                                struct btrfs_root_attr,
-                                                attr);
-
-       return a->show ? a->show(root, buf) : 0;
-}
-
-static ssize_t btrfs_root_attr_store(struct kobject *kobj,
-                                    struct attribute *attr,
-                                    const char *buf, size_t len)
-{
-       struct btrfs_root *root = container_of(kobj, struct btrfs_root,
-                                               root_kobj);
-       struct btrfs_root_attr *a = container_of(attr,
-                                                struct btrfs_root_attr,
-                                                attr);
-       return a->store ? a->store(root, buf, len) : 0;
-}
-
-static void btrfs_super_release(struct kobject *kobj)
-{
-       struct btrfs_fs_info *fs = container_of(kobj, struct btrfs_fs_info,
-                                               super_kobj);
-       complete(&fs->kobj_unregister);
-}
-
-static void btrfs_root_release(struct kobject *kobj)
-{
-       struct btrfs_root *root = container_of(kobj, struct btrfs_root,
-                                               root_kobj);
-       complete(&root->kobj_unregister);
-}
-
-static const struct sysfs_ops btrfs_super_attr_ops = {
-       .show   = btrfs_super_attr_show,
-       .store  = btrfs_super_attr_store,
-};
-
-static const struct sysfs_ops btrfs_root_attr_ops = {
-       .show   = btrfs_root_attr_show,
-       .store  = btrfs_root_attr_store,
-};
-
-static struct kobj_type btrfs_root_ktype = {
-       .default_attrs  = btrfs_root_attrs,
-       .sysfs_ops      = &btrfs_root_attr_ops,
-       .release        = btrfs_root_release,
-};
-
-static struct kobj_type btrfs_super_ktype = {
-       .default_attrs  = btrfs_super_attrs,
-       .sysfs_ops      = &btrfs_super_attr_ops,
-       .release        = btrfs_super_release,
-};
-
 /* /sys/fs/btrfs/ entry */
 static struct kset *btrfs_kset;
 
-int btrfs_sysfs_add_super(struct btrfs_fs_info *fs)
-{
-       int error;
-       char *name;
-       char c;
-       int len = strlen(fs->sb->s_id) + 1;
-       int i;
-
-       name = kmalloc(len, GFP_NOFS);
-       if (!name) {
-               error = -ENOMEM;
-               goto fail;
-       }
-
-       for (i = 0; i < len; i++) {
-               c = fs->sb->s_id[i];
-               if (c == '/' || c == '\\')
-                       c = '!';
-               name[i] = c;
-       }
-       name[len] = '\0';
-
-       fs->super_kobj.kset = btrfs_kset;
-       error = kobject_init_and_add(&fs->super_kobj, &btrfs_super_ktype,
-                                    NULL, "%s", name);
-       kfree(name);
-       if (error)
-               goto fail;
-
-       return 0;
-
-fail:
-       printk(KERN_ERR "btrfs: sysfs creation for super failed\n");
-       return error;
-}
-
-int btrfs_sysfs_add_root(struct btrfs_root *root)
-{
-       int error;
-
-       error = kobject_init_and_add(&root->root_kobj, &btrfs_root_ktype,
-                                    &root->fs_info->super_kobj,
-                                    "%s", root->name);
-       if (error)
-               goto fail;
-
-       return 0;
-
-fail:
-       printk(KERN_ERR "btrfs: sysfs creation for root failed\n");
-       return error;
-}
-
-void btrfs_sysfs_del_root(struct btrfs_root *root)
-{
-       kobject_put(&root->root_kobj);
-       wait_for_completion(&root->kobj_unregister);
-}
-
-void btrfs_sysfs_del_super(struct btrfs_fs_info *fs)
-{
-       kobject_put(&fs->super_kobj);
-       wait_for_completion(&fs->kobj_unregister);
-}
-
 int btrfs_init_sysfs(void)
 {
        btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj);
index c571734d5e5a802ea73a0c6458dd41c0b2e56659..51dcec86757f071654bc3866123e65157ef0286b 100644 (file)
@@ -27,6 +27,7 @@
 #include "transaction.h"
 #include "locking.h"
 #include "tree-log.h"
+#include "inode-map.h"
 
 #define BTRFS_ROOT_TRANS_TAG 0
 
@@ -34,6 +35,7 @@ static noinline void put_transaction(struct btrfs_transaction *transaction)
 {
        WARN_ON(atomic_read(&transaction->use_count) == 0);
        if (atomic_dec_and_test(&transaction->use_count)) {
+               BUG_ON(!list_empty(&transaction->list));
                memset(transaction, 0, sizeof(*transaction));
                kmem_cache_free(btrfs_transaction_cachep, transaction);
        }
@@ -48,47 +50,72 @@ static noinline void switch_commit_root(struct btrfs_root *root)
 /*
  * either allocate a new transaction or hop into the existing one
  */
-static noinline int join_transaction(struct btrfs_root *root)
+static noinline int join_transaction(struct btrfs_root *root, int nofail)
 {
        struct btrfs_transaction *cur_trans;
+
+       spin_lock(&root->fs_info->trans_lock);
+       if (root->fs_info->trans_no_join) {
+               if (!nofail) {
+                       spin_unlock(&root->fs_info->trans_lock);
+                       return -EBUSY;
+               }
+       }
+
        cur_trans = root->fs_info->running_transaction;
-       if (!cur_trans) {
-               cur_trans = kmem_cache_alloc(btrfs_transaction_cachep,
-                                            GFP_NOFS);
-               if (!cur_trans)
-                       return -ENOMEM;
-               root->fs_info->generation++;
-               atomic_set(&cur_trans->num_writers, 1);
-               cur_trans->num_joined = 0;
-               cur_trans->transid = root->fs_info->generation;
-               init_waitqueue_head(&cur_trans->writer_wait);
-               init_waitqueue_head(&cur_trans->commit_wait);
-               cur_trans->in_commit = 0;
-               cur_trans->blocked = 0;
-               atomic_set(&cur_trans->use_count, 1);
-               cur_trans->commit_done = 0;
-               cur_trans->start_time = get_seconds();
-
-               cur_trans->delayed_refs.root = RB_ROOT;
-               cur_trans->delayed_refs.num_entries = 0;
-               cur_trans->delayed_refs.num_heads_ready = 0;
-               cur_trans->delayed_refs.num_heads = 0;
-               cur_trans->delayed_refs.flushing = 0;
-               cur_trans->delayed_refs.run_delayed_start = 0;
-               spin_lock_init(&cur_trans->delayed_refs.lock);
-
-               INIT_LIST_HEAD(&cur_trans->pending_snapshots);
-               list_add_tail(&cur_trans->list, &root->fs_info->trans_list);
-               extent_io_tree_init(&cur_trans->dirty_pages,
-                                    root->fs_info->btree_inode->i_mapping,
-                                    GFP_NOFS);
-               spin_lock(&root->fs_info->new_trans_lock);
-               root->fs_info->running_transaction = cur_trans;
-               spin_unlock(&root->fs_info->new_trans_lock);
-       } else {
+       if (cur_trans) {
+               atomic_inc(&cur_trans->use_count);
                atomic_inc(&cur_trans->num_writers);
                cur_trans->num_joined++;
+               spin_unlock(&root->fs_info->trans_lock);
+               return 0;
        }
+       spin_unlock(&root->fs_info->trans_lock);
+
+       cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS);
+       if (!cur_trans)
+               return -ENOMEM;
+       spin_lock(&root->fs_info->trans_lock);
+       if (root->fs_info->running_transaction) {
+               kmem_cache_free(btrfs_transaction_cachep, cur_trans);
+               cur_trans = root->fs_info->running_transaction;
+               atomic_inc(&cur_trans->use_count);
+               atomic_inc(&cur_trans->num_writers);
+               cur_trans->num_joined++;
+               spin_unlock(&root->fs_info->trans_lock);
+               return 0;
+       }
+       atomic_set(&cur_trans->num_writers, 1);
+       cur_trans->num_joined = 0;
+       init_waitqueue_head(&cur_trans->writer_wait);
+       init_waitqueue_head(&cur_trans->commit_wait);
+       cur_trans->in_commit = 0;
+       cur_trans->blocked = 0;
+       /*
+        * One for this trans handle, one so it will live on until we
+        * commit the transaction.
+        */
+       atomic_set(&cur_trans->use_count, 2);
+       cur_trans->commit_done = 0;
+       cur_trans->start_time = get_seconds();
+
+       cur_trans->delayed_refs.root = RB_ROOT;
+       cur_trans->delayed_refs.num_entries = 0;
+       cur_trans->delayed_refs.num_heads_ready = 0;
+       cur_trans->delayed_refs.num_heads = 0;
+       cur_trans->delayed_refs.flushing = 0;
+       cur_trans->delayed_refs.run_delayed_start = 0;
+       spin_lock_init(&cur_trans->commit_lock);
+       spin_lock_init(&cur_trans->delayed_refs.lock);
+
+       INIT_LIST_HEAD(&cur_trans->pending_snapshots);
+       list_add_tail(&cur_trans->list, &root->fs_info->trans_list);
+       extent_io_tree_init(&cur_trans->dirty_pages,
+                            root->fs_info->btree_inode->i_mapping);
+       root->fs_info->generation++;
+       cur_trans->transid = root->fs_info->generation;
+       root->fs_info->running_transaction = cur_trans;
+       spin_unlock(&root->fs_info->trans_lock);
 
        return 0;
 }
@@ -99,36 +126,82 @@ static noinline int join_transaction(struct btrfs_root *root)
  * to make sure the old root from before we joined the transaction is deleted
  * when the transaction commits
  */
-static noinline int record_root_in_trans(struct btrfs_trans_handle *trans,
-                                        struct btrfs_root *root)
+static int record_root_in_trans(struct btrfs_trans_handle *trans,
+                              struct btrfs_root *root)
 {
        if (root->ref_cows && root->last_trans < trans->transid) {
                WARN_ON(root == root->fs_info->extent_root);
                WARN_ON(root->commit_root != root->node);
 
+               /*
+                * see below for in_trans_setup usage rules
+                * we have the reloc mutex held now, so there
+                * is only one writer in this function
+                */
+               root->in_trans_setup = 1;
+
+               /* make sure readers find in_trans_setup before
+                * they find our root->last_trans update
+                */
+               smp_wmb();
+
+               spin_lock(&root->fs_info->fs_roots_radix_lock);
+               if (root->last_trans == trans->transid) {
+                       spin_unlock(&root->fs_info->fs_roots_radix_lock);
+                       return 0;
+               }
                radix_tree_tag_set(&root->fs_info->fs_roots_radix,
                           (unsigned long)root->root_key.objectid,
                           BTRFS_ROOT_TRANS_TAG);
+               spin_unlock(&root->fs_info->fs_roots_radix_lock);
                root->last_trans = trans->transid;
+
+               /* this is pretty tricky.  We don't want to
+                * take the relocation lock in btrfs_record_root_in_trans
+                * unless we're really doing the first setup for this root in
+                * this transaction.
+                *
+                * Normally we'd use root->last_trans as a flag to decide
+                * if we want to take the expensive mutex.
+                *
+                * But, we have to set root->last_trans before we
+                * init the relocation root, otherwise, we trip over warnings
+                * in ctree.c.  The solution used here is to flag ourselves
+                * with root->in_trans_setup.  When this is 1, we're still
+                * fixing up the reloc trees and everyone must wait.
+                *
+                * When this is zero, they can trust root->last_trans and fly
+                * through btrfs_record_root_in_trans without having to take the
+                * lock.  smp_wmb() makes sure that all the writes above are
+                * done before we pop in the zero below
+                */
                btrfs_init_reloc_root(trans, root);
+               smp_wmb();
+               root->in_trans_setup = 0;
        }
        return 0;
 }
 
+
 int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans,
                               struct btrfs_root *root)
 {
        if (!root->ref_cows)
                return 0;
 
-       mutex_lock(&root->fs_info->trans_mutex);
-       if (root->last_trans == trans->transid) {
-               mutex_unlock(&root->fs_info->trans_mutex);
+       /*
+        * see record_root_in_trans for comments about in_trans_setup usage
+        * and barriers
+        */
+       smp_rmb();
+       if (root->last_trans == trans->transid &&
+           !root->in_trans_setup)
                return 0;
-       }
 
+       mutex_lock(&root->fs_info->reloc_mutex);
        record_root_in_trans(trans, root);
-       mutex_unlock(&root->fs_info->trans_mutex);
+       mutex_unlock(&root->fs_info->reloc_mutex);
+
        return 0;
 }
 
@@ -140,21 +213,23 @@ static void wait_current_trans(struct btrfs_root *root)
 {
        struct btrfs_transaction *cur_trans;
 
+       spin_lock(&root->fs_info->trans_lock);
        cur_trans = root->fs_info->running_transaction;
        if (cur_trans && cur_trans->blocked) {
                DEFINE_WAIT(wait);
                atomic_inc(&cur_trans->use_count);
+               spin_unlock(&root->fs_info->trans_lock);
                while (1) {
                        prepare_to_wait(&root->fs_info->transaction_wait, &wait,
                                        TASK_UNINTERRUPTIBLE);
                        if (!cur_trans->blocked)
                                break;
-                       mutex_unlock(&root->fs_info->trans_mutex);
                        schedule();
-                       mutex_lock(&root->fs_info->trans_mutex);
                }
                finish_wait(&root->fs_info->transaction_wait, &wait);
                put_transaction(cur_trans);
+       } else {
+               spin_unlock(&root->fs_info->trans_lock);
        }
 }
 
@@ -167,10 +242,16 @@ enum btrfs_trans_type {
 
 static int may_wait_transaction(struct btrfs_root *root, int type)
 {
-       if (!root->fs_info->log_root_recovering &&
-           ((type == TRANS_START && !root->fs_info->open_ioctl_trans) ||
-            type == TRANS_USERSPACE))
+       if (root->fs_info->log_root_recovering)
+               return 0;
+
+       if (type == TRANS_USERSPACE)
+               return 1;
+
+       if (type == TRANS_START &&
+           !atomic_read(&root->fs_info->open_ioctl_trans))
                return 1;
+
        return 0;
 }
 
@@ -184,36 +265,44 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
 
        if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
                return ERR_PTR(-EROFS);
+
+       if (current->journal_info) {
+               WARN_ON(type != TRANS_JOIN && type != TRANS_JOIN_NOLOCK);
+               h = current->journal_info;
+               h->use_count++;
+               h->orig_rsv = h->block_rsv;
+               h->block_rsv = NULL;
+               goto got_it;
+       }
 again:
        h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS);
        if (!h)
                return ERR_PTR(-ENOMEM);
 
-       if (type != TRANS_JOIN_NOLOCK)
-               mutex_lock(&root->fs_info->trans_mutex);
        if (may_wait_transaction(root, type))
                wait_current_trans(root);
 
-       ret = join_transaction(root);
+       do {
+               ret = join_transaction(root, type == TRANS_JOIN_NOLOCK);
+               if (ret == -EBUSY)
+                       wait_current_trans(root);
+       } while (ret == -EBUSY);
+
        if (ret < 0) {
                kmem_cache_free(btrfs_trans_handle_cachep, h);
-               if (type != TRANS_JOIN_NOLOCK)
-                       mutex_unlock(&root->fs_info->trans_mutex);
                return ERR_PTR(ret);
        }
 
        cur_trans = root->fs_info->running_transaction;
-       atomic_inc(&cur_trans->use_count);
-       if (type != TRANS_JOIN_NOLOCK)
-               mutex_unlock(&root->fs_info->trans_mutex);
 
        h->transid = cur_trans->transid;
        h->transaction = cur_trans;
        h->blocks_used = 0;
-       h->block_group = 0;
        h->bytes_reserved = 0;
        h->delayed_ref_updates = 0;
+       h->use_count = 1;
        h->block_rsv = NULL;
+       h->orig_rsv = NULL;
 
        smp_mb();
        if (cur_trans->blocked && may_wait_transaction(root, type)) {
@@ -241,11 +330,8 @@ again:
                }
        }
 
-       if (type != TRANS_JOIN_NOLOCK)
-               mutex_lock(&root->fs_info->trans_mutex);
-       record_root_in_trans(h, root);
-       if (type != TRANS_JOIN_NOLOCK)
-               mutex_unlock(&root->fs_info->trans_mutex);
+got_it:
+       btrfs_record_root_in_trans(h, root);
 
        if (!current->journal_info && type != TRANS_USERSPACE)
                current->journal_info = h;
@@ -257,22 +343,19 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
 {
        return start_transaction(root, num_items, TRANS_START);
 }
-struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root,
-                                                  int num_blocks)
+struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root)
 {
        return start_transaction(root, 0, TRANS_JOIN);
 }
 
-struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root,
-                                                         int num_blocks)
+struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root)
 {
        return start_transaction(root, 0, TRANS_JOIN_NOLOCK);
 }
 
-struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *r,
-                                                        int num_blocks)
+struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root)
 {
-       return start_transaction(r, 0, TRANS_USERSPACE);
+       return start_transaction(root, 0, TRANS_USERSPACE);
 }
 
 /* wait for a transaction commit to be fully complete */
@@ -280,17 +363,13 @@ static noinline int wait_for_commit(struct btrfs_root *root,
                                    struct btrfs_transaction *commit)
 {
        DEFINE_WAIT(wait);
-       mutex_lock(&root->fs_info->trans_mutex);
        while (!commit->commit_done) {
                prepare_to_wait(&commit->commit_wait, &wait,
                                TASK_UNINTERRUPTIBLE);
                if (commit->commit_done)
                        break;
-               mutex_unlock(&root->fs_info->trans_mutex);
                schedule();
-               mutex_lock(&root->fs_info->trans_mutex);
        }
-       mutex_unlock(&root->fs_info->trans_mutex);
        finish_wait(&commit->commit_wait, &wait);
        return 0;
 }
@@ -300,102 +379,56 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid)
        struct btrfs_transaction *cur_trans = NULL, *t;
        int ret;
 
-       mutex_lock(&root->fs_info->trans_mutex);
-
        ret = 0;
        if (transid) {
                if (transid <= root->fs_info->last_trans_committed)
-                       goto out_unlock;
+                       goto out;
 
                /* find specified transaction */
+               spin_lock(&root->fs_info->trans_lock);
                list_for_each_entry(t, &root->fs_info->trans_list, list) {
                        if (t->transid == transid) {
                                cur_trans = t;
+                               atomic_inc(&cur_trans->use_count);
                                break;
                        }
                        if (t->transid > transid)
                                break;
                }
+               spin_unlock(&root->fs_info->trans_lock);
                ret = -EINVAL;
                if (!cur_trans)
-                       goto out_unlock;  /* bad transid */
+                       goto out;  /* bad transid */
        } else {
                /* find newest transaction that is committing | committed */
+               spin_lock(&root->fs_info->trans_lock);
                list_for_each_entry_reverse(t, &root->fs_info->trans_list,
                                            list) {
                        if (t->in_commit) {
                                if (t->commit_done)
-                                       goto out_unlock;
+                                       break;
                                cur_trans = t;
+                               atomic_inc(&cur_trans->use_count);
                                break;
                        }
                }
+               spin_unlock(&root->fs_info->trans_lock);
                if (!cur_trans)
-                       goto out_unlock;  /* nothing committing|committed */
+                       goto out;  /* nothing committing|committed */
        }
 
-       atomic_inc(&cur_trans->use_count);
-       mutex_unlock(&root->fs_info->trans_mutex);
-
        wait_for_commit(root, cur_trans);
 
-       mutex_lock(&root->fs_info->trans_mutex);
        put_transaction(cur_trans);
        ret = 0;
-out_unlock:
-       mutex_unlock(&root->fs_info->trans_mutex);
+out:
        return ret;
 }
 
-#if 0
-/*
- * rate limit against the drop_snapshot code.  This helps to slow down new
- * operations if the drop_snapshot code isn't able to keep up.
- */
-static void throttle_on_drops(struct btrfs_root *root)
-{
-       struct btrfs_fs_info *info = root->fs_info;
-       int harder_count = 0;
-
-harder:
-       if (atomic_read(&info->throttles)) {
-               DEFINE_WAIT(wait);
-               int thr;
-               thr = atomic_read(&info->throttle_gen);
-
-               do {
-                       prepare_to_wait(&info->transaction_throttle,
-                                       &wait, TASK_UNINTERRUPTIBLE);
-                       if (!atomic_read(&info->throttles)) {
-                               finish_wait(&info->transaction_throttle, &wait);
-                               break;
-                       }
-                       schedule();
-                       finish_wait(&info->transaction_throttle, &wait);
-               } while (thr == atomic_read(&info->throttle_gen));
-               harder_count++;
-
-               if (root->fs_info->total_ref_cache_size > 1 * 1024 * 1024 &&
-                   harder_count < 2)
-                       goto harder;
-
-               if (root->fs_info->total_ref_cache_size > 5 * 1024 * 1024 &&
-                   harder_count < 10)
-                       goto harder;
-
-               if (root->fs_info->total_ref_cache_size > 10 * 1024 * 1024 &&
-                   harder_count < 20)
-                       goto harder;
-       }
-}
-#endif
-
 void btrfs_throttle(struct btrfs_root *root)
 {
-       mutex_lock(&root->fs_info->trans_mutex);
-       if (!root->fs_info->open_ioctl_trans)
+       if (!atomic_read(&root->fs_info->open_ioctl_trans))
                wait_current_trans(root);
-       mutex_unlock(&root->fs_info->trans_mutex);
 }
 
 static int should_end_transaction(struct btrfs_trans_handle *trans,
@@ -413,6 +446,7 @@ int btrfs_should_end_transaction(struct btrfs_trans_handle *trans,
        struct btrfs_transaction *cur_trans = trans->transaction;
        int updates;
 
+       smp_mb();
        if (cur_trans->blocked || cur_trans->delayed_refs.flushing)
                return 1;
 
@@ -431,6 +465,11 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
        struct btrfs_fs_info *info = root->fs_info;
        int count = 0;
 
+       if (--trans->use_count) {
+               trans->block_rsv = trans->orig_rsv;
+               return 0;
+       }
+
        while (count < 4) {
                unsigned long cur = trans->delayed_ref_updates;
                trans->delayed_ref_updates = 0;
@@ -453,9 +492,11 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
 
        btrfs_trans_release_metadata(trans, root);
 
-       if (lock && !root->fs_info->open_ioctl_trans &&
-           should_end_transaction(trans, root))
+       if (lock && !atomic_read(&root->fs_info->open_ioctl_trans) &&
+           should_end_transaction(trans, root)) {
                trans->transaction->blocked = 1;
+               smp_wmb();
+       }
 
        if (lock && cur_trans->blocked && !cur_trans->in_commit) {
                if (throttle)
@@ -487,19 +528,40 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
 int btrfs_end_transaction(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root)
 {
-       return __btrfs_end_transaction(trans, root, 0, 1);
+       int ret;
+
+       ret = __btrfs_end_transaction(trans, root, 0, 1);
+       if (ret)
+               return ret;
+       return 0;
 }
 
 int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root)
 {
-       return __btrfs_end_transaction(trans, root, 1, 1);
+       int ret;
+
+       ret = __btrfs_end_transaction(trans, root, 1, 1);
+       if (ret)
+               return ret;
+       return 0;
 }
 
 int btrfs_end_transaction_nolock(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root)
 {
-       return __btrfs_end_transaction(trans, root, 0, 0);
+       int ret;
+
+       ret = __btrfs_end_transaction(trans, root, 0, 0);
+       if (ret)
+               return ret;
+       return 0;
+}
+
+int btrfs_end_transaction_dmeta(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root)
+{
+       return __btrfs_end_transaction(trans, root, 1, 1);
 }
 
 /*
@@ -725,9 +787,9 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
  */
 int btrfs_add_dead_root(struct btrfs_root *root)
 {
-       mutex_lock(&root->fs_info->trans_mutex);
+       spin_lock(&root->fs_info->trans_lock);
        list_add(&root->root_list, &root->fs_info->dead_roots);
-       mutex_unlock(&root->fs_info->trans_mutex);
+       spin_unlock(&root->fs_info->trans_lock);
        return 0;
 }
 
@@ -743,6 +805,7 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,
        int ret;
        int err = 0;
 
+       spin_lock(&fs_info->fs_roots_radix_lock);
        while (1) {
                ret = radix_tree_gang_lookup_tag(&fs_info->fs_roots_radix,
                                                 (void **)gang, 0,
@@ -755,13 +818,20 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,
                        radix_tree_tag_clear(&fs_info->fs_roots_radix,
                                        (unsigned long)root->root_key.objectid,
                                        BTRFS_ROOT_TRANS_TAG);
+                       spin_unlock(&fs_info->fs_roots_radix_lock);
 
                        btrfs_free_log(trans, root);
                        btrfs_update_reloc_root(trans, root);
                        btrfs_orphan_commit_root(trans, root);
 
+                       btrfs_save_ino_cache(root, trans);
+
                        if (root->commit_root != root->node) {
+                               mutex_lock(&root->fs_commit_mutex);
                                switch_commit_root(root);
+                               btrfs_unpin_free_ino(root);
+                               mutex_unlock(&root->fs_commit_mutex);
+
                                btrfs_set_root_node(&root->root_item,
                                                    root->node);
                        }
@@ -769,10 +839,12 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,
                        err = btrfs_update_root(trans, fs_info->tree_root,
                                                &root->root_key,
                                                &root->root_item);
+                       spin_lock(&fs_info->fs_roots_radix_lock);
                        if (err)
                                break;
                }
        }
+       spin_unlock(&fs_info->fs_roots_radix_lock);
        return err;
 }
 
@@ -802,104 +874,13 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly)
                btrfs_btree_balance_dirty(info->tree_root, nr);
                cond_resched();
 
-               if (root->fs_info->closing || ret != -EAGAIN)
+               if (btrfs_fs_closing(root->fs_info) || ret != -EAGAIN)
                        break;
        }
        root->defrag_running = 0;
        return ret;
 }
 
-#if 0
-/*
- * when dropping snapshots, we generate a ton of delayed refs, and it makes
- * sense not to join the transaction while it is trying to flush the current
- * queue of delayed refs out.
- *
- * This is used by the drop snapshot code only
- */
-static noinline int wait_transaction_pre_flush(struct btrfs_fs_info *info)
-{
-       DEFINE_WAIT(wait);
-
-       mutex_lock(&info->trans_mutex);
-       while (info->running_transaction &&
-              info->running_transaction->delayed_refs.flushing) {
-               prepare_to_wait(&info->transaction_wait, &wait,
-                               TASK_UNINTERRUPTIBLE);
-               mutex_unlock(&info->trans_mutex);
-
-               schedule();
-
-               mutex_lock(&info->trans_mutex);
-               finish_wait(&info->transaction_wait, &wait);
-       }
-       mutex_unlock(&info->trans_mutex);
-       return 0;
-}
-
-/*
- * Given a list of roots that need to be deleted, call btrfs_drop_snapshot on
- * all of them
- */
-int btrfs_drop_dead_root(struct btrfs_root *root)
-{
-       struct btrfs_trans_handle *trans;
-       struct btrfs_root *tree_root = root->fs_info->tree_root;
-       unsigned long nr;
-       int ret;
-
-       while (1) {
-               /*
-                * we don't want to jump in and create a bunch of
-                * delayed refs if the transaction is starting to close
-                */
-               wait_transaction_pre_flush(tree_root->fs_info);
-               trans = btrfs_start_transaction(tree_root, 1);
-
-               /*
-                * we've joined a transaction, make sure it isn't
-                * closing right now
-                */
-               if (trans->transaction->delayed_refs.flushing) {
-                       btrfs_end_transaction(trans, tree_root);
-                       continue;
-               }
-
-               ret = btrfs_drop_snapshot(trans, root);
-               if (ret != -EAGAIN)
-                       break;
-
-               ret = btrfs_update_root(trans, tree_root,
-                                       &root->root_key,
-                                       &root->root_item);
-               if (ret)
-                       break;
-
-               nr = trans->blocks_used;
-               ret = btrfs_end_transaction(trans, tree_root);
-               BUG_ON(ret);
-
-               btrfs_btree_balance_dirty(tree_root, nr);
-               cond_resched();
-       }
-       BUG_ON(ret);
-
-       ret = btrfs_del_root(trans, tree_root, &root->root_key);
-       BUG_ON(ret);
-
-       nr = trans->blocks_used;
-       ret = btrfs_end_transaction(trans, tree_root);
-       BUG_ON(ret);
-
-       free_extent_buffer(root->node);
-       free_extent_buffer(root->commit_root);
-       kfree(root);
-
-       btrfs_btree_balance_dirty(tree_root, nr);
-       return ret;
-}
-#endif
-
 /*
  * new snapshots need to be created at a very specific time in the
  * transaction commit.  This does the actual creation
@@ -930,7 +911,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
                goto fail;
        }
 
-       ret = btrfs_find_free_objectid(trans, tree_root, 0, &objectid);
+       ret = btrfs_find_free_objectid(tree_root, &objectid);
        if (ret) {
                pending->error = ret;
                goto fail;
@@ -967,7 +948,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        BUG_ON(ret);
        ret = btrfs_insert_dir_item(trans, parent_root,
                                dentry->d_name.name, dentry->d_name.len,
-                               parent_inode->i_ino, &key,
+                               parent_inode, &key,
                                BTRFS_FT_DIR, index);
        BUG_ON(ret);
 
@@ -976,6 +957,15 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        ret = btrfs_update_inode(trans, parent_root, parent_inode);
        BUG_ON(ret);
 
+       /*
+        * pull in the delayed directory update
+        * and the delayed inode item
+        * otherwise we corrupt the FS during
+        * snapshot
+        */
+       ret = btrfs_run_delayed_items(trans, root);
+       BUG_ON(ret);
+
        record_root_in_trans(trans, root);
        btrfs_set_root_last_snapshot(&root->root_item, trans->transid);
        memcpy(new_root_item, &root->root_item, sizeof(*new_root_item));
@@ -1009,7 +999,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
         */
        ret = btrfs_add_root_ref(trans, tree_root, objectid,
                                 parent_root->root_key.objectid,
-                                parent_inode->i_ino, index,
+                                btrfs_ino(parent_inode), index,
                                 dentry->d_name.name, dentry->d_name.len);
        BUG_ON(ret);
        dput(parent);
@@ -1066,20 +1056,20 @@ static void update_super_roots(struct btrfs_root *root)
 int btrfs_transaction_in_commit(struct btrfs_fs_info *info)
 {
        int ret = 0;
-       spin_lock(&info->new_trans_lock);
+       spin_lock(&info->trans_lock);
        if (info->running_transaction)
                ret = info->running_transaction->in_commit;
-       spin_unlock(&info->new_trans_lock);
+       spin_unlock(&info->trans_lock);
        return ret;
 }
 
 int btrfs_transaction_blocked(struct btrfs_fs_info *info)
 {
        int ret = 0;
-       spin_lock(&info->new_trans_lock);
+       spin_lock(&info->trans_lock);
        if (info->running_transaction)
                ret = info->running_transaction->blocked;
-       spin_unlock(&info->new_trans_lock);
+       spin_unlock(&info->trans_lock);
        return ret;
 }
 
@@ -1103,9 +1093,7 @@ static void wait_current_trans_commit_start(struct btrfs_root *root,
                                    &wait);
                        break;
                }
-               mutex_unlock(&root->fs_info->trans_mutex);
                schedule();
-               mutex_lock(&root->fs_info->trans_mutex);
                finish_wait(&root->fs_info->transaction_blocked_wait, &wait);
        }
 }
@@ -1131,9 +1119,7 @@ static void wait_current_trans_commit_start_and_unblock(struct btrfs_root *root,
                                    &wait);
                        break;
                }
-               mutex_unlock(&root->fs_info->trans_mutex);
                schedule();
-               mutex_lock(&root->fs_info->trans_mutex);
                finish_wait(&root->fs_info->transaction_wait,
                            &wait);
        }
@@ -1171,7 +1157,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
 
        INIT_DELAYED_WORK(&ac->work, do_async_commit);
        ac->root = root;
-       ac->newtrans = btrfs_join_transaction(root, 0);
+       ac->newtrans = btrfs_join_transaction(root);
        if (IS_ERR(ac->newtrans)) {
                int err = PTR_ERR(ac->newtrans);
                kfree(ac);
@@ -1179,23 +1165,22 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
        }
 
        /* take transaction reference */
-       mutex_lock(&root->fs_info->trans_mutex);
        cur_trans = trans->transaction;
        atomic_inc(&cur_trans->use_count);
-       mutex_unlock(&root->fs_info->trans_mutex);
 
        btrfs_end_transaction(trans, root);
        schedule_delayed_work(&ac->work, 0);
 
        /* wait for transaction to start and unblock */
-       mutex_lock(&root->fs_info->trans_mutex);
        if (wait_for_unblock)
                wait_current_trans_commit_start_and_unblock(root, cur_trans);
        else
                wait_current_trans_commit_start(root, cur_trans);
-       put_transaction(cur_trans);
-       mutex_unlock(&root->fs_info->trans_mutex);
 
+       if (current->journal_info == trans)
+               current->journal_info = NULL;
+
+       put_transaction(cur_trans);
        return 0;
 }
 
@@ -1238,38 +1223,41 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        ret = btrfs_run_delayed_refs(trans, root, 0);
        BUG_ON(ret);
 
-       mutex_lock(&root->fs_info->trans_mutex);
+       spin_lock(&cur_trans->commit_lock);
        if (cur_trans->in_commit) {
+               spin_unlock(&cur_trans->commit_lock);
                atomic_inc(&cur_trans->use_count);
-               mutex_unlock(&root->fs_info->trans_mutex);
                btrfs_end_transaction(trans, root);
 
                ret = wait_for_commit(root, cur_trans);
                BUG_ON(ret);
 
-               mutex_lock(&root->fs_info->trans_mutex);
                put_transaction(cur_trans);
-               mutex_unlock(&root->fs_info->trans_mutex);
 
                return 0;
        }
 
        trans->transaction->in_commit = 1;
        trans->transaction->blocked = 1;
+       spin_unlock(&cur_trans->commit_lock);
        wake_up(&root->fs_info->transaction_blocked_wait);
 
+       spin_lock(&root->fs_info->trans_lock);
        if (cur_trans->list.prev != &root->fs_info->trans_list) {
                prev_trans = list_entry(cur_trans->list.prev,
                                        struct btrfs_transaction, list);
                if (!prev_trans->commit_done) {
                        atomic_inc(&prev_trans->use_count);
-                       mutex_unlock(&root->fs_info->trans_mutex);
+                       spin_unlock(&root->fs_info->trans_lock);
 
                        wait_for_commit(root, prev_trans);
 
-                       mutex_lock(&root->fs_info->trans_mutex);
                        put_transaction(prev_trans);
+               } else {
+                       spin_unlock(&root->fs_info->trans_lock);
                }
+       } else {
+               spin_unlock(&root->fs_info->trans_lock);
        }
 
        if (now < cur_trans->start_time || now - cur_trans->start_time < 1)
@@ -1277,12 +1265,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        do {
                int snap_pending = 0;
+
                joined = cur_trans->num_joined;
                if (!list_empty(&trans->transaction->pending_snapshots))
                        snap_pending = 1;
 
                WARN_ON(cur_trans != trans->transaction);
-               mutex_unlock(&root->fs_info->trans_mutex);
 
                if (flush_on_commit || snap_pending) {
                        btrfs_start_delalloc_inodes(root, 1);
@@ -1290,6 +1278,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                        BUG_ON(ret);
                }
 
+               ret = btrfs_run_delayed_items(trans, root);
+               BUG_ON(ret);
+
                /*
                 * rename don't use btrfs_join_transaction, so, once we
                 * set the transaction to blocked above, we aren't going
@@ -1302,25 +1293,51 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                prepare_to_wait(&cur_trans->writer_wait, &wait,
                                TASK_UNINTERRUPTIBLE);
 
-               smp_mb();
                if (atomic_read(&cur_trans->num_writers) > 1)
                        schedule_timeout(MAX_SCHEDULE_TIMEOUT);
                else if (should_grow)
                        schedule_timeout(1);
 
-               mutex_lock(&root->fs_info->trans_mutex);
                finish_wait(&cur_trans->writer_wait, &wait);
        } while (atomic_read(&cur_trans->num_writers) > 1 ||
                 (should_grow && cur_trans->num_joined != joined));
 
+       /*
+        * Ok now we need to make sure to block out any other joins while we
+        * commit the transaction.  We could have started a join before setting
+        * no_join so make sure to wait for num_writers to == 1 again.
+        */
+       spin_lock(&root->fs_info->trans_lock);
+       root->fs_info->trans_no_join = 1;
+       spin_unlock(&root->fs_info->trans_lock);
+       wait_event(cur_trans->writer_wait,
+                  atomic_read(&cur_trans->num_writers) == 1);
+
+       /*
+        * the reloc mutex makes sure that we stop
+        * the balancing code from coming in and moving
+        * extents around in the middle of the commit
+        */
+       mutex_lock(&root->fs_info->reloc_mutex);
+
+       ret = btrfs_run_delayed_items(trans, root);
+       BUG_ON(ret);
+
        ret = create_pending_snapshots(trans, root->fs_info);
        BUG_ON(ret);
 
        ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
        BUG_ON(ret);
 
+       /*
+        * make sure none of the code above managed to slip in a
+        * delayed item
+        */
+       btrfs_assert_delayed_root_empty(root);
+
        WARN_ON(cur_trans != trans->transaction);
 
+       btrfs_scrub_pause(root);
        /* btrfs_commit_tree_roots is responsible for getting the
         * various roots consistent with each other.  Every pointer
         * in the tree of tree roots has to point to the most up to date
@@ -1350,9 +1367,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        btrfs_prepare_extent_commit(trans, root);
 
        cur_trans = root->fs_info->running_transaction;
-       spin_lock(&root->fs_info->new_trans_lock);
-       root->fs_info->running_transaction = NULL;
-       spin_unlock(&root->fs_info->new_trans_lock);
 
        btrfs_set_root_node(&root->fs_info->tree_root->root_item,
                            root->fs_info->tree_root->node);
@@ -1373,10 +1387,14 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
               sizeof(root->fs_info->super_copy));
 
        trans->transaction->blocked = 0;
+       spin_lock(&root->fs_info->trans_lock);
+       root->fs_info->running_transaction = NULL;
+       root->fs_info->trans_no_join = 0;
+       spin_unlock(&root->fs_info->trans_lock);
+       mutex_unlock(&root->fs_info->reloc_mutex);
 
        wake_up(&root->fs_info->transaction_wait);
 
-       mutex_unlock(&root->fs_info->trans_mutex);
        ret = btrfs_write_and_wait_transaction(trans, root);
        BUG_ON(ret);
        write_ctree_super(trans, root, 0);
@@ -1389,21 +1407,22 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        btrfs_finish_extent_commit(trans, root);
 
-       mutex_lock(&root->fs_info->trans_mutex);
-
        cur_trans->commit_done = 1;
 
        root->fs_info->last_trans_committed = cur_trans->transid;
 
        wake_up(&cur_trans->commit_wait);
 
+       spin_lock(&root->fs_info->trans_lock);
        list_del_init(&cur_trans->list);
+       spin_unlock(&root->fs_info->trans_lock);
+
        put_transaction(cur_trans);
        put_transaction(cur_trans);
 
        trace_btrfs_transaction_commit(root);
 
-       mutex_unlock(&root->fs_info->trans_mutex);
+       btrfs_scrub_continue(root);
 
        if (current->journal_info == trans)
                current->journal_info = NULL;
@@ -1424,14 +1443,16 @@ int btrfs_clean_old_snapshots(struct btrfs_root *root)
        LIST_HEAD(list);
        struct btrfs_fs_info *fs_info = root->fs_info;
 
-       mutex_lock(&fs_info->trans_mutex);
+       spin_lock(&fs_info->trans_lock);
        list_splice_init(&fs_info->dead_roots, &list);
-       mutex_unlock(&fs_info->trans_mutex);
+       spin_unlock(&fs_info->trans_lock);
 
        while (!list_empty(&list)) {
                root = list_entry(list.next, struct btrfs_root, root_list);
                list_del(&root->root_list);
 
+               btrfs_kill_all_delayed_nodes(root);
+
                if (btrfs_header_backref_rev(root->node) <
                    BTRFS_MIXED_BACKREF_REV)
                        btrfs_drop_snapshot(root, NULL, 0);
index e441acc6c584a7e03859d3e63cd3e455312ff631..02564e6230acd672b5fa6539cc88890417204e41 100644 (file)
@@ -28,10 +28,12 @@ struct btrfs_transaction {
         * transaction can end
         */
        atomic_t num_writers;
+       atomic_t use_count;
 
        unsigned long num_joined;
+
+       spinlock_t commit_lock;
        int in_commit;
-       atomic_t use_count;
        int commit_done;
        int blocked;
        struct list_head list;
@@ -45,13 +47,14 @@ struct btrfs_transaction {
 
 struct btrfs_trans_handle {
        u64 transid;
-       u64 block_group;
        u64 bytes_reserved;
+       unsigned long use_count;
        unsigned long blocks_reserved;
        unsigned long blocks_used;
        unsigned long delayed_ref_updates;
        struct btrfs_transaction *transaction;
        struct btrfs_block_rsv *block_rsv;
+       struct btrfs_block_rsv *orig_rsv;
 };
 
 struct btrfs_pending_snapshot {
@@ -66,19 +69,6 @@ struct btrfs_pending_snapshot {
        struct list_head list;
 };
 
-static inline void btrfs_set_trans_block_group(struct btrfs_trans_handle *trans,
-                                              struct inode *inode)
-{
-       trans->block_group = BTRFS_I(inode)->block_group;
-}
-
-static inline void btrfs_update_inode_block_group(
-                                         struct btrfs_trans_handle *trans,
-                                         struct inode *inode)
-{
-       BTRFS_I(inode)->block_group = trans->block_group;
-}
-
 static inline void btrfs_set_inode_last_trans(struct btrfs_trans_handle *trans,
                                              struct inode *inode)
 {
@@ -92,20 +82,14 @@ int btrfs_end_transaction_nolock(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root);
 struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
                                                   int num_items);
-struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root,
-                                                 int num_blocks);
-struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root,
-                                                         int num_blocks);
-struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *r,
-                                                        int num_blocks);
+struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root);
+struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root);
+struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root);
 int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid);
 int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root);
-int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
-                           struct btrfs_root *root);
 
 int btrfs_add_dead_root(struct btrfs_root *root);
-int btrfs_drop_dead_root(struct btrfs_root *root);
 int btrfs_defrag_root(struct btrfs_root *root, int cacheonly);
 int btrfs_clean_old_snapshots(struct btrfs_root *root);
 int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
@@ -115,6 +99,8 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
                                   int wait_for_unblock);
 int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root);
+int btrfs_end_transaction_dmeta(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root);
 int btrfs_should_end_transaction(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root);
 void btrfs_throttle(struct btrfs_root *root);
index 992ab425599d10bfe0b32e866b9c4bd366a1a9b9..3b580ee8ab1ddc01eb06028c8790c815562c977a 100644 (file)
@@ -97,7 +97,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
                ret = 0;
                goto out;
        }
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        wret = btrfs_search_slot(trans, root, &key, path, 0, 1);
 
        if (wret < 0) {
index f997ec0c1ba4b8efb6b46f88160de43cda3da4f2..4ce8a9f41d1ec3916753bd610183a82b4dc6aa21 100644 (file)
@@ -333,13 +333,13 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
                        goto insert;
 
                if (item_size == 0) {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        return 0;
                }
                dst_copy = kmalloc(item_size, GFP_NOFS);
                src_copy = kmalloc(item_size, GFP_NOFS);
                if (!dst_copy || !src_copy) {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        kfree(dst_copy);
                        kfree(src_copy);
                        return -ENOMEM;
@@ -361,13 +361,13 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
                 * sync
                 */
                if (ret == 0) {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        return 0;
                }
 
        }
 insert:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        /* try to insert the key into the destination tree */
        ret = btrfs_insert_empty_item(trans, root, path,
                                      key, item_size);
@@ -382,7 +382,6 @@ insert:
                } else if (found_size < item_size) {
                        ret = btrfs_extend_item(trans, root, path,
                                                item_size - found_size);
-                       BUG_ON(ret);
                }
        } else if (ret) {
                return ret;
@@ -438,7 +437,7 @@ insert:
        }
 no_copy:
        btrfs_mark_buffer_dirty(path->nodes[0]);
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        return 0;
 }
 
@@ -519,7 +518,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
         * file.  This must be done before the btrfs_drop_extents run
         * so we don't try to drop this extent.
         */
-       ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino,
+       ret = btrfs_lookup_file_extent(trans, root, path, btrfs_ino(inode),
                                       start, 0);
 
        if (ret == 0 &&
@@ -544,11 +543,11 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
                 * we don't have to do anything
                 */
                if (memcmp(&cmp1, &cmp2, sizeof(cmp1)) == 0) {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        goto out;
                }
        }
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        saved_nbytes = inode_get_bytes(inode);
        /* drop any overlapping extents */
@@ -590,6 +589,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
                                                ins.objectid, ins.offset,
                                                0, root->root_key.objectid,
                                                key->objectid, offset);
+                               BUG_ON(ret);
                        } else {
                                /*
                                 * insert the extent pointer in the extent
@@ -600,7 +600,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
                                                key->objectid, offset, &ins);
                                BUG_ON(ret);
                        }
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
 
                        if (btrfs_file_extent_compression(eb, item)) {
                                csum_start = ins.objectid;
@@ -614,7 +614,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
 
                        ret = btrfs_lookup_csums_range(root->log_root,
                                                csum_start, csum_end - 1,
-                                               &ordered_sums);
+                                               &ordered_sums, 0);
                        BUG_ON(ret);
                        while (!list_empty(&ordered_sums)) {
                                struct btrfs_ordered_sum *sums;
@@ -629,7 +629,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
                                kfree(sums);
                        }
                } else {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                }
        } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
                /* inline extents are easy, we just overwrite them */
@@ -675,10 +675,13 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
                return -ENOMEM;
 
        read_extent_buffer(leaf, name, (unsigned long)(di + 1), name_len);
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        inode = read_one_inode(root, location.objectid);
-       BUG_ON(!inode);
+       if (!inode) {
+               kfree(name);
+               return -EIO;
+       }
 
        ret = link_to_fixup_dir(trans, root, path, location.objectid);
        BUG_ON(ret);
@@ -713,7 +716,7 @@ static noinline int inode_in_dir(struct btrfs_root *root,
                        goto out;
        } else
                goto out;
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        di = btrfs_lookup_dir_item(NULL, root, path, dirid, name, name_len, 0);
        if (di && !IS_ERR(di)) {
@@ -724,7 +727,7 @@ static noinline int inode_in_dir(struct btrfs_root *root,
                goto out;
        match = 1;
 out:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        return match;
 }
 
@@ -817,7 +820,10 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
                return -ENOENT;
 
        inode = read_one_inode(root, key->objectid);
-       BUG_ON(!inode);
+       if (!inode) {
+               iput(dir);
+               return -EIO;
+       }
 
        ref_ptr = btrfs_item_ptr_offset(eb, slot);
        ref_end = ref_ptr + btrfs_item_size_nr(eb, slot);
@@ -832,7 +838,7 @@ again:
        read_extent_buffer(eb, name, (unsigned long)(ref + 1), namelen);
 
        /* if we already have a perfect match, we're done */
-       if (inode_in_dir(root, path, dir->i_ino, inode->i_ino,
+       if (inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode),
                         btrfs_inode_ref_index(eb, ref),
                         name, namelen)) {
                goto out;
@@ -884,7 +890,7 @@ again:
                        if (!backref_in_log(log, key, victim_name,
                                            victim_name_len)) {
                                btrfs_inc_nlink(inode);
-                               btrfs_release_path(root, path);
+                               btrfs_release_path(path);
 
                                ret = btrfs_unlink_inode(trans, root, dir,
                                                         inode, victim_name,
@@ -901,7 +907,7 @@ again:
                 */
                search_done = 1;
        }
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
 insert:
        /* insert our name */
@@ -922,7 +928,7 @@ out:
        BUG_ON(ret);
 
 out_nowrite:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        iput(dir);
        iput(inode);
        return 0;
@@ -960,8 +966,9 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
        unsigned long ptr;
        unsigned long ptr_end;
        int name_len;
+       u64 ino = btrfs_ino(inode);
 
-       key.objectid = inode->i_ino;
+       key.objectid = ino;
        key.type = BTRFS_INODE_REF_KEY;
        key.offset = (u64)-1;
 
@@ -980,7 +987,7 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
                }
                btrfs_item_key_to_cpu(path->nodes[0], &key,
                                      path->slots[0]);
-               if (key.objectid != inode->i_ino ||
+               if (key.objectid != ino ||
                    key.type != BTRFS_INODE_REF_KEY)
                        break;
                ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]);
@@ -999,9 +1006,9 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
                if (key.offset == 0)
                        break;
                key.offset--;
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
        }
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        if (nlink != inode->i_nlink) {
                inode->i_nlink = nlink;
                btrfs_update_inode(trans, root, inode);
@@ -1011,10 +1018,10 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
        if (inode->i_nlink == 0) {
                if (S_ISDIR(inode->i_mode)) {
                        ret = replay_dir_deletes(trans, root, NULL, path,
-                                                inode->i_ino, 1);
+                                                ino, 1);
                        BUG_ON(ret);
                }
-               ret = insert_orphan_item(trans, root, inode->i_ino);
+               ret = insert_orphan_item(trans, root, ino);
                BUG_ON(ret);
        }
        btrfs_free_path(path);
@@ -1050,11 +1057,13 @@ static noinline int fixup_inode_link_counts(struct btrfs_trans_handle *trans,
                        break;
 
                ret = btrfs_del_item(trans, root, path);
-               BUG_ON(ret);
+               if (ret)
+                       goto out;
 
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                inode = read_one_inode(root, key.offset);
-               BUG_ON(!inode);
+               if (!inode)
+                       return -EIO;
 
                ret = fixup_inode_link_count(trans, root, inode);
                BUG_ON(ret);
@@ -1068,8 +1077,10 @@ static noinline int fixup_inode_link_counts(struct btrfs_trans_handle *trans,
                 */
                key.offset = (u64)-1;
        }
-       btrfs_release_path(root, path);
-       return 0;
+       ret = 0;
+out:
+       btrfs_release_path(path);
+       return ret;
 }
 
 
@@ -1088,7 +1099,8 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans,
        struct inode *inode;
 
        inode = read_one_inode(root, objectid);
-       BUG_ON(!inode);
+       if (!inode)
+               return -EIO;
 
        key.objectid = BTRFS_TREE_LOG_FIXUP_OBJECTID;
        btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY);
@@ -1096,7 +1108,7 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans,
 
        ret = btrfs_insert_empty_item(trans, root, path, &key, 0);
 
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        if (ret == 0) {
                btrfs_inc_nlink(inode);
                btrfs_update_inode(trans, root, inode);
@@ -1175,7 +1187,8 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
        int ret;
 
        dir = read_one_inode(root, key->objectid);
-       BUG_ON(!dir);
+       if (!dir)
+               return -EIO;
 
        name_len = btrfs_dir_name_len(eb, di);
        name = kmalloc(name_len, GFP_NOFS);
@@ -1192,7 +1205,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
                exists = 1;
        else
                exists = 0;
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        if (key->type == BTRFS_DIR_ITEM_KEY) {
                dst_di = btrfs_lookup_dir_item(trans, root, path, key->objectid,
@@ -1205,7 +1218,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
        } else {
                BUG();
        }
-       if (!dst_di || IS_ERR(dst_di)) {
+       if (IS_ERR_OR_NULL(dst_di)) {
                /* we need a sequence number to insert, so we only
                 * do inserts for the BTRFS_DIR_INDEX_KEY types
                 */
@@ -1236,13 +1249,13 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
        if (key->type == BTRFS_DIR_INDEX_KEY)
                goto insert;
 out:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        kfree(name);
        iput(dir);
        return 0;
 
 insert:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        ret = insert_one_name(trans, root, path, key->objectid, key->offset,
                              name, name_len, log_type, &log_key);
 
@@ -1363,7 +1376,7 @@ next:
        *end_ret = found_end;
        ret = 0;
 out:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        return ret;
 }
 
@@ -1426,12 +1439,15 @@ again:
                                                     dir_key->offset,
                                                     name, name_len, 0);
                }
-               if (!log_di || IS_ERR(log_di)) {
+               if (IS_ERR_OR_NULL(log_di)) {
                        btrfs_dir_item_key_to_cpu(eb, di, &location);
-                       btrfs_release_path(root, path);
-                       btrfs_release_path(log, log_path);
+                       btrfs_release_path(path);
+                       btrfs_release_path(log_path);
                        inode = read_one_inode(root, location.objectid);
-                       BUG_ON(!inode);
+                       if (!inode) {
+                               kfree(name);
+                               return -EIO;
+                       }
 
                        ret = link_to_fixup_dir(trans, root,
                                                path, location.objectid);
@@ -1453,7 +1469,7 @@ again:
                        ret = 0;
                        goto out;
                }
-               btrfs_release_path(log, log_path);
+               btrfs_release_path(log_path);
                kfree(name);
 
                ptr = (unsigned long)(di + 1);
@@ -1461,8 +1477,8 @@ again:
        }
        ret = 0;
 out:
-       btrfs_release_path(root, path);
-       btrfs_release_path(log, log_path);
+       btrfs_release_path(path);
+       btrfs_release_path(log_path);
        return ret;
 }
 
@@ -1550,7 +1566,7 @@ again:
                                break;
                        dir_key.offset = found_key.offset + 1;
                }
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                if (range_end == (u64)-1)
                        break;
                range_start = range_end + 1;
@@ -1561,11 +1577,11 @@ next_type:
        if (key_type == BTRFS_DIR_LOG_ITEM_KEY) {
                key_type = BTRFS_DIR_LOG_INDEX_KEY;
                dir_key.type = BTRFS_DIR_INDEX_KEY;
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                goto again;
        }
 out:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        btrfs_free_path(log_path);
        iput(dir);
        return ret;
@@ -2093,7 +2109,9 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
         * the running transaction open, so a full commit can't hop
         * in and cause problems either.
         */
+       btrfs_scrub_pause_super(root);
        write_ctree_super(trans, root->fs_info->tree_root, 1);
+       btrfs_scrub_continue_super(root);
        ret = 0;
 
        mutex_lock(&root->log_mutex);
@@ -2197,6 +2215,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
        int ret;
        int err = 0;
        int bytes_del = 0;
+       u64 dir_ino = btrfs_ino(dir);
 
        if (BTRFS_I(dir)->logged_trans < trans->transid)
                return 0;
@@ -2214,7 +2233,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
                goto out_unlock;
        }
 
-       di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino,
+       di = btrfs_lookup_dir_item(trans, log, path, dir_ino,
                                   name, name_len, -1);
        if (IS_ERR(di)) {
                err = PTR_ERR(di);
@@ -2225,8 +2244,8 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
                bytes_del += name_len;
                BUG_ON(ret);
        }
-       btrfs_release_path(log, path);
-       di = btrfs_lookup_dir_index_item(trans, log, path, dir->i_ino,
+       btrfs_release_path(path);
+       di = btrfs_lookup_dir_index_item(trans, log, path, dir_ino,
                                         index, name, name_len, -1);
        if (IS_ERR(di)) {
                err = PTR_ERR(di);
@@ -2244,10 +2263,10 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
        if (bytes_del) {
                struct btrfs_key key;
 
-               key.objectid = dir->i_ino;
+               key.objectid = dir_ino;
                key.offset = 0;
                key.type = BTRFS_INODE_ITEM_KEY;
-               btrfs_release_path(log, path);
+               btrfs_release_path(path);
 
                ret = btrfs_search_slot(trans, log, &key, path, 0, 1);
                if (ret < 0) {
@@ -2269,7 +2288,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
                        btrfs_mark_buffer_dirty(path->nodes[0]);
                } else
                        ret = 0;
-               btrfs_release_path(log, path);
+               btrfs_release_path(path);
        }
 fail:
        btrfs_free_path(path);
@@ -2303,7 +2322,7 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
        log = root->log_root;
        mutex_lock(&BTRFS_I(inode)->log_mutex);
 
-       ret = btrfs_del_inode_ref(trans, log, name, name_len, inode->i_ino,
+       ret = btrfs_del_inode_ref(trans, log, name, name_len, btrfs_ino(inode),
                                  dirid, &index);
        mutex_unlock(&BTRFS_I(inode)->log_mutex);
        if (ret == -ENOSPC) {
@@ -2344,7 +2363,7 @@ static noinline int insert_dir_log_key(struct btrfs_trans_handle *trans,
                              struct btrfs_dir_log_item);
        btrfs_set_dir_log_end(path->nodes[0], item, last_offset);
        btrfs_mark_buffer_dirty(path->nodes[0]);
-       btrfs_release_path(log, path);
+       btrfs_release_path(path);
        return 0;
 }
 
@@ -2369,13 +2388,14 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
        int nritems;
        u64 first_offset = min_offset;
        u64 last_offset = (u64)-1;
+       u64 ino = btrfs_ino(inode);
 
        log = root->log_root;
-       max_key.objectid = inode->i_ino;
+       max_key.objectid = ino;
        max_key.offset = (u64)-1;
        max_key.type = key_type;
 
-       min_key.objectid = inode->i_ino;
+       min_key.objectid = ino;
        min_key.type = key_type;
        min_key.offset = min_offset;
 
@@ -2388,18 +2408,17 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
         * we didn't find anything from this transaction, see if there
         * is anything at all
         */
-       if (ret != 0 || min_key.objectid != inode->i_ino ||
-           min_key.type != key_type) {
-               min_key.objectid = inode->i_ino;
+       if (ret != 0 || min_key.objectid != ino || min_key.type != key_type) {
+               min_key.objectid = ino;
                min_key.type = key_type;
                min_key.offset = (u64)-1;
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0);
                if (ret < 0) {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        return ret;
                }
-               ret = btrfs_previous_item(root, path, inode->i_ino, key_type);
+               ret = btrfs_previous_item(root, path, ino, key_type);
 
                /* if ret == 0 there are items for this type,
                 * create a range to tell us the last key of this type.
@@ -2417,7 +2436,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
        }
 
        /* go backward to find any previous key */
-       ret = btrfs_previous_item(root, path, inode->i_ino, key_type);
+       ret = btrfs_previous_item(root, path, ino, key_type);
        if (ret == 0) {
                struct btrfs_key tmp;
                btrfs_item_key_to_cpu(path->nodes[0], &tmp, path->slots[0]);
@@ -2432,7 +2451,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
                        }
                }
        }
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        /* find the first key from this transaction again */
        ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0);
@@ -2452,8 +2471,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
                for (i = path->slots[0]; i < nritems; i++) {
                        btrfs_item_key_to_cpu(src, &min_key, i);
 
-                       if (min_key.objectid != inode->i_ino ||
-                           min_key.type != key_type)
+                       if (min_key.objectid != ino || min_key.type != key_type)
                                goto done;
                        ret = overwrite_item(trans, log, dst_path, src, i,
                                             &min_key);
@@ -2474,7 +2492,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
                        goto done;
                }
                btrfs_item_key_to_cpu(path->nodes[0], &tmp, path->slots[0]);
-               if (tmp.objectid != inode->i_ino || tmp.type != key_type) {
+               if (tmp.objectid != ino || tmp.type != key_type) {
                        last_offset = (u64)-1;
                        goto done;
                }
@@ -2490,8 +2508,8 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
                }
        }
 done:
-       btrfs_release_path(root, path);
-       btrfs_release_path(log, dst_path);
+       btrfs_release_path(path);
+       btrfs_release_path(dst_path);
 
        if (err == 0) {
                *last_offset_ret = last_offset;
@@ -2500,8 +2518,7 @@ done:
                 * is valid
                 */
                ret = insert_dir_log_key(trans, log, path, key_type,
-                                        inode->i_ino, first_offset,
-                                        last_offset);
+                                        ino, first_offset, last_offset);
                if (ret)
                        err = ret;
        }
@@ -2587,10 +2604,11 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans,
                        break;
 
                ret = btrfs_del_item(trans, log, path);
-               BUG_ON(ret);
-               btrfs_release_path(log, path);
+               if (ret)
+                       break;
+               btrfs_release_path(path);
        }
-       btrfs_release_path(log, path);
+       btrfs_release_path(path);
        return ret;
 }
 
@@ -2665,6 +2683,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
                        extent = btrfs_item_ptr(src, start_slot + i,
                                                struct btrfs_file_extent_item);
 
+                       if (btrfs_file_extent_generation(src, extent) < trans->transid)
+                               continue;
+
                        found_type = btrfs_file_extent_type(src, extent);
                        if (found_type == BTRFS_FILE_EXTENT_REG ||
                            found_type == BTRFS_FILE_EXTENT_PREALLOC) {
@@ -2689,14 +2710,14 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
                                ret = btrfs_lookup_csums_range(
                                                log->fs_info->csum_root,
                                                ds + cs, ds + cs + cl - 1,
-                                               &ordered_sums);
+                                               &ordered_sums, 0);
                                BUG_ON(ret);
                        }
                }
        }
 
        btrfs_mark_buffer_dirty(dst_path->nodes[0]);
-       btrfs_release_path(log, dst_path);
+       btrfs_release_path(dst_path);
        kfree(ins_data);
 
        /*
@@ -2745,6 +2766,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
        int nritems;
        int ins_start_slot = 0;
        int ins_nr;
+       u64 ino = btrfs_ino(inode);
 
        log = root->log_root;
 
@@ -2757,11 +2779,11 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                return -ENOMEM;
        }
 
-       min_key.objectid = inode->i_ino;
+       min_key.objectid = ino;
        min_key.type = BTRFS_INODE_ITEM_KEY;
        min_key.offset = 0;
 
-       max_key.objectid = inode->i_ino;
+       max_key.objectid = ino;
 
        /* today the code can only do partial logging of directories */
        if (!S_ISDIR(inode->i_mode))
@@ -2773,6 +2795,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                max_key.type = (u8)-1;
        max_key.offset = (u64)-1;
 
+       ret = btrfs_commit_inode_delayed_items(trans, inode);
+       if (ret) {
+               btrfs_free_path(path);
+               btrfs_free_path(dst_path);
+               return ret;
+       }
+
        mutex_lock(&BTRFS_I(inode)->log_mutex);
 
        /*
@@ -2784,8 +2813,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
 
                if (inode_only == LOG_INODE_EXISTS)
                        max_key_type = BTRFS_XATTR_ITEM_KEY;
-               ret = drop_objectid_items(trans, log, path,
-                                         inode->i_ino, max_key_type);
+               ret = drop_objectid_items(trans, log, path, ino, max_key_type);
        } else {
                ret = btrfs_truncate_inode_items(trans, log, inode, 0, 0);
        }
@@ -2803,7 +2831,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                        break;
 again:
                /* note, ins_nr might be > 0 here, cleanup outside the loop */
-               if (min_key.objectid != inode->i_ino)
+               if (min_key.objectid != ino)
                        break;
                if (min_key.type > max_key.type)
                        break;
@@ -2845,7 +2873,7 @@ next_slot:
                        }
                        ins_nr = 0;
                }
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
 
                if (min_key.offset < (u64)-1)
                        min_key.offset++;
@@ -2868,8 +2896,8 @@ next_slot:
        }
        WARN_ON(ins_nr);
        if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) {
-               btrfs_release_path(root, path);
-               btrfs_release_path(log, dst_path);
+               btrfs_release_path(path);
+               btrfs_release_path(dst_path);
                ret = log_directory_changes(trans, root, inode, path, dst_path);
                if (ret) {
                        err = ret;
@@ -3136,7 +3164,7 @@ again:
                }
                btrfs_item_key_to_cpu(path->nodes[0], &found_key,
                                      path->slots[0]);
-               btrfs_release_path(log_root_tree, path);
+               btrfs_release_path(path);
                if (found_key.objectid != BTRFS_TREE_LOG_OBJECTID)
                        break;
 
@@ -3149,7 +3177,7 @@ again:
                tmp_key.offset = (u64)-1;
 
                wc.replay_dest = btrfs_read_fs_root_no_name(fs_info, &tmp_key);
-               BUG_ON(!wc.replay_dest);
+               BUG_ON(IS_ERR_OR_NULL(wc.replay_dest));
 
                wc.replay_dest->log_root = log;
                btrfs_record_root_in_trans(trans, wc.replay_dest);
@@ -3171,7 +3199,7 @@ again:
                if (found_key.offset == 0)
                        break;
        }
-       btrfs_release_path(log_root_tree, path);
+       btrfs_release_path(path);
 
        /* step one is to pin it all, step two is to replay just inodes */
        if (wc.pin) {
index 3dfae84c8cc8bc1fada072bb45a3676dcedb323d..2270ac58d7469849c748de5bf55aa96ece38f7a2 100644 (file)
@@ -38,7 +38,6 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
                               struct btrfs_root *root,
                               const char *name, int name_len,
                               struct inode *inode, u64 dirid);
-int btrfs_join_running_log_trans(struct btrfs_root *root);
 int btrfs_end_log_trans(struct btrfs_root *root);
 int btrfs_pin_log_trans(struct btrfs_root *root);
 int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
diff --git a/fs/btrfs/version.sh b/fs/btrfs/version.sh
deleted file mode 100644 (file)
index 1ca1952..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/bin/bash
-#
-# determine-version -- report a useful version for releases
-#
-# Copyright 2008, Aron Griffis <agriffis@n01se.net>
-# Copyright 2008, Oracle
-# Released under the GNU GPLv2
-v="v0.16"
-
-which git &> /dev/null
-if [ $? == 0 ]; then
-    git branch >& /dev/null
-    if [ $? == 0 ]; then
-           if head=`git rev-parse --verify HEAD 2>/dev/null`; then
-               if tag=`git describe --tags 2>/dev/null`; then
-                   v="$tag"
-               fi
-
-               # Are there uncommitted changes?
-               git update-index --refresh --unmerged > /dev/null
-               if git diff-index --name-only HEAD | \
-                   grep -v "^scripts/package" \
-                   | read dummy; then
-                   v="$v"-dirty
-               fi
-           fi
-    fi
-fi
-echo "#ifndef __BUILD_VERSION" > .build-version.h
-echo "#define __BUILD_VERSION" >> .build-version.h
-echo "#define BTRFS_BUILD_VERSION \"Btrfs $v\"" >> .build-version.h
-echo "#endif" >> .build-version.h
-
-diff -q version.h .build-version.h >& /dev/null
-
-if [ $? == 0 ]; then
-    rm .build-version.h
-    exit 0
-fi
-
-mv .build-version.h version.h
index c7367ae5a3e6d9427add05ebf8a594ae92e81d5b..1efa56e18f9b905ceac4dbcb3faa0221ab331ce2 100644 (file)
@@ -38,22 +38,9 @@ static int init_first_rw_device(struct btrfs_trans_handle *trans,
                                struct btrfs_device *device);
 static int btrfs_relocate_sys_chunks(struct btrfs_root *root);
 
-#define map_lookup_size(n) (sizeof(struct map_lookup) + \
-                           (sizeof(struct btrfs_bio_stripe) * (n)))
-
 static DEFINE_MUTEX(uuid_mutex);
 static LIST_HEAD(fs_uuids);
 
-void btrfs_lock_volumes(void)
-{
-       mutex_lock(&uuid_mutex);
-}
-
-void btrfs_unlock_volumes(void)
-{
-       mutex_unlock(&uuid_mutex);
-}
-
 static void lock_chunks(struct btrfs_root *root)
 {
        mutex_lock(&root->fs_info->chunk_mutex);
@@ -363,7 +350,7 @@ static noinline int device_list_add(const char *path,
                INIT_LIST_HEAD(&device->dev_alloc_list);
 
                mutex_lock(&fs_devices->device_list_mutex);
-               list_add(&device->dev_list, &fs_devices->devices);
+               list_add_rcu(&device->dev_list, &fs_devices->devices);
                mutex_unlock(&fs_devices->device_list_mutex);
 
                device->fs_devices = fs_devices;
@@ -406,7 +393,7 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)
        fs_devices->latest_trans = orig->latest_trans;
        memcpy(fs_devices->fsid, orig->fsid, sizeof(fs_devices->fsid));
 
-       mutex_lock(&orig->device_list_mutex);
+       /* We have held the volume lock, it is safe to get the devices. */
        list_for_each_entry(orig_dev, &orig->devices, dev_list) {
                device = kzalloc(sizeof(*device), GFP_NOFS);
                if (!device)
@@ -429,10 +416,8 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)
                device->fs_devices = fs_devices;
                fs_devices->num_devices++;
        }
-       mutex_unlock(&orig->device_list_mutex);
        return fs_devices;
 error:
-       mutex_unlock(&orig->device_list_mutex);
        free_fs_devices(fs_devices);
        return ERR_PTR(-ENOMEM);
 }
@@ -443,7 +428,7 @@ int btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices)
 
        mutex_lock(&uuid_mutex);
 again:
-       mutex_lock(&fs_devices->device_list_mutex);
+       /* This is the initialized path, it is safe to release the devices. */
        list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
                if (device->in_fs_metadata)
                        continue;
@@ -463,7 +448,6 @@ again:
                kfree(device->name);
                kfree(device);
        }
-       mutex_unlock(&fs_devices->device_list_mutex);
 
        if (fs_devices->seed) {
                fs_devices = fs_devices->seed;
@@ -474,6 +458,29 @@ again:
        return 0;
 }
 
+static void __free_device(struct work_struct *work)
+{
+       struct btrfs_device *device;
+
+       device = container_of(work, struct btrfs_device, rcu_work);
+
+       if (device->bdev)
+               blkdev_put(device->bdev, device->mode);
+
+       kfree(device->name);
+       kfree(device);
+}
+
+static void free_device(struct rcu_head *head)
+{
+       struct btrfs_device *device;
+
+       device = container_of(head, struct btrfs_device, rcu);
+
+       INIT_WORK(&device->rcu_work, __free_device);
+       schedule_work(&device->rcu_work);
+}
+
 static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
 {
        struct btrfs_device *device;
@@ -481,20 +488,32 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
        if (--fs_devices->opened > 0)
                return 0;
 
+       mutex_lock(&fs_devices->device_list_mutex);
        list_for_each_entry(device, &fs_devices->devices, dev_list) {
-               if (device->bdev) {
-                       blkdev_put(device->bdev, device->mode);
+               struct btrfs_device *new_device;
+
+               if (device->bdev)
                        fs_devices->open_devices--;
-               }
+
                if (device->writeable) {
                        list_del_init(&device->dev_alloc_list);
                        fs_devices->rw_devices--;
                }
 
-               device->bdev = NULL;
-               device->writeable = 0;
-               device->in_fs_metadata = 0;
+               new_device = kmalloc(sizeof(*new_device), GFP_NOFS);
+               BUG_ON(!new_device);
+               memcpy(new_device, device, sizeof(*new_device));
+               new_device->name = kstrdup(device->name, GFP_NOFS);
+               BUG_ON(device->name && !new_device->name);
+               new_device->bdev = NULL;
+               new_device->writeable = 0;
+               new_device->in_fs_metadata = 0;
+               list_replace_rcu(&device->dev_list, &new_device->dev_list);
+
+               call_rcu(&device->rcu, free_device);
        }
+       mutex_unlock(&fs_devices->device_list_mutex);
+
        WARN_ON(fs_devices->open_devices);
        WARN_ON(fs_devices->rw_devices);
        fs_devices->opened = 0;
@@ -597,6 +616,7 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
                        list_add(&device->dev_alloc_list,
                                 &fs_devices->alloc_list);
                }
+               brelse(bh);
                continue;
 
 error_brelse:
@@ -669,12 +689,8 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
        transid = btrfs_super_generation(disk_super);
        if (disk_super->label[0])
                printk(KERN_INFO "device label %s ", disk_super->label);
-       else {
-               /* FIXME, make a readl uuid parser */
-               printk(KERN_INFO "device fsid %llx-%llx ",
-                      *(unsigned long long *)disk_super->fsid,
-                      *(unsigned long long *)(disk_super->fsid + 8));
-       }
+       else
+               printk(KERN_INFO "device fsid %pU ", disk_super->fsid);
        printk(KERN_CONT "devid %llu transid %llu %s\n",
               (unsigned long long)devid, (unsigned long long)transid, path);
        ret = device_list_add(path, disk_super, devid, fs_devices_ret);
@@ -815,10 +831,7 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans,
        /* we don't want to overwrite the superblock on the drive,
         * so we make sure to start at an offset of at least 1MB
         */
-       search_start = 1024 * 1024;
-
-       if (root->fs_info->alloc_start + num_bytes <= search_end)
-               search_start = max(root->fs_info->alloc_start, search_start);
+       search_start = max(root->fs_info->alloc_start, 1024ull * 1024);
 
        max_hole_start = search_start;
        max_hole_size = 0;
@@ -949,14 +962,14 @@ static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,
        if (ret > 0) {
                ret = btrfs_previous_item(root, path, key.objectid,
                                          BTRFS_DEV_EXTENT_KEY);
-               BUG_ON(ret);
+               if (ret)
+                       goto out;
                leaf = path->nodes[0];
                btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
                extent = btrfs_item_ptr(leaf, path->slots[0],
                                        struct btrfs_dev_extent);
                BUG_ON(found_key.offset > start || found_key.offset +
                       btrfs_dev_extent_length(leaf, extent) < start);
-               ret = 0;
        } else if (ret == 0) {
                leaf = path->nodes[0];
                extent = btrfs_item_ptr(leaf, path->slots[0],
@@ -967,8 +980,8 @@ static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,
        if (device->bytes_used > 0)
                device->bytes_used -= btrfs_dev_extent_length(leaf, extent);
        ret = btrfs_del_item(trans, root, path);
-       BUG_ON(ret);
 
+out:
        btrfs_free_path(path);
        return ret;
 }
@@ -1203,11 +1216,13 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
        struct block_device *bdev;
        struct buffer_head *bh = NULL;
        struct btrfs_super_block *disk_super;
+       struct btrfs_fs_devices *cur_devices;
        u64 all_avail;
        u64 devid;
        u64 num_devices;
        u8 *dev_uuid;
        int ret = 0;
+       bool clear_super = false;
 
        mutex_lock(&uuid_mutex);
        mutex_lock(&root->fs_info->volume_mutex);
@@ -1238,14 +1253,16 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
 
                device = NULL;
                devices = &root->fs_info->fs_devices->devices;
-               mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
+               /*
+                * It is safe to read the devices since the volume_mutex
+                * is held.
+                */
                list_for_each_entry(tmp, devices, dev_list) {
                        if (tmp->in_fs_metadata && !tmp->bdev) {
                                device = tmp;
                                break;
                        }
                }
-               mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
                bdev = NULL;
                bh = NULL;
                disk_super = NULL;
@@ -1287,8 +1304,11 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
        }
 
        if (device->writeable) {
+               lock_chunks(root);
                list_del_init(&device->dev_alloc_list);
+               unlock_chunks(root);
                root->fs_info->fs_devices->rw_devices--;
+               clear_super = true;
        }
 
        ret = btrfs_shrink_device(device, 0);
@@ -1300,15 +1320,17 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
                goto error_undo;
 
        device->in_fs_metadata = 0;
+       btrfs_scrub_cancel_dev(root, device);
 
        /*
         * the device list mutex makes sure that we don't change
         * the device list while someone else is writing out all
         * the device supers.
         */
+
+       cur_devices = device->fs_devices;
        mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
-       list_del_init(&device->dev_list);
-       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+       list_del_rcu(&device->dev_list);
 
        device->fs_devices->num_devices--;
 
@@ -1322,34 +1344,36 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
        if (device->bdev == root->fs_info->fs_devices->latest_bdev)
                root->fs_info->fs_devices->latest_bdev = next_device->bdev;
 
-       if (device->bdev) {
-               blkdev_put(device->bdev, device->mode);
-               device->bdev = NULL;
+       if (device->bdev)
                device->fs_devices->open_devices--;
-       }
+
+       call_rcu(&device->rcu, free_device);
+       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
 
        num_devices = btrfs_super_num_devices(&root->fs_info->super_copy) - 1;
        btrfs_set_super_num_devices(&root->fs_info->super_copy, num_devices);
 
-       if (device->fs_devices->open_devices == 0) {
+       if (cur_devices->open_devices == 0) {
                struct btrfs_fs_devices *fs_devices;
                fs_devices = root->fs_info->fs_devices;
                while (fs_devices) {
-                       if (fs_devices->seed == device->fs_devices)
+                       if (fs_devices->seed == cur_devices)
                                break;
                        fs_devices = fs_devices->seed;
                }
-               fs_devices->seed = device->fs_devices->seed;
-               device->fs_devices->seed = NULL;
-               __btrfs_close_devices(device->fs_devices);
-               free_fs_devices(device->fs_devices);
+               fs_devices->seed = cur_devices->seed;
+               cur_devices->seed = NULL;
+               lock_chunks(root);
+               __btrfs_close_devices(cur_devices);
+               unlock_chunks(root);
+               free_fs_devices(cur_devices);
        }
 
        /*
         * at this point, the device is zero sized.  We want to
         * remove it from the devices list and zero out the old super
         */
-       if (device->writeable) {
+       if (clear_super) {
                /* make sure this device isn't detected as part of
                 * the FS anymore
                 */
@@ -1358,8 +1382,6 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
                sync_dirty_buffer(bh);
        }
 
-       kfree(device->name);
-       kfree(device);
        ret = 0;
 
 error_brelse:
@@ -1373,8 +1395,10 @@ out:
        return ret;
 error_undo:
        if (device->writeable) {
+               lock_chunks(root);
                list_add(&device->dev_alloc_list,
                         &root->fs_info->fs_devices->alloc_list);
+               unlock_chunks(root);
                root->fs_info->fs_devices->rw_devices++;
        }
        goto error_brelse;
@@ -1414,7 +1438,12 @@ static int btrfs_prepare_sprout(struct btrfs_trans_handle *trans,
        INIT_LIST_HEAD(&seed_devices->devices);
        INIT_LIST_HEAD(&seed_devices->alloc_list);
        mutex_init(&seed_devices->device_list_mutex);
-       list_splice_init(&fs_devices->devices, &seed_devices->devices);
+
+       mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
+       list_splice_init_rcu(&fs_devices->devices, &seed_devices->devices,
+                             synchronize_rcu);
+       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+
        list_splice_init(&fs_devices->alloc_list, &seed_devices->alloc_list);
        list_for_each_entry(device, &seed_devices->devices, dev_list) {
                device->fs_devices = seed_devices;
@@ -1475,7 +1504,7 @@ next_slot:
                                goto error;
                        leaf = path->nodes[0];
                        btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        continue;
                }
 
@@ -1611,7 +1640,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
         * half setup
         */
        mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
-       list_add(&device->dev_list, &root->fs_info->fs_devices->devices);
+       list_add_rcu(&device->dev_list, &root->fs_info->fs_devices->devices);
        list_add(&device->dev_alloc_list,
                 &root->fs_info->fs_devices->alloc_list);
        root->fs_info->fs_devices->num_devices++;
@@ -1769,10 +1798,9 @@ static int btrfs_free_chunk(struct btrfs_trans_handle *trans,
        BUG_ON(ret);
 
        ret = btrfs_del_item(trans, root, path);
-       BUG_ON(ret);
 
        btrfs_free_path(path);
-       return 0;
+       return ret;
 }
 
 static int btrfs_del_sys_chunk(struct btrfs_root *root, u64 chunk_objectid, u64
@@ -1947,7 +1975,7 @@ again:
                chunk = btrfs_item_ptr(leaf, path->slots[0],
                                       struct btrfs_chunk);
                chunk_type = btrfs_chunk_type(leaf, chunk);
-               btrfs_release_path(chunk_root, path);
+               btrfs_release_path(path);
 
                if (chunk_type & BTRFS_BLOCK_GROUP_SYSTEM) {
                        ret = btrfs_relocate_chunk(chunk_root, chunk_tree,
@@ -2065,7 +2093,7 @@ int btrfs_balance(struct btrfs_root *dev_root)
                if (found_key.offset == 0)
                        break;
 
-               btrfs_release_path(chunk_root, path);
+               btrfs_release_path(path);
                ret = btrfs_relocate_chunk(chunk_root,
                                           chunk_root->root_key.objectid,
                                           found_key.objectid,
@@ -2137,7 +2165,7 @@ again:
                        goto done;
                if (ret) {
                        ret = 0;
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        break;
                }
 
@@ -2146,7 +2174,7 @@ again:
                btrfs_item_key_to_cpu(l, &key, path->slots[0]);
 
                if (key.objectid != device->devid) {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        break;
                }
 
@@ -2154,14 +2182,14 @@ again:
                length = btrfs_dev_extent_length(l, dev_extent);
 
                if (key.offset + length <= new_size) {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        break;
                }
 
                chunk_tree = btrfs_dev_extent_chunk_tree(l, dev_extent);
                chunk_objectid = btrfs_dev_extent_chunk_objectid(l, dev_extent);
                chunk_offset = btrfs_dev_extent_chunk_offset(l, dev_extent);
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
 
                ret = btrfs_relocate_chunk(root, chunk_tree, chunk_objectid,
                                           chunk_offset);
@@ -2237,275 +2265,204 @@ static int btrfs_add_system_chunk(struct btrfs_trans_handle *trans,
        return 0;
 }
 
-static noinline u64 chunk_bytes_by_type(u64 type, u64 calc_size,
-                                       int num_stripes, int sub_stripes)
+/*
+ * sort the devices in descending order by max_avail, total_avail
+ */
+static int btrfs_cmp_device_info(const void *a, const void *b)
 {
-       if (type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP))
-               return calc_size;
-       else if (type & BTRFS_BLOCK_GROUP_RAID10)
-               return calc_size * (num_stripes / sub_stripes);
-       else
-               return calc_size * num_stripes;
-}
+       const struct btrfs_device_info *di_a = a;
+       const struct btrfs_device_info *di_b = b;
 
-/* Used to sort the devices by max_avail(descending sort) */
-int btrfs_cmp_device_free_bytes(const void *dev_info1, const void *dev_info2)
-{
-       if (((struct btrfs_device_info *)dev_info1)->max_avail >
-           ((struct btrfs_device_info *)dev_info2)->max_avail)
+       if (di_a->max_avail > di_b->max_avail)
                return -1;
-       else if (((struct btrfs_device_info *)dev_info1)->max_avail <
-                ((struct btrfs_device_info *)dev_info2)->max_avail)
+       if (di_a->max_avail < di_b->max_avail)
                return 1;
-       else
-               return 0;
+       if (di_a->total_avail > di_b->total_avail)
+               return -1;
+       if (di_a->total_avail < di_b->total_avail)
+               return 1;
+       return 0;
 }
 
-static int __btrfs_calc_nstripes(struct btrfs_fs_devices *fs_devices, u64 type,
-                                int *num_stripes, int *min_stripes,
-                                int *sub_stripes)
+static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
+                              struct btrfs_root *extent_root,
+                              struct map_lookup **map_ret,
+                              u64 *num_bytes_out, u64 *stripe_size_out,
+                              u64 start, u64 type)
 {
-       *num_stripes = 1;
-       *min_stripes = 1;
-       *sub_stripes = 0;
+       struct btrfs_fs_info *info = extent_root->fs_info;
+       struct btrfs_fs_devices *fs_devices = info->fs_devices;
+       struct list_head *cur;
+       struct map_lookup *map = NULL;
+       struct extent_map_tree *em_tree;
+       struct extent_map *em;
+       struct btrfs_device_info *devices_info = NULL;
+       u64 total_avail;
+       int num_stripes;        /* total number of stripes to allocate */
+       int sub_stripes;        /* sub_stripes info for map */
+       int dev_stripes;        /* stripes per dev */
+       int devs_max;           /* max devs to use */
+       int devs_min;           /* min devs needed */
+       int devs_increment;     /* ndevs has to be a multiple of this */
+       int ncopies;            /* how many copies to data has */
+       int ret;
+       u64 max_stripe_size;
+       u64 max_chunk_size;
+       u64 stripe_size;
+       u64 num_bytes;
+       int ndevs;
+       int i;
+       int j;
 
-       if (type & (BTRFS_BLOCK_GROUP_RAID0)) {
-               *num_stripes = fs_devices->rw_devices;
-               *min_stripes = 2;
-       }
-       if (type & (BTRFS_BLOCK_GROUP_DUP)) {
-               *num_stripes = 2;
-               *min_stripes = 2;
-       }
-       if (type & (BTRFS_BLOCK_GROUP_RAID1)) {
-               if (fs_devices->rw_devices < 2)
-                       return -ENOSPC;
-               *num_stripes = 2;
-               *min_stripes = 2;
-       }
-       if (type & (BTRFS_BLOCK_GROUP_RAID10)) {
-               *num_stripes = fs_devices->rw_devices;
-               if (*num_stripes < 4)
-                       return -ENOSPC;
-               *num_stripes &= ~(u32)1;
-               *sub_stripes = 2;
-               *min_stripes = 4;
+       if ((type & BTRFS_BLOCK_GROUP_RAID1) &&
+           (type & BTRFS_BLOCK_GROUP_DUP)) {
+               WARN_ON(1);
+               type &= ~BTRFS_BLOCK_GROUP_DUP;
        }
 
-       return 0;
-}
+       if (list_empty(&fs_devices->alloc_list))
+               return -ENOSPC;
 
-static u64 __btrfs_calc_stripe_size(struct btrfs_fs_devices *fs_devices,
-                                   u64 proposed_size, u64 type,
-                                   int num_stripes, int small_stripe)
-{
-       int min_stripe_size = 1 * 1024 * 1024;
-       u64 calc_size = proposed_size;
-       u64 max_chunk_size = calc_size;
-       int ncopies = 1;
+       sub_stripes = 1;
+       dev_stripes = 1;
+       devs_increment = 1;
+       ncopies = 1;
+       devs_max = 0;   /* 0 == as many as possible */
+       devs_min = 1;
 
-       if (type & (BTRFS_BLOCK_GROUP_RAID1 |
-                   BTRFS_BLOCK_GROUP_DUP |
-                   BTRFS_BLOCK_GROUP_RAID10))
+       /*
+        * define the properties of each RAID type.
+        * FIXME: move this to a global table and use it in all RAID
+        * calculation code
+        */
+       if (type & (BTRFS_BLOCK_GROUP_DUP)) {
+               dev_stripes = 2;
                ncopies = 2;
+               devs_max = 1;
+       } else if (type & (BTRFS_BLOCK_GROUP_RAID0)) {
+               devs_min = 2;
+       } else if (type & (BTRFS_BLOCK_GROUP_RAID1)) {
+               devs_increment = 2;
+               ncopies = 2;
+               devs_max = 2;
+               devs_min = 2;
+       } else if (type & (BTRFS_BLOCK_GROUP_RAID10)) {
+               sub_stripes = 2;
+               devs_increment = 2;
+               ncopies = 2;
+               devs_min = 4;
+       } else {
+               devs_max = 1;
+       }
 
        if (type & BTRFS_BLOCK_GROUP_DATA) {
-               max_chunk_size = 10 * calc_size;
-               min_stripe_size = 64 * 1024 * 1024;
+               max_stripe_size = 1024 * 1024 * 1024;
+               max_chunk_size = 10 * max_stripe_size;
        } else if (type & BTRFS_BLOCK_GROUP_METADATA) {
-               max_chunk_size = 256 * 1024 * 1024;
-               min_stripe_size = 32 * 1024 * 1024;
+               max_stripe_size = 256 * 1024 * 1024;
+               max_chunk_size = max_stripe_size;
        } else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
-               calc_size = 8 * 1024 * 1024;
-               max_chunk_size = calc_size * 2;
-               min_stripe_size = 1 * 1024 * 1024;
+               max_stripe_size = 8 * 1024 * 1024;
+               max_chunk_size = 2 * max_stripe_size;
+       } else {
+               printk(KERN_ERR "btrfs: invalid chunk type 0x%llx requested\n",
+                      type);
+               BUG_ON(1);
        }
 
        /* we don't want a chunk larger than 10% of writeable space */
        max_chunk_size = min(div_factor(fs_devices->total_rw_bytes, 1),
                             max_chunk_size);
 
-       if (calc_size * num_stripes > max_chunk_size * ncopies) {
-               calc_size = max_chunk_size * ncopies;
-               do_div(calc_size, num_stripes);
-               do_div(calc_size, BTRFS_STRIPE_LEN);
-               calc_size *= BTRFS_STRIPE_LEN;
-       }
+       devices_info = kzalloc(sizeof(*devices_info) * fs_devices->rw_devices,
+                              GFP_NOFS);
+       if (!devices_info)
+               return -ENOMEM;
 
-       /* we don't want tiny stripes */
-       if (!small_stripe)
-               calc_size = max_t(u64, min_stripe_size, calc_size);
+       cur = fs_devices->alloc_list.next;
 
        /*
-        * we're about to do_div by the BTRFS_STRIPE_LEN so lets make sure
-        * we end up with something bigger than a stripe
+        * in the first pass through the devices list, we gather information
+        * about the available holes on each device.
         */
-       calc_size = max_t(u64, calc_size, BTRFS_STRIPE_LEN);
-
-       do_div(calc_size, BTRFS_STRIPE_LEN);
-       calc_size *= BTRFS_STRIPE_LEN;
-
-       return calc_size;
-}
-
-static struct map_lookup *__shrink_map_lookup_stripes(struct map_lookup *map,
-                                                     int num_stripes)
-{
-       struct map_lookup *new;
-       size_t len = map_lookup_size(num_stripes);
-
-       BUG_ON(map->num_stripes < num_stripes);
-
-       if (map->num_stripes == num_stripes)
-               return map;
-
-       new = kmalloc(len, GFP_NOFS);
-       if (!new) {
-               /* just change map->num_stripes */
-               map->num_stripes = num_stripes;
-               return map;
-       }
-
-       memcpy(new, map, len);
-       new->num_stripes = num_stripes;
-       kfree(map);
-       return new;
-}
+       ndevs = 0;
+       while (cur != &fs_devices->alloc_list) {
+               struct btrfs_device *device;
+               u64 max_avail;
+               u64 dev_offset;
 
-/*
- * helper to allocate device space from btrfs_device_info, in which we stored
- * max free space information of every device. It is used when we can not
- * allocate chunks by default size.
- *
- * By this helper, we can allocate a new chunk as larger as possible.
- */
-static int __btrfs_alloc_tiny_space(struct btrfs_trans_handle *trans,
-                                   struct btrfs_fs_devices *fs_devices,
-                                   struct btrfs_device_info *devices,
-                                   int nr_device, u64 type,
-                                   struct map_lookup **map_lookup,
-                                   int min_stripes, u64 *stripe_size)
-{
-       int i, index, sort_again = 0;
-       int min_devices = min_stripes;
-       u64 max_avail, min_free;
-       struct map_lookup *map = *map_lookup;
-       int ret;
+               device = list_entry(cur, struct btrfs_device, dev_alloc_list);
 
-       if (nr_device < min_stripes)
-               return -ENOSPC;
+               cur = cur->next;
 
-       btrfs_descending_sort_devices(devices, nr_device);
+               if (!device->writeable) {
+                       printk(KERN_ERR
+                              "btrfs: read-only device in alloc_list\n");
+                       WARN_ON(1);
+                       continue;
+               }
 
-       max_avail = devices[0].max_avail;
-       if (!max_avail)
-               return -ENOSPC;
+               if (!device->in_fs_metadata)
+                       continue;
 
-       for (i = 0; i < nr_device; i++) {
-               /*
-                * if dev_offset = 0, it means the free space of this device
-                * is less than what we need, and we didn't search max avail
-                * extent on this device, so do it now.
+               if (device->total_bytes > device->bytes_used)
+                       total_avail = device->total_bytes - device->bytes_used;
+               else
+                       total_avail = 0;
+               /* avail is off by max(alloc_start, 1MB), but that is the same
+                * for all devices, so it doesn't hurt the sorting later on
                 */
-               if (!devices[i].dev_offset) {
-                       ret = find_free_dev_extent(trans, devices[i].dev,
-                                                  max_avail,
-                                                  &devices[i].dev_offset,
-                                                  &devices[i].max_avail);
-                       if (ret != 0 && ret != -ENOSPC)
-                               return ret;
-                       sort_again = 1;
-               }
-       }
 
-       /* we update the max avail free extent of each devices, sort again */
-       if (sort_again)
-               btrfs_descending_sort_devices(devices, nr_device);
-
-       if (type & BTRFS_BLOCK_GROUP_DUP)
-               min_devices = 1;
+               ret = find_free_dev_extent(trans, device,
+                                          max_stripe_size * dev_stripes,
+                                          &dev_offset, &max_avail);
+               if (ret && ret != -ENOSPC)
+                       goto error;
 
-       if (!devices[min_devices - 1].max_avail)
-               return -ENOSPC;
+               if (ret == 0)
+                       max_avail = max_stripe_size * dev_stripes;
 
-       max_avail = devices[min_devices - 1].max_avail;
-       if (type & BTRFS_BLOCK_GROUP_DUP)
-               do_div(max_avail, 2);
+               if (max_avail < BTRFS_STRIPE_LEN * dev_stripes)
+                       continue;
 
-       max_avail = __btrfs_calc_stripe_size(fs_devices, max_avail, type,
-                                            min_stripes, 1);
-       if (type & BTRFS_BLOCK_GROUP_DUP)
-               min_free = max_avail * 2;
-       else
-               min_free = max_avail;
+               devices_info[ndevs].dev_offset = dev_offset;
+               devices_info[ndevs].max_avail = max_avail;
+               devices_info[ndevs].total_avail = total_avail;
+               devices_info[ndevs].dev = device;
+               ++ndevs;
+       }
 
-       if (min_free > devices[min_devices - 1].max_avail)
-               return -ENOSPC;
+       /*
+        * now sort the devices by hole size / available space
+        */
+       sort(devices_info, ndevs, sizeof(struct btrfs_device_info),
+            btrfs_cmp_device_info, NULL);
 
-       map = __shrink_map_lookup_stripes(map, min_stripes);
-       *stripe_size = max_avail;
+       /* round down to number of usable stripes */
+       ndevs -= ndevs % devs_increment;
 
-       index = 0;
-       for (i = 0; i < min_stripes; i++) {
-               map->stripes[i].dev = devices[index].dev;
-               map->stripes[i].physical = devices[index].dev_offset;
-               if (type & BTRFS_BLOCK_GROUP_DUP) {
-                       i++;
-                       map->stripes[i].dev = devices[index].dev;
-                       map->stripes[i].physical = devices[index].dev_offset +
-                                                  max_avail;
-               }
-               index++;
+       if (ndevs < devs_increment * sub_stripes || ndevs < devs_min) {
+               ret = -ENOSPC;
+               goto error;
        }
-       *map_lookup = map;
-
-       return 0;
-}
 
-static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
-                              struct btrfs_root *extent_root,
-                              struct map_lookup **map_ret,
-                              u64 *num_bytes, u64 *stripe_size,
-                              u64 start, u64 type)
-{
-       struct btrfs_fs_info *info = extent_root->fs_info;
-       struct btrfs_device *device = NULL;
-       struct btrfs_fs_devices *fs_devices = info->fs_devices;
-       struct list_head *cur;
-       struct map_lookup *map;
-       struct extent_map_tree *em_tree;
-       struct extent_map *em;
-       struct btrfs_device_info *devices_info;
-       struct list_head private_devs;
-       u64 calc_size = 1024 * 1024 * 1024;
-       u64 min_free;
-       u64 avail;
-       u64 dev_offset;
-       int num_stripes;
-       int min_stripes;
-       int sub_stripes;
-       int min_devices;        /* the min number of devices we need */
-       int i;
-       int ret;
-       int index;
+       if (devs_max && ndevs > devs_max)
+               ndevs = devs_max;
+       /*
+        * the primary goal is to maximize the number of stripes, so use as many
+        * devices as possible, even if the stripes are not maximum sized.
+        */
+       stripe_size = devices_info[ndevs-1].max_avail;
+       num_stripes = ndevs * dev_stripes;
 
-       if ((type & BTRFS_BLOCK_GROUP_RAID1) &&
-           (type & BTRFS_BLOCK_GROUP_DUP)) {
-               WARN_ON(1);
-               type &= ~BTRFS_BLOCK_GROUP_DUP;
+       if (stripe_size * num_stripes > max_chunk_size * ncopies) {
+               stripe_size = max_chunk_size * ncopies;
+               do_div(stripe_size, num_stripes);
        }
-       if (list_empty(&fs_devices->alloc_list))
-               return -ENOSPC;
-
-       ret = __btrfs_calc_nstripes(fs_devices, type, &num_stripes,
-                                   &min_stripes, &sub_stripes);
-       if (ret)
-               return ret;
 
-       devices_info = kzalloc(sizeof(*devices_info) * fs_devices->rw_devices,
-                              GFP_NOFS);
-       if (!devices_info)
-               return -ENOMEM;
+       do_div(stripe_size, dev_stripes);
+       do_div(stripe_size, BTRFS_STRIPE_LEN);
+       stripe_size *= BTRFS_STRIPE_LEN;
 
        map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
        if (!map) {
@@ -2514,85 +2471,12 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
        }
        map->num_stripes = num_stripes;
 
-       cur = fs_devices->alloc_list.next;
-       index = 0;
-       i = 0;
-
-       calc_size = __btrfs_calc_stripe_size(fs_devices, calc_size, type,
-                                            num_stripes, 0);
-
-       if (type & BTRFS_BLOCK_GROUP_DUP) {
-               min_free = calc_size * 2;
-               min_devices = 1;
-       } else {
-               min_free = calc_size;
-               min_devices = min_stripes;
-       }
-
-       INIT_LIST_HEAD(&private_devs);
-       while (index < num_stripes) {
-               device = list_entry(cur, struct btrfs_device, dev_alloc_list);
-               BUG_ON(!device->writeable);
-               if (device->total_bytes > device->bytes_used)
-                       avail = device->total_bytes - device->bytes_used;
-               else
-                       avail = 0;
-               cur = cur->next;
-
-               if (device->in_fs_metadata && avail >= min_free) {
-                       ret = find_free_dev_extent(trans, device, min_free,
-                                                  &devices_info[i].dev_offset,
-                                                  &devices_info[i].max_avail);
-                       if (ret == 0) {
-                               list_move_tail(&device->dev_alloc_list,
-                                              &private_devs);
-                               map->stripes[index].dev = device;
-                               map->stripes[index].physical =
-                                               devices_info[i].dev_offset;
-                               index++;
-                               if (type & BTRFS_BLOCK_GROUP_DUP) {
-                                       map->stripes[index].dev = device;
-                                       map->stripes[index].physical =
-                                               devices_info[i].dev_offset +
-                                               calc_size;
-                                       index++;
-                               }
-                       } else if (ret != -ENOSPC)
-                               goto error;
-
-                       devices_info[i].dev = device;
-                       i++;
-               } else if (device->in_fs_metadata &&
-                          avail >= BTRFS_STRIPE_LEN) {
-                       devices_info[i].dev = device;
-                       devices_info[i].max_avail = avail;
-                       i++;
-               }
-
-               if (cur == &fs_devices->alloc_list)
-                       break;
-       }
-
-       list_splice(&private_devs, &fs_devices->alloc_list);
-       if (index < num_stripes) {
-               if (index >= min_stripes) {
-                       num_stripes = index;
-                       if (type & (BTRFS_BLOCK_GROUP_RAID10)) {
-                               num_stripes /= sub_stripes;
-                               num_stripes *= sub_stripes;
-                       }
-
-                       map = __shrink_map_lookup_stripes(map, num_stripes);
-               } else if (i >= min_devices) {
-                       ret = __btrfs_alloc_tiny_space(trans, fs_devices,
-                                                      devices_info, i, type,
-                                                      &map, min_stripes,
-                                                      &calc_size);
-                       if (ret)
-                               goto error;
-               } else {
-                       ret = -ENOSPC;
-                       goto error;
+       for (i = 0; i < ndevs; ++i) {
+               for (j = 0; j < dev_stripes; ++j) {
+                       int s = i * dev_stripes + j;
+                       map->stripes[s].dev = devices_info[i].dev;
+                       map->stripes[s].physical = devices_info[i].dev_offset +
+                                                  j * stripe_size;
                }
        }
        map->sector_size = extent_root->sectorsize;
@@ -2603,20 +2487,21 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
        map->sub_stripes = sub_stripes;
 
        *map_ret = map;
-       *stripe_size = calc_size;
-       *num_bytes = chunk_bytes_by_type(type, calc_size,
-                                        map->num_stripes, sub_stripes);
+       num_bytes = stripe_size * (num_stripes / ncopies);
 
-       trace_btrfs_chunk_alloc(info->chunk_root, map, start, *num_bytes);
+       *stripe_size_out = stripe_size;
+       *num_bytes_out = num_bytes;
 
-       em = alloc_extent_map(GFP_NOFS);
+       trace_btrfs_chunk_alloc(info->chunk_root, map, start, num_bytes);
+
+       em = alloc_extent_map();
        if (!em) {
                ret = -ENOMEM;
                goto error;
        }
        em->bdev = (struct block_device *)map;
        em->start = start;
-       em->len = *num_bytes;
+       em->len = num_bytes;
        em->block_start = 0;
        em->block_len = em->len;
 
@@ -2629,20 +2514,21 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 
        ret = btrfs_make_block_group(trans, extent_root, 0, type,
                                     BTRFS_FIRST_CHUNK_TREE_OBJECTID,
-                                    start, *num_bytes);
+                                    start, num_bytes);
        BUG_ON(ret);
 
-       index = 0;
-       while (index < map->num_stripes) {
-               device = map->stripes[index].dev;
-               dev_offset = map->stripes[index].physical;
+       for (i = 0; i < map->num_stripes; ++i) {
+               struct btrfs_device *device;
+               u64 dev_offset;
+
+               device = map->stripes[i].dev;
+               dev_offset = map->stripes[i].physical;
 
                ret = btrfs_alloc_dev_extent(trans, device,
                                info->chunk_root->root_key.objectid,
                                BTRFS_FIRST_CHUNK_TREE_OBJECTID,
-                               start, dev_offset, calc_size);
+                               start, dev_offset, stripe_size);
                BUG_ON(ret);
-               index++;
        }
 
        kfree(devices_info);
@@ -2849,7 +2735,7 @@ int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset)
 
 void btrfs_mapping_init(struct btrfs_mapping_tree *tree)
 {
-       extent_map_tree_init(&tree->map_tree, GFP_NOFS);
+       extent_map_tree_init(&tree->map_tree);
 }
 
 void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree)
@@ -3499,7 +3385,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
                free_extent_map(em);
        }
 
-       em = alloc_extent_map(GFP_NOFS);
+       em = alloc_extent_map();
        if (!em)
                return -ENOMEM;
        num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
@@ -3688,15 +3574,6 @@ static int read_one_dev(struct btrfs_root *root,
        return ret;
 }
 
-int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf)
-{
-       struct btrfs_dev_item *dev_item;
-
-       dev_item = (struct btrfs_dev_item *)offsetof(struct btrfs_super_block,
-                                                    dev_item);
-       return read_one_dev(root, buf, dev_item);
-}
-
 int btrfs_read_sys_array(struct btrfs_root *root)
 {
        struct btrfs_super_block *super_copy = &root->fs_info->super_copy;
@@ -3813,7 +3690,7 @@ again:
        }
        if (key.objectid == BTRFS_DEV_ITEMS_OBJECTID) {
                key.objectid = 0;
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                goto again;
        }
        ret = 0;
index cc2eadaf7a27b996af24eaea258b14c5c5c1cfe0..7c12d61ae7aed7936d07886d8abfb4a8028dea4b 100644 (file)
@@ -85,7 +85,12 @@ struct btrfs_device {
        /* physical drive uuid (or lvm uuid) */
        u8 uuid[BTRFS_UUID_SIZE];
 
+       /* per-device scrub information */
+       struct scrub_dev *scrub_device;
+
        struct btrfs_work work;
+       struct rcu_head rcu;
+       struct work_struct rcu_work;
 };
 
 struct btrfs_fs_devices {
@@ -144,6 +149,7 @@ struct btrfs_device_info {
        struct btrfs_device *dev;
        u64 dev_offset;
        u64 max_avail;
+       u64 total_avail;
 };
 
 struct map_lookup {
@@ -157,20 +163,8 @@ struct map_lookup {
        struct btrfs_bio_stripe stripes[];
 };
 
-/* Used to sort the devices by max_avail(descending sort) */
-int btrfs_cmp_device_free_bytes(const void *dev_info1, const void *dev_info2);
-
-/*
- * sort the devices by max_avail, in which max free extent size of each device
- * is stored.(Descending Sort)
- */
-static inline void btrfs_descending_sort_devices(
-                                       struct btrfs_device_info *devices,
-                                       size_t nr_devices)
-{
-       sort(devices, nr_devices, sizeof(struct btrfs_device_info),
-            btrfs_cmp_device_free_bytes, NULL);
-}
+#define map_lookup_size(n) (sizeof(struct map_lookup) + \
+                           (sizeof(struct btrfs_bio_stripe) * (n)))
 
 int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start,
                                   u64 end, u64 *length);
@@ -196,7 +190,6 @@ void btrfs_mapping_init(struct btrfs_mapping_tree *tree);
 void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree);
 int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
                  int mirror_num, int async_submit);
-int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf);
 int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
                       fmode_t flags, void *holder);
 int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
@@ -209,8 +202,6 @@ int btrfs_add_device(struct btrfs_trans_handle *trans,
 int btrfs_rm_device(struct btrfs_root *root, char *device_path);
 int btrfs_cleanup_fs_uuids(void);
 int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len);
-int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree,
-                     u64 logical, struct page *page);
 int btrfs_grow_device(struct btrfs_trans_handle *trans,
                      struct btrfs_device *device, u64 new_size);
 struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid,
@@ -218,8 +209,6 @@ struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid,
 int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
 int btrfs_init_new_device(struct btrfs_root *root, char *path);
 int btrfs_balance(struct btrfs_root *dev_root);
-void btrfs_unlock_volumes(void);
-void btrfs_lock_volumes(void);
 int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
 int find_free_dev_extent(struct btrfs_trans_handle *trans,
                         struct btrfs_device *device, u64 num_bytes,
index cfd660550ded035fd2fad7aadce102aa23fc27fb..5366fe452ab07db7402402e96351c1b956809e20 100644 (file)
@@ -44,7 +44,7 @@ ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
                return -ENOMEM;
 
        /* lookup the xattr by name */
-       di = btrfs_lookup_xattr(NULL, root, path, inode->i_ino, name,
+       di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode), name,
                                strlen(name), 0);
        if (!di) {
                ret = -ENODATA;
@@ -103,7 +103,7 @@ static int do_setxattr(struct btrfs_trans_handle *trans,
                return -ENOMEM;
 
        /* first lets see if we already have this xattr */
-       di = btrfs_lookup_xattr(trans, root, path, inode->i_ino, name,
+       di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode), name,
                                strlen(name), -1);
        if (IS_ERR(di)) {
                ret = PTR_ERR(di);
@@ -120,13 +120,13 @@ static int do_setxattr(struct btrfs_trans_handle *trans,
 
                ret = btrfs_delete_one_dir_name(trans, root, path, di);
                BUG_ON(ret);
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
 
                /* if we don't have a value then we are removing the xattr */
                if (!value)
                        goto out;
        } else {
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
 
                if (flags & XATTR_REPLACE) {
                        /* we couldn't find the attr to replace */
@@ -136,7 +136,7 @@ static int do_setxattr(struct btrfs_trans_handle *trans,
        }
 
        /* ok we have to create a completely new xattr */
-       ret = btrfs_insert_xattr_item(trans, root, path, inode->i_ino,
+       ret = btrfs_insert_xattr_item(trans, root, path, btrfs_ino(inode),
                                      name, name_len, value, size);
        BUG_ON(ret);
 out:
@@ -158,8 +158,6 @@ int __btrfs_setxattr(struct btrfs_trans_handle *trans,
        if (IS_ERR(trans))
                return PTR_ERR(trans);
 
-       btrfs_set_trans_block_group(trans, inode);
-
        ret = do_setxattr(trans, inode, name, value, size, flags);
        if (ret)
                goto out;
@@ -190,7 +188,7 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
         * NOTE: we set key.offset = 0; because we want to start with the
         * first xattr that we find and walk forward
         */
-       key.objectid = inode->i_ino;
+       key.objectid = btrfs_ino(inode);
        btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
        key.offset = 0;
 
index a08bb8e61c6fc275376c9a0748226deb34a6b0f0..1a80b048ade822849b88fb51003e5244c80872f5 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/bitops.h>
 #include <linux/mpage.h>
 #include <linux/bit_spinlock.h>
+#include <linux/cleancache.h>
 
 static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
 
@@ -269,6 +270,10 @@ void invalidate_bdev(struct block_device *bdev)
        invalidate_bh_lrus();
        lru_add_drain_all();    /* make sure all lru add caches are flushed */
        invalidate_mapping_pages(mapping, 0, -1);
+       /* 99% of the time, we don't need to flush the cleancache on the bdev.
+        * But, for the strange corners, lets be cautious
+        */
+       cleancache_flush_inode(mapping);
 }
 EXPORT_SYMBOL(invalidate_bdev);
 
@@ -1897,10 +1902,8 @@ int __block_write_begin(struct page *page, loff_t pos, unsigned len,
                if (!buffer_uptodate(*wait_bh))
                        err = -EIO;
        }
-       if (unlikely(err)) {
+       if (unlikely(err))
                page_zero_new_buffers(page, from, to);
-               ClearPageUptodate(page);
-       }
        return err;
 }
 EXPORT_SYMBOL(__block_write_begin);
@@ -2331,24 +2334,26 @@ EXPORT_SYMBOL(block_commit_write);
  * page lock we can determine safely if the page is beyond EOF. If it is not
  * beyond EOF, then the page is guaranteed safe against truncation until we
  * unlock the page.
+ *
+ * Direct callers of this function should call vfs_check_frozen() so that page
+ * fault does not busyloop until the fs is thawed.
  */
-int
-block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
-                  get_block_t get_block)
+int __block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
+                        get_block_t get_block)
 {
        struct page *page = vmf->page;
        struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
        unsigned long end;
        loff_t size;
-       int ret = VM_FAULT_NOPAGE; /* make the VM retry the fault */
+       int ret;
 
        lock_page(page);
        size = i_size_read(inode);
        if ((page->mapping != inode->i_mapping) ||
            (page_offset(page) > size)) {
-               /* page got truncated out from underneath us */
-               unlock_page(page);
-               goto out;
+               /* We overload EFAULT to mean page got truncated */
+               ret = -EFAULT;
+               goto out_unlock;
        }
 
        /* page is wholly or partially inside EOF */
@@ -2361,18 +2366,42 @@ block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
        if (!ret)
                ret = block_commit_write(page, 0, end);
 
-       if (unlikely(ret)) {
-               unlock_page(page);
-               if (ret == -ENOMEM)
-                       ret = VM_FAULT_OOM;
-               else /* -ENOSPC, -EIO, etc */
-                       ret = VM_FAULT_SIGBUS;
-       } else
-               ret = VM_FAULT_LOCKED;
-
-out:
+       if (unlikely(ret < 0))
+               goto out_unlock;
+       /*
+        * Freezing in progress? We check after the page is marked dirty and
+        * with page lock held so if the test here fails, we are sure freezing
+        * code will wait during syncing until the page fault is done - at that
+        * point page will be dirty and unlocked so freezing code will write it
+        * and writeprotect it again.
+        */
+       set_page_dirty(page);
+       if (inode->i_sb->s_frozen != SB_UNFROZEN) {
+               ret = -EAGAIN;
+               goto out_unlock;
+       }
+       wait_on_page_writeback(page);
+       return 0;
+out_unlock:
+       unlock_page(page);
        return ret;
 }
+EXPORT_SYMBOL(__block_page_mkwrite);
+
+int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
+                  get_block_t get_block)
+{
+       int ret;
+       struct super_block *sb = vma->vm_file->f_path.dentry->d_inode->i_sb;
+
+       /*
+        * This check is racy but catches the common case. The check in
+        * __block_page_mkwrite() is reliable.
+        */
+       vfs_check_frozen(sb, SB_FREEZE_WRITE);
+       ret = __block_page_mkwrite(vma, vmf, get_block);
+       return block_page_mkwrite_return(ret);
+}
 EXPORT_SYMBOL(block_page_mkwrite);
 
 /*
index 38b8ab554924cd2d4a9ddf11ce3a79efe3d411cd..5a3953db81184170a8f221fc6c231996993724d2 100644 (file)
@@ -453,7 +453,7 @@ static int ceph_writepage(struct page *page, struct writeback_control *wbc)
        int err;
        struct inode *inode = page->mapping->host;
        BUG_ON(!inode);
-       igrab(inode);
+       ihold(inode);
        err = writepage_nounlock(page, wbc);
        unlock_page(page);
        iput(inode);
@@ -848,7 +848,8 @@ get_more_pages:
                op->payload_len = cpu_to_le32(len);
                req->r_request->hdr.data_len = cpu_to_le32(len);
 
-               ceph_osdc_start_request(&fsc->client->osdc, req, true);
+               rc = ceph_osdc_start_request(&fsc->client->osdc, req, true);
+               BUG_ON(rc);
                req = NULL;
 
                /* continue? */
@@ -880,8 +881,6 @@ release_pvec_pages:
 out:
        if (req)
                ceph_osdc_put_request(req);
-       if (rc > 0)
-               rc = 0;  /* vfs expects us to return 0 */
        ceph_put_snap_context(snapc);
        dout("writepages done, rc = %d\n", rc);
        return rc;
index 2a5404c1c42f4efd1be78f5d24eed337c24429e3..f605753c8fe9b20aa4d2f165b57534d1d9b3fe78 100644 (file)
@@ -569,7 +569,8 @@ retry:
                list_add_tail(&cap->session_caps, &session->s_caps);
                session->s_nr_caps++;
                spin_unlock(&session->s_cap_lock);
-       }
+       } else if (new_cap)
+               ceph_put_cap(mdsc, new_cap);
 
        if (!ci->i_snap_realm) {
                /*
@@ -2634,6 +2635,7 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex,
                              struct ceph_mds_session *session,
                              int *open_target_sessions)
 {
+       struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
        struct ceph_inode_info *ci = ceph_inode(inode);
        int mds = session->s_mds;
        unsigned mseq = le32_to_cpu(ex->migrate_seq);
@@ -2670,6 +2672,19 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex,
                         * export targets, so that we get the matching IMPORT
                         */
                        *open_target_sessions = 1;
+
+                       /*
+                        * we can't flush dirty caps that we've seen the
+                        * EXPORT but no IMPORT for
+                        */
+                       spin_lock(&mdsc->cap_dirty_lock);
+                       if (!list_empty(&ci->i_dirty_item)) {
+                               dout(" moving %p to cap_dirty_migrating\n",
+                                    inode);
+                               list_move(&ci->i_dirty_item,
+                                         &mdsc->cap_dirty_migrating);
+                       }
+                       spin_unlock(&mdsc->cap_dirty_lock);
                }
                __ceph_remove_cap(cap);
        }
@@ -2707,6 +2722,13 @@ static void handle_cap_import(struct ceph_mds_client *mdsc,
                ci->i_cap_exporting_issued = 0;
                ci->i_cap_exporting_mseq = 0;
                ci->i_cap_exporting_mds = -1;
+
+               spin_lock(&mdsc->cap_dirty_lock);
+               if (!list_empty(&ci->i_dirty_item)) {
+                       dout(" moving %p back to cap_dirty\n", inode);
+                       list_move(&ci->i_dirty_item, &mdsc->cap_dirty);
+               }
+               spin_unlock(&mdsc->cap_dirty_lock);
        } else {
                dout("handle_cap_import inode %p ci %p mds%d mseq %d\n",
                     inode, ci, mds, mseq);
@@ -2910,47 +2932,24 @@ void ceph_check_delayed_caps(struct ceph_mds_client *mdsc)
  */
 void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc)
 {
-       struct ceph_inode_info *ci, *nci = NULL;
-       struct inode *inode, *ninode = NULL;
-       struct list_head *p, *n;
+       struct ceph_inode_info *ci;
+       struct inode *inode;
 
        dout("flush_dirty_caps\n");
        spin_lock(&mdsc->cap_dirty_lock);
-       list_for_each_safe(p, n, &mdsc->cap_dirty) {
-               if (nci) {
-                       ci = nci;
-                       inode = ninode;
-                       ci->i_ceph_flags &= ~CEPH_I_NOFLUSH;
-                       dout("flush_dirty_caps inode %p (was next inode)\n",
-                            inode);
-               } else {
-                       ci = list_entry(p, struct ceph_inode_info,
-                                       i_dirty_item);
-                       inode = igrab(&ci->vfs_inode);
-                       BUG_ON(!inode);
-                       dout("flush_dirty_caps inode %p\n", inode);
-               }
-               if (n != &mdsc->cap_dirty) {
-                       nci = list_entry(n, struct ceph_inode_info,
-                                        i_dirty_item);
-                       ninode = igrab(&nci->vfs_inode);
-                       BUG_ON(!ninode);
-                       nci->i_ceph_flags |= CEPH_I_NOFLUSH;
-                       dout("flush_dirty_caps next inode %p, noflush\n",
-                            ninode);
-               } else {
-                       nci = NULL;
-                       ninode = NULL;
-               }
+       while (!list_empty(&mdsc->cap_dirty)) {
+               ci = list_first_entry(&mdsc->cap_dirty, struct ceph_inode_info,
+                                     i_dirty_item);
+               inode = &ci->vfs_inode;
+               ihold(inode);
+               dout("flush_dirty_caps %p\n", inode);
                spin_unlock(&mdsc->cap_dirty_lock);
-               if (inode) {
-                       ceph_check_caps(ci, CHECK_CAPS_NODELAY|CHECK_CAPS_FLUSH,
-                                       NULL);
-                       iput(inode);
-               }
+               ceph_check_caps(ci, CHECK_CAPS_NODELAY|CHECK_CAPS_FLUSH, NULL);
+               iput(inode);
                spin_lock(&mdsc->cap_dirty_lock);
        }
        spin_unlock(&mdsc->cap_dirty_lock);
+       dout("flush_dirty_caps done\n");
 }
 
 /*
index 1a867a3601aea88ee25c9fadf399d4a2a3472498..ef8f08c343e8936df6f6fd2cde5eb895f93d8f83 100644 (file)
@@ -308,7 +308,8 @@ more:
                req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
                if (IS_ERR(req))
                        return PTR_ERR(req);
-               req->r_inode = igrab(inode);
+               req->r_inode = inode;
+               ihold(inode);
                req->r_dentry = dget(filp->f_dentry);
                /* hints to request -> mds selection code */
                req->r_direct_mode = USE_AUTH_MDS;
@@ -360,7 +361,7 @@ more:
        rinfo = &fi->last_readdir->r_reply_info;
        dout("readdir frag %x num %d off %d chunkoff %d\n", frag,
             rinfo->dir_nr, off, fi->offset);
-       while (off - fi->offset >= 0 && off - fi->offset < rinfo->dir_nr) {
+       while (off >= fi->offset && off - fi->offset < rinfo->dir_nr) {
                u64 pos = ceph_make_fpos(frag, off);
                struct ceph_mds_reply_inode *in =
                        rinfo->dir_in[off - fi->offset].in;
@@ -787,10 +788,12 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir,
        req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
        req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
        err = ceph_mdsc_do_request(mdsc, dir, req);
-       if (err)
+       if (err) {
                d_drop(dentry);
-       else if (!req->r_reply_info.head->is_dentry)
-               d_instantiate(dentry, igrab(old_dentry->d_inode));
+       } else if (!req->r_reply_info.head->is_dentry) {
+               ihold(old_dentry->d_inode);
+               d_instantiate(dentry, old_dentry->d_inode);
+       }
        ceph_mdsc_put_request(req);
        return err;
 }
@@ -1066,16 +1069,17 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size,
        struct inode *inode = file->f_dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
        int left;
+       const int bufsize = 1024;
 
        if (!ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb), DIRSTAT))
                return -EISDIR;
 
        if (!cf->dir_info) {
-               cf->dir_info = kmalloc(1024, GFP_NOFS);
+               cf->dir_info = kmalloc(bufsize, GFP_NOFS);
                if (!cf->dir_info)
                        return -ENOMEM;
                cf->dir_info_len =
-                       sprintf(cf->dir_info,
+                       snprintf(cf->dir_info, bufsize,
                                "entries:   %20lld\n"
                                " files:    %20lld\n"
                                " subdirs:  %20lld\n"
index e41056174bf81ad96397500ad89b19754a9bc0ff..f67b687550dea4cd00e27554650ce892845d4d90 100644 (file)
@@ -86,6 +86,7 @@ static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len,
 static struct dentry *__fh_to_dentry(struct super_block *sb,
                                     struct ceph_nfs_fh *fh)
 {
+       struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
        struct inode *inode;
        struct dentry *dentry;
        struct ceph_vino vino;
@@ -95,8 +96,24 @@ static struct dentry *__fh_to_dentry(struct super_block *sb,
        vino.ino = fh->ino;
        vino.snap = CEPH_NOSNAP;
        inode = ceph_find_inode(sb, vino);
-       if (!inode)
-               return ERR_PTR(-ESTALE);
+       if (!inode) {
+               struct ceph_mds_request *req;
+
+               req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
+                                              USE_ANY_MDS);
+               if (IS_ERR(req))
+                       return ERR_CAST(req);
+
+               req->r_ino1 = vino;
+               req->r_num_caps = 1;
+               err = ceph_mdsc_do_request(mdsc, NULL, req);
+               inode = req->r_target_inode;
+               if (inode)
+                       ihold(inode);
+               ceph_mdsc_put_request(req);
+               if (!inode)
+                       return ERR_PTR(-ESTALE);
+       }
 
        dentry = d_obtain_alias(inode);
        if (IS_ERR(dentry)) {
@@ -148,8 +165,10 @@ static struct dentry *__cfh_to_dentry(struct super_block *sb,
                snprintf(req->r_path2, 16, "%d", cfh->parent_name_hash);
                req->r_num_caps = 1;
                err = ceph_mdsc_do_request(mdsc, NULL, req);
+               inode = req->r_target_inode;
+               if (inode)
+                       ihold(inode);
                ceph_mdsc_put_request(req);
-               inode = ceph_find_inode(sb, vino);
                if (!inode)
                        return ERR_PTR(err ? err : -ESTALE);
        }
index 203252d88d9fa6509d1dd7bfed3e4198c414d906..9542f07d0b9306774e7172afed25b6f809503c06 100644 (file)
@@ -191,7 +191,8 @@ int ceph_open(struct inode *inode, struct file *file)
                err = PTR_ERR(req);
                goto out;
        }
-       req->r_inode = igrab(inode);
+       req->r_inode = inode;
+       ihold(inode);
        req->r_num_caps = 1;
        err = ceph_mdsc_do_request(mdsc, parent_inode, req);
        if (!err)
@@ -282,7 +283,7 @@ int ceph_release(struct inode *inode, struct file *file)
 static int striped_read(struct inode *inode,
                        u64 off, u64 len,
                        struct page **pages, int num_pages,
-                       int *checkeof, bool align_to_pages,
+                       int *checkeof, bool o_direct,
                        unsigned long buf_align)
 {
        struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
@@ -307,7 +308,7 @@ static int striped_read(struct inode *inode,
        io_align = off & ~PAGE_MASK;
 
 more:
-       if (align_to_pages)
+       if (o_direct)
                page_align = (pos - io_align + buf_align) & ~PAGE_MASK;
        else
                page_align = pos & ~PAGE_MASK;
@@ -317,10 +318,10 @@ more:
                                  ci->i_truncate_seq,
                                  ci->i_truncate_size,
                                  page_pos, pages_left, page_align);
-       hit_stripe = this_len < left;
-       was_short = ret >= 0 && ret < this_len;
        if (ret == -ENOENT)
                ret = 0;
+       hit_stripe = this_len < left;
+       was_short = ret >= 0 && ret < this_len;
        dout("striped_read %llu~%u (read %u) got %d%s%s\n", pos, left, read,
             ret, hit_stripe ? " HITSTRIPE" : "", was_short ? " SHORT" : "");
 
@@ -345,20 +346,22 @@ more:
        }
 
        if (was_short) {
-               /* was original extent fully inside i_size? */
-               if (pos + left <= inode->i_size) {
-                       dout("zero tail\n");
-                       ceph_zero_page_vector_range(page_off + read, len - read,
+               /* did we bounce off eof? */
+               if (pos + left > inode->i_size)
+                       *checkeof = 1;
+
+               /* zero trailing bytes (inside i_size) */
+               if (left > 0 && pos < inode->i_size) {
+                       if (pos + left > inode->i_size)
+                               left = inode->i_size - pos;
+
+                       dout("zero tail %d\n", left);
+                       ceph_zero_page_vector_range(page_off + read, left,
                                                    pages);
-                       read = len;
-                       goto out;
+                       read += left;
                }
-
-               /* check i_size */
-               *checkeof = 1;
        }
 
-out:
        if (ret >= 0)
                ret = read;
        dout("striped_read returns %d\n", ret);
@@ -658,7 +661,7 @@ out:
 
                /* hit EOF or hole? */
                if (statret == 0 && *ppos < inode->i_size) {
-                       dout("aio_read sync_read hit hole, reading more\n");
+                       dout("aio_read sync_read hit hole, ppos %lld < size %lld, reading more\n", *ppos, inode->i_size);
                        read += ret;
                        base += ret;
                        len -= ret;
index 70b6a4839c386be5fa4b40b48c3bf6521eda7ca7..d8858e96ab1870d62f1597185f87a2c8fb93f34a 100644 (file)
@@ -1101,10 +1101,10 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
                                goto done;
                        }
                        req->r_dentry = dn;  /* may have spliced */
-                       igrab(in);
+                       ihold(in);
                } else if (ceph_ino(in) == vino.ino &&
                           ceph_snap(in) == vino.snap) {
-                       igrab(in);
+                       ihold(in);
                } else {
                        dout(" %p links to %p %llx.%llx, not %llx.%llx\n",
                             dn, in, ceph_ino(in), ceph_snap(in),
@@ -1144,7 +1144,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
                        goto done;
                }
                req->r_dentry = dn;  /* may have spliced */
-               igrab(in);
+               ihold(in);
                rinfo->head->is_dentry = 1;  /* fool notrace handlers */
        }
 
@@ -1328,7 +1328,7 @@ void ceph_queue_writeback(struct inode *inode)
        if (queue_work(ceph_inode_to_client(inode)->wb_wq,
                       &ceph_inode(inode)->i_wb_work)) {
                dout("ceph_queue_writeback %p\n", inode);
-               igrab(inode);
+               ihold(inode);
        } else {
                dout("ceph_queue_writeback %p failed\n", inode);
        }
@@ -1353,7 +1353,7 @@ void ceph_queue_invalidate(struct inode *inode)
        if (queue_work(ceph_inode_to_client(inode)->pg_inv_wq,
                       &ceph_inode(inode)->i_pg_inv_work)) {
                dout("ceph_queue_invalidate %p\n", inode);
-               igrab(inode);
+               ihold(inode);
        } else {
                dout("ceph_queue_invalidate %p failed\n", inode);
        }
@@ -1477,7 +1477,7 @@ void ceph_queue_vmtruncate(struct inode *inode)
        if (queue_work(ceph_sb_to_client(inode->i_sb)->trunc_wq,
                       &ci->i_vmtruncate_work)) {
                dout("ceph_queue_vmtruncate %p\n", inode);
-               igrab(inode);
+               ihold(inode);
        } else {
                dout("ceph_queue_vmtruncate %p failed, pending=%d\n",
                     inode, ci->i_truncate_pending);
@@ -1738,7 +1738,8 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
                __mark_inode_dirty(inode, inode_dirty_flags);
 
        if (mask) {
-               req->r_inode = igrab(inode);
+               req->r_inode = inode;
+               ihold(inode);
                req->r_inode_drop = release;
                req->r_args.setattr.mask = cpu_to_le32(mask);
                req->r_num_caps = 1;
@@ -1779,7 +1780,8 @@ int ceph_do_getattr(struct inode *inode, int mask)
        req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_GETATTR, USE_ANY_MDS);
        if (IS_ERR(req))
                return PTR_ERR(req);
-       req->r_inode = igrab(inode);
+       req->r_inode = inode;
+       ihold(inode);
        req->r_num_caps = 1;
        req->r_args.getattr.mask = cpu_to_le32(mask);
        err = ceph_mdsc_do_request(mdsc, NULL, req);
index 8888c9ba68dbfec194e06f06142547ee2d35c8bc..ef0b5f48e13ac77a75233a40634d000068c9a21c 100644 (file)
@@ -73,7 +73,8 @@ static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
                                       USE_AUTH_MDS);
        if (IS_ERR(req))
                return PTR_ERR(req);
-       req->r_inode = igrab(inode);
+       req->r_inode = inode;
+       ihold(inode);
        req->r_inode_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL;
 
        req->r_args.setlayout.layout.fl_stripe_unit =
@@ -135,7 +136,8 @@ static long ceph_ioctl_set_layout_policy (struct file *file, void __user *arg)
 
        if (IS_ERR(req))
                return PTR_ERR(req);
-       req->r_inode = igrab(inode);
+       req->r_inode = inode;
+       ihold(inode);
 
        req->r_args.setlayout.layout.fl_stripe_unit =
                        cpu_to_le32(l.stripe_unit);
index 476b329867d41cf2cec7b3e2ad51e5f3885d9d7a..80576d05d687639bc72fb089b6803980500dbbd3 100644 (file)
@@ -23,7 +23,8 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
        req = ceph_mdsc_create_request(mdsc, operation, USE_AUTH_MDS);
        if (IS_ERR(req))
                return PTR_ERR(req);
-       req->r_inode = igrab(inode);
+       req->r_inode = inode;
+       ihold(inode);
 
        /* mds requires start and length rather than start and end */
        if (LLONG_MAX == fl->fl_end)
@@ -32,11 +33,10 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
                length = fl->fl_end - fl->fl_start + 1;
 
        dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, "
-            "length: %llu, wait: %d, type`: %d", (int)lock_type,
+            "length: %llu, wait: %d, type: %d", (int)lock_type,
             (int)operation, (u64)fl->fl_pid, fl->fl_start,
             length, wait, fl->fl_type);
 
-
        req->r_args.filelock_change.rule = lock_type;
        req->r_args.filelock_change.type = cmd;
        req->r_args.filelock_change.pid = cpu_to_le64((u64)fl->fl_pid);
@@ -70,7 +70,7 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
        }
        ceph_mdsc_put_request(req);
        dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, "
-            "length: %llu, wait: %d, type`: %d, err code %d", (int)lock_type,
+            "length: %llu, wait: %d, type: %d, err code %d", (int)lock_type,
             (int)operation, (u64)fl->fl_pid, fl->fl_start,
             length, wait, fl->fl_type, err);
        return err;
@@ -109,16 +109,20 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
                        dout("mds locked, locking locally");
                        err = posix_lock_file(file, fl, NULL);
                        if (err && (CEPH_MDS_OP_SETFILELOCK == op)) {
-                               /* undo! This should only happen if the kernel detects
-                                * local deadlock. */
+                               /* undo! This should only happen if
+                                * the kernel detects local
+                                * deadlock. */
                                ceph_lock_message(CEPH_LOCK_FCNTL, op, file,
                                                  CEPH_LOCK_UNLOCK, 0, fl);
-                               dout("got %d on posix_lock_file, undid lock", err);
+                               dout("got %d on posix_lock_file, undid lock",
+                                    err);
                        }
                }
 
-       } else {
-               dout("mds returned error code %d", err);
+       } else if (err == -ERESTARTSYS) {
+               dout("undoing lock\n");
+               ceph_lock_message(CEPH_LOCK_FCNTL, op, file,
+                                 CEPH_LOCK_UNLOCK, 0, fl);
        }
        return err;
 }
@@ -155,8 +159,11 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
                                          file, CEPH_LOCK_UNLOCK, 0, fl);
                        dout("got %d on flock_lock_file_wait, undid lock", err);
                }
-       } else {
-               dout("mds error code %d", err);
+       } else if (err == -ERESTARTSYS) {
+               dout("undoing lock\n");
+               ceph_lock_message(CEPH_LOCK_FLOCK,
+                                 CEPH_MDS_OP_SETFILELOCK,
+                                 file, CEPH_LOCK_UNLOCK, 0, fl);
        }
        return err;
 }
index d0fae4ce9ba55b704ccedadbfd3f298e3a00cfb4..79743d146be69ec8ce3f279a032e1a5459eb462c 100644 (file)
@@ -578,6 +578,7 @@ static void __register_request(struct ceph_mds_client *mdsc,
        if (dir) {
                struct ceph_inode_info *ci = ceph_inode(dir);
 
+               ihold(dir);
                spin_lock(&ci->i_unsafe_lock);
                req->r_unsafe_dir = dir;
                list_add_tail(&req->r_unsafe_dir_item, &ci->i_unsafe_dirops);
@@ -598,6 +599,9 @@ static void __unregister_request(struct ceph_mds_client *mdsc,
                spin_lock(&ci->i_unsafe_lock);
                list_del_init(&req->r_unsafe_dir_item);
                spin_unlock(&ci->i_unsafe_lock);
+
+               iput(req->r_unsafe_dir);
+               req->r_unsafe_dir = NULL;
        }
 
        ceph_mdsc_put_request(req);
@@ -2691,7 +2695,6 @@ static void handle_lease(struct ceph_mds_client *mdsc,
 {
        struct super_block *sb = mdsc->fsc->sb;
        struct inode *inode;
-       struct ceph_inode_info *ci;
        struct dentry *parent, *dentry;
        struct ceph_dentry_info *di;
        int mds = session->s_mds;
@@ -2728,7 +2731,6 @@ static void handle_lease(struct ceph_mds_client *mdsc,
                dout("handle_lease no inode %llx\n", vino.ino);
                goto release;
        }
-       ci = ceph_inode(inode);
 
        /* dentry */
        parent = d_find_alias(inode);
@@ -3002,6 +3004,7 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc)
        spin_lock_init(&mdsc->snap_flush_lock);
        mdsc->cap_flush_seq = 0;
        INIT_LIST_HEAD(&mdsc->cap_dirty);
+       INIT_LIST_HEAD(&mdsc->cap_dirty_migrating);
        mdsc->num_cap_flushing = 0;
        spin_lock_init(&mdsc->cap_dirty_lock);
        init_waitqueue_head(&mdsc->cap_flushing_wq);
index 4e3a9cc0bba6f1f89a77e6355a8f72a52614d43f..7d8a0d662d56cfa73876d302f8de892a046a9972 100644 (file)
@@ -278,6 +278,7 @@ struct ceph_mds_client {
 
        u64               cap_flush_seq;
        struct list_head  cap_dirty;        /* inodes with dirty caps */
+       struct list_head  cap_dirty_migrating; /* ...that are migration... */
        int               num_cap_flushing; /* # caps we are flushing */
        spinlock_t        cap_dirty_lock;   /* protects above items */
        wait_queue_head_t cap_flushing_wq;
index 24067d68a5549769df4be2c2a2574c36d6dcf702..54b14de2e729114d50d91fde0f9c5ab5bf7d29d7 100644 (file)
@@ -722,7 +722,7 @@ static void flush_snaps(struct ceph_mds_client *mdsc)
                ci = list_first_entry(&mdsc->snap_flush_list,
                                struct ceph_inode_info, i_snap_flush_item);
                inode = &ci->vfs_inode;
-               igrab(inode);
+               ihold(inode);
                spin_unlock(&mdsc->snap_flush_lock);
                spin_lock(&inode->i_lock);
                __ceph_flush_snaps(ci, &session, 0);
index f2b628696180e93d69bae9c72464ed4b795d694e..f42d730f1b66ce26afa774d5faeb3752fbc1646e 100644 (file)
@@ -665,7 +665,8 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
                err = PTR_ERR(req);
                goto out;
        }
-       req->r_inode = igrab(inode);
+       req->r_inode = inode;
+       ihold(inode);
        req->r_inode_drop = CEPH_CAP_XATTR_SHARED;
        req->r_num_caps = 1;
        req->r_args.setxattr.flags = cpu_to_le32(flags);
@@ -795,7 +796,8 @@ static int ceph_send_removexattr(struct dentry *dentry, const char *name)
                                       USE_AUTH_MDS);
        if (IS_ERR(req))
                return PTR_ERR(req);
-       req->r_inode = igrab(inode);
+       req->r_inode = inode;
+       ihold(inode);
        req->r_inode_drop = CEPH_CAP_XATTR_SHARED;
        req->r_num_caps = 1;
        req->r_path2 = kstrdup(name, GFP_NOFS);
index 75c47cd8d086eb0e0466ca21cce0658d5eed8edb..f66cc1625150839244870bb6bbb3d27893b7ec82 100644 (file)
@@ -7,6 +7,7 @@ config CIFS
        select CRYPTO_MD5
        select CRYPTO_HMAC
        select CRYPTO_ARC4
+       select CRYPTO_ECB
        select CRYPTO_DES
        help
          This is the client VFS module for the Common Internet File System
@@ -148,33 +149,13 @@ config CIFS_FSCACHE
 
 config CIFS_ACL
          bool "Provide CIFS ACL support (EXPERIMENTAL)"
-         depends on EXPERIMENTAL && CIFS_XATTR
+         depends on EXPERIMENTAL && CIFS_XATTR && KEYS
          help
            Allows to fetch CIFS/NTFS ACL from the server.  The DACL blob
            is handed over to the application/caller.
 
-config CIFS_SMB2
-       bool "SMB2 network file system support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && INET && BROKEN
-       select NLS
-       select KEYS
-       select FSCACHE
-       select DNS_RESOLVER
-
-       help
-         This enables experimental support for the SMB2 (Server Message Block
-         version 2) protocol. The SMB2 protocol is the successor to the
-         popular CIFS and SMB network file sharing protocols. SMB2 is the
-         native file sharing mechanism for recent versions of Windows
-         operating systems (since Vista).  SMB2 enablement will eventually
-         allow users better performance, security and features, than would be
-         possible with cifs. Note that smb2 mount options also are simpler
-         (compared to cifs) due to protocol improvements.
-
-         Unless you are a developer or tester, say N.
-
 config CIFS_NFSD_EXPORT
          bool "Allow nfsd to export CIFS file system (EXPERIMENTAL)"
-         depends on CIFS && EXPERIMENTAL
+         depends on CIFS && EXPERIMENTAL && BROKEN
          help
           Allows NFS server to export a CIFS mounted share (nfsd over cifs)
index 4a3ca0e5ca24d3ad6445dfa73a5a76dc73e590c0..c5c2c5e5f0f296f4df15bac07163ef693105947a 100644 (file)
@@ -457,6 +457,9 @@ A partial list of the supported mount options follows:
                otherwise - read from the server. All written data are stored
                in the cache, but if the client doesn't have Exclusive Oplock,
                it writes the data to the server.
+  rwpidforward  Forward pid of a process who opened a file to any read or write
+               operation on that file. This prevent applications like WINE
+               from failing on read and write if we use mandatory brlock style.
   acl          Allow setfacl and getfacl to manage posix ACLs if server
                supports them.  (default)
   noacl        Do not allow setfacl and getfacl calls on this mount
index 53d57a3fe427c3d94218a7f54b4ab87df3d68031..545509c3313b0a8e1061742e5360c8d665c2e94c 100644 (file)
@@ -92,7 +92,7 @@ static uint16_t cifs_server_get_key(const void *cookie_netfs_data,
                break;
 
        default:
-               cERROR(1, "CIFS: Unknown network family '%d'", sa->sa_family);
+               cERROR(1, "Unknown network family '%d'", sa->sa_family);
                key_len = 0;
                break;
        }
@@ -146,13 +146,13 @@ static char *extract_sharename(const char *treename)
 static uint16_t cifs_super_get_key(const void *cookie_netfs_data, void *buffer,
                                   uint16_t maxbuf)
 {
-       const struct cifsTconInfo *tcon = cookie_netfs_data;
+       const struct cifs_tcon *tcon = cookie_netfs_data;
        char *sharename;
        uint16_t len;
 
        sharename = extract_sharename(tcon->treeName);
        if (IS_ERR(sharename)) {
-               cFYI(1, "CIFS: couldn't extract sharename\n");
+               cFYI(1, "%s: couldn't extract sharename\n", __func__);
                sharename = NULL;
                return 0;
        }
@@ -173,7 +173,7 @@ cifs_fscache_super_get_aux(const void *cookie_netfs_data, void *buffer,
                           uint16_t maxbuf)
 {
        struct cifs_fscache_super_auxdata auxdata;
-       const struct cifsTconInfo *tcon = cookie_netfs_data;
+       const struct cifs_tcon *tcon = cookie_netfs_data;
 
        memset(&auxdata, 0, sizeof(auxdata));
        auxdata.resource_id = tcon->resource_id;
@@ -192,7 +192,7 @@ fscache_checkaux cifs_fscache_super_check_aux(void *cookie_netfs_data,
                                              uint16_t datalen)
 {
        struct cifs_fscache_super_auxdata auxdata;
-       const struct cifsTconInfo *tcon = cookie_netfs_data;
+       const struct cifs_tcon *tcon = cookie_netfs_data;
 
        if (datalen != sizeof(auxdata))
                return FSCACHE_CHECKAUX_OBSOLETE;
@@ -302,7 +302,7 @@ static void cifs_fscache_inode_now_uncached(void *cookie_netfs_data)
        pagevec_init(&pvec, 0);
        first = 0;
 
-       cFYI(1, "cifs inode 0x%p now uncached", cifsi);
+       cFYI(1, "%s: cifs inode 0x%p now uncached", __func__, cifsi);
 
        for (;;) {
                nr_pages = pagevec_lookup(&pvec,
index 18f4272d9047aa75046c57ac833f908b775df103..2fe3cf13b2e92b968221703f0d462a94c834ca29 100644 (file)
@@ -110,8 +110,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
        struct list_head *tmp1, *tmp2, *tmp3;
        struct mid_q_entry *mid_entry;
        struct TCP_Server_Info *server;
-       struct cifsSesInfo *ses;
-       struct cifsTconInfo *tcon;
+       struct cifs_ses *ses;
+       struct cifs_tcon *tcon;
        int i, j;
        __u32 dev_type;
 
@@ -152,7 +152,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
                                    tcp_ses_list);
                i++;
                list_for_each(tmp2, &server->smb_ses_list) {
-                       ses = list_entry(tmp2, struct cifsSesInfo,
+                       ses = list_entry(tmp2, struct cifs_ses,
                                         smb_ses_list);
                        if ((ses->serverDomain == NULL) ||
                                (ses->serverOS == NULL) ||
@@ -171,7 +171,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
                        seq_printf(m, "TCP status: %d\n\tLocal Users To "
                                   "Server: %d SecMode: 0x%x Req On Wire: %d",
                                   server->tcpStatus, server->srv_count,
-                                  server->secMode,
+                                  server->sec_mode,
                                   atomic_read(&server->inFlight));
 
 #ifdef CONFIG_CIFS_STATS2
@@ -183,7 +183,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
                        seq_puts(m, "\n\tShares:");
                        j = 0;
                        list_for_each(tmp3, &ses->tcon_list) {
-                               tcon = list_entry(tmp3, struct cifsTconInfo,
+                               tcon = list_entry(tmp3, struct cifs_tcon,
                                                  tcon_list);
                                ++j;
                                dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
@@ -256,8 +256,8 @@ static ssize_t cifs_stats_proc_write(struct file *file,
        int rc;
        struct list_head *tmp1, *tmp2, *tmp3;
        struct TCP_Server_Info *server;
-       struct cifsSesInfo *ses;
-       struct cifsTconInfo *tcon;
+       struct cifs_ses *ses;
+       struct cifs_tcon *tcon;
 
        rc = get_user(c, buffer);
        if (rc)
@@ -273,11 +273,11 @@ static ssize_t cifs_stats_proc_write(struct file *file,
                        server = list_entry(tmp1, struct TCP_Server_Info,
                                            tcp_ses_list);
                        list_for_each(tmp2, &server->smb_ses_list) {
-                               ses = list_entry(tmp2, struct cifsSesInfo,
+                               ses = list_entry(tmp2, struct cifs_ses,
                                                 smb_ses_list);
                                list_for_each(tmp3, &ses->tcon_list) {
                                        tcon = list_entry(tmp3,
-                                                         struct cifsTconInfo,
+                                                         struct cifs_tcon,
                                                          tcon_list);
                                        atomic_set(&tcon->num_smbs_sent, 0);
                                        atomic_set(&tcon->num_writes, 0);
@@ -312,8 +312,8 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
        int i;
        struct list_head *tmp1, *tmp2, *tmp3;
        struct TCP_Server_Info *server;
-       struct cifsSesInfo *ses;
-       struct cifsTconInfo *tcon;
+       struct cifs_ses *ses;
+       struct cifs_tcon *tcon;
 
        seq_printf(m,
                        "Resources in use\nCIFS Session: %d\n",
@@ -346,11 +346,11 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
                server = list_entry(tmp1, struct TCP_Server_Info,
                                    tcp_ses_list);
                list_for_each(tmp2, &server->smb_ses_list) {
-                       ses = list_entry(tmp2, struct cifsSesInfo,
+                       ses = list_entry(tmp2, struct cifs_ses,
                                         smb_ses_list);
                        list_for_each(tmp3, &ses->tcon_list) {
                                tcon = list_entry(tmp3,
-                                                 struct cifsTconInfo,
+                                                 struct cifs_tcon,
                                                  tcon_list);
                                i++;
                                seq_printf(m, "\n%d) %s", i, tcon->treeName);
index 2b68ac57d97d3ffdd0bc8bd425cff8ef121138a3..8d8f28c94c0fe608f61684c2b34e5045f01489f9 100644 (file)
@@ -272,7 +272,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
        struct dfs_info3_param *referrals = NULL;
        unsigned int num_referrals = 0;
        struct cifs_sb_info *cifs_sb;
-       struct cifsSesInfo *ses;
+       struct cifs_ses *ses;
        char *full_path;
        int xid, i;
        int rc;
index a9d5692e0c2067783a3a0607da7fc7e3cda06c5d..7260e11e21f8429304b519b2ec0f5aeb477ce0b9 100644 (file)
@@ -41,6 +41,8 @@
 #define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */
 #define CIFS_MOUNT_MULTIUSER   0x20000 /* multiuser mount */
 #define CIFS_MOUNT_STRICT_IO   0x40000 /* strict cache mode */
+#define CIFS_MOUNT_RWPIDFORWARD        0x80000 /* use pid forwarding for rw */
+#define CIFS_MOUNT_POSIXACL    0x100000 /* mirror of MS_POSIXACL in mnt_cifs_flags */
 
 struct cifs_sb_info {
        struct rb_root tlink_tree;
@@ -56,8 +58,6 @@ struct cifs_sb_info {
        mode_t  mnt_file_mode;
        mode_t  mnt_dir_mode;
        unsigned int mnt_cifs_flags;
-       int     prepathlen;
-       char   *prepath; /* relative path under the share to mount to */
        char   *mountdata; /* options received at mount time or via DFS refs */
        struct backing_dev_info bdi;
        struct delayed_work prune_tlinks;
index 33d221394acae068807adea4eeca47317a821888..2272fd5fe5b74fcac62d001987ce3980a8a0b3e0 100644 (file)
@@ -95,7 +95,7 @@ struct key_type cifs_spnego_key_type = {
 
 /* get a key struct with a SPNEGO security blob, suitable for session setup */
 struct key *
-cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
+cifs_get_spnego_key(struct cifs_ses *sesInfo)
 {
        struct TCP_Server_Info *server = sesInfo->server;
        struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr;
index e4041ec4d712943c412e0d97addbea7c4964c77a..31bef9ee078bdebb977ca830c0acb0a33d2565ba 100644 (file)
@@ -41,7 +41,7 @@ struct cifs_spnego_msg {
 
 #ifdef __KERNEL__
 extern struct key_type cifs_spnego_key_type;
-extern struct key *cifs_get_spnego_key(struct cifsSesInfo *sesInfo);
+extern struct key *cifs_get_spnego_key(struct cifs_ses *sesInfo);
 #endif /* KERNEL */
 
 #endif /* _CIFS_SPNEGO_H */
index f3c6fb9942ac9f03651cc1b1f6e3b46f954b7af8..21de1d6d5849e21977ce9c23bb480439693f2d1e 100644 (file)
@@ -38,7 +38,7 @@ static const struct cifs_sid sid_everyone = {
        1, 1, {0, 0, 0, 0, 0, 1}, {0} };
 /* security id for Authenticated Users system group */
 static const struct cifs_sid sid_authusers = {
-       1, 1, {0, 0, 0, 0, 0, 5}, {11} };
+       1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11)} };
 /* group users */
 static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
 
@@ -74,8 +74,9 @@ shrink_idmap_tree(struct rb_root *root, int nr_to_scan, int *nr_rem,
  * Run idmap cache shrinker.
  */
 static int
-cifs_idmap_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
+cifs_idmap_shrinker(struct shrinker *shrink, struct shrink_control *sc)
 {
+       int nr_to_scan = sc->nr_to_scan;
        int nr_del = 0;
        int nr_rem = 0;
        struct rb_root *root;
@@ -458,7 +459,8 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
        if (num_subauth) {
                for (i = 0; i < num_subauth; ++i) {
                        if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
-                               if (ctsid->sub_auth[i] > cwsid->sub_auth[i])
+                               if (le32_to_cpu(ctsid->sub_auth[i]) >
+                                       le32_to_cpu(cwsid->sub_auth[i]))
                                        return 1;
                                else
                                        return -1;
@@ -945,7 +947,7 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
        int oplock = 0;
        int xid, rc;
        __u16 fid;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
        struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
 
        if (IS_ERR(tlink))
@@ -1013,7 +1015,7 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
        int oplock = 0;
        int xid, rc;
        __u16 fid;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
        struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
 
        if (IS_ERR(tlink))
index 45c3f78c8f81374d4cc7c695bb5e9e4b5f9f12d3..5a0ee7f2af062a68fdec065c43099274486c1b2d 100644 (file)
@@ -184,7 +184,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu,
        if (cifs_pdu == NULL || server == NULL)
                return -EINVAL;
 
-       if (cifs_pdu->Command == SMB_COM_NEGOTIATE)
+       if (!server->session_estab)
                return 0;
 
        if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
@@ -229,7 +229,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu,
 }
 
 /* first calculate 24 bytes ntlm response and then 16 byte session key */
-int setup_ntlm_response(struct cifsSesInfo *ses)
+int setup_ntlm_response(struct cifs_ses *ses)
 {
        int rc = 0;
        unsigned int temp_len = CIFS_SESS_KEY_SIZE + CIFS_AUTH_RESP_SIZE;
@@ -312,7 +312,7 @@ int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
  * Allocate domain name which gets freed when session struct is deallocated.
  */
 static int
-build_avpair_blob(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
+build_avpair_blob(struct cifs_ses *ses, const struct nls_table *nls_cp)
 {
        unsigned int dlen;
        unsigned int wlen;
@@ -400,7 +400,7 @@ build_avpair_blob(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
  * about target string i.e. for some, just user name might suffice.
  */
 static int
-find_domain_name(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
+find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp)
 {
        unsigned int attrsize;
        unsigned int type;
@@ -445,7 +445,7 @@ find_domain_name(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
        return 0;
 }
 
-static int calc_ntlmv2_hash(struct cifsSesInfo *ses, char *ntlmv2_hash,
+static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
                            const struct nls_table *nls_cp)
 {
        int rc = 0;
@@ -527,7 +527,7 @@ calc_exit_2:
 }
 
 static int
-CalcNTLMv2_response(const struct cifsSesInfo *ses, char *ntlmv2_hash)
+CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
 {
        int rc;
        unsigned int offset = CIFS_SESS_KEY_SIZE + 8;
@@ -563,7 +563,7 @@ CalcNTLMv2_response(const struct cifsSesInfo *ses, char *ntlmv2_hash)
 
 
 int
-setup_ntlmv2_rsp(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
+setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
 {
        int rc;
        int baselen;
@@ -649,7 +649,7 @@ setup_ntlmv2_rsp_ret:
 }
 
 int
-calc_seckey(struct cifsSesInfo *ses)
+calc_seckey(struct cifs_ses *ses)
 {
        int rc;
        struct crypto_blkcipher *tfm_arc4;
index 493b74ca5648b69d676dd423ede90a24c5c6e452..35f9154615fa5ca7cc01fe857324b640b9533245 100644 (file)
@@ -104,52 +104,24 @@ cifs_sb_deactive(struct super_block *sb)
 }
 
 static int
-cifs_read_super(struct super_block *sb, void *data,
-               const char *devname, int silent)
+cifs_read_super(struct super_block *sb)
 {
        struct inode *inode;
        struct cifs_sb_info *cifs_sb;
        int rc = 0;
 
-       /* BB should we make this contingent on mount parm? */
-       sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
-       sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL);
        cifs_sb = CIFS_SB(sb);
-       if (cifs_sb == NULL)
-               return -ENOMEM;
 
-       spin_lock_init(&cifs_sb->tlink_tree_lock);
-       cifs_sb->tlink_tree = RB_ROOT;
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL)
+               sb->s_flags |= MS_POSIXACL;
 
-       rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY);
-       if (rc) {
-               kfree(cifs_sb);
-               return rc;
-       }
-       cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages;
-
-       /*
-        * Copy mount params to sb for use in submounts. Better to do
-        * the copy here and deal with the error before cleanup gets
-        * complicated post-mount.
-        */
-       if (data) {
-               cifs_sb->mountdata = kstrndup(data, PAGE_SIZE, GFP_KERNEL);
-               if (cifs_sb->mountdata == NULL) {
-                       bdi_destroy(&cifs_sb->bdi);
-                       kfree(sb->s_fs_info);
-                       sb->s_fs_info = NULL;
-                       return -ENOMEM;
-               }
-       }
+       if (cifs_sb_master_tcon(cifs_sb)->ses->capabilities & CAP_LARGE_FILES)
+               sb->s_maxbytes = MAX_LFS_FILESIZE;
+       else
+               sb->s_maxbytes = MAX_NON_LFS;
 
-       rc = cifs_mount(sb, cifs_sb, devname);
-
-       if (rc) {
-               if (!silent)
-                       cERROR(1, "cifs_mount failed w/return code = %d", rc);
-               goto out_mount_failed;
-       }
+       /* BB FIXME fix time_gran to be larger for LANMAN sessions */
+       sb->s_time_gran = 100;
 
        sb->s_magic = CIFS_MAGIC_NUMBER;
        sb->s_op = &cifs_super_ops;
@@ -191,45 +163,14 @@ out_no_root:
        if (inode)
                iput(inode);
 
-       cifs_umount(sb, cifs_sb);
-
-out_mount_failed:
-       if (cifs_sb) {
-               if (cifs_sb->mountdata) {
-                       kfree(cifs_sb->mountdata);
-                       cifs_sb->mountdata = NULL;
-               }
-               unload_nls(cifs_sb->local_nls);
-               bdi_destroy(&cifs_sb->bdi);
-               kfree(cifs_sb);
-       }
        return rc;
 }
 
-static void
-cifs_put_super(struct super_block *sb)
+static void cifs_kill_sb(struct super_block *sb)
 {
-       int rc = 0;
-       struct cifs_sb_info *cifs_sb;
-
-       cFYI(1, "In cifs_put_super");
-       cifs_sb = CIFS_SB(sb);
-       if (cifs_sb == NULL) {
-               cFYI(1, "Empty cifs superblock info passed to unmount");
-               return;
-       }
-
-       rc = cifs_umount(sb, cifs_sb);
-       if (rc)
-               cERROR(1, "cifs_umount failed with return code %d", rc);
-       if (cifs_sb->mountdata) {
-               kfree(cifs_sb->mountdata);
-               cifs_sb->mountdata = NULL;
-       }
-
-       unload_nls(cifs_sb->local_nls);
-       bdi_destroy(&cifs_sb->bdi);
-       kfree(cifs_sb);
+       struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+       kill_anon_super(sb);
+       cifs_umount(cifs_sb);
 }
 
 static int
@@ -237,7 +178,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-       struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
+       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
        int rc = -EOPNOTSUPP;
        int xid;
 
@@ -286,9 +227,6 @@ static int cifs_permission(struct inode *inode, int mask, unsigned int flags)
 {
        struct cifs_sb_info *cifs_sb;
 
-       if (flags & IPERM_FLAG_RCU)
-               return -ECHILD;
-
        cifs_sb = CIFS_SB(inode->i_sb);
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) {
@@ -381,6 +319,37 @@ cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server)
        }
 }
 
+static void
+cifs_show_security(struct seq_file *s, struct TCP_Server_Info *server)
+{
+       seq_printf(s, ",sec=");
+
+       switch (server->secType) {
+       case LANMAN:
+               seq_printf(s, "lanman");
+               break;
+       case NTLMv2:
+               seq_printf(s, "ntlmv2");
+               break;
+       case NTLM:
+               seq_printf(s, "ntlm");
+               break;
+       case Kerberos:
+               seq_printf(s, "krb5");
+               break;
+       case RawNTLMSSP:
+               seq_printf(s, "ntlmssp");
+               break;
+       default:
+               /* shouldn't ever happen */
+               seq_printf(s, "unknown");
+               break;
+       }
+
+       if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+               seq_printf(s, "i");
+}
+
 /*
  * cifs_show_options() is for displaying mount options in /proc/mounts.
  * Not all settable options are displayed but most of the important
@@ -390,10 +359,12 @@ static int
 cifs_show_options(struct seq_file *s, struct vfsmount *m)
 {
        struct cifs_sb_info *cifs_sb = CIFS_SB(m->mnt_sb);
-       struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
+       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
        struct sockaddr *srcaddr;
        srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr;
 
+       cifs_show_security(s, tcon->ses->server);
+
        seq_printf(s, ",unc=%s", tcon->treeName);
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)
@@ -444,14 +415,20 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
                seq_printf(s, ",nocase");
        if (tcon->retry)
                seq_printf(s, ",hard");
-       if (cifs_sb->prepath)
-               seq_printf(s, ",prepath=%s", cifs_sb->prepath);
+       if (tcon->unix_ext)
+               seq_printf(s, ",unix");
+       else
+               seq_printf(s, ",nounix");
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
                seq_printf(s, ",posixpaths");
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
                seq_printf(s, ",setuids");
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
                seq_printf(s, ",serverino");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
+               seq_printf(s, ",rwpidforward");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL)
+               seq_printf(s, ",forcemand");
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
                seq_printf(s, ",directio");
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
@@ -484,7 +461,7 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
 static void cifs_umount_begin(struct super_block *sb)
 {
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
 
        if (cifs_sb == NULL)
                return;
@@ -541,7 +518,6 @@ static int cifs_drop_inode(struct inode *inode)
 }
 
 static const struct super_operations cifs_super_ops = {
-       .put_super = cifs_put_super,
        .statfs = cifs_statfs,
        .alloc_inode = cifs_alloc_inode,
        .destroy_inode = cifs_destroy_inode,
@@ -559,29 +535,194 @@ static const struct super_operations cifs_super_ops = {
 #endif
 };
 
+/*
+ * Get root dentry from superblock according to prefix path mount option.
+ * Return dentry with refcount + 1 on success and NULL otherwise.
+ */
+static struct dentry *
+cifs_get_root(struct smb_vol *vol, struct super_block *sb)
+{
+       int xid, rc;
+       struct inode *inode;
+       struct qstr name;
+       struct dentry *dparent = NULL, *dchild = NULL, *alias;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+       unsigned int i, full_len, len;
+       char *full_path = NULL, *pstart;
+       char sep;
+
+       full_path = cifs_build_path_to_root(vol, cifs_sb,
+                                           cifs_sb_master_tcon(cifs_sb));
+       if (full_path == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       cFYI(1, "Get root dentry for %s", full_path);
+
+       xid = GetXid();
+       sep = CIFS_DIR_SEP(cifs_sb);
+       dparent = dget(sb->s_root);
+       full_len = strlen(full_path);
+       full_path[full_len] = sep;
+       pstart = full_path + 1;
+
+       for (i = 1, len = 0; i <= full_len; i++) {
+               if (full_path[i] != sep || !len) {
+                       len++;
+                       continue;
+               }
+
+               full_path[i] = 0;
+               cFYI(1, "get dentry for %s", pstart);
+
+               name.name = pstart;
+               name.len = len;
+               name.hash = full_name_hash(pstart, len);
+               dchild = d_lookup(dparent, &name);
+               if (dchild == NULL) {
+                       cFYI(1, "not exists");
+                       dchild = d_alloc(dparent, &name);
+                       if (dchild == NULL) {
+                               dput(dparent);
+                               dparent = ERR_PTR(-ENOMEM);
+                               goto out;
+                       }
+               }
+
+               cFYI(1, "get inode");
+               if (dchild->d_inode == NULL) {
+                       cFYI(1, "not exists");
+                       inode = NULL;
+                       if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
+                               rc = cifs_get_inode_info_unix(&inode, full_path,
+                                                             sb, xid);
+                       else
+                               rc = cifs_get_inode_info(&inode, full_path,
+                                                        NULL, sb, xid, NULL);
+                       if (rc) {
+                               dput(dchild);
+                               dput(dparent);
+                               dparent = ERR_PTR(rc);
+                               goto out;
+                       }
+                       alias = d_materialise_unique(dchild, inode);
+                       if (alias != NULL) {
+                               dput(dchild);
+                               if (IS_ERR(alias)) {
+                                       dput(dparent);
+                                       dparent = ERR_PTR(-EINVAL); /* XXX */
+                                       goto out;
+                               }
+                               dchild = alias;
+                       }
+               }
+               cFYI(1, "parent %p, child %p", dparent, dchild);
+
+               dput(dparent);
+               dparent = dchild;
+               len = 0;
+               pstart = full_path + i + 1;
+               full_path[i] = sep;
+       }
+out:
+       _FreeXid(xid);
+       kfree(full_path);
+       return dparent;
+}
+
+static int cifs_set_super(struct super_block *sb, void *data)
+{
+       struct cifs_mnt_data *mnt_data = data;
+       sb->s_fs_info = mnt_data->cifs_sb;
+       return set_anon_super(sb, NULL);
+}
+
 static struct dentry *
 cifs_do_mount(struct file_system_type *fs_type,
-           int flags, const char *dev_name, void *data)
+             int flags, const char *dev_name, void *data)
 {
        int rc;
        struct super_block *sb;
-
-       sb = sget(fs_type, NULL, set_anon_super, NULL);
+       struct cifs_sb_info *cifs_sb;
+       struct smb_vol *volume_info;
+       struct cifs_mnt_data mnt_data;
+       struct dentry *root;
 
        cFYI(1, "Devname: %s flags: %d ", dev_name, flags);
 
-       if (IS_ERR(sb))
-               return ERR_CAST(sb);
+       rc = cifs_setup_volume_info(&volume_info, (char *)data, dev_name);
+       if (rc)
+               return ERR_PTR(rc);
+
+       cifs_sb = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL);
+       if (cifs_sb == NULL) {
+               root = ERR_PTR(-ENOMEM);
+               goto out_nls;
+       }
+
+       cifs_sb->mountdata = kstrndup(data, PAGE_SIZE, GFP_KERNEL);
+       if (cifs_sb->mountdata == NULL) {
+               root = ERR_PTR(-ENOMEM);
+               goto out_cifs_sb;
+       }
 
-       sb->s_flags = flags;
+       cifs_setup_cifs_sb(volume_info, cifs_sb);
 
-       rc = cifs_read_super(sb, data, dev_name, flags & MS_SILENT ? 1 : 0);
+       rc = cifs_mount(cifs_sb, volume_info);
        if (rc) {
-               deactivate_locked_super(sb);
-               return ERR_PTR(rc);
+               if (!(flags & MS_SILENT))
+                       cERROR(1, "cifs_mount failed w/return code = %d", rc);
+               root = ERR_PTR(rc);
+               goto out_mountdata;
+       }
+
+       mnt_data.vol = volume_info;
+       mnt_data.cifs_sb = cifs_sb;
+       mnt_data.flags = flags;
+
+       sb = sget(fs_type, cifs_match_super, cifs_set_super, &mnt_data);
+       if (IS_ERR(sb)) {
+               root = ERR_CAST(sb);
+               cifs_umount(cifs_sb);
+               goto out;
+       }
+
+       if (sb->s_root) {
+               cFYI(1, "Use existing superblock");
+               cifs_umount(cifs_sb);
+       } else {
+               sb->s_flags = flags;
+               /* BB should we make this contingent on mount parm? */
+               sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
+
+               rc = cifs_read_super(sb);
+               if (rc) {
+                       root = ERR_PTR(rc);
+                       goto out_super;
+               }
+
+               sb->s_flags |= MS_ACTIVE;
        }
-       sb->s_flags |= MS_ACTIVE;
-       return dget(sb->s_root);
+
+       root = cifs_get_root(volume_info, sb);
+       if (IS_ERR(root))
+               goto out_super;
+
+       cFYI(1, "dentry root is: %p", root);
+       goto out;
+
+out_super:
+       deactivate_locked_super(sb);
+out:
+       cifs_cleanup_volume_info(&volume_info);
+       return root;
+
+out_mountdata:
+       kfree(cifs_sb->mountdata);
+out_cifs_sb:
+       kfree(cifs_sb);
+out_nls:
+       unload_nls(volume_info->local_nls);
+       goto out;
 }
 
 static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
@@ -670,7 +811,7 @@ struct file_system_type cifs_fs_type = {
        .owner = THIS_MODULE,
        .name = "cifs",
        .mount = cifs_do_mount,
-       .kill_sb = kill_anon_super,
+       .kill_sb = cifs_kill_sb,
        /*  .fs_flags */
 };
 const struct inode_operations cifs_dir_inode_ops = {
index 64313f778ebfcd50c456c2b7b92ebcc6c82fb364..0900e1658c967de0fc2f4d70cc7645c9363a5d30 100644 (file)
@@ -129,5 +129,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 extern const struct export_operations cifs_export_ops;
 #endif /* CIFS_NFSD_EXPORT */
 
-#define CIFS_VERSION   "1.72"
+#define CIFS_VERSION   "1.73"
 #endif                         /* _CIFSFS_H */
index 76b4517e74b07d5ff15865c2f4860ed9062c7780..6255fa812c7a28b2071ced3f7585cb2359e6a3c4 100644 (file)
@@ -155,6 +155,81 @@ struct cifs_cred {
  *****************************************************************
  */
 
+struct smb_vol {
+       char *username;
+       char *password;
+       char *domainname;
+       char *UNC;
+       char *UNCip;
+       char *iocharset;  /* local code page for mapping to and from Unicode */
+       char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */
+       char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */
+       uid_t cred_uid;
+       uid_t linux_uid;
+       gid_t linux_gid;
+       mode_t file_mode;
+       mode_t dir_mode;
+       unsigned secFlg;
+       bool retry:1;
+       bool intr:1;
+       bool setuids:1;
+       bool override_uid:1;
+       bool override_gid:1;
+       bool dynperm:1;
+       bool noperm:1;
+       bool no_psx_acl:1; /* set if posix acl support should be disabled */
+       bool cifs_acl:1;
+       bool no_xattr:1;   /* set if xattr (EA) support should be disabled*/
+       bool server_ino:1; /* use inode numbers from server ie UniqueId */
+       bool direct_io:1;
+       bool strict_io:1; /* strict cache behavior */
+       bool remap:1;      /* set to remap seven reserved chars in filenames */
+       bool posix_paths:1; /* unset to not ask for posix pathnames. */
+       bool no_linux_ext:1;
+       bool sfu_emul:1;
+       bool nullauth:1;   /* attempt to authenticate with null user */
+       bool nocase:1;     /* request case insensitive filenames */
+       bool nobrl:1;      /* disable sending byte range locks to srv */
+       bool mand_lock:1;  /* send mandatory not posix byte range lock reqs */
+       bool seal:1;       /* request transport encryption on share */
+       bool nodfs:1;      /* Do not request DFS, even if available */
+       bool local_lease:1; /* check leases only on local system, not remote */
+       bool noblocksnd:1;
+       bool noautotune:1;
+       bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
+       bool fsc:1;     /* enable fscache */
+       bool mfsymlinks:1; /* use Minshall+French Symlinks */
+       bool multiuser:1;
+       bool rwpidforward:1; /* pid forward for read/write operations */
+       unsigned int rsize;
+       unsigned int wsize;
+       bool sockopt_tcp_nodelay:1;
+       unsigned short int port;
+       unsigned long actimeo; /* attribute cache timeout (jiffies) */
+       char *prepath;
+       struct sockaddr_storage srcaddr; /* allow binding to a local IP */
+       struct nls_table *local_nls;
+};
+
+#define CIFS_MOUNT_MASK (CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID | \
+                        CIFS_MOUNT_SERVER_INUM | CIFS_MOUNT_DIRECT_IO | \
+                        CIFS_MOUNT_NO_XATTR | CIFS_MOUNT_MAP_SPECIAL_CHR | \
+                        CIFS_MOUNT_UNX_EMUL | CIFS_MOUNT_NO_BRL | \
+                        CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_OVERR_UID | \
+                        CIFS_MOUNT_OVERR_GID | CIFS_MOUNT_DYNPERM | \
+                        CIFS_MOUNT_NOPOSIXBRL | CIFS_MOUNT_NOSSYNC | \
+                        CIFS_MOUNT_FSCACHE | CIFS_MOUNT_MF_SYMLINKS | \
+                        CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_STRICT_IO)
+
+#define CIFS_MS_MASK (MS_RDONLY | MS_MANDLOCK | MS_NOEXEC | MS_NOSUID | \
+                     MS_NODEV | MS_SYNCHRONOUS)
+
+struct cifs_mnt_data {
+       struct cifs_sb_info *cifs_sb;
+       struct smb_vol *vol;
+       int flags;
+};
+
 struct TCP_Server_Info {
        struct list_head tcp_ses_list;
        struct list_head smb_ses_list;
@@ -179,7 +254,7 @@ struct TCP_Server_Info {
        struct mutex srv_mutex;
        struct task_struct *tsk;
        char server_GUID[16];
-       char secMode;
+       char sec_mode;
        bool session_estab; /* mark when very first sess is established */
        u16 dialect; /* dialect index that server chose */
        enum securityEnum secType;
@@ -254,7 +329,7 @@ static inline void cifs_set_net_ns(struct TCP_Server_Info *srv, struct net *net)
 /*
  * Session structure.  One of these for each uid session with a particular host
  */
-struct cifsSesInfo {
+struct cifs_ses {
        struct list_head smb_ses_list;
        struct list_head tcon_list;
        struct mutex session_mutex;
@@ -294,11 +369,11 @@ struct cifsSesInfo {
  * there is one of these for each connection to a resource on a particular
  * session
  */
-struct cifsTconInfo {
+struct cifs_tcon {
        struct list_head tcon_list;
        int tc_count;
        struct list_head openFileList;
-       struct cifsSesInfo *ses;        /* pointer to session associated with */
+       struct cifs_ses *ses;   /* pointer to session associated with */
        char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
        char *nativeFileSystem;
        char *password;         /* for share-level security */
@@ -380,12 +455,12 @@ struct tcon_link {
 #define TCON_LINK_IN_TREE      2
        unsigned long           tl_time;
        atomic_t                tl_count;
-       struct cifsTconInfo     *tl_tcon;
+       struct cifs_tcon        *tl_tcon;
 };
 
 extern struct tcon_link *cifs_sb_tlink(struct cifs_sb_info *cifs_sb);
 
-static inline struct cifsTconInfo *
+static inline struct cifs_tcon *
 tlink_tcon(struct tcon_link *tlink)
 {
        return tlink->tl_tcon;
@@ -402,7 +477,7 @@ cifs_get_tlink(struct tcon_link *tlink)
 }
 
 /* This function is always expected to succeed */
-extern struct cifsTconInfo *cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb);
+extern struct cifs_tcon *cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb);
 
 /*
  * This info hangs off the cifsFileInfo structure, pointed to by llist.
@@ -455,6 +530,14 @@ struct cifsFileInfo {
        struct work_struct oplock_break; /* work for oplock breaks */
 };
 
+struct cifs_io_parms {
+       __u16 netfid;
+       __u32 pid;
+       __u64 offset;
+       unsigned int length;
+       struct cifs_tcon *tcon;
+};
+
 /*
  * Take a reference on the file private data. Must be called with
  * cifs_file_list_lock held.
@@ -509,10 +592,30 @@ static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb)
                return '\\';
 }
 
+static inline void
+convert_delimiter(char *path, char delim)
+{
+       int i;
+       char old_delim;
+
+       if (path == NULL)
+               return;
+
+       if (delim == '/')
+               old_delim = '\\';
+       else
+               old_delim = '/';
+
+       for (i = 0; path[i] != '\0'; i++) {
+               if (path[i] == old_delim)
+                       path[i] = delim;
+       }
+}
+
 #ifdef CONFIG_CIFS_STATS
 #define cifs_stats_inc atomic_inc
 
-static inline void cifs_stats_bytes_written(struct cifsTconInfo *tcon,
+static inline void cifs_stats_bytes_written(struct cifs_tcon *tcon,
                                            unsigned int bytes)
 {
        if (bytes) {
@@ -522,7 +625,7 @@ static inline void cifs_stats_bytes_written(struct cifsTconInfo *tcon,
        }
 }
 
-static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon,
+static inline void cifs_stats_bytes_read(struct cifs_tcon *tcon,
                                         unsigned int bytes)
 {
        spin_lock(&tcon->stat_lock);
@@ -543,9 +646,8 @@ struct mid_q_entry;
  * This is the prototype for the mid callback function. When creating one,
  * take special care to avoid deadlocks. Things to bear in mind:
  *
- * - it will be called by cifsd
- * - the GlobalMid_Lock will be held
- * - the mid will be removed from the pending_mid_q list
+ * - it will be called by cifsd, with no locks held
+ * - the mid will be removed from any lists
  */
 typedef void (mid_callback_t)(struct mid_q_entry *mid);
 
@@ -573,7 +675,7 @@ struct mid_q_entry {
 struct oplock_q_entry {
        struct list_head qhead;
        struct inode *pinode;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
        __u16 netfid;
 };
 
@@ -656,6 +758,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
 #define   MID_RESPONSE_RECEIVED 4
 #define   MID_RETRY_NEEDED      8 /* session closed while this request out */
 #define   MID_RESPONSE_MALFORMED 0x10
+#define   MID_SHUTDOWN          0x20
 
 /* Types of response buffer returned from SendReceive2 */
 #define   CIFS_NO_BUFFER        0    /* Response buffer not returned */
index 6e69e06a30b3334687cf07034044a01c6b0beaed..257f312ede422d6e5c1592954bb9467f602c6e6a 100644 (file)
@@ -57,8 +57,9 @@ extern int init_cifs_idmap(void);
 extern void exit_cifs_idmap(void);
 extern void cifs_destroy_idmaptrees(void);
 extern char *build_path_from_dentry(struct dentry *);
-extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
-                                       struct cifsTconInfo *tcon);
+extern char *cifs_build_path_to_root(struct smb_vol *vol,
+                                    struct cifs_sb_info *cifs_sb,
+                                    struct cifs_tcon *tcon);
 extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
 extern char *cifs_compose_mount_options(const char *sb_mountdata,
                const char *fullpath, const struct dfs_info3_param *ref,
@@ -67,20 +68,22 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata,
 extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
                                        struct TCP_Server_Info *server);
 extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
-extern int cifs_call_async(struct TCP_Server_Info *server,
-                          struct smb_hdr *in_buf, mid_callback_t *callback,
-                          void *cbdata);
-extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
+extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
+                          unsigned int nvec, mid_callback_t *callback,
+                          void *cbdata, bool ignore_pend);
+extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
                        struct smb_hdr * /* input */ ,
                        struct smb_hdr * /* out */ ,
                        int * /* bytes returned */ , const int long_op);
-extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
+extern int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
                        struct smb_hdr *in_buf, int flags);
-extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
+extern int cifs_check_receive(struct mid_q_entry *mid,
+                       struct TCP_Server_Info *server, bool log_error);
+extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
                        struct kvec *, int /* nvec to send */,
                        int * /* type of buf returned */ , const int flags);
 extern int SendReceiveBlockingLock(const unsigned int xid,
-                       struct cifsTconInfo *ptcon,
+                       struct cifs_tcon *ptcon,
                        struct smb_hdr *in_buf ,
                        struct smb_hdr *out_buf,
                        int *bytes_returned);
@@ -99,14 +102,14 @@ extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
 extern int cifs_set_port(struct sockaddr *addr, const unsigned short int port);
 extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
                                const unsigned short int port);
-extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr);
+extern int map_smb_to_linux_error(struct smb_hdr *smb, bool logErr);
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
-                           const struct cifsTconInfo *, int /* length of
+                           const struct cifs_tcon *, int /* length of
                            fixed section (word count) in two byte units */);
 extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
-                               struct cifsSesInfo *ses,
+                               struct cifs_ses *ses,
                                void **request_buf);
-extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
+extern int CIFS_SessSetup(unsigned int xid, struct cifs_ses *ses,
                             const struct nls_table *nls_cp);
 extern __u16 GetNextMid(struct TCP_Server_Info *server);
 extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
@@ -148,102 +151,108 @@ extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
 extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
                                const char *);
 
-extern int cifs_mount(struct super_block *, struct cifs_sb_info *,
-                       const char *);
-extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
+extern void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
+                              struct cifs_sb_info *cifs_sb);
+extern int cifs_match_super(struct super_block *, void *);
+extern void cifs_cleanup_volume_info(struct smb_vol **pvolume_info);
+extern int cifs_setup_volume_info(struct smb_vol **pvolume_info,
+                                 char *mount_data, const char *devname);
+extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *);
+extern void cifs_umount(struct cifs_sb_info *);
 extern void cifs_dfs_release_automount_timer(void);
 void cifs_proc_init(void);
 void cifs_proc_clean(void);
 
 extern int cifs_negotiate_protocol(unsigned int xid,
-                                 struct cifsSesInfo *ses);
-extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses,
+                                 struct cifs_ses *ses);
+extern int cifs_setup_session(unsigned int xid, struct cifs_ses *ses,
                        struct nls_table *nls_info);
-extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses);
+extern int CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses);
 
-extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
-                       const char *tree, struct cifsTconInfo *tcon,
+extern int CIFSTCon(unsigned int xid, struct cifs_ses *ses,
+                       const char *tree, struct cifs_tcon *tcon,
                        const struct nls_table *);
 
-extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
                const char *searchName, const struct nls_table *nls_codepage,
                __u16 *searchHandle, struct cifs_search_info *psrch_inf,
                int map, const char dirsep);
 
-extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
                __u16 searchHandle, struct cifs_search_info *psrch_inf);
 
-extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
+extern int CIFSFindClose(const int, struct cifs_tcon *tcon,
                        const __u16 search_handle);
 
-extern int CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon,
                        u16 netfid, FILE_ALL_INFO *pFindData);
-extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon,
                        const unsigned char *searchName,
                        FILE_ALL_INFO *findData,
                        int legacy /* whether to use old info level */,
                        const struct nls_table *nls_codepage, int remap);
-extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
+extern int SMBQueryInformation(const int xid, struct cifs_tcon *tcon,
                        const unsigned char *searchName,
                        FILE_ALL_INFO *findData,
                        const struct nls_table *nls_codepage, int remap);
 
-extern int CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon,
                        u16 netfid, FILE_UNIX_BASIC_INFO *pFindData);
 extern int CIFSSMBUnixQPathInfo(const int xid,
-                       struct cifsTconInfo *tcon,
+                       struct cifs_tcon *tcon,
                        const unsigned char *searchName,
                        FILE_UNIX_BASIC_INFO *pFindData,
                        const struct nls_table *nls_codepage, int remap);
 
-extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
+extern int CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
                        const unsigned char *searchName,
                        struct dfs_info3_param **target_nodes,
                        unsigned int *number_of_nodes_in_array,
                        const struct nls_table *nls_codepage, int remap);
 
-extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
+extern int get_dfs_path(int xid, struct cifs_ses *pSesInfo,
                        const char *old_path,
                        const struct nls_table *nls_codepage,
                        unsigned int *pnum_referrals,
                        struct dfs_info3_param **preferrals,
                        int remap);
-extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
-                                struct super_block *sb, struct smb_vol *vol);
-extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
+extern void reset_cifs_unix_caps(int xid, struct cifs_tcon *tcon,
+                                struct cifs_sb_info *cifs_sb,
+                                struct smb_vol *vol);
+extern int CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon,
                        struct kstatfs *FSData);
-extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon,
+extern int SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon,
                        struct kstatfs *FSData);
-extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon,
                        __u64 cap);
 
 extern int CIFSSMBQFSAttributeInfo(const int xid,
-                       struct cifsTconInfo *tcon);
-extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon);
-extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon);
-extern int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
+                       struct cifs_tcon *tcon);
+extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon);
+extern int CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon);
+extern int CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon,
                        struct kstatfs *FSData);
 
-extern int CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon,
                        const char *fileName, const FILE_BASIC_INFO *data,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
-extern int CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
                        const FILE_BASIC_INFO *data, __u16 fid,
                        __u32 pid_of_opener);
-extern int CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
                        bool delete_file, __u16 fid, __u32 pid_of_opener);
 #if 0
-extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon,
                        char *fileName, __u16 dos_attributes,
                        const struct nls_table *nls_codepage);
 #endif /* possibly unneeded function */
-extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon,
                        const char *fileName, __u64 size,
                        bool setAllocationSizeFlag,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
-extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon,
                         __u64 size, __u16 fileHandle, __u32 opener_pid,
                        bool AllocSizeFlag);
 
@@ -257,120 +266,116 @@ struct cifs_unix_set_info_args {
        dev_t   device;
 };
 
-extern int CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
                                  const struct cifs_unix_set_info_args *args,
                                  u16 fid, u32 pid_of_opener);
 
-extern int CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *pTcon,
+extern int CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *pTcon,
                        char *fileName,
                        const struct cifs_unix_set_info_args *args,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
 
-extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon,
                        const char *newName,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
-extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon,
                        const char *name, const struct nls_table *nls_codepage,
                        int remap_special_chars);
-extern int CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon,
                        const char *name, __u16 type,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
-extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon,
                        const char *name,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
-extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBRename(const int xid, struct cifs_tcon *tcon,
                        const char *fromName, const char *toName,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
-extern int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
+extern int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
                        int netfid, const char *target_name,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
 extern int CIFSCreateHardLink(const int xid,
-                       struct cifsTconInfo *tcon,
+                       struct cifs_tcon *tcon,
                        const char *fromName, const char *toName,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
 extern int CIFSUnixCreateHardLink(const int xid,
-                       struct cifsTconInfo *tcon,
+                       struct cifs_tcon *tcon,
                        const char *fromName, const char *toName,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
 extern int CIFSUnixCreateSymLink(const int xid,
-                       struct cifsTconInfo *tcon,
+                       struct cifs_tcon *tcon,
                        const char *fromName, const char *toName,
                        const struct nls_table *nls_codepage);
 extern int CIFSSMBUnixQuerySymLink(const int xid,
-                       struct cifsTconInfo *tcon,
+                       struct cifs_tcon *tcon,
                        const unsigned char *searchName, char **syminfo,
                        const struct nls_table *nls_codepage);
 #ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
 extern int CIFSSMBQueryReparseLinkInfo(const int xid,
-                       struct cifsTconInfo *tcon,
+                       struct cifs_tcon *tcon,
                        const unsigned char *searchName,
                        char *symlinkinfo, const int buflen, __u16 fid,
                        const struct nls_table *nls_codepage);
 #endif /* temporarily unused until cifs_symlink fixed */
-extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
                        const char *fileName, const int disposition,
                        const int access_flags, const int omode,
                        __u16 *netfid, int *pOplock, FILE_ALL_INFO *,
                        const struct nls_table *nls_codepage, int remap);
-extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
+extern int SMBLegacyOpen(const int xid, struct cifs_tcon *tcon,
                        const char *fileName, const int disposition,
                        const int access_flags, const int omode,
                        __u16 *netfid, int *pOplock, FILE_ALL_INFO *,
                        const struct nls_table *nls_codepage, int remap);
-extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon,
                        u32 posix_flags, __u64 mode, __u16 *netfid,
                        FILE_UNIX_BASIC_INFO *pRetData,
                        __u32 *pOplock, const char *name,
                        const struct nls_table *nls_codepage, int remap);
-extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBClose(const int xid, struct cifs_tcon *tcon,
                        const int smb_file_id);
 
-extern int CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBFlush(const int xid, struct cifs_tcon *tcon,
                        const int smb_file_id);
 
-extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
-                       const int netfid, unsigned int count,
-                       const __u64 lseek, unsigned int *nbytes, char **buf,
+extern int CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms,
+                       unsigned int *nbytes, char **buf,
                        int *return_buf_type);
-extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
-                       const int netfid, const unsigned int count,
-                       const __u64 lseek, unsigned int *nbytes,
-                       const char *buf, const char __user *ubuf,
+extern int CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
+                       unsigned int *nbytes, const char *buf,
+                       const char __user *ubuf, const int long_op);
+extern int CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
+                       unsigned int *nbytes, struct kvec *iov, const int nvec,
                        const int long_op);
-extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
-                       const int netfid, const unsigned int count,
-                       const __u64 offset, unsigned int *nbytes,
-                       struct kvec *iov, const int nvec, const int long_op);
-extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
                        const unsigned char *searchName, __u64 *inode_number,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
 
-extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
                        const __u16 netfid, const __u64 len,
                        const __u64 offset, const __u32 numUnlock,
                        const __u32 numLock, const __u8 lockType,
                        const bool waitFlag, const __u8 oplock_level);
-extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
                        const __u16 smb_file_id, const int get_flag,
                        const __u64 len, struct file_lock *,
                        const __u16 lock_type, const bool waitFlag);
-extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon);
+extern int CIFSSMBTDis(const int xid, struct cifs_tcon *tcon);
 extern int CIFSSMBEcho(struct TCP_Server_Info *server);
-extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses);
+extern int CIFSSMBLogoff(const int xid, struct cifs_ses *ses);
 
-extern struct cifsSesInfo *sesInfoAlloc(void);
-extern void sesInfoFree(struct cifsSesInfo *);
-extern struct cifsTconInfo *tconInfoAlloc(void);
-extern void tconInfoFree(struct cifsTconInfo *);
+extern struct cifs_ses *sesInfoAlloc(void);
+extern void sesInfoFree(struct cifs_ses *);
+extern struct cifs_tcon *tconInfoAlloc(void);
+extern void tconInfoFree(struct cifs_tcon *);
 
 extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *);
 extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
@@ -379,51 +384,51 @@ extern int cifs_verify_signature(struct smb_hdr *,
                                 struct TCP_Server_Info *server,
                                __u32 expected_sequence_number);
 extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *);
-extern int setup_ntlm_response(struct cifsSesInfo *);
-extern int setup_ntlmv2_rsp(struct cifsSesInfo *, const struct nls_table *);
+extern int setup_ntlm_response(struct cifs_ses *);
+extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
 extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
 extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
-extern int calc_seckey(struct cifsSesInfo *);
+extern int calc_seckey(struct cifs_ses *);
 
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
 extern int calc_lanman_hash(const char *password, const char *cryptkey,
                                bool encrypt, char *lnm_session_key);
 #endif /* CIFS_WEAK_PW_HASH */
 #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */
-extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
                        const int notify_subdirs, const __u16 netfid,
                        __u32 filter, struct file *file, int multishot,
                        const struct nls_table *nls_codepage);
 #endif /* was needed for dnotify, and will be needed for inotify when VFS fix */
 extern int CIFSSMBCopy(int xid,
-                       struct cifsTconInfo *source_tcon,
+                       struct cifs_tcon *source_tcon,
                        const char *fromName,
                        const __u16 target_tid,
                        const char *toName, const int flags,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
-extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
+extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
                        const unsigned char *searchName,
                        const unsigned char *ea_name, char *EAData,
                        size_t bufsize, const struct nls_table *nls_codepage,
                        int remap_special_chars);
-extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon,
                const char *fileName, const char *ea_name,
                const void *ea_value, const __u16 ea_value_len,
                const struct nls_table *nls_codepage, int remap_special_chars);
-extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon,
                        __u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
-extern int CIFSSMBSetCIFSACL(const int, struct cifsTconInfo *, __u16,
+extern int CIFSSMBSetCIFSACL(const int, struct cifs_tcon *, __u16,
                        struct cifs_ntsd *, __u32);
-extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
                const unsigned char *searchName,
                char *acl_inf, const int buflen, const int acl_type,
                const struct nls_table *nls_codepage, int remap_special_chars);
-extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon,
                const unsigned char *fileName,
                const char *local_acl, const int buflen, const int acl_type,
                const struct nls_table *nls_codepage, int remap_special_chars);
-extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon,
                        const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
 extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb);
 extern bool CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr);
@@ -434,4 +439,22 @@ extern int mdfour(unsigned char *, unsigned char *, int);
 extern int E_md4hash(const unsigned char *passwd, unsigned char *p16);
 extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
                        unsigned char *p24);
+
+/* asynchronous write support */
+struct cifs_writedata {
+       struct kref                     refcount;
+       enum writeback_sync_modes       sync_mode;
+       struct work_struct              work;
+       struct cifsFileInfo             *cfile;
+       __u64                           offset;
+       unsigned int                    bytes;
+       int                             result;
+       unsigned int                    nr_pages;
+       struct page                     *pages[1];
+};
+
+int cifs_async_writev(struct cifs_writedata *wdata);
+struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages);
+void cifs_writedata_release(struct kref *refcount);
+
 #endif                 /* _CIFSPROTO_H */
index 83df937b814e0b92bd99020a35e5db8988e4a1c4..1a9fe7f816d1b83dd630141412d3dd109b23a385 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/vfs.h>
 #include <linux/slab.h>
 #include <linux/posix_acl_xattr.h>
+#include <linux/pagemap.h>
 #include <asm/uaccess.h>
 #include "cifspdu.h"
 #include "cifsglob.h"
@@ -84,7 +85,7 @@ static struct {
 
 /* Mark as invalid, all open files on tree connections since they
    were closed when session to server was lost */
-static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
+static void mark_open_files_invalid(struct cifs_tcon *pTcon)
 {
        struct cifsFileInfo *open_file = NULL;
        struct list_head *tmp;
@@ -104,10 +105,10 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
 
 /* reconnect the socket, tcon, and smb session if needed */
 static int
-cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
+cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
 {
        int rc = 0;
-       struct cifsSesInfo *ses;
+       struct cifs_ses *ses;
        struct TCP_Server_Info *server;
        struct nls_table *nls_codepage;
 
@@ -226,7 +227,7 @@ out:
    SMB information in the SMB header.  If the return code is zero, this
    function must have filled in request_buf pointer */
 static int
-small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
+small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
                void **request_buf)
 {
        int rc;
@@ -252,7 +253,7 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
 
 int
 small_smb_init_no_tc(const int smb_command, const int wct,
-                    struct cifsSesInfo *ses, void **request_buf)
+                    struct cifs_ses *ses, void **request_buf)
 {
        int rc;
        struct smb_hdr *buffer;
@@ -278,7 +279,7 @@ small_smb_init_no_tc(const int smb_command, const int wct,
 
 /* If the return code is zero, this function must fill in request_buf pointer */
 static int
-__smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
+__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
                        void **request_buf, void **response_buf)
 {
        *request_buf = cifs_buf_get();
@@ -304,7 +305,7 @@ __smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
 
 /* If the return code is zero, this function must fill in request_buf pointer */
 static int
-smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
+smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
         void **request_buf, void **response_buf)
 {
        int rc;
@@ -317,7 +318,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
 }
 
 static int
-smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon,
+smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
                        void **request_buf, void **response_buf)
 {
        if (tcon->ses->need_reconnect || tcon->need_reconnect)
@@ -366,7 +367,7 @@ static inline void inc_rfc1001_len(void *pSMB, int count)
 }
 
 int
-CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
+CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
 {
        NEGOTIATE_REQ *pSMB;
        NEGOTIATE_RSP *pSMBr;
@@ -450,7 +451,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                        rc = -EOPNOTSUPP;
                        goto neg_err_exit;
                }
-               server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
+               server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
                server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
                server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
                                (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
@@ -504,7 +505,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                                cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
                        memcpy(ses->server->cryptkey, rsp->EncryptionKey,
                                CIFS_CRYPTO_KEY_SIZE);
-               } else if (server->secMode & SECMODE_PW_ENCRYPT) {
+               } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
                        rc = -EIO; /* need cryptkey unless plain text */
                        goto neg_err_exit;
                }
@@ -526,11 +527,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                goto neg_err_exit;
        }
        /* else wct == 17 NTLM */
-       server->secMode = pSMBr->SecurityMode;
-       if ((server->secMode & SECMODE_USER) == 0)
+       server->sec_mode = pSMBr->SecurityMode;
+       if ((server->sec_mode & SECMODE_USER) == 0)
                cFYI(1, "share mode security");
 
-       if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
+       if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
                if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
 #endif /* CIFS_WEAK_PW_HASH */
@@ -570,18 +571,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
        if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
                memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
                       CIFS_CRYPTO_KEY_SIZE);
-       } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
-                       && (pSMBr->EncryptionKeyLength == 0)) {
+       } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
+                       server->capabilities & CAP_EXTENDED_SECURITY) &&
+                               (pSMBr->EncryptionKeyLength == 0)) {
                /* decode security blob */
-       } else if (server->secMode & SECMODE_PW_ENCRYPT) {
-               rc = -EIO; /* no crypt key only if plain text pwd */
-               goto neg_err_exit;
-       }
-
-       /* BB might be helpful to save off the domain of server here */
-
-       if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
-               (server->capabilities & CAP_EXTENDED_SECURITY)) {
                count = get_bcc(&pSMBr->hdr);
                if (count < 16) {
                        rc = -EIO;
@@ -624,6 +617,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                        } else
                                        rc = -EOPNOTSUPP;
                }
+       } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
+               rc = -EIO; /* no crypt key only if plain text pwd */
+               goto neg_err_exit;
        } else
                server->capabilities &= ~CAP_EXTENDED_SECURITY;
 
@@ -634,27 +630,27 @@ signing_check:
                /* MUST_SIGN already includes the MAY_SIGN FLAG
                   so if this is zero it means that signing is disabled */
                cFYI(1, "Signing disabled");
-               if (server->secMode & SECMODE_SIGN_REQUIRED) {
+               if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
                        cERROR(1, "Server requires "
                                   "packet signing to be enabled in "
                                   "/proc/fs/cifs/SecurityFlags.");
                        rc = -EOPNOTSUPP;
                }
-               server->secMode &=
+               server->sec_mode &=
                        ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
        } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
                /* signing required */
                cFYI(1, "Must sign - secFlags 0x%x", secFlags);
-               if ((server->secMode &
+               if ((server->sec_mode &
                        (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
                        cERROR(1, "signing required but server lacks support");
                        rc = -EOPNOTSUPP;
                } else
-                       server->secMode |= SECMODE_SIGN_REQUIRED;
+                       server->sec_mode |= SECMODE_SIGN_REQUIRED;
        } else {
                /* signing optional ie CIFSSEC_MAY_SIGN */
-               if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
-                       server->secMode &=
+               if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
+                       server->sec_mode &=
                                ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
        }
 
@@ -666,7 +662,7 @@ neg_err_exit:
 }
 
 int
-CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
+CIFSSMBTDis(const int xid, struct cifs_tcon *tcon)
 {
        struct smb_hdr *smb_buffer;
        int rc = 0;
@@ -725,6 +721,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
 {
        ECHO_REQ *smb;
        int rc = 0;
+       struct kvec iov;
 
        cFYI(1, "In echo request");
 
@@ -739,9 +736,10 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
        put_bcc(1, &smb->hdr);
        smb->Data[0] = 'a';
        inc_rfc1001_len(smb, 3);
+       iov.iov_base = smb;
+       iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
 
-       rc = cifs_call_async(server, (struct smb_hdr *)smb,
-                               cifs_echo_callback, server);
+       rc = cifs_call_async(server, &iov, 1, cifs_echo_callback, server, true);
        if (rc)
                cFYI(1, "Echo request failed: %d", rc);
 
@@ -751,7 +749,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
 }
 
 int
-CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
+CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
 {
        LOGOFF_ANDX_REQ *pSMB;
        int rc = 0;
@@ -778,7 +776,7 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
 
        pSMB->hdr.Mid = GetNextMid(ses->server);
 
-       if (ses->server->secMode &
+       if (ses->server->sec_mode &
                   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                        pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
@@ -798,7 +796,7 @@ session_already_dead:
 }
 
 int
-CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
+CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
                 __u16 type, const struct nls_table *nls_codepage, int remap)
 {
        TRANSACTION2_SPI_REQ *pSMB = NULL;
@@ -873,7 +871,7 @@ PsxDelete:
 }
 
 int
-CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
+CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
               const struct nls_table *nls_codepage, int remap)
 {
        DELETE_FILE_REQ *pSMB = NULL;
@@ -918,7 +916,7 @@ DelFileRetry:
 }
 
 int
-CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
+CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon, const char *dirName,
             const struct nls_table *nls_codepage, int remap)
 {
        DELETE_DIRECTORY_REQ *pSMB = NULL;
@@ -961,7 +959,7 @@ RmDirRetry:
 }
 
 int
-CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon,
             const char *name, const struct nls_table *nls_codepage, int remap)
 {
        int rc = 0;
@@ -1004,7 +1002,7 @@ MkDirRetry:
 }
 
 int
-CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
+CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon, __u32 posix_flags,
                __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
                __u32 *pOplock, const char *name,
                const struct nls_table *nls_codepage, int remap)
@@ -1170,7 +1168,7 @@ access_flags_to_smbopen_mode(const int access_flags)
 }
 
 int
-SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
+SMBLegacyOpen(const int xid, struct cifs_tcon *tcon,
            const char *fileName, const int openDisposition,
            const int access_flags, const int create_options, __u16 *netfid,
            int *pOplock, FILE_ALL_INFO *pfile_info,
@@ -1277,7 +1275,7 @@ OldOpenRetry:
 }
 
 int
-CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
            const char *fileName, const int openDisposition,
            const int access_flags, const int create_options, __u16 *netfid,
            int *pOplock, FILE_ALL_INFO *pfile_info,
@@ -1379,8 +1377,7 @@ openRetry:
 }
 
 int
-CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
-           const unsigned int count, const __u64 lseek, unsigned int *nbytes,
+CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
            char **buf, int *pbuf_type)
 {
        int rc = -EACCES;
@@ -1390,13 +1387,18 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
        int wct;
        int resp_buf_type = 0;
        struct kvec iov[1];
+       __u32 pid = io_parms->pid;
+       __u16 netfid = io_parms->netfid;
+       __u64 offset = io_parms->offset;
+       struct cifs_tcon *tcon = io_parms->tcon;
+       unsigned int count = io_parms->length;
 
        cFYI(1, "Reading %d bytes on fid %d", count, netfid);
        if (tcon->ses->capabilities & CAP_LARGE_FILES)
                wct = 12;
        else {
                wct = 10; /* old style read */
-               if ((lseek >> 32) > 0)  {
+               if ((offset >> 32) > 0)  {
                        /* can not handle this big offset for old */
                        return -EIO;
                }
@@ -1407,15 +1409,18 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
        if (rc)
                return rc;
 
+       pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
+       pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
+
        /* tcon and ses pointer are checked in smb_init */
        if (tcon->ses->server == NULL)
                return -ECONNABORTED;
 
        pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = netfid;
-       pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
+       pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
        if (wct == 12)
-               pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
+               pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
 
        pSMB->Remaining = 0;
        pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
@@ -1484,9 +1489,8 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
 
 
 int
-CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
-            const int netfid, const unsigned int count,
-            const __u64 offset, unsigned int *nbytes, const char *buf,
+CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
+            unsigned int *nbytes, const char *buf,
             const char __user *ubuf, const int long_op)
 {
        int rc = -EACCES;
@@ -1495,6 +1499,11 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        int bytes_returned, wct;
        __u32 bytes_sent;
        __u16 byte_count;
+       __u32 pid = io_parms->pid;
+       __u16 netfid = io_parms->netfid;
+       __u64 offset = io_parms->offset;
+       struct cifs_tcon *tcon = io_parms->tcon;
+       unsigned int count = io_parms->length;
 
        *nbytes = 0;
 
@@ -1516,6 +1525,10 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
                      (void **) &pSMBr);
        if (rc)
                return rc;
+
+       pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
+       pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
+
        /* tcon and ses pointer are checked in smb_init */
        if (tcon->ses->server == NULL)
                return -ECONNABORTED;
@@ -1602,17 +1615,259 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        return rc;
 }
 
+void
+cifs_writedata_release(struct kref *refcount)
+{
+       struct cifs_writedata *wdata = container_of(refcount,
+                                       struct cifs_writedata, refcount);
+
+       if (wdata->cfile)
+               cifsFileInfo_put(wdata->cfile);
+
+       kfree(wdata);
+}
+
+/*
+ * Write failed with a retryable error. Resend the write request. It's also
+ * possible that the page was redirtied so re-clean the page.
+ */
+static void
+cifs_writev_requeue(struct cifs_writedata *wdata)
+{
+       int i, rc;
+       struct inode *inode = wdata->cfile->dentry->d_inode;
+
+       for (i = 0; i < wdata->nr_pages; i++) {
+               lock_page(wdata->pages[i]);
+               clear_page_dirty_for_io(wdata->pages[i]);
+       }
+
+       do {
+               rc = cifs_async_writev(wdata);
+       } while (rc == -EAGAIN);
+
+       for (i = 0; i < wdata->nr_pages; i++) {
+               if (rc != 0)
+                       SetPageError(wdata->pages[i]);
+               unlock_page(wdata->pages[i]);
+       }
+
+       mapping_set_error(inode->i_mapping, rc);
+       kref_put(&wdata->refcount, cifs_writedata_release);
+}
+
+static void
+cifs_writev_complete(struct work_struct *work)
+{
+       struct cifs_writedata *wdata = container_of(work,
+                                               struct cifs_writedata, work);
+       struct inode *inode = wdata->cfile->dentry->d_inode;
+       int i = 0;
+
+       if (wdata->result == 0) {
+               cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
+               cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
+                                        wdata->bytes);
+       } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
+               return cifs_writev_requeue(wdata);
+
+       for (i = 0; i < wdata->nr_pages; i++) {
+               struct page *page = wdata->pages[i];
+               if (wdata->result == -EAGAIN)
+                       __set_page_dirty_nobuffers(page);
+               else if (wdata->result < 0)
+                       SetPageError(page);
+               end_page_writeback(page);
+               page_cache_release(page);
+       }
+       if (wdata->result != -EAGAIN)
+               mapping_set_error(inode->i_mapping, wdata->result);
+       kref_put(&wdata->refcount, cifs_writedata_release);
+}
+
+struct cifs_writedata *
+cifs_writedata_alloc(unsigned int nr_pages)
+{
+       struct cifs_writedata *wdata;
+
+       /* this would overflow */
+       if (nr_pages == 0) {
+               cERROR(1, "%s: called with nr_pages == 0!", __func__);
+               return NULL;
+       }
+
+       /* writedata + number of page pointers */
+       wdata = kzalloc(sizeof(*wdata) +
+                       sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
+       if (wdata != NULL) {
+               INIT_WORK(&wdata->work, cifs_writev_complete);
+               kref_init(&wdata->refcount);
+       }
+       return wdata;
+}
+
+/*
+ * Check the midState and signature on received buffer (if any), and queue the
+ * workqueue completion task.
+ */
+static void
+cifs_writev_callback(struct mid_q_entry *mid)
+{
+       struct cifs_writedata *wdata = mid->callback_data;
+       struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
+       unsigned int written;
+       WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
+
+       switch (mid->midState) {
+       case MID_RESPONSE_RECEIVED:
+               wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
+               if (wdata->result != 0)
+                       break;
+
+               written = le16_to_cpu(smb->CountHigh);
+               written <<= 16;
+               written += le16_to_cpu(smb->Count);
+               /*
+                * Mask off high 16 bits when bytes written as returned
+                * by the server is greater than bytes requested by the
+                * client. OS/2 servers are known to set incorrect
+                * CountHigh values.
+                */
+               if (written > wdata->bytes)
+                       written &= 0xFFFF;
+
+               if (written < wdata->bytes)
+                       wdata->result = -ENOSPC;
+               else
+                       wdata->bytes = written;
+               break;
+       case MID_REQUEST_SUBMITTED:
+       case MID_RETRY_NEEDED:
+               wdata->result = -EAGAIN;
+               break;
+       default:
+               wdata->result = -EIO;
+               break;
+       }
+
+       queue_work(system_nrt_wq, &wdata->work);
+       DeleteMidQEntry(mid);
+       atomic_dec(&tcon->ses->server->inFlight);
+       wake_up(&tcon->ses->server->request_q);
+}
+
+/* cifs_async_writev - send an async write, and set up mid to handle result */
+int
+cifs_async_writev(struct cifs_writedata *wdata)
+{
+       int i, rc = -EACCES;
+       WRITE_REQ *smb = NULL;
+       int wct;
+       struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
+       struct inode *inode = wdata->cfile->dentry->d_inode;
+       struct kvec *iov = NULL;
+
+       if (tcon->ses->capabilities & CAP_LARGE_FILES) {
+               wct = 14;
+       } else {
+               wct = 12;
+               if (wdata->offset >> 32 > 0) {
+                       /* can not handle big offset for old srv */
+                       return -EIO;
+               }
+       }
+
+       rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
+       if (rc)
+               goto async_writev_out;
+
+       /* 1 iov per page + 1 for header */
+       iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
+       if (iov == NULL) {
+               rc = -ENOMEM;
+               goto async_writev_out;
+       }
+
+       smb->hdr.Pid = cpu_to_le16((__u16)wdata->cfile->pid);
+       smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->cfile->pid >> 16));
+
+       smb->AndXCommand = 0xFF;        /* none */
+       smb->Fid = wdata->cfile->netfid;
+       smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
+       if (wct == 14)
+               smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
+       smb->Reserved = 0xFFFFFFFF;
+       smb->WriteMode = 0;
+       smb->Remaining = 0;
+
+       smb->DataOffset =
+           cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
+
+       /* 4 for RFC1001 length + 1 for BCC */
+       iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
+       iov[0].iov_base = smb;
+
+       /* marshal up the pages into iov array */
+       wdata->bytes = 0;
+       for (i = 0; i < wdata->nr_pages; i++) {
+               iov[i + 1].iov_len = min(inode->i_size -
+                                     page_offset(wdata->pages[i]),
+                                       (loff_t)PAGE_CACHE_SIZE);
+               iov[i + 1].iov_base = kmap(wdata->pages[i]);
+               wdata->bytes += iov[i + 1].iov_len;
+       }
+
+       cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
+
+       smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
+       smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
+
+       if (wct == 14) {
+               inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
+               put_bcc(wdata->bytes + 1, &smb->hdr);
+       } else {
+               /* wct == 12 */
+               struct smb_com_writex_req *smbw =
+                               (struct smb_com_writex_req *)smb;
+               inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
+               put_bcc(wdata->bytes + 5, &smbw->hdr);
+               iov[0].iov_len += 4; /* pad bigger by four bytes */
+       }
+
+       kref_get(&wdata->refcount);
+       rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
+                            cifs_writev_callback, wdata, false);
+
+       if (rc == 0)
+               cifs_stats_inc(&tcon->num_writes);
+       else
+               kref_put(&wdata->refcount, cifs_writedata_release);
+
+       /* send is done, unmap pages */
+       for (i = 0; i < wdata->nr_pages; i++)
+               kunmap(wdata->pages[i]);
+
+async_writev_out:
+       cifs_small_buf_release(smb);
+       kfree(iov);
+       return rc;
+}
+
 int
-CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
-            const int netfid, const unsigned int count,
-            const __u64 offset, unsigned int *nbytes, struct kvec *iov,
-            int n_vec, const int long_op)
+CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
+             unsigned int *nbytes, struct kvec *iov, int n_vec,
+             const int long_op)
 {
        int rc = -EACCES;
        WRITE_REQ *pSMB = NULL;
        int wct;
        int smb_hdr_len;
        int resp_buf_type = 0;
+       __u32 pid = io_parms->pid;
+       __u16 netfid = io_parms->netfid;
+       __u64 offset = io_parms->offset;
+       struct cifs_tcon *tcon = io_parms->tcon;
+       unsigned int count = io_parms->length;
 
        *nbytes = 0;
 
@@ -1630,6 +1885,10 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
        rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
        if (rc)
                return rc;
+
+       pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
+       pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
+
        /* tcon and ses pointer are checked in smb_init */
        if (tcon->ses->server == NULL)
                return -ECONNABORTED;
@@ -1705,7 +1964,7 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 
 
 int
-CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
            const __u16 smb_file_id, const __u64 len,
            const __u64 offset, const __u32 numUnlock,
            const __u32 numLock, const __u8 lockType,
@@ -1775,7 +2034,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
 }
 
 int
-CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
                const __u16 smb_file_id, const int get_flag, const __u64 len,
                struct file_lock *pLockData, const __u16 lock_type,
                const bool waitFlag)
@@ -1913,7 +2172,7 @@ plk_err_exit:
 
 
 int
-CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
+CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
 {
        int rc = 0;
        CLOSE_REQ *pSMB = NULL;
@@ -1946,7 +2205,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
 }
 
 int
-CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
+CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
 {
        int rc = 0;
        FLUSH_REQ *pSMB = NULL;
@@ -1967,7 +2226,7 @@ CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
 }
 
 int
-CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBRename(const int xid, struct cifs_tcon *tcon,
              const char *fromName, const char *toName,
              const struct nls_table *nls_codepage, int remap)
 {
@@ -2034,7 +2293,7 @@ renameRetry:
        return rc;
 }
 
-int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
+int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
                int netfid, const char *target_name,
                const struct nls_table *nls_codepage, int remap)
 {
@@ -2114,7 +2373,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
 }
 
 int
-CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
+CIFSSMBCopy(const int xid, struct cifs_tcon *tcon, const char *fromName,
            const __u16 target_tid, const char *toName, const int flags,
            const struct nls_table *nls_codepage, int remap)
 {
@@ -2182,7 +2441,7 @@ copyRetry:
 }
 
 int
-CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
+CIFSUnixCreateSymLink(const int xid, struct cifs_tcon *tcon,
                      const char *fromName, const char *toName,
                      const struct nls_table *nls_codepage)
 {
@@ -2271,7 +2530,7 @@ createSymLinkRetry:
 }
 
 int
-CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
+CIFSUnixCreateHardLink(const int xid, struct cifs_tcon *tcon,
                       const char *fromName, const char *toName,
                       const struct nls_table *nls_codepage, int remap)
 {
@@ -2356,7 +2615,7 @@ createHardLinkRetry:
 }
 
 int
-CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
+CIFSCreateHardLink(const int xid, struct cifs_tcon *tcon,
                   const char *fromName, const char *toName,
                   const struct nls_table *nls_codepage, int remap)
 {
@@ -2428,7 +2687,7 @@ winCreateHardLinkRetry:
 }
 
 int
-CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBUnixQuerySymLink(const int xid, struct cifs_tcon *tcon,
                        const unsigned char *searchName, char **symlinkinfo,
                        const struct nls_table *nls_codepage)
 {
@@ -2533,7 +2792,7 @@ querySymLinkRetry:
  *     it is not compiled in by default until callers fixed up and more tested.
  */
 int
-CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon,
                        const unsigned char *searchName,
                        char *symlinkinfo, const int buflen, __u16 fid,
                        const struct nls_table *nls_codepage)
@@ -2771,7 +3030,7 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
 }
 
 int
-CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
                   const unsigned char *searchName,
                   char *acl_inf, const int buflen, const int acl_type,
                   const struct nls_table *nls_codepage, int remap)
@@ -2859,7 +3118,7 @@ queryAclRetry:
 }
 
 int
-CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon,
                   const unsigned char *fileName,
                   const char *local_acl, const int buflen,
                   const int acl_type,
@@ -2939,7 +3198,7 @@ setACLerrorExit:
 
 /* BB fix tabs in this function FIXME BB */
 int
-CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
+CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon,
               const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
 {
        int rc = 0;
@@ -3032,7 +3291,7 @@ GetExtAttrOut:
  */
 static int
 smb_init_nttransact(const __u16 sub_command, const int setup_count,
-                  const int parm_len, struct cifsTconInfo *tcon,
+                  const int parm_len, struct cifs_tcon *tcon,
                   void **ret_buf)
 {
        int rc;
@@ -3115,7 +3374,7 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata,
 
 /* Get Security Descriptor (by handle) from remote server for a file or dir */
 int
-CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
+CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
                  struct cifs_ntsd **acl_inf, __u32 *pbuflen)
 {
        int rc = 0;
@@ -3207,7 +3466,7 @@ qsec_out:
 }
 
 int
-CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
+CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
                        struct cifs_ntsd *pntsd, __u32 acllen)
 {
        __u16 byte_count, param_count, data_count, param_offset, data_offset;
@@ -3273,7 +3532,7 @@ setCifsAclRetry:
 
 /* Legacy Query Path Information call for lookup to old servers such
    as Win9x/WinME */
-int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
+int SMBQueryInformation(const int xid, struct cifs_tcon *tcon,
                        const unsigned char *searchName,
                        FILE_ALL_INFO *pFinfo,
                        const struct nls_table *nls_codepage, int remap)
@@ -3341,7 +3600,7 @@ QInfRetry:
 }
 
 int
-CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon,
                 u16 netfid, FILE_ALL_INFO *pFindData)
 {
        struct smb_t2_qfi_req *pSMB = NULL;
@@ -3408,7 +3667,7 @@ QFileInfoRetry:
 }
 
 int
-CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon,
                 const unsigned char *searchName,
                 FILE_ALL_INFO *pFindData,
                 int legacy /* old style infolevel */,
@@ -3509,7 +3768,7 @@ QPathInfoRetry:
 }
 
 int
-CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon,
                 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
 {
        struct smb_t2_qfi_req *pSMB = NULL;
@@ -3578,7 +3837,7 @@ UnixQFileInfoRetry:
 }
 
 int
-CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBUnixQPathInfo(const int xid, struct cifs_tcon *tcon,
                     const unsigned char *searchName,
                     FILE_UNIX_BASIC_INFO *pFindData,
                     const struct nls_table *nls_codepage, int remap)
@@ -3664,7 +3923,7 @@ UnixQPathInfoRetry:
 
 /* xid, tcon, searchName and codepage are input parms, rest are returned */
 int
-CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
+CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
              const char *searchName,
              const struct nls_table *nls_codepage,
              __u16 *pnetfid,
@@ -3812,7 +4071,7 @@ findFirstRetry:
        return rc;
 }
 
-int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
+int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
                 __u16 searchHandle, struct cifs_search_info *psrch_inf)
 {
        TRANSACTION2_FNEXT_REQ *pSMB = NULL;
@@ -3950,7 +4209,7 @@ FNext2_err_exit:
 }
 
 int
-CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
+CIFSFindClose(const int xid, struct cifs_tcon *tcon,
              const __u16 searchHandle)
 {
        int rc = 0;
@@ -3982,7 +4241,7 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
 }
 
 int
-CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
+CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
                      const unsigned char *searchName,
                      __u64 *inode_number,
                      const struct nls_table *nls_codepage, int remap)
@@ -4184,7 +4443,7 @@ parse_DFS_referrals_exit:
 }
 
 int
-CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
+CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
                const unsigned char *searchName,
                struct dfs_info3_param **target_nodes,
                unsigned int *num_of_nodes,
@@ -4233,7 +4492,7 @@ getDFSRetry:
        }
 
        if (ses->server) {
-               if (ses->server->secMode &
+               if (ses->server->sec_mode &
                   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                        pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
        }
@@ -4298,7 +4557,7 @@ GetDFSRefExit:
 
 /* Query File System Info such as free space to old servers such as Win 9x */
 int
-SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
+SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
 {
 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
        TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -4377,7 +4636,7 @@ oldQFSInfoRetry:
 }
 
 int
-CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
+CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
 {
 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
        TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -4456,7 +4715,7 @@ QFSInfoRetry:
 }
 
 int
-CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
+CIFSSMBQFSAttributeInfo(const int xid, struct cifs_tcon *tcon)
 {
 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
        TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -4526,7 +4785,7 @@ QFSAttributeRetry:
 }
 
 int
-CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
+CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon)
 {
 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
        TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -4597,7 +4856,7 @@ QFSDeviceRetry:
 }
 
 int
-CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
+CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon)
 {
 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
        TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -4667,7 +4926,7 @@ QFSUnixRetry:
 }
 
 int
-CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
+CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon, __u64 cap)
 {
 /* level 0x200  SMB_SET_CIFS_UNIX_INFO */
        TRANSACTION2_SETFSI_REQ *pSMB = NULL;
@@ -4741,7 +5000,7 @@ SETFSUnixRetry:
 
 
 int
-CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon,
                   struct kstatfs *FSData)
 {
 /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
@@ -4834,7 +5093,7 @@ QFSPosixRetry:
    in Samba which this routine can run into */
 
 int
-CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
+CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon, const char *fileName,
              __u64 size, bool SetAllocation,
              const struct nls_table *nls_codepage, int remap)
 {
@@ -4923,7 +5182,7 @@ SetEOFRetry:
 }
 
 int
-CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
+CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
                   __u16 fid, __u32 pid_of_opener, bool SetAllocation)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
@@ -5005,7 +5264,7 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
    time and resort to the original setpathinfo level which takes the ancient
    DOS time format with 2 second granularity */
 int
-CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
                    const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
@@ -5067,7 +5326,7 @@ CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
 }
 
 int
-CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
                          bool delete_file, __u16 fid, __u32 pid_of_opener)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
@@ -5123,7 +5382,7 @@ CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
 }
 
 int
-CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon,
                   const char *fileName, const FILE_BASIC_INFO *data,
                   const struct nls_table *nls_codepage, int remap)
 {
@@ -5207,7 +5466,7 @@ SetTimesRetry:
          handling it anyway and NT4 was what we thought it would be needed for
          Do not delete it until we prove whether needed for Win9x though */
 int
-CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
+CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon, char *fileName,
                __u16 dos_attrs, const struct nls_table *nls_codepage)
 {
        SETATTR_REQ *pSMB = NULL;
@@ -5295,7 +5554,7 @@ cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
 }
 
 int
-CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
                       const struct cifs_unix_set_info_args *args,
                       u16 fid, u32 pid_of_opener)
 {
@@ -5358,7 +5617,7 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
 }
 
 int
-CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
+CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *tcon, char *fileName,
                       const struct cifs_unix_set_info_args *args,
                       const struct nls_table *nls_codepage, int remap)
 {
@@ -5445,7 +5704,7 @@ setPermsRetry:
  * the data isn't copied to it, but the length is returned.
  */
 ssize_t
-CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
+CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
                const unsigned char *searchName, const unsigned char *ea_name,
                char *EAData, size_t buf_size,
                const struct nls_table *nls_codepage, int remap)
@@ -5626,7 +5885,7 @@ QAllEAsOut:
 }
 
 int
-CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
+CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, const char *fileName,
             const char *ea_name, const void *ea_value,
             const __u16 ea_value_len, const struct nls_table *nls_codepage,
             int remap)
@@ -5753,7 +6012,7 @@ SetEARetry:
  *     incompatible for network fs clients, we could instead simply
  *     expose this config flag by adding a future cifs (and smb2) notify ioctl.
  */
-int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
+int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
                  const int notify_subdirs, const __u16 netfid,
                  __u32 filter, struct file *pfile, int multishot,
                  const struct nls_table *nls_codepage)
index da284e3cb6535e206b9d502e45fdd1c5b9adf5d4..7f540df5252786b41d0af7c6bf3846a825069cb4 100644 (file)
 
 extern mempool_t *cifs_req_poolp;
 
-struct smb_vol {
-       char *username;
-       char *password;
-       char *domainname;
-       char *UNC;
-       char *UNCip;
-       char *iocharset;  /* local code page for mapping to and from Unicode */
-       char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */
-       char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */
-       uid_t cred_uid;
-       uid_t linux_uid;
-       gid_t linux_gid;
-       mode_t file_mode;
-       mode_t dir_mode;
-       unsigned secFlg;
-       bool retry:1;
-       bool intr:1;
-       bool setuids:1;
-       bool override_uid:1;
-       bool override_gid:1;
-       bool dynperm:1;
-       bool noperm:1;
-       bool no_psx_acl:1; /* set if posix acl support should be disabled */
-       bool cifs_acl:1;
-       bool no_xattr:1;   /* set if xattr (EA) support should be disabled*/
-       bool server_ino:1; /* use inode numbers from server ie UniqueId */
-       bool direct_io:1;
-       bool strict_io:1; /* strict cache behavior */
-       bool remap:1;      /* set to remap seven reserved chars in filenames */
-       bool posix_paths:1; /* unset to not ask for posix pathnames. */
-       bool no_linux_ext:1;
-       bool sfu_emul:1;
-       bool nullauth:1;   /* attempt to authenticate with null user */
-       bool nocase:1;     /* request case insensitive filenames */
-       bool nobrl:1;      /* disable sending byte range locks to srv */
-       bool mand_lock:1;  /* send mandatory not posix byte range lock reqs */
-       bool seal:1;       /* request transport encryption on share */
-       bool nodfs:1;      /* Do not request DFS, even if available */
-       bool local_lease:1; /* check leases only on local system, not remote */
-       bool noblocksnd:1;
-       bool noautotune:1;
-       bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
-       bool fsc:1;     /* enable fscache */
-       bool mfsymlinks:1; /* use Minshall+French Symlinks */
-       bool multiuser:1;
-       bool use_smb2:1; /* force smb2 use on mount instead of cifs */
-       unsigned int rsize;
-       unsigned int wsize;
-       bool sockopt_tcp_nodelay:1;
-       unsigned short int port;
-       unsigned long actimeo; /* attribute cache timeout (jiffies) */
-       char *prepath;
-       struct sockaddr_storage srcaddr; /* allow binding to a local IP */
-       struct nls_table *local_nls;
-};
-
 /* FIXME: should these be tunable? */
 #define TLINK_ERROR_EXPIRE     (1 * HZ)
 #define TLINK_IDLE_EXPIRE      (600 * HZ)
@@ -135,9 +79,10 @@ cifs_reconnect(struct TCP_Server_Info *server)
 {
        int rc = 0;
        struct list_head *tmp, *tmp2;
-       struct cifsSesInfo *ses;
-       struct cifsTconInfo *tcon;
+       struct cifs_ses *ses;
+       struct cifs_tcon *tcon;
        struct mid_q_entry *mid_entry;
+       struct list_head retry_list;
 
        spin_lock(&GlobalMid_Lock);
        if (server->tcpStatus == CifsExiting) {
@@ -157,11 +102,11 @@ cifs_reconnect(struct TCP_Server_Info *server)
        cFYI(1, "%s: marking sessions and tcons for reconnect", __func__);
        spin_lock(&cifs_tcp_ses_lock);
        list_for_each(tmp, &server->smb_ses_list) {
-               ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
+               ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
                ses->need_reconnect = true;
                ses->ipc_tid = 0;
                list_for_each(tmp2, &ses->tcon_list) {
-                       tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list);
+                       tcon = list_entry(tmp2, struct cifs_tcon, tcon_list);
                        tcon->need_reconnect = true;
                }
        }
@@ -189,18 +134,25 @@ cifs_reconnect(struct TCP_Server_Info *server)
        mutex_unlock(&server->srv_mutex);
 
        /* mark submitted MIDs for retry and issue callback */
-       cFYI(1, "%s: issuing mid callbacks", __func__);
+       INIT_LIST_HEAD(&retry_list);
+       cFYI(1, "%s: moving mids to private list", __func__);
        spin_lock(&GlobalMid_Lock);
        list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
                mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
                if (mid_entry->midState == MID_REQUEST_SUBMITTED)
                        mid_entry->midState = MID_RETRY_NEEDED;
+               list_move(&mid_entry->qhead, &retry_list);
+       }
+       spin_unlock(&GlobalMid_Lock);
+
+       cFYI(1, "%s: issuing mid callbacks", __func__);
+       list_for_each_safe(tmp, tmp2, &retry_list) {
+               mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
                list_del_init(&mid_entry->qhead);
                mid_entry->callback(mid_entry);
        }
-       spin_unlock(&GlobalMid_Lock);
 
-       while (server->tcpStatus == CifsNeedReconnect) {
+       do {
                try_to_freeze();
 
                /* we should try only the port we connected to before */
@@ -215,7 +167,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
                                server->tcpStatus = CifsNeedNegotiate;
                        spin_unlock(&GlobalMid_Lock);
                }
-       }
+       } while (server->tcpStatus == CifsNeedReconnect);
 
        return rc;
 }
@@ -672,12 +624,12 @@ multi_t2_fnd:
                        mid_entry->when_received = jiffies;
 #endif
                        list_del_init(&mid_entry->qhead);
-                       mid_entry->callback(mid_entry);
                        break;
                }
                spin_unlock(&GlobalMid_Lock);
 
                if (mid_entry != NULL) {
+                       mid_entry->callback(mid_entry);
                        /* Was previous buf put in mpx struct for multi-rsp? */
                        if (!isMultiRsp) {
                                /* smb buffer will be freed by user thread */
@@ -741,15 +693,25 @@ multi_t2_fnd:
                cifs_small_buf_release(smallbuf);
 
        if (!list_empty(&server->pending_mid_q)) {
+               struct list_head dispose_list;
+
+               INIT_LIST_HEAD(&dispose_list);
                spin_lock(&GlobalMid_Lock);
                list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
                        mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-                       cFYI(1, "Clearing Mid 0x%x - issuing callback",
-                                        mid_entry->mid);
+                       cFYI(1, "Clearing mid 0x%x", mid_entry->mid);
+                       mid_entry->midState = MID_SHUTDOWN;
+                       list_move(&mid_entry->qhead, &dispose_list);
+               }
+               spin_unlock(&GlobalMid_Lock);
+
+               /* now walk dispose list and issue callbacks */
+               list_for_each_safe(tmp, tmp2, &dispose_list) {
+                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+                       cFYI(1, "Callback mid 0x%x", mid_entry->mid);
                        list_del_init(&mid_entry->qhead);
                        mid_entry->callback(mid_entry);
                }
-               spin_unlock(&GlobalMid_Lock);
                /* 1/8th of sec is more than enough time for them to exit */
                msleep(125);
        }
@@ -822,7 +784,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                         struct smb_vol *vol)
 {
        char *value, *data, *end;
-       char *mountdata_copy, *options;
+       char *mountdata_copy = NULL, *options;
        unsigned int  temp_len, i, j;
        char separator[2];
        short int override_uid = -1;
@@ -1062,13 +1024,6 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                                   (strnicmp(value, "1", 1) == 0)) {
                                /* this is the default */
                                continue;
-                       } else if ((strnicmp(value, "smb2", 4) == 0) ||
-                                  (strnicmp(value, "2", 1) == 0)) {
-#ifdef CONFIG_CIFS_SMB2
-                               vol->use_smb2 = true;
-#else
-                               cERROR(1, "smb2 support not enabled");
-#endif /* CONFIG_CIFS_SMB2 */
                        }
                } else if ((strnicmp(data, "unc", 3) == 0)
                           || (strnicmp(data, "target", 6) == 0)
@@ -1404,6 +1359,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        vol->server_ino = 1;
                } else if (strnicmp(data, "noserverino", 9) == 0) {
                        vol->server_ino = 0;
+               } else if (strnicmp(data, "rwpidforward", 4) == 0) {
+                       vol->rwpidforward = 1;
                } else if (strnicmp(data, "cifsacl", 7) == 0) {
                        vol->cifs_acl = 1;
                } else if (strnicmp(data, "nocifsacl", 9) == 0) {
@@ -1434,7 +1391,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                                "/proc/fs/cifs/LookupCacheEnabled to 0\n");
                } else if (strnicmp(data, "fsc", 3) == 0) {
 #ifndef CONFIG_CIFS_FSCACHE
-                       cERROR(1, "FS-Cache support needs CONFIG_CIFS_FSCACHE"
+                       cERROR(1, "FS-Cache support needs CONFIG_CIFS_FSCACHE "
                                  "kernel config option set");
                        goto cifs_parse_mount_err;
 #endif
@@ -1640,16 +1597,35 @@ match_security(struct TCP_Server_Info *server, struct smb_vol *vol)
 
        /* now check if signing mode is acceptable */
        if ((secFlags & CIFSSEC_MAY_SIGN) == 0 &&
-           (server->secMode & SECMODE_SIGN_REQUIRED))
+           (server->sec_mode & SECMODE_SIGN_REQUIRED))
                        return false;
        else if (((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) &&
-                (server->secMode &
+                (server->sec_mode &
                  (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED)) == 0)
                        return false;
 
        return true;
 }
 
+static int match_server(struct TCP_Server_Info *server, struct sockaddr *addr,
+                        struct smb_vol *vol)
+{
+       if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns))
+               return 0;
+
+       if (!match_address(server, addr,
+                          (struct sockaddr *)&vol->srcaddr))
+               return 0;
+
+       if (!match_port(server, addr))
+               return 0;
+
+       if (!match_security(server, vol))
+               return 0;
+
+       return 1;
+}
+
 static struct TCP_Server_Info *
 cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
 {
@@ -1657,17 +1633,7 @@ cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
 
        spin_lock(&cifs_tcp_ses_lock);
        list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
-               if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns))
-                       continue;
-
-               if (!match_address(server, addr,
-                                  (struct sockaddr *)&vol->srcaddr))
-                       continue;
-
-               if (!match_port(server, addr))
-                       continue;
-
-               if (!match_security(server, vol))
+               if (!match_server(server, addr, vol))
                        continue;
 
                ++server->srv_count;
@@ -1861,32 +1827,39 @@ out_err:
        return ERR_PTR(rc);
 }
 
-static struct cifsSesInfo *
+static int match_session(struct cifs_ses *ses, struct smb_vol *vol)
+{
+       switch (ses->server->secType) {
+       case Kerberos:
+               if (vol->cred_uid != ses->cred_uid)
+                       return 0;
+               break;
+       default:
+               /* anything else takes username/password */
+               if (ses->user_name == NULL)
+                       return 0;
+               if (strncmp(ses->user_name, vol->username,
+                           MAX_USERNAME_SIZE))
+                       return 0;
+               if (strlen(vol->username) != 0 &&
+                   ses->password != NULL &&
+                   strncmp(ses->password,
+                           vol->password ? vol->password : "",
+                           MAX_PASSWORD_SIZE))
+                       return 0;
+       }
+       return 1;
+}
+
+static struct cifs_ses *
 cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
 {
-       struct cifsSesInfo *ses;
+       struct cifs_ses *ses;
 
        spin_lock(&cifs_tcp_ses_lock);
        list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
-               switch (server->secType) {
-               case Kerberos:
-                       if (vol->cred_uid != ses->cred_uid)
-                               continue;
-                       break;
-               default:
-                       /* anything else takes username/password */
-                       if (ses->user_name == NULL)
-                               continue;
-                       if (strncmp(ses->user_name, vol->username,
-                                   MAX_USERNAME_SIZE))
-                               continue;
-                       if (strlen(vol->username) != 0 &&
-                           ses->password != NULL &&
-                           strncmp(ses->password,
-                                   vol->password ? vol->password : "",
-                                   MAX_PASSWORD_SIZE))
-                               continue;
-               }
+               if (!match_session(ses, vol))
+                       continue;
                ++ses->ses_count;
                spin_unlock(&cifs_tcp_ses_lock);
                return ses;
@@ -1896,7 +1869,7 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
 }
 
 static void
-cifs_put_smb_ses(struct cifsSesInfo *ses)
+cifs_put_smb_ses(struct cifs_ses *ses)
 {
        int xid;
        struct TCP_Server_Info *server = ses->server;
@@ -1922,11 +1895,11 @@ cifs_put_smb_ses(struct cifsSesInfo *ses)
 
 static bool warned_on_ntlm;  /* globals init to false automatically */
 
-static struct cifsSesInfo *
+static struct cifs_ses *
 cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
 {
        int rc = -ENOMEM, xid;
-       struct cifsSesInfo *ses;
+       struct cifs_ses *ses;
        struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
        struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
 
@@ -2003,7 +1976,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
                warned_on_ntlm = true;
                cERROR(1, "default security mechanism requested.  The default "
                        "security mechanism will be upgraded from ntlm to "
-                       "ntlmv2 in kernel release 2.6.41");
+                       "ntlmv2 in kernel release 3.1");
        }
        ses->overrideSecFlg = volume_info->secFlg;
 
@@ -2029,20 +2002,26 @@ get_ses_fail:
        return ERR_PTR(rc);
 }
 
-static struct cifsTconInfo *
-cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
+static int match_tcon(struct cifs_tcon *tcon, const char *unc)
+{
+       if (tcon->tidStatus == CifsExiting)
+               return 0;
+       if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
+               return 0;
+       return 1;
+}
+
+static struct cifs_tcon *
+cifs_find_tcon(struct cifs_ses *ses, const char *unc)
 {
        struct list_head *tmp;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
 
        spin_lock(&cifs_tcp_ses_lock);
        list_for_each(tmp, &ses->tcon_list) {
-               tcon = list_entry(tmp, struct cifsTconInfo, tcon_list);
-               if (tcon->tidStatus == CifsExiting)
+               tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
+               if (!match_tcon(tcon, unc))
                        continue;
-               if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
-                       continue;
-
                ++tcon->tc_count;
                spin_unlock(&cifs_tcp_ses_lock);
                return tcon;
@@ -2052,10 +2031,10 @@ cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
 }
 
 static void
-cifs_put_tcon(struct cifsTconInfo *tcon)
+cifs_put_tcon(struct cifs_tcon *tcon)
 {
        int xid;
-       struct cifsSesInfo *ses = tcon->ses;
+       struct cifs_ses *ses = tcon->ses;
 
        cFYI(1, "%s: tc_count=%d\n", __func__, tcon->tc_count);
        spin_lock(&cifs_tcp_ses_lock);
@@ -2076,11 +2055,11 @@ cifs_put_tcon(struct cifsTconInfo *tcon)
        cifs_put_smb_ses(ses);
 }
 
-static struct cifsTconInfo *
-cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info)
+static struct cifs_tcon *
+cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
 {
        int rc, xid;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
 
        tcon = cifs_find_tcon(ses, volume_info->UNC);
        if (tcon) {
@@ -2169,8 +2148,105 @@ cifs_put_tlink(struct tcon_link *tlink)
        return;
 }
 
+static inline struct tcon_link *
+cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb)
+{
+       return cifs_sb->master_tlink;
+}
+
+static int
+compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data)
+{
+       struct cifs_sb_info *old = CIFS_SB(sb);
+       struct cifs_sb_info *new = mnt_data->cifs_sb;
+
+       if ((sb->s_flags & CIFS_MS_MASK) != (mnt_data->flags & CIFS_MS_MASK))
+               return 0;
+
+       if ((old->mnt_cifs_flags & CIFS_MOUNT_MASK) !=
+           (new->mnt_cifs_flags & CIFS_MOUNT_MASK))
+               return 0;
+
+       if (old->rsize != new->rsize)
+               return 0;
+
+       /*
+        * We want to share sb only if we don't specify wsize or specified wsize
+        * is greater or equal than existing one.
+        */
+       if (new->wsize && new->wsize < old->wsize)
+               return 0;
+
+       if (old->mnt_uid != new->mnt_uid || old->mnt_gid != new->mnt_gid)
+               return 0;
+
+       if (old->mnt_file_mode != new->mnt_file_mode ||
+           old->mnt_dir_mode != new->mnt_dir_mode)
+               return 0;
+
+       if (strcmp(old->local_nls->charset, new->local_nls->charset))
+               return 0;
+
+       if (old->actimeo != new->actimeo)
+               return 0;
+
+       return 1;
+}
+
+int
+cifs_match_super(struct super_block *sb, void *data)
+{
+       struct cifs_mnt_data *mnt_data = (struct cifs_mnt_data *)data;
+       struct smb_vol *volume_info;
+       struct cifs_sb_info *cifs_sb;
+       struct TCP_Server_Info *tcp_srv;
+       struct cifs_ses *ses;
+       struct cifs_tcon *tcon;
+       struct tcon_link *tlink;
+       struct sockaddr_storage addr;
+       int rc = 0;
+
+       memset(&addr, 0, sizeof(struct sockaddr_storage));
+
+       spin_lock(&cifs_tcp_ses_lock);
+       cifs_sb = CIFS_SB(sb);
+       tlink = cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
+       if (IS_ERR(tlink)) {
+               spin_unlock(&cifs_tcp_ses_lock);
+               return rc;
+       }
+       tcon = tlink_tcon(tlink);
+       ses = tcon->ses;
+       tcp_srv = ses->server;
+
+       volume_info = mnt_data->vol;
+
+       if (!volume_info->UNCip || !volume_info->UNC)
+               goto out;
+
+       rc = cifs_fill_sockaddr((struct sockaddr *)&addr,
+                               volume_info->UNCip,
+                               strlen(volume_info->UNCip),
+                               volume_info->port);
+       if (!rc)
+               goto out;
+
+       if (!match_server(tcp_srv, (struct sockaddr *)&addr, volume_info) ||
+           !match_session(ses, volume_info) ||
+           !match_tcon(tcon, volume_info->UNC)) {
+               rc = 0;
+               goto out;
+       }
+
+       rc = compare_mount_options(sb, mnt_data);
+out:
+       cifs_put_tlink(tlink);
+       spin_unlock(&cifs_tcp_ses_lock);
+       return rc;
+}
+
 int
-get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
+get_dfs_path(int xid, struct cifs_ses *pSesInfo, const char *old_path,
             const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
             struct dfs_info3_param **preferrals, int remap)
 {
@@ -2469,8 +2545,8 @@ ip_connect(struct TCP_Server_Info *server)
        return generic_ip_connect(server);
 }
 
-void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
-                         struct super_block *sb, struct smb_vol *vol_info)
+void reset_cifs_unix_caps(int xid, struct cifs_tcon *tcon,
+                         struct cifs_sb_info *cifs_sb, struct smb_vol *vol_info)
 {
        /* if we are reconnecting then should we check to see if
         * any requested capabilities changed locally e.g. via
@@ -2498,7 +2574,7 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
 
        if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
                __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
-
+               cFYI(1, "unix caps which server supports %lld", cap);
                /* check for reconnect case in which we do not
                   want to change the mount behavior if we can avoid it */
                if (vol_info == NULL) {
@@ -2516,33 +2592,31 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
                        }
                }
 
+               if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)
+                       cERROR(1, "per-share encryption not supported yet");
+
                cap &= CIFS_UNIX_CAP_MASK;
                if (vol_info && vol_info->no_psx_acl)
                        cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
                else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
                        cFYI(1, "negotiated posix acl support");
-                       if (sb)
-                               sb->s_flags |= MS_POSIXACL;
+                       if (cifs_sb)
+                               cifs_sb->mnt_cifs_flags |=
+                                       CIFS_MOUNT_POSIXACL;
                }
 
                if (vol_info && vol_info->posix_paths == 0)
                        cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
                else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
                        cFYI(1, "negotiate posix pathnames");
-                       if (sb)
-                               CIFS_SB(sb)->mnt_cifs_flags |=
+                       if (cifs_sb)
+                               cifs_sb->mnt_cifs_flags |=
                                        CIFS_MOUNT_POSIX_PATHS;
                }
 
-               /* We might be setting the path sep back to a different
-               form if we are reconnecting and the server switched its
-               posix path capability for this share */
-               if (sb && (CIFS_SB(sb)->prepathlen > 0))
-                       CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
-
-               if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
+               if (cifs_sb && (cifs_sb->rsize > 127 * 1024)) {
                        if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
-                               CIFS_SB(sb)->rsize = 127 * 1024;
+                               cifs_sb->rsize = 127 * 1024;
                                cFYI(DBG2, "larger reads not supported by srv");
                        }
                }
@@ -2564,6 +2638,10 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
                        cFYI(1, "very large read cap");
                if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
                        cFYI(1, "very large write cap");
+               if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)
+                       cFYI(1, "transport encryption cap");
+               if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)
+                       cFYI(1, "mandatory transport encryption cap");
 #endif /* CIFS_DEBUG2 */
                if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
                        if (vol_info == NULL) {
@@ -2580,31 +2658,14 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
        }
 }
 
-static void
-convert_delimiter(char *path, char delim)
-{
-       int i;
-       char old_delim;
-
-       if (path == NULL)
-               return;
-
-       if (delim == '/')
-               old_delim = '\\';
-       else
-               old_delim = '/';
-
-       for (i = 0; path[i] != '\0'; i++) {
-               if (path[i] == old_delim)
-                       path[i] = delim;
-       }
-}
-
-static void setup_cifs_sb(struct smb_vol *pvolume_info,
-                         struct cifs_sb_info *cifs_sb)
+void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
+                       struct cifs_sb_info *cifs_sb)
 {
        INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks);
 
+       spin_lock_init(&cifs_sb->tlink_tree_lock);
+       cifs_sb->tlink_tree = RB_ROOT;
+
        if (pvolume_info->rsize > CIFSMaxBufSize) {
                cERROR(1, "rsize %d too large, using MaxBufSize",
                        pvolume_info->rsize);
@@ -2615,40 +2676,19 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
        else /* default */
                cifs_sb->rsize = CIFSMaxBufSize;
 
-       if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
-               cERROR(1, "wsize %d too large, using 4096 instead",
-                         pvolume_info->wsize);
-               cifs_sb->wsize = 4096;
-       } else if (pvolume_info->wsize)
-               cifs_sb->wsize = pvolume_info->wsize;
-       else
-               cifs_sb->wsize = min_t(const int,
-                                       PAGEVEC_SIZE * PAGE_CACHE_SIZE,
-                                       127*1024);
-               /* old default of CIFSMaxBufSize was too small now
-                  that SMB Write2 can send multiple pages in kvec.
-                  RFC1001 does not describe what happens when frame
-                  bigger than 128K is sent so use that as max in
-                  conjunction with 52K kvec constraint on arch with 4K
-                  page size  */
-
        if (cifs_sb->rsize < 2048) {
                cifs_sb->rsize = 2048;
                /* Windows ME may prefer this */
                cFYI(1, "readsize set to minimum: 2048");
        }
-       /* calculate prepath */
-       cifs_sb->prepath = pvolume_info->prepath;
-       if (cifs_sb->prepath) {
-               cifs_sb->prepathlen = strlen(cifs_sb->prepath);
-               /* we can not convert the / to \ in the path
-               separators in the prefixpath yet because we do not
-               know (until reset_cifs_unix_caps is called later)
-               whether POSIX PATH CAP is available. We normalize
-               the / to \ after reset_cifs_unix_caps is called */
-               pvolume_info->prepath = NULL;
-       } else
-               cifs_sb->prepathlen = 0;
+
+       /*
+        * Temporarily set wsize for matching superblock. If we end up using
+        * new sb then cifs_negotiate_wsize will later negotiate it downward
+        * if needed.
+        */
+       cifs_sb->wsize = pvolume_info->wsize;
+
        cifs_sb->mnt_uid = pvolume_info->linux_uid;
        cifs_sb->mnt_gid = pvolume_info->linux_gid;
        cifs_sb->mnt_file_mode = pvolume_info->file_mode;
@@ -2657,6 +2697,7 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
                cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode);
 
        cifs_sb->actimeo = pvolume_info->actimeo;
+       cifs_sb->local_nls = pvolume_info->local_nls;
 
        if (pvolume_info->noperm)
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
@@ -2676,6 +2717,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC;
        if (pvolume_info->mand_lock)
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
+       if (pvolume_info->rwpidforward)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD;
        if (pvolume_info->cifs_acl)
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
        if (pvolume_info->override_uid)
@@ -2709,8 +2752,62 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
                           "mount option supported");
 }
 
+/*
+ * When the server supports very large writes via POSIX extensions, we can
+ * allow up to 2^24-1, minus the size of a WRITE_AND_X header, not including
+ * the RFC1001 length.
+ *
+ * Note that this might make for "interesting" allocation problems during
+ * writeback however as we have to allocate an array of pointers for the
+ * pages. A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096.
+ */
+#define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4)
+
+/*
+ * When the server doesn't allow large posix writes, only allow a wsize of
+ * 128k minus the size of the WRITE_AND_X header. That allows for a write up
+ * to the maximum size described by RFC1002.
+ */
+#define CIFS_MAX_RFC1002_WSIZE (128 * 1024 - sizeof(WRITE_REQ) + 4)
+
+/*
+ * The default wsize is 1M. find_get_pages seems to return a maximum of 256
+ * pages in a single call. With PAGE_CACHE_SIZE == 4k, this means we can fill
+ * a single wsize request with a single call.
+ */
+#define CIFS_DEFAULT_WSIZE (1024 * 1024)
+
+static unsigned int
+cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
+{
+       __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+       struct TCP_Server_Info *server = tcon->ses->server;
+       unsigned int wsize = pvolume_info->wsize ? pvolume_info->wsize :
+                               CIFS_DEFAULT_WSIZE;
+
+       /* can server support 24-bit write sizes? (via UNIX extensions) */
+       if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
+               wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1002_WSIZE);
+
+       /*
+        * no CAP_LARGE_WRITE_X or is signing enabled without CAP_UNIX set?
+        * Limit it to max buffer offered by the server, minus the size of the
+        * WRITEX header, not including the 4 byte RFC1001 length.
+        */
+       if (!(server->capabilities & CAP_LARGE_WRITE_X) ||
+           (!(server->capabilities & CAP_UNIX) &&
+            (server->sec_mode & (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED))))
+               wsize = min_t(unsigned int, wsize,
+                               server->maxBuf - sizeof(WRITE_REQ) + 4);
+
+       /* hard limit of CIFS_MAX_WSIZE */
+       wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
+
+       return wsize;
+}
+
 static int
-is_path_accessible(int xid, struct cifsTconInfo *tcon,
+is_path_accessible(int xid, struct cifs_tcon *tcon,
                   struct cifs_sb_info *cifs_sb, const char *full_path)
 {
        int rc;
@@ -2733,8 +2830,8 @@ is_path_accessible(int xid, struct cifsTconInfo *tcon,
        return rc;
 }
 
-static void
-cleanup_volume_info(struct smb_vol **pvolume_info)
+void
+cifs_cleanup_volume_info(struct smb_vol **pvolume_info)
 {
        struct smb_vol *volume_info;
 
@@ -2764,24 +2861,13 @@ build_unc_path_to_root(const struct smb_vol *volume_info,
        char *full_path;
 
        int unc_len = strnlen(volume_info->UNC, MAX_TREE_SIZE + 1);
-       full_path = kmalloc(unc_len + cifs_sb->prepathlen + 1, GFP_KERNEL);
+       full_path = kmalloc(unc_len + 1, GFP_KERNEL);
        if (full_path == NULL)
                return ERR_PTR(-ENOMEM);
 
        strncpy(full_path, volume_info->UNC, unc_len);
-       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
-               int i;
-               for (i = 0; i < unc_len; i++) {
-                       if (full_path[i] == '\\')
-                               full_path[i] = '/';
-               }
-       }
-
-       if (cifs_sb->prepathlen)
-               strncpy(full_path + unc_len, cifs_sb->prepath,
-                               cifs_sb->prepathlen);
-
-       full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */
+       full_path[unc_len] = 0; /* add trailing null */
+       convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb));
        return full_path;
 }
 
@@ -2796,7 +2882,7 @@ build_unc_path_to_root(const struct smb_vol *volume_info,
  * determine whether there were referrals.
  */
 static int
-expand_dfs_referral(int xid, struct cifsSesInfo *pSesInfo,
+expand_dfs_referral(int xid, struct cifs_ses *pSesInfo,
                    struct smb_vol *volume_info, struct cifs_sb_info *cifs_sb,
                    int check_prefix)
 {
@@ -2840,40 +2926,13 @@ expand_dfs_referral(int xid, struct cifsSesInfo *pSesInfo,
 }
 #endif
 
-int
-cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
-               const char *devname)
+int cifs_setup_volume_info(struct smb_vol **pvolume_info, char *mount_data,
+                          const char *devname)
 {
-       int rc;
-       int xid;
        struct smb_vol *volume_info;
-       struct cifsSesInfo *pSesInfo;
-       struct cifsTconInfo *tcon;
-       struct TCP_Server_Info *srvTcp;
-       char   *full_path;
-       struct tcon_link *tlink;
-#ifdef CONFIG_CIFS_DFS_UPCALL
-       int referral_walks_count = 0;
-try_mount_again:
-       /* cleanup activities if we're chasing a referral */
-       if (referral_walks_count) {
-               if (tcon)
-                       cifs_put_tcon(tcon);
-               else if (pSesInfo)
-                       cifs_put_smb_ses(pSesInfo);
-
-               cleanup_volume_info(&volume_info);
-               FreeXid(xid);
-       }
-#endif
-       rc = 0;
-       tcon = NULL;
-       pSesInfo = NULL;
-       srvTcp = NULL;
-       full_path = NULL;
-       tlink = NULL;
+       int rc = 0;
 
-       xid = GetXid();
+       *pvolume_info = NULL;
 
        volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL);
        if (!volume_info) {
@@ -2881,7 +2940,7 @@ try_mount_again:
                goto out;
        }
 
-       if (cifs_parse_mount_options(cifs_sb->mountdata, devname,
+       if (cifs_parse_mount_options(mount_data, devname,
                                     volume_info)) {
                rc = -EINVAL;
                goto out;
@@ -2889,7 +2948,11 @@ try_mount_again:
 
        if (volume_info->nullauth) {
                cFYI(1, "null user");
-               volume_info->username = "";
+               volume_info->username = kzalloc(1, GFP_KERNEL);
+               if (volume_info->username == NULL) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
        } else if (volume_info->username) {
                /* BB fixme parse for domain name here */
                cFYI(1, "Username: %s", volume_info->username);
@@ -2914,12 +2977,58 @@ try_mount_again:
                        goto out;
                }
        }
-       cifs_sb->local_nls = volume_info->local_nls;
+
+       *pvolume_info = volume_info;
+       return rc;
+out:
+       cifs_cleanup_volume_info(&volume_info);
+       return rc;
+}
+
+int
+cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
+{
+       int rc = 0;
+       int xid;
+       struct cifs_ses *pSesInfo;
+       struct cifs_tcon *tcon;
+       struct TCP_Server_Info *srvTcp;
+       char   *full_path;
+       struct tcon_link *tlink;
+#ifdef CONFIG_CIFS_DFS_UPCALL
+       int referral_walks_count = 0;
+
+       rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY);
+       if (rc)
+               return rc;
+
+       cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages;
+
+try_mount_again:
+       /* cleanup activities if we're chasing a referral */
+       if (referral_walks_count) {
+               if (tcon)
+                       cifs_put_tcon(tcon);
+               else if (pSesInfo)
+                       cifs_put_smb_ses(pSesInfo);
+
+               cifs_cleanup_volume_info(&volume_info);
+               FreeXid(xid);
+       }
+#endif
+       tcon = NULL;
+       pSesInfo = NULL;
+       srvTcp = NULL;
+       full_path = NULL;
+       tlink = NULL;
+
+       xid = GetXid();
 
        /* get a reference to a tcp session */
        srvTcp = cifs_get_tcp_session(volume_info);
        if (IS_ERR(srvTcp)) {
                rc = PTR_ERR(srvTcp);
+               bdi_destroy(&cifs_sb->bdi);
                goto out;
        }
 
@@ -2931,15 +3040,6 @@ try_mount_again:
                goto mount_fail_check;
        }
 
-       setup_cifs_sb(volume_info, cifs_sb);
-       if (pSesInfo->capabilities & CAP_LARGE_FILES)
-               sb->s_maxbytes = MAX_LFS_FILESIZE;
-       else
-               sb->s_maxbytes = MAX_NON_LFS;
-
-       /* BB FIXME fix time_gran to be larger for LANMAN sessions */
-       sb->s_time_gran = 100;
-
        /* search for existing tcon to this server share */
        tcon = cifs_get_tcon(pSesInfo, volume_info);
        if (IS_ERR(tcon)) {
@@ -2948,35 +3048,36 @@ try_mount_again:
                goto remote_path_check;
        }
 
-       /* do not care if following two calls succeed - informational */
-       if (!tcon->ipc) {
-               CIFSSMBQFSDeviceInfo(xid, tcon);
-               CIFSSMBQFSAttributeInfo(xid, tcon);
-       }
-
        /* tell server which Unix caps we support */
-       if (tcon->ses->capabilities & CAP_UNIX)
+       if (tcon->ses->capabilities & CAP_UNIX) {
                /* reset of caps checks mount to see if unix extensions
                   disabled for just this mount */
-               reset_cifs_unix_caps(xid, tcon, sb, volume_info);
-       else
+               reset_cifs_unix_caps(xid, tcon, cifs_sb, volume_info);
+               if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) &&
+                   (le64_to_cpu(tcon->fsUnixInfo.Capability) &
+                    CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)) {
+                       rc = -EACCES;
+                       goto mount_fail_check;
+               }
+       } else
                tcon->unix_ext = 0; /* server does not support them */
 
-       /* convert forward to back slashes in prepath here if needed */
-       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
-               convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
+       /* do not care if following two calls succeed - informational */
+       if (!tcon->ipc) {
+               CIFSSMBQFSDeviceInfo(xid, tcon);
+               CIFSSMBQFSAttributeInfo(xid, tcon);
+       }
 
        if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
                cifs_sb->rsize = 1024 * 127;
                cFYI(DBG2, "no very large read support, rsize now 127K");
        }
-       if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
-               cifs_sb->wsize = min(cifs_sb->wsize,
-                              (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
        if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
                cifs_sb->rsize = min(cifs_sb->rsize,
                               (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
 
+       cifs_sb->wsize = cifs_negotiate_wsize(tcon, volume_info);
+
 remote_path_check:
 #ifdef CONFIG_CIFS_DFS_UPCALL
        /*
@@ -2996,10 +3097,10 @@ remote_path_check:
        }
 #endif
 
-       /* check if a whole path (including prepath) is not remote */
+       /* check if a whole path is not remote */
        if (!rc && tcon) {
                /* build_path_to_root works only when we have a valid tcon */
-               full_path = cifs_build_path_to_root(cifs_sb, tcon);
+               full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon);
                if (full_path == NULL) {
                        rc = -ENOMEM;
                        goto mount_fail_check;
@@ -3025,10 +3126,6 @@ remote_path_check:
                        rc = -ELOOP;
                        goto mount_fail_check;
                }
-               /* convert forward to back slashes in prepath here if needed */
-               if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
-                       convert_delimiter(cifs_sb->prepath,
-                                       CIFS_DIR_SEP(cifs_sb));
 
                rc = expand_dfs_referral(xid, pSesInfo, volume_info, cifs_sb,
                                         true);
@@ -3078,6 +3175,7 @@ mount_fail_check:
                        cifs_put_smb_ses(pSesInfo);
                else
                        cifs_put_tcp_session(srvTcp);
+               bdi_destroy(&cifs_sb->bdi);
                goto out;
        }
 
@@ -3087,14 +3185,17 @@ mount_fail_check:
        password will be freed at unmount time) */
 out:
        /* zero out password before freeing */
-       cleanup_volume_info(&volume_info);
        FreeXid(xid);
        return rc;
 }
 
+/*
+ * Issue a TREE_CONNECT request. Note that for IPC$ shares, that the tcon
+ * pointer may be NULL.
+ */
 int
-CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
-        const char *tree, struct cifsTconInfo *tcon,
+CIFSTCon(unsigned int xid, struct cifs_ses *ses,
+        const char *tree, struct cifs_tcon *tcon,
         const struct nls_table *nls_codepage)
 {
        struct smb_hdr *smb_buffer;
@@ -3126,7 +3227,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
        pSMB->AndXCommand = 0xFF;
        pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
        bcc_ptr = &pSMB->Password[0];
-       if ((ses->server->secMode) & SECMODE_USER) {
+       if (!tcon || (ses->server->sec_mode & SECMODE_USER)) {
                pSMB->PasswordLength = cpu_to_le16(1);  /* minimum */
                *bcc_ptr = 0; /* password is null byte */
                bcc_ptr++;              /* skip password */
@@ -3143,7 +3244,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                if ((global_secflags & CIFSSEC_MAY_LANMAN) &&
                    (ses->server->secType == LANMAN))
                        calc_lanman_hash(tcon->password, ses->server->cryptkey,
-                                        ses->server->secMode &
+                                        ses->server->sec_mode &
                                            SECMODE_PW_ENCRYPT ? true : false,
                                         bcc_ptr);
                else
@@ -3159,7 +3260,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                }
        }
 
-       if (ses->server->secMode &
+       if (ses->server->sec_mode &
                        (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
@@ -3249,13 +3350,12 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
        return rc;
 }
 
-int
-cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
+void
+cifs_umount(struct cifs_sb_info *cifs_sb)
 {
        struct rb_root *root = &cifs_sb->tlink_tree;
        struct rb_node *node;
        struct tcon_link *tlink;
-       char *tmp;
 
        cancel_delayed_work_sync(&cifs_sb->prune_tlinks);
 
@@ -3272,15 +3372,13 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
        }
        spin_unlock(&cifs_sb->tlink_tree_lock);
 
-       tmp = cifs_sb->prepath;
-       cifs_sb->prepathlen = 0;
-       cifs_sb->prepath = NULL;
-       kfree(tmp);
-
-       return 0;
+       bdi_destroy(&cifs_sb->bdi);
+       kfree(cifs_sb->mountdata);
+       unload_nls(cifs_sb->local_nls);
+       kfree(cifs_sb);
 }
 
-int cifs_negotiate_protocol(unsigned int xid, struct cifsSesInfo *ses)
+int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses)
 {
        int rc = 0;
        struct TCP_Server_Info *server = ses->server;
@@ -3298,7 +3396,7 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifsSesInfo *ses)
        }
        if (rc == 0) {
                spin_lock(&GlobalMid_Lock);
-               if (server->tcpStatus != CifsExiting)
+               if (server->tcpStatus == CifsNeedNegotiate)
                        server->tcpStatus = CifsGood;
                else
                        rc = -EHOSTDOWN;
@@ -3310,7 +3408,7 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifsSesInfo *ses)
 }
 
 
-int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses,
+int cifs_setup_session(unsigned int xid, struct cifs_ses *ses,
                        struct nls_table *nls_info)
 {
        int rc = 0;
@@ -3322,7 +3420,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses,
                ses->capabilities &= (~CAP_UNIX);
 
        cFYI(1, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
-                server->secMode, server->capabilities, server->timeAdj);
+                server->sec_mode, server->capabilities, server->timeAdj);
 
        rc = CIFS_SessSetup(xid, ses, nls_info);
        if (rc) {
@@ -3354,12 +3452,12 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses,
        return rc;
 }
 
-static struct cifsTconInfo *
+static struct cifs_tcon *
 cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
 {
-       struct cifsTconInfo *master_tcon = cifs_sb_master_tcon(cifs_sb);
-       struct cifsSesInfo *ses;
-       struct cifsTconInfo *tcon = NULL;
+       struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb);
+       struct cifs_ses *ses;
+       struct cifs_tcon *tcon = NULL;
        struct smb_vol *vol_info;
        char username[28]; /* big enough for "krb50x" + hex of ULONG_MAX 6+16 */
                           /* We used to have this as MAX_USERNAME which is   */
@@ -3392,7 +3490,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
 
        ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info);
        if (IS_ERR(ses)) {
-               tcon = (struct cifsTconInfo *)ses;
+               tcon = (struct cifs_tcon *)ses;
                cifs_put_tcp_session(master_tcon->ses->server);
                goto out;
        }
@@ -3411,13 +3509,7 @@ out:
        return tcon;
 }
 
-static inline struct tcon_link *
-cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb)
-{
-       return cifs_sb->master_tlink;
-}
-
-struct cifsTconInfo *
+struct cifs_tcon *
 cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb)
 {
        return tlink_tcon(cifs_sb_master_tlink(cifs_sb));
index 9ea65cf367146905cc0dababe262397752a15894..81914df47ef1612c1ab742d228503bbf5e598046 100644 (file)
@@ -50,12 +50,11 @@ build_path_from_dentry(struct dentry *direntry)
 {
        struct dentry *temp;
        int namelen;
-       int pplen;
        int dfsplen;
        char *full_path;
        char dirsep;
        struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
-       struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
+       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
 
        if (direntry == NULL)
                return NULL;  /* not much we can do if dentry is freed and
@@ -63,13 +62,12 @@ build_path_from_dentry(struct dentry *direntry)
                when the server crashed */
 
        dirsep = CIFS_DIR_SEP(cifs_sb);
-       pplen = cifs_sb->prepathlen;
        if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
                dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
        else
                dfsplen = 0;
 cifs_bp_rename_retry:
-       namelen = pplen + dfsplen;
+       namelen = dfsplen;
        for (temp = direntry; !IS_ROOT(temp);) {
                namelen += (1 + temp->d_name.len);
                temp = temp->d_parent;
@@ -100,7 +98,7 @@ cifs_bp_rename_retry:
                        return NULL;
                }
        }
-       if (namelen != pplen + dfsplen) {
+       if (namelen != dfsplen) {
                cERROR(1, "did not end path lookup where expected namelen is %d",
                        namelen);
                /* presumably this is only possible if racing with a rename
@@ -126,7 +124,6 @@ cifs_bp_rename_retry:
                        }
                }
        }
-       strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen);
        return full_path;
 }
 
@@ -152,7 +149,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
        __u16 fileHandle;
        struct cifs_sb_info *cifs_sb;
        struct tcon_link *tlink;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
        char *full_path = NULL;
        FILE_ALL_INFO *buf = NULL;
        struct inode *newinode = NULL;
@@ -356,7 +353,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
        int xid;
        struct cifs_sb_info *cifs_sb;
        struct tcon_link *tlink;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
+       struct cifs_io_parms io_parms;
        char *full_path = NULL;
        struct inode *newinode = NULL;
        int oplock = 0;
@@ -439,16 +437,19 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
         * timestamps in, but we can reuse it safely */
 
        pdev = (struct win_dev *)buf;
+       io_parms.netfid = fileHandle;
+       io_parms.pid = current->tgid;
+       io_parms.tcon = pTcon;
+       io_parms.offset = 0;
+       io_parms.length = sizeof(struct win_dev);
        if (S_ISCHR(mode)) {
                memcpy(pdev->type, "IntxCHR", 8);
                pdev->major =
                      cpu_to_le64(MAJOR(device_number));
                pdev->minor =
                      cpu_to_le64(MINOR(device_number));
-               rc = CIFSSMBWrite(xid, pTcon,
-                       fileHandle,
-                       sizeof(struct win_dev),
-                       0, &bytes_written, (char *)pdev,
+               rc = CIFSSMBWrite(xid, &io_parms,
+                       &bytes_written, (char *)pdev,
                        NULL, 0);
        } else if (S_ISBLK(mode)) {
                memcpy(pdev->type, "IntxBLK", 8);
@@ -456,10 +457,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
                      cpu_to_le64(MAJOR(device_number));
                pdev->minor =
                      cpu_to_le64(MINOR(device_number));
-               rc = CIFSSMBWrite(xid, pTcon,
-                       fileHandle,
-                       sizeof(struct win_dev),
-                       0, &bytes_written, (char *)pdev,
+               rc = CIFSSMBWrite(xid, &io_parms,
+                       &bytes_written, (char *)pdev,
                        NULL, 0);
        } /* else if (S_ISFIFO) */
        CIFSSMBClose(xid, pTcon, fileHandle);
@@ -486,7 +485,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
        bool posix_open = false;
        struct cifs_sb_info *cifs_sb;
        struct tcon_link *tlink;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        struct cifsFileInfo *cfile;
        struct inode *newInode = NULL;
        char *full_path = NULL;
index c672afef0c096b2361bcfbd777a0f09c23b37d06..bb71471a4d9d68516269550d6b5eeb5603d5a46b 100644 (file)
@@ -114,7 +114,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
        struct cifs_fattr fattr;
        struct tcon_link *tlink;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
 
        cFYI(1, "posix open %s", full_path);
 
@@ -168,7 +168,7 @@ posix_open_ret:
 
 static int
 cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
-            struct cifsTconInfo *tcon, unsigned int f_flags, __u32 *poplock,
+            struct cifs_tcon *tcon, unsigned int f_flags, __u32 *poplock,
             __u16 *pnetfid, int xid)
 {
        int rc;
@@ -285,7 +285,7 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
 void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
 {
        struct inode *inode = cifs_file->dentry->d_inode;
-       struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink);
+       struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink);
        struct cifsInodeInfo *cifsi = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct cifsLockInfo *li, *tmp;
@@ -343,7 +343,7 @@ int cifs_open(struct inode *inode, struct file *file)
        int xid;
        __u32 oplock;
        struct cifs_sb_info *cifs_sb;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
        struct tcon_link *tlink;
        struct cifsFileInfo *pCifsFile = NULL;
        char *full_path = NULL;
@@ -457,7 +457,7 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
        int xid;
        __u32 oplock;
        struct cifs_sb_info *cifs_sb;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
        struct cifsInodeInfo *pCifsInode;
        struct inode *inode;
        char *full_path = NULL;
@@ -596,7 +596,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
        xid = GetXid();
 
        if (pCFileStruct) {
-               struct cifsTconInfo *pTcon = tlink_tcon(pCFileStruct->tlink);
+               struct cifs_tcon *pTcon = tlink_tcon(pCFileStruct->tlink);
 
                cFYI(1, "Freeing private data in close dir");
                spin_lock(&cifs_file_list_lock);
@@ -653,7 +653,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
        __u64 length;
        bool wait_flag = false;
        struct cifs_sb_info *cifs_sb;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
        __u16 netfid;
        __u8 lockType = LOCKING_ANDX_LARGE_FILES;
        bool posix_locking = 0;
@@ -725,8 +725,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
                        else
                                posix_lock_type = CIFS_WRLCK;
                        rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
-                                       length, pfLock,
-                                       posix_lock_type, wait_flag);
+                                       length, pfLock, posix_lock_type,
+                                       wait_flag);
                        FreeXid(xid);
                        return rc;
                }
@@ -797,8 +797,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
                        posix_lock_type = CIFS_UNLCK;
 
                rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
-                                     length, pfLock,
-                                     posix_lock_type, wait_flag);
+                                     length, pfLock, posix_lock_type,
+                                     wait_flag);
        } else {
                struct cifsFileInfo *fid = file->private_data;
 
@@ -857,7 +857,7 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
                cifsi->server_eof = end_of_write;
 }
 
-static ssize_t cifs_write(struct cifsFileInfo *open_file,
+static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
                          const char *write_data, size_t write_size,
                          loff_t *poffset)
 {
@@ -865,10 +865,11 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
        unsigned int bytes_written = 0;
        unsigned int total_written;
        struct cifs_sb_info *cifs_sb;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        int xid;
        struct dentry *dentry = open_file->dentry;
        struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
+       struct cifs_io_parms io_parms;
 
        cifs_sb = CIFS_SB(dentry->d_sb);
 
@@ -901,8 +902,13 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
                        /* iov[0] is reserved for smb header */
                        iov[1].iov_base = (char *)write_data + total_written;
                        iov[1].iov_len = len;
-                       rc = CIFSSMBWrite2(xid, pTcon, open_file->netfid, len,
-                                          *poffset, &bytes_written, iov, 1, 0);
+                       io_parms.netfid = open_file->netfid;
+                       io_parms.pid = pid;
+                       io_parms.tcon = pTcon;
+                       io_parms.offset = *poffset;
+                       io_parms.length = len;
+                       rc = CIFSSMBWrite2(xid, &io_parms, &bytes_written, iov,
+                                          1, 0);
                }
                if (rc || (bytes_written == 0)) {
                        if (total_written)
@@ -1071,8 +1077,8 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 
        open_file = find_writable_file(CIFS_I(mapping->host), false);
        if (open_file) {
-               bytes_written = cifs_write(open_file, write_data,
-                                          to - from, &offset);
+               bytes_written = cifs_write(open_file, open_file->pid,
+                                          write_data, to - from, &offset);
                cifsFileInfo_put(open_file);
                /* Does mm or vfs already set times? */
                inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
@@ -1092,58 +1098,20 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 static int cifs_writepages(struct address_space *mapping,
                           struct writeback_control *wbc)
 {
-       unsigned int bytes_to_write;
-       unsigned int bytes_written;
-       struct cifs_sb_info *cifs_sb;
-       int done = 0;
-       pgoff_t end;
-       pgoff_t index;
-       int range_whole = 0;
-       struct kvec *iov;
-       int len;
-       int n_iov = 0;
-       pgoff_t next;
-       int nr_pages;
-       __u64 offset = 0;
-       struct cifsFileInfo *open_file;
-       struct cifsTconInfo *tcon;
-       struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
+       struct cifs_sb_info *cifs_sb = CIFS_SB(mapping->host->i_sb);
+       bool done = false, scanned = false, range_whole = false;
+       pgoff_t end, index;
+       struct cifs_writedata *wdata;
        struct page *page;
-       struct pagevec pvec;
        int rc = 0;
-       int scanned = 0;
-       int xid;
-
-       cifs_sb = CIFS_SB(mapping->host->i_sb);
 
        /*
-        * If wsize is smaller that the page cache size, default to writing
+        * If wsize is smaller than the page cache size, default to writing
         * one page at a time via cifs_writepage
         */
        if (cifs_sb->wsize < PAGE_CACHE_SIZE)
                return generic_writepages(mapping, wbc);
 
-       iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
-       if (iov == NULL)
-               return generic_writepages(mapping, wbc);
-
-       /*
-        * if there's no open file, then this is likely to fail too,
-        * but it'll at least handle the return. Maybe it should be
-        * a BUG() instead?
-        */
-       open_file = find_writable_file(CIFS_I(mapping->host), false);
-       if (!open_file) {
-               kfree(iov);
-               return generic_writepages(mapping, wbc);
-       }
-
-       tcon = tlink_tcon(open_file->tlink);
-       cifsFileInfo_put(open_file);
-
-       xid = GetXid();
-
-       pagevec_init(&pvec, 0);
        if (wbc->range_cyclic) {
                index = mapping->writeback_index; /* Start from prev offset */
                end = -1;
@@ -1151,24 +1119,49 @@ static int cifs_writepages(struct address_space *mapping,
                index = wbc->range_start >> PAGE_CACHE_SHIFT;
                end = wbc->range_end >> PAGE_CACHE_SHIFT;
                if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
-                       range_whole = 1;
-               scanned = 1;
+                       range_whole = true;
+               scanned = true;
        }
 retry:
-       while (!done && (index <= end) &&
-              (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
-                       PAGECACHE_TAG_DIRTY,
-                       min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
-               int first;
-               unsigned int i;
-
-               first = -1;
-               next = 0;
-               n_iov = 0;
-               bytes_to_write = 0;
-
-               for (i = 0; i < nr_pages; i++) {
-                       page = pvec.pages[i];
+       while (!done && index <= end) {
+               unsigned int i, nr_pages, found_pages;
+               pgoff_t next = 0, tofind;
+               struct page **pages;
+
+               tofind = min((cifs_sb->wsize / PAGE_CACHE_SIZE) - 1,
+                               end - index) + 1;
+
+               wdata = cifs_writedata_alloc((unsigned int)tofind);
+               if (!wdata) {
+                       rc = -ENOMEM;
+                       break;
+               }
+
+               /*
+                * find_get_pages_tag seems to return a max of 256 on each
+                * iteration, so we must call it several times in order to
+                * fill the array or the wsize is effectively limited to
+                * 256 * PAGE_CACHE_SIZE.
+                */
+               found_pages = 0;
+               pages = wdata->pages;
+               do {
+                       nr_pages = find_get_pages_tag(mapping, &index,
+                                                       PAGECACHE_TAG_DIRTY,
+                                                       tofind, pages);
+                       found_pages += nr_pages;
+                       tofind -= nr_pages;
+                       pages += nr_pages;
+               } while (nr_pages && tofind && index <= end);
+
+               if (found_pages == 0) {
+                       kref_put(&wdata->refcount, cifs_writedata_release);
+                       break;
+               }
+
+               nr_pages = 0;
+               for (i = 0; i < found_pages; i++) {
+                       page = wdata->pages[i];
                        /*
                         * At this point we hold neither mapping->tree_lock nor
                         * lock on the page itself: the page may be truncated or
@@ -1177,7 +1170,7 @@ retry:
                         * mapping
                         */
 
-                       if (first < 0)
+                       if (nr_pages == 0)
                                lock_page(page);
                        else if (!trylock_page(page))
                                break;
@@ -1188,7 +1181,7 @@ retry:
                        }
 
                        if (!wbc->range_cyclic && page->index > end) {
-                               done = 1;
+                               done = true;
                                unlock_page(page);
                                break;
                        }
@@ -1215,119 +1208,89 @@ retry:
                        set_page_writeback(page);
 
                        if (page_offset(page) >= mapping->host->i_size) {
-                               done = 1;
+                               done = true;
                                unlock_page(page);
                                end_page_writeback(page);
                                break;
                        }
 
-                       /*
-                        * BB can we get rid of this?  pages are held by pvec
-                        */
-                       page_cache_get(page);
+                       wdata->pages[i] = page;
+                       next = page->index + 1;
+                       ++nr_pages;
+               }
 
-                       len = min(mapping->host->i_size - page_offset(page),
-                                 (loff_t)PAGE_CACHE_SIZE);
+               /* reset index to refind any pages skipped */
+               if (nr_pages == 0)
+                       index = wdata->pages[0]->index + 1;
 
-                       /* reserve iov[0] for the smb header */
-                       n_iov++;
-                       iov[n_iov].iov_base = kmap(page);
-                       iov[n_iov].iov_len = len;
-                       bytes_to_write += len;
+               /* put any pages we aren't going to use */
+               for (i = nr_pages; i < found_pages; i++) {
+                       page_cache_release(wdata->pages[i]);
+                       wdata->pages[i] = NULL;
+               }
 
-                       if (first < 0) {
-                               first = i;
-                               offset = page_offset(page);
-                       }
-                       next = page->index + 1;
-                       if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
-                               break;
+               /* nothing to write? */
+               if (nr_pages == 0) {
+                       kref_put(&wdata->refcount, cifs_writedata_release);
+                       continue;
                }
-               if (n_iov) {
-retry_write:
-                       open_file = find_writable_file(CIFS_I(mapping->host),
-                                                       false);
-                       if (!open_file) {
-                               cERROR(1, "No writable handles for inode");
-                               rc = -EBADF;
-                       } else {
-                               rc = CIFSSMBWrite2(xid, tcon, open_file->netfid,
-                                                  bytes_to_write, offset,
-                                                  &bytes_written, iov, n_iov,
-                                                  0);
-                               cifsFileInfo_put(open_file);
-                       }
 
-                       cFYI(1, "Write2 rc=%d, wrote=%u", rc, bytes_written);
+               wdata->sync_mode = wbc->sync_mode;
+               wdata->nr_pages = nr_pages;
+               wdata->offset = page_offset(wdata->pages[0]);
 
-                       /*
-                        * For now, treat a short write as if nothing got
-                        * written. A zero length write however indicates
-                        * ENOSPC or EFBIG. We have no way to know which
-                        * though, so call it ENOSPC for now. EFBIG would
-                        * get translated to AS_EIO anyway.
-                        *
-                        * FIXME: make it take into account the data that did
-                        *        get written
-                        */
-                       if (rc == 0) {
-                               if (bytes_written == 0)
-                                       rc = -ENOSPC;
-                               else if (bytes_written < bytes_to_write)
-                                       rc = -EAGAIN;
+               do {
+                       if (wdata->cfile != NULL)
+                               cifsFileInfo_put(wdata->cfile);
+                       wdata->cfile = find_writable_file(CIFS_I(mapping->host),
+                                                         false);
+                       if (!wdata->cfile) {
+                               cERROR(1, "No writable handles for inode");
+                               rc = -EBADF;
+                               break;
                        }
+                       rc = cifs_async_writev(wdata);
+               } while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);
 
-                       /* retry on data-integrity flush */
-                       if (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN)
-                               goto retry_write;
-
-                       /* fix the stats and EOF */
-                       if (bytes_written > 0) {
-                               cifs_stats_bytes_written(tcon, bytes_written);
-                               cifs_update_eof(cifsi, offset, bytes_written);
-                       }
+               for (i = 0; i < nr_pages; ++i)
+                       unlock_page(wdata->pages[i]);
 
-                       for (i = 0; i < n_iov; i++) {
-                               page = pvec.pages[first + i];
-                               /* on retryable write error, redirty page */
+               /* send failure -- clean up the mess */
+               if (rc != 0) {
+                       for (i = 0; i < nr_pages; ++i) {
                                if (rc == -EAGAIN)
-                                       redirty_page_for_writepage(wbc, page);
-                               else if (rc != 0)
-                                       SetPageError(page);
-                               kunmap(page);
-                               unlock_page(page);
-                               end_page_writeback(page);
-                               page_cache_release(page);
+                                       redirty_page_for_writepage(wbc,
+                                                          wdata->pages[i]);
+                               else
+                                       SetPageError(wdata->pages[i]);
+                               end_page_writeback(wdata->pages[i]);
+                               page_cache_release(wdata->pages[i]);
                        }
-
                        if (rc != -EAGAIN)
                                mapping_set_error(mapping, rc);
-                       else
-                               rc = 0;
+               }
+               kref_put(&wdata->refcount, cifs_writedata_release);
 
-                       if ((wbc->nr_to_write -= n_iov) <= 0)
-                               done = 1;
-                       index = next;
-               } else
-                       /* Need to re-find the pages we skipped */
-                       index = pvec.pages[0]->index + 1;
+               wbc->nr_to_write -= nr_pages;
+               if (wbc->nr_to_write <= 0)
+                       done = true;
 
-               pagevec_release(&pvec);
+               index = next;
        }
+
        if (!scanned && !done) {
                /*
                 * We hit the last page and there is more work to be done: wrap
                 * back to the start of the file
                 */
-               scanned = 1;
+               scanned = true;
                index = 0;
                goto retry;
        }
+
        if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
                mapping->writeback_index = index;
 
-       FreeXid(xid);
-       kfree(iov);
        return rc;
 }
 
@@ -1383,6 +1346,14 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
 {
        int rc;
        struct inode *inode = mapping->host;
+       struct cifsFileInfo *cfile = file->private_data;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb);
+       __u32 pid;
+
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
+               pid = cfile->pid;
+       else
+               pid = current->tgid;
 
        cFYI(1, "write_end for page %p from pos %lld with %d bytes",
                 page, pos, copied);
@@ -1406,8 +1377,7 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
                /* BB check if anything else missing out of ppw
                   such as updating last write time */
                page_data = kmap(page);
-               rc = cifs_write(file->private_data, page_data + offset,
-                               copied, &pos);
+               rc = cifs_write(cfile, pid, page_data + offset, copied, &pos);
                /* if (rc < 0) should we set writebehind rc? */
                kunmap(page);
 
@@ -1435,7 +1405,7 @@ int cifs_strict_fsync(struct file *file, int datasync)
 {
        int xid;
        int rc = 0;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
        struct cifsFileInfo *smbfile = file->private_data;
        struct inode *inode = file->f_path.dentry->d_inode;
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
@@ -1465,7 +1435,7 @@ int cifs_fsync(struct file *file, int datasync)
 {
        int xid;
        int rc = 0;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
        struct cifsFileInfo *smbfile = file->private_data;
        struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 
@@ -1556,9 +1526,11 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
        struct iov_iter it;
        struct inode *inode;
        struct cifsFileInfo *open_file;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        struct cifs_sb_info *cifs_sb;
+       struct cifs_io_parms io_parms;
        int xid, rc;
+       __u32 pid;
 
        len = iov_length(iov, nr_segs);
        if (!len)
@@ -1590,6 +1562,12 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
 
        xid = GetXid();
        open_file = file->private_data;
+
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
+               pid = open_file->pid;
+       else
+               pid = current->tgid;
+
        pTcon = tlink_tcon(open_file->tlink);
        inode = file->f_path.dentry->d_inode;
 
@@ -1616,9 +1594,13 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
                                if (rc != 0)
                                        break;
                        }
-                       rc = CIFSSMBWrite2(xid, pTcon, open_file->netfid,
-                                          cur_len, *poffset, &written,
-                                          to_send, npages, 0);
+                       io_parms.netfid = open_file->netfid;
+                       io_parms.pid = pid;
+                       io_parms.tcon = pTcon;
+                       io_parms.offset = *poffset;
+                       io_parms.length = cur_len;
+                       rc = CIFSSMBWrite2(xid, &io_parms, &written, to_send,
+                                          npages, 0);
                } while (rc == -EAGAIN);
 
                for (i = 0; i < npages; i++)
@@ -1711,10 +1693,12 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
        size_t len, cur_len;
        int iov_offset = 0;
        struct cifs_sb_info *cifs_sb;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        struct cifsFileInfo *open_file;
        struct smb_com_read_rsp *pSMBr;
+       struct cifs_io_parms io_parms;
        char *read_data;
+       __u32 pid;
 
        if (!nr_segs)
                return 0;
@@ -1729,6 +1713,11 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
        open_file = file->private_data;
        pTcon = tlink_tcon(open_file->tlink);
 
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
+               pid = open_file->pid;
+       else
+               pid = current->tgid;
+
        if ((file->f_flags & O_ACCMODE) == O_WRONLY)
                cFYI(1, "attempting read on write only file instance");
 
@@ -1744,8 +1733,12 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
                                if (rc != 0)
                                        break;
                        }
-                       rc = CIFSSMBRead(xid, pTcon, open_file->netfid,
-                                        cur_len, *poffset, &bytes_read,
+                       io_parms.netfid = open_file->netfid;
+                       io_parms.pid = pid;
+                       io_parms.tcon = pTcon;
+                       io_parms.offset = *poffset;
+                       io_parms.length = len;
+                       rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
                                         &read_data, &buf_type);
                        pSMBr = (struct smb_com_read_rsp *)read_data;
                        if (read_data) {
@@ -1822,11 +1815,13 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
        unsigned int total_read;
        unsigned int current_read_size;
        struct cifs_sb_info *cifs_sb;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        int xid;
        char *current_offset;
        struct cifsFileInfo *open_file;
+       struct cifs_io_parms io_parms;
        int buf_type = CIFS_NO_BUFFER;
+       __u32 pid;
 
        xid = GetXid();
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
@@ -1839,6 +1834,11 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
        open_file = file->private_data;
        pTcon = tlink_tcon(open_file->tlink);
 
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
+               pid = open_file->pid;
+       else
+               pid = current->tgid;
+
        if ((file->f_flags & O_ACCMODE) == O_WRONLY)
                cFYI(1, "attempting read on write only file instance");
 
@@ -1861,11 +1861,13 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
                                if (rc != 0)
                                        break;
                        }
-                       rc = CIFSSMBRead(xid, pTcon,
-                                        open_file->netfid,
-                                        current_read_size, *poffset,
-                                        &bytes_read, &current_offset,
-                                        &buf_type);
+                       io_parms.netfid = open_file->netfid;
+                       io_parms.pid = pid;
+                       io_parms.tcon = pTcon;
+                       io_parms.offset = *poffset;
+                       io_parms.length = current_read_size;
+                       rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
+                                        &current_offset, &buf_type);
                }
                if (rc || (bytes_read == 0)) {
                        if (total_read) {
@@ -1996,13 +1998,15 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
        loff_t offset;
        struct page *page;
        struct cifs_sb_info *cifs_sb;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        unsigned int bytes_read = 0;
        unsigned int read_size, i;
        char *smb_read_data = NULL;
        struct smb_com_read_rsp *pSMBr;
        struct cifsFileInfo *open_file;
+       struct cifs_io_parms io_parms;
        int buf_type = CIFS_NO_BUFFER;
+       __u32 pid;
 
        xid = GetXid();
        if (file->private_data == NULL) {
@@ -2024,6 +2028,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                goto read_complete;
 
        cFYI(DBG2, "rpages: num pages %d", num_pages);
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
+               pid = open_file->pid;
+       else
+               pid = current->tgid;
+
        for (i = 0; i < num_pages; ) {
                unsigned contig_pages;
                struct page *tmp_page;
@@ -2065,12 +2074,13 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                                if (rc != 0)
                                        break;
                        }
-
-                       rc = CIFSSMBRead(xid, pTcon,
-                                        open_file->netfid,
-                                        read_size, offset,
-                                        &bytes_read, &smb_read_data,
-                                        &buf_type);
+                       io_parms.netfid = open_file->netfid;
+                       io_parms.pid = pid;
+                       io_parms.tcon = pTcon;
+                       io_parms.offset = offset;
+                       io_parms.length = read_size;
+                       rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
+                                        &smb_read_data, &buf_type);
                        /* BB more RC checks ? */
                        if (rc == -EAGAIN) {
                                if (smb_read_data) {
index 297a43d0ff7f5a4716d13eccd595286b44b3af65..816696621ec9ea1be2d5b351ac4fc17d0e8f41aa 100644 (file)
@@ -28,32 +28,32 @@ void cifs_fscache_get_client_cookie(struct TCP_Server_Info *server)
        server->fscache =
                fscache_acquire_cookie(cifs_fscache_netfs.primary_index,
                                &cifs_fscache_server_index_def, server);
-       cFYI(1, "CIFS: get client cookie (0x%p/0x%p)", server,
-                               server->fscache);
+       cFYI(1, "%s: (0x%p/0x%p)", __func__, server,
+                       server->fscache);
 }
 
 void cifs_fscache_release_client_cookie(struct TCP_Server_Info *server)
 {
-       cFYI(1, "CIFS: release client cookie (0x%p/0x%p)", server,
-                               server->fscache);
+       cFYI(1, "%s: (0x%p/0x%p)", __func__, server,
+                       server->fscache);
        fscache_relinquish_cookie(server->fscache, 0);
        server->fscache = NULL;
 }
 
-void cifs_fscache_get_super_cookie(struct cifsTconInfo *tcon)
+void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon)
 {
        struct TCP_Server_Info *server = tcon->ses->server;
 
        tcon->fscache =
                fscache_acquire_cookie(server->fscache,
                                &cifs_fscache_super_index_def, tcon);
-       cFYI(1, "CIFS: get superblock cookie (0x%p/0x%p)",
-                               server->fscache, tcon->fscache);
+       cFYI(1, "%s: (0x%p/0x%p)", __func__, server->fscache,
+                       tcon->fscache);
 }
 
-void cifs_fscache_release_super_cookie(struct cifsTconInfo *tcon)
+void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon)
 {
-       cFYI(1, "CIFS: releasing superblock cookie (0x%p)", tcon->fscache);
+       cFYI(1, "%s: (0x%p)", __func__, tcon->fscache);
        fscache_relinquish_cookie(tcon->fscache, 0);
        tcon->fscache = NULL;
 }
@@ -62,7 +62,7 @@ static void cifs_fscache_enable_inode_cookie(struct inode *inode)
 {
        struct cifsInodeInfo *cifsi = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-       struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
+       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
 
        if (cifsi->fscache)
                return;
@@ -70,8 +70,8 @@ static void cifs_fscache_enable_inode_cookie(struct inode *inode)
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) {
                cifsi->fscache = fscache_acquire_cookie(tcon->fscache,
                                &cifs_fscache_inode_object_def, cifsi);
-               cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)", tcon->fscache,
-                               cifsi->fscache);
+               cFYI(1, "%s: got FH cookie (0x%p/0x%p)", __func__,
+                               tcon->fscache, cifsi->fscache);
        }
 }
 
@@ -80,8 +80,7 @@ void cifs_fscache_release_inode_cookie(struct inode *inode)
        struct cifsInodeInfo *cifsi = CIFS_I(inode);
 
        if (cifsi->fscache) {
-               cFYI(1, "CIFS releasing inode cookie (0x%p)",
-                               cifsi->fscache);
+               cFYI(1, "%s: (0x%p)", __func__, cifsi->fscache);
                fscache_relinquish_cookie(cifsi->fscache, 0);
                cifsi->fscache = NULL;
        }
@@ -92,8 +91,7 @@ static void cifs_fscache_disable_inode_cookie(struct inode *inode)
        struct cifsInodeInfo *cifsi = CIFS_I(inode);
 
        if (cifsi->fscache) {
-               cFYI(1, "CIFS disabling inode cookie (0x%p)",
-                               cifsi->fscache);
+               cFYI(1, "%s: (0x%p)", __func__, cifsi->fscache);
                fscache_relinquish_cookie(cifsi->fscache, 1);
                cifsi->fscache = NULL;
        }
@@ -121,8 +119,8 @@ void cifs_fscache_reset_inode_cookie(struct inode *inode)
                                        cifs_sb_master_tcon(cifs_sb)->fscache,
                                        &cifs_fscache_inode_object_def,
                                        cifsi);
-               cFYI(1, "CIFS: new cookie 0x%p oldcookie 0x%p",
-                               cifsi->fscache, old);
+               cFYI(1, "%s: new cookie 0x%p oldcookie 0x%p",
+                               __func__, cifsi->fscache, old);
        }
 }
 
@@ -132,8 +130,8 @@ int cifs_fscache_release_page(struct page *page, gfp_t gfp)
                struct inode *inode = page->mapping->host;
                struct cifsInodeInfo *cifsi = CIFS_I(inode);
 
-               cFYI(1, "CIFS: fscache release page (0x%p/0x%p)",
-                               page, cifsi->fscache);
+               cFYI(1, "%s: (0x%p/0x%p)", __func__, page,
+                               cifsi->fscache);
                if (!fscache_maybe_release_page(cifsi->fscache, page, gfp))
                        return 0;
        }
@@ -144,8 +142,7 @@ int cifs_fscache_release_page(struct page *page, gfp_t gfp)
 static void cifs_readpage_from_fscache_complete(struct page *page, void *ctx,
                                                int error)
 {
-       cFYI(1, "CFS: readpage_from_fscache_complete (0x%p/%d)",
-                       page, error);
+       cFYI(1, "%s: (0x%p/%d)", __func__, page, error);
        if (!error)
                SetPageUptodate(page);
        unlock_page(page);
@@ -158,7 +155,7 @@ int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
 {
        int ret;
 
-       cFYI(1, "CIFS: readpage_from_fscache(fsc:%p, p:%p, i:0x%p",
+       cFYI(1, "%s: (fsc:%p, p:%p, i:0x%p", __func__,
                        CIFS_I(inode)->fscache, page, inode);
        ret = fscache_read_or_alloc_page(CIFS_I(inode)->fscache, page,
                                         cifs_readpage_from_fscache_complete,
@@ -167,11 +164,11 @@ int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
        switch (ret) {
 
        case 0: /* page found in fscache, read submitted */
-               cFYI(1, "CIFS: readpage_from_fscache: submitted");
+               cFYI(1, "%s: submitted", __func__);
                return ret;
        case -ENOBUFS:  /* page won't be cached */
        case -ENODATA:  /* page not in cache */
-               cFYI(1, "CIFS: readpage_from_fscache %d", ret);
+               cFYI(1, "%s: %d", __func__, ret);
                return 1;
 
        default:
@@ -190,7 +187,7 @@ int __cifs_readpages_from_fscache(struct inode *inode,
 {
        int ret;
 
-       cFYI(1, "CIFS: __cifs_readpages_from_fscache (0x%p/%u/0x%p)",
+       cFYI(1, "%s: (0x%p/%u/0x%p)", __func__,
                        CIFS_I(inode)->fscache, *nr_pages, inode);
        ret = fscache_read_or_alloc_pages(CIFS_I(inode)->fscache, mapping,
                                          pages, nr_pages,
@@ -199,12 +196,12 @@ int __cifs_readpages_from_fscache(struct inode *inode,
                                          mapping_gfp_mask(mapping));
        switch (ret) {
        case 0: /* read submitted to the cache for all pages */
-               cFYI(1, "CIFS: readpages_from_fscache: submitted");
+               cFYI(1, "%s: submitted", __func__);
                return ret;
 
        case -ENOBUFS:  /* some pages are not cached and can't be */
        case -ENODATA:  /* some pages are not cached */
-               cFYI(1, "CIFS: readpages_from_fscache: no page");
+               cFYI(1, "%s: no page", __func__);
                return 1;
 
        default:
@@ -218,7 +215,7 @@ void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
 {
        int ret;
 
-       cFYI(1, "CIFS: readpage_to_fscache(fsc: %p, p: %p, i: %p",
+       cFYI(1, "%s: (fsc: %p, p: %p, i: %p)", __func__,
                        CIFS_I(inode)->fscache, page, inode);
        ret = fscache_write_page(CIFS_I(inode)->fscache, page, GFP_KERNEL);
        if (ret != 0)
@@ -230,7 +227,7 @@ void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
        struct cifsInodeInfo *cifsi = CIFS_I(inode);
        struct fscache_cookie *cookie = cifsi->fscache;
 
-       cFYI(1, "CIFS: fscache invalidatepage (0x%p/0x%p)", page, cookie);
+       cFYI(1, "%s: (0x%p/0x%p)", __func__, page, cookie);
        fscache_wait_on_page_write(cookie, page);
        fscache_uncache_page(cookie, page);
 }
index 31b88ec2341e2b36fcf10ffdfc9effb02c5b4e36..63539323e0b960f3ecf9788eca6e67ba0ec8ce67 100644 (file)
@@ -40,8 +40,8 @@ extern void cifs_fscache_unregister(void);
  */
 extern void cifs_fscache_get_client_cookie(struct TCP_Server_Info *);
 extern void cifs_fscache_release_client_cookie(struct TCP_Server_Info *);
-extern void cifs_fscache_get_super_cookie(struct cifsTconInfo *);
-extern void cifs_fscache_release_super_cookie(struct cifsTconInfo *);
+extern void cifs_fscache_get_super_cookie(struct cifs_tcon *);
+extern void cifs_fscache_release_super_cookie(struct cifs_tcon *);
 
 extern void cifs_fscache_release_inode_cookie(struct inode *);
 extern void cifs_fscache_set_inode_cookie(struct inode *, struct file *);
@@ -99,9 +99,9 @@ static inline void
 cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) {}
 static inline void
 cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) {}
-static inline void cifs_fscache_get_super_cookie(struct cifsTconInfo *tcon) {}
+static inline void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) {}
 static inline void
-cifs_fscache_release_super_cookie(struct cifsTconInfo *tcon) {}
+cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) {}
 
 static inline void cifs_fscache_release_inode_cookie(struct inode *inode) {}
 static inline void cifs_fscache_set_inode_cookie(struct inode *inode,
index de02ed5e25c2ad09919cf84c23c69b2383e55360..9b018c8334fa1d67bf090db12f8821700341c1df 100644 (file)
@@ -295,7 +295,7 @@ int cifs_get_file_info_unix(struct file *filp)
        struct inode *inode = filp->f_path.dentry->d_inode;
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct cifsFileInfo *cfile = filp->private_data;
-       struct cifsTconInfo *tcon = tlink_tcon(cfile->tlink);
+       struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 
        xid = GetXid();
        rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
@@ -318,7 +318,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
        int rc;
        FILE_UNIX_BASIC_INFO find_data;
        struct cifs_fattr fattr;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
        struct tcon_link *tlink;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 
@@ -373,7 +373,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
        int oplock = 0;
        __u16 netfid;
        struct tcon_link *tlink;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
+       struct cifs_io_parms io_parms;
        char buf[24];
        unsigned int bytes_read;
        char *pbuf;
@@ -405,9 +406,13 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
        if (rc == 0) {
                int buf_type = CIFS_NO_BUFFER;
                        /* Read header */
-               rc = CIFSSMBRead(xid, tcon, netfid,
-                                24 /* length */, 0 /* offset */,
-                                &bytes_read, &pbuf, &buf_type);
+               io_parms.netfid = netfid;
+               io_parms.pid = current->tgid;
+               io_parms.tcon = tcon;
+               io_parms.offset = 0;
+               io_parms.length = 24;
+               rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf,
+                                &buf_type);
                if ((rc == 0) && (bytes_read >= 8)) {
                        if (memcmp("IntxBLK", pbuf, 8) == 0) {
                                cFYI(1, "Block device");
@@ -468,7 +473,7 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
        char ea_value[4];
        __u32 mode;
        struct tcon_link *tlink;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
 
        tlink = cifs_sb_tlink(cifs_sb);
        if (IS_ERR(tlink))
@@ -502,7 +507,7 @@ static void
 cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
                       struct cifs_sb_info *cifs_sb, bool adjust_tz)
 {
-       struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
+       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
 
        memset(fattr, 0, sizeof(*fattr));
        fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
@@ -553,7 +558,7 @@ int cifs_get_file_info(struct file *filp)
        struct inode *inode = filp->f_path.dentry->d_inode;
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct cifsFileInfo *cfile = filp->private_data;
-       struct cifsTconInfo *tcon = tlink_tcon(cfile->tlink);
+       struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 
        xid = GetXid();
        rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
@@ -590,7 +595,7 @@ int cifs_get_inode_info(struct inode **pinode,
        struct super_block *sb, int xid, const __u16 *pfid)
 {
        int rc = 0, tmprc;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        struct tcon_link *tlink;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
        char *buf = NULL;
@@ -735,10 +740,10 @@ static const struct inode_operations cifs_ipc_inode_ops = {
        .lookup = cifs_lookup,
 };
 
-char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
-                               struct cifsTconInfo *tcon)
+char *cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
+                             struct cifs_tcon *tcon)
 {
-       int pplen = cifs_sb->prepathlen;
+       int pplen = vol->prepath ? strlen(vol->prepath) : 0;
        int dfsplen;
        char *full_path = NULL;
 
@@ -772,7 +777,7 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
                        }
                }
        }
-       strncpy(full_path + dfsplen, cifs_sb->prepath, pplen);
+       strncpy(full_path + dfsplen, vol->prepath, pplen);
        full_path[dfsplen + pplen] = 0; /* add trailing null */
        return full_path;
 }
@@ -884,19 +889,13 @@ struct inode *cifs_root_iget(struct super_block *sb)
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
        struct inode *inode = NULL;
        long rc;
-       char *full_path;
-       struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
-
-       full_path = cifs_build_path_to_root(cifs_sb, tcon);
-       if (full_path == NULL)
-               return ERR_PTR(-ENOMEM);
+       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
 
        xid = GetXid();
        if (tcon->unix_ext)
-               rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
+               rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
        else
-               rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
-                                               xid, NULL);
+               rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL);
 
        if (!inode) {
                inode = ERR_PTR(rc);
@@ -922,7 +921,6 @@ struct inode *cifs_root_iget(struct super_block *sb)
        }
 
 out:
-       kfree(full_path);
        /* can not call macro FreeXid here since in a void func
         * TODO: This is no longer true
         */
@@ -943,7 +941,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
        struct cifsInodeInfo *cifsInode = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct tcon_link *tlink = NULL;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        FILE_BASIC_INFO info_buf;
 
        if (attrs == NULL)
@@ -1061,7 +1059,7 @@ cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid)
        struct cifsInodeInfo *cifsInode = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct tcon_link *tlink;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
        __u32 dosattr, origattr;
        FILE_BASIC_INFO *info_buf = NULL;
 
@@ -1179,7 +1177,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
        struct super_block *sb = dir->i_sb;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
        struct tcon_link *tlink;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
        struct iattr *attrs = NULL;
        __u32 dosattr = 0, origattr = 0;
 
@@ -1277,7 +1275,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
        int xid;
        struct cifs_sb_info *cifs_sb;
        struct tcon_link *tlink;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        char *full_path = NULL;
        struct inode *newinode = NULL;
        struct cifs_fattr fattr;
@@ -1455,7 +1453,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
        int xid;
        struct cifs_sb_info *cifs_sb;
        struct tcon_link *tlink;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        char *full_path = NULL;
        struct cifsInodeInfo *cifsInode;
 
@@ -1512,7 +1510,7 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
 {
        struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
        struct tcon_link *tlink;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        __u16 srcfid;
        int oplock, rc;
 
@@ -1564,7 +1562,7 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
        char *toName = NULL;
        struct cifs_sb_info *cifs_sb;
        struct tcon_link *tlink;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
        FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
        FILE_UNIX_BASIC_INFO *info_buf_target;
        int xid, rc, tmprc;
@@ -1794,7 +1792,7 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
                 struct kstat *stat)
 {
        struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
-       struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
+       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
        struct inode *inode = dentry->d_inode;
        int rc;
 
@@ -1872,7 +1870,8 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
        struct cifsInodeInfo *cifsInode = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct tcon_link *tlink = NULL;
-       struct cifsTconInfo *pTcon = NULL;
+       struct cifs_tcon *pTcon = NULL;
+       struct cifs_io_parms io_parms;
 
        /*
         * To avoid spurious oplock breaks from server, in the case of
@@ -1894,8 +1893,14 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
                cFYI(1, "SetFSize for attrs rc = %d", rc);
                if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
                        unsigned int bytes_written;
-                       rc = CIFSSMBWrite(xid, pTcon, nfid, 0, attrs->ia_size,
-                                         &bytes_written, NULL, NULL, 1);
+
+                       io_parms.netfid = nfid;
+                       io_parms.pid = npid;
+                       io_parms.tcon = pTcon;
+                       io_parms.offset = 0;
+                       io_parms.length = attrs->ia_size;
+                       rc = CIFSSMBWrite(xid, &io_parms, &bytes_written,
+                                         NULL, NULL, 1);
                        cFYI(1, "Wrt seteof rc %d", rc);
                }
        } else
@@ -1930,10 +1935,15 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
                        if (rc == 0) {
                                unsigned int bytes_written;
-                               rc = CIFSSMBWrite(xid, pTcon, netfid, 0,
-                                                 attrs->ia_size,
-                                                 &bytes_written, NULL,
-                                                 NULL, 1);
+
+                               io_parms.netfid = netfid;
+                               io_parms.pid = current->tgid;
+                               io_parms.tcon = pTcon;
+                               io_parms.offset = 0;
+                               io_parms.length = attrs->ia_size;
+                               rc = CIFSSMBWrite(xid, &io_parms,
+                                                 &bytes_written,
+                                                 NULL, NULL,  1);
                                cFYI(1, "wrt seteof rc %d", rc);
                                CIFSSMBClose(xid, pTcon, netfid);
                        }
@@ -1961,7 +1971,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
        struct cifsInodeInfo *cifsInode = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct tcon_link *tlink;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        struct cifs_unix_set_info_args *args = NULL;
        struct cifsFileInfo *open_file;
 
@@ -2247,7 +2257,7 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 {
        struct inode *inode = direntry->d_inode;
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-       struct cifsTconInfo *pTcon = cifs_sb_master_tcon(cifs_sb);
+       struct cifs_tcon *pTcon = cifs_sb_master_tcon(cifs_sb);
 
        if (pTcon->unix_ext)
                return cifs_setattr_unix(direntry, attrs);
index 0c98672d01225ccadb67bb09705e7c21922332c7..4221b5e48a426af74b540105ec255026291e8c05 100644 (file)
@@ -38,7 +38,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
        struct cifs_sb_info *cifs_sb;
 #ifdef CONFIG_CIFS_POSIX
        struct cifsFileInfo *pSMBFile = filep->private_data;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
        __u64   ExtAttrBits = 0;
        __u64   ExtAttrMask = 0;
        __u64   caps;
index ce417a9764a3fe5c3963e1e93fe5e5b17bf7390c..556b1a0b54de95159aede9e710d47d66a6bc97d6 100644 (file)
@@ -175,7 +175,7 @@ CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str)
 }
 
 static int
-CIFSCreateMFSymLink(const int xid, struct cifsTconInfo *tcon,
+CIFSCreateMFSymLink(const int xid, struct cifs_tcon *tcon,
                    const char *fromName, const char *toName,
                    const struct nls_table *nls_codepage, int remap)
 {
@@ -184,6 +184,7 @@ CIFSCreateMFSymLink(const int xid, struct cifsTconInfo *tcon,
        __u16 netfid = 0;
        u8 *buf;
        unsigned int bytes_written = 0;
+       struct cifs_io_parms io_parms;
 
        buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
        if (!buf)
@@ -203,10 +204,13 @@ CIFSCreateMFSymLink(const int xid, struct cifsTconInfo *tcon,
                return rc;
        }
 
-       rc = CIFSSMBWrite(xid, tcon, netfid,
-                         CIFS_MF_SYMLINK_FILE_SIZE /* length */,
-                         0 /* offset */,
-                         &bytes_written, buf, NULL, 0);
+       io_parms.netfid = netfid;
+       io_parms.pid = current->tgid;
+       io_parms.tcon = tcon;
+       io_parms.offset = 0;
+       io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
+
+       rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, buf, NULL, 0);
        CIFSSMBClose(xid, tcon, netfid);
        kfree(buf);
        if (rc != 0)
@@ -219,7 +223,7 @@ CIFSCreateMFSymLink(const int xid, struct cifsTconInfo *tcon,
 }
 
 static int
-CIFSQueryMFSymLink(const int xid, struct cifsTconInfo *tcon,
+CIFSQueryMFSymLink(const int xid, struct cifs_tcon *tcon,
                   const unsigned char *searchName, char **symlinkinfo,
                   const struct nls_table *nls_codepage, int remap)
 {
@@ -231,6 +235,7 @@ CIFSQueryMFSymLink(const int xid, struct cifsTconInfo *tcon,
        unsigned int bytes_read = 0;
        int buf_type = CIFS_NO_BUFFER;
        unsigned int link_len = 0;
+       struct cifs_io_parms io_parms;
        FILE_ALL_INFO file_info;
 
        rc = CIFSSMBOpen(xid, tcon, searchName, FILE_OPEN, GENERIC_READ,
@@ -249,11 +254,13 @@ CIFSQueryMFSymLink(const int xid, struct cifsTconInfo *tcon,
        if (!buf)
                return -ENOMEM;
        pbuf = buf;
+       io_parms.netfid = netfid;
+       io_parms.pid = current->tgid;
+       io_parms.tcon = tcon;
+       io_parms.offset = 0;
+       io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
 
-       rc = CIFSSMBRead(xid, tcon, netfid,
-                        CIFS_MF_SYMLINK_FILE_SIZE /* length */,
-                        0 /* offset */,
-                        &bytes_read, &pbuf, &buf_type);
+       rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type);
        CIFSSMBClose(xid, tcon, netfid);
        if (rc != 0) {
                kfree(buf);
@@ -291,7 +298,8 @@ CIFSCheckMFSymlink(struct cifs_fattr *fattr,
        int oplock = 0;
        __u16 netfid = 0;
        struct tcon_link *tlink;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
+       struct cifs_io_parms io_parms;
        u8 *buf;
        char *pbuf;
        unsigned int bytes_read = 0;
@@ -328,11 +336,13 @@ CIFSCheckMFSymlink(struct cifs_fattr *fattr,
                goto out;
        }
        pbuf = buf;
+       io_parms.netfid = netfid;
+       io_parms.pid = current->tgid;
+       io_parms.tcon = pTcon;
+       io_parms.offset = 0;
+       io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
 
-       rc = CIFSSMBRead(xid, pTcon, netfid,
-                        CIFS_MF_SYMLINK_FILE_SIZE /* length */,
-                        0 /* offset */,
-                        &bytes_read, &pbuf, &buf_type);
+       rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type);
        CIFSSMBClose(xid, pTcon, netfid);
        if (rc != 0) {
                kfree(buf);
@@ -370,7 +380,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
        char *toName = NULL;
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct tcon_link *tlink;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        struct cifsInodeInfo *cifsInode;
 
        tlink = cifs_sb_tlink(cifs_sb);
@@ -445,7 +455,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
        char *target_path = NULL;
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct tcon_link *tlink = NULL;
-       struct cifsTconInfo *tcon;
+       struct cifs_tcon *tcon;
 
        xid = GetXid();
 
@@ -518,7 +528,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
        int xid;
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct tcon_link *tlink;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        char *full_path = NULL;
        struct inode *newinode = NULL;
 
index 907531ac58886dda635f9f9a739c4c223ec4835d..03a1f491d39b494632ecf09845c84ac839f6a6eb 100644 (file)
@@ -67,12 +67,12 @@ _FreeXid(unsigned int xid)
        spin_unlock(&GlobalMid_Lock);
 }
 
-struct cifsSesInfo *
+struct cifs_ses *
 sesInfoAlloc(void)
 {
-       struct cifsSesInfo *ret_buf;
+       struct cifs_ses *ret_buf;
 
-       ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL);
+       ret_buf = kzalloc(sizeof(struct cifs_ses), GFP_KERNEL);
        if (ret_buf) {
                atomic_inc(&sesInfoAllocCount);
                ret_buf->status = CifsNew;
@@ -85,7 +85,7 @@ sesInfoAlloc(void)
 }
 
 void
-sesInfoFree(struct cifsSesInfo *buf_to_free)
+sesInfoFree(struct cifs_ses *buf_to_free)
 {
        if (buf_to_free == NULL) {
                cFYI(1, "Null buffer passed to sesInfoFree");
@@ -105,11 +105,11 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
        kfree(buf_to_free);
 }
 
-struct cifsTconInfo *
+struct cifs_tcon *
 tconInfoAlloc(void)
 {
-       struct cifsTconInfo *ret_buf;
-       ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL);
+       struct cifs_tcon *ret_buf;
+       ret_buf = kzalloc(sizeof(struct cifs_tcon), GFP_KERNEL);
        if (ret_buf) {
                atomic_inc(&tconInfoAllocCount);
                ret_buf->tidStatus = CifsNew;
@@ -124,7 +124,7 @@ tconInfoAlloc(void)
 }
 
 void
-tconInfoFree(struct cifsTconInfo *buf_to_free)
+tconInfoFree(struct cifs_tcon *buf_to_free)
 {
        if (buf_to_free == NULL) {
                cFYI(1, "Null buffer passed to tconInfoFree");
@@ -295,11 +295,11 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
    case it is responsbility of caller to set the mid */
 void
 header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
-               const struct cifsTconInfo *treeCon, int word_count
+               const struct cifs_tcon *treeCon, int word_count
                /* length of fixed section (word count) in two byte units  */)
 {
        struct list_head *temp_item;
-       struct cifsSesInfo *ses;
+       struct cifs_ses *ses;
        char *temp = (char *) buffer;
 
        memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */
@@ -359,7 +359,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
                                                 "did not match tcon uid");
                                        spin_lock(&cifs_tcp_ses_lock);
                                        list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) {
-                                               ses = list_entry(temp_item, struct cifsSesInfo, smb_ses_list);
+                                               ses = list_entry(temp_item, struct cifs_ses, smb_ses_list);
                                                if (ses->linux_uid == current_fsuid()) {
                                                        if (ses->server == treeCon->ses->server) {
                                                                cFYI(1, "found matching uid substitute right smb_uid");
@@ -380,7 +380,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
                if (treeCon->nocase)
                        buffer->Flags  |= SMBFLG_CASELESS;
                if ((treeCon->ses) && (treeCon->ses->server))
-                       if (treeCon->ses->server->secMode &
+                       if (treeCon->ses->server->sec_mode &
                          (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                                buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
        }
@@ -507,8 +507,8 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
 {
        struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
        struct list_head *tmp, *tmp1, *tmp2;
-       struct cifsSesInfo *ses;
-       struct cifsTconInfo *tcon;
+       struct cifs_ses *ses;
+       struct cifs_tcon *tcon;
        struct cifsInodeInfo *pCifsInode;
        struct cifsFileInfo *netfile;
 
@@ -566,9 +566,9 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
        /* look up tcon based on tid & uid */
        spin_lock(&cifs_tcp_ses_lock);
        list_for_each(tmp, &srv->smb_ses_list) {
-               ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
+               ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
                list_for_each(tmp1, &ses->tcon_list) {
-                       tcon = list_entry(tmp1, struct cifsTconInfo, tcon_list);
+                       tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
                        if (tcon->tid != buf->Tid)
                                continue;
 
index 79b71c2c7c9dd2f4b5f9857e8cf32de73c02fd7b..73e47e84b61a4827fa13ed69a41e205be510234e 100644 (file)
@@ -836,7 +836,7 @@ ntstatus_to_dos(__u32 ntstatus, __u8 *eclass, __u16 *ecode)
 }
 
 int
-map_smb_to_linux_error(struct smb_hdr *smb, int logErr)
+map_smb_to_linux_error(struct smb_hdr *smb, bool logErr)
 {
        unsigned int i;
        int rc = -EIO;  /* if transport error smb error may not be set */
index f8e4cd2a79127a855b8c319b4d6c2d9fbfa5f2c1..6751e745bbc6a5611081a462c36c5159cbf9ee05 100644 (file)
@@ -195,7 +195,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
        int len;
        int oplock = 0;
        int rc;
-       struct cifsTconInfo *ptcon = cifs_sb_tcon(cifs_sb);
+       struct cifs_tcon *ptcon = cifs_sb_tcon(cifs_sb);
        char *tmpbuffer;
 
        rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ,
@@ -223,7 +223,7 @@ static int initiate_cifs_search(const int xid, struct file *file)
        struct cifsFileInfo *cifsFile;
        struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
        struct tcon_link *tlink = NULL;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
 
        if (file->private_data == NULL) {
                tlink = cifs_sb_tlink(cifs_sb);
@@ -496,7 +496,7 @@ static int cifs_save_resume_key(const char *current_entry,
    assume that they are located in the findfirst return buffer.*/
 /* We start counting in the buffer with entry 2 and increment for every
    entry (do not increment for . or .. entry) */
-static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
+static int find_cifs_entry(const int xid, struct cifs_tcon *pTcon,
        struct file *file, char **ppCurrentEntry, int *num_to_ret)
 {
        int rc = 0;
@@ -764,7 +764,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 {
        int rc = 0;
        int xid, i;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        struct cifsFileInfo *cifsFile = NULL;
        char *current_entry;
        int num_to_fill = 0;
index 7dd46210037807aa17f65bb3d2076dbae03bfe4c..3892ab817a36407975d6738a1b20d7c90c846574 100644 (file)
  * the socket has been reestablished (so we know whether to use vc 0).
  * Called while holding the cifs_tcp_ses_lock, so do not block
  */
-static bool is_first_ses_reconnect(struct cifsSesInfo *ses)
+static bool is_first_ses_reconnect(struct cifs_ses *ses)
 {
        struct list_head *tmp;
-       struct cifsSesInfo *tmp_ses;
+       struct cifs_ses *tmp_ses;
 
        list_for_each(tmp, &ses->server->smb_ses_list) {
-               tmp_ses = list_entry(tmp, struct cifsSesInfo,
+               tmp_ses = list_entry(tmp, struct cifs_ses,
                                     smb_ses_list);
                if (tmp_ses->need_reconnect == false)
                        return false;
@@ -61,11 +61,11 @@ static bool is_first_ses_reconnect(struct cifsSesInfo *ses)
  *     any vc but zero (some servers reset the connection on vcnum zero)
  *
  */
-static __le16 get_next_vcnum(struct cifsSesInfo *ses)
+static __le16 get_next_vcnum(struct cifs_ses *ses)
 {
        __u16 vcnum = 0;
        struct list_head *tmp;
-       struct cifsSesInfo *tmp_ses;
+       struct cifs_ses *tmp_ses;
        __u16 max_vcs = ses->server->max_vcs;
        __u16 i;
        int free_vc_found = 0;
@@ -87,7 +87,7 @@ static __le16 get_next_vcnum(struct cifsSesInfo *ses)
                free_vc_found = 1;
 
                list_for_each(tmp, &ses->server->smb_ses_list) {
-                       tmp_ses = list_entry(tmp, struct cifsSesInfo,
+                       tmp_ses = list_entry(tmp, struct cifs_ses,
                                             smb_ses_list);
                        if (tmp_ses->vcnum == i) {
                                free_vc_found = 0;
@@ -114,7 +114,7 @@ get_vc_num_exit:
        return cpu_to_le16(vcnum);
 }
 
-static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
+static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
 {
        __u32 capabilities = 0;
 
@@ -136,7 +136,7 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
        capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
                        CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
 
-       if (ses->server->secMode &
+       if (ses->server->sec_mode &
            (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
@@ -181,7 +181,7 @@ unicode_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp)
        *pbcc_area = bcc_ptr;
 }
 
-static void unicode_domain_string(char **pbcc_area, struct cifsSesInfo *ses,
+static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses,
                                   const struct nls_table *nls_cp)
 {
        char *bcc_ptr = *pbcc_area;
@@ -204,7 +204,7 @@ static void unicode_domain_string(char **pbcc_area, struct cifsSesInfo *ses,
 }
 
 
-static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
+static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses,
                                   const struct nls_table *nls_cp)
 {
        char *bcc_ptr = *pbcc_area;
@@ -236,7 +236,7 @@ static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
        *pbcc_area = bcc_ptr;
 }
 
-static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
+static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses,
                                 const struct nls_table *nls_cp)
 {
        char *bcc_ptr = *pbcc_area;
@@ -276,7 +276,7 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
 }
 
 static void
-decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses,
+decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses,
                      const struct nls_table *nls_cp)
 {
        int len;
@@ -310,7 +310,7 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses,
 }
 
 static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
-                              struct cifsSesInfo *ses,
+                              struct cifs_ses *ses,
                               const struct nls_table *nls_cp)
 {
        int rc = 0;
@@ -364,7 +364,7 @@ static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
 }
 
 static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
-                                   struct cifsSesInfo *ses)
+                                   struct cifs_ses *ses)
 {
        unsigned int tioffset; /* challenge message target info area */
        unsigned int tilen; /* challenge message target info area length  */
@@ -411,7 +411,7 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
 /* We do not malloc the blob, it is passed in pbuffer, because
    it is fixed size, and small, making this approach cleaner */
 static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
-                                        struct cifsSesInfo *ses)
+                                        struct cifs_ses *ses)
 {
        NEGOTIATE_MESSAGE *sec_blob = (NEGOTIATE_MESSAGE *)pbuffer;
        __u32 flags;
@@ -424,7 +424,7 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
        flags = NTLMSSP_NEGOTIATE_56 |  NTLMSSP_REQUEST_TARGET |
                NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
                NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
-       if (ses->server->secMode &
+       if (ses->server->sec_mode &
                        (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
                flags |= NTLMSSP_NEGOTIATE_SIGN;
                if (!ses->server->session_estab)
@@ -449,7 +449,7 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
    This function returns the length of the data in the blob */
 static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
                                        u16 *buflen,
-                                  struct cifsSesInfo *ses,
+                                  struct cifs_ses *ses,
                                   const struct nls_table *nls_cp)
 {
        int rc;
@@ -464,10 +464,10 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
                NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO |
                NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
                NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
-       if (ses->server->secMode &
+       if (ses->server->sec_mode &
           (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                flags |= NTLMSSP_NEGOTIATE_SIGN;
-       if (ses->server->secMode & SECMODE_SIGN_REQUIRED)
+       if (ses->server->sec_mode & SECMODE_SIGN_REQUIRED)
                flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
 
        tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE);
@@ -551,7 +551,7 @@ setup_ntlmv2_ret:
 }
 
 int
-CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
+CIFS_SessSetup(unsigned int xid, struct cifs_ses *ses,
               const struct nls_table *nls_cp)
 {
        int rc = 0;
@@ -657,7 +657,7 @@ ssetup_ntlmssp_authenticate:
                 */
 
                rc = calc_lanman_hash(ses->password, ses->server->cryptkey,
-                                ses->server->secMode & SECMODE_PW_ENCRYPT ?
+                                ses->server->sec_mode & SECMODE_PW_ENCRYPT ?
                                        true : false, lnm_session_key);
 
                ses->flags |= CIFS_SES_LANMAN;
index 1525d5e662b65cd11649587458013bd47dc7fc2a..1c5b770c314135a3ed932c88260470f13edd6008 100644 (file)
@@ -90,12 +90,10 @@ smbhash(unsigned char *out, const unsigned char *in, unsigned char *key)
        sg_init_one(&sgout, out, 8);
 
        rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, 8);
-       if (rc) {
+       if (rc)
                cERROR(1, "could not encrypt crypt key rc: %d\n", rc);
-               crypto_free_blkcipher(tfm_des);
-               goto smbhash_err;
-       }
 
+       crypto_free_blkcipher(tfm_des);
 smbhash_err:
        return rc;
 }
index f2513fb8c391d5bdd39eaeef08987165e1ac2006..147aa22c3c3a4b0f2b647b6978ec31340ff1a5da 100644 (file)
@@ -295,7 +295,7 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
        return 0;
 }
 
-static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
+static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
                        struct mid_q_entry **ppmidQ)
 {
        if (ses->server->tcpStatus == CifsExiting) {
@@ -342,22 +342,24 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
  * the result. Caller is responsible for dealing with timeouts.
  */
 int
-cifs_call_async(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
-               mid_callback_t *callback, void *cbdata)
+cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
+               unsigned int nvec, mid_callback_t *callback, void *cbdata,
+               bool ignore_pend)
 {
        int rc;
        struct mid_q_entry *mid;
+       struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base;
 
-       rc = wait_for_free_request(server, CIFS_ASYNC_OP);
+       rc = wait_for_free_request(server, ignore_pend ? CIFS_ASYNC_OP : 0);
        if (rc)
                return rc;
 
        /* enable signing if server requires it */
-       if (server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-               in_buf->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+       if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+               hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        mutex_lock(&server->srv_mutex);
-       mid = AllocMidQEntry(in_buf, server);
+       mid = AllocMidQEntry(hdr, server);
        if (mid == NULL) {
                mutex_unlock(&server->srv_mutex);
                return -ENOMEM;
@@ -368,7 +370,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
        list_add_tail(&mid->qhead, &server->pending_mid_q);
        spin_unlock(&GlobalMid_Lock);
 
-       rc = cifs_sign_smb(in_buf, server, &mid->sequence_number);
+       rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number);
        if (rc) {
                mutex_unlock(&server->srv_mutex);
                goto out_err;
@@ -380,7 +382,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
 #ifdef CONFIG_CIFS_STATS2
        atomic_inc(&server->inSend);
 #endif
-       rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
+       rc = smb_sendv(server, iov, nvec);
 #ifdef CONFIG_CIFS_STATS2
        atomic_dec(&server->inSend);
        mid->when_sent = jiffies;
@@ -407,7 +409,7 @@ out_err:
  *
  */
 int
-SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
+SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
                struct smb_hdr *in_buf, int flags)
 {
        int rc;
@@ -424,7 +426,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
 }
 
 static int
-sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
+cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
 {
        int rc = 0;
 
@@ -432,28 +434,21 @@ sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
                mid->mid, mid->midState);
 
        spin_lock(&GlobalMid_Lock);
-       /* ensure that it's no longer on the pending_mid_q */
-       list_del_init(&mid->qhead);
-
        switch (mid->midState) {
        case MID_RESPONSE_RECEIVED:
                spin_unlock(&GlobalMid_Lock);
                return rc;
-       case MID_REQUEST_SUBMITTED:
-               /* socket is going down, reject all calls */
-               if (server->tcpStatus == CifsExiting) {
-                       cERROR(1, "%s: canceling mid=%d cmd=0x%x state=%d",
-                              __func__, mid->mid, mid->command, mid->midState);
-                       rc = -EHOSTDOWN;
-                       break;
-               }
        case MID_RETRY_NEEDED:
                rc = -EAGAIN;
                break;
        case MID_RESPONSE_MALFORMED:
                rc = -EIO;
                break;
+       case MID_SHUTDOWN:
+               rc = -EHOSTDOWN;
+               break;
        default:
+               list_del_init(&mid->qhead);
                cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__,
                        mid->mid, mid->midState);
                rc = -EIO;
@@ -502,13 +497,31 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
 }
 
 int
-SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
+cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+                  bool log_error)
+{
+       dump_smb(mid->resp_buf,
+                min_t(u32, 92, be32_to_cpu(mid->resp_buf->smb_buf_length)));
+
+       /* convert the length into a more usable form */
+       if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
+               /* FIXME: add code to kill session */
+               if (cifs_verify_signature(mid->resp_buf, server,
+                                         mid->sequence_number + 1) != 0)
+                       cERROR(1, "Unexpected SMB signature");
+       }
+
+       /* BB special case reconnect tid and uid here? */
+       return map_smb_to_linux_error(mid->resp_buf, log_error);
+}
+
+int
+SendReceive2(const unsigned int xid, struct cifs_ses *ses,
             struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
             const int flags)
 {
        int rc = 0;
        int long_op;
-       unsigned int receive_len;
        struct mid_q_entry *midQ;
        struct smb_hdr *in_buf = iov[0].iov_base;
 
@@ -598,61 +611,31 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 
        cifs_small_buf_release(in_buf);
 
-       rc = sync_mid_result(midQ, ses->server);
+       rc = cifs_sync_mid_result(midQ, ses->server);
        if (rc != 0) {
                atomic_dec(&ses->server->inFlight);
                wake_up(&ses->server->request_q);
                return rc;
        }
 
-       receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length);
-
-       if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
-               cERROR(1, "Frame too large received.  Length: %d  Xid: %d",
-                       receive_len, xid);
+       if (!midQ->resp_buf || midQ->midState != MID_RESPONSE_RECEIVED) {
                rc = -EIO;
+               cFYI(1, "Bad MID state?");
                goto out;
        }
 
-       /* rcvd frame is ok */
-
-       if (midQ->resp_buf &&
-           (midQ->midState == MID_RESPONSE_RECEIVED)) {
-
-               iov[0].iov_base = (char *)midQ->resp_buf;
-               if (midQ->largeBuf)
-                       *pRespBufType = CIFS_LARGE_BUFFER;
-               else
-                       *pRespBufType = CIFS_SMALL_BUFFER;
-               iov[0].iov_len = receive_len + 4;
-
-               dump_smb(midQ->resp_buf, 80);
-               /* convert the length into a more usable form */
-               if ((receive_len > 24) &&
-                   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
-                                            SECMODE_SIGN_ENABLED))) {
-                       rc = cifs_verify_signature(midQ->resp_buf,
-                                               ses->server,
-                                               midQ->sequence_number+1);
-                       if (rc) {
-                               cERROR(1, "Unexpected SMB signature");
-                               /* BB FIXME add code to kill session */
-                       }
-               }
-
-               /* BB special case reconnect tid and uid here? */
-               rc = map_smb_to_linux_error(midQ->resp_buf,
-                                           flags & CIFS_LOG_ERROR);
+       iov[0].iov_base = (char *)midQ->resp_buf;
+       iov[0].iov_len = be32_to_cpu(midQ->resp_buf->smb_buf_length) + 4;
+       if (midQ->largeBuf)
+               *pRespBufType = CIFS_LARGE_BUFFER;
+       else
+               *pRespBufType = CIFS_SMALL_BUFFER;
 
-               if ((flags & CIFS_NO_RESP) == 0)
-                       midQ->resp_buf = NULL;  /* mark it so buf will
-                                                  not be freed by
-                                                  delete_mid */
-       } else {
-               rc = -EIO;
-               cFYI(1, "Bad MID state?");
-       }
+       rc = cifs_check_receive(midQ, ses->server, flags & CIFS_LOG_ERROR);
 
+       /* mark it so buf will not be freed by delete_mid */
+       if ((flags & CIFS_NO_RESP) == 0)
+               midQ->resp_buf = NULL;
 out:
        delete_mid(midQ);
        atomic_dec(&ses->server->inFlight);
@@ -662,12 +645,11 @@ out:
 }
 
 int
-SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
+SendReceive(const unsigned int xid, struct cifs_ses *ses,
            struct smb_hdr *in_buf, struct smb_hdr *out_buf,
            int *pbytes_returned, const int long_op)
 {
        int rc = 0;
-       unsigned int receive_len;
        struct mid_q_entry *midQ;
 
        if (ses == NULL) {
@@ -750,54 +732,23 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
                spin_unlock(&GlobalMid_Lock);
        }
 
-       rc = sync_mid_result(midQ, ses->server);
+       rc = cifs_sync_mid_result(midQ, ses->server);
        if (rc != 0) {
                atomic_dec(&ses->server->inFlight);
                wake_up(&ses->server->request_q);
                return rc;
        }
 
-       receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length);
-
-       if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
-               cERROR(1, "Frame too large received.  Length: %d  Xid: %d",
-                       receive_len, xid);
-               rc = -EIO;
-               goto out;
-       }
-
-       /* rcvd frame is ok */
-
-       if (midQ->resp_buf && out_buf
-           && (midQ->midState == MID_RESPONSE_RECEIVED)) {
-               out_buf->smb_buf_length = cpu_to_be32(receive_len);
-               memcpy((char *)out_buf + 4,
-                      (char *)midQ->resp_buf + 4,
-                      receive_len);
-
-               dump_smb(out_buf, 92);
-               /* convert the length into a more usable form */
-               if ((receive_len > 24) &&
-                   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
-                                            SECMODE_SIGN_ENABLED))) {
-                       rc = cifs_verify_signature(out_buf,
-                                               ses->server,
-                                               midQ->sequence_number+1);
-                       if (rc) {
-                               cERROR(1, "Unexpected SMB signature");
-                               /* BB FIXME add code to kill session */
-                       }
-               }
-
-               *pbytes_returned = be32_to_cpu(out_buf->smb_buf_length);
-
-               /* BB special case reconnect tid and uid here? */
-               rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
-       } else {
+       if (!midQ->resp_buf || !out_buf ||
+           midQ->midState != MID_RESPONSE_RECEIVED) {
                rc = -EIO;
                cERROR(1, "Bad MID state?");
+               goto out;
        }
 
+       *pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length);
+       memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
+       rc = cifs_check_receive(midQ, ses->server, 0);
 out:
        delete_mid(midQ);
        atomic_dec(&ses->server->inFlight);
@@ -810,12 +761,12 @@ out:
    blocking lock to return. */
 
 static int
-send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
+send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon,
                        struct smb_hdr *in_buf,
                        struct smb_hdr *out_buf)
 {
        int bytes_returned;
-       struct cifsSesInfo *ses = tcon->ses;
+       struct cifs_ses *ses = tcon->ses;
        LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
 
        /* We just modify the current in_buf to change
@@ -832,15 +783,14 @@ send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
 }
 
 int
-SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
+SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
            struct smb_hdr *in_buf, struct smb_hdr *out_buf,
            int *pbytes_returned)
 {
        int rc = 0;
        int rstart = 0;
-       unsigned int receive_len;
        struct mid_q_entry *midQ;
-       struct cifsSesInfo *ses;
+       struct cifs_ses *ses;
 
        if (tcon == NULL || tcon->ses == NULL) {
                cERROR(1, "Null smb session");
@@ -957,50 +907,20 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
                rstart = 1;
        }
 
-       rc = sync_mid_result(midQ, ses->server);
+       rc = cifs_sync_mid_result(midQ, ses->server);
        if (rc != 0)
                return rc;
 
-       receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length);
-       if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
-               cERROR(1, "Frame too large received.  Length: %d  Xid: %d",
-                       receive_len, xid);
-               rc = -EIO;
-               goto out;
-       }
-
        /* rcvd frame is ok */
-
-       if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) {
+       if (out_buf == NULL || midQ->midState != MID_RESPONSE_RECEIVED) {
                rc = -EIO;
                cERROR(1, "Bad MID state?");
                goto out;
        }
 
-       out_buf->smb_buf_length = cpu_to_be32(receive_len);
-       memcpy((char *)out_buf + 4,
-              (char *)midQ->resp_buf + 4,
-              receive_len);
-
-       dump_smb(out_buf, 92);
-       /* convert the length into a more usable form */
-       if ((receive_len > 24) &&
-           (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
-                                    SECMODE_SIGN_ENABLED))) {
-               rc = cifs_verify_signature(out_buf,
-                                          ses->server,
-                                          midQ->sequence_number+1);
-               if (rc) {
-                       cERROR(1, "Unexpected SMB signature");
-                       /* BB FIXME add code to kill session */
-               }
-       }
-
-       *pbytes_returned = be32_to_cpu(out_buf->smb_buf_length);
-
-       /* BB special case reconnect tid and uid here? */
-       rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
-
+       *pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length);
+       memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
+       rc = cifs_check_receive(midQ, ses->server, 0);
 out:
        delete_mid(midQ);
        if (rstart && rc == -EACCES)
index 912995e013ecb8414b3058543237bc19f8b5e903..2a22fb2989e4780fd977c683b27ddf23e78e7d8e 100644 (file)
@@ -49,7 +49,7 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
        int xid;
        struct cifs_sb_info *cifs_sb;
        struct tcon_link *tlink;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        struct super_block *sb;
        char *full_path = NULL;
 
@@ -109,7 +109,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
        int xid;
        struct cifs_sb_info *cifs_sb;
        struct tcon_link *tlink;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        struct super_block *sb;
        char *full_path;
        struct cifs_ntsd *pacl;
@@ -240,7 +240,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
        int xid;
        struct cifs_sb_info *cifs_sb;
        struct tcon_link *tlink;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        struct super_block *sb;
        char *full_path;
 
@@ -372,7 +372,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
        int xid;
        struct cifs_sb_info *cifs_sb;
        struct tcon_link *tlink;
-       struct cifsTconInfo *pTcon;
+       struct cifs_tcon *pTcon;
        struct super_block *sb;
        char *full_path;
 
index 6cbb3afb36dc2b28b9aa3f2b585c195330894699..cb140ef293e46e8739669f2e69eea701d8213874 100644 (file)
@@ -43,8 +43,6 @@ const struct file_operations coda_ioctl_operations = {
 /* the coda pioctl inode ops */
 static int coda_ioctl_permission(struct inode *inode, int mask, unsigned int flags)
 {
-       if (flags & IPERM_FLAG_RCU)
-               return -ECHILD;
        return (mask & MAY_EXEC) ? -EACCES : 0;
 }
 
index 18b2a1f10ed89cab1562f696adebf391bf2a8763..37f72ee5bf7c9577f164ce4a472d7d4d8f0c4aaa 100644 (file)
@@ -1220,7 +1220,7 @@ void shrink_dcache_parent(struct dentry * parent)
 EXPORT_SYMBOL(shrink_dcache_parent);
 
 /*
- * Scan `nr' dentries and return the number which remain.
+ * Scan `sc->nr_slab_to_reclaim' dentries and return the number which remain.
  *
  * We need to avoid reentering the filesystem if the caller is performing a
  * GFP_NOFS allocation attempt.  One example deadlock is:
@@ -1231,8 +1231,12 @@ EXPORT_SYMBOL(shrink_dcache_parent);
  *
  * In this case we return -1 to tell the caller that we baled.
  */
-static int shrink_dcache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
+static int shrink_dcache_memory(struct shrinker *shrink,
+                               struct shrink_control *sc)
 {
+       int nr = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
+
        if (nr) {
                if (!(gfp_mask & __GFP_FS))
                        return -1;
index a21cabdbd87b174c635b584e548fcfbd3d1d1679..dda0dc702d1b8da82cbe360bba1ffd9f2c6ced46 100644 (file)
@@ -178,6 +178,8 @@ SYSCALL_DEFINE(lookup_dcookie)(u64 cookie64, char __user * buf, size_t len)
        /* FIXME: (deleted) ? */
        path = d_path(&dcs->path, kbuf, PAGE_SIZE);
 
+       mutex_unlock(&dcookie_mutex);
+
        if (IS_ERR(path)) {
                err = PTR_ERR(path);
                goto out_free;
@@ -194,6 +196,7 @@ SYSCALL_DEFINE(lookup_dcookie)(u64 cookie64, char __user * buf, size_t len)
 
 out_free:
        kfree(kbuf);
+       return err;
 out:
        mutex_unlock(&dcookie_mutex);
        return err;
index 0d329ff8ed4cf65127c7e017bda08f988977e12e..9b026ea8baa94a92205213249723491237ae803d 100644 (file)
@@ -100,6 +100,7 @@ struct dlm_cluster {
        unsigned int cl_log_debug;
        unsigned int cl_protocol;
        unsigned int cl_timewarn_cs;
+       unsigned int cl_waitwarn_us;
 };
 
 enum {
@@ -114,6 +115,7 @@ enum {
        CLUSTER_ATTR_LOG_DEBUG,
        CLUSTER_ATTR_PROTOCOL,
        CLUSTER_ATTR_TIMEWARN_CS,
+       CLUSTER_ATTR_WAITWARN_US,
 };
 
 struct cluster_attribute {
@@ -166,6 +168,7 @@ CLUSTER_ATTR(scan_secs, 1);
 CLUSTER_ATTR(log_debug, 0);
 CLUSTER_ATTR(protocol, 0);
 CLUSTER_ATTR(timewarn_cs, 1);
+CLUSTER_ATTR(waitwarn_us, 0);
 
 static struct configfs_attribute *cluster_attrs[] = {
        [CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port.attr,
@@ -179,6 +182,7 @@ static struct configfs_attribute *cluster_attrs[] = {
        [CLUSTER_ATTR_LOG_DEBUG] = &cluster_attr_log_debug.attr,
        [CLUSTER_ATTR_PROTOCOL] = &cluster_attr_protocol.attr,
        [CLUSTER_ATTR_TIMEWARN_CS] = &cluster_attr_timewarn_cs.attr,
+       [CLUSTER_ATTR_WAITWARN_US] = &cluster_attr_waitwarn_us.attr,
        NULL,
 };
 
@@ -439,6 +443,7 @@ static struct config_group *make_cluster(struct config_group *g,
        cl->cl_log_debug = dlm_config.ci_log_debug;
        cl->cl_protocol = dlm_config.ci_protocol;
        cl->cl_timewarn_cs = dlm_config.ci_timewarn_cs;
+       cl->cl_waitwarn_us = dlm_config.ci_waitwarn_us;
 
        space_list = &sps->ss_group;
        comm_list = &cms->cs_group;
@@ -986,6 +991,7 @@ int dlm_our_addr(struct sockaddr_storage *addr, int num)
 #define DEFAULT_LOG_DEBUG          0
 #define DEFAULT_PROTOCOL           0
 #define DEFAULT_TIMEWARN_CS      500 /* 5 sec = 500 centiseconds */
+#define DEFAULT_WAITWARN_US       0
 
 struct dlm_config_info dlm_config = {
        .ci_tcp_port = DEFAULT_TCP_PORT,
@@ -998,6 +1004,7 @@ struct dlm_config_info dlm_config = {
        .ci_scan_secs = DEFAULT_SCAN_SECS,
        .ci_log_debug = DEFAULT_LOG_DEBUG,
        .ci_protocol = DEFAULT_PROTOCOL,
-       .ci_timewarn_cs = DEFAULT_TIMEWARN_CS
+       .ci_timewarn_cs = DEFAULT_TIMEWARN_CS,
+       .ci_waitwarn_us = DEFAULT_WAITWARN_US
 };
 
index 4f1d6fce58c5e2ff47cadf83de384e788b2f4756..dd0ce24d5a802c83907146db0c7eb32c5dfe6aa3 100644 (file)
@@ -28,6 +28,7 @@ struct dlm_config_info {
        int ci_log_debug;
        int ci_protocol;
        int ci_timewarn_cs;
+       int ci_waitwarn_us;
 };
 
 extern struct dlm_config_info dlm_config;
index b94204913011e088c82a294712d7aa8a64457c73..0262451eb9c6e90cf77d71fb955fff7f60c44668 100644 (file)
@@ -209,6 +209,7 @@ struct dlm_args {
 #define DLM_IFL_WATCH_TIMEWARN 0x00400000
 #define DLM_IFL_TIMEOUT_CANCEL 0x00800000
 #define DLM_IFL_DEADLOCK_CANCEL        0x01000000
+#define DLM_IFL_STUB_MS                0x02000000 /* magic number for m_flags */
 #define DLM_IFL_USER           0x00000001
 #define DLM_IFL_ORPHAN         0x00000002
 
@@ -245,6 +246,7 @@ struct dlm_lkb {
 
        int8_t                  lkb_wait_type;  /* type of reply waiting for */
        int8_t                  lkb_wait_count;
+       int                     lkb_wait_nodeid; /* for debugging */
 
        struct list_head        lkb_idtbl_list; /* lockspace lkbtbl */
        struct list_head        lkb_statequeue; /* rsb g/c/w list */
@@ -254,6 +256,7 @@ struct dlm_lkb {
        struct list_head        lkb_ownqueue;   /* list of locks for a process */
        struct list_head        lkb_time_list;
        ktime_t                 lkb_timestamp;
+       ktime_t                 lkb_wait_time;
        unsigned long           lkb_timeout_cs;
 
        struct dlm_callback     lkb_callbacks[DLM_CALLBACKS_SIZE];
index 56d6bfcc1e48895f2d9523d70376779349b44cfa..f71d0b5abd954db4dee39e5288c7835584f0cc36 100644 (file)
@@ -799,10 +799,84 @@ static int msg_reply_type(int mstype)
        return -1;
 }
 
+static int nodeid_warned(int nodeid, int num_nodes, int *warned)
+{
+       int i;
+
+       for (i = 0; i < num_nodes; i++) {
+               if (!warned[i]) {
+                       warned[i] = nodeid;
+                       return 0;
+               }
+               if (warned[i] == nodeid)
+                       return 1;
+       }
+       return 0;
+}
+
+void dlm_scan_waiters(struct dlm_ls *ls)
+{
+       struct dlm_lkb *lkb;
+       ktime_t zero = ktime_set(0, 0);
+       s64 us;
+       s64 debug_maxus = 0;
+       u32 debug_scanned = 0;
+       u32 debug_expired = 0;
+       int num_nodes = 0;
+       int *warned = NULL;
+
+       if (!dlm_config.ci_waitwarn_us)
+               return;
+
+       mutex_lock(&ls->ls_waiters_mutex);
+
+       list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
+               if (ktime_equal(lkb->lkb_wait_time, zero))
+                       continue;
+
+               debug_scanned++;
+
+               us = ktime_to_us(ktime_sub(ktime_get(), lkb->lkb_wait_time));
+
+               if (us < dlm_config.ci_waitwarn_us)
+                       continue;
+
+               lkb->lkb_wait_time = zero;
+
+               debug_expired++;
+               if (us > debug_maxus)
+                       debug_maxus = us;
+
+               if (!num_nodes) {
+                       num_nodes = ls->ls_num_nodes;
+                       warned = kmalloc(GFP_KERNEL, num_nodes * sizeof(int));
+                       if (warned)
+                               memset(warned, 0, num_nodes * sizeof(int));
+               }
+               if (!warned)
+                       continue;
+               if (nodeid_warned(lkb->lkb_wait_nodeid, num_nodes, warned))
+                       continue;
+
+               log_error(ls, "waitwarn %x %lld %d us check connection to "
+                         "node %d", lkb->lkb_id, (long long)us,
+                         dlm_config.ci_waitwarn_us, lkb->lkb_wait_nodeid);
+       }
+       mutex_unlock(&ls->ls_waiters_mutex);
+
+       if (warned)
+               kfree(warned);
+
+       if (debug_expired)
+               log_debug(ls, "scan_waiters %u warn %u over %d us max %lld us",
+                         debug_scanned, debug_expired,
+                         dlm_config.ci_waitwarn_us, (long long)debug_maxus);
+}
+
 /* add/remove lkb from global waiters list of lkb's waiting for
    a reply from a remote node */
 
-static int add_to_waiters(struct dlm_lkb *lkb, int mstype)
+static int add_to_waiters(struct dlm_lkb *lkb, int mstype, int to_nodeid)
 {
        struct dlm_ls *ls = lkb->lkb_resource->res_ls;
        int error = 0;
@@ -842,6 +916,8 @@ static int add_to_waiters(struct dlm_lkb *lkb, int mstype)
 
        lkb->lkb_wait_count++;
        lkb->lkb_wait_type = mstype;
+       lkb->lkb_wait_time = ktime_get();
+       lkb->lkb_wait_nodeid = to_nodeid; /* for debugging */
        hold_lkb(lkb);
        list_add(&lkb->lkb_wait_reply, &ls->ls_waiters);
  out:
@@ -961,10 +1037,10 @@ static int remove_from_waiters_ms(struct dlm_lkb *lkb, struct dlm_message *ms)
        struct dlm_ls *ls = lkb->lkb_resource->res_ls;
        int error;
 
-       if (ms != &ls->ls_stub_ms)
+       if (ms->m_flags != DLM_IFL_STUB_MS)
                mutex_lock(&ls->ls_waiters_mutex);
        error = _remove_from_waiters(lkb, ms->m_type, ms);
-       if (ms != &ls->ls_stub_ms)
+       if (ms->m_flags != DLM_IFL_STUB_MS)
                mutex_unlock(&ls->ls_waiters_mutex);
        return error;
 }
@@ -1157,6 +1233,16 @@ void dlm_adjust_timeouts(struct dlm_ls *ls)
        list_for_each_entry(lkb, &ls->ls_timeout, lkb_time_list)
                lkb->lkb_timestamp = ktime_add_us(lkb->lkb_timestamp, adj_us);
        mutex_unlock(&ls->ls_timeout_mutex);
+
+       if (!dlm_config.ci_waitwarn_us)
+               return;
+
+       mutex_lock(&ls->ls_waiters_mutex);
+       list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
+               if (ktime_to_us(lkb->lkb_wait_time))
+                       lkb->lkb_wait_time = ktime_get();
+       }
+       mutex_unlock(&ls->ls_waiters_mutex);
 }
 
 /* lkb is master or local copy */
@@ -1376,14 +1462,8 @@ static void grant_lock_pending(struct dlm_rsb *r, struct dlm_lkb *lkb)
    ALTPR/ALTCW: our rqmode may have been changed to PR or CW to become
    compatible with other granted locks */
 
-static void munge_demoted(struct dlm_lkb *lkb, struct dlm_message *ms)
+static void munge_demoted(struct dlm_lkb *lkb)
 {
-       if (ms->m_type != DLM_MSG_CONVERT_REPLY) {
-               log_print("munge_demoted %x invalid reply type %d",
-                         lkb->lkb_id, ms->m_type);
-               return;
-       }
-
        if (lkb->lkb_rqmode == DLM_LOCK_IV || lkb->lkb_grmode == DLM_LOCK_IV) {
                log_print("munge_demoted %x invalid modes gr %d rq %d",
                          lkb->lkb_id, lkb->lkb_grmode, lkb->lkb_rqmode);
@@ -2844,12 +2924,12 @@ static int send_common(struct dlm_rsb *r, struct dlm_lkb *lkb, int mstype)
        struct dlm_mhandle *mh;
        int to_nodeid, error;
 
-       error = add_to_waiters(lkb, mstype);
+       to_nodeid = r->res_nodeid;
+
+       error = add_to_waiters(lkb, mstype, to_nodeid);
        if (error)
                return error;
 
-       to_nodeid = r->res_nodeid;
-
        error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh);
        if (error)
                goto fail;
@@ -2880,9 +2960,9 @@ static int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
        /* down conversions go without a reply from the master */
        if (!error && down_conversion(lkb)) {
                remove_from_waiters(lkb, DLM_MSG_CONVERT_REPLY);
+               r->res_ls->ls_stub_ms.m_flags = DLM_IFL_STUB_MS;
                r->res_ls->ls_stub_ms.m_type = DLM_MSG_CONVERT_REPLY;
                r->res_ls->ls_stub_ms.m_result = 0;
-               r->res_ls->ls_stub_ms.m_flags = lkb->lkb_flags;
                __receive_convert_reply(r, lkb, &r->res_ls->ls_stub_ms);
        }
 
@@ -2951,12 +3031,12 @@ static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb)
        struct dlm_mhandle *mh;
        int to_nodeid, error;
 
-       error = add_to_waiters(lkb, DLM_MSG_LOOKUP);
+       to_nodeid = dlm_dir_nodeid(r);
+
+       error = add_to_waiters(lkb, DLM_MSG_LOOKUP, to_nodeid);
        if (error)
                return error;
 
-       to_nodeid = dlm_dir_nodeid(r);
-
        error = create_message(r, NULL, to_nodeid, DLM_MSG_LOOKUP, &ms, &mh);
        if (error)
                goto fail;
@@ -3070,6 +3150,9 @@ static void receive_flags(struct dlm_lkb *lkb, struct dlm_message *ms)
 
 static void receive_flags_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
 {
+       if (ms->m_flags == DLM_IFL_STUB_MS)
+               return;
+
        lkb->lkb_sbflags = ms->m_sbflags;
        lkb->lkb_flags = (lkb->lkb_flags & 0xFFFF0000) |
                         (ms->m_flags & 0x0000FFFF);
@@ -3612,7 +3695,7 @@ static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
                /* convert was queued on remote master */
                receive_flags_reply(lkb, ms);
                if (is_demoted(lkb))
-                       munge_demoted(lkb, ms);
+                       munge_demoted(lkb);
                del_lkb(r, lkb);
                add_lkb(r, lkb, DLM_LKSTS_CONVERT);
                add_timeout(lkb);
@@ -3622,7 +3705,7 @@ static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
                /* convert was granted on remote master */
                receive_flags_reply(lkb, ms);
                if (is_demoted(lkb))
-                       munge_demoted(lkb, ms);
+                       munge_demoted(lkb);
                grant_lock_pc(r, lkb, ms);
                queue_cast(r, lkb, 0);
                break;
@@ -3996,15 +4079,17 @@ void dlm_receive_buffer(union dlm_packet *p, int nodeid)
        dlm_put_lockspace(ls);
 }
 
-static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb)
+static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb,
+                                  struct dlm_message *ms_stub)
 {
        if (middle_conversion(lkb)) {
                hold_lkb(lkb);
-               ls->ls_stub_ms.m_type = DLM_MSG_CONVERT_REPLY;
-               ls->ls_stub_ms.m_result = -EINPROGRESS;
-               ls->ls_stub_ms.m_flags = lkb->lkb_flags;
-               ls->ls_stub_ms.m_header.h_nodeid = lkb->lkb_nodeid;
-               _receive_convert_reply(lkb, &ls->ls_stub_ms);
+               memset(ms_stub, 0, sizeof(struct dlm_message));
+               ms_stub->m_flags = DLM_IFL_STUB_MS;
+               ms_stub->m_type = DLM_MSG_CONVERT_REPLY;
+               ms_stub->m_result = -EINPROGRESS;
+               ms_stub->m_header.h_nodeid = lkb->lkb_nodeid;
+               _receive_convert_reply(lkb, ms_stub);
 
                /* Same special case as in receive_rcom_lock_args() */
                lkb->lkb_grmode = DLM_LOCK_IV;
@@ -4045,13 +4130,27 @@ static int waiter_needs_recovery(struct dlm_ls *ls, struct dlm_lkb *lkb)
 void dlm_recover_waiters_pre(struct dlm_ls *ls)
 {
        struct dlm_lkb *lkb, *safe;
+       struct dlm_message *ms_stub;
        int wait_type, stub_unlock_result, stub_cancel_result;
 
+       ms_stub = kmalloc(GFP_KERNEL, sizeof(struct dlm_message));
+       if (!ms_stub) {
+               log_error(ls, "dlm_recover_waiters_pre no mem");
+               return;
+       }
+
        mutex_lock(&ls->ls_waiters_mutex);
 
        list_for_each_entry_safe(lkb, safe, &ls->ls_waiters, lkb_wait_reply) {
-               log_debug(ls, "pre recover waiter lkid %x type %d flags %x",
-                         lkb->lkb_id, lkb->lkb_wait_type, lkb->lkb_flags);
+
+               /* exclude debug messages about unlocks because there can be so
+                  many and they aren't very interesting */
+
+               if (lkb->lkb_wait_type != DLM_MSG_UNLOCK) {
+                       log_debug(ls, "recover_waiter %x nodeid %d "
+                                 "msg %d to %d", lkb->lkb_id, lkb->lkb_nodeid,
+                                 lkb->lkb_wait_type, lkb->lkb_wait_nodeid);
+               }
 
                /* all outstanding lookups, regardless of destination  will be
                   resent after recovery is done */
@@ -4097,26 +4196,28 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls)
                        break;
 
                case DLM_MSG_CONVERT:
-                       recover_convert_waiter(ls, lkb);
+                       recover_convert_waiter(ls, lkb, ms_stub);
                        break;
 
                case DLM_MSG_UNLOCK:
                        hold_lkb(lkb);
-                       ls->ls_stub_ms.m_type = DLM_MSG_UNLOCK_REPLY;
-                       ls->ls_stub_ms.m_result = stub_unlock_result;
-                       ls->ls_stub_ms.m_flags = lkb->lkb_flags;
-                       ls->ls_stub_ms.m_header.h_nodeid = lkb->lkb_nodeid;
-                       _receive_unlock_reply(lkb, &ls->ls_stub_ms);
+                       memset(ms_stub, 0, sizeof(struct dlm_message));
+                       ms_stub->m_flags = DLM_IFL_STUB_MS;
+                       ms_stub->m_type = DLM_MSG_UNLOCK_REPLY;
+                       ms_stub->m_result = stub_unlock_result;
+                       ms_stub->m_header.h_nodeid = lkb->lkb_nodeid;
+                       _receive_unlock_reply(lkb, ms_stub);
                        dlm_put_lkb(lkb);
                        break;
 
                case DLM_MSG_CANCEL:
                        hold_lkb(lkb);
-                       ls->ls_stub_ms.m_type = DLM_MSG_CANCEL_REPLY;
-                       ls->ls_stub_ms.m_result = stub_cancel_result;
-                       ls->ls_stub_ms.m_flags = lkb->lkb_flags;
-                       ls->ls_stub_ms.m_header.h_nodeid = lkb->lkb_nodeid;
-                       _receive_cancel_reply(lkb, &ls->ls_stub_ms);
+                       memset(ms_stub, 0, sizeof(struct dlm_message));
+                       ms_stub->m_flags = DLM_IFL_STUB_MS;
+                       ms_stub->m_type = DLM_MSG_CANCEL_REPLY;
+                       ms_stub->m_result = stub_cancel_result;
+                       ms_stub->m_header.h_nodeid = lkb->lkb_nodeid;
+                       _receive_cancel_reply(lkb, ms_stub);
                        dlm_put_lkb(lkb);
                        break;
 
@@ -4127,6 +4228,7 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls)
                schedule();
        }
        mutex_unlock(&ls->ls_waiters_mutex);
+       kfree(ms_stub);
 }
 
 static struct dlm_lkb *find_resend_waiter(struct dlm_ls *ls)
@@ -4191,8 +4293,8 @@ int dlm_recover_waiters_post(struct dlm_ls *ls)
                ou = is_overlap_unlock(lkb);
                err = 0;
 
-               log_debug(ls, "recover_waiters_post %x type %d flags %x %s",
-                         lkb->lkb_id, mstype, lkb->lkb_flags, r->res_name);
+               log_debug(ls, "recover_waiter %x nodeid %d msg %d r_nodeid %d",
+                         lkb->lkb_id, lkb->lkb_nodeid, mstype, r->res_nodeid);
 
                /* At this point we assume that we won't get a reply to any
                   previous op or overlap op on this lock.  First, do a big
index 88e93c80cc22491202dcd1843f3931678e324b76..265017a7c3e7a6246f39400566238bddf996507c 100644 (file)
@@ -24,6 +24,7 @@ int dlm_put_lkb(struct dlm_lkb *lkb);
 void dlm_scan_rsbs(struct dlm_ls *ls);
 int dlm_lock_recovery_try(struct dlm_ls *ls);
 void dlm_unlock_recovery(struct dlm_ls *ls);
+void dlm_scan_waiters(struct dlm_ls *ls);
 void dlm_scan_timeout(struct dlm_ls *ls);
 void dlm_adjust_timeouts(struct dlm_ls *ls);
 
index f994a7dfda85c69e9d1d514329add11811bd9278..14cbf409975387ca6b404c8b6ed2600c1ae4954d 100644 (file)
@@ -243,7 +243,6 @@ static struct dlm_ls *find_ls_to_scan(void)
 static int dlm_scand(void *data)
 {
        struct dlm_ls *ls;
-       int timeout_jiffies = dlm_config.ci_scan_secs * HZ;
 
        while (!kthread_should_stop()) {
                ls = find_ls_to_scan();
@@ -252,13 +251,14 @@ static int dlm_scand(void *data)
                                ls->ls_scan_time = jiffies;
                                dlm_scan_rsbs(ls);
                                dlm_scan_timeout(ls);
+                               dlm_scan_waiters(ls);
                                dlm_unlock_recovery(ls);
                        } else {
                                ls->ls_scan_time += HZ;
                        }
-               } else {
-                       schedule_timeout_interruptible(timeout_jiffies);
+                       continue;
                }
+               schedule_timeout_interruptible(dlm_config.ci_scan_secs * HZ);
        }
        return 0;
 }
index b80e0aa3cfa534e6ef130dc09bb36454fbbe260d..5a59efa0bb469ebb9991be5d29bdb98c93233cfd 100644 (file)
@@ -50,7 +50,7 @@ static int __init init_dlm(void)
        if (error)
                goto out_netlink;
 
-       printk("DLM (built %s %s) installed\n", __DATE__, __TIME__);
+       printk("DLM installed\n");
 
        return 0;
 
index 30d8b85febbf1eb413333bddac0b365b29b676d3..e2b87800436427ab2783118876ddeacfa2ace9cd 100644 (file)
@@ -71,6 +71,36 @@ static void send_op(struct plock_op *op)
        wake_up(&send_wq);
 }
 
+/* If a process was killed while waiting for the only plock on a file,
+   locks_remove_posix will not see any lock on the file so it won't
+   send an unlock-close to us to pass on to userspace to clean up the
+   abandoned waiter.  So, we have to insert the unlock-close when the
+   lock call is interrupted. */
+
+static void do_unlock_close(struct dlm_ls *ls, u64 number,
+                           struct file *file, struct file_lock *fl)
+{
+       struct plock_op *op;
+
+       op = kzalloc(sizeof(*op), GFP_NOFS);
+       if (!op)
+               return;
+
+       op->info.optype         = DLM_PLOCK_OP_UNLOCK;
+       op->info.pid            = fl->fl_pid;
+       op->info.fsid           = ls->ls_global_id;
+       op->info.number         = number;
+       op->info.start          = 0;
+       op->info.end            = OFFSET_MAX;
+       if (fl->fl_lmops && fl->fl_lmops->fl_grant)
+               op->info.owner  = (__u64) fl->fl_pid;
+       else
+               op->info.owner  = (__u64)(long) fl->fl_owner;
+
+       op->info.flags |= DLM_PLOCK_FL_CLOSE;
+       send_op(op);
+}
+
 int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
                   int cmd, struct file_lock *fl)
 {
@@ -114,9 +144,19 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
 
        send_op(op);
 
-       if (xop->callback == NULL)
-               wait_event(recv_wq, (op->done != 0));
-       else {
+       if (xop->callback == NULL) {
+               rv = wait_event_killable(recv_wq, (op->done != 0));
+               if (rv == -ERESTARTSYS) {
+                       log_debug(ls, "dlm_posix_lock: wait killed %llx",
+                                 (unsigned long long)number);
+                       spin_lock(&ops_lock);
+                       list_del(&op->list);
+                       spin_unlock(&ops_lock);
+                       kfree(xop);
+                       do_unlock_close(ls, number, file, fl);
+                       goto out;
+               }
+       } else {
                rv = FILE_LOCK_DEFERRED;
                goto out;
        }
@@ -233,6 +273,13 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
        else
                op->info.owner  = (__u64)(long) fl->fl_owner;
 
+       if (fl->fl_flags & FL_CLOSE) {
+               op->info.flags |= DLM_PLOCK_FL_CLOSE;
+               send_op(op);
+               rv = 0;
+               goto out;
+       }
+
        send_op(op);
        wait_event(recv_wq, (op->done != 0));
 
@@ -334,7 +381,10 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count,
        spin_lock(&ops_lock);
        if (!list_empty(&send_list)) {
                op = list_entry(send_list.next, struct plock_op, list);
-               list_move(&op->list, &recv_list);
+               if (op->info.flags & DLM_PLOCK_FL_CLOSE)
+                       list_del(&op->list);
+               else
+                       list_move(&op->list, &recv_list);
                memcpy(&info, &op->info, sizeof(info));
        }
        spin_unlock(&ops_lock);
@@ -342,6 +392,13 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count,
        if (!op)
                return -EAGAIN;
 
+       /* there is no need to get a reply from userspace for unlocks
+          that were generated by the vfs cleaning up for a close
+          (the process did not make an unlock call). */
+
+       if (op->info.flags & DLM_PLOCK_FL_CLOSE)
+               kfree(op);
+
        if (copy_to_user(u, &info, sizeof(info)))
                return -EFAULT;
        return sizeof(info);
index d5ab3fe7c198ab7da612c0421cb22d4cbeba8568..e96bf3e9be88e566e1095f6960974a5e3fc1340d 100644 (file)
@@ -611,7 +611,6 @@ static ssize_t device_write(struct file *file, const char __user *buf,
 
  out_sig:
        sigprocmask(SIG_SETMASK, &tmpsig, NULL);
-       recalc_sigpending();
  out_free:
        kfree(kbuf);
        return error;
index 98b77c89494caf7c364272194316d431e10cfcef..c00e055b62820945bef291fa68b145a4d7145667 100644 (file)
@@ -40,9 +40,12 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)
 static void drop_slab(void)
 {
        int nr_objects;
+       struct shrink_control shrink = {
+               .gfp_mask = GFP_KERNEL,
+       };
 
        do {
-               nr_objects = shrink_slab(1000, GFP_KERNEL, 1000);
+               nr_objects = shrink_slab(&shrink, 1000, 1000);
        } while (nr_objects > 10);
 }
 
index b8d5c8091024cd1a66d8f36cf9d8fde25f3d2052..58609bde3b9fc076187afa3317582788f2f6bc7f 100644 (file)
@@ -1024,25 +1024,25 @@ out:
 }
 
 /**
- * contains_ecryptfs_marker - check for the ecryptfs marker
+ * ecryptfs_validate_marker - check for the ecryptfs marker
  * @data: The data block in which to check
  *
- * Returns one if marker found; zero if not found
+ * Returns zero if marker found; -EINVAL if not found
  */
-static int contains_ecryptfs_marker(char *data)
+static int ecryptfs_validate_marker(char *data)
 {
        u32 m_1, m_2;
 
        m_1 = get_unaligned_be32(data);
        m_2 = get_unaligned_be32(data + 4);
        if ((m_1 ^ MAGIC_ECRYPTFS_MARKER) == m_2)
-               return 1;
+               return 0;
        ecryptfs_printk(KERN_DEBUG, "m_1 = [0x%.8x]; m_2 = [0x%.8x]; "
                        "MAGIC_ECRYPTFS_MARKER = [0x%.8x]\n", m_1, m_2,
                        MAGIC_ECRYPTFS_MARKER);
        ecryptfs_printk(KERN_DEBUG, "(m_1 ^ MAGIC_ECRYPTFS_MARKER) = "
                        "[0x%.8x]\n", (m_1 ^ MAGIC_ECRYPTFS_MARKER));
-       return 0;
+       return -EINVAL;
 }
 
 struct ecryptfs_flag_map_elem {
@@ -1201,27 +1201,19 @@ int ecryptfs_cipher_code_to_string(char *str, u8 cipher_code)
        return rc;
 }
 
-int ecryptfs_read_and_validate_header_region(char *data,
-                                            struct inode *ecryptfs_inode)
+int ecryptfs_read_and_validate_header_region(struct inode *inode)
 {
-       struct ecryptfs_crypt_stat *crypt_stat =
-               &(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat);
+       u8 file_size[ECRYPTFS_SIZE_AND_MARKER_BYTES];
+       u8 *marker = file_size + ECRYPTFS_FILE_SIZE_BYTES;
        int rc;
 
-       if (crypt_stat->extent_size == 0)
-               crypt_stat->extent_size = ECRYPTFS_DEFAULT_EXTENT_SIZE;
-       rc = ecryptfs_read_lower(data, 0, crypt_stat->extent_size,
-                                ecryptfs_inode);
-       if (rc < 0) {
-               printk(KERN_ERR "%s: Error reading header region; rc = [%d]\n",
-                      __func__, rc);
-               goto out;
-       }
-       if (!contains_ecryptfs_marker(data + ECRYPTFS_FILE_SIZE_BYTES)) {
-               rc = -EINVAL;
-       } else
-               rc = 0;
-out:
+       rc = ecryptfs_read_lower(file_size, 0, ECRYPTFS_SIZE_AND_MARKER_BYTES,
+                                inode);
+       if (rc < ECRYPTFS_SIZE_AND_MARKER_BYTES)
+               return rc >= 0 ? -EINVAL : rc;
+       rc = ecryptfs_validate_marker(marker);
+       if (!rc)
+               ecryptfs_i_size_init(file_size, inode);
        return rc;
 }
 
@@ -1242,8 +1234,7 @@ ecryptfs_write_header_metadata(char *virt,
        (*written) = 6;
 }
 
-struct kmem_cache *ecryptfs_header_cache_1;
-struct kmem_cache *ecryptfs_header_cache_2;
+struct kmem_cache *ecryptfs_header_cache;
 
 /**
  * ecryptfs_write_headers_virt
@@ -1496,11 +1487,9 @@ static int ecryptfs_read_headers_virt(char *page_virt,
        crypt_stat->mount_crypt_stat = &ecryptfs_superblock_to_private(
                ecryptfs_dentry->d_sb)->mount_crypt_stat;
        offset = ECRYPTFS_FILE_SIZE_BYTES;
-       rc = contains_ecryptfs_marker(page_virt + offset);
-       if (rc == 0) {
-               rc = -EINVAL;
+       rc = ecryptfs_validate_marker(page_virt + offset);
+       if (rc)
                goto out;
-       }
        if (!(crypt_stat->flags & ECRYPTFS_I_SIZE_INITIALIZED))
                ecryptfs_i_size_init(page_virt, ecryptfs_dentry->d_inode);
        offset += MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;
@@ -1567,20 +1556,21 @@ out:
        return rc;
 }
 
-int ecryptfs_read_and_validate_xattr_region(char *page_virt,
-                                           struct dentry *ecryptfs_dentry)
+int ecryptfs_read_and_validate_xattr_region(struct dentry *dentry,
+                                           struct inode *inode)
 {
+       u8 file_size[ECRYPTFS_SIZE_AND_MARKER_BYTES];
+       u8 *marker = file_size + ECRYPTFS_FILE_SIZE_BYTES;
        int rc;
 
-       rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_dentry->d_inode);
-       if (rc)
-               goto out;
-       if (!contains_ecryptfs_marker(page_virt + ECRYPTFS_FILE_SIZE_BYTES)) {
-               printk(KERN_WARNING "Valid data found in [%s] xattr, but "
-                       "the marker is invalid\n", ECRYPTFS_XATTR_NAME);
-               rc = -EINVAL;
-       }
-out:
+       rc = ecryptfs_getxattr_lower(ecryptfs_dentry_to_lower(dentry),
+                                    ECRYPTFS_XATTR_NAME, file_size,
+                                    ECRYPTFS_SIZE_AND_MARKER_BYTES);
+       if (rc < ECRYPTFS_SIZE_AND_MARKER_BYTES)
+               return rc >= 0 ? -EINVAL : rc;
+       rc = ecryptfs_validate_marker(marker);
+       if (!rc)
+               ecryptfs_i_size_init(file_size, inode);
        return rc;
 }
 
@@ -1610,7 +1600,7 @@ int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry)
        ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat,
                                                      mount_crypt_stat);
        /* Read the first page from the underlying file */
-       page_virt = kmem_cache_alloc(ecryptfs_header_cache_1, GFP_USER);
+       page_virt = kmem_cache_alloc(ecryptfs_header_cache, GFP_USER);
        if (!page_virt) {
                rc = -ENOMEM;
                printk(KERN_ERR "%s: Unable to allocate page_virt\n",
@@ -1655,7 +1645,7 @@ int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry)
 out:
        if (page_virt) {
                memset(page_virt, 0, PAGE_CACHE_SIZE);
-               kmem_cache_free(ecryptfs_header_cache_1, page_virt);
+               kmem_cache_free(ecryptfs_header_cache, page_virt);
        }
        return rc;
 }
index e70282775e2c193f11da232c897f6859a2e4334b..43c7c43b06f54f10c692a21df3b4158059257bbb 100644 (file)
@@ -200,6 +200,8 @@ ecryptfs_get_key_payload_data(struct key *key)
 #define MAGIC_ECRYPTFS_MARKER 0x3c81b7f5
 #define MAGIC_ECRYPTFS_MARKER_SIZE_BYTES 8     /* 4*2 */
 #define ECRYPTFS_FILE_SIZE_BYTES (sizeof(u64))
+#define ECRYPTFS_SIZE_AND_MARKER_BYTES (ECRYPTFS_FILE_SIZE_BYTES \
+                                       + MAGIC_ECRYPTFS_MARKER_SIZE_BYTES)
 #define ECRYPTFS_DEFAULT_CIPHER "aes"
 #define ECRYPTFS_DEFAULT_KEY_BYTES 16
 #define ECRYPTFS_DEFAULT_HASH "md5"
@@ -603,8 +605,7 @@ extern struct kmem_cache *ecryptfs_file_info_cache;
 extern struct kmem_cache *ecryptfs_dentry_info_cache;
 extern struct kmem_cache *ecryptfs_inode_info_cache;
 extern struct kmem_cache *ecryptfs_sb_info_cache;
-extern struct kmem_cache *ecryptfs_header_cache_1;
-extern struct kmem_cache *ecryptfs_header_cache_2;
+extern struct kmem_cache *ecryptfs_header_cache;
 extern struct kmem_cache *ecryptfs_xattr_cache;
 extern struct kmem_cache *ecryptfs_key_record_cache;
 extern struct kmem_cache *ecryptfs_key_sig_cache;
@@ -625,14 +626,9 @@ struct ecryptfs_open_req {
        struct list_head kthread_ctl_list;
 };
 
-#define ECRYPTFS_INTERPOSE_FLAG_D_ADD                 0x00000001
-int ecryptfs_interpose(struct dentry *hidden_dentry,
-                      struct dentry *this_dentry, struct super_block *sb,
-                      u32 flags);
+struct inode *ecryptfs_get_inode(struct inode *lower_inode,
+                                struct super_block *sb);
 void ecryptfs_i_size_init(const char *page_virt, struct inode *inode);
-int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
-                                       struct dentry *lower_dentry,
-                                       struct inode *ecryptfs_dir_inode);
 int ecryptfs_decode_and_decrypt_filename(char **decrypted_name,
                                         size_t *decrypted_name_size,
                                         struct dentry *ecryptfs_dentry,
@@ -664,10 +660,9 @@ int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry);
 void ecryptfs_write_crypt_stat_flags(char *page_virt,
                                     struct ecryptfs_crypt_stat *crypt_stat,
                                     size_t *written);
-int ecryptfs_read_and_validate_header_region(char *data,
-                                            struct inode *ecryptfs_inode);
-int ecryptfs_read_and_validate_xattr_region(char *page_virt,
-                                           struct dentry *ecryptfs_dentry);
+int ecryptfs_read_and_validate_header_region(struct inode *inode);
+int ecryptfs_read_and_validate_xattr_region(struct dentry *dentry,
+                                           struct inode *inode);
 u8 ecryptfs_code_for_cipher_string(char *cipher_name, size_t key_bytes);
 int ecryptfs_cipher_code_to_string(char *str, u8 cipher_code);
 void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat);
@@ -679,9 +674,6 @@ int
 ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
                          unsigned char *src, struct dentry *ecryptfs_dentry);
 int ecryptfs_truncate(struct dentry *dentry, loff_t new_length);
-int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode);
-int ecryptfs_inode_set(struct inode *inode, void *lower_inode);
-void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode);
 ssize_t
 ecryptfs_getxattr_lower(struct dentry *lower_dentry, const char *name,
                        void *value, size_t size);
@@ -761,7 +753,7 @@ int ecryptfs_privileged_open(struct file **lower_file,
                             struct dentry *lower_dentry,
                             struct vfsmount *lower_mnt,
                             const struct cred *cred);
-int ecryptfs_get_lower_file(struct dentry *ecryptfs_dentry);
+int ecryptfs_get_lower_file(struct dentry *dentry, struct inode *inode);
 void ecryptfs_put_lower_file(struct inode *inode);
 int
 ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
index 566e5472f78c3d6dae8e5008689eef281cba37ab..4ec9eb00a241fb56adcec03587d8b3c8ae506d40 100644 (file)
@@ -191,7 +191,7 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
                                      | ECRYPTFS_ENCRYPTED);
        }
        mutex_unlock(&crypt_stat->cs_mutex);
-       rc = ecryptfs_get_lower_file(ecryptfs_dentry);
+       rc = ecryptfs_get_lower_file(ecryptfs_dentry, inode);
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to initialize "
                        "the lower file for the dentry with name "
index 4d4cc6a90cd57f18b330674f8e5320205cc2a5e6..7349ade17de671cabadaeb9e90ec1bdaca28e55b 100644 (file)
@@ -51,6 +51,97 @@ static void unlock_dir(struct dentry *dir)
        dput(dir);
 }
 
+static int ecryptfs_inode_test(struct inode *inode, void *lower_inode)
+{
+       if (ecryptfs_inode_to_lower(inode) == (struct inode *)lower_inode)
+               return 1;
+       return 0;
+}
+
+static int ecryptfs_inode_set(struct inode *inode, void *opaque)
+{
+       struct inode *lower_inode = opaque;
+
+       ecryptfs_set_inode_lower(inode, lower_inode);
+       fsstack_copy_attr_all(inode, lower_inode);
+       /* i_size will be overwritten for encrypted regular files */
+       fsstack_copy_inode_size(inode, lower_inode);
+       inode->i_ino = lower_inode->i_ino;
+       inode->i_version++;
+       inode->i_mapping->a_ops = &ecryptfs_aops;
+
+       if (S_ISLNK(inode->i_mode))
+               inode->i_op = &ecryptfs_symlink_iops;
+       else if (S_ISDIR(inode->i_mode))
+               inode->i_op = &ecryptfs_dir_iops;
+       else
+               inode->i_op = &ecryptfs_main_iops;
+
+       if (S_ISDIR(inode->i_mode))
+               inode->i_fop = &ecryptfs_dir_fops;
+       else if (special_file(inode->i_mode))
+               init_special_inode(inode, inode->i_mode, inode->i_rdev);
+       else
+               inode->i_fop = &ecryptfs_main_fops;
+
+       return 0;
+}
+
+static struct inode *__ecryptfs_get_inode(struct inode *lower_inode,
+                                         struct super_block *sb)
+{
+       struct inode *inode;
+
+       if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb))
+               return ERR_PTR(-EXDEV);
+       if (!igrab(lower_inode))
+               return ERR_PTR(-ESTALE);
+       inode = iget5_locked(sb, (unsigned long)lower_inode,
+                            ecryptfs_inode_test, ecryptfs_inode_set,
+                            lower_inode);
+       if (!inode) {
+               iput(lower_inode);
+               return ERR_PTR(-EACCES);
+       }
+       if (!(inode->i_state & I_NEW))
+               iput(lower_inode);
+
+       return inode;
+}
+
+struct inode *ecryptfs_get_inode(struct inode *lower_inode,
+                                struct super_block *sb)
+{
+       struct inode *inode = __ecryptfs_get_inode(lower_inode, sb);
+
+       if (!IS_ERR(inode) && (inode->i_state & I_NEW))
+               unlock_new_inode(inode);
+
+       return inode;
+}
+
+/**
+ * ecryptfs_interpose
+ * @lower_dentry: Existing dentry in the lower filesystem
+ * @dentry: ecryptfs' dentry
+ * @sb: ecryptfs's super_block
+ *
+ * Interposes upper and lower dentries.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_interpose(struct dentry *lower_dentry,
+                             struct dentry *dentry, struct super_block *sb)
+{
+       struct inode *inode = ecryptfs_get_inode(lower_dentry->d_inode, sb);
+
+       if (IS_ERR(inode))
+               return PTR_ERR(inode);
+       d_instantiate(dentry, inode);
+
+       return 0;
+}
+
 /**
  * ecryptfs_create_underlying_file
  * @lower_dir_inode: inode of the parent in the lower fs of the new file
@@ -129,7 +220,7 @@ ecryptfs_do_create(struct inode *directory_inode,
                goto out_lock;
        }
        rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry,
-                               directory_inode->i_sb, 0);
+                               directory_inode->i_sb);
        if (rc) {
                ecryptfs_printk(KERN_ERR, "Failure in ecryptfs_interpose\n");
                goto out_lock;
@@ -168,7 +259,8 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry)
                                "context; rc = [%d]\n", rc);
                goto out;
        }
-       rc = ecryptfs_get_lower_file(ecryptfs_dentry);
+       rc = ecryptfs_get_lower_file(ecryptfs_dentry,
+                                    ecryptfs_dentry->d_inode);
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to initialize "
                        "the lower file for the dentry with name "
@@ -215,102 +307,90 @@ out:
        return rc;
 }
 
+static int ecryptfs_i_size_read(struct dentry *dentry, struct inode *inode)
+{
+       struct ecryptfs_crypt_stat *crypt_stat;
+       int rc;
+
+       rc = ecryptfs_get_lower_file(dentry, inode);
+       if (rc) {
+               printk(KERN_ERR "%s: Error attempting to initialize "
+                       "the lower file for the dentry with name "
+                       "[%s]; rc = [%d]\n", __func__,
+                       dentry->d_name.name, rc);
+               return rc;
+       }
+
+       crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
+       /* TODO: lock for crypt_stat comparison */
+       if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED))
+               ecryptfs_set_default_sizes(crypt_stat);
+
+       rc = ecryptfs_read_and_validate_header_region(inode);
+       ecryptfs_put_lower_file(inode);
+       if (rc) {
+               rc = ecryptfs_read_and_validate_xattr_region(dentry, inode);
+               if (!rc)
+                       crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR;
+       }
+
+       /* Must return 0 to allow non-eCryptfs files to be looked up, too */
+       return 0;
+}
+
 /**
- * ecryptfs_lookup_and_interpose_lower - Perform a lookup
+ * ecryptfs_lookup_interpose - Dentry interposition for a lookup
  */
-int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
-                                       struct dentry *lower_dentry,
-                                       struct inode *ecryptfs_dir_inode)
+static int ecryptfs_lookup_interpose(struct dentry *dentry,
+                                    struct dentry *lower_dentry,
+                                    struct inode *dir_inode)
 {
-       struct dentry *lower_dir_dentry;
+       struct inode *inode, *lower_inode = lower_dentry->d_inode;
+       struct ecryptfs_dentry_info *dentry_info;
        struct vfsmount *lower_mnt;
-       struct inode *lower_inode;
-       struct ecryptfs_crypt_stat *crypt_stat;
-       char *page_virt = NULL;
-       int put_lower = 0, rc = 0;
-
-       lower_dir_dentry = lower_dentry->d_parent;
-       lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(
-                                  ecryptfs_dentry->d_parent));
-       lower_inode = lower_dentry->d_inode;
-       fsstack_copy_attr_atime(ecryptfs_dir_inode, lower_dir_dentry->d_inode);
+       int rc = 0;
+
+       lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent));
+       fsstack_copy_attr_atime(dir_inode, lower_dentry->d_parent->d_inode);
        BUG_ON(!lower_dentry->d_count);
-       ecryptfs_set_dentry_private(ecryptfs_dentry,
-                                   kmem_cache_alloc(ecryptfs_dentry_info_cache,
-                                                    GFP_KERNEL));
-       if (!ecryptfs_dentry_to_private(ecryptfs_dentry)) {
-               rc = -ENOMEM;
+
+       dentry_info = kmem_cache_alloc(ecryptfs_dentry_info_cache, GFP_KERNEL);
+       ecryptfs_set_dentry_private(dentry, dentry_info);
+       if (!dentry_info) {
                printk(KERN_ERR "%s: Out of memory whilst attempting "
                       "to allocate ecryptfs_dentry_info struct\n",
                        __func__);
-               goto out_put;
+               dput(lower_dentry);
+               mntput(lower_mnt);
+               d_drop(dentry);
+               return -ENOMEM;
        }
-       ecryptfs_set_dentry_lower(ecryptfs_dentry, lower_dentry);
-       ecryptfs_set_dentry_lower_mnt(ecryptfs_dentry, lower_mnt);
+       ecryptfs_set_dentry_lower(dentry, lower_dentry);
+       ecryptfs_set_dentry_lower_mnt(dentry, lower_mnt);
+
        if (!lower_dentry->d_inode) {
                /* We want to add because we couldn't find in lower */
-               d_add(ecryptfs_dentry, NULL);
-               goto out;
+               d_add(dentry, NULL);
+               return 0;
        }
-       rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry,
-                               ecryptfs_dir_inode->i_sb,
-                               ECRYPTFS_INTERPOSE_FLAG_D_ADD);
-       if (rc) {
-               printk(KERN_ERR "%s: Error interposing; rc = [%d]\n",
-                      __func__, rc);
-               goto out;
+       inode = __ecryptfs_get_inode(lower_inode, dir_inode->i_sb);
+       if (IS_ERR(inode)) {
+               printk(KERN_ERR "%s: Error interposing; rc = [%ld]\n",
+                      __func__, PTR_ERR(inode));
+               return PTR_ERR(inode);
        }
-       if (S_ISDIR(lower_inode->i_mode))
-               goto out;
-       if (S_ISLNK(lower_inode->i_mode))
-               goto out;
-       if (special_file(lower_inode->i_mode))
-               goto out;
-       /* Released in this function */
-       page_virt = kmem_cache_zalloc(ecryptfs_header_cache_2, GFP_USER);
-       if (!page_virt) {
-               printk(KERN_ERR "%s: Cannot kmem_cache_zalloc() a page\n",
-                      __func__);
-               rc = -ENOMEM;
-               goto out;
-       }
-       rc = ecryptfs_get_lower_file(ecryptfs_dentry);
-       if (rc) {
-               printk(KERN_ERR "%s: Error attempting to initialize "
-                       "the lower file for the dentry with name "
-                       "[%s]; rc = [%d]\n", __func__,
-                       ecryptfs_dentry->d_name.name, rc);
-               goto out_free_kmem;
-       }
-       put_lower = 1;
-       crypt_stat = &ecryptfs_inode_to_private(
-                                       ecryptfs_dentry->d_inode)->crypt_stat;
-       /* TODO: lock for crypt_stat comparison */
-       if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED))
-                       ecryptfs_set_default_sizes(crypt_stat);
-       rc = ecryptfs_read_and_validate_header_region(page_virt,
-                                                     ecryptfs_dentry->d_inode);
-       if (rc) {
-               memset(page_virt, 0, PAGE_CACHE_SIZE);
-               rc = ecryptfs_read_and_validate_xattr_region(page_virt,
-                                                            ecryptfs_dentry);
+       if (S_ISREG(inode->i_mode)) {
+               rc = ecryptfs_i_size_read(dentry, inode);
                if (rc) {
-                       rc = 0;
-                       goto out_free_kmem;
+                       make_bad_inode(inode);
+                       return rc;
                }
-               crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR;
        }
-       ecryptfs_i_size_init(page_virt, ecryptfs_dentry->d_inode);
-out_free_kmem:
-       kmem_cache_free(ecryptfs_header_cache_2, page_virt);
-       goto out;
-out_put:
-       dput(lower_dentry);
-       mntput(lower_mnt);
-       d_drop(ecryptfs_dentry);
-out:
-       if (put_lower)
-               ecryptfs_put_lower_file(ecryptfs_dentry->d_inode);
+
+       if (inode->i_state & I_NEW)
+               unlock_new_inode(inode);
+       d_add(dentry, inode);
+
        return rc;
 }
 
@@ -353,12 +433,12 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
                goto out_d_drop;
        }
        if (lower_dentry->d_inode)
-               goto lookup_and_interpose;
+               goto interpose;
        mount_crypt_stat = &ecryptfs_superblock_to_private(
                                ecryptfs_dentry->d_sb)->mount_crypt_stat;
        if (!(mount_crypt_stat
            && (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)))
-               goto lookup_and_interpose;
+               goto interpose;
        dput(lower_dentry);
        rc = ecryptfs_encrypt_and_encode_filename(
                &encrypted_and_encoded_name, &encrypted_and_encoded_name_size,
@@ -381,9 +461,9 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
                                encrypted_and_encoded_name);
                goto out_d_drop;
        }
-lookup_and_interpose:
-       rc = ecryptfs_lookup_and_interpose_lower(ecryptfs_dentry, lower_dentry,
-                                                ecryptfs_dir_inode);
+interpose:
+       rc = ecryptfs_lookup_interpose(ecryptfs_dentry, lower_dentry,
+                                      ecryptfs_dir_inode);
        goto out;
 out_d_drop:
        d_drop(ecryptfs_dentry);
@@ -411,7 +491,7 @@ static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,
                      lower_new_dentry);
        if (rc || !lower_new_dentry->d_inode)
                goto out_lock;
-       rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0);
+       rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb);
        if (rc)
                goto out_lock;
        fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
@@ -478,7 +558,7 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
        kfree(encoded_symname);
        if (rc || !lower_dentry->d_inode)
                goto out_lock;
-       rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
+       rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
        if (rc)
                goto out_lock;
        fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
@@ -502,7 +582,7 @@ static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, mode);
        if (rc || !lower_dentry->d_inode)
                goto out;
-       rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
+       rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
        if (rc)
                goto out;
        fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
@@ -527,6 +607,8 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
        dget(lower_dentry);
        rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
        dput(lower_dentry);
+       if (!rc && dentry->d_inode)
+               clear_nlink(dentry->d_inode);
        fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
        dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
        unlock_dir(lower_dir_dentry);
@@ -548,7 +630,7 @@ ecryptfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
        rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, mode, dev);
        if (rc || !lower_dentry->d_inode)
                goto out;
-       rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
+       rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
        if (rc)
                goto out;
        fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
@@ -748,7 +830,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
                lower_ia->ia_valid &= ~ATTR_SIZE;
                return 0;
        }
-       rc = ecryptfs_get_lower_file(dentry);
+       rc = ecryptfs_get_lower_file(dentry, inode);
        if (rc)
                return rc;
        crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
@@ -904,7 +986,7 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
 
                mount_crypt_stat = &ecryptfs_superblock_to_private(
                        dentry->d_sb)->mount_crypt_stat;
-               rc = ecryptfs_get_lower_file(dentry);
+               rc = ecryptfs_get_lower_file(dentry, inode);
                if (rc) {
                        mutex_unlock(&crypt_stat->cs_mutex);
                        goto out;
@@ -1077,21 +1159,6 @@ out:
        return rc;
 }
 
-int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode)
-{
-       if ((ecryptfs_inode_to_lower(inode)
-            == (struct inode *)candidate_lower_inode))
-               return 1;
-       else
-               return 0;
-}
-
-int ecryptfs_inode_set(struct inode *inode, void *lower_inode)
-{
-       ecryptfs_init_inode(inode, (struct inode *)lower_inode);
-       return 0;
-}
-
 const struct inode_operations ecryptfs_symlink_iops = {
        .readlink = ecryptfs_readlink,
        .follow_link = ecryptfs_follow_link,
index 03e609c450120674673a5a6e07460b2014751ed0..27a7fefb83eb07f04d092416654b3b3f4142e55d 100644 (file)
@@ -599,8 +599,8 @@ struct ecryptfs_write_tag_70_packet_silly_stack {
        struct mutex *tfm_mutex;
        char *block_aligned_filename;
        struct ecryptfs_auth_tok *auth_tok;
-       struct scatterlist src_sg;
-       struct scatterlist dst_sg;
+       struct scatterlist src_sg[2];
+       struct scatterlist dst_sg[2];
        struct blkcipher_desc desc;
        char iv[ECRYPTFS_MAX_IV_BYTES];
        char hash[ECRYPTFS_TAG_70_DIGEST_SIZE];
@@ -816,23 +816,21 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
        memcpy(&s->block_aligned_filename[s->num_rand_bytes], filename,
               filename_size);
        rc = virt_to_scatterlist(s->block_aligned_filename,
-                                s->block_aligned_filename_size, &s->src_sg, 1);
-       if (rc != 1) {
+                                s->block_aligned_filename_size, s->src_sg, 2);
+       if (rc < 1) {
                printk(KERN_ERR "%s: Internal error whilst attempting to "
-                      "convert filename memory to scatterlist; "
-                      "expected rc = 1; got rc = [%d]. "
+                      "convert filename memory to scatterlist; rc = [%d]. "
                       "block_aligned_filename_size = [%zd]\n", __func__, rc,
                       s->block_aligned_filename_size);
                goto out_release_free_unlock;
        }
        rc = virt_to_scatterlist(&dest[s->i], s->block_aligned_filename_size,
-                                &s->dst_sg, 1);
-       if (rc != 1) {
+                                s->dst_sg, 2);
+       if (rc < 1) {
                printk(KERN_ERR "%s: Internal error whilst attempting to "
                       "convert encrypted filename memory to scatterlist; "
-                      "expected rc = 1; got rc = [%d]. "
-                      "block_aligned_filename_size = [%zd]\n", __func__, rc,
-                      s->block_aligned_filename_size);
+                      "rc = [%d]. block_aligned_filename_size = [%zd]\n",
+                      __func__, rc, s->block_aligned_filename_size);
                goto out_release_free_unlock;
        }
        /* The characters in the first block effectively do the job
@@ -855,7 +853,7 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
                       mount_crypt_stat->global_default_fn_cipher_key_bytes);
                goto out_release_free_unlock;
        }
-       rc = crypto_blkcipher_encrypt_iv(&s->desc, &s->dst_sg, &s->src_sg,
+       rc = crypto_blkcipher_encrypt_iv(&s->desc, s->dst_sg, s->src_sg,
                                         s->block_aligned_filename_size);
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to encrypt filename; "
@@ -891,8 +889,8 @@ struct ecryptfs_parse_tag_70_packet_silly_stack {
        struct mutex *tfm_mutex;
        char *decrypted_filename;
        struct ecryptfs_auth_tok *auth_tok;
-       struct scatterlist src_sg;
-       struct scatterlist dst_sg;
+       struct scatterlist src_sg[2];
+       struct scatterlist dst_sg[2];
        struct blkcipher_desc desc;
        char fnek_sig_hex[ECRYPTFS_SIG_SIZE_HEX + 1];
        char iv[ECRYPTFS_MAX_IV_BYTES];
@@ -1008,13 +1006,12 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,
        }
        mutex_lock(s->tfm_mutex);
        rc = virt_to_scatterlist(&data[(*packet_size)],
-                                s->block_aligned_filename_size, &s->src_sg, 1);
-       if (rc != 1) {
+                                s->block_aligned_filename_size, s->src_sg, 2);
+       if (rc < 1) {
                printk(KERN_ERR "%s: Internal error whilst attempting to "
                       "convert encrypted filename memory to scatterlist; "
-                      "expected rc = 1; got rc = [%d]. "
-                      "block_aligned_filename_size = [%zd]\n", __func__, rc,
-                      s->block_aligned_filename_size);
+                      "rc = [%d]. block_aligned_filename_size = [%zd]\n",
+                      __func__, rc, s->block_aligned_filename_size);
                goto out_unlock;
        }
        (*packet_size) += s->block_aligned_filename_size;
@@ -1028,13 +1025,12 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,
                goto out_unlock;
        }
        rc = virt_to_scatterlist(s->decrypted_filename,
-                                s->block_aligned_filename_size, &s->dst_sg, 1);
-       if (rc != 1) {
+                                s->block_aligned_filename_size, s->dst_sg, 2);
+       if (rc < 1) {
                printk(KERN_ERR "%s: Internal error whilst attempting to "
                       "convert decrypted filename memory to scatterlist; "
-                      "expected rc = 1; got rc = [%d]. "
-                      "block_aligned_filename_size = [%zd]\n", __func__, rc,
-                      s->block_aligned_filename_size);
+                      "rc = [%d]. block_aligned_filename_size = [%zd]\n",
+                      __func__, rc, s->block_aligned_filename_size);
                goto out_free_unlock;
        }
        /* The characters in the first block effectively do the job of
@@ -1065,7 +1061,7 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,
                       mount_crypt_stat->global_default_fn_cipher_key_bytes);
                goto out_free_unlock;
        }
-       rc = crypto_blkcipher_decrypt_iv(&s->desc, &s->dst_sg, &s->src_sg,
+       rc = crypto_blkcipher_decrypt_iv(&s->desc, s->dst_sg, s->src_sg,
                                         s->block_aligned_filename_size);
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to decrypt filename; "
index 89b93389af8ee0a69b44cbfe709f4f766156a6c0..9f1bb747d77dd17bbcc907b3e249f3865cf4d31e 100644 (file)
@@ -135,12 +135,12 @@ static int ecryptfs_init_lower_file(struct dentry *dentry,
        return rc;
 }
 
-int ecryptfs_get_lower_file(struct dentry *dentry)
+int ecryptfs_get_lower_file(struct dentry *dentry, struct inode *inode)
 {
-       struct ecryptfs_inode_info *inode_info =
-               ecryptfs_inode_to_private(dentry->d_inode);
+       struct ecryptfs_inode_info *inode_info;
        int count, rc = 0;
 
+       inode_info = ecryptfs_inode_to_private(inode);
        mutex_lock(&inode_info->lower_file_mutex);
        count = atomic_inc_return(&inode_info->lower_file_count);
        if (WARN_ON_ONCE(count < 1))
@@ -168,75 +168,6 @@ void ecryptfs_put_lower_file(struct inode *inode)
        }
 }
 
-static struct inode *ecryptfs_get_inode(struct inode *lower_inode,
-                      struct super_block *sb)
-{
-       struct inode *inode;
-       int rc = 0;
-
-       if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb)) {
-               rc = -EXDEV;
-               goto out;
-       }
-       if (!igrab(lower_inode)) {
-               rc = -ESTALE;
-               goto out;
-       }
-       inode = iget5_locked(sb, (unsigned long)lower_inode,
-                            ecryptfs_inode_test, ecryptfs_inode_set,
-                            lower_inode);
-       if (!inode) {
-               rc = -EACCES;
-               iput(lower_inode);
-               goto out;
-       }
-       if (inode->i_state & I_NEW)
-               unlock_new_inode(inode);
-       else
-               iput(lower_inode);
-       if (S_ISLNK(lower_inode->i_mode))
-               inode->i_op = &ecryptfs_symlink_iops;
-       else if (S_ISDIR(lower_inode->i_mode))
-               inode->i_op = &ecryptfs_dir_iops;
-       if (S_ISDIR(lower_inode->i_mode))
-               inode->i_fop = &ecryptfs_dir_fops;
-       if (special_file(lower_inode->i_mode))
-               init_special_inode(inode, lower_inode->i_mode,
-                                  lower_inode->i_rdev);
-       fsstack_copy_attr_all(inode, lower_inode);
-       /* This size will be overwritten for real files w/ headers and
-        * other metadata */
-       fsstack_copy_inode_size(inode, lower_inode);
-       return inode;
-out:
-       return ERR_PTR(rc);
-}
-
-/**
- * ecryptfs_interpose
- * @lower_dentry: Existing dentry in the lower filesystem
- * @dentry: ecryptfs' dentry
- * @sb: ecryptfs's super_block
- * @flags: flags to govern behavior of interpose procedure
- *
- * Interposes upper and lower dentries.
- *
- * Returns zero on success; non-zero otherwise
- */
-int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry,
-                      struct super_block *sb, u32 flags)
-{
-       struct inode *lower_inode = lower_dentry->d_inode;
-       struct inode *inode = ecryptfs_get_inode(lower_inode, sb);
-       if (IS_ERR(inode))
-               return PTR_ERR(inode);
-       if (flags & ECRYPTFS_INTERPOSE_FLAG_D_ADD)
-               d_add(dentry, inode);
-       else
-               d_instantiate(dentry, inode);
-       return 0;
-}
-
 enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig,
        ecryptfs_opt_cipher, ecryptfs_opt_ecryptfs_cipher,
        ecryptfs_opt_ecryptfs_key_bytes,
@@ -704,13 +635,8 @@ static struct ecryptfs_cache_info {
                .size = sizeof(struct ecryptfs_sb_info),
        },
        {
-               .cache = &ecryptfs_header_cache_1,
-               .name = "ecryptfs_headers_1",
-               .size = PAGE_CACHE_SIZE,
-       },
-       {
-               .cache = &ecryptfs_header_cache_2,
-               .name = "ecryptfs_headers_2",
+               .cache = &ecryptfs_header_cache,
+               .name = "ecryptfs_headers",
                .size = PAGE_CACHE_SIZE,
        },
        {
index 245b517bf1b65ec5dc5dfa294891e40038d201d7..dbd52d40df4c4c94100d650db5097e0567dad3d3 100644 (file)
@@ -92,22 +92,6 @@ static void ecryptfs_destroy_inode(struct inode *inode)
        call_rcu(&inode->i_rcu, ecryptfs_i_callback);
 }
 
-/**
- * ecryptfs_init_inode
- * @inode: The ecryptfs inode
- *
- * Set up the ecryptfs inode.
- */
-void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode)
-{
-       ecryptfs_set_inode_lower(inode, lower_inode);
-       inode->i_ino = lower_inode->i_ino;
-       inode->i_version++;
-       inode->i_op = &ecryptfs_main_iops;
-       inode->i_fop = &ecryptfs_main_fops;
-       inode->i_mapping->a_ops = &ecryptfs_aops;
-}
-
 /**
  * ecryptfs_statfs
  * @sb: The ecryptfs super block
index c1cf372f17a7fdb5bb0d7dc89f1ae8ccf5964638..6075a1e727aee13dd3cd492b61d55edd81ee258e 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -42,7 +42,6 @@
 #include <linux/pid_namespace.h>
 #include <linux/module.h>
 #include <linux/namei.h>
-#include <linux/proc_fs.h>
 #include <linux/mount.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
@@ -200,7 +199,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
 
 #ifdef CONFIG_STACK_GROWSUP
        if (write) {
-               ret = expand_stack_downwards(bprm->vma, pos);
+               ret = expand_downwards(bprm->vma, pos);
                if (ret < 0)
                        return NULL;
        }
@@ -600,7 +599,7 @@ static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift)
        unsigned long length = old_end - old_start;
        unsigned long new_start = old_start - shift;
        unsigned long new_end = old_end - shift;
-       struct mmu_gather *tlb;
+       struct mmu_gather tlb;
 
        BUG_ON(new_start > new_end);
 
@@ -626,12 +625,12 @@ static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift)
                return -ENOMEM;
 
        lru_add_drain();
-       tlb = tlb_gather_mmu(mm, 0);
+       tlb_gather_mmu(&tlb, mm, 0);
        if (new_end > old_start) {
                /*
                 * when the old and new regions overlap clear from new_end.
                 */
-               free_pgd_range(tlb, new_end, old_end, new_end,
+               free_pgd_range(&tlb, new_end, old_end, new_end,
                        vma->vm_next ? vma->vm_next->vm_start : 0);
        } else {
                /*
@@ -640,10 +639,10 @@ static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift)
                 * have constraints on va-space that make this illegal (IA64) -
                 * for the others its just a little faster.
                 */
-               free_pgd_range(tlb, old_start, old_end, new_end,
+               free_pgd_range(&tlb, old_start, old_end, new_end,
                        vma->vm_next ? vma->vm_next->vm_start : 0);
        }
-       tlb_finish_mmu(tlb, new_end, old_end);
+       tlb_finish_mmu(&tlb, new_end, old_end);
 
        /*
         * Shrink the vma to just the new range.  Always succeeds.
@@ -1094,6 +1093,7 @@ int flush_old_exec(struct linux_binprm * bprm)
 
        bprm->mm = NULL;                /* We're using it now */
 
+       set_fs(USER_DS);
        current->flags &= ~(PF_RANDOMIZE | PF_KTHREAD);
        flush_thread();
        current->personality &= ~bprm->per_clear;
@@ -1358,10 +1358,6 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
        if (retval)
                return retval;
 
-       /* kernel module loader fixup */
-       /* so we don't try to load run modprobe in kernel space. */
-       set_fs(USER_DS);
-
        retval = audit_bprm(bprm);
        if (retval)
                return retval;
@@ -1624,6 +1620,41 @@ expand_fail:
        return ret;
 }
 
+static int cn_print_exe_file(struct core_name *cn)
+{
+       struct file *exe_file;
+       char *pathbuf, *path, *p;
+       int ret;
+
+       exe_file = get_mm_exe_file(current->mm);
+       if (!exe_file)
+               return cn_printf(cn, "(unknown)");
+
+       pathbuf = kmalloc(PATH_MAX, GFP_TEMPORARY);
+       if (!pathbuf) {
+               ret = -ENOMEM;
+               goto put_exe_file;
+       }
+
+       path = d_path(&exe_file->f_path, pathbuf, PATH_MAX);
+       if (IS_ERR(path)) {
+               ret = PTR_ERR(path);
+               goto free_buf;
+       }
+
+       for (p = path; *p; p++)
+               if (*p == '/')
+                       *p = '!';
+
+       ret = cn_printf(cn, "%s", path);
+
+free_buf:
+       kfree(pathbuf);
+put_exe_file:
+       fput(exe_file);
+       return ret;
+}
+
 /* format_corename will inspect the pattern parameter, and output a
  * name into corename, which must have space for at least
  * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator.
@@ -1695,6 +1726,9 @@ static int format_corename(struct core_name *cn, long signr)
                        case 'e':
                                err = cn_printf(cn, "%s", current->comm);
                                break;
+                       case 'E':
+                               err = cn_print_exe_file(cn);
+                               break;
                        /* core limit size */
                        case 'c':
                                err = cn_printf(cn, "%lu",
@@ -1962,7 +1996,7 @@ static void wait_for_dump_helpers(struct file *file)
  * is a special value that we use to trap recursive
  * core dumps
  */
-static int umh_pipe_setup(struct subprocess_info *info)
+static int umh_pipe_setup(struct subprocess_info *info, struct cred *new)
 {
        struct file *rp, *wp;
        struct fdtable *fdt;
index 0a78dae7e2cbbaea9f76045c7db6fe90426e278e..1dd62ed35b8511efece6cd6733eb960185f9ec28 100644 (file)
@@ -898,7 +898,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
                brelse(bh);
 
                if (!sb_set_blocksize(sb, blocksize)) {
-                       ext2_msg(sb, KERN_ERR, "error: blocksize is too small");
+                       ext2_msg(sb, KERN_ERR,
+                               "error: bad blocksize %d", blocksize);
                        goto failed_sbi;
                }
 
index 68b2e43d7c35fec1576cf7bd5d3136332720ad8e..3451d23c3bae3eedd75d8504694a22735e7dc291 100644 (file)
@@ -3392,7 +3392,7 @@ int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode)
  * so would cause a commit on atime updates, which we don't bother doing.
  * We handle synchronous inodes at the highest possible level.
  */
-void ext3_dirty_inode(struct inode *inode)
+void ext3_dirty_inode(struct inode *inode, int flags)
 {
        handle_t *current_handle = ext3_journal_current_handle();
        handle_t *handle;
index 32f3b869585927400a035259c0fee27e312b39c8..34b6d9bfc48a511de1a4e52bbb778cdd10a519b6 100644 (file)
@@ -1416,10 +1416,19 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
        frame->at = entries;
        frame->bh = bh;
        bh = bh2;
+       /*
+        * Mark buffers dirty here so that if do_split() fails we write a
+        * consistent set of buffers to disk.
+        */
+       ext3_journal_dirty_metadata(handle, frame->bh);
+       ext3_journal_dirty_metadata(handle, bh);
        de = do_split(handle,dir, &bh, frame, &hinfo, &retval);
-       dx_release (frames);
-       if (!(de))
+       if (!de) {
+               ext3_mark_inode_dirty(handle, dir);
+               dx_release(frames);
                return retval;
+       }
+       dx_release(frames);
 
        return add_dirent_to_buf(handle, dentry, inode, de, bh);
 }
@@ -2189,6 +2198,7 @@ static int ext3_symlink (struct inode * dir,
        handle_t *handle;
        struct inode * inode;
        int l, err, retries = 0;
+       int credits;
 
        l = strlen(symname)+1;
        if (l > dir->i_sb->s_blocksize)
@@ -2196,10 +2206,26 @@ static int ext3_symlink (struct inode * dir,
 
        dquot_initialize(dir);
 
+       if (l > EXT3_N_BLOCKS * 4) {
+               /*
+                * For non-fast symlinks, we just allocate inode and put it on
+                * orphan list in the first transaction => we need bitmap,
+                * group descriptor, sb, inode block, quota blocks.
+                */
+               credits = 4 + EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
+       } else {
+               /*
+                * Fast symlink. We have to add entry to directory
+                * (EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS),
+                * allocate new inode (bitmap, group descriptor, inode block,
+                * quota blocks, sb is already counted in previous macros).
+                */
+               credits = EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
+                         EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
+                         EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
+       }
 retry:
-       handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
-                                       EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 +
-                                       EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb));
+       handle = ext3_journal_start(dir, credits);
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -2211,21 +2237,45 @@ retry:
        if (IS_ERR(inode))
                goto out_stop;
 
-       if (l > sizeof (EXT3_I(inode)->i_data)) {
+       if (l > EXT3_N_BLOCKS * 4) {
                inode->i_op = &ext3_symlink_inode_operations;
                ext3_set_aops(inode);
                /*
-                * page_symlink() calls into ext3_prepare/commit_write.
-                * We have a transaction open.  All is sweetness.  It also sets
-                * i_size in generic_commit_write().
+                * We cannot call page_symlink() with transaction started
+                * because it calls into ext3_write_begin() which acquires page
+                * lock which ranks below transaction start (and it can also
+                * wait for journal commit if we are running out of space). So
+                * we have to stop transaction now and restart it when symlink
+                * contents is written. 
+                *
+                * To keep fs consistent in case of crash, we have to put inode
+                * to orphan list in the mean time.
                 */
+               drop_nlink(inode);
+               err = ext3_orphan_add(handle, inode);
+               ext3_journal_stop(handle);
+               if (err)
+                       goto err_drop_inode;
                err = __page_symlink(inode, symname, l, 1);
+               if (err)
+                       goto err_drop_inode;
+               /*
+                * Now inode is being linked into dir (EXT3_DATA_TRANS_BLOCKS
+                * + EXT3_INDEX_EXTRA_TRANS_BLOCKS), inode is also modified
+                */
+               handle = ext3_journal_start(dir,
+                               EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
+                               EXT3_INDEX_EXTRA_TRANS_BLOCKS + 1);
+               if (IS_ERR(handle)) {
+                       err = PTR_ERR(handle);
+                       goto err_drop_inode;
+               }
+               inc_nlink(inode);
+               err = ext3_orphan_del(handle, inode);
                if (err) {
+                       ext3_journal_stop(handle);
                        drop_nlink(inode);
-                       unlock_new_inode(inode);
-                       ext3_mark_inode_dirty(handle, inode);
-                       iput (inode);
-                       goto out_stop;
+                       goto err_drop_inode;
                }
        } else {
                inode->i_op = &ext3_fast_symlink_inode_operations;
@@ -2239,6 +2289,10 @@ out_stop:
        if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
                goto retry;
        return err;
+err_drop_inode:
+       unlock_new_inode(inode);
+       iput(inode);
+       return err;
 }
 
 static int ext3_link (struct dentry * old_dentry,
index 3c6a9e0eadc18214b45686e175f0a474f638b23e..aad153ef6b783a6820e9f38e60d61d6cbea2c8eb 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/quotaops.h>
 #include <linux/seq_file.h>
 #include <linux/log2.h>
+#include <linux/cleancache.h>
 
 #include <asm/uaccess.h>
 
@@ -1367,6 +1368,7 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es,
        } else {
                ext3_msg(sb, KERN_INFO, "using internal journal");
        }
+       cleancache_init_fs(sb);
        return res;
 }
 
index c947e36eda6c9d568b0c00b28c778ac2216996d5..04109460ba9e3f22d0115f8cc8b16d4e9b13d3f6 100644 (file)
@@ -6,7 +6,8 @@ obj-$(CONFIG_EXT4_FS) += ext4.o
 
 ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \
                ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \
-               ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o
+               ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o \
+               mmp.o
 
 ext4-$(CONFIG_EXT4_FS_XATTR)           += xattr.o xattr_user.o xattr_trusted.o
 ext4-$(CONFIG_EXT4_FS_POSIX_ACL)       += acl.o
index 1c67139ad4b422119c76d10f384dad9eabdf9158..264f6949511ef842169438571049ccb736955531 100644 (file)
@@ -361,130 +361,6 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
        return bh;
 }
 
-/**
- * ext4_add_groupblocks() -- Add given blocks to an existing group
- * @handle:                    handle to this transaction
- * @sb:                                super block
- * @block:                     start physcial block to add to the block group
- * @count:                     number of blocks to free
- *
- * This marks the blocks as free in the bitmap. We ask the
- * mballoc to reload the buddy after this by setting group
- * EXT4_GROUP_INFO_NEED_INIT_BIT flag
- */
-void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
-                        ext4_fsblk_t block, unsigned long count)
-{
-       struct buffer_head *bitmap_bh = NULL;
-       struct buffer_head *gd_bh;
-       ext4_group_t block_group;
-       ext4_grpblk_t bit;
-       unsigned int i;
-       struct ext4_group_desc *desc;
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-       int err = 0, ret, blk_free_count;
-       ext4_grpblk_t blocks_freed;
-       struct ext4_group_info *grp;
-
-       ext4_debug("Adding block(s) %llu-%llu\n", block, block + count - 1);
-
-       ext4_get_group_no_and_offset(sb, block, &block_group, &bit);
-       grp = ext4_get_group_info(sb, block_group);
-       /*
-        * Check to see if we are freeing blocks across a group
-        * boundary.
-        */
-       if (bit + count > EXT4_BLOCKS_PER_GROUP(sb)) {
-               goto error_return;
-       }
-       bitmap_bh = ext4_read_block_bitmap(sb, block_group);
-       if (!bitmap_bh)
-               goto error_return;
-       desc = ext4_get_group_desc(sb, block_group, &gd_bh);
-       if (!desc)
-               goto error_return;
-
-       if (in_range(ext4_block_bitmap(sb, desc), block, count) ||
-           in_range(ext4_inode_bitmap(sb, desc), block, count) ||
-           in_range(block, ext4_inode_table(sb, desc), sbi->s_itb_per_group) ||
-           in_range(block + count - 1, ext4_inode_table(sb, desc),
-                    sbi->s_itb_per_group)) {
-               ext4_error(sb, "Adding blocks in system zones - "
-                          "Block = %llu, count = %lu",
-                          block, count);
-               goto error_return;
-       }
-
-       /*
-        * We are about to add blocks to the bitmap,
-        * so we need undo access.
-        */
-       BUFFER_TRACE(bitmap_bh, "getting undo access");
-       err = ext4_journal_get_undo_access(handle, bitmap_bh);
-       if (err)
-               goto error_return;
-
-       /*
-        * We are about to modify some metadata.  Call the journal APIs
-        * to unshare ->b_data if a currently-committing transaction is
-        * using it
-        */
-       BUFFER_TRACE(gd_bh, "get_write_access");
-       err = ext4_journal_get_write_access(handle, gd_bh);
-       if (err)
-               goto error_return;
-       /*
-        * make sure we don't allow a parallel init on other groups in the
-        * same buddy cache
-        */
-       down_write(&grp->alloc_sem);
-       for (i = 0, blocks_freed = 0; i < count; i++) {
-               BUFFER_TRACE(bitmap_bh, "clear bit");
-               if (!ext4_clear_bit_atomic(ext4_group_lock_ptr(sb, block_group),
-                                               bit + i, bitmap_bh->b_data)) {
-                       ext4_error(sb, "bit already cleared for block %llu",
-                                  (ext4_fsblk_t)(block + i));
-                       BUFFER_TRACE(bitmap_bh, "bit already cleared");
-               } else {
-                       blocks_freed++;
-               }
-       }
-       ext4_lock_group(sb, block_group);
-       blk_free_count = blocks_freed + ext4_free_blks_count(sb, desc);
-       ext4_free_blks_set(sb, desc, blk_free_count);
-       desc->bg_checksum = ext4_group_desc_csum(sbi, block_group, desc);
-       ext4_unlock_group(sb, block_group);
-       percpu_counter_add(&sbi->s_freeblocks_counter, blocks_freed);
-
-       if (sbi->s_log_groups_per_flex) {
-               ext4_group_t flex_group = ext4_flex_group(sbi, block_group);
-               atomic_add(blocks_freed,
-                          &sbi->s_flex_groups[flex_group].free_blocks);
-       }
-       /*
-        * request to reload the buddy with the
-        * new bitmap information
-        */
-       set_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &(grp->bb_state));
-       grp->bb_free += blocks_freed;
-       up_write(&grp->alloc_sem);
-
-       /* We dirtied the bitmap block */
-       BUFFER_TRACE(bitmap_bh, "dirtied bitmap block");
-       err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
-
-       /* And the group descriptor block */
-       BUFFER_TRACE(gd_bh, "dirtied group descriptor block");
-       ret = ext4_handle_dirty_metadata(handle, NULL, gd_bh);
-       if (!err)
-               err = ret;
-
-error_return:
-       brelse(bitmap_bh);
-       ext4_std_error(sb, err);
-       return;
-}
-
 /**
  * ext4_has_free_blocks()
  * @sbi:       in-core super block structure.
@@ -493,7 +369,8 @@ error_return:
  * Check if filesystem has nblocks free & available for allocation.
  * On success return 1, return 0 on failure.
  */
-static int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks)
+static int ext4_has_free_blocks(struct ext4_sb_info *sbi,
+                               s64 nblocks, unsigned int flags)
 {
        s64 free_blocks, dirty_blocks, root_blocks;
        struct percpu_counter *fbc = &sbi->s_freeblocks_counter;
@@ -507,11 +384,6 @@ static int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks)
                                                EXT4_FREEBLOCKS_WATERMARK) {
                free_blocks  = percpu_counter_sum_positive(fbc);
                dirty_blocks = percpu_counter_sum_positive(dbc);
-               if (dirty_blocks < 0) {
-                       printk(KERN_CRIT "Dirty block accounting "
-                                       "went wrong %lld\n",
-                                       (long long)dirty_blocks);
-               }
        }
        /* Check whether we have space after
         * accounting for current dirty blocks & root reserved blocks.
@@ -522,7 +394,9 @@ static int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks)
        /* Hm, nope.  Are (enough) root reserved blocks available? */
        if (sbi->s_resuid == current_fsuid() ||
            ((sbi->s_resgid != 0) && in_group_p(sbi->s_resgid)) ||
-           capable(CAP_SYS_RESOURCE)) {
+           capable(CAP_SYS_RESOURCE) ||
+               (flags & EXT4_MB_USE_ROOT_BLOCKS)) {
+
                if (free_blocks >= (nblocks + dirty_blocks))
                        return 1;
        }
@@ -531,9 +405,9 @@ static int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks)
 }
 
 int ext4_claim_free_blocks(struct ext4_sb_info *sbi,
-                                               s64 nblocks)
+                          s64 nblocks, unsigned int flags)
 {
-       if (ext4_has_free_blocks(sbi, nblocks)) {
+       if (ext4_has_free_blocks(sbi, nblocks, flags)) {
                percpu_counter_add(&sbi->s_dirtyblocks_counter, nblocks);
                return 0;
        } else
@@ -554,7 +428,7 @@ int ext4_claim_free_blocks(struct ext4_sb_info *sbi,
  */
 int ext4_should_retry_alloc(struct super_block *sb, int *retries)
 {
-       if (!ext4_has_free_blocks(EXT4_SB(sb), 1) ||
+       if (!ext4_has_free_blocks(EXT4_SB(sb), 1, 0) ||
            (*retries)++ > 3 ||
            !EXT4_SB(sb)->s_journal)
                return 0;
@@ -577,7 +451,8 @@ int ext4_should_retry_alloc(struct super_block *sb, int *retries)
  * error stores in errp pointer
  */
 ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode,
-               ext4_fsblk_t goal, unsigned long *count, int *errp)
+                                 ext4_fsblk_t goal, unsigned int flags,
+                                 unsigned long *count, int *errp)
 {
        struct ext4_allocation_request ar;
        ext4_fsblk_t ret;
@@ -587,6 +462,7 @@ ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode,
        ar.inode = inode;
        ar.goal = goal;
        ar.len = count ? *count : 1;
+       ar.flags = flags;
 
        ret = ext4_mb_new_blocks(handle, &ar, errp);
        if (count)
index 4daaf2b753f4fa037fd783ac34e47e15d1438b55..1921392cd7085d4b2679ea398979ec78d17d2099 100644 (file)
@@ -108,7 +108,8 @@ typedef unsigned int ext4_group_t;
 #define EXT4_MB_DELALLOC_RESERVED      0x0400
 /* We are doing stream allocation */
 #define EXT4_MB_STREAM_ALLOC           0x0800
-
+/* Use reserved root blocks if needed */
+#define EXT4_MB_USE_ROOT_BLOCKS                0x1000
 
 struct ext4_allocation_request {
        /* target inode for block we're allocating */
@@ -209,6 +210,8 @@ struct ext4_io_submit {
  */
 #define        EXT4_BAD_INO             1      /* Bad blocks inode */
 #define EXT4_ROOT_INO           2      /* Root inode */
+#define EXT4_USR_QUOTA_INO      3      /* User quota inode */
+#define EXT4_GRP_QUOTA_INO      4      /* Group quota inode */
 #define EXT4_BOOT_LOADER_INO    5      /* Boot loader inode */
 #define EXT4_UNDEL_DIR_INO      6      /* Undelete directory inode */
 #define EXT4_RESIZE_INO                 7      /* Reserved group descriptors inode */
@@ -512,6 +515,10 @@ struct ext4_new_group_data {
        /* Convert extent to initialized after IO complete */
 #define EXT4_GET_BLOCKS_IO_CONVERT_EXT         (EXT4_GET_BLOCKS_CONVERT|\
                                         EXT4_GET_BLOCKS_CREATE_UNINIT_EXT)
+       /* Punch out blocks of an extent */
+#define EXT4_GET_BLOCKS_PUNCH_OUT_EXT          0x0020
+       /* Don't normalize allocation size (used for fallocate) */
+#define EXT4_GET_BLOCKS_NO_NORMALIZE           0x0040
 
 /*
  * Flags used by ext4_free_blocks
@@ -1028,7 +1035,7 @@ struct ext4_super_block {
        __le16  s_want_extra_isize;     /* New inodes should reserve # bytes */
        __le32  s_flags;                /* Miscellaneous flags */
        __le16  s_raid_stride;          /* RAID stride */
-       __le16  s_mmp_interval;         /* # seconds to wait in MMP checking */
+       __le16  s_mmp_update_interval;  /* # seconds to wait in MMP checking */
        __le64  s_mmp_block;            /* Block for multi-mount protection */
        __le32  s_raid_stripe_width;    /* blocks on all data disks (N*stride)*/
        __u8    s_log_groups_per_flex;  /* FLEX_BG group size */
@@ -1144,6 +1151,9 @@ struct ext4_sb_info {
        unsigned long s_ext_blocks;
        unsigned long s_ext_extents;
 #endif
+       /* ext4 extent cache stats */
+       unsigned long extent_cache_hits;
+       unsigned long extent_cache_misses;
 
        /* for buddy allocator */
        struct ext4_group_info ***s_group_info;
@@ -1201,6 +1211,9 @@ struct ext4_sb_info {
        struct ext4_li_request *s_li_request;
        /* Wait multiplier for lazy initialization thread */
        unsigned int s_li_wait_mult;
+
+       /* Kernel thread for multiple mount protection */
+       struct task_struct *s_mmp_tsk;
 };
 
 static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
@@ -1338,6 +1351,7 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
 #define EXT4_FEATURE_RO_COMPAT_GDT_CSUM                0x0010
 #define EXT4_FEATURE_RO_COMPAT_DIR_NLINK       0x0020
 #define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE     0x0040
+#define EXT4_FEATURE_RO_COMPAT_QUOTA           0x0100
 
 #define EXT4_FEATURE_INCOMPAT_COMPRESSION      0x0001
 #define EXT4_FEATURE_INCOMPAT_FILETYPE         0x0002
@@ -1351,13 +1365,29 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
 #define EXT4_FEATURE_INCOMPAT_EA_INODE         0x0400 /* EA in inode */
 #define EXT4_FEATURE_INCOMPAT_DIRDATA          0x1000 /* data in dirent */
 
+#define EXT2_FEATURE_COMPAT_SUPP       EXT4_FEATURE_COMPAT_EXT_ATTR
+#define EXT2_FEATURE_INCOMPAT_SUPP     (EXT4_FEATURE_INCOMPAT_FILETYPE| \
+                                        EXT4_FEATURE_INCOMPAT_META_BG)
+#define EXT2_FEATURE_RO_COMPAT_SUPP    (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+                                        EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
+                                        EXT4_FEATURE_RO_COMPAT_BTREE_DIR)
+
+#define EXT3_FEATURE_COMPAT_SUPP       EXT4_FEATURE_COMPAT_EXT_ATTR
+#define EXT3_FEATURE_INCOMPAT_SUPP     (EXT4_FEATURE_INCOMPAT_FILETYPE| \
+                                        EXT4_FEATURE_INCOMPAT_RECOVER| \
+                                        EXT4_FEATURE_INCOMPAT_META_BG)
+#define EXT3_FEATURE_RO_COMPAT_SUPP    (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+                                        EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
+                                        EXT4_FEATURE_RO_COMPAT_BTREE_DIR)
+
 #define EXT4_FEATURE_COMPAT_SUPP       EXT2_FEATURE_COMPAT_EXT_ATTR
 #define EXT4_FEATURE_INCOMPAT_SUPP     (EXT4_FEATURE_INCOMPAT_FILETYPE| \
                                         EXT4_FEATURE_INCOMPAT_RECOVER| \
                                         EXT4_FEATURE_INCOMPAT_META_BG| \
                                         EXT4_FEATURE_INCOMPAT_EXTENTS| \
                                         EXT4_FEATURE_INCOMPAT_64BIT| \
-                                        EXT4_FEATURE_INCOMPAT_FLEX_BG)
+                                        EXT4_FEATURE_INCOMPAT_FLEX_BG| \
+                                        EXT4_FEATURE_INCOMPAT_MMP)
 #define EXT4_FEATURE_RO_COMPAT_SUPP    (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
                                         EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
                                         EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
@@ -1590,12 +1620,6 @@ void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
  */
 struct ext4_lazy_init {
        unsigned long           li_state;
-
-       wait_queue_head_t       li_wait_daemon;
-       wait_queue_head_t       li_wait_task;
-       struct timer_list       li_timer;
-       struct task_struct      *li_task;
-
        struct list_head        li_request_list;
        struct mutex            li_list_mtx;
 };
@@ -1614,6 +1638,67 @@ struct ext4_features {
        struct completion f_kobj_unregister;
 };
 
+/*
+ * This structure will be used for multiple mount protection. It will be
+ * written into the block number saved in the s_mmp_block field in the
+ * superblock. Programs that check MMP should assume that if
+ * SEQ_FSCK (or any unknown code above SEQ_MAX) is present then it is NOT safe
+ * to use the filesystem, regardless of how old the timestamp is.
+ */
+#define EXT4_MMP_MAGIC     0x004D4D50U /* ASCII for MMP */
+#define EXT4_MMP_SEQ_CLEAN 0xFF4D4D50U /* mmp_seq value for clean unmount */
+#define EXT4_MMP_SEQ_FSCK  0xE24D4D50U /* mmp_seq value when being fscked */
+#define EXT4_MMP_SEQ_MAX   0xE24D4D4FU /* maximum valid mmp_seq value */
+
+struct mmp_struct {
+       __le32  mmp_magic;              /* Magic number for MMP */
+       __le32  mmp_seq;                /* Sequence no. updated periodically */
+
+       /*
+        * mmp_time, mmp_nodename & mmp_bdevname are only used for information
+        * purposes and do not affect the correctness of the algorithm
+        */
+       __le64  mmp_time;               /* Time last updated */
+       char    mmp_nodename[64];       /* Node which last updated MMP block */
+       char    mmp_bdevname[32];       /* Bdev which last updated MMP block */
+
+       /*
+        * mmp_check_interval is used to verify if the MMP block has been
+        * updated on the block device. The value is updated based on the
+        * maximum time to write the MMP block during an update cycle.
+        */
+       __le16  mmp_check_interval;
+
+       __le16  mmp_pad1;
+       __le32  mmp_pad2[227];
+};
+
+/* arguments passed to the mmp thread */
+struct mmpd_data {
+       struct buffer_head *bh; /* bh from initial read_mmp_block() */
+       struct super_block *sb;  /* super block of the fs */
+};
+
+/*
+ * Check interval multiplier
+ * The MMP block is written every update interval and initially checked every
+ * update interval x the multiplier (the value is then adapted based on the
+ * write latency). The reason is that writes can be delayed under load and we
+ * don't want readers to incorrectly assume that the filesystem is no longer
+ * in use.
+ */
+#define EXT4_MMP_CHECK_MULT            2UL
+
+/*
+ * Minimum interval for MMP checking in seconds.
+ */
+#define EXT4_MMP_MIN_CHECK_INTERVAL    5UL
+
+/*
+ * Maximum interval for MMP checking in seconds.
+ */
+#define EXT4_MMP_MAX_CHECK_INTERVAL    300UL
+
 /*
  * Function prototypes
  */
@@ -1638,10 +1723,12 @@ extern int ext4_bg_has_super(struct super_block *sb, ext4_group_t group);
 extern unsigned long ext4_bg_num_gdb(struct super_block *sb,
                        ext4_group_t group);
 extern ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode,
-                       ext4_fsblk_t goal, unsigned long *count, int *errp);
-extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, s64 nblocks);
-extern void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
-                               ext4_fsblk_t block, unsigned long count);
+                                        ext4_fsblk_t goal,
+                                        unsigned int flags,
+                                        unsigned long *count,
+                                        int *errp);
+extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi,
+                                 s64 nblocks, unsigned int flags);
 extern ext4_fsblk_t ext4_count_free_blocks(struct super_block *);
 extern void ext4_check_blocks_bitmap(struct super_block *);
 extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
@@ -1706,6 +1793,8 @@ extern void ext4_free_blocks(handle_t *handle, struct inode *inode,
                             unsigned long count, int flags);
 extern int ext4_mb_add_groupinfo(struct super_block *sb,
                ext4_group_t i, struct ext4_group_desc *desc);
+extern void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
+                               ext4_fsblk_t block, unsigned long count);
 extern int ext4_trim_fs(struct super_block *, struct fstrim_range *);
 
 /* inode.c */
@@ -1724,11 +1813,12 @@ extern int  ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
 extern void ext4_evict_inode(struct inode *);
 extern void ext4_clear_inode(struct inode *);
 extern int  ext4_sync_inode(handle_t *, struct inode *);
-extern void ext4_dirty_inode(struct inode *);
+extern void ext4_dirty_inode(struct inode *, int);
 extern int ext4_change_inode_journal_flag(struct inode *, int);
 extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *);
 extern int ext4_can_truncate(struct inode *inode);
 extern void ext4_truncate(struct inode *);
+extern int ext4_punch_hole(struct file *file, loff_t offset, loff_t length);
 extern int ext4_truncate_restart_trans(handle_t *, struct inode *, int nblocks);
 extern void ext4_set_inode_flags(struct inode *);
 extern void ext4_get_inode_flags(struct ext4_inode_info *);
@@ -1738,6 +1828,8 @@ extern int ext4_writepage_trans_blocks(struct inode *);
 extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks);
 extern int ext4_block_truncate_page(handle_t *handle,
                struct address_space *mapping, loff_t from);
+extern int ext4_block_zero_page_range(handle_t *handle,
+               struct address_space *mapping, loff_t from, loff_t length);
 extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
 extern qsize_t *ext4_get_reserved_space(struct inode *inode);
 extern void ext4_da_update_reserve_space(struct inode *inode,
@@ -1788,6 +1880,10 @@ extern void __ext4_warning(struct super_block *, const char *, unsigned int,
                                                       __LINE__, ## message)
 extern void ext4_msg(struct super_block *, const char *, const char *, ...)
        __attribute__ ((format (printf, 3, 4)));
+extern void __dump_mmp_msg(struct super_block *, struct mmp_struct *mmp,
+                          const char *, unsigned int, const char *);
+#define dump_mmp_msg(sb, mmp, msg)     __dump_mmp_msg(sb, mmp, __func__, \
+                                                      __LINE__, msg)
 extern void __ext4_grp_locked_error(const char *, unsigned int, \
                                    struct super_block *, ext4_group_t, \
                                    unsigned long, ext4_fsblk_t, \
@@ -2064,6 +2160,8 @@ extern int ext4_ext_index_trans_blocks(struct inode *inode, int nrblocks,
 extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
                               struct ext4_map_blocks *map, int flags);
 extern void ext4_ext_truncate(struct inode *);
+extern int ext4_ext_punch_hole(struct file *file, loff_t offset,
+                               loff_t length);
 extern void ext4_ext_init(struct super_block *);
 extern void ext4_ext_release(struct super_block *);
 extern long ext4_fallocate(struct file *file, int mode, loff_t offset,
@@ -2092,6 +2190,9 @@ extern int ext4_bio_write_page(struct ext4_io_submit *io,
                               int len,
                               struct writeback_control *wbc);
 
+/* mmp.c */
+extern int ext4_multi_mount_protect(struct super_block *, ext4_fsblk_t);
+
 /* BH_Uninit flag: blocks are allocated but uninitialized on disk */
 enum ext4_state_bits {
        BH_Uninit       /* blocks are allocated but uninitialized on disk */
index 2e29abb30f7629903f11d493bc685e3877f49917..095c36f3b6129e97db937f30a969174c4facacf1 100644 (file)
@@ -125,7 +125,7 @@ struct ext4_ext_path {
  * positive retcode - signal for ext4_ext_walk_space(), see below
  * callback must return valid extent (passed or newly created)
  */
-typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *,
+typedef int (*ext_prepare_callback)(struct inode *, ext4_lblk_t,
                                        struct ext4_ext_cache *,
                                        struct ext4_extent *, void *);
 
@@ -133,8 +133,11 @@ typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *,
 #define EXT_BREAK      1
 #define EXT_REPEAT     2
 
-/* Maximum logical block in a file; ext4_extent's ee_block is __le32 */
-#define EXT_MAX_BLOCK  0xffffffff
+/*
+ * Maximum number of logical blocks in a file; ext4_extent's ee_block is
+ * __le32.
+ */
+#define EXT_MAX_BLOCKS 0xffffffff
 
 /*
  * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an
index 6e272ef6ba96c4938cc357ef498c760bde67d39e..f5240aa15601a6b34c40b339b0153e6f8bc6867d 100644 (file)
@@ -6,20 +6,6 @@
 
 #include <trace/events/ext4.h>
 
-int __ext4_journal_get_undo_access(const char *where, unsigned int line,
-                                  handle_t *handle, struct buffer_head *bh)
-{
-       int err = 0;
-
-       if (ext4_handle_valid(handle)) {
-               err = jbd2_journal_get_undo_access(handle, bh);
-               if (err)
-                       ext4_journal_abort_handle(where, line, __func__, bh,
-                                                 handle, err);
-       }
-       return err;
-}
-
 int __ext4_journal_get_write_access(const char *where, unsigned int line,
                                    handle_t *handle, struct buffer_head *bh)
 {
index d0f53538a57fd8663b03443898e4d12492ff399b..bb85757689b6af513dd556559a407049a1fc9782 100644 (file)
@@ -126,9 +126,6 @@ void ext4_journal_abort_handle(const char *caller, unsigned int line,
                               const char *err_fn,
                struct buffer_head *bh, handle_t *handle, int err);
 
-int __ext4_journal_get_undo_access(const char *where, unsigned int line,
-                                  handle_t *handle, struct buffer_head *bh);
-
 int __ext4_journal_get_write_access(const char *where, unsigned int line,
                                    handle_t *handle, struct buffer_head *bh);
 
@@ -146,8 +143,6 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
 int __ext4_handle_dirty_super(const char *where, unsigned int line,
                              handle_t *handle, struct super_block *sb);
 
-#define ext4_journal_get_undo_access(handle, bh) \
-       __ext4_journal_get_undo_access(__func__, __LINE__, (handle), (bh))
 #define ext4_journal_get_write_access(handle, bh) \
        __ext4_journal_get_write_access(__func__, __LINE__, (handle), (bh))
 #define ext4_forget(handle, is_metadata, inode, bh, block_nr) \
index 4890d6f3ad15a976417ae542296a0051fe97bc27..f815cc81e7a287bd7198dc874d7954938c188464 100644 (file)
 
 #include <trace/events/ext4.h>
 
+static int ext4_split_extent(handle_t *handle,
+                               struct inode *inode,
+                               struct ext4_ext_path *path,
+                               struct ext4_map_blocks *map,
+                               int split_flag,
+                               int flags);
+
 static int ext4_ext_truncate_extend_restart(handle_t *handle,
                                            struct inode *inode,
                                            int needed)
@@ -192,12 +199,13 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
 static ext4_fsblk_t
 ext4_ext_new_meta_block(handle_t *handle, struct inode *inode,
                        struct ext4_ext_path *path,
-                       struct ext4_extent *ex, int *err)
+                       struct ext4_extent *ex, int *err, unsigned int flags)
 {
        ext4_fsblk_t goal, newblock;
 
        goal = ext4_ext_find_goal(inode, path, le32_to_cpu(ex->ee_block));
-       newblock = ext4_new_meta_blocks(handle, inode, goal, NULL, err);
+       newblock = ext4_new_meta_blocks(handle, inode, goal, flags,
+                                       NULL, err);
        return newblock;
 }
 
@@ -474,9 +482,43 @@ static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path)
        }
        ext_debug("\n");
 }
+
+static void ext4_ext_show_move(struct inode *inode, struct ext4_ext_path *path,
+                       ext4_fsblk_t newblock, int level)
+{
+       int depth = ext_depth(inode);
+       struct ext4_extent *ex;
+
+       if (depth != level) {
+               struct ext4_extent_idx *idx;
+               idx = path[level].p_idx;
+               while (idx <= EXT_MAX_INDEX(path[level].p_hdr)) {
+                       ext_debug("%d: move %d:%llu in new index %llu\n", level,
+                                       le32_to_cpu(idx->ei_block),
+                                       ext4_idx_pblock(idx),
+                                       newblock);
+                       idx++;
+               }
+
+               return;
+       }
+
+       ex = path[depth].p_ext;
+       while (ex <= EXT_MAX_EXTENT(path[depth].p_hdr)) {
+               ext_debug("move %d:%llu:[%d]%d in new leaf %llu\n",
+                               le32_to_cpu(ex->ee_block),
+                               ext4_ext_pblock(ex),
+                               ext4_ext_is_uninitialized(ex),
+                               ext4_ext_get_actual_len(ex),
+                               newblock);
+               ex++;
+       }
+}
+
 #else
 #define ext4_ext_show_path(inode, path)
 #define ext4_ext_show_leaf(inode, path)
+#define ext4_ext_show_move(inode, path, newblock, level)
 #endif
 
 void ext4_ext_drop_refs(struct ext4_ext_path *path)
@@ -792,14 +834,14 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
  * - initializes subtree
  */
 static int ext4_ext_split(handle_t *handle, struct inode *inode,
-                               struct ext4_ext_path *path,
-                               struct ext4_extent *newext, int at)
+                         unsigned int flags,
+                         struct ext4_ext_path *path,
+                         struct ext4_extent *newext, int at)
 {
        struct buffer_head *bh = NULL;
        int depth = ext_depth(inode);
        struct ext4_extent_header *neh;
        struct ext4_extent_idx *fidx;
-       struct ext4_extent *ex;
        int i = at, k, m, a;
        ext4_fsblk_t newblock, oldblock;
        __le32 border;
@@ -847,7 +889,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
        ext_debug("allocate %d blocks for indexes/leaf\n", depth - at);
        for (a = 0; a < depth - at; a++) {
                newblock = ext4_ext_new_meta_block(handle, inode, path,
-                                                  newext, &err);
+                                                  newext, &err, flags);
                if (newblock == 0)
                        goto cleanup;
                ablocks[a] = newblock;
@@ -876,7 +918,6 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
        neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0));
        neh->eh_magic = EXT4_EXT_MAGIC;
        neh->eh_depth = 0;
-       ex = EXT_FIRST_EXTENT(neh);
 
        /* move remainder of path[depth] to the new leaf */
        if (unlikely(path[depth].p_hdr->eh_entries !=
@@ -888,25 +929,12 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
                goto cleanup;
        }
        /* start copy from next extent */
-       /* TODO: we could do it by single memmove */
-       m = 0;
-       path[depth].p_ext++;
-       while (path[depth].p_ext <=
-                       EXT_MAX_EXTENT(path[depth].p_hdr)) {
-               ext_debug("move %d:%llu:[%d]%d in new leaf %llu\n",
-                               le32_to_cpu(path[depth].p_ext->ee_block),
-                               ext4_ext_pblock(path[depth].p_ext),
-                               ext4_ext_is_uninitialized(path[depth].p_ext),
-                               ext4_ext_get_actual_len(path[depth].p_ext),
-                               newblock);
-               /*memmove(ex++, path[depth].p_ext++,
-                               sizeof(struct ext4_extent));
-               neh->eh_entries++;*/
-               path[depth].p_ext++;
-               m++;
-       }
+       m = EXT_MAX_EXTENT(path[depth].p_hdr) - path[depth].p_ext++;
+       ext4_ext_show_move(inode, path, newblock, depth);
        if (m) {
-               memmove(ex, path[depth].p_ext-m, sizeof(struct ext4_extent)*m);
+               struct ext4_extent *ex;
+               ex = EXT_FIRST_EXTENT(neh);
+               memmove(ex, path[depth].p_ext, sizeof(struct ext4_extent) * m);
                le16_add_cpu(&neh->eh_entries, m);
        }
 
@@ -968,12 +996,8 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
 
                ext_debug("int.index at %d (block %llu): %u -> %llu\n",
                                i, newblock, le32_to_cpu(border), oldblock);
-               /* copy indexes */
-               m = 0;
-               path[i].p_idx++;
 
-               ext_debug("cur 0x%p, last 0x%p\n", path[i].p_idx,
-                               EXT_MAX_INDEX(path[i].p_hdr));
+               /* move remainder of path[i] to the new index block */
                if (unlikely(EXT_MAX_INDEX(path[i].p_hdr) !=
                                        EXT_LAST_INDEX(path[i].p_hdr))) {
                        EXT4_ERROR_INODE(inode,
@@ -982,20 +1006,13 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
                        err = -EIO;
                        goto cleanup;
                }
-               while (path[i].p_idx <= EXT_MAX_INDEX(path[i].p_hdr)) {
-                       ext_debug("%d: move %d:%llu in new index %llu\n", i,
-                                       le32_to_cpu(path[i].p_idx->ei_block),
-                                       ext4_idx_pblock(path[i].p_idx),
-                                       newblock);
-                       /*memmove(++fidx, path[i].p_idx++,
-                                       sizeof(struct ext4_extent_idx));
-                       neh->eh_entries++;
-                       BUG_ON(neh->eh_entries > neh->eh_max);*/
-                       path[i].p_idx++;
-                       m++;
-               }
+               /* start copy indexes */
+               m = EXT_MAX_INDEX(path[i].p_hdr) - path[i].p_idx++;
+               ext_debug("cur 0x%p, last 0x%p\n", path[i].p_idx,
+                               EXT_MAX_INDEX(path[i].p_hdr));
+               ext4_ext_show_move(inode, path, newblock, i);
                if (m) {
-                       memmove(++fidx, path[i].p_idx - m,
+                       memmove(++fidx, path[i].p_idx,
                                sizeof(struct ext4_extent_idx) * m);
                        le16_add_cpu(&neh->eh_entries, m);
                }
@@ -1056,8 +1073,9 @@ cleanup:
  *   just created block
  */
 static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
-                                       struct ext4_ext_path *path,
-                                       struct ext4_extent *newext)
+                                unsigned int flags,
+                                struct ext4_ext_path *path,
+                                struct ext4_extent *newext)
 {
        struct ext4_ext_path *curp = path;
        struct ext4_extent_header *neh;
@@ -1065,7 +1083,8 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
        ext4_fsblk_t newblock;
        int err = 0;
 
-       newblock = ext4_ext_new_meta_block(handle, inode, path, newext, &err);
+       newblock = ext4_ext_new_meta_block(handle, inode, path,
+               newext, &err, flags);
        if (newblock == 0)
                return err;
 
@@ -1140,8 +1159,9 @@ out:
  * if no free index is found, then it requests in-depth growing.
  */
 static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode,
-                                       struct ext4_ext_path *path,
-                                       struct ext4_extent *newext)
+                                   unsigned int flags,
+                                   struct ext4_ext_path *path,
+                                   struct ext4_extent *newext)
 {
        struct ext4_ext_path *curp;
        int depth, i, err = 0;
@@ -1161,7 +1181,7 @@ repeat:
        if (EXT_HAS_FREE_INDEX(curp)) {
                /* if we found index with free entry, then use that
                 * entry: create all needed subtree and add new leaf */
-               err = ext4_ext_split(handle, inode, path, newext, i);
+               err = ext4_ext_split(handle, inode, flags, path, newext, i);
                if (err)
                        goto out;
 
@@ -1174,7 +1194,8 @@ repeat:
                        err = PTR_ERR(path);
        } else {
                /* tree is full, time to grow in depth */
-               err = ext4_ext_grow_indepth(handle, inode, path, newext);
+               err = ext4_ext_grow_indepth(handle, inode, flags,
+                                           path, newext);
                if (err)
                        goto out;
 
@@ -1387,7 +1408,7 @@ got_index:
 
 /*
  * ext4_ext_next_allocated_block:
- * returns allocated block in subsequent extent or EXT_MAX_BLOCK.
+ * returns allocated block in subsequent extent or EXT_MAX_BLOCKS.
  * NOTE: it considers block number from index entry as
  * allocated block. Thus, index entries have to be consistent
  * with leaves.
@@ -1401,7 +1422,7 @@ ext4_ext_next_allocated_block(struct ext4_ext_path *path)
        depth = path->p_depth;
 
        if (depth == 0 && path->p_ext == NULL)
-               return EXT_MAX_BLOCK;
+               return EXT_MAX_BLOCKS;
 
        while (depth >= 0) {
                if (depth == path->p_depth) {
@@ -1418,12 +1439,12 @@ ext4_ext_next_allocated_block(struct ext4_ext_path *path)
                depth--;
        }
 
-       return EXT_MAX_BLOCK;
+       return EXT_MAX_BLOCKS;
 }
 
 /*
  * ext4_ext_next_leaf_block:
- * returns first allocated block from next leaf or EXT_MAX_BLOCK
+ * returns first allocated block from next leaf or EXT_MAX_BLOCKS
  */
 static ext4_lblk_t ext4_ext_next_leaf_block(struct inode *inode,
                                        struct ext4_ext_path *path)
@@ -1435,7 +1456,7 @@ static ext4_lblk_t ext4_ext_next_leaf_block(struct inode *inode,
 
        /* zero-tree has no leaf blocks at all */
        if (depth == 0)
-               return EXT_MAX_BLOCK;
+               return EXT_MAX_BLOCKS;
 
        /* go to index block */
        depth--;
@@ -1448,7 +1469,7 @@ static ext4_lblk_t ext4_ext_next_leaf_block(struct inode *inode,
                depth--;
        }
 
-       return EXT_MAX_BLOCK;
+       return EXT_MAX_BLOCKS;
 }
 
 /*
@@ -1563,7 +1584,7 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
  * Returns 0 if the extents (ex and ex+1) were _not_ merged and returns
  * 1 if they got merged.
  */
-static int ext4_ext_try_to_merge(struct inode *inode,
+static int ext4_ext_try_to_merge_right(struct inode *inode,
                                 struct ext4_ext_path *path,
                                 struct ext4_extent *ex)
 {
@@ -1602,6 +1623,31 @@ static int ext4_ext_try_to_merge(struct inode *inode,
        return merge_done;
 }
 
+/*
+ * This function tries to merge the @ex extent to neighbours in the tree.
+ * return 1 if merge left else 0.
+ */
+static int ext4_ext_try_to_merge(struct inode *inode,
+                                 struct ext4_ext_path *path,
+                                 struct ext4_extent *ex) {
+       struct ext4_extent_header *eh;
+       unsigned int depth;
+       int merge_done = 0;
+       int ret = 0;
+
+       depth = ext_depth(inode);
+       BUG_ON(path[depth].p_hdr == NULL);
+       eh = path[depth].p_hdr;
+
+       if (ex > EXT_FIRST_EXTENT(eh))
+               merge_done = ext4_ext_try_to_merge_right(inode, path, ex - 1);
+
+       if (!merge_done)
+               ret = ext4_ext_try_to_merge_right(inode, path, ex);
+
+       return ret;
+}
+
 /*
  * check if a portion of the "newext" extent overlaps with an
  * existing extent.
@@ -1631,13 +1677,13 @@ static unsigned int ext4_ext_check_overlap(struct inode *inode,
         */
        if (b2 < b1) {
                b2 = ext4_ext_next_allocated_block(path);
-               if (b2 == EXT_MAX_BLOCK)
+               if (b2 == EXT_MAX_BLOCKS)
                        goto out;
        }
 
        /* check for wrap through zero on extent logical start block*/
        if (b1 + len1 < b1) {
-               len1 = EXT_MAX_BLOCK - b1;
+               len1 = EXT_MAX_BLOCKS - b1;
                newext->ee_len = cpu_to_le16(len1);
                ret = 1;
        }
@@ -1668,6 +1714,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
        int depth, len, err;
        ext4_lblk_t next;
        unsigned uninitialized = 0;
+       int flags = 0;
 
        if (unlikely(ext4_ext_get_actual_len(newext) == 0)) {
                EXT4_ERROR_INODE(inode, "ext4_ext_get_actual_len(newext) == 0");
@@ -1720,7 +1767,7 @@ repeat:
        fex = EXT_LAST_EXTENT(eh);
        next = ext4_ext_next_leaf_block(inode, path);
        if (le32_to_cpu(newext->ee_block) > le32_to_cpu(fex->ee_block)
-           && next != EXT_MAX_BLOCK) {
+           && next != EXT_MAX_BLOCKS) {
                ext_debug("next leaf block - %d\n", next);
                BUG_ON(npath != NULL);
                npath = ext4_ext_find_extent(inode, next, NULL);
@@ -1742,7 +1789,9 @@ repeat:
         * There is no free space in the found leaf.
         * We're gonna add a new leaf in the tree.
         */
-       err = ext4_ext_create_new_leaf(handle, inode, path, newext);
+       if (flag & EXT4_GET_BLOCKS_PUNCH_OUT_EXT)
+               flags = EXT4_MB_USE_ROOT_BLOCKS;
+       err = ext4_ext_create_new_leaf(handle, inode, flags, path, newext);
        if (err)
                goto cleanup;
        depth = ext_depth(inode);
@@ -1838,7 +1887,7 @@ static int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block,
        BUG_ON(func == NULL);
        BUG_ON(inode == NULL);
 
-       while (block < last && block != EXT_MAX_BLOCK) {
+       while (block < last && block != EXT_MAX_BLOCKS) {
                num = last - block;
                /* find extent for this block */
                down_read(&EXT4_I(inode)->i_data_sem);
@@ -1909,7 +1958,7 @@ static int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block,
                        err = -EIO;
                        break;
                }
-               err = func(inode, path, &cbex, ex, cbdata);
+               err = func(inode, next, &cbex, ex, cbdata);
                ext4_ext_drop_refs(path);
 
                if (err < 0)
@@ -1971,7 +2020,7 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
        if (ex == NULL) {
                /* there is no extent yet, so gap is [0;-] */
                lblock = 0;
-               len = EXT_MAX_BLOCK;
+               len = EXT_MAX_BLOCKS;
                ext_debug("cache gap(whole file):");
        } else if (block < le32_to_cpu(ex->ee_block)) {
                lblock = block;
@@ -2003,13 +2052,25 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
 }
 
 /*
+ * ext4_ext_in_cache()
+ * Checks to see if the given block is in the cache.
+ * If it is, the cached extent is stored in the given
+ * cache extent pointer.  If the cached extent is a hole,
+ * this routine should be used instead of
+ * ext4_ext_in_cache if the calling function needs to
+ * know the size of the hole.
+ *
+ * @inode: The files inode
+ * @block: The block to look for in the cache
+ * @ex:    Pointer where the cached extent will be stored
+ *         if it contains block
+ *
  * Return 0 if cache is invalid; 1 if the cache is valid
  */
-static int
-ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block,
-                       struct ext4_extent *ex)
-{
+static int ext4_ext_check_cache(struct inode *inode, ext4_lblk_t block,
+       struct ext4_ext_cache *ex){
        struct ext4_ext_cache *cex;
+       struct ext4_sb_info *sbi;
        int ret = 0;
 
        /*
@@ -2017,25 +2078,59 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block,
         */
        spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
        cex = &EXT4_I(inode)->i_cached_extent;
+       sbi = EXT4_SB(inode->i_sb);
 
        /* has cache valid data? */
        if (cex->ec_len == 0)
                goto errout;
 
        if (in_range(block, cex->ec_block, cex->ec_len)) {
-               ex->ee_block = cpu_to_le32(cex->ec_block);
-               ext4_ext_store_pblock(ex, cex->ec_start);
-               ex->ee_len = cpu_to_le16(cex->ec_len);
+               memcpy(ex, cex, sizeof(struct ext4_ext_cache));
                ext_debug("%u cached by %u:%u:%llu\n",
                                block,
                                cex->ec_block, cex->ec_len, cex->ec_start);
                ret = 1;
        }
 errout:
+       if (!ret)
+               sbi->extent_cache_misses++;
+       else
+               sbi->extent_cache_hits++;
        spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
        return ret;
 }
 
+/*
+ * ext4_ext_in_cache()
+ * Checks to see if the given block is in the cache.
+ * If it is, the cached extent is stored in the given
+ * extent pointer.
+ *
+ * @inode: The files inode
+ * @block: The block to look for in the cache
+ * @ex:    Pointer where the cached extent will be stored
+ *         if it contains block
+ *
+ * Return 0 if cache is invalid; 1 if the cache is valid
+ */
+static int
+ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block,
+                       struct ext4_extent *ex)
+{
+       struct ext4_ext_cache cex;
+       int ret = 0;
+
+       if (ext4_ext_check_cache(inode, block, &cex)) {
+               ex->ee_block = cpu_to_le32(cex.ec_block);
+               ext4_ext_store_pblock(ex, cex.ec_start);
+               ex->ee_len = cpu_to_le16(cex.ec_len);
+               ret = 1;
+       }
+
+       return ret;
+}
+
+
 /*
  * ext4_ext_rm_idx:
  * removes index from the index block.
@@ -2163,8 +2258,16 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
                ext4_free_blocks(handle, inode, NULL, start, num, flags);
        } else if (from == le32_to_cpu(ex->ee_block)
                   && to <= le32_to_cpu(ex->ee_block) + ee_len - 1) {
-               printk(KERN_INFO "strange request: removal %u-%u from %u:%u\n",
-                       from, to, le32_to_cpu(ex->ee_block), ee_len);
+               /* head removal */
+               ext4_lblk_t num;
+               ext4_fsblk_t start;
+
+               num = to - from;
+               start = ext4_ext_pblock(ex);
+
+               ext_debug("free first %u blocks starting %llu\n", num, start);
+               ext4_free_blocks(handle, inode, 0, start, num, flags);
+
        } else {
                printk(KERN_INFO "strange request: removal(2) "
                                "%u-%u from %u:%u\n",
@@ -2173,9 +2276,22 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
        return 0;
 }
 
+
+/*
+ * ext4_ext_rm_leaf() Removes the extents associated with the
+ * blocks appearing between "start" and "end", and splits the extents
+ * if "start" and "end" appear in the same extent
+ *
+ * @handle: The journal handle
+ * @inode:  The files inode
+ * @path:   The path to the leaf
+ * @start:  The first block to remove
+ * @end:   The last block to remove
+ */
 static int
 ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
-               struct ext4_ext_path *path, ext4_lblk_t start)
+               struct ext4_ext_path *path, ext4_lblk_t start,
+               ext4_lblk_t end)
 {
        int err = 0, correct_index = 0;
        int depth = ext_depth(inode), credits;
@@ -2186,6 +2302,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
        unsigned short ex_ee_len;
        unsigned uninitialized = 0;
        struct ext4_extent *ex;
+       struct ext4_map_blocks map;
 
        /* the header must be checked already in ext4_ext_remove_space() */
        ext_debug("truncate since %u in leaf\n", start);
@@ -2215,31 +2332,95 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
                path[depth].p_ext = ex;
 
                a = ex_ee_block > start ? ex_ee_block : start;
-               b = ex_ee_block + ex_ee_len - 1 < EXT_MAX_BLOCK ?
-                       ex_ee_block + ex_ee_len - 1 : EXT_MAX_BLOCK;
+               b = ex_ee_block+ex_ee_len - 1 < end ?
+                       ex_ee_block+ex_ee_len - 1 : end;
 
                ext_debug("  border %u:%u\n", a, b);
 
-               if (a != ex_ee_block && b != ex_ee_block + ex_ee_len - 1) {
-                       block = 0;
-                       num = 0;
-                       BUG();
+               /* If this extent is beyond the end of the hole, skip it */
+               if (end <= ex_ee_block) {
+                       ex--;
+                       ex_ee_block = le32_to_cpu(ex->ee_block);
+                       ex_ee_len = ext4_ext_get_actual_len(ex);
+                       continue;
+               } else if (a != ex_ee_block &&
+                       b != ex_ee_block + ex_ee_len - 1) {
+                       /*
+                        * If this is a truncate, then this condition should
+                        * never happen because at least one of the end points
+                        * needs to be on the edge of the extent.
+                        */
+                       if (end == EXT_MAX_BLOCKS - 1) {
+                               ext_debug("  bad truncate %u:%u\n",
+                                               start, end);
+                               block = 0;
+                               num = 0;
+                               err = -EIO;
+                               goto out;
+                       }
+                       /*
+                        * else this is a hole punch, so the extent needs to
+                        * be split since neither edge of the hole is on the
+                        * extent edge
+                        */
+                       else{
+                               map.m_pblk = ext4_ext_pblock(ex);
+                               map.m_lblk = ex_ee_block;
+                               map.m_len = b - ex_ee_block;
+
+                               err = ext4_split_extent(handle,
+                                       inode, path, &map, 0,
+                                       EXT4_GET_BLOCKS_PUNCH_OUT_EXT |
+                                       EXT4_GET_BLOCKS_PRE_IO);
+
+                               if (err < 0)
+                                       goto out;
+
+                               ex_ee_len = ext4_ext_get_actual_len(ex);
+
+                               b = ex_ee_block+ex_ee_len - 1 < end ?
+                                       ex_ee_block+ex_ee_len - 1 : end;
+
+                               /* Then remove tail of this extent */
+                               block = ex_ee_block;
+                               num = a - block;
+                       }
                } else if (a != ex_ee_block) {
                        /* remove tail of the extent */
                        block = ex_ee_block;
                        num = a - block;
                } else if (b != ex_ee_block + ex_ee_len - 1) {
                        /* remove head of the extent */
-                       block = a;
-                       num = b - a;
-                       /* there is no "make a hole" API yet */
-                       BUG();
+                       block = b;
+                       num =  ex_ee_block + ex_ee_len - b;
+
+                       /*
+                        * If this is a truncate, this condition
+                        * should never happen
+                        */
+                       if (end == EXT_MAX_BLOCKS - 1) {
+                               ext_debug("  bad truncate %u:%u\n",
+                                       start, end);
+                               err = -EIO;
+                               goto out;
+                       }
                } else {
                        /* remove whole extent: excellent! */
                        block = ex_ee_block;
                        num = 0;
-                       BUG_ON(a != ex_ee_block);
-                       BUG_ON(b != ex_ee_block + ex_ee_len - 1);
+                       if (a != ex_ee_block) {
+                               ext_debug("  bad truncate %u:%u\n",
+                                       start, end);
+                               err = -EIO;
+                               goto out;
+                       }
+
+                       if (b != ex_ee_block + ex_ee_len - 1) {
+                               ext_debug("  bad truncate %u:%u\n",
+                                       start, end);
+                               err = -EIO;
+                               goto out;
+                       }
                }
 
                /*
@@ -2270,7 +2451,13 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
                if (num == 0) {
                        /* this extent is removed; mark slot entirely unused */
                        ext4_ext_store_pblock(ex, 0);
-                       le16_add_cpu(&eh->eh_entries, -1);
+               } else if (block != ex_ee_block) {
+                       /*
+                        * If this was a head removal, then we need to update
+                        * the physical block since it is now at a different
+                        * location
+                        */
+                       ext4_ext_store_pblock(ex, ext4_ext_pblock(ex) + (b-a));
                }
 
                ex->ee_block = cpu_to_le32(block);
@@ -2286,6 +2473,27 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
                if (err)
                        goto out;
 
+               /*
+                * If the extent was completely released,
+                * we need to remove it from the leaf
+                */
+               if (num == 0) {
+                       if (end != EXT_MAX_BLOCKS - 1) {
+                               /*
+                                * For hole punching, we need to scoot all the
+                                * extents up when an extent is removed so that
+                                * we dont have blank extents in the middle
+                                */
+                               memmove(ex, ex+1, (EXT_LAST_EXTENT(eh) - ex) *
+                                       sizeof(struct ext4_extent));
+
+                               /* Now get rid of the one at the end */
+                               memset(EXT_LAST_EXTENT(eh), 0,
+                                       sizeof(struct ext4_extent));
+                       }
+                       le16_add_cpu(&eh->eh_entries, -1);
+               }
+
                ext_debug("new extent: %u:%u:%llu\n", block, num,
                                ext4_ext_pblock(ex));
                ex--;
@@ -2326,7 +2534,8 @@ ext4_ext_more_to_rm(struct ext4_ext_path *path)
        return 1;
 }
 
-static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
+static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
+                               ext4_lblk_t end)
 {
        struct super_block *sb = inode->i_sb;
        int depth = ext_depth(inode);
@@ -2365,7 +2574,8 @@ again:
        while (i >= 0 && err == 0) {
                if (i == depth) {
                        /* this is leaf block */
-                       err = ext4_ext_rm_leaf(handle, inode, path, start);
+                       err = ext4_ext_rm_leaf(handle, inode, path,
+                                       start, end);
                        /* root level has p_bh == NULL, brelse() eats this */
                        brelse(path[i].p_bh);
                        path[i].p_bh = NULL;
@@ -2529,6 +2739,195 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
        return ret;
 }
 
+/*
+ * used by extent splitting.
+ */
+#define EXT4_EXT_MAY_ZEROOUT   0x1  /* safe to zeroout if split fails \
+                                       due to ENOSPC */
+#define EXT4_EXT_MARK_UNINIT1  0x2  /* mark first half uninitialized */
+#define EXT4_EXT_MARK_UNINIT2  0x4  /* mark second half uninitialized */
+
+/*
+ * ext4_split_extent_at() splits an extent at given block.
+ *
+ * @handle: the journal handle
+ * @inode: the file inode
+ * @path: the path to the extent
+ * @split: the logical block where the extent is splitted.
+ * @split_flags: indicates if the extent could be zeroout if split fails, and
+ *              the states(init or uninit) of new extents.
+ * @flags: flags used to insert new extent to extent tree.
+ *
+ *
+ * Splits extent [a, b] into two extents [a, @split) and [@split, b], states
+ * of which are deterimined by split_flag.
+ *
+ * There are two cases:
+ *  a> the extent are splitted into two extent.
+ *  b> split is not needed, and just mark the extent.
+ *
+ * return 0 on success.
+ */
+static int ext4_split_extent_at(handle_t *handle,
+                            struct inode *inode,
+                            struct ext4_ext_path *path,
+                            ext4_lblk_t split,
+                            int split_flag,
+                            int flags)
+{
+       ext4_fsblk_t newblock;
+       ext4_lblk_t ee_block;
+       struct ext4_extent *ex, newex, orig_ex;
+       struct ext4_extent *ex2 = NULL;
+       unsigned int ee_len, depth;
+       int err = 0;
+
+       ext_debug("ext4_split_extents_at: inode %lu, logical"
+               "block %llu\n", inode->i_ino, (unsigned long long)split);
+
+       ext4_ext_show_leaf(inode, path);
+
+       depth = ext_depth(inode);
+       ex = path[depth].p_ext;
+       ee_block = le32_to_cpu(ex->ee_block);
+       ee_len = ext4_ext_get_actual_len(ex);
+       newblock = split - ee_block + ext4_ext_pblock(ex);
+
+       BUG_ON(split < ee_block || split >= (ee_block + ee_len));
+
+       err = ext4_ext_get_access(handle, inode, path + depth);
+       if (err)
+               goto out;
+
+       if (split == ee_block) {
+               /*
+                * case b: block @split is the block that the extent begins with
+                * then we just change the state of the extent, and splitting
+                * is not needed.
+                */
+               if (split_flag & EXT4_EXT_MARK_UNINIT2)
+                       ext4_ext_mark_uninitialized(ex);
+               else
+                       ext4_ext_mark_initialized(ex);
+
+               if (!(flags & EXT4_GET_BLOCKS_PRE_IO))
+                       ext4_ext_try_to_merge(inode, path, ex);
+
+               err = ext4_ext_dirty(handle, inode, path + depth);
+               goto out;
+       }
+
+       /* case a */
+       memcpy(&orig_ex, ex, sizeof(orig_ex));
+       ex->ee_len = cpu_to_le16(split - ee_block);
+       if (split_flag & EXT4_EXT_MARK_UNINIT1)
+               ext4_ext_mark_uninitialized(ex);
+
+       /*
+        * path may lead to new leaf, not to original leaf any more
+        * after ext4_ext_insert_extent() returns,
+        */
+       err = ext4_ext_dirty(handle, inode, path + depth);
+       if (err)
+               goto fix_extent_len;
+
+       ex2 = &newex;
+       ex2->ee_block = cpu_to_le32(split);
+       ex2->ee_len   = cpu_to_le16(ee_len - (split - ee_block));
+       ext4_ext_store_pblock(ex2, newblock);
+       if (split_flag & EXT4_EXT_MARK_UNINIT2)
+               ext4_ext_mark_uninitialized(ex2);
+
+       err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
+       if (err == -ENOSPC && (EXT4_EXT_MAY_ZEROOUT & split_flag)) {
+               err = ext4_ext_zeroout(inode, &orig_ex);
+               if (err)
+                       goto fix_extent_len;
+               /* update the extent length and mark as initialized */
+               ex->ee_len = cpu_to_le32(ee_len);
+               ext4_ext_try_to_merge(inode, path, ex);
+               err = ext4_ext_dirty(handle, inode, path + depth);
+               goto out;
+       } else if (err)
+               goto fix_extent_len;
+
+out:
+       ext4_ext_show_leaf(inode, path);
+       return err;
+
+fix_extent_len:
+       ex->ee_len = orig_ex.ee_len;
+       ext4_ext_dirty(handle, inode, path + depth);
+       return err;
+}
+
+/*
+ * ext4_split_extents() splits an extent and mark extent which is covered
+ * by @map as split_flags indicates
+ *
+ * It may result in splitting the extent into multiple extents (upto three)
+ * There are three possibilities:
+ *   a> There is no split required
+ *   b> Splits in two extents: Split is happening at either end of the extent
+ *   c> Splits in three extents: Somone is splitting in middle of the extent
+ *
+ */
+static int ext4_split_extent(handle_t *handle,
+                             struct inode *inode,
+                             struct ext4_ext_path *path,
+                             struct ext4_map_blocks *map,
+                             int split_flag,
+                             int flags)
+{
+       ext4_lblk_t ee_block;
+       struct ext4_extent *ex;
+       unsigned int ee_len, depth;
+       int err = 0;
+       int uninitialized;
+       int split_flag1, flags1;
+
+       depth = ext_depth(inode);
+       ex = path[depth].p_ext;
+       ee_block = le32_to_cpu(ex->ee_block);
+       ee_len = ext4_ext_get_actual_len(ex);
+       uninitialized = ext4_ext_is_uninitialized(ex);
+
+       if (map->m_lblk + map->m_len < ee_block + ee_len) {
+               split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT ?
+                             EXT4_EXT_MAY_ZEROOUT : 0;
+               flags1 = flags | EXT4_GET_BLOCKS_PRE_IO;
+               if (uninitialized)
+                       split_flag1 |= EXT4_EXT_MARK_UNINIT1 |
+                                      EXT4_EXT_MARK_UNINIT2;
+               err = ext4_split_extent_at(handle, inode, path,
+                               map->m_lblk + map->m_len, split_flag1, flags1);
+               if (err)
+                       goto out;
+       }
+
+       ext4_ext_drop_refs(path);
+       path = ext4_ext_find_extent(inode, map->m_lblk, path);
+       if (IS_ERR(path))
+               return PTR_ERR(path);
+
+       if (map->m_lblk >= ee_block) {
+               split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT ?
+                             EXT4_EXT_MAY_ZEROOUT : 0;
+               if (uninitialized)
+                       split_flag1 |= EXT4_EXT_MARK_UNINIT1;
+               if (split_flag & EXT4_EXT_MARK_UNINIT2)
+                       split_flag1 |= EXT4_EXT_MARK_UNINIT2;
+               err = ext4_split_extent_at(handle, inode, path,
+                               map->m_lblk, split_flag1, flags);
+               if (err)
+                       goto out;
+       }
+
+       ext4_ext_show_leaf(inode, path);
+out:
+       return err ? err : map->m_len;
+}
+
 #define EXT4_EXT_ZERO_LEN 7
 /*
  * This function is called by ext4_ext_map_blocks() if someone tries to write
@@ -2545,17 +2944,13 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                                           struct ext4_map_blocks *map,
                                           struct ext4_ext_path *path)
 {
-       struct ext4_extent *ex, newex, orig_ex;
-       struct ext4_extent *ex1 = NULL;
-       struct ext4_extent *ex2 = NULL;
-       struct ext4_extent *ex3 = NULL;
-       struct ext4_extent_header *eh;
+       struct ext4_map_blocks split_map;
+       struct ext4_extent zero_ex;
+       struct ext4_extent *ex;
        ext4_lblk_t ee_block, eof_block;
        unsigned int allocated, ee_len, depth;
-       ext4_fsblk_t newblock;
        int err = 0;
-       int ret = 0;
-       int may_zeroout;
+       int split_flag = 0;
 
        ext_debug("ext4_ext_convert_to_initialized: inode %lu, logical"
                "block %llu, max_blocks %u\n", inode->i_ino,
@@ -2567,280 +2962,86 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                eof_block = map->m_lblk + map->m_len;
 
        depth = ext_depth(inode);
-       eh = path[depth].p_hdr;
        ex = path[depth].p_ext;
        ee_block = le32_to_cpu(ex->ee_block);
        ee_len = ext4_ext_get_actual_len(ex);
        allocated = ee_len - (map->m_lblk - ee_block);
-       newblock = map->m_lblk - ee_block + ext4_ext_pblock(ex);
-
-       ex2 = ex;
-       orig_ex.ee_block = ex->ee_block;
-       orig_ex.ee_len   = cpu_to_le16(ee_len);
-       ext4_ext_store_pblock(&orig_ex, ext4_ext_pblock(ex));
 
+       WARN_ON(map->m_lblk < ee_block);
        /*
         * It is safe to convert extent to initialized via explicit
         * zeroout only if extent is fully insde i_size or new_size.
         */
-       may_zeroout = ee_block + ee_len <= eof_block;
+       split_flag |= ee_block + ee_len <= eof_block ? EXT4_EXT_MAY_ZEROOUT : 0;
 
-       err = ext4_ext_get_access(handle, inode, path + depth);
-       if (err)
-               goto out;
        /* If extent has less than 2*EXT4_EXT_ZERO_LEN zerout directly */
-       if (ee_len <= 2*EXT4_EXT_ZERO_LEN && may_zeroout) {
-               err =  ext4_ext_zeroout(inode, &orig_ex);
+       if (ee_len <= 2*EXT4_EXT_ZERO_LEN &&
+           (EXT4_EXT_MAY_ZEROOUT & split_flag)) {
+               err = ext4_ext_zeroout(inode, ex);
                if (err)
-                       goto fix_extent_len;
-               /* update the extent length and mark as initialized */
-               ex->ee_block = orig_ex.ee_block;
-               ex->ee_len   = orig_ex.ee_len;
-               ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
-               ext4_ext_dirty(handle, inode, path + depth);
-               /* zeroed the full extent */
-               return allocated;
-       }
+                       goto out;
 
-       /* ex1: ee_block to map->m_lblk - 1 : uninitialized */
-       if (map->m_lblk > ee_block) {
-               ex1 = ex;
-               ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
-               ext4_ext_mark_uninitialized(ex1);
-               ex2 = &newex;
+               err = ext4_ext_get_access(handle, inode, path + depth);
+               if (err)
+                       goto out;
+               ext4_ext_mark_initialized(ex);
+               ext4_ext_try_to_merge(inode, path, ex);
+               err = ext4_ext_dirty(handle, inode, path + depth);
+               goto out;
        }
+
        /*
-        * for sanity, update the length of the ex2 extent before
-        * we insert ex3, if ex1 is NULL. This is to avoid temporary
-        * overlap of blocks.
+        * four cases:
+        * 1. split the extent into three extents.
+        * 2. split the extent into two extents, zeroout the first half.
+        * 3. split the extent into two extents, zeroout the second half.
+        * 4. split the extent into two extents with out zeroout.
         */
-       if (!ex1 && allocated > map->m_len)
-               ex2->ee_len = cpu_to_le16(map->m_len);
-       /* ex3: to ee_block + ee_len : uninitialised */
-       if (allocated > map->m_len) {
-               unsigned int newdepth;
-               /* If extent has less than EXT4_EXT_ZERO_LEN zerout directly */
-               if (allocated <= EXT4_EXT_ZERO_LEN && may_zeroout) {
-                       /*
-                        * map->m_lblk == ee_block is handled by the zerouout
-                        * at the beginning.
-                        * Mark first half uninitialized.
-                        * Mark second half initialized and zero out the
-                        * initialized extent
-                        */
-                       ex->ee_block = orig_ex.ee_block;
-                       ex->ee_len   = cpu_to_le16(ee_len - allocated);
-                       ext4_ext_mark_uninitialized(ex);
-                       ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
-                       ext4_ext_dirty(handle, inode, path + depth);
-
-                       ex3 = &newex;
-                       ex3->ee_block = cpu_to_le32(map->m_lblk);
-                       ext4_ext_store_pblock(ex3, newblock);
-                       ex3->ee_len = cpu_to_le16(allocated);
-                       err = ext4_ext_insert_extent(handle, inode, path,
-                                                       ex3, 0);
-                       if (err == -ENOSPC) {
-                               err =  ext4_ext_zeroout(inode, &orig_ex);
-                               if (err)
-                                       goto fix_extent_len;
-                               ex->ee_block = orig_ex.ee_block;
-                               ex->ee_len   = orig_ex.ee_len;
-                               ext4_ext_store_pblock(ex,
-                                       ext4_ext_pblock(&orig_ex));
-                               ext4_ext_dirty(handle, inode, path + depth);
-                               /* blocks available from map->m_lblk */
-                               return allocated;
-
-                       } else if (err)
-                               goto fix_extent_len;
+       split_map.m_lblk = map->m_lblk;
+       split_map.m_len = map->m_len;
 
-                       /*
-                        * We need to zero out the second half because
-                        * an fallocate request can update file size and
-                        * converting the second half to initialized extent
-                        * implies that we can leak some junk data to user
-                        * space.
-                        */
-                       err =  ext4_ext_zeroout(inode, ex3);
-                       if (err) {
-                               /*
-                                * We should actually mark the
-                                * second half as uninit and return error
-                                * Insert would have changed the extent
-                                */
-                               depth = ext_depth(inode);
-                               ext4_ext_drop_refs(path);
-                               path = ext4_ext_find_extent(inode, map->m_lblk,
-                                                           path);
-                               if (IS_ERR(path)) {
-                                       err = PTR_ERR(path);
-                                       return err;
-                               }
-                               /* get the second half extent details */
-                               ex = path[depth].p_ext;
-                               err = ext4_ext_get_access(handle, inode,
-                                                               path + depth);
+       if (allocated > map->m_len) {
+               if (allocated <= EXT4_EXT_ZERO_LEN &&
+                   (EXT4_EXT_MAY_ZEROOUT & split_flag)) {
+                       /* case 3 */
+                       zero_ex.ee_block =
+                                        cpu_to_le32(map->m_lblk);
+                       zero_ex.ee_len = cpu_to_le16(allocated);
+                       ext4_ext_store_pblock(&zero_ex,
+                               ext4_ext_pblock(ex) + map->m_lblk - ee_block);
+                       err = ext4_ext_zeroout(inode, &zero_ex);
+                       if (err)
+                               goto out;
+                       split_map.m_lblk = map->m_lblk;
+                       split_map.m_len = allocated;
+               } else if ((map->m_lblk - ee_block + map->m_len <
+                          EXT4_EXT_ZERO_LEN) &&
+                          (EXT4_EXT_MAY_ZEROOUT & split_flag)) {
+                       /* case 2 */
+                       if (map->m_lblk != ee_block) {
+                               zero_ex.ee_block = ex->ee_block;
+                               zero_ex.ee_len = cpu_to_le16(map->m_lblk -
+                                                       ee_block);
+                               ext4_ext_store_pblock(&zero_ex,
+                                                     ext4_ext_pblock(ex));
+                               err = ext4_ext_zeroout(inode, &zero_ex);
                                if (err)
-                                       return err;
-                               ext4_ext_mark_uninitialized(ex);
-                               ext4_ext_dirty(handle, inode, path + depth);
-                               return err;
+                                       goto out;
                        }
 
-                       /* zeroed the second half */
-                       return allocated;
-               }
-               ex3 = &newex;
-               ex3->ee_block = cpu_to_le32(map->m_lblk + map->m_len);
-               ext4_ext_store_pblock(ex3, newblock + map->m_len);
-               ex3->ee_len = cpu_to_le16(allocated - map->m_len);
-               ext4_ext_mark_uninitialized(ex3);
-               err = ext4_ext_insert_extent(handle, inode, path, ex3, 0);
-               if (err == -ENOSPC && may_zeroout) {
-                       err =  ext4_ext_zeroout(inode, &orig_ex);
-                       if (err)
-                               goto fix_extent_len;
-                       /* update the extent length and mark as initialized */
-                       ex->ee_block = orig_ex.ee_block;
-                       ex->ee_len   = orig_ex.ee_len;
-                       ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
-                       ext4_ext_dirty(handle, inode, path + depth);
-                       /* zeroed the full extent */
-                       /* blocks available from map->m_lblk */
-                       return allocated;
-
-               } else if (err)
-                       goto fix_extent_len;
-               /*
-                * The depth, and hence eh & ex might change
-                * as part of the insert above.
-                */
-               newdepth = ext_depth(inode);
-               /*
-                * update the extent length after successful insert of the
-                * split extent
-                */
-               ee_len -= ext4_ext_get_actual_len(ex3);
-               orig_ex.ee_len = cpu_to_le16(ee_len);
-               may_zeroout = ee_block + ee_len <= eof_block;
-
-               depth = newdepth;
-               ext4_ext_drop_refs(path);
-               path = ext4_ext_find_extent(inode, map->m_lblk, path);
-               if (IS_ERR(path)) {
-                       err = PTR_ERR(path);
-                       goto out;
+                       split_map.m_lblk = ee_block;
+                       split_map.m_len = map->m_lblk - ee_block + map->m_len;
+                       allocated = map->m_len;
                }
-               eh = path[depth].p_hdr;
-               ex = path[depth].p_ext;
-               if (ex2 != &newex)
-                       ex2 = ex;
-
-               err = ext4_ext_get_access(handle, inode, path + depth);
-               if (err)
-                       goto out;
+       }
 
-               allocated = map->m_len;
+       allocated = ext4_split_extent(handle, inode, path,
+                                      &split_map, split_flag, 0);
+       if (allocated < 0)
+               err = allocated;
 
-               /* If extent has less than EXT4_EXT_ZERO_LEN and we are trying
-                * to insert a extent in the middle zerout directly
-                * otherwise give the extent a chance to merge to left
-                */
-               if (le16_to_cpu(orig_ex.ee_len) <= EXT4_EXT_ZERO_LEN &&
-                       map->m_lblk != ee_block && may_zeroout) {
-                       err =  ext4_ext_zeroout(inode, &orig_ex);
-                       if (err)
-                               goto fix_extent_len;
-                       /* update the extent length and mark as initialized */
-                       ex->ee_block = orig_ex.ee_block;
-                       ex->ee_len   = orig_ex.ee_len;
-                       ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
-                       ext4_ext_dirty(handle, inode, path + depth);
-                       /* zero out the first half */
-                       /* blocks available from map->m_lblk */
-                       return allocated;
-               }
-       }
-       /*
-        * If there was a change of depth as part of the
-        * insertion of ex3 above, we need to update the length
-        * of the ex1 extent again here
-        */
-       if (ex1 && ex1 != ex) {
-               ex1 = ex;
-               ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
-               ext4_ext_mark_uninitialized(ex1);
-               ex2 = &newex;
-       }
-       /* ex2: map->m_lblk to map->m_lblk + maxblocks-1 : initialised */
-       ex2->ee_block = cpu_to_le32(map->m_lblk);
-       ext4_ext_store_pblock(ex2, newblock);
-       ex2->ee_len = cpu_to_le16(allocated);
-       if (ex2 != ex)
-               goto insert;
-       /*
-        * New (initialized) extent starts from the first block
-        * in the current extent. i.e., ex2 == ex
-        * We have to see if it can be merged with the extent
-        * on the left.
-        */
-       if (ex2 > EXT_FIRST_EXTENT(eh)) {
-               /*
-                * To merge left, pass "ex2 - 1" to try_to_merge(),
-                * since it merges towards right _only_.
-                */
-               ret = ext4_ext_try_to_merge(inode, path, ex2 - 1);
-               if (ret) {
-                       err = ext4_ext_correct_indexes(handle, inode, path);
-                       if (err)
-                               goto out;
-                       depth = ext_depth(inode);
-                       ex2--;
-               }
-       }
-       /*
-        * Try to Merge towards right. This might be required
-        * only when the whole extent is being written to.
-        * i.e. ex2 == ex and ex3 == NULL.
-        */
-       if (!ex3) {
-               ret = ext4_ext_try_to_merge(inode, path, ex2);
-               if (ret) {
-                       err = ext4_ext_correct_indexes(handle, inode, path);
-                       if (err)
-                               goto out;
-               }
-       }
-       /* Mark modified extent as dirty */
-       err = ext4_ext_dirty(handle, inode, path + depth);
-       goto out;
-insert:
-       err = ext4_ext_insert_extent(handle, inode, path, &newex, 0);
-       if (err == -ENOSPC && may_zeroout) {
-               err =  ext4_ext_zeroout(inode, &orig_ex);
-               if (err)
-                       goto fix_extent_len;
-               /* update the extent length and mark as initialized */
-               ex->ee_block = orig_ex.ee_block;
-               ex->ee_len   = orig_ex.ee_len;
-               ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
-               ext4_ext_dirty(handle, inode, path + depth);
-               /* zero out the first half */
-               return allocated;
-       } else if (err)
-               goto fix_extent_len;
 out:
-       ext4_ext_show_leaf(inode, path);
        return err ? err : allocated;
-
-fix_extent_len:
-       ex->ee_block = orig_ex.ee_block;
-       ex->ee_len   = orig_ex.ee_len;
-       ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
-       ext4_ext_mark_uninitialized(ex);
-       ext4_ext_dirty(handle, inode, path + depth);
-       return err;
 }
 
 /*
@@ -2871,15 +3072,11 @@ static int ext4_split_unwritten_extents(handle_t *handle,
                                        struct ext4_ext_path *path,
                                        int flags)
 {
-       struct ext4_extent *ex, newex, orig_ex;
-       struct ext4_extent *ex1 = NULL;
-       struct ext4_extent *ex2 = NULL;
-       struct ext4_extent *ex3 = NULL;
-       ext4_lblk_t ee_block, eof_block;
-       unsigned int allocated, ee_len, depth;
-       ext4_fsblk_t newblock;
-       int err = 0;
-       int may_zeroout;
+       ext4_lblk_t eof_block;
+       ext4_lblk_t ee_block;
+       struct ext4_extent *ex;
+       unsigned int ee_len;
+       int split_flag = 0, depth;
 
        ext_debug("ext4_split_unwritten_extents: inode %lu, logical"
                "block %llu, max_blocks %u\n", inode->i_ino,
@@ -2889,156 +3086,22 @@ static int ext4_split_unwritten_extents(handle_t *handle,
                inode->i_sb->s_blocksize_bits;
        if (eof_block < map->m_lblk + map->m_len)
                eof_block = map->m_lblk + map->m_len;
-
-       depth = ext_depth(inode);
-       ex = path[depth].p_ext;
-       ee_block = le32_to_cpu(ex->ee_block);
-       ee_len = ext4_ext_get_actual_len(ex);
-       allocated = ee_len - (map->m_lblk - ee_block);
-       newblock = map->m_lblk - ee_block + ext4_ext_pblock(ex);
-
-       ex2 = ex;
-       orig_ex.ee_block = ex->ee_block;
-       orig_ex.ee_len   = cpu_to_le16(ee_len);
-       ext4_ext_store_pblock(&orig_ex, ext4_ext_pblock(ex));
-
        /*
         * It is safe to convert extent to initialized via explicit
         * zeroout only if extent is fully insde i_size or new_size.
         */
-       may_zeroout = ee_block + ee_len <= eof_block;
-
-       /*
-        * If the uninitialized extent begins at the same logical
-        * block where the write begins, and the write completely
-        * covers the extent, then we don't need to split it.
-        */
-       if ((map->m_lblk == ee_block) && (allocated <= map->m_len))
-               return allocated;
-
-       err = ext4_ext_get_access(handle, inode, path + depth);
-       if (err)
-               goto out;
-       /* ex1: ee_block to map->m_lblk - 1 : uninitialized */
-       if (map->m_lblk > ee_block) {
-               ex1 = ex;
-               ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
-               ext4_ext_mark_uninitialized(ex1);
-               ex2 = &newex;
-       }
-       /*
-        * for sanity, update the length of the ex2 extent before
-        * we insert ex3, if ex1 is NULL. This is to avoid temporary
-        * overlap of blocks.
-        */
-       if (!ex1 && allocated > map->m_len)
-               ex2->ee_len = cpu_to_le16(map->m_len);
-       /* ex3: to ee_block + ee_len : uninitialised */
-       if (allocated > map->m_len) {
-               unsigned int newdepth;
-               ex3 = &newex;
-               ex3->ee_block = cpu_to_le32(map->m_lblk + map->m_len);
-               ext4_ext_store_pblock(ex3, newblock + map->m_len);
-               ex3->ee_len = cpu_to_le16(allocated - map->m_len);
-               ext4_ext_mark_uninitialized(ex3);
-               err = ext4_ext_insert_extent(handle, inode, path, ex3, flags);
-               if (err == -ENOSPC && may_zeroout) {
-                       err =  ext4_ext_zeroout(inode, &orig_ex);
-                       if (err)
-                               goto fix_extent_len;
-                       /* update the extent length and mark as initialized */
-                       ex->ee_block = orig_ex.ee_block;
-                       ex->ee_len   = orig_ex.ee_len;
-                       ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
-                       ext4_ext_dirty(handle, inode, path + depth);
-                       /* zeroed the full extent */
-                       /* blocks available from map->m_lblk */
-                       return allocated;
-
-               } else if (err)
-                       goto fix_extent_len;
-               /*
-                * The depth, and hence eh & ex might change
-                * as part of the insert above.
-                */
-               newdepth = ext_depth(inode);
-               /*
-                * update the extent length after successful insert of the
-                * split extent
-                */
-               ee_len -= ext4_ext_get_actual_len(ex3);
-               orig_ex.ee_len = cpu_to_le16(ee_len);
-               may_zeroout = ee_block + ee_len <= eof_block;
-
-               depth = newdepth;
-               ext4_ext_drop_refs(path);
-               path = ext4_ext_find_extent(inode, map->m_lblk, path);
-               if (IS_ERR(path)) {
-                       err = PTR_ERR(path);
-                       goto out;
-               }
-               ex = path[depth].p_ext;
-               if (ex2 != &newex)
-                       ex2 = ex;
-
-               err = ext4_ext_get_access(handle, inode, path + depth);
-               if (err)
-                       goto out;
+       depth = ext_depth(inode);
+       ex = path[depth].p_ext;
+       ee_block = le32_to_cpu(ex->ee_block);
+       ee_len = ext4_ext_get_actual_len(ex);
 
-               allocated = map->m_len;
-       }
-       /*
-        * If there was a change of depth as part of the
-        * insertion of ex3 above, we need to update the length
-        * of the ex1 extent again here
-        */
-       if (ex1 && ex1 != ex) {
-               ex1 = ex;
-               ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
-               ext4_ext_mark_uninitialized(ex1);
-               ex2 = &newex;
-       }
-       /*
-        * ex2: map->m_lblk to map->m_lblk + map->m_len-1 : to be written
-        * using direct I/O, uninitialised still.
-        */
-       ex2->ee_block = cpu_to_le32(map->m_lblk);
-       ext4_ext_store_pblock(ex2, newblock);
-       ex2->ee_len = cpu_to_le16(allocated);
-       ext4_ext_mark_uninitialized(ex2);
-       if (ex2 != ex)
-               goto insert;
-       /* Mark modified extent as dirty */
-       err = ext4_ext_dirty(handle, inode, path + depth);
-       ext_debug("out here\n");
-       goto out;
-insert:
-       err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
-       if (err == -ENOSPC && may_zeroout) {
-               err =  ext4_ext_zeroout(inode, &orig_ex);
-               if (err)
-                       goto fix_extent_len;
-               /* update the extent length and mark as initialized */
-               ex->ee_block = orig_ex.ee_block;
-               ex->ee_len   = orig_ex.ee_len;
-               ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
-               ext4_ext_dirty(handle, inode, path + depth);
-               /* zero out the first half */
-               return allocated;
-       } else if (err)
-               goto fix_extent_len;
-out:
-       ext4_ext_show_leaf(inode, path);
-       return err ? err : allocated;
+       split_flag |= ee_block + ee_len <= eof_block ? EXT4_EXT_MAY_ZEROOUT : 0;
+       split_flag |= EXT4_EXT_MARK_UNINIT2;
 
-fix_extent_len:
-       ex->ee_block = orig_ex.ee_block;
-       ex->ee_len   = orig_ex.ee_len;
-       ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
-       ext4_ext_mark_uninitialized(ex);
-       ext4_ext_dirty(handle, inode, path + depth);
-       return err;
+       flags |= EXT4_GET_BLOCKS_PRE_IO;
+       return ext4_split_extent(handle, inode, path, map, split_flag, flags);
 }
+
 static int ext4_convert_unwritten_extents_endio(handle_t *handle,
                                              struct inode *inode,
                                              struct ext4_ext_path *path)
@@ -3047,46 +3110,27 @@ static int ext4_convert_unwritten_extents_endio(handle_t *handle,
        struct ext4_extent_header *eh;
        int depth;
        int err = 0;
-       int ret = 0;
 
        depth = ext_depth(inode);
        eh = path[depth].p_hdr;
        ex = path[depth].p_ext;
 
+       ext_debug("ext4_convert_unwritten_extents_endio: inode %lu, logical"
+               "block %llu, max_blocks %u\n", inode->i_ino,
+               (unsigned long long)le32_to_cpu(ex->ee_block),
+               ext4_ext_get_actual_len(ex));
+
        err = ext4_ext_get_access(handle, inode, path + depth);
        if (err)
                goto out;
        /* first mark the extent as initialized */
        ext4_ext_mark_initialized(ex);
 
-       /*
-        * We have to see if it can be merged with the extent
-        * on the left.
-        */
-       if (ex > EXT_FIRST_EXTENT(eh)) {
-               /*
-                * To merge left, pass "ex - 1" to try_to_merge(),
-                * since it merges towards right _only_.
-                */
-               ret = ext4_ext_try_to_merge(inode, path, ex - 1);
-               if (ret) {
-                       err = ext4_ext_correct_indexes(handle, inode, path);
-                       if (err)
-                               goto out;
-                       depth = ext_depth(inode);
-                       ex--;
-               }
-       }
-       /*
-        * Try to Merge towards right.
+       /* note: ext4_ext_correct_indexes() isn't needed here because
+        * borders are not changed
         */
-       ret = ext4_ext_try_to_merge(inode, path, ex);
-       if (ret) {
-               err = ext4_ext_correct_indexes(handle, inode, path);
-               if (err)
-                       goto out;
-               depth = ext_depth(inode);
-       }
+       ext4_ext_try_to_merge(inode, path, ex);
+
        /* Mark modified extent as dirty */
        err = ext4_ext_dirty(handle, inode, path + depth);
 out:
@@ -3302,15 +3346,19 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
        ext4_fsblk_t newblock = 0;
        int err = 0, depth, ret;
        unsigned int allocated = 0;
+       unsigned int punched_out = 0;
+       unsigned int result = 0;
        struct ext4_allocation_request ar;
        ext4_io_end_t *io = EXT4_I(inode)->cur_aio_dio;
+       struct ext4_map_blocks punch_map;
 
        ext_debug("blocks %u/%u requested for inode %lu\n",
                  map->m_lblk, map->m_len, inode->i_ino);
        trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags);
 
        /* check in cache */
-       if (ext4_ext_in_cache(inode, map->m_lblk, &newex)) {
+       if (ext4_ext_in_cache(inode, map->m_lblk, &newex) &&
+               ((flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) == 0)) {
                if (!newex.ee_start_lo && !newex.ee_start_hi) {
                        if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
                                /*
@@ -3375,16 +3423,84 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
                        ext_debug("%u fit into %u:%d -> %llu\n", map->m_lblk,
                                  ee_block, ee_len, newblock);
 
-                       /* Do not put uninitialized extent in the cache */
-                       if (!ext4_ext_is_uninitialized(ex)) {
-                               ext4_ext_put_in_cache(inode, ee_block,
-                                                       ee_len, ee_start);
-                               goto out;
+                       if ((flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) == 0) {
+                               /*
+                                * Do not put uninitialized extent
+                                * in the cache
+                                */
+                               if (!ext4_ext_is_uninitialized(ex)) {
+                                       ext4_ext_put_in_cache(inode, ee_block,
+                                               ee_len, ee_start);
+                                       goto out;
+                               }
+                               ret = ext4_ext_handle_uninitialized_extents(
+                                       handle, inode, map, path, flags,
+                                       allocated, newblock);
+                               return ret;
                        }
-                       ret = ext4_ext_handle_uninitialized_extents(handle,
-                                       inode, map, path, flags, allocated,
-                                       newblock);
-                       return ret;
+
+                       /*
+                        * Punch out the map length, but only to the
+                        * end of the extent
+                        */
+                       punched_out = allocated < map->m_len ?
+                               allocated : map->m_len;
+
+                       /*
+                        * Sense extents need to be converted to
+                        * uninitialized, they must fit in an
+                        * uninitialized extent
+                        */
+                       if (punched_out > EXT_UNINIT_MAX_LEN)
+                               punched_out = EXT_UNINIT_MAX_LEN;
+
+                       punch_map.m_lblk = map->m_lblk;
+                       punch_map.m_pblk = newblock;
+                       punch_map.m_len = punched_out;
+                       punch_map.m_flags = 0;
+
+                       /* Check to see if the extent needs to be split */
+                       if (punch_map.m_len != ee_len ||
+                               punch_map.m_lblk != ee_block) {
+
+                               ret = ext4_split_extent(handle, inode,
+                               path, &punch_map, 0,
+                               EXT4_GET_BLOCKS_PUNCH_OUT_EXT |
+                               EXT4_GET_BLOCKS_PRE_IO);
+
+                               if (ret < 0) {
+                                       err = ret;
+                                       goto out2;
+                               }
+                               /*
+                                * find extent for the block at
+                                * the start of the hole
+                                */
+                               ext4_ext_drop_refs(path);
+                               kfree(path);
+
+                               path = ext4_ext_find_extent(inode,
+                               map->m_lblk, NULL);
+                               if (IS_ERR(path)) {
+                                       err = PTR_ERR(path);
+                                       path = NULL;
+                                       goto out2;
+                               }
+
+                               depth = ext_depth(inode);
+                               ex = path[depth].p_ext;
+                               ee_len = ext4_ext_get_actual_len(ex);
+                               ee_block = le32_to_cpu(ex->ee_block);
+                               ee_start = ext4_ext_pblock(ex);
+
+                       }
+
+                       ext4_ext_mark_uninitialized(ex);
+
+                       err = ext4_ext_remove_space(inode, map->m_lblk,
+                               map->m_lblk + punched_out);
+
+                       goto out2;
                }
        }
 
@@ -3446,6 +3562,8 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
        else
                /* disable in-core preallocation for non-regular files */
                ar.flags = 0;
+       if (flags & EXT4_GET_BLOCKS_NO_NORMALIZE)
+               ar.flags |= EXT4_MB_HINT_NOPREALLOC;
        newblock = ext4_mb_new_blocks(handle, &ar, &err);
        if (!newblock)
                goto out2;
@@ -3529,7 +3647,11 @@ out2:
        }
        trace_ext4_ext_map_blocks_exit(inode, map->m_lblk,
                newblock, map->m_len, err ? err : allocated);
-       return err ? err : allocated;
+
+       result = (flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) ?
+                       punched_out : allocated;
+
+       return err ? err : result;
 }
 
 void ext4_ext_truncate(struct inode *inode)
@@ -3577,7 +3699,7 @@ void ext4_ext_truncate(struct inode *inode)
 
        last_block = (inode->i_size + sb->s_blocksize - 1)
                        >> EXT4_BLOCK_SIZE_BITS(sb);
-       err = ext4_ext_remove_space(inode, last_block);
+       err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1);
 
        /* In a multi-transaction truncate, we only make the final
         * transaction synchronous.
@@ -3585,8 +3707,9 @@ void ext4_ext_truncate(struct inode *inode)
        if (IS_SYNC(inode))
                ext4_handle_sync(handle);
 
-out_stop:
        up_write(&EXT4_I(inode)->i_data_sem);
+
+out_stop:
        /*
         * If this was a simple ftruncate() and the file will remain alive,
         * then we need to clear up the orphan record which we created above.
@@ -3651,10 +3774,6 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
        struct ext4_map_blocks map;
        unsigned int credits, blkbits = inode->i_blkbits;
 
-       /* We only support the FALLOC_FL_KEEP_SIZE mode */
-       if (mode & ~FALLOC_FL_KEEP_SIZE)
-               return -EOPNOTSUPP;
-
        /*
         * currently supporting (pre)allocate mode for extent-based
         * files _only_
@@ -3662,6 +3781,13 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
        if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
                return -EOPNOTSUPP;
 
+       /* Return error if mode is not supported */
+       if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
+               return -EOPNOTSUPP;
+
+       if (mode & FALLOC_FL_PUNCH_HOLE)
+               return ext4_punch_hole(file, offset, len);
+
        trace_ext4_fallocate_enter(inode, offset, len, mode);
        map.m_lblk = offset >> blkbits;
        /*
@@ -3691,7 +3817,8 @@ retry:
                        break;
                }
                ret = ext4_map_blocks(handle, inode, &map,
-                                     EXT4_GET_BLOCKS_CREATE_UNINIT_EXT);
+                                     EXT4_GET_BLOCKS_CREATE_UNINIT_EXT |
+                                     EXT4_GET_BLOCKS_NO_NORMALIZE);
                if (ret <= 0) {
 #ifdef EXT4FS_DEBUG
                        WARN_ON(ret <= 0);
@@ -3787,14 +3914,13 @@ int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset,
 /*
  * Callback function called for each extent to gather FIEMAP information.
  */
-static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
+static int ext4_ext_fiemap_cb(struct inode *inode, ext4_lblk_t next,
                       struct ext4_ext_cache *newex, struct ext4_extent *ex,
                       void *data)
 {
        __u64   logical;
        __u64   physical;
        __u64   length;
-       loff_t  size;
        __u32   flags = 0;
        int             ret = 0;
        struct fiemap_extent_info *fieinfo = data;
@@ -3822,6 +3948,7 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
                pgoff_t         last_offset;
                pgoff_t         offset;
                pgoff_t         index;
+               pgoff_t         start_index = 0;
                struct page     **pages = NULL;
                struct buffer_head *bh = NULL;
                struct buffer_head *head = NULL;
@@ -3848,39 +3975,57 @@ out:
                                kfree(pages);
                                return EXT_CONTINUE;
                        }
+                       index = 0;
 
+next_page:
                        /* Try to find the 1st mapped buffer. */
-                       end = ((__u64)pages[0]->index << PAGE_SHIFT) >>
+                       end = ((__u64)pages[index]->index << PAGE_SHIFT) >>
                                  blksize_bits;
-                       if (!page_has_buffers(pages[0]))
+                       if (!page_has_buffers(pages[index]))
                                goto out;
-                       head = page_buffers(pages[0]);
+                       head = page_buffers(pages[index]);
                        if (!head)
                                goto out;
 
+                       index++;
                        bh = head;
                        do {
-                               if (buffer_mapped(bh)) {
+                               if (end >= newex->ec_block +
+                                       newex->ec_len)
+                                       /* The buffer is out of
+                                        * the request range.
+                                        */
+                                       goto out;
+
+                               if (buffer_mapped(bh) &&
+                                   end >= newex->ec_block) {
+                                       start_index = index - 1;
                                        /* get the 1st mapped buffer. */
-                                       if (end > newex->ec_block +
-                                               newex->ec_len)
-                                               /* The buffer is out of
-                                                * the request range.
-                                                */
-                                               goto out;
                                        goto found_mapped_buffer;
                                }
+
                                bh = bh->b_this_page;
                                end++;
                        } while (bh != head);
 
-                       /* No mapped buffer found. */
-                       goto out;
+                       /* No mapped buffer in the range found in this page,
+                        * We need to look up next page.
+                        */
+                       if (index >= ret) {
+                               /* There is no page left, but we need to limit
+                                * newex->ec_len.
+                                */
+                               newex->ec_len = end - newex->ec_block;
+                               goto out;
+                       }
+                       goto next_page;
                } else {
                        /*Find contiguous delayed buffers. */
                        if (ret > 0 && pages[0]->index == last_offset)
                                head = page_buffers(pages[0]);
                        bh = head;
+                       index = 1;
+                       start_index = 0;
                }
 
 found_mapped_buffer:
@@ -3903,7 +4048,7 @@ found_mapped_buffer:
                                end++;
                        } while (bh != head);
 
-                       for (index = 1; index < ret; index++) {
+                       for (; index < ret; index++) {
                                if (!page_has_buffers(pages[index])) {
                                        bh = NULL;
                                        break;
@@ -3913,8 +4058,10 @@ found_mapped_buffer:
                                        bh = NULL;
                                        break;
                                }
+
                                if (pages[index]->index !=
-                                       pages[0]->index + index) {
+                                   pages[start_index]->index + index
+                                   - start_index) {
                                        /* Blocks are not contiguous. */
                                        bh = NULL;
                                        break;
@@ -3955,8 +4102,7 @@ found_delayed_extent:
        if (ex && ext4_ext_is_uninitialized(ex))
                flags |= FIEMAP_EXTENT_UNWRITTEN;
 
-       size = i_size_read(inode);
-       if (logical + length >= size)
+       if (next == EXT_MAX_BLOCKS)
                flags |= FIEMAP_EXTENT_LAST;
 
        ret = fiemap_fill_next_extent(fieinfo, logical, physical,
@@ -4006,6 +4152,177 @@ static int ext4_xattr_fiemap(struct inode *inode,
        return (error < 0 ? error : 0);
 }
 
+/*
+ * ext4_ext_punch_hole
+ *
+ * Punches a hole of "length" bytes in a file starting
+ * at byte "offset"
+ *
+ * @inode:  The inode of the file to punch a hole in
+ * @offset: The starting byte offset of the hole
+ * @length: The length of the hole
+ *
+ * Returns the number of blocks removed or negative on err
+ */
+int ext4_ext_punch_hole(struct file *file, loff_t offset, loff_t length)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct super_block *sb = inode->i_sb;
+       struct ext4_ext_cache cache_ex;
+       ext4_lblk_t first_block, last_block, num_blocks, iblock, max_blocks;
+       struct address_space *mapping = inode->i_mapping;
+       struct ext4_map_blocks map;
+       handle_t *handle;
+       loff_t first_block_offset, last_block_offset, block_len;
+       loff_t first_page, last_page, first_page_offset, last_page_offset;
+       int ret, credits, blocks_released, err = 0;
+
+       first_block = (offset + sb->s_blocksize - 1) >>
+               EXT4_BLOCK_SIZE_BITS(sb);
+       last_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb);
+
+       first_block_offset = first_block << EXT4_BLOCK_SIZE_BITS(sb);
+       last_block_offset = last_block << EXT4_BLOCK_SIZE_BITS(sb);
+
+       first_page = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       last_page = (offset + length) >> PAGE_CACHE_SHIFT;
+
+       first_page_offset = first_page << PAGE_CACHE_SHIFT;
+       last_page_offset = last_page << PAGE_CACHE_SHIFT;
+
+       /*
+        * Write out all dirty pages to avoid race conditions
+        * Then release them.
+        */
+       if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
+               err = filemap_write_and_wait_range(mapping,
+                       first_page_offset == 0 ? 0 : first_page_offset-1,
+                       last_page_offset);
+
+                       if (err)
+                               return err;
+       }
+
+       /* Now release the pages */
+       if (last_page_offset > first_page_offset) {
+               truncate_inode_pages_range(mapping, first_page_offset,
+                                          last_page_offset-1);
+       }
+
+       /* finish any pending end_io work */
+       ext4_flush_completed_IO(inode);
+
+       credits = ext4_writepage_trans_blocks(inode);
+       handle = ext4_journal_start(inode, credits);
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+
+       err = ext4_orphan_add(handle, inode);
+       if (err)
+               goto out;
+
+       /*
+        * Now we need to zero out the un block aligned data.
+        * If the file is smaller than a block, just
+        * zero out the middle
+        */
+       if (first_block > last_block)
+               ext4_block_zero_page_range(handle, mapping, offset, length);
+       else {
+               /* zero out the head of the hole before the first block */
+               block_len  = first_block_offset - offset;
+               if (block_len > 0)
+                       ext4_block_zero_page_range(handle, mapping,
+                                                  offset, block_len);
+
+               /* zero out the tail of the hole after the last block */
+               block_len = offset + length - last_block_offset;
+               if (block_len > 0) {
+                       ext4_block_zero_page_range(handle, mapping,
+                                       last_block_offset, block_len);
+               }
+       }
+
+       /* If there are no blocks to remove, return now */
+       if (first_block >= last_block)
+               goto out;
+
+       down_write(&EXT4_I(inode)->i_data_sem);
+       ext4_ext_invalidate_cache(inode);
+       ext4_discard_preallocations(inode);
+
+       /*
+        * Loop over all the blocks and identify blocks
+        * that need to be punched out
+        */
+       iblock = first_block;
+       blocks_released = 0;
+       while (iblock < last_block) {
+               max_blocks = last_block - iblock;
+               num_blocks = 1;
+               memset(&map, 0, sizeof(map));
+               map.m_lblk = iblock;
+               map.m_len = max_blocks;
+               ret = ext4_ext_map_blocks(handle, inode, &map,
+                       EXT4_GET_BLOCKS_PUNCH_OUT_EXT);
+
+               if (ret > 0) {
+                       blocks_released += ret;
+                       num_blocks = ret;
+               } else if (ret == 0) {
+                       /*
+                        * If map blocks could not find the block,
+                        * then it is in a hole.  If the hole was
+                        * not already cached, then map blocks should
+                        * put it in the cache.  So we can get the hole
+                        * out of the cache
+                        */
+                       memset(&cache_ex, 0, sizeof(cache_ex));
+                       if ((ext4_ext_check_cache(inode, iblock, &cache_ex)) &&
+                               !cache_ex.ec_start) {
+
+                               /* The hole is cached */
+                               num_blocks = cache_ex.ec_block +
+                               cache_ex.ec_len - iblock;
+
+                       } else {
+                               /* The block could not be identified */
+                               err = -EIO;
+                               break;
+                       }
+               } else {
+                       /* Map blocks error */
+                       err = ret;
+                       break;
+               }
+
+               if (num_blocks == 0) {
+                       /* This condition should never happen */
+                       ext_debug("Block lookup failed");
+                       err = -EIO;
+                       break;
+               }
+
+               iblock += num_blocks;
+       }
+
+       if (blocks_released > 0) {
+               ext4_ext_invalidate_cache(inode);
+               ext4_discard_preallocations(inode);
+       }
+
+       if (IS_SYNC(inode))
+               ext4_handle_sync(handle);
+
+       up_write(&EXT4_I(inode)->i_data_sem);
+
+out:
+       ext4_orphan_del(handle, inode);
+       inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
+       ext4_mark_inode_dirty(handle, inode);
+       ext4_journal_stop(handle);
+       return err;
+}
 int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                __u64 start, __u64 len)
 {
@@ -4028,8 +4345,8 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 
                start_blk = start >> inode->i_sb->s_blocksize_bits;
                last_blk = (start + len - 1) >> inode->i_sb->s_blocksize_bits;
-               if (last_blk >= EXT_MAX_BLOCK)
-                       last_blk = EXT_MAX_BLOCK-1;
+               if (last_blk >= EXT_MAX_BLOCKS)
+                       last_blk = EXT_MAX_BLOCKS-1;
                len_blks = ((ext4_lblk_t) last_blk) - start_blk + 1;
 
                /*
@@ -4042,4 +4359,3 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 
        return error;
 }
-
index 7b80d543b89e71c41764b54a5d6eee59992c712c..2c09723220091f7520b5a9c04622e1d788b9b1c4 100644 (file)
@@ -272,7 +272,6 @@ const struct file_operations ext4_file_operations = {
 };
 
 const struct inode_operations ext4_file_inode_operations = {
-       .truncate       = ext4_truncate,
        .setattr        = ext4_setattr,
        .getattr        = ext4_getattr,
 #ifdef CONFIG_EXT4_FS_XATTR
index e9473cbe80dfd00a7245e13f4de57229011a7bb2..ce66d2fe826cbdf99389dea50aa3f72240e911d9 100644 (file)
@@ -36,7 +36,7 @@
 
 static void dump_completed_IO(struct inode * inode)
 {
-#ifdef EXT4_DEBUG
+#ifdef EXT4FS_DEBUG
        struct list_head *cur, *before, *after;
        ext4_io_end_t *io, *io0, *io1;
        unsigned long flags;
@@ -172,6 +172,7 @@ int ext4_sync_file(struct file *file, int datasync)
        journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
        int ret;
        tid_t commit_tid;
+       bool needs_barrier = false;
 
        J_ASSERT(ext4_journal_current_handle() == NULL);
 
@@ -211,22 +212,12 @@ int ext4_sync_file(struct file *file, int datasync)
        }
 
        commit_tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid;
-       if (jbd2_log_start_commit(journal, commit_tid)) {
-               /*
-                * When the journal is on a different device than the
-                * fs data disk, we need to issue the barrier in
-                * writeback mode.  (In ordered mode, the jbd2 layer
-                * will take care of issuing the barrier.  In
-                * data=journal, all of the data blocks are written to
-                * the journal device.)
-                */
-               if (ext4_should_writeback_data(inode) &&
-                   (journal->j_fs_dev != journal->j_dev) &&
-                   (journal->j_flags & JBD2_BARRIER))
-                       blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL,
-                                       NULL);
-               ret = jbd2_log_wait_commit(journal, commit_tid);
-       } else if (journal->j_flags & JBD2_BARRIER)
+       if (journal->j_flags & JBD2_BARRIER &&
+           !jbd2_trans_will_send_data_barrier(journal, commit_tid))
+               needs_barrier = true;
+       jbd2_log_start_commit(journal, commit_tid);
+       ret = jbd2_log_wait_commit(journal, commit_tid);
+       if (needs_barrier)
                blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
  out:
        trace_ext4_sync_file_exit(inode, ret);
index f2fa5e8a582caf92dba32df3cfad714920a85721..e3126c0510066fec7fe8bd0d46123aa1af16388c 100644 (file)
@@ -639,8 +639,8 @@ static int ext4_alloc_blocks(handle_t *handle, struct inode *inode,
        while (target > 0) {
                count = target;
                /* allocating blocks for indirect blocks and direct blocks */
-               current_block = ext4_new_meta_blocks(handle, inode,
-                                                       goal, &count, err);
+               current_block = ext4_new_meta_blocks(handle, inode, goal,
+                                                    0, &count, err);
                if (*err)
                        goto failed_out;
 
@@ -1930,7 +1930,7 @@ repeat:
         * We do still charge estimated metadata to the sb though;
         * we cannot afford to run out of free blocks.
         */
-       if (ext4_claim_free_blocks(sbi, md_needed + 1)) {
+       if (ext4_claim_free_blocks(sbi, md_needed + 1, 0)) {
                dquot_release_reservation_block(inode, 1);
                if (ext4_should_retry_alloc(inode->i_sb, &retries)) {
                        yield();
@@ -2634,7 +2634,7 @@ static int ext4_writepage(struct page *page,
        struct buffer_head *page_bufs = NULL;
        struct inode *inode = page->mapping->host;
 
-       trace_ext4_writepage(inode, page);
+       trace_ext4_writepage(page);
        size = i_size_read(inode);
        if (page->index == size >> PAGE_CACHE_SHIFT)
                len = size & ~PAGE_CACHE_MASK;
@@ -2796,9 +2796,7 @@ static int write_cache_pages_da(struct address_space *mapping,
                                continue;
                        }
 
-                       if (PageWriteback(page))
-                               wait_on_page_writeback(page);
-
+                       wait_on_page_writeback(page);
                        BUG_ON(PageWriteback(page));
 
                        if (mpd->next_page != page->index)
@@ -3513,7 +3511,7 @@ retry:
                        loff_t end = offset + iov_length(iov, nr_segs);
 
                        if (end > isize)
-                               vmtruncate(inode, isize);
+                               ext4_truncate_failed_write(inode);
                }
        }
        if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
@@ -3915,10 +3913,31 @@ void ext4_set_aops(struct inode *inode)
  */
 int ext4_block_truncate_page(handle_t *handle,
                struct address_space *mapping, loff_t from)
+{
+       unsigned offset = from & (PAGE_CACHE_SIZE-1);
+       unsigned length;
+       unsigned blocksize;
+       struct inode *inode = mapping->host;
+
+       blocksize = inode->i_sb->s_blocksize;
+       length = blocksize - (offset & (blocksize - 1));
+
+       return ext4_block_zero_page_range(handle, mapping, from, length);
+}
+
+/*
+ * ext4_block_zero_page_range() zeros out a mapping of length 'length'
+ * starting from file offset 'from'.  The range to be zero'd must
+ * be contained with in one block.  If the specified range exceeds
+ * the end of the block it will be shortened to end of the block
+ * that cooresponds to 'from'
+ */
+int ext4_block_zero_page_range(handle_t *handle,
+               struct address_space *mapping, loff_t from, loff_t length)
 {
        ext4_fsblk_t index = from >> PAGE_CACHE_SHIFT;
        unsigned offset = from & (PAGE_CACHE_SIZE-1);
-       unsigned blocksize, length, pos;
+       unsigned blocksize, max, pos;
        ext4_lblk_t iblock;
        struct inode *inode = mapping->host;
        struct buffer_head *bh;
@@ -3931,7 +3950,15 @@ int ext4_block_truncate_page(handle_t *handle,
                return -EINVAL;
 
        blocksize = inode->i_sb->s_blocksize;
-       length = blocksize - (offset & (blocksize - 1));
+       max = blocksize - (offset & (blocksize - 1));
+
+       /*
+        * correct length if it does not fall between
+        * 'from' and the end of the block
+        */
+       if (length > max || length < 0)
+               length = max;
+
        iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
 
        if (!page_has_buffers(page))
@@ -4380,8 +4407,6 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
 
 int ext4_can_truncate(struct inode *inode)
 {
-       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
-               return 0;
        if (S_ISREG(inode->i_mode))
                return 1;
        if (S_ISDIR(inode->i_mode))
@@ -4391,6 +4416,31 @@ int ext4_can_truncate(struct inode *inode)
        return 0;
 }
 
+/*
+ * ext4_punch_hole: punches a hole in a file by releaseing the blocks
+ * associated with the given offset and length
+ *
+ * @inode:  File inode
+ * @offset: The offset where the hole will begin
+ * @len:    The length of the hole
+ *
+ * Returns: 0 on sucess or negative on failure
+ */
+
+int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       if (!S_ISREG(inode->i_mode))
+               return -ENOTSUPP;
+
+       if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
+               /* TODO: Add support for non extent hole punching */
+               return -ENOTSUPP;
+       }
+
+       return ext4_ext_punch_hole(file, offset, length);
+}
+
 /*
  * ext4_truncate()
  *
@@ -4617,7 +4667,7 @@ static int __ext4_get_inode_loc(struct inode *inode,
        /*
         * Figure out the offset within the block group inode table
         */
-       inodes_per_block = (EXT4_BLOCK_SIZE(sb) / EXT4_INODE_SIZE(sb));
+       inodes_per_block = EXT4_SB(sb)->s_inodes_per_block;
        inode_offset = ((inode->i_ino - 1) %
                        EXT4_INODES_PER_GROUP(sb));
        block = ext4_inode_table(sb, gdp) + (inode_offset / inodes_per_block);
@@ -5311,8 +5361,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
 
        if (S_ISREG(inode->i_mode) &&
            attr->ia_valid & ATTR_SIZE &&
-           (attr->ia_size < inode->i_size ||
-            (ext4_test_inode_flag(inode, EXT4_INODE_EOFBLOCKS)))) {
+           (attr->ia_size < inode->i_size)) {
                handle_t *handle;
 
                handle = ext4_journal_start(inode, 3);
@@ -5346,14 +5395,15 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
                                goto err_out;
                        }
                }
-               /* ext4_truncate will clear the flag */
-               if ((ext4_test_inode_flag(inode, EXT4_INODE_EOFBLOCKS)))
-                       ext4_truncate(inode);
        }
 
-       if ((attr->ia_valid & ATTR_SIZE) &&
-           attr->ia_size != i_size_read(inode))
-               rc = vmtruncate(inode, attr->ia_size);
+       if (attr->ia_valid & ATTR_SIZE) {
+               if (attr->ia_size != i_size_read(inode)) {
+                       truncate_setsize(inode, attr->ia_size);
+                       ext4_truncate(inode);
+               } else if (ext4_test_inode_flag(inode, EXT4_INODE_EOFBLOCKS))
+                       ext4_truncate(inode);
+       }
 
        if (!rc) {
                setattr_copy(inode, attr);
@@ -5683,7 +5733,7 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
  * so would cause a commit on atime updates, which we don't bother doing.
  * We handle synchronous inodes at the highest possible level.
  */
-void ext4_dirty_inode(struct inode *inode)
+void ext4_dirty_inode(struct inode *inode, int flags)
 {
        handle_t *handle;
 
@@ -5811,15 +5861,19 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
                goto out_unlock;
        }
        ret = 0;
-       if (PageMappedToDisk(page))
-               goto out_unlock;
+
+       lock_page(page);
+       wait_on_page_writeback(page);
+       if (PageMappedToDisk(page)) {
+               up_read(&inode->i_alloc_sem);
+               return VM_FAULT_LOCKED;
+       }
 
        if (page->index == size >> PAGE_CACHE_SHIFT)
                len = size & ~PAGE_CACHE_MASK;
        else
                len = PAGE_CACHE_SIZE;
 
-       lock_page(page);
        /*
         * return if we have all the buffers mapped. This avoid
         * the need to call write_begin/write_end which does a
@@ -5829,8 +5883,8 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        if (page_has_buffers(page)) {
                if (!walk_page_buffers(NULL, page_buffers(page), 0, len, NULL,
                                        ext4_bh_unmapped)) {
-                       unlock_page(page);
-                       goto out_unlock;
+                       up_read(&inode->i_alloc_sem);
+                       return VM_FAULT_LOCKED;
                }
        }
        unlock_page(page);
@@ -5850,6 +5904,16 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        if (ret < 0)
                goto out_unlock;
        ret = 0;
+
+       /*
+        * write_begin/end might have created a dirty page and someone
+        * could wander in and start the IO.  Make sure that hasn't
+        * happened.
+        */
+       lock_page(page);
+       wait_on_page_writeback(page);
+       up_read(&inode->i_alloc_sem);
+       return VM_FAULT_LOCKED;
 out_unlock:
        if (ret)
                ret = VM_FAULT_SIGBUS;
index d8a16eecf1d55748f59c6b66efe8cdf46b589803..6ed859d56850494d440dbbacc56967c4538fc659 100644 (file)
@@ -787,6 +787,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
        struct inode *inode;
        char *data;
        char *bitmap;
+       struct ext4_group_info *grinfo;
 
        mb_debug(1, "init page %lu\n", page->index);
 
@@ -819,6 +820,18 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
                if (first_group + i >= ngroups)
                        break;
 
+               grinfo = ext4_get_group_info(sb, first_group + i);
+               /*
+                * If page is uptodate then we came here after online resize
+                * which added some new uninitialized group info structs, so
+                * we must skip all initialized uptodate buddies on the page,
+                * which may be currently in use by an allocating task.
+                */
+               if (PageUptodate(page) && !EXT4_MB_GRP_NEED_INIT(grinfo)) {
+                       bh[i] = NULL;
+                       continue;
+               }
+
                err = -EIO;
                desc = ext4_get_group_desc(sb, first_group + i, NULL);
                if (desc == NULL)
@@ -871,26 +884,28 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
        }
 
        /* wait for I/O completion */
-       for (i = 0; i < groups_per_page && bh[i]; i++)
-               wait_on_buffer(bh[i]);
+       for (i = 0; i < groups_per_page; i++)
+               if (bh[i])
+                       wait_on_buffer(bh[i]);
 
        err = -EIO;
-       for (i = 0; i < groups_per_page && bh[i]; i++)
-               if (!buffer_uptodate(bh[i]))
+       for (i = 0; i < groups_per_page; i++)
+               if (bh[i] && !buffer_uptodate(bh[i]))
                        goto out;
 
        err = 0;
        first_block = page->index * blocks_per_page;
-       /* init the page  */
-       memset(page_address(page), 0xff, PAGE_CACHE_SIZE);
        for (i = 0; i < blocks_per_page; i++) {
                int group;
-               struct ext4_group_info *grinfo;
 
                group = (first_block + i) >> 1;
                if (group >= ngroups)
                        break;
 
+               if (!bh[group - first_group])
+                       /* skip initialized uptodate buddy */
+                       continue;
+
                /*
                 * data carry information regarding this
                 * particular group in the format specified
@@ -919,6 +934,8 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
                         * incore got set to the group block bitmap below
                         */
                        ext4_lock_group(sb, group);
+                       /* init the buddy */
+                       memset(data, 0xff, blocksize);
                        ext4_mb_generate_buddy(sb, data, incore, group);
                        ext4_unlock_group(sb, group);
                        incore = NULL;
@@ -948,7 +965,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
 
 out:
        if (bh) {
-               for (i = 0; i < groups_per_page && bh[i]; i++)
+               for (i = 0; i < groups_per_page; i++)
                        brelse(bh[i]);
                if (bh != &bhs)
                        kfree(bh);
@@ -957,22 +974,21 @@ out:
 }
 
 /*
- * lock the group_info alloc_sem of all the groups
- * belonging to the same buddy cache page. This
- * make sure other parallel operation on the buddy
- * cache doesn't happen  whild holding the buddy cache
- * lock
+ * Lock the buddy and bitmap pages. This make sure other parallel init_group
+ * on the same buddy page doesn't happen whild holding the buddy page lock.
+ * Return locked buddy and bitmap pages on e4b struct. If buddy and bitmap
+ * are on the same page e4b->bd_buddy_page is NULL and return value is 0.
  */
-static int ext4_mb_get_buddy_cache_lock(struct super_block *sb,
-                                       ext4_group_t group)
+static int ext4_mb_get_buddy_page_lock(struct super_block *sb,
+               ext4_group_t group, struct ext4_buddy *e4b)
 {
-       int i;
-       int block, pnum;
+       struct inode *inode = EXT4_SB(sb)->s_buddy_cache;
+       int block, pnum, poff;
        int blocks_per_page;
-       int groups_per_page;
-       ext4_group_t ngroups = ext4_get_groups_count(sb);
-       ext4_group_t first_group;
-       struct ext4_group_info *grp;
+       struct page *page;
+
+       e4b->bd_buddy_page = NULL;
+       e4b->bd_bitmap_page = NULL;
 
        blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize;
        /*
@@ -982,57 +998,40 @@ static int ext4_mb_get_buddy_cache_lock(struct super_block *sb,
         */
        block = group * 2;
        pnum = block / blocks_per_page;
-       first_group = pnum * blocks_per_page / 2;
-
-       groups_per_page = blocks_per_page >> 1;
-       if (groups_per_page == 0)
-               groups_per_page = 1;
-       /* read all groups the page covers into the cache */
-       for (i = 0; i < groups_per_page; i++) {
+       poff = block % blocks_per_page;
+       page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
+       if (!page)
+               return -EIO;
+       BUG_ON(page->mapping != inode->i_mapping);
+       e4b->bd_bitmap_page = page;
+       e4b->bd_bitmap = page_address(page) + (poff * sb->s_blocksize);
 
-               if ((first_group + i) >= ngroups)
-                       break;
-               grp = ext4_get_group_info(sb, first_group + i);
-               /* take all groups write allocation
-                * semaphore. This make sure there is
-                * no block allocation going on in any
-                * of that groups
-                */
-               down_write_nested(&grp->alloc_sem, i);
+       if (blocks_per_page >= 2) {
+               /* buddy and bitmap are on the same page */
+               return 0;
        }
-       return i;
+
+       block++;
+       pnum = block / blocks_per_page;
+       poff = block % blocks_per_page;
+       page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
+       if (!page)
+               return -EIO;
+       BUG_ON(page->mapping != inode->i_mapping);
+       e4b->bd_buddy_page = page;
+       return 0;
 }
 
-static void ext4_mb_put_buddy_cache_lock(struct super_block *sb,
-                                        ext4_group_t group, int locked_group)
+static void ext4_mb_put_buddy_page_lock(struct ext4_buddy *e4b)
 {
-       int i;
-       int block, pnum;
-       int blocks_per_page;
-       ext4_group_t first_group;
-       struct ext4_group_info *grp;
-
-       blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize;
-       /*
-        * the buddy cache inode stores the block bitmap
-        * and buddy information in consecutive blocks.
-        * So for each group we need two blocks.
-        */
-       block = group * 2;
-       pnum = block / blocks_per_page;
-       first_group = pnum * blocks_per_page / 2;
-       /* release locks on all the groups */
-       for (i = 0; i < locked_group; i++) {
-
-               grp = ext4_get_group_info(sb, first_group + i);
-               /* take all groups write allocation
-                * semaphore. This make sure there is
-                * no block allocation going on in any
-                * of that groups
-                */
-               up_write(&grp->alloc_sem);
+       if (e4b->bd_bitmap_page) {
+               unlock_page(e4b->bd_bitmap_page);
+               page_cache_release(e4b->bd_bitmap_page);
+       }
+       if (e4b->bd_buddy_page) {
+               unlock_page(e4b->bd_buddy_page);
+               page_cache_release(e4b->bd_buddy_page);
        }
-
 }
 
 /*
@@ -1044,93 +1043,60 @@ static noinline_for_stack
 int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
 {
 
-       int ret = 0;
-       void *bitmap;
-       int blocks_per_page;
-       int block, pnum, poff;
-       int num_grp_locked = 0;
        struct ext4_group_info *this_grp;
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-       struct inode *inode = sbi->s_buddy_cache;
-       struct page *page = NULL, *bitmap_page = NULL;
+       struct ext4_buddy e4b;
+       struct page *page;
+       int ret = 0;
 
        mb_debug(1, "init group %u\n", group);
-       blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize;
        this_grp = ext4_get_group_info(sb, group);
        /*
         * This ensures that we don't reinit the buddy cache
         * page which map to the group from which we are already
         * allocating. If we are looking at the buddy cache we would
         * have taken a reference using ext4_mb_load_buddy and that
-        * would have taken the alloc_sem lock.
+        * would have pinned buddy page to page cache.
         */
-       num_grp_locked =  ext4_mb_get_buddy_cache_lock(sb, group);
-       if (!EXT4_MB_GRP_NEED_INIT(this_grp)) {
+       ret = ext4_mb_get_buddy_page_lock(sb, group, &e4b);
+       if (ret || !EXT4_MB_GRP_NEED_INIT(this_grp)) {
                /*
                 * somebody initialized the group
                 * return without doing anything
                 */
-               ret = 0;
                goto err;
        }
-       /*
-        * the buddy cache inode stores the block bitmap
-        * and buddy information in consecutive blocks.
-        * So for each group we need two blocks.
-        */
-       block = group * 2;
-       pnum = block / blocks_per_page;
-       poff = block % blocks_per_page;
-       page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
-       if (page) {
-               BUG_ON(page->mapping != inode->i_mapping);
-               ret = ext4_mb_init_cache(page, NULL);
-               if (ret) {
-                       unlock_page(page);
-                       goto err;
-               }
-               unlock_page(page);
-       }
-       if (page == NULL || !PageUptodate(page)) {
+
+       page = e4b.bd_bitmap_page;
+       ret = ext4_mb_init_cache(page, NULL);
+       if (ret)
+               goto err;
+       if (!PageUptodate(page)) {
                ret = -EIO;
                goto err;
        }
        mark_page_accessed(page);
-       bitmap_page = page;
-       bitmap = page_address(page) + (poff * sb->s_blocksize);
 
-       /* init buddy cache */
-       block++;
-       pnum = block / blocks_per_page;
-       poff = block % blocks_per_page;
-       page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
-       if (page == bitmap_page) {
+       if (e4b.bd_buddy_page == NULL) {
                /*
                 * If both the bitmap and buddy are in
                 * the same page we don't need to force
                 * init the buddy
                 */
-               unlock_page(page);
-       } else if (page) {
-               BUG_ON(page->mapping != inode->i_mapping);
-               ret = ext4_mb_init_cache(page, bitmap);
-               if (ret) {
-                       unlock_page(page);
-                       goto err;
-               }
-               unlock_page(page);
+               ret = 0;
+               goto err;
        }
-       if (page == NULL || !PageUptodate(page)) {
+       /* init buddy cache */
+       page = e4b.bd_buddy_page;
+       ret = ext4_mb_init_cache(page, e4b.bd_bitmap);
+       if (ret)
+               goto err;
+       if (!PageUptodate(page)) {
                ret = -EIO;
                goto err;
        }
        mark_page_accessed(page);
 err:
-       ext4_mb_put_buddy_cache_lock(sb, group, num_grp_locked);
-       if (bitmap_page)
-               page_cache_release(bitmap_page);
-       if (page)
-               page_cache_release(page);
+       ext4_mb_put_buddy_page_lock(&e4b);
        return ret;
 }
 
@@ -1164,24 +1130,8 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
        e4b->bd_group = group;
        e4b->bd_buddy_page = NULL;
        e4b->bd_bitmap_page = NULL;
-       e4b->alloc_semp = &grp->alloc_sem;
-
-       /* Take the read lock on the group alloc
-        * sem. This would make sure a parallel
-        * ext4_mb_init_group happening on other
-        * groups mapped by the page is blocked
-        * till we are done with allocation
-        */
-repeat_load_buddy:
-       down_read(e4b->alloc_semp);
 
        if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) {
-               /* we need to check for group need init flag
-                * with alloc_semp held so that we can be sure
-                * that new blocks didn't get added to the group
-                * when we are loading the buddy cache
-                */
-               up_read(e4b->alloc_semp);
                /*
                 * we need full data about the group
                 * to make a good selection
@@ -1189,7 +1139,6 @@ repeat_load_buddy:
                ret = ext4_mb_init_group(sb, group);
                if (ret)
                        return ret;
-               goto repeat_load_buddy;
        }
 
        /*
@@ -1273,15 +1222,14 @@ repeat_load_buddy:
        return 0;
 
 err:
+       if (page)
+               page_cache_release(page);
        if (e4b->bd_bitmap_page)
                page_cache_release(e4b->bd_bitmap_page);
        if (e4b->bd_buddy_page)
                page_cache_release(e4b->bd_buddy_page);
        e4b->bd_buddy = NULL;
        e4b->bd_bitmap = NULL;
-
-       /* Done with the buddy cache */
-       up_read(e4b->alloc_semp);
        return ret;
 }
 
@@ -1291,9 +1239,6 @@ static void ext4_mb_unload_buddy(struct ext4_buddy *e4b)
                page_cache_release(e4b->bd_bitmap_page);
        if (e4b->bd_buddy_page)
                page_cache_release(e4b->bd_buddy_page);
-       /* Done with the buddy cache */
-       if (e4b->alloc_semp)
-               up_read(e4b->alloc_semp);
 }
 
 
@@ -1606,9 +1551,6 @@ static void ext4_mb_use_best_found(struct ext4_allocation_context *ac,
        get_page(ac->ac_bitmap_page);
        ac->ac_buddy_page = e4b->bd_buddy_page;
        get_page(ac->ac_buddy_page);
-       /* on allocation we use ac to track the held semaphore */
-       ac->alloc_semp =  e4b->alloc_semp;
-       e4b->alloc_semp = NULL;
        /* store last allocated for subsequent stream allocation */
        if (ac->ac_flags & EXT4_MB_STREAM_ALLOC) {
                spin_lock(&sbi->s_md_lock);
@@ -2659,7 +2601,7 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
        struct super_block *sb = journal->j_private;
        struct ext4_buddy e4b;
        struct ext4_group_info *db;
-       int err, ret, count = 0, count2 = 0;
+       int err, count = 0, count2 = 0;
        struct ext4_free_data *entry;
        struct list_head *l, *ltmp;
 
@@ -2669,15 +2611,9 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
                mb_debug(1, "gonna free %u blocks in group %u (0x%p):",
                         entry->count, entry->group, entry);
 
-               if (test_opt(sb, DISCARD)) {
-                       ret = ext4_issue_discard(sb, entry->group,
-                                       entry->start_blk, entry->count);
-                       if (unlikely(ret == -EOPNOTSUPP)) {
-                               ext4_warning(sb, "discard not supported, "
-                                                "disabling");
-                               clear_opt(sb, DISCARD);
-                       }
-               }
+               if (test_opt(sb, DISCARD))
+                       ext4_issue_discard(sb, entry->group,
+                                          entry->start_blk, entry->count);
 
                err = ext4_mb_load_buddy(sb, entry->group, &e4b);
                /* we expect to find existing buddy because it's pinned */
@@ -3642,8 +3578,8 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
                free += next - bit;
 
                trace_ext4_mballoc_discard(sb, NULL, group, bit, next - bit);
-               trace_ext4_mb_release_inode_pa(sb, pa->pa_inode, pa,
-                                              grp_blk_start + bit, next - bit);
+               trace_ext4_mb_release_inode_pa(pa, grp_blk_start + bit,
+                                              next - bit);
                mb_free_blocks(pa->pa_inode, e4b, bit, next - bit);
                bit = next + 1;
        }
@@ -3672,7 +3608,7 @@ ext4_mb_release_group_pa(struct ext4_buddy *e4b,
        ext4_group_t group;
        ext4_grpblk_t bit;
 
-       trace_ext4_mb_release_group_pa(sb, pa);
+       trace_ext4_mb_release_group_pa(pa);
        BUG_ON(pa->pa_deleted == 0);
        ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, &bit);
        BUG_ON(group != e4b->bd_group && pa->pa_len != 0);
@@ -4226,15 +4162,12 @@ static int ext4_mb_release_context(struct ext4_allocation_context *ac)
                        spin_unlock(&pa->pa_lock);
                }
        }
-       if (ac->alloc_semp)
-               up_read(ac->alloc_semp);
        if (pa) {
                /*
                 * We want to add the pa to the right bucket.
                 * Remove it from the list and while adding
                 * make sure the list to which we are adding
-                * doesn't grow big.  We need to release
-                * alloc_semp before calling ext4_mb_add_n_trim()
+                * doesn't grow big.
                 */
                if ((pa->pa_type == MB_GROUP_PA) && likely(pa->pa_free)) {
                        spin_lock(pa->pa_obj_lock);
@@ -4303,7 +4236,9 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
                 * there is enough free blocks to do block allocation
                 * and verify allocation doesn't exceed the quota limits.
                 */
-               while (ar->len && ext4_claim_free_blocks(sbi, ar->len)) {
+               while (ar->len &&
+                       ext4_claim_free_blocks(sbi, ar->len, ar->flags)) {
+
                        /* let others to free the space */
                        yield();
                        ar->len = ar->len >> 1;
@@ -4313,9 +4248,15 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
                        return 0;
                }
                reserv_blks = ar->len;
-               while (ar->len && dquot_alloc_block(ar->inode, ar->len)) {
-                       ar->flags |= EXT4_MB_HINT_NOPREALLOC;
-                       ar->len--;
+               if (ar->flags & EXT4_MB_USE_ROOT_BLOCKS) {
+                       dquot_alloc_block_nofail(ar->inode, ar->len);
+               } else {
+                       while (ar->len &&
+                               dquot_alloc_block(ar->inode, ar->len)) {
+
+                               ar->flags |= EXT4_MB_HINT_NOPREALLOC;
+                               ar->len--;
+                       }
                }
                inquota = ar->len;
                if (ar->len == 0) {
@@ -4507,7 +4448,7 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
  * @inode:             inode
  * @block:             start physical block to free
  * @count:             number of blocks to count
- * @metadata:          Are these metadata blocks
+ * @flags:             flags used by ext4_free_blocks
  */
 void ext4_free_blocks(handle_t *handle, struct inode *inode,
                      struct buffer_head *bh, ext4_fsblk_t block,
@@ -4703,6 +4644,127 @@ error_return:
        return;
 }
 
+/**
+ * ext4_add_groupblocks() -- Add given blocks to an existing group
+ * @handle:                    handle to this transaction
+ * @sb:                                super block
+ * @block:                     start physcial block to add to the block group
+ * @count:                     number of blocks to free
+ *
+ * This marks the blocks as free in the bitmap and buddy.
+ */
+void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
+                        ext4_fsblk_t block, unsigned long count)
+{
+       struct buffer_head *bitmap_bh = NULL;
+       struct buffer_head *gd_bh;
+       ext4_group_t block_group;
+       ext4_grpblk_t bit;
+       unsigned int i;
+       struct ext4_group_desc *desc;
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       struct ext4_buddy e4b;
+       int err = 0, ret, blk_free_count;
+       ext4_grpblk_t blocks_freed;
+       struct ext4_group_info *grp;
+
+       ext4_debug("Adding block(s) %llu-%llu\n", block, block + count - 1);
+
+       ext4_get_group_no_and_offset(sb, block, &block_group, &bit);
+       grp = ext4_get_group_info(sb, block_group);
+       /*
+        * Check to see if we are freeing blocks across a group
+        * boundary.
+        */
+       if (bit + count > EXT4_BLOCKS_PER_GROUP(sb))
+               goto error_return;
+
+       bitmap_bh = ext4_read_block_bitmap(sb, block_group);
+       if (!bitmap_bh)
+               goto error_return;
+       desc = ext4_get_group_desc(sb, block_group, &gd_bh);
+       if (!desc)
+               goto error_return;
+
+       if (in_range(ext4_block_bitmap(sb, desc), block, count) ||
+           in_range(ext4_inode_bitmap(sb, desc), block, count) ||
+           in_range(block, ext4_inode_table(sb, desc), sbi->s_itb_per_group) ||
+           in_range(block + count - 1, ext4_inode_table(sb, desc),
+                    sbi->s_itb_per_group)) {
+               ext4_error(sb, "Adding blocks in system zones - "
+                          "Block = %llu, count = %lu",
+                          block, count);
+               goto error_return;
+       }
+
+       BUFFER_TRACE(bitmap_bh, "getting write access");
+       err = ext4_journal_get_write_access(handle, bitmap_bh);
+       if (err)
+               goto error_return;
+
+       /*
+        * We are about to modify some metadata.  Call the journal APIs
+        * to unshare ->b_data if a currently-committing transaction is
+        * using it
+        */
+       BUFFER_TRACE(gd_bh, "get_write_access");
+       err = ext4_journal_get_write_access(handle, gd_bh);
+       if (err)
+               goto error_return;
+
+       for (i = 0, blocks_freed = 0; i < count; i++) {
+               BUFFER_TRACE(bitmap_bh, "clear bit");
+               if (!mb_test_bit(bit + i, bitmap_bh->b_data)) {
+                       ext4_error(sb, "bit already cleared for block %llu",
+                                  (ext4_fsblk_t)(block + i));
+                       BUFFER_TRACE(bitmap_bh, "bit already cleared");
+               } else {
+                       blocks_freed++;
+               }
+       }
+
+       err = ext4_mb_load_buddy(sb, block_group, &e4b);
+       if (err)
+               goto error_return;
+
+       /*
+        * need to update group_info->bb_free and bitmap
+        * with group lock held. generate_buddy look at
+        * them with group lock_held
+        */
+       ext4_lock_group(sb, block_group);
+       mb_clear_bits(bitmap_bh->b_data, bit, count);
+       mb_free_blocks(NULL, &e4b, bit, count);
+       blk_free_count = blocks_freed + ext4_free_blks_count(sb, desc);
+       ext4_free_blks_set(sb, desc, blk_free_count);
+       desc->bg_checksum = ext4_group_desc_csum(sbi, block_group, desc);
+       ext4_unlock_group(sb, block_group);
+       percpu_counter_add(&sbi->s_freeblocks_counter, blocks_freed);
+
+       if (sbi->s_log_groups_per_flex) {
+               ext4_group_t flex_group = ext4_flex_group(sbi, block_group);
+               atomic_add(blocks_freed,
+                          &sbi->s_flex_groups[flex_group].free_blocks);
+       }
+
+       ext4_mb_unload_buddy(&e4b);
+
+       /* We dirtied the bitmap block */
+       BUFFER_TRACE(bitmap_bh, "dirtied bitmap block");
+       err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
+
+       /* And the group descriptor block */
+       BUFFER_TRACE(gd_bh, "dirtied group descriptor block");
+       ret = ext4_handle_dirty_metadata(handle, NULL, gd_bh);
+       if (!err)
+               err = ret;
+
+error_return:
+       brelse(bitmap_bh);
+       ext4_std_error(sb, err);
+       return;
+}
+
 /**
  * ext4_trim_extent -- function to TRIM one single free extent in the group
  * @sb:                super block for the file system
@@ -4715,11 +4777,10 @@ error_return:
  * one will allocate those blocks, mark it as used in buddy bitmap. This must
  * be called with under the group lock.
  */
-static int ext4_trim_extent(struct super_block *sb, int start, int count,
-               ext4_group_t group, struct ext4_buddy *e4b)
+static void ext4_trim_extent(struct super_block *sb, int start, int count,
+                            ext4_group_t group, struct ext4_buddy *e4b)
 {
        struct ext4_free_extent ex;
-       int ret = 0;
 
        assert_spin_locked(ext4_group_lock_ptr(sb, group));
 
@@ -4733,12 +4794,9 @@ static int ext4_trim_extent(struct super_block *sb, int start, int count,
         */
        mb_mark_used(e4b, &ex);
        ext4_unlock_group(sb, group);
-
-       ret = ext4_issue_discard(sb, group, start, count);
-
+       ext4_issue_discard(sb, group, start, count);
        ext4_lock_group(sb, group);
        mb_free_blocks(NULL, e4b, start, ex.fe_len);
-       return ret;
 }
 
 /**
@@ -4760,21 +4818,26 @@ static int ext4_trim_extent(struct super_block *sb, int start, int count,
  * the group buddy bitmap. This is done until whole group is scanned.
  */
 static ext4_grpblk_t
-ext4_trim_all_free(struct super_block *sb, struct ext4_buddy *e4b,
-               ext4_grpblk_t start, ext4_grpblk_t max, ext4_grpblk_t minblocks)
+ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
+                  ext4_grpblk_t start, ext4_grpblk_t max,
+                  ext4_grpblk_t minblocks)
 {
        void *bitmap;
        ext4_grpblk_t next, count = 0;
-       ext4_group_t group;
-       int ret = 0;
+       struct ext4_buddy e4b;
+       int ret;
 
-       BUG_ON(e4b == NULL);
+       ret = ext4_mb_load_buddy(sb, group, &e4b);
+       if (ret) {
+               ext4_error(sb, "Error in loading buddy "
+                               "information for %u", group);
+               return ret;
+       }
+       bitmap = e4b.bd_bitmap;
 
-       bitmap = e4b->bd_bitmap;
-       group = e4b->bd_group;
-       start = (e4b->bd_info->bb_first_free > start) ?
-               e4b->bd_info->bb_first_free : start;
        ext4_lock_group(sb, group);
+       start = (e4b.bd_info->bb_first_free > start) ?
+               e4b.bd_info->bb_first_free : start;
 
        while (start < max) {
                start = mb_find_next_zero_bit(bitmap, max, start);
@@ -4783,10 +4846,8 @@ ext4_trim_all_free(struct super_block *sb, struct ext4_buddy *e4b,
                next = mb_find_next_bit(bitmap, max, start);
 
                if ((next - start) >= minblocks) {
-                       ret = ext4_trim_extent(sb, start,
-                               next - start, group, e4b);
-                       if (ret < 0)
-                               break;
+                       ext4_trim_extent(sb, start,
+                                        next - start, group, &e4b);
                        count += next - start;
                }
                start = next + 1;
@@ -4802,17 +4863,15 @@ ext4_trim_all_free(struct super_block *sb, struct ext4_buddy *e4b,
                        ext4_lock_group(sb, group);
                }
 
-               if ((e4b->bd_info->bb_free - count) < minblocks)
+               if ((e4b.bd_info->bb_free - count) < minblocks)
                        break;
        }
        ext4_unlock_group(sb, group);
+       ext4_mb_unload_buddy(&e4b);
 
        ext4_debug("trimmed %d blocks in the group %d\n",
                count, group);
 
-       if (ret < 0)
-               count = ret;
-
        return count;
 }
 
@@ -4830,11 +4889,11 @@ ext4_trim_all_free(struct super_block *sb, struct ext4_buddy *e4b,
  */
 int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
 {
-       struct ext4_buddy e4b;
+       struct ext4_group_info *grp;
        ext4_group_t first_group, last_group;
        ext4_group_t group, ngroups = ext4_get_groups_count(sb);
        ext4_grpblk_t cnt = 0, first_block, last_block;
-       uint64_t start, len, minlen, trimmed;
+       uint64_t start, len, minlen, trimmed = 0;
        ext4_fsblk_t first_data_blk =
                        le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
        int ret = 0;
@@ -4842,7 +4901,6 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
        start = range->start >> sb->s_blocksize_bits;
        len = range->len >> sb->s_blocksize_bits;
        minlen = range->minlen >> sb->s_blocksize_bits;
-       trimmed = 0;
 
        if (unlikely(minlen > EXT4_BLOCKS_PER_GROUP(sb)))
                return -EINVAL;
@@ -4863,11 +4921,12 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
                return -EINVAL;
 
        for (group = first_group; group <= last_group; group++) {
-               ret = ext4_mb_load_buddy(sb, group, &e4b);
-               if (ret) {
-                       ext4_error(sb, "Error in loading buddy "
-                                       "information for %u", group);
-                       break;
+               grp = ext4_get_group_info(sb, group);
+               /* We only do this if the grp has never been initialized */
+               if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) {
+                       ret = ext4_mb_init_group(sb, group);
+                       if (ret)
+                               break;
                }
 
                /*
@@ -4880,16 +4939,14 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
                        last_block = first_block + len;
                len -= last_block - first_block;
 
-               if (e4b.bd_info->bb_free >= minlen) {
-                       cnt = ext4_trim_all_free(sb, &e4b, first_block,
+               if (grp->bb_free >= minlen) {
+                       cnt = ext4_trim_all_free(sb, group, first_block,
                                                last_block, minlen);
                        if (cnt < 0) {
                                ret = cnt;
-                               ext4_mb_unload_buddy(&e4b);
                                break;
                        }
                }
-               ext4_mb_unload_buddy(&e4b);
                trimmed += cnt;
                first_block = 0;
        }
index 22bd4d7f289b834b277fb55ce92cefa019c9d354..20b5e7bfebd175e27db63f959c0d5d89a9f929b0 100644 (file)
@@ -193,11 +193,6 @@ struct ext4_allocation_context {
        __u8 ac_op;             /* operation, for history only */
        struct page *ac_bitmap_page;
        struct page *ac_buddy_page;
-       /*
-        * pointer to the held semaphore upon successful
-        * block allocation
-        */
-       struct rw_semaphore *alloc_semp;
        struct ext4_prealloc_space *ac_pa;
        struct ext4_locality_group *ac_lg;
 };
@@ -215,7 +210,6 @@ struct ext4_buddy {
        struct super_block *bd_sb;
        __u16 bd_blkbits;
        ext4_group_t bd_group;
-       struct rw_semaphore *alloc_semp;
 };
 #define EXT4_MB_BITMAP(e4b)    ((e4b)->bd_bitmap)
 #define EXT4_MB_BUDDY(e4b)     ((e4b)->bd_buddy)
index 92816b4e0f16a143f555d539cb9cb47abc7e1d48..b57b98fb44d1457ec9f98e60290d6da3a90fb6c8 100644 (file)
@@ -376,7 +376,7 @@ static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
         * We have the extent map build with the tmp inode.
         * Now copy the i_data across
         */
-       ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS);
+       ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS);
        memcpy(ei->i_data, tmp_ei->i_data, sizeof(ei->i_data));
 
        /*
diff --git a/fs/ext4/mmp.c b/fs/ext4/mmp.c
new file mode 100644 (file)
index 0000000..9bdef3f
--- /dev/null
@@ -0,0 +1,351 @@
+#include <linux/fs.h>
+#include <linux/random.h>
+#include <linux/buffer_head.h>
+#include <linux/utsname.h>
+#include <linux/kthread.h>
+
+#include "ext4.h"
+
+/*
+ * Write the MMP block using WRITE_SYNC to try to get the block on-disk
+ * faster.
+ */
+static int write_mmp_block(struct buffer_head *bh)
+{
+       mark_buffer_dirty(bh);
+       lock_buffer(bh);
+       bh->b_end_io = end_buffer_write_sync;
+       get_bh(bh);
+       submit_bh(WRITE_SYNC, bh);
+       wait_on_buffer(bh);
+       if (unlikely(!buffer_uptodate(bh)))
+               return 1;
+
+       return 0;
+}
+
+/*
+ * Read the MMP block. It _must_ be read from disk and hence we clear the
+ * uptodate flag on the buffer.
+ */
+static int read_mmp_block(struct super_block *sb, struct buffer_head **bh,
+                         ext4_fsblk_t mmp_block)
+{
+       struct mmp_struct *mmp;
+
+       if (*bh)
+               clear_buffer_uptodate(*bh);
+
+       /* This would be sb_bread(sb, mmp_block), except we need to be sure
+        * that the MD RAID device cache has been bypassed, and that the read
+        * is not blocked in the elevator. */
+       if (!*bh)
+               *bh = sb_getblk(sb, mmp_block);
+       if (*bh) {
+               get_bh(*bh);
+               lock_buffer(*bh);
+               (*bh)->b_end_io = end_buffer_read_sync;
+               submit_bh(READ_SYNC, *bh);
+               wait_on_buffer(*bh);
+               if (!buffer_uptodate(*bh)) {
+                       brelse(*bh);
+                       *bh = NULL;
+               }
+       }
+       if (!*bh) {
+               ext4_warning(sb, "Error while reading MMP block %llu",
+                            mmp_block);
+               return -EIO;
+       }
+
+       mmp = (struct mmp_struct *)((*bh)->b_data);
+       if (le32_to_cpu(mmp->mmp_magic) != EXT4_MMP_MAGIC)
+               return -EINVAL;
+
+       return 0;
+}
+
+/*
+ * Dump as much information as possible to help the admin.
+ */
+void __dump_mmp_msg(struct super_block *sb, struct mmp_struct *mmp,
+                   const char *function, unsigned int line, const char *msg)
+{
+       __ext4_warning(sb, function, line, msg);
+       __ext4_warning(sb, function, line,
+                      "MMP failure info: last update time: %llu, last update "
+                      "node: %s, last update device: %s\n",
+                      (long long unsigned int) le64_to_cpu(mmp->mmp_time),
+                      mmp->mmp_nodename, mmp->mmp_bdevname);
+}
+
+/*
+ * kmmpd will update the MMP sequence every s_mmp_update_interval seconds
+ */
+static int kmmpd(void *data)
+{
+       struct super_block *sb = ((struct mmpd_data *) data)->sb;
+       struct buffer_head *bh = ((struct mmpd_data *) data)->bh;
+       struct ext4_super_block *es = EXT4_SB(sb)->s_es;
+       struct mmp_struct *mmp;
+       ext4_fsblk_t mmp_block;
+       u32 seq = 0;
+       unsigned long failed_writes = 0;
+       int mmp_update_interval = le16_to_cpu(es->s_mmp_update_interval);
+       unsigned mmp_check_interval;
+       unsigned long last_update_time;
+       unsigned long diff;
+       int retval;
+
+       mmp_block = le64_to_cpu(es->s_mmp_block);
+       mmp = (struct mmp_struct *)(bh->b_data);
+       mmp->mmp_time = cpu_to_le64(get_seconds());
+       /*
+        * Start with the higher mmp_check_interval and reduce it if
+        * the MMP block is being updated on time.
+        */
+       mmp_check_interval = max(EXT4_MMP_CHECK_MULT * mmp_update_interval,
+                                EXT4_MMP_MIN_CHECK_INTERVAL);
+       mmp->mmp_check_interval = cpu_to_le16(mmp_check_interval);
+       bdevname(bh->b_bdev, mmp->mmp_bdevname);
+
+       memcpy(mmp->mmp_nodename, init_utsname()->sysname,
+              sizeof(mmp->mmp_nodename));
+
+       while (!kthread_should_stop()) {
+               if (++seq > EXT4_MMP_SEQ_MAX)
+                       seq = 1;
+
+               mmp->mmp_seq = cpu_to_le32(seq);
+               mmp->mmp_time = cpu_to_le64(get_seconds());
+               last_update_time = jiffies;
+
+               retval = write_mmp_block(bh);
+               /*
+                * Don't spew too many error messages. Print one every
+                * (s_mmp_update_interval * 60) seconds.
+                */
+               if (retval && (failed_writes % 60) == 0) {
+                       ext4_error(sb, "Error writing to MMP block");
+                       failed_writes++;
+               }
+
+               if (!(le32_to_cpu(es->s_feature_incompat) &
+                   EXT4_FEATURE_INCOMPAT_MMP)) {
+                       ext4_warning(sb, "kmmpd being stopped since MMP feature"
+                                    " has been disabled.");
+                       EXT4_SB(sb)->s_mmp_tsk = NULL;
+                       goto failed;
+               }
+
+               if (sb->s_flags & MS_RDONLY) {
+                       ext4_warning(sb, "kmmpd being stopped since filesystem "
+                                    "has been remounted as readonly.");
+                       EXT4_SB(sb)->s_mmp_tsk = NULL;
+                       goto failed;
+               }
+
+               diff = jiffies - last_update_time;
+               if (diff < mmp_update_interval * HZ)
+                       schedule_timeout_interruptible(mmp_update_interval *
+                                                      HZ - diff);
+
+               /*
+                * We need to make sure that more than mmp_check_interval
+                * seconds have not passed since writing. If that has happened
+                * we need to check if the MMP block is as we left it.
+                */
+               diff = jiffies - last_update_time;
+               if (diff > mmp_check_interval * HZ) {
+                       struct buffer_head *bh_check = NULL;
+                       struct mmp_struct *mmp_check;
+
+                       retval = read_mmp_block(sb, &bh_check, mmp_block);
+                       if (retval) {
+                               ext4_error(sb, "error reading MMP data: %d",
+                                          retval);
+
+                               EXT4_SB(sb)->s_mmp_tsk = NULL;
+                               goto failed;
+                       }
+
+                       mmp_check = (struct mmp_struct *)(bh_check->b_data);
+                       if (mmp->mmp_seq != mmp_check->mmp_seq ||
+                           memcmp(mmp->mmp_nodename, mmp_check->mmp_nodename,
+                                  sizeof(mmp->mmp_nodename))) {
+                               dump_mmp_msg(sb, mmp_check,
+                                            "Error while updating MMP info. "
+                                            "The filesystem seems to have been"
+                                            " multiply mounted.");
+                               ext4_error(sb, "abort");
+                               goto failed;
+                       }
+                       put_bh(bh_check);
+               }
+
+                /*
+                * Adjust the mmp_check_interval depending on how much time
+                * it took for the MMP block to be written.
+                */
+               mmp_check_interval = max(min(EXT4_MMP_CHECK_MULT * diff / HZ,
+                                            EXT4_MMP_MAX_CHECK_INTERVAL),
+                                        EXT4_MMP_MIN_CHECK_INTERVAL);
+               mmp->mmp_check_interval = cpu_to_le16(mmp_check_interval);
+       }
+
+       /*
+        * Unmount seems to be clean.
+        */
+       mmp->mmp_seq = cpu_to_le32(EXT4_MMP_SEQ_CLEAN);
+       mmp->mmp_time = cpu_to_le64(get_seconds());
+
+       retval = write_mmp_block(bh);
+
+failed:
+       kfree(data);
+       brelse(bh);
+       return retval;
+}
+
+/*
+ * Get a random new sequence number but make sure it is not greater than
+ * EXT4_MMP_SEQ_MAX.
+ */
+static unsigned int mmp_new_seq(void)
+{
+       u32 new_seq;
+
+       do {
+               get_random_bytes(&new_seq, sizeof(u32));
+       } while (new_seq > EXT4_MMP_SEQ_MAX);
+
+       return new_seq;
+}
+
+/*
+ * Protect the filesystem from being mounted more than once.
+ */
+int ext4_multi_mount_protect(struct super_block *sb,
+                                   ext4_fsblk_t mmp_block)
+{
+       struct ext4_super_block *es = EXT4_SB(sb)->s_es;
+       struct buffer_head *bh = NULL;
+       struct mmp_struct *mmp = NULL;
+       struct mmpd_data *mmpd_data;
+       u32 seq;
+       unsigned int mmp_check_interval = le16_to_cpu(es->s_mmp_update_interval);
+       unsigned int wait_time = 0;
+       int retval;
+
+       if (mmp_block < le32_to_cpu(es->s_first_data_block) ||
+           mmp_block >= ext4_blocks_count(es)) {
+               ext4_warning(sb, "Invalid MMP block in superblock");
+               goto failed;
+       }
+
+       retval = read_mmp_block(sb, &bh, mmp_block);
+       if (retval)
+               goto failed;
+
+       mmp = (struct mmp_struct *)(bh->b_data);
+
+       if (mmp_check_interval < EXT4_MMP_MIN_CHECK_INTERVAL)
+               mmp_check_interval = EXT4_MMP_MIN_CHECK_INTERVAL;
+
+       /*
+        * If check_interval in MMP block is larger, use that instead of
+        * update_interval from the superblock.
+        */
+       if (mmp->mmp_check_interval > mmp_check_interval)
+               mmp_check_interval = mmp->mmp_check_interval;
+
+       seq = le32_to_cpu(mmp->mmp_seq);
+       if (seq == EXT4_MMP_SEQ_CLEAN)
+               goto skip;
+
+       if (seq == EXT4_MMP_SEQ_FSCK) {
+               dump_mmp_msg(sb, mmp, "fsck is running on the filesystem");
+               goto failed;
+       }
+
+       wait_time = min(mmp_check_interval * 2 + 1,
+                       mmp_check_interval + 60);
+
+       /* Print MMP interval if more than 20 secs. */
+       if (wait_time > EXT4_MMP_MIN_CHECK_INTERVAL * 4)
+               ext4_warning(sb, "MMP interval %u higher than expected, please"
+                            " wait.\n", wait_time * 2);
+
+       if (schedule_timeout_interruptible(HZ * wait_time) != 0) {
+               ext4_warning(sb, "MMP startup interrupted, failing mount\n");
+               goto failed;
+       }
+
+       retval = read_mmp_block(sb, &bh, mmp_block);
+       if (retval)
+               goto failed;
+       mmp = (struct mmp_struct *)(bh->b_data);
+       if (seq != le32_to_cpu(mmp->mmp_seq)) {
+               dump_mmp_msg(sb, mmp,
+                            "Device is already active on another node.");
+               goto failed;
+       }
+
+skip:
+       /*
+        * write a new random sequence number.
+        */
+       mmp->mmp_seq = seq = cpu_to_le32(mmp_new_seq());
+
+       retval = write_mmp_block(bh);
+       if (retval)
+               goto failed;
+
+       /*
+        * wait for MMP interval and check mmp_seq.
+        */
+       if (schedule_timeout_interruptible(HZ * wait_time) != 0) {
+               ext4_warning(sb, "MMP startup interrupted, failing mount\n");
+               goto failed;
+       }
+
+       retval = read_mmp_block(sb, &bh, mmp_block);
+       if (retval)
+               goto failed;
+       mmp = (struct mmp_struct *)(bh->b_data);
+       if (seq != le32_to_cpu(mmp->mmp_seq)) {
+               dump_mmp_msg(sb, mmp,
+                            "Device is already active on another node.");
+               goto failed;
+       }
+
+       mmpd_data = kmalloc(sizeof(struct mmpd_data), GFP_KERNEL);
+       if (!mmpd_data) {
+               ext4_warning(sb, "not enough memory for mmpd_data");
+               goto failed;
+       }
+       mmpd_data->sb = sb;
+       mmpd_data->bh = bh;
+
+       /*
+        * Start a kernel thread to update the MMP block periodically.
+        */
+       EXT4_SB(sb)->s_mmp_tsk = kthread_run(kmmpd, mmpd_data, "kmmpd-%s",
+                                            bdevname(bh->b_bdev,
+                                                     mmp->mmp_bdevname));
+       if (IS_ERR(EXT4_SB(sb)->s_mmp_tsk)) {
+               EXT4_SB(sb)->s_mmp_tsk = NULL;
+               kfree(mmpd_data);
+               ext4_warning(sb, "Unable to create kmmpd thread for %s.",
+                            sb->s_id);
+               goto failed;
+       }
+
+       return 0;
+
+failed:
+       brelse(bh);
+       return 1;
+}
+
+
index b9f3e7862f13834b2c166b21a1b96d3e36dde428..f57455a1b1b281bdf21e12f63bc46087abe58194 100644 (file)
@@ -876,8 +876,7 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode,
         * It needs to call wait_on_page_writeback() to wait for the
         * writeback of the page.
         */
-       if (PageWriteback(page))
-               wait_on_page_writeback(page);
+       wait_on_page_writeback(page);
 
        /* Release old bh and drop refs */
        try_to_release_page(page, 0);
@@ -1003,12 +1002,12 @@ mext_check_arguments(struct inode *orig_inode,
                return -EINVAL;
        }
 
-       if ((orig_start > EXT_MAX_BLOCK) ||
-           (donor_start > EXT_MAX_BLOCK) ||
-           (*len > EXT_MAX_BLOCK) ||
-           (orig_start + *len > EXT_MAX_BLOCK))  {
+       if ((orig_start >= EXT_MAX_BLOCKS) ||
+           (donor_start >= EXT_MAX_BLOCKS) ||
+           (*len > EXT_MAX_BLOCKS) ||
+           (orig_start + *len >= EXT_MAX_BLOCKS))  {
                ext4_debug("ext4 move extent: Can't handle over [%u] blocks "
-                       "[ino:orig %lu, donor %lu]\n", EXT_MAX_BLOCK,
+                       "[ino:orig %lu, donor %lu]\n", EXT_MAX_BLOCKS,
                        orig_inode->i_ino, donor_inode->i_ino);
                return -EINVAL;
        }
index 67fd0b0258589ae64428d26530807b898e79854b..b754b7721f51fea4dd943a68e436fe5677f301a0 100644 (file)
@@ -1413,10 +1413,22 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
        frame->at = entries;
        frame->bh = bh;
        bh = bh2;
+
+       ext4_handle_dirty_metadata(handle, dir, frame->bh);
+       ext4_handle_dirty_metadata(handle, dir, bh);
+
        de = do_split(handle,dir, &bh, frame, &hinfo, &retval);
-       dx_release (frames);
-       if (!(de))
+       if (!de) {
+               /*
+                * Even if the block split failed, we have to properly write
+                * out all the changes we did so far. Otherwise we can end up
+                * with corrupted filesystem.
+                */
+               ext4_mark_inode_dirty(handle, dir);
+               dx_release(frames);
                return retval;
+       }
+       dx_release(frames);
 
        retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
        brelse(bh);
@@ -2240,6 +2252,7 @@ static int ext4_symlink(struct inode *dir,
        handle_t *handle;
        struct inode *inode;
        int l, err, retries = 0;
+       int credits;
 
        l = strlen(symname)+1;
        if (l > dir->i_sb->s_blocksize)
@@ -2247,10 +2260,26 @@ static int ext4_symlink(struct inode *dir,
 
        dquot_initialize(dir);
 
+       if (l > EXT4_N_BLOCKS * 4) {
+               /*
+                * For non-fast symlinks, we just allocate inode and put it on
+                * orphan list in the first transaction => we need bitmap,
+                * group descriptor, sb, inode block, quota blocks.
+                */
+               credits = 4 + EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
+       } else {
+               /*
+                * Fast symlink. We have to add entry to directory
+                * (EXT4_DATA_TRANS_BLOCKS + EXT4_INDEX_EXTRA_TRANS_BLOCKS),
+                * allocate new inode (bitmap, group descriptor, inode block,
+                * quota blocks, sb is already counted in previous macros).
+                */
+               credits = EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
+                         EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +
+                         EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
+       }
 retry:
-       handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
-                                       EXT4_INDEX_EXTRA_TRANS_BLOCKS + 5 +
-                                       EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb));
+       handle = ext4_journal_start(dir, credits);
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -2263,21 +2292,44 @@ retry:
        if (IS_ERR(inode))
                goto out_stop;
 
-       if (l > sizeof(EXT4_I(inode)->i_data)) {
+       if (l > EXT4_N_BLOCKS * 4) {
                inode->i_op = &ext4_symlink_inode_operations;
                ext4_set_aops(inode);
                /*
-                * page_symlink() calls into ext4_prepare/commit_write.
-                * We have a transaction open.  All is sweetness.  It also sets
-                * i_size in generic_commit_write().
+                * We cannot call page_symlink() with transaction started
+                * because it calls into ext4_write_begin() which can wait
+                * for transaction commit if we are running out of space
+                * and thus we deadlock. So we have to stop transaction now
+                * and restart it when symlink contents is written.
+                * 
+                * To keep fs consistent in case of crash, we have to put inode
+                * to orphan list in the mean time.
                 */
+               drop_nlink(inode);
+               err = ext4_orphan_add(handle, inode);
+               ext4_journal_stop(handle);
+               if (err)
+                       goto err_drop_inode;
                err = __page_symlink(inode, symname, l, 1);
+               if (err)
+                       goto err_drop_inode;
+               /*
+                * Now inode is being linked into dir (EXT4_DATA_TRANS_BLOCKS
+                * + EXT4_INDEX_EXTRA_TRANS_BLOCKS), inode is also modified
+                */
+               handle = ext4_journal_start(dir,
+                               EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
+                               EXT4_INDEX_EXTRA_TRANS_BLOCKS + 1);
+               if (IS_ERR(handle)) {
+                       err = PTR_ERR(handle);
+                       goto err_drop_inode;
+               }
+               inc_nlink(inode);
+               err = ext4_orphan_del(handle, inode);
                if (err) {
+                       ext4_journal_stop(handle);
                        clear_nlink(inode);
-                       unlock_new_inode(inode);
-                       ext4_mark_inode_dirty(handle, inode);
-                       iput(inode);
-                       goto out_stop;
+                       goto err_drop_inode;
                }
        } else {
                /* clear the extent format for fast symlink */
@@ -2293,6 +2345,10 @@ out_stop:
        if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
                goto retry;
        return err;
+err_drop_inode:
+       unlock_new_inode(inode);
+       iput(inode);
+       return err;
 }
 
 static int ext4_link(struct dentry *old_dentry,
index b6dbd056fcb1d7f532f428e34cae4ef5248680ce..7bb8f76d470a019dd3801c6b9d8e6d76825f96c2 100644 (file)
@@ -203,46 +203,29 @@ static void ext4_end_bio(struct bio *bio, int error)
        for (i = 0; i < io_end->num_io_pages; i++) {
                struct page *page = io_end->pages[i]->p_page;
                struct buffer_head *bh, *head;
-               int partial_write = 0;
+               loff_t offset;
+               loff_t io_end_offset;
 
-               head = page_buffers(page);
-               if (error)
+               if (error) {
                        SetPageError(page);
-               BUG_ON(!head);
-               if (head->b_size != PAGE_CACHE_SIZE) {
-                       loff_t offset;
-                       loff_t io_end_offset = io_end->offset + io_end->size;
+                       set_bit(AS_EIO, &page->mapping->flags);
+                       head = page_buffers(page);
+                       BUG_ON(!head);
+
+                       io_end_offset = io_end->offset + io_end->size;
 
                        offset = (sector_t) page->index << PAGE_CACHE_SHIFT;
                        bh = head;
                        do {
                                if ((offset >= io_end->offset) &&
-                                   (offset+bh->b_size <= io_end_offset)) {
-                                       if (error)
-                                               buffer_io_error(bh);
-
-                               }
-                               if (buffer_delay(bh))
-                                       partial_write = 1;
-                               else if (!buffer_mapped(bh))
-                                       clear_buffer_dirty(bh);
-                               else if (buffer_dirty(bh))
-                                       partial_write = 1;
+                                   (offset+bh->b_size <= io_end_offset))
+                                       buffer_io_error(bh);
+
                                offset += bh->b_size;
                                bh = bh->b_this_page;
                        } while (bh != head);
                }
 
-               /*
-                * If this is a partial write which happened to make
-                * all buffers uptodate then we can optimize away a
-                * bogus readpage() for the next read(). Here we
-                * 'discover' whether the page went uptodate as a
-                * result of this (potentially partial) write.
-                */
-               if (!partial_write)
-                       SetPageUptodate(page);
-
                put_io_page(io_end->pages[i]);
        }
        io_end->num_io_pages = 0;
index 8553dfb310afd7ac2209d186125287e99a867f61..9ea71aa864b3a620667aed2c7fbbe5348341d312 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/ctype.h>
 #include <linux/log2.h>
 #include <linux/crc16.h>
+#include <linux/cleancache.h>
 #include <asm/uaccess.h>
 
 #include <linux/kthread.h>
@@ -75,11 +76,27 @@ static void ext4_write_super(struct super_block *sb);
 static int ext4_freeze(struct super_block *sb);
 static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags,
                       const char *dev_name, void *data);
+static inline int ext2_feature_set_ok(struct super_block *sb);
+static inline int ext3_feature_set_ok(struct super_block *sb);
 static int ext4_feature_set_ok(struct super_block *sb, int readonly);
 static void ext4_destroy_lazyinit_thread(void);
 static void ext4_unregister_li_request(struct super_block *sb);
 static void ext4_clear_request_list(void);
 
+#if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23)
+static struct file_system_type ext2_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "ext2",
+       .mount          = ext4_mount,
+       .kill_sb        = kill_block_super,
+       .fs_flags       = FS_REQUIRES_DEV,
+};
+#define IS_EXT2_SB(sb) ((sb)->s_bdev->bd_holder == &ext2_fs_type)
+#else
+#define IS_EXT2_SB(sb) (0)
+#endif
+
+
 #if !defined(CONFIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23)
 static struct file_system_type ext3_fs_type = {
        .owner          = THIS_MODULE,
@@ -806,6 +823,8 @@ static void ext4_put_super(struct super_block *sb)
                invalidate_bdev(sbi->journal_bdev);
                ext4_blkdev_remove(sbi);
        }
+       if (sbi->s_mmp_tsk)
+               kthread_stop(sbi->s_mmp_tsk);
        sb->s_fs_info = NULL;
        /*
         * Now that we are completely done shutting down the
@@ -1096,7 +1115,7 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
 
        if (!test_opt(sb, INIT_INODE_TABLE))
                seq_puts(seq, ",noinit_inode_table");
-       else if (sbi->s_li_wait_mult)
+       else if (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT)
                seq_printf(seq, ",init_inode_table=%u",
                           (unsigned) sbi->s_li_wait_mult);
 
@@ -1187,9 +1206,7 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
                                const char *data, size_t len, loff_t off);
 
 static const struct dquot_operations ext4_quota_operations = {
-#ifdef CONFIG_QUOTA
        .get_reserved_space = ext4_get_reserved_space,
-#endif
        .write_dquot    = ext4_write_dquot,
        .acquire_dquot  = ext4_acquire_dquot,
        .release_dquot  = ext4_release_dquot,
@@ -1900,7 +1917,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
                ext4_msg(sb, KERN_WARNING,
                         "warning: mounting fs with errors, "
                         "running e2fsck is recommended");
-       else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 &&
+       else if ((__s16) le16_to_cpu(es->s_max_mnt_count) > 0 &&
                 le16_to_cpu(es->s_mnt_count) >=
                 (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count))
                ext4_msg(sb, KERN_WARNING,
@@ -1932,6 +1949,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
                        EXT4_INODES_PER_GROUP(sb),
                        sbi->s_mount_opt, sbi->s_mount_opt2);
 
+       cleancache_init_fs(sb);
        return res;
 }
 
@@ -2225,6 +2243,12 @@ static void ext4_orphan_cleanup(struct super_block *sb,
  * in the vfs.  ext4 inode has 48 bits of i_block in fsblock units,
  * so that won't be a limiting factor.
  *
+ * However there is other limiting factor. We do store extents in the form
+ * of starting block and length, hence the resulting length of the extent
+ * covering maximum file size must fit into on-disk format containers as
+ * well. Given that length is always by 1 unit bigger than max unit (because
+ * we count 0 as well) we have to lower the s_maxbytes by one fs block.
+ *
  * Note, this does *not* consider any metadata overhead for vfs i_blocks.
  */
 static loff_t ext4_max_size(int blkbits, int has_huge_files)
@@ -2246,10 +2270,13 @@ static loff_t ext4_max_size(int blkbits, int has_huge_files)
                upper_limit <<= blkbits;
        }
 
-       /* 32-bit extent-start container, ee_block */
-       res = 1LL << 32;
+       /*
+        * 32-bit extent-start container, ee_block. We lower the maxbytes
+        * by one fs block, so ee_len can cover the extent of maximum file
+        * size
+        */
+       res = (1LL << 32) - 1;
        res <<= blkbits;
-       res -= 1;
 
        /* Sanity check against vm- & vfs- imposed limits */
        if (res > upper_limit)
@@ -2425,6 +2452,18 @@ static ssize_t lifetime_write_kbytes_show(struct ext4_attr *a,
                          EXT4_SB(sb)->s_sectors_written_start) >> 1)));
 }
 
+static ssize_t extent_cache_hits_show(struct ext4_attr *a,
+                                     struct ext4_sb_info *sbi, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%lu\n", sbi->extent_cache_hits);
+}
+
+static ssize_t extent_cache_misses_show(struct ext4_attr *a,
+                                       struct ext4_sb_info *sbi, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%lu\n", sbi->extent_cache_misses);
+}
+
 static ssize_t inode_readahead_blks_store(struct ext4_attr *a,
                                          struct ext4_sb_info *sbi,
                                          const char *buf, size_t count)
@@ -2482,6 +2521,8 @@ static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store)
 EXT4_RO_ATTR(delayed_allocation_blocks);
 EXT4_RO_ATTR(session_write_kbytes);
 EXT4_RO_ATTR(lifetime_write_kbytes);
+EXT4_RO_ATTR(extent_cache_hits);
+EXT4_RO_ATTR(extent_cache_misses);
 EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, sbi_ui_show,
                 inode_readahead_blks_store, s_inode_readahead_blks);
 EXT4_RW_ATTR_SBI_UI(inode_goal, s_inode_goal);
@@ -2497,6 +2538,8 @@ static struct attribute *ext4_attrs[] = {
        ATTR_LIST(delayed_allocation_blocks),
        ATTR_LIST(session_write_kbytes),
        ATTR_LIST(lifetime_write_kbytes),
+       ATTR_LIST(extent_cache_hits),
+       ATTR_LIST(extent_cache_misses),
        ATTR_LIST(inode_readahead_blks),
        ATTR_LIST(inode_goal),
        ATTR_LIST(mb_stats),
@@ -2659,12 +2702,6 @@ static void print_daily_error_info(unsigned long arg)
        mod_timer(&sbi->s_err_report, jiffies + 24*60*60*HZ);  /* Once a day */
 }
 
-static void ext4_lazyinode_timeout(unsigned long data)
-{
-       struct task_struct *p = (struct task_struct *)data;
-       wake_up_process(p);
-}
-
 /* Find next suitable group and run ext4_init_inode_table */
 static int ext4_run_li_request(struct ext4_li_request *elr)
 {
@@ -2696,11 +2733,8 @@ static int ext4_run_li_request(struct ext4_li_request *elr)
                ret = ext4_init_inode_table(sb, group,
                                            elr->lr_timeout ? 0 : 1);
                if (elr->lr_timeout == 0) {
-                       timeout = jiffies - timeout;
-                       if (elr->lr_sbi->s_li_wait_mult)
-                               timeout *= elr->lr_sbi->s_li_wait_mult;
-                       else
-                               timeout *= 20;
+                       timeout = (jiffies - timeout) *
+                                 elr->lr_sbi->s_li_wait_mult;
                        elr->lr_timeout = timeout;
                }
                elr->lr_next_sched = jiffies + elr->lr_timeout;
@@ -2712,7 +2746,7 @@ static int ext4_run_li_request(struct ext4_li_request *elr)
 
 /*
  * Remove lr_request from the list_request and free the
- * request tructure. Should be called with li_list_mtx held
+ * request structure. Should be called with li_list_mtx held
  */
 static void ext4_remove_li_request(struct ext4_li_request *elr)
 {
@@ -2730,14 +2764,16 @@ static void ext4_remove_li_request(struct ext4_li_request *elr)
 
 static void ext4_unregister_li_request(struct super_block *sb)
 {
-       struct ext4_li_request *elr = EXT4_SB(sb)->s_li_request;
-
-       if (!ext4_li_info)
+       mutex_lock(&ext4_li_mtx);
+       if (!ext4_li_info) {
+               mutex_unlock(&ext4_li_mtx);
                return;
+       }
 
        mutex_lock(&ext4_li_info->li_list_mtx);
-       ext4_remove_li_request(elr);
+       ext4_remove_li_request(EXT4_SB(sb)->s_li_request);
        mutex_unlock(&ext4_li_info->li_list_mtx);
+       mutex_unlock(&ext4_li_mtx);
 }
 
 static struct task_struct *ext4_lazyinit_task;
@@ -2756,17 +2792,10 @@ static int ext4_lazyinit_thread(void *arg)
        struct ext4_lazy_init *eli = (struct ext4_lazy_init *)arg;
        struct list_head *pos, *n;
        struct ext4_li_request *elr;
-       unsigned long next_wakeup;
-       DEFINE_WAIT(wait);
+       unsigned long next_wakeup, cur;
 
        BUG_ON(NULL == eli);
 
-       eli->li_timer.data = (unsigned long)current;
-       eli->li_timer.function = ext4_lazyinode_timeout;
-
-       eli->li_task = current;
-       wake_up(&eli->li_wait_task);
-
 cont_thread:
        while (true) {
                next_wakeup = MAX_JIFFY_OFFSET;
@@ -2797,19 +2826,15 @@ cont_thread:
                if (freezing(current))
                        refrigerator();
 
-               if ((time_after_eq(jiffies, next_wakeup)) ||
+               cur = jiffies;
+               if ((time_after_eq(cur, next_wakeup)) ||
                    (MAX_JIFFY_OFFSET == next_wakeup)) {
                        cond_resched();
                        continue;
                }
 
-               eli->li_timer.expires = next_wakeup;
-               add_timer(&eli->li_timer);
-               prepare_to_wait(&eli->li_wait_daemon, &wait,
-                               TASK_INTERRUPTIBLE);
-               if (time_before(jiffies, next_wakeup))
-                       schedule();
-               finish_wait(&eli->li_wait_daemon, &wait);
+               schedule_timeout_interruptible(next_wakeup - cur);
+
                if (kthread_should_stop()) {
                        ext4_clear_request_list();
                        goto exit_thread;
@@ -2833,12 +2858,7 @@ exit_thread:
                goto cont_thread;
        }
        mutex_unlock(&eli->li_list_mtx);
-       del_timer_sync(&ext4_li_info->li_timer);
-       eli->li_task = NULL;
-       wake_up(&eli->li_wait_task);
-
        kfree(ext4_li_info);
-       ext4_lazyinit_task = NULL;
        ext4_li_info = NULL;
        mutex_unlock(&ext4_li_mtx);
 
@@ -2866,7 +2886,6 @@ static int ext4_run_lazyinit_thread(void)
        if (IS_ERR(ext4_lazyinit_task)) {
                int err = PTR_ERR(ext4_lazyinit_task);
                ext4_clear_request_list();
-               del_timer_sync(&ext4_li_info->li_timer);
                kfree(ext4_li_info);
                ext4_li_info = NULL;
                printk(KERN_CRIT "EXT4: error %d creating inode table "
@@ -2875,8 +2894,6 @@ static int ext4_run_lazyinit_thread(void)
                return err;
        }
        ext4_li_info->li_state |= EXT4_LAZYINIT_RUNNING;
-
-       wait_event(ext4_li_info->li_wait_task, ext4_li_info->li_task != NULL);
        return 0;
 }
 
@@ -2911,13 +2928,9 @@ static int ext4_li_info_new(void)
        if (!eli)
                return -ENOMEM;
 
-       eli->li_task = NULL;
        INIT_LIST_HEAD(&eli->li_request_list);
        mutex_init(&eli->li_list_mtx);
 
-       init_waitqueue_head(&eli->li_wait_daemon);
-       init_waitqueue_head(&eli->li_wait_task);
-       init_timer(&eli->li_timer);
        eli->li_state |= EXT4_LAZYINIT_QUIT;
 
        ext4_li_info = eli;
@@ -2960,20 +2973,19 @@ static int ext4_register_li_request(struct super_block *sb,
        ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
        int ret = 0;
 
-       if (sbi->s_li_request != NULL)
+       if (sbi->s_li_request != NULL) {
+               /*
+                * Reset timeout so it can be computed again, because
+                * s_li_wait_mult might have changed.
+                */
+               sbi->s_li_request->lr_timeout = 0;
                return 0;
+       }
 
        if (first_not_zeroed == ngroups ||
            (sb->s_flags & MS_RDONLY) ||
-           !test_opt(sb, INIT_INODE_TABLE)) {
-               sbi->s_li_request = NULL;
+           !test_opt(sb, INIT_INODE_TABLE))
                return 0;
-       }
-
-       if (first_not_zeroed == ngroups) {
-               sbi->s_li_request = NULL;
-               return 0;
-       }
 
        elr = ext4_li_request_new(sb, first_not_zeroed);
        if (!elr)
@@ -3166,6 +3178,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
            ((def_mount_opts & EXT4_DEFM_NODELALLOC) == 0))
                set_opt(sb, DELALLOC);
 
+       /*
+        * set default s_li_wait_mult for lazyinit, for the case there is
+        * no mount option specified.
+        */
+       sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT;
+
        if (!parse_options((char *) sbi->s_es->s_mount_opts, sb,
                           &journal_devnum, &journal_ioprio, NULL, 0)) {
                ext4_msg(sb, KERN_WARNING,
@@ -3187,6 +3205,28 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                       "feature flags set on rev 0 fs, "
                       "running e2fsck is recommended");
 
+       if (IS_EXT2_SB(sb)) {
+               if (ext2_feature_set_ok(sb))
+                       ext4_msg(sb, KERN_INFO, "mounting ext2 file system "
+                                "using the ext4 subsystem");
+               else {
+                       ext4_msg(sb, KERN_ERR, "couldn't mount as ext2 due "
+                                "to feature incompatibilities");
+                       goto failed_mount;
+               }
+       }
+
+       if (IS_EXT3_SB(sb)) {
+               if (ext3_feature_set_ok(sb))
+                       ext4_msg(sb, KERN_INFO, "mounting ext3 file system "
+                                "using the ext4 subsystem");
+               else {
+                       ext4_msg(sb, KERN_ERR, "couldn't mount as ext3 due "
+                                "to feature incompatibilities");
+                       goto failed_mount;
+               }
+       }
+
        /*
         * Check feature flags regardless of the revision level, since we
         * previously didn't change the revision level when setting the flags,
@@ -3459,6 +3499,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                          EXT4_HAS_INCOMPAT_FEATURE(sb,
                                    EXT4_FEATURE_INCOMPAT_RECOVER));
 
+       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_MMP) &&
+           !(sb->s_flags & MS_RDONLY))
+               if (ext4_multi_mount_protect(sb, le64_to_cpu(es->s_mmp_block)))
+                       goto failed_mount3;
+
        /*
         * The first inode we look at is the journal inode.  Don't try
         * root first: it may be modified in the journal!
@@ -3474,7 +3519,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                goto failed_mount_wq;
        } else {
                clear_opt(sb, DATA_FLAGS);
-               set_opt(sb, WRITEBACK_DATA);
                sbi->s_journal = NULL;
                needs_recovery = 0;
                goto no_journal;
@@ -3707,6 +3751,8 @@ failed_mount3:
        percpu_counter_destroy(&sbi->s_freeinodes_counter);
        percpu_counter_destroy(&sbi->s_dirs_counter);
        percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
+       if (sbi->s_mmp_tsk)
+               kthread_stop(sbi->s_mmp_tsk);
 failed_mount2:
        for (i = 0; i < db_count; i++)
                brelse(sbi->s_group_desc[i]);
@@ -4242,7 +4288,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
        int enable_quota = 0;
        ext4_group_t g;
        unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
-       int err;
+       int err = 0;
 #ifdef CONFIG_QUOTA
        int i;
 #endif
@@ -4368,6 +4414,13 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                                goto restore_opts;
                        if (!ext4_setup_super(sb, es, 0))
                                sb->s_flags &= ~MS_RDONLY;
+                       if (EXT4_HAS_INCOMPAT_FEATURE(sb,
+                                                    EXT4_FEATURE_INCOMPAT_MMP))
+                               if (ext4_multi_mount_protect(sb,
+                                               le64_to_cpu(es->s_mmp_block))) {
+                                       err = -EROFS;
+                                       goto restore_opts;
+                               }
                        enable_quota = 1;
                }
        }
@@ -4432,6 +4485,7 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct ext4_super_block *es = sbi->s_es;
        u64 fsid;
+       s64 bfree;
 
        if (test_opt(sb, MINIX_DF)) {
                sbi->s_overhead_last = 0;
@@ -4475,8 +4529,10 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_type = EXT4_SUPER_MAGIC;
        buf->f_bsize = sb->s_blocksize;
        buf->f_blocks = ext4_blocks_count(es) - sbi->s_overhead_last;
-       buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter) -
+       bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter) -
                       percpu_counter_sum_positive(&sbi->s_dirtyblocks_counter);
+       /* prevent underflow in case that few free space is available */
+       buf->f_bfree = max_t(s64, bfree, 0);
        buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es);
        if (buf->f_bfree < ext4_r_blocks_count(es))
                buf->f_bavail = 0;
@@ -4652,6 +4708,9 @@ static int ext4_quota_off(struct super_block *sb, int type)
        if (test_opt(sb, DELALLOC))
                sync_filesystem(sb);
 
+       if (!inode)
+               goto out;
+
        /* Update modification times of quota files when userspace can
         * start looking at them */
        handle = ext4_journal_start(inode, 1);
@@ -4772,14 +4831,6 @@ static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags,
 }
 
 #if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23)
-static struct file_system_type ext2_fs_type = {
-       .owner          = THIS_MODULE,
-       .name           = "ext2",
-       .mount          = ext4_mount,
-       .kill_sb        = kill_block_super,
-       .fs_flags       = FS_REQUIRES_DEV,
-};
-
 static inline void register_as_ext2(void)
 {
        int err = register_filesystem(&ext2_fs_type);
@@ -4792,10 +4843,22 @@ static inline void unregister_as_ext2(void)
 {
        unregister_filesystem(&ext2_fs_type);
 }
+
+static inline int ext2_feature_set_ok(struct super_block *sb)
+{
+       if (EXT4_HAS_INCOMPAT_FEATURE(sb, ~EXT2_FEATURE_INCOMPAT_SUPP))
+               return 0;
+       if (sb->s_flags & MS_RDONLY)
+               return 1;
+       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT2_FEATURE_RO_COMPAT_SUPP))
+               return 0;
+       return 1;
+}
 MODULE_ALIAS("ext2");
 #else
 static inline void register_as_ext2(void) { }
 static inline void unregister_as_ext2(void) { }
+static inline int ext2_feature_set_ok(struct super_block *sb) { return 0; }
 #endif
 
 #if !defined(CONFIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23)
@@ -4811,10 +4874,24 @@ static inline void unregister_as_ext3(void)
 {
        unregister_filesystem(&ext3_fs_type);
 }
+
+static inline int ext3_feature_set_ok(struct super_block *sb)
+{
+       if (EXT4_HAS_INCOMPAT_FEATURE(sb, ~EXT3_FEATURE_INCOMPAT_SUPP))
+               return 0;
+       if (!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL))
+               return 0;
+       if (sb->s_flags & MS_RDONLY)
+               return 1;
+       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT3_FEATURE_RO_COMPAT_SUPP))
+               return 0;
+       return 1;
+}
 MODULE_ALIAS("ext3");
 #else
 static inline void register_as_ext3(void) { }
 static inline void unregister_as_ext3(void) { }
+static inline int ext3_feature_set_ok(struct super_block *sb) { return 0; }
 #endif
 
 static struct file_system_type ext4_fs_type = {
@@ -4898,8 +4975,8 @@ static int __init ext4_init_fs(void)
        err = init_inodecache();
        if (err)
                goto out1;
-       register_as_ext2();
        register_as_ext3();
+       register_as_ext2();
        err = register_filesystem(&ext4_fs_type);
        if (err)
                goto out;
index b545ca1c459c42e2cc6aef35ce49dea3fcd2694d..c757adc972506d672c78b7de03e654ede7eb8b1e 100644 (file)
@@ -820,8 +820,8 @@ inserted:
                        if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
                                goal = goal & EXT4_MAX_BLOCK_FILE_PHYS;
 
-                       block = ext4_new_meta_blocks(handle, inode,
-                                                 goal, NULL, &error);
+                       block = ext4_new_meta_blocks(handle, inode, goal, 0,
+                                                    NULL, &error);
                        if (error)
                                goto cleanup;
 
index 7257752b6d5d3f0c8c133597135cb2f92821f784..7018e1d8902dee6c4b38f7247a38e9315cba27f5 100644 (file)
@@ -102,7 +102,7 @@ static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr)
                if (attr & ATTR_SYS)
                        inode->i_flags |= S_IMMUTABLE;
                else
-                       inode->i_flags &= S_IMMUTABLE;
+                       inode->i_flags &= ~S_IMMUTABLE;
        }
 
        fat_save_attrs(inode, attr);
index 34591ee804b58ad8e81ee04b3754dba1bcf77f8c..0f015a0468de53e7c4b27a9a5efdfeb9fa4cd67b 100644 (file)
@@ -1007,9 +1007,6 @@ static noinline void block_dump___mark_inode_dirty(struct inode *inode)
  * In short, make sure you hash any inodes _before_ you start marking
  * them dirty.
  *
- * This function *must* be atomic for the I_DIRTY_PAGES case -
- * set_page_dirty() is called under spinlock in several places.
- *
  * Note that for blockdevs, inode->dirtied_when represents the dirtying time of
  * the block-special inode (/dev/hda1) itself.  And the ->dirtied_when field of
  * the kernel-internal blockdev inode represents the dirtying time of the
@@ -1028,7 +1025,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
         */
        if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) {
                if (sb->s_op->dirty_inode)
-                       sb->s_op->dirty_inode(inode);
+                       sb->s_op->dirty_inode(inode, flags);
        }
 
        /*
index 48a18f184d5041b9f4909137898fe0fd51bc45d8..30afdfa7aec78b6a7e47ab791fbf9ec1198870d6 100644 (file)
@@ -33,8 +33,6 @@ void fscache_enqueue_operation(struct fscache_operation *op)
        _enter("{OBJ%x OP%x,%u}",
               op->object->debug_id, op->debug_id, atomic_read(&op->usage));
 
-       fscache_set_op_state(op, "EnQ");
-
        ASSERT(list_empty(&op->pend_link));
        ASSERT(op->processor != NULL);
        ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE);
@@ -66,8 +64,6 @@ EXPORT_SYMBOL(fscache_enqueue_operation);
 static void fscache_run_op(struct fscache_object *object,
                           struct fscache_operation *op)
 {
-       fscache_set_op_state(op, "Run");
-
        object->n_in_progress++;
        if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags))
                wake_up_bit(&op->flags, FSCACHE_OP_WAITING);
@@ -88,8 +84,6 @@ int fscache_submit_exclusive_op(struct fscache_object *object,
 
        _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id);
 
-       fscache_set_op_state(op, "SubmitX");
-
        spin_lock(&object->lock);
        ASSERTCMP(object->n_ops, >=, object->n_in_progress);
        ASSERTCMP(object->n_ops, >=, object->n_exclusive);
@@ -194,8 +188,6 @@ int fscache_submit_op(struct fscache_object *object,
 
        ASSERTCMP(atomic_read(&op->usage), >, 0);
 
-       fscache_set_op_state(op, "Submit");
-
        spin_lock(&object->lock);
        ASSERTCMP(object->n_ops, >=, object->n_in_progress);
        ASSERTCMP(object->n_ops, >=, object->n_exclusive);
@@ -335,8 +327,6 @@ void fscache_put_operation(struct fscache_operation *op)
        if (!atomic_dec_and_test(&op->usage))
                return;
 
-       fscache_set_op_state(op, "Put");
-
        _debug("PUT OP");
        if (test_and_set_bit(FSCACHE_OP_DEAD, &op->flags))
                BUG();
index 41c441c2058daad798aff3766cb5444c9961b44a..a2a5d19ece6adc92b3deda283bd6f5db1f2c701c 100644 (file)
@@ -155,11 +155,9 @@ static void fscache_attr_changed_op(struct fscache_operation *op)
        fscache_stat(&fscache_n_attr_changed_calls);
 
        if (fscache_object_is_active(object)) {
-               fscache_set_op_state(op, "CallFS");
                fscache_stat(&fscache_n_cop_attr_changed);
                ret = object->cache->ops->attr_changed(object);
                fscache_stat_d(&fscache_n_cop_attr_changed);
-               fscache_set_op_state(op, "Done");
                if (ret < 0)
                        fscache_abort_object(object);
        }
@@ -190,7 +188,6 @@ int __fscache_attr_changed(struct fscache_cookie *cookie)
 
        fscache_operation_init(op, fscache_attr_changed_op, NULL);
        op->flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_EXCLUSIVE);
-       fscache_set_op_name(op, "Attr");
 
        spin_lock(&cookie->lock);
 
@@ -257,7 +254,6 @@ static struct fscache_retrieval *fscache_alloc_retrieval(
        op->context     = context;
        op->start_time  = jiffies;
        INIT_LIST_HEAD(&op->to_do);
-       fscache_set_op_name(&op->op, "Retr");
        return op;
 }
 
@@ -368,7 +364,6 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie,
                _leave(" = -ENOMEM");
                return -ENOMEM;
        }
-       fscache_set_op_name(&op->op, "RetrRA1");
 
        spin_lock(&cookie->lock);
 
@@ -487,7 +482,6 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie,
        op = fscache_alloc_retrieval(mapping, end_io_func, context);
        if (!op)
                return -ENOMEM;
-       fscache_set_op_name(&op->op, "RetrRAN");
 
        spin_lock(&cookie->lock);
 
@@ -589,7 +583,6 @@ int __fscache_alloc_page(struct fscache_cookie *cookie,
        op = fscache_alloc_retrieval(page->mapping, NULL, NULL);
        if (!op)
                return -ENOMEM;
-       fscache_set_op_name(&op->op, "RetrAL1");
 
        spin_lock(&cookie->lock);
 
@@ -662,8 +655,6 @@ static void fscache_write_op(struct fscache_operation *_op)
 
        _enter("{OP%x,%d}", op->op.debug_id, atomic_read(&op->op.usage));
 
-       fscache_set_op_state(&op->op, "GetPage");
-
        spin_lock(&object->lock);
        cookie = object->cookie;
 
@@ -698,15 +689,12 @@ static void fscache_write_op(struct fscache_operation *_op)
        spin_unlock(&cookie->stores_lock);
        spin_unlock(&object->lock);
 
-       fscache_set_op_state(&op->op, "Store");
        fscache_stat(&fscache_n_store_pages);
        fscache_stat(&fscache_n_cop_write_page);
        ret = object->cache->ops->write_page(op, page);
        fscache_stat_d(&fscache_n_cop_write_page);
-       fscache_set_op_state(&op->op, "EndWrite");
        fscache_end_page_write(object, page);
        if (ret < 0) {
-               fscache_set_op_state(&op->op, "Abort");
                fscache_abort_object(object);
        } else {
                fscache_enqueue_operation(&op->op);
@@ -778,7 +766,6 @@ int __fscache_write_page(struct fscache_cookie *cookie,
        fscache_operation_init(&op->op, fscache_write_op,
                               fscache_release_write_op);
        op->op.flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_WAITING);
-       fscache_set_op_name(&op->op, "Write1");
 
        ret = radix_tree_preload(gfp & ~__GFP_HIGHMEM);
        if (ret < 0)
index b32eb29a4e6ff4f8dd892b1af9ea74d712f148ee..d501607145951d7b5f4b1ac62e230eae27e6e452 100644 (file)
@@ -691,6 +691,7 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
        struct fuse_rename_in inarg;
        struct fuse_conn *fc = get_fuse_conn(olddir);
        struct fuse_req *req = fuse_get_req(fc);
+
        if (IS_ERR(req))
                return PTR_ERR(req);
 
index cc6ec4b2f0ffed9c05959b149614a8a1e19e467d..38f84cd48b67d057798f8f75fe5c8f22f12b10dc 100644 (file)
@@ -921,6 +921,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
        if (sb->s_flags & MS_MANDLOCK)
                goto err;
 
+       sb->s_flags &= ~MS_NOSEC;
+
        if (!parse_fuse_opt((char *) data, &d, is_bdev))
                goto err;
 
index a2a6abbccc070194c94dfeb37913291fb57be61a..1c1336e7b3b222d347f657fa2895ddc1c2f05c65 100644 (file)
@@ -663,14 +663,19 @@ static void glock_work_func(struct work_struct *work)
                drop_ref = 1;
        }
        spin_lock(&gl->gl_spin);
-       if (test_and_clear_bit(GLF_PENDING_DEMOTE, &gl->gl_flags) &&
+       if (test_bit(GLF_PENDING_DEMOTE, &gl->gl_flags) &&
            gl->gl_state != LM_ST_UNLOCKED &&
            gl->gl_demote_state != LM_ST_EXCLUSIVE) {
                unsigned long holdtime, now = jiffies;
+
                holdtime = gl->gl_tchange + gl->gl_ops->go_min_hold_time;
                if (time_before(now, holdtime))
                        delay = holdtime - now;
-               set_bit(delay ? GLF_PENDING_DEMOTE : GLF_DEMOTE, &gl->gl_flags);
+
+               if (!delay) {
+                       clear_bit(GLF_PENDING_DEMOTE, &gl->gl_flags);
+                       set_bit(GLF_DEMOTE, &gl->gl_flags);
+               }
        }
        run_queue(gl, 0);
        spin_unlock(&gl->gl_spin);
@@ -1346,11 +1351,14 @@ void gfs2_glock_complete(struct gfs2_glock *gl, int ret)
 }
 
 
-static int gfs2_shrink_glock_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
+static int gfs2_shrink_glock_memory(struct shrinker *shrink,
+                                   struct shrink_control *sc)
 {
        struct gfs2_glock *gl;
        int may_demote;
        int nr_skipped = 0;
+       int nr = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
        LIST_HEAD(skipped);
 
        if (nr == 0)
index cfa327d331942aae3b9ee99497be51110e1a2843..c2b34cd2abe0e81f7be6eab08189817507d9f307 100644 (file)
@@ -146,7 +146,7 @@ static int __init init_gfs2_fs(void)
 
        gfs2_register_debugfs();
 
-       printk("GFS2 (built %s %s) installed\n", __DATE__, __TIME__);
+       printk("GFS2 installed\n");
 
        return 0;
 
index e23d9864c418d69c0abdce5d699a20904baa3779..42e8d23bc0472007aa0178b7d049d952175b2391 100644 (file)
@@ -38,6 +38,7 @@
 
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/mm.h>
 #include <linux/spinlock.h>
 #include <linux/completion.h>
 #include <linux/buffer_head.h>
@@ -77,19 +78,20 @@ static LIST_HEAD(qd_lru_list);
 static atomic_t qd_lru_count = ATOMIC_INIT(0);
 static DEFINE_SPINLOCK(qd_lru_lock);
 
-int gfs2_shrink_qd_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
+int gfs2_shrink_qd_memory(struct shrinker *shrink, struct shrink_control *sc)
 {
        struct gfs2_quota_data *qd;
        struct gfs2_sbd *sdp;
+       int nr_to_scan = sc->nr_to_scan;
 
-       if (nr == 0)
+       if (nr_to_scan == 0)
                goto out;
 
-       if (!(gfp_mask & __GFP_FS))
+       if (!(sc->gfp_mask & __GFP_FS))
                return -1;
 
        spin_lock(&qd_lru_lock);
-       while (nr && !list_empty(&qd_lru_list)) {
+       while (nr_to_scan && !list_empty(&qd_lru_list)) {
                qd = list_entry(qd_lru_list.next,
                                struct gfs2_quota_data, qd_reclaim);
                sdp = qd->qd_gl->gl_sbd;
@@ -110,7 +112,7 @@ int gfs2_shrink_qd_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
                spin_unlock(&qd_lru_lock);
                kmem_cache_free(gfs2_quotad_cachep, qd);
                spin_lock(&qd_lru_lock);
-               nr--;
+               nr_to_scan--;
        }
        spin_unlock(&qd_lru_lock);
 
index e7d236ca48bd28df49f8555fbaa9e1b90460fbd0..90bf1c302a983df6c74191f5c2341b8cf5c70f69 100644 (file)
@@ -12,6 +12,7 @@
 
 struct gfs2_inode;
 struct gfs2_sbd;
+struct shrink_control;
 
 #define NO_QUOTA_CHANGE ((u32)-1)
 
@@ -51,7 +52,8 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip)
        return ret;
 }
 
-extern int gfs2_shrink_qd_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask);
+extern int gfs2_shrink_qd_memory(struct shrinker *shrink,
+                                struct shrink_control *sc);
 extern const struct quotactl_ops gfs2_quotactl_ops;
 
 #endif /* __QUOTA_DOT_H__ */
index 1f05839c27a7fca1f24c99dda71adf07bb2930c5..acf95dab2aac97e38ae6a5d8209c70f107189ef9 100644 (file)
@@ -395,7 +395,6 @@ again:
 
                dentry_unhash(dentry);
                if (!d_unhashed(dentry)) {
-                       dput(dentry);
                        hpfs_unlock(dir->i_sb);
                        return -ENOSPC;
                }
@@ -403,7 +402,6 @@ again:
                    !S_ISREG(inode->i_mode) ||
                    get_write_access(inode)) {
                        d_rehash(dentry);
-                       dput(dentry);
                } else {
                        struct iattr newattrs;
                        /*printk("HPFS: truncating file before delete.\n");*/
@@ -411,7 +409,6 @@ again:
                        newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
                        err = notify_change(dentry, &newattrs);
                        put_write_access(inode);
-                       dput(dentry);
                        if (!err)
                                goto again;
                }
@@ -535,6 +532,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct buffer_head *bh;
        struct fnode *fnode;
        int err;
+
        if ((err = hpfs_chk_name(new_name, &new_len))) return err;
        err = 0;
        hpfs_adjust_length(old_name, &old_len);
index b9eeb1cd03ff540dc87aa31f43dc9eb03fbafb61..7aafeb8fa3005eb14fd09f75d94c17dbeefe8481 100644 (file)
@@ -412,10 +412,10 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset)
        pgoff = offset >> PAGE_SHIFT;
 
        i_size_write(inode, offset);
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
        if (!prio_tree_empty(&mapping->i_mmap))
                hugetlb_vmtruncate_list(&mapping->i_mmap, pgoff);
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
        truncate_hugepages(inode, offset);
        return 0;
 }
@@ -921,7 +921,8 @@ static int can_do_hugetlb_shm(void)
        return capable(CAP_IPC_LOCK) || in_group_p(sysctl_hugetlb_shm_group);
 }
 
-struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag,
+struct file *hugetlb_file_setup(const char *name, size_t size,
+                               vm_flags_t acctflag,
                                struct user_struct **user, int creat_flags)
 {
        int error = -ENOMEM;
index 05f4fa521325b071f7ad114354b30233b131ae48..0f7e88a7803f39e52b778eb30652654d7d61d2d1 100644 (file)
@@ -1,9 +1,7 @@
 /*
- * linux/fs/inode.c
- *
  * (C) 1997 Linus Torvalds
+ * (C) 1999 Andrea Arcangeli <andrea@suse.de> (dynamic inode allocation)
  */
-
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/dcache.h>
 #include <linux/prefetch.h>
 #include <linux/ima.h>
 #include <linux/cred.h>
+#include <linux/buffer_head.h> /* for inode_has_buffers */
 #include "internal.h"
 
 /*
- * inode locking rules.
+ * Inode locking rules:
  *
  * inode->i_lock protects:
  *   inode->i_state, inode->i_hash, __iget()
  *   inode_hash_lock
  */
 
-/*
- * This is needed for the following functions:
- *  - inode_has_buffers
- *  - invalidate_bdev
- *
- * FIXME: remove all knowledge of the buffer layer from this file
- */
-#include <linux/buffer_head.h>
-
-/*
- * New inode.c implementation.
- *
- * This implementation has the basic premise of trying
- * to be extremely low-overhead and SMP-safe, yet be
- * simple enough to be "obviously correct".
- *
- * Famous last words.
- */
-
-/* inode dynamic allocation 1999, Andrea Arcangeli <andrea@suse.de> */
-
-/* #define INODE_PARANOIA 1 */
-/* #define INODE_DEBUG 1 */
-
-/*
- * Inode lookup is no longer as critical as it used to be:
- * most of the lookups are going to be through the dcache.
- */
-#define I_HASHBITS     i_hash_shift
-#define I_HASHMASK     i_hash_mask
-
 static unsigned int i_hash_mask __read_mostly;
 static unsigned int i_hash_shift __read_mostly;
 static struct hlist_head *inode_hashtable __read_mostly;
 static __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_hash_lock);
 
-/*
- * Each inode can be on two separate lists. One is
- * the hash list of the inode, used for lookups. The
- * other linked list is the "type" list:
- *  "in_use" - valid inode, i_count > 0, i_nlink > 0
- *  "dirty"  - as "in_use" but also dirty
- *  "unused" - valid inode, i_count = 0
- *
- * A "dirty" list is maintained for each super block,
- * allowing for low-overhead inode sync() operations.
- */
-
 static LIST_HEAD(inode_lru);
 static DEFINE_SPINLOCK(inode_lru_lock);
 
@@ -326,12 +282,11 @@ void address_space_init_once(struct address_space *mapping)
        memset(mapping, 0, sizeof(*mapping));
        INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC);
        spin_lock_init(&mapping->tree_lock);
-       spin_lock_init(&mapping->i_mmap_lock);
+       mutex_init(&mapping->i_mmap_mutex);
        INIT_LIST_HEAD(&mapping->private_list);
        spin_lock_init(&mapping->private_lock);
        INIT_RAW_PRIO_TREE_ROOT(&mapping->i_mmap);
        INIT_LIST_HEAD(&mapping->i_mmap_nonlinear);
-       mutex_init(&mapping->unmap_mutex);
 }
 EXPORT_SYMBOL(address_space_init_once);
 
@@ -425,8 +380,8 @@ static unsigned long hash(struct super_block *sb, unsigned long hashval)
 
        tmp = (hashval * (unsigned long)sb) ^ (GOLDEN_RATIO_PRIME + hashval) /
                        L1_CACHE_BYTES;
-       tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> I_HASHBITS);
-       return tmp & I_HASHMASK;
+       tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> i_hash_shift);
+       return tmp & i_hash_mask;
 }
 
 /**
@@ -752,8 +707,12 @@ static void prune_icache(int nr_to_scan)
  * This function is passed the number of inodes to scan, and it returns the
  * total number of remaining possibly-reclaimable inodes.
  */
-static int shrink_icache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
+static int shrink_icache_memory(struct shrinker *shrink,
+                               struct shrink_control *sc)
 {
+       int nr = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
+
        if (nr) {
                /*
                 * Nasty deadlock avoidance.  We may hold various FS locks,
index 3db5ba4568fc8efd30025a9e9906eb01a47f9c45..b3cc8586984e9748ff3c66e6c8703fa84c822c1c 100644 (file)
@@ -974,7 +974,7 @@ out_no_inode:
 out_no_read:
        printk(KERN_WARNING "%s: bread failed, dev=%s, iso_blknum=%d, block=%d\n",
                __func__, s->s_id, iso_blknum, block);
-       goto out_freesbi;
+       goto out_freebh;
 out_bad_zone_size:
        printk(KERN_WARNING "ISOFS: Bad logical zone size %ld\n",
                sbi->s_log_zone_size);
@@ -989,6 +989,7 @@ out_unknown_format:
 
 out_freebh:
        brelse(bh);
+       brelse(pri_bh);
 out_freesbi:
        kfree(opt.iocharset);
        kfree(sbi);
index 69b18045946330a5a35c54226094ca0dc657a903..72ffa974b0b8d52852e25d7e016f7b4f1fc50b4a 100644 (file)
@@ -302,12 +302,6 @@ void journal_commit_transaction(journal_t *journal)
         * all outstanding updates to complete.
         */
 
-#ifdef COMMIT_STATS
-       spin_lock(&journal->j_list_lock);
-       summarise_journal_usage(journal);
-       spin_unlock(&journal->j_list_lock);
-#endif
-
        /* Do we need to erase the effects of a prior journal_flush? */
        if (journal->j_flags & JFS_FLUSHED) {
                jbd_debug(3, "super block updated\n");
@@ -722,8 +716,13 @@ wait_for_iobuf:
                    required. */
                JBUFFER_TRACE(jh, "file as BJ_Forget");
                journal_file_buffer(jh, commit_transaction, BJ_Forget);
-               /* Wake up any transactions which were waiting for this
-                  IO to complete */
+               /*
+                * Wake up any transactions which were waiting for this
+                * IO to complete. The barrier must be here so that changes
+                * by journal_file_buffer() take effect before wake_up_bit()
+                * does the waitqueue check.
+                */
+               smp_mb();
                wake_up_bit(&bh->b_state, BH_Unshadow);
                JBUFFER_TRACE(jh, "brelse shadowed buffer");
                __brelse(bh);
index b3713afaaa9e698337b40c7e1fecac6afbebc1bf..e2d4285fbe90ebcc511a96574283418bc933634d 100644 (file)
@@ -437,9 +437,12 @@ int __log_space_left(journal_t *journal)
 int __log_start_commit(journal_t *journal, tid_t target)
 {
        /*
-        * Are we already doing a recent enough commit?
+        * The only transaction we can possibly wait upon is the
+        * currently running transaction (if it exists).  Otherwise,
+        * the target tid must be an old one.
         */
-       if (!tid_geq(journal->j_commit_request, target)) {
+       if (journal->j_running_transaction &&
+           journal->j_running_transaction->t_tid == target) {
                /*
                 * We want a new commit: OK, mark the request and wakeup the
                 * commit thread.  We do _not_ do the commit ourselves.
@@ -451,7 +454,14 @@ int __log_start_commit(journal_t *journal, tid_t target)
                          journal->j_commit_sequence);
                wake_up(&journal->j_wait_commit);
                return 1;
-       }
+       } else if (!tid_geq(journal->j_commit_request, target))
+               /* This should never happen, but if it does, preserve
+                  the evidence before kjournald goes into a loop and
+                  increments j_commit_sequence beyond all recognition. */
+               WARN_ONCE(1, "jbd: bad log_start_commit: %u %u %u %u\n",
+                   journal->j_commit_request, journal->j_commit_sequence,
+                   target, journal->j_running_transaction ?
+                   journal->j_running_transaction->t_tid : 0);
        return 0;
 }
 
index 60d2319651b2c2b0f80d346d53a439f3f2513cc6..f7ee81a065dabae13e29501603a8c1726132d05c 100644 (file)
@@ -266,7 +266,8 @@ static handle_t *new_handle(int nblocks)
  * This function is visible to journal users (like ext3fs), so is not
  * called with the journal already locked.
  *
- * Return a pointer to a newly allocated handle, or NULL on failure
+ * Return a pointer to a newly allocated handle, or an ERR_PTR() value
+ * on failure.
  */
 handle_t *journal_start(journal_t *journal, int nblocks)
 {
index 6a79fd0a1a32cdd018fea9879a6026e4dcf9c8b6..2c62c5aae82ff8936ae30036fe595aff68ab6877 100644 (file)
@@ -97,10 +97,14 @@ static int __try_to_free_cp_buf(struct journal_head *jh)
 
        if (jh->b_jlist == BJ_None && !buffer_locked(bh) &&
            !buffer_dirty(bh) && !buffer_write_io_error(bh)) {
+               /*
+                * Get our reference so that bh cannot be freed before
+                * we unlock it
+                */
+               get_bh(bh);
                JBUFFER_TRACE(jh, "remove from checkpoint list");
                ret = __jbd2_journal_remove_checkpoint(jh) + 1;
                jbd_unlock_bh_state(bh);
-               jbd2_journal_remove_journal_head(bh);
                BUFFER_TRACE(bh, "release");
                __brelse(bh);
        } else {
@@ -223,8 +227,8 @@ restart:
                        spin_lock(&journal->j_list_lock);
                        goto restart;
                }
+               get_bh(bh);
                if (buffer_locked(bh)) {
-                       atomic_inc(&bh->b_count);
                        spin_unlock(&journal->j_list_lock);
                        jbd_unlock_bh_state(bh);
                        wait_on_buffer(bh);
@@ -243,7 +247,6 @@ restart:
                 */
                released = __jbd2_journal_remove_checkpoint(jh);
                jbd_unlock_bh_state(bh);
-               jbd2_journal_remove_journal_head(bh);
                __brelse(bh);
        }
 
@@ -284,7 +287,7 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
        int ret = 0;
 
        if (buffer_locked(bh)) {
-               atomic_inc(&bh->b_count);
+               get_bh(bh);
                spin_unlock(&journal->j_list_lock);
                jbd_unlock_bh_state(bh);
                wait_on_buffer(bh);
@@ -316,12 +319,12 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
                ret = 1;
                if (unlikely(buffer_write_io_error(bh)))
                        ret = -EIO;
+               get_bh(bh);
                J_ASSERT_JH(jh, !buffer_jbddirty(bh));
                BUFFER_TRACE(bh, "remove from checkpoint");
                __jbd2_journal_remove_checkpoint(jh);
                spin_unlock(&journal->j_list_lock);
                jbd_unlock_bh_state(bh);
-               jbd2_journal_remove_journal_head(bh);
                __brelse(bh);
        } else {
                /*
@@ -554,7 +557,8 @@ int jbd2_cleanup_journal_tail(journal_t *journal)
 /*
  * journal_clean_one_cp_list
  *
- * Find all the written-back checkpoint buffers in the given list and release them.
+ * Find all the written-back checkpoint buffers in the given list and
+ * release them.
  *
  * Called with the journal locked.
  * Called with j_list_lock held.
@@ -663,8 +667,8 @@ out:
  * checkpoint lists.
  *
  * The function returns 1 if it frees the transaction, 0 otherwise.
+ * The function can free jh and bh.
  *
- * This function is called with the journal locked.
  * This function is called with j_list_lock held.
  * This function is called with jbd_lock_bh_state(jh2bh(jh))
  */
@@ -684,13 +688,14 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
        }
        journal = transaction->t_journal;
 
+       JBUFFER_TRACE(jh, "removing from transaction");
        __buffer_unlink(jh);
        jh->b_cp_transaction = NULL;
+       jbd2_journal_put_journal_head(jh);
 
        if (transaction->t_checkpoint_list != NULL ||
            transaction->t_checkpoint_io_list != NULL)
                goto out;
-       JBUFFER_TRACE(jh, "transaction has no more buffers");
 
        /*
         * There is one special case to worry about: if we have just pulled the
@@ -701,10 +706,8 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
         * The locking here around t_state is a bit sleazy.
         * See the comment at the end of jbd2_journal_commit_transaction().
         */
-       if (transaction->t_state != T_FINISHED) {
-               JBUFFER_TRACE(jh, "belongs to running/committing transaction");
+       if (transaction->t_state != T_FINISHED)
                goto out;
-       }
 
        /* OK, that was the last buffer for the transaction: we can now
           safely remove this transaction from the log */
@@ -723,7 +726,6 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
        wake_up(&journal->j_wait_logspace);
        ret = 1;
 out:
-       JBUFFER_TRACE(jh, "exit");
        return ret;
 }
 
@@ -742,6 +744,8 @@ void __jbd2_journal_insert_checkpoint(struct journal_head *jh,
        J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jbddirty(jh2bh(jh)));
        J_ASSERT_JH(jh, jh->b_cp_transaction == NULL);
 
+       /* Get reference for checkpointing transaction */
+       jbd2_journal_grab_journal_head(jh2bh(jh));
        jh->b_cp_transaction = transaction;
 
        if (!transaction->t_checkpoint_list) {
index 6e28000a4b2168c36d1cee255058ac41b72f34eb..eef6979821a4c8db91f48854c46f81c291ef4c27 100644 (file)
@@ -219,7 +219,6 @@ static int journal_submit_data_buffers(journal_t *journal,
                        ret = err;
                spin_lock(&journal->j_list_lock);
                J_ASSERT(jinode->i_transaction == commit_transaction);
-               commit_transaction->t_flushed_data_blocks = 1;
                clear_bit(__JI_COMMIT_RUNNING, &jinode->i_flags);
                smp_mb__after_clear_bit();
                wake_up_bit(&jinode->i_flags, __JI_COMMIT_RUNNING);
@@ -338,12 +337,6 @@ void jbd2_journal_commit_transaction(journal_t *journal)
         * all outstanding updates to complete.
         */
 
-#ifdef COMMIT_STATS
-       spin_lock(&journal->j_list_lock);
-       summarise_journal_usage(journal);
-       spin_unlock(&journal->j_list_lock);
-#endif
-
        /* Do we need to erase the effects of a prior jbd2_journal_flush? */
        if (journal->j_flags & JBD2_FLUSHED) {
                jbd_debug(3, "super block updated\n");
@@ -678,12 +671,16 @@ start_journal_io:
                err = 0;
        }
 
+       write_lock(&journal->j_state_lock);
+       J_ASSERT(commit_transaction->t_state == T_COMMIT);
+       commit_transaction->t_state = T_COMMIT_DFLUSH;
+       write_unlock(&journal->j_state_lock);
        /* 
         * If the journal is not located on the file system device,
         * then we must flush the file system device before we issue
         * the commit record
         */
-       if (commit_transaction->t_flushed_data_blocks &&
+       if (commit_transaction->t_need_data_flush &&
            (journal->j_fs_dev != journal->j_dev) &&
            (journal->j_flags & JBD2_BARRIER))
                blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL);
@@ -760,8 +757,13 @@ wait_for_iobuf:
                    required. */
                JBUFFER_TRACE(jh, "file as BJ_Forget");
                jbd2_journal_file_buffer(jh, commit_transaction, BJ_Forget);
-               /* Wake up any transactions which were waiting for this
-                  IO to complete */
+               /*
+                * Wake up any transactions which were waiting for this IO to
+                * complete. The barrier must be here so that changes by
+                * jbd2_journal_file_buffer() take effect before wake_up_bit()
+                * does the waitqueue check.
+                */
+               smp_mb();
                wake_up_bit(&bh->b_state, BH_Unshadow);
                JBUFFER_TRACE(jh, "brelse shadowed buffer");
                __brelse(bh);
@@ -800,6 +802,10 @@ wait_for_iobuf:
                jbd2_journal_abort(journal, err);
 
        jbd_debug(3, "JBD: commit phase 5\n");
+       write_lock(&journal->j_state_lock);
+       J_ASSERT(commit_transaction->t_state == T_COMMIT_DFLUSH);
+       commit_transaction->t_state = T_COMMIT_JFLUSH;
+       write_unlock(&journal->j_state_lock);
 
        if (!JBD2_HAS_INCOMPAT_FEATURE(journal,
                                       JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) {
@@ -842,10 +848,16 @@ restart_loop:
        while (commit_transaction->t_forget) {
                transaction_t *cp_transaction;
                struct buffer_head *bh;
+               int try_to_free = 0;
 
                jh = commit_transaction->t_forget;
                spin_unlock(&journal->j_list_lock);
                bh = jh2bh(jh);
+               /*
+                * Get a reference so that bh cannot be freed before we are
+                * done with it.
+                */
+               get_bh(bh);
                jbd_lock_bh_state(bh);
                J_ASSERT_JH(jh, jh->b_transaction == commit_transaction);
 
@@ -908,28 +920,27 @@ restart_loop:
                        __jbd2_journal_insert_checkpoint(jh, commit_transaction);
                        if (is_journal_aborted(journal))
                                clear_buffer_jbddirty(bh);
-                       JBUFFER_TRACE(jh, "refile for checkpoint writeback");
-                       __jbd2_journal_refile_buffer(jh);
-                       jbd_unlock_bh_state(bh);
                } else {
                        J_ASSERT_BH(bh, !buffer_dirty(bh));
-                       /* The buffer on BJ_Forget list and not jbddirty means
+                       /*
+                        * The buffer on BJ_Forget list and not jbddirty means
                         * it has been freed by this transaction and hence it
                         * could not have been reallocated until this
                         * transaction has committed. *BUT* it could be
                         * reallocated once we have written all the data to
                         * disk and before we process the buffer on BJ_Forget
-                        * list. */
-                       JBUFFER_TRACE(jh, "refile or unfile freed buffer");
-                       __jbd2_journal_refile_buffer(jh);
-                       if (!jh->b_transaction) {
-                               jbd_unlock_bh_state(bh);
-                                /* needs a brelse */
-                               jbd2_journal_remove_journal_head(bh);
-                               release_buffer_page(bh);
-                       } else
-                               jbd_unlock_bh_state(bh);
+                        * list.
+                        */
+                       if (!jh->b_next_transaction)
+                               try_to_free = 1;
                }
+               JBUFFER_TRACE(jh, "refile or unfile buffer");
+               __jbd2_journal_refile_buffer(jh);
+               jbd_unlock_bh_state(bh);
+               if (try_to_free)
+                       release_buffer_page(bh);        /* Drops bh reference */
+               else
+                       __brelse(bh);
                cond_resched_lock(&journal->j_list_lock);
        }
        spin_unlock(&journal->j_list_lock);
@@ -955,7 +966,7 @@ restart_loop:
 
        jbd_debug(3, "JBD: commit phase 7\n");
 
-       J_ASSERT(commit_transaction->t_state == T_COMMIT);
+       J_ASSERT(commit_transaction->t_state == T_COMMIT_JFLUSH);
 
        commit_transaction->t_start = jiffies;
        stats.run.rs_logging = jbd2_time_diff(stats.run.rs_logging,
index e0ec3db1c395b6c338acc6f7c14af6a2c11eb067..0dfa5b598e68fa3f358f043c442eb39558bf6f52 100644 (file)
@@ -479,9 +479,12 @@ int __jbd2_log_space_left(journal_t *journal)
 int __jbd2_log_start_commit(journal_t *journal, tid_t target)
 {
        /*
-        * Are we already doing a recent enough commit?
+        * The only transaction we can possibly wait upon is the
+        * currently running transaction (if it exists).  Otherwise,
+        * the target tid must be an old one.
         */
-       if (!tid_geq(journal->j_commit_request, target)) {
+       if (journal->j_running_transaction &&
+           journal->j_running_transaction->t_tid == target) {
                /*
                 * We want a new commit: OK, mark the request and wakeup the
                 * commit thread.  We do _not_ do the commit ourselves.
@@ -493,7 +496,15 @@ int __jbd2_log_start_commit(journal_t *journal, tid_t target)
                          journal->j_commit_sequence);
                wake_up(&journal->j_wait_commit);
                return 1;
-       }
+       } else if (!tid_geq(journal->j_commit_request, target))
+               /* This should never happen, but if it does, preserve
+                  the evidence before kjournald goes into a loop and
+                  increments j_commit_sequence beyond all recognition. */
+               WARN_ONCE(1, "jbd: bad log_start_commit: %u %u %u %u\n",
+                         journal->j_commit_request,
+                         journal->j_commit_sequence,
+                         target, journal->j_running_transaction ? 
+                         journal->j_running_transaction->t_tid : 0);
        return 0;
 }
 
@@ -576,6 +587,47 @@ int jbd2_journal_start_commit(journal_t *journal, tid_t *ptid)
        return ret;
 }
 
+/*
+ * Return 1 if a given transaction has not yet sent barrier request
+ * connected with a transaction commit. If 0 is returned, transaction
+ * may or may not have sent the barrier. Used to avoid sending barrier
+ * twice in common cases.
+ */
+int jbd2_trans_will_send_data_barrier(journal_t *journal, tid_t tid)
+{
+       int ret = 0;
+       transaction_t *commit_trans;
+
+       if (!(journal->j_flags & JBD2_BARRIER))
+               return 0;
+       read_lock(&journal->j_state_lock);
+       /* Transaction already committed? */
+       if (tid_geq(journal->j_commit_sequence, tid))
+               goto out;
+       commit_trans = journal->j_committing_transaction;
+       if (!commit_trans || commit_trans->t_tid != tid) {
+               ret = 1;
+               goto out;
+       }
+       /*
+        * Transaction is being committed and we already proceeded to
+        * submitting a flush to fs partition?
+        */
+       if (journal->j_fs_dev != journal->j_dev) {
+               if (!commit_trans->t_need_data_flush ||
+                   commit_trans->t_state >= T_COMMIT_DFLUSH)
+                       goto out;
+       } else {
+               if (commit_trans->t_state >= T_COMMIT_JFLUSH)
+                       goto out;
+       }
+       ret = 1;
+out:
+       read_unlock(&journal->j_state_lock);
+       return ret;
+}
+EXPORT_SYMBOL(jbd2_trans_will_send_data_barrier);
+
 /*
  * Wait for a specified commit to complete.
  * The caller may not hold the journal lock.
@@ -2026,10 +2078,9 @@ static void journal_free_journal_head(struct journal_head *jh)
  * When a buffer has its BH_JBD bit set it is immune from being released by
  * core kernel code, mainly via ->b_count.
  *
- * A journal_head may be detached from its buffer_head when the journal_head's
- * b_transaction, b_cp_transaction and b_next_transaction pointers are NULL.
- * Various places in JBD call jbd2_journal_remove_journal_head() to indicate that the
- * journal_head can be dropped if needed.
+ * A journal_head is detached from its buffer_head when the journal_head's
+ * b_jcount reaches zero. Running transaction (b_transaction) and checkpoint
+ * transaction (b_cp_transaction) hold their references to b_jcount.
  *
  * Various places in the kernel want to attach a journal_head to a buffer_head
  * _before_ attaching the journal_head to a transaction.  To protect the
@@ -2042,17 +2093,16 @@ static void journal_free_journal_head(struct journal_head *jh)
  *     (Attach a journal_head if needed.  Increments b_jcount)
  *     struct journal_head *jh = jbd2_journal_add_journal_head(bh);
  *     ...
+ *      (Get another reference for transaction)
+ *     jbd2_journal_grab_journal_head(bh);
  *     jh->b_transaction = xxx;
+ *     (Put original reference)
  *     jbd2_journal_put_journal_head(jh);
- *
- * Now, the journal_head's b_jcount is zero, but it is safe from being released
- * because it has a non-zero b_transaction.
  */
 
 /*
  * Give a buffer_head a journal_head.
  *
- * Doesn't need the journal lock.
  * May sleep.
  */
 struct journal_head *jbd2_journal_add_journal_head(struct buffer_head *bh)
@@ -2116,61 +2166,29 @@ static void __journal_remove_journal_head(struct buffer_head *bh)
        struct journal_head *jh = bh2jh(bh);
 
        J_ASSERT_JH(jh, jh->b_jcount >= 0);
-
-       get_bh(bh);
-       if (jh->b_jcount == 0) {
-               if (jh->b_transaction == NULL &&
-                               jh->b_next_transaction == NULL &&
-                               jh->b_cp_transaction == NULL) {
-                       J_ASSERT_JH(jh, jh->b_jlist == BJ_None);
-                       J_ASSERT_BH(bh, buffer_jbd(bh));
-                       J_ASSERT_BH(bh, jh2bh(jh) == bh);
-                       BUFFER_TRACE(bh, "remove journal_head");
-                       if (jh->b_frozen_data) {
-                               printk(KERN_WARNING "%s: freeing "
-                                               "b_frozen_data\n",
-                                               __func__);
-                               jbd2_free(jh->b_frozen_data, bh->b_size);
-                       }
-                       if (jh->b_committed_data) {
-                               printk(KERN_WARNING "%s: freeing "
-                                               "b_committed_data\n",
-                                               __func__);
-                               jbd2_free(jh->b_committed_data, bh->b_size);
-                       }
-                       bh->b_private = NULL;
-                       jh->b_bh = NULL;        /* debug, really */
-                       clear_buffer_jbd(bh);
-                       __brelse(bh);
-                       journal_free_journal_head(jh);
-               } else {
-                       BUFFER_TRACE(bh, "journal_head was locked");
-               }
+       J_ASSERT_JH(jh, jh->b_transaction == NULL);
+       J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
+       J_ASSERT_JH(jh, jh->b_cp_transaction == NULL);
+       J_ASSERT_JH(jh, jh->b_jlist == BJ_None);
+       J_ASSERT_BH(bh, buffer_jbd(bh));
+       J_ASSERT_BH(bh, jh2bh(jh) == bh);
+       BUFFER_TRACE(bh, "remove journal_head");
+       if (jh->b_frozen_data) {
+               printk(KERN_WARNING "%s: freeing b_frozen_data\n", __func__);
+               jbd2_free(jh->b_frozen_data, bh->b_size);
        }
+       if (jh->b_committed_data) {
+               printk(KERN_WARNING "%s: freeing b_committed_data\n", __func__);
+               jbd2_free(jh->b_committed_data, bh->b_size);
+       }
+       bh->b_private = NULL;
+       jh->b_bh = NULL;        /* debug, really */
+       clear_buffer_jbd(bh);
+       journal_free_journal_head(jh);
 }
 
 /*
- * jbd2_journal_remove_journal_head(): if the buffer isn't attached to a transaction
- * and has a zero b_jcount then remove and release its journal_head.   If we did
- * see that the buffer is not used by any transaction we also "logically"
- * decrement ->b_count.
- *
- * We in fact take an additional increment on ->b_count as a convenience,
- * because the caller usually wants to do additional things with the bh
- * after calling here.
- * The caller of jbd2_journal_remove_journal_head() *must* run __brelse(bh) at some
- * time.  Once the caller has run __brelse(), the buffer is eligible for
- * reaping by try_to_free_buffers().
- */
-void jbd2_journal_remove_journal_head(struct buffer_head *bh)
-{
-       jbd_lock_bh_journal_head(bh);
-       __journal_remove_journal_head(bh);
-       jbd_unlock_bh_journal_head(bh);
-}
-
-/*
- * Drop a reference on the passed journal_head.  If it fell to zero then try to
+ * Drop a reference on the passed journal_head.  If it fell to zero then
  * release the journal_head from the buffer_head.
  */
 void jbd2_journal_put_journal_head(struct journal_head *jh)
@@ -2180,11 +2198,12 @@ void jbd2_journal_put_journal_head(struct journal_head *jh)
        jbd_lock_bh_journal_head(bh);
        J_ASSERT_JH(jh, jh->b_jcount > 0);
        --jh->b_jcount;
-       if (!jh->b_jcount && !jh->b_transaction) {
+       if (!jh->b_jcount) {
                __journal_remove_journal_head(bh);
+               jbd_unlock_bh_journal_head(bh);
                __brelse(bh);
-       }
-       jbd_unlock_bh_journal_head(bh);
+       } else
+               jbd_unlock_bh_journal_head(bh);
 }
 
 /*
index 05fa77a23711f8db041cac46984452451daae70c..2d7109414cdd6b7a4d21bdb2e738ff20581523a4 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/module.h>
 
 static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh);
+static void __jbd2_journal_unfile_buffer(struct journal_head *jh);
 
 /*
  * jbd2_get_transaction: obtain a new transaction_t object.
@@ -82,7 +83,7 @@ jbd2_get_transaction(journal_t *journal, transaction_t *transaction)
  */
 
 /*
- * Update transiaction's maximum wait time, if debugging is enabled.
+ * Update transaction's maximum wait time, if debugging is enabled.
  *
  * In order for t_max_wait to be reliable, it must be protected by a
  * lock.  But doing so will mean that start_this_handle() can not be
@@ -91,11 +92,10 @@ jbd2_get_transaction(journal_t *journal, transaction_t *transaction)
  * means that maximum wait time reported by the jbd2_run_stats
  * tracepoint will always be zero.
  */
-static inline void update_t_max_wait(transaction_t *transaction)
+static inline void update_t_max_wait(transaction_t *transaction,
+                                    unsigned long ts)
 {
 #ifdef CONFIG_JBD2_DEBUG
-       unsigned long ts = jiffies;
-
        if (jbd2_journal_enable_debug &&
            time_after(transaction->t_start, ts)) {
                ts = jbd2_time_diff(ts, transaction->t_start);
@@ -121,6 +121,7 @@ static int start_this_handle(journal_t *journal, handle_t *handle,
        tid_t           tid;
        int             needed, need_to_start;
        int             nblocks = handle->h_buffer_credits;
+       unsigned long ts = jiffies;
 
        if (nblocks > journal->j_max_transaction_buffers) {
                printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n",
@@ -271,7 +272,7 @@ repeat:
        /* OK, account for the buffers that this operation expects to
         * use and add the handle to the running transaction. 
         */
-       update_t_max_wait(transaction);
+       update_t_max_wait(transaction, ts);
        handle->h_transaction = transaction;
        atomic_inc(&transaction->t_updates);
        atomic_inc(&transaction->t_handle_count);
@@ -316,7 +317,8 @@ static handle_t *new_handle(int nblocks)
  * This function is visible to journal users (like ext3fs), so is not
  * called with the journal already locked.
  *
- * Return a pointer to a newly allocated handle, or NULL on failure
+ * Return a pointer to a newly allocated handle, or an ERR_PTR() value
+ * on failure.
  */
 handle_t *jbd2__journal_start(journal_t *journal, int nblocks, int gfp_mask)
 {
@@ -763,7 +765,6 @@ repeat:
        if (!jh->b_transaction) {
                JBUFFER_TRACE(jh, "no transaction");
                J_ASSERT_JH(jh, !jh->b_next_transaction);
-               jh->b_transaction = transaction;
                JBUFFER_TRACE(jh, "file as BJ_Reserved");
                spin_lock(&journal->j_list_lock);
                __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved);
@@ -813,7 +814,6 @@ out:
  * int jbd2_journal_get_write_access() - notify intent to modify a buffer for metadata (not data) update.
  * @handle: transaction to add buffer modifications to
  * @bh:     bh to be used for metadata writes
- * @credits: variable that will receive credits for the buffer
  *
  * Returns an error code or 0 on success.
  *
@@ -895,8 +895,6 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh)
                 * committed and so it's safe to clear the dirty bit.
                 */
                clear_buffer_dirty(jh2bh(jh));
-               jh->b_transaction = transaction;
-
                /* first access by this transaction */
                jh->b_modified = 0;
 
@@ -921,8 +919,8 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh)
         */
        JBUFFER_TRACE(jh, "cancelling revoke");
        jbd2_journal_cancel_revoke(handle, jh);
-       jbd2_journal_put_journal_head(jh);
 out:
+       jbd2_journal_put_journal_head(jh);
        return err;
 }
 
@@ -931,7 +929,6 @@ out:
  *     non-rewindable consequences
  * @handle: transaction
  * @bh: buffer to undo
- * @credits: store the number of taken credits here (if not NULL)
  *
  * Sometimes there is a need to distinguish between metadata which has
  * been committed to disk and that which has not.  The ext3fs code uses
@@ -1231,8 +1228,6 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh)
                        __jbd2_journal_file_buffer(jh, transaction, BJ_Forget);
                } else {
                        __jbd2_journal_unfile_buffer(jh);
-                       jbd2_journal_remove_journal_head(bh);
-                       __brelse(bh);
                        if (!buffer_jbd(bh)) {
                                spin_unlock(&journal->j_list_lock);
                                jbd_unlock_bh_state(bh);
@@ -1555,19 +1550,32 @@ void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh)
                mark_buffer_dirty(bh);  /* Expose it to the VM */
 }
 
-void __jbd2_journal_unfile_buffer(struct journal_head *jh)
+/*
+ * Remove buffer from all transactions.
+ *
+ * Called with bh_state lock and j_list_lock
+ *
+ * jh and bh may be already freed when this function returns.
+ */
+static void __jbd2_journal_unfile_buffer(struct journal_head *jh)
 {
        __jbd2_journal_temp_unlink_buffer(jh);
        jh->b_transaction = NULL;
+       jbd2_journal_put_journal_head(jh);
 }
 
 void jbd2_journal_unfile_buffer(journal_t *journal, struct journal_head *jh)
 {
-       jbd_lock_bh_state(jh2bh(jh));
+       struct buffer_head *bh = jh2bh(jh);
+
+       /* Get reference so that buffer cannot be freed before we unlock it */
+       get_bh(bh);
+       jbd_lock_bh_state(bh);
        spin_lock(&journal->j_list_lock);
        __jbd2_journal_unfile_buffer(jh);
        spin_unlock(&journal->j_list_lock);
-       jbd_unlock_bh_state(jh2bh(jh));
+       jbd_unlock_bh_state(bh);
+       __brelse(bh);
 }
 
 /*
@@ -1594,8 +1602,6 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh)
                if (jh->b_jlist == BJ_None) {
                        JBUFFER_TRACE(jh, "remove from checkpoint list");
                        __jbd2_journal_remove_checkpoint(jh);
-                       jbd2_journal_remove_journal_head(bh);
-                       __brelse(bh);
                }
        }
        spin_unlock(&journal->j_list_lock);
@@ -1658,7 +1664,6 @@ int jbd2_journal_try_to_free_buffers(journal_t *journal,
                /*
                 * We take our own ref against the journal_head here to avoid
                 * having to add tons of locking around each instance of
-                * jbd2_journal_remove_journal_head() and
                 * jbd2_journal_put_journal_head().
                 */
                jh = jbd2_journal_grab_journal_head(bh);
@@ -1696,10 +1701,9 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction)
        int may_free = 1;
        struct buffer_head *bh = jh2bh(jh);
 
-       __jbd2_journal_unfile_buffer(jh);
-
        if (jh->b_cp_transaction) {
                JBUFFER_TRACE(jh, "on running+cp transaction");
+               __jbd2_journal_temp_unlink_buffer(jh);
                /*
                 * We don't want to write the buffer anymore, clear the
                 * bit so that we don't confuse checks in
@@ -1710,8 +1714,7 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction)
                may_free = 0;
        } else {
                JBUFFER_TRACE(jh, "on running transaction");
-               jbd2_journal_remove_journal_head(bh);
-               __brelse(bh);
+               __jbd2_journal_unfile_buffer(jh);
        }
        return may_free;
 }
@@ -1989,6 +1992,8 @@ void __jbd2_journal_file_buffer(struct journal_head *jh,
 
        if (jh->b_transaction)
                __jbd2_journal_temp_unlink_buffer(jh);
+       else
+               jbd2_journal_grab_journal_head(bh);
        jh->b_transaction = transaction;
 
        switch (jlist) {
@@ -2040,9 +2045,10 @@ void jbd2_journal_file_buffer(struct journal_head *jh,
  * already started to be used by a subsequent transaction, refile the
  * buffer on that transaction's metadata list.
  *
- * Called under journal->j_list_lock
- *
+ * Called under j_list_lock
  * Called under jbd_lock_bh_state(jh2bh(jh))
+ *
+ * jh and bh may be already free when this function returns
  */
 void __jbd2_journal_refile_buffer(struct journal_head *jh)
 {
@@ -2066,6 +2072,11 @@ void __jbd2_journal_refile_buffer(struct journal_head *jh)
 
        was_dirty = test_clear_buffer_jbddirty(bh);
        __jbd2_journal_temp_unlink_buffer(jh);
+       /*
+        * We set b_transaction here because b_next_transaction will inherit
+        * our jh reference and thus __jbd2_journal_file_buffer() must not
+        * take a new one.
+        */
        jh->b_transaction = jh->b_next_transaction;
        jh->b_next_transaction = NULL;
        if (buffer_freed(bh))
@@ -2082,30 +2093,21 @@ void __jbd2_journal_refile_buffer(struct journal_head *jh)
 }
 
 /*
- * For the unlocked version of this call, also make sure that any
- * hanging journal_head is cleaned up if necessary.
- *
- * __jbd2_journal_refile_buffer is usually called as part of a single locked
- * operation on a buffer_head, in which the caller is probably going to
- * be hooking the journal_head onto other lists.  In that case it is up
- * to the caller to remove the journal_head if necessary.  For the
- * unlocked jbd2_journal_refile_buffer call, the caller isn't going to be
- * doing anything else to the buffer so we need to do the cleanup
- * ourselves to avoid a jh leak.
- *
- * *** The journal_head may be freed by this call! ***
+ * __jbd2_journal_refile_buffer() with necessary locking added. We take our
+ * bh reference so that we can safely unlock bh.
+ *
+ * The jh and bh may be freed by this call.
  */
 void jbd2_journal_refile_buffer(journal_t *journal, struct journal_head *jh)
 {
        struct buffer_head *bh = jh2bh(jh);
 
+       /* Get reference so that buffer cannot be freed before we unlock it */
+       get_bh(bh);
        jbd_lock_bh_state(bh);
        spin_lock(&journal->j_list_lock);
-
        __jbd2_journal_refile_buffer(jh);
        jbd_unlock_bh_state(bh);
-       jbd2_journal_remove_journal_head(bh);
-
        spin_unlock(&journal->j_list_lock);
        __brelse(bh);
 }
@@ -2147,6 +2149,13 @@ int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *jinode)
            jinode->i_next_transaction == transaction)
                goto done;
 
+       /*
+        * We only ever set this variable to 1 so the test is safe. Since
+        * t_need_data_flush is likely to be set, we do the test to save some
+        * cacheline bouncing
+        */
+       if (!transaction->t_need_data_flush)
+               transaction->t_need_data_flush = 1;
        /* On some different transaction's list - should be
         * the committing one */
        if (jinode->i_transaction) {
index 82faddd1f321b74e8efd4f11fe07449e409d7bbc..4bca6a2e5c07431628b5acb9c201bb4daf56ba55 100644 (file)
@@ -75,7 +75,6 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
                                   struct nameidata *nd)
 {
        struct jffs2_inode_info *dir_f;
-       struct jffs2_sb_info *c;
        struct jffs2_full_dirent *fd = NULL, *fd_list;
        uint32_t ino = 0;
        struct inode *inode = NULL;
@@ -86,7 +85,6 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
                return ERR_PTR(-ENAMETOOLONG);
 
        dir_f = JFFS2_INODE_INFO(dir_i);
-       c = JFFS2_SB_INFO(dir_i->i_sb);
 
        mutex_lock(&dir_f->sem);
 
@@ -119,7 +117,6 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
 static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
        struct jffs2_inode_info *f;
-       struct jffs2_sb_info *c;
        struct inode *inode = filp->f_path.dentry->d_inode;
        struct jffs2_full_dirent *fd;
        unsigned long offset, curofs;
@@ -127,7 +124,6 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
        D1(printk(KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", filp->f_path.dentry->d_inode->i_ino));
 
        f = JFFS2_INODE_INFO(inode);
-       c = JFFS2_SB_INFO(inode->i_sb);
 
        offset = filp->f_pos;
 
index e896e67767eb9e10515f37a7608fd7bdcc2d330d..46ad619b6124fdd92ab0ac83e439311a58c4ca9b 100644 (file)
@@ -357,7 +357,7 @@ error:
        return ERR_PTR(ret);
 }
 
-void jffs2_dirty_inode(struct inode *inode)
+void jffs2_dirty_inode(struct inode *inode, int flags)
 {
        struct iattr iattr;
 
index 00bae7cc2e48eba4029f0b58d92e2113e057c5a6..65c6c43ca482b4359e675be6c21a0f6d5d97ac69 100644 (file)
@@ -172,7 +172,7 @@ int jffs2_setattr (struct dentry *, struct iattr *);
 int jffs2_do_setattr (struct inode *, struct iattr *);
 struct inode *jffs2_iget(struct super_block *, unsigned long);
 void jffs2_evict_inode (struct inode *);
-void jffs2_dirty_inode(struct inode *inode);
+void jffs2_dirty_inode(struct inode *inode, int flags);
 struct inode *jffs2_new_inode (struct inode *dir_i, int mode,
                               struct jffs2_raw_inode *ri);
 int jffs2_statfs (struct dentry *, struct kstatfs *);
index b632dddcb482821122918bd1673391ff34d51e4c..8d8cd3419d02a75a7b0a7336da995a430324448b 100644 (file)
@@ -94,7 +94,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
        uint32_t buf_size = 0;
        struct jffs2_summary *s = NULL; /* summary info collected by the scan process */
 #ifndef __ECOS
-       size_t pointlen;
+       size_t pointlen, try_size;
 
        if (c->mtd->point) {
                ret = c->mtd->point(c->mtd, 0, c->mtd->size, &pointlen,
@@ -113,18 +113,21 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
                /* For NAND it's quicker to read a whole eraseblock at a time,
                   apparently */
                if (jffs2_cleanmarker_oob(c))
-                       buf_size = c->sector_size;
+                       try_size = c->sector_size;
                else
-                       buf_size = PAGE_SIZE;
+                       try_size = PAGE_SIZE;
 
-               /* Respect kmalloc limitations */
-               if (buf_size > 128*1024)
-                       buf_size = 128*1024;
+               D1(printk(KERN_DEBUG "Trying to allocate readbuf of %zu "
+                       "bytes\n", try_size));
 
-               D1(printk(KERN_DEBUG "Allocating readbuf of %d bytes\n", buf_size));
-               flashbuf = kmalloc(buf_size, GFP_KERNEL);
+               flashbuf = mtd_kmalloc_up_to(c->mtd, &try_size);
                if (!flashbuf)
                        return -ENOMEM;
+
+               D1(printk(KERN_DEBUG "Allocated readbuf of %zu bytes\n",
+                       try_size));
+
+               buf_size = (uint32_t)try_size;
        }
 
        if (jffs2_sum_active()) {
index c5ce6c1d1ff406c567d0b59d0ffe03ed11b8daa5..2f3f531f36064772dfd4e934847dd5c33fd1cbe4 100644 (file)
@@ -66,9 +66,9 @@ static int jfs_open(struct inode *inode, struct file *file)
                struct jfs_inode_info *ji = JFS_IP(inode);
                spin_lock_irq(&ji->ag_lock);
                if (ji->active_ag == -1) {
-                       ji->active_ag = ji->agno;
-                       atomic_inc(
-                           &JFS_SBI(inode->i_sb)->bmap->db_active[ji->agno]);
+                       struct jfs_sb_info *jfs_sb = JFS_SBI(inode->i_sb);
+                       ji->active_ag = BLKTOAG(addressPXD(&ji->ixpxd), jfs_sb);
+                       atomic_inc( &jfs_sb->bmap->db_active[ji->active_ag]);
                }
                spin_unlock_irq(&ji->ag_lock);
        }
index eddbb373209e9c2dc013657bc041d44badb0aa29..109655904bbcde5ecb62513c5a8712da7486bce6 100644 (file)
@@ -173,7 +173,7 @@ void jfs_evict_inode(struct inode *inode)
        dquot_drop(inode);
 }
 
-void jfs_dirty_inode(struct inode *inode)
+void jfs_dirty_inode(struct inode *inode, int flags)
 {
        static int noisy = 5;
 
index ed53a4740168bc2d7692ea07531663049d991dfe..b78b2f978f043dae0f18c24713532218b3201582 100644 (file)
@@ -397,7 +397,7 @@ int diRead(struct inode *ip)
        release_metapage(mp);
 
        /* set the ag for the inode */
-       JFS_IP(ip)->agno = BLKTOAG(agstart, sbi);
+       JFS_IP(ip)->agstart = agstart;
        JFS_IP(ip)->active_ag = -1;
 
        return (rc);
@@ -901,7 +901,7 @@ int diFree(struct inode *ip)
 
        /* get the allocation group for this ino.
         */
-       agno = JFS_IP(ip)->agno;
+       agno = BLKTOAG(JFS_IP(ip)->agstart, JFS_SBI(ip->i_sb));
 
        /* Lock the AG specific inode map information
         */
@@ -1315,12 +1315,11 @@ int diFree(struct inode *ip)
 static inline void
 diInitInode(struct inode *ip, int iagno, int ino, int extno, struct iag * iagp)
 {
-       struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
        struct jfs_inode_info *jfs_ip = JFS_IP(ip);
 
        ip->i_ino = (iagno << L2INOSPERIAG) + ino;
        jfs_ip->ixpxd = iagp->inoext[extno];
-       jfs_ip->agno = BLKTOAG(le64_to_cpu(iagp->agstart), sbi);
+       jfs_ip->agstart = le64_to_cpu(iagp->agstart);
        jfs_ip->active_ag = -1;
 }
 
@@ -1379,7 +1378,7 @@ int diAlloc(struct inode *pip, bool dir, struct inode *ip)
         */
 
        /* get the ag number of this iag */
-       agno = JFS_IP(pip)->agno;
+       agno = BLKTOAG(JFS_IP(pip)->agstart, JFS_SBI(pip->i_sb));
 
        if (atomic_read(&JFS_SBI(pip->i_sb)->bmap->db_active[agno])) {
                /*
@@ -2921,10 +2920,9 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
                        continue;
                }
 
-               /* agstart that computes to the same ag is treated as same; */
                agstart = le64_to_cpu(iagp->agstart);
-               /* iagp->agstart = agstart & ~(mp->db_agsize - 1); */
                n = agstart >> mp->db_agl2size;
+               iagp->agstart = cpu_to_le64((s64)n << mp->db_agl2size);
 
                /* compute backed inodes */
                numinos = (EXTSPERIAG - le32_to_cpu(iagp->nfreeexts))
index 1439f119ec830876ded18b7c5bf66b2ed1fdc80d..584a4a1a6e81478a2e212b2f20ec08400159e946 100644 (file)
@@ -50,8 +50,9 @@ struct jfs_inode_info {
        short   btindex;        /* btpage entry index*/
        struct inode *ipimap;   /* inode map                    */
        unsigned long cflag;    /* commit flags         */
+       u64     agstart;        /* agstart of the containing IAG */
        u16     bxflag;         /* xflag of pseudo buffer?      */
-       unchar  agno;           /* ag number                    */
+       unchar  pad;
        signed char active_ag;  /* ag currently allocating from */
        lid_t   blid;           /* lid of pseudo buffer?        */
        lid_t   atlhead;        /* anonymous tlock list head    */
index 155e91eff07d6efa31adcea1ea69278f71e18478..ec2fb8b945fc9d0ac102028bbfc6a5c184521683 100644 (file)
@@ -28,7 +28,7 @@ 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 *, struct writeback_control *);
 extern void jfs_evict_inode(struct inode *);
-extern void jfs_dirty_inode(struct inode *);
+extern void jfs_dirty_inode(struct inode *, int);
 extern void jfs_truncate(struct inode *);
 extern void jfs_truncate_nolock(struct inode *, loff_t);
 extern void jfs_free_zero_link(struct inode *);
index 278e3fb40b71e259b3eab7492fcebbd2c2a033e2..583636f745e59dbe7e66e1b3871496ac3b29a63d 100644 (file)
@@ -1123,7 +1123,7 @@ int lmLogOpen(struct super_block *sb)
        bdev = blkdev_get_by_dev(sbi->logdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL,
                                 log);
        if (IS_ERR(bdev)) {
-               rc = -PTR_ERR(bdev);
+               rc = PTR_ERR(bdev);
                goto free;
        }
 
index 8ea5efb5a34e3c5ccc01d24d4764469b20a71ddc..8d0c1c7c08204177e5f6f6127daa5caa7c545757 100644 (file)
@@ -80,7 +80,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
        int log_formatted = 0;
        struct inode *iplist[1];
        struct jfs_superblock *j_sb, *j_sb2;
-       uint old_agsize;
+       s64 old_agsize;
        int agsizechanged = 0;
        struct buffer_head *bh, *bh2;
 
index adb45ec9038cc95530e5d1be50d521a927110ac2..e374050a911c6141342bf5b464bb04fca396ce3e 100644 (file)
@@ -708,7 +708,13 @@ static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
 
        if (task->tk_status < 0) {
                dprintk("lockd: unlock failed (err = %d)\n", -task->tk_status);
-               goto retry_rebind;
+               switch (task->tk_status) {
+               case -EACCES:
+               case -EIO:
+                       goto die;
+               default:
+                       goto retry_rebind;
+               }
        }
        if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
                rpc_delay(task, NLMCLNT_GRACE_WAIT);
index 9ed89d1663f839c86b84e133617a47f4d855ee25..1afae26cf2364936d3053801c41f12cbb06f29d9 100644 (file)
@@ -555,13 +555,6 @@ static int logfs_symlink(struct inode *dir, struct dentry *dentry,
        return __logfs_create(dir, dentry, inode, target, destlen);
 }
 
-static int logfs_permission(struct inode *inode, int mask, unsigned int flags)
-{
-       if (flags & IPERM_FLAG_RCU)
-               return -ECHILD;
-       return generic_permission(inode, mask, flags, NULL);
-}
-
 static int logfs_link(struct dentry *old_dentry, struct inode *dir,
                struct dentry *dentry)
 {
@@ -820,7 +813,6 @@ const struct inode_operations logfs_dir_iops = {
        .mknod          = logfs_mknod,
        .rename         = logfs_rename,
        .rmdir          = logfs_rmdir,
-       .permission     = logfs_permission,
        .symlink        = logfs_symlink,
        .unlink         = logfs_unlink,
 };
index 2f174be065558500c1192cf401dbd6cc0e13c046..8c32ef3ba88e7ac25a197866a38c4590836f12be 100644 (file)
@@ -90,7 +90,8 @@ static DEFINE_SPINLOCK(mb_cache_spinlock);
  * What the mbcache registers as to get shrunk dynamically.
  */
 
-static int mb_cache_shrink_fn(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask);
+static int mb_cache_shrink_fn(struct shrinker *shrink,
+                             struct shrink_control *sc);
 
 static struct shrinker mb_cache_shrinker = {
        .shrink = mb_cache_shrink_fn,
@@ -156,18 +157,19 @@ forget:
  * gets low.
  *
  * @shrink: (ignored)
- * @nr_to_scan: Number of objects to scan
- * @gfp_mask: (ignored)
+ * @sc: shrink_control passed from reclaim
  *
  * Returns the number of objects which are present in the cache.
  */
 static int
-mb_cache_shrink_fn(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
+mb_cache_shrink_fn(struct shrinker *shrink, struct shrink_control *sc)
 {
        LIST_HEAD(free_list);
        struct mb_cache *cache;
        struct mb_cache_entry *entry, *tmp;
        int count = 0;
+       int nr_to_scan = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
 
        mb_debug("trying to free %d entries", nr_to_scan);
        spin_lock(&mb_cache_spinlock);
index 0afc809e46e09b53cb767e56795fba3139c4b181..fdfae9fa98cda52f26b730ab6786db084124d279 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/writeback.h>
 #include <linux/backing-dev.h>
 #include <linux/pagevec.h>
+#include <linux/cleancache.h>
 
 /*
  * I/O completion handler for multipage BIOs.
@@ -271,6 +272,12 @@ do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages,
                SetPageMappedToDisk(page);
        }
 
+       if (fully_mapped && blocks_per_page == 1 && !PageUptodate(page) &&
+           cleancache_get_page(page) == 0) {
+               SetPageUptodate(page);
+               goto confused;
+       }
+
        /*
         * This page will go to BIO.  Do we need to send this BIO off first?
         */
index 6ff858c049c030fd5ea1e142a02c39bb4b51a2dc..0223c41fb1146cb529a92c784912498e15829a00 100644 (file)
@@ -238,7 +238,8 @@ int generic_permission(struct inode *inode, int mask, unsigned int flags,
 
        /*
         * Read/write DACs are always overridable.
-        * Executable DACs are overridable if at least one exec bit is set.
+        * Executable DACs are overridable for all directories and
+        * for non-directories that have least one exec bit set.
         */
        if (!(mask & MAY_EXEC) || execute_ok(inode))
                if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE))
@@ -391,79 +392,28 @@ void path_put(struct path *path)
 }
 EXPORT_SYMBOL(path_put);
 
-/**
- * nameidata_drop_rcu - drop this nameidata out of rcu-walk
- * @nd: nameidata pathwalk data to drop
- * Returns: 0 on success, -ECHILD on failure
- *
+/*
  * Path walking has 2 modes, rcu-walk and ref-walk (see
- * Documentation/filesystems/path-lookup.txt). __drop_rcu* functions attempt
- * to drop out of rcu-walk mode and take normal reference counts on dentries
- * and vfsmounts to transition to rcu-walk mode. __drop_rcu* functions take
- * refcounts at the last known good point before rcu-walk got stuck, so
- * ref-walk may continue from there. If this is not successful (eg. a seqcount
- * has changed), then failure is returned and path walk restarts from the
- * beginning in ref-walk mode.
- *
- * nameidata_drop_rcu attempts to drop the current nd->path and nd->root into
- * ref-walk. Must be called from rcu-walk context.
+ * Documentation/filesystems/path-lookup.txt).  In situations when we can't
+ * continue in RCU mode, we attempt to drop out of rcu-walk mode and grab
+ * normal reference counts on dentries and vfsmounts to transition to rcu-walk
+ * mode.  Refcounts are grabbed at the last known good point before rcu-walk
+ * got stuck, so ref-walk may continue from there. If this is not successful
+ * (eg. a seqcount has changed), then failure is returned and it's up to caller
+ * to restart the path walk from the beginning in ref-walk mode.
  */
-static int nameidata_drop_rcu(struct nameidata *nd)
-{
-       struct fs_struct *fs = current->fs;
-       struct dentry *dentry = nd->path.dentry;
-       int want_root = 0;
-
-       BUG_ON(!(nd->flags & LOOKUP_RCU));
-       if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
-               want_root = 1;
-               spin_lock(&fs->lock);
-               if (nd->root.mnt != fs->root.mnt ||
-                               nd->root.dentry != fs->root.dentry)
-                       goto err_root;
-       }
-       spin_lock(&dentry->d_lock);
-       if (!__d_rcu_to_refcount(dentry, nd->seq))
-               goto err;
-       BUG_ON(nd->inode != dentry->d_inode);
-       spin_unlock(&dentry->d_lock);
-       if (want_root) {
-               path_get(&nd->root);
-               spin_unlock(&fs->lock);
-       }
-       mntget(nd->path.mnt);
-
-       rcu_read_unlock();
-       br_read_unlock(vfsmount_lock);
-       nd->flags &= ~LOOKUP_RCU;
-       return 0;
-err:
-       spin_unlock(&dentry->d_lock);
-err_root:
-       if (want_root)
-               spin_unlock(&fs->lock);
-       return -ECHILD;
-}
-
-/* Try to drop out of rcu-walk mode if we were in it, otherwise do nothing.  */
-static inline int nameidata_drop_rcu_maybe(struct nameidata *nd)
-{
-       if (nd->flags & LOOKUP_RCU)
-               return nameidata_drop_rcu(nd);
-       return 0;
-}
 
 /**
- * nameidata_dentry_drop_rcu - drop nameidata and dentry out of rcu-walk
- * @nd: nameidata pathwalk data to drop
- * @dentry: dentry to drop
+ * unlazy_walk - try to switch to ref-walk mode.
+ * @nd: nameidata pathwalk data
+ * @dentry: child of nd->path.dentry or NULL
  * Returns: 0 on success, -ECHILD on failure
  *
- * nameidata_dentry_drop_rcu attempts to drop the current nd->path and nd->root,
- * and dentry into ref-walk. @dentry must be a path found by a do_lookup call on
- * @nd. Must be called from rcu-walk context.
+ * unlazy_walk attempts to legitimize the current nd->path, nd->root and dentry
+ * for ref-walk mode.  @dentry must be a path found by a do_lookup call on
+ * @nd or NULL.  Must be called from rcu-walk context.
  */
-static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry)
+static int unlazy_walk(struct nameidata *nd, struct dentry *dentry)
 {
        struct fs_struct *fs = current->fs;
        struct dentry *parent = nd->path.dentry;
@@ -478,18 +428,25 @@ static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry
                        goto err_root;
        }
        spin_lock(&parent->d_lock);
-       spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
-       if (!__d_rcu_to_refcount(dentry, nd->seq))
-               goto err;
-       /*
-        * If the sequence check on the child dentry passed, then the child has
-        * not been removed from its parent. This means the parent dentry must
-        * be valid and able to take a reference at this point.
-        */
-       BUG_ON(!IS_ROOT(dentry) && dentry->d_parent != parent);
-       BUG_ON(!parent->d_count);
-       parent->d_count++;
-       spin_unlock(&dentry->d_lock);
+       if (!dentry) {
+               if (!__d_rcu_to_refcount(parent, nd->seq))
+                       goto err_parent;
+               BUG_ON(nd->inode != parent->d_inode);
+       } else {
+               spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+               if (!__d_rcu_to_refcount(dentry, nd->seq))
+                       goto err_child;
+               /*
+                * If the sequence check on the child dentry passed, then
+                * the child has not been removed from its parent. This
+                * means the parent dentry must be valid and able to take
+                * a reference at this point.
+                */
+               BUG_ON(!IS_ROOT(dentry) && dentry->d_parent != parent);
+               BUG_ON(!parent->d_count);
+               parent->d_count++;
+               spin_unlock(&dentry->d_lock);
+       }
        spin_unlock(&parent->d_lock);
        if (want_root) {
                path_get(&nd->root);
@@ -501,8 +458,10 @@ static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry
        br_read_unlock(vfsmount_lock);
        nd->flags &= ~LOOKUP_RCU;
        return 0;
-err:
+
+err_child:
        spin_unlock(&dentry->d_lock);
+err_parent:
        spin_unlock(&parent->d_lock);
 err_root:
        if (want_root)
@@ -510,59 +469,6 @@ err_root:
        return -ECHILD;
 }
 
-/* Try to drop out of rcu-walk mode if we were in it, otherwise do nothing.  */
-static inline int nameidata_dentry_drop_rcu_maybe(struct nameidata *nd, struct dentry *dentry)
-{
-       if (nd->flags & LOOKUP_RCU) {
-               if (unlikely(nameidata_dentry_drop_rcu(nd, dentry))) {
-                       nd->flags &= ~LOOKUP_RCU;
-                       if (!(nd->flags & LOOKUP_ROOT))
-                               nd->root.mnt = NULL;
-                       rcu_read_unlock();
-                       br_read_unlock(vfsmount_lock);
-                       return -ECHILD;
-               }
-       }
-       return 0;
-}
-
-/**
- * nameidata_drop_rcu_last - drop nameidata ending path walk out of rcu-walk
- * @nd: nameidata pathwalk data to drop
- * Returns: 0 on success, -ECHILD on failure
- *
- * nameidata_drop_rcu_last attempts to drop the current nd->path into ref-walk.
- * nd->path should be the final element of the lookup, so nd->root is discarded.
- * Must be called from rcu-walk context.
- */
-static int nameidata_drop_rcu_last(struct nameidata *nd)
-{
-       struct dentry *dentry = nd->path.dentry;
-
-       BUG_ON(!(nd->flags & LOOKUP_RCU));
-       nd->flags &= ~LOOKUP_RCU;
-       if (!(nd->flags & LOOKUP_ROOT))
-               nd->root.mnt = NULL;
-       spin_lock(&dentry->d_lock);
-       if (!__d_rcu_to_refcount(dentry, nd->seq))
-               goto err_unlock;
-       BUG_ON(nd->inode != dentry->d_inode);
-       spin_unlock(&dentry->d_lock);
-
-       mntget(nd->path.mnt);
-
-       rcu_read_unlock();
-       br_read_unlock(vfsmount_lock);
-
-       return 0;
-
-err_unlock:
-       spin_unlock(&dentry->d_lock);
-       rcu_read_unlock();
-       br_read_unlock(vfsmount_lock);
-       return -ECHILD;
-}
-
 /**
  * release_open_intent - free up open intent resources
  * @nd: pointer to nameidata
@@ -606,26 +512,39 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd)
        return dentry;
 }
 
-/*
- * handle_reval_path - force revalidation of a dentry
- *
- * In some situations the path walking code will trust dentries without
- * revalidating them. This causes problems for filesystems that depend on
- * d_revalidate to handle file opens (e.g. NFSv4). When FS_REVAL_DOT is set
- * (which indicates that it's possible for the dentry to go stale), force
- * a d_revalidate call before proceeding.
+/**
+ * complete_walk - successful completion of path walk
+ * @nd:  pointer nameidata
  *
- * Returns 0 if the revalidation was successful. If the revalidation fails,
- * either return the error returned by d_revalidate or -ESTALE if the
- * revalidation it just returned 0. If d_revalidate returns 0, we attempt to
- * invalidate the dentry. It's up to the caller to handle putting references
- * to the path if necessary.
+ * If we had been in RCU mode, drop out of it and legitimize nd->path.
+ * Revalidate the final result, unless we'd already done that during
+ * the path walk or the filesystem doesn't ask for it.  Return 0 on
+ * success, -error on failure.  In case of failure caller does not
+ * need to drop nd->path.
  */
-static inline int handle_reval_path(struct nameidata *nd)
+static int complete_walk(struct nameidata *nd)
 {
        struct dentry *dentry = nd->path.dentry;
        int status;
 
+       if (nd->flags & LOOKUP_RCU) {
+               nd->flags &= ~LOOKUP_RCU;
+               if (!(nd->flags & LOOKUP_ROOT))
+                       nd->root.mnt = NULL;
+               spin_lock(&dentry->d_lock);
+               if (unlikely(!__d_rcu_to_refcount(dentry, nd->seq))) {
+                       spin_unlock(&dentry->d_lock);
+                       rcu_read_unlock();
+                       br_read_unlock(vfsmount_lock);
+                       return -ECHILD;
+               }
+               BUG_ON(nd->inode != dentry->d_inode);
+               spin_unlock(&dentry->d_lock);
+               mntget(nd->path.mnt);
+               rcu_read_unlock();
+               br_read_unlock(vfsmount_lock);
+       }
+
        if (likely(!(nd->flags & LOOKUP_JUMPED)))
                return 0;
 
@@ -643,6 +562,7 @@ static inline int handle_reval_path(struct nameidata *nd)
        if (!status)
                status = -ESTALE;
 
+       path_put(&nd->path);
        return status;
 }
 
@@ -893,6 +813,11 @@ static int follow_automount(struct path *path, unsigned flags,
        if (!mnt) /* mount collision */
                return 0;
 
+       if (!*need_mntput) {
+               /* lock_mount() may release path->mnt on error */
+               mntget(path->mnt);
+               *need_mntput = true;
+       }
        err = finish_automount(mnt, path);
 
        switch (err) {
@@ -900,12 +825,9 @@ static int follow_automount(struct path *path, unsigned flags,
                /* Someone else made a mount here whilst we were busy */
                return 0;
        case 0:
-               dput(path->dentry);
-               if (*need_mntput)
-                       mntput(path->mnt);
+               path_put(path);
                path->mnt = mnt;
                path->dentry = dget(mnt->mnt_root);
-               *need_mntput = true;
                return 0;
        default:
                return err;
@@ -925,9 +847,10 @@ static int follow_automount(struct path *path, unsigned flags,
  */
 static int follow_managed(struct path *path, unsigned flags)
 {
+       struct vfsmount *mnt = path->mnt; /* held by caller, must be left alone */
        unsigned managed;
        bool need_mntput = false;
-       int ret;
+       int ret = 0;
 
        /* Given that we're not holding a lock here, we retain the value in a
         * local variable for each dentry as we look at it so that we don't see
@@ -942,7 +865,7 @@ static int follow_managed(struct path *path, unsigned flags)
                        BUG_ON(!path->dentry->d_op->d_manage);
                        ret = path->dentry->d_op->d_manage(path->dentry, false);
                        if (ret < 0)
-                               return ret == -EISDIR ? 0 : ret;
+                               break;
                }
 
                /* Transit to a mounted filesystem. */
@@ -968,14 +891,19 @@ static int follow_managed(struct path *path, unsigned flags)
                if (managed & DCACHE_NEED_AUTOMOUNT) {
                        ret = follow_automount(path, flags, &need_mntput);
                        if (ret < 0)
-                               return ret == -EISDIR ? 0 : ret;
+                               break;
                        continue;
                }
 
                /* We didn't change the current path point */
                break;
        }
-       return 0;
+
+       if (need_mntput && path->mnt == mnt)
+               mntput(path->mnt);
+       if (ret == -EISDIR)
+               ret = 0;
+       return ret;
 }
 
 int follow_down_one(struct path *path)
@@ -1000,12 +928,11 @@ static inline bool managed_dentry_might_block(struct dentry *dentry)
 }
 
 /*
- * Skip to top of mountpoint pile in rcuwalk mode.  We abort the rcu-walk if we
- * meet a managed dentry and we're not walking to "..".  True is returned to
- * continue, false to abort.
+ * Try to skip to top of mountpoint pile in rcuwalk mode.  Fail if
+ * we meet a managed dentry that would need blocking.
  */
 static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
-                              struct inode **inode, bool reverse_transit)
+                              struct inode **inode)
 {
        for (;;) {
                struct vfsmount *mounted;
@@ -1014,8 +941,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                 * that wants to block transit.
                 */
                *inode = path->dentry->d_inode;
-               if (!reverse_transit &&
-                    unlikely(managed_dentry_might_block(path->dentry)))
+               if (unlikely(managed_dentry_might_block(path->dentry)))
                        return false;
 
                if (!d_mountpoint(path->dentry))
@@ -1028,16 +954,24 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                path->dentry = mounted->mnt_root;
                nd->seq = read_seqcount_begin(&path->dentry->d_seq);
        }
-
-       if (unlikely(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT))
-               return reverse_transit;
        return true;
 }
 
-static int follow_dotdot_rcu(struct nameidata *nd)
+static void follow_mount_rcu(struct nameidata *nd)
 {
-       struct inode *inode = nd->inode;
+       while (d_mountpoint(nd->path.dentry)) {
+               struct vfsmount *mounted;
+               mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry, 1);
+               if (!mounted)
+                       break;
+               nd->path.mnt = mounted;
+               nd->path.dentry = mounted->mnt_root;
+               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
+       }
+}
 
+static int follow_dotdot_rcu(struct nameidata *nd)
+{
        set_root_rcu(nd);
 
        while (1) {
@@ -1053,7 +987,6 @@ static int follow_dotdot_rcu(struct nameidata *nd)
                        seq = read_seqcount_begin(&parent->d_seq);
                        if (read_seqcount_retry(&old->d_seq, nd->seq))
                                goto failed;
-                       inode = parent->d_inode;
                        nd->path.dentry = parent;
                        nd->seq = seq;
                        break;
@@ -1061,10 +994,9 @@ static int follow_dotdot_rcu(struct nameidata *nd)
                if (!follow_up_rcu(&nd->path))
                        break;
                nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
-               inode = nd->path.dentry->d_inode;
        }
-       __follow_mount_rcu(nd, &nd->path, &inode, true);
-       nd->inode = inode;
+       follow_mount_rcu(nd);
+       nd->inode = nd->path.dentry->d_inode;
        return 0;
 
 failed:
@@ -1080,9 +1012,6 @@ failed:
  * Follow down to the covering mount currently visible to userspace.  At each
  * point, the filesystem owning that dentry may be queried as to whether the
  * caller is permitted to proceed or not.
- *
- * Care must be taken as namespace_sem may be held (indicated by mounting_here
- * being true).
  */
 int follow_down(struct path *path)
 {
@@ -1238,16 +1167,14 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
                }
                path->mnt = mnt;
                path->dentry = dentry;
-               if (likely(__follow_mount_rcu(nd, path, inode, false)))
-                       return 0;
+               if (unlikely(!__follow_mount_rcu(nd, path, inode)))
+                       goto unlazy;
+               if (unlikely(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT))
+                       goto unlazy;
+               return 0;
 unlazy:
-               if (dentry) {
-                       if (nameidata_dentry_drop_rcu(nd, dentry))
-                               return -ECHILD;
-               } else {
-                       if (nameidata_drop_rcu(nd))
-                               return -ECHILD;
-               }
+               if (unlazy_walk(nd, dentry))
+                       return -ECHILD;
        } else {
                dentry = __d_lookup(parent, name);
        }
@@ -1303,7 +1230,7 @@ static inline int may_lookup(struct nameidata *nd)
                int err = exec_permission(nd->inode, IPERM_FLAG_RCU);
                if (err != -ECHILD)
                        return err;
-               if (nameidata_drop_rcu(nd))
+               if (unlazy_walk(nd, NULL))
                        return -ECHILD;
        }
        return exec_permission(nd->inode, 0);
@@ -1357,8 +1284,12 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
                return -ENOENT;
        }
        if (unlikely(inode->i_op->follow_link) && follow) {
-               if (nameidata_dentry_drop_rcu_maybe(nd, path->dentry))
-                       return -ECHILD;
+               if (nd->flags & LOOKUP_RCU) {
+                       if (unlikely(unlazy_walk(nd, path->dentry))) {
+                               terminate_walk(nd);
+                               return -ECHILD;
+                       }
+               }
                BUG_ON(inode != path->dentry->d_inode);
                return 1;
        }
@@ -1657,18 +1588,8 @@ static int path_lookupat(int dfd, const char *name,
                }
        }
 
-       if (nd->flags & LOOKUP_RCU) {
-               /* went all way through without dropping RCU */
-               BUG_ON(err);
-               if (nameidata_drop_rcu_last(nd))
-                       err = -ECHILD;
-       }
-
-       if (!err) {
-               err = handle_reval_path(nd);
-               if (err)
-                       path_put(&nd->path);
-       }
+       if (!err)
+               err = complete_walk(nd);
 
        if (!err && nd->flags & LOOKUP_DIRECTORY) {
                if (!nd->inode->i_op->lookup) {
@@ -2134,13 +2055,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
                        return ERR_PTR(error);
                /* fallthrough */
        case LAST_ROOT:
-               if (nd->flags & LOOKUP_RCU) {
-                       if (nameidata_drop_rcu_last(nd))
-                               return ERR_PTR(-ECHILD);
-               }
-               error = handle_reval_path(nd);
+               error = complete_walk(nd);
                if (error)
-                       goto exit;
+                       return ERR_PTR(error);
                audit_inode(pathname, nd->path.dentry);
                if (open_flag & O_CREAT) {
                        error = -EISDIR;
@@ -2148,10 +2065,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
                }
                goto ok;
        case LAST_BIND:
-               /* can't be RCU mode here */
-               error = handle_reval_path(nd);
+               error = complete_walk(nd);
                if (error)
-                       goto exit;
+                       return ERR_PTR(error);
                audit_inode(pathname, dir);
                goto ok;
        }
@@ -2170,10 +2086,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
                if (error) /* symlink */
                        return NULL;
                /* sayonara */
-               if (nd->flags & LOOKUP_RCU) {
-                       if (nameidata_drop_rcu_last(nd))
-                               return ERR_PTR(-ECHILD);
-               }
+               error = complete_walk(nd);
+               if (error)
+                       return ERR_PTR(-ECHILD);
 
                error = -ENOTDIR;
                if (nd->flags & LOOKUP_DIRECTORY) {
@@ -2185,11 +2100,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
        }
 
        /* create side of things */
-
-       if (nd->flags & LOOKUP_RCU) {
-               if (nameidata_drop_rcu_last(nd))
-                       return ERR_PTR(-ECHILD);
-       }
+       error = complete_walk(nd);
+       if (error)
+               return ERR_PTR(error);
 
        audit_inode(pathname, dir);
        error = -EISDIR;
@@ -2629,10 +2542,10 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)
 }
 
 /*
- * We try to drop the dentry early: we should have
- * a usage count of 2 if we're the only user of this
- * dentry, and if that is true (possibly after pruning
- * the dcache), then we drop the dentry now.
+ * The dentry_unhash() helper will try to drop the dentry early: we
+ * should have a usage count of 2 if we're the only user of this
+ * dentry, and if that is true (possibly after pruning the dcache),
+ * then we drop the dentry now.
  *
  * A low-level filesystem can, if it choses, legally
  * do a
@@ -2645,10 +2558,9 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)
  */
 void dentry_unhash(struct dentry *dentry)
 {
-       dget(dentry);
        shrink_dcache_parent(dentry);
        spin_lock(&dentry->d_lock);
-       if (dentry->d_count == 2)
+       if (dentry->d_count == 1)
                __d_drop(dentry);
        spin_unlock(&dentry->d_lock);
 }
@@ -2664,25 +2576,27 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
                return -EPERM;
 
        mutex_lock(&dentry->d_inode->i_mutex);
-       dentry_unhash(dentry);
+
+       error = -EBUSY;
        if (d_mountpoint(dentry))
-               error = -EBUSY;
-       else {
-               error = security_inode_rmdir(dir, dentry);
-               if (!error) {
-                       error = dir->i_op->rmdir(dir, dentry);
-                       if (!error) {
-                               dentry->d_inode->i_flags |= S_DEAD;
-                               dont_mount(dentry);
-                       }
-               }
-       }
+               goto out;
+
+       error = security_inode_rmdir(dir, dentry);
+       if (error)
+               goto out;
+
+       shrink_dcache_parent(dentry);
+       error = dir->i_op->rmdir(dir, dentry);
+       if (error)
+               goto out;
+
+       dentry->d_inode->i_flags |= S_DEAD;
+       dont_mount(dentry);
+
+out:
        mutex_unlock(&dentry->d_inode->i_mutex);
-       if (!error) {
+       if (!error)
                d_delete(dentry);
-       }
-       dput(dentry);
-
        return error;
 }
 
@@ -2716,6 +2630,10 @@ static long do_rmdir(int dfd, const char __user *pathname)
        error = PTR_ERR(dentry);
        if (IS_ERR(dentry))
                goto exit2;
+       if (!dentry->d_inode) {
+               error = -ENOENT;
+               goto exit3;
+       }
        error = mnt_want_write(nd.path.mnt);
        if (error)
                goto exit3;
@@ -2804,8 +2722,9 @@ static long do_unlinkat(int dfd, const char __user *pathname)
                if (nd.last.name[nd.last.len])
                        goto slashes;
                inode = dentry->d_inode;
-               if (inode)
-                       ihold(inode);
+               if (!inode)
+                       goto slashes;
+               ihold(inode);
                error = mnt_want_write(nd.path.mnt);
                if (error)
                        goto exit2;
@@ -3053,12 +2972,7 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname
  *        HOWEVER, it relies on the assumption that any object with ->lookup()
  *        has no more than 1 dentry.  If "hybrid" objects will ever appear,
  *        we'd better make sure that there's no link(2) for them.
- *     d) some filesystems don't support opened-but-unlinked directories,
- *        either because of layout or because they are not ready to deal with
- *        all cases correctly. The latter will be fixed (taking this sort of
- *        stuff into VFS), but the former is not going away. Solution: the same
- *        trick as in rmdir().
- *     e) conversion from fhandle to dentry may come in the wrong moment - when
+ *     d) conversion from fhandle to dentry may come in the wrong moment - when
  *        we are removing the target. Solution: we will have to grab ->i_mutex
  *        in the fhandle_to_dentry code. [FIXME - current nfsfh.c relies on
  *        ->i_mutex on parents, which works but leads to some truly excessive
@@ -3068,7 +2982,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
                          struct inode *new_dir, struct dentry *new_dentry)
 {
        int error = 0;
-       struct inode *target;
+       struct inode *target = new_dentry->d_inode;
 
        /*
         * If we are going to change the parent - check write permissions,
@@ -3084,26 +2998,26 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
        if (error)
                return error;
 
-       target = new_dentry->d_inode;
        if (target)
                mutex_lock(&target->i_mutex);
-       if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
-               error = -EBUSY;
-       else {
-               if (target)
-                       dentry_unhash(new_dentry);
-               error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
-       }
+
+       error = -EBUSY;
+       if (d_mountpoint(old_dentry) || d_mountpoint(new_dentry))
+               goto out;
+
+       if (target)
+               shrink_dcache_parent(new_dentry);
+       error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
+       if (error)
+               goto out;
+
        if (target) {
-               if (!error) {
-                       target->i_flags |= S_DEAD;
-                       dont_mount(new_dentry);
-               }
-               mutex_unlock(&target->i_mutex);
-               if (d_unhashed(new_dentry))
-                       d_rehash(new_dentry);
-               dput(new_dentry);
+               target->i_flags |= S_DEAD;
+               dont_mount(new_dentry);
        }
+out:
+       if (target)
+               mutex_unlock(&target->i_mutex);
        if (!error)
                if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
                        d_move(old_dentry,new_dentry);
@@ -3113,7 +3027,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
 static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
                            struct inode *new_dir, struct dentry *new_dentry)
 {
-       struct inode *target;
+       struct inode *target = new_dentry->d_inode;
        int error;
 
        error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry);
@@ -3121,19 +3035,22 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
                return error;
 
        dget(new_dentry);
-       target = new_dentry->d_inode;
        if (target)
                mutex_lock(&target->i_mutex);
+
+       error = -EBUSY;
        if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
-               error = -EBUSY;
-       else
-               error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
-       if (!error) {
-               if (target)
-                       dont_mount(new_dentry);
-               if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
-                       d_move(old_dentry, new_dentry);
-       }
+               goto out;
+
+       error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
+       if (error)
+               goto out;
+
+       if (target)
+               dont_mount(new_dentry);
+       if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
+               d_move(old_dentry, new_dentry);
+out:
        if (target)
                mutex_unlock(&target->i_mutex);
        dput(new_dentry);
index d99bcf59e4c2fd23b2c03d2c9ed7471f7b2b230e..fe59bd145d214b0157b75dd7b441c91e24dcb56c 100644 (file)
@@ -1695,7 +1695,7 @@ static int graft_tree(struct vfsmount *mnt, struct path *path)
 
 static int flags_to_propagation_type(int flags)
 {
-       int type = flags & ~MS_REC;
+       int type = flags & ~(MS_REC | MS_SILENT);
 
        /* Fail if any non-propagation flags are set */
        if (type & ~(MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
index f6946bb5cb5530a655dba93d0aedb072ceb627cc..9c51f621e90105bad9481ab83272f57850c5d104 100644 (file)
@@ -1033,6 +1033,11 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
        DPRINTK("ncp_rmdir: removing %s/%s\n",
                dentry->d_parent->d_name.name, dentry->d_name.name);
 
+       /*
+        * fail with EBUSY if there are still references to this
+        * directory.
+        */
+       dentry_unhash(dentry);
        error = -EBUSY;
        if (!d_unhashed(dentry))
                goto out;
@@ -1139,6 +1144,17 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
                old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
                new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
 
+       if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode)) {
+               /*
+                * fail with EBUSY if there are still references to this
+                * directory.
+                */
+               dentry_unhash(new_dentry);
+               error = -EBUSY;
+               if (!d_unhashed(new_dentry))
+                       goto out;
+       }
+
        ncp_age_dentry(server, old_dentry);
        ncp_age_dentry(server, new_dentry);
 
index 0250e4ce489347f0a23fdbd551cd216a7abe208a..202f370526a724979ed3a8af6d1d6156027e5a09 100644 (file)
@@ -461,7 +461,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
 #endif
        struct ncp_entry_info finfo;
 
-       data.wdog_pid = NULL;
+       memset(&data, 0, sizeof(data));
        server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
        if (!server)
                return -ENOMEM;
@@ -496,7 +496,6 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
                                struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
 
                                data.flags = md->flags;
-                               data.int_flags = 0;
                                data.mounted_uid = md->mounted_uid;
                                data.wdog_pid = find_get_pid(md->wdog_pid);
                                data.ncp_fd = md->ncp_fd;
@@ -507,7 +506,6 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
                                data.file_mode = md->file_mode;
                                data.dir_mode = md->dir_mode;
                                data.info_fd = -1;
-                               data.mounted_vol[0] = 0;
                        }
                        break;
                default:
index a7c07b44b100b499593fb1ef7c6a24e1b9a3c15d..e5d71b27a5b0588be72426a598d80197d042a521 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/mman.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
+#include <linux/memcontrol.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -92,6 +93,7 @@ static int ncp_file_mmap_fault(struct vm_area_struct *area,
         * -- wli
         */
        count_vm_event(PGMAJFAULT);
+       mem_cgroup_count_vm_event(area->vm_mm, PGMAJFAULT);
        return VM_FAULT_MAJOR;
 }
 
index ba306658a6db16441843d7c4244a8c0158625acd..81515545ba755af46d4763d15560283087596d0b 100644 (file)
@@ -87,6 +87,16 @@ config NFS_V4_1
 config PNFS_FILE_LAYOUT
        tristate
 
+config PNFS_OBJLAYOUT
+       tristate "Provide support for the pNFS Objects Layout Driver for NFSv4.1 pNFS (EXPERIMENTAL)"
+       depends on NFS_FS && NFS_V4_1 && SCSI_OSD_ULD
+       help
+         Say M here if you want your pNFS client to support the Objects Layout Driver.
+         Requires the SCSI osd initiator library (SCSI_OSD_INITIATOR) and
+         upper level driver (SCSI_OSD_ULD).
+
+         If unsure, say N.
+
 config ROOT_NFS
        bool "Root file system on NFS"
        depends on NFS_FS=y && IP_PNP
index 4776ff9e38143d5f3c01744d8cd7261c2a62553c..6a34f7dd0e6f628a6ed0e68d09d09879dd03f366 100644 (file)
@@ -15,9 +15,11 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
                           delegation.o idmap.o \
                           callback.o callback_xdr.o callback_proc.o \
                           nfs4namespace.o
-nfs-$(CONFIG_NFS_V4_1) += pnfs.o
+nfs-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o
 nfs-$(CONFIG_SYSCTL) += sysctl.o
 nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o
 
 obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o
 nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o
+
+obj-$(CONFIG_PNFS_OBJLAYOUT) += objlayout/
index 46d93ce7311bb107a39005e0a66c818064e41ef2..b257383bb565a1331a68197a53d45545d436225e 100644 (file)
@@ -167,6 +167,23 @@ extern unsigned nfs4_callback_layoutrecall(
 
 extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses);
 extern void nfs4_cb_take_slot(struct nfs_client *clp);
+
+struct cb_devicenotifyitem {
+       uint32_t                cbd_notify_type;
+       uint32_t                cbd_layout_type;
+       struct nfs4_deviceid    cbd_dev_id;
+       uint32_t                cbd_immediate;
+};
+
+struct cb_devicenotifyargs {
+       int                              ndevs;
+       struct cb_devicenotifyitem       *devs;
+};
+
+extern __be32 nfs4_callback_devicenotify(
+       struct cb_devicenotifyargs *args,
+       void *dummy, struct cb_process_state *cps);
+
 #endif /* CONFIG_NFS_V4_1 */
 extern int check_gss_callback_principal(struct nfs_client *, struct svc_rqst *);
 extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args,
index 2f41dccea18ef3202e0daafc0747fb98cc9a5a8a..d4d1954e9bb989148d25cda962c008dfd0d29b37 100644 (file)
@@ -139,7 +139,7 @@ static u32 initiate_file_draining(struct nfs_client *clp,
        spin_lock(&ino->i_lock);
        if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
            mark_matching_lsegs_invalid(lo, &free_me_list,
-                                       args->cbl_range.iomode))
+                                       &args->cbl_range))
                rv = NFS4ERR_DELAY;
        else
                rv = NFS4ERR_NOMATCHING_LAYOUT;
@@ -184,7 +184,7 @@ static u32 initiate_bulk_draining(struct nfs_client *clp,
                ino = lo->plh_inode;
                spin_lock(&ino->i_lock);
                set_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags);
-               if (mark_matching_lsegs_invalid(lo, &free_me_list, range.iomode))
+               if (mark_matching_lsegs_invalid(lo, &free_me_list, &range))
                        rv = NFS4ERR_DELAY;
                list_del_init(&lo->plh_bulk_recall);
                spin_unlock(&ino->i_lock);
@@ -241,6 +241,53 @@ static void pnfs_recall_all_layouts(struct nfs_client *clp)
        do_callback_layoutrecall(clp, &args);
 }
 
+__be32 nfs4_callback_devicenotify(struct cb_devicenotifyargs *args,
+                                 void *dummy, struct cb_process_state *cps)
+{
+       int i;
+       __be32 res = 0;
+       struct nfs_client *clp = cps->clp;
+       struct nfs_server *server = NULL;
+
+       dprintk("%s: -->\n", __func__);
+
+       if (!clp) {
+               res = cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION);
+               goto out;
+       }
+
+       for (i = 0; i < args->ndevs; i++) {
+               struct cb_devicenotifyitem *dev = &args->devs[i];
+
+               if (!server ||
+                   server->pnfs_curr_ld->id != dev->cbd_layout_type) {
+                       rcu_read_lock();
+                       list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
+                               if (server->pnfs_curr_ld &&
+                                   server->pnfs_curr_ld->id == dev->cbd_layout_type) {
+                                       rcu_read_unlock();
+                                       goto found;
+                               }
+                       rcu_read_unlock();
+                       dprintk("%s: layout type %u not found\n",
+                               __func__, dev->cbd_layout_type);
+                       continue;
+               }
+
+       found:
+               if (dev->cbd_notify_type == NOTIFY_DEVICEID4_CHANGE)
+                       dprintk("%s: NOTIFY_DEVICEID4_CHANGE not supported, "
+                               "deleting instead\n", __func__);
+               nfs4_delete_deviceid(server->pnfs_curr_ld, clp, &dev->cbd_dev_id);
+       }
+
+out:
+       kfree(args->devs);
+       dprintk("%s: exit with status = %u\n",
+               __func__, be32_to_cpu(res));
+       return res;
+}
+
 int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
 {
        if (delegation == NULL)
index 00ecf62ce7c19023ee3abaedbe480478121524cc..c6c86a77e043fe938c40df750314116b8a3fcbb0 100644 (file)
@@ -25,6 +25,7 @@
 
 #if defined(CONFIG_NFS_V4_1)
 #define CB_OP_LAYOUTRECALL_RES_MAXSZ   (CB_OP_HDR_RES_MAXSZ)
+#define CB_OP_DEVICENOTIFY_RES_MAXSZ   (CB_OP_HDR_RES_MAXSZ)
 #define CB_OP_SEQUENCE_RES_MAXSZ       (CB_OP_HDR_RES_MAXSZ + \
                                        4 + 1 + 3)
 #define CB_OP_RECALLANY_RES_MAXSZ      (CB_OP_HDR_RES_MAXSZ)
@@ -284,6 +285,93 @@ out:
        return status;
 }
 
+static
+__be32 decode_devicenotify_args(struct svc_rqst *rqstp,
+                               struct xdr_stream *xdr,
+                               struct cb_devicenotifyargs *args)
+{
+       __be32 *p;
+       __be32 status = 0;
+       u32 tmp;
+       int n, i;
+       args->ndevs = 0;
+
+       /* Num of device notifications */
+       p = read_buf(xdr, sizeof(uint32_t));
+       if (unlikely(p == NULL)) {
+               status = htonl(NFS4ERR_BADXDR);
+               goto out;
+       }
+       n = ntohl(*p++);
+       if (n <= 0)
+               goto out;
+
+       args->devs = kmalloc(n * sizeof(*args->devs), GFP_KERNEL);
+       if (!args->devs) {
+               status = htonl(NFS4ERR_DELAY);
+               goto out;
+       }
+
+       /* Decode each dev notification */
+       for (i = 0; i < n; i++) {
+               struct cb_devicenotifyitem *dev = &args->devs[i];
+
+               p = read_buf(xdr, (4 * sizeof(uint32_t)) + NFS4_DEVICEID4_SIZE);
+               if (unlikely(p == NULL)) {
+                       status = htonl(NFS4ERR_BADXDR);
+                       goto err;
+               }
+
+               tmp = ntohl(*p++);      /* bitmap size */
+               if (tmp != 1) {
+                       status = htonl(NFS4ERR_INVAL);
+                       goto err;
+               }
+               dev->cbd_notify_type = ntohl(*p++);
+               if (dev->cbd_notify_type != NOTIFY_DEVICEID4_CHANGE &&
+                   dev->cbd_notify_type != NOTIFY_DEVICEID4_DELETE) {
+                       status = htonl(NFS4ERR_INVAL);
+                       goto err;
+               }
+
+               tmp = ntohl(*p++);      /* opaque size */
+               if (((dev->cbd_notify_type == NOTIFY_DEVICEID4_CHANGE) &&
+                    (tmp != NFS4_DEVICEID4_SIZE + 8)) ||
+                   ((dev->cbd_notify_type == NOTIFY_DEVICEID4_DELETE) &&
+                    (tmp != NFS4_DEVICEID4_SIZE + 4))) {
+                       status = htonl(NFS4ERR_INVAL);
+                       goto err;
+               }
+               dev->cbd_layout_type = ntohl(*p++);
+               memcpy(dev->cbd_dev_id.data, p, NFS4_DEVICEID4_SIZE);
+               p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
+
+               if (dev->cbd_layout_type == NOTIFY_DEVICEID4_CHANGE) {
+                       p = read_buf(xdr, sizeof(uint32_t));
+                       if (unlikely(p == NULL)) {
+                               status = htonl(NFS4ERR_BADXDR);
+                               goto err;
+                       }
+                       dev->cbd_immediate = ntohl(*p++);
+               } else {
+                       dev->cbd_immediate = 0;
+               }
+
+               args->ndevs++;
+
+               dprintk("%s: type %d layout 0x%x immediate %d\n",
+                       __func__, dev->cbd_notify_type, dev->cbd_layout_type,
+                       dev->cbd_immediate);
+       }
+out:
+       dprintk("%s: status %d ndevs %d\n",
+               __func__, ntohl(status), args->ndevs);
+       return status;
+err:
+       kfree(args->devs);
+       goto out;
+}
+
 static __be32 decode_sessionid(struct xdr_stream *xdr,
                                 struct nfs4_sessionid *sid)
 {
@@ -639,10 +727,10 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
        case OP_CB_RECALL_ANY:
        case OP_CB_RECALL_SLOT:
        case OP_CB_LAYOUTRECALL:
+       case OP_CB_NOTIFY_DEVICEID:
                *op = &callback_ops[op_nr];
                break;
 
-       case OP_CB_NOTIFY_DEVICEID:
        case OP_CB_NOTIFY:
        case OP_CB_PUSH_DELEG:
        case OP_CB_RECALLABLE_OBJ_AVAIL:
@@ -849,6 +937,12 @@ static struct callback_op callback_ops[] = {
                        (callback_decode_arg_t)decode_layoutrecall_args,
                .res_maxsize = CB_OP_LAYOUTRECALL_RES_MAXSZ,
        },
+       [OP_CB_NOTIFY_DEVICEID] = {
+               .process_op = (callback_process_op_t)nfs4_callback_devicenotify,
+               .decode_args =
+                       (callback_decode_arg_t)decode_devicenotify_args,
+               .res_maxsize = CB_OP_DEVICENOTIFY_RES_MAXSZ,
+       },
        [OP_CB_SEQUENCE] = {
                .process_op = (callback_process_op_t)nfs4_callback_sequence,
                .decode_args = (callback_decode_arg_t)decode_cb_sequence_args,
index 139be9647d80ed9c95a13c83d147a7355befd51b..b3dc2b88b65b139bae97fab53ad46be6b51846ab 100644 (file)
@@ -290,6 +290,8 @@ static void nfs_free_client(struct nfs_client *clp)
        if (clp->cl_machine_cred != NULL)
                put_rpccred(clp->cl_machine_cred);
 
+       nfs4_deviceid_purge_client(clp);
+
        kfree(clp->cl_hostname);
        kfree(clp);
 
index bbbc6bf5cb2e42a8b1440c31eafa2e0f2c0c5a77..dd25c2aec37598f23f63d5a4decf128121609cd7 100644 (file)
 #include "delegation.h"
 #include "internal.h"
 
-static void nfs_do_free_delegation(struct nfs_delegation *delegation)
-{
-       kfree(delegation);
-}
-
-static void nfs_free_delegation_callback(struct rcu_head *head)
-{
-       struct nfs_delegation *delegation = container_of(head, struct nfs_delegation, rcu);
-
-       nfs_do_free_delegation(delegation);
-}
-
 static void nfs_free_delegation(struct nfs_delegation *delegation)
 {
        if (delegation->cred) {
                put_rpccred(delegation->cred);
                delegation->cred = NULL;
        }
-       call_rcu(&delegation->rcu, nfs_free_delegation_callback);
+       kfree_rcu(delegation, rcu);
 }
 
 /**
index 7237672216c804769b945c9b09b1e57e1b3de202..ededdbd0db389197d2732174856e794ec72b6ead 100644 (file)
@@ -512,12 +512,7 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
                                struct page **xdr_pages, struct page *page, unsigned int buflen)
 {
        struct xdr_stream stream;
-       struct xdr_buf buf = {
-               .pages = xdr_pages,
-               .page_len = buflen,
-               .buflen = buflen,
-               .len = buflen,
-       };
+       struct xdr_buf buf;
        struct page *scratch;
        struct nfs_cache_array *array;
        unsigned int count = 0;
@@ -527,7 +522,7 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
        if (scratch == NULL)
                return -ENOMEM;
 
-       xdr_init_decode(&stream, &buf, NULL);
+       xdr_init_decode_pages(&stream, &buf, xdr_pages, buflen);
        xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
 
        do {
@@ -2042,11 +2037,14 @@ static void nfs_access_free_list(struct list_head *head)
        }
 }
 
-int nfs_access_cache_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
+int nfs_access_cache_shrinker(struct shrinker *shrink,
+                             struct shrink_control *sc)
 {
        LIST_HEAD(head);
        struct nfs_inode *nfsi, *next;
        struct nfs_access_entry *cache;
+       int nr_to_scan = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
 
        if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL)
                return (nr_to_scan == 0) ? 0 : -1;
index 57bb31ad7a5ec1c46a5533db711ee6d7d423f68e..6f4850deb272857ae5829251d64bf7aabf702130 100644 (file)
@@ -256,7 +256,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 
        nfs_attr_check_mountpoint(sb, fattr);
 
-       if ((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0 && (fattr->valid & NFS_ATTR_FATTR_MOUNTPOINT) == 0)
+       if (((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0) &&
+           !nfs_attr_use_mounted_on_fileid(fattr))
                goto out_no_inode;
        if ((fattr->valid & NFS_ATTR_FATTR_TYPE) == 0)
                goto out_no_inode;
@@ -1294,12 +1295,17 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                if (new_isize != cur_isize) {
                        /* Do we perhaps have any outstanding writes, or has
                         * the file grown beyond our last write? */
-                       if (nfsi->npages == 0 || new_isize > cur_isize) {
+                       if ((nfsi->npages == 0 && !test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) ||
+                            new_isize > cur_isize) {
                                i_size_write(inode, new_isize);
                                invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
                        }
-                       dprintk("NFS: isize change on server for file %s/%ld\n",
-                                       inode->i_sb->s_id, inode->i_ino);
+                       dprintk("NFS: isize change on server for file %s/%ld "
+                                       "(%Ld to %Ld)\n",
+                                       inode->i_sb->s_id,
+                                       inode->i_ino,
+                                       (long long)cur_isize,
+                                       (long long)new_isize);
                }
        } else
                invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
@@ -1424,9 +1430,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
  */
 void nfs4_evict_inode(struct inode *inode)
 {
-       pnfs_destroy_layout(NFS_I(inode));
        truncate_inode_pages(&inode->i_data, 0);
        end_writeback(inode);
+       pnfs_return_layout(inode);
+       pnfs_destroy_layout(NFS_I(inode));
        /* If we are holding a delegation, return it! */
        nfs_inode_return_delegation_noreclaim(inode);
        /* First call standard NFS clear_inode() code */
index ce118ce885dd5e20276356011e288d8502c6ef11..2a55347a2daa85f66aa24b44d7bb7c93efe1d409 100644 (file)
@@ -45,6 +45,17 @@ static inline void nfs_attr_check_mountpoint(struct super_block *parent, struct
                fattr->valid |= NFS_ATTR_FATTR_MOUNTPOINT;
 }
 
+static inline int nfs_attr_use_mounted_on_fileid(struct nfs_fattr *fattr)
+{
+       if (((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) == 0) ||
+           (((fattr->valid & NFS_ATTR_FATTR_MOUNTPOINT) == 0) &&
+            ((fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) == 0)))
+               return 0;
+
+       fattr->fileid = fattr->mounted_on_fileid;
+       return 1;
+}
+
 struct nfs_clone_mount {
        const struct super_block *sb;
        const struct dentry *dentry;
@@ -234,7 +245,7 @@ extern int nfs_init_client(struct nfs_client *clp,
 
 /* dir.c */
 extern int nfs_access_cache_shrinker(struct shrinker *shrink,
-                                       int nr_to_scan, gfp_t gfp_mask);
+                                       struct shrink_control *sc);
 
 /* inode.c */
 extern struct workqueue_struct *nfsiod_workqueue;
@@ -310,6 +321,7 @@ extern int nfs_migrate_page(struct address_space *,
 #endif
 
 /* nfs4proc.c */
+extern void __nfs4_read_done_cb(struct nfs_read_data *);
 extern void nfs4_reset_read(struct rpc_task *task, struct nfs_read_data *data);
 extern int nfs4_init_client(struct nfs_client *clp,
                            const struct rpc_timeout *timeparms,
index be79dc9f386da265328c1975127e8f577c85ed25..0bafcc91c27f8d8513dc1a7c8776fefd3411eee2 100644 (file)
@@ -30,6 +30,7 @@
  */
 
 #include <linux/nfs_fs.h>
+#include <linux/nfs_page.h>
 
 #include "internal.h"
 #include "nfs4filelayout.h"
@@ -421,6 +422,7 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo,
                        struct nfs4_deviceid *id,
                        gfp_t gfp_flags)
 {
+       struct nfs4_deviceid_node *d;
        struct nfs4_file_layout_dsaddr *dsaddr;
        int status = -EINVAL;
        struct nfs_server *nfss = NFS_SERVER(lo->plh_inode);
@@ -428,7 +430,7 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo,
        dprintk("--> %s\n", __func__);
 
        if (fl->pattern_offset > lgr->range.offset) {
-               dprintk("%s pattern_offset %lld to large\n",
+               dprintk("%s pattern_offset %lld too large\n",
                                __func__, fl->pattern_offset);
                goto out;
        }
@@ -440,12 +442,14 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo,
        }
 
        /* find and reference the deviceid */
-       dsaddr = nfs4_fl_find_get_deviceid(id);
-       if (dsaddr == NULL) {
+       d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode)->pnfs_curr_ld,
+                                  NFS_SERVER(lo->plh_inode)->nfs_client, id);
+       if (d == NULL) {
                dsaddr = get_device_info(lo->plh_inode, id, gfp_flags);
                if (dsaddr == NULL)
                        goto out;
-       }
+       } else
+               dsaddr = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
        fl->dsaddr = dsaddr;
 
        if (fl->first_stripe_index < 0 ||
@@ -507,12 +511,7 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
                         gfp_t gfp_flags)
 {
        struct xdr_stream stream;
-       struct xdr_buf buf = {
-               .pages =  lgr->layoutp->pages,
-               .page_len =  lgr->layoutp->len,
-               .buflen =  lgr->layoutp->len,
-               .len = lgr->layoutp->len,
-       };
+       struct xdr_buf buf;
        struct page *scratch;
        __be32 *p;
        uint32_t nfl_util;
@@ -524,7 +523,7 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
        if (!scratch)
                return -ENOMEM;
 
-       xdr_init_decode(&stream, &buf, NULL);
+       xdr_init_decode_pages(&stream, &buf, lgr->layoutp->pages, lgr->layoutp->len);
        xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
 
        /* 20 = ufl_util (4), first_stripe_index (4), pattern_offset (8),
@@ -535,7 +534,7 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
 
        memcpy(id, p, sizeof(*id));
        p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
-       print_deviceid(id);
+       nfs4_print_deviceid(id);
 
        nfl_util = be32_to_cpup(p++);
        if (nfl_util & NFL4_UFLG_COMMIT_THRU_MDS)
@@ -554,13 +553,18 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
                __func__, nfl_util, fl->num_fh, fl->first_stripe_index,
                fl->pattern_offset);
 
-       if (!fl->num_fh)
+       /* Note that a zero value for num_fh is legal for STRIPE_SPARSE.
+        * Futher checking is done in filelayout_check_layout */
+       if (fl->num_fh < 0 || fl->num_fh >
+           max(NFS4_PNFS_MAX_STRIPE_CNT, NFS4_PNFS_MAX_MULTI_CNT))
                goto out_err;
 
-       fl->fh_array = kzalloc(fl->num_fh * sizeof(struct nfs_fh *),
-                              gfp_flags);
-       if (!fl->fh_array)
-               goto out_err;
+       if (fl->num_fh > 0) {
+               fl->fh_array = kzalloc(fl->num_fh * sizeof(struct nfs_fh *),
+                                      gfp_flags);
+               if (!fl->fh_array)
+                       goto out_err;
+       }
 
        for (i = 0; i < fl->num_fh; i++) {
                /* Do we want to use a mempool here? */
@@ -653,16 +657,20 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
 /*
  * filelayout_pg_test(). Called by nfs_can_coalesce_requests()
  *
- * return 1 :  coalesce page
- * return 0 :  don't coalesce page
+ * return true  : coalesce page
+ * return false : don't coalesce page
  */
-int
+bool
 filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
                   struct nfs_page *req)
 {
        u64 p_stripe, r_stripe;
        u32 stripe_unit;
 
+       if (!pnfs_generic_pg_test(pgio, prev, req) ||
+           !nfs_generic_pg_test(pgio, prev, req))
+               return false;
+
        if (!pgio->pg_lseg)
                return 1;
        p_stripe = (u64)prev->wb_index << PAGE_CACHE_SHIFT;
@@ -860,6 +868,12 @@ filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
        return -ENOMEM;
 }
 
+static void
+filelayout_free_deveiceid_node(struct nfs4_deviceid_node *d)
+{
+       nfs4_fl_free_deviceid(container_of(d, struct nfs4_file_layout_dsaddr, id_node));
+}
+
 static struct pnfs_layoutdriver_type filelayout_type = {
        .id                     = LAYOUT_NFSV4_1_FILES,
        .name                   = "LAYOUT_NFSV4_1_FILES",
@@ -872,6 +886,7 @@ static struct pnfs_layoutdriver_type filelayout_type = {
        .commit_pagelist        = filelayout_commit_pagelist,
        .read_pagelist          = filelayout_read_pagelist,
        .write_pagelist         = filelayout_write_pagelist,
+       .free_deviceid_node     = filelayout_free_deveiceid_node,
 };
 
 static int __init nfs4filelayout_init(void)
index 2b461d77b43a9efa1c8235a955c18941ee8f56b5..cebe01e3795e949345ed169d3c4e0e2d10b6a62b 100644 (file)
@@ -59,9 +59,7 @@ struct nfs4_pnfs_ds {
 #define NFS4_DEVICE_ID_NEG_ENTRY       0x00000001
 
 struct nfs4_file_layout_dsaddr {
-       struct hlist_node               node;
-       struct nfs4_deviceid            deviceid;
-       atomic_t                        ref;
+       struct nfs4_deviceid_node       id_node;
        unsigned long                   flags;
        u32                             stripe_count;
        u8                              *stripe_indices;
@@ -95,14 +93,12 @@ extern struct nfs_fh *
 nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j);
 
 extern void print_ds(struct nfs4_pnfs_ds *ds);
-extern void print_deviceid(struct nfs4_deviceid *dev_id);
 u32 nfs4_fl_calc_j_index(struct pnfs_layout_segment *lseg, loff_t offset);
 u32 nfs4_fl_calc_ds_index(struct pnfs_layout_segment *lseg, u32 j);
 struct nfs4_pnfs_ds *nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg,
                                        u32 ds_idx);
-extern struct nfs4_file_layout_dsaddr *
-nfs4_fl_find_get_deviceid(struct nfs4_deviceid *dev_id);
 extern void nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr);
+extern void nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr);
 struct nfs4_file_layout_dsaddr *
 get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags);
 
index db07c7af139519a3b938e44e0042a8d91102434c..3b7bf13772641ac8409aef9e4e70d6eca99e7ec3 100644 (file)
 
 #define NFSDBG_FACILITY                NFSDBG_PNFS_LD
 
-/*
- * Device ID RCU cache. A device ID is unique per client ID and layout type.
- */
-#define NFS4_FL_DEVICE_ID_HASH_BITS    5
-#define NFS4_FL_DEVICE_ID_HASH_SIZE    (1 << NFS4_FL_DEVICE_ID_HASH_BITS)
-#define NFS4_FL_DEVICE_ID_HASH_MASK    (NFS4_FL_DEVICE_ID_HASH_SIZE - 1)
-
-static inline u32
-nfs4_fl_deviceid_hash(struct nfs4_deviceid *id)
-{
-       unsigned char *cptr = (unsigned char *)id->data;
-       unsigned int nbytes = NFS4_DEVICEID4_SIZE;
-       u32 x = 0;
-
-       while (nbytes--) {
-               x *= 37;
-               x += *cptr++;
-       }
-       return x & NFS4_FL_DEVICE_ID_HASH_MASK;
-}
-
-static struct hlist_head filelayout_deviceid_cache[NFS4_FL_DEVICE_ID_HASH_SIZE];
-static DEFINE_SPINLOCK(filelayout_deviceid_lock);
-
 /*
  * Data server cache
  *
@@ -89,27 +65,6 @@ print_ds(struct nfs4_pnfs_ds *ds)
                ds->ds_clp ? ds->ds_clp->cl_exchange_flags : 0);
 }
 
-void
-print_ds_list(struct nfs4_file_layout_dsaddr *dsaddr)
-{
-       int i;
-
-       ifdebug(FACILITY) {
-               printk("%s dsaddr->ds_num %d\n", __func__,
-                      dsaddr->ds_num);
-               for (i = 0; i < dsaddr->ds_num; i++)
-                       print_ds(dsaddr->ds_list[i]);
-       }
-}
-
-void print_deviceid(struct nfs4_deviceid *id)
-{
-       u32 *p = (u32 *)id;
-
-       dprintk("%s: device id= [%x%x%x%x]\n", __func__,
-               p[0], p[1], p[2], p[3]);
-}
-
 /* nfs4_ds_cache_lock is held */
 static struct nfs4_pnfs_ds *
 _data_server_lookup_locked(u32 ip_addr, u32 port)
@@ -201,13 +156,13 @@ destroy_ds(struct nfs4_pnfs_ds *ds)
        kfree(ds);
 }
 
-static void
+void
 nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
 {
        struct nfs4_pnfs_ds *ds;
        int i;
 
-       print_deviceid(&dsaddr->deviceid);
+       nfs4_print_deviceid(&dsaddr->id_node.deviceid);
 
        for (i = 0; i < dsaddr->ds_num; i++) {
                ds = dsaddr->ds_list[i];
@@ -353,12 +308,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
        u8 max_stripe_index;
        struct nfs4_file_layout_dsaddr *dsaddr = NULL;
        struct xdr_stream stream;
-       struct xdr_buf buf = {
-               .pages = pdev->pages,
-               .page_len = pdev->pglen,
-               .buflen = pdev->pglen,
-               .len = pdev->pglen,
-       };
+       struct xdr_buf buf;
        struct page *scratch;
 
        /* set up xdr stream */
@@ -366,7 +316,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
        if (!scratch)
                goto out_err;
 
-       xdr_init_decode(&stream, &buf, NULL);
+       xdr_init_decode_pages(&stream, &buf, pdev->pages, pdev->pglen);
        xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
 
        /* Get the stripe count (number of stripe index) */
@@ -431,8 +381,10 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
        dsaddr->stripe_indices = stripe_indices;
        stripe_indices = NULL;
        dsaddr->ds_num = num;
-
-       memcpy(&dsaddr->deviceid, &pdev->dev_id, sizeof(pdev->dev_id));
+       nfs4_init_deviceid_node(&dsaddr->id_node,
+                               NFS_SERVER(ino)->pnfs_curr_ld,
+                               NFS_SERVER(ino)->nfs_client,
+                               &pdev->dev_id);
 
        for (i = 0; i < dsaddr->ds_num; i++) {
                int j;
@@ -505,8 +457,8 @@ out_err:
 static struct nfs4_file_layout_dsaddr *
 decode_and_add_device(struct inode *inode, struct pnfs_device *dev, gfp_t gfp_flags)
 {
-       struct nfs4_file_layout_dsaddr *d, *new;
-       long hash;
+       struct nfs4_deviceid_node *d;
+       struct nfs4_file_layout_dsaddr *n, *new;
 
        new = decode_device(inode, dev, gfp_flags);
        if (!new) {
@@ -515,20 +467,13 @@ decode_and_add_device(struct inode *inode, struct pnfs_device *dev, gfp_t gfp_fl
                return NULL;
        }
 
-       spin_lock(&filelayout_deviceid_lock);
-       d = nfs4_fl_find_get_deviceid(&new->deviceid);
-       if (d) {
-               spin_unlock(&filelayout_deviceid_lock);
+       d = nfs4_insert_deviceid_node(&new->id_node);
+       n = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
+       if (n != new) {
                nfs4_fl_free_deviceid(new);
-               return d;
+               return n;
        }
 
-       INIT_HLIST_NODE(&new->node);
-       atomic_set(&new->ref, 1);
-       hash = nfs4_fl_deviceid_hash(&new->deviceid);
-       hlist_add_head_rcu(&new->node, &filelayout_deviceid_cache[hash]);
-       spin_unlock(&filelayout_deviceid_lock);
-
        return new;
 }
 
@@ -600,35 +545,7 @@ out_free:
 void
 nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
 {
-       if (atomic_dec_and_lock(&dsaddr->ref, &filelayout_deviceid_lock)) {
-               hlist_del_rcu(&dsaddr->node);
-               spin_unlock(&filelayout_deviceid_lock);
-
-               synchronize_rcu();
-               nfs4_fl_free_deviceid(dsaddr);
-       }
-}
-
-struct nfs4_file_layout_dsaddr *
-nfs4_fl_find_get_deviceid(struct nfs4_deviceid *id)
-{
-       struct nfs4_file_layout_dsaddr *d;
-       struct hlist_node *n;
-       long hash = nfs4_fl_deviceid_hash(id);
-
-
-       rcu_read_lock();
-       hlist_for_each_entry_rcu(d, n, &filelayout_deviceid_cache[hash], node) {
-               if (!memcmp(&d->deviceid, id, sizeof(*id))) {
-                       if (!atomic_inc_not_zero(&d->ref))
-                               goto fail;
-                       rcu_read_unlock();
-                       return d;
-               }
-       }
-fail:
-       rcu_read_unlock();
-       return NULL;
+       nfs4_put_deviceid_node(&dsaddr->id_node);
 }
 
 /*
@@ -676,15 +593,15 @@ static void
 filelayout_mark_devid_negative(struct nfs4_file_layout_dsaddr *dsaddr,
                               int err, u32 ds_addr)
 {
-       u32 *p = (u32 *)&dsaddr->deviceid;
+       u32 *p = (u32 *)&dsaddr->id_node.deviceid;
 
        printk(KERN_ERR "NFS: data server %x connection error %d."
                " Deviceid [%x%x%x%x] marked out of use.\n",
                ds_addr, err, p[0], p[1], p[2], p[3]);
 
-       spin_lock(&filelayout_deviceid_lock);
+       spin_lock(&nfs4_ds_cache_lock);
        dsaddr->flags |= NFS4_DEVICE_ID_NEG_ENTRY;
-       spin_unlock(&filelayout_deviceid_lock);
+       spin_unlock(&nfs4_ds_cache_lock);
 }
 
 struct nfs4_pnfs_ds *
index cf1b339c3937f7d959c6e5cbcf4a056ac16fbb2e..5879b23e0c99a1b0dfcff8c072bb0432ade497bf 100644 (file)
@@ -267,9 +267,11 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
                                break;
                        nfs4_schedule_stateid_recovery(server, state);
                        goto wait_on_recovery;
+               case -NFS4ERR_EXPIRED:
+                       if (state != NULL)
+                               nfs4_schedule_stateid_recovery(server, state);
                case -NFS4ERR_STALE_STATEID:
                case -NFS4ERR_STALE_CLIENTID:
-               case -NFS4ERR_EXPIRED:
                        nfs4_schedule_lease_recovery(clp);
                        goto wait_on_recovery;
 #if defined(CONFIG_NFS_V4_1)
@@ -2263,12 +2265,14 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
        return nfs4_map_errors(status);
 }
 
+static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);
 /*
  * Get locations and (maybe) other attributes of a referral.
  * Note that we'll actually follow the referral later when
  * we detect fsid mismatch in inode revalidation
  */
-static int nfs4_get_referral(struct inode *dir, const struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle)
+static int nfs4_get_referral(struct inode *dir, const struct qstr *name,
+                            struct nfs_fattr *fattr, struct nfs_fh *fhandle)
 {
        int status = -ENOMEM;
        struct page *page = NULL;
@@ -2286,15 +2290,16 @@ static int nfs4_get_referral(struct inode *dir, const struct qstr *name, struct
                goto out;
        /* Make sure server returned a different fsid for the referral */
        if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) {
-               dprintk("%s: server did not return a different fsid for a referral at %s\n", __func__, name->name);
+               dprintk("%s: server did not return a different fsid for"
+                       " a referral at %s\n", __func__, name->name);
                status = -EIO;
                goto out;
        }
+       /* Fixup attributes for the nfs_lookup() call to nfs_fhget() */
+       nfs_fixup_referral_attributes(&locations->fattr);
 
+       /* replace the lookup nfs_fattr with the locations nfs_fattr */
        memcpy(fattr, &locations->fattr, sizeof(struct nfs_fattr));
-       fattr->valid |= NFS_ATTR_FATTR_V4_REFERRAL;
-       if (!fattr->mode)
-               fattr->mode = S_IFDIR;
        memset(fhandle, 0, sizeof(struct nfs_fh));
 out:
        if (page)
@@ -2361,6 +2366,9 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
        struct nfs4_state *state = NULL;
        int status;
 
+       if (pnfs_ld_layoutret_on_setattr(inode))
+               pnfs_return_layout(inode);
+
        nfs_fattr_init(fattr);
        
        /* Search for an existing open(O_WRITE) file */
@@ -3175,6 +3183,11 @@ static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
        return err;
 }
 
+void __nfs4_read_done_cb(struct nfs_read_data *data)
+{
+       nfs_invalidate_atime(data->inode);
+}
+
 static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data)
 {
        struct nfs_server *server = NFS_SERVER(data->inode);
@@ -3184,7 +3197,7 @@ static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data)
                return -EAGAIN;
        }
 
-       nfs_invalidate_atime(data->inode);
+       __nfs4_read_done_cb(data);
        if (task->tk_status > 0)
                renew_lease(server, data->timestamp);
        return 0;
@@ -3198,7 +3211,8 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
        if (!nfs4_sequence_done(task, &data->res.seq_res))
                return -EAGAIN;
 
-       return data->read_done_cb(task, data);
+       return data->read_done_cb ? data->read_done_cb(task, data) :
+                                   nfs4_read_done_cb(task, data);
 }
 
 static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg)
@@ -3243,7 +3257,8 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
 {
        if (!nfs4_sequence_done(task, &data->res.seq_res))
                return -EAGAIN;
-       return data->write_done_cb(task, data);
+       return data->write_done_cb ? data->write_done_cb(task, data) :
+               nfs4_write_done_cb(task, data);
 }
 
 /* Reset the the nfs_write_data to send the write to the MDS. */
@@ -3670,9 +3685,11 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
                                break;
                        nfs4_schedule_stateid_recovery(server, state);
                        goto wait_on_recovery;
+               case -NFS4ERR_EXPIRED:
+                       if (state != NULL)
+                               nfs4_schedule_stateid_recovery(server, state);
                case -NFS4ERR_STALE_STATEID:
                case -NFS4ERR_STALE_CLIENTID:
-               case -NFS4ERR_EXPIRED:
                        nfs4_schedule_lease_recovery(clp);
                        goto wait_on_recovery;
 #if defined(CONFIG_NFS_V4_1)
@@ -4543,6 +4560,7 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
                        case -ESTALE:
                                goto out;
                        case -NFS4ERR_EXPIRED:
+                               nfs4_schedule_stateid_recovery(server, state);
                        case -NFS4ERR_STALE_CLIENTID:
                        case -NFS4ERR_STALE_STATEID:
                                nfs4_schedule_lease_recovery(server->nfs_client);
@@ -4652,11 +4670,15 @@ static size_t nfs4_xattr_list_nfs4_acl(struct dentry *dentry, char *list,
        return len;
 }
 
+/*
+ * nfs_fhget will use either the mounted_on_fileid or the fileid
+ */
 static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr)
 {
-       if (!((fattr->valid & NFS_ATTR_FATTR_FILEID) &&
-               (fattr->valid & NFS_ATTR_FATTR_FSID) &&
-               (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)))
+       if (!(((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) ||
+              (fattr->valid & NFS_ATTR_FATTR_FILEID)) &&
+             (fattr->valid & NFS_ATTR_FATTR_FSID) &&
+             (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)))
                return;
 
        fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE |
@@ -4671,7 +4693,6 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
        struct nfs_server *server = NFS_SERVER(dir);
        u32 bitmask[2] = {
                [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
-               [1] = FATTR4_WORD1_MOUNTED_ON_FILEID,
        };
        struct nfs4_fs_locations_arg args = {
                .dir_fh = NFS_FH(dir),
@@ -4690,11 +4711,18 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
        int status;
 
        dprintk("%s: start\n", __func__);
+
+       /* Ask for the fileid of the absent filesystem if mounted_on_fileid
+        * is not supported */
+       if (NFS_SERVER(dir)->attr_bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
+               bitmask[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID;
+       else
+               bitmask[0] |= FATTR4_WORD0_FILEID;
+
        nfs_fattr_init(&fs_locations->fattr);
        fs_locations->server = server;
        fs_locations->nlocations = 0;
        status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
-       nfs_fixup_referral_attributes(&fs_locations->fattr);
        dprintk("%s: returned status = %d\n", __func__, status);
        return status;
 }
@@ -5083,7 +5111,6 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args)
        if (mxresp_sz == 0)
                mxresp_sz = NFS_MAX_FILE_IO_SIZE;
        /* Fore channel attributes */
-       args->fc_attrs.headerpadsz = 0;
        args->fc_attrs.max_rqst_sz = mxrqst_sz;
        args->fc_attrs.max_resp_sz = mxresp_sz;
        args->fc_attrs.max_ops = NFS4_MAX_OPS;
@@ -5096,7 +5123,6 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args)
                args->fc_attrs.max_ops, args->fc_attrs.max_reqs);
 
        /* Back channel attributes */
-       args->bc_attrs.headerpadsz = 0;
        args->bc_attrs.max_rqst_sz = PAGE_SIZE;
        args->bc_attrs.max_resp_sz = PAGE_SIZE;
        args->bc_attrs.max_resp_sz_cached = 0;
@@ -5116,8 +5142,6 @@ static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args
        struct nfs4_channel_attrs *sent = &args->fc_attrs;
        struct nfs4_channel_attrs *rcvd = &session->fc_attrs;
 
-       if (rcvd->headerpadsz > sent->headerpadsz)
-               return -EINVAL;
        if (rcvd->max_resp_sz > sent->max_resp_sz)
                return -EINVAL;
        /*
@@ -5666,6 +5690,88 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
        return status;
 }
 
+static void
+nfs4_layoutreturn_prepare(struct rpc_task *task, void *calldata)
+{
+       struct nfs4_layoutreturn *lrp = calldata;
+
+       dprintk("--> %s\n", __func__);
+       if (nfs41_setup_sequence(lrp->clp->cl_session, &lrp->args.seq_args,
+                               &lrp->res.seq_res, 0, task))
+               return;
+       rpc_call_start(task);
+}
+
+static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
+{
+       struct nfs4_layoutreturn *lrp = calldata;
+       struct nfs_server *server;
+       struct pnfs_layout_hdr *lo = NFS_I(lrp->args.inode)->layout;
+
+       dprintk("--> %s\n", __func__);
+
+       if (!nfs4_sequence_done(task, &lrp->res.seq_res))
+               return;
+
+       server = NFS_SERVER(lrp->args.inode);
+       if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
+               nfs_restart_rpc(task, lrp->clp);
+               return;
+       }
+       spin_lock(&lo->plh_inode->i_lock);
+       if (task->tk_status == 0) {
+               if (lrp->res.lrs_present) {
+                       pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
+               } else
+                       BUG_ON(!list_empty(&lo->plh_segs));
+       }
+       lo->plh_block_lgets--;
+       spin_unlock(&lo->plh_inode->i_lock);
+       dprintk("<-- %s\n", __func__);
+}
+
+static void nfs4_layoutreturn_release(void *calldata)
+{
+       struct nfs4_layoutreturn *lrp = calldata;
+
+       dprintk("--> %s\n", __func__);
+       put_layout_hdr(NFS_I(lrp->args.inode)->layout);
+       kfree(calldata);
+       dprintk("<-- %s\n", __func__);
+}
+
+static const struct rpc_call_ops nfs4_layoutreturn_call_ops = {
+       .rpc_call_prepare = nfs4_layoutreturn_prepare,
+       .rpc_call_done = nfs4_layoutreturn_done,
+       .rpc_release = nfs4_layoutreturn_release,
+};
+
+int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)
+{
+       struct rpc_task *task;
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTRETURN],
+               .rpc_argp = &lrp->args,
+               .rpc_resp = &lrp->res,
+       };
+       struct rpc_task_setup task_setup_data = {
+               .rpc_client = lrp->clp->cl_rpcclient,
+               .rpc_message = &msg,
+               .callback_ops = &nfs4_layoutreturn_call_ops,
+               .callback_data = lrp,
+       };
+       int status;
+
+       dprintk("--> %s\n", __func__);
+       task = rpc_run_task(&task_setup_data);
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+       status = task->tk_status;
+       dprintk("<-- %s status=%d\n", __func__, status);
+       rpc_put_task(task);
+       return status;
+}
+
 static int
 _nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
 {
index 036f5adc9e1fad417eb13c2b8687e6ea56abb613..e97dd219f84f4e205cf0a583fdb247d4ba01d807 100644 (file)
@@ -1466,7 +1466,10 @@ static int nfs4_reclaim_lease(struct nfs_client *clp)
 #ifdef CONFIG_NFS_V4_1
 void nfs4_schedule_session_recovery(struct nfs4_session *session)
 {
-       nfs4_schedule_lease_recovery(session->clp);
+       struct nfs_client *clp = session->clp;
+
+       set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
+       nfs4_schedule_lease_recovery(clp);
 }
 EXPORT_SYMBOL_GPL(nfs4_schedule_session_recovery);
 
@@ -1549,6 +1552,7 @@ static int nfs4_reset_session(struct nfs_client *clp)
                status = nfs4_recovery_handle_error(clp, status);
                goto out;
        }
+       clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
        /* create_session negotiated new slot table */
        clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state);
 
index c3ccd2c468344fab9076214fec8d99fc1eee9036..6870bc61ceec4083f80818c4a31f934dab3227b1 100644 (file)
@@ -255,7 +255,7 @@ static int nfs4_stat_to_errno(int);
 #define decode_fs_locations_maxsz \
                                (0)
 #define encode_secinfo_maxsz   (op_encode_hdr_maxsz + nfs4_name_maxsz)
-#define decode_secinfo_maxsz   (op_decode_hdr_maxsz + 4 + (NFS_MAX_SECFLAVORS * (16 + GSS_OID_MAX_LEN)))
+#define decode_secinfo_maxsz   (op_decode_hdr_maxsz + 1 + ((NFS_MAX_SECFLAVORS * (16 + GSS_OID_MAX_LEN)) / 4))
 
 #if defined(CONFIG_NFS_V4_1)
 #define NFS4_MAX_MACHINE_NAME_LEN (64)
@@ -338,7 +338,11 @@ static int nfs4_stat_to_errno(int);
                                1 /* layoutupdate4 layout type */ + \
                                1 /* NULL filelayout layoutupdate4 payload */)
 #define decode_layoutcommit_maxsz (op_decode_hdr_maxsz + 3)
-
+#define encode_layoutreturn_maxsz (8 + op_encode_hdr_maxsz + \
+                               encode_stateid_maxsz + \
+                               1 /* FIXME: opaque lrf_body always empty at the moment */)
+#define decode_layoutreturn_maxsz (op_decode_hdr_maxsz + \
+                               1 + decode_stateid_maxsz)
 #else /* CONFIG_NFS_V4_1 */
 #define encode_sequence_maxsz  0
 #define decode_sequence_maxsz  0
@@ -760,7 +764,14 @@ static int nfs4_stat_to_errno(int);
                                decode_putfh_maxsz + \
                                decode_layoutcommit_maxsz + \
                                decode_getattr_maxsz)
-
+#define NFS4_enc_layoutreturn_sz (compound_encode_hdr_maxsz + \
+                               encode_sequence_maxsz + \
+                               encode_putfh_maxsz + \
+                               encode_layoutreturn_maxsz)
+#define NFS4_dec_layoutreturn_sz (compound_decode_hdr_maxsz + \
+                               decode_sequence_maxsz + \
+                               decode_putfh_maxsz + \
+                               decode_layoutreturn_maxsz)
 
 const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
                                      compound_encode_hdr_maxsz +
@@ -1714,7 +1725,7 @@ static void encode_create_session(struct xdr_stream *xdr,
        *p++ = cpu_to_be32(args->flags);                        /*flags */
 
        /* Fore Channel */
-       *p++ = cpu_to_be32(args->fc_attrs.headerpadsz); /* header padding size */
+       *p++ = cpu_to_be32(0);                          /* header padding size */
        *p++ = cpu_to_be32(args->fc_attrs.max_rqst_sz); /* max req size */
        *p++ = cpu_to_be32(args->fc_attrs.max_resp_sz); /* max resp size */
        *p++ = cpu_to_be32(max_resp_sz_cached);         /* Max resp sz cached */
@@ -1723,7 +1734,7 @@ static void encode_create_session(struct xdr_stream *xdr,
        *p++ = cpu_to_be32(0);                          /* rdmachannel_attrs */
 
        /* Back Channel */
-       *p++ = cpu_to_be32(args->fc_attrs.headerpadsz); /* header padding size */
+       *p++ = cpu_to_be32(0);                          /* header padding size */
        *p++ = cpu_to_be32(args->bc_attrs.max_rqst_sz); /* max req size */
        *p++ = cpu_to_be32(args->bc_attrs.max_resp_sz); /* max resp size */
        *p++ = cpu_to_be32(args->bc_attrs.max_resp_sz_cached);  /* Max resp sz cached */
@@ -1864,6 +1875,7 @@ encode_layoutget(struct xdr_stream *xdr,
 
 static int
 encode_layoutcommit(struct xdr_stream *xdr,
+                   struct inode *inode,
                    const struct nfs4_layoutcommit_args *args,
                    struct compound_hdr *hdr)
 {
@@ -1872,7 +1884,7 @@ encode_layoutcommit(struct xdr_stream *xdr,
        dprintk("%s: lbw: %llu type: %d\n", __func__, args->lastbytewritten,
                NFS_SERVER(args->inode)->pnfs_curr_ld->id);
 
-       p = reserve_space(xdr, 48 + NFS4_STATEID_SIZE);
+       p = reserve_space(xdr, 44 + NFS4_STATEID_SIZE);
        *p++ = cpu_to_be32(OP_LAYOUTCOMMIT);
        /* Only whole file layouts */
        p = xdr_encode_hyper(p, 0); /* offset */
@@ -1883,12 +1895,49 @@ encode_layoutcommit(struct xdr_stream *xdr,
        p = xdr_encode_hyper(p, args->lastbytewritten);
        *p++ = cpu_to_be32(0); /* Never send time_modify_changed */
        *p++ = cpu_to_be32(NFS_SERVER(args->inode)->pnfs_curr_ld->id);/* type */
-       *p++ = cpu_to_be32(0); /* no file layout payload */
+
+       if (NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit)
+               NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit(
+                       NFS_I(inode)->layout, xdr, args);
+       else {
+               p = reserve_space(xdr, 4);
+               *p = cpu_to_be32(0); /* no layout-type payload */
+       }
 
        hdr->nops++;
        hdr->replen += decode_layoutcommit_maxsz;
        return 0;
 }
+
+static void
+encode_layoutreturn(struct xdr_stream *xdr,
+                   const struct nfs4_layoutreturn_args *args,
+                   struct compound_hdr *hdr)
+{
+       __be32 *p;
+
+       p = reserve_space(xdr, 20);
+       *p++ = cpu_to_be32(OP_LAYOUTRETURN);
+       *p++ = cpu_to_be32(0);          /* reclaim. always 0 for now */
+       *p++ = cpu_to_be32(args->layout_type);
+       *p++ = cpu_to_be32(IOMODE_ANY);
+       *p = cpu_to_be32(RETURN_FILE);
+       p = reserve_space(xdr, 16 + NFS4_STATEID_SIZE);
+       p = xdr_encode_hyper(p, 0);
+       p = xdr_encode_hyper(p, NFS4_MAX_UINT64);
+       spin_lock(&args->inode->i_lock);
+       xdr_encode_opaque_fixed(p, &args->stateid.data, NFS4_STATEID_SIZE);
+       spin_unlock(&args->inode->i_lock);
+       if (NFS_SERVER(args->inode)->pnfs_curr_ld->encode_layoutreturn) {
+               NFS_SERVER(args->inode)->pnfs_curr_ld->encode_layoutreturn(
+                       NFS_I(args->inode)->layout, xdr, args);
+       } else {
+               p = reserve_space(xdr, 4);
+               *p = cpu_to_be32(0);
+       }
+       hdr->nops++;
+       hdr->replen += decode_layoutreturn_maxsz;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 /*
@@ -2706,10 +2755,12 @@ static void nfs4_xdr_enc_layoutget(struct rpc_rqst *req,
 /*
  *  Encode LAYOUTCOMMIT request
  */
-static int nfs4_xdr_enc_layoutcommit(struct rpc_rqst *req,
-                                    struct xdr_stream *xdr,
-                                    struct nfs4_layoutcommit_args *args)
+static void nfs4_xdr_enc_layoutcommit(struct rpc_rqst *req,
+                                     struct xdr_stream *xdr,
+                                     struct nfs4_layoutcommit_args *args)
 {
+       struct nfs4_layoutcommit_data *data =
+               container_of(args, struct nfs4_layoutcommit_data, args);
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
@@ -2717,10 +2768,27 @@ static int nfs4_xdr_enc_layoutcommit(struct rpc_rqst *req,
        encode_compound_hdr(xdr, req, &hdr);
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, NFS_FH(args->inode), &hdr);
-       encode_layoutcommit(xdr, args, &hdr);
+       encode_layoutcommit(xdr, data->args.inode, args, &hdr);
        encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
-       return 0;
+}
+
+/*
+ * Encode LAYOUTRETURN request
+ */
+static void nfs4_xdr_enc_layoutreturn(struct rpc_rqst *req,
+                                     struct xdr_stream *xdr,
+                                     struct nfs4_layoutreturn_args *args)
+{
+       struct compound_hdr hdr = {
+               .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+       };
+
+       encode_compound_hdr(xdr, req, &hdr);
+       encode_sequence(xdr, &args->seq_args, &hdr);
+       encode_putfh(xdr, NFS_FH(args->inode), &hdr);
+       encode_layoutreturn(xdr, args, &hdr);
+       encode_nops(&hdr);
 }
 #endif /* CONFIG_NFS_V4_1 */
 
@@ -3030,7 +3098,7 @@ out_overflow:
        return -EIO;
 }
 
-static int decode_attr_error(struct xdr_stream *xdr, uint32_t *bitmap)
+static int decode_attr_error(struct xdr_stream *xdr, uint32_t *bitmap, int32_t *res)
 {
        __be32 *p;
 
@@ -3041,7 +3109,7 @@ static int decode_attr_error(struct xdr_stream *xdr, uint32_t *bitmap)
                if (unlikely(!p))
                        goto out_overflow;
                bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR;
-               return -be32_to_cpup(p);
+               *res = -be32_to_cpup(p);
        }
        return 0;
 out_overflow:
@@ -4002,6 +4070,7 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
        int status;
        umode_t fmode = 0;
        uint32_t type;
+       int32_t err;
 
        status = decode_attr_type(xdr, bitmap, &type);
        if (status < 0)
@@ -4027,13 +4096,12 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
                goto xdr_error;
        fattr->valid |= status;
 
-       status = decode_attr_error(xdr, bitmap);
-       if (status == -NFS4ERR_WRONGSEC) {
-               nfs_fixup_secinfo_attributes(fattr, fh);
-               status = 0;
-       }
+       err = 0;
+       status = decode_attr_error(xdr, bitmap, &err);
        if (status < 0)
                goto xdr_error;
+       if (err == -NFS4ERR_WRONGSEC)
+               nfs_fixup_secinfo_attributes(fattr, fh);
 
        status = decode_attr_filehandle(xdr, bitmap, fh);
        if (status < 0)
@@ -4929,12 +4997,14 @@ static int decode_chan_attrs(struct xdr_stream *xdr,
                             struct nfs4_channel_attrs *attrs)
 {
        __be32 *p;
-       u32 nr_attrs;
+       u32 nr_attrs, val;
 
        p = xdr_inline_decode(xdr, 28);
        if (unlikely(!p))
                goto out_overflow;
-       attrs->headerpadsz = be32_to_cpup(p++);
+       val = be32_to_cpup(p++);        /* headerpadsz */
+       if (val)
+               return -EINVAL;         /* no support for header padding yet */
        attrs->max_rqst_sz = be32_to_cpup(p++);
        attrs->max_resp_sz = be32_to_cpup(p++);
        attrs->max_resp_sz_cached = be32_to_cpup(p++);
@@ -5203,6 +5273,27 @@ out_overflow:
        return -EIO;
 }
 
+static int decode_layoutreturn(struct xdr_stream *xdr,
+                              struct nfs4_layoutreturn_res *res)
+{
+       __be32 *p;
+       int status;
+
+       status = decode_op_hdr(xdr, OP_LAYOUTRETURN);
+       if (status)
+               return status;
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       res->lrs_present = be32_to_cpup(p);
+       if (res->lrs_present)
+               status = decode_stateid(xdr, &res->stateid);
+       return status;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+}
+
 static int decode_layoutcommit(struct xdr_stream *xdr,
                               struct rpc_rqst *req,
                               struct nfs4_layoutcommit_res *res)
@@ -6319,6 +6410,30 @@ out:
        return status;
 }
 
+/*
+ * Decode LAYOUTRETURN response
+ */
+static int nfs4_xdr_dec_layoutreturn(struct rpc_rqst *rqstp,
+                                    struct xdr_stream *xdr,
+                                    struct nfs4_layoutreturn_res *res)
+{
+       struct compound_hdr hdr;
+       int status;
+
+       status = decode_compound_hdr(xdr, &hdr);
+       if (status)
+               goto out;
+       status = decode_sequence(xdr, &res->seq_res, rqstp);
+       if (status)
+               goto out;
+       status = decode_putfh(xdr);
+       if (status)
+               goto out;
+       status = decode_layoutreturn(xdr, res);
+out:
+       return status;
+}
+
 /*
  * Decode LAYOUTCOMMIT response
  */
@@ -6547,6 +6662,7 @@ struct rpc_procinfo       nfs4_procedures[] = {
        PROC(GETDEVICEINFO,     enc_getdeviceinfo,      dec_getdeviceinfo),
        PROC(LAYOUTGET,         enc_layoutget,          dec_layoutget),
        PROC(LAYOUTCOMMIT,      enc_layoutcommit,       dec_layoutcommit),
+       PROC(LAYOUTRETURN,      enc_layoutreturn,       dec_layoutreturn),
 #endif /* CONFIG_NFS_V4_1 */
 };
 
index c541093a5bf2cf058521a1bddd82c404befb5f38..c4744e1d513c826545898e3310631c5f8153ae98 100644 (file)
@@ -87,7 +87,7 @@
 #define NFS_ROOT               "/tftpboot/%s"
 
 /* Default NFSROOT mount options. */
-#define NFS_DEF_OPTIONS                "udp"
+#define NFS_DEF_OPTIONS                "vers=2,udp,rsize=4096,wsize=4096"
 
 /* Parameters passed from the kernel command line */
 static char nfs_root_parms[256] __initdata = "";
diff --git a/fs/nfs/objlayout/Kbuild b/fs/nfs/objlayout/Kbuild
new file mode 100644 (file)
index 0000000..ed30ea0
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for the pNFS Objects Layout Driver kernel module
+#
+objlayoutdriver-y := objio_osd.o pnfs_osd_xdr_cli.o objlayout.o
+obj-$(CONFIG_PNFS_OBJLAYOUT) += objlayoutdriver.o
diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c
new file mode 100644 (file)
index 0000000..8ff2ea3
--- /dev/null
@@ -0,0 +1,1059 @@
+/*
+ *  pNFS Objects layout implementation over open-osd initiator library
+ *
+ *  Copyright (C) 2009 Panasas Inc. [year of first publication]
+ *  All rights reserved.
+ *
+ *  Benny Halevy <bhalevy@panasas.com>
+ *  Boaz Harrosh <bharrosh@panasas.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  See the file COPYING included with this distribution for more details.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the Panasas company nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <scsi/osd_initiator.h>
+
+#include "objlayout.h"
+
+#define NFSDBG_FACILITY         NFSDBG_PNFS_LD
+
+#define _LLU(x) ((unsigned long long)x)
+
+enum { BIO_MAX_PAGES_KMALLOC =
+               (PAGE_SIZE - sizeof(struct bio)) / sizeof(struct bio_vec),
+};
+
+struct objio_dev_ent {
+       struct nfs4_deviceid_node id_node;
+       struct osd_dev *od;
+};
+
+static void
+objio_free_deviceid_node(struct nfs4_deviceid_node *d)
+{
+       struct objio_dev_ent *de = container_of(d, struct objio_dev_ent, id_node);
+
+       dprintk("%s: free od=%p\n", __func__, de->od);
+       osduld_put_device(de->od);
+       kfree(de);
+}
+
+static struct objio_dev_ent *_dev_list_find(const struct nfs_server *nfss,
+       const struct nfs4_deviceid *d_id)
+{
+       struct nfs4_deviceid_node *d;
+       struct objio_dev_ent *de;
+
+       d = nfs4_find_get_deviceid(nfss->pnfs_curr_ld, nfss->nfs_client, d_id);
+       if (!d)
+               return NULL;
+
+       de = container_of(d, struct objio_dev_ent, id_node);
+       return de;
+}
+
+static struct objio_dev_ent *
+_dev_list_add(const struct nfs_server *nfss,
+       const struct nfs4_deviceid *d_id, struct osd_dev *od,
+       gfp_t gfp_flags)
+{
+       struct nfs4_deviceid_node *d;
+       struct objio_dev_ent *de = kzalloc(sizeof(*de), gfp_flags);
+       struct objio_dev_ent *n;
+
+       if (!de) {
+               dprintk("%s: -ENOMEM od=%p\n", __func__, od);
+               return NULL;
+       }
+
+       dprintk("%s: Adding od=%p\n", __func__, od);
+       nfs4_init_deviceid_node(&de->id_node,
+                               nfss->pnfs_curr_ld,
+                               nfss->nfs_client,
+                               d_id);
+       de->od = od;
+
+       d = nfs4_insert_deviceid_node(&de->id_node);
+       n = container_of(d, struct objio_dev_ent, id_node);
+       if (n != de) {
+               dprintk("%s: Race with other n->od=%p\n", __func__, n->od);
+               objio_free_deviceid_node(&de->id_node);
+               de = n;
+       }
+
+       return de;
+}
+
+struct caps_buffers {
+       u8 caps_key[OSD_CRYPTO_KEYID_SIZE];
+       u8 creds[OSD_CAP_LEN];
+};
+
+struct objio_segment {
+       struct pnfs_layout_segment lseg;
+
+       struct pnfs_osd_object_cred *comps;
+
+       unsigned mirrors_p1;
+       unsigned stripe_unit;
+       unsigned group_width;   /* Data stripe_units without integrity comps */
+       u64 group_depth;
+       unsigned group_count;
+
+       unsigned max_io_size;
+
+       unsigned comps_index;
+       unsigned num_comps;
+       /* variable length */
+       struct objio_dev_ent *ods[];
+};
+
+static inline struct objio_segment *
+OBJIO_LSEG(struct pnfs_layout_segment *lseg)
+{
+       return container_of(lseg, struct objio_segment, lseg);
+}
+
+struct objio_state;
+typedef ssize_t (*objio_done_fn)(struct objio_state *ios);
+
+struct objio_state {
+       /* Generic layer */
+       struct objlayout_io_state ol_state;
+
+       struct objio_segment *layout;
+
+       struct kref kref;
+       objio_done_fn done;
+       void *private;
+
+       unsigned long length;
+       unsigned numdevs; /* Actually used devs in this IO */
+       /* A per-device variable array of size numdevs */
+       struct _objio_per_comp {
+               struct bio *bio;
+               struct osd_request *or;
+               unsigned long length;
+               u64 offset;
+               unsigned dev;
+       } per_dev[];
+};
+
+/* Send and wait for a get_device_info of devices in the layout,
+   then look them up with the osd_initiator library */
+static struct objio_dev_ent *_device_lookup(struct pnfs_layout_hdr *pnfslay,
+                               struct objio_segment *objio_seg, unsigned comp,
+                               gfp_t gfp_flags)
+{
+       struct pnfs_osd_deviceaddr *deviceaddr;
+       struct nfs4_deviceid *d_id;
+       struct objio_dev_ent *ode;
+       struct osd_dev *od;
+       struct osd_dev_info odi;
+       int err;
+
+       d_id = &objio_seg->comps[comp].oc_object_id.oid_device_id;
+
+       ode = _dev_list_find(NFS_SERVER(pnfslay->plh_inode), d_id);
+       if (ode)
+               return ode;
+
+       err = objlayout_get_deviceinfo(pnfslay, d_id, &deviceaddr, gfp_flags);
+       if (unlikely(err)) {
+               dprintk("%s: objlayout_get_deviceinfo dev(%llx:%llx) =>%d\n",
+                       __func__, _DEVID_LO(d_id), _DEVID_HI(d_id), err);
+               return ERR_PTR(err);
+       }
+
+       odi.systemid_len = deviceaddr->oda_systemid.len;
+       if (odi.systemid_len > sizeof(odi.systemid)) {
+               err = -EINVAL;
+               goto out;
+       } else if (odi.systemid_len)
+               memcpy(odi.systemid, deviceaddr->oda_systemid.data,
+                      odi.systemid_len);
+       odi.osdname_len  = deviceaddr->oda_osdname.len;
+       odi.osdname      = (u8 *)deviceaddr->oda_osdname.data;
+
+       if (!odi.osdname_len && !odi.systemid_len) {
+               dprintk("%s: !odi.osdname_len && !odi.systemid_len\n",
+                       __func__);
+               err = -ENODEV;
+               goto out;
+       }
+
+       od = osduld_info_lookup(&odi);
+       if (unlikely(IS_ERR(od))) {
+               err = PTR_ERR(od);
+               dprintk("%s: osduld_info_lookup => %d\n", __func__, err);
+               goto out;
+       }
+
+       ode = _dev_list_add(NFS_SERVER(pnfslay->plh_inode), d_id, od,
+                           gfp_flags);
+
+out:
+       dprintk("%s: return=%d\n", __func__, err);
+       objlayout_put_deviceinfo(deviceaddr);
+       return err ? ERR_PTR(err) : ode;
+}
+
+static int objio_devices_lookup(struct pnfs_layout_hdr *pnfslay,
+       struct objio_segment *objio_seg,
+       gfp_t gfp_flags)
+{
+       unsigned i;
+       int err;
+
+       /* lookup all devices */
+       for (i = 0; i < objio_seg->num_comps; i++) {
+               struct objio_dev_ent *ode;
+
+               ode = _device_lookup(pnfslay, objio_seg, i, gfp_flags);
+               if (unlikely(IS_ERR(ode))) {
+                       err = PTR_ERR(ode);
+                       goto out;
+               }
+               objio_seg->ods[i] = ode;
+       }
+       err = 0;
+
+out:
+       dprintk("%s: return=%d\n", __func__, err);
+       return err;
+}
+
+static int _verify_data_map(struct pnfs_osd_layout *layout)
+{
+       struct pnfs_osd_data_map *data_map = &layout->olo_map;
+       u64 stripe_length;
+       u32 group_width;
+
+/* FIXME: Only raid0 for now. if not go through MDS */
+       if (data_map->odm_raid_algorithm != PNFS_OSD_RAID_0) {
+               printk(KERN_ERR "Only RAID_0 for now\n");
+               return -ENOTSUPP;
+       }
+       if (0 != (data_map->odm_num_comps % (data_map->odm_mirror_cnt + 1))) {
+               printk(KERN_ERR "Data Map wrong, num_comps=%u mirrors=%u\n",
+                         data_map->odm_num_comps, data_map->odm_mirror_cnt);
+               return -EINVAL;
+       }
+
+       if (data_map->odm_group_width)
+               group_width = data_map->odm_group_width;
+       else
+               group_width = data_map->odm_num_comps /
+                                               (data_map->odm_mirror_cnt + 1);
+
+       stripe_length = (u64)data_map->odm_stripe_unit * group_width;
+       if (stripe_length >= (1ULL << 32)) {
+               printk(KERN_ERR "Total Stripe length(0x%llx)"
+                         " >= 32bit is not supported\n", _LLU(stripe_length));
+               return -ENOTSUPP;
+       }
+
+       if (0 != (data_map->odm_stripe_unit & ~PAGE_MASK)) {
+               printk(KERN_ERR "Stripe Unit(0x%llx)"
+                         " must be Multples of PAGE_SIZE(0x%lx)\n",
+                         _LLU(data_map->odm_stripe_unit), PAGE_SIZE);
+               return -ENOTSUPP;
+       }
+
+       return 0;
+}
+
+static void copy_single_comp(struct pnfs_osd_object_cred *cur_comp,
+                            struct pnfs_osd_object_cred *src_comp,
+                            struct caps_buffers *caps_p)
+{
+       WARN_ON(src_comp->oc_cap_key.cred_len > sizeof(caps_p->caps_key));
+       WARN_ON(src_comp->oc_cap.cred_len > sizeof(caps_p->creds));
+
+       *cur_comp = *src_comp;
+
+       memcpy(caps_p->caps_key, src_comp->oc_cap_key.cred,
+              sizeof(caps_p->caps_key));
+       cur_comp->oc_cap_key.cred = caps_p->caps_key;
+
+       memcpy(caps_p->creds, src_comp->oc_cap.cred,
+              sizeof(caps_p->creds));
+       cur_comp->oc_cap.cred = caps_p->creds;
+}
+
+int objio_alloc_lseg(struct pnfs_layout_segment **outp,
+       struct pnfs_layout_hdr *pnfslay,
+       struct pnfs_layout_range *range,
+       struct xdr_stream *xdr,
+       gfp_t gfp_flags)
+{
+       struct objio_segment *objio_seg;
+       struct pnfs_osd_xdr_decode_layout_iter iter;
+       struct pnfs_osd_layout layout;
+       struct pnfs_osd_object_cred *cur_comp, src_comp;
+       struct caps_buffers *caps_p;
+       int err;
+
+       err = pnfs_osd_xdr_decode_layout_map(&layout, &iter, xdr);
+       if (unlikely(err))
+               return err;
+
+       err = _verify_data_map(&layout);
+       if (unlikely(err))
+               return err;
+
+       objio_seg = kzalloc(sizeof(*objio_seg) +
+                           sizeof(objio_seg->ods[0]) * layout.olo_num_comps +
+                           sizeof(*objio_seg->comps) * layout.olo_num_comps +
+                           sizeof(struct caps_buffers) * layout.olo_num_comps,
+                           gfp_flags);
+       if (!objio_seg)
+               return -ENOMEM;
+
+       objio_seg->comps = (void *)(objio_seg->ods + layout.olo_num_comps);
+       cur_comp = objio_seg->comps;
+       caps_p = (void *)(cur_comp + layout.olo_num_comps);
+       while (pnfs_osd_xdr_decode_layout_comp(&src_comp, &iter, xdr, &err))
+               copy_single_comp(cur_comp++, &src_comp, caps_p++);
+       if (unlikely(err))
+               goto err;
+
+       objio_seg->num_comps = layout.olo_num_comps;
+       objio_seg->comps_index = layout.olo_comps_index;
+       err = objio_devices_lookup(pnfslay, objio_seg, gfp_flags);
+       if (err)
+               goto err;
+
+       objio_seg->mirrors_p1 = layout.olo_map.odm_mirror_cnt + 1;
+       objio_seg->stripe_unit = layout.olo_map.odm_stripe_unit;
+       if (layout.olo_map.odm_group_width) {
+               objio_seg->group_width = layout.olo_map.odm_group_width;
+               objio_seg->group_depth = layout.olo_map.odm_group_depth;
+               objio_seg->group_count = layout.olo_map.odm_num_comps /
+                                               objio_seg->mirrors_p1 /
+                                               objio_seg->group_width;
+       } else {
+               objio_seg->group_width = layout.olo_map.odm_num_comps /
+                                               objio_seg->mirrors_p1;
+               objio_seg->group_depth = -1;
+               objio_seg->group_count = 1;
+       }
+
+       /* Cache this calculation it will hit for every page */
+       objio_seg->max_io_size = (BIO_MAX_PAGES_KMALLOC * PAGE_SIZE -
+                                 objio_seg->stripe_unit) *
+                                objio_seg->group_width;
+
+       *outp = &objio_seg->lseg;
+       return 0;
+
+err:
+       kfree(objio_seg);
+       dprintk("%s: Error: return %d\n", __func__, err);
+       *outp = NULL;
+       return err;
+}
+
+void objio_free_lseg(struct pnfs_layout_segment *lseg)
+{
+       int i;
+       struct objio_segment *objio_seg = OBJIO_LSEG(lseg);
+
+       for (i = 0; i < objio_seg->num_comps; i++) {
+               if (!objio_seg->ods[i])
+                       break;
+               nfs4_put_deviceid_node(&objio_seg->ods[i]->id_node);
+       }
+       kfree(objio_seg);
+}
+
+int objio_alloc_io_state(struct pnfs_layout_segment *lseg,
+                        struct objlayout_io_state **outp,
+                        gfp_t gfp_flags)
+{
+       struct objio_segment *objio_seg = OBJIO_LSEG(lseg);
+       struct objio_state *ios;
+       const unsigned first_size = sizeof(*ios) +
+                               objio_seg->num_comps * sizeof(ios->per_dev[0]);
+       const unsigned sec_size = objio_seg->num_comps *
+                                               sizeof(ios->ol_state.ioerrs[0]);
+
+       ios = kzalloc(first_size + sec_size, gfp_flags);
+       if (unlikely(!ios))
+               return -ENOMEM;
+
+       ios->layout = objio_seg;
+       ios->ol_state.ioerrs = ((void *)ios) + first_size;
+       ios->ol_state.num_comps = objio_seg->num_comps;
+
+       *outp = &ios->ol_state;
+       return 0;
+}
+
+void objio_free_io_state(struct objlayout_io_state *ol_state)
+{
+       struct objio_state *ios = container_of(ol_state, struct objio_state,
+                                              ol_state);
+
+       kfree(ios);
+}
+
+enum pnfs_osd_errno osd_pri_2_pnfs_err(enum osd_err_priority oep)
+{
+       switch (oep) {
+       case OSD_ERR_PRI_NO_ERROR:
+               return (enum pnfs_osd_errno)0;
+
+       case OSD_ERR_PRI_CLEAR_PAGES:
+               BUG_ON(1);
+               return 0;
+
+       case OSD_ERR_PRI_RESOURCE:
+               return PNFS_OSD_ERR_RESOURCE;
+       case OSD_ERR_PRI_BAD_CRED:
+               return PNFS_OSD_ERR_BAD_CRED;
+       case OSD_ERR_PRI_NO_ACCESS:
+               return PNFS_OSD_ERR_NO_ACCESS;
+       case OSD_ERR_PRI_UNREACHABLE:
+               return PNFS_OSD_ERR_UNREACHABLE;
+       case OSD_ERR_PRI_NOT_FOUND:
+               return PNFS_OSD_ERR_NOT_FOUND;
+       case OSD_ERR_PRI_NO_SPACE:
+               return PNFS_OSD_ERR_NO_SPACE;
+       default:
+               WARN_ON(1);
+               /* fallthrough */
+       case OSD_ERR_PRI_EIO:
+               return PNFS_OSD_ERR_EIO;
+       }
+}
+
+static void _clear_bio(struct bio *bio)
+{
+       struct bio_vec *bv;
+       unsigned i;
+
+       __bio_for_each_segment(bv, bio, i, 0) {
+               unsigned this_count = bv->bv_len;
+
+               if (likely(PAGE_SIZE == this_count))
+                       clear_highpage(bv->bv_page);
+               else
+                       zero_user(bv->bv_page, bv->bv_offset, this_count);
+       }
+}
+
+static int _io_check(struct objio_state *ios, bool is_write)
+{
+       enum osd_err_priority oep = OSD_ERR_PRI_NO_ERROR;
+       int lin_ret = 0;
+       int i;
+
+       for (i = 0; i <  ios->numdevs; i++) {
+               struct osd_sense_info osi;
+               struct osd_request *or = ios->per_dev[i].or;
+               unsigned dev;
+               int ret;
+
+               if (!or)
+                       continue;
+
+               ret = osd_req_decode_sense(or, &osi);
+               if (likely(!ret))
+                       continue;
+
+               if (OSD_ERR_PRI_CLEAR_PAGES == osi.osd_err_pri) {
+                       /* start read offset passed endof file */
+                       BUG_ON(is_write);
+                       _clear_bio(ios->per_dev[i].bio);
+                       dprintk("%s: start read offset passed end of file "
+                               "offset=0x%llx, length=0x%lx\n", __func__,
+                               _LLU(ios->per_dev[i].offset),
+                               ios->per_dev[i].length);
+
+                       continue; /* we recovered */
+               }
+               dev = ios->per_dev[i].dev;
+               objlayout_io_set_result(&ios->ol_state, dev,
+                                       &ios->layout->comps[dev].oc_object_id,
+                                       osd_pri_2_pnfs_err(osi.osd_err_pri),
+                                       ios->per_dev[i].offset,
+                                       ios->per_dev[i].length,
+                                       is_write);
+
+               if (osi.osd_err_pri >= oep) {
+                       oep = osi.osd_err_pri;
+                       lin_ret = ret;
+               }
+       }
+
+       return lin_ret;
+}
+
+/*
+ * Common IO state helpers.
+ */
+static void _io_free(struct objio_state *ios)
+{
+       unsigned i;
+
+       for (i = 0; i < ios->numdevs; i++) {
+               struct _objio_per_comp *per_dev = &ios->per_dev[i];
+
+               if (per_dev->or) {
+                       osd_end_request(per_dev->or);
+                       per_dev->or = NULL;
+               }
+
+               if (per_dev->bio) {
+                       bio_put(per_dev->bio);
+                       per_dev->bio = NULL;
+               }
+       }
+}
+
+struct osd_dev *_io_od(struct objio_state *ios, unsigned dev)
+{
+       unsigned min_dev = ios->layout->comps_index;
+       unsigned max_dev = min_dev + ios->layout->num_comps;
+
+       BUG_ON(dev < min_dev || max_dev <= dev);
+       return ios->layout->ods[dev - min_dev]->od;
+}
+
+struct _striping_info {
+       u64 obj_offset;
+       u64 group_length;
+       unsigned dev;
+       unsigned unit_off;
+};
+
+static void _calc_stripe_info(struct objio_state *ios, u64 file_offset,
+                             struct _striping_info *si)
+{
+       u32     stripe_unit = ios->layout->stripe_unit;
+       u32     group_width = ios->layout->group_width;
+       u64     group_depth = ios->layout->group_depth;
+       u32     U = stripe_unit * group_width;
+
+       u64     T = U * group_depth;
+       u64     S = T * ios->layout->group_count;
+       u64     M = div64_u64(file_offset, S);
+
+       /*
+       G = (L - (M * S)) / T
+       H = (L - (M * S)) % T
+       */
+       u64     LmodU = file_offset - M * S;
+       u32     G = div64_u64(LmodU, T);
+       u64     H = LmodU - G * T;
+
+       u32     N = div_u64(H, U);
+
+       div_u64_rem(file_offset, stripe_unit, &si->unit_off);
+       si->obj_offset = si->unit_off + (N * stripe_unit) +
+                                 (M * group_depth * stripe_unit);
+
+       /* "H - (N * U)" is just "H % U" so it's bound to u32 */
+       si->dev = (u32)(H - (N * U)) / stripe_unit + G * group_width;
+       si->dev *= ios->layout->mirrors_p1;
+
+       si->group_length = T - H;
+}
+
+static int _add_stripe_unit(struct objio_state *ios,  unsigned *cur_pg,
+               unsigned pgbase, struct _objio_per_comp *per_dev, int cur_len,
+               gfp_t gfp_flags)
+{
+       unsigned pg = *cur_pg;
+       struct request_queue *q =
+                       osd_request_queue(_io_od(ios, per_dev->dev));
+
+       per_dev->length += cur_len;
+
+       if (per_dev->bio == NULL) {
+               unsigned stripes = ios->layout->num_comps /
+                                                    ios->layout->mirrors_p1;
+               unsigned pages_in_stripe = stripes *
+                                     (ios->layout->stripe_unit / PAGE_SIZE);
+               unsigned bio_size = (ios->ol_state.nr_pages + pages_in_stripe) /
+                                   stripes;
+
+               if (BIO_MAX_PAGES_KMALLOC < bio_size)
+                       bio_size = BIO_MAX_PAGES_KMALLOC;
+
+               per_dev->bio = bio_kmalloc(gfp_flags, bio_size);
+               if (unlikely(!per_dev->bio)) {
+                       dprintk("Faild to allocate BIO size=%u\n", bio_size);
+                       return -ENOMEM;
+               }
+       }
+
+       while (cur_len > 0) {
+               unsigned pglen = min_t(unsigned, PAGE_SIZE - pgbase, cur_len);
+               unsigned added_len;
+
+               BUG_ON(ios->ol_state.nr_pages <= pg);
+               cur_len -= pglen;
+
+               added_len = bio_add_pc_page(q, per_dev->bio,
+                                       ios->ol_state.pages[pg], pglen, pgbase);
+               if (unlikely(pglen != added_len))
+                       return -ENOMEM;
+               pgbase = 0;
+               ++pg;
+       }
+       BUG_ON(cur_len);
+
+       *cur_pg = pg;
+       return 0;
+}
+
+static int _prepare_one_group(struct objio_state *ios, u64 length,
+                             struct _striping_info *si, unsigned *last_pg,
+                             gfp_t gfp_flags)
+{
+       unsigned stripe_unit = ios->layout->stripe_unit;
+       unsigned mirrors_p1 = ios->layout->mirrors_p1;
+       unsigned devs_in_group = ios->layout->group_width * mirrors_p1;
+       unsigned dev = si->dev;
+       unsigned first_dev = dev - (dev % devs_in_group);
+       unsigned max_comp = ios->numdevs ? ios->numdevs - mirrors_p1 : 0;
+       unsigned cur_pg = *last_pg;
+       int ret = 0;
+
+       while (length) {
+               struct _objio_per_comp *per_dev = &ios->per_dev[dev];
+               unsigned cur_len, page_off = 0;
+
+               if (!per_dev->length) {
+                       per_dev->dev = dev;
+                       if (dev < si->dev) {
+                               per_dev->offset = si->obj_offset + stripe_unit -
+                                                                  si->unit_off;
+                               cur_len = stripe_unit;
+                       } else if (dev == si->dev) {
+                               per_dev->offset = si->obj_offset;
+                               cur_len = stripe_unit - si->unit_off;
+                               page_off = si->unit_off & ~PAGE_MASK;
+                               BUG_ON(page_off &&
+                                     (page_off != ios->ol_state.pgbase));
+                       } else { /* dev > si->dev */
+                               per_dev->offset = si->obj_offset - si->unit_off;
+                               cur_len = stripe_unit;
+                       }
+
+                       if (max_comp < dev)
+                               max_comp = dev;
+               } else {
+                       cur_len = stripe_unit;
+               }
+               if (cur_len >= length)
+                       cur_len = length;
+
+               ret = _add_stripe_unit(ios, &cur_pg, page_off , per_dev,
+                                      cur_len, gfp_flags);
+               if (unlikely(ret))
+                       goto out;
+
+               dev += mirrors_p1;
+               dev = (dev % devs_in_group) + first_dev;
+
+               length -= cur_len;
+               ios->length += cur_len;
+       }
+out:
+       ios->numdevs = max_comp + mirrors_p1;
+       *last_pg = cur_pg;
+       return ret;
+}
+
+static int _io_rw_pagelist(struct objio_state *ios, gfp_t gfp_flags)
+{
+       u64 length = ios->ol_state.count;
+       u64 offset = ios->ol_state.offset;
+       struct _striping_info si;
+       unsigned last_pg = 0;
+       int ret = 0;
+
+       while (length) {
+               _calc_stripe_info(ios, offset, &si);
+
+               if (length < si.group_length)
+                       si.group_length = length;
+
+               ret = _prepare_one_group(ios, si.group_length, &si, &last_pg, gfp_flags);
+               if (unlikely(ret))
+                       goto out;
+
+               offset += si.group_length;
+               length -= si.group_length;
+       }
+
+out:
+       if (!ios->length)
+               return ret;
+
+       return 0;
+}
+
+static ssize_t _sync_done(struct objio_state *ios)
+{
+       struct completion *waiting = ios->private;
+
+       complete(waiting);
+       return 0;
+}
+
+static void _last_io(struct kref *kref)
+{
+       struct objio_state *ios = container_of(kref, struct objio_state, kref);
+
+       ios->done(ios);
+}
+
+static void _done_io(struct osd_request *or, void *p)
+{
+       struct objio_state *ios = p;
+
+       kref_put(&ios->kref, _last_io);
+}
+
+static ssize_t _io_exec(struct objio_state *ios)
+{
+       DECLARE_COMPLETION_ONSTACK(wait);
+       ssize_t status = 0; /* sync status */
+       unsigned i;
+       objio_done_fn saved_done_fn = ios->done;
+       bool sync = ios->ol_state.sync;
+
+       if (sync) {
+               ios->done = _sync_done;
+               ios->private = &wait;
+       }
+
+       kref_init(&ios->kref);
+
+       for (i = 0; i < ios->numdevs; i++) {
+               struct osd_request *or = ios->per_dev[i].or;
+
+               if (!or)
+                       continue;
+
+               kref_get(&ios->kref);
+               osd_execute_request_async(or, _done_io, ios);
+       }
+
+       kref_put(&ios->kref, _last_io);
+
+       if (sync) {
+               wait_for_completion(&wait);
+               status = saved_done_fn(ios);
+       }
+
+       return status;
+}
+
+/*
+ * read
+ */
+static ssize_t _read_done(struct objio_state *ios)
+{
+       ssize_t status;
+       int ret = _io_check(ios, false);
+
+       _io_free(ios);
+
+       if (likely(!ret))
+               status = ios->length;
+       else
+               status = ret;
+
+       objlayout_read_done(&ios->ol_state, status, ios->ol_state.sync);
+       return status;
+}
+
+static int _read_mirrors(struct objio_state *ios, unsigned cur_comp)
+{
+       struct osd_request *or = NULL;
+       struct _objio_per_comp *per_dev = &ios->per_dev[cur_comp];
+       unsigned dev = per_dev->dev;
+       struct pnfs_osd_object_cred *cred =
+                       &ios->layout->comps[dev];
+       struct osd_obj_id obj = {
+               .partition = cred->oc_object_id.oid_partition_id,
+               .id = cred->oc_object_id.oid_object_id,
+       };
+       int ret;
+
+       or = osd_start_request(_io_od(ios, dev), GFP_KERNEL);
+       if (unlikely(!or)) {
+               ret = -ENOMEM;
+               goto err;
+       }
+       per_dev->or = or;
+
+       osd_req_read(or, &obj, per_dev->offset, per_dev->bio, per_dev->length);
+
+       ret = osd_finalize_request(or, 0, cred->oc_cap.cred, NULL);
+       if (ret) {
+               dprintk("%s: Faild to osd_finalize_request() => %d\n",
+                       __func__, ret);
+               goto err;
+       }
+
+       dprintk("%s:[%d] dev=%d obj=0x%llx start=0x%llx length=0x%lx\n",
+               __func__, cur_comp, dev, obj.id, _LLU(per_dev->offset),
+               per_dev->length);
+
+err:
+       return ret;
+}
+
+static ssize_t _read_exec(struct objio_state *ios)
+{
+       unsigned i;
+       int ret;
+
+       for (i = 0; i < ios->numdevs; i += ios->layout->mirrors_p1) {
+               if (!ios->per_dev[i].length)
+                       continue;
+               ret = _read_mirrors(ios, i);
+               if (unlikely(ret))
+                       goto err;
+       }
+
+       ios->done = _read_done;
+       return _io_exec(ios); /* In sync mode exec returns the io status */
+
+err:
+       _io_free(ios);
+       return ret;
+}
+
+ssize_t objio_read_pagelist(struct objlayout_io_state *ol_state)
+{
+       struct objio_state *ios = container_of(ol_state, struct objio_state,
+                                              ol_state);
+       int ret;
+
+       ret = _io_rw_pagelist(ios, GFP_KERNEL);
+       if (unlikely(ret))
+               return ret;
+
+       return _read_exec(ios);
+}
+
+/*
+ * write
+ */
+static ssize_t _write_done(struct objio_state *ios)
+{
+       ssize_t status;
+       int ret = _io_check(ios, true);
+
+       _io_free(ios);
+
+       if (likely(!ret)) {
+               /* FIXME: should be based on the OSD's persistence model
+                * See OSD2r05 Section 4.13 Data persistence model */
+               ios->ol_state.committed = NFS_FILE_SYNC;
+               status = ios->length;
+       } else {
+               status = ret;
+       }
+
+       objlayout_write_done(&ios->ol_state, status, ios->ol_state.sync);
+       return status;
+}
+
+static int _write_mirrors(struct objio_state *ios, unsigned cur_comp)
+{
+       struct _objio_per_comp *master_dev = &ios->per_dev[cur_comp];
+       unsigned dev = ios->per_dev[cur_comp].dev;
+       unsigned last_comp = cur_comp + ios->layout->mirrors_p1;
+       int ret;
+
+       for (; cur_comp < last_comp; ++cur_comp, ++dev) {
+               struct osd_request *or = NULL;
+               struct pnfs_osd_object_cred *cred =
+                                       &ios->layout->comps[dev];
+               struct osd_obj_id obj = {
+                       .partition = cred->oc_object_id.oid_partition_id,
+                       .id = cred->oc_object_id.oid_object_id,
+               };
+               struct _objio_per_comp *per_dev = &ios->per_dev[cur_comp];
+               struct bio *bio;
+
+               or = osd_start_request(_io_od(ios, dev), GFP_NOFS);
+               if (unlikely(!or)) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+               per_dev->or = or;
+
+               if (per_dev != master_dev) {
+                       bio = bio_kmalloc(GFP_NOFS,
+                                         master_dev->bio->bi_max_vecs);
+                       if (unlikely(!bio)) {
+                               dprintk("Faild to allocate BIO size=%u\n",
+                                       master_dev->bio->bi_max_vecs);
+                               ret = -ENOMEM;
+                               goto err;
+                       }
+
+                       __bio_clone(bio, master_dev->bio);
+                       bio->bi_bdev = NULL;
+                       bio->bi_next = NULL;
+                       per_dev->bio = bio;
+                       per_dev->dev = dev;
+                       per_dev->length = master_dev->length;
+                       per_dev->offset =  master_dev->offset;
+               } else {
+                       bio = master_dev->bio;
+                       bio->bi_rw |= REQ_WRITE;
+               }
+
+               osd_req_write(or, &obj, per_dev->offset, bio, per_dev->length);
+
+               ret = osd_finalize_request(or, 0, cred->oc_cap.cred, NULL);
+               if (ret) {
+                       dprintk("%s: Faild to osd_finalize_request() => %d\n",
+                               __func__, ret);
+                       goto err;
+               }
+
+               dprintk("%s:[%d] dev=%d obj=0x%llx start=0x%llx length=0x%lx\n",
+                       __func__, cur_comp, dev, obj.id, _LLU(per_dev->offset),
+                       per_dev->length);
+       }
+
+err:
+       return ret;
+}
+
+static ssize_t _write_exec(struct objio_state *ios)
+{
+       unsigned i;
+       int ret;
+
+       for (i = 0; i < ios->numdevs; i += ios->layout->mirrors_p1) {
+               if (!ios->per_dev[i].length)
+                       continue;
+               ret = _write_mirrors(ios, i);
+               if (unlikely(ret))
+                       goto err;
+       }
+
+       ios->done = _write_done;
+       return _io_exec(ios); /* In sync mode exec returns the io->status */
+
+err:
+       _io_free(ios);
+       return ret;
+}
+
+ssize_t objio_write_pagelist(struct objlayout_io_state *ol_state, bool stable)
+{
+       struct objio_state *ios = container_of(ol_state, struct objio_state,
+                                              ol_state);
+       int ret;
+
+       /* TODO: ios->stable = stable; */
+       ret = _io_rw_pagelist(ios, GFP_NOFS);
+       if (unlikely(ret))
+               return ret;
+
+       return _write_exec(ios);
+}
+
+static bool objio_pg_test(struct nfs_pageio_descriptor *pgio,
+                         struct nfs_page *prev, struct nfs_page *req)
+{
+       if (!pnfs_generic_pg_test(pgio, prev, req))
+               return false;
+
+       if (pgio->pg_lseg == NULL)
+               return true;
+
+       return pgio->pg_count + req->wb_bytes <=
+                       OBJIO_LSEG(pgio->pg_lseg)->max_io_size;
+}
+
+static struct pnfs_layoutdriver_type objlayout_type = {
+       .id = LAYOUT_OSD2_OBJECTS,
+       .name = "LAYOUT_OSD2_OBJECTS",
+       .flags                   = PNFS_LAYOUTRET_ON_SETATTR,
+
+       .alloc_layout_hdr        = objlayout_alloc_layout_hdr,
+       .free_layout_hdr         = objlayout_free_layout_hdr,
+
+       .alloc_lseg              = objlayout_alloc_lseg,
+       .free_lseg               = objlayout_free_lseg,
+
+       .read_pagelist           = objlayout_read_pagelist,
+       .write_pagelist          = objlayout_write_pagelist,
+       .pg_test                 = objio_pg_test,
+
+       .free_deviceid_node      = objio_free_deviceid_node,
+
+       .encode_layoutcommit     = objlayout_encode_layoutcommit,
+       .encode_layoutreturn     = objlayout_encode_layoutreturn,
+};
+
+MODULE_DESCRIPTION("pNFS Layout Driver for OSD2 objects");
+MODULE_AUTHOR("Benny Halevy <bhalevy@panasas.com>");
+MODULE_LICENSE("GPL");
+
+static int __init
+objlayout_init(void)
+{
+       int ret = pnfs_register_layoutdriver(&objlayout_type);
+
+       if (ret)
+               printk(KERN_INFO
+                       "%s: Registering OSD pNFS Layout Driver failed: error=%d\n",
+                       __func__, ret);
+       else
+               printk(KERN_INFO "%s: Registered OSD pNFS Layout Driver\n",
+                       __func__);
+       return ret;
+}
+
+static void __exit
+objlayout_exit(void)
+{
+       pnfs_unregister_layoutdriver(&objlayout_type);
+       printk(KERN_INFO "%s: Unregistered OSD pNFS Layout Driver\n",
+              __func__);
+}
+
+module_init(objlayout_init);
+module_exit(objlayout_exit);
diff --git a/fs/nfs/objlayout/objlayout.c b/fs/nfs/objlayout/objlayout.c
new file mode 100644 (file)
index 0000000..1d06f8e
--- /dev/null
@@ -0,0 +1,712 @@
+/*
+ *  pNFS Objects layout driver high level definitions
+ *
+ *  Copyright (C) 2007 Panasas Inc. [year of first publication]
+ *  All rights reserved.
+ *
+ *  Benny Halevy <bhalevy@panasas.com>
+ *  Boaz Harrosh <bharrosh@panasas.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  See the file COPYING included with this distribution for more details.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the Panasas company nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <scsi/osd_initiator.h>
+#include "objlayout.h"
+
+#define NFSDBG_FACILITY         NFSDBG_PNFS_LD
+/*
+ * Create a objlayout layout structure for the given inode and return it.
+ */
+struct pnfs_layout_hdr *
+objlayout_alloc_layout_hdr(struct inode *inode, gfp_t gfp_flags)
+{
+       struct objlayout *objlay;
+
+       objlay = kzalloc(sizeof(struct objlayout), gfp_flags);
+       if (objlay) {
+               spin_lock_init(&objlay->lock);
+               INIT_LIST_HEAD(&objlay->err_list);
+       }
+       dprintk("%s: Return %p\n", __func__, objlay);
+       return &objlay->pnfs_layout;
+}
+
+/*
+ * Free an objlayout layout structure
+ */
+void
+objlayout_free_layout_hdr(struct pnfs_layout_hdr *lo)
+{
+       struct objlayout *objlay = OBJLAYOUT(lo);
+
+       dprintk("%s: objlay %p\n", __func__, objlay);
+
+       WARN_ON(!list_empty(&objlay->err_list));
+       kfree(objlay);
+}
+
+/*
+ * Unmarshall layout and store it in pnfslay.
+ */
+struct pnfs_layout_segment *
+objlayout_alloc_lseg(struct pnfs_layout_hdr *pnfslay,
+                    struct nfs4_layoutget_res *lgr,
+                    gfp_t gfp_flags)
+{
+       int status = -ENOMEM;
+       struct xdr_stream stream;
+       struct xdr_buf buf = {
+               .pages =  lgr->layoutp->pages,
+               .page_len =  lgr->layoutp->len,
+               .buflen =  lgr->layoutp->len,
+               .len = lgr->layoutp->len,
+       };
+       struct page *scratch;
+       struct pnfs_layout_segment *lseg;
+
+       dprintk("%s: Begin pnfslay %p\n", __func__, pnfslay);
+
+       scratch = alloc_page(gfp_flags);
+       if (!scratch)
+               goto err_nofree;
+
+       xdr_init_decode(&stream, &buf, NULL);
+       xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
+
+       status = objio_alloc_lseg(&lseg, pnfslay, &lgr->range, &stream, gfp_flags);
+       if (unlikely(status)) {
+               dprintk("%s: objio_alloc_lseg Return err %d\n", __func__,
+                       status);
+               goto err;
+       }
+
+       __free_page(scratch);
+
+       dprintk("%s: Return %p\n", __func__, lseg);
+       return lseg;
+
+err:
+       __free_page(scratch);
+err_nofree:
+       dprintk("%s: Err Return=>%d\n", __func__, status);
+       return ERR_PTR(status);
+}
+
+/*
+ * Free a layout segement
+ */
+void
+objlayout_free_lseg(struct pnfs_layout_segment *lseg)
+{
+       dprintk("%s: freeing layout segment %p\n", __func__, lseg);
+
+       if (unlikely(!lseg))
+               return;
+
+       objio_free_lseg(lseg);
+}
+
+/*
+ * I/O Operations
+ */
+static inline u64
+end_offset(u64 start, u64 len)
+{
+       u64 end;
+
+       end = start + len;
+       return end >= start ? end : NFS4_MAX_UINT64;
+}
+
+/* last octet in a range */
+static inline u64
+last_byte_offset(u64 start, u64 len)
+{
+       u64 end;
+
+       BUG_ON(!len);
+       end = start + len;
+       return end > start ? end - 1 : NFS4_MAX_UINT64;
+}
+
+static struct objlayout_io_state *
+objlayout_alloc_io_state(struct pnfs_layout_hdr *pnfs_layout_type,
+                       struct page **pages,
+                       unsigned pgbase,
+                       loff_t offset,
+                       size_t count,
+                       struct pnfs_layout_segment *lseg,
+                       void *rpcdata,
+                       gfp_t gfp_flags)
+{
+       struct objlayout_io_state *state;
+       u64 lseg_end_offset;
+
+       dprintk("%s: allocating io_state\n", __func__);
+       if (objio_alloc_io_state(lseg, &state, gfp_flags))
+               return NULL;
+
+       BUG_ON(offset < lseg->pls_range.offset);
+       lseg_end_offset = end_offset(lseg->pls_range.offset,
+                                    lseg->pls_range.length);
+       BUG_ON(offset >= lseg_end_offset);
+       if (offset + count > lseg_end_offset) {
+               count = lseg->pls_range.length -
+                               (offset - lseg->pls_range.offset);
+               dprintk("%s: truncated count %Zd\n", __func__, count);
+       }
+
+       if (pgbase > PAGE_SIZE) {
+               pages += pgbase >> PAGE_SHIFT;
+               pgbase &= ~PAGE_MASK;
+       }
+
+       INIT_LIST_HEAD(&state->err_list);
+       state->lseg = lseg;
+       state->rpcdata = rpcdata;
+       state->pages = pages;
+       state->pgbase = pgbase;
+       state->nr_pages = (pgbase + count + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       state->offset = offset;
+       state->count = count;
+       state->sync = 0;
+
+       return state;
+}
+
+static void
+objlayout_free_io_state(struct objlayout_io_state *state)
+{
+       dprintk("%s: freeing io_state\n", __func__);
+       if (unlikely(!state))
+               return;
+
+       objio_free_io_state(state);
+}
+
+/*
+ * I/O done common code
+ */
+static void
+objlayout_iodone(struct objlayout_io_state *state)
+{
+       dprintk("%s: state %p status\n", __func__, state);
+
+       if (likely(state->status >= 0)) {
+               objlayout_free_io_state(state);
+       } else {
+               struct objlayout *objlay = OBJLAYOUT(state->lseg->pls_layout);
+
+               spin_lock(&objlay->lock);
+               objlay->delta_space_valid = OBJ_DSU_INVALID;
+               list_add(&objlay->err_list, &state->err_list);
+               spin_unlock(&objlay->lock);
+       }
+}
+
+/*
+ * objlayout_io_set_result - Set an osd_error code on a specific osd comp.
+ *
+ * The @index component IO failed (error returned from target). Register
+ * the error for later reporting at layout-return.
+ */
+void
+objlayout_io_set_result(struct objlayout_io_state *state, unsigned index,
+                       struct pnfs_osd_objid *pooid, int osd_error,
+                       u64 offset, u64 length, bool is_write)
+{
+       struct pnfs_osd_ioerr *ioerr = &state->ioerrs[index];
+
+       BUG_ON(index >= state->num_comps);
+       if (osd_error) {
+               ioerr->oer_component = *pooid;
+               ioerr->oer_comp_offset = offset;
+               ioerr->oer_comp_length = length;
+               ioerr->oer_iswrite = is_write;
+               ioerr->oer_errno = osd_error;
+
+               dprintk("%s: err[%d]: errno=%d is_write=%d dev(%llx:%llx) "
+                       "par=0x%llx obj=0x%llx offset=0x%llx length=0x%llx\n",
+                       __func__, index, ioerr->oer_errno,
+                       ioerr->oer_iswrite,
+                       _DEVID_LO(&ioerr->oer_component.oid_device_id),
+                       _DEVID_HI(&ioerr->oer_component.oid_device_id),
+                       ioerr->oer_component.oid_partition_id,
+                       ioerr->oer_component.oid_object_id,
+                       ioerr->oer_comp_offset,
+                       ioerr->oer_comp_length);
+       } else {
+               /* User need not call if no error is reported */
+               ioerr->oer_errno = 0;
+       }
+}
+
+/* Function scheduled on rpc workqueue to call ->nfs_readlist_complete().
+ * This is because the osd completion is called with ints-off from
+ * the block layer
+ */
+static void _rpc_read_complete(struct work_struct *work)
+{
+       struct rpc_task *task;
+       struct nfs_read_data *rdata;
+
+       dprintk("%s enter\n", __func__);
+       task = container_of(work, struct rpc_task, u.tk_work);
+       rdata = container_of(task, struct nfs_read_data, task);
+
+       pnfs_ld_read_done(rdata);
+}
+
+void
+objlayout_read_done(struct objlayout_io_state *state, ssize_t status, bool sync)
+{
+       int eof = state->eof;
+       struct nfs_read_data *rdata;
+
+       state->status = status;
+       dprintk("%s: Begin status=%zd eof=%d\n", __func__, status, eof);
+       rdata = state->rpcdata;
+       rdata->task.tk_status = status;
+       if (status >= 0) {
+               rdata->res.count = status;
+               rdata->res.eof = eof;
+       }
+       objlayout_iodone(state);
+       /* must not use state after this point */
+
+       if (sync)
+               pnfs_ld_read_done(rdata);
+       else {
+               INIT_WORK(&rdata->task.u.tk_work, _rpc_read_complete);
+               schedule_work(&rdata->task.u.tk_work);
+       }
+}
+
+/*
+ * Perform sync or async reads.
+ */
+enum pnfs_try_status
+objlayout_read_pagelist(struct nfs_read_data *rdata)
+{
+       loff_t offset = rdata->args.offset;
+       size_t count = rdata->args.count;
+       struct objlayout_io_state *state;
+       ssize_t status = 0;
+       loff_t eof;
+
+       dprintk("%s: Begin inode %p offset %llu count %d\n",
+               __func__, rdata->inode, offset, (int)count);
+
+       eof = i_size_read(rdata->inode);
+       if (unlikely(offset + count > eof)) {
+               if (offset >= eof) {
+                       status = 0;
+                       rdata->res.count = 0;
+                       rdata->res.eof = 1;
+                       goto out;
+               }
+               count = eof - offset;
+       }
+
+       state = objlayout_alloc_io_state(NFS_I(rdata->inode)->layout,
+                                        rdata->args.pages, rdata->args.pgbase,
+                                        offset, count,
+                                        rdata->lseg, rdata,
+                                        GFP_KERNEL);
+       if (unlikely(!state)) {
+               status = -ENOMEM;
+               goto out;
+       }
+
+       state->eof = state->offset + state->count >= eof;
+
+       status = objio_read_pagelist(state);
+ out:
+       dprintk("%s: Return status %Zd\n", __func__, status);
+       rdata->pnfs_error = status;
+       return PNFS_ATTEMPTED;
+}
+
+/* Function scheduled on rpc workqueue to call ->nfs_writelist_complete().
+ * This is because the osd completion is called with ints-off from
+ * the block layer
+ */
+static void _rpc_write_complete(struct work_struct *work)
+{
+       struct rpc_task *task;
+       struct nfs_write_data *wdata;
+
+       dprintk("%s enter\n", __func__);
+       task = container_of(work, struct rpc_task, u.tk_work);
+       wdata = container_of(task, struct nfs_write_data, task);
+
+       pnfs_ld_write_done(wdata);
+}
+
+void
+objlayout_write_done(struct objlayout_io_state *state, ssize_t status,
+                    bool sync)
+{
+       struct nfs_write_data *wdata;
+
+       dprintk("%s: Begin\n", __func__);
+       wdata = state->rpcdata;
+       state->status = status;
+       wdata->task.tk_status = status;
+       if (status >= 0) {
+               wdata->res.count = status;
+               wdata->verf.committed = state->committed;
+               dprintk("%s: Return status %d committed %d\n",
+                       __func__, wdata->task.tk_status,
+                       wdata->verf.committed);
+       } else
+               dprintk("%s: Return status %d\n",
+                       __func__, wdata->task.tk_status);
+       objlayout_iodone(state);
+       /* must not use state after this point */
+
+       if (sync)
+               pnfs_ld_write_done(wdata);
+       else {
+               INIT_WORK(&wdata->task.u.tk_work, _rpc_write_complete);
+               schedule_work(&wdata->task.u.tk_work);
+       }
+}
+
+/*
+ * Perform sync or async writes.
+ */
+enum pnfs_try_status
+objlayout_write_pagelist(struct nfs_write_data *wdata,
+                        int how)
+{
+       struct objlayout_io_state *state;
+       ssize_t status;
+
+       dprintk("%s: Begin inode %p offset %llu count %u\n",
+               __func__, wdata->inode, wdata->args.offset, wdata->args.count);
+
+       state = objlayout_alloc_io_state(NFS_I(wdata->inode)->layout,
+                                        wdata->args.pages,
+                                        wdata->args.pgbase,
+                                        wdata->args.offset,
+                                        wdata->args.count,
+                                        wdata->lseg, wdata,
+                                        GFP_NOFS);
+       if (unlikely(!state)) {
+               status = -ENOMEM;
+               goto out;
+       }
+
+       state->sync = how & FLUSH_SYNC;
+
+       status = objio_write_pagelist(state, how & FLUSH_STABLE);
+ out:
+       dprintk("%s: Return status %Zd\n", __func__, status);
+       wdata->pnfs_error = status;
+       return PNFS_ATTEMPTED;
+}
+
+void
+objlayout_encode_layoutcommit(struct pnfs_layout_hdr *pnfslay,
+                             struct xdr_stream *xdr,
+                             const struct nfs4_layoutcommit_args *args)
+{
+       struct objlayout *objlay = OBJLAYOUT(pnfslay);
+       struct pnfs_osd_layoutupdate lou;
+       __be32 *start;
+
+       dprintk("%s: Begin\n", __func__);
+
+       spin_lock(&objlay->lock);
+       lou.dsu_valid = (objlay->delta_space_valid == OBJ_DSU_VALID);
+       lou.dsu_delta = objlay->delta_space_used;
+       objlay->delta_space_used = 0;
+       objlay->delta_space_valid = OBJ_DSU_INIT;
+       lou.olu_ioerr_flag = !list_empty(&objlay->err_list);
+       spin_unlock(&objlay->lock);
+
+       start = xdr_reserve_space(xdr, 4);
+
+       BUG_ON(pnfs_osd_xdr_encode_layoutupdate(xdr, &lou));
+
+       *start = cpu_to_be32((xdr->p - start - 1) * 4);
+
+       dprintk("%s: Return delta_space_used %lld err %d\n", __func__,
+               lou.dsu_delta, lou.olu_ioerr_flag);
+}
+
+static int
+err_prio(u32 oer_errno)
+{
+       switch (oer_errno) {
+       case 0:
+               return 0;
+
+       case PNFS_OSD_ERR_RESOURCE:
+               return OSD_ERR_PRI_RESOURCE;
+       case PNFS_OSD_ERR_BAD_CRED:
+               return OSD_ERR_PRI_BAD_CRED;
+       case PNFS_OSD_ERR_NO_ACCESS:
+               return OSD_ERR_PRI_NO_ACCESS;
+       case PNFS_OSD_ERR_UNREACHABLE:
+               return OSD_ERR_PRI_UNREACHABLE;
+       case PNFS_OSD_ERR_NOT_FOUND:
+               return OSD_ERR_PRI_NOT_FOUND;
+       case PNFS_OSD_ERR_NO_SPACE:
+               return OSD_ERR_PRI_NO_SPACE;
+       default:
+               WARN_ON(1);
+               /* fallthrough */
+       case PNFS_OSD_ERR_EIO:
+               return OSD_ERR_PRI_EIO;
+       }
+}
+
+static void
+merge_ioerr(struct pnfs_osd_ioerr *dest_err,
+           const struct pnfs_osd_ioerr *src_err)
+{
+       u64 dest_end, src_end;
+
+       if (!dest_err->oer_errno) {
+               *dest_err = *src_err;
+               /* accumulated device must be blank */
+               memset(&dest_err->oer_component.oid_device_id, 0,
+                       sizeof(dest_err->oer_component.oid_device_id));
+
+               return;
+       }
+
+       if (dest_err->oer_component.oid_partition_id !=
+                               src_err->oer_component.oid_partition_id)
+               dest_err->oer_component.oid_partition_id = 0;
+
+       if (dest_err->oer_component.oid_object_id !=
+                               src_err->oer_component.oid_object_id)
+               dest_err->oer_component.oid_object_id = 0;
+
+       if (dest_err->oer_comp_offset > src_err->oer_comp_offset)
+               dest_err->oer_comp_offset = src_err->oer_comp_offset;
+
+       dest_end = end_offset(dest_err->oer_comp_offset,
+                             dest_err->oer_comp_length);
+       src_end =  end_offset(src_err->oer_comp_offset,
+                             src_err->oer_comp_length);
+       if (dest_end < src_end)
+               dest_end = src_end;
+
+       dest_err->oer_comp_length = dest_end - dest_err->oer_comp_offset;
+
+       if ((src_err->oer_iswrite == dest_err->oer_iswrite) &&
+           (err_prio(src_err->oer_errno) > err_prio(dest_err->oer_errno))) {
+                       dest_err->oer_errno = src_err->oer_errno;
+       } else if (src_err->oer_iswrite) {
+               dest_err->oer_iswrite = true;
+               dest_err->oer_errno = src_err->oer_errno;
+       }
+}
+
+static void
+encode_accumulated_error(struct objlayout *objlay, __be32 *p)
+{
+       struct objlayout_io_state *state, *tmp;
+       struct pnfs_osd_ioerr accumulated_err = {.oer_errno = 0};
+
+       list_for_each_entry_safe(state, tmp, &objlay->err_list, err_list) {
+               unsigned i;
+
+               for (i = 0; i < state->num_comps; i++) {
+                       struct pnfs_osd_ioerr *ioerr = &state->ioerrs[i];
+
+                       if (!ioerr->oer_errno)
+                               continue;
+
+                       printk(KERN_ERR "%s: err[%d]: errno=%d is_write=%d "
+                               "dev(%llx:%llx) par=0x%llx obj=0x%llx "
+                               "offset=0x%llx length=0x%llx\n",
+                               __func__, i, ioerr->oer_errno,
+                               ioerr->oer_iswrite,
+                               _DEVID_LO(&ioerr->oer_component.oid_device_id),
+                               _DEVID_HI(&ioerr->oer_component.oid_device_id),
+                               ioerr->oer_component.oid_partition_id,
+                               ioerr->oer_component.oid_object_id,
+                               ioerr->oer_comp_offset,
+                               ioerr->oer_comp_length);
+
+                       merge_ioerr(&accumulated_err, ioerr);
+               }
+               list_del(&state->err_list);
+               objlayout_free_io_state(state);
+       }
+
+       pnfs_osd_xdr_encode_ioerr(p, &accumulated_err);
+}
+
+void
+objlayout_encode_layoutreturn(struct pnfs_layout_hdr *pnfslay,
+                             struct xdr_stream *xdr,
+                             const struct nfs4_layoutreturn_args *args)
+{
+       struct objlayout *objlay = OBJLAYOUT(pnfslay);
+       struct objlayout_io_state *state, *tmp;
+       __be32 *start;
+
+       dprintk("%s: Begin\n", __func__);
+       start = xdr_reserve_space(xdr, 4);
+       BUG_ON(!start);
+
+       spin_lock(&objlay->lock);
+
+       list_for_each_entry_safe(state, tmp, &objlay->err_list, err_list) {
+               __be32 *last_xdr = NULL, *p;
+               unsigned i;
+               int res = 0;
+
+               for (i = 0; i < state->num_comps; i++) {
+                       struct pnfs_osd_ioerr *ioerr = &state->ioerrs[i];
+
+                       if (!ioerr->oer_errno)
+                               continue;
+
+                       dprintk("%s: err[%d]: errno=%d is_write=%d "
+                               "dev(%llx:%llx) par=0x%llx obj=0x%llx "
+                               "offset=0x%llx length=0x%llx\n",
+                               __func__, i, ioerr->oer_errno,
+                               ioerr->oer_iswrite,
+                               _DEVID_LO(&ioerr->oer_component.oid_device_id),
+                               _DEVID_HI(&ioerr->oer_component.oid_device_id),
+                               ioerr->oer_component.oid_partition_id,
+                               ioerr->oer_component.oid_object_id,
+                               ioerr->oer_comp_offset,
+                               ioerr->oer_comp_length);
+
+                       p = pnfs_osd_xdr_ioerr_reserve_space(xdr);
+                       if (unlikely(!p)) {
+                               res = -E2BIG;
+                               break; /* accumulated_error */
+                       }
+
+                       last_xdr = p;
+                       pnfs_osd_xdr_encode_ioerr(p, &state->ioerrs[i]);
+               }
+
+               /* TODO: use xdr_write_pages */
+               if (unlikely(res)) {
+                       /* no space for even one error descriptor */
+                       BUG_ON(!last_xdr);
+
+                       /* we've encountered a situation with lots and lots of
+                        * errors and no space to encode them all. Use the last
+                        * available slot to report the union of all the
+                        * remaining errors.
+                        */
+                       encode_accumulated_error(objlay, last_xdr);
+                       goto loop_done;
+               }
+               list_del(&state->err_list);
+               objlayout_free_io_state(state);
+       }
+loop_done:
+       spin_unlock(&objlay->lock);
+
+       *start = cpu_to_be32((xdr->p - start - 1) * 4);
+       dprintk("%s: Return\n", __func__);
+}
+
+
+/*
+ * Get Device Info API for io engines
+ */
+struct objlayout_deviceinfo {
+       struct page *page;
+       struct pnfs_osd_deviceaddr da; /* This must be last */
+};
+
+/* Initialize and call nfs_getdeviceinfo, then decode and return a
+ * "struct pnfs_osd_deviceaddr *" Eventually objlayout_put_deviceinfo()
+ * should be called.
+ */
+int objlayout_get_deviceinfo(struct pnfs_layout_hdr *pnfslay,
+       struct nfs4_deviceid *d_id, struct pnfs_osd_deviceaddr **deviceaddr,
+       gfp_t gfp_flags)
+{
+       struct objlayout_deviceinfo *odi;
+       struct pnfs_device pd;
+       struct super_block *sb;
+       struct page *page, **pages;
+       u32 *p;
+       int err;
+
+       page = alloc_page(gfp_flags);
+       if (!page)
+               return -ENOMEM;
+
+       pages = &page;
+       pd.pages = pages;
+
+       memcpy(&pd.dev_id, d_id, sizeof(*d_id));
+       pd.layout_type = LAYOUT_OSD2_OBJECTS;
+       pd.pages = &page;
+       pd.pgbase = 0;
+       pd.pglen = PAGE_SIZE;
+       pd.mincount = 0;
+
+       sb = pnfslay->plh_inode->i_sb;
+       err = nfs4_proc_getdeviceinfo(NFS_SERVER(pnfslay->plh_inode), &pd);
+       dprintk("%s nfs_getdeviceinfo returned %d\n", __func__, err);
+       if (err)
+               goto err_out;
+
+       p = page_address(page);
+       odi = kzalloc(sizeof(*odi), gfp_flags);
+       if (!odi) {
+               err = -ENOMEM;
+               goto err_out;
+       }
+       pnfs_osd_xdr_decode_deviceaddr(&odi->da, p);
+       odi->page = page;
+       *deviceaddr = &odi->da;
+       return 0;
+
+err_out:
+       __free_page(page);
+       return err;
+}
+
+void objlayout_put_deviceinfo(struct pnfs_osd_deviceaddr *deviceaddr)
+{
+       struct objlayout_deviceinfo *odi = container_of(deviceaddr,
+                                               struct objlayout_deviceinfo,
+                                               da);
+
+       __free_page(odi->page);
+       kfree(odi);
+}
diff --git a/fs/nfs/objlayout/objlayout.h b/fs/nfs/objlayout/objlayout.h
new file mode 100644 (file)
index 0000000..a8244c8
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ *  Data types and function declerations for interfacing with the
+ *  pNFS standard object layout driver.
+ *
+ *  Copyright (C) 2007 Panasas Inc. [year of first publication]
+ *  All rights reserved.
+ *
+ *  Benny Halevy <bhalevy@panasas.com>
+ *  Boaz Harrosh <bharrosh@panasas.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  See the file COPYING included with this distribution for more details.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the Panasas company nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _OBJLAYOUT_H
+#define _OBJLAYOUT_H
+
+#include <linux/nfs_fs.h>
+#include <linux/pnfs_osd_xdr.h>
+#include "../pnfs.h"
+
+/*
+ * per-inode layout
+ */
+struct objlayout {
+       struct pnfs_layout_hdr pnfs_layout;
+
+        /* for layout_commit */
+       enum osd_delta_space_valid_enum {
+               OBJ_DSU_INIT = 0,
+               OBJ_DSU_VALID,
+               OBJ_DSU_INVALID,
+       } delta_space_valid;
+       s64 delta_space_used;  /* consumed by write ops */
+
+        /* for layout_return */
+       spinlock_t lock;
+       struct list_head err_list;
+};
+
+static inline struct objlayout *
+OBJLAYOUT(struct pnfs_layout_hdr *lo)
+{
+       return container_of(lo, struct objlayout, pnfs_layout);
+}
+
+/*
+ * per-I/O operation state
+ * embedded in objects provider io_state data structure
+ */
+struct objlayout_io_state {
+       struct pnfs_layout_segment *lseg;
+
+       struct page **pages;
+       unsigned pgbase;
+       unsigned nr_pages;
+       unsigned long count;
+       loff_t offset;
+       bool sync;
+
+       void *rpcdata;
+       int status;             /* res */
+       int eof;                /* res */
+       int committed;          /* res */
+
+       /* Error reporting (layout_return) */
+       struct list_head err_list;
+       unsigned num_comps;
+       /* Pointer to array of error descriptors of size num_comps.
+        * It should contain as many entries as devices in the osd_layout
+        * that participate in the I/O. It is up to the io_engine to allocate
+        * needed space and set num_comps.
+        */
+       struct pnfs_osd_ioerr *ioerrs;
+};
+
+/*
+ * Raid engine I/O API
+ */
+extern int objio_alloc_lseg(struct pnfs_layout_segment **outp,
+       struct pnfs_layout_hdr *pnfslay,
+       struct pnfs_layout_range *range,
+       struct xdr_stream *xdr,
+       gfp_t gfp_flags);
+extern void objio_free_lseg(struct pnfs_layout_segment *lseg);
+
+extern int objio_alloc_io_state(
+       struct pnfs_layout_segment *lseg,
+       struct objlayout_io_state **outp,
+       gfp_t gfp_flags);
+extern void objio_free_io_state(struct objlayout_io_state *state);
+
+extern ssize_t objio_read_pagelist(struct objlayout_io_state *ol_state);
+extern ssize_t objio_write_pagelist(struct objlayout_io_state *ol_state,
+                                   bool stable);
+
+/*
+ * callback API
+ */
+extern void objlayout_io_set_result(struct objlayout_io_state *state,
+                       unsigned index, struct pnfs_osd_objid *pooid,
+                       int osd_error, u64 offset, u64 length, bool is_write);
+
+static inline void
+objlayout_add_delta_space_used(struct objlayout_io_state *state, s64 space_used)
+{
+       struct objlayout *objlay = OBJLAYOUT(state->lseg->pls_layout);
+
+       /* If one of the I/Os errored out and the delta_space_used was
+        * invalid we render the complete report as invalid. Protocol mandate
+        * the DSU be accurate or not reported.
+        */
+       spin_lock(&objlay->lock);
+       if (objlay->delta_space_valid != OBJ_DSU_INVALID) {
+               objlay->delta_space_valid = OBJ_DSU_VALID;
+               objlay->delta_space_used += space_used;
+       }
+       spin_unlock(&objlay->lock);
+}
+
+extern void objlayout_read_done(struct objlayout_io_state *state,
+                               ssize_t status, bool sync);
+extern void objlayout_write_done(struct objlayout_io_state *state,
+                                ssize_t status, bool sync);
+
+extern int objlayout_get_deviceinfo(struct pnfs_layout_hdr *pnfslay,
+       struct nfs4_deviceid *d_id, struct pnfs_osd_deviceaddr **deviceaddr,
+       gfp_t gfp_flags);
+extern void objlayout_put_deviceinfo(struct pnfs_osd_deviceaddr *deviceaddr);
+
+/*
+ * exported generic objects function vectors
+ */
+
+extern struct pnfs_layout_hdr *objlayout_alloc_layout_hdr(struct inode *, gfp_t gfp_flags);
+extern void objlayout_free_layout_hdr(struct pnfs_layout_hdr *);
+
+extern struct pnfs_layout_segment *objlayout_alloc_lseg(
+       struct pnfs_layout_hdr *,
+       struct nfs4_layoutget_res *,
+       gfp_t gfp_flags);
+extern void objlayout_free_lseg(struct pnfs_layout_segment *);
+
+extern enum pnfs_try_status objlayout_read_pagelist(
+       struct nfs_read_data *);
+
+extern enum pnfs_try_status objlayout_write_pagelist(
+       struct nfs_write_data *,
+       int how);
+
+extern void objlayout_encode_layoutcommit(
+       struct pnfs_layout_hdr *,
+       struct xdr_stream *,
+       const struct nfs4_layoutcommit_args *);
+
+extern void objlayout_encode_layoutreturn(
+       struct pnfs_layout_hdr *,
+       struct xdr_stream *,
+       const struct nfs4_layoutreturn_args *);
+
+#endif /* _OBJLAYOUT_H */
diff --git a/fs/nfs/objlayout/pnfs_osd_xdr_cli.c b/fs/nfs/objlayout/pnfs_osd_xdr_cli.c
new file mode 100644 (file)
index 0000000..16fc758
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ *  Object-Based pNFS Layout XDR layer
+ *
+ *  Copyright (C) 2007 Panasas Inc. [year of first publication]
+ *  All rights reserved.
+ *
+ *  Benny Halevy <bhalevy@panasas.com>
+ *  Boaz Harrosh <bharrosh@panasas.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  See the file COPYING included with this distribution for more details.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the Panasas company nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/pnfs_osd_xdr.h>
+
+#define NFSDBG_FACILITY         NFSDBG_PNFS_LD
+
+/*
+ * The following implementation is based on RFC5664
+ */
+
+/*
+ * struct pnfs_osd_objid {
+ *     struct nfs4_deviceid    oid_device_id;
+ *     u64                     oid_partition_id;
+ *     u64                     oid_object_id;
+ * }; // xdr size 32 bytes
+ */
+static __be32 *
+_osd_xdr_decode_objid(__be32 *p, struct pnfs_osd_objid *objid)
+{
+       p = xdr_decode_opaque_fixed(p, objid->oid_device_id.data,
+                                   sizeof(objid->oid_device_id.data));
+
+       p = xdr_decode_hyper(p, &objid->oid_partition_id);
+       p = xdr_decode_hyper(p, &objid->oid_object_id);
+       return p;
+}
+/*
+ * struct pnfs_osd_opaque_cred {
+ *     u32 cred_len;
+ *     void *cred;
+ * }; // xdr size [variable]
+ * The return pointers are from the xdr buffer
+ */
+static int
+_osd_xdr_decode_opaque_cred(struct pnfs_osd_opaque_cred *opaque_cred,
+                           struct xdr_stream *xdr)
+{
+       __be32 *p = xdr_inline_decode(xdr, 1);
+
+       if (!p)
+               return -EINVAL;
+
+       opaque_cred->cred_len = be32_to_cpu(*p++);
+
+       p = xdr_inline_decode(xdr, opaque_cred->cred_len);
+       if (!p)
+               return -EINVAL;
+
+       opaque_cred->cred = p;
+       return 0;
+}
+
+/*
+ * struct pnfs_osd_object_cred {
+ *     struct pnfs_osd_objid           oc_object_id;
+ *     u32                             oc_osd_version;
+ *     u32                             oc_cap_key_sec;
+ *     struct pnfs_osd_opaque_cred     oc_cap_key
+ *     struct pnfs_osd_opaque_cred     oc_cap;
+ * }; // xdr size 32 + 4 + 4 + [variable] + [variable]
+ */
+static int
+_osd_xdr_decode_object_cred(struct pnfs_osd_object_cred *comp,
+                           struct xdr_stream *xdr)
+{
+       __be32 *p = xdr_inline_decode(xdr, 32 + 4 + 4);
+       int ret;
+
+       if (!p)
+               return -EIO;
+
+       p = _osd_xdr_decode_objid(p, &comp->oc_object_id);
+       comp->oc_osd_version = be32_to_cpup(p++);
+       comp->oc_cap_key_sec = be32_to_cpup(p);
+
+       ret = _osd_xdr_decode_opaque_cred(&comp->oc_cap_key, xdr);
+       if (unlikely(ret))
+               return ret;
+
+       ret = _osd_xdr_decode_opaque_cred(&comp->oc_cap, xdr);
+       return ret;
+}
+
+/*
+ * struct pnfs_osd_data_map {
+ *     u32     odm_num_comps;
+ *     u64     odm_stripe_unit;
+ *     u32     odm_group_width;
+ *     u32     odm_group_depth;
+ *     u32     odm_mirror_cnt;
+ *     u32     odm_raid_algorithm;
+ * }; // xdr size 4 + 8 + 4 + 4 + 4 + 4
+ */
+static inline int
+_osd_data_map_xdr_sz(void)
+{
+       return 4 + 8 + 4 + 4 + 4 + 4;
+}
+
+static __be32 *
+_osd_xdr_decode_data_map(__be32 *p, struct pnfs_osd_data_map *data_map)
+{
+       data_map->odm_num_comps = be32_to_cpup(p++);
+       p = xdr_decode_hyper(p, &data_map->odm_stripe_unit);
+       data_map->odm_group_width = be32_to_cpup(p++);
+       data_map->odm_group_depth = be32_to_cpup(p++);
+       data_map->odm_mirror_cnt = be32_to_cpup(p++);
+       data_map->odm_raid_algorithm = be32_to_cpup(p++);
+       dprintk("%s: odm_num_comps=%u odm_stripe_unit=%llu odm_group_width=%u "
+               "odm_group_depth=%u odm_mirror_cnt=%u odm_raid_algorithm=%u\n",
+               __func__,
+               data_map->odm_num_comps,
+               (unsigned long long)data_map->odm_stripe_unit,
+               data_map->odm_group_width,
+               data_map->odm_group_depth,
+               data_map->odm_mirror_cnt,
+               data_map->odm_raid_algorithm);
+       return p;
+}
+
+int pnfs_osd_xdr_decode_layout_map(struct pnfs_osd_layout *layout,
+       struct pnfs_osd_xdr_decode_layout_iter *iter, struct xdr_stream *xdr)
+{
+       __be32 *p;
+
+       memset(iter, 0, sizeof(*iter));
+
+       p = xdr_inline_decode(xdr, _osd_data_map_xdr_sz() + 4 + 4);
+       if (unlikely(!p))
+               return -EINVAL;
+
+       p = _osd_xdr_decode_data_map(p, &layout->olo_map);
+       layout->olo_comps_index = be32_to_cpup(p++);
+       layout->olo_num_comps = be32_to_cpup(p++);
+       iter->total_comps = layout->olo_num_comps;
+       return 0;
+}
+
+bool pnfs_osd_xdr_decode_layout_comp(struct pnfs_osd_object_cred *comp,
+       struct pnfs_osd_xdr_decode_layout_iter *iter, struct xdr_stream *xdr,
+       int *err)
+{
+       BUG_ON(iter->decoded_comps > iter->total_comps);
+       if (iter->decoded_comps == iter->total_comps)
+               return false;
+
+       *err = _osd_xdr_decode_object_cred(comp, xdr);
+       if (unlikely(*err)) {
+               dprintk("%s: _osd_xdr_decode_object_cred=>%d decoded_comps=%d "
+                       "total_comps=%d\n", __func__, *err,
+                       iter->decoded_comps, iter->total_comps);
+               return false; /* stop the loop */
+       }
+       dprintk("%s: dev(%llx:%llx) par=0x%llx obj=0x%llx "
+               "key_len=%u cap_len=%u\n",
+               __func__,
+               _DEVID_LO(&comp->oc_object_id.oid_device_id),
+               _DEVID_HI(&comp->oc_object_id.oid_device_id),
+               comp->oc_object_id.oid_partition_id,
+               comp->oc_object_id.oid_object_id,
+               comp->oc_cap_key.cred_len, comp->oc_cap.cred_len);
+
+       iter->decoded_comps++;
+       return true;
+}
+
+/*
+ * Get Device Information Decoding
+ *
+ * Note: since Device Information is currently done synchronously, all
+ *       variable strings fields are left inside the rpc buffer and are only
+ *       pointed to by the pnfs_osd_deviceaddr members. So the read buffer
+ *       should not be freed while the returned information is in use.
+ */
+/*
+ *struct nfs4_string {
+ *     unsigned int len;
+ *     char *data;
+ *}; // size [variable]
+ * NOTE: Returned string points to inside the XDR buffer
+ */
+static __be32 *
+__read_u8_opaque(__be32 *p, struct nfs4_string *str)
+{
+       str->len = be32_to_cpup(p++);
+       str->data = (char *)p;
+
+       p += XDR_QUADLEN(str->len);
+       return p;
+}
+
+/*
+ * struct pnfs_osd_targetid {
+ *     u32                     oti_type;
+ *     struct nfs4_string      oti_scsi_device_id;
+ * };// size 4 + [variable]
+ */
+static __be32 *
+__read_targetid(__be32 *p, struct pnfs_osd_targetid* targetid)
+{
+       u32 oti_type;
+
+       oti_type = be32_to_cpup(p++);
+       targetid->oti_type = oti_type;
+
+       switch (oti_type) {
+       case OBJ_TARGET_SCSI_NAME:
+       case OBJ_TARGET_SCSI_DEVICE_ID:
+               p = __read_u8_opaque(p, &targetid->oti_scsi_device_id);
+       }
+
+       return p;
+}
+
+/*
+ * struct pnfs_osd_net_addr {
+ *     struct nfs4_string      r_netid;
+ *     struct nfs4_string      r_addr;
+ * };
+ */
+static __be32 *
+__read_net_addr(__be32 *p, struct pnfs_osd_net_addr* netaddr)
+{
+       p = __read_u8_opaque(p, &netaddr->r_netid);
+       p = __read_u8_opaque(p, &netaddr->r_addr);
+
+       return p;
+}
+
+/*
+ * struct pnfs_osd_targetaddr {
+ *     u32                             ota_available;
+ *     struct pnfs_osd_net_addr        ota_netaddr;
+ * };
+ */
+static __be32 *
+__read_targetaddr(__be32 *p, struct pnfs_osd_targetaddr *targetaddr)
+{
+       u32 ota_available;
+
+       ota_available = be32_to_cpup(p++);
+       targetaddr->ota_available = ota_available;
+
+       if (ota_available)
+               p = __read_net_addr(p, &targetaddr->ota_netaddr);
+
+
+       return p;
+}
+
+/*
+ * struct pnfs_osd_deviceaddr {
+ *     struct pnfs_osd_targetid        oda_targetid;
+ *     struct pnfs_osd_targetaddr      oda_targetaddr;
+ *     u8                              oda_lun[8];
+ *     struct nfs4_string              oda_systemid;
+ *     struct pnfs_osd_object_cred     oda_root_obj_cred;
+ *     struct nfs4_string              oda_osdname;
+ * };
+ */
+
+/* We need this version for the pnfs_osd_xdr_decode_deviceaddr which does
+ * not have an xdr_stream
+ */
+static __be32 *
+__read_opaque_cred(__be32 *p,
+                             struct pnfs_osd_opaque_cred *opaque_cred)
+{
+       opaque_cred->cred_len = be32_to_cpu(*p++);
+       opaque_cred->cred = p;
+       return p + XDR_QUADLEN(opaque_cred->cred_len);
+}
+
+static __be32 *
+__read_object_cred(__be32 *p, struct pnfs_osd_object_cred *comp)
+{
+       p = _osd_xdr_decode_objid(p, &comp->oc_object_id);
+       comp->oc_osd_version = be32_to_cpup(p++);
+       comp->oc_cap_key_sec = be32_to_cpup(p++);
+
+       p = __read_opaque_cred(p, &comp->oc_cap_key);
+       p = __read_opaque_cred(p, &comp->oc_cap);
+       return p;
+}
+
+void pnfs_osd_xdr_decode_deviceaddr(
+       struct pnfs_osd_deviceaddr *deviceaddr, __be32 *p)
+{
+       p = __read_targetid(p, &deviceaddr->oda_targetid);
+
+       p = __read_targetaddr(p, &deviceaddr->oda_targetaddr);
+
+       p = xdr_decode_opaque_fixed(p, deviceaddr->oda_lun,
+                                   sizeof(deviceaddr->oda_lun));
+
+       p = __read_u8_opaque(p, &deviceaddr->oda_systemid);
+
+       p = __read_object_cred(p, &deviceaddr->oda_root_obj_cred);
+
+       p = __read_u8_opaque(p, &deviceaddr->oda_osdname);
+
+       /* libosd likes this terminated in dbg. It's last, so no problems */
+       deviceaddr->oda_osdname.data[deviceaddr->oda_osdname.len] = 0;
+}
+
+/*
+ * struct pnfs_osd_layoutupdate {
+ *     u32     dsu_valid;
+ *     s64     dsu_delta;
+ *     u32     olu_ioerr_flag;
+ * }; xdr size 4 + 8 + 4
+ */
+int
+pnfs_osd_xdr_encode_layoutupdate(struct xdr_stream *xdr,
+                                struct pnfs_osd_layoutupdate *lou)
+{
+       __be32 *p = xdr_reserve_space(xdr,  4 + 8 + 4);
+
+       if (!p)
+               return -E2BIG;
+
+       *p++ = cpu_to_be32(lou->dsu_valid);
+       if (lou->dsu_valid)
+               p = xdr_encode_hyper(p, lou->dsu_delta);
+       *p++ = cpu_to_be32(lou->olu_ioerr_flag);
+       return 0;
+}
+
+/*
+ * struct pnfs_osd_objid {
+ *     struct nfs4_deviceid    oid_device_id;
+ *     u64                     oid_partition_id;
+ *     u64                     oid_object_id;
+ * }; // xdr size 32 bytes
+ */
+static inline __be32 *
+pnfs_osd_xdr_encode_objid(__be32 *p, struct pnfs_osd_objid *object_id)
+{
+       p = xdr_encode_opaque_fixed(p, &object_id->oid_device_id.data,
+                                   sizeof(object_id->oid_device_id.data));
+       p = xdr_encode_hyper(p, object_id->oid_partition_id);
+       p = xdr_encode_hyper(p, object_id->oid_object_id);
+
+       return p;
+}
+
+/*
+ * struct pnfs_osd_ioerr {
+ *     struct pnfs_osd_objid   oer_component;
+ *     u64                     oer_comp_offset;
+ *     u64                     oer_comp_length;
+ *     u32                     oer_iswrite;
+ *     u32                     oer_errno;
+ * }; // xdr size 32 + 24 bytes
+ */
+void pnfs_osd_xdr_encode_ioerr(__be32 *p, struct pnfs_osd_ioerr *ioerr)
+{
+       p = pnfs_osd_xdr_encode_objid(p, &ioerr->oer_component);
+       p = xdr_encode_hyper(p, ioerr->oer_comp_offset);
+       p = xdr_encode_hyper(p, ioerr->oer_comp_length);
+       *p++ = cpu_to_be32(ioerr->oer_iswrite);
+       *p   = cpu_to_be32(ioerr->oer_errno);
+}
+
+__be32 *pnfs_osd_xdr_ioerr_reserve_space(struct xdr_stream *xdr)
+{
+       __be32 *p;
+
+       p = xdr_reserve_space(xdr, 32 + 24);
+       if (unlikely(!p))
+               dprintk("%s: out of xdr space\n", __func__);
+
+       return p;
+}
index c80add6e2213ab6d4f301a2ca06134b4a4f5581c..009855716286bf098eba9ac20a6c04db201d3d06 100644 (file)
@@ -204,6 +204,22 @@ nfs_wait_on_request(struct nfs_page *req)
                        TASK_UNINTERRUPTIBLE);
 }
 
+bool nfs_generic_pg_test(struct nfs_pageio_descriptor *desc, struct nfs_page *prev, struct nfs_page *req)
+{
+       /*
+        * FIXME: ideally we should be able to coalesce all requests
+        * that are not block boundary aligned, but currently this
+        * is problematic for the case of bsize < PAGE_CACHE_SIZE,
+        * since nfs_flush_multi and nfs_pagein_multi assume you
+        * can have only one struct nfs_page.
+        */
+       if (desc->pg_bsize < PAGE_SIZE)
+               return 0;
+
+       return desc->pg_count + req->wb_bytes <= desc->pg_bsize;
+}
+EXPORT_SYMBOL_GPL(nfs_generic_pg_test);
+
 /**
  * nfs_pageio_init - initialise a page io descriptor
  * @desc: pointer to descriptor
@@ -229,6 +245,8 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
        desc->pg_ioflags = io_flags;
        desc->pg_error = 0;
        desc->pg_lseg = NULL;
+       desc->pg_test = nfs_generic_pg_test;
+       pnfs_pageio_init(desc, inode);
 }
 
 /**
@@ -242,29 +260,23 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
  *
  * Return 'true' if this is the case, else return 'false'.
  */
-static int nfs_can_coalesce_requests(struct nfs_page *prev,
-                                    struct nfs_page *req,
-                                    struct nfs_pageio_descriptor *pgio)
+static bool nfs_can_coalesce_requests(struct nfs_page *prev,
+                                     struct nfs_page *req,
+                                     struct nfs_pageio_descriptor *pgio)
 {
        if (req->wb_context->cred != prev->wb_context->cred)
-               return 0;
+               return false;
        if (req->wb_lock_context->lockowner != prev->wb_lock_context->lockowner)
-               return 0;
+               return false;
        if (req->wb_context->state != prev->wb_context->state)
-               return 0;
+               return false;
        if (req->wb_index != (prev->wb_index + 1))
-               return 0;
+               return false;
        if (req->wb_pgbase != 0)
-               return 0;
+               return false;
        if (prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE)
-               return 0;
-       /*
-        * Non-whole file layouts need to check that req is inside of
-        * pgio->pg_lseg.
-        */
-       if (pgio->pg_test && !pgio->pg_test(pgio, prev, req))
-               return 0;
-       return 1;
+               return false;
+       return pgio->pg_test(pgio, prev, req);
 }
 
 /**
@@ -278,31 +290,18 @@ static int nfs_can_coalesce_requests(struct nfs_page *prev,
 static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc,
                                     struct nfs_page *req)
 {
-       size_t newlen = req->wb_bytes;
-
        if (desc->pg_count != 0) {
                struct nfs_page *prev;
 
-               /*
-                * FIXME: ideally we should be able to coalesce all requests
-                * that are not block boundary aligned, but currently this
-                * is problematic for the case of bsize < PAGE_CACHE_SIZE,
-                * since nfs_flush_multi and nfs_pagein_multi assume you
-                * can have only one struct nfs_page.
-                */
-               if (desc->pg_bsize < PAGE_SIZE)
-                       return 0;
-               newlen += desc->pg_count;
-               if (newlen > desc->pg_bsize)
-                       return 0;
                prev = nfs_list_entry(desc->pg_list.prev);
                if (!nfs_can_coalesce_requests(prev, req, desc))
                        return 0;
-       } else
+       } else {
                desc->pg_base = req->wb_pgbase;
+       }
        nfs_list_remove_request(req);
        nfs_list_add_request(req, &desc->pg_list);
-       desc->pg_count = newlen;
+       desc->pg_count += req->wb_bytes;
        return 1;
 }
 
index f57f5281a52090ac8445a3ebb362515708225661..29c0ca7fc347cdf8cebf6bd83960de18942ca4e4 100644 (file)
@@ -177,13 +177,28 @@ get_layout_hdr(struct pnfs_layout_hdr *lo)
        atomic_inc(&lo->plh_refcount);
 }
 
+static struct pnfs_layout_hdr *
+pnfs_alloc_layout_hdr(struct inode *ino, gfp_t gfp_flags)
+{
+       struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld;
+       return ld->alloc_layout_hdr ? ld->alloc_layout_hdr(ino, gfp_flags) :
+               kzalloc(sizeof(struct pnfs_layout_hdr), gfp_flags);
+}
+
+static void
+pnfs_free_layout_hdr(struct pnfs_layout_hdr *lo)
+{
+       struct pnfs_layoutdriver_type *ld = NFS_SERVER(lo->plh_inode)->pnfs_curr_ld;
+       return ld->alloc_layout_hdr ? ld->free_layout_hdr(lo) : kfree(lo);
+}
+
 static void
 destroy_layout_hdr(struct pnfs_layout_hdr *lo)
 {
        dprintk("%s: freeing layout cache %p\n", __func__, lo);
        BUG_ON(!list_empty(&lo->plh_layouts));
        NFS_I(lo->plh_inode)->layout = NULL;
-       kfree(lo);
+       pnfs_free_layout_hdr(lo);
 }
 
 static void
@@ -228,7 +243,7 @@ put_lseg_common(struct pnfs_layout_segment *lseg)
 {
        struct inode *inode = lseg->pls_layout->plh_inode;
 
-       BUG_ON(test_bit(NFS_LSEG_VALID, &lseg->pls_flags));
+       WARN_ON(test_bit(NFS_LSEG_VALID, &lseg->pls_flags));
        list_del_init(&lseg->pls_list);
        if (list_empty(&lseg->pls_layout->plh_segs)) {
                set_bit(NFS_LAYOUT_DESTROYED, &lseg->pls_layout->plh_flags);
@@ -261,11 +276,72 @@ put_lseg(struct pnfs_layout_segment *lseg)
 }
 EXPORT_SYMBOL_GPL(put_lseg);
 
+static inline u64
+end_offset(u64 start, u64 len)
+{
+       u64 end;
+
+       end = start + len;
+       return end >= start ? end : NFS4_MAX_UINT64;
+}
+
+/* last octet in a range */
+static inline u64
+last_byte_offset(u64 start, u64 len)
+{
+       u64 end;
+
+       BUG_ON(!len);
+       end = start + len;
+       return end > start ? end - 1 : NFS4_MAX_UINT64;
+}
+
+/*
+ * is l2 fully contained in l1?
+ *   start1                             end1
+ *   [----------------------------------)
+ *           start2           end2
+ *           [----------------)
+ */
+static inline int
+lo_seg_contained(struct pnfs_layout_range *l1,
+                struct pnfs_layout_range *l2)
+{
+       u64 start1 = l1->offset;
+       u64 end1 = end_offset(start1, l1->length);
+       u64 start2 = l2->offset;
+       u64 end2 = end_offset(start2, l2->length);
+
+       return (start1 <= start2) && (end1 >= end2);
+}
+
+/*
+ * is l1 and l2 intersecting?
+ *   start1                             end1
+ *   [----------------------------------)
+ *                              start2           end2
+ *                              [----------------)
+ */
+static inline int
+lo_seg_intersecting(struct pnfs_layout_range *l1,
+                   struct pnfs_layout_range *l2)
+{
+       u64 start1 = l1->offset;
+       u64 end1 = end_offset(start1, l1->length);
+       u64 start2 = l2->offset;
+       u64 end2 = end_offset(start2, l2->length);
+
+       return (end1 == NFS4_MAX_UINT64 || end1 > start2) &&
+              (end2 == NFS4_MAX_UINT64 || end2 > start1);
+}
+
 static bool
-should_free_lseg(u32 lseg_iomode, u32 recall_iomode)
+should_free_lseg(struct pnfs_layout_range *lseg_range,
+                struct pnfs_layout_range *recall_range)
 {
-       return (recall_iomode == IOMODE_ANY ||
-               lseg_iomode == recall_iomode);
+       return (recall_range->iomode == IOMODE_ANY ||
+               lseg_range->iomode == recall_range->iomode) &&
+              lo_seg_intersecting(lseg_range, recall_range);
 }
 
 /* Returns 1 if lseg is removed from list, 0 otherwise */
@@ -296,7 +372,7 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
 int
 mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
                            struct list_head *tmp_list,
-                           u32 iomode)
+                           struct pnfs_layout_range *recall_range)
 {
        struct pnfs_layout_segment *lseg, *next;
        int invalid = 0, removed = 0;
@@ -309,7 +385,8 @@ mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
                return 0;
        }
        list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list)
-               if (should_free_lseg(lseg->pls_range.iomode, iomode)) {
+               if (!recall_range ||
+                   should_free_lseg(&lseg->pls_range, recall_range)) {
                        dprintk("%s: freeing lseg %p iomode %d "
                                "offset %llu length %llu\n", __func__,
                                lseg, lseg->pls_range.iomode, lseg->pls_range.offset,
@@ -358,7 +435,7 @@ pnfs_destroy_layout(struct nfs_inode *nfsi)
        lo = nfsi->layout;
        if (lo) {
                lo->plh_block_lgets++; /* permanently block new LAYOUTGETs */
-               mark_matching_lsegs_invalid(lo, &tmp_list, IOMODE_ANY);
+               mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
        }
        spin_unlock(&nfsi->vfs_inode.i_lock);
        pnfs_free_lseg_list(&tmp_list);
@@ -467,7 +544,7 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
 static struct pnfs_layout_segment *
 send_layoutget(struct pnfs_layout_hdr *lo,
           struct nfs_open_context *ctx,
-          u32 iomode,
+          struct pnfs_layout_range *range,
           gfp_t gfp_flags)
 {
        struct inode *ino = lo->plh_inode;
@@ -499,11 +576,11 @@ send_layoutget(struct pnfs_layout_hdr *lo,
                        goto out_err_free;
        }
 
-       lgp->args.minlength = NFS4_MAX_UINT64;
+       lgp->args.minlength = PAGE_CACHE_SIZE;
+       if (lgp->args.minlength > range->length)
+               lgp->args.minlength = range->length;
        lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE;
-       lgp->args.range.iomode = iomode;
-       lgp->args.range.offset = 0;
-       lgp->args.range.length = NFS4_MAX_UINT64;
+       lgp->args.range = *range;
        lgp->args.type = server->pnfs_curr_ld->id;
        lgp->args.inode = ino;
        lgp->args.ctx = get_nfs_open_context(ctx);
@@ -518,7 +595,7 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        nfs4_proc_layoutget(lgp);
        if (!lseg) {
                /* remember that LAYOUTGET failed and suspend trying */
-               set_bit(lo_fail_bit(iomode), &lo->plh_flags);
+               set_bit(lo_fail_bit(range->iomode), &lo->plh_flags);
        }
 
        /* free xdr pages */
@@ -542,6 +619,56 @@ out_err_free:
        return NULL;
 }
 
+/* Initiates a LAYOUTRETURN(FILE) */
+int
+_pnfs_return_layout(struct inode *ino)
+{
+       struct pnfs_layout_hdr *lo = NULL;
+       struct nfs_inode *nfsi = NFS_I(ino);
+       LIST_HEAD(tmp_list);
+       struct nfs4_layoutreturn *lrp;
+       nfs4_stateid stateid;
+       int status = 0;
+
+       dprintk("--> %s\n", __func__);
+
+       spin_lock(&ino->i_lock);
+       lo = nfsi->layout;
+       if (!lo) {
+               spin_unlock(&ino->i_lock);
+               dprintk("%s: no layout to return\n", __func__);
+               return status;
+       }
+       stateid = nfsi->layout->plh_stateid;
+       /* Reference matched in nfs4_layoutreturn_release */
+       get_layout_hdr(lo);
+       mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
+       lo->plh_block_lgets++;
+       spin_unlock(&ino->i_lock);
+       pnfs_free_lseg_list(&tmp_list);
+
+       WARN_ON(test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags));
+
+       lrp = kzalloc(sizeof(*lrp), GFP_KERNEL);
+       if (unlikely(lrp == NULL)) {
+               status = -ENOMEM;
+               set_bit(NFS_LAYOUT_RW_FAILED, &lo->plh_flags);
+               set_bit(NFS_LAYOUT_RO_FAILED, &lo->plh_flags);
+               put_layout_hdr(lo);
+               goto out;
+       }
+
+       lrp->args.stateid = stateid;
+       lrp->args.layout_type = NFS_SERVER(ino)->pnfs_curr_ld->id;
+       lrp->args.inode = ino;
+       lrp->clp = NFS_SERVER(ino)->nfs_client;
+
+       status = nfs4_proc_layoutreturn(lrp);
+out:
+       dprintk("<-- %s status: %d\n", __func__, status);
+       return status;
+}
+
 bool pnfs_roc(struct inode *ino)
 {
        struct pnfs_layout_hdr *lo;
@@ -625,10 +752,23 @@ bool pnfs_roc_drain(struct inode *ino, u32 *barrier)
  * are seen first.
  */
 static s64
-cmp_layout(u32 iomode1, u32 iomode2)
+cmp_layout(struct pnfs_layout_range *l1,
+          struct pnfs_layout_range *l2)
 {
+       s64 d;
+
+       /* high offset > low offset */
+       d = l1->offset - l2->offset;
+       if (d)
+               return d;
+
+       /* short length > long length */
+       d = l2->length - l1->length;
+       if (d)
+               return d;
+
        /* read > read/write */
-       return (int)(iomode2 == IOMODE_READ) - (int)(iomode1 == IOMODE_READ);
+       return (int)(l1->iomode == IOMODE_READ) - (int)(l2->iomode == IOMODE_READ);
 }
 
 static void
@@ -636,13 +776,12 @@ pnfs_insert_layout(struct pnfs_layout_hdr *lo,
                   struct pnfs_layout_segment *lseg)
 {
        struct pnfs_layout_segment *lp;
-       int found = 0;
 
        dprintk("%s:Begin\n", __func__);
 
        assert_spin_locked(&lo->plh_inode->i_lock);
        list_for_each_entry(lp, &lo->plh_segs, pls_list) {
-               if (cmp_layout(lp->pls_range.iomode, lseg->pls_range.iomode) > 0)
+               if (cmp_layout(&lseg->pls_range, &lp->pls_range) > 0)
                        continue;
                list_add_tail(&lseg->pls_list, &lp->pls_list);
                dprintk("%s: inserted lseg %p "
@@ -652,16 +791,14 @@ pnfs_insert_layout(struct pnfs_layout_hdr *lo,
                        lseg->pls_range.offset, lseg->pls_range.length,
                        lp, lp->pls_range.iomode, lp->pls_range.offset,
                        lp->pls_range.length);
-               found = 1;
-               break;
-       }
-       if (!found) {
-               list_add_tail(&lseg->pls_list, &lo->plh_segs);
-               dprintk("%s: inserted lseg %p "
-                       "iomode %d offset %llu length %llu at tail\n",
-                       __func__, lseg, lseg->pls_range.iomode,
-                       lseg->pls_range.offset, lseg->pls_range.length);
+               goto out;
        }
+       list_add_tail(&lseg->pls_list, &lo->plh_segs);
+       dprintk("%s: inserted lseg %p "
+               "iomode %d offset %llu length %llu at tail\n",
+               __func__, lseg, lseg->pls_range.iomode,
+               lseg->pls_range.offset, lseg->pls_range.length);
+out:
        get_layout_hdr(lo);
 
        dprintk("%s:Return\n", __func__);
@@ -672,7 +809,7 @@ alloc_init_layout_hdr(struct inode *ino, gfp_t gfp_flags)
 {
        struct pnfs_layout_hdr *lo;
 
-       lo = kzalloc(sizeof(struct pnfs_layout_hdr), gfp_flags);
+       lo = pnfs_alloc_layout_hdr(ino, gfp_flags);
        if (!lo)
                return NULL;
        atomic_set(&lo->plh_refcount, 1);
@@ -705,7 +842,7 @@ pnfs_find_alloc_layout(struct inode *ino, gfp_t gfp_flags)
        if (likely(nfsi->layout == NULL))       /* Won the race? */
                nfsi->layout = new;
        else
-               kfree(new);
+               pnfs_free_layout_hdr(new);
        return nfsi->layout;
 }
 
@@ -721,16 +858,28 @@ pnfs_find_alloc_layout(struct inode *ino, gfp_t gfp_flags)
  * READ                RW      true
  */
 static int
-is_matching_lseg(struct pnfs_layout_segment *lseg, u32 iomode)
+is_matching_lseg(struct pnfs_layout_range *ls_range,
+                struct pnfs_layout_range *range)
 {
-       return (iomode != IOMODE_RW || lseg->pls_range.iomode == IOMODE_RW);
+       struct pnfs_layout_range range1;
+
+       if ((range->iomode == IOMODE_RW &&
+            ls_range->iomode != IOMODE_RW) ||
+           !lo_seg_intersecting(ls_range, range))
+               return 0;
+
+       /* range1 covers only the first byte in the range */
+       range1 = *range;
+       range1.length = 1;
+       return lo_seg_contained(ls_range, &range1);
 }
 
 /*
  * lookup range in layout
  */
 static struct pnfs_layout_segment *
-pnfs_find_lseg(struct pnfs_layout_hdr *lo, u32 iomode)
+pnfs_find_lseg(struct pnfs_layout_hdr *lo,
+               struct pnfs_layout_range *range)
 {
        struct pnfs_layout_segment *lseg, *ret = NULL;
 
@@ -739,11 +888,11 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo, u32 iomode)
        assert_spin_locked(&lo->plh_inode->i_lock);
        list_for_each_entry(lseg, &lo->plh_segs, pls_list) {
                if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags) &&
-                   is_matching_lseg(lseg, iomode)) {
+                   is_matching_lseg(&lseg->pls_range, range)) {
                        ret = get_lseg(lseg);
                        break;
                }
-               if (cmp_layout(iomode, lseg->pls_range.iomode) > 0)
+               if (lseg->pls_range.offset > range->offset)
                        break;
        }
 
@@ -759,9 +908,17 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo, u32 iomode)
 struct pnfs_layout_segment *
 pnfs_update_layout(struct inode *ino,
                   struct nfs_open_context *ctx,
+                  loff_t pos,
+                  u64 count,
                   enum pnfs_iomode iomode,
                   gfp_t gfp_flags)
 {
+       struct pnfs_layout_range arg = {
+               .iomode = iomode,
+               .offset = pos,
+               .length = count,
+       };
+       unsigned pg_offset;
        struct nfs_inode *nfsi = NFS_I(ino);
        struct nfs_client *clp = NFS_SERVER(ino)->nfs_client;
        struct pnfs_layout_hdr *lo;
@@ -789,7 +946,7 @@ pnfs_update_layout(struct inode *ino,
                goto out_unlock;
 
        /* Check to see if the layout for the given range already exists */
-       lseg = pnfs_find_lseg(lo, iomode);
+       lseg = pnfs_find_lseg(lo, &arg);
        if (lseg)
                goto out_unlock;
 
@@ -811,7 +968,14 @@ pnfs_update_layout(struct inode *ino,
                spin_unlock(&clp->cl_lock);
        }
 
-       lseg = send_layoutget(lo, ctx, iomode, gfp_flags);
+       pg_offset = arg.offset & ~PAGE_CACHE_MASK;
+       if (pg_offset) {
+               arg.offset -= pg_offset;
+               arg.length += pg_offset;
+       }
+       arg.length = PAGE_CACHE_ALIGN(arg.length);
+
+       lseg = send_layoutget(lo, ctx, &arg, gfp_flags);
        if (!lseg && first) {
                spin_lock(&clp->cl_lock);
                list_del_init(&lo->plh_layouts);
@@ -838,17 +1002,6 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
        struct nfs_client *clp = NFS_SERVER(ino)->nfs_client;
        int status = 0;
 
-       /* Verify we got what we asked for.
-        * Note that because the xdr parsing only accepts a single
-        * element array, this can fail even if the server is behaving
-        * correctly.
-        */
-       if (lgp->args.range.iomode > res->range.iomode ||
-           res->range.offset != 0 ||
-           res->range.length != NFS4_MAX_UINT64) {
-               status = -EINVAL;
-               goto out;
-       }
        /* Inject layout blob into I/O device driver */
        lseg = NFS_SERVER(ino)->pnfs_curr_ld->alloc_lseg(lo, res, lgp->gfp_flags);
        if (!lseg || IS_ERR(lseg)) {
@@ -895,51 +1048,77 @@ out_forget_reply:
        goto out;
 }
 
-static int pnfs_read_pg_test(struct nfs_pageio_descriptor *pgio,
-                            struct nfs_page *prev,
-                            struct nfs_page *req)
-{
-       if (pgio->pg_count == prev->wb_bytes) {
-               /* This is first coelesce call for a series of nfs_pages */
-               pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
-                                                  prev->wb_context,
-                                                  IOMODE_READ,
-                                                  GFP_KERNEL);
-       }
-       return NFS_SERVER(pgio->pg_inode)->pnfs_curr_ld->pg_test(pgio, prev, req);
-}
-
-void
-pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode)
+bool
+pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
+                    struct nfs_page *req)
 {
-       struct pnfs_layoutdriver_type *ld;
+       enum pnfs_iomode access_type;
+       gfp_t gfp_flags;
 
-       ld = NFS_SERVER(inode)->pnfs_curr_ld;
-       pgio->pg_test = (ld && ld->pg_test) ? pnfs_read_pg_test : NULL;
-}
+       /* We assume that pg_ioflags == 0 iff we're reading a page */
+       if (pgio->pg_ioflags == 0) {
+               access_type = IOMODE_READ;
+               gfp_flags = GFP_KERNEL;
+       } else {
+               access_type = IOMODE_RW;
+               gfp_flags = GFP_NOFS;
+       }
 
-static int pnfs_write_pg_test(struct nfs_pageio_descriptor *pgio,
-                             struct nfs_page *prev,
-                             struct nfs_page *req)
-{
-       if (pgio->pg_count == prev->wb_bytes) {
+       if (pgio->pg_lseg == NULL) {
+               if (pgio->pg_count != prev->wb_bytes)
+                       return true;
                /* This is first coelesce call for a series of nfs_pages */
                pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
                                                   prev->wb_context,
-                                                  IOMODE_RW,
-                                                  GFP_NOFS);
+                                                  req_offset(prev),
+                                                  pgio->pg_count,
+                                                  access_type,
+                                                  gfp_flags);
+               if (pgio->pg_lseg == NULL)
+                       return true;
        }
-       return NFS_SERVER(pgio->pg_inode)->pnfs_curr_ld->pg_test(pgio, prev, req);
+
+       /*
+        * Test if a nfs_page is fully contained in the pnfs_layout_range.
+        * Note that this test makes several assumptions:
+        * - that the previous nfs_page in the struct nfs_pageio_descriptor
+        *   is known to lie within the range.
+        *   - that the nfs_page being tested is known to be contiguous with the
+        *   previous nfs_page.
+        *   - Layout ranges are page aligned, so we only have to test the
+        *   start offset of the request.
+        *
+        * Please also note that 'end_offset' is actually the offset of the
+        * first byte that lies outside the pnfs_layout_range. FIXME?
+        *
+        */
+       return req_offset(req) < end_offset(pgio->pg_lseg->pls_range.offset,
+                                        pgio->pg_lseg->pls_range.length);
 }
+EXPORT_SYMBOL_GPL(pnfs_generic_pg_test);
 
-void
-pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode)
+/*
+ * Called by non rpc-based layout drivers
+ */
+int
+pnfs_ld_write_done(struct nfs_write_data *data)
 {
-       struct pnfs_layoutdriver_type *ld;
+       int status;
 
-       ld = NFS_SERVER(inode)->pnfs_curr_ld;
-       pgio->pg_test = (ld && ld->pg_test) ? pnfs_write_pg_test : NULL;
+       if (!data->pnfs_error) {
+               pnfs_set_layoutcommit(data);
+               data->mds_ops->rpc_call_done(&data->task, data);
+               data->mds_ops->rpc_release(data);
+               return 0;
+       }
+
+       dprintk("%s: pnfs_error=%d, retry via MDS\n", __func__,
+               data->pnfs_error);
+       status = nfs_initiate_write(data, NFS_CLIENT(data->inode),
+                                   data->mds_ops, NFS_FILE_SYNC);
+       return status ? : -EAGAIN;
 }
+EXPORT_SYMBOL_GPL(pnfs_ld_write_done);
 
 enum pnfs_try_status
 pnfs_try_to_write_data(struct nfs_write_data *wdata,
@@ -965,6 +1144,29 @@ pnfs_try_to_write_data(struct nfs_write_data *wdata,
        return trypnfs;
 }
 
+/*
+ * Called by non rpc-based layout drivers
+ */
+int
+pnfs_ld_read_done(struct nfs_read_data *data)
+{
+       int status;
+
+       if (!data->pnfs_error) {
+               __nfs4_read_done_cb(data);
+               data->mds_ops->rpc_call_done(&data->task, data);
+               data->mds_ops->rpc_release(data);
+               return 0;
+       }
+
+       dprintk("%s: pnfs_error=%d, retry via MDS\n", __func__,
+               data->pnfs_error);
+       status = nfs_initiate_read(data, NFS_CLIENT(data->inode),
+                                  data->mds_ops);
+       return status ? : -EAGAIN;
+}
+EXPORT_SYMBOL_GPL(pnfs_ld_read_done);
+
 /*
  * Call the appropriate parallel I/O subsystem read function.
  */
@@ -1009,7 +1211,7 @@ void
 pnfs_set_layoutcommit(struct nfs_write_data *wdata)
 {
        struct nfs_inode *nfsi = NFS_I(wdata->inode);
-       loff_t end_pos = wdata->args.offset + wdata->res.count;
+       loff_t end_pos = wdata->mds_offset + wdata->res.count;
        bool mark_as_dirty = false;
 
        spin_lock(&nfsi->vfs_inode.i_lock);
index 0c015bad9e7aa4c780297746a988581c8c69acda..96bf4e6f45beda6d9646c5b19a48d13ef1ec3f5d 100644 (file)
@@ -30,6 +30,7 @@
 #ifndef FS_NFS_PNFS_H
 #define FS_NFS_PNFS_H
 
+#include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
 
 enum {
@@ -64,17 +65,29 @@ enum {
        NFS_LAYOUT_DESTROYED,           /* no new use of layout allowed */
 };
 
+enum layoutdriver_policy_flags {
+       /* Should the pNFS client commit and return the layout upon a setattr */
+       PNFS_LAYOUTRET_ON_SETATTR       = 1 << 0,
+};
+
+struct nfs4_deviceid_node;
+
 /* Per-layout driver specific registration structure */
 struct pnfs_layoutdriver_type {
        struct list_head pnfs_tblid;
        const u32 id;
        const char *name;
        struct module *owner;
+       unsigned flags;
+
+       struct pnfs_layout_hdr * (*alloc_layout_hdr) (struct inode *inode, gfp_t gfp_flags);
+       void (*free_layout_hdr) (struct pnfs_layout_hdr *);
+
        struct pnfs_layout_segment * (*alloc_lseg) (struct pnfs_layout_hdr *layoutid, struct nfs4_layoutget_res *lgr, gfp_t gfp_flags);
        void (*free_lseg) (struct pnfs_layout_segment *lseg);
 
        /* test for nfs page cache coalescing */
-       int (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *);
+       bool (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *);
 
        /* Returns true if layoutdriver wants to divert this request to
         * driver's commit routine.
@@ -89,6 +102,16 @@ struct pnfs_layoutdriver_type {
         */
        enum pnfs_try_status (*read_pagelist) (struct nfs_read_data *nfs_data);
        enum pnfs_try_status (*write_pagelist) (struct nfs_write_data *nfs_data, int how);
+
+       void (*free_deviceid_node) (struct nfs4_deviceid_node *);
+
+       void (*encode_layoutreturn) (struct pnfs_layout_hdr *layoutid,
+                                    struct xdr_stream *xdr,
+                                    const struct nfs4_layoutreturn_args *args);
+
+       void (*encode_layoutcommit) (struct pnfs_layout_hdr *layoutid,
+                                    struct xdr_stream *xdr,
+                                    const struct nfs4_layoutcommit_args *args);
 };
 
 struct pnfs_layout_hdr {
@@ -120,21 +143,22 @@ extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *);
 extern int nfs4_proc_getdeviceinfo(struct nfs_server *server,
                                   struct pnfs_device *dev);
 extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp);
+extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp);
 
 /* pnfs.c */
 void get_layout_hdr(struct pnfs_layout_hdr *lo);
 void put_lseg(struct pnfs_layout_segment *lseg);
 struct pnfs_layout_segment *
 pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
-                  enum pnfs_iomode access_type, gfp_t gfp_flags);
+                  loff_t pos, u64 count, enum pnfs_iomode access_type,
+                  gfp_t gfp_flags);
 void set_pnfs_layoutdriver(struct nfs_server *, u32 id);
 void unset_pnfs_layoutdriver(struct nfs_server *);
 enum pnfs_try_status pnfs_try_to_write_data(struct nfs_write_data *,
                                             const struct rpc_call_ops *, int);
 enum pnfs_try_status pnfs_try_to_read_data(struct nfs_read_data *,
                                            const struct rpc_call_ops *);
-void pnfs_pageio_init_read(struct nfs_pageio_descriptor *, struct inode *);
-void pnfs_pageio_init_write(struct nfs_pageio_descriptor *, struct inode *);
+bool pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, struct nfs_page *req);
 int pnfs_layout_process(struct nfs4_layoutget *lgp);
 void pnfs_free_lseg_list(struct list_head *tmp_list);
 void pnfs_destroy_layout(struct nfs_inode *);
@@ -148,13 +172,38 @@ int pnfs_choose_layoutget_stateid(nfs4_stateid *dst,
                                  struct nfs4_state *open_state);
 int mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
                                struct list_head *tmp_list,
-                               u32 iomode);
+                               struct pnfs_layout_range *recall_range);
 bool pnfs_roc(struct inode *ino);
 void pnfs_roc_release(struct inode *ino);
 void pnfs_roc_set_barrier(struct inode *ino, u32 barrier);
 bool pnfs_roc_drain(struct inode *ino, u32 *barrier);
 void pnfs_set_layoutcommit(struct nfs_write_data *wdata);
 int pnfs_layoutcommit_inode(struct inode *inode, bool sync);
+int _pnfs_return_layout(struct inode *);
+int pnfs_ld_write_done(struct nfs_write_data *);
+int pnfs_ld_read_done(struct nfs_read_data *);
+
+/* pnfs_dev.c */
+struct nfs4_deviceid_node {
+       struct hlist_node               node;
+       struct hlist_node               tmpnode;
+       const struct pnfs_layoutdriver_type *ld;
+       const struct nfs_client         *nfs_client;
+       struct nfs4_deviceid            deviceid;
+       atomic_t                        ref;
+};
+
+void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id);
+struct nfs4_deviceid_node *nfs4_find_get_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *);
+struct nfs4_deviceid_node *nfs4_unhash_put_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *);
+void nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *);
+void nfs4_init_deviceid_node(struct nfs4_deviceid_node *,
+                            const struct pnfs_layoutdriver_type *,
+                            const struct nfs_client *,
+                            const struct nfs4_deviceid *);
+struct nfs4_deviceid_node *nfs4_insert_deviceid_node(struct nfs4_deviceid_node *);
+bool nfs4_put_deviceid_node(struct nfs4_deviceid_node *);
+void nfs4_deviceid_purge_client(const struct nfs_client *);
 
 static inline int lo_fail_bit(u32 iomode)
 {
@@ -223,6 +272,36 @@ static inline void pnfs_clear_request_commit(struct nfs_page *req)
                put_lseg(req->wb_commit_lseg);
 }
 
+/* Should the pNFS client commit and return the layout upon a setattr */
+static inline bool
+pnfs_ld_layoutret_on_setattr(struct inode *inode)
+{
+       if (!pnfs_enabled_sb(NFS_SERVER(inode)))
+               return false;
+       return NFS_SERVER(inode)->pnfs_curr_ld->flags &
+               PNFS_LAYOUTRET_ON_SETATTR;
+}
+
+static inline int pnfs_return_layout(struct inode *ino)
+{
+       struct nfs_inode *nfsi = NFS_I(ino);
+       struct nfs_server *nfss = NFS_SERVER(ino);
+
+       if (pnfs_enabled_sb(nfss) && nfsi->layout)
+               return _pnfs_return_layout(ino);
+
+       return 0;
+}
+
+static inline void pnfs_pageio_init(struct nfs_pageio_descriptor *pgio,
+                                   struct inode *inode)
+{
+       struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld;
+
+       if (ld)
+               pgio->pg_test = ld->pg_test;
+}
+
 #else  /* CONFIG_NFS_V4_1 */
 
 static inline void pnfs_destroy_all_layouts(struct nfs_client *clp)
@@ -245,7 +324,8 @@ static inline void put_lseg(struct pnfs_layout_segment *lseg)
 
 static inline struct pnfs_layout_segment *
 pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
-                  enum pnfs_iomode access_type, gfp_t gfp_flags)
+                  loff_t pos, u64 count, enum pnfs_iomode access_type,
+                  gfp_t gfp_flags)
 {
        return NULL;
 }
@@ -264,6 +344,17 @@ pnfs_try_to_write_data(struct nfs_write_data *data,
        return PNFS_NOT_ATTEMPTED;
 }
 
+static inline int pnfs_return_layout(struct inode *ino)
+{
+       return 0;
+}
+
+static inline bool
+pnfs_ld_layoutret_on_setattr(struct inode *inode)
+{
+       return false;
+}
+
 static inline bool
 pnfs_roc(struct inode *ino)
 {
@@ -294,16 +385,9 @@ static inline void unset_pnfs_layoutdriver(struct nfs_server *s)
 {
 }
 
-static inline void
-pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *ino)
-{
-       pgio->pg_test = NULL;
-}
-
-static inline void
-pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *ino)
+static inline void pnfs_pageio_init(struct nfs_pageio_descriptor *pgio,
+                                   struct inode *inode)
 {
-       pgio->pg_test = NULL;
 }
 
 static inline void
@@ -331,6 +415,10 @@ static inline int pnfs_layoutcommit_inode(struct inode *inode, bool sync)
 {
        return 0;
 }
+
+static inline void nfs4_deviceid_purge_client(struct nfs_client *ncl)
+{
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 #endif /* FS_NFS_PNFS_H */
diff --git a/fs/nfs/pnfs_dev.c b/fs/nfs/pnfs_dev.c
new file mode 100644 (file)
index 0000000..f0f8e1e
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ *  Device operations for the pnfs client.
+ *
+ *  Copyright (c) 2002
+ *  The Regents of the University of Michigan
+ *  All Rights Reserved
+ *
+ *  Dean Hildebrand <dhildebz@umich.edu>
+ *  Garth Goodson   <Garth.Goodson@netapp.com>
+ *
+ *  Permission is granted to use, copy, create derivative works, and
+ *  redistribute this software and such derivative works for any purpose,
+ *  so long as the name of the University of Michigan is not used in
+ *  any advertising or publicity pertaining to the use or distribution
+ *  of this software without specific, written prior authorization. If
+ *  the above copyright notice or any other identification of the
+ *  University of Michigan is included in any copy of any portion of
+ *  this software, then the disclaimer below must also be included.
+ *
+ *  This software is provided as is, without representation or warranty
+ *  of any kind either express or implied, including without limitation
+ *  the implied warranties of merchantability, fitness for a particular
+ *  purpose, or noninfringement.  The Regents of the University of
+ *  Michigan shall not be liable for any damages, including special,
+ *  indirect, incidental, or consequential damages, with respect to any
+ *  claim arising out of or in connection with the use of the software,
+ *  even if it has been or is hereafter advised of the possibility of
+ *  such damages.
+ */
+
+#include "pnfs.h"
+
+#define NFSDBG_FACILITY                NFSDBG_PNFS
+
+/*
+ * Device ID RCU cache. A device ID is unique per server and layout type.
+ */
+#define NFS4_DEVICE_ID_HASH_BITS       5
+#define NFS4_DEVICE_ID_HASH_SIZE       (1 << NFS4_DEVICE_ID_HASH_BITS)
+#define NFS4_DEVICE_ID_HASH_MASK       (NFS4_DEVICE_ID_HASH_SIZE - 1)
+
+static struct hlist_head nfs4_deviceid_cache[NFS4_DEVICE_ID_HASH_SIZE];
+static DEFINE_SPINLOCK(nfs4_deviceid_lock);
+
+void
+nfs4_print_deviceid(const struct nfs4_deviceid *id)
+{
+       u32 *p = (u32 *)id;
+
+       dprintk("%s: device id= [%x%x%x%x]\n", __func__,
+               p[0], p[1], p[2], p[3]);
+}
+EXPORT_SYMBOL_GPL(nfs4_print_deviceid);
+
+static inline u32
+nfs4_deviceid_hash(const struct nfs4_deviceid *id)
+{
+       unsigned char *cptr = (unsigned char *)id->data;
+       unsigned int nbytes = NFS4_DEVICEID4_SIZE;
+       u32 x = 0;
+
+       while (nbytes--) {
+               x *= 37;
+               x += *cptr++;
+       }
+       return x & NFS4_DEVICE_ID_HASH_MASK;
+}
+
+static struct nfs4_deviceid_node *
+_lookup_deviceid(const struct pnfs_layoutdriver_type *ld,
+                const struct nfs_client *clp, const struct nfs4_deviceid *id,
+                long hash)
+{
+       struct nfs4_deviceid_node *d;
+       struct hlist_node *n;
+
+       hlist_for_each_entry_rcu(d, n, &nfs4_deviceid_cache[hash], node)
+               if (d->ld == ld && d->nfs_client == clp &&
+                   !memcmp(&d->deviceid, id, sizeof(*id))) {
+                       if (atomic_read(&d->ref))
+                               return d;
+                       else
+                               continue;
+               }
+       return NULL;
+}
+
+/*
+ * Lookup a deviceid in cache and get a reference count on it if found
+ *
+ * @clp nfs_client associated with deviceid
+ * @id deviceid to look up
+ */
+struct nfs4_deviceid_node *
+_find_get_deviceid(const struct pnfs_layoutdriver_type *ld,
+                  const struct nfs_client *clp, const struct nfs4_deviceid *id,
+                  long hash)
+{
+       struct nfs4_deviceid_node *d;
+
+       rcu_read_lock();
+       d = _lookup_deviceid(ld, clp, id, hash);
+       if (d && !atomic_inc_not_zero(&d->ref))
+               d = NULL;
+       rcu_read_unlock();
+       return d;
+}
+
+struct nfs4_deviceid_node *
+nfs4_find_get_deviceid(const struct pnfs_layoutdriver_type *ld,
+                      const struct nfs_client *clp, const struct nfs4_deviceid *id)
+{
+       return _find_get_deviceid(ld, clp, id, nfs4_deviceid_hash(id));
+}
+EXPORT_SYMBOL_GPL(nfs4_find_get_deviceid);
+
+/*
+ * Unhash and put deviceid
+ *
+ * @clp nfs_client associated with deviceid
+ * @id the deviceid to unhash
+ *
+ * @ret the unhashed node, if found and dereferenced to zero, NULL otherwise.
+ */
+struct nfs4_deviceid_node *
+nfs4_unhash_put_deviceid(const struct pnfs_layoutdriver_type *ld,
+                        const struct nfs_client *clp, const struct nfs4_deviceid *id)
+{
+       struct nfs4_deviceid_node *d;
+
+       spin_lock(&nfs4_deviceid_lock);
+       rcu_read_lock();
+       d = _lookup_deviceid(ld, clp, id, nfs4_deviceid_hash(id));
+       rcu_read_unlock();
+       if (!d) {
+               spin_unlock(&nfs4_deviceid_lock);
+               return NULL;
+       }
+       hlist_del_init_rcu(&d->node);
+       spin_unlock(&nfs4_deviceid_lock);
+       synchronize_rcu();
+
+       /* balance the initial ref set in pnfs_insert_deviceid */
+       if (atomic_dec_and_test(&d->ref))
+               return d;
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(nfs4_unhash_put_deviceid);
+
+/*
+ * Delete a deviceid from cache
+ *
+ * @clp struct nfs_client qualifying the deviceid
+ * @id deviceid to delete
+ */
+void
+nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *ld,
+                    const struct nfs_client *clp, const struct nfs4_deviceid *id)
+{
+       struct nfs4_deviceid_node *d;
+
+       d = nfs4_unhash_put_deviceid(ld, clp, id);
+       if (!d)
+               return;
+       d->ld->free_deviceid_node(d);
+}
+EXPORT_SYMBOL_GPL(nfs4_delete_deviceid);
+
+void
+nfs4_init_deviceid_node(struct nfs4_deviceid_node *d,
+                       const struct pnfs_layoutdriver_type *ld,
+                       const struct nfs_client *nfs_client,
+                       const struct nfs4_deviceid *id)
+{
+       INIT_HLIST_NODE(&d->node);
+       INIT_HLIST_NODE(&d->tmpnode);
+       d->ld = ld;
+       d->nfs_client = nfs_client;
+       d->deviceid = *id;
+       atomic_set(&d->ref, 1);
+}
+EXPORT_SYMBOL_GPL(nfs4_init_deviceid_node);
+
+/*
+ * Uniquely initialize and insert a deviceid node into cache
+ *
+ * @new new deviceid node
+ *      Note that the caller must set up the following members:
+ *        new->ld
+ *        new->nfs_client
+ *        new->deviceid
+ *
+ * @ret the inserted node, if none found, otherwise, the found entry.
+ */
+struct nfs4_deviceid_node *
+nfs4_insert_deviceid_node(struct nfs4_deviceid_node *new)
+{
+       struct nfs4_deviceid_node *d;
+       long hash;
+
+       spin_lock(&nfs4_deviceid_lock);
+       hash = nfs4_deviceid_hash(&new->deviceid);
+       d = _find_get_deviceid(new->ld, new->nfs_client, &new->deviceid, hash);
+       if (d) {
+               spin_unlock(&nfs4_deviceid_lock);
+               return d;
+       }
+
+       hlist_add_head_rcu(&new->node, &nfs4_deviceid_cache[hash]);
+       spin_unlock(&nfs4_deviceid_lock);
+       atomic_inc(&new->ref);
+
+       return new;
+}
+EXPORT_SYMBOL_GPL(nfs4_insert_deviceid_node);
+
+/*
+ * Dereference a deviceid node and delete it when its reference count drops
+ * to zero.
+ *
+ * @d deviceid node to put
+ *
+ * @ret true iff the node was deleted
+ */
+bool
+nfs4_put_deviceid_node(struct nfs4_deviceid_node *d)
+{
+       if (!atomic_dec_and_lock(&d->ref, &nfs4_deviceid_lock))
+               return false;
+       hlist_del_init_rcu(&d->node);
+       spin_unlock(&nfs4_deviceid_lock);
+       synchronize_rcu();
+       d->ld->free_deviceid_node(d);
+       return true;
+}
+EXPORT_SYMBOL_GPL(nfs4_put_deviceid_node);
+
+static void
+_deviceid_purge_client(const struct nfs_client *clp, long hash)
+{
+       struct nfs4_deviceid_node *d;
+       struct hlist_node *n;
+       HLIST_HEAD(tmp);
+
+       spin_lock(&nfs4_deviceid_lock);
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(d, n, &nfs4_deviceid_cache[hash], node)
+               if (d->nfs_client == clp && atomic_read(&d->ref)) {
+                       hlist_del_init_rcu(&d->node);
+                       hlist_add_head(&d->tmpnode, &tmp);
+               }
+       rcu_read_unlock();
+       spin_unlock(&nfs4_deviceid_lock);
+
+       if (hlist_empty(&tmp))
+               return;
+
+       synchronize_rcu();
+       while (!hlist_empty(&tmp)) {
+               d = hlist_entry(tmp.first, struct nfs4_deviceid_node, tmpnode);
+               hlist_del(&d->tmpnode);
+               if (atomic_dec_and_test(&d->ref))
+                       d->ld->free_deviceid_node(d);
+       }
+}
+
+void
+nfs4_deviceid_purge_client(const struct nfs_client *clp)
+{
+       long h;
+
+       if (!(clp->cl_exchange_flags & EXCHGID4_FLAG_USE_PNFS_MDS))
+               return;
+       for (h = 0; h < NFS4_DEVICE_ID_HASH_SIZE; h++)
+               _deviceid_purge_client(clp, h);
+}
index 2bcf0dc306a1000e2211ef117670ac47f6ef4407..20a7f952e244c763065ce01f1b44aa34c3e2c25d 100644 (file)
@@ -288,7 +288,9 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc)
        atomic_set(&req->wb_complete, requests);
 
        BUG_ON(desc->pg_lseg != NULL);
-       lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_READ, GFP_KERNEL);
+       lseg = pnfs_update_layout(desc->pg_inode, req->wb_context,
+                                 req_offset(req), desc->pg_count,
+                                 IOMODE_READ, GFP_KERNEL);
        ClearPageError(page);
        offset = 0;
        nbytes = desc->pg_count;
@@ -351,7 +353,9 @@ static int nfs_pagein_one(struct nfs_pageio_descriptor *desc)
        }
        req = nfs_list_entry(data->pages.next);
        if ((!lseg) && list_is_singular(&data->pages))
-               lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_READ, GFP_KERNEL);
+               lseg = pnfs_update_layout(desc->pg_inode, req->wb_context,
+                                         req_offset(req), desc->pg_count,
+                                         IOMODE_READ, GFP_KERNEL);
 
        ret = nfs_read_rpcsetup(req, data, &nfs_read_full_ops, desc->pg_count,
                                0, lseg);
@@ -660,7 +664,6 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
        if (ret == 0)
                goto read_complete; /* all pages were read */
 
-       pnfs_pageio_init_read(&pgio, inode);
        if (rsize < PAGE_CACHE_SIZE)
                nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0);
        else
index e288f06d3fa7de5f6d06e134b1854230aa9b7611..ce40e5c568ba393ec297fbdbc4d288b750491e5a 100644 (file)
@@ -63,6 +63,7 @@
 #include "iostat.h"
 #include "internal.h"
 #include "fscache.h"
+#include "pnfs.h"
 
 #define NFSDBG_FACILITY                NFSDBG_VFS
 
@@ -732,6 +733,28 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
 
        return 0;
 }
+#ifdef CONFIG_NFS_V4_1
+void show_sessions(struct seq_file *m, struct nfs_server *server)
+{
+       if (nfs4_has_session(server->nfs_client))
+               seq_printf(m, ",sessions");
+}
+#else
+void show_sessions(struct seq_file *m, struct nfs_server *server) {}
+#endif
+
+#ifdef CONFIG_NFS_V4_1
+void show_pnfs(struct seq_file *m, struct nfs_server *server)
+{
+       seq_printf(m, ",pnfs=");
+       if (server->pnfs_curr_ld)
+               seq_printf(m, "%s", server->pnfs_curr_ld->name);
+       else
+               seq_printf(m, "not configured");
+}
+#else  /* CONFIG_NFS_V4_1 */
+void show_pnfs(struct seq_file *m, struct nfs_server *server) {}
+#endif /* CONFIG_NFS_V4_1 */
 
 static int nfs_show_devname(struct seq_file *m, struct vfsmount *mnt)
 {
@@ -792,6 +815,8 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
                seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
                seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
                seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
+               show_sessions(m, nfss);
+               show_pnfs(m, nfss);
        }
 #endif
 
index 49c715b4ac927b9bbd283e0f991118d34bf9af10..e268e3b23497282f02e7cb9d209f189a886c60a7 100644 (file)
@@ -939,7 +939,9 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc)
        atomic_set(&req->wb_complete, requests);
 
        BUG_ON(desc->pg_lseg);
-       lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW, GFP_NOFS);
+       lseg = pnfs_update_layout(desc->pg_inode, req->wb_context,
+                                 req_offset(req), desc->pg_count,
+                                 IOMODE_RW, GFP_NOFS);
        ClearPageError(page);
        offset = 0;
        nbytes = desc->pg_count;
@@ -1013,7 +1015,9 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc)
        }
        req = nfs_list_entry(data->pages.next);
        if ((!lseg) && list_is_singular(&data->pages))
-               lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW, GFP_NOFS);
+               lseg = pnfs_update_layout(desc->pg_inode, req->wb_context,
+                                         req_offset(req), desc->pg_count,
+                                         IOMODE_RW, GFP_NOFS);
 
        if ((desc->pg_ioflags & FLUSH_COND_STABLE) &&
            (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit))
@@ -1032,8 +1036,6 @@ static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
 {
        size_t wsize = NFS_SERVER(inode)->wsize;
 
-       pnfs_pageio_init_write(pgio, inode);
-
        if (wsize < PAGE_CACHE_SIZE)
                nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags);
        else
index 18b3e8975fe05c2364dd507d50b364b4c13b0dfd..fbb2a5ef5817cfa8c3800c0a1205562ae47549db 100644 (file)
@@ -82,6 +82,7 @@ config NFSD_V4
        select NFSD_V3
        select FS_POSIX_ACL
        select SUNRPC_GSS
+       select CRYPTO
        help
          This option enables support in your system's NFS server for
          version 4 of the NFS protocol (RFC 3530).
index ad000aeb21a2aa85d351b32038f57032cfb8a78e..b9566e46219f3ac8af1e9ab6916aadece4a02177 100644 (file)
@@ -1354,12 +1354,6 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
        if (IS_ERR(exp))
                return nfserrno(PTR_ERR(exp));
        rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
-       if (rv)
-               goto out;
-       rv = check_nfsd_access(exp, rqstp);
-       if (rv)
-               fh_put(fhp);
-out:
        exp_put(exp);
        return rv;
 }
index 2247fc91d5e9728e0796d45bb63c8784fb2da96e..9095f3c21df9e93a7bba11160f06896877851c09 100644 (file)
@@ -245,7 +245,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
        }
 
        /* Now create the file and set attributes */
-       nfserr = nfsd_create_v3(rqstp, dirfhp, argp->name, argp->len,
+       nfserr = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len,
                                attr, newfhp,
                                argp->createmode, argp->verf, NULL, NULL);
 
index ad48faca20fc7f777dfcd76dbd35b7e62a197eca..08c6e36ab2eb05d8c28f68394a326573a7f52658 100644 (file)
@@ -842,7 +842,7 @@ out:
        return rv;
 }
 
-__be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen)
+static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen)
 {
        struct svc_fh   fh;
        int err;
index 5fcb1396a7e324ada8f3cf639f2e6c025ca9a689..3a6dbd70b34b57146cacfb8e22d0601481ec5349 100644 (file)
@@ -196,9 +196,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
 
                /*
                 * Note: create modes (UNCHECKED,GUARDED...) are the same
-                * in NFSv4 as in v3.
+                * in NFSv4 as in v3 except EXCLUSIVE4_1.
                 */
-               status = nfsd_create_v3(rqstp, current_fh, open->op_fname.data,
+               status = do_nfsd_create(rqstp, current_fh, open->op_fname.data,
                                        open->op_fname.len, &open->op_iattr,
                                        &resfh, open->op_createmode,
                                        (u32 *)open->op_verf.data,
@@ -403,7 +403,7 @@ nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen;
        memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval,
               putfh->pf_fhlen);
-       return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
+       return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_BYPASS_GSS);
 }
 
 static __be32
@@ -762,6 +762,9 @@ nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        __be32 err;
 
        fh_init(&resfh, NFS4_FHSIZE);
+       err = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, NFSD_MAY_EXEC);
+       if (err)
+               return err;
        err = nfsd_lookup_dentry(rqstp, &cstate->current_fh,
                                    secinfo->si_name, secinfo->si_namelen,
                                    &exp, &dentry);
@@ -986,6 +989,9 @@ enum nfsd4_op_flags {
        ALLOWED_WITHOUT_FH = 1 << 0,    /* No current filehandle required */
        ALLOWED_ON_ABSENT_FS = 1 << 1,  /* ops processed on absent fs */
        ALLOWED_AS_FIRST_OP = 1 << 2,   /* ops reqired first in compound */
+       /* For rfc 5661 section 2.6.3.1.1: */
+       OP_HANDLES_WRONGSEC = 1 << 3,
+       OP_IS_PUTFH_LIKE = 1 << 4,
 };
 
 struct nfsd4_operation {
@@ -1031,6 +1037,44 @@ static __be32 nfs41_check_op_ordering(struct nfsd4_compoundargs *args)
        return nfs_ok;
 }
 
+static inline struct nfsd4_operation *OPDESC(struct nfsd4_op *op)
+{
+       return &nfsd4_ops[op->opnum];
+}
+
+static bool need_wrongsec_check(struct svc_rqst *rqstp)
+{
+       struct nfsd4_compoundres *resp = rqstp->rq_resp;
+       struct nfsd4_compoundargs *argp = rqstp->rq_argp;
+       struct nfsd4_op *this = &argp->ops[resp->opcnt - 1];
+       struct nfsd4_op *next = &argp->ops[resp->opcnt];
+       struct nfsd4_operation *thisd;
+       struct nfsd4_operation *nextd;
+
+       thisd = OPDESC(this);
+       /*
+        * Most ops check wronsec on our own; only the putfh-like ops
+        * have special rules.
+        */
+       if (!(thisd->op_flags & OP_IS_PUTFH_LIKE))
+               return false;
+       /*
+        * rfc 5661 2.6.3.1.1.6: don't bother erroring out a
+        * put-filehandle operation if we're not going to use the
+        * result:
+        */
+       if (argp->opcnt == resp->opcnt)
+               return false;
+
+       nextd = OPDESC(next);
+       /*
+        * Rest of 2.6.3.1.1: certain operations will return WRONGSEC
+        * errors themselves as necessary; others should check for them
+        * now:
+        */
+       return !(nextd->op_flags & OP_HANDLES_WRONGSEC);
+}
+
 /*
  * COMPOUND call.
  */
@@ -1108,7 +1152,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
                        goto encode_op;
                }
 
-               opdesc = &nfsd4_ops[op->opnum];
+               opdesc = OPDESC(op);
 
                if (!cstate->current_fh.fh_dentry) {
                        if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
@@ -1126,6 +1170,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
                else
                        BUG_ON(op->status == nfs_ok);
 
+               if (!op->status && need_wrongsec_check(rqstp))
+                       op->status = check_nfsd_access(cstate->current_fh.fh_export, rqstp);
+
 encode_op:
                /* Only from SEQUENCE */
                if (resp->cstate.status == nfserr_replay_cache) {
@@ -1217,10 +1264,12 @@ static struct nfsd4_operation nfsd4_ops[] = {
        },
        [OP_LOOKUP] = {
                .op_func = (nfsd4op_func)nfsd4_lookup,
+               .op_flags = OP_HANDLES_WRONGSEC,
                .op_name = "OP_LOOKUP",
        },
        [OP_LOOKUPP] = {
                .op_func = (nfsd4op_func)nfsd4_lookupp,
+               .op_flags = OP_HANDLES_WRONGSEC,
                .op_name = "OP_LOOKUPP",
        },
        [OP_NVERIFY] = {
@@ -1229,6 +1278,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
        },
        [OP_OPEN] = {
                .op_func = (nfsd4op_func)nfsd4_open,
+               .op_flags = OP_HANDLES_WRONGSEC,
                .op_name = "OP_OPEN",
        },
        [OP_OPEN_CONFIRM] = {
@@ -1241,17 +1291,20 @@ static struct nfsd4_operation nfsd4_ops[] = {
        },
        [OP_PUTFH] = {
                .op_func = (nfsd4op_func)nfsd4_putfh,
-               .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
+               .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
+                               | OP_IS_PUTFH_LIKE,
                .op_name = "OP_PUTFH",
        },
        [OP_PUTPUBFH] = {
                .op_func = (nfsd4op_func)nfsd4_putrootfh,
-               .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
+               .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
+                               | OP_IS_PUTFH_LIKE,
                .op_name = "OP_PUTPUBFH",
        },
        [OP_PUTROOTFH] = {
                .op_func = (nfsd4op_func)nfsd4_putrootfh,
-               .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
+               .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
+                               | OP_IS_PUTFH_LIKE,
                .op_name = "OP_PUTROOTFH",
        },
        [OP_READ] = {
@@ -1281,15 +1334,18 @@ static struct nfsd4_operation nfsd4_ops[] = {
        },
        [OP_RESTOREFH] = {
                .op_func = (nfsd4op_func)nfsd4_restorefh,
-               .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
+               .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
+                               | OP_IS_PUTFH_LIKE,
                .op_name = "OP_RESTOREFH",
        },
        [OP_SAVEFH] = {
                .op_func = (nfsd4op_func)nfsd4_savefh,
+               .op_flags = OP_HANDLES_WRONGSEC,
                .op_name = "OP_SAVEFH",
        },
        [OP_SECINFO] = {
                .op_func = (nfsd4op_func)nfsd4_secinfo,
+               .op_flags = OP_HANDLES_WRONGSEC,
                .op_name = "OP_SECINFO",
        },
        [OP_SETATTR] = {
@@ -1353,6 +1409,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
        },
        [OP_SECINFO_NO_NAME] = {
                .op_func = (nfsd4op_func)nfsd4_secinfo_no_name,
+               .op_flags = OP_HANDLES_WRONGSEC,
                .op_name = "OP_SECINFO_NO_NAME",
        },
 };
index 4cf04e11c66ca39c80dc6b54b6854842de246826..e98f3c2e9492a9d2dd3e86e6e443e924c9f04187 100644 (file)
@@ -1519,6 +1519,9 @@ nfsd4_create_session(struct svc_rqst *rqstp,
        bool confirm_me = false;
        int status = 0;
 
+       if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
+               return nfserr_inval;
+
        nfs4_lock_state();
        unconf = find_unconfirmed_client(&cr_ses->clientid);
        conf = find_confirmed_client(&cr_ses->clientid);
@@ -1637,8 +1640,9 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
                return nfserr_badsession;
 
        status = nfsd4_map_bcts_dir(&bcts->dir);
-       nfsd4_new_conn(rqstp, cstate->session, bcts->dir);
-       return nfs_ok;
+       if (!status)
+               nfsd4_new_conn(rqstp, cstate->session, bcts->dir);
+       return status;
 }
 
 static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
@@ -1725,6 +1729,13 @@ static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_sessi
        return;
 }
 
+static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session)
+{
+       struct nfsd4_compoundargs *args = rqstp->rq_argp;
+
+       return args->opcnt > session->se_fchannel.maxops;
+}
+
 __be32
 nfsd4_sequence(struct svc_rqst *rqstp,
               struct nfsd4_compound_state *cstate,
@@ -1753,6 +1764,10 @@ nfsd4_sequence(struct svc_rqst *rqstp,
        if (!session)
                goto out;
 
+       status = nfserr_too_many_ops;
+       if (nfsd4_session_too_many_ops(rqstp, session))
+               goto out;
+
        status = nfserr_badslot;
        if (seq->slotid >= session->se_fchannel.maxreqs)
                goto out;
@@ -1808,6 +1823,8 @@ out:
 __be32
 nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc)
 {
+       int status = 0;
+
        if (rc->rca_one_fs) {
                if (!cstate->current_fh.fh_dentry)
                        return nfserr_nofilehandle;
@@ -1817,9 +1834,14 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
                 */
                 return nfs_ok;
        }
+
        nfs4_lock_state();
-       if (is_client_expired(cstate->session->se_client)) {
-               nfs4_unlock_state();
+       status = nfserr_complete_already;
+       if (cstate->session->se_client->cl_firststate)
+               goto out;
+
+       status = nfserr_stale_clientid;
+       if (is_client_expired(cstate->session->se_client))
                /*
                 * The following error isn't really legal.
                 * But we only get here if the client just explicitly
@@ -1827,11 +1849,13 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
                 * error it gets back on an operation for the dead
                 * client.
                 */
-               return nfserr_stale_clientid;
-       }
+               goto out;
+
+       status = nfs_ok;
        nfsd4_create_clid_dir(cstate->session->se_client);
+out:
        nfs4_unlock_state();
-       return nfs_ok;
+       return status;
 }
 
 __be32
@@ -2462,7 +2486,7 @@ find_delegation_file(struct nfs4_file *fp, stateid_t *stid)
        return NULL;
 }
 
-int share_access_to_flags(u32 share_access)
+static int share_access_to_flags(u32 share_access)
 {
        share_access &= ~NFS4_SHARE_WANT_MASK;
 
@@ -2882,7 +2906,7 @@ out:
        return status;
 }
 
-struct lock_manager nfsd4_manager = {
+static struct lock_manager nfsd4_manager = {
 };
 
 static void
index c6766af00d983ec2573266b6592f62fc2f8ba1c9..990181103214de4f45d305753aea2daa064f44c0 100644 (file)
@@ -424,15 +424,12 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access
 static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts)
 {
        DECODE_HEAD;
-       u32 dummy;
 
        READ_BUF(NFS4_MAX_SESSIONID_LEN + 8);
        COPYMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN);
        READ32(bcts->dir);
-       /* XXX: Perhaps Tom Tucker could help us figure out how we
-        * should be using ctsa_use_conn_in_rdma_mode: */
-       READ32(dummy);
-
+       /* XXX: skipping ctsa_use_conn_in_rdma_mode.  Perhaps Tom Tucker
+        * could help us figure out we should be using it. */
        DECODE_TAIL;
 }
 
@@ -588,8 +585,6 @@ nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt)
        READ_BUF(lockt->lt_owner.len);
        READMEM(lockt->lt_owner.data, lockt->lt_owner.len);
 
-       if (argp->minorversion && !zero_clientid(&lockt->lt_clientid))
-               return nfserr_inval;
        DECODE_TAIL;
 }
 
@@ -3120,7 +3115,7 @@ nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr,
        return nfserr;
 }
 
-__be32
+static __be32
 nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
                      struct nfsd4_sequence *seq)
 {
index 1f5eae40f34ef4aa57174be24445a39854906e71..2b1449dd2f495b4c6389399b8e29e0da7165d2c2 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/lockd/lockd.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/gss_api.h>
+#include <linux/sunrpc/gss_krb5_enctypes.h>
 
 #include "idmap.h"
 #include "nfsd.h"
@@ -189,18 +190,10 @@ static struct file_operations export_features_operations = {
        .release        = single_release,
 };
 
-#ifdef CONFIG_SUNRPC_GSS
+#if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
 static int supported_enctypes_show(struct seq_file *m, void *v)
 {
-       struct gss_api_mech *k5mech;
-
-       k5mech = gss_mech_get_by_name("krb5");
-       if (k5mech == NULL)
-               goto out;
-       if (k5mech->gm_upcall_enctypes != NULL)
-               seq_printf(m, k5mech->gm_upcall_enctypes);
-       gss_mech_put(k5mech);
-out:
+       seq_printf(m, KRB5_SUPPORTED_ENCTYPES);
        return 0;
 }
 
@@ -215,7 +208,7 @@ static struct file_operations supported_enctypes_ops = {
        .llseek         = seq_lseek,
        .release        = single_release,
 };
-#endif /* CONFIG_SUNRPC_GSS */
+#endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
 
 extern int nfsd_pool_stats_open(struct inode *inode, struct file *file);
 extern int nfsd_pool_stats_release(struct inode *inode, struct file *file);
@@ -1427,9 +1420,9 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
                [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
                [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
                [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
-#ifdef CONFIG_SUNRPC_GSS
+#if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
                [NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO},
-#endif /* CONFIG_SUNRPC_GSS */
+#endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
 #ifdef CONFIG_NFSD_V4
                [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
                [NFSD_Gracetime] = {"nfsv4gracetime", &transaction_ops, S_IWUSR|S_IRUSR},
index 55c8e63af0be76d566e7723916675a0627145a12..90c6aa6d5e0f9c413f0427081368bb1bc894566e 100644 (file)
@@ -344,7 +344,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
         * which clients virtually always use auth_sys for,
         * even while using RPCSEC_GSS for NFS.
         */
-       if (access & NFSD_MAY_LOCK)
+       if (access & NFSD_MAY_LOCK || access & NFSD_MAY_BYPASS_GSS)
                goto skip_pseudoflavor_check;
        /*
         * Clients may expect to be able to use auth_sys during mount,
index 129f3c9f62d589f44b947fccd04c8f745cdfb485..fd0acca5370a5da699fe62a5d94d0b6e81f67b78 100644 (file)
@@ -181,16 +181,10 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
        struct svc_export       *exp;
        struct dentry           *dparent;
        struct dentry           *dentry;
-       __be32                  err;
        int                     host_err;
 
        dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name);
 
-       /* Obtain dentry and export. */
-       err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
-       if (err)
-               return err;
-
        dparent = fhp->fh_dentry;
        exp  = fhp->fh_export;
        exp_get(exp);
@@ -254,6 +248,9 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
        struct dentry           *dentry;
        __be32 err;
 
+       err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
+       if (err)
+               return err;
        err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry);
        if (err)
                return err;
@@ -699,7 +696,15 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor
 }
 #endif /* CONFIG_NFSD_V3 */
 
+static int nfsd_open_break_lease(struct inode *inode, int access)
+{
+       unsigned int mode;
 
+       if (access & NFSD_MAY_NOT_BREAK_LEASE)
+               return 0;
+       mode = (access & NFSD_MAY_WRITE) ? O_WRONLY : O_RDONLY;
+       return break_lease(inode, mode | O_NONBLOCK);
+}
 
 /*
  * Open an existing file or directory.
@@ -747,12 +752,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
        if (!inode->i_fop)
                goto out;
 
-       /*
-        * Check to see if there are any leases on this file.
-        * This may block while leases are broken.
-        */
-       if (!(access & NFSD_MAY_NOT_BREAK_LEASE))
-               host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? O_WRONLY : 0));
+       host_err = nfsd_open_break_lease(inode, access);
        if (host_err) /* NOMEM or WOULDBLOCK */
                goto out_nfserr;
 
@@ -877,13 +877,11 @@ static __be32
 nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
               loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
 {
-       struct inode *inode;
        mm_segment_t    oldfs;
        __be32          err;
        int             host_err;
 
        err = nfserr_perm;
-       inode = file->f_path.dentry->d_inode;
 
        if (file->f_op->splice_read && rqstp->rq_splice_ok) {
                struct splice_desc sd = {
@@ -1340,11 +1338,18 @@ out_nfserr:
 }
 
 #ifdef CONFIG_NFSD_V3
+
+static inline int nfsd_create_is_exclusive(int createmode)
+{
+       return createmode == NFS3_CREATE_EXCLUSIVE
+              || createmode == NFS4_CREATE_EXCLUSIVE4_1;
+}
+
 /*
- * NFSv3 version of nfsd_create
+ * NFSv3 and NFSv4 version of nfsd_create
  */
 __be32
-nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
+do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
                char *fname, int flen, struct iattr *iap,
                struct svc_fh *resfhp, int createmode, u32 *verifier,
                int *truncp, int *created)
@@ -1396,7 +1401,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (err)
                goto out;
 
-       if (createmode == NFS3_CREATE_EXCLUSIVE) {
+       if (nfsd_create_is_exclusive(createmode)) {
                /* solaris7 gets confused (bugid 4218508) if these have
                 * the high bit set, so just clear the high bits. If this is
                 * ever changed to use different attrs for storing the
@@ -1437,6 +1442,11 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
                            && dchild->d_inode->i_atime.tv_sec == v_atime
                            && dchild->d_inode->i_size  == 0 )
                                break;
+               case NFS4_CREATE_EXCLUSIVE4_1:
+                       if (   dchild->d_inode->i_mtime.tv_sec == v_mtime
+                           && dchild->d_inode->i_atime.tv_sec == v_atime
+                           && dchild->d_inode->i_size  == 0 )
+                               goto set_attr;
                         /* fallthru */
                case NFS3_CREATE_GUARDED:
                        err = nfserr_exist;
@@ -1455,7 +1465,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
 
        nfsd_check_ignore_resizing(iap);
 
-       if (createmode == NFS3_CREATE_EXCLUSIVE) {
+       if (nfsd_create_is_exclusive(createmode)) {
                /* Cram the verifier into atime/mtime */
                iap->ia_valid = ATTR_MTIME|ATTR_ATIME
                        | ATTR_MTIME_SET|ATTR_ATIME_SET;
@@ -1653,8 +1663,10 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
        if (!dold->d_inode)
                goto out_drop_write;
        host_err = nfsd_break_lease(dold->d_inode);
-       if (host_err)
+       if (host_err) {
+               err = nfserrno(host_err);
                goto out_drop_write;
+       }
        host_err = vfs_link(dold, dirp, dnew);
        if (!host_err) {
                err = nfserrno(commit_metadata(ffhp));
@@ -2034,7 +2046,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
        struct inode    *inode = dentry->d_inode;
        int             err;
 
-       if (acc == NFSD_MAY_NOP)
+       if ((acc & NFSD_MAY_MASK) == NFSD_MAY_NOP)
                return 0;
 #if 0
        dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n",
index 9a370a5e36b7ea9409b0b5b250ff88b6d5bee6ce..e0bbac04d1dd01ec899e86666258c7c5405d2e8e 100644 (file)
 #define NFSD_MAY_SATTR         8
 #define NFSD_MAY_TRUNC         16
 #define NFSD_MAY_LOCK          32
+#define NFSD_MAY_MASK          63
+
+/* extra hints to permission and open routines: */
 #define NFSD_MAY_OWNER_OVERRIDE        64
 #define NFSD_MAY_LOCAL_ACCESS  128 /* IRIX doing local access check on device special file*/
 #define NFSD_MAY_BYPASS_GSS_ON_ROOT 256
 #define NFSD_MAY_NOT_BREAK_LEASE 512
+#define NFSD_MAY_BYPASS_GSS    1024
 
 #define NFSD_MAY_CREATE                (NFSD_MAY_EXEC|NFSD_MAY_WRITE)
 #define NFSD_MAY_REMOVE                (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC)
@@ -54,7 +58,7 @@ __be32                nfsd_create(struct svc_rqst *, struct svc_fh *,
                                int type, dev_t rdev, struct svc_fh *res);
 #ifdef CONFIG_NFSD_V3
 __be32         nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *);
-__be32         nfsd_create_v3(struct svc_rqst *, struct svc_fh *,
+__be32         do_nfsd_create(struct svc_rqst *, struct svc_fh *,
                                char *name, int len, struct iattr *attrs,
                                struct svc_fh *res, int createmode,
                                u32 *verifier, int *truncp, int *created);
index 7eafe468a29c71cb5338612149a435cf8b037756..b2e3ff34762070a4b37085c051223809b59e4a6c 100644 (file)
@@ -1346,6 +1346,11 @@ static void nilfs_btree_shrink(struct nilfs_bmap *btree,
        path[level].bp_bh = NULL;
 }
 
+static void nilfs_btree_nop(struct nilfs_bmap *btree,
+                           struct nilfs_btree_path *path,
+                           int level, __u64 *keyp, __u64 *ptrp)
+{
+}
 
 static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree,
                                      struct nilfs_btree_path *path,
@@ -1356,20 +1361,19 @@ static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree,
        struct buffer_head *bh;
        struct nilfs_btree_node *node, *parent, *sib;
        __u64 sibptr;
-       int pindex, level, ncmin, ncmax, ncblk, ret;
+       int pindex, dindex, level, ncmin, ncmax, ncblk, ret;
 
        ret = 0;
        stats->bs_nblocks = 0;
        ncmin = NILFS_BTREE_NODE_NCHILDREN_MIN(nilfs_btree_node_size(btree));
        ncblk = nilfs_btree_nchildren_per_block(btree);
 
-       for (level = NILFS_BTREE_LEVEL_NODE_MIN;
+       for (level = NILFS_BTREE_LEVEL_NODE_MIN, dindex = path[level].bp_index;
             level < nilfs_btree_height(btree) - 1;
             level++) {
                node = nilfs_btree_get_nonroot_node(path, level);
                path[level].bp_oldreq.bpr_ptr =
-                       nilfs_btree_node_get_ptr(node, path[level].bp_index,
-                                                ncblk);
+                       nilfs_btree_node_get_ptr(node, dindex, ncblk);
                ret = nilfs_bmap_prepare_end_ptr(btree,
                                                 &path[level].bp_oldreq, dat);
                if (ret < 0)
@@ -1383,6 +1387,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree,
 
                parent = nilfs_btree_get_node(btree, path, level + 1, &ncmax);
                pindex = path[level + 1].bp_index;
+               dindex = pindex;
 
                if (pindex > 0) {
                        /* left sibling */
@@ -1421,6 +1426,14 @@ static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree,
                                path[level].bp_sib_bh = bh;
                                path[level].bp_op = nilfs_btree_concat_right;
                                stats->bs_nblocks++;
+                               /*
+                                * When merging right sibling node
+                                * into the current node, pointer to
+                                * the right sibling node must be
+                                * terminated instead.  The adjustment
+                                * below is required for that.
+                                */
+                               dindex = pindex + 1;
                                /* continue; */
                        }
                } else {
@@ -1431,29 +1444,31 @@ static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree,
                            NILFS_BTREE_ROOT_NCHILDREN_MAX) {
                                path[level].bp_op = nilfs_btree_shrink;
                                stats->bs_nblocks += 2;
+                               level++;
+                               path[level].bp_op = nilfs_btree_nop;
+                               goto shrink_root_child;
                        } else {
                                path[level].bp_op = nilfs_btree_do_delete;
                                stats->bs_nblocks++;
+                               goto out;
                        }
-
-                       goto out;
-
                }
        }
 
+       /* child of the root node is deleted */
+       path[level].bp_op = nilfs_btree_do_delete;
+       stats->bs_nblocks++;
+
+shrink_root_child:
        node = nilfs_btree_get_root(btree);
        path[level].bp_oldreq.bpr_ptr =
-               nilfs_btree_node_get_ptr(node, path[level].bp_index,
+               nilfs_btree_node_get_ptr(node, dindex,
                                         NILFS_BTREE_ROOT_NCHILDREN_MAX);
 
        ret = nilfs_bmap_prepare_end_ptr(btree, &path[level].bp_oldreq, dat);
        if (ret < 0)
                goto err_out_child_node;
 
-       /* child of the root node is deleted */
-       path[level].bp_op = nilfs_btree_do_delete;
-       stats->bs_nblocks++;
-
        /* success */
  out:
        *levelp = level;
index 587f18432832e542571ba49ad5f3fac6e8669721..b9b45fc2903e6c38f52410a23bbe258032edd872 100644 (file)
@@ -801,12 +801,7 @@ out_err:
 
 int nilfs_permission(struct inode *inode, int mask, unsigned int flags)
 {
-       struct nilfs_root *root;
-
-       if (flags & IPERM_FLAG_RCU)
-               return -ECHILD;
-
-       root = NILFS_I(inode)->i_root;
+       struct nilfs_root *root = NILFS_I(inode)->i_root;
        if ((mask & MAY_WRITE) && root &&
            root->cno != NILFS_CPTREE_CURRENT_CNO)
                return -EROFS; /* snapshot is not writable */
@@ -917,7 +912,7 @@ int nilfs_mark_inode_dirty(struct inode *inode)
  * construction. This function can be called both as a single operation
  * and as a part of indivisible file operations.
  */
-void nilfs_dirty_inode(struct inode *inode)
+void nilfs_dirty_inode(struct inode *inode, int flags)
 {
        struct nilfs_transaction_info ti;
        struct nilfs_mdt_info *mdi = NILFS_MDT(inode);
index a9c6a531f80c5786ce628e3cbf0bd331ba86141f..f02b9ad43a21f9537d23e3678a115e570488174a 100644 (file)
@@ -269,7 +269,7 @@ int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh);
 extern int nilfs_inode_dirty(struct inode *);
 int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty);
 extern int nilfs_mark_inode_dirty(struct inode *);
-extern void nilfs_dirty_inode(struct inode *);
+extern void nilfs_dirty_inode(struct inode *, int flags);
 int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                 __u64 start, __u64 len);
 
index 141646e88fb5a9e3d5103ed69d3eb4880b33963e..bb24ab6c282fae5099bc9442478c6689e1d44c59 100644 (file)
@@ -2573,7 +2573,7 @@ static struct nilfs_sc_info *nilfs_segctor_new(struct super_block *sb,
        sci->sc_watermark = NILFS_SC_DEFAULT_WATERMARK;
 
        if (nilfs->ns_interval)
-               sci->sc_interval = nilfs->ns_interval;
+               sci->sc_interval = HZ * nilfs->ns_interval;
        if (nilfs->ns_watermark)
                sci->sc_watermark = nilfs->ns_watermark;
        return sci;
index d8a0313e99e6af42b8412e91bb44cb2d7bb410b8..f17e58b32989a53f4f0413065bbd5e07d7901d5d 100644 (file)
@@ -30,6 +30,7 @@ ocfs2-objs := \
        namei.o                 \
        refcounttree.o          \
        reservations.o          \
+       move_extents.o          \
        resize.o                \
        slot_map.o              \
        suballoc.o              \
index 48aa9c7401c77aa5487fbc2fb1c472efa6217faa..ed553c60de827e0ebad24e3501e0e00d21c82cfc 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/highmem.h>
 #include <linux/swap.h>
 #include <linux/quotaops.h>
+#include <linux/blkdev.h>
 
 #include <cluster/masklog.h>
 
@@ -7184,3 +7185,168 @@ out_commit:
 out:
        return ret;
 }
+
+static int ocfs2_trim_extent(struct super_block *sb,
+                            struct ocfs2_group_desc *gd,
+                            u32 start, u32 count)
+{
+       u64 discard, bcount;
+
+       bcount = ocfs2_clusters_to_blocks(sb, count);
+       discard = le64_to_cpu(gd->bg_blkno) +
+                       ocfs2_clusters_to_blocks(sb, start);
+
+       trace_ocfs2_trim_extent(sb, (unsigned long long)discard, bcount);
+
+       return sb_issue_discard(sb, discard, bcount, GFP_NOFS, 0);
+}
+
+static int ocfs2_trim_group(struct super_block *sb,
+                           struct ocfs2_group_desc *gd,
+                           u32 start, u32 max, u32 minbits)
+{
+       int ret = 0, count = 0, next;
+       void *bitmap = gd->bg_bitmap;
+
+       if (le16_to_cpu(gd->bg_free_bits_count) < minbits)
+               return 0;
+
+       trace_ocfs2_trim_group((unsigned long long)le64_to_cpu(gd->bg_blkno),
+                              start, max, minbits);
+
+       while (start < max) {
+               start = ocfs2_find_next_zero_bit(bitmap, max, start);
+               if (start >= max)
+                       break;
+               next = ocfs2_find_next_bit(bitmap, max, start);
+
+               if ((next - start) >= minbits) {
+                       ret = ocfs2_trim_extent(sb, gd,
+                                               start, next - start);
+                       if (ret < 0) {
+                               mlog_errno(ret);
+                               break;
+                       }
+                       count += next - start;
+               }
+               start = next + 1;
+
+               if (fatal_signal_pending(current)) {
+                       count = -ERESTARTSYS;
+                       break;
+               }
+
+               if ((le16_to_cpu(gd->bg_free_bits_count) - count) < minbits)
+                       break;
+       }
+
+       if (ret < 0)
+               count = ret;
+
+       return count;
+}
+
+int ocfs2_trim_fs(struct super_block *sb, struct fstrim_range *range)
+{
+       struct ocfs2_super *osb = OCFS2_SB(sb);
+       u64 start, len, trimmed, first_group, last_group, group;
+       int ret, cnt;
+       u32 first_bit, last_bit, minlen;
+       struct buffer_head *main_bm_bh = NULL;
+       struct inode *main_bm_inode = NULL;
+       struct buffer_head *gd_bh = NULL;
+       struct ocfs2_dinode *main_bm;
+       struct ocfs2_group_desc *gd = NULL;
+
+       start = range->start >> osb->s_clustersize_bits;
+       len = range->len >> osb->s_clustersize_bits;
+       minlen = range->minlen >> osb->s_clustersize_bits;
+       trimmed = 0;
+
+       if (!len) {
+               range->len = 0;
+               return 0;
+       }
+
+       if (minlen >= osb->bitmap_cpg)
+               return -EINVAL;
+
+       main_bm_inode = ocfs2_get_system_file_inode(osb,
+                                                   GLOBAL_BITMAP_SYSTEM_INODE,
+                                                   OCFS2_INVALID_SLOT);
+       if (!main_bm_inode) {
+               ret = -EIO;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       mutex_lock(&main_bm_inode->i_mutex);
+
+       ret = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 0);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out_mutex;
+       }
+       main_bm = (struct ocfs2_dinode *)main_bm_bh->b_data;
+
+       if (start >= le32_to_cpu(main_bm->i_clusters)) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       if (start + len > le32_to_cpu(main_bm->i_clusters))
+               len = le32_to_cpu(main_bm->i_clusters) - start;
+
+       trace_ocfs2_trim_fs(start, len, minlen);
+
+       /* Determine first and last group to examine based on start and len */
+       first_group = ocfs2_which_cluster_group(main_bm_inode, start);
+       if (first_group == osb->first_cluster_group_blkno)
+               first_bit = start;
+       else
+               first_bit = start - ocfs2_blocks_to_clusters(sb, first_group);
+       last_group = ocfs2_which_cluster_group(main_bm_inode, start + len - 1);
+       last_bit = osb->bitmap_cpg;
+
+       for (group = first_group; group <= last_group;) {
+               if (first_bit + len >= osb->bitmap_cpg)
+                       last_bit = osb->bitmap_cpg;
+               else
+                       last_bit = first_bit + len;
+
+               ret = ocfs2_read_group_descriptor(main_bm_inode,
+                                                 main_bm, group,
+                                                 &gd_bh);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       break;
+               }
+
+               gd = (struct ocfs2_group_desc *)gd_bh->b_data;
+               cnt = ocfs2_trim_group(sb, gd, first_bit, last_bit, minlen);
+               brelse(gd_bh);
+               gd_bh = NULL;
+               if (cnt < 0) {
+                       ret = cnt;
+                       mlog_errno(ret);
+                       break;
+               }
+
+               trimmed += cnt;
+               len -= osb->bitmap_cpg - first_bit;
+               first_bit = 0;
+               if (group == osb->first_cluster_group_blkno)
+                       group = ocfs2_clusters_to_blocks(sb, osb->bitmap_cpg);
+               else
+                       group += ocfs2_clusters_to_blocks(sb, osb->bitmap_cpg);
+       }
+       range->len = trimmed * sb->s_blocksize;
+out_unlock:
+       ocfs2_inode_unlock(main_bm_inode, 0);
+       brelse(main_bm_bh);
+out_mutex:
+       mutex_unlock(&main_bm_inode->i_mutex);
+       iput(main_bm_inode);
+out:
+       return ret;
+}
index 3bd08a03251c32fe904af81cb49305f72dba1e41..ca381c5841273433d279cd6aca8137ec01d03bbd 100644 (file)
@@ -239,6 +239,7 @@ int ocfs2_find_leaf(struct ocfs2_caching_info *ci,
                    struct buffer_head **leaf_bh);
 int ocfs2_search_extent_list(struct ocfs2_extent_list *el, u32 v_cluster);
 
+int ocfs2_trim_fs(struct super_block *sb, struct fstrim_range *range);
 /*
  * Helper function to look at the # of clusters in an extent record.
  */
index bc702dab5d1f912be9e70ee1dd58fb8aaeb441dc..a4b07730b2e1d0abb257a126fce7f3911ae1d434 100644 (file)
@@ -57,7 +57,6 @@ static struct kset *o2cb_kset;
 void o2cb_sys_shutdown(void)
 {
        mlog_sys_shutdown();
-       sysfs_remove_link(NULL, "o2cb");
        kset_unregister(o2cb_kset);
 }
 
@@ -69,14 +68,6 @@ int o2cb_sys_init(void)
        if (!o2cb_kset)
                return -ENOMEM;
 
-       /*
-        * Create this symlink for backwards compatibility with old
-        * versions of ocfs2-tools which look for things in /sys/o2cb.
-        */
-       ret = sysfs_create_link(NULL, &o2cb_kset->kobj, "o2cb");
-       if (ret)
-               goto error;
-
        ret = sysfs_create_group(&o2cb_kset->kobj, &o2cb_attr_group);
        if (ret)
                goto error;
index 4bdf7baee344dd9533bf08bc3969f3b4b00b4ac8..d602abb51b610d525cc437daa05c25d2105fe0c3 100644 (file)
@@ -144,6 +144,7 @@ struct dlm_ctxt
        wait_queue_head_t dlm_join_events;
        unsigned long live_nodes_map[BITS_TO_LONGS(O2NM_MAX_NODES)];
        unsigned long domain_map[BITS_TO_LONGS(O2NM_MAX_NODES)];
+       unsigned long exit_domain_map[BITS_TO_LONGS(O2NM_MAX_NODES)];
        unsigned long recovery_map[BITS_TO_LONGS(O2NM_MAX_NODES)];
        struct dlm_recovery_ctxt reco;
        spinlock_t master_lock;
@@ -401,6 +402,18 @@ static inline int dlm_lvb_is_empty(char *lvb)
        return 1;
 }
 
+static inline char *dlm_list_in_text(enum dlm_lockres_list idx)
+{
+       if (idx == DLM_GRANTED_LIST)
+               return "granted";
+       else if (idx == DLM_CONVERTING_LIST)
+               return "converting";
+       else if (idx == DLM_BLOCKED_LIST)
+               return "blocked";
+       else
+               return "unknown";
+}
+
 static inline struct list_head *
 dlm_list_idx_to_ptr(struct dlm_lock_resource *res, enum dlm_lockres_list idx)
 {
@@ -448,6 +461,7 @@ enum {
        DLM_FINALIZE_RECO_MSG           = 518,
        DLM_QUERY_REGION                = 519,
        DLM_QUERY_NODEINFO              = 520,
+       DLM_BEGIN_EXIT_DOMAIN_MSG       = 521,
 };
 
 struct dlm_reco_node_data
index 04a32be0aeb92f6ec15fb9217e0cca789f895bca..56f82cb912e379e4149ab5454261a9bb6bdadf67 100644 (file)
@@ -756,6 +756,12 @@ static int debug_state_print(struct dlm_ctxt *dlm, char *buf, int len)
                                 buf + out, len - out);
        out += snprintf(buf + out, len - out, "\n");
 
+       /* Exit Domain Map: xx xx xx */
+       out += snprintf(buf + out, len - out, "Exit Domain Map: ");
+       out += stringify_nodemap(dlm->exit_domain_map, O2NM_MAX_NODES,
+                                buf + out, len - out);
+       out += snprintf(buf + out, len - out, "\n");
+
        /* Live Map: xx xx xx */
        out += snprintf(buf + out, len - out, "Live Map: ");
        out += stringify_nodemap(dlm->live_nodes_map, O2NM_MAX_NODES,
index 3b179d6cbde09be9017eb21fbefcc5df8b217a53..6ed6b95dcf935a6516e935b85a3ca9ffc0b8a9d8 100644 (file)
@@ -132,10 +132,12 @@ static DECLARE_WAIT_QUEUE_HEAD(dlm_domain_events);
  * New in version 1.1:
  *     - Message DLM_QUERY_REGION added to support global heartbeat
  *     - Message DLM_QUERY_NODEINFO added to allow online node removes
+ * New in version 1.2:
+ *     - Message DLM_BEGIN_EXIT_DOMAIN_MSG added to mark start of exit domain
  */
 static const struct dlm_protocol_version dlm_protocol = {
        .pv_major = 1,
-       .pv_minor = 1,
+       .pv_minor = 2,
 };
 
 #define DLM_DOMAIN_BACKOFF_MS 200
@@ -449,14 +451,18 @@ redo_bucket:
                        dropped = dlm_empty_lockres(dlm, res);
 
                        spin_lock(&res->spinlock);
-                       __dlm_lockres_calc_usage(dlm, res);
-                       iter = res->hash_node.next;
+                       if (dropped)
+                               __dlm_lockres_calc_usage(dlm, res);
+                       else
+                               iter = res->hash_node.next;
                        spin_unlock(&res->spinlock);
 
                        dlm_lockres_put(res);
 
-                       if (dropped)
+                       if (dropped) {
+                               cond_resched_lock(&dlm->spinlock);
                                goto redo_bucket;
+                       }
                }
                cond_resched_lock(&dlm->spinlock);
                num += n;
@@ -486,6 +492,28 @@ static int dlm_no_joining_node(struct dlm_ctxt *dlm)
        return ret;
 }
 
+static int dlm_begin_exit_domain_handler(struct o2net_msg *msg, u32 len,
+                                        void *data, void **ret_data)
+{
+       struct dlm_ctxt *dlm = data;
+       unsigned int node;
+       struct dlm_exit_domain *exit_msg = (struct dlm_exit_domain *) msg->buf;
+
+       if (!dlm_grab(dlm))
+               return 0;
+
+       node = exit_msg->node_idx;
+       mlog(0, "%s: Node %u sent a begin exit domain message\n", dlm->name, node);
+
+       spin_lock(&dlm->spinlock);
+       set_bit(node, dlm->exit_domain_map);
+       spin_unlock(&dlm->spinlock);
+
+       dlm_put(dlm);
+
+       return 0;
+}
+
 static void dlm_mark_domain_leaving(struct dlm_ctxt *dlm)
 {
        /* Yikes, a double spinlock! I need domain_lock for the dlm
@@ -542,6 +570,7 @@ static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data,
 
        spin_lock(&dlm->spinlock);
        clear_bit(node, dlm->domain_map);
+       clear_bit(node, dlm->exit_domain_map);
        __dlm_print_nodes(dlm);
 
        /* notify anything attached to the heartbeat events */
@@ -554,29 +583,56 @@ static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data,
        return 0;
 }
 
-static int dlm_send_one_domain_exit(struct dlm_ctxt *dlm,
+static int dlm_send_one_domain_exit(struct dlm_ctxt *dlm, u32 msg_type,
                                    unsigned int node)
 {
        int status;
        struct dlm_exit_domain leave_msg;
 
-       mlog(0, "Asking node %u if we can leave the domain %s me = %u\n",
-                 node, dlm->name, dlm->node_num);
+       mlog(0, "%s: Sending domain exit message %u to node %u\n", dlm->name,
+            msg_type, node);
 
        memset(&leave_msg, 0, sizeof(leave_msg));
        leave_msg.node_idx = dlm->node_num;
 
-       status = o2net_send_message(DLM_EXIT_DOMAIN_MSG, dlm->key,
-                                   &leave_msg, sizeof(leave_msg), node,
-                                   NULL);
+       status = o2net_send_message(msg_type, dlm->key, &leave_msg,
+                                   sizeof(leave_msg), node, NULL);
        if (status < 0)
-               mlog(ML_ERROR, "Error %d when sending message %u (key 0x%x) to "
-                    "node %u\n", status, DLM_EXIT_DOMAIN_MSG, dlm->key, node);
-       mlog(0, "status return %d from o2net_send_message\n", status);
+               mlog(ML_ERROR, "Error %d sending domain exit message %u "
+                    "to node %u on domain %s\n", status, msg_type, node,
+                    dlm->name);
 
        return status;
 }
 
+static void dlm_begin_exit_domain(struct dlm_ctxt *dlm)
+{
+       int node = -1;
+
+       /* Support for begin exit domain was added in 1.2 */
+       if (dlm->dlm_locking_proto.pv_major == 1 &&
+           dlm->dlm_locking_proto.pv_minor < 2)
+               return;
+
+       /*
+        * Unlike DLM_EXIT_DOMAIN_MSG, DLM_BEGIN_EXIT_DOMAIN_MSG is purely
+        * informational. Meaning if a node does not receive the message,
+        * so be it.
+        */
+       spin_lock(&dlm->spinlock);
+       while (1) {
+               node = find_next_bit(dlm->domain_map, O2NM_MAX_NODES, node + 1);
+               if (node >= O2NM_MAX_NODES)
+                       break;
+               if (node == dlm->node_num)
+                       continue;
+
+               spin_unlock(&dlm->spinlock);
+               dlm_send_one_domain_exit(dlm, DLM_BEGIN_EXIT_DOMAIN_MSG, node);
+               spin_lock(&dlm->spinlock);
+       }
+       spin_unlock(&dlm->spinlock);
+}
 
 static void dlm_leave_domain(struct dlm_ctxt *dlm)
 {
@@ -602,7 +658,8 @@ static void dlm_leave_domain(struct dlm_ctxt *dlm)
 
                clear_node = 1;
 
-               status = dlm_send_one_domain_exit(dlm, node);
+               status = dlm_send_one_domain_exit(dlm, DLM_EXIT_DOMAIN_MSG,
+                                                 node);
                if (status < 0 &&
                    status != -ENOPROTOOPT &&
                    status != -ENOTCONN) {
@@ -677,6 +734,7 @@ void dlm_unregister_domain(struct dlm_ctxt *dlm)
 
        if (leave) {
                mlog(0, "shutting down domain %s\n", dlm->name);
+               dlm_begin_exit_domain(dlm);
 
                /* We changed dlm state, notify the thread */
                dlm_kick_thread(dlm, NULL);
@@ -909,6 +967,7 @@ static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data,
                 * leftover join state. */
                BUG_ON(dlm->joining_node != assert->node_idx);
                set_bit(assert->node_idx, dlm->domain_map);
+               clear_bit(assert->node_idx, dlm->exit_domain_map);
                __dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN);
 
                printk(KERN_NOTICE "o2dlm: Node %u joins domain %s\n",
@@ -1793,6 +1852,13 @@ static int dlm_register_domain_handlers(struct dlm_ctxt *dlm)
        if (status)
                goto bail;
 
+       status = o2net_register_handler(DLM_BEGIN_EXIT_DOMAIN_MSG, dlm->key,
+                                       sizeof(struct dlm_exit_domain),
+                                       dlm_begin_exit_domain_handler,
+                                       dlm, NULL, &dlm->dlm_domain_handlers);
+       if (status)
+               goto bail;
+
 bail:
        if (status)
                dlm_unregister_domain_handlers(dlm);
index 84d166328cf7448f36cfcb0a54f08eefda50e18d..11eefb8c12e98fb418f41c31a3b0a32201be3ca1 100644 (file)
@@ -2339,65 +2339,55 @@ static void dlm_deref_lockres_worker(struct dlm_work_item *item, void *data)
        dlm_lockres_put(res);
 }
 
-/* Checks whether the lockres can be migrated. Returns 0 if yes, < 0
- * if not. If 0, numlocks is set to the number of locks in the lockres.
+/*
+ * A migrateable resource is one that is :
+ * 1. locally mastered, and,
+ * 2. zero local locks, and,
+ * 3. one or more non-local locks, or, one or more references
+ * Returns 1 if yes, 0 if not.
  */
 static int dlm_is_lockres_migrateable(struct dlm_ctxt *dlm,
-                                     struct dlm_lock_resource *res,
-                                     int *numlocks,
-                                     int *hasrefs)
+                                     struct dlm_lock_resource *res)
 {
-       int ret;
-       int i;
-       int count = 0;
+       enum dlm_lockres_list idx;
+       int nonlocal = 0, node_ref;
        struct list_head *queue;
        struct dlm_lock *lock;
+       u64 cookie;
 
        assert_spin_locked(&res->spinlock);
 
-       *numlocks = 0;
-       *hasrefs = 0;
-
-       ret = -EINVAL;
-       if (res->owner == DLM_LOCK_RES_OWNER_UNKNOWN) {
-               mlog(0, "cannot migrate lockres with unknown owner!\n");
-               goto leave;
-       }
-
-       if (res->owner != dlm->node_num) {
-               mlog(0, "cannot migrate lockres this node doesn't own!\n");
-               goto leave;
-       }
+       if (res->owner != dlm->node_num)
+               return 0;
 
-       ret = 0;
-       queue = &res->granted;
-       for (i = 0; i < 3; i++) {
+        for (idx = DLM_GRANTED_LIST; idx <= DLM_BLOCKED_LIST; idx++) {
+               queue = dlm_list_idx_to_ptr(res, idx);
                list_for_each_entry(lock, queue, list) {
-                       ++count;
-                       if (lock->ml.node == dlm->node_num) {
-                               mlog(0, "found a lock owned by this node still "
-                                    "on the %s queue!  will not migrate this "
-                                    "lockres\n", (i == 0 ? "granted" :
-                                                  (i == 1 ? "converting" :
-                                                   "blocked")));
-                               ret = -ENOTEMPTY;
-                               goto leave;
+                       if (lock->ml.node != dlm->node_num) {
+                               nonlocal++;
+                               continue;
                        }
+                       cookie = be64_to_cpu(lock->ml.cookie);
+                       mlog(0, "%s: Not migrateable res %.*s, lock %u:%llu on "
+                            "%s list\n", dlm->name, res->lockname.len,
+                            res->lockname.name,
+                            dlm_get_lock_cookie_node(cookie),
+                            dlm_get_lock_cookie_seq(cookie),
+                            dlm_list_in_text(idx));
+                       return 0;
                }
-               queue++;
        }
 
-       *numlocks = count;
-
-       count = find_next_bit(res->refmap, O2NM_MAX_NODES, 0);
-       if (count < O2NM_MAX_NODES)
-               *hasrefs = 1;
+       if (!nonlocal) {
+               node_ref = find_next_bit(res->refmap, O2NM_MAX_NODES, 0);
+               if (node_ref >= O2NM_MAX_NODES)
+                       return 0;
+       }
 
-       mlog(0, "%s: res %.*s, Migrateable, locks %d, refs %d\n", dlm->name,
-            res->lockname.len, res->lockname.name, *numlocks, *hasrefs);
+       mlog(0, "%s: res %.*s, Migrateable\n", dlm->name, res->lockname.len,
+            res->lockname.name);
 
-leave:
-       return ret;
+       return 1;
 }
 
 /*
@@ -2406,8 +2396,7 @@ leave:
 
 
 static int dlm_migrate_lockres(struct dlm_ctxt *dlm,
-                              struct dlm_lock_resource *res,
-                              u8 target)
+                              struct dlm_lock_resource *res, u8 target)
 {
        struct dlm_master_list_entry *mle = NULL;
        struct dlm_master_list_entry *oldmle = NULL;
@@ -2416,37 +2405,20 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm,
        const char *name;
        unsigned int namelen;
        int mle_added = 0;
-       int numlocks, hasrefs;
        int wake = 0;
 
        if (!dlm_grab(dlm))
                return -EINVAL;
 
+       BUG_ON(target == O2NM_MAX_NODES);
+
        name = res->lockname.name;
        namelen = res->lockname.len;
 
-       mlog(0, "%s: Migrating %.*s to %u\n", dlm->name, namelen, name, target);
-
-       /*
-        * ensure this lockres is a proper candidate for migration
-        */
-       spin_lock(&res->spinlock);
-       ret = dlm_is_lockres_migrateable(dlm, res, &numlocks, &hasrefs);
-       if (ret < 0) {
-               spin_unlock(&res->spinlock);
-               goto leave;
-       }
-       spin_unlock(&res->spinlock);
-
-       /* no work to do */
-       if (numlocks == 0 && !hasrefs)
-               goto leave;
-
-       /*
-        * preallocate up front
-        * if this fails, abort
-        */
+       mlog(0, "%s: Migrating %.*s to node %u\n", dlm->name, namelen, name,
+            target);
 
+       /* preallocate up front. if this fails, abort */
        ret = -ENOMEM;
        mres = (struct dlm_migratable_lockres *) __get_free_page(GFP_NOFS);
        if (!mres) {
@@ -2461,36 +2433,11 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm,
        }
        ret = 0;
 
-       /*
-        * find a node to migrate the lockres to
-        */
-
-       spin_lock(&dlm->spinlock);
-       /* pick a new node */
-       if (!test_bit(target, dlm->domain_map) ||
-           target >= O2NM_MAX_NODES) {
-               target = dlm_pick_migration_target(dlm, res);
-       }
-       mlog(0, "%s: res %.*s, Node %u chosen for migration\n", dlm->name,
-            namelen, name, target);
-
-       if (target >= O2NM_MAX_NODES ||
-           !test_bit(target, dlm->domain_map)) {
-               /* target chosen is not alive */
-               ret = -EINVAL;
-       }
-
-       if (ret) {
-               spin_unlock(&dlm->spinlock);
-               goto fail;
-       }
-
-       mlog(0, "continuing with target = %u\n", target);
-
        /*
         * clear any existing master requests and
         * add the migration mle to the list
         */
+       spin_lock(&dlm->spinlock);
        spin_lock(&dlm->master_lock);
        ret = dlm_add_migration_mle(dlm, res, mle, &oldmle, name,
                                    namelen, target, dlm->node_num);
@@ -2531,6 +2478,7 @@ fail:
                        dlm_put_mle(mle);
                } else if (mle) {
                        kmem_cache_free(dlm_mle_cache, mle);
+                       mle = NULL;
                }
                goto leave;
        }
@@ -2652,69 +2600,52 @@ leave:
        if (wake)
                wake_up(&res->wq);
 
-       /* TODO: cleanup */
        if (mres)
                free_page((unsigned long)mres);
 
        dlm_put(dlm);
 
-       mlog(0, "returning %d\n", ret);
+       mlog(0, "%s: Migrating %.*s to %u, returns %d\n", dlm->name, namelen,
+            name, target, ret);
        return ret;
 }
 
 #define DLM_MIGRATION_RETRY_MS  100
 
-/* Should be called only after beginning the domain leave process.
+/*
+ * Should be called only after beginning the domain leave process.
  * There should not be any remaining locks on nonlocal lock resources,
  * and there should be no local locks left on locally mastered resources.
  *
  * Called with the dlm spinlock held, may drop it to do migration, but
  * will re-acquire before exit.
  *
- * Returns: 1 if dlm->spinlock was dropped/retaken, 0 if never dropped */
+ * Returns: 1 if dlm->spinlock was dropped/retaken, 0 if never dropped
+ */
 int dlm_empty_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res)
 {
        int ret;
        int lock_dropped = 0;
-       int numlocks, hasrefs;
+       u8 target = O2NM_MAX_NODES;
+
+       assert_spin_locked(&dlm->spinlock);
 
        spin_lock(&res->spinlock);
-       if (res->owner != dlm->node_num) {
-               if (!__dlm_lockres_unused(res)) {
-                       mlog(ML_ERROR, "%s:%.*s: this node is not master, "
-                            "trying to free this but locks remain\n",
-                            dlm->name, res->lockname.len, res->lockname.name);
-               }
-               spin_unlock(&res->spinlock);
-               goto leave;
-       }
+       if (dlm_is_lockres_migrateable(dlm, res))
+               target = dlm_pick_migration_target(dlm, res);
+       spin_unlock(&res->spinlock);
 
-       /* No need to migrate a lockres having no locks */
-       ret = dlm_is_lockres_migrateable(dlm, res, &numlocks, &hasrefs);
-       if (ret >= 0 && numlocks == 0 && !hasrefs) {
-               spin_unlock(&res->spinlock);
+       if (target == O2NM_MAX_NODES)
                goto leave;
-       }
-       spin_unlock(&res->spinlock);
 
        /* Wheee! Migrate lockres here! Will sleep so drop spinlock. */
        spin_unlock(&dlm->spinlock);
        lock_dropped = 1;
-       while (1) {
-               ret = dlm_migrate_lockres(dlm, res, O2NM_MAX_NODES);
-               if (ret >= 0)
-                       break;
-               if (ret == -ENOTEMPTY) {
-                       mlog(ML_ERROR, "lockres %.*s still has local locks!\n",
-                               res->lockname.len, res->lockname.name);
-                       BUG();
-               }
-
-               mlog(0, "lockres %.*s: migrate failed, "
-                    "retrying\n", res->lockname.len,
-                    res->lockname.name);
-               msleep(DLM_MIGRATION_RETRY_MS);
-       }
+       ret = dlm_migrate_lockres(dlm, res, target);
+       if (ret)
+               mlog(0, "%s: res %.*s, Migrate to node %u failed with %d\n",
+                    dlm->name, res->lockname.len, res->lockname.name,
+                    target, ret);
        spin_lock(&dlm->spinlock);
 leave:
        return lock_dropped;
@@ -2898,61 +2829,55 @@ static void dlm_remove_nonlocal_locks(struct dlm_ctxt *dlm,
        }
 }
 
-/* for now this is not too intelligent.  we will
- * need stats to make this do the right thing.
- * this just finds the first lock on one of the
- * queues and uses that node as the target. */
+/*
+ * Pick a node to migrate the lock resource to. This function selects a
+ * potential target based first on the locks and then on refmap. It skips
+ * nodes that are in the process of exiting the domain.
+ */
 static u8 dlm_pick_migration_target(struct dlm_ctxt *dlm,
                                    struct dlm_lock_resource *res)
 {
-       int i;
+       enum dlm_lockres_list idx;
        struct list_head *queue = &res->granted;
        struct dlm_lock *lock;
-       int nodenum;
+       int noderef;
+       u8 nodenum = O2NM_MAX_NODES;
 
        assert_spin_locked(&dlm->spinlock);
+       assert_spin_locked(&res->spinlock);
 
-       spin_lock(&res->spinlock);
-       for (i=0; i<3; i++) {
+       /* Go through all the locks */
+       for (idx = DLM_GRANTED_LIST; idx <= DLM_BLOCKED_LIST; idx++) {
+               queue = dlm_list_idx_to_ptr(res, idx);
                list_for_each_entry(lock, queue, list) {
-                       /* up to the caller to make sure this node
-                        * is alive */
-                       if (lock->ml.node != dlm->node_num) {
-                               spin_unlock(&res->spinlock);
-                               return lock->ml.node;
-                       }
+                       if (lock->ml.node == dlm->node_num)
+                               continue;
+                       if (test_bit(lock->ml.node, dlm->exit_domain_map))
+                               continue;
+                       nodenum = lock->ml.node;
+                       goto bail;
                }
-               queue++;
-       }
-
-       nodenum = find_next_bit(res->refmap, O2NM_MAX_NODES, 0);
-       if (nodenum < O2NM_MAX_NODES) {
-               spin_unlock(&res->spinlock);
-               return nodenum;
        }
-       spin_unlock(&res->spinlock);
-       mlog(0, "have not found a suitable target yet! checking domain map\n");
 
-       /* ok now we're getting desperate.  pick anyone alive. */
-       nodenum = -1;
+       /* Go thru the refmap */
+       noderef = -1;
        while (1) {
-               nodenum = find_next_bit(dlm->domain_map,
-                                       O2NM_MAX_NODES, nodenum+1);
-               mlog(0, "found %d in domain map\n", nodenum);
-               if (nodenum >= O2NM_MAX_NODES)
+               noderef = find_next_bit(res->refmap, O2NM_MAX_NODES,
+                                       noderef + 1);
+               if (noderef >= O2NM_MAX_NODES)
                        break;
-               if (nodenum != dlm->node_num) {
-                       mlog(0, "picking %d\n", nodenum);
-                       return nodenum;
-               }
+               if (noderef == dlm->node_num)
+                       continue;
+               if (test_bit(noderef, dlm->exit_domain_map))
+                       continue;
+               nodenum = noderef;
+               goto bail;
        }
 
-       mlog(0, "giving up.  no master to migrate to\n");
-       return DLM_LOCK_RES_OWNER_UNKNOWN;
+bail:
+       return nodenum;
 }
 
-
-
 /* this is called by the new master once all lockres
  * data has been received */
 static int dlm_do_migrate_request(struct dlm_ctxt *dlm,
index f1beb6fc254d1720ae10b10a0a7ea904703c7d0d..7efab6d28a21b4ee6a8376559d70f739a4e1da90 100644 (file)
@@ -2393,6 +2393,7 @@ static void __dlm_hb_node_down(struct dlm_ctxt *dlm, int idx)
 
        mlog(0, "node %u being removed from domain map!\n", idx);
        clear_bit(idx, dlm->domain_map);
+       clear_bit(idx, dlm->exit_domain_map);
        /* wake up migration waiters if a node goes down.
         * perhaps later we can genericize this for other waiters. */
        wake_up(&dlm->migration_wq);
index 8c5c0eddc365a060d278d49dac042226fafa0515..b420767970492082b357cf67f8735894dd7e103f 100644 (file)
@@ -88,7 +88,7 @@ struct workqueue_struct *user_dlm_worker;
  *               signifies a bast fired on the lock.
  */
 #define DLMFS_CAPABILITIES "bast stackglue"
-extern int param_set_dlmfs_capabilities(const char *val,
+static int param_set_dlmfs_capabilities(const char *val,
                                        struct kernel_param *kp)
 {
        printk(KERN_ERR "%s: readonly parameter\n", kp->name);
index 89659d6dc2067276f2cebcea63a9bcc34a0a2486..b1e35a392ca5279d7aa7d645aa75fd8c101c6d05 100644 (file)
@@ -2670,6 +2670,7 @@ const struct file_operations ocfs2_fops_no_plocks = {
        .flock          = ocfs2_flock,
        .splice_read    = ocfs2_file_splice_read,
        .splice_write   = ocfs2_file_splice_write,
+       .fallocate      = ocfs2_fallocate,
 };
 
 const struct file_operations ocfs2_dops_no_plocks = {
index 8f13c5989eaeeecd543be983cec37176c1c54ece..bc91072b72196fd335c4b7cbc02ba08cb67254e6 100644 (file)
 #include "ioctl.h"
 #include "resize.h"
 #include "refcounttree.h"
+#include "sysfile.h"
+#include "dir.h"
+#include "buffer_head_io.h"
+#include "suballoc.h"
+#include "move_extents.h"
 
 #include <linux/ext2_fs.h>
 
  * be -EFAULT.  The error will be returned from the ioctl(2) call.  It's
  * just a best-effort to tell userspace that this request caused the error.
  */
-static inline void __o2info_set_request_error(struct ocfs2_info_request *kreq,
+static inline void o2info_set_request_error(struct ocfs2_info_request *kreq,
                                        struct ocfs2_info_request __user *req)
 {
        kreq->ir_flags |= OCFS2_INFO_FL_ERROR;
        (void)put_user(kreq->ir_flags, (__u32 __user *)&(req->ir_flags));
 }
 
-#define o2info_set_request_error(a, b) \
-               __o2info_set_request_error((struct ocfs2_info_request *)&(a), b)
-
-static inline void __o2info_set_request_filled(struct ocfs2_info_request *req)
+static inline void o2info_set_request_filled(struct ocfs2_info_request *req)
 {
        req->ir_flags |= OCFS2_INFO_FL_FILLED;
 }
 
-#define o2info_set_request_filled(a) \
-               __o2info_set_request_filled((struct ocfs2_info_request *)&(a))
-
-static inline void __o2info_clear_request_filled(struct ocfs2_info_request *req)
+static inline void o2info_clear_request_filled(struct ocfs2_info_request *req)
 {
        req->ir_flags &= ~OCFS2_INFO_FL_FILLED;
 }
 
-#define o2info_clear_request_filled(a) \
-               __o2info_clear_request_filled((struct ocfs2_info_request *)&(a))
+static inline int o2info_coherent(struct ocfs2_info_request *req)
+{
+       return (!(req->ir_flags & OCFS2_INFO_FL_NON_COHERENT));
+}
 
 static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags)
 {
@@ -153,7 +154,7 @@ int ocfs2_info_handle_blocksize(struct inode *inode,
 
        oib.ib_blocksize = inode->i_sb->s_blocksize;
 
-       o2info_set_request_filled(oib);
+       o2info_set_request_filled(&oib.ib_req);
 
        if (o2info_to_user(oib, req))
                goto bail;
@@ -161,7 +162,7 @@ int ocfs2_info_handle_blocksize(struct inode *inode,
        status = 0;
 bail:
        if (status)
-               o2info_set_request_error(oib, req);
+               o2info_set_request_error(&oib.ib_req, req);
 
        return status;
 }
@@ -178,7 +179,7 @@ int ocfs2_info_handle_clustersize(struct inode *inode,
 
        oic.ic_clustersize = osb->s_clustersize;
 
-       o2info_set_request_filled(oic);
+       o2info_set_request_filled(&oic.ic_req);
 
        if (o2info_to_user(oic, req))
                goto bail;
@@ -186,7 +187,7 @@ int ocfs2_info_handle_clustersize(struct inode *inode,
        status = 0;
 bail:
        if (status)
-               o2info_set_request_error(oic, req);
+               o2info_set_request_error(&oic.ic_req, req);
 
        return status;
 }
@@ -203,7 +204,7 @@ int ocfs2_info_handle_maxslots(struct inode *inode,
 
        oim.im_max_slots = osb->max_slots;
 
-       o2info_set_request_filled(oim);
+       o2info_set_request_filled(&oim.im_req);
 
        if (o2info_to_user(oim, req))
                goto bail;
@@ -211,7 +212,7 @@ int ocfs2_info_handle_maxslots(struct inode *inode,
        status = 0;
 bail:
        if (status)
-               o2info_set_request_error(oim, req);
+               o2info_set_request_error(&oim.im_req, req);
 
        return status;
 }
@@ -228,7 +229,7 @@ int ocfs2_info_handle_label(struct inode *inode,
 
        memcpy(oil.il_label, osb->vol_label, OCFS2_MAX_VOL_LABEL_LEN);
 
-       o2info_set_request_filled(oil);
+       o2info_set_request_filled(&oil.il_req);
 
        if (o2info_to_user(oil, req))
                goto bail;
@@ -236,7 +237,7 @@ int ocfs2_info_handle_label(struct inode *inode,
        status = 0;
 bail:
        if (status)
-               o2info_set_request_error(oil, req);
+               o2info_set_request_error(&oil.il_req, req);
 
        return status;
 }
@@ -253,7 +254,7 @@ int ocfs2_info_handle_uuid(struct inode *inode,
 
        memcpy(oiu.iu_uuid_str, osb->uuid_str, OCFS2_TEXT_UUID_LEN + 1);
 
-       o2info_set_request_filled(oiu);
+       o2info_set_request_filled(&oiu.iu_req);
 
        if (o2info_to_user(oiu, req))
                goto bail;
@@ -261,7 +262,7 @@ int ocfs2_info_handle_uuid(struct inode *inode,
        status = 0;
 bail:
        if (status)
-               o2info_set_request_error(oiu, req);
+               o2info_set_request_error(&oiu.iu_req, req);
 
        return status;
 }
@@ -280,7 +281,7 @@ int ocfs2_info_handle_fs_features(struct inode *inode,
        oif.if_incompat_features = osb->s_feature_incompat;
        oif.if_ro_compat_features = osb->s_feature_ro_compat;
 
-       o2info_set_request_filled(oif);
+       o2info_set_request_filled(&oif.if_req);
 
        if (o2info_to_user(oif, req))
                goto bail;
@@ -288,7 +289,7 @@ int ocfs2_info_handle_fs_features(struct inode *inode,
        status = 0;
 bail:
        if (status)
-               o2info_set_request_error(oif, req);
+               o2info_set_request_error(&oif.if_req, req);
 
        return status;
 }
@@ -305,7 +306,7 @@ int ocfs2_info_handle_journal_size(struct inode *inode,
 
        oij.ij_journal_size = osb->journal->j_inode->i_size;
 
-       o2info_set_request_filled(oij);
+       o2info_set_request_filled(&oij.ij_req);
 
        if (o2info_to_user(oij, req))
                goto bail;
@@ -313,7 +314,408 @@ int ocfs2_info_handle_journal_size(struct inode *inode,
        status = 0;
 bail:
        if (status)
-               o2info_set_request_error(oij, req);
+               o2info_set_request_error(&oij.ij_req, req);
+
+       return status;
+}
+
+int ocfs2_info_scan_inode_alloc(struct ocfs2_super *osb,
+                               struct inode *inode_alloc, u64 blkno,
+                               struct ocfs2_info_freeinode *fi, u32 slot)
+{
+       int status = 0, unlock = 0;
+
+       struct buffer_head *bh = NULL;
+       struct ocfs2_dinode *dinode_alloc = NULL;
+
+       if (inode_alloc)
+               mutex_lock(&inode_alloc->i_mutex);
+
+       if (o2info_coherent(&fi->ifi_req)) {
+               status = ocfs2_inode_lock(inode_alloc, &bh, 0);
+               if (status < 0) {
+                       mlog_errno(status);
+                       goto bail;
+               }
+               unlock = 1;
+       } else {
+               status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh);
+               if (status < 0) {
+                       mlog_errno(status);
+                       goto bail;
+               }
+       }
+
+       dinode_alloc = (struct ocfs2_dinode *)bh->b_data;
+
+       fi->ifi_stat[slot].lfi_total =
+               le32_to_cpu(dinode_alloc->id1.bitmap1.i_total);
+       fi->ifi_stat[slot].lfi_free =
+               le32_to_cpu(dinode_alloc->id1.bitmap1.i_total) -
+               le32_to_cpu(dinode_alloc->id1.bitmap1.i_used);
+
+bail:
+       if (unlock)
+               ocfs2_inode_unlock(inode_alloc, 0);
+
+       if (inode_alloc)
+               mutex_unlock(&inode_alloc->i_mutex);
+
+       brelse(bh);
+
+       return status;
+}
+
+int ocfs2_info_handle_freeinode(struct inode *inode,
+                               struct ocfs2_info_request __user *req)
+{
+       u32 i;
+       u64 blkno = -1;
+       char namebuf[40];
+       int status = -EFAULT, type = INODE_ALLOC_SYSTEM_INODE;
+       struct ocfs2_info_freeinode *oifi = NULL;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct inode *inode_alloc = NULL;
+
+       oifi = kzalloc(sizeof(struct ocfs2_info_freeinode), GFP_KERNEL);
+       if (!oifi) {
+               status = -ENOMEM;
+               mlog_errno(status);
+               goto bail;
+       }
+
+       if (o2info_from_user(*oifi, req))
+               goto bail;
+
+       oifi->ifi_slotnum = osb->max_slots;
+
+       for (i = 0; i < oifi->ifi_slotnum; i++) {
+               if (o2info_coherent(&oifi->ifi_req)) {
+                       inode_alloc = ocfs2_get_system_file_inode(osb, type, i);
+                       if (!inode_alloc) {
+                               mlog(ML_ERROR, "unable to get alloc inode in "
+                                   "slot %u\n", i);
+                               status = -EIO;
+                               goto bail;
+                       }
+               } else {
+                       ocfs2_sprintf_system_inode_name(namebuf,
+                                                       sizeof(namebuf),
+                                                       type, i);
+                       status = ocfs2_lookup_ino_from_name(osb->sys_root_inode,
+                                                           namebuf,
+                                                           strlen(namebuf),
+                                                           &blkno);
+                       if (status < 0) {
+                               status = -ENOENT;
+                               goto bail;
+                       }
+               }
+
+               status = ocfs2_info_scan_inode_alloc(osb, inode_alloc, blkno, oifi, i);
+               if (status < 0)
+                       goto bail;
+
+               iput(inode_alloc);
+               inode_alloc = NULL;
+       }
+
+       o2info_set_request_filled(&oifi->ifi_req);
+
+       if (o2info_to_user(*oifi, req))
+               goto bail;
+
+       status = 0;
+bail:
+       if (status)
+               o2info_set_request_error(&oifi->ifi_req, req);
+
+       kfree(oifi);
+
+       return status;
+}
+
+static void o2ffg_update_histogram(struct ocfs2_info_free_chunk_list *hist,
+                                  unsigned int chunksize)
+{
+       int index;
+
+       index = __ilog2_u32(chunksize);
+       if (index >= OCFS2_INFO_MAX_HIST)
+               index = OCFS2_INFO_MAX_HIST - 1;
+
+       hist->fc_chunks[index]++;
+       hist->fc_clusters[index] += chunksize;
+}
+
+static void o2ffg_update_stats(struct ocfs2_info_freefrag_stats *stats,
+                              unsigned int chunksize)
+{
+       if (chunksize > stats->ffs_max)
+               stats->ffs_max = chunksize;
+
+       if (chunksize < stats->ffs_min)
+               stats->ffs_min = chunksize;
+
+       stats->ffs_avg += chunksize;
+       stats->ffs_free_chunks_real++;
+}
+
+void ocfs2_info_update_ffg(struct ocfs2_info_freefrag *ffg,
+                          unsigned int chunksize)
+{
+       o2ffg_update_histogram(&(ffg->iff_ffs.ffs_fc_hist), chunksize);
+       o2ffg_update_stats(&(ffg->iff_ffs), chunksize);
+}
+
+int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb,
+                                  struct inode *gb_inode,
+                                  struct ocfs2_dinode *gb_dinode,
+                                  struct ocfs2_chain_rec *rec,
+                                  struct ocfs2_info_freefrag *ffg,
+                                  u32 chunks_in_group)
+{
+       int status = 0, used;
+       u64 blkno;
+
+       struct buffer_head *bh = NULL;
+       struct ocfs2_group_desc *bg = NULL;
+
+       unsigned int max_bits, num_clusters;
+       unsigned int offset = 0, cluster, chunk;
+       unsigned int chunk_free, last_chunksize = 0;
+
+       if (!le32_to_cpu(rec->c_free))
+               goto bail;
+
+       do {
+               if (!bg)
+                       blkno = le64_to_cpu(rec->c_blkno);
+               else
+                       blkno = le64_to_cpu(bg->bg_next_group);
+
+               if (bh) {
+                       brelse(bh);
+                       bh = NULL;
+               }
+
+               if (o2info_coherent(&ffg->iff_req))
+                       status = ocfs2_read_group_descriptor(gb_inode,
+                                                            gb_dinode,
+                                                            blkno, &bh);
+               else
+                       status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh);
+
+               if (status < 0) {
+                       mlog(ML_ERROR, "Can't read the group descriptor # "
+                            "%llu from device.", (unsigned long long)blkno);
+                       status = -EIO;
+                       goto bail;
+               }
+
+               bg = (struct ocfs2_group_desc *)bh->b_data;
+
+               if (!le16_to_cpu(bg->bg_free_bits_count))
+                       continue;
+
+               max_bits = le16_to_cpu(bg->bg_bits);
+               offset = 0;
+
+               for (chunk = 0; chunk < chunks_in_group; chunk++) {
+                       /*
+                        * last chunk may be not an entire one.
+                        */
+                       if ((offset + ffg->iff_chunksize) > max_bits)
+                               num_clusters = max_bits - offset;
+                       else
+                               num_clusters = ffg->iff_chunksize;
+
+                       chunk_free = 0;
+                       for (cluster = 0; cluster < num_clusters; cluster++) {
+                               used = ocfs2_test_bit(offset,
+                                               (unsigned long *)bg->bg_bitmap);
+                               /*
+                                * - chunk_free counts free clusters in #N chunk.
+                                * - last_chunksize records the size(in) clusters
+                                *   for the last real free chunk being counted.
+                                */
+                               if (!used) {
+                                       last_chunksize++;
+                                       chunk_free++;
+                               }
+
+                               if (used && last_chunksize) {
+                                       ocfs2_info_update_ffg(ffg,
+                                                             last_chunksize);
+                                       last_chunksize = 0;
+                               }
+
+                               offset++;
+                       }
+
+                       if (chunk_free == ffg->iff_chunksize)
+                               ffg->iff_ffs.ffs_free_chunks++;
+               }
+
+               /*
+                * need to update the info for last free chunk.
+                */
+               if (last_chunksize)
+                       ocfs2_info_update_ffg(ffg, last_chunksize);
+
+       } while (le64_to_cpu(bg->bg_next_group));
+
+bail:
+       brelse(bh);
+
+       return status;
+}
+
+int ocfs2_info_freefrag_scan_bitmap(struct ocfs2_super *osb,
+                                   struct inode *gb_inode, u64 blkno,
+                                   struct ocfs2_info_freefrag *ffg)
+{
+       u32 chunks_in_group;
+       int status = 0, unlock = 0, i;
+
+       struct buffer_head *bh = NULL;
+       struct ocfs2_chain_list *cl = NULL;
+       struct ocfs2_chain_rec *rec = NULL;
+       struct ocfs2_dinode *gb_dinode = NULL;
+
+       if (gb_inode)
+               mutex_lock(&gb_inode->i_mutex);
+
+       if (o2info_coherent(&ffg->iff_req)) {
+               status = ocfs2_inode_lock(gb_inode, &bh, 0);
+               if (status < 0) {
+                       mlog_errno(status);
+                       goto bail;
+               }
+               unlock = 1;
+       } else {
+               status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh);
+               if (status < 0) {
+                       mlog_errno(status);
+                       goto bail;
+               }
+       }
+
+       gb_dinode = (struct ocfs2_dinode *)bh->b_data;
+       cl = &(gb_dinode->id2.i_chain);
+
+       /*
+        * Chunksize(in) clusters from userspace should be
+        * less than clusters in a group.
+        */
+       if (ffg->iff_chunksize > le16_to_cpu(cl->cl_cpg)) {
+               status = -EINVAL;
+               goto bail;
+       }
+
+       memset(&ffg->iff_ffs, 0, sizeof(struct ocfs2_info_freefrag_stats));
+
+       ffg->iff_ffs.ffs_min = ~0U;
+       ffg->iff_ffs.ffs_clusters =
+                       le32_to_cpu(gb_dinode->id1.bitmap1.i_total);
+       ffg->iff_ffs.ffs_free_clusters = ffg->iff_ffs.ffs_clusters -
+                       le32_to_cpu(gb_dinode->id1.bitmap1.i_used);
+
+       chunks_in_group = le16_to_cpu(cl->cl_cpg) / ffg->iff_chunksize + 1;
+
+       for (i = 0; i < le16_to_cpu(cl->cl_next_free_rec); i++) {
+               rec = &(cl->cl_recs[i]);
+               status = ocfs2_info_freefrag_scan_chain(osb, gb_inode,
+                                                       gb_dinode,
+                                                       rec, ffg,
+                                                       chunks_in_group);
+               if (status)
+                       goto bail;
+       }
+
+       if (ffg->iff_ffs.ffs_free_chunks_real)
+               ffg->iff_ffs.ffs_avg = (ffg->iff_ffs.ffs_avg /
+                                       ffg->iff_ffs.ffs_free_chunks_real);
+bail:
+       if (unlock)
+               ocfs2_inode_unlock(gb_inode, 0);
+
+       if (gb_inode)
+               mutex_unlock(&gb_inode->i_mutex);
+
+       if (gb_inode)
+               iput(gb_inode);
+
+       brelse(bh);
+
+       return status;
+}
+
+int ocfs2_info_handle_freefrag(struct inode *inode,
+                              struct ocfs2_info_request __user *req)
+{
+       u64 blkno = -1;
+       char namebuf[40];
+       int status = -EFAULT, type = GLOBAL_BITMAP_SYSTEM_INODE;
+
+       struct ocfs2_info_freefrag *oiff;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct inode *gb_inode = NULL;
+
+       oiff = kzalloc(sizeof(struct ocfs2_info_freefrag), GFP_KERNEL);
+       if (!oiff) {
+               status = -ENOMEM;
+               mlog_errno(status);
+               goto bail;
+       }
+
+       if (o2info_from_user(*oiff, req))
+               goto bail;
+       /*
+        * chunksize from userspace should be power of 2.
+        */
+       if ((oiff->iff_chunksize & (oiff->iff_chunksize - 1)) ||
+           (!oiff->iff_chunksize)) {
+               status = -EINVAL;
+               goto bail;
+       }
+
+       if (o2info_coherent(&oiff->iff_req)) {
+               gb_inode = ocfs2_get_system_file_inode(osb, type,
+                                                      OCFS2_INVALID_SLOT);
+               if (!gb_inode) {
+                       mlog(ML_ERROR, "unable to get global_bitmap inode\n");
+                       status = -EIO;
+                       goto bail;
+               }
+       } else {
+               ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf), type,
+                                               OCFS2_INVALID_SLOT);
+               status = ocfs2_lookup_ino_from_name(osb->sys_root_inode,
+                                                   namebuf,
+                                                   strlen(namebuf),
+                                                   &blkno);
+               if (status < 0) {
+                       status = -ENOENT;
+                       goto bail;
+               }
+       }
+
+       status = ocfs2_info_freefrag_scan_bitmap(osb, gb_inode, blkno, oiff);
+       if (status < 0)
+               goto bail;
+
+       o2info_set_request_filled(&oiff->iff_req);
+
+       if (o2info_to_user(*oiff, req))
+               goto bail;
+
+       status = 0;
+bail:
+       if (status)
+               o2info_set_request_error(&oiff->iff_req, req);
+
+       kfree(oiff);
 
        return status;
 }
@@ -327,7 +729,7 @@ int ocfs2_info_handle_unknown(struct inode *inode,
        if (o2info_from_user(oir, req))
                goto bail;
 
-       o2info_clear_request_filled(oir);
+       o2info_clear_request_filled(&oir);
 
        if (o2info_to_user(oir, req))
                goto bail;
@@ -335,7 +737,7 @@ int ocfs2_info_handle_unknown(struct inode *inode,
        status = 0;
 bail:
        if (status)
-               o2info_set_request_error(oir, req);
+               o2info_set_request_error(&oir, req);
 
        return status;
 }
@@ -389,6 +791,14 @@ int ocfs2_info_handle_request(struct inode *inode,
                if (oir.ir_size == sizeof(struct ocfs2_info_journal_size))
                        status = ocfs2_info_handle_journal_size(inode, req);
                break;
+       case OCFS2_INFO_FREEINODE:
+               if (oir.ir_size == sizeof(struct ocfs2_info_freeinode))
+                       status = ocfs2_info_handle_freeinode(inode, req);
+               break;
+       case OCFS2_INFO_FREEFRAG:
+               if (oir.ir_size == sizeof(struct ocfs2_info_freefrag))
+                       status = ocfs2_info_handle_freefrag(inode, req);
+               break;
        default:
                status = ocfs2_info_handle_unknown(inode, req);
                break;
@@ -542,6 +952,31 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                        return -EFAULT;
 
                return ocfs2_info_handle(inode, &info, 0);
+       case FITRIM:
+       {
+               struct super_block *sb = inode->i_sb;
+               struct fstrim_range range;
+               int ret = 0;
+
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+
+               if (copy_from_user(&range, (struct fstrim_range *)arg,
+                   sizeof(range)))
+                       return -EFAULT;
+
+               ret = ocfs2_trim_fs(sb, &range);
+               if (ret < 0)
+                       return ret;
+
+               if (copy_to_user((struct fstrim_range *)arg, &range,
+                   sizeof(range)))
+                       return -EFAULT;
+
+               return 0;
+       }
+       case OCFS2_IOC_MOVE_EXT:
+               return ocfs2_ioctl_move_extents(filp, (void __user *)arg);
        default:
                return -ENOTTY;
        }
@@ -569,6 +1004,7 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
        case OCFS2_IOC_GROUP_EXTEND:
        case OCFS2_IOC_GROUP_ADD:
        case OCFS2_IOC_GROUP_ADD64:
+       case FITRIM:
                break;
        case OCFS2_IOC_REFLINK:
                if (copy_from_user(&args, (struct reflink_arguments *)arg,
@@ -584,6 +1020,8 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
                        return -EFAULT;
 
                return ocfs2_info_handle(inode, &info, 1);
+       case OCFS2_IOC_MOVE_EXT:
+               break;
        default:
                return -ENOIOCTLCMD;
        }
diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c
new file mode 100644 (file)
index 0000000..cd94270
--- /dev/null
@@ -0,0 +1,1152 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * move_extents.c
+ *
+ * Copyright (C) 2011 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License 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.
+ */
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/mount.h>
+#include <linux/swap.h>
+
+#include <cluster/masklog.h>
+
+#include "ocfs2.h"
+#include "ocfs2_ioctl.h"
+
+#include "alloc.h"
+#include "aops.h"
+#include "dlmglue.h"
+#include "extent_map.h"
+#include "inode.h"
+#include "journal.h"
+#include "suballoc.h"
+#include "uptodate.h"
+#include "super.h"
+#include "dir.h"
+#include "buffer_head_io.h"
+#include "sysfile.h"
+#include "suballoc.h"
+#include "refcounttree.h"
+#include "move_extents.h"
+
+struct ocfs2_move_extents_context {
+       struct inode *inode;
+       struct file *file;
+       int auto_defrag;
+       int partial;
+       int credits;
+       u32 new_phys_cpos;
+       u32 clusters_moved;
+       u64 refcount_loc;
+       struct ocfs2_move_extents *range;
+       struct ocfs2_extent_tree et;
+       struct ocfs2_alloc_context *meta_ac;
+       struct ocfs2_alloc_context *data_ac;
+       struct ocfs2_cached_dealloc_ctxt dealloc;
+};
+
+static int __ocfs2_move_extent(handle_t *handle,
+                              struct ocfs2_move_extents_context *context,
+                              u32 cpos, u32 len, u32 p_cpos, u32 new_p_cpos,
+                              int ext_flags)
+{
+       int ret = 0, index;
+       struct inode *inode = context->inode;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct ocfs2_extent_rec *rec, replace_rec;
+       struct ocfs2_path *path = NULL;
+       struct ocfs2_extent_list *el;
+       u64 ino = ocfs2_metadata_cache_owner(context->et.et_ci);
+       u64 old_blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cpos);
+
+       ret = ocfs2_duplicate_clusters_by_page(handle, context->file, cpos,
+                                              p_cpos, new_p_cpos, len);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       memset(&replace_rec, 0, sizeof(replace_rec));
+       replace_rec.e_cpos = cpu_to_le32(cpos);
+       replace_rec.e_leaf_clusters = cpu_to_le16(len);
+       replace_rec.e_blkno = cpu_to_le64(ocfs2_clusters_to_blocks(inode->i_sb,
+                                                                  new_p_cpos));
+
+       path = ocfs2_new_path_from_et(&context->et);
+       if (!path) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_find_path(INODE_CACHE(inode), path, cpos);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       el = path_leaf_el(path);
+
+       index = ocfs2_search_extent_list(el, cpos);
+       if (index == -1 || index >= le16_to_cpu(el->l_next_free_rec)) {
+               ocfs2_error(inode->i_sb,
+                           "Inode %llu has an extent at cpos %u which can no "
+                           "longer be found.\n",
+                           (unsigned long long)ino, cpos);
+               ret = -EROFS;
+               goto out;
+       }
+
+       rec = &el->l_recs[index];
+
+       BUG_ON(ext_flags != rec->e_flags);
+       /*
+        * after moving/defraging to new location, the extent is not going
+        * to be refcounted anymore.
+        */
+       replace_rec.e_flags = ext_flags & ~OCFS2_EXT_REFCOUNTED;
+
+       ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode),
+                                     context->et.et_root_bh,
+                                     OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_split_extent(handle, &context->et, path, index,
+                                &replace_rec, context->meta_ac,
+                                &context->dealloc);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ocfs2_journal_dirty(handle, context->et.et_root_bh);
+
+       context->new_phys_cpos = new_p_cpos;
+
+       /*
+        * need I to append truncate log for old clusters?
+        */
+       if (old_blkno) {
+               if (ext_flags & OCFS2_EXT_REFCOUNTED)
+                       ret = ocfs2_decrease_refcount(inode, handle,
+                                       ocfs2_blocks_to_clusters(osb->sb,
+                                                                old_blkno),
+                                       len, context->meta_ac,
+                                       &context->dealloc, 1);
+               else
+                       ret = ocfs2_truncate_log_append(osb, handle,
+                                                       old_blkno, len);
+       }
+
+out:
+       return ret;
+}
+
+/*
+ * lock allocators, and reserving appropriate number of bits for
+ * meta blocks and data clusters.
+ *
+ * in some cases, we don't need to reserve clusters, just let data_ac
+ * be NULL.
+ */
+static int ocfs2_lock_allocators_move_extents(struct inode *inode,
+                                       struct ocfs2_extent_tree *et,
+                                       u32 clusters_to_move,
+                                       u32 extents_to_split,
+                                       struct ocfs2_alloc_context **meta_ac,
+                                       struct ocfs2_alloc_context **data_ac,
+                                       int extra_blocks,
+                                       int *credits)
+{
+       int ret, num_free_extents;
+       unsigned int max_recs_needed = 2 * extents_to_split + clusters_to_move;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       num_free_extents = ocfs2_num_free_extents(osb, et);
+       if (num_free_extents < 0) {
+               ret = num_free_extents;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       if (!num_free_extents ||
+           (ocfs2_sparse_alloc(osb) && num_free_extents < max_recs_needed))
+               extra_blocks += ocfs2_extend_meta_needed(et->et_root_el);
+
+       ret = ocfs2_reserve_new_metadata_blocks(osb, extra_blocks, meta_ac);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       if (data_ac) {
+               ret = ocfs2_reserve_clusters(osb, clusters_to_move, data_ac);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       *credits += ocfs2_calc_extend_credits(osb->sb, et->et_root_el,
+                                             clusters_to_move + 2);
+
+       mlog(0, "reserve metadata_blocks: %d, data_clusters: %u, credits: %d\n",
+            extra_blocks, clusters_to_move, *credits);
+out:
+       if (ret) {
+               if (*meta_ac) {
+                       ocfs2_free_alloc_context(*meta_ac);
+                       *meta_ac = NULL;
+               }
+       }
+
+       return ret;
+}
+
+/*
+ * Using one journal handle to guarantee the data consistency in case
+ * crash happens anywhere.
+ *
+ *  XXX: defrag can end up with finishing partial extent as requested,
+ * due to not enough contiguous clusters can be found in allocator.
+ */
+static int ocfs2_defrag_extent(struct ocfs2_move_extents_context *context,
+                              u32 cpos, u32 phys_cpos, u32 *len, int ext_flags)
+{
+       int ret, credits = 0, extra_blocks = 0, partial = context->partial;
+       handle_t *handle;
+       struct inode *inode = context->inode;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct inode *tl_inode = osb->osb_tl_inode;
+       struct ocfs2_refcount_tree *ref_tree = NULL;
+       u32 new_phys_cpos, new_len;
+       u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
+
+       if ((ext_flags & OCFS2_EXT_REFCOUNTED) && *len) {
+
+               BUG_ON(!(OCFS2_I(inode)->ip_dyn_features &
+                        OCFS2_HAS_REFCOUNT_FL));
+
+               BUG_ON(!context->refcount_loc);
+
+               ret = ocfs2_lock_refcount_tree(osb, context->refcount_loc, 1,
+                                              &ref_tree, NULL);
+               if (ret) {
+                       mlog_errno(ret);
+                       return ret;
+               }
+
+               ret = ocfs2_prepare_refcount_change_for_del(inode,
+                                                       context->refcount_loc,
+                                                       phys_blkno,
+                                                       *len,
+                                                       &credits,
+                                                       &extra_blocks);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       ret = ocfs2_lock_allocators_move_extents(inode, &context->et, *len, 1,
+                                                &context->meta_ac,
+                                                &context->data_ac,
+                                                extra_blocks, &credits);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       /*
+        * should be using allocation reservation strategy there?
+        *
+        * if (context->data_ac)
+        *      context->data_ac->ac_resv = &OCFS2_I(inode)->ip_la_data_resv;
+        */
+
+       mutex_lock(&tl_inode->i_mutex);
+
+       if (ocfs2_truncate_log_needs_flush(osb)) {
+               ret = __ocfs2_flush_truncate_log(osb);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out_unlock_mutex;
+               }
+       }
+
+       handle = ocfs2_start_trans(osb, credits);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out_unlock_mutex;
+       }
+
+       ret = __ocfs2_claim_clusters(handle, context->data_ac, 1, *len,
+                                    &new_phys_cpos, &new_len);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       /*
+        * allowing partial extent moving is kind of 'pros and cons', it makes
+        * whole defragmentation less likely to fail, on the contrary, the bad
+        * thing is it may make the fs even more fragmented after moving, let
+        * userspace make a good decision here.
+        */
+       if (new_len != *len) {
+               mlog(0, "len_claimed: %u, len: %u\n", new_len, *len);
+               if (!partial) {
+                       context->range->me_flags &= ~OCFS2_MOVE_EXT_FL_COMPLETE;
+                       ret = -ENOSPC;
+                       goto out_commit;
+               }
+       }
+
+       mlog(0, "cpos: %u, phys_cpos: %u, new_phys_cpos: %u\n", cpos,
+            phys_cpos, new_phys_cpos);
+
+       ret = __ocfs2_move_extent(handle, context, cpos, new_len, phys_cpos,
+                                 new_phys_cpos, ext_flags);
+       if (ret)
+               mlog_errno(ret);
+
+       if (partial && (new_len != *len))
+               *len = new_len;
+
+       /*
+        * Here we should write the new page out first if we are
+        * in write-back mode.
+        */
+       ret = ocfs2_cow_sync_writeback(inode->i_sb, context->inode, cpos, *len);
+       if (ret)
+               mlog_errno(ret);
+
+out_commit:
+       ocfs2_commit_trans(osb, handle);
+
+out_unlock_mutex:
+       mutex_unlock(&tl_inode->i_mutex);
+
+       if (context->data_ac) {
+               ocfs2_free_alloc_context(context->data_ac);
+               context->data_ac = NULL;
+       }
+
+       if (context->meta_ac) {
+               ocfs2_free_alloc_context(context->meta_ac);
+               context->meta_ac = NULL;
+       }
+
+out:
+       if (ref_tree)
+               ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
+
+       return ret;
+}
+
+/*
+ * find the victim alloc group, where #blkno fits.
+ */
+static int ocfs2_find_victim_alloc_group(struct inode *inode,
+                                        u64 vict_blkno,
+                                        int type, int slot,
+                                        int *vict_bit,
+                                        struct buffer_head **ret_bh)
+{
+       int ret, i, bits_per_unit = 0;
+       u64 blkno;
+       char namebuf[40];
+
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct buffer_head *ac_bh = NULL, *gd_bh = NULL;
+       struct ocfs2_chain_list *cl;
+       struct ocfs2_chain_rec *rec;
+       struct ocfs2_dinode *ac_dinode;
+       struct ocfs2_group_desc *bg;
+
+       ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf), type, slot);
+       ret = ocfs2_lookup_ino_from_name(osb->sys_root_inode, namebuf,
+                                        strlen(namebuf), &blkno);
+       if (ret) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       ret = ocfs2_read_blocks_sync(osb, blkno, 1, &ac_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ac_dinode = (struct ocfs2_dinode *)ac_bh->b_data;
+       cl = &(ac_dinode->id2.i_chain);
+       rec = &(cl->cl_recs[0]);
+
+       if (type == GLOBAL_BITMAP_SYSTEM_INODE)
+               bits_per_unit = osb->s_clustersize_bits -
+                                       inode->i_sb->s_blocksize_bits;
+       /*
+        * 'vict_blkno' was out of the valid range.
+        */
+       if ((vict_blkno < le64_to_cpu(rec->c_blkno)) ||
+           (vict_blkno >= (le32_to_cpu(ac_dinode->id1.bitmap1.i_total) <<
+                               bits_per_unit))) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       for (i = 0; i < le16_to_cpu(cl->cl_next_free_rec); i++) {
+
+               rec = &(cl->cl_recs[i]);
+               if (!rec)
+                       continue;
+
+               bg = NULL;
+
+               do {
+                       if (!bg)
+                               blkno = le64_to_cpu(rec->c_blkno);
+                       else
+                               blkno = le64_to_cpu(bg->bg_next_group);
+
+                       if (gd_bh) {
+                               brelse(gd_bh);
+                               gd_bh = NULL;
+                       }
+
+                       ret = ocfs2_read_blocks_sync(osb, blkno, 1, &gd_bh);
+                       if (ret) {
+                               mlog_errno(ret);
+                               goto out;
+                       }
+
+                       bg = (struct ocfs2_group_desc *)gd_bh->b_data;
+
+                       if (vict_blkno < (le64_to_cpu(bg->bg_blkno) +
+                                               le16_to_cpu(bg->bg_bits))) {
+
+                               *ret_bh = gd_bh;
+                               *vict_bit = (vict_blkno - blkno) >>
+                                                       bits_per_unit;
+                               mlog(0, "find the victim group: #%llu, "
+                                    "total_bits: %u, vict_bit: %u\n",
+                                    blkno, le16_to_cpu(bg->bg_bits),
+                                    *vict_bit);
+                               goto out;
+                       }
+
+               } while (le64_to_cpu(bg->bg_next_group));
+       }
+
+       ret = -EINVAL;
+out:
+       brelse(ac_bh);
+
+       /*
+        * caller has to release the gd_bh properly.
+        */
+       return ret;
+}
+
+/*
+ * XXX: helper to validate and adjust moving goal.
+ */
+static int ocfs2_validate_and_adjust_move_goal(struct inode *inode,
+                                              struct ocfs2_move_extents *range)
+{
+       int ret, goal_bit = 0;
+
+       struct buffer_head *gd_bh = NULL;
+       struct ocfs2_group_desc *bg = NULL;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       int c_to_b = 1 << (osb->s_clustersize_bits -
+                                       inode->i_sb->s_blocksize_bits);
+
+       /*
+        * make goal become cluster aligned.
+        */
+       range->me_goal = ocfs2_block_to_cluster_start(inode->i_sb,
+                                                     range->me_goal);
+       /*
+        * moving goal is not allowd to start with a group desc blok(#0 blk)
+        * let's compromise to the latter cluster.
+        */
+       if (range->me_goal == le64_to_cpu(bg->bg_blkno))
+               range->me_goal += c_to_b;
+
+       /*
+        * validate goal sits within global_bitmap, and return the victim
+        * group desc
+        */
+       ret = ocfs2_find_victim_alloc_group(inode, range->me_goal,
+                                           GLOBAL_BITMAP_SYSTEM_INODE,
+                                           OCFS2_INVALID_SLOT,
+                                           &goal_bit, &gd_bh);
+       if (ret)
+               goto out;
+
+       bg = (struct ocfs2_group_desc *)gd_bh->b_data;
+
+       /*
+        * movement is not gonna cross two groups.
+        */
+       if ((le16_to_cpu(bg->bg_bits) - goal_bit) * osb->s_clustersize <
+                                                               range->me_len) {
+               ret = -EINVAL;
+               goto out;
+       }
+       /*
+        * more exact validations/adjustments will be performed later during
+        * moving operation for each extent range.
+        */
+       mlog(0, "extents get ready to be moved to #%llu block\n",
+            range->me_goal);
+
+out:
+       brelse(gd_bh);
+
+       return ret;
+}
+
+static void ocfs2_probe_alloc_group(struct inode *inode, struct buffer_head *bh,
+                                   int *goal_bit, u32 move_len, u32 max_hop,
+                                   u32 *phys_cpos)
+{
+       int i, used, last_free_bits = 0, base_bit = *goal_bit;
+       struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *)bh->b_data;
+       u32 base_cpos = ocfs2_blocks_to_clusters(inode->i_sb,
+                                                le64_to_cpu(gd->bg_blkno));
+
+       for (i = base_bit; i < le16_to_cpu(gd->bg_bits); i++) {
+
+               used = ocfs2_test_bit(i, (unsigned long *)gd->bg_bitmap);
+               if (used) {
+                       /*
+                        * we even tried searching the free chunk by jumping
+                        * a 'max_hop' distance, but still failed.
+                        */
+                       if ((i - base_bit) > max_hop) {
+                               *phys_cpos = 0;
+                               break;
+                       }
+
+                       if (last_free_bits)
+                               last_free_bits = 0;
+
+                       continue;
+               } else
+                       last_free_bits++;
+
+               if (last_free_bits == move_len) {
+                       *goal_bit = i;
+                       *phys_cpos = base_cpos + i;
+                       break;
+               }
+       }
+
+       mlog(0, "found phys_cpos: %u to fit the wanted moving.\n", *phys_cpos);
+}
+
+static int ocfs2_alloc_dinode_update_counts(struct inode *inode,
+                                      handle_t *handle,
+                                      struct buffer_head *di_bh,
+                                      u32 num_bits,
+                                      u16 chain)
+{
+       int ret;
+       u32 tmp_used;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *) di_bh->b_data;
+       struct ocfs2_chain_list *cl =
+                               (struct ocfs2_chain_list *) &di->id2.i_chain;
+
+       ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
+                                     OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       tmp_used = le32_to_cpu(di->id1.bitmap1.i_used);
+       di->id1.bitmap1.i_used = cpu_to_le32(num_bits + tmp_used);
+       le32_add_cpu(&cl->cl_recs[chain].c_free, -num_bits);
+       ocfs2_journal_dirty(handle, di_bh);
+
+out:
+       return ret;
+}
+
+static inline int ocfs2_block_group_set_bits(handle_t *handle,
+                                            struct inode *alloc_inode,
+                                            struct ocfs2_group_desc *bg,
+                                            struct buffer_head *group_bh,
+                                            unsigned int bit_off,
+                                            unsigned int num_bits)
+{
+       int status;
+       void *bitmap = bg->bg_bitmap;
+       int journal_type = OCFS2_JOURNAL_ACCESS_WRITE;
+
+       /* All callers get the descriptor via
+        * ocfs2_read_group_descriptor().  Any corruption is a code bug. */
+       BUG_ON(!OCFS2_IS_VALID_GROUP_DESC(bg));
+       BUG_ON(le16_to_cpu(bg->bg_free_bits_count) < num_bits);
+
+       mlog(0, "block_group_set_bits: off = %u, num = %u\n", bit_off,
+            num_bits);
+
+       if (ocfs2_is_cluster_bitmap(alloc_inode))
+               journal_type = OCFS2_JOURNAL_ACCESS_UNDO;
+
+       status = ocfs2_journal_access_gd(handle,
+                                        INODE_CACHE(alloc_inode),
+                                        group_bh,
+                                        journal_type);
+       if (status < 0) {
+               mlog_errno(status);
+               goto bail;
+       }
+
+       le16_add_cpu(&bg->bg_free_bits_count, -num_bits);
+       if (le16_to_cpu(bg->bg_free_bits_count) > le16_to_cpu(bg->bg_bits)) {
+               ocfs2_error(alloc_inode->i_sb, "Group descriptor # %llu has bit"
+                           " count %u but claims %u are freed. num_bits %d",
+                           (unsigned long long)le64_to_cpu(bg->bg_blkno),
+                           le16_to_cpu(bg->bg_bits),
+                           le16_to_cpu(bg->bg_free_bits_count), num_bits);
+               return -EROFS;
+       }
+       while (num_bits--)
+               ocfs2_set_bit(bit_off++, bitmap);
+
+       ocfs2_journal_dirty(handle, group_bh);
+
+bail:
+       return status;
+}
+
+static int ocfs2_move_extent(struct ocfs2_move_extents_context *context,
+                            u32 cpos, u32 phys_cpos, u32 *new_phys_cpos,
+                            u32 len, int ext_flags)
+{
+       int ret, credits = 0, extra_blocks = 0, goal_bit = 0;
+       handle_t *handle;
+       struct inode *inode = context->inode;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct inode *tl_inode = osb->osb_tl_inode;
+       struct inode *gb_inode = NULL;
+       struct buffer_head *gb_bh = NULL;
+       struct buffer_head *gd_bh = NULL;
+       struct ocfs2_group_desc *gd;
+       struct ocfs2_refcount_tree *ref_tree = NULL;
+       u32 move_max_hop = ocfs2_blocks_to_clusters(inode->i_sb,
+                                                   context->range->me_threshold);
+       u64 phys_blkno, new_phys_blkno;
+
+       phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
+
+       if ((ext_flags & OCFS2_EXT_REFCOUNTED) && len) {
+
+               BUG_ON(!(OCFS2_I(inode)->ip_dyn_features &
+                        OCFS2_HAS_REFCOUNT_FL));
+
+               BUG_ON(!context->refcount_loc);
+
+               ret = ocfs2_lock_refcount_tree(osb, context->refcount_loc, 1,
+                                              &ref_tree, NULL);
+               if (ret) {
+                       mlog_errno(ret);
+                       return ret;
+               }
+
+               ret = ocfs2_prepare_refcount_change_for_del(inode,
+                                                       context->refcount_loc,
+                                                       phys_blkno,
+                                                       len,
+                                                       &credits,
+                                                       &extra_blocks);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       ret = ocfs2_lock_allocators_move_extents(inode, &context->et, len, 1,
+                                                &context->meta_ac,
+                                                NULL, extra_blocks, &credits);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       /*
+        * need to count 2 extra credits for global_bitmap inode and
+        * group descriptor.
+        */
+       credits += OCFS2_INODE_UPDATE_CREDITS + 1;
+
+       /*
+        * ocfs2_move_extent() didn't reserve any clusters in lock_allocators()
+        * logic, while we still need to lock the global_bitmap.
+        */
+       gb_inode = ocfs2_get_system_file_inode(osb, GLOBAL_BITMAP_SYSTEM_INODE,
+                                              OCFS2_INVALID_SLOT);
+       if (!gb_inode) {
+               mlog(ML_ERROR, "unable to get global_bitmap inode\n");
+               ret = -EIO;
+               goto out;
+       }
+
+       mutex_lock(&gb_inode->i_mutex);
+
+       ret = ocfs2_inode_lock(gb_inode, &gb_bh, 1);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_unlock_gb_mutex;
+       }
+
+       mutex_lock(&tl_inode->i_mutex);
+
+       handle = ocfs2_start_trans(osb, credits);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out_unlock_tl_inode;
+       }
+
+       new_phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, *new_phys_cpos);
+       ret = ocfs2_find_victim_alloc_group(inode, new_phys_blkno,
+                                           GLOBAL_BITMAP_SYSTEM_INODE,
+                                           OCFS2_INVALID_SLOT,
+                                           &goal_bit, &gd_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       /*
+        * probe the victim cluster group to find a proper
+        * region to fit wanted movement, it even will perfrom
+        * a best-effort attempt by compromising to a threshold
+        * around the goal.
+        */
+       ocfs2_probe_alloc_group(inode, gd_bh, &goal_bit, len, move_max_hop,
+                               new_phys_cpos);
+       if (!new_phys_cpos) {
+               ret = -ENOSPC;
+               goto out_commit;
+       }
+
+       ret = __ocfs2_move_extent(handle, context, cpos, len, phys_cpos,
+                                 *new_phys_cpos, ext_flags);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       gd = (struct ocfs2_group_desc *)gd_bh->b_data;
+       ret = ocfs2_alloc_dinode_update_counts(gb_inode, handle, gb_bh, len,
+                                              le16_to_cpu(gd->bg_chain));
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       ret = ocfs2_block_group_set_bits(handle, gb_inode, gd, gd_bh,
+                                        goal_bit, len);
+       if (ret)
+               mlog_errno(ret);
+
+       /*
+        * Here we should write the new page out first if we are
+        * in write-back mode.
+        */
+       ret = ocfs2_cow_sync_writeback(inode->i_sb, context->inode, cpos, len);
+       if (ret)
+               mlog_errno(ret);
+
+out_commit:
+       ocfs2_commit_trans(osb, handle);
+       brelse(gd_bh);
+
+out_unlock_tl_inode:
+       mutex_unlock(&tl_inode->i_mutex);
+
+       ocfs2_inode_unlock(gb_inode, 1);
+out_unlock_gb_mutex:
+       mutex_unlock(&gb_inode->i_mutex);
+       brelse(gb_bh);
+       iput(gb_inode);
+
+out:
+       if (context->meta_ac) {
+               ocfs2_free_alloc_context(context->meta_ac);
+               context->meta_ac = NULL;
+       }
+
+       if (ref_tree)
+               ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
+
+       return ret;
+}
+
+/*
+ * Helper to calculate the defraging length in one run according to threshold.
+ */
+static void ocfs2_calc_extent_defrag_len(u32 *alloc_size, u32 *len_defraged,
+                                        u32 threshold, int *skip)
+{
+       if ((*alloc_size + *len_defraged) < threshold) {
+               /*
+                * proceed defragmentation until we meet the thresh
+                */
+               *len_defraged += *alloc_size;
+       } else if (*len_defraged == 0) {
+               /*
+                * XXX: skip a large extent.
+                */
+               *skip = 1;
+       } else {
+               /*
+                * split this extent to coalesce with former pieces as
+                * to reach the threshold.
+                *
+                * we're done here with one cycle of defragmentation
+                * in a size of 'thresh', resetting 'len_defraged'
+                * forces a new defragmentation.
+                */
+               *alloc_size = threshold - *len_defraged;
+               *len_defraged = 0;
+       }
+}
+
+static int __ocfs2_move_extents_range(struct buffer_head *di_bh,
+                               struct ocfs2_move_extents_context *context)
+{
+       int ret = 0, flags, do_defrag, skip = 0;
+       u32 cpos, phys_cpos, move_start, len_to_move, alloc_size;
+       u32 len_defraged = 0, defrag_thresh = 0, new_phys_cpos = 0;
+
+       struct inode *inode = context->inode;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+       struct ocfs2_move_extents *range = context->range;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if ((inode->i_size == 0) || (range->me_len == 0))
+               return 0;
+
+       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+               return 0;
+
+       context->refcount_loc = le64_to_cpu(di->i_refcount_loc);
+
+       ocfs2_init_dinode_extent_tree(&context->et, INODE_CACHE(inode), di_bh);
+       ocfs2_init_dealloc_ctxt(&context->dealloc);
+
+       /*
+        * TO-DO XXX:
+        *
+        * - xattr extents.
+        */
+
+       do_defrag = context->auto_defrag;
+
+       /*
+        * extents moving happens in unit of clusters, for the sake
+        * of simplicity, we may ignore two clusters where 'byte_start'
+        * and 'byte_start + len' were within.
+        */
+       move_start = ocfs2_clusters_for_bytes(osb->sb, range->me_start);
+       len_to_move = (range->me_start + range->me_len) >>
+                                               osb->s_clustersize_bits;
+       if (len_to_move >= move_start)
+               len_to_move -= move_start;
+       else
+               len_to_move = 0;
+
+       if (do_defrag) {
+               defrag_thresh = range->me_threshold >> osb->s_clustersize_bits;
+               if (defrag_thresh <= 1)
+                       goto done;
+       } else
+               new_phys_cpos = ocfs2_blocks_to_clusters(inode->i_sb,
+                                                        range->me_goal);
+
+       mlog(0, "Inode: %llu, start: %llu, len: %llu, cstart: %u, clen: %u, "
+            "thresh: %u\n",
+            (unsigned long long)OCFS2_I(inode)->ip_blkno,
+            (unsigned long long)range->me_start,
+            (unsigned long long)range->me_len,
+            move_start, len_to_move, defrag_thresh);
+
+       cpos = move_start;
+       while (len_to_move) {
+               ret = ocfs2_get_clusters(inode, cpos, &phys_cpos, &alloc_size,
+                                        &flags);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               if (alloc_size > len_to_move)
+                       alloc_size = len_to_move;
+
+               /*
+                * XXX: how to deal with a hole:
+                *
+                * - skip the hole of course
+                * - force a new defragmentation
+                */
+               if (!phys_cpos) {
+                       if (do_defrag)
+                               len_defraged = 0;
+
+                       goto next;
+               }
+
+               if (do_defrag) {
+                       ocfs2_calc_extent_defrag_len(&alloc_size, &len_defraged,
+                                                    defrag_thresh, &skip);
+                       /*
+                        * skip large extents
+                        */
+                       if (skip) {
+                               skip = 0;
+                               goto next;
+                       }
+
+                       mlog(0, "#Defrag: cpos: %u, phys_cpos: %u, "
+                            "alloc_size: %u, len_defraged: %u\n",
+                            cpos, phys_cpos, alloc_size, len_defraged);
+
+                       ret = ocfs2_defrag_extent(context, cpos, phys_cpos,
+                                                 &alloc_size, flags);
+               } else {
+                       ret = ocfs2_move_extent(context, cpos, phys_cpos,
+                                               &new_phys_cpos, alloc_size,
+                                               flags);
+
+                       new_phys_cpos += alloc_size;
+               }
+
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               context->clusters_moved += alloc_size;
+next:
+               cpos += alloc_size;
+               len_to_move -= alloc_size;
+       }
+
+done:
+       range->me_flags |= OCFS2_MOVE_EXT_FL_COMPLETE;
+
+out:
+       range->me_moved_len = ocfs2_clusters_to_bytes(osb->sb,
+                                                     context->clusters_moved);
+       range->me_new_offset = ocfs2_clusters_to_bytes(osb->sb,
+                                                      context->new_phys_cpos);
+
+       ocfs2_schedule_truncate_log_flush(osb, 1);
+       ocfs2_run_deallocs(osb, &context->dealloc);
+
+       return ret;
+}
+
+static int ocfs2_move_extents(struct ocfs2_move_extents_context *context)
+{
+       int status;
+       handle_t *handle;
+       struct inode *inode = context->inode;
+       struct ocfs2_dinode *di;
+       struct buffer_head *di_bh = NULL;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (!inode)
+               return -ENOENT;
+
+       if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb))
+               return -EROFS;
+
+       mutex_lock(&inode->i_mutex);
+
+       /*
+        * This prevents concurrent writes from other nodes
+        */
+       status = ocfs2_rw_lock(inode, 1);
+       if (status) {
+               mlog_errno(status);
+               goto out;
+       }
+
+       status = ocfs2_inode_lock(inode, &di_bh, 1);
+       if (status) {
+               mlog_errno(status);
+               goto out_rw_unlock;
+       }
+
+       /*
+        * rememer ip_xattr_sem also needs to be held if necessary
+        */
+       down_write(&OCFS2_I(inode)->ip_alloc_sem);
+
+       status = __ocfs2_move_extents_range(di_bh, context);
+
+       up_write(&OCFS2_I(inode)->ip_alloc_sem);
+       if (status) {
+               mlog_errno(status);
+               goto out_inode_unlock;
+       }
+
+       /*
+        * We update ctime for these changes
+        */
+       handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
+       if (IS_ERR(handle)) {
+               status = PTR_ERR(handle);
+               mlog_errno(status);
+               goto out_inode_unlock;
+       }
+
+       status = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
+                                        OCFS2_JOURNAL_ACCESS_WRITE);
+       if (status) {
+               mlog_errno(status);
+               goto out_commit;
+       }
+
+       di = (struct ocfs2_dinode *)di_bh->b_data;
+       inode->i_ctime = CURRENT_TIME;
+       di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
+       di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
+
+       ocfs2_journal_dirty(handle, di_bh);
+
+out_commit:
+       ocfs2_commit_trans(osb, handle);
+
+out_inode_unlock:
+       brelse(di_bh);
+       ocfs2_inode_unlock(inode, 1);
+out_rw_unlock:
+       ocfs2_rw_unlock(inode, 1);
+out:
+       mutex_unlock(&inode->i_mutex);
+
+       return status;
+}
+
+int ocfs2_ioctl_move_extents(struct file *filp, void __user *argp)
+{
+       int status;
+
+       struct inode *inode = filp->f_path.dentry->d_inode;
+       struct ocfs2_move_extents range;
+       struct ocfs2_move_extents_context *context = NULL;
+
+       status = mnt_want_write(filp->f_path.mnt);
+       if (status)
+               return status;
+
+       if ((!S_ISREG(inode->i_mode)) || !(filp->f_mode & FMODE_WRITE))
+               goto out;
+
+       if (inode->i_flags & (S_IMMUTABLE|S_APPEND)) {
+               status = -EPERM;
+               goto out;
+       }
+
+       context = kzalloc(sizeof(struct ocfs2_move_extents_context), GFP_NOFS);
+       if (!context) {
+               status = -ENOMEM;
+               mlog_errno(status);
+               goto out;
+       }
+
+       context->inode = inode;
+       context->file = filp;
+
+       if (argp) {
+               if (copy_from_user(&range, (struct ocfs2_move_extents *)argp,
+                                  sizeof(range))) {
+                       status = -EFAULT;
+                       goto out;
+               }
+       } else {
+               status = -EINVAL;
+               goto out;
+       }
+
+       if (range.me_start > i_size_read(inode))
+               goto out;
+
+       if (range.me_start + range.me_len > i_size_read(inode))
+                       range.me_len = i_size_read(inode) - range.me_start;
+
+       context->range = &range;
+
+       if (range.me_flags & OCFS2_MOVE_EXT_FL_AUTO_DEFRAG) {
+               context->auto_defrag = 1;
+               /*
+                * ok, the default theshold for the defragmentation
+                * is 1M, since our maximum clustersize was 1M also.
+                * any thought?
+                */
+               if (!range.me_threshold)
+                       range.me_threshold = 1024 * 1024;
+
+               if (range.me_threshold > i_size_read(inode))
+                       range.me_threshold = i_size_read(inode);
+
+               if (range.me_flags & OCFS2_MOVE_EXT_FL_PART_DEFRAG)
+                       context->partial = 1;
+       } else {
+               /*
+                * first best-effort attempt to validate and adjust the goal
+                * (physical address in block), while it can't guarantee later
+                * operation can succeed all the time since global_bitmap may
+                * change a bit over time.
+                */
+
+               status = ocfs2_validate_and_adjust_move_goal(inode, &range);
+               if (status)
+                       goto out;
+       }
+
+       status = ocfs2_move_extents(context);
+       if (status)
+               mlog_errno(status);
+out:
+       /*
+        * movement/defragmentation may end up being partially completed,
+        * that's the reason why we need to return userspace the finished
+        * length and new_offset even if failure happens somewhere.
+        */
+       if (argp) {
+               if (copy_to_user((struct ocfs2_move_extents *)argp, &range,
+                               sizeof(range)))
+                       status = -EFAULT;
+       }
+
+       kfree(context);
+
+       mnt_drop_write(filp->f_path.mnt);
+
+       return status;
+}
diff --git a/fs/ocfs2/move_extents.h b/fs/ocfs2/move_extents.h
new file mode 100644 (file)
index 0000000..4e143e8
--- /dev/null
@@ -0,0 +1,22 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * move_extents.h
+ *
+ * Copyright (C) 2011 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License 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.
+ */
+#ifndef OCFS2_MOVE_EXTENTS_H
+#define OCFS2_MOVE_EXTENTS_H
+
+int ocfs2_ioctl_move_extents(struct file *filp,  void __user *argp);
+
+#endif /* OCFS2_MOVE_EXTENTS_H */
index b46f39bf7438d5048dd5637d5762b4d6c44990e4..5b27ff1fa577d95533c0b594349b23f8cc62bd62 100644 (file)
@@ -142,6 +142,38 @@ struct ocfs2_info_journal_size {
        __u64 ij_journal_size;
 };
 
+struct ocfs2_info_freeinode {
+       struct ocfs2_info_request ifi_req;
+       struct ocfs2_info_local_freeinode {
+               __u64 lfi_total;
+               __u64 lfi_free;
+       } ifi_stat[OCFS2_MAX_SLOTS];
+       __u32 ifi_slotnum; /* out */
+       __u32 ifi_pad;
+};
+
+#define OCFS2_INFO_MAX_HIST     (32)
+
+struct ocfs2_info_freefrag {
+       struct ocfs2_info_request iff_req;
+       struct ocfs2_info_freefrag_stats { /* (out) */
+               struct ocfs2_info_free_chunk_list {
+                       __u32 fc_chunks[OCFS2_INFO_MAX_HIST];
+                       __u32 fc_clusters[OCFS2_INFO_MAX_HIST];
+               } ffs_fc_hist;
+               __u32 ffs_clusters;
+               __u32 ffs_free_clusters;
+               __u32 ffs_free_chunks;
+               __u32 ffs_free_chunks_real;
+               __u32 ffs_min; /* Minimum free chunksize in clusters */
+               __u32 ffs_max;
+               __u32 ffs_avg;
+               __u32 ffs_pad;
+       } iff_ffs;
+       __u32 iff_chunksize; /* chunksize in clusters(in) */
+       __u32 iff_pad;
+};
+
 /* Codes for ocfs2_info_request */
 enum ocfs2_info_type {
        OCFS2_INFO_CLUSTERSIZE = 1,
@@ -151,6 +183,8 @@ enum ocfs2_info_type {
        OCFS2_INFO_UUID,
        OCFS2_INFO_FS_FEATURES,
        OCFS2_INFO_JOURNAL_SIZE,
+       OCFS2_INFO_FREEINODE,
+       OCFS2_INFO_FREEFRAG,
        OCFS2_INFO_NUM_TYPES
 };
 
@@ -171,4 +205,38 @@ enum ocfs2_info_type {
 
 #define OCFS2_IOC_INFO         _IOR('o', 5, struct ocfs2_info)
 
+struct ocfs2_move_extents {
+/* All values are in bytes */
+       /* in */
+       __u64 me_start;         /* Virtual start in the file to move */
+       __u64 me_len;           /* Length of the extents to be moved */
+       __u64 me_goal;          /* Physical offset of the goal,
+                                  it's in block unit */
+       __u64 me_threshold;     /* Maximum distance from goal or threshold
+                                  for auto defragmentation */
+       __u64 me_flags;         /* Flags for the operation:
+                                * - auto defragmentation.
+                                * - refcount,xattr cases.
+                                */
+       /* out */
+       __u64 me_moved_len;     /* Moved/defraged length */
+       __u64 me_new_offset;    /* Resulting physical location */
+       __u32 me_reserved[2];   /* Reserved for futhure */
+};
+
+#define OCFS2_MOVE_EXT_FL_AUTO_DEFRAG  (0x00000001)    /* Kernel manages to
+                                                          claim new clusters
+                                                          as the goal place
+                                                          for extents moving */
+#define OCFS2_MOVE_EXT_FL_PART_DEFRAG  (0x00000002)    /* Allow partial extent
+                                                          moving, is to make
+                                                          movement less likely
+                                                          to fail, may make fs
+                                                          even more fragmented */
+#define OCFS2_MOVE_EXT_FL_COMPLETE     (0x00000004)    /* Move or defragmenation
+                                                          completely gets done.
+                                                        */
+
+#define OCFS2_IOC_MOVE_EXT     _IOW('o', 6, struct ocfs2_move_extents)
+
 #endif /* OCFS2_IOCTL_H */
index a1dae5bb54acda9d6e852d9d66e24c3d4cde8926..3b481f490633af2f483afd1817fe8ad538908b6a 100644 (file)
@@ -688,6 +688,31 @@ TRACE_EVENT(ocfs2_cache_block_dealloc,
                  __entry->blkno, __entry->bit)
 );
 
+TRACE_EVENT(ocfs2_trim_extent,
+       TP_PROTO(struct super_block *sb, unsigned long long blk,
+                unsigned long long count),
+       TP_ARGS(sb, blk, count),
+       TP_STRUCT__entry(
+               __field(int, dev_major)
+               __field(int, dev_minor)
+               __field(unsigned long long, blk)
+               __field(__u64,  count)
+       ),
+       TP_fast_assign(
+               __entry->dev_major = MAJOR(sb->s_dev);
+               __entry->dev_minor = MINOR(sb->s_dev);
+               __entry->blk = blk;
+               __entry->count = count;
+       ),
+       TP_printk("%d %d %llu %llu",
+                 __entry->dev_major, __entry->dev_minor,
+                 __entry->blk, __entry->count)
+);
+
+DEFINE_OCFS2_ULL_UINT_UINT_UINT_EVENT(ocfs2_trim_group);
+
+DEFINE_OCFS2_ULL_ULL_ULL_EVENT(ocfs2_trim_fs);
+
 /* End of trace events for fs/ocfs2/alloc.c. */
 
 /* Trace events for fs/ocfs2/localalloc.c. */
index 3c7606cff1ab4f3c7df789f14ef89dfdff70063e..ebfd3825f12a367b3c2786507146913a8191e56f 100644 (file)
@@ -66,7 +66,7 @@ struct ocfs2_cow_context {
                            u32 *num_clusters,
                            unsigned int *extent_flags);
        int (*cow_duplicate_clusters)(handle_t *handle,
-                                     struct ocfs2_cow_context *context,
+                                     struct file *file,
                                      u32 cpos, u32 old_cluster,
                                      u32 new_cluster, u32 new_len);
 };
@@ -2921,20 +2921,21 @@ static int ocfs2_clear_cow_buffer(handle_t *handle, struct buffer_head *bh)
        return 0;
 }
 
-static int ocfs2_duplicate_clusters_by_page(handle_t *handle,
-                                           struct ocfs2_cow_context *context,
-                                           u32 cpos, u32 old_cluster,
-                                           u32 new_cluster, u32 new_len)
+int ocfs2_duplicate_clusters_by_page(handle_t *handle,
+                                    struct file *file,
+                                    u32 cpos, u32 old_cluster,
+                                    u32 new_cluster, u32 new_len)
 {
        int ret = 0, partial;
-       struct ocfs2_caching_info *ci = context->data_et.et_ci;
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct ocfs2_caching_info *ci = INODE_CACHE(inode);
        struct super_block *sb = ocfs2_metadata_cache_get_super(ci);
        u64 new_block = ocfs2_clusters_to_blocks(sb, new_cluster);
        struct page *page;
        pgoff_t page_index;
        unsigned int from, to, readahead_pages;
        loff_t offset, end, map_end;
-       struct address_space *mapping = context->inode->i_mapping;
+       struct address_space *mapping = inode->i_mapping;
 
        trace_ocfs2_duplicate_clusters_by_page(cpos, old_cluster,
                                               new_cluster, new_len);
@@ -2948,8 +2949,8 @@ static int ocfs2_duplicate_clusters_by_page(handle_t *handle,
         * We only duplicate pages until we reach the page contains i_size - 1.
         * So trim 'end' to i_size.
         */
-       if (end > i_size_read(context->inode))
-               end = i_size_read(context->inode);
+       if (end > i_size_read(inode))
+               end = i_size_read(inode);
 
        while (offset < end) {
                page_index = offset >> PAGE_CACHE_SHIFT;
@@ -2972,10 +2973,9 @@ static int ocfs2_duplicate_clusters_by_page(handle_t *handle,
                if (PAGE_CACHE_SIZE <= OCFS2_SB(sb)->s_clustersize)
                        BUG_ON(PageDirty(page));
 
-               if (PageReadahead(page) && context->file) {
+               if (PageReadahead(page)) {
                        page_cache_async_readahead(mapping,
-                                                  &context->file->f_ra,
-                                                  context->file,
+                                                  &file->f_ra, file,
                                                   page, page_index,
                                                   readahead_pages);
                }
@@ -2999,8 +2999,7 @@ static int ocfs2_duplicate_clusters_by_page(handle_t *handle,
                        }
                }
 
-               ocfs2_map_and_dirty_page(context->inode,
-                                        handle, from, to,
+               ocfs2_map_and_dirty_page(inode, handle, from, to,
                                         page, 0, &new_block);
                mark_page_accessed(page);
 unlock:
@@ -3015,14 +3014,15 @@ unlock:
        return ret;
 }
 
-static int ocfs2_duplicate_clusters_by_jbd(handle_t *handle,
-                                          struct ocfs2_cow_context *context,
-                                          u32 cpos, u32 old_cluster,
-                                          u32 new_cluster, u32 new_len)
+int ocfs2_duplicate_clusters_by_jbd(handle_t *handle,
+                                   struct file *file,
+                                   u32 cpos, u32 old_cluster,
+                                   u32 new_cluster, u32 new_len)
 {
        int ret = 0;
-       struct super_block *sb = context->inode->i_sb;
-       struct ocfs2_caching_info *ci = context->data_et.et_ci;
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct super_block *sb = inode->i_sb;
+       struct ocfs2_caching_info *ci = INODE_CACHE(inode);
        int i, blocks = ocfs2_clusters_to_blocks(sb, new_len);
        u64 old_block = ocfs2_clusters_to_blocks(sb, old_cluster);
        u64 new_block = ocfs2_clusters_to_blocks(sb, new_cluster);
@@ -3145,8 +3145,8 @@ static int ocfs2_replace_clusters(handle_t *handle,
 
        /*If the old clusters is unwritten, no need to duplicate. */
        if (!(ext_flags & OCFS2_EXT_UNWRITTEN)) {
-               ret = context->cow_duplicate_clusters(handle, context, cpos,
-                                                     old, new, len);
+               ret = context->cow_duplicate_clusters(handle, context->file,
+                                                     cpos, old, new, len);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -3162,22 +3162,22 @@ out:
        return ret;
 }
 
-static int ocfs2_cow_sync_writeback(struct super_block *sb,
-                                   struct ocfs2_cow_context *context,
-                                   u32 cpos, u32 num_clusters)
+int ocfs2_cow_sync_writeback(struct super_block *sb,
+                            struct inode *inode,
+                            u32 cpos, u32 num_clusters)
 {
        int ret = 0;
        loff_t offset, end, map_end;
        pgoff_t page_index;
        struct page *page;
 
-       if (ocfs2_should_order_data(context->inode))
+       if (ocfs2_should_order_data(inode))
                return 0;
 
        offset = ((loff_t)cpos) << OCFS2_SB(sb)->s_clustersize_bits;
        end = offset + (num_clusters << OCFS2_SB(sb)->s_clustersize_bits);
 
-       ret = filemap_fdatawrite_range(context->inode->i_mapping,
+       ret = filemap_fdatawrite_range(inode->i_mapping,
                                       offset, end - 1);
        if (ret < 0) {
                mlog_errno(ret);
@@ -3190,7 +3190,7 @@ static int ocfs2_cow_sync_writeback(struct super_block *sb,
                if (map_end > end)
                        map_end = end;
 
-               page = find_or_create_page(context->inode->i_mapping,
+               page = find_or_create_page(inode->i_mapping,
                                           page_index, GFP_NOFS);
                BUG_ON(!page);
 
@@ -3349,7 +3349,7 @@ static int ocfs2_make_clusters_writable(struct super_block *sb,
         * in write-back mode.
         */
        if (context->get_clusters == ocfs2_di_get_clusters) {
-               ret = ocfs2_cow_sync_writeback(sb, context, cpos,
+               ret = ocfs2_cow_sync_writeback(sb, context->inode, cpos,
                                               orig_num_clusters);
                if (ret)
                        mlog_errno(ret);
index c8ce46f7d8e30ee842cc8966a8c034aefae3b98b..7754608c83a47b1b44425c8f9c5e13a2adc65675 100644 (file)
@@ -84,6 +84,17 @@ int ocfs2_refcount_cow_xattr(struct inode *inode,
                             struct buffer_head *ref_root_bh,
                             u32 cpos, u32 write_len,
                             struct ocfs2_post_refcount *post);
+int ocfs2_duplicate_clusters_by_page(handle_t *handle,
+                                    struct file *file,
+                                    u32 cpos, u32 old_cluster,
+                                    u32 new_cluster, u32 new_len);
+int ocfs2_duplicate_clusters_by_jbd(handle_t *handle,
+                                   struct file *file,
+                                   u32 cpos, u32 old_cluster,
+                                   u32 new_cluster, u32 new_len);
+int ocfs2_cow_sync_writeback(struct super_block *sb,
+                            struct inode *inode,
+                            u32 cpos, u32 num_clusters);
 int ocfs2_add_refcount_flag(struct inode *inode,
                            struct ocfs2_extent_tree *data_et,
                            struct ocfs2_caching_info *ref_ci,
index 5a521c748859945c76299e93fe01127c76408d8f..56f61027236b696fce1ccde3e1edaf86acee59a0 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/mount.h>
 #include <linux/seq_file.h>
 #include <linux/quotaops.h>
+#include <linux/cleancache.h>
 
 #define CREATE_TRACE_POINTS
 #include "ocfs2_trace.h"
@@ -1071,7 +1072,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 
        sb->s_magic = OCFS2_SUPER_MAGIC;
 
-       sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
+       sb->s_flags = (sb->s_flags & ~(MS_POSIXACL | MS_NOSEC)) |
                ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
 
        /* Hard readonly mode only if: bdev_read_only, MS_RDONLY,
@@ -1566,7 +1567,7 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
        if (osb->preferred_slot != OCFS2_INVALID_SLOT)
                seq_printf(s, ",preferred_slot=%d", osb->preferred_slot);
 
-       if (osb->s_atime_quantum != OCFS2_DEFAULT_ATIME_QUANTUM)
+       if (!(mnt->mnt_flags & MNT_NOATIME) && !(mnt->mnt_flags & MNT_RELATIME))
                seq_printf(s, ",atime_quantum=%u", osb->s_atime_quantum);
 
        if (osb->osb_commit_interval)
@@ -2352,6 +2353,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
                mlog_errno(status);
                goto bail;
        }
+       cleancache_init_shared_fs((char *)&uuid_net_key, sb);
 
 bail:
        return status;
index de4ff29f1e0595c549877d16144064dae9bcbb7a..3b8d3979e03b69230dd1991c9f69c0d49344cca9 100644 (file)
@@ -240,7 +240,9 @@ static int omfs_remove(struct inode *dir, struct dentry *dentry)
        struct inode *inode = dentry->d_inode;
        int ret;
 
-       if (S_ISDIR(inode->i_mode) && !omfs_dir_is_empty(inode))
+
+       if (S_ISDIR(inode->i_mode) &&
+           !omfs_dir_is_empty(inode))
                return -ENOTEMPTY;
 
        ret = omfs_delete_entry(dentry);
index d738a7e493ddc07ed1b4b1fb7a30198b3d477c5f..2c6d95257a4d5c7a61bf39b895c5ebbd647cc49b 100644 (file)
@@ -4,7 +4,6 @@
  * Released under GPL v2.
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
index 19d6750d1d6ce3b5571e463ee2fb2d768985d644..6296b403c67a3d5ca512b05e048ecf3525330153 100644 (file)
@@ -310,6 +310,15 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba,
                goto fail;
        }
 
+       /* Check the GUID Partition Table header size */
+       if (le32_to_cpu((*gpt)->header_size) >
+                       bdev_logical_block_size(state->bdev)) {
+               pr_debug("GUID Partition Table Header size is wrong: %u > %u\n",
+                       le32_to_cpu((*gpt)->header_size),
+                       bdev_logical_block_size(state->bdev));
+               goto fail;
+       }
+
        /* Check the GUID Partition Table CRC */
        origcrc = le32_to_cpu((*gpt)->header_crc32);
        (*gpt)->header_crc32 = 0;
index df434c5f28fbdce6fe676dcc2a6fe8ecb9e75ec6..c1c729335924803f92e5530d4197b1eb3bd4907c 100644 (file)
@@ -20,6 +20,7 @@ proc-y        += stat.o
 proc-y += uptime.o
 proc-y += version.o
 proc-y += softirqs.o
+proc-y += namespaces.o
 proc-$(CONFIG_PROC_SYSCTL)     += proc_sysctl.o
 proc-$(CONFIG_NET)             += proc_net.o
 proc-$(CONFIG_PROC_KCORE)      += kcore.o
index 5e4f776b0917a48bf0602d9ce8f0000f2b54d77d..9b45ee84fbccd584144fd942ffe8fcca34c47b50 100644 (file)
@@ -131,7 +131,7 @@ static inline void task_name(struct seq_file *m, struct task_struct *p)
  * you can test for combinations of others with
  * simple bit tests.
  */
-static const char *task_state_array[] = {
+static const char * const task_state_array[] = {
        "R (running)",          /*   0 */
        "S (sleeping)",         /*   1 */
        "D (disk sleep)",       /*   2 */
@@ -147,7 +147,7 @@ static const char *task_state_array[] = {
 static inline const char *get_task_state(struct task_struct *tsk)
 {
        unsigned int state = (tsk->state & TASK_REPORT) | tsk->exit_state;
-       const char **p = &task_state_array[0];
+       const char * const *p = &task_state_array[0];
 
        BUILD_BUG_ON(1 + ilog2(TASK_STATE_MAX) != ARRAY_SIZE(task_state_array));
 
index dfa532730e55788a7459095ca9c788dbb58d6af9..8a84210ca080e43bc10500c4e21d85e4c224f2a1 100644 (file)
@@ -83,6 +83,9 @@
 #include <linux/pid_namespace.h>
 #include <linux/fs_struct.h>
 #include <linux/slab.h>
+#ifdef CONFIG_HARDWALL
+#include <asm/hardwall.h>
+#endif
 #include "internal.h"
 
 /* NOTE:
@@ -600,7 +603,7 @@ static int proc_fd_access_allowed(struct inode *inode)
        return allowed;
 }
 
-static int proc_setattr(struct dentry *dentry, struct iattr *attr)
+int proc_setattr(struct dentry *dentry, struct iattr *attr)
 {
        int error;
        struct inode *inode = dentry->d_inode;
@@ -894,20 +897,20 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
        if (!task)
                goto out_no_task;
 
+       copied = -ENOMEM;
+       page = (char *)__get_free_page(GFP_TEMPORARY);
+       if (!page)
+               goto out_task;
+
        mm = check_mem_permission(task);
        copied = PTR_ERR(mm);
        if (IS_ERR(mm))
-               goto out_task;
+               goto out_free;
 
        copied = -EIO;
        if (file->private_data != (void *)((long)current->self_exec_id))
                goto out_mm;
 
-       copied = -ENOMEM;
-       page = (char *)__get_free_page(GFP_TEMPORARY);
-       if (!page)
-               goto out_mm;
-
        copied = 0;
        while (count > 0) {
                int this_len, retval;
@@ -929,9 +932,11 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
                count -= retval;                        
        }
        *ppos = dst;
-       free_page((unsigned long) page);
+
 out_mm:
        mmput(mm);
+out_free:
+       free_page((unsigned long) page);
 out_task:
        put_task_struct(task);
 out_no_task:
@@ -1059,7 +1064,7 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
 {
        struct task_struct *task;
        char buffer[PROC_NUMBUF];
-       long oom_adjust;
+       int oom_adjust;
        unsigned long flags;
        int err;
 
@@ -1071,7 +1076,7 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
                goto out;
        }
 
-       err = strict_strtol(strstrip(buffer), 0, &oom_adjust);
+       err = kstrtoint(strstrip(buffer), 0, &oom_adjust);
        if (err)
                goto out;
        if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) &&
@@ -1168,7 +1173,7 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
        struct task_struct *task;
        char buffer[PROC_NUMBUF];
        unsigned long flags;
-       long oom_score_adj;
+       int oom_score_adj;
        int err;
 
        memset(buffer, 0, sizeof(buffer));
@@ -1179,7 +1184,7 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
                goto out;
        }
 
-       err = strict_strtol(strstrip(buffer), 0, &oom_score_adj);
+       err = kstrtoint(strstrip(buffer), 0, &oom_score_adj);
        if (err)
                goto out;
        if (oom_score_adj < OOM_SCORE_ADJ_MIN ||
@@ -1468,7 +1473,7 @@ sched_autogroup_write(struct file *file, const char __user *buf,
        struct inode *inode = file->f_path.dentry->d_inode;
        struct task_struct *p;
        char buffer[PROC_NUMBUF];
-       long nice;
+       int nice;
        int err;
 
        memset(buffer, 0, sizeof(buffer));
@@ -1477,9 +1482,9 @@ sched_autogroup_write(struct file *file, const char __user *buf,
        if (copy_from_user(buffer, buf, count))
                return -EFAULT;
 
-       err = strict_strtol(strstrip(buffer), 0, &nice);
-       if (err)
-               return -EINVAL;
+       err = kstrtoint(strstrip(buffer), 0, &nice);
+       if (err < 0)
+               return err;
 
        p = get_proc_task(inode);
        if (!p)
@@ -1576,57 +1581,6 @@ static const struct file_operations proc_pid_set_comm_operations = {
        .release        = single_release,
 };
 
-/*
- * We added or removed a vma mapping the executable. The vmas are only mapped
- * during exec and are not mapped with the mmap system call.
- * Callers must hold down_write() on the mm's mmap_sem for these
- */
-void added_exe_file_vma(struct mm_struct *mm)
-{
-       mm->num_exe_file_vmas++;
-}
-
-void removed_exe_file_vma(struct mm_struct *mm)
-{
-       mm->num_exe_file_vmas--;
-       if ((mm->num_exe_file_vmas == 0) && mm->exe_file){
-               fput(mm->exe_file);
-               mm->exe_file = NULL;
-       }
-
-}
-
-void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file)
-{
-       if (new_exe_file)
-               get_file(new_exe_file);
-       if (mm->exe_file)
-               fput(mm->exe_file);
-       mm->exe_file = new_exe_file;
-       mm->num_exe_file_vmas = 0;
-}
-
-struct file *get_mm_exe_file(struct mm_struct *mm)
-{
-       struct file *exe_file;
-
-       /* We need mmap_sem to protect against races with removal of
-        * VM_EXECUTABLE vmas */
-       down_read(&mm->mmap_sem);
-       exe_file = mm->exe_file;
-       if (exe_file)
-               get_file(exe_file);
-       up_read(&mm->mmap_sem);
-       return exe_file;
-}
-
-void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm)
-{
-       /* It's safe to write the exe_file pointer without exe_file_lock because
-        * this is called during fork when the task is not yet in /proc */
-       newmm->exe_file = get_mm_exe_file(oldmm);
-}
-
 static int proc_exe_link(struct inode *inode, struct path *exe_path)
 {
        struct task_struct *task;
@@ -1736,8 +1690,7 @@ static int task_dumpable(struct task_struct *task)
        return 0;
 }
 
-
-static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task)
+struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task)
 {
        struct inode * inode;
        struct proc_inode *ei;
@@ -1779,7 +1732,7 @@ out_unlock:
        return NULL;
 }
 
-static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
 {
        struct inode *inode = dentry->d_inode;
        struct task_struct *task;
@@ -1820,7 +1773,7 @@ static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat
  * made this apply to all per process world readable and executable
  * directories.
  */
-static int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
+int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
        struct inode *inode;
        struct task_struct *task;
@@ -1862,7 +1815,7 @@ static int pid_delete_dentry(const struct dentry * dentry)
        return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first;
 }
 
-static const struct dentry_operations pid_dentry_operations =
+const struct dentry_operations pid_dentry_operations =
 {
        .d_revalidate   = pid_revalidate,
        .d_delete       = pid_delete_dentry,
@@ -1870,9 +1823,6 @@ static const struct dentry_operations pid_dentry_operations =
 
 /* Lookups */
 
-typedef struct dentry *instantiate_t(struct inode *, struct dentry *,
-                               struct task_struct *, const void *);
-
 /*
  * Fill a directory entry.
  *
@@ -1885,8 +1835,8 @@ typedef struct dentry *instantiate_t(struct inode *, struct dentry *,
  * reported by readdir in sync with the inode numbers reported
  * by stat.
  */
-static int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
-       char *name, int len,
+int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+       const char *name, int len,
        instantiate_t instantiate, struct task_struct *task, const void *ptr)
 {
        struct dentry *child, *dir = filp->f_path.dentry;
@@ -2219,11 +2169,7 @@ static const struct file_operations proc_fd_operations = {
  */
 static int proc_fd_permission(struct inode *inode, int mask, unsigned int flags)
 {
-       int rv;
-
-       if (flags & IPERM_FLAG_RCU)
-               return -ECHILD;
-       rv = generic_permission(inode, mask, flags, NULL);
+       int rv = generic_permission(inode, mask, flags, NULL);
        if (rv == 0)
                return 0;
        if (task_pid(current) == proc_pid(inode))
@@ -2820,6 +2766,7 @@ static const struct pid_entry tgid_base_stuff[] = {
        DIR("task",       S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations),
        DIR("fd",         S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations),
        DIR("fdinfo",     S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations),
+       DIR("ns",         S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations),
 #ifdef CONFIG_NET
        DIR("net",        S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations),
 #endif
@@ -2894,6 +2841,9 @@ static const struct pid_entry tgid_base_stuff[] = {
 #ifdef CONFIG_TASK_IO_ACCOUNTING
        INF("io",       S_IRUGO, proc_tgid_io_accounting),
 #endif
+#ifdef CONFIG_HARDWALL
+       INF("hardwall",   S_IRUGO, proc_pid_hardwall),
+#endif
 };
 
 static int proc_tgid_base_readdir(struct file * filp,
@@ -3168,6 +3118,7 @@ out_no_task:
 static const struct pid_entry tid_base_stuff[] = {
        DIR("fd",        S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations),
        DIR("fdinfo",    S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations),
+       DIR("ns",        S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations),
        REG("environ",   S_IRUSR, proc_environ_operations),
        INF("auxv",      S_IRUSR, proc_pid_auxv),
        ONE("status",    S_IRUGO, proc_pid_status),
@@ -3232,6 +3183,9 @@ static const struct pid_entry tid_base_stuff[] = {
 #ifdef CONFIG_TASK_IO_ACCOUNTING
        INF("io",       S_IRUGO, proc_tid_io_accounting),
 #endif
+#ifdef CONFIG_HARDWALL
+       INF("hardwall",   S_IRUGO, proc_pid_hardwall),
+#endif
 };
 
 static int proc_tid_base_readdir(struct file * filp,
index f1281339b6fadc27ab1237e2d0191f666b0ed5ce..f1637f17c37c8b39c353c455c040d63d6e3637ed 100644 (file)
@@ -674,6 +674,7 @@ struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode,
        }
        return ent;
 }
+EXPORT_SYMBOL(proc_mkdir_mode);
 
 struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name,
                struct proc_dir_entry *parent)
index d15aa1b1cc8fea9f9a7e702849035095e38f4613..74b48cfa1bb2d4be464180b6913c6cd28462eb5f 100644 (file)
@@ -28,6 +28,7 @@ static void proc_evict_inode(struct inode *inode)
 {
        struct proc_dir_entry *de;
        struct ctl_table_header *head;
+       const struct proc_ns_operations *ns_ops;
 
        truncate_inode_pages(&inode->i_data, 0);
        end_writeback(inode);
@@ -44,6 +45,10 @@ static void proc_evict_inode(struct inode *inode)
                rcu_assign_pointer(PROC_I(inode)->sysctl, NULL);
                sysctl_head_put(head);
        }
+       /* Release any associated namespace */
+       ns_ops = PROC_I(inode)->ns_ops;
+       if (ns_ops && ns_ops->put)
+               ns_ops->put(PROC_I(inode)->ns);
 }
 
 static struct kmem_cache * proc_inode_cachep;
@@ -62,6 +67,8 @@ static struct inode *proc_alloc_inode(struct super_block *sb)
        ei->pde = NULL;
        ei->sysctl = NULL;
        ei->sysctl_entry = NULL;
+       ei->ns = NULL;
+       ei->ns_ops = NULL;
        inode = &ei->vfs_inode;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        return inode;
index c03e8d3a3a5b550ef8b88bc60776b48b42795065..7838e5cfec145d4655d4af0e291a8d8bebad91cd 100644 (file)
@@ -61,6 +61,14 @@ extern const struct file_operations proc_pagemap_operations;
 extern const struct file_operations proc_net_operations;
 extern const struct inode_operations proc_net_inode_operations;
 
+struct proc_maps_private {
+       struct pid *pid;
+       struct task_struct *task;
+#ifdef CONFIG_MMU
+       struct vm_area_struct *tail_vma;
+#endif
+};
+
 void proc_init_inodecache(void);
 
 static inline struct pid *proc_pid(struct inode *inode)
@@ -119,3 +127,21 @@ struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *);
  */
 int proc_readdir(struct file *, void *, filldir_t);
 struct dentry *proc_lookup(struct inode *, struct dentry *, struct nameidata *);
+
+
+
+/* Lookups */
+typedef struct dentry *instantiate_t(struct inode *, struct dentry *,
+                               struct task_struct *, const void *);
+int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+       const char *name, int len,
+       instantiate_t instantiate, struct task_struct *task, const void *ptr);
+int pid_revalidate(struct dentry *dentry, struct nameidata *nd);
+struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task);
+extern const struct dentry_operations pid_dentry_operations;
+int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
+int proc_setattr(struct dentry *dentry, struct iattr *attr);
+
+extern const struct inode_operations proc_ns_dir_inode_operations;
+extern const struct file_operations proc_ns_dir_operations;
+
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
new file mode 100644 (file)
index 0000000..be177f7
--- /dev/null
@@ -0,0 +1,201 @@
+#include <linux/proc_fs.h>
+#include <linux/nsproxy.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/fs_struct.h>
+#include <linux/mount.h>
+#include <linux/path.h>
+#include <linux/namei.h>
+#include <linux/file.h>
+#include <linux/utsname.h>
+#include <net/net_namespace.h>
+#include <linux/mnt_namespace.h>
+#include <linux/ipc_namespace.h>
+#include <linux/pid_namespace.h>
+#include "internal.h"
+
+
+static const struct proc_ns_operations *ns_entries[] = {
+#ifdef CONFIG_NET_NS
+       &netns_operations,
+#endif
+#ifdef CONFIG_UTS_NS
+       &utsns_operations,
+#endif
+#ifdef CONFIG_IPC_NS
+       &ipcns_operations,
+#endif
+};
+
+static const struct file_operations ns_file_operations = {
+       .llseek         = no_llseek,
+};
+
+static struct dentry *proc_ns_instantiate(struct inode *dir,
+       struct dentry *dentry, struct task_struct *task, const void *ptr)
+{
+       const struct proc_ns_operations *ns_ops = ptr;
+       struct inode *inode;
+       struct proc_inode *ei;
+       struct dentry *error = ERR_PTR(-ENOENT);
+       void *ns;
+
+       inode = proc_pid_make_inode(dir->i_sb, task);
+       if (!inode)
+               goto out;
+
+       ns = ns_ops->get(task);
+       if (!ns)
+               goto out_iput;
+
+       ei = PROC_I(inode);
+       inode->i_mode = S_IFREG|S_IRUSR;
+       inode->i_fop  = &ns_file_operations;
+       ei->ns_ops    = ns_ops;
+       ei->ns        = ns;
+
+       dentry->d_op = &pid_dentry_operations;
+       d_add(dentry, inode);
+       /* Close the race of the process dying before we return the dentry */
+       if (pid_revalidate(dentry, NULL))
+               error = NULL;
+out:
+       return error;
+out_iput:
+       iput(inode);
+       goto out;
+}
+
+static int proc_ns_fill_cache(struct file *filp, void *dirent,
+       filldir_t filldir, struct task_struct *task,
+       const struct proc_ns_operations *ops)
+{
+       return proc_fill_cache(filp, dirent, filldir,
+                               ops->name, strlen(ops->name),
+                               proc_ns_instantiate, task, ops);
+}
+
+static int proc_ns_dir_readdir(struct file *filp, void *dirent,
+                               filldir_t filldir)
+{
+       int i;
+       struct dentry *dentry = filp->f_path.dentry;
+       struct inode *inode = dentry->d_inode;
+       struct task_struct *task = get_proc_task(inode);
+       const struct proc_ns_operations **entry, **last;
+       ino_t ino;
+       int ret;
+
+       ret = -ENOENT;
+       if (!task)
+               goto out_no_task;
+
+       ret = -EPERM;
+       if (!ptrace_may_access(task, PTRACE_MODE_READ))
+               goto out;
+
+       ret = 0;
+       i = filp->f_pos;
+       switch (i) {
+       case 0:
+               ino = inode->i_ino;
+               if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
+                       goto out;
+               i++;
+               filp->f_pos++;
+               /* fall through */
+       case 1:
+               ino = parent_ino(dentry);
+               if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
+                       goto out;
+               i++;
+               filp->f_pos++;
+               /* fall through */
+       default:
+               i -= 2;
+               if (i >= ARRAY_SIZE(ns_entries)) {
+                       ret = 1;
+                       goto out;
+               }
+               entry = ns_entries + i;
+               last = &ns_entries[ARRAY_SIZE(ns_entries) - 1];
+               while (entry <= last) {
+                       if (proc_ns_fill_cache(filp, dirent, filldir,
+                                               task, *entry) < 0)
+                               goto out;
+                       filp->f_pos++;
+                       entry++;
+               }
+       }
+
+       ret = 1;
+out:
+       put_task_struct(task);
+out_no_task:
+       return ret;
+}
+
+const struct file_operations proc_ns_dir_operations = {
+       .read           = generic_read_dir,
+       .readdir        = proc_ns_dir_readdir,
+};
+
+static struct dentry *proc_ns_dir_lookup(struct inode *dir,
+                               struct dentry *dentry, struct nameidata *nd)
+{
+       struct dentry *error;
+       struct task_struct *task = get_proc_task(dir);
+       const struct proc_ns_operations **entry, **last;
+       unsigned int len = dentry->d_name.len;
+
+       error = ERR_PTR(-ENOENT);
+
+       if (!task)
+               goto out_no_task;
+
+       error = ERR_PTR(-EPERM);
+       if (!ptrace_may_access(task, PTRACE_MODE_READ))
+               goto out;
+
+       last = &ns_entries[ARRAY_SIZE(ns_entries) - 1];
+       for (entry = ns_entries; entry <= last; entry++) {
+               if (strlen((*entry)->name) != len)
+                       continue;
+               if (!memcmp(dentry->d_name.name, (*entry)->name, len))
+                       break;
+       }
+       error = ERR_PTR(-ENOENT);
+       if (entry > last)
+               goto out;
+
+       error = proc_ns_instantiate(dir, dentry, task, *entry);
+out:
+       put_task_struct(task);
+out_no_task:
+       return error;
+}
+
+const struct inode_operations proc_ns_dir_inode_operations = {
+       .lookup         = proc_ns_dir_lookup,
+       .getattr        = pid_getattr,
+       .setattr        = proc_setattr,
+};
+
+struct file *proc_ns_fget(int fd)
+{
+       struct file *file;
+
+       file = fget(fd);
+       if (!file)
+               return ERR_PTR(-EBADF);
+
+       if (file->f_op != &ns_file_operations)
+               goto out_invalid;
+
+       return file;
+
+out_invalid:
+       fput(file);
+       return ERR_PTR(-EINVAL);
+}
+
index f50133c11c2458a223f4575aa3b04e884cafd60d..d167de365a8de0f52ae880e0b88c75750109d981 100644 (file)
@@ -304,9 +304,6 @@ static int proc_sys_permission(struct inode *inode, int mask,unsigned int flags)
        struct ctl_table *table;
        int error;
 
-       if (flags & IPERM_FLAG_RCU)
-               return -ECHILD;
-
        /* Executable files are not allowed under /proc/sys/ */
        if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))
                return -EACCES;
index a9000e9cfee54ac804eb71e75d0b72bf989041ed..d6c3b416529b9709f2db526be706dbb415902ea3 100644 (file)
@@ -28,11 +28,12 @@ static int proc_test_super(struct super_block *sb, void *data)
 
 static int proc_set_super(struct super_block *sb, void *data)
 {
-       struct pid_namespace *ns;
-
-       ns = (struct pid_namespace *)data;
-       sb->s_fs_info = get_pid_ns(ns);
-       return set_anon_super(sb, NULL);
+       int err = set_anon_super(sb, NULL);
+       if (!err) {
+               struct pid_namespace *ns = (struct pid_namespace *)data;
+               sb->s_fs_info = get_pid_ns(ns);
+       }
+       return err;
 }
 
 static struct dentry *proc_mount(struct file_system_type *fs_type,
index 1cffa2b8a2fcd5dc9a6b329ce29498ef9e24cab0..9758b654a1bcffe27c414ef322f34cd6a8658c33 100644 (file)
@@ -138,9 +138,9 @@ static int stat_open(struct inode *inode, struct file *file)
        struct seq_file *m;
        int res;
 
-       /* don't ask for more than the kmalloc() max size, currently 128 KB */
-       if (size > 128 * 1024)
-               size = 128 * 1024;
+       /* don't ask for more than the kmalloc() max size */
+       if (size > KMALLOC_MAX_SIZE)
+               size = KMALLOC_MAX_SIZE;
        buf = kmalloc(size, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
index 318d8654989bf70479321fb8599b0dcf9ac29365..25b6a887adb916a93d20aa092481f67df451ff8c 100644 (file)
@@ -211,7 +211,7 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
 {
        struct mm_struct *mm = vma->vm_mm;
        struct file *file = vma->vm_file;
-       int flags = vma->vm_flags;
+       vm_flags_t flags = vma->vm_flags;
        unsigned long ino = 0;
        unsigned long long pgoff = 0;
        unsigned long start, end;
@@ -536,15 +536,17 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
        char buffer[PROC_NUMBUF];
        struct mm_struct *mm;
        struct vm_area_struct *vma;
-       long type;
+       int type;
+       int rv;
 
        memset(buffer, 0, sizeof(buffer));
        if (count > sizeof(buffer) - 1)
                count = sizeof(buffer) - 1;
        if (copy_from_user(buffer, buf, count))
                return -EFAULT;
-       if (strict_strtol(strstrip(buffer), 10, &type))
-               return -EINVAL;
+       rv = kstrtoint(strstrip(buffer), 10, &type);
+       if (rv < 0)
+               return rv;
        if (type < CLEAR_REFS_ALL || type > CLEAR_REFS_MAPPED)
                return -EINVAL;
        task = get_proc_task(file->f_path.dentry->d_inode);
@@ -769,18 +771,12 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
        if (!task)
                goto out;
 
-       mm = mm_for_maps(task);
-       ret = PTR_ERR(mm);
-       if (!mm || IS_ERR(mm))
-               goto out_task;
-
        ret = -EINVAL;
        /* file position must be aligned */
        if ((*ppos % PM_ENTRY_BYTES) || (count % PM_ENTRY_BYTES))
                goto out_task;
 
        ret = 0;
-
        if (!count)
                goto out_task;
 
@@ -788,7 +784,12 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
        pm.buffer = kmalloc(pm.len, GFP_TEMPORARY);
        ret = -ENOMEM;
        if (!pm.buffer)
-               goto out_mm;
+               goto out_task;
+
+       mm = mm_for_maps(task);
+       ret = PTR_ERR(mm);
+       if (!mm || IS_ERR(mm))
+               goto out_free;
 
        pagemap_walk.pmd_entry = pagemap_pte_range;
        pagemap_walk.pte_hole = pagemap_pte_hole;
@@ -831,7 +832,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
                len = min(count, PM_ENTRY_BYTES * pm.pos);
                if (copy_to_user(buf, pm.buffer, len)) {
                        ret = -EFAULT;
-                       goto out_free;
+                       goto out_mm;
                }
                copied += len;
                buf += len;
@@ -841,10 +842,10 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
        if (!ret || ret == PM_END_OF_BUFFER)
                ret = copied;
 
-out_free:
-       kfree(pm.buffer);
 out_mm:
        mmput(mm);
+out_free:
+       kfree(pm.buffer);
 out_task:
        put_task_struct(task);
 out:
@@ -858,7 +859,192 @@ const struct file_operations proc_pagemap_operations = {
 #endif /* CONFIG_PROC_PAGE_MONITOR */
 
 #ifdef CONFIG_NUMA
-extern int show_numa_map(struct seq_file *m, void *v);
+
+struct numa_maps {
+       struct vm_area_struct *vma;
+       unsigned long pages;
+       unsigned long anon;
+       unsigned long active;
+       unsigned long writeback;
+       unsigned long mapcount_max;
+       unsigned long dirty;
+       unsigned long swapcache;
+       unsigned long node[MAX_NUMNODES];
+};
+
+struct numa_maps_private {
+       struct proc_maps_private proc_maps;
+       struct numa_maps md;
+};
+
+static void gather_stats(struct page *page, struct numa_maps *md, int pte_dirty)
+{
+       int count = page_mapcount(page);
+
+       md->pages++;
+       if (pte_dirty || PageDirty(page))
+               md->dirty++;
+
+       if (PageSwapCache(page))
+               md->swapcache++;
+
+       if (PageActive(page) || PageUnevictable(page))
+               md->active++;
+
+       if (PageWriteback(page))
+               md->writeback++;
+
+       if (PageAnon(page))
+               md->anon++;
+
+       if (count > md->mapcount_max)
+               md->mapcount_max = count;
+
+       md->node[page_to_nid(page)]++;
+}
+
+static int gather_pte_stats(pmd_t *pmd, unsigned long addr,
+               unsigned long end, struct mm_walk *walk)
+{
+       struct numa_maps *md;
+       spinlock_t *ptl;
+       pte_t *orig_pte;
+       pte_t *pte;
+
+       md = walk->private;
+       orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
+       do {
+               struct page *page;
+               int nid;
+
+               if (!pte_present(*pte))
+                       continue;
+
+               page = vm_normal_page(md->vma, addr, *pte);
+               if (!page)
+                       continue;
+
+               if (PageReserved(page))
+                       continue;
+
+               nid = page_to_nid(page);
+               if (!node_isset(nid, node_states[N_HIGH_MEMORY]))
+                       continue;
+
+               gather_stats(page, md, pte_dirty(*pte));
+
+       } while (pte++, addr += PAGE_SIZE, addr != end);
+       pte_unmap_unlock(orig_pte, ptl);
+       return 0;
+}
+#ifdef CONFIG_HUGETLB_PAGE
+static int gather_hugetbl_stats(pte_t *pte, unsigned long hmask,
+               unsigned long addr, unsigned long end, struct mm_walk *walk)
+{
+       struct numa_maps *md;
+       struct page *page;
+
+       if (pte_none(*pte))
+               return 0;
+
+       page = pte_page(*pte);
+       if (!page)
+               return 0;
+
+       md = walk->private;
+       gather_stats(page, md, pte_dirty(*pte));
+       return 0;
+}
+
+#else
+static int gather_hugetbl_stats(pte_t *pte, unsigned long hmask,
+               unsigned long addr, unsigned long end, struct mm_walk *walk)
+{
+       return 0;
+}
+#endif
+
+/*
+ * Display pages allocated per node and memory policy via /proc.
+ */
+static int show_numa_map(struct seq_file *m, void *v)
+{
+       struct numa_maps_private *numa_priv = m->private;
+       struct proc_maps_private *proc_priv = &numa_priv->proc_maps;
+       struct vm_area_struct *vma = v;
+       struct numa_maps *md = &numa_priv->md;
+       struct file *file = vma->vm_file;
+       struct mm_struct *mm = vma->vm_mm;
+       struct mm_walk walk = {};
+       struct mempolicy *pol;
+       int n;
+       char buffer[50];
+
+       if (!mm)
+               return 0;
+
+       /* Ensure we start with an empty set of numa_maps statistics. */
+       memset(md, 0, sizeof(*md));
+
+       md->vma = vma;
+
+       walk.hugetlb_entry = gather_hugetbl_stats;
+       walk.pmd_entry = gather_pte_stats;
+       walk.private = md;
+       walk.mm = mm;
+
+       pol = get_vma_policy(proc_priv->task, vma, vma->vm_start);
+       mpol_to_str(buffer, sizeof(buffer), pol, 0);
+       mpol_cond_put(pol);
+
+       seq_printf(m, "%08lx %s", vma->vm_start, buffer);
+
+       if (file) {
+               seq_printf(m, " file=");
+               seq_path(m, &file->f_path, "\n\t= ");
+       } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) {
+               seq_printf(m, " heap");
+       } else if (vma->vm_start <= mm->start_stack &&
+                       vma->vm_end >= mm->start_stack) {
+               seq_printf(m, " stack");
+       }
+
+       walk_page_range(vma->vm_start, vma->vm_end, &walk);
+
+       if (!md->pages)
+               goto out;
+
+       if (md->anon)
+               seq_printf(m, " anon=%lu", md->anon);
+
+       if (md->dirty)
+               seq_printf(m, " dirty=%lu", md->dirty);
+
+       if (md->pages != md->anon && md->pages != md->dirty)
+               seq_printf(m, " mapped=%lu", md->pages);
+
+       if (md->mapcount_max > 1)
+               seq_printf(m, " mapmax=%lu", md->mapcount_max);
+
+       if (md->swapcache)
+               seq_printf(m, " swapcache=%lu", md->swapcache);
+
+       if (md->active < md->pages && !is_vm_hugetlb_page(vma))
+               seq_printf(m, " active=%lu", md->active);
+
+       if (md->writeback)
+               seq_printf(m, " writeback=%lu", md->writeback);
+
+       for_each_node_state(n, N_HIGH_MEMORY)
+               if (md->node[n])
+                       seq_printf(m, " N%d=%lu", n, md->node[n]);
+out:
+       seq_putc(m, '\n');
+
+       if (m->count < m->size)
+               m->version = (vma != proc_priv->tail_vma) ? vma->vm_start : 0;
+       return 0;
+}
 
 static const struct seq_operations proc_pid_numa_maps_op = {
         .start  = m_start,
@@ -869,7 +1055,20 @@ static const struct seq_operations proc_pid_numa_maps_op = {
 
 static int numa_maps_open(struct inode *inode, struct file *file)
 {
-       return do_maps_open(inode, file, &proc_pid_numa_maps_op);
+       struct numa_maps_private *priv;
+       int ret = -ENOMEM;
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (priv) {
+               priv->proc_maps.pid = proc_pid(inode);
+               ret = seq_open(file, &proc_pid_numa_maps_op);
+               if (!ret) {
+                       struct seq_file *m = file->private_data;
+                       m->private = priv;
+               } else {
+                       kfree(priv);
+               }
+       }
+       return ret;
 }
 
 const struct file_operations proc_numa_maps_operations = {
@@ -878,4 +1077,4 @@ const struct file_operations proc_numa_maps_operations = {
        .llseek         = seq_lseek,
        .release        = seq_release_private,
 };
-#endif
+#endif /* CONFIG_NUMA */
index 74802bc5ded95e09d510bcadfba94167e1390bc2..cd99bf557650c4c727cdd9ac060ec28800a0ffe5 100644 (file)
@@ -35,6 +35,46 @@ static u64 vmcore_size;
 
 static struct proc_dir_entry *proc_vmcore = NULL;
 
+/*
+ * Returns > 0 for RAM pages, 0 for non-RAM pages, < 0 on error
+ * The called function has to take care of module refcounting.
+ */
+static int (*oldmem_pfn_is_ram)(unsigned long pfn);
+
+int register_oldmem_pfn_is_ram(int (*fn)(unsigned long pfn))
+{
+       if (oldmem_pfn_is_ram)
+               return -EBUSY;
+       oldmem_pfn_is_ram = fn;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(register_oldmem_pfn_is_ram);
+
+void unregister_oldmem_pfn_is_ram(void)
+{
+       oldmem_pfn_is_ram = NULL;
+       wmb();
+}
+EXPORT_SYMBOL_GPL(unregister_oldmem_pfn_is_ram);
+
+static int pfn_is_ram(unsigned long pfn)
+{
+       int (*fn)(unsigned long pfn);
+       /* pfn is ram unless fn() checks pagetype */
+       int ret = 1;
+
+       /*
+        * Ask hypervisor if the pfn is really ram.
+        * A ballooned page contains no data and reading from such a page
+        * will cause high load in the hypervisor.
+        */
+       fn = oldmem_pfn_is_ram;
+       if (fn)
+               ret = fn(pfn);
+
+       return ret;
+}
+
 /* Reads a page from the oldmem device from given offset. */
 static ssize_t read_from_oldmem(char *buf, size_t count,
                                u64 *ppos, int userbuf)
@@ -55,9 +95,15 @@ static ssize_t read_from_oldmem(char *buf, size_t count,
                else
                        nr_bytes = count;
 
-               tmp = copy_oldmem_page(pfn, buf, nr_bytes, offset, userbuf);
-               if (tmp < 0)
-                       return tmp;
+               /* If pfn is not ram, return zeros for sparse dump files */
+               if (pfn_is_ram(pfn) == 0)
+                       memset(buf, 0, nr_bytes);
+               else {
+                       tmp = copy_oldmem_page(pfn, buf, nr_bytes,
+                                               offset, userbuf);
+                       if (tmp < 0)
+                               return tmp;
+               }
                *ppos += nr_bytes;
                count -= nr_bytes;
                buf += nr_bytes;
index d3c032f5fa0aeb600e3d8801fb6fe80f89ad39df..5b572c89e6c4bcbb028b5faf417c098503cc2991 100644 (file)
@@ -691,8 +691,11 @@ static void prune_dqcache(int count)
  * This is called from kswapd when we think we need some
  * more memory
  */
-static int shrink_dqcache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
+static int shrink_dqcache_memory(struct shrinker *shrink,
+                                struct shrink_control *sc)
 {
+       int nr = sc->nr_to_scan;
+
        if (nr) {
                spin_lock(&dq_list_lock);
                prune_dqcache(nr);
index b216ff6be1c9db1e22e768828beaf6def35d8c75..aa91089162cb568ce4e5426c4b9db2e942240ce7 100644 (file)
@@ -568,7 +568,7 @@ static void destroy_inodecache(void)
 }
 
 /* we don't mark inodes dirty, we just log them */
-static void reiserfs_dirty_inode(struct inode *inode)
+static void reiserfs_dirty_inode(struct inode *inode, int flags)
 {
        struct reiserfs_transaction_handle th;
 
index 47d2a4498b039cc0fa6c397ec1defd4f65c0db11..d78089690965b3540344ea8fafbd9403fe825cf8 100644 (file)
@@ -98,14 +98,12 @@ static int xattr_rmdir(struct inode *dir, struct dentry *dentry)
 
        reiserfs_mutex_lock_nested_safe(&dentry->d_inode->i_mutex,
                                        I_MUTEX_CHILD, dir->i_sb);
-       dentry_unhash(dentry);
        error = dir->i_op->rmdir(dir, dentry);
        if (!error)
                dentry->d_inode->i_flags |= S_DEAD;
        mutex_unlock(&dentry->d_inode->i_mutex);
        if (!error)
                d_delete(dentry);
-       dput(dentry);
 
        return error;
 }
@@ -956,8 +954,6 @@ static int xattr_mount_check(struct super_block *s)
 
 int reiserfs_permission(struct inode *inode, int mask, unsigned int flags)
 {
-       if (flags & IPERM_FLAG_RCU)
-               return -ECHILD;
        /*
         * We don't do permission checks on the internal objects.
         * Permissions are determined by the "owning" object.
index 50a5d978da1698f68cf8d2d2eca97474887ea223..aa866d309695497c1c8925cb30c8af6884f20aaf 100644 (file)
@@ -162,6 +162,14 @@ static const struct pipe_buf_operations user_page_pipe_buf_ops = {
        .get = generic_pipe_buf_get,
 };
 
+static void wakeup_pipe_readers(struct pipe_inode_info *pipe)
+{
+       smp_mb();
+       if (waitqueue_active(&pipe->wait))
+               wake_up_interruptible(&pipe->wait);
+       kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
+}
+
 /**
  * splice_to_pipe - fill passed data into a pipe
  * @pipe:      pipe to fill
@@ -247,12 +255,8 @@ ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
 
        pipe_unlock(pipe);
 
-       if (do_wakeup) {
-               smp_mb();
-               if (waitqueue_active(&pipe->wait))
-                       wake_up_interruptible(&pipe->wait);
-               kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
-       }
+       if (do_wakeup)
+               wakeup_pipe_readers(pipe);
 
        while (page_nr < spd_pages)
                spd->spd_release(spd, page_nr++);
@@ -1892,12 +1896,9 @@ retry:
        /*
         * If we put data in the output pipe, wakeup any potential readers.
         */
-       if (ret > 0) {
-               smp_mb();
-               if (waitqueue_active(&opipe->wait))
-                       wake_up_interruptible(&opipe->wait);
-               kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN);
-       }
+       if (ret > 0)
+               wakeup_pipe_readers(opipe);
+
        if (input_wakeup)
                wakeup_pipe_writers(ipipe);
 
@@ -1976,12 +1977,8 @@ static int link_pipe(struct pipe_inode_info *ipipe,
        /*
         * If we put data in the output pipe, wakeup any potential readers.
         */
-       if (ret > 0) {
-               smp_mb();
-               if (waitqueue_active(&opipe->wait))
-                       wake_up_interruptible(&opipe->wait);
-               kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN);
-       }
+       if (ret > 0)
+               wakeup_pipe_readers(opipe);
 
        return ret;
 }
index 8ab48bc2fa7d4f17f75288ac64544b9894f15dfc..ed0eb2a921f4bdb654bca99407b542db061b0054 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 4b5a3fbb1f1f6e3a611063fd0eadfe5f0579c248..f744be98cd5abc8dd6d93cf4a699981491f8e811 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -393,19 +393,36 @@ struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *sb,
 /*
  * Read a filesystem table (uncompressed sequence of bytes) from disk
  */
-int squashfs_read_table(struct super_block *sb, void *buffer, u64 block,
-       int length)
+void *squashfs_read_table(struct super_block *sb, u64 block, int length)
 {
        int pages = (length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
        int i, res;
-       void **data = kcalloc(pages, sizeof(void *), GFP_KERNEL);
-       if (data == NULL)
-               return -ENOMEM;
+       void *table, *buffer, **data;
+
+       table = buffer = kmalloc(length, GFP_KERNEL);
+       if (table == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       data = kcalloc(pages, sizeof(void *), GFP_KERNEL);
+       if (data == NULL) {
+               res = -ENOMEM;
+               goto failed;
+       }
 
        for (i = 0; i < pages; i++, buffer += PAGE_CACHE_SIZE)
                data[i] = buffer;
+
        res = squashfs_read_data(sb, data, block, length |
                SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length, pages);
+
        kfree(data);
-       return res;
+
+       if (res < 0)
+               goto failed;
+
+       return table;
+
+failed:
+       kfree(table);
+       return ERR_PTR(res);
 }
index e921bd213738fdfe1d15b50150c1060986d3e0ec..9f1b0bb96f138b49f67f008e9043a27ec997e480 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 099745ad5691ed1e129afba411eb56e821a4be27..8ba70cff09a60e89f39713eb88a51f2abb10145d 100644 (file)
@@ -4,7 +4,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 3f79cd1d0c197b4428356c120fbff7cead1042fe..9dfe2ce0fb70f0b0caee3d14c9f0f3026bf5d3f4 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 7f93d5a9ee056648a865ae2e2dbf45a3783ce9bb..5e1101ff276f940eeda02c596dcbdc9acff98d04 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -121,30 +121,38 @@ static struct dentry *squashfs_get_parent(struct dentry *child)
  * Read uncompressed inode lookup table indexes off disk into memory
  */
 __le64 *squashfs_read_inode_lookup_table(struct super_block *sb,
-               u64 lookup_table_start, unsigned int inodes)
+               u64 lookup_table_start, u64 next_table, unsigned int inodes)
 {
        unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(inodes);
-       __le64 *inode_lookup_table;
-       int err;
+       __le64 *table;
 
        TRACE("In read_inode_lookup_table, length %d\n", length);
 
-       /* Allocate inode lookup table indexes */
-       inode_lookup_table = kmalloc(length, GFP_KERNEL);
-       if (inode_lookup_table == NULL) {
-               ERROR("Failed to allocate inode lookup table\n");
-               return ERR_PTR(-ENOMEM);
-       }
+       /* Sanity check values */
+
+       /* there should always be at least one inode */
+       if (inodes == 0)
+               return ERR_PTR(-EINVAL);
+
+       /* length bytes should not extend into the next table - this check
+        * also traps instances where lookup_table_start is incorrectly larger
+        * than the next table start
+        */
+       if (lookup_table_start + length > next_table)
+               return ERR_PTR(-EINVAL);
+
+       table = squashfs_read_table(sb, lookup_table_start, length);
 
-       err = squashfs_read_table(sb, inode_lookup_table, lookup_table_start,
-                       length);
-       if (err < 0) {
-               ERROR("unable to read inode lookup table\n");
-               kfree(inode_lookup_table);
-               return ERR_PTR(err);
+       /*
+        * table[0] points to the first inode lookup table metadata block,
+        * this should be less than lookup_table_start
+        */
+       if (!IS_ERR(table) && le64_to_cpu(table[0]) >= lookup_table_start) {
+               kfree(table);
+               return ERR_PTR(-EINVAL);
        }
 
-       return inode_lookup_table;
+       return table;
 }
 
 
index a25c5060bdcb5437726497e8bf43d621f09af599..38bb1c6405590fa92addaa44a88b3f411575a9a3 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 7eef571443c6d50936619357514fcc9d8df3be57..0ed6edbc5c7170aa06f191e33df193721206cb3f 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -71,26 +71,29 @@ int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment,
  * Read the uncompressed fragment lookup table indexes off disk into memory
  */
 __le64 *squashfs_read_fragment_index_table(struct super_block *sb,
-       u64 fragment_table_start, unsigned int fragments)
+       u64 fragment_table_start, u64 next_table, unsigned int fragments)
 {
        unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(fragments);
-       __le64 *fragment_index;
-       int err;
+       __le64 *table;
 
-       /* Allocate fragment lookup table indexes */
-       fragment_index = kmalloc(length, GFP_KERNEL);
-       if (fragment_index == NULL) {
-               ERROR("Failed to allocate fragment index table\n");
-               return ERR_PTR(-ENOMEM);
-       }
+       /*
+        * Sanity check, length bytes should not extend into the next table -
+        * this check also traps instances where fragment_table_start is
+        * incorrectly larger than the next table start
+        */
+       if (fragment_table_start + length > next_table)
+               return ERR_PTR(-EINVAL);
+
+       table = squashfs_read_table(sb, fragment_table_start, length);
 
-       err = squashfs_read_table(sb, fragment_index, fragment_table_start,
-                       length);
-       if (err < 0) {
-               ERROR("unable to read fragment index table\n");
-               kfree(fragment_index);
-               return ERR_PTR(err);
+       /*
+        * table[0] points to the first fragment table metadata block, this
+        * should be less than fragment_table_start
+        */
+       if (!IS_ERR(table) && le64_to_cpu(table[0]) >= fragment_table_start) {
+               kfree(table);
+               return ERR_PTR(-EINVAL);
        }
 
-       return fragment_index;
+       return table;
 }
index d8f32452638e192f4418ff7ffd226a27c7f373c3..d38ea3dab95151916906bc1999d21b6cfa47f6a2 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -66,27 +66,37 @@ int squashfs_get_id(struct super_block *sb, unsigned int index,
  * Read uncompressed id lookup table indexes from disk into memory
  */
 __le64 *squashfs_read_id_index_table(struct super_block *sb,
-                       u64 id_table_start, unsigned short no_ids)
+               u64 id_table_start, u64 next_table, unsigned short no_ids)
 {
        unsigned int length = SQUASHFS_ID_BLOCK_BYTES(no_ids);
-       __le64 *id_table;
-       int err;
+       __le64 *table;
 
        TRACE("In read_id_index_table, length %d\n", length);
 
-       /* Allocate id lookup table indexes */
-       id_table = kmalloc(length, GFP_KERNEL);
-       if (id_table == NULL) {
-               ERROR("Failed to allocate id index table\n");
-               return ERR_PTR(-ENOMEM);
-       }
+       /* Sanity check values */
+
+       /* there should always be at least one id */
+       if (no_ids == 0)
+               return ERR_PTR(-EINVAL);
+
+       /*
+        * length bytes should not extend into the next table - this check
+        * also traps instances where id_table_start is incorrectly larger
+        * than the next table start
+        */
+       if (id_table_start + length > next_table)
+               return ERR_PTR(-EINVAL);
+
+       table = squashfs_read_table(sb, id_table_start, length);
 
-       err = squashfs_read_table(sb, id_table, id_table_start, length);
-       if (err < 0) {
-               ERROR("unable to read id index table\n");
-               kfree(id_table);
-               return ERR_PTR(err);
+       /*
+        * table[0] points to the first id lookup table metadata block, this
+        * should be less than id_table_start
+        */
+       if (!IS_ERR(table) && le64_to_cpu(table[0]) >= id_table_start) {
+               kfree(table);
+               return ERR_PTR(-EINVAL);
        }
 
-       return id_table;
+       return table;
 }
index 62e63ad250755ed6d51fd56aa75f2c91f82e74e7..04bebcaa237331cd3a27d252dbdcc60dd4e6d98d 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 5d922a6701ab730bf27d70451dd5c37c17337c9e..4bc63ac64bc01bdbbc01cc6a22e5494b06a876ae 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 1f2e608b87858ffdd39911bd09155e4bbc845cac..e3be6a71cfa7508c4602c40cdab86641ac6742d7 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -44,24 +44,24 @@ extern struct squashfs_cache_entry *squashfs_get_fragment(struct super_block *,
                                u64, int);
 extern struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *,
                                u64, int);
-extern int squashfs_read_table(struct super_block *, void *, u64, int);
+extern void *squashfs_read_table(struct super_block *, u64, int);
 
 /* decompressor.c */
 extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int);
 extern void *squashfs_decompressor_init(struct super_block *, unsigned short);
 
 /* export.c */
-extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64,
+extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, u64,
                                unsigned int);
 
 /* fragment.c */
 extern int squashfs_frag_lookup(struct super_block *, unsigned int, u64 *);
 extern __le64 *squashfs_read_fragment_index_table(struct super_block *,
-                               u64, unsigned int);
+                               u64, u64, unsigned int);
 
 /* id.c */
 extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *);
-extern __le64 *squashfs_read_id_index_table(struct super_block *, u64,
+extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, u64,
                                unsigned short);
 
 /* inode.c */
index 4582c568ef4d115df3491af9f7c46216e5acb7bf..b4a4e539a08ca99846979777e738279962779568 100644 (file)
@@ -4,7 +4,7 @@
  * Squashfs
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 359baefc01fc00be8eae64f74e77b847061e5521..73588e7700ed8a38aa98b5765d0d331df9c83193 100644 (file)
@@ -4,7 +4,7 @@
  * Squashfs
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index d9037a5215f00b77044c030b37c1255fe4273a41..651f0b31d2966318bfd5ec7ce6ee4bd152486c8e 100644 (file)
@@ -4,7 +4,7 @@
  * Squashfs
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 5c8184c061a49e15920909b07d151b0a6b985ea6..7438850c62d0ad538b61455bbed423569e3ac692 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -83,7 +83,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
        long long root_inode;
        unsigned short flags;
        unsigned int fragments;
-       u64 lookup_table_start, xattr_id_table_start;
+       u64 lookup_table_start, xattr_id_table_start, next_table;
        int err;
 
        TRACE("Entered squashfs_fill_superblock\n");
@@ -95,12 +95,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
        }
        msblk = sb->s_fs_info;
 
-       sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
-       if (sblk == NULL) {
-               ERROR("Failed to allocate squashfs_super_block\n");
-               goto failure;
-       }
-
        msblk->devblksize = sb_min_blocksize(sb, BLOCK_SIZE);
        msblk->devblksize_log2 = ffz(~msblk->devblksize);
 
@@ -114,10 +108,12 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
         * of bytes_used) we need to set it to an initial sensible dummy value
         */
        msblk->bytes_used = sizeof(*sblk);
-       err = squashfs_read_table(sb, sblk, SQUASHFS_START, sizeof(*sblk));
+       sblk = squashfs_read_table(sb, SQUASHFS_START, sizeof(*sblk));
 
-       if (err < 0) {
+       if (IS_ERR(sblk)) {
                ERROR("unable to read squashfs_super_block\n");
+               err = PTR_ERR(sblk);
+               sblk = NULL;
                goto failed_mount;
        }
 
@@ -218,18 +214,61 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
                goto failed_mount;
        }
 
+       /* Handle xattrs */
+       sb->s_xattr = squashfs_xattr_handlers;
+       xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start);
+       if (xattr_id_table_start == SQUASHFS_INVALID_BLK) {
+               next_table = msblk->bytes_used;
+               goto allocate_id_index_table;
+       }
+
+       /* Allocate and read xattr id lookup table */
+       msblk->xattr_id_table = squashfs_read_xattr_id_table(sb,
+               xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids);
+       if (IS_ERR(msblk->xattr_id_table)) {
+               ERROR("unable to read xattr id index table\n");
+               err = PTR_ERR(msblk->xattr_id_table);
+               msblk->xattr_id_table = NULL;
+               if (err != -ENOTSUPP)
+                       goto failed_mount;
+       }
+       next_table = msblk->xattr_table;
+
+allocate_id_index_table:
        /* Allocate and read id index table */
        msblk->id_table = squashfs_read_id_index_table(sb,
-               le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids));
+               le64_to_cpu(sblk->id_table_start), next_table,
+               le16_to_cpu(sblk->no_ids));
        if (IS_ERR(msblk->id_table)) {
+               ERROR("unable to read id index table\n");
                err = PTR_ERR(msblk->id_table);
                msblk->id_table = NULL;
                goto failed_mount;
        }
+       next_table = le64_to_cpu(msblk->id_table[0]);
+
+       /* Handle inode lookup table */
+       lookup_table_start = le64_to_cpu(sblk->lookup_table_start);
+       if (lookup_table_start == SQUASHFS_INVALID_BLK)
+               goto handle_fragments;
+
+       /* Allocate and read inode lookup table */
+       msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb,
+               lookup_table_start, next_table, msblk->inodes);
+       if (IS_ERR(msblk->inode_lookup_table)) {
+               ERROR("unable to read inode lookup table\n");
+               err = PTR_ERR(msblk->inode_lookup_table);
+               msblk->inode_lookup_table = NULL;
+               goto failed_mount;
+       }
+       next_table = le64_to_cpu(msblk->inode_lookup_table[0]);
 
+       sb->s_export_op = &squashfs_export_ops;
+
+handle_fragments:
        fragments = le32_to_cpu(sblk->fragments);
        if (fragments == 0)
-               goto allocate_lookup_table;
+               goto check_directory_table;
 
        msblk->fragment_cache = squashfs_cache_init("fragment",
                SQUASHFS_CACHED_FRAGMENTS, msblk->block_size);
@@ -240,45 +279,29 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
 
        /* Allocate and read fragment index table */
        msblk->fragment_index = squashfs_read_fragment_index_table(sb,
-               le64_to_cpu(sblk->fragment_table_start), fragments);
+               le64_to_cpu(sblk->fragment_table_start), next_table, fragments);
        if (IS_ERR(msblk->fragment_index)) {
+               ERROR("unable to read fragment index table\n");
                err = PTR_ERR(msblk->fragment_index);
                msblk->fragment_index = NULL;
                goto failed_mount;
        }
+       next_table = le64_to_cpu(msblk->fragment_index[0]);
 
-allocate_lookup_table:
-       lookup_table_start = le64_to_cpu(sblk->lookup_table_start);
-       if (lookup_table_start == SQUASHFS_INVALID_BLK)
-               goto allocate_xattr_table;
-
-       /* Allocate and read inode lookup table */
-       msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb,
-               lookup_table_start, msblk->inodes);
-       if (IS_ERR(msblk->inode_lookup_table)) {
-               err = PTR_ERR(msblk->inode_lookup_table);
-               msblk->inode_lookup_table = NULL;
+check_directory_table:
+       /* Sanity check directory_table */
+       if (msblk->directory_table >= next_table) {
+               err = -EINVAL;
                goto failed_mount;
        }
 
-       sb->s_export_op = &squashfs_export_ops;
-
-allocate_xattr_table:
-       sb->s_xattr = squashfs_xattr_handlers;
-       xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start);
-       if (xattr_id_table_start == SQUASHFS_INVALID_BLK)
-               goto allocate_root;
-
-       /* Allocate and read xattr id lookup table */
-       msblk->xattr_id_table = squashfs_read_xattr_id_table(sb,
-               xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids);
-       if (IS_ERR(msblk->xattr_id_table)) {
-               err = PTR_ERR(msblk->xattr_id_table);
-               msblk->xattr_id_table = NULL;
-               if (err != -ENOTSUPP)
-                       goto failed_mount;
+       /* Sanity check inode_table */
+       if (msblk->inode_table >= msblk->directory_table) {
+               err = -EINVAL;
+               goto failed_mount;
        }
-allocate_root:
+
+       /* allocate root */
        root = new_inode(sb);
        if (!root) {
                err = -ENOMEM;
@@ -318,11 +341,6 @@ failed_mount:
        sb->s_fs_info = NULL;
        kfree(sblk);
        return err;
-
-failure:
-       kfree(sb->s_fs_info);
-       sb->s_fs_info = NULL;
-       return -ENOMEM;
 }
 
 
@@ -475,5 +493,5 @@ static const struct super_operations squashfs_super_ops = {
 module_init(init_squashfs_fs);
 module_exit(exit_squashfs_fs);
 MODULE_DESCRIPTION("squashfs 4.0, a compressed read-only filesystem");
-MODULE_AUTHOR("Phillip Lougher <phillip@lougher.demon.co.uk>");
+MODULE_AUTHOR("Phillip Lougher <phillip@squashfs.org.uk>");
 MODULE_LICENSE("GPL");
index ec86434921e18c6a5bd180246439f84b56a5d00b..1191817264cc22dc1b07b6d5ca14aee99668e33c 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 3876c36699a1ca5a8d8303c11e9a5d99ab4c0492..92fcde7b4d6189c3d88f341d170dbd0fa3441012 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2010
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index b634efce4bded85e487849738af0cda27650048c..c83f5d9ec125c75a79d8578f261fe07988ad2254 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2010
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -31,6 +31,7 @@ static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb,
                u64 start, u64 *xattr_table_start, int *xattr_ids)
 {
        ERROR("Xattrs in filesystem, these will be ignored\n");
+       *xattr_table_start = start;
        return ERR_PTR(-ENOTSUPP);
 }
 
index 05385dbe1465f8ea4a2cec4cddba4042cb22ceed..c89607d690c48a8b1e6eb7cb3e8929a30dda4689 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2010
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -67,34 +67,29 @@ __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start,
                u64 *xattr_table_start, int *xattr_ids)
 {
        unsigned int len;
-       __le64 *xid_table;
-       struct squashfs_xattr_id_table id_table;
-       int err;
+       struct squashfs_xattr_id_table *id_table;
+
+       id_table = squashfs_read_table(sb, start, sizeof(*id_table));
+       if (IS_ERR(id_table))
+               return (__le64 *) id_table;
+
+       *xattr_table_start = le64_to_cpu(id_table->xattr_table_start);
+       *xattr_ids = le32_to_cpu(id_table->xattr_ids);
+       kfree(id_table);
+
+       /* Sanity check values */
+
+       /* there is always at least one xattr id */
+       if (*xattr_ids == 0)
+               return ERR_PTR(-EINVAL);
+
+       /* xattr_table should be less than start */
+       if (*xattr_table_start >= start)
+               return ERR_PTR(-EINVAL);
 
-       err = squashfs_read_table(sb, &id_table, start, sizeof(id_table));
-       if (err < 0) {
-               ERROR("unable to read xattr id table\n");
-               return ERR_PTR(err);
-       }
-       *xattr_table_start = le64_to_cpu(id_table.xattr_table_start);
-       *xattr_ids = le32_to_cpu(id_table.xattr_ids);
        len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids);
 
        TRACE("In read_xattr_index_table, length %d\n", len);
 
-       /* Allocate xattr id lookup table indexes */
-       xid_table = kmalloc(len, GFP_KERNEL);
-       if (xid_table == NULL) {
-               ERROR("Failed to allocate xattr id index table\n");
-               return ERR_PTR(-ENOMEM);
-       }
-
-       err = squashfs_read_table(sb, xid_table, start + sizeof(id_table), len);
-       if (err < 0) {
-               ERROR("unable to read xattr id index table\n");
-               kfree(xid_table);
-               return ERR_PTR(err);
-       }
-
-       return xid_table;
+       return squashfs_read_table(sb, start + sizeof(*id_table), len);
 }
index aa47a286d1f8e813b47e2d7fd30ee22957e9ced1..1760b7d108f66a55614102c43713ef315592374e 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 517688b32ffaec065505ef967742d43c1295421f..55d918fd2d862605beb85dae54c3a177b776381d 100644 (file)
@@ -2,7 +2,7 @@
  * Squashfs - a compressed read only filesystem for Linux
  *
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
- * Phillip Lougher <phillip@lougher.demon.co.uk>
+ * Phillip Lougher <phillip@squashfs.org.uk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index c04f7e0b7ed260e906f49d6d295e47d63d0b7e87..ab3d672db0deae0a84a01bc1938cd967cc27e79f 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/mutex.h>
 #include <linux/backing-dev.h>
 #include <linux/rculist_bl.h>
+#include <linux/cleancache.h>
 #include "internal.h"
 
 
@@ -112,6 +113,7 @@ static struct super_block *alloc_super(struct file_system_type *type)
                s->s_maxbytes = MAX_NON_LFS;
                s->s_op = &default_op;
                s->s_time_gran = 1000000000;
+               s->cleancache_poolid = -1;
        }
 out:
        return s;
@@ -177,6 +179,7 @@ void deactivate_locked_super(struct super_block *s)
 {
        struct file_system_type *fs = s->s_type;
        if (atomic_dec_and_test(&s->s_active)) {
+               cleancache_flush_fs(s);
                fs->kill_sb(s);
                /*
                 * We need to call rcu_barrier so all the delayed rcu free
@@ -819,7 +822,7 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
        } else {
                char b[BDEVNAME_SIZE];
 
-               s->s_flags = flags;
+               s->s_flags = flags | MS_NOSEC;
                s->s_mode = mode;
                strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
                sb_set_blocksize(s, block_size(bdev));
index 266895783b477a94e64248217483ec52f02c75fb..e34f0d99ea4ec5a7b3361b1fc0cd02fad2d23410 100644 (file)
@@ -95,6 +95,14 @@ static int sysfs_set_super(struct super_block *sb, void *data)
        return error;
 }
 
+static void free_sysfs_super_info(struct sysfs_super_info *info)
+{
+       int type;
+       for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++)
+               kobj_ns_drop(type, info->ns[type]);
+       kfree(info);
+}
+
 static struct dentry *sysfs_mount(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data)
 {
@@ -108,11 +116,11 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
                return ERR_PTR(-ENOMEM);
 
        for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++)
-               info->ns[type] = kobj_ns_current(type);
+               info->ns[type] = kobj_ns_grab_current(type);
 
        sb = sget(fs_type, sysfs_test_super, sysfs_set_super, info);
        if (IS_ERR(sb) || sb->s_fs_info != info)
-               kfree(info);
+               free_sysfs_super_info(info);
        if (IS_ERR(sb))
                return ERR_CAST(sb);
        if (!sb->s_root) {
@@ -131,12 +139,11 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
 static void sysfs_kill_sb(struct super_block *sb)
 {
        struct sysfs_super_info *info = sysfs_info(sb);
-
        /* Remove the superblock from fs_supers/s_instances
         * so we can't find it, before freeing sysfs_super_info.
         */
        kill_anon_super(sb);
-       kfree(info);
+       free_sysfs_super_info(info);
 }
 
 static struct file_system_type sysfs_fs_type = {
@@ -145,28 +152,6 @@ static struct file_system_type sysfs_fs_type = {
        .kill_sb        = sysfs_kill_sb,
 };
 
-void sysfs_exit_ns(enum kobj_ns_type type, const void *ns)
-{
-       struct super_block *sb;
-
-       mutex_lock(&sysfs_mutex);
-       spin_lock(&sb_lock);
-       list_for_each_entry(sb, &sysfs_fs_type.fs_supers, s_instances) {
-               struct sysfs_super_info *info = sysfs_info(sb);
-               /*
-                * If we see a superblock on the fs_supers/s_instances
-                * list the unmount has not completed and sb->s_fs_info
-                * points to a valid struct sysfs_super_info.
-                */
-               /* Ignore superblocks with the wrong ns */
-               if (info->ns[type] != ns)
-                       continue;
-               info->ns[type] = NULL;
-       }
-       spin_unlock(&sb_lock);
-       mutex_unlock(&sysfs_mutex);
-}
-
 int __init sysfs_init(void)
 {
        int err = -ENOMEM;
index 3d28af31d86300ecbddde7b4dc9d7eb25a255dc6..2ed2404f3113be24b1c77fa55e47f5126578e9e9 100644 (file)
@@ -136,7 +136,7 @@ struct sysfs_addrm_cxt {
  * instance).
  */
 struct sysfs_super_info {
-       const void *ns[KOBJ_NS_TYPES];
+       void *ns[KOBJ_NS_TYPES];
 };
 #define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info))
 extern struct sysfs_dirent sysfs_root;
index f67acbdda5e8c13fce54e51f72fe0882f2fa94da..dffeb3795af1d4204f8554447dbb2d2c33992429 100644 (file)
@@ -61,7 +61,9 @@ static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
 
 /*
  * Called when the clock was set to cancel the timers in the cancel
- * list.
+ * list. This will wake up processes waiting on these timers. The
+ * wake-up requires ctx->ticks to be non zero, therefore we increment
+ * it before calling wake_up_locked().
  */
 void timerfd_clock_was_set(void)
 {
@@ -76,6 +78,7 @@ void timerfd_clock_was_set(void)
                spin_lock_irqsave(&ctx->wqh.lock, flags);
                if (ctx->moffs.tv64 != moffs.tv64) {
                        ctx->moffs.tv64 = KTIME_MAX;
+                       ctx->ticks++;
                        wake_up_locked(&ctx->wqh);
                }
                spin_unlock_irqrestore(&ctx->wqh.lock, flags);
index 8b3a7da531ebc10c38cad6b73d937e7a29095699..315de66e52b21fc8016f96b5a62b4e94fa41ecd7 100644 (file)
@@ -106,7 +106,7 @@ static long long get_liability(struct ubifs_info *c)
        long long liab;
 
        spin_lock(&c->space_lock);
-       liab = c->budg_idx_growth + c->budg_data_growth + c->budg_dd_growth;
+       liab = c->bi.idx_growth + c->bi.data_growth + c->bi.dd_growth;
        spin_unlock(&c->space_lock);
        return liab;
 }
@@ -180,7 +180,7 @@ int ubifs_calc_min_idx_lebs(struct ubifs_info *c)
        int idx_lebs;
        long long idx_size;
 
-       idx_size = c->old_idx_sz + c->budg_idx_growth + c->budg_uncommitted_idx;
+       idx_size = c->bi.old_idx_sz + c->bi.idx_growth + c->bi.uncommitted_idx;
        /* And make sure we have thrice the index size of space reserved */
        idx_size += idx_size << 1;
        /*
@@ -292,13 +292,13 @@ static int can_use_rp(struct ubifs_info *c)
  * budgeted index space to the size of the current index, multiplies this by 3,
  * and makes sure this does not exceed the amount of free LEBs.
  *
- * Notes about @c->min_idx_lebs and @c->lst.idx_lebs variables:
+ * Notes about @c->bi.min_idx_lebs and @c->lst.idx_lebs variables:
  * o @c->lst.idx_lebs is the number of LEBs the index currently uses. It might
  *    be large, because UBIFS does not do any index consolidation as long as
  *    there is free space. IOW, the index may take a lot of LEBs, but the LEBs
  *    will contain a lot of dirt.
- * o @c->min_idx_lebs is the number of LEBS the index presumably takes. IOW,
- *    the index may be consolidated to take up to @c->min_idx_lebs LEBs.
+ * o @c->bi.min_idx_lebs is the number of LEBS the index presumably takes. IOW,
+ *    the index may be consolidated to take up to @c->bi.min_idx_lebs LEBs.
  *
  * This function returns zero in case of success, and %-ENOSPC in case of
  * failure.
@@ -343,13 +343,13 @@ static int do_budget_space(struct ubifs_info *c)
               c->lst.taken_empty_lebs;
        if (unlikely(rsvd_idx_lebs > lebs)) {
                dbg_budg("out of indexing space: min_idx_lebs %d (old %d), "
-                        "rsvd_idx_lebs %d", min_idx_lebs, c->min_idx_lebs,
+                        "rsvd_idx_lebs %d", min_idx_lebs, c->bi.min_idx_lebs,
                         rsvd_idx_lebs);
                return -ENOSPC;
        }
 
        available = ubifs_calc_available(c, min_idx_lebs);
-       outstanding = c->budg_data_growth + c->budg_dd_growth;
+       outstanding = c->bi.data_growth + c->bi.dd_growth;
 
        if (unlikely(available < outstanding)) {
                dbg_budg("out of data space: available %lld, outstanding %lld",
@@ -360,7 +360,7 @@ static int do_budget_space(struct ubifs_info *c)
        if (available - outstanding <= c->rp_size && !can_use_rp(c))
                return -ENOSPC;
 
-       c->min_idx_lebs = min_idx_lebs;
+       c->bi.min_idx_lebs = min_idx_lebs;
        return 0;
 }
 
@@ -393,11 +393,11 @@ static int calc_data_growth(const struct ubifs_info *c,
 {
        int data_growth;
 
-       data_growth = req->new_ino  ? c->inode_budget : 0;
+       data_growth = req->new_ino  ? c->bi.inode_budget : 0;
        if (req->new_page)
-               data_growth += c->page_budget;
+               data_growth += c->bi.page_budget;
        if (req->new_dent)
-               data_growth += c->dent_budget;
+               data_growth += c->bi.dent_budget;
        data_growth += req->new_ino_d;
        return data_growth;
 }
@@ -413,12 +413,12 @@ static int calc_dd_growth(const struct ubifs_info *c,
 {
        int dd_growth;
 
-       dd_growth = req->dirtied_page ? c->page_budget : 0;
+       dd_growth = req->dirtied_page ? c->bi.page_budget : 0;
 
        if (req->dirtied_ino)
-               dd_growth += c->inode_budget << (req->dirtied_ino - 1);
+               dd_growth += c->bi.inode_budget << (req->dirtied_ino - 1);
        if (req->mod_dent)
-               dd_growth += c->dent_budget;
+               dd_growth += c->bi.dent_budget;
        dd_growth += req->dirtied_ino_d;
        return dd_growth;
 }
@@ -460,19 +460,19 @@ int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req)
 
 again:
        spin_lock(&c->space_lock);
-       ubifs_assert(c->budg_idx_growth >= 0);
-       ubifs_assert(c->budg_data_growth >= 0);
-       ubifs_assert(c->budg_dd_growth >= 0);
+       ubifs_assert(c->bi.idx_growth >= 0);
+       ubifs_assert(c->bi.data_growth >= 0);
+       ubifs_assert(c->bi.dd_growth >= 0);
 
-       if (unlikely(c->nospace) && (c->nospace_rp || !can_use_rp(c))) {
+       if (unlikely(c->bi.nospace) && (c->bi.nospace_rp || !can_use_rp(c))) {
                dbg_budg("no space");
                spin_unlock(&c->space_lock);
                return -ENOSPC;
        }
 
-       c->budg_idx_growth += idx_growth;
-       c->budg_data_growth += data_growth;
-       c->budg_dd_growth += dd_growth;
+       c->bi.idx_growth += idx_growth;
+       c->bi.data_growth += data_growth;
+       c->bi.dd_growth += dd_growth;
 
        err = do_budget_space(c);
        if (likely(!err)) {
@@ -484,9 +484,9 @@ again:
        }
 
        /* Restore the old values */
-       c->budg_idx_growth -= idx_growth;
-       c->budg_data_growth -= data_growth;
-       c->budg_dd_growth -= dd_growth;
+       c->bi.idx_growth -= idx_growth;
+       c->bi.data_growth -= data_growth;
+       c->bi.dd_growth -= dd_growth;
        spin_unlock(&c->space_lock);
 
        if (req->fast) {
@@ -506,9 +506,9 @@ again:
                        goto again;
                }
                dbg_budg("FS is full, -ENOSPC");
-               c->nospace = 1;
+               c->bi.nospace = 1;
                if (can_use_rp(c) || c->rp_size == 0)
-                       c->nospace_rp = 1;
+                       c->bi.nospace_rp = 1;
                smp_wmb();
        } else
                ubifs_err("cannot budget space, error %d", err);
@@ -523,8 +523,8 @@ again:
  * This function releases the space budgeted by 'ubifs_budget_space()'. Note,
  * since the index changes (which were budgeted for in @req->idx_growth) will
  * only be written to the media on commit, this function moves the index budget
- * from @c->budg_idx_growth to @c->budg_uncommitted_idx. The latter will be
- * zeroed by the commit operation.
+ * from @c->bi.idx_growth to @c->bi.uncommitted_idx. The latter will be zeroed
+ * by the commit operation.
  */
 void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req)
 {
@@ -553,23 +553,23 @@ void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req)
        if (!req->data_growth && !req->dd_growth)
                return;
 
-       c->nospace = c->nospace_rp = 0;
+       c->bi.nospace = c->bi.nospace_rp = 0;
        smp_wmb();
 
        spin_lock(&c->space_lock);
-       c->budg_idx_growth -= req->idx_growth;
-       c->budg_uncommitted_idx += req->idx_growth;
-       c->budg_data_growth -= req->data_growth;
-       c->budg_dd_growth -= req->dd_growth;
-       c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
-
-       ubifs_assert(c->budg_idx_growth >= 0);
-       ubifs_assert(c->budg_data_growth >= 0);
-       ubifs_assert(c->budg_dd_growth >= 0);
-       ubifs_assert(c->min_idx_lebs < c->main_lebs);
-       ubifs_assert(!(c->budg_idx_growth & 7));
-       ubifs_assert(!(c->budg_data_growth & 7));
-       ubifs_assert(!(c->budg_dd_growth & 7));
+       c->bi.idx_growth -= req->idx_growth;
+       c->bi.uncommitted_idx += req->idx_growth;
+       c->bi.data_growth -= req->data_growth;
+       c->bi.dd_growth -= req->dd_growth;
+       c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+
+       ubifs_assert(c->bi.idx_growth >= 0);
+       ubifs_assert(c->bi.data_growth >= 0);
+       ubifs_assert(c->bi.dd_growth >= 0);
+       ubifs_assert(c->bi.min_idx_lebs < c->main_lebs);
+       ubifs_assert(!(c->bi.idx_growth & 7));
+       ubifs_assert(!(c->bi.data_growth & 7));
+       ubifs_assert(!(c->bi.dd_growth & 7));
        spin_unlock(&c->space_lock);
 }
 
@@ -586,13 +586,13 @@ void ubifs_convert_page_budget(struct ubifs_info *c)
 {
        spin_lock(&c->space_lock);
        /* Release the index growth reservation */
-       c->budg_idx_growth -= c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT;
+       c->bi.idx_growth -= c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT;
        /* Release the data growth reservation */
-       c->budg_data_growth -= c->page_budget;
+       c->bi.data_growth -= c->bi.page_budget;
        /* Increase the dirty data growth reservation instead */
-       c->budg_dd_growth += c->page_budget;
+       c->bi.dd_growth += c->bi.page_budget;
        /* And re-calculate the indexing space reservation */
-       c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
        spin_unlock(&c->space_lock);
 }
 
@@ -612,7 +612,7 @@ void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
 
        memset(&req, 0, sizeof(struct ubifs_budget_req));
        /* The "no space" flags will be cleared because dd_growth is > 0 */
-       req.dd_growth = c->inode_budget + ALIGN(ui->data_len, 8);
+       req.dd_growth = c->bi.inode_budget + ALIGN(ui->data_len, 8);
        ubifs_release_budget(c, &req);
 }
 
@@ -682,9 +682,9 @@ long long ubifs_get_free_space_nolock(struct ubifs_info *c)
        int rsvd_idx_lebs, lebs;
        long long available, outstanding, free;
 
-       ubifs_assert(c->min_idx_lebs == ubifs_calc_min_idx_lebs(c));
-       outstanding = c->budg_data_growth + c->budg_dd_growth;
-       available = ubifs_calc_available(c, c->min_idx_lebs);
+       ubifs_assert(c->bi.min_idx_lebs == ubifs_calc_min_idx_lebs(c));
+       outstanding = c->bi.data_growth + c->bi.dd_growth;
+       available = ubifs_calc_available(c, c->bi.min_idx_lebs);
 
        /*
         * When reporting free space to user-space, UBIFS guarantees that it is
@@ -697,8 +697,8 @@ long long ubifs_get_free_space_nolock(struct ubifs_info *c)
         * Note, the calculations below are similar to what we have in
         * 'do_budget_space()', so refer there for comments.
         */
-       if (c->min_idx_lebs > c->lst.idx_lebs)
-               rsvd_idx_lebs = c->min_idx_lebs - c->lst.idx_lebs;
+       if (c->bi.min_idx_lebs > c->lst.idx_lebs)
+               rsvd_idx_lebs = c->bi.min_idx_lebs - c->lst.idx_lebs;
        else
                rsvd_idx_lebs = 0;
        lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
index 1bd01ded7123913f28574261811f73a43a6d4e70..87cd0ead8633f17f9596f1b38adc1f4e48055865 100644 (file)
@@ -182,7 +182,7 @@ static int do_commit(struct ubifs_info *c)
        c->mst_node->root_len    = cpu_to_le32(zroot.len);
        c->mst_node->ihead_lnum  = cpu_to_le32(c->ihead_lnum);
        c->mst_node->ihead_offs  = cpu_to_le32(c->ihead_offs);
-       c->mst_node->index_size  = cpu_to_le64(c->old_idx_sz);
+       c->mst_node->index_size  = cpu_to_le64(c->bi.old_idx_sz);
        c->mst_node->lpt_lnum    = cpu_to_le32(c->lpt_lnum);
        c->mst_node->lpt_offs    = cpu_to_le32(c->lpt_offs);
        c->mst_node->nhead_lnum  = cpu_to_le32(c->nhead_lnum);
index 004d3745dc453a1dcdb6f9eb32cd0a0499d85923..0bb2bcef0de9a8ab8815dfd62103b0bbe601202f 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/moduleparam.h>
 #include <linux/debugfs.h>
 #include <linux/math64.h>
-#include <linux/slab.h>
 
 #ifdef CONFIG_UBIFS_FS_DEBUG
 
@@ -43,15 +42,12 @@ DEFINE_SPINLOCK(dbg_lock);
 static char dbg_key_buf0[128];
 static char dbg_key_buf1[128];
 
-unsigned int ubifs_msg_flags;
 unsigned int ubifs_chk_flags;
 unsigned int ubifs_tst_flags;
 
-module_param_named(debug_msgs, ubifs_msg_flags, uint, S_IRUGO | S_IWUSR);
 module_param_named(debug_chks, ubifs_chk_flags, uint, S_IRUGO | S_IWUSR);
 module_param_named(debug_tsts, ubifs_tst_flags, uint, S_IRUGO | S_IWUSR);
 
-MODULE_PARM_DESC(debug_msgs, "Debug message type flags");
 MODULE_PARM_DESC(debug_chks, "Debug check flags");
 MODULE_PARM_DESC(debug_tsts, "Debug special test flags");
 
@@ -317,6 +313,8 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
                printk(KERN_DEBUG "\tflags          %#x\n", sup_flags);
                printk(KERN_DEBUG "\t  big_lpt      %u\n",
                       !!(sup_flags & UBIFS_FLG_BIGLPT));
+               printk(KERN_DEBUG "\t  space_fixup  %u\n",
+                      !!(sup_flags & UBIFS_FLG_SPACE_FIXUP));
                printk(KERN_DEBUG "\tmin_io_size    %u\n",
                       le32_to_cpu(sup->min_io_size));
                printk(KERN_DEBUG "\tleb_size       %u\n",
@@ -602,7 +600,7 @@ void dbg_dump_lstats(const struct ubifs_lp_stats *lst)
        spin_unlock(&dbg_lock);
 }
 
-void dbg_dump_budg(struct ubifs_info *c)
+void dbg_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi)
 {
        int i;
        struct rb_node *rb;
@@ -610,26 +608,42 @@ void dbg_dump_budg(struct ubifs_info *c)
        struct ubifs_gced_idx_leb *idx_gc;
        long long available, outstanding, free;
 
-       ubifs_assert(spin_is_locked(&c->space_lock));
+       spin_lock(&c->space_lock);
        spin_lock(&dbg_lock);
-       printk(KERN_DEBUG "(pid %d) Budgeting info: budg_data_growth %lld, "
-              "budg_dd_growth %lld, budg_idx_growth %lld\n", current->pid,
-              c->budg_data_growth, c->budg_dd_growth, c->budg_idx_growth);
-       printk(KERN_DEBUG "\tdata budget sum %lld, total budget sum %lld, "
-              "freeable_cnt %d\n", c->budg_data_growth + c->budg_dd_growth,
-              c->budg_data_growth + c->budg_dd_growth + c->budg_idx_growth,
-              c->freeable_cnt);
-       printk(KERN_DEBUG "\tmin_idx_lebs %d, old_idx_sz %lld, "
-              "calc_idx_sz %lld, idx_gc_cnt %d\n", c->min_idx_lebs,
-              c->old_idx_sz, c->calc_idx_sz, c->idx_gc_cnt);
+       printk(KERN_DEBUG "(pid %d) Budgeting info: data budget sum %lld, "
+              "total budget sum %lld\n", current->pid,
+              bi->data_growth + bi->dd_growth,
+              bi->data_growth + bi->dd_growth + bi->idx_growth);
+       printk(KERN_DEBUG "\tbudg_data_growth %lld, budg_dd_growth %lld, "
+              "budg_idx_growth %lld\n", bi->data_growth, bi->dd_growth,
+              bi->idx_growth);
+       printk(KERN_DEBUG "\tmin_idx_lebs %d, old_idx_sz %llu, "
+              "uncommitted_idx %lld\n", bi->min_idx_lebs, bi->old_idx_sz,
+              bi->uncommitted_idx);
+       printk(KERN_DEBUG "\tpage_budget %d, inode_budget %d, dent_budget %d\n",
+              bi->page_budget, bi->inode_budget, bi->dent_budget);
+       printk(KERN_DEBUG "\tnospace %u, nospace_rp %u\n",
+              bi->nospace, bi->nospace_rp);
+       printk(KERN_DEBUG "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n",
+              c->dark_wm, c->dead_wm, c->max_idx_node_sz);
+
+       if (bi != &c->bi)
+               /*
+                * If we are dumping saved budgeting data, do not print
+                * additional information which is about the current state, not
+                * the old one which corresponded to the saved budgeting data.
+                */
+               goto out_unlock;
+
+       printk(KERN_DEBUG "\tfreeable_cnt %d, calc_idx_sz %lld, idx_gc_cnt %d\n",
+              c->freeable_cnt, c->calc_idx_sz, c->idx_gc_cnt);
        printk(KERN_DEBUG "\tdirty_pg_cnt %ld, dirty_zn_cnt %ld, "
               "clean_zn_cnt %ld\n", atomic_long_read(&c->dirty_pg_cnt),
               atomic_long_read(&c->dirty_zn_cnt),
               atomic_long_read(&c->clean_zn_cnt));
-       printk(KERN_DEBUG "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n",
-              c->dark_wm, c->dead_wm, c->max_idx_node_sz);
        printk(KERN_DEBUG "\tgc_lnum %d, ihead_lnum %d\n",
               c->gc_lnum, c->ihead_lnum);
+
        /* If we are in R/O mode, journal heads do not exist */
        if (c->jheads)
                for (i = 0; i < c->jhead_cnt; i++)
@@ -648,13 +662,15 @@ void dbg_dump_budg(struct ubifs_info *c)
        printk(KERN_DEBUG "\tcommit state %d\n", c->cmt_state);
 
        /* Print budgeting predictions */
-       available = ubifs_calc_available(c, c->min_idx_lebs);
-       outstanding = c->budg_data_growth + c->budg_dd_growth;
+       available = ubifs_calc_available(c, c->bi.min_idx_lebs);
+       outstanding = c->bi.data_growth + c->bi.dd_growth;
        free = ubifs_get_free_space_nolock(c);
        printk(KERN_DEBUG "Budgeting predictions:\n");
        printk(KERN_DEBUG "\tavailable: %lld, outstanding %lld, free %lld\n",
               available, outstanding, free);
+out_unlock:
        spin_unlock(&dbg_lock);
+       spin_unlock(&c->space_lock);
 }
 
 void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
@@ -729,7 +745,13 @@ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
                if (bud->lnum == lp->lnum) {
                        int head = 0;
                        for (i = 0; i < c->jhead_cnt; i++) {
-                               if (lp->lnum == c->jheads[i].wbuf.lnum) {
+                               /*
+                                * Note, if we are in R/O mode or in the middle
+                                * of mounting/re-mounting, the write-buffers do
+                                * not exist.
+                                */
+                               if (c->jheads &&
+                                   lp->lnum == c->jheads[i].wbuf.lnum) {
                                        printk(KERN_CONT ", jhead %s",
                                               dbg_jhead(i));
                                        head = 1;
@@ -976,6 +998,8 @@ void dbg_save_space_info(struct ubifs_info *c)
 
        spin_lock(&c->space_lock);
        memcpy(&d->saved_lst, &c->lst, sizeof(struct ubifs_lp_stats));
+       memcpy(&d->saved_bi, &c->bi, sizeof(struct ubifs_budg_info));
+       d->saved_idx_gc_cnt = c->idx_gc_cnt;
 
        /*
         * We use a dirty hack here and zero out @c->freeable_cnt, because it
@@ -1042,14 +1066,14 @@ int dbg_check_space_info(struct ubifs_info *c)
 out:
        ubifs_msg("saved lprops statistics dump");
        dbg_dump_lstats(&d->saved_lst);
-       ubifs_get_lp_stats(c, &lst);
-
+       ubifs_msg("saved budgeting info dump");
+       dbg_dump_budg(c, &d->saved_bi);
+       ubifs_msg("saved idx_gc_cnt %d", d->saved_idx_gc_cnt);
        ubifs_msg("current lprops statistics dump");
+       ubifs_get_lp_stats(c, &lst);
        dbg_dump_lstats(&lst);
-
-       spin_lock(&c->space_lock);
-       dbg_dump_budg(c);
-       spin_unlock(&c->space_lock);
+       ubifs_msg("current budgeting info dump");
+       dbg_dump_budg(c, &c->bi);
        dump_stack();
        return -EINVAL;
 }
@@ -1793,6 +1817,8 @@ static struct fsck_inode *add_inode(struct ubifs_info *c,
        struct rb_node **p, *parent = NULL;
        struct fsck_inode *fscki;
        ino_t inum = key_inum_flash(c, &ino->key);
+       struct inode *inode;
+       struct ubifs_inode *ui;
 
        p = &fsckd->inodes.rb_node;
        while (*p) {
@@ -1816,19 +1842,46 @@ static struct fsck_inode *add_inode(struct ubifs_info *c,
        if (!fscki)
                return ERR_PTR(-ENOMEM);
 
+       inode = ilookup(c->vfs_sb, inum);
+
        fscki->inum = inum;
-       fscki->nlink = le32_to_cpu(ino->nlink);
-       fscki->size = le64_to_cpu(ino->size);
-       fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt);
-       fscki->xattr_sz = le32_to_cpu(ino->xattr_size);
-       fscki->xattr_nms = le32_to_cpu(ino->xattr_names);
-       fscki->mode = le32_to_cpu(ino->mode);
+       /*
+        * If the inode is present in the VFS inode cache, use it instead of
+        * the on-flash inode which might be out-of-date. E.g., the size might
+        * be out-of-date. If we do not do this, the following may happen, for
+        * example:
+        *   1. A power cut happens
+        *   2. We mount the file-system R/O, the replay process fixes up the
+        *      inode size in the VFS cache, but on on-flash.
+        *   3. 'check_leaf()' fails because it hits a data node beyond inode
+        *      size.
+        */
+       if (!inode) {
+               fscki->nlink = le32_to_cpu(ino->nlink);
+               fscki->size = le64_to_cpu(ino->size);
+               fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt);
+               fscki->xattr_sz = le32_to_cpu(ino->xattr_size);
+               fscki->xattr_nms = le32_to_cpu(ino->xattr_names);
+               fscki->mode = le32_to_cpu(ino->mode);
+       } else {
+               ui = ubifs_inode(inode);
+               fscki->nlink = inode->i_nlink;
+               fscki->size = inode->i_size;
+               fscki->xattr_cnt = ui->xattr_cnt;
+               fscki->xattr_sz = ui->xattr_size;
+               fscki->xattr_nms = ui->xattr_names;
+               fscki->mode = inode->i_mode;
+               iput(inode);
+       }
+
        if (S_ISDIR(fscki->mode)) {
                fscki->calc_sz = UBIFS_INO_NODE_SZ;
                fscki->calc_cnt = 2;
        }
+
        rb_link_node(&fscki->rb, parent, p);
        rb_insert_color(&fscki->rb, &fsckd->inodes);
+
        return fscki;
 }
 
@@ -2421,7 +2474,8 @@ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
                hashb = key_block(c, &sb->key);
 
                if (hasha > hashb) {
-                       ubifs_err("larger hash %u goes before %u", hasha, hashb);
+                       ubifs_err("larger hash %u goes before %u",
+                                 hasha, hashb);
                        goto error_dump;
                }
        }
@@ -2437,14 +2491,12 @@ error_dump:
        return 0;
 }
 
-static int invocation_cnt;
-
 int dbg_force_in_the_gaps(void)
 {
-       if (!dbg_force_in_the_gaps_enabled)
+       if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
                return 0;
-       /* Force in-the-gaps every 8th commit */
-       return !((invocation_cnt++) & 0x7);
+
+       return !(random32() & 7);
 }
 
 /* Failure mode for recovery testing */
@@ -2632,7 +2684,7 @@ int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
                 int len, int check)
 {
        if (in_failure_mode(desc))
-               return -EIO;
+               return -EROFS;
        return ubi_leb_read(desc, lnum, buf, offset, len, check);
 }
 
@@ -2642,7 +2694,7 @@ int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
        int err, failing;
 
        if (in_failure_mode(desc))
-               return -EIO;
+               return -EROFS;
        failing = do_fail(desc, lnum, 1);
        if (failing)
                cut_data(buf, len);
@@ -2650,7 +2702,7 @@ int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
        if (err)
                return err;
        if (failing)
-               return -EIO;
+               return -EROFS;
        return 0;
 }
 
@@ -2660,12 +2712,12 @@ int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
        int err;
 
        if (do_fail(desc, lnum, 1))
-               return -EIO;
+               return -EROFS;
        err = ubi_leb_change(desc, lnum, buf, len, dtype);
        if (err)
                return err;
        if (do_fail(desc, lnum, 1))
-               return -EIO;
+               return -EROFS;
        return 0;
 }
 
@@ -2674,12 +2726,12 @@ int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum)
        int err;
 
        if (do_fail(desc, lnum, 0))
-               return -EIO;
+               return -EROFS;
        err = ubi_leb_erase(desc, lnum);
        if (err)
                return err;
        if (do_fail(desc, lnum, 0))
-               return -EIO;
+               return -EROFS;
        return 0;
 }
 
@@ -2688,19 +2740,19 @@ int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum)
        int err;
 
        if (do_fail(desc, lnum, 0))
-               return -EIO;
+               return -EROFS;
        err = ubi_leb_unmap(desc, lnum);
        if (err)
                return err;
        if (do_fail(desc, lnum, 0))
-               return -EIO;
+               return -EROFS;
        return 0;
 }
 
 int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum)
 {
        if (in_failure_mode(desc))
-               return -EIO;
+               return -EROFS;
        return ubi_is_mapped(desc, lnum);
 }
 
@@ -2709,12 +2761,12 @@ int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
        int err;
 
        if (do_fail(desc, lnum, 0))
-               return -EIO;
+               return -EROFS;
        err = ubi_leb_map(desc, lnum, dtype);
        if (err)
                return err;
        if (do_fail(desc, lnum, 0))
-               return -EIO;
+               return -EROFS;
        return 0;
 }
 
@@ -2784,7 +2836,7 @@ void dbg_debugfs_exit(void)
 static int open_debugfs_file(struct inode *inode, struct file *file)
 {
        file->private_data = inode->i_private;
-       return 0;
+       return nonseekable_open(inode, file);
 }
 
 static ssize_t write_debugfs_file(struct file *file, const char __user *buf,
@@ -2795,18 +2847,15 @@ static ssize_t write_debugfs_file(struct file *file, const char __user *buf,
 
        if (file->f_path.dentry == d->dfs_dump_lprops)
                dbg_dump_lprops(c);
-       else if (file->f_path.dentry == d->dfs_dump_budg) {
-               spin_lock(&c->space_lock);
-               dbg_dump_budg(c);
-               spin_unlock(&c->space_lock);
-       } else if (file->f_path.dentry == d->dfs_dump_tnc) {
+       else if (file->f_path.dentry == d->dfs_dump_budg)
+               dbg_dump_budg(c, &c->bi);
+       else if (file->f_path.dentry == d->dfs_dump_tnc) {
                mutex_lock(&c->tnc_mutex);
                dbg_dump_tnc(c);
                mutex_unlock(&c->tnc_mutex);
        } else
                return -EINVAL;
 
-       *ppos += count;
        return count;
 }
 
@@ -2814,7 +2863,7 @@ static const struct file_operations dfs_fops = {
        .open = open_debugfs_file,
        .write = write_debugfs_file,
        .owner = THIS_MODULE,
-       .llseek = default_llseek,
+       .llseek = no_llseek,
 };
 
 /**
index e6493cac193d60d92c6e3e72d743d03f46a5796d..a811ac4a26bb68de36c14756446d1c0de9bcbc7b 100644 (file)
@@ -31,6 +31,8 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
 
 #ifdef CONFIG_UBIFS_FS_DEBUG
 
+#include <linux/random.h>
+
 /**
  * ubifs_debug_info - per-FS debugging information.
  * @old_zroot: old index root - used by 'dbg_check_old_index()'
@@ -50,13 +52,15 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
  * @new_ihead_offs: used by debugging to check @c->ihead_offs
  *
  * @saved_lst: saved lprops statistics (used by 'dbg_save_space_info()')
- * @saved_free: saved free space (used by 'dbg_save_space_info()')
+ * @saved_bi: saved budgeting information
+ * @saved_free: saved amount of free space
+ * @saved_idx_gc_cnt: saved value of @c->idx_gc_cnt
  *
- * dfs_dir_name: name of debugfs directory containing this file-system's files
- * dfs_dir: direntry object of the file-system debugfs directory
- * dfs_dump_lprops: "dump lprops" debugfs knob
- * dfs_dump_budg: "dump budgeting information" debugfs knob
- * dfs_dump_tnc: "dump TNC" debugfs knob
+ * @dfs_dir_name: name of debugfs directory containing this file-system's files
+ * @dfs_dir: direntry object of the file-system debugfs directory
+ * @dfs_dump_lprops: "dump lprops" debugfs knob
+ * @dfs_dump_budg: "dump budgeting information" debugfs knob
+ * @dfs_dump_tnc: "dump TNC" debugfs knob
  */
 struct ubifs_debug_info {
        struct ubifs_zbranch old_zroot;
@@ -76,7 +80,9 @@ struct ubifs_debug_info {
        int new_ihead_offs;
 
        struct ubifs_lp_stats saved_lst;
+       struct ubifs_budg_info saved_bi;
        long long saved_free;
+       int saved_idx_gc_cnt;
 
        char dfs_dir_name[100];
        struct dentry *dfs_dir;
@@ -101,23 +107,7 @@ struct ubifs_debug_info {
        }                                                                      \
 } while (0)
 
-#define dbg_dump_stack() do {                                                  \
-       if (!dbg_failure_mode)                                                 \
-               dump_stack();                                                  \
-} while (0)
-
-/* Generic debugging messages */
-#define dbg_msg(fmt, ...) do {                                                 \
-       spin_lock(&dbg_lock);                                                  \
-       printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", current->pid,   \
-              __func__, ##__VA_ARGS__);                                       \
-       spin_unlock(&dbg_lock);                                                \
-} while (0)
-
-#define dbg_do_msg(typ, fmt, ...) do {                                         \
-       if (ubifs_msg_flags & typ)                                             \
-               dbg_msg(fmt, ##__VA_ARGS__);                                   \
-} while (0)
+#define dbg_dump_stack() dump_stack()
 
 #define dbg_err(fmt, ...) do {                                                 \
        spin_lock(&dbg_lock);                                                  \
@@ -137,77 +127,40 @@ const char *dbg_key_str1(const struct ubifs_info *c,
 #define DBGKEY(key) dbg_key_str0(c, (key))
 #define DBGKEY1(key) dbg_key_str1(c, (key))
 
-/* General messages */
-#define dbg_gen(fmt, ...)   dbg_do_msg(UBIFS_MSG_GEN, fmt, ##__VA_ARGS__)
+#define ubifs_dbg_msg(type, fmt, ...) do {                        \
+       spin_lock(&dbg_lock);                                     \
+       pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__); \
+       spin_unlock(&dbg_lock);                                   \
+} while (0)
 
+/* Just a debugging messages not related to any specific UBIFS subsystem */
+#define dbg_msg(fmt, ...)   ubifs_dbg_msg("msg", fmt, ##__VA_ARGS__)
+/* General messages */
+#define dbg_gen(fmt, ...)   ubifs_dbg_msg("gen", fmt, ##__VA_ARGS__)
 /* Additional journal messages */
-#define dbg_jnl(fmt, ...)   dbg_do_msg(UBIFS_MSG_JNL, fmt, ##__VA_ARGS__)
-
+#define dbg_jnl(fmt, ...)   ubifs_dbg_msg("jnl", fmt, ##__VA_ARGS__)
 /* Additional TNC messages */
-#define dbg_tnc(fmt, ...)   dbg_do_msg(UBIFS_MSG_TNC, fmt, ##__VA_ARGS__)
-
+#define dbg_tnc(fmt, ...)   ubifs_dbg_msg("tnc", fmt, ##__VA_ARGS__)
 /* Additional lprops messages */
-#define dbg_lp(fmt, ...)    dbg_do_msg(UBIFS_MSG_LP, fmt, ##__VA_ARGS__)
-
+#define dbg_lp(fmt, ...)    ubifs_dbg_msg("lp", fmt, ##__VA_ARGS__)
 /* Additional LEB find messages */
-#define dbg_find(fmt, ...)  dbg_do_msg(UBIFS_MSG_FIND, fmt, ##__VA_ARGS__)
-
+#define dbg_find(fmt, ...)  ubifs_dbg_msg("find", fmt, ##__VA_ARGS__)
 /* Additional mount messages */
-#define dbg_mnt(fmt, ...)   dbg_do_msg(UBIFS_MSG_MNT, fmt, ##__VA_ARGS__)
-
+#define dbg_mnt(fmt, ...)   ubifs_dbg_msg("mnt", fmt, ##__VA_ARGS__)
 /* Additional I/O messages */
-#define dbg_io(fmt, ...)    dbg_do_msg(UBIFS_MSG_IO, fmt, ##__VA_ARGS__)
-
+#define dbg_io(fmt, ...)    ubifs_dbg_msg("io", fmt, ##__VA_ARGS__)
 /* Additional commit messages */
-#define dbg_cmt(fmt, ...)   dbg_do_msg(UBIFS_MSG_CMT, fmt, ##__VA_ARGS__)
-
+#define dbg_cmt(fmt, ...)   ubifs_dbg_msg("cmt", fmt, ##__VA_ARGS__)
 /* Additional budgeting messages */
-#define dbg_budg(fmt, ...)  dbg_do_msg(UBIFS_MSG_BUDG, fmt, ##__VA_ARGS__)
-
+#define dbg_budg(fmt, ...)  ubifs_dbg_msg("budg", fmt, ##__VA_ARGS__)
 /* Additional log messages */
-#define dbg_log(fmt, ...)   dbg_do_msg(UBIFS_MSG_LOG, fmt, ##__VA_ARGS__)
-
+#define dbg_log(fmt, ...)   ubifs_dbg_msg("log", fmt, ##__VA_ARGS__)
 /* Additional gc messages */
-#define dbg_gc(fmt, ...)    dbg_do_msg(UBIFS_MSG_GC, fmt, ##__VA_ARGS__)
-
+#define dbg_gc(fmt, ...)    ubifs_dbg_msg("gc", fmt, ##__VA_ARGS__)
 /* Additional scan messages */
-#define dbg_scan(fmt, ...)  dbg_do_msg(UBIFS_MSG_SCAN, fmt, ##__VA_ARGS__)
-
+#define dbg_scan(fmt, ...)  ubifs_dbg_msg("scan", fmt, ##__VA_ARGS__)
 /* Additional recovery messages */
-#define dbg_rcvry(fmt, ...) dbg_do_msg(UBIFS_MSG_RCVRY, fmt, ##__VA_ARGS__)
-
-/*
- * Debugging message type flags.
- *
- * UBIFS_MSG_GEN: general messages
- * UBIFS_MSG_JNL: journal messages
- * UBIFS_MSG_MNT: mount messages
- * UBIFS_MSG_CMT: commit messages
- * UBIFS_MSG_FIND: LEB find messages
- * UBIFS_MSG_BUDG: budgeting messages
- * UBIFS_MSG_GC: garbage collection messages
- * UBIFS_MSG_TNC: TNC messages
- * UBIFS_MSG_LP: lprops messages
- * UBIFS_MSG_IO: I/O messages
- * UBIFS_MSG_LOG: log messages
- * UBIFS_MSG_SCAN: scan messages
- * UBIFS_MSG_RCVRY: recovery messages
- */
-enum {
-       UBIFS_MSG_GEN   = 0x1,
-       UBIFS_MSG_JNL   = 0x2,
-       UBIFS_MSG_MNT   = 0x4,
-       UBIFS_MSG_CMT   = 0x8,
-       UBIFS_MSG_FIND  = 0x10,
-       UBIFS_MSG_BUDG  = 0x20,
-       UBIFS_MSG_GC    = 0x40,
-       UBIFS_MSG_TNC   = 0x80,
-       UBIFS_MSG_LP    = 0x100,
-       UBIFS_MSG_IO    = 0x200,
-       UBIFS_MSG_LOG   = 0x400,
-       UBIFS_MSG_SCAN  = 0x800,
-       UBIFS_MSG_RCVRY = 0x1000,
-};
+#define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__)
 
 /*
  * Debugging check flags.
@@ -233,11 +186,9 @@ enum {
 /*
  * Special testing flags.
  *
- * UBIFS_TST_FORCE_IN_THE_GAPS: force the use of in-the-gaps method
  * UBIFS_TST_RCVRY: failure mode for recovery testing
  */
 enum {
-       UBIFS_TST_FORCE_IN_THE_GAPS = 0x2,
        UBIFS_TST_RCVRY             = 0x4,
 };
 
@@ -262,7 +213,7 @@ void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum,
                       int offs);
 void dbg_dump_budget_req(const struct ubifs_budget_req *req);
 void dbg_dump_lstats(const struct ubifs_lp_stats *lst);
-void dbg_dump_budg(struct ubifs_info *c);
+void dbg_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi);
 void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp);
 void dbg_dump_lprops(struct ubifs_info *c);
 void dbg_dump_lpt_info(struct ubifs_info *c);
@@ -304,18 +255,16 @@ int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head);
 int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head);
 
 /* Force the use of in-the-gaps method for testing */
-
-#define dbg_force_in_the_gaps_enabled \
-       (ubifs_tst_flags & UBIFS_TST_FORCE_IN_THE_GAPS)
-
+static inline int dbg_force_in_the_gaps_enabled(void)
+{
+       return ubifs_chk_flags & UBIFS_CHK_GEN;
+}
 int dbg_force_in_the_gaps(void);
 
 /* Failure mode for recovery testing */
-
 #define dbg_failure_mode (ubifs_tst_flags & UBIFS_TST_RCVRY)
 
 #ifndef UBIFS_DBG_PRESERVE_UBI
-
 #define ubi_leb_read   dbg_leb_read
 #define ubi_leb_write  dbg_leb_write
 #define ubi_leb_change dbg_leb_change
@@ -323,7 +272,6 @@ int dbg_force_in_the_gaps(void);
 #define ubi_leb_unmap  dbg_leb_unmap
 #define ubi_is_mapped  dbg_is_mapped
 #define ubi_leb_map    dbg_leb_map
-
 #endif
 
 int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
@@ -370,33 +318,33 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
                       __func__, __LINE__, current->pid);                      \
 } while (0)
 
-#define dbg_err(fmt, ...)   do {                                               \
-       if (0)                                                                 \
-               ubifs_err(fmt, ##__VA_ARGS__);                                 \
+#define dbg_err(fmt, ...)   do {                   \
+       if (0)                                     \
+               ubifs_err(fmt, ##__VA_ARGS__);     \
 } while (0)
 
-#define dbg_msg(fmt, ...) do {                                                 \
-       if (0)                                                                 \
-               printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n",         \
-                      current->pid, __func__, ##__VA_ARGS__);                 \
+#define ubifs_dbg_msg(fmt, ...) do {               \
+       if (0)                                     \
+               pr_debug(fmt "\n", ##__VA_ARGS__); \
 } while (0)
 
 #define dbg_dump_stack()
 #define ubifs_assert_cmt_locked(c)
 
-#define dbg_gen(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_jnl(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_tnc(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_lp(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_find(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_mnt(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_io(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_cmt(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_budg(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_log(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_gc(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_scan(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_rcvry(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_msg(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_gen(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_jnl(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_tnc(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_lp(fmt, ...)    ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_find(fmt, ...)  ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_mnt(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_io(fmt, ...)    ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_cmt(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_budg(fmt, ...)  ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_log(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_gc(fmt, ...)    ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_scan(fmt, ...)  ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_rcvry(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
 
 #define DBGKEY(key)  ((char *)(key))
 #define DBGKEY1(key) ((char *)(key))
@@ -420,7 +368,9 @@ static inline void
 dbg_dump_budget_req(const struct ubifs_budget_req *req)           { return; }
 static inline void
 dbg_dump_lstats(const struct ubifs_lp_stats *lst)                 { return; }
-static inline void dbg_dump_budg(struct ubifs_info *c)            { return; }
+static inline void
+dbg_dump_budg(struct ubifs_info *c,
+             const struct ubifs_budg_info *bi)                   { return; }
 static inline void dbg_dump_lprop(const struct ubifs_info *c,
                                  const struct ubifs_lprops *lp)  { return; }
 static inline void dbg_dump_lprops(struct ubifs_info *c)          { return; }
@@ -482,8 +432,8 @@ dbg_check_nondata_nodes_order(struct ubifs_info *c,
                              struct list_head *head)             { return 0; }
 
 static inline int dbg_force_in_the_gaps(void)                     { return 0; }
-#define dbg_force_in_the_gaps_enabled 0
-#define dbg_failure_mode              0
+#define dbg_force_in_the_gaps_enabled() 0
+#define dbg_failure_mode                0
 
 static inline int dbg_debugfs_init(void)                          { return 0; }
 static inline void dbg_debugfs_exit(void)                         { return; }
index 7217d67a80a691a8114e4d7f04d2f98037d03997..ef5abd38f0bf32a90f30ef6994c81b6d864f93e8 100644 (file)
@@ -603,7 +603,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
                ubifs_release_budget(c, &req);
        else {
                /* We've deleted something - clean the "no space" flags */
-               c->nospace = c->nospace_rp = 0;
+               c->bi.nospace = c->bi.nospace_rp = 0;
                smp_wmb();
        }
        return 0;
@@ -693,7 +693,7 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
                ubifs_release_budget(c, &req);
        else {
                /* We've deleted something - clean the "no space" flags */
-               c->nospace = c->nospace_rp = 0;
+               c->bi.nospace = c->bi.nospace_rp = 0;
                smp_wmb();
        }
        return 0;
index b286db79c686597bb593208ff577905d2663f7bf..5e7fccfc4b29d0c7eab7481ff1c89a5213c548df 100644 (file)
@@ -212,7 +212,7 @@ static void release_new_page_budget(struct ubifs_info *c)
  */
 static void release_existing_page_budget(struct ubifs_info *c)
 {
-       struct ubifs_budget_req req = { .dd_growth = c->page_budget};
+       struct ubifs_budget_req req = { .dd_growth = c->bi.page_budget};
 
        ubifs_release_budget(c, &req);
 }
@@ -971,11 +971,11 @@ static int do_writepage(struct page *page, int len)
  * the page locked, and it locks @ui_mutex. However, write-back does take inode
  * @i_mutex, which means other VFS operations may be run on this inode at the
  * same time. And the problematic one is truncation to smaller size, from where
- * we have to call 'truncate_setsize()', which first changes @inode->i_size, then
- * drops the truncated pages. And while dropping the pages, it takes the page
- * lock. This means that 'do_truncation()' cannot call 'truncate_setsize()' with
- * @ui_mutex locked, because it would deadlock with 'ubifs_writepage()'. This
- * means that @inode->i_size is changed while @ui_mutex is unlocked.
+ * we have to call 'truncate_setsize()', which first changes @inode->i_size,
+ * then drops the truncated pages. And while dropping the pages, it takes the
+ * page lock. This means that 'do_truncation()' cannot call 'truncate_setsize()'
+ * with @ui_mutex locked, because it would deadlock with 'ubifs_writepage()'.
+ * This means that @inode->i_size is changed while @ui_mutex is unlocked.
  *
  * XXX(truncate): with the new truncate sequence this is not true anymore,
  * and the calls to truncate_setsize can be move around freely.  They should
@@ -1189,7 +1189,7 @@ out_budg:
        if (budgeted)
                ubifs_release_budget(c, &req);
        else {
-               c->nospace = c->nospace_rp = 0;
+               c->bi.nospace = c->bi.nospace_rp = 0;
                smp_wmb();
        }
        return err;
@@ -1312,7 +1312,11 @@ int ubifs_fsync(struct file *file, int datasync)
 
        dbg_gen("syncing inode %lu", inode->i_ino);
 
-       if (inode->i_sb->s_flags & MS_RDONLY)
+       if (c->ro_mount)
+               /*
+                * For some really strange reasons VFS does not filter out
+                * 'fsync()' for R/O mounted file-systems as per 2.6.39.
+                */
                return 0;
 
        /*
@@ -1432,10 +1436,11 @@ static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags)
 }
 
 /*
- * mmap()d file has taken write protection fault and is being made
- * writable. UBIFS must ensure page is budgeted for.
+ * mmap()d file has taken write protection fault and is being made writable.
+ * UBIFS must ensure page is budgeted for.
  */
-static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
+static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma,
+                                struct vm_fault *vmf)
 {
        struct page *page = vmf->page;
        struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
@@ -1536,7 +1541,6 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
        int err;
 
-       /* 'generic_file_mmap()' takes care of NOMMU case */
        err = generic_file_mmap(file, vma);
        if (err)
                return err;
index 1d54383d1269b1df2ecfdc8cb7a8e02c917afc74..2559d174e0040a45578fcc2e7612522a08e99a2f 100644 (file)
@@ -252,8 +252,8 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
                 * But if the index takes fewer LEBs than it is reserved for it,
                 * this function must avoid picking those reserved LEBs.
                 */
-               if (c->min_idx_lebs >= c->lst.idx_lebs) {
-                       rsvd_idx_lebs = c->min_idx_lebs -  c->lst.idx_lebs;
+               if (c->bi.min_idx_lebs >= c->lst.idx_lebs) {
+                       rsvd_idx_lebs = c->bi.min_idx_lebs -  c->lst.idx_lebs;
                        exclude_index = 1;
                }
                spin_unlock(&c->space_lock);
@@ -276,7 +276,7 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
                        pick_free = 0;
        } else {
                spin_lock(&c->space_lock);
-               exclude_index = (c->min_idx_lebs >= c->lst.idx_lebs);
+               exclude_index = (c->bi.min_idx_lebs >= c->lst.idx_lebs);
                spin_unlock(&c->space_lock);
        }
 
@@ -501,8 +501,8 @@ int ubifs_find_free_space(struct ubifs_info *c, int min_space, int *offs,
 
        /* Check if there are enough empty LEBs for commit */
        spin_lock(&c->space_lock);
-       if (c->min_idx_lebs > c->lst.idx_lebs)
-               rsvd_idx_lebs = c->min_idx_lebs -  c->lst.idx_lebs;
+       if (c->bi.min_idx_lebs > c->lst.idx_lebs)
+               rsvd_idx_lebs = c->bi.min_idx_lebs -  c->lst.idx_lebs;
        else
                rsvd_idx_lebs = 0;
        lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
index 151f108828204dc4d88c9d890fbcce051b2d8912..ded29f6224c27155765a366a6ec1e13644b224d6 100644 (file)
@@ -100,6 +100,10 @@ static int switch_gc_head(struct ubifs_info *c)
        if (err)
                return err;
 
+       err = ubifs_wbuf_sync_nolock(wbuf);
+       if (err)
+               return err;
+
        err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0);
        if (err)
                return err;
@@ -118,7 +122,7 @@ static int switch_gc_head(struct ubifs_info *c)
  * This function compares data nodes @a and @b. Returns %1 if @a has greater
  * inode or block number, and %-1 otherwise.
  */
-int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
+static int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
 {
        ino_t inuma, inumb;
        struct ubifs_info *c = priv;
@@ -161,7 +165,8 @@ int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
  * first and sorted by length in descending order. Directory entry nodes go
  * after inode nodes and are sorted in ascending hash valuer order.
  */
-int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
+static int nondata_nodes_cmp(void *priv, struct list_head *a,
+                            struct list_head *b)
 {
        ino_t inuma, inumb;
        struct ubifs_info *c = priv;
@@ -473,6 +478,37 @@ int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp)
        ubifs_assert(c->gc_lnum != lnum);
        ubifs_assert(wbuf->lnum != lnum);
 
+       if (lp->free + lp->dirty == c->leb_size) {
+               /* Special case - a free LEB  */
+               dbg_gc("LEB %d is free, return it", lp->lnum);
+               ubifs_assert(!(lp->flags & LPROPS_INDEX));
+
+               if (lp->free != c->leb_size) {
+                       /*
+                        * Write buffers must be sync'd before unmapping
+                        * freeable LEBs, because one of them may contain data
+                        * which obsoletes something in 'lp->pnum'.
+                        */
+                       err = gc_sync_wbufs(c);
+                       if (err)
+                               return err;
+                       err = ubifs_change_one_lp(c, lp->lnum, c->leb_size,
+                                                 0, 0, 0, 0);
+                       if (err)
+                               return err;
+               }
+               err = ubifs_leb_unmap(c, lp->lnum);
+               if (err)
+                       return err;
+
+               if (c->gc_lnum == -1) {
+                       c->gc_lnum = lnum;
+                       return LEB_RETAINED;
+               }
+
+               return LEB_FREED;
+       }
+
        /*
         * We scan the entire LEB even though we only really need to scan up to
         * (c->leb_size - lp->free).
@@ -682,37 +718,6 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway)
                       "(min. space %d)", lp.lnum, lp.free, lp.dirty,
                       lp.free + lp.dirty, min_space);
 
-               if (lp.free + lp.dirty == c->leb_size) {
-                       /* An empty LEB was returned */
-                       dbg_gc("LEB %d is free, return it", lp.lnum);
-                       /*
-                        * ubifs_find_dirty_leb() doesn't return freeable index
-                        * LEBs.
-                        */
-                       ubifs_assert(!(lp.flags & LPROPS_INDEX));
-                       if (lp.free != c->leb_size) {
-                               /*
-                                * Write buffers must be sync'd before
-                                * unmapping freeable LEBs, because one of them
-                                * may contain data which obsoletes something
-                                * in 'lp.pnum'.
-                                */
-                               ret = gc_sync_wbufs(c);
-                               if (ret)
-                                       goto out;
-                               ret = ubifs_change_one_lp(c, lp.lnum,
-                                                         c->leb_size, 0, 0, 0,
-                                                         0);
-                               if (ret)
-                                       goto out;
-                       }
-                       ret = ubifs_leb_unmap(c, lp.lnum);
-                       if (ret)
-                               goto out;
-                       ret = lp.lnum;
-                       break;
-               }
-
                space_before = c->leb_size - wbuf->offs - wbuf->used;
                if (wbuf->lnum == -1)
                        space_before = 0;
index dfd168b7807e179fd450784a6e3a4c0d4b222ebe..3be645e012c9358170ad45a87af3b83b8fbd72ca 100644 (file)
@@ -393,7 +393,7 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
        ubifs_assert(wbuf->size % c->min_io_size == 0);
        ubifs_assert(!c->ro_media && !c->ro_mount);
        if (c->leb_size - wbuf->offs >= c->max_write_size)
-               ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size ));
+               ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size));
 
        if (c->ro_error)
                return -EROFS;
@@ -452,8 +452,8 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
  * @dtype: data type
  *
  * This function targets the write-buffer to logical eraseblock @lnum:@offs.
- * The write-buffer is synchronized if it is not empty. Returns zero in case of
- * success and a negative error code in case of failure.
+ * The write-buffer has to be empty. Returns zero in case of success and a
+ * negative error code in case of failure.
  */
 int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
                           int dtype)
@@ -465,13 +465,7 @@ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
        ubifs_assert(offs >= 0 && offs <= c->leb_size);
        ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7));
        ubifs_assert(lnum != wbuf->lnum);
-
-       if (wbuf->used > 0) {
-               int err = ubifs_wbuf_sync_nolock(wbuf);
-
-               if (err)
-                       return err;
-       }
+       ubifs_assert(wbuf->used == 0);
 
        spin_lock(&wbuf->lock);
        wbuf->lnum = lnum;
@@ -573,7 +567,7 @@ out_timers:
 int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
 {
        struct ubifs_info *c = wbuf->c;
-       int err, written, n, aligned_len = ALIGN(len, 8), offs;
+       int err, written, n, aligned_len = ALIGN(len, 8);
 
        dbg_io("%d bytes (%s) to jhead %s wbuf at LEB %d:%d", len,
               dbg_ntype(((struct ubifs_ch *)buf)->node_type),
@@ -587,8 +581,9 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
        ubifs_assert(wbuf->size % c->min_io_size == 0);
        ubifs_assert(mutex_is_locked(&wbuf->io_mutex));
        ubifs_assert(!c->ro_media && !c->ro_mount);
+       ubifs_assert(!c->space_fixup);
        if (c->leb_size - wbuf->offs >= c->max_write_size)
-               ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size ));
+               ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size));
 
        if (c->leb_size - wbuf->offs - wbuf->used < aligned_len) {
                err = -ENOSPC;
@@ -636,7 +631,6 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
                goto exit;
        }
 
-       offs = wbuf->offs;
        written = 0;
 
        if (wbuf->used) {
@@ -653,7 +647,7 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
                if (err)
                        goto out;
 
-               offs += wbuf->size;
+               wbuf->offs += wbuf->size;
                len -= wbuf->avail;
                aligned_len -= wbuf->avail;
                written += wbuf->avail;
@@ -672,7 +666,7 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
                if (err)
                        goto out;
 
-               offs += wbuf->size;
+               wbuf->offs += wbuf->size;
                len -= wbuf->size;
                aligned_len -= wbuf->size;
                written += wbuf->size;
@@ -687,12 +681,13 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
        n = aligned_len >> c->max_write_shift;
        if (n) {
                n <<= c->max_write_shift;
-               dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum, offs);
-               err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written, offs, n,
-                                   wbuf->dtype);
+               dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum,
+                      wbuf->offs);
+               err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written,
+                                   wbuf->offs, n, wbuf->dtype);
                if (err)
                        goto out;
-               offs += n;
+               wbuf->offs += n;
                aligned_len -= n;
                len -= n;
                written += n;
@@ -707,7 +702,6 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
                 */
                memcpy(wbuf->buf, buf + written, len);
 
-       wbuf->offs = offs;
        if (c->leb_size - wbuf->offs >= c->max_write_size)
                wbuf->size = c->max_write_size;
        else
@@ -766,6 +760,7 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
        ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
        ubifs_assert(offs % c->min_io_size == 0 && offs < c->leb_size);
        ubifs_assert(!c->ro_media && !c->ro_mount);
+       ubifs_assert(!c->space_fixup);
 
        if (c->ro_error)
                return -EROFS;
index aed25e864227d83b1e200021014765a913d16518..cef0460f4c54651bbe5c432d8fc4e3307ee45d07 100644 (file)
@@ -141,14 +141,8 @@ again:
         * LEB with some empty space.
         */
        lnum = ubifs_find_free_space(c, len, &offs, squeeze);
-       if (lnum >= 0) {
-               /* Found an LEB, add it to the journal head */
-               err = ubifs_add_bud_to_log(c, jhead, lnum, offs);
-               if (err)
-                       goto out_return;
-               /* A new bud was successfully allocated and added to the log */
+       if (lnum >= 0)
                goto out;
-       }
 
        err = lnum;
        if (err != -ENOSPC)
@@ -203,12 +197,23 @@ again:
                return 0;
        }
 
-       err = ubifs_add_bud_to_log(c, jhead, lnum, 0);
-       if (err)
-               goto out_return;
        offs = 0;
 
 out:
+       /*
+        * Make sure we synchronize the write-buffer before we add the new bud
+        * to the log. Otherwise we may have a power cut after the log
+        * reference node for the last bud (@lnum) is written but before the
+        * write-buffer data are written to the next-to-last bud
+        * (@wbuf->lnum). And the effect would be that the recovery would see
+        * that there is corruption in the next-to-last bud.
+        */
+       err = ubifs_wbuf_sync_nolock(wbuf);
+       if (err)
+               goto out_return;
+       err = ubifs_add_bud_to_log(c, jhead, lnum, offs);
+       if (err)
+               goto out_return;
        err = ubifs_wbuf_seek_nolock(wbuf, lnum, offs, wbuf->dtype);
        if (err)
                goto out_unlock;
@@ -380,10 +385,8 @@ out:
        if (err == -ENOSPC) {
                /* This are some budgeting problems, print useful information */
                down_write(&c->commit_sem);
-               spin_lock(&c->space_lock);
                dbg_dump_stack();
-               dbg_dump_budg(c);
-               spin_unlock(&c->space_lock);
+               dbg_dump_budg(c, &c->bi);
                dbg_dump_lprops(c);
                cmt_retries = dbg_check_lprops(c);
                up_write(&c->commit_sem);
@@ -666,6 +669,7 @@ out_free:
 
 out_release:
        release_head(c, BASEHD);
+       kfree(dent);
 out_ro:
        ubifs_ro_mode(c, err);
        if (last_reference)
index 40fa780ebea7d6280cc83f30ca4db9b0a0052b98..affea9494ae23551fd34109f009ad6f74cdec276 100644 (file)
@@ -99,20 +99,6 @@ struct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum)
        return NULL;
 }
 
-/**
- * next_log_lnum - switch to the next log LEB.
- * @c: UBIFS file-system description object
- * @lnum: current log LEB
- */
-static inline int next_log_lnum(const struct ubifs_info *c, int lnum)
-{
-       lnum += 1;
-       if (lnum > c->log_last)
-               lnum = UBIFS_LOG_LNUM;
-
-       return lnum;
-}
-
 /**
  * empty_log_bytes - calculate amount of empty space in the log.
  * @c: UBIFS file-system description object
@@ -257,7 +243,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
        ref->jhead = cpu_to_le32(jhead);
 
        if (c->lhead_offs > c->leb_size - c->ref_node_alsz) {
-               c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
+               c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
                c->lhead_offs = 0;
        }
 
@@ -425,7 +411,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
 
        /* Switch to the next log LEB */
        if (c->lhead_offs) {
-               c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
+               c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
                c->lhead_offs = 0;
        }
 
@@ -446,7 +432,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
 
        c->lhead_offs += len;
        if (c->lhead_offs == c->leb_size) {
-               c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
+               c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
                c->lhead_offs = 0;
        }
 
@@ -533,7 +519,7 @@ int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum)
        }
        mutex_lock(&c->log_mutex);
        for (lnum = old_ltail_lnum; lnum != c->ltail_lnum;
-            lnum = next_log_lnum(c, lnum)) {
+            lnum = ubifs_next_log_lnum(c, lnum)) {
                dbg_log("unmap log LEB %d", lnum);
                err = ubifs_leb_unmap(c, lnum);
                if (err)
@@ -642,7 +628,7 @@ static int add_node(struct ubifs_info *c, void *buf, int *lnum, int *offs,
                err = ubifs_leb_change(c, *lnum, buf, sz, UBI_SHORTTERM);
                if (err)
                        return err;
-               *lnum = next_log_lnum(c, *lnum);
+               *lnum = ubifs_next_log_lnum(c, *lnum);
                *offs = 0;
        }
        memcpy(buf + *offs, node, len);
@@ -712,7 +698,7 @@ int ubifs_consolidate_log(struct ubifs_info *c)
                ubifs_scan_destroy(sleb);
                if (lnum == c->lhead_lnum)
                        break;
-               lnum = next_log_lnum(c, lnum);
+               lnum = ubifs_next_log_lnum(c, lnum);
        }
        if (offs) {
                int sz = ALIGN(offs, c->min_io_size);
@@ -732,7 +718,7 @@ int ubifs_consolidate_log(struct ubifs_info *c)
        /* Unmap remaining LEBs */
        lnum = write_lnum;
        do {
-               lnum = next_log_lnum(c, lnum);
+               lnum = ubifs_next_log_lnum(c, lnum);
                err = ubifs_leb_unmap(c, lnum);
                if (err)
                        return err;
index 0ee0847f24218b0e44cfefeb888dc501b8d159f1..667884f4a61537717adae74d76ba6ebe6a2982ac 100644 (file)
@@ -1006,22 +1006,12 @@ out:
        }
 }
 
-/**
- * struct scan_check_data - data provided to scan callback function.
- * @lst: LEB properties statistics
- * @err: error code
- */
-struct scan_check_data {
-       struct ubifs_lp_stats lst;
-       int err;
-};
-
 /**
  * scan_check_cb - scan callback.
  * @c: the UBIFS file-system description object
  * @lp: LEB properties to scan
  * @in_tree: whether the LEB properties are in main memory
- * @data: information passed to and from the caller of the scan
+ * @lst: lprops statistics to update
  *
  * This function returns a code that indicates whether the scan should continue
  * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree
@@ -1030,11 +1020,10 @@ struct scan_check_data {
  */
 static int scan_check_cb(struct ubifs_info *c,
                         const struct ubifs_lprops *lp, int in_tree,
-                        struct scan_check_data *data)
+                        struct ubifs_lp_stats *lst)
 {
        struct ubifs_scan_leb *sleb;
        struct ubifs_scan_node *snod;
-       struct ubifs_lp_stats *lst = &data->lst;
        int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty, ret;
        void *buf = NULL;
 
@@ -1044,7 +1033,7 @@ static int scan_check_cb(struct ubifs_info *c,
                if (cat != (lp->flags & LPROPS_CAT_MASK)) {
                        ubifs_err("bad LEB category %d expected %d",
                                  (lp->flags & LPROPS_CAT_MASK), cat);
-                       goto out;
+                       return -EINVAL;
                }
        }
 
@@ -1078,7 +1067,7 @@ static int scan_check_cb(struct ubifs_info *c,
                        }
                        if (!found) {
                                ubifs_err("bad LPT list (category %d)", cat);
-                               goto out;
+                               return -EINVAL;
                        }
                }
        }
@@ -1090,45 +1079,40 @@ static int scan_check_cb(struct ubifs_info *c,
                if ((lp->hpos != -1 && heap->arr[lp->hpos]->lnum != lnum) ||
                    lp != heap->arr[lp->hpos]) {
                        ubifs_err("bad LPT heap (category %d)", cat);
-                       goto out;
+                       return -EINVAL;
                }
        }
 
        buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
-       if (!buf) {
-               ubifs_err("cannot allocate memory to scan LEB %d", lnum);
-               goto out;
+       if (!buf)
+               return -ENOMEM;
+
+       /*
+        * After an unclean unmount, empty and freeable LEBs
+        * may contain garbage - do not scan them.
+        */
+       if (lp->free == c->leb_size) {
+               lst->empty_lebs += 1;
+               lst->total_free += c->leb_size;
+               lst->total_dark += ubifs_calc_dark(c, c->leb_size);
+               return LPT_SCAN_CONTINUE;
+       }
+       if (lp->free + lp->dirty == c->leb_size &&
+           !(lp->flags & LPROPS_INDEX)) {
+               lst->total_free  += lp->free;
+               lst->total_dirty += lp->dirty;
+               lst->total_dark  +=  ubifs_calc_dark(c, c->leb_size);
+               return LPT_SCAN_CONTINUE;
        }
 
        sleb = ubifs_scan(c, lnum, 0, buf, 0);
        if (IS_ERR(sleb)) {
-               /*
-                * After an unclean unmount, empty and freeable LEBs
-                * may contain garbage.
-                */
-               if (lp->free == c->leb_size) {
-                       ubifs_err("scan errors were in empty LEB "
-                                 "- continuing checking");
-                       lst->empty_lebs += 1;
-                       lst->total_free += c->leb_size;
-                       lst->total_dark += ubifs_calc_dark(c, c->leb_size);
-                       ret = LPT_SCAN_CONTINUE;
-                       goto exit;
-               }
-
-               if (lp->free + lp->dirty == c->leb_size &&
-                   !(lp->flags & LPROPS_INDEX)) {
-                       ubifs_err("scan errors were in freeable LEB "
-                                 "- continuing checking");
-                       lst->total_free  += lp->free;
-                       lst->total_dirty += lp->dirty;
-                       lst->total_dark  +=  ubifs_calc_dark(c, c->leb_size);
-                       ret = LPT_SCAN_CONTINUE;
-                       goto exit;
+               ret = PTR_ERR(sleb);
+               if (ret == -EUCLEAN) {
+                       dbg_dump_lprops(c);
+                       dbg_dump_budg(c, &c->bi);
                }
-               data->err = PTR_ERR(sleb);
-               ret = LPT_SCAN_STOP;
-               goto exit;
+               goto out;
        }
 
        is_idx = -1;
@@ -1246,10 +1230,8 @@ static int scan_check_cb(struct ubifs_info *c,
        }
 
        ubifs_scan_destroy(sleb);
-       ret = LPT_SCAN_CONTINUE;
-exit:
        vfree(buf);
-       return ret;
+       return LPT_SCAN_CONTINUE;
 
 out_print:
        ubifs_err("bad accounting of LEB %d: free %d, dirty %d flags %#x, "
@@ -1258,10 +1240,10 @@ out_print:
        dbg_dump_leb(c, lnum);
 out_destroy:
        ubifs_scan_destroy(sleb);
+       ret = -EINVAL;
 out:
        vfree(buf);
-       data->err = -EINVAL;
-       return LPT_SCAN_STOP;
+       return ret;
 }
 
 /**
@@ -1278,8 +1260,7 @@ out:
 int dbg_check_lprops(struct ubifs_info *c)
 {
        int i, err;
-       struct scan_check_data data;
-       struct ubifs_lp_stats *lst = &data.lst;
+       struct ubifs_lp_stats lst;
 
        if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
                return 0;
@@ -1294,29 +1275,23 @@ int dbg_check_lprops(struct ubifs_info *c)
                        return err;
        }
 
-       memset(lst, 0, sizeof(struct ubifs_lp_stats));
-
-       data.err = 0;
+       memset(&lst, 0, sizeof(struct ubifs_lp_stats));
        err = ubifs_lpt_scan_nolock(c, c->main_first, c->leb_cnt - 1,
                                    (ubifs_lpt_scan_callback)scan_check_cb,
-                                   &data);
+                                   &lst);
        if (err && err != -ENOSPC)
                goto out;
-       if (data.err) {
-               err = data.err;
-               goto out;
-       }
 
-       if (lst->empty_lebs != c->lst.empty_lebs ||
-           lst->idx_lebs != c->lst.idx_lebs ||
-           lst->total_free != c->lst.total_free ||
-           lst->total_dirty != c->lst.total_dirty ||
-           lst->total_used != c->lst.total_used) {
+       if (lst.empty_lebs != c->lst.empty_lebs ||
+           lst.idx_lebs != c->lst.idx_lebs ||
+           lst.total_free != c->lst.total_free ||
+           lst.total_dirty != c->lst.total_dirty ||
+           lst.total_used != c->lst.total_used) {
                ubifs_err("bad overall accounting");
                ubifs_err("calculated: empty_lebs %d, idx_lebs %d, "
                          "total_free %lld, total_dirty %lld, total_used %lld",
-                         lst->empty_lebs, lst->idx_lebs, lst->total_free,
-                         lst->total_dirty, lst->total_used);
+                         lst.empty_lebs, lst.idx_lebs, lst.total_free,
+                         lst.total_dirty, lst.total_used);
                ubifs_err("read from lprops: empty_lebs %d, idx_lebs %d, "
                          "total_free %lld, total_dirty %lld, total_used %lld",
                          c->lst.empty_lebs, c->lst.idx_lebs, c->lst.total_free,
@@ -1325,11 +1300,11 @@ int dbg_check_lprops(struct ubifs_info *c)
                goto out;
        }
 
-       if (lst->total_dead != c->lst.total_dead ||
-           lst->total_dark != c->lst.total_dark) {
+       if (lst.total_dead != c->lst.total_dead ||
+           lst.total_dark != c->lst.total_dark) {
                ubifs_err("bad dead/dark space accounting");
                ubifs_err("calculated: total_dead %lld, total_dark %lld",
-                         lst->total_dead, lst->total_dark);
+                         lst.total_dead, lst.total_dark);
                ubifs_err("read from lprops: total_dead %lld, total_dark %lld",
                          c->lst.total_dead, c->lst.total_dark);
                err = -EINVAL;
index 0c9c69bd983a94c0854d90508a15832b99b6fe0f..dfcb5748a7dc14db8695f694e021f4c1a52fefcc 100644 (file)
 #include <linux/slab.h>
 #include "ubifs.h"
 
+#ifdef CONFIG_UBIFS_FS_DEBUG
+static int dbg_populate_lsave(struct ubifs_info *c);
+#else
+#define dbg_populate_lsave(c) 0
+#endif
+
 /**
  * first_dirty_cnode - find first dirty cnode.
  * @c: UBIFS file-system description object
@@ -586,7 +592,7 @@ static struct ubifs_pnode *next_pnode_to_dirty(struct ubifs_info *c,
                        if (nnode->nbranch[iip].lnum)
                                break;
                }
-       } while (iip >= UBIFS_LPT_FANOUT);
+       } while (iip >= UBIFS_LPT_FANOUT);
 
        /* Go right */
        nnode = ubifs_get_nnode(c, nnode, iip);
@@ -815,6 +821,10 @@ static void populate_lsave(struct ubifs_info *c)
                c->lpt_drty_flgs |= LSAVE_DIRTY;
                ubifs_add_lpt_dirt(c, c->lsave_lnum, c->lsave_sz);
        }
+
+       if (dbg_populate_lsave(c))
+               return;
+
        list_for_each_entry(lprops, &c->empty_list, list) {
                c->lsave[cnt++] = lprops->lnum;
                if (cnt >= c->lsave_cnt)
@@ -1994,4 +2004,47 @@ void dbg_dump_lpt_lebs(const struct ubifs_info *c)
               current->pid);
 }
 
+/**
+ * dbg_populate_lsave - debugging version of 'populate_lsave()'
+ * @c: UBIFS file-system description object
+ *
+ * This is a debugging version for 'populate_lsave()' which populates lsave
+ * with random LEBs instead of useful LEBs, which is good for test coverage.
+ * Returns zero if lsave has not been populated (this debugging feature is
+ * disabled) an non-zero if lsave has been populated.
+ */
+static int dbg_populate_lsave(struct ubifs_info *c)
+{
+       struct ubifs_lprops *lprops;
+       struct ubifs_lpt_heap *heap;
+       int i;
+
+       if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
+               return 0;
+       if (random32() & 3)
+               return 0;
+
+       for (i = 0; i < c->lsave_cnt; i++)
+               c->lsave[i] = c->main_first;
+
+       list_for_each_entry(lprops, &c->empty_list, list)
+               c->lsave[random32() % c->lsave_cnt] = lprops->lnum;
+       list_for_each_entry(lprops, &c->freeable_list, list)
+               c->lsave[random32() % c->lsave_cnt] = lprops->lnum;
+       list_for_each_entry(lprops, &c->frdi_idx_list, list)
+               c->lsave[random32() % c->lsave_cnt] = lprops->lnum;
+
+       heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1];
+       for (i = 0; i < heap->cnt; i++)
+               c->lsave[random32() % c->lsave_cnt] = heap->arr[i]->lnum;
+       heap = &c->lpt_heap[LPROPS_DIRTY - 1];
+       for (i = 0; i < heap->cnt; i++)
+               c->lsave[random32() % c->lsave_cnt] = heap->arr[i]->lnum;
+       heap = &c->lpt_heap[LPROPS_FREE - 1];
+       for (i = 0; i < heap->cnt; i++)
+               c->lsave[random32() % c->lsave_cnt] = heap->arr[i]->lnum;
+
+       return 1;
+}
+
 #endif /* CONFIG_UBIFS_FS_DEBUG */
index 21f47afdacff170b5241d69e00edbb6fb3e0ae4b..278c2382e8c21a7daafaea11c63caf9663c30d52 100644 (file)
@@ -148,7 +148,7 @@ static int validate_master(const struct ubifs_info *c)
        }
 
        main_sz = (long long)c->main_lebs * c->leb_size;
-       if (c->old_idx_sz & 7 || c->old_idx_sz >= main_sz) {
+       if (c->bi.old_idx_sz & 7 || c->bi.old_idx_sz >= main_sz) {
                err = 9;
                goto out;
        }
@@ -218,7 +218,7 @@ static int validate_master(const struct ubifs_info *c)
        }
 
        if (c->lst.total_dead + c->lst.total_dark +
-           c->lst.total_used + c->old_idx_sz > main_sz) {
+           c->lst.total_used + c->bi.old_idx_sz > main_sz) {
                err = 21;
                goto out;
        }
@@ -286,7 +286,7 @@ int ubifs_read_master(struct ubifs_info *c)
        c->gc_lnum         = le32_to_cpu(c->mst_node->gc_lnum);
        c->ihead_lnum      = le32_to_cpu(c->mst_node->ihead_lnum);
        c->ihead_offs      = le32_to_cpu(c->mst_node->ihead_offs);
-       c->old_idx_sz      = le64_to_cpu(c->mst_node->index_size);
+       c->bi.old_idx_sz   = le64_to_cpu(c->mst_node->index_size);
        c->lpt_lnum        = le32_to_cpu(c->mst_node->lpt_lnum);
        c->lpt_offs        = le32_to_cpu(c->mst_node->lpt_offs);
        c->nhead_lnum      = le32_to_cpu(c->mst_node->nhead_lnum);
@@ -305,7 +305,7 @@ int ubifs_read_master(struct ubifs_info *c)
        c->lst.total_dead  = le64_to_cpu(c->mst_node->total_dead);
        c->lst.total_dark  = le64_to_cpu(c->mst_node->total_dark);
 
-       c->calc_idx_sz = c->old_idx_sz;
+       c->calc_idx_sz = c->bi.old_idx_sz;
 
        if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS))
                c->no_orphs = 1;
index c3de04dc952a5c735428f73ad53c3ad40cf3dc4e..0b5296a9a4c5cc811ab2cc2d7ac50fdadd69f20e 100644 (file)
@@ -340,4 +340,21 @@ static inline void ubifs_release_lprops(struct ubifs_info *c)
        mutex_unlock(&c->lp_mutex);
 }
 
+/**
+ * ubifs_next_log_lnum - switch to the next log LEB.
+ * @c: UBIFS file-system description object
+ * @lnum: current log LEB
+ *
+ * This helper function returns the log LEB number which goes next after LEB
+ * 'lnum'.
+ */
+static inline int ubifs_next_log_lnum(const struct ubifs_info *c, int lnum)
+{
+       lnum += 1;
+       if (lnum > c->log_last)
+               lnum = UBIFS_LOG_LNUM;
+
+       return lnum;
+}
+
 #endif /* __UBIFS_MISC_H__ */
index 09df318e368f492f3d249f97680c1f9b479393c7..a5422fffbd69e10a11b27143feab3cc6a7d7f3f5 100644 (file)
@@ -673,7 +673,8 @@ static int kill_orphans(struct ubifs_info *c)
                sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1);
                if (IS_ERR(sleb)) {
                        if (PTR_ERR(sleb) == -EUCLEAN)
-                               sleb = ubifs_recover_leb(c, lnum, 0, c->sbuf, 0);
+                               sleb = ubifs_recover_leb(c, lnum, 0,
+                                                        c->sbuf, -1);
                        if (IS_ERR(sleb)) {
                                err = PTR_ERR(sleb);
                                break;
index 3dbad6fbd1eba528661e458ae56e97c03c43b609..783d8e0beb76b59da67c2509d0371b194f994045 100644 (file)
@@ -564,16 +564,15 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
 }
 
 /**
- * drop_incomplete_group - drop nodes from an incomplete group.
+ * drop_last_group - drop the last group of nodes.
  * @sleb: scanned LEB information
  * @offs: offset of dropped nodes is returned here
  *
- * This function returns %1 if nodes are dropped and %0 otherwise.
+ * This is a helper function for 'ubifs_recover_leb()' which drops the last
+ * group of nodes of the scanned LEB.
  */
-static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
+static void drop_last_group(struct ubifs_scan_leb *sleb, int *offs)
 {
-       int dropped = 0;
-
        while (!list_empty(&sleb->nodes)) {
                struct ubifs_scan_node *snod;
                struct ubifs_ch *ch;
@@ -582,15 +581,40 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
                                  list);
                ch = snod->node;
                if (ch->group_type != UBIFS_IN_NODE_GROUP)
-                       return dropped;
-               dbg_rcvry("dropping node at %d:%d", sleb->lnum, snod->offs);
+                       break;
+
+               dbg_rcvry("dropping grouped node at %d:%d",
+                         sleb->lnum, snod->offs);
+               *offs = snod->offs;
+               list_del(&snod->list);
+               kfree(snod);
+               sleb->nodes_cnt -= 1;
+       }
+}
+
+/**
+ * drop_last_node - drop the last node.
+ * @sleb: scanned LEB information
+ * @offs: offset of dropped nodes is returned here
+ * @grouped: non-zero if whole group of nodes have to be dropped
+ *
+ * This is a helper function for 'ubifs_recover_leb()' which drops the last
+ * node of the scanned LEB.
+ */
+static void drop_last_node(struct ubifs_scan_leb *sleb, int *offs)
+{
+       struct ubifs_scan_node *snod;
+
+       if (!list_empty(&sleb->nodes)) {
+               snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,
+                                 list);
+
+               dbg_rcvry("dropping last node at %d:%d", sleb->lnum, snod->offs);
                *offs = snod->offs;
                list_del(&snod->list);
                kfree(snod);
                sleb->nodes_cnt -= 1;
-               dropped = 1;
        }
-       return dropped;
 }
 
 /**
@@ -599,7 +623,8 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
  * @lnum: LEB number
  * @offs: offset
  * @sbuf: LEB-sized buffer to use
- * @grouped: nodes may be grouped for recovery
+ * @jhead: journal head number this LEB belongs to (%-1 if the LEB does not
+ *         belong to any journal head)
  *
  * This function does a scan of a LEB, but caters for errors that might have
  * been caused by the unclean unmount from which we are attempting to recover.
@@ -607,25 +632,21 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
  * found, and a negative error code in case of failure.
  */
 struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
-                                        int offs, void *sbuf, int grouped)
+                                        int offs, void *sbuf, int jhead)
 {
-       int err, len = c->leb_size - offs, need_clean = 0, quiet = 1;
-       int empty_chkd = 0, start = offs;
+       int ret = 0, err, len = c->leb_size - offs, start = offs, min_io_unit;
+       int grouped = jhead == -1 ? 0 : c->jheads[jhead].grouped;
        struct ubifs_scan_leb *sleb;
        void *buf = sbuf + offs;
 
-       dbg_rcvry("%d:%d", lnum, offs);
+       dbg_rcvry("%d:%d, jhead %d, grouped %d", lnum, offs, jhead, grouped);
 
        sleb = ubifs_start_scan(c, lnum, offs, sbuf);
        if (IS_ERR(sleb))
                return sleb;
 
-       if (sleb->ecc)
-               need_clean = 1;
-
+       ubifs_assert(len >= 8);
        while (len >= 8) {
-               int ret;
-
                dbg_scan("look at LEB %d:%d (%d bytes left)",
                         lnum, offs, len);
 
@@ -635,8 +656,7 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
                 * Scan quietly until there is an error from which we cannot
                 * recover
                 */
-               ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet);
-
+               ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
                if (ret == SCANNED_A_NODE) {
                        /* A valid node, and not a padding node */
                        struct ubifs_ch *ch = buf;
@@ -649,70 +669,32 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
                        offs += node_len;
                        buf += node_len;
                        len -= node_len;
-                       continue;
-               }
-
-               if (ret > 0) {
+               } else if (ret > 0) {
                        /* Padding bytes or a valid padding node */
                        offs += ret;
                        buf += ret;
                        len -= ret;
-                       continue;
-               }
-
-               if (ret == SCANNED_EMPTY_SPACE) {
-                       if (!is_empty(buf, len)) {
-                               if (!is_last_write(c, buf, offs))
-                                       break;
-                               clean_buf(c, &buf, lnum, &offs, &len);
-                               need_clean = 1;
-                       }
-                       empty_chkd = 1;
+               } else if (ret == SCANNED_EMPTY_SPACE ||
+                          ret == SCANNED_GARBAGE     ||
+                          ret == SCANNED_A_BAD_PAD_NODE ||
+                          ret == SCANNED_A_CORRUPT_NODE) {
+                       dbg_rcvry("found corruption - %d", ret);
                        break;
-               }
-
-               if (ret == SCANNED_GARBAGE || ret == SCANNED_A_BAD_PAD_NODE)
-                       if (is_last_write(c, buf, offs)) {
-                               clean_buf(c, &buf, lnum, &offs, &len);
-                               need_clean = 1;
-                               empty_chkd = 1;
-                               break;
-                       }
-
-               if (ret == SCANNED_A_CORRUPT_NODE)
-                       if (no_more_nodes(c, buf, len, lnum, offs)) {
-                               clean_buf(c, &buf, lnum, &offs, &len);
-                               need_clean = 1;
-                               empty_chkd = 1;
-                               break;
-                       }
-
-               if (quiet) {
-                       /* Redo the last scan but noisily */
-                       quiet = 0;
-                       continue;
-               }
-
-               switch (ret) {
-               case SCANNED_GARBAGE:
-                       dbg_err("garbage");
-                       goto corrupted;
-               case SCANNED_A_CORRUPT_NODE:
-               case SCANNED_A_BAD_PAD_NODE:
-                       dbg_err("bad node");
-                       goto corrupted;
-               default:
-                       dbg_err("unknown");
+               } else {
+                       dbg_err("unexpected return value %d", ret);
                        err = -EINVAL;
                        goto error;
                }
        }
 
-       if (!empty_chkd && !is_empty(buf, len)) {
-               if (is_last_write(c, buf, offs)) {
-                       clean_buf(c, &buf, lnum, &offs, &len);
-                       need_clean = 1;
-               } else {
+       if (ret == SCANNED_GARBAGE || ret == SCANNED_A_BAD_PAD_NODE) {
+               if (!is_last_write(c, buf, offs))
+                       goto corrupted_rescan;
+       } else if (ret == SCANNED_A_CORRUPT_NODE) {
+               if (!no_more_nodes(c, buf, len, lnum, offs))
+                       goto corrupted_rescan;
+       } else if (!is_empty(buf, len)) {
+               if (!is_last_write(c, buf, offs)) {
                        int corruption = first_non_ff(buf, len);
 
                        /*
@@ -728,29 +710,85 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
                }
        }
 
-       /* Drop nodes from incomplete group */
-       if (grouped && drop_incomplete_group(sleb, &offs)) {
-               buf = sbuf + offs;
-               len = c->leb_size - offs;
-               clean_buf(c, &buf, lnum, &offs, &len);
-               need_clean = 1;
-       }
+       min_io_unit = round_down(offs, c->min_io_size);
+       if (grouped)
+               /*
+                * If nodes are grouped, always drop the incomplete group at
+                * the end.
+                */
+               drop_last_group(sleb, &offs);
 
-       if (offs % c->min_io_size) {
-               clean_buf(c, &buf, lnum, &offs, &len);
-               need_clean = 1;
+       if (jhead == GCHD) {
+               /*
+                * If this LEB belongs to the GC head then while we are in the
+                * middle of the same min. I/O unit keep dropping nodes. So
+                * basically, what we want is to make sure that the last min.
+                * I/O unit where we saw the corruption is dropped completely
+                * with all the uncorrupted nodes which may possibly sit there.
+                *
+                * In other words, let's name the min. I/O unit where the
+                * corruption starts B, and the previous min. I/O unit A. The
+                * below code tries to deal with a situation when half of B
+                * contains valid nodes or the end of a valid node, and the
+                * second half of B contains corrupted data or garbage. This
+                * means that UBIFS had been writing to B just before the power
+                * cut happened. I do not know how realistic is this scenario
+                * that half of the min. I/O unit had been written successfully
+                * and the other half not, but this is possible in our 'failure
+                * mode emulation' infrastructure at least.
+                *
+                * So what is the problem, why we need to drop those nodes? Why
+                * can't we just clean-up the second half of B by putting a
+                * padding node there? We can, and this works fine with one
+                * exception which was reproduced with power cut emulation
+                * testing and happens extremely rarely.
+                *
+                * Imagine the file-system is full, we run GC which starts
+                * moving valid nodes from LEB X to LEB Y (obviously, LEB Y is
+                * the current GC head LEB). The @c->gc_lnum is -1, which means
+                * that GC will retain LEB X and will try to continue. Imagine
+                * that LEB X is currently the dirtiest LEB, and the amount of
+                * used space in LEB Y is exactly the same as amount of free
+                * space in LEB X.
+                *
+                * And a power cut happens when nodes are moved from LEB X to
+                * LEB Y. We are here trying to recover LEB Y which is the GC
+                * head LEB. We find the min. I/O unit B as described above.
+                * Then we clean-up LEB Y by padding min. I/O unit. And later
+                * 'ubifs_rcvry_gc_commit()' function fails, because it cannot
+                * find a dirty LEB which could be GC'd into LEB Y! Even LEB X
+                * does not match because the amount of valid nodes there does
+                * not fit the free space in LEB Y any more! And this is
+                * because of the padding node which we added to LEB Y. The
+                * user-visible effect of this which I once observed and
+                * analysed is that we cannot mount the file-system with
+                * -ENOSPC error.
+                *
+                * So obviously, to make sure that situation does not happen we
+                * should free min. I/O unit B in LEB Y completely and the last
+                * used min. I/O unit in LEB Y should be A. This is basically
+                * what the below code tries to do.
+                */
+               while (offs > min_io_unit)
+                       drop_last_node(sleb, &offs);
        }
 
+       buf = sbuf + offs;
+       len = c->leb_size - offs;
+
+       clean_buf(c, &buf, lnum, &offs, &len);
        ubifs_end_scan(c, sleb, lnum, offs);
 
-       if (need_clean) {
-               err = fix_unclean_leb(c, sleb, start);
-               if (err)
-                       goto error;
-       }
+       err = fix_unclean_leb(c, sleb, start);
+       if (err)
+               goto error;
 
        return sleb;
 
+corrupted_rescan:
+       /* Re-scan the corrupted data with verbose messages */
+       dbg_err("corruptio %d", ret);
+       ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
 corrupted:
        ubifs_scanned_corruption(c, lnum, offs, buf);
        err = -EUCLEAN;
@@ -867,7 +905,7 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
                }
                ubifs_scan_destroy(sleb);
        }
-       return ubifs_recover_leb(c, lnum, offs, sbuf, 0);
+       return ubifs_recover_leb(c, lnum, offs, sbuf, -1);
 }
 
 /**
@@ -1069,6 +1107,53 @@ int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf)
        return 0;
 }
 
+/**
+ * grab_empty_leb - grab an empty LEB to use as GC LEB and run commit.
+ * @c: UBIFS file-system description object
+ *
+ * This is a helper function for 'ubifs_rcvry_gc_commit()' which grabs an empty
+ * LEB to be used as GC LEB (@c->gc_lnum), and then runs the commit. Returns
+ * zero in case of success and a negative error code in case of failure.
+ */
+static int grab_empty_leb(struct ubifs_info *c)
+{
+       int lnum, err;
+
+       /*
+        * Note, it is very important to first search for an empty LEB and then
+        * run the commit, not vice-versa. The reason is that there might be
+        * only one empty LEB at the moment, the one which has been the
+        * @c->gc_lnum just before the power cut happened. During the regular
+        * UBIFS operation (not now) @c->gc_lnum is marked as "taken", so no
+        * one but GC can grab it. But at this moment this single empty LEB is
+        * not marked as taken, so if we run commit - what happens? Right, the
+        * commit will grab it and write the index there. Remember that the
+        * index always expands as long as there is free space, and it only
+        * starts consolidating when we run out of space.
+        *
+        * IOW, if we run commit now, we might not be able to find a free LEB
+        * after this.
+        */
+       lnum = ubifs_find_free_leb_for_idx(c);
+       if (lnum < 0) {
+               dbg_err("could not find an empty LEB");
+               dbg_dump_lprops(c);
+               dbg_dump_budg(c, &c->bi);
+               return lnum;
+       }
+
+       /* Reset the index flag */
+       err = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
+                                 LPROPS_INDEX, 0);
+       if (err)
+               return err;
+
+       c->gc_lnum = lnum;
+       dbg_rcvry("found empty LEB %d, run commit", lnum);
+
+       return ubifs_run_commit(c);
+}
+
 /**
  * ubifs_rcvry_gc_commit - recover the GC LEB number and run the commit.
  * @c: UBIFS file-system description object
@@ -1091,71 +1176,26 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
 {
        struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
        struct ubifs_lprops lp;
-       int lnum, err;
+       int err;
+
+       dbg_rcvry("GC head LEB %d, offs %d", wbuf->lnum, wbuf->offs);
 
        c->gc_lnum = -1;
-       if (wbuf->lnum == -1) {
-               dbg_rcvry("no GC head LEB");
-               goto find_free;
-       }
-       /*
-        * See whether the used space in the dirtiest LEB fits in the GC head
-        * LEB.
-        */
-       if (wbuf->offs == c->leb_size) {
-               dbg_rcvry("no room in GC head LEB");
-               goto find_free;
-       }
+       if (wbuf->lnum == -1 || wbuf->offs == c->leb_size)
+               return grab_empty_leb(c);
+
        err = ubifs_find_dirty_leb(c, &lp, wbuf->offs, 2);
        if (err) {
-               /*
-                * There are no dirty or empty LEBs subject to here being
-                * enough for the index. Try to use
-                * 'ubifs_find_free_leb_for_idx()', which will return any empty
-                * LEBs (ignoring index requirements). If the index then
-                * doesn't have enough LEBs the recovery commit will fail -
-                * which is the  same result anyway i.e. recovery fails. So
-                * there is no problem ignoring index  requirements and just
-                * grabbing a free LEB since we have already established there
-                * is not a dirty LEB we could have used instead.
-                */
-               if (err == -ENOSPC) {
-                       dbg_rcvry("could not find a dirty LEB");
-                       goto find_free;
-               }
-               return err;
-       }
-       ubifs_assert(!(lp.flags & LPROPS_INDEX));
-       lnum = lp.lnum;
-       if (lp.free + lp.dirty == c->leb_size) {
-               /* An empty LEB was returned */
-               if (lp.free != c->leb_size) {
-                       err = ubifs_change_one_lp(c, lnum, c->leb_size,
-                                                 0, 0, 0, 0);
-                       if (err)
-                               return err;
-               }
-               err = ubifs_leb_unmap(c, lnum);
-               if (err)
-                       return err;
-               c->gc_lnum = lnum;
-               dbg_rcvry("allocated LEB %d for GC", lnum);
-               /* Run the commit */
-               dbg_rcvry("committing");
-               return ubifs_run_commit(c);
-       }
-       /*
-        * There was no empty LEB so the used space in the dirtiest LEB must fit
-        * in the GC head LEB.
-        */
-       if (lp.free + lp.dirty < wbuf->offs) {
-               dbg_rcvry("LEB %d doesn't fit in GC head LEB %d:%d",
-                         lnum, wbuf->lnum, wbuf->offs);
-               err = ubifs_return_leb(c, lnum);
-               if (err)
+               if (err != -ENOSPC)
                        return err;
-               goto find_free;
+
+               dbg_rcvry("could not find a dirty LEB");
+               return grab_empty_leb(c);
        }
+
+       ubifs_assert(!(lp.flags & LPROPS_INDEX));
+       ubifs_assert(lp.free + lp.dirty >= wbuf->offs);
+
        /*
         * We run the commit before garbage collection otherwise subsequent
         * mounts will see the GC and orphan deletion in a different order.
@@ -1164,11 +1204,8 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
        err = ubifs_run_commit(c);
        if (err)
                return err;
-       /*
-        * The data in the dirtiest LEB fits in the GC head LEB, so do the GC
-        * - use locking to keep 'ubifs_assert()' happy.
-        */
-       dbg_rcvry("GC'ing LEB %d", lnum);
+
+       dbg_rcvry("GC'ing LEB %d", lp.lnum);
        mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
        err = ubifs_garbage_collect_leb(c, &lp);
        if (err >= 0) {
@@ -1184,37 +1221,17 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
                        err = -EINVAL;
                return err;
        }
-       if (err != LEB_RETAINED) {
-               dbg_err("GC returned %d", err);
+
+       ubifs_assert(err == LEB_RETAINED);
+       if (err != LEB_RETAINED)
                return -EINVAL;
-       }
+
        err = ubifs_leb_unmap(c, c->gc_lnum);
        if (err)
                return err;
-       dbg_rcvry("allocated LEB %d for GC", lnum);
-       return 0;
 
-find_free:
-       /*
-        * There is no GC head LEB or the free space in the GC head LEB is too
-        * small, or there are not dirty LEBs. Allocate gc_lnum by calling
-        * 'ubifs_find_free_leb_for_idx()' so GC is not run.
-        */
-       lnum = ubifs_find_free_leb_for_idx(c);
-       if (lnum < 0) {
-               dbg_err("could not find an empty LEB");
-               return lnum;
-       }
-       /* And reset the index flag */
-       err = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
-                                 LPROPS_INDEX, 0);
-       if (err)
-               return err;
-       c->gc_lnum = lnum;
-       dbg_rcvry("allocated LEB %d for GC", lnum);
-       /* Run the commit */
-       dbg_rcvry("committing");
-       return ubifs_run_commit(c);
+       dbg_rcvry("allocated LEB %d for GC", lp.lnum);
+       return 0;
 }
 
 /**
@@ -1456,7 +1473,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
        err = ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN);
        if (err)
                goto out;
-       dbg_rcvry("inode %lu at %d:%d size %lld -> %lld ",
+       dbg_rcvry("inode %lu at %d:%d size %lld -> %lld",
                  (unsigned long)e->inum, lnum, offs, i_size, e->d_size);
        return 0;
 
@@ -1505,20 +1522,27 @@ int ubifs_recover_size(struct ubifs_info *c)
                                e->i_size = le64_to_cpu(ino->size);
                        }
                }
+
                if (e->exists && e->i_size < e->d_size) {
-                       if (!e->inode && c->ro_mount) {
+                       if (c->ro_mount) {
                                /* Fix the inode size and pin it in memory */
                                struct inode *inode;
+                               struct ubifs_inode *ui;
+
+                               ubifs_assert(!e->inode);
 
                                inode = ubifs_iget(c->vfs_sb, e->inum);
                                if (IS_ERR(inode))
                                        return PTR_ERR(inode);
+
+                               ui = ubifs_inode(inode);
                                if (inode->i_size < e->d_size) {
                                        dbg_rcvry("ino %lu size %lld -> %lld",
                                                  (unsigned long)e->inum,
-                                                 e->d_size, inode->i_size);
+                                                 inode->i_size, e->d_size);
                                        inode->i_size = e->d_size;
-                                       ubifs_inode(inode)->ui_size = e->d_size;
+                                       ui->ui_size = e->d_size;
+                                       ui->synced_i_size = e->d_size;
                                        e->inode = inode;
                                        this = rb_next(this);
                                        continue;
@@ -1533,9 +1557,11 @@ int ubifs_recover_size(struct ubifs_info *c)
                                        iput(e->inode);
                        }
                }
+
                this = rb_next(this);
                rb_erase(&e->rb, &c->size_tree);
                kfree(e);
        }
+
        return 0;
 }
index d3d6d365bfc11345d49e3a6bbdc33dd97c476ea9..5e97161ce4d35f929a953184098057f37454dde2 100644 (file)
  */
 
 #include "ubifs.h"
-
-/*
- * Replay flags.
- *
- * REPLAY_DELETION: node was deleted
- * REPLAY_REF: node is a reference node
- */
-enum {
-       REPLAY_DELETION = 1,
-       REPLAY_REF = 2,
-};
+#include <linux/list_sort.h>
 
 /**
- * struct replay_entry - replay tree entry.
+ * struct replay_entry - replay list entry.
  * @lnum: logical eraseblock number of the node
  * @offs: node offset
  * @len: node length
+ * @deletion: non-zero if this entry corresponds to a node deletion
  * @sqnum: node sequence number
- * @flags: replay flags
- * @rb: links the replay tree
+ * @list: links the replay list
  * @key: node key
  * @nm: directory entry name
  * @old_size: truncation old size
  * @new_size: truncation new size
- * @free: amount of free space in a bud
- * @dirty: amount of dirty space in a bud from padding and deletion nodes
- * @jhead: journal head number of the bud
  *
- * UBIFS journal replay must compare node sequence numbers, which means it must
- * build a tree of node information to insert into the TNC.
+ * The replay process first scans all buds and builds the replay list, then
+ * sorts the replay list in nodes sequence number order, and then inserts all
+ * the replay entries to the TNC.
  */
 struct replay_entry {
        int lnum;
        int offs;
        int len;
+       unsigned int deletion:1;
        unsigned long long sqnum;
-       int flags;
-       struct rb_node rb;
+       struct list_head list;
        union ubifs_key key;
        union {
                struct qstr nm;
@@ -78,11 +66,6 @@ struct replay_entry {
                        loff_t old_size;
                        loff_t new_size;
                };
-               struct {
-                       int free;
-                       int dirty;
-                       int jhead;
-               };
        };
 };
 
@@ -90,57 +73,64 @@ struct replay_entry {
  * struct bud_entry - entry in the list of buds to replay.
  * @list: next bud in the list
  * @bud: bud description object
- * @free: free bytes in the bud
  * @sqnum: reference node sequence number
+ * @free: free bytes in the bud
+ * @dirty: dirty bytes in the bud
  */
 struct bud_entry {
        struct list_head list;
        struct ubifs_bud *bud;
-       int free;
        unsigned long long sqnum;
+       int free;
+       int dirty;
 };
 
 /**
  * set_bud_lprops - set free and dirty space used by a bud.
  * @c: UBIFS file-system description object
- * @r: replay entry of bud
+ * @b: bud entry which describes the bud
+ *
+ * This function makes sure the LEB properties of bud @b are set correctly
+ * after the replay. Returns zero in case of success and a negative error code
+ * in case of failure.
  */
-static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
+static int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b)
 {
        const struct ubifs_lprops *lp;
        int err = 0, dirty;
 
        ubifs_get_lprops(c);
 
-       lp = ubifs_lpt_lookup_dirty(c, r->lnum);
+       lp = ubifs_lpt_lookup_dirty(c, b->bud->lnum);
        if (IS_ERR(lp)) {
                err = PTR_ERR(lp);
                goto out;
        }
 
        dirty = lp->dirty;
-       if (r->offs == 0 && (lp->free != c->leb_size || lp->dirty != 0)) {
+       if (b->bud->start == 0 && (lp->free != c->leb_size || lp->dirty != 0)) {
                /*
                 * The LEB was added to the journal with a starting offset of
                 * zero which means the LEB must have been empty. The LEB
-                * property values should be lp->free == c->leb_size and
-                * lp->dirty == 0, but that is not the case. The reason is that
-                * the LEB was garbage collected. The garbage collector resets
-                * the free and dirty space without recording it anywhere except
-                * lprops, so if there is not a commit then lprops does not have
-                * that information next time the file system is mounted.
+                * property values should be @lp->free == @c->leb_size and
+                * @lp->dirty == 0, but that is not the case. The reason is that
+                * the LEB had been garbage collected before it became the bud,
+                * and there was not commit inbetween. The garbage collector
+                * resets the free and dirty space without recording it
+                * anywhere except lprops, so if there was no commit then
+                * lprops does not have that information.
                 *
                 * We do not need to adjust free space because the scan has told
                 * us the exact value which is recorded in the replay entry as
-                * r->free.
+                * @b->free.
                 *
                 * However we do need to subtract from the dirty space the
                 * amount of space that the garbage collector reclaimed, which
                 * is the whole LEB minus the amount of space that was free.
                 */
-               dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
+               dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum,
                        lp->free, lp->dirty);
-               dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
+               dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum,
                        lp->free, lp->dirty);
                dirty -= c->leb_size - lp->free;
                /*
@@ -152,10 +142,10 @@ static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
                 */
                if (dirty != 0)
                        dbg_msg("LEB %d lp: %d free %d dirty "
-                               "replay: %d free %d dirty", r->lnum, lp->free,
-                               lp->dirty, r->free, r->dirty);
+                               "replay: %d free %d dirty", b->bud->lnum,
+                               lp->free, lp->dirty, b->free, b->dirty);
        }
-       lp = ubifs_change_lp(c, lp, r->free, dirty + r->dirty,
+       lp = ubifs_change_lp(c, lp, b->free, dirty + b->dirty,
                             lp->flags | LPROPS_TAKEN, 0);
        if (IS_ERR(lp)) {
                err = PTR_ERR(lp);
@@ -163,14 +153,36 @@ static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
        }
 
        /* Make sure the journal head points to the latest bud */
-       err = ubifs_wbuf_seek_nolock(&c->jheads[r->jhead].wbuf, r->lnum,
-                                    c->leb_size - r->free, UBI_SHORTTERM);
+       err = ubifs_wbuf_seek_nolock(&c->jheads[b->bud->jhead].wbuf,
+                                    b->bud->lnum, c->leb_size - b->free,
+                                    UBI_SHORTTERM);
 
 out:
        ubifs_release_lprops(c);
        return err;
 }
 
+/**
+ * set_buds_lprops - set free and dirty space for all replayed buds.
+ * @c: UBIFS file-system description object
+ *
+ * This function sets LEB properties for all replayed buds. Returns zero in
+ * case of success and a negative error code in case of failure.
+ */
+static int set_buds_lprops(struct ubifs_info *c)
+{
+       struct bud_entry *b;
+       int err;
+
+       list_for_each_entry(b, &c->replay_buds, list) {
+               err = set_bud_lprops(c, b);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
 /**
  * trun_remove_range - apply a replay entry for a truncation to the TNC.
  * @c: UBIFS file-system description object
@@ -207,24 +219,22 @@ static int trun_remove_range(struct ubifs_info *c, struct replay_entry *r)
  */
 static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
 {
-       int err, deletion = ((r->flags & REPLAY_DELETION) != 0);
+       int err;
 
-       dbg_mnt("LEB %d:%d len %d flgs %d sqnum %llu %s", r->lnum,
-               r->offs, r->len, r->flags, r->sqnum, DBGKEY(&r->key));
+       dbg_mnt("LEB %d:%d len %d deletion %d sqnum %llu %s", r->lnum,
+               r->offs, r->len, r->deletion, r->sqnum, DBGKEY(&r->key));
 
        /* Set c->replay_sqnum to help deal with dangling branches. */
        c->replay_sqnum = r->sqnum;
 
-       if (r->flags & REPLAY_REF)
-               err = set_bud_lprops(c, r);
-       else if (is_hash_key(c, &r->key)) {
-               if (deletion)
+       if (is_hash_key(c, &r->key)) {
+               if (r->deletion)
                        err = ubifs_tnc_remove_nm(c, &r->key, &r->nm);
                else
                        err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs,
                                               r->len, &r->nm);
        } else {
-               if (deletion)
+               if (r->deletion)
                        switch (key_type(c, &r->key)) {
                        case UBIFS_INO_KEY:
                        {
@@ -247,7 +257,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
                        return err;
 
                if (c->need_recovery)
-                       err = ubifs_recover_size_accum(c, &r->key, deletion,
+                       err = ubifs_recover_size_accum(c, &r->key, r->deletion,
                                                       r->new_size);
        }
 
@@ -255,68 +265,77 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
 }
 
 /**
- * destroy_replay_tree - destroy the replay.
- * @c: UBIFS file-system description object
+ * replay_entries_cmp - compare 2 replay entries.
+ * @priv: UBIFS file-system description object
+ * @a: first replay entry
+ * @a: second replay entry
  *
- * Destroy the replay tree.
+ * This is a comparios function for 'list_sort()' which compares 2 replay
+ * entries @a and @b by comparing their sequence numer.  Returns %1 if @a has
+ * greater sequence number and %-1 otherwise.
  */
-static void destroy_replay_tree(struct ubifs_info *c)
+static int replay_entries_cmp(void *priv, struct list_head *a,
+                             struct list_head *b)
 {
-       struct rb_node *this = c->replay_tree.rb_node;
-       struct replay_entry *r;
-
-       while (this) {
-               if (this->rb_left) {
-                       this = this->rb_left;
-                       continue;
-               } else if (this->rb_right) {
-                       this = this->rb_right;
-                       continue;
-               }
-               r = rb_entry(this, struct replay_entry, rb);
-               this = rb_parent(this);
-               if (this) {
-                       if (this->rb_left == &r->rb)
-                               this->rb_left = NULL;
-                       else
-                               this->rb_right = NULL;
-               }
-               if (is_hash_key(c, &r->key))
-                       kfree(r->nm.name);
-               kfree(r);
-       }
-       c->replay_tree = RB_ROOT;
+       struct replay_entry *ra, *rb;
+
+       cond_resched();
+       if (a == b)
+               return 0;
+
+       ra = list_entry(a, struct replay_entry, list);
+       rb = list_entry(b, struct replay_entry, list);
+       ubifs_assert(ra->sqnum != rb->sqnum);
+       if (ra->sqnum > rb->sqnum)
+               return 1;
+       return -1;
 }
 
 /**
- * apply_replay_tree - apply the replay tree to the TNC.
+ * apply_replay_list - apply the replay list to the TNC.
  * @c: UBIFS file-system description object
  *
- * Apply the replay tree.
- * Returns zero in case of success and a negative error code in case of
- * failure.
+ * Apply all entries in the replay list to the TNC. Returns zero in case of
+ * success and a negative error code in case of failure.
  */
-static int apply_replay_tree(struct ubifs_info *c)
+static int apply_replay_list(struct ubifs_info *c)
 {
-       struct rb_node *this = rb_first(&c->replay_tree);
+       struct replay_entry *r;
+       int err;
 
-       while (this) {
-               struct replay_entry *r;
-               int err;
+       list_sort(c, &c->replay_list, &replay_entries_cmp);
 
+       list_for_each_entry(r, &c->replay_list, list) {
                cond_resched();
 
-               r = rb_entry(this, struct replay_entry, rb);
                err = apply_replay_entry(c, r);
                if (err)
                        return err;
-               this = rb_next(this);
        }
+
        return 0;
 }
 
 /**
- * insert_node - insert a node to the replay tree.
+ * destroy_replay_list - destroy the replay.
+ * @c: UBIFS file-system description object
+ *
+ * Destroy the replay list.
+ */
+static void destroy_replay_list(struct ubifs_info *c)
+{
+       struct replay_entry *r, *tmp;
+
+       list_for_each_entry_safe(r, tmp, &c->replay_list, list) {
+               if (is_hash_key(c, &r->key))
+                       kfree(r->nm.name);
+               list_del(&r->list);
+               kfree(r);
+       }
+}
+
+/**
+ * insert_node - insert a node to the replay list
  * @c: UBIFS file-system description object
  * @lnum: node logical eraseblock number
  * @offs: node offset
@@ -328,39 +347,25 @@ static int apply_replay_tree(struct ubifs_info *c)
  * @old_size: truncation old size
  * @new_size: truncation new size
  *
- * This function inserts a scanned non-direntry node to the replay tree. The
- * replay tree is an RB-tree containing @struct replay_entry elements which are
- * indexed by the sequence number. The replay tree is applied at the very end
- * of the replay process. Since the tree is sorted in sequence number order,
- * the older modifications are applied first. This function returns zero in
- * case of success and a negative error code in case of failure.
+ * This function inserts a scanned non-direntry node to the replay list. The
+ * replay list contains @struct replay_entry elements, and we sort this list in
+ * sequence number order before applying it. The replay list is applied at the
+ * very end of the replay process. Since the list is sorted in sequence number
+ * order, the older modifications are applied first. This function returns zero
+ * in case of success and a negative error code in case of failure.
  */
 static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
                       union ubifs_key *key, unsigned long long sqnum,
                       int deletion, int *used, loff_t old_size,
                       loff_t new_size)
 {
-       struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
        struct replay_entry *r;
 
+       dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
+
        if (key_inum(c, key) >= c->highest_inum)
                c->highest_inum = key_inum(c, key);
 
-       dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
-       while (*p) {
-               parent = *p;
-               r = rb_entry(parent, struct replay_entry, rb);
-               if (sqnum < r->sqnum) {
-                       p = &(*p)->rb_left;
-                       continue;
-               } else if (sqnum > r->sqnum) {
-                       p = &(*p)->rb_right;
-                       continue;
-               }
-               ubifs_err("duplicate sqnum in replay");
-               return -EINVAL;
-       }
-
        r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
        if (!r)
                return -ENOMEM;
@@ -370,19 +375,18 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
        r->lnum = lnum;
        r->offs = offs;
        r->len = len;
+       r->deletion = !!deletion;
        r->sqnum = sqnum;
-       r->flags = (deletion ? REPLAY_DELETION : 0);
+       key_copy(c, key, &r->key);
        r->old_size = old_size;
        r->new_size = new_size;
-       key_copy(c, key, &r->key);
 
-       rb_link_node(&r->rb, parent, p);
-       rb_insert_color(&r->rb, &c->replay_tree);
+       list_add_tail(&r->list, &c->replay_list);
        return 0;
 }
 
 /**
- * insert_dent - insert a directory entry node into the replay tree.
+ * insert_dent - insert a directory entry node into the replay list.
  * @c: UBIFS file-system description object
  * @lnum: node logical eraseblock number
  * @offs: node offset
@@ -394,43 +398,25 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
  * @deletion: non-zero if this is a deletion
  * @used: number of bytes in use in a LEB
  *
- * This function inserts a scanned directory entry node to the replay tree.
- * Returns zero in case of success and a negative error code in case of
- * failure.
- *
- * This function is also used for extended attribute entries because they are
- * implemented as directory entry nodes.
+ * This function inserts a scanned directory entry node or an extended
+ * attribute entry to the replay list. Returns zero in case of success and a
+ * negative error code in case of failure.
  */
 static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
                       union ubifs_key *key, const char *name, int nlen,
                       unsigned long long sqnum, int deletion, int *used)
 {
-       struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
        struct replay_entry *r;
        char *nbuf;
 
+       dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
        if (key_inum(c, key) >= c->highest_inum)
                c->highest_inum = key_inum(c, key);
 
-       dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
-       while (*p) {
-               parent = *p;
-               r = rb_entry(parent, struct replay_entry, rb);
-               if (sqnum < r->sqnum) {
-                       p = &(*p)->rb_left;
-                       continue;
-               }
-               if (sqnum > r->sqnum) {
-                       p = &(*p)->rb_right;
-                       continue;
-               }
-               ubifs_err("duplicate sqnum in replay");
-               return -EINVAL;
-       }
-
        r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
        if (!r)
                return -ENOMEM;
+
        nbuf = kmalloc(nlen + 1, GFP_KERNEL);
        if (!nbuf) {
                kfree(r);
@@ -442,17 +428,15 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
        r->lnum = lnum;
        r->offs = offs;
        r->len = len;
+       r->deletion = !!deletion;
        r->sqnum = sqnum;
+       key_copy(c, key, &r->key);
        r->nm.len = nlen;
        memcpy(nbuf, name, nlen);
        nbuf[nlen] = '\0';
        r->nm.name = nbuf;
-       r->flags = (deletion ? REPLAY_DELETION : 0);
-       key_copy(c, key, &r->key);
 
-       ubifs_assert(!*p);
-       rb_link_node(&r->rb, parent, p);
-       rb_insert_color(&r->rb, &c->replay_tree);
+       list_add_tail(&r->list, &c->replay_list);
        return 0;
 }
 
@@ -488,30 +472,92 @@ int ubifs_validate_entry(struct ubifs_info *c,
        return 0;
 }
 
+/**
+ * is_last_bud - check if the bud is the last in the journal head.
+ * @c: UBIFS file-system description object
+ * @bud: bud description object
+ *
+ * This function checks if bud @bud is the last bud in its journal head. This
+ * information is then used by 'replay_bud()' to decide whether the bud can
+ * have corruptions or not. Indeed, only last buds can be corrupted by power
+ * cuts. Returns %1 if this is the last bud, and %0 if not.
+ */
+static int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud)
+{
+       struct ubifs_jhead *jh = &c->jheads[bud->jhead];
+       struct ubifs_bud *next;
+       uint32_t data;
+       int err;
+
+       if (list_is_last(&bud->list, &jh->buds_list))
+               return 1;
+
+       /*
+        * The following is a quirk to make sure we work correctly with UBIFS
+        * images used with older UBIFS.
+        *
+        * Normally, the last bud will be the last in the journal head's list
+        * of bud. However, there is one exception if the UBIFS image belongs
+        * to older UBIFS. This is fairly unlikely: one would need to use old
+        * UBIFS, then have a power cut exactly at the right point, and then
+        * try to mount this image with new UBIFS.
+        *
+        * The exception is: it is possible to have 2 buds A and B, A goes
+        * before B, and B is the last, bud B is contains no data, and bud A is
+        * corrupted at the end. The reason is that in older versions when the
+        * journal code switched the next bud (from A to B), it first added a
+        * log reference node for the new bud (B), and only after this it
+        * synchronized the write-buffer of current bud (A). But later this was
+        * changed and UBIFS started to always synchronize the write-buffer of
+        * the bud (A) before writing the log reference for the new bud (B).
+        *
+        * But because older UBIFS always synchronized A's write-buffer before
+        * writing to B, we can recognize this exceptional situation but
+        * checking the contents of bud B - if it is empty, then A can be
+        * treated as the last and we can recover it.
+        *
+        * TODO: remove this piece of code in a couple of years (today it is
+        * 16.05.2011).
+        */
+       next = list_entry(bud->list.next, struct ubifs_bud, list);
+       if (!list_is_last(&next->list, &jh->buds_list))
+               return 0;
+
+       err = ubi_read(c->ubi, next->lnum, (char *)&data,
+                      next->start, 4);
+       if (err)
+               return 0;
+
+       return data == 0xFFFFFFFF;
+}
+
 /**
  * replay_bud - replay a bud logical eraseblock.
  * @c: UBIFS file-system description object
- * @lnum: bud logical eraseblock number to replay
- * @offs: bud start offset
- * @jhead: journal head to which this bud belongs
- * @free: amount of free space in the bud is returned here
- * @dirty: amount of dirty space from padding and deletion nodes is returned
- * here
+ * @b: bud entry which describes the bud
  *
- * This function returns zero in case of success and a negative error code in
- * case of failure.
+ * This function replays bud @bud, recovers it if needed, and adds all nodes
+ * from this bud to the replay list. Returns zero in case of success and a
+ * negative error code in case of failure.
  */
-static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
-                     int *free, int *dirty)
+static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
 {
-       int err = 0, used = 0;
+       int is_last = is_last_bud(c, b->bud);
+       int err = 0, used = 0, lnum = b->bud->lnum, offs = b->bud->start;
        struct ubifs_scan_leb *sleb;
        struct ubifs_scan_node *snod;
-       struct ubifs_bud *bud;
 
-       dbg_mnt("replay bud LEB %d, head %d", lnum, jhead);
-       if (c->need_recovery)
-               sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, jhead != GCHD);
+       dbg_mnt("replay bud LEB %d, head %d, offs %d, is_last %d",
+               lnum, b->bud->jhead, offs, is_last);
+
+       if (c->need_recovery && is_last)
+               /*
+                * Recover only last LEBs in the journal heads, because power
+                * cuts may cause corruptions only in these LEBs, because only
+                * these LEBs could possibly be written to at the power cut
+                * time.
+                */
+               sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, b->bud->jhead);
        else
                sleb = ubifs_scan(c, lnum, offs, c->sbuf, 0);
        if (IS_ERR(sleb))
@@ -627,15 +673,13 @@ static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
                        goto out;
        }
 
-       bud = ubifs_search_bud(c, lnum);
-       if (!bud)
-               BUG();
-
+       ubifs_assert(ubifs_search_bud(c, lnum));
        ubifs_assert(sleb->endpt - offs >= used);
        ubifs_assert(sleb->endpt % c->min_io_size == 0);
 
-       *dirty = sleb->endpt - offs - used;
-       *free = c->leb_size - sleb->endpt;
+       b->dirty = sleb->endpt - offs - used;
+       b->free = c->leb_size - sleb->endpt;
+       dbg_mnt("bud LEB %d replied: dirty %d, free %d", lnum, b->dirty, b->free);
 
 out:
        ubifs_scan_destroy(sleb);
@@ -648,58 +692,6 @@ out_dump:
        return -EINVAL;
 }
 
-/**
- * insert_ref_node - insert a reference node to the replay tree.
- * @c: UBIFS file-system description object
- * @lnum: node logical eraseblock number
- * @offs: node offset
- * @sqnum: sequence number
- * @free: amount of free space in bud
- * @dirty: amount of dirty space from padding and deletion nodes
- * @jhead: journal head number for the bud
- *
- * This function inserts a reference node to the replay tree and returns zero
- * in case of success or a negative error code in case of failure.
- */
-static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
-                          unsigned long long sqnum, int free, int dirty,
-                          int jhead)
-{
-       struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
-       struct replay_entry *r;
-
-       dbg_mnt("add ref LEB %d:%d", lnum, offs);
-       while (*p) {
-               parent = *p;
-               r = rb_entry(parent, struct replay_entry, rb);
-               if (sqnum < r->sqnum) {
-                       p = &(*p)->rb_left;
-                       continue;
-               } else if (sqnum > r->sqnum) {
-                       p = &(*p)->rb_right;
-                       continue;
-               }
-               ubifs_err("duplicate sqnum in replay tree");
-               return -EINVAL;
-       }
-
-       r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
-       if (!r)
-               return -ENOMEM;
-
-       r->lnum = lnum;
-       r->offs = offs;
-       r->sqnum = sqnum;
-       r->flags = REPLAY_REF;
-       r->free = free;
-       r->dirty = dirty;
-       r->jhead = jhead;
-
-       rb_link_node(&r->rb, parent, p);
-       rb_insert_color(&r->rb, &c->replay_tree);
-       return 0;
-}
-
 /**
  * replay_buds - replay all buds.
  * @c: UBIFS file-system description object
@@ -710,17 +702,16 @@ static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
 static int replay_buds(struct ubifs_info *c)
 {
        struct bud_entry *b;
-       int err, uninitialized_var(free), uninitialized_var(dirty);
+       int err;
+       unsigned long long prev_sqnum = 0;
 
        list_for_each_entry(b, &c->replay_buds, list) {
-               err = replay_bud(c, b->bud->lnum, b->bud->start, b->bud->jhead,
-                                &free, &dirty);
-               if (err)
-                       return err;
-               err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum,
-                                     free, dirty, b->bud->jhead);
+               err = replay_bud(c, b);
                if (err)
                        return err;
+
+               ubifs_assert(b->sqnum > prev_sqnum);
+               prev_sqnum = b->sqnum;
        }
 
        return 0;
@@ -1060,25 +1051,29 @@ int ubifs_replay_journal(struct ubifs_info *c)
        if (err)
                goto out;
 
-       err = apply_replay_tree(c);
+       err = apply_replay_list(c);
+       if (err)
+               goto out;
+
+       err = set_buds_lprops(c);
        if (err)
                goto out;
 
        /*
-        * UBIFS budgeting calculations use @c->budg_uncommitted_idx variable
-        * to roughly estimate index growth. Things like @c->min_idx_lebs
+        * UBIFS budgeting calculations use @c->bi.uncommitted_idx variable
+        * to roughly estimate index growth. Things like @c->bi.min_idx_lebs
         * depend on it. This means we have to initialize it to make sure
         * budgeting works properly.
         */
-       c->budg_uncommitted_idx = atomic_long_read(&c->dirty_zn_cnt);
-       c->budg_uncommitted_idx *= c->max_idx_node_sz;
+       c->bi.uncommitted_idx = atomic_long_read(&c->dirty_zn_cnt);
+       c->bi.uncommitted_idx *= c->max_idx_node_sz;
 
        ubifs_assert(c->bud_bytes <= c->max_bud_bytes || c->need_recovery);
        dbg_mnt("finished, log head LEB %d:%d, max_sqnum %llu, "
                "highest_inum %lu", c->lhead_lnum, c->lhead_offs, c->max_sqnum,
                (unsigned long)c->highest_inum);
 out:
-       destroy_replay_tree(c);
+       destroy_replay_list(c);
        destroy_bud_list(c);
        c->replaying = 0;
        return err;
index bf31b4729e51ce466560777a1e24bad90356311b..c606f010e8df072882d23633c9a58831ca805f86 100644 (file)
@@ -475,7 +475,8 @@ failed:
  * @c: UBIFS file-system description object
  *
  * This function returns a pointer to the superblock node or a negative error
- * code.
+ * code. Note, the user of this function is responsible of kfree()'ing the
+ * returned superblock buffer.
  */
 struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
 {
@@ -616,6 +617,7 @@ int ubifs_read_superblock(struct ubifs_info *c)
        c->vfs_sb->s_time_gran = le32_to_cpu(sup->time_gran);
        memcpy(&c->uuid, &sup->uuid, 16);
        c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
+       c->space_fixup = !!(sup_flags & UBIFS_FLG_SPACE_FIXUP);
 
        /* Automatically increase file system size to the maximum size */
        c->old_leb_cnt = c->leb_cnt;
@@ -650,3 +652,152 @@ out:
        kfree(sup);
        return err;
 }
+
+/**
+ * fixup_leb - fixup/unmap an LEB containing free space.
+ * @c: UBIFS file-system description object
+ * @lnum: the LEB number to fix up
+ * @len: number of used bytes in LEB (starting at offset 0)
+ *
+ * This function reads the contents of the given LEB number @lnum, then fixes
+ * it up, so that empty min. I/O units in the end of LEB are actually erased on
+ * flash (rather than being just all-0xff real data). If the LEB is completely
+ * empty, it is simply unmapped.
+ */
+static int fixup_leb(struct ubifs_info *c, int lnum, int len)
+{
+       int err;
+
+       ubifs_assert(len >= 0);
+       ubifs_assert(len % c->min_io_size == 0);
+       ubifs_assert(len < c->leb_size);
+
+       if (len == 0) {
+               dbg_mnt("unmap empty LEB %d", lnum);
+               return ubi_leb_unmap(c->ubi, lnum);
+       }
+
+       dbg_mnt("fixup LEB %d, data len %d", lnum, len);
+       err = ubi_read(c->ubi, lnum, c->sbuf, 0, len);
+       if (err)
+               return err;
+
+       return ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN);
+}
+
+/**
+ * fixup_free_space - find & remap all LEBs containing free space.
+ * @c: UBIFS file-system description object
+ *
+ * This function walks through all LEBs in the filesystem and fiexes up those
+ * containing free/empty space.
+ */
+static int fixup_free_space(struct ubifs_info *c)
+{
+       int lnum, err = 0;
+       struct ubifs_lprops *lprops;
+
+       ubifs_get_lprops(c);
+
+       /* Fixup LEBs in the master area */
+       for (lnum = UBIFS_MST_LNUM; lnum < UBIFS_LOG_LNUM; lnum++) {
+               err = fixup_leb(c, lnum, c->mst_offs + c->mst_node_alsz);
+               if (err)
+                       goto out;
+       }
+
+       /* Unmap unused log LEBs */
+       lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
+       while (lnum != c->ltail_lnum) {
+               err = fixup_leb(c, lnum, 0);
+               if (err)
+                       goto out;
+               lnum = ubifs_next_log_lnum(c, lnum);
+       }
+
+       /* Fixup the current log head */
+       err = fixup_leb(c, c->lhead_lnum, c->lhead_offs);
+       if (err)
+               goto out;
+
+       /* Fixup LEBs in the LPT area */
+       for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) {
+               int free = c->ltab[lnum - c->lpt_first].free;
+
+               if (free > 0) {
+                       err = fixup_leb(c, lnum, c->leb_size - free);
+                       if (err)
+                               goto out;
+               }
+       }
+
+       /* Unmap LEBs in the orphans area */
+       for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
+               err = fixup_leb(c, lnum, 0);
+               if (err)
+                       goto out;
+       }
+
+       /* Fixup LEBs in the main area */
+       for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) {
+               lprops = ubifs_lpt_lookup(c, lnum);
+               if (IS_ERR(lprops)) {
+                       err = PTR_ERR(lprops);
+                       goto out;
+               }
+
+               if (lprops->free > 0) {
+                       err = fixup_leb(c, lnum, c->leb_size - lprops->free);
+                       if (err)
+                               goto out;
+               }
+       }
+
+out:
+       ubifs_release_lprops(c);
+       return err;
+}
+
+/**
+ * ubifs_fixup_free_space - find & fix all LEBs with free space.
+ * @c: UBIFS file-system description object
+ *
+ * This function fixes up LEBs containing free space on first mount, if the
+ * appropriate flag was set when the FS was created. Each LEB with one or more
+ * empty min. I/O unit (i.e. free-space-count > 0) is re-written, to make sure
+ * the free space is actually erased. E.g., this is necessary for some NAND
+ * chips, since the free space may have been programmed like real "0xff" data
+ * (generating a non-0xff ECC), causing future writes to the not-really-erased
+ * NAND pages to behave badly. After the space is fixed up, the superblock flag
+ * is cleared, so that this is skipped for all future mounts.
+ */
+int ubifs_fixup_free_space(struct ubifs_info *c)
+{
+       int err;
+       struct ubifs_sb_node *sup;
+
+       ubifs_assert(c->space_fixup);
+       ubifs_assert(!c->ro_mount);
+
+       ubifs_msg("start fixing up free space");
+
+       err = fixup_free_space(c);
+       if (err)
+               return err;
+
+       sup = ubifs_read_sb_node(c);
+       if (IS_ERR(sup))
+               return PTR_ERR(sup);
+
+       /* Free-space fixup is no longer required */
+       c->space_fixup = 0;
+       sup->flags &= cpu_to_le32(~UBIFS_FLG_SPACE_FIXUP);
+
+       err = ubifs_write_sb_node(c, sup);
+       kfree(sup);
+       if (err)
+               return err;
+
+       ubifs_msg("free space fixup complete");
+       return err;
+}
index 46961c00323627f3ee2a77d4633b7bcd44a839b8..9e1d05666fed5d1ad03589995f8ecb3f78ec7b82 100644 (file)
@@ -277,13 +277,18 @@ static int kick_a_thread(void)
        return 0;
 }
 
-int ubifs_shrinker(struct shrinker *shrink, int nr, gfp_t gfp_mask)
+int ubifs_shrinker(struct shrinker *shrink, struct shrink_control *sc)
 {
+       int nr = sc->nr_to_scan;
        int freed, contention = 0;
        long clean_zn_cnt = atomic_long_read(&ubifs_clean_zn_cnt);
 
        if (nr == 0)
-               return clean_zn_cnt;
+               /*
+                * Due to the way UBIFS updates the clean znode counter it may
+                * temporarily be negative.
+                */
+               return clean_zn_cnt >= 0 ? clean_zn_cnt : 1;
 
        if (!clean_zn_cnt) {
                /*
index 04ad07f4fcc3da11b05e868442ed6f3bc7ad7729..529be058202938cf1226ec8644401951df8ab032 100644 (file)
@@ -375,14 +375,14 @@ out:
                ubifs_release_dirty_inode_budget(c, ui);
        else {
                /* We've deleted something - clean the "no space" flags */
-               c->nospace = c->nospace_rp = 0;
+               c->bi.nospace = c->bi.nospace_rp = 0;
                smp_wmb();
        }
 done:
        end_writeback(inode);
 }
 
-static void ubifs_dirty_inode(struct inode *inode)
+static void ubifs_dirty_inode(struct inode *inode, int flags)
 {
        struct ubifs_inode *ui = ubifs_inode(inode);
 
@@ -694,11 +694,11 @@ static int init_constants_sb(struct ubifs_info *c)
         * be compressed and direntries are of the maximum size.
         *
         * Note, data, which may be stored in inodes is budgeted separately, so
-        * it is not included into 'c->inode_budget'.
+        * it is not included into 'c->bi.inode_budget'.
         */
-       c->page_budget = UBIFS_MAX_DATA_NODE_SZ * UBIFS_BLOCKS_PER_PAGE;
-       c->inode_budget = UBIFS_INO_NODE_SZ;
-       c->dent_budget = UBIFS_MAX_DENT_NODE_SZ;
+       c->bi.page_budget = UBIFS_MAX_DATA_NODE_SZ * UBIFS_BLOCKS_PER_PAGE;
+       c->bi.inode_budget = UBIFS_INO_NODE_SZ;
+       c->bi.dent_budget = UBIFS_MAX_DENT_NODE_SZ;
 
        /*
         * When the amount of flash space used by buds becomes
@@ -742,7 +742,7 @@ static void init_constants_master(struct ubifs_info *c)
 {
        long long tmp64;
 
-       c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
        c->report_rp_size = ubifs_reported_space(c, c->rp_size);
 
        /*
@@ -811,15 +811,18 @@ static int alloc_wbufs(struct ubifs_info *c)
 
                c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback;
                c->jheads[i].wbuf.jhead = i;
+               c->jheads[i].grouped = 1;
        }
 
        c->jheads[BASEHD].wbuf.dtype = UBI_SHORTTERM;
        /*
         * Garbage Collector head likely contains long-term data and
-        * does not need to be synchronized by timer.
+        * does not need to be synchronized by timer. Also GC head nodes are
+        * not grouped.
         */
        c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM;
        c->jheads[GCHD].wbuf.no_timer = 1;
+       c->jheads[GCHD].grouped = 0;
 
        return 0;
 }
@@ -1144,8 +1147,8 @@ static int check_free_space(struct ubifs_info *c)
 {
        ubifs_assert(c->dark_wm > 0);
        if (c->lst.total_free + c->lst.total_dirty < c->dark_wm) {
-               ubifs_err("insufficient free space to mount in read/write mode");
-               dbg_dump_budg(c);
+               ubifs_err("insufficient free space to mount in R/W mode");
+               dbg_dump_budg(c, &c->bi);
                dbg_dump_lprops(c);
                return -ENOSPC;
        }
@@ -1284,12 +1287,25 @@ static int mount_ubifs(struct ubifs_info *c)
        if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) {
                ubifs_msg("recovery needed");
                c->need_recovery = 1;
-               if (!c->ro_mount) {
-                       err = ubifs_recover_inl_heads(c, c->sbuf);
-                       if (err)
-                               goto out_master;
-               }
-       } else if (!c->ro_mount) {
+       }
+
+       if (c->need_recovery && !c->ro_mount) {
+               err = ubifs_recover_inl_heads(c, c->sbuf);
+               if (err)
+                       goto out_master;
+       }
+
+       err = ubifs_lpt_init(c, 1, !c->ro_mount);
+       if (err)
+               goto out_master;
+
+       if (!c->ro_mount && c->space_fixup) {
+               err = ubifs_fixup_free_space(c);
+               if (err)
+                       goto out_master;
+       }
+
+       if (!c->ro_mount) {
                /*
                 * Set the "dirty" flag so that if we reboot uncleanly we
                 * will notice this immediately on the next mount.
@@ -1297,14 +1313,10 @@ static int mount_ubifs(struct ubifs_info *c)
                c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
                err = ubifs_write_master(c);
                if (err)
-                       goto out_master;
+                       goto out_lpt;
        }
 
-       err = ubifs_lpt_init(c, 1, !c->ro_mount);
-       if (err)
-               goto out_lpt;
-
-       err = dbg_check_idx_size(c, c->old_idx_sz);
+       err = dbg_check_idx_size(c, c->bi.old_idx_sz);
        if (err)
                goto out_lpt;
 
@@ -1313,7 +1325,7 @@ static int mount_ubifs(struct ubifs_info *c)
                goto out_journal;
 
        /* Calculate 'min_idx_lebs' after journal replay */
-       c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
 
        err = ubifs_mount_orphans(c, c->need_recovery, c->ro_mount);
        if (err)
@@ -1442,7 +1454,8 @@ static int mount_ubifs(struct ubifs_info *c)
                c->main_lebs, c->main_first, c->leb_cnt - 1);
        dbg_msg("index LEBs:          %d", c->lst.idx_lebs);
        dbg_msg("total index bytes:   %lld (%lld KiB, %lld MiB)",
-               c->old_idx_sz, c->old_idx_sz >> 10, c->old_idx_sz >> 20);
+               c->bi.old_idx_sz, c->bi.old_idx_sz >> 10,
+               c->bi.old_idx_sz >> 20);
        dbg_msg("key hash type:       %d", c->key_hash_type);
        dbg_msg("tree fanout:         %d", c->fanout);
        dbg_msg("reserved GC LEB:     %d", c->gc_lnum);
@@ -1456,7 +1469,7 @@ static int mount_ubifs(struct ubifs_info *c)
        dbg_msg("node sizes:          ref %zu, cmt. start %zu, orph %zu",
                UBIFS_REF_NODE_SZ, UBIFS_CS_NODE_SZ, UBIFS_ORPH_NODE_SZ);
        dbg_msg("max. node sizes:     data %zu, inode %zu dentry %zu, idx %d",
-               UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ,
+               UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ,
                UBIFS_MAX_DENT_NODE_SZ, ubifs_idx_node_sz(c, c->fanout));
        dbg_msg("dead watermark:      %d", c->dead_wm);
        dbg_msg("dark watermark:      %d", c->dark_wm);
@@ -1584,6 +1597,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
                }
                sup->leb_cnt = cpu_to_le32(c->leb_cnt);
                err = ubifs_write_sb_node(c, sup);
+               kfree(sup);
                if (err)
                        goto out;
        }
@@ -1684,6 +1698,13 @@ static int ubifs_remount_rw(struct ubifs_info *c)
                 */
                err = dbg_check_space_info(c);
        }
+
+       if (c->space_fixup) {
+               err = ubifs_fixup_free_space(c);
+               if (err)
+                       goto out;
+       }
+
        mutex_unlock(&c->umount_mutex);
        return err;
 
@@ -1766,10 +1787,9 @@ static void ubifs_put_super(struct super_block *sb)
         * to write them back because of I/O errors.
         */
        if (!c->ro_error) {
-               ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0);
-               ubifs_assert(c->budg_idx_growth == 0);
-               ubifs_assert(c->budg_dd_growth == 0);
-               ubifs_assert(c->budg_data_growth == 0);
+               ubifs_assert(c->bi.idx_growth == 0);
+               ubifs_assert(c->bi.dd_growth == 0);
+               ubifs_assert(c->bi.data_growth == 0);
        }
 
        /*
@@ -1828,7 +1848,6 @@ static void ubifs_put_super(struct super_block *sb)
        bdi_destroy(&c->bdi);
        ubi_close_volume(c->ubi);
        mutex_unlock(&c->umount_mutex);
-       kfree(c);
 }
 
 static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
@@ -1951,61 +1970,65 @@ static struct ubi_volume_desc *open_ubi(const char *name, int mode)
        return ERR_PTR(-EINVAL);
 }
 
-static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
+static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi)
 {
-       struct ubi_volume_desc *ubi = sb->s_fs_info;
        struct ubifs_info *c;
-       struct inode *root;
-       int err;
 
        c = kzalloc(sizeof(struct ubifs_info), GFP_KERNEL);
-       if (!c)
-               return -ENOMEM;
+       if (c) {
+               spin_lock_init(&c->cnt_lock);
+               spin_lock_init(&c->cs_lock);
+               spin_lock_init(&c->buds_lock);
+               spin_lock_init(&c->space_lock);
+               spin_lock_init(&c->orphan_lock);
+               init_rwsem(&c->commit_sem);
+               mutex_init(&c->lp_mutex);
+               mutex_init(&c->tnc_mutex);
+               mutex_init(&c->log_mutex);
+               mutex_init(&c->mst_mutex);
+               mutex_init(&c->umount_mutex);
+               mutex_init(&c->bu_mutex);
+               mutex_init(&c->write_reserve_mutex);
+               init_waitqueue_head(&c->cmt_wq);
+               c->buds = RB_ROOT;
+               c->old_idx = RB_ROOT;
+               c->size_tree = RB_ROOT;
+               c->orph_tree = RB_ROOT;
+               INIT_LIST_HEAD(&c->infos_list);
+               INIT_LIST_HEAD(&c->idx_gc);
+               INIT_LIST_HEAD(&c->replay_list);
+               INIT_LIST_HEAD(&c->replay_buds);
+               INIT_LIST_HEAD(&c->uncat_list);
+               INIT_LIST_HEAD(&c->empty_list);
+               INIT_LIST_HEAD(&c->freeable_list);
+               INIT_LIST_HEAD(&c->frdi_idx_list);
+               INIT_LIST_HEAD(&c->unclean_leb_list);
+               INIT_LIST_HEAD(&c->old_buds);
+               INIT_LIST_HEAD(&c->orph_list);
+               INIT_LIST_HEAD(&c->orph_new);
+               c->no_chk_data_crc = 1;
+
+               c->highest_inum = UBIFS_FIRST_INO;
+               c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM;
+
+               ubi_get_volume_info(ubi, &c->vi);
+               ubi_get_device_info(c->vi.ubi_num, &c->di);
+       }
+       return c;
+}
 
-       spin_lock_init(&c->cnt_lock);
-       spin_lock_init(&c->cs_lock);
-       spin_lock_init(&c->buds_lock);
-       spin_lock_init(&c->space_lock);
-       spin_lock_init(&c->orphan_lock);
-       init_rwsem(&c->commit_sem);
-       mutex_init(&c->lp_mutex);
-       mutex_init(&c->tnc_mutex);
-       mutex_init(&c->log_mutex);
-       mutex_init(&c->mst_mutex);
-       mutex_init(&c->umount_mutex);
-       mutex_init(&c->bu_mutex);
-       mutex_init(&c->write_reserve_mutex);
-       init_waitqueue_head(&c->cmt_wq);
-       c->buds = RB_ROOT;
-       c->old_idx = RB_ROOT;
-       c->size_tree = RB_ROOT;
-       c->orph_tree = RB_ROOT;
-       INIT_LIST_HEAD(&c->infos_list);
-       INIT_LIST_HEAD(&c->idx_gc);
-       INIT_LIST_HEAD(&c->replay_list);
-       INIT_LIST_HEAD(&c->replay_buds);
-       INIT_LIST_HEAD(&c->uncat_list);
-       INIT_LIST_HEAD(&c->empty_list);
-       INIT_LIST_HEAD(&c->freeable_list);
-       INIT_LIST_HEAD(&c->frdi_idx_list);
-       INIT_LIST_HEAD(&c->unclean_leb_list);
-       INIT_LIST_HEAD(&c->old_buds);
-       INIT_LIST_HEAD(&c->orph_list);
-       INIT_LIST_HEAD(&c->orph_new);
-       c->no_chk_data_crc = 1;
+static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
+{
+       struct ubifs_info *c = sb->s_fs_info;
+       struct inode *root;
+       int err;
 
        c->vfs_sb = sb;
-       c->highest_inum = UBIFS_FIRST_INO;
-       c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM;
-
-       ubi_get_volume_info(ubi, &c->vi);
-       ubi_get_device_info(c->vi.ubi_num, &c->di);
-
        /* Re-open the UBI device in read-write mode */
        c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READWRITE);
        if (IS_ERR(c->ubi)) {
                err = PTR_ERR(c->ubi);
-               goto out_free;
+               goto out;
        }
 
        /*
@@ -2071,24 +2094,29 @@ out_bdi:
        bdi_destroy(&c->bdi);
 out_close:
        ubi_close_volume(c->ubi);
-out_free:
-       kfree(c);
+out:
        return err;
 }
 
 static int sb_test(struct super_block *sb, void *data)
 {
-       dev_t *dev = data;
+       struct ubifs_info *c1 = data;
        struct ubifs_info *c = sb->s_fs_info;
 
-       return c->vi.cdev == *dev;
+       return c->vi.cdev == c1->vi.cdev;
+}
+
+static int sb_set(struct super_block *sb, void *data)
+{
+       sb->s_fs_info = data;
+       return set_anon_super(sb, NULL);
 }
 
 static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
                        const char *name, void *data)
 {
        struct ubi_volume_desc *ubi;
-       struct ubi_volume_info vi;
+       struct ubifs_info *c;
        struct super_block *sb;
        int err;
 
@@ -2105,19 +2133,25 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
                        name, (int)PTR_ERR(ubi));
                return ERR_CAST(ubi);
        }
-       ubi_get_volume_info(ubi, &vi);
 
-       dbg_gen("opened ubi%d_%d", vi.ubi_num, vi.vol_id);
+       c = alloc_ubifs_info(ubi);
+       if (!c) {
+               err = -ENOMEM;
+               goto out_close;
+       }
+
+       dbg_gen("opened ubi%d_%d", c->vi.ubi_num, c->vi.vol_id);
 
-       sb = sget(fs_type, &sb_test, &set_anon_super, &vi.cdev);
+       sb = sget(fs_type, sb_test, sb_set, c);
        if (IS_ERR(sb)) {
                err = PTR_ERR(sb);
+               kfree(c);
                goto out_close;
        }
 
        if (sb->s_root) {
                struct ubifs_info *c1 = sb->s_fs_info;
-
+               kfree(c);
                /* A new mount point for already mounted UBIFS */
                dbg_gen("this ubi volume is already mounted");
                if (!!(flags & MS_RDONLY) != c1->ro_mount) {
@@ -2126,11 +2160,6 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
                }
        } else {
                sb->s_flags = flags;
-               /*
-                * Pass 'ubi' to 'fill_super()' in sb->s_fs_info where it is
-                * replaced by 'c'.
-                */
-               sb->s_fs_info = ubi;
                err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
                if (err)
                        goto out_deact;
@@ -2150,11 +2179,18 @@ out_close:
        return ERR_PTR(err);
 }
 
+static void kill_ubifs_super(struct super_block *s)
+{
+       struct ubifs_info *c = s->s_fs_info;
+       kill_anon_super(s);
+       kfree(c);
+}
+
 static struct file_system_type ubifs_fs_type = {
        .name    = "ubifs",
        .owner   = THIS_MODULE,
        .mount   = ubifs_mount,
-       .kill_sb = kill_anon_super,
+       .kill_sb = kill_ubifs_super,
 };
 
 /*
index de485979ca393eebb7db3fb8c60d382b6857eabe..91b4213dde84d11934fc32741b2f902d76a1a84e 100644 (file)
@@ -2557,11 +2557,11 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
                if (err) {
                        /* Ensure the znode is dirtied */
                        if (znode->cnext || !ubifs_zn_dirty(znode)) {
-                                   znode = dirty_cow_bottom_up(c, znode);
-                                   if (IS_ERR(znode)) {
-                                           err = PTR_ERR(znode);
-                                           goto out_unlock;
-                                   }
+                               znode = dirty_cow_bottom_up(c, znode);
+                               if (IS_ERR(znode)) {
+                                       err = PTR_ERR(znode);
+                                       goto out_unlock;
+                               }
                        }
                        err = tnc_delete(c, znode, n);
                }
@@ -2876,12 +2876,13 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
  */
 void ubifs_tnc_close(struct ubifs_info *c)
 {
-       long clean_freed;
-
        tnc_destroy_cnext(c);
        if (c->zroot.znode) {
-               clean_freed = ubifs_destroy_tnc_subtree(c->zroot.znode);
-               atomic_long_sub(clean_freed, &ubifs_clean_zn_cnt);
+               long n;
+
+               ubifs_destroy_tnc_subtree(c->zroot.znode);
+               n = atomic_long_read(&c->clean_zn_cnt);
+               atomic_long_sub(n, &ubifs_clean_zn_cnt);
        }
        kfree(c->gap_lebs);
        kfree(c->ilebs);
index 53288e5d604e92bd5584b1a3595565261a1c2c81..41920f357bbfc13e49668ef19fd6a0560ca195fc 100644 (file)
@@ -377,15 +377,13 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt)
                                c->gap_lebs = NULL;
                                return err;
                        }
-                       if (!dbg_force_in_the_gaps_enabled) {
+                       if (dbg_force_in_the_gaps_enabled()) {
                                /*
                                 * Do not print scary warnings if the debugging
                                 * option which forces in-the-gaps is enabled.
                                 */
-                               ubifs_err("out of space");
-                               spin_lock(&c->space_lock);
-                               dbg_dump_budg(c);
-                               spin_unlock(&c->space_lock);
+                               ubifs_warn("out of space");
+                               dbg_dump_budg(c, &c->bi);
                                dbg_dump_lprops(c);
                        }
                        /* Try to commit anyway */
@@ -796,16 +794,16 @@ int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot)
        spin_lock(&c->space_lock);
        /*
         * Although we have not finished committing yet, update size of the
-        * committed index ('c->old_idx_sz') and zero out the index growth
+        * committed index ('c->bi.old_idx_sz') and zero out the index growth
         * budget. It is OK to do this now, because we've reserved all the
         * space which is needed to commit the index, and it is save for the
         * budgeting subsystem to assume the index is already committed,
         * even though it is not.
         */
-       ubifs_assert(c->min_idx_lebs == ubifs_calc_min_idx_lebs(c));
-       c->old_idx_sz = c->calc_idx_sz;
-       c->budg_uncommitted_idx = 0;
-       c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       ubifs_assert(c->bi.min_idx_lebs == ubifs_calc_min_idx_lebs(c));
+       c->bi.old_idx_sz = c->calc_idx_sz;
+       c->bi.uncommitted_idx = 0;
+       c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
        spin_unlock(&c->space_lock);
        mutex_unlock(&c->tnc_mutex);
 
index 191ca7863fe7a94bcca45ab2b2ba2ab6dae74e7b..e24380cf46ed4b0506dcc2f2e9258f04e4367a28 100644 (file)
@@ -408,9 +408,11 @@ enum {
  * Superblock flags.
  *
  * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set
+ * UBIFS_FLG_SPACE_FIXUP: first-mount "fixup" of free space within LEBs needed
  */
 enum {
        UBIFS_FLG_BIGLPT = 0x02,
+       UBIFS_FLG_SPACE_FIXUP = 0x04,
 };
 
 /**
@@ -434,7 +436,7 @@ struct ubifs_ch {
        __u8 node_type;
        __u8 group_type;
        __u8 padding[2];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * union ubifs_dev_desc - device node descriptor.
@@ -448,7 +450,7 @@ struct ubifs_ch {
 union ubifs_dev_desc {
        __le32 new;
        __le64 huge;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_ino_node - inode node.
@@ -509,7 +511,7 @@ struct ubifs_ino_node {
        __le16 compr_type;
        __u8 padding2[26]; /* Watch 'zero_ino_node_unused()' if changing! */
        __u8 data[];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_dent_node - directory entry node.
@@ -534,7 +536,7 @@ struct ubifs_dent_node {
        __le16 nlen;
        __u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */
        __u8 name[];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_data_node - data node.
@@ -555,7 +557,7 @@ struct ubifs_data_node {
        __le16 compr_type;
        __u8 padding[2]; /* Watch 'zero_data_node_unused()' if changing! */
        __u8 data[];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_trun_node - truncation node.
@@ -575,7 +577,7 @@ struct ubifs_trun_node {
        __u8 padding[12]; /* Watch 'zero_trun_node_unused()' if changing! */
        __le64 old_size;
        __le64 new_size;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_pad_node - padding node.
@@ -586,7 +588,7 @@ struct ubifs_trun_node {
 struct ubifs_pad_node {
        struct ubifs_ch ch;
        __le32 pad_len;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_sb_node - superblock node.
@@ -644,7 +646,7 @@ struct ubifs_sb_node {
        __u8 uuid[16];
        __le32 ro_compat_version;
        __u8 padding2[3968];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_mst_node - master node.
@@ -711,7 +713,7 @@ struct ubifs_mst_node {
        __le32 idx_lebs;
        __le32 leb_cnt;
        __u8 padding[344];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_ref_node - logical eraseblock reference node.
@@ -727,7 +729,7 @@ struct ubifs_ref_node {
        __le32 offs;
        __le32 jhead;
        __u8 padding[28];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_branch - key/reference/length branch
@@ -741,7 +743,7 @@ struct ubifs_branch {
        __le32 offs;
        __le32 len;
        __u8 key[];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_idx_node - indexing node.
@@ -755,7 +757,7 @@ struct ubifs_idx_node {
        __le16 child_cnt;
        __le16 level;
        __u8 branches[];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_cs_node - commit start node.
@@ -765,7 +767,7 @@ struct ubifs_idx_node {
 struct ubifs_cs_node {
        struct ubifs_ch ch;
        __le64 cmt_no;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_orph_node - orphan node.
@@ -777,6 +779,6 @@ struct ubifs_orph_node {
        struct ubifs_ch ch;
        __le64 cmt_no;
        __le64 inos[];
-} __attribute__ ((packed));
+} __packed;
 
 #endif /* __UBIFS_MEDIA_H__ */
index 8c40ad3c67213375c6d9b99927851f51fabd18d1..f79983d6f860eb43ec766dab9b6b044f1e23dd7b 100644 (file)
@@ -389,9 +389,9 @@ struct ubifs_gced_idx_leb {
  * The @ui_size is a "shadow" variable for @inode->i_size and UBIFS uses
  * @ui_size instead of @inode->i_size. The reason for this is that UBIFS cannot
  * make sure @inode->i_size is always changed under @ui_mutex, because it
- * cannot call 'truncate_setsize()' with @ui_mutex locked, because it would deadlock
- * with 'ubifs_writepage()' (see file.c). All the other inode fields are
- * changed under @ui_mutex, so they do not need "shadow" fields. Note, one
+ * cannot call 'truncate_setsize()' with @ui_mutex locked, because it would
+ * deadlock with 'ubifs_writepage()' (see file.c). All the other inode fields
+ * are changed under @ui_mutex, so they do not need "shadow" fields. Note, one
  * could consider to rework locking and base it on "shadow" fields.
  */
 struct ubifs_inode {
@@ -722,12 +722,14 @@ struct ubifs_bud {
  * struct ubifs_jhead - journal head.
  * @wbuf: head's write-buffer
  * @buds_list: list of bud LEBs belonging to this journal head
+ * @grouped: non-zero if UBIFS groups nodes when writing to this journal head
  *
  * Note, the @buds list is protected by the @c->buds_lock.
  */
 struct ubifs_jhead {
        struct ubifs_wbuf wbuf;
        struct list_head buds_list;
+       unsigned int grouped:1;
 };
 
 /**
@@ -937,6 +939,40 @@ struct ubifs_mount_opts {
        unsigned int compr_type:2;
 };
 
+/**
+ * struct ubifs_budg_info - UBIFS budgeting information.
+ * @idx_growth: amount of bytes budgeted for index growth
+ * @data_growth: amount of bytes budgeted for cached data
+ * @dd_growth: amount of bytes budgeted for cached data that will make
+ *             other data dirty
+ * @uncommitted_idx: amount of bytes were budgeted for growth of the index, but
+ *                   which still have to be taken into account because the index
+ *                   has not been committed so far
+ * @old_idx_sz: size of index on flash
+ * @min_idx_lebs: minimum number of LEBs required for the index
+ * @nospace: non-zero if the file-system does not have flash space (used as
+ *           optimization)
+ * @nospace_rp: the same as @nospace, but additionally means that even reserved
+ *              pool is full
+ * @page_budget: budget for a page (constant, nenver changed after mount)
+ * @inode_budget: budget for an inode (constant, nenver changed after mount)
+ * @dent_budget: budget for a directory entry (constant, nenver changed after
+ *               mount)
+ */
+struct ubifs_budg_info {
+       long long idx_growth;
+       long long data_growth;
+       long long dd_growth;
+       long long uncommitted_idx;
+       unsigned long long old_idx_sz;
+       int min_idx_lebs;
+       unsigned int nospace:1;
+       unsigned int nospace_rp:1;
+       int page_budget;
+       int inode_budget;
+       int dent_budget;
+};
+
 struct ubifs_debug_info;
 
 /**
@@ -980,6 +1016,7 @@ struct ubifs_debug_info;
  * @cmt_wq: wait queue to sleep on if the log is full and a commit is running
  *
  * @big_lpt: flag that LPT is too big to write whole during commit
+ * @space_fixup: flag indicating that free space in LEBs needs to be cleaned up
  * @no_chk_data_crc: do not check CRCs when reading data nodes (except during
  *                   recovery)
  * @bulk_read: enable bulk-reads
@@ -1057,32 +1094,14 @@ struct ubifs_debug_info;
  * @dirty_zn_cnt: number of dirty znodes
  * @clean_zn_cnt: number of clean znodes
  *
- * @budg_idx_growth: amount of bytes budgeted for index growth
- * @budg_data_growth: amount of bytes budgeted for cached data
- * @budg_dd_growth: amount of bytes budgeted for cached data that will make
- *                  other data dirty
- * @budg_uncommitted_idx: amount of bytes were budgeted for growth of the index,
- *                        but which still have to be taken into account because
- *                        the index has not been committed so far
- * @space_lock: protects @budg_idx_growth, @budg_data_growth, @budg_dd_growth,
- *              @budg_uncommited_idx, @min_idx_lebs, @old_idx_sz, @lst,
- *              @nospace, and @nospace_rp;
- * @min_idx_lebs: minimum number of LEBs required for the index
- * @old_idx_sz: size of index on flash
+ * @space_lock: protects @bi and @lst
+ * @lst: lprops statistics
+ * @bi: budgeting information
  * @calc_idx_sz: temporary variable which is used to calculate new index size
  *               (contains accurate new index size at end of TNC commit start)
- * @lst: lprops statistics
- * @nospace: non-zero if the file-system does not have flash space (used as
- *           optimization)
- * @nospace_rp: the same as @nospace, but additionally means that even reserved
- *              pool is full
- *
- * @page_budget: budget for a page
- * @inode_budget: budget for an inode
- * @dent_budget: budget for a directory entry
  *
  * @ref_node_alsz: size of the LEB reference node aligned to the min. flash
- * I/O unit
+ *                 I/O unit
  * @mst_node_alsz: master node aligned size
  * @min_idx_node_sz: minimum indexing node aligned on 8-bytes boundary
  * @max_idx_node_sz: maximum indexing node aligned on 8-bytes boundary
@@ -1189,7 +1208,6 @@ struct ubifs_debug_info;
  * @replaying: %1 during journal replay
  * @mounting: %1 while mounting
  * @remounting_rw: %1 while re-mounting from R/O mode to R/W mode
- * @replay_tree: temporary tree used during journal replay
  * @replay_list: temporary list used during journal replay
  * @replay_buds: list of buds to replay
  * @cs_sqnum: sequence number of first node in the log (commit start node)
@@ -1238,6 +1256,7 @@ struct ubifs_info {
        wait_queue_head_t cmt_wq;
 
        unsigned int big_lpt:1;
+       unsigned int space_fixup:1;
        unsigned int no_chk_data_crc:1;
        unsigned int bulk_read:1;
        unsigned int default_compr:2;
@@ -1308,21 +1327,10 @@ struct ubifs_info {
        atomic_long_t dirty_zn_cnt;
        atomic_long_t clean_zn_cnt;
 
-       long long budg_idx_growth;
-       long long budg_data_growth;
-       long long budg_dd_growth;
-       long long budg_uncommitted_idx;
        spinlock_t space_lock;
-       int min_idx_lebs;
-       unsigned long long old_idx_sz;
-       unsigned long long calc_idx_sz;
        struct ubifs_lp_stats lst;
-       unsigned int nospace:1;
-       unsigned int nospace_rp:1;
-
-       int page_budget;
-       int inode_budget;
-       int dent_budget;
+       struct ubifs_budg_info bi;
+       unsigned long long calc_idx_sz;
 
        int ref_node_alsz;
        int mst_node_alsz;
@@ -1430,7 +1438,6 @@ struct ubifs_info {
        unsigned int replaying:1;
        unsigned int mounting:1;
        unsigned int remounting_rw:1;
-       struct rb_root replay_tree;
        struct list_head replay_list;
        struct list_head replay_buds;
        unsigned long long cs_sqnum;
@@ -1609,7 +1616,7 @@ int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot);
 int ubifs_tnc_end_commit(struct ubifs_info *c);
 
 /* shrinker.c */
-int ubifs_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask);
+int ubifs_shrinker(struct shrinker *shrink, struct shrink_control *sc);
 
 /* commit.c */
 int ubifs_bg_thread(void *info);
@@ -1628,6 +1635,7 @@ int ubifs_write_master(struct ubifs_info *c);
 int ubifs_read_superblock(struct ubifs_info *c);
 struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c);
 int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup);
+int ubifs_fixup_free_space(struct ubifs_info *c);
 
 /* replay.c */
 int ubifs_validate_entry(struct ubifs_info *c,
@@ -1736,7 +1744,7 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
 int ubifs_recover_master_node(struct ubifs_info *c);
 int ubifs_write_rcvrd_mst_node(struct ubifs_info *c);
 struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
-                                        int offs, void *sbuf, int grouped);
+                                        int offs, void *sbuf, int jhead);
 struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
                                             int offs, void *sbuf);
 int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf);
index 3299f469e7126a004d2b3a37c5c2661b3c6a127d..16f19f55e63fa53e20dcc2cf520794b27b1290a7 100644 (file)
@@ -80,8 +80,8 @@ enum {
        SECURITY_XATTR,
 };
 
-static const struct inode_operations none_inode_operations;
-static const struct file_operations none_file_operations;
+static const struct inode_operations empty_iops;
+static const struct file_operations empty_fops;
 
 /**
  * create_xattr - create an extended attribute.
@@ -131,8 +131,8 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
 
        /* Re-define all operations to be "nothing" */
        inode->i_mapping->a_ops = &empty_aops;
-       inode->i_op = &none_inode_operations;
-       inode->i_fop = &none_file_operations;
+       inode->i_op = &empty_iops;
+       inode->i_fop = &empty_fops;
 
        inode->i_flags |= S_SYNC | S_NOATIME | S_NOCMTIME | S_NOQUOTA;
        ui = ubifs_inode(inode);
index 46f7a807bbc1ec8313af3df1a4c08c2afb3498eb..42694e11c23de46b25f1177888b97ec2aac1cf32 100644 (file)
@@ -424,8 +424,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment,
                        ufs_cpu_to_data_ptr(sb, p, result);
                        *err = 0;
                        UFS_I(inode)->i_lastfrag =
-                               max_t(u32, UFS_I(inode)->i_lastfrag,
-                                     fragment + count);
+                               max(UFS_I(inode)->i_lastfrag, fragment + count);
                        ufs_clear_frags(inode, result + oldcount,
                                        newcount - oldcount, locked_page != NULL);
                }
@@ -440,7 +439,8 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment,
        result = ufs_add_fragments (inode, tmp, oldcount, newcount, err);
        if (result) {
                *err = 0;
-               UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
+               UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag,
+                                               fragment + count);
                ufs_clear_frags(inode, result + oldcount, newcount - oldcount,
                                locked_page != NULL);
                unlock_super(sb);
@@ -479,7 +479,8 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment,
                                   uspi->s_sbbase + result, locked_page);
                ufs_cpu_to_data_ptr(sb, p, result);
                *err = 0;
-               UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
+               UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag,
+                                               fragment + count);
                unlock_super(sb);
                if (newcount < request)
                        ufs_free_fragments (inode, result + newcount, request - newcount);
index 5f821dbc057905c379df686dfbb2f2ff67609c9a..f04f89fbd4d9914b0a1a16f2cce8c8e0799e020e 100644 (file)
@@ -84,7 +84,7 @@ static int ufs_trunc_direct(struct inode *inode)
        retry = 0;
        
        frag1 = DIRECT_FRAGMENT;
-       frag4 = min_t(u32, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag);
+       frag4 = min_t(u64, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag);
        frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1);
        frag3 = frag4 & ~uspi->s_fpbmask;
        block1 = block2 = 0;
index f1ef94974dea12f10beceff4a12899851ba7aeab..f060663ab70c2b2c602aa7a7f4f8a343f621f5e4 100644 (file)
@@ -46,18 +46,22 @@ xattr_permission(struct inode *inode, const char *name, int mask)
                return 0;
 
        /*
-        * The trusted.* namespace can only be accessed by a privileged user.
+        * The trusted.* namespace can only be accessed by privileged users.
         */
-       if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
-               return (capable(CAP_SYS_ADMIN) ? 0 : -EPERM);
+       if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) {
+               if (!capable(CAP_SYS_ADMIN))
+                       return (mask & MAY_WRITE) ? -EPERM : -ENODATA;
+               return 0;
+       }
 
-       /* In user.* namespace, only regular files and directories can have
+       /*
+        * In the user.* namespace, only regular files and directories can have
         * extended attributes. For sticky directories, only the owner and
-        * privileged user can write attributes.
+        * privileged users can write attributes.
         */
        if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
                if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
-                       return -EPERM;
+                       return (mask & MAY_WRITE) ? -EPERM : -ENODATA;
                if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
                    (mask & MAY_WRITE) && !inode_owner_or_capable(inode))
                        return -EPERM;
@@ -87,7 +91,11 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
 {
        struct inode *inode = dentry->d_inode;
        int error = -EOPNOTSUPP;
+       int issec = !strncmp(name, XATTR_SECURITY_PREFIX,
+                                  XATTR_SECURITY_PREFIX_LEN);
 
+       if (issec)
+               inode->i_flags &= ~S_NOSEC;
        if (inode->i_op->setxattr) {
                error = inode->i_op->setxattr(dentry, name, value, size, flags);
                if (!error) {
@@ -95,8 +103,7 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
                        security_inode_post_setxattr(dentry, name, value,
                                                     size, flags);
                }
-       } else if (!strncmp(name, XATTR_SECURITY_PREFIX,
-                               XATTR_SECURITY_PREFIX_LEN)) {
+       } else if (issec) {
                const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
                error = security_inode_setsecurity(inode, suffix, value,
                                                   size, flags);
index 52b2b5da566e7ff801adda6b7c2f57147f39fc80..5e68099db2a5fdc97a284031e06a7f70fcea27cb 100644 (file)
@@ -1422,12 +1422,12 @@ restart:
 int
 xfs_buftarg_shrink(
        struct shrinker         *shrink,
-       int                     nr_to_scan,
-       gfp_t                   mask)
+       struct shrink_control   *sc)
 {
        struct xfs_buftarg      *btp = container_of(shrink,
                                        struct xfs_buftarg, bt_shrinker);
        struct xfs_buf          *bp;
+       int nr_to_scan = sc->nr_to_scan;
        LIST_HEAD(dispose);
 
        if (!nr_to_scan)
index d61611c88012c8daaab1840f9534983fac62bd2d..244e797dae327a7da95992e23697489397c4bbc1 100644 (file)
@@ -191,3 +191,32 @@ xfs_ioc_trim(
                return -XFS_ERROR(EFAULT);
        return 0;
 }
+
+int
+xfs_discard_extents(
+       struct xfs_mount        *mp,
+       struct list_head        *list)
+{
+       struct xfs_busy_extent  *busyp;
+       int                     error = 0;
+
+       list_for_each_entry(busyp, list, list) {
+               trace_xfs_discard_extent(mp, busyp->agno, busyp->bno,
+                                        busyp->length);
+
+               error = -blkdev_issue_discard(mp->m_ddev_targp->bt_bdev,
+                               XFS_AGB_TO_DADDR(mp, busyp->agno, busyp->bno),
+                               XFS_FSB_TO_BB(mp, busyp->length),
+                               GFP_NOFS, 0);
+               if (error && error != EOPNOTSUPP) {
+                       xfs_info(mp,
+        "discard failed for extent [0x%llu,%u], error %d",
+                                (unsigned long long)busyp->bno,
+                                busyp->length,
+                                error);
+                       return error;
+               }
+       }
+
+       return 0;
+}
index e82b6dd3e127707ed0a8e154ab1617da23444a90..344879aea646cfbaf3ac1c57916f9fce5e6a50c2 100644 (file)
@@ -2,7 +2,9 @@
 #define XFS_DISCARD_H 1
 
 struct fstrim_range;
+struct list_head;
 
 extern int     xfs_ioc_trim(struct xfs_mount *, struct fstrim_range __user *);
+extern int     xfs_discard_extents(struct xfs_mount *, struct list_head *);
 
 #endif /* XFS_DISCARD_H */
index f4213ba1ff853dad53d16d27b6cd713f01784ea7..7f782af286bfa0edd73a125cdcb892339025913a 100644 (file)
@@ -131,19 +131,34 @@ xfs_file_fsync(
 {
        struct inode            *inode = file->f_mapping->host;
        struct xfs_inode        *ip = XFS_I(inode);
+       struct xfs_mount        *mp = ip->i_mount;
        struct xfs_trans        *tp;
        int                     error = 0;
        int                     log_flushed = 0;
 
        trace_xfs_file_fsync(ip);
 
-       if (XFS_FORCED_SHUTDOWN(ip->i_mount))
+       if (XFS_FORCED_SHUTDOWN(mp))
                return -XFS_ERROR(EIO);
 
        xfs_iflags_clear(ip, XFS_ITRUNCATED);
 
        xfs_ioend_wait(ip);
 
+       if (mp->m_flags & XFS_MOUNT_BARRIER) {
+               /*
+                * If we have an RT and/or log subvolume we need to make sure
+                * to flush the write cache the device used for file data
+                * first.  This is to ensure newly written file data make
+                * it to disk before logging the new inode size in case of
+                * an extending write.
+                */
+               if (XFS_IS_REALTIME_INODE(ip))
+                       xfs_blkdev_issue_flush(mp->m_rtdev_targp);
+               else if (mp->m_logdev_targp != mp->m_ddev_targp)
+                       xfs_blkdev_issue_flush(mp->m_ddev_targp);
+       }
+
        /*
         * We always need to make sure that the required inode state is safe on
         * disk.  The inode might be clean but we still might need to force the
@@ -175,9 +190,9 @@ xfs_file_fsync(
                 * updates.  The sync transaction will also force the log.
                 */
                xfs_iunlock(ip, XFS_ILOCK_SHARED);
-               tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_FSYNC_TS);
+               tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
                error = xfs_trans_reserve(tp, 0,
-                               XFS_FSYNC_TS_LOG_RES(ip->i_mount), 0, 0, 0);
+                               XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
                if (error) {
                        xfs_trans_cancel(tp, 0);
                        return -error;
@@ -209,28 +224,25 @@ xfs_file_fsync(
                 * force the log.
                 */
                if (xfs_ipincount(ip)) {
-                       error = _xfs_log_force_lsn(ip->i_mount,
+                       error = _xfs_log_force_lsn(mp,
                                        ip->i_itemp->ili_last_lsn,
                                        XFS_LOG_SYNC, &log_flushed);
                }
                xfs_iunlock(ip, XFS_ILOCK_SHARED);
        }
 
-       if (ip->i_mount->m_flags & XFS_MOUNT_BARRIER) {
-               /*
-                * If the log write didn't issue an ordered tag we need
-                * to flush the disk cache for the data device now.
-                */
-               if (!log_flushed)
-                       xfs_blkdev_issue_flush(ip->i_mount->m_ddev_targp);
-
-               /*
-                * If this inode is on the RT dev we need to flush that
-                * cache as well.
-                */
-               if (XFS_IS_REALTIME_INODE(ip))
-                       xfs_blkdev_issue_flush(ip->i_mount->m_rtdev_targp);
-       }
+       /*
+        * If we only have a single device, and the log force about was
+        * a no-op we might have to flush the data device cache here.
+        * This can only happen for fdatasync/O_DSYNC if we were overwriting
+        * an already allocated file and thus do not have any metadata to
+        * commit.
+        */
+       if ((mp->m_flags & XFS_MOUNT_BARRIER) &&
+           mp->m_logdev_targp == mp->m_ddev_targp &&
+           !XFS_IS_REALTIME_INODE(ip) &&
+           !log_flushed)
+               xfs_blkdev_issue_flush(mp->m_ddev_targp);
 
        return -error;
 }
index dd21784525a8096ef76f6d6cd14c80a319918839..d44d92cd12b17c7645156b4754c39ea29b5b10e5 100644 (file)
@@ -182,7 +182,7 @@ xfs_vn_mknod(
        if (IS_POSIXACL(dir)) {
                default_acl = xfs_get_acl(dir, ACL_TYPE_DEFAULT);
                if (IS_ERR(default_acl))
-                       return -PTR_ERR(default_acl);
+                       return PTR_ERR(default_acl);
 
                if (!default_acl)
                        mode &= ~current_umask();
index b0aa59e51fd066377d29f92da999dff54b1a1620..a1a881e68a9aa86a1aa76c27931e02202a57a08d 100644 (file)
@@ -110,8 +110,10 @@ mempool_t *xfs_ioend_pool;
 #define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */
 #define MNTOPT_PQUOTANOENF "pqnoenforce"/* project quota limit enforcement */
 #define MNTOPT_QUOTANOENF  "qnoenforce"        /* same as uqnoenforce */
-#define MNTOPT_DELAYLOG   "delaylog"   /* Delayed loging enabled */
-#define MNTOPT_NODELAYLOG "nodelaylog" /* Delayed loging disabled */
+#define MNTOPT_DELAYLOG    "delaylog"  /* Delayed logging enabled */
+#define MNTOPT_NODELAYLOG  "nodelaylog"        /* Delayed logging disabled */
+#define MNTOPT_DISCARD    "discard"    /* Discard unused blocks */
+#define MNTOPT_NODISCARD   "nodiscard" /* Do not discard unused blocks */
 
 /*
  * Table driven mount option parser.
@@ -355,6 +357,10 @@ xfs_parseargs(
                        mp->m_flags |= XFS_MOUNT_DELAYLOG;
                } else if (!strcmp(this_char, MNTOPT_NODELAYLOG)) {
                        mp->m_flags &= ~XFS_MOUNT_DELAYLOG;
+               } else if (!strcmp(this_char, MNTOPT_DISCARD)) {
+                       mp->m_flags |= XFS_MOUNT_DISCARD;
+               } else if (!strcmp(this_char, MNTOPT_NODISCARD)) {
+                       mp->m_flags &= ~XFS_MOUNT_DISCARD;
                } else if (!strcmp(this_char, "ihashsize")) {
                        xfs_warn(mp,
        "ihashsize no longer used, option is deprecated.");
@@ -388,6 +394,13 @@ xfs_parseargs(
                return EINVAL;
        }
 
+       if ((mp->m_flags & XFS_MOUNT_DISCARD) &&
+           !(mp->m_flags & XFS_MOUNT_DELAYLOG)) {
+               xfs_warn(mp,
+       "the discard option is incompatible with the nodelaylog option");
+               return EINVAL;
+       }
+
 #ifndef CONFIG_XFS_QUOTA
        if (XFS_IS_QUOTA_RUNNING(mp)) {
                xfs_warn(mp, "quota support not available in this kernel.");
@@ -488,6 +501,7 @@ xfs_showargs(
                { XFS_MOUNT_FILESTREAMS,        "," MNTOPT_FILESTREAM },
                { XFS_MOUNT_GRPID,              "," MNTOPT_GRPID },
                { XFS_MOUNT_DELAYLOG,           "," MNTOPT_DELAYLOG },
+               { XFS_MOUNT_DISCARD,            "," MNTOPT_DISCARD },
                { 0, NULL }
        };
        static struct proc_xfs_info xfs_info_unset[] = {
@@ -613,68 +627,6 @@ xfs_blkdev_put(
                blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
 }
 
-/*
- * Try to write out the superblock using barriers.
- */
-STATIC int
-xfs_barrier_test(
-       xfs_mount_t     *mp)
-{
-       xfs_buf_t       *sbp = xfs_getsb(mp, 0);
-       int             error;
-
-       XFS_BUF_UNDONE(sbp);
-       XFS_BUF_UNREAD(sbp);
-       XFS_BUF_UNDELAYWRITE(sbp);
-       XFS_BUF_WRITE(sbp);
-       XFS_BUF_UNASYNC(sbp);
-       XFS_BUF_ORDERED(sbp);
-
-       xfsbdstrat(mp, sbp);
-       error = xfs_buf_iowait(sbp);
-
-       /*
-        * Clear all the flags we set and possible error state in the
-        * buffer.  We only did the write to try out whether barriers
-        * worked and shouldn't leave any traces in the superblock
-        * buffer.
-        */
-       XFS_BUF_DONE(sbp);
-       XFS_BUF_ERROR(sbp, 0);
-       XFS_BUF_UNORDERED(sbp);
-
-       xfs_buf_relse(sbp);
-       return error;
-}
-
-STATIC void
-xfs_mountfs_check_barriers(xfs_mount_t *mp)
-{
-       int error;
-
-       if (mp->m_logdev_targp != mp->m_ddev_targp) {
-               xfs_notice(mp,
-                 "Disabling barriers, not supported with external log device");
-               mp->m_flags &= ~XFS_MOUNT_BARRIER;
-               return;
-       }
-
-       if (xfs_readonly_buftarg(mp->m_ddev_targp)) {
-               xfs_notice(mp,
-                       "Disabling barriers, underlying device is readonly");
-               mp->m_flags &= ~XFS_MOUNT_BARRIER;
-               return;
-       }
-
-       error = xfs_barrier_test(mp);
-       if (error) {
-               xfs_notice(mp,
-                       "Disabling barriers, trial barrier write failed");
-               mp->m_flags &= ~XFS_MOUNT_BARRIER;
-               return;
-       }
-}
-
 void
 xfs_blkdev_issue_flush(
        xfs_buftarg_t           *buftarg)
@@ -911,7 +863,8 @@ xfs_fs_inode_init_once(
  */
 STATIC void
 xfs_fs_dirty_inode(
-       struct inode    *inode)
+       struct inode    *inode,
+       int             flags)
 {
        barrier();
        XFS_I(inode)->i_update_core = 1;
@@ -1225,14 +1178,6 @@ xfs_fs_remount(
                switch (token) {
                case Opt_barrier:
                        mp->m_flags |= XFS_MOUNT_BARRIER;
-
-                       /*
-                        * Test if barriers are actually working if we can,
-                        * else delay this check until the filesystem is
-                        * marked writeable.
-                        */
-                       if (!(mp->m_flags & XFS_MOUNT_RDONLY))
-                               xfs_mountfs_check_barriers(mp);
                        break;
                case Opt_nobarrier:
                        mp->m_flags &= ~XFS_MOUNT_BARRIER;
@@ -1267,8 +1212,6 @@ xfs_fs_remount(
        /* ro -> rw */
        if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(*flags & MS_RDONLY)) {
                mp->m_flags &= ~XFS_MOUNT_RDONLY;
-               if (mp->m_flags & XFS_MOUNT_BARRIER)
-                       xfs_mountfs_check_barriers(mp);
 
                /*
                 * If this is the first remount to writeable state we
@@ -1450,9 +1393,6 @@ xfs_fs_fill_super(
        if (error)
                goto out_free_sb;
 
-       if (mp->m_flags & XFS_MOUNT_BARRIER)
-               xfs_mountfs_check_barriers(mp);
-
        error = xfs_filestream_mount(mp);
        if (error)
                goto out_free_sb;
index cb1bb2080e44b7d3acc2803a275c290894fd3245..8ecad5ff9f9b0e0bdb5a4f76dd97b694147a5a55 100644 (file)
@@ -1032,13 +1032,14 @@ xfs_reclaim_inodes(
 static int
 xfs_reclaim_inode_shrink(
        struct shrinker *shrink,
-       int             nr_to_scan,
-       gfp_t           gfp_mask)
+       struct shrink_control *sc)
 {
        struct xfs_mount *mp;
        struct xfs_perag *pag;
        xfs_agnumber_t  ag;
        int             reclaimable;
+       int nr_to_scan = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
 
        mp = container_of(shrink, struct xfs_mount, m_inode_shrink);
        if (nr_to_scan) {
index 69228aa8605a9f6e07d1f66845c0e4c0c7beff2c..b94dace4e7852333274cd3ca42f633aca98d33f9 100644 (file)
@@ -60,7 +60,7 @@ STATIC void   xfs_qm_list_destroy(xfs_dqlist_t *);
 
 STATIC int     xfs_qm_init_quotainos(xfs_mount_t *);
 STATIC int     xfs_qm_init_quotainfo(xfs_mount_t *);
-STATIC int     xfs_qm_shake(struct shrinker *, int, gfp_t);
+STATIC int     xfs_qm_shake(struct shrinker *, struct shrink_control *);
 
 static struct shrinker xfs_qm_shaker = {
        .shrink = xfs_qm_shake,
@@ -2009,10 +2009,10 @@ xfs_qm_shake_freelist(
 STATIC int
 xfs_qm_shake(
        struct shrinker *shrink,
-       int             nr_to_scan,
-       gfp_t           gfp_mask)
+       struct shrink_control *sc)
 {
        int     ndqused, nfree, n;
+       gfp_t gfp_mask = sc->gfp_mask;
 
        if (!kmem_shake_allow(gfp_mask))
                return 0;
index da0a561ffba2abc2ed277992f21f44c1a38dbc54..6530769a999bdb045ba4ec5d1588440a04993e1c 100644 (file)
@@ -187,6 +187,9 @@ struct xfs_busy_extent {
        xfs_agnumber_t  agno;
        xfs_agblock_t   bno;
        xfs_extlen_t    length;
+       unsigned int    flags;
+#define XFS_ALLOC_BUSY_DISCARDED       0x01    /* undergoing a discard op. */
+#define XFS_ALLOC_BUSY_SKIP_DISCARD    0x02    /* do not discard */
 };
 
 /*
index acdced86413ce0d90e5fb07ac7ea08005727a2e4..95862bbff56bf0cf8c82d4e88178dc43408866d7 100644 (file)
@@ -2469,7 +2469,7 @@ xfs_free_extent(
 
        error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0);
        if (!error)
-               xfs_alloc_busy_insert(tp, args.agno, args.agbno, len);
+               xfs_alloc_busy_insert(tp, args.agno, args.agbno, len, 0);
 error0:
        xfs_perag_put(args.pag);
        return error;
@@ -2480,7 +2480,8 @@ xfs_alloc_busy_insert(
        struct xfs_trans        *tp,
        xfs_agnumber_t          agno,
        xfs_agblock_t           bno,
-       xfs_extlen_t            len)
+       xfs_extlen_t            len,
+       unsigned int            flags)
 {
        struct xfs_busy_extent  *new;
        struct xfs_busy_extent  *busyp;
@@ -2504,6 +2505,7 @@ xfs_alloc_busy_insert(
        new->bno = bno;
        new->length = len;
        INIT_LIST_HEAD(&new->list);
+       new->flags = flags;
 
        /* trace before insert to be able to see failed inserts */
        trace_xfs_alloc_busy(tp->t_mountp, agno, bno, len);
@@ -2608,6 +2610,18 @@ xfs_alloc_busy_update_extent(
        xfs_agblock_t           bbno = busyp->bno;
        xfs_agblock_t           bend = bbno + busyp->length;
 
+       /*
+        * This extent is currently being discarded.  Give the thread
+        * performing the discard a chance to mark the extent unbusy
+        * and retry.
+        */
+       if (busyp->flags & XFS_ALLOC_BUSY_DISCARDED) {
+               spin_unlock(&pag->pagb_lock);
+               delay(1);
+               spin_lock(&pag->pagb_lock);
+               return false;
+       }
+
        /*
         * If there is a busy extent overlapping a user allocation, we have
         * no choice but to force the log and retry the search.
@@ -2813,7 +2827,8 @@ restart:
                 * If this is a metadata allocation, try to reuse the busy
                 * extent instead of trimming the allocation.
                 */
-               if (!args->userdata) {
+               if (!args->userdata &&
+                   !(busyp->flags & XFS_ALLOC_BUSY_DISCARDED)) {
                        if (!xfs_alloc_busy_update_extent(args->mp, args->pag,
                                                          busyp, fbno, flen,
                                                          false))
@@ -2979,10 +2994,16 @@ xfs_alloc_busy_clear_one(
        kmem_free(busyp);
 }
 
+/*
+ * Remove all extents on the passed in list from the busy extents tree.
+ * If do_discard is set skip extents that need to be discarded, and mark
+ * these as undergoing a discard operation instead.
+ */
 void
 xfs_alloc_busy_clear(
        struct xfs_mount        *mp,
-       struct list_head        *list)
+       struct list_head        *list,
+       bool                    do_discard)
 {
        struct xfs_busy_extent  *busyp, *n;
        struct xfs_perag        *pag = NULL;
@@ -2999,7 +3020,11 @@ xfs_alloc_busy_clear(
                        agno = busyp->agno;
                }
 
-               xfs_alloc_busy_clear_one(mp, pag, busyp);
+               if (do_discard && busyp->length &&
+                   !(busyp->flags & XFS_ALLOC_BUSY_SKIP_DISCARD))
+                       busyp->flags = XFS_ALLOC_BUSY_DISCARDED;
+               else
+                       xfs_alloc_busy_clear_one(mp, pag, busyp);
        }
 
        if (pag) {
index 240ad288f2f99d7b6805591460846ce6a4c905b8..2f52b924be79f424b0a3115849af602f719a6b79 100644 (file)
@@ -137,10 +137,11 @@ xfs_alloc_longest_free_extent(struct xfs_mount *mp,
 #ifdef __KERNEL__
 void
 xfs_alloc_busy_insert(struct xfs_trans *tp, xfs_agnumber_t agno,
-       xfs_agblock_t bno, xfs_extlen_t len);
+       xfs_agblock_t bno, xfs_extlen_t len, unsigned int flags);
 
 void
-xfs_alloc_busy_clear(struct xfs_mount *mp, struct list_head *list);
+xfs_alloc_busy_clear(struct xfs_mount *mp, struct list_head *list,
+       bool do_discard);
 
 int
 xfs_alloc_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno,
index 8b469d53599fb4b35cd0851a0baef7e916787969..2b3518826a692640c46e3e4fb5f5192e418e868b 100644 (file)
@@ -120,7 +120,8 @@ xfs_allocbt_free_block(
        if (error)
                return error;
 
-       xfs_alloc_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1);
+       xfs_alloc_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1,
+                             XFS_ALLOC_BUSY_SKIP_DISCARD);
        xfs_trans_agbtree_delta(cur->bc_tp, -1);
        return 0;
 }
index c8637537881082a58fb30efbb56abef66d2b26f4..01d2072fb6d4580ca6ceb7f77a20eed67c94cf1c 100644 (file)
@@ -489,6 +489,13 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
        args.total = 0;
        args.whichfork = XFS_ATTR_FORK;
 
+       /*
+        * we have no control over the attribute names that userspace passes us
+        * to remove, so we have to allow the name lookup prior to attribute
+        * removal to fail.
+        */
+       args.op_flags = XFS_DA_OP_OKNOENT;
+
        /*
         * Attach the dquots to the inode.
         */
index fa00788de2f549acf0d51bdb913e64350f703b16..e546a33214c93b9d6d4e9e75450451c8592b40aa 100644 (file)
@@ -88,22 +88,6 @@ xfs_bmap_add_attrfork_local(
        xfs_bmap_free_t         *flist,         /* blocks to free at commit */
        int                     *flags);        /* inode logging flags */
 
-/*
- * Called by xfs_bmapi to update file extent records and the btree
- * after allocating space (or doing a delayed allocation).
- */
-STATIC int                             /* error */
-xfs_bmap_add_extent(
-       xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_extnum_t            idx,    /* extent number to update/insert */
-       xfs_btree_cur_t         **curp, /* if *curp is null, not a btree */
-       xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
-       xfs_fsblock_t           *first, /* pointer to firstblock variable */
-       xfs_bmap_free_t         *flist, /* list of extents to be freed */
-       int                     *logflagsp, /* inode logging flags */
-       int                     whichfork, /* data or attr fork */
-       int                     rsvd);  /* OK to allocate reserved blocks */
-
 /*
  * Called by xfs_bmap_add_extent to handle cases converting a delayed
  * allocation to a real allocation.
@@ -111,14 +95,13 @@ xfs_bmap_add_extent(
 STATIC int                             /* error */
 xfs_bmap_add_extent_delay_real(
        xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_extnum_t            idx,    /* extent number to update/insert */
+       xfs_extnum_t            *idx,   /* extent number to update/insert */
        xfs_btree_cur_t         **curp, /* if *curp is null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        xfs_filblks_t           *dnew,  /* new delayed-alloc indirect blocks */
        xfs_fsblock_t           *first, /* pointer to firstblock variable */
        xfs_bmap_free_t         *flist, /* list of extents to be freed */
-       int                     *logflagsp, /* inode logging flags */
-       int                     rsvd);  /* OK to allocate reserved blocks */
+       int                     *logflagsp); /* inode logging flags */
 
 /*
  * Called by xfs_bmap_add_extent to handle cases converting a hole
@@ -127,10 +110,9 @@ xfs_bmap_add_extent_delay_real(
 STATIC int                             /* error */
 xfs_bmap_add_extent_hole_delay(
        xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_extnum_t            idx,    /* extent number to update/insert */
+       xfs_extnum_t            *idx,   /* extent number to update/insert */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
-       int                     *logflagsp,/* inode logging flags */
-       int                     rsvd);  /* OK to allocate reserved blocks */
+       int                     *logflagsp); /* inode logging flags */
 
 /*
  * Called by xfs_bmap_add_extent to handle cases converting a hole
@@ -139,7 +121,7 @@ xfs_bmap_add_extent_hole_delay(
 STATIC int                             /* error */
 xfs_bmap_add_extent_hole_real(
        xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_extnum_t            idx,    /* extent number to update/insert */
+       xfs_extnum_t            *idx,   /* extent number to update/insert */
        xfs_btree_cur_t         *cur,   /* if null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        int                     *logflagsp, /* inode logging flags */
@@ -152,7 +134,7 @@ xfs_bmap_add_extent_hole_real(
 STATIC int                             /* error */
 xfs_bmap_add_extent_unwritten_real(
        xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_extnum_t            idx,    /* extent number to update/insert */
+       xfs_extnum_t            *idx,   /* extent number to update/insert */
        xfs_btree_cur_t         **curp, /* if *curp is null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        int                     *logflagsp); /* inode logging flags */
@@ -179,22 +161,6 @@ xfs_bmap_btree_to_extents(
        int                     *logflagsp, /* inode logging flags */
        int                     whichfork); /* data or attr fork */
 
-/*
- * Called by xfs_bmapi to update file extent records and the btree
- * after removing space (or undoing a delayed allocation).
- */
-STATIC int                             /* error */
-xfs_bmap_del_extent(
-       xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_trans_t             *tp,    /* current trans pointer */
-       xfs_extnum_t            idx,    /* extent number to update/insert */
-       xfs_bmap_free_t         *flist, /* list of extents to be freed */
-       xfs_btree_cur_t         *cur,   /* if null, not a btree */
-       xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
-       int                     *logflagsp,/* inode logging flags */
-       int                     whichfork, /* data or attr fork */
-       int                     rsvd);   /* OK to allocate reserved blocks */
-
 /*
  * Remove the entry "free" from the free item list.  Prev points to the
  * previous entry, unless "free" is the head of the list.
@@ -474,14 +440,13 @@ xfs_bmap_add_attrfork_local(
 STATIC int                             /* error */
 xfs_bmap_add_extent(
        xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_extnum_t            idx,    /* extent number to update/insert */
+       xfs_extnum_t            *idx,   /* extent number to update/insert */
        xfs_btree_cur_t         **curp, /* if *curp is null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        xfs_fsblock_t           *first, /* pointer to firstblock variable */
        xfs_bmap_free_t         *flist, /* list of extents to be freed */
        int                     *logflagsp, /* inode logging flags */
-       int                     whichfork, /* data or attr fork */
-       int                     rsvd)   /* OK to use reserved data blocks */
+       int                     whichfork) /* data or attr fork */
 {
        xfs_btree_cur_t         *cur;   /* btree cursor or null */
        xfs_filblks_t           da_new; /* new count del alloc blocks used */
@@ -492,23 +457,27 @@ xfs_bmap_add_extent(
        xfs_extnum_t            nextents; /* number of extents in file now */
 
        XFS_STATS_INC(xs_add_exlist);
+
        cur = *curp;
        ifp = XFS_IFORK_PTR(ip, whichfork);
        nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-       ASSERT(idx <= nextents);
        da_old = da_new = 0;
        error = 0;
+
+       ASSERT(*idx >= 0);
+       ASSERT(*idx <= nextents);
+
        /*
         * This is the first extent added to a new/empty file.
         * Special case this one, so other routines get to assume there are
         * already extents in the list.
         */
        if (nextents == 0) {
-               xfs_iext_insert(ip, 0, 1, new,
+               xfs_iext_insert(ip, *idx, 1, new,
                                whichfork == XFS_ATTR_FORK ? BMAP_ATTRFORK : 0);
 
                ASSERT(cur == NULL);
-               ifp->if_lastex = 0;
+
                if (!isnullstartblock(new->br_startblock)) {
                        XFS_IFORK_NEXT_SET(ip, whichfork, 1);
                        logflags = XFS_ILOG_CORE | xfs_ilog_fext(whichfork);
@@ -522,27 +491,25 @@ xfs_bmap_add_extent(
                if (cur)
                        ASSERT((cur->bc_private.b.flags &
                                XFS_BTCUR_BPRV_WASDEL) == 0);
-               if ((error = xfs_bmap_add_extent_hole_delay(ip, idx, new,
-                               &logflags, rsvd)))
-                       goto done;
+               error = xfs_bmap_add_extent_hole_delay(ip, idx, new,
+                                                      &logflags);
        }
        /*
         * Real allocation off the end of the file.
         */
-       else if (idx == nextents) {
+       else if (*idx == nextents) {
                if (cur)
                        ASSERT((cur->bc_private.b.flags &
                                XFS_BTCUR_BPRV_WASDEL) == 0);
-               if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur, new,
-                               &logflags, whichfork)))
-                       goto done;
+               error = xfs_bmap_add_extent_hole_real(ip, idx, cur, new,
+                               &logflags, whichfork);
        } else {
                xfs_bmbt_irec_t prev;   /* old extent at offset idx */
 
                /*
                 * Get the record referred to by idx.
                 */
-               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), &prev);
+               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx), &prev);
                /*
                 * If it's a real allocation record, and the new allocation ends
                 * after the start of the referred to record, then we're filling
@@ -557,22 +524,18 @@ xfs_bmap_add_extent(
                                if (cur)
                                        ASSERT(cur->bc_private.b.flags &
                                                XFS_BTCUR_BPRV_WASDEL);
-                               if ((error = xfs_bmap_add_extent_delay_real(ip,
-                                       idx, &cur, new, &da_new, first, flist,
-                                       &logflags, rsvd)))
-                                       goto done;
-                       } else if (new->br_state == XFS_EXT_NORM) {
-                               ASSERT(new->br_state == XFS_EXT_NORM);
-                               if ((error = xfs_bmap_add_extent_unwritten_real(
-                                       ip, idx, &cur, new, &logflags)))
-                                       goto done;
+                               error = xfs_bmap_add_extent_delay_real(ip,
+                                               idx, &cur, new, &da_new,
+                                               first, flist, &logflags);
                        } else {
-                               ASSERT(new->br_state == XFS_EXT_UNWRITTEN);
-                               if ((error = xfs_bmap_add_extent_unwritten_real(
-                                       ip, idx, &cur, new, &logflags)))
+                               ASSERT(new->br_state == XFS_EXT_NORM ||
+                                      new->br_state == XFS_EXT_UNWRITTEN);
+
+                               error = xfs_bmap_add_extent_unwritten_real(ip,
+                                               idx, &cur, new, &logflags);
+                               if (error)
                                        goto done;
                        }
-                       ASSERT(*curp == cur || *curp == NULL);
                }
                /*
                 * Otherwise we're filling in a hole with an allocation.
@@ -581,13 +544,15 @@ xfs_bmap_add_extent(
                        if (cur)
                                ASSERT((cur->bc_private.b.flags &
                                        XFS_BTCUR_BPRV_WASDEL) == 0);
-                       if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur,
-                                       new, &logflags, whichfork)))
-                               goto done;
+                       error = xfs_bmap_add_extent_hole_real(ip, idx, cur,
+                                       new, &logflags, whichfork);
                }
        }
 
+       if (error)
+               goto done;
        ASSERT(*curp == cur || *curp == NULL);
+
        /*
         * Convert to a btree if necessary.
         */
@@ -615,7 +580,7 @@ xfs_bmap_add_extent(
                ASSERT(nblks <= da_old);
                if (nblks < da_old)
                        xfs_icsb_modify_counters(ip->i_mount, XFS_SBS_FDBLOCKS,
-                               (int64_t)(da_old - nblks), rsvd);
+                               (int64_t)(da_old - nblks), 0);
        }
        /*
         * Clear out the allocated field, done with it now in any case.
@@ -640,14 +605,13 @@ done:
 STATIC int                             /* error */
 xfs_bmap_add_extent_delay_real(
        xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_extnum_t            idx,    /* extent number to update/insert */
+       xfs_extnum_t            *idx,   /* extent number to update/insert */
        xfs_btree_cur_t         **curp, /* if *curp is null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        xfs_filblks_t           *dnew,  /* new delayed-alloc indirect blocks */
        xfs_fsblock_t           *first, /* pointer to firstblock variable */
        xfs_bmap_free_t         *flist, /* list of extents to be freed */
-       int                     *logflagsp, /* inode logging flags */
-       int                     rsvd)   /* OK to use reserved data block allocation */
+       int                     *logflagsp) /* inode logging flags */
 {
        xfs_btree_cur_t         *cur;   /* btree cursor */
        int                     diff;   /* temp value */
@@ -673,7 +637,7 @@ xfs_bmap_add_extent_delay_real(
         */
        cur = *curp;
        ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
-       ep = xfs_iext_get_ext(ifp, idx);
+       ep = xfs_iext_get_ext(ifp, *idx);
        xfs_bmbt_get_all(ep, &PREV);
        new_endoff = new->br_startoff + new->br_blockcount;
        ASSERT(PREV.br_startoff <= new->br_startoff);
@@ -692,9 +656,9 @@ xfs_bmap_add_extent_delay_real(
         * Check and set flags if this segment has a left neighbor.
         * Don't set contiguous if the combined extent would be too large.
         */
-       if (idx > 0) {
+       if (*idx > 0) {
                state |= BMAP_LEFT_VALID;
-               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx - 1), &LEFT);
+               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx - 1), &LEFT);
 
                if (isnullstartblock(LEFT.br_startblock))
                        state |= BMAP_LEFT_DELAY;
@@ -712,9 +676,9 @@ xfs_bmap_add_extent_delay_real(
         * Don't set contiguous if the combined extent would be too large.
         * Also check for all-three-contiguous being too large.
         */
-       if (idx < ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1) {
+       if (*idx < ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1) {
                state |= BMAP_RIGHT_VALID;
-               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx + 1), &RIGHT);
+               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx + 1), &RIGHT);
 
                if (isnullstartblock(RIGHT.br_startblock))
                        state |= BMAP_RIGHT_DELAY;
@@ -745,14 +709,14 @@ xfs_bmap_add_extent_delay_real(
                 * Filling in all of a previously delayed allocation extent.
                 * The left and right neighbors are both contiguous with new.
                 */
-               trace_xfs_bmap_pre_update(ip, idx - 1, state, _THIS_IP_);
-               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
+               --*idx;
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx),
                        LEFT.br_blockcount + PREV.br_blockcount +
                        RIGHT.br_blockcount);
-               trace_xfs_bmap_post_update(ip, idx - 1, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
 
-               xfs_iext_remove(ip, idx, 2, state);
-               ip->i_df.if_lastex = idx - 1;
+               xfs_iext_remove(ip, *idx + 1, 2, state);
                ip->i_d.di_nextents--;
                if (cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
@@ -784,13 +748,14 @@ xfs_bmap_add_extent_delay_real(
                 * Filling in all of a previously delayed allocation extent.
                 * The left neighbor is contiguous, the right is not.
                 */
-               trace_xfs_bmap_pre_update(ip, idx - 1, state, _THIS_IP_);
-               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
+               --*idx;
+
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx),
                        LEFT.br_blockcount + PREV.br_blockcount);
-               trace_xfs_bmap_post_update(ip, idx - 1, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
 
-               ip->i_df.if_lastex = idx - 1;
-               xfs_iext_remove(ip, idx, 1, state);
+               xfs_iext_remove(ip, *idx + 1, 1, state);
                if (cur == NULL)
                        rval = XFS_ILOG_DEXT;
                else {
@@ -814,14 +779,13 @@ xfs_bmap_add_extent_delay_real(
                 * Filling in all of a previously delayed allocation extent.
                 * The right neighbor is contiguous, the left is not.
                 */
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
                xfs_bmbt_set_startblock(ep, new->br_startblock);
                xfs_bmbt_set_blockcount(ep,
                        PREV.br_blockcount + RIGHT.br_blockcount);
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
 
-               ip->i_df.if_lastex = idx;
-               xfs_iext_remove(ip, idx + 1, 1, state);
+               xfs_iext_remove(ip, *idx + 1, 1, state);
                if (cur == NULL)
                        rval = XFS_ILOG_DEXT;
                else {
@@ -837,6 +801,7 @@ xfs_bmap_add_extent_delay_real(
                                        RIGHT.br_blockcount, PREV.br_state)))
                                goto done;
                }
+
                *dnew = 0;
                break;
 
@@ -846,11 +811,10 @@ xfs_bmap_add_extent_delay_real(
                 * Neither the left nor right neighbors are contiguous with
                 * the new one.
                 */
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
                xfs_bmbt_set_startblock(ep, new->br_startblock);
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
 
-               ip->i_df.if_lastex = idx;
                ip->i_d.di_nextents++;
                if (cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
@@ -866,6 +830,7 @@ xfs_bmap_add_extent_delay_real(
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
                }
+
                *dnew = 0;
                break;
 
@@ -874,17 +839,16 @@ xfs_bmap_add_extent_delay_real(
                 * Filling in the first part of a previous delayed allocation.
                 * The left neighbor is contiguous.
                 */
-               trace_xfs_bmap_pre_update(ip, idx - 1, state, _THIS_IP_);
-               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
+               trace_xfs_bmap_pre_update(ip, *idx - 1, state, _THIS_IP_);
+               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx - 1),
                        LEFT.br_blockcount + new->br_blockcount);
                xfs_bmbt_set_startoff(ep,
                        PREV.br_startoff + new->br_blockcount);
-               trace_xfs_bmap_post_update(ip, idx - 1, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx - 1, state, _THIS_IP_);
 
                temp = PREV.br_blockcount - new->br_blockcount;
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
                xfs_bmbt_set_blockcount(ep, temp);
-               ip->i_df.if_lastex = idx - 1;
                if (cur == NULL)
                        rval = XFS_ILOG_DEXT;
                else {
@@ -904,7 +868,9 @@ xfs_bmap_add_extent_delay_real(
                temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
                        startblockval(PREV.br_startblock));
                xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+
+               --*idx;
                *dnew = temp;
                break;
 
@@ -913,12 +879,11 @@ xfs_bmap_add_extent_delay_real(
                 * Filling in the first part of a previous delayed allocation.
                 * The left neighbor is not contiguous.
                 */
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
                xfs_bmbt_set_startoff(ep, new_endoff);
                temp = PREV.br_blockcount - new->br_blockcount;
                xfs_bmbt_set_blockcount(ep, temp);
-               xfs_iext_insert(ip, idx, 1, new, state);
-               ip->i_df.if_lastex = idx;
+               xfs_iext_insert(ip, *idx, 1, new, state);
                ip->i_d.di_nextents++;
                if (cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
@@ -946,9 +911,10 @@ xfs_bmap_add_extent_delay_real(
                temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
                        startblockval(PREV.br_startblock) -
                        (cur ? cur->bc_private.b.allocated : 0));
-               ep = xfs_iext_get_ext(ifp, idx + 1);
+               ep = xfs_iext_get_ext(ifp, *idx + 1);
                xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
-               trace_xfs_bmap_post_update(ip, idx + 1, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx + 1, state, _THIS_IP_);
+
                *dnew = temp;
                break;
 
@@ -958,15 +924,13 @@ xfs_bmap_add_extent_delay_real(
                 * The right neighbor is contiguous with the new allocation.
                 */
                temp = PREV.br_blockcount - new->br_blockcount;
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
-               trace_xfs_bmap_pre_update(ip, idx + 1, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx + 1, state, _THIS_IP_);
                xfs_bmbt_set_blockcount(ep, temp);
-               xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, idx + 1),
+               xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, *idx + 1),
                        new->br_startoff, new->br_startblock,
                        new->br_blockcount + RIGHT.br_blockcount,
                        RIGHT.br_state);
-               trace_xfs_bmap_post_update(ip, idx + 1, state, _THIS_IP_);
-               ip->i_df.if_lastex = idx + 1;
+               trace_xfs_bmap_post_update(ip, *idx + 1, state, _THIS_IP_);
                if (cur == NULL)
                        rval = XFS_ILOG_DEXT;
                else {
@@ -983,10 +947,14 @@ xfs_bmap_add_extent_delay_real(
                                        RIGHT.br_state)))
                                goto done;
                }
+
                temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
                        startblockval(PREV.br_startblock));
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
                xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+
+               ++*idx;
                *dnew = temp;
                break;
 
@@ -996,10 +964,9 @@ xfs_bmap_add_extent_delay_real(
                 * The right neighbor is not contiguous.
                 */
                temp = PREV.br_blockcount - new->br_blockcount;
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
                xfs_bmbt_set_blockcount(ep, temp);
-               xfs_iext_insert(ip, idx + 1, 1, new, state);
-               ip->i_df.if_lastex = idx + 1;
+               xfs_iext_insert(ip, *idx + 1, 1, new, state);
                ip->i_d.di_nextents++;
                if (cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
@@ -1027,9 +994,11 @@ xfs_bmap_add_extent_delay_real(
                temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
                        startblockval(PREV.br_startblock) -
                        (cur ? cur->bc_private.b.allocated : 0));
-               ep = xfs_iext_get_ext(ifp, idx);
+               ep = xfs_iext_get_ext(ifp, *idx);
                xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+
+               ++*idx;
                *dnew = temp;
                break;
 
@@ -1056,7 +1025,7 @@ xfs_bmap_add_extent_delay_real(
                 */
                temp = new->br_startoff - PREV.br_startoff;
                temp2 = PREV.br_startoff + PREV.br_blockcount - new_endoff;
-               trace_xfs_bmap_pre_update(ip, idx, 0, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx, 0, _THIS_IP_);
                xfs_bmbt_set_blockcount(ep, temp);      /* truncate PREV */
                LEFT = *new;
                RIGHT.br_state = PREV.br_state;
@@ -1065,8 +1034,7 @@ xfs_bmap_add_extent_delay_real(
                RIGHT.br_startoff = new_endoff;
                RIGHT.br_blockcount = temp2;
                /* insert LEFT (r[0]) and RIGHT (r[1]) at the same time */
-               xfs_iext_insert(ip, idx + 1, 2, &LEFT, state);
-               ip->i_df.if_lastex = idx + 1;
+               xfs_iext_insert(ip, *idx + 1, 2, &LEFT, state);
                ip->i_d.di_nextents++;
                if (cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
@@ -1097,7 +1065,7 @@ xfs_bmap_add_extent_delay_real(
                        (cur ? cur->bc_private.b.allocated : 0));
                if (diff > 0 &&
                    xfs_icsb_modify_counters(ip->i_mount, XFS_SBS_FDBLOCKS,
-                                            -((int64_t)diff), rsvd)) {
+                                            -((int64_t)diff), 0)) {
                        /*
                         * Ick gross gag me with a spoon.
                         */
@@ -1109,7 +1077,7 @@ xfs_bmap_add_extent_delay_real(
                                        if (!diff ||
                                            !xfs_icsb_modify_counters(ip->i_mount,
                                                    XFS_SBS_FDBLOCKS,
-                                                   -((int64_t)diff), rsvd))
+                                                   -((int64_t)diff), 0))
                                                break;
                                }
                                if (temp2) {
@@ -1118,18 +1086,20 @@ xfs_bmap_add_extent_delay_real(
                                        if (!diff ||
                                            !xfs_icsb_modify_counters(ip->i_mount,
                                                    XFS_SBS_FDBLOCKS,
-                                                   -((int64_t)diff), rsvd))
+                                                   -((int64_t)diff), 0))
                                                break;
                                }
                        }
                }
-               ep = xfs_iext_get_ext(ifp, idx);
+               ep = xfs_iext_get_ext(ifp, *idx);
                xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
-               trace_xfs_bmap_pre_update(ip, idx + 2, state, _THIS_IP_);
-               xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, idx + 2),
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx + 2, state, _THIS_IP_);
+               xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, *idx + 2),
                        nullstartblock((int)temp2));
-               trace_xfs_bmap_post_update(ip, idx + 2, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx + 2, state, _THIS_IP_);
+
+               ++*idx;
                *dnew = temp + temp2;
                break;
 
@@ -1161,7 +1131,7 @@ done:
 STATIC int                             /* error */
 xfs_bmap_add_extent_unwritten_real(
        xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_extnum_t            idx,    /* extent number to update/insert */
+       xfs_extnum_t            *idx,   /* extent number to update/insert */
        xfs_btree_cur_t         **curp, /* if *curp is null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        int                     *logflagsp) /* inode logging flags */
@@ -1188,7 +1158,7 @@ xfs_bmap_add_extent_unwritten_real(
        error = 0;
        cur = *curp;
        ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
-       ep = xfs_iext_get_ext(ifp, idx);
+       ep = xfs_iext_get_ext(ifp, *idx);
        xfs_bmbt_get_all(ep, &PREV);
        newext = new->br_state;
        oldext = (newext == XFS_EXT_UNWRITTEN) ?
@@ -1211,9 +1181,9 @@ xfs_bmap_add_extent_unwritten_real(
         * Check and set flags if this segment has a left neighbor.
         * Don't set contiguous if the combined extent would be too large.
         */
-       if (idx > 0) {
+       if (*idx > 0) {
                state |= BMAP_LEFT_VALID;
-               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx - 1), &LEFT);
+               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx - 1), &LEFT);
 
                if (isnullstartblock(LEFT.br_startblock))
                        state |= BMAP_LEFT_DELAY;
@@ -1231,9 +1201,9 @@ xfs_bmap_add_extent_unwritten_real(
         * Don't set contiguous if the combined extent would be too large.
         * Also check for all-three-contiguous being too large.
         */
-       if (idx < ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1) {
+       if (*idx < ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1) {
                state |= BMAP_RIGHT_VALID;
-               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx + 1), &RIGHT);
+               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx + 1), &RIGHT);
                if (isnullstartblock(RIGHT.br_startblock))
                        state |= BMAP_RIGHT_DELAY;
        }
@@ -1262,14 +1232,15 @@ xfs_bmap_add_extent_unwritten_real(
                 * Setting all of a previous oldext extent to newext.
                 * The left and right neighbors are both contiguous with new.
                 */
-               trace_xfs_bmap_pre_update(ip, idx - 1, state, _THIS_IP_);
-               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
+               --*idx;
+
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx),
                        LEFT.br_blockcount + PREV.br_blockcount +
                        RIGHT.br_blockcount);
-               trace_xfs_bmap_post_update(ip, idx - 1, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
 
-               xfs_iext_remove(ip, idx, 2, state);
-               ip->i_df.if_lastex = idx - 1;
+               xfs_iext_remove(ip, *idx + 1, 2, state);
                ip->i_d.di_nextents -= 2;
                if (cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
@@ -1305,13 +1276,14 @@ xfs_bmap_add_extent_unwritten_real(
                 * Setting all of a previous oldext extent to newext.
                 * The left neighbor is contiguous, the right is not.
                 */
-               trace_xfs_bmap_pre_update(ip, idx - 1, state, _THIS_IP_);
-               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
+               --*idx;
+
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx),
                        LEFT.br_blockcount + PREV.br_blockcount);
-               trace_xfs_bmap_post_update(ip, idx - 1, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
 
-               ip->i_df.if_lastex = idx - 1;
-               xfs_iext_remove(ip, idx, 1, state);
+               xfs_iext_remove(ip, *idx + 1, 1, state);
                ip->i_d.di_nextents--;
                if (cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
@@ -1341,13 +1313,12 @@ xfs_bmap_add_extent_unwritten_real(
                 * Setting all of a previous oldext extent to newext.
                 * The right neighbor is contiguous, the left is not.
                 */
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
                xfs_bmbt_set_blockcount(ep,
                        PREV.br_blockcount + RIGHT.br_blockcount);
                xfs_bmbt_set_state(ep, newext);
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
-               ip->i_df.if_lastex = idx;
-               xfs_iext_remove(ip, idx + 1, 1, state);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+               xfs_iext_remove(ip, *idx + 1, 1, state);
                ip->i_d.di_nextents--;
                if (cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
@@ -1378,11 +1349,10 @@ xfs_bmap_add_extent_unwritten_real(
                 * Neither the left nor right neighbors are contiguous with
                 * the new one.
                 */
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
                xfs_bmbt_set_state(ep, newext);
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
 
-               ip->i_df.if_lastex = idx;
                if (cur == NULL)
                        rval = XFS_ILOG_DEXT;
                else {
@@ -1404,21 +1374,22 @@ xfs_bmap_add_extent_unwritten_real(
                 * Setting the first part of a previous oldext extent to newext.
                 * The left neighbor is contiguous.
                 */
-               trace_xfs_bmap_pre_update(ip, idx - 1, state, _THIS_IP_);
-               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
+               trace_xfs_bmap_pre_update(ip, *idx - 1, state, _THIS_IP_);
+               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx - 1),
                        LEFT.br_blockcount + new->br_blockcount);
                xfs_bmbt_set_startoff(ep,
                        PREV.br_startoff + new->br_blockcount);
-               trace_xfs_bmap_post_update(ip, idx - 1, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx - 1, state, _THIS_IP_);
 
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
                xfs_bmbt_set_startblock(ep,
                        new->br_startblock + new->br_blockcount);
                xfs_bmbt_set_blockcount(ep,
                        PREV.br_blockcount - new->br_blockcount);
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+
+               --*idx;
 
-               ip->i_df.if_lastex = idx - 1;
                if (cur == NULL)
                        rval = XFS_ILOG_DEXT;
                else {
@@ -1449,17 +1420,16 @@ xfs_bmap_add_extent_unwritten_real(
                 * Setting the first part of a previous oldext extent to newext.
                 * The left neighbor is not contiguous.
                 */
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
                ASSERT(ep && xfs_bmbt_get_state(ep) == oldext);
                xfs_bmbt_set_startoff(ep, new_endoff);
                xfs_bmbt_set_blockcount(ep,
                        PREV.br_blockcount - new->br_blockcount);
                xfs_bmbt_set_startblock(ep,
                        new->br_startblock + new->br_blockcount);
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
 
-               xfs_iext_insert(ip, idx, 1, new, state);
-               ip->i_df.if_lastex = idx;
+               xfs_iext_insert(ip, *idx, 1, new, state);
                ip->i_d.di_nextents++;
                if (cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
@@ -1488,17 +1458,19 @@ xfs_bmap_add_extent_unwritten_real(
                 * Setting the last part of a previous oldext extent to newext.
                 * The right neighbor is contiguous with the new allocation.
                 */
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
-               trace_xfs_bmap_pre_update(ip, idx + 1, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
                xfs_bmbt_set_blockcount(ep,
                        PREV.br_blockcount - new->br_blockcount);
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
-               xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, idx + 1),
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+
+               ++*idx;
+
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, *idx),
                        new->br_startoff, new->br_startblock,
                        new->br_blockcount + RIGHT.br_blockcount, newext);
-               trace_xfs_bmap_post_update(ip, idx + 1, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
 
-               ip->i_df.if_lastex = idx + 1;
                if (cur == NULL)
                        rval = XFS_ILOG_DEXT;
                else {
@@ -1528,13 +1500,14 @@ xfs_bmap_add_extent_unwritten_real(
                 * Setting the last part of a previous oldext extent to newext.
                 * The right neighbor is not contiguous.
                 */
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
                xfs_bmbt_set_blockcount(ep,
                        PREV.br_blockcount - new->br_blockcount);
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+
+               ++*idx;
+               xfs_iext_insert(ip, *idx, 1, new, state);
 
-               xfs_iext_insert(ip, idx + 1, 1, new, state);
-               ip->i_df.if_lastex = idx + 1;
                ip->i_d.di_nextents++;
                if (cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
@@ -1568,10 +1541,10 @@ xfs_bmap_add_extent_unwritten_real(
                 * newext.  Contiguity is impossible here.
                 * One extent becomes three extents.
                 */
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
                xfs_bmbt_set_blockcount(ep,
                        new->br_startoff - PREV.br_startoff);
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
 
                r[0] = *new;
                r[1].br_startoff = new_endoff;
@@ -1579,8 +1552,10 @@ xfs_bmap_add_extent_unwritten_real(
                        PREV.br_startoff + PREV.br_blockcount - new_endoff;
                r[1].br_startblock = new->br_startblock + new->br_blockcount;
                r[1].br_state = oldext;
-               xfs_iext_insert(ip, idx + 1, 2, &r[0], state);
-               ip->i_df.if_lastex = idx + 1;
+
+               ++*idx;
+               xfs_iext_insert(ip, *idx, 2, &r[0], state);
+
                ip->i_d.di_nextents += 2;
                if (cur == NULL)
                        rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
@@ -1650,12 +1625,10 @@ done:
 STATIC int                             /* error */
 xfs_bmap_add_extent_hole_delay(
        xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_extnum_t            idx,    /* extent number to update/insert */
+       xfs_extnum_t            *idx,   /* extent number to update/insert */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
-       int                     *logflagsp, /* inode logging flags */
-       int                     rsvd)           /* OK to allocate reserved blocks */
+       int                     *logflagsp) /* inode logging flags */
 {
-       xfs_bmbt_rec_host_t     *ep;    /* extent record for idx */
        xfs_ifork_t             *ifp;   /* inode fork pointer */
        xfs_bmbt_irec_t         left;   /* left neighbor extent entry */
        xfs_filblks_t           newlen=0;       /* new indirect size */
@@ -1665,16 +1638,15 @@ xfs_bmap_add_extent_hole_delay(
        xfs_filblks_t           temp=0; /* temp for indirect calculations */
 
        ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
-       ep = xfs_iext_get_ext(ifp, idx);
        state = 0;
        ASSERT(isnullstartblock(new->br_startblock));
 
        /*
         * Check and set flags if this segment has a left neighbor
         */
-       if (idx > 0) {
+       if (*idx > 0) {
                state |= BMAP_LEFT_VALID;
-               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx - 1), &left);
+               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx - 1), &left);
 
                if (isnullstartblock(left.br_startblock))
                        state |= BMAP_LEFT_DELAY;
@@ -1684,9 +1656,9 @@ xfs_bmap_add_extent_hole_delay(
         * Check and set flags if the current (right) segment exists.
         * If it doesn't exist, we're converting the hole at end-of-file.
         */
-       if (idx < ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t)) {
+       if (*idx < ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t)) {
                state |= BMAP_RIGHT_VALID;
-               xfs_bmbt_get_all(ep, &right);
+               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx), &right);
 
                if (isnullstartblock(right.br_startblock))
                        state |= BMAP_RIGHT_DELAY;
@@ -1719,21 +1691,21 @@ xfs_bmap_add_extent_hole_delay(
                 * on the left and on the right.
                 * Merge all three into a single extent record.
                 */
+               --*idx;
                temp = left.br_blockcount + new->br_blockcount +
                        right.br_blockcount;
 
-               trace_xfs_bmap_pre_update(ip, idx - 1, state, _THIS_IP_);
-               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1), temp);
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx), temp);
                oldlen = startblockval(left.br_startblock) +
                        startblockval(new->br_startblock) +
                        startblockval(right.br_startblock);
                newlen = xfs_bmap_worst_indlen(ip, temp);
-               xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, idx - 1),
+               xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, *idx),
                        nullstartblock((int)newlen));
-               trace_xfs_bmap_post_update(ip, idx - 1, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
 
-               xfs_iext_remove(ip, idx, 1, state);
-               ip->i_df.if_lastex = idx - 1;
+               xfs_iext_remove(ip, *idx + 1, 1, state);
                break;
 
        case BMAP_LEFT_CONTIG:
@@ -1742,17 +1714,17 @@ xfs_bmap_add_extent_hole_delay(
                 * on the left.
                 * Merge the new allocation with the left neighbor.
                 */
+               --*idx;
                temp = left.br_blockcount + new->br_blockcount;
-               trace_xfs_bmap_pre_update(ip, idx - 1, state, _THIS_IP_);
-               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1), temp);
+
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx), temp);
                oldlen = startblockval(left.br_startblock) +
                        startblockval(new->br_startblock);
                newlen = xfs_bmap_worst_indlen(ip, temp);
-               xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, idx - 1),
+               xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, *idx),
                        nullstartblock((int)newlen));
-               trace_xfs_bmap_post_update(ip, idx - 1, state, _THIS_IP_);
-
-               ip->i_df.if_lastex = idx - 1;
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
                break;
 
        case BMAP_RIGHT_CONTIG:
@@ -1761,16 +1733,15 @@ xfs_bmap_add_extent_hole_delay(
                 * on the right.
                 * Merge the new allocation with the right neighbor.
                 */
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
                temp = new->br_blockcount + right.br_blockcount;
                oldlen = startblockval(new->br_startblock) +
                        startblockval(right.br_startblock);
                newlen = xfs_bmap_worst_indlen(ip, temp);
-               xfs_bmbt_set_allf(ep, new->br_startoff,
+               xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, *idx),
+                       new->br_startoff,
                        nullstartblock((int)newlen), temp, right.br_state);
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
-
-               ip->i_df.if_lastex = idx;
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
                break;
 
        case 0:
@@ -1780,14 +1751,13 @@ xfs_bmap_add_extent_hole_delay(
                 * Insert a new entry.
                 */
                oldlen = newlen = 0;
-               xfs_iext_insert(ip, idx, 1, new, state);
-               ip->i_df.if_lastex = idx;
+               xfs_iext_insert(ip, *idx, 1, new, state);
                break;
        }
        if (oldlen != newlen) {
                ASSERT(oldlen > newlen);
                xfs_icsb_modify_counters(ip->i_mount, XFS_SBS_FDBLOCKS,
-                       (int64_t)(oldlen - newlen), rsvd);
+                       (int64_t)(oldlen - newlen), 0);
                /*
                 * Nothing to do for disk quota accounting here.
                 */
@@ -1803,13 +1773,12 @@ xfs_bmap_add_extent_hole_delay(
 STATIC int                             /* error */
 xfs_bmap_add_extent_hole_real(
        xfs_inode_t             *ip,    /* incore inode pointer */
-       xfs_extnum_t            idx,    /* extent number to update/insert */
+       xfs_extnum_t            *idx,   /* extent number to update/insert */
        xfs_btree_cur_t         *cur,   /* if null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        int                     *logflagsp, /* inode logging flags */
        int                     whichfork) /* data or attr fork */
 {
-       xfs_bmbt_rec_host_t     *ep;    /* pointer to extent entry ins. point */
        int                     error;  /* error return value */
        int                     i;      /* temp state */
        xfs_ifork_t             *ifp;   /* inode fork pointer */
@@ -1819,8 +1788,7 @@ xfs_bmap_add_extent_hole_real(
        int                     state;  /* state bits, accessed thru macros */
 
        ifp = XFS_IFORK_PTR(ip, whichfork);
-       ASSERT(idx <= ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t));
-       ep = xfs_iext_get_ext(ifp, idx);
+       ASSERT(*idx <= ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t));
        state = 0;
 
        if (whichfork == XFS_ATTR_FORK)
@@ -1829,9 +1797,9 @@ xfs_bmap_add_extent_hole_real(
        /*
         * Check and set flags if this segment has a left neighbor.
         */
-       if (idx > 0) {
+       if (*idx > 0) {
                state |= BMAP_LEFT_VALID;
-               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx - 1), &left);
+               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx - 1), &left);
                if (isnullstartblock(left.br_startblock))
                        state |= BMAP_LEFT_DELAY;
        }
@@ -1840,9 +1808,9 @@ xfs_bmap_add_extent_hole_real(
         * Check and set flags if this segment has a current value.
         * Not true if we're inserting into the "hole" at eof.
         */
-       if (idx < ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t)) {
+       if (*idx < ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t)) {
                state |= BMAP_RIGHT_VALID;
-               xfs_bmbt_get_all(ep, &right);
+               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx), &right);
                if (isnullstartblock(right.br_startblock))
                        state |= BMAP_RIGHT_DELAY;
        }
@@ -1879,14 +1847,15 @@ xfs_bmap_add_extent_hole_real(
                 * left and on the right.
                 * Merge all three into a single extent record.
                 */
-               trace_xfs_bmap_pre_update(ip, idx - 1, state, _THIS_IP_);
-               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
+               --*idx;
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx),
                        left.br_blockcount + new->br_blockcount +
                        right.br_blockcount);
-               trace_xfs_bmap_post_update(ip, idx - 1, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+
+               xfs_iext_remove(ip, *idx + 1, 1, state);
 
-               xfs_iext_remove(ip, idx, 1, state);
-               ifp->if_lastex = idx - 1;
                XFS_IFORK_NEXT_SET(ip, whichfork,
                        XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
                if (cur == NULL) {
@@ -1921,12 +1890,12 @@ xfs_bmap_add_extent_hole_real(
                 * on the left.
                 * Merge the new allocation with the left neighbor.
                 */
-               trace_xfs_bmap_pre_update(ip, idx - 1, state, _THIS_IP_);
-               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
+               --*idx;
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx),
                        left.br_blockcount + new->br_blockcount);
-               trace_xfs_bmap_post_update(ip, idx - 1, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
 
-               ifp->if_lastex = idx - 1;
                if (cur == NULL) {
                        rval = xfs_ilog_fext(whichfork);
                } else {
@@ -1952,13 +1921,13 @@ xfs_bmap_add_extent_hole_real(
                 * on the right.
                 * Merge the new allocation with the right neighbor.
                 */
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
-               xfs_bmbt_set_allf(ep, new->br_startoff, new->br_startblock,
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, *idx),
+                       new->br_startoff, new->br_startblock,
                        new->br_blockcount + right.br_blockcount,
                        right.br_state);
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
 
-               ifp->if_lastex = idx;
                if (cur == NULL) {
                        rval = xfs_ilog_fext(whichfork);
                } else {
@@ -1984,8 +1953,7 @@ xfs_bmap_add_extent_hole_real(
                 * real allocation.
                 * Insert a new entry.
                 */
-               xfs_iext_insert(ip, idx, 1, new, state);
-               ifp->if_lastex = idx;
+               xfs_iext_insert(ip, *idx, 1, new, state);
                XFS_IFORK_NEXT_SET(ip, whichfork,
                        XFS_IFORK_NEXTENTS(ip, whichfork) + 1);
                if (cur == NULL) {
@@ -2833,13 +2801,12 @@ STATIC int                              /* error */
 xfs_bmap_del_extent(
        xfs_inode_t             *ip,    /* incore inode pointer */
        xfs_trans_t             *tp,    /* current transaction pointer */
-       xfs_extnum_t            idx,    /* extent number to update/delete */
+       xfs_extnum_t            *idx,   /* extent number to update/delete */
        xfs_bmap_free_t         *flist, /* list of extents to be freed */
        xfs_btree_cur_t         *cur,   /* if null, not a btree */
        xfs_bmbt_irec_t         *del,   /* data to remove from extents */
        int                     *logflagsp, /* inode logging flags */
-       int                     whichfork, /* data or attr fork */
-       int                     rsvd)   /* OK to allocate reserved blocks */
+       int                     whichfork) /* data or attr fork */
 {
        xfs_filblks_t           da_new; /* new delay-alloc indirect blocks */
        xfs_filblks_t           da_old; /* old delay-alloc indirect blocks */
@@ -2870,10 +2837,10 @@ xfs_bmap_del_extent(
 
        mp = ip->i_mount;
        ifp = XFS_IFORK_PTR(ip, whichfork);
-       ASSERT((idx >= 0) && (idx < ifp->if_bytes /
+       ASSERT((*idx >= 0) && (*idx < ifp->if_bytes /
                (uint)sizeof(xfs_bmbt_rec_t)));
        ASSERT(del->br_blockcount > 0);
-       ep = xfs_iext_get_ext(ifp, idx);
+       ep = xfs_iext_get_ext(ifp, *idx);
        xfs_bmbt_get_all(ep, &got);
        ASSERT(got.br_startoff <= del->br_startoff);
        del_endoff = del->br_startoff + del->br_blockcount;
@@ -2947,11 +2914,12 @@ xfs_bmap_del_extent(
                /*
                 * Matches the whole extent.  Delete the entry.
                 */
-               xfs_iext_remove(ip, idx, 1,
+               xfs_iext_remove(ip, *idx, 1,
                                whichfork == XFS_ATTR_FORK ? BMAP_ATTRFORK : 0);
-               ifp->if_lastex = idx;
+               --*idx;
                if (delay)
                        break;
+
                XFS_IFORK_NEXT_SET(ip, whichfork,
                        XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
                flags |= XFS_ILOG_CORE;
@@ -2968,21 +2936,20 @@ xfs_bmap_del_extent(
                /*
                 * Deleting the first part of the extent.
                 */
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
                xfs_bmbt_set_startoff(ep, del_endoff);
                temp = got.br_blockcount - del->br_blockcount;
                xfs_bmbt_set_blockcount(ep, temp);
-               ifp->if_lastex = idx;
                if (delay) {
                        temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
                                da_old);
                        xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
-                       trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
+                       trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
                        da_new = temp;
                        break;
                }
                xfs_bmbt_set_startblock(ep, del_endblock);
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
                if (!cur) {
                        flags |= xfs_ilog_fext(whichfork);
                        break;
@@ -2998,18 +2965,17 @@ xfs_bmap_del_extent(
                 * Deleting the last part of the extent.
                 */
                temp = got.br_blockcount - del->br_blockcount;
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
                xfs_bmbt_set_blockcount(ep, temp);
-               ifp->if_lastex = idx;
                if (delay) {
                        temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
                                da_old);
                        xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
-                       trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
+                       trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
                        da_new = temp;
                        break;
                }
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
                if (!cur) {
                        flags |= xfs_ilog_fext(whichfork);
                        break;
@@ -3026,7 +2992,7 @@ xfs_bmap_del_extent(
                 * Deleting the middle of the extent.
                 */
                temp = del->br_startoff - got.br_startoff;
-               trace_xfs_bmap_pre_update(ip, idx, state, _THIS_IP_);
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
                xfs_bmbt_set_blockcount(ep, temp);
                new.br_startoff = del_endoff;
                temp2 = got_endoff - del_endoff;
@@ -3113,9 +3079,9 @@ xfs_bmap_del_extent(
                                }
                        }
                }
-               trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
-               xfs_iext_insert(ip, idx + 1, 1, &new, state);
-               ifp->if_lastex = idx + 1;
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+               xfs_iext_insert(ip, *idx + 1, 1, &new, state);
+               ++*idx;
                break;
        }
        /*
@@ -3142,7 +3108,7 @@ xfs_bmap_del_extent(
        ASSERT(da_old >= da_new);
        if (da_old > da_new) {
                xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS,
-                       (int64_t)(da_old - da_new), rsvd);
+                       (int64_t)(da_old - da_new), 0);
        }
 done:
        *logflagsp = flags;
@@ -4562,29 +4528,24 @@ xfs_bmapi(
                                if (rt) {
                                        error = xfs_mod_incore_sb(mp,
                                                        XFS_SBS_FREXTENTS,
-                                                       -((int64_t)extsz), (flags &
-                                                       XFS_BMAPI_RSVBLOCKS));
+                                                       -((int64_t)extsz), 0);
                                } else {
                                        error = xfs_icsb_modify_counters(mp,
                                                        XFS_SBS_FDBLOCKS,
-                                                       -((int64_t)alen), (flags &
-                                                       XFS_BMAPI_RSVBLOCKS));
+                                                       -((int64_t)alen), 0);
                                }
                                if (!error) {
                                        error = xfs_icsb_modify_counters(mp,
                                                        XFS_SBS_FDBLOCKS,
-                                                       -((int64_t)indlen), (flags &
-                                                       XFS_BMAPI_RSVBLOCKS));
+                                                       -((int64_t)indlen), 0);
                                        if (error && rt)
                                                xfs_mod_incore_sb(mp,
                                                        XFS_SBS_FREXTENTS,
-                                                       (int64_t)extsz, (flags &
-                                                       XFS_BMAPI_RSVBLOCKS));
+                                                       (int64_t)extsz, 0);
                                        else if (error)
                                                xfs_icsb_modify_counters(mp,
                                                        XFS_SBS_FDBLOCKS,
-                                                       (int64_t)alen, (flags &
-                                                       XFS_BMAPI_RSVBLOCKS));
+                                                       (int64_t)alen, 0);
                                }
 
                                if (error) {
@@ -4701,13 +4662,12 @@ xfs_bmapi(
                                if (!wasdelay && (flags & XFS_BMAPI_PREALLOC))
                                        got.br_state = XFS_EXT_UNWRITTEN;
                        }
-                       error = xfs_bmap_add_extent(ip, lastx, &cur, &got,
+                       error = xfs_bmap_add_extent(ip, &lastx, &cur, &got,
                                firstblock, flist, &tmp_logflags,
-                               whichfork, (flags & XFS_BMAPI_RSVBLOCKS));
+                               whichfork);
                        logflags |= tmp_logflags;
                        if (error)
                                goto error0;
-                       lastx = ifp->if_lastex;
                        ep = xfs_iext_get_ext(ifp, lastx);
                        nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
                        xfs_bmbt_get_all(ep, &got);
@@ -4803,13 +4763,12 @@ xfs_bmapi(
                        mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN)
                                                ? XFS_EXT_NORM
                                                : XFS_EXT_UNWRITTEN;
-                       error = xfs_bmap_add_extent(ip, lastx, &cur, mval,
+                       error = xfs_bmap_add_extent(ip, &lastx, &cur, mval,
                                firstblock, flist, &tmp_logflags,
-                               whichfork, (flags & XFS_BMAPI_RSVBLOCKS));
+                               whichfork);
                        logflags |= tmp_logflags;
                        if (error)
                                goto error0;
-                       lastx = ifp->if_lastex;
                        ep = xfs_iext_get_ext(ifp, lastx);
                        nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
                        xfs_bmbt_get_all(ep, &got);
@@ -4868,14 +4827,14 @@ xfs_bmapi(
                /*
                 * Else go on to the next record.
                 */
-               ep = xfs_iext_get_ext(ifp, ++lastx);
                prev = got;
-               if (lastx >= nextents)
-                       eof = 1;
-               else
+               if (++lastx < nextents) {
+                       ep = xfs_iext_get_ext(ifp, lastx);
                        xfs_bmbt_get_all(ep, &got);
+               } else {
+                       eof = 1;
+               }
        }
-       ifp->if_lastex = lastx;
        *nmap = n;
        /*
         * Transform from btree to extents, give it cur.
@@ -4984,7 +4943,6 @@ xfs_bmapi_single(
        ASSERT(!isnullstartblock(got.br_startblock));
        ASSERT(bno < got.br_startoff + got.br_blockcount);
        *fsb = got.br_startblock + (bno - got.br_startoff);
-       ifp->if_lastex = lastx;
        return 0;
 }
 
@@ -5026,7 +4984,6 @@ xfs_bunmapi(
        int                     tmp_logflags;   /* partial logging flags */
        int                     wasdel;         /* was a delayed alloc extent */
        int                     whichfork;      /* data or attribute fork */
-       int                     rsvd;           /* OK to allocate reserved blocks */
        xfs_fsblock_t           sum;
 
        trace_xfs_bunmap(ip, bno, len, flags, _RET_IP_);
@@ -5044,7 +5001,7 @@ xfs_bunmapi(
        mp = ip->i_mount;
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
-       rsvd = (flags & XFS_BMAPI_RSVBLOCKS) != 0;
+
        ASSERT(len > 0);
        ASSERT(nexts >= 0);
        ASSERT(ifp->if_ext_max ==
@@ -5160,9 +5117,9 @@ xfs_bunmapi(
                                del.br_blockcount = mod;
                        }
                        del.br_state = XFS_EXT_UNWRITTEN;
-                       error = xfs_bmap_add_extent(ip, lastx, &cur, &del,
+                       error = xfs_bmap_add_extent(ip, &lastx, &cur, &del,
                                firstblock, flist, &logflags,
-                               XFS_DATA_FORK, 0);
+                               XFS_DATA_FORK);
                        if (error)
                                goto error0;
                        goto nodelete;
@@ -5188,9 +5145,12 @@ xfs_bunmapi(
                                 */
                                ASSERT(bno >= del.br_blockcount);
                                bno -= del.br_blockcount;
-                               if (bno < got.br_startoff) {
-                                       if (--lastx >= 0)
-                                               xfs_bmbt_get_all(--ep, &got);
+                               if (got.br_startoff > bno) {
+                                       if (--lastx >= 0) {
+                                               ep = xfs_iext_get_ext(ifp,
+                                                                     lastx);
+                                               xfs_bmbt_get_all(ep, &got);
+                                       }
                                }
                                continue;
                        } else if (del.br_state == XFS_EXT_UNWRITTEN) {
@@ -5214,18 +5174,19 @@ xfs_bunmapi(
                                        prev.br_startoff = start;
                                }
                                prev.br_state = XFS_EXT_UNWRITTEN;
-                               error = xfs_bmap_add_extent(ip, lastx - 1, &cur,
+                               lastx--;
+                               error = xfs_bmap_add_extent(ip, &lastx, &cur,
                                        &prev, firstblock, flist, &logflags,
-                                       XFS_DATA_FORK, 0);
+                                       XFS_DATA_FORK);
                                if (error)
                                        goto error0;
                                goto nodelete;
                        } else {
                                ASSERT(del.br_state == XFS_EXT_NORM);
                                del.br_state = XFS_EXT_UNWRITTEN;
-                               error = xfs_bmap_add_extent(ip, lastx, &cur,
+                               error = xfs_bmap_add_extent(ip, &lastx, &cur,
                                        &del, firstblock, flist, &logflags,
-                                       XFS_DATA_FORK, 0);
+                                       XFS_DATA_FORK);
                                if (error)
                                        goto error0;
                                goto nodelete;
@@ -5240,13 +5201,13 @@ xfs_bunmapi(
                                rtexts = XFS_FSB_TO_B(mp, del.br_blockcount);
                                do_div(rtexts, mp->m_sb.sb_rextsize);
                                xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS,
-                                               (int64_t)rtexts, rsvd);
+                                               (int64_t)rtexts, 0);
                                (void)xfs_trans_reserve_quota_nblks(NULL,
                                        ip, -((long)del.br_blockcount), 0,
                                        XFS_QMOPT_RES_RTBLKS);
                        } else {
                                xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS,
-                                               (int64_t)del.br_blockcount, rsvd);
+                                               (int64_t)del.br_blockcount, 0);
                                (void)xfs_trans_reserve_quota_nblks(NULL,
                                        ip, -((long)del.br_blockcount), 0,
                                        XFS_QMOPT_RES_REGBLKS);
@@ -5277,31 +5238,29 @@ xfs_bunmapi(
                        error = XFS_ERROR(ENOSPC);
                        goto error0;
                }
-               error = xfs_bmap_del_extent(ip, tp, lastx, flist, cur, &del,
-                               &tmp_logflags, whichfork, rsvd);
+               error = xfs_bmap_del_extent(ip, tp, &lastx, flist, cur, &del,
+                               &tmp_logflags, whichfork);
                logflags |= tmp_logflags;
                if (error)
                        goto error0;
                bno = del.br_startoff - 1;
 nodelete:
-               lastx = ifp->if_lastex;
                /*
                 * If not done go on to the next (previous) record.
-                * Reset ep in case the extents array was re-alloced.
                 */
-               ep = xfs_iext_get_ext(ifp, lastx);
                if (bno != (xfs_fileoff_t)-1 && bno >= start) {
-                       if (lastx >= XFS_IFORK_NEXTENTS(ip, whichfork) ||
-                           xfs_bmbt_get_startoff(ep) > bno) {
-                               if (--lastx >= 0)
-                                       ep = xfs_iext_get_ext(ifp, lastx);
-                       }
-                       if (lastx >= 0)
+                       if (lastx >= 0) {
+                               ep = xfs_iext_get_ext(ifp, lastx);
+                               if (xfs_bmbt_get_startoff(ep) > bno) {
+                                       if (--lastx >= 0)
+                                               ep = xfs_iext_get_ext(ifp,
+                                                                     lastx);
+                               }
                                xfs_bmbt_get_all(ep, &got);
+                       }
                        extno++;
                }
        }
-       ifp->if_lastex = lastx;
        *done = bno == (xfs_fileoff_t)-1 || bno < start || lastx < 0;
        ASSERT(ifp->if_ext_max ==
               XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
index 3651191daea10cd99bae79443a2b1b9305940250..c62234bde053de008d13d41d40d92f133649e446 100644 (file)
@@ -69,7 +69,6 @@ typedef       struct xfs_bmap_free
 #define XFS_BMAPI_ENTIRE       0x004   /* return entire extent, not trimmed */
 #define XFS_BMAPI_METADATA     0x008   /* mapping metadata not user data */
 #define XFS_BMAPI_ATTRFORK     0x010   /* use attribute fork not data */
-#define XFS_BMAPI_RSVBLOCKS    0x020   /* OK to alloc. reserved data blocks */
 #define        XFS_BMAPI_PREALLOC      0x040   /* preallocation op: unwritten space */
 #define        XFS_BMAPI_IGSTATE       0x080   /* Ignore state - */
                                        /* combine contig. space */
@@ -87,7 +86,6 @@ typedef       struct xfs_bmap_free
        { XFS_BMAPI_ENTIRE,     "ENTIRE" }, \
        { XFS_BMAPI_METADATA,   "METADATA" }, \
        { XFS_BMAPI_ATTRFORK,   "ATTRFORK" }, \
-       { XFS_BMAPI_RSVBLOCKS,  "RSVBLOCKS" }, \
        { XFS_BMAPI_PREALLOC,   "PREALLOC" }, \
        { XFS_BMAPI_IGSTATE,    "IGSTATE" }, \
        { XFS_BMAPI_CONTIG,     "CONTIG" }, \
index cb9b6d1469f7579256061f6de61755c0d6b63df6..3631783b2b5385ee939a61e5cafd5b06ef6b0a45 100644 (file)
@@ -253,16 +253,21 @@ xfs_iget_cache_hit(
                        rcu_read_lock();
                        spin_lock(&ip->i_flags_lock);
 
-                       ip->i_flags &= ~XFS_INEW;
-                       ip->i_flags |= XFS_IRECLAIMABLE;
-                       __xfs_inode_set_reclaim_tag(pag, ip);
+                       ip->i_flags &= ~(XFS_INEW | XFS_IRECLAIM);
+                       ASSERT(ip->i_flags & XFS_IRECLAIMABLE);
                        trace_xfs_iget_reclaim_fail(ip);
                        goto out_error;
                }
 
                spin_lock(&pag->pag_ici_lock);
                spin_lock(&ip->i_flags_lock);
-               ip->i_flags &= ~(XFS_IRECLAIMABLE | XFS_IRECLAIM);
+
+               /*
+                * Clear the per-lifetime state in the inode as we are now
+                * effectively a new inode and need to return to the initial
+                * state before reuse occurs.
+                */
+               ip->i_flags &= ~XFS_IRECLAIM_RESET_FLAGS;
                ip->i_flags |= XFS_INEW;
                __xfs_inode_clear_reclaim_tag(mp, pag, ip);
                inode->i_state = I_NEW;
index c8e3349c287c635275224b65f4200dd99ed5431f..a098a20ca63e29bbd021a266e287d87ca796fd8c 100644 (file)
@@ -920,7 +920,6 @@ xfs_iread_extents(
        /*
         * We know that the size is valid (it's checked in iformat_btree)
         */
-       ifp->if_lastex = NULLEXTNUM;
        ifp->if_bytes = ifp->if_real_bytes = 0;
        ifp->if_flags |= XFS_IFEXTENTS;
        xfs_iext_add(ifp, 0, nextents);
@@ -2558,12 +2557,9 @@ xfs_iflush_fork(
        case XFS_DINODE_FMT_EXTENTS:
                ASSERT((ifp->if_flags & XFS_IFEXTENTS) ||
                       !(iip->ili_format.ilf_fields & extflag[whichfork]));
-               ASSERT((xfs_iext_get_ext(ifp, 0) != NULL) ||
-                       (ifp->if_bytes == 0));
-               ASSERT((xfs_iext_get_ext(ifp, 0) == NULL) ||
-                       (ifp->if_bytes > 0));
                if ((iip->ili_format.ilf_fields & extflag[whichfork]) &&
                    (ifp->if_bytes > 0)) {
+                       ASSERT(xfs_iext_get_ext(ifp, 0));
                        ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0);
                        (void)xfs_iextents_copy(ip, (xfs_bmbt_rec_t *)cp,
                                whichfork);
@@ -3112,6 +3108,8 @@ xfs_iext_get_ext(
        xfs_extnum_t    idx)            /* index of target extent */
 {
        ASSERT(idx >= 0);
+       ASSERT(idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t));
+
        if ((ifp->if_flags & XFS_IFEXTIREC) && (idx == 0)) {
                return ifp->if_u1.if_ext_irec->er_extbuf;
        } else if (ifp->if_flags & XFS_IFEXTIREC) {
@@ -3191,7 +3189,6 @@ xfs_iext_add(
                }
                ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
                ifp->if_real_bytes = 0;
-               ifp->if_lastex = nextents + ext_diff;
        }
        /*
         * Otherwise use a linear (direct) extent list.
@@ -3886,8 +3883,10 @@ xfs_iext_idx_to_irec(
        xfs_extnum_t    page_idx = *idxp; /* extent index in target list */
 
        ASSERT(ifp->if_flags & XFS_IFEXTIREC);
-       ASSERT(page_idx >= 0 && page_idx <=
-               ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t));
+       ASSERT(page_idx >= 0);
+       ASSERT(page_idx <= ifp->if_bytes / sizeof(xfs_bmbt_rec_t));
+       ASSERT(page_idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t) || realloc);
+
        nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
        erp_idx = 0;
        low = 0;
index ff4e2a30227dcb4b86dd69b784a8bb94cca4b5d7..964cfea776868684afb26f818b8a761ce652b1b5 100644 (file)
@@ -67,7 +67,6 @@ typedef struct xfs_ifork {
        short                   if_broot_bytes; /* bytes allocated for root */
        unsigned char           if_flags;       /* per-fork flags */
        unsigned char           if_ext_max;     /* max # of extent records */
-       xfs_extnum_t            if_lastex;      /* last if_extents used */
        union {
                xfs_bmbt_rec_host_t *if_extents;/* linear map file exts */
                xfs_ext_irec_t  *if_ext_irec;   /* irec map file exts */
@@ -384,6 +383,16 @@ static inline void xfs_ifunlock(xfs_inode_t *ip)
 #define XFS_ITRUNCATED         0x0020  /* truncated down so flush-on-close */
 #define XFS_IDIRTY_RELEASE     0x0040  /* dirty release already seen */
 
+/*
+ * Per-lifetime flags need to be reset when re-using a reclaimable inode during
+ * inode lookup. Thi prevents unintended behaviour on the new inode from
+ * ocurring.
+ */
+#define XFS_IRECLAIM_RESET_FLAGS       \
+       (XFS_IRECLAIMABLE | XFS_IRECLAIM | \
+        XFS_IDIRTY_RELEASE | XFS_ITRUNCATED | \
+        XFS_IFILESTREAM);
+
 /*
  * Flags for inode locking.
  * Bit ranges: 1<<1  - 1<<16-1 -- iolock/ilock modes (bitfield)
index 211930246f2073f4759a569936b79ab387003e21..41d5b8f2bf92d3fd3fae9773f667a0bf1cb42381 100644 (file)
@@ -1372,8 +1372,17 @@ xlog_sync(xlog_t         *log,
        XFS_BUF_ASYNC(bp);
        bp->b_flags |= XBF_LOG_BUFFER;
 
-       if (log->l_mp->m_flags & XFS_MOUNT_BARRIER)
+       if (log->l_mp->m_flags & XFS_MOUNT_BARRIER) {
+               /*
+                * If we have an external log device, flush the data device
+                * before flushing the log to make sure all meta data
+                * written back from the AIL actually made it to disk
+                * before writing out the new log tail LSN in the log buffer.
+                */
+               if (log->l_mp->m_logdev_targp != log->l_mp->m_ddev_targp)
+                       xfs_blkdev_issue_flush(log->l_mp->m_ddev_targp);
                XFS_BUF_ORDERED(bp);
+       }
 
        ASSERT(XFS_BUF_ADDR(bp) <= log->l_logBBsize-1);
        ASSERT(XFS_BUF_ADDR(bp) + BTOBB(count) <= log->l_logBBsize);
index 7d56e88a3f0eb6c671e863c4977d2f47a500b830..c7755d5a5fbe967ed58bb04ffcc0d47d082a87e4 100644 (file)
@@ -29,6 +29,7 @@
 #include "xfs_mount.h"
 #include "xfs_error.h"
 #include "xfs_alloc.h"
+#include "xfs_discard.h"
 
 /*
  * Perform initial CIL structure initialisation. If the CIL is not
@@ -361,18 +362,28 @@ xlog_cil_committed(
        int     abort)
 {
        struct xfs_cil_ctx      *ctx = args;
+       struct xfs_mount        *mp = ctx->cil->xc_log->l_mp;
 
        xfs_trans_committed_bulk(ctx->cil->xc_log->l_ailp, ctx->lv_chain,
                                        ctx->start_lsn, abort);
 
        xfs_alloc_busy_sort(&ctx->busy_extents);
-       xfs_alloc_busy_clear(ctx->cil->xc_log->l_mp, &ctx->busy_extents);
+       xfs_alloc_busy_clear(mp, &ctx->busy_extents,
+                            (mp->m_flags & XFS_MOUNT_DISCARD) && !abort);
 
        spin_lock(&ctx->cil->xc_cil_lock);
        list_del(&ctx->committing);
        spin_unlock(&ctx->cil->xc_cil_lock);
 
        xlog_cil_free_logvec(ctx->lv_chain);
+
+       if (!list_empty(&ctx->busy_extents)) {
+               ASSERT(mp->m_flags & XFS_MOUNT_DISCARD);
+
+               xfs_discard_extents(mp, &ctx->busy_extents);
+               xfs_alloc_busy_clear(mp, &ctx->busy_extents, false);
+       }
+
        kmem_free(ctx);
 }
 
index 19af0ab0d0c6c6c1cab862016dbe258263e39d31..3d68bb267c5fc064279c5545cf2039974c89fa7b 100644 (file)
@@ -224,6 +224,7 @@ typedef struct xfs_mount {
 #define XFS_MOUNT_FS_SHUTDOWN  (1ULL << 4)     /* atomic stop of all filesystem
                                                   operations, typically for
                                                   disk errors in metadata */
+#define XFS_MOUNT_DISCARD      (1ULL << 5)     /* discard unused blocks */
 #define XFS_MOUNT_RETERR       (1ULL << 6)     /* return alignment errors to
                                                   user */
 #define XFS_MOUNT_NOALIGN      (1ULL << 7)     /* turn off stripe alignment
index d1f24858ccc4d365db467f8bdbe222ef4511d354..7c7bc2b786bd47d6ec89e31bcf966f6dc5121ec1 100644 (file)
@@ -609,7 +609,7 @@ xfs_trans_free(
        struct xfs_trans        *tp)
 {
        xfs_alloc_busy_sort(&tp->t_busy);
-       xfs_alloc_busy_clear(tp->t_mountp, &tp->t_busy);
+       xfs_alloc_busy_clear(tp->t_mountp, &tp->t_busy, false);
 
        atomic_dec(&tp->t_mountp->m_active_trans);
        xfs_trans_free_dqinfo(tp);
index b7a5fe7c52c895776f125d53851d40c48795dce7..619720705bc6843e4624ce02c27829fa32256ba9 100644 (file)
@@ -960,8 +960,11 @@ xfs_release(
                 * be exposed to that problem.
                 */
                truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED);
-               if (truncated && VN_DIRTY(VFS_I(ip)) && ip->i_delayed_blks > 0)
-                       xfs_flush_pages(ip, 0, -1, XBF_ASYNC, FI_NONE);
+               if (truncated) {
+                       xfs_iflags_clear(ip, XFS_IDIRTY_RELEASE);
+                       if (VN_DIRTY(VFS_I(ip)) && ip->i_delayed_blks > 0)
+                               xfs_flush_pages(ip, 0, -1, XBF_ASYNC, FI_NONE);
+               }
        }
 
        if (ip->i_d.di_nlink == 0)
index a3252a5ead669d360c37c1403c1fa0de9945a50d..a756bc8d866db15af5fbe3c2813e873b48aa48d7 100644 (file)
@@ -98,6 +98,9 @@ acpi_os_table_override(struct acpi_table_header *existing_table,
 /*
  * Spinlock primitives
  */
+acpi_status
+acpi_os_create_lock(acpi_spinlock *out_handle);
+
 void acpi_os_delete_lock(acpi_spinlock handle);
 
 acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock handle);
index f6ad63d25b739fbba1d41eabed483db4abf7feb1..2ed0a8486c1962f979e1f1d7e18b167efee0eb38 100644 (file)
@@ -47,7 +47,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20110316
+#define ACPI_CA_VERSION                 0x20110413
 
 #include "actypes.h"
 #include "actbl.h"
index 64f838beaabffdeead528c4aaf2c4240fb9e9701..b67231bef632714add11abf65eac32c82cda4dd6 100644 (file)
@@ -501,8 +501,9 @@ typedef u64 acpi_integer;
 #define ACPI_STATE_D1                   (u8) 1
 #define ACPI_STATE_D2                   (u8) 2
 #define ACPI_STATE_D3                   (u8) 3
-#define ACPI_D_STATES_MAX               ACPI_STATE_D3
-#define ACPI_D_STATE_COUNT              4
+#define ACPI_STATE_D3_COLD              (u8) 4
+#define ACPI_D_STATES_MAX               ACPI_STATE_D3_COLD
+#define ACPI_D_STATE_COUNT              5
 
 #define ACPI_STATE_C0                   (u8) 0
 #define ACPI_STATE_C1                   (u8) 1
@@ -712,8 +713,24 @@ typedef u8 acpi_adr_space_type;
 #define ACPI_ADR_SPACE_CMOS             (acpi_adr_space_type) 5
 #define ACPI_ADR_SPACE_PCI_BAR_TARGET   (acpi_adr_space_type) 6
 #define ACPI_ADR_SPACE_IPMI             (acpi_adr_space_type) 7
-#define ACPI_ADR_SPACE_DATA_TABLE       (acpi_adr_space_type) 8
-#define ACPI_ADR_SPACE_FIXED_HARDWARE   (acpi_adr_space_type) 127
+
+#define ACPI_NUM_PREDEFINED_REGIONS     8
+
+/*
+ * Special Address Spaces
+ *
+ * Note: A Data Table region is a special type of operation region
+ * that has its own AML opcode. However, internally, the AML
+ * interpreter simply creates an operation region with an an address
+ * space type of ACPI_ADR_SPACE_DATA_TABLE.
+ */
+#define ACPI_ADR_SPACE_DATA_TABLE       (acpi_adr_space_type) 0x7E     /* Internal to ACPICA only */
+#define ACPI_ADR_SPACE_FIXED_HARDWARE   (acpi_adr_space_type) 0x7F
+
+/* Values for _REG connection code */
+
+#define ACPI_REG_DISCONNECT             0
+#define ACPI_REG_CONNECT                1
 
 /*
  * bit_register IDs
index 55192ac0cede7e019e4f4617efd53eefa87424c6..ba4928cae473bbca750affdc71a021e6134e469e 100644 (file)
@@ -310,14 +310,7 @@ static inline int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
 
 /* in processor_core.c */
 void acpi_processor_set_pdc(acpi_handle handle);
-#ifdef CONFIG_SMP
 int acpi_get_cpuid(acpi_handle, int type, u32 acpi_id);
-#else
-static inline int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
-{
-       return -1;
-}
-#endif
 
 /* in processor_throttling.c */
 int acpi_processor_tstate_has_changed(struct acpi_processor *pr);
index bcbab3e4a3be6c802698fe0d1419f02b54a1eba3..89b73e5d0fd0ca626f7b99e5236f20247553ceaf 100644 (file)
@@ -1,4 +1,6 @@
+#ifdef __NR_chmod
 __NR_chmod,
+#endif
 __NR_fchmod,
 #ifdef __NR_chown
 __NR_chown,
@@ -20,7 +22,9 @@ __NR_chown32,
 __NR_fchown32,
 __NR_lchown32,
 #endif
+#ifdef __NR_link
 __NR_link,
+#endif
 #ifdef __NR_linkat
 __NR_linkat,
 #endif
index 6621bd82cbe82319dc075c42f557bfb3c663555a..7b61db4fe72b1cb610674038d8577c82a9f6224f 100644 (file)
@@ -1,13 +1,27 @@
+#ifdef __NR_rename
 __NR_rename,
+#endif
+#ifdef __NR_mkdir
 __NR_mkdir,
+#endif
+#ifdef __NR_rmdir
 __NR_rmdir,
+#endif
 #ifdef __NR_creat
 __NR_creat,
 #endif
+#ifdef __NR_link
 __NR_link,
+#endif
+#ifdef __NR_unlink
 __NR_unlink,
+#endif
+#ifdef __NR_symlink
 __NR_symlink,
+#endif
+#ifdef __NR_mknod
 __NR_mknod,
+#endif
 #ifdef __NR_mkdirat
 __NR_mkdirat,
 __NR_mknodat,
index 0e87464d98471a95a6823b9e215e83cc17fc169e..3b249cb857dc55dfb33dec433d4617318a7bc1ac 100644 (file)
@@ -1,4 +1,6 @@
+#ifdef __NR_readlink
 __NR_readlink,
+#endif
 __NR_quotactl,
 __NR_listxattr,
 __NR_llistxattr,
@@ -6,3 +8,6 @@ __NR_flistxattr,
 __NR_getxattr,
 __NR_lgetxattr,
 __NR_fgetxattr,
+#ifdef __NR_readlinkat
+__NR_readlinkat,
+#endif
index c5f1c2c920e26c033761d640a81256b0b13c13eb..e7020c57b13b8014ba8c28800e8b66dc9ea37cdb 100644 (file)
@@ -4,7 +4,9 @@ __NR_acct,
 __NR_swapon,
 #endif
 __NR_quotactl,
+#ifdef __NR_truncate
 __NR_truncate,
+#endif
 #ifdef __NR_truncate64
 __NR_truncate64,
 #endif
index 110fa700f85380e29397287ef597734f2a366149..71c778033f575e53b106c0fa649202d0a6a5ee3a 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _ASM_GENERIC_BITOPS_FIND_H_
 #define _ASM_GENERIC_BITOPS_FIND_H_
 
+#ifndef find_next_bit
 /**
  * find_next_bit - find the next set bit in a memory region
  * @addr: The address to base the search on
@@ -9,7 +10,9 @@
  */
 extern unsigned long find_next_bit(const unsigned long *addr, unsigned long
                size, unsigned long offset);
+#endif
 
+#ifndef find_next_zero_bit
 /**
  * find_next_zero_bit - find the next cleared bit in a memory region
  * @addr: The address to base the search on
@@ -18,6 +21,7 @@ extern unsigned long find_next_bit(const unsigned long *addr, unsigned long
  */
 extern unsigned long find_next_zero_bit(const unsigned long *addr, unsigned
                long size, unsigned long offset);
+#endif
 
 #ifdef CONFIG_GENERIC_FIND_FIRST_BIT
 
index 946a21b1b5dc66dffae64c4b58f10efaa2e940fd..f95c663a6a4169f6a7ae2258623aeebec6d661c9 100644 (file)
@@ -30,13 +30,20 @@ static inline unsigned long find_first_zero_bit_le(const void *addr,
 
 #define BITOP_LE_SWIZZLE       ((BITS_PER_LONG-1) & ~0x7)
 
+#ifndef find_next_zero_bit_le
 extern unsigned long find_next_zero_bit_le(const void *addr,
                unsigned long size, unsigned long offset);
+#endif
+
+#ifndef find_next_bit_le
 extern unsigned long find_next_bit_le(const void *addr,
                unsigned long size, unsigned long offset);
+#endif
 
+#ifndef find_first_zero_bit_le
 #define find_first_zero_bit_le(addr, size) \
        find_next_zero_bit_le((addr), (size), 0)
+#endif
 
 #else
 #error "Please fix <asm/byteorder.h>"
index e5a3f588000173d8e9da0f8ae00c98dc275d63b1..dfb0ec666c9441d08ab1e81166e27c6a290b56c9 100644 (file)
@@ -162,9 +162,6 @@ extern void warn_slowpath_null(const char *file, const int line);
        unlikely(__ret_warn_once);                              \
 })
 
-#define WARN_ON_RATELIMIT(condition, state)                    \
-               WARN_ON((condition) && __ratelimit(state))
-
 /*
  * WARN_ON_SMP() is for cases that the warning is either
  * meaningless for !SMP or may even cause failures.
index 57b5c3c82e86a8e2e7b875e49dc1641ca20fb7aa..87bc536ccde3cedb139a892e692e83ee45a12cfe 100644 (file)
 #define flush_cache_vunmap(start, end)         do { } while (0)
 
 #define copy_to_user_page(vma, page, vaddr, dst, src, len) \
-       memcpy(dst, src, len)
+       do { \
+               memcpy(dst, src, len); \
+               flush_icache_user_range(vma, page, vaddr, len); \
+       } while (0)
 #define copy_from_user_page(vma, page, vaddr, dst, src, len) \
        memcpy(dst, src, len)
 
index ff5c66080c8c947e64edd2c8db17436d98921ad7..d494001b12260a2f56b9337e01226f17dcee3634 100644 (file)
@@ -35,9 +35,9 @@
  * platform data and other tables.
  */
 
-static inline int gpio_is_valid(int number)
+static inline bool gpio_is_valid(int number)
 {
-       return ((unsigned)number) < ARCH_NR_GPIOS;
+       return number >= 0 && number < ARCH_NR_GPIOS;
 }
 
 struct device;
@@ -170,16 +170,6 @@ extern int __gpio_cansleep(unsigned gpio);
 
 extern int __gpio_to_irq(unsigned gpio);
 
-#define GPIOF_DIR_OUT  (0 << 0)
-#define GPIOF_DIR_IN   (1 << 0)
-
-#define GPIOF_INIT_LOW (0 << 1)
-#define GPIOF_INIT_HIGH        (1 << 1)
-
-#define GPIOF_IN               (GPIOF_DIR_IN)
-#define GPIOF_OUT_INIT_LOW     (GPIOF_DIR_OUT | GPIOF_INIT_LOW)
-#define GPIOF_OUT_INIT_HIGH    (GPIOF_DIR_OUT | GPIOF_INIT_HIGH)
-
 /**
  * struct gpio - a structure describing a GPIO with configuration
  * @gpio:      the GPIO number
@@ -193,8 +183,8 @@ struct gpio {
 };
 
 extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
-extern int gpio_request_array(struct gpio *array, size_t num);
-extern void gpio_free_array(struct gpio *array, size_t num);
+extern int gpio_request_array(const struct gpio *array, size_t num);
+extern void gpio_free_array(const struct gpio *array, size_t num);
 
 #ifdef CONFIG_GPIO_SYSFS
 
@@ -212,7 +202,7 @@ extern void gpio_unexport(unsigned gpio);
 
 #else  /* !CONFIG_GPIOLIB */
 
-static inline int gpio_is_valid(int number)
+static inline bool gpio_is_valid(int number)
 {
        /* only non-negative numbers are valid */
        return number >= 0;
index b4bfe338ea0e568258bc66ffffa4b03c6e51ca6d..76bff2bff15e346532be60dc1ce1a13aff070471 100644 (file)
@@ -88,7 +88,7 @@ static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm,
        pmd_t pmd = *pmdp;
        pmd_clear(mm, address, pmdp);
        return pmd;
-})
+}
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 #endif
 
@@ -184,22 +184,18 @@ static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b)
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 #endif
 
-#ifndef __HAVE_ARCH_PAGE_TEST_DIRTY
-#define page_test_dirty(page)          (0)
-#endif
-
-#ifndef __HAVE_ARCH_PAGE_CLEAR_DIRTY
-#define page_clear_dirty(page, mapped) do { } while (0)
+#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY
+#define page_test_and_clear_dirty(pfn, mapped) (0)
 #endif
 
-#ifndef __HAVE_ARCH_PAGE_TEST_DIRTY
+#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY
 #define pte_maybe_dirty(pte)           pte_dirty(pte)
 #else
 #define pte_maybe_dirty(pte)           (1)
 #endif
 
 #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
-#define page_test_and_clear_young(page) (0)
+#define page_test_and_clear_young(pfn) (0)
 #endif
 
 #ifndef __HAVE_ARCH_PGD_OFFSET_GATE
diff --git a/include/asm-generic/ptrace.h b/include/asm-generic/ptrace.h
new file mode 100644 (file)
index 0000000..82e674f
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Common low level (register) ptrace helpers
+ *
+ * Copyright 2004-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __ASM_GENERIC_PTRACE_H__
+#define __ASM_GENERIC_PTRACE_H__
+
+#ifndef __ASSEMBLY__
+
+/* Helpers for working with the instruction pointer */
+#ifndef GET_IP
+#define GET_IP(regs) ((regs)->pc)
+#endif
+#ifndef SET_IP
+#define SET_IP(regs, val) (GET_IP(regs) = (val))
+#endif
+
+static inline unsigned long instruction_pointer(struct pt_regs *regs)
+{
+       return GET_IP(regs);
+}
+static inline void instruction_pointer_set(struct pt_regs *regs,
+                                           unsigned long val)
+{
+       SET_IP(regs, val);
+}
+
+#ifndef profile_pc
+#define profile_pc(regs) instruction_pointer(regs)
+#endif
+
+/* Helpers for working with the user stack pointer */
+#ifndef GET_USP
+#define GET_USP(regs) ((regs)->usp)
+#endif
+#ifndef SET_USP
+#define SET_USP(regs, val) (GET_USP(regs) = (val))
+#endif
+
+static inline unsigned long user_stack_pointer(struct pt_regs *regs)
+{
+       return GET_USP(regs);
+}
+static inline void user_stack_pointer_set(struct pt_regs *regs,
+                                          unsigned long val)
+{
+       SET_USP(regs, val);
+}
+
+/* Helpers for working with the frame pointer */
+#ifndef GET_FP
+#define GET_FP(regs) ((regs)->fp)
+#endif
+#ifndef SET_FP
+#define SET_FP(regs, val) (GET_FP(regs) = (val))
+#endif
+
+static inline unsigned long frame_pointer(struct pt_regs *regs)
+{
+       return GET_FP(regs);
+}
+static inline void frame_pointer_set(struct pt_regs *regs,
+                                     unsigned long val)
+{
+       SET_FP(regs, val);
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif
index 587566f95f6ccd61eb3931097542b37a9c769138..61fa862fe08d61fb326bd66c20e31c567e3fb6f8 100644 (file)
@@ -78,7 +78,7 @@
        [RLIMIT_CORE]           = {              0,  RLIM_INFINITY },   \
        [RLIMIT_RSS]            = {  RLIM_INFINITY,  RLIM_INFINITY },   \
        [RLIMIT_NPROC]          = {              0,              0 },   \
-       [RLIMIT_NOFILE]         = {       INR_OPEN,       INR_OPEN },   \
+       [RLIMIT_NOFILE]         = {   INR_OPEN_CUR,   INR_OPEN_MAX },   \
        [RLIMIT_MEMLOCK]        = {    MLOCK_LIMIT,    MLOCK_LIMIT },   \
        [RLIMIT_AS]             = {  RLIM_INFINITY,  RLIM_INFINITY },   \
        [RLIMIT_LOCKS]          = {  RLIM_INFINITY,  RLIM_INFINITY },   \
index e43f9766259f301b2087e83d70a1e563e568edbd..e58fa777fa09abe91831026852bfe21bdfa4f8d4 100644 (file)
@@ -5,6 +5,8 @@
  * Copyright 2001 Red Hat, Inc.
  * Based on code from mm/memory.c Copyright Linus Torvalds and others.
  *
+ * Copyright 2011 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.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
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
 /*
- * For UP we don't need to worry about TLB flush
- * and page free order so much..
+ * Semi RCU freeing of the page directories.
+ *
+ * This is needed by some architectures to implement software pagetable walkers.
+ *
+ * gup_fast() and other software pagetable walkers do a lockless page-table
+ * walk and therefore needs some synchronization with the freeing of the page
+ * directories. The chosen means to accomplish that is by disabling IRQs over
+ * the walk.
+ *
+ * Architectures that use IPIs to flush TLBs will then automagically DTRT,
+ * since we unlink the page, flush TLBs, free the page. Since the disabling of
+ * IRQs delays the completion of the TLB flush we can never observe an already
+ * freed page.
+ *
+ * Architectures that do not have this (PPC) need to delay the freeing by some
+ * other means, this is that means.
+ *
+ * What we do is batch the freed directory pages (tables) and RCU free them.
+ * We use the sched RCU variant, as that guarantees that IRQ/preempt disabling
+ * holds off grace periods.
+ *
+ * However, in order to batch these pages we need to allocate storage, this
+ * allocation is deep inside the MM code and can thus easily fail on memory
+ * pressure. To guarantee progress we fall back to single table freeing, see
+ * the implementation of tlb_remove_table_one().
+ *
  */
-#ifdef CONFIG_SMP
-  #ifdef ARCH_FREE_PTR_NR
-    #define FREE_PTR_NR   ARCH_FREE_PTR_NR
-  #else
-    #define FREE_PTE_NR        506
-  #endif
-  #define tlb_fast_mode(tlb) ((tlb)->nr == ~0U)
-#else
-  #define FREE_PTE_NR  1
-  #define tlb_fast_mode(tlb) 1
+struct mmu_table_batch {
+       struct rcu_head         rcu;
+       unsigned int            nr;
+       void                    *tables[0];
+};
+
+#define MAX_TABLE_BATCH                \
+       ((PAGE_SIZE - sizeof(struct mmu_table_batch)) / sizeof(void *))
+
+extern void tlb_table_flush(struct mmu_gather *tlb);
+extern void tlb_remove_table(struct mmu_gather *tlb, void *table);
+
 #endif
 
-/* struct mmu_gather is an opaque type used by the mm code for passing around
- * any data needed by arch specific code for tlb_remove_page.
+/*
+ * If we can't allocate a page to make a big batch of page pointers
+ * to work on, then just handle a few from the on-stack structure.
  */
-struct mmu_gather {
-       struct mm_struct        *mm;
-       unsigned int            nr;     /* set to ~0U means fast mode */
-       unsigned int            need_flush;/* Really unmapped some ptes? */
-       unsigned int            fullmm; /* non-zero means full mm flush */
-       struct page *           pages[FREE_PTE_NR];
+#define MMU_GATHER_BUNDLE      8
+
+struct mmu_gather_batch {
+       struct mmu_gather_batch *next;
+       unsigned int            nr;
+       unsigned int            max;
+       struct page             *pages[0];
 };
 
-/* Users of the generic TLB shootdown code must declare this storage space. */
-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
+#define MAX_GATHER_BATCH       \
+       ((PAGE_SIZE - sizeof(struct mmu_gather_batch)) / sizeof(void *))
 
-/* tlb_gather_mmu
- *     Return a pointer to an initialized struct mmu_gather.
+/* struct mmu_gather is an opaque type used by the mm code for passing around
+ * any data needed by arch specific code for tlb_remove_page.
  */
-static inline struct mmu_gather *
-tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
-{
-       struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
-
-       tlb->mm = mm;
+struct mmu_gather {
+       struct mm_struct        *mm;
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+       struct mmu_table_batch  *batch;
+#endif
+       unsigned int            need_flush : 1, /* Did free PTEs */
+                               fast_mode  : 1; /* No batching   */
 
-       /* Use fast mode if only one CPU is online */
-       tlb->nr = num_online_cpus() > 1 ? 0U : ~0U;
+       unsigned int            fullmm;
 
-       tlb->fullmm = full_mm_flush;
+       struct mmu_gather_batch *active;
+       struct mmu_gather_batch local;
+       struct page             *__pages[MMU_GATHER_BUNDLE];
+};
 
-       return tlb;
-}
+#define HAVE_GENERIC_MMU_GATHER
 
-static inline void
-tlb_flush_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
+static inline int tlb_fast_mode(struct mmu_gather *tlb)
 {
-       if (!tlb->need_flush)
-               return;
-       tlb->need_flush = 0;
-       tlb_flush(tlb);
-       if (!tlb_fast_mode(tlb)) {
-               free_pages_and_swap_cache(tlb->pages, tlb->nr);
-               tlb->nr = 0;
-       }
+#ifdef CONFIG_SMP
+       return tlb->fast_mode;
+#else
+       /*
+        * For UP we don't need to worry about TLB flush
+        * and page free order so much..
+        */
+       return 1;
+#endif
 }
 
-/* tlb_finish_mmu
- *     Called at the end of the shootdown operation to free up any resources
- *     that were required.
- */
-static inline void
-tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
-{
-       tlb_flush_mmu(tlb, start, end);
-
-       /* keep the page table cache within bounds */
-       check_pgt_cache();
-
-       put_cpu_var(mmu_gathers);
-}
+void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm);
+void tlb_flush_mmu(struct mmu_gather *tlb);
+void tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end);
+int __tlb_remove_page(struct mmu_gather *tlb, struct page *page);
 
 /* tlb_remove_page
- *     Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), while
- *     handling the additional races in SMP caused by other CPUs caching valid
- *     mappings in their TLBs.
+ *     Similar to __tlb_remove_page but will call tlb_flush_mmu() itself when
+ *     required.
  */
 static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
 {
-       tlb->need_flush = 1;
-       if (tlb_fast_mode(tlb)) {
-               free_page_and_swap_cache(page);
-               return;
-       }
-       tlb->pages[tlb->nr++] = page;
-       if (tlb->nr >= FREE_PTE_NR)
-               tlb_flush_mmu(tlb, 0, 0);
+       if (!__tlb_remove_page(tlb, page))
+               tlb_flush_mmu(tlb);
 }
 
 /**
index 07c40d5149de41ee263a450db1141781f806f44b..4f76959397fa88a869dff276ba5ab0ccc9494071 100644 (file)
 #define __SC_3264(_nr, _32, _64) __SYSCALL(_nr, _64)
 #endif
 
+#ifdef __SYSCALL_COMPAT
+#define __SC_COMP(_nr, _sys, _comp) __SYSCALL(_nr, _comp)
+#define __SC_COMP_3264(_nr, _32, _64, _comp) __SYSCALL(_nr, _comp)
+#else
+#define __SC_COMP(_nr, _sys, _comp) __SYSCALL(_nr, _sys)
+#define __SC_COMP_3264(_nr, _32, _64, _comp) __SC_3264(_nr, _32, _64)
+#endif
+
 #define __NR_io_setup 0
-__SYSCALL(__NR_io_setup, sys_io_setup)
+__SC_COMP(__NR_io_setup, sys_io_setup, compat_sys_io_setup)
 #define __NR_io_destroy 1
 __SYSCALL(__NR_io_destroy, sys_io_destroy)
 #define __NR_io_submit 2
-__SYSCALL(__NR_io_submit, sys_io_submit)
+__SC_COMP(__NR_io_submit, sys_io_submit, compat_sys_io_submit)
 #define __NR_io_cancel 3
 __SYSCALL(__NR_io_cancel, sys_io_cancel)
 #define __NR_io_getevents 4
-__SYSCALL(__NR_io_getevents, sys_io_getevents)
+__SC_COMP(__NR_io_getevents, sys_io_getevents, compat_sys_io_getevents)
 
 /* fs/xattr.c */
 #define __NR_setxattr 5
@@ -67,7 +75,7 @@ __SYSCALL(__NR_getcwd, sys_getcwd)
 
 /* fs/cookies.c */
 #define __NR_lookup_dcookie 18
-__SYSCALL(__NR_lookup_dcookie, sys_lookup_dcookie)
+__SC_COMP(__NR_lookup_dcookie, sys_lookup_dcookie, compat_sys_lookup_dcookie)
 
 /* fs/eventfd.c */
 #define __NR_eventfd2 19
@@ -79,7 +87,7 @@ __SYSCALL(__NR_epoll_create1, sys_epoll_create1)
 #define __NR_epoll_ctl 21
 __SYSCALL(__NR_epoll_ctl, sys_epoll_ctl)
 #define __NR_epoll_pwait 22
-__SYSCALL(__NR_epoll_pwait, sys_epoll_pwait)
+__SC_COMP(__NR_epoll_pwait, sys_epoll_pwait, compat_sys_epoll_pwait)
 
 /* fs/fcntl.c */
 #define __NR_dup 23
@@ -87,7 +95,7 @@ __SYSCALL(__NR_dup, sys_dup)
 #define __NR_dup3 24
 __SYSCALL(__NR_dup3, sys_dup3)
 #define __NR3264_fcntl 25
-__SC_3264(__NR3264_fcntl, sys_fcntl64, sys_fcntl)
+__SC_COMP_3264(__NR3264_fcntl, sys_fcntl64, sys_fcntl, compat_sys_fcntl64)
 
 /* fs/inotify_user.c */
 #define __NR_inotify_init1 26
@@ -99,7 +107,7 @@ __SYSCALL(__NR_inotify_rm_watch, sys_inotify_rm_watch)
 
 /* fs/ioctl.c */
 #define __NR_ioctl 29
-__SYSCALL(__NR_ioctl, sys_ioctl)
+__SC_COMP(__NR_ioctl, sys_ioctl, compat_sys_ioctl)
 
 /* fs/ioprio.c */
 #define __NR_ioprio_set 30
@@ -129,26 +137,30 @@ __SYSCALL(__NR_renameat, sys_renameat)
 #define __NR_umount2 39
 __SYSCALL(__NR_umount2, sys_umount)
 #define __NR_mount 40
-__SYSCALL(__NR_mount, sys_mount)
+__SC_COMP(__NR_mount, sys_mount, compat_sys_mount)
 #define __NR_pivot_root 41
 __SYSCALL(__NR_pivot_root, sys_pivot_root)
 
 /* fs/nfsctl.c */
 #define __NR_nfsservctl 42
-__SYSCALL(__NR_nfsservctl, sys_nfsservctl)
+__SC_COMP(__NR_nfsservctl, sys_nfsservctl, compat_sys_nfsservctl)
 
 /* fs/open.c */
 #define __NR3264_statfs 43
-__SC_3264(__NR3264_statfs, sys_statfs64, sys_statfs)
+__SC_COMP_3264(__NR3264_statfs, sys_statfs64, sys_statfs, \
+              compat_sys_statfs64)
 #define __NR3264_fstatfs 44
-__SC_3264(__NR3264_fstatfs, sys_fstatfs64, sys_fstatfs)
+__SC_COMP_3264(__NR3264_fstatfs, sys_fstatfs64, sys_fstatfs, \
+              compat_sys_fstatfs64)
 #define __NR3264_truncate 45
-__SC_3264(__NR3264_truncate, sys_truncate64, sys_truncate)
+__SC_COMP_3264(__NR3264_truncate, sys_truncate64, sys_truncate, \
+              compat_sys_truncate64)
 #define __NR3264_ftruncate 46
-__SC_3264(__NR3264_ftruncate, sys_ftruncate64, sys_ftruncate)
+__SC_COMP_3264(__NR3264_ftruncate, sys_ftruncate64, sys_ftruncate, \
+              compat_sys_ftruncate64)
 
 #define __NR_fallocate 47
-__SYSCALL(__NR_fallocate, sys_fallocate)
+__SC_COMP(__NR_fallocate, sys_fallocate, compat_sys_fallocate)
 #define __NR_faccessat 48
 __SYSCALL(__NR_faccessat, sys_faccessat)
 #define __NR_chdir 49
@@ -166,7 +178,7 @@ __SYSCALL(__NR_fchownat, sys_fchownat)
 #define __NR_fchown 55
 __SYSCALL(__NR_fchown, sys_fchown)
 #define __NR_openat 56
-__SYSCALL(__NR_openat, sys_openat)
+__SC_COMP(__NR_openat, sys_openat, compat_sys_openat)
 #define __NR_close 57
 __SYSCALL(__NR_close, sys_close)
 #define __NR_vhangup 58
@@ -182,7 +194,7 @@ __SYSCALL(__NR_quotactl, sys_quotactl)
 
 /* fs/readdir.c */
 #define __NR_getdents64 61
-__SYSCALL(__NR_getdents64, sys_getdents64)
+__SC_COMP(__NR_getdents64, sys_getdents64, compat_sys_getdents64)
 
 /* fs/read_write.c */
 #define __NR3264_lseek 62
@@ -192,17 +204,17 @@ __SYSCALL(__NR_read, sys_read)
 #define __NR_write 64
 __SYSCALL(__NR_write, sys_write)
 #define __NR_readv 65
-__SYSCALL(__NR_readv, sys_readv)
+__SC_COMP(__NR_readv, sys_readv, compat_sys_readv)
 #define __NR_writev 66
-__SYSCALL(__NR_writev, sys_writev)
+__SC_COMP(__NR_writev, sys_writev, compat_sys_writev)
 #define __NR_pread64 67
-__SYSCALL(__NR_pread64, sys_pread64)
+__SC_COMP(__NR_pread64, sys_pread64, compat_sys_pread64)
 #define __NR_pwrite64 68
-__SYSCALL(__NR_pwrite64, sys_pwrite64)
+__SC_COMP(__NR_pwrite64, sys_pwrite64, compat_sys_pwrite64)
 #define __NR_preadv 69
-__SYSCALL(__NR_preadv, sys_preadv)
+__SC_COMP(__NR_preadv, sys_preadv, compat_sys_preadv)
 #define __NR_pwritev 70
-__SYSCALL(__NR_pwritev, sys_pwritev)
+__SC_COMP(__NR_pwritev, sys_pwritev, compat_sys_pwritev)
 
 /* fs/sendfile.c */
 #define __NR3264_sendfile 71
@@ -210,17 +222,17 @@ __SC_3264(__NR3264_sendfile, sys_sendfile64, sys_sendfile)
 
 /* fs/select.c */
 #define __NR_pselect6 72
-__SYSCALL(__NR_pselect6, sys_pselect6)
+__SC_COMP(__NR_pselect6, sys_pselect6, compat_sys_pselect6)
 #define __NR_ppoll 73
-__SYSCALL(__NR_ppoll, sys_ppoll)
+__SC_COMP(__NR_ppoll, sys_ppoll, compat_sys_ppoll)
 
 /* fs/signalfd.c */
 #define __NR_signalfd4 74
-__SYSCALL(__NR_signalfd4, sys_signalfd4)
+__SC_COMP(__NR_signalfd4, sys_signalfd4, compat_sys_signalfd4)
 
 /* fs/splice.c */
 #define __NR_vmsplice 75
-__SYSCALL(__NR_vmsplice, sys_vmsplice)
+__SC_COMP(__NR_vmsplice, sys_vmsplice, compat_sys_vmsplice)
 #define __NR_splice 76
 __SYSCALL(__NR_splice, sys_splice)
 #define __NR_tee 77
@@ -243,23 +255,27 @@ __SYSCALL(__NR_fsync, sys_fsync)
 __SYSCALL(__NR_fdatasync, sys_fdatasync)
 #ifdef __ARCH_WANT_SYNC_FILE_RANGE2
 #define __NR_sync_file_range2 84
-__SYSCALL(__NR_sync_file_range2, sys_sync_file_range2)
+__SC_COMP(__NR_sync_file_range2, sys_sync_file_range2, \
+         compat_sys_sync_file_range2)
 #else
 #define __NR_sync_file_range 84
-__SYSCALL(__NR_sync_file_range, sys_sync_file_range)
+__SC_COMP(__NR_sync_file_range, sys_sync_file_range, \
+         compat_sys_sync_file_range)
 #endif
 
 /* fs/timerfd.c */
 #define __NR_timerfd_create 85
 __SYSCALL(__NR_timerfd_create, sys_timerfd_create)
 #define __NR_timerfd_settime 86
-__SYSCALL(__NR_timerfd_settime, sys_timerfd_settime)
+__SC_COMP(__NR_timerfd_settime, sys_timerfd_settime, \
+         compat_sys_timerfd_settime)
 #define __NR_timerfd_gettime 87
-__SYSCALL(__NR_timerfd_gettime, sys_timerfd_gettime)
+__SC_COMP(__NR_timerfd_gettime, sys_timerfd_gettime, \
+         compat_sys_timerfd_gettime)
 
 /* fs/utimes.c */
 #define __NR_utimensat 88
-__SYSCALL(__NR_utimensat, sys_utimensat)
+__SC_COMP(__NR_utimensat, sys_utimensat, compat_sys_utimensat)
 
 /* kernel/acct.c */
 #define __NR_acct 89
@@ -281,7 +297,7 @@ __SYSCALL(__NR_exit, sys_exit)
 #define __NR_exit_group 94
 __SYSCALL(__NR_exit_group, sys_exit_group)
 #define __NR_waitid 95
-__SYSCALL(__NR_waitid, sys_waitid)
+__SC_COMP(__NR_waitid, sys_waitid, compat_sys_waitid)
 
 /* kernel/fork.c */
 #define __NR_set_tid_address 96
@@ -291,25 +307,27 @@ __SYSCALL(__NR_unshare, sys_unshare)
 
 /* kernel/futex.c */
 #define __NR_futex 98
-__SYSCALL(__NR_futex, sys_futex)
+__SC_COMP(__NR_futex, sys_futex, compat_sys_futex)
 #define __NR_set_robust_list 99
-__SYSCALL(__NR_set_robust_list, sys_set_robust_list)
+__SC_COMP(__NR_set_robust_list, sys_set_robust_list, \
+         compat_sys_set_robust_list)
 #define __NR_get_robust_list 100
-__SYSCALL(__NR_get_robust_list, sys_get_robust_list)
+__SC_COMP(__NR_get_robust_list, sys_get_robust_list, \
+         compat_sys_get_robust_list)
 
 /* kernel/hrtimer.c */
 #define __NR_nanosleep 101
-__SYSCALL(__NR_nanosleep, sys_nanosleep)
+__SC_COMP(__NR_nanosleep, sys_nanosleep, compat_sys_nanosleep)
 
 /* kernel/itimer.c */
 #define __NR_getitimer 102
-__SYSCALL(__NR_getitimer, sys_getitimer)
+__SC_COMP(__NR_getitimer, sys_getitimer, compat_sys_getitimer)
 #define __NR_setitimer 103
-__SYSCALL(__NR_setitimer, sys_setitimer)
+__SC_COMP(__NR_setitimer, sys_setitimer, compat_sys_setitimer)
 
 /* kernel/kexec.c */
 #define __NR_kexec_load 104
-__SYSCALL(__NR_kexec_load, sys_kexec_load)
+__SC_COMP(__NR_kexec_load, sys_kexec_load, compat_sys_kexec_load)
 
 /* kernel/module.c */
 #define __NR_init_module 105
@@ -319,23 +337,24 @@ __SYSCALL(__NR_delete_module, sys_delete_module)
 
 /* kernel/posix-timers.c */
 #define __NR_timer_create 107
-__SYSCALL(__NR_timer_create, sys_timer_create)
+__SC_COMP(__NR_timer_create, sys_timer_create, compat_sys_timer_create)
 #define __NR_timer_gettime 108
-__SYSCALL(__NR_timer_gettime, sys_timer_gettime)
+__SC_COMP(__NR_timer_gettime, sys_timer_gettime, compat_sys_timer_gettime)
 #define __NR_timer_getoverrun 109
 __SYSCALL(__NR_timer_getoverrun, sys_timer_getoverrun)
 #define __NR_timer_settime 110
-__SYSCALL(__NR_timer_settime, sys_timer_settime)
+__SC_COMP(__NR_timer_settime, sys_timer_settime, compat_sys_timer_settime)
 #define __NR_timer_delete 111
 __SYSCALL(__NR_timer_delete, sys_timer_delete)
 #define __NR_clock_settime 112
-__SYSCALL(__NR_clock_settime, sys_clock_settime)
+__SC_COMP(__NR_clock_settime, sys_clock_settime, compat_sys_clock_settime)
 #define __NR_clock_gettime 113
-__SYSCALL(__NR_clock_gettime, sys_clock_gettime)
+__SC_COMP(__NR_clock_gettime, sys_clock_gettime, compat_sys_clock_gettime)
 #define __NR_clock_getres 114
-__SYSCALL(__NR_clock_getres, sys_clock_getres)
+__SC_COMP(__NR_clock_getres, sys_clock_getres, compat_sys_clock_getres)
 #define __NR_clock_nanosleep 115
-__SYSCALL(__NR_clock_nanosleep, sys_clock_nanosleep)
+__SC_COMP(__NR_clock_nanosleep, sys_clock_nanosleep, \
+         compat_sys_clock_nanosleep)
 
 /* kernel/printk.c */
 #define __NR_syslog 116
@@ -355,9 +374,11 @@ __SYSCALL(__NR_sched_getscheduler, sys_sched_getscheduler)
 #define __NR_sched_getparam 121
 __SYSCALL(__NR_sched_getparam, sys_sched_getparam)
 #define __NR_sched_setaffinity 122
-__SYSCALL(__NR_sched_setaffinity, sys_sched_setaffinity)
+__SC_COMP(__NR_sched_setaffinity, sys_sched_setaffinity, \
+         compat_sys_sched_setaffinity)
 #define __NR_sched_getaffinity 123
-__SYSCALL(__NR_sched_getaffinity, sys_sched_getaffinity)
+__SC_COMP(__NR_sched_getaffinity, sys_sched_getaffinity, \
+         compat_sys_sched_getaffinity)
 #define __NR_sched_yield 124
 __SYSCALL(__NR_sched_yield, sys_sched_yield)
 #define __NR_sched_get_priority_max 125
@@ -365,7 +386,8 @@ __SYSCALL(__NR_sched_get_priority_max, sys_sched_get_priority_max)
 #define __NR_sched_get_priority_min 126
 __SYSCALL(__NR_sched_get_priority_min, sys_sched_get_priority_min)
 #define __NR_sched_rr_get_interval 127
-__SYSCALL(__NR_sched_rr_get_interval, sys_sched_rr_get_interval)
+__SC_COMP(__NR_sched_rr_get_interval, sys_sched_rr_get_interval, \
+         compat_sys_sched_rr_get_interval)
 
 /* kernel/signal.c */
 #define __NR_restart_syscall 128
@@ -377,21 +399,23 @@ __SYSCALL(__NR_tkill, sys_tkill)
 #define __NR_tgkill 131
 __SYSCALL(__NR_tgkill, sys_tgkill)
 #define __NR_sigaltstack 132
-__SYSCALL(__NR_sigaltstack, sys_sigaltstack)
+__SC_COMP(__NR_sigaltstack, sys_sigaltstack, compat_sys_sigaltstack)
 #define __NR_rt_sigsuspend 133
-__SYSCALL(__NR_rt_sigsuspend, sys_rt_sigsuspend) /* __ARCH_WANT_SYS_RT_SIGSUSPEND */
+__SC_COMP(__NR_rt_sigsuspend, sys_rt_sigsuspend, compat_sys_rt_sigsuspend)
 #define __NR_rt_sigaction 134
-__SYSCALL(__NR_rt_sigaction, sys_rt_sigaction) /* __ARCH_WANT_SYS_RT_SIGACTION */
+__SC_COMP(__NR_rt_sigaction, sys_rt_sigaction, compat_sys_rt_sigaction)
 #define __NR_rt_sigprocmask 135
 __SYSCALL(__NR_rt_sigprocmask, sys_rt_sigprocmask)
 #define __NR_rt_sigpending 136
 __SYSCALL(__NR_rt_sigpending, sys_rt_sigpending)
 #define __NR_rt_sigtimedwait 137
-__SYSCALL(__NR_rt_sigtimedwait, sys_rt_sigtimedwait)
+__SC_COMP(__NR_rt_sigtimedwait, sys_rt_sigtimedwait, \
+         compat_sys_rt_sigtimedwait)
 #define __NR_rt_sigqueueinfo 138
-__SYSCALL(__NR_rt_sigqueueinfo, sys_rt_sigqueueinfo)
+__SC_COMP(__NR_rt_sigqueueinfo, sys_rt_sigqueueinfo, \
+         compat_sys_rt_sigqueueinfo)
 #define __NR_rt_sigreturn 139
-__SYSCALL(__NR_rt_sigreturn, sys_rt_sigreturn) /* sys_rt_sigreturn_wrapper, */
+__SC_COMP(__NR_rt_sigreturn, sys_rt_sigreturn, compat_sys_rt_sigreturn)
 
 /* kernel/sys.c */
 #define __NR_setpriority 140
@@ -421,7 +445,7 @@ __SYSCALL(__NR_setfsuid, sys_setfsuid)
 #define __NR_setfsgid 152
 __SYSCALL(__NR_setfsgid, sys_setfsgid)
 #define __NR_times 153
-__SYSCALL(__NR_times, sys_times)
+__SC_COMP(__NR_times, sys_times, compat_sys_times)
 #define __NR_setpgid 154
 __SYSCALL(__NR_setpgid, sys_setpgid)
 #define __NR_getpgid 155
@@ -441,11 +465,11 @@ __SYSCALL(__NR_sethostname, sys_sethostname)
 #define __NR_setdomainname 162
 __SYSCALL(__NR_setdomainname, sys_setdomainname)
 #define __NR_getrlimit 163
-__SYSCALL(__NR_getrlimit, sys_getrlimit)
+__SC_COMP(__NR_getrlimit, sys_getrlimit, compat_sys_getrlimit)
 #define __NR_setrlimit 164
-__SYSCALL(__NR_setrlimit, sys_setrlimit)
+__SC_COMP(__NR_setrlimit, sys_setrlimit, compat_sys_setrlimit)
 #define __NR_getrusage 165
-__SYSCALL(__NR_getrusage, sys_getrusage)
+__SC_COMP(__NR_getrusage, sys_getrusage, compat_sys_getrusage)
 #define __NR_umask 166
 __SYSCALL(__NR_umask, sys_umask)
 #define __NR_prctl 167
@@ -455,11 +479,11 @@ __SYSCALL(__NR_getcpu, sys_getcpu)
 
 /* kernel/time.c */
 #define __NR_gettimeofday 169
-__SYSCALL(__NR_gettimeofday, sys_gettimeofday)
+__SC_COMP(__NR_gettimeofday, sys_gettimeofday, compat_sys_gettimeofday)
 #define __NR_settimeofday 170
-__SYSCALL(__NR_settimeofday, sys_settimeofday)
+__SC_COMP(__NR_settimeofday, sys_settimeofday, compat_sys_settimeofday)
 #define __NR_adjtimex 171
-__SYSCALL(__NR_adjtimex, sys_adjtimex)
+__SC_COMP(__NR_adjtimex, sys_adjtimex, compat_sys_adjtimex)
 
 /* kernel/timer.c */
 #define __NR_getpid 172
@@ -477,39 +501,40 @@ __SYSCALL(__NR_getegid, sys_getegid)
 #define __NR_gettid 178
 __SYSCALL(__NR_gettid, sys_gettid)
 #define __NR_sysinfo 179
-__SYSCALL(__NR_sysinfo, sys_sysinfo)
+__SC_COMP(__NR_sysinfo, sys_sysinfo, compat_sys_sysinfo)
 
 /* ipc/mqueue.c */
 #define __NR_mq_open 180
-__SYSCALL(__NR_mq_open, sys_mq_open)
+__SC_COMP(__NR_mq_open, sys_mq_open, compat_sys_mq_open)
 #define __NR_mq_unlink 181
 __SYSCALL(__NR_mq_unlink, sys_mq_unlink)
 #define __NR_mq_timedsend 182
-__SYSCALL(__NR_mq_timedsend, sys_mq_timedsend)
+__SC_COMP(__NR_mq_timedsend, sys_mq_timedsend, compat_sys_mq_timedsend)
 #define __NR_mq_timedreceive 183
-__SYSCALL(__NR_mq_timedreceive, sys_mq_timedreceive)
+__SC_COMP(__NR_mq_timedreceive, sys_mq_timedreceive, \
+         compat_sys_mq_timedreceive)
 #define __NR_mq_notify 184
-__SYSCALL(__NR_mq_notify, sys_mq_notify)
+__SC_COMP(__NR_mq_notify, sys_mq_notify, compat_sys_mq_notify)
 #define __NR_mq_getsetattr 185
-__SYSCALL(__NR_mq_getsetattr, sys_mq_getsetattr)
+__SC_COMP(__NR_mq_getsetattr, sys_mq_getsetattr, compat_sys_mq_getsetattr)
 
 /* ipc/msg.c */
 #define __NR_msgget 186
 __SYSCALL(__NR_msgget, sys_msgget)
 #define __NR_msgctl 187
-__SYSCALL(__NR_msgctl, sys_msgctl)
+__SC_COMP(__NR_msgctl, sys_msgctl, compat_sys_msgctl)
 #define __NR_msgrcv 188
-__SYSCALL(__NR_msgrcv, sys_msgrcv)
+__SC_COMP(__NR_msgrcv, sys_msgrcv, compat_sys_msgrcv)
 #define __NR_msgsnd 189
-__SYSCALL(__NR_msgsnd, sys_msgsnd)
+__SC_COMP(__NR_msgsnd, sys_msgsnd, compat_sys_msgsnd)
 
 /* ipc/sem.c */
 #define __NR_semget 190
 __SYSCALL(__NR_semget, sys_semget)
 #define __NR_semctl 191
-__SYSCALL(__NR_semctl, sys_semctl)
+__SC_COMP(__NR_semctl, sys_semctl, compat_sys_semctl)
 #define __NR_semtimedop 192
-__SYSCALL(__NR_semtimedop, sys_semtimedop)
+__SC_COMP(__NR_semtimedop, sys_semtimedop, compat_sys_semtimedop)
 #define __NR_semop 193
 __SYSCALL(__NR_semop, sys_semop)
 
@@ -517,9 +542,9 @@ __SYSCALL(__NR_semop, sys_semop)
 #define __NR_shmget 194
 __SYSCALL(__NR_shmget, sys_shmget)
 #define __NR_shmctl 195
-__SYSCALL(__NR_shmctl, sys_shmctl)
+__SC_COMP(__NR_shmctl, sys_shmctl, compat_sys_shmctl)
 #define __NR_shmat 196
-__SYSCALL(__NR_shmat, sys_shmat)
+__SC_COMP(__NR_shmat, sys_shmat, compat_sys_shmat)
 #define __NR_shmdt 197
 __SYSCALL(__NR_shmdt, sys_shmdt)
 
@@ -543,21 +568,21 @@ __SYSCALL(__NR_getpeername, sys_getpeername)
 #define __NR_sendto 206
 __SYSCALL(__NR_sendto, sys_sendto)
 #define __NR_recvfrom 207
-__SYSCALL(__NR_recvfrom, sys_recvfrom)
+__SC_COMP(__NR_recvfrom, sys_recvfrom, compat_sys_recvfrom)
 #define __NR_setsockopt 208
-__SYSCALL(__NR_setsockopt, sys_setsockopt)
+__SC_COMP(__NR_setsockopt, sys_setsockopt, compat_sys_setsockopt)
 #define __NR_getsockopt 209
-__SYSCALL(__NR_getsockopt, sys_getsockopt)
+__SC_COMP(__NR_getsockopt, sys_getsockopt, compat_sys_getsockopt)
 #define __NR_shutdown 210
 __SYSCALL(__NR_shutdown, sys_shutdown)
 #define __NR_sendmsg 211
-__SYSCALL(__NR_sendmsg, sys_sendmsg)
+__SC_COMP(__NR_sendmsg, sys_sendmsg, compat_sys_sendmsg)
 #define __NR_recvmsg 212
-__SYSCALL(__NR_recvmsg, sys_recvmsg)
+__SC_COMP(__NR_recvmsg, sys_recvmsg, compat_sys_recvmsg)
 
 /* mm/filemap.c */
 #define __NR_readahead 213
-__SYSCALL(__NR_readahead, sys_readahead)
+__SC_COMP(__NR_readahead, sys_readahead, compat_sys_readahead)
 
 /* mm/nommu.c, also with MMU */
 #define __NR_brk 214
@@ -573,19 +598,19 @@ __SYSCALL(__NR_add_key, sys_add_key)
 #define __NR_request_key 218
 __SYSCALL(__NR_request_key, sys_request_key)
 #define __NR_keyctl 219
-__SYSCALL(__NR_keyctl, sys_keyctl)
+__SC_COMP(__NR_keyctl, sys_keyctl, compat_sys_keyctl)
 
 /* arch/example/kernel/sys_example.c */
 #define __NR_clone 220
-__SYSCALL(__NR_clone, sys_clone)       /* .long sys_clone_wrapper */
+__SYSCALL(__NR_clone, sys_clone)
 #define __NR_execve 221
-__SYSCALL(__NR_execve, sys_execve)     /* .long sys_execve_wrapper */
+__SC_COMP(__NR_execve, sys_execve, compat_sys_execve)
 
 #define __NR3264_mmap 222
 __SC_3264(__NR3264_mmap, sys_mmap2, sys_mmap)
 /* mm/fadvise.c */
 #define __NR3264_fadvise64 223
-__SYSCALL(__NR3264_fadvise64, sys_fadvise64_64)
+__SC_COMP(__NR3264_fadvise64, sys_fadvise64_64, compat_sys_fadvise64_64)
 
 /* mm/, CONFIG_MMU only */
 #ifndef __ARCH_NOMMU
@@ -612,25 +637,26 @@ __SYSCALL(__NR_madvise, sys_madvise)
 #define __NR_remap_file_pages 234
 __SYSCALL(__NR_remap_file_pages, sys_remap_file_pages)
 #define __NR_mbind 235
-__SYSCALL(__NR_mbind, sys_mbind)
+__SC_COMP(__NR_mbind, sys_mbind, compat_sys_mbind)
 #define __NR_get_mempolicy 236
-__SYSCALL(__NR_get_mempolicy, sys_get_mempolicy)
+__SC_COMP(__NR_get_mempolicy, sys_get_mempolicy, compat_sys_get_mempolicy)
 #define __NR_set_mempolicy 237
-__SYSCALL(__NR_set_mempolicy, sys_set_mempolicy)
+__SC_COMP(__NR_set_mempolicy, sys_set_mempolicy, compat_sys_set_mempolicy)
 #define __NR_migrate_pages 238
-__SYSCALL(__NR_migrate_pages, sys_migrate_pages)
+__SC_COMP(__NR_migrate_pages, sys_migrate_pages, compat_sys_migrate_pages)
 #define __NR_move_pages 239
-__SYSCALL(__NR_move_pages, sys_move_pages)
+__SC_COMP(__NR_move_pages, sys_move_pages, compat_sys_move_pages)
 #endif
 
 #define __NR_rt_tgsigqueueinfo 240
-__SYSCALL(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo)
+__SC_COMP(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo, \
+         compat_sys_rt_tgsigqueueinfo)
 #define __NR_perf_event_open 241
 __SYSCALL(__NR_perf_event_open, sys_perf_event_open)
 #define __NR_accept4 242
 __SYSCALL(__NR_accept4, sys_accept4)
 #define __NR_recvmmsg 243
-__SYSCALL(__NR_recvmmsg, sys_recvmmsg)
+__SC_COMP(__NR_recvmmsg, sys_recvmmsg, compat_sys_recvmmsg)
 
 /*
  * Architectures may provide up to 16 syscalls of their own
@@ -639,24 +665,29 @@ __SYSCALL(__NR_recvmmsg, sys_recvmmsg)
 #define __NR_arch_specific_syscall 244
 
 #define __NR_wait4 260
-__SYSCALL(__NR_wait4, sys_wait4)
+__SC_COMP(__NR_wait4, sys_wait4, compat_sys_wait4)
 #define __NR_prlimit64 261
 __SYSCALL(__NR_prlimit64, sys_prlimit64)
 #define __NR_fanotify_init 262
 __SYSCALL(__NR_fanotify_init, sys_fanotify_init)
 #define __NR_fanotify_mark 263
 __SYSCALL(__NR_fanotify_mark, sys_fanotify_mark)
-#define __NR_name_to_handle_at         264
+#define __NR_name_to_handle_at         264
 __SYSCALL(__NR_name_to_handle_at, sys_name_to_handle_at)
-#define __NR_open_by_handle_at         265
-__SYSCALL(__NR_open_by_handle_at, sys_open_by_handle_at)
+#define __NR_open_by_handle_at         265
+__SC_COMP(__NR_open_by_handle_at, sys_open_by_handle_at, \
+         compat_sys_open_by_handle_at)
 #define __NR_clock_adjtime 266
-__SYSCALL(__NR_clock_adjtime, sys_clock_adjtime)
+__SC_COMP(__NR_clock_adjtime, sys_clock_adjtime, compat_sys_clock_adjtime)
 #define __NR_syncfs 267
 __SYSCALL(__NR_syncfs, sys_syncfs)
+#define __NR_setns 268
+__SYSCALL(__NR_setns, sys_setns)
+#define __NR_sendmmsg 269
+__SC_COMP(__NR_sendmmsg, sys_sendmmsg, compat_sys_sendmmsg)
 
 #undef __NR_syscalls
-#define __NR_syscalls 268
+#define __NR_syscalls 270
 
 /*
  * All syscalls below here should go away really,
index 077c00d94f6e47f63092d6731085e61e12c012db..db22d136ad08bf671266faa87f89de37178187f3 100644 (file)
@@ -15,7 +15,7 @@
  *     HEAD_TEXT_SECTION
  *     INIT_TEXT_SECTION(PAGE_SIZE)
  *     INIT_DATA_SECTION(...)
- *     PERCPU(CACHELINE_SIZE, PAGE_SIZE)
+ *     PERCPU_SECTION(CACHELINE_SIZE)
  *     __init_end = .;
  *
  *     _stext = .;
        *(.discard.*)                                                   \
        }
 
+/**
+ * PERCPU_INPUT - the percpu input sections
+ * @cacheline: cacheline size
+ *
+ * The core percpu section names and core symbols which do not rely
+ * directly upon load addresses.
+ *
+ * @cacheline is used to align subsections to avoid false cacheline
+ * sharing between subsections for different purposes.
+ */
+#define PERCPU_INPUT(cacheline)                                                \
+       VMLINUX_SYMBOL(__per_cpu_start) = .;                            \
+       *(.data..percpu..first)                                         \
+       . = ALIGN(PAGE_SIZE);                                           \
+       *(.data..percpu..page_aligned)                                  \
+       . = ALIGN(cacheline);                                           \
+       *(.data..percpu..readmostly)                                    \
+       . = ALIGN(cacheline);                                           \
+       *(.data..percpu)                                                \
+       *(.data..percpu..shared_aligned)                                \
+       VMLINUX_SYMBOL(__per_cpu_end) = .;
+
 /**
  * PERCPU_VADDR - define output section for percpu area
  * @cacheline: cacheline size
  *
  * Note that this macros defines __per_cpu_load as an absolute symbol.
  * If there is no need to put the percpu section at a predetermined
- * address, use PERCPU().
+ * address, use PERCPU_SECTION.
  */
 #define PERCPU_VADDR(cacheline, vaddr, phdr)                           \
        VMLINUX_SYMBOL(__per_cpu_load) = .;                             \
        .data..percpu vaddr : AT(VMLINUX_SYMBOL(__per_cpu_load)         \
                                - LOAD_OFFSET) {                        \
-               VMLINUX_SYMBOL(__per_cpu_start) = .;                    \
-               *(.data..percpu..first)                                 \
-               . = ALIGN(PAGE_SIZE);                                   \
-               *(.data..percpu..page_aligned)                          \
-               . = ALIGN(cacheline);                                   \
-               *(.data..percpu..readmostly)                            \
-               . = ALIGN(cacheline);                                   \
-               *(.data..percpu)                                        \
-               *(.data..percpu..shared_aligned)                        \
-               VMLINUX_SYMBOL(__per_cpu_end) = .;                      \
+               PERCPU_INPUT(cacheline)                                 \
        } phdr                                                          \
        . = VMLINUX_SYMBOL(__per_cpu_load) + SIZEOF(.data..percpu);
 
 /**
- * PERCPU - define output section for percpu area, simple version
+ * PERCPU_SECTION - define output section for percpu area, simple version
  * @cacheline: cacheline size
- * @align: required alignment
  *
- * Align to @align and outputs output section for percpu area.  This macro
- * doesn't manipulate @vaddr or @phdr and __per_cpu_load and
+ * Align to PAGE_SIZE and outputs output section for percpu area.  This
+ * macro doesn't manipulate @vaddr or @phdr and __per_cpu_load and
  * __per_cpu_start will be identical.
  *
- * This macro is equivalent to ALIGN(@align); PERCPU_VADDR(@cacheline,,)
+ * This macro is equivalent to ALIGN(PAGE_SIZE); PERCPU_VADDR(@cacheline,,)
  * except that __per_cpu_load is defined as a relative symbol against
  * .data..percpu which is required for relocatable x86_32 configuration.
  */
-#define PERCPU(cacheline, align)                                       \
-       . = ALIGN(align);                                               \
+#define PERCPU_SECTION(cacheline)                                      \
+       . = ALIGN(PAGE_SIZE);                                           \
        .data..percpu   : AT(ADDR(.data..percpu) - LOAD_OFFSET) {       \
                VMLINUX_SYMBOL(__per_cpu_load) = .;                     \
-               VMLINUX_SYMBOL(__per_cpu_start) = .;                    \
-               *(.data..percpu..first)                                 \
-               . = ALIGN(PAGE_SIZE);                                   \
-               *(.data..percpu..page_aligned)                          \
-               . = ALIGN(cacheline);                                   \
-               *(.data..percpu..readmostly)                            \
-               . = ALIGN(cacheline);                                   \
-               *(.data..percpu)                                        \
-               *(.data..percpu..shared_aligned)                        \
-               VMLINUX_SYMBOL(__per_cpu_end) = .;                      \
+               PERCPU_INPUT(cacheline)                                 \
        }
 
 
index 202424d17ed7c1924ae5d26936369dc110564e44..738b3a5faa1294215479ddf88e99c2c523dfa72c 100644 (file)
@@ -122,10 +122,14 @@ struct drm_device;
  * using the DRM_DEBUG_KMS and DRM_DEBUG.
  */
 
-extern void drm_ut_debug_printk(unsigned int request_level,
+extern __attribute__((format (printf, 4, 5)))
+void drm_ut_debug_printk(unsigned int request_level,
                                const char *prefix,
                                const char *function_name,
                                const char *format, ...);
+extern __attribute__((format (printf, 2, 3)))
+int drm_err(const char *func, const char *format, ...);
+
 /***********************************************************************/
 /** \name DRM template customization defaults */
 /*@{*/
@@ -181,21 +185,11 @@ extern void drm_ut_debug_printk(unsigned int request_level,
  * \param fmt printf() like format string.
  * \param arg arguments
  */
-#define DRM_ERROR(fmt, arg...) \
-       printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __func__ , ##arg)
-
-/**
- * Memory error output.
- *
- * \param area memory area where the error occurred.
- * \param fmt printf() like format string.
- * \param arg arguments
- */
-#define DRM_MEM_ERROR(area, fmt, arg...) \
-       printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __func__, \
-              drm_mem_stats[area].name , ##arg)
+#define DRM_ERROR(fmt, ...)                            \
+       drm_err(__func__, fmt, ##__VA_ARGS__)
 
-#define DRM_INFO(fmt, arg...)  printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg)
+#define DRM_INFO(fmt, ...)                             \
+       printk(KERN_INFO "[" DRM_NAME "] " fmt, ##__VA_ARGS__)
 
 /**
  * Debug output.
@@ -1000,6 +994,22 @@ struct drm_minor {
        struct drm_mode_group mode_group;
 };
 
+/* mode specified on the command line */
+struct drm_cmdline_mode {
+       bool specified;
+       bool refresh_specified;
+       bool bpp_specified;
+       int xres, yres;
+       int bpp;
+       int refresh;
+       bool rb;
+       bool interlace;
+       bool cvt;
+       bool margins;
+       enum drm_connector_force force;
+};
+
+
 struct drm_pending_vblank_event {
        struct drm_pending_event base;
        int pipe;
@@ -1395,6 +1405,15 @@ extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
                                                 struct drm_crtc *refcrtc);
 extern void drm_calc_timestamping_constants(struct drm_crtc *crtc);
 
+extern bool
+drm_mode_parse_command_line_for_connector(const char *mode_option,
+                                         struct drm_connector *connector,
+                                         struct drm_cmdline_mode *mode);
+
+extern struct drm_display_mode *
+drm_mode_create_from_cmdline_mode(struct drm_device *dev,
+                                 struct drm_cmdline_mode *cmd);
+
 /* Modesetting support */
 extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc);
 extern void drm_vblank_post_modeset(struct drm_device *dev, int crtc);
index d94684b7ba3462ab8e62a0460b3ca06bd3fe9662..33d12f87f0e01735d41a800a73b7ea5ddc9b31a6 100644 (file)
@@ -183,7 +183,9 @@ enum subpixel_order {
        SubPixelNone,
 };
 
-
+#define DRM_COLOR_FORMAT_RGB444                (1<<0)
+#define DRM_COLOR_FORMAT_YCRCB444      (1<<1)
+#define DRM_COLOR_FORMAT_YCRCB422      (1<<2)
 /*
  * Describes a given display (e.g. CRT or flat panel) and its limitations.
  */
@@ -198,8 +200,10 @@ struct drm_display_info {
        unsigned int min_vfreq, max_vfreq;
        unsigned int min_hfreq, max_hfreq;
        unsigned int pixel_clock;
+       unsigned int bpc;
 
        enum subpixel_order subpixel_order;
+       u32 color_formats;
 
        char *raw_edid; /* if any */
 };
@@ -516,6 +520,8 @@ struct drm_connector {
        uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER];
        uint32_t force_encoder_id;
        struct drm_encoder *encoder; /* currently active encoder */
+
+       int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */
 };
 
 /**
index 83a389e44543f19911efe7726ad48d4dd602f967..91567bbdb027c5f36a09923a2d9852c10fe1f07d 100644 (file)
@@ -53,6 +53,7 @@
 
 #define DP_MAX_LANE_COUNT                   0x002
 # define DP_MAX_LANE_COUNT_MASK                    0x1f
+# define DP_TPS3_SUPPORTED                 (1 << 6)
 # define DP_ENHANCED_FRAME_CAP             (1 << 7)
 
 #define DP_MAX_DOWNSPREAD                   0x003
 
 #define DP_MAIN_LINK_CHANNEL_CODING         0x006
 
+#define DP_TRAINING_AUX_RD_INTERVAL         0x00e
+
 /* link configuration */
 #define        DP_LINK_BW_SET                      0x100
 # define DP_LINK_BW_1_62                   0x06
 # define DP_LINK_BW_2_7                            0x0a
+# define DP_LINK_BW_5_4                            0x14
 
 #define DP_LANE_COUNT_SET                  0x101
 # define DP_LANE_COUNT_MASK                0x0f
@@ -84,6 +88,7 @@
 # define DP_TRAINING_PATTERN_DISABLE       0
 # define DP_TRAINING_PATTERN_1             1
 # define DP_TRAINING_PATTERN_2             2
+# define DP_TRAINING_PATTERN_3             3
 # define DP_TRAINING_PATTERN_MASK          0x3
 
 # define DP_LINK_QUAL_PATTERN_DISABLE      (0 << 2)
index 5881fad91faa29ef3d446a75b7e22280ca0dd270..eacb415b309a2c72e20928b4d0faecbff905d132 100644 (file)
@@ -155,12 +155,35 @@ struct detailed_timing {
 #define DRM_EDID_INPUT_SEPARATE_SYNCS  (1 << 3)
 #define DRM_EDID_INPUT_BLANK_TO_BLACK  (1 << 4)
 #define DRM_EDID_INPUT_VIDEO_LEVEL     (3 << 5)
-#define DRM_EDID_INPUT_DIGITAL         (1 << 7) /* bits below must be zero if set */
+#define DRM_EDID_INPUT_DIGITAL         (1 << 7)
+#define DRM_EDID_DIGITAL_DEPTH_MASK    (7 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_UNDEF   (0 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_6       (1 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_8       (2 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_10      (3 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_12      (4 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_14      (5 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_16      (6 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_RSVD    (7 << 4)
+#define DRM_EDID_DIGITAL_TYPE_UNDEF    (0)
+#define DRM_EDID_DIGITAL_TYPE_DVI      (1)
+#define DRM_EDID_DIGITAL_TYPE_HDMI_A   (2)
+#define DRM_EDID_DIGITAL_TYPE_HDMI_B   (3)
+#define DRM_EDID_DIGITAL_TYPE_MDDI     (4)
+#define DRM_EDID_DIGITAL_TYPE_DP       (5)
 
 #define DRM_EDID_FEATURE_DEFAULT_GTF      (1 << 0)
 #define DRM_EDID_FEATURE_PREFERRED_TIMING (1 << 1)
 #define DRM_EDID_FEATURE_STANDARD_COLOR   (1 << 2)
+/* If analog */
 #define DRM_EDID_FEATURE_DISPLAY_TYPE     (3 << 3) /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */
+/* If digital */
+#define DRM_EDID_FEATURE_COLOR_MASK      (3 << 3)
+#define DRM_EDID_FEATURE_RGB             (0 << 3)
+#define DRM_EDID_FEATURE_RGB_YCRCB444    (1 << 3)
+#define DRM_EDID_FEATURE_RGB_YCRCB422    (2 << 3)
+#define DRM_EDID_FEATURE_RGB_YCRCB       (3 << 3) /* both 4:4:4 and 4:2:2 */
+
 #define DRM_EDID_FEATURE_PM_ACTIVE_OFF    (1 << 5)
 #define DRM_EDID_FEATURE_PM_SUSPEND       (1 << 6)
 #define DRM_EDID_FEATURE_PM_STANDBY       (1 << 7)
index c99c3d3e78113d8a8596d0696464034c5e20fe8b..6e3076ad646e99debaecdc315affe494b52f2f28 100644 (file)
@@ -40,20 +40,6 @@ struct drm_fb_helper_crtc {
        struct drm_display_mode *desired_mode;
 };
 
-/* mode specified on the command line */
-struct drm_fb_helper_cmdline_mode {
-       bool specified;
-       bool refresh_specified;
-       bool bpp_specified;
-       int xres, yres;
-       int bpp;
-       int refresh;
-       bool rb;
-       bool interlace;
-       bool cvt;
-       bool margins;
-};
-
 struct drm_fb_helper_surface_size {
        u32 fb_width;
        u32 fb_height;
@@ -74,8 +60,8 @@ struct drm_fb_helper_funcs {
 };
 
 struct drm_fb_helper_connector {
-       struct drm_fb_helper_cmdline_mode cmdline_mode;
        struct drm_connector *connector;
+       struct drm_cmdline_mode cmdline_mode;
 };
 
 struct drm_fb_helper {
index f04b2a3b0f49b7117cb74163af0997a7a6fd4742..e08f344c6cffc546660506b37e8659679ac78211 100644 (file)
        {0x1002, 0x9614, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x9615, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x9616, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x9640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x9641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x9642, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x9643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x9644, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x9645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x9647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
+       {0x1002, 0x9648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
+       {0x1002, 0x964a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x964e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
+       {0x1002, 0x964f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
        {0x1002, 0x9710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x9711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x9712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
index cb1ded2bd54520f2f26f82ea786653f110c9d01d..01f6362750570e19e01c01d5fbc22f50f63cbed6 100644 (file)
@@ -4,6 +4,7 @@ header-y += caif/
 header-y += dvb/
 header-y += hdlc/
 header-y += isdn/
+header-y += mmc/
 header-y += nfsd/
 header-y += raid/
 header-y += spi/
@@ -302,6 +303,7 @@ header-y += ppp-comp.h
 header-y += ppp_defs.h
 header-y += pps.h
 header-y += prctl.h
+header-y += ptp_clock.h
 header-y += ptrace.h
 header-y += qnx4_fs.h
 header-y += qnxtypes.h
index a2e910e01293a01fd229cd59dfb1c1bb69f7be1a..1deb2a73c2daf861fb20130f17b4c6a3d924e152 100644 (file)
@@ -150,8 +150,7 @@ extern int ec_read(u8 addr, u8 *val);
 extern int ec_write(u8 addr, u8 val);
 extern int ec_transaction(u8 command,
                           const u8 *wdata, unsigned wdata_len,
-                          u8 *rdata, unsigned rdata_len,
-                         int force_poll);
+                          u8 *rdata, unsigned rdata_len);
 
 #if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
 
index 96c038e43d667ad04d15cec41841d2f2606cb816..ee456c79b0e6784cb8af04fcddbc3f354030b59f 100644 (file)
@@ -34,4 +34,17 @@ static inline int atomic_inc_not_zero_hint(atomic_t *v, int hint)
 }
 #endif
 
+#ifndef CONFIG_ARCH_HAS_ATOMIC_OR
+static inline void atomic_or(int i, atomic_t *v)
+{
+       int old;
+       int new;
+
+       do {
+               old = atomic_read(v);
+               new = old | i;
+       } while (atomic_cmpxchg(v, old, new) != old);
+}
+#endif /* #ifndef CONFIG_ARCH_HAS_ATOMIC_OR */
+
 #endif /* _LINUX_ATOMIC_H */
index 198087a16fc4f5407049e416abec17c846086ca1..98999cf107ce01fec1fb5dc2559a73f308e31de2 100644 (file)
 #ifndef __BASIC_MMIO_GPIO_H
 #define __BASIC_MMIO_GPIO_H
 
+#include <linux/gpio.h>
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/spinlock_types.h>
+
 struct bgpio_pdata {
        int base;
+       int ngpio;
 };
 
+struct device;
+
+struct bgpio_chip {
+       struct gpio_chip gc;
+
+       unsigned long (*read_reg)(void __iomem *reg);
+       void (*write_reg)(void __iomem *reg, unsigned long data);
+
+       void __iomem *reg_dat;
+       void __iomem *reg_set;
+       void __iomem *reg_clr;
+       void __iomem *reg_dir;
+
+       /* Number of bits (GPIOs): <register width> * 8. */
+       int bits;
+
+       /*
+        * Some GPIO controllers work with the big-endian bits notation,
+        * e.g. in a 8-bits register, GPIO7 is the least significant bit.
+        */
+       unsigned long (*pin2mask)(struct bgpio_chip *bgc, unsigned int pin);
+
+       /*
+        * Used to lock bgpio_chip->data. Also, this is needed to keep
+        * shadowed and real data registers writes together.
+        */
+       spinlock_t lock;
+
+       /* Shadowed data register to clear/set bits safely. */
+       unsigned long data;
+
+       /* Shadowed direction registers to clear/set direction safely. */
+       unsigned long dir;
+};
+
+static inline struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc)
+{
+       return container_of(gc, struct bgpio_chip, gc);
+}
+
+int __devexit bgpio_remove(struct bgpio_chip *bgc);
+int __devinit bgpio_init(struct bgpio_chip *bgc,
+                        struct device *dev,
+                        unsigned long sz,
+                        void __iomem *dat,
+                        void __iomem *set,
+                        void __iomem *clr,
+                        void __iomem *dirout,
+                        void __iomem *dirin,
+                        bool big_endian);
+
 #endif /* __BASIC_MMIO_GPIO_H */
index daf8c480c7867e9a60f3cdd715e9b4a8c030942c..dcafe0bf0005ac11e10dbcb0f3cc6f756221e60e 100644 (file)
@@ -55,7 +55,8 @@
  * bitmap_parse(buf, buflen, dst, nbits)       Parse bitmap dst from kernel buf
  * bitmap_parse_user(ubuf, ulen, dst, nbits)   Parse bitmap dst from user buf
  * bitmap_scnlistprintf(buf, len, src, nbits)  Print bitmap src as list to buf
- * bitmap_parselist(buf, dst, nbits)           Parse bitmap dst from list
+ * bitmap_parselist(buf, dst, nbits)           Parse bitmap dst from kernel buf
+ * bitmap_parselist_user(buf, dst, nbits)      Parse bitmap dst from user buf
  * bitmap_find_free_region(bitmap, bits, order)        Find and allocate bit region
  * bitmap_release_region(bitmap, pos, order)   Free specified bit region
  * bitmap_allocate_region(bitmap, pos, order)  Allocate specified bit region
@@ -129,6 +130,8 @@ extern int bitmap_scnlistprintf(char *buf, unsigned int len,
                        const unsigned long *src, int nbits);
 extern int bitmap_parselist(const char *buf, unsigned long *maskp,
                        int nmaskbits);
+extern int bitmap_parselist_user(const char __user *ubuf, unsigned int ulen,
+                       unsigned long *dst, int nbits);
 extern void bitmap_remap(unsigned long *dst, const unsigned long *src,
                const unsigned long *old, const unsigned long *new, int bits);
 extern int bitmap_bitremap(int oldbit,
index 2184c6b97aebb699206e2eb7426bd716b8f0e54f..a3ef66a2a08303bb8cc7492a70bda66c22c2e473 100644 (file)
@@ -148,7 +148,7 @@ static inline unsigned long __ffs64(u64 word)
 
 #ifdef __KERNEL__
 
-#ifdef CONFIG_GENERIC_FIND_LAST_BIT
+#ifndef find_last_bit
 /**
  * find_last_bit - find the last set bit in a memory region
  * @addr: The address to start the search at
@@ -158,7 +158,7 @@ static inline unsigned long __ffs64(u64 word)
  */
 extern unsigned long find_last_bit(const unsigned long *addr,
                                   unsigned long size);
-#endif /* CONFIG_GENERIC_FIND_LAST_BIT */
+#endif
 
 #endif /* __KERNEL__ */
 #endif
index be50d9e70a7d45577782c90050384252db735bd8..6395692b2e7a9dec9725dcf42dbf244585f7c83e 100644 (file)
@@ -151,7 +151,6 @@ enum rq_flag_bits {
        __REQ_IO_STAT,          /* account I/O stat */
        __REQ_MIXED_MERGE,      /* merge of different types, fail separately */
        __REQ_SECURE,           /* secure discard (used with __REQ_DISCARD) */
-       __REQ_ON_PLUG,          /* on plug list */
        __REQ_NR_BITS,          /* stops here */
 };
 
@@ -168,7 +167,7 @@ enum rq_flag_bits {
        (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER)
 #define REQ_COMMON_MASK \
        (REQ_WRITE | REQ_FAILFAST_MASK | REQ_SYNC | REQ_META | REQ_DISCARD | \
-        REQ_NOIDLE | REQ_FLUSH | REQ_FUA)
+        REQ_NOIDLE | REQ_FLUSH | REQ_FUA | REQ_SECURE)
 #define REQ_CLONE_MASK         REQ_COMMON_MASK
 
 #define REQ_RAHEAD             (1 << __REQ_RAHEAD)
@@ -192,6 +191,5 @@ enum rq_flag_bits {
 #define REQ_IO_STAT            (1 << __REQ_IO_STAT)
 #define REQ_MIXED_MERGE                (1 << __REQ_MIXED_MERGE)
 #define REQ_SECURE             (1 << __REQ_SECURE)
-#define REQ_ON_PLUG            (1 << __REQ_ON_PLUG)
 
 #endif /* __LINUX_BLK_TYPES_H */
index 2ad95fa1d130f8c8f5cfd68e5fe7a0108aec31d9..1a23722e8878619aec4017cbbd31b951439fdb2b 100644 (file)
@@ -257,7 +257,7 @@ struct queue_limits {
        unsigned char           misaligned;
        unsigned char           discard_misaligned;
        unsigned char           cluster;
-       signed char             discard_zeroes_data;
+       unsigned char           discard_zeroes_data;
 };
 
 struct request_queue
@@ -364,6 +364,8 @@ struct request_queue
         * for flush operations
         */
        unsigned int            flush_flags;
+       unsigned int            flush_not_queueable:1;
+       unsigned int            flush_queue_delayed:1;
        unsigned int            flush_pending_idx:1;
        unsigned int            flush_running_idx:1;
        unsigned long           flush_pending_since;
@@ -843,6 +845,7 @@ extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *);
 extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *);
 extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
 extern void blk_queue_flush(struct request_queue *q, unsigned int flush);
+extern void blk_queue_flush_queueable(struct request_queue *q, bool queueable);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 
 extern int blk_rq_map_sg(struct request_queue *, struct request *, struct scatterlist *);
@@ -1066,13 +1069,16 @@ static inline int queue_limit_discard_alignment(struct queue_limits *lim, sector
 {
        unsigned int alignment = (sector << 9) & (lim->discard_granularity - 1);
 
+       if (!lim->max_discard_sectors)
+               return 0;
+
        return (lim->discard_granularity + lim->discard_alignment - alignment)
                & (lim->discard_granularity - 1);
 }
 
 static inline unsigned int queue_discard_zeroes_data(struct request_queue *q)
 {
-       if (q->limits.discard_zeroes_data == 1)
+       if (q->limits.max_discard_sectors && q->limits.discard_zeroes_data == 1)
                return 1;
 
        return 0;
@@ -1111,6 +1117,11 @@ static inline unsigned int block_size(struct block_device *bdev)
        return bdev->bd_block_size;
 }
 
+static inline bool queue_flush_queueable(struct request_queue *q)
+{
+       return !q->flush_not_queueable;
+}
+
 typedef struct {struct page *v;} Sector;
 
 unsigned char *read_dev_sector(struct block_device *, sector_t, Sector *);
@@ -1271,8 +1282,8 @@ queue_max_integrity_segments(struct request_queue *q)
 #define blk_get_integrity(a)                   (0)
 #define blk_integrity_compare(a, b)            (0)
 #define blk_integrity_register(a, b)           (0)
-#define blk_integrity_unregister(a)            do { } while (0);
-#define blk_queue_max_integrity_segments(a, b) do { } while (0);
+#define blk_integrity_unregister(a)            do { } while (0)
+#define blk_queue_max_integrity_segments(a, b) do { } while (0)
 #define queue_max_integrity_segments(a)                (0)
 #define blk_integrity_merge_rq(a, b, c)                (0)
 #define blk_integrity_merge_bio(a, b, c)       (0)
index b22fb0d3db0f5fb0fa364bbae9e12ee46b8e918a..8c7c2de7631a6fb59ab8f4e86334516a7f07e7d1 100644 (file)
@@ -169,7 +169,8 @@ extern void blk_trace_shutdown(struct request_queue *);
 extern int do_blk_trace_setup(struct request_queue *q, char *name,
                              dev_t dev, struct block_device *bdev,
                              struct blk_user_trace_setup *buts);
-extern void __trace_note_message(struct blk_trace *, const char *fmt, ...);
+extern __attribute__((format(printf, 2, 3)))
+void __trace_note_message(struct blk_trace *, const char *fmt, ...);
 
 /**
  * blk_add_trace_msg - Add a (simple) message to the blktrace stream
index 01eca1794e148efb906d3aa9fe0327abb49cbd8a..ab344a52110571b6600c8bbb37871960fa8d67f0 100644 (file)
@@ -99,24 +99,31 @@ extern void *__alloc_bootmem_low_node(pg_data_t *pgdat,
                                      unsigned long align,
                                      unsigned long goal);
 
+#ifdef CONFIG_NO_BOOTMEM
+/* We are using top down, so it is safe to use 0 here */
+#define BOOTMEM_LOW_LIMIT 0
+#else
+#define BOOTMEM_LOW_LIMIT __pa(MAX_DMA_ADDRESS)
+#endif
+
 #define alloc_bootmem(x) \
-       __alloc_bootmem(x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem(x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT)
 #define alloc_bootmem_align(x, align) \
-       __alloc_bootmem(x, align, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem(x, align, BOOTMEM_LOW_LIMIT)
 #define alloc_bootmem_nopanic(x) \
-       __alloc_bootmem_nopanic(x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem_nopanic(x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT)
 #define alloc_bootmem_pages(x) \
-       __alloc_bootmem(x, PAGE_SIZE, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem(x, PAGE_SIZE, BOOTMEM_LOW_LIMIT)
 #define alloc_bootmem_pages_nopanic(x) \
-       __alloc_bootmem_nopanic(x, PAGE_SIZE, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem_nopanic(x, PAGE_SIZE, BOOTMEM_LOW_LIMIT)
 #define alloc_bootmem_node(pgdat, x) \
-       __alloc_bootmem_node(pgdat, x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem_node(pgdat, x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT)
 #define alloc_bootmem_node_nopanic(pgdat, x) \
-       __alloc_bootmem_node_nopanic(pgdat, x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem_node_nopanic(pgdat, x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT)
 #define alloc_bootmem_pages_node(pgdat, x) \
-       __alloc_bootmem_node(pgdat, x, PAGE_SIZE, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem_node(pgdat, x, PAGE_SIZE, BOOTMEM_LOW_LIMIT)
 #define alloc_bootmem_pages_node_nopanic(pgdat, x) \
-       __alloc_bootmem_node_nopanic(pgdat, x, PAGE_SIZE, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem_node_nopanic(pgdat, x, PAGE_SIZE, BOOTMEM_LOW_LIMIT)
 
 #define alloc_bootmem_low(x) \
        __alloc_bootmem_low(x, SMP_CACHE_BYTES, 0)
index f5df23561b96d0428cfed1d26fdaa11127e46b0d..503c8a6b30792d8e725a9233be6298e801e439ac 100644 (file)
@@ -217,8 +217,24 @@ int cont_write_begin(struct file *, struct address_space *, loff_t,
                        get_block_t *, loff_t *);
 int generic_cont_expand_simple(struct inode *inode, loff_t size);
 int block_commit_write(struct page *page, unsigned from, unsigned to);
+int __block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
+                               get_block_t get_block);
 int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
                                get_block_t get_block);
+/* Convert errno to return value from ->page_mkwrite() call */
+static inline int block_page_mkwrite_return(int err)
+{
+       if (err == 0)
+               return VM_FAULT_LOCKED;
+       if (err == -EFAULT)
+               return VM_FAULT_NOPAGE;
+       if (err == -ENOMEM)
+               return VM_FAULT_OOM;
+       if (err == -EAGAIN)
+               return VM_FAULT_RETRY;
+       /* -ENOSPC, -EDQUOT, -EIO ... */
+       return VM_FAULT_SIGBUS;
+}
 sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
 int block_truncate_page(struct address_space *, loff_t, get_block_t *);
 int nobh_write_begin(struct address_space *, loff_t, unsigned, unsigned,
index 2a5cd867c365c3fd4e7f776ceb7e6d42d4e255f9..a2f7d7413f30534f039f902405faaf8be7e4a921 100644 (file)
@@ -60,9 +60,6 @@ struct c2port_ops {
  * Exported functions
  */
 
-#define to_class_dev(obj) container_of((obj), struct class_device, kobj)
-#define to_c2port_device(obj) container_of((obj), struct c2port_device, class)
-
 extern struct c2port_device *c2port_device_register(char *name,
                                        struct c2port_ops *ops, void *devdata);
 extern void c2port_device_unregister(struct c2port_device *dev);
index 4554db0cde863dab0c454b42e6c032651545bf8f..c42112350003d35bd7890b3a9023fe3161b79f27 100644 (file)
@@ -417,7 +417,6 @@ extern const kernel_cap_t __cap_init_eff_set;
 
 # define CAP_EMPTY_SET    ((kernel_cap_t){{ 0, 0 }})
 # define CAP_FULL_SET     ((kernel_cap_t){{ ~0, ~0 }})
-# define CAP_INIT_EFF_SET ((kernel_cap_t){{ ~CAP_TO_MASK(CAP_SETPCAP), ~0 }})
 # define CAP_FS_SET       ((kernel_cap_t){{ CAP_FS_MASK_B0 \
                                    | CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \
                                    CAP_FS_MASK_B1 } })
@@ -427,11 +426,7 @@ extern const kernel_cap_t __cap_init_eff_set;
 
 #endif /* _KERNEL_CAPABILITY_U32S != 2 */
 
-#define CAP_INIT_INH_SET    CAP_EMPTY_SET
-
 # define cap_clear(c)         do { (c) = __cap_empty_set; } while (0)
-# define cap_set_full(c)      do { (c) = __cap_full_set; } while (0)
-# define cap_set_init_eff(c)  do { (c) = __cap_init_eff_set; } while (0)
 
 #define cap_raise(c, flag)  ((c).cap[CAP_TO_INDEX(flag)] |= CAP_TO_MASK(flag))
 #define cap_lower(c, flag)  ((c).cap[CAP_TO_INDEX(flag)] &= ~CAP_TO_MASK(flag))
index b8e995fbd8670a2c7303d590432dc2a5e1f62b0d..b8c60694b2b0977d4ecdb982d8bcaea5f0ef2673 100644 (file)
@@ -313,6 +313,7 @@ enum {
        CEPH_MDS_OP_GETATTR    = 0x00101,
        CEPH_MDS_OP_LOOKUPHASH = 0x00102,
        CEPH_MDS_OP_LOOKUPPARENT = 0x00103,
+       CEPH_MDS_OP_LOOKUPINO  = 0x00104,
 
        CEPH_MDS_OP_SETXATTR   = 0x01105,
        CEPH_MDS_OP_RMXATTR    = 0x01106,
index 5ac7ebc36dbb335604acfa74007a325fc0c7d658..ab4ac0ccb857ac4c6b5197c19f3a31a2dc2a3504 100644 (file)
@@ -467,12 +467,14 @@ struct cgroup_subsys {
        int (*pre_destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
        void (*destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
        int (*can_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
-                         struct task_struct *tsk, bool threadgroup);
+                         struct task_struct *tsk);
+       int (*can_attach_task)(struct cgroup *cgrp, struct task_struct *tsk);
        void (*cancel_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
-                         struct task_struct *tsk, bool threadgroup);
+                             struct task_struct *tsk);
+       void (*pre_attach)(struct cgroup *cgrp);
+       void (*attach_task)(struct cgroup *cgrp, struct task_struct *tsk);
        void (*attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
-                       struct cgroup *old_cgrp, struct task_struct *tsk,
-                       bool threadgroup);
+                      struct cgroup *old_cgrp, struct task_struct *tsk);
        void (*fork)(struct cgroup_subsys *ss, struct task_struct *task);
        void (*exit)(struct cgroup_subsys *ss, struct cgroup *cgrp,
                        struct cgroup *old_cgrp, struct task_struct *task);
@@ -553,9 +555,6 @@ static inline struct cgroup* task_cgroup(struct task_struct *task,
        return task_subsys_state(task, subsys_id)->cgroup;
 }
 
-int cgroup_clone(struct task_struct *tsk, struct cgroup_subsys *ss,
-                                                       char *nodename);
-
 /* A cgroup_iter should be treated as an opaque object */
 struct cgroup_iter {
        struct list_head *cg_link;
index cdbfcb8780ec94d4e69ea9ab0826e31d49ca8cfe..ac663c18776c95fdf77f7eb49ce2b4503d2cb795 100644 (file)
@@ -19,12 +19,6 @@ SUBSYS(debug)
 
 /* */
 
-#ifdef CONFIG_CGROUP_NS
-SUBSYS(ns)
-#endif
-
-/* */
-
 #ifdef CONFIG_CGROUP_SCHED
 SUBSYS(cpu_cgroup)
 #endif
diff --git a/include/linux/cleancache.h b/include/linux/cleancache.h
new file mode 100644 (file)
index 0000000..04ffb2e
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef _LINUX_CLEANCACHE_H
+#define _LINUX_CLEANCACHE_H
+
+#include <linux/fs.h>
+#include <linux/exportfs.h>
+#include <linux/mm.h>
+
+#define CLEANCACHE_KEY_MAX 6
+
+/*
+ * cleancache requires every file with a page in cleancache to have a
+ * unique key unless/until the file is removed/truncated.  For some
+ * filesystems, the inode number is unique, but for "modern" filesystems
+ * an exportable filehandle is required (see exportfs.h)
+ */
+struct cleancache_filekey {
+       union {
+               ino_t ino;
+               __u32 fh[CLEANCACHE_KEY_MAX];
+               u32 key[CLEANCACHE_KEY_MAX];
+       } u;
+};
+
+struct cleancache_ops {
+       int (*init_fs)(size_t);
+       int (*init_shared_fs)(char *uuid, size_t);
+       int (*get_page)(int, struct cleancache_filekey,
+                       pgoff_t, struct page *);
+       void (*put_page)(int, struct cleancache_filekey,
+                       pgoff_t, struct page *);
+       void (*flush_page)(int, struct cleancache_filekey, pgoff_t);
+       void (*flush_inode)(int, struct cleancache_filekey);
+       void (*flush_fs)(int);
+};
+
+extern struct cleancache_ops
+       cleancache_register_ops(struct cleancache_ops *ops);
+extern void __cleancache_init_fs(struct super_block *);
+extern void __cleancache_init_shared_fs(char *, struct super_block *);
+extern int  __cleancache_get_page(struct page *);
+extern void __cleancache_put_page(struct page *);
+extern void __cleancache_flush_page(struct address_space *, struct page *);
+extern void __cleancache_flush_inode(struct address_space *);
+extern void __cleancache_flush_fs(struct super_block *);
+extern int cleancache_enabled;
+
+#ifdef CONFIG_CLEANCACHE
+static inline bool cleancache_fs_enabled(struct page *page)
+{
+       return page->mapping->host->i_sb->cleancache_poolid >= 0;
+}
+static inline bool cleancache_fs_enabled_mapping(struct address_space *mapping)
+{
+       return mapping->host->i_sb->cleancache_poolid >= 0;
+}
+#else
+#define cleancache_enabled (0)
+#define cleancache_fs_enabled(_page) (0)
+#define cleancache_fs_enabled_mapping(_page) (0)
+#endif
+
+/*
+ * The shim layer provided by these inline functions allows the compiler
+ * to reduce all cleancache hooks to nothingness if CONFIG_CLEANCACHE
+ * is disabled, to a single global variable check if CONFIG_CLEANCACHE
+ * is enabled but no cleancache "backend" has dynamically enabled it,
+ * and, for the most frequent cleancache ops, to a single global variable
+ * check plus a superblock element comparison if CONFIG_CLEANCACHE is enabled
+ * and a cleancache backend has dynamically enabled cleancache, but the
+ * filesystem referenced by that cleancache op has not enabled cleancache.
+ * As a result, CONFIG_CLEANCACHE can be enabled by default with essentially
+ * no measurable performance impact.
+ */
+
+static inline void cleancache_init_fs(struct super_block *sb)
+{
+       if (cleancache_enabled)
+               __cleancache_init_fs(sb);
+}
+
+static inline void cleancache_init_shared_fs(char *uuid, struct super_block *sb)
+{
+       if (cleancache_enabled)
+               __cleancache_init_shared_fs(uuid, sb);
+}
+
+static inline int cleancache_get_page(struct page *page)
+{
+       int ret = -1;
+
+       if (cleancache_enabled && cleancache_fs_enabled(page))
+               ret = __cleancache_get_page(page);
+       return ret;
+}
+
+static inline void cleancache_put_page(struct page *page)
+{
+       if (cleancache_enabled && cleancache_fs_enabled(page))
+               __cleancache_put_page(page);
+}
+
+static inline void cleancache_flush_page(struct address_space *mapping,
+                                       struct page *page)
+{
+       /* careful... page->mapping is NULL sometimes when this is called */
+       if (cleancache_enabled && cleancache_fs_enabled_mapping(mapping))
+               __cleancache_flush_page(mapping, page);
+}
+
+static inline void cleancache_flush_inode(struct address_space *mapping)
+{
+       if (cleancache_enabled && cleancache_fs_enabled_mapping(mapping))
+               __cleancache_flush_inode(mapping);
+}
+
+static inline void cleancache_flush_fs(struct super_block *sb)
+{
+       if (cleancache_enabled)
+               __cleancache_flush_fs(sb);
+}
+
+#endif /* _LINUX_CLEANCACHE_H */
index d4646b48dc4a7b0074dc7491e7f66186f398e70e..18a1baf31f2d531493526a48132dc38a5f2f0f03 100644 (file)
@@ -188,6 +188,7 @@ struct clocksource {
 #ifdef CONFIG_CLOCKSOURCE_WATCHDOG
        /* Watchdog related data, used by the framework */
        struct list_head wd_list;
+       cycle_t cs_last;
        cycle_t wd_last;
 #endif
 } ____cacheline_aligned;
index 5778b559d59c3222ee825897b7430523aa96c353..ddcb7db38e67cc1f822d9cca89c7253a0883a63e 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/sem.h>
 #include <linux/socket.h>
 #include <linux/if.h>
+#include <linux/fs.h>
+#include <linux/aio_abi.h>     /* for aio_context_t */
 
 #include <asm/compat.h>
 #include <asm/siginfo.h>
@@ -26,7 +28,7 @@ typedef __compat_gid32_t      compat_gid_t;
 struct compat_sel_arg_struct;
 struct rusage;
 
-struct compat_itimerspec { 
+struct compat_itimerspec {
        struct compat_timespec it_interval;
        struct compat_timespec it_value;
 };
@@ -70,9 +72,9 @@ struct compat_timex {
        compat_long_t stbcnt;
        compat_int_t tai;
 
-       compat_int_t :32; compat_int_t :32; compat_int_t :32; compat_int_t :32;
-       compat_int_t :32; compat_int_t :32; compat_int_t :32; compat_int_t :32;
-       compat_int_t :32; compat_int_t :32; compat_int_t :32;
+       compat_int_t:32; compat_int_t:32; compat_int_t:32; compat_int_t:32;
+       compat_int_t:32; compat_int_t:32; compat_int_t:32; compat_int_t:32;
+       compat_int_t:32; compat_int_t:32; compat_int_t:32;
 };
 
 #define _COMPAT_NSIG_WORDS     (_COMPAT_NSIG / _COMPAT_NSIG_BPW)
@@ -81,8 +83,10 @@ typedef struct {
        compat_sigset_word      sig[_COMPAT_NSIG_WORDS];
 } compat_sigset_t;
 
-extern int get_compat_timespec(struct timespec *, const struct compat_timespec __user *);
-extern int put_compat_timespec(const struct timespec *, struct compat_timespec __user *);
+extern int get_compat_timespec(struct timespec *,
+                              const struct compat_timespec __user *);
+extern int put_compat_timespec(const struct timespec *,
+                              struct compat_timespec __user *);
 
 struct compat_iovec {
        compat_uptr_t   iov_base;
@@ -113,7 +117,8 @@ struct compat_rusage {
        compat_long_t   ru_nivcsw;
 };
 
-extern int put_compat_rusage(const struct rusage *, struct compat_rusage __user *);
+extern int put_compat_rusage(const struct rusage *,
+                            struct compat_rusage __user *);
 
 struct compat_siginfo;
 
@@ -166,8 +171,7 @@ struct compat_ifmap {
        unsigned char port;
 };
 
-struct compat_if_settings
-{
+struct compat_if_settings {
        unsigned int type;      /* Type of physical device or protocol */
        unsigned int size;      /* Size of the data allocated by the caller */
        compat_uptr_t ifs_ifsu; /* union of pointers */
@@ -195,8 +199,8 @@ struct compat_ifreq {
 };
 
 struct compat_ifconf {
-        compat_int_t   ifc_len;                        /* size of buffer       */
-        compat_caddr_t  ifcbuf;
+       compat_int_t    ifc_len;                /* size of buffer */
+       compat_caddr_t  ifcbuf;
 };
 
 struct compat_robust_list {
@@ -209,6 +213,18 @@ struct compat_robust_list_head {
        compat_uptr_t                   list_op_pending;
 };
 
+struct compat_statfs;
+struct compat_statfs64;
+struct compat_old_linux_dirent;
+struct compat_linux_dirent;
+struct linux_dirent64;
+struct compat_msghdr;
+struct compat_mmsghdr;
+struct compat_sysinfo;
+struct compat_sysctl_args;
+struct compat_kexec_segment;
+struct compat_mq_attr;
+
 extern void compat_exit_robust_list(struct task_struct *curr);
 
 asmlinkage long
@@ -243,8 +259,8 @@ asmlinkage ssize_t compat_sys_pwritev(unsigned long fd,
                const struct compat_iovec __user *vec,
                unsigned long vlen, u32 pos_low, u32 pos_high);
 
-int compat_do_execve(char * filename, compat_uptr_t __user *argv,
-               compat_uptr_t __user *envp, struct pt_regs * regs);
+int compat_do_execve(char *filename, compat_uptr_t __user *argv,
+                    compat_uptr_t __user *envp, struct pt_regs *regs);
 
 asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
                compat_ulong_t __user *outp, compat_ulong_t __user *exp,
@@ -331,12 +347,18 @@ asmlinkage long compat_sys_epoll_pwait(int epfd,
                        const compat_sigset_t __user *sigmask,
                        compat_size_t sigsetsize);
 
-asmlinkage long compat_sys_utimensat(unsigned int dfd, const char __user *filename,
-                               struct compat_timespec __user *t, int flags);
+asmlinkage long compat_sys_utime(const char __user *filename,
+                                struct compat_utimbuf __user *t);
+asmlinkage long compat_sys_utimensat(unsigned int dfd,
+                                    const char __user *filename,
+                                    struct compat_timespec __user *t,
+                                    int flags);
 
+asmlinkage long compat_sys_time(compat_time_t __user *tloc);
+asmlinkage long compat_sys_stime(compat_time_t __user *tptr);
 asmlinkage long compat_sys_signalfd(int ufd,
-                               const compat_sigset_t __user *sigmask,
-                                compat_size_t sigsetsize);
+                                   const compat_sigset_t __user *sigmask,
+                                   compat_size_t sigsetsize);
 asmlinkage long compat_sys_timerfd_settime(int ufd, int flags,
                                   const struct compat_itimerspec __user *utmr,
                                   struct compat_itimerspec __user *otmr);
@@ -348,16 +370,190 @@ asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_page,
                                      const int __user *nodes,
                                      int __user *status,
                                      int flags);
-asmlinkage long compat_sys_futimesat(unsigned int dfd, const char __user *filename,
+asmlinkage long compat_sys_futimesat(unsigned int dfd,
+                                    const char __user *filename,
                                     struct compat_timeval __user *t);
-asmlinkage long compat_sys_newfstatat(unsigned int dfd, const char __user * filename,
+asmlinkage long compat_sys_utimes(const char __user *filename,
+                                 struct compat_timeval __user *t);
+asmlinkage long compat_sys_newstat(const char __user *filename,
+                                  struct compat_stat __user *statbuf);
+asmlinkage long compat_sys_newlstat(const char __user *filename,
+                                   struct compat_stat __user *statbuf);
+asmlinkage long compat_sys_newfstatat(unsigned int dfd,
+                                     const char __user *filename,
                                      struct compat_stat __user *statbuf,
                                      int flag);
+asmlinkage long compat_sys_newfstat(unsigned int fd,
+                                   struct compat_stat __user *statbuf);
+asmlinkage long compat_sys_statfs(const char __user *pathname,
+                                 struct compat_statfs __user *buf);
+asmlinkage long compat_sys_fstatfs(unsigned int fd,
+                                  struct compat_statfs __user *buf);
+asmlinkage long compat_sys_statfs64(const char __user *pathname,
+                                   compat_size_t sz,
+                                   struct compat_statfs64 __user *buf);
+asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz,
+                                    struct compat_statfs64 __user *buf);
+asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
+                                  unsigned long arg);
+asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd,
+                                unsigned long arg);
+asmlinkage long compat_sys_io_setup(unsigned nr_reqs, u32 __user *ctx32p);
+asmlinkage long compat_sys_io_getevents(aio_context_t ctx_id,
+                                       unsigned long min_nr,
+                                       unsigned long nr,
+                                       struct io_event __user *events,
+                                       struct compat_timespec __user *timeout);
+asmlinkage long compat_sys_io_submit(aio_context_t ctx_id, int nr,
+                                    u32 __user *iocb);
+asmlinkage long compat_sys_mount(const char __user *dev_name,
+                                const char __user *dir_name,
+                                const char __user *type, unsigned long flags,
+                                const void __user *data);
+asmlinkage long compat_sys_old_readdir(unsigned int fd,
+                                      struct compat_old_linux_dirent __user *,
+                                      unsigned int count);
+asmlinkage long compat_sys_getdents(unsigned int fd,
+                                   struct compat_linux_dirent __user *dirent,
+                                   unsigned int count);
+asmlinkage long compat_sys_getdents64(unsigned int fd,
+                                     struct linux_dirent64 __user *dirent,
+                                     unsigned int count);
+asmlinkage long compat_sys_vmsplice(int fd, const struct compat_iovec __user *,
+                                   unsigned int nr_segs, unsigned int flags);
+asmlinkage long compat_sys_open(const char __user *filename, int flags,
+                               int mode);
 asmlinkage long compat_sys_openat(unsigned int dfd, const char __user *filename,
                                  int flags, int mode);
+asmlinkage long compat_sys_open_by_handle_at(int mountdirfd,
+                                            struct file_handle __user *handle,
+                                            int flags);
+asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp,
+                                   compat_ulong_t __user *outp,
+                                   compat_ulong_t __user *exp,
+                                   struct compat_timespec __user *tsp,
+                                   void __user *sig);
+asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
+                                unsigned int nfds,
+                                struct compat_timespec __user *tsp,
+                                const compat_sigset_t __user *sigmask,
+                                compat_size_t sigsetsize);
+#if (defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)) && \
+       !defined(CONFIG_NFSD_DEPRECATED)
+union compat_nfsctl_res;
+struct compat_nfsctl_arg;
+asmlinkage long compat_sys_nfsservctl(int cmd,
+                                     struct compat_nfsctl_arg __user *arg,
+                                     union compat_nfsctl_res __user *res);
+#else
+asmlinkage long compat_sys_nfsservctl(int cmd, void *notused, void *notused2);
+#endif
+asmlinkage long compat_sys_signalfd4(int ufd,
+                                    const compat_sigset_t __user *sigmask,
+                                    compat_size_t sigsetsize, int flags);
+asmlinkage long compat_sys_get_mempolicy(int __user *policy,
+                                        compat_ulong_t __user *nmask,
+                                        compat_ulong_t maxnode,
+                                        compat_ulong_t addr,
+                                        compat_ulong_t flags);
+asmlinkage long compat_sys_set_mempolicy(int mode, compat_ulong_t __user *nmask,
+                                        compat_ulong_t maxnode);
+asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len,
+                                compat_ulong_t mode,
+                                compat_ulong_t __user *nmask,
+                                compat_ulong_t maxnode, compat_ulong_t flags);
+
+asmlinkage long compat_sys_setsockopt(int fd, int level, int optname,
+                                     char __user *optval, unsigned int optlen);
+asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg,
+                                  unsigned flags);
+asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg,
+                                  unsigned int flags);
+asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len,
+                               unsigned flags);
+asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, size_t len,
+                           unsigned flags, struct sockaddr __user *addr,
+                           int __user *addrlen);
+asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
+                                   unsigned vlen, unsigned int flags,
+                                   struct compat_timespec __user *timeout);
+asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp,
+                                    struct compat_timespec __user *rmtp);
+asmlinkage long compat_sys_getitimer(int which,
+                                    struct compat_itimerval __user *it);
+asmlinkage long compat_sys_setitimer(int which,
+                                    struct compat_itimerval __user *in,
+                                    struct compat_itimerval __user *out);
+asmlinkage long compat_sys_times(struct compat_tms __user *tbuf);
+asmlinkage long compat_sys_setrlimit(unsigned int resource,
+                                    struct compat_rlimit __user *rlim);
+asmlinkage long compat_sys_getrlimit(unsigned int resource,
+                                    struct compat_rlimit __user *rlim);
+asmlinkage long compat_sys_getrusage(int who, struct compat_rusage __user *ru);
+asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid,
+                                    unsigned int len,
+                                    compat_ulong_t __user *user_mask_ptr);
+asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid,
+                                    unsigned int len,
+                                    compat_ulong_t __user *user_mask_ptr);
+asmlinkage long compat_sys_timer_create(clockid_t which_clock,
+                       struct compat_sigevent __user *timer_event_spec,
+                       timer_t __user *created_timer_id);
+asmlinkage long compat_sys_timer_settime(timer_t timer_id, int flags,
+                                        struct compat_itimerspec __user *new,
+                                        struct compat_itimerspec __user *old);
+asmlinkage long compat_sys_timer_gettime(timer_t timer_id,
+                                struct compat_itimerspec __user *setting);
+asmlinkage long compat_sys_clock_settime(clockid_t which_clock,
+                                        struct compat_timespec __user *tp);
+asmlinkage long compat_sys_clock_gettime(clockid_t which_clock,
+                                        struct compat_timespec __user *tp);
+asmlinkage long compat_sys_clock_adjtime(clockid_t which_clock,
+                                        struct compat_timex __user *tp);
+asmlinkage long compat_sys_clock_getres(clockid_t which_clock,
+                                       struct compat_timespec __user *tp);
+asmlinkage long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,
+                                          struct compat_timespec __user *rqtp,
+                                          struct compat_timespec __user *rmtp);
+asmlinkage long compat_sys_rt_sigtimedwait(compat_sigset_t __user *uthese,
+               struct compat_siginfo __user *uinfo,
+               struct compat_timespec __user *uts, compat_size_t sigsetsize);
+asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset,
+                                        compat_size_t sigsetsize);
+asmlinkage long compat_sys_sysinfo(struct compat_sysinfo __user *info);
+asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
+                                unsigned long arg);
+asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
+               struct compat_timespec __user *utime, u32 __user *uaddr2,
+               u32 val3);
+asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
+                                     char __user *optval, int __user *optlen);
+asmlinkage long compat_sys_kexec_load(unsigned long entry,
+                                     unsigned long nr_segments,
+                                     struct compat_kexec_segment __user *,
+                                     unsigned long flags);
+asmlinkage long compat_sys_mq_getsetattr(mqd_t mqdes,
+                       const struct compat_mq_attr __user *u_mqstat,
+                       struct compat_mq_attr __user *u_omqstat);
+asmlinkage long compat_sys_mq_notify(mqd_t mqdes,
+                       const struct compat_sigevent __user *u_notification);
+asmlinkage long compat_sys_mq_open(const char __user *u_name,
+                       int oflag, compat_mode_t mode,
+                       struct compat_mq_attr __user *u_attr);
+asmlinkage long compat_sys_mq_timedsend(mqd_t mqdes,
+                       const char __user *u_msg_ptr,
+                       size_t msg_len, unsigned int msg_prio,
+                       const struct compat_timespec __user *u_abs_timeout);
+asmlinkage ssize_t compat_sys_mq_timedreceive(mqd_t mqdes,
+                       char __user *u_msg_ptr,
+                       size_t msg_len, unsigned int __user *u_msg_prio,
+                       const struct compat_timespec __user *u_abs_timeout);
+asmlinkage long compat_sys_socketcall(int call, u32 __user *args);
+asmlinkage long compat_sys_sysctl(struct compat_sysctl_args __user *args);
 
 extern ssize_t compat_rw_copy_check_uvector(int type,
-               const struct compat_iovec __user *uvector, unsigned long nr_segs,
+               const struct compat_iovec __user *uvector,
+               unsigned long nr_segs,
                unsigned long fast_segs, struct iovec *fast_pointer,
                struct iovec **ret_pointer);
 
index cb4c1eb7778e4f776bf9343f93d5f9c8636ab148..59e4028e833d0ffe7c1fa11844cc5ebd027886f9 100644 (file)
     __asm__ ("" : "=r"(__ptr) : "0"(ptr));             \
     (typeof(ptr)) (__ptr + (off)); })
 
+#ifdef __CHECKER__
+#define __must_be_array(arr) 0
+#else
 /* &a[0] degrades to a pointer: a different type from an array */
 #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
+#endif
 
 /*
  * Force always-inline if the user requests it so via the .config,
index 64b7c003fd7a50c056d98f0a2aa412da067a753d..dfadc96e9d63851c334885f0ec7761c8d6cfe3ff 100644 (file)
@@ -51,7 +51,7 @@
 #if __GNUC_MINOR__ > 0
 #define __compiletime_object_size(obj) __builtin_object_size(obj, 0)
 #endif
-#if __GNUC_MINOR__ >= 4
+#if __GNUC_MINOR__ >= 4 && !defined(__CHECKER__)
 #define __compiletime_warning(message) __attribute__((warning(message)))
 #define __compiletime_error(message) __attribute__((error(message)))
 #endif
index bae6fe24d1f9de103d75d40b6439f7e17a406b2a..b24ac56477b46bea69e7e748c04896cc564eda43 100644 (file)
@@ -546,6 +546,21 @@ static inline int cpumask_parse_user(const char __user *buf, int len,
        return bitmap_parse_user(buf, len, cpumask_bits(dstp), nr_cpumask_bits);
 }
 
+/**
+ * cpumask_parselist_user - extract a cpumask from a user string
+ * @buf: the buffer to extract from
+ * @len: the length of the buffer
+ * @dstp: the cpumask to set.
+ *
+ * Returns -errno, or 0 for success.
+ */
+static inline int cpumask_parselist_user(const char __user *buf, int len,
+                                    struct cpumask *dstp)
+{
+       return bitmap_parselist_user(buf, len, cpumask_bits(dstp),
+                                                       nr_cpumask_bits);
+}
+
 /**
  * cpulist_scnprintf - print a cpumask into a string as comma-separated list
  * @buf: the buffer to sprintf into
index f20eb8f16025d74534dd2b62fa22cf494404ef1c..e9eaec522655c4da77f55fefb851564c31cae711 100644 (file)
@@ -146,7 +146,7 @@ static inline void cpuset_cpus_allowed(struct task_struct *p,
 
 static inline int cpuset_cpus_allowed_fallback(struct task_struct *p)
 {
-       cpumask_copy(&p->cpus_allowed, cpu_possible_mask);
+       do_set_cpus_allowed(p, cpu_possible_mask);
        return cpumask_any(cpu_active_mask);
 }
 
index 088cd4ace4ef756c542cffc66e9b8a42f5ad1b38..74054074e876d8da1ae9de24dc8ae64f856391c7 100644 (file)
@@ -66,6 +66,11 @@ static inline void vmcore_unusable(void)
        if (is_kdump_kernel())
                elfcorehdr_addr = ELFCORE_ADDR_ERR;
 }
+
+#define HAVE_OLDMEM_PFN_IS_RAM 1
+extern int register_oldmem_pfn_is_ram(int (*fn)(unsigned long pfn));
+extern void unregister_oldmem_pfn_is_ram(void);
+
 #else /* !CONFIG_CRASH_DUMP */
 static inline int is_kdump_kernel(void) { return 0; }
 #endif /* CONFIG_CRASH_DUMP */
index be16b61283ccb9855eabe82a97e4fd2345409f90..82607992f308aa4510f15c1becd64158e86947ca 100644 (file)
@@ -1,4 +1,4 @@
-/* Credentials management - see Documentation/credentials.txt
+/* Credentials management - see Documentation/security/credentials.txt
  *
  * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
index 32a4423710f51e54045413415a53b6b8cd0afd56..4427e04540516ef006e08ce8de95bebc23516905 100644 (file)
@@ -191,6 +191,12 @@ struct dm_target {
 
        /* Used to provide an error string from the ctr */
        char *error;
+
+       /*
+        * Set if this target needs to receive discards regardless of
+        * whether or not its underlying devices have support.
+        */
+       unsigned discards_supported:1;
 };
 
 /* Each target can link one of these into the table */
index c66111affca9a6e93f246b66f39ff5e4b998da58..553fd37b173b14cc41bed5d083f9f064d8d37a9f 100644 (file)
@@ -654,13 +654,13 @@ static inline int device_is_registered(struct device *dev)
 
 static inline void device_enable_async_suspend(struct device *dev)
 {
-       if (!dev->power.in_suspend)
+       if (!dev->power.is_prepared)
                dev->power.async_suspend = true;
 }
 
 static inline void device_disable_async_suspend(struct device *dev)
 {
-       if (!dev->power.in_suspend)
+       if (!dev->power.is_prepared)
                dev->power.async_suspend = false;
 }
 
index 0b0d9c39ed670d10c1ddf7d9863fbbb67cfd356b..7aad1f440867e796ed6f5d2c811771e700e7ad15 100644 (file)
@@ -2,8 +2,16 @@
 #include <linux/fs.h>
 
 #ifdef CONFIG_CGROUP_DEVICE
-extern int devcgroup_inode_permission(struct inode *inode, int mask);
+extern int __devcgroup_inode_permission(struct inode *inode, int mask);
 extern int devcgroup_inode_mknod(int mode, dev_t dev);
+static inline int devcgroup_inode_permission(struct inode *inode, int mask)
+{
+       if (likely(!inode->i_rdev))
+               return 0;
+       if (!S_ISBLK(inode->i_mode) && !S_ISCHR(inode->i_mode))
+               return 0;
+       return __devcgroup_inode_permission(inode, mask);
+}
 #else
 static inline int devcgroup_inode_permission(struct inode *inode, int mask)
 { return 0; }
index 2dd21243104ffd72dff12fb7cfa70d1b77de0f69..3b1cc1be419f8b13aa31be413360293c7de052a9 100644 (file)
@@ -14,7 +14,7 @@
 #define DLM_PLOCK_MISC_NAME            "dlm_plock"
 
 #define DLM_PLOCK_VERSION_MAJOR        1
-#define DLM_PLOCK_VERSION_MINOR        1
+#define DLM_PLOCK_VERSION_MINOR        2
 #define DLM_PLOCK_VERSION_PATCH        0
 
 enum {
@@ -23,12 +23,14 @@ enum {
        DLM_PLOCK_OP_GET,
 };
 
+#define DLM_PLOCK_FL_CLOSE 1
+
 struct dlm_plock_info {
        __u32 version[3];
        __u8 optype;
        __u8 ex;
        __u8 wait;
-       __u8 pad;
+       __u8 flags;
        __u32 pid;
        __s32 nodeid;
        __s32 rv;
index 5c9186b93fff0794488233df3afce65be8471e47..f4b0aa3126f5deae8ff8908375a9da1eca790ecf 100644 (file)
@@ -69,8 +69,7 @@ struct dm_io_request {
  *
  * Create/destroy may block.
  */
-struct dm_io_client *dm_io_client_create(unsigned num_pages);
-int dm_io_client_resize(unsigned num_pages, struct dm_io_client *client);
+struct dm_io_client *dm_io_client_create(void);
 void dm_io_client_destroy(struct dm_io_client *client);
 
 /*
index 5db21631169567af72279f3d2fc65bec48c511ea..298d587e349b17169ad1a295645f66e307f42ff4 100644 (file)
@@ -25,8 +25,7 @@
  * To use kcopyd you must first create a dm_kcopyd_client object.
  */
 struct dm_kcopyd_client;
-int dm_kcopyd_client_create(unsigned num_pages,
-                           struct dm_kcopyd_client **result);
+struct dm_kcopyd_client *dm_kcopyd_client_create(void);
 void dm_kcopyd_client_destroy(struct dm_kcopyd_client *kc);
 
 /*
index 5619f8522738b44f3318392da050e7ef9f246020..bbd8661b34736f80e392f05d8b0fcdeff5fdf067 100644 (file)
@@ -9,8 +9,12 @@
 #define VTD_PAGE_MASK          (((u64)-1) << VTD_PAGE_SHIFT)
 #define VTD_PAGE_ALIGN(addr)   (((addr) + VTD_PAGE_SIZE - 1) & VTD_PAGE_MASK)
 
+#define VTD_STRIDE_SHIFT        (9)
+#define VTD_STRIDE_MASK         (((u64)-1) << VTD_STRIDE_SHIFT)
+
 #define DMA_PTE_READ (1)
 #define DMA_PTE_WRITE (2)
+#define DMA_PTE_LARGE_PAGE (1 << 7)
 #define DMA_PTE_SNP (1 << 11)
 
 #define CONTEXT_TT_MULTI_LEVEL 0
index cec467f5d6768ae92f958058ab93f20edba28ec6..9e5f5607eba36b918db8beb8a3bf0c1a807e9ecc 100644 (file)
@@ -38,7 +38,7 @@
 
 /* Although the Linux source code makes a difference between
    generic endianness and the bitfields' endianness, there is no
-   architecture as of Linux-2.6.24-rc4 where the bitfileds' endianness
+   architecture as of Linux-2.6.24-rc4 where the bitfields' endianness
    does not match the generic endianness. */
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -53,7 +53,7 @@
 
 
 extern const char *drbd_buildtag(void);
-#define REL_VERSION "8.3.10"
+#define REL_VERSION "8.3.11"
 #define API_VERSION 88
 #define PRO_VERSION_MIN 86
 #define PRO_VERSION_MAX 96
@@ -195,7 +195,7 @@ enum drbd_conns {
        C_WF_REPORT_PARAMS, /* we have a socket */
        C_CONNECTED,      /* we have introduced each other */
        C_STARTING_SYNC_S,  /* starting full sync by admin request. */
-       C_STARTING_SYNC_T,  /* stariing full sync by admin request. */
+       C_STARTING_SYNC_T,  /* starting full sync by admin request. */
        C_WF_BITMAP_S,
        C_WF_BITMAP_T,
        C_WF_SYNC_UUID,
@@ -236,7 +236,7 @@ union drbd_state {
  * pointed out by Maxim Uvarov q<muvarov@ru.mvista.com>
  * even though we transmit as "cpu_to_be32(state)",
  * the offsets of the bitfields still need to be swapped
- * on different endianess.
+ * on different endianness.
  */
        struct {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
@@ -266,7 +266,7 @@ union drbd_state {
                unsigned peer:2 ;   /* 3/4       primary/secondary/unknown */
                unsigned role:2 ;   /* 3/4       primary/secondary/unknown */
 #else
-# error "this endianess is not supported"
+# error "this endianness is not supported"
 #endif
        };
        unsigned int i;
index f14a165e82dc162ef0306d6dc8d9d7266a816387..0695431905162cdc1c50aad7b23efa2e5f0810ec 100644 (file)
@@ -30,7 +30,7 @@ enum packet_types {
        int tag_and_len ## member;
 #include "linux/drbd_nl.h"
 
-/* declate tag-list-sizes */
+/* declare tag-list-sizes */
 static const int tag_list_sizes[] = {
 #define NL_PACKET(name, number, fields) 2 fields ,
 #define NL_INTEGER(pn, pr, member)      + 4 + 4
index 6998d9376ef902781acd1c13d06ebdbbff9f56fe..4bfe0a2f7d50cc218bce24040154286a582aaf94 100644 (file)
@@ -3,6 +3,7 @@
  * AVR32 systems.)
  *
  * Copyright (C) 2007 Atmel Corporation
+ * Copyright (C) 2010-2011 ST Microelectronics
  *
  * 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
index 33fa1203024e4ec601d75180a496f6de242a4650..e376270cd26e648d9a2fdecec685e0d5ae4474c3 100644 (file)
@@ -299,6 +299,7 @@ extern void efi_initialize_iomem_resources(struct resource *code_resource,
                struct resource *data_resource, struct resource *bss_resource);
 extern unsigned long efi_get_time(void);
 extern int efi_set_rtc_mmss(unsigned long nowtime);
+extern void efi_reserve_boot_services(void);
 extern struct efi_memory_map memmap;
 
 /**
index c6a850ab2ec5b6f0f8b2fdc75a8dec25510ffc0e..439b173c58822a6438bc73cdd71bf01a3beee64a 100644 (file)
@@ -268,7 +268,7 @@ struct ethtool_pauseparam {
        __u32   cmd;    /* ETHTOOL_{G,S}PAUSEPARAM */
 
        /* If the link is being auto-negotiated (via ethtool_cmd.autoneg
-        * being true) the user may set 'autonet' here non-zero to have the
+        * being true) the user may set 'autoneg' here non-zero to have the
         * pause parameters be auto-negotiated too.  In such a case, the
         * {rx,tx}_pause values below determine what capabilities are
         * advertised.
@@ -811,7 +811,7 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported);
  * @get_tx_csum: Deprecated as redundant. Report whether transmit checksums
  *     are turned on or off.
  * @set_tx_csum: Deprecated in favour of generic netdev features.  Turn
- *     transmit checksums on or off.  Returns a egative error code or zero.
+ *     transmit checksums on or off.  Returns a negative error code or zero.
  * @get_sg: Deprecated as redundant.  Report whether scatter-gather is
  *     enabled.  
  * @set_sg: Deprecated in favour of generic netdev features.  Turn
@@ -1087,7 +1087,7 @@ struct ethtool_ops {
 /* The following are all involved in forcing a particular link
  * mode for the device for setting things.  When getting the
  * devices settings, these indicate the current mode and whether
- * it was foced up into this mode or autonegotiated.
+ * it was forced up into this mode or autonegotiated.
  */
 
 /* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */
index 85c1d302c12ec6833c013fc076b801da85a07abc..5e06acf95d0f84271b637f41711749c6968a32b4 100644 (file)
@@ -909,7 +909,7 @@ extern int  ext3_setattr (struct dentry *, struct iattr *);
 extern void ext3_evict_inode (struct inode *);
 extern int  ext3_sync_inode (handle_t *, struct inode *);
 extern void ext3_discard_reservation (struct inode *);
-extern void ext3_dirty_inode(struct inode *);
+extern void ext3_dirty_inode(struct inode *, int);
 extern int ext3_change_inode_journal_flag(struct inode *, int);
 extern int ext3_get_inode_loc(struct inode *, struct ext3_iloc *);
 extern int ext3_can_truncate(struct inode *inode);
index ebeb2f3ad068db1ec6d8cee92a1bcfb6cd097630..6843cf193a445134cde17f7d2db6893399ac8cda 100644 (file)
@@ -21,6 +21,8 @@ struct flex_array {
                struct {
                        int element_size;
                        int total_nr_elements;
+                       int elems_per_part;
+                       u32 reciprocal_elems;
                        struct flex_array_part *parts[];
                };
                /*
index cdf9495df204aa917605613b220c852349528b54..6e73e2e9ae33c5b7719f11fb303cee693dc1b043 100644 (file)
@@ -23,7 +23,8 @@
 
 /* Fixed constants first: */
 #undef NR_OPEN
-#define INR_OPEN 1024          /* Initial setting for nfile rlimits */
+#define INR_OPEN_CUR 1024      /* Initial setting for nfile rlimits */
+#define INR_OPEN_MAX 4096      /* Hard limit for nfile rlimits */
 
 #define BLOCK_SIZE_BITS 10
 #define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
@@ -207,6 +208,7 @@ struct inodes_stat_t {
 #define MS_KERNMOUNT   (1<<22) /* this is a kern_mount call */
 #define MS_I_VERSION   (1<<23) /* Update inode I_version field */
 #define MS_STRICTATIME (1<<24) /* Always perform atime updates */
+#define MS_NOSEC       (1<<28)
 #define MS_BORN                (1<<29)
 #define MS_ACTIVE      (1<<30)
 #define MS_NOUSER      (1<<31)
@@ -236,6 +238,7 @@ struct inodes_stat_t {
 #define S_PRIVATE      512     /* Inode is fs-internal */
 #define S_IMA          1024    /* Inode has an associated IMA struct */
 #define S_AUTOMOUNT    2048    /* Automount/referral quasi-directory */
+#define S_NOSEC                4096    /* no suid or xattr security attributes */
 
 /*
  * Note that nosuid etc flags are inode-specific: setting some file-system
@@ -272,6 +275,7 @@ struct inodes_stat_t {
 #define IS_PRIVATE(inode)      ((inode)->i_flags & S_PRIVATE)
 #define IS_IMA(inode)          ((inode)->i_flags & S_IMA)
 #define IS_AUTOMOUNT(inode)    ((inode)->i_flags & S_AUTOMOUNT)
+#define IS_NOSEC(inode)                ((inode)->i_flags & S_NOSEC)
 
 /* the read-only stuff doesn't really belong here, but any other place is
    probably as bad and I don't want to create yet another include file. */
@@ -634,8 +638,7 @@ struct address_space {
        unsigned int            i_mmap_writable;/* count VM_SHARED mappings */
        struct prio_tree_root   i_mmap;         /* tree of private and shared mappings */
        struct list_head        i_mmap_nonlinear;/*list VM_NONLINEAR mappings */
-       spinlock_t              i_mmap_lock;    /* protect tree, count, list */
-       unsigned int            truncate_count; /* Cover race condition with truncate */
+       struct mutex            i_mmap_mutex;   /* protect tree, count, list */
        unsigned long           nrpages;        /* number of total pages */
        pgoff_t                 writeback_index;/* writeback starts here */
        const struct address_space_operations *a_ops;   /* methods */
@@ -644,7 +647,6 @@ struct address_space {
        spinlock_t              private_lock;   /* for use by the address_space */
        struct list_head        private_list;   /* ditto */
        struct address_space    *assoc_mapping; /* ditto */
-       struct mutex            unmap_mutex;    /* to protect unmapping */
 } __attribute__((aligned(sizeof(long))));
        /*
         * On most architectures that alignment is already the case; but
@@ -742,9 +744,13 @@ struct inode {
 
        spinlock_t              i_lock; /* i_blocks, i_bytes, maybe i_size */
        unsigned int            i_flags;
+       unsigned long           i_state;
+#ifdef CONFIG_SECURITY
+       void                    *i_security;
+#endif
        struct mutex            i_mutex;
 
-       unsigned long           i_state;
+
        unsigned long           dirtied_when;   /* jiffies of first dirtying */
 
        struct hlist_node       i_hash;
@@ -796,9 +802,6 @@ struct inode {
        atomic_t                i_readcount; /* struct files open RO */
 #endif
        atomic_t                i_writecount;
-#ifdef CONFIG_SECURITY
-       void                    *i_security;
-#endif
 #ifdef CONFIG_FS_POSIX_ACL
        struct posix_acl        *i_acl;
        struct posix_acl        *i_default_acl;
@@ -1429,6 +1432,11 @@ struct super_block {
         */
        char __rcu *s_options;
        const struct dentry_operations *s_d_op; /* default d_op for dentries */
+
+       /*
+        * Saved pool identifier for cleancache (-1 means none)
+        */
+       int cleancache_poolid;
 };
 
 extern struct timespec current_fs_time(struct super_block *sb);
@@ -1614,7 +1622,7 @@ struct super_operations {
        struct inode *(*alloc_inode)(struct super_block *sb);
        void (*destroy_inode)(struct inode *);
 
-       void (*dirty_inode) (struct inode *);
+       void (*dirty_inode) (struct inode *, int flags);
        int (*write_inode) (struct inode *, struct writeback_control *wbc);
        int (*drop_inode) (struct inode *);
        void (*evict_inode) (struct inode *);
@@ -2578,5 +2586,16 @@ int __init get_filesystem_list(char *buf);
 #define OPEN_FMODE(flag) ((__force fmode_t)(((flag + 1) & O_ACCMODE) | \
                                            (flag & __FMODE_NONOTIFY)))
 
+static inline int is_sxid(mode_t mode)
+{
+       return (mode & S_ISUID) || ((mode & S_ISGID) && (mode & S_IXGRP));
+}
+
+static inline void inode_has_no_xattr(struct inode *inode)
+{
+       if (!is_sxid(inode->i_mode) && (inode->i_sb->s_flags & MS_NOSEC))
+               inode->i_flags |= S_NOSEC;
+}
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_FS_H */
index 76427e688d1581f590478fcf8447a4443223901f..af095b54502e35471cad25d0e74e042fb50ecc4f 100644 (file)
@@ -100,17 +100,6 @@ struct fscache_operation {
 
        /* operation releaser */
        fscache_operation_release_t release;
-
-#ifdef CONFIG_WORKQUEUE_DEBUGFS
-       struct work_struct put_work;    /* work to delay operation put */
-       const char *name;               /* operation name */
-       const char *state;              /* operation state */
-#define fscache_set_op_name(OP, N)     do { (OP)->name  = (N); } while(0)
-#define fscache_set_op_state(OP, S)    do { (OP)->state = (S); } while(0)
-#else
-#define fscache_set_op_name(OP, N)     do { } while(0)
-#define fscache_set_op_state(OP, S)    do { } while(0)
-#endif
 };
 
 extern atomic_t fscache_op_debug_id;
@@ -137,7 +126,6 @@ static inline void fscache_operation_init(struct fscache_operation *op,
        op->processor = processor;
        op->release = release;
        INIT_LIST_HEAD(&op->pend_link);
-       fscache_set_op_state(op, "Init");
 }
 
 /*
index b5a550a39a70ddd0a119479ce4a528892c6a7aa9..59d3ef100eb9310a9c2c0cff903d6cae259d0810 100644 (file)
@@ -16,6 +16,11 @@ struct trace_print_flags {
        const char              *name;
 };
 
+struct trace_print_flags_u64 {
+       unsigned long long      mask;
+       const char              *name;
+};
+
 const char *ftrace_print_flags_seq(struct trace_seq *p, const char *delim,
                                   unsigned long flags,
                                   const struct trace_print_flags *flag_array);
@@ -23,6 +28,13 @@ const char *ftrace_print_flags_seq(struct trace_seq *p, const char *delim,
 const char *ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val,
                                     const struct trace_print_flags *symbol_array);
 
+#if BITS_PER_LONG == 32
+const char *ftrace_print_symbols_seq_u64(struct trace_seq *p,
+                                        unsigned long long val,
+                                        const struct trace_print_flags_u64
+                                                                *symbol_array);
+#endif
+
 const char *ftrace_print_hex_seq(struct trace_seq *p,
                                 const unsigned char *buf, int len);
 
index 9869ef3674acbfe0f1a8fbad4fd20286c092c3be..5bbebda78b025d8bc63b2c24e960d20733fa2613 100644 (file)
@@ -9,6 +9,8 @@
  */
 
 
+#ifndef __GENALLOC_H__
+#define __GENALLOC_H__
 /*
  *  General purpose special memory pool descriptor.
  */
@@ -24,13 +26,34 @@ struct gen_pool {
 struct gen_pool_chunk {
        spinlock_t lock;
        struct list_head next_chunk;    /* next chunk in pool */
+       phys_addr_t phys_addr;          /* physical starting address of memory chunk */
        unsigned long start_addr;       /* starting address of memory chunk */
        unsigned long end_addr;         /* ending address of memory chunk */
        unsigned long bits[0];          /* bitmap for allocating memory chunk */
 };
 
 extern struct gen_pool *gen_pool_create(int, int);
-extern int gen_pool_add(struct gen_pool *, unsigned long, size_t, int);
+extern phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long);
+extern int gen_pool_add_virt(struct gen_pool *, unsigned long, phys_addr_t,
+                            size_t, int);
+/**
+ * gen_pool_add - add a new chunk of special memory to the pool
+ * @pool: pool to add new memory chunk to
+ * @addr: starting address of memory chunk to add to pool
+ * @size: size in bytes of the memory chunk to add to pool
+ * @nid: node id of the node the chunk structure and bitmap should be
+ *       allocated on, or -1
+ *
+ * Add a new chunk of special memory to the specified pool.
+ *
+ * Returns 0 on success or a -ve errno on failure.
+ */
+static inline int gen_pool_add(struct gen_pool *pool, unsigned long addr,
+                              size_t size, int nid)
+{
+       return gen_pool_add_virt(pool, addr, -1, size, nid);
+}
 extern void gen_pool_destroy(struct gen_pool *);
 extern unsigned long gen_pool_alloc(struct gen_pool *, size_t);
 extern void gen_pool_free(struct gen_pool *, unsigned long, size_t);
+#endif /* __GENALLOC_H__ */
index d764a426e9fdbf5b5086542e3eeb6c6a2e6d3c8a..300d7582006e49f6ea08a3df09fc9070748c5256 100644 (file)
@@ -127,6 +127,7 @@ struct hd_struct {
 #define GENHD_FL_SUPPRESS_PARTITION_INFO       32
 #define GENHD_FL_EXT_DEVT                      64 /* allow extended devt */
 #define GENHD_FL_NATIVE_CAPACITY               128
+#define GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE    256
 
 enum {
        DISK_EVENT_MEDIA_CHANGE                 = 1 << 0, /* media changed */
index 56d8fc87fbbc70e8f1d5de07aa0bd7aaccd6887c..cb4089254f01feb22fa7db68841f81e7e6b2569c 100644 (file)
@@ -249,14 +249,7 @@ static inline enum zone_type gfp_zone(gfp_t flags)
 
        z = (GFP_ZONE_TABLE >> (bit * ZONES_SHIFT)) &
                                         ((1 << ZONES_SHIFT) - 1);
-
-       if (__builtin_constant_p(bit))
-               BUILD_BUG_ON((GFP_ZONE_BAD >> bit) & 1);
-       else {
-#ifdef CONFIG_DEBUG_VM
-               BUG_ON((GFP_ZONE_BAD >> bit) & 1);
-#endif
-       }
+       VM_BUG_ON((GFP_ZONE_BAD >> bit) & 1);
        return z;
 }
 
index 32720baf70f1c8f1e46741ff8006d44da82f6188..17b5a0d80e4239cc10fceb670be29dbf4e49a0f0 100644 (file)
@@ -3,6 +3,17 @@
 
 /* see Documentation/gpio.txt */
 
+/* make these flag values available regardless of GPIO kconfig options */
+#define GPIOF_DIR_OUT  (0 << 0)
+#define GPIOF_DIR_IN   (1 << 0)
+
+#define GPIOF_INIT_LOW (0 << 1)
+#define GPIOF_INIT_HIGH        (1 << 1)
+
+#define GPIOF_IN               (GPIOF_DIR_IN)
+#define GPIOF_OUT_INIT_LOW     (GPIOF_DIR_OUT | GPIOF_INIT_LOW)
+#define GPIOF_OUT_INIT_HIGH    (GPIOF_DIR_OUT | GPIOF_INIT_HIGH)
+
 #ifdef CONFIG_GENERIC_GPIO
 #include <asm/gpio.h>
 
@@ -25,9 +36,9 @@ struct gpio_chip;
  * warning when something is wrongly called.
  */
 
-static inline int gpio_is_valid(int number)
+static inline bool gpio_is_valid(int number)
 {
-       return 0;
+       return false;
 }
 
 static inline int gpio_request(unsigned gpio, const char *label)
@@ -41,7 +52,7 @@ static inline int gpio_request_one(unsigned gpio,
        return -ENOSYS;
 }
 
-static inline int gpio_request_array(struct gpio *array, size_t num)
+static inline int gpio_request_array(const struct gpio *array, size_t num)
 {
        return -ENOSYS;
 }
@@ -54,7 +65,7 @@ static inline void gpio_free(unsigned gpio)
        WARN_ON(1);
 }
 
-static inline void gpio_free_array(struct gpio *array, size_t num)
+static inline void gpio_free_array(const struct gpio *array, size_t num)
 {
        might_sleep();
 
index dd1a56fbe9241235f4baa059394d5d36bd050de7..b5ca4b2c08ecad2fad00c33d48b62466737966b0 100644 (file)
@@ -3,14 +3,15 @@
 
 struct gpio_keys_button {
        /* Configuration parameters */
-       int code;               /* input event code (KEY_*, SW_*) */
+       unsigned int code;      /* input event code (KEY_*, SW_*) */
        int gpio;
        int active_low;
-       char *desc;
-       int type;               /* input event type (EV_KEY, EV_SW) */
+       const char *desc;
+       unsigned int type;      /* input event type (EV_KEY, EV_SW, EV_ABS) */
        int wakeup;             /* configure the button as a wake-up source */
        int debounce_interval;  /* debounce ticks interval in msecs */
        bool can_disable;
+       int value;              /* axis value for EV_ABS */
 };
 
 struct gpio_keys_platform_data {
@@ -21,6 +22,7 @@ struct gpio_keys_platform_data {
        unsigned int rep:1;             /* enable input subsystem auto repeat */
        int (*enable)(struct device *dev);
        void (*disable)(struct device *dev);
+       const char *name;               /* input device name */
 };
 
 #endif
index 8847c8c29791c8c078dedaf0db9ff6dce85faa23..48c32ebf65a77a2c19b35fe900bc28daf3f64e86 100644 (file)
@@ -92,12 +92,8 @@ extern void __split_huge_page_pmd(struct mm_struct *mm, pmd_t *pmd);
 #define wait_split_huge_page(__anon_vma, __pmd)                                \
        do {                                                            \
                pmd_t *____pmd = (__pmd);                               \
-               spin_unlock_wait(&(__anon_vma)->root->lock);            \
-               /*                                                      \
-                * spin_unlock_wait() is just a loop in C and so the    \
-                * CPU can reorder anything around it.                  \
-                */                                                     \
-               smp_mb();                                               \
+               anon_vma_lock(__anon_vma);                              \
+               anon_vma_unlock(__anon_vma);                            \
                BUG_ON(pmd_trans_splitting(*____pmd) ||                 \
                       pmd_trans_huge(*____pmd));                       \
        } while (0)
index 943c76b3d4bb94d9536ecf8e324bea8ffda853e4..59225ef27d15062813e4799ad95e6df2f57241be 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _LINUX_HUGETLB_H
 #define _LINUX_HUGETLB_H
 
+#include <linux/mm_types.h>
 #include <linux/fs.h>
 #include <linux/hugetlb_inline.h>
 
@@ -41,7 +42,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                        unsigned long address, unsigned int flags);
 int hugetlb_reserve_pages(struct inode *inode, long from, long to,
                                                struct vm_area_struct *vma,
-                                               int acctflags);
+                                               vm_flags_t vm_flags);
 void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed);
 int dequeue_hwpoisoned_huge_page(struct page *page);
 void copy_huge_page(struct page *dst, struct page *src);
@@ -168,7 +169,7 @@ static inline struct hugetlbfs_sb_info *HUGETLBFS_SB(struct super_block *sb)
 
 extern const struct file_operations hugetlbfs_file_operations;
 extern const struct vm_operations_struct hugetlb_vm_ops;
-struct file *hugetlb_file_setup(const char *name, size_t size, int acct,
+struct file *hugetlb_file_setup(const char *name, size_t size, vm_flags_t acct,
                                struct user_struct **user, int creat_flags);
 int hugetlb_get_quota(struct address_space *mapping, long delta);
 void hugetlb_put_quota(struct address_space *mapping, long delta);
@@ -192,7 +193,7 @@ static inline void set_file_hugepages(struct file *file)
 #define is_file_hugepages(file)                        0
 #define set_file_hugepages(file)               BUG()
 static inline struct file *hugetlb_file_setup(const char *name, size_t size,
-               int acctflag, struct user_struct **user, int creat_flags)
+               vm_flags_t acctflag, struct user_struct **user, int creat_flags)
 {
        return ERR_PTR(-ENOSYS);
 }
index 6931489a5c14433e57b28493e306d92f8b1d28d4..2bb681fbeb35b3f4dcdece493931e0679c89d824 100644 (file)
@@ -7,7 +7,7 @@
 
 static inline int is_vm_hugetlb_page(struct vm_area_struct *vma)
 {
-       return vma->vm_flags & VM_HUGETLB;
+       return !!(vma->vm_flags & VM_HUGETLB);
 }
 
 #else
index f1e3ff5880a9f1d6d505f2e1102aeceef10fdb47..a6c652ef516d559dc405cefe5607d08772436e63 100644 (file)
@@ -409,7 +409,7 @@ void i2c_unlock_adapter(struct i2c_adapter *);
 /* i2c adapter classes (bitmask) */
 #define I2C_CLASS_HWMON                (1<<0)  /* lm_sensors, ... */
 #define I2C_CLASS_DDC          (1<<3)  /* DDC bus on graphics adapters */
-#define I2C_CLASS_SPD          (1<<7)  /* SPD EEPROMs and similar */
+#define I2C_CLASS_SPD          (1<<7)  /* Memory modules */
 
 /* Internal numbers to terminate lists */
 #define I2C_CLIENT_END         0xfffeU
diff --git a/include/linux/i2c/adp8870.h b/include/linux/i2c/adp8870.h
new file mode 100644 (file)
index 0000000..624dcec
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Definitions and platform data for Analog Devices
+ * Backlight drivers ADP8870
+ *
+ * Copyright 2009-2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __LINUX_I2C_ADP8870_H
+#define __LINUX_I2C_ADP8870_H
+
+#define ID_ADP8870             8870
+
+#define ADP8870_MAX_BRIGHTNESS 0x7F
+#define FLAG_OFFT_SHIFT 8
+
+/*
+ * LEDs subdevice platform data
+ */
+
+#define ADP8870_LED_DIS_BLINK  (0 << FLAG_OFFT_SHIFT)
+#define ADP8870_LED_OFFT_600ms (1 << FLAG_OFFT_SHIFT)
+#define ADP8870_LED_OFFT_1200ms        (2 << FLAG_OFFT_SHIFT)
+#define ADP8870_LED_OFFT_1800ms        (3 << FLAG_OFFT_SHIFT)
+
+#define ADP8870_LED_ONT_200ms  0
+#define ADP8870_LED_ONT_600ms  1
+#define ADP8870_LED_ONT_800ms  2
+#define ADP8870_LED_ONT_1200ms 3
+
+#define ADP8870_LED_D7         (7)
+#define ADP8870_LED_D6         (6)
+#define ADP8870_LED_D5         (5)
+#define ADP8870_LED_D4         (4)
+#define ADP8870_LED_D3         (3)
+#define ADP8870_LED_D2         (2)
+#define ADP8870_LED_D1         (1)
+
+/*
+ * Backlight subdevice platform data
+ */
+
+#define ADP8870_BL_D7          (1 << 6)
+#define ADP8870_BL_D6          (1 << 5)
+#define ADP8870_BL_D5          (1 << 4)
+#define ADP8870_BL_D4          (1 << 3)
+#define ADP8870_BL_D3          (1 << 2)
+#define ADP8870_BL_D2          (1 << 1)
+#define ADP8870_BL_D1          (1 << 0)
+
+#define ADP8870_FADE_T_DIS     0       /* Fade Timer Disabled */
+#define ADP8870_FADE_T_300ms   1       /* 0.3 Sec */
+#define ADP8870_FADE_T_600ms   2
+#define ADP8870_FADE_T_900ms   3
+#define ADP8870_FADE_T_1200ms  4
+#define ADP8870_FADE_T_1500ms  5
+#define ADP8870_FADE_T_1800ms  6
+#define ADP8870_FADE_T_2100ms  7
+#define ADP8870_FADE_T_2400ms  8
+#define ADP8870_FADE_T_2700ms  9
+#define ADP8870_FADE_T_3000ms  10
+#define ADP8870_FADE_T_3500ms  11
+#define ADP8870_FADE_T_4000ms  12
+#define ADP8870_FADE_T_4500ms  13
+#define ADP8870_FADE_T_5000ms  14
+#define ADP8870_FADE_T_5500ms  15      /* 5.5 Sec */
+
+#define ADP8870_FADE_LAW_LINEAR        0
+#define ADP8870_FADE_LAW_SQUARE        1
+#define ADP8870_FADE_LAW_CUBIC1        2
+#define ADP8870_FADE_LAW_CUBIC2        3
+
+#define ADP8870_BL_AMBL_FILT_80ms      0       /* Light sensor filter time */
+#define ADP8870_BL_AMBL_FILT_160ms     1
+#define ADP8870_BL_AMBL_FILT_320ms     2
+#define ADP8870_BL_AMBL_FILT_640ms     3
+#define ADP8870_BL_AMBL_FILT_1280ms    4
+#define ADP8870_BL_AMBL_FILT_2560ms    5
+#define ADP8870_BL_AMBL_FILT_5120ms    6
+#define ADP8870_BL_AMBL_FILT_10240ms   7       /* 10.24 sec */
+
+/*
+ * Blacklight current 0..30mA
+ */
+#define ADP8870_BL_CUR_mA(I)           ((I * 127) / 30)
+
+/*
+ * L2 comparator current 0..1106uA
+ */
+#define ADP8870_L2_COMP_CURR_uA(I)     ((I * 255) / 1106)
+
+/*
+ * L3 comparator current 0..551uA
+ */
+#define ADP8870_L3_COMP_CURR_uA(I)     ((I * 255) / 551)
+
+/*
+ * L4 comparator current 0..275uA
+ */
+#define ADP8870_L4_COMP_CURR_uA(I)     ((I * 255) / 275)
+
+/*
+ * L5 comparator current 0..138uA
+ */
+#define ADP8870_L5_COMP_CURR_uA(I)     ((I * 255) / 138)
+
+struct adp8870_backlight_platform_data {
+       u8 bl_led_assign;       /* 1 = Backlight 0 = Individual LED */
+       u8 pwm_assign;          /* 1 = Enables PWM mode */
+
+       u8 bl_fade_in;          /* Backlight Fade-In Timer */
+       u8 bl_fade_out;         /* Backlight Fade-Out Timer */
+       u8 bl_fade_law;         /* fade-on/fade-off transfer characteristic */
+
+       u8 en_ambl_sens;        /* 1 = enable ambient light sensor */
+       u8 abml_filt;           /* Light sensor filter time */
+
+       u8 l1_daylight_max;     /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l1_daylight_dim;     /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l2_bright_max;       /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l2_bright_dim;       /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l3_office_max;       /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l3_office_dim;       /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l4_indoor_max;       /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l4_indor_dim;        /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l5_dark_max;         /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
+       u8 l5_dark_dim;         /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
+
+       u8 l2_trip;             /* use L2_COMP_CURR_uA(I) 0 <= I <= 1106 uA */
+       u8 l2_hyst;             /* use L2_COMP_CURR_uA(I) 0 <= I <= 1106 uA */
+       u8 l3_trip;             /* use L3_COMP_CURR_uA(I) 0 <= I <= 551 uA */
+       u8 l3_hyst;             /* use L3_COMP_CURR_uA(I) 0 <= I <= 551 uA */
+       u8 l4_trip;             /* use L4_COMP_CURR_uA(I) 0 <= I <= 275 uA */
+       u8 l4_hyst;             /* use L4_COMP_CURR_uA(I) 0 <= I <= 275 uA */
+       u8 l5_trip;             /* use L5_COMP_CURR_uA(I) 0 <= I <= 138 uA */
+       u8 l5_hyst;             /* use L6_COMP_CURR_uA(I) 0 <= I <= 138 uA */
+
+       /**
+        * Independent Current Sinks / LEDS
+        * Sinks not assigned to the Backlight can be exposed to
+        * user space using the LEDS CLASS interface
+        */
+
+       int num_leds;
+       struct led_info *leds;
+       u8 led_fade_in;         /* LED Fade-In Timer */
+       u8 led_fade_out;        /* LED Fade-Out Timer */
+       u8 led_fade_law;        /* fade-on/fade-off transfer characteristic */
+       u8 led_on_time;
+};
+
+#endif /* __LINUX_I2C_ADP8870_H */
diff --git a/include/linux/i2c/i2c-sh_mobile.h b/include/linux/i2c/i2c-sh_mobile.h
new file mode 100644 (file)
index 0000000..beda708
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __I2C_SH_MOBILE_H__
+#define __I2C_SH_MOBILE_H__
+
+#include <linux/platform_device.h>
+
+struct i2c_sh_mobile_platform_data {
+       unsigned long bus_speed;
+};
+
+#endif /* __I2C_SH_MOBILE_H__ */
diff --git a/include/linux/i2c/mpr121_touchkey.h b/include/linux/i2c/mpr121_touchkey.h
new file mode 100644 (file)
index 0000000..f0bcc38
--- /dev/null
@@ -0,0 +1,20 @@
+/* Header file for Freescale MPR121 Capacitive Touch Sensor */
+
+#ifndef _MPR121_TOUCHKEY_H
+#define _MPR121_TOUCHKEY_H
+
+/**
+ * struct mpr121_platform_data - platform data for mpr121 sensor
+ * @keymap: pointer to array of KEY_* values representing keymap
+ * @keymap_size: size of the keymap
+ * @wakeup: configure the button as a wake-up source
+ * @vdd_uv: VDD voltage in uV
+ */
+struct mpr121_platform_data {
+       const unsigned short *keymap;
+       unsigned int keymap_size;
+       bool wakeup;
+       int vdd_uv;
+};
+
+#endif /* _MPR121_TOUCHKEY_H */
index c6361fbb7bf9e2eb38e087e158910c0b4daf4528..591427a63b062635e991f025222da003915c4911 100644 (file)
@@ -6,6 +6,13 @@
 struct tsc2007_platform_data {
        u16     model;                          /* 2007. */
        u16     x_plate_ohms;
+       u16     max_rt; /* max. resistance above which samples are ignored */
+       unsigned long poll_delay; /* delay (in ms) after pen-down event
+                                    before polling starts */
+       unsigned long poll_period; /* time (in ms) between samples */
+       int     fuzzx; /* fuzz factor for X, Y and pressure axes */
+       int     fuzzy;
+       int     fuzzz;
 
        int     (*get_pendown_state)(void);
        void    (*clear_penirq)(void);          /* If needed, clear 2nd level
index 0c0d1ae79981f90e48fa71eea442a8d06026c7f1..ba4f88624fcd2321fbeffd11ce61ec983e81dd9d 100644 (file)
@@ -91,6 +91,7 @@
 #define BCI_INTR_OFFSET                2
 #define MADC_INTR_OFFSET       3
 #define USB_INTR_OFFSET                4
+#define CHARGERFAULT_INTR_OFFSET 5
 #define BCI_PRES_INTR_OFFSET   9
 #define USB_PRES_INTR_OFFSET   10
 #define RTC_INTR_OFFSET                11
 #define MMC_PU                         (0x1 << 3)
 #define MMC_PD                         (0x1 << 2)
 
-
+#define TWL_SIL_TYPE(rev)              ((rev) & 0x00FFFFFF)
+#define TWL_SIL_REV(rev)               ((rev) >> 24)
+#define TWL_SIL_5030                   0x09002F
+#define TWL5030_REV_1_0                        0x00
+#define TWL5030_REV_1_1                        0x10
+#define TWL5030_REV_1_2                        0x30
 
 #define TWL4030_CLASS_ID               0x4030
 #define TWL6030_CLASS_ID               0x6030
@@ -165,6 +171,8 @@ static inline int twl_class_is_ ##class(void)       \
 TWL_CLASS_IS(4030, TWL4030_CLASS_ID)
 TWL_CLASS_IS(6030, TWL6030_CLASS_ID)
 
+#define TWL6025_SUBCLASS       BIT(4)  /* TWL6025 has changed registers */
+
 /*
  * Read and write single 8-bit registers
  */
@@ -180,6 +188,9 @@ int twl_i2c_read_u8(u8 mod_no, u8 *val, u8 reg);
 int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
 int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
 
+int twl_get_type(void);
+int twl_get_version(void);
+
 int twl6030_interrupt_unmask(u8 bit_mask, u8 offset);
 int twl6030_interrupt_mask(u8 bit_mask, u8 offset);
 
@@ -279,7 +290,12 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
  *(Use TWL_4030_MODULE_INTBR)
  */
 
+#define REG_IDCODE_7_0                 0x00
+#define REG_IDCODE_15_8                        0x01
+#define REG_IDCODE_16_23               0x02
+#define REG_IDCODE_31_24               0x03
 #define REG_GPPUPDCTR1                 0x0F
+#define REG_UNLOCK_TEST_REG            0x12
 
 /*I2C1 and I2C4(SR) SDA/SCL pull-up control bits */
 
@@ -288,6 +304,8 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
 #define SR_I2C_SCL_CTRL_PU             BIT(4)
 #define SR_I2C_SDA_CTRL_PU             BIT(6)
 
+#define TWL_EEPROM_R_UNLOCK            0x49
+
 /*----------------------------------------------------------------------*/
 
 /*
@@ -501,7 +519,7 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
 #define RES_32KCLKOUT           26
 #define RES_RESET               27
 /* Power Reference */
-#define RES_Main_Ref            28
+#define RES_MAIN_REF            28
 
 #define TOTAL_RESOURCES                28
 /*
@@ -593,6 +611,7 @@ enum twl4030_usb_mode {
 
 struct twl4030_usb_data {
        enum twl4030_usb_mode   usb_mode;
+       unsigned long           features;
 
        int             (*phy_init)(struct device *dev);
        int             (*phy_exit)(struct device *dev);
@@ -699,6 +718,20 @@ struct twl4030_platform_data {
        struct regulator_init_data              *vcxio;
        struct regulator_init_data              *vusb;
        struct regulator_init_data              *clk32kg;
+       /* TWL6025 LDO regulators */
+       struct regulator_init_data              *ldo1;
+       struct regulator_init_data              *ldo2;
+       struct regulator_init_data              *ldo3;
+       struct regulator_init_data              *ldo4;
+       struct regulator_init_data              *ldo5;
+       struct regulator_init_data              *ldo6;
+       struct regulator_init_data              *ldo7;
+       struct regulator_init_data              *ldoln;
+       struct regulator_init_data              *ldousb;
+       /* TWL6025 DCDC regulators */
+       struct regulator_init_data              *smps3;
+       struct regulator_init_data              *smps4;
+       struct regulator_init_data              *vio6025;
 };
 
 /*----------------------------------------------------------------------*/
@@ -780,4 +813,21 @@ static inline int twl4030charger_usb_en(int enable) { return 0; }
 #define TWL6030_REG_VRTC       47
 #define TWL6030_REG_CLK32KG    48
 
+/* LDOs on 6025 have different names */
+#define TWL6025_REG_LDO2       49
+#define TWL6025_REG_LDO4       50
+#define TWL6025_REG_LDO3       51
+#define TWL6025_REG_LDO5       52
+#define TWL6025_REG_LDO1       53
+#define TWL6025_REG_LDO7       54
+#define TWL6025_REG_LDO6       55
+#define TWL6025_REG_LDOLN      56
+#define TWL6025_REG_LDOUSB     57
+
+/* 6025 DCDC supplies */
+#define TWL6025_REG_SMPS3      58
+#define TWL6025_REG_SMPS4      59
+#define TWL6025_REG_VIO                60
+
+
 #endif /* End of __TWL4030_H */
index b2eee5879883b3fbaf4d00ce28330320c03a9213..bf56b6f78270e6a60a63e4870295006a07ca23d8 100644 (file)
@@ -1003,8 +1003,12 @@ struct ieee80211_ht_info {
 #define WLAN_CAPABILITY_ESS            (1<<0)
 #define WLAN_CAPABILITY_IBSS           (1<<1)
 
-/* A mesh STA sets the ESS and IBSS capability bits to zero */
-#define WLAN_CAPABILITY_IS_MBSS(cap)   \
+/*
+ * A mesh STA sets the ESS and IBSS capability bits to zero.
+ * however, this holds true for p2p probe responses (in the p2p_find
+ * phase) as well.
+ */
+#define WLAN_CAPABILITY_IS_STA_BSS(cap)        \
        (!((cap) & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)))
 
 #define WLAN_CAPABILITY_CF_POLLABLE    (1<<2)
index 0f1325d98295d5b8b88761fe46f34654ffee8011..0065ffd3226ba9dc17d272d80bee076b8c0f612f 100644 (file)
@@ -132,10 +132,6 @@ static inline struct ethhdr *eth_hdr(const struct sk_buff *skb)
 
 int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr);
 
-#ifdef CONFIG_SYSCTL
-extern struct ctl_table ether_table[];
-#endif
-
 int mac_pton(const char *s, u8 *mac);
 extern ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len);
 
index f4a2e6b1b864c5d8d83caffd2343c2cf12fe3b84..0ee969a5593d0fe0defc15089dc8c8515933836e 100644 (file)
@@ -136,6 +136,7 @@ enum {
        IFLA_PORT_SELF,
        IFLA_AF_SPEC,
        IFLA_GROUP,             /* Group the device belongs to */
+       IFLA_NET_NS_FD,
        __IFLA_MAX
 };
 
index 72bfa5a034dd430a1a79aa2ef1cb24a1b79836df..7b318630139f3e50f55e82eefcbaae09490d6faf 100644 (file)
@@ -62,6 +62,7 @@ struct tpacket_auxdata {
        __u16           tp_mac;
        __u16           tp_net;
        __u16           tp_vlan_tci;
+       __u16           tp_padding;
 };
 
 /* Rx ring - header status */
@@ -70,6 +71,7 @@ struct tpacket_auxdata {
 #define TP_STATUS_COPY         0x2
 #define TP_STATUS_LOSING       0x4
 #define TP_STATUS_CSUMNOTREADY 0x8
+#define TP_STATUS_VLAN_VALID   0x10 /* auxdata has valid tp_vlan_tci */
 
 /* Tx ring - header status */
 #define TP_STATUS_AVAILABLE    0x0
@@ -100,6 +102,7 @@ struct tpacket2_hdr {
        __u32           tp_sec;
        __u32           tp_nsec;
        __u16           tp_vlan_tci;
+       __u16           tp_padding;
 };
 
 #define TPACKET2_HDRLEN                (TPACKET_ALIGN(sizeof(struct tpacket2_hdr)) + sizeof(struct sockaddr_ll))
index 290bd8ac94cfe461f71eaf12bc4bdafc4fc993ce..affa27380b72e6096a060bf59c8f5261dfb03b1c 100644 (file)
@@ -110,6 +110,11 @@ static inline void vlan_group_set_device(struct vlan_group *vg,
        array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev;
 }
 
+static inline int is_vlan_dev(struct net_device *dev)
+{
+        return dev->priv_flags & IFF_802_1Q_VLAN;
+}
+
 #define vlan_tx_tag_present(__skb)     ((__skb)->vlan_tci & VLAN_TAG_PRESENT)
 #define vlan_tx_tag_get(__skb)         ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT)
 
@@ -220,7 +225,7 @@ static inline int vlan_hwaccel_receive_skb(struct sk_buff *skb,
 }
 
 /**
- * __vlan_put_tag - regular VLAN tag inserting
+ * vlan_insert_tag - regular VLAN tag inserting
  * @skb: skbuff to tag
  * @vlan_tci: VLAN TCI to insert
  *
@@ -229,8 +234,10 @@ static inline int vlan_hwaccel_receive_skb(struct sk_buff *skb,
  *
  * Following the skb_unshare() example, in case of error, the calling function
  * doesn't have to worry about freeing the original skb.
+ *
+ * Does not change skb->protocol so this function can be used during receive.
  */
-static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci)
+static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb, u16 vlan_tci)
 {
        struct vlan_ethhdr *veth;
 
@@ -250,8 +257,25 @@ static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci)
        /* now, the TCI */
        veth->h_vlan_TCI = htons(vlan_tci);
 
-       skb->protocol = htons(ETH_P_8021Q);
+       return skb;
+}
 
+/**
+ * __vlan_put_tag - regular VLAN tag inserting
+ * @skb: skbuff to tag
+ * @vlan_tci: VLAN TCI to insert
+ *
+ * Inserts the VLAN tag into @skb as part of the payload
+ * Returns a VLAN tagged skb. If a new skb is created, @skb is freed.
+ *
+ * Following the skb_unshare() example, in case of error, the calling function
+ * doesn't have to worry about freeing the original skb.
+ */
+static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci)
+{
+       skb = vlan_insert_tag(skb, vlan_tci);
+       if (skb)
+               skb->protocol = htons(ETH_P_8021Q);
        return skb;
 }
 
index 689496bb6654b60ba37bbc000d982356140f9565..580f70c02391712f7cc0351d645361b683b82a8b 100644 (file)
 extern struct files_struct init_files;
 extern struct fs_struct init_fs;
 
+#ifdef CONFIG_CGROUPS
+#define INIT_THREADGROUP_FORK_LOCK(sig)                                        \
+       .threadgroup_fork_lock =                                        \
+               __RWSEM_INITIALIZER(sig.threadgroup_fork_lock),
+#else
+#define INIT_THREADGROUP_FORK_LOCK(sig)
+#endif
+
 #define INIT_SIGNALS(sig) {                                            \
        .nr_threads     = 1,                                            \
        .wait_chldexit  = __WAIT_QUEUE_HEAD_INITIALIZER(sig.wait_chldexit),\
@@ -38,6 +46,7 @@ extern struct fs_struct init_fs;
        },                                                              \
        .cred_guard_mutex =                                             \
                 __MUTEX_INITIALIZER(sig.cred_guard_mutex),             \
+       INIT_THREADGROUP_FORK_LOCK(sig)                                 \
 }
 
 extern struct nsproxy init_nsproxy;
@@ -83,13 +92,6 @@ extern struct group_info init_groups;
 #define INIT_IDS
 #endif
 
-/*
- * Because of the reduced scope of CAP_SETPCAP when filesystem
- * capabilities are in effect, it is safe to allow CAP_SETPCAP to
- * be available in the default configuration.
- */
-# define CAP_INIT_BSET  CAP_FULL_SET
-
 #ifdef CONFIG_RCU_BOOST
 #define INIT_TASK_RCU_BOOST()                                          \
        .rcu_boost_mutex = NULL,
index 0cbe5e81482eea96046d7e8f219a7e09297d1bf2..d388d857bf14063d15c662bd898d824112f30f02 100644 (file)
@@ -6,7 +6,7 @@
  * The platform_data for the device's "struct device" holds this
  * information.
  *
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2011 Analog Devices Inc.
  *
  * Licensed under the GPL-2 or later.
  */
@@ -58,6 +58,7 @@ struct ad714x_platform_data {
        struct ad714x_button_plat *button;
        unsigned short stage_cfg_reg[STAGE_NUM][STAGE_CFGREG_NUM];
        unsigned short sys_cfg_reg[SYS_CFGREG_NUM];
+       unsigned long irqflags;
 };
 
 #endif
diff --git a/include/linux/input/adp5589.h b/include/linux/input/adp5589.h
new file mode 100644 (file)
index 0000000..ef792ec
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Analog Devices ADP5589 I/O Expander and QWERTY Keypad Controller
+ *
+ * Copyright 2010-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef _ADP5589_H
+#define _ADP5589_H
+
+#define ADP5589_ID                     0x00
+#define ADP5589_INT_STATUS             0x01
+#define ADP5589_STATUS                 0x02
+#define ADP5589_FIFO_1                 0x03
+#define ADP5589_FIFO_2                 0x04
+#define ADP5589_FIFO_3                 0x05
+#define ADP5589_FIFO_4                 0x06
+#define ADP5589_FIFO_5                 0x07
+#define ADP5589_FIFO_6                 0x08
+#define ADP5589_FIFO_7                 0x09
+#define ADP5589_FIFO_8                 0x0A
+#define ADP5589_FIFO_9                 0x0B
+#define ADP5589_FIFO_10                        0x0C
+#define ADP5589_FIFO_11                        0x0D
+#define ADP5589_FIFO_12                        0x0E
+#define ADP5589_FIFO_13                        0x0F
+#define ADP5589_FIFO_14                        0x10
+#define ADP5589_FIFO_15                        0x11
+#define ADP5589_FIFO_16                        0x12
+#define ADP5589_GPI_INT_STAT_A         0x13
+#define ADP5589_GPI_INT_STAT_B         0x14
+#define ADP5589_GPI_INT_STAT_C         0x15
+#define ADP5589_GPI_STATUS_A           0x16
+#define ADP5589_GPI_STATUS_B           0x17
+#define ADP5589_GPI_STATUS_C           0x18
+#define ADP5589_RPULL_CONFIG_A         0x19
+#define ADP5589_RPULL_CONFIG_B         0x1A
+#define ADP5589_RPULL_CONFIG_C         0x1B
+#define ADP5589_RPULL_CONFIG_D         0x1C
+#define ADP5589_RPULL_CONFIG_E         0x1D
+#define ADP5589_GPI_INT_LEVEL_A                0x1E
+#define ADP5589_GPI_INT_LEVEL_B                0x1F
+#define ADP5589_GPI_INT_LEVEL_C                0x20
+#define ADP5589_GPI_EVENT_EN_A         0x21
+#define ADP5589_GPI_EVENT_EN_B         0x22
+#define ADP5589_GPI_EVENT_EN_C         0x23
+#define ADP5589_GPI_INTERRUPT_EN_A     0x24
+#define ADP5589_GPI_INTERRUPT_EN_B     0x25
+#define ADP5589_GPI_INTERRUPT_EN_C     0x26
+#define ADP5589_DEBOUNCE_DIS_A         0x27
+#define ADP5589_DEBOUNCE_DIS_B         0x28
+#define ADP5589_DEBOUNCE_DIS_C         0x29
+#define ADP5589_GPO_DATA_OUT_A         0x2A
+#define ADP5589_GPO_DATA_OUT_B         0x2B
+#define ADP5589_GPO_DATA_OUT_C         0x2C
+#define ADP5589_GPO_OUT_MODE_A         0x2D
+#define ADP5589_GPO_OUT_MODE_B         0x2E
+#define ADP5589_GPO_OUT_MODE_C         0x2F
+#define ADP5589_GPIO_DIRECTION_A       0x30
+#define ADP5589_GPIO_DIRECTION_B       0x31
+#define ADP5589_GPIO_DIRECTION_C       0x32
+#define ADP5589_UNLOCK1                        0x33
+#define ADP5589_UNLOCK2                        0x34
+#define ADP5589_EXT_LOCK_EVENT         0x35
+#define ADP5589_UNLOCK_TIMERS          0x36
+#define ADP5589_LOCK_CFG               0x37
+#define ADP5589_RESET1_EVENT_A         0x38
+#define ADP5589_RESET1_EVENT_B         0x39
+#define ADP5589_RESET1_EVENT_C         0x3A
+#define ADP5589_RESET2_EVENT_A         0x3B
+#define ADP5589_RESET2_EVENT_B         0x3C
+#define ADP5589_RESET_CFG              0x3D
+#define ADP5589_PWM_OFFT_LOW           0x3E
+#define ADP5589_PWM_OFFT_HIGH          0x3F
+#define ADP5589_PWM_ONT_LOW            0x40
+#define ADP5589_PWM_ONT_HIGH           0x41
+#define ADP5589_PWM_CFG                        0x42
+#define ADP5589_CLOCK_DIV_CFG          0x43
+#define ADP5589_LOGIC_1_CFG            0x44
+#define ADP5589_LOGIC_2_CFG            0x45
+#define ADP5589_LOGIC_FF_CFG           0x46
+#define ADP5589_LOGIC_INT_EVENT_EN     0x47
+#define ADP5589_POLL_PTIME_CFG         0x48
+#define ADP5589_PIN_CONFIG_A           0x49
+#define ADP5589_PIN_CONFIG_B           0x4A
+#define ADP5589_PIN_CONFIG_C           0x4B
+#define ADP5589_PIN_CONFIG_D           0x4C
+#define ADP5589_GENERAL_CFG            0x4D
+#define ADP5589_INT_EN                 0x4E
+
+#define ADP5589_DEVICE_ID_MASK 0xF
+
+/* Put one of these structures in i2c_board_info platform_data */
+
+#define ADP5589_KEYMAPSIZE     88
+
+#define ADP5589_GPI_PIN_ROW0 97
+#define ADP5589_GPI_PIN_ROW1 98
+#define ADP5589_GPI_PIN_ROW2 99
+#define ADP5589_GPI_PIN_ROW3 100
+#define ADP5589_GPI_PIN_ROW4 101
+#define ADP5589_GPI_PIN_ROW5 102
+#define ADP5589_GPI_PIN_ROW6 103
+#define ADP5589_GPI_PIN_ROW7 104
+#define ADP5589_GPI_PIN_COL0 105
+#define ADP5589_GPI_PIN_COL1 106
+#define ADP5589_GPI_PIN_COL2 107
+#define ADP5589_GPI_PIN_COL3 108
+#define ADP5589_GPI_PIN_COL4 109
+#define ADP5589_GPI_PIN_COL5 110
+#define ADP5589_GPI_PIN_COL6 111
+#define ADP5589_GPI_PIN_COL7 112
+#define ADP5589_GPI_PIN_COL8 113
+#define ADP5589_GPI_PIN_COL9 114
+#define ADP5589_GPI_PIN_COL10 115
+#define GPI_LOGIC1 116
+#define GPI_LOGIC2 117
+
+#define ADP5589_GPI_PIN_ROW_BASE ADP5589_GPI_PIN_ROW0
+#define ADP5589_GPI_PIN_ROW_END ADP5589_GPI_PIN_ROW7
+#define ADP5589_GPI_PIN_COL_BASE ADP5589_GPI_PIN_COL0
+#define ADP5589_GPI_PIN_COL_END ADP5589_GPI_PIN_COL10
+
+#define ADP5589_GPI_PIN_BASE ADP5589_GPI_PIN_ROW_BASE
+#define ADP5589_GPI_PIN_END ADP5589_GPI_PIN_COL_END
+
+#define ADP5589_GPIMAPSIZE_MAX (ADP5589_GPI_PIN_END - ADP5589_GPI_PIN_BASE + 1)
+
+struct adp5589_gpi_map {
+       unsigned short pin;
+       unsigned short sw_evt;
+};
+
+/* scan_cycle_time */
+#define ADP5589_SCAN_CYCLE_10ms                0
+#define ADP5589_SCAN_CYCLE_20ms                1
+#define ADP5589_SCAN_CYCLE_30ms                2
+#define ADP5589_SCAN_CYCLE_40ms                3
+
+/* RESET_CFG */
+#define RESET_PULSE_WIDTH_500us                0
+#define RESET_PULSE_WIDTH_1ms          1
+#define RESET_PULSE_WIDTH_2ms          2
+#define RESET_PULSE_WIDTH_10ms         3
+
+#define RESET_TRIG_TIME_0ms            (0 << 2)
+#define RESET_TRIG_TIME_1000ms         (1 << 2)
+#define RESET_TRIG_TIME_1500ms         (2 << 2)
+#define RESET_TRIG_TIME_2000ms         (3 << 2)
+#define RESET_TRIG_TIME_2500ms         (4 << 2)
+#define RESET_TRIG_TIME_3000ms         (5 << 2)
+#define RESET_TRIG_TIME_3500ms         (6 << 2)
+#define RESET_TRIG_TIME_4000ms         (7 << 2)
+
+#define RESET_PASSTHRU_EN              (1 << 5)
+#define RESET1_POL_HIGH                        (1 << 6)
+#define RESET1_POL_LOW                 (0 << 6)
+#define RESET2_POL_HIGH                        (1 << 7)
+#define RESET2_POL_LOW                 (0 << 7)
+
+/* Mask Bits:
+ * C C C C C C C C C C C | R R R R R R R R
+ * 1 9 8 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0
+ * 0
+ * ---------------- BIT ------------------
+ * 1 1 1 1 1 1 1 1 1 0 0 | 0 0 0 0 0 0 0 0
+ * 8 7 6 5 4 3 2 1 0 9 8 | 7 6 5 4 3 2 1 0
+ */
+
+#define ADP_ROW(x)                     (1 << (x))
+#define ADP_COL(x)                     (1 << (x + 8))
+
+struct adp5589_kpad_platform_data {
+       unsigned keypad_en_mask;        /* Keypad (Rows/Columns) enable mask */
+       const unsigned short *keymap;   /* Pointer to keymap */
+       unsigned short keymapsize;      /* Keymap size */
+       bool repeat;                    /* Enable key repeat */
+       bool en_keylock;                /* Enable key lock feature */
+       unsigned char unlock_key1;      /* Unlock Key 1 */
+       unsigned char unlock_key2;      /* Unlock Key 2 */
+       unsigned char unlock_timer;     /* Time in seconds [0..7] between the two unlock keys 0=disable */
+       unsigned char scan_cycle_time;  /* Time between consecutive scan cycles */
+       unsigned char reset_cfg;        /* Reset config */
+       unsigned short reset1_key_1;    /* Reset Key 1 */
+       unsigned short reset1_key_2;    /* Reset Key 2 */
+       unsigned short reset1_key_3;    /* Reset Key 3 */
+       unsigned short reset2_key_1;    /* Reset Key 1 */
+       unsigned short reset2_key_2;    /* Reset Key 2 */
+       unsigned debounce_dis_mask;     /* Disable debounce mask */
+       unsigned pull_dis_mask;         /* Disable all pull resistors mask */
+       unsigned pullup_en_100k;        /* Pull-Up 100k Enable Mask */
+       unsigned pullup_en_300k;        /* Pull-Up 300k Enable Mask */
+       unsigned pulldown_en_300k;      /* Pull-Down 300k Enable Mask */
+       const struct adp5589_gpi_map *gpimap;
+       unsigned short gpimapsize;
+       const struct adp5589_gpio_platform_data *gpio_data;
+};
+
+struct i2c_client; /* forward declaration */
+
+struct adp5589_gpio_platform_data {
+       int     gpio_start;     /* GPIO Chip base # */
+       int     (*setup)(struct i2c_client *client,
+                               int gpio, unsigned ngpio,
+                               void *context);
+       int     (*teardown)(struct i2c_client *client,
+                               int gpio, unsigned ngpio,
+                               void *context);
+       void    *context;
+};
+
+#endif
diff --git a/include/linux/input/pmic8xxx-keypad.h b/include/linux/input/pmic8xxx-keypad.h
new file mode 100644 (file)
index 0000000..5f1e2f9
--- /dev/null
@@ -0,0 +1,52 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#ifndef __PMIC8XXX_KEYPAD_H__
+#define __PMIC8XXX_KEYPAD_H__
+
+#include <linux/input/matrix_keypad.h>
+
+#define PM8XXX_KEYPAD_DEV_NAME     "pm8xxx-keypad"
+
+/**
+ * struct pm8xxx_keypad_platform_data - platform data for keypad
+ * @keymap_data - matrix keymap data
+ * @input_name - input device name
+ * @input_phys_device - input device name
+ * @num_cols - number of columns of keypad
+ * @num_rows - number of row of keypad
+ * @debounce_ms - debounce period in milliseconds
+ * @scan_delay_ms - scan delay in milliseconds
+ * @row_hold_ns - row hold period in nanoseconds
+ * @wakeup - configure keypad as wakeup
+ * @rep - enable or disable key repeat bit
+ */
+struct pm8xxx_keypad_platform_data {
+       const struct matrix_keymap_data *keymap_data;
+
+       const char *input_name;
+       const char *input_phys_device;
+
+       unsigned int num_cols;
+       unsigned int num_rows;
+       unsigned int rows_gpio_start;
+       unsigned int cols_gpio_start;
+
+       unsigned int debounce_ms;
+       unsigned int scan_delay_ms;
+       unsigned int row_hold_ns;
+
+       bool wakeup;
+       bool rep;
+};
+
+#endif /*__PMIC8XXX_KEYPAD_H__ */
diff --git a/include/linux/input/pmic8xxx-pwrkey.h b/include/linux/input/pmic8xxx-pwrkey.h
new file mode 100644 (file)
index 0000000..6d2974e
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#ifndef __PMIC8XXX_PWRKEY_H__
+#define __PMIC8XXX_PWRKEY_H__
+
+#define PM8XXX_PWRKEY_DEV_NAME "pm8xxx-pwrkey"
+
+/**
+ * struct pm8xxx_pwrkey_platform_data - platform data for pwrkey driver
+ * @pull up:  power on register control for pull up/down configuration
+ * @kpd_trigger_delay_us: time delay for power key state change interrupt
+ *                  trigger.
+ * @wakeup: configure power key as wakeup source
+ */
+struct pm8xxx_pwrkey_platform_data  {
+       bool pull_up;
+       u32  kpd_trigger_delay_us;
+       u32  wakeup;
+};
+
+#endif /* __PMIC8XXX_PWRKEY_H__ */
index 649dc7f12925d0ac7a9152e7e9f7e79b269b3ec6..5d253cd93691d2bec2a12b34fe2791f61e57a09f 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __SH_KEYSC_H__
 #define __SH_KEYSC_H__
 
-#define SH_KEYSC_MAXKEYS 49
+#define SH_KEYSC_MAXKEYS 64
 
 struct sh_keysc_info {
        enum { SH_KEYSC_MODE_1, SH_KEYSC_MODE_2, SH_KEYSC_MODE_3,
index 6c12989839d9093f970b9f90d8dffe44dec6f7a2..f6efed0039edfdb06cbe1430588e51bf2db07aca 100644 (file)
@@ -414,6 +414,7 @@ enum
        TASKLET_SOFTIRQ,
        SCHED_SOFTIRQ,
        HRTIMER_SOFTIRQ,
+       RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */
 
        NR_SOFTIRQS
 };
index 906590aa69072959bbf9e758d28f00bae609089d..204f9cd26c16012126206106f5d36be3c0af21cf 100644 (file)
@@ -236,7 +236,7 @@ static inline void ipmi_free_smi_msg(struct ipmi_smi_msg *msg)
    directory for this interface.  Note that the entry will
    automatically be dstroyed when the interface is destroyed. */
 int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
-                           read_proc_t *read_proc,
+                           const struct file_operations *proc_ops,
                            void *data);
 
 #endif /* __LINUX_IPMI_SMI_H */
index 819acaaac3f5877bc4802bbbc928a5c21686fde2..714ba08dc09265922fe8ab81dee1caadc12a9100 100644 (file)
@@ -8,9 +8,9 @@
  * @IRQ_WAKE_THREAD    handler requests to wake the handler thread
  */
 enum irqreturn {
-       IRQ_NONE,
-       IRQ_HANDLED,
-       IRQ_WAKE_THREAD,
+       IRQ_NONE                = (0 << 0),
+       IRQ_HANDLED             = (1 << 0),
+       IRQ_WAKE_THREAD         = (1 << 1),
 };
 
 typedef enum irqreturn irqreturn_t;
index a32dcaec04e147917a3e085a5e83146189782336..d087c2e7b2aa0303a22b181cdc617a67e99cff80 100644 (file)
@@ -529,9 +529,10 @@ struct transaction_s
        enum {
                T_RUNNING,
                T_LOCKED,
-               T_RUNDOWN,
                T_FLUSH,
                T_COMMIT,
+               T_COMMIT_DFLUSH,
+               T_COMMIT_JFLUSH,
                T_FINISHED
        }                       t_state;
 
@@ -658,7 +659,9 @@ struct transaction_s
         * waiting for it to finish.
         */
        unsigned int t_synchronous_commit:1;
-       unsigned int t_flushed_data_blocks:1;
+
+       /* Disk flush needs to be sent to fs partition [no locking] */
+       int                     t_need_data_flush;
 
        /*
         * For use by the filesystem to store fs-specific data
@@ -1021,7 +1024,6 @@ struct journal_s
 
 /* Filing buffers */
 extern void jbd2_journal_unfile_buffer(journal_t *, struct journal_head *);
-extern void __jbd2_journal_unfile_buffer(struct journal_head *);
 extern void __jbd2_journal_refile_buffer(struct journal_head *);
 extern void jbd2_journal_refile_buffer(journal_t *, struct journal_head *);
 extern void __jbd2_journal_file_buffer(struct journal_head *, transaction_t *, int);
@@ -1162,7 +1164,6 @@ extern void          jbd2_journal_release_jbd_inode(journal_t *journal, struct jbd2_in
  */
 struct journal_head *jbd2_journal_add_journal_head(struct buffer_head *bh);
 struct journal_head *jbd2_journal_grab_journal_head(struct buffer_head *bh);
-void jbd2_journal_remove_journal_head(struct buffer_head *bh);
 void jbd2_journal_put_journal_head(struct journal_head *jh);
 
 /*
@@ -1228,6 +1229,7 @@ int jbd2_journal_start_commit(journal_t *journal, tid_t *tid);
 int jbd2_journal_force_commit_nested(journal_t *journal);
 int jbd2_log_wait_commit(journal_t *journal, tid_t tid);
 int jbd2_log_do_checkpoint(journal_t *journal);
+int jbd2_trans_will_send_data_barrier(journal_t *journal, tid_t tid);
 
 void __jbd2_log_wait_for_space(journal_t *journal);
 extern void __jbd2_journal_drop_transaction(journal_t *, transaction_t *);
index f37ba716ef8b7fe81f73a586289286a879404609..953352a88336c0385e2e385f93e41c278513be7b 100644 (file)
@@ -248,6 +248,37 @@ int __must_check kstrtos16(const char *s, unsigned int base, s16 *res);
 int __must_check kstrtou8(const char *s, unsigned int base, u8 *res);
 int __must_check kstrtos8(const char *s, unsigned int base, s8 *res);
 
+int __must_check kstrtoull_from_user(const char __user *s, size_t count, unsigned int base, unsigned long long *res);
+int __must_check kstrtoll_from_user(const char __user *s, size_t count, unsigned int base, long long *res);
+int __must_check kstrtoul_from_user(const char __user *s, size_t count, unsigned int base, unsigned long *res);
+int __must_check kstrtol_from_user(const char __user *s, size_t count, unsigned int base, long *res);
+int __must_check kstrtouint_from_user(const char __user *s, size_t count, unsigned int base, unsigned int *res);
+int __must_check kstrtoint_from_user(const char __user *s, size_t count, unsigned int base, int *res);
+int __must_check kstrtou16_from_user(const char __user *s, size_t count, unsigned int base, u16 *res);
+int __must_check kstrtos16_from_user(const char __user *s, size_t count, unsigned int base, s16 *res);
+int __must_check kstrtou8_from_user(const char __user *s, size_t count, unsigned int base, u8 *res);
+int __must_check kstrtos8_from_user(const char __user *s, size_t count, unsigned int base, s8 *res);
+
+static inline int __must_check kstrtou64_from_user(const char __user *s, size_t count, unsigned int base, u64 *res)
+{
+       return kstrtoull_from_user(s, count, base, res);
+}
+
+static inline int __must_check kstrtos64_from_user(const char __user *s, size_t count, unsigned int base, s64 *res)
+{
+       return kstrtoll_from_user(s, count, base, res);
+}
+
+static inline int __must_check kstrtou32_from_user(const char __user *s, size_t count, unsigned int base, u32 *res)
+{
+       return kstrtouint_from_user(s, count, base, res);
+}
+
+static inline int __must_check kstrtos32_from_user(const char __user *s, size_t count, unsigned int base, s32 *res)
+{
+       return kstrtoint_from_user(s, count, base, res);
+}
+
 extern unsigned long simple_strtoul(const char *,char **,unsigned int);
 extern long simple_strtol(const char *,char **,unsigned int);
 extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
@@ -638,6 +669,13 @@ struct sysinfo {
        char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
 };
 
+#ifdef __CHECKER__
+#define BUILD_BUG_ON_NOT_POWER_OF_2(n)
+#define BUILD_BUG_ON_ZERO(e) (0)
+#define BUILD_BUG_ON_NULL(e) ((void*)0)
+#define BUILD_BUG_ON(condition)
+#else /* __CHECKER__ */
+
 /* Force a compilation error if a constant expression is not a power of 2 */
 #define BUILD_BUG_ON_NOT_POWER_OF_2(n)                 \
        BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))
@@ -674,6 +712,7 @@ extern int __build_bug_on_failed;
                if (condition) __build_bug_on_failed = 1;       \
        } while(0)
 #endif
+#endif /* __CHECKER__ */
 
 /* Trap pasters of __FUNCTION__ at compile-time */
 #define __FUNCTION__ (__func__)
index b2bb01719561f0d3de11945a9dba0a78744b8acc..6ea4eebd3467b220f19bc5cd6e77214096ca2278 100644 (file)
@@ -9,7 +9,7 @@
  * 2 of the License, or (at your option) any later version.
  *
  *
- * See Documentation/keys.txt for information on keys/keyrings.
+ * See Documentation/security/keys.txt for information on keys/keyrings.
  */
 
 #ifndef _LINUX_KEY_H
@@ -276,6 +276,19 @@ static inline key_serial_t key_serial(struct key *key)
        return key ? key->serial : 0;
 }
 
+/**
+ * key_is_instantiated - Determine if a key has been positively instantiated
+ * @key: The key to check.
+ *
+ * Return true if the specified key has been positively instantiated, false
+ * otherwise.
+ */
+static inline bool key_is_instantiated(const struct key *key)
+{
+       return test_bit(KEY_FLAG_INSTANTIATED, &key->flags) &&
+               !test_bit(KEY_FLAG_NEGATIVE, &key->flags);
+}
+
 #define rcu_dereference_key(KEY)                                       \
        (rcu_dereference_protected((KEY)->payload.rcudata,              \
                                   rwsem_is_locked(&((struct key *)(KEY))->sem)))
index 310231823852026b69bf25cc88868ab86de69975..0da38cf7db7bddc8841d14620a9e831866afcfd2 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/errno.h>
 #include <linux/compiler.h>
 #include <linux/workqueue.h>
+#include <linux/sysctl.h>
 
 #define KMOD_PATH_LEN 256
 
@@ -44,7 +45,7 @@ static inline int request_module_nowait(const char *name, ...) { return -ENOSYS;
 #endif
 
 
-struct key;
+struct cred;
 struct file;
 
 enum umh_wait {
@@ -61,7 +62,7 @@ struct subprocess_info {
        char **envp;
        enum umh_wait wait;
        int retval;
-       int (*init)(struct subprocess_info *info);
+       int (*init)(struct subprocess_info *info, struct cred *new);
        void (*cleanup)(struct subprocess_info *info);
        void *data;
 };
@@ -72,7 +73,7 @@ struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
 
 /* Set various pieces of state into the subprocess_info structure */
 void call_usermodehelper_setfns(struct subprocess_info *info,
-                   int (*init)(struct subprocess_info *info),
+                   int (*init)(struct subprocess_info *info, struct cred *new),
                    void (*cleanup)(struct subprocess_info *info),
                    void *data);
 
@@ -86,7 +87,7 @@ void call_usermodehelper_freeinfo(struct subprocess_info *info);
 static inline int
 call_usermodehelper_fns(char *path, char **argv, char **envp,
                        enum umh_wait wait,
-                       int (*init)(struct subprocess_info *info),
+                       int (*init)(struct subprocess_info *info, struct cred *new),
                        void (*cleanup)(struct subprocess_info *), void *data)
 {
        struct subprocess_info *info;
@@ -109,6 +110,8 @@ call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait)
                                       NULL, NULL, NULL);
 }
 
+extern struct ctl_table usermodehelper_table[];
+
 extern void usermodehelper_init(void);
 
 extern int usermodehelper_disable(void);
index 2a0d7d651dc34f98daff0d111c5e458339006945..ee0c952188de2c99281fd7567f701893e90a47dd 100644 (file)
@@ -12,6 +12,7 @@
 #ifndef _LINUX_KMSG_DUMP_H
 #define _LINUX_KMSG_DUMP_H
 
+#include <linux/errno.h>
 #include <linux/list.h>
 
 enum kmsg_dump_reason {
index 82cb5bf461fb4ace0c8fa5dc8e68c44a0e5fca19..f66b065a8b5ff1af1efdc698aadc248a79175917 100644 (file)
@@ -32,15 +32,17 @@ enum kobj_ns_type {
 
 /*
  * Callbacks so sysfs can determine namespaces
- *   @current_ns: return calling task's namespace
+ *   @grab_current_ns: return a new reference to calling task's namespace
  *   @netlink_ns: return namespace to which a sock belongs (right?)
  *   @initial_ns: return the initial namespace (i.e. init_net_ns)
+ *   @drop_ns: drops a reference to namespace
  */
 struct kobj_ns_type_operations {
        enum kobj_ns_type type;
-       const void *(*current_ns)(void);
+       void *(*grab_current_ns)(void);
        const void *(*netlink_ns)(struct sock *sk);
        const void *(*initial_ns)(void);
+       void (*drop_ns)(void *);
 };
 
 int kobj_ns_type_register(const struct kobj_ns_type_operations *ops);
@@ -48,9 +50,9 @@ int kobj_ns_type_registered(enum kobj_ns_type type);
 const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent);
 const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj);
 
-const void *kobj_ns_current(enum kobj_ns_type type);
+void *kobj_ns_grab_current(enum kobj_ns_type type);
 const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk);
 const void *kobj_ns_initial(enum kobj_ns_type type);
-void kobj_ns_exit(enum kobj_ns_type type, const void *ns);
+void kobj_ns_drop(enum kobj_ns_type type, void *ns);
 
 #endif /* _LINUX_KOBJECT_NS_H */
index f158eb1149aa8b6cd0029ca92ac2645a672a3928..b8d6fffed4d801c938e69bf7aa99fe3ad98085cb 100644 (file)
@@ -25,7 +25,7 @@ enum pca9532_state {
 };
 
 enum pca9532_type { PCA9532_TYPE_NONE, PCA9532_TYPE_LED,
-       PCA9532_TYPE_N2100_BEEP };
+       PCA9532_TYPE_N2100_BEEP, PCA9532_TYPE_GPIO };
 
 struct pca9532_led {
        u8 id;
@@ -41,6 +41,7 @@ struct pca9532_platform_data {
        struct pca9532_led leds[16];
        u8 pwm[2];
        u8 psc[2];
+       int gpio_base;
 };
 
 #endif /* __LINUX_PCA9532_H */
index 61e0340a4b770c3675787130afdc8174eb902262..5884def15a24872a2b4be5ef9abe815fad233388 100644 (file)
@@ -207,5 +207,7 @@ struct gpio_led_platform_data {
                                        unsigned long *delay_off);
 };
 
+struct platform_device *gpio_led_register_device(
+               int id, const struct gpio_led_platform_data *pdata);
 
 #endif         /* __LINUX_LEDS_H_INCLUDED */
index 7135ebc8428c5273fd62535b985e1fb00e9bfbe0..3f46aedea42fbb5024f8e9896e380d0051c74132 100644 (file)
 #define asmlinkage CPP_ASMLINKAGE
 #endif
 
-#ifndef asmregparm
-# define asmregparm
-#endif
-
 #define __page_aligned_data    __section(.data..page_aligned) __aligned(PAGE_SIZE)
 #define __page_aligned_bss     __section(.bss..page_aligned) __aligned(PAGE_SIZE)
 
index 4aef1dda64065e90bd846cd553b3c26fc93c594e..ef820a3c378bb421a51fb0920f289571f8f96382 100644 (file)
@@ -487,12 +487,15 @@ static inline void print_irqtrace_events(struct task_struct *curr)
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 # ifdef CONFIG_PROVE_LOCKING
 #  define mutex_acquire(l, s, t, i)            lock_acquire(l, s, t, 0, 2, NULL, i)
+#  define mutex_acquire_nest(l, s, t, n, i)    lock_acquire(l, s, t, 0, 2, n, i)
 # else
 #  define mutex_acquire(l, s, t, i)            lock_acquire(l, s, t, 0, 1, NULL, i)
+#  define mutex_acquire_nest(l, s, t, n, i)    lock_acquire(l, s, t, 0, 1, n, i)
 # endif
 # define mutex_release(l, n, i)                        lock_release(l, n, i)
 #else
 # define mutex_acquire(l, s, t, i)             do { } while (0)
+# define mutex_acquire_nest(l, s, t, n, i)     do { } while (0)
 # define mutex_release(l, n, i)                        do { } while (0)
 #endif
 
index 6a4fab7c6e0902e261c3decc4b725cda0589b5d8..7a71ffad037c7ebd07aa79d7e23c08b6b38554bb 100644 (file)
@@ -139,9 +139,9 @@ write intent log information, three of which are mentioned here.
  * .list is on one of three lists:
  *  in_use: currently in use (refcnt > 0, lc_number != LC_FREE)
  *     lru: unused but ready to be reused or recycled
- *          (ts_refcnt == 0, lc_number != LC_FREE),
+ *          (lc_refcnt == 0, lc_number != LC_FREE),
  *    free: unused but ready to be recycled
- *          (ts_refcnt == 0, lc_number == LC_FREE),
+ *          (lc_refcnt == 0, lc_number == LC_FREE),
  *
  * an element is said to be "in the active set",
  * if either on "in_use" or "lru", i.e. lc_number != LC_FREE.
@@ -160,8 +160,8 @@ struct lc_element {
        struct hlist_node colision;
        struct list_head list;           /* LRU list or free list */
        unsigned refcnt;
-       /* back "pointer" into ts_cache->element[index],
-        * for paranoia, and for "ts_element_to_index" */
+       /* back "pointer" into lc_cache->element[index],
+        * for paranoia, and for "lc_element_to_index" */
        unsigned lc_index;
        /* if we want to track a larger set of objects,
         * it needs to become arch independend u64 */
@@ -190,8 +190,8 @@ struct lru_cache {
        /* Arbitrary limit on maximum tracked objects. Practical limit is much
         * lower due to allocation failures, probably. For typical use cases,
         * nr_elements should be a few thousand at most.
-        * This also limits the maximum value of ts_element.ts_index, allowing the
-        * 8 high bits of .ts_index to be overloaded with flags in the future. */
+        * This also limits the maximum value of lc_element.lc_index, allowing the
+        * 8 high bits of .lc_index to be overloaded with flags in the future. */
 #define LC_MAX_ACTIVE  (1<<24)
 
        /* statistics */
index 112a55033352bbaaf79e045f9367edd3f45f5b1e..88e78dedc2e81394f7cbe2e9094782fc2ce32ba5 100644 (file)
@@ -27,7 +27,7 @@
 /* Auxiliary data to use in generating the audit record. */
 struct common_audit_data {
        char type;
-#define LSM_AUDIT_DATA_FS      1
+#define LSM_AUDIT_DATA_PATH    1
 #define LSM_AUDIT_DATA_NET     2
 #define LSM_AUDIT_DATA_CAP     3
 #define LSM_AUDIT_DATA_IPC     4
@@ -35,12 +35,13 @@ struct common_audit_data {
 #define LSM_AUDIT_DATA_KEY     6
 #define LSM_AUDIT_DATA_NONE    7
 #define LSM_AUDIT_DATA_KMOD    8
+#define LSM_AUDIT_DATA_INODE   9
+#define LSM_AUDIT_DATA_DENTRY  10
        struct task_struct *tsk;
        union   {
-               struct {
-                       struct path path;
-                       struct inode *inode;
-               } fs;
+               struct path path;
+               struct dentry *dentry;
+               struct inode *inode;
                struct {
                        int netif;
                        struct sock *sk;
index 62a10c2a11f2dc6a68f5bf4b1e30bbb23149ce6a..7525e38c434d64fa690c454922d99df75d75c983 100644 (file)
@@ -2,6 +2,8 @@
 #define _LINUX_MEMBLOCK_H
 #ifdef __KERNEL__
 
+#define MEMBLOCK_ERROR 0
+
 #ifdef CONFIG_HAVE_MEMBLOCK
 /*
  * Logical memory blocks.
@@ -20,7 +22,6 @@
 #include <asm/memblock.h>
 
 #define INIT_MEMBLOCK_REGIONS  128
-#define MEMBLOCK_ERROR         0
 
 struct memblock_region {
        phys_addr_t base;
@@ -160,6 +161,12 @@ static inline unsigned long memblock_region_reserved_end_pfn(const struct memblo
 #define __initdata_memblock
 #endif
 
+#else
+static inline phys_addr_t memblock_alloc(phys_addr_t size, phys_addr_t align)
+{
+       return MEMBLOCK_ERROR;
+}
+
 #endif /* CONFIG_HAVE_MEMBLOCK */
 
 #endif /* __KERNEL__ */
index 5e9840f509804df5e49224a12bbbd079177ee4f6..50940da6adf36d7a544c32448b6873f83cef2224 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef _LINUX_MEMCONTROL_H
 #define _LINUX_MEMCONTROL_H
 #include <linux/cgroup.h>
+#include <linux/vm_event_item.h>
+
 struct mem_cgroup;
 struct page_cgroup;
 struct page;
@@ -82,6 +84,7 @@ int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *mem);
 
 extern struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page);
 extern struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p);
+extern struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm);
 
 static inline
 int mm_match_cgroup(const struct mm_struct *mm, const struct mem_cgroup *cgroup)
@@ -106,9 +109,10 @@ extern void mem_cgroup_end_migration(struct mem_cgroup *mem,
  */
 int mem_cgroup_inactive_anon_is_low(struct mem_cgroup *memcg);
 int mem_cgroup_inactive_file_is_low(struct mem_cgroup *memcg);
-unsigned long mem_cgroup_zone_nr_pages(struct mem_cgroup *memcg,
-                                      struct zone *zone,
-                                      enum lru_list lru);
+int mem_cgroup_select_victim_node(struct mem_cgroup *memcg);
+unsigned long mem_cgroup_zone_nr_lru_pages(struct mem_cgroup *memcg,
+                                               struct zone *zone,
+                                               enum lru_list lru);
 struct zone_reclaim_stat *mem_cgroup_get_reclaim_stat(struct mem_cgroup *memcg,
                                                      struct zone *zone);
 struct zone_reclaim_stat*
@@ -144,9 +148,11 @@ static inline void mem_cgroup_dec_page_stat(struct page *page,
 }
 
 unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
-                                               gfp_t gfp_mask);
+                                               gfp_t gfp_mask,
+                                               unsigned long *total_scanned);
 u64 mem_cgroup_get_limit(struct mem_cgroup *mem);
 
+void mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx);
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail);
 #endif
@@ -241,6 +247,11 @@ static inline struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page)
        return NULL;
 }
 
+static inline struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)
+{
+       return NULL;
+}
+
 static inline int mm_match_cgroup(struct mm_struct *mm, struct mem_cgroup *mem)
 {
        return 1;
@@ -302,8 +313,8 @@ mem_cgroup_inactive_file_is_low(struct mem_cgroup *memcg)
 }
 
 static inline unsigned long
-mem_cgroup_zone_nr_pages(struct mem_cgroup *memcg, struct zone *zone,
-                        enum lru_list lru)
+mem_cgroup_zone_nr_lru_pages(struct mem_cgroup *memcg, struct zone *zone,
+                            enum lru_list lru)
 {
        return 0;
 }
@@ -338,7 +349,8 @@ static inline void mem_cgroup_dec_page_stat(struct page *page,
 
 static inline
 unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
-                                           gfp_t gfp_mask)
+                                           gfp_t gfp_mask,
+                                           unsigned long *total_scanned)
 {
        return 0;
 }
@@ -354,6 +366,10 @@ static inline void mem_cgroup_split_huge_fixup(struct page *head,
 {
 }
 
+static inline
+void mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx)
+{
+}
 #endif /* CONFIG_CGROUP_MEM_CONT */
 
 #if !defined(CONFIG_CGROUP_MEM_RES_CTLR) || !defined(CONFIG_DEBUG_VM)
index 31ac26ca4acf1afbe2e0afe343a5ca974acb49cc..7978eec1b7d9964420c2e854afba51a8f9cbf8f5 100644 (file)
@@ -199,6 +199,9 @@ void mpol_free_shared_policy(struct shared_policy *p);
 struct mempolicy *mpol_shared_policy_lookup(struct shared_policy *sp,
                                            unsigned long idx);
 
+struct mempolicy *get_vma_policy(struct task_struct *tsk,
+               struct vm_area_struct *vma, unsigned long addr);
+
 extern void numa_default_policy(void);
 extern void numa_policy_init(void);
 extern void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new,
@@ -228,10 +231,10 @@ int do_migrate_pages(struct mm_struct *mm,
 
 #ifdef CONFIG_TMPFS
 extern int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context);
+#endif
 
 extern int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol,
                        int no_context);
-#endif
 
 /* Check if a vma is migratable */
 static inline int vma_migratable(struct vm_area_struct *vma)
@@ -368,13 +371,13 @@ static inline int mpol_parse_str(char *str, struct mempolicy **mpol,
 {
        return 1;       /* error */
 }
+#endif
 
 static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol,
                                int no_context)
 {
        return 0;
 }
-#endif
 
 #endif /* CONFIG_NUMA */
 #endif /* __KERNEL__ */
index 8fba7972ff5f782f57c4db2609e70a847f308f89..63b4fb8e3b6f9aac05faef4534755a55dffc8733 100644 (file)
@@ -330,6 +330,11 @@ struct pm860x_led_pdata {
        unsigned long   flags;
 };
 
+struct pm860x_rtc_pdata {
+       int             (*sync)(unsigned int ticks);
+       int             vrtc;
+};
+
 struct pm860x_touch_pdata {
        int             gpadc_prebias;
        int             slot_cycle;
@@ -349,6 +354,7 @@ struct pm860x_power_pdata {
 struct pm860x_platform_data {
        struct pm860x_backlight_pdata   *backlight;
        struct pm860x_led_pdata         *led;
+       struct pm860x_rtc_pdata         *rtc;
        struct pm860x_touch_pdata       *touch;
        struct pm860x_power_pdata       *power;
        struct regulator_init_data      *regulator;
index 7d9b6ae1c203928ea28b0971d528054ad0a23162..896b5e47f16ec5a9ab0ef962de083e85ddbb0d19 100644 (file)
 #define AB5500_2_0     0x21
 #define AB5500_2_1     0x22
 
+/* AB8500 CIDs*/
+#define AB8500_CUTEARLY        0x00
+#define AB8500_CUT1P0  0x10
+#define AB8500_CUT1P1  0x11
+#define AB8500_CUT2P0  0x20
+#define AB8500_CUT3P0  0x30
+
 /*
  * AB3100, EVENTA1, A2 and A3 event register flags
  * these are catenated into a single 32-bit flag in the code
@@ -186,6 +193,7 @@ struct abx500_init_settings {
 struct ab3550_platform_data {
        struct {unsigned int base; unsigned int count; } irq;
        void *dev_data[AB3550_NUM_DEVICES];
+       size_t dev_data_sz[AB3550_NUM_DEVICES];
        struct abx500_init_settings *init_settings;
        unsigned int init_settings_sz;
 };
index de3c4ad19afb2def54bfceb28d2073d4d978b55f..ed793b77a1c5e2a77301964fc8822f18c4239e1c 100644 (file)
 
 #include <linux/types.h>
 
+struct led_classdev;
+struct asic3_led {
+       const char      *name;
+       const char      *default_trigger;
+       struct led_classdev *cdev;
+};
+
 struct asic3_platform_data {
        u16 *gpio_config;
        unsigned int gpio_config_num;
@@ -23,6 +30,8 @@ struct asic3_platform_data {
        unsigned int irq_base;
 
        unsigned int gpio_base;
+
+       struct asic3_led *leds;
 };
 
 #define ASIC3_NUM_GPIO_BANKS   4
@@ -111,9 +120,9 @@ struct asic3_platform_data {
 #define ASIC3_GPIOA11_PWM0             ASIC3_CONFIG_GPIO(11, 1, 1, 0)
 #define ASIC3_GPIOA12_PWM1             ASIC3_CONFIG_GPIO(12, 1, 1, 0)
 #define ASIC3_GPIOA15_CONTROL_CX       ASIC3_CONFIG_GPIO(15, 1, 1, 0)
-#define ASIC3_GPIOC0_LED0              ASIC3_CONFIG_GPIO(32, 1, 1, 0)
-#define ASIC3_GPIOC1_LED1              ASIC3_CONFIG_GPIO(33, 1, 1, 0)
-#define ASIC3_GPIOC2_LED2              ASIC3_CONFIG_GPIO(34, 1, 1, 0)
+#define ASIC3_GPIOC0_LED0              ASIC3_CONFIG_GPIO(32, 1, 0, 0)
+#define ASIC3_GPIOC1_LED1              ASIC3_CONFIG_GPIO(33, 1, 0, 0)
+#define ASIC3_GPIOC2_LED2              ASIC3_CONFIG_GPIO(34, 1, 0, 0)
 #define ASIC3_GPIOC3_SPI_RXD           ASIC3_CONFIG_GPIO(35, 1, 0, 0)
 #define ASIC3_GPIOC4_CF_nCD            ASIC3_CONFIG_GPIO(36, 1, 0, 0)
 #define ASIC3_GPIOC4_SPI_TXD           ASIC3_CONFIG_GPIO(36, 1, 1, 0)
@@ -152,6 +161,7 @@ struct asic3_platform_data {
 #define PWM_TIMEBASE_VALUE(x)    ((x)&0xf)   /* Low 4 bits sets time base */
 #define PWM_TIMEBASE_ENABLE     (1 << 4)   /* Enable clock */
 
+#define ASIC3_NUM_LEDS                  3
 #define ASIC3_LED_0_Base                0x0700
 #define ASIC3_LED_1_Base                0x0800
 #define ASIC3_LED_2_Base                     0x0900
@@ -287,10 +297,17 @@ struct asic3_platform_data {
  *
  *****************************************************************************/
 #define ASIC3_SD_CONFIG_BASE   0x0400 /* Assumes 32 bit addressing */
+#define ASIC3_SD_CONFIG_SIZE   0x0200 /* Assumes 32 bit addressing */
 #define ASIC3_SD_CTRL_BASE     0x1000
 #define ASIC3_SDIO_CTRL_BASE   0x1200
 
 #define ASIC3_MAP_SIZE_32BIT   0x2000
 #define ASIC3_MAP_SIZE_16BIT   0x1000
 
+/* Functions needed by leds-asic3 */
+
+struct asic3;
+extern void asic3_write_register(struct asic3 *asic, unsigned int reg, u32 val);
+extern u32 asic3_read_register(struct asic3 *asic, unsigned int reg);
+
 #endif /* __ASIC3_H__ */
index aef23309a742334d9f3fb33d3f3b5af38b7f024d..4e76163dd8624dec3dba23b7bdebb32ce8ad2d11 100644 (file)
@@ -33,8 +33,9 @@ struct mfd_cell {
        int                     (*suspend)(struct platform_device *dev);
        int                     (*resume)(struct platform_device *dev);
 
-       /* mfd_data can be used to pass data to client drivers */
-       void                    *mfd_data;
+       /* platform data passed to the sub devices drivers */
+       void                    *platform_data;
+       size_t                  pdata_size;
 
        /*
         * These resources can be specified relative to the parent device.
@@ -89,24 +90,6 @@ static inline const struct mfd_cell *mfd_get_cell(struct platform_device *pdev)
        return pdev->mfd_cell;
 }
 
-/*
- * Given a platform device that's been created by mfd_add_devices(), fetch
- * the .mfd_data entry from the mfd_cell that created it.
- * Otherwise just return the platform_data pointer.
- * This maintains compatibility with platform drivers whose devices aren't
- * created by the mfd layer, and expect platform_data to contain what would've
- * otherwise been in mfd_data.
- */
-static inline void *mfd_get_data(struct platform_device *pdev)
-{
-       const struct mfd_cell *cell = mfd_get_cell(pdev);
-
-       if (cell)
-               return cell->mfd_data;
-       else
-               return pdev->dev.platform_data;
-}
-
 extern int mfd_add_devices(struct device *parent, int id,
                           struct mfd_cell *cells, int n_devs,
                           struct resource *mem_base,
diff --git a/include/linux/mfd/db5500-prcmu.h b/include/linux/mfd/db5500-prcmu.h
new file mode 100644 (file)
index 0000000..f097798
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * U5500 PRCMU API.
+ */
+#ifndef __MACH_PRCMU_U5500_H
+#define __MACH_PRCMU_U5500_H
+
+#ifdef CONFIG_UX500_SOC_DB5500
+
+void db5500_prcmu_early_init(void);
+
+int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
+int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
+
+#else /* !CONFIG_UX500_SOC_DB5500 */
+
+static inline void db5500_prcmu_early_init(void)
+{
+}
+
+static inline int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       return -ENOSYS;
+}
+
+static inline int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       return -ENOSYS;
+}
+
+#endif /* CONFIG_UX500_SOC_DB5500 */
+
+static inline int db5500_prcmu_config_abb_event_readout(u32 abb_events)
+{
+#ifdef CONFIG_MACH_U5500_SIMULATOR
+       return 0;
+#else
+       return -1;
+#endif
+}
+
+#endif /* __MACH_PRCMU_U5500_H */
diff --git a/include/linux/mfd/db8500-prcmu.h b/include/linux/mfd/db8500-prcmu.h
new file mode 100644 (file)
index 0000000..917dbca
--- /dev/null
@@ -0,0 +1,978 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
+ *
+ * PRCMU f/w APIs
+ */
+#ifndef __MFD_DB8500_PRCMU_H
+#define __MFD_DB8500_PRCMU_H
+
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+
+/* This portion previously known as <mach/prcmu-fw-defs_v1.h> */
+
+/**
+ * enum state - ON/OFF state definition
+ * @OFF: State is ON
+ * @ON: State is OFF
+ *
+ */
+enum state {
+       OFF = 0x0,
+       ON  = 0x1,
+};
+
+/**
+ * enum ret_state - general purpose On/Off/Retention states
+ *
+ */
+enum ret_state {
+       OFFST = 0,
+       ONST  = 1,
+       RETST = 2
+};
+
+/**
+ * enum clk_arm - ARM Cortex A9 clock schemes
+ * @A9_OFF:
+ * @A9_BOOT:
+ * @A9_OPPT1:
+ * @A9_OPPT2:
+ * @A9_EXTCLK:
+ */
+enum clk_arm {
+       A9_OFF,
+       A9_BOOT,
+       A9_OPPT1,
+       A9_OPPT2,
+       A9_EXTCLK
+};
+
+/**
+ * enum clk_gen - GEN#0/GEN#1 clock schemes
+ * @GEN_OFF:
+ * @GEN_BOOT:
+ * @GEN_OPPT1:
+ */
+enum clk_gen {
+       GEN_OFF,
+       GEN_BOOT,
+       GEN_OPPT1,
+};
+
+/* some information between arm and xp70 */
+
+/**
+ * enum romcode_write - Romcode message written by A9 AND read by XP70
+ * @RDY_2_DS: Value set when ApDeepSleep state can be executed by XP70
+ * @RDY_2_XP70_RST: Value set when 0x0F has been successfully polled by the
+ *                 romcode. The xp70 will go into self-reset
+ */
+enum romcode_write {
+       RDY_2_DS = 0x09,
+       RDY_2_XP70_RST = 0x10
+};
+
+/**
+ * enum romcode_read - Romcode message written by XP70 and read by A9
+ * @INIT: Init value when romcode field is not used
+ * @FS_2_DS: Value set when power state is going from ApExecute to
+ *          ApDeepSleep
+ * @END_DS: Value set when ApDeepSleep power state is reached coming from
+ *         ApExecute state
+ * @DS_TO_FS: Value set when power state is going from ApDeepSleep to
+ *           ApExecute
+ * @END_FS: Value set when ApExecute power state is reached coming from
+ *         ApDeepSleep state
+ * @SWR: Value set when power state is going to ApReset
+ * @END_SWR: Value set when the xp70 finished executing ApReset actions and
+ *          waits for romcode acknowledgment to go to self-reset
+ */
+enum romcode_read {
+       INIT = 0x00,
+       FS_2_DS = 0x0A,
+       END_DS = 0x0B,
+       DS_TO_FS = 0x0C,
+       END_FS = 0x0D,
+       SWR = 0x0E,
+       END_SWR = 0x0F
+};
+
+/**
+ * enum ap_pwrst - current power states defined in PRCMU firmware
+ * @NO_PWRST: Current power state init
+ * @AP_BOOT: Current power state is apBoot
+ * @AP_EXECUTE: Current power state is apExecute
+ * @AP_DEEP_SLEEP: Current power state is apDeepSleep
+ * @AP_SLEEP: Current power state is apSleep
+ * @AP_IDLE: Current power state is apIdle
+ * @AP_RESET: Current power state is apReset
+ */
+enum ap_pwrst {
+       NO_PWRST = 0x00,
+       AP_BOOT = 0x01,
+       AP_EXECUTE = 0x02,
+       AP_DEEP_SLEEP = 0x03,
+       AP_SLEEP = 0x04,
+       AP_IDLE = 0x05,
+       AP_RESET = 0x06
+};
+
+/**
+ * enum ap_pwrst_trans - Transition states defined in PRCMU firmware
+ * @NO_TRANSITION: No power state transition
+ * @APEXECUTE_TO_APSLEEP: Power state transition from ApExecute to ApSleep
+ * @APIDLE_TO_APSLEEP: Power state transition from ApIdle to ApSleep
+ * @APBOOT_TO_APEXECUTE: Power state transition from ApBoot to ApExecute
+ * @APEXECUTE_TO_APDEEPSLEEP: Power state transition from ApExecute to
+ *                          ApDeepSleep
+ * @APEXECUTE_TO_APIDLE: Power state transition from ApExecute to ApIdle
+ */
+enum ap_pwrst_trans {
+       NO_TRANSITION                   = 0x00,
+       APEXECUTE_TO_APSLEEP            = 0x01,
+       APIDLE_TO_APSLEEP               = 0x02, /* To be removed */
+       PRCMU_AP_SLEEP                  = 0x01,
+       APBOOT_TO_APEXECUTE             = 0x03,
+       APEXECUTE_TO_APDEEPSLEEP        = 0x04, /* To be removed */
+       PRCMU_AP_DEEP_SLEEP             = 0x04,
+       APEXECUTE_TO_APIDLE             = 0x05, /* To be removed */
+       PRCMU_AP_IDLE                   = 0x05,
+       PRCMU_AP_DEEP_IDLE              = 0x07,
+};
+
+/**
+ * enum ddr_pwrst - DDR power states definition
+ * @DDR_PWR_STATE_UNCHANGED: SDRAM and DDR controller state is unchanged
+ * @DDR_PWR_STATE_ON:
+ * @DDR_PWR_STATE_OFFLOWLAT:
+ * @DDR_PWR_STATE_OFFHIGHLAT:
+ */
+enum ddr_pwrst {
+       DDR_PWR_STATE_UNCHANGED     = 0x00,
+       DDR_PWR_STATE_ON            = 0x01,
+       DDR_PWR_STATE_OFFLOWLAT     = 0x02,
+       DDR_PWR_STATE_OFFHIGHLAT    = 0x03
+};
+
+/**
+ * enum arm_opp - ARM OPP states definition
+ * @ARM_OPP_INIT:
+ * @ARM_NO_CHANGE: The ARM operating point is unchanged
+ * @ARM_100_OPP: The new ARM operating point is arm100opp
+ * @ARM_50_OPP: The new ARM operating point is arm50opp
+ * @ARM_MAX_OPP: Operating point is "max" (more than 100)
+ * @ARM_MAX_FREQ100OPP: Set max opp if available, else 100
+ * @ARM_EXTCLK: The new ARM operating point is armExtClk
+ */
+enum arm_opp {
+       ARM_OPP_INIT = 0x00,
+       ARM_NO_CHANGE = 0x01,
+       ARM_100_OPP = 0x02,
+       ARM_50_OPP = 0x03,
+       ARM_MAX_OPP = 0x04,
+       ARM_MAX_FREQ100OPP = 0x05,
+       ARM_EXTCLK = 0x07
+};
+
+/**
+ * enum ape_opp - APE OPP states definition
+ * @APE_OPP_INIT:
+ * @APE_NO_CHANGE: The APE operating point is unchanged
+ * @APE_100_OPP: The new APE operating point is ape100opp
+ * @APE_50_OPP: 50%
+ */
+enum ape_opp {
+       APE_OPP_INIT = 0x00,
+       APE_NO_CHANGE = 0x01,
+       APE_100_OPP = 0x02,
+       APE_50_OPP = 0x03
+};
+
+/**
+ * enum hw_acc_state - State definition for hardware accelerator
+ * @HW_NO_CHANGE: The hardware accelerator state must remain unchanged
+ * @HW_OFF: The hardware accelerator must be switched off
+ * @HW_OFF_RAMRET: The hardware accelerator must be switched off with its
+ *               internal RAM in retention
+ * @HW_ON: The hwa hardware accelerator hwa must be switched on
+ *
+ * NOTE! Deprecated, to be removed when all users switched over to use the
+ * regulator API.
+ */
+enum hw_acc_state {
+       HW_NO_CHANGE = 0x00,
+       HW_OFF = 0x01,
+       HW_OFF_RAMRET = 0x02,
+       HW_ON = 0x04
+};
+
+/**
+ * enum  mbox_2_arm_stat - Status messages definition for mbox_arm
+ * @BOOT_TO_EXECUTEOK: The apBoot to apExecute state transition has been
+ *                    completed
+ * @DEEPSLEEPOK: The apExecute to apDeepSleep state transition has been
+ *              completed
+ * @SLEEPOK: The apExecute to apSleep state transition has been completed
+ * @IDLEOK: The apExecute to apIdle state transition has been completed
+ * @SOFTRESETOK: The A9 watchdog/ SoftReset state has been completed
+ * @SOFTRESETGO : The A9 watchdog/SoftReset state is on going
+ * @BOOT_TO_EXECUTE: The apBoot to apExecute state transition is on going
+ * @EXECUTE_TO_DEEPSLEEP: The apExecute to apDeepSleep state transition is on
+ *                       going
+ * @DEEPSLEEP_TO_EXECUTE: The apDeepSleep to apExecute state transition is on
+ *                       going
+ * @DEEPSLEEP_TO_EXECUTEOK: The apDeepSleep to apExecute state transition has
+ *                         been completed
+ * @EXECUTE_TO_SLEEP: The apExecute to apSleep state transition is on going
+ * @SLEEP_TO_EXECUTE: The apSleep to apExecute state transition is on going
+ * @SLEEP_TO_EXECUTEOK: The apSleep to apExecute state transition has been
+ *                     completed
+ * @EXECUTE_TO_IDLE: The apExecute to apIdle state transition is on going
+ * @IDLE_TO_EXECUTE: The apIdle to apExecute state transition is on going
+ * @IDLE_TO_EXECUTEOK: The apIdle to apExecute state transition has been
+ *                    completed
+ * @INIT_STATUS: Status init
+ */
+enum ap_pwrsttr_status {
+       BOOT_TO_EXECUTEOK = 0xFF,
+       DEEPSLEEPOK = 0xFE,
+       SLEEPOK = 0xFD,
+       IDLEOK = 0xFC,
+       SOFTRESETOK = 0xFB,
+       SOFTRESETGO = 0xFA,
+       BOOT_TO_EXECUTE = 0xF9,
+       EXECUTE_TO_DEEPSLEEP = 0xF8,
+       DEEPSLEEP_TO_EXECUTE = 0xF7,
+       DEEPSLEEP_TO_EXECUTEOK = 0xF6,
+       EXECUTE_TO_SLEEP = 0xF5,
+       SLEEP_TO_EXECUTE = 0xF4,
+       SLEEP_TO_EXECUTEOK = 0xF3,
+       EXECUTE_TO_IDLE = 0xF2,
+       IDLE_TO_EXECUTE = 0xF1,
+       IDLE_TO_EXECUTEOK = 0xF0,
+       RDYTODS_RETURNTOEXE    = 0xEF,
+       NORDYTODS_RETURNTOEXE  = 0xEE,
+       EXETOSLEEP_RETURNTOEXE = 0xED,
+       EXETOIDLE_RETURNTOEXE  = 0xEC,
+       INIT_STATUS = 0xEB,
+
+       /*error messages */
+       INITERROR                     = 0x00,
+       PLLARMLOCKP_ER                = 0x01,
+       PLLDDRLOCKP_ER                = 0x02,
+       PLLSOCLOCKP_ER                = 0x03,
+       PLLSOCK1LOCKP_ER              = 0x04,
+       ARMWFI_ER                     = 0x05,
+       SYSCLKOK_ER                   = 0x06,
+       I2C_NACK_DATA_ER              = 0x07,
+       BOOT_ER                       = 0x08,
+       I2C_STATUS_ALWAYS_1           = 0x0A,
+       I2C_NACK_REG_ADDR_ER          = 0x0B,
+       I2C_NACK_DATA0123_ER          = 0x1B,
+       I2C_NACK_ADDR_ER              = 0x1F,
+       CURAPPWRSTISNOT_BOOT          = 0x20,
+       CURAPPWRSTISNOT_EXECUTE       = 0x21,
+       CURAPPWRSTISNOT_SLEEPMODE     = 0x22,
+       CURAPPWRSTISNOT_CORRECTFORIT10 = 0x23,
+       FIFO4500WUISNOT_WUPEVENT      = 0x24,
+       PLL32KLOCKP_ER                = 0x29,
+       DDRDEEPSLEEPOK_ER             = 0x2A,
+       ROMCODEREADY_ER               = 0x50,
+       WUPBEFOREDS                   = 0x51,
+       DDRCONFIG_ER                  = 0x52,
+       WUPBEFORESLEEP                = 0x53,
+       WUPBEFOREIDLE                 = 0x54
+};  /* earlier called as  mbox_2_arm_stat */
+
+/**
+ * enum dvfs_stat - DVFS status messages definition
+ * @DVFS_GO: A state transition DVFS is on going
+ * @DVFS_ARM100OPPOK: The state transition DVFS has been completed for 100OPP
+ * @DVFS_ARM50OPPOK: The state transition DVFS has been completed for 50OPP
+ * @DVFS_ARMEXTCLKOK: The state transition DVFS has been completed for EXTCLK
+ * @DVFS_NOCHGTCLKOK: The state transition DVFS has been completed for
+ *                   NOCHGCLK
+ * @DVFS_INITSTATUS: Value init
+ */
+enum dvfs_stat {
+       DVFS_GO = 0xFF,
+       DVFS_ARM100OPPOK = 0xFE,
+       DVFS_ARM50OPPOK = 0xFD,
+       DVFS_ARMEXTCLKOK = 0xFC,
+       DVFS_NOCHGTCLKOK = 0xFB,
+       DVFS_INITSTATUS = 0x00
+};
+
+/**
+ * enum sva_mmdsp_stat - SVA MMDSP status messages
+ * @SVA_MMDSP_GO: SVAMMDSP interrupt has happened
+ * @SVA_MMDSP_INIT: Status init
+ */
+enum sva_mmdsp_stat {
+       SVA_MMDSP_GO = 0xFF,
+       SVA_MMDSP_INIT = 0x00
+};
+
+/**
+ * enum sia_mmdsp_stat - SIA MMDSP status messages
+ * @SIA_MMDSP_GO: SIAMMDSP interrupt has happened
+ * @SIA_MMDSP_INIT: Status init
+ */
+enum sia_mmdsp_stat {
+       SIA_MMDSP_GO = 0xFF,
+       SIA_MMDSP_INIT = 0x00
+};
+
+/**
+ * enum  mbox_to_arm_err - Error messages definition
+ * @INIT_ERR: Init value
+ * @PLLARMLOCKP_ERR: PLLARM has not been correctly locked in given time
+ * @PLLDDRLOCKP_ERR: PLLDDR has not been correctly locked in the given time
+ * @PLLSOC0LOCKP_ERR: PLLSOC0 has not been correctly locked in the given time
+ * @PLLSOC1LOCKP_ERR: PLLSOC1 has not been correctly locked in the given time
+ * @ARMWFI_ERR: The ARM WFI has not been correctly executed in the given time
+ * @SYSCLKOK_ERR: The SYSCLK is not available in the given time
+ * @BOOT_ERR: Romcode has not validated the XP70 self reset in the given time
+ * @ROMCODESAVECONTEXT: The Romcode didn.t correctly save it secure context
+ * @VARMHIGHSPEEDVALTO_ERR: The ARM high speed supply value transfered
+ *          through I2C has not been correctly executed in the given time
+ * @VARMHIGHSPEEDACCESS_ERR: The command value of VarmHighSpeedVal transfered
+ *             through I2C has not been correctly executed in the given time
+ * @VARMLOWSPEEDVALTO_ERR:The ARM low speed supply value transfered through
+ *                     I2C has not been correctly executed in the given time
+ * @VARMLOWSPEEDACCESS_ERR: The command value of VarmLowSpeedVal transfered
+ *             through I2C has not been correctly executed in the given time
+ * @VARMRETENTIONVALTO_ERR: The ARM retention supply value transfered through
+ *                     I2C has not been correctly executed in the given time
+ * @VARMRETENTIONACCESS_ERR: The command value of VarmRetentionVal transfered
+ *             through I2C has not been correctly executed in the given time
+ * @VAPEHIGHSPEEDVALTO_ERR: The APE highspeed supply value transfered through
+ *                     I2C has not been correctly executed in the given time
+ * @VSAFEHPVALTO_ERR: The SAFE high power supply value transfered through I2C
+ *                         has not been correctly executed in the given time
+ * @VMODSEL1VALTO_ERR: The MODEM sel1 supply value transfered through I2C has
+ *                             not been correctly executed in the given time
+ * @VMODSEL2VALTO_ERR: The MODEM sel2 supply value transfered through I2C has
+ *                             not been correctly executed in the given time
+ * @VARMOFFACCESS_ERR: The command value of Varm ON/OFF transfered through
+ *                     I2C has not been correctly executed in the given time
+ * @VAPEOFFACCESS_ERR: The command value of Vape ON/OFF transfered through
+ *                     I2C has not been correctly executed in the given time
+ * @VARMRETACCES_ERR: The command value of Varm retention ON/OFF transfered
+ *             through I2C has not been correctly executed in the given time
+ * @CURAPPWRSTISNOTBOOT:Generated when Arm want to do power state transition
+ *             ApBoot to ApExecute but the power current state is not Apboot
+ * @CURAPPWRSTISNOTEXECUTE: Generated when Arm want to do power state
+ *              transition from ApExecute to others power state but the
+ *              power current state is not ApExecute
+ * @CURAPPWRSTISNOTSLEEPMODE: Generated when wake up events are transmitted
+ *             but the power current state is not ApDeepSleep/ApSleep/ApIdle
+ * @CURAPPWRSTISNOTCORRECTDBG:  Generated when wake up events are transmitted
+ *              but the power current state is not correct
+ * @ARMREGU1VALTO_ERR:The ArmRegu1 value transferred through I2C has not
+ *                    been correctly executed in the given time
+ * @ARMREGU2VALTO_ERR: The ArmRegu2 value transferred through I2C has not
+ *                    been correctly executed in the given time
+ * @VAPEREGUVALTO_ERR: The VApeRegu value transfered through I2C has not
+ *                    been correctly executed in the given time
+ * @VSMPS3REGUVALTO_ERR: The VSmps3Regu value transfered through I2C has not
+ *                      been correctly executed in the given time
+ * @VMODREGUVALTO_ERR: The VModemRegu value transfered through I2C has not
+ *                    been correctly executed in the given time
+ */
+enum mbox_to_arm_err {
+       INIT_ERR = 0x00,
+       PLLARMLOCKP_ERR = 0x01,
+       PLLDDRLOCKP_ERR = 0x02,
+       PLLSOC0LOCKP_ERR = 0x03,
+       PLLSOC1LOCKP_ERR = 0x04,
+       ARMWFI_ERR = 0x05,
+       SYSCLKOK_ERR = 0x06,
+       BOOT_ERR = 0x07,
+       ROMCODESAVECONTEXT = 0x08,
+       VARMHIGHSPEEDVALTO_ERR = 0x10,
+       VARMHIGHSPEEDACCESS_ERR = 0x11,
+       VARMLOWSPEEDVALTO_ERR = 0x12,
+       VARMLOWSPEEDACCESS_ERR = 0x13,
+       VARMRETENTIONVALTO_ERR = 0x14,
+       VARMRETENTIONACCESS_ERR = 0x15,
+       VAPEHIGHSPEEDVALTO_ERR = 0x16,
+       VSAFEHPVALTO_ERR = 0x17,
+       VMODSEL1VALTO_ERR = 0x18,
+       VMODSEL2VALTO_ERR = 0x19,
+       VARMOFFACCESS_ERR = 0x1A,
+       VAPEOFFACCESS_ERR = 0x1B,
+       VARMRETACCES_ERR = 0x1C,
+       CURAPPWRSTISNOTBOOT = 0x20,
+       CURAPPWRSTISNOTEXECUTE = 0x21,
+       CURAPPWRSTISNOTSLEEPMODE = 0x22,
+       CURAPPWRSTISNOTCORRECTDBG = 0x23,
+       ARMREGU1VALTO_ERR = 0x24,
+       ARMREGU2VALTO_ERR = 0x25,
+       VAPEREGUVALTO_ERR = 0x26,
+       VSMPS3REGUVALTO_ERR = 0x27,
+       VMODREGUVALTO_ERR = 0x28
+};
+
+enum hw_acc {
+       SVAMMDSP = 0,
+       SVAPIPE = 1,
+       SIAMMDSP = 2,
+       SIAPIPE = 3,
+       SGA = 4,
+       B2R2MCDE = 5,
+       ESRAM12 = 6,
+       ESRAM34 = 7,
+};
+
+enum cs_pwrmgt {
+       PWRDNCS0  = 0,
+       WKUPCS0   = 1,
+       PWRDNCS1  = 2,
+       WKUPCS1   = 3
+};
+
+/* Defs related to autonomous power management */
+
+/**
+ * enum sia_sva_pwr_policy - Power policy
+ * @NO_CHGT:   No change
+ * @DSPOFF_HWPOFF:
+ * @DSPOFFRAMRET_HWPOFF:
+ * @DSPCLKOFF_HWPOFF:
+ * @DSPCLKOFF_HWPCLKOFF:
+ *
+ */
+enum sia_sva_pwr_policy {
+       NO_CHGT                 = 0x0,
+       DSPOFF_HWPOFF           = 0x1,
+       DSPOFFRAMRET_HWPOFF     = 0x2,
+       DSPCLKOFF_HWPOFF        = 0x3,
+       DSPCLKOFF_HWPCLKOFF     = 0x4,
+};
+
+/**
+ * enum auto_enable - Auto Power enable
+ * @AUTO_OFF:
+ * @AUTO_ON:
+ *
+ */
+enum auto_enable {
+       AUTO_OFF        = 0x0,
+       AUTO_ON         = 0x1,
+};
+
+/* End of file previously known as prcmu-fw-defs_v1.h */
+
+/* PRCMU Wakeup defines */
+enum prcmu_wakeup_index {
+       PRCMU_WAKEUP_INDEX_RTC,
+       PRCMU_WAKEUP_INDEX_RTT0,
+       PRCMU_WAKEUP_INDEX_RTT1,
+       PRCMU_WAKEUP_INDEX_HSI0,
+       PRCMU_WAKEUP_INDEX_HSI1,
+       PRCMU_WAKEUP_INDEX_USB,
+       PRCMU_WAKEUP_INDEX_ABB,
+       PRCMU_WAKEUP_INDEX_ABB_FIFO,
+       PRCMU_WAKEUP_INDEX_ARM,
+       NUM_PRCMU_WAKEUP_INDICES
+};
+#define PRCMU_WAKEUP(_name) (BIT(PRCMU_WAKEUP_INDEX_##_name))
+
+/* PRCMU QoS APE OPP class */
+#define PRCMU_QOS_APE_OPP 1
+#define PRCMU_QOS_DDR_OPP 2
+#define PRCMU_QOS_DEFAULT_VALUE -1
+
+/**
+ * enum hw_acc_dev - enum for hw accelerators
+ * @HW_ACC_SVAMMDSP: for SVAMMDSP
+ * @HW_ACC_SVAPIPE:  for SVAPIPE
+ * @HW_ACC_SIAMMDSP: for SIAMMDSP
+ * @HW_ACC_SIAPIPE: for SIAPIPE
+ * @HW_ACC_SGA: for SGA
+ * @HW_ACC_B2R2: for B2R2
+ * @HW_ACC_MCDE: for MCDE
+ * @HW_ACC_ESRAM1: for ESRAM1
+ * @HW_ACC_ESRAM2: for ESRAM2
+ * @HW_ACC_ESRAM3: for ESRAM3
+ * @HW_ACC_ESRAM4: for ESRAM4
+ * @NUM_HW_ACC: number of hardware accelerators
+ *
+ * Different hw accelerators which can be turned ON/
+ * OFF or put into retention (MMDSPs and ESRAMs).
+ * Used with EPOD API.
+ *
+ * NOTE! Deprecated, to be removed when all users switched over to use the
+ * regulator API.
+ */
+enum hw_acc_dev {
+       HW_ACC_SVAMMDSP,
+       HW_ACC_SVAPIPE,
+       HW_ACC_SIAMMDSP,
+       HW_ACC_SIAPIPE,
+       HW_ACC_SGA,
+       HW_ACC_B2R2,
+       HW_ACC_MCDE,
+       HW_ACC_ESRAM1,
+       HW_ACC_ESRAM2,
+       HW_ACC_ESRAM3,
+       HW_ACC_ESRAM4,
+       NUM_HW_ACC
+};
+
+/*
+ * Ids for all EPODs (power domains)
+ * - EPOD_ID_SVAMMDSP: power domain for SVA MMDSP
+ * - EPOD_ID_SVAPIPE: power domain for SVA pipe
+ * - EPOD_ID_SIAMMDSP: power domain for SIA MMDSP
+ * - EPOD_ID_SIAPIPE: power domain for SIA pipe
+ * - EPOD_ID_SGA: power domain for SGA
+ * - EPOD_ID_B2R2_MCDE: power domain for B2R2 and MCDE
+ * - EPOD_ID_ESRAM12: power domain for ESRAM 1 and 2
+ * - EPOD_ID_ESRAM34: power domain for ESRAM 3 and 4
+ * - NUM_EPOD_ID: number of power domains
+ */
+#define EPOD_ID_SVAMMDSP       0
+#define EPOD_ID_SVAPIPE                1
+#define EPOD_ID_SIAMMDSP       2
+#define EPOD_ID_SIAPIPE                3
+#define EPOD_ID_SGA            4
+#define EPOD_ID_B2R2_MCDE      5
+#define EPOD_ID_ESRAM12                6
+#define EPOD_ID_ESRAM34                7
+#define NUM_EPOD_ID            8
+
+/*
+ * state definition for EPOD (power domain)
+ * - EPOD_STATE_NO_CHANGE: The EPOD should remain unchanged
+ * - EPOD_STATE_OFF: The EPOD is switched off
+ * - EPOD_STATE_RAMRET: The EPOD is switched off with its internal RAM in
+ *                         retention
+ * - EPOD_STATE_ON_CLK_OFF: The EPOD is switched on, clock is still off
+ * - EPOD_STATE_ON: Same as above, but with clock enabled
+ */
+#define EPOD_STATE_NO_CHANGE   0x00
+#define EPOD_STATE_OFF         0x01
+#define EPOD_STATE_RAMRET      0x02
+#define EPOD_STATE_ON_CLK_OFF  0x03
+#define EPOD_STATE_ON          0x04
+
+/*
+ * CLKOUT sources
+ */
+#define PRCMU_CLKSRC_CLK38M            0x00
+#define PRCMU_CLKSRC_ACLK              0x01
+#define PRCMU_CLKSRC_SYSCLK            0x02
+#define PRCMU_CLKSRC_LCDCLK            0x03
+#define PRCMU_CLKSRC_SDMMCCLK          0x04
+#define PRCMU_CLKSRC_TVCLK             0x05
+#define PRCMU_CLKSRC_TIMCLK            0x06
+#define PRCMU_CLKSRC_CLK009            0x07
+/* These are only valid for CLKOUT1: */
+#define PRCMU_CLKSRC_SIAMMDSPCLK       0x40
+#define PRCMU_CLKSRC_I2CCLK            0x41
+#define PRCMU_CLKSRC_MSP02CLK          0x42
+#define PRCMU_CLKSRC_ARMPLL_OBSCLK     0x43
+#define PRCMU_CLKSRC_HSIRXCLK          0x44
+#define PRCMU_CLKSRC_HSITXCLK          0x45
+#define PRCMU_CLKSRC_ARMCLKFIX         0x46
+#define PRCMU_CLKSRC_HDMICLK           0x47
+
+/*
+ * Definitions for autonomous power management configuration.
+ */
+
+#define PRCMU_AUTO_PM_OFF 0
+#define PRCMU_AUTO_PM_ON 1
+
+#define PRCMU_AUTO_PM_POWER_ON_HSEM BIT(0)
+#define PRCMU_AUTO_PM_POWER_ON_ABB_FIFO_IT BIT(1)
+
+enum prcmu_auto_pm_policy {
+       PRCMU_AUTO_PM_POLICY_NO_CHANGE,
+       PRCMU_AUTO_PM_POLICY_DSP_OFF_HWP_OFF,
+       PRCMU_AUTO_PM_POLICY_DSP_OFF_RAMRET_HWP_OFF,
+       PRCMU_AUTO_PM_POLICY_DSP_CLK_OFF_HWP_OFF,
+       PRCMU_AUTO_PM_POLICY_DSP_CLK_OFF_HWP_CLK_OFF,
+};
+
+/**
+ * struct prcmu_auto_pm_config - Autonomous power management configuration.
+ * @sia_auto_pm_enable: SIA autonomous pm enable. (PRCMU_AUTO_PM_{OFF,ON})
+ * @sia_power_on:       SIA power ON enable. (PRCMU_AUTO_PM_POWER_ON_* bitmask)
+ * @sia_policy:         SIA power policy. (enum prcmu_auto_pm_policy)
+ * @sva_auto_pm_enable: SVA autonomous pm enable. (PRCMU_AUTO_PM_{OFF,ON})
+ * @sva_power_on:       SVA power ON enable. (PRCMU_AUTO_PM_POWER_ON_* bitmask)
+ * @sva_policy:         SVA power policy. (enum prcmu_auto_pm_policy)
+ */
+struct prcmu_auto_pm_config {
+       u8 sia_auto_pm_enable;
+       u8 sia_power_on;
+       u8 sia_policy;
+       u8 sva_auto_pm_enable;
+       u8 sva_power_on;
+       u8 sva_policy;
+};
+
+/**
+ * enum ddr_opp - DDR OPP states definition
+ * @DDR_100_OPP: The new DDR operating point is ddr100opp
+ * @DDR_50_OPP: The new DDR operating point is ddr50opp
+ * @DDR_25_OPP: The new DDR operating point is ddr25opp
+ */
+enum ddr_opp {
+       DDR_100_OPP = 0x00,
+       DDR_50_OPP = 0x01,
+       DDR_25_OPP = 0x02,
+};
+
+/*
+ * Clock identifiers.
+ */
+enum prcmu_clock {
+       PRCMU_SGACLK,
+       PRCMU_UARTCLK,
+       PRCMU_MSP02CLK,
+       PRCMU_MSP1CLK,
+       PRCMU_I2CCLK,
+       PRCMU_SDMMCCLK,
+       PRCMU_SLIMCLK,
+       PRCMU_PER1CLK,
+       PRCMU_PER2CLK,
+       PRCMU_PER3CLK,
+       PRCMU_PER5CLK,
+       PRCMU_PER6CLK,
+       PRCMU_PER7CLK,
+       PRCMU_LCDCLK,
+       PRCMU_BMLCLK,
+       PRCMU_HSITXCLK,
+       PRCMU_HSIRXCLK,
+       PRCMU_HDMICLK,
+       PRCMU_APEATCLK,
+       PRCMU_APETRACECLK,
+       PRCMU_MCDECLK,
+       PRCMU_IPI2CCLK,
+       PRCMU_DSIALTCLK,
+       PRCMU_DMACLK,
+       PRCMU_B2R2CLK,
+       PRCMU_TVCLK,
+       PRCMU_SSPCLK,
+       PRCMU_RNGCLK,
+       PRCMU_UICCCLK,
+       PRCMU_NUM_REG_CLOCKS,
+       PRCMU_SYSCLK = PRCMU_NUM_REG_CLOCKS,
+       PRCMU_TIMCLK,
+};
+
+/*
+ * Definitions for controlling ESRAM0 in deep sleep.
+ */
+#define ESRAM0_DEEP_SLEEP_STATE_OFF 1
+#define ESRAM0_DEEP_SLEEP_STATE_RET 2
+
+#ifdef CONFIG_MFD_DB8500_PRCMU
+void __init prcmu_early_init(void);
+int prcmu_set_display_clocks(void);
+int prcmu_disable_dsipll(void);
+int prcmu_enable_dsipll(void);
+#else
+static inline void __init prcmu_early_init(void) {}
+#endif
+
+#ifdef CONFIG_MFD_DB8500_PRCMU
+
+int prcmu_set_rc_a2p(enum romcode_write);
+enum romcode_read prcmu_get_rc_p2a(void);
+enum ap_pwrst prcmu_get_xp70_current_state(void);
+int prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll);
+
+void prcmu_enable_wakeups(u32 wakeups);
+static inline void prcmu_disable_wakeups(void)
+{
+       prcmu_enable_wakeups(0);
+}
+
+void prcmu_config_abb_event_readout(u32 abb_events);
+void prcmu_get_abb_event_buffer(void __iomem **buf);
+int prcmu_set_arm_opp(u8 opp);
+int prcmu_get_arm_opp(void);
+bool prcmu_has_arm_maxopp(void);
+bool prcmu_is_u8400(void);
+int prcmu_set_ape_opp(u8 opp);
+int prcmu_get_ape_opp(void);
+int prcmu_request_ape_opp_100_voltage(bool enable);
+int prcmu_release_usb_wakeup_state(void);
+int prcmu_set_ddr_opp(u8 opp);
+int prcmu_get_ddr_opp(void);
+unsigned long prcmu_qos_get_cpufreq_opp_delay(void);
+void prcmu_qos_set_cpufreq_opp_delay(unsigned long);
+/* NOTE! Use regulator framework instead */
+int prcmu_set_hwacc(u16 hw_acc_dev, u8 state);
+int prcmu_set_epod(u16 epod_id, u8 epod_state);
+void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
+       struct prcmu_auto_pm_config *idle);
+bool prcmu_is_auto_pm_enabled(void);
+
+int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
+int prcmu_request_clock(u8 clock, bool enable);
+int prcmu_set_clock_divider(u8 clock, u8 divider);
+int prcmu_config_esram0_deep_sleep(u8 state);
+int prcmu_config_hotdog(u8 threshold);
+int prcmu_config_hotmon(u8 low, u8 high);
+int prcmu_start_temp_sense(u16 cycles32k);
+int prcmu_stop_temp_sense(void);
+int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
+
+void prcmu_ac_wake_req(void);
+void prcmu_ac_sleep_req(void);
+void prcmu_system_reset(u16 reset_code);
+void prcmu_modem_reset(void);
+bool prcmu_is_ac_wake_requested(void);
+void prcmu_enable_spi2(void);
+void prcmu_disable_spi2(void);
+
+#else /* !CONFIG_MFD_DB8500_PRCMU */
+
+static inline int prcmu_set_rc_a2p(enum romcode_write code)
+{
+       return 0;
+}
+
+static inline enum romcode_read prcmu_get_rc_p2a(void)
+{
+       return INIT;
+}
+
+static inline enum ap_pwrst prcmu_get_xp70_current_state(void)
+{
+       return AP_EXECUTE;
+}
+
+static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
+       bool keep_ap_pll)
+{
+       return 0;
+}
+
+static inline void prcmu_enable_wakeups(u32 wakeups) {}
+
+static inline void prcmu_disable_wakeups(void) {}
+
+static inline void prcmu_config_abb_event_readout(u32 abb_events) {}
+
+static inline int prcmu_set_arm_opp(u8 opp)
+{
+       return 0;
+}
+
+static inline int prcmu_get_arm_opp(void)
+{
+       return ARM_100_OPP;
+}
+
+static bool prcmu_has_arm_maxopp(void)
+{
+       return false;
+}
+
+static bool prcmu_is_u8400(void)
+{
+       return false;
+}
+
+static inline int prcmu_set_ape_opp(u8 opp)
+{
+       return 0;
+}
+
+static inline int prcmu_get_ape_opp(void)
+{
+       return APE_100_OPP;
+}
+
+static inline int prcmu_request_ape_opp_100_voltage(bool enable)
+{
+       return 0;
+}
+
+static inline int prcmu_release_usb_wakeup_state(void)
+{
+       return 0;
+}
+
+static inline int prcmu_set_ddr_opp(u8 opp)
+{
+       return 0;
+}
+
+static inline int prcmu_get_ddr_opp(void)
+{
+       return DDR_100_OPP;
+}
+
+static inline unsigned long prcmu_qos_get_cpufreq_opp_delay(void)
+{
+       return 0;
+}
+
+static inline void prcmu_qos_set_cpufreq_opp_delay(unsigned long n) {}
+
+static inline int prcmu_set_hwacc(u16 hw_acc_dev, u8 state)
+{
+       return 0;
+}
+
+static inline void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
+       struct prcmu_auto_pm_config *idle)
+{
+}
+
+static inline bool prcmu_is_auto_pm_enabled(void)
+{
+       return false;
+}
+
+static inline int prcmu_config_clkout(u8 clkout, u8 source, u8 div)
+{
+       return 0;
+}
+
+static inline int prcmu_request_clock(u8 clock, bool enable)
+{
+       return 0;
+}
+
+static inline int prcmu_set_clock_divider(u8 clock, u8 divider)
+{
+       return 0;
+}
+
+int prcmu_config_esram0_deep_sleep(u8 state)
+{
+       return 0;
+}
+
+static inline int prcmu_config_hotdog(u8 threshold)
+{
+       return 0;
+}
+
+static inline int prcmu_config_hotmon(u8 low, u8 high)
+{
+       return 0;
+}
+
+static inline int prcmu_start_temp_sense(u16 cycles32k)
+{
+       return 0;
+}
+
+static inline int prcmu_stop_temp_sense(void)
+{
+       return 0;
+}
+
+static inline int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       return -ENOSYS;
+}
+
+static inline int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       return -ENOSYS;
+}
+
+static inline void prcmu_ac_wake_req(void) {}
+
+static inline void prcmu_ac_sleep_req(void) {}
+
+static inline void prcmu_system_reset(u16 reset_code) {}
+
+static inline void prcmu_modem_reset(void) {}
+
+static inline bool prcmu_is_ac_wake_requested(void)
+{
+       return false;
+}
+
+#ifndef CONFIG_UX500_SOC_DB5500
+static inline int prcmu_set_display_clocks(void)
+{
+       return 0;
+}
+
+static inline int prcmu_disable_dsipll(void)
+{
+       return 0;
+}
+
+static inline int prcmu_enable_dsipll(void)
+{
+       return 0;
+}
+#endif
+
+static inline int prcmu_enable_spi2(void)
+{
+       return 0;
+}
+
+static inline int prcmu_disable_spi2(void)
+{
+       return 0;
+}
+
+#endif /* !CONFIG_MFD_DB8500_PRCMU */
+
+#ifdef CONFIG_UX500_PRCMU_QOS_POWER
+int prcmu_qos_requirement(int pm_qos_class);
+int prcmu_qos_add_requirement(int pm_qos_class, char *name, s32 value);
+int prcmu_qos_update_requirement(int pm_qos_class, char *name, s32 new_value);
+void prcmu_qos_remove_requirement(int pm_qos_class, char *name);
+int prcmu_qos_add_notifier(int prcmu_qos_class,
+                          struct notifier_block *notifier);
+int prcmu_qos_remove_notifier(int prcmu_qos_class,
+                             struct notifier_block *notifier);
+#else
+static inline int prcmu_qos_requirement(int prcmu_qos_class)
+{
+       return 0;
+}
+
+static inline int prcmu_qos_add_requirement(int prcmu_qos_class,
+                                           char *name, s32 value)
+{
+       return 0;
+}
+
+static inline int prcmu_qos_update_requirement(int prcmu_qos_class,
+                                              char *name, s32 new_value)
+{
+       return 0;
+}
+
+static inline void prcmu_qos_remove_requirement(int prcmu_qos_class, char *name)
+{
+}
+
+static inline int prcmu_qos_add_notifier(int prcmu_qos_class,
+                                        struct notifier_block *notifier)
+{
+       return 0;
+}
+static inline int prcmu_qos_remove_notifier(int prcmu_qos_class,
+                                           struct notifier_block *notifier)
+{
+       return 0;
+}
+
+#endif
+
+#endif /* __MFD_DB8500_PRCMU_H */
index 69d1010e2e5146d7cd8d0a1c71cf8c05608024e0..5ff2400ad46cd4325b31027ff8b82554eb6bc592 100644 (file)
@@ -311,10 +311,6 @@ enum max8997_irq {
        MAX8997_IRQ_NR,
 };
 
-#define MAX8997_REG_BUCK1DVS(x)        (MAX8997_REG_BUCK1DVS1 + (x) - 1)
-#define MAX8997_REG_BUCK2DVS(x)        (MAX8997_REG_BUCK2DVS1 + (x) - 1)
-#define MAX8997_REG_BUCK5DVS(x)        (MAX8997_REG_BUCK5DVS1 + (x) - 1)
-
 #define MAX8997_NUM_GPIO       12
 struct max8997_dev {
        struct device *dev;
diff --git a/include/linux/mfd/pm8xxx/core.h b/include/linux/mfd/pm8xxx/core.h
new file mode 100644 (file)
index 0000000..bd2f4f6
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+/*
+ * Qualcomm PMIC 8xxx driver header file
+ *
+ */
+
+#ifndef __MFD_PM8XXX_CORE_H
+#define __MFD_PM8XXX_CORE_H
+
+#include <linux/mfd/core.h>
+
+struct pm8xxx_drvdata {
+       int     (*pmic_readb) (const struct device *dev, u16 addr, u8 *val);
+       int     (*pmic_writeb) (const struct device *dev, u16 addr, u8 val);
+       int     (*pmic_read_buf) (const struct device *dev, u16 addr, u8 *buf,
+                                                                       int n);
+       int     (*pmic_write_buf) (const struct device *dev, u16 addr, u8 *buf,
+                                                                       int n);
+       int     (*pmic_read_irq_stat) (const struct device *dev, int irq);
+       void    *pm_chip_data;
+};
+
+static inline int pm8xxx_readb(const struct device *dev, u16 addr, u8 *val)
+{
+       struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
+
+       if (!dd)
+               return -EINVAL;
+       return dd->pmic_readb(dev, addr, val);
+}
+
+static inline int pm8xxx_writeb(const struct device *dev, u16 addr, u8 val)
+{
+       struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
+
+       if (!dd)
+               return -EINVAL;
+       return dd->pmic_writeb(dev, addr, val);
+}
+
+static inline int pm8xxx_read_buf(const struct device *dev, u16 addr, u8 *buf,
+                                                                       int n)
+{
+       struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
+
+       if (!dd)
+               return -EINVAL;
+       return dd->pmic_read_buf(dev, addr, buf, n);
+}
+
+static inline int pm8xxx_write_buf(const struct device *dev, u16 addr, u8 *buf,
+                                                                       int n)
+{
+       struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
+
+       if (!dd)
+               return -EINVAL;
+       return dd->pmic_write_buf(dev, addr, buf, n);
+}
+
+static inline int pm8xxx_read_irq_stat(const struct device *dev, int irq)
+{
+       struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
+
+       if (!dd)
+               return -EINVAL;
+       return dd->pmic_read_irq_stat(dev, irq);
+}
+
+#endif
diff --git a/include/linux/mfd/pm8xxx/irq.h b/include/linux/mfd/pm8xxx/irq.h
new file mode 100644 (file)
index 0000000..4b21769
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+/*
+ * Qualcomm PMIC irq 8xxx driver header file
+ *
+ */
+
+#ifndef __MFD_PM8XXX_IRQ_H
+#define __MFD_PM8XXX_IRQ_H
+
+#include <linux/errno.h>
+#include <linux/err.h>
+
+struct pm8xxx_irq_core_data {
+       u32             rev;
+       int             nirqs;
+};
+
+struct pm8xxx_irq_platform_data {
+       int                             irq_base;
+       struct pm8xxx_irq_core_data     irq_cdata;
+       int                             devirq;
+       int                             irq_trigger_flag;
+};
+
+struct pm_irq_chip;
+
+#ifdef CONFIG_MFD_PM8XXX_IRQ
+int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq);
+struct pm_irq_chip * __devinit pm8xxx_irq_init(struct device *dev,
+                               const struct pm8xxx_irq_platform_data *pdata);
+int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip);
+#else
+static inline int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
+{
+       return -ENXIO;
+}
+static inline struct pm_irq_chip * __devinit pm8xxx_irq_init(
+                               const struct device *dev,
+                               const struct pm8xxx_irq_platform_data *pdata)
+{
+       return ERR_PTR(-ENXIO);
+}
+static inline int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip)
+{
+       return -ENXIO;
+}
+#endif /* CONFIG_MFD_PM8XXX_IRQ */
+#endif /* __MFD_PM8XXX_IRQ_H */
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
new file mode 100644 (file)
index 0000000..d5517fd
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+/*
+ * Qualcomm PMIC 8921 driver header file
+ *
+ */
+
+#ifndef __MFD_PM8921_H
+#define __MFD_PM8921_H
+
+#include <linux/device.h>
+#include <linux/mfd/pm8xxx/irq.h>
+
+#define PM8921_NR_IRQS         256
+
+struct pm8921_platform_data {
+       int                                     irq_base;
+       struct pm8xxx_irq_platform_data         *irq_pdata;
+};
+
+#endif
index 8e70310ee9453c6d5abdcd514345479055d8d684..5a90266c3a5a7061a0e3639082d106ffbe72ff01 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/fb.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 #define tmio_ioread8(addr) readb(addr)
 #define tmio_ioread16(addr) readw(addr)
  * Some controllers can support SDIO IRQ signalling.
  */
 #define TMIO_MMC_SDIO_IRQ              (1 << 2)
+/*
+ * Some platforms can detect card insertion events with controller powered
+ * down, in which case they have to call tmio_mmc_cd_wakeup() to power up the
+ * controller and report the event to the driver.
+ */
+#define TMIO_MMC_HAS_COLD_CD           (1 << 3)
 
 int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base);
 int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base);
@@ -82,11 +89,21 @@ struct tmio_mmc_data {
        unsigned long                   flags;
        u32                             ocr_mask;       /* available voltages */
        struct tmio_mmc_dma             *dma;
+       struct device                   *dev;
+       bool                            power;
        void (*set_pwr)(struct platform_device *host, int state);
        void (*set_clk_div)(struct platform_device *host, int state);
        int (*get_cd)(struct platform_device *host);
 };
 
+static inline void tmio_mmc_cd_wakeup(struct tmio_mmc_data *pdata)
+{
+       if (pdata && !pdata->power) {
+               pdata->power = true;
+               pm_runtime_get(pdata->dev);
+       }
+}
+
 /*
  * data for the NAND controller
  */
diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h
new file mode 100644 (file)
index 0000000..8bb85b9
--- /dev/null
@@ -0,0 +1,800 @@
+/*
+ * tps65910.h  --  TI TPS6591x
+ *
+ * Copyright 2010-2011 Texas Instruments Inc.
+ *
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
+ * Author: Arnaud Deconinck <a-deconinck@ti.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.
+ *
+ */
+
+#ifndef __LINUX_MFD_TPS65910_H
+#define __LINUX_MFD_TPS65910_H
+
+/* TPS chip id list */
+#define TPS65910                       0
+#define TPS65911                       1
+
+/* TPS regulator type list */
+#define REGULATOR_LDO                  0
+#define REGULATOR_DCDC                 1
+
+/*
+ * List of registers for component TPS65910
+ *
+ */
+
+#define TPS65910_SECONDS                               0x0
+#define TPS65910_MINUTES                               0x1
+#define TPS65910_HOURS                                 0x2
+#define TPS65910_DAYS                                  0x3
+#define TPS65910_MONTHS                                        0x4
+#define TPS65910_YEARS                                 0x5
+#define TPS65910_WEEKS                                 0x6
+#define TPS65910_ALARM_SECONDS                         0x8
+#define TPS65910_ALARM_MINUTES                         0x9
+#define TPS65910_ALARM_HOURS                           0xA
+#define TPS65910_ALARM_DAYS                            0xB
+#define TPS65910_ALARM_MONTHS                          0xC
+#define TPS65910_ALARM_YEARS                           0xD
+#define TPS65910_RTC_CTRL                              0x10
+#define TPS65910_RTC_STATUS                            0x11
+#define TPS65910_RTC_INTERRUPTS                                0x12
+#define TPS65910_RTC_COMP_LSB                          0x13
+#define TPS65910_RTC_COMP_MSB                          0x14
+#define TPS65910_RTC_RES_PROG                          0x15
+#define TPS65910_RTC_RESET_STATUS                      0x16
+#define TPS65910_BCK1                                  0x17
+#define TPS65910_BCK2                                  0x18
+#define TPS65910_BCK3                                  0x19
+#define TPS65910_BCK4                                  0x1A
+#define TPS65910_BCK5                                  0x1B
+#define TPS65910_PUADEN                                        0x1C
+#define TPS65910_REF                                   0x1D
+#define TPS65910_VRTC                                  0x1E
+#define TPS65910_VIO                                   0x20
+#define TPS65910_VDD1                                  0x21
+#define TPS65910_VDD1_OP                               0x22
+#define TPS65910_VDD1_SR                               0x23
+#define TPS65910_VDD2                                  0x24
+#define TPS65910_VDD2_OP                               0x25
+#define TPS65910_VDD2_SR                               0x26
+#define TPS65910_VDD3                                  0x27
+#define TPS65910_VDIG1                                 0x30
+#define TPS65910_VDIG2                                 0x31
+#define TPS65910_VAUX1                                 0x32
+#define TPS65910_VAUX2                                 0x33
+#define TPS65910_VAUX33                                        0x34
+#define TPS65910_VMMC                                  0x35
+#define TPS65910_VPLL                                  0x36
+#define TPS65910_VDAC                                  0x37
+#define TPS65910_THERM                                 0x38
+#define TPS65910_BBCH                                  0x39
+#define TPS65910_DCDCCTRL                              0x3E
+#define TPS65910_DEVCTRL                               0x3F
+#define TPS65910_DEVCTRL2                              0x40
+#define TPS65910_SLEEP_KEEP_LDO_ON                     0x41
+#define TPS65910_SLEEP_KEEP_RES_ON                     0x42
+#define TPS65910_SLEEP_SET_LDO_OFF                     0x43
+#define TPS65910_SLEEP_SET_RES_OFF                     0x44
+#define TPS65910_EN1_LDO_ASS                           0x45
+#define TPS65910_EN1_SMPS_ASS                          0x46
+#define TPS65910_EN2_LDO_ASS                           0x47
+#define TPS65910_EN2_SMPS_ASS                          0x48
+#define TPS65910_EN3_LDO_ASS                           0x49
+#define TPS65910_SPARE                                 0x4A
+#define TPS65910_INT_STS                               0x50
+#define TPS65910_INT_MSK                               0x51
+#define TPS65910_INT_STS2                              0x52
+#define TPS65910_INT_MSK2                              0x53
+#define TPS65910_INT_STS3                              0x54
+#define TPS65910_INT_MSK3                              0x55
+#define TPS65910_GPIO0                                 0x60
+#define TPS65910_GPIO1                                 0x61
+#define TPS65910_GPIO2                                 0x62
+#define TPS65910_GPIO3                                 0x63
+#define TPS65910_GPIO4                                 0x64
+#define TPS65910_GPIO5                                 0x65
+#define TPS65910_GPIO6                                 0x66
+#define TPS65910_GPIO7                                 0x67
+#define TPS65910_GPIO8                                 0x68
+#define TPS65910_JTAGVERNUM                            0x80
+#define TPS65910_MAX_REGISTER                          0x80
+
+/*
+ * List of registers specific to TPS65911
+ */
+#define TPS65911_VDDCTRL                               0x27
+#define TPS65911_VDDCTRL_OP                            0x28
+#define TPS65911_VDDCTRL_SR                            0x29
+#define TPS65911_LDO1                                  0x30
+#define TPS65911_LDO2                                  0x31
+#define TPS65911_LDO5                                  0x32
+#define TPS65911_LDO8                                  0x33
+#define TPS65911_LDO7                                  0x34
+#define TPS65911_LDO6                                  0x35
+#define TPS65911_LDO4                                  0x36
+#define TPS65911_LDO3                                  0x37
+#define TPS65911_VMBCH                                 0x6A
+#define TPS65911_VMBCH2                                        0x6B
+
+/*
+ * List of register bitfields for component TPS65910
+ *
+ */
+
+
+/*Register BCK1  (0x80) register.RegisterDescription */
+#define BCK1_BCKUP_MASK                                        0xFF
+#define BCK1_BCKUP_SHIFT                               0
+
+
+/*Register BCK2  (0x80) register.RegisterDescription */
+#define BCK2_BCKUP_MASK                                        0xFF
+#define BCK2_BCKUP_SHIFT                               0
+
+
+/*Register BCK3  (0x80) register.RegisterDescription */
+#define BCK3_BCKUP_MASK                                        0xFF
+#define BCK3_BCKUP_SHIFT                               0
+
+
+/*Register BCK4  (0x80) register.RegisterDescription */
+#define BCK4_BCKUP_MASK                                        0xFF
+#define BCK4_BCKUP_SHIFT                               0
+
+
+/*Register BCK5  (0x80) register.RegisterDescription */
+#define BCK5_BCKUP_MASK                                        0xFF
+#define BCK5_BCKUP_SHIFT                               0
+
+
+/*Register PUADEN  (0x80) register.RegisterDescription */
+#define PUADEN_EN3P_MASK                               0x80
+#define PUADEN_EN3P_SHIFT                              7
+#define PUADEN_I2CCTLP_MASK                            0x40
+#define PUADEN_I2CCTLP_SHIFT                           6
+#define PUADEN_I2CSRP_MASK                             0x20
+#define PUADEN_I2CSRP_SHIFT                            5
+#define PUADEN_PWRONP_MASK                             0x10
+#define PUADEN_PWRONP_SHIFT                            4
+#define PUADEN_SLEEPP_MASK                             0x08
+#define PUADEN_SLEEPP_SHIFT                            3
+#define PUADEN_PWRHOLDP_MASK                           0x04
+#define PUADEN_PWRHOLDP_SHIFT                          2
+#define PUADEN_BOOT1P_MASK                             0x02
+#define PUADEN_BOOT1P_SHIFT                            1
+#define PUADEN_BOOT0P_MASK                             0x01
+#define PUADEN_BOOT0P_SHIFT                            0
+
+
+/*Register REF (0x80) register.RegisterDescription */
+#define REF_VMBCH_SEL_MASK                             0x0C
+#define REF_VMBCH_SEL_SHIFT                            2
+#define REF_ST_MASK                                    0x03
+#define REF_ST_SHIFT                                   0
+
+
+/*Register VRTC  (0x80) register.RegisterDescription */
+#define VRTC_VRTC_OFFMASK_MASK                         0x08
+#define VRTC_VRTC_OFFMASK_SHIFT                                3
+#define VRTC_ST_MASK                                   0x03
+#define VRTC_ST_SHIFT                                  0
+
+
+/*Register VIO (0x80) register.RegisterDescription */
+#define VIO_ILMAX_MASK                                 0xC0
+#define VIO_ILMAX_SHIFT                                        6
+#define VIO_SEL_MASK                                   0x0C
+#define VIO_SEL_SHIFT                                  2
+#define VIO_ST_MASK                                    0x03
+#define VIO_ST_SHIFT                                   0
+
+
+/*Register VDD1  (0x80) register.RegisterDescription */
+#define VDD1_VGAIN_SEL_MASK                            0xC0
+#define VDD1_VGAIN_SEL_SHIFT                           6
+#define VDD1_ILMAX_MASK                                        0x20
+#define VDD1_ILMAX_SHIFT                               5
+#define VDD1_TSTEP_MASK                                        0x1C
+#define VDD1_TSTEP_SHIFT                               2
+#define VDD1_ST_MASK                                   0x03
+#define VDD1_ST_SHIFT                                  0
+
+
+/*Register VDD1_OP  (0x80) register.RegisterDescription */
+#define VDD1_OP_CMD_MASK                               0x80
+#define VDD1_OP_CMD_SHIFT                              7
+#define VDD1_OP_SEL_MASK                               0x7F
+#define VDD1_OP_SEL_SHIFT                              0
+
+
+/*Register VDD1_SR  (0x80) register.RegisterDescription */
+#define VDD1_SR_SEL_MASK                               0x7F
+#define VDD1_SR_SEL_SHIFT                              0
+
+
+/*Register VDD2  (0x80) register.RegisterDescription */
+#define VDD2_VGAIN_SEL_MASK                            0xC0
+#define VDD2_VGAIN_SEL_SHIFT                           6
+#define VDD2_ILMAX_MASK                                        0x20
+#define VDD2_ILMAX_SHIFT                               5
+#define VDD2_TSTEP_MASK                                        0x1C
+#define VDD2_TSTEP_SHIFT                               2
+#define VDD2_ST_MASK                                   0x03
+#define VDD2_ST_SHIFT                                  0
+
+
+/*Register VDD2_OP  (0x80) register.RegisterDescription */
+#define VDD2_OP_CMD_MASK                               0x80
+#define VDD2_OP_CMD_SHIFT                              7
+#define VDD2_OP_SEL_MASK                               0x7F
+#define VDD2_OP_SEL_SHIFT                              0
+
+/*Register VDD2_SR  (0x80) register.RegisterDescription */
+#define VDD2_SR_SEL_MASK                               0x7F
+#define VDD2_SR_SEL_SHIFT                              0
+
+
+/*Registers VDD1, VDD2 voltage values definitions */
+#define VDD1_2_NUM_VOLTS                               73
+#define VDD1_2_MIN_VOLT                                        6000
+#define VDD1_2_OFFSET                                  125
+
+
+/*Register VDD3  (0x80) register.RegisterDescription */
+#define VDD3_CKINEN_MASK                               0x04
+#define VDD3_CKINEN_SHIFT                              2
+#define VDD3_ST_MASK                                   0x03
+#define VDD3_ST_SHIFT                                  0
+#define VDDCTRL_MIN_VOLT                               6000
+#define VDDCTRL_OFFSET                                 125
+
+/*Registers VDIG (0x80) to VDAC register.RegisterDescription */
+#define LDO_SEL_MASK                                   0x0C
+#define LDO_SEL_SHIFT                                  2
+#define LDO_ST_MASK                                    0x03
+#define LDO_ST_SHIFT                                   0
+#define LDO_ST_ON_BIT                                  0x01
+#define LDO_ST_MODE_BIT                                        0x02    
+
+
+/* Registers LDO1 to LDO8 in tps65910 */
+#define LDO1_SEL_MASK                                  0xFC
+#define LDO3_SEL_MASK                                  0x7C
+#define LDO_MIN_VOLT                                   1000
+#define LDO_MAX_VOLT                                   3300;
+
+
+/*Register VDIG1  (0x80) register.RegisterDescription */
+#define VDIG1_SEL_MASK                                 0x0C
+#define VDIG1_SEL_SHIFT                                        2
+#define VDIG1_ST_MASK                                  0x03
+#define VDIG1_ST_SHIFT                                 0
+
+
+/*Register VDIG2  (0x80) register.RegisterDescription */
+#define VDIG2_SEL_MASK                                 0x0C
+#define VDIG2_SEL_SHIFT                                        2
+#define VDIG2_ST_MASK                                  0x03
+#define VDIG2_ST_SHIFT                                 0
+
+
+/*Register VAUX1  (0x80) register.RegisterDescription */
+#define VAUX1_SEL_MASK                                 0x0C
+#define VAUX1_SEL_SHIFT                                        2
+#define VAUX1_ST_MASK                                  0x03
+#define VAUX1_ST_SHIFT                                 0
+
+
+/*Register VAUX2  (0x80) register.RegisterDescription */
+#define VAUX2_SEL_MASK                                 0x0C
+#define VAUX2_SEL_SHIFT                                        2
+#define VAUX2_ST_MASK                                  0x03
+#define VAUX2_ST_SHIFT                                 0
+
+
+/*Register VAUX33  (0x80) register.RegisterDescription */
+#define VAUX33_SEL_MASK                                        0x0C
+#define VAUX33_SEL_SHIFT                               2
+#define VAUX33_ST_MASK                                 0x03
+#define VAUX33_ST_SHIFT                                        0
+
+
+/*Register VMMC  (0x80) register.RegisterDescription */
+#define VMMC_SEL_MASK                                  0x0C
+#define VMMC_SEL_SHIFT                                 2
+#define VMMC_ST_MASK                                   0x03
+#define VMMC_ST_SHIFT                                  0
+
+
+/*Register VPLL  (0x80) register.RegisterDescription */
+#define VPLL_SEL_MASK                                  0x0C
+#define VPLL_SEL_SHIFT                                 2
+#define VPLL_ST_MASK                                   0x03
+#define VPLL_ST_SHIFT                                  0
+
+
+/*Register VDAC  (0x80) register.RegisterDescription */
+#define VDAC_SEL_MASK                                  0x0C
+#define VDAC_SEL_SHIFT                                 2
+#define VDAC_ST_MASK                                   0x03
+#define VDAC_ST_SHIFT                                  0
+
+
+/*Register THERM  (0x80) register.RegisterDescription */
+#define THERM_THERM_HD_MASK                            0x20
+#define THERM_THERM_HD_SHIFT                           5
+#define THERM_THERM_TS_MASK                            0x10
+#define THERM_THERM_TS_SHIFT                           4
+#define THERM_THERM_HDSEL_MASK                         0x0C
+#define THERM_THERM_HDSEL_SHIFT                                2
+#define THERM_RSVD1_MASK                               0x02
+#define THERM_RSVD1_SHIFT                              1
+#define THERM_THERM_STATE_MASK                         0x01
+#define THERM_THERM_STATE_SHIFT                                0
+
+
+/*Register BBCH  (0x80) register.RegisterDescription */
+#define BBCH_BBSEL_MASK                                        0x06
+#define BBCH_BBSEL_SHIFT                               1
+#define BBCH_BBCHEN_MASK                               0x01
+#define BBCH_BBCHEN_SHIFT                              0
+
+
+/*Register DCDCCTRL  (0x80) register.RegisterDescription */
+#define DCDCCTRL_VDD2_PSKIP_MASK                       0x20
+#define DCDCCTRL_VDD2_PSKIP_SHIFT                      5
+#define DCDCCTRL_VDD1_PSKIP_MASK                       0x10
+#define DCDCCTRL_VDD1_PSKIP_SHIFT                      4
+#define DCDCCTRL_VIO_PSKIP_MASK                                0x08
+#define DCDCCTRL_VIO_PSKIP_SHIFT                       3
+#define DCDCCTRL_DCDCCKEXT_MASK                                0x04
+#define DCDCCTRL_DCDCCKEXT_SHIFT                       2
+#define DCDCCTRL_DCDCCKSYNC_MASK                       0x03
+#define DCDCCTRL_DCDCCKSYNC_SHIFT                      0
+
+
+/*Register DEVCTRL  (0x80) register.RegisterDescription */
+#define DEVCTRL_RTC_PWDN_MASK                          0x40
+#define DEVCTRL_RTC_PWDN_SHIFT                         6
+#define DEVCTRL_CK32K_CTRL_MASK                                0x20
+#define DEVCTRL_CK32K_CTRL_SHIFT                       5
+#define DEVCTRL_SR_CTL_I2C_SEL_MASK                    0x10
+#define DEVCTRL_SR_CTL_I2C_SEL_SHIFT                   4
+#define DEVCTRL_DEV_OFF_RST_MASK                       0x08
+#define DEVCTRL_DEV_OFF_RST_SHIFT                      3
+#define DEVCTRL_DEV_ON_MASK                            0x04
+#define DEVCTRL_DEV_ON_SHIFT                           2
+#define DEVCTRL_DEV_SLP_MASK                           0x02
+#define DEVCTRL_DEV_SLP_SHIFT                          1
+#define DEVCTRL_DEV_OFF_MASK                           0x01
+#define DEVCTRL_DEV_OFF_SHIFT                          0
+
+
+/*Register DEVCTRL2  (0x80) register.RegisterDescription */
+#define DEVCTRL2_TSLOT_LENGTH_MASK                     0x30
+#define DEVCTRL2_TSLOT_LENGTH_SHIFT                    4
+#define DEVCTRL2_SLEEPSIG_POL_MASK                     0x08
+#define DEVCTRL2_SLEEPSIG_POL_SHIFT                    3
+#define DEVCTRL2_PWON_LP_OFF_MASK                      0x04
+#define DEVCTRL2_PWON_LP_OFF_SHIFT                     2
+#define DEVCTRL2_PWON_LP_RST_MASK                      0x02
+#define DEVCTRL2_PWON_LP_RST_SHIFT                     1
+#define DEVCTRL2_IT_POL_MASK                           0x01
+#define DEVCTRL2_IT_POL_SHIFT                          0
+
+
+/*Register SLEEP_KEEP_LDO_ON  (0x80) register.RegisterDescription */
+#define SLEEP_KEEP_LDO_ON_VDAC_KEEPON_MASK             0x80
+#define SLEEP_KEEP_LDO_ON_VDAC_KEEPON_SHIFT            7
+#define SLEEP_KEEP_LDO_ON_VPLL_KEEPON_MASK             0x40
+#define SLEEP_KEEP_LDO_ON_VPLL_KEEPON_SHIFT            6
+#define SLEEP_KEEP_LDO_ON_VAUX33_KEEPON_MASK           0x20
+#define SLEEP_KEEP_LDO_ON_VAUX33_KEEPON_SHIFT          5
+#define SLEEP_KEEP_LDO_ON_VAUX2_KEEPON_MASK            0x10
+#define SLEEP_KEEP_LDO_ON_VAUX2_KEEPON_SHIFT           4
+#define SLEEP_KEEP_LDO_ON_VAUX1_KEEPON_MASK            0x08
+#define SLEEP_KEEP_LDO_ON_VAUX1_KEEPON_SHIFT           3
+#define SLEEP_KEEP_LDO_ON_VDIG2_KEEPON_MASK            0x04
+#define SLEEP_KEEP_LDO_ON_VDIG2_KEEPON_SHIFT           2
+#define SLEEP_KEEP_LDO_ON_VDIG1_KEEPON_MASK            0x02
+#define SLEEP_KEEP_LDO_ON_VDIG1_KEEPON_SHIFT           1
+#define SLEEP_KEEP_LDO_ON_VMMC_KEEPON_MASK             0x01
+#define SLEEP_KEEP_LDO_ON_VMMC_KEEPON_SHIFT            0
+
+
+/*Register SLEEP_KEEP_RES_ON  (0x80) register.RegisterDescription */
+#define SLEEP_KEEP_RES_ON_THERM_KEEPON_MASK            0x80
+#define SLEEP_KEEP_RES_ON_THERM_KEEPON_SHIFT           7
+#define SLEEP_KEEP_RES_ON_CLKOUT32K_KEEPON_MASK                0x40
+#define SLEEP_KEEP_RES_ON_CLKOUT32K_KEEPON_SHIFT       6
+#define SLEEP_KEEP_RES_ON_VRTC_KEEPON_MASK             0x20
+#define SLEEP_KEEP_RES_ON_VRTC_KEEPON_SHIFT            5
+#define SLEEP_KEEP_RES_ON_I2CHS_KEEPON_MASK            0x10
+#define SLEEP_KEEP_RES_ON_I2CHS_KEEPON_SHIFT           4
+#define SLEEP_KEEP_RES_ON_VDD3_KEEPON_MASK             0x08
+#define SLEEP_KEEP_RES_ON_VDD3_KEEPON_SHIFT            3
+#define SLEEP_KEEP_RES_ON_VDD2_KEEPON_MASK             0x04
+#define SLEEP_KEEP_RES_ON_VDD2_KEEPON_SHIFT            2
+#define SLEEP_KEEP_RES_ON_VDD1_KEEPON_MASK             0x02
+#define SLEEP_KEEP_RES_ON_VDD1_KEEPON_SHIFT            1
+#define SLEEP_KEEP_RES_ON_VIO_KEEPON_MASK              0x01
+#define SLEEP_KEEP_RES_ON_VIO_KEEPON_SHIFT             0
+
+
+/*Register SLEEP_SET_LDO_OFF  (0x80) register.RegisterDescription */
+#define SLEEP_SET_LDO_OFF_VDAC_SETOFF_MASK             0x80
+#define SLEEP_SET_LDO_OFF_VDAC_SETOFF_SHIFT            7
+#define SLEEP_SET_LDO_OFF_VPLL_SETOFF_MASK             0x40
+#define SLEEP_SET_LDO_OFF_VPLL_SETOFF_SHIFT            6
+#define SLEEP_SET_LDO_OFF_VAUX33_SETOFF_MASK           0x20
+#define SLEEP_SET_LDO_OFF_VAUX33_SETOFF_SHIFT          5
+#define SLEEP_SET_LDO_OFF_VAUX2_SETOFF_MASK            0x10
+#define SLEEP_SET_LDO_OFF_VAUX2_SETOFF_SHIFT           4
+#define SLEEP_SET_LDO_OFF_VAUX1_SETOFF_MASK            0x08
+#define SLEEP_SET_LDO_OFF_VAUX1_SETOFF_SHIFT           3
+#define SLEEP_SET_LDO_OFF_VDIG2_SETOFF_MASK            0x04
+#define SLEEP_SET_LDO_OFF_VDIG2_SETOFF_SHIFT           2
+#define SLEEP_SET_LDO_OFF_VDIG1_SETOFF_MASK            0x02
+#define SLEEP_SET_LDO_OFF_VDIG1_SETOFF_SHIFT           1
+#define SLEEP_SET_LDO_OFF_VMMC_SETOFF_MASK             0x01
+#define SLEEP_SET_LDO_OFF_VMMC_SETOFF_SHIFT            0
+
+
+/*Register SLEEP_SET_RES_OFF  (0x80) register.RegisterDescription */
+#define SLEEP_SET_RES_OFF_DEFAULT_VOLT_MASK            0x80
+#define SLEEP_SET_RES_OFF_DEFAULT_VOLT_SHIFT           7
+#define SLEEP_SET_RES_OFF_RSVD_MASK                    0x60
+#define SLEEP_SET_RES_OFF_RSVD_SHIFT                   5
+#define SLEEP_SET_RES_OFF_SPARE_SETOFF_MASK            0x10
+#define SLEEP_SET_RES_OFF_SPARE_SETOFF_SHIFT           4
+#define SLEEP_SET_RES_OFF_VDD3_SETOFF_MASK             0x08
+#define SLEEP_SET_RES_OFF_VDD3_SETOFF_SHIFT            3
+#define SLEEP_SET_RES_OFF_VDD2_SETOFF_MASK             0x04
+#define SLEEP_SET_RES_OFF_VDD2_SETOFF_SHIFT            2
+#define SLEEP_SET_RES_OFF_VDD1_SETOFF_MASK             0x02
+#define SLEEP_SET_RES_OFF_VDD1_SETOFF_SHIFT            1
+#define SLEEP_SET_RES_OFF_VIO_SETOFF_MASK              0x01
+#define SLEEP_SET_RES_OFF_VIO_SETOFF_SHIFT             0
+
+
+/*Register EN1_LDO_ASS (0x80) register.RegisterDescription */
+#define EN1_LDO_ASS_VDAC_EN1_MASK                      0x80
+#define EN1_LDO_ASS_VDAC_EN1_SHIFT                     7
+#define EN1_LDO_ASS_VPLL_EN1_MASK                      0x40
+#define EN1_LDO_ASS_VPLL_EN1_SHIFT                     6
+#define EN1_LDO_ASS_VAUX33_EN1_MASK                    0x20
+#define EN1_LDO_ASS_VAUX33_EN1_SHIFT                   5
+#define EN1_LDO_ASS_VAUX2_EN1_MASK                     0x10
+#define EN1_LDO_ASS_VAUX2_EN1_SHIFT                    4
+#define EN1_LDO_ASS_VAUX1_EN1_MASK                     0x08
+#define EN1_LDO_ASS_VAUX1_EN1_SHIFT                    3
+#define EN1_LDO_ASS_VDIG2_EN1_MASK                     0x04
+#define EN1_LDO_ASS_VDIG2_EN1_SHIFT                    2
+#define EN1_LDO_ASS_VDIG1_EN1_MASK                     0x02
+#define EN1_LDO_ASS_VDIG1_EN1_SHIFT                    1
+#define EN1_LDO_ASS_VMMC_EN1_MASK                      0x01
+#define EN1_LDO_ASS_VMMC_EN1_SHIFT                     0
+
+
+/*Register EN1_SMPS_ASS  (0x80) register.RegisterDescription */
+#define EN1_SMPS_ASS_RSVD_MASK                         0xE0
+#define EN1_SMPS_ASS_RSVD_SHIFT                                5
+#define EN1_SMPS_ASS_SPARE_EN1_MASK                    0x10
+#define EN1_SMPS_ASS_SPARE_EN1_SHIFT                   4
+#define EN1_SMPS_ASS_VDD3_EN1_MASK                     0x08
+#define EN1_SMPS_ASS_VDD3_EN1_SHIFT                    3
+#define EN1_SMPS_ASS_VDD2_EN1_MASK                     0x04
+#define EN1_SMPS_ASS_VDD2_EN1_SHIFT                    2
+#define EN1_SMPS_ASS_VDD1_EN1_MASK                     0x02
+#define EN1_SMPS_ASS_VDD1_EN1_SHIFT                    1
+#define EN1_SMPS_ASS_VIO_EN1_MASK                      0x01
+#define EN1_SMPS_ASS_VIO_EN1_SHIFT                     0
+
+
+/*Register EN2_LDO_ASS (0x80) register.RegisterDescription */
+#define EN2_LDO_ASS_VDAC_EN2_MASK                      0x80
+#define EN2_LDO_ASS_VDAC_EN2_SHIFT                     7
+#define EN2_LDO_ASS_VPLL_EN2_MASK                      0x40
+#define EN2_LDO_ASS_VPLL_EN2_SHIFT                     6
+#define EN2_LDO_ASS_VAUX33_EN2_MASK                    0x20
+#define EN2_LDO_ASS_VAUX33_EN2_SHIFT                   5
+#define EN2_LDO_ASS_VAUX2_EN2_MASK                     0x10
+#define EN2_LDO_ASS_VAUX2_EN2_SHIFT                    4
+#define EN2_LDO_ASS_VAUX1_EN2_MASK                     0x08
+#define EN2_LDO_ASS_VAUX1_EN2_SHIFT                    3
+#define EN2_LDO_ASS_VDIG2_EN2_MASK                     0x04
+#define EN2_LDO_ASS_VDIG2_EN2_SHIFT                    2
+#define EN2_LDO_ASS_VDIG1_EN2_MASK                     0x02
+#define EN2_LDO_ASS_VDIG1_EN2_SHIFT                    1
+#define EN2_LDO_ASS_VMMC_EN2_MASK                      0x01
+#define EN2_LDO_ASS_VMMC_EN2_SHIFT                     0
+
+
+/*Register EN2_SMPS_ASS  (0x80) register.RegisterDescription */
+#define EN2_SMPS_ASS_RSVD_MASK                         0xE0
+#define EN2_SMPS_ASS_RSVD_SHIFT                                5
+#define EN2_SMPS_ASS_SPARE_EN2_MASK                    0x10
+#define EN2_SMPS_ASS_SPARE_EN2_SHIFT                   4
+#define EN2_SMPS_ASS_VDD3_EN2_MASK                     0x08
+#define EN2_SMPS_ASS_VDD3_EN2_SHIFT                    3
+#define EN2_SMPS_ASS_VDD2_EN2_MASK                     0x04
+#define EN2_SMPS_ASS_VDD2_EN2_SHIFT                    2
+#define EN2_SMPS_ASS_VDD1_EN2_MASK                     0x02
+#define EN2_SMPS_ASS_VDD1_EN2_SHIFT                    1
+#define EN2_SMPS_ASS_VIO_EN2_MASK                      0x01
+#define EN2_SMPS_ASS_VIO_EN2_SHIFT                     0
+
+
+/*Register EN3_LDO_ASS (0x80) register.RegisterDescription */
+#define EN3_LDO_ASS_VDAC_EN3_MASK                      0x80
+#define EN3_LDO_ASS_VDAC_EN3_SHIFT                     7
+#define EN3_LDO_ASS_VPLL_EN3_MASK                      0x40
+#define EN3_LDO_ASS_VPLL_EN3_SHIFT                     6
+#define EN3_LDO_ASS_VAUX33_EN3_MASK                    0x20
+#define EN3_LDO_ASS_VAUX33_EN3_SHIFT                   5
+#define EN3_LDO_ASS_VAUX2_EN3_MASK                     0x10
+#define EN3_LDO_ASS_VAUX2_EN3_SHIFT                    4
+#define EN3_LDO_ASS_VAUX1_EN3_MASK                     0x08
+#define EN3_LDO_ASS_VAUX1_EN3_SHIFT                    3
+#define EN3_LDO_ASS_VDIG2_EN3_MASK                     0x04
+#define EN3_LDO_ASS_VDIG2_EN3_SHIFT                    2
+#define EN3_LDO_ASS_VDIG1_EN3_MASK                     0x02
+#define EN3_LDO_ASS_VDIG1_EN3_SHIFT                    1
+#define EN3_LDO_ASS_VMMC_EN3_MASK                      0x01
+#define EN3_LDO_ASS_VMMC_EN3_SHIFT                     0
+
+
+/*Register SPARE  (0x80) register.RegisterDescription */
+#define SPARE_SPARE_MASK                               0xFF
+#define SPARE_SPARE_SHIFT                              0
+
+
+/*Register INT_STS  (0x80) register.RegisterDescription */
+#define INT_STS_RTC_PERIOD_IT_MASK                     0x80
+#define INT_STS_RTC_PERIOD_IT_SHIFT                    7
+#define INT_STS_RTC_ALARM_IT_MASK                      0x40
+#define INT_STS_RTC_ALARM_IT_SHIFT                     6
+#define INT_STS_HOTDIE_IT_MASK                         0x20
+#define INT_STS_HOTDIE_IT_SHIFT                                5
+#define INT_STS_PWRHOLD_IT_MASK                                0x10
+#define INT_STS_PWRHOLD_IT_SHIFT                       4
+#define INT_STS_PWRON_LP_IT_MASK                       0x08
+#define INT_STS_PWRON_LP_IT_SHIFT                      3
+#define INT_STS_PWRON_IT_MASK                          0x04
+#define INT_STS_PWRON_IT_SHIFT                         2
+#define INT_STS_VMBHI_IT_MASK                          0x02
+#define INT_STS_VMBHI_IT_SHIFT                         1
+#define INT_STS_VMBDCH_IT_MASK                         0x01
+#define INT_STS_VMBDCH_IT_SHIFT                                0
+
+
+/*Register INT_MSK  (0x80) register.RegisterDescription */
+#define INT_MSK_RTC_PERIOD_IT_MSK_MASK                 0x80
+#define INT_MSK_RTC_PERIOD_IT_MSK_SHIFT                        7
+#define INT_MSK_RTC_ALARM_IT_MSK_MASK                  0x40
+#define INT_MSK_RTC_ALARM_IT_MSK_SHIFT                 6
+#define INT_MSK_HOTDIE_IT_MSK_MASK                     0x20
+#define INT_MSK_HOTDIE_IT_MSK_SHIFT                    5
+#define INT_MSK_PWRHOLD_IT_MSK_MASK                    0x10
+#define INT_MSK_PWRHOLD_IT_MSK_SHIFT                   4
+#define INT_MSK_PWRON_LP_IT_MSK_MASK                   0x08
+#define INT_MSK_PWRON_LP_IT_MSK_SHIFT                  3
+#define INT_MSK_PWRON_IT_MSK_MASK                      0x04
+#define INT_MSK_PWRON_IT_MSK_SHIFT                     2
+#define INT_MSK_VMBHI_IT_MSK_MASK                      0x02
+#define INT_MSK_VMBHI_IT_MSK_SHIFT                     1
+#define INT_MSK_VMBDCH_IT_MSK_MASK                     0x01
+#define INT_MSK_VMBDCH_IT_MSK_SHIFT                    0
+
+
+/*Register INT_STS2  (0x80) register.RegisterDescription */
+#define INT_STS2_GPIO3_F_IT_MASK                       0x80
+#define INT_STS2_GPIO3_F_IT_SHIFT                      7
+#define INT_STS2_GPIO3_R_IT_MASK                       0x40
+#define INT_STS2_GPIO3_R_IT_SHIFT                      6
+#define INT_STS2_GPIO2_F_IT_MASK                       0x20
+#define INT_STS2_GPIO2_F_IT_SHIFT                      5
+#define INT_STS2_GPIO2_R_IT_MASK                       0x10
+#define INT_STS2_GPIO2_R_IT_SHIFT                      4
+#define INT_STS2_GPIO1_F_IT_MASK                       0x08
+#define INT_STS2_GPIO1_F_IT_SHIFT                      3
+#define INT_STS2_GPIO1_R_IT_MASK                       0x04
+#define INT_STS2_GPIO1_R_IT_SHIFT                      2
+#define INT_STS2_GPIO0_F_IT_MASK                       0x02
+#define INT_STS2_GPIO0_F_IT_SHIFT                      1
+#define INT_STS2_GPIO0_R_IT_MASK                       0x01
+#define INT_STS2_GPIO0_R_IT_SHIFT                      0
+
+
+/*Register INT_MSK2  (0x80) register.RegisterDescription */
+#define INT_MSK2_GPIO3_F_IT_MSK_MASK                   0x80
+#define INT_MSK2_GPIO3_F_IT_MSK_SHIFT                  7
+#define INT_MSK2_GPIO3_R_IT_MSK_MASK                   0x40
+#define INT_MSK2_GPIO3_R_IT_MSK_SHIFT                  6
+#define INT_MSK2_GPIO2_F_IT_MSK_MASK                   0x20
+#define INT_MSK2_GPIO2_F_IT_MSK_SHIFT                  5
+#define INT_MSK2_GPIO2_R_IT_MSK_MASK                   0x10
+#define INT_MSK2_GPIO2_R_IT_MSK_SHIFT                  4
+#define INT_MSK2_GPIO1_F_IT_MSK_MASK                   0x08
+#define INT_MSK2_GPIO1_F_IT_MSK_SHIFT                  3
+#define INT_MSK2_GPIO1_R_IT_MSK_MASK                   0x04
+#define INT_MSK2_GPIO1_R_IT_MSK_SHIFT                  2
+#define INT_MSK2_GPIO0_F_IT_MSK_MASK                   0x02
+#define INT_MSK2_GPIO0_F_IT_MSK_SHIFT                  1
+#define INT_MSK2_GPIO0_R_IT_MSK_MASK                   0x01
+#define INT_MSK2_GPIO0_R_IT_MSK_SHIFT                  0
+
+
+/*Register INT_STS3  (0x80) register.RegisterDescription */
+#define INT_STS3_GPIO5_F_IT_MASK                       0x08
+#define INT_STS3_GPIO5_F_IT_SHIFT                      3
+#define INT_STS3_GPIO5_R_IT_MASK                       0x04
+#define INT_STS3_GPIO5_R_IT_SHIFT                      2
+#define INT_STS3_GPIO4_F_IT_MASK                       0x02
+#define INT_STS3_GPIO4_F_IT_SHIFT                      1
+#define INT_STS3_GPIO4_R_IT_MASK                       0x01
+#define INT_STS3_GPIO4_R_IT_SHIFT                      0
+
+
+/*Register INT_MSK3  (0x80) register.RegisterDescription */
+#define INT_MSK3_GPIO5_F_IT_MSK_MASK                   0x08
+#define INT_MSK3_GPIO5_F_IT_MSK_SHIFT                  3
+#define INT_MSK3_GPIO5_R_IT_MSK_MASK                   0x04
+#define INT_MSK3_GPIO5_R_IT_MSK_SHIFT                  2
+#define INT_MSK3_GPIO4_F_IT_MSK_MASK                   0x02
+#define INT_MSK3_GPIO4_F_IT_MSK_SHIFT                  1
+#define INT_MSK3_GPIO4_R_IT_MSK_MASK                   0x01
+#define INT_MSK3_GPIO4_R_IT_MSK_SHIFT                  0
+
+
+/*Register GPIO  (0x80) register.RegisterDescription */
+#define GPIO_DEB_MASK                           0x10
+#define GPIO_DEB_SHIFT                          4
+#define GPIO_PUEN_MASK                          0x08
+#define GPIO_PUEN_SHIFT                         3
+#define GPIO_CFG_MASK                           0x04
+#define GPIO_CFG_SHIFT                          2
+#define GPIO_STS_MASK                           0x02
+#define GPIO_STS_SHIFT                          1
+#define GPIO_SET_MASK                           0x01
+#define GPIO_SET_SHIFT                          0
+
+
+/*Register JTAGVERNUM  (0x80) register.RegisterDescription */
+#define JTAGVERNUM_VERNUM_MASK                         0x0F
+#define JTAGVERNUM_VERNUM_SHIFT                                0
+
+
+/* Register VDDCTRL (0x27) bit definitions */
+#define VDDCTRL_ST_MASK                                  0x03
+#define VDDCTRL_ST_SHIFT                                 0
+
+
+/*Register VDDCTRL_OP  (0x28) bit definitios */
+#define VDDCTRL_OP_CMD_MASK                              0x80
+#define VDDCTRL_OP_CMD_SHIFT                             7
+#define VDDCTRL_OP_SEL_MASK                              0x7F
+#define VDDCTRL_OP_SEL_SHIFT                             0
+
+
+/*Register VDDCTRL_SR  (0x29) bit definitions */
+#define VDDCTRL_SR_SEL_MASK                              0x7F
+#define VDDCTRL_SR_SEL_SHIFT                             0
+
+
+/* IRQ Definitions */
+#define TPS65910_IRQ_VBAT_VMBDCH                       0
+#define TPS65910_IRQ_VBAT_VMHI                         1
+#define TPS65910_IRQ_PWRON                             2
+#define TPS65910_IRQ_PWRON_LP                          3
+#define TPS65910_IRQ_PWRHOLD                           4
+#define TPS65910_IRQ_HOTDIE                            5
+#define TPS65910_IRQ_RTC_ALARM                         6
+#define TPS65910_IRQ_RTC_PERIOD                                7
+#define TPS65910_IRQ_GPIO_R                            8
+#define TPS65910_IRQ_GPIO_F                            9
+#define TPS65910_NUM_IRQ                               10
+
+#define TPS65911_IRQ_VBAT_VMBDCH                       0
+#define TPS65911_IRQ_VBAT_VMBDCH2L                     1
+#define TPS65911_IRQ_VBAT_VMBDCH2H                     2
+#define TPS65911_IRQ_VBAT_VMHI                         3
+#define TPS65911_IRQ_PWRON                             4
+#define TPS65911_IRQ_PWRON_LP                          5
+#define TPS65911_IRQ_PWRHOLD_F                         6
+#define TPS65911_IRQ_PWRHOLD_R                         7
+#define TPS65911_IRQ_HOTDIE                            8
+#define TPS65911_IRQ_RTC_ALARM                         9
+#define TPS65911_IRQ_RTC_PERIOD                                10
+#define TPS65911_IRQ_GPIO0_R                           11
+#define TPS65911_IRQ_GPIO0_F                           12
+#define TPS65911_IRQ_GPIO1_R                           13
+#define TPS65911_IRQ_GPIO1_F                           14
+#define TPS65911_IRQ_GPIO2_R                           15
+#define TPS65911_IRQ_GPIO2_F                           16
+#define TPS65911_IRQ_GPIO3_R                           17
+#define TPS65911_IRQ_GPIO3_F                           18
+#define TPS65911_IRQ_GPIO4_R                           19
+#define TPS65911_IRQ_GPIO4_F                           20
+#define TPS65911_IRQ_GPIO5_R                           21
+#define TPS65911_IRQ_GPIO5_F                           22
+#define TPS65911_IRQ_WTCHDG                            23
+#define TPS65911_IRQ_PWRDN                             24
+
+#define TPS65911_NUM_IRQ                               25
+
+
+/* GPIO Register Definitions */
+#define TPS65910_GPIO_DEB                              BIT(2)
+#define TPS65910_GPIO_PUEN                             BIT(3)
+#define TPS65910_GPIO_CFG                              BIT(2)
+#define TPS65910_GPIO_STS                              BIT(1)
+#define TPS65910_GPIO_SET                              BIT(0)
+
+/**
+ * struct tps65910_board
+ * Board platform data may be used to initialize regulators.
+ */
+
+struct tps65910_board {
+       int gpio_base;
+       int irq;
+       int irq_base;
+       int vmbch_threshold;
+       int vmbch2_threshold;
+       struct regulator_init_data *tps65910_pmic_init_data;
+};
+
+/**
+ * struct tps65910 - tps65910 sub-driver chip access routines
+ */
+
+struct tps65910 {
+       struct device *dev;
+       struct i2c_client *i2c_client;
+       struct mutex io_mutex;
+       unsigned int id;
+       int (*read)(struct tps65910 *tps65910, u8 reg, int size, void *dest);
+       int (*write)(struct tps65910 *tps65910, u8 reg, int size, void *src);
+
+       /* Client devices */
+       struct tps65910_pmic *pmic;
+       struct tps65910_rtc *rtc;
+       struct tps65910_power *power;
+
+       /* GPIO Handling */
+       struct gpio_chip gpio;
+
+       /* IRQ Handling */
+       struct mutex irq_lock;
+       int chip_irq;
+       int irq_base;
+       int irq_num;
+       u32 irq_mask;
+};
+
+struct tps65910_platform_data {
+       int irq;
+       int irq_base;
+};
+
+int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask);
+int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask);
+void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base);
+int tps65910_irq_init(struct tps65910 *tps65910, int irq,
+               struct tps65910_platform_data *pdata);
+
+static inline int tps65910_chip_id(struct tps65910 *tps65910)
+{
+       return tps65910->id;
+}
+
+#endif /*  __LINUX_MFD_TPS65910_H */
index 2ec317c68e59acf6769775ae9c24b1bfddefd59f..5cc16bbd1da1a855aaa924f25f1a6f0c716f97d5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * MFD driver for twl4030 codec submodule
  *
- * Author:     Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * Copyright:   (C) 2009 Nokia Corporation
  *
index 903280d21866a9ae690c37bb7f57537a4d61ae95..0d515ee1c24747319b561f0f0bda98dd1e50903e 100644 (file)
@@ -301,30 +301,4 @@ int wm831x_device_suspend(struct wm831x *wm831x);
 int wm831x_irq_init(struct wm831x *wm831x, int irq);
 void wm831x_irq_exit(struct wm831x *wm831x);
 
-static inline int __must_check wm831x_request_irq(struct wm831x *wm831x,
-                                                 unsigned int irq,
-                                                 irq_handler_t handler,
-                                                 unsigned long flags,
-                                                 const char *name,
-                                                 void *dev)
-{
-       return request_threaded_irq(irq, NULL, handler, flags, name, dev);
-}
-
-static inline void wm831x_free_irq(struct wm831x *wm831x,
-                                  unsigned int irq, void *dev)
-{
-       free_irq(irq, dev);
-}
-
-static inline void wm831x_disable_irq(struct wm831x *wm831x, int irq)
-{
-       disable_irq(irq);
-}
-
-static inline void wm831x_enable_irq(struct wm831x *wm831x, int irq)
-{
-       enable_irq(irq);
-}
-
 #endif
index 632d1567a1b676f4c74dfeec798951081fed108c..ff42d700293fc71485d80f092c978fd633919b27 100644 (file)
@@ -105,6 +105,9 @@ struct wm831x_watchdog_pdata {
 #define WM831X_MAX_LDO    11
 #define WM831X_MAX_ISINK  2
 
+#define WM831X_GPIO_CONFIGURE 0x10000
+#define WM831X_GPIO_NUM 16
+
 struct wm831x_pdata {
        /** Used to distinguish multiple WM831x chips */
        int wm831x_num;
@@ -119,6 +122,7 @@ struct wm831x_pdata {
 
        int irq_base;
        int gpio_base;
+       int gpio_defaults[WM831X_GPIO_NUM];
        struct wm831x_backlight_pdata *backlight;
        struct wm831x_backup_pdata *backup;
        struct wm831x_battery_pdata *battery;
index 6507dde38b16602a1b819492088f6ce5ea8fba40..9670f71d7be961bbe56e9c1701f475bc4be7981c 100644 (file)
@@ -153,6 +153,7 @@ extern pgprot_t protection_map[16];
 #define FAULT_FLAG_MKWRITE     0x04    /* Fault was mkwrite of existing pte */
 #define FAULT_FLAG_ALLOW_RETRY 0x08    /* Retry fault if blocking */
 #define FAULT_FLAG_RETRY_NOWAIT        0x10    /* Don't drop mmap_sem and wait when retrying */
+#define FAULT_FLAG_KILLABLE    0x20    /* The fault task is in SIGKILL killable region */
 
 /*
  * This interface is used by x86 PAT code to identify a pfn mapping that is
@@ -164,12 +165,12 @@ extern pgprot_t protection_map[16];
  */
 static inline int is_linear_pfn_mapping(struct vm_area_struct *vma)
 {
-       return (vma->vm_flags & VM_PFN_AT_MMAP);
+       return !!(vma->vm_flags & VM_PFN_AT_MMAP);
 }
 
 static inline int is_pfn_mapping(struct vm_area_struct *vma)
 {
-       return (vma->vm_flags & VM_PFNMAP);
+       return !!(vma->vm_flags & VM_PFNMAP);
 }
 
 /*
@@ -604,10 +605,6 @@ static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma)
 #define NODE_NOT_IN_PAGE_FLAGS
 #endif
 
-#ifndef PFN_SECTION_SHIFT
-#define PFN_SECTION_SHIFT 0
-#endif
-
 /*
  * Define the bit shifts to access each section.  For non-existent
  * sections we define the shift as 0; that plus a 0 mask ensures
@@ -681,6 +678,12 @@ static inline struct zone *page_zone(struct page *page)
 }
 
 #if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
+static inline void set_page_section(struct page *page, unsigned long section)
+{
+       page->flags &= ~(SECTIONS_MASK << SECTIONS_PGSHIFT);
+       page->flags |= (section & SECTIONS_MASK) << SECTIONS_PGSHIFT;
+}
+
 static inline unsigned long page_to_section(struct page *page)
 {
        return (page->flags >> SECTIONS_PGSHIFT) & SECTIONS_MASK;
@@ -699,18 +702,14 @@ static inline void set_page_node(struct page *page, unsigned long node)
        page->flags |= (node & NODES_MASK) << NODES_PGSHIFT;
 }
 
-static inline void set_page_section(struct page *page, unsigned long section)
-{
-       page->flags &= ~(SECTIONS_MASK << SECTIONS_PGSHIFT);
-       page->flags |= (section & SECTIONS_MASK) << SECTIONS_PGSHIFT;
-}
-
 static inline void set_page_links(struct page *page, enum zone_type zone,
        unsigned long node, unsigned long pfn)
 {
        set_page_zone(page, zone);
        set_page_node(page, node);
+#if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
        set_page_section(page, pfn_to_section_nr(pfn));
+#endif
 }
 
 /*
@@ -862,26 +861,18 @@ extern void pagefault_out_of_memory(void);
 #define offset_in_page(p)      ((unsigned long)(p) & ~PAGE_MASK)
 
 /*
- * Flags passed to show_mem() and __show_free_areas() to suppress output in
+ * Flags passed to show_mem() and show_free_areas() to suppress output in
  * various contexts.
  */
 #define SHOW_MEM_FILTER_NODES  (0x0001u)       /* filter disallowed nodes */
 
-extern void show_free_areas(void);
-extern void __show_free_areas(unsigned int flags);
+extern void show_free_areas(unsigned int flags);
+extern bool skip_free_areas_node(unsigned int flags, int nid);
 
 int shmem_lock(struct file *file, int lock, struct user_struct *user);
 struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags);
 int shmem_zero_setup(struct vm_area_struct *);
 
-#ifndef CONFIG_MMU
-extern unsigned long shmem_get_unmapped_area(struct file *file,
-                                            unsigned long addr,
-                                            unsigned long len,
-                                            unsigned long pgoff,
-                                            unsigned long flags);
-#endif
-
 extern int can_do_mlock(void);
 extern int user_shm_lock(size_t, struct user_struct *);
 extern void user_shm_unlock(size_t, struct user_struct *);
@@ -894,8 +885,6 @@ struct zap_details {
        struct address_space *check_mapping;    /* Check page->mapping if set */
        pgoff_t first_index;                    /* Lowest page->index to unmap */
        pgoff_t last_index;                     /* Highest page->index to unmap */
-       spinlock_t *i_mmap_lock;                /* For unmap_mapping_range: */
-       unsigned long truncate_count;           /* Compare vm_truncate_count */
 };
 
 struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr,
@@ -905,7 +894,7 @@ int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address,
                unsigned long size);
 unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address,
                unsigned long size, struct zap_details *);
-unsigned long unmap_vmas(struct mmu_gather **tlb,
+unsigned long unmap_vmas(struct mmu_gather *tlb,
                struct vm_area_struct *start_vma, unsigned long start_addr,
                unsigned long end_addr, unsigned long *nr_accounted,
                struct zap_details *);
@@ -1056,65 +1045,35 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
 /*
  * per-process(per-mm_struct) statistics.
  */
-#if defined(SPLIT_RSS_COUNTING)
-/*
- * The mm counters are not protected by its page_table_lock,
- * so must be incremented atomically.
- */
 static inline void set_mm_counter(struct mm_struct *mm, int member, long value)
 {
        atomic_long_set(&mm->rss_stat.count[member], value);
 }
 
+#if defined(SPLIT_RSS_COUNTING)
 unsigned long get_mm_counter(struct mm_struct *mm, int member);
-
-static inline void add_mm_counter(struct mm_struct *mm, int member, long value)
-{
-       atomic_long_add(value, &mm->rss_stat.count[member]);
-}
-
-static inline void inc_mm_counter(struct mm_struct *mm, int member)
-{
-       atomic_long_inc(&mm->rss_stat.count[member]);
-}
-
-static inline void dec_mm_counter(struct mm_struct *mm, int member)
-{
-       atomic_long_dec(&mm->rss_stat.count[member]);
-}
-
-#else  /* !USE_SPLIT_PTLOCKS */
-/*
- * The mm counters are protected by its page_table_lock,
- * so can be incremented directly.
- */
-static inline void set_mm_counter(struct mm_struct *mm, int member, long value)
-{
-       mm->rss_stat.count[member] = value;
-}
-
+#else
 static inline unsigned long get_mm_counter(struct mm_struct *mm, int member)
 {
-       return mm->rss_stat.count[member];
+       return atomic_long_read(&mm->rss_stat.count[member]);
 }
+#endif
 
 static inline void add_mm_counter(struct mm_struct *mm, int member, long value)
 {
-       mm->rss_stat.count[member] += value;
+       atomic_long_add(value, &mm->rss_stat.count[member]);
 }
 
 static inline void inc_mm_counter(struct mm_struct *mm, int member)
 {
-       mm->rss_stat.count[member]++;
+       atomic_long_inc(&mm->rss_stat.count[member]);
 }
 
 static inline void dec_mm_counter(struct mm_struct *mm, int member)
 {
-       mm->rss_stat.count[member]--;
+       atomic_long_dec(&mm->rss_stat.count[member]);
 }
 
-#endif /* !USE_SPLIT_PTLOCKS */
-
 static inline unsigned long get_mm_rss(struct mm_struct *mm)
 {
        return get_mm_counter(mm, MM_FILEPAGES) +
@@ -1162,14 +1121,25 @@ static inline void sync_mm_rss(struct task_struct *task, struct mm_struct *mm)
 }
 #endif
 
+/*
+ * This struct is used to pass information from page reclaim to the shrinkers.
+ * We consolidate the values for easier extention later.
+ */
+struct shrink_control {
+       gfp_t gfp_mask;
+
+       /* How many slab objects shrinker() should scan and try to reclaim */
+       unsigned long nr_to_scan;
+};
+
 /*
  * A callback you can register to apply pressure to ageable caches.
  *
- * 'shrink' is passed a count 'nr_to_scan' and a 'gfpmask'.  It should
- * look through the least-recently-used 'nr_to_scan' entries and
- * attempt to free them up.  It should return the number of objects
- * which remain in the cache.  If it returns -1, it means it cannot do
- * any scanning at this time (eg. there is a risk of deadlock).
+ * 'sc' is passed shrink_control which includes a count 'nr_to_scan'
+ * and a 'gfpmask'.  It should look through the least-recently-used
+ * 'nr_to_scan' entries and attempt to free them up.  It should return
+ * the number of objects which remain in the cache.  If it returns -1, it means
+ * it cannot do any scanning at this time (eg. there is a risk of deadlock).
  *
  * The 'gfpmask' refers to the allocation we are currently trying to
  * fulfil.
@@ -1178,7 +1148,7 @@ static inline void sync_mm_rss(struct task_struct *task, struct mm_struct *mm)
  * querying the cache size, so a fastpath for that case is appropriate.
  */
 struct shrinker {
-       int (*shrink)(struct shrinker *, int nr_to_scan, gfp_t gfp_mask);
+       int (*shrink)(struct shrinker *, struct shrink_control *sc);
        int seeks;      /* seeks to recreate an obj */
 
        /* These are for internal use */
@@ -1380,7 +1350,7 @@ extern void set_dma_reserve(unsigned long new_dma_reserve);
 extern void memmap_init_zone(unsigned long, int, unsigned long,
                                unsigned long, enum memmap_context);
 extern void setup_per_zone_wmarks(void);
-extern void calculate_zone_inactive_ratio(struct zone *zone);
+extern int __meminit init_per_zone_wmark_min(void);
 extern void mem_init(void);
 extern void __init mmap_init(void);
 extern void show_mem(unsigned int flags);
@@ -1388,6 +1358,8 @@ extern void si_meminfo(struct sysinfo * val);
 extern void si_meminfo_node(struct sysinfo *val, int nid);
 extern int after_bootmem;
 
+extern void warn_alloc_failed(gfp_t gfp_mask, int order, const char *fmt, ...);
+
 extern void setup_per_cpu_pageset(void);
 
 extern void zone_pcp_update(struct zone *zone);
@@ -1436,17 +1408,11 @@ extern void exit_mmap(struct mm_struct *);
 extern int mm_take_all_locks(struct mm_struct *mm);
 extern void mm_drop_all_locks(struct mm_struct *mm);
 
-#ifdef CONFIG_PROC_FS
 /* From fs/proc/base.c. callers must _not_ hold the mm's exe_file_lock */
 extern void added_exe_file_vma(struct mm_struct *mm);
 extern void removed_exe_file_vma(struct mm_struct *mm);
-#else
-static inline void added_exe_file_vma(struct mm_struct *mm)
-{}
-
-static inline void removed_exe_file_vma(struct mm_struct *mm)
-{}
-#endif /* CONFIG_PROC_FS */
+extern void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file);
+extern struct file *get_mm_exe_file(struct mm_struct *mm);
 
 extern int may_expand_vm(struct mm_struct *mm, unsigned long npages);
 extern int install_special_mapping(struct mm_struct *mm,
@@ -1460,7 +1426,7 @@ extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
        unsigned long flag, unsigned long pgoff);
 extern unsigned long mmap_region(struct file *file, unsigned long addr,
        unsigned long len, unsigned long flags,
-       unsigned int vm_flags, unsigned long pgoff);
+       vm_flags_t vm_flags, unsigned long pgoff);
 
 static inline unsigned long do_mmap(struct file *file, unsigned long addr,
        unsigned long len, unsigned long prot,
@@ -1517,15 +1483,17 @@ unsigned long ra_submit(struct file_ra_state *ra,
                        struct address_space *mapping,
                        struct file *filp);
 
-/* Do stack extension */
+/* Generic expand stack which grows the stack according to GROWS{UP,DOWN} */
 extern int expand_stack(struct vm_area_struct *vma, unsigned long address);
+
+/* CONFIG_STACK_GROWSUP still needs to to grow downwards at some places */
+extern int expand_downwards(struct vm_area_struct *vma,
+               unsigned long address);
 #if VM_GROWSUP
 extern int expand_upwards(struct vm_area_struct *vma, unsigned long address);
 #else
   #define expand_upwards(vma, address) do { } while (0)
 #endif
-extern int expand_stack_downwards(struct vm_area_struct *vma,
-                                 unsigned long address);
 
 /* Look up the first VMA which satisfies  addr < vm_end,  NULL if none. */
 extern struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr);
@@ -1627,8 +1595,9 @@ int in_gate_area_no_mm(unsigned long addr);
 
 int drop_caches_sysctl_handler(struct ctl_table *, int,
                                        void __user *, size_t *, loff_t *);
-unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
-                       unsigned long lru_pages);
+unsigned long shrink_slab(struct shrink_control *shrink,
+                         unsigned long nr_pages_scanned,
+                         unsigned long lru_pages);
 
 #ifndef CONFIG_MMU
 #define randomize_va_space 0
index 02aa5619709b9bab0a40d183fc3b0b017b8bd50c..027935c86c688df2315d7ea4862d2c8e233ab8aa 100644 (file)
@@ -102,6 +102,8 @@ struct page {
 #endif
 };
 
+typedef unsigned long __nocast vm_flags_t;
+
 /*
  * A region containing a mapping of a non-memory backed file under NOMMU
  * conditions.  These are held in a global tree and are pinned by the VMAs that
@@ -109,7 +111,7 @@ struct page {
  */
 struct vm_region {
        struct rb_node  vm_rb;          /* link in global region tree */
-       unsigned long   vm_flags;       /* VMA vm_flags */
+       vm_flags_t      vm_flags;       /* VMA vm_flags */
        unsigned long   vm_start;       /* start address of region */
        unsigned long   vm_end;         /* region initialised to here */
        unsigned long   vm_top;         /* region allocated to here */
@@ -175,7 +177,6 @@ struct vm_area_struct {
                                           units, *not* PAGE_CACHE_SIZE */
        struct file * vm_file;          /* File we map to (can be NULL). */
        void * vm_private_data;         /* was vm_pte (shared mem) */
-       unsigned long vm_truncate_count;/* truncate_count or restart_addr */
 
 #ifndef CONFIG_MMU
        struct vm_region *vm_region;    /* NOMMU mapping region */
@@ -205,19 +206,16 @@ enum {
 
 #if USE_SPLIT_PTLOCKS && defined(CONFIG_MMU)
 #define SPLIT_RSS_COUNTING
-struct mm_rss_stat {
-       atomic_long_t count[NR_MM_COUNTERS];
-};
 /* per-thread cached information, */
 struct task_rss_stat {
        int events;     /* for synchronization threshold */
        int count[NR_MM_COUNTERS];
 };
-#else  /* !USE_SPLIT_PTLOCKS */
+#endif /* USE_SPLIT_PTLOCKS */
+
 struct mm_rss_stat {
-       unsigned long count[NR_MM_COUNTERS];
+       atomic_long_t count[NR_MM_COUNTERS];
 };
-#endif /* !USE_SPLIT_PTLOCKS */
 
 struct mm_struct {
        struct vm_area_struct * mmap;           /* list of VMAs */
@@ -266,7 +264,7 @@ struct mm_struct {
 
        struct linux_binfmt *binfmt;
 
-       cpumask_t cpu_vm_mask;
+       cpumask_var_t cpu_vm_mask_var;
 
        /* Architecture-specific MM context */
        mm_context_t context;
@@ -306,20 +304,31 @@ struct mm_struct {
        struct task_struct __rcu *owner;
 #endif
 
-#ifdef CONFIG_PROC_FS
        /* store ref to file /proc/<pid>/exe symlink points to */
        struct file *exe_file;
        unsigned long num_exe_file_vmas;
-#endif
 #ifdef CONFIG_MMU_NOTIFIER
        struct mmu_notifier_mm *mmu_notifier_mm;
 #endif
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
        pgtable_t pmd_huge_pte; /* protected by page_table_lock */
 #endif
+#ifdef CONFIG_CPUMASK_OFFSTACK
+       struct cpumask cpumask_allocation;
+#endif
 };
 
+static inline void mm_init_cpumask(struct mm_struct *mm)
+{
+#ifdef CONFIG_CPUMASK_OFFSTACK
+       mm->cpu_vm_mask_var = &mm->cpumask_allocation;
+#endif
+}
+
 /* Future-safe accessor for struct mm_struct's cpu_vm_mask. */
-#define mm_cpumask(mm) (&(mm)->cpu_vm_mask)
+static inline cpumask_t *mm_cpumask(struct mm_struct *mm)
+{
+       return mm->cpu_vm_mask_var;
+}
 
 #endif /* _LINUX_MM_TYPES_H */
diff --git a/include/linux/mmc/Kbuild b/include/linux/mmc/Kbuild
new file mode 100644 (file)
index 0000000..1fb2644
--- /dev/null
@@ -0,0 +1 @@
+header-y += ioctl.h
index adb4888248be9a06219f71f39dceb06c60edd15d..c6927a4d157fd3cfb9f4a963065353c730364b99 100644 (file)
@@ -11,6 +11,7 @@
 #define LINUX_MMC_CARD_H
 
 #include <linux/mmc/core.h>
+#include <linux/mod_devicetable.h>
 
 struct mmc_cid {
        unsigned int            manfid;
@@ -29,6 +30,7 @@ struct mmc_csd {
        unsigned short          cmdclass;
        unsigned short          tacc_clks;
        unsigned int            tacc_ns;
+       unsigned int            c_size;
        unsigned int            r2w_factor;
        unsigned int            max_dtr;
        unsigned int            erase_size;             /* In sectors */
@@ -45,6 +47,10 @@ struct mmc_ext_csd {
        u8                      rev;
        u8                      erase_group_def;
        u8                      sec_feature_support;
+       u8                      rel_sectors;
+       u8                      rel_param;
+       u8                      part_config;
+       unsigned int            part_time;              /* Units: ms */
        unsigned int            sa_timeout;             /* Units: 100ns */
        unsigned int            hs_max_dtr;
        unsigned int            sectors;
@@ -57,13 +63,18 @@ struct mmc_ext_csd {
        bool                    enhanced_area_en;       /* enable bit */
        unsigned long long      enhanced_area_offset;   /* Units: Byte */
        unsigned int            enhanced_area_size;     /* Units: KB */
+       unsigned int            boot_size;              /* in bytes */
 };
 
 struct sd_scr {
        unsigned char           sda_vsn;
+       unsigned char           sda_spec3;
        unsigned char           bus_widths;
 #define SD_SCR_BUS_WIDTH_1     (1<<0)
 #define SD_SCR_BUS_WIDTH_4     (1<<2)
+       unsigned char           cmds;
+#define SD_SCR_CMD20_SUPPORT   (1<<0)
+#define SD_SCR_CMD23_SUPPORT   (1<<1)
 };
 
 struct sd_ssr {
@@ -74,6 +85,39 @@ struct sd_ssr {
 
 struct sd_switch_caps {
        unsigned int            hs_max_dtr;
+       unsigned int            uhs_max_dtr;
+#define UHS_SDR104_MAX_DTR     208000000
+#define UHS_SDR50_MAX_DTR      100000000
+#define UHS_DDR50_MAX_DTR      50000000
+#define UHS_SDR25_MAX_DTR      UHS_DDR50_MAX_DTR
+#define UHS_SDR12_MAX_DTR      25000000
+       unsigned int            sd3_bus_mode;
+#define UHS_SDR12_BUS_SPEED    0
+#define UHS_SDR25_BUS_SPEED    1
+#define UHS_SDR50_BUS_SPEED    2
+#define UHS_SDR104_BUS_SPEED   3
+#define UHS_DDR50_BUS_SPEED    4
+
+#define SD_MODE_UHS_SDR12      (1 << UHS_SDR12_BUS_SPEED)
+#define SD_MODE_UHS_SDR25      (1 << UHS_SDR25_BUS_SPEED)
+#define SD_MODE_UHS_SDR50      (1 << UHS_SDR50_BUS_SPEED)
+#define SD_MODE_UHS_SDR104     (1 << UHS_SDR104_BUS_SPEED)
+#define SD_MODE_UHS_DDR50      (1 << UHS_DDR50_BUS_SPEED)
+       unsigned int            sd3_drv_type;
+#define SD_DRIVER_TYPE_B       0x01
+#define SD_DRIVER_TYPE_A       0x02
+#define SD_DRIVER_TYPE_C       0x04
+#define SD_DRIVER_TYPE_D       0x08
+       unsigned int            sd3_curr_limit;
+#define SD_SET_CURRENT_LIMIT_200       0
+#define SD_SET_CURRENT_LIMIT_400       1
+#define SD_SET_CURRENT_LIMIT_600       2
+#define SD_SET_CURRENT_LIMIT_800       3
+
+#define SD_MAX_CURRENT_200     (1 << SD_SET_CURRENT_LIMIT_200)
+#define SD_MAX_CURRENT_400     (1 << SD_SET_CURRENT_LIMIT_400)
+#define SD_MAX_CURRENT_600     (1 << SD_SET_CURRENT_LIMIT_600)
+#define SD_MAX_CURRENT_800     (1 << SD_SET_CURRENT_LIMIT_800)
 };
 
 struct sdio_cccr {
@@ -118,6 +162,8 @@ struct mmc_card {
 #define MMC_STATE_HIGHSPEED    (1<<2)          /* card is in high speed mode */
 #define MMC_STATE_BLOCKADDR    (1<<3)          /* card uses block-addressing */
 #define MMC_STATE_HIGHSPEED_DDR (1<<4)         /* card is in high speed mode */
+#define MMC_STATE_ULTRAHIGHSPEED (1<<5)                /* card is in ultra high speed mode */
+#define MMC_CARD_SDXC          (1<<6)          /* card is SDXC */
        unsigned int            quirks;         /* card quirks */
 #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
@@ -125,6 +171,10 @@ struct mmc_card {
 #define MMC_QUIRK_NONSTD_SDIO  (1<<2)          /* non-standard SDIO card attached */
                                                /* (missing CIA registers) */
 #define MMC_QUIRK_BROKEN_CLK_GATING (1<<3)     /* clock gating the sdio bus will make card fail */
+#define MMC_QUIRK_NONSTD_FUNC_IF (1<<4)                /* SDIO card has nonstd function interfaces */
+#define MMC_QUIRK_DISABLE_CD   (1<<5)          /* disconnect CD/DAT[3] resistor */
+#define MMC_QUIRK_INAND_CMD38  (1<<6)          /* iNAND devices have broken CMD38 */
+#define MMC_QUIRK_BLK_NO_CMD23 (1<<7)          /* Avoid CMD23 for regular multiblock */
 
        unsigned int            erase_size;     /* erase size in sectors */
        unsigned int            erase_shift;    /* if erase unit is power 2 */
@@ -145,14 +195,100 @@ struct mmc_card {
        struct sdio_cccr        cccr;           /* common card info */
        struct sdio_cis         cis;            /* common tuple info */
        struct sdio_func        *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */
+       struct sdio_func        *sdio_single_irq; /* SDIO function when only one IRQ active */
        unsigned                num_info;       /* number of info strings */
        const char              **info;         /* info strings */
        struct sdio_func_tuple  *tuples;        /* unknown common tuples */
 
+       unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
+
        struct dentry           *debugfs_root;
 };
 
-void mmc_fixup_device(struct mmc_card *dev);
+/*
+ *  The world is not perfect and supplies us with broken mmc/sdio devices.
+ *  For at least some of these bugs we need a work-around.
+ */
+
+struct mmc_fixup {
+       /* CID-specific fields. */
+       const char *name;
+
+       /* Valid revision range */
+       u64 rev_start, rev_end;
+
+       unsigned int manfid;
+       unsigned short oemid;
+
+       /* SDIO-specfic fields. You can use SDIO_ANY_ID here of course */
+       u16 cis_vendor, cis_device;
+
+       void (*vendor_fixup)(struct mmc_card *card, int data);
+       int data;
+};
+
+#define CID_MANFID_ANY (-1u)
+#define CID_OEMID_ANY ((unsigned short) -1)
+#define CID_NAME_ANY (NULL)
+
+#define END_FIXUP { 0 }
+
+#define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end,       \
+                  _cis_vendor, _cis_device,                            \
+                  _fixup, _data)                                       \
+       {                                                  \
+               .name = (_name),                           \
+               .manfid = (_manfid),                       \
+               .oemid = (_oemid),                         \
+               .rev_start = (_rev_start),                 \
+               .rev_end = (_rev_end),                     \
+               .cis_vendor = (_cis_vendor),               \
+               .cis_device = (_cis_device),               \
+               .vendor_fixup = (_fixup),                  \
+               .data = (_data),                           \
+        }
+
+#define MMC_FIXUP_REV(_name, _manfid, _oemid, _rev_start, _rev_end,    \
+                     _fixup, _data)                                    \
+       _FIXUP_EXT(_name, _manfid,                                      \
+                  _oemid, _rev_start, _rev_end,                        \
+                  SDIO_ANY_ID, SDIO_ANY_ID,                            \
+                  _fixup, _data)                                       \
+
+#define MMC_FIXUP(_name, _manfid, _oemid, _fixup, _data) \
+       MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data)
+
+#define SDIO_FIXUP(_vendor, _device, _fixup, _data)                    \
+       _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_ANY,                        \
+                   CID_OEMID_ANY, 0, -1ull,                            \
+                  _vendor, _device,                                    \
+                  _fixup, _data)                                       \
+
+#define cid_rev(hwrev, fwrev, year, month)     \
+       (((u64) hwrev) << 40 |                  \
+        ((u64) fwrev) << 32 |                  \
+        ((u64) year) << 16 |                   \
+        ((u64) month))
+
+#define cid_rev_card(card)               \
+       cid_rev(card->cid.hwrev,          \
+                   card->cid.fwrev,      \
+                   card->cid.year,       \
+                   card->cid.month)
+
+/*
+ * Unconditionally quirk add/remove.
+ */
+
+static inline void __maybe_unused add_quirk(struct mmc_card *card, int data)
+{
+       card->quirks |= data;
+}
+
+static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
+{
+       card->quirks &= ~data;
+}
 
 #define mmc_card_mmc(c)                ((c)->type == MMC_TYPE_MMC)
 #define mmc_card_sd(c)         ((c)->type == MMC_TYPE_SD)
@@ -163,12 +299,50 @@ void mmc_fixup_device(struct mmc_card *dev);
 #define mmc_card_highspeed(c)  ((c)->state & MMC_STATE_HIGHSPEED)
 #define mmc_card_blockaddr(c)  ((c)->state & MMC_STATE_BLOCKADDR)
 #define mmc_card_ddr_mode(c)   ((c)->state & MMC_STATE_HIGHSPEED_DDR)
+#define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
+#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
 
 #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
 #define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
+#define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
+#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
+
+/*
+ * Quirk add/remove for MMC products.
+ */
+
+static inline void __maybe_unused add_quirk_mmc(struct mmc_card *card, int data)
+{
+       if (mmc_card_mmc(card))
+               card->quirks |= data;
+}
+
+static inline void __maybe_unused remove_quirk_mmc(struct mmc_card *card,
+                                                  int data)
+{
+       if (mmc_card_mmc(card))
+               card->quirks &= ~data;
+}
+
+/*
+ * Quirk add/remove for SD products.
+ */
+
+static inline void __maybe_unused add_quirk_sd(struct mmc_card *card, int data)
+{
+       if (mmc_card_sd(card))
+               card->quirks |= data;
+}
+
+static inline void __maybe_unused remove_quirk_sd(struct mmc_card *card,
+                                                  int data)
+{
+       if (mmc_card_sd(card))
+               card->quirks &= ~data;
+}
 
 static inline int mmc_card_lenient_fn0(const struct mmc_card *c)
 {
@@ -180,6 +354,16 @@ static inline int mmc_blksz_for_byte_mode(const struct mmc_card *c)
        return c->quirks & MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
 }
 
+static inline int mmc_card_disable_cd(const struct mmc_card *c)
+{
+       return c->quirks & MMC_QUIRK_DISABLE_CD;
+}
+
+static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c)
+{
+       return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF;
+}
+
 #define mmc_card_name(c)       ((c)->cid.prod_name)
 #define mmc_card_id(c)         (dev_name(&(c)->dev))
 
@@ -203,4 +387,7 @@ struct mmc_driver {
 extern int mmc_register_driver(struct mmc_driver *);
 extern void mmc_unregister_driver(struct mmc_driver *);
 
+extern void mmc_fixup_device(struct mmc_card *card,
+                            const struct mmc_fixup *table);
+
 #endif
index 07f27af4dba5221b1139206cc2bd33858a3b38ef..b6718e549a510780e0f8c9a3be17e64753d6c2f5 100644 (file)
@@ -92,7 +92,7 @@ struct mmc_command {
  *              actively failing requests
  */
 
-       unsigned int            erase_timeout;  /* in milliseconds */
+       unsigned int            cmd_timeout_ms; /* in milliseconds */
 
        struct mmc_data         *data;          /* data segment associated with cmd */
        struct mmc_request      *mrq;           /* associated request */
@@ -120,6 +120,7 @@ struct mmc_data {
 };
 
 struct mmc_request {
+       struct mmc_command      *sbc;           /* SET_BLOCK_COUNT for multiblock */
        struct mmc_command      *cmd;
        struct mmc_data         *data;
        struct mmc_command      *stop;
@@ -133,8 +134,10 @@ struct mmc_card;
 
 extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
+extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *);
 extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
        struct mmc_command *, int);
+extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
 
 #define MMC_ERASE_ARG          0x00000000
 #define MMC_SECURE_ERASE_ARG   0x80000000
index bcb793ec7374f61d2552cca43f573bdd1f100ece..1ee4424462ebcf98f2e81082b65c7211d64a248e 100644 (file)
@@ -50,12 +50,30 @@ struct mmc_ios {
 #define MMC_TIMING_LEGACY      0
 #define MMC_TIMING_MMC_HS      1
 #define MMC_TIMING_SD_HS       2
+#define MMC_TIMING_UHS_SDR12   MMC_TIMING_LEGACY
+#define MMC_TIMING_UHS_SDR25   MMC_TIMING_SD_HS
+#define MMC_TIMING_UHS_SDR50   3
+#define MMC_TIMING_UHS_SDR104  4
+#define MMC_TIMING_UHS_DDR50   5
 
        unsigned char   ddr;                    /* dual data rate used */
 
 #define MMC_SDR_MODE           0
 #define MMC_1_2V_DDR_MODE      1
 #define MMC_1_8V_DDR_MODE      2
+
+       unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
+
+#define MMC_SIGNAL_VOLTAGE_330 0
+#define MMC_SIGNAL_VOLTAGE_180 1
+#define MMC_SIGNAL_VOLTAGE_120 2
+
+       unsigned char   drv_type;               /* driver type (A, B, C, D) */
+
+#define MMC_SET_DRIVER_TYPE_B  0
+#define MMC_SET_DRIVER_TYPE_A  1
+#define MMC_SET_DRIVER_TYPE_C  2
+#define MMC_SET_DRIVER_TYPE_D  3
 };
 
 struct mmc_host_ops {
@@ -117,6 +135,10 @@ struct mmc_host_ops {
 
        /* optional callback for HC quirks */
        void    (*init_card)(struct mmc_host *host, struct mmc_card *card);
+
+       int     (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
+       int     (*execute_tuning)(struct mmc_host *host);
+       void    (*enable_preset_value)(struct mmc_host *host, bool enable);
 };
 
 struct mmc_card;
@@ -173,6 +195,22 @@ struct mmc_host {
                                                /* DDR mode at 1.2V */
 #define MMC_CAP_POWER_OFF_CARD (1 << 13)       /* Can power off after boot */
 #define MMC_CAP_BUS_WIDTH_TEST (1 << 14)       /* CMD14/CMD19 bus width ok */
+#define MMC_CAP_UHS_SDR12      (1 << 15)       /* Host supports UHS SDR12 mode */
+#define MMC_CAP_UHS_SDR25      (1 << 16)       /* Host supports UHS SDR25 mode */
+#define MMC_CAP_UHS_SDR50      (1 << 17)       /* Host supports UHS SDR50 mode */
+#define MMC_CAP_UHS_SDR104     (1 << 18)       /* Host supports UHS SDR104 mode */
+#define MMC_CAP_UHS_DDR50      (1 << 19)       /* Host supports UHS DDR50 mode */
+#define MMC_CAP_SET_XPC_330    (1 << 20)       /* Host supports >150mA current at 3.3V */
+#define MMC_CAP_SET_XPC_300    (1 << 21)       /* Host supports >150mA current at 3.0V */
+#define MMC_CAP_SET_XPC_180    (1 << 22)       /* Host supports >150mA current at 1.8V */
+#define MMC_CAP_DRIVER_TYPE_A  (1 << 23)       /* Host supports Driver Type A */
+#define MMC_CAP_DRIVER_TYPE_C  (1 << 24)       /* Host supports Driver Type C */
+#define MMC_CAP_DRIVER_TYPE_D  (1 << 25)       /* Host supports Driver Type D */
+#define MMC_CAP_MAX_CURRENT_200        (1 << 26)       /* Host max current limit is 200mA */
+#define MMC_CAP_MAX_CURRENT_400        (1 << 27)       /* Host max current limit is 400mA */
+#define MMC_CAP_MAX_CURRENT_600        (1 << 28)       /* Host max current limit is 600mA */
+#define MMC_CAP_MAX_CURRENT_800        (1 << 29)       /* Host max current limit is 800mA */
+#define MMC_CAP_CMD23          (1 << 30)       /* CMD23 supported. */
 
        mmc_pm_flag_t           pm_caps;        /* supported pm features */
 
@@ -321,10 +359,19 @@ static inline int mmc_card_is_removable(struct mmc_host *host)
        return !(host->caps & MMC_CAP_NONREMOVABLE) && mmc_assume_removable;
 }
 
-static inline int mmc_card_is_powered_resumed(struct mmc_host *host)
+static inline int mmc_card_keep_power(struct mmc_host *host)
 {
        return host->pm_flags & MMC_PM_KEEP_POWER;
 }
 
+static inline int mmc_card_wake_sdio_irq(struct mmc_host *host)
+{
+       return host->pm_flags & MMC_PM_WAKE_SDIO_IRQ;
+}
+
+static inline int mmc_host_cmd23(struct mmc_host *host)
+{
+       return host->caps & MMC_CAP_CMD23;
+}
 #endif
 
diff --git a/include/linux/mmc/ioctl.h b/include/linux/mmc/ioctl.h
new file mode 100644 (file)
index 0000000..5baf298
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef LINUX_MMC_IOCTL_H
+#define LINUX_MMC_IOCTL_H
+struct mmc_ioc_cmd {
+       /* Implies direction of data.  true = write, false = read */
+       int write_flag;
+
+       /* Application-specific command.  true = precede with CMD55 */
+       int is_acmd;
+
+       __u32 opcode;
+       __u32 arg;
+       __u32 response[4];  /* CMD response */
+       unsigned int flags;
+       unsigned int blksz;
+       unsigned int blocks;
+
+       /*
+        * Sleep at least postsleep_min_us useconds, and at most
+        * postsleep_max_us useconds *after* issuing command.  Needed for
+        * some read commands for which cards have no other way of indicating
+        * they're ready for the next command (i.e. there is no equivalent of
+        * a "busy" indicator for read operations).
+        */
+       unsigned int postsleep_min_us;
+       unsigned int postsleep_max_us;
+
+       /*
+        * Override driver-computed timeouts.  Note the difference in units!
+        */
+       unsigned int data_timeout_ns;
+       unsigned int cmd_timeout_ms;
+
+       /*
+        * For 64-bit machines, the next member, ``__u64 data_ptr``, wants to
+        * be 8-byte aligned.  Make sure this struct is the same size when
+        * built for 32-bit.
+        */
+       __u32 __pad;
+
+       /* DAT buffer */
+       __u64 data_ptr;
+};
+#define mmc_ioc_cmd_set_data(ic, ptr) ic.data_ptr = (__u64)(unsigned long) ptr
+
+#define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd)
+
+/*
+ * Since this ioctl is only meant to enhance (and not replace) normal access
+ * to the mmc bus device, an upper data transfer limit of MMC_IOC_MAX_BYTES
+ * is enforced per ioctl call.  For larger data transfers, use the normal
+ * block device operations.
+ */
+#define MMC_IOC_MAX_BYTES  (512L * 256)
+#endif  /* LINUX_MMC_IOCTL_H */
index 264ba5451e3b98449832d94693d167792cec1f7b..ac26a685cca8a82e55f2b6eba31ee1321ff70727 100644 (file)
@@ -50,6 +50,7 @@
 #define MMC_SET_BLOCKLEN         16   /* ac   [31:0] block len   R1  */
 #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1  */
 #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
+#define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1  */
 
   /* class 3 */
 #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
 #define MMC_APP_CMD              55   /* ac   [31:16] RCA        R1  */
 #define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1  */
 
+static inline bool mmc_op_multi(u32 opcode)
+{
+       return opcode == MMC_WRITE_MULTIPLE_BLOCK ||
+              opcode == MMC_READ_MULTIPLE_BLOCK;
+}
+
 /*
  * MMC_SWITCH argument format:
  *
@@ -255,18 +262,23 @@ struct _mmc_csd {
 
 #define EXT_CSD_PARTITION_ATTRIBUTE    156     /* R/W */
 #define EXT_CSD_PARTITION_SUPPORT      160     /* RO */
+#define EXT_CSD_WR_REL_PARAM           166     /* RO */
 #define EXT_CSD_ERASE_GROUP_DEF                175     /* R/W */
+#define EXT_CSD_PART_CONFIG            179     /* R/W */
 #define EXT_CSD_ERASED_MEM_CONT                181     /* RO */
 #define EXT_CSD_BUS_WIDTH              183     /* R/W */
 #define EXT_CSD_HS_TIMING              185     /* R/W */
 #define EXT_CSD_REV                    192     /* RO */
 #define EXT_CSD_STRUCTURE              194     /* RO */
 #define EXT_CSD_CARD_TYPE              196     /* RO */
+#define EXT_CSD_PART_SWITCH_TIME        199     /* RO */
 #define EXT_CSD_SEC_CNT                        212     /* RO, 4 bytes */
 #define EXT_CSD_S_A_TIMEOUT            217     /* RO */
+#define EXT_CSD_REL_WR_SEC_C           222     /* RO */
 #define EXT_CSD_HC_WP_GRP_SIZE         221     /* RO */
 #define EXT_CSD_ERASE_TIMEOUT_MULT     223     /* RO */
 #define EXT_CSD_HC_ERASE_GRP_SIZE      224     /* RO */
+#define EXT_CSD_BOOT_MULT              226     /* RO */
 #define EXT_CSD_SEC_TRIM_MULT          229     /* RO */
 #define EXT_CSD_SEC_ERASE_MULT         230     /* RO */
 #define EXT_CSD_SEC_FEATURE_SUPPORT    231     /* RO */
@@ -276,6 +288,12 @@ struct _mmc_csd {
  * EXT_CSD field definitions
  */
 
+#define EXT_CSD_WR_REL_PARAM_EN                (1<<2)
+
+#define EXT_CSD_PART_CONFIG_ACC_MASK   (0x7)
+#define EXT_CSD_PART_CONFIG_ACC_BOOT0  (0x1)
+#define EXT_CSD_PART_CONFIG_ACC_BOOT1  (0x2)
+
 #define EXT_CSD_CMD_SET_NORMAL         (1<<0)
 #define EXT_CSD_CMD_SET_SECURE         (1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE       (1<<2)
index 3fd85e088cc3fd7547f3f7a6b31b8df1a2e86a3c..7d35d52c3df374a2a19ad7d9089381992f88317c 100644 (file)
@@ -17,6 +17,7 @@
 /* This is basically the same command as for MMC with some quirks. */
 #define SD_SEND_RELATIVE_ADDR     3   /* bcr                     R6  */
 #define SD_SEND_IF_COND           8   /* bcr  [11:0] See below   R7  */
+#define SD_SWITCH_VOLTAGE         11  /* ac                      R1  */
 
   /* class 10 */
 #define SD_SWITCH                 6   /* adtc [31:0] See below   R1  */
 #define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
 #define SD_APP_SEND_SCR          51   /* adtc                    R1  */
 
+/* OCR bit definitions */
+#define SD_OCR_S18R            (1 << 24)    /* 1.8V switching request */
+#define SD_ROCR_S18A           SD_OCR_S18R  /* 1.8V switching accepted by card */
+#define SD_OCR_XPC             (1 << 28)    /* SDXC power control */
+#define SD_OCR_CCS             (1 << 30)    /* Card Capacity Status */
+
 /*
  * SD_SWITCH argument format:
  *
@@ -59,7 +66,7 @@
 
 #define SCR_SPEC_VER_0         0       /* Implements system specification 1.0 - 1.01 */
 #define SCR_SPEC_VER_1         1       /* Implements system specification 1.10 */
-#define SCR_SPEC_VER_2         2       /* Implements system specification 2.00 */
+#define SCR_SPEC_VER_2         2       /* Implements system specification 2.00-3.0X */
 
 /*
  * SD bus widths
index 83bd9f76709aa90b32ad76a175a408bf7725b468..6a68c4eb4e444b55137d0e561275aad5f80f1910 100644 (file)
@@ -85,6 +85,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK_NO_HISPD_BIT                       (1<<29)
 /* Controller treats ADMA descriptors with length 0000h incorrectly */
 #define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC           (1<<30)
+/* The read-only detection via SDHCI_PRESENT_STATE register is unstable */
+#define SDHCI_QUIRK_UNSTABLE_RO_DETECT                 (1<<31)
 
        int irq;                /* Device IRQ */
        void __iomem *ioaddr;   /* Mapped address */
@@ -109,11 +111,16 @@ struct sdhci_host {
 #define SDHCI_USE_ADMA         (1<<1)  /* Host is ADMA capable */
 #define SDHCI_REQ_USE_DMA      (1<<2)  /* Use DMA for this req. */
 #define SDHCI_DEVICE_DEAD      (1<<3)  /* Device unresponsive */
+#define SDHCI_SDR50_NEEDS_TUNING (1<<4)        /* SDR50 needs tuning */
+#define SDHCI_NEEDS_RETUNING   (1<<5)  /* Host needs retuning */
+#define SDHCI_AUTO_CMD12       (1<<6)  /* Auto CMD12 support */
+#define SDHCI_AUTO_CMD23       (1<<7)  /* Auto CMD23 support */
 
        unsigned int version;   /* SDHCI spec. version */
 
        unsigned int max_clk;   /* Max possible freq (MHz) */
        unsigned int timeout_clk;       /* Timeout freq (KHz) */
+       unsigned int clk_mul;   /* Clock Muliplier value */
 
        unsigned int clock;     /* Current clock (MHz) */
        u8 pwr;                 /* Current voltage */
@@ -145,6 +152,14 @@ struct sdhci_host {
        unsigned int            ocr_avail_sd;
        unsigned int            ocr_avail_mmc;
 
+       wait_queue_head_t       buf_ready_int;  /* Waitqueue for Buffer Read Ready interrupt */
+       unsigned int            tuning_done;    /* Condition flag set when CMD19 succeeds */
+
+       unsigned int            tuning_count;   /* Timer count for re-tuning */
+       unsigned int            tuning_mode;    /* Re-tuning mode supported by host */
+#define SDHCI_TUNING_MODE_1    0
+       struct timer_list       tuning_timer;   /* Timer for tuning */
+
        unsigned long private[0] ____cacheline_aligned;
 };
 #endif /* __SDHCI_H */
index c981b959760f717ffff9e88895900bb6e46321bf..faf32b6ec18517dc3948497fd6919f17239348f8 100644 (file)
@@ -3,12 +3,16 @@
 
 #include <linux/types.h>
 
+struct platform_device;
+struct tmio_mmc_data;
+
 struct sh_mobile_sdhi_info {
        int dma_slave_tx;
        int dma_slave_rx;
        unsigned long tmio_flags;
        unsigned long tmio_caps;
        u32 tmio_ocr_mask;      /* available MMC voltages */
+       struct tmio_mmc_data *pdata;
        void (*set_pwr)(struct platform_device *pdev, int state);
        int (*get_cd)(struct platform_device *pdev);
 };
index cc2e7dfea9d7f6a57661155cb88ca487863e66af..1d1b1e13f79fbc13c0f2abfec525c8026a286b8f 100644 (file)
@@ -150,7 +150,7 @@ struct mmu_notifier_ops {
  * Therefore notifier chains can only be traversed when either
  *
  * 1. mmap_sem is held.
- * 2. One of the reverse map locks is held (i_mmap_lock or anon_vma->lock).
+ * 2. One of the reverse map locks is held (i_mmap_mutex or anon_vma->mutex).
  * 3. No other concurrent thread can access the list (release)
  */
 struct mmu_notifier {
index e56f835274c9becd407fe28705fd81f09f5bbc3d..c928dac6cad0c3b1022ebdca9d53ecef1865b797 100644 (file)
@@ -273,11 +273,6 @@ struct zone_reclaim_stat {
         */
        unsigned long           recent_rotated[2];
        unsigned long           recent_scanned[2];
-
-       /*
-        * accumulated for batching
-        */
-       unsigned long           nr_saved_scan[NR_LRU_LISTS];
 };
 
 struct zone {
@@ -928,9 +923,6 @@ static inline unsigned long early_pfn_to_nid(unsigned long pfn)
 #define pfn_to_nid(pfn)                (0)
 #endif
 
-#define pfn_to_section_nr(pfn) ((pfn) >> PFN_SECTION_SHIFT)
-#define section_nr_to_pfn(sec) ((sec) << PFN_SECTION_SHIFT)
-
 #ifdef CONFIG_SPARSEMEM
 
 /*
@@ -956,6 +948,12 @@ static inline unsigned long early_pfn_to_nid(unsigned long pfn)
 #error Allocator MAX_ORDER exceeds SECTION_SIZE
 #endif
 
+#define pfn_to_section_nr(pfn) ((pfn) >> PFN_SECTION_SHIFT)
+#define section_nr_to_pfn(sec) ((sec) << PFN_SECTION_SHIFT)
+
+#define SECTION_ALIGN_UP(pfn)  (((pfn) + PAGES_PER_SECTION - 1) & PAGE_SECTION_MASK)
+#define SECTION_ALIGN_DOWN(pfn)        ((pfn) & PAGE_SECTION_MASK)
+
 struct page;
 struct page_cgroup;
 struct mem_section {
@@ -1053,12 +1051,14 @@ static inline struct mem_section *__pfn_to_section(unsigned long pfn)
        return __nr_to_section(pfn_to_section_nr(pfn));
 }
 
+#ifndef CONFIG_HAVE_ARCH_PFN_VALID
 static inline int pfn_valid(unsigned long pfn)
 {
        if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
                return 0;
        return valid_section(__nr_to_section(pfn_to_section_nr(pfn)));
 }
+#endif
 
 static inline int pfn_present(unsigned long pfn)
 {
index 9d5306bad117fcc850bf3c440127b56efb1ce027..2541fb848daa7c2108c7ff74e27a44d146731642 100644 (file)
@@ -322,9 +322,12 @@ static inline uint32_t mtd_mod_by_ws(uint64_t sz, struct mtd_info *mtd)
 
        /* Kernel-side ioctl definitions */
 
-extern int add_mtd_device(struct mtd_info *mtd);
-extern int del_mtd_device (struct mtd_info *mtd);
+struct mtd_partition;
 
+extern int mtd_device_register(struct mtd_info *master,
+                              const struct mtd_partition *parts,
+                              int nr_parts);
+extern int mtd_device_unregister(struct mtd_info *master);
 extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num);
 extern int __get_mtd_device(struct mtd_info *mtd);
 extern void __put_mtd_device(struct mtd_info *mtd);
@@ -348,15 +351,9 @@ int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
 int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs,
                      unsigned long count, loff_t from, size_t *retlen);
 
-#ifdef CONFIG_MTD_PARTITIONS
+void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size);
+
 void mtd_erase_callback(struct erase_info *instr);
-#else
-static inline void mtd_erase_callback(struct erase_info *instr)
-{
-       if (instr->callback)
-               instr->callback(instr);
-}
-#endif
 
 /*
  * Debugging macro and defines
index d44192740f6fa44ab52ca03c1425f6659bfc8265..c2b9ac4fbc4ab588074acd2d77f2ad20bc1bddb6 100644 (file)
@@ -237,9 +237,9 @@ typedef enum {
  * If passed additionally to NAND_USE_FLASH_BBT then BBT code will not touch
  * the OOB area.
  */
-#define NAND_USE_FLASH_BBT_NO_OOB      0x00100000
+#define NAND_USE_FLASH_BBT_NO_OOB      0x00800000
 /* Create an empty BBT with no vendor information if the BBT is available */
-#define NAND_CREATE_EMPTY_BBT          0x00200000
+#define NAND_CREATE_EMPTY_BBT          0x01000000
 
 /* Options set by nand scan */
 /* Nand scan has allocated controller struct */
index 4a0a8ba90a72cf9c3995eb6ef718fd23f542c852..3a6f0372fc9658f267fabdf61190b9a32ed4d7e3 100644 (file)
@@ -16,7 +16,7 @@
  * Partition definition structure:
  *
  * An array of struct partition is passed along with a MTD object to
- * add_mtd_partitions() to create them.
+ * mtd_device_register() to create them.
  *
  * For each partition, these fields are available:
  * name: string that will be used to label the partition's MTD device.
@@ -49,9 +49,6 @@ struct mtd_partition {
 
 struct mtd_info;
 
-int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
-int del_mtd_partitions(struct mtd_info *);
-
 /*
  * Functions dealing with the various ways of partitioning the space
  */
@@ -73,14 +70,17 @@ extern int parse_mtd_partitions(struct mtd_info *master, const char **types,
 struct device;
 struct device_node;
 
+#ifdef CONFIG_MTD_OF_PARTS
 int __devinit of_mtd_parse_partitions(struct device *dev,
                                       struct device_node *node,
                                       struct mtd_partition **pparts);
-
-#ifdef CONFIG_MTD_PARTITIONS
-static inline int mtd_has_partitions(void) { return 1; }
 #else
-static inline int mtd_has_partitions(void) { return 0; }
+static inline int of_mtd_parse_partitions(struct device *dev,
+                                         struct device_node *node,
+                                         struct mtd_partition **pparts)
+{
+       return 0;
+}
 #endif
 
 #ifdef CONFIG_MTD_CMDLINE_PARTS
index 49b959029417ced9e72e6693bd4407303223a2cb..e5f21d293c70175f1395c3355b3da5a230ee0d99 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mtd/partitions.h>
 
 struct map_info;
+struct platform_device;
 
 struct physmap_flash_data {
        unsigned int            width;
@@ -37,8 +38,6 @@ struct physmap_flash_data {
 void physmap_configure(unsigned long addr, unsigned long size,
                int bankwidth, void (*set_vpp)(struct map_info *, int) );
 
-#ifdef CONFIG_MTD_PARTITIONS
-
 /*
  * Machines that wish to do flash partition may want to call this function in
  * their setup routine.
@@ -50,6 +49,4 @@ void physmap_configure(unsigned long addr, unsigned long size,
  */
 void physmap_set_partitions(struct mtd_partition *parts, int num_parts);
 
-#endif /* defined(CONFIG_MTD_PARTITIONS) */
-
 #endif /* __LINUX_MTD_PHYSMAP__ */
index 84854edf4436f2a62ff7bc956101a6953236726e..15da0e99f48aef0615fafeefb9c3142a0f2bfa5a 100644 (file)
@@ -21,7 +21,7 @@
 #ifndef __LINUX_UBI_H__
 #define __LINUX_UBI_H__
 
-#include <asm/ioctl.h>
+#include <linux/ioctl.h>
 #include <linux/types.h>
 #include <mtd/ubi-user.h>
 
@@ -87,7 +87,7 @@ enum {
  * physical eraseblock size and on how much bytes UBI headers consume. But
  * because of the volume alignment (@alignment), the usable size of logical
  * eraseblocks if a volume may be less. The following equation is true:
- *     @usable_leb_size = LEB size - (LEB size mod @alignment),
+ *     @usable_leb_size = LEB size - (LEB size mod @alignment),
  * where LEB size is the logical eraseblock size defined by the UBI device.
  *
  * The alignment is multiple to the minimal flash input/output unit size or %1
index c75471db576ef0d500eb5a363b607819f38b869b..a940fe435acac1e6b48774686cdd39c9f0cd652d 100644 (file)
@@ -132,6 +132,7 @@ static inline int mutex_is_locked(struct mutex *lock)
  */
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
+extern void _mutex_lock_nest_lock(struct mutex *lock, struct lockdep_map *nest_lock);
 extern int __must_check mutex_lock_interruptible_nested(struct mutex *lock,
                                        unsigned int subclass);
 extern int __must_check mutex_lock_killable_nested(struct mutex *lock,
@@ -140,6 +141,13 @@ extern int __must_check mutex_lock_killable_nested(struct mutex *lock,
 #define mutex_lock(lock) mutex_lock_nested(lock, 0)
 #define mutex_lock_interruptible(lock) mutex_lock_interruptible_nested(lock, 0)
 #define mutex_lock_killable(lock) mutex_lock_killable_nested(lock, 0)
+
+#define mutex_lock_nest_lock(lock, nest_lock)                          \
+do {                                                                   \
+       typecheck(struct lockdep_map *, &(nest_lock)->dep_map);         \
+       _mutex_lock_nest_lock(lock, &(nest_lock)->dep_map);             \
+} while (0)
+
 #else
 extern void mutex_lock(struct mutex *lock);
 extern int __must_check mutex_lock_interruptible(struct mutex *lock);
@@ -148,6 +156,7 @@ extern int __must_check mutex_lock_killable(struct mutex *lock);
 # define mutex_lock_nested(lock, subclass) mutex_lock(lock)
 # define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock)
 # define mutex_lock_killable_nested(lock, subclass) mutex_lock_killable(lock)
+# define mutex_lock_nest_lock(lock, nest_lock) mutex_lock(lock)
 #endif
 
 /*
diff --git a/include/linux/mxm-wmi.h b/include/linux/mxm-wmi.h
new file mode 100644 (file)
index 0000000..617a295
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * MXM WMI driver
+ *
+ * Copyright(C) 2010 Red Hat.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef MXM_WMI_H
+#define MXM_WMI_H
+
+/* discrete adapters */
+#define MXM_MXDS_ADAPTER_0 0x0
+#define MXM_MXDS_ADAPTER_1 0x0
+/* integrated adapter */
+#define MXM_MXDS_ADAPTER_IGD 0x10
+int mxm_wmi_call_mxds(int adapter);
+int mxm_wmi_call_mxmx(int adapter);
+bool mxm_wmi_supported(void);
+
+#endif
index 1da55e9b6f01a9733f38b309e7b282f447764da7..b29923006b11e50b4aac2c99f9a81be14afc7fd1 100644 (file)
@@ -289,11 +289,5 @@ extern int kernel_sock_shutdown(struct socket *sock,
        MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto) \
                     "-type-" __stringify(type))
 
-#ifdef CONFIG_SYSCTL
-#include <linux/sysctl.h>
-#include <linux/ratelimit.h>
-extern struct ratelimit_state net_ratelimit_state;
-#endif
-
 #endif /* __KERNEL__ */
 #endif /* _LINUX_NET_H */
index ca333e79e10ff92e7fbc83a4908d2d54ccf514b0..54b8b4d7b68f1a2a42f68de4128f563f9f86eb4e 100644 (file)
@@ -2555,7 +2555,7 @@ extern void netdev_class_remove_file(struct class_attribute *class_attr);
 
 extern struct kobj_ns_type_operations net_ns_type_operations;
 
-extern char *netdev_drivername(const struct net_device *dev, char *buffer, int len);
+extern const char *netdev_drivername(const struct net_device *dev);
 
 extern void linkwatch_run_queue(void);
 
index 7fa95df60146f2920cf89e2163289017230a91a6..857f5026ced65267ad77db343be0f486cb61a7d5 100644 (file)
@@ -13,6 +13,7 @@
 #endif
 #include <linux/types.h>
 #include <linux/compiler.h>
+#include <linux/sysctl.h>
 
 /* Responses from hook functions. */
 #define NF_DROP 0
index a0196ac790513b9c8dcbb8f33b04218a7fa67b01..ac3c822eb39a66e48253fd3e4193d755bed51bf5 100644 (file)
@@ -839,7 +839,7 @@ type_pf_tdel(struct ip_set *set, void *value, u32 timeout)
        struct htable *t = h->table;
        const struct type_pf_elem *d = value;
        struct hbucket *n;
-       int i, ret = 0;
+       int i;
        struct type_pf_elem *data;
        u32 key;
 
@@ -850,7 +850,7 @@ type_pf_tdel(struct ip_set *set, void *value, u32 timeout)
                if (!type_pf_data_equal(data, d))
                        continue;
                if (type_pf_data_expired(data))
-                       ret = -IPSET_ERR_EXIST;
+                       return -IPSET_ERR_EXIST;
                if (i != n->pos - 1)
                        /* Not last one */
                        type_pf_data_copy(data, ahash_tdata(n, n->pos - 1));
index 9f30c5f2ec1cfcd6f02bb3d76413f4e223402827..bcdd40ad39ed57c0d8f47cc9a0859d779d9b8021 100644 (file)
@@ -45,7 +45,7 @@ ip_set_timeout_test(unsigned long timeout)
 {
        return timeout != IPSET_ELEM_UNSET &&
               (timeout == IPSET_ELEM_PERMANENT ||
-               time_after(timeout, jiffies));
+               time_is_after_jiffies(timeout));
 }
 
 static inline bool
@@ -53,7 +53,7 @@ ip_set_timeout_expired(unsigned long timeout)
 {
        return timeout != IPSET_ELEM_UNSET &&
               timeout != IPSET_ELEM_PERMANENT &&
-              time_before(timeout, jiffies);
+              time_is_before_jiffies(timeout);
 }
 
 static inline unsigned long
@@ -64,7 +64,7 @@ ip_set_timeout_set(u32 timeout)
        if (!timeout)
                return IPSET_ELEM_PERMANENT;
 
-       t = timeout * HZ + jiffies;
+       t = msecs_to_jiffies(timeout * 1000) + jiffies;
        if (t == IPSET_ELEM_UNSET || t == IPSET_ELEM_PERMANENT)
                /* Bingo! */
                t++;
@@ -75,7 +75,8 @@ ip_set_timeout_set(u32 timeout)
 static inline u32
 ip_set_timeout_get(unsigned long timeout)
 {
-       return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ;
+       return timeout == IPSET_ELEM_PERMANENT ? 0 : 
+               jiffies_to_msecs(timeout - jiffies)/1000;
 }
 
 #else
@@ -89,14 +90,14 @@ static inline bool
 ip_set_timeout_test(unsigned long timeout)
 {
        return timeout == IPSET_ELEM_PERMANENT ||
-              time_after(timeout, jiffies);
+              time_is_after_jiffies(timeout);
 }
 
 static inline bool
 ip_set_timeout_expired(unsigned long timeout)
 {
        return timeout != IPSET_ELEM_PERMANENT &&
-              time_before(timeout, jiffies);
+              time_is_before_jiffies(timeout);
 }
 
 static inline unsigned long
@@ -107,7 +108,7 @@ ip_set_timeout_set(u32 timeout)
        if (!timeout)
                return IPSET_ELEM_PERMANENT;
 
-       t = timeout * HZ + jiffies;
+       t = msecs_to_jiffies(timeout * 1000) + jiffies;
        if (t == IPSET_ELEM_PERMANENT)
                /* Bingo! :-) */
                t++;
@@ -118,7 +119,8 @@ ip_set_timeout_set(u32 timeout)
 static inline u32
 ip_set_timeout_get(unsigned long timeout)
 {
-       return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ;
+       return timeout == IPSET_ELEM_PERMANENT ? 0 :
+               jiffies_to_msecs(timeout - jiffies)/1000;
 }
 #endif /* ! IP_SET_BITMAP_TIMEOUT */
 
index 50cdc2559a5aa05a10e4d1115c48da7185a5e7bd..0d3dd66322ecbb24529303f6634f36e5ce6f390d 100644 (file)
@@ -18,6 +18,9 @@ enum ip_conntrack_info {
        /* >= this indicates reply direction */
        IP_CT_IS_REPLY,
 
+       IP_CT_ESTABLISHED_REPLY = IP_CT_ESTABLISHED + IP_CT_IS_REPLY,
+       IP_CT_RELATED_REPLY = IP_CT_RELATED + IP_CT_IS_REPLY,
+       IP_CT_NEW_REPLY = IP_CT_NEW + IP_CT_IS_REPLY,   
        /* Number of distinct IP_CT types (no NEW in reply dirn). */
        IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1
 };
index 4c4ac3f3ce5a9968b0b5f2c7534ebc04faa74248..a9dd89552f9c61e804249e5b21d2504251925f2f 100644 (file)
@@ -24,6 +24,7 @@
 /* leave room for NETLINK_DM (DM Events) */
 #define NETLINK_SCSITRANSPORT  18      /* SCSI Transports */
 #define NETLINK_ECRYPTFS       19
+#define NETLINK_RDMA           20
 
 #define MAX_LINKS 32           
 
index 178fafe0ff9303426675f3b0134b01202de3ade1..504b289ba6806ec7d4c6016f2cf9471f1b7f0370 100644 (file)
@@ -562,6 +562,7 @@ enum {
        NFSPROC4_CLNT_LAYOUTGET,
        NFSPROC4_CLNT_GETDEVICEINFO,
        NFSPROC4_CLNT_LAYOUTCOMMIT,
+       NFSPROC4_CLNT_LAYOUTRETURN,
 };
 
 /* nfs41 types */
@@ -570,9 +571,11 @@ struct nfs4_sessionid {
 };
 
 /* Create Session Flags */
-#define SESSION4_PERSIST        0x001
-#define SESSION4_BACK_CHAN      0x002
-#define SESSION4_RDMA           0x004
+#define SESSION4_PERSIST       0x001
+#define SESSION4_BACK_CHAN     0x002
+#define SESSION4_RDMA          0x004
+
+#define SESSION4_FLAG_MASK_A   0x007
 
 enum state_protect_how4 {
        SP4_NONE        = 0,
index 91af2e49fa3ab1a532bdc22143da19021f0248da..25311b3bedf855574eb79170ea7b25d98962b0d6 100644 (file)
@@ -68,7 +68,7 @@ struct nfs_pageio_descriptor {
        int                     pg_ioflags;
        int                     pg_error;
        struct pnfs_layout_segment *pg_lseg;
-       int                     (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *);
+       bool                    (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *);
 };
 
 #define NFS_WBACK_BUSY(req)    (test_bit(PG_BUSY,&(req)->wb_flags))
@@ -92,6 +92,9 @@ extern        int nfs_pageio_add_request(struct nfs_pageio_descriptor *,
                                   struct nfs_page *);
 extern void nfs_pageio_complete(struct nfs_pageio_descriptor *desc);
 extern void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *, pgoff_t);
+extern bool nfs_generic_pg_test(struct nfs_pageio_descriptor *desc,
+                               struct nfs_page *prev,
+                               struct nfs_page *req);
 extern  int nfs_wait_on_request(struct nfs_page *);
 extern void nfs_unlock_request(struct nfs_page *req);
 extern int nfs_set_page_tag_locked(struct nfs_page *req);
index 7e371f7df9c463270a15b23a1b3fce52b26fc02d..00848d86ffb250fe50b7e5090986646aac43aa47 100644 (file)
@@ -158,7 +158,6 @@ struct nfs_seqid;
 
 /* nfs41 sessions channel attributes */
 struct nfs4_channel_attrs {
-       u32                     headerpadsz;
        u32                     max_rqst_sz;
        u32                     max_resp_sz;
        u32                     max_resp_sz_cached;
@@ -269,6 +268,27 @@ struct nfs4_layoutcommit_data {
        struct nfs4_layoutcommit_res res;
 };
 
+struct nfs4_layoutreturn_args {
+       __u32   layout_type;
+       struct inode *inode;
+       nfs4_stateid stateid;
+       struct nfs4_sequence_args seq_args;
+};
+
+struct nfs4_layoutreturn_res {
+       struct nfs4_sequence_res seq_res;
+       u32 lrs_present;
+       nfs4_stateid stateid;
+};
+
+struct nfs4_layoutreturn {
+       struct nfs4_layoutreturn_args args;
+       struct nfs4_layoutreturn_res res;
+       struct rpc_cred *cred;
+       struct nfs_client *clp;
+       int rpc_status;
+};
+
 /*
  * Arguments to the open call.
  */
@@ -1087,6 +1107,7 @@ struct nfs_read_data {
        const struct rpc_call_ops *mds_ops;
        int (*read_done_cb) (struct rpc_task *task, struct nfs_read_data *data);
        __u64                   mds_offset;
+       int                     pnfs_error;
        struct page             *page_array[NFS_PAGEVEC_SIZE];
 };
 
@@ -1112,6 +1133,7 @@ struct nfs_write_data {
        unsigned long           timestamp;      /* For lease renewal */
 #endif
        __u64                   mds_offset;     /* Filelayout dense stripe */
+       int                     pnfs_error;
        struct page             *page_array[NFS_PAGEVEC_SIZE];
 };
 
index 7b370c7cfeffb27db00d71fa2127381abdbfd518..50d20aba57d3067c4fdd42680c7ca0b7b938ede0 100644 (file)
@@ -81,13 +81,4 @@ static inline void get_nsproxy(struct nsproxy *ns)
        atomic_inc(&ns->count);
 }
 
-#ifdef CONFIG_CGROUP_NS
-int ns_cgroup_clone(struct task_struct *tsk, struct pid *pid);
-#else
-static inline int ns_cgroup_clone(struct task_struct *tsk, struct pid *pid)
-{
-       return 0;
-}
-#endif
-
 #endif
index 5e3aa8311c5ed40f2598ccd814162bef5173030e..4952fb874ad3dadd631b3e10f0ae35eb0df59135 100644 (file)
@@ -40,6 +40,8 @@ enum oom_constraint {
        CONSTRAINT_MEMCG,
 };
 
+extern int test_set_oom_score_adj(int new_val);
+
 extern unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem,
                        const nodemask_t *nodemask, unsigned long totalpages);
 extern int try_set_zonelist_oom(struct zonelist *zonelist, gfp_t gfp_flags);
index 811183de1ef5eb27792b0b272f7e513c6b78d457..6081493db68ff65aadcf3316128d0130a6973f1d 100644 (file)
@@ -308,7 +308,7 @@ static inline void SetPageUptodate(struct page *page)
 {
 #ifdef CONFIG_S390
        if (!test_and_set_bit(PG_uptodate, &page->flags))
-               page_clear_dirty(page, 0);
+               page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY, 0);
 #else
        /*
         * Memory barrier must be issued before setting the PG_uptodate bit,
index c119506526467d204b2c78a7d47bc0a7152129a4..716875e53520ecb4afe8ae7edd1e39a7eb75032a 100644 (file)
@@ -219,6 +219,12 @@ static inline struct page *page_cache_alloc_cold(struct address_space *x)
        return __page_cache_alloc(mapping_gfp_mask(x)|__GFP_COLD);
 }
 
+static inline struct page *page_cache_alloc_readahead(struct address_space *x)
+{
+       return __page_cache_alloc(mapping_gfp_mask(x) |
+                                 __GFP_COLD | __GFP_NORETRY | __GFP_NOWARN);
+}
+
 typedef int filler_t(void *, struct page *);
 
 extern struct page * find_get_page(struct address_space *mapping,
@@ -357,6 +363,15 @@ static inline int lock_page_or_retry(struct page *page, struct mm_struct *mm,
  */
 extern void wait_on_page_bit(struct page *page, int bit_nr);
 
+extern int wait_on_page_bit_killable(struct page *page, int bit_nr);
+
+static inline int wait_on_page_locked_killable(struct page *page)
+{
+       if (PageLocked(page))
+               return wait_on_page_bit_killable(page, PG_locked);
+       return 0;
+}
+
 /* 
  * Wait for a page to be unlocked.
  *
index 4604d1d5514d9b84bba1eecf8a254a2699fe5575..c446b5ca2d38e0e58b650b217bec0f0f90945dd7 100644 (file)
@@ -941,8 +941,11 @@ int pci_cfg_space_size_ext(struct pci_dev *dev);
 int pci_cfg_space_size(struct pci_dev *dev);
 unsigned char pci_bus_max_busnr(struct pci_bus *bus);
 
+#define PCI_VGA_STATE_CHANGE_BRIDGE (1 << 0)
+#define PCI_VGA_STATE_CHANGE_DECODES (1 << 1)
+
 int pci_set_vga_state(struct pci_dev *pdev, bool decode,
-                     unsigned int command_bits, bool change_bridge);
+                     unsigned int command_bits, u32 flags);
 /* kmem_cache style wrapper around pci_alloc_consistent() */
 
 #include <linux/pci-dma.h>
@@ -1087,7 +1090,7 @@ static inline int pci_proc_domain(struct pci_bus *bus)
 
 /* some architectures require additional setup to direct VGA traffic */
 typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode,
-                     unsigned int command_bits, bool change_bridge);
+                     unsigned int command_bits, u32 flags);
 extern void pci_register_set_vga_state(arch_set_vga_state_t func);
 
 #else /* CONFIG_PCI is not enabled */
index 24787b751286ef4d7f69b08f9a4e8791d1f3e9c3..a311008af5e1538c262990459fb2daefe7d8dddb 100644 (file)
 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX        0x1c5f
 #define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0     0x1d40
 #define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_1     0x1d41
+#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI  0x1e31
 #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN       0x1e40
 #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX       0x1e5f
 #define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MIN   0x2310
index 8b97308e65df3ccf094d79af23266e2da5fc73af..9ca008f0c542935440f3c39c0a5fb070dd6f5e8c 100644 (file)
@@ -259,6 +259,9 @@ extern void __bad_size_call_parameter(void);
  * Special handling for cmpxchg_double.  cmpxchg_double is passed two
  * percpu variables.  The first has to be aligned to a double word
  * boundary and the second has to follow directly thereafter.
+ * We enforce this on all architectures even if they don't support
+ * a double cmpxchg instruction, since it's a cheap requirement, and it
+ * avoids breaking the requirement for architectures with the instruction.
  */
 #define __pcpu_double_call_return_bool(stem, pcp1, pcp2, ...)          \
 ({                                                                     \
index 46f6ba56fa9139909c04acbad98383b7ed88babb..5edc9014263aca9e10cfda70dc4c5e3e8a94f8bb 100644 (file)
@@ -75,7 +75,7 @@ static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
        barrier();              /* Prevent reloads of fbc->count */
        if (ret >= 0)
                return ret;
-       return 1;
+       return 0;
 }
 
 static inline int percpu_counter_initialized(struct percpu_counter *fbc)
@@ -133,6 +133,10 @@ static inline s64 percpu_counter_read(struct percpu_counter *fbc)
        return fbc->count;
 }
 
+/*
+ * percpu_counter is intended to track positive numbers. In the UP case the
+ * number should never be negative.
+ */
 static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
 {
        return fbc->count;
index 3412684ce5d541176ba1e5b64f09244e8d3cdc45..e0786e35f247664a8fd9838dced3a46d4f71257c 100644 (file)
@@ -137,14 +137,14 @@ enum perf_event_sample_format {
  *
  * struct read_format {
  *     { u64           value;
- *       { u64         time_enabled; } && PERF_FORMAT_ENABLED
- *       { u64         time_running; } && PERF_FORMAT_RUNNING
+ *       { u64         time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
+ *       { u64         time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
  *       { u64         id;           } && PERF_FORMAT_ID
  *     } && !PERF_FORMAT_GROUP
  *
  *     { u64           nr;
- *       { u64         time_enabled; } && PERF_FORMAT_ENABLED
- *       { u64         time_running; } && PERF_FORMAT_RUNNING
+ *       { u64         time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
+ *       { u64         time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
  *       { u64         value;
  *         { u64       id;           } && PERF_FORMAT_ID
  *       }             cntr[nr];
index cdced84261d79d125a8d6031c76638b72d259c20..b152d44fb18122e0659a7cdabf0d6b782ef63d59 100644 (file)
@@ -105,7 +105,7 @@ extern struct pid_namespace init_pid_ns;
  * or rcu_read_lock() held.
  *
  * find_pid_ns() finds the pid in the namespace specified
- * find_vpid() finr the pid by its virtual id, i.e. in the current namespace
+ * find_vpid() finds the pid by its virtual id, i.e. in the current namespace
  *
  * see also find_task_by_vpid() set in include/linux/sched.h
  */
index 3160648ccdda1ffe47312d3b2e90b368f36898f3..411e4f4be52b984fa22f9a36502a8c2b79b18b4a 100644 (file)
@@ -425,7 +425,8 @@ struct dev_pm_info {
        pm_message_t            power_state;
        unsigned int            can_wakeup:1;
        unsigned int            async_suspend:1;
-       unsigned int            in_suspend:1;   /* Owned by the PM core */
+       bool                    is_prepared:1;  /* Owned by the PM core */
+       bool                    is_suspended:1; /* Ditto */
        spinlock_t              lock;
 #ifdef CONFIG_PM_SLEEP
        struct list_head        entry;
index 77cbddb3784cf7bf390e49e6035633f827d85175..a7d87f911cabbbe7b1c8d9eabb01c8667e86fb6d 100644 (file)
 #define PM_QOS_NUM_CLASSES 4
 #define PM_QOS_DEFAULT_VALUE -1
 
+#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE       (2000 * USEC_PER_SEC)
+#define PM_QOS_NETWORK_LAT_DEFAULT_VALUE       (2000 * USEC_PER_SEC)
+#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE        0
+
 struct pm_qos_request_list {
        struct plist_node list;
        int pm_qos_class;
diff --git a/include/linux/pnfs_osd_xdr.h b/include/linux/pnfs_osd_xdr.h
new file mode 100644 (file)
index 0000000..76efbdd
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ *  pNFS-osd on-the-wire data structures
+ *
+ *  Copyright (C) 2007 Panasas Inc. [year of first publication]
+ *  All rights reserved.
+ *
+ *  Benny Halevy <bhalevy@panasas.com>
+ *  Boaz Harrosh <bharrosh@panasas.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  See the file COPYING included with this distribution for more details.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the Panasas company nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __PNFS_OSD_XDR_H__
+#define __PNFS_OSD_XDR_H__
+
+#include <linux/nfs_fs.h>
+#include <linux/nfs_page.h>
+#include <scsi/osd_protocol.h>
+
+#define PNFS_OSD_OSDNAME_MAXSIZE 256
+
+/*
+ * draft-ietf-nfsv4-minorversion-22
+ * draft-ietf-nfsv4-pnfs-obj-12
+ */
+
+/* Layout Structure */
+
+enum pnfs_osd_raid_algorithm4 {
+       PNFS_OSD_RAID_0         = 1,
+       PNFS_OSD_RAID_4         = 2,
+       PNFS_OSD_RAID_5         = 3,
+       PNFS_OSD_RAID_PQ        = 4     /* Reed-Solomon P+Q */
+};
+
+/*   struct pnfs_osd_data_map4 {
+ *       uint32_t                    odm_num_comps;
+ *       length4                     odm_stripe_unit;
+ *       uint32_t                    odm_group_width;
+ *       uint32_t                    odm_group_depth;
+ *       uint32_t                    odm_mirror_cnt;
+ *       pnfs_osd_raid_algorithm4    odm_raid_algorithm;
+ *   };
+ */
+struct pnfs_osd_data_map {
+       u32     odm_num_comps;
+       u64     odm_stripe_unit;
+       u32     odm_group_width;
+       u32     odm_group_depth;
+       u32     odm_mirror_cnt;
+       u32     odm_raid_algorithm;
+};
+
+/*   struct pnfs_osd_objid4 {
+ *       deviceid4       oid_device_id;
+ *       uint64_t        oid_partition_id;
+ *       uint64_t        oid_object_id;
+ *   };
+ */
+struct pnfs_osd_objid {
+       struct nfs4_deviceid    oid_device_id;
+       u64                     oid_partition_id;
+       u64                     oid_object_id;
+};
+
+/* For printout. I use:
+ * kprint("dev(%llx:%llx)", _DEVID_LO(pointer), _DEVID_HI(pointer));
+ * BE style
+ */
+#define _DEVID_LO(oid_device_id) \
+       (unsigned long long)be64_to_cpup((__be64 *)(oid_device_id)->data)
+
+#define _DEVID_HI(oid_device_id) \
+       (unsigned long long)be64_to_cpup(((__be64 *)(oid_device_id)->data) + 1)
+
+static inline int
+pnfs_osd_objid_xdr_sz(void)
+{
+       return (NFS4_DEVICEID4_SIZE / 4) + 2 + 2;
+}
+
+enum pnfs_osd_version {
+       PNFS_OSD_MISSING              = 0,
+       PNFS_OSD_VERSION_1            = 1,
+       PNFS_OSD_VERSION_2            = 2
+};
+
+struct pnfs_osd_opaque_cred {
+       u32 cred_len;
+       void *cred;
+};
+
+enum pnfs_osd_cap_key_sec {
+       PNFS_OSD_CAP_KEY_SEC_NONE     = 0,
+       PNFS_OSD_CAP_KEY_SEC_SSV      = 1,
+};
+
+/*   struct pnfs_osd_object_cred4 {
+ *       pnfs_osd_objid4         oc_object_id;
+ *       pnfs_osd_version4       oc_osd_version;
+ *       pnfs_osd_cap_key_sec4   oc_cap_key_sec;
+ *       opaque                  oc_capability_key<>;
+ *       opaque                  oc_capability<>;
+ *   };
+ */
+struct pnfs_osd_object_cred {
+       struct pnfs_osd_objid           oc_object_id;
+       u32                             oc_osd_version;
+       u32                             oc_cap_key_sec;
+       struct pnfs_osd_opaque_cred     oc_cap_key;
+       struct pnfs_osd_opaque_cred     oc_cap;
+};
+
+/*   struct pnfs_osd_layout4 {
+ *       pnfs_osd_data_map4      olo_map;
+ *       uint32_t                olo_comps_index;
+ *       pnfs_osd_object_cred4   olo_components<>;
+ *   };
+ */
+struct pnfs_osd_layout {
+       struct pnfs_osd_data_map        olo_map;
+       u32                             olo_comps_index;
+       u32                             olo_num_comps;
+       struct pnfs_osd_object_cred     *olo_comps;
+};
+
+/* Device Address */
+enum pnfs_osd_targetid_type {
+       OBJ_TARGET_ANON = 1,
+       OBJ_TARGET_SCSI_NAME = 2,
+       OBJ_TARGET_SCSI_DEVICE_ID = 3,
+};
+
+/*   union pnfs_osd_targetid4 switch (pnfs_osd_targetid_type4 oti_type) {
+ *       case OBJ_TARGET_SCSI_NAME:
+ *           string              oti_scsi_name<>;
+ *
+ *       case OBJ_TARGET_SCSI_DEVICE_ID:
+ *           opaque              oti_scsi_device_id<>;
+ *
+ *       default:
+ *           void;
+ *   };
+ *
+ *   union pnfs_osd_targetaddr4 switch (bool ota_available) {
+ *       case TRUE:
+ *           netaddr4            ota_netaddr;
+ *       case FALSE:
+ *           void;
+ *   };
+ *
+ *   struct pnfs_osd_deviceaddr4 {
+ *       pnfs_osd_targetid4      oda_targetid;
+ *       pnfs_osd_targetaddr4    oda_targetaddr;
+ *       uint64_t                oda_lun;
+ *       opaque                  oda_systemid<>;
+ *       pnfs_osd_object_cred4   oda_root_obj_cred;
+ *       opaque                  oda_osdname<>;
+ *   };
+ */
+struct pnfs_osd_targetid {
+       u32                             oti_type;
+       struct nfs4_string              oti_scsi_device_id;
+};
+
+enum { PNFS_OSD_TARGETID_MAX = 1 + PNFS_OSD_OSDNAME_MAXSIZE / 4 };
+
+/*   struct netaddr4 {
+ *       // see struct rpcb in RFC1833
+ *       string r_netid<>;    // network id
+ *       string r_addr<>;     // universal address
+ *   };
+ */
+struct pnfs_osd_net_addr {
+       struct nfs4_string      r_netid;
+       struct nfs4_string      r_addr;
+};
+
+struct pnfs_osd_targetaddr {
+       u32                             ota_available;
+       struct pnfs_osd_net_addr        ota_netaddr;
+};
+
+enum {
+       NETWORK_ID_MAX = 16 / 4,
+       UNIVERSAL_ADDRESS_MAX = 64 / 4,
+       PNFS_OSD_TARGETADDR_MAX = 3 +  NETWORK_ID_MAX + UNIVERSAL_ADDRESS_MAX,
+};
+
+struct pnfs_osd_deviceaddr {
+       struct pnfs_osd_targetid        oda_targetid;
+       struct pnfs_osd_targetaddr      oda_targetaddr;
+       u8                              oda_lun[8];
+       struct nfs4_string              oda_systemid;
+       struct pnfs_osd_object_cred     oda_root_obj_cred;
+       struct nfs4_string              oda_osdname;
+};
+
+enum {
+       ODA_OSDNAME_MAX = PNFS_OSD_OSDNAME_MAXSIZE / 4,
+       PNFS_OSD_DEVICEADDR_MAX =
+               PNFS_OSD_TARGETID_MAX + PNFS_OSD_TARGETADDR_MAX +
+               2 /*oda_lun*/ +
+               1 + OSD_SYSTEMID_LEN +
+               1 + ODA_OSDNAME_MAX,
+};
+
+/* LAYOUTCOMMIT: layoutupdate */
+
+/*   union pnfs_osd_deltaspaceused4 switch (bool dsu_valid) {
+ *       case TRUE:
+ *           int64_t     dsu_delta;
+ *       case FALSE:
+ *           void;
+ *   };
+ *
+ *   struct pnfs_osd_layoutupdate4 {
+ *       pnfs_osd_deltaspaceused4    olu_delta_space_used;
+ *       bool                        olu_ioerr_flag;
+ *   };
+ */
+struct pnfs_osd_layoutupdate {
+       u32     dsu_valid;
+       s64     dsu_delta;
+       u32     olu_ioerr_flag;
+};
+
+/* LAYOUTRETURN: I/O Rrror Report */
+
+enum pnfs_osd_errno {
+       PNFS_OSD_ERR_EIO                = 1,
+       PNFS_OSD_ERR_NOT_FOUND          = 2,
+       PNFS_OSD_ERR_NO_SPACE           = 3,
+       PNFS_OSD_ERR_BAD_CRED           = 4,
+       PNFS_OSD_ERR_NO_ACCESS          = 5,
+       PNFS_OSD_ERR_UNREACHABLE        = 6,
+       PNFS_OSD_ERR_RESOURCE           = 7
+};
+
+/*   struct pnfs_osd_ioerr4 {
+ *       pnfs_osd_objid4     oer_component;
+ *       length4             oer_comp_offset;
+ *       length4             oer_comp_length;
+ *       bool                oer_iswrite;
+ *       pnfs_osd_errno4     oer_errno;
+ *   };
+ */
+struct pnfs_osd_ioerr {
+       struct pnfs_osd_objid   oer_component;
+       u64                     oer_comp_offset;
+       u64                     oer_comp_length;
+       u32                     oer_iswrite;
+       u32                     oer_errno;
+};
+
+/* OSD XDR API */
+/* Layout helpers */
+/* Layout decoding is done in two parts:
+ * 1. First Call pnfs_osd_xdr_decode_layout_map to read in only the header part
+ *    of the layout. @iter members need not be initialized.
+ *    Returned:
+ *             @layout members are set. (@layout->olo_comps set to NULL).
+ *
+ *             Zero on success, or negative error if passed xdr is broken.
+ *
+ * 2. 2nd Call pnfs_osd_xdr_decode_layout_comp() in a loop until it returns
+ *    false, to decode the next component.
+ *    Returned:
+ *       true if there is more to decode or false if we are done or error.
+ *
+ * Example:
+ *     struct pnfs_osd_xdr_decode_layout_iter iter;
+ *     struct pnfs_osd_layout layout;
+ *     struct pnfs_osd_object_cred comp;
+ *     int status;
+ *
+ *     status = pnfs_osd_xdr_decode_layout_map(&layout, &iter, xdr);
+ *     if (unlikely(status))
+ *             goto err;
+ *     while(pnfs_osd_xdr_decode_layout_comp(&comp, &iter, xdr, &status)) {
+ *             // All of @comp strings point to inside the xdr_buffer
+ *             // or scrach buffer. Copy them out to user memory eg.
+ *             copy_single_comp(dest_comp++, &comp);
+ *     }
+ *     if (unlikely(status))
+ *             goto err;
+ */
+
+struct pnfs_osd_xdr_decode_layout_iter {
+       unsigned total_comps;
+       unsigned decoded_comps;
+};
+
+extern int pnfs_osd_xdr_decode_layout_map(struct pnfs_osd_layout *layout,
+       struct pnfs_osd_xdr_decode_layout_iter *iter, struct xdr_stream *xdr);
+
+extern bool pnfs_osd_xdr_decode_layout_comp(struct pnfs_osd_object_cred *comp,
+       struct pnfs_osd_xdr_decode_layout_iter *iter, struct xdr_stream *xdr,
+       int *err);
+
+/* Device Info helpers */
+
+/* Note: All strings inside @deviceaddr point to space inside @p.
+ * @p should stay valid while @deviceaddr is in use.
+ */
+extern void pnfs_osd_xdr_decode_deviceaddr(
+       struct pnfs_osd_deviceaddr *deviceaddr, __be32 *p);
+
+/* layoutupdate (layout_commit) xdr helpers */
+extern int
+pnfs_osd_xdr_encode_layoutupdate(struct xdr_stream *xdr,
+                                struct pnfs_osd_layoutupdate *lou);
+
+/* osd_ioerror encoding/decoding (layout_return) */
+/* Client */
+extern __be32 *pnfs_osd_xdr_ioerr_reserve_space(struct xdr_stream *xdr);
+extern void pnfs_osd_xdr_encode_ioerr(__be32 *p, struct pnfs_osd_ioerr *ioerr);
+
+#endif /* __PNFS_OSD_XDR_H__ */
index 808227d40a645a7cabf83cb0d0c10cc04e2ac86d..959c14132f465f8f3d0f5f61cd6d2701c252ae30 100644 (file)
@@ -82,6 +82,7 @@ struct k_itimer {
                        unsigned long expires;
                } mmtimer;
                struct alarm alarmtimer;
+               struct rcu_head rcu;
        } it;
 };
 
similarity index 67%
rename from arch/arm/mach-s5p6442/include/mach/dma.h
rename to include/linux/power/isp1704_charger.h
index 81209eb1409b7ad4c55a70897379547991ea2958..68096a6aa2d7911411e860b9b87b90218894a3e6 100644 (file)
@@ -1,6 +1,7 @@
 /*
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *     Jaswinder Singh <jassi.brar@samsung.com>
+ * ISP1704 USB Charger Detection driver
+ *
+ * Copyright (C) 2011 Nokia 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
  *
  * 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.
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
-#ifndef __MACH_DMA_H
-#define __MACH_DMA_H
 
-/* This platform uses the common S3C DMA API driver for PL330 */
-#include <plat/s3c-dma-pl330.h>
+#ifndef __ISP1704_CHARGER_H
+#define __ISP1704_CHARGER_H
+
+struct isp1704_charger_data {
+       void            (*set_power)(bool on);
+};
 
-#endif /* __MACH_DMA_H */
+#endif
diff --git a/include/linux/power/max8903_charger.h b/include/linux/power/max8903_charger.h
new file mode 100644 (file)
index 0000000..24f51db
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * max8903_charger.h - Maxim 8903 USB/Adapter Charger Driver
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@samsung.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
+ *
+ */
+
+#ifndef __MAX8903_CHARGER_H__
+#define __MAX8903_CHARGER_H__
+
+struct max8903_pdata {
+       /*
+        * GPIOs
+        * cen, chg, flt, and usus are optional.
+        * dok, dcm, and uok are not optional depending on the status of
+        * dc_valid and usb_valid.
+        */
+       int cen;        /* Charger Enable input */
+       int dok;        /* DC(Adapter) Power OK output */
+       int uok;        /* USB Power OK output */
+       int chg;        /* Charger status output */
+       int flt;        /* Fault output */
+       int dcm;        /* Current-Limit Mode input (1: DC, 2: USB) */
+       int usus;       /* USB Suspend Input (1: suspended) */
+
+       /*
+        * DC(Adapter/TA) is wired
+        * When dc_valid is true,
+        *      dok and dcm should be valid.
+        *
+        * At least one of dc_valid or usb_valid should be true.
+        */
+       bool dc_valid;
+       /*
+        * USB is wired
+        * When usb_valid is true,
+        *      uok should be valid.
+        */
+       bool usb_valid;
+};
+
+#endif /* __MAX8903_CHARGER_H__ */
index ee048e77e1ae092f178e9d88675ea6cb1ae33019..0101d55d9651f3cc1dc48858ba0ca1b301ec6425 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __KERNEL_PRINTK__
 #define __KERNEL_PRINTK__
 
+#include <linux/init.h>
+
 extern const char linux_banner[];
 extern const char linux_proc_banner[];
 
@@ -113,6 +115,7 @@ extern int dmesg_restrict;
 extern int kptr_restrict;
 
 void log_buf_kexec_setup(void);
+void __init setup_log_buf(int early);
 #else
 static inline __attribute__ ((format (printf, 1, 0)))
 int vprintk(const char *s, va_list args)
@@ -137,6 +140,10 @@ static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies,
 static inline void log_buf_kexec_setup(void)
 {
 }
+
+static inline void setup_log_buf(int early)
+{
+}
 #endif
 
 extern void dump_stack(void) __cold;
index eaf4350c0f905bfb5e2dfa6380118fe805b1b785..e7576cf9e32d7bf8cdc1bb50230a42fb80d184ad 100644 (file)
@@ -173,11 +173,7 @@ extern void proc_net_remove(struct net *net, const char *name);
 extern struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name,
        struct proc_dir_entry *parent);
 
-/* While the {get|set|dup}_mm_exe_file functions are for mm_structs, they are
- * only needed to implement /proc/<pid>|self/exe so we define them here. */
-extern void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file);
-extern struct file *get_mm_exe_file(struct mm_struct *mm);
-extern void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm);
+extern struct file *proc_ns_fget(int fd);
 
 #else
 
@@ -228,19 +224,11 @@ static inline void pid_ns_release_proc(struct pid_namespace *ns)
 {
 }
 
-static inline void set_mm_exe_file(struct mm_struct *mm,
-                                  struct file *new_exe_file)
-{}
-
-static inline struct file *get_mm_exe_file(struct mm_struct *mm)
+static inline struct file *proc_ns_fget(int fd)
 {
-       return NULL;
+       return ERR_PTR(-EINVAL);
 }
 
-static inline void dup_mm_exe_file(struct mm_struct *oldmm,
-                                  struct mm_struct *newmm)
-{}
-
 #endif /* CONFIG_PROC_FS */
 
 #if !defined(CONFIG_PROC_KCORE)
@@ -252,6 +240,18 @@ kclist_add(struct kcore_list *new, void *addr, size_t size, int type)
 extern void kclist_add(struct kcore_list *, void *, size_t, int type);
 #endif
 
+struct nsproxy;
+struct proc_ns_operations {
+       const char *name;
+       int type;
+       void *(*get)(struct task_struct *task);
+       void (*put)(void *ns);
+       int (*install)(struct nsproxy *nsproxy, void *ns);
+};
+extern const struct proc_ns_operations netns_operations;
+extern const struct proc_ns_operations utsns_operations;
+extern const struct proc_ns_operations ipcns_operations;
+
 union proc_op {
        int (*proc_get_link)(struct inode *, struct path *);
        int (*proc_read)(struct task_struct *task, char *page);
@@ -270,6 +270,8 @@ struct proc_inode {
        struct proc_dir_entry *pde;
        struct ctl_table_header *sysctl;
        struct ctl_table *sysctl_entry;
+       void *ns;
+       const struct proc_ns_operations *ns_ops;
        struct inode vfs_inode;
 };
 
@@ -288,12 +290,4 @@ static inline struct net *PDE_NET(struct proc_dir_entry *pde)
        return pde->parent->data;
 }
 
-struct proc_maps_private {
-       struct pid *pid;
-       struct task_struct *task;
-#ifdef CONFIG_MMU
-       struct vm_area_struct *tail_vma;
-#endif
-};
-
 #endif /* _LINUX_PROC_FS_H */
index 943a85ab0020a289895d6069650a6d94867deb06..e07e2742a865a46d13740934a830b35dbde17af5 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <linux/if_ether.h>
 #include <linux/if_vlan.h>
+#include <linux/ip.h>
 #include <linux/filter.h>
 #ifdef __KERNEL__
 #include <linux/in.h>
 #define OFF_NEXT       6
 #define OFF_UDP_DST    2
 
+#define OFF_PTP_SOURCE_UUID    22 /* PTPv1 only */
+#define OFF_PTP_SEQUENCE_ID    30
+#define OFF_PTP_CONTROL                32 /* PTPv1 only */
+
+#define IPV4_HLEN(data) (((struct iphdr *)(data + OFF_IHL))->ihl << 2)
+
 #define IP6_HLEN       40
 #define UDP_HLEN       8
 
diff --git a/include/linux/ptp_clock.h b/include/linux/ptp_clock.h
new file mode 100644 (file)
index 0000000..94e981f
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * PTP 1588 clock support - user space interface
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  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.
+ */
+
+#ifndef _PTP_CLOCK_H_
+#define _PTP_CLOCK_H_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/* PTP_xxx bits, for the flags field within the request structures. */
+#define PTP_ENABLE_FEATURE (1<<0)
+#define PTP_RISING_EDGE    (1<<1)
+#define PTP_FALLING_EDGE   (1<<2)
+
+/*
+ * struct ptp_clock_time - represents a time value
+ *
+ * The sign of the seconds field applies to the whole value. The
+ * nanoseconds field is always unsigned. The reserved field is
+ * included for sub-nanosecond resolution, should the demand for
+ * this ever appear.
+ *
+ */
+struct ptp_clock_time {
+       __s64 sec;  /* seconds */
+       __u32 nsec; /* nanoseconds */
+       __u32 reserved;
+};
+
+struct ptp_clock_caps {
+       int max_adj;   /* Maximum frequency adjustment in parts per billon. */
+       int n_alarm;   /* Number of programmable alarms. */
+       int n_ext_ts;  /* Number of external time stamp channels. */
+       int n_per_out; /* Number of programmable periodic signals. */
+       int pps;       /* Whether the clock supports a PPS callback. */
+       int rsv[15];   /* Reserved for future use. */
+};
+
+struct ptp_extts_request {
+       unsigned int index;  /* Which channel to configure. */
+       unsigned int flags;  /* Bit field for PTP_xxx flags. */
+       unsigned int rsv[2]; /* Reserved for future use. */
+};
+
+struct ptp_perout_request {
+       struct ptp_clock_time start;  /* Absolute start time. */
+       struct ptp_clock_time period; /* Desired period, zero means disable. */
+       unsigned int index;           /* Which channel to configure. */
+       unsigned int flags;           /* Reserved for future use. */
+       unsigned int rsv[4];          /* Reserved for future use. */
+};
+
+#define PTP_CLK_MAGIC '='
+
+#define PTP_CLOCK_GETCAPS  _IOR(PTP_CLK_MAGIC, 1, struct ptp_clock_caps)
+#define PTP_EXTTS_REQUEST  _IOW(PTP_CLK_MAGIC, 2, struct ptp_extts_request)
+#define PTP_PEROUT_REQUEST _IOW(PTP_CLK_MAGIC, 3, struct ptp_perout_request)
+#define PTP_ENABLE_PPS     _IOW(PTP_CLK_MAGIC, 4, int)
+
+struct ptp_extts_event {
+       struct ptp_clock_time t; /* Time event occured. */
+       unsigned int index;      /* Which channel produced the event. */
+       unsigned int flags;      /* Reserved for future use. */
+       unsigned int rsv[2];     /* Reserved for future use. */
+};
+
+#endif
diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_kernel.h
new file mode 100644 (file)
index 0000000..dd2e44f
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * PTP 1588 clock support
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  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.
+ */
+
+#ifndef _PTP_CLOCK_KERNEL_H_
+#define _PTP_CLOCK_KERNEL_H_
+
+#include <linux/ptp_clock.h>
+
+
+struct ptp_clock_request {
+       enum {
+               PTP_CLK_REQ_EXTTS,
+               PTP_CLK_REQ_PEROUT,
+               PTP_CLK_REQ_PPS,
+       } type;
+       union {
+               struct ptp_extts_request extts;
+               struct ptp_perout_request perout;
+       };
+};
+
+/**
+ * struct ptp_clock_info - decribes a PTP hardware clock
+ *
+ * @owner:     The clock driver should set to THIS_MODULE.
+ * @name:      A short name to identify the clock.
+ * @max_adj:   The maximum possible frequency adjustment, in parts per billon.
+ * @n_alarm:   The number of programmable alarms.
+ * @n_ext_ts:  The number of external time stamp channels.
+ * @n_per_out: The number of programmable periodic signals.
+ * @pps:       Indicates whether the clock supports a PPS callback.
+ *
+ * clock operations
+ *
+ * @adjfreq:  Adjusts the frequency of the hardware clock.
+ *            parameter delta: Desired period change in parts per billion.
+ *
+ * @adjtime:  Shifts the time of the hardware clock.
+ *            parameter delta: Desired change in nanoseconds.
+ *
+ * @gettime:  Reads the current time from the hardware clock.
+ *            parameter ts: Holds the result.
+ *
+ * @settime:  Set the current time on the hardware clock.
+ *            parameter ts: Time value to set.
+ *
+ * @enable:   Request driver to enable or disable an ancillary feature.
+ *            parameter request: Desired resource to enable or disable.
+ *            parameter on: Caller passes one to enable or zero to disable.
+ *
+ * Drivers should embed their ptp_clock_info within a private
+ * structure, obtaining a reference to it using container_of().
+ *
+ * The callbacks must all return zero on success, non-zero otherwise.
+ */
+
+struct ptp_clock_info {
+       struct module *owner;
+       char name[16];
+       s32 max_adj;
+       int n_alarm;
+       int n_ext_ts;
+       int n_per_out;
+       int pps;
+       int (*adjfreq)(struct ptp_clock_info *ptp, s32 delta);
+       int (*adjtime)(struct ptp_clock_info *ptp, s64 delta);
+       int (*gettime)(struct ptp_clock_info *ptp, struct timespec *ts);
+       int (*settime)(struct ptp_clock_info *ptp, const struct timespec *ts);
+       int (*enable)(struct ptp_clock_info *ptp,
+                     struct ptp_clock_request *request, int on);
+};
+
+struct ptp_clock;
+
+/**
+ * ptp_clock_register() - register a PTP hardware clock driver
+ *
+ * @info:  Structure describing the new clock.
+ */
+
+extern struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info);
+
+/**
+ * ptp_clock_unregister() - unregister a PTP hardware clock driver
+ *
+ * @ptp:  The clock to remove from service.
+ */
+
+extern int ptp_clock_unregister(struct ptp_clock *ptp);
+
+
+enum ptp_clock_events {
+       PTP_CLOCK_ALARM,
+       PTP_CLOCK_EXTTS,
+       PTP_CLOCK_PPS,
+};
+
+/**
+ * struct ptp_clock_event - decribes a PTP hardware clock event
+ *
+ * @type:  One of the ptp_clock_events enumeration values.
+ * @index: Identifies the source of the event.
+ * @timestamp: When the event occured.
+ */
+
+struct ptp_clock_event {
+       int type;
+       int index;
+       u64 timestamp;
+};
+
+/**
+ * ptp_clock_event() - notify the PTP layer about an event
+ *
+ * @ptp:    The clock obtained from ptp_clock_register().
+ * @event:  Message structure describing the event.
+ */
+
+extern void ptp_clock_event(struct ptp_clock *ptp,
+                           struct ptp_clock_event *event);
+
+#endif
index 03ff67b0cdf5403deab6f69924c3f9a419e644db..2f007157fab9b9f51370136658b0918f85d15e9a 100644 (file)
@@ -41,4 +41,44 @@ extern struct ratelimit_state printk_ratelimit_state;
 extern int ___ratelimit(struct ratelimit_state *rs, const char *func);
 #define __ratelimit(state) ___ratelimit(state, __func__)
 
+#ifdef CONFIG_PRINTK
+
+#define WARN_ON_RATELIMIT(condition, state)                    \
+               WARN_ON((condition) && __ratelimit(state))
+
+#define __WARN_RATELIMIT(condition, state, format...)          \
+({                                                             \
+       int rtn = 0;                                            \
+       if (unlikely(__ratelimit(state)))                       \
+               rtn = WARN(condition, format);                  \
+       rtn;                                                    \
+})
+
+#define WARN_RATELIMIT(condition, format...)                   \
+({                                                             \
+       static DEFINE_RATELIMIT_STATE(_rs,                      \
+                                     DEFAULT_RATELIMIT_INTERVAL,       \
+                                     DEFAULT_RATELIMIT_BURST); \
+       __WARN_RATELIMIT(condition, &_rs, format);              \
+})
+
+#else
+
+#define WARN_ON_RATELIMIT(condition, state)                    \
+       WARN_ON(condition)
+
+#define __WARN_RATELIMIT(condition, state, format...)          \
+({                                                             \
+       int rtn = WARN(condition, format);                      \
+       rtn;                                                    \
+})
+
+#define WARN_RATELIMIT(condition, format...)                   \
+({                                                             \
+       int rtn = WARN(condition, format);                      \
+       rtn;                                                    \
+})
+
+#endif
+
 #endif /* _LINUX_RATELIMIT_H */
diff --git a/include/linux/regulator/db8500-prcmu.h b/include/linux/regulator/db8500-prcmu.h
new file mode 100644 (file)
index 0000000..6120623
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ *
+ * Interface to power domain regulators on DB8500
+ */
+
+#ifndef __REGULATOR_H__
+#define __REGULATOR_H__
+
+/* Number of DB8500 regulators and regulator enumeration */
+enum db8500_regulator_id {
+       DB8500_REGULATOR_VAPE,
+       DB8500_REGULATOR_VARM,
+       DB8500_REGULATOR_VMODEM,
+       DB8500_REGULATOR_VPLL,
+       DB8500_REGULATOR_VSMPS1,
+       DB8500_REGULATOR_VSMPS2,
+       DB8500_REGULATOR_VSMPS3,
+       DB8500_REGULATOR_VRF1,
+       DB8500_REGULATOR_SWITCH_SVAMMDSP,
+       DB8500_REGULATOR_SWITCH_SVAMMDSPRET,
+       DB8500_REGULATOR_SWITCH_SVAPIPE,
+       DB8500_REGULATOR_SWITCH_SIAMMDSP,
+       DB8500_REGULATOR_SWITCH_SIAMMDSPRET,
+       DB8500_REGULATOR_SWITCH_SIAPIPE,
+       DB8500_REGULATOR_SWITCH_SGA,
+       DB8500_REGULATOR_SWITCH_B2R2_MCDE,
+       DB8500_REGULATOR_SWITCH_ESRAM12,
+       DB8500_REGULATOR_SWITCH_ESRAM12RET,
+       DB8500_REGULATOR_SWITCH_ESRAM34,
+       DB8500_REGULATOR_SWITCH_ESRAM34RET,
+       DB8500_NUM_REGULATORS
+};
+
+/*
+ * Exported interface for CPUIdle only. This function is called with all
+ * interrupts turned off.
+ */
+int power_state_active_is_enabled(void);
+
+#endif
index c4c4fc45f856ee7ee57b4a9234827aafa3242f61..ce3127a75c8866a27afeeb875bd5943c2dc61976 100644 (file)
@@ -68,6 +68,8 @@ struct regulator_state {
  *
  * @min_uV: Smallest voltage consumers may set.
  * @max_uV: Largest voltage consumers may set.
+ * @uV_offset: Offset applied to voltages from consumer to compensate for
+ *             voltage drops.
  *
  * @min_uA: Smallest consumers consumers may set.
  * @max_uA: Largest current consumers may set.
@@ -99,6 +101,8 @@ struct regulation_constraints {
        int min_uV;
        int max_uV;
 
+       int uV_offset;
+
        /* current output range (inclusive) - for current control */
        int min_uA;
        int max_uA;
@@ -160,8 +164,6 @@ struct regulator_consumer_supply {
  * @supply_regulator: Parent regulator.  Specified using the regulator name
  *                    as it appears in the name field in sysfs, which can
  *                    be explicitly set using the constraints field 'name'.
- * @supply_regulator_dev: Parent regulator (if any) - DEPRECATED in favour
- *                        of supply_regulator.
  *
  * @constraints: Constraints.  These must be specified for the regulator to
  *               be usable.
@@ -173,7 +175,6 @@ struct regulator_consumer_supply {
  */
 struct regulator_init_data {
        const char *supply_regulator;        /* or NULL for system supply */
-       struct device *supply_regulator_dev; /* or NULL for system supply */
 
        struct regulation_constraints constraints;
 
diff --git a/include/linux/rfkill-gpio.h b/include/linux/rfkill-gpio.h
new file mode 100644 (file)
index 0000000..a175d05
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2011, NVIDIA 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.
+ *
+ * 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 __RFKILL_GPIO_H
+#define __RFKILL_GPIO_H
+
+#include <linux/types.h>
+#include <linux/rfkill.h>
+
+/**
+ * struct rfkill_gpio_platform_data - platform data for rfkill gpio device.
+ * for unused gpio's, the expected value is -1.
+ * @name:              name for the gpio rf kill instance
+ * @reset_gpio:                GPIO which is used for reseting rfkill switch
+ * @shutdown_gpio:     GPIO which is used for shutdown of rfkill switch
+ * @power_clk_name:    [optional] name of clk to turn off while blocked
+ */
+
+struct rfkill_gpio_platform_data {
+       char                    *name;
+       int                     reset_gpio;
+       int                     shutdown_gpio;
+       const char              *power_clk_name;
+       enum rfkill_type        type;
+};
+
+#endif /* __RFKILL_GPIO_H */
index 830e65dc01ee1f264e715632f2f99fd95c7bd529..2148b122779b5a2fd8421c5e15cfc9ca91ea85ff 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/memcontrol.h>
 
 /*
@@ -26,7 +26,7 @@
  */
 struct anon_vma {
        struct anon_vma *root;  /* Root of this anon_vma tree */
-       spinlock_t lock;        /* Serialize access to vma list */
+       struct mutex mutex;     /* Serialize access to vma list */
        /*
         * The refcount is taken on an anon_vma when there is no
         * guarantee that the vma of page tables will exist for
@@ -64,7 +64,7 @@ struct anon_vma_chain {
        struct vm_area_struct *vma;
        struct anon_vma *anon_vma;
        struct list_head same_vma;   /* locked by mmap_sem & page_table_lock */
-       struct list_head same_anon_vma; /* locked by anon_vma->lock */
+       struct list_head same_anon_vma; /* locked by anon_vma->mutex */
 };
 
 #ifdef CONFIG_MMU
@@ -93,24 +93,24 @@ static inline void vma_lock_anon_vma(struct vm_area_struct *vma)
 {
        struct anon_vma *anon_vma = vma->anon_vma;
        if (anon_vma)
-               spin_lock(&anon_vma->root->lock);
+               mutex_lock(&anon_vma->root->mutex);
 }
 
 static inline void vma_unlock_anon_vma(struct vm_area_struct *vma)
 {
        struct anon_vma *anon_vma = vma->anon_vma;
        if (anon_vma)
-               spin_unlock(&anon_vma->root->lock);
+               mutex_unlock(&anon_vma->root->mutex);
 }
 
 static inline void anon_vma_lock(struct anon_vma *anon_vma)
 {
-       spin_lock(&anon_vma->root->lock);
+       mutex_lock(&anon_vma->root->mutex);
 }
 
 static inline void anon_vma_unlock(struct anon_vma *anon_vma)
 {
-       spin_unlock(&anon_vma->root->lock);
+       mutex_unlock(&anon_vma->root->mutex);
 }
 
 /*
@@ -218,20 +218,7 @@ int try_to_munlock(struct page *);
 /*
  * Called by memory-failure.c to kill processes.
  */
-struct anon_vma *__page_lock_anon_vma(struct page *page);
-
-static inline struct anon_vma *page_lock_anon_vma(struct page *page)
-{
-       struct anon_vma *anon_vma;
-
-       __cond_lock(RCU, anon_vma = __page_lock_anon_vma(page));
-
-       /* (void) is needed to make gcc happy */
-       (void) __cond_lock(&anon_vma->root->lock, anon_vma);
-
-       return anon_vma;
-}
-
+struct anon_vma *page_lock_anon_vma(struct page *page);
 void page_unlock_anon_vma(struct anon_vma *anon_vma);
 int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma);
 
index 215278b8df2aba5ca56f5eef120ef7b782523da6..3f594dce571650c76253a785e8720490a7c0f80e 100644 (file)
@@ -10,6 +10,7 @@ struct rotary_encoder_platform_data {
        unsigned int inverted_b;
        bool relative_axis;
        bool rollover;
+       bool half_period;
 };
 
 #endif /* __ROTARY_ENCODER_H__ */
index 877ece45426f6c3eb0fa3850f0c93db0ee84468a..b27ebea25660bff86dbdf2f86040f26904ab45c7 100644 (file)
@@ -92,10 +92,10 @@ struct rtc_pll_info {
 #define RTC_PLL_SET    _IOW('p', 0x12, struct rtc_pll_info)  /* Set PLL correction */
 
 /* interrupt flags */
-#define RTC_IRQF 0x80 /* any of the following is active */
-#define RTC_PF 0x40
-#define RTC_AF 0x20
-#define RTC_UF 0x10
+#define RTC_IRQF 0x80  /* Any of the following is active */
+#define RTC_PF 0x40    /* Periodic interrupt */
+#define RTC_AF 0x20    /* Alarm interrupt */
+#define RTC_UF 0x10    /* Update interrupt for 1Hz RTC */
 
 #ifdef __KERNEL__
 
index aaf71e08222ca70e0984e374bfe2e4ee66a4ce7c..a837b20ba190330c23b59ec5a3fb584fc9f6308f 100644 (file)
@@ -513,6 +513,7 @@ struct thread_group_cputimer {
        spinlock_t lock;
 };
 
+#include <linux/rwsem.h>
 struct autogroup;
 
 /*
@@ -632,6 +633,16 @@ struct signal_struct {
        unsigned audit_tty;
        struct tty_audit_buf *tty_audit_buf;
 #endif
+#ifdef CONFIG_CGROUPS
+       /*
+        * The threadgroup_fork_lock prevents threads from forking with
+        * CLONE_THREAD while held for writing. Use this for fork-sensitive
+        * threadgroup-wide operations. It's taken for reading in fork.c in
+        * copy_process().
+        * Currently only needed write-side by cgroups.
+        */
+       struct rw_semaphore threadgroup_fork_lock;
+#endif
 
        int oom_adj;            /* OOM kill score adjustment (bit shift) */
        int oom_score_adj;      /* OOM kill score adjustment */
@@ -1052,6 +1063,7 @@ struct sched_domain;
  */
 #define WF_SYNC                0x01            /* waker goes to sleep after wakup */
 #define WF_FORK                0x02            /* child wakeup after fork */
+#define WF_MIGRATED    0x04            /* internal use, task got migrated */
 
 #define ENQUEUE_WAKEUP         1
 #define ENQUEUE_HEAD           2
@@ -1535,7 +1547,7 @@ struct task_struct {
 #ifdef CONFIG_TRACING
        /* state flags for use by tracers */
        unsigned long trace;
-       /* bitmask of trace recursion */
+       /* bitmask and counter of trace recursion */
        unsigned long trace_recursion;
 #endif /* CONFIG_TRACING */
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR /* memcg uses this to do batch job */
@@ -1753,7 +1765,6 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
 #define PF_FROZEN      0x00010000      /* frozen for system suspend */
 #define PF_FSTRANS     0x00020000      /* inside a filesystem transaction */
 #define PF_KSWAPD      0x00040000      /* I am kswapd */
-#define PF_OOM_ORIGIN  0x00080000      /* Allocating much memory to others */
 #define PF_LESS_THROTTLE 0x00100000    /* Throttle me less: I clean memory */
 #define PF_KTHREAD     0x00200000      /* I am a kernel thread */
 #define PF_RANDOMIZE   0x00400000      /* randomize virtual address space */
@@ -1831,9 +1842,16 @@ static inline void rcu_copy_process(struct task_struct *p)
 #endif
 
 #ifdef CONFIG_SMP
+extern void do_set_cpus_allowed(struct task_struct *p,
+                              const struct cpumask *new_mask);
+
 extern int set_cpus_allowed_ptr(struct task_struct *p,
                                const struct cpumask *new_mask);
 #else
+static inline void do_set_cpus_allowed(struct task_struct *p,
+                                     const struct cpumask *new_mask)
+{
+}
 static inline int set_cpus_allowed_ptr(struct task_struct *p,
                                       const struct cpumask *new_mask)
 {
@@ -2323,6 +2341,31 @@ static inline void unlock_task_sighand(struct task_struct *tsk,
        spin_unlock_irqrestore(&tsk->sighand->siglock, *flags);
 }
 
+/* See the declaration of threadgroup_fork_lock in signal_struct. */
+#ifdef CONFIG_CGROUPS
+static inline void threadgroup_fork_read_lock(struct task_struct *tsk)
+{
+       down_read(&tsk->signal->threadgroup_fork_lock);
+}
+static inline void threadgroup_fork_read_unlock(struct task_struct *tsk)
+{
+       up_read(&tsk->signal->threadgroup_fork_lock);
+}
+static inline void threadgroup_fork_write_lock(struct task_struct *tsk)
+{
+       down_write(&tsk->signal->threadgroup_fork_lock);
+}
+static inline void threadgroup_fork_write_unlock(struct task_struct *tsk)
+{
+       up_write(&tsk->signal->threadgroup_fork_lock);
+}
+#else
+static inline void threadgroup_fork_read_lock(struct task_struct *tsk) {}
+static inline void threadgroup_fork_read_unlock(struct task_struct *tsk) {}
+static inline void threadgroup_fork_write_lock(struct task_struct *tsk) {}
+static inline void threadgroup_fork_write_unlock(struct task_struct *tsk) {}
+#endif
+
 #ifndef __HAVE_THREAD_FUNCTIONS
 
 #define task_thread_info(task) ((struct thread_info *)(task)->stack)
index 06d69648fc86c3a731c528cde7fba3b72a2688be..c6db9fb33c448f28197ffb6d135689daf58625b6 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <linux/spinlock.h>
 #include <linux/preempt.h>
+#include <asm/processor.h>
 
 typedef struct {
        unsigned sequence;
@@ -41,9 +42,6 @@ typedef struct {
 #define __SEQLOCK_UNLOCKED(lockname) \
                 { 0, __SPIN_LOCK_UNLOCKED(lockname) }
 
-#define SEQLOCK_UNLOCKED \
-                __SEQLOCK_UNLOCKED(old_style_seqlock_init)
-
 #define seqlock_init(x)                                        \
        do {                                            \
                (x)->sequence = 0;                      \
index 399be5ad2f996cb0124412d68a9f1b191cc1e685..2b7fec840517ff00ae46d14b0662bbf85bb4dc62 100644 (file)
@@ -9,6 +9,8 @@
 
 #define SHMEM_NR_DIRECT 16
 
+#define SHMEM_SYMLINK_INLINE_LEN (SHMEM_NR_DIRECT * sizeof(swp_entry_t))
+
 struct shmem_inode_info {
        spinlock_t              lock;
        unsigned long           flags;
@@ -17,8 +19,12 @@ struct shmem_inode_info {
        unsigned long           next_index;     /* highest alloced index + 1 */
        struct shared_policy    policy;         /* NUMA memory alloc policy */
        struct page             *i_indirect;    /* top indirect blocks page */
-       swp_entry_t             i_direct[SHMEM_NR_DIRECT]; /* first blocks */
+       union {
+               swp_entry_t     i_direct[SHMEM_NR_DIRECT]; /* first blocks */
+               char            inline_symlink[SHMEM_SYMLINK_INLINE_LEN];
+       };
        struct list_head        swaplist;       /* chain of maybes on swap */
+       struct list_head        xattr_list;     /* list of shmem_xattr */
        struct inode            vfs_inode;
 };
 
index e8b78ce144741fda866f79bd32ce3c96ba0c4096..c0a4f3ab0cc047490eb9eaf20d9cf577cc5c2d65 100644 (file)
@@ -1256,6 +1256,11 @@ static inline void skb_reserve(struct sk_buff *skb, int len)
        skb->tail += len;
 }
 
+static inline void skb_reset_mac_len(struct sk_buff *skb)
+{
+       skb->mac_len = skb->network_header - skb->mac_header;
+}
+
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
 static inline unsigned char *skb_transport_header(const struct sk_buff *skb)
 {
index 74243c86ba39fd475c3188083f95d0f367133498..8cc38d3bab0c57a79f68fe53e4915f9393335cba 100644 (file)
@@ -85,12 +85,15 @@ int smp_call_function_any(const struct cpumask *mask,
  * Generic and arch helpers
  */
 #ifdef CONFIG_USE_GENERIC_SMP_HELPERS
+void __init call_function_init(void);
 void generic_smp_call_function_single_interrupt(void);
 void generic_smp_call_function_interrupt(void);
 void ipi_call_lock(void);
 void ipi_call_unlock(void);
 void ipi_call_lock_irq(void);
 void ipi_call_unlock_irq(void);
+#else
+static inline void call_function_init(void) { }
 #endif
 
 /*
@@ -98,16 +101,6 @@ void ipi_call_unlock_irq(void);
  */
 int on_each_cpu(smp_call_func_t func, void *info, int wait);
 
-#define MSG_ALL_BUT_SELF       0x8000  /* Assume <32768 CPU's */
-#define MSG_ALL                        0x8001
-
-#define MSG_INVALIDATE_TLB     0x0001  /* Remote processor TLB invalidate */
-#define MSG_STOP_CPU           0x0002  /* Sent to shut down slave CPU's
-                                        * when rebooting
-                                        */
-#define MSG_RESCHEDULE         0x0003  /* Reschedule request from master CPU*/
-#define MSG_CALL_FUNCTION       0x0004  /* Call function on all other CPUs */
-
 /*
  * Mark the boot cpu "online" so that it can call console drivers in
  * printk() and can access its per-cpu storage.
@@ -144,7 +137,7 @@ static inline void smp_send_reschedule(int cpu) { }
 #define smp_prepare_boot_cpu()                 do {} while (0)
 #define smp_call_function_many(mask, func, info, wait) \
                        (up_smp_call_function(func, info))
-static inline void init_call_single_data(void) { }
+static inline void call_function_init(void) { }
 
 static inline int
 smp_call_function_any(const struct cpumask *mask, smp_call_func_t func,
index 92bd0839d5b49a414f8cd23fef827403ed965bab..c64de9dd7631bb44232eeca7d8080c62521c5b1e 100644 (file)
@@ -14,7 +14,8 @@ enum ads7846_filter {
 struct ads7846_platform_data {
        u16     model;                  /* 7843, 7845, 7846, 7873. */
        u16     vref_delay_usecs;       /* 0 for external vref; etc */
-       u16     vref_mv;                /* external vref value, milliVolts */
+       u16     vref_mv;                /* external vref value, milliVolts
+                                        * ads7846: if 0, use internal vref */
        bool    keep_vref_on;           /* set to keep vref on for differential
                                         * measurements as well */
        bool    swap_xy;                /* swap x and y axes */
index b4d7710bc38d2b26effd6025243150490e0a26a9..bb4f5fbbbd8e8ba1cfcfaed6b99533ec8a68ca0e 100644 (file)
@@ -581,7 +581,7 @@ extern int spi_bus_unlock(struct spi_master *master);
  * Callable only from contexts that can sleep.
  */
 static inline int
-spi_write(struct spi_device *spi, const u8 *buf, size_t len)
+spi_write(struct spi_device *spi, const void *buf, size_t len)
 {
        struct spi_transfer     t = {
                        .tx_buf         = buf,
@@ -605,7 +605,7 @@ spi_write(struct spi_device *spi, const u8 *buf, size_t len)
  * Callable only from contexts that can sleep.
  */
 static inline int
-spi_read(struct spi_device *spi, u8 *buf, size_t len)
+spi_read(struct spi_device *spi, void *buf, size_t len)
 {
        struct spi_transfer     t = {
                        .rx_buf         = buf,
@@ -620,8 +620,8 @@ spi_read(struct spi_device *spi, u8 *buf, size_t len)
 
 /* this copies txbuf and rxbuf data; for small transfers only! */
 extern int spi_write_then_read(struct spi_device *spi,
-               const u8 *txbuf, unsigned n_tx,
-               u8 *rxbuf, unsigned n_rx);
+               const void *txbuf, unsigned n_tx,
+               void *rxbuf, unsigned n_rx);
 
 /**
  * spi_w8r8 - SPI synchronous 8 bit write followed by 8 bit read
diff --git a/include/linux/sunrpc/gss_krb5_enctypes.h b/include/linux/sunrpc/gss_krb5_enctypes.h
new file mode 100644 (file)
index 0000000..ec6234e
--- /dev/null
@@ -0,0 +1,4 @@
+/*
+ * Dumb way to share this static piece of information with nfsd
+ */
+#define KRB5_SUPPORTED_ENCTYPES "18,17,16,23,3,1,2"
index 77e624883393ccd855ed2ae189270547a141d2c7..c68a147939a63ef9a6b04e08c9aef27e97621c31 100644 (file)
@@ -145,6 +145,7 @@ typedef __be32      rpc_fraghdr;
 #define RPCBIND_NETID_TCP      "tcp"
 #define RPCBIND_NETID_UDP6     "udp6"
 #define RPCBIND_NETID_TCP6     "tcp6"
+#define RPCBIND_NETID_LOCAL    "local"
 
 /*
  * Note that RFC 1833 does not put any size restrictions on the
index f73c482ec9c6080cc5201c047546928c53c8b723..fe2d8e6b923b416908220e2ef70bed01dee60897 100644 (file)
@@ -84,7 +84,8 @@ struct rpc_task {
 #endif
        unsigned char           tk_priority : 2,/* Task priority */
                                tk_garb_retry : 2,
-                               tk_cred_retry : 2;
+                               tk_cred_retry : 2,
+                               tk_rebind_retry : 2;
 };
 #define tk_xprt                        tk_client->cl_xprt
 
index 04dba23c59f2c4aead01ab313127368a63b93a05..85c50b40759de9df4528077a64b6346a472f9dfb 100644 (file)
@@ -28,6 +28,7 @@ struct svc_sock {
        /* private TCP part */
        u32                     sk_reclen;      /* length of record */
        u32                     sk_tcplen;      /* current read length */
+       struct page *           sk_pages[RPCSVC_MAXPAGES];      /* received data */
 };
 
 /*
index fc84b7a19ca3322659d03f504c87a6f9be27b7db..a20970ef9e4ebbf5b95aa224d11d30cef7ca7411 100644 (file)
@@ -216,6 +216,8 @@ extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
 extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
                unsigned int base, unsigned int len);
 extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
+extern void xdr_init_decode_pages(struct xdr_stream *xdr, struct xdr_buf *buf,
+               struct page **pages, unsigned int len);
 extern void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen);
 extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
 extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
index a0f998c07c65ec142dc89bce5ff4c117ff5ad808..81cce3b3ee668195f406988cf35ef43394b8e846 100644 (file)
@@ -141,7 +141,8 @@ enum xprt_transports {
        XPRT_TRANSPORT_UDP      = IPPROTO_UDP,
        XPRT_TRANSPORT_TCP      = IPPROTO_TCP,
        XPRT_TRANSPORT_BC_TCP   = IPPROTO_TCP | XPRT_TRANSPORT_BC,
-       XPRT_TRANSPORT_RDMA     = 256
+       XPRT_TRANSPORT_RDMA     = 256,
+       XPRT_TRANSPORT_LOCAL    = 257,
 };
 
 struct rpc_xprt {
index a5c6da5d8df8dd5ad28b6b9525bfa787caa3e74d..e70564647039fdcbdf5516aa9f8a9ed1cffd4d6d 100644 (file)
@@ -257,7 +257,8 @@ extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem,
 extern unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
                                                gfp_t gfp_mask, bool noswap,
                                                unsigned int swappiness,
-                                               struct zone *zone);
+                                               struct zone *zone,
+                                               unsigned long *nr_scanned);
 extern int __isolate_lru_page(struct page *page, int mode, int file);
 extern unsigned long shrink_all_memory(unsigned long nr_pages);
 extern int vm_swappiness;
@@ -357,6 +358,7 @@ struct backing_dev_info;
 extern struct mm_struct *swap_token_mm;
 extern void grab_swap_token(struct mm_struct *);
 extern void __put_swap_token(struct mm_struct *);
+extern void disable_swap_token(struct mem_cgroup *memcg);
 
 static inline int has_swap_token(struct mm_struct *mm)
 {
@@ -369,11 +371,6 @@ static inline void put_swap_token(struct mm_struct *mm)
                __put_swap_token(mm);
 }
 
-static inline void disable_swap_token(void)
-{
-       put_swap_token(swap_token_mm);
-}
-
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR
 extern void
 mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout);
@@ -499,7 +496,7 @@ static inline int has_swap_token(struct mm_struct *mm)
        return 0;
 }
 
-static inline void disable_swap_token(void)
+static inline void disable_swap_token(struct mem_cgroup *memcg)
 {
 }
 
index 8c0e349f4a6cb83f616f1d0046c1db7ab504d531..445702c60d0468c38a14aa0624e3bb1c1df29a5c 100644 (file)
@@ -24,6 +24,7 @@ extern int swiotlb_force;
 
 extern void swiotlb_init(int verbose);
 extern void swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose);
+extern unsigned long swioltb_nr_tbl(void);
 
 /*
  * Enumeration for sync targets
index ab71447d0c5ad7d470751b856cb4869960ad1fee..8c03b98df5f93d196d523c60f31a850ffe9a22e4 100644 (file)
@@ -846,4 +846,5 @@ asmlinkage long sys_name_to_handle_at(int dfd, const char __user *name,
 asmlinkage long sys_open_by_handle_at(int mountdirfd,
                                      struct file_handle __user *handle,
                                      int flags);
+asmlinkage long sys_setns(int fd, int nstype);
 #endif
index c3acda60eee0819f9735e059b925ed739bf5831e..e2696d76a59956eeea4bb3431fddc3b7ecbc4780 100644 (file)
@@ -177,9 +177,6 @@ struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
 struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd);
 void sysfs_put(struct sysfs_dirent *sd);
 
-/* Called to clear a ns tag when it is no longer valid */
-void sysfs_exit_ns(enum kobj_ns_type type, const void *tag);
-
 int __must_check sysfs_init(void);
 
 #else /* CONFIG_SYSFS */
@@ -338,10 +335,6 @@ static inline void sysfs_put(struct sysfs_dirent *sd)
 {
 }
 
-static inline void sysfs_exit_ns(int type, const void *tag)
-{
-}
-
 static inline int __must_check sysfs_init(void)
 {
        return 0;
index b91a40e847d236d9046dc3154a7e7a58ea594776..fc839bfa7935aff66380a22e9b95589127ec66d2 100644 (file)
@@ -60,7 +60,7 @@ int arch_update_cpu_topology(void);
  * (in whatever arch specific measurement units returned by node_distance())
  * then switch on zone reclaim on boot.
  */
-#define RECLAIM_DISTANCE 20
+#define RECLAIM_DISTANCE 30
 #endif
 #ifndef PENALTY_FOR_NODE_WITH_CPUS
 #define PENALTY_FOR_NODE_WITH_CPUS     (1)
index 5b07792ccb46cb62280438159f3f6e3f00de573d..ff7dc08696a8cc67c812ea516e9bcd9fee9c53c7 100644 (file)
@@ -76,7 +76,7 @@
  *     tty device.  It is solely the responsibility of the line
  *     discipline to handle poll requests.
  *
- * unsigned int (*receive_buf)(struct tty_struct *, const unsigned char *cp,
+ * void        (*receive_buf)(struct tty_struct *, const unsigned char *cp,
  *                    char *fp, int count);
  *
  *     This function is called by the low-level tty driver to send
@@ -84,8 +84,7 @@
  *     processing.  <cp> is a pointer to the buffer of input
  *     character received by the device.  <fp> is a pointer to a
  *     pointer of flag bytes which indicate whether a character was
- *     received with a parity error, etc. Returns the amount of bytes
- *     received.
+ *     received with a parity error, etc.
  * 
  * void        (*write_wakeup)(struct tty_struct *);
  *
@@ -141,8 +140,8 @@ struct tty_ldisc_ops {
        /*
         * The following routines are called from below.
         */
-       unsigned int (*receive_buf)(struct tty_struct *,
-                       const unsigned char *cp, char *fp, int count);
+       void    (*receive_buf)(struct tty_struct *, const unsigned char *cp,
+                              char *fp, int count);
        void    (*write_wakeup)(struct tty_struct *);
        void    (*dcd_change)(struct tty_struct *, unsigned int,
                                struct pps_event_time *);
index d512d98dfb7dbae07b1669132e40af457da3e879..5ca0951e1855b103ff65337cef6f94449f34d6c5 100644 (file)
@@ -93,8 +93,8 @@ static inline unsigned long __copy_from_user_nocache(void *to,
  * Safely read from address @src to the buffer at @dst.  If a kernel fault
  * happens, handle that and return -EFAULT.
  */
-extern long probe_kernel_read(void *dst, void *src, size_t size);
-extern long __probe_kernel_read(void *dst, void *src, size_t size);
+extern long probe_kernel_read(void *dst, const void *src, size_t size);
+extern long __probe_kernel_read(void *dst, const void *src, size_t size);
 
 /*
  * probe_kernel_write(): safely attempt to write to a location
@@ -105,7 +105,7 @@ extern long __probe_kernel_read(void *dst, void *src, size_t size);
  * Safely write to address @dst from the buffer at @src.  If a kernel fault
  * happens, handle that and return -EFAULT.
  */
-extern long notrace probe_kernel_write(void *dst, void *src, size_t size);
-extern long notrace __probe_kernel_write(void *dst, void *src, size_t size);
+extern long notrace probe_kernel_write(void *dst, const void *src, size_t size);
+extern long notrace __probe_kernel_write(void *dst, const void *src, size_t size);
 
 #endif         /* __LINUX_UACCESS_H__ */
index 71693d4a4fe187db6da029ec670ae124b90a3ef6..17df3600bcef74bf674b9d13c9db5657e64cc558 100644 (file)
@@ -62,7 +62,9 @@
        US_FLAG(NO_READ_DISC_INFO,      0x00040000)             \
                /* cannot handle READ_DISC_INFO */              \
        US_FLAG(NO_READ_CAPACITY_16,    0x00080000)             \
-               /* cannot handle READ_CAPACITY_16 */
+               /* cannot handle READ_CAPACITY_16 */            \
+       US_FLAG(INITIAL_READ10, 0x00100000)                     \
+               /* Initial READ(10) (and others) must be retried */
 
 #define US_FLAG(name, value)   US_FL_##name = value ,
 enum { US_DO_ALL_FLAGS };
index 73eb1ed36ec4cdb19b92a33b146b632ac9378f38..6ddbd86377dec3375549f2f02ef5c7c47fa9bfb3 100644 (file)
@@ -9,7 +9,7 @@
 #endif
 
 #ifndef UTS_NODENAME
-#define UTS_NODENAME "(none)"  /* set by sethostname() */
+#define UTS_NODENAME CONFIG_DEFAULT_HOSTNAME /* set by sethostname() */
 #endif
 
 #ifndef UTS_DOMAINNAME
index aff5b4f740417ee39cc3b42c8c70bfe351fc4564..7108857496055b1ed9f437ef22ae96c2ae9f0bf3 100644 (file)
@@ -51,6 +51,13 @@ struct virtqueue {
  *     This re-enables callbacks; it returns "false" if there are pending
  *     buffers in the queue, to detect a possible race between the driver
  *     checking for more work, and enabling callbacks.
+ * virtqueue_enable_cb_delayed: restart callbacks after disable_cb.
+ *     vq: the struct virtqueue we're talking about.
+ *     This re-enables callbacks but hints to the other side to delay
+ *     interrupts until most of the available buffers have been processed;
+ *     it returns "false" if there are many pending buffers in the queue,
+ *     to detect a possible race between the driver checking for more work,
+ *     and enabling callbacks.
  * virtqueue_detach_unused_buf: detach first unused buffer
  *     vq: the struct virtqueue we're talking about.
  *     Returns NULL or the "data" token handed to add_buf
@@ -86,6 +93,8 @@ void virtqueue_disable_cb(struct virtqueue *vq);
 
 bool virtqueue_enable_cb(struct virtqueue *vq);
 
+bool virtqueue_enable_cb_delayed(struct virtqueue *vq);
+
 void *virtqueue_detach_unused_buf(struct virtqueue *vq);
 
 /**
index e68b439b2860e7aa5e9490fec542fdfe245c6b2f..277c4ad44e842448df79c1afda9322e84c32e842 100644 (file)
@@ -1,7 +1,30 @@
 #ifndef _LINUX_VIRTIO_9P_H
 #define _LINUX_VIRTIO_9P_H
 /* This header is BSD licensed so anyone can use the definitions to implement
- * compatible drivers/servers. */
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
 #include <linux/types.h>
 #include <linux/virtio_ids.h>
 #include <linux/virtio_config.h>
index a50ecd1b81a2acce1da35758767d3abcf0b06a99..652dc8bea92131a4d3134fe6b59ae75cdc6092a8 100644 (file)
@@ -1,7 +1,30 @@
 #ifndef _LINUX_VIRTIO_BALLOON_H
 #define _LINUX_VIRTIO_BALLOON_H
 /* This header is BSD licensed so anyone can use the definitions to implement
- * compatible drivers/servers. */
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
 #include <linux/virtio_ids.h>
 #include <linux/virtio_config.h>
 
index 167720d695ed00bb94b9174381de80f13fd6d009..e0edb40ca7aaca3ffeeb9261fa017eedd6548291 100644 (file)
@@ -1,7 +1,30 @@
 #ifndef _LINUX_VIRTIO_BLK_H
 #define _LINUX_VIRTIO_BLK_H
 /* This header is BSD licensed so anyone can use the definitions to implement
- * compatible drivers/servers. */
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
 #include <linux/types.h>
 #include <linux/virtio_ids.h>
 #include <linux/virtio_config.h>
index 800617b4ddd56c3dd0a790f97a4c73f2fa38de64..39c88c5ad19dfd85c5fcbed38837d514c477679f 100644 (file)
@@ -1,7 +1,30 @@
 #ifndef _LINUX_VIRTIO_CONFIG_H
 #define _LINUX_VIRTIO_CONFIG_H
 /* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
- * anyone can use the definitions to implement compatible drivers/servers. */
+ * anyone can use the definitions to implement compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
 
 /* Virtio devices use a standardized configuration space to define their
  * features and pass configuration information, but each implementation can
index e4d333543a33a65b450f637f0ed2ce231ae0f088..bdf4b0034739e379b4eae94e17171aaca64f3bd0 100644 (file)
@@ -5,7 +5,31 @@
 #include <linux/virtio_config.h>
 /*
  * This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
- * anyone can use the definitions to implement compatible drivers/servers.
+ * anyone can use the definitions to implement compatible drivers/servers:
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  *
  * Copyright (C) Red Hat, Inc., 2009, 2010, 2011
  * Copyright (C) Amit Shah <amit.shah@redhat.com>, 2009, 2010, 2011
index 06660c0a78d720e5d4b2155041c10b3800c9ffbd..85bb0bb66ffc5c33b985194975466bb30189657b 100644 (file)
@@ -5,7 +5,29 @@
  *
  * This header is BSD licensed so anyone can use the definitions to implement
  * compatible drivers/servers.
- */
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
 
 #define VIRTIO_ID_NET          1 /* virtio net */
 #define VIRTIO_ID_BLOCK                2 /* virtio block */
index 085e42298ce5b1b9f353f457951e7fc49a5ef949..136040bba3e36068364c276e38f3ab975b0cabef 100644 (file)
@@ -1,7 +1,30 @@
 #ifndef _LINUX_VIRTIO_NET_H
 #define _LINUX_VIRTIO_NET_H
 /* This header is BSD licensed so anyone can use the definitions to implement
- * compatible drivers/servers. */
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
 #include <linux/types.h>
 #include <linux/virtio_ids.h>
 #include <linux/virtio_config.h>
index 9a3d7c48c622d8c3e525ce5653fd12e98b4d9f9a..ea66f3f60d63f7db3234c2f75058826af072a771 100644 (file)
  *
  * This header is BSD licensed so anyone can use the definitions to implement
  * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef _LINUX_VIRTIO_PCI_H
index e4d144b132b5e27d3c4713738acfc63ce6262781..4a32cb6da425abe92c9eaa019121f4710171c77a 100644 (file)
@@ -7,6 +7,29 @@
  * This header is BSD licensed so anyone can use the definitions to implement
  * compatible drivers/servers.
  *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
  * Copyright Rusty Russell IBM Corporation 2007. */
 #include <linux/types.h>
 
 /* We support indirect buffer descriptors */
 #define VIRTIO_RING_F_INDIRECT_DESC    28
 
+/* The Guest publishes the used index for which it expects an interrupt
+ * at the end of the avail ring. Host should ignore the avail->flags field. */
+/* The Host publishes the avail index for which it expects a kick
+ * at the end of the used ring. Guest should ignore the used->flags field. */
+#define VIRTIO_RING_F_EVENT_IDX                29
+
 /* Virtio ring descriptors: 16 bytes.  These can chain together via "next". */
 struct vring_desc {
        /* Address (guest-physical). */
@@ -83,6 +112,7 @@ struct vring {
  *     __u16 avail_flags;
  *     __u16 avail_idx;
  *     __u16 available[num];
+ *     __u16 used_event_idx;
  *
  *     // Padding to the next align boundary.
  *     char pad[];
@@ -91,8 +121,14 @@ struct vring {
  *     __u16 used_flags;
  *     __u16 used_idx;
  *     struct vring_used_elem used[num];
+ *     __u16 avail_event_idx;
  * };
  */
+/* We publish the used event index at the end of the available ring, and vice
+ * versa. They are at the end for backwards compatibility. */
+#define vring_used_event(vr) ((vr)->avail->ring[(vr)->num])
+#define vring_avail_event(vr) (*(__u16 *)&(vr)->used->ring[(vr)->num])
+
 static inline void vring_init(struct vring *vr, unsigned int num, void *p,
                              unsigned long align)
 {
@@ -107,7 +143,21 @@ static inline unsigned vring_size(unsigned int num, unsigned long align)
 {
        return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (2 + num)
                 + align - 1) & ~(align - 1))
-               + sizeof(__u16) * 2 + sizeof(struct vring_used_elem) * num;
+               + sizeof(__u16) * 3 + sizeof(struct vring_used_elem) * num;
+}
+
+/* The following is used with USED_EVENT_IDX and AVAIL_EVENT_IDX */
+/* Assuming a given event_idx value from the other size, if
+ * we have just incremented index from old to new_idx,
+ * should we trigger an event? */
+static inline int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old)
+{
+       /* Note: Xen has similar logic for notification hold-off
+        * in include/xen/interface/io/ring.h with req_event and req_prod
+        * corresponding to event_idx + 1 and new_idx respectively.
+        * Note also that req_event and req_prod in Xen start at 1,
+        * event indexes in virtio start at 0. */
+       return (__u16)(new_idx - event_idx - 1) < (__u16)(new_idx - old);
 }
 
 #ifdef __KERNEL__
diff --git a/include/linux/vm_event_item.h b/include/linux/vm_event_item.h
new file mode 100644 (file)
index 0000000..03b90cd
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef VM_EVENT_ITEM_H_INCLUDED
+#define VM_EVENT_ITEM_H_INCLUDED
+
+#ifdef CONFIG_ZONE_DMA
+#define DMA_ZONE(xx) xx##_DMA,
+#else
+#define DMA_ZONE(xx)
+#endif
+
+#ifdef CONFIG_ZONE_DMA32
+#define DMA32_ZONE(xx) xx##_DMA32,
+#else
+#define DMA32_ZONE(xx)
+#endif
+
+#ifdef CONFIG_HIGHMEM
+#define HIGHMEM_ZONE(xx) , xx##_HIGH
+#else
+#define HIGHMEM_ZONE(xx)
+#endif
+
+#define FOR_ALL_ZONES(xx) DMA_ZONE(xx) DMA32_ZONE(xx) xx##_NORMAL HIGHMEM_ZONE(xx) , xx##_MOVABLE
+
+enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
+               FOR_ALL_ZONES(PGALLOC),
+               PGFREE, PGACTIVATE, PGDEACTIVATE,
+               PGFAULT, PGMAJFAULT,
+               FOR_ALL_ZONES(PGREFILL),
+               FOR_ALL_ZONES(PGSTEAL),
+               FOR_ALL_ZONES(PGSCAN_KSWAPD),
+               FOR_ALL_ZONES(PGSCAN_DIRECT),
+#ifdef CONFIG_NUMA
+               PGSCAN_ZONE_RECLAIM_FAILED,
+#endif
+               PGINODESTEAL, SLABS_SCANNED, KSWAPD_STEAL, KSWAPD_INODESTEAL,
+               KSWAPD_LOW_WMARK_HIT_QUICKLY, KSWAPD_HIGH_WMARK_HIT_QUICKLY,
+               KSWAPD_SKIP_CONGESTION_WAIT,
+               PAGEOUTRUN, ALLOCSTALL, PGROTATED,
+#ifdef CONFIG_COMPACTION
+               COMPACTBLOCKS, COMPACTPAGES, COMPACTPAGEFAILED,
+               COMPACTSTALL, COMPACTFAIL, COMPACTSUCCESS,
+#endif
+#ifdef CONFIG_HUGETLB_PAGE
+               HTLB_BUDDY_PGALLOC, HTLB_BUDDY_PGALLOC_FAIL,
+#endif
+               UNEVICTABLE_PGCULLED,   /* culled to noreclaim list */
+               UNEVICTABLE_PGSCANNED,  /* scanned for reclaimability */
+               UNEVICTABLE_PGRESCUED,  /* rescued from noreclaim list */
+               UNEVICTABLE_PGMLOCKED,
+               UNEVICTABLE_PGMUNLOCKED,
+               UNEVICTABLE_PGCLEARED,  /* on COW, page truncate */
+               UNEVICTABLE_PGSTRANDED, /* unable to isolate on unlock */
+               UNEVICTABLE_MLOCKFREED,
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+               THP_FAULT_ALLOC,
+               THP_FAULT_FALLBACK,
+               THP_COLLAPSE_ALLOC,
+               THP_COLLAPSE_ALLOC_FAILED,
+               THP_SPLIT,
+#endif
+               NR_VM_EVENT_ITEMS
+};
+
+#endif         /* VM_EVENT_ITEM_H_INCLUDED */
index 2b3831b58aa4312a754c41b2608431db85e31887..bcd942fa611cadd855a15078bbdb78ed58ff5404 100644 (file)
@@ -5,69 +5,9 @@
 #include <linux/percpu.h>
 #include <linux/mm.h>
 #include <linux/mmzone.h>
+#include <linux/vm_event_item.h>
 #include <asm/atomic.h>
 
-#ifdef CONFIG_ZONE_DMA
-#define DMA_ZONE(xx) xx##_DMA,
-#else
-#define DMA_ZONE(xx)
-#endif
-
-#ifdef CONFIG_ZONE_DMA32
-#define DMA32_ZONE(xx) xx##_DMA32,
-#else
-#define DMA32_ZONE(xx)
-#endif
-
-#ifdef CONFIG_HIGHMEM
-#define HIGHMEM_ZONE(xx) , xx##_HIGH
-#else
-#define HIGHMEM_ZONE(xx)
-#endif
-
-
-#define FOR_ALL_ZONES(xx) DMA_ZONE(xx) DMA32_ZONE(xx) xx##_NORMAL HIGHMEM_ZONE(xx) , xx##_MOVABLE
-
-enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
-               FOR_ALL_ZONES(PGALLOC),
-               PGFREE, PGACTIVATE, PGDEACTIVATE,
-               PGFAULT, PGMAJFAULT,
-               FOR_ALL_ZONES(PGREFILL),
-               FOR_ALL_ZONES(PGSTEAL),
-               FOR_ALL_ZONES(PGSCAN_KSWAPD),
-               FOR_ALL_ZONES(PGSCAN_DIRECT),
-#ifdef CONFIG_NUMA
-               PGSCAN_ZONE_RECLAIM_FAILED,
-#endif
-               PGINODESTEAL, SLABS_SCANNED, KSWAPD_STEAL, KSWAPD_INODESTEAL,
-               KSWAPD_LOW_WMARK_HIT_QUICKLY, KSWAPD_HIGH_WMARK_HIT_QUICKLY,
-               KSWAPD_SKIP_CONGESTION_WAIT,
-               PAGEOUTRUN, ALLOCSTALL, PGROTATED,
-#ifdef CONFIG_COMPACTION
-               COMPACTBLOCKS, COMPACTPAGES, COMPACTPAGEFAILED,
-               COMPACTSTALL, COMPACTFAIL, COMPACTSUCCESS,
-#endif
-#ifdef CONFIG_HUGETLB_PAGE
-               HTLB_BUDDY_PGALLOC, HTLB_BUDDY_PGALLOC_FAIL,
-#endif
-               UNEVICTABLE_PGCULLED,   /* culled to noreclaim list */
-               UNEVICTABLE_PGSCANNED,  /* scanned for reclaimability */
-               UNEVICTABLE_PGRESCUED,  /* rescued from noreclaim list */
-               UNEVICTABLE_PGMLOCKED,
-               UNEVICTABLE_PGMUNLOCKED,
-               UNEVICTABLE_PGCLEARED,  /* on COW, page truncate */
-               UNEVICTABLE_PGSTRANDED, /* unable to isolate on unlock */
-               UNEVICTABLE_MLOCKFREED,
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-               THP_FAULT_ALLOC,
-               THP_FAULT_FALLBACK,
-               THP_COLLAPSE_ALLOC,
-               THP_COLLAPSE_ALLOC_FAILED,
-               THP_SPLIT,
-#endif
-               NR_VM_EVENT_ITEMS
-};
-
 extern int sysctl_stat_interval;
 
 #ifdef CONFIG_VM_EVENT_COUNTERS
@@ -261,6 +201,7 @@ extern void dec_zone_state(struct zone *, enum zone_stat_item);
 extern void __dec_zone_state(struct zone *, enum zone_stat_item);
 
 void refresh_cpu_vm_stats(int);
+void refresh_zone_stat_thresholds(void);
 
 int calculate_pressure_threshold(struct zone *zone);
 int calculate_normal_threshold(struct zone *zone);
@@ -313,6 +254,10 @@ static inline void __dec_zone_page_state(struct page *page,
 #define set_pgdat_percpu_threshold(pgdat, callback) { }
 
 static inline void refresh_cpu_vm_stats(int cpu) { }
-#endif
+static inline void refresh_zone_stat_thresholds(void) { }
+
+#endif         /* CONFIG_SMP */
+
+extern const char * const vmstat_text[];
 
 #endif /* _LINUX_VMSTAT_H */
index 6050783005bd9839ceaa1df692b526afd14982fc..aed54c50aa665b89e61bf007c6715e65a26cbefb 100644 (file)
 #define XATTR_CREATE   0x1     /* set value, fail if attr already exists */
 #define XATTR_REPLACE  0x2     /* set value, fail if attr does not exist */
 
-#ifdef  __KERNEL__
-
-#include <linux/types.h>
-
 /* Namespaces */
 #define XATTR_OS2_PREFIX "os2."
 #define XATTR_OS2_PREFIX_LEN (sizeof (XATTR_OS2_PREFIX) - 1)
 #define XATTR_CAPS_SUFFIX "capability"
 #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
 
+#ifdef  __KERNEL__
+
+#include <linux/types.h>
+
 struct inode;
 struct dentry;
 
diff --git a/include/media/m5mols.h b/include/media/m5mols.h
new file mode 100644 (file)
index 0000000..2d7e7ca
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Driver header for M-5MOLS 8M Pixel camera sensor with ISP
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Author: HeungJun Kim, riverful.kim@samsung.com
+ *
+ * Copyright (C) 2009 Samsung Electronics Co., Ltd.
+ * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.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.
+ */
+
+#ifndef MEDIA_M5MOLS_H
+#define MEDIA_M5MOLS_H
+
+/**
+ * struct m5mols_platform_data - platform data for M-5MOLS driver
+ * @irq:       GPIO getting the irq pin of M-5MOLS
+ * @gpio_reset:        GPIO driving the reset pin of M-5MOLS
+ * @reset_polarity: active state for gpio_rst pin, 0 or 1
+ * @set_power: an additional callback to the board setup code
+ *             to be called after enabling and before disabling
+ *             the sensor's supply regulators
+ */
+struct m5mols_platform_data {
+       int irq;
+       int gpio_reset;
+       u8 reset_polarity;
+       int (*set_power)(struct device *dev, int on);
+};
+
+#endif /* MEDIA_M5MOLS_H */
index 93e96fb934526e44b327e8d677bb91f7accd80c4..c7c40f1d2624a7eb7988ee376e324904b54c1d39 100644 (file)
@@ -128,8 +128,8 @@ struct video_device
        struct mutex *lock;
 };
 
-#define media_entity_to_video_device(entity) \
-       container_of(entity, struct video_device, entity)
+#define media_entity_to_video_device(__e) \
+       container_of(__e, struct video_device, entity)
 /* dev to video-device */
 #define to_video_device(cd) container_of(cd, struct video_device, dev)
 
index 07cf4b9d0a656e56c28b3e6e16c4d6abc14f1b0a..bf365721d6b05f180169bfb4030c05b2c0345cab 100644 (file)
@@ -4,6 +4,9 @@
 #include <dvb_net.h>
 #include <dvb_frontend.h>
 
+#ifndef _VIDEOBUF_DVB_H_
+#define        _VIDEOBUF_DVB_H_
+
 struct videobuf_dvb {
        /* filling that the job of the driver */
        char                       *name;
@@ -54,6 +57,7 @@ void videobuf_dvb_dealloc_frontends(struct videobuf_dvb_frontends *f);
 struct videobuf_dvb_frontend * videobuf_dvb_get_frontend(struct videobuf_dvb_frontends *f, int id);
 int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, struct dvb_frontend *p);
 
+#endif                 /* _VIDEOBUF_DVB_H_ */
 
 /*
  * Local variables:
index c0d47ad4b103b5a502cf98230f3d52da3e38d74b..3c4109777afff101c192b880ca1072978eddf3d8 100644 (file)
  * ~~~~~~~~~~~~~~~~~~~~~~~~~
  *
  * To set an UBI volume property the %UBI_IOCSETPROP ioctl command should be
- * used. A pointer to a &struct ubi_set_prop_req object is expected to be
+ * used. A pointer to a &struct ubi_set_vol_prop_req object is expected to be
  * passed. The object describes which property should be set, and to which value
  * it should be set.
  */
 /* Check if LEB is mapped command */
 #define UBI_IOCEBISMAP _IOR(UBI_VOL_IOC_MAGIC, 5, __s32)
 /* Set an UBI volume property */
-#define UBI_IOCSETPROP _IOW(UBI_VOL_IOC_MAGIC, 6, struct ubi_set_prop_req)
+#define UBI_IOCSETVOLPROP _IOW(UBI_VOL_IOC_MAGIC, 6, \
+                              struct ubi_set_vol_prop_req)
 
 /* Maximum MTD device name length supported by UBI */
 #define MAX_UBI_MTD_NAME_LEN 127
@@ -223,13 +224,14 @@ enum {
 };
 
 /*
- * UBI set property ioctl constants
+ * UBI set volume property ioctl constants.
  *
- * @UBI_PROP_DIRECT_WRITE: allow / disallow user to directly write and
- *                         erase individual eraseblocks on dynamic volumes
+ * @UBI_VOL_PROP_DIRECT_WRITE: allow (any non-zero value) or disallow (value 0)
+ *                             user to directly write and erase individual
+ *                             eraseblocks on dynamic volumes
  */
 enum {
-       UBI_PROP_DIRECT_WRITE = 1,
+       UBI_VOL_PROP_DIRECT_WRITE = 1,
 };
 
 /**
@@ -308,7 +310,7 @@ struct ubi_mkvol_req {
        __s16 name_len;
        __s8 padding2[4];
        char name[UBI_MAX_VOLUME_NAME + 1];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubi_rsvol_req - a data structure used in volume re-size requests.
@@ -324,7 +326,7 @@ struct ubi_mkvol_req {
 struct ubi_rsvol_req {
        __s64 bytes;
        __s32 vol_id;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubi_rnvol_req - volumes re-name request.
@@ -366,7 +368,7 @@ struct ubi_rnvol_req {
                __s8  padding2[2];
                char    name[UBI_MAX_VOLUME_NAME + 1];
        } ents[UBI_MAX_RNVOL];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubi_leb_change_req - a data structure used in atomic LEB change
@@ -381,7 +383,7 @@ struct ubi_leb_change_req {
        __s32 bytes;
        __s8  dtype;
        __s8  padding[7];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubi_map_req - a data structure used in map LEB requests.
@@ -393,20 +395,20 @@ struct ubi_map_req {
        __s32 lnum;
        __s8  dtype;
        __s8  padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 
 /**
- * struct ubi_set_prop_req - a data structure used to set an ubi volume
- *                           property.
- * @property: property to set (%UBI_PROP_DIRECT_WRITE)
+ * struct ubi_set_vol_prop_req - a data structure used to set an UBI volume
+ *                               property.
+ * @property: property to set (%UBI_VOL_PROP_DIRECT_WRITE)
  * @padding: reserved for future, not used, has to be zeroed
  * @value: value to set
  */
-struct ubi_set_prop_req {
-       __u8  property;
-       __u8  padding[7];
-       __u64 value;
-}  __attribute__ ((packed));
+struct ubi_set_vol_prop_req {
+       __u8  property;
+       __u8  padding[7];
+       __u64 value;
+}  __packed;
 
 #endif /* __UBI_USER_H__ */
index d2df55b0c2134a35044a583429ac34e01b37f065..008711e8e78f265d512105d788aad6877c016a07 100644 (file)
@@ -241,10 +241,10 @@ enum p9_open_mode_t {
 
 /**
  * enum p9_perm_t - 9P permissions
- * @P9_DMDIR: mode bite for directories
+ * @P9_DMDIR: mode bit for directories
  * @P9_DMAPPEND: mode bit for is append-only
  * @P9_DMEXCL: mode bit for excluse use (only one open handle allowed)
- * @P9_DMMOUNT: mode bite for mount points
+ * @P9_DMMOUNT: mode bit for mount points
  * @P9_DMAUTH: mode bit for authentication file
  * @P9_DMTMP: mode bit for non-backed-up files
  * @P9_DMSYMLINK: mode bit for symbolic links (9P2000.u)
@@ -362,7 +362,7 @@ struct p9_qid {
 };
 
 /**
- * struct p9_stat - file system metadata information
+ * struct p9_wstat - file system metadata information
  * @size: length prefix for this stat structure instance
  * @type: the type of the server (equivalent to a major number)
  * @dev: the sub-type of the server (equivalent to a minor number)
@@ -687,10 +687,10 @@ struct p9_rwstat {
  * @size: prefixed length of the structure
  * @id: protocol operating identifier of type &p9_msg_t
  * @tag: transaction id of the request
- * @offset: used by marshalling routines to track currentposition in buffer
+ * @offset: used by marshalling routines to track current position in buffer
  * @capacity: used by marshalling routines to track total malloc'd capacity
  * @pubuf: Payload user buffer given by the caller
- * @pubuf: Payload kernel buffer given by the caller
+ * @pkbuf: Payload kernel buffer given by the caller
  * @pbuf_size: pubuf/pkbuf(only one will be !NULL) size to be read/write.
  * @private: For transport layer's use.
  * @sdata: payload
@@ -714,7 +714,7 @@ struct p9_fcall {
        size_t pbuf_size;
        void *private;
 
-       uint8_t *sdata;
+       u8 *sdata;
 };
 
 struct p9_idpool;
@@ -728,7 +728,6 @@ void p9_idpool_put(int id, struct p9_idpool *p);
 int p9_idpool_check(int id, struct p9_idpool *p);
 
 int p9_error_init(void);
-int p9_errstr2errno(char *, int);
 int p9_trans_fd_init(void);
 void p9_trans_fd_exit(void);
 #endif /* NET_9P_H */
index 051a99f79769a59021fdcb958a6f850e1f2ddc71..d26d5e98a1737e85e9e2004f30d5fa17f4f007ae 100644 (file)
@@ -60,7 +60,7 @@ enum p9_trans_status {
 };
 
 /**
- * enum p9_req_status_t - virtio request status
+ * enum p9_req_status_t - status of a request
  * @REQ_STATUS_IDLE: request slot unused
  * @REQ_STATUS_ALLOC: request has been allocated but not sent
  * @REQ_STATUS_UNSENT: request waiting to be sent
index 8f08c736c4c3c22a86988c89c9f5fec77e68ff7b..d8549fb9c742209369f324db5953fd5904aa36dd 100644 (file)
@@ -41,6 +41,7 @@
  * @pref: Preferences of this transport
  * @def: set if this transport should be considered the default
  * @create: member function to create a new connection on this transport
+ * @close: member function to discard a connection on this transport
  * @request: member function to issue a request to the transport
  * @cancel: member function to cancel a request (if it hasn't been sent)
  *
@@ -48,7 +49,7 @@
  * transport module with the 9P core network module and used by the client
  * to instantiate a new connection on a transport.
  *
- * BUGS: the transport module list isn't protected.
+ * The transport module list is protected by v9fs_trans_lock.
  */
 
 struct p9_trans_module {
index bfd6557946beca9f5cf2525cf7931be4a2c51cbe..0589f554788aea2dd5dc28c9a372ee10637e3eb6 100644 (file)
@@ -531,6 +531,7 @@ struct sta_bss_parameters {
  * @tx_retries: cumulative retry counts
  * @tx_failed: number of failed transmissions (retries exceeded, no ACK)
  * @rx_dropped_misc:  Dropped for un-specified reason.
+ * @bss_param: current BSS parameters
  * @generation: generation number for nl80211 dumps.
  *     This number should increase every time the list of stations
  *     changes, i.e. when a station is added or removed, so that
@@ -1537,7 +1538,7 @@ struct cfg80211_ops {
  * @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN.
  * @WIPHY_FLAG_MESH_AUTH: The device supports mesh authentication by routing
  *     auth frames to userspace. See @NL80211_MESH_SETUP_USERSPACE_AUTH.
- * @WIPHY_FLAG_SCHED_SCAN: The device supports scheduled scans.
+ * @WIPHY_FLAG_SUPPORTS_SCHED_SCAN: The device supports scheduled scans.
  */
 enum wiphy_flags {
        WIPHY_FLAG_CUSTOM_REGULATORY            = BIT(0),
@@ -2878,6 +2879,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
  * cfg80211_roamed - notify cfg80211 of roaming
  *
  * @dev: network device
+ * @channel: the channel of the new AP
  * @bssid: the BSSID of the new AP
  * @req_ie: association request IEs (maybe be %NULL)
  * @req_ie_len: association request IEs length
@@ -2888,7 +2890,9 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
  * It should be called by the underlying driver whenever it roamed
  * from one AP to another while connected.
  */
-void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
+void cfg80211_roamed(struct net_device *dev,
+                    struct ieee80211_channel *channel,
+                    const u8 *bssid,
                     const u8 *req_ie, size_t req_ie_len,
                     const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
 
index 07a0402c52e6b3cec976652d7aa0c3d4a101d955..7d15d238b6ecc4f3d4c47af4389525ead0f7a2c7 100644 (file)
@@ -111,6 +111,8 @@ static inline u32 *dst_metrics_write_ptr(struct dst_entry *dst)
 {
        unsigned long p = dst->_metrics;
 
+       BUG_ON(!p);
+
        if (p & DST_METRICS_READ_ONLY)
                return dst->ops->cow_metrics(dst, p);
        return __DST_METRICS_PTR(p);
index 4fff432aeade033b06f62e2526711035424e299d..481f856c650f8132f77f7f0c9afaa78fe83eb39b 100644 (file)
@@ -797,7 +797,8 @@ struct netns_ipvs {
        struct list_head        rs_table[IP_VS_RTAB_SIZE];
        /* ip_vs_app */
        struct list_head        app_list;
-
+       /* ip_vs_ftp */
+       struct ip_vs_app        *ftp_app;
        /* ip_vs_proto */
        #define IP_VS_PROTO_TAB_SIZE    32      /* must be power of 2 */
        struct ip_vs_proto_data *proto_data_table[IP_VS_PROTO_TAB_SIZE];
index 3ae491932bc80305909f278864c370e0f6e689df..aef430d779bdd07542f5be64967c8f5c8fb9d809 100644 (file)
@@ -7,6 +7,7 @@
 #include <asm/atomic.h>
 #include <linux/workqueue.h>
 #include <linux/list.h>
+#include <linux/sysctl.h>
 
 #include <net/netns/core.h>
 #include <net/netns/mib.h>
@@ -34,8 +35,11 @@ struct netns_ipvs;
 #define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS)
 
 struct net {
+       atomic_t                passive;        /* To decided when the network
+                                                * namespace should be freed.
+                                                */
        atomic_t                count;          /* To decided when the network
-                                                *  namespace should be freed.
+                                                *  namespace should be shut down.
                                                 */
 #ifdef NETNS_REFCNT_DEBUG
        atomic_t                use_count;      /* To track references we
@@ -119,6 +123,7 @@ static inline struct net *copy_net_ns(unsigned long flags, struct net *net_ns)
 extern struct list_head net_namespace_list;
 
 extern struct net *get_net_ns_by_pid(pid_t pid);
+extern struct net *get_net_ns_by_fd(int pid);
 
 #ifdef CONFIG_NET_NS
 extern void __put_net(struct net *net);
@@ -152,6 +157,9 @@ int net_eq(const struct net *net1, const struct net *net2)
 {
        return net1 == net2;
 }
+
+extern void net_drop_ns(void *);
+
 #else
 
 static inline struct net *get_net(struct net *net)
@@ -173,6 +181,8 @@ int net_eq(const struct net *net1, const struct net *net2)
 {
        return 1;
 }
+
+#define net_drop_ns NULL
 #endif
 
 
diff --git a/include/net/net_ratelimit.h b/include/net/net_ratelimit.h
new file mode 100644 (file)
index 0000000..7727b42
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _LINUX_NET_RATELIMIT_H
+#define _LINUX_NET_RATELIMIT_H
+
+#include <linux/ratelimit.h>
+
+extern struct ratelimit_state net_ratelimit_state;
+
+#endif /* _LINUX_NET_RATELIMIT_H */
index c7c42e7acc31004d10ba3adaa0f42c1e9131b127..5d4f8e586e32e6489da5fb7ff5d1525a5b8fe1b1 100644 (file)
@@ -307,6 +307,12 @@ static inline int nf_ct_is_untracked(const struct nf_conn *ct)
        return test_bit(IPS_UNTRACKED_BIT, &ct->status);
 }
 
+/* Packet is received from loopback */
+static inline bool nf_is_loopback_packet(const struct sk_buff *skb)
+{
+       return skb->dev && skb->skb_iif && skb->dev->flags & IFF_LOOPBACK;
+}
+
 extern int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp);
 extern unsigned int nf_conntrack_htable_size;
 extern unsigned int nf_conntrack_max;
index 2b447646ce4bf3d64926d4c8a7bdd969f1a8bb1d..dd6847e5d6e46264ffe6db00ccb7128ce61483fa 100644 (file)
@@ -107,6 +107,7 @@ typedef enum {
        SCTP_CMD_UPDATE_INITTAG, /* Update peer inittag */
        SCTP_CMD_SEND_MSG,       /* Send the whole use message */
        SCTP_CMD_SEND_NEXT_ASCONF, /* Send the next ASCONF after ACK */
+       SCTP_CMD_PURGE_ASCONF_QUEUE, /* Purge all asconf queues.*/
        SCTP_CMD_LAST
 } sctp_verb_t;
 
index 795f4886e1112dc7245e841f29f0465ae4aa1d59..7df327a6d564e8b2b57609ff714d4eb9a0e8b872 100644 (file)
@@ -1993,7 +1993,7 @@ void sctp_assoc_clean_asconf_ack_cache(const struct sctp_association *asoc);
 struct sctp_chunk *sctp_assoc_lookup_asconf_ack(
                                        const struct sctp_association *asoc,
                                        __be32 serial);
-
+void sctp_asconf_queue_teardown(struct sctp_association *asoc);
 
 int sctp_cmp_addr_exact(const union sctp_addr *ss1,
                        const union sctp_addr *ss2);
index 3fd5064dd43a7805c900f28a20a218179836ebbe..7b82080eb02ce325c944341b961545914987a380 100644 (file)
@@ -56,7 +56,7 @@ struct pcmcia_driver {
        int (*resume)           (struct pcmcia_device *dev);
 
        struct module           *owner;
-       struct pcmcia_device_id *id_table;
+       const struct pcmcia_device_id   *id_table;
        struct device_driver    drv;
        struct pcmcia_dynids    dynids;
 };
index e7c043216558eba802e4e1011dab4e08ed144c76..ea56f76c0c2208dd2a9aea0d599b67e3b51b6a18 100644 (file)
@@ -1 +1,6 @@
+header-y += ib_user_cm.h
 header-y += ib_user_mad.h
+header-y += ib_user_sa.h
+header-y += ib_user_verbs.h
+header-y += rdma_netlink.h
+header-y += rdma_user_cm.h
index bd3d380781e0bcc61fb464d9d50d217b24251d14..f79014aa28f9928da0a72904c8cbf2ebe9b7fb36 100644 (file)
@@ -34,6 +34,7 @@
 #ifndef IB_USER_CM_H
 #define IB_USER_CM_H
 
+#include <linux/types.h>
 #include <rdma/ib_user_sa.h>
 
 #define IB_USER_CM_ABI_VERSION 5
index 169f7a53fb0c696cf7cbb9f441a4e5fe021641bd..26977c149c414df2a9f166b3dcb9539f0aca6205 100644 (file)
@@ -111,6 +111,20 @@ struct rdma_cm_event {
        } param;
 };
 
+enum rdma_cm_state {
+       RDMA_CM_IDLE,
+       RDMA_CM_ADDR_QUERY,
+       RDMA_CM_ADDR_RESOLVED,
+       RDMA_CM_ROUTE_QUERY,
+       RDMA_CM_ROUTE_RESOLVED,
+       RDMA_CM_CONNECT,
+       RDMA_CM_DISCONNECT,
+       RDMA_CM_ADDR_BOUND,
+       RDMA_CM_LISTEN,
+       RDMA_CM_DEVICE_REMOVAL,
+       RDMA_CM_DESTROYING
+};
+
 struct rdma_cm_id;
 
 /**
@@ -130,6 +144,7 @@ struct rdma_cm_id {
        rdma_cm_event_handler    event_handler;
        struct rdma_route        route;
        enum rdma_port_space     ps;
+       enum ib_qp_type          qp_type;
        u8                       port_num;
 };
 
@@ -140,9 +155,11 @@ struct rdma_cm_id {
  *   returned rdma_id.
  * @context: User specified context associated with the id.
  * @ps: RDMA port space.
+ * @qp_type: type of queue pair associated with the id.
  */
 struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler,
-                                 void *context, enum rdma_port_space ps);
+                                 void *context, enum rdma_port_space ps,
+                                 enum ib_qp_type qp_type);
 
 /**
   * rdma_destroy_id - Destroys an RDMA identifier.
diff --git a/include/rdma/rdma_netlink.h b/include/rdma/rdma_netlink.h
new file mode 100644 (file)
index 0000000..3c5363a
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef _RDMA_NETLINK_H
+#define _RDMA_NETLINK_H
+
+#include <linux/types.h>
+
+enum {
+       RDMA_NL_RDMA_CM = 1
+};
+
+#define RDMA_NL_GET_CLIENT(type) ((type & (((1 << 6) - 1) << 10)) >> 10)
+#define RDMA_NL_GET_OP(type) (type & ((1 << 10) - 1))
+#define RDMA_NL_GET_TYPE(client, op) ((client << 10) + op)
+
+enum {
+       RDMA_NL_RDMA_CM_ID_STATS = 0,
+       RDMA_NL_RDMA_CM_NUM_OPS
+};
+
+enum {
+       RDMA_NL_RDMA_CM_ATTR_SRC_ADDR = 1,
+       RDMA_NL_RDMA_CM_ATTR_DST_ADDR,
+       RDMA_NL_RDMA_CM_NUM_ATTR,
+};
+
+struct rdma_cm_id_stats {
+       __u32   qp_num;
+       __u32   bound_dev_if;
+       __u32   port_space;
+       __s32   pid;
+       __u8    cm_state;
+       __u8    node_type;
+       __u8    port_num;
+       __u8    qp_type;
+};
+
+#ifdef __KERNEL__
+
+#include <linux/netlink.h>
+
+struct ibnl_client_cbs {
+       int (*dump)(struct sk_buff *skb, struct netlink_callback *nlcb);
+};
+
+int ibnl_init(void);
+void ibnl_cleanup(void);
+
+/**
+ * Add a a client to the list of IB netlink exporters.
+ * @index: Index of the added client
+ * @nops: Number of supported ops by the added client.
+ * @cb_table: A table for op->callback
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int ibnl_add_client(int index, int nops,
+                   const struct ibnl_client_cbs cb_table[]);
+
+/**
+ * Remove a client from IB netlink.
+ * @index: Index of the removed IB client.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int ibnl_remove_client(int index);
+
+/**
+ * Put a new message in a supplied skb.
+ * @skb: The netlink skb.
+ * @nlh: Pointer to put the header of the new netlink message.
+ * @seq: The message sequence number.
+ * @len: The requested message length to allocate.
+ * @client: Calling IB netlink client.
+ * @op: message content op.
+ * Returns the allocated buffer on success and NULL on failure.
+ */
+void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq,
+                  int len, int client, int op);
+/**
+ * Put a new attribute in a supplied skb.
+ * @skb: The netlink skb.
+ * @nlh: Header of the netlink message to append the attribute to.
+ * @len: The length of the attribute data.
+ * @data: The attribute data to put.
+ * @type: The attribute type.
+ * Returns the 0 and a negative error code on failure.
+ */
+int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh,
+                 int len, void *data, int type);
+
+#endif /* __KERNEL__ */
+
+#endif /* _RDMA_NETLINK_H */
index 8f6bb9c7f3eb1b038a784e4d706098f3442937ba..ee866060f8a4d2c6441cba43d6c27a454bacf1ed 100644 (file)
@@ -604,6 +604,7 @@ struct sas_domain_function_template {
        int (*lldd_clear_aca)(struct domain_device *, u8 *lun);
        int (*lldd_clear_task_set)(struct domain_device *, u8 *lun);
        int (*lldd_I_T_nexus_reset)(struct domain_device *);
+       int (*lldd_ata_soft_reset)(struct domain_device *);
        int (*lldd_lu_reset)(struct domain_device *, u8 *lun);
        int (*lldd_query_task)(struct sas_task *);
 
index d6e7994aa634666f1ff072bf2fa96220d4b7e19f..81dd12edc38c4e7fb5d3699a088bbec88eb2d1f7 100644 (file)
@@ -9,6 +9,7 @@
 #define MSG_SIMPLE_TAG 0x20
 #define MSG_HEAD_TAG   0x21
 #define MSG_ORDERED_TAG        0x22
+#define MSG_ACA_TAG    0x24    /* unsupported */
 
 #define SCSI_NO_TAG    (-1)    /* identify no tag in use */
 
index f1de3e0c75bcad1da0cbed760272fe5e190bccdc..3a4bd3a3c68d25cb2ccd6896a2750a761668937a 100644 (file)
@@ -248,8 +248,7 @@ typedef int (*hw_write_t)(void *,const char* ,int);
 extern struct snd_ac97_bus_ops soc_ac97_ops;
 
 enum snd_soc_control_type {
-       SND_SOC_CUSTOM = 1,
-       SND_SOC_I2C,
+       SND_SOC_I2C = 1,
        SND_SOC_SPI,
 };
 
index 1d3b5b2f0dbcfcb51199b52383bc9fdc07cde746..561ac99def5af8b51d9db422625dcf1712907267 100644 (file)
@@ -98,6 +98,7 @@ enum transport_state_table {
        TRANSPORT_REMOVE        = 14,
        TRANSPORT_FREE          = 15,
        TRANSPORT_NEW_CMD_MAP   = 16,
+       TRANSPORT_FREE_CMD_INTR = 17,
 };
 
 /* Used for struct se_cmd->se_cmd_flags */
index dc78f77f9450c042c0d10bf9d0bb4f85f71cf836..747e1404dca0db5c43041e6521eb4ba95ee5ed14 100644 (file)
@@ -77,7 +77,6 @@ struct target_core_fabric_ops {
        u16 (*set_fabric_sense_len)(struct se_cmd *, u32);
        u16 (*get_fabric_sense_len)(void);
        int (*is_state_remove)(struct se_cmd *);
-       u64 (*pack_lun)(unsigned int);
        /*
         * fabric module calls for target_core_fabric_configfs.c
         */
index 59aa464f6ee27b59a084061e22763a855d6341e6..24a1c6cb83c348eeeb4e575e460b4e5ac7c36882 100644 (file)
@@ -172,6 +172,7 @@ extern int transport_generic_handle_cdb_map(struct se_cmd *);
 extern int transport_generic_handle_data(struct se_cmd *);
 extern void transport_new_cmd_failure(struct se_cmd *);
 extern int transport_generic_handle_tmr(struct se_cmd *);
+extern void transport_generic_free_cmd_intr(struct se_cmd *);
 extern void __transport_stop_task_timer(struct se_task *, unsigned long *);
 extern unsigned char transport_asciihex_to_binaryhex(unsigned char val[2]);
 extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32,
index f445cff66ab716f01aead12284470ca30f5b1ec7..4114129f0794cdcc79fb9fc9b2f0aa69f76e54dd 100644 (file)
@@ -28,7 +28,7 @@ struct extent_buffer;
                { BTRFS_SHARED_DATA_REF_KEY,    "SHARED_DATA_REF" })
 
 #define __show_root_type(obj)                                          \
-       __print_symbolic(obj,                                           \
+       __print_symbolic_u64(obj,                                       \
                { BTRFS_ROOT_TREE_OBJECTID,     "ROOT_TREE"     },      \
                { BTRFS_EXTENT_TREE_OBJECTID,   "EXTENT_TREE"   },      \
                { BTRFS_CHUNK_TREE_OBJECTID,    "CHUNK_TREE"    },      \
@@ -125,7 +125,7 @@ DEFINE_EVENT(btrfs__inode, btrfs_inode_evict,
 );
 
 #define __show_map_type(type)                                          \
-       __print_symbolic(type,                                          \
+       __print_symbolic_u64(type,                                      \
                { EXTENT_MAP_LAST_BYTE, "LAST_BYTE"     },              \
                { EXTENT_MAP_HOLE,      "HOLE"          },              \
                { EXTENT_MAP_INLINE,    "INLINE"        },              \
index e09592d2f916adfdf041272e3b7a672379f7eea1..5ce2b2f5f524de65de6902a97232886196d7575f 100644 (file)
@@ -26,7 +26,7 @@ TRACE_EVENT(ext4_free_inode,
                __field(        umode_t, mode                   )
                __field(        uid_t,  uid                     )
                __field(        gid_t,  gid                     )
-               __field(        blkcnt_t, blocks                )
+               __field(        __u64, blocks                   )
        ),
 
        TP_fast_assign(
@@ -40,9 +40,8 @@ TRACE_EVENT(ext4_free_inode,
 
        TP_printk("dev %d,%d ino %lu mode 0%o uid %u gid %u blocks %llu",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
-                 (unsigned long) __entry->ino,
-                 __entry->mode, __entry->uid, __entry->gid,
-                 (unsigned long long) __entry->blocks)
+                 (unsigned long) __entry->ino, __entry->mode,
+                 __entry->uid, __entry->gid, __entry->blocks)
 );
 
 TRACE_EVENT(ext4_request_inode,
@@ -178,7 +177,7 @@ TRACE_EVENT(ext4_begin_ordered_truncate,
        TP_printk("dev %d,%d ino %lu new_size %lld",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
-                 (long long) __entry->new_size)
+                 __entry->new_size)
 );
 
 DECLARE_EVENT_CLASS(ext4__write_begin,
@@ -204,7 +203,7 @@ DECLARE_EVENT_CLASS(ext4__write_begin,
                __entry->flags  = flags;
        ),
 
-       TP_printk("dev %d,%d ino %lu pos %llu len %u flags %u",
+       TP_printk("dev %d,%d ino %lu pos %lld len %u flags %u",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  __entry->pos, __entry->len, __entry->flags)
@@ -248,7 +247,7 @@ DECLARE_EVENT_CLASS(ext4__write_end,
                __entry->copied = copied;
        ),
 
-       TP_printk("dev %d,%d ino %lu pos %llu len %u copied %u",
+       TP_printk("dev %d,%d ino %lu pos %lld len %u copied %u",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  __entry->pos, __entry->len, __entry->copied)
@@ -286,29 +285,6 @@ DEFINE_EVENT(ext4__write_end, ext4_da_write_end,
        TP_ARGS(inode, pos, len, copied)
 );
 
-TRACE_EVENT(ext4_writepage,
-       TP_PROTO(struct inode *inode, struct page *page),
-
-       TP_ARGS(inode, page),
-
-       TP_STRUCT__entry(
-               __field(        dev_t,  dev                     )
-               __field(        ino_t,  ino                     )
-               __field(        pgoff_t, index                  )
-
-       ),
-
-       TP_fast_assign(
-               __entry->dev    = inode->i_sb->s_dev;
-               __entry->ino    = inode->i_ino;
-               __entry->index  = page->index;
-       ),
-
-       TP_printk("dev %d,%d ino %lu page_index %lu",
-                 MAJOR(__entry->dev), MINOR(__entry->dev),
-                 (unsigned long) __entry->ino, __entry->index)
-);
-
 TRACE_EVENT(ext4_da_writepages,
        TP_PROTO(struct inode *inode, struct writeback_control *wbc),
 
@@ -341,7 +317,7 @@ TRACE_EVENT(ext4_da_writepages,
        ),
 
        TP_printk("dev %d,%d ino %lu nr_to_write %ld pages_skipped %ld "
-                 "range_start %llu range_end %llu sync_mode %d"
+                 "range_start %lld range_end %lld sync_mode %d"
                  "for_kupdate %d range_cyclic %d writeback_index %lu",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino, __entry->nr_to_write,
@@ -449,7 +425,14 @@ DECLARE_EVENT_CLASS(ext4__page_op,
        TP_printk("dev %d,%d ino %lu page_index %lu",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
-                 __entry->index)
+                 (unsigned long) __entry->index)
+);
+
+DEFINE_EVENT(ext4__page_op, ext4_writepage,
+
+       TP_PROTO(struct page *page),
+
+       TP_ARGS(page)
 );
 
 DEFINE_EVENT(ext4__page_op, ext4_readpage,
@@ -489,7 +472,7 @@ TRACE_EVENT(ext4_invalidatepage,
        TP_printk("dev %d,%d ino %lu page_index %lu offset %lu",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
-                 __entry->index, __entry->offset)
+                 (unsigned long) __entry->index, __entry->offset)
 );
 
 TRACE_EVENT(ext4_discard_blocks,
@@ -562,12 +545,10 @@ DEFINE_EVENT(ext4__mb_new_pa, ext4_mb_new_group_pa,
 );
 
 TRACE_EVENT(ext4_mb_release_inode_pa,
-       TP_PROTO(struct super_block *sb,
-                struct inode *inode,
-                struct ext4_prealloc_space *pa,
+       TP_PROTO(struct ext4_prealloc_space *pa,
                 unsigned long long block, unsigned int count),
 
-       TP_ARGS(sb, inode, pa, block, count),
+       TP_ARGS(pa, block, count),
 
        TP_STRUCT__entry(
                __field(        dev_t,  dev                     )
@@ -578,8 +559,8 @@ TRACE_EVENT(ext4_mb_release_inode_pa,
        ),
 
        TP_fast_assign(
-               __entry->dev            = sb->s_dev;
-               __entry->ino            = inode->i_ino;
+               __entry->dev            = pa->pa_inode->i_sb->s_dev;
+               __entry->ino            = pa->pa_inode->i_ino;
                __entry->block          = block;
                __entry->count          = count;
        ),
@@ -591,10 +572,9 @@ TRACE_EVENT(ext4_mb_release_inode_pa,
 );
 
 TRACE_EVENT(ext4_mb_release_group_pa,
-       TP_PROTO(struct super_block *sb,
-                struct ext4_prealloc_space *pa),
+       TP_PROTO(struct ext4_prealloc_space *pa),
 
-       TP_ARGS(sb, pa),
+       TP_ARGS(pa),
 
        TP_STRUCT__entry(
                __field(        dev_t,  dev                     )
@@ -604,7 +584,7 @@ TRACE_EVENT(ext4_mb_release_group_pa,
        ),
 
        TP_fast_assign(
-               __entry->dev            = sb->s_dev;
+               __entry->dev            = pa->pa_inode->i_sb->s_dev;
                __entry->pa_pstart      = pa->pa_pstart;
                __entry->pa_len         = pa->pa_len;
        ),
@@ -666,10 +646,10 @@ TRACE_EVENT(ext4_request_blocks,
                __field(        ino_t,  ino                     )
                __field(        unsigned int, flags             )
                __field(        unsigned int, len               )
-               __field(        __u64,  logical                 )
+               __field(        __u32,  logical                 )
+               __field(        __u32,  lleft                   )
+               __field(        __u32,  lright                  )
                __field(        __u64,  goal                    )
-               __field(        __u64,  lleft                   )
-               __field(        __u64,  lright                  )
                __field(        __u64,  pleft                   )
                __field(        __u64,  pright                  )
        ),
@@ -687,17 +667,13 @@ TRACE_EVENT(ext4_request_blocks,
                __entry->pright = ar->pright;
        ),
 
-       TP_printk("dev %d,%d ino %lu flags %u len %u lblk %llu goal %llu "
-                 "lleft %llu lright %llu pleft %llu pright %llu ",
+       TP_printk("dev %d,%d ino %lu flags %u len %u lblk %u goal %llu "
+                 "lleft %u lright %u pleft %llu pright %llu ",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
-                 (unsigned long) __entry->ino,
-                 __entry->flags, __entry->len,
-                 (unsigned long long) __entry->logical,
-                 (unsigned long long) __entry->goal,
-                 (unsigned long long) __entry->lleft,
-                 (unsigned long long) __entry->lright,
-                 (unsigned long long) __entry->pleft,
-                 (unsigned long long) __entry->pright)
+                 (unsigned long) __entry->ino, __entry->flags,
+                 __entry->len, __entry->logical, __entry->goal,
+                 __entry->lleft, __entry->lright, __entry->pleft,
+                 __entry->pright)
 );
 
 TRACE_EVENT(ext4_allocate_blocks,
@@ -711,10 +687,10 @@ TRACE_EVENT(ext4_allocate_blocks,
                __field(        __u64,  block                   )
                __field(        unsigned int, flags             )
                __field(        unsigned int, len               )
-               __field(        __u64,  logical                 )
+               __field(        __u32,  logical                 )
+               __field(        __u32,  lleft                   )
+               __field(        __u32,  lright                  )
                __field(        __u64,  goal                    )
-               __field(        __u64,  lleft                   )
-               __field(        __u64,  lright                  )
                __field(        __u64,  pleft                   )
                __field(        __u64,  pright                  )
        ),
@@ -733,17 +709,13 @@ TRACE_EVENT(ext4_allocate_blocks,
                __entry->pright = ar->pright;
        ),
 
-       TP_printk("dev %d,%d ino %lu flags %u len %u block %llu lblk %llu "
-                 "goal %llu lleft %llu lright %llu pleft %llu pright %llu",
+       TP_printk("dev %d,%d ino %lu flags %u len %u block %llu lblk %u "
+                 "goal %llu lleft %u lright %u pleft %llu pright %llu",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
-                 (unsigned long) __entry->ino,
-                 __entry->flags, __entry->len, __entry->block,
-                 (unsigned long long) __entry->logical,
-                 (unsigned long long) __entry->goal,
-                 (unsigned long long) __entry->lleft,
-                 (unsigned long long) __entry->lright,
-                 (unsigned long long) __entry->pleft,
-                 (unsigned long long) __entry->pright)
+                 (unsigned long) __entry->ino, __entry->flags,
+                 __entry->len, __entry->block, __entry->logical,
+                 __entry->goal,  __entry->lleft, __entry->lright,
+                 __entry->pleft, __entry->pright)
 );
 
 TRACE_EVENT(ext4_free_blocks,
@@ -755,10 +727,10 @@ TRACE_EVENT(ext4_free_blocks,
        TP_STRUCT__entry(
                __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
-               __field(      umode_t, mode                     )
+               __field(        umode_t, mode                   )
                __field(        __u64,  block                   )
                __field(        unsigned long,  count           )
-               __field(         int,   flags                   )
+               __field(        int,    flags                   )
        ),
 
        TP_fast_assign(
@@ -798,7 +770,7 @@ TRACE_EVENT(ext4_sync_file_enter,
                __entry->parent         = dentry->d_parent->d_inode->i_ino;
        ),
 
-       TP_printk("dev %d,%d ino %ld parent %ld datasync %d ",
+       TP_printk("dev %d,%d ino %lu parent %lu datasync %d ",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  (unsigned long) __entry->parent, __entry->datasync)
@@ -821,7 +793,7 @@ TRACE_EVENT(ext4_sync_file_exit,
                __entry->dev            = inode->i_sb->s_dev;
        ),
 
-       TP_printk("dev %d,%d ino %ld ret %d",
+       TP_printk("dev %d,%d ino %lu ret %d",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  __entry->ret)
@@ -1005,7 +977,7 @@ DECLARE_EVENT_CLASS(ext4__mballoc,
                __entry->result_len     = len;
        ),
 
-       TP_printk("dev %d,%d inode %lu extent %u/%d/%u ",
+       TP_printk("dev %d,%d inode %lu extent %u/%d/%d ",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  __entry->result_group, __entry->result_start,
@@ -1093,7 +1065,7 @@ TRACE_EVENT(ext4_da_update_reserve_space,
                  "allocated_meta_blocks %d",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
-                 __entry->mode,  (unsigned long long) __entry->i_blocks,
+                 __entry->mode, __entry->i_blocks,
                  __entry->used_blocks, __entry->reserved_data_blocks,
                  __entry->reserved_meta_blocks, __entry->allocated_meta_blocks)
 );
@@ -1127,7 +1099,7 @@ TRACE_EVENT(ext4_da_reserve_space,
                  "reserved_data_blocks %d reserved_meta_blocks %d",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
-                 __entry->mode, (unsigned long long) __entry->i_blocks,
+                 __entry->mode, __entry->i_blocks,
                  __entry->md_needed, __entry->reserved_data_blocks,
                  __entry->reserved_meta_blocks)
 );
@@ -1164,7 +1136,7 @@ TRACE_EVENT(ext4_da_release_space,
                  "allocated_meta_blocks %d",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
-                 __entry->mode, (unsigned long long) __entry->i_blocks,
+                 __entry->mode, __entry->i_blocks,
                  __entry->freed_blocks, __entry->reserved_data_blocks,
                  __entry->reserved_meta_blocks, __entry->allocated_meta_blocks)
 );
@@ -1239,14 +1211,15 @@ TRACE_EVENT(ext4_direct_IO_enter,
                __entry->rw     = rw;
        ),
 
-       TP_printk("dev %d,%d ino %lu pos %llu len %lu rw %d",
+       TP_printk("dev %d,%d ino %lu pos %lld len %lu rw %d",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
-                 (unsigned long long) __entry->pos, __entry->len, __entry->rw)
+                 __entry->pos, __entry->len, __entry->rw)
 );
 
 TRACE_EVENT(ext4_direct_IO_exit,
-       TP_PROTO(struct inode *inode, loff_t offset, unsigned long len, int rw, int ret),
+       TP_PROTO(struct inode *inode, loff_t offset, unsigned long len,
+                int rw, int ret),
 
        TP_ARGS(inode, offset, len, rw, ret),
 
@@ -1268,10 +1241,10 @@ TRACE_EVENT(ext4_direct_IO_exit,
                __entry->ret    = ret;
        ),
 
-       TP_printk("dev %d,%d ino %lu pos %llu len %lu rw %d ret %d",
+       TP_printk("dev %d,%d ino %lu pos %lld len %lu rw %d ret %d",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
-                 (unsigned long long) __entry->pos, __entry->len,
+                 __entry->pos, __entry->len,
                  __entry->rw, __entry->ret)
 );
 
@@ -1296,15 +1269,15 @@ TRACE_EVENT(ext4_fallocate_enter,
                __entry->mode   = mode;
        ),
 
-       TP_printk("dev %d,%d ino %ld pos %llu len %llu mode %d",
+       TP_printk("dev %d,%d ino %lu pos %lld len %lld mode %d",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
-                 (unsigned long) __entry->ino,
-                 (unsigned long long) __entry->pos,
-                 (unsigned long long) __entry->len, __entry->mode)
+                 (unsigned long) __entry->ino, __entry->pos,
+                 __entry->len, __entry->mode)
 );
 
 TRACE_EVENT(ext4_fallocate_exit,
-       TP_PROTO(struct inode *inode, loff_t offset, unsigned int max_blocks, int ret),
+       TP_PROTO(struct inode *inode, loff_t offset,
+                unsigned int max_blocks, int ret),
 
        TP_ARGS(inode, offset, max_blocks, ret),
 
@@ -1312,7 +1285,7 @@ TRACE_EVENT(ext4_fallocate_exit,
                __field(        ino_t,  ino                     )
                __field(        dev_t,  dev                     )
                __field(        loff_t, pos                     )
-               __field(        unsigned,       blocks          )
+               __field(        unsigned int,   blocks          )
                __field(        int,    ret                     )
        ),
 
@@ -1324,10 +1297,10 @@ TRACE_EVENT(ext4_fallocate_exit,
                __entry->ret    = ret;
        ),
 
-       TP_printk("dev %d,%d ino %ld pos %llu blocks %d ret %d",
+       TP_printk("dev %d,%d ino %lu pos %lld blocks %u ret %d",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
-                 (unsigned long long) __entry->pos, __entry->blocks,
+                 __entry->pos, __entry->blocks,
                  __entry->ret)
 );
 
@@ -1350,7 +1323,7 @@ TRACE_EVENT(ext4_unlink_enter,
                __entry->dev            = dentry->d_inode->i_sb->s_dev;
        ),
 
-       TP_printk("dev %d,%d ino %ld size %lld parent %ld",
+       TP_printk("dev %d,%d ino %lu size %lld parent %lu",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino, __entry->size,
                  (unsigned long) __entry->parent)
@@ -1373,7 +1346,7 @@ TRACE_EVENT(ext4_unlink_exit,
                __entry->ret            = ret;
        ),
 
-       TP_printk("dev %d,%d ino %ld ret %d",
+       TP_printk("dev %d,%d ino %lu ret %d",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  __entry->ret)
@@ -1387,7 +1360,7 @@ DECLARE_EVENT_CLASS(ext4__truncate,
        TP_STRUCT__entry(
                __field(        ino_t,          ino             )
                __field(        dev_t,          dev             )
-               __field(        blkcnt_t,       blocks          )
+               __field(        __u64,          blocks          )
        ),
 
        TP_fast_assign(
@@ -1396,9 +1369,9 @@ DECLARE_EVENT_CLASS(ext4__truncate,
                __entry->blocks = inode->i_blocks;
        ),
 
-       TP_printk("dev %d,%d ino %lu blocks %lu",
+       TP_printk("dev %d,%d ino %lu blocks %llu",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
-                 (unsigned long) __entry->ino, (unsigned long) __entry->blocks)
+                 (unsigned long) __entry->ino, __entry->blocks)
 );
 
 DEFINE_EVENT(ext4__truncate, ext4_truncate_enter,
@@ -1417,7 +1390,7 @@ DEFINE_EVENT(ext4__truncate, ext4_truncate_exit,
 
 DECLARE_EVENT_CLASS(ext4__map_blocks_enter,
        TP_PROTO(struct inode *inode, ext4_lblk_t lblk,
-                unsigned len, unsigned flags),
+                unsigned int len, unsigned int flags),
 
        TP_ARGS(inode, lblk, len, flags),
 
@@ -1425,8 +1398,8 @@ DECLARE_EVENT_CLASS(ext4__map_blocks_enter,
                __field(        ino_t,          ino             )
                __field(        dev_t,          dev             )
                __field(        ext4_lblk_t,    lblk            )
-               __field(        unsigned,       len             )
-               __field(        unsigned,       flags           )
+               __field(        unsigned int,   len             )
+               __field(        unsigned int,   flags           )
        ),
 
        TP_fast_assign(
@@ -1440,7 +1413,7 @@ DECLARE_EVENT_CLASS(ext4__map_blocks_enter,
        TP_printk("dev %d,%d ino %lu lblk %u len %u flags %u",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
-                 (unsigned) __entry->lblk, __entry->len, __entry->flags)
+                 __entry->lblk, __entry->len, __entry->flags)
 );
 
 DEFINE_EVENT(ext4__map_blocks_enter, ext4_ext_map_blocks_enter,
@@ -1459,7 +1432,7 @@ DEFINE_EVENT(ext4__map_blocks_enter, ext4_ind_map_blocks_enter,
 
 DECLARE_EVENT_CLASS(ext4__map_blocks_exit,
        TP_PROTO(struct inode *inode, ext4_lblk_t lblk,
-                ext4_fsblk_t pblk, unsigned len, int ret),
+                ext4_fsblk_t pblk, unsigned int len, int ret),
 
        TP_ARGS(inode, lblk, pblk, len, ret),
 
@@ -1468,7 +1441,7 @@ DECLARE_EVENT_CLASS(ext4__map_blocks_exit,
                __field(        dev_t,          dev             )
                __field(        ext4_lblk_t,    lblk            )
                __field(        ext4_fsblk_t,   pblk            )
-               __field(        unsigned,       len             )
+               __field(        unsigned int,   len             )
                __field(        int,            ret             )
        ),
 
@@ -1484,7 +1457,7 @@ DECLARE_EVENT_CLASS(ext4__map_blocks_exit,
        TP_printk("dev %d,%d ino %lu lblk %u pblk %llu len %u ret %d",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
-                 (unsigned) __entry->lblk, (unsigned long long) __entry->pblk,
+                 __entry->lblk, __entry->pblk,
                  __entry->len, __entry->ret)
 );
 
@@ -1524,7 +1497,7 @@ TRACE_EVENT(ext4_ext_load_extent,
        TP_printk("dev %d,%d ino %lu lblk %u pblk %llu",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
-                 (unsigned) __entry->lblk, (unsigned long long) __entry->pblk)
+                 __entry->lblk, __entry->pblk)
 );
 
 TRACE_EVENT(ext4_load_inode,
diff --git a/include/trace/events/gpio.h b/include/trace/events/gpio.h
new file mode 100644 (file)
index 0000000..927a8ad
--- /dev/null
@@ -0,0 +1,56 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM gpio
+
+#if !defined(_TRACE_GPIO_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_GPIO_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(gpio_direction,
+
+       TP_PROTO(unsigned gpio, int in, int err),
+
+       TP_ARGS(gpio, in, err),
+
+       TP_STRUCT__entry(
+               __field(unsigned, gpio)
+               __field(int, in)
+               __field(int, err)
+       ),
+
+       TP_fast_assign(
+               __entry->gpio = gpio;
+               __entry->in = in;
+               __entry->err = err;
+       ),
+
+       TP_printk("%u %3s (%d)", __entry->gpio,
+               __entry->in ? "in" : "out", __entry->err)
+);
+
+TRACE_EVENT(gpio_value,
+
+       TP_PROTO(unsigned gpio, int get, int value),
+
+       TP_ARGS(gpio, get, value),
+
+       TP_STRUCT__entry(
+               __field(unsigned, gpio)
+               __field(int, get)
+               __field(int, value)
+       ),
+
+       TP_fast_assign(
+               __entry->gpio = gpio;
+               __entry->get = get;
+               __entry->value = value;
+       ),
+
+       TP_printk("%u %3s %d", __entry->gpio,
+               __entry->get ? "get" : "set", __entry->value)
+);
+
+#endif /* if !defined(_TRACE_GPIO_H) || defined(TRACE_HEADER_MULTI_READ) */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index ae045ca7d356033d49c8a9650a618c206503f68c..1c09820df58564f8d0430d996998edc6f8d893c0 100644 (file)
@@ -20,7 +20,8 @@ struct softirq_action;
                         softirq_name(BLOCK_IOPOLL),    \
                         softirq_name(TASKLET),         \
                         softirq_name(SCHED),           \
-                        softirq_name(HRTIMER))
+                        softirq_name(HRTIMER),         \
+                        softirq_name(RCU))
 
 /**
  * irq_handler_entry - called immediately before the irq action handler
index 5f247f5ffc565c50e49f70eb84f52b101d3c03f0..f99645d05a8f201eea78a399468e51b3876d2019 100644 (file)
 TRACE_EVENT(net_dev_xmit,
 
        TP_PROTO(struct sk_buff *skb,
-                int rc),
+                int rc,
+                struct net_device *dev,
+                unsigned int skb_len),
 
-       TP_ARGS(skb, rc),
+       TP_ARGS(skb, rc, dev, skb_len),
 
        TP_STRUCT__entry(
                __field(        void *,         skbaddr         )
                __field(        unsigned int,   len             )
                __field(        int,            rc              )
-               __string(       name,           skb->dev->name  )
+               __string(       name,           dev->name       )
        ),
 
        TP_fast_assign(
                __entry->skbaddr = skb;
-               __entry->len = skb->len;
+               __entry->len = skb_len;
                __entry->rc = rc;
-               __assign_str(name, skb->dev->name);
+               __assign_str(name, dev->name);
        ),
 
        TP_printk("dev=%s skbaddr=%p len=%u rc=%d",
index ea422aaa23e12a2397e08a167e36dd65ce7041cf..b2c33bd955faa4536082e62e6c9f17946994afde 100644 (file)
@@ -6,6 +6,8 @@
 
 #include <linux/types.h>
 #include <linux/tracepoint.h>
+#include <linux/mm.h>
+#include <linux/memcontrol.h>
 #include "gfpflags.h"
 
 #define RECLAIM_WB_ANON                0x0001u
@@ -310,6 +312,87 @@ TRACE_EVENT(mm_vmscan_lru_shrink_inactive,
                show_reclaim_flags(__entry->reclaim_flags))
 );
 
+TRACE_EVENT(replace_swap_token,
+       TP_PROTO(struct mm_struct *old_mm,
+                struct mm_struct *new_mm),
+
+       TP_ARGS(old_mm, new_mm),
+
+       TP_STRUCT__entry(
+               __field(struct mm_struct*,      old_mm)
+               __field(unsigned int,           old_prio)
+               __field(struct mm_struct*,      new_mm)
+               __field(unsigned int,           new_prio)
+       ),
+
+       TP_fast_assign(
+               __entry->old_mm   = old_mm;
+               __entry->old_prio = old_mm ? old_mm->token_priority : 0;
+               __entry->new_mm   = new_mm;
+               __entry->new_prio = new_mm->token_priority;
+       ),
+
+       TP_printk("old_token_mm=%p old_prio=%u new_token_mm=%p new_prio=%u",
+                 __entry->old_mm, __entry->old_prio,
+                 __entry->new_mm, __entry->new_prio)
+);
+
+DECLARE_EVENT_CLASS(put_swap_token_template,
+       TP_PROTO(struct mm_struct *swap_token_mm),
+
+       TP_ARGS(swap_token_mm),
+
+       TP_STRUCT__entry(
+               __field(struct mm_struct*, swap_token_mm)
+       ),
+
+       TP_fast_assign(
+               __entry->swap_token_mm = swap_token_mm;
+       ),
+
+       TP_printk("token_mm=%p", __entry->swap_token_mm)
+);
+
+DEFINE_EVENT(put_swap_token_template, put_swap_token,
+       TP_PROTO(struct mm_struct *swap_token_mm),
+       TP_ARGS(swap_token_mm)
+);
+
+DEFINE_EVENT_CONDITION(put_swap_token_template, disable_swap_token,
+       TP_PROTO(struct mm_struct *swap_token_mm),
+       TP_ARGS(swap_token_mm),
+       TP_CONDITION(swap_token_mm != NULL)
+);
+
+TRACE_EVENT_CONDITION(update_swap_token_priority,
+       TP_PROTO(struct mm_struct *mm,
+                unsigned int old_prio,
+                struct mm_struct *swap_token_mm),
+
+       TP_ARGS(mm, old_prio, swap_token_mm),
+
+       TP_CONDITION(mm->token_priority != old_prio),
+
+       TP_STRUCT__entry(
+               __field(struct mm_struct*, mm)
+               __field(unsigned int, old_prio)
+               __field(unsigned int, new_prio)
+               __field(struct mm_struct*, swap_token_mm)
+               __field(unsigned int, swap_token_prio)
+       ),
+
+       TP_fast_assign(
+               __entry->mm             = mm;
+               __entry->old_prio       = old_prio;
+               __entry->new_prio       = mm->token_priority;
+               __entry->swap_token_mm  = swap_token_mm;
+               __entry->swap_token_prio = swap_token_mm ? swap_token_mm->token_priority : 0;
+       ),
+
+       TP_printk("mm=%p old_prio=%u new_prio=%u swap_token_mm=%p token_prio=%u",
+                 __entry->mm, __entry->old_prio, __entry->new_prio,
+                 __entry->swap_token_mm, __entry->swap_token_prio)
+);
 
 #endif /* _TRACE_VMSCAN_H */
 
index 3e68366d485af387a1f894bec7e15f491484d3a3..533c49f480477321f3193320321cbf273b092698 100644 (file)
                ftrace_print_symbols_seq(p, value, symbols);            \
        })
 
+#undef __print_symbolic_u64
+#if BITS_PER_LONG == 32
+#define __print_symbolic_u64(value, symbol_array...)                   \
+       ({                                                              \
+               static const struct trace_print_flags_u64 symbols[] =   \
+                       { symbol_array, { -1, NULL } };                 \
+               ftrace_print_symbols_seq_u64(p, value, symbols);        \
+       })
+#else
+#define __print_symbolic_u64(value, symbol_array...)                   \
+                       __print_symbolic(value, symbol_array)
+#endif
+
 #undef __print_hex
 #define __print_hex(buf, buf_len) ftrace_print_hex_seq(p, buf, buf_len)
 
similarity index 86%
rename from arch/arm/plat-omap/include/plat/panel-generic-dpi.h
rename to include/video/omap-panel-generic-dpi.h
index 790619734bcd920eafdcc523dc35a682733d44b7..127e3f20328e59e17d6f2b4b7de8f3eba2d5fee8 100644 (file)
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H
-#define __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H
+#ifndef __OMAP_PANEL_GENERIC_DPI_H
+#define __OMAP_PANEL_GENERIC_DPI_H
 
-#include "display.h"
+struct omap_dss_device;
 
 /**
  * struct panel_generic_dpi_data - panel driver configuration data
@@ -34,4 +34,4 @@ struct panel_generic_dpi_data {
        void (*platform_disable)(struct omap_dss_device *dssdev);
 };
 
-#endif /* __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H */
+#endif /* __OMAP_PANEL_GENERIC_DPI_H */
similarity index 65%
rename from arch/arm/plat-omap/include/plat/nokia-dsi-panel.h
rename to include/video/omap-panel-nokia-dsi.h
index 01ab6572ccbbb35c19f9e16db3d806f1701f6f63..921ae9327228cb7592b1f908fc4de2ed3eba4192 100644 (file)
@@ -1,14 +1,15 @@
-#ifndef __ARCH_ARM_PLAT_OMAP_NOKIA_DSI_PANEL_H
-#define __ARCH_ARM_PLAT_OMAP_NOKIA_DSI_PANEL_H
+#ifndef __OMAP_NOKIA_DSI_PANEL_H
+#define __OMAP_NOKIA_DSI_PANEL_H
 
-#include "display.h"
+struct omap_dss_device;
 
 /**
  * struct nokia_dsi_panel_data - Nokia DSI panel driver configuration
  * @name: panel name
  * @use_ext_te: use external TE
  * @ext_te_gpio: external TE GPIO
- * @use_esd_check: perform ESD checks
+ * @esd_interval: interval of ESD checks, 0 = disabled (ms)
+ * @ulps_timeout: time to wait before entering ULPS, 0 = disabled (ms)
  * @max_backlight_level: maximum backlight level
  * @set_backlight: pointer to backlight set function
  * @get_backlight: pointer to backlight get function
@@ -21,11 +22,12 @@ struct nokia_dsi_panel_data {
        bool use_ext_te;
        int ext_te_gpio;
 
-       bool use_esd_check;
+       unsigned esd_interval;
+       unsigned ulps_timeout;
 
        int max_backlight_level;
        int (*set_backlight)(struct omap_dss_device *dssdev, int level);
        int (*get_backlight)(struct omap_dss_device *dssdev);
 };
 
-#endif /* __ARCH_ARM_PLAT_OMAP_NOKIA_DSI_PANEL_H */
+#endif /* __OMAP_NOKIA_DSI_PANEL_H */
similarity index 85%
rename from arch/arm/plat-omap/include/plat/display.h
rename to include/video/omapdss.h
index 5e04ddc18fa8c512fbafb205e6818d1b064e2335..892b97f8e1576f969821688820350a0020762641 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/include/asm-arm/arch-omap/display.h
- *
  * Copyright (C) 2008 Nokia Corporation
  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
  *
@@ -17,8 +15,8 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __ASM_ARCH_OMAP_DISPLAY_H
-#define __ASM_ARCH_OMAP_DISPLAY_H
+#ifndef __OMAP_OMAPDSS_H
+#define __OMAP_OMAPDSS_H
 
 #include <linux/list.h>
 #include <linux/kobject.h>
@@ -88,6 +86,11 @@ enum omap_color_mode {
        OMAP_DSS_COLOR_ARGB32   = 1 << 11, /* ARGB32 */
        OMAP_DSS_COLOR_RGBA32   = 1 << 12, /* RGBA32 */
        OMAP_DSS_COLOR_RGBX32   = 1 << 13, /* RGBx32 */
+       OMAP_DSS_COLOR_NV12             = 1 << 14, /* NV12 format: YUV 4:2:0 */
+       OMAP_DSS_COLOR_RGBA16           = 1 << 15, /* RGBA16 - 4444 */
+       OMAP_DSS_COLOR_RGBX16           = 1 << 16, /* RGBx16 - 4444 */
+       OMAP_DSS_COLOR_ARGB16_1555      = 1 << 17, /* ARGB16 - 1555 */
+       OMAP_DSS_COLOR_XRGB16_1555      = 1 << 18, /* xRGB16 - 1555 */
 };
 
 enum omap_lcd_display_type {
@@ -174,6 +177,17 @@ enum omap_overlay_manager_caps {
        OMAP_DSS_OVL_MGR_CAP_DISPC = 1 << 0,
 };
 
+enum omap_dss_clk_source {
+       OMAP_DSS_CLK_SRC_FCK = 0,               /* OMAP2/3: DSS1_ALWON_FCLK
+                                                * OMAP4: DSS_FCLK */
+       OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC,   /* OMAP3: DSI1_PLL_FCLK
+                                                * OMAP4: PLL1_CLK1 */
+       OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI,     /* OMAP3: DSI2_PLL_FCLK
+                                                * OMAP4: PLL1_CLK2 */
+       OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC,  /* OMAP4: PLL2_CLK1 */
+       OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI,    /* OMAP4: PLL2_CLK2 */
+};
+
 /* RFBI */
 
 struct rfbi_timings {
@@ -205,20 +219,30 @@ int omap_rfbi_enable_te(bool enable, unsigned line);
 int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
                             unsigned hs_pulse_time, unsigned vs_pulse_time,
                             int hs_pol_inv, int vs_pol_inv, int extif_div);
+void rfbi_bus_lock(void);
+void rfbi_bus_unlock(void);
 
 /* DSI */
-void dsi_bus_lock(void);
-void dsi_bus_unlock(void);
-int dsi_vc_dcs_write(int channel, u8 *data, int len);
-int dsi_vc_dcs_write_0(int channel, u8 dcs_cmd);
-int dsi_vc_dcs_write_1(int channel, u8 dcs_cmd, u8 param);
-int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len);
-int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen);
-int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data);
-int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u8 *data1, u8 *data2);
-int dsi_vc_set_max_rx_packet_size(int channel, u16 len);
-int dsi_vc_send_null(int channel);
-int dsi_vc_send_bta_sync(int channel);
+void dsi_bus_lock(struct omap_dss_device *dssdev);
+void dsi_bus_unlock(struct omap_dss_device *dssdev);
+int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
+               int len);
+int dsi_vc_dcs_write_0(struct omap_dss_device *dssdev, int channel,
+               u8 dcs_cmd);
+int dsi_vc_dcs_write_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+               u8 param);
+int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
+               u8 *data, int len);
+int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+               u8 *buf, int buflen);
+int dsi_vc_dcs_read_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+               u8 *data);
+int dsi_vc_dcs_read_2(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+               u8 *data1, u8 *data2);
+int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel,
+               u16 len);
+int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel);
+int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel);
 
 /* Board specific data */
 struct omap_dss_board_info {
@@ -226,6 +250,7 @@ struct omap_dss_board_info {
        int num_devices;
        struct omap_dss_device **devices;
        struct omap_dss_device *default_device;
+       void (*dsi_mux_pads)(bool enable);
 };
 
 #if defined(CONFIG_OMAP2_DSS_MODULE) || defined(CONFIG_OMAP2_DSS)
@@ -280,6 +305,7 @@ struct omap_overlay_info {
 
        u32 paddr;
        void __iomem *vaddr;
+       u32 p_uv_addr;  /* for NV12 format */
        u16 screen_width;
        u16 width;
        u16 height;
@@ -400,18 +426,12 @@ struct omap_dss_device {
                        u8 data1_pol;
                        u8 data2_lane;
                        u8 data2_pol;
+                       u8 data3_lane;
+                       u8 data3_pol;
+                       u8 data4_lane;
+                       u8 data4_pol;
 
-                       struct {
-                               u16 regn;
-                               u16 regm;
-                               u16 regm_dispc;
-                               u16 regm_dsi;
-
-                               u16 lp_clk_div;
-
-                               u16 lck_div;
-                               u16 pck_div;
-                       } div;
+                       int module;
 
                        bool ext_te;
                        u8 ext_te_gpio;
@@ -423,6 +443,33 @@ struct omap_dss_device {
                } venc;
        } phy;
 
+       struct {
+               struct {
+                       struct {
+                               u16 lck_div;
+                               u16 pck_div;
+                               enum omap_dss_clk_source lcd_clk_src;
+                       } channel;
+
+                       enum omap_dss_clk_source dispc_fclk_src;
+               } dispc;
+
+               struct {
+                       u16 regn;
+                       u16 regm;
+                       u16 regm_dispc;
+                       u16 regm_dsi;
+
+                       u16 lp_clk_div;
+                       enum omap_dss_clk_source dsi_fclk_src;
+               } dsi;
+
+               struct {
+                       u16 regn;
+                       u16 regm2;
+               } hdmi;
+       } clocks;
+
        struct {
                struct omap_video_timings timings;
 
@@ -503,6 +550,8 @@ struct omap_dss_driver {
 
        void (*get_resolution)(struct omap_dss_device *dssdev,
                        u16 *xres, u16 *yres);
+       void (*get_dimensions)(struct omap_dss_device *dssdev,
+                       u32 *width, u32 *height);
        int (*get_recommended_bpp)(struct omap_dss_device *dssdev);
 
        int (*check_timings)(struct omap_dss_device *dssdev,
@@ -519,9 +568,6 @@ struct omap_dss_driver {
 int omap_dss_register_driver(struct omap_dss_driver *);
 void omap_dss_unregister_driver(struct omap_dss_driver *);
 
-int omap_dss_register_device(struct omap_dss_device *);
-void omap_dss_unregister_device(struct omap_dss_device *);
-
 void omap_dss_get_device(struct omap_dss_device *dssdev);
 void omap_dss_put_device(struct omap_dss_device *dssdev);
 #define for_each_dss_dev(d) while ((d = omap_dss_get_next_device(d)) != NULL)
@@ -553,7 +599,8 @@ int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
 #define to_dss_driver(x) container_of((x), struct omap_dss_driver, driver)
 #define to_dss_device(x) container_of((x), struct omap_dss_device, dev)
 
-void omapdss_dsi_vc_enable_hs(int channel, bool enable);
+void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
+               bool enable);
 int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable);
 
 int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
@@ -568,7 +615,8 @@ int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id);
 void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel);
 
 int omapdss_dsi_display_enable(struct omap_dss_device *dssdev);
-void omapdss_dsi_display_disable(struct omap_dss_device *dssdev);
+void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
+               bool disconnect_lanes, bool enter_ulps);
 
 int omapdss_dpi_display_enable(struct omap_dss_device *dssdev);
 void omapdss_dpi_display_disable(struct omap_dss_device *dssdev);
@@ -587,5 +635,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
 int omap_rfbi_update(struct omap_dss_device *dssdev,
                u16 x, u16 y, u16 w, u16 h,
                void (*callback)(void *), void *data);
+int omap_rfbi_configure(struct omap_dss_device *dssdev, int pixel_size,
+               int data_lines);
 
 #endif
index 2c8d369190b3af142bacb5796bb53d48ead04c81..d964e68fc61dab119e504f3f8feb1a5d0a44d36d 100644 (file)
@@ -2,6 +2,7 @@
 #define __ASM_SH_MOBILE_LCDC_H__
 
 #include <linux/fb.h>
+#include <video/sh_mobile_meram.h>
 
 enum {
        RGB8,   /* 24bpp, 8:8:8 */
@@ -87,11 +88,13 @@ struct sh_mobile_lcdc_chan_cfg {
        struct sh_mobile_lcdc_bl_info bl_info;
        struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */
        int nonstd;
+       struct sh_mobile_meram_cfg *meram_cfg;
 };
 
 struct sh_mobile_lcdc_info {
        int clock_source;
        struct sh_mobile_lcdc_chan_cfg ch[2];
+       struct sh_mobile_meram_info *meram_dev;
 };
 
 #endif /* __ASM_SH_MOBILE_LCDC_H__ */
diff --git a/include/video/sh_mobile_meram.h b/include/video/sh_mobile_meram.h
new file mode 100644 (file)
index 0000000..af602d6
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef __VIDEO_SH_MOBILE_MERAM_H__
+#define __VIDEO_SH_MOBILE_MERAM_H__
+
+/* For sh_mobile_meram_info.addr_mode */
+enum {
+       SH_MOBILE_MERAM_MODE0 = 0,
+       SH_MOBILE_MERAM_MODE1
+};
+
+enum {
+       SH_MOBILE_MERAM_PF_NV = 0,
+       SH_MOBILE_MERAM_PF_RGB,
+       SH_MOBILE_MERAM_PF_NV24
+};
+
+
+struct sh_mobile_meram_priv;
+struct sh_mobile_meram_ops;
+
+struct sh_mobile_meram_info {
+       int                             addr_mode;
+       struct sh_mobile_meram_ops      *ops;
+       struct sh_mobile_meram_priv     *priv;
+       struct platform_device          *pdev;
+};
+
+/* icb config */
+struct sh_mobile_meram_icb {
+       int marker_icb;         /* ICB # for Marker ICB */
+       int cache_icb;          /* ICB # for Cache ICB */
+       int meram_offset;       /* MERAM Buffer Offset to use */
+       int meram_size;         /* MERAM Buffer Size to use */
+
+       int cache_unit;         /* bytes to cache per ICB */
+};
+
+struct sh_mobile_meram_cfg {
+       struct sh_mobile_meram_icb      icb[2];
+       int                             pixelformat;
+       int                             current_reg;
+};
+
+struct module;
+struct sh_mobile_meram_ops {
+       struct module   *module;
+       /* register usage of meram */
+       int (*meram_register)(struct sh_mobile_meram_info *meram_dev,
+                             struct sh_mobile_meram_cfg *cfg,
+                             int xres, int yres, int pixelformat,
+                             unsigned long base_addr_y,
+                             unsigned long base_addr_c,
+                             unsigned long *icb_addr_y,
+                             unsigned long *icb_addr_c, int *pitch);
+
+       /* unregister usage of meram */
+       int (*meram_unregister)(struct sh_mobile_meram_info *meram_dev,
+                               struct sh_mobile_meram_cfg *cfg);
+
+       /* update meram settings */
+       int (*meram_update)(struct sh_mobile_meram_info *meram_dev,
+                           struct sh_mobile_meram_cfg *cfg,
+                           unsigned long base_addr_y,
+                           unsigned long base_addr_c,
+                           unsigned long *icb_addr_y,
+                           unsigned long *icb_addr_c);
+};
+
+#endif /* __VIDEO_SH_MOBILE_MERAM_H__  */
index 61e523af3c46c8311c354a4fb22e36048ebf2a0a..3d5d6db864fe9781e2fc79214474f7101c84187c 100644 (file)
@@ -44,6 +44,19 @@ typedef uint64_t blkif_sector_t;
  */
 #define BLKIF_OP_WRITE_BARRIER     2
 
+/*
+ * Recognised if "feature-flush-cache" is present in backend xenbus
+ * info.  A flush will ask the underlying storage hardware to flush its
+ * non-volatile caches as appropriate.  The "feature-flush-cache" node
+ * contains a boolean indicating whether flush requests are likely to
+ * succeed or fail. Either way, a flush request may fail at any time
+ * with BLKIF_RSP_EOPNOTSUPP if it is unsupported by the underlying
+ * block-device hardware. The boolean simply indicates whether or not it
+ * is worthwhile for the frontend to attempt flushes.  If a backend does
+ * not recognise BLKIF_OP_WRITE_FLUSH_CACHE, it should *not* create the
+ * "feature-flush-cache" node!
+ */
+#define BLKIF_OP_FLUSH_DISKCACHE   3
 /*
  * Maximum scatter/gather segments per request.
  * This is carefully chosen so that sizeof(struct blkif_ring) <= PAGE_SIZE.
index b33257bc7e83b58562dd5abc9f12cd89eadbc813..70213b4515ebcd562e0995ac6f14b5c1ba07e9a4 100644 (file)
@@ -58,6 +58,7 @@
 #define __HYPERVISOR_event_channel_op     32
 #define __HYPERVISOR_physdev_op           33
 #define __HYPERVISOR_hvm_op               34
+#define __HYPERVISOR_tmem_op              38
 
 /* Architecture-specific hypercall definitions. */
 #define __HYPERVISOR_arch_0               48
@@ -461,6 +462,27 @@ typedef uint8_t xen_domain_handle_t[16];
 #define __mk_unsigned_long(x) x ## UL
 #define mk_unsigned_long(x) __mk_unsigned_long(x)
 
+#define TMEM_SPEC_VERSION 1
+
+struct tmem_op {
+       uint32_t cmd;
+       int32_t pool_id;
+       union {
+               struct {  /* for cmd == TMEM_NEW_POOL */
+                       uint64_t uuid[2];
+                       uint32_t flags;
+               } new;
+               struct {
+                       uint64_t oid[3];
+                       uint32_t index;
+                       uint32_t tmem_offset;
+                       uint32_t pfn_offset;
+                       uint32_t len;
+                       GUEST_HANDLE(void) gmfn; /* guest machine page frame */
+               } gen;
+       } u;
+};
+
 #else /* __ASSEMBLY__ */
 
 /* In assembly code we cannot use C numeric constant suffixes. */
index c8b172efaa65bf9264ecae76422159214f943b95..412c21b00d513f81269d7860b1a9af1909e0225f 100644 (file)
@@ -19,7 +19,6 @@ config DEFCONFIG_LIST
 config CONSTRUCTORS
        bool
        depends on !UML
-       default y
 
 config HAVE_IRQ_WORK
        bool
@@ -204,6 +203,15 @@ config KERNEL_LZO
 
 endchoice
 
+config DEFAULT_HOSTNAME
+       string "Default hostname"
+       default "(none)"
+       help
+         This option determines the default system hostname before userspace
+         calls sethostname(2). The kernel traditionally uses "(none)" here,
+         but you may wish to use a different default here to make a minimal
+         system more usable with less configuration.
+
 config SWAP
        bool "Support for paging of anonymous memory (swap)"
        depends on MMU && BLOCK
@@ -589,14 +597,6 @@ config CGROUP_DEBUG
 
          Say N if unsure.
 
-config CGROUP_NS
-       bool "Namespace cgroup subsystem"
-       help
-         Provides a simple namespace cgroup subsystem to
-         provide hierarchical naming of sets of namespaces,
-         for instance virtual servers and checkpoint/restart
-         jobs.
-
 config CGROUP_FREEZER
        bool "Freezer cgroup subsystem"
        help
@@ -959,24 +959,18 @@ config KALLSYMS_ALL
        bool "Include all symbols in kallsyms"
        depends on DEBUG_KERNEL && KALLSYMS
        help
-          Normally kallsyms only contains the symbols of functions, for nicer
-          OOPS messages.  Some debuggers can use kallsyms for other
-          symbols too: say Y here to include all symbols, if you need them 
-          and you don't care about adding 300k to the size of your kernel.
-
-          Say N.
+          Normally kallsyms only contains the symbols of functions for nicer
+          OOPS messages and backtraces (i.e., symbols from the text and inittext
+          sections). This is sufficient for most cases. And only in very rare
+          cases (e.g., when a debugger is used) all symbols are required (e.g.,
+          names of variables from the data sections, etc).
 
-config KALLSYMS_EXTRA_PASS
-       bool "Do an extra kallsyms pass"
-       depends on KALLSYMS
-       help
-          If kallsyms is not working correctly, the build will fail with
-          inconsistent kallsyms data.  If that occurs, log a bug report and
-          turn on KALLSYMS_EXTRA_PASS which should result in a stable build.
-          Always say N here unless you find a bug in kallsyms, which must be
-          reported.  KALLSYMS_EXTRA_PASS is only a temporary workaround while
-          you wait for kallsyms to be fixed.
+          This option makes sure that all symbols are loaded into the kernel
+          image (i.e., symbols from all sections) in cost of increased kernel
+          size (depending on the kernel configuration, it may be 300KiB or
+          something like this).
 
+          Say N unless you really need all symbols.
 
 config HOTPLUG
        bool "Support for hot-pluggable devices" if EXPERT
index 76ac9194cbc437911e2394f8e94f4530eff716c8..aae2f40fea4cbea200f0658c7f6afddb60f1d934 100644 (file)
@@ -38,6 +38,9 @@ static unsigned long __cpuinit calibrate_delay_direct(void)
        unsigned long timer_rate_min, timer_rate_max;
        unsigned long good_timer_sum = 0;
        unsigned long good_timer_count = 0;
+       unsigned long measured_times[MAX_DIRECT_CALIBRATION_RETRIES];
+       int max = -1; /* index of measured_times with max/min values or not set */
+       int min = -1;
        int i;
 
        if (read_current_timer(&pre_start) < 0 )
@@ -90,18 +93,75 @@ static unsigned long __cpuinit calibrate_delay_direct(void)
                 * If the upper limit and lower limit of the timer_rate is
                 * >= 12.5% apart, redo calibration.
                 */
-               if (pre_start != 0 && pre_end != 0 &&
+               if (start >= post_end)
+                       printk(KERN_NOTICE "calibrate_delay_direct() ignoring "
+                                       "timer_rate as we had a TSC wrap around"
+                                       " start=%lu >=post_end=%lu\n",
+                               start, post_end);
+               if (start < post_end && pre_start != 0 && pre_end != 0 &&
                    (timer_rate_max - timer_rate_min) < (timer_rate_max >> 3)) {
                        good_timer_count++;
                        good_timer_sum += timer_rate_max;
-               }
+                       measured_times[i] = timer_rate_max;
+                       if (max < 0 || timer_rate_max > measured_times[max])
+                               max = i;
+                       if (min < 0 || timer_rate_max < measured_times[min])
+                               min = i;
+               } else
+                       measured_times[i] = 0;
+
        }
 
-       if (good_timer_count)
-               return (good_timer_sum/good_timer_count);
+       /*
+        * Find the maximum & minimum - if they differ too much throw out the
+        * one with the largest difference from the mean and try again...
+        */
+       while (good_timer_count > 1) {
+               unsigned long estimate;
+               unsigned long maxdiff;
+
+               /* compute the estimate */
+               estimate = (good_timer_sum/good_timer_count);
+               maxdiff = estimate >> 3;
+
+               /* if range is within 12% let's take it */
+               if ((measured_times[max] - measured_times[min]) < maxdiff)
+                       return estimate;
+
+               /* ok - drop the worse value and try again... */
+               good_timer_sum = 0;
+               good_timer_count = 0;
+               if ((measured_times[max] - estimate) <
+                               (estimate - measured_times[min])) {
+                       printk(KERN_NOTICE "calibrate_delay_direct() dropping "
+                                       "min bogoMips estimate %d = %lu\n",
+                               min, measured_times[min]);
+                       measured_times[min] = 0;
+                       min = max;
+               } else {
+                       printk(KERN_NOTICE "calibrate_delay_direct() dropping "
+                                       "max bogoMips estimate %d = %lu\n",
+                               max, measured_times[max]);
+                       measured_times[max] = 0;
+                       max = min;
+               }
+
+               for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) {
+                       if (measured_times[i] == 0)
+                               continue;
+                       good_timer_count++;
+                       good_timer_sum += measured_times[i];
+                       if (measured_times[i] < measured_times[min])
+                               min = i;
+                       if (measured_times[i] > measured_times[max])
+                               max = i;
+               }
+
+       }
 
-       printk(KERN_WARNING "calibrate_delay_direct() failed to get a good "
-              "estimate for loops_per_jiffy.\nProbably due to long platform interrupts. Consider using \"lpj=\" boot option.\n");
+       printk(KERN_NOTICE "calibrate_delay_direct() failed to get a good "
+              "estimate for loops_per_jiffy.\nProbably due to long platform "
+               "interrupts. Consider using \"lpj=\" boot option.\n");
        return 0;
 }
 #else
@@ -185,30 +245,32 @@ recalibrate:
 
 void __cpuinit calibrate_delay(void)
 {
+       unsigned long lpj;
        static bool printed;
 
        if (preset_lpj) {
-               loops_per_jiffy = preset_lpj;
+               lpj = preset_lpj;
                if (!printed)
                        pr_info("Calibrating delay loop (skipped) "
                                "preset value.. ");
        } else if ((!printed) && lpj_fine) {
-               loops_per_jiffy = lpj_fine;
+               lpj = lpj_fine;
                pr_info("Calibrating delay loop (skipped), "
                        "value calculated using timer frequency.. ");
-       } else if ((loops_per_jiffy = calibrate_delay_direct()) != 0) {
+       } else if ((lpj = calibrate_delay_direct()) != 0) {
                if (!printed)
                        pr_info("Calibrating delay using timer "
                                "specific routine.. ");
        } else {
                if (!printed)
                        pr_info("Calibrating delay loop... ");
-               loops_per_jiffy = calibrate_delay_converge();
+               lpj = calibrate_delay_converge();
        }
        if (!printed)
                pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n",
-                       loops_per_jiffy/(500000/HZ),
-                       (loops_per_jiffy/(5000/HZ)) % 100, loops_per_jiffy);
+                       lpj/(500000/HZ),
+                       (lpj/(5000/HZ)) % 100, lpj);
 
+       loops_per_jiffy = lpj;
        printed = true;
 }
index 48df882d51d2e709eaf5e79be55e806d75b6d6c5..d7211faed2adfb295caf46bbb9c70835f622eabe 100644 (file)
@@ -487,6 +487,7 @@ asmlinkage void __init start_kernel(void)
        printk(KERN_NOTICE "%s", linux_banner);
        setup_arch(&command_line);
        mm_init_owner(&init_mm, &init_task);
+       mm_init_cpumask(&init_mm);
        setup_command_line(command_line);
        setup_nr_cpu_ids();
        setup_per_cpu_areas();
@@ -504,11 +505,13 @@ asmlinkage void __init start_kernel(void)
         * These use large bootmem allocations and must precede
         * kmem_cache_init()
         */
+       setup_log_buf(0);
        pidhash_init();
        vfs_caches_init_early();
        sort_main_extable();
        trap_init();
        mm_init();
+
        /*
         * Set up the scheduler prior starting any interrupts (such as the
         * timer interrupt). Full topology setup happens at smp_init()
@@ -539,6 +542,7 @@ asmlinkage void __init start_kernel(void)
        timekeeping_init();
        time_init();
        profile_init();
+       call_function_init();
        if (!irqs_disabled())
                printk(KERN_CRIT "start_kernel(): bug: interrupts were "
                                 "enabled early\n");
index 8054c8e5faf1da309ef7b44d9ecebd4000883277..ce0a647869b1e8797290930770bbfc9557d19fab 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/fs.h>
 #include <linux/mount.h>
 #include <linux/user_namespace.h>
+#include <linux/proc_fs.h>
 
 #include "util.h"
 
@@ -140,3 +141,39 @@ void put_ipc_ns(struct ipc_namespace *ns)
                free_ipc_ns(ns);
        }
 }
+
+static void *ipcns_get(struct task_struct *task)
+{
+       struct ipc_namespace *ns = NULL;
+       struct nsproxy *nsproxy;
+
+       rcu_read_lock();
+       nsproxy = task_nsproxy(task);
+       if (nsproxy)
+               ns = get_ipc_ns(nsproxy->ipc_ns);
+       rcu_read_unlock();
+
+       return ns;
+}
+
+static void ipcns_put(void *ns)
+{
+       return put_ipc_ns(ns);
+}
+
+static int ipcns_install(struct nsproxy *nsproxy, void *ns)
+{
+       /* Ditch state from the old ipc namespace */
+       exit_sem(current);
+       put_ipc_ns(nsproxy->ipc_ns);
+       nsproxy->ipc_ns = get_ipc_ns(ns);
+       return 0;
+}
+
+const struct proc_ns_operations ipcns_operations = {
+       .name           = "ipc",
+       .type           = CLONE_NEWIPC,
+       .get            = ipcns_get,
+       .put            = ipcns_put,
+       .install        = ipcns_install,
+};
index 729acb7e31487f67660a3202d818f1f55b4fd6e5..ab3385a21b27ac9b528ea270f2d4567522d2c966 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -347,7 +347,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
        struct file * file;
        char name[13];
        int id;
-       int acctflag = 0;
+       vm_flags_t acctflag = 0;
 
        if (size < SHMMIN || size > ns->shm_ctlmax)
                return -EINVAL;
index e9cf19155b4620a061af103c9732fc5e7d7a8290..2d64cfcc8b42bd187bed3b3bf3124be74b392219 100644 (file)
@@ -61,7 +61,6 @@ obj-$(CONFIG_COMPAT) += compat.o
 obj-$(CONFIG_CGROUPS) += cgroup.o
 obj-$(CONFIG_CGROUP_FREEZER) += cgroup_freezer.o
 obj-$(CONFIG_CPUSETS) += cpuset.o
-obj-$(CONFIG_CGROUP_NS) += ns_cgroup.o
 obj-$(CONFIG_UTS_NS) += utsname.o
 obj-$(CONFIG_USER_NS) += user_namespace.o
 obj-$(CONFIG_PID_NS) += pid_namespace.o
index 32a80e08ff4b8ebf725ebc8d3a526c2dee3f00f4..283c529f8b1cfd2199e90e238aa3d2a67370c414 100644 (file)
  */
 
 const kernel_cap_t __cap_empty_set = CAP_EMPTY_SET;
-const kernel_cap_t __cap_full_set = CAP_FULL_SET;
-const kernel_cap_t __cap_init_eff_set = CAP_INIT_EFF_SET;
 
 EXPORT_SYMBOL(__cap_empty_set);
-EXPORT_SYMBOL(__cap_full_set);
-EXPORT_SYMBOL(__cap_init_eff_set);
 
 int file_caps_enabled = 1;
 
index 909a35510af53656c684021b113977c10bfbbac8..2731d115d725c0a216f06d18cd60367eab4210da 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/vmalloc.h> /* TODO: replace with more sophisticated array */
 #include <linux/eventfd.h>
 #include <linux/poll.h>
+#include <linux/flex_array.h> /* used in cgroup_attach_proc */
 
 #include <asm/atomic.h>
 
@@ -1735,6 +1736,76 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
 }
 EXPORT_SYMBOL_GPL(cgroup_path);
 
+/*
+ * cgroup_task_migrate - move a task from one cgroup to another.
+ *
+ * 'guarantee' is set if the caller promises that a new css_set for the task
+ * will already exist. If not set, this function might sleep, and can fail with
+ * -ENOMEM. Otherwise, it can only fail with -ESRCH.
+ */
+static int cgroup_task_migrate(struct cgroup *cgrp, struct cgroup *oldcgrp,
+                              struct task_struct *tsk, bool guarantee)
+{
+       struct css_set *oldcg;
+       struct css_set *newcg;
+
+       /*
+        * get old css_set. we need to take task_lock and refcount it, because
+        * an exiting task can change its css_set to init_css_set and drop its
+        * old one without taking cgroup_mutex.
+        */
+       task_lock(tsk);
+       oldcg = tsk->cgroups;
+       get_css_set(oldcg);
+       task_unlock(tsk);
+
+       /* locate or allocate a new css_set for this task. */
+       if (guarantee) {
+               /* we know the css_set we want already exists. */
+               struct cgroup_subsys_state *template[CGROUP_SUBSYS_COUNT];
+               read_lock(&css_set_lock);
+               newcg = find_existing_css_set(oldcg, cgrp, template);
+               BUG_ON(!newcg);
+               get_css_set(newcg);
+               read_unlock(&css_set_lock);
+       } else {
+               might_sleep();
+               /* find_css_set will give us newcg already referenced. */
+               newcg = find_css_set(oldcg, cgrp);
+               if (!newcg) {
+                       put_css_set(oldcg);
+                       return -ENOMEM;
+               }
+       }
+       put_css_set(oldcg);
+
+       /* if PF_EXITING is set, the tsk->cgroups pointer is no longer safe. */
+       task_lock(tsk);
+       if (tsk->flags & PF_EXITING) {
+               task_unlock(tsk);
+               put_css_set(newcg);
+               return -ESRCH;
+       }
+       rcu_assign_pointer(tsk->cgroups, newcg);
+       task_unlock(tsk);
+
+       /* Update the css_set linked lists if we're using them */
+       write_lock(&css_set_lock);
+       if (!list_empty(&tsk->cg_list))
+               list_move(&tsk->cg_list, &newcg->tasks);
+       write_unlock(&css_set_lock);
+
+       /*
+        * We just gained a reference on oldcg by taking it from the task. As
+        * trading it for newcg is protected by cgroup_mutex, we're safe to drop
+        * it here; it will be freed under RCU.
+        */
+       put_css_set(oldcg);
+
+       set_bit(CGRP_RELEASABLE, &oldcgrp->flags);
+       return 0;
+}
+
 /**
  * cgroup_attach_task - attach task 'tsk' to cgroup 'cgrp'
  * @cgrp: the cgroup the task is attaching to
@@ -1745,11 +1816,9 @@ EXPORT_SYMBOL_GPL(cgroup_path);
  */
 int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
 {
-       int retval = 0;
+       int retval;
        struct cgroup_subsys *ss, *failed_ss = NULL;
        struct cgroup *oldcgrp;
-       struct css_set *cg;
-       struct css_set *newcg;
        struct cgroupfs_root *root = cgrp->root;
 
        /* Nothing to do if the task is already in that cgroup */
@@ -1759,7 +1828,7 @@ int cgroup_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, false);
+                       retval = ss->can_attach(ss, cgrp, tsk);
                        if (retval) {
                                /*
                                 * Remember on which subsystem the can_attach()
@@ -1771,46 +1840,29 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
                                goto out;
                        }
                }
+               if (ss->can_attach_task) {
+                       retval = ss->can_attach_task(cgrp, tsk);
+                       if (retval) {
+                               failed_ss = ss;
+                               goto out;
+                       }
+               }
        }
 
-       task_lock(tsk);
-       cg = tsk->cgroups;
-       get_css_set(cg);
-       task_unlock(tsk);
-       /*
-        * Locate or allocate a new css_set for this task,
-        * based on its final set of cgroups
-        */
-       newcg = find_css_set(cg, cgrp);
-       put_css_set(cg);
-       if (!newcg) {
-               retval = -ENOMEM;
-               goto out;
-       }
-
-       task_lock(tsk);
-       if (tsk->flags & PF_EXITING) {
-               task_unlock(tsk);
-               put_css_set(newcg);
-               retval = -ESRCH;
+       retval = cgroup_task_migrate(cgrp, oldcgrp, tsk, false);
+       if (retval)
                goto out;
-       }
-       rcu_assign_pointer(tsk->cgroups, newcg);
-       task_unlock(tsk);
-
-       /* Update the css_set linked lists if we're using them */
-       write_lock(&css_set_lock);
-       if (!list_empty(&tsk->cg_list))
-               list_move(&tsk->cg_list, &newcg->tasks);
-       write_unlock(&css_set_lock);
 
        for_each_subsys(root, ss) {
+               if (ss->pre_attach)
+                       ss->pre_attach(cgrp);
+               if (ss->attach_task)
+                       ss->attach_task(cgrp, tsk);
                if (ss->attach)
-                       ss->attach(ss, cgrp, oldcgrp, tsk, false);
+                       ss->attach(ss, cgrp, oldcgrp, tsk);
        }
-       set_bit(CGRP_RELEASABLE, &oldcgrp->flags);
+
        synchronize_rcu();
-       put_css_set(cg);
 
        /*
         * wake up rmdir() waiter. the rmdir should fail since the cgroup
@@ -1829,7 +1881,7 @@ out:
                                 */
                                break;
                        if (ss->cancel_attach)
-                               ss->cancel_attach(ss, cgrp, tsk, false);
+                               ss->cancel_attach(ss, cgrp, tsk);
                }
        }
        return retval;
@@ -1860,49 +1912,370 @@ int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk)
 EXPORT_SYMBOL_GPL(cgroup_attach_task_all);
 
 /*
- * Attach task with pid 'pid' to cgroup 'cgrp'. Call with cgroup_mutex
- * held. May take task_lock of task
+ * cgroup_attach_proc works in two stages, the first of which prefetches all
+ * new css_sets needed (to make sure we have enough memory before committing
+ * to the move) and stores them in a list of entries of the following type.
+ * TODO: possible optimization: use css_set->rcu_head for chaining instead
+ */
+struct cg_list_entry {
+       struct css_set *cg;
+       struct list_head links;
+};
+
+static bool css_set_check_fetched(struct cgroup *cgrp,
+                                 struct task_struct *tsk, struct css_set *cg,
+                                 struct list_head *newcg_list)
+{
+       struct css_set *newcg;
+       struct cg_list_entry *cg_entry;
+       struct cgroup_subsys_state *template[CGROUP_SUBSYS_COUNT];
+
+       read_lock(&css_set_lock);
+       newcg = find_existing_css_set(cg, cgrp, template);
+       if (newcg)
+               get_css_set(newcg);
+       read_unlock(&css_set_lock);
+
+       /* doesn't exist at all? */
+       if (!newcg)
+               return false;
+       /* see if it's already in the list */
+       list_for_each_entry(cg_entry, newcg_list, links) {
+               if (cg_entry->cg == newcg) {
+                       put_css_set(newcg);
+                       return true;
+               }
+       }
+
+       /* not found */
+       put_css_set(newcg);
+       return false;
+}
+
+/*
+ * Find the new css_set and store it in the list in preparation for moving the
+ * given task to the given cgroup. Returns 0 or -ENOMEM.
+ */
+static int css_set_prefetch(struct cgroup *cgrp, struct css_set *cg,
+                           struct list_head *newcg_list)
+{
+       struct css_set *newcg;
+       struct cg_list_entry *cg_entry;
+
+       /* ensure a new css_set will exist for this thread */
+       newcg = find_css_set(cg, cgrp);
+       if (!newcg)
+               return -ENOMEM;
+       /* add it to the list */
+       cg_entry = kmalloc(sizeof(struct cg_list_entry), GFP_KERNEL);
+       if (!cg_entry) {
+               put_css_set(newcg);
+               return -ENOMEM;
+       }
+       cg_entry->cg = newcg;
+       list_add(&cg_entry->links, newcg_list);
+       return 0;
+}
+
+/**
+ * cgroup_attach_proc - attach all threads in a threadgroup to a cgroup
+ * @cgrp: the cgroup to attach to
+ * @leader: the threadgroup leader task_struct of the group to be attached
+ *
+ * Call holding cgroup_mutex and the threadgroup_fork_lock of the leader. Will
+ * take task_lock of each thread in leader's threadgroup individually in turn.
+ */
+int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
+{
+       int retval, i, group_size;
+       struct cgroup_subsys *ss, *failed_ss = NULL;
+       bool cancel_failed_ss = false;
+       /* guaranteed to be initialized later, but the compiler needs this */
+       struct cgroup *oldcgrp = NULL;
+       struct css_set *oldcg;
+       struct cgroupfs_root *root = cgrp->root;
+       /* threadgroup list cursor and array */
+       struct task_struct *tsk;
+       struct flex_array *group;
+       /*
+        * we need to make sure we have css_sets for all the tasks we're
+        * going to move -before- we actually start moving them, so that in
+        * case we get an ENOMEM we can bail out before making any changes.
+        */
+       struct list_head newcg_list;
+       struct cg_list_entry *cg_entry, *temp_nobe;
+
+       /*
+        * step 0: in order to do expensive, possibly blocking operations for
+        * every thread, we cannot iterate the thread group list, since it needs
+        * rcu or tasklist locked. instead, build an array of all threads in the
+        * group - threadgroup_fork_lock prevents new threads from appearing,
+        * and if threads exit, this will just be an over-estimate.
+        */
+       group_size = get_nr_threads(leader);
+       /* flex_array supports very large thread-groups better than kmalloc. */
+       group = flex_array_alloc(sizeof(struct task_struct *), group_size,
+                                GFP_KERNEL);
+       if (!group)
+               return -ENOMEM;
+       /* pre-allocate to guarantee space while iterating in rcu read-side. */
+       retval = flex_array_prealloc(group, 0, group_size - 1, GFP_KERNEL);
+       if (retval)
+               goto out_free_group_list;
+
+       /* prevent changes to the threadgroup list while we take a snapshot. */
+       rcu_read_lock();
+       if (!thread_group_leader(leader)) {
+               /*
+                * a race with de_thread from another thread's exec() may strip
+                * us of our leadership, making while_each_thread unsafe to use
+                * on this task. if this happens, there is no choice but to
+                * throw this task away and try again (from cgroup_procs_write);
+                * this is "double-double-toil-and-trouble-check locking".
+                */
+               rcu_read_unlock();
+               retval = -EAGAIN;
+               goto out_free_group_list;
+       }
+       /* take a reference on each task in the group to go in the array. */
+       tsk = leader;
+       i = 0;
+       do {
+               /* as per above, nr_threads may decrease, but not increase. */
+               BUG_ON(i >= group_size);
+               get_task_struct(tsk);
+               /*
+                * saying GFP_ATOMIC has no effect here because we did prealloc
+                * earlier, but it's good form to communicate our expectations.
+                */
+               retval = flex_array_put_ptr(group, i, tsk, GFP_ATOMIC);
+               BUG_ON(retval != 0);
+               i++;
+       } while_each_thread(leader, tsk);
+       /* remember the number of threads in the array for later. */
+       group_size = i;
+       rcu_read_unlock();
+
+       /*
+        * step 1: check that we can legitimately attach to the cgroup.
+        */
+       for_each_subsys(root, ss) {
+               if (ss->can_attach) {
+                       retval = ss->can_attach(ss, cgrp, leader);
+                       if (retval) {
+                               failed_ss = ss;
+                               goto out_cancel_attach;
+                       }
+               }
+               /* a callback to be run on every thread in the threadgroup. */
+               if (ss->can_attach_task) {
+                       /* run on each task in the threadgroup. */
+                       for (i = 0; i < group_size; i++) {
+                               tsk = flex_array_get_ptr(group, i);
+                               retval = ss->can_attach_task(cgrp, tsk);
+                               if (retval) {
+                                       failed_ss = ss;
+                                       cancel_failed_ss = true;
+                                       goto out_cancel_attach;
+                               }
+                       }
+               }
+       }
+
+       /*
+        * step 2: make sure css_sets exist for all threads to be migrated.
+        * we use find_css_set, which allocates a new one if necessary.
+        */
+       INIT_LIST_HEAD(&newcg_list);
+       for (i = 0; i < group_size; i++) {
+               tsk = flex_array_get_ptr(group, i);
+               /* nothing to do if this task is already in the cgroup */
+               oldcgrp = task_cgroup_from_root(tsk, root);
+               if (cgrp == oldcgrp)
+                       continue;
+               /* get old css_set pointer */
+               task_lock(tsk);
+               if (tsk->flags & PF_EXITING) {
+                       /* ignore this task if it's going away */
+                       task_unlock(tsk);
+                       continue;
+               }
+               oldcg = tsk->cgroups;
+               get_css_set(oldcg);
+               task_unlock(tsk);
+               /* see if the new one for us is already in the list? */
+               if (css_set_check_fetched(cgrp, tsk, oldcg, &newcg_list)) {
+                       /* was already there, nothing to do. */
+                       put_css_set(oldcg);
+               } else {
+                       /* we don't already have it. get new one. */
+                       retval = css_set_prefetch(cgrp, oldcg, &newcg_list);
+                       put_css_set(oldcg);
+                       if (retval)
+                               goto out_list_teardown;
+               }
+       }
+
+       /*
+        * step 3: now that we're guaranteed success wrt the css_sets, proceed
+        * to move all tasks to the new cgroup, calling ss->attach_task for each
+        * one along the way. there are no failure cases after here, so this is
+        * the commit point.
+        */
+       for_each_subsys(root, ss) {
+               if (ss->pre_attach)
+                       ss->pre_attach(cgrp);
+       }
+       for (i = 0; i < group_size; i++) {
+               tsk = flex_array_get_ptr(group, i);
+               /* leave current thread as it is if it's already there */
+               oldcgrp = task_cgroup_from_root(tsk, root);
+               if (cgrp == oldcgrp)
+                       continue;
+               /* attach each task to each subsystem */
+               for_each_subsys(root, ss) {
+                       if (ss->attach_task)
+                               ss->attach_task(cgrp, tsk);
+               }
+               /* if the thread is PF_EXITING, it can just get skipped. */
+               retval = cgroup_task_migrate(cgrp, oldcgrp, tsk, true);
+               BUG_ON(retval != 0 && retval != -ESRCH);
+       }
+       /* nothing is sensitive to fork() after this point. */
+
+       /*
+        * step 4: do expensive, non-thread-specific subsystem callbacks.
+        * TODO: if ever a subsystem needs to know the oldcgrp for each task
+        * being moved, this call will need to be reworked to communicate that.
+        */
+       for_each_subsys(root, ss) {
+               if (ss->attach)
+                       ss->attach(ss, cgrp, oldcgrp, leader);
+       }
+
+       /*
+        * step 5: success! and cleanup
+        */
+       synchronize_rcu();
+       cgroup_wakeup_rmdir_waiter(cgrp);
+       retval = 0;
+out_list_teardown:
+       /* clean up the list of prefetched css_sets. */
+       list_for_each_entry_safe(cg_entry, temp_nobe, &newcg_list, links) {
+               list_del(&cg_entry->links);
+               put_css_set(cg_entry->cg);
+               kfree(cg_entry);
+       }
+out_cancel_attach:
+       /* same deal as in cgroup_attach_task */
+       if (retval) {
+               for_each_subsys(root, ss) {
+                       if (ss == failed_ss) {
+                               if (cancel_failed_ss && ss->cancel_attach)
+                                       ss->cancel_attach(ss, cgrp, leader);
+                               break;
+                       }
+                       if (ss->cancel_attach)
+                               ss->cancel_attach(ss, cgrp, leader);
+               }
+       }
+       /* clean up the array of referenced threads in the group. */
+       for (i = 0; i < group_size; i++) {
+               tsk = flex_array_get_ptr(group, i);
+               put_task_struct(tsk);
+       }
+out_free_group_list:
+       flex_array_free(group);
+       return retval;
+}
+
+/*
+ * Find the task_struct of the task to attach by vpid and pass it along to the
+ * function to attach either it or all tasks in its threadgroup. Will take
+ * cgroup_mutex; may take task_lock of task.
  */
-static int attach_task_by_pid(struct cgroup *cgrp, u64 pid)
+static int attach_task_by_pid(struct cgroup *cgrp, u64 pid, bool threadgroup)
 {
        struct task_struct *tsk;
        const struct cred *cred = current_cred(), *tcred;
        int ret;
 
+       if (!cgroup_lock_live_group(cgrp))
+               return -ENODEV;
+
        if (pid) {
                rcu_read_lock();
                tsk = find_task_by_vpid(pid);
-               if (!tsk || tsk->flags & PF_EXITING) {
+               if (!tsk) {
                        rcu_read_unlock();
+                       cgroup_unlock();
+                       return -ESRCH;
+               }
+               if (threadgroup) {
+                       /*
+                        * RCU protects this access, since tsk was found in the
+                        * tid map. a race with de_thread may cause group_leader
+                        * to stop being the leader, but cgroup_attach_proc will
+                        * detect it later.
+                        */
+                       tsk = tsk->group_leader;
+               } else if (tsk->flags & PF_EXITING) {
+                       /* optimization for the single-task-only case */
+                       rcu_read_unlock();
+                       cgroup_unlock();
                        return -ESRCH;
                }
 
+               /*
+                * even if we're attaching all tasks in the thread group, we
+                * only need to check permissions on one of them.
+                */
                tcred = __task_cred(tsk);
                if (cred->euid &&
                    cred->euid != tcred->uid &&
                    cred->euid != tcred->suid) {
                        rcu_read_unlock();
+                       cgroup_unlock();
                        return -EACCES;
                }
                get_task_struct(tsk);
                rcu_read_unlock();
        } else {
-               tsk = current;
+               if (threadgroup)
+                       tsk = current->group_leader;
+               else
+                       tsk = current;
                get_task_struct(tsk);
        }
 
-       ret = cgroup_attach_task(cgrp, tsk);
+       if (threadgroup) {
+               threadgroup_fork_write_lock(tsk);
+               ret = cgroup_attach_proc(cgrp, tsk);
+               threadgroup_fork_write_unlock(tsk);
+       } else {
+               ret = cgroup_attach_task(cgrp, tsk);
+       }
        put_task_struct(tsk);
+       cgroup_unlock();
        return ret;
 }
 
 static int cgroup_tasks_write(struct cgroup *cgrp, struct cftype *cft, u64 pid)
+{
+       return attach_task_by_pid(cgrp, pid, false);
+}
+
+static int cgroup_procs_write(struct cgroup *cgrp, struct cftype *cft, u64 tgid)
 {
        int ret;
-       if (!cgroup_lock_live_group(cgrp))
-               return -ENODEV;
-       ret = attach_task_by_pid(cgrp, pid);
-       cgroup_unlock();
+       do {
+               /*
+                * attach_proc fails with -EAGAIN if threadgroup leadership
+                * changes in the middle of the operation, in which case we need
+                * to find the task_struct for the new leader and start over.
+                */
+               ret = attach_task_by_pid(cgrp, tgid, true);
+       } while (ret == -EAGAIN);
        return ret;
 }
 
@@ -3259,9 +3632,9 @@ static struct cftype files[] = {
        {
                .name = CGROUP_FILE_GENERIC_PREFIX "procs",
                .open = cgroup_procs_open,
-               /* .write_u64 = cgroup_procs_write, TODO */
+               .write_u64 = cgroup_procs_write,
                .release = cgroup_pidlist_release,
-               .mode = S_IRUGO,
+               .mode = S_IRUGO | S_IWUSR,
        },
        {
                .name = "notify_on_release",
@@ -4256,122 +4629,6 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks)
                put_css_set_taskexit(cg);
 }
 
-/**
- * cgroup_clone - clone the cgroup the given subsystem is attached to
- * @tsk: the task to be moved
- * @subsys: the given subsystem
- * @nodename: the name for the new cgroup
- *
- * Duplicate the current cgroup in the hierarchy that the given
- * subsystem is attached to, and move this task into the new
- * child.
- */
-int cgroup_clone(struct task_struct *tsk, struct cgroup_subsys *subsys,
-                                                       char *nodename)
-{
-       struct dentry *dentry;
-       int ret = 0;
-       struct cgroup *parent, *child;
-       struct inode *inode;
-       struct css_set *cg;
-       struct cgroupfs_root *root;
-       struct cgroup_subsys *ss;
-
-       /* We shouldn't be called by an unregistered subsystem */
-       BUG_ON(!subsys->active);
-
-       /* First figure out what hierarchy and cgroup we're dealing
-        * with, and pin them so we can drop cgroup_mutex */
-       mutex_lock(&cgroup_mutex);
- again:
-       root = subsys->root;
-       if (root == &rootnode) {
-               mutex_unlock(&cgroup_mutex);
-               return 0;
-       }
-
-       /* Pin the hierarchy */
-       if (!atomic_inc_not_zero(&root->sb->s_active)) {
-               /* We race with the final deactivate_super() */
-               mutex_unlock(&cgroup_mutex);
-               return 0;
-       }
-
-       /* Keep the cgroup alive */
-       task_lock(tsk);
-       parent = task_cgroup(tsk, subsys->subsys_id);
-       cg = tsk->cgroups;
-       get_css_set(cg);
-       task_unlock(tsk);
-
-       mutex_unlock(&cgroup_mutex);
-
-       /* Now do the VFS work to create a cgroup */
-       inode = parent->dentry->d_inode;
-
-       /* Hold the parent directory mutex across this operation to
-        * stop anyone else deleting the new cgroup */
-       mutex_lock(&inode->i_mutex);
-       dentry = lookup_one_len(nodename, parent->dentry, strlen(nodename));
-       if (IS_ERR(dentry)) {
-               printk(KERN_INFO
-                      "cgroup: Couldn't allocate dentry for %s: %ld\n", nodename,
-                      PTR_ERR(dentry));
-               ret = PTR_ERR(dentry);
-               goto out_release;
-       }
-
-       /* Create the cgroup directory, which also creates the cgroup */
-       ret = vfs_mkdir(inode, dentry, 0755);
-       child = __d_cgrp(dentry);
-       dput(dentry);
-       if (ret) {
-               printk(KERN_INFO
-                      "Failed to create cgroup %s: %d\n", nodename,
-                      ret);
-               goto out_release;
-       }
-
-       /* The cgroup now exists. Retake cgroup_mutex and check
-        * that we're still in the same state that we thought we
-        * were. */
-       mutex_lock(&cgroup_mutex);
-       if ((root != subsys->root) ||
-           (parent != task_cgroup(tsk, subsys->subsys_id))) {
-               /* Aargh, we raced ... */
-               mutex_unlock(&inode->i_mutex);
-               put_css_set(cg);
-
-               deactivate_super(root->sb);
-               /* The cgroup is still accessible in the VFS, but
-                * we're not going to try to rmdir() it at this
-                * point. */
-               printk(KERN_INFO
-                      "Race in cgroup_clone() - leaking cgroup %s\n",
-                      nodename);
-               goto again;
-       }
-
-       /* do any required auto-setup */
-       for_each_subsys(root, ss) {
-               if (ss->post_clone)
-                       ss->post_clone(ss, child);
-       }
-
-       /* All seems fine. Finish by moving the task into the new cgroup */
-       ret = cgroup_attach_task(child, tsk);
-       mutex_unlock(&cgroup_mutex);
-
- out_release:
-       mutex_unlock(&inode->i_mutex);
-
-       mutex_lock(&cgroup_mutex);
-       put_css_set(cg);
-       mutex_unlock(&cgroup_mutex);
-       deactivate_super(root->sb);
-       return ret;
-}
-
 /**
  * cgroup_is_descendant - see if @cgrp is a descendant of @task's cgrp
  * @cgrp: the cgroup in question
index e7bebb7c6c38ff7ddaefb807d7e50cd1bcc1adbc..e691818d7e450f5f8785b8b97a08cdbb2f4e1493 100644 (file)
@@ -160,7 +160,7 @@ static void freezer_destroy(struct cgroup_subsys *ss,
  */
 static int freezer_can_attach(struct cgroup_subsys *ss,
                              struct cgroup *new_cgroup,
-                             struct task_struct *task, bool threadgroup)
+                             struct task_struct *task)
 {
        struct freezer *freezer;
 
@@ -172,26 +172,17 @@ static int freezer_can_attach(struct cgroup_subsys *ss,
        if (freezer->state != CGROUP_THAWED)
                return -EBUSY;
 
+       return 0;
+}
+
+static int freezer_can_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
+{
        rcu_read_lock();
-       if (__cgroup_freezing_or_frozen(task)) {
+       if (__cgroup_freezing_or_frozen(tsk)) {
                rcu_read_unlock();
                return -EBUSY;
        }
        rcu_read_unlock();
-
-       if (threadgroup) {
-               struct task_struct *c;
-
-               rcu_read_lock();
-               list_for_each_entry_rcu(c, &task->thread_group, thread_group) {
-                       if (__cgroup_freezing_or_frozen(c)) {
-                               rcu_read_unlock();
-                               return -EBUSY;
-                       }
-               }
-               rcu_read_unlock();
-       }
-
        return 0;
 }
 
@@ -390,6 +381,9 @@ struct cgroup_subsys freezer_subsys = {
        .populate       = freezer_populate,
        .subsys_id      = freezer_subsys_id,
        .can_attach     = freezer_can_attach,
+       .can_attach_task = freezer_can_attach_task,
+       .pre_attach     = NULL,
+       .attach_task    = NULL,
        .attach         = NULL,
        .fork           = freezer_fork,
        .exit           = NULL,
index 9214dcd087b7369fb754e6391015918db6d6ed3f..fc9eb093acd5fc006e9f296b1a6c92b7a39d53ff 100644 (file)
@@ -293,6 +293,8 @@ asmlinkage long compat_sys_times(struct compat_tms __user *tbuf)
        return compat_jiffies_to_clock_t(jiffies);
 }
 
+#ifdef __ARCH_WANT_SYS_SIGPENDING
+
 /*
  * Assumption: old_sigset_t and compat_old_sigset_t are both
  * types that can be passed to put_user()/get_user().
@@ -312,6 +314,10 @@ asmlinkage long compat_sys_sigpending(compat_old_sigset_t __user *set)
        return ret;
 }
 
+#endif
+
+#ifdef __ARCH_WANT_SYS_SIGPROCMASK
+
 asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set,
                compat_old_sigset_t __user *oset)
 {
@@ -333,6 +339,8 @@ asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set,
        return ret;
 }
 
+#endif
+
 asmlinkage long compat_sys_setrlimit(unsigned int resource,
                struct compat_rlimit __user *rlim)
 {
index 2bb8c2e98fff4074bce131a145966bfb1c788866..9c9b7545c81078c7ae43253cc1714a73fcb2691e 100644 (file)
@@ -1367,14 +1367,10 @@ static int fmeter_getrate(struct fmeter *fmp)
        return val;
 }
 
-/* Protected by cgroup_lock */
-static cpumask_var_t cpus_attach;
-
 /* 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, bool threadgroup)
+                            struct task_struct *tsk)
 {
-       int ret;
        struct cpuset *cs = cgroup_cs(cont);
 
        if (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed))
@@ -1391,29 +1387,42 @@ static int cpuset_can_attach(struct cgroup_subsys *ss, struct cgroup *cont,
        if (tsk->flags & PF_THREAD_BOUND)
                return -EINVAL;
 
-       ret = security_task_setscheduler(tsk);
-       if (ret)
-               return ret;
-       if (threadgroup) {
-               struct task_struct *c;
-
-               rcu_read_lock();
-               list_for_each_entry_rcu(c, &tsk->thread_group, thread_group) {
-                       ret = security_task_setscheduler(c);
-                       if (ret) {
-                               rcu_read_unlock();
-                               return ret;
-                       }
-               }
-               rcu_read_unlock();
-       }
        return 0;
 }
 
-static void cpuset_attach_task(struct task_struct *tsk, nodemask_t *to,
-                              struct cpuset *cs)
+static int cpuset_can_attach_task(struct cgroup *cgrp, struct task_struct *task)
+{
+       return security_task_setscheduler(task);
+}
+
+/*
+ * Protected by cgroup_lock. The nodemasks must be stored globally because
+ * dynamically allocating them is not allowed in pre_attach, and they must
+ * persist among pre_attach, attach_task, and attach.
+ */
+static cpumask_var_t cpus_attach;
+static nodemask_t cpuset_attach_nodemask_from;
+static nodemask_t cpuset_attach_nodemask_to;
+
+/* Set-up work for before attaching each task. */
+static void cpuset_pre_attach(struct cgroup *cont)
+{
+       struct cpuset *cs = cgroup_cs(cont);
+
+       if (cs == &top_cpuset)
+               cpumask_copy(cpus_attach, cpu_possible_mask);
+       else
+               guarantee_online_cpus(cs, cpus_attach);
+
+       guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
+}
+
+/* Per-thread attachment work. */
+static void cpuset_attach_task(struct cgroup *cont, struct task_struct *tsk)
 {
        int err;
+       struct cpuset *cs = cgroup_cs(cont);
+
        /*
         * can_attach beforehand should guarantee that this doesn't fail.
         * TODO: have a better way to handle failure here
@@ -1421,45 +1430,29 @@ static void cpuset_attach_task(struct task_struct *tsk, nodemask_t *to,
        err = set_cpus_allowed_ptr(tsk, cpus_attach);
        WARN_ON_ONCE(err);
 
-       cpuset_change_task_nodemask(tsk, to);
+       cpuset_change_task_nodemask(tsk, &cpuset_attach_nodemask_to);
        cpuset_update_task_spread_flag(cs, tsk);
-
 }
 
 static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont,
-                         struct cgroup *oldcont, struct task_struct *tsk,
-                         bool threadgroup)
+                         struct cgroup *oldcont, struct task_struct *tsk)
 {
        struct mm_struct *mm;
        struct cpuset *cs = cgroup_cs(cont);
        struct cpuset *oldcs = cgroup_cs(oldcont);
-       static nodemask_t to;           /* protected by cgroup_mutex */
 
-       if (cs == &top_cpuset) {
-               cpumask_copy(cpus_attach, cpu_possible_mask);
-       } else {
-               guarantee_online_cpus(cs, cpus_attach);
-       }
-       guarantee_online_mems(cs, &to);
-
-       /* do per-task migration stuff possibly for each in the threadgroup */
-       cpuset_attach_task(tsk, &to, cs);
-       if (threadgroup) {
-               struct task_struct *c;
-               rcu_read_lock();
-               list_for_each_entry_rcu(c, &tsk->thread_group, thread_group) {
-                       cpuset_attach_task(c, &to, cs);
-               }
-               rcu_read_unlock();
-       }
-
-       /* change mm; only needs to be done once even if threadgroup */
-       to = cs->mems_allowed;
+       /*
+        * Change mm, possibly for multiple threads in a threadgroup. This is
+        * expensive and may sleep.
+        */
+       cpuset_attach_nodemask_from = oldcs->mems_allowed;
+       cpuset_attach_nodemask_to = cs->mems_allowed;
        mm = get_task_mm(tsk);
        if (mm) {
-               mpol_rebind_mm(mm, &to);
+               mpol_rebind_mm(mm, &cpuset_attach_nodemask_to);
                if (is_memory_migrate(cs))
-                       cpuset_migrate_mm(mm, &oldcs->mems_allowed, &to);
+                       cpuset_migrate_mm(mm, &cpuset_attach_nodemask_from,
+                                         &cpuset_attach_nodemask_to);
                mmput(mm);
        }
 }
@@ -1809,10 +1802,9 @@ static int cpuset_populate(struct cgroup_subsys *ss, struct cgroup *cont)
 }
 
 /*
- * post_clone() is called at the end of cgroup_clone().
- * 'cgroup' was just created automatically as a result of
- * a cgroup_clone(), and the current task is about to
- * be moved into 'cgroup'.
+ * post_clone() is called during cgroup_create() when the
+ * clone_children mount argument was specified.  The cgroup
+ * can not yet have any tasks.
  *
  * Currently we refuse to set up the cgroup - thereby
  * refusing the task to be entered, and as a result refusing
@@ -1911,6 +1903,9 @@ struct cgroup_subsys cpuset_subsys = {
        .create = cpuset_create,
        .destroy = cpuset_destroy,
        .can_attach = cpuset_can_attach,
+       .can_attach_task = cpuset_can_attach_task,
+       .pre_attach = cpuset_pre_attach,
+       .attach_task = cpuset_attach_task,
        .attach = cpuset_attach,
        .populate = cpuset_populate,
        .post_clone = cpuset_post_clone,
@@ -2195,7 +2190,7 @@ int cpuset_cpus_allowed_fallback(struct task_struct *tsk)
        rcu_read_lock();
        cs = task_cs(tsk);
        if (cs)
-               cpumask_copy(&tsk->cpus_allowed, cs->cpus_allowed);
+               do_set_cpus_allowed(tsk, cs->cpus_allowed);
        rcu_read_unlock();
 
        /*
@@ -2222,7 +2217,7 @@ int cpuset_cpus_allowed_fallback(struct task_struct *tsk)
                 * Like above we can temporary set any mask and rely on
                 * set_cpus_allowed_ptr() as synchronization point.
                 */
-               cpumask_copy(&tsk->cpus_allowed, cpu_possible_mask);
+               do_set_cpus_allowed(tsk, cpu_possible_mask);
                cpu = cpumask_any(cpu_active_mask);
        }
 
index 8093c16b84b13d2e9e0714af279b29b0549a0652..174fa84eca303ced39cc03910114d495f7b777b0 100644 (file)
@@ -1,4 +1,4 @@
-/* Task credentials management - see Documentation/credentials.txt
+/* Task credentials management - see Documentation/security/credentials.txt
  *
  * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
@@ -49,10 +49,10 @@ struct cred init_cred = {
        .magic                  = CRED_MAGIC,
 #endif
        .securebits             = SECUREBITS_DEFAULT,
-       .cap_inheritable        = CAP_INIT_INH_SET,
+       .cap_inheritable        = CAP_EMPTY_SET,
        .cap_permitted          = CAP_FULL_SET,
-       .cap_effective          = CAP_INIT_EFF_SET,
-       .cap_bset               = CAP_INIT_BSET,
+       .cap_effective          = CAP_FULL_SET,
+       .cap_bset               = CAP_FULL_SET,
        .user                   = INIT_USER,
        .user_ns                = &init_user_ns,
        .group_info             = &init_groups,
index c09767f7db3e20e4a510c7a51fba7d662e967659..9efe7108ccaf8debca9bd9a70e2bf6265a50949c 100644 (file)
@@ -5028,6 +5028,14 @@ static int __perf_event_overflow(struct perf_event *event, int nmi,
        else
                perf_event_output(event, nmi, data, regs);
 
+       if (event->fasync && event->pending_kill) {
+               if (nmi) {
+                       event->pending_wakeup = 1;
+                       irq_work_queue(&event->pending);
+               } else
+                       perf_event_wakeup(event);
+       }
+
        return ret;
 }
 
@@ -7394,26 +7402,12 @@ static int __perf_cgroup_move(void *info)
        return 0;
 }
 
-static void perf_cgroup_move(struct task_struct *task)
+static void
+perf_cgroup_attach_task(struct cgroup *cgrp, struct task_struct *task)
 {
        task_function_call(task, __perf_cgroup_move, task);
 }
 
-static void perf_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
-               struct cgroup *old_cgrp, struct task_struct *task,
-               bool threadgroup)
-{
-       perf_cgroup_move(task);
-       if (threadgroup) {
-               struct task_struct *c;
-               rcu_read_lock();
-               list_for_each_entry_rcu(c, &task->thread_group, thread_group) {
-                       perf_cgroup_move(c);
-               }
-               rcu_read_unlock();
-       }
-}
-
 static void perf_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp,
                struct cgroup *old_cgrp, struct task_struct *task)
 {
@@ -7425,7 +7419,7 @@ static void perf_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp,
        if (!(task->flags & PF_EXITING))
                return;
 
-       perf_cgroup_move(task);
+       perf_cgroup_attach_task(cgrp, task);
 }
 
 struct cgroup_subsys perf_subsys = {
@@ -7434,6 +7428,6 @@ struct cgroup_subsys perf_subsys = {
        .create         = perf_cgroup_create,
        .destroy        = perf_cgroup_destroy,
        .exit           = perf_cgroup_exit,
-       .attach         = perf_cgroup_attach,
+       .attach_task    = perf_cgroup_attach_task,
 };
 #endif /* CONFIG_CGROUP_PERF */
index 20a406471525af2087cf914d8569d401306b3a5b..f2b321bae44037c08d4b09b90b8610a80b979eb7 100644 (file)
@@ -561,29 +561,28 @@ void exit_files(struct task_struct *tsk)
 
 #ifdef CONFIG_MM_OWNER
 /*
- * Task p is exiting and it owned mm, lets find a new owner for it
+ * A task is exiting.   If it owned this mm, find a new owner for the mm.
  */
-static inline int
-mm_need_new_owner(struct mm_struct *mm, struct task_struct *p)
-{
-       /*
-        * If there are other users of the mm and the owner (us) is exiting
-        * we need to find a new owner to take on the responsibility.
-        */
-       if (atomic_read(&mm->mm_users) <= 1)
-               return 0;
-       if (mm->owner != p)
-               return 0;
-       return 1;
-}
-
 void mm_update_next_owner(struct mm_struct *mm)
 {
        struct task_struct *c, *g, *p = current;
 
 retry:
-       if (!mm_need_new_owner(mm, p))
+       /*
+        * If the exiting or execing task is not the owner, it's
+        * someone else's problem.
+        */
+       if (mm->owner != p)
                return;
+       /*
+        * The current owner is exiting/execing and there are no other
+        * candidates.  Do not leave the mm pointing to a possibly
+        * freed task structure.
+        */
+       if (atomic_read(&mm->mm_users) <= 1) {
+               mm->owner = NULL;
+               return;
+       }
 
        read_lock(&tasklist_lock);
        /*
index 2b44d82b8237f6fb8e98cef8cff1c5cb84620efb..0276c30401a081132d1e4fadac663f3afdf292c0 100644 (file)
@@ -59,7 +59,6 @@
 #include <linux/taskstats_kern.h>
 #include <linux/random.h>
 #include <linux/tty.h>
-#include <linux/proc_fs.h>
 #include <linux/blkdev.h>
 #include <linux/fs_struct.h>
 #include <linux/magic.h>
@@ -383,15 +382,14 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
                        get_file(file);
                        if (tmp->vm_flags & VM_DENYWRITE)
                                atomic_dec(&inode->i_writecount);
-                       spin_lock(&mapping->i_mmap_lock);
+                       mutex_lock(&mapping->i_mmap_mutex);
                        if (tmp->vm_flags & VM_SHARED)
                                mapping->i_mmap_writable++;
-                       tmp->vm_truncate_count = mpnt->vm_truncate_count;
                        flush_dcache_mmap_lock(mapping);
                        /* insert tmp into the share list, just after mpnt */
                        vma_prio_tree_add(tmp, mpnt);
                        flush_dcache_mmap_unlock(mapping);
-                       spin_unlock(&mapping->i_mmap_lock);
+                       mutex_unlock(&mapping->i_mmap_mutex);
                }
 
                /*
@@ -522,11 +520,12 @@ struct mm_struct * mm_alloc(void)
        struct mm_struct * mm;
 
        mm = allocate_mm();
-       if (mm) {
-               memset(mm, 0, sizeof(*mm));
-               mm = mm_init(mm, current);
-       }
-       return mm;
+       if (!mm)
+               return NULL;
+
+       memset(mm, 0, sizeof(*mm));
+       mm_init_cpumask(mm);
+       return mm_init(mm, current);
 }
 
 /*
@@ -573,6 +572,57 @@ void mmput(struct mm_struct *mm)
 }
 EXPORT_SYMBOL_GPL(mmput);
 
+/*
+ * We added or removed a vma mapping the executable. The vmas are only mapped
+ * during exec and are not mapped with the mmap system call.
+ * Callers must hold down_write() on the mm's mmap_sem for these
+ */
+void added_exe_file_vma(struct mm_struct *mm)
+{
+       mm->num_exe_file_vmas++;
+}
+
+void removed_exe_file_vma(struct mm_struct *mm)
+{
+       mm->num_exe_file_vmas--;
+       if ((mm->num_exe_file_vmas == 0) && mm->exe_file){
+               fput(mm->exe_file);
+               mm->exe_file = NULL;
+       }
+
+}
+
+void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file)
+{
+       if (new_exe_file)
+               get_file(new_exe_file);
+       if (mm->exe_file)
+               fput(mm->exe_file);
+       mm->exe_file = new_exe_file;
+       mm->num_exe_file_vmas = 0;
+}
+
+struct file *get_mm_exe_file(struct mm_struct *mm)
+{
+       struct file *exe_file;
+
+       /* We need mmap_sem to protect against races with removal of
+        * VM_EXECUTABLE vmas */
+       down_read(&mm->mmap_sem);
+       exe_file = mm->exe_file;
+       if (exe_file)
+               get_file(exe_file);
+       up_read(&mm->mmap_sem);
+       return exe_file;
+}
+
+static void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm)
+{
+       /* It's safe to write the exe_file pointer without exe_file_lock because
+        * this is called during fork when the task is not yet in /proc */
+       newmm->exe_file = get_mm_exe_file(oldmm);
+}
+
 /**
  * get_task_mm - acquire a reference to the task's mm
  *
@@ -679,6 +729,7 @@ struct mm_struct *dup_mm(struct task_struct *tsk)
                goto fail_nomem;
 
        memcpy(mm, oldmm, sizeof(*mm));
+       mm_init_cpumask(mm);
 
        /* Initializing for Swap token stuff */
        mm->token_priority = 0;
@@ -927,6 +978,10 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
        tty_audit_fork(sig);
        sched_autogroup_fork(sig);
 
+#ifdef CONFIG_CGROUPS
+       init_rwsem(&sig->threadgroup_fork_lock);
+#endif
+
        sig->oom_adj = current->signal->oom_adj;
        sig->oom_score_adj = current->signal->oom_score_adj;
        sig->oom_score_adj_min = current->signal->oom_score_adj_min;
@@ -1108,6 +1163,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        monotonic_to_bootbased(&p->real_start_time);
        p->io_context = NULL;
        p->audit_context = NULL;
+       if (clone_flags & CLONE_THREAD)
+               threadgroup_fork_read_lock(current);
        cgroup_fork(p);
 #ifdef CONFIG_NUMA
        p->mempolicy = mpol_dup(p->mempolicy);
@@ -1193,12 +1250,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        if (clone_flags & CLONE_THREAD)
                p->tgid = current->tgid;
 
-       if (current->nsproxy != p->nsproxy) {
-               retval = ns_cgroup_clone(p, pid);
-               if (retval)
-                       goto bad_fork_free_pid;
-       }
-
        p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
        /*
         * Clear TID on mm_release()?
@@ -1312,6 +1363,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        write_unlock_irq(&tasklist_lock);
        proc_fork_connector(p);
        cgroup_post_fork(p);
+       if (clone_flags & CLONE_THREAD)
+               threadgroup_fork_read_unlock(current);
        perf_event_fork(p);
        return p;
 
@@ -1350,6 +1403,8 @@ bad_fork_cleanup_policy:
        mpol_put(p->mempolicy);
 bad_fork_cleanup_cgroup:
 #endif
+       if (clone_flags & CLONE_THREAD)
+               threadgroup_fork_read_unlock(current);
        cgroup_exit(p, cgroup_callbacks_done);
        delayacct_tsk_free(p);
        module_put(task_thread_info(p)->exec_domain->module);
@@ -1507,6 +1562,13 @@ void __init proc_caches_init(void)
        fs_cachep = kmem_cache_create("fs_cache",
                        sizeof(struct fs_struct), 0,
                        SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK, NULL);
+       /*
+        * FIXME! The "sizeof(struct mm_struct)" currently includes the
+        * whole struct cpumask for the OFFSTACK case. We could change
+        * this to *only* allocate as much of it as required by the
+        * maximum number of CPU's we can ever have.  The cpumask_allocation
+        * is at the end of the structure, exactly for that reason.
+        */
        mm_cachep = kmem_cache_create("mm_struct",
                        sizeof(struct mm_struct), ARCH_MIN_MMSTRUCT_ALIGN,
                        SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK, NULL);
index b8cadf70b1fbd109c4ca56f78f6f9a685e2f9974..5bf924d80b5c64be2888be0afd65008260e8db01 100644 (file)
@@ -2,7 +2,8 @@ menu "GCOV-based kernel profiling"
 
 config GCOV_KERNEL
        bool "Enable gcov-based kernel profiling"
-       depends on DEBUG_FS && CONSTRUCTORS
+       depends on DEBUG_FS
+       select CONSTRUCTORS
        default n
        ---help---
        This option enables gcov-based code profiling (e.g. for code coverage
index c541ee527ecb72443dc598764ede707b664a4b79..a9205e32a059cde761f924c498d2984b0aacb36c 100644 (file)
@@ -748,7 +748,7 @@ static inline void retrigger_next_event(void *arg) { }
  */
 void clock_was_set(void)
 {
-#ifdef CONFIG_HIGHRES_TIMERS
+#ifdef CONFIG_HIGH_RES_TIMERS
        /* Retrigger the CPU local events everywhere */
        on_each_cpu(retrigger_next_event, NULL, 1);
 #endif
index 90cb55f6d7ebe4496b339f5202f0a31926854963..470d08c82bbe29f373a9aa79d07794d56985763b 100644 (file)
@@ -132,12 +132,6 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
 
                switch (res) {
                case IRQ_WAKE_THREAD:
-                       /*
-                        * Set result to handled so the spurious check
-                        * does not trigger.
-                        */
-                       res = IRQ_HANDLED;
-
                        /*
                         * Catch drivers which return WAKE_THREAD but
                         * did not set up a thread function
index 886e80347b322795b56630857fd98996545ea5a4..4c60a50e66b237922381c5b0d0d82d55b436b6dc 100644 (file)
@@ -257,13 +257,11 @@ int __init early_irq_init(void)
        count = ARRAY_SIZE(irq_desc);
 
        for (i = 0; i < count; i++) {
-               desc[i].irq_data.irq = i;
-               desc[i].irq_data.chip = &no_irq_chip;
                desc[i].kstat_irqs = alloc_percpu(unsigned int);
-               irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS);
-               alloc_masks(desc + i, GFP_KERNEL, node);
-               desc_smp_init(desc + i, node);
+               alloc_masks(&desc[i], GFP_KERNEL, node);
+               raw_spin_lock_init(&desc[i].lock);
                lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
+               desc_set_defaults(i, &desc[i], node);
        }
        return arch_early_irq_init();
 }
@@ -346,6 +344,12 @@ irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node)
        if (!cnt)
                return -EINVAL;
 
+       if (irq >= 0) {
+               if (from > irq)
+                       return -EINVAL;
+               from = irq;
+       }
+
        mutex_lock(&sparse_irq_lock);
 
        start = bitmap_find_next_zero_area(allocated_irqs, IRQ_BITMAP_BITS,
index f7ce0021e1c48eb02e2eb6531265ac84bfc24d96..0a7840aeb0fb9efbc18a6e6e8e6f01de17ed91cd 100644 (file)
@@ -491,6 +491,9 @@ int irq_set_irq_wake(unsigned int irq, unsigned int on)
        struct irq_desc *desc = irq_get_desc_buslock(irq, &flags);
        int ret = 0;
 
+       if (!desc)
+               return -EINVAL;
+
        /* wakeup-capable irqs can be shared between drivers that
         * don't need to have the same sleep mode behaviors.
         */
@@ -723,13 +726,16 @@ irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) { }
  * context. So we need to disable bh here to avoid deadlocks and other
  * side effects.
  */
-static void
+static irqreturn_t
 irq_forced_thread_fn(struct irq_desc *desc, struct irqaction *action)
 {
+       irqreturn_t ret;
+
        local_bh_disable();
-       action->thread_fn(action->irq, action->dev_id);
+       ret = action->thread_fn(action->irq, action->dev_id);
        irq_finalize_oneshot(desc, action, false);
        local_bh_enable();
+       return ret;
 }
 
 /*
@@ -737,10 +743,14 @@ irq_forced_thread_fn(struct irq_desc *desc, struct irqaction *action)
  * preemtible - many of them need to sleep and wait for slow busses to
  * complete.
  */
-static void irq_thread_fn(struct irq_desc *desc, struct irqaction *action)
+static irqreturn_t irq_thread_fn(struct irq_desc *desc,
+               struct irqaction *action)
 {
-       action->thread_fn(action->irq, action->dev_id);
+       irqreturn_t ret;
+
+       ret = action->thread_fn(action->irq, action->dev_id);
        irq_finalize_oneshot(desc, action, false);
+       return ret;
 }
 
 /*
@@ -753,7 +763,8 @@ static int irq_thread(void *data)
        };
        struct irqaction *action = data;
        struct irq_desc *desc = irq_to_desc(action->irq);
-       void (*handler_fn)(struct irq_desc *desc, struct irqaction *action);
+       irqreturn_t (*handler_fn)(struct irq_desc *desc,
+                       struct irqaction *action);
        int wake;
 
        if (force_irqthreads & test_bit(IRQTF_FORCED_THREAD,
@@ -783,8 +794,12 @@ static int irq_thread(void *data)
                        desc->istate |= IRQS_PENDING;
                        raw_spin_unlock_irq(&desc->lock);
                } else {
+                       irqreturn_t action_ret;
+
                        raw_spin_unlock_irq(&desc->lock);
-                       handler_fn(desc, action);
+                       action_ret = handler_fn(desc, action);
+                       if (!noirqdebug)
+                               note_interrupt(action->irq, desc, action_ret);
                }
 
                wake = atomic_dec_and_test(&desc->threads_active);
index 834899f2500fc550d3da66306d31386eb80baf91..4bd4faa6323ac14d327addcf1012c9318c51f623 100644 (file)
@@ -19,7 +19,7 @@ static struct proc_dir_entry *root_irq_dir;
 
 #ifdef CONFIG_SMP
 
-static int irq_affinity_proc_show(struct seq_file *m, void *v)
+static int show_irq_affinity(int type, struct seq_file *m, void *v)
 {
        struct irq_desc *desc = irq_to_desc((long)m->private);
        const struct cpumask *mask = desc->irq_data.affinity;
@@ -28,7 +28,10 @@ static int irq_affinity_proc_show(struct seq_file *m, void *v)
        if (irqd_is_setaffinity_pending(&desc->irq_data))
                mask = desc->pending_mask;
 #endif
-       seq_cpumask(m, mask);
+       if (type)
+               seq_cpumask_list(m, mask);
+       else
+               seq_cpumask(m, mask);
        seq_putc(m, '\n');
        return 0;
 }
@@ -59,7 +62,18 @@ static int irq_affinity_hint_proc_show(struct seq_file *m, void *v)
 #endif
 
 int no_irq_affinity;
-static ssize_t irq_affinity_proc_write(struct file *file,
+static int irq_affinity_proc_show(struct seq_file *m, void *v)
+{
+       return show_irq_affinity(0, m, v);
+}
+
+static int irq_affinity_list_proc_show(struct seq_file *m, void *v)
+{
+       return show_irq_affinity(1, m, v);
+}
+
+
+static ssize_t write_irq_affinity(int type, struct file *file,
                const char __user *buffer, size_t count, loff_t *pos)
 {
        unsigned int irq = (int)(long)PDE(file->f_path.dentry->d_inode)->data;
@@ -72,7 +86,10 @@ static ssize_t irq_affinity_proc_write(struct file *file,
        if (!alloc_cpumask_var(&new_value, GFP_KERNEL))
                return -ENOMEM;
 
-       err = cpumask_parse_user(buffer, count, new_value);
+       if (type)
+               err = cpumask_parselist_user(buffer, count, new_value);
+       else
+               err = cpumask_parse_user(buffer, count, new_value);
        if (err)
                goto free_cpumask;
 
@@ -100,11 +117,28 @@ free_cpumask:
        return err;
 }
 
+static ssize_t irq_affinity_proc_write(struct file *file,
+               const char __user *buffer, size_t count, loff_t *pos)
+{
+       return write_irq_affinity(0, file, buffer, count, pos);
+}
+
+static ssize_t irq_affinity_list_proc_write(struct file *file,
+               const char __user *buffer, size_t count, loff_t *pos)
+{
+       return write_irq_affinity(1, file, buffer, count, pos);
+}
+
 static int irq_affinity_proc_open(struct inode *inode, struct file *file)
 {
        return single_open(file, irq_affinity_proc_show, PDE(inode)->data);
 }
 
+static int irq_affinity_list_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, irq_affinity_list_proc_show, PDE(inode)->data);
+}
+
 static int irq_affinity_hint_proc_open(struct inode *inode, struct file *file)
 {
        return single_open(file, irq_affinity_hint_proc_show, PDE(inode)->data);
@@ -125,6 +159,14 @@ static const struct file_operations irq_affinity_hint_proc_fops = {
        .release        = single_release,
 };
 
+static const struct file_operations irq_affinity_list_proc_fops = {
+       .open           = irq_affinity_list_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = irq_affinity_list_proc_write,
+};
+
 static int default_affinity_show(struct seq_file *m, void *v)
 {
        seq_cpumask(m, irq_default_affinity);
@@ -289,6 +331,10 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc)
        proc_create_data("affinity_hint", 0400, desc->dir,
                         &irq_affinity_hint_proc_fops, (void *)(long)irq);
 
+       /* create /proc/irq/<irq>/smp_affinity_list */
+       proc_create_data("smp_affinity_list", 0600, desc->dir,
+                        &irq_affinity_list_proc_fops, (void *)(long)irq);
+
        proc_create_data("node", 0444, desc->dir,
                         &irq_node_proc_fops, (void *)(long)irq);
 #endif
@@ -306,6 +352,7 @@ void unregister_irq_proc(unsigned int irq, struct irq_desc *desc)
 #ifdef CONFIG_SMP
        remove_proc_entry("smp_affinity", desc->dir);
        remove_proc_entry("affinity_hint", desc->dir);
+       remove_proc_entry("smp_affinity_list", desc->dir);
        remove_proc_entry("node", desc->dir);
 #endif
        remove_proc_entry("spurious", desc->dir);
index dfbd550401b28f29a4db69807fae318c8ec7341a..aa57d5da18c1de65e807098702ad9b841fa3788d 100644 (file)
@@ -167,6 +167,13 @@ out:
                  jiffies + POLL_SPURIOUS_IRQ_INTERVAL);
 }
 
+static inline int bad_action_ret(irqreturn_t action_ret)
+{
+       if (likely(action_ret <= (IRQ_HANDLED | IRQ_WAKE_THREAD)))
+               return 0;
+       return 1;
+}
+
 /*
  * If 99,900 of the previous 100,000 interrupts have not been handled
  * then assume that the IRQ is stuck in some manner. Drop a diagnostic
@@ -182,7 +189,7 @@ __report_bad_irq(unsigned int irq, struct irq_desc *desc,
        struct irqaction *action;
        unsigned long flags;
 
-       if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
+       if (bad_action_ret(action_ret)) {
                printk(KERN_ERR "irq event %d: bogus return value %x\n",
                                irq, action_ret);
        } else {
@@ -201,10 +208,11 @@ __report_bad_irq(unsigned int irq, struct irq_desc *desc,
        raw_spin_lock_irqsave(&desc->lock, flags);
        action = desc->action;
        while (action) {
-               printk(KERN_ERR "[<%p>]", action->handler);
-               print_symbol(" (%s)",
-                       (unsigned long)action->handler);
-               printk("\n");
+               printk(KERN_ERR "[<%p>] %pf", action->handler, action->handler);
+               if (action->thread_fn)
+                       printk(KERN_CONT " threaded [<%p>] %pf",
+                                       action->thread_fn, action->thread_fn);
+               printk(KERN_CONT "\n");
                action = action->next;
        }
        raw_spin_unlock_irqrestore(&desc->lock, flags);
@@ -262,7 +270,16 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
        if (desc->istate & IRQS_POLL_INPROGRESS)
                return;
 
-       if (unlikely(action_ret != IRQ_HANDLED)) {
+       /* we get here again via the threaded handler */
+       if (action_ret == IRQ_WAKE_THREAD)
+               return;
+
+       if (bad_action_ret(action_ret)) {
+               report_bad_irq(irq, desc, action_ret);
+               return;
+       }
+
+       if (unlikely(action_ret == IRQ_NONE)) {
                /*
                 * If we are seeing only the odd spurious IRQ caused by
                 * bus asynchronicity then don't eventually trigger an error,
@@ -274,8 +291,6 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
                else
                        desc->irqs_unhandled++;
                desc->last_unhandled = jiffies;
-               if (unlikely(action_ret != IRQ_NONE))
-                       report_bad_irq(irq, desc, action_ret);
        }
 
        if (unlikely(try_misrouted_irq(irq, desc, action_ret))) {
index 74d1c099fbd1d8a8a3368865f919e978020e3521..fa27e750dbc0edb3dd5c502da1b5be38d83d8c8b 100644 (file)
@@ -105,9 +105,12 @@ static int __jump_label_text_reserved(struct jump_entry *iter_start,
 }
 
 static void __jump_label_update(struct jump_label_key *key,
-               struct jump_entry *entry, int enable)
+                               struct jump_entry *entry,
+                               struct jump_entry *stop, int enable)
 {
-       for (; entry->key == (jump_label_t)(unsigned long)key; entry++) {
+       for (; (entry < stop) &&
+             (entry->key == (jump_label_t)(unsigned long)key);
+             entry++) {
                /*
                 * entry->code set to 0 invalidates module init text sections
                 * kernel_text_address() verifies we are not in core kernel
@@ -181,7 +184,11 @@ static void __jump_label_mod_update(struct jump_label_key *key, int enable)
        struct jump_label_mod *mod = key->next;
 
        while (mod) {
-               __jump_label_update(key, mod->entries, enable);
+               struct module *m = mod->mod;
+
+               __jump_label_update(key, mod->entries,
+                                   m->jump_entries + m->num_jump_entries,
+                                   enable);
                mod = mod->next;
        }
 }
@@ -245,7 +252,8 @@ static int jump_label_add_module(struct module *mod)
                key->next = jlm;
 
                if (jump_label_enabled(key))
-                       __jump_label_update(key, iter, JUMP_LABEL_ENABLE);
+                       __jump_label_update(key, iter, iter_stop,
+                                           JUMP_LABEL_ENABLE);
        }
 
        return 0;
@@ -371,7 +379,7 @@ static void jump_label_update(struct jump_label_key *key, int enable)
 
        /* if there are no users, entry can be NULL */
        if (entry)
-               __jump_label_update(key, entry, enable);
+               __jump_label_update(key, entry, __stop___jump_table, enable);
 
 #ifdef CONFIG_MODULES
        __jump_label_mod_update(key, enable);
index 5ae0ff38425f7ec6dfd0a794668df7a02d1ff923..47613dfb7b28c340825493ed36a4c3347a39290d 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/kmod.h>
 #include <linux/slab.h>
 #include <linux/completion.h>
+#include <linux/cred.h>
 #include <linux/file.h>
 #include <linux/fdtable.h>
 #include <linux/workqueue.h>
@@ -43,6 +44,13 @@ extern int max_threads;
 
 static struct workqueue_struct *khelper_wq;
 
+#define CAP_BSET       (void *)1
+#define CAP_PI         (void *)2
+
+static kernel_cap_t usermodehelper_bset = CAP_FULL_SET;
+static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET;
+static DEFINE_SPINLOCK(umh_sysctl_lock);
+
 #ifdef CONFIG_MODULES
 
 /*
@@ -132,6 +140,7 @@ EXPORT_SYMBOL(__request_module);
 static int ____call_usermodehelper(void *data)
 {
        struct subprocess_info *sub_info = data;
+       struct cred *new;
        int retval;
 
        spin_lock_irq(&current->sighand->siglock);
@@ -147,12 +156,27 @@ static int ____call_usermodehelper(void *data)
         */
        set_user_nice(current, 0);
 
+       retval = -ENOMEM;
+       new = prepare_kernel_cred(current);
+       if (!new)
+               goto fail;
+
+       spin_lock(&umh_sysctl_lock);
+       new->cap_bset = cap_intersect(usermodehelper_bset, new->cap_bset);
+       new->cap_inheritable = cap_intersect(usermodehelper_inheritable,
+                                            new->cap_inheritable);
+       spin_unlock(&umh_sysctl_lock);
+
        if (sub_info->init) {
-               retval = sub_info->init(sub_info);
-               if (retval)
+               retval = sub_info->init(sub_info, new);
+               if (retval) {
+                       abort_creds(new);
                        goto fail;
+               }
        }
 
+       commit_creds(new);
+
        retval = kernel_execve(sub_info->path,
                               (const char *const *)sub_info->argv,
                               (const char *const *)sub_info->envp);
@@ -366,7 +390,7 @@ EXPORT_SYMBOL(call_usermodehelper_setup);
  * context in which call_usermodehelper_exec is called.
  */
 void call_usermodehelper_setfns(struct subprocess_info *info,
-                   int (*init)(struct subprocess_info *info),
+                   int (*init)(struct subprocess_info *info, struct cred *new),
                    void (*cleanup)(struct subprocess_info *info),
                    void *data)
 {
@@ -420,6 +444,84 @@ unlock:
 }
 EXPORT_SYMBOL(call_usermodehelper_exec);
 
+static int proc_cap_handler(struct ctl_table *table, int write,
+                        void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       struct ctl_table t;
+       unsigned long cap_array[_KERNEL_CAPABILITY_U32S];
+       kernel_cap_t new_cap;
+       int err, i;
+
+       if (write && (!capable(CAP_SETPCAP) ||
+                     !capable(CAP_SYS_MODULE)))
+               return -EPERM;
+
+       /*
+        * convert from the global kernel_cap_t to the ulong array to print to
+        * userspace if this is a read.
+        */
+       spin_lock(&umh_sysctl_lock);
+       for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++)  {
+               if (table->data == CAP_BSET)
+                       cap_array[i] = usermodehelper_bset.cap[i];
+               else if (table->data == CAP_PI)
+                       cap_array[i] = usermodehelper_inheritable.cap[i];
+               else
+                       BUG();
+       }
+       spin_unlock(&umh_sysctl_lock);
+
+       t = *table;
+       t.data = &cap_array;
+
+       /*
+        * actually read or write and array of ulongs from userspace.  Remember
+        * these are least significant 32 bits first
+        */
+       err = proc_doulongvec_minmax(&t, write, buffer, lenp, ppos);
+       if (err < 0)
+               return err;
+
+       /*
+        * convert from the sysctl array of ulongs to the kernel_cap_t
+        * internal representation
+        */
+       for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++)
+               new_cap.cap[i] = cap_array[i];
+
+       /*
+        * Drop everything not in the new_cap (but don't add things)
+        */
+       spin_lock(&umh_sysctl_lock);
+       if (write) {
+               if (table->data == CAP_BSET)
+                       usermodehelper_bset = cap_intersect(usermodehelper_bset, new_cap);
+               if (table->data == CAP_PI)
+                       usermodehelper_inheritable = cap_intersect(usermodehelper_inheritable, new_cap);
+       }
+       spin_unlock(&umh_sysctl_lock);
+
+       return 0;
+}
+
+struct ctl_table usermodehelper_table[] = {
+       {
+               .procname       = "bset",
+               .data           = CAP_BSET,
+               .maxlen         = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long),
+               .mode           = 0600,
+               .proc_handler   = proc_cap_handler,
+       },
+       {
+               .procname       = "inheritable",
+               .data           = CAP_PI,
+               .maxlen         = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long),
+               .mode           = 0600,
+               .proc_handler   = proc_cap_handler,
+       },
+       { }
+};
+
 void __init usermodehelper_init(void)
 {
        khelper_wq = create_singlethread_workqueue("khelper");
index 3b34d2732bcecb3719b67976f5b8b7bc66e68b2b..4ba7cccb4994f24d6bc5965cda9b7f568d214f35 100644 (file)
@@ -202,8 +202,8 @@ void kthread_bind(struct task_struct *p, unsigned int cpu)
                return;
        }
 
-       p->cpus_allowed = cpumask_of_cpu(cpu);
-       p->rt.nr_cpus_allowed = 1;
+       /* It's safe because the task is inactive. */
+       do_set_cpus_allowed(p, cpumask_of(cpu));
        p->flags |= PF_THREAD_BOUND;
 }
 EXPORT_SYMBOL(kthread_bind);
index 63437d065ac89d69bbc6e70fd3789e64ac7e1d6a..298c9276dfdb378877249384db860c3658485ef2 100644 (file)
@@ -3426,7 +3426,7 @@ int lock_is_held(struct lockdep_map *lock)
        int ret = 0;
 
        if (unlikely(current->lockdep_recursion))
-               return ret;
+               return 1; /* avoid false negative lockdep_assert_held() */
 
        raw_local_irq_save(flags);
        check_flags(flags);
index 2c938e2337cd36f3e627bb5758186aa7b4e0a327..d607ed5dd4416b5a688a271d788d7c2e51190662 100644 (file)
@@ -131,14 +131,14 @@ EXPORT_SYMBOL(mutex_unlock);
  */
 static inline int __sched
 __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
-               unsigned long ip)
+                   struct lockdep_map *nest_lock, unsigned long ip)
 {
        struct task_struct *task = current;
        struct mutex_waiter waiter;
        unsigned long flags;
 
        preempt_disable();
-       mutex_acquire(&lock->dep_map, subclass, 0, ip);
+       mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, ip);
 
 #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
        /*
@@ -269,16 +269,25 @@ void __sched
 mutex_lock_nested(struct mutex *lock, unsigned int subclass)
 {
        might_sleep();
-       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass, _RET_IP_);
+       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass, NULL, _RET_IP_);
 }
 
 EXPORT_SYMBOL_GPL(mutex_lock_nested);
 
+void __sched
+_mutex_lock_nest_lock(struct mutex *lock, struct lockdep_map *nest)
+{
+       might_sleep();
+       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, nest, _RET_IP_);
+}
+
+EXPORT_SYMBOL_GPL(_mutex_lock_nest_lock);
+
 int __sched
 mutex_lock_killable_nested(struct mutex *lock, unsigned int subclass)
 {
        might_sleep();
-       return __mutex_lock_common(lock, TASK_KILLABLE, subclass, _RET_IP_);
+       return __mutex_lock_common(lock, TASK_KILLABLE, subclass, NULL, _RET_IP_);
 }
 EXPORT_SYMBOL_GPL(mutex_lock_killable_nested);
 
@@ -287,7 +296,7 @@ mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass)
 {
        might_sleep();
        return __mutex_lock_common(lock, TASK_INTERRUPTIBLE,
-                                  subclass, _RET_IP_);
+                                  subclass, NULL, _RET_IP_);
 }
 
 EXPORT_SYMBOL_GPL(mutex_lock_interruptible_nested);
@@ -393,7 +402,7 @@ __mutex_lock_slowpath(atomic_t *lock_count)
 {
        struct mutex *lock = container_of(lock_count, struct mutex, count);
 
-       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, _RET_IP_);
+       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, NULL, _RET_IP_);
 }
 
 static noinline int __sched
@@ -401,7 +410,7 @@ __mutex_lock_killable_slowpath(atomic_t *lock_count)
 {
        struct mutex *lock = container_of(lock_count, struct mutex, count);
 
-       return __mutex_lock_common(lock, TASK_KILLABLE, 0, _RET_IP_);
+       return __mutex_lock_common(lock, TASK_KILLABLE, 0, NULL, _RET_IP_);
 }
 
 static noinline int __sched
@@ -409,7 +418,7 @@ __mutex_lock_interruptible_slowpath(atomic_t *lock_count)
 {
        struct mutex *lock = container_of(lock_count, struct mutex, count);
 
-       return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, 0, _RET_IP_);
+       return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, 0, NULL, _RET_IP_);
 }
 #endif
 
diff --git a/kernel/ns_cgroup.c b/kernel/ns_cgroup.c
deleted file mode 100644 (file)
index 2c98ad9..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * ns_cgroup.c - namespace cgroup subsystem
- *
- * Copyright 2006, 2007 IBM Corp
- */
-
-#include <linux/module.h>
-#include <linux/cgroup.h>
-#include <linux/fs.h>
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/nsproxy.h>
-
-struct ns_cgroup {
-       struct cgroup_subsys_state css;
-};
-
-struct cgroup_subsys ns_subsys;
-
-static inline struct ns_cgroup *cgroup_to_ns(
-               struct cgroup *cgroup)
-{
-       return container_of(cgroup_subsys_state(cgroup, ns_subsys_id),
-                           struct ns_cgroup, css);
-}
-
-int ns_cgroup_clone(struct task_struct *task, struct pid *pid)
-{
-       char name[PROC_NUMBUF];
-
-       snprintf(name, PROC_NUMBUF, "%d", pid_vnr(pid));
-       return cgroup_clone(task, &ns_subsys, name);
-}
-
-/*
- * Rules:
- *   1. you can only enter a cgroup which is a descendant of your current
- *     cgroup
- *   2. you can only place another process into a cgroup if
- *     a. you have CAP_SYS_ADMIN
- *     b. your cgroup is an ancestor of task's destination cgroup
- *       (hence either you are in the same cgroup as task, or in an
- *        ancestor cgroup thereof)
- */
-static int ns_can_attach(struct cgroup_subsys *ss, struct cgroup *new_cgroup,
-                        struct task_struct *task, bool threadgroup)
-{
-       if (current != task) {
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-
-               if (!cgroup_is_descendant(new_cgroup, current))
-                       return -EPERM;
-       }
-
-       if (!cgroup_is_descendant(new_cgroup, task))
-               return -EPERM;
-
-       if (threadgroup) {
-               struct task_struct *c;
-               rcu_read_lock();
-               list_for_each_entry_rcu(c, &task->thread_group, thread_group) {
-                       if (!cgroup_is_descendant(new_cgroup, c)) {
-                               rcu_read_unlock();
-                               return -EPERM;
-                       }
-               }
-               rcu_read_unlock();
-       }
-
-       return 0;
-}
-
-/*
- * Rules: you can only create a cgroup if
- *     1. you are capable(CAP_SYS_ADMIN)
- *     2. the target cgroup is a descendant of your own cgroup
- */
-static struct cgroup_subsys_state *ns_create(struct cgroup_subsys *ss,
-                                               struct cgroup *cgroup)
-{
-       struct ns_cgroup *ns_cgroup;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return ERR_PTR(-EPERM);
-       if (!cgroup_is_descendant(cgroup, current))
-               return ERR_PTR(-EPERM);
-       if (test_bit(CGRP_CLONE_CHILDREN, &cgroup->flags)) {
-               printk("ns_cgroup can't be created with parent "
-                      "'clone_children' set.\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       printk_once("ns_cgroup deprecated: consider using the "
-                   "'clone_children' flag without the ns_cgroup.\n");
-
-       ns_cgroup = kzalloc(sizeof(*ns_cgroup), GFP_KERNEL);
-       if (!ns_cgroup)
-               return ERR_PTR(-ENOMEM);
-       return &ns_cgroup->css;
-}
-
-static void ns_destroy(struct cgroup_subsys *ss,
-                       struct cgroup *cgroup)
-{
-       struct ns_cgroup *ns_cgroup;
-
-       ns_cgroup = cgroup_to_ns(cgroup);
-       kfree(ns_cgroup);
-}
-
-struct cgroup_subsys ns_subsys = {
-       .name = "ns",
-       .can_attach = ns_can_attach,
-       .create = ns_create,
-       .destroy  = ns_destroy,
-       .subsys_id = ns_subsys_id,
-};
index a05d191ffdd903bd2efc5e10d783021ef1b29a98..d6a00f3de15d59b3e1bcb8ebcc32373e447df180 100644 (file)
@@ -22,6 +22,9 @@
 #include <linux/pid_namespace.h>
 #include <net/net_namespace.h>
 #include <linux/ipc_namespace.h>
+#include <linux/proc_fs.h>
+#include <linux/file.h>
+#include <linux/syscalls.h>
 
 static struct kmem_cache *nsproxy_cachep;
 
@@ -198,10 +201,6 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags,
                goto out;
        }
 
-       err = ns_cgroup_clone(current, task_pid(current));
-       if (err)
-               put_nsproxy(*new_nsp);
-
 out:
        return err;
 }
@@ -233,6 +232,45 @@ void exit_task_namespaces(struct task_struct *p)
        switch_task_namespaces(p, NULL);
 }
 
+SYSCALL_DEFINE2(setns, int, fd, int, nstype)
+{
+       const struct proc_ns_operations *ops;
+       struct task_struct *tsk = current;
+       struct nsproxy *new_nsproxy;
+       struct proc_inode *ei;
+       struct file *file;
+       int err;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       file = proc_ns_fget(fd);
+       if (IS_ERR(file))
+               return PTR_ERR(file);
+
+       err = -EINVAL;
+       ei = PROC_I(file->f_dentry->d_inode);
+       ops = ei->ns_ops;
+       if (nstype && (ops->type != nstype))
+               goto out;
+
+       new_nsproxy = create_new_namespaces(0, tsk, tsk->fs);
+       if (IS_ERR(new_nsproxy)) {
+               err = PTR_ERR(new_nsproxy);
+               goto out;
+       }
+
+       err = ops->install(new_nsproxy, ei->ns);
+       if (err) {
+               free_nsproxy(new_nsproxy);
+               goto out;
+       }
+       switch_task_namespaces(tsk, new_nsproxy);
+out:
+       fput(file);
+       return err;
+}
+
 static int __init nsproxy_cache_init(void)
 {
        nsproxy_cachep = KMEM_CACHE(nsproxy, SLAB_PANIC);
index beb184689af9a1f225d3ab874a92c5690276c500..6824ca7d4d0cf7e7efad597aa4dec8c0a58f4af9 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/string.h>
 #include <linux/platform_device.h>
 #include <linux/init.h>
+#include <linux/kernel.h>
 
 #include <linux/uaccess.h>
 
@@ -53,11 +54,17 @@ enum pm_qos_type {
        PM_QOS_MIN              /* return the smallest value */
 };
 
+/*
+ * Note: The lockless read path depends on the CPU accessing
+ * target_value atomically.  Atomic access is only guaranteed on all CPU
+ * types linux supports for 32 bit quantites
+ */
 struct pm_qos_object {
        struct plist_head requests;
        struct blocking_notifier_head *notifiers;
        struct miscdevice pm_qos_power_miscdev;
        char *name;
+       s32 target_value;       /* Do not change to 64 bit */
        s32 default_value;
        enum pm_qos_type type;
 };
@@ -70,7 +77,8 @@ static struct pm_qos_object cpu_dma_pm_qos = {
        .requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests, pm_qos_lock),
        .notifiers = &cpu_dma_lat_notifier,
        .name = "cpu_dma_latency",
-       .default_value = 2000 * USEC_PER_SEC,
+       .target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
+       .default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
        .type = PM_QOS_MIN,
 };
 
@@ -79,7 +87,8 @@ static struct pm_qos_object network_lat_pm_qos = {
        .requests = PLIST_HEAD_INIT(network_lat_pm_qos.requests, pm_qos_lock),
        .notifiers = &network_lat_notifier,
        .name = "network_latency",
-       .default_value = 2000 * USEC_PER_SEC,
+       .target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
+       .default_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
        .type = PM_QOS_MIN
 };
 
@@ -89,7 +98,8 @@ static struct pm_qos_object network_throughput_pm_qos = {
        .requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests, pm_qos_lock),
        .notifiers = &network_throughput_notifier,
        .name = "network_throughput",
-       .default_value = 0,
+       .target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
+       .default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
        .type = PM_QOS_MAX,
 };
 
@@ -135,6 +145,16 @@ static inline int pm_qos_get_value(struct pm_qos_object *o)
        }
 }
 
+static inline s32 pm_qos_read_value(struct pm_qos_object *o)
+{
+       return o->target_value;
+}
+
+static inline void pm_qos_set_value(struct pm_qos_object *o, s32 value)
+{
+       o->target_value = value;
+}
+
 static void update_target(struct pm_qos_object *o, struct plist_node *node,
                          int del, int value)
 {
@@ -159,6 +179,7 @@ static void update_target(struct pm_qos_object *o, struct plist_node *node,
                plist_add(node, &o->requests);
        }
        curr_value = pm_qos_get_value(o);
+       pm_qos_set_value(o, curr_value);
        spin_unlock_irqrestore(&pm_qos_lock, flags);
 
        if (prev_value != curr_value)
@@ -193,18 +214,11 @@ static int find_pm_qos_object_by_minor(int minor)
  * pm_qos_request - returns current system wide qos expectation
  * @pm_qos_class: identification of which qos value is requested
  *
- * This function returns the current target value in an atomic manner.
+ * This function returns the current target value.
  */
 int pm_qos_request(int pm_qos_class)
 {
-       unsigned long flags;
-       int value;
-
-       spin_lock_irqsave(&pm_qos_lock, flags);
-       value = pm_qos_get_value(pm_qos_array[pm_qos_class]);
-       spin_unlock_irqrestore(&pm_qos_lock, flags);
-
-       return value;
+       return pm_qos_read_value(pm_qos_array[pm_qos_class]);
 }
 EXPORT_SYMBOL_GPL(pm_qos_request);
 
@@ -404,24 +418,36 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
                size_t count, loff_t *f_pos)
 {
        s32 value;
-       int x;
-       char ascii_value[11];
        struct pm_qos_request_list *pm_qos_req;
 
        if (count == sizeof(s32)) {
                if (copy_from_user(&value, buf, sizeof(s32)))
                        return -EFAULT;
-       } else if (count == 11) { /* len('0x12345678/0') */
-               if (copy_from_user(ascii_value, buf, 11))
+       } else if (count <= 11) { /* ASCII perhaps? */
+               char ascii_value[11];
+               unsigned long int ulval;
+               int ret;
+
+               if (copy_from_user(ascii_value, buf, count))
                        return -EFAULT;
-               if (strlen(ascii_value) != 10)
-                       return -EINVAL;
-               x = sscanf(ascii_value, "%x", &value);
-               if (x != 1)
+
+               if (count > 10) {
+                       if (ascii_value[10] == '\n')
+                               ascii_value[10] = '\0';
+                       else
+                               return -EINVAL;
+               } else {
+                       ascii_value[count] = '\0';
+               }
+               ret = strict_strtoul(ascii_value, 16, &ulval);
+               if (ret) {
+                       pr_debug("%s, 0x%lx, 0x%x\n", ascii_value, ulval, ret);
                        return -EINVAL;
-               pr_debug("%s, %d, 0x%x\n", ascii_value, x, value);
-       } else
+               }
+               value = (s32)lower_32_bits(ulval);
+       } else {
                return -EINVAL;
+       }
 
        pm_qos_req = filp->private_data;
        pm_qos_update_request(pm_qos_req, value);
index a1b5edf1bf92b6890f0bcb2b872e6bcc001d728e..4556182527f38fe88dba74dd753cec5ed0112785 100644 (file)
@@ -491,6 +491,13 @@ static struct k_itimer * alloc_posix_timer(void)
        return tmr;
 }
 
+static void k_itimer_rcu_free(struct rcu_head *head)
+{
+       struct k_itimer *tmr = container_of(head, struct k_itimer, it.rcu);
+
+       kmem_cache_free(posix_timers_cache, tmr);
+}
+
 #define IT_ID_SET      1
 #define IT_ID_NOT_SET  0
 static void release_posix_timer(struct k_itimer *tmr, int it_id_set)
@@ -503,7 +510,7 @@ static void release_posix_timer(struct k_itimer *tmr, int it_id_set)
        }
        put_pid(tmr->it_pid);
        sigqueue_free(tmr->sigq);
-       kmem_cache_free(posix_timers_cache, tmr);
+       call_rcu(&tmr->it.rcu, k_itimer_rcu_free);
 }
 
 static struct k_clock *clockid_to_kclock(const clockid_t id)
@@ -631,22 +638,18 @@ out:
 static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags)
 {
        struct k_itimer *timr;
-       /*
-        * Watch out here.  We do a irqsave on the idr_lock and pass the
-        * flags part over to the timer lock.  Must not let interrupts in
-        * while we are moving the lock.
-        */
-       spin_lock_irqsave(&idr_lock, *flags);
+
+       rcu_read_lock();
        timr = idr_find(&posix_timers_id, (int)timer_id);
        if (timr) {
-               spin_lock(&timr->it_lock);
+               spin_lock_irqsave(&timr->it_lock, *flags);
                if (timr->it_signal == current->signal) {
-                       spin_unlock(&idr_lock);
+                       rcu_read_unlock();
                        return timr;
                }
-               spin_unlock(&timr->it_lock);
+               spin_unlock_irqrestore(&timr->it_lock, *flags);
        }
-       spin_unlock_irqrestore(&idr_lock, *flags);
+       rcu_read_unlock();
 
        return NULL;
 }
index f9bec56d88258992b61e8f9fb3306dd010e652e1..8f7b1db1ece1b3273f9eebbc128d7c884390c638 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/gfp.h>
 #include <linux/syscore_ops.h>
 #include <scsi/scsi_scan.h>
-#include <asm/suspend.h>
 
 #include "power.h"
 
@@ -55,10 +54,9 @@ static int hibernation_mode = HIBERNATION_SHUTDOWN;
 static const struct platform_hibernation_ops *hibernation_ops;
 
 /**
- * hibernation_set_ops - set the global hibernate operations
- * @ops: the hibernation operations to use in subsequent hibernation transitions
+ * hibernation_set_ops - Set the global hibernate operations.
+ * @ops: Hibernation operations to use in subsequent hibernation transitions.
  */
-
 void hibernation_set_ops(const struct platform_hibernation_ops *ops)
 {
        if (ops && !(ops->begin && ops->end &&  ops->pre_snapshot
@@ -115,10 +113,9 @@ static int hibernation_test(int level) { return 0; }
 #endif /* !CONFIG_PM_DEBUG */
 
 /**
- *     platform_begin - tell the platform driver that we're starting
- *     hibernation
+ * platform_begin - Call platform to start hibernation.
+ * @platform_mode: Whether or not to use the platform driver.
  */
-
 static int platform_begin(int platform_mode)
 {
        return (platform_mode && hibernation_ops) ?
@@ -126,10 +123,9 @@ static int platform_begin(int platform_mode)
 }
 
 /**
- *     platform_end - tell the platform driver that we've entered the
- *     working state
+ * platform_end - Call platform to finish transition to the working state.
+ * @platform_mode: Whether or not to use the platform driver.
  */
-
 static void platform_end(int platform_mode)
 {
        if (platform_mode && hibernation_ops)
@@ -137,8 +133,11 @@ static void platform_end(int platform_mode)
 }
 
 /**
- *     platform_pre_snapshot - prepare the machine for hibernation using the
- *     platform driver if so configured and return an error code if it fails
+ * platform_pre_snapshot - Call platform to prepare the machine for hibernation.
+ * @platform_mode: Whether or not to use the platform driver.
+ *
+ * Use the platform driver to prepare the system for creating a hibernate image,
+ * if so configured, and return an error code if that fails.
  */
 
 static int platform_pre_snapshot(int platform_mode)
@@ -148,10 +147,14 @@ static int platform_pre_snapshot(int platform_mode)
 }
 
 /**
- *     platform_leave - prepare the machine for switching to the normal mode
- *     of operation using the platform driver (called with interrupts disabled)
+ * platform_leave - Call platform to prepare a transition to the working state.
+ * @platform_mode: Whether or not to use the platform driver.
+ *
+ * Use the platform driver prepare to prepare the machine for switching to the
+ * normal mode of operation.
+ *
+ * This routine is called on one CPU with interrupts disabled.
  */
-
 static void platform_leave(int platform_mode)
 {
        if (platform_mode && hibernation_ops)
@@ -159,10 +162,14 @@ static void platform_leave(int platform_mode)
 }
 
 /**
- *     platform_finish - switch the machine to the normal mode of operation
- *     using the platform driver (must be called after platform_prepare())
+ * platform_finish - Call platform to switch the system to the working state.
+ * @platform_mode: Whether or not to use the platform driver.
+ *
+ * Use the platform driver to switch the machine to the normal mode of
+ * operation.
+ *
+ * This routine must be called after platform_prepare().
  */
-
 static void platform_finish(int platform_mode)
 {
        if (platform_mode && hibernation_ops)
@@ -170,11 +177,15 @@ static void platform_finish(int platform_mode)
 }
 
 /**
- *     platform_pre_restore - prepare the platform for the restoration from a
- *     hibernation image.  If the restore fails after this function has been
- *     called, platform_restore_cleanup() must be called.
+ * platform_pre_restore - Prepare for hibernate image restoration.
+ * @platform_mode: Whether or not to use the platform driver.
+ *
+ * Use the platform driver to prepare the system for resume from a hibernation
+ * image.
+ *
+ * If the restore fails after this function has been called,
+ * platform_restore_cleanup() must be called.
  */
-
 static int platform_pre_restore(int platform_mode)
 {
        return (platform_mode && hibernation_ops) ?
@@ -182,12 +193,16 @@ static int platform_pre_restore(int platform_mode)
 }
 
 /**
- *     platform_restore_cleanup - switch the platform to the normal mode of
- *     operation after a failing restore.  If platform_pre_restore() has been
- *     called before the failing restore, this function must be called too,
- *     regardless of the result of platform_pre_restore().
+ * platform_restore_cleanup - Switch to the working state after failing restore.
+ * @platform_mode: Whether or not to use the platform driver.
+ *
+ * Use the platform driver to switch the system to the normal mode of operation
+ * after a failing restore.
+ *
+ * If platform_pre_restore() has been called before the failing restore, this
+ * function must be called too, regardless of the result of
+ * platform_pre_restore().
  */
-
 static void platform_restore_cleanup(int platform_mode)
 {
        if (platform_mode && hibernation_ops)
@@ -195,10 +210,9 @@ static void platform_restore_cleanup(int platform_mode)
 }
 
 /**
- *     platform_recover - recover the platform from a failure to suspend
- *     devices.
+ * platform_recover - Recover from a failure to suspend devices.
+ * @platform_mode: Whether or not to use the platform driver.
  */
-
 static void platform_recover(int platform_mode)
 {
        if (platform_mode && hibernation_ops && hibernation_ops->recover)
@@ -206,13 +220,12 @@ static void platform_recover(int platform_mode)
 }
 
 /**
- *     swsusp_show_speed - print the time elapsed between two events.
- *     @start: Starting event.
- *     @stop: Final event.
- *     @nr_pages -     number of pages processed between @start and @stop
- *     @msg -          introductory message to print
+ * swsusp_show_speed - Print time elapsed between two events during hibernation.
+ * @start: Starting event.
+ * @stop: Final event.
+ * @nr_pages: Number of memory pages processed between @start and @stop.
+ * @msg: Additional diagnostic message to print.
  */
-
 void swsusp_show_speed(struct timeval *start, struct timeval *stop,
                        unsigned nr_pages, char *msg)
 {
@@ -235,25 +248,18 @@ void swsusp_show_speed(struct timeval *start, struct timeval *stop,
 }
 
 /**
- *     create_image - freeze devices that need to be frozen with interrupts
- *     off, create the hibernation image and thaw those devices.  Control
- *     reappears in this routine after a restore.
+ * create_image - Create a hibernation image.
+ * @platform_mode: Whether or not to use the platform driver.
+ *
+ * Execute device drivers' .freeze_noirq() callbacks, create a hibernation image
+ * and execute the drivers' .thaw_noirq() callbacks.
+ *
+ * Control reappears in this routine after the subsequent restore.
  */
-
 static int create_image(int platform_mode)
 {
        int error;
 
-       error = arch_prepare_suspend();
-       if (error)
-               return error;
-
-       /* At this point, dpm_suspend_start() has been called, but *not*
-        * dpm_suspend_noirq(). We *must* call dpm_suspend_noirq() now.
-        * Otherwise, drivers for some devices (e.g. interrupt controllers)
-        * become desynchronized with the actual state of the hardware
-        * at resume time, and evil weirdness ensues.
-        */
        error = dpm_suspend_noirq(PMSG_FREEZE);
        if (error) {
                printk(KERN_ERR "PM: Some devices failed to power down, "
@@ -297,9 +303,6 @@ static int create_image(int platform_mode)
 
  Power_up:
        syscore_resume();
-       /* NOTE:  dpm_resume_noirq() is just a resume() for devices
-        * that suspended with irqs off ... no overall powerup.
-        */
 
  Enable_irqs:
        local_irq_enable();
@@ -317,14 +320,11 @@ static int create_image(int platform_mode)
 }
 
 /**
- *     hibernation_snapshot - quiesce devices and create the hibernation
- *     snapshot image.
- *     @platform_mode - if set, use the platform driver, if available, to
- *                      prepare the platform firmware for the power transition.
+ * hibernation_snapshot - Quiesce devices and create a hibernation image.
+ * @platform_mode: If set, use platform driver to prepare for the transition.
  *
- *     Must be called with pm_mutex held
+ * This routine must be called with pm_mutex held.
  */
-
 int hibernation_snapshot(int platform_mode)
 {
        pm_message_t msg = PMSG_RECOVER;
@@ -384,13 +384,14 @@ int hibernation_snapshot(int platform_mode)
 }
 
 /**
- *     resume_target_kernel - prepare devices that need to be suspended with
- *     interrupts off, restore the contents of highmem that have not been
- *     restored yet from the image and run the low level code that will restore
- *     the remaining contents of memory and switch to the just restored target
- *     kernel.
+ * resume_target_kernel - Restore system state from a hibernation image.
+ * @platform_mode: Whether or not to use the platform driver.
+ *
+ * Execute device drivers' .freeze_noirq() callbacks, restore the contents of
+ * highmem that have not been restored yet from the image and run the low-level
+ * code that will restore the remaining contents of memory and switch to the
+ * just restored target kernel.
  */
-
 static int resume_target_kernel(bool platform_mode)
 {
        int error;
@@ -416,24 +417,26 @@ static int resume_target_kernel(bool platform_mode)
        if (error)
                goto Enable_irqs;
 
-       /* We'll ignore saved state, but this gets preempt count (etc) right */
        save_processor_state();
        error = restore_highmem();
        if (!error) {
                error = swsusp_arch_resume();
                /*
                 * The code below is only ever reached in case of a failure.
-                * Otherwise execution continues at place where
-                * swsusp_arch_suspend() was called
+                * Otherwise, execution continues at the place where
+                * swsusp_arch_suspend() was called.
                 */
                BUG_ON(!error);
-               /* This call to restore_highmem() undos the previous one */
+               /*
+                * This call to restore_highmem() reverts the changes made by
+                * the previous one.
+                */
                restore_highmem();
        }
        /*
         * The only reason why swsusp_arch_resume() can fail is memory being
         * very tight, so we have to free it as soon as we can to avoid
-        * subsequent failures
+        * subsequent failures.
         */
        swsusp_free();
        restore_processor_state();
@@ -456,14 +459,12 @@ static int resume_target_kernel(bool platform_mode)
 }
 
 /**
- *     hibernation_restore - quiesce devices and restore the hibernation
- *     snapshot image.  If successful, control returns in hibernation_snaphot()
- *     @platform_mode - if set, use the platform driver, if available, to
- *                      prepare the platform firmware for the transition.
+ * hibernation_restore - Quiesce devices and restore from a hibernation image.
+ * @platform_mode: If set, use platform driver to prepare for the transition.
  *
- *     Must be called with pm_mutex held
+ * This routine must be called with pm_mutex held.  If it is successful, control
+ * reappears in the restored target kernel in hibernation_snaphot().
  */
-
 int hibernation_restore(int platform_mode)
 {
        int error;
@@ -483,10 +484,8 @@ int hibernation_restore(int platform_mode)
 }
 
 /**
- *     hibernation_platform_enter - enter the hibernation state using the
- *     platform driver (if available)
+ * hibernation_platform_enter - Power off the system using the platform driver.
  */
-
 int hibernation_platform_enter(void)
 {
        int error;
@@ -557,12 +556,12 @@ int hibernation_platform_enter(void)
 }
 
 /**
- *     power_down - Shut the machine down for hibernation.
+ * power_down - Shut the machine down for hibernation.
  *
- *     Use the platform driver, if configured so; otherwise try
- *     to power off or reboot.
+ * Use the platform driver, if configured, to put the system into the sleep
+ * state corresponding to hibernation, or try to power it off or reboot,
+ * depending on the value of hibernation_mode.
  */
-
 static void power_down(void)
 {
        switch (hibernation_mode) {
@@ -599,9 +598,8 @@ static int prepare_processes(void)
 }
 
 /**
- *     hibernate - The granpappy of the built-in hibernation management
+ * hibernate - Carry out system hibernation, including saving the image.
  */
-
 int hibernate(void)
 {
        int error;
@@ -679,17 +677,20 @@ int hibernate(void)
 
 
 /**
- *     software_resume - Resume from a saved image.
+ * software_resume - Resume from a saved hibernation image.
  *
- *     Called as a late_initcall (so all devices are discovered and
- *     initialized), we call swsusp to see if we have a saved image or not.
- *     If so, we quiesce devices, the restore the saved image. We will
- *     return above (in hibernate() ) if everything goes well.
- *     Otherwise, we fail gracefully and return to the normally
- *     scheduled program.
+ * This routine is called as a late initcall, when all devices have been
+ * discovered and initialized already.
  *
+ * The image reading code is called to see if there is a hibernation image
+ * available for reading.  If that is the case, devices are quiesced and the
+ * contents of memory is restored from the saved image.
+ *
+ * If this is successful, control reappears in the restored target kernel in
+ * hibernation_snaphot() which returns to hibernate().  Otherwise, the routine
+ * attempts to recover gracefully and make the kernel return to the normal mode
+ * of operation.
  */
-
 static int software_resume(void)
 {
        int error;
@@ -819,21 +820,17 @@ static const char * const hibernation_modes[] = {
        [HIBERNATION_TESTPROC]  = "testproc",
 };
 
-/**
- *     disk - Control hibernation mode
- *
- *     Suspend-to-disk can be handled in several ways. We have a few options
- *     for putting the system to sleep - using the platform driver (e.g. ACPI
- *     or other hibernation_ops), powering off the system or rebooting the
- *     system (for testing) as well as the two test modes.
+/*
+ * /sys/power/disk - Control hibernation mode.
  *
- *     The system can support 'platform', and that is known a priori (and
- *     encoded by the presence of hibernation_ops). However, the user may
- *     choose 'shutdown' or 'reboot' as alternatives, as well as one fo the
- *     test modes, 'test' or 'testproc'.
+ * Hibernation can be handled in several ways.  There are a few different ways
+ * to put the system into the sleep state: using the platform driver (e.g. ACPI
+ * or other hibernation_ops), powering it off or rebooting it (for testing
+ * mostly), or using one of the two available test modes.
  *
- *     show() will display what the mode is currently set to.
- *     store() will accept one of
+ * The sysfs file /sys/power/disk provides an interface for selecting the
+ * hibernation mode to use.  Reading from this file causes the available modes
+ * to be printed.  There are 5 modes that can be supported:
  *
  *     'platform'
  *     'shutdown'
@@ -841,8 +838,14 @@ static const char * const hibernation_modes[] = {
  *     'test'
  *     'testproc'
  *
- *     It will only change to 'platform' if the system
- *     supports it (as determined by having hibernation_ops).
+ * If a platform hibernation driver is in use, 'platform' will be supported
+ * and will be used by default.  Otherwise, 'shutdown' will be used by default.
+ * The selected option (i.e. the one corresponding to the current value of
+ * hibernation_mode) is enclosed by a square bracket.
+ *
+ * To select a given hibernation mode it is necessary to write the mode's
+ * string representation (as returned by reading from /sys/power/disk) back
+ * into /sys/power/disk.
  */
 
 static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
@@ -875,7 +878,6 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
        return buf-start;
 }
 
-
 static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
                          const char *buf, size_t n)
 {
index 7d02d33be699f97d4956c76ea71b939bb0832d06..42ddbc6f0de6ffcf2d245dd9c8ec253c2780ffab 100644 (file)
@@ -113,8 +113,10 @@ static int snapshot_open(struct inode *inode, struct file *filp)
                if (error)
                        pm_notifier_call_chain(PM_POST_RESTORE);
        }
-       if (error)
+       if (error) {
+               free_basic_memory_bitmaps();
                atomic_inc(&snapshot_device_available);
+       }
        data->frozen = 0;
        data->ready = 0;
        data->platform_support = 0;
index da8ca817eae3b817d037f3f2d4b9666e52569b35..35185392173f5af5fc39fff30cadc115b92114e8 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/smp.h>
 #include <linux/security.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/syscalls.h>
 #include <linux/kexec.h>
 #include <linux/kdb.h>
@@ -167,46 +168,74 @@ void log_buf_kexec_setup(void)
 }
 #endif
 
+/* requested log_buf_len from kernel cmdline */
+static unsigned long __initdata new_log_buf_len;
+
+/* save requested log_buf_len since it's too early to process it */
 static int __init log_buf_len_setup(char *str)
 {
        unsigned size = memparse(str, &str);
-       unsigned long flags;
 
        if (size)
                size = roundup_pow_of_two(size);
-       if (size > log_buf_len) {
-               unsigned start, dest_idx, offset;
-               char *new_log_buf;
+       if (size > log_buf_len)
+               new_log_buf_len = size;
 
-               new_log_buf = alloc_bootmem(size);
-               if (!new_log_buf) {
-                       printk(KERN_WARNING "log_buf_len: allocation failed\n");
-                       goto out;
-               }
+       return 0;
+}
+early_param("log_buf_len", log_buf_len_setup);
 
-               spin_lock_irqsave(&logbuf_lock, flags);
-               log_buf_len = size;
-               log_buf = new_log_buf;
-
-               offset = start = min(con_start, log_start);
-               dest_idx = 0;
-               while (start != log_end) {
-                       log_buf[dest_idx] = __log_buf[start & (__LOG_BUF_LEN - 1)];
-                       start++;
-                       dest_idx++;
-               }
-               log_start -= offset;
-               con_start -= offset;
-               log_end -= offset;
-               spin_unlock_irqrestore(&logbuf_lock, flags);
+void __init setup_log_buf(int early)
+{
+       unsigned long flags;
+       unsigned start, dest_idx, offset;
+       char *new_log_buf;
+       int free;
+
+       if (!new_log_buf_len)
+               return;
+
+       if (early) {
+               unsigned long mem;
 
-               printk(KERN_NOTICE "log_buf_len: %d\n", log_buf_len);
+               mem = memblock_alloc(new_log_buf_len, PAGE_SIZE);
+               if (mem == MEMBLOCK_ERROR)
+                       return;
+               new_log_buf = __va(mem);
+       } else {
+               new_log_buf = alloc_bootmem_nopanic(new_log_buf_len);
        }
-out:
-       return 1;
-}
 
-__setup("log_buf_len=", log_buf_len_setup);
+       if (unlikely(!new_log_buf)) {
+               pr_err("log_buf_len: %ld bytes not available\n",
+                       new_log_buf_len);
+               return;
+       }
+
+       spin_lock_irqsave(&logbuf_lock, flags);
+       log_buf_len = new_log_buf_len;
+       log_buf = new_log_buf;
+       new_log_buf_len = 0;
+       free = __LOG_BUF_LEN - log_end;
+
+       offset = start = min(con_start, log_start);
+       dest_idx = 0;
+       while (start != log_end) {
+               unsigned log_idx_mask = start & (__LOG_BUF_LEN - 1);
+
+               log_buf[dest_idx] = __log_buf[log_idx_mask];
+               start++;
+               dest_idx++;
+       }
+       log_start -= offset;
+       con_start -= offset;
+       log_end -= offset;
+       spin_unlock_irqrestore(&logbuf_lock, flags);
+
+       pr_info("log_buf_len: %d\n", log_buf_len);
+       pr_info("early log buf free: %d(%d%%)\n",
+               free, (free * 100) / __LOG_BUF_LEN);
+}
 
 #ifdef CONFIG_BOOT_PRINTK_DELAY
 
index 14c9f87b9fc95d8eeb545b7fe29cccc171c9df47..961b389fe52fec5324910d5b85f6eb3b6749a43d 100644 (file)
@@ -303,14 +303,12 @@ static void profile_discard_flip_buffers(void)
        mutex_unlock(&profile_flip_mutex);
 }
 
-void profile_hits(int type, void *__pc, unsigned int nr_hits)
+static void do_profile_hits(int type, void *__pc, unsigned int nr_hits)
 {
        unsigned long primary, secondary, flags, pc = (unsigned long)__pc;
        int i, j, cpu;
        struct profile_hit *hits;
 
-       if (prof_on != type || !prof_buffer)
-               return;
        pc = min((pc - (unsigned long)_stext) >> prof_shift, prof_len - 1);
        i = primary = (pc & (NR_PROFILE_GRP - 1)) << PROFILE_GRPSHIFT;
        secondary = (~(pc << 1) & (NR_PROFILE_GRP - 1)) << PROFILE_GRPSHIFT;
@@ -417,16 +415,20 @@ out_free:
 #define profile_discard_flip_buffers() do { } while (0)
 #define profile_cpu_callback           NULL
 
-void profile_hits(int type, void *__pc, unsigned int nr_hits)
+static void do_profile_hits(int type, void *__pc, unsigned int nr_hits)
 {
        unsigned long pc;
-
-       if (prof_on != type || !prof_buffer)
-               return;
        pc = ((unsigned long)__pc - (unsigned long)_stext) >> prof_shift;
        atomic_add(nr_hits, &prof_buffer[min(pc, prof_len - 1)]);
 }
 #endif /* !CONFIG_SMP */
+
+void profile_hits(int type, void *__pc, unsigned int nr_hits)
+{
+       if (prof_on != type || !prof_buffer)
+               return;
+       do_profile_hits(type, __pc, nr_hits);
+}
 EXPORT_SYMBOL_GPL(profile_hits);
 
 void profile_tick(int type)
index 7a81fc0713442590c6643e411c77da127bc2520e..2df115790cd9e1ab6a1128603697ce5b6ed255d9 100644 (file)
@@ -562,7 +562,7 @@ static int ptrace_resume(struct task_struct *child, long request,
        }
 
        child->exit_code = data;
-       wake_up_process(child);
+       wake_up_state(child, __TASK_TRACED);
 
        return 0;
 }
index f07d2f03181a9b6c296a09e5e2869ea7c5844580..7e59ffb3d0ba487c0474270a476b25cbc96d2ac1 100644 (file)
@@ -36,7 +36,7 @@
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/nmi.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
 #include <linux/bitops.h>
 #include <linux/module.h>
 #include <linux/completion.h>
@@ -87,6 +87,8 @@ static struct rcu_state *rcu_state;
 int rcu_scheduler_active __read_mostly;
 EXPORT_SYMBOL_GPL(rcu_scheduler_active);
 
+#ifdef CONFIG_RCU_BOOST
+
 /*
  * Control variables for per-CPU and per-rcu_node kthreads.  These
  * handle all flavors of RCU.
@@ -95,12 +97,14 @@ static DEFINE_PER_CPU(struct task_struct *, rcu_cpu_kthread_task);
 DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_status);
 DEFINE_PER_CPU(int, rcu_cpu_kthread_cpu);
 DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_loops);
-static DEFINE_PER_CPU(wait_queue_head_t, rcu_cpu_wq);
 DEFINE_PER_CPU(char, rcu_cpu_has_work);
 static char rcu_kthreads_spawnable;
 
+#endif /* #ifdef CONFIG_RCU_BOOST */
+
 static void rcu_node_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu);
-static void invoke_rcu_cpu_kthread(void);
+static void invoke_rcu_core(void);
+static void invoke_rcu_callbacks(struct rcu_state *rsp, struct rcu_data *rdp);
 
 #define RCU_KTHREAD_PRIO 1     /* RT priority for per-CPU kthreads. */
 
@@ -163,7 +167,7 @@ EXPORT_SYMBOL_GPL(rcu_note_context_switch);
 #ifdef CONFIG_NO_HZ
 DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = {
        .dynticks_nesting = 1,
-       .dynticks = 1,
+       .dynticks = ATOMIC_INIT(1),
 };
 #endif /* #ifdef CONFIG_NO_HZ */
 
@@ -322,13 +326,25 @@ void rcu_enter_nohz(void)
        unsigned long flags;
        struct rcu_dynticks *rdtp;
 
-       smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */
        local_irq_save(flags);
        rdtp = &__get_cpu_var(rcu_dynticks);
-       rdtp->dynticks++;
-       rdtp->dynticks_nesting--;
-       WARN_ON_ONCE(rdtp->dynticks & 0x1);
+       if (--rdtp->dynticks_nesting) {
+               local_irq_restore(flags);
+               return;
+       }
+       /* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */
+       smp_mb__before_atomic_inc();  /* See above. */
+       atomic_inc(&rdtp->dynticks);
+       smp_mb__after_atomic_inc();  /* Force ordering with next sojourn. */
+       WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1);
        local_irq_restore(flags);
+
+       /* If the interrupt queued a callback, get out of dyntick mode. */
+       if (in_irq() &&
+           (__get_cpu_var(rcu_sched_data).nxtlist ||
+            __get_cpu_var(rcu_bh_data).nxtlist ||
+            rcu_preempt_needs_cpu(smp_processor_id())))
+               set_need_resched();
 }
 
 /*
@@ -344,11 +360,16 @@ void rcu_exit_nohz(void)
 
        local_irq_save(flags);
        rdtp = &__get_cpu_var(rcu_dynticks);
-       rdtp->dynticks++;
-       rdtp->dynticks_nesting++;
-       WARN_ON_ONCE(!(rdtp->dynticks & 0x1));
+       if (rdtp->dynticks_nesting++) {
+               local_irq_restore(flags);
+               return;
+       }
+       smp_mb__before_atomic_inc();  /* Force ordering w/previous sojourn. */
+       atomic_inc(&rdtp->dynticks);
+       /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */
+       smp_mb__after_atomic_inc();  /* See above. */
+       WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1));
        local_irq_restore(flags);
-       smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */
 }
 
 /**
@@ -362,11 +383,15 @@ void rcu_nmi_enter(void)
 {
        struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks);
 
-       if (rdtp->dynticks & 0x1)
+       if (rdtp->dynticks_nmi_nesting == 0 &&
+           (atomic_read(&rdtp->dynticks) & 0x1))
                return;
-       rdtp->dynticks_nmi++;
-       WARN_ON_ONCE(!(rdtp->dynticks_nmi & 0x1));
-       smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */
+       rdtp->dynticks_nmi_nesting++;
+       smp_mb__before_atomic_inc();  /* Force delay from prior write. */
+       atomic_inc(&rdtp->dynticks);
+       /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */
+       smp_mb__after_atomic_inc();  /* See above. */
+       WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1));
 }
 
 /**
@@ -380,11 +405,14 @@ void rcu_nmi_exit(void)
 {
        struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks);
 
-       if (rdtp->dynticks & 0x1)
+       if (rdtp->dynticks_nmi_nesting == 0 ||
+           --rdtp->dynticks_nmi_nesting != 0)
                return;
-       smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */
-       rdtp->dynticks_nmi++;
-       WARN_ON_ONCE(rdtp->dynticks_nmi & 0x1);
+       /* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */
+       smp_mb__before_atomic_inc();  /* See above. */
+       atomic_inc(&rdtp->dynticks);
+       smp_mb__after_atomic_inc();  /* Force delay to next write. */
+       WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1);
 }
 
 /**
@@ -395,13 +423,7 @@ void rcu_nmi_exit(void)
  */
 void rcu_irq_enter(void)
 {
-       struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks);
-
-       if (rdtp->dynticks_nesting++)
-               return;
-       rdtp->dynticks++;
-       WARN_ON_ONCE(!(rdtp->dynticks & 0x1));
-       smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */
+       rcu_exit_nohz();
 }
 
 /**
@@ -413,18 +435,7 @@ void rcu_irq_enter(void)
  */
 void rcu_irq_exit(void)
 {
-       struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks);
-
-       if (--rdtp->dynticks_nesting)
-               return;
-       smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */
-       rdtp->dynticks++;
-       WARN_ON_ONCE(rdtp->dynticks & 0x1);
-
-       /* If the interrupt queued a callback, get out of dyntick mode. */
-       if (__this_cpu_read(rcu_sched_data.nxtlist) ||
-           __this_cpu_read(rcu_bh_data.nxtlist))
-               set_need_resched();
+       rcu_enter_nohz();
 }
 
 #ifdef CONFIG_SMP
@@ -436,19 +447,8 @@ void rcu_irq_exit(void)
  */
 static int dyntick_save_progress_counter(struct rcu_data *rdp)
 {
-       int ret;
-       int snap;
-       int snap_nmi;
-
-       snap = rdp->dynticks->dynticks;
-       snap_nmi = rdp->dynticks->dynticks_nmi;
-       smp_mb();       /* Order sampling of snap with end of grace period. */
-       rdp->dynticks_snap = snap;
-       rdp->dynticks_nmi_snap = snap_nmi;
-       ret = ((snap & 0x1) == 0) && ((snap_nmi & 0x1) == 0);
-       if (ret)
-               rdp->dynticks_fqs++;
-       return ret;
+       rdp->dynticks_snap = atomic_add_return(0, &rdp->dynticks->dynticks);
+       return 0;
 }
 
 /*
@@ -459,16 +459,11 @@ static int dyntick_save_progress_counter(struct rcu_data *rdp)
  */
 static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
 {
-       long curr;
-       long curr_nmi;
-       long snap;
-       long snap_nmi;
+       unsigned long curr;
+       unsigned long snap;
 
-       curr = rdp->dynticks->dynticks;
-       snap = rdp->dynticks_snap;
-       curr_nmi = rdp->dynticks->dynticks_nmi;
-       snap_nmi = rdp->dynticks_nmi_snap;
-       smp_mb(); /* force ordering with cpu entering/leaving dynticks. */
+       curr = (unsigned long)atomic_add_return(0, &rdp->dynticks->dynticks);
+       snap = (unsigned long)rdp->dynticks_snap;
 
        /*
         * If the CPU passed through or entered a dynticks idle phase with
@@ -478,8 +473,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
         * read-side critical section that started before the beginning
         * of the current RCU grace period.
         */
-       if ((curr != snap || (curr & 0x1) == 0) &&
-           (curr_nmi != snap_nmi || (curr_nmi & 0x1) == 0)) {
+       if ((curr & 0x1) == 0 || ULONG_CMP_GE(curr, snap + 2)) {
                rdp->dynticks_fqs++;
                return 1;
        }
@@ -908,6 +902,12 @@ static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags)
        unsigned long gp_duration;
 
        WARN_ON_ONCE(!rcu_gp_in_progress(rsp));
+
+       /*
+        * Ensure that all grace-period and pre-grace-period activity
+        * is seen before the assignment to rsp->completed.
+        */
+       smp_mb(); /* See above block comment. */
        gp_duration = jiffies - rsp->gp_start;
        if (gp_duration > rsp->gp_max)
                rsp->gp_max = gp_duration;
@@ -1093,14 +1093,8 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp)
        int need_report = 0;
        struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
        struct rcu_node *rnp;
-       struct task_struct *t;
 
-       /* Stop the CPU's kthread. */
-       t = per_cpu(rcu_cpu_kthread_task, cpu);
-       if (t != NULL) {
-               per_cpu(rcu_cpu_kthread_task, cpu) = NULL;
-               kthread_stop(t);
-       }
+       rcu_stop_cpu_kthread(cpu);
 
        /* Exclude any attempts to start a new grace period. */
        raw_spin_lock_irqsave(&rsp->onofflock, flags);
@@ -1236,7 +1230,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
 
        /* Re-raise the RCU softirq if there are callbacks remaining. */
        if (cpu_has_callbacks_ready_to_invoke(rdp))
-               invoke_rcu_cpu_kthread();
+               invoke_rcu_core();
 }
 
 /*
@@ -1282,7 +1276,7 @@ void rcu_check_callbacks(int cpu, int user)
        }
        rcu_preempt_check_callbacks(cpu);
        if (rcu_pending(cpu))
-               invoke_rcu_cpu_kthread();
+               invoke_rcu_core();
 }
 
 #ifdef CONFIG_SMP
@@ -1447,33 +1441,20 @@ __rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp)
        }
 
        /* If there are callbacks ready, invoke them. */
-       rcu_do_batch(rsp, rdp);
+       if (cpu_has_callbacks_ready_to_invoke(rdp))
+               invoke_rcu_callbacks(rsp, rdp);
 }
 
 /*
  * Do softirq processing for the current CPU.
  */
-static void rcu_process_callbacks(void)
+static void rcu_process_callbacks(struct softirq_action *unused)
 {
-       /*
-        * Memory references from any prior RCU read-side critical sections
-        * executed by the interrupted code must be seen before any RCU
-        * grace-period manipulations below.
-        */
-       smp_mb(); /* See above block comment. */
-
        __rcu_process_callbacks(&rcu_sched_state,
                                &__get_cpu_var(rcu_sched_data));
        __rcu_process_callbacks(&rcu_bh_state, &__get_cpu_var(rcu_bh_data));
        rcu_preempt_process_callbacks();
 
-       /*
-        * Memory references from any later RCU read-side critical sections
-        * executed by the interrupted code must be seen after any RCU
-        * grace-period manipulations above.
-        */
-       smp_mb(); /* See above block comment. */
-
        /* If we are last CPU on way to dyntick-idle mode, accelerate it. */
        rcu_needs_cpu_flush();
 }
@@ -1484,341 +1465,20 @@ static void rcu_process_callbacks(void)
  * the current CPU with interrupts disabled, the rcu_cpu_kthread_task
  * cannot disappear out from under us.
  */
-static void invoke_rcu_cpu_kthread(void)
+static void invoke_rcu_callbacks(struct rcu_state *rsp, struct rcu_data *rdp)
 {
-       unsigned long flags;
-
-       local_irq_save(flags);
-       __this_cpu_write(rcu_cpu_has_work, 1);
-       if (__this_cpu_read(rcu_cpu_kthread_task) == NULL) {
-               local_irq_restore(flags);
+       if (likely(!rsp->boost)) {
+               rcu_do_batch(rsp, rdp);
                return;
        }
-       wake_up(&__get_cpu_var(rcu_cpu_wq));
-       local_irq_restore(flags);
-}
-
-/*
- * Wake up the specified per-rcu_node-structure kthread.
- * Because the per-rcu_node kthreads are immortal, we don't need
- * to do anything to keep them alive.
- */
-static void invoke_rcu_node_kthread(struct rcu_node *rnp)
-{
-       struct task_struct *t;
-
-       t = rnp->node_kthread_task;
-       if (t != NULL)
-               wake_up_process(t);
+       invoke_rcu_callbacks_kthread();
 }
 
-/*
- * Set the specified CPU's kthread to run RT or not, as specified by
- * the to_rt argument.  The CPU-hotplug locks are held, so the task
- * is not going away.
- */
-static void rcu_cpu_kthread_setrt(int cpu, int to_rt)
+static void invoke_rcu_core(void)
 {
-       int policy;
-       struct sched_param sp;
-       struct task_struct *t;
-
-       t = per_cpu(rcu_cpu_kthread_task, cpu);
-       if (t == NULL)
-               return;
-       if (to_rt) {
-               policy = SCHED_FIFO;
-               sp.sched_priority = RCU_KTHREAD_PRIO;
-       } else {
-               policy = SCHED_NORMAL;
-               sp.sched_priority = 0;
-       }
-       sched_setscheduler_nocheck(t, policy, &sp);
+       raise_softirq(RCU_SOFTIRQ);
 }
 
-/*
- * Timer handler to initiate the waking up of per-CPU kthreads that
- * have yielded the CPU due to excess numbers of RCU callbacks.
- * We wake up the per-rcu_node kthread, which in turn will wake up
- * the booster kthread.
- */
-static void rcu_cpu_kthread_timer(unsigned long arg)
-{
-       unsigned long flags;
-       struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, arg);
-       struct rcu_node *rnp = rdp->mynode;
-
-       raw_spin_lock_irqsave(&rnp->lock, flags);
-       rnp->wakemask |= rdp->grpmask;
-       raw_spin_unlock_irqrestore(&rnp->lock, flags);
-       invoke_rcu_node_kthread(rnp);
-}
-
-/*
- * Drop to non-real-time priority and yield, but only after posting a
- * timer that will cause us to regain our real-time priority if we
- * remain preempted.  Either way, we restore our real-time priority
- * before returning.
- */
-static void rcu_yield(void (*f)(unsigned long), unsigned long arg)
-{
-       struct sched_param sp;
-       struct timer_list yield_timer;
-
-       setup_timer_on_stack(&yield_timer, f, arg);
-       mod_timer(&yield_timer, jiffies + 2);
-       sp.sched_priority = 0;
-       sched_setscheduler_nocheck(current, SCHED_NORMAL, &sp);
-       set_user_nice(current, 19);
-       schedule();
-       sp.sched_priority = RCU_KTHREAD_PRIO;
-       sched_setscheduler_nocheck(current, SCHED_FIFO, &sp);
-       del_timer(&yield_timer);
-}
-
-/*
- * Handle cases where the rcu_cpu_kthread() ends up on the wrong CPU.
- * This can happen while the corresponding CPU is either coming online
- * or going offline.  We cannot wait until the CPU is fully online
- * before starting the kthread, because the various notifier functions
- * can wait for RCU grace periods.  So we park rcu_cpu_kthread() until
- * the corresponding CPU is online.
- *
- * Return 1 if the kthread needs to stop, 0 otherwise.
- *
- * Caller must disable bh.  This function can momentarily enable it.
- */
-static int rcu_cpu_kthread_should_stop(int cpu)
-{
-       while (cpu_is_offline(cpu) ||
-              !cpumask_equal(&current->cpus_allowed, cpumask_of(cpu)) ||
-              smp_processor_id() != cpu) {
-               if (kthread_should_stop())
-                       return 1;
-               per_cpu(rcu_cpu_kthread_status, cpu) = RCU_KTHREAD_OFFCPU;
-               per_cpu(rcu_cpu_kthread_cpu, cpu) = raw_smp_processor_id();
-               local_bh_enable();
-               schedule_timeout_uninterruptible(1);
-               if (!cpumask_equal(&current->cpus_allowed, cpumask_of(cpu)))
-                       set_cpus_allowed_ptr(current, cpumask_of(cpu));
-               local_bh_disable();
-       }
-       per_cpu(rcu_cpu_kthread_cpu, cpu) = cpu;
-       return 0;
-}
-
-/*
- * Per-CPU kernel thread that invokes RCU callbacks.  This replaces the
- * earlier RCU softirq.
- */
-static int rcu_cpu_kthread(void *arg)
-{
-       int cpu = (int)(long)arg;
-       unsigned long flags;
-       int spincnt = 0;
-       unsigned int *statusp = &per_cpu(rcu_cpu_kthread_status, cpu);
-       wait_queue_head_t *wqp = &per_cpu(rcu_cpu_wq, cpu);
-       char work;
-       char *workp = &per_cpu(rcu_cpu_has_work, cpu);
-
-       for (;;) {
-               *statusp = RCU_KTHREAD_WAITING;
-               wait_event_interruptible(*wqp,
-                                        *workp != 0 || kthread_should_stop());
-               local_bh_disable();
-               if (rcu_cpu_kthread_should_stop(cpu)) {
-                       local_bh_enable();
-                       break;
-               }
-               *statusp = RCU_KTHREAD_RUNNING;
-               per_cpu(rcu_cpu_kthread_loops, cpu)++;
-               local_irq_save(flags);
-               work = *workp;
-               *workp = 0;
-               local_irq_restore(flags);
-               if (work)
-                       rcu_process_callbacks();
-               local_bh_enable();
-               if (*workp != 0)
-                       spincnt++;
-               else
-                       spincnt = 0;
-               if (spincnt > 10) {
-                       *statusp = RCU_KTHREAD_YIELDING;
-                       rcu_yield(rcu_cpu_kthread_timer, (unsigned long)cpu);
-                       spincnt = 0;
-               }
-       }
-       *statusp = RCU_KTHREAD_STOPPED;
-       return 0;
-}
-
-/*
- * Spawn a per-CPU kthread, setting up affinity and priority.
- * Because the CPU hotplug lock is held, no other CPU will be attempting
- * to manipulate rcu_cpu_kthread_task.  There might be another CPU
- * attempting to access it during boot, but the locking in kthread_bind()
- * will enforce sufficient ordering.
- */
-static int __cpuinit rcu_spawn_one_cpu_kthread(int cpu)
-{
-       struct sched_param sp;
-       struct task_struct *t;
-
-       if (!rcu_kthreads_spawnable ||
-           per_cpu(rcu_cpu_kthread_task, cpu) != NULL)
-               return 0;
-       t = kthread_create(rcu_cpu_kthread, (void *)(long)cpu, "rcuc%d", cpu);
-       if (IS_ERR(t))
-               return PTR_ERR(t);
-       kthread_bind(t, cpu);
-       per_cpu(rcu_cpu_kthread_cpu, cpu) = cpu;
-       WARN_ON_ONCE(per_cpu(rcu_cpu_kthread_task, cpu) != NULL);
-       per_cpu(rcu_cpu_kthread_task, cpu) = t;
-       wake_up_process(t);
-       sp.sched_priority = RCU_KTHREAD_PRIO;
-       sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
-       return 0;
-}
-
-/*
- * Per-rcu_node kthread, which is in charge of waking up the per-CPU
- * kthreads when needed.  We ignore requests to wake up kthreads
- * for offline CPUs, which is OK because force_quiescent_state()
- * takes care of this case.
- */
-static int rcu_node_kthread(void *arg)
-{
-       int cpu;
-       unsigned long flags;
-       unsigned long mask;
-       struct rcu_node *rnp = (struct rcu_node *)arg;
-       struct sched_param sp;
-       struct task_struct *t;
-
-       for (;;) {
-               rnp->node_kthread_status = RCU_KTHREAD_WAITING;
-               wait_event_interruptible(rnp->node_wq, rnp->wakemask != 0);
-               rnp->node_kthread_status = RCU_KTHREAD_RUNNING;
-               raw_spin_lock_irqsave(&rnp->lock, flags);
-               mask = rnp->wakemask;
-               rnp->wakemask = 0;
-               rcu_initiate_boost(rnp, flags); /* releases rnp->lock. */
-               for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask >>= 1) {
-                       if ((mask & 0x1) == 0)
-                               continue;
-                       preempt_disable();
-                       t = per_cpu(rcu_cpu_kthread_task, cpu);
-                       if (!cpu_online(cpu) || t == NULL) {
-                               preempt_enable();
-                               continue;
-                       }
-                       per_cpu(rcu_cpu_has_work, cpu) = 1;
-                       sp.sched_priority = RCU_KTHREAD_PRIO;
-                       sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
-                       preempt_enable();
-               }
-       }
-       /* NOTREACHED */
-       rnp->node_kthread_status = RCU_KTHREAD_STOPPED;
-       return 0;
-}
-
-/*
- * Set the per-rcu_node kthread's affinity to cover all CPUs that are
- * served by the rcu_node in question.  The CPU hotplug lock is still
- * held, so the value of rnp->qsmaskinit will be stable.
- *
- * We don't include outgoingcpu in the affinity set, use -1 if there is
- * no outgoing CPU.  If there are no CPUs left in the affinity set,
- * this function allows the kthread to execute on any CPU.
- */
-static void rcu_node_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
-{
-       cpumask_var_t cm;
-       int cpu;
-       unsigned long mask = rnp->qsmaskinit;
-
-       if (rnp->node_kthread_task == NULL)
-               return;
-       if (!alloc_cpumask_var(&cm, GFP_KERNEL))
-               return;
-       cpumask_clear(cm);
-       for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask >>= 1)
-               if ((mask & 0x1) && cpu != outgoingcpu)
-                       cpumask_set_cpu(cpu, cm);
-       if (cpumask_weight(cm) == 0) {
-               cpumask_setall(cm);
-               for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++)
-                       cpumask_clear_cpu(cpu, cm);
-               WARN_ON_ONCE(cpumask_weight(cm) == 0);
-       }
-       set_cpus_allowed_ptr(rnp->node_kthread_task, cm);
-       rcu_boost_kthread_setaffinity(rnp, cm);
-       free_cpumask_var(cm);
-}
-
-/*
- * Spawn a per-rcu_node kthread, setting priority and affinity.
- * Called during boot before online/offline can happen, or, if
- * during runtime, with the main CPU-hotplug locks held.  So only
- * one of these can be executing at a time.
- */
-static int __cpuinit rcu_spawn_one_node_kthread(struct rcu_state *rsp,
-                                               struct rcu_node *rnp)
-{
-       unsigned long flags;
-       int rnp_index = rnp - &rsp->node[0];
-       struct sched_param sp;
-       struct task_struct *t;
-
-       if (!rcu_kthreads_spawnable ||
-           rnp->qsmaskinit == 0)
-               return 0;
-       if (rnp->node_kthread_task == NULL) {
-               t = kthread_create(rcu_node_kthread, (void *)rnp,
-                                  "rcun%d", rnp_index);
-               if (IS_ERR(t))
-                       return PTR_ERR(t);
-               raw_spin_lock_irqsave(&rnp->lock, flags);
-               rnp->node_kthread_task = t;
-               raw_spin_unlock_irqrestore(&rnp->lock, flags);
-               wake_up_process(t);
-               sp.sched_priority = 99;
-               sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
-       }
-       return rcu_spawn_one_boost_kthread(rsp, rnp, rnp_index);
-}
-
-/*
- * Spawn all kthreads -- called as soon as the scheduler is running.
- */
-static int __init rcu_spawn_kthreads(void)
-{
-       int cpu;
-       struct rcu_node *rnp;
-
-       rcu_kthreads_spawnable = 1;
-       for_each_possible_cpu(cpu) {
-               init_waitqueue_head(&per_cpu(rcu_cpu_wq, cpu));
-               per_cpu(rcu_cpu_has_work, cpu) = 0;
-               if (cpu_online(cpu))
-                       (void)rcu_spawn_one_cpu_kthread(cpu);
-       }
-       rnp = rcu_get_root(rcu_state);
-       init_waitqueue_head(&rnp->node_wq);
-       rcu_init_boost_waitqueue(rnp);
-       (void)rcu_spawn_one_node_kthread(rcu_state, rnp);
-       if (NUM_RCU_NODES > 1)
-               rcu_for_each_leaf_node(rcu_state, rnp) {
-                       init_waitqueue_head(&rnp->node_wq);
-                       rcu_init_boost_waitqueue(rnp);
-                       (void)rcu_spawn_one_node_kthread(rcu_state, rnp);
-               }
-       return 0;
-}
-early_initcall(rcu_spawn_kthreads);
-
 static void
 __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
           struct rcu_state *rsp)
@@ -2218,26 +1878,13 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible)
        raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
 }
 
-static void __cpuinit rcu_online_cpu(int cpu)
+static void __cpuinit rcu_prepare_cpu(int cpu)
 {
        rcu_init_percpu_data(cpu, &rcu_sched_state, 0);
        rcu_init_percpu_data(cpu, &rcu_bh_state, 0);
        rcu_preempt_init_percpu_data(cpu);
 }
 
-static void __cpuinit rcu_online_kthreads(int cpu)
-{
-       struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, cpu);
-       struct rcu_node *rnp = rdp->mynode;
-
-       /* Fire up the incoming CPU's kthread and leaf rcu_node kthread. */
-       if (rcu_kthreads_spawnable) {
-               (void)rcu_spawn_one_cpu_kthread(cpu);
-               if (rnp->node_kthread_task == NULL)
-                       (void)rcu_spawn_one_node_kthread(rcu_state, rnp);
-       }
-}
-
 /*
  * Handle CPU online/offline notification events.
  */
@@ -2251,8 +1898,8 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
        switch (action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               rcu_online_cpu(cpu);
-               rcu_online_kthreads(cpu);
+               rcu_prepare_cpu(cpu);
+               rcu_prepare_kthreads(cpu);
                break;
        case CPU_ONLINE:
        case CPU_DOWN_FAILED:
@@ -2402,6 +2049,7 @@ void __init rcu_init(void)
        rcu_init_one(&rcu_sched_state, &rcu_sched_data);
        rcu_init_one(&rcu_bh_state, &rcu_bh_data);
        __rcu_init_preempt();
+        open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
 
        /*
         * We don't need protection against CPU-hotplug here because
index 257664815d5d9cdfd645d08f6bd2e873e10a2cff..01b2ccda26fbf82880cc1d4a50bf9f2877e91bba 100644 (file)
  * Dynticks per-CPU state.
  */
 struct rcu_dynticks {
-       int dynticks_nesting;   /* Track nesting level, sort of. */
-       int dynticks;           /* Even value for dynticks-idle, else odd. */
-       int dynticks_nmi;       /* Even value for either dynticks-idle or */
-                               /*  not in nmi handler, else odd.  So this */
-                               /*  remains even for nmi from irq handler. */
+       int dynticks_nesting;   /* Track irq/process nesting level. */
+       int dynticks_nmi_nesting; /* Track NMI nesting level. */
+       atomic_t dynticks;      /* Even value for dynticks-idle, else odd. */
 };
 
 /* RCU's kthread states for tracing. */
@@ -121,7 +119,9 @@ struct rcu_node {
                                /*  elements that need to drain to allow the */
                                /*  current expedited grace period to */
                                /*  complete (only for TREE_PREEMPT_RCU). */
-       unsigned long wakemask; /* CPUs whose kthread needs to be awakened. */
+       atomic_t wakemask;      /* CPUs whose kthread needs to be awakened. */
+                               /*  Since this has meaning only for leaf */
+                               /*  rcu_node structures, 32 bits suffices. */
        unsigned long qsmaskinit;
                                /* Per-GP initial value for qsmask & expmask. */
        unsigned long grpmask;  /* Mask to apply to parent qsmask. */
@@ -159,9 +159,6 @@ struct rcu_node {
        struct task_struct *boost_kthread_task;
                                /* kthread that takes care of priority */
                                /*  boosting for this rcu_node structure. */
-       wait_queue_head_t boost_wq;
-                               /* Wait queue on which to park the boost */
-                               /*  kthread. */
        unsigned int boost_kthread_status;
                                /* State of boost_kthread_task for tracing. */
        unsigned long n_tasks_boosted;
@@ -188,9 +185,6 @@ struct rcu_node {
                                /* kthread that takes care of this rcu_node */
                                /*  structure, for example, awakening the */
                                /*  per-CPU kthreads as needed. */
-       wait_queue_head_t node_wq;
-                               /* Wait queue on which to park the per-node */
-                               /*  kthread. */
        unsigned int node_kthread_status;
                                /* State of node_kthread_task for tracing. */
 } ____cacheline_internodealigned_in_smp;
@@ -284,7 +278,6 @@ struct rcu_data {
        /* 3) dynticks interface. */
        struct rcu_dynticks *dynticks;  /* Shared per-CPU dynticks state. */
        int dynticks_snap;              /* Per-GP tracking for dynticks. */
-       int dynticks_nmi_snap;          /* Per-GP tracking for dynticks_nmi. */
 #endif /* #ifdef CONFIG_NO_HZ */
 
        /* 4) reasons this CPU needed to be kicked by force_quiescent_state */
@@ -337,6 +330,16 @@ struct rcu_data {
                                                /*  scheduling clock irq */
                                                /*  before ratting on them. */
 
+#define rcu_wait(cond)                                                 \
+do {                                                                   \
+       for (;;) {                                                      \
+               set_current_state(TASK_INTERRUPTIBLE);                  \
+               if (cond)                                               \
+                       break;                                          \
+               schedule();                                             \
+       }                                                               \
+       __set_current_state(TASK_RUNNING);                              \
+} while (0)
 
 /*
  * RCU global state, including node hierarchy.  This hierarchy is
@@ -366,6 +369,7 @@ struct rcu_state {
                                                /*  period because */
                                                /*  force_quiescent_state() */
                                                /*  was running. */
+       u8      boost;                          /* Subject to priority boost. */
        unsigned long gpnum;                    /* Current gp number. */
        unsigned long completed;                /* # of last completed gp. */
 
@@ -423,6 +427,7 @@ static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp);
 #ifdef CONFIG_HOTPLUG_CPU
 static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp,
                                      unsigned long flags);
+static void rcu_stop_cpu_kthread(int cpu);
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
 static void rcu_print_detail_task_stall(struct rcu_state *rsp);
 static void rcu_print_task_stall(struct rcu_node *rnp);
@@ -446,13 +451,20 @@ static void __cpuinit rcu_preempt_init_percpu_data(int cpu);
 static void rcu_preempt_send_cbs_to_online(void);
 static void __init __rcu_init_preempt(void);
 static void rcu_needs_cpu_flush(void);
-static void __init rcu_init_boost_waitqueue(struct rcu_node *rnp);
 static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags);
+static void rcu_preempt_boost_start_gp(struct rcu_node *rnp);
+static void invoke_rcu_callbacks_kthread(void);
+#ifdef CONFIG_RCU_BOOST
+static void rcu_preempt_do_callbacks(void);
 static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp,
                                          cpumask_var_t cm);
-static void rcu_preempt_boost_start_gp(struct rcu_node *rnp);
 static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
                                                 struct rcu_node *rnp,
                                                 int rnp_index);
+static void invoke_rcu_node_kthread(struct rcu_node *rnp);
+static void rcu_yield(void (*f)(unsigned long), unsigned long arg);
+#endif /* #ifdef CONFIG_RCU_BOOST */
+static void rcu_cpu_kthread_setrt(int cpu, int to_rt);
+static void __cpuinit rcu_prepare_kthreads(int cpu);
 
 #endif /* #ifndef RCU_TREE_NONCORE */
index 3f6559a5f5cd7911fac44ac500b670e125e73157..14dc7dd0090220f717f83f666fb2a30a32f66143 100644 (file)
@@ -602,6 +602,15 @@ static void rcu_preempt_process_callbacks(void)
                                &__get_cpu_var(rcu_preempt_data));
 }
 
+#ifdef CONFIG_RCU_BOOST
+
+static void rcu_preempt_do_callbacks(void)
+{
+       rcu_do_batch(&rcu_preempt_state, &__get_cpu_var(rcu_preempt_data));
+}
+
+#endif /* #ifdef CONFIG_RCU_BOOST */
+
 /*
  * Queue a preemptible-RCU callback for invocation after a grace period.
  */
@@ -1196,8 +1205,7 @@ static int rcu_boost_kthread(void *arg)
 
        for (;;) {
                rnp->boost_kthread_status = RCU_KTHREAD_WAITING;
-               wait_event_interruptible(rnp->boost_wq, rnp->boost_tasks ||
-                                                       rnp->exp_tasks);
+               rcu_wait(rnp->boost_tasks || rnp->exp_tasks);
                rnp->boost_kthread_status = RCU_KTHREAD_RUNNING;
                more2boost = rcu_boost(rnp);
                if (more2boost)
@@ -1249,6 +1257,23 @@ static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags)
        }
 }
 
+/*
+ * Wake up the per-CPU kthread to invoke RCU callbacks.
+ */
+static void invoke_rcu_callbacks_kthread(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       __this_cpu_write(rcu_cpu_has_work, 1);
+       if (__this_cpu_read(rcu_cpu_kthread_task) == NULL) {
+               local_irq_restore(flags);
+               return;
+       }
+       wake_up_process(__this_cpu_read(rcu_cpu_kthread_task));
+       local_irq_restore(flags);
+}
+
 /*
  * Set the affinity of the boost kthread.  The CPU-hotplug locks are
  * held, so no one should be messing with the existence of the boost
@@ -1274,14 +1299,6 @@ static void rcu_preempt_boost_start_gp(struct rcu_node *rnp)
        rnp->boost_time = jiffies + RCU_BOOST_DELAY_JIFFIES;
 }
 
-/*
- * Initialize the RCU-boost waitqueue.
- */
-static void __init rcu_init_boost_waitqueue(struct rcu_node *rnp)
-{
-       init_waitqueue_head(&rnp->boost_wq);
-}
-
 /*
  * Create an RCU-boost kthread for the specified node if one does not
  * already exist.  We only create this kthread for preemptible RCU.
@@ -1297,6 +1314,7 @@ static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
 
        if (&rcu_preempt_state != rsp)
                return 0;
+       rsp->boost = 1;
        if (rnp->boost_kthread_task != NULL)
                return 0;
        t = kthread_create(rcu_boost_kthread, (void *)rnp,
@@ -1306,12 +1324,376 @@ static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
        raw_spin_lock_irqsave(&rnp->lock, flags);
        rnp->boost_kthread_task = t;
        raw_spin_unlock_irqrestore(&rnp->lock, flags);
-       wake_up_process(t);
        sp.sched_priority = RCU_KTHREAD_PRIO;
        sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
+       wake_up_process(t); /* get to TASK_INTERRUPTIBLE quickly. */
        return 0;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+
+/*
+ * Stop the RCU's per-CPU kthread when its CPU goes offline,.
+ */
+static void rcu_stop_cpu_kthread(int cpu)
+{
+       struct task_struct *t;
+
+       /* Stop the CPU's kthread. */
+       t = per_cpu(rcu_cpu_kthread_task, cpu);
+       if (t != NULL) {
+               per_cpu(rcu_cpu_kthread_task, cpu) = NULL;
+               kthread_stop(t);
+       }
+}
+
+#endif /* #ifdef CONFIG_HOTPLUG_CPU */
+
+static void rcu_kthread_do_work(void)
+{
+       rcu_do_batch(&rcu_sched_state, &__get_cpu_var(rcu_sched_data));
+       rcu_do_batch(&rcu_bh_state, &__get_cpu_var(rcu_bh_data));
+       rcu_preempt_do_callbacks();
+}
+
+/*
+ * Wake up the specified per-rcu_node-structure kthread.
+ * Because the per-rcu_node kthreads are immortal, we don't need
+ * to do anything to keep them alive.
+ */
+static void invoke_rcu_node_kthread(struct rcu_node *rnp)
+{
+       struct task_struct *t;
+
+       t = rnp->node_kthread_task;
+       if (t != NULL)
+               wake_up_process(t);
+}
+
+/*
+ * Set the specified CPU's kthread to run RT or not, as specified by
+ * the to_rt argument.  The CPU-hotplug locks are held, so the task
+ * is not going away.
+ */
+static void rcu_cpu_kthread_setrt(int cpu, int to_rt)
+{
+       int policy;
+       struct sched_param sp;
+       struct task_struct *t;
+
+       t = per_cpu(rcu_cpu_kthread_task, cpu);
+       if (t == NULL)
+               return;
+       if (to_rt) {
+               policy = SCHED_FIFO;
+               sp.sched_priority = RCU_KTHREAD_PRIO;
+       } else {
+               policy = SCHED_NORMAL;
+               sp.sched_priority = 0;
+       }
+       sched_setscheduler_nocheck(t, policy, &sp);
+}
+
+/*
+ * Timer handler to initiate the waking up of per-CPU kthreads that
+ * have yielded the CPU due to excess numbers of RCU callbacks.
+ * We wake up the per-rcu_node kthread, which in turn will wake up
+ * the booster kthread.
+ */
+static void rcu_cpu_kthread_timer(unsigned long arg)
+{
+       struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, arg);
+       struct rcu_node *rnp = rdp->mynode;
+
+       atomic_or(rdp->grpmask, &rnp->wakemask);
+       invoke_rcu_node_kthread(rnp);
+}
+
+/*
+ * Drop to non-real-time priority and yield, but only after posting a
+ * timer that will cause us to regain our real-time priority if we
+ * remain preempted.  Either way, we restore our real-time priority
+ * before returning.
+ */
+static void rcu_yield(void (*f)(unsigned long), unsigned long arg)
+{
+       struct sched_param sp;
+       struct timer_list yield_timer;
+
+       setup_timer_on_stack(&yield_timer, f, arg);
+       mod_timer(&yield_timer, jiffies + 2);
+       sp.sched_priority = 0;
+       sched_setscheduler_nocheck(current, SCHED_NORMAL, &sp);
+       set_user_nice(current, 19);
+       schedule();
+       sp.sched_priority = RCU_KTHREAD_PRIO;
+       sched_setscheduler_nocheck(current, SCHED_FIFO, &sp);
+       del_timer(&yield_timer);
+}
+
+/*
+ * Handle cases where the rcu_cpu_kthread() ends up on the wrong CPU.
+ * This can happen while the corresponding CPU is either coming online
+ * or going offline.  We cannot wait until the CPU is fully online
+ * before starting the kthread, because the various notifier functions
+ * can wait for RCU grace periods.  So we park rcu_cpu_kthread() until
+ * the corresponding CPU is online.
+ *
+ * Return 1 if the kthread needs to stop, 0 otherwise.
+ *
+ * Caller must disable bh.  This function can momentarily enable it.
+ */
+static int rcu_cpu_kthread_should_stop(int cpu)
+{
+       while (cpu_is_offline(cpu) ||
+              !cpumask_equal(&current->cpus_allowed, cpumask_of(cpu)) ||
+              smp_processor_id() != cpu) {
+               if (kthread_should_stop())
+                       return 1;
+               per_cpu(rcu_cpu_kthread_status, cpu) = RCU_KTHREAD_OFFCPU;
+               per_cpu(rcu_cpu_kthread_cpu, cpu) = raw_smp_processor_id();
+               local_bh_enable();
+               schedule_timeout_uninterruptible(1);
+               if (!cpumask_equal(&current->cpus_allowed, cpumask_of(cpu)))
+                       set_cpus_allowed_ptr(current, cpumask_of(cpu));
+               local_bh_disable();
+       }
+       per_cpu(rcu_cpu_kthread_cpu, cpu) = cpu;
+       return 0;
+}
+
+/*
+ * Per-CPU kernel thread that invokes RCU callbacks.  This replaces the
+ * earlier RCU softirq.
+ */
+static int rcu_cpu_kthread(void *arg)
+{
+       int cpu = (int)(long)arg;
+       unsigned long flags;
+       int spincnt = 0;
+       unsigned int *statusp = &per_cpu(rcu_cpu_kthread_status, cpu);
+       char work;
+       char *workp = &per_cpu(rcu_cpu_has_work, cpu);
+
+       for (;;) {
+               *statusp = RCU_KTHREAD_WAITING;
+               rcu_wait(*workp != 0 || kthread_should_stop());
+               local_bh_disable();
+               if (rcu_cpu_kthread_should_stop(cpu)) {
+                       local_bh_enable();
+                       break;
+               }
+               *statusp = RCU_KTHREAD_RUNNING;
+               per_cpu(rcu_cpu_kthread_loops, cpu)++;
+               local_irq_save(flags);
+               work = *workp;
+               *workp = 0;
+               local_irq_restore(flags);
+               if (work)
+                       rcu_kthread_do_work();
+               local_bh_enable();
+               if (*workp != 0)
+                       spincnt++;
+               else
+                       spincnt = 0;
+               if (spincnt > 10) {
+                       *statusp = RCU_KTHREAD_YIELDING;
+                       rcu_yield(rcu_cpu_kthread_timer, (unsigned long)cpu);
+                       spincnt = 0;
+               }
+       }
+       *statusp = RCU_KTHREAD_STOPPED;
+       return 0;
+}
+
+/*
+ * Spawn a per-CPU kthread, setting up affinity and priority.
+ * Because the CPU hotplug lock is held, no other CPU will be attempting
+ * to manipulate rcu_cpu_kthread_task.  There might be another CPU
+ * attempting to access it during boot, but the locking in kthread_bind()
+ * will enforce sufficient ordering.
+ *
+ * Please note that we cannot simply refuse to wake up the per-CPU
+ * kthread because kthreads are created in TASK_UNINTERRUPTIBLE state,
+ * which can result in softlockup complaints if the task ends up being
+ * idle for more than a couple of minutes.
+ *
+ * However, please note also that we cannot bind the per-CPU kthread to its
+ * CPU until that CPU is fully online.  We also cannot wait until the
+ * CPU is fully online before we create its per-CPU kthread, as this would
+ * deadlock the system when CPU notifiers tried waiting for grace
+ * periods.  So we bind the per-CPU kthread to its CPU only if the CPU
+ * is online.  If its CPU is not yet fully online, then the code in
+ * rcu_cpu_kthread() will wait until it is fully online, and then do
+ * the binding.
+ */
+static int __cpuinit rcu_spawn_one_cpu_kthread(int cpu)
+{
+       struct sched_param sp;
+       struct task_struct *t;
+
+       if (!rcu_kthreads_spawnable ||
+           per_cpu(rcu_cpu_kthread_task, cpu) != NULL)
+               return 0;
+       t = kthread_create(rcu_cpu_kthread, (void *)(long)cpu, "rcuc%d", cpu);
+       if (IS_ERR(t))
+               return PTR_ERR(t);
+       if (cpu_online(cpu))
+               kthread_bind(t, cpu);
+       per_cpu(rcu_cpu_kthread_cpu, cpu) = cpu;
+       WARN_ON_ONCE(per_cpu(rcu_cpu_kthread_task, cpu) != NULL);
+       sp.sched_priority = RCU_KTHREAD_PRIO;
+       sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
+       per_cpu(rcu_cpu_kthread_task, cpu) = t;
+       wake_up_process(t); /* Get to TASK_INTERRUPTIBLE quickly. */
+       return 0;
+}
+
+/*
+ * Per-rcu_node kthread, which is in charge of waking up the per-CPU
+ * kthreads when needed.  We ignore requests to wake up kthreads
+ * for offline CPUs, which is OK because force_quiescent_state()
+ * takes care of this case.
+ */
+static int rcu_node_kthread(void *arg)
+{
+       int cpu;
+       unsigned long flags;
+       unsigned long mask;
+       struct rcu_node *rnp = (struct rcu_node *)arg;
+       struct sched_param sp;
+       struct task_struct *t;
+
+       for (;;) {
+               rnp->node_kthread_status = RCU_KTHREAD_WAITING;
+               rcu_wait(atomic_read(&rnp->wakemask) != 0);
+               rnp->node_kthread_status = RCU_KTHREAD_RUNNING;
+               raw_spin_lock_irqsave(&rnp->lock, flags);
+               mask = atomic_xchg(&rnp->wakemask, 0);
+               rcu_initiate_boost(rnp, flags); /* releases rnp->lock. */
+               for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask >>= 1) {
+                       if ((mask & 0x1) == 0)
+                               continue;
+                       preempt_disable();
+                       t = per_cpu(rcu_cpu_kthread_task, cpu);
+                       if (!cpu_online(cpu) || t == NULL) {
+                               preempt_enable();
+                               continue;
+                       }
+                       per_cpu(rcu_cpu_has_work, cpu) = 1;
+                       sp.sched_priority = RCU_KTHREAD_PRIO;
+                       sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
+                       preempt_enable();
+               }
+       }
+       /* NOTREACHED */
+       rnp->node_kthread_status = RCU_KTHREAD_STOPPED;
+       return 0;
+}
+
+/*
+ * Set the per-rcu_node kthread's affinity to cover all CPUs that are
+ * served by the rcu_node in question.  The CPU hotplug lock is still
+ * held, so the value of rnp->qsmaskinit will be stable.
+ *
+ * We don't include outgoingcpu in the affinity set, use -1 if there is
+ * no outgoing CPU.  If there are no CPUs left in the affinity set,
+ * this function allows the kthread to execute on any CPU.
+ */
+static void rcu_node_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
+{
+       cpumask_var_t cm;
+       int cpu;
+       unsigned long mask = rnp->qsmaskinit;
+
+       if (rnp->node_kthread_task == NULL)
+               return;
+       if (!alloc_cpumask_var(&cm, GFP_KERNEL))
+               return;
+       cpumask_clear(cm);
+       for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask >>= 1)
+               if ((mask & 0x1) && cpu != outgoingcpu)
+                       cpumask_set_cpu(cpu, cm);
+       if (cpumask_weight(cm) == 0) {
+               cpumask_setall(cm);
+               for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++)
+                       cpumask_clear_cpu(cpu, cm);
+               WARN_ON_ONCE(cpumask_weight(cm) == 0);
+       }
+       set_cpus_allowed_ptr(rnp->node_kthread_task, cm);
+       rcu_boost_kthread_setaffinity(rnp, cm);
+       free_cpumask_var(cm);
+}
+
+/*
+ * Spawn a per-rcu_node kthread, setting priority and affinity.
+ * Called during boot before online/offline can happen, or, if
+ * during runtime, with the main CPU-hotplug locks held.  So only
+ * one of these can be executing at a time.
+ */
+static int __cpuinit rcu_spawn_one_node_kthread(struct rcu_state *rsp,
+                                               struct rcu_node *rnp)
+{
+       unsigned long flags;
+       int rnp_index = rnp - &rsp->node[0];
+       struct sched_param sp;
+       struct task_struct *t;
+
+       if (!rcu_kthreads_spawnable ||
+           rnp->qsmaskinit == 0)
+               return 0;
+       if (rnp->node_kthread_task == NULL) {
+               t = kthread_create(rcu_node_kthread, (void *)rnp,
+                                  "rcun%d", rnp_index);
+               if (IS_ERR(t))
+                       return PTR_ERR(t);
+               raw_spin_lock_irqsave(&rnp->lock, flags);
+               rnp->node_kthread_task = t;
+               raw_spin_unlock_irqrestore(&rnp->lock, flags);
+               sp.sched_priority = 99;
+               sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
+               wake_up_process(t); /* get to TASK_INTERRUPTIBLE quickly. */
+       }
+       return rcu_spawn_one_boost_kthread(rsp, rnp, rnp_index);
+}
+
+/*
+ * Spawn all kthreads -- called as soon as the scheduler is running.
+ */
+static int __init rcu_spawn_kthreads(void)
+{
+       int cpu;
+       struct rcu_node *rnp;
+
+       rcu_kthreads_spawnable = 1;
+       for_each_possible_cpu(cpu) {
+               per_cpu(rcu_cpu_has_work, cpu) = 0;
+               if (cpu_online(cpu))
+                       (void)rcu_spawn_one_cpu_kthread(cpu);
+       }
+       rnp = rcu_get_root(rcu_state);
+       (void)rcu_spawn_one_node_kthread(rcu_state, rnp);
+       if (NUM_RCU_NODES > 1) {
+               rcu_for_each_leaf_node(rcu_state, rnp)
+                       (void)rcu_spawn_one_node_kthread(rcu_state, rnp);
+       }
+       return 0;
+}
+early_initcall(rcu_spawn_kthreads);
+
+static void __cpuinit rcu_prepare_kthreads(int cpu)
+{
+       struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, cpu);
+       struct rcu_node *rnp = rdp->mynode;
+
+       /* Fire up the incoming CPU's kthread and leaf rcu_node kthread. */
+       if (rcu_kthreads_spawnable) {
+               (void)rcu_spawn_one_cpu_kthread(cpu);
+               if (rnp->node_kthread_task == NULL)
+                       (void)rcu_spawn_one_node_kthread(rcu_state, rnp);
+       }
+}
+
 #else /* #ifdef CONFIG_RCU_BOOST */
 
 static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags)
@@ -1319,24 +1701,33 @@ static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags)
        raw_spin_unlock_irqrestore(&rnp->lock, flags);
 }
 
-static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp,
-                                         cpumask_var_t cm)
+static void invoke_rcu_callbacks_kthread(void)
 {
+       WARN_ON_ONCE(1);
 }
 
 static void rcu_preempt_boost_start_gp(struct rcu_node *rnp)
 {
 }
 
-static void __init rcu_init_boost_waitqueue(struct rcu_node *rnp)
+#ifdef CONFIG_HOTPLUG_CPU
+
+static void rcu_stop_cpu_kthread(int cpu)
 {
 }
 
-static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
-                                                struct rcu_node *rnp,
-                                                int rnp_index)
+#endif /* #ifdef CONFIG_HOTPLUG_CPU */
+
+static void rcu_node_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
+{
+}
+
+static void rcu_cpu_kthread_setrt(int cpu, int to_rt)
+{
+}
+
+static void __cpuinit rcu_prepare_kthreads(int cpu)
 {
-       return 0;
 }
 
 #endif /* #else #ifdef CONFIG_RCU_BOOST */
@@ -1513,14 +1904,13 @@ static DEFINE_PER_CPU(unsigned long, rcu_dyntick_holdoff);
  *
  * Because it is not legal to invoke rcu_process_callbacks() with irqs
  * disabled, we do one pass of force_quiescent_state(), then do a
- * invoke_rcu_cpu_kthread() to cause rcu_process_callbacks() to be invoked
+ * invoke_rcu_core() to cause rcu_process_callbacks() to be invoked
  * later.  The per-cpu rcu_dyntick_drain variable controls the sequencing.
  */
 int rcu_needs_cpu(int cpu)
 {
        int c = 0;
        int snap;
-       int snap_nmi;
        int thatcpu;
 
        /* Check for being in the holdoff period. */
@@ -1531,10 +1921,10 @@ int rcu_needs_cpu(int cpu)
        for_each_online_cpu(thatcpu) {
                if (thatcpu == cpu)
                        continue;
-               snap = per_cpu(rcu_dynticks, thatcpu).dynticks;
-               snap_nmi = per_cpu(rcu_dynticks, thatcpu).dynticks_nmi;
+               snap = atomic_add_return(0, &per_cpu(rcu_dynticks,
+                                                    thatcpu).dynticks);
                smp_mb(); /* Order sampling of snap with end of grace period. */
-               if (((snap & 0x1) != 0) || ((snap_nmi & 0x1) != 0)) {
+               if ((snap & 0x1) != 0) {
                        per_cpu(rcu_dyntick_drain, cpu) = 0;
                        per_cpu(rcu_dyntick_holdoff, cpu) = jiffies - 1;
                        return rcu_needs_cpu_quick_check(cpu);
@@ -1565,7 +1955,7 @@ int rcu_needs_cpu(int cpu)
 
        /* If RCU callbacks are still pending, RCU still needs this CPU. */
        if (c)
-               invoke_rcu_cpu_kthread();
+               invoke_rcu_core();
        return c;
 }
 
index aa0fd72b4bc714ae3b8f4c41f48f712513e8d6f3..4e144876dc68208b89931518c2d64d1433def061 100644 (file)
@@ -46,6 +46,8 @@
 #define RCU_TREE_NONCORE
 #include "rcutree.h"
 
+#ifdef CONFIG_RCU_BOOST
+
 DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_status);
 DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_cpu);
 DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_loops);
@@ -58,6 +60,8 @@ static char convert_kthread_status(unsigned int kthread_status)
        return "SRWOY"[kthread_status];
 }
 
+#endif /* #ifdef CONFIG_RCU_BOOST */
+
 static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
 {
        if (!rdp->beenonline)
@@ -69,14 +73,14 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
                   rdp->passed_quiesc, rdp->passed_quiesc_completed,
                   rdp->qs_pending);
 #ifdef CONFIG_NO_HZ
-       seq_printf(m, " dt=%d/%d dn=%d df=%lu",
-                  rdp->dynticks->dynticks,
+       seq_printf(m, " dt=%d/%d/%d df=%lu",
+                  atomic_read(&rdp->dynticks->dynticks),
                   rdp->dynticks->dynticks_nesting,
-                  rdp->dynticks->dynticks_nmi,
+                  rdp->dynticks->dynticks_nmi_nesting,
                   rdp->dynticks_fqs);
 #endif /* #ifdef CONFIG_NO_HZ */
        seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi);
-       seq_printf(m, " ql=%ld qs=%c%c%c%c kt=%d/%c/%d ktl=%x b=%ld",
+       seq_printf(m, " ql=%ld qs=%c%c%c%c",
                   rdp->qlen,
                   ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] !=
                        rdp->nxttail[RCU_NEXT_TAIL]],
@@ -84,13 +88,16 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
                        rdp->nxttail[RCU_NEXT_READY_TAIL]],
                   ".W"[rdp->nxttail[RCU_DONE_TAIL] !=
                        rdp->nxttail[RCU_WAIT_TAIL]],
-                  ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]],
+                  ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]]);
+#ifdef CONFIG_RCU_BOOST
+       seq_printf(m, " kt=%d/%c/%d ktl=%x",
                   per_cpu(rcu_cpu_has_work, rdp->cpu),
                   convert_kthread_status(per_cpu(rcu_cpu_kthread_status,
                                          rdp->cpu)),
                   per_cpu(rcu_cpu_kthread_cpu, rdp->cpu),
-                  per_cpu(rcu_cpu_kthread_loops, rdp->cpu) & 0xffff,
-                  rdp->blimit);
+                  per_cpu(rcu_cpu_kthread_loops, rdp->cpu) & 0xffff);
+#endif /* #ifdef CONFIG_RCU_BOOST */
+       seq_printf(m, " b=%ld", rdp->blimit);
        seq_printf(m, " ci=%lu co=%lu ca=%lu\n",
                   rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted);
 }
@@ -141,24 +148,27 @@ static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp)
                   rdp->qs_pending);
 #ifdef CONFIG_NO_HZ
        seq_printf(m, ",%d,%d,%d,%lu",
-                  rdp->dynticks->dynticks,
+                  atomic_read(&rdp->dynticks->dynticks),
                   rdp->dynticks->dynticks_nesting,
-                  rdp->dynticks->dynticks_nmi,
+                  rdp->dynticks->dynticks_nmi_nesting,
                   rdp->dynticks_fqs);
 #endif /* #ifdef CONFIG_NO_HZ */
        seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi);
-       seq_printf(m, ",%ld,\"%c%c%c%c\",%d,\"%c\",%ld", rdp->qlen,
+       seq_printf(m, ",%ld,\"%c%c%c%c\"", rdp->qlen,
                   ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] !=
                        rdp->nxttail[RCU_NEXT_TAIL]],
                   ".R"[rdp->nxttail[RCU_WAIT_TAIL] !=
                        rdp->nxttail[RCU_NEXT_READY_TAIL]],
                   ".W"[rdp->nxttail[RCU_DONE_TAIL] !=
                        rdp->nxttail[RCU_WAIT_TAIL]],
-                  ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]],
+                  ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]]);
+#ifdef CONFIG_RCU_BOOST
+       seq_printf(m, ",%d,\"%c\"",
                   per_cpu(rcu_cpu_has_work, rdp->cpu),
                   convert_kthread_status(per_cpu(rcu_cpu_kthread_status,
-                                         rdp->cpu)),
-                  rdp->blimit);
+                                         rdp->cpu)));
+#endif /* #ifdef CONFIG_RCU_BOOST */
+       seq_printf(m, ",%ld", rdp->blimit);
        seq_printf(m, ",%lu,%lu,%lu\n",
                   rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted);
 }
@@ -167,9 +177,13 @@ static int show_rcudata_csv(struct seq_file *m, void *unused)
 {
        seq_puts(m, "\"CPU\",\"Online?\",\"c\",\"g\",\"pq\",\"pqc\",\"pq\",");
 #ifdef CONFIG_NO_HZ
-       seq_puts(m, "\"dt\",\"dt nesting\",\"dn\",\"df\",");
+       seq_puts(m, "\"dt\",\"dt nesting\",\"dt NMI nesting\",\"df\",");
 #endif /* #ifdef CONFIG_NO_HZ */
-       seq_puts(m, "\"of\",\"ri\",\"ql\",\"b\",\"ci\",\"co\",\"ca\"\n");
+       seq_puts(m, "\"of\",\"ri\",\"ql\",\"qs\"");
+#ifdef CONFIG_RCU_BOOST
+       seq_puts(m, "\"kt\",\"ktl\"");
+#endif /* #ifdef CONFIG_RCU_BOOST */
+       seq_puts(m, ",\"b\",\"ci\",\"co\",\"ca\"\n");
 #ifdef CONFIG_TREE_PREEMPT_RCU
        seq_puts(m, "\"rcu_preempt:\"\n");
        PRINT_RCU_DATA(rcu_preempt_data, print_one_rcu_data_csv, m);
index 2d12893b8b0f0788dacb310f988cefd7d6d15440..3f2e502d609bb7957e10b4ec6aa647c9b3069c6e 100644 (file)
@@ -605,10 +605,10 @@ static inline int cpu_of(struct rq *rq)
 /*
  * Return the group to which this tasks belongs.
  *
- * We use task_subsys_state_check() and extend the RCU verification
- * with lockdep_is_held(&p->pi_lock) because cpu_cgroup_attach()
- * holds that lock for each task it moves into the cgroup. Therefore
- * by holding that lock, we pin the task to the current cgroup.
+ * We use task_subsys_state_check() and extend the RCU verification with
+ * pi->lock and rq->lock because cpu_cgroup_attach() holds those locks for each
+ * task it moves into the cgroup. Therefore by holding either of those locks,
+ * we pin the task to the current cgroup.
  */
 static inline struct task_group *task_group(struct task_struct *p)
 {
@@ -616,7 +616,8 @@ static inline struct task_group *task_group(struct task_struct *p)
        struct cgroup_subsys_state *css;
 
        css = task_subsys_state_check(p, cpu_cgroup_subsys_id,
-                       lockdep_is_held(&p->pi_lock));
+                       lockdep_is_held(&p->pi_lock) ||
+                       lockdep_is_held(&task_rq(p)->lock));
        tg = container_of(css, struct task_group, css);
 
        return autogroup_task_group(p, tg);
@@ -2200,6 +2201,16 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
                        !(task_thread_info(p)->preempt_count & PREEMPT_ACTIVE));
 
 #ifdef CONFIG_LOCKDEP
+       /*
+        * The caller should hold either p->pi_lock or rq->lock, when changing
+        * a task's CPU. ->pi_lock for waking tasks, rq->lock for runnable tasks.
+        *
+        * sched_move_task() holds both and thus holding either pins the cgroup,
+        * see set_task_rq().
+        *
+        * Furthermore, all task_rq users should acquire both locks, see
+        * task_rq_lock().
+        */
        WARN_ON_ONCE(debug_locks && !(lockdep_is_held(&p->pi_lock) ||
                                      lockdep_is_held(&task_rq(p)->lock)));
 #endif
@@ -2447,6 +2458,10 @@ ttwu_stat(struct task_struct *p, int cpu, int wake_flags)
                }
                rcu_read_unlock();
        }
+
+       if (wake_flags & WF_MIGRATED)
+               schedstat_inc(p, se.statistics.nr_wakeups_migrate);
+
 #endif /* CONFIG_SMP */
 
        schedstat_inc(rq, ttwu_count);
@@ -2455,9 +2470,6 @@ ttwu_stat(struct task_struct *p, int cpu, int wake_flags)
        if (wake_flags & WF_SYNC)
                schedstat_inc(p, se.statistics.nr_wakeups_sync);
 
-       if (cpu != task_cpu(p))
-               schedstat_inc(p, se.statistics.nr_wakeups_migrate);
-
 #endif /* CONFIG_SCHEDSTATS */
 }
 
@@ -2573,7 +2585,26 @@ static void ttwu_queue_remote(struct task_struct *p, int cpu)
        if (!next)
                smp_send_reschedule(cpu);
 }
-#endif
+
+#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
+static int ttwu_activate_remote(struct task_struct *p, int wake_flags)
+{
+       struct rq *rq;
+       int ret = 0;
+
+       rq = __task_rq_lock(p);
+       if (p->on_cpu) {
+               ttwu_activate(rq, p, ENQUEUE_WAKEUP);
+               ttwu_do_wakeup(rq, p, wake_flags);
+               ret = 1;
+       }
+       __task_rq_unlock(rq);
+
+       return ret;
+
+}
+#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */
+#endif /* CONFIG_SMP */
 
 static void ttwu_queue(struct task_struct *p, int cpu)
 {
@@ -2581,6 +2612,7 @@ static void ttwu_queue(struct task_struct *p, int cpu)
 
 #if defined(CONFIG_SMP)
        if (sched_feat(TTWU_QUEUE) && cpu != smp_processor_id()) {
+               sched_clock_cpu(cpu); /* sync clocks x-cpu */
                ttwu_queue_remote(p, cpu);
                return;
        }
@@ -2631,17 +2663,17 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
        while (p->on_cpu) {
 #ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
                /*
-                * If called from interrupt context we could have landed in the
-                * middle of schedule(), in this case we should take care not
-                * to spin on ->on_cpu if p is current, since that would
-                * deadlock.
+                * In case the architecture enables interrupts in
+                * context_switch(), we cannot busy wait, since that
+                * would lead to deadlocks when an interrupt hits and
+                * tries to wake up @prev. So bail and do a complete
+                * remote wakeup.
                 */
-               if (p == current) {
-                       ttwu_queue(p, cpu);
+               if (ttwu_activate_remote(p, wake_flags))
                        goto stat;
-               }
-#endif
+#else
                cpu_relax();
+#endif
        }
        /*
         * Pairs with the smp_wmb() in finish_lock_switch().
@@ -2655,8 +2687,10 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
                p->sched_class->task_waking(p);
 
        cpu = select_task_rq(p, SD_BALANCE_WAKE, wake_flags);
-       if (task_cpu(p) != cpu)
+       if (task_cpu(p) != cpu) {
+               wake_flags |= WF_MIGRATED;
                set_task_cpu(p, cpu);
+       }
 #endif /* CONFIG_SMP */
 
        ttwu_queue(p, cpu);
@@ -5841,7 +5875,7 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
        idle->state = TASK_RUNNING;
        idle->se.exec_start = sched_clock();
 
-       cpumask_copy(&idle->cpus_allowed, cpumask_of(cpu));
+       do_set_cpus_allowed(idle, cpumask_of(cpu));
        /*
         * We're having a chicken and egg problem, even though we are
         * holding rq->lock, the cpu isn't yet set to this cpu so the
@@ -5929,6 +5963,16 @@ static inline void sched_init_granularity(void)
 }
 
 #ifdef CONFIG_SMP
+void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask)
+{
+       if (p->sched_class && p->sched_class->set_cpus_allowed)
+               p->sched_class->set_cpus_allowed(p, new_mask);
+       else {
+               cpumask_copy(&p->cpus_allowed, new_mask);
+               p->rt.nr_cpus_allowed = cpumask_weight(new_mask);
+       }
+}
+
 /*
  * This is how migration works:
  *
@@ -5974,12 +6018,7 @@ int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask)
                goto out;
        }
 
-       if (p->sched_class->set_cpus_allowed)
-               p->sched_class->set_cpus_allowed(p, new_mask);
-       else {
-               cpumask_copy(&p->cpus_allowed, new_mask);
-               p->rt.nr_cpus_allowed = cpumask_weight(new_mask);
-       }
+       do_set_cpus_allowed(p, new_mask);
 
        /* Can the task run on the task's current CPU? If so, we're done */
        if (cpumask_test_cpu(task_cpu(p), new_mask))
@@ -8764,42 +8803,10 @@ cpu_cgroup_can_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
        return 0;
 }
 
-static int
-cpu_cgroup_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
-                     struct task_struct *tsk, bool threadgroup)
-{
-       int retval = cpu_cgroup_can_attach_task(cgrp, tsk);
-       if (retval)
-               return retval;
-       if (threadgroup) {
-               struct task_struct *c;
-               rcu_read_lock();
-               list_for_each_entry_rcu(c, &tsk->thread_group, thread_group) {
-                       retval = cpu_cgroup_can_attach_task(cgrp, c);
-                       if (retval) {
-                               rcu_read_unlock();
-                               return retval;
-                       }
-               }
-               rcu_read_unlock();
-       }
-       return 0;
-}
-
 static void
-cpu_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
-                 struct cgroup *old_cont, struct task_struct *tsk,
-                 bool threadgroup)
+cpu_cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
 {
        sched_move_task(tsk);
-       if (threadgroup) {
-               struct task_struct *c;
-               rcu_read_lock();
-               list_for_each_entry_rcu(c, &tsk->thread_group, thread_group) {
-                       sched_move_task(c);
-               }
-               rcu_read_unlock();
-       }
 }
 
 static void
@@ -8887,8 +8894,8 @@ struct cgroup_subsys cpu_cgroup_subsys = {
        .name           = "cpu",
        .create         = cpu_cgroup_create,
        .destroy        = cpu_cgroup_destroy,
-       .can_attach     = cpu_cgroup_can_attach,
-       .attach         = cpu_cgroup_attach,
+       .can_attach_task = cpu_cgroup_can_attach_task,
+       .attach_task    = cpu_cgroup_attach_task,
        .exit           = cpu_cgroup_exit,
        .populate       = cpu_cgroup_populate,
        .subsys_id      = cpu_cgroup_subsys_id,
index e32a9b70ee9c716149d57a33f298495d368b292c..433491c2dc8f5c9952655de72958c7019dadd57f 100644 (file)
@@ -1076,8 +1076,6 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
        se->on_rq = 0;
        update_cfs_load(cfs_rq, 0);
        account_entity_dequeue(cfs_rq, se);
-       update_min_vruntime(cfs_rq);
-       update_cfs_shares(cfs_rq);
 
        /*
         * Normalize the entity after updating the min_vruntime because the
@@ -1086,6 +1084,9 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
         */
        if (!(flags & DEQUEUE_SLEEP))
                se->vruntime -= cfs_rq->min_vruntime;
+
+       update_min_vruntime(cfs_rq);
+       update_cfs_shares(cfs_rq);
 }
 
 /*
index 64b2a37c07d0839ffe771ecaf4fa46cb73647750..10d018212bab8b1ad2f53e1ed388a4bbd56d4656 100644 (file)
@@ -1096,7 +1096,7 @@ static void check_preempt_curr_rt(struct rq *rq, struct task_struct *p, int flag
         * to move current somewhere else, making room for our non-migratable
         * task.
         */
-       if (p->prio == rq->curr->prio && !need_resched())
+       if (p->prio == rq->curr->prio && !test_tsk_need_resched(rq->curr))
                check_preempt_equal_prio(rq, p);
 #endif
 }
@@ -1239,6 +1239,10 @@ static int find_lowest_rq(struct task_struct *task)
        int this_cpu = smp_processor_id();
        int cpu      = task_cpu(task);
 
+       /* Make sure the mask is initialized first */
+       if (unlikely(!lowest_mask))
+               return -1;
+
        if (task->rt.nr_cpus_allowed == 1)
                return -1; /* No other targets possible */
 
@@ -1263,6 +1267,7 @@ static int find_lowest_rq(struct task_struct *task)
        if (!cpumask_test_cpu(this_cpu, lowest_mask))
                this_cpu = -1; /* Skip this_cpu opt if not among lowest */
 
+       rcu_read_lock();
        for_each_domain(cpu, sd) {
                if (sd->flags & SD_WAKE_AFFINE) {
                        int best_cpu;
@@ -1272,15 +1277,20 @@ static int find_lowest_rq(struct task_struct *task)
                         * remote processor.
                         */
                        if (this_cpu != -1 &&
-                           cpumask_test_cpu(this_cpu, sched_domain_span(sd)))
+                           cpumask_test_cpu(this_cpu, sched_domain_span(sd))) {
+                               rcu_read_unlock();
                                return this_cpu;
+                       }
 
                        best_cpu = cpumask_first_and(lowest_mask,
                                                     sched_domain_span(sd));
-                       if (best_cpu < nr_cpu_ids)
+                       if (best_cpu < nr_cpu_ids) {
+                               rcu_read_unlock();
                                return best_cpu;
+                       }
                }
        }
+       rcu_read_unlock();
 
        /*
         * And finally, if there were no matches within the domains
index 48ddf431db0ee4da60025e364e0b2a64e459508f..331e01bcd0260c9fc9db3269ba1416a83c355039 100644 (file)
@@ -37,7 +37,7 @@ static int show_schedstat(struct seq_file *seq, void *v)
 
 #ifdef CONFIG_SMP
                /* domain-specific stats */
-               preempt_disable();
+               rcu_read_lock();
                for_each_domain(cpu, sd) {
                        enum cpu_idle_type itype;
 
@@ -64,7 +64,7 @@ static int show_schedstat(struct seq_file *seq, void *v)
                            sd->ttwu_wake_remote, sd->ttwu_move_affine,
                            sd->ttwu_move_balance);
                }
-               preempt_enable();
+               rcu_read_unlock();
 #endif
        }
        kfree(mask_str);
index ad5e818baacc43fb5e4046926bf52dde55acacfa..ff7678603328b3ba5e00c74dc9fd08bcbf113987 100644 (file)
@@ -2365,7 +2365,7 @@ int sigprocmask(int how, sigset_t *set, sigset_t *oldset)
 /**
  *  sys_rt_sigprocmask - change the list of currently blocked signals
  *  @how: whether to add, remove, or set signals
- *  @set: stores pending signals
+ *  @nset: stores pending signals
  *  @oset: previous value of signal mask if non-null
  *  @sigsetsize: size of sigset_t type
  */
@@ -3023,8 +3023,10 @@ SYSCALL_DEFINE2(signal, int, sig, __sighandler_t, handler)
 
 SYSCALL_DEFINE0(pause)
 {
-       current->state = TASK_INTERRUPTIBLE;
-       schedule();
+       while (!signal_pending(current)) {
+               current->state = TASK_INTERRUPTIBLE;
+               schedule();
+       }
        return -ERESTARTNOHAND;
 }
 
index 73a1951935581f48915d77e8409a3049b78de8df..fb67dfa8394edc70174a51fd93b72965a3929b71 100644 (file)
@@ -74,7 +74,7 @@ static struct notifier_block __cpuinitdata hotplug_cfd_notifier = {
        .notifier_call          = hotplug_cfd,
 };
 
-static int __cpuinit init_call_single_data(void)
+void __init call_function_init(void)
 {
        void *cpu = (void *)(long)smp_processor_id();
        int i;
@@ -88,10 +88,7 @@ static int __cpuinit init_call_single_data(void)
 
        hotplug_cfd(&hotplug_cfd_notifier, CPU_UP_PREPARE, cpu);
        register_cpu_notifier(&hotplug_cfd_notifier);
-
-       return 0;
 }
-early_initcall(init_call_single_data);
 
 /*
  * csd_lock/csd_unlock used to serialize access to per-cpu csd resources
index 13960170cad4d91f0ec00dba8e0132d64e7c68fd..40cf63ddd4b3d740d2620ddbf1fa245830b1d703 100644 (file)
@@ -58,7 +58,7 @@ DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
 
 char *softirq_to_name[NR_SOFTIRQS] = {
        "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "BLOCK_IOPOLL",
-       "TASKLET", "SCHED", "HRTIMER"
+       "TASKLET", "SCHED", "HRTIMER", "RCU"
 };
 
 /*
index 3dd0c46fa3bbd68d1d4774e23e0189c54508fd0b..f175d98bd3557c912e15f65fcd98be713f400f29 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/kprobes.h>
 #include <linux/pipe_fs_i.h>
 #include <linux/oom.h>
+#include <linux/kmod.h>
 
 #include <asm/uaccess.h>
 #include <asm/processor.h>
@@ -615,6 +616,11 @@ static struct ctl_table kern_table[] = {
                .mode           = 0555,
                .child          = random_table,
        },
+       {
+               .procname       = "usermodehelper",
+               .mode           = 0555,
+               .child          = usermodehelper_table,
+       },
        {
                .procname       = "overflowuid",
                .data           = &overflowuid,
@@ -932,6 +938,12 @@ static struct ctl_table kern_table[] = {
        },
 #endif
 #ifdef CONFIG_PERF_EVENTS
+       /*
+        * User-space scripts rely on the existence of this file
+        * as a feature check for perf_events being enabled.
+        *
+        * So it's an ABI, do not remove!
+        */
        {
                .procname       = "perf_event_paranoid",
                .data           = &sysctl_perf_event_paranoid,
@@ -1500,7 +1512,7 @@ static struct ctl_table fs_table[] = {
 
 static struct ctl_table debug_table[] = {
 #if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) || \
-    defined(CONFIG_S390)
+    defined(CONFIG_S390) || defined(CONFIG_TILE)
        {
                .procname       = "exception-trace",
                .data           = &show_unhandled_signals,
index 2d966244ea60d0a8dcf963e1052b2dbfbfcac76d..59f369f98a04311f5bfa49d01e706d4b12ca97c4 100644 (file)
@@ -42,15 +42,75 @@ static struct alarm_base {
        clockid_t               base_clockid;
 } alarm_bases[ALARM_NUMTYPE];
 
+/* freezer delta & lock used to handle clock_nanosleep triggered wakeups */
+static ktime_t freezer_delta;
+static DEFINE_SPINLOCK(freezer_delta_lock);
+
 #ifdef CONFIG_RTC_CLASS
 /* rtc timer and device for setting alarm wakeups at suspend */
 static struct rtc_timer                rtctimer;
 static struct rtc_device       *rtcdev;
-#endif
+static DEFINE_SPINLOCK(rtcdev_lock);
 
-/* freezer delta & lock used to handle clock_nanosleep triggered wakeups */
-static ktime_t freezer_delta;
-static DEFINE_SPINLOCK(freezer_delta_lock);
+/**
+ * has_wakealarm - check rtc device has wakealarm ability
+ * @dev: current device
+ * @name_ptr: name to be returned
+ *
+ * This helper function checks to see if the rtc device can wake
+ * from suspend.
+ */
+static int has_wakealarm(struct device *dev, void *name_ptr)
+{
+       struct rtc_device *candidate = to_rtc_device(dev);
+
+       if (!candidate->ops->set_alarm)
+               return 0;
+       if (!device_may_wakeup(candidate->dev.parent))
+               return 0;
+
+       *(const char **)name_ptr = dev_name(dev);
+       return 1;
+}
+
+/**
+ * alarmtimer_get_rtcdev - Return selected rtcdevice
+ *
+ * This function returns the rtc device to use for wakealarms.
+ * If one has not already been chosen, it checks to see if a
+ * functional rtc device is available.
+ */
+static struct rtc_device *alarmtimer_get_rtcdev(void)
+{
+       struct device *dev;
+       char *str;
+       unsigned long flags;
+       struct rtc_device *ret;
+
+       spin_lock_irqsave(&rtcdev_lock, flags);
+       if (!rtcdev) {
+               /* Find an rtc device and init the rtc_timer */
+               dev = class_find_device(rtc_class, NULL, &str, has_wakealarm);
+               /* If we have a device then str is valid. See has_wakealarm() */
+               if (dev) {
+                       rtcdev = rtc_class_open(str);
+                       /*
+                        * Drop the reference we got in class_find_device,
+                        * rtc_open takes its own.
+                        */
+                       put_device(dev);
+                       rtc_timer_init(&rtctimer, NULL, NULL);
+               }
+       }
+       ret = rtcdev;
+       spin_unlock_irqrestore(&rtcdev_lock, flags);
+
+       return ret;
+}
+#else
+#define alarmtimer_get_rtcdev() (0)
+#define rtcdev (0)
+#endif
 
 
 /**
@@ -166,6 +226,7 @@ static int alarmtimer_suspend(struct device *dev)
        struct rtc_time tm;
        ktime_t min, now;
        unsigned long flags;
+       struct rtc_device *rtc;
        int i;
 
        spin_lock_irqsave(&freezer_delta_lock, flags);
@@ -173,8 +234,9 @@ static int alarmtimer_suspend(struct device *dev)
        freezer_delta = ktime_set(0, 0);
        spin_unlock_irqrestore(&freezer_delta_lock, flags);
 
+       rtc = rtcdev;
        /* If we have no rtcdev, just return */
-       if (!rtcdev)
+       if (!rtc)
                return 0;
 
        /* Find the soonest timer to expire*/
@@ -199,12 +261,12 @@ static int alarmtimer_suspend(struct device *dev)
        WARN_ON(min.tv64 < NSEC_PER_SEC);
 
        /* Setup an rtc timer to fire that far in the future */
-       rtc_timer_cancel(rtcdev, &rtctimer);
-       rtc_read_time(rtcdev, &tm);
+       rtc_timer_cancel(rtc, &rtctimer);
+       rtc_read_time(rtc, &tm);
        now = rtc_tm_to_ktime(tm);
        now = ktime_add(now, min);
 
-       rtc_timer_start(rtcdev, &rtctimer, now, ktime_set(0, 0));
+       rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0));
 
        return 0;
 }
@@ -322,6 +384,9 @@ static int alarm_clock_getres(const clockid_t which_clock, struct timespec *tp)
 {
        clockid_t baseid = alarm_bases[clock2alarm(which_clock)].base_clockid;
 
+       if (!alarmtimer_get_rtcdev())
+               return -ENOTSUPP;
+
        return hrtimer_get_res(baseid, tp);
 }
 
@@ -336,6 +401,9 @@ static int alarm_clock_get(clockid_t which_clock, struct timespec *tp)
 {
        struct alarm_base *base = &alarm_bases[clock2alarm(which_clock)];
 
+       if (!alarmtimer_get_rtcdev())
+               return -ENOTSUPP;
+
        *tp = ktime_to_timespec(base->gettime());
        return 0;
 }
@@ -351,6 +419,9 @@ static int alarm_timer_create(struct k_itimer *new_timer)
        enum  alarmtimer_type type;
        struct alarm_base *base;
 
+       if (!alarmtimer_get_rtcdev())
+               return -ENOTSUPP;
+
        if (!capable(CAP_WAKE_ALARM))
                return -EPERM;
 
@@ -385,6 +456,9 @@ static void alarm_timer_get(struct k_itimer *timr,
  */
 static int alarm_timer_del(struct k_itimer *timr)
 {
+       if (!rtcdev)
+               return -ENOTSUPP;
+
        alarm_cancel(&timr->it.alarmtimer);
        return 0;
 }
@@ -402,6 +476,9 @@ static int alarm_timer_set(struct k_itimer *timr, int flags,
                                struct itimerspec *new_setting,
                                struct itimerspec *old_setting)
 {
+       if (!rtcdev)
+               return -ENOTSUPP;
+
        /* Save old values */
        old_setting->it_interval =
                        ktime_to_timespec(timr->it.alarmtimer.period);
@@ -541,6 +618,9 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
        int ret = 0;
        struct restart_block *restart;
 
+       if (!alarmtimer_get_rtcdev())
+               return -ENOTSUPP;
+
        if (!capable(CAP_WAKE_ALARM))
                return -EPERM;
 
@@ -638,65 +718,3 @@ static int __init alarmtimer_init(void)
 }
 device_initcall(alarmtimer_init);
 
-#ifdef CONFIG_RTC_CLASS
-/**
- * has_wakealarm - check rtc device has wakealarm ability
- * @dev: current device
- * @name_ptr: name to be returned
- *
- * This helper function checks to see if the rtc device can wake
- * from suspend.
- */
-static int __init has_wakealarm(struct device *dev, void *name_ptr)
-{
-       struct rtc_device *candidate = to_rtc_device(dev);
-
-       if (!candidate->ops->set_alarm)
-               return 0;
-       if (!device_may_wakeup(candidate->dev.parent))
-               return 0;
-
-       *(const char **)name_ptr = dev_name(dev);
-       return 1;
-}
-
-/**
- * alarmtimer_init_late - Late initializing of alarmtimer code
- *
- * This function locates a rtc device to use for wakealarms.
- * Run as late_initcall to make sure rtc devices have been
- * registered.
- */
-static int __init alarmtimer_init_late(void)
-{
-       struct device *dev;
-       char *str;
-
-       /* Find an rtc device and init the rtc_timer */
-       dev = class_find_device(rtc_class, NULL, &str, has_wakealarm);
-       /* If we have a device then str is valid. See has_wakealarm() */
-       if (dev) {
-               rtcdev = rtc_class_open(str);
-               /*
-                * Drop the reference we got in class_find_device,
-                * rtc_open takes its own.
-                */
-               put_device(dev);
-       }
-       if (!rtcdev) {
-               printk(KERN_WARNING "No RTC device found, ALARM timers will"
-                       " not wake from suspend");
-       }
-       rtc_timer_init(&rtctimer, NULL, NULL);
-
-       return 0;
-}
-#else
-static int __init alarmtimer_init_late(void)
-{
-       printk(KERN_WARNING "Kernel not built with RTC support, ALARM timers"
-               " will not wake from suspend");
-       return 0;
-}
-#endif
-late_initcall(alarmtimer_init_late);
index c027d4f602f18276f73694a593cefb6ea77bc3a0..e4c699dfa4e8776ee3ed9e671922e962002b6a06 100644 (file)
@@ -182,7 +182,10 @@ void clockevents_register_device(struct clock_event_device *dev)
        unsigned long flags;
 
        BUG_ON(dev->mode != CLOCK_EVT_MODE_UNUSED);
-       BUG_ON(!dev->cpumask);
+       if (!dev->cpumask) {
+               WARN_ON(num_possible_cpus() > 1);
+               dev->cpumask = cpumask_of(smp_processor_id());
+       }
 
        raw_spin_lock_irqsave(&clockevents_lock, flags);
 
index 1c95fd677328e4fe3d0e582fc62284d9ec150a68..e0980f0d9a0ad2d559b98c12f26317b55044cad1 100644 (file)
@@ -185,7 +185,6 @@ static struct clocksource *watchdog;
 static struct timer_list watchdog_timer;
 static DECLARE_WORK(watchdog_work, clocksource_watchdog_work);
 static DEFINE_SPINLOCK(watchdog_lock);
-static cycle_t watchdog_last;
 static int watchdog_running;
 
 static int clocksource_watchdog_kthread(void *data);
@@ -254,11 +253,6 @@ static void clocksource_watchdog(unsigned long data)
        if (!watchdog_running)
                goto out;
 
-       wdnow = watchdog->read(watchdog);
-       wd_nsec = clocksource_cyc2ns((wdnow - watchdog_last) & watchdog->mask,
-                                    watchdog->mult, watchdog->shift);
-       watchdog_last = wdnow;
-
        list_for_each_entry(cs, &watchdog_list, wd_list) {
 
                /* Clocksource already marked unstable? */
@@ -268,19 +262,28 @@ static void clocksource_watchdog(unsigned long data)
                        continue;
                }
 
+               local_irq_disable();
                csnow = cs->read(cs);
+               wdnow = watchdog->read(watchdog);
+               local_irq_enable();
 
                /* Clocksource initialized ? */
                if (!(cs->flags & CLOCK_SOURCE_WATCHDOG)) {
                        cs->flags |= CLOCK_SOURCE_WATCHDOG;
-                       cs->wd_last = csnow;
+                       cs->wd_last = wdnow;
+                       cs->cs_last = csnow;
                        continue;
                }
 
-               /* Check the deviation from the watchdog clocksource. */
-               cs_nsec = clocksource_cyc2ns((csnow - cs->wd_last) &
+               wd_nsec = clocksource_cyc2ns((wdnow - cs->wd_last) & watchdog->mask,
+                                            watchdog->mult, watchdog->shift);
+
+               cs_nsec = clocksource_cyc2ns((csnow - cs->cs_last) &
                                             cs->mask, cs->mult, cs->shift);
-               cs->wd_last = csnow;
+               cs->cs_last = csnow;
+               cs->wd_last = wdnow;
+
+               /* Check the deviation from the watchdog clocksource. */
                if (abs(cs_nsec - wd_nsec) > WATCHDOG_THRESHOLD) {
                        clocksource_unstable(cs, cs_nsec - wd_nsec);
                        continue;
@@ -318,7 +321,6 @@ static inline void clocksource_start_watchdog(void)
                return;
        init_timer(&watchdog_timer);
        watchdog_timer.function = clocksource_watchdog;
-       watchdog_last = watchdog->read(watchdog);
        watchdog_timer.expires = jiffies + WATCHDOG_INTERVAL;
        add_timer_on(&watchdog_timer, cpumask_first(cpu_online_mask));
        watchdog_running = 1;
index fd6198692b57b16e47132d1eb5183bafd98b050e..8cff36119e4d50f7336a06e8d01e59e8b162e694 100644 (file)
@@ -749,16 +749,15 @@ unsigned long apply_slack(struct timer_list *timer, unsigned long expires)
        unsigned long expires_limit, mask;
        int bit;
 
-       expires_limit = expires;
-
        if (timer->slack >= 0) {
                expires_limit = expires + timer->slack;
        } else {
-               unsigned long now = jiffies;
+               long delta = expires - jiffies;
+
+               if (delta < 256)
+                       return expires;
 
-               /* No slack, if already expired else auto slack 0.4% */
-               if (time_after(expires, now))
-                       expires_limit = expires + (expires - now)/256;
+               expires_limit = expires + delta / 256;
        }
        mask = expires ^ expires_limit;
        if (mask == 0)
@@ -795,6 +794,8 @@ unsigned long apply_slack(struct timer_list *timer, unsigned long expires)
  */
 int mod_timer(struct timer_list *timer, unsigned long expires)
 {
+       expires = apply_slack(timer, expires);
+
        /*
         * This is a common optimization triggered by the
         * networking code - if the timer is re-modified
@@ -803,8 +804,6 @@ int mod_timer(struct timer_list *timer, unsigned long expires)
        if (timer_pending(timer) && timer->expires == expires)
                return 1;
 
-       expires = apply_slack(timer, expires);
-
        return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
 }
 EXPORT_SYMBOL(mod_timer);
index d017c2c82c44a084fcfc88faf7c88b32463a82c4..908038f57440e5eec44233351578105ff8c64e08 100644 (file)
@@ -109,12 +109,18 @@ ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip);
 static void ftrace_global_list_func(unsigned long ip,
                                    unsigned long parent_ip)
 {
-       struct ftrace_ops *op = rcu_dereference_raw(ftrace_global_list); /*see above*/
+       struct ftrace_ops *op;
+
+       if (unlikely(trace_recursion_test(TRACE_GLOBAL_BIT)))
+               return;
 
+       trace_recursion_set(TRACE_GLOBAL_BIT);
+       op = rcu_dereference_raw(ftrace_global_list); /*see above*/
        while (op != &ftrace_list_end) {
                op->func(ip, parent_ip);
                op = rcu_dereference_raw(op->next); /*see above*/
        };
+       trace_recursion_clear(TRACE_GLOBAL_BIT);
 }
 
 static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip)
@@ -1638,12 +1644,12 @@ static void ftrace_startup_enable(int command)
        ftrace_run_update_code(command);
 }
 
-static void ftrace_startup(struct ftrace_ops *ops, int command)
+static int ftrace_startup(struct ftrace_ops *ops, int command)
 {
        bool hash_enable = true;
 
        if (unlikely(ftrace_disabled))
-               return;
+               return -ENODEV;
 
        ftrace_start_up++;
        command |= FTRACE_ENABLE_CALLS;
@@ -1662,6 +1668,8 @@ static void ftrace_startup(struct ftrace_ops *ops, int command)
                ftrace_hash_rec_enable(ops, 1);
 
        ftrace_startup_enable(command);
+
+       return 0;
 }
 
 static void ftrace_shutdown(struct ftrace_ops *ops, int command)
@@ -2501,7 +2509,7 @@ static void __enable_ftrace_function_probe(void)
 
        ret = __register_ftrace_function(&trace_probe_ops);
        if (!ret)
-               ftrace_startup(&trace_probe_ops, 0);
+               ret = ftrace_startup(&trace_probe_ops, 0);
 
        ftrace_probe_registered = 1;
 }
@@ -2732,7 +2740,7 @@ static int ftrace_process_regex(struct ftrace_hash *hash,
 {
        char *func, *command, *next = buff;
        struct ftrace_func_command *p;
-       int ret;
+       int ret = -EINVAL;
 
        func = strsep(&next, ":");
 
@@ -3322,6 +3330,7 @@ static int ftrace_process_locs(struct module *mod,
 {
        unsigned long *p;
        unsigned long addr;
+       unsigned long flags;
 
        mutex_lock(&ftrace_lock);
        p = start;
@@ -3338,7 +3347,13 @@ static int ftrace_process_locs(struct module *mod,
                ftrace_record_ip(addr);
        }
 
+       /*
+        * Disable interrupts to prevent interrupts from executing
+        * code that is being modified.
+        */
+       local_irq_save(flags);
        ftrace_update_code(mod);
+       local_irq_restore(flags);
        mutex_unlock(&ftrace_lock);
 
        return 0;
@@ -3466,7 +3481,11 @@ device_initcall(ftrace_nodyn_init);
 static inline int ftrace_init_dyn_debugfs(struct dentry *d_tracer) { return 0; }
 static inline void ftrace_startup_enable(int command) { }
 /* Keep as macros so we do not need to define the commands */
-# define ftrace_startup(ops, command)  do { } while (0)
+# define ftrace_startup(ops, command)                  \
+       ({                                              \
+               (ops)->flags |= FTRACE_OPS_FL_ENABLED;  \
+               0;                                      \
+       })
 # define ftrace_shutdown(ops, command) do { } while (0)
 # define ftrace_startup_sysctl()       do { } while (0)
 # define ftrace_shutdown_sysctl()      do { } while (0)
@@ -3484,6 +3503,10 @@ ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip)
 {
        struct ftrace_ops *op;
 
+       if (unlikely(trace_recursion_test(TRACE_INTERNAL_BIT)))
+               return;
+
+       trace_recursion_set(TRACE_INTERNAL_BIT);
        /*
         * Some of the ops may be dynamically allocated,
         * they must be freed after a synchronize_sched().
@@ -3496,6 +3519,7 @@ ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip)
                op = rcu_dereference_raw(op->next);
        };
        preempt_enable_notrace();
+       trace_recursion_clear(TRACE_INTERNAL_BIT);
 }
 
 static void clear_ftrace_swapper(void)
@@ -3799,7 +3823,7 @@ int register_ftrace_function(struct ftrace_ops *ops)
 
        ret = __register_ftrace_function(ops);
        if (!ret)
-               ftrace_startup(ops, 0);
+               ret = ftrace_startup(ops, 0);
 
 
  out_unlock:
@@ -4045,7 +4069,7 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc,
        ftrace_graph_return = retfunc;
        ftrace_graph_entry = entryfunc;
 
-       ftrace_startup(&global_ops, FTRACE_START_FUNC_RET);
+       ret = ftrace_startup(&global_ops, FTRACE_START_FUNC_RET);
 
 out:
        mutex_unlock(&ftrace_lock);
index 0ef7b4b2a1f7a15d315f1fb1fd76deed790b3acf..b0c7aa4079431fa630e24bc58a4cce3364b70abb 100644 (file)
@@ -2216,7 +2216,7 @@ static noinline void trace_recursive_fail(void)
 
        printk_once(KERN_WARNING "Tracing recursion: depth[%ld]:"
                    "HC[%lu]:SC[%lu]:NMI[%lu]\n",
-                   current->trace_recursion,
+                   trace_recursion_buffer(),
                    hardirq_count() >> HARDIRQ_SHIFT,
                    softirq_count() >> SOFTIRQ_SHIFT,
                    in_nmi());
@@ -2226,9 +2226,9 @@ static noinline void trace_recursive_fail(void)
 
 static inline int trace_recursive_lock(void)
 {
-       current->trace_recursion++;
+       trace_recursion_inc();
 
-       if (likely(current->trace_recursion < TRACE_RECURSIVE_DEPTH))
+       if (likely(trace_recursion_buffer() < TRACE_RECURSIVE_DEPTH))
                return 0;
 
        trace_recursive_fail();
@@ -2238,9 +2238,9 @@ static inline int trace_recursive_lock(void)
 
 static inline void trace_recursive_unlock(void)
 {
-       WARN_ON_ONCE(!current->trace_recursion);
+       WARN_ON_ONCE(!trace_recursion_buffer());
 
-       current->trace_recursion--;
+       trace_recursion_dec();
 }
 
 #else
index 6b69c4bd306f72cbbce93b9fe94827a8696c0fba..229f8591f61db792780fb7579a1061458a663b4c 100644 (file)
@@ -784,4 +784,19 @@ extern const char *__stop___trace_bprintk_fmt[];
        FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print))
 #include "trace_entries.h"
 
+/* Only current can touch trace_recursion */
+#define trace_recursion_inc() do { (current)->trace_recursion++; } while (0)
+#define trace_recursion_dec() do { (current)->trace_recursion--; } while (0)
+
+/* Ring buffer has the 10 LSB bits to count */
+#define trace_recursion_buffer() ((current)->trace_recursion & 0x3ff)
+
+/* for function tracing recursion */
+#define TRACE_INTERNAL_BIT             (1<<11)
+#define TRACE_GLOBAL_BIT               (1<<12)
+
+#define trace_recursion_set(bit)       do { (current)->trace_recursion |= (bit); } while (0)
+#define trace_recursion_clear(bit)     do { (current)->trace_recursion &= ~(bit); } while (0)
+#define trace_recursion_test(bit)      ((current)->trace_recursion & (bit))
+
 #endif /* _LINUX_KERNEL_TRACE_H */
index 2fe110341359539b0498d49472bbdee19e344dc2..686ec399f2a83a007ddacfdbd07fd7cced24783f 100644 (file)
@@ -1657,7 +1657,12 @@ static struct ftrace_ops trace_ops __initdata  =
 
 static __init void event_trace_self_test_with_function(void)
 {
-       register_ftrace_function(&trace_ops);
+       int ret;
+       ret = register_ftrace_function(&trace_ops);
+       if (WARN_ON(ret < 0)) {
+               pr_info("Failed to enable function tracer for event tests\n");
+               return;
+       }
        pr_info("Running tests again, along with the function tracer\n");
        event_trace_self_tests();
        unregister_ftrace_function(&trace_ops);
index f925c45f0afa86d77c1c7b38cb174e72cba1aad6..27d13b36b8be9606deac3e1f42774ce7f3312c22 100644 (file)
@@ -1870,8 +1870,12 @@ fs_initcall(init_kprobe_trace);
 
 #ifdef CONFIG_FTRACE_STARTUP_TEST
 
-static int kprobe_trace_selftest_target(int a1, int a2, int a3,
-                                       int a4, int a5, int a6)
+/*
+ * The "__used" keeps gcc from removing the function symbol
+ * from the kallsyms table.
+ */
+static __used int kprobe_trace_selftest_target(int a1, int a2, int a3,
+                                              int a4, int a5, int a6)
 {
        return a1 + a2 + a3 + a4 + a5 + a6;
 }
index cf535ccedc86abe7732876860e59eb7e68686643..e37de492a9e18c7d41b629c8267ce0f78f03fff9 100644 (file)
@@ -353,6 +353,33 @@ ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val,
 }
 EXPORT_SYMBOL(ftrace_print_symbols_seq);
 
+#if BITS_PER_LONG == 32
+const char *
+ftrace_print_symbols_seq_u64(struct trace_seq *p, unsigned long long val,
+                        const struct trace_print_flags_u64 *symbol_array)
+{
+       int i;
+       const char *ret = p->buffer + p->len;
+
+       for (i = 0;  symbol_array[i].name; i++) {
+
+               if (val != symbol_array[i].mask)
+                       continue;
+
+               trace_seq_puts(p, symbol_array[i].name);
+               break;
+       }
+
+       if (!p->len)
+               trace_seq_printf(p, "0x%llx", val);
+
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+EXPORT_SYMBOL(ftrace_print_symbols_seq_u64);
+#endif
+
 const char *
 ftrace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int buf_len)
 {
index dff763b7baf172d9d7b90c8f0dddc0427a83a1c4..1f06468a10d7a65ad8c0bffa8e13c0eaf44a8ad4 100644 (file)
@@ -240,13 +240,10 @@ static const char **find_next(void *v, loff_t *pos)
        const char **fmt = v;
        int start_index;
 
-       if (!fmt)
-               fmt = __start___trace_bprintk_fmt + *pos;
-
        start_index = __stop___trace_bprintk_fmt - __start___trace_bprintk_fmt;
 
        if (*pos < start_index)
-               return fmt;
+               return __start___trace_bprintk_fmt + *pos;
 
        return find_next_mod_format(start_index, v, fmt, pos);
 }
index 44646179eabae8e8fd848174869f7d1782c90be8..bff131b9510a425452428005afda0acf7c979507 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/user_namespace.h>
+#include <linux/proc_fs.h>
 
 static struct uts_namespace *create_uts_ns(void)
 {
@@ -79,3 +80,41 @@ void free_uts_ns(struct kref *kref)
        put_user_ns(ns->user_ns);
        kfree(ns);
 }
+
+static void *utsns_get(struct task_struct *task)
+{
+       struct uts_namespace *ns = NULL;
+       struct nsproxy *nsproxy;
+
+       rcu_read_lock();
+       nsproxy = task_nsproxy(task);
+       if (nsproxy) {
+               ns = nsproxy->uts_ns;
+               get_uts_ns(ns);
+       }
+       rcu_read_unlock();
+
+       return ns;
+}
+
+static void utsns_put(void *ns)
+{
+       put_uts_ns(ns);
+}
+
+static int utsns_install(struct nsproxy *nsproxy, void *ns)
+{
+       get_uts_ns(ns);
+       put_uts_ns(nsproxy->uts_ns);
+       nsproxy->uts_ns = ns;
+       return 0;
+}
+
+const struct proc_ns_operations utsns_operations = {
+       .name           = "uts",
+       .type           = CLONE_NEWUTS,
+       .get            = utsns_get,
+       .put            = utsns_put,
+       .install        = utsns_install,
+};
+
index 7daa4b072e9fca1cfcf8e2c0dbd3d0b7cbfb63bc..3d0c56ad47929c91795ac7db81d97acbb1e28cf9 100644 (file)
@@ -415,15 +415,13 @@ static void watchdog_nmi_disable(int cpu) { return; }
 #endif /* CONFIG_HARDLOCKUP_DETECTOR */
 
 /* prepare/enable/disable routines */
-static int watchdog_prepare_cpu(int cpu)
+static void watchdog_prepare_cpu(int cpu)
 {
        struct hrtimer *hrtimer = &per_cpu(watchdog_hrtimer, cpu);
 
        WARN_ON(per_cpu(softlockup_watchdog, cpu));
        hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        hrtimer->function = watchdog_timer_fn;
-
-       return 0;
 }
 
 static int watchdog_enable(int cpu)
@@ -542,17 +540,16 @@ static int __cpuinit
 cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 {
        int hotcpu = (unsigned long)hcpu;
-       int err = 0;
 
        switch (action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               err = watchdog_prepare_cpu(hotcpu);
+               watchdog_prepare_cpu(hotcpu);
                break;
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
                if (watchdog_enabled)
-                       err = watchdog_enable(hotcpu);
+                       watchdog_enable(hotcpu);
                break;
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_UP_CANCELED:
index e3378e8d3a5ce7e16fbbbb35ebd30a1c51fde650..0400553f0d049807d109e9cc87d7a5dc2c0dcc99 100644 (file)
@@ -2866,9 +2866,7 @@ static int alloc_cwqs(struct workqueue_struct *wq)
                }
        }
 
-       /* just in case, make sure it's actually aligned
-        * - this is affected by PERCPU() alignment in vmlinux.lds.S
-        */
+       /* just in case, make sure it's actually aligned */
        BUG_ON(!IS_ALIGNED(wq->cpu_wq.v, align));
        return wq->cpu_wq.v ? 0 : -ENOMEM;
 }
index 9c10e38fc609b86605549eba4ce02b1b1cb09de1..830181cc7a83b3a7fa5d6898d6b83461a118fe92 100644 (file)
@@ -19,16 +19,6 @@ config RATIONAL
 config GENERIC_FIND_FIRST_BIT
        bool
 
-config GENERIC_FIND_NEXT_BIT
-       bool
-
-config GENERIC_FIND_BIT_LE
-       bool
-
-config GENERIC_FIND_LAST_BIT
-       bool
-       default y
-
 config CRC_CCITT
        tristate "CRC-CCITT functions"
        help
index 0efcdca9751ac7f24d05ab8a828f0c0f2c757069..dd373c8ee94399efad67ad5bc3adf57e51cf4a3d 100644 (file)
@@ -670,6 +670,15 @@ config STACKTRACE
        bool
        depends on STACKTRACE_SUPPORT
 
+config DEBUG_STACK_USAGE
+       bool "Stack utilization instrumentation"
+       depends on DEBUG_KERNEL
+       help
+         Enables the display of the minimum amount of free stack which each
+         task has ever had available in the sysrq-T and sysrq-P debug output.
+
+         This option will slow down process creation somewhat.
+
 config DEBUG_KOBJECT
        bool "kobject debugging"
        depends on DEBUG_KERNEL
@@ -688,7 +697,7 @@ config DEBUG_BUGVERBOSE
        bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EXPERT
        depends on BUG
        depends on ARM || AVR32 || M32R || M68K || SPARC32 || SPARC64 || \
-                  FRV || SUPERH || GENERIC_BUG || BLACKFIN || MN10300
+                  FRV || SUPERH || GENERIC_BUG || BLACKFIN || MN10300 || TILE
        default y
        help
          Say Y here to make BUG() panics output the file name and line number
@@ -983,6 +992,17 @@ config DEBUG_FORCE_WEAK_PER_CPU
          To ensure that generic code follows the above rules, this
          option forces all percpu variables to be defined as weak.
 
+config DEBUG_PER_CPU_MAPS
+       bool "Debug access to per_cpu maps"
+       depends on DEBUG_KERNEL
+       depends on SMP
+       help
+         Say Y to verify that the per_cpu map being accessed has
+         been set up. This adds a fair amount of code to kernel memory
+         and decreases performance.
+
+         Say N if unsure.
+
 config LKDTM
        tristate "Linux Kernel Dump Test Tool Module"
        depends on DEBUG_FS
index 4b49a249064b5f747ebcec353c610536237e604a..6b597fdb1898c9a132dde2a343e9ec8fa2a5f1bf 100644 (file)
@@ -12,7 +12,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
         idr.o int_sqrt.o extable.o prio_tree.o \
         sha1.o irq_regs.o reciprocal_div.o argv_split.o \
         proportions.o prio_heap.o ratelimit.o show_mem.o \
-        is_single_threaded.o plist.o decompress.o
+        is_single_threaded.o plist.o decompress.o find_next_bit.o
 
 lib-$(CONFIG_MMU) += ioremap.o
 lib-$(CONFIG_SMP) += cpumask.o
@@ -22,7 +22,7 @@ lib-y += kobject.o kref.o klist.o
 obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
         bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
         string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o \
-        bsearch.o
+        bsearch.o find_last_bit.o
 obj-y += kstrtox.o
 obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
 
@@ -39,10 +39,6 @@ obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o
 obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o
 lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
 lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
-lib-$(CONFIG_GENERIC_FIND_FIRST_BIT) += find_next_bit.o
-lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
-lib-$(CONFIG_GENERIC_FIND_BIT_LE) += find_next_bit.o
-obj-$(CONFIG_GENERIC_FIND_LAST_BIT) += find_last_bit.o
 
 CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS))
 obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
index 8e7dc1c63aa9b1d5ce1fcdc8fa5796578b93aaed..76bbed4a20e55d85ebdfc32881d436ee98592f4f 100644 (file)
@@ -36,8 +36,10 @@ int audit_classify_arch(int arch)
 int audit_classify_syscall(int abi, unsigned syscall)
 {
        switch(syscall) {
+#ifdef __NR_open
        case __NR_open:
                return 2;
+#endif
 #ifdef __NR_openat
        case __NR_openat:
                return 3;
index 91e0ccfdb4241b1651d70d8b8bd2e4c903a4599e..3f3b68199d744bd4fc9b94dcb9ca6e831502b0f2 100644 (file)
@@ -571,8 +571,11 @@ int bitmap_scnlistprintf(char *buf, unsigned int buflen,
 EXPORT_SYMBOL(bitmap_scnlistprintf);
 
 /**
- * bitmap_parselist - convert list format ASCII string to bitmap
- * @bp: read nul-terminated user string from this buffer
+ * __bitmap_parselist - convert list format ASCII string to bitmap
+ * @buf: read nul-terminated user string from this buffer
+ * @buflen: buffer size in bytes.  If string is smaller than this
+ *    then it must be terminated with a \0.
+ * @is_user: location of buffer, 0 indicates kernel space
  * @maskp: write resulting mask here
  * @nmaskbits: number of bits in mask to be written
  *
@@ -587,20 +590,63 @@ EXPORT_SYMBOL(bitmap_scnlistprintf);
  *    %-EINVAL: invalid character in string
  *    %-ERANGE: bit number specified too large for mask
  */
-int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits)
+static int __bitmap_parselist(const char *buf, unsigned int buflen,
+               int is_user, unsigned long *maskp,
+               int nmaskbits)
 {
        unsigned a, b;
+       int c, old_c, totaldigits;
+       const char __user *ubuf = buf;
+       int exp_digit, in_range;
 
+       totaldigits = c = 0;
        bitmap_zero(maskp, nmaskbits);
        do {
-               if (!isdigit(*bp))
-                       return -EINVAL;
-               b = a = simple_strtoul(bp, (char **)&bp, BASEDEC);
-               if (*bp == '-') {
-                       bp++;
-                       if (!isdigit(*bp))
+               exp_digit = 1;
+               in_range = 0;
+               a = b = 0;
+
+               /* Get the next cpu# or a range of cpu#'s */
+               while (buflen) {
+                       old_c = c;
+                       if (is_user) {
+                               if (__get_user(c, ubuf++))
+                                       return -EFAULT;
+                       } else
+                               c = *buf++;
+                       buflen--;
+                       if (isspace(c))
+                               continue;
+
+                       /*
+                        * If the last character was a space and the current
+                        * character isn't '\0', we've got embedded whitespace.
+                        * This is a no-no, so throw an error.
+                        */
+                       if (totaldigits && c && isspace(old_c))
+                               return -EINVAL;
+
+                       /* A '\0' or a ',' signal the end of a cpu# or range */
+                       if (c == '\0' || c == ',')
+                               break;
+
+                       if (c == '-') {
+                               if (exp_digit || in_range)
+                                       return -EINVAL;
+                               b = 0;
+                               in_range = 1;
+                               exp_digit = 1;
+                               continue;
+                       }
+
+                       if (!isdigit(c))
                                return -EINVAL;
-                       b = simple_strtoul(bp, (char **)&bp, BASEDEC);
+
+                       b = b * 10 + (c - '0');
+                       if (!in_range)
+                               a = b;
+                       exp_digit = 0;
+                       totaldigits++;
                }
                if (!(a <= b))
                        return -EINVAL;
@@ -610,13 +656,52 @@ int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits)
                        set_bit(a, maskp);
                        a++;
                }
-               if (*bp == ',')
-                       bp++;
-       } while (*bp != '\0' && *bp != '\n');
+       } while (buflen && c == ',');
        return 0;
 }
+
+int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits)
+{
+       char *nl  = strchr(bp, '\n');
+       int len;
+
+       if (nl)
+               len = nl - bp;
+       else
+               len = strlen(bp);
+
+       return __bitmap_parselist(bp, len, 0, maskp, nmaskbits);
+}
 EXPORT_SYMBOL(bitmap_parselist);
 
+
+/**
+ * bitmap_parselist_user()
+ *
+ * @ubuf: pointer to user buffer containing string.
+ * @ulen: buffer size in bytes.  If string is smaller than this
+ *    then it must be terminated with a \0.
+ * @maskp: pointer to bitmap array that will contain result.
+ * @nmaskbits: size of bitmap, in bits.
+ *
+ * Wrapper for bitmap_parselist(), providing it with user buffer.
+ *
+ * We cannot have this as an inline function in bitmap.h because it needs
+ * linux/uaccess.h to get the access_ok() declaration and this causes
+ * cyclic dependencies.
+ */
+int bitmap_parselist_user(const char __user *ubuf,
+                       unsigned int ulen, unsigned long *maskp,
+                       int nmaskbits)
+{
+       if (!access_ok(VERIFY_READ, ubuf, ulen))
+               return -EFAULT;
+       return __bitmap_parselist((const char *)ubuf,
+                                       ulen, 1, maskp, nmaskbits);
+}
+EXPORT_SYMBOL(bitmap_parselist_user);
+
+
 /**
  * bitmap_pos_to_ord - find ordinal of set bit at given position in bitmap
  *     @buf: pointer to a bitmap
index 5d202e36bdd8b9e2d3e36d61d4733f11e2c4f147..d903959ad69598732ce47eba3cc17afbd45b0087 100644 (file)
@@ -15,6 +15,8 @@
 #include <asm/types.h>
 #include <asm/byteorder.h>
 
+#ifndef find_last_bit
+
 unsigned long find_last_bit(const unsigned long *addr, unsigned long size)
 {
        unsigned long words;
@@ -43,3 +45,5 @@ found:
        return size;
 }
 EXPORT_SYMBOL(find_last_bit);
+
+#endif
index b0a8767282bf674fe980f17b5d192103e5ffc4f5..4bd75a73ba0041c0e4607e4c292c10f37ff343a2 100644 (file)
@@ -16,7 +16,7 @@
 
 #define BITOP_WORD(nr)         ((nr) / BITS_PER_LONG)
 
-#ifdef CONFIG_GENERIC_FIND_NEXT_BIT
+#ifndef find_next_bit
 /*
  * Find the next set bit in a memory region.
  */
@@ -59,7 +59,9 @@ found_middle:
        return result + __ffs(tmp);
 }
 EXPORT_SYMBOL(find_next_bit);
+#endif
 
+#ifndef find_next_zero_bit
 /*
  * This implementation of find_{first,next}_zero_bit was stolen from
  * Linus' asm-alpha/bitops.h.
@@ -103,9 +105,9 @@ found_middle:
        return result + ffz(tmp);
 }
 EXPORT_SYMBOL(find_next_zero_bit);
-#endif /* CONFIG_GENERIC_FIND_NEXT_BIT */
+#endif
 
-#ifdef CONFIG_GENERIC_FIND_FIRST_BIT
+#ifndef find_first_bit
 /*
  * Find the first set bit in a memory region.
  */
@@ -131,7 +133,9 @@ found:
        return result + __ffs(tmp);
 }
 EXPORT_SYMBOL(find_first_bit);
+#endif
 
+#ifndef find_first_zero_bit
 /*
  * Find the first cleared bit in a memory region.
  */
@@ -157,10 +161,9 @@ found:
        return result + ffz(tmp);
 }
 EXPORT_SYMBOL(find_first_zero_bit);
-#endif /* CONFIG_GENERIC_FIND_FIRST_BIT */
+#endif
 
 #ifdef __BIG_ENDIAN
-#ifdef CONFIG_GENERIC_FIND_BIT_LE
 
 /* include/linux/byteorder does not support "unsigned long" type */
 static inline unsigned long ext2_swabp(const unsigned long * x)
@@ -186,6 +189,7 @@ static inline unsigned long ext2_swab(const unsigned long y)
 #endif
 }
 
+#ifndef find_next_zero_bit_le
 unsigned long find_next_zero_bit_le(const void *addr, unsigned
                long size, unsigned long offset)
 {
@@ -229,7 +233,9 @@ found_middle_swap:
        return result + ffz(ext2_swab(tmp));
 }
 EXPORT_SYMBOL(find_next_zero_bit_le);
+#endif
 
+#ifndef find_next_bit_le
 unsigned long find_next_bit_le(const void *addr, unsigned
                long size, unsigned long offset)
 {
@@ -274,6 +280,6 @@ found_middle_swap:
        return result + __ffs(ext2_swab(tmp));
 }
 EXPORT_SYMBOL(find_next_bit_le);
+#endif
 
-#endif /* CONFIG_GENERIC_FIND_BIT_LE */
 #endif /* __BIG_ENDIAN */
index 854b57bd7d9d346276fe83599f5cbd306c6e0fe4..9b8b89458c4ce4a8995afd9448f000c6e73335a7 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/stddef.h>
 #include <linux/module.h>
+#include <linux/reciprocal_div.h>
 
 struct flex_array_part {
        char elements[FLEX_ARRAY_PART_SIZE];
@@ -70,15 +71,15 @@ static inline int elements_fit_in_base(struct flex_array *fa)
  * Element size | Objects | Objects |
  * PAGE_SIZE=4k |  32-bit |  64-bit |
  * ---------------------------------|
- *      1 bytes | 4186112 | 2093056 |
- *      2 bytes | 2093056 | 1046528 |
- *      3 bytes | 1395030 |  697515 |
- *      4 bytes | 1046528 |  523264 |
- *     32 bytes |  130816 |   65408 |
- *     33 bytes |  126728 |   63364 |
- *   2048 bytes |    2044 |    1022 |
- *   2049 bytes |    1022 |     511 |
- *       void * | 1046528 |  261632 |
+ *      1 bytes | 4177920 | 2088960 |
+ *      2 bytes | 2088960 | 1044480 |
+ *      3 bytes | 1392300 |  696150 |
+ *      4 bytes | 1044480 |  522240 |
+ *     32 bytes |  130560 |   65408 |
+ *     33 bytes |  126480 |   63240 |
+ *   2048 bytes |    2040 |    1020 |
+ *   2049 bytes |    1020 |     510 |
+ *       void * | 1044480 |  261120 |
  *
  * Since 64-bit pointers are twice the size, we lose half the
  * capacity in the base structure.  Also note that no effort is made
@@ -88,8 +89,15 @@ struct flex_array *flex_array_alloc(int element_size, unsigned int total,
                                        gfp_t flags)
 {
        struct flex_array *ret;
-       int max_size = FLEX_ARRAY_NR_BASE_PTRS *
-                               FLEX_ARRAY_ELEMENTS_PER_PART(element_size);
+       int elems_per_part = 0;
+       int reciprocal_elems = 0;
+       int max_size = 0;
+
+       if (element_size) {
+               elems_per_part = FLEX_ARRAY_ELEMENTS_PER_PART(element_size);
+               reciprocal_elems = reciprocal_value(elems_per_part);
+               max_size = FLEX_ARRAY_NR_BASE_PTRS * elems_per_part;
+       }
 
        /* max_size will end up 0 if element_size > PAGE_SIZE */
        if (total > max_size)
@@ -99,6 +107,8 @@ struct flex_array *flex_array_alloc(int element_size, unsigned int total,
                return NULL;
        ret->element_size = element_size;
        ret->total_nr_elements = total;
+       ret->elems_per_part = elems_per_part;
+       ret->reciprocal_elems = reciprocal_elems;
        if (elements_fit_in_base(ret) && !(flags & __GFP_ZERO))
                memset(&ret->parts[0], FLEX_ARRAY_FREE,
                                                FLEX_ARRAY_BASE_BYTES_LEFT);
@@ -109,7 +119,7 @@ EXPORT_SYMBOL(flex_array_alloc);
 static int fa_element_to_part_nr(struct flex_array *fa,
                                        unsigned int element_nr)
 {
-       return element_nr / FLEX_ARRAY_ELEMENTS_PER_PART(fa->element_size);
+       return reciprocal_divide(element_nr, fa->reciprocal_elems);
 }
 
 /**
@@ -138,12 +148,12 @@ void flex_array_free(struct flex_array *fa)
 EXPORT_SYMBOL(flex_array_free);
 
 static unsigned int index_inside_part(struct flex_array *fa,
-                                       unsigned int element_nr)
+                                       unsigned int element_nr,
+                                       unsigned int part_nr)
 {
        unsigned int part_offset;
 
-       part_offset = element_nr %
-                               FLEX_ARRAY_ELEMENTS_PER_PART(fa->element_size);
+       part_offset = element_nr - part_nr * fa->elems_per_part;
        return part_offset * fa->element_size;
 }
 
@@ -183,20 +193,23 @@ __fa_get_part(struct flex_array *fa, int part_nr, gfp_t flags)
 int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src,
                        gfp_t flags)
 {
-       int part_nr = fa_element_to_part_nr(fa, element_nr);
+       int part_nr = 0;
        struct flex_array_part *part;
        void *dst;
 
        if (element_nr >= fa->total_nr_elements)
                return -ENOSPC;
+       if (!fa->element_size)
+               return 0;
        if (elements_fit_in_base(fa))
                part = (struct flex_array_part *)&fa->parts[0];
        else {
+               part_nr = fa_element_to_part_nr(fa, element_nr);
                part = __fa_get_part(fa, part_nr, flags);
                if (!part)
                        return -ENOMEM;
        }
-       dst = &part->elements[index_inside_part(fa, element_nr)];
+       dst = &part->elements[index_inside_part(fa, element_nr, part_nr)];
        memcpy(dst, src, fa->element_size);
        return 0;
 }
@@ -211,20 +224,23 @@ EXPORT_SYMBOL(flex_array_put);
  */
 int flex_array_clear(struct flex_array *fa, unsigned int element_nr)
 {
-       int part_nr = fa_element_to_part_nr(fa, element_nr);
+       int part_nr = 0;
        struct flex_array_part *part;
        void *dst;
 
        if (element_nr >= fa->total_nr_elements)
                return -ENOSPC;
+       if (!fa->element_size)
+               return 0;
        if (elements_fit_in_base(fa))
                part = (struct flex_array_part *)&fa->parts[0];
        else {
+               part_nr = fa_element_to_part_nr(fa, element_nr);
                part = fa->parts[part_nr];
                if (!part)
                        return -EINVAL;
        }
-       dst = &part->elements[index_inside_part(fa, element_nr)];
+       dst = &part->elements[index_inside_part(fa, element_nr, part_nr)];
        memset(dst, FLEX_ARRAY_FREE, fa->element_size);
        return 0;
 }
@@ -264,6 +280,8 @@ int flex_array_prealloc(struct flex_array *fa, unsigned int start,
 
        if (end >= fa->total_nr_elements)
                return -ENOSPC;
+       if (!fa->element_size)
+               return 0;
        if (elements_fit_in_base(fa))
                return 0;
        start_part = fa_element_to_part_nr(fa, start);
@@ -291,19 +309,22 @@ EXPORT_SYMBOL(flex_array_prealloc);
  */
 void *flex_array_get(struct flex_array *fa, unsigned int element_nr)
 {
-       int part_nr = fa_element_to_part_nr(fa, element_nr);
+       int part_nr = 0;
        struct flex_array_part *part;
 
+       if (!fa->element_size)
+               return NULL;
        if (element_nr >= fa->total_nr_elements)
                return NULL;
        if (elements_fit_in_base(fa))
                part = (struct flex_array_part *)&fa->parts[0];
        else {
+               part_nr = fa_element_to_part_nr(fa, element_nr);
                part = fa->parts[part_nr];
                if (!part)
                        return NULL;
        }
-       return &part->elements[index_inside_part(fa, element_nr)];
+       return &part->elements[index_inside_part(fa, element_nr, part_nr)];
 }
 EXPORT_SYMBOL(flex_array_get);
 
@@ -353,7 +374,7 @@ int flex_array_shrink(struct flex_array *fa)
        int part_nr;
        int ret = 0;
 
-       if (!fa->total_nr_elements)
+       if (!fa->total_nr_elements || !fa->element_size)
                return 0;
        if (elements_fit_in_base(fa))
                return ret;
index 1923f1490e72618b36756b326bbd2e280d71bd49..577ddf8059758b05ecf9871c2409e3c8d346b5c6 100644 (file)
@@ -39,17 +39,20 @@ struct gen_pool *gen_pool_create(int min_alloc_order, int nid)
 EXPORT_SYMBOL(gen_pool_create);
 
 /**
- * gen_pool_add - add a new chunk of special memory to the pool
+ * gen_pool_add_virt - add a new chunk of special memory to the pool
  * @pool: pool to add new memory chunk to
- * @addr: starting address of memory chunk to add to pool
+ * @virt: virtual starting address of memory chunk to add to pool
+ * @phys: physical starting address of memory chunk to add to pool
  * @size: size in bytes of the memory chunk to add to pool
  * @nid: node id of the node the chunk structure and bitmap should be
  *       allocated on, or -1
  *
  * Add a new chunk of special memory to the specified pool.
+ *
+ * Returns 0 on success or a -ve errno on failure.
  */
-int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size,
-                int nid)
+int gen_pool_add_virt(struct gen_pool *pool, unsigned long virt, phys_addr_t phys,
+                size_t size, int nid)
 {
        struct gen_pool_chunk *chunk;
        int nbits = size >> pool->min_alloc_order;
@@ -58,11 +61,12 @@ int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size,
 
        chunk = kmalloc_node(nbytes, GFP_KERNEL | __GFP_ZERO, nid);
        if (unlikely(chunk == NULL))
-               return -1;
+               return -ENOMEM;
 
        spin_lock_init(&chunk->lock);
-       chunk->start_addr = addr;
-       chunk->end_addr = addr + size;
+       chunk->phys_addr = phys;
+       chunk->start_addr = virt;
+       chunk->end_addr = virt + size;
 
        write_lock(&pool->lock);
        list_add(&chunk->next_chunk, &pool->chunks);
@@ -70,7 +74,32 @@ int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size,
 
        return 0;
 }
-EXPORT_SYMBOL(gen_pool_add);
+EXPORT_SYMBOL(gen_pool_add_virt);
+
+/**
+ * gen_pool_virt_to_phys - return the physical address of memory
+ * @pool: pool to allocate from
+ * @addr: starting address of memory
+ *
+ * Returns the physical address on success, or -1 on error.
+ */
+phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long addr)
+{
+       struct list_head *_chunk;
+       struct gen_pool_chunk *chunk;
+
+       read_lock(&pool->lock);
+       list_for_each(_chunk, &pool->chunks) {
+               chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
+
+               if (addr >= chunk->start_addr && addr < chunk->end_addr)
+                       return chunk->phys_addr + addr - chunk->start_addr;
+       }
+       read_unlock(&pool->lock);
+
+       return -1;
+}
+EXPORT_SYMBOL(gen_pool_virt_to_phys);
 
 /**
  * gen_pool_destroy - destroy a special memory pool
index 82dc34c095c25ea0e14619d68bda9d3942836bd5..640bd98a4c8aa59fd3f597da6f0706287de5609c 100644 (file)
@@ -948,14 +948,14 @@ const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj)
 }
 
 
-const void *kobj_ns_current(enum kobj_ns_type type)
+void *kobj_ns_grab_current(enum kobj_ns_type type)
 {
-       const void *ns = NULL;
+       void *ns = NULL;
 
        spin_lock(&kobj_ns_type_lock);
        if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
            kobj_ns_ops_tbl[type])
-               ns = kobj_ns_ops_tbl[type]->current_ns();
+               ns = kobj_ns_ops_tbl[type]->grab_current_ns();
        spin_unlock(&kobj_ns_type_lock);
 
        return ns;
@@ -987,23 +987,15 @@ const void *kobj_ns_initial(enum kobj_ns_type type)
        return ns;
 }
 
-/*
- * kobj_ns_exit - invalidate a namespace tag
- *
- * @type: the namespace type (i.e. KOBJ_NS_TYPE_NET)
- * @ns: the actual namespace being invalidated
- *
- * This is called when a tag is no longer valid.  For instance,
- * when a network namespace exits, it uses this helper to
- * make sure no sb's sysfs_info points to the now-invalidated
- * netns.
- */
-void kobj_ns_exit(enum kobj_ns_type type, const void *ns)
+void kobj_ns_drop(enum kobj_ns_type type, void *ns)
 {
-       sysfs_exit_ns(type, ns);
+       spin_lock(&kobj_ns_type_lock);
+       if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
+           kobj_ns_ops_tbl[type] && kobj_ns_ops_tbl[type]->drop_ns)
+               kobj_ns_ops_tbl[type]->drop_ns(ns);
+       spin_unlock(&kobj_ns_type_lock);
 }
 
-
 EXPORT_SYMBOL(kobject_get);
 EXPORT_SYMBOL(kobject_put);
 EXPORT_SYMBOL(kobject_del);
index a235f3cc471c6d427fd4c2e713a701fa0b1e7e1b..2dbae88090ac3232f591f98289521fa3c9f3b3dd 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <asm/uaccess.h>
 
 static inline char _tolower(const char c)
 {
@@ -222,3 +223,28 @@ int kstrtos8(const char *s, unsigned int base, s8 *res)
        return 0;
 }
 EXPORT_SYMBOL(kstrtos8);
+
+#define kstrto_from_user(f, g, type)                                   \
+int f(const char __user *s, size_t count, unsigned int base, type *res)        \
+{                                                                      \
+       /* sign, base 2 representation, newline, terminator */          \
+       char buf[1 + sizeof(type) * 8 + 1 + 1];                         \
+                                                                       \
+       count = min(count, sizeof(buf) - 1);                            \
+       if (copy_from_user(buf, s, count))                              \
+               return -EFAULT;                                         \
+       buf[count] = '\0';                                              \
+       return g(buf, base, res);                                       \
+}                                                                      \
+EXPORT_SYMBOL(f)
+
+kstrto_from_user(kstrtoull_from_user,  kstrtoull,      unsigned long long);
+kstrto_from_user(kstrtoll_from_user,   kstrtoll,       long long);
+kstrto_from_user(kstrtoul_from_user,   kstrtoul,       unsigned long);
+kstrto_from_user(kstrtol_from_user,    kstrtol,        long);
+kstrto_from_user(kstrtouint_from_user, kstrtouint,     unsigned int);
+kstrto_from_user(kstrtoint_from_user,  kstrtoint,      int);
+kstrto_from_user(kstrtou16_from_user,  kstrtou16,      u16);
+kstrto_from_user(kstrtos16_from_user,  kstrtos16,      s16);
+kstrto_from_user(kstrtou8_from_user,   kstrtou8,       u8);
+kstrto_from_user(kstrtos8_from_user,   kstrtos8,       s8);
index 619313ed6c46d78ef7b35a6ab870bfd764376486..507a22fab7380c120bcf45cb683051c2e4adb0da 100644 (file)
@@ -144,7 +144,7 @@ static void init_shared_classes(void)
 
 #define HARDIRQ_ENTER()                                \
        local_irq_disable();                    \
-       irq_enter();                            \
+       __irq_enter();                          \
        WARN_ON(!in_irq());
 
 #define HARDIRQ_EXIT()                         \
index 270de9d31b8c1a04940489e6bdd60b06480179b2..a07e7268d7ed4aa446f590076fed5a86aab96877 100644 (file)
@@ -84,7 +84,7 @@ struct lru_cache *lc_create(const char *name, struct kmem_cache *cache,
        if (e_count > LC_MAX_ACTIVE)
                return NULL;
 
-       slot = kzalloc(e_count * sizeof(struct hlist_head*), GFP_KERNEL);
+       slot = kcalloc(e_count, sizeof(struct hlist_head), GFP_KERNEL);
        if (!slot)
                goto out_fail;
        element = kzalloc(e_count * sizeof(struct lc_element *), GFP_KERNEL);
index 90cbe4bb5960fc480eaf45273638159ac48d2aa7..4407f8c9b1f71046d8b4aec0519734491b8bdd2a 100644 (file)
@@ -16,7 +16,7 @@ void show_mem(unsigned int filter)
                nonshared = 0, highmem = 0;
 
        printk("Mem-Info:\n");
-       __show_free_areas(filter);
+       show_free_areas(filter);
 
        for_each_online_pgdat(pgdat) {
                unsigned long i, flags;
index 93ca08b8a451411c3c4ac18f1f9525637e4a7140..99093b396145957d52b5e88a183ee1eb9cedeb60 100644 (file)
@@ -110,6 +110,11 @@ setup_io_tlb_npages(char *str)
 __setup("swiotlb=", setup_io_tlb_npages);
 /* make io_tlb_overflow tunable too? */
 
+unsigned long swioltb_nr_tbl(void)
+{
+       return io_tlb_nslabs;
+}
+
 /* Note that this doesn't work with highmem page */
 static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev,
                                      volatile void *address)
index 1d659d7bb0f8ed595156f9863f773c476fe68d23..4365df31a1d52122cd670d5ad2fe321fc887337f 100644 (file)
@@ -666,6 +666,8 @@ char *ip6_compressed_string(char *p, const char *addr)
                        colonpos = i;
                }
        }
+       if (longest == 1)               /* don't compress a single 0 */
+               colonpos = -1;
 
        /* emit address */
        for (i = 0; i < range; i++) {
@@ -826,7 +828,7 @@ int kptr_restrict __read_mostly;
  *       IPv4 uses dot-separated decimal with leading 0's (010.123.045.006)
  * - '[Ii]4[hnbl]' IPv4 addresses in host, network, big or little endian order
  * - 'I6c' for IPv6 addresses printed as specified by
- *       http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-00
+ *       http://tools.ietf.org/html/rfc5952
  * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form
  *       "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  *       Options for %pU are:
@@ -898,7 +900,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
        case 'U':
                return uuid_string(buf, end, ptr, spec, fmt);
        case 'V':
-               return buf + vsnprintf(buf, end - buf,
+               return buf + vsnprintf(buf, end > buf ? end - buf : 0,
                                       ((struct va_format *)ptr)->fmt,
                                       *(((struct va_format *)ptr)->va));
        case 'K':
index e9c0c61f2ddd0881bbb9dee37d3384dae0146ece..8ca47a5ee9c8529262c7d7e5a3224e1c2c36d27b 100644 (file)
@@ -347,3 +347,26 @@ config NEED_PER_CPU_KM
        depends on !SMP
        bool
        default y
+
+config CLEANCACHE
+       bool "Enable cleancache driver to cache clean pages if tmem is present"
+       default n
+       help
+         Cleancache can be thought of as a page-granularity victim cache
+         for clean pages that the kernel's pageframe replacement algorithm
+         (PFRA) would like to keep around, but can't since there isn't enough
+         memory.  So when the PFRA "evicts" a page, it first attempts to use
+         cleancacne code to put the data contained in that page into
+         "transcendent memory", memory that is not directly accessible or
+         addressable by the kernel and is of unknown and possibly
+         time-varying size.  And when a cleancache-enabled
+         filesystem wishes to access a page in a file on disk, it first
+         checks cleancache to see if it already contains it; if it does,
+         the page is copied into the kernel and a disk access is avoided.
+         When a transcendent memory driver is available (such as zcache or
+         Xen transcendent memory), a significant I/O reduction
+         may be achieved.  When none is available, all cleancache calls
+         are reduced to a single pointer-compare-against-NULL resulting
+         in a negligible performance hit.
+
+         If unsure, say Y to enable cleancache
index 42a8326c3e3da1f9fbedb0e0ee26d4cac47d1d85..836e4163c1bfd91c5742c9f5227fc105d79a3b76 100644 (file)
@@ -49,3 +49,4 @@ obj-$(CONFIG_MEMORY_FAILURE) += memory-failure.o
 obj-$(CONFIG_HWPOISON_INJECT) += hwpoison-inject.o
 obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak.o
 obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak-test.o
+obj-$(CONFIG_CLEANCACHE) += cleancache.o
index befc87531e4fe0f7630f65195f00806d1feaaeef..f032e6e1e09af069bbaab3537a6169827237189d 100644 (file)
@@ -63,10 +63,10 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v)
        unsigned long background_thresh;
        unsigned long dirty_thresh;
        unsigned long bdi_thresh;
-       unsigned long nr_dirty, nr_io, nr_more_io, nr_wb;
+       unsigned long nr_dirty, nr_io, nr_more_io;
        struct inode *inode;
 
-       nr_wb = nr_dirty = nr_io = nr_more_io = 0;
+       nr_dirty = nr_io = nr_more_io = 0;
        spin_lock(&inode_wb_list_lock);
        list_for_each_entry(inode, &wb->b_dirty, i_wb_list)
                nr_dirty++;
diff --git a/mm/cleancache.c b/mm/cleancache.c
new file mode 100644 (file)
index 0000000..bcaae4c
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Cleancache frontend
+ *
+ * This code provides the generic "frontend" layer to call a matching
+ * "backend" driver implementation of cleancache.  See
+ * Documentation/vm/cleancache.txt for more information.
+ *
+ * Copyright (C) 2009-2010 Oracle Corp. All rights reserved.
+ * Author: Dan Magenheimer
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/exportfs.h>
+#include <linux/mm.h>
+#include <linux/cleancache.h>
+
+/*
+ * This global enablement flag may be read thousands of times per second
+ * by cleancache_get/put/flush even on systems where cleancache_ops
+ * is not claimed (e.g. cleancache is config'ed on but remains
+ * disabled), so is preferred to the slower alternative: a function
+ * call that checks a non-global.
+ */
+int cleancache_enabled;
+EXPORT_SYMBOL(cleancache_enabled);
+
+/*
+ * cleancache_ops is set by cleancache_ops_register to contain the pointers
+ * to the cleancache "backend" implementation functions.
+ */
+static struct cleancache_ops cleancache_ops;
+
+/* useful stats available in /sys/kernel/mm/cleancache */
+static unsigned long cleancache_succ_gets;
+static unsigned long cleancache_failed_gets;
+static unsigned long cleancache_puts;
+static unsigned long cleancache_flushes;
+
+/*
+ * register operations for cleancache, returning previous thus allowing
+ * detection of multiple backends and possible nesting
+ */
+struct cleancache_ops cleancache_register_ops(struct cleancache_ops *ops)
+{
+       struct cleancache_ops old = cleancache_ops;
+
+       cleancache_ops = *ops;
+       cleancache_enabled = 1;
+       return old;
+}
+EXPORT_SYMBOL(cleancache_register_ops);
+
+/* Called by a cleancache-enabled filesystem at time of mount */
+void __cleancache_init_fs(struct super_block *sb)
+{
+       sb->cleancache_poolid = (*cleancache_ops.init_fs)(PAGE_SIZE);
+}
+EXPORT_SYMBOL(__cleancache_init_fs);
+
+/* Called by a cleancache-enabled clustered filesystem at time of mount */
+void __cleancache_init_shared_fs(char *uuid, struct super_block *sb)
+{
+       sb->cleancache_poolid =
+               (*cleancache_ops.init_shared_fs)(uuid, PAGE_SIZE);
+}
+EXPORT_SYMBOL(__cleancache_init_shared_fs);
+
+/*
+ * If the filesystem uses exportable filehandles, use the filehandle as
+ * the key, else use the inode number.
+ */
+static int cleancache_get_key(struct inode *inode,
+                             struct cleancache_filekey *key)
+{
+       int (*fhfn)(struct dentry *, __u32 *fh, int *, int);
+       int len = 0, maxlen = CLEANCACHE_KEY_MAX;
+       struct super_block *sb = inode->i_sb;
+
+       key->u.ino = inode->i_ino;
+       if (sb->s_export_op != NULL) {
+               fhfn = sb->s_export_op->encode_fh;
+               if  (fhfn) {
+                       struct dentry d;
+                       d.d_inode = inode;
+                       len = (*fhfn)(&d, &key->u.fh[0], &maxlen, 0);
+                       if (len <= 0 || len == 255)
+                               return -1;
+                       if (maxlen > CLEANCACHE_KEY_MAX)
+                               return -1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * "Get" data from cleancache associated with the poolid/inode/index
+ * that were specified when the data was put to cleanache and, if
+ * successful, use it to fill the specified page with data and return 0.
+ * The pageframe is unchanged and returns -1 if the get fails.
+ * Page must be locked by caller.
+ */
+int __cleancache_get_page(struct page *page)
+{
+       int ret = -1;
+       int pool_id;
+       struct cleancache_filekey key = { .u.key = { 0 } };
+
+       VM_BUG_ON(!PageLocked(page));
+       pool_id = page->mapping->host->i_sb->cleancache_poolid;
+       if (pool_id < 0)
+               goto out;
+
+       if (cleancache_get_key(page->mapping->host, &key) < 0)
+               goto out;
+
+       ret = (*cleancache_ops.get_page)(pool_id, key, page->index, page);
+       if (ret == 0)
+               cleancache_succ_gets++;
+       else
+               cleancache_failed_gets++;
+out:
+       return ret;
+}
+EXPORT_SYMBOL(__cleancache_get_page);
+
+/*
+ * "Put" data from a page to cleancache and associate it with the
+ * (previously-obtained per-filesystem) poolid and the page's,
+ * inode and page index.  Page must be locked.  Note that a put_page
+ * always "succeeds", though a subsequent get_page may succeed or fail.
+ */
+void __cleancache_put_page(struct page *page)
+{
+       int pool_id;
+       struct cleancache_filekey key = { .u.key = { 0 } };
+
+       VM_BUG_ON(!PageLocked(page));
+       pool_id = page->mapping->host->i_sb->cleancache_poolid;
+       if (pool_id >= 0 &&
+             cleancache_get_key(page->mapping->host, &key) >= 0) {
+               (*cleancache_ops.put_page)(pool_id, key, page->index, page);
+               cleancache_puts++;
+       }
+}
+EXPORT_SYMBOL(__cleancache_put_page);
+
+/*
+ * Flush any data from cleancache associated with the poolid and the
+ * page's inode and page index so that a subsequent "get" will fail.
+ */
+void __cleancache_flush_page(struct address_space *mapping, struct page *page)
+{
+       /* careful... page->mapping is NULL sometimes when this is called */
+       int pool_id = mapping->host->i_sb->cleancache_poolid;
+       struct cleancache_filekey key = { .u.key = { 0 } };
+
+       if (pool_id >= 0) {
+               VM_BUG_ON(!PageLocked(page));
+               if (cleancache_get_key(mapping->host, &key) >= 0) {
+                       (*cleancache_ops.flush_page)(pool_id, key, page->index);
+                       cleancache_flushes++;
+               }
+       }
+}
+EXPORT_SYMBOL(__cleancache_flush_page);
+
+/*
+ * Flush all data from cleancache associated with the poolid and the
+ * mappings's inode so that all subsequent gets to this poolid/inode
+ * will fail.
+ */
+void __cleancache_flush_inode(struct address_space *mapping)
+{
+       int pool_id = mapping->host->i_sb->cleancache_poolid;
+       struct cleancache_filekey key = { .u.key = { 0 } };
+
+       if (pool_id >= 0 && cleancache_get_key(mapping->host, &key) >= 0)
+               (*cleancache_ops.flush_inode)(pool_id, key);
+}
+EXPORT_SYMBOL(__cleancache_flush_inode);
+
+/*
+ * Called by any cleancache-enabled filesystem at time of unmount;
+ * note that pool_id is surrendered and may be reutrned by a subsequent
+ * cleancache_init_fs or cleancache_init_shared_fs
+ */
+void __cleancache_flush_fs(struct super_block *sb)
+{
+       if (sb->cleancache_poolid >= 0) {
+               int old_poolid = sb->cleancache_poolid;
+               sb->cleancache_poolid = -1;
+               (*cleancache_ops.flush_fs)(old_poolid);
+       }
+}
+EXPORT_SYMBOL(__cleancache_flush_fs);
+
+#ifdef CONFIG_SYSFS
+
+/* see Documentation/ABI/xxx/sysfs-kernel-mm-cleancache */
+
+#define CLEANCACHE_SYSFS_RO(_name) \
+       static ssize_t cleancache_##_name##_show(struct kobject *kobj, \
+                               struct kobj_attribute *attr, char *buf) \
+       { \
+               return sprintf(buf, "%lu\n", cleancache_##_name); \
+       } \
+       static struct kobj_attribute cleancache_##_name##_attr = { \
+               .attr = { .name = __stringify(_name), .mode = 0444 }, \
+               .show = cleancache_##_name##_show, \
+       }
+
+CLEANCACHE_SYSFS_RO(succ_gets);
+CLEANCACHE_SYSFS_RO(failed_gets);
+CLEANCACHE_SYSFS_RO(puts);
+CLEANCACHE_SYSFS_RO(flushes);
+
+static struct attribute *cleancache_attrs[] = {
+       &cleancache_succ_gets_attr.attr,
+       &cleancache_failed_gets_attr.attr,
+       &cleancache_puts_attr.attr,
+       &cleancache_flushes_attr.attr,
+       NULL,
+};
+
+static struct attribute_group cleancache_attr_group = {
+       .attrs = cleancache_attrs,
+       .name = "cleancache",
+};
+
+#endif /* CONFIG_SYSFS */
+
+static int __init init_cleancache(void)
+{
+#ifdef CONFIG_SYSFS
+       int err;
+
+       err = sysfs_create_group(mm_kobj, &cleancache_attr_group);
+#endif /* CONFIG_SYSFS */
+       return 0;
+}
+module_init(init_cleancache)
index 021a2960ef9e18d061c972590f7651a35e7652ce..6cc604bd56496e2742e371d63234af08f9f0859b 100644 (file)
@@ -144,9 +144,20 @@ static void isolate_freepages(struct zone *zone,
        int nr_freepages = cc->nr_freepages;
        struct list_head *freelist = &cc->freepages;
 
+       /*
+        * Initialise the free scanner. The starting point is where we last
+        * scanned from (or the end of the zone if starting). The low point
+        * is the end of the pageblock the migration scanner is using.
+        */
        pfn = cc->free_pfn;
        low_pfn = cc->migrate_pfn + pageblock_nr_pages;
-       high_pfn = low_pfn;
+
+       /*
+        * Take care that if the migration scanner is at the end of the zone
+        * that the free scanner does not accidentally move to the next zone
+        * in the next isolation cycle.
+        */
+       high_pfn = min(low_pfn, pfn);
 
        /*
         * Isolate free pages until enough are available to migrate the
@@ -240,11 +251,18 @@ static bool too_many_isolated(struct zone *zone)
        return isolated > (inactive + active) / 2;
 }
 
+/* possible outcome of isolate_migratepages */
+typedef enum {
+       ISOLATE_ABORT,          /* Abort compaction now */
+       ISOLATE_NONE,           /* No pages isolated, continue scanning */
+       ISOLATE_SUCCESS,        /* Pages isolated, migrate */
+} isolate_migrate_t;
+
 /*
  * Isolate all pages that can be migrated from the block pointed to by
  * the migrate scanner within compact_control.
  */
-static unsigned long isolate_migratepages(struct zone *zone,
+static isolate_migrate_t isolate_migratepages(struct zone *zone,
                                        struct compact_control *cc)
 {
        unsigned long low_pfn, end_pfn;
@@ -261,7 +279,7 @@ static unsigned long isolate_migratepages(struct zone *zone,
        /* Do not cross the free scanner or scan within a memory hole */
        if (end_pfn > cc->free_pfn || !pfn_valid(low_pfn)) {
                cc->migrate_pfn = end_pfn;
-               return 0;
+               return ISOLATE_NONE;
        }
 
        /*
@@ -270,10 +288,14 @@ static unsigned long isolate_migratepages(struct zone *zone,
         * delay for some time until fewer pages are isolated
         */
        while (unlikely(too_many_isolated(zone))) {
+               /* async migration should just abort */
+               if (!cc->sync)
+                       return ISOLATE_ABORT;
+
                congestion_wait(BLK_RW_ASYNC, HZ/10);
 
                if (fatal_signal_pending(current))
-                       return 0;
+                       return ISOLATE_ABORT;
        }
 
        /* Time to isolate some pages for migration */
@@ -358,7 +380,7 @@ static unsigned long isolate_migratepages(struct zone *zone,
 
        trace_mm_compaction_isolate_migratepages(nr_scanned, nr_isolated);
 
-       return cc->nr_migratepages;
+       return ISOLATE_SUCCESS;
 }
 
 /*
@@ -420,13 +442,6 @@ static int compact_finished(struct zone *zone,
        if (cc->free_pfn <= cc->migrate_pfn)
                return COMPACT_COMPLETE;
 
-       /* Compaction run is not finished if the watermark is not met */
-       watermark = low_wmark_pages(zone);
-       watermark += (1 << cc->order);
-
-       if (!zone_watermark_ok(zone, cc->order, watermark, 0, 0))
-               return COMPACT_CONTINUE;
-
        /*
         * order == -1 is expected when compacting via
         * /proc/sys/vm/compact_memory
@@ -434,6 +449,13 @@ static int compact_finished(struct zone *zone,
        if (cc->order == -1)
                return COMPACT_CONTINUE;
 
+       /* Compaction run is not finished if the watermark is not met */
+       watermark = low_wmark_pages(zone);
+       watermark += (1 << cc->order);
+
+       if (!zone_watermark_ok(zone, cc->order, watermark, 0, 0))
+               return COMPACT_CONTINUE;
+
        /* Direct compactor: Is a suitable page free? */
        for (order = cc->order; order < MAX_ORDER; order++) {
                /* Job done if page is free of the right migratetype */
@@ -460,6 +482,13 @@ unsigned long compaction_suitable(struct zone *zone, int order)
        int fragindex;
        unsigned long watermark;
 
+       /*
+        * order == -1 is expected when compacting via
+        * /proc/sys/vm/compact_memory
+        */
+       if (order == -1)
+               return COMPACT_CONTINUE;
+
        /*
         * Watermarks for order-0 must be met for compaction. Note the 2UL.
         * This is because during migration, copies of pages need to be
@@ -469,18 +498,12 @@ unsigned long compaction_suitable(struct zone *zone, int order)
        if (!zone_watermark_ok(zone, 0, watermark, 0, 0))
                return COMPACT_SKIPPED;
 
-       /*
-        * order == -1 is expected when compacting via
-        * /proc/sys/vm/compact_memory
-        */
-       if (order == -1)
-               return COMPACT_CONTINUE;
-
        /*
         * fragmentation index determines if allocation failures are due to
         * low memory or external fragmentation
         *
-        * index of -1 implies allocations might succeed dependingon watermarks
+        * index of -1000 implies allocations might succeed depending on
+        * watermarks
         * index towards 0 implies failure is due to lack of memory
         * index towards 1000 implies failure is due to fragmentation
         *
@@ -490,7 +513,8 @@ unsigned long compaction_suitable(struct zone *zone, int order)
        if (fragindex >= 0 && fragindex <= sysctl_extfrag_threshold)
                return COMPACT_SKIPPED;
 
-       if (fragindex == -1 && zone_watermark_ok(zone, order, watermark, 0, 0))
+       if (fragindex == -1000 && zone_watermark_ok(zone, order, watermark,
+           0, 0))
                return COMPACT_PARTIAL;
 
        return COMPACT_CONTINUE;
@@ -522,8 +546,15 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
                unsigned long nr_migrate, nr_remaining;
                int err;
 
-               if (!isolate_migratepages(zone, cc))
+               switch (isolate_migratepages(zone, cc)) {
+               case ISOLATE_ABORT:
+                       ret = COMPACT_PARTIAL;
+                       goto out;
+               case ISOLATE_NONE:
                        continue;
+               case ISOLATE_SUCCESS:
+                       ;
+               }
 
                nr_migrate = cc->nr_migratepages;
                err = migrate_pages(&cc->migratepages, compaction_alloc,
@@ -547,6 +578,7 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
 
        }
 
+out:
        /* Release free pages and check accounting */
        cc->nr_freepages -= release_freepages(&cc->freepages);
        VM_BUG_ON(cc->nr_freepages != 0);
index c641edf553a9373dd3f2c3a20c584fa3dcb2c957..a8251a8d3457d28802164d6538c9226e98416f73 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/hardirq.h> /* for BUG_ON(!in_atomic()) only */
 #include <linux/memcontrol.h>
 #include <linux/mm_inline.h> /* for page_is_file_cache() */
+#include <linux/cleancache.h>
 #include "internal.h"
 
 /*
 /*
  * Lock ordering:
  *
- *  ->i_mmap_lock              (truncate_pagecache)
+ *  ->i_mmap_mutex             (truncate_pagecache)
  *    ->private_lock           (__free_pte->__set_page_dirty_buffers)
  *      ->swap_lock            (exclusive_swap_page, others)
  *        ->mapping->tree_lock
  *
  *  ->i_mutex
- *    ->i_mmap_lock            (truncate->unmap_mapping_range)
+ *    ->i_mmap_mutex           (truncate->unmap_mapping_range)
  *
  *  ->mmap_sem
- *    ->i_mmap_lock
+ *    ->i_mmap_mutex
  *      ->page_table_lock or pte_lock  (various, mainly in memory.c)
  *        ->mapping->tree_lock (arch-dependent flush_dcache_mmap_lock)
  *
@@ -84,7 +85,7 @@
  *    sb_lock                  (fs/fs-writeback.c)
  *    ->mapping->tree_lock     (__sync_single_inode)
  *
- *  ->i_mmap_lock
+ *  ->i_mmap_mutex
  *    ->anon_vma.lock          (vma_adjust)
  *
  *  ->anon_vma.lock
  *
  *  (code doesn't rely on that order, so you could switch it around)
  *  ->tasklist_lock             (memory_failure, collect_procs_ao)
- *    ->i_mmap_lock
+ *    ->i_mmap_mutex
  */
 
 /*
@@ -118,6 +119,16 @@ void __delete_from_page_cache(struct page *page)
 {
        struct address_space *mapping = page->mapping;
 
+       /*
+        * if we're uptodate, flush out into the cleancache, otherwise
+        * invalidate any existing cleancache entries.  We can't leave
+        * stale data around in the cleancache once our page is gone
+        */
+       if (PageUptodate(page) && PageMappedToDisk(page))
+               cleancache_put_page(page);
+       else
+               cleancache_flush_page(mapping, page);
+
        radix_tree_delete(&mapping->page_tree, page->index);
        page->mapping = NULL;
        mapping->nrpages--;
@@ -562,6 +573,17 @@ void wait_on_page_bit(struct page *page, int bit_nr)
 }
 EXPORT_SYMBOL(wait_on_page_bit);
 
+int wait_on_page_bit_killable(struct page *page, int bit_nr)
+{
+       DEFINE_WAIT_BIT(wait, &page->flags, bit_nr);
+
+       if (!test_bit(bit_nr, &page->flags))
+               return 0;
+
+       return __wait_on_bit(page_waitqueue(page), &wait,
+                            sleep_on_page_killable, TASK_KILLABLE);
+}
+
 /**
  * add_page_wait_queue - Add an arbitrary waiter to a page's wait queue
  * @page: Page defining the wait queue of interest
@@ -643,15 +665,32 @@ EXPORT_SYMBOL_GPL(__lock_page_killable);
 int __lock_page_or_retry(struct page *page, struct mm_struct *mm,
                         unsigned int flags)
 {
-       if (!(flags & FAULT_FLAG_ALLOW_RETRY)) {
-               __lock_page(page);
-               return 1;
-       } else {
-               if (!(flags & FAULT_FLAG_RETRY_NOWAIT)) {
-                       up_read(&mm->mmap_sem);
+       if (flags & FAULT_FLAG_ALLOW_RETRY) {
+               /*
+                * CAUTION! In this case, mmap_sem is not released
+                * even though return 0.
+                */
+               if (flags & FAULT_FLAG_RETRY_NOWAIT)
+                       return 0;
+
+               up_read(&mm->mmap_sem);
+               if (flags & FAULT_FLAG_KILLABLE)
+                       wait_on_page_locked_killable(page);
+               else
                        wait_on_page_locked(page);
-               }
                return 0;
+       } else {
+               if (flags & FAULT_FLAG_KILLABLE) {
+                       int ret;
+
+                       ret = __lock_page_killable(page);
+                       if (ret) {
+                               up_read(&mm->mmap_sem);
+                               return 0;
+                       }
+               } else
+                       __lock_page(page);
+               return 1;
        }
 }
 
@@ -1528,15 +1567,17 @@ static void do_sync_mmap_readahead(struct vm_area_struct *vma,
        /* If we don't want any read-ahead, don't bother */
        if (VM_RandomReadHint(vma))
                return;
+       if (!ra->ra_pages)
+               return;
 
-       if (VM_SequentialReadHint(vma) ||
-                       offset - 1 == (ra->prev_pos >> PAGE_CACHE_SHIFT)) {
+       if (VM_SequentialReadHint(vma)) {
                page_cache_sync_readahead(mapping, ra, file, offset,
                                          ra->ra_pages);
                return;
        }
 
-       if (ra->mmap_miss < INT_MAX)
+       /* Avoid banging the cache line if not needed */
+       if (ra->mmap_miss < MMAP_LOTSAMISS * 10)
                ra->mmap_miss++;
 
        /*
@@ -1550,12 +1591,10 @@ static void do_sync_mmap_readahead(struct vm_area_struct *vma,
         * mmap read-around
         */
        ra_pages = max_sane_readahead(ra->ra_pages);
-       if (ra_pages) {
-               ra->start = max_t(long, 0, offset - ra_pages/2);
-               ra->size = ra_pages;
-               ra->async_size = 0;
-               ra_submit(ra, mapping, file);
-       }
+       ra->start = max_t(long, 0, offset - ra_pages / 2);
+       ra->size = ra_pages;
+       ra->async_size = ra_pages / 4;
+       ra_submit(ra, mapping, file);
 }
 
 /*
@@ -1622,6 +1661,7 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                /* No page in the page cache at all */
                do_sync_mmap_readahead(vma, ra, file, offset);
                count_vm_event(PGMAJFAULT);
+               mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT);
                ret = VM_FAULT_MAJOR;
 retry_find:
                page = find_get_page(mapping, offset);
@@ -1660,7 +1700,6 @@ retry_find:
                return VM_FAULT_SIGBUS;
        }
 
-       ra->prev_pos = (loff_t)offset << PAGE_CACHE_SHIFT;
        vmf->page = page;
        return ret | VM_FAULT_LOCKED;
 
@@ -1943,16 +1982,26 @@ static int __remove_suid(struct dentry *dentry, int kill)
 int file_remove_suid(struct file *file)
 {
        struct dentry *dentry = file->f_path.dentry;
-       int killsuid = should_remove_suid(dentry);
-       int killpriv = security_inode_need_killpriv(dentry);
+       struct inode *inode = dentry->d_inode;
+       int killsuid;
+       int killpriv;
        int error = 0;
 
+       /* Fast path for nothing security related */
+       if (IS_NOSEC(inode))
+               return 0;
+
+       killsuid = should_remove_suid(dentry);
+       killpriv = security_inode_need_killpriv(dentry);
+
        if (killpriv < 0)
                return killpriv;
        if (killpriv)
                error = security_inode_killpriv(dentry);
        if (!error && killsuid)
                error = __remove_suid(dentry, killsuid);
+       if (!error && (inode->i_sb->s_flags & MS_NOSEC))
+               inode->i_flags |= S_NOSEC;
 
        return error;
 }
@@ -2288,7 +2337,7 @@ struct page *grab_cache_page_write_begin(struct address_space *mapping,
 repeat:
        page = find_lock_page(mapping, index);
        if (page)
-               return page;
+               goto found;
 
        page = __page_cache_alloc(mapping_gfp_mask(mapping) & ~gfp_notmask);
        if (!page)
@@ -2301,6 +2350,8 @@ repeat:
                        goto repeat;
                return NULL;
        }
+found:
+       wait_on_page_writeback(page);
        return page;
 }
 EXPORT_SYMBOL(grab_cache_page_write_begin);
index 83364df74a33811ea7aea971412bfe91d4fe9c17..93356cd12828a40eb4d635a9e0e0bea3d6ba0790 100644 (file)
@@ -183,7 +183,7 @@ __xip_unmap (struct address_space * mapping,
                return;
 
 retry:
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
        vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
                mm = vma->vm_mm;
                address = vma->vm_start +
@@ -201,7 +201,7 @@ retry:
                        page_cache_release(page);
                }
        }
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
 
        if (locked) {
                mutex_unlock(&xip_sparse_mutex);
index ec520c7b28dffedb5027de6b27834831938671cd..b8e0e2d468afb276816174bcb76a46667d74831b 100644 (file)
@@ -211,20 +211,20 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
                        }
                        goto out;
                }
-               spin_lock(&mapping->i_mmap_lock);
+               mutex_lock(&mapping->i_mmap_mutex);
                flush_dcache_mmap_lock(mapping);
                vma->vm_flags |= VM_NONLINEAR;
                vma_prio_tree_remove(vma, &mapping->i_mmap);
                vma_nonlinear_insert(vma, &mapping->i_mmap_nonlinear);
                flush_dcache_mmap_unlock(mapping);
-               spin_unlock(&mapping->i_mmap_lock);
+               mutex_unlock(&mapping->i_mmap_mutex);
        }
 
        if (vma->vm_flags & VM_LOCKED) {
                /*
                 * drop PG_Mlocked flag for over-mapped range
                 */
-               unsigned int saved_flags = vma->vm_flags;
+               vm_flags_t saved_flags = vma->vm_flags;
                munlock_vma_pages_range(vma, start, start + size);
                vma->vm_flags = saved_flags;
        }
index 83326ad66d9b15df1027a0274d92886c85386394..81532f297fd22cd11e1c7a4161c8e320a7015ec2 100644 (file)
@@ -1139,7 +1139,7 @@ static int __split_huge_page_splitting(struct page *page,
                 * We can't temporarily set the pmd to null in order
                 * to split it, the pmd must remain marked huge at all
                 * times or the VM won't take the pmd_trans_huge paths
-                * and it won't wait on the anon_vma->root->lock to
+                * and it won't wait on the anon_vma->root->mutex to
                 * serialize against split_huge_page*.
                 */
                pmdp_splitting_flush_notify(vma, address, pmd);
@@ -1333,7 +1333,7 @@ static int __split_huge_page_map(struct page *page,
        return ret;
 }
 
-/* must be called with anon_vma->root->lock hold */
+/* must be called with anon_vma->root->mutex hold */
 static void __split_huge_page(struct page *page,
                              struct anon_vma *anon_vma)
 {
@@ -1771,12 +1771,9 @@ static void collapse_huge_page(struct mm_struct *mm,
 
        VM_BUG_ON(address & ~HPAGE_PMD_MASK);
 #ifndef CONFIG_NUMA
+       up_read(&mm->mmap_sem);
        VM_BUG_ON(!*hpage);
        new_page = *hpage;
-       if (unlikely(mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL))) {
-               up_read(&mm->mmap_sem);
-               return;
-       }
 #else
        VM_BUG_ON(*hpage);
        /*
@@ -1791,22 +1788,26 @@ static void collapse_huge_page(struct mm_struct *mm,
         */
        new_page = alloc_hugepage_vma(khugepaged_defrag(), vma, address,
                                      node, __GFP_OTHER_NODE);
+
+       /*
+        * After allocating the hugepage, release the mmap_sem read lock in
+        * preparation for taking it in write mode.
+        */
+       up_read(&mm->mmap_sem);
        if (unlikely(!new_page)) {
-               up_read(&mm->mmap_sem);
                count_vm_event(THP_COLLAPSE_ALLOC_FAILED);
                *hpage = ERR_PTR(-ENOMEM);
                return;
        }
+#endif
+
        count_vm_event(THP_COLLAPSE_ALLOC);
        if (unlikely(mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL))) {
-               up_read(&mm->mmap_sem);
+#ifdef CONFIG_NUMA
                put_page(new_page);
+#endif
                return;
        }
-#endif
-
-       /* after allocating the hugepage upgrade to mmap_sem write mode */
-       up_read(&mm->mmap_sem);
 
        /*
         * Prevent all access to pagetables with the exception of
@@ -2233,11 +2234,8 @@ static void khugepaged_loop(void)
        while (likely(khugepaged_enabled())) {
 #ifndef CONFIG_NUMA
                hpage = khugepaged_alloc_hugepage();
-               if (unlikely(!hpage)) {
-                       count_vm_event(THP_COLLAPSE_ALLOC_FAILED);
+               if (unlikely(!hpage))
                        break;
-               }
-               count_vm_event(THP_COLLAPSE_ALLOC);
 #else
                if (IS_ERR(hpage)) {
                        khugepaged_alloc_sleep();
index bbb4a5bbb9582055945237692b8938a731c5492a..bfcf153bc82907f31ccc1921256622a82bf20d2f 100644 (file)
@@ -1033,10 +1033,10 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
         */
        chg = vma_needs_reservation(h, vma, addr);
        if (chg < 0)
-               return ERR_PTR(chg);
+               return ERR_PTR(-VM_FAULT_OOM);
        if (chg)
                if (hugetlb_get_quota(inode->i_mapping, chg))
-                       return ERR_PTR(-ENOSPC);
+                       return ERR_PTR(-VM_FAULT_SIGBUS);
 
        spin_lock(&hugetlb_lock);
        page = dequeue_huge_page_vma(h, vma, addr, avoid_reserve);
@@ -1111,6 +1111,14 @@ static void __init gather_bootmem_prealloc(void)
                WARN_ON(page_count(page) != 1);
                prep_compound_huge_page(page, h->order);
                prep_new_huge_page(h, page, page_to_nid(page));
+               /*
+                * If we had gigantic hugepages allocated at boot time, we need
+                * to restore the 'stolen' pages to totalram_pages in order to
+                * fix confusing memory reports from free(1) and another
+                * side-effects, like CommitLimit going negative.
+                */
+               if (h->order > (MAX_ORDER - 1))
+                       totalram_pages += 1 << h->order;
        }
 }
 
@@ -2205,7 +2213,7 @@ void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
        unsigned long sz = huge_page_size(h);
 
        /*
-        * A page gathering list, protected by per file i_mmap_lock. The
+        * A page gathering list, protected by per file i_mmap_mutex. The
         * lock is used to avoid list corruption from multiple unmapping
         * of the same page since we are using page->lru.
         */
@@ -2274,9 +2282,9 @@ void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
 void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
                          unsigned long end, struct page *ref_page)
 {
-       spin_lock(&vma->vm_file->f_mapping->i_mmap_lock);
+       mutex_lock(&vma->vm_file->f_mapping->i_mmap_mutex);
        __unmap_hugepage_range(vma, start, end, ref_page);
-       spin_unlock(&vma->vm_file->f_mapping->i_mmap_lock);
+       mutex_unlock(&vma->vm_file->f_mapping->i_mmap_mutex);
 }
 
 /*
@@ -2308,7 +2316,7 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
         * this mapping should be shared between all the VMAs,
         * __unmap_hugepage_range() is called as the lock is already held
         */
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
        vma_prio_tree_foreach(iter_vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
                /* Do not unmap the current VMA */
                if (iter_vma == vma)
@@ -2326,7 +2334,7 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
                                address, address + huge_page_size(h),
                                page);
        }
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
 
        return 1;
 }
@@ -2810,7 +2818,7 @@ void hugetlb_change_protection(struct vm_area_struct *vma,
        BUG_ON(address >= end);
        flush_cache_range(vma, address, end);
 
-       spin_lock(&vma->vm_file->f_mapping->i_mmap_lock);
+       mutex_lock(&vma->vm_file->f_mapping->i_mmap_mutex);
        spin_lock(&mm->page_table_lock);
        for (; address < end; address += huge_page_size(h)) {
                ptep = huge_pte_offset(mm, address);
@@ -2825,7 +2833,7 @@ void hugetlb_change_protection(struct vm_area_struct *vma,
                }
        }
        spin_unlock(&mm->page_table_lock);
-       spin_unlock(&vma->vm_file->f_mapping->i_mmap_lock);
+       mutex_unlock(&vma->vm_file->f_mapping->i_mmap_mutex);
 
        flush_tlb_range(vma, start, end);
 }
@@ -2833,7 +2841,7 @@ void hugetlb_change_protection(struct vm_area_struct *vma,
 int hugetlb_reserve_pages(struct inode *inode,
                                        long from, long to,
                                        struct vm_area_struct *vma,
-                                       int acctflag)
+                                       vm_flags_t vm_flags)
 {
        long ret, chg;
        struct hstate *h = hstate_inode(inode);
@@ -2843,7 +2851,7 @@ int hugetlb_reserve_pages(struct inode *inode,
         * attempt will be made for VM_NORESERVE to allocate a page
         * and filesystem quota without using reserves
         */
-       if (acctflag & VM_NORESERVE)
+       if (vm_flags & VM_NORESERVE)
                return 0;
 
        /*
index 1d29cdfe8ebb6b2c21f1b0fafe68509bba14b2ab..4019979b263722098b8231391e9a7ae82dc153f6 100644 (file)
@@ -21,6 +21,5 @@ struct mm_struct init_mm = {
        .mmap_sem       = __RWSEM_INITIALIZER(init_mm.mmap_sem),
        .page_table_lock =  __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock),
        .mmlist         = LIST_HEAD_INIT(init_mm.mmlist),
-       .cpu_vm_mask    = CPU_MASK_ALL,
        INIT_MM_CONTEXT(init_mm)
 };
index 9d0ced8e505e9276dabb42e129a4b918966a2421..d071d380fb498ab36ac6700343bf86485463bdbe 100644 (file)
@@ -66,6 +66,10 @@ static inline unsigned long page_order(struct page *page)
        return page_private(page);
 }
 
+/* mm/util.c */
+void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
+               struct vm_area_struct *prev, struct rb_node *rb_parent);
+
 #ifdef CONFIG_MMU
 extern long mlock_vma_pages_range(struct vm_area_struct *vma,
                        unsigned long start, unsigned long end);
index 942dfc73a2ff89c3c7c96b3f9b1838c99ec16d02..9a68b0cf0a1c4c8009ee25d2990530d7e2927132 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -35,6 +35,7 @@
 #include <linux/ksm.h>
 #include <linux/hash.h>
 #include <linux/freezer.h>
+#include <linux/oom.h>
 
 #include <asm/tlbflush.h>
 #include "internal.h"
@@ -1301,6 +1302,12 @@ static struct rmap_item *scan_get_next_rmap_item(struct page **page)
                slot = list_entry(slot->mm_list.next, struct mm_slot, mm_list);
                ksm_scan.mm_slot = slot;
                spin_unlock(&ksm_mmlist_lock);
+               /*
+                * Although we tested list_empty() above, a racing __ksm_exit
+                * of the last mm on the list may have removed it since then.
+                */
+               if (slot == &ksm_mm_head)
+                       return NULL;
 next_mm:
                ksm_scan.address = 0;
                ksm_scan.rmap_list = &slot->rmap_list;
@@ -1894,9 +1901,11 @@ static ssize_t run_store(struct kobject *kobj, struct kobj_attribute *attr,
        if (ksm_run != flags) {
                ksm_run = flags;
                if (flags & KSM_RUN_UNMERGE) {
-                       current->flags |= PF_OOM_ORIGIN;
+                       int oom_score_adj;
+
+                       oom_score_adj = test_set_oom_score_adj(OOM_SCORE_ADJ_MAX);
                        err = unmerge_and_remove_all_rmap_items();
-                       current->flags &= ~PF_OOM_ORIGIN;
+                       test_set_oom_score_adj(oom_score_adj);
                        if (err) {
                                ksm_run = KSM_RUN_STOP;
                                count = err;
index e2b6f5634e0d38bf4b4a8df34816e86af72a07e9..4cee182ab5f3bc1805b1850b5c13a1ec9c5fa8b6 100644 (file)
  * happens, handle that and return -EFAULT.
  */
 
-long __weak probe_kernel_read(void *dst, void *src, size_t size)
+long __weak probe_kernel_read(void *dst, const void *src, size_t size)
     __attribute__((alias("__probe_kernel_read")));
 
-long __probe_kernel_read(void *dst, void *src, size_t size)
+long __probe_kernel_read(void *dst, const void *src, size_t size)
 {
        long ret;
        mm_segment_t old_fs = get_fs();
@@ -43,10 +43,10 @@ EXPORT_SYMBOL_GPL(probe_kernel_read);
  * Safely write to address @dst from the buffer at @src.  If a kernel fault
  * happens, handle that and return -EFAULT.
  */
-long __weak probe_kernel_write(void *dst, void *src, size_t size)
+long __weak probe_kernel_write(void *dst, const void *src, size_t size)
     __attribute__((alias("__probe_kernel_write")));
 
-long __probe_kernel_write(void *dst, void *src, size_t size)
+long __probe_kernel_write(void *dst, const void *src, size_t size)
 {
        long ret;
        mm_segment_t old_fs = get_fs();
index 010f9166fa6ea099b7ab7b5ccdefe7af8cf033f4..cf7d027a8844b115bcc6d213264707d220c6c3d9 100644 (file)
@@ -94,6 +94,8 @@ enum mem_cgroup_events_index {
        MEM_CGROUP_EVENTS_PGPGIN,       /* # of pages paged in */
        MEM_CGROUP_EVENTS_PGPGOUT,      /* # of pages paged out */
        MEM_CGROUP_EVENTS_COUNT,        /* # of pages paged in/out */
+       MEM_CGROUP_EVENTS_PGFAULT,      /* # of page-faults */
+       MEM_CGROUP_EVENTS_PGMAJFAULT,   /* # of major page-faults */
        MEM_CGROUP_EVENTS_NSTATS,
 };
 /*
@@ -231,6 +233,11 @@ struct mem_cgroup {
         * reclaimed from.
         */
        int last_scanned_child;
+       int last_scanned_node;
+#if MAX_NUMNODES > 1
+       nodemask_t      scan_nodes;
+       unsigned long   next_scan_node_update;
+#endif
        /*
         * Should the accounting and control be hierarchical, per subtree?
         */
@@ -352,7 +359,7 @@ enum charge_type {
 static void mem_cgroup_get(struct mem_cgroup *mem);
 static void mem_cgroup_put(struct mem_cgroup *mem);
 static struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *mem);
-static void drain_all_stock_async(void);
+static void drain_all_stock_async(struct mem_cgroup *mem);
 
 static struct mem_cgroup_per_zone *
 mem_cgroup_zoneinfo(struct mem_cgroup *mem, int nid, int zid)
@@ -585,6 +592,16 @@ static void mem_cgroup_swap_statistics(struct mem_cgroup *mem,
        this_cpu_add(mem->stat->count[MEM_CGROUP_STAT_SWAPOUT], val);
 }
 
+void mem_cgroup_pgfault(struct mem_cgroup *mem, int val)
+{
+       this_cpu_add(mem->stat->events[MEM_CGROUP_EVENTS_PGFAULT], val);
+}
+
+void mem_cgroup_pgmajfault(struct mem_cgroup *mem, int val)
+{
+       this_cpu_add(mem->stat->events[MEM_CGROUP_EVENTS_PGMAJFAULT], val);
+}
+
 static unsigned long mem_cgroup_read_events(struct mem_cgroup *mem,
                                            enum mem_cgroup_events_index idx)
 {
@@ -624,18 +641,27 @@ static void mem_cgroup_charge_statistics(struct mem_cgroup *mem,
        preempt_enable();
 }
 
+static unsigned long
+mem_cgroup_get_zonestat_node(struct mem_cgroup *mem, int nid, enum lru_list idx)
+{
+       struct mem_cgroup_per_zone *mz;
+       u64 total = 0;
+       int zid;
+
+       for (zid = 0; zid < MAX_NR_ZONES; zid++) {
+               mz = mem_cgroup_zoneinfo(mem, nid, zid);
+               total += MEM_CGROUP_ZSTAT(mz, idx);
+       }
+       return total;
+}
 static unsigned long mem_cgroup_get_local_zonestat(struct mem_cgroup *mem,
                                        enum lru_list idx)
 {
-       int nid, zid;
-       struct mem_cgroup_per_zone *mz;
+       int nid;
        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);
-               }
+               total += mem_cgroup_get_zonestat_node(mem, nid, idx);
        return total;
 }
 
@@ -709,7 +735,7 @@ struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p)
                                struct mem_cgroup, css);
 }
 
-static struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)
+struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)
 {
        struct mem_cgroup *mem = NULL;
 
@@ -813,6 +839,33 @@ static inline bool mem_cgroup_is_root(struct mem_cgroup *mem)
        return (mem == root_mem_cgroup);
 }
 
+void mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx)
+{
+       struct mem_cgroup *mem;
+
+       if (!mm)
+               return;
+
+       rcu_read_lock();
+       mem = mem_cgroup_from_task(rcu_dereference(mm->owner));
+       if (unlikely(!mem))
+               goto out;
+
+       switch (idx) {
+       case PGMAJFAULT:
+               mem_cgroup_pgmajfault(mem, 1);
+               break;
+       case PGFAULT:
+               mem_cgroup_pgfault(mem, 1);
+               break;
+       default:
+               BUG();
+       }
+out:
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL(mem_cgroup_count_vm_event);
+
 /*
  * Following LRU functions are allowed to be used without PCG_LOCK.
  * Operations are called by routine of global LRU independently from memcg.
@@ -1064,9 +1117,9 @@ int mem_cgroup_inactive_file_is_low(struct mem_cgroup *memcg)
        return (active > inactive);
 }
 
-unsigned long mem_cgroup_zone_nr_pages(struct mem_cgroup *memcg,
-                                      struct zone *zone,
-                                      enum lru_list lru)
+unsigned long mem_cgroup_zone_nr_lru_pages(struct mem_cgroup *memcg,
+                                               struct zone *zone,
+                                               enum lru_list lru)
 {
        int nid = zone_to_nid(zone);
        int zid = zone_idx(zone);
@@ -1075,6 +1128,93 @@ unsigned long mem_cgroup_zone_nr_pages(struct mem_cgroup *memcg,
        return MEM_CGROUP_ZSTAT(mz, lru);
 }
 
+#ifdef CONFIG_NUMA
+static unsigned long mem_cgroup_node_nr_file_lru_pages(struct mem_cgroup *memcg,
+                                                       int nid)
+{
+       unsigned long ret;
+
+       ret = mem_cgroup_get_zonestat_node(memcg, nid, LRU_INACTIVE_FILE) +
+               mem_cgroup_get_zonestat_node(memcg, nid, LRU_ACTIVE_FILE);
+
+       return ret;
+}
+
+static unsigned long mem_cgroup_nr_file_lru_pages(struct mem_cgroup *memcg)
+{
+       u64 total = 0;
+       int nid;
+
+       for_each_node_state(nid, N_HIGH_MEMORY)
+               total += mem_cgroup_node_nr_file_lru_pages(memcg, nid);
+
+       return total;
+}
+
+static unsigned long mem_cgroup_node_nr_anon_lru_pages(struct mem_cgroup *memcg,
+                                                       int nid)
+{
+       unsigned long ret;
+
+       ret = mem_cgroup_get_zonestat_node(memcg, nid, LRU_INACTIVE_ANON) +
+               mem_cgroup_get_zonestat_node(memcg, nid, LRU_ACTIVE_ANON);
+
+       return ret;
+}
+
+static unsigned long mem_cgroup_nr_anon_lru_pages(struct mem_cgroup *memcg)
+{
+       u64 total = 0;
+       int nid;
+
+       for_each_node_state(nid, N_HIGH_MEMORY)
+               total += mem_cgroup_node_nr_anon_lru_pages(memcg, nid);
+
+       return total;
+}
+
+static unsigned long
+mem_cgroup_node_nr_unevictable_lru_pages(struct mem_cgroup *memcg, int nid)
+{
+       return mem_cgroup_get_zonestat_node(memcg, nid, LRU_UNEVICTABLE);
+}
+
+static unsigned long
+mem_cgroup_nr_unevictable_lru_pages(struct mem_cgroup *memcg)
+{
+       u64 total = 0;
+       int nid;
+
+       for_each_node_state(nid, N_HIGH_MEMORY)
+               total += mem_cgroup_node_nr_unevictable_lru_pages(memcg, nid);
+
+       return total;
+}
+
+static unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
+                                                       int nid)
+{
+       enum lru_list l;
+       u64 total = 0;
+
+       for_each_lru(l)
+               total += mem_cgroup_get_zonestat_node(memcg, nid, l);
+
+       return total;
+}
+
+static unsigned long mem_cgroup_nr_lru_pages(struct mem_cgroup *memcg)
+{
+       u64 total = 0;
+       int nid;
+
+       for_each_node_state(nid, N_HIGH_MEMORY)
+               total += mem_cgroup_node_nr_lru_pages(memcg, nid);
+
+       return total;
+}
+#endif /* CONFIG_NUMA */
+
 struct zone_reclaim_stat *mem_cgroup_get_reclaim_stat(struct mem_cgroup *memcg,
                                                      struct zone *zone)
 {
@@ -1418,6 +1558,81 @@ mem_cgroup_select_victim(struct mem_cgroup *root_mem)
        return ret;
 }
 
+#if MAX_NUMNODES > 1
+
+/*
+ * Always updating the nodemask is not very good - even if we have an empty
+ * list or the wrong list here, we can start from some node and traverse all
+ * nodes based on the zonelist. So update the list loosely once per 10 secs.
+ *
+ */
+static void mem_cgroup_may_update_nodemask(struct mem_cgroup *mem)
+{
+       int nid;
+
+       if (time_after(mem->next_scan_node_update, jiffies))
+               return;
+
+       mem->next_scan_node_update = jiffies + 10*HZ;
+       /* make a nodemask where this memcg uses memory from */
+       mem->scan_nodes = node_states[N_HIGH_MEMORY];
+
+       for_each_node_mask(nid, node_states[N_HIGH_MEMORY]) {
+
+               if (mem_cgroup_get_zonestat_node(mem, nid, LRU_INACTIVE_FILE) ||
+                   mem_cgroup_get_zonestat_node(mem, nid, LRU_ACTIVE_FILE))
+                       continue;
+
+               if (total_swap_pages &&
+                   (mem_cgroup_get_zonestat_node(mem, nid, LRU_INACTIVE_ANON) ||
+                    mem_cgroup_get_zonestat_node(mem, nid, LRU_ACTIVE_ANON)))
+                       continue;
+               node_clear(nid, mem->scan_nodes);
+       }
+}
+
+/*
+ * Selecting a node where we start reclaim from. Because what we need is just
+ * reducing usage counter, start from anywhere is O,K. Considering
+ * memory reclaim from current node, there are pros. and cons.
+ *
+ * Freeing memory from current node means freeing memory from a node which
+ * we'll use or we've used. So, it may make LRU bad. And if several threads
+ * hit limits, it will see a contention on a node. But freeing from remote
+ * node means more costs for memory reclaim because of memory latency.
+ *
+ * Now, we use round-robin. Better algorithm is welcomed.
+ */
+int mem_cgroup_select_victim_node(struct mem_cgroup *mem)
+{
+       int node;
+
+       mem_cgroup_may_update_nodemask(mem);
+       node = mem->last_scanned_node;
+
+       node = next_node(node, mem->scan_nodes);
+       if (node == MAX_NUMNODES)
+               node = first_node(mem->scan_nodes);
+       /*
+        * We call this when we hit limit, not when pages are added to LRU.
+        * No LRU may hold pages because all pages are UNEVICTABLE or
+        * memcg is too small and all pages are not on LRU. In that case,
+        * we use curret node.
+        */
+       if (unlikely(node == MAX_NUMNODES))
+               node = numa_node_id();
+
+       mem->last_scanned_node = node;
+       return node;
+}
+
+#else
+int mem_cgroup_select_victim_node(struct mem_cgroup *mem)
+{
+       return 0;
+}
+#endif
+
 /*
  * Scan the hierarchy if needed to reclaim memory. We remember the last child
  * we reclaimed from, so that we don't end up penalizing one child extensively
@@ -1433,7 +1648,8 @@ mem_cgroup_select_victim(struct mem_cgroup *root_mem)
 static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
                                                struct zone *zone,
                                                gfp_t gfp_mask,
-                                               unsigned long reclaim_options)
+                                               unsigned long reclaim_options,
+                                               unsigned long *total_scanned)
 {
        struct mem_cgroup *victim;
        int ret, total = 0;
@@ -1442,19 +1658,26 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
        bool shrink = reclaim_options & MEM_CGROUP_RECLAIM_SHRINK;
        bool check_soft = reclaim_options & MEM_CGROUP_RECLAIM_SOFT;
        unsigned long excess;
+       unsigned long nr_scanned;
 
        excess = res_counter_soft_limit_excess(&root_mem->res) >> PAGE_SHIFT;
 
        /* If memsw_is_minimum==1, swap-out is of-no-use. */
-       if (root_mem->memsw_is_minimum)
+       if (!check_soft && root_mem->memsw_is_minimum)
                noswap = true;
 
        while (1) {
                victim = mem_cgroup_select_victim(root_mem);
                if (victim == root_mem) {
                        loop++;
-                       if (loop >= 1)
-                               drain_all_stock_async();
+                       /*
+                        * We are not draining per cpu cached charges during
+                        * soft limit reclaim  because global reclaim doesn't
+                        * care about charges. It tries to free some memory and
+                        * charges will not give any.
+                        */
+                       if (!check_soft && loop >= 1)
+                               drain_all_stock_async(root_mem);
                        if (loop >= 2) {
                                /*
                                 * If we have not been able to reclaim
@@ -1484,10 +1707,12 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
                        continue;
                }
                /* we use swappiness of local cgroup */
-               if (check_soft)
+               if (check_soft) {
                        ret = mem_cgroup_shrink_node_zone(victim, gfp_mask,
-                               noswap, get_swappiness(victim), zone);
-               else
+                               noswap, get_swappiness(victim), zone,
+                               &nr_scanned);
+                       *total_scanned += nr_scanned;
+               } else
                        ret = try_to_free_mem_cgroup_pages(victim, gfp_mask,
                                                noswap, get_swappiness(victim));
                css_put(&victim->css);
@@ -1503,7 +1728,7 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
                        if (!res_counter_soft_limit_excess(&root_mem->res))
                                return total;
                } else if (mem_cgroup_margin(root_mem))
-                       return 1 + total;
+                       return total;
        }
        return total;
 }
@@ -1715,9 +1940,11 @@ struct memcg_stock_pcp {
        struct mem_cgroup *cached; /* this never be root cgroup */
        unsigned int nr_pages;
        struct work_struct work;
+       unsigned long flags;
+#define FLUSHING_CACHED_CHARGE (0)
 };
 static DEFINE_PER_CPU(struct memcg_stock_pcp, memcg_stock);
-static atomic_t memcg_drain_count;
+static DEFINE_MUTEX(percpu_charge_mutex);
 
 /*
  * Try to consume stocked charge on this cpu. If success, one page is consumed
@@ -1765,6 +1992,7 @@ static void drain_local_stock(struct work_struct *dummy)
 {
        struct memcg_stock_pcp *stock = &__get_cpu_var(memcg_stock);
        drain_stock(stock);
+       clear_bit(FLUSHING_CACHED_CHARGE, &stock->flags);
 }
 
 /*
@@ -1789,26 +2017,45 @@ static void refill_stock(struct mem_cgroup *mem, unsigned int nr_pages)
  * expects some charges will be back to res_counter later but cannot wait for
  * it.
  */
-static void drain_all_stock_async(void)
+static void drain_all_stock_async(struct mem_cgroup *root_mem)
 {
-       int cpu;
-       /* This function is for scheduling "drain" in asynchronous way.
-        * The result of "drain" is not directly handled by callers. Then,
-        * if someone is calling drain, we don't have to call drain more.
-        * Anyway, WORK_STRUCT_PENDING check in queue_work_on() will catch if
-        * there is a race. We just do loose check here.
+       int cpu, curcpu;
+       /*
+        * If someone calls draining, avoid adding more kworker runs.
         */
-       if (atomic_read(&memcg_drain_count))
+       if (!mutex_trylock(&percpu_charge_mutex))
                return;
        /* Notify other cpus that system-wide "drain" is running */
-       atomic_inc(&memcg_drain_count);
        get_online_cpus();
+       /*
+        * Get a hint for avoiding draining charges on the current cpu,
+        * which must be exhausted by our charging.  It is not required that
+        * this be a precise check, so we use raw_smp_processor_id() instead of
+        * getcpu()/putcpu().
+        */
+       curcpu = raw_smp_processor_id();
        for_each_online_cpu(cpu) {
                struct memcg_stock_pcp *stock = &per_cpu(memcg_stock, cpu);
-               schedule_work_on(cpu, &stock->work);
+               struct mem_cgroup *mem;
+
+               if (cpu == curcpu)
+                       continue;
+
+               mem = stock->cached;
+               if (!mem)
+                       continue;
+               if (mem != root_mem) {
+                       if (!root_mem->use_hierarchy)
+                               continue;
+                       /* check whether "mem" is under tree of "root_mem" */
+                       if (!css_is_ancestor(&mem->css, &root_mem->css))
+                               continue;
+               }
+               if (!test_and_set_bit(FLUSHING_CACHED_CHARGE, &stock->flags))
+                       schedule_work_on(cpu, &stock->work);
        }
        put_online_cpus();
-       atomic_dec(&memcg_drain_count);
+       mutex_unlock(&percpu_charge_mutex);
        /* We don't wait for flush_work */
 }
 
@@ -1816,9 +2063,9 @@ static void drain_all_stock_async(void)
 static void drain_all_stock_sync(void)
 {
        /* called when force_empty is called */
-       atomic_inc(&memcg_drain_count);
+       mutex_lock(&percpu_charge_mutex);
        schedule_on_each_cpu(drain_local_stock);
-       atomic_dec(&memcg_drain_count);
+       mutex_unlock(&percpu_charge_mutex);
 }
 
 /*
@@ -1928,7 +2175,7 @@ static int mem_cgroup_do_charge(struct mem_cgroup *mem, gfp_t gfp_mask,
                return CHARGE_WOULDBLOCK;
 
        ret = mem_cgroup_hierarchical_reclaim(mem_over_limit, NULL,
-                                             gfp_mask, flags);
+                                             gfp_mask, flags, NULL);
        if (mem_cgroup_margin(mem_over_limit) >= nr_pages)
                return CHARGE_RETRY;
        /*
@@ -3211,7 +3458,8 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
                        break;
 
                mem_cgroup_hierarchical_reclaim(memcg, NULL, GFP_KERNEL,
-                                               MEM_CGROUP_RECLAIM_SHRINK);
+                                               MEM_CGROUP_RECLAIM_SHRINK,
+                                               NULL);
                curusage = res_counter_read_u64(&memcg->res, RES_USAGE);
                /* Usage is reduced ? */
                if (curusage >= oldusage)
@@ -3271,7 +3519,8 @@ static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
 
                mem_cgroup_hierarchical_reclaim(memcg, NULL, GFP_KERNEL,
                                                MEM_CGROUP_RECLAIM_NOSWAP |
-                                               MEM_CGROUP_RECLAIM_SHRINK);
+                                               MEM_CGROUP_RECLAIM_SHRINK,
+                                               NULL);
                curusage = res_counter_read_u64(&memcg->memsw, RES_USAGE);
                /* Usage is reduced ? */
                if (curusage >= oldusage)
@@ -3285,7 +3534,8 @@ static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
 }
 
 unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
-                                           gfp_t gfp_mask)
+                                           gfp_t gfp_mask,
+                                           unsigned long *total_scanned)
 {
        unsigned long nr_reclaimed = 0;
        struct mem_cgroup_per_zone *mz, *next_mz = NULL;
@@ -3293,6 +3543,7 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
        int loop = 0;
        struct mem_cgroup_tree_per_zone *mctz;
        unsigned long long excess;
+       unsigned long nr_scanned;
 
        if (order > 0)
                return 0;
@@ -3311,10 +3562,13 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
                if (!mz)
                        break;
 
+               nr_scanned = 0;
                reclaimed = mem_cgroup_hierarchical_reclaim(mz->mem, zone,
                                                gfp_mask,
-                                               MEM_CGROUP_RECLAIM_SOFT);
+                                               MEM_CGROUP_RECLAIM_SOFT,
+                                               &nr_scanned);
                nr_reclaimed += reclaimed;
+               *total_scanned += nr_scanned;
                spin_lock(&mctz->lock);
 
                /*
@@ -3337,10 +3591,9 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
                                 */
                                next_mz =
                                __mem_cgroup_largest_soft_limit_node(mctz);
-                               if (next_mz == mz) {
+                               if (next_mz == mz)
                                        css_put(&next_mz->mem->css);
-                                       next_mz = NULL;
-                               } else /* next_mz == NULL or other memcg */
+                               else /* next_mz == NULL or other memcg */
                                        break;
                        } while (1);
                }
@@ -3772,6 +4025,8 @@ enum {
        MCS_PGPGIN,
        MCS_PGPGOUT,
        MCS_SWAP,
+       MCS_PGFAULT,
+       MCS_PGMAJFAULT,
        MCS_INACTIVE_ANON,
        MCS_ACTIVE_ANON,
        MCS_INACTIVE_FILE,
@@ -3794,6 +4049,8 @@ struct {
        {"pgpgin", "total_pgpgin"},
        {"pgpgout", "total_pgpgout"},
        {"swap", "total_swap"},
+       {"pgfault", "total_pgfault"},
+       {"pgmajfault", "total_pgmajfault"},
        {"inactive_anon", "total_inactive_anon"},
        {"active_anon", "total_active_anon"},
        {"inactive_file", "total_inactive_file"},
@@ -3822,6 +4079,10 @@ mem_cgroup_get_local_stat(struct mem_cgroup *mem, struct mcs_total_stat *s)
                val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_SWAPOUT);
                s->stat[MCS_SWAP] += val * PAGE_SIZE;
        }
+       val = mem_cgroup_read_events(mem, MEM_CGROUP_EVENTS_PGFAULT);
+       s->stat[MCS_PGFAULT] += val;
+       val = mem_cgroup_read_events(mem, MEM_CGROUP_EVENTS_PGMAJFAULT);
+       s->stat[MCS_PGMAJFAULT] += val;
 
        /* per zone stat */
        val = mem_cgroup_get_local_zonestat(mem, LRU_INACTIVE_ANON);
@@ -3845,6 +4106,51 @@ mem_cgroup_get_total_stat(struct mem_cgroup *mem, struct mcs_total_stat *s)
                mem_cgroup_get_local_stat(iter, s);
 }
 
+#ifdef CONFIG_NUMA
+static int mem_control_numa_stat_show(struct seq_file *m, void *arg)
+{
+       int nid;
+       unsigned long total_nr, file_nr, anon_nr, unevictable_nr;
+       unsigned long node_nr;
+       struct cgroup *cont = m->private;
+       struct mem_cgroup *mem_cont = mem_cgroup_from_cont(cont);
+
+       total_nr = mem_cgroup_nr_lru_pages(mem_cont);
+       seq_printf(m, "total=%lu", total_nr);
+       for_each_node_state(nid, N_HIGH_MEMORY) {
+               node_nr = mem_cgroup_node_nr_lru_pages(mem_cont, nid);
+               seq_printf(m, " N%d=%lu", nid, node_nr);
+       }
+       seq_putc(m, '\n');
+
+       file_nr = mem_cgroup_nr_file_lru_pages(mem_cont);
+       seq_printf(m, "file=%lu", file_nr);
+       for_each_node_state(nid, N_HIGH_MEMORY) {
+               node_nr = mem_cgroup_node_nr_file_lru_pages(mem_cont, nid);
+               seq_printf(m, " N%d=%lu", nid, node_nr);
+       }
+       seq_putc(m, '\n');
+
+       anon_nr = mem_cgroup_nr_anon_lru_pages(mem_cont);
+       seq_printf(m, "anon=%lu", anon_nr);
+       for_each_node_state(nid, N_HIGH_MEMORY) {
+               node_nr = mem_cgroup_node_nr_anon_lru_pages(mem_cont, nid);
+               seq_printf(m, " N%d=%lu", nid, node_nr);
+       }
+       seq_putc(m, '\n');
+
+       unevictable_nr = mem_cgroup_nr_unevictable_lru_pages(mem_cont);
+       seq_printf(m, "unevictable=%lu", unevictable_nr);
+       for_each_node_state(nid, N_HIGH_MEMORY) {
+               node_nr = mem_cgroup_node_nr_unevictable_lru_pages(mem_cont,
+                                                                       nid);
+               seq_printf(m, " N%d=%lu", nid, node_nr);
+       }
+       seq_putc(m, '\n');
+       return 0;
+}
+#endif /* CONFIG_NUMA */
+
 static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft,
                                 struct cgroup_map_cb *cb)
 {
@@ -3855,6 +4161,7 @@ static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft,
        memset(&mystat, 0, sizeof(mystat));
        mem_cgroup_get_local_stat(mem_cont, &mystat);
 
+
        for (i = 0; i < NR_MCS_STAT; i++) {
                if (i == MCS_SWAP && !do_swap_account)
                        continue;
@@ -4278,6 +4585,22 @@ static int mem_cgroup_oom_control_write(struct cgroup *cgrp,
        return 0;
 }
 
+#ifdef CONFIG_NUMA
+static const struct file_operations mem_control_numa_stat_file_operations = {
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static int mem_control_numa_stat_open(struct inode *unused, struct file *file)
+{
+       struct cgroup *cont = file->f_dentry->d_parent->d_fsdata;
+
+       file->f_op = &mem_control_numa_stat_file_operations;
+       return single_open(file, mem_control_numa_stat_show, cont);
+}
+#endif /* CONFIG_NUMA */
+
 static struct cftype mem_cgroup_files[] = {
        {
                .name = "usage_in_bytes",
@@ -4341,6 +4664,13 @@ static struct cftype mem_cgroup_files[] = {
                .unregister_event = mem_cgroup_oom_unregister_event,
                .private = MEMFILE_PRIVATE(_OOM_TYPE, OOM_CONTROL),
        },
+#ifdef CONFIG_NUMA
+       {
+               .name = "numa_stat",
+               .open = mem_control_numa_stat_open,
+               .mode = S_IRUGO,
+       },
+#endif
 };
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
@@ -4596,6 +4926,7 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
                res_counter_init(&mem->memsw, NULL);
        }
        mem->last_scanned_child = 0;
+       mem->last_scanned_node = MAX_NUMNODES;
        INIT_LIST_HEAD(&mem->oom_notify);
 
        if (parent)
@@ -4953,8 +5284,7 @@ static void mem_cgroup_clear_mc(void)
 
 static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
                                struct cgroup *cgroup,
-                               struct task_struct *p,
-                               bool threadgroup)
+                               struct task_struct *p)
 {
        int ret = 0;
        struct mem_cgroup *mem = mem_cgroup_from_cont(cgroup);
@@ -4993,8 +5323,7 @@ static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
 
 static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss,
                                struct cgroup *cgroup,
-                               struct task_struct *p,
-                               bool threadgroup)
+                               struct task_struct *p)
 {
        mem_cgroup_clear_mc();
 }
@@ -5112,41 +5441,35 @@ retry:
 static void mem_cgroup_move_task(struct cgroup_subsys *ss,
                                struct cgroup *cont,
                                struct cgroup *old_cont,
-                               struct task_struct *p,
-                               bool threadgroup)
+                               struct task_struct *p)
 {
-       struct mm_struct *mm;
-
-       if (!mc.to)
-               /* no need to move charge */
-               return;
+       struct mm_struct *mm = get_task_mm(p);
 
-       mm = get_task_mm(p);
        if (mm) {
-               mem_cgroup_move_charge(mm);
+               if (mc.to)
+                       mem_cgroup_move_charge(mm);
+               put_swap_token(mm);
                mmput(mm);
        }
-       mem_cgroup_clear_mc();
+       if (mc.to)
+               mem_cgroup_clear_mc();
 }
 #else  /* !CONFIG_MMU */
 static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
                                struct cgroup *cgroup,
-                               struct task_struct *p,
-                               bool threadgroup)
+                               struct task_struct *p)
 {
        return 0;
 }
 static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss,
                                struct cgroup *cgroup,
-                               struct task_struct *p,
-                               bool threadgroup)
+                               struct task_struct *p)
 {
 }
 static void mem_cgroup_move_task(struct cgroup_subsys *ss,
                                struct cgroup *cont,
                                struct cgroup *old_cont,
-                               struct task_struct *p,
-                               bool threadgroup)
+                               struct task_struct *p)
 {
 }
 #endif
@@ -5169,19 +5492,12 @@ struct cgroup_subsys mem_cgroup_subsys = {
 static int __init enable_swap_account(char *s)
 {
        /* consider enabled if no parameter or 1 is given */
-       if (!(*s) || !strcmp(s, "=1"))
+       if (!strcmp(s, "1"))
                really_do_swap_account = 1;
-       else if (!strcmp(s, "=0"))
+       else if (!strcmp(s, "0"))
                really_do_swap_account = 0;
        return 1;
 }
-__setup("swapaccount", enable_swap_account);
+__setup("swapaccount=", enable_swap_account);
 
-static int __init disable_swap_account(char *s)
-{
-       printk_once("noswapaccount is deprecated and will be removed in 2.6.40. Use swapaccount=0 instead\n");
-       enable_swap_account("=0");
-       return 1;
-}
-__setup("noswapaccount", disable_swap_account);
 #endif
index 2b9a5eef39e0661d48e7a9976780345587aff80c..eac0ba5614912e57c7b83b22382bc1165138ef2a 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/swapops.h>
 #include <linux/hugetlb.h>
 #include <linux/memory_hotplug.h>
+#include <linux/mm_inline.h>
 #include "internal.h"
 
 int sysctl_memory_failure_early_kill __read_mostly = 0;
@@ -239,7 +240,11 @@ void shake_page(struct page *p, int access)
        if (access) {
                int nr;
                do {
-                       nr = shrink_slab(1000, GFP_KERNEL, 1000);
+                       struct shrink_control shrink = {
+                               .gfp_mask = GFP_KERNEL,
+                       };
+
+                       nr = shrink_slab(&shrink, 1000, 1000);
                        if (page_count(p) == 1)
                                break;
                } while (nr > 10);
@@ -429,7 +434,7 @@ static void collect_procs_file(struct page *page, struct list_head *to_kill,
         */
 
        read_lock(&tasklist_lock);
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
        for_each_process(tsk) {
                pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
 
@@ -449,7 +454,7 @@ static void collect_procs_file(struct page *page, struct list_head *to_kill,
                                add_to_kill(tsk, page, vma, to_kill, tkc);
                }
        }
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
        read_unlock(&tasklist_lock);
 }
 
@@ -1440,16 +1445,12 @@ int soft_offline_page(struct page *page, int flags)
         */
        ret = invalidate_inode_page(page);
        unlock_page(page);
-
        /*
-        * Drop count because page migration doesn't like raised
-        * counts. The page could get re-allocated, but if it becomes
-        * LRU the isolation will just fail.
         * RED-PEN would be better to keep it isolated here, but we
         * would need to fix isolation locking first.
         */
-       put_page(page);
        if (ret == 1) {
+               put_page(page);
                ret = 0;
                pr_info("soft_offline: %#lx: invalidated\n", pfn);
                goto done;
@@ -1461,9 +1462,15 @@ int soft_offline_page(struct page *page, int flags)
         * handles a large number of cases for us.
         */
        ret = isolate_lru_page(page);
+       /*
+        * Drop page reference which is came from get_any_page()
+        * successful isolate_lru_page() already took another one.
+        */
+       put_page(page);
        if (!ret) {
                LIST_HEAD(pagelist);
-
+               inc_zone_page_state(page, NR_ISOLATED_ANON +
+                                           page_is_file_cache(page));
                list_add(&page->lru, &pagelist);
                ret = migrate_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL,
                                                                0, true);
index 61e66f026563b4b473fc73922d58a984c490c827..87d935333f0dda3d477c5cacd1219b78e7b910e7 100644 (file)
@@ -182,7 +182,7 @@ void sync_mm_rss(struct task_struct *task, struct mm_struct *mm)
 {
        __sync_task_rss_stat(task, mm);
 }
-#else
+#else /* SPLIT_RSS_COUNTING */
 
 #define inc_mm_counter_fast(mm, member) inc_mm_counter(mm, member)
 #define dec_mm_counter_fast(mm, member) dec_mm_counter(mm, member)
@@ -191,8 +191,205 @@ static void check_sync_rss_stat(struct task_struct *task)
 {
 }
 
+#endif /* SPLIT_RSS_COUNTING */
+
+#ifdef HAVE_GENERIC_MMU_GATHER
+
+static int tlb_next_batch(struct mmu_gather *tlb)
+{
+       struct mmu_gather_batch *batch;
+
+       batch = tlb->active;
+       if (batch->next) {
+               tlb->active = batch->next;
+               return 1;
+       }
+
+       batch = (void *)__get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);
+       if (!batch)
+               return 0;
+
+       batch->next = NULL;
+       batch->nr   = 0;
+       batch->max  = MAX_GATHER_BATCH;
+
+       tlb->active->next = batch;
+       tlb->active = batch;
+
+       return 1;
+}
+
+/* tlb_gather_mmu
+ *     Called to initialize an (on-stack) mmu_gather structure for page-table
+ *     tear-down from @mm. The @fullmm argument is used when @mm is without
+ *     users and we're going to destroy the full address space (exit/execve).
+ */
+void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm)
+{
+       tlb->mm = mm;
+
+       tlb->fullmm     = fullmm;
+       tlb->need_flush = 0;
+       tlb->fast_mode  = (num_possible_cpus() == 1);
+       tlb->local.next = NULL;
+       tlb->local.nr   = 0;
+       tlb->local.max  = ARRAY_SIZE(tlb->__pages);
+       tlb->active     = &tlb->local;
+
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+       tlb->batch = NULL;
+#endif
+}
+
+void tlb_flush_mmu(struct mmu_gather *tlb)
+{
+       struct mmu_gather_batch *batch;
+
+       if (!tlb->need_flush)
+               return;
+       tlb->need_flush = 0;
+       tlb_flush(tlb);
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+       tlb_table_flush(tlb);
 #endif
 
+       if (tlb_fast_mode(tlb))
+               return;
+
+       for (batch = &tlb->local; batch; batch = batch->next) {
+               free_pages_and_swap_cache(batch->pages, batch->nr);
+               batch->nr = 0;
+       }
+       tlb->active = &tlb->local;
+}
+
+/* tlb_finish_mmu
+ *     Called at the end of the shootdown operation to free up any resources
+ *     that were required.
+ */
+void tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
+{
+       struct mmu_gather_batch *batch, *next;
+
+       tlb_flush_mmu(tlb);
+
+       /* keep the page table cache within bounds */
+       check_pgt_cache();
+
+       for (batch = tlb->local.next; batch; batch = next) {
+               next = batch->next;
+               free_pages((unsigned long)batch, 0);
+       }
+       tlb->local.next = NULL;
+}
+
+/* __tlb_remove_page
+ *     Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), while
+ *     handling the additional races in SMP caused by other CPUs caching valid
+ *     mappings in their TLBs. Returns the number of free page slots left.
+ *     When out of page slots we must call tlb_flush_mmu().
+ */
+int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       struct mmu_gather_batch *batch;
+
+       tlb->need_flush = 1;
+
+       if (tlb_fast_mode(tlb)) {
+               free_page_and_swap_cache(page);
+               return 1; /* avoid calling tlb_flush_mmu() */
+       }
+
+       batch = tlb->active;
+       batch->pages[batch->nr++] = page;
+       if (batch->nr == batch->max) {
+               if (!tlb_next_batch(tlb))
+                       return 0;
+       }
+       VM_BUG_ON(batch->nr > batch->max);
+
+       return batch->max - batch->nr;
+}
+
+#endif /* HAVE_GENERIC_MMU_GATHER */
+
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+
+/*
+ * See the comment near struct mmu_table_batch.
+ */
+
+static void tlb_remove_table_smp_sync(void *arg)
+{
+       /* Simply deliver the interrupt */
+}
+
+static void tlb_remove_table_one(void *table)
+{
+       /*
+        * This isn't an RCU grace period and hence the page-tables cannot be
+        * assumed to be actually RCU-freed.
+        *
+        * It is however sufficient for software page-table walkers that rely on
+        * IRQ disabling. See the comment near struct mmu_table_batch.
+        */
+       smp_call_function(tlb_remove_table_smp_sync, NULL, 1);
+       __tlb_remove_table(table);
+}
+
+static void tlb_remove_table_rcu(struct rcu_head *head)
+{
+       struct mmu_table_batch *batch;
+       int i;
+
+       batch = container_of(head, struct mmu_table_batch, rcu);
+
+       for (i = 0; i < batch->nr; i++)
+               __tlb_remove_table(batch->tables[i]);
+
+       free_page((unsigned long)batch);
+}
+
+void tlb_table_flush(struct mmu_gather *tlb)
+{
+       struct mmu_table_batch **batch = &tlb->batch;
+
+       if (*batch) {
+               call_rcu_sched(&(*batch)->rcu, tlb_remove_table_rcu);
+               *batch = NULL;
+       }
+}
+
+void tlb_remove_table(struct mmu_gather *tlb, void *table)
+{
+       struct mmu_table_batch **batch = &tlb->batch;
+
+       tlb->need_flush = 1;
+
+       /*
+        * When there's less then two users of this mm there cannot be a
+        * concurrent page-table walk.
+        */
+       if (atomic_read(&tlb->mm->mm_users) < 2) {
+               __tlb_remove_table(table);
+               return;
+       }
+
+       if (*batch == NULL) {
+               *batch = (struct mmu_table_batch *)__get_free_page(GFP_NOWAIT | __GFP_NOWARN);
+               if (*batch == NULL) {
+                       tlb_remove_table_one(table);
+                       return;
+               }
+               (*batch)->nr = 0;
+       }
+       (*batch)->tables[(*batch)->nr++] = table;
+       if ((*batch)->nr == MAX_TABLE_BATCH)
+               tlb_table_flush(tlb);
+}
+
+#endif /* CONFIG_HAVE_RCU_TABLE_FREE */
+
 /*
  * If a p?d_bad entry is found while walking page tables, report
  * the error, before resetting entry to p?d_none.  Usually (but
@@ -533,7 +730,7 @@ static void print_bad_pte(struct vm_area_struct *vma, unsigned long addr,
        add_taint(TAINT_BAD_PAGE);
 }
 
-static inline int is_cow_mapping(unsigned int flags)
+static inline int is_cow_mapping(vm_flags_t flags)
 {
        return (flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
 }
@@ -909,26 +1106,26 @@ int copy_page_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 static unsigned long zap_pte_range(struct mmu_gather *tlb,
                                struct vm_area_struct *vma, pmd_t *pmd,
                                unsigned long addr, unsigned long end,
-                               long *zap_work, struct zap_details *details)
+                               struct zap_details *details)
 {
        struct mm_struct *mm = tlb->mm;
-       pte_t *pte;
-       spinlock_t *ptl;
+       int force_flush = 0;
        int rss[NR_MM_COUNTERS];
+       spinlock_t *ptl;
+       pte_t *start_pte;
+       pte_t *pte;
 
+again:
        init_rss_vec(rss);
-
-       pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+       start_pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+       pte = start_pte;
        arch_enter_lazy_mmu_mode();
        do {
                pte_t ptent = *pte;
                if (pte_none(ptent)) {
-                       (*zap_work)--;
                        continue;
                }
 
-               (*zap_work) -= PAGE_SIZE;
-
                if (pte_present(ptent)) {
                        struct page *page;
 
@@ -974,7 +1171,9 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
                        page_remove_rmap(page);
                        if (unlikely(page_mapcount(page) < 0))
                                print_bad_pte(vma, addr, ptent, page);
-                       tlb_remove_page(tlb, page);
+                       force_flush = !__tlb_remove_page(tlb, page);
+                       if (force_flush)
+                               break;
                        continue;
                }
                /*
@@ -995,11 +1194,23 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
                                print_bad_pte(vma, addr, ptent, NULL);
                }
                pte_clear_not_present_full(mm, addr, pte, tlb->fullmm);
-       } while (pte++, addr += PAGE_SIZE, (addr != end && *zap_work > 0));
+       } while (pte++, addr += PAGE_SIZE, addr != end);
 
        add_mm_rss_vec(mm, rss);
        arch_leave_lazy_mmu_mode();
-       pte_unmap_unlock(pte - 1, ptl);
+       pte_unmap_unlock(start_pte, ptl);
+
+       /*
+        * mmu_gather ran out of room to batch pages, we break out of
+        * the PTE lock to avoid doing the potential expensive TLB invalidate
+        * and page-free while holding it.
+        */
+       if (force_flush) {
+               force_flush = 0;
+               tlb_flush_mmu(tlb);
+               if (addr != end)
+                       goto again;
+       }
 
        return addr;
 }
@@ -1007,7 +1218,7 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
 static inline unsigned long zap_pmd_range(struct mmu_gather *tlb,
                                struct vm_area_struct *vma, pud_t *pud,
                                unsigned long addr, unsigned long end,
-                               long *zap_work, struct zap_details *details)
+                               struct zap_details *details)
 {
        pmd_t *pmd;
        unsigned long next;
@@ -1019,19 +1230,15 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb,
                        if (next-addr != HPAGE_PMD_SIZE) {
                                VM_BUG_ON(!rwsem_is_locked(&tlb->mm->mmap_sem));
                                split_huge_page_pmd(vma->vm_mm, pmd);
-                       } else if (zap_huge_pmd(tlb, vma, pmd)) {
-                               (*zap_work)--;
+                       } else if (zap_huge_pmd(tlb, vma, pmd))
                                continue;
-                       }
                        /* fall through */
                }
-               if (pmd_none_or_clear_bad(pmd)) {
-                       (*zap_work)--;
+               if (pmd_none_or_clear_bad(pmd))
                        continue;
-               }
-               next = zap_pte_range(tlb, vma, pmd, addr, next,
-                                               zap_work, details);
-       } while (pmd++, addr = next, (addr != end && *zap_work > 0));
+               next = zap_pte_range(tlb, vma, pmd, addr, next, details);
+               cond_resched();
+       } while (pmd++, addr = next, addr != end);
 
        return addr;
 }
@@ -1039,7 +1246,7 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb,
 static inline unsigned long zap_pud_range(struct mmu_gather *tlb,
                                struct vm_area_struct *vma, pgd_t *pgd,
                                unsigned long addr, unsigned long end,
-                               long *zap_work, struct zap_details *details)
+                               struct zap_details *details)
 {
        pud_t *pud;
        unsigned long next;
@@ -1047,13 +1254,10 @@ static inline unsigned long zap_pud_range(struct mmu_gather *tlb,
        pud = pud_offset(pgd, addr);
        do {
                next = pud_addr_end(addr, end);
-               if (pud_none_or_clear_bad(pud)) {
-                       (*zap_work)--;
+               if (pud_none_or_clear_bad(pud))
                        continue;
-               }
-               next = zap_pmd_range(tlb, vma, pud, addr, next,
-                                               zap_work, details);
-       } while (pud++, addr = next, (addr != end && *zap_work > 0));
+               next = zap_pmd_range(tlb, vma, pud, addr, next, details);
+       } while (pud++, addr = next, addr != end);
 
        return addr;
 }
@@ -1061,7 +1265,7 @@ static inline unsigned long zap_pud_range(struct mmu_gather *tlb,
 static unsigned long unmap_page_range(struct mmu_gather *tlb,
                                struct vm_area_struct *vma,
                                unsigned long addr, unsigned long end,
-                               long *zap_work, struct zap_details *details)
+                               struct zap_details *details)
 {
        pgd_t *pgd;
        unsigned long next;
@@ -1075,13 +1279,10 @@ static unsigned long unmap_page_range(struct mmu_gather *tlb,
        pgd = pgd_offset(vma->vm_mm, addr);
        do {
                next = pgd_addr_end(addr, end);
-               if (pgd_none_or_clear_bad(pgd)) {
-                       (*zap_work)--;
+               if (pgd_none_or_clear_bad(pgd))
                        continue;
-               }
-               next = zap_pud_range(tlb, vma, pgd, addr, next,
-                                               zap_work, details);
-       } while (pgd++, addr = next, (addr != end && *zap_work > 0));
+               next = zap_pud_range(tlb, vma, pgd, addr, next, details);
+       } while (pgd++, addr = next, addr != end);
        tlb_end_vma(tlb, vma);
        mem_cgroup_uncharge_end();
 
@@ -1097,7 +1298,7 @@ static unsigned long unmap_page_range(struct mmu_gather *tlb,
 
 /**
  * unmap_vmas - unmap a range of memory covered by a list of vma's
- * @tlbp: address of the caller's struct mmu_gather
+ * @tlb: address of the caller's struct mmu_gather
  * @vma: the starting vma
  * @start_addr: virtual address at which to start unmapping
  * @end_addr: virtual address at which to end unmapping
@@ -1121,17 +1322,12 @@ static unsigned long unmap_page_range(struct mmu_gather *tlb,
  * ensure that any thus-far unmapped pages are flushed before unmap_vmas()
  * drops the lock and schedules.
  */
-unsigned long unmap_vmas(struct mmu_gather **tlbp,
+unsigned long unmap_vmas(struct mmu_gather *tlb,
                struct vm_area_struct *vma, unsigned long start_addr,
                unsigned long end_addr, unsigned long *nr_accounted,
                struct zap_details *details)
 {
-       long zap_work = ZAP_BLOCK_SIZE;
-       unsigned long tlb_start = 0;    /* For tlb_finish_mmu */
-       int tlb_start_valid = 0;
        unsigned long start = start_addr;
-       spinlock_t *i_mmap_lock = details? details->i_mmap_lock: NULL;
-       int fullmm = (*tlbp)->fullmm;
        struct mm_struct *mm = vma->vm_mm;
 
        mmu_notifier_invalidate_range_start(mm, start_addr, end_addr);
@@ -1152,11 +1348,6 @@ unsigned long unmap_vmas(struct mmu_gather **tlbp,
                        untrack_pfn_vma(vma, 0, 0);
 
                while (start != end) {
-                       if (!tlb_start_valid) {
-                               tlb_start = start;
-                               tlb_start_valid = 1;
-                       }
-
                        if (unlikely(is_vm_hugetlb_page(vma))) {
                                /*
                                 * It is undesirable to test vma->vm_file as it
@@ -1169,39 +1360,15 @@ unsigned long unmap_vmas(struct mmu_gather **tlbp,
                                 * Since no pte has actually been setup, it is
                                 * safe to do nothing in this case.
                                 */
-                               if (vma->vm_file) {
+                               if (vma->vm_file)
                                        unmap_hugepage_range(vma, start, end, NULL);
-                                       zap_work -= (end - start) /
-                                       pages_per_huge_page(hstate_vma(vma));
-                               }
 
                                start = end;
                        } else
-                               start = unmap_page_range(*tlbp, vma,
-                                               start, end, &zap_work, details);
-
-                       if (zap_work > 0) {
-                               BUG_ON(start != end);
-                               break;
-                       }
-
-                       tlb_finish_mmu(*tlbp, tlb_start, start);
-
-                       if (need_resched() ||
-                               (i_mmap_lock && spin_needbreak(i_mmap_lock))) {
-                               if (i_mmap_lock) {
-                                       *tlbp = NULL;
-                                       goto out;
-                               }
-                               cond_resched();
-                       }
-
-                       *tlbp = tlb_gather_mmu(vma->vm_mm, fullmm);
-                       tlb_start_valid = 0;
-                       zap_work = ZAP_BLOCK_SIZE;
+                               start = unmap_page_range(tlb, vma, start, end, details);
                }
        }
-out:
+
        mmu_notifier_invalidate_range_end(mm, start_addr, end_addr);
        return start;   /* which is now the end (or restart) address */
 }
@@ -1217,16 +1384,15 @@ unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address,
                unsigned long size, struct zap_details *details)
 {
        struct mm_struct *mm = vma->vm_mm;
-       struct mmu_gather *tlb;
+       struct mmu_gather tlb;
        unsigned long end = address + size;
        unsigned long nr_accounted = 0;
 
        lru_add_drain();
-       tlb = tlb_gather_mmu(mm, 0);
+       tlb_gather_mmu(&tlb, mm, 0);
        update_hiwater_rss(mm);
        end = unmap_vmas(&tlb, vma, address, end, &nr_accounted, details);
-       if (tlb)
-               tlb_finish_mmu(tlb, address, end);
+       tlb_finish_mmu(&tlb, address, end);
        return end;
 }
 
@@ -2535,96 +2701,11 @@ unwritable_page:
        return ret;
 }
 
-/*
- * Helper functions for unmap_mapping_range().
- *
- * __ Notes on dropping i_mmap_lock to reduce latency while unmapping __
- *
- * We have to restart searching the prio_tree whenever we drop the lock,
- * since the iterator is only valid while the lock is held, and anyway
- * a later vma might be split and reinserted earlier while lock dropped.
- *
- * The list of nonlinear vmas could be handled more efficiently, using
- * a placeholder, but handle it in the same way until a need is shown.
- * It is important to search the prio_tree before nonlinear list: a vma
- * may become nonlinear and be shifted from prio_tree to nonlinear list
- * while the lock is dropped; but never shifted from list to prio_tree.
- *
- * In order to make forward progress despite restarting the search,
- * vm_truncate_count is used to mark a vma as now dealt with, so we can
- * quickly skip it next time around.  Since the prio_tree search only
- * shows us those vmas affected by unmapping the range in question, we
- * can't efficiently keep all vmas in step with mapping->truncate_count:
- * so instead reset them all whenever it wraps back to 0 (then go to 1).
- * mapping->truncate_count and vma->vm_truncate_count are protected by
- * i_mmap_lock.
- *
- * In order to make forward progress despite repeatedly restarting some
- * large vma, note the restart_addr from unmap_vmas when it breaks out:
- * and restart from that address when we reach that vma again.  It might
- * have been split or merged, shrunk or extended, but never shifted: so
- * restart_addr remains valid so long as it remains in the vma's range.
- * unmap_mapping_range forces truncate_count to leap over page-aligned
- * values so we can save vma's restart_addr in its truncate_count field.
- */
-#define is_restart_addr(truncate_count) (!((truncate_count) & ~PAGE_MASK))
-
-static void reset_vma_truncate_counts(struct address_space *mapping)
-{
-       struct vm_area_struct *vma;
-       struct prio_tree_iter iter;
-
-       vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, 0, ULONG_MAX)
-               vma->vm_truncate_count = 0;
-       list_for_each_entry(vma, &mapping->i_mmap_nonlinear, shared.vm_set.list)
-               vma->vm_truncate_count = 0;
-}
-
-static int unmap_mapping_range_vma(struct vm_area_struct *vma,
+static void unmap_mapping_range_vma(struct vm_area_struct *vma,
                unsigned long start_addr, unsigned long end_addr,
                struct zap_details *details)
 {
-       unsigned long restart_addr;
-       int need_break;
-
-       /*
-        * files that support invalidating or truncating portions of the
-        * file from under mmaped areas must have their ->fault function
-        * return a locked page (and set VM_FAULT_LOCKED in the return).
-        * This provides synchronisation against concurrent unmapping here.
-        */
-
-again:
-       restart_addr = vma->vm_truncate_count;
-       if (is_restart_addr(restart_addr) && start_addr < restart_addr) {
-               start_addr = restart_addr;
-               if (start_addr >= end_addr) {
-                       /* Top of vma has been split off since last time */
-                       vma->vm_truncate_count = details->truncate_count;
-                       return 0;
-               }
-       }
-
-       restart_addr = zap_page_range(vma, start_addr,
-                                       end_addr - start_addr, details);
-       need_break = need_resched() || spin_needbreak(details->i_mmap_lock);
-
-       if (restart_addr >= end_addr) {
-               /* We have now completed this vma: mark it so */
-               vma->vm_truncate_count = details->truncate_count;
-               if (!need_break)
-                       return 0;
-       } else {
-               /* Note restart_addr in vma's truncate_count field */
-               vma->vm_truncate_count = restart_addr;
-               if (!need_break)
-                       goto again;
-       }
-
-       spin_unlock(details->i_mmap_lock);
-       cond_resched();
-       spin_lock(details->i_mmap_lock);
-       return -EINTR;
+       zap_page_range(vma, start_addr, end_addr - start_addr, details);
 }
 
 static inline void unmap_mapping_range_tree(struct prio_tree_root *root,
@@ -2634,12 +2715,8 @@ static inline void unmap_mapping_range_tree(struct prio_tree_root *root,
        struct prio_tree_iter iter;
        pgoff_t vba, vea, zba, zea;
 
-restart:
        vma_prio_tree_foreach(vma, &iter, root,
                        details->first_index, details->last_index) {
-               /* Skip quickly over those we have already dealt with */
-               if (vma->vm_truncate_count == details->truncate_count)
-                       continue;
 
                vba = vma->vm_pgoff;
                vea = vba + ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) - 1;
@@ -2651,11 +2728,10 @@ restart:
                if (zea > vea)
                        zea = vea;
 
-               if (unmap_mapping_range_vma(vma,
+               unmap_mapping_range_vma(vma,
                        ((zba - vba) << PAGE_SHIFT) + vma->vm_start,
                        ((zea - vba + 1) << PAGE_SHIFT) + vma->vm_start,
-                               details) < 0)
-                       goto restart;
+                               details);
        }
 }
 
@@ -2670,15 +2746,9 @@ static inline void unmap_mapping_range_list(struct list_head *head,
         * across *all* the pages in each nonlinear VMA, not just the pages
         * whose virtual address lies outside the file truncation point.
         */
-restart:
        list_for_each_entry(vma, head, shared.vm_set.list) {
-               /* Skip quickly over those we have already dealt with */
-               if (vma->vm_truncate_count == details->truncate_count)
-                       continue;
                details->nonlinear_vma = vma;
-               if (unmap_mapping_range_vma(vma, vma->vm_start,
-                                       vma->vm_end, details) < 0)
-                       goto restart;
+               unmap_mapping_range_vma(vma, vma->vm_start, vma->vm_end, details);
        }
 }
 
@@ -2717,26 +2787,14 @@ void unmap_mapping_range(struct address_space *mapping,
        details.last_index = hba + hlen - 1;
        if (details.last_index < details.first_index)
                details.last_index = ULONG_MAX;
-       details.i_mmap_lock = &mapping->i_mmap_lock;
 
-       mutex_lock(&mapping->unmap_mutex);
-       spin_lock(&mapping->i_mmap_lock);
-
-       /* Protect against endless unmapping loops */
-       mapping->truncate_count++;
-       if (unlikely(is_restart_addr(mapping->truncate_count))) {
-               if (mapping->truncate_count == 0)
-                       reset_vma_truncate_counts(mapping);
-               mapping->truncate_count++;
-       }
-       details.truncate_count = mapping->truncate_count;
 
+       mutex_lock(&mapping->i_mmap_mutex);
        if (unlikely(!prio_tree_empty(&mapping->i_mmap)))
                unmap_mapping_range_tree(&mapping->i_mmap, &details);
        if (unlikely(!list_empty(&mapping->i_mmap_nonlinear)))
                unmap_mapping_range_list(&mapping->i_mmap_nonlinear, &details);
-       spin_unlock(&mapping->i_mmap_lock);
-       mutex_unlock(&mapping->unmap_mutex);
+       mutex_unlock(&mapping->i_mmap_mutex);
 }
 EXPORT_SYMBOL(unmap_mapping_range);
 
@@ -2818,6 +2876,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
                /* Had to read the page from swap area: Major fault */
                ret = VM_FAULT_MAJOR;
                count_vm_event(PGMAJFAULT);
+               mem_cgroup_count_vm_event(mm, PGMAJFAULT);
        } else if (PageHWPoison(page)) {
                /*
                 * hwpoisoned dirty swapcache pages are kept for killing
@@ -2966,7 +3025,7 @@ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned lo
                if (prev && prev->vm_end == address)
                        return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM;
 
-               expand_stack(vma, address - PAGE_SIZE);
+               expand_downwards(vma, address - PAGE_SIZE);
        }
        if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) {
                struct vm_area_struct *next = vma->vm_next;
@@ -3357,6 +3416,7 @@ int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        __set_current_state(TASK_RUNNING);
 
        count_vm_event(PGFAULT);
+       mem_cgroup_count_vm_event(mm, PGFAULT);
 
        /* do counter updates before entering really critical section. */
        check_sync_rss_stat(current);
index 9ca1d604f7cd74aab7a897de22e0784a8c0bcb45..c46887b5a11eaa5bbe48008d16ad71bd37f7302f 100644 (file)
@@ -374,10 +374,6 @@ void online_page(struct page *page)
                totalhigh_pages++;
 #endif
 
-#ifdef CONFIG_FLATMEM
-       max_mapnr = max(pfn, max_mapnr);
-#endif
-
        ClearPageReserved(page);
        init_page_count(page);
        __free_page(page);
@@ -400,7 +396,7 @@ static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages,
 }
 
 
-int online_pages(unsigned long pfn, unsigned long nr_pages)
+int __ref online_pages(unsigned long pfn, unsigned long nr_pages)
 {
        unsigned long onlined_pages = 0;
        struct zone *zone;
@@ -459,8 +455,9 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
                zone_pcp_update(zone);
 
        mutex_unlock(&zonelists_mutex);
-       setup_per_zone_wmarks();
-       calculate_zone_inactive_ratio(zone);
+
+       init_per_zone_wmark_min();
+
        if (onlined_pages) {
                kswapd_run(zone_to_nid(zone));
                node_set_state(zone_to_nid(zone), N_HIGH_MEMORY);
@@ -497,6 +494,14 @@ static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start)
        /* init node's zones as empty zones, we don't have any present pages.*/
        free_area_init_node(nid, zones_size, start_pfn, zholes_size);
 
+       /*
+        * The node we allocated has no zone fallback lists. For avoiding
+        * to access not-initialized zonelist, build here.
+        */
+       mutex_lock(&zonelists_mutex);
+       build_all_zonelists(NULL);
+       mutex_unlock(&zonelists_mutex);
+
        return pgdat;
 }
 
@@ -518,7 +523,7 @@ int mem_online_node(int nid)
 
        lock_memory_hotplug();
        pgdat = hotadd_new_pgdat(nid, 0);
-       if (pgdat) {
+       if (!pgdat) {
                ret = -ENOMEM;
                goto out;
        }
@@ -705,7 +710,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                if (!pfn_valid(pfn))
                        continue;
                page = pfn_to_page(pfn);
-               if (!page_count(page))
+               if (!get_page_unless_zero(page))
                        continue;
                /*
                 * We can skip free pages. And we can only deal with pages on
@@ -713,6 +718,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                 */
                ret = isolate_lru_page(page);
                if (!ret) { /* Success */
+                       put_page(page);
                        list_add_tail(&page->lru, &source);
                        move_pages--;
                        inc_zone_page_state(page, NR_ISOLATED_ANON +
@@ -724,6 +730,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                               pfn);
                        dump_page(page);
 #endif
+                       put_page(page);
                        /* Because we don't have big zone->lock. we should
                           check this again here. */
                        if (page_count(page)) {
@@ -795,7 +802,7 @@ check_pages_isolated(unsigned long start_pfn, unsigned long end_pfn)
        return offlined;
 }
 
-static int offline_pages(unsigned long start_pfn,
+static int __ref offline_pages(unsigned long start_pfn,
                  unsigned long end_pfn, unsigned long timeout)
 {
        unsigned long pfn, nr_pages, expire;
@@ -893,8 +900,8 @@ repeat:
        zone->zone_pgdat->node_present_pages -= offlined_pages;
        totalram_pages -= offlined_pages;
 
-       setup_per_zone_wmarks();
-       calculate_zone_inactive_ratio(zone);
+       init_per_zone_wmark_min();
+
        if (!node_present_pages(node)) {
                node_clear_state(node, N_HIGH_MEMORY);
                kswapd_stop(node);
index 959a8b8c7350c28ffa6cacced61b4c24977479da..e7fb9d25c54eb80a62a987fbfd5cb08c4ae8e055 100644 (file)
@@ -99,7 +99,6 @@
 /* Internal flags */
 #define MPOL_MF_DISCONTIG_OK (MPOL_MF_INTERNAL << 0)   /* Skip checks for continuous vmas */
 #define MPOL_MF_INVERT (MPOL_MF_INTERNAL << 1)         /* Invert check for nodemask */
-#define MPOL_MF_STATS (MPOL_MF_INTERNAL << 2)          /* Gather statistics */
 
 static struct kmem_cache *policy_cache;
 static struct kmem_cache *sn_cache;
@@ -457,7 +456,6 @@ static const struct mempolicy_operations mpol_ops[MPOL_MAX] = {
        },
 };
 
-static void gather_stats(struct page *, void *, int pte_dirty);
 static void migrate_page_add(struct page *page, struct list_head *pagelist,
                                unsigned long flags);
 
@@ -492,9 +490,7 @@ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                if (node_isset(nid, *nodes) == !!(flags & MPOL_MF_INVERT))
                        continue;
 
-               if (flags & MPOL_MF_STATS)
-                       gather_stats(page, private, pte_dirty(*pte));
-               else if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL))
+               if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL))
                        migrate_page_add(page, private, flags);
                else
                        break;
@@ -1489,7 +1485,7 @@ asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len,
  * freeing by another task.  It is the caller's responsibility to free the
  * extra reference for shared policies.
  */
-static struct mempolicy *get_vma_policy(struct task_struct *task,
+struct mempolicy *get_vma_policy(struct task_struct *task,
                struct vm_area_struct *vma, unsigned long addr)
 {
        struct mempolicy *pol = task->mempolicy;
@@ -2529,159 +2525,3 @@ int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol, int no_context)
        }
        return p - buffer;
 }
-
-struct numa_maps {
-       unsigned long pages;
-       unsigned long anon;
-       unsigned long active;
-       unsigned long writeback;
-       unsigned long mapcount_max;
-       unsigned long dirty;
-       unsigned long swapcache;
-       unsigned long node[MAX_NUMNODES];
-};
-
-static void gather_stats(struct page *page, void *private, int pte_dirty)
-{
-       struct numa_maps *md = private;
-       int count = page_mapcount(page);
-
-       md->pages++;
-       if (pte_dirty || PageDirty(page))
-               md->dirty++;
-
-       if (PageSwapCache(page))
-               md->swapcache++;
-
-       if (PageActive(page) || PageUnevictable(page))
-               md->active++;
-
-       if (PageWriteback(page))
-               md->writeback++;
-
-       if (PageAnon(page))
-               md->anon++;
-
-       if (count > md->mapcount_max)
-               md->mapcount_max = count;
-
-       md->node[page_to_nid(page)]++;
-}
-
-#ifdef CONFIG_HUGETLB_PAGE
-static void check_huge_range(struct vm_area_struct *vma,
-               unsigned long start, unsigned long end,
-               struct numa_maps *md)
-{
-       unsigned long addr;
-       struct page *page;
-       struct hstate *h = hstate_vma(vma);
-       unsigned long sz = huge_page_size(h);
-
-       for (addr = start; addr < end; addr += sz) {
-               pte_t *ptep = huge_pte_offset(vma->vm_mm,
-                                               addr & huge_page_mask(h));
-               pte_t pte;
-
-               if (!ptep)
-                       continue;
-
-               pte = *ptep;
-               if (pte_none(pte))
-                       continue;
-
-               page = pte_page(pte);
-               if (!page)
-                       continue;
-
-               gather_stats(page, md, pte_dirty(*ptep));
-       }
-}
-#else
-static inline void check_huge_range(struct vm_area_struct *vma,
-               unsigned long start, unsigned long end,
-               struct numa_maps *md)
-{
-}
-#endif
-
-/*
- * Display pages allocated per node and memory policy via /proc.
- */
-int show_numa_map(struct seq_file *m, void *v)
-{
-       struct proc_maps_private *priv = m->private;
-       struct vm_area_struct *vma = v;
-       struct numa_maps *md;
-       struct file *file = vma->vm_file;
-       struct mm_struct *mm = vma->vm_mm;
-       struct mempolicy *pol;
-       int n;
-       char buffer[50];
-
-       if (!mm)
-               return 0;
-
-       md = kzalloc(sizeof(struct numa_maps), GFP_KERNEL);
-       if (!md)
-               return 0;
-
-       pol = get_vma_policy(priv->task, vma, vma->vm_start);
-       mpol_to_str(buffer, sizeof(buffer), pol, 0);
-       mpol_cond_put(pol);
-
-       seq_printf(m, "%08lx %s", vma->vm_start, buffer);
-
-       if (file) {
-               seq_printf(m, " file=");
-               seq_path(m, &file->f_path, "\n\t= ");
-       } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) {
-               seq_printf(m, " heap");
-       } else if (vma->vm_start <= mm->start_stack &&
-                       vma->vm_end >= mm->start_stack) {
-               seq_printf(m, " stack");
-       }
-
-       if (is_vm_hugetlb_page(vma)) {
-               check_huge_range(vma, vma->vm_start, vma->vm_end, md);
-               seq_printf(m, " huge");
-       } else {
-               check_pgd_range(vma, vma->vm_start, vma->vm_end,
-                       &node_states[N_HIGH_MEMORY], MPOL_MF_STATS, md);
-       }
-
-       if (!md->pages)
-               goto out;
-
-       if (md->anon)
-               seq_printf(m," anon=%lu",md->anon);
-
-       if (md->dirty)
-               seq_printf(m," dirty=%lu",md->dirty);
-
-       if (md->pages != md->anon && md->pages != md->dirty)
-               seq_printf(m, " mapped=%lu", md->pages);
-
-       if (md->mapcount_max > 1)
-               seq_printf(m, " mapmax=%lu", md->mapcount_max);
-
-       if (md->swapcache)
-               seq_printf(m," swapcache=%lu", md->swapcache);
-
-       if (md->active < md->pages && !is_vm_hugetlb_page(vma))
-               seq_printf(m," active=%lu", md->active);
-
-       if (md->writeback)
-               seq_printf(m," writeback=%lu", md->writeback);
-
-       for_each_node_state(n, N_HIGH_MEMORY)
-               if (md->node[n])
-                       seq_printf(m, " N%d=%lu", n, md->node[n]);
-out:
-       seq_putc(m, '\n');
-       kfree(md);
-
-       if (m->count < m->size)
-               m->version = (vma != priv->tail_vma) ? vma->vm_start : 0;
-       return 0;
-}
index 34132f8e9109e1b2af4c92fdd74c5df7ef073392..666e4e677414e6d790de715761e395116441e6c4 100644 (file)
@@ -288,7 +288,7 @@ static int migrate_page_move_mapping(struct address_space *mapping,
         */
        __dec_zone_page_state(page, NR_FILE_PAGES);
        __inc_zone_page_state(newpage, NR_FILE_PAGES);
-       if (PageSwapBacked(page)) {
+       if (!PageSwapCache(page) && PageSwapBacked(page)) {
                __dec_zone_page_state(page, NR_SHMEM);
                __inc_zone_page_state(newpage, NR_SHMEM);
        }
@@ -721,15 +721,11 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
                 * Only page_lock_anon_vma() understands the subtleties of
                 * getting a hold on an anon_vma from outside one of its mms.
                 */
-               anon_vma = page_lock_anon_vma(page);
+               anon_vma = page_get_anon_vma(page);
                if (anon_vma) {
                        /*
-                        * Take a reference count on the anon_vma if the
-                        * page is mapped so that it is guaranteed to
-                        * exist when the page is remapped later
+                        * Anon page
                         */
-                       get_anon_vma(anon_vma);
-                       page_unlock_anon_vma(anon_vma);
                } else if (PageSwapCache(page)) {
                        /*
                         * We cannot be sure that the anon_vma of an unmapped
@@ -857,13 +853,8 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
                lock_page(hpage);
        }
 
-       if (PageAnon(hpage)) {
-               anon_vma = page_lock_anon_vma(hpage);
-               if (anon_vma) {
-                       get_anon_vma(anon_vma);
-                       page_unlock_anon_vma(anon_vma);
-               }
-       }
+       if (PageAnon(hpage))
+               anon_vma = page_get_anon_vma(hpage);
 
        try_to_unmap(hpage, TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
 
index 516b2c2ddd5a55b244a89af33eeb3b6f3b88d410..048260c4e02ea7ced2692cc05fba67c9798c9145 100644 (file)
@@ -307,13 +307,13 @@ void munlock_vma_pages_range(struct vm_area_struct *vma,
  * For vmas that pass the filters, merge/split as appropriate.
  */
 static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev,
-       unsigned long start, unsigned long end, unsigned int newflags)
+       unsigned long start, unsigned long end, vm_flags_t newflags)
 {
        struct mm_struct *mm = vma->vm_mm;
        pgoff_t pgoff;
        int nr_pages;
        int ret = 0;
-       int lock = newflags & VM_LOCKED;
+       int lock = !!(newflags & VM_LOCKED);
 
        if (newflags == vma->vm_flags || (vma->vm_flags & VM_SPECIAL) ||
            is_vm_hugetlb_page(vma) || vma == get_gate_vma(current->mm))
@@ -385,7 +385,7 @@ static int do_mlock(unsigned long start, size_t len, int on)
                prev = vma;
 
        for (nstart = start ; ; ) {
-               unsigned int newflags;
+               vm_flags_t newflags;
 
                /* Here we know that  vma->vm_start <= nstart < vma->vm_end. */
 
@@ -524,7 +524,7 @@ static int do_mlockall(int flags)
                goto out;
 
        for (vma = current->mm->mmap; vma ; vma = prev->vm_next) {
-               unsigned int newflags;
+               vm_flags_t newflags;
 
                newflags = vma->vm_flags | VM_LOCKED;
                if (!(flags & MCL_CURRENT))
index 772140c53ab185ebc76d1f185d6feb9fb8935c15..d49736ff8a8dad10420a4f2f76ca89da52c7da89 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -84,10 +84,14 @@ pgprot_t vm_get_page_prot(unsigned long vm_flags)
 }
 EXPORT_SYMBOL(vm_get_page_prot);
 
-int sysctl_overcommit_memory = OVERCOMMIT_GUESS;  /* heuristic overcommit */
-int sysctl_overcommit_ratio = 50;      /* default is 50% */
+int sysctl_overcommit_memory __read_mostly = OVERCOMMIT_GUESS;  /* heuristic overcommit */
+int sysctl_overcommit_ratio __read_mostly = 50;        /* default is 50% */
 int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT;
-struct percpu_counter vm_committed_as;
+/*
+ * Make sure vm_committed_as in one cacheline and not cacheline shared with
+ * other variables. It can be updated by several CPUs frequently.
+ */
+struct percpu_counter vm_committed_as ____cacheline_aligned_in_smp;
 
 /*
  * Check that a process has enough memory to allocate a new virtual
@@ -190,7 +194,7 @@ error:
 }
 
 /*
- * Requires inode->i_mapping->i_mmap_lock
+ * Requires inode->i_mapping->i_mmap_mutex
  */
 static void __remove_shared_vm_struct(struct vm_area_struct *vma,
                struct file *file, struct address_space *mapping)
@@ -218,9 +222,9 @@ void unlink_file_vma(struct vm_area_struct *vma)
 
        if (file) {
                struct address_space *mapping = file->f_mapping;
-               spin_lock(&mapping->i_mmap_lock);
+               mutex_lock(&mapping->i_mmap_mutex);
                __remove_shared_vm_struct(vma, file, mapping);
-               spin_unlock(&mapping->i_mmap_lock);
+               mutex_unlock(&mapping->i_mmap_mutex);
        }
 }
 
@@ -394,29 +398,6 @@ find_vma_prepare(struct mm_struct *mm, unsigned long addr,
        return vma;
 }
 
-static inline void
-__vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
-               struct vm_area_struct *prev, struct rb_node *rb_parent)
-{
-       struct vm_area_struct *next;
-
-       vma->vm_prev = prev;
-       if (prev) {
-               next = prev->vm_next;
-               prev->vm_next = vma;
-       } else {
-               mm->mmap = vma;
-               if (rb_parent)
-                       next = rb_entry(rb_parent,
-                                       struct vm_area_struct, vm_rb);
-               else
-                       next = NULL;
-       }
-       vma->vm_next = next;
-       if (next)
-               next->vm_prev = vma;
-}
-
 void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma,
                struct rb_node **rb_link, struct rb_node *rb_parent)
 {
@@ -464,16 +445,14 @@ static void vma_link(struct mm_struct *mm, struct vm_area_struct *vma,
        if (vma->vm_file)
                mapping = vma->vm_file->f_mapping;
 
-       if (mapping) {
-               spin_lock(&mapping->i_mmap_lock);
-               vma->vm_truncate_count = mapping->truncate_count;
-       }
+       if (mapping)
+               mutex_lock(&mapping->i_mmap_mutex);
 
        __vma_link(mm, vma, prev, rb_link, rb_parent);
        __vma_link_file(vma);
 
        if (mapping)
-               spin_unlock(&mapping->i_mmap_lock);
+               mutex_unlock(&mapping->i_mmap_mutex);
 
        mm->map_count++;
        validate_mm(mm);
@@ -576,17 +555,8 @@ again:                     remove_next = 1 + (end > next->vm_end);
                mapping = file->f_mapping;
                if (!(vma->vm_flags & VM_NONLINEAR))
                        root = &mapping->i_mmap;
-               spin_lock(&mapping->i_mmap_lock);
-               if (importer &&
-                   vma->vm_truncate_count != next->vm_truncate_count) {
-                       /*
-                        * unmap_mapping_range might be in progress:
-                        * ensure that the expanding vma is rescanned.
-                        */
-                       importer->vm_truncate_count = 0;
-               }
+               mutex_lock(&mapping->i_mmap_mutex);
                if (insert) {
-                       insert->vm_truncate_count = vma->vm_truncate_count;
                        /*
                         * Put into prio_tree now, so instantiated pages
                         * are visible to arm/parisc __flush_dcache_page
@@ -605,7 +575,7 @@ again:                      remove_next = 1 + (end > next->vm_end);
         * lock may be shared between many sibling processes.  Skipping
         * the lock for brk adjustments makes a difference sometimes.
         */
-       if (vma->anon_vma && (insert || importer || start != vma->vm_start)) {
+       if (vma->anon_vma && (importer || start != vma->vm_start)) {
                anon_vma = vma->anon_vma;
                anon_vma_lock(anon_vma);
        }
@@ -652,7 +622,7 @@ again:                      remove_next = 1 + (end > next->vm_end);
        if (anon_vma)
                anon_vma_unlock(anon_vma);
        if (mapping)
-               spin_unlock(&mapping->i_mmap_lock);
+               mutex_unlock(&mapping->i_mmap_mutex);
 
        if (remove_next) {
                if (file) {
@@ -699,9 +669,17 @@ static inline int is_mergeable_vma(struct vm_area_struct *vma,
 }
 
 static inline int is_mergeable_anon_vma(struct anon_vma *anon_vma1,
-                                       struct anon_vma *anon_vma2)
+                                       struct anon_vma *anon_vma2,
+                                       struct vm_area_struct *vma)
 {
-       return !anon_vma1 || !anon_vma2 || (anon_vma1 == anon_vma2);
+       /*
+        * The list_is_singular() test is to avoid merging VMA cloned from
+        * parents. This can improve scalability caused by anon_vma lock.
+        */
+       if ((!anon_vma1 || !anon_vma2) && (!vma ||
+               list_is_singular(&vma->anon_vma_chain)))
+               return 1;
+       return anon_vma1 == anon_vma2;
 }
 
 /*
@@ -720,7 +698,7 @@ can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags,
        struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff)
 {
        if (is_mergeable_vma(vma, file, vm_flags) &&
-           is_mergeable_anon_vma(anon_vma, vma->anon_vma)) {
+           is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) {
                if (vma->vm_pgoff == vm_pgoff)
                        return 1;
        }
@@ -739,7 +717,7 @@ can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags,
        struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff)
 {
        if (is_mergeable_vma(vma, file, vm_flags) &&
-           is_mergeable_anon_vma(anon_vma, vma->anon_vma)) {
+           is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) {
                pgoff_t vm_pglen;
                vm_pglen = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
                if (vma->vm_pgoff + vm_pglen == vm_pgoff)
@@ -817,7 +795,7 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm,
                                can_vma_merge_before(next, vm_flags,
                                        anon_vma, file, pgoff+pglen) &&
                                is_mergeable_anon_vma(prev->anon_vma,
-                                                     next->anon_vma)) {
+                                                     next->anon_vma, NULL)) {
                                                        /* cases 1, 6 */
                        err = vma_adjust(prev, prev->vm_start,
                                next->vm_end, prev->vm_pgoff, NULL);
@@ -928,14 +906,7 @@ struct anon_vma *find_mergeable_anon_vma(struct vm_area_struct *vma)
        if (anon_vma)
                return anon_vma;
 try_prev:
-       /*
-        * It is potentially slow to have to call find_vma_prev here.
-        * But it's only on the first write fault on the vma, not
-        * every time, and we could devise a way to avoid it later
-        * (e.g. stash info in next's anon_vma_node when assigning
-        * an anon_vma, or when trying vma_merge).  Another time.
-        */
-       BUG_ON(find_vma_prev(vma->vm_mm, vma->vm_start, &near) != vma);
+       near = vma->vm_prev;
        if (!near)
                goto none;
 
@@ -982,7 +953,7 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
 {
        struct mm_struct * mm = current->mm;
        struct inode *inode;
-       unsigned int vm_flags;
+       vm_flags_t vm_flags;
        int error;
        unsigned long reqprot = prot;
 
@@ -1187,7 +1158,7 @@ SYSCALL_DEFINE1(old_mmap, struct mmap_arg_struct __user *, arg)
  */
 int vma_wants_writenotify(struct vm_area_struct *vma)
 {
-       unsigned int vm_flags = vma->vm_flags;
+       vm_flags_t vm_flags = vma->vm_flags;
 
        /* If it was private or non-writable, the write bit is already clear */
        if ((vm_flags & (VM_WRITE|VM_SHARED)) != ((VM_WRITE|VM_SHARED)))
@@ -1215,7 +1186,7 @@ int vma_wants_writenotify(struct vm_area_struct *vma)
  * We account for memory if it's a private writeable mapping,
  * not hugepages and VM_NORESERVE wasn't set.
  */
-static inline int accountable_mapping(struct file *file, unsigned int vm_flags)
+static inline int accountable_mapping(struct file *file, vm_flags_t vm_flags)
 {
        /*
         * hugetlb has its own accounting separate from the core VM
@@ -1229,7 +1200,7 @@ static inline int accountable_mapping(struct file *file, unsigned int vm_flags)
 
 unsigned long mmap_region(struct file *file, unsigned long addr,
                          unsigned long len, unsigned long flags,
-                         unsigned int vm_flags, unsigned long pgoff)
+                         vm_flags_t vm_flags, unsigned long pgoff)
 {
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma, *prev;
@@ -1785,7 +1756,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
 /*
  * vma is the first one with address < vma->vm_start.  Have to extend vma.
  */
-static int expand_downwards(struct vm_area_struct *vma,
+int expand_downwards(struct vm_area_struct *vma,
                                   unsigned long address)
 {
        int error;
@@ -1832,11 +1803,6 @@ static int expand_downwards(struct vm_area_struct *vma,
        return error;
 }
 
-int expand_stack_downwards(struct vm_area_struct *vma, unsigned long address)
-{
-       return expand_downwards(vma, address);
-}
-
 #ifdef CONFIG_STACK_GROWSUP
 int expand_stack(struct vm_area_struct *vma, unsigned long address)
 {
@@ -1919,17 +1885,17 @@ static void unmap_region(struct mm_struct *mm,
                unsigned long start, unsigned long end)
 {
        struct vm_area_struct *next = prev? prev->vm_next: mm->mmap;
-       struct mmu_gather *tlb;
+       struct mmu_gather tlb;
        unsigned long nr_accounted = 0;
 
        lru_add_drain();
-       tlb = tlb_gather_mmu(mm, 0);
+       tlb_gather_mmu(&tlb, mm, 0);
        update_hiwater_rss(mm);
        unmap_vmas(&tlb, vma, start, end, &nr_accounted, NULL);
        vm_unacct_memory(nr_accounted);
-       free_pgtables(tlb, vma, prev? prev->vm_end: FIRST_USER_ADDRESS,
-                                next? next->vm_start: 0);
-       tlb_finish_mmu(tlb, start, end);
+       free_pgtables(&tlb, vma, prev ? prev->vm_end : FIRST_USER_ADDRESS,
+                                next ? next->vm_start : 0);
+       tlb_finish_mmu(&tlb, start, end);
 }
 
 /*
@@ -2071,9 +2037,10 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
                return -EINVAL;
 
        /* Find the first overlapping VMA */
-       vma = find_vma_prev(mm, start, &prev);
+       vma = find_vma(mm, start);
        if (!vma)
                return 0;
+       prev = vma->vm_prev;
        /* we have  start < vma->vm_end  */
 
        /* if it doesn't overlap, we have nothing.. */
@@ -2271,7 +2238,7 @@ EXPORT_SYMBOL(do_brk);
 /* Release all mmaps. */
 void exit_mmap(struct mm_struct *mm)
 {
-       struct mmu_gather *tlb;
+       struct mmu_gather tlb;
        struct vm_area_struct *vma;
        unsigned long nr_accounted = 0;
        unsigned long end;
@@ -2296,14 +2263,14 @@ void exit_mmap(struct mm_struct *mm)
 
        lru_add_drain();
        flush_cache_mm(mm);
-       tlb = tlb_gather_mmu(mm, 1);
+       tlb_gather_mmu(&tlb, mm, 1);
        /* update_hiwater_rss(mm) here? but nobody should be looking */
        /* Use -1 here to ensure all VMAs in the mm are unmapped */
        end = unmap_vmas(&tlb, vma, 0, -1, &nr_accounted, NULL);
        vm_unacct_memory(nr_accounted);
 
-       free_pgtables(tlb, vma, FIRST_USER_ADDRESS, 0);
-       tlb_finish_mmu(tlb, 0, end);
+       free_pgtables(&tlb, vma, FIRST_USER_ADDRESS, 0);
+       tlb_finish_mmu(&tlb, 0, end);
 
        /*
         * Walk the list again, actually closing and freeing it,
@@ -2317,7 +2284,7 @@ void exit_mmap(struct mm_struct *mm)
 
 /* Insert vm structure into process list sorted by address
  * and into the inode's i_mmap tree.  If vm_file is non-NULL
- * then i_mmap_lock is taken here.
+ * then i_mmap_mutex is taken here.
  */
 int insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
 {
@@ -2529,15 +2496,15 @@ static void vm_lock_anon_vma(struct mm_struct *mm, struct anon_vma *anon_vma)
                 * The LSB of head.next can't change from under us
                 * because we hold the mm_all_locks_mutex.
                 */
-               spin_lock_nest_lock(&anon_vma->root->lock, &mm->mmap_sem);
+               mutex_lock_nest_lock(&anon_vma->root->mutex, &mm->mmap_sem);
                /*
                 * We can safely modify head.next after taking the
-                * anon_vma->root->lock. If some other vma in this mm shares
+                * anon_vma->root->mutex. If some other vma in this mm shares
                 * the same anon_vma we won't take it again.
                 *
                 * No need of atomic instructions here, head.next
                 * can't change from under us thanks to the
-                * anon_vma->root->lock.
+                * anon_vma->root->mutex.
                 */
                if (__test_and_set_bit(0, (unsigned long *)
                                       &anon_vma->root->head.next))
@@ -2559,7 +2526,7 @@ static void vm_lock_mapping(struct mm_struct *mm, struct address_space *mapping)
                 */
                if (test_and_set_bit(AS_MM_ALL_LOCKS, &mapping->flags))
                        BUG();
-               spin_lock_nest_lock(&mapping->i_mmap_lock, &mm->mmap_sem);
+               mutex_lock_nest_lock(&mapping->i_mmap_mutex, &mm->mmap_sem);
        }
 }
 
@@ -2586,7 +2553,7 @@ static void vm_lock_mapping(struct mm_struct *mm, struct address_space *mapping)
  * vma in this mm is backed by the same anon_vma or address_space.
  *
  * We can take all the locks in random order because the VM code
- * taking i_mmap_lock or anon_vma->lock outside the mmap_sem never
+ * taking i_mmap_mutex or anon_vma->mutex outside the mmap_sem never
  * takes more than one of them in a row. Secondly we're protected
  * against a concurrent mm_take_all_locks() by the mm_all_locks_mutex.
  *
@@ -2642,7 +2609,7 @@ static void vm_unlock_anon_vma(struct anon_vma *anon_vma)
                 *
                 * No need of atomic instructions here, head.next
                 * can't change from under us until we release the
-                * anon_vma->root->lock.
+                * anon_vma->root->mutex.
                 */
                if (!__test_and_clear_bit(0, (unsigned long *)
                                          &anon_vma->root->head.next))
@@ -2658,7 +2625,7 @@ static void vm_unlock_mapping(struct address_space *mapping)
                 * AS_MM_ALL_LOCKS can't change to 0 from under us
                 * because we hold the mm_all_locks_mutex.
                 */
-               spin_unlock(&mapping->i_mmap_lock);
+               mutex_unlock(&mapping->i_mmap_mutex);
                if (!test_and_clear_bit(AS_MM_ALL_LOCKS,
                                        &mapping->flags))
                        BUG();
index a7c1f9f9b94157033e232ef2618ebb67e0eef99d..506fa44403df5cc3215cb69ec2d1098a96bb7919 100644 (file)
@@ -93,8 +93,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
                 * and we propagate stale pages into the dst afterward.
                 */
                mapping = vma->vm_file->f_mapping;
-               spin_lock(&mapping->i_mmap_lock);
-               new_vma->vm_truncate_count = 0;
+               mutex_lock(&mapping->i_mmap_mutex);
        }
 
        /*
@@ -123,7 +122,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
        pte_unmap(new_pte - 1);
        pte_unmap_unlock(old_pte - 1, old_ptl);
        if (mapping)
-               spin_unlock(&mapping->i_mmap_lock);
+               mutex_unlock(&mapping->i_mmap_mutex);
        mmu_notifier_invalidate_range_end(vma->vm_mm, old_start, old_end);
 }
 
index 9109049f0bbce176071d1776da87e12087485a12..6e93dc7f25863628b576539648dfe0c7ba8d3f10 100644 (file)
@@ -307,30 +307,7 @@ void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
 void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
                                   unsigned long align, unsigned long goal)
 {
-#ifdef MAX_DMA32_PFN
-       unsigned long end_pfn;
-
-       if (WARN_ON_ONCE(slab_is_available()))
-               return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
-
-       /* update goal according ...MAX_DMA32_PFN */
-       end_pfn = pgdat->node_start_pfn + pgdat->node_spanned_pages;
-
-       if (end_pfn > MAX_DMA32_PFN + (128 >> (20 - PAGE_SHIFT)) &&
-           (goal >> PAGE_SHIFT) < MAX_DMA32_PFN) {
-               void *ptr;
-               unsigned long new_goal;
-
-               new_goal = MAX_DMA32_PFN << PAGE_SHIFT;
-               ptr =  __alloc_memory_core_early(pgdat->node_id, size, align,
-                                                new_goal, -1ULL);
-               if (ptr)
-                       return ptr;
-       }
-#endif
-
        return __alloc_bootmem_node(pgdat, size, align, goal);
-
 }
 
 #ifdef CONFIG_SPARSEMEM
index c4c542c736a962774f0770eef0d50c419b19a2cb..1fd0c51b10a63db69181fc6ba2f42127aaad6ef7 100644 (file)
@@ -680,9 +680,9 @@ static void protect_vma(struct vm_area_struct *vma, unsigned long flags)
  */
 static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma)
 {
-       struct vm_area_struct *pvma, **pp, *next;
+       struct vm_area_struct *pvma, *prev;
        struct address_space *mapping;
-       struct rb_node **p, *parent;
+       struct rb_node **p, *parent, *rb_prev;
 
        kenter(",%p", vma);
 
@@ -703,7 +703,7 @@ static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma)
        }
 
        /* add the VMA to the tree */
-       parent = NULL;
+       parent = rb_prev = NULL;
        p = &mm->mm_rb.rb_node;
        while (*p) {
                parent = *p;
@@ -713,17 +713,20 @@ static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma)
                 * (the latter is necessary as we may get identical VMAs) */
                if (vma->vm_start < pvma->vm_start)
                        p = &(*p)->rb_left;
-               else if (vma->vm_start > pvma->vm_start)
+               else if (vma->vm_start > pvma->vm_start) {
+                       rb_prev = parent;
                        p = &(*p)->rb_right;
-               else if (vma->vm_end < pvma->vm_end)
+               else if (vma->vm_end < pvma->vm_end)
                        p = &(*p)->rb_left;
-               else if (vma->vm_end > pvma->vm_end)
+               else if (vma->vm_end > pvma->vm_end) {
+                       rb_prev = parent;
                        p = &(*p)->rb_right;
-               else if (vma < pvma)
+               else if (vma < pvma)
                        p = &(*p)->rb_left;
-               else if (vma > pvma)
+               else if (vma > pvma) {
+                       rb_prev = parent;
                        p = &(*p)->rb_right;
-               else
+               else
                        BUG();
        }
 
@@ -731,20 +734,11 @@ static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma)
        rb_insert_color(&vma->vm_rb, &mm->mm_rb);
 
        /* add VMA to the VMA list also */
-       for (pp = &mm->mmap; (pvma = *pp); pp = &(*pp)->vm_next) {
-               if (pvma->vm_start > vma->vm_start)
-                       break;
-               if (pvma->vm_start < vma->vm_start)
-                       continue;
-               if (pvma->vm_end < vma->vm_end)
-                       break;
-       }
+       prev = NULL;
+       if (rb_prev)
+               prev = rb_entry(rb_prev, struct vm_area_struct, vm_rb);
 
-       next = *pp;
-       *pp = vma;
-       vma->vm_next = next;
-       if (next)
-               next->vm_prev = vma;
+       __vma_link_list(mm, vma, prev, parent);
 }
 
 /*
@@ -752,7 +746,6 @@ static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma)
  */
 static void delete_vma_from_mm(struct vm_area_struct *vma)
 {
-       struct vm_area_struct **pp;
        struct address_space *mapping;
        struct mm_struct *mm = vma->vm_mm;
 
@@ -775,12 +768,14 @@ static void delete_vma_from_mm(struct vm_area_struct *vma)
 
        /* remove from the MM's tree and list */
        rb_erase(&vma->vm_rb, &mm->mm_rb);
-       for (pp = &mm->mmap; *pp; pp = &(*pp)->vm_next) {
-               if (*pp == vma) {
-                       *pp = vma->vm_next;
-                       break;
-               }
-       }
+
+       if (vma->vm_prev)
+               vma->vm_prev->vm_next = vma->vm_next;
+       else
+               mm->mmap = vma->vm_next;
+
+       if (vma->vm_next)
+               vma->vm_next->vm_prev = vma->vm_prev;
 
        vma->vm_mm = NULL;
 }
@@ -809,17 +804,15 @@ static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma)
 struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
 {
        struct vm_area_struct *vma;
-       struct rb_node *n = mm->mm_rb.rb_node;
 
        /* check the cache first */
        vma = mm->mmap_cache;
        if (vma && vma->vm_start <= addr && vma->vm_end > addr)
                return vma;
 
-       /* trawl the tree (there may be multiple mappings in which addr
+       /* trawl the list (there may be multiple mappings in which addr
         * resides) */
-       for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) {
-               vma = rb_entry(n, struct vm_area_struct, vm_rb);
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
                if (vma->vm_start > addr)
                        return NULL;
                if (vma->vm_end > addr) {
@@ -859,7 +852,6 @@ static struct vm_area_struct *find_vma_exact(struct mm_struct *mm,
                                             unsigned long len)
 {
        struct vm_area_struct *vma;
-       struct rb_node *n = mm->mm_rb.rb_node;
        unsigned long end = addr + len;
 
        /* check the cache first */
@@ -867,10 +859,9 @@ static struct vm_area_struct *find_vma_exact(struct mm_struct *mm,
        if (vma && vma->vm_start == addr && vma->vm_end == end)
                return vma;
 
-       /* trawl the tree (there may be multiple mappings in which addr
+       /* trawl the list (there may be multiple mappings in which addr
         * resides) */
-       for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) {
-               vma = rb_entry(n, struct vm_area_struct, vm_rb);
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
                if (vma->vm_start < addr)
                        continue;
                if (vma->vm_start > addr)
@@ -1133,7 +1124,7 @@ static int do_mmap_private(struct vm_area_struct *vma,
                           unsigned long capabilities)
 {
        struct page *pages;
-       unsigned long total, point, n, rlen;
+       unsigned long total, point, n;
        void *base;
        int ret, order;
 
@@ -1157,13 +1148,12 @@ static int do_mmap_private(struct vm_area_struct *vma,
                 * make a private copy of the data and map that instead */
        }
 
-       rlen = PAGE_ALIGN(len);
 
        /* allocate some memory to hold the mapping
         * - note that this may not return a page-aligned address if the object
         *   we're allocating is smaller than a page
         */
-       order = get_order(rlen);
+       order = get_order(len);
        kdebug("alloc order %d for %lx", order, len);
 
        pages = alloc_pages(GFP_KERNEL, order);
@@ -1173,7 +1163,7 @@ static int do_mmap_private(struct vm_area_struct *vma,
        total = 1 << order;
        atomic_long_add(total, &mmap_pages_allocated);
 
-       point = rlen >> PAGE_SHIFT;
+       point = len >> PAGE_SHIFT;
 
        /* we allocated a power-of-2 sized page set, so we may want to trim off
         * the excess */
@@ -1195,7 +1185,7 @@ static int do_mmap_private(struct vm_area_struct *vma,
        base = page_address(pages);
        region->vm_flags = vma->vm_flags |= VM_MAPPED_COPY;
        region->vm_start = (unsigned long) base;
-       region->vm_end   = region->vm_start + rlen;
+       region->vm_end   = region->vm_start + len;
        region->vm_top   = region->vm_start + (total << PAGE_SHIFT);
 
        vma->vm_start = region->vm_start;
@@ -1211,22 +1201,22 @@ static int do_mmap_private(struct vm_area_struct *vma,
 
                old_fs = get_fs();
                set_fs(KERNEL_DS);
-               ret = vma->vm_file->f_op->read(vma->vm_file, base, rlen, &fpos);
+               ret = vma->vm_file->f_op->read(vma->vm_file, base, len, &fpos);
                set_fs(old_fs);
 
                if (ret < 0)
                        goto error_free;
 
                /* clear the last little bit */
-               if (ret < rlen)
-                       memset(base + ret, 0, rlen - ret);
+               if (ret < len)
+                       memset(base + ret, 0, len - ret);
 
        }
 
        return 0;
 
 error_free:
-       free_page_series(region->vm_start, region->vm_end);
+       free_page_series(region->vm_start, region->vm_top);
        region->vm_start = vma->vm_start = 0;
        region->vm_end   = vma->vm_end = 0;
        region->vm_top   = 0;
@@ -1235,7 +1225,7 @@ error_free:
 enomem:
        printk("Allocation of length %lu from process %d (%s) failed\n",
               len, current->pid, current->comm);
-       show_free_areas();
+       show_free_areas(0);
        return -ENOMEM;
 }
 
@@ -1268,6 +1258,7 @@ unsigned long do_mmap_pgoff(struct file *file,
 
        /* we ignore the address hint */
        addr = 0;
+       len = PAGE_ALIGN(len);
 
        /* we've determined that we can make the mapping, now translate what we
         * now know into VMA flags */
@@ -1385,15 +1376,15 @@ unsigned long do_mmap_pgoff(struct file *file,
                if (capabilities & BDI_CAP_MAP_DIRECT) {
                        addr = file->f_op->get_unmapped_area(file, addr, len,
                                                             pgoff, flags);
-                       if (IS_ERR((void *) addr)) {
+                       if (IS_ERR_VALUE(addr)) {
                                ret = addr;
-                               if (ret != (unsigned long) -ENOSYS)
+                               if (ret != -ENOSYS)
                                        goto error_just_free;
 
                                /* the driver refused to tell us where to site
                                 * the mapping so we'll have to attempt to copy
                                 * it */
-                               ret = (unsigned long) -ENODEV;
+                               ret = -ENODEV;
                                if (!(capabilities & BDI_CAP_MAP_COPY))
                                        goto error_just_free;
 
@@ -1468,14 +1459,14 @@ error_getting_vma:
        printk(KERN_WARNING "Allocation of vma for %lu byte allocation"
               " from process %d failed\n",
               len, current->pid);
-       show_free_areas();
+       show_free_areas(0);
        return -ENOMEM;
 
 error_getting_region:
        printk(KERN_WARNING "Allocation of vm region for %lu byte allocation"
               " from process %d failed\n",
               len, current->pid);
-       show_free_areas();
+       show_free_areas(0);
        return -ENOMEM;
 }
 EXPORT_SYMBOL(do_mmap_pgoff);
@@ -1644,15 +1635,17 @@ static int shrink_vma(struct mm_struct *mm,
 int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
 {
        struct vm_area_struct *vma;
-       struct rb_node *rb;
-       unsigned long end = start + len;
+       unsigned long end;
        int ret;
 
        kenter(",%lx,%zx", start, len);
 
+       len = PAGE_ALIGN(len);
        if (len == 0)
                return -EINVAL;
 
+       end = start + len;
+
        /* find the first potentially overlapping VMA */
        vma = find_vma(mm, start);
        if (!vma) {
@@ -1677,9 +1670,8 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
                        }
                        if (end == vma->vm_end)
                                goto erase_whole_vma;
-                       rb = rb_next(&vma->vm_rb);
-                       vma = rb_entry(rb, struct vm_area_struct, vm_rb);
-               } while (rb);
+                       vma = vma->vm_next;
+               } while (vma);
                kleave(" = -EINVAL [split file]");
                return -EINVAL;
        } else {
@@ -1773,6 +1765,8 @@ unsigned long do_mremap(unsigned long addr,
        struct vm_area_struct *vma;
 
        /* insanity checks first */
+       old_len = PAGE_ALIGN(old_len);
+       new_len = PAGE_ALIGN(new_len);
        if (old_len == 0 || new_len == 0)
                return (unsigned long) -EINVAL;
 
index f52e85c80e8d554fcae1a7ad40e0617c0bb1318f..e4b0991ca3516b3fc3590f40da1ede9f8a4ba637 100644 (file)
@@ -38,6 +38,33 @@ int sysctl_oom_kill_allocating_task;
 int sysctl_oom_dump_tasks = 1;
 static DEFINE_SPINLOCK(zone_scan_lock);
 
+/**
+ * test_set_oom_score_adj() - set current's oom_score_adj and return old value
+ * @new_val: new oom_score_adj value
+ *
+ * Sets the oom_score_adj value for current to @new_val with proper
+ * synchronization and returns the old value.  Usually used to temporarily
+ * set a value, save the old value in the caller, and then reinstate it later.
+ */
+int test_set_oom_score_adj(int new_val)
+{
+       struct sighand_struct *sighand = current->sighand;
+       int old_val;
+
+       spin_lock_irq(&sighand->siglock);
+       old_val = current->signal->oom_score_adj;
+       if (new_val != old_val) {
+               if (new_val == OOM_SCORE_ADJ_MIN)
+                       atomic_inc(&current->mm->oom_disable_count);
+               else if (old_val == OOM_SCORE_ADJ_MIN)
+                       atomic_dec(&current->mm->oom_disable_count);
+               current->signal->oom_score_adj = new_val;
+       }
+       spin_unlock_irq(&sighand->siglock);
+
+       return old_val;
+}
+
 #ifdef CONFIG_NUMA
 /**
  * has_intersects_mems_allowed() - check task eligiblity for kill
@@ -154,15 +181,6 @@ unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem,
                return 0;
        }
 
-       /*
-        * When the PF_OOM_ORIGIN bit is set, it indicates the task should have
-        * priority for oom killing.
-        */
-       if (p->flags & PF_OOM_ORIGIN) {
-               task_unlock(p);
-               return 1000;
-       }
-
        /*
         * The memory controller may have a limit of 0 bytes, so avoid a divide
         * by zero, if necessary.
index 9d5498e2d0f5a73c527c32b4ffe14cbfa897a7be..4e8985acdab8b5c234a6486b3c84caf5fb89dca0 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/pagevec.h>
 #include <linux/blkdev.h>
 #include <linux/slab.h>
+#include <linux/ratelimit.h>
 #include <linux/oom.h>
 #include <linux/notifier.h>
 #include <linux/topology.h>
@@ -39,6 +40,7 @@
 #include <linux/memory_hotplug.h>
 #include <linux/nodemask.h>
 #include <linux/vmalloc.h>
+#include <linux/vmstat.h>
 #include <linux/mempolicy.h>
 #include <linux/stop_machine.h>
 #include <linux/sort.h>
@@ -1735,6 +1737,45 @@ static inline bool should_suppress_show_mem(void)
        return ret;
 }
 
+static DEFINE_RATELIMIT_STATE(nopage_rs,
+               DEFAULT_RATELIMIT_INTERVAL,
+               DEFAULT_RATELIMIT_BURST);
+
+void warn_alloc_failed(gfp_t gfp_mask, int order, const char *fmt, ...)
+{
+       va_list args;
+       unsigned int filter = SHOW_MEM_FILTER_NODES;
+
+       if ((gfp_mask & __GFP_NOWARN) || !__ratelimit(&nopage_rs))
+               return;
+
+       /*
+        * This documents exceptions given to allocations in certain
+        * contexts that are allowed to allocate outside current's set
+        * of allowed nodes.
+        */
+       if (!(gfp_mask & __GFP_NOMEMALLOC))
+               if (test_thread_flag(TIF_MEMDIE) ||
+                   (current->flags & (PF_MEMALLOC | PF_EXITING)))
+                       filter &= ~SHOW_MEM_FILTER_NODES;
+       if (in_interrupt() || !(gfp_mask & __GFP_WAIT))
+               filter &= ~SHOW_MEM_FILTER_NODES;
+
+       if (fmt) {
+               printk(KERN_WARNING);
+               va_start(args, fmt);
+               vprintk(fmt, args);
+               va_end(args);
+       }
+
+       pr_warning("%s: page allocation failure: order:%d, mode:0x%x\n",
+                  current->comm, order, gfp_mask);
+
+       dump_stack();
+       if (!should_suppress_show_mem())
+               show_mem(filter);
+}
+
 static inline int
 should_alloc_retry(gfp_t gfp_mask, unsigned int order,
                                unsigned long pages_reclaimed)
@@ -2065,6 +2106,7 @@ restart:
                first_zones_zonelist(zonelist, high_zoneidx, NULL,
                                        &preferred_zone);
 
+rebalance:
        /* This is the last chance, in general, before the goto nopage. */
        page = get_page_from_freelist(gfp_mask, nodemask, order, zonelist,
                        high_zoneidx, alloc_flags & ~ALLOC_NO_WATERMARKS,
@@ -2072,7 +2114,6 @@ restart:
        if (page)
                goto got_pg;
 
-rebalance:
        /* Allocate without watermarks if the context allows */
        if (alloc_flags & ALLOC_NO_WATERMARKS) {
                page = __alloc_pages_high_priority(gfp_mask, order,
@@ -2106,7 +2147,7 @@ rebalance:
                                        sync_migration);
        if (page)
                goto got_pg;
-       sync_migration = !(gfp_mask & __GFP_NO_KSWAPD);
+       sync_migration = true;
 
        /* Try direct reclaim and then allocating */
        page = __alloc_pages_direct_reclaim(gfp_mask, order,
@@ -2177,27 +2218,7 @@ rebalance:
        }
 
 nopage:
-       if (!(gfp_mask & __GFP_NOWARN) && printk_ratelimit()) {
-               unsigned int filter = SHOW_MEM_FILTER_NODES;
-
-               /*
-                * This documents exceptions given to allocations in certain
-                * contexts that are allowed to allocate outside current's set
-                * of allowed nodes.
-                */
-               if (!(gfp_mask & __GFP_NOMEMALLOC))
-                       if (test_thread_flag(TIF_MEMDIE) ||
-                           (current->flags & (PF_MEMALLOC | PF_EXITING)))
-                               filter &= ~SHOW_MEM_FILTER_NODES;
-               if (in_interrupt() || !wait)
-                       filter &= ~SHOW_MEM_FILTER_NODES;
-
-               pr_warning("%s: page allocation failure. order:%d, mode:0x%x\n",
-                       current->comm, order, gfp_mask);
-               dump_stack();
-               if (!should_suppress_show_mem())
-                       show_mem(filter);
-       }
+       warn_alloc_failed(gfp_mask, order, NULL);
        return page;
 got_pg:
        if (kmemcheck_enabled)
@@ -2473,10 +2494,10 @@ void si_meminfo_node(struct sysinfo *val, int nid)
 #endif
 
 /*
- * Determine whether the zone's node should be displayed or not, depending on
- * whether SHOW_MEM_FILTER_NODES was passed to __show_free_areas().
+ * Determine whether the node should be displayed or not, depending on whether
+ * SHOW_MEM_FILTER_NODES was passed to show_free_areas().
  */
-static bool skip_free_areas_zone(unsigned int flags, const struct zone *zone)
+bool skip_free_areas_node(unsigned int flags, int nid)
 {
        bool ret = false;
 
@@ -2484,8 +2505,7 @@ static bool skip_free_areas_zone(unsigned int flags, const struct zone *zone)
                goto out;
 
        get_mems_allowed();
-       ret = !node_isset(zone->zone_pgdat->node_id,
-                               cpuset_current_mems_allowed);
+       ret = !node_isset(nid, cpuset_current_mems_allowed);
        put_mems_allowed();
 out:
        return ret;
@@ -2500,13 +2520,13 @@ out:
  * Suppresses nodes that are not allowed by current's cpuset if
  * SHOW_MEM_FILTER_NODES is passed.
  */
-void __show_free_areas(unsigned int filter)
+void show_free_areas(unsigned int filter)
 {
        int cpu;
        struct zone *zone;
 
        for_each_populated_zone(zone) {
-               if (skip_free_areas_zone(filter, zone))
+               if (skip_free_areas_node(filter, zone_to_nid(zone)))
                        continue;
                show_node(zone);
                printk("%s per-cpu:\n", zone->name);
@@ -2549,7 +2569,7 @@ void __show_free_areas(unsigned int filter)
        for_each_populated_zone(zone) {
                int i;
 
-               if (skip_free_areas_zone(filter, zone))
+               if (skip_free_areas_node(filter, zone_to_nid(zone)))
                        continue;
                show_node(zone);
                printk("%s"
@@ -2618,7 +2638,7 @@ void __show_free_areas(unsigned int filter)
        for_each_populated_zone(zone) {
                unsigned long nr[MAX_ORDER], flags, order, total = 0;
 
-               if (skip_free_areas_zone(filter, zone))
+               if (skip_free_areas_node(filter, zone_to_nid(zone)))
                        continue;
                show_node(zone);
                printk("%s: ", zone->name);
@@ -2639,11 +2659,6 @@ void __show_free_areas(unsigned int filter)
        show_swap_cache_info();
 }
 
-void show_free_areas(void)
-{
-       __show_free_areas(0);
-}
-
 static void zoneref_set_zone(struct zone *zone, struct zoneref *zoneref)
 {
        zoneref->zone = zone;
@@ -3313,6 +3328,20 @@ static inline unsigned long wait_table_bits(unsigned long size)
 
 #define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
 
+/*
+ * Check if a pageblock contains reserved pages
+ */
+static int pageblock_is_reserved(unsigned long start_pfn, unsigned long end_pfn)
+{
+       unsigned long pfn;
+
+       for (pfn = start_pfn; pfn < end_pfn; pfn++) {
+               if (!pfn_valid_within(pfn) || PageReserved(pfn_to_page(pfn)))
+                       return 1;
+       }
+       return 0;
+}
+
 /*
  * Mark a number of pageblocks as MIGRATE_RESERVE. The number
  * of blocks reserved is based on min_wmark_pages(zone). The memory within
@@ -3322,7 +3351,7 @@ static inline unsigned long wait_table_bits(unsigned long size)
  */
 static void setup_zone_migrate_reserve(struct zone *zone)
 {
-       unsigned long start_pfn, pfn, end_pfn;
+       unsigned long start_pfn, pfn, end_pfn, block_end_pfn;
        struct page *page;
        unsigned long block_migratetype;
        int reserve;
@@ -3352,7 +3381,8 @@ static void setup_zone_migrate_reserve(struct zone *zone)
                        continue;
 
                /* Blocks with reserved pages will never free, skip them. */
-               if (PageReserved(page))
+               block_end_pfn = min(pfn + pageblock_nr_pages, end_pfn);
+               if (pageblock_is_reserved(pfn, block_end_pfn))
                        continue;
 
                block_migratetype = get_pageblock_migratetype(page);
@@ -4289,10 +4319,8 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
                zone->zone_pgdat = pgdat;
 
                zone_pcp_init(zone);
-               for_each_lru(l) {
+               for_each_lru(l)
                        INIT_LIST_HEAD(&zone->lru[l].list);
-                       zone->reclaim_stat.nr_saved_scan[l] = 0;
-               }
                zone->reclaim_stat.recent_rotated[0] = 0;
                zone->reclaim_stat.recent_rotated[1] = 0;
                zone->reclaim_stat.recent_scanned[0] = 0;
@@ -5100,7 +5128,7 @@ void setup_per_zone_wmarks(void)
  *    1TB     101        10GB
  *   10TB     320        32GB
  */
-void calculate_zone_inactive_ratio(struct zone *zone)
+static void __meminit calculate_zone_inactive_ratio(struct zone *zone)
 {
        unsigned int gb, ratio;
 
@@ -5114,7 +5142,7 @@ void calculate_zone_inactive_ratio(struct zone *zone)
        zone->inactive_ratio = ratio;
 }
 
-static void __init setup_per_zone_inactive_ratio(void)
+static void __meminit setup_per_zone_inactive_ratio(void)
 {
        struct zone *zone;
 
@@ -5146,7 +5174,7 @@ static void __init setup_per_zone_inactive_ratio(void)
  * 8192MB:     11584k
  * 16384MB:    16384k
  */
-static int __init init_per_zone_wmark_min(void)
+int __meminit init_per_zone_wmark_min(void)
 {
        unsigned long lowmem_kbytes;
 
@@ -5158,6 +5186,7 @@ static int __init init_per_zone_wmark_min(void)
        if (min_free_kbytes > 65536)
                min_free_kbytes = 65536;
        setup_per_zone_wmarks();
+       refresh_zone_stat_thresholds();
        setup_per_zone_lowmem_reserve();
        setup_per_zone_inactive_ratio();
        return 0;
@@ -5508,10 +5537,8 @@ int set_migratetype_isolate(struct page *page)
        struct memory_isolate_notify arg;
        int notifier_ret;
        int ret = -EBUSY;
-       int zone_idx;
 
        zone = page_zone(page);
-       zone_idx = zone_idx(zone);
 
        spin_lock_irqsave(&zone->lock, flags);
 
index 2daadc322ba61678cfc9120e3b65c551b5b96d2d..53bffc6c293eb4fb7aa2a00be5a8712946dab5c9 100644 (file)
@@ -130,7 +130,7 @@ struct page *lookup_cgroup_page(struct page_cgroup *pc)
        return page;
 }
 
-static void *__init_refok alloc_page_cgroup(size_t size, int nid)
+static void *__meminit alloc_page_cgroup(size_t size, int nid)
 {
        void *addr = NULL;
 
@@ -162,13 +162,13 @@ static void free_page_cgroup(void *addr)
 }
 #endif
 
-static int __init_refok init_section_page_cgroup(unsigned long pfn)
+static int __meminit init_section_page_cgroup(unsigned long pfn, int nid)
 {
        struct page_cgroup *base, *pc;
        struct mem_section *section;
        unsigned long table_size;
        unsigned long nr;
-       int nid, index;
+       int index;
 
        nr = pfn_to_section_nr(pfn);
        section = __nr_to_section(nr);
@@ -176,7 +176,6 @@ static int __init_refok init_section_page_cgroup(unsigned long pfn)
        if (section->page_cgroup)
                return 0;
 
-       nid = page_to_nid(pfn_to_page(pfn));
        table_size = sizeof(struct page_cgroup) * PAGES_PER_SECTION;
        base = alloc_page_cgroup(table_size, nid);
 
@@ -196,7 +195,11 @@ static int __init_refok init_section_page_cgroup(unsigned long pfn)
                pc = base + index;
                init_page_cgroup(pc, nr);
        }
-
+       /*
+        * The passed "pfn" may not be aligned to SECTION.  For the calculation
+        * we need to apply a mask.
+        */
+       pfn &= PAGE_SECTION_MASK;
        section->page_cgroup = base - pfn;
        total_usage += table_size;
        return 0;
@@ -225,10 +228,20 @@ int __meminit online_page_cgroup(unsigned long start_pfn,
        start = start_pfn & ~(PAGES_PER_SECTION - 1);
        end = ALIGN(start_pfn + nr_pages, PAGES_PER_SECTION);
 
+       if (nid == -1) {
+               /*
+                * In this case, "nid" already exists and contains valid memory.
+                * "start_pfn" passed to us is a pfn which is an arg for
+                * online__pages(), and start_pfn should exist.
+                */
+               nid = pfn_to_nid(start_pfn);
+               VM_BUG_ON(!node_state(nid, N_ONLINE));
+       }
+
        for (pfn = start; !fail && pfn < end; pfn += PAGES_PER_SECTION) {
                if (!pfn_present(pfn))
                        continue;
-               fail = init_section_page_cgroup(pfn);
+               fail = init_section_page_cgroup(pfn, nid);
        }
        if (!fail)
                return 0;
@@ -284,25 +297,47 @@ static int __meminit page_cgroup_callback(struct notifier_block *self,
 void __init page_cgroup_init(void)
 {
        unsigned long pfn;
-       int fail = 0;
+       int nid;
 
        if (mem_cgroup_disabled())
                return;
 
-       for (pfn = 0; !fail && pfn < max_pfn; pfn += PAGES_PER_SECTION) {
-               if (!pfn_present(pfn))
-                       continue;
-               fail = init_section_page_cgroup(pfn);
-       }
-       if (fail) {
-               printk(KERN_CRIT "try 'cgroup_disable=memory' boot option\n");
-               panic("Out of memory");
-       } else {
-               hotplug_memory_notifier(page_cgroup_callback, 0);
+       for_each_node_state(nid, N_HIGH_MEMORY) {
+               unsigned long start_pfn, end_pfn;
+
+               start_pfn = node_start_pfn(nid);
+               end_pfn = node_end_pfn(nid);
+               /*
+                * start_pfn and end_pfn may not be aligned to SECTION and the
+                * page->flags of out of node pages are not initialized.  So we
+                * scan [start_pfn, the biggest section's pfn < end_pfn) here.
+                */
+               for (pfn = start_pfn;
+                    pfn < end_pfn;
+                     pfn = ALIGN(pfn + 1, PAGES_PER_SECTION)) {
+
+                       if (!pfn_valid(pfn))
+                               continue;
+                       /*
+                        * Nodes's pfns can be overlapping.
+                        * We know some arch can have a nodes layout such as
+                        * -------------pfn-------------->
+                        * N0 | N1 | N2 | N0 | N1 | N2|....
+                        */
+                       if (pfn_to_nid(pfn) != nid)
+                               continue;
+                       if (init_section_page_cgroup(pfn, nid))
+                               goto oom;
+               }
        }
+       hotplug_memory_notifier(page_cgroup_callback, 0);
        printk(KERN_INFO "allocated %ld bytes of page_cgroup\n", total_usage);
-       printk(KERN_INFO "please try 'cgroup_disable=memory' option if you don't"
-       " want memory cgroups\n");
+       printk(KERN_INFO "please try 'cgroup_disable=memory' option if you "
+                        "don't want memory cgroups\n");
+       return;
+oom:
+       printk(KERN_CRIT "try 'cgroup_disable=memory' boot option\n");
+       panic("Out of memory");
 }
 
 void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat)
@@ -475,7 +510,7 @@ int swap_cgroup_swapon(int type, unsigned long max_pages)
        if (!do_swap_account)
                return 0;
 
-       length = ((max_pages/SC_PER_PAGE) + 1);
+       length = DIV_ROUND_UP(max_pages, SC_PER_PAGE);
        array_size = length * sizeof(void *);
 
        array = vmalloc(array_size);
@@ -492,8 +527,8 @@ int swap_cgroup_swapon(int type, unsigned long max_pages)
                /* memory shortage */
                ctrl->map = NULL;
                ctrl->length = 0;
-               vfree(array);
                mutex_unlock(&swap_cgroup_mutex);
+               vfree(array);
                goto nomem;
        }
        mutex_unlock(&swap_cgroup_mutex);
@@ -508,7 +543,8 @@ nomem:
 
 void swap_cgroup_swapoff(int type)
 {
-       int i;
+       struct page **map;
+       unsigned long i, length;
        struct swap_cgroup_ctrl *ctrl;
 
        if (!do_swap_account)
@@ -516,17 +552,20 @@ void swap_cgroup_swapoff(int type)
 
        mutex_lock(&swap_cgroup_mutex);
        ctrl = &swap_cgroup_ctrl[type];
-       if (ctrl->map) {
-               for (i = 0; i < ctrl->length; i++) {
-                       struct page *page = ctrl->map[i];
+       map = ctrl->map;
+       length = ctrl->length;
+       ctrl->map = NULL;
+       ctrl->length = 0;
+       mutex_unlock(&swap_cgroup_mutex);
+
+       if (map) {
+               for (i = 0; i < length; i++) {
+                       struct page *page = map[i];
                        if (page)
                                __free_page(page);
                }
-               vfree(ctrl->map);
-               ctrl->map = NULL;
-               ctrl->length = 0;
+               vfree(map);
        }
-       mutex_unlock(&swap_cgroup_mutex);
 }
 
 #endif
index a160db39b810d3e7cd5981298b125c807419e964..bf80e55dbed7e66fcd28f6dbc46c86fbd222a008 100644 (file)
@@ -1215,8 +1215,10 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
        PCPU_SETUP_BUG_ON(ai->nr_groups <= 0);
 #ifdef CONFIG_SMP
        PCPU_SETUP_BUG_ON(!ai->static_size);
+       PCPU_SETUP_BUG_ON((unsigned long)__per_cpu_start & ~PAGE_MASK);
 #endif
        PCPU_SETUP_BUG_ON(!base_addr);
+       PCPU_SETUP_BUG_ON((unsigned long)base_addr & ~PAGE_MASK);
        PCPU_SETUP_BUG_ON(ai->unit_size < size_sum);
        PCPU_SETUP_BUG_ON(ai->unit_size & ~PAGE_MASK);
        PCPU_SETUP_BUG_ON(ai->unit_size < PCPU_MIN_UNIT_SIZE);
@@ -1645,8 +1647,8 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size,
        /* warn if maximum distance is further than 75% of vmalloc space */
        if (max_distance > (VMALLOC_END - VMALLOC_START) * 3 / 4) {
                pr_warning("PERCPU: max_distance=0x%zx too large for vmalloc "
-                          "space 0x%lx\n",
-                          max_distance, VMALLOC_END - VMALLOC_START);
+                          "space 0x%lx\n", max_distance,
+                          (unsigned long)(VMALLOC_END - VMALLOC_START));
 #ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK
                /* and fail if we have fallback */
                rc = -EINVAL;
index 2c0cc489e2880cb319a92b905a5ee7b292039b7f..867f9dd82dcde9d5c11f49bde159c3c6a0276c4e 100644 (file)
@@ -180,7 +180,7 @@ __do_page_cache_readahead(struct address_space *mapping, struct file *filp,
                if (page)
                        continue;
 
-               page = page_cache_alloc_cold(mapping);
+               page = page_cache_alloc_readahead(mapping);
                if (!page)
                        break;
                page->index = page_offset;
index 8da044a1db0f4db1524f2450cd733e41eb8690ca..27dfd3b82b0f39cfcd38ff8b2a02c55151651f30 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -24,8 +24,8 @@
  *   inode->i_alloc_sem (vmtruncate_range)
  *   mm->mmap_sem
  *     page->flags PG_locked (lock_page)
- *       mapping->i_mmap_lock
- *         anon_vma->lock
+ *       mapping->i_mmap_mutex
+ *         anon_vma->mutex
  *           mm->page_table_lock or pte_lock
  *             zone->lru_lock (in mark_page_accessed, isolate_lru_page)
  *             swap_lock (in swap_duplicate, swap_info_get)
@@ -40,7 +40,7 @@
  *
  * (code doesn't rely on that order so it could be switched around)
  * ->tasklist_lock
- *   anon_vma->lock      (memory_failure, collect_procs_anon)
+ *   anon_vma->mutex      (memory_failure, collect_procs_anon)
  *     pte map lock
  */
 
@@ -86,12 +86,35 @@ static inline struct anon_vma *anon_vma_alloc(void)
 static inline void anon_vma_free(struct anon_vma *anon_vma)
 {
        VM_BUG_ON(atomic_read(&anon_vma->refcount));
+
+       /*
+        * Synchronize against page_lock_anon_vma() such that
+        * we can safely hold the lock without the anon_vma getting
+        * freed.
+        *
+        * Relies on the full mb implied by the atomic_dec_and_test() from
+        * put_anon_vma() against the acquire barrier implied by
+        * mutex_trylock() from page_lock_anon_vma(). This orders:
+        *
+        * page_lock_anon_vma()         VS      put_anon_vma()
+        *   mutex_trylock()                      atomic_dec_and_test()
+        *   LOCK                                 MB
+        *   atomic_read()                        mutex_is_locked()
+        *
+        * LOCK should suffice since the actual taking of the lock must
+        * happen _before_ what follows.
+        */
+       if (mutex_is_locked(&anon_vma->root->mutex)) {
+               anon_vma_lock(anon_vma);
+               anon_vma_unlock(anon_vma);
+       }
+
        kmem_cache_free(anon_vma_cachep, anon_vma);
 }
 
-static inline struct anon_vma_chain *anon_vma_chain_alloc(void)
+static inline struct anon_vma_chain *anon_vma_chain_alloc(gfp_t gfp)
 {
-       return kmem_cache_alloc(anon_vma_chain_cachep, GFP_KERNEL);
+       return kmem_cache_alloc(anon_vma_chain_cachep, gfp);
 }
 
 static void anon_vma_chain_free(struct anon_vma_chain *anon_vma_chain)
@@ -136,7 +159,7 @@ int anon_vma_prepare(struct vm_area_struct *vma)
                struct mm_struct *mm = vma->vm_mm;
                struct anon_vma *allocated;
 
-               avc = anon_vma_chain_alloc();
+               avc = anon_vma_chain_alloc(GFP_KERNEL);
                if (!avc)
                        goto out_enomem;
 
@@ -177,6 +200,32 @@ int anon_vma_prepare(struct vm_area_struct *vma)
        return -ENOMEM;
 }
 
+/*
+ * This is a useful helper function for locking the anon_vma root as
+ * we traverse the vma->anon_vma_chain, looping over anon_vma's that
+ * have the same vma.
+ *
+ * Such anon_vma's should have the same root, so you'd expect to see
+ * just a single mutex_lock for the whole traversal.
+ */
+static inline struct anon_vma *lock_anon_vma_root(struct anon_vma *root, struct anon_vma *anon_vma)
+{
+       struct anon_vma *new_root = anon_vma->root;
+       if (new_root != root) {
+               if (WARN_ON_ONCE(root))
+                       mutex_unlock(&root->mutex);
+               root = new_root;
+               mutex_lock(&root->mutex);
+       }
+       return root;
+}
+
+static inline void unlock_anon_vma_root(struct anon_vma *root)
+{
+       if (root)
+               mutex_unlock(&root->mutex);
+}
+
 static void anon_vma_chain_link(struct vm_area_struct *vma,
                                struct anon_vma_chain *avc,
                                struct anon_vma *anon_vma)
@@ -185,13 +234,11 @@ static void anon_vma_chain_link(struct vm_area_struct *vma,
        avc->anon_vma = anon_vma;
        list_add(&avc->same_vma, &vma->anon_vma_chain);
 
-       anon_vma_lock(anon_vma);
        /*
         * It's critical to add new vmas to the tail of the anon_vma,
         * see comment in huge_memory.c:__split_huge_page().
         */
        list_add_tail(&avc->same_anon_vma, &anon_vma->head);
-       anon_vma_unlock(anon_vma);
 }
 
 /*
@@ -201,13 +248,24 @@ static void anon_vma_chain_link(struct vm_area_struct *vma,
 int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src)
 {
        struct anon_vma_chain *avc, *pavc;
+       struct anon_vma *root = NULL;
 
        list_for_each_entry_reverse(pavc, &src->anon_vma_chain, same_vma) {
-               avc = anon_vma_chain_alloc();
-               if (!avc)
-                       goto enomem_failure;
-               anon_vma_chain_link(dst, avc, pavc->anon_vma);
+               struct anon_vma *anon_vma;
+
+               avc = anon_vma_chain_alloc(GFP_NOWAIT | __GFP_NOWARN);
+               if (unlikely(!avc)) {
+                       unlock_anon_vma_root(root);
+                       root = NULL;
+                       avc = anon_vma_chain_alloc(GFP_KERNEL);
+                       if (!avc)
+                               goto enomem_failure;
+               }
+               anon_vma = pavc->anon_vma;
+               root = lock_anon_vma_root(root, anon_vma);
+               anon_vma_chain_link(dst, avc, anon_vma);
        }
+       unlock_anon_vma_root(root);
        return 0;
 
  enomem_failure:
@@ -240,7 +298,7 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
        anon_vma = anon_vma_alloc();
        if (!anon_vma)
                goto out_error;
-       avc = anon_vma_chain_alloc();
+       avc = anon_vma_chain_alloc(GFP_KERNEL);
        if (!avc)
                goto out_error_free_anon_vma;
 
@@ -257,7 +315,9 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
        get_anon_vma(anon_vma->root);
        /* Mark this anon_vma as the one where our new (COWed) pages go. */
        vma->anon_vma = anon_vma;
+       anon_vma_lock(anon_vma);
        anon_vma_chain_link(vma, avc, anon_vma);
+       anon_vma_unlock(anon_vma);
 
        return 0;
 
@@ -268,36 +328,43 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
        return -ENOMEM;
 }
 
-static void anon_vma_unlink(struct anon_vma_chain *anon_vma_chain)
-{
-       struct anon_vma *anon_vma = anon_vma_chain->anon_vma;
-       int empty;
-
-       /* If anon_vma_fork fails, we can get an empty anon_vma_chain. */
-       if (!anon_vma)
-               return;
-
-       anon_vma_lock(anon_vma);
-       list_del(&anon_vma_chain->same_anon_vma);
-
-       /* We must garbage collect the anon_vma if it's empty */
-       empty = list_empty(&anon_vma->head);
-       anon_vma_unlock(anon_vma);
-
-       if (empty)
-               put_anon_vma(anon_vma);
-}
-
 void unlink_anon_vmas(struct vm_area_struct *vma)
 {
        struct anon_vma_chain *avc, *next;
+       struct anon_vma *root = NULL;
 
        /*
         * Unlink each anon_vma chained to the VMA.  This list is ordered
         * from newest to oldest, ensuring the root anon_vma gets freed last.
         */
        list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) {
-               anon_vma_unlink(avc);
+               struct anon_vma *anon_vma = avc->anon_vma;
+
+               root = lock_anon_vma_root(root, anon_vma);
+               list_del(&avc->same_anon_vma);
+
+               /*
+                * Leave empty anon_vmas on the list - we'll need
+                * to free them outside the lock.
+                */
+               if (list_empty(&anon_vma->head))
+                       continue;
+
+               list_del(&avc->same_vma);
+               anon_vma_chain_free(avc);
+       }
+       unlock_anon_vma_root(root);
+
+       /*
+        * Iterate the list once more, it now only contains empty and unlinked
+        * anon_vmas, destroy them. Could not do before due to __put_anon_vma()
+        * needing to acquire the anon_vma->root->mutex.
+        */
+       list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) {
+               struct anon_vma *anon_vma = avc->anon_vma;
+
+               put_anon_vma(anon_vma);
+
                list_del(&avc->same_vma);
                anon_vma_chain_free(avc);
        }
@@ -307,7 +374,7 @@ static void anon_vma_ctor(void *data)
 {
        struct anon_vma *anon_vma = data;
 
-       spin_lock_init(&anon_vma->lock);
+       mutex_init(&anon_vma->mutex);
        atomic_set(&anon_vma->refcount, 0);
        INIT_LIST_HEAD(&anon_vma->head);
 }
@@ -320,12 +387,31 @@ void __init anon_vma_init(void)
 }
 
 /*
- * Getting a lock on a stable anon_vma from a page off the LRU is
- * tricky: page_lock_anon_vma rely on RCU to guard against the races.
+ * Getting a lock on a stable anon_vma from a page off the LRU is tricky!
+ *
+ * Since there is no serialization what so ever against page_remove_rmap()
+ * the best this function can do is return a locked anon_vma that might
+ * have been relevant to this page.
+ *
+ * The page might have been remapped to a different anon_vma or the anon_vma
+ * returned may already be freed (and even reused).
+ *
+ * In case it was remapped to a different anon_vma, the new anon_vma will be a
+ * child of the old anon_vma, and the anon_vma lifetime rules will therefore
+ * ensure that any anon_vma obtained from the page will still be valid for as
+ * long as we observe page_mapped() [ hence all those page_mapped() tests ].
+ *
+ * All users of this function must be very careful when walking the anon_vma
+ * chain and verify that the page in question is indeed mapped in it
+ * [ something equivalent to page_mapped_in_vma() ].
+ *
+ * Since anon_vma's slab is DESTROY_BY_RCU and we know from page_remove_rmap()
+ * that the anon_vma pointer from page->mapping is valid if there is a
+ * mapcount, we can dereference the anon_vma after observing those.
  */
-struct anon_vma *__page_lock_anon_vma(struct page *page)
+struct anon_vma *page_get_anon_vma(struct page *page)
 {
-       struct anon_vma *anon_vma, *root_anon_vma;
+       struct anon_vma *anon_vma = NULL;
        unsigned long anon_mapping;
 
        rcu_read_lock();
@@ -336,32 +422,100 @@ struct anon_vma *__page_lock_anon_vma(struct page *page)
                goto out;
 
        anon_vma = (struct anon_vma *) (anon_mapping - PAGE_MAPPING_ANON);
-       root_anon_vma = ACCESS_ONCE(anon_vma->root);
-       spin_lock(&root_anon_vma->lock);
+       if (!atomic_inc_not_zero(&anon_vma->refcount)) {
+               anon_vma = NULL;
+               goto out;
+       }
 
        /*
         * If this page is still mapped, then its anon_vma cannot have been
-        * freed.  But if it has been unmapped, we have no security against
-        * the anon_vma structure being freed and reused (for another anon_vma:
-        * SLAB_DESTROY_BY_RCU guarantees that - so the spin_lock above cannot
-        * corrupt): with anon_vma_prepare() or anon_vma_fork() redirecting
-        * anon_vma->root before page_unlock_anon_vma() is called to unlock.
+        * freed.  But if it has been unmapped, we have no security against the
+        * anon_vma structure being freed and reused (for another anon_vma:
+        * SLAB_DESTROY_BY_RCU guarantees that - so the atomic_inc_not_zero()
+        * above cannot corrupt).
         */
-       if (page_mapped(page))
-               return anon_vma;
+       if (!page_mapped(page)) {
+               put_anon_vma(anon_vma);
+               anon_vma = NULL;
+       }
+out:
+       rcu_read_unlock();
+
+       return anon_vma;
+}
+
+/*
+ * Similar to page_get_anon_vma() except it locks the anon_vma.
+ *
+ * Its a little more complex as it tries to keep the fast path to a single
+ * atomic op -- the trylock. If we fail the trylock, we fall back to getting a
+ * reference like with page_get_anon_vma() and then block on the mutex.
+ */
+struct anon_vma *page_lock_anon_vma(struct page *page)
+{
+       struct anon_vma *anon_vma = NULL;
+       struct anon_vma *root_anon_vma;
+       unsigned long anon_mapping;
+
+       rcu_read_lock();
+       anon_mapping = (unsigned long) ACCESS_ONCE(page->mapping);
+       if ((anon_mapping & PAGE_MAPPING_FLAGS) != PAGE_MAPPING_ANON)
+               goto out;
+       if (!page_mapped(page))
+               goto out;
+
+       anon_vma = (struct anon_vma *) (anon_mapping - PAGE_MAPPING_ANON);
+       root_anon_vma = ACCESS_ONCE(anon_vma->root);
+       if (mutex_trylock(&root_anon_vma->mutex)) {
+               /*
+                * If the page is still mapped, then this anon_vma is still
+                * its anon_vma, and holding the mutex ensures that it will
+                * not go away, see anon_vma_free().
+                */
+               if (!page_mapped(page)) {
+                       mutex_unlock(&root_anon_vma->mutex);
+                       anon_vma = NULL;
+               }
+               goto out;
+       }
+
+       /* trylock failed, we got to sleep */
+       if (!atomic_inc_not_zero(&anon_vma->refcount)) {
+               anon_vma = NULL;
+               goto out;
+       }
+
+       if (!page_mapped(page)) {
+               put_anon_vma(anon_vma);
+               anon_vma = NULL;
+               goto out;
+       }
+
+       /* we pinned the anon_vma, its safe to sleep */
+       rcu_read_unlock();
+       anon_vma_lock(anon_vma);
+
+       if (atomic_dec_and_test(&anon_vma->refcount)) {
+               /*
+                * Oops, we held the last refcount, release the lock
+                * and bail -- can't simply use put_anon_vma() because
+                * we'll deadlock on the anon_vma_lock() recursion.
+                */
+               anon_vma_unlock(anon_vma);
+               __put_anon_vma(anon_vma);
+               anon_vma = NULL;
+       }
+
+       return anon_vma;
 
-       spin_unlock(&root_anon_vma->lock);
 out:
        rcu_read_unlock();
-       return NULL;
+       return anon_vma;
 }
 
 void page_unlock_anon_vma(struct anon_vma *anon_vma)
-       __releases(&anon_vma->root->lock)
-       __releases(RCU)
 {
        anon_vma_unlock(anon_vma);
-       rcu_read_unlock();
 }
 
 /*
@@ -646,14 +800,14 @@ static int page_referenced_file(struct page *page,
         * The page lock not only makes sure that page->mapping cannot
         * suddenly be NULLified by truncation, it makes sure that the
         * structure at mapping cannot be freed and reused yet,
-        * so we can safely take mapping->i_mmap_lock.
+        * so we can safely take mapping->i_mmap_mutex.
         */
        BUG_ON(!PageLocked(page));
 
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
 
        /*
-        * i_mmap_lock does not stabilize mapcount at all, but mapcount
+        * i_mmap_mutex does not stabilize mapcount at all, but mapcount
         * is more likely to be accurate if we note it after spinning.
         */
        mapcount = page_mapcount(page);
@@ -675,7 +829,7 @@ static int page_referenced_file(struct page *page,
                        break;
        }
 
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
        return referenced;
 }
 
@@ -719,7 +873,7 @@ int page_referenced(struct page *page,
                        unlock_page(page);
        }
 out:
-       if (page_test_and_clear_young(page))
+       if (page_test_and_clear_young(page_to_pfn(page)))
                referenced++;
 
        return referenced;
@@ -762,7 +916,7 @@ static int page_mkclean_file(struct address_space *mapping, struct page *page)
 
        BUG_ON(PageAnon(page));
 
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
        vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
                if (vma->vm_flags & VM_SHARED) {
                        unsigned long address = vma_address(page, vma);
@@ -771,7 +925,7 @@ static int page_mkclean_file(struct address_space *mapping, struct page *page)
                        ret += page_mkclean_one(page, vma, address);
                }
        }
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
        return ret;
 }
 
@@ -785,10 +939,8 @@ int page_mkclean(struct page *page)
                struct address_space *mapping = page_mapping(page);
                if (mapping) {
                        ret = page_mkclean_file(mapping, page);
-                       if (page_test_dirty(page)) {
-                               page_clear_dirty(page, 1);
+                       if (page_test_and_clear_dirty(page_to_pfn(page), 1))
                                ret = 1;
-                       }
                }
        }
 
@@ -914,7 +1066,7 @@ void do_page_add_anon_rmap(struct page *page,
                return;
 
        VM_BUG_ON(!PageLocked(page));
-       VM_BUG_ON(address < vma->vm_start || address >= vma->vm_end);
+       /* address might be in next vma when migration races vma_adjust */
        if (first)
                __page_set_anon_rmap(page, vma, address, exclusive);
        else
@@ -981,10 +1133,9 @@ void page_remove_rmap(struct page *page)
         * not if it's in swapcache - there might be another pte slot
         * containing the swap entry, but page not yet written to swap.
         */
-       if ((!PageAnon(page) || PageSwapCache(page)) && page_test_dirty(page)) {
-               page_clear_dirty(page, 1);
+       if ((!PageAnon(page) || PageSwapCache(page)) &&
+           page_test_and_clear_dirty(page_to_pfn(page), 1))
                set_page_dirty(page);
-       }
        /*
         * Hugepages are not counted in NR_ANON_PAGES nor NR_FILE_MAPPED
         * and not charged by memcg for now.
@@ -1122,7 +1273,7 @@ out_mlock:
        /*
         * We need mmap_sem locking, Otherwise VM_LOCKED check makes
         * unstable result and race. Plus, We can't wait here because
-        * we now hold anon_vma->lock or mapping->i_mmap_lock.
+        * we now hold anon_vma->mutex or mapping->i_mmap_mutex.
         * if trylock failed, the page remain in evictable lru and later
         * vmscan could retry to move the page to unevictable lru if the
         * page is actually mlocked.
@@ -1348,7 +1499,7 @@ static int try_to_unmap_file(struct page *page, enum ttu_flags flags)
        unsigned long max_nl_size = 0;
        unsigned int mapcount;
 
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
        vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
                unsigned long address = vma_address(page, vma);
                if (address == -EFAULT)
@@ -1394,7 +1545,7 @@ static int try_to_unmap_file(struct page *page, enum ttu_flags flags)
        mapcount = page_mapcount(page);
        if (!mapcount)
                goto out;
-       cond_resched_lock(&mapping->i_mmap_lock);
+       cond_resched();
 
        max_nl_size = (max_nl_size + CLUSTER_SIZE - 1) & CLUSTER_MASK;
        if (max_nl_cursor == 0)
@@ -1416,7 +1567,7 @@ static int try_to_unmap_file(struct page *page, enum ttu_flags flags)
                        }
                        vma->vm_private_data = (void *) max_nl_cursor;
                }
-               cond_resched_lock(&mapping->i_mmap_lock);
+               cond_resched();
                max_nl_cursor += CLUSTER_SIZE;
        } while (max_nl_cursor <= max_nl_size);
 
@@ -1428,7 +1579,7 @@ static int try_to_unmap_file(struct page *page, enum ttu_flags flags)
        list_for_each_entry(vma, &mapping->i_mmap_nonlinear, shared.vm_set.list)
                vma->vm_private_data = NULL;
 out:
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
        return ret;
 }
 
@@ -1547,7 +1698,7 @@ static int rmap_walk_file(struct page *page, int (*rmap_one)(struct page *,
 
        if (!mapping)
                return ret;
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
        vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
                unsigned long address = vma_address(page, vma);
                if (address == -EFAULT)
@@ -1561,7 +1712,7 @@ static int rmap_walk_file(struct page *page, int (*rmap_one)(struct page *,
         * never contain migration ptes.  Decide what to do about this
         * limitation to linear when we need rmap_walk() on nonlinear.
         */
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
        return ret;
 }
 
@@ -1610,7 +1761,7 @@ void hugepage_add_anon_rmap(struct page *page,
 
        BUG_ON(!PageLocked(page));
        BUG_ON(!anon_vma);
-       BUG_ON(address < vma->vm_start || address >= vma->vm_end);
+       /* address might be in next vma when migration races vma_adjust */
        first = atomic_inc_and_test(&page->_mapcount);
        if (first)
                __hugepage_set_anon_rmap(page, vma, address, 0);
index ba4ad28b7db6b81c141915a5d3eb4241fdbfd1a7..d221a1cfd7b196175ab9134aac147b22400c13e6 100644 (file)
@@ -99,6 +99,13 @@ static struct vfsmount *shm_mnt;
 /* Pretend that each entry is of this size in directory's i_size */
 #define BOGO_DIRENT_SIZE 20
 
+struct shmem_xattr {
+       struct list_head list;  /* anchored by shmem_inode_info->xattr_list */
+       char *name;             /* xattr name */
+       size_t size;
+       char value[0];
+};
+
 /* Flag allocation requirements to shmem_getpage and shmem_swp_alloc */
 enum sgp_type {
        SGP_READ,       /* don't exceed i_size, don't allocate page */
@@ -822,6 +829,7 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
 static void shmem_evict_inode(struct inode *inode)
 {
        struct shmem_inode_info *info = SHMEM_I(inode);
+       struct shmem_xattr *xattr, *nxattr;
 
        if (inode->i_mapping->a_ops == &shmem_aops) {
                truncate_inode_pages(inode->i_mapping, 0);
@@ -834,6 +842,11 @@ static void shmem_evict_inode(struct inode *inode)
                        mutex_unlock(&shmem_swaplist_mutex);
                }
        }
+
+       list_for_each_entry_safe(xattr, nxattr, &info->xattr_list, list) {
+               kfree(xattr->name);
+               kfree(xattr);
+       }
        BUG_ON(inode->i_blocks);
        shmem_free_inode(inode->i_sb);
        end_writeback(inode);
@@ -1101,8 +1114,8 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
                delete_from_page_cache(page);
                shmem_swp_set(info, entry, swap.val);
                shmem_swp_unmap(entry);
-               spin_unlock(&info->lock);
                swap_shmem_alloc(swap);
+               spin_unlock(&info->lock);
                BUG_ON(page_mapped(page));
                swap_writepage(page, wbc);
                return 0;
@@ -1292,12 +1305,10 @@ repeat:
                swappage = lookup_swap_cache(swap);
                if (!swappage) {
                        shmem_swp_unmap(entry);
+                       spin_unlock(&info->lock);
                        /* here we actually do the io */
-                       if (type && !(*type & VM_FAULT_MAJOR)) {
-                               __count_vm_event(PGMAJFAULT);
+                       if (type)
                                *type |= VM_FAULT_MAJOR;
-                       }
-                       spin_unlock(&info->lock);
                        swappage = shmem_swapin(swap, gfp, info, idx);
                        if (!swappage) {
                                spin_lock(&info->lock);
@@ -1536,7 +1547,10 @@ static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_CACHE, &ret);
        if (error)
                return ((error == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS);
-
+       if (ret & VM_FAULT_MAJOR) {
+               count_vm_event(PGMAJFAULT);
+               mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT);
+       }
        return ret | VM_FAULT_LOCKED;
 }
 
@@ -1615,6 +1629,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
                spin_lock_init(&info->lock);
                info->flags = flags & VM_NORESERVE;
                INIT_LIST_HEAD(&info->swaplist);
+               INIT_LIST_HEAD(&info->xattr_list);
                cache_no_acl(inode);
 
                switch (mode & S_IFMT) {
@@ -2014,9 +2029,9 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
 
        info = SHMEM_I(inode);
        inode->i_size = len-1;
-       if (len <= (char *)inode - (char *)info) {
+       if (len <= SHMEM_SYMLINK_INLINE_LEN) {
                /* do it inline */
-               memcpy(info, symname, len);
+               memcpy(info->inline_symlink, symname, len);
                inode->i_op = &shmem_symlink_inline_operations;
        } else {
                error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
@@ -2042,7 +2057,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
 
 static void *shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd)
 {
-       nd_set_link(nd, (char *)SHMEM_I(dentry->d_inode));
+       nd_set_link(nd, SHMEM_I(dentry->d_inode)->inline_symlink);
        return NULL;
 }
 
@@ -2066,63 +2081,253 @@ static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *co
        }
 }
 
-static const struct inode_operations shmem_symlink_inline_operations = {
-       .readlink       = generic_readlink,
-       .follow_link    = shmem_follow_link_inline,
-};
-
-static const struct inode_operations shmem_symlink_inode_operations = {
-       .readlink       = generic_readlink,
-       .follow_link    = shmem_follow_link,
-       .put_link       = shmem_put_link,
-};
-
-#ifdef CONFIG_TMPFS_POSIX_ACL
+#ifdef CONFIG_TMPFS_XATTR
 /*
- * Superblocks without xattr inode operations will get security.* xattr
- * support from the VFS "for free". As soon as we have any other xattrs
+ * Superblocks without xattr inode operations may get some security.* xattr
+ * support from the LSM "for free". As soon as we have any other xattrs
  * like ACLs, we also need to implement the security.* handlers at
  * filesystem level, though.
  */
 
-static size_t shmem_xattr_security_list(struct dentry *dentry, char *list,
-                                       size_t list_len, const char *name,
-                                       size_t name_len, int handler_flags)
+static int shmem_xattr_get(struct dentry *dentry, const char *name,
+                          void *buffer, size_t size)
 {
-       return security_inode_listsecurity(dentry->d_inode, list, list_len);
-}
+       struct shmem_inode_info *info;
+       struct shmem_xattr *xattr;
+       int ret = -ENODATA;
 
-static int shmem_xattr_security_get(struct dentry *dentry, const char *name,
-               void *buffer, size_t size, int handler_flags)
-{
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
-       return xattr_getsecurity(dentry->d_inode, name, buffer, size);
+       info = SHMEM_I(dentry->d_inode);
+
+       spin_lock(&info->lock);
+       list_for_each_entry(xattr, &info->xattr_list, list) {
+               if (strcmp(name, xattr->name))
+                       continue;
+
+               ret = xattr->size;
+               if (buffer) {
+                       if (size < xattr->size)
+                               ret = -ERANGE;
+                       else
+                               memcpy(buffer, xattr->value, xattr->size);
+               }
+               break;
+       }
+       spin_unlock(&info->lock);
+       return ret;
 }
 
-static int shmem_xattr_security_set(struct dentry *dentry, const char *name,
-               const void *value, size_t size, int flags, int handler_flags)
+static int shmem_xattr_set(struct dentry *dentry, const char *name,
+                          const void *value, size_t size, int flags)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
-       return security_inode_setsecurity(dentry->d_inode, name, value,
-                                         size, flags);
+       struct inode *inode = dentry->d_inode;
+       struct shmem_inode_info *info = SHMEM_I(inode);
+       struct shmem_xattr *xattr;
+       struct shmem_xattr *new_xattr = NULL;
+       size_t len;
+       int err = 0;
+
+       /* value == NULL means remove */
+       if (value) {
+               /* wrap around? */
+               len = sizeof(*new_xattr) + size;
+               if (len <= sizeof(*new_xattr))
+                       return -ENOMEM;
+
+               new_xattr = kmalloc(len, GFP_KERNEL);
+               if (!new_xattr)
+                       return -ENOMEM;
+
+               new_xattr->name = kstrdup(name, GFP_KERNEL);
+               if (!new_xattr->name) {
+                       kfree(new_xattr);
+                       return -ENOMEM;
+               }
+
+               new_xattr->size = size;
+               memcpy(new_xattr->value, value, size);
+       }
+
+       spin_lock(&info->lock);
+       list_for_each_entry(xattr, &info->xattr_list, list) {
+               if (!strcmp(name, xattr->name)) {
+                       if (flags & XATTR_CREATE) {
+                               xattr = new_xattr;
+                               err = -EEXIST;
+                       } else if (new_xattr) {
+                               list_replace(&xattr->list, &new_xattr->list);
+                       } else {
+                               list_del(&xattr->list);
+                       }
+                       goto out;
+               }
+       }
+       if (flags & XATTR_REPLACE) {
+               xattr = new_xattr;
+               err = -ENODATA;
+       } else {
+               list_add(&new_xattr->list, &info->xattr_list);
+               xattr = NULL;
+       }
+out:
+       spin_unlock(&info->lock);
+       if (xattr)
+               kfree(xattr->name);
+       kfree(xattr);
+       return err;
 }
 
-static const struct xattr_handler shmem_xattr_security_handler = {
-       .prefix = XATTR_SECURITY_PREFIX,
-       .list   = shmem_xattr_security_list,
-       .get    = shmem_xattr_security_get,
-       .set    = shmem_xattr_security_set,
-};
 
 static const struct xattr_handler *shmem_xattr_handlers[] = {
+#ifdef CONFIG_TMPFS_POSIX_ACL
        &generic_acl_access_handler,
        &generic_acl_default_handler,
-       &shmem_xattr_security_handler,
+#endif
        NULL
 };
+
+static int shmem_xattr_validate(const char *name)
+{
+       struct { const char *prefix; size_t len; } arr[] = {
+               { XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN },
+               { XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN }
+       };
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(arr); i++) {
+               size_t preflen = arr[i].len;
+               if (strncmp(name, arr[i].prefix, preflen) == 0) {
+                       if (!name[preflen])
+                               return -EINVAL;
+                       return 0;
+               }
+       }
+       return -EOPNOTSUPP;
+}
+
+static ssize_t shmem_getxattr(struct dentry *dentry, const char *name,
+                             void *buffer, size_t size)
+{
+       int err;
+
+       /*
+        * If this is a request for a synthetic attribute in the system.*
+        * namespace use the generic infrastructure to resolve a handler
+        * for it via sb->s_xattr.
+        */
+       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+               return generic_getxattr(dentry, name, buffer, size);
+
+       err = shmem_xattr_validate(name);
+       if (err)
+               return err;
+
+       return shmem_xattr_get(dentry, name, buffer, size);
+}
+
+static int shmem_setxattr(struct dentry *dentry, const char *name,
+                         const void *value, size_t size, int flags)
+{
+       int err;
+
+       /*
+        * If this is a request for a synthetic attribute in the system.*
+        * namespace use the generic infrastructure to resolve a handler
+        * for it via sb->s_xattr.
+        */
+       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+               return generic_setxattr(dentry, name, value, size, flags);
+
+       err = shmem_xattr_validate(name);
+       if (err)
+               return err;
+
+       if (size == 0)
+               value = "";  /* empty EA, do not remove */
+
+       return shmem_xattr_set(dentry, name, value, size, flags);
+
+}
+
+static int shmem_removexattr(struct dentry *dentry, const char *name)
+{
+       int err;
+
+       /*
+        * If this is a request for a synthetic attribute in the system.*
+        * namespace use the generic infrastructure to resolve a handler
+        * for it via sb->s_xattr.
+        */
+       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+               return generic_removexattr(dentry, name);
+
+       err = shmem_xattr_validate(name);
+       if (err)
+               return err;
+
+       return shmem_xattr_set(dentry, name, NULL, 0, XATTR_REPLACE);
+}
+
+static bool xattr_is_trusted(const char *name)
+{
+       return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
+}
+
+static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
+{
+       bool trusted = capable(CAP_SYS_ADMIN);
+       struct shmem_xattr *xattr;
+       struct shmem_inode_info *info;
+       size_t used = 0;
+
+       info = SHMEM_I(dentry->d_inode);
+
+       spin_lock(&info->lock);
+       list_for_each_entry(xattr, &info->xattr_list, list) {
+               size_t len;
+
+               /* skip "trusted." attributes for unprivileged callers */
+               if (!trusted && xattr_is_trusted(xattr->name))
+                       continue;
+
+               len = strlen(xattr->name) + 1;
+               used += len;
+               if (buffer) {
+                       if (size < used) {
+                               used = -ERANGE;
+                               break;
+                       }
+                       memcpy(buffer, xattr->name, len);
+                       buffer += len;
+               }
+       }
+       spin_unlock(&info->lock);
+
+       return used;
+}
+#endif /* CONFIG_TMPFS_XATTR */
+
+static const struct inode_operations shmem_symlink_inline_operations = {
+       .readlink       = generic_readlink,
+       .follow_link    = shmem_follow_link_inline,
+#ifdef CONFIG_TMPFS_XATTR
+       .setxattr       = shmem_setxattr,
+       .getxattr       = shmem_getxattr,
+       .listxattr      = shmem_listxattr,
+       .removexattr    = shmem_removexattr,
 #endif
+};
+
+static const struct inode_operations shmem_symlink_inode_operations = {
+       .readlink       = generic_readlink,
+       .follow_link    = shmem_follow_link,
+       .put_link       = shmem_put_link,
+#ifdef CONFIG_TMPFS_XATTR
+       .setxattr       = shmem_setxattr,
+       .getxattr       = shmem_getxattr,
+       .listxattr      = shmem_listxattr,
+       .removexattr    = shmem_removexattr,
+#endif
+};
 
 static struct dentry *shmem_get_parent(struct dentry *child)
 {
@@ -2402,8 +2607,10 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_magic = TMPFS_MAGIC;
        sb->s_op = &shmem_ops;
        sb->s_time_gran = 1;
-#ifdef CONFIG_TMPFS_POSIX_ACL
+#ifdef CONFIG_TMPFS_XATTR
        sb->s_xattr = shmem_xattr_handlers;
+#endif
+#ifdef CONFIG_TMPFS_POSIX_ACL
        sb->s_flags |= MS_POSIXACL;
 #endif
 
@@ -2501,11 +2708,13 @@ static const struct file_operations shmem_file_operations = {
 static const struct inode_operations shmem_inode_operations = {
        .setattr        = shmem_notify_change,
        .truncate_range = shmem_truncate_range,
+#ifdef CONFIG_TMPFS_XATTR
+       .setxattr       = shmem_setxattr,
+       .getxattr       = shmem_getxattr,
+       .listxattr      = shmem_listxattr,
+       .removexattr    = shmem_removexattr,
+#endif
 #ifdef CONFIG_TMPFS_POSIX_ACL
-       .setxattr       = generic_setxattr,
-       .getxattr       = generic_getxattr,
-       .listxattr      = generic_listxattr,
-       .removexattr    = generic_removexattr,
        .check_acl      = generic_check_acl,
 #endif
 
@@ -2523,23 +2732,27 @@ static const struct inode_operations shmem_dir_inode_operations = {
        .mknod          = shmem_mknod,
        .rename         = shmem_rename,
 #endif
+#ifdef CONFIG_TMPFS_XATTR
+       .setxattr       = shmem_setxattr,
+       .getxattr       = shmem_getxattr,
+       .listxattr      = shmem_listxattr,
+       .removexattr    = shmem_removexattr,
+#endif
 #ifdef CONFIG_TMPFS_POSIX_ACL
        .setattr        = shmem_notify_change,
-       .setxattr       = generic_setxattr,
-       .getxattr       = generic_getxattr,
-       .listxattr      = generic_listxattr,
-       .removexattr    = generic_removexattr,
        .check_acl      = generic_check_acl,
 #endif
 };
 
 static const struct inode_operations shmem_special_inode_operations = {
+#ifdef CONFIG_TMPFS_XATTR
+       .setxattr       = shmem_setxattr,
+       .getxattr       = shmem_getxattr,
+       .listxattr      = shmem_listxattr,
+       .removexattr    = shmem_removexattr,
+#endif
 #ifdef CONFIG_TMPFS_POSIX_ACL
        .setattr        = shmem_notify_change,
-       .setxattr       = generic_setxattr,
-       .getxattr       = generic_getxattr,
-       .listxattr      = generic_listxattr,
-       .removexattr    = generic_removexattr,
        .check_acl      = generic_check_acl,
 #endif
 };
index bcfa4987c8ae2c9fc273f1baf75d4461ed743052..d96e223de775378f78d7597d8c2d87a9e24e70a2 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3604,13 +3604,14 @@ free_done:
  * Release an obj back to its cache. If the obj has a constructed state, it must
  * be in this state _before_ it is released.  Called with disabled ints.
  */
-static inline void __cache_free(struct kmem_cache *cachep, void *objp)
+static inline void __cache_free(struct kmem_cache *cachep, void *objp,
+    void *caller)
 {
        struct array_cache *ac = cpu_cache_get(cachep);
 
        check_irq_off();
        kmemleak_free_recursive(objp, cachep->flags);
-       objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0));
+       objp = cache_free_debugcheck(cachep, objp, caller);
 
        kmemcheck_slab_free(cachep, objp, obj_size(cachep));
 
@@ -3801,7 +3802,7 @@ void kmem_cache_free(struct kmem_cache *cachep, void *objp)
        debug_check_no_locks_freed(objp, obj_size(cachep));
        if (!(cachep->flags & SLAB_DEBUG_OBJECTS))
                debug_check_no_obj_freed(objp, obj_size(cachep));
-       __cache_free(cachep, objp);
+       __cache_free(cachep, objp, __builtin_return_address(0));
        local_irq_restore(flags);
 
        trace_kmem_cache_free(_RET_IP_, objp);
@@ -3831,7 +3832,7 @@ void kfree(const void *objp)
        c = virt_to_cache(objp);
        debug_check_no_locks_freed(objp, obj_size(c));
        debug_check_no_obj_freed(objp, obj_size(c));
-       __cache_free(c, (void *)objp);
+       __cache_free(c, (void *)objp, __builtin_return_address(0));
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL(kfree);
index 4ea7f1a22a9468f332f529c60e7be0b85a97616f..35f351f26193a47145cd8bcb7f55ae091331ca97 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1831,7 +1831,6 @@ load_freelist:
        page->inuse = page->objects;
        page->freelist = NULL;
 
-unlock_out:
        slab_unlock(page);
        c->tid = next_tid(c->tid);
        local_irq_restore(flags);
@@ -1884,7 +1883,8 @@ debug:
        deactivate_slab(s, c);
        c->page = NULL;
        c->node = NUMA_NO_NODE;
-       goto unlock_out;
+       local_irq_restore(flags);
+       return object;
 }
 
 /*
@@ -2320,16 +2320,12 @@ static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
        BUILD_BUG_ON(PERCPU_DYNAMIC_EARLY_SIZE <
                        SLUB_PAGE_SHIFT * sizeof(struct kmem_cache_cpu));
 
-#ifdef CONFIG_CMPXCHG_LOCAL
        /*
-        * Must align to double word boundary for the double cmpxchg instructions
-        * to work.
+        * Must align to double word boundary for the double cmpxchg
+        * instructions to work; see __pcpu_double_call_return_bool().
         */
-       s->cpu_slab = __alloc_percpu(sizeof(struct kmem_cache_cpu), 2 * sizeof(void *));
-#else
-       /* Regular alignment is sufficient */
-       s->cpu_slab = alloc_percpu(struct kmem_cache_cpu);
-#endif
+       s->cpu_slab = __alloc_percpu(sizeof(struct kmem_cache_cpu),
+                                    2 * sizeof(void *));
 
        if (!s->cpu_slab)
                return 0;
index 5602f1a1b1e724ba547bdee3ef21d773fd24ee04..3a442f18b0b3dab5acfd99b5fc4e85389b9b5439 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -272,14 +272,10 @@ static void update_page_reclaim_stat(struct zone *zone, struct page *page,
                memcg_reclaim_stat->recent_rotated[file]++;
 }
 
-/*
- * FIXME: speed this up?
- */
-void activate_page(struct page *page)
+static void __activate_page(struct page *page, void *arg)
 {
        struct zone *zone = page_zone(page);
 
-       spin_lock_irq(&zone->lru_lock);
        if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
                int file = page_is_file_cache(page);
                int lru = page_lru_base_type(page);
@@ -292,8 +288,45 @@ void activate_page(struct page *page)
 
                update_page_reclaim_stat(zone, page, file, 1);
        }
+}
+
+#ifdef CONFIG_SMP
+static DEFINE_PER_CPU(struct pagevec, activate_page_pvecs);
+
+static void activate_page_drain(int cpu)
+{
+       struct pagevec *pvec = &per_cpu(activate_page_pvecs, cpu);
+
+       if (pagevec_count(pvec))
+               pagevec_lru_move_fn(pvec, __activate_page, NULL);
+}
+
+void activate_page(struct page *page)
+{
+       if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
+               struct pagevec *pvec = &get_cpu_var(activate_page_pvecs);
+
+               page_cache_get(page);
+               if (!pagevec_add(pvec, page))
+                       pagevec_lru_move_fn(pvec, __activate_page, NULL);
+               put_cpu_var(activate_page_pvecs);
+       }
+}
+
+#else
+static inline void activate_page_drain(int cpu)
+{
+}
+
+void activate_page(struct page *page)
+{
+       struct zone *zone = page_zone(page);
+
+       spin_lock_irq(&zone->lru_lock);
+       __activate_page(page, NULL);
        spin_unlock_irq(&zone->lru_lock);
 }
+#endif
 
 /*
  * Mark a page as having seen activity.
@@ -464,6 +497,8 @@ static void drain_cpu_pagevecs(int cpu)
        pvec = &per_cpu(lru_deactivate_pvecs, cpu);
        if (pagevec_count(pvec))
                pagevec_lru_move_fn(pvec, lru_deactivate_fn, NULL);
+
+       activate_page_drain(cpu);
 }
 
 /**
@@ -476,6 +511,13 @@ static void drain_cpu_pagevecs(int cpu)
  */
 void deactivate_page(struct page *page)
 {
+       /*
+        * In a workload with many unevictable page such as mprotect, unevictable
+        * page deactivation for accelerating reclaim is pointless.
+        */
+       if (PageUnevictable(page))
+               return;
+
        if (likely(get_page_unless_zero(page))) {
                struct pagevec *pvec = &get_cpu_var(lru_deactivate_pvecs);
 
index 8c6b3ce38f09aa0e4f824ce3f70e6e9254a87724..d537d29e9b7bb5d9364b531e17f972618a5cad4b 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/syscalls.h>
 #include <linux/memcontrol.h>
 #include <linux/poll.h>
+#include <linux/oom.h>
 
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
@@ -1555,6 +1556,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
        struct address_space *mapping;
        struct inode *inode;
        char *pathname;
+       int oom_score_adj;
        int i, type, prev;
        int err;
 
@@ -1613,9 +1615,9 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
        p->flags &= ~SWP_WRITEOK;
        spin_unlock(&swap_lock);
 
-       current->flags |= PF_OOM_ORIGIN;
+       oom_score_adj = test_set_oom_score_adj(OOM_SCORE_ADJ_MAX);
        err = try_to_unuse(type);
-       current->flags &= ~PF_OOM_ORIGIN;
+       test_set_oom_score_adj(oom_score_adj);
 
        if (err) {
                /*
index 2372d4ed5dd8ff763d3aaed5cb546c8033eca1ff..fabf2d0f51695eddacdb6b013fac0b9cdee3a655 100644 (file)
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/swap.h>
+#include <linux/memcontrol.h>
+
+#include <trace/events/vmscan.h>
+
+#define TOKEN_AGING_INTERVAL   (0xFF)
 
 static DEFINE_SPINLOCK(swap_token_lock);
 struct mm_struct *swap_token_mm;
+struct mem_cgroup *swap_token_memcg;
 static unsigned int global_faults;
+static unsigned int last_aging;
+
+#ifdef CONFIG_CGROUP_MEM_RES_CTLR
+static struct mem_cgroup *swap_token_memcg_from_mm(struct mm_struct *mm)
+{
+       struct mem_cgroup *memcg;
+
+       memcg = try_get_mem_cgroup_from_mm(mm);
+       if (memcg)
+               css_put(mem_cgroup_css(memcg));
+
+       return memcg;
+}
+#else
+static struct mem_cgroup *swap_token_memcg_from_mm(struct mm_struct *mm)
+{
+       return NULL;
+}
+#endif
 
 void grab_swap_token(struct mm_struct *mm)
 {
        int current_interval;
+       unsigned int old_prio = mm->token_priority;
 
        global_faults++;
 
@@ -38,40 +64,81 @@ void grab_swap_token(struct mm_struct *mm)
                return;
 
        /* First come first served */
-       if (swap_token_mm == NULL) {
-               mm->token_priority = mm->token_priority + 2;
-               swap_token_mm = mm;
-               goto out;
+       if (!swap_token_mm)
+               goto replace_token;
+
+       if ((global_faults - last_aging) > TOKEN_AGING_INTERVAL) {
+               swap_token_mm->token_priority /= 2;
+               last_aging = global_faults;
        }
 
-       if (mm != swap_token_mm) {
-               if (current_interval < mm->last_interval)
-                       mm->token_priority++;
-               else {
-                       if (likely(mm->token_priority > 0))
-                               mm->token_priority--;
-               }
-               /* Check if we deserve the token */
-               if (mm->token_priority > swap_token_mm->token_priority) {
-                       mm->token_priority += 2;
-                       swap_token_mm = mm;
-               }
-       } else {
-               /* Token holder came in again! */
+       if (mm == swap_token_mm) {
                mm->token_priority += 2;
+               goto update_priority;
+       }
+
+       if (current_interval < mm->last_interval)
+               mm->token_priority++;
+       else {
+               if (likely(mm->token_priority > 0))
+                       mm->token_priority--;
        }
 
+       /* Check if we deserve the token */
+       if (mm->token_priority > swap_token_mm->token_priority)
+               goto replace_token;
+
+update_priority:
+       trace_update_swap_token_priority(mm, old_prio, swap_token_mm);
+
 out:
        mm->faultstamp = global_faults;
        mm->last_interval = current_interval;
        spin_unlock(&swap_token_lock);
+       return;
+
+replace_token:
+       mm->token_priority += 2;
+       trace_replace_swap_token(swap_token_mm, mm);
+       swap_token_mm = mm;
+       swap_token_memcg = swap_token_memcg_from_mm(mm);
+       last_aging = global_faults;
+       goto out;
 }
 
 /* Called on process exit. */
 void __put_swap_token(struct mm_struct *mm)
 {
        spin_lock(&swap_token_lock);
-       if (likely(mm == swap_token_mm))
+       if (likely(mm == swap_token_mm)) {
+               trace_put_swap_token(swap_token_mm);
                swap_token_mm = NULL;
+               swap_token_memcg = NULL;
+       }
        spin_unlock(&swap_token_lock);
 }
+
+static bool match_memcg(struct mem_cgroup *a, struct mem_cgroup *b)
+{
+       if (!a)
+               return true;
+       if (!b)
+               return true;
+       if (a == b)
+               return true;
+       return false;
+}
+
+void disable_swap_token(struct mem_cgroup *memcg)
+{
+       /* memcg reclaim don't disable unrelated mm token. */
+       if (match_memcg(memcg, swap_token_memcg)) {
+               spin_lock(&swap_token_lock);
+               if (match_memcg(memcg, swap_token_memcg)) {
+                       trace_disable_swap_token(swap_token_mm);
+                       swap_token_mm = NULL;
+                       swap_token_memcg = NULL;
+               }
+               spin_unlock(&swap_token_lock);
+       }
+}
index a9566752913596152022f5d22983cb4f2cb4d2cf..3a29a6180212d7bcf25ab0d6fd97acdb16fc8f42 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/task_io_accounting_ops.h>
 #include <linux/buffer_head.h> /* grr. try_to_release_page,
                                   do_invalidatepage */
+#include <linux/cleancache.h>
 #include "internal.h"
 
 
@@ -51,6 +52,7 @@ void do_invalidatepage(struct page *page, unsigned long offset)
 static inline void truncate_partial_page(struct page *page, unsigned partial)
 {
        zero_user_segment(page, partial, PAGE_CACHE_SIZE);
+       cleancache_flush_page(page->mapping, page);
        if (page_has_private(page))
                do_invalidatepage(page, partial);
 }
@@ -214,6 +216,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
        pgoff_t next;
        int i;
 
+       cleancache_flush_inode(mapping);
        if (mapping->nrpages == 0)
                return;
 
@@ -291,6 +294,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
                pagevec_release(&pvec);
                mem_cgroup_uncharge_end();
        }
+       cleancache_flush_inode(mapping);
 }
 EXPORT_SYMBOL(truncate_inode_pages_range);
 
@@ -440,6 +444,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
        int did_range_unmap = 0;
        int wrapped = 0;
 
+       cleancache_flush_inode(mapping);
        pagevec_init(&pvec, 0);
        next = start;
        while (next <= end && !wrapped &&
@@ -498,6 +503,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
                mem_cgroup_uncharge_end();
                cond_resched();
        }
+       cleancache_flush_inode(mapping);
        return ret;
 }
 EXPORT_SYMBOL_GPL(invalidate_inode_pages2_range);
index e7b103a6fd21c50857eda25cb5750e6d319e6498..88ea1bd661c0f5164e37a8415050808fa815808f 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -6,6 +6,8 @@
 #include <linux/sched.h>
 #include <asm/uaccess.h>
 
+#include "internal.h"
+
 #define CREATE_TRACE_POINTS
 #include <trace/events/kmem.h>
 
@@ -215,6 +217,28 @@ char *strndup_user(const char __user *s, long n)
 }
 EXPORT_SYMBOL(strndup_user);
 
+void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
+               struct vm_area_struct *prev, struct rb_node *rb_parent)
+{
+       struct vm_area_struct *next;
+
+       vma->vm_prev = prev;
+       if (prev) {
+               next = prev->vm_next;
+               prev->vm_next = vma;
+       } else {
+               mm->mmap = vma;
+               if (rb_parent)
+                       next = rb_entry(rb_parent,
+                                       struct vm_area_struct, vm_rb);
+               else
+                       next = NULL;
+       }
+       vma->vm_next = next;
+       if (next)
+               next->vm_prev = vma;
+}
+
 #if defined(CONFIG_MMU) && !defined(HAVE_ARCH_PICK_MMAP_LAYOUT)
 void arch_pick_mmap_layout(struct mm_struct *mm)
 {
index 5d6030235d7a8e4462498e6d9154ca97029069ed..1d34d75366a7d6902d3dd826bdcab42848c9503c 100644 (file)
@@ -375,7 +375,7 @@ nocache:
        /* find starting point for our search */
        if (free_vmap_cache) {
                first = rb_entry(free_vmap_cache, struct vmap_area, rb_node);
-               addr = ALIGN(first->va_end + PAGE_SIZE, align);
+               addr = ALIGN(first->va_end, align);
                if (addr < vstart)
                        goto nocache;
                if (addr + size - 1 < addr)
@@ -406,10 +406,10 @@ nocache:
        }
 
        /* from the starting point, walk areas until a suitable hole is found */
-       while (addr + size >= first->va_start && addr + size <= vend) {
+       while (addr + size > first->va_start && addr + size <= vend) {
                if (addr + cached_hole_size < first->va_start)
                        cached_hole_size = first->va_start - addr;
-               addr = ALIGN(first->va_end + PAGE_SIZE, align);
+               addr = ALIGN(first->va_end, align);
                if (addr + size - 1 < addr)
                        goto overflow;
 
@@ -1534,6 +1534,7 @@ static void *__vmalloc_node(unsigned long size, unsigned long align,
 static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
                                 pgprot_t prot, int node, void *caller)
 {
+       const int order = 0;
        struct page **pages;
        unsigned int nr_pages, array_size, i;
        gfp_t nested_gfp = (gfp_mask & GFP_RECLAIM_MASK) | __GFP_ZERO;
@@ -1560,11 +1561,12 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
 
        for (i = 0; i < area->nr_pages; i++) {
                struct page *page;
+               gfp_t tmp_mask = gfp_mask | __GFP_NOWARN;
 
                if (node < 0)
-                       page = alloc_page(gfp_mask);
+                       page = alloc_page(tmp_mask);
                else
-                       page = alloc_pages_node(node, gfp_mask, 0);
+                       page = alloc_pages_node(node, tmp_mask, order);
 
                if (unlikely(!page)) {
                        /* Successfully allocated i pages, free them in __vunmap() */
@@ -1579,6 +1581,9 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
        return area->addr;
 
 fail:
+       warn_alloc_failed(gfp_mask, order, "vmalloc: allocation failure, "
+                         "allocated %ld of %ld bytes\n",
+                         (area->nr_pages*PAGE_SIZE), area->size);
        vfree(area->addr);
        return NULL;
 }
@@ -2148,10 +2153,6 @@ struct vm_struct *alloc_vm_area(size_t size)
                return NULL;
        }
 
-       /* Make sure the pagetables are constructed in process kernel
-          mappings */
-       vmalloc_sync_all();
-
        return area;
 }
 EXPORT_SYMBOL_GPL(alloc_vm_area);
index c9177202c8ce2ce2f9bfe9045f2a40a8105de8e8..8ff834e19c2460d33844e43154b058974a6c9849 100644 (file)
@@ -173,7 +173,7 @@ static unsigned long zone_nr_lru_pages(struct zone *zone,
                                struct scan_control *sc, enum lru_list lru)
 {
        if (!scanning_global_lru(sc))
-               return mem_cgroup_zone_nr_pages(sc->mem_cgroup, zone, lru);
+               return mem_cgroup_zone_nr_lru_pages(sc->mem_cgroup, zone, lru);
 
        return zone_page_state(zone, NR_LRU_BASE + lru);
 }
@@ -202,6 +202,14 @@ void unregister_shrinker(struct shrinker *shrinker)
 }
 EXPORT_SYMBOL(unregister_shrinker);
 
+static inline int do_shrinker_shrink(struct shrinker *shrinker,
+                                    struct shrink_control *sc,
+                                    unsigned long nr_to_scan)
+{
+       sc->nr_to_scan = nr_to_scan;
+       return (*shrinker->shrink)(shrinker, sc);
+}
+
 #define SHRINK_BATCH 128
 /*
  * Call the shrink functions to age shrinkable caches
@@ -222,25 +230,29 @@ EXPORT_SYMBOL(unregister_shrinker);
  *
  * Returns the number of slab objects which we shrunk.
  */
-unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
-                       unsigned long lru_pages)
+unsigned long shrink_slab(struct shrink_control *shrink,
+                         unsigned long nr_pages_scanned,
+                         unsigned long lru_pages)
 {
        struct shrinker *shrinker;
        unsigned long ret = 0;
 
-       if (scanned == 0)
-               scanned = SWAP_CLUSTER_MAX;
+       if (nr_pages_scanned == 0)
+               nr_pages_scanned = SWAP_CLUSTER_MAX;
 
-       if (!down_read_trylock(&shrinker_rwsem))
-               return 1;       /* Assume we'll be able to shrink next time */
+       if (!down_read_trylock(&shrinker_rwsem)) {
+               /* Assume we'll be able to shrink next time */
+               ret = 1;
+               goto out;
+       }
 
        list_for_each_entry(shrinker, &shrinker_list, list) {
                unsigned long long delta;
                unsigned long total_scan;
                unsigned long max_pass;
 
-               max_pass = (*shrinker->shrink)(shrinker, 0, gfp_mask);
-               delta = (4 * scanned) / shrinker->seeks;
+               max_pass = do_shrinker_shrink(shrinker, shrink, 0);
+               delta = (4 * nr_pages_scanned) / shrinker->seeks;
                delta *= max_pass;
                do_div(delta, lru_pages + 1);
                shrinker->nr += delta;
@@ -267,9 +279,9 @@ unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
                        int shrink_ret;
                        int nr_before;
 
-                       nr_before = (*shrinker->shrink)(shrinker, 0, gfp_mask);
-                       shrink_ret = (*shrinker->shrink)(shrinker, this_scan,
-                                                               gfp_mask);
+                       nr_before = do_shrinker_shrink(shrinker, shrink, 0);
+                       shrink_ret = do_shrinker_shrink(shrinker, shrink,
+                                                       this_scan);
                        if (shrink_ret == -1)
                                break;
                        if (shrink_ret < nr_before)
@@ -283,6 +295,8 @@ unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
                shrinker->nr += total_scan;
        }
        up_read(&shrinker_rwsem);
+out:
+       cond_resched();
        return ret;
 }
 
@@ -1110,8 +1124,20 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
                                        nr_lumpy_dirty++;
                                scan++;
                        } else {
-                               /* the page is freed already. */
-                               if (!page_count(cursor_page))
+                               /*
+                                * Check if the page is freed already.
+                                *
+                                * We can't use page_count() as that
+                                * requires compound_head and we don't
+                                * have a pin on the page here. If a
+                                * page is tail, we may or may not
+                                * have isolated the head, so assume
+                                * it's not free, it'd be tricky to
+                                * track the head status without a
+                                * page pin.
+                                */
+                               if (!PageTail(cursor_page) &&
+                                   !atomic_read(&cursor_page->_count))
                                        continue;
                                break;
                        }
@@ -1202,13 +1228,16 @@ int isolate_lru_page(struct page *page)
 {
        int ret = -EBUSY;
 
+       VM_BUG_ON(!page_count(page));
+
        if (PageLRU(page)) {
                struct zone *zone = page_zone(page);
 
                spin_lock_irq(&zone->lru_lock);
-               if (PageLRU(page) && get_page_unless_zero(page)) {
+               if (PageLRU(page)) {
                        int lru = page_lru(page);
                        ret = 0;
+                       get_page(page);
                        ClearPageLRU(page);
 
                        del_page_from_lru_list(zone, page, lru);
@@ -1700,26 +1729,6 @@ static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan,
        return shrink_inactive_list(nr_to_scan, zone, sc, priority, file);
 }
 
-/*
- * Smallish @nr_to_scan's are deposited in @nr_saved_scan,
- * until we collected @swap_cluster_max pages to scan.
- */
-static unsigned long nr_scan_try_batch(unsigned long nr_to_scan,
-                                      unsigned long *nr_saved_scan)
-{
-       unsigned long nr;
-
-       *nr_saved_scan += nr_to_scan;
-       nr = *nr_saved_scan;
-
-       if (nr >= SWAP_CLUSTER_MAX)
-               *nr_saved_scan = 0;
-       else
-               nr = 0;
-
-       return nr;
-}
-
 /*
  * Determine how aggressively the anon and file LRU lists should be
  * scanned.  The relative value of each set of LRU lists is determined
@@ -1738,6 +1747,22 @@ static void get_scan_count(struct zone *zone, struct scan_control *sc,
        u64 fraction[2], denominator;
        enum lru_list l;
        int noswap = 0;
+       int force_scan = 0;
+
+
+       anon  = zone_nr_lru_pages(zone, sc, LRU_ACTIVE_ANON) +
+               zone_nr_lru_pages(zone, sc, LRU_INACTIVE_ANON);
+       file  = zone_nr_lru_pages(zone, sc, LRU_ACTIVE_FILE) +
+               zone_nr_lru_pages(zone, sc, LRU_INACTIVE_FILE);
+
+       if (((anon + file) >> priority) < SWAP_CLUSTER_MAX) {
+               /* kswapd does zone balancing and need to scan this zone */
+               if (scanning_global_lru(sc) && current_is_kswapd())
+                       force_scan = 1;
+               /* memcg may have small limit and need to avoid priority drop */
+               if (!scanning_global_lru(sc))
+                       force_scan = 1;
+       }
 
        /* If we have no swap space, do not bother scanning anon pages. */
        if (!sc->may_swap || (nr_swap_pages <= 0)) {
@@ -1748,11 +1773,6 @@ static void get_scan_count(struct zone *zone, struct scan_control *sc,
                goto out;
        }
 
-       anon  = zone_nr_lru_pages(zone, sc, LRU_ACTIVE_ANON) +
-               zone_nr_lru_pages(zone, sc, LRU_INACTIVE_ANON);
-       file  = zone_nr_lru_pages(zone, sc, LRU_ACTIVE_FILE) +
-               zone_nr_lru_pages(zone, sc, LRU_INACTIVE_FILE);
-
        if (scanning_global_lru(sc)) {
                free  = zone_page_state(zone, NR_FREE_PAGES);
                /* If we have very few page cache pages,
@@ -1819,8 +1839,23 @@ out:
                        scan >>= priority;
                        scan = div64_u64(scan * fraction[file], denominator);
                }
-               nr[l] = nr_scan_try_batch(scan,
-                                         &reclaim_stat->nr_saved_scan[l]);
+
+               /*
+                * If zone is small or memcg is small, nr[l] can be 0.
+                * This results no-scan on this priority and priority drop down.
+                * For global direct reclaim, it can visit next zone and tend
+                * not to have problems. For global kswapd, it's for zone
+                * balancing and it need to scan a small amounts. When using
+                * memcg, priority drop can cause big latency. So, it's better
+                * to scan small amount. See may_noscan above.
+                */
+               if (!scan && force_scan) {
+                       if (file)
+                               scan = SWAP_CLUSTER_MAX;
+                       else if (!noswap)
+                               scan = SWAP_CLUSTER_MAX;
+               }
+               nr[l] = scan;
        }
 }
 
@@ -1960,11 +1995,14 @@ restart:
  * If a zone is deemed to be full of pinned pages then just give it a light
  * scan then give up on it.
  */
-static void shrink_zones(int priority, struct zonelist *zonelist,
+static unsigned long shrink_zones(int priority, struct zonelist *zonelist,
                                        struct scan_control *sc)
 {
        struct zoneref *z;
        struct zone *zone;
+       unsigned long nr_soft_reclaimed;
+       unsigned long nr_soft_scanned;
+       unsigned long total_scanned = 0;
 
        for_each_zone_zonelist_nodemask(zone, z, zonelist,
                                        gfp_zone(sc->gfp_mask), sc->nodemask) {
@@ -1981,8 +2019,17 @@ static void shrink_zones(int priority, struct zonelist *zonelist,
                                continue;       /* Let kswapd poll it */
                }
 
+               nr_soft_scanned = 0;
+               nr_soft_reclaimed = mem_cgroup_soft_limit_reclaim(zone,
+                                                       sc->order, sc->gfp_mask,
+                                                       &nr_soft_scanned);
+               sc->nr_reclaimed += nr_soft_reclaimed;
+               total_scanned += nr_soft_scanned;
+
                shrink_zone(priority, zone, sc);
        }
+
+       return total_scanned;
 }
 
 static bool zone_reclaimable(struct zone *zone)
@@ -2027,7 +2074,8 @@ static bool all_unreclaimable(struct zonelist *zonelist,
  *             else, the number of pages reclaimed
  */
 static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
-                                       struct scan_control *sc)
+                                       struct scan_control *sc,
+                                       struct shrink_control *shrink)
 {
        int priority;
        unsigned long total_scanned = 0;
@@ -2045,8 +2093,8 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
        for (priority = DEF_PRIORITY; priority >= 0; priority--) {
                sc->nr_scanned = 0;
                if (!priority)
-                       disable_swap_token();
-               shrink_zones(priority, zonelist, sc);
+                       disable_swap_token(sc->mem_cgroup);
+               total_scanned += shrink_zones(priority, zonelist, sc);
                /*
                 * Don't shrink slabs when reclaiming memory from
                 * over limit cgroups
@@ -2061,7 +2109,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
                                lru_pages += zone_reclaimable_pages(zone);
                        }
 
-                       shrink_slab(sc->nr_scanned, sc->gfp_mask, lru_pages);
+                       shrink_slab(shrink, sc->nr_scanned, lru_pages);
                        if (reclaim_state) {
                                sc->nr_reclaimed += reclaim_state->reclaimed_slab;
                                reclaim_state->reclaimed_slab = 0;
@@ -2133,12 +2181,15 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
                .mem_cgroup = NULL,
                .nodemask = nodemask,
        };
+       struct shrink_control shrink = {
+               .gfp_mask = sc.gfp_mask,
+       };
 
        trace_mm_vmscan_direct_reclaim_begin(order,
                                sc.may_writepage,
                                gfp_mask);
 
-       nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
+       nr_reclaimed = do_try_to_free_pages(zonelist, &sc, &shrink);
 
        trace_mm_vmscan_direct_reclaim_end(nr_reclaimed);
 
@@ -2150,9 +2201,11 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
 unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
                                                gfp_t gfp_mask, bool noswap,
                                                unsigned int swappiness,
-                                               struct zone *zone)
+                                               struct zone *zone,
+                                               unsigned long *nr_scanned)
 {
        struct scan_control sc = {
+               .nr_scanned = 0,
                .nr_to_reclaim = SWAP_CLUSTER_MAX,
                .may_writepage = !laptop_mode,
                .may_unmap = 1,
@@ -2161,6 +2214,7 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
                .order = 0,
                .mem_cgroup = mem,
        };
+
        sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
                        (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK);
 
@@ -2179,6 +2233,7 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
 
        trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed);
 
+       *nr_scanned = sc.nr_scanned;
        return sc.nr_reclaimed;
 }
 
@@ -2189,6 +2244,7 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
 {
        struct zonelist *zonelist;
        unsigned long nr_reclaimed;
+       int nid;
        struct scan_control sc = {
                .may_writepage = !laptop_mode,
                .may_unmap = 1,
@@ -2198,17 +2254,27 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
                .order = 0,
                .mem_cgroup = mem_cont,
                .nodemask = NULL, /* we don't care the placement */
+               .gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
+                               (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK),
+       };
+       struct shrink_control shrink = {
+               .gfp_mask = sc.gfp_mask,
        };
 
-       sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
-                       (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK);
-       zonelist = NODE_DATA(numa_node_id())->node_zonelists;
+       /*
+        * Unlike direct reclaim via alloc_pages(), memcg's reclaim doesn't
+        * take care of from where we get pages. So the node where we start the
+        * scan does not need to be the current node.
+        */
+       nid = mem_cgroup_select_victim_node(mem_cont);
+
+       zonelist = NODE_DATA(nid)->node_zonelists;
 
        trace_mm_vmscan_memcg_reclaim_begin(0,
                                            sc.may_writepage,
                                            sc.gfp_mask);
 
-       nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
+       nr_reclaimed = do_try_to_free_pages(zonelist, &sc, &shrink);
 
        trace_mm_vmscan_memcg_reclaim_end(nr_reclaimed);
 
@@ -2287,7 +2353,7 @@ static bool sleeping_prematurely(pg_data_t *pgdat, int order, long remaining,
         * must be balanced
         */
        if (order)
-               return pgdat_balanced(pgdat, balanced, classzone_idx);
+               return !pgdat_balanced(pgdat, balanced, classzone_idx);
        else
                return !all_zones_ok;
 }
@@ -2323,6 +2389,8 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order,
        int end_zone = 0;       /* Inclusive.  0 = ZONE_DMA */
        unsigned long total_scanned;
        struct reclaim_state *reclaim_state = current->reclaim_state;
+       unsigned long nr_soft_reclaimed;
+       unsigned long nr_soft_scanned;
        struct scan_control sc = {
                .gfp_mask = GFP_KERNEL,
                .may_unmap = 1,
@@ -2336,6 +2404,9 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order,
                .order = order,
                .mem_cgroup = NULL,
        };
+       struct shrink_control shrink = {
+               .gfp_mask = sc.gfp_mask,
+       };
 loop_again:
        total_scanned = 0;
        sc.nr_reclaimed = 0;
@@ -2348,7 +2419,7 @@ loop_again:
 
                /* The swap token gets in the way of swapout... */
                if (!priority)
-                       disable_swap_token();
+                       disable_swap_token(NULL);
 
                all_zones_ok = 1;
                balanced = 0;
@@ -2412,11 +2483,15 @@ loop_again:
 
                        sc.nr_scanned = 0;
 
+                       nr_soft_scanned = 0;
                        /*
                         * Call soft limit reclaim before calling shrink_zone.
-                        * For now we ignore the return value
                         */
-                       mem_cgroup_soft_limit_reclaim(zone, order, sc.gfp_mask);
+                       nr_soft_reclaimed = mem_cgroup_soft_limit_reclaim(zone,
+                                                       order, sc.gfp_mask,
+                                                       &nr_soft_scanned);
+                       sc.nr_reclaimed += nr_soft_reclaimed;
+                       total_scanned += nr_soft_scanned;
 
                        /*
                         * We put equal pressure on every zone, unless
@@ -2435,8 +2510,7 @@ loop_again:
                                        end_zone, 0))
                                shrink_zone(priority, zone, &sc);
                        reclaim_state->reclaimed_slab = 0;
-                       nr_slab = shrink_slab(sc.nr_scanned, GFP_KERNEL,
-                                               lru_pages);
+                       nr_slab = shrink_slab(&shrink, sc.nr_scanned, lru_pages);
                        sc.nr_reclaimed += reclaim_state->reclaimed_slab;
                        total_scanned += sc.nr_scanned;
 
@@ -2788,7 +2862,10 @@ unsigned long shrink_all_memory(unsigned long nr_to_reclaim)
                .swappiness = vm_swappiness,
                .order = 0,
        };
-       struct zonelist * zonelist = node_zonelist(numa_node_id(), sc.gfp_mask);
+       struct shrink_control shrink = {
+               .gfp_mask = sc.gfp_mask,
+       };
+       struct zonelist *zonelist = node_zonelist(numa_node_id(), sc.gfp_mask);
        struct task_struct *p = current;
        unsigned long nr_reclaimed;
 
@@ -2797,7 +2874,7 @@ unsigned long shrink_all_memory(unsigned long nr_to_reclaim)
        reclaim_state.reclaimed_slab = 0;
        p->reclaim_state = &reclaim_state;
 
-       nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
+       nr_reclaimed = do_try_to_free_pages(zonelist, &sc, &shrink);
 
        p->reclaim_state = NULL;
        lockdep_clear_current_reclaim_state();
@@ -2972,6 +3049,9 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
                .swappiness = vm_swappiness,
                .order = order,
        };
+       struct shrink_control shrink = {
+               .gfp_mask = sc.gfp_mask,
+       };
        unsigned long nr_slab_pages0, nr_slab_pages1;
 
        cond_resched();
@@ -3013,7 +3093,7 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
                        unsigned long lru_pages = zone_reclaimable_pages(zone);
 
                        /* No reclaimable slab or very low memory pressure */
-                       if (!shrink_slab(sc.nr_scanned, gfp_mask, lru_pages))
+                       if (!shrink_slab(&shrink, sc.nr_scanned, lru_pages))
                                break;
 
                        /* Freed enough memory */
index 897ea9e88238d1a9ffd99c4f35124988bbc85ef0..20c18b7694b284f236149612335d017a2419f063 100644 (file)
@@ -157,7 +157,7 @@ int calculate_normal_threshold(struct zone *zone)
 /*
  * Refresh the thresholds for each zone.
  */
-static void refresh_zone_stat_thresholds(void)
+void refresh_zone_stat_thresholds(void)
 {
        struct zone *zone;
        int cpu;
@@ -659,6 +659,138 @@ static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
 }
 #endif
 
+#if defined(CONFIG_PROC_FS) || defined(CONFIG_SYSFS)
+#ifdef CONFIG_ZONE_DMA
+#define TEXT_FOR_DMA(xx) xx "_dma",
+#else
+#define TEXT_FOR_DMA(xx)
+#endif
+
+#ifdef CONFIG_ZONE_DMA32
+#define TEXT_FOR_DMA32(xx) xx "_dma32",
+#else
+#define TEXT_FOR_DMA32(xx)
+#endif
+
+#ifdef CONFIG_HIGHMEM
+#define TEXT_FOR_HIGHMEM(xx) xx "_high",
+#else
+#define TEXT_FOR_HIGHMEM(xx)
+#endif
+
+#define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \
+                                       TEXT_FOR_HIGHMEM(xx) xx "_movable",
+
+const char * const vmstat_text[] = {
+       /* Zoned VM counters */
+       "nr_free_pages",
+       "nr_inactive_anon",
+       "nr_active_anon",
+       "nr_inactive_file",
+       "nr_active_file",
+       "nr_unevictable",
+       "nr_mlock",
+       "nr_anon_pages",
+       "nr_mapped",
+       "nr_file_pages",
+       "nr_dirty",
+       "nr_writeback",
+       "nr_slab_reclaimable",
+       "nr_slab_unreclaimable",
+       "nr_page_table_pages",
+       "nr_kernel_stack",
+       "nr_unstable",
+       "nr_bounce",
+       "nr_vmscan_write",
+       "nr_writeback_temp",
+       "nr_isolated_anon",
+       "nr_isolated_file",
+       "nr_shmem",
+       "nr_dirtied",
+       "nr_written",
+
+#ifdef CONFIG_NUMA
+       "numa_hit",
+       "numa_miss",
+       "numa_foreign",
+       "numa_interleave",
+       "numa_local",
+       "numa_other",
+#endif
+       "nr_anon_transparent_hugepages",
+       "nr_dirty_threshold",
+       "nr_dirty_background_threshold",
+
+#ifdef CONFIG_VM_EVENT_COUNTERS
+       "pgpgin",
+       "pgpgout",
+       "pswpin",
+       "pswpout",
+
+       TEXTS_FOR_ZONES("pgalloc")
+
+       "pgfree",
+       "pgactivate",
+       "pgdeactivate",
+
+       "pgfault",
+       "pgmajfault",
+
+       TEXTS_FOR_ZONES("pgrefill")
+       TEXTS_FOR_ZONES("pgsteal")
+       TEXTS_FOR_ZONES("pgscan_kswapd")
+       TEXTS_FOR_ZONES("pgscan_direct")
+
+#ifdef CONFIG_NUMA
+       "zone_reclaim_failed",
+#endif
+       "pginodesteal",
+       "slabs_scanned",
+       "kswapd_steal",
+       "kswapd_inodesteal",
+       "kswapd_low_wmark_hit_quickly",
+       "kswapd_high_wmark_hit_quickly",
+       "kswapd_skip_congestion_wait",
+       "pageoutrun",
+       "allocstall",
+
+       "pgrotated",
+
+#ifdef CONFIG_COMPACTION
+       "compact_blocks_moved",
+       "compact_pages_moved",
+       "compact_pagemigrate_failed",
+       "compact_stall",
+       "compact_fail",
+       "compact_success",
+#endif
+
+#ifdef CONFIG_HUGETLB_PAGE
+       "htlb_buddy_alloc_success",
+       "htlb_buddy_alloc_fail",
+#endif
+       "unevictable_pgs_culled",
+       "unevictable_pgs_scanned",
+       "unevictable_pgs_rescued",
+       "unevictable_pgs_mlocked",
+       "unevictable_pgs_munlocked",
+       "unevictable_pgs_cleared",
+       "unevictable_pgs_stranded",
+       "unevictable_pgs_mlockfreed",
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+       "thp_fault_alloc",
+       "thp_fault_fallback",
+       "thp_collapse_alloc",
+       "thp_collapse_alloc_failed",
+       "thp_split",
+#endif
+
+#endif /* CONFIG_VM_EVENTS_COUNTERS */
+};
+#endif /* CONFIG_PROC_FS || CONFIG_SYSFS */
+
+
 #ifdef CONFIG_PROC_FS
 static void frag_show_print(struct seq_file *m, pg_data_t *pgdat,
                                                struct zone *zone)
@@ -831,135 +963,6 @@ static const struct file_operations pagetypeinfo_file_ops = {
        .release        = seq_release,
 };
 
-#ifdef CONFIG_ZONE_DMA
-#define TEXT_FOR_DMA(xx) xx "_dma",
-#else
-#define TEXT_FOR_DMA(xx)
-#endif
-
-#ifdef CONFIG_ZONE_DMA32
-#define TEXT_FOR_DMA32(xx) xx "_dma32",
-#else
-#define TEXT_FOR_DMA32(xx)
-#endif
-
-#ifdef CONFIG_HIGHMEM
-#define TEXT_FOR_HIGHMEM(xx) xx "_high",
-#else
-#define TEXT_FOR_HIGHMEM(xx)
-#endif
-
-#define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \
-                                       TEXT_FOR_HIGHMEM(xx) xx "_movable",
-
-static const char * const vmstat_text[] = {
-       /* Zoned VM counters */
-       "nr_free_pages",
-       "nr_inactive_anon",
-       "nr_active_anon",
-       "nr_inactive_file",
-       "nr_active_file",
-       "nr_unevictable",
-       "nr_mlock",
-       "nr_anon_pages",
-       "nr_mapped",
-       "nr_file_pages",
-       "nr_dirty",
-       "nr_writeback",
-       "nr_slab_reclaimable",
-       "nr_slab_unreclaimable",
-       "nr_page_table_pages",
-       "nr_kernel_stack",
-       "nr_unstable",
-       "nr_bounce",
-       "nr_vmscan_write",
-       "nr_writeback_temp",
-       "nr_isolated_anon",
-       "nr_isolated_file",
-       "nr_shmem",
-       "nr_dirtied",
-       "nr_written",
-
-#ifdef CONFIG_NUMA
-       "numa_hit",
-       "numa_miss",
-       "numa_foreign",
-       "numa_interleave",
-       "numa_local",
-       "numa_other",
-#endif
-       "nr_anon_transparent_hugepages",
-       "nr_dirty_threshold",
-       "nr_dirty_background_threshold",
-
-#ifdef CONFIG_VM_EVENT_COUNTERS
-       "pgpgin",
-       "pgpgout",
-       "pswpin",
-       "pswpout",
-
-       TEXTS_FOR_ZONES("pgalloc")
-
-       "pgfree",
-       "pgactivate",
-       "pgdeactivate",
-
-       "pgfault",
-       "pgmajfault",
-
-       TEXTS_FOR_ZONES("pgrefill")
-       TEXTS_FOR_ZONES("pgsteal")
-       TEXTS_FOR_ZONES("pgscan_kswapd")
-       TEXTS_FOR_ZONES("pgscan_direct")
-
-#ifdef CONFIG_NUMA
-       "zone_reclaim_failed",
-#endif
-       "pginodesteal",
-       "slabs_scanned",
-       "kswapd_steal",
-       "kswapd_inodesteal",
-       "kswapd_low_wmark_hit_quickly",
-       "kswapd_high_wmark_hit_quickly",
-       "kswapd_skip_congestion_wait",
-       "pageoutrun",
-       "allocstall",
-
-       "pgrotated",
-
-#ifdef CONFIG_COMPACTION
-       "compact_blocks_moved",
-       "compact_pages_moved",
-       "compact_pagemigrate_failed",
-       "compact_stall",
-       "compact_fail",
-       "compact_success",
-#endif
-
-#ifdef CONFIG_HUGETLB_PAGE
-       "htlb_buddy_alloc_success",
-       "htlb_buddy_alloc_fail",
-#endif
-       "unevictable_pgs_culled",
-       "unevictable_pgs_scanned",
-       "unevictable_pgs_rescued",
-       "unevictable_pgs_mlocked",
-       "unevictable_pgs_munlocked",
-       "unevictable_pgs_cleared",
-       "unevictable_pgs_stranded",
-       "unevictable_pgs_mlockfreed",
-
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-       "thp_fault_alloc",
-       "thp_fault_fallback",
-       "thp_collapse_alloc",
-       "thp_collapse_alloc_failed",
-       "thp_split",
-#endif
-
-#endif /* CONFIG_VM_EVENTS_COUNTERS */
-};
-
 static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
                                                        struct zone *zone)
 {
@@ -1198,7 +1201,6 @@ static int __init setup_vmstat(void)
 #ifdef CONFIG_SMP
        int cpu;
 
-       refresh_zone_stat_thresholds();
        register_cpu_notifier(&vmstat_notifier);
 
        for_each_online_cpu(cpu)
index 21cde8fd5795310a823367783cc3f4cd9eb92d0c..db6baf7cf6e97779bdf5405aa55cfe282107a5fe 100644 (file)
@@ -147,7 +147,6 @@ struct datalink_proto *register_snap_client(const unsigned char *desc,
 out:
        spin_unlock_bh(&snap_lock);
 
-       synchronize_net();
        return proto;
 }
 
index b2274d1fd605b90cdeeb14a72cc909acd9e55001..917ecb93ea28d477d75c729accac39eacbdfa752 100644 (file)
@@ -46,8 +46,6 @@ int vlan_net_id __read_mostly;
 
 const char vlan_fullname[] = "802.1Q VLAN Support";
 const char vlan_version[] = DRV_VERSION;
-static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
-static const char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
 
 /* End of global variables definitions. */
 
@@ -207,7 +205,7 @@ int register_vlan_dev(struct net_device *dev)
        grp->nr_vlans++;
 
        if (ngrp) {
-               if (ops->ndo_vlan_rx_register)
+               if (ops->ndo_vlan_rx_register && (real_dev->features & NETIF_F_HW_VLAN_RX))
                        ops->ndo_vlan_rx_register(real_dev, ngrp);
                rcu_assign_pointer(real_dev->vlgrp, ngrp);
        }
@@ -673,8 +671,7 @@ static int __init vlan_proto_init(void)
 {
        int err;
 
-       pr_info("%s v%s %s\n", vlan_fullname, vlan_version, vlan_copyright);
-       pr_info("All bugs added by %s\n", vlan_buggyright);
+       pr_info("%s v%s\n", vlan_fullname, vlan_version);
 
        err = register_pernet_subsys(&vlan_net_ops);
        if (err < 0)
index c3408def8a19992014f94fa193115c8054585065..9da07e30d1a250aabd453bbe90e1aa6bd18c8521 100644 (file)
@@ -118,11 +118,6 @@ extern void vlan_netlink_fini(void);
 
 extern struct rtnl_link_ops vlan_link_ops;
 
-static inline int is_vlan_dev(struct net_device *dev)
-{
-       return dev->priv_flags & IFF_802_1Q_VLAN;
-}
-
 extern int vlan_net_id;
 
 struct proc_dir_entry;
index 41495dc2a4c9a2649579938a1894916efb723684..fcc684678af67e644c6cc043dacee9f4159fb5b4 100644 (file)
@@ -23,6 +23,31 @@ bool vlan_do_receive(struct sk_buff **skbp)
                return false;
 
        skb->dev = vlan_dev;
+       if (skb->pkt_type == PACKET_OTHERHOST) {
+               /* Our lower layer thinks this is not local, let's make sure.
+                * This allows the VLAN to have a different MAC than the
+                * underlying device, and still route correctly. */
+               if (!compare_ether_addr(eth_hdr(skb)->h_dest,
+                                       vlan_dev->dev_addr))
+                       skb->pkt_type = PACKET_HOST;
+       }
+
+       if (!(vlan_dev_info(vlan_dev)->flags & VLAN_FLAG_REORDER_HDR)) {
+               unsigned int offset = skb->data - skb_mac_header(skb);
+
+               /*
+                * vlan_insert_tag expect skb->data pointing to mac header.
+                * So change skb->data before calling it and change back to
+                * original position later
+                */
+               skb_push(skb, offset);
+               skb = *skbp = vlan_insert_tag(skb, skb->vlan_tci);
+               if (!skb)
+                       return false;
+               skb_pull(skb, offset + VLAN_HLEN);
+               skb_reset_mac_len(skb);
+       }
+
        skb->priority = vlan_get_ingress_priority(vlan_dev, skb->vlan_tci);
        skb->vlan_tci = 0;
 
@@ -31,22 +56,8 @@ bool vlan_do_receive(struct sk_buff **skbp)
        u64_stats_update_begin(&rx_stats->syncp);
        rx_stats->rx_packets++;
        rx_stats->rx_bytes += skb->len;
-
-       switch (skb->pkt_type) {
-       case PACKET_BROADCAST:
-               break;
-       case PACKET_MULTICAST:
+       if (skb->pkt_type == PACKET_MULTICAST)
                rx_stats->rx_multicast++;
-               break;
-       case PACKET_OTHERHOST:
-               /* Our lower layer thinks this is not local, let's make sure.
-                * This allows the VLAN to have a different MAC than the
-                * underlying device, and still route correctly. */
-               if (!compare_ether_addr(eth_hdr(skb)->h_dest,
-                                       vlan_dev->dev_addr))
-                       skb->pkt_type = PACKET_HOST;
-               break;
-       }
        u64_stats_update_end(&rx_stats->syncp);
 
        return true;
@@ -89,18 +100,13 @@ gro_result_t vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp,
 }
 EXPORT_SYMBOL(vlan_gro_frags);
 
-static struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb)
+static struct sk_buff *vlan_reorder_header(struct sk_buff *skb)
 {
-       if (vlan_dev_info(skb->dev)->flags & VLAN_FLAG_REORDER_HDR) {
-               if (skb_cow(skb, skb_headroom(skb)) < 0)
-                       skb = NULL;
-               if (skb) {
-                       /* Lifted from Gleb's VLAN code... */
-                       memmove(skb->data - ETH_HLEN,
-                               skb->data - VLAN_ETH_HLEN, 12);
-                       skb->mac_header += VLAN_HLEN;
-               }
-       }
+       if (skb_cow(skb, skb_headroom(skb)) < 0)
+               return NULL;
+       memmove(skb->data - ETH_HLEN, skb->data - VLAN_ETH_HLEN, 2 * ETH_ALEN);
+       skb->mac_header += VLAN_HLEN;
+       skb_reset_mac_len(skb);
        return skb;
 }
 
@@ -161,7 +167,7 @@ struct sk_buff *vlan_untag(struct sk_buff *skb)
        skb_pull_rcsum(skb, VLAN_HLEN);
        vlan_set_encap_proto(skb, vhdr);
 
-       skb = vlan_check_reorder_header(skb);
+       skb = vlan_reorder_header(skb);
        if (unlikely(!skb))
                goto err_free;
 
index f247f5bff88ddb61d252951f57a965789e63f45d..7ea5cf9ea08a9db7f3b6edaf083f14030914463c 100644 (file)
@@ -165,7 +165,7 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
                u64_stats_update_begin(&stats->syncp);
                stats->tx_packets++;
                stats->tx_bytes += len;
-               u64_stats_update_begin(&stats->syncp);
+               u64_stats_update_end(&stats->syncp);
        } else {
                this_cpu_inc(vlan_dev_info(dev)->vlan_pcpu_stats->tx_dropped);
        }
index 7ed75c7bd5d1384943e7425dd9c81f44983fec8e..d9ea09b11cf8140529b0649b34a5252a551e81b5 100644 (file)
@@ -3,8 +3,8 @@
 #
 
 menuconfig NET_9P
-       depends on NET && EXPERIMENTAL
-       tristate "Plan 9 Resource Sharing Support (9P2000) (Experimental)"
+       depends on NET
+       tristate "Plan 9 Resource Sharing Support (9P2000)"
        help
          If you say Y here, you will get experimental support for
          Plan 9 resource sharing via the 9P2000 protocol.
@@ -16,8 +16,8 @@ menuconfig NET_9P
 if NET_9P
 
 config NET_9P_VIRTIO
-       depends on EXPERIMENTAL && VIRTIO
-       tristate "9P Virtio Transport (Experimental)"
+       depends on VIRTIO
+       tristate "9P Virtio Transport"
        help
          This builds support for a transports between
          guest partitions and a host partition.
index ceab943dfc496cd10467f78c948d28ebf1d29a93..9e3b0e640da179a122f6f846bd8cff31920db159 100644 (file)
@@ -92,9 +92,6 @@ static int get_protocol_version(const substring_t *name)
        return version;
 }
 
-static struct p9_req_t *
-p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
-
 /**
  * parse_options - parse mount options into client structure
  * @opts: options string passed from mount
@@ -307,12 +304,13 @@ static int p9_tag_init(struct p9_client *c)
        c->tagpool = p9_idpool_create();
        if (IS_ERR(c->tagpool)) {
                err = PTR_ERR(c->tagpool);
-               c->tagpool = NULL;
                goto error;
        }
-
-       p9_idpool_get(c->tagpool); /* reserve tag 0 */
-
+       err = p9_idpool_get(c->tagpool); /* reserve tag 0 */
+       if (err < 0) {
+               p9_idpool_destroy(c->tagpool);
+               goto error;
+       }
        c->max_tag = 0;
 error:
        return err;
@@ -518,12 +516,15 @@ out_err:
        return err;
 }
 
+static struct p9_req_t *
+p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
+
 /**
  * p9_client_flush - flush (cancel) a request
  * @c: client state
  * @oldreq: request to cancel
  *
- * This sents a flush for a particular requests and links
+ * This sents a flush for a particular request and links
  * the flush request to the original request.  The current
  * code only supports a single flush request although the protocol
  * allows for multiple flush requests to be sent for a single request.
@@ -789,11 +790,13 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
        spin_lock_init(&clnt->lock);
        INIT_LIST_HEAD(&clnt->fidlist);
 
-       p9_tag_init(clnt);
+       err = p9_tag_init(clnt);
+       if (err < 0)
+               goto free_client;
 
        err = parse_opts(options, clnt);
        if (err < 0)
-               goto free_client;
+               goto destroy_tagpool;
 
        if (!clnt->trans_mod)
                clnt->trans_mod = v9fs_get_default_trans();
@@ -802,13 +805,12 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
                err = -EPROTONOSUPPORT;
                P9_DPRINTK(P9_DEBUG_ERROR,
                                "No transport defined or default transport\n");
-               goto free_client;
+               goto destroy_tagpool;
        }
 
        clnt->fidpool = p9_idpool_create();
        if (IS_ERR(clnt->fidpool)) {
                err = PTR_ERR(clnt->fidpool);
-               clnt->fidpool = NULL;
                goto put_trans;
        }
 
@@ -834,6 +836,8 @@ destroy_fidpool:
        p9_idpool_destroy(clnt->fidpool);
 put_trans:
        v9fs_put_trans(clnt->trans_mod);
+destroy_tagpool:
+       p9_idpool_destroy(clnt->tagpool);
 free_client:
        kfree(clnt);
        return ERR_PTR(err);
@@ -1298,7 +1302,7 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
        if (count < rsize)
                rsize = count;
 
-       /* Don't bother zerocopy form small IO (< 1024) */
+       /* Don't bother zerocopy for small IO (< 1024) */
        if (((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) ==
                        P9_TRANS_PREF_PAYLOAD_SEP) && (rsize > 1024)) {
                req = p9_client_rpc(clnt, P9_TREAD, "dqE", fid->fid, offset,
index cf8a4128cd5c03560bfb93971779965176bea7dd..72c39827505125b618b7a007b6a1dc23d98b4f4f 100644 (file)
@@ -139,7 +139,7 @@ void v9fs_put_trans(struct p9_trans_module *m)
 }
 
 /**
- * v9fs_init - Initialize module
+ * init_p9 - Initialize module
  *
  */
 static int __init init_p9(void)
@@ -154,7 +154,7 @@ static int __init init_p9(void)
 }
 
 /**
- * v9fs_init - shutdown module
+ * exit_p9 - shutdown module
  *
  */
 
index 4a9084395d358320840a3fdf7398da8b0d85b09b..fdfdb5747f63b6492fc23eafa000dcd7d93c9c5b 100644 (file)
@@ -916,8 +916,8 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
        sin_server.sin_family = AF_INET;
        sin_server.sin_addr.s_addr = in_aton(addr);
        sin_server.sin_port = htons(opts.port);
-       err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
-
+       err = __sock_create(read_pnet(&current->nsproxy->net_ns), PF_INET,
+                           SOCK_STREAM, IPPROTO_TCP, &csocket, 1);
        if (err) {
                P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n");
                return err;
@@ -954,7 +954,8 @@ p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
 
        sun_server.sun_family = PF_UNIX;
        strcpy(sun_server.sun_path, addr);
-       err = sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
+       err = __sock_create(read_pnet(&current->nsproxy->net_ns), PF_UNIX,
+                           SOCK_STREAM, 0, &csocket, 1);
        if (err < 0) {
                P9_EPRINTK(KERN_ERR, "p9_trans_unix: problem creating socket\n");
                return err;
index 844a7a5607e3d2ee985f80b18577ac2b6ff4be62..159c50f1c6bf672c24b0d13f8e4f52dd40a18589 100644 (file)
@@ -589,7 +589,8 @@ rdma_create_trans(struct p9_client *client, const char *addr, char *args)
                return -ENOMEM;
 
        /* Create the RDMA CM ID */
-       rdma->cm_id = rdma_create_id(p9_cm_event_handler, client, RDMA_PS_TCP);
+       rdma->cm_id = rdma_create_id(p9_cm_event_handler, client, RDMA_PS_TCP,
+                                    IB_QPT_RC);
        if (IS_ERR(rdma->cm_id))
                goto error;
 
index da6af81e59d9fa504345c306e6636acd1f91b093..9c1c9348ac35d3410ccb255266f9367bbf5d2549 100644 (file)
@@ -93,7 +93,7 @@ int p9_idpool_get(struct p9_idpool *p)
 
 retry:
        if (idr_pre_get(&p->pool, GFP_NOFS) == 0)
-               return 0;
+               return -1;
 
        spin_lock_irqsave(&p->lock, flags);
 
index f7fa67c78766f59c0b107ece600348f401a40d57..f49da5814bc3c9828829ac2be54ed58b2fbc82a9 100644 (file)
@@ -59,6 +59,14 @@ static ssize_t show_atmaddress(struct device *cdev,
        return pos - buf;
 }
 
+static ssize_t show_atmindex(struct device *cdev,
+                            struct device_attribute *attr, char *buf)
+{
+       struct atm_dev *adev = to_atm_dev(cdev);
+
+       return sprintf(buf, "%d\n", adev->number);
+}
+
 static ssize_t show_carrier(struct device *cdev,
                            struct device_attribute *attr, char *buf)
 {
@@ -99,6 +107,7 @@ static ssize_t show_link_rate(struct device *cdev,
 
 static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
 static DEVICE_ATTR(atmaddress, S_IRUGO, show_atmaddress, NULL);
+static DEVICE_ATTR(atmindex, S_IRUGO, show_atmindex, NULL);
 static DEVICE_ATTR(carrier, S_IRUGO, show_carrier, NULL);
 static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
 static DEVICE_ATTR(link_rate, S_IRUGO, show_link_rate, NULL);
@@ -106,6 +115,7 @@ static DEVICE_ATTR(link_rate, S_IRUGO, show_link_rate, NULL);
 static struct device_attribute *atm_attrs[] = {
        &dev_attr_atmaddress,
        &dev_attr_address,
+       &dev_attr_atmindex,
        &dev_attr_carrier,
        &dev_attr_type,
        &dev_attr_link_rate,
index 25073b6ef4746cea1197e52f64bba908869d7b29..ba48daa68c1f19e19427ac96c64b161f271c3e57 100644 (file)
@@ -1171,7 +1171,7 @@ static int __init lane_module_init(void)
 #endif
 
        register_atm_ioctl(&lane_ioctl_ops);
-       pr_info("lec.c: " __DATE__ " " __TIME__ " initialized\n");
+       pr_info("lec.c: initialized\n");
        return 0;
 }
 
index 644cdf07164211b007d10e40918486497efe93c5..3ccca42e6f90ad476706770b78cce263c736f02e 100644 (file)
@@ -1482,7 +1482,7 @@ static __init int atm_mpoa_init(void)
        if (mpc_proc_init() != 0)
                pr_info("failed to initialize /proc/mpoa\n");
 
-       pr_info("mpc.c: " __DATE__ " " __TIME__ " initialized\n");
+       pr_info("mpc.c: initialized\n");
 
        return 0;
 }
index f85da0779e5ee162015ae88aa00e48e2114aa5e3..be3afdefec5832bb8e3861f883eff27e07bfcad0 100644 (file)
@@ -191,7 +191,7 @@ static void vcc_info(struct seq_file *seq, struct atm_vcc *vcc)
 {
        struct sock *sk = sk_atm(vcc);
 
-       seq_printf(seq, "%p ", vcc);
+       seq_printf(seq, "%pK ", vcc);
        if (!vcc->dev)
                seq_printf(seq, "Unassigned    ");
        else
@@ -218,7 +218,7 @@ static void svc_info(struct seq_file *seq, struct atm_vcc *vcc)
 {
        if (!vcc->dev)
                seq_printf(seq, sizeof(void *) == 4 ?
-                          "N/A@%p%10s" : "N/A@%p%2s", vcc, "");
+                          "N/A@%pK%10s" : "N/A@%pK%2s", vcc, "");
        else
                seq_printf(seq, "%3d %3d %5d         ",
                           vcc->dev->number, vcc->vpi, vcc->vci);
index f13ddbf858ba4e90dd92b891d1b13d3fece1d496..77930aa522e3456231d6482f0683d60598771937 100644 (file)
@@ -477,14 +477,16 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
         * command otherwise */
        u8 events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
 
-       /* Events for 1.2 and newer controllers */
-       if (hdev->lmp_ver > 1) {
-               events[4] |= 0x01; /* Flow Specification Complete */
-               events[4] |= 0x02; /* Inquiry Result with RSSI */
-               events[4] |= 0x04; /* Read Remote Extended Features Complete */
-               events[5] |= 0x08; /* Synchronous Connection Complete */
-               events[5] |= 0x10; /* Synchronous Connection Changed */
-       }
+       /* CSR 1.1 dongles does not accept any bitfield so don't try to set
+        * any event mask for pre 1.2 devices */
+       if (hdev->lmp_ver <= 1)
+               return;
+
+       events[4] |= 0x01; /* Flow Specification Complete */
+       events[4] |= 0x02; /* Inquiry Result with RSSI */
+       events[4] |= 0x04; /* Read Remote Extended Features Complete */
+       events[5] |= 0x08; /* Synchronous Connection Complete */
+       events[5] |= 0x10; /* Synchronous Connection Changed */
 
        if (hdev->features[3] & LMP_RSSI_INQ)
                events[4] |= 0x04; /* Inquiry Result with RSSI */
index a86f9ba4f05cd473b6ccd20c17a1d293a459877a..e64a1c2df238d3fc0aac368075b8b0fd3bbb6917 100644 (file)
@@ -906,7 +906,7 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr
                if (c->psm == psm) {
                        /* Exact match. */
                        if (!bacmp(&bt_sk(sk)->src, src)) {
-                               read_unlock_bh(&chan_list_lock);
+                               read_unlock(&chan_list_lock);
                                return c;
                        }
 
index 18dc9888d8c28064f9a32bd129c7a23d6711af04..8248303f44e892f66ba5af8841f094696e88f8cd 100644 (file)
@@ -413,6 +413,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
                        break;
                }
 
+               memset(&cinfo, 0, sizeof(cinfo));
                cinfo.hci_handle = chan->conn->hcon->handle;
                memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3);
 
index 386cfaffd4b7569e919c933f89192eeb30cf14e2..1b10727ce523e077c1f571910275e085b6ee32f6 100644 (file)
@@ -788,6 +788,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
 
                l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk;
 
+               memset(&cinfo, 0, sizeof(cinfo));
                cinfo.hci_handle = conn->hcon->handle;
                memcpy(cinfo.dev_class, conn->hcon->dev_class, 3);
 
index 42fdffd1d76c0c17c5ab3382b94ea5bf4fcc62c9..cb4fb7837e5c381736b257cf77917ac6992df3b7 100644 (file)
@@ -369,6 +369,15 @@ static void __sco_sock_close(struct sock *sk)
 
        case BT_CONNECTED:
        case BT_CONFIG:
+               if (sco_pi(sk)->conn) {
+                       sk->sk_state = BT_DISCONN;
+                       sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
+                       hci_conn_put(sco_pi(sk)->conn->hcon);
+                       sco_pi(sk)->conn->hcon = NULL;
+               } else
+                       sco_chan_del(sk, ECONNRESET);
+               break;
+
        case BT_CONNECT:
        case BT_DISCONN:
                sco_chan_del(sk, ECONNRESET);
@@ -819,7 +828,9 @@ static void sco_chan_del(struct sock *sk, int err)
                conn->sk = NULL;
                sco_pi(sk)->conn = NULL;
                sco_conn_unlock(conn);
-               hci_conn_put(conn->hcon);
+
+               if (conn->hcon)
+                       hci_conn_put(conn->hcon);
        }
 
        sk->sk_state = BT_CLOSED;
index a6b2f86378c75437bba1300d23acc3b9ca188a58..c188c803c09c5085014b5bb221aeb57c8fba4871 100644 (file)
@@ -243,6 +243,7 @@ int br_netpoll_enable(struct net_bridge_port *p)
                goto out;
 
        np->dev = p->dev;
+       strlcpy(np->dev_name, p->dev->name, IFNAMSIZ);
 
        err = __netpoll_setup(np);
        if (err) {
index 2f14eafdeeabe80d5dd5a5643e55ecf3a2e74f52..29b9812c8da0d38f5ab9461162cdbc74093c25cf 100644 (file)
@@ -1424,7 +1424,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
        switch (ih->type) {
        case IGMP_HOST_MEMBERSHIP_REPORT:
        case IGMPV2_HOST_MEMBERSHIP_REPORT:
-               BR_INPUT_SKB_CB(skb2)->mrouters_only = 1;
+               BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
                err = br_ip4_multicast_add_group(br, port, ih->group);
                break;
        case IGMPV3_HOST_MEMBERSHIP_REPORT:
@@ -1543,7 +1543,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
                        goto out;
                }
                mld = (struct mld_msg *)skb_transport_header(skb2);
-               BR_INPUT_SKB_CB(skb2)->mrouters_only = 1;
+               BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
                err = br_ip6_multicast_add_group(br, port, &mld->mld_mca);
                break;
            }
index e1f5ec75e91cd8c93fb22f3092dbdd30f5855c85..56149ec36d7fd5d8a411b3996f5e7985a3792c77 100644 (file)
@@ -104,10 +104,16 @@ static void fake_update_pmtu(struct dst_entry *dst, u32 mtu)
 {
 }
 
+static u32 *fake_cow_metrics(struct dst_entry *dst, unsigned long old)
+{
+       return NULL;
+}
+
 static struct dst_ops fake_dst_ops = {
        .family =               AF_INET,
        .protocol =             cpu_to_be16(ETH_P_IP),
        .update_pmtu =          fake_update_pmtu,
+       .cow_metrics =          fake_cow_metrics,
 };
 
 /*
@@ -117,6 +123,10 @@ static struct dst_ops fake_dst_ops = {
  * ipt_REJECT needs it.  Future netfilter modules might
  * require us to fill additional fields.
  */
+static const u32 br_dst_default_metrics[RTAX_MAX] = {
+       [RTAX_MTU - 1] = 1500,
+};
+
 void br_netfilter_rtable_init(struct net_bridge *br)
 {
        struct rtable *rt = &br->fake_rtable;
@@ -124,7 +134,7 @@ void br_netfilter_rtable_init(struct net_bridge *br)
        atomic_set(&rt->dst.__refcnt, 1);
        rt->dst.dev = br->dev;
        rt->dst.path = &rt->dst;
-       dst_metric_set(&rt->dst, RTAX_MTU, 1500);
+       dst_init_metrics(&rt->dst, br_dst_default_metrics, true);
        rt->dst.flags   = DST_NOXFRM;
        rt->dst.ops = &fake_dst_ops;
 }
index 1a92b369c8202c8706c42452950594233882ca06..2b5ca1a0054da4aec5f6a17064e1040c4a107dda 100644 (file)
@@ -1883,14 +1883,13 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt,
        struct xt_target *wt;
        void *dst = NULL;
        int off, pad = 0;
-       unsigned int size_kern, entry_offset, match_size = mwt->match_size;
+       unsigned int size_kern, match_size = mwt->match_size;
 
        strlcpy(name, mwt->u.name, sizeof(name));
 
        if (state->buf_kern_start)
                dst = state->buf_kern_start + state->buf_kern_offset;
 
-       entry_offset = (unsigned char *) mwt - base;
        switch (compat_mwt) {
        case EBT_COMPAT_MATCH:
                match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
@@ -1933,6 +1932,9 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt,
                size_kern = wt->targetsize;
                module_put(wt->me);
                break;
+
+       default:
+               return -EINVAL;
        }
 
        state->buf_kern_offset += match_size + off;
index 3a66b8c10e09ab1876e7b678efc65073699342a0..c23979e79dfadce502c5d70927412849b79b868e 100644 (file)
@@ -255,7 +255,7 @@ static void cfmuxl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
 
                if (cfsrvl_phyid_match(layer, phyid) && layer->ctrlcmd) {
 
-                       if ((ctrl == _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND ||
+                       if ((ctrl == _CAIF_CTRLCMD_PHYIF_DOWN_IND ||
                                ctrl == CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND) &&
                                        layer->id != 0) {
 
index 649ebacaf6bce69f29028e33c20233fb1932bbee..adbb424403d48982624f36e62418ec9cb47c0132 100644 (file)
@@ -139,17 +139,14 @@ static void close_work(struct work_struct *work)
        struct chnl_net *dev = NULL;
        struct list_head *list_node;
        struct list_head *_tmp;
-       /* May be called with or without RTNL lock held */
-       int islocked = rtnl_is_locked();
-       if (!islocked)
-               rtnl_lock();
+
+       rtnl_lock();
        list_for_each_safe(list_node, _tmp, &chnl_net_list) {
                dev = list_entry(list_node, struct chnl_net, list_field);
                if (dev->state == CAIF_SHUTDOWN)
                        dev_close(dev->netdev);
        }
-       if (!islocked)
-               rtnl_unlock();
+       rtnl_unlock();
 }
 static DECLARE_WORK(close_worker, close_work);
 
index cced806098a94ab81f76347c5bdc0ab0c23e28e3..184a6572b67e6be824ba1ef30b122d065269a262 100644 (file)
@@ -165,9 +165,9 @@ static int bcm_proc_show(struct seq_file *m, void *v)
        struct bcm_sock *bo = bcm_sk(sk);
        struct bcm_op *op;
 
-       seq_printf(m, ">>> socket %p", sk->sk_socket);
-       seq_printf(m, " / sk %p", sk);
-       seq_printf(m, " / bo %p", bo);
+       seq_printf(m, ">>> socket %pK", sk->sk_socket);
+       seq_printf(m, " / sk %pK", sk);
+       seq_printf(m, " / bo %pK", bo);
        seq_printf(m, " / dropped %lu", bo->dropped_usr_msgs);
        seq_printf(m, " / bound %s", bcm_proc_getifname(ifname, bo->ifindex));
        seq_printf(m, " <<<\n");
index f4265cc9c3fbee335f16f467ac7f0a197e43977c..0016f73396995e2ca21275d6bfc17ed8374e7f3c 100644 (file)
@@ -204,12 +204,11 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list,
 
        hlist_for_each_entry_rcu(r, n, rx_list, list) {
                char *fmt = (r->can_id & CAN_EFF_FLAG)?
-                       "   %-5s  %08X  %08x  %08x  %08x  %8ld  %s\n" :
-                       "   %-5s     %03X    %08x  %08lx  %08lx  %8ld  %s\n";
+                       "   %-5s  %08x  %08x  %pK  %pK  %8ld  %s\n" :
+                       "   %-5s     %03x    %08x  %pK  %pK  %8ld  %s\n";
 
                seq_printf(m, fmt, DNAME(dev), r->can_id, r->mask,
-                               (unsigned long)r->func, (unsigned long)r->data,
-                               r->matches, r->ident);
+                               r->func, r->data, r->matches, r->ident);
        }
 }
 
index e15a82ccc05f69789e162c5caa51d4bb2cc082a5..78b55f49de7cba5bbdf0fb872b4b3c0464190f04 100644 (file)
@@ -76,7 +76,8 @@ const char *ceph_pr_addr(const struct sockaddr_storage *ss)
                break;
 
        default:
-               sprintf(s, "(unknown sockaddr family %d)", (int)ss->ss_family);
+               snprintf(s, MAX_ADDR_STR_LEN, "(unknown sockaddr family %d)",
+                        (int)ss->ss_family);
        }
 
        return s;
@@ -598,7 +599,7 @@ static void prepare_write_keepalive(struct ceph_connection *con)
  * Connection negotiation.
  */
 
-static void prepare_connect_authorizer(struct ceph_connection *con)
+static int prepare_connect_authorizer(struct ceph_connection *con)
 {
        void *auth_buf;
        int auth_len = 0;
@@ -612,13 +613,20 @@ static void prepare_connect_authorizer(struct ceph_connection *con)
                                         con->auth_retry);
        mutex_lock(&con->mutex);
 
+       if (test_bit(CLOSED, &con->state) ||
+           test_bit(OPENING, &con->state))
+               return -EAGAIN;
+
        con->out_connect.authorizer_protocol = cpu_to_le32(auth_protocol);
        con->out_connect.authorizer_len = cpu_to_le32(auth_len);
 
-       con->out_kvec[con->out_kvec_left].iov_base = auth_buf;
-       con->out_kvec[con->out_kvec_left].iov_len = auth_len;
-       con->out_kvec_left++;
-       con->out_kvec_bytes += auth_len;
+       if (auth_len) {
+               con->out_kvec[con->out_kvec_left].iov_base = auth_buf;
+               con->out_kvec[con->out_kvec_left].iov_len = auth_len;
+               con->out_kvec_left++;
+               con->out_kvec_bytes += auth_len;
+       }
+       return 0;
 }
 
 /*
@@ -640,9 +648,9 @@ static void prepare_write_banner(struct ceph_messenger *msgr,
        set_bit(WRITE_PENDING, &con->state);
 }
 
-static void prepare_write_connect(struct ceph_messenger *msgr,
-                                 struct ceph_connection *con,
-                                 int after_banner)
+static int prepare_write_connect(struct ceph_messenger *msgr,
+                                struct ceph_connection *con,
+                                int after_banner)
 {
        unsigned global_seq = get_global_seq(con->msgr, 0);
        int proto;
@@ -683,7 +691,7 @@ static void prepare_write_connect(struct ceph_messenger *msgr,
        con->out_more = 0;
        set_bit(WRITE_PENDING, &con->state);
 
-       prepare_connect_authorizer(con);
+       return prepare_connect_authorizer(con);
 }
 
 
@@ -1065,8 +1073,10 @@ static void addr_set_port(struct sockaddr_storage *ss, int p)
        switch (ss->ss_family) {
        case AF_INET:
                ((struct sockaddr_in *)ss)->sin_port = htons(p);
+               break;
        case AF_INET6:
                ((struct sockaddr_in6 *)ss)->sin6_port = htons(p);
+               break;
        }
 }
 
@@ -1216,6 +1226,7 @@ static int process_connect(struct ceph_connection *con)
        u64 sup_feat = con->msgr->supported_features;
        u64 req_feat = con->msgr->required_features;
        u64 server_feat = le64_to_cpu(con->in_reply.features);
+       int ret;
 
        dout("process_connect on %p tag %d\n", con, (int)con->in_tag);
 
@@ -1250,7 +1261,9 @@ static int process_connect(struct ceph_connection *con)
                        return -1;
                }
                con->auth_retry = 1;
-               prepare_write_connect(con->msgr, con, 0);
+               ret = prepare_write_connect(con->msgr, con, 0);
+               if (ret < 0)
+                       return ret;
                prepare_read_connect(con);
                break;
 
@@ -1277,6 +1290,9 @@ static int process_connect(struct ceph_connection *con)
                if (con->ops->peer_reset)
                        con->ops->peer_reset(con);
                mutex_lock(&con->mutex);
+               if (test_bit(CLOSED, &con->state) ||
+                   test_bit(OPENING, &con->state))
+                       return -EAGAIN;
                break;
 
        case CEPH_MSGR_TAG_RETRY_SESSION:
@@ -1341,7 +1357,9 @@ static int process_connect(struct ceph_connection *con)
                 * to WAIT.  This shouldn't happen if we are the
                 * client.
                 */
-               pr_err("process_connect peer connecting WAIT\n");
+               pr_err("process_connect got WAIT as client\n");
+               con->error_msg = "protocol error, got WAIT as client";
+               return -1;
 
        default:
                pr_err("connect protocol error, will retry\n");
@@ -1810,6 +1828,17 @@ static int try_read(struct ceph_connection *con)
 more:
        dout("try_read tag %d in_base_pos %d\n", (int)con->in_tag,
             con->in_base_pos);
+
+       /*
+        * process_connect and process_message drop and re-take
+        * con->mutex.  make sure we handle a racing close or reopen.
+        */
+       if (test_bit(CLOSED, &con->state) ||
+           test_bit(OPENING, &con->state)) {
+               ret = -EAGAIN;
+               goto out;
+       }
+
        if (test_bit(CONNECTING, &con->state)) {
                if (!test_bit(NEGOTIATING, &con->state)) {
                        dout("try_read connecting\n");
@@ -1938,8 +1967,10 @@ static void con_work(struct work_struct *work)
 {
        struct ceph_connection *con = container_of(work, struct ceph_connection,
                                                   work.work);
+       int ret;
 
        mutex_lock(&con->mutex);
+restart:
        if (test_and_clear_bit(BACKOFF, &con->state)) {
                dout("con_work %p backing off\n", con);
                if (queue_delayed_work(ceph_msgr_wq, &con->work,
@@ -1969,18 +2000,31 @@ static void con_work(struct work_struct *work)
                con_close_socket(con);
        }
 
-       if (test_and_clear_bit(SOCK_CLOSED, &con->state) ||
-           try_read(con) < 0 ||
-           try_write(con) < 0) {
-               mutex_unlock(&con->mutex);
-               ceph_fault(con);     /* error/fault path */
-               goto done_unlocked;
-       }
+       if (test_and_clear_bit(SOCK_CLOSED, &con->state))
+               goto fault;
+
+       ret = try_read(con);
+       if (ret == -EAGAIN)
+               goto restart;
+       if (ret < 0)
+               goto fault;
+
+       ret = try_write(con);
+       if (ret == -EAGAIN)
+               goto restart;
+       if (ret < 0)
+               goto fault;
 
 done:
        mutex_unlock(&con->mutex);
 done_unlocked:
        con->ops->put(con);
+       return;
+
+fault:
+       mutex_unlock(&con->mutex);
+       ceph_fault(con);     /* error/fault path */
+       goto done_unlocked;
 }
 
 
index 6b5dda1cb5df1a7adf6b93a49201b34d81eb8dcb..9cb627a4073aef3007afe4dd600ae96d85f0af0b 100644 (file)
@@ -124,7 +124,7 @@ static void calc_layout(struct ceph_osd_client *osdc,
        ceph_calc_raw_layout(osdc, layout, vino.snap, off,
                             plen, &bno, req, op);
 
-       sprintf(req->r_oid, "%llx.%08llx", vino.ino, bno);
+       snprintf(req->r_oid, sizeof(req->r_oid), "%llx.%08llx", vino.ino, bno);
        req->r_oid_len = strlen(req->r_oid);
 }
 
@@ -1144,6 +1144,13 @@ static void handle_osds_timeout(struct work_struct *work)
                              round_jiffies_relative(delay));
 }
 
+static void complete_request(struct ceph_osd_request *req)
+{
+       if (req->r_safe_callback)
+               req->r_safe_callback(req, NULL);
+       complete_all(&req->r_safe_completion);  /* fsync waiter */
+}
+
 /*
  * handle osd op reply.  either call the callback if it is specified,
  * or do the completion to wake up the waiting thread.
@@ -1226,11 +1233,8 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg,
        else
                complete_all(&req->r_completion);
 
-       if (flags & CEPH_OSD_FLAG_ONDISK) {
-               if (req->r_safe_callback)
-                       req->r_safe_callback(req, msg);
-               complete_all(&req->r_safe_completion);  /* fsync waiter */
-       }
+       if (flags & CEPH_OSD_FLAG_ONDISK)
+               complete_request(req);
 
 done:
        dout("req=%p req->r_linger=%d\n", req, req->r_linger);
@@ -1421,6 +1425,15 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
 done:
        downgrade_write(&osdc->map_sem);
        ceph_monc_got_osdmap(&osdc->client->monc, osdc->osdmap->epoch);
+
+       /*
+        * subscribe to subsequent osdmap updates if full to ensure
+        * we find out when we are no longer full and stop returning
+        * ENOSPC.
+        */
+       if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL))
+               ceph_monc_request_next_osdmap(&osdc->client->monc);
+
        send_queued(osdc);
        up_read(&osdc->map_sem);
        wake_up_all(&osdc->client->auth_wq);
@@ -1677,8 +1690,14 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
         */
        if (req->r_sent == 0) {
                rc = __map_request(osdc, req);
-               if (rc < 0)
+               if (rc < 0) {
+                       if (nofail) {
+                               dout("osdc_start_request failed map, "
+                                    " will retry %lld\n", req->r_tid);
+                               rc = 0;
+                       }
                        goto out_unlock;
+               }
                if (req->r_osd == NULL) {
                        dout("send_request %p no up osds in pg\n", req);
                        ceph_monc_request_next_osdmap(&osdc->client->monc);
@@ -1717,6 +1736,7 @@ int ceph_osdc_wait_request(struct ceph_osd_client *osdc,
                __cancel_request(req);
                __unregister_request(osdc, req);
                mutex_unlock(&osdc->request_mutex);
+               complete_request(req);
                dout("wait_request tid %llu canceled/timed out\n", req->r_tid);
                return rc;
        }
index 71603ac3dff54486cf1cdacaea142a3ecfc5f6fc..e97c3588c3ec00e719f7cb400784c36b5cb2fad6 100644 (file)
@@ -765,7 +765,7 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
        }
 
        map->epoch++;
-       map->modified = map->modified;
+       map->modified = modified;
        if (newcrush) {
                if (map->crush)
                        crush_destroy(map->crush);
@@ -830,15 +830,20 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
                map->osd_addr[osd] = addr;
        }
 
-       /* new_down */
+       /* new_state */
        ceph_decode_32_safe(p, end, len, bad);
        while (len--) {
                u32 osd;
+               u8 xorstate;
                ceph_decode_32_safe(p, end, osd, bad);
+               xorstate = **(u8 **)p;
                (*p)++;  /* clean flag */
-               pr_info("osd%d down\n", osd);
+               if (xorstate == 0)
+                       xorstate = CEPH_OSD_UP;
+               if (xorstate & CEPH_OSD_UP)
+                       pr_info("osd%d down\n", osd);
                if (osd < map->max_osd)
-                       map->osd_state[osd] &= ~CEPH_OSD_UP;
+                       map->osd_state[osd] ^= xorstate;
        }
 
        /* new_weight */
index bcb05cb799c11ff4373ca112b3c3b62a46d55ad2..9c58c1ec41a9dba24cca0318f723b01208c7b880 100644 (file)
@@ -1308,6 +1308,13 @@ void dev_disable_lro(struct net_device *dev)
 {
        u32 flags;
 
+       /*
+        * If we're trying to disable lro on a vlan device
+        * use the underlying physical device instead
+        */
+       if (is_vlan_dev(dev))
+               dev = vlan_dev_real_dev(dev);
+
        if (dev->ethtool_ops && dev->ethtool_ops->get_flags)
                flags = dev->ethtool_ops->get_flags(dev);
        else
@@ -2089,6 +2096,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
 {
        const struct net_device_ops *ops = dev->netdev_ops;
        int rc = NETDEV_TX_OK;
+       unsigned int skb_len;
 
        if (likely(!skb->next)) {
                u32 features;
@@ -2139,8 +2147,9 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
                        }
                }
 
+               skb_len = skb->len;
                rc = ops->ndo_start_xmit(skb, dev);
-               trace_net_dev_xmit(skb, rc);
+               trace_net_dev_xmit(skb, rc, dev, skb_len);
                if (rc == NETDEV_TX_OK)
                        txq_trans_update(txq);
                return rc;
@@ -2160,8 +2169,9 @@ gso:
                if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
                        skb_dst_drop(nskb);
 
+               skb_len = nskb->len;
                rc = ops->ndo_start_xmit(nskb, dev);
-               trace_net_dev_xmit(nskb, rc);
+               trace_net_dev_xmit(nskb, rc, dev, skb_len);
                if (unlikely(rc != NETDEV_TX_OK)) {
                        if (rc & ~NETDEV_TX_MASK)
                                goto out_kfree_gso_skb;
@@ -3104,7 +3114,7 @@ static int __netif_receive_skb(struct sk_buff *skb)
 
        skb_reset_network_header(skb);
        skb_reset_transport_header(skb);
-       skb->mac_len = skb->network_header - skb->mac_header;
+       skb_reset_mac_len(skb);
 
        pt_prev = NULL;
 
@@ -5954,7 +5964,10 @@ EXPORT_SYMBOL(free_netdev);
 void synchronize_net(void)
 {
        might_sleep();
-       synchronize_rcu();
+       if (rtnl_is_locked())
+               synchronize_rcu_expedited();
+       else
+               synchronize_rcu();
 }
 EXPORT_SYMBOL(synchronize_net);
 
@@ -6165,6 +6178,11 @@ static int dev_cpu_callback(struct notifier_block *nfb,
                oldsd->output_queue = NULL;
                oldsd->output_queue_tailp = &oldsd->output_queue;
        }
+       /* Append NAPI poll list from offline CPU. */
+       if (!list_empty(&oldsd->poll_list)) {
+               list_splice_init(&oldsd->poll_list, &sd->poll_list);
+               raise_softirq_irqoff(NET_RX_SOFTIRQ);
+       }
 
        raise_softirq_irqoff(NET_TX_SOFTIRQ);
        local_irq_enable();
@@ -6251,29 +6269,23 @@ err_name:
 /**
  *     netdev_drivername - network driver for the device
  *     @dev: network device
- *     @buffer: buffer for resulting name
- *     @len: size of buffer
  *
  *     Determine network driver for device.
  */
-char *netdev_drivername(const struct net_device *dev, char *buffer, int len)
+const char *netdev_drivername(const struct net_device *dev)
 {
        const struct device_driver *driver;
        const struct device *parent;
-
-       if (len <= 0 || !buffer)
-               return buffer;
-       buffer[0] = 0;
+       const char *empty = "";
 
        parent = dev->dev.parent;
-
        if (!parent)
-               return buffer;
+               return empty;
 
        driver = parent->driver;
        if (driver && driver->name)
-               strlcpy(buffer, driver->name, len);
-       return buffer;
+               return driver->name;
+       return empty;
 }
 
 static int __netdev_printk(const char *level, const struct net_device *dev,
index 81a4fa1c95ed32a266ef503b796ee998f4599a1d..9ccca038444f11fda683bbed8bf56ad0d5e1b65e 100644 (file)
@@ -315,7 +315,7 @@ void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old)
 {
        unsigned long prev, new;
 
-       new = (unsigned long) dst_default_metrics;
+       new = ((unsigned long) dst_default_metrics) | DST_METRICS_READ_ONLY;
        prev = cmpxchg(&dst->_metrics, old, new);
        if (prev == old)
                kfree(__DST_METRICS_PTR(old));
index 84e7304532e69f7ba1cc32fc47a4bdf8b7f5fc87..fd14116ad7f0626aca22412e3a02f1f0b9830d7d 100644 (file)
@@ -233,6 +233,29 @@ static int ethtool_set_feature_compat(struct net_device *dev,
        return 1;
 }
 
+static int ethtool_set_flags_compat(struct net_device *dev,
+       int (*legacy_set)(struct net_device *, u32),
+       struct ethtool_set_features_block *features, u32 mask)
+{
+       u32 value;
+
+       if (!legacy_set)
+               return 0;
+
+       if (!(features[0].valid & mask))
+               return 0;
+
+       value = dev->features & ~features[0].valid;
+       value |= features[0].requested;
+
+       features[0].valid &= ~mask;
+
+       if (legacy_set(dev, value & mask) < 0)
+               netdev_info(dev, "Legacy flags change failed\n");
+
+       return 1;
+}
+
 static int ethtool_set_features_compat(struct net_device *dev,
        struct ethtool_set_features_block *features)
 {
@@ -249,7 +272,7 @@ static int ethtool_set_features_compat(struct net_device *dev,
                features, NETIF_F_ALL_TSO);
        compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_rx_csum,
                features, NETIF_F_RXCSUM);
-       compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_flags,
+       compat |= ethtool_set_flags_compat(dev, dev->ethtool_ops->set_flags,
                features, flags_dup_features);
 
        return compat;
index 3911586e12e4b09d2fa5ab0d02110d5db877f479..008dc70b064b3043cbf17fd4a63605db51d0fa94 100644 (file)
@@ -602,6 +602,7 @@ static int dump_rules(struct sk_buff *skb, struct netlink_callback *cb,
 skip:
                idx++;
        }
+       rcu_read_unlock();
        cb->args[1] = idx;
        rules_ops_put(ops);
 
index 0eb8c4466eaa001bad837087e72df34685778c9a..36f975fa87cb4975a01e4105c5cc3b0f9d905367 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/unaligned.h>
 #include <linux/filter.h>
 #include <linux/reciprocal_div.h>
+#include <linux/ratelimit.h>
 
 /* No hurry in this branch */
 static void *__load_pointer(const struct sk_buff *skb, int k, unsigned int size)
@@ -350,7 +351,9 @@ load_b:
                        continue;
                }
                default:
-                       WARN_ON(1);
+                       WARN_RATELIMIT(1, "Unknown code:%u jt:%u tf:%u k:%u\n",
+                                      fentry->code, fentry->jt,
+                                      fentry->jf, fentry->k);
                        return 0;
                }
        }
index 11b98bc2aa8f4db7805cfe14f2087f5d8ced9824..33d2a1fba131695451de05e191ae9c10fb2cd307 100644 (file)
@@ -1179,9 +1179,14 @@ static void remove_queue_kobjects(struct net_device *net)
 #endif
 }
 
-static const void *net_current_ns(void)
+static void *net_grab_current_ns(void)
 {
-       return current->nsproxy->net_ns;
+       struct net *ns = current->nsproxy->net_ns;
+#ifdef CONFIG_NET_NS
+       if (ns)
+               atomic_inc(&ns->passive);
+#endif
+       return ns;
 }
 
 static const void *net_initial_ns(void)
@@ -1196,22 +1201,13 @@ static const void *net_netlink_ns(struct sock *sk)
 
 struct kobj_ns_type_operations net_ns_type_operations = {
        .type = KOBJ_NS_TYPE_NET,
-       .current_ns = net_current_ns,
+       .grab_current_ns = net_grab_current_ns,
        .netlink_ns = net_netlink_ns,
        .initial_ns = net_initial_ns,
+       .drop_ns = net_drop_ns,
 };
 EXPORT_SYMBOL_GPL(net_ns_type_operations);
 
-static void net_kobj_ns_exit(struct net *net)
-{
-       kobj_ns_exit(KOBJ_NS_TYPE_NET, net);
-}
-
-static struct pernet_operations kobj_net_ops = {
-       .exit = net_kobj_ns_exit,
-};
-
-
 #ifdef CONFIG_HOTPLUG
 static int netdev_uevent(struct device *d, struct kobj_uevent_env *env)
 {
@@ -1339,6 +1335,5 @@ EXPORT_SYMBOL(netdev_class_remove_file);
 int netdev_kobject_init(void)
 {
        kobj_ns_type_register(&net_ns_type_operations);
-       register_pernet_subsys(&kobj_net_ops);
        return class_register(&net_class);
 }
index 2e2dce6583e14f10c786ecf81b4042cacf3593ae..ea489db1bc2361c20001576a5e909aa22cb689d2 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/idr.h>
 #include <linux/rculist.h>
 #include <linux/nsproxy.h>
+#include <linux/proc_fs.h>
+#include <linux/file.h>
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 
@@ -126,6 +128,7 @@ static __net_init int setup_net(struct net *net)
        LIST_HEAD(net_exit_list);
 
        atomic_set(&net->count, 1);
+       atomic_set(&net->passive, 1);
 
 #ifdef NETNS_REFCNT_DEBUG
        atomic_set(&net->use_count, 0);
@@ -208,6 +211,13 @@ static void net_free(struct net *net)
        kmem_cache_free(net_cachep, net);
 }
 
+void net_drop_ns(void *p)
+{
+       struct net *ns = p;
+       if (ns && atomic_dec_and_test(&ns->passive))
+               net_free(ns);
+}
+
 struct net *copy_net_ns(unsigned long flags, struct net *old_net)
 {
        struct net *net;
@@ -228,7 +238,7 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net)
        }
        mutex_unlock(&net_mutex);
        if (rv < 0) {
-               net_free(net);
+               net_drop_ns(net);
                return ERR_PTR(rv);
        }
        return net;
@@ -284,7 +294,7 @@ static void cleanup_net(struct work_struct *work)
        /* Finally it is safe to free my network namespace structure */
        list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) {
                list_del_init(&net->exit_list);
-               net_free(net);
+               net_drop_ns(net);
        }
 }
 static DECLARE_WORK(net_cleanup_work, cleanup_net);
@@ -302,6 +312,26 @@ void __put_net(struct net *net)
 }
 EXPORT_SYMBOL_GPL(__put_net);
 
+struct net *get_net_ns_by_fd(int fd)
+{
+       struct proc_inode *ei;
+       struct file *file;
+       struct net *net;
+
+       file = proc_ns_fget(fd);
+       if (IS_ERR(file))
+               return ERR_CAST(file);
+
+       ei = PROC_I(file->f_dentry->d_inode);
+       if (ei->ns_ops == &netns_operations)
+               net = get_net(ei->ns);
+       else
+               net = ERR_PTR(-EINVAL);
+
+       fput(file);
+       return net;
+}
+
 #else
 struct net *copy_net_ns(unsigned long flags, struct net *old_net)
 {
@@ -309,6 +339,11 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net)
                return ERR_PTR(-EINVAL);
        return old_net;
 }
+
+struct net *get_net_ns_by_fd(int fd)
+{
+       return ERR_PTR(-EINVAL);
+}
 #endif
 
 struct net *get_net_ns_by_pid(pid_t pid)
@@ -561,3 +596,39 @@ void unregister_pernet_device(struct pernet_operations *ops)
        mutex_unlock(&net_mutex);
 }
 EXPORT_SYMBOL_GPL(unregister_pernet_device);
+
+#ifdef CONFIG_NET_NS
+static void *netns_get(struct task_struct *task)
+{
+       struct net *net = NULL;
+       struct nsproxy *nsproxy;
+
+       rcu_read_lock();
+       nsproxy = task_nsproxy(task);
+       if (nsproxy)
+               net = get_net(nsproxy->net_ns);
+       rcu_read_unlock();
+
+       return net;
+}
+
+static void netns_put(void *ns)
+{
+       put_net(ns);
+}
+
+static int netns_install(struct nsproxy *nsproxy, void *ns)
+{
+       put_net(nsproxy->net_ns);
+       nsproxy->net_ns = get_net(ns);
+       return 0;
+}
+
+const struct proc_ns_operations netns_operations = {
+       .name           = "net",
+       .type           = CLONE_NEWNET,
+       .get            = netns_get,
+       .put            = netns_put,
+       .install        = netns_install,
+};
+#endif
index 2d7d6d4737810c0bd9d0b93defbf2c972f1c6b2e..18d9cbda3a39c0b19d0751350489c08249cba635 100644 (file)
@@ -792,6 +792,13 @@ int netpoll_setup(struct netpoll *np)
                return -ENODEV;
        }
 
+       if (ndev->master) {
+               printk(KERN_ERR "%s: %s is a slave device, aborting.\n",
+                      np->name, np->dev_name);
+               err = -EBUSY;
+               goto put;
+       }
+
        if (!netif_running(ndev)) {
                unsigned long atmost, atleast;
 
index d1644e317e70cd2634e92fb5a61153ec18c74882..abd936d8a71658ecb108cadcfd1af67f5c8b982a 100644 (file)
@@ -850,6 +850,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
        struct nlattr *attr, *af_spec;
        struct rtnl_af_ops *af_ops;
 
+       ASSERT_RTNL();
        nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
        if (nlh == NULL)
                return -EMSGSIZE;
@@ -1045,6 +1046,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
        [IFLA_LINKMODE]         = { .type = NLA_U8 },
        [IFLA_LINKINFO]         = { .type = NLA_NESTED },
        [IFLA_NET_NS_PID]       = { .type = NLA_U32 },
+       [IFLA_NET_NS_FD]        = { .type = NLA_U32 },
        [IFLA_IFALIAS]          = { .type = NLA_STRING, .len = IFALIASZ-1 },
        [IFLA_VFINFO_LIST]      = {. type = NLA_NESTED },
        [IFLA_VF_PORTS]         = { .type = NLA_NESTED },
@@ -1093,6 +1095,8 @@ struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
         */
        if (tb[IFLA_NET_NS_PID])
                net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID]));
+       else if (tb[IFLA_NET_NS_FD])
+               net = get_net_ns_by_fd(nla_get_u32(tb[IFLA_NET_NS_FD]));
        else
                net = get_net(src_net);
        return net;
@@ -1223,7 +1227,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
        int send_addr_notify = 0;
        int err;
 
-       if (tb[IFLA_NET_NS_PID]) {
+       if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) {
                struct net *net = rtnl_link_get_net(dev_net(dev), tb);
                if (IS_ERR(net)) {
                        err = PTR_ERR(net);
@@ -1876,6 +1880,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        int min_len;
        int family;
        int type;
+       int err;
 
        type = nlh->nlmsg_type;
        if (type > RTM_MAX)
@@ -1902,8 +1907,11 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                if (dumpit == NULL)
                        return -EOPNOTSUPP;
 
+               __rtnl_unlock();
                rtnl = net->rtnl;
-               return netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
+               err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
+               rtnl_lock();
+               return err;
        }
 
        memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *)));
@@ -1975,7 +1983,7 @@ static int __net_init rtnetlink_net_init(struct net *net)
 {
        struct sock *sk;
        sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX,
-                                  rtnetlink_rcv, NULL, THIS_MODULE);
+                                  rtnetlink_rcv, &rtnl_mutex, THIS_MODULE);
        if (!sk)
                return -ENOMEM;
        net->rtnl = sk;
index a829e3f60aeb2812a9a4a92e3d5accf3ce128b77..77a65f031488b3f222e13d1f071a2d3f44218c70 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <net/ip.h>
 #include <net/sock.h>
+#include <net/net_ratelimit.h>
 
 #ifdef CONFIG_RPS
 static int rps_sock_flow_sysctl(ctl_table *table, int write,
index 2012bc797f9c32b9a9a2af81fc08768177d86377..386e263f60669a3a25be7e6d8a4361d7ce93161e 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/ratelimit.h>
 
 #include <net/sock.h>
+#include <net/net_ratelimit.h>
 
 #include <asm/byteorder.h>
 #include <asm/system.h>
index cfa7a5e1c5c98ca4592e09588a3a80bc1ba24d10..fa000d26dc6097220fe8bf53ed7cfc822afc31a0 100644 (file)
@@ -212,10 +212,12 @@ static void dns_resolver_describe(const struct key *key, struct seq_file *m)
        int err = key->type_data.x[0];
 
        seq_puts(m, key->description);
-       if (err)
-               seq_printf(m, ": %d", err);
-       else
-               seq_printf(m, ": %u", key->datalen);
+       if (key_is_instantiated(key)) {
+               if (err)
+                       seq_printf(m, ": %d", err);
+               else
+                       seq_printf(m, ": %u", key->datalen);
+       }
 }
 
 /*
index ed0eab39f531f028e96deaa5f61755c46c4e5855..02548b292b53bf416f4e0ced8daeeb9e842666e3 100644 (file)
@@ -44,7 +44,7 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 pid,
        pr_debug("%s\n", __func__);
 
        if (!buf)
-               goto out;
+               return -EMSGSIZE;
 
        hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags,
                IEEE802154_LIST_PHY);
@@ -65,6 +65,7 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 pid,
                                pages * sizeof(uint32_t), buf);
 
        mutex_unlock(&phy->pib_lock);
+       kfree(buf);
        return genlmsg_end(msg, hdr);
 
 nla_put_failure:
index cc1463156cd037ad08b6a2f637c90b4d43fc5e7a..eae1f676f870a8e219bcb3ee4a28453961604def 100644 (file)
@@ -465,6 +465,9 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        if (addr_len < sizeof(struct sockaddr_in))
                goto out;
 
+       if (addr->sin_family != AF_INET)
+               goto out;
+
        chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr);
 
        /* Not specified by any standard per-se, however it breaks too
@@ -673,6 +676,7 @@ int inet_accept(struct socket *sock, struct socket *newsock, int flags)
 
        lock_sock(sk2);
 
+       sock_rps_record_flow(sk2);
        WARN_ON(!((1 << sk2->sk_state) &
                  (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_CLOSE)));
 
index 672e476c8c8a824a98c99fee9c3cabe765411c72..f1d27f6c9351d2a2bdc15d22fbb35ea270022f22 100644 (file)
@@ -1155,20 +1155,18 @@ static void igmp_group_dropped(struct ip_mc_list *im)
 
        if (!in_dev->dead) {
                if (IGMP_V1_SEEN(in_dev))
-                       goto done;
+                       return;
                if (IGMP_V2_SEEN(in_dev)) {
                        if (reporter)
                                igmp_send_report(in_dev, im, IGMP_HOST_LEAVE_MESSAGE);
-                       goto done;
+                       return;
                }
                /* IGMPv3 */
                igmpv3_add_delrec(in_dev, im);
 
                igmp_ifc_event(in_dev);
        }
-done:
 #endif
-       ip_mc_clear_src(im);
 }
 
 static void igmp_group_added(struct ip_mc_list *im)
@@ -1305,6 +1303,7 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
                                *ip = i->next_rcu;
                                in_dev->mc_count--;
                                igmp_group_dropped(i);
+                               ip_mc_clear_src(i);
 
                                if (!in_dev->dead)
                                        ip_rt_multicast_event(in_dev);
@@ -1414,7 +1413,8 @@ void ip_mc_destroy_dev(struct in_device *in_dev)
                in_dev->mc_list = i->next_rcu;
                in_dev->mc_count--;
 
-               igmp_group_dropped(i);
+               /* We've dropped the groups in ip_mc_down already */
+               ip_mc_clear_src(i);
                ip_ma_put(i);
        }
 }
index 61fac4cabc7825f591c5b94dd7520c095d9e7f3f..c14d88ad348d3365a11685a59c453d54c4db5332 100644 (file)
@@ -33,7 +33,7 @@ EXPORT_SYMBOL(inet_csk_timer_bug_msg);
  * This struct holds the first and last local port number.
  */
 struct local_ports sysctl_local_ports __read_mostly = {
-       .lock = SEQLOCK_UNLOCKED,
+       .lock = __SEQLOCK_UNLOCKED(sysctl_local_ports.lock),
        .range = { 32768, 61000 },
 };
 
index 6ffe94ca5bc98bfea2488679ba416ef71295b71a..3267d389843794e0b481f05c22021e905fc6e6d1 100644 (file)
@@ -437,7 +437,7 @@ static int valid_cc(const void *bc, int len, int cc)
                        return 0;
                if (cc == len)
                        return 1;
-               if (op->yes < 4)
+               if (op->yes < 4 || op->yes & 3)
                        return 0;
                len -= op->yes;
                bc  += op->yes;
@@ -447,11 +447,11 @@ static int valid_cc(const void *bc, int len, int cc)
 
 static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
 {
-       const unsigned char *bc = bytecode;
+       const void *bc = bytecode;
        int  len = bytecode_len;
 
        while (len > 0) {
-               struct inet_diag_bc_op *op = (struct inet_diag_bc_op *)bc;
+               const struct inet_diag_bc_op *op = bc;
 
 //printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len);
                switch (op->code) {
@@ -462,22 +462,20 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
                case INET_DIAG_BC_S_LE:
                case INET_DIAG_BC_D_GE:
                case INET_DIAG_BC_D_LE:
-                       if (op->yes < 4 || op->yes > len + 4)
-                               return -EINVAL;
                case INET_DIAG_BC_JMP:
-                       if (op->no < 4 || op->no > len + 4)
+                       if (op->no < 4 || op->no > len + 4 || op->no & 3)
                                return -EINVAL;
                        if (op->no < len &&
                            !valid_cc(bytecode, bytecode_len, len - op->no))
                                return -EINVAL;
                        break;
                case INET_DIAG_BC_NOP:
-                       if (op->yes < 4 || op->yes > len + 4)
-                               return -EINVAL;
                        break;
                default:
                        return -EINVAL;
                }
+               if (op->yes < 4 || op->yes > len + 4 || op->yes & 3)
+                       return -EINVAL;
                bc  += op->yes;
                len -= op->yes;
        }
index 9df4e635fb5fe5d4a0c92526ad68b845094aa39d..ce616d92cc544dd0a8e3ffb0974aff825a5939e9 100644 (file)
@@ -154,11 +154,9 @@ void __init inet_initpeers(void)
 /* Called with or without local BH being disabled. */
 static void unlink_from_unused(struct inet_peer *p)
 {
-       if (!list_empty(&p->unused)) {
-               spin_lock_bh(&unused_peers.lock);
-               list_del_init(&p->unused);
-               spin_unlock_bh(&unused_peers.lock);
-       }
+       spin_lock_bh(&unused_peers.lock);
+       list_del_init(&p->unused);
+       spin_unlock_bh(&unused_peers.lock);
 }
 
 static int addr_compare(const struct inetpeer_addr *a,
@@ -205,6 +203,20 @@ static int addr_compare(const struct inetpeer_addr *a,
        u;                                                      \
 })
 
+static bool atomic_add_unless_return(atomic_t *ptr, int a, int u, int *newv)
+{
+       int cur, old = atomic_read(ptr);
+
+       while (old != u) {
+               *newv = old + a;
+               cur = atomic_cmpxchg(ptr, old, *newv);
+               if (cur == old)
+                       return true;
+               old = cur;
+       }
+       return false;
+}
+
 /*
  * Called with rcu_read_lock()
  * Because we hold no lock against a writer, its quite possible we fall
@@ -213,7 +225,8 @@ static int addr_compare(const struct inetpeer_addr *a,
  * We exit from this function if number of links exceeds PEER_MAXDEPTH
  */
 static struct inet_peer *lookup_rcu(const struct inetpeer_addr *daddr,
-                                   struct inet_peer_base *base)
+                                   struct inet_peer_base *base,
+                                   int *newrefcnt)
 {
        struct inet_peer *u = rcu_dereference(base->root);
        int count = 0;
@@ -226,7 +239,7 @@ static struct inet_peer *lookup_rcu(const struct inetpeer_addr *daddr,
                         * distinction between an unused entry (refcnt=0) and
                         * a freed one.
                         */
-                       if (unlikely(!atomic_add_unless(&u->refcnt, 1, -1)))
+                       if (!atomic_add_unless_return(&u->refcnt, 1, -1, newrefcnt))
                                u = NULL;
                        return u;
                }
@@ -465,22 +478,23 @@ struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create)
        struct inet_peer_base *base = family_to_base(daddr->family);
        struct inet_peer *p;
        unsigned int sequence;
-       int invalidated;
+       int invalidated, newrefcnt = 0;
 
        /* Look up for the address quickly, lockless.
         * Because of a concurrent writer, we might not find an existing entry.
         */
        rcu_read_lock();
        sequence = read_seqbegin(&base->lock);
-       p = lookup_rcu(daddr, base);
+       p = lookup_rcu(daddr, base, &newrefcnt);
        invalidated = read_seqretry(&base->lock, sequence);
        rcu_read_unlock();
 
        if (p) {
-               /* The existing node has been found.
+found:         /* The existing node has been found.
                 * Remove the entry from unused list if it was there.
                 */
-               unlink_from_unused(p);
+               if (newrefcnt == 1)
+                       unlink_from_unused(p);
                return p;
        }
 
@@ -494,11 +508,9 @@ struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create)
        write_seqlock_bh(&base->lock);
        p = lookup(daddr, stack, base);
        if (p != peer_avl_empty) {
-               atomic_inc(&p->refcnt);
+               newrefcnt = atomic_inc_return(&p->refcnt);
                write_sequnlock_bh(&base->lock);
-               /* Remove the entry from unused list if it was there. */
-               unlink_from_unused(p);
-               return p;
+               goto found;
        }
        p = create ? kmem_cache_alloc(peer_cachep, GFP_ATOMIC) : NULL;
        if (p) {
index c3118e1cd3bb502c293748e40b2c3ccc648c8b94..ec93335901ddc45d09f7c85c53270ea9a6772207 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <asm/uaccess.h>
+#include <asm/unaligned.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
 #include <linux/icmp.h>
@@ -350,7 +351,7 @@ int ip_options_compile(struct net *net,
                                goto error;
                        }
                        if (optptr[2] <= optlen) {
-                               __be32 *timeptr = NULL;
+                               unsigned char *timeptr = NULL;
                                if (optptr[2]+3 > optptr[1]) {
                                        pp_ptr = optptr + 2;
                                        goto error;
@@ -359,7 +360,7 @@ int ip_options_compile(struct net *net,
                                      case IPOPT_TS_TSONLY:
                                        opt->ts = optptr - iph;
                                        if (skb)
-                                               timeptr = (__be32*)&optptr[optptr[2]-1];
+                                               timeptr = &optptr[optptr[2]-1];
                                        opt->ts_needtime = 1;
                                        optptr[2] += 4;
                                        break;
@@ -371,7 +372,7 @@ int ip_options_compile(struct net *net,
                                        opt->ts = optptr - iph;
                                        if (rt)  {
                                                memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4);
-                                               timeptr = (__be32*)&optptr[optptr[2]+3];
+                                               timeptr = &optptr[optptr[2]+3];
                                        }
                                        opt->ts_needaddr = 1;
                                        opt->ts_needtime = 1;
@@ -389,7 +390,7 @@ int ip_options_compile(struct net *net,
                                                if (inet_addr_type(net, addr) == RTN_UNICAST)
                                                        break;
                                                if (skb)
-                                                       timeptr = (__be32*)&optptr[optptr[2]+3];
+                                                       timeptr = &optptr[optptr[2]+3];
                                        }
                                        opt->ts_needtime = 1;
                                        optptr[2] += 8;
@@ -403,10 +404,10 @@ int ip_options_compile(struct net *net,
                                }
                                if (timeptr) {
                                        struct timespec tv;
-                                       __be32  midtime;
+                                       u32  midtime;
                                        getnstimeofday(&tv);
-                                       midtime = htonl((tv.tv_sec % 86400) * MSEC_PER_SEC + tv.tv_nsec / NSEC_PER_MSEC);
-                                       memcpy(timeptr, &midtime, sizeof(__be32));
+                                       midtime = (tv.tv_sec % 86400) * MSEC_PER_SEC + tv.tv_nsec / NSEC_PER_MSEC;
+                                       put_unaligned_be32(midtime, timeptr);
                                        opt->is_changed = 1;
                                }
                        } else {
index 98af3697c7188870effc865e3caaef76e579a809..a8024eaa0e87b15ebdc86058a87c24f0813a610a 100644 (file)
@@ -799,7 +799,9 @@ static int __ip_append_data(struct sock *sk,
        int csummode = CHECKSUM_NONE;
        struct rtable *rt = (struct rtable *)cork->dst;
 
-       exthdrlen = transhdrlen ? rt->dst.header_len : 0;
+       skb = skb_peek_tail(queue);
+
+       exthdrlen = !skb ? rt->dst.header_len : 0;
        length += exthdrlen;
        transhdrlen += exthdrlen;
        mtu = cork->fragsize;
@@ -825,8 +827,6 @@ static int __ip_append_data(struct sock *sk,
            !exthdrlen)
                csummode = CHECKSUM_PARTIAL;
 
-       skb = skb_peek_tail(queue);
-
        cork->length += length;
        if (((length > mtu) || (skb && skb_is_gso(skb))) &&
            (sk->sk_protocol == IPPROTO_UDP) &&
index d2c1311cb28d6aee7b218351580210b4e5783a3e..5c9b9d963918aa538086239d2351afea574324cb 100644 (file)
@@ -203,7 +203,8 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
        else
                pmsg->outdev_name[0] = '\0';
 
-       if (entry->indev && entry->skb->dev) {
+       if (entry->indev && entry->skb->dev &&
+           entry->skb->mac_header != entry->skb->network_header) {
                pmsg->hw_type = entry->skb->dev->type;
                pmsg->hw_addrlen = dev_parse_header(entry->skb,
                                                    pmsg->hw_addr);
@@ -402,7 +403,8 @@ ipq_dev_drop(int ifindex)
 static inline void
 __ipq_rcv_skb(struct sk_buff *skb)
 {
-       int status, type, pid, flags, nlmsglen, skblen;
+       int status, type, pid, flags;
+       unsigned int nlmsglen, skblen;
        struct nlmsghdr *nlh;
 
        skblen = skb->len;
index 7647438435030a4fa29ba98539ec423921086b16..24e556e83a3ba97fe633525c10e63d4bcb767b34 100644 (file)
@@ -566,7 +566,7 @@ check_entry(const struct ipt_entry *e, const char *name)
        const struct xt_entry_target *t;
 
        if (!ip_checkentry(&e->ip)) {
-               duprintf("ip check failed %p %s.\n", e, par->match->name);
+               duprintf("ip check failed %p %s.\n", e, name);
                return -EINVAL;
        }
 
index d609ac3cb9a450e69d47e4d5bdb7365347cbb46a..5c9e97c790172984b7d87bd2d2f40b61028184cc 100644 (file)
@@ -307,7 +307,7 @@ clusterip_tg(struct sk_buff *skb, const struct xt_action_param *par)
         * error messages (RELATED) and information requests (see below) */
        if (ip_hdr(skb)->protocol == IPPROTO_ICMP &&
            (ctinfo == IP_CT_RELATED ||
-            ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY))
+            ctinfo == IP_CT_RELATED_REPLY))
                return XT_CONTINUE;
 
        /* ip_conntrack_icmp guarantees us that we only have ICMP_ECHO,
@@ -321,12 +321,12 @@ clusterip_tg(struct sk_buff *skb, const struct xt_action_param *par)
                        ct->mark = hash;
                        break;
                case IP_CT_RELATED:
-               case IP_CT_RELATED+IP_CT_IS_REPLY:
+               case IP_CT_RELATED_REPLY:
                        /* FIXME: we don't handle expectations at the
                         * moment.  they can arrive on a different node than
                         * the master connection (e.g. FTP passive mode) */
                case IP_CT_ESTABLISHED:
-               case IP_CT_ESTABLISHED+IP_CT_IS_REPLY:
+               case IP_CT_ESTABLISHED_REPLY:
                        break;
                default:
                        break;
index d2ed9dc74ebc3c029e134295f4ed490f27af0ef6..9931152a78b54e4512bc95bbbe720258ebb44d09 100644 (file)
@@ -60,7 +60,7 @@ masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par)
        nat = nfct_nat(ct);
 
        NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
-                           ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
+                           ctinfo == IP_CT_RELATED_REPLY));
 
        /* Source address is 0.0.0.0 - locally generated packet that is
         * probably not supposed to be masqueraded.
index af6e9c778345ff802916cc7fa0078cbd79735c81..2b57e52c746c4518b914da30775044692a740396 100644 (file)
@@ -25,7 +25,8 @@ MODULE_LICENSE("GPL");
 static inline bool match_ip(const struct sk_buff *skb,
                            const struct ipt_ecn_info *einfo)
 {
-       return (ip_hdr(skb)->tos & IPT_ECN_IP_MASK) == einfo->ip_ect;
+       return ((ip_hdr(skb)->tos & IPT_ECN_IP_MASK) == einfo->ip_ect) ^
+              !!(einfo->invert & IPT_ECN_OP_MATCH_IP);
 }
 
 static inline bool match_tcp(const struct sk_buff *skb,
@@ -76,8 +77,6 @@ static bool ecn_mt(const struct sk_buff *skb, struct xt_action_param *par)
                        return false;
 
        if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) {
-               if (ip_hdr(skb)->protocol != IPPROTO_TCP)
-                       return false;
                if (!match_tcp(skb, info, &par->hotdrop))
                        return false;
        }
@@ -97,7 +96,7 @@ static int ecn_mt_check(const struct xt_mtchk_param *par)
                return -EINVAL;
 
        if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR) &&
-           ip->proto != IPPROTO_TCP) {
+           (ip->proto != IPPROTO_TCP || ip->invflags & IPT_INV_PROTO)) {
                pr_info("cannot match TCP bits in rule for non-tcp packets\n");
                return -EINVAL;
        }
index 5a03c02af999a45ac7d3f9e403ea1c2d38bc0c5a..de9da21113a11be6c9f57b15a97b3936a574e512 100644 (file)
@@ -101,7 +101,7 @@ static unsigned int ipv4_confirm(unsigned int hooknum,
 
        /* This is where we call the helper: as the packet goes out. */
        ct = nf_ct_get(skb, &ctinfo);
-       if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)
+       if (!ct || ctinfo == IP_CT_RELATED_REPLY)
                goto out;
 
        help = nfct_help(ct);
@@ -121,7 +121,9 @@ static unsigned int ipv4_confirm(unsigned int hooknum,
                return ret;
        }
 
-       if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
+       /* adjust seqs for loopback traffic only in outgoing direction */
+       if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
+           !nf_is_loopback_packet(skb)) {
                typeof(nf_nat_seq_adjust_hook) seq_adjust;
 
                seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook);
index 7404bde959943d4fbbcee7901f3006bb4a971574..ab5b27a2916f70b79430f1a90ac7d7af6cceaebe 100644 (file)
@@ -160,7 +160,7 @@ icmp_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
        /* Update skb to refer to this connection */
        skb->nfct = &nf_ct_tuplehash_to_ctrack(h)->ct_general;
        skb->nfctinfo = *ctinfo;
-       return -NF_ACCEPT;
+       return NF_ACCEPT;
 }
 
 /* Small and modified version of icmp_rcv */
index 9c71b2755ce3e4eea5331fe17a49ec1701dccf02..3346de5d94d009ffe3466ce61f1103d5f66a5ca2 100644 (file)
@@ -433,7 +433,7 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
 
        /* Must be RELATED */
        NF_CT_ASSERT(skb->nfctinfo == IP_CT_RELATED ||
-                    skb->nfctinfo == IP_CT_RELATED+IP_CT_IS_REPLY);
+                    skb->nfctinfo == IP_CT_RELATED_REPLY);
 
        /* Redirects on non-null nats must be dropped, else they'll
           start talking to each other without our translation, and be
index 99cfa28b6d38f12fef3e1e94c07223d83e066e14..ebc5f8894f99eb06b8ef5616cafc06b427dd6a42 100644 (file)
@@ -160,7 +160,7 @@ static void nf_nat_csum(struct sk_buff *skb, const struct iphdr *iph, void *data
 
        if (skb->ip_summed != CHECKSUM_PARTIAL) {
                if (!(rt->rt_flags & RTCF_LOCAL) &&
-                   skb->dev->features & NETIF_F_V4_CSUM) {
+                   (!skb->dev || skb->dev->features & NETIF_F_V4_CSUM)) {
                        skb->ip_summed = CHECKSUM_PARTIAL;
                        skb->csum_start = skb_headroom(skb) +
                                          skb_network_offset(skb) +
index 21c30426480b0d08cdc10a0257ee2f6ce736840f..733c9abc1cbd9ddb7c45a0b7ffae9d72f608ae62 100644 (file)
@@ -53,7 +53,7 @@ ipt_snat_target(struct sk_buff *skb, const struct xt_action_param *par)
 
        /* Connection must be valid and new. */
        NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
-                           ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
+                           ctinfo == IP_CT_RELATED_REPLY));
        NF_CT_ASSERT(par->out != NULL);
 
        return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_SRC);
index 7317bdf1d457544daeef7dc05dce0b3dc23f7a2a..483b76d042da5ad2836005ab1dad3d1c17727c61 100644 (file)
@@ -116,7 +116,7 @@ nf_nat_fn(unsigned int hooknum,
 
        switch (ctinfo) {
        case IP_CT_RELATED:
-       case IP_CT_RELATED+IP_CT_IS_REPLY:
+       case IP_CT_RELATED_REPLY:
                if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
                        if (!nf_nat_icmp_reply_translation(ct, ctinfo,
                                                           hooknum, skb))
@@ -144,7 +144,7 @@ nf_nat_fn(unsigned int hooknum,
        default:
                /* ESTABLISHED */
                NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
-                            ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
+                            ctinfo == IP_CT_ESTABLISHED_REPLY);
        }
 
        return nf_nat_packet(ct, ctinfo, hooknum, skb);
index 1f3bb11490c960fff3f4d332c00bd1aeb98d9054..39b403f854c6debeb03437a2a9a0c9746083b399 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/proc_fs.h>
 #include <net/sock.h>
 #include <net/ping.h>
-#include <net/icmp.h>
 #include <net/udp.h>
 #include <net/route.h>
 #include <net/inet_common.h>
@@ -137,9 +136,6 @@ static void ping_v4_unhash(struct sock *sk)
        struct inet_sock *isk = inet_sk(sk);
        pr_debug("ping_v4_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num);
        if (sk_hashed(sk)) {
-               struct hlist_nulls_head *hslot;
-
-               hslot = ping_hashslot(&ping_table, sock_net(sk), isk->inet_num);
                write_lock_bh(&ping_table.lock);
                hlist_nulls_del(&sk->sk_nulls_node);
                sock_put(sk);
index 11e1780455f2aea349a8c163eecbb7f6bb43d1a6..c9893d43242e52c83580f4676f20793fd5bdf48b 100644 (file)
@@ -979,7 +979,7 @@ static void raw_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
              srcp  = inet->inet_num;
 
        seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
-               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
+               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d\n",
                i, src, srcp, dest, destp, sp->sk_state,
                sk_wmem_alloc_get(sp),
                sk_rmem_alloc_get(sp),
index 52b0b956508b93046dd0cc3ef9dfd157f3d57ea5..aa13ef1051108dac93a9151d0819d9fd7447ec64 100644 (file)
@@ -1316,6 +1316,23 @@ reject_redirect:
        ;
 }
 
+static bool peer_pmtu_expired(struct inet_peer *peer)
+{
+       unsigned long orig = ACCESS_ONCE(peer->pmtu_expires);
+
+       return orig &&
+              time_after_eq(jiffies, orig) &&
+              cmpxchg(&peer->pmtu_expires, orig, 0) == orig;
+}
+
+static bool peer_pmtu_cleaned(struct inet_peer *peer)
+{
+       unsigned long orig = ACCESS_ONCE(peer->pmtu_expires);
+
+       return orig &&
+              cmpxchg(&peer->pmtu_expires, orig, 0) == orig;
+}
+
 static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
 {
        struct rtable *rt = (struct rtable *)dst;
@@ -1331,14 +1348,8 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
                                                rt_genid(dev_net(dst->dev)));
                        rt_del(hash, rt);
                        ret = NULL;
-               } else if (rt->peer &&
-                          rt->peer->pmtu_expires &&
-                          time_after_eq(jiffies, rt->peer->pmtu_expires)) {
-                       unsigned long orig = rt->peer->pmtu_expires;
-
-                       if (cmpxchg(&rt->peer->pmtu_expires, orig, 0) == orig)
-                               dst_metric_set(dst, RTAX_MTU,
-                                              rt->peer->pmtu_orig);
+               } else if (rt->peer && peer_pmtu_expired(rt->peer)) {
+                       dst_metric_set(dst, RTAX_MTU, rt->peer->pmtu_orig);
                }
        }
        return ret;
@@ -1531,8 +1542,10 @@ unsigned short ip_rt_frag_needed(struct net *net, const struct iphdr *iph,
 
 static void check_peer_pmtu(struct dst_entry *dst, struct inet_peer *peer)
 {
-       unsigned long expires = peer->pmtu_expires;
+       unsigned long expires = ACCESS_ONCE(peer->pmtu_expires);
 
+       if (!expires)
+               return;
        if (time_before(jiffies, expires)) {
                u32 orig_dst_mtu = dst_mtu(dst);
                if (peer->pmtu_learned < orig_dst_mtu) {
@@ -1555,10 +1568,11 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
                rt_bind_peer(rt, rt->rt_dst, 1);
        peer = rt->peer;
        if (peer) {
+               unsigned long pmtu_expires = ACCESS_ONCE(peer->pmtu_expires);
+
                if (mtu < ip_rt_min_pmtu)
                        mtu = ip_rt_min_pmtu;
-               if (!peer->pmtu_expires || mtu < peer->pmtu_learned) {
-                       unsigned long pmtu_expires;
+               if (!pmtu_expires || mtu < peer->pmtu_learned) {
 
                        pmtu_expires = jiffies + ip_rt_mtu_expires;
                        if (!pmtu_expires)
@@ -1612,13 +1626,14 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
                        rt_bind_peer(rt, rt->rt_dst, 0);
 
                peer = rt->peer;
-               if (peer && peer->pmtu_expires)
+               if (peer) {
                        check_peer_pmtu(dst, peer);
 
-               if (peer && peer->redirect_learned.a4 &&
-                   peer->redirect_learned.a4 != rt->rt_gateway) {
-                       if (check_peer_redir(dst, peer))
-                               return NULL;
+                       if (peer->redirect_learned.a4 &&
+                           peer->redirect_learned.a4 != rt->rt_gateway) {
+                               if (check_peer_redir(dst, peer))
+                                       return NULL;
+                       }
                }
 
                rt->rt_peer_genid = rt_peer_genid();
@@ -1649,14 +1664,8 @@ static void ipv4_link_failure(struct sk_buff *skb)
        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
 
        rt = skb_rtable(skb);
-       if (rt &&
-           rt->peer &&
-           rt->peer->pmtu_expires) {
-               unsigned long orig = rt->peer->pmtu_expires;
-
-               if (cmpxchg(&rt->peer->pmtu_expires, orig, 0) == orig)
-                       dst_metric_set(&rt->dst, RTAX_MTU, rt->peer->pmtu_orig);
-       }
+       if (rt && rt->peer && peer_pmtu_cleaned(rt->peer))
+               dst_metric_set(&rt->dst, RTAX_MTU, rt->peer->pmtu_orig);
 }
 
 static int ip_rt_bug(struct sk_buff *skb)
@@ -1770,8 +1779,7 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4,
                               sizeof(u32) * RTAX_MAX);
                dst_init_metrics(&rt->dst, peer->metrics, false);
 
-               if (peer->pmtu_expires)
-                       check_peer_pmtu(&rt->dst, peer);
+               check_peer_pmtu(&rt->dst, peer);
                if (peer->redirect_learned.a4 &&
                    peer->redirect_learned.a4 != rt->rt_gateway) {
                        rt->rt_gateway = peer->redirect_learned.a4;
@@ -1894,9 +1902,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 
        hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev)));
        rth = rt_intern_hash(hash, rth, skb, dev->ifindex);
-       err = 0;
-       if (IS_ERR(rth))
-               err = PTR_ERR(rth);
+       return IS_ERR(rth) ? PTR_ERR(rth) : 0;
 
 e_nobufs:
        return -ENOBUFS;
@@ -2775,7 +2781,8 @@ static int rt_fill_info(struct net *net,
        struct rtable *rt = skb_rtable(skb);
        struct rtmsg *r;
        struct nlmsghdr *nlh;
-       long expires;
+       long expires = 0;
+       const struct inet_peer *peer = rt->peer;
        u32 id = 0, ts = 0, tsage = 0, error;
 
        nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags);
@@ -2823,15 +2830,16 @@ static int rt_fill_info(struct net *net,
                NLA_PUT_BE32(skb, RTA_MARK, rt->rt_mark);
 
        error = rt->dst.error;
-       expires = (rt->peer && rt->peer->pmtu_expires) ?
-               rt->peer->pmtu_expires - jiffies : 0;
-       if (rt->peer) {
+       if (peer) {
                inet_peer_refcheck(rt->peer);
-               id = atomic_read(&rt->peer->ip_id_count) & 0xffff;
-               if (rt->peer->tcp_ts_stamp) {
-                       ts = rt->peer->tcp_ts;
-                       tsage = get_seconds() - rt->peer->tcp_ts_stamp;
+               id = atomic_read(&peer->ip_id_count) & 0xffff;
+               if (peer->tcp_ts_stamp) {
+                       ts = peer->tcp_ts;
+                       tsage = get_seconds() - peer->tcp_ts_stamp;
                }
+               expires = ACCESS_ONCE(peer->pmtu_expires);
+               if (expires)
+                       expires -= jiffies;
        }
 
        if (rt_is_input_route(rt)) {
index 3c8d9b6f1ea4f05af6d8227672119e258ec7d8f5..708dc203b0348c3365b6ac3cd2e36559a069d0cc 100644 (file)
@@ -1589,6 +1589,7 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
                        goto discard;
 
                if (nsk != sk) {
+                       sock_rps_save_rxhash(nsk, skb->rxhash);
                        if (tcp_child_process(sk, nsk, skb)) {
                                rsk = nsk;
                                goto reset;
@@ -2371,7 +2372,7 @@ static void get_openreq4(struct sock *sk, struct request_sock *req,
        int ttd = req->expires - jiffies;
 
        seq_printf(f, "%4d: %08X:%04X %08X:%04X"
-               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %p%n",
+               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %pK%n",
                i,
                ireq->loc_addr,
                ntohs(inet_sk(sk)->inet_sport),
@@ -2426,7 +2427,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
                rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);
 
        seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
-                       "%08X %5d %8d %lu %d %p %lu %lu %u %u %d%n",
+                       "%08X %5d %8d %lu %d %pK %lu %lu %u %u %d%n",
                i, src, srcp, dest, destp, sk->sk_state,
                tp->write_seq - tp->snd_una,
                rx_queue,
@@ -2461,7 +2462,7 @@ static void get_timewait4_sock(struct inet_timewait_sock *tw,
        srcp  = ntohs(tw->tw_sport);
 
        seq_printf(f, "%4d: %08X:%04X %08X:%04X"
-               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p%n",
+               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK%n",
                i, src, srcp, dest, destp, tw->tw_substate, 0, 0,
                3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
                atomic_read(&tw->tw_refcnt), tw, len);
index 599374f65c7646473c1fa6781a9cf92ce6d90153..abca870d8ff69fe76a19bef7d9338d4f80fabaf0 100644 (file)
@@ -2090,7 +2090,7 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
        __u16 srcp        = ntohs(inet->inet_sport);
 
        seq_printf(f, "%5d: %08X:%04X %08X:%04X"
-               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d%n",
+               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d%n",
                bucket, src, srcp, dest, destp, sp->sk_state,
                sk_wmem_alloc_get(sp),
                sk_rmem_alloc_get(sp),
index b7919f901fbf76ce511313d39e638d69a18269ad..d450a2f9fc0645b7addef3fcbf2d586e89d86da7 100644 (file)
@@ -272,6 +272,10 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 
        if (addr_len < SIN6_LEN_RFC2133)
                return -EINVAL;
+
+       if (addr->sin6_family != AF_INET6)
+               return -EINVAL;
+
        addr_type = ipv6_addr_type(&addr->sin6_addr);
        if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM)
                return -EINVAL;
index 413ab0754e1fe4923c139e632444f2cfcc623d86..249394863284bcb2edcb3228183a953393df1a26 100644 (file)
@@ -204,7 +204,8 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
        else
                pmsg->outdev_name[0] = '\0';
 
-       if (entry->indev && entry->skb->dev) {
+       if (entry->indev && entry->skb->dev &&
+           entry->skb->mac_header != entry->skb->network_header) {
                pmsg->hw_type = entry->skb->dev->type;
                pmsg->hw_addrlen = dev_parse_header(entry->skb, pmsg->hw_addr);
        }
@@ -403,7 +404,8 @@ ipq_dev_drop(int ifindex)
 static inline void
 __ipq_rcv_skb(struct sk_buff *skb)
 {
-       int status, type, pid, flags, nlmsglen, skblen;
+       int status, type, pid, flags;
+       unsigned int nlmsglen, skblen;
        struct nlmsghdr *nlh;
 
        skblen = skb->len;
index c8af58b225620795af240156ae1e5b735fa78a2d..4111050a9fc524e0cd225aa81d5dfa4c4e166d06 100644 (file)
@@ -160,7 +160,7 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
 
        /* This is where we call the helper: as the packet goes out. */
        ct = nf_ct_get(skb, &ctinfo);
-       if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)
+       if (!ct || ctinfo == IP_CT_RELATED_REPLY)
                goto out;
 
        help = nfct_help(ct);
index 1df3c8b6bf4723668e6b8c43666b3e31f4583fd8..7c05e7eacbc6561744566168c4ff3c3f64fc828d 100644 (file)
@@ -177,7 +177,7 @@ icmpv6_error_message(struct net *net, struct nf_conn *tmpl,
        /* Update skb to refer to this connection */
        skb->nfct = &nf_ct_tuplehash_to_ctrack(h)->ct_general;
        skb->nfctinfo = *ctinfo;
-       return -NF_ACCEPT;
+       return NF_ACCEPT;
 }
 
 static int
index ae64984f81aa857ee1b361a9786a7524b989d3ef..cc7313b8f7eaee42ec5385f9fa9999f1227f01db 100644 (file)
@@ -1240,7 +1240,7 @@ static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
        srcp  = inet_sk(sp)->inet_num;
        seq_printf(seq,
                   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
-                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
+                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d\n",
                   i,
                   src->s6_addr32[0], src->s6_addr32[1],
                   src->s6_addr32[2], src->s6_addr32[3], srcp,
index 868366470b4af1702b81dcfa03db815b33378d00..87551ca568cd80e35671153b80acb5c6f6986fe8 100644 (file)
@@ -1644,6 +1644,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
                 * the new socket..
                 */
                if(nsk != sk) {
+                       sock_rps_save_rxhash(nsk, skb->rxhash);
                        if (tcp_child_process(sk, nsk, skb))
                                goto reset;
                        if (opt_skb)
@@ -2036,7 +2037,7 @@ static void get_openreq6(struct seq_file *seq,
 
        seq_printf(seq,
                   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
-                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
+                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n",
                   i,
                   src->s6_addr32[0], src->s6_addr32[1],
                   src->s6_addr32[2], src->s6_addr32[3],
@@ -2087,7 +2088,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
 
        seq_printf(seq,
                   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
-                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %lu %lu %u %u %d\n",
+                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %lu %lu %u %u %d\n",
                   i,
                   src->s6_addr32[0], src->s6_addr32[1],
                   src->s6_addr32[2], src->s6_addr32[3], srcp,
@@ -2129,7 +2130,7 @@ static void get_timewait6_sock(struct seq_file *seq,
 
        seq_printf(seq,
                   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
-                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
+                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n",
                   i,
                   src->s6_addr32[0], src->s6_addr32[1],
                   src->s6_addr32[2], src->s6_addr32[3], srcp,
index fc0c42a88e549edb441c62a1d13a32d0499154d6..41f8c9c08dbaf86051a16c5488b6c961f65278fc 100644 (file)
@@ -1391,7 +1391,7 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket
        srcp  = ntohs(inet->inet_sport);
        seq_printf(seq,
                   "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
-                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
+                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d\n",
                   bucket,
                   src->s6_addr32[0], src->s6_addr32[1],
                   src->s6_addr32[2], src->s6_addr32[3], srcp,
index a6770a04e3bd33fbc05c8ce157ea05520401ae99..4fe1db12d2a3761d550c17d58531a7e8de6825bb 100644 (file)
@@ -241,7 +241,7 @@ static int xfrm6_tunnel_rcv(struct sk_buff *skb)
        __be32 spi;
 
        spi = xfrm6_tunnel_spi_lookup(net, (const xfrm_address_t *)&iph->saddr);
-       return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0;
+       return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi);
 }
 
 static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
index 36477538cea8eba501f000253b433d673b8d579f..f876eed7d4aad3099869acad4670e102e1bf368e 100644 (file)
@@ -87,6 +87,8 @@ static inline void iriap_start_watchdog_timer(struct iriap_cb *self,
                         iriap_watchdog_timer_expired);
 }
 
+static struct lock_class_key irias_objects_key;
+
 /*
  * Function iriap_init (void)
  *
@@ -114,6 +116,9 @@ int __init iriap_init(void)
                return -ENOMEM;
        }
 
+       lockdep_set_class_and_name(&irias_objects->hb_spinlock, &irias_objects_key,
+                                  "irias_objects");
+
        /*
         *  Register some default services for IrLMP
         */
index a15c0152495922893cdd43b605ebb936e668d40d..7f9124914b139b062c71ccc3d526433dc9109ef4 100644 (file)
@@ -54,7 +54,7 @@
 #include <asm/atomic.h>
 #include <asm/ebcdic.h>
 #include <asm/io.h>
-#include <asm/s390_ext.h>
+#include <asm/irq.h>
 #include <asm/smp.h>
 
 /*
index d62401c2568434e7f36aac8d5a5613a30ff26281..8f92cf8116ea6b0604961c8438b15acf21fcf6f1 100644 (file)
@@ -3656,7 +3656,7 @@ static int pfkey_seq_show(struct seq_file *f, void *v)
        if (v == SEQ_START_TOKEN)
                seq_printf(f ,"sk       RefCnt Rmem   Wmem   User   Inode\n");
        else
-               seq_printf(f ,"%p %-6d %-6u %-6u %-6u %-6lu\n",
+               seq_printf(f, "%pK %-6d %-6u %-6u %-6u %-6lu\n",
                               s,
                               atomic_read(&s->sk_refcnt),
                               sk_rmem_alloc_get(s),
index b8dbae82fab8612974d603c42b4cbac3b0509165..76130134bfa6215d3cb7ffce9813f95724dc7d65 100644 (file)
@@ -258,7 +258,7 @@ static int l2tp_dfs_seq_open(struct inode *inode, struct file *file)
         */
        pd->net = get_net_ns_by_pid(current->pid);
        if (IS_ERR(pd->net)) {
-               rc = -PTR_ERR(pd->net);
+               rc = PTR_ERR(pd->net);
                goto err_free_pd;
        }
 
index 421eaa6b0c2b36cbb9a1131b78d995a248debaf0..56c24cabf26d3cb6552f157320e1e782acff16cf 100644 (file)
@@ -965,6 +965,10 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
 
        mutex_lock(&sdata->u.ibss.mtx);
 
+       sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH;
+       memset(sdata->u.ibss.bssid, 0, ETH_ALEN);
+       sdata->u.ibss.ssid_len = 0;
+
        active_ibss = ieee80211_sta_active_ibss(sdata);
 
        if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
@@ -999,8 +1003,6 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
        kfree_skb(skb);
 
        skb_queue_purge(&sdata->skb_queue);
-       memset(sdata->u.ibss.bssid, 0, ETH_ALEN);
-       sdata->u.ibss.ssid_len = 0;
 
        del_timer_sync(&sdata->u.ibss.timer);
 
index 2025af52b195647a3e83794ae090b8ca84a7cdfa..090b0ec1e05653c246973a74de8fe4c6057f261e 100644 (file)
@@ -775,9 +775,6 @@ struct ieee80211_local {
 
        int tx_headroom; /* required headroom for hardware/radiotap */
 
-       /* count for keys needing tailroom space allocation */
-       int crypto_tx_tailroom_needed_cnt;
-
        /* Tasklet and skb queue to process calls from IRQ mode. All frames
         * added to skb_queue will be processed, but frames in
         * skb_queue_unreliable may be dropped if the total length of these
index 7dfbe71dc637334d410eea7e4eef04a6b114b7d8..dee30aea9ab31eba7021812894c35d495e28ab71 100644 (file)
@@ -384,11 +384,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        int i;
        enum nl80211_channel_type orig_ct;
 
+       clear_bit(SDATA_STATE_RUNNING, &sdata->state);
+
        if (local->scan_sdata == sdata)
                ieee80211_scan_cancel(local);
 
-       clear_bit(SDATA_STATE_RUNNING, &sdata->state);
-
        /*
         * Stop TX on this interface first.
         */
@@ -1145,6 +1145,10 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
                                + IEEE80211_ENCRYPT_HEADROOM;
        ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM;
 
+       ret = dev_alloc_name(ndev, ndev->name);
+       if (ret < 0)
+               goto fail;
+
        ieee80211_assign_perm_addr(local, ndev, type);
        memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
        SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
index 31afd712930df2a7507505a26cd24f4f4e1ee2bd..f825e2f0a57e034a839f37bfafc19e12206367b9 100644 (file)
@@ -101,11 +101,6 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 
        if (!ret) {
                key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
-
-               if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-                     (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
-                       key->local->crypto_tx_tailroom_needed_cnt--;
-
                return 0;
        }
 
@@ -161,10 +156,6 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
                          key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
 
        key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
-
-       if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-             (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
-               key->local->crypto_tx_tailroom_needed_cnt++;
 }
 
 void ieee80211_key_removed(struct ieee80211_key_conf *key_conf)
@@ -403,10 +394,8 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
                ieee80211_aes_key_free(key->u.ccmp.tfm);
        if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
                ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
-       if (key->local) {
+       if (key->local)
                ieee80211_debugfs_key_remove(key);
-               key->local->crypto_tx_tailroom_needed_cnt--;
-       }
 
        kfree(key);
 }
@@ -468,8 +457,6 @@ int ieee80211_key_link(struct ieee80211_key *key,
 
        ieee80211_debugfs_key_add(key);
 
-       key->local->crypto_tx_tailroom_needed_cnt++;
-
        ret = ieee80211_key_enable_hw_accel(key);
 
        mutex_unlock(&sdata->local->key_mtx);
@@ -511,12 +498,8 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
 
        mutex_lock(&sdata->local->key_mtx);
 
-       sdata->local->crypto_tx_tailroom_needed_cnt = 0;
-
-       list_for_each_entry(key, &sdata->key_list, list) {
-               sdata->local->crypto_tx_tailroom_needed_cnt++;
+       list_for_each_entry(key, &sdata->key_list, list)
                ieee80211_key_enable_hw_accel(key);
-       }
 
        mutex_unlock(&sdata->local->key_mtx);
 }
index 0d7b08db8e564e07e953b1a501bc97a0e41a6db6..866f269183cf9a1532f317e3b9f52bc437a98213 100644 (file)
@@ -752,11 +752,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
        hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
 
-       /* mac80211 doesn't support more than 1 channel */
-       for (i = 0; i < hw->wiphy->n_iface_combinations; i++)
-               if (hw->wiphy->iface_combinations[i].num_different_channels > 1)
+       /*
+        * mac80211 doesn't support more than 1 channel, and also not more
+        * than one IBSS interface
+        */
+       for (i = 0; i < hw->wiphy->n_iface_combinations; i++) {
+               const struct ieee80211_iface_combination *c;
+               int j;
+
+               c = &hw->wiphy->iface_combinations[i];
+
+               if (c->num_different_channels > 1)
                        return -EINVAL;
 
+               for (j = 0; j < c->n_limits; j++)
+                       if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) &&
+                           c->limits[j].max > 1)
+                               return -EINVAL;
+       }
+
 #ifndef CONFIG_MAC80211_MESH
        /* mesh depends on Kconfig, but drivers should set it if they want */
        local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT);
@@ -1076,6 +1090,8 @@ static void __exit ieee80211_exit(void)
                ieee80211s_stop();
 
        ieee80211_iface_exit();
+
+       rcu_barrier();
 }
 
 
index e7c5fddb480400a8d61c08b577d093ff32b3b22b..249e733362e7b9bf4d48714800ba7da48273832d 100644 (file)
@@ -120,6 +120,7 @@ struct mesh_path {
  *     buckets
  * @mean_chain_len: maximum average length for the hash buckets' list, if it is
  *     reached, the table will grow
+ * rcu_head: RCU head to free the table
  */
 struct mesh_table {
        /* Number of buckets will be 2^N */
@@ -132,6 +133,8 @@ struct mesh_table {
        int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
        int size_order;
        int mean_chain_len;
+
+       struct rcu_head rcu_head;
 };
 
 /* Recent multicast cache */
@@ -286,10 +289,6 @@ static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
        return sdata->u.mesh.mesh_pp_id == IEEE80211_PATH_PROTOCOL_HWMP;
 }
 
-#define for_each_mesh_entry(x, p, node, i) \
-       for (i = 0; i <= x->hash_mask; i++) \
-               hlist_for_each_entry_rcu(node, p, &x->hash_buckets[i], list)
-
 void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local);
 
 void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata);
index 83ce48e3191344384939ce669a71b5e266f336bf..0d2faacc3e870c0feee42ad2d854cb1110f32ecc 100644 (file)
@@ -36,8 +36,8 @@ struct mpath_node {
        struct mesh_path *mpath;
 };
 
-static struct mesh_table *mesh_paths;
-static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */
+static struct mesh_table __rcu *mesh_paths;
+static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */
 
 int mesh_paths_generation;
 
@@ -48,17 +48,40 @@ int mesh_paths_generation;
 static DEFINE_RWLOCK(pathtbl_resize_lock);
 
 
+static inline struct mesh_table *resize_dereference_mesh_paths(void)
+{
+       return rcu_dereference_protected(mesh_paths,
+               lockdep_is_held(&pathtbl_resize_lock));
+}
+
+static inline struct mesh_table *resize_dereference_mpp_paths(void)
+{
+       return rcu_dereference_protected(mpp_paths,
+               lockdep_is_held(&pathtbl_resize_lock));
+}
+
+/*
+ * CAREFUL -- "tbl" must not be an expression,
+ * in particular not an rcu_dereference(), since
+ * it's used twice. So it is illegal to do
+ *     for_each_mesh_entry(rcu_dereference(...), ...)
+ */
+#define for_each_mesh_entry(tbl, p, node, i) \
+       for (i = 0; i <= tbl->hash_mask; i++) \
+               hlist_for_each_entry_rcu(node, p, &tbl->hash_buckets[i], list)
+
+
 static struct mesh_table *mesh_table_alloc(int size_order)
 {
        int i;
        struct mesh_table *newtbl;
 
-       newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL);
+       newtbl = kmalloc(sizeof(struct mesh_table), GFP_ATOMIC);
        if (!newtbl)
                return NULL;
 
        newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) *
-                       (1 << size_order), GFP_KERNEL);
+                       (1 << size_order), GFP_ATOMIC);
 
        if (!newtbl->hash_buckets) {
                kfree(newtbl);
@@ -66,7 +89,7 @@ static struct mesh_table *mesh_table_alloc(int size_order)
        }
 
        newtbl->hashwlock = kmalloc(sizeof(spinlock_t) *
-                       (1 << size_order), GFP_KERNEL);
+                       (1 << size_order), GFP_ATOMIC);
        if (!newtbl->hashwlock) {
                kfree(newtbl->hash_buckets);
                kfree(newtbl);
@@ -258,12 +281,13 @@ struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
  */
 struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data *sdata)
 {
+       struct mesh_table *tbl = rcu_dereference(mesh_paths);
        struct mpath_node *node;
        struct hlist_node *p;
        int i;
        int j = 0;
 
-       for_each_mesh_entry(mesh_paths, p, node, i) {
+       for_each_mesh_entry(tbl, p, node, i) {
                if (sdata && node->mpath->sdata != sdata)
                        continue;
                if (j++ == idx) {
@@ -293,6 +317,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        struct ieee80211_local *local = sdata->local;
+       struct mesh_table *tbl;
        struct mesh_path *mpath, *new_mpath;
        struct mpath_node *node, *new_node;
        struct hlist_head *bucket;
@@ -332,10 +357,12 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
        spin_lock_init(&new_mpath->state_lock);
        init_timer(&new_mpath->timer);
 
-       hash_idx = mesh_table_hash(dst, sdata, mesh_paths);
-       bucket = &mesh_paths->hash_buckets[hash_idx];
+       tbl = resize_dereference_mesh_paths();
+
+       hash_idx = mesh_table_hash(dst, sdata, tbl);
+       bucket = &tbl->hash_buckets[hash_idx];
 
-       spin_lock_bh(&mesh_paths->hashwlock[hash_idx]);
+       spin_lock_bh(&tbl->hashwlock[hash_idx]);
 
        err = -EEXIST;
        hlist_for_each_entry(node, n, bucket, list) {
@@ -345,13 +372,13 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
        }
 
        hlist_add_head_rcu(&new_node->list, bucket);
-       if (atomic_inc_return(&mesh_paths->entries) >=
-               mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1))
+       if (atomic_inc_return(&tbl->entries) >=
+           tbl->mean_chain_len * (tbl->hash_mask + 1))
                grow = 1;
 
        mesh_paths_generation++;
 
-       spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]);
+       spin_unlock_bh(&tbl->hashwlock[hash_idx]);
        read_unlock_bh(&pathtbl_resize_lock);
        if (grow) {
                set_bit(MESH_WORK_GROW_MPATH_TABLE,  &ifmsh->wrkq_flags);
@@ -360,7 +387,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
        return 0;
 
 err_exists:
-       spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]);
+       spin_unlock_bh(&tbl->hashwlock[hash_idx]);
        read_unlock_bh(&pathtbl_resize_lock);
        kfree(new_node);
 err_node_alloc:
@@ -370,58 +397,59 @@ err_path_alloc:
        return err;
 }
 
+static void mesh_table_free_rcu(struct rcu_head *rcu)
+{
+       struct mesh_table *tbl = container_of(rcu, struct mesh_table, rcu_head);
+
+       mesh_table_free(tbl, false);
+}
+
 void mesh_mpath_table_grow(void)
 {
        struct mesh_table *oldtbl, *newtbl;
 
-       rcu_read_lock();
-       newtbl = mesh_table_alloc(rcu_dereference(mesh_paths)->size_order + 1);
-       if (!newtbl)
-               return;
        write_lock_bh(&pathtbl_resize_lock);
-       oldtbl = mesh_paths;
-       if (mesh_table_grow(mesh_paths, newtbl) < 0) {
-               rcu_read_unlock();
+       oldtbl = resize_dereference_mesh_paths();
+       newtbl = mesh_table_alloc(oldtbl->size_order + 1);
+       if (!newtbl)
+               goto out;
+       if (mesh_table_grow(oldtbl, newtbl) < 0) {
                __mesh_table_free(newtbl);
-               write_unlock_bh(&pathtbl_resize_lock);
-               return;
+               goto out;
        }
-       rcu_read_unlock();
        rcu_assign_pointer(mesh_paths, newtbl);
-       write_unlock_bh(&pathtbl_resize_lock);
 
-       synchronize_rcu();
-       mesh_table_free(oldtbl, false);
+       call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu);
+
+ out:
+       write_unlock_bh(&pathtbl_resize_lock);
 }
 
 void mesh_mpp_table_grow(void)
 {
        struct mesh_table *oldtbl, *newtbl;
 
-       rcu_read_lock();
-       newtbl = mesh_table_alloc(rcu_dereference(mpp_paths)->size_order + 1);
-       if (!newtbl)
-               return;
        write_lock_bh(&pathtbl_resize_lock);
-       oldtbl = mpp_paths;
-       if (mesh_table_grow(mpp_paths, newtbl) < 0) {
-               rcu_read_unlock();
+       oldtbl = resize_dereference_mpp_paths();
+       newtbl = mesh_table_alloc(oldtbl->size_order + 1);
+       if (!newtbl)
+               goto out;
+       if (mesh_table_grow(oldtbl, newtbl) < 0) {
                __mesh_table_free(newtbl);
-               write_unlock_bh(&pathtbl_resize_lock);
-               return;
+               goto out;
        }
-       rcu_read_unlock();
        rcu_assign_pointer(mpp_paths, newtbl);
-       write_unlock_bh(&pathtbl_resize_lock);
+       call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu);
 
-       synchronize_rcu();
-       mesh_table_free(oldtbl, false);
+ out:
+       write_unlock_bh(&pathtbl_resize_lock);
 }
 
 int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        struct ieee80211_local *local = sdata->local;
+       struct mesh_table *tbl;
        struct mesh_path *mpath, *new_mpath;
        struct mpath_node *node, *new_node;
        struct hlist_head *bucket;
@@ -456,10 +484,12 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
        new_mpath->exp_time = jiffies;
        spin_lock_init(&new_mpath->state_lock);
 
-       hash_idx = mesh_table_hash(dst, sdata, mpp_paths);
-       bucket = &mpp_paths->hash_buckets[hash_idx];
+       tbl = resize_dereference_mpp_paths();
 
-       spin_lock_bh(&mpp_paths->hashwlock[hash_idx]);
+       hash_idx = mesh_table_hash(dst, sdata, tbl);
+       bucket = &tbl->hash_buckets[hash_idx];
+
+       spin_lock_bh(&tbl->hashwlock[hash_idx]);
 
        err = -EEXIST;
        hlist_for_each_entry(node, n, bucket, list) {
@@ -469,11 +499,11 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
        }
 
        hlist_add_head_rcu(&new_node->list, bucket);
-       if (atomic_inc_return(&mpp_paths->entries) >=
-               mpp_paths->mean_chain_len * (mpp_paths->hash_mask + 1))
+       if (atomic_inc_return(&tbl->entries) >=
+           tbl->mean_chain_len * (tbl->hash_mask + 1))
                grow = 1;
 
-       spin_unlock_bh(&mpp_paths->hashwlock[hash_idx]);
+       spin_unlock_bh(&tbl->hashwlock[hash_idx]);
        read_unlock_bh(&pathtbl_resize_lock);
        if (grow) {
                set_bit(MESH_WORK_GROW_MPP_TABLE,  &ifmsh->wrkq_flags);
@@ -482,7 +512,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
        return 0;
 
 err_exists:
-       spin_unlock_bh(&mpp_paths->hashwlock[hash_idx]);
+       spin_unlock_bh(&tbl->hashwlock[hash_idx]);
        read_unlock_bh(&pathtbl_resize_lock);
        kfree(new_node);
 err_node_alloc:
@@ -502,6 +532,7 @@ err_path_alloc:
  */
 void mesh_plink_broken(struct sta_info *sta)
 {
+       struct mesh_table *tbl;
        static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
        struct mesh_path *mpath;
        struct mpath_node *node;
@@ -510,10 +541,11 @@ void mesh_plink_broken(struct sta_info *sta)
        int i;
 
        rcu_read_lock();
-       for_each_mesh_entry(mesh_paths, p, node, i) {
+       tbl = rcu_dereference(mesh_paths);
+       for_each_mesh_entry(tbl, p, node, i) {
                mpath = node->mpath;
                spin_lock_bh(&mpath->state_lock);
-               if (mpath->next_hop == sta &&
+               if (rcu_dereference(mpath->next_hop) == sta &&
                    mpath->flags & MESH_PATH_ACTIVE &&
                    !(mpath->flags & MESH_PATH_FIXED)) {
                        mpath->flags &= ~MESH_PATH_ACTIVE;
@@ -542,30 +574,38 @@ void mesh_plink_broken(struct sta_info *sta)
  */
 void mesh_path_flush_by_nexthop(struct sta_info *sta)
 {
+       struct mesh_table *tbl;
        struct mesh_path *mpath;
        struct mpath_node *node;
        struct hlist_node *p;
        int i;
 
-       for_each_mesh_entry(mesh_paths, p, node, i) {
+       rcu_read_lock();
+       tbl = rcu_dereference(mesh_paths);
+       for_each_mesh_entry(tbl, p, node, i) {
                mpath = node->mpath;
-               if (mpath->next_hop == sta)
+               if (rcu_dereference(mpath->next_hop) == sta)
                        mesh_path_del(mpath->dst, mpath->sdata);
        }
+       rcu_read_unlock();
 }
 
 void mesh_path_flush(struct ieee80211_sub_if_data *sdata)
 {
+       struct mesh_table *tbl;
        struct mesh_path *mpath;
        struct mpath_node *node;
        struct hlist_node *p;
        int i;
 
-       for_each_mesh_entry(mesh_paths, p, node, i) {
+       rcu_read_lock();
+       tbl = rcu_dereference(mesh_paths);
+       for_each_mesh_entry(tbl, p, node, i) {
                mpath = node->mpath;
                if (mpath->sdata == sdata)
                        mesh_path_del(mpath->dst, mpath->sdata);
        }
+       rcu_read_unlock();
 }
 
 static void mesh_path_node_reclaim(struct rcu_head *rp)
@@ -589,6 +629,7 @@ static void mesh_path_node_reclaim(struct rcu_head *rp)
  */
 int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
 {
+       struct mesh_table *tbl;
        struct mesh_path *mpath;
        struct mpath_node *node;
        struct hlist_head *bucket;
@@ -597,19 +638,20 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
        int err = 0;
 
        read_lock_bh(&pathtbl_resize_lock);
-       hash_idx = mesh_table_hash(addr, sdata, mesh_paths);
-       bucket = &mesh_paths->hash_buckets[hash_idx];
+       tbl = resize_dereference_mesh_paths();
+       hash_idx = mesh_table_hash(addr, sdata, tbl);
+       bucket = &tbl->hash_buckets[hash_idx];
 
-       spin_lock_bh(&mesh_paths->hashwlock[hash_idx]);
+       spin_lock_bh(&tbl->hashwlock[hash_idx]);
        hlist_for_each_entry(node, n, bucket, list) {
                mpath = node->mpath;
                if (mpath->sdata == sdata &&
-                               memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
+                   memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
                        spin_lock_bh(&mpath->state_lock);
                        mpath->flags |= MESH_PATH_RESOLVING;
                        hlist_del_rcu(&node->list);
                        call_rcu(&node->rcu, mesh_path_node_reclaim);
-                       atomic_dec(&mesh_paths->entries);
+                       atomic_dec(&tbl->entries);
                        spin_unlock_bh(&mpath->state_lock);
                        goto enddel;
                }
@@ -618,7 +660,7 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
        err = -ENXIO;
 enddel:
        mesh_paths_generation++;
-       spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]);
+       spin_unlock_bh(&tbl->hashwlock[hash_idx]);
        read_unlock_bh(&pathtbl_resize_lock);
        return err;
 }
@@ -719,8 +761,10 @@ static void mesh_path_node_free(struct hlist_node *p, bool free_leafs)
        struct mpath_node *node = hlist_entry(p, struct mpath_node, list);
        mpath = node->mpath;
        hlist_del_rcu(p);
-       if (free_leafs)
+       if (free_leafs) {
+               del_timer_sync(&mpath->timer);
                kfree(mpath);
+       }
        kfree(node);
 }
 
@@ -745,52 +789,60 @@ static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
 
 int mesh_pathtbl_init(void)
 {
-       mesh_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
-       if (!mesh_paths)
+       struct mesh_table *tbl_path, *tbl_mpp;
+
+       tbl_path = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
+       if (!tbl_path)
                return -ENOMEM;
-       mesh_paths->free_node = &mesh_path_node_free;
-       mesh_paths->copy_node = &mesh_path_node_copy;
-       mesh_paths->mean_chain_len = MEAN_CHAIN_LEN;
+       tbl_path->free_node = &mesh_path_node_free;
+       tbl_path->copy_node = &mesh_path_node_copy;
+       tbl_path->mean_chain_len = MEAN_CHAIN_LEN;
 
-       mpp_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
-       if (!mpp_paths) {
-               mesh_table_free(mesh_paths, true);
+       tbl_mpp = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
+       if (!tbl_mpp) {
+               mesh_table_free(tbl_path, true);
                return -ENOMEM;
        }
-       mpp_paths->free_node = &mesh_path_node_free;
-       mpp_paths->copy_node = &mesh_path_node_copy;
-       mpp_paths->mean_chain_len = MEAN_CHAIN_LEN;
+       tbl_mpp->free_node = &mesh_path_node_free;
+       tbl_mpp->copy_node = &mesh_path_node_copy;
+       tbl_mpp->mean_chain_len = MEAN_CHAIN_LEN;
+
+       /* Need no locking since this is during init */
+       RCU_INIT_POINTER(mesh_paths, tbl_path);
+       RCU_INIT_POINTER(mpp_paths, tbl_mpp);
 
        return 0;
 }
 
 void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
 {
+       struct mesh_table *tbl;
        struct mesh_path *mpath;
        struct mpath_node *node;
        struct hlist_node *p;
        int i;
 
-       read_lock_bh(&pathtbl_resize_lock);
-       for_each_mesh_entry(mesh_paths, p, node, i) {
+       rcu_read_lock();
+       tbl = rcu_dereference(mesh_paths);
+       for_each_mesh_entry(tbl, p, node, i) {
                if (node->mpath->sdata != sdata)
                        continue;
                mpath = node->mpath;
                spin_lock_bh(&mpath->state_lock);
                if ((!(mpath->flags & MESH_PATH_RESOLVING)) &&
                    (!(mpath->flags & MESH_PATH_FIXED)) &&
-                       time_after(jiffies,
-                        mpath->exp_time + MESH_PATH_EXPIRE)) {
+                    time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) {
                        spin_unlock_bh(&mpath->state_lock);
                        mesh_path_del(mpath->dst, mpath->sdata);
                } else
                        spin_unlock_bh(&mpath->state_lock);
        }
-       read_unlock_bh(&pathtbl_resize_lock);
+       rcu_read_unlock();
 }
 
 void mesh_pathtbl_unregister(void)
 {
-       mesh_table_free(mesh_paths, true);
-       mesh_table_free(mpp_paths, true);
+       /* no need for locking during exit path */
+       mesh_table_free(rcu_dereference_raw(mesh_paths), true);
+       mesh_table_free(rcu_dereference_raw(mpp_paths), true);
 }
index 4f6b2675e41d43fd8335e35094875b41774d9ca8..d595265d6c22c4a8e618daa17111b28da495836b 100644 (file)
@@ -1089,6 +1089,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
                local->hw.conf.flags &= ~IEEE80211_CONF_PS;
                config_changed |= IEEE80211_CONF_CHANGE_PS;
        }
+       local->ps_sdata = NULL;
 
        ieee80211_hw_config(local, config_changed);
 
index d20046b5d8f4953bb4ae4007e927ccee1505985a..58ffa7d069c791c7d2c2c681861212d806260956 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
 #include <linux/pm_qos_params.h>
-#include <linux/slab.h>
 #include <net/sch_generic.h>
 #include <linux/slab.h>
 #include <net/mac80211.h>
@@ -719,6 +718,11 @@ void ieee80211_scan_work(struct work_struct *work)
         * without scheduling a new work
         */
        do {
+               if (!ieee80211_sdata_running(sdata)) {
+                       aborted = true;
+                       goto out_complete;
+               }
+
                switch (local->next_scan_state) {
                case SCAN_DECISION:
                        /* if no more bands/channels left, complete scan */
index 64e0f7587e6d6f09e11a8029ef7a995e406ff60d..3104c844b544c5465ef5ba1e7efcff05ca920501 100644 (file)
@@ -1480,7 +1480,12 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
 {
        int tail_need = 0;
 
-       if (may_encrypt && local->crypto_tx_tailroom_needed_cnt) {
+       /*
+        * This could be optimised, devices that do full hardware
+        * crypto (including TKIP MMIC) need no tailroom... But we
+        * have no drivers for such devices currently.
+        */
+       if (may_encrypt) {
                tail_need = IEEE80211_ENCRYPT_TAILROOM;
                tail_need -= skb_tailroom(skb);
                tail_need = max_t(int, tail_need, 0);
index 72d1ac611fdc8e70124c6fca29686ffa416e9cd3..42aa64b6b0b1b6c7ae87dbe7831776ea2d345366 100644 (file)
@@ -767,7 +767,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
        if (!attr[IPSET_ATTR_SETNAME]) {
                for (i = 0; i < ip_set_max; i++) {
                        if (ip_set_list[i] != NULL && ip_set_list[i]->ref) {
-                               ret = IPSET_ERR_BUSY;
+                               ret = -IPSET_ERR_BUSY;
                                goto out;
                        }
                }
@@ -815,7 +815,7 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb,
        ip_set_id_t i;
 
        if (unlikely(protocol_failed(attr)))
-               return -EPROTO;
+               return -IPSET_ERR_PROTOCOL;
 
        if (!attr[IPSET_ATTR_SETNAME]) {
                for (i = 0; i < ip_set_max; i++)
index 4743e5402522fb6793c2022ade4bed020b240295..565a7c5b8818a22038f9a4f1b87c03a0cf8c31ad 100644 (file)
@@ -146,8 +146,9 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
-       struct hash_ipportnet4_elem data =
-               { .cidr = h->nets[0].cidr || HOST_MASK };
+       struct hash_ipportnet4_elem data = {
+               .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+       };
 
        if (data.cidr == 0)
                return -EINVAL;
@@ -394,8 +395,9 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
-       struct hash_ipportnet6_elem data =
-               { .cidr = h->nets[0].cidr || HOST_MASK };
+       struct hash_ipportnet6_elem data = {
+               .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+       };
 
        if (data.cidr == 0)
                return -EINVAL;
index c4db202b7da4bcaefc22e9c637e3a242233c5c9e..2aeeabcd5a211af76b3dd4c6c5eabda69ea97705 100644 (file)
@@ -131,7 +131,9 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
-       struct hash_net4_elem data = { .cidr = h->nets[0].cidr || HOST_MASK };
+       struct hash_net4_elem data = {
+               .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+       };
 
        if (data.cidr == 0)
                return -EINVAL;
@@ -296,7 +298,9 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
-       struct hash_net6_elem data = { .cidr = h->nets[0].cidr || HOST_MASK };
+       struct hash_net6_elem data = {
+               .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+       };
 
        if (data.cidr == 0)
                return -EINVAL;
index d2a40362dd3aadb6510ff1603a42e132eeeb5c7a..e50d9bb8820b24c7bb4bda72429eddd4ce746dfd 100644 (file)
@@ -144,7 +144,8 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_netport4_elem data = {
-               .cidr = h->nets[0].cidr || HOST_MASK };
+               .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+       };
 
        if (data.cidr == 0)
                return -EINVAL;
@@ -357,7 +358,8 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_netport6_elem data = {
-               .cidr = h->nets[0].cidr || HOST_MASK };
+               .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+       };
 
        if (data.cidr == 0)
                return -EINVAL;
index bf28ac2fc99b7cf164d82417e6248049787ff923..782db275ac53591eeae96b750f5bbf5cc14b063f 100644 (file)
@@ -776,8 +776,16 @@ static void ip_vs_conn_expire(unsigned long data)
                if (cp->control)
                        ip_vs_control_del(cp);
 
-               if (cp->flags & IP_VS_CONN_F_NFCT)
+               if (cp->flags & IP_VS_CONN_F_NFCT) {
                        ip_vs_conn_drop_conntrack(cp);
+                       /* Do not access conntracks during subsys cleanup
+                        * because nf_conntrack_find_get can not be used after
+                        * conntrack cleanup for the net.
+                        */
+                       smp_rmb();
+                       if (ipvs->enable)
+                               ip_vs_conn_drop_conntrack(cp);
+               }
 
                ip_vs_pe_put(cp->pe);
                kfree(cp->pe_data);
index bfa808f4da137fbe4d112155db205633a3e042a8..24c28d238dcb62f7dc148648a35e8a05b7278fbc 100644 (file)
@@ -1772,7 +1772,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
                .owner          = THIS_MODULE,
                .pf             = PF_INET,
                .hooknum        = NF_INET_LOCAL_IN,
-               .priority       = 99,
+               .priority       = NF_IP_PRI_NAT_SRC - 2,
        },
        /* After packet filtering, forward packet through VS/DR, VS/TUN,
         * or VS/NAT(change destination), so that filtering rules can be
@@ -1782,7 +1782,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
                .owner          = THIS_MODULE,
                .pf             = PF_INET,
                .hooknum        = NF_INET_LOCAL_IN,
-               .priority       = 101,
+               .priority       = NF_IP_PRI_NAT_SRC - 1,
        },
        /* Before ip_vs_in, change source only for VS/NAT */
        {
@@ -1790,7 +1790,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
                .owner          = THIS_MODULE,
                .pf             = PF_INET,
                .hooknum        = NF_INET_LOCAL_OUT,
-               .priority       = -99,
+               .priority       = NF_IP_PRI_NAT_DST + 1,
        },
        /* After mangle, schedule and forward local requests */
        {
@@ -1798,7 +1798,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
                .owner          = THIS_MODULE,
                .pf             = PF_INET,
                .hooknum        = NF_INET_LOCAL_OUT,
-               .priority       = -98,
+               .priority       = NF_IP_PRI_NAT_DST + 2,
        },
        /* After packet filtering (but before ip_vs_out_icmp), catch icmp
         * destined for 0.0.0.0/0, which is for incoming IPVS connections */
@@ -1824,7 +1824,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
                .owner          = THIS_MODULE,
                .pf             = PF_INET6,
                .hooknum        = NF_INET_LOCAL_IN,
-               .priority       = 99,
+               .priority       = NF_IP6_PRI_NAT_SRC - 2,
        },
        /* After packet filtering, forward packet through VS/DR, VS/TUN,
         * or VS/NAT(change destination), so that filtering rules can be
@@ -1834,7 +1834,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
                .owner          = THIS_MODULE,
                .pf             = PF_INET6,
                .hooknum        = NF_INET_LOCAL_IN,
-               .priority       = 101,
+               .priority       = NF_IP6_PRI_NAT_SRC - 1,
        },
        /* Before ip_vs_in, change source only for VS/NAT */
        {
@@ -1842,7 +1842,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
                .owner          = THIS_MODULE,
                .pf             = PF_INET,
                .hooknum        = NF_INET_LOCAL_OUT,
-               .priority       = -99,
+               .priority       = NF_IP6_PRI_NAT_DST + 1,
        },
        /* After mangle, schedule and forward local requests */
        {
@@ -1850,7 +1850,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
                .owner          = THIS_MODULE,
                .pf             = PF_INET6,
                .hooknum        = NF_INET_LOCAL_OUT,
-               .priority       = -98,
+               .priority       = NF_IP6_PRI_NAT_DST + 2,
        },
        /* After packet filtering (but before ip_vs_out_icmp), catch icmp
         * destined for 0.0.0.0/0, which is for incoming IPVS connections */
@@ -1945,6 +1945,7 @@ static void __net_exit __ip_vs_dev_cleanup(struct net *net)
 {
        EnterFunction(2);
        net_ipvs(net)->enable = 0;      /* Disable packet reception */
+       smp_wmb();
        __ip_vs_sync_cleanup(net);
        LeaveFunction(2);
 }
index 6b5dd6ddaae999b7153e68506be8cd26b59ceed6..af63553fa332e06bf0562a6f1630e33e30ca889c 100644 (file)
@@ -411,25 +411,35 @@ static struct ip_vs_app ip_vs_ftp = {
 static int __net_init __ip_vs_ftp_init(struct net *net)
 {
        int i, ret;
-       struct ip_vs_app *app = &ip_vs_ftp;
+       struct ip_vs_app *app;
+       struct netns_ipvs *ipvs = net_ipvs(net);
+
+       app = kmemdup(&ip_vs_ftp, sizeof(struct ip_vs_app), GFP_KERNEL);
+       if (!app)
+               return -ENOMEM;
+       INIT_LIST_HEAD(&app->a_list);
+       INIT_LIST_HEAD(&app->incs_list);
+       ipvs->ftp_app = app;
 
        ret = register_ip_vs_app(net, app);
        if (ret)
-               return ret;
+               goto err_exit;
 
        for (i=0; i<IP_VS_APP_MAX_PORTS; i++) {
                if (!ports[i])
                        continue;
                ret = register_ip_vs_app_inc(net, app, app->protocol, ports[i]);
                if (ret)
-                       break;
+                       goto err_unreg;
                pr_info("%s: loaded support on port[%d] = %d\n",
                        app->name, i, ports[i]);
        }
+       return 0;
 
-       if (ret)
-               unregister_ip_vs_app(net, app);
-
+err_unreg:
+       unregister_ip_vs_app(net, app);
+err_exit:
+       kfree(ipvs->ftp_app);
        return ret;
 }
 /*
@@ -437,9 +447,10 @@ static int __net_init __ip_vs_ftp_init(struct net *net)
  */
 static void __ip_vs_ftp_exit(struct net *net)
 {
-       struct ip_vs_app *app = &ip_vs_ftp;
+       struct netns_ipvs *ipvs = net_ipvs(net);
 
-       unregister_ip_vs_app(net, app);
+       unregister_ip_vs_app(net, ipvs->ftp_app);
+       kfree(ipvs->ftp_app);
 }
 
 static struct pernet_operations ip_vs_ftp_ops = {
index 2e1c11f784193b4b319b37f246cc8f7d6fded26b..f7af8b866017040600fb842d9441ff4fa9912fc7 100644 (file)
@@ -850,7 +850,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
 
        /* It exists; we have (non-exclusive) reference. */
        if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) {
-               *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
+               *ctinfo = IP_CT_ESTABLISHED_REPLY;
                /* Please set reply bit if this packet OK */
                *set_reply = 1;
        } else {
@@ -922,6 +922,9 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
                        ret = -ret;
                        goto out;
                }
+               /* ICMP[v6] protocol trackers may assign one conntrack. */
+               if (skb->nfct)
+                       goto out;
        }
 
        ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum,
@@ -1143,7 +1146,7 @@ static void nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb)
        /* This ICMP is in reverse direction to the packet which caused it */
        ct = nf_ct_get(skb, &ctinfo);
        if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
-               ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY;
+               ctinfo = IP_CT_RELATED_REPLY;
        else
                ctinfo = IP_CT_RELATED;
 
index e17cb7c7dd8fda61efabf12d8cefb45c4c8d4a78..6f5801eac99923eaaa66e3dd8572678df0ac8ceb 100644 (file)
@@ -368,7 +368,7 @@ static int help(struct sk_buff *skb,
 
        /* Until there's been traffic both ways, don't look in packets. */
        if (ctinfo != IP_CT_ESTABLISHED &&
-           ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
+           ctinfo != IP_CT_ESTABLISHED_REPLY) {
                pr_debug("ftp: Conntrackinfo = %u\n", ctinfo);
                return NF_ACCEPT;
        }
index 18b2ce5c8ced1c82f5f4e3f41af1ed1e659079f9..f03c2d4539f6b8517530c899b2bc2419e4f80f88 100644 (file)
@@ -571,10 +571,9 @@ static int h245_help(struct sk_buff *skb, unsigned int protoff,
        int ret;
 
        /* Until there's been traffic both ways, don't look in packets. */
-       if (ctinfo != IP_CT_ESTABLISHED &&
-           ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
+       if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED_REPLY)
                return NF_ACCEPT;
-       }
+
        pr_debug("nf_ct_h245: skblen = %u\n", skb->len);
 
        spin_lock_bh(&nf_h323_lock);
@@ -1125,10 +1124,9 @@ static int q931_help(struct sk_buff *skb, unsigned int protoff,
        int ret;
 
        /* Until there's been traffic both ways, don't look in packets. */
-       if (ctinfo != IP_CT_ESTABLISHED &&
-           ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
+       if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED_REPLY)
                return NF_ACCEPT;
-       }
+
        pr_debug("nf_ct_q931: skblen = %u\n", skb->len);
 
        spin_lock_bh(&nf_h323_lock);
index b394aa318776447d243a2c95ed0aa0c86a754f4d..4f9390b98697e55ec00cd81c9c6d327a43e908d7 100644 (file)
@@ -125,8 +125,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
                return NF_ACCEPT;
 
        /* Until there's been traffic both ways, don't look in packets. */
-       if (ctinfo != IP_CT_ESTABLISHED &&
-           ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY)
+       if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED_REPLY)
                return NF_ACCEPT;
 
        /* Not a full tcp header? */
index 088944824e135f53c769477aa201888cd343e398..2fd4565144defa5221bef7e458253de3d7df787f 100644 (file)
@@ -519,8 +519,7 @@ conntrack_pptp_help(struct sk_buff *skb, unsigned int protoff,
        u_int16_t msg;
 
        /* don't do any tracking before tcp handshake complete */
-       if (ctinfo != IP_CT_ESTABLISHED &&
-           ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY)
+       if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED_REPLY)
                return NF_ACCEPT;
 
        nexthdr_off = protoff;
index d9e27734b2a223adab2f73b199431df97e022b70..8501823b3f9b0f4af53b1392e465bb0215dee11d 100644 (file)
@@ -78,7 +78,7 @@ static int help(struct sk_buff *skb,
        ct_sane_info = &nfct_help(ct)->help.ct_sane_info;
        /* Until there's been traffic both ways, don't look in packets. */
        if (ctinfo != IP_CT_ESTABLISHED &&
-           ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY)
+           ctinfo != IP_CT_ESTABLISHED_REPLY)
                return NF_ACCEPT;
 
        /* Not a full tcp header? */
index cb5a285817827a0ad036adba9ea08a34a6147dff..93faf6a3a6379d5f8c4c9e52fcaf91cebdfabf66 100644 (file)
@@ -1423,7 +1423,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
        typeof(nf_nat_sip_seq_adjust_hook) nf_nat_sip_seq_adjust;
 
        if (ctinfo != IP_CT_ESTABLISHED &&
-           ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY)
+           ctinfo != IP_CT_ESTABLISHED_REPLY)
                return NF_ACCEPT;
 
        /* No Data ? */
index e0ee010935e7008a8730b2c87a2c9c689226fb8a..2e7ccbb43ddb563b7491eafe197ec0e91d8c4b4b 100644 (file)
@@ -456,7 +456,8 @@ __build_packet_message(struct nfulnl_instance *inst,
        if (skb->mark)
                NLA_PUT_BE32(inst->skb, NFULA_MARK, htonl(skb->mark));
 
-       if (indev && skb->dev) {
+       if (indev && skb->dev &&
+           skb->mac_header != skb->network_header) {
                struct nfulnl_msg_packet_hw phw;
                int len = dev_parse_header(skb, phw.hw_addr);
                if (len > 0) {
index b83123f12b42e30612481796bc6c9a4d3bacab60..fdd2fafe0a14ed8810181aae57168f841d5b3f1e 100644 (file)
@@ -335,7 +335,8 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
        if (entskb->mark)
                NLA_PUT_BE32(skb, NFQA_MARK, htonl(entskb->mark));
 
-       if (indev && entskb->dev) {
+       if (indev && entskb->dev &&
+           entskb->mac_header != entskb->network_header) {
                struct nfqnl_msg_packet_hw phw;
                int len = dev_parse_header(entskb, phw.hw_addr);
                if (len) {
index 9cc46356b5773058c0554931bc84866a14113f75..fe39f7e913dff490e948ca47b1ce6c14844013d6 100644 (file)
@@ -143,9 +143,9 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
        ct = nf_ct_get(skb, &ctinfo);
        if (ct && !nf_ct_is_untracked(ct) &&
            ((iph->protocol != IPPROTO_ICMP &&
-             ctinfo == IP_CT_IS_REPLY + IP_CT_ESTABLISHED) ||
+             ctinfo == IP_CT_ESTABLISHED_REPLY) ||
             (iph->protocol == IPPROTO_ICMP &&
-             ctinfo == IP_CT_IS_REPLY + IP_CT_RELATED)) &&
+             ctinfo == IP_CT_RELATED_REPLY)) &&
            (ct->status & IPS_SRC_NAT_DONE)) {
 
                daddr = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
index 5fe4f3b04ed37e8d0cc46d456804aef6044c3150..6ef64adf7362a421240c28e5196407ce5729f1dd 100644 (file)
@@ -1985,7 +1985,7 @@ static int netlink_seq_show(struct seq_file *seq, void *v)
                struct sock *s = v;
                struct netlink_sock *nlk = nlk_sk(s);
 
-               seq_printf(seq, "%p %-3d %-6d %08x %-8d %-8d %p %-8d %-8d %-8lu\n",
+               seq_printf(seq, "%pK %-3d %-6d %08x %-8d %-8d %pK %-8d %-8d %-8lu\n",
                           s,
                           s->sk_protocol,
                           nlk->pid,
index 549527bca87a9a6b9bc323e19834aae5cf03d647..c0c3cda19712d3a5a76307f5c85aefc98dc94957 100644 (file)
@@ -798,7 +798,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
                        getnstimeofday(&ts);
                h.h2->tp_sec = ts.tv_sec;
                h.h2->tp_nsec = ts.tv_nsec;
-               h.h2->tp_vlan_tci = vlan_tx_tag_get(skb);
+               if (vlan_tx_tag_present(skb)) {
+                       h.h2->tp_vlan_tci = vlan_tx_tag_get(skb);
+                       status |= TP_STATUS_VLAN_VALID;
+               } else {
+                       h.h2->tp_vlan_tci = 0;
+               }
+               h.h2->tp_padding = 0;
                hdrlen = sizeof(*h.h2);
                break;
        default:
@@ -1725,8 +1731,13 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
                aux.tp_snaplen = skb->len;
                aux.tp_mac = 0;
                aux.tp_net = skb_network_offset(skb);
-               aux.tp_vlan_tci = vlan_tx_tag_get(skb);
-
+               if (vlan_tx_tag_present(skb)) {
+                       aux.tp_vlan_tci = vlan_tx_tag_get(skb);
+                       aux.tp_status |= TP_STATUS_VLAN_VALID;
+               } else {
+                       aux.tp_vlan_tci = 0;
+               }
+               aux.tp_padding = 0;
                put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux);
        }
 
@@ -2706,7 +2717,7 @@ static int packet_seq_show(struct seq_file *seq, void *v)
                const struct packet_sock *po = pkt_sk(s);
 
                seq_printf(seq,
-                          "%p %-6d %-4d %04x   %-5d %1d %-6u %-6u %-6lu\n",
+                          "%pK %-6d %-4d %04x   %-5d %1d %-6u %-6u %-6lu\n",
                           s,
                           atomic_read(&s->sk_refcnt),
                           s->sk_type,
index 8c5bfcef92cb1707d25fa209e9a461f2654b6939..ab07711cf2f40e161cd0602678ce3b4555ab68b3 100644 (file)
@@ -607,7 +607,7 @@ static int pn_sock_seq_show(struct seq_file *seq, void *v)
                struct pn_sock *pn = pn_sk(sk);
 
                seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu "
-                       "%d %p %d%n",
+                       "%d %pK %d%n",
                        sk->sk_protocol, pn->sobject, pn->dobject,
                        pn->resource, sk->sk_state,
                        sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
index cce19f95c62467471bcc4b752b02b1d6205b14f2..3b83086bcc3045a2231dab3d84753dd0af7bed51 100644 (file)
@@ -325,7 +325,7 @@ static int rds_ib_laddr_check(__be32 addr)
        /* Create a CMA ID and try to bind it. This catches both
         * IB and iWARP capable NICs.
         */
-       cm_id = rdma_create_id(NULL, NULL, RDMA_PS_TCP);
+       cm_id = rdma_create_id(NULL, NULL, RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(cm_id))
                return PTR_ERR(cm_id);
 
index ee369d201a65891b8f8e3b562bf738067665df2f..fd453dd5124bed89d16fca1a8d198275d64d7053 100644 (file)
@@ -587,7 +587,7 @@ int rds_ib_conn_connect(struct rds_connection *conn)
        /* XXX I wonder what affect the port space has */
        /* delegate cm event handler to rdma_transport */
        ic->i_cm_id = rdma_create_id(rds_rdma_cm_event_handler, conn,
-                                    RDMA_PS_TCP);
+                                    RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(ic->i_cm_id)) {
                ret = PTR_ERR(ic->i_cm_id);
                ic->i_cm_id = NULL;
index 5a9676fe594f412215e75c2a4dc44fe3e599d58f..f7474844f096e50b9d340055c32c9a81f9a5c96a 100644 (file)
@@ -226,7 +226,7 @@ static int rds_iw_laddr_check(__be32 addr)
        /* Create a CMA ID and try to bind it. This catches both
         * IB and iWARP capable NICs.
         */
-       cm_id = rdma_create_id(NULL, NULL, RDMA_PS_TCP);
+       cm_id = rdma_create_id(NULL, NULL, RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(cm_id))
                return PTR_ERR(cm_id);
 
index 3a60a15d1b4a96deb7bd5636e8cab8244e64902e..c12db66f24c738fb83d1f7999b1784fd4ad807fd 100644 (file)
@@ -522,7 +522,7 @@ int rds_iw_conn_connect(struct rds_connection *conn)
        /* XXX I wonder what affect the port space has */
        /* delegate cm event handler to rdma_transport */
        ic->i_cm_id = rdma_create_id(rds_rdma_cm_event_handler, conn,
-                                    RDMA_PS_TCP);
+                                    RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(ic->i_cm_id)) {
                ret = PTR_ERR(ic->i_cm_id);
                ic->i_cm_id = NULL;
index 4195a0539829a85ebc2485d060172493a4817fe7..f8760e1b6688b4d68247e1f0f5a45a11f55702f1 100644 (file)
@@ -158,7 +158,8 @@ static int rds_rdma_listen_init(void)
        struct rdma_cm_id *cm_id;
        int ret;
 
-       cm_id = rdma_create_id(rds_rdma_cm_event_handler, NULL, RDMA_PS_TCP);
+       cm_id = rdma_create_id(rds_rdma_cm_event_handler, NULL, RDMA_PS_TCP,
+                              IB_QPT_RC);
        if (IS_ERR(cm_id)) {
                ret = PTR_ERR(cm_id);
                printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
index 48464ca13b242c45a8825ed57e326affc5026455..78efe895b6636c4a57af6d72f156501e2c778992 100644 (file)
@@ -33,3 +33,12 @@ config RFKILL_REGULATOR
 
           To compile this driver as a module, choose M here: the module will
           be called rfkill-regulator.
+
+config RFKILL_GPIO
+       tristate "GPIO RFKILL driver"
+       depends on RFKILL && GPIOLIB && HAVE_CLK
+       default n
+       help
+         If you say yes here you get support of a generic gpio RFKILL
+         driver. The platform should fill in the appropriate fields in the
+         rfkill_gpio_platform_data structure and pass that to the driver.
index d9a5a58ffd8c8102553f18abdd7729d6d7e4c43c..311768783f4a116843349687c99a3cf65f6c6314 100644 (file)
@@ -6,3 +6,4 @@ rfkill-y                        += core.o
 rfkill-$(CONFIG_RFKILL_INPUT)  += input.o
 obj-$(CONFIG_RFKILL)           += rfkill.o
 obj-$(CONFIG_RFKILL_REGULATOR) += rfkill-regulator.o
+obj-$(CONFIG_RFKILL_GPIO)      += rfkill-gpio.o
diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c
new file mode 100644 (file)
index 0000000..256c5dd
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2011, NVIDIA 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.
+ *
+ * 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.
+ */
+
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rfkill.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include <linux/rfkill-gpio.h>
+
+enum rfkill_gpio_clk_state {
+       UNSPECIFIED = 0,
+       PWR_ENABLED,
+       PWR_DISABLED
+};
+
+#define PWR_CLK_SET(_RF, _EN) \
+       ((_RF)->pwr_clk_enabled = (!(_EN) ? PWR_ENABLED : PWR_DISABLED))
+#define PWR_CLK_ENABLED(_RF) ((_RF)->pwr_clk_enabled == PWR_ENABLED)
+#define PWR_CLK_DISABLED(_RF) ((_RF)->pwr_clk_enabled != PWR_ENABLED)
+
+struct rfkill_gpio_data {
+       struct rfkill_gpio_platform_data        *pdata;
+       struct rfkill                           *rfkill_dev;
+       char                                    *reset_name;
+       char                                    *shutdown_name;
+       enum rfkill_gpio_clk_state              pwr_clk_enabled;
+       struct clk                              *pwr_clk;
+};
+
+static int rfkill_gpio_set_power(void *data, bool blocked)
+{
+       struct rfkill_gpio_data *rfkill = data;
+
+       if (blocked) {
+               if (gpio_is_valid(rfkill->pdata->shutdown_gpio))
+                       gpio_direction_output(rfkill->pdata->shutdown_gpio, 0);
+               if (gpio_is_valid(rfkill->pdata->reset_gpio))
+                       gpio_direction_output(rfkill->pdata->reset_gpio, 0);
+               if (rfkill->pwr_clk && PWR_CLK_ENABLED(rfkill))
+                       clk_disable(rfkill->pwr_clk);
+       } else {
+               if (rfkill->pwr_clk && PWR_CLK_DISABLED(rfkill))
+                       clk_enable(rfkill->pwr_clk);
+               if (gpio_is_valid(rfkill->pdata->reset_gpio))
+                       gpio_direction_output(rfkill->pdata->reset_gpio, 1);
+               if (gpio_is_valid(rfkill->pdata->shutdown_gpio))
+                       gpio_direction_output(rfkill->pdata->shutdown_gpio, 1);
+       }
+
+       if (rfkill->pwr_clk)
+               PWR_CLK_SET(rfkill, blocked);
+
+       return 0;
+}
+
+static const struct rfkill_ops rfkill_gpio_ops = {
+       .set_block = rfkill_gpio_set_power,
+};
+
+static int rfkill_gpio_probe(struct platform_device *pdev)
+{
+       struct rfkill_gpio_data *rfkill;
+       struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data;
+       int ret = 0;
+       int len = 0;
+
+       if (!pdata) {
+               pr_warn("%s: No platform data specified\n", __func__);
+               return -EINVAL;
+       }
+
+       /* make sure at-least one of the GPIO is defined and that
+        * a name is specified for this instance */
+       if (!pdata->name || (!gpio_is_valid(pdata->reset_gpio) &&
+               !gpio_is_valid(pdata->shutdown_gpio))) {
+               pr_warn("%s: invalid platform data\n", __func__);
+               return -EINVAL;
+       }
+
+       rfkill = kzalloc(sizeof(*rfkill), GFP_KERNEL);
+       if (!rfkill)
+               return -ENOMEM;
+
+       rfkill->pdata = pdata;
+
+       len = strlen(pdata->name);
+       rfkill->reset_name = kzalloc(len + 7, GFP_KERNEL);
+       if (!rfkill->reset_name) {
+               ret = -ENOMEM;
+               goto fail_alloc;
+       }
+
+       rfkill->shutdown_name = kzalloc(len + 10, GFP_KERNEL);
+       if (!rfkill->shutdown_name) {
+               ret = -ENOMEM;
+               goto fail_reset_name;
+       }
+
+       snprintf(rfkill->reset_name, len + 6 , "%s_reset", pdata->name);
+       snprintf(rfkill->shutdown_name, len + 9, "%s_shutdown", pdata->name);
+
+       if (pdata->power_clk_name) {
+               rfkill->pwr_clk = clk_get(&pdev->dev, pdata->power_clk_name);
+               if (IS_ERR(rfkill->pwr_clk)) {
+                       pr_warn("%s: can't find pwr_clk.\n", __func__);
+                       goto fail_shutdown_name;
+               }
+       }
+
+       if (gpio_is_valid(pdata->reset_gpio)) {
+               ret = gpio_request(pdata->reset_gpio, rfkill->reset_name);
+               if (ret) {
+                       pr_warn("%s: failed to get reset gpio.\n", __func__);
+                       goto fail_clock;
+               }
+       }
+
+       if (gpio_is_valid(pdata->shutdown_gpio)) {
+               ret = gpio_request(pdata->shutdown_gpio, rfkill->shutdown_name);
+               if (ret) {
+                       pr_warn("%s: failed to get shutdown gpio.\n", __func__);
+                       goto fail_reset;
+               }
+       }
+
+       rfkill->rfkill_dev = rfkill_alloc(pdata->name, &pdev->dev, pdata->type,
+                               &rfkill_gpio_ops, rfkill);
+       if (!rfkill->rfkill_dev)
+               goto fail_shutdown;
+
+       ret = rfkill_register(rfkill->rfkill_dev);
+       if (ret < 0)
+               goto fail_rfkill;
+
+       platform_set_drvdata(pdev, rfkill);
+
+       dev_info(&pdev->dev, "%s device registered.\n", pdata->name);
+
+       return 0;
+
+fail_rfkill:
+       rfkill_destroy(rfkill->rfkill_dev);
+fail_shutdown:
+       if (gpio_is_valid(pdata->shutdown_gpio))
+               gpio_free(pdata->shutdown_gpio);
+fail_reset:
+       if (gpio_is_valid(pdata->reset_gpio))
+               gpio_free(pdata->reset_gpio);
+fail_clock:
+       if (rfkill->pwr_clk)
+               clk_put(rfkill->pwr_clk);
+fail_shutdown_name:
+       kfree(rfkill->shutdown_name);
+fail_reset_name:
+       kfree(rfkill->reset_name);
+fail_alloc:
+       kfree(rfkill);
+
+       return ret;
+}
+
+static int rfkill_gpio_remove(struct platform_device *pdev)
+{
+       struct rfkill_gpio_data *rfkill = platform_get_drvdata(pdev);
+
+       rfkill_unregister(rfkill->rfkill_dev);
+       rfkill_destroy(rfkill->rfkill_dev);
+       if (gpio_is_valid(rfkill->pdata->shutdown_gpio))
+               gpio_free(rfkill->pdata->shutdown_gpio);
+       if (gpio_is_valid(rfkill->pdata->reset_gpio))
+               gpio_free(rfkill->pdata->reset_gpio);
+       if (rfkill->pwr_clk && PWR_CLK_ENABLED(rfkill))
+               clk_disable(rfkill->pwr_clk);
+       if (rfkill->pwr_clk)
+               clk_put(rfkill->pwr_clk);
+       kfree(rfkill->shutdown_name);
+       kfree(rfkill->reset_name);
+       kfree(rfkill);
+
+       return 0;
+}
+
+static struct platform_driver rfkill_gpio_driver = {
+       .probe = rfkill_gpio_probe,
+       .remove = __devexit_p(rfkill_gpio_remove),
+       .driver = {
+                  .name = "rfkill_gpio",
+                  .owner = THIS_MODULE,
+       },
+};
+
+static int __init rfkill_gpio_init(void)
+{
+       return platform_driver_register(&rfkill_gpio_driver);
+}
+
+static void __exit rfkill_gpio_exit(void)
+{
+       platform_driver_unregister(&rfkill_gpio_driver);
+}
+
+module_init(rfkill_gpio_init);
+module_exit(rfkill_gpio_exit);
+
+MODULE_DESCRIPTION("gpio rfkill");
+MODULE_AUTHOR("NVIDIA");
+MODULE_LICENSE("GPL");
index b1721d71c27c909a8c852fd425e0b74f7c37cfbf..b4c680900d7a8c9b417d1c976ef838f9eb5eb960 100644 (file)
@@ -251,9 +251,8 @@ static void dev_watchdog(unsigned long arg)
                        }
 
                        if (some_queue_timedout) {
-                               char drivername[64];
                                WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit queue %u timed out\n",
-                                      dev->name, netdev_drivername(dev, drivername, 64), i);
+                                      dev->name, netdev_drivername(dev), i);
                                dev->netdev_ops->ndo_tx_timeout(dev);
                        }
                        if (!mod_timer(&dev->watchdog_timer,
index 7ef87f9eb675d3b29ef207703c917d7912f6b130..b6ea6afa55b0197a7d7975ea5ec24aa500a92868 100644 (file)
@@ -361,7 +361,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
        unsigned int hash;
-       sfq_index x;
+       sfq_index x, qlen;
        struct sfq_slot *slot;
        int uninitialized_var(ret);
 
@@ -405,20 +405,12 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        if (++sch->q.qlen <= q->limit)
                return NET_XMIT_SUCCESS;
 
+       qlen = slot->qlen;
        sfq_drop(sch);
-       return NET_XMIT_CN;
-}
-
-static struct sk_buff *
-sfq_peek(struct Qdisc *sch)
-{
-       struct sfq_sched_data *q = qdisc_priv(sch);
-
-       /* No active slots */
-       if (q->tail == NULL)
-               return NULL;
-
-       return q->slots[q->tail->next].skblist_next;
+       /* Return Congestion Notification only if we dropped a packet
+        * from this flow.
+        */
+       return (qlen != slot->qlen) ? NET_XMIT_CN : NET_XMIT_SUCCESS;
 }
 
 static struct sk_buff *
@@ -702,7 +694,7 @@ static struct Qdisc_ops sfq_qdisc_ops __read_mostly = {
        .priv_size      =       sizeof(struct sfq_sched_data),
        .enqueue        =       sfq_enqueue,
        .dequeue        =       sfq_dequeue,
-       .peek           =       sfq_peek,
+       .peek           =       qdisc_peek_dequeued,
        .drop           =       sfq_drop,
        .init           =       sfq_init,
        .reset          =       sfq_reset,
index 1a21c571aa034fc90db2a38d4606681af03f0669..4a62888f2e43f43a7037f556257520a462d5ece2 100644 (file)
@@ -64,6 +64,7 @@
 /* Forward declarations for internal functions. */
 static void sctp_assoc_bh_rcv(struct work_struct *work);
 static void sctp_assoc_free_asconf_acks(struct sctp_association *asoc);
+static void sctp_assoc_free_asconf_queue(struct sctp_association *asoc);
 
 /* Keep track of the new idr low so that we don't re-use association id
  * numbers too fast.  It is protected by they idr spin lock is in the
@@ -443,12 +444,7 @@ void sctp_association_free(struct sctp_association *asoc)
 
        asoc->peer.transport_count = 0;
 
-       /* Free any cached ASCONF_ACK chunk. */
-       sctp_assoc_free_asconf_acks(asoc);
-
-       /* Free any cached ASCONF chunk. */
-       if (asoc->addip_last_asconf)
-               sctp_chunk_free(asoc->addip_last_asconf);
+       sctp_asconf_queue_teardown(asoc);
 
        /* AUTH - Free the endpoint shared keys */
        sctp_auth_destroy_keys(&asoc->endpoint_shared_keys);
@@ -1578,6 +1574,18 @@ retry:
        return error;
 }
 
+/* Free the ASCONF queue */
+static void sctp_assoc_free_asconf_queue(struct sctp_association *asoc)
+{
+       struct sctp_chunk *asconf;
+       struct sctp_chunk *tmp;
+
+       list_for_each_entry_safe(asconf, tmp, &asoc->addip_chunk_list, list) {
+               list_del_init(&asconf->list);
+               sctp_chunk_free(asconf);
+       }
+}
+
 /* Free asconf_ack cache */
 static void sctp_assoc_free_asconf_acks(struct sctp_association *asoc)
 {
@@ -1630,3 +1638,16 @@ struct sctp_chunk *sctp_assoc_lookup_asconf_ack(
 
        return NULL;
 }
+
+void sctp_asconf_queue_teardown(struct sctp_association *asoc)
+{
+       /* Free any cached ASCONF_ACK chunk. */
+       sctp_assoc_free_asconf_acks(asoc);
+
+       /* Free the ASCONF queue. */
+       sctp_assoc_free_asconf_queue(asoc);
+
+       /* Free any cached ASCONF chunk. */
+       if (asoc->addip_last_asconf)
+               sctp_chunk_free(asoc->addip_last_asconf);
+}
index 61aacfbbaa92f55829730687fdf0026d123301d1..05a6ce2147147b4e4fbb9de92d7913d3877e4fb2 100644 (file)
@@ -212,7 +212,7 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v)
        sctp_for_each_hentry(epb, node, &head->chain) {
                ep = sctp_ep(epb);
                sk = epb->sk;
-               seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk,
+               seq_printf(seq, "%8pK %8pK %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk,
                           sctp_sk(sk)->type, sk->sk_state, hash,
                           epb->bind_addr.port,
                           sock_i_uid(sk), sock_i_ino(sk));
@@ -316,7 +316,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
                assoc = sctp_assoc(epb);
                sk = epb->sk;
                seq_printf(seq,
-                          "%8p %8p %-3d %-3d %-2d %-4d "
+                          "%8pK %8pK %-3d %-3d %-2d %-4d "
                           "%4d %8d %8d %7d %5lu %-5d %5d ",
                           assoc, sk, sctp_sk(sk)->type, sk->sk_state,
                           assoc->state, hash,
index d612ca1ca6c08fb979bbfad4f6252e27be729be6..534c2e5feb054c933cbd0dcf46a0cb66386646dd 100644 (file)
@@ -1670,6 +1670,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
                case SCTP_CMD_SEND_NEXT_ASCONF:
                        sctp_cmd_send_asconf(asoc);
                        break;
+               case SCTP_CMD_PURGE_ASCONF_QUEUE:
+                       sctp_asconf_queue_teardown(asoc);
+                       break;
                default:
                        pr_warn("Impossible command: %u, %p\n",
                                cmd->verb, cmd->obj.ptr);
index 7f4a4f8368ee0df6b6ccab07ada25df655b7b521..a297283154d5035c6342e54916f10445aa610d83 100644 (file)
@@ -1718,11 +1718,21 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep,
                return SCTP_DISPOSITION_CONSUME;
        }
 
-       /* For now, fail any unsent/unacked data.  Consider the optional
-        * choice of resending of this data.
+       /* For now, stop pending T3-rtx and SACK timers, fail any unsent/unacked
+        * data. Consider the optional choice of resending of this data.
         */
+       sctp_add_cmd_sf(commands, SCTP_CMD_T3_RTX_TIMERS_STOP, SCTP_NULL());
+       sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
+                       SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
        sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL());
 
+       /* Stop pending T4-rto timer, teardown ASCONF queue, ASCONF-ACK queue
+        * and ASCONF-ACK cache.
+        */
+       sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
+                       SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
+       sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_ASCONF_QUEUE, SCTP_NULL());
+
        repl = sctp_make_cookie_ack(new_asoc, chunk);
        if (!repl)
                goto nomem;
index 67e31276682ab5a969da50b300d2ff941d7f3553..cd6e4aa19dbfca0de4d54ea5bf6bf5e0d1a79d9f 100644 (file)
@@ -326,10 +326,12 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan)
  * Run memory cache shrinker.
  */
 static int
-rpcauth_cache_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
+rpcauth_cache_shrinker(struct shrinker *shrink, struct shrink_control *sc)
 {
        LIST_HEAD(free);
        int res;
+       int nr_to_scan = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
 
        if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL)
                return (nr_to_scan == 0) ? 0 : -1;
index 339ba64cce1e2ee7134a2c9d09cd64f5fb9cb85e..5daf6cc4faea19f39081765433f4cf2333280605 100644 (file)
@@ -577,13 +577,13 @@ retry:
        }
        inode = &gss_msg->inode->vfs_inode;
        for (;;) {
-               prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_KILLABLE);
                spin_lock(&inode->i_lock);
                if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) {
                        break;
                }
                spin_unlock(&inode->i_lock);
-               if (signalled()) {
+               if (fatal_signal_pending(current)) {
                        err = -ERESTARTSYS;
                        goto out_intr;
                }
index 0a9a2ec2e46983f0b73bf20d267721024c11646c..c3b75333b821d2b58da65d16dc099ee6cf2b9da3 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/sunrpc/gss_krb5.h>
 #include <linux/sunrpc/xdr.h>
 #include <linux/crypto.h>
+#include <linux/sunrpc/gss_krb5_enctypes.h>
 
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY       RPCDBG_AUTH
@@ -750,7 +751,7 @@ static struct gss_api_mech gss_kerberos_mech = {
        .gm_ops         = &gss_kerberos_ops,
        .gm_pf_num      = ARRAY_SIZE(gss_kerberos_pfs),
        .gm_pfs         = gss_kerberos_pfs,
-       .gm_upcall_enctypes = "18,17,16,23,3,1,2",
+       .gm_upcall_enctypes = KRB5_SUPPORTED_ENCTYPES,
 };
 
 static int __init init_kerberos_module(void)
index 8d83f9d487130bb7789fe0dc53201ec3aedc5a95..8c9141583d6f135714eac27c100e4bc9c3426631 100644 (file)
  *     and need to be refreshed, or when a packet was damaged in transit.
  *     This may be have to be moved to the VFS layer.
  *
- *  NB: BSD uses a more intelligent approach to guessing when a request
- *  or reply has been lost by keeping the RTO estimate for each procedure.
- *  We currently make do with a constant timeout value.
- *
  *  Copyright (C) 1992,1993 Rick Sladkey <jrs@world.std.com>
  *  Copyright (C) 1995,1996 Olaf Kirch <okir@monad.swb.de>
  */
@@ -32,7 +28,9 @@
 #include <linux/slab.h>
 #include <linux/utsname.h>
 #include <linux/workqueue.h>
+#include <linux/in.h>
 #include <linux/in6.h>
+#include <linux/un.h>
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
@@ -298,22 +296,27 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
         * up a string representation of the passed-in address.
         */
        if (args->servername == NULL) {
+               struct sockaddr_un *sun =
+                               (struct sockaddr_un *)args->address;
+               struct sockaddr_in *sin =
+                               (struct sockaddr_in *)args->address;
+               struct sockaddr_in6 *sin6 =
+                               (struct sockaddr_in6 *)args->address;
+
                servername[0] = '\0';
                switch (args->address->sa_family) {
-               case AF_INET: {
-                       struct sockaddr_in *sin =
-                                       (struct sockaddr_in *)args->address;
+               case AF_LOCAL:
+                       snprintf(servername, sizeof(servername), "%s",
+                                sun->sun_path);
+                       break;
+               case AF_INET:
                        snprintf(servername, sizeof(servername), "%pI4",
                                 &sin->sin_addr.s_addr);
                        break;
-               }
-               case AF_INET6: {
-                       struct sockaddr_in6 *sin =
-                                       (struct sockaddr_in6 *)args->address;
+               case AF_INET6:
                        snprintf(servername, sizeof(servername), "%pI6",
-                                &sin->sin6_addr);
+                                &sin6->sin6_addr);
                        break;
-               }
                default:
                        /* caller wants default server name, but
                         * address family isn't recognized. */
@@ -1058,7 +1061,7 @@ call_allocate(struct rpc_task *task)
 
        dprintk("RPC: %5u rpc_buffer allocation failed\n", task->tk_pid);
 
-       if (RPC_IS_ASYNC(task) || !signalled()) {
+       if (RPC_IS_ASYNC(task) || !fatal_signal_pending(current)) {
                task->tk_action = call_allocate;
                rpc_delay(task, HZ>>4);
                return;
@@ -1172,6 +1175,9 @@ call_bind_status(struct rpc_task *task)
                        status = -EOPNOTSUPP;
                        break;
                }
+               if (task->tk_rebind_retry == 0)
+                       break;
+               task->tk_rebind_retry--;
                rpc_delay(task, 3*HZ);
                goto retry_timeout;
        case -ETIMEDOUT:
index c652e4cc9fe97c987dbb9eb1eef3e1c639ed1af4..9a80a922c5270ee78d8a76feebac4360c551da82 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/types.h>
 #include <linux/socket.h>
+#include <linux/un.h>
 #include <linux/in.h>
 #include <linux/in6.h>
 #include <linux/kernel.h>
@@ -32,6 +33,8 @@
 # define RPCDBG_FACILITY       RPCDBG_BIND
 #endif
 
+#define RPCBIND_SOCK_PATHNAME  "/var/run/rpcbind.sock"
+
 #define RPCBIND_PROGRAM                (100000u)
 #define RPCBIND_PORT           (111u)
 
@@ -158,20 +161,69 @@ static void rpcb_map_release(void *data)
        kfree(map);
 }
 
-static const struct sockaddr_in rpcb_inaddr_loopback = {
-       .sin_family             = AF_INET,
-       .sin_addr.s_addr        = htonl(INADDR_LOOPBACK),
-       .sin_port               = htons(RPCBIND_PORT),
-};
+/*
+ * Returns zero on success, otherwise a negative errno value
+ * is returned.
+ */
+static int rpcb_create_local_unix(void)
+{
+       static const struct sockaddr_un rpcb_localaddr_rpcbind = {
+               .sun_family             = AF_LOCAL,
+               .sun_path               = RPCBIND_SOCK_PATHNAME,
+       };
+       struct rpc_create_args args = {
+               .net            = &init_net,
+               .protocol       = XPRT_TRANSPORT_LOCAL,
+               .address        = (struct sockaddr *)&rpcb_localaddr_rpcbind,
+               .addrsize       = sizeof(rpcb_localaddr_rpcbind),
+               .servername     = "localhost",
+               .program        = &rpcb_program,
+               .version        = RPCBVERS_2,
+               .authflavor     = RPC_AUTH_NULL,
+       };
+       struct rpc_clnt *clnt, *clnt4;
+       int result = 0;
+
+       /*
+        * Because we requested an RPC PING at transport creation time,
+        * this works only if the user space portmapper is rpcbind, and
+        * it's listening on AF_LOCAL on the named socket.
+        */
+       clnt = rpc_create(&args);
+       if (IS_ERR(clnt)) {
+               dprintk("RPC:       failed to create AF_LOCAL rpcbind "
+                               "client (errno %ld).\n", PTR_ERR(clnt));
+               result = -PTR_ERR(clnt);
+               goto out;
+       }
+
+       clnt4 = rpc_bind_new_program(clnt, &rpcb_program, RPCBVERS_4);
+       if (IS_ERR(clnt4)) {
+               dprintk("RPC:       failed to bind second program to "
+                               "rpcbind v4 client (errno %ld).\n",
+                               PTR_ERR(clnt4));
+               clnt4 = NULL;
+       }
+
+       /* Protected by rpcb_create_local_mutex */
+       rpcb_local_clnt = clnt;
+       rpcb_local_clnt4 = clnt4;
 
-static DEFINE_MUTEX(rpcb_create_local_mutex);
+out:
+       return result;
+}
 
 /*
  * Returns zero on success, otherwise a negative errno value
  * is returned.
  */
-static int rpcb_create_local(void)
+static int rpcb_create_local_net(void)
 {
+       static const struct sockaddr_in rpcb_inaddr_loopback = {
+               .sin_family             = AF_INET,
+               .sin_addr.s_addr        = htonl(INADDR_LOOPBACK),
+               .sin_port               = htons(RPCBIND_PORT),
+       };
        struct rpc_create_args args = {
                .net            = &init_net,
                .protocol       = XPRT_TRANSPORT_TCP,
@@ -186,13 +238,6 @@ static int rpcb_create_local(void)
        struct rpc_clnt *clnt, *clnt4;
        int result = 0;
 
-       if (rpcb_local_clnt)
-               return result;
-
-       mutex_lock(&rpcb_create_local_mutex);
-       if (rpcb_local_clnt)
-               goto out;
-
        clnt = rpc_create(&args);
        if (IS_ERR(clnt)) {
                dprintk("RPC:       failed to create local rpcbind "
@@ -214,9 +259,33 @@ static int rpcb_create_local(void)
                clnt4 = NULL;
        }
 
+       /* Protected by rpcb_create_local_mutex */
        rpcb_local_clnt = clnt;
        rpcb_local_clnt4 = clnt4;
 
+out:
+       return result;
+}
+
+/*
+ * Returns zero on success, otherwise a negative errno value
+ * is returned.
+ */
+static int rpcb_create_local(void)
+{
+       static DEFINE_MUTEX(rpcb_create_local_mutex);
+       int result = 0;
+
+       if (rpcb_local_clnt)
+               return result;
+
+       mutex_lock(&rpcb_create_local_mutex);
+       if (rpcb_local_clnt)
+               goto out;
+
+       if (rpcb_create_local_unix() != 0)
+               result = rpcb_create_local_net();
+
 out:
        mutex_unlock(&rpcb_create_local_mutex);
        return result;
index 6b43ee7221d5a830b8b0acea4375f9341aacfc90..a27406b1654f190f645e9b3c393b46f4b6d939fb 100644 (file)
@@ -792,6 +792,7 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta
        /* Initialize retry counters */
        task->tk_garb_retry = 2;
        task->tk_cred_retry = 2;
+       task->tk_rebind_retry = 2;
 
        task->tk_priority = task_setup_data->priority - RPC_PRIORITY_LOW;
        task->tk_owner = current->tgid;
index 08e05a8ce0255b338cc9c812006302a79e7ad4a9..2b90292e95053acace4d02a3269b960591b3b426 100644 (file)
@@ -942,6 +942,8 @@ static void svc_unregister(const struct svc_serv *serv)
                        if (progp->pg_vers[i]->vs_hidden)
                                continue;
 
+                       dprintk("svc: attempting to unregister %sv%u\n",
+                               progp->pg_name, i);
                        __svc_unregister(progp->pg_prog, i, progp->pg_name);
                }
        }
index b7d435c3f19ec537275cb8b413d6c929c4dc8fa6..af04f779ce9f1afb624c3dd20d99941fa6c1e60e 100644 (file)
@@ -387,6 +387,33 @@ static int svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr,
        return len;
 }
 
+static int svc_partial_recvfrom(struct svc_rqst *rqstp,
+                               struct kvec *iov, int nr,
+                               int buflen, unsigned int base)
+{
+       size_t save_iovlen;
+       void __user *save_iovbase;
+       unsigned int i;
+       int ret;
+
+       if (base == 0)
+               return svc_recvfrom(rqstp, iov, nr, buflen);
+
+       for (i = 0; i < nr; i++) {
+               if (iov[i].iov_len > base)
+                       break;
+               base -= iov[i].iov_len;
+       }
+       save_iovlen = iov[i].iov_len;
+       save_iovbase = iov[i].iov_base;
+       iov[i].iov_len -= base;
+       iov[i].iov_base += base;
+       ret = svc_recvfrom(rqstp, &iov[i], nr - i, buflen);
+       iov[i].iov_len = save_iovlen;
+       iov[i].iov_base = save_iovbase;
+       return ret;
+}
+
 /*
  * Set socket snd and rcv buffer lengths
  */
@@ -409,7 +436,6 @@ static void svc_sock_setbufsize(struct socket *sock, unsigned int snd,
        lock_sock(sock->sk);
        sock->sk->sk_sndbuf = snd * 2;
        sock->sk->sk_rcvbuf = rcv * 2;
-       sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK;
        sock->sk->sk_write_space(sock->sk);
        release_sock(sock->sk);
 #endif
@@ -884,6 +910,56 @@ failed:
        return NULL;
 }
 
+static unsigned int svc_tcp_restore_pages(struct svc_sock *svsk, struct svc_rqst *rqstp)
+{
+       unsigned int i, len, npages;
+
+       if (svsk->sk_tcplen <= sizeof(rpc_fraghdr))
+               return 0;
+       len = svsk->sk_tcplen - sizeof(rpc_fraghdr);
+       npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       for (i = 0; i < npages; i++) {
+               if (rqstp->rq_pages[i] != NULL)
+                       put_page(rqstp->rq_pages[i]);
+               BUG_ON(svsk->sk_pages[i] == NULL);
+               rqstp->rq_pages[i] = svsk->sk_pages[i];
+               svsk->sk_pages[i] = NULL;
+       }
+       rqstp->rq_arg.head[0].iov_base = page_address(rqstp->rq_pages[0]);
+       return len;
+}
+
+static void svc_tcp_save_pages(struct svc_sock *svsk, struct svc_rqst *rqstp)
+{
+       unsigned int i, len, npages;
+
+       if (svsk->sk_tcplen <= sizeof(rpc_fraghdr))
+               return;
+       len = svsk->sk_tcplen - sizeof(rpc_fraghdr);
+       npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       for (i = 0; i < npages; i++) {
+               svsk->sk_pages[i] = rqstp->rq_pages[i];
+               rqstp->rq_pages[i] = NULL;
+       }
+}
+
+static void svc_tcp_clear_pages(struct svc_sock *svsk)
+{
+       unsigned int i, len, npages;
+
+       if (svsk->sk_tcplen <= sizeof(rpc_fraghdr))
+               goto out;
+       len = svsk->sk_tcplen - sizeof(rpc_fraghdr);
+       npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       for (i = 0; i < npages; i++) {
+               BUG_ON(svsk->sk_pages[i] == NULL);
+               put_page(svsk->sk_pages[i]);
+               svsk->sk_pages[i] = NULL;
+       }
+out:
+       svsk->sk_tcplen = 0;
+}
+
 /*
  * Receive data.
  * If we haven't gotten the record length yet, get the next four bytes.
@@ -893,31 +969,15 @@ failed:
 static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp)
 {
        struct svc_serv *serv = svsk->sk_xprt.xpt_server;
+       unsigned int want;
        int len;
 
-       if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags))
-               /* sndbuf needs to have room for one request
-                * per thread, otherwise we can stall even when the
-                * network isn't a bottleneck.
-                *
-                * We count all threads rather than threads in a
-                * particular pool, which provides an upper bound
-                * on the number of threads which will access the socket.
-                *
-                * rcvbuf just needs to be able to hold a few requests.
-                * Normally they will be removed from the queue
-                * as soon a a complete request arrives.
-                */
-               svc_sock_setbufsize(svsk->sk_sock,
-                                   (serv->sv_nrthreads+3) * serv->sv_max_mesg,
-                                   3 * serv->sv_max_mesg);
-
        clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
 
        if (svsk->sk_tcplen < sizeof(rpc_fraghdr)) {
-               int             want = sizeof(rpc_fraghdr) - svsk->sk_tcplen;
                struct kvec     iov;
 
+               want = sizeof(rpc_fraghdr) - svsk->sk_tcplen;
                iov.iov_base = ((char *) &svsk->sk_reclen) + svsk->sk_tcplen;
                iov.iov_len  = want;
                if ((len = svc_recvfrom(rqstp, &iov, 1, want)) < 0)
@@ -927,7 +987,7 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp)
                if (len < want) {
                        dprintk("svc: short recvfrom while reading record "
                                "length (%d of %d)\n", len, want);
-                       goto err_again; /* record header not complete */
+                       return -EAGAIN;
                }
 
                svsk->sk_reclen = ntohl(svsk->sk_reclen);
@@ -954,83 +1014,75 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp)
                }
        }
 
-       /* Check whether enough data is available */
-       len = svc_recv_available(svsk);
-       if (len < 0)
-               goto error;
+       if (svsk->sk_reclen < 8)
+               goto err_delete; /* client is nuts. */
 
-       if (len < svsk->sk_reclen) {
-               dprintk("svc: incomplete TCP record (%d of %d)\n",
-                       len, svsk->sk_reclen);
-               goto err_again; /* record not complete */
-       }
        len = svsk->sk_reclen;
-       set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
 
        return len;
- error:
-       if (len == -EAGAIN)
-               dprintk("RPC: TCP recv_record got EAGAIN\n");
+error:
+       dprintk("RPC: TCP recv_record got %d\n", len);
        return len;
- err_delete:
+err_delete:
        set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
- err_again:
        return -EAGAIN;
 }
 
-static int svc_process_calldir(struct svc_sock *svsk, struct svc_rqst *rqstp,
-                              struct rpc_rqst **reqpp, struct kvec *vec)
+static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
 {
+       struct rpc_xprt *bc_xprt = svsk->sk_xprt.xpt_bc_xprt;
        struct rpc_rqst *req = NULL;
-       u32 *p;
-       u32 xid;
-       u32 calldir;
-       int len;
-
-       len = svc_recvfrom(rqstp, vec, 1, 8);
-       if (len < 0)
-               goto error;
+       struct kvec *src, *dst;
+       __be32 *p = (__be32 *)rqstp->rq_arg.head[0].iov_base;
+       __be32 xid;
+       __be32 calldir;
 
-       p = (u32 *)rqstp->rq_arg.head[0].iov_base;
        xid = *p++;
        calldir = *p;
 
-       if (calldir == 0) {
-               /* REQUEST is the most common case */
-               vec[0] = rqstp->rq_arg.head[0];
-       } else {
-               /* REPLY */
-               struct rpc_xprt *bc_xprt = svsk->sk_xprt.xpt_bc_xprt;
-
-               if (bc_xprt)
-                       req = xprt_lookup_rqst(bc_xprt, xid);
-
-               if (!req) {
-                       printk(KERN_NOTICE
-                               "%s: Got unrecognized reply: "
-                               "calldir 0x%x xpt_bc_xprt %p xid %08x\n",
-                               __func__, ntohl(calldir),
-                               bc_xprt, xid);
-                       vec[0] = rqstp->rq_arg.head[0];
-                       goto out;
-               }
+       if (bc_xprt)
+               req = xprt_lookup_rqst(bc_xprt, xid);
 
-               memcpy(&req->rq_private_buf, &req->rq_rcv_buf,
-                      sizeof(struct xdr_buf));
-               /* copy the xid and call direction */
-               memcpy(req->rq_private_buf.head[0].iov_base,
-                      rqstp->rq_arg.head[0].iov_base, 8);
-               vec[0] = req->rq_private_buf.head[0];
+       if (!req) {
+               printk(KERN_NOTICE
+                       "%s: Got unrecognized reply: "
+                       "calldir 0x%x xpt_bc_xprt %p xid %08x\n",
+                       __func__, ntohl(calldir),
+                       bc_xprt, xid);
+               return -EAGAIN;
        }
- out:
-       vec[0].iov_base += 8;
-       vec[0].iov_len -= 8;
-       len = svsk->sk_reclen - 8;
- error:
-       *reqpp = req;
-       return len;
+
+       memcpy(&req->rq_private_buf, &req->rq_rcv_buf, sizeof(struct xdr_buf));
+       /*
+        * XXX!: cheating for now!  Only copying HEAD.
+        * But we know this is good enough for now (in fact, for any
+        * callback reply in the forseeable future).
+        */
+       dst = &req->rq_private_buf.head[0];
+       src = &rqstp->rq_arg.head[0];
+       if (dst->iov_len < src->iov_len)
+               return -EAGAIN; /* whatever; just giving up. */
+       memcpy(dst->iov_base, src->iov_base, src->iov_len);
+       xprt_complete_rqst(req->rq_task, svsk->sk_reclen);
+       rqstp->rq_arg.len = 0;
+       return 0;
 }
 
+static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len)
+{
+       int i = 0;
+       int t = 0;
+
+       while (t < len) {
+               vec[i].iov_base = page_address(pages[i]);
+               vec[i].iov_len = PAGE_SIZE;
+               i++;
+               t += PAGE_SIZE;
+       }
+       return i;
+}
+
+
 /*
  * Receive data from a TCP socket.
  */
@@ -1041,8 +1093,10 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
        struct svc_serv *serv = svsk->sk_xprt.xpt_server;
        int             len;
        struct kvec *vec;
-       int pnum, vlen;
-       struct rpc_rqst *req = NULL;
+       unsigned int want, base;
+       __be32 *p;
+       __be32 calldir;
+       int pnum;
 
        dprintk("svc: tcp_recv %p data %d conn %d close %d\n",
                svsk, test_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags),
@@ -1053,87 +1107,73 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
        if (len < 0)
                goto error;
 
+       base = svc_tcp_restore_pages(svsk, rqstp);
+       want = svsk->sk_reclen - base;
+
        vec = rqstp->rq_vec;
-       vec[0] = rqstp->rq_arg.head[0];
-       vlen = PAGE_SIZE;
 
-       /*
-        * We have enough data for the whole tcp record. Let's try and read the
-        * first 8 bytes to get the xid and the call direction. We can use this
-        * to figure out if this is a call or a reply to a callback. If
-        * sk_reclen is < 8 (xid and calldir), then this is a malformed packet.
-        * In that case, don't bother with the calldir and just read the data.
-        * It will be rejected in svc_process.
-        */
-       if (len >= 8) {
-               len = svc_process_calldir(svsk, rqstp, &req, vec);
-               if (len < 0)
-                       goto err_again;
-               vlen -= 8;
-       }
+       pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0],
+                                               svsk->sk_reclen);
 
-       pnum = 1;
-       while (vlen < len) {
-               vec[pnum].iov_base = (req) ?
-                       page_address(req->rq_private_buf.pages[pnum - 1]) :
-                       page_address(rqstp->rq_pages[pnum]);
-               vec[pnum].iov_len = PAGE_SIZE;
-               pnum++;
-               vlen += PAGE_SIZE;
-       }
        rqstp->rq_respages = &rqstp->rq_pages[pnum];
 
        /* Now receive data */
-       len = svc_recvfrom(rqstp, vec, pnum, len);
-       if (len < 0)
-               goto err_again;
-
-       /*
-        * Account for the 8 bytes we read earlier
-        */
-       len += 8;
-
-       if (req) {
-               xprt_complete_rqst(req->rq_task, len);
-               len = 0;
-               goto out;
+       len = svc_partial_recvfrom(rqstp, vec, pnum, want, base);
+       if (len >= 0)
+               svsk->sk_tcplen += len;
+       if (len != want) {
+               if (len < 0 && len != -EAGAIN)
+                       goto err_other;
+               svc_tcp_save_pages(svsk, rqstp);
+               dprintk("svc: incomplete TCP record (%d of %d)\n",
+                       svsk->sk_tcplen, svsk->sk_reclen);
+               goto err_noclose;
        }
-       dprintk("svc: TCP complete record (%d bytes)\n", len);
-       rqstp->rq_arg.len = len;
+
+       rqstp->rq_arg.len = svsk->sk_reclen;
        rqstp->rq_arg.page_base = 0;
-       if (len <= rqstp->rq_arg.head[0].iov_len) {
-               rqstp->rq_arg.head[0].iov_len = len;
+       if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) {
+               rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len;
                rqstp->rq_arg.page_len = 0;
-       } else {
-               rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len;
-       }
+       } else
+               rqstp->rq_arg.page_len = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len;
 
        rqstp->rq_xprt_ctxt   = NULL;
        rqstp->rq_prot        = IPPROTO_TCP;
 
-out:
+       p = (__be32 *)rqstp->rq_arg.head[0].iov_base;
+       calldir = p[1];
+       if (calldir)
+               len = receive_cb_reply(svsk, rqstp);
+
        /* Reset TCP read info */
        svsk->sk_reclen = 0;
        svsk->sk_tcplen = 0;
+       /* If we have more data, signal svc_xprt_enqueue() to try again */
+       if (svc_recv_available(svsk) > sizeof(rpc_fraghdr))
+               set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
+
+       if (len < 0)
+               goto error;
 
        svc_xprt_copy_addrs(rqstp, &svsk->sk_xprt);
        if (serv->sv_stats)
                serv->sv_stats->nettcpcnt++;
 
-       return len;
+       dprintk("svc: TCP complete record (%d bytes)\n", rqstp->rq_arg.len);
+       return rqstp->rq_arg.len;
 
-err_again:
-       if (len == -EAGAIN) {
-               dprintk("RPC: TCP recvfrom got EAGAIN\n");
-               return len;
-       }
 error:
-       if (len != -EAGAIN) {
-               printk(KERN_NOTICE "%s: recvfrom returned errno %d\n",
-                      svsk->sk_xprt.xpt_server->sv_name, -len);
-               set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
-       }
+       if (len != -EAGAIN)
+               goto err_other;
+       dprintk("RPC: TCP recvfrom got EAGAIN\n");
        return -EAGAIN;
+err_other:
+       printk(KERN_NOTICE "%s: recvfrom returned errno %d\n",
+              svsk->sk_xprt.xpt_server->sv_name, -len);
+       set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
+err_noclose:
+       return -EAGAIN; /* record not complete */
 }
 
 /*
@@ -1304,18 +1344,10 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
 
                svsk->sk_reclen = 0;
                svsk->sk_tcplen = 0;
+               memset(&svsk->sk_pages[0], 0, sizeof(svsk->sk_pages));
 
                tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
 
-               /* initialise setting must have enough space to
-                * receive and respond to one request.
-                * svc_tcp_recvfrom will re-adjust if necessary
-                */
-               svc_sock_setbufsize(svsk->sk_sock,
-                                   3 * svsk->sk_xprt.xpt_server->sv_max_mesg,
-                                   3 * svsk->sk_xprt.xpt_server->sv_max_mesg);
-
-               set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
                set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
                if (sk->sk_state != TCP_ESTABLISHED)
                        set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
@@ -1379,8 +1411,14 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
        /* Initialize the socket */
        if (sock->type == SOCK_DGRAM)
                svc_udp_init(svsk, serv);
-       else
+       else {
+               /* initialise setting must have enough space to
+                * receive and respond to one request.
+                */
+               svc_sock_setbufsize(svsk->sk_sock, 4 * serv->sv_max_mesg,
+                                       4 * serv->sv_max_mesg);
                svc_tcp_init(svsk, serv);
+       }
 
        dprintk("svc: svc_setup_socket created %p (inet %p)\n",
                                svsk, svsk->sk_sk);
@@ -1562,8 +1600,10 @@ static void svc_tcp_sock_detach(struct svc_xprt *xprt)
 
        svc_sock_detach(xprt);
 
-       if (!test_bit(XPT_LISTENER, &xprt->xpt_flags))
+       if (!test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
+               svc_tcp_clear_pages(svsk);
                kernel_sock_shutdown(svsk->sk_sock, SHUT_RDWR);
+       }
 }
 
 /*
index 679cd674b81dcd878362c89262a6b4949d04a364..f008c14ad34cc03703f6550e95b0144c8a572402 100644 (file)
@@ -638,6 +638,25 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
 }
 EXPORT_SYMBOL_GPL(xdr_init_decode);
 
+/**
+ * xdr_init_decode - Initialize an xdr_stream for decoding data.
+ * @xdr: pointer to xdr_stream struct
+ * @buf: pointer to XDR buffer from which to decode data
+ * @pages: list of pages to decode into
+ * @len: length in bytes of buffer in pages
+ */
+void xdr_init_decode_pages(struct xdr_stream *xdr, struct xdr_buf *buf,
+                          struct page **pages, unsigned int len)
+{
+       memset(buf, 0, sizeof(*buf));
+       buf->pages =  pages;
+       buf->page_len =  len;
+       buf->buflen =  len;
+       buf->len = len;
+       xdr_init_decode(xdr, buf, NULL);
+}
+EXPORT_SYMBOL_GPL(xdr_init_decode_pages);
+
 static __be32 * __xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
 {
        __be32 *p = xdr->p;
index 6c014dd3a20bf235c5ccb32408ed7f2c726406be..c3c232a88d94daa8a9facb1c9cbd3a3025d0354e 100644 (file)
@@ -695,7 +695,8 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
                return ERR_PTR(-ENOMEM);
        xprt = &cma_xprt->sc_xprt;
 
-       listen_id = rdma_create_id(rdma_listen_handler, cma_xprt, RDMA_PS_TCP);
+       listen_id = rdma_create_id(rdma_listen_handler, cma_xprt, RDMA_PS_TCP,
+                                  IB_QPT_RC);
        if (IS_ERR(listen_id)) {
                ret = PTR_ERR(listen_id);
                dprintk("svcrdma: rdma_create_id failed = %d\n", ret);
index d4297dc43dc4c834ecfa457f36f221385353ecf2..80f8da344df538c5b6ef054e3caddc617a9a49ec 100644 (file)
@@ -387,7 +387,7 @@ rpcrdma_create_id(struct rpcrdma_xprt *xprt,
 
        init_completion(&ia->ri_done);
 
-       id = rdma_create_id(rpcrdma_conn_upcall, xprt, RDMA_PS_TCP);
+       id = rdma_create_id(rpcrdma_conn_upcall, xprt, RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(id)) {
                rc = PTR_ERR(id);
                dprintk("RPC:       %s: rdma_create_id() failed %i\n",
index bf005d3c65efbffb46f5f05967de3806d9ac9b7d..72abb735893321d4616d5d9b0801e5cb6f777cff 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/capability.h>
@@ -28,6 +29,7 @@
 #include <linux/in.h>
 #include <linux/net.h>
 #include <linux/mm.h>
+#include <linux/un.h>
 #include <linux/udp.h>
 #include <linux/tcp.h>
 #include <linux/sunrpc/clnt.h>
@@ -45,6 +47,9 @@
 #include <net/tcp.h>
 
 #include "sunrpc.h"
+
+static void xs_close(struct rpc_xprt *xprt);
+
 /*
  * xprtsock tunables
  */
@@ -261,6 +266,11 @@ static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt)
        return (struct sockaddr *) &xprt->addr;
 }
 
+static inline struct sockaddr_un *xs_addr_un(struct rpc_xprt *xprt)
+{
+       return (struct sockaddr_un *) &xprt->addr;
+}
+
 static inline struct sockaddr_in *xs_addr_in(struct rpc_xprt *xprt)
 {
        return (struct sockaddr_in *) &xprt->addr;
@@ -276,23 +286,34 @@ static void xs_format_common_peer_addresses(struct rpc_xprt *xprt)
        struct sockaddr *sap = xs_addr(xprt);
        struct sockaddr_in6 *sin6;
        struct sockaddr_in *sin;
+       struct sockaddr_un *sun;
        char buf[128];
 
-       (void)rpc_ntop(sap, buf, sizeof(buf));
-       xprt->address_strings[RPC_DISPLAY_ADDR] = kstrdup(buf, GFP_KERNEL);
-
        switch (sap->sa_family) {
+       case AF_LOCAL:
+               sun = xs_addr_un(xprt);
+               strlcpy(buf, sun->sun_path, sizeof(buf));
+               xprt->address_strings[RPC_DISPLAY_ADDR] =
+                                               kstrdup(buf, GFP_KERNEL);
+               break;
        case AF_INET:
+               (void)rpc_ntop(sap, buf, sizeof(buf));
+               xprt->address_strings[RPC_DISPLAY_ADDR] =
+                                               kstrdup(buf, GFP_KERNEL);
                sin = xs_addr_in(xprt);
                snprintf(buf, sizeof(buf), "%08x", ntohl(sin->sin_addr.s_addr));
                break;
        case AF_INET6:
+               (void)rpc_ntop(sap, buf, sizeof(buf));
+               xprt->address_strings[RPC_DISPLAY_ADDR] =
+                                               kstrdup(buf, GFP_KERNEL);
                sin6 = xs_addr_in6(xprt);
                snprintf(buf, sizeof(buf), "%pi6", &sin6->sin6_addr);
                break;
        default:
                BUG();
        }
+
        xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = kstrdup(buf, GFP_KERNEL);
 }
 
@@ -495,6 +516,70 @@ static int xs_nospace(struct rpc_task *task)
        return ret;
 }
 
+/*
+ * Construct a stream transport record marker in @buf.
+ */
+static inline void xs_encode_stream_record_marker(struct xdr_buf *buf)
+{
+       u32 reclen = buf->len - sizeof(rpc_fraghdr);
+       rpc_fraghdr *base = buf->head[0].iov_base;
+       *base = cpu_to_be32(RPC_LAST_STREAM_FRAGMENT | reclen);
+}
+
+/**
+ * xs_local_send_request - write an RPC request to an AF_LOCAL socket
+ * @task: RPC task that manages the state of an RPC request
+ *
+ * Return values:
+ *        0:   The request has been sent
+ *   EAGAIN:   The socket was blocked, please call again later to
+ *             complete the request
+ * ENOTCONN:   Caller needs to invoke connect logic then call again
+ *    other:   Some other error occured, the request was not sent
+ */
+static int xs_local_send_request(struct rpc_task *task)
+{
+       struct rpc_rqst *req = task->tk_rqstp;
+       struct rpc_xprt *xprt = req->rq_xprt;
+       struct sock_xprt *transport =
+                               container_of(xprt, struct sock_xprt, xprt);
+       struct xdr_buf *xdr = &req->rq_snd_buf;
+       int status;
+
+       xs_encode_stream_record_marker(&req->rq_snd_buf);
+
+       xs_pktdump("packet data:",
+                       req->rq_svec->iov_base, req->rq_svec->iov_len);
+
+       status = xs_sendpages(transport->sock, NULL, 0,
+                                               xdr, req->rq_bytes_sent);
+       dprintk("RPC:       %s(%u) = %d\n",
+                       __func__, xdr->len - req->rq_bytes_sent, status);
+       if (likely(status >= 0)) {
+               req->rq_bytes_sent += status;
+               req->rq_xmit_bytes_sent += status;
+               if (likely(req->rq_bytes_sent >= req->rq_slen)) {
+                       req->rq_bytes_sent = 0;
+                       return 0;
+               }
+               status = -EAGAIN;
+       }
+
+       switch (status) {
+       case -EAGAIN:
+               status = xs_nospace(task);
+               break;
+       default:
+               dprintk("RPC:       sendmsg returned unrecognized error %d\n",
+                       -status);
+       case -EPIPE:
+               xs_close(xprt);
+               status = -ENOTCONN;
+       }
+
+       return status;
+}
+
 /**
  * xs_udp_send_request - write an RPC request to a UDP socket
  * @task: address of RPC task that manages the state of an RPC request
@@ -574,13 +659,6 @@ static void xs_tcp_shutdown(struct rpc_xprt *xprt)
                kernel_sock_shutdown(sock, SHUT_WR);
 }
 
-static inline void xs_encode_tcp_record_marker(struct xdr_buf *buf)
-{
-       u32 reclen = buf->len - sizeof(rpc_fraghdr);
-       rpc_fraghdr *base = buf->head[0].iov_base;
-       *base = htonl(RPC_LAST_STREAM_FRAGMENT | reclen);
-}
-
 /**
  * xs_tcp_send_request - write an RPC request to a TCP socket
  * @task: address of RPC task that manages the state of an RPC request
@@ -603,7 +681,7 @@ static int xs_tcp_send_request(struct rpc_task *task)
        struct xdr_buf *xdr = &req->rq_snd_buf;
        int status;
 
-       xs_encode_tcp_record_marker(&req->rq_snd_buf);
+       xs_encode_stream_record_marker(&req->rq_snd_buf);
 
        xs_pktdump("packet data:",
                                req->rq_svec->iov_base,
@@ -785,6 +863,88 @@ static inline struct rpc_xprt *xprt_from_sock(struct sock *sk)
        return (struct rpc_xprt *) sk->sk_user_data;
 }
 
+static int xs_local_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb)
+{
+       struct xdr_skb_reader desc = {
+               .skb            = skb,
+               .offset         = sizeof(rpc_fraghdr),
+               .count          = skb->len - sizeof(rpc_fraghdr),
+       };
+
+       if (xdr_partial_copy_from_skb(xdr, 0, &desc, xdr_skb_read_bits) < 0)
+               return -1;
+       if (desc.count)
+               return -1;
+       return 0;
+}
+
+/**
+ * xs_local_data_ready - "data ready" callback for AF_LOCAL sockets
+ * @sk: socket with data to read
+ * @len: how much data to read
+ *
+ * Currently this assumes we can read the whole reply in a single gulp.
+ */
+static void xs_local_data_ready(struct sock *sk, int len)
+{
+       struct rpc_task *task;
+       struct rpc_xprt *xprt;
+       struct rpc_rqst *rovr;
+       struct sk_buff *skb;
+       int err, repsize, copied;
+       u32 _xid;
+       __be32 *xp;
+
+       read_lock_bh(&sk->sk_callback_lock);
+       dprintk("RPC:       %s...\n", __func__);
+       xprt = xprt_from_sock(sk);
+       if (xprt == NULL)
+               goto out;
+
+       skb = skb_recv_datagram(sk, 0, 1, &err);
+       if (skb == NULL)
+               goto out;
+
+       if (xprt->shutdown)
+               goto dropit;
+
+       repsize = skb->len - sizeof(rpc_fraghdr);
+       if (repsize < 4) {
+               dprintk("RPC:       impossible RPC reply size %d\n", repsize);
+               goto dropit;
+       }
+
+       /* Copy the XID from the skb... */
+       xp = skb_header_pointer(skb, sizeof(rpc_fraghdr), sizeof(_xid), &_xid);
+       if (xp == NULL)
+               goto dropit;
+
+       /* Look up and lock the request corresponding to the given XID */
+       spin_lock(&xprt->transport_lock);
+       rovr = xprt_lookup_rqst(xprt, *xp);
+       if (!rovr)
+               goto out_unlock;
+       task = rovr->rq_task;
+
+       copied = rovr->rq_private_buf.buflen;
+       if (copied > repsize)
+               copied = repsize;
+
+       if (xs_local_copy_to_xdr(&rovr->rq_private_buf, skb)) {
+               dprintk("RPC:       sk_buff copy failed\n");
+               goto out_unlock;
+       }
+
+       xprt_complete_rqst(task, copied);
+
+ out_unlock:
+       spin_unlock(&xprt->transport_lock);
+ dropit:
+       skb_free_datagram(sk, skb);
+ out:
+       read_unlock_bh(&sk->sk_callback_lock);
+}
+
 /**
  * xs_udp_data_ready - "data ready" callback for UDP sockets
  * @sk: socket with data to read
@@ -1344,7 +1504,6 @@ static void xs_tcp_state_change(struct sock *sk)
        case TCP_CLOSE_WAIT:
                /* The server initiated a shutdown of the socket */
                xprt_force_disconnect(xprt);
-       case TCP_SYN_SENT:
                xprt->connect_cookie++;
        case TCP_CLOSING:
                /*
@@ -1571,11 +1730,31 @@ static int xs_bind(struct sock_xprt *transport, struct socket *sock)
        return err;
 }
 
+/*
+ * We don't support autobind on AF_LOCAL sockets
+ */
+static void xs_local_rpcbind(struct rpc_task *task)
+{
+       xprt_set_bound(task->tk_xprt);
+}
+
+static void xs_local_set_port(struct rpc_xprt *xprt, unsigned short port)
+{
+}
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 static struct lock_class_key xs_key[2];
 static struct lock_class_key xs_slock_key[2];
 
+static inline void xs_reclassify_socketu(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
+
+       BUG_ON(sock_owned_by_user(sk));
+       sock_lock_init_class_and_name(sk, "slock-AF_LOCAL-RPC",
+               &xs_slock_key[1], "sk_lock-AF_LOCAL-RPC", &xs_key[1]);
+}
+
 static inline void xs_reclassify_socket4(struct socket *sock)
 {
        struct sock *sk = sock->sk;
@@ -1597,6 +1776,9 @@ static inline void xs_reclassify_socket6(struct socket *sock)
 static inline void xs_reclassify_socket(int family, struct socket *sock)
 {
        switch (family) {
+       case AF_LOCAL:
+               xs_reclassify_socketu(sock);
+               break;
        case AF_INET:
                xs_reclassify_socket4(sock);
                break;
@@ -1606,6 +1788,10 @@ static inline void xs_reclassify_socket(int family, struct socket *sock)
        }
 }
 #else
+static inline void xs_reclassify_socketu(struct socket *sock)
+{
+}
+
 static inline void xs_reclassify_socket4(struct socket *sock)
 {
 }
@@ -1644,6 +1830,94 @@ out:
        return ERR_PTR(err);
 }
 
+static int xs_local_finish_connecting(struct rpc_xprt *xprt,
+                                     struct socket *sock)
+{
+       struct sock_xprt *transport = container_of(xprt, struct sock_xprt,
+                                                                       xprt);
+
+       if (!transport->inet) {
+               struct sock *sk = sock->sk;
+
+               write_lock_bh(&sk->sk_callback_lock);
+
+               xs_save_old_callbacks(transport, sk);
+
+               sk->sk_user_data = xprt;
+               sk->sk_data_ready = xs_local_data_ready;
+               sk->sk_write_space = xs_udp_write_space;
+               sk->sk_error_report = xs_error_report;
+               sk->sk_allocation = GFP_ATOMIC;
+
+               xprt_clear_connected(xprt);
+
+               /* Reset to new socket */
+               transport->sock = sock;
+               transport->inet = sk;
+
+               write_unlock_bh(&sk->sk_callback_lock);
+       }
+
+       /* Tell the socket layer to start connecting... */
+       xprt->stat.connect_count++;
+       xprt->stat.connect_start = jiffies;
+       return kernel_connect(sock, xs_addr(xprt), xprt->addrlen, 0);
+}
+
+/**
+ * xs_local_setup_socket - create AF_LOCAL socket, connect to a local endpoint
+ * @xprt: RPC transport to connect
+ * @transport: socket transport to connect
+ * @create_sock: function to create a socket of the correct type
+ *
+ * Invoked by a work queue tasklet.
+ */
+static void xs_local_setup_socket(struct work_struct *work)
+{
+       struct sock_xprt *transport =
+               container_of(work, struct sock_xprt, connect_worker.work);
+       struct rpc_xprt *xprt = &transport->xprt;
+       struct socket *sock;
+       int status = -EIO;
+
+       if (xprt->shutdown)
+               goto out;
+
+       clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
+       status = __sock_create(xprt->xprt_net, AF_LOCAL,
+                                       SOCK_STREAM, 0, &sock, 1);
+       if (status < 0) {
+               dprintk("RPC:       can't create AF_LOCAL "
+                       "transport socket (%d).\n", -status);
+               goto out;
+       }
+       xs_reclassify_socketu(sock);
+
+       dprintk("RPC:       worker connecting xprt %p via AF_LOCAL to %s\n",
+                       xprt, xprt->address_strings[RPC_DISPLAY_ADDR]);
+
+       status = xs_local_finish_connecting(xprt, sock);
+       switch (status) {
+       case 0:
+               dprintk("RPC:       xprt %p connected to %s\n",
+                               xprt, xprt->address_strings[RPC_DISPLAY_ADDR]);
+               xprt_set_connected(xprt);
+               break;
+       case -ENOENT:
+               dprintk("RPC:       xprt %p: socket %s does not exist\n",
+                               xprt, xprt->address_strings[RPC_DISPLAY_ADDR]);
+               break;
+       default:
+               printk(KERN_ERR "%s: unhandled error (%d) connecting to %s\n",
+                               __func__, -status,
+                               xprt->address_strings[RPC_DISPLAY_ADDR]);
+       }
+
+out:
+       xprt_clear_connecting(xprt);
+       xprt_wake_pending_tasks(xprt, status);
+}
+
 static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
 {
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
@@ -1758,6 +2032,7 @@ static void xs_tcp_reuse_connection(struct sock_xprt *transport)
 static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
 {
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+       int ret = -ENOTCONN;
 
        if (!transport->inet) {
                struct sock *sk = sock->sk;
@@ -1789,12 +2064,22 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
        }
 
        if (!xprt_bound(xprt))
-               return -ENOTCONN;
+               goto out;
 
        /* Tell the socket layer to start connecting... */
        xprt->stat.connect_count++;
        xprt->stat.connect_start = jiffies;
-       return kernel_connect(sock, xs_addr(xprt), xprt->addrlen, O_NONBLOCK);
+       ret = kernel_connect(sock, xs_addr(xprt), xprt->addrlen, O_NONBLOCK);
+       switch (ret) {
+       case 0:
+       case -EINPROGRESS:
+               /* SYN_SENT! */
+               xprt->connect_cookie++;
+               if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO)
+                       xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
+       }
+out:
+       return ret;
 }
 
 /**
@@ -1916,6 +2201,32 @@ static void xs_connect(struct rpc_task *task)
        }
 }
 
+/**
+ * xs_local_print_stats - display AF_LOCAL socket-specifc stats
+ * @xprt: rpc_xprt struct containing statistics
+ * @seq: output file
+ *
+ */
+static void xs_local_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
+{
+       long idle_time = 0;
+
+       if (xprt_connected(xprt))
+               idle_time = (long)(jiffies - xprt->last_used) / HZ;
+
+       seq_printf(seq, "\txprt:\tlocal %lu %lu %lu %ld %lu %lu %lu "
+                       "%llu %llu\n",
+                       xprt->stat.bind_count,
+                       xprt->stat.connect_count,
+                       xprt->stat.connect_time,
+                       idle_time,
+                       xprt->stat.sends,
+                       xprt->stat.recvs,
+                       xprt->stat.bad_xids,
+                       xprt->stat.req_u,
+                       xprt->stat.bklog_u);
+}
+
 /**
  * xs_udp_print_stats - display UDP socket-specifc stats
  * @xprt: rpc_xprt struct containing statistics
@@ -2014,10 +2325,7 @@ static int bc_sendto(struct rpc_rqst *req)
        unsigned long headoff;
        unsigned long tailoff;
 
-       /*
-        * Set up the rpc header and record marker stuff
-        */
-       xs_encode_tcp_record_marker(xbufp);
+       xs_encode_stream_record_marker(xbufp);
 
        tailoff = (unsigned long)xbufp->tail[0].iov_base & ~PAGE_MASK;
        headoff = (unsigned long)xbufp->head[0].iov_base & ~PAGE_MASK;
@@ -2089,6 +2397,21 @@ static void bc_destroy(struct rpc_xprt *xprt)
 {
 }
 
+static struct rpc_xprt_ops xs_local_ops = {
+       .reserve_xprt           = xprt_reserve_xprt,
+       .release_xprt           = xs_tcp_release_xprt,
+       .rpcbind                = xs_local_rpcbind,
+       .set_port               = xs_local_set_port,
+       .connect                = xs_connect,
+       .buf_alloc              = rpc_malloc,
+       .buf_free               = rpc_free,
+       .send_request           = xs_local_send_request,
+       .set_retrans_timeout    = xprt_set_retrans_timeout_def,
+       .close                  = xs_close,
+       .destroy                = xs_destroy,
+       .print_stats            = xs_local_print_stats,
+};
+
 static struct rpc_xprt_ops xs_udp_ops = {
        .set_buffer_size        = xs_udp_set_buffer_size,
        .reserve_xprt           = xprt_reserve_xprt_cong,
@@ -2150,6 +2473,8 @@ static int xs_init_anyaddr(const int family, struct sockaddr *sap)
        };
 
        switch (family) {
+       case AF_LOCAL:
+               break;
        case AF_INET:
                memcpy(sap, &sin, sizeof(sin));
                break;
@@ -2197,6 +2522,70 @@ static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
        return xprt;
 }
 
+static const struct rpc_timeout xs_local_default_timeout = {
+       .to_initval = 10 * HZ,
+       .to_maxval = 10 * HZ,
+       .to_retries = 2,
+};
+
+/**
+ * xs_setup_local - Set up transport to use an AF_LOCAL socket
+ * @args: rpc transport creation arguments
+ *
+ * AF_LOCAL is a "tpi_cots_ord" transport, just like TCP
+ */
+static struct rpc_xprt *xs_setup_local(struct xprt_create *args)
+{
+       struct sockaddr_un *sun = (struct sockaddr_un *)args->dstaddr;
+       struct sock_xprt *transport;
+       struct rpc_xprt *xprt;
+       struct rpc_xprt *ret;
+
+       xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries);
+       if (IS_ERR(xprt))
+               return xprt;
+       transport = container_of(xprt, struct sock_xprt, xprt);
+
+       xprt->prot = 0;
+       xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32);
+       xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;
+
+       xprt->bind_timeout = XS_BIND_TO;
+       xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
+       xprt->idle_timeout = XS_IDLE_DISC_TO;
+
+       xprt->ops = &xs_local_ops;
+       xprt->timeout = &xs_local_default_timeout;
+
+       switch (sun->sun_family) {
+       case AF_LOCAL:
+               if (sun->sun_path[0] != '/') {
+                       dprintk("RPC:       bad AF_LOCAL address: %s\n",
+                                       sun->sun_path);
+                       ret = ERR_PTR(-EINVAL);
+                       goto out_err;
+               }
+               xprt_set_bound(xprt);
+               INIT_DELAYED_WORK(&transport->connect_worker,
+                                       xs_local_setup_socket);
+               xs_format_peer_addresses(xprt, "local", RPCBIND_NETID_LOCAL);
+               break;
+       default:
+               ret = ERR_PTR(-EAFNOSUPPORT);
+               goto out_err;
+       }
+
+       dprintk("RPC:       set up xprt to %s via AF_LOCAL\n",
+                       xprt->address_strings[RPC_DISPLAY_ADDR]);
+
+       if (try_module_get(THIS_MODULE))
+               return xprt;
+       ret = ERR_PTR(-EINVAL);
+out_err:
+       xprt_free(xprt);
+       return ret;
+}
+
 static const struct rpc_timeout xs_udp_default_timeout = {
        .to_initval = 5 * HZ,
        .to_maxval = 30 * HZ,
@@ -2438,6 +2827,14 @@ out_err:
        return ret;
 }
 
+static struct xprt_class       xs_local_transport = {
+       .list           = LIST_HEAD_INIT(xs_local_transport.list),
+       .name           = "named UNIX socket",
+       .owner          = THIS_MODULE,
+       .ident          = XPRT_TRANSPORT_LOCAL,
+       .setup          = xs_setup_local,
+};
+
 static struct xprt_class       xs_udp_transport = {
        .list           = LIST_HEAD_INIT(xs_udp_transport.list),
        .name           = "udp",
@@ -2473,6 +2870,7 @@ int init_socket_xprt(void)
                sunrpc_table_header = register_sysctl_table(sunrpc_table);
 #endif
 
+       xprt_register_transport(&xs_local_transport);
        xprt_register_transport(&xs_udp_transport);
        xprt_register_transport(&xs_tcp_transport);
        xprt_register_transport(&xs_bc_tcp_transport);
@@ -2493,6 +2891,7 @@ void cleanup_socket_xprt(void)
        }
 #endif
 
+       xprt_unregister_transport(&xs_local_transport);
        xprt_unregister_transport(&xs_udp_transport);
        xprt_unregister_transport(&xs_tcp_transport);
        xprt_unregister_transport(&xs_bc_tcp_transport);
index b1d75beb7e20e8e3155a84be37161871023396ac..0722a25a3a33e6717b5e305d1cf0550b3abb9bb1 100644 (file)
@@ -2254,7 +2254,7 @@ static int unix_seq_show(struct seq_file *seq, void *v)
                struct unix_sock *u = unix_sk(s);
                unix_state_lock(s);
 
-               seq_printf(seq, "%p: %08X %08X %08X %04X %02X %5lu",
+               seq_printf(seq, "%pK: %08X %08X %08X %04X %02X %5lu",
                        s,
                        atomic_read(&s->sk_refcnt),
                        0,
index bf0fb40e3c8ba2eeac28292128e16e29fb4a7ff5..3dce1f167eba338a6a3c92d0c584636936600420 100644 (file)
@@ -245,6 +245,7 @@ struct cfg80211_event {
                        u16 status;
                } cr;
                struct {
+                       struct ieee80211_channel *channel;
                        u8 bssid[ETH_ALEN];
                        const u8 *req_ie;
                        const u8 *resp_ie;
@@ -392,7 +393,9 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
 int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
                        struct net_device *dev, u16 reason,
                        bool wextev);
-void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
+void __cfg80211_roamed(struct wireless_dev *wdev,
+                      struct ieee80211_channel *channel,
+                      const u8 *bssid,
                       const u8 *req_ie, size_t req_ie_len,
                       const u8 *resp_ie, size_t resp_ie_len);
 int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
index 2222ce08ee91ea8d82e8c8222451c4af1bb4c5ef..98fa8eb6cc4bec27e6adbf737c3653392da32adc 100644 (file)
@@ -3294,8 +3294,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct net_device *dev = info->user_ptr[1];
        struct cfg80211_scan_request *request;
-       struct cfg80211_ssid *ssid;
-       struct ieee80211_channel *channel;
        struct nlattr *attr;
        struct wiphy *wiphy;
        int err, tmp, n_ssids = 0, n_channels, i;
@@ -3342,8 +3340,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                return -EINVAL;
 
        request = kzalloc(sizeof(*request)
-                       + sizeof(*ssid) * n_ssids
-                       + sizeof(channel) * n_channels
+                       + sizeof(*request->ssids) * n_ssids
+                       + sizeof(*request->channels) * n_channels
                        + ie_len, GFP_KERNEL);
        if (!request)
                return -ENOMEM;
@@ -3408,12 +3406,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        i = 0;
        if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) {
                nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
-                       if (request->ssids[i].ssid_len > IEEE80211_MAX_SSID_LEN) {
+                       if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
                                err = -EINVAL;
                                goto out_free;
                        }
-                       memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
                        request->ssids[i].ssid_len = nla_len(attr);
+                       memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
                        i++;
                }
        }
@@ -3449,8 +3447,6 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
        struct cfg80211_sched_scan_request *request;
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct net_device *dev = info->user_ptr[1];
-       struct cfg80211_ssid *ssid;
-       struct ieee80211_channel *channel;
        struct nlattr *attr;
        struct wiphy *wiphy;
        int err, tmp, n_ssids = 0, n_channels, i;
@@ -3507,8 +3503,8 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
                return -EINVAL;
 
        request = kzalloc(sizeof(*request)
-                       + sizeof(*ssid) * n_ssids
-                       + sizeof(channel) * n_channels
+                       + sizeof(*request->ssids) * n_ssids
+                       + sizeof(*request->channels) * n_channels
                        + ie_len, GFP_KERNEL);
        if (!request)
                return -ENOMEM;
@@ -3576,14 +3572,13 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
        if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) {
                nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS],
                                    tmp) {
-                       if (request->ssids[i].ssid_len >
-                           IEEE80211_MAX_SSID_LEN) {
+                       if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
                                err = -EINVAL;
                                goto out_free;
                        }
+                       request->ssids[i].ssid_len = nla_len(attr);
                        memcpy(request->ssids[i].ssid, nla_data(attr),
                               nla_len(attr));
-                       request->ssids[i].ssid_len = nla_len(attr);
                        i++;
                }
        }
index 73a441d237b59ea89eaef14598299877459a3f61..7a6c67667d708e97400a6974175323f7cfd712e6 100644 (file)
@@ -267,13 +267,35 @@ static bool is_bss(struct cfg80211_bss *a,
        return memcmp(ssidie + 2, ssid, ssid_len) == 0;
 }
 
+static bool is_mesh_bss(struct cfg80211_bss *a)
+{
+       const u8 *ie;
+
+       if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability))
+               return false;
+
+       ie = cfg80211_find_ie(WLAN_EID_MESH_ID,
+                             a->information_elements,
+                             a->len_information_elements);
+       if (!ie)
+               return false;
+
+       ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG,
+                             a->information_elements,
+                             a->len_information_elements);
+       if (!ie)
+               return false;
+
+       return true;
+}
+
 static bool is_mesh(struct cfg80211_bss *a,
                    const u8 *meshid, size_t meshidlen,
                    const u8 *meshcfg)
 {
        const u8 *ie;
 
-       if (!WLAN_CAPABILITY_IS_MBSS(a->capability))
+       if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability))
                return false;
 
        ie = cfg80211_find_ie(WLAN_EID_MESH_ID,
@@ -311,7 +333,7 @@ static int cmp_bss(struct cfg80211_bss *a,
        if (a->channel != b->channel)
                return b->channel->center_freq - a->channel->center_freq;
 
-       if (WLAN_CAPABILITY_IS_MBSS(a->capability | b->capability)) {
+       if (is_mesh_bss(a) && is_mesh_bss(b)) {
                r = cmp_ies(WLAN_EID_MESH_ID,
                            a->information_elements,
                            a->len_information_elements,
@@ -457,7 +479,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
                    struct cfg80211_internal_bss *res)
 {
        struct cfg80211_internal_bss *found = NULL;
-       const u8 *meshid, *meshcfg;
 
        /*
         * The reference to "res" is donated to this function.
@@ -470,22 +491,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 
        res->ts = jiffies;
 
-       if (WLAN_CAPABILITY_IS_MBSS(res->pub.capability)) {
-               /* must be mesh, verify */
-               meshid = cfg80211_find_ie(WLAN_EID_MESH_ID,
-                                         res->pub.information_elements,
-                                         res->pub.len_information_elements);
-               meshcfg = cfg80211_find_ie(WLAN_EID_MESH_CONFIG,
-                                          res->pub.information_elements,
-                                          res->pub.len_information_elements);
-               if (!meshid || !meshcfg ||
-                   meshcfg[1] != sizeof(struct ieee80211_meshconf_ie)) {
-                       /* bogus mesh */
-                       kref_put(&res->ref, bss_release);
-                       return NULL;
-               }
-       }
-
        spin_lock_bh(&dev->bss_lock);
 
        found = rb_find_bss(dev, res);
index e17b0bee6bdc7b8e0b6d74a401ea9df3bdf7e977..b7b6ff8be553a10f7a0191ac04f09eeaff06463c 100644 (file)
@@ -250,7 +250,8 @@ static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
        if (wdev->conn->params.privacy)
                capa |= WLAN_CAPABILITY_PRIVACY;
 
-       bss = cfg80211_get_bss(wdev->wiphy, NULL, wdev->conn->params.bssid,
+       bss = cfg80211_get_bss(wdev->wiphy, wdev->conn->params.channel,
+                              wdev->conn->params.bssid,
                               wdev->conn->params.ssid,
                               wdev->conn->params.ssid_len,
                               WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY,
@@ -470,7 +471,10 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
        }
 
        if (!bss)
-               bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
+               bss = cfg80211_get_bss(wdev->wiphy,
+                                      wdev->conn ? wdev->conn->params.channel :
+                                      NULL,
+                                      bssid,
                                       wdev->ssid, wdev->ssid_len,
                                       WLAN_CAPABILITY_ESS,
                                       WLAN_CAPABILITY_ESS);
@@ -538,7 +542,9 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 }
 EXPORT_SYMBOL(cfg80211_connect_result);
 
-void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
+void __cfg80211_roamed(struct wireless_dev *wdev,
+                      struct ieee80211_channel *channel,
+                      const u8 *bssid,
                       const u8 *req_ie, size_t req_ie_len,
                       const u8 *resp_ie, size_t resp_ie_len)
 {
@@ -565,7 +571,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
        cfg80211_put_bss(&wdev->current_bss->pub);
        wdev->current_bss = NULL;
 
-       bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
+       bss = cfg80211_get_bss(wdev->wiphy, channel, bssid,
                               wdev->ssid, wdev->ssid_len,
                               WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
 
@@ -603,7 +609,9 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
 #endif
 }
 
-void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
+void cfg80211_roamed(struct net_device *dev,
+                    struct ieee80211_channel *channel,
+                    const u8 *bssid,
                     const u8 *req_ie, size_t req_ie_len,
                     const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
 {
@@ -619,6 +627,7 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
                return;
 
        ev->type = EVENT_ROAMED;
+       ev->rm.channel = channel;
        memcpy(ev->rm.bssid, bssid, ETH_ALEN);
        ev->rm.req_ie = ((u8 *)ev) + sizeof(*ev);
        ev->rm.req_ie_len = req_ie_len;
index f0536d44d43c18e11b54b8f060f8e1b5da42709d..4d7b83fbc32f0eb042e3a70e23d01d626a5add04 100644 (file)
@@ -746,7 +746,7 @@ static void cfg80211_process_wdev_events(struct wireless_dev *wdev)
                                NULL);
                        break;
                case EVENT_ROAMED:
-                       __cfg80211_roamed(wdev, ev->rm.bssid,
+                       __cfg80211_roamed(wdev, ev->rm.channel, ev->rm.bssid,
                                          ev->rm.req_ie, ev->rm.req_ie_len,
                                          ev->rm.resp_ie, ev->rm.resp_ie_len);
                        break;
index 47f1b8638df9987dca1cf7ad2bbce5c674044881..b11ea692bd7d0870c8586e115bcfc6b6a69c2997 100644 (file)
@@ -265,7 +265,7 @@ static void xfrm_replay_advance_bmp(struct xfrm_state *x, __be32 net_seq)
                        bitnr = bitnr & 0x1F;
                        replay_esn->bmp[nr] |= (1U << bitnr);
                } else {
-                       nr = replay_esn->replay_window >> 5;
+                       nr = (replay_esn->replay_window - 1) >> 5;
                        for (i = 0; i <= nr; i++)
                                replay_esn->bmp[i] = 0;
 
@@ -471,7 +471,7 @@ static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq)
                        bitnr = bitnr & 0x1F;
                        replay_esn->bmp[nr] |= (1U << bitnr);
                } else {
-                       nr = replay_esn->replay_window >> 5;
+                       nr = (replay_esn->replay_window - 1) >> 5;
                        for (i = 0; i <= nr; i++)
                                replay_esn->bmp[i] = 0;
 
index e2741d23bab8c2343a928e402b063bcc0f251a0d..105b21f0818597e4c881e3f1b7e4f286616cc8d9 100644 (file)
@@ -8,3 +8,4 @@ bin2c
 unifdef
 ihex2fw
 recordmcount
+docproc
index ed2773edfe71bae99adc0a7b64a454912dfd4477..be39cd1c74cff6009eac1120c1eafe18085ed37e 100644 (file)
@@ -118,6 +118,11 @@ cc-option-yn = $(call try-run,\
 cc-option-align = $(subst -functions=0,,\
        $(call cc-option,-falign-functions=0,-malign-functions=0))
 
+# cc-disable-warning
+# Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable)
+cc-disable-warning = $(call try-run,\
+       $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -xc /dev/null -o "$$TMP",-Wno-$(strip $(1)))
+
 # cc-version
 # Usage gcc-ver := $(call cc-version)
 cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
@@ -141,6 +146,11 @@ cc-ldoption = $(call try-run,\
 ld-option = $(call try-run,\
        $(CC) /dev/null -c -o "$$TMPO" ; $(LD) $(1) "$$TMPO" -o "$$TMP",$(1),$(2))
 
+# ar-option
+# Usage: KBUILD_ARFLAGS := $(call ar-option,D)
+# Important: no spaces around options
+ar-option = $(call try-run, $(AR) rc$(1) "$$TMP",$(1),$(2))
+
 ######
 
 ###
@@ -187,6 +197,8 @@ ifneq ($(KBUILD_NOCMDDEP),1)
 # User may override this check using make KBUILD_NOCMDDEP=1
 arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
                     $(filter-out $(cmd_$@),   $(cmd_$(1))) )
+else
+arg-check = $(if $(strip $(cmd_$@)),,1)
 endif
 
 # >'< substitution is for echo to work,
index fcea26168bca718afb07cf4a2a71081b309e906e..df7678febf277b119cbffc4d3b6f230974fb18f0 100644 (file)
@@ -6,6 +6,7 @@
 # pnmttologo:    Convert pnm files to logo files
 # conmakehash:   Create chartable
 # conmakehash:  Create arrays for initializing the kernel console tables
+# docproc:       Used in Documentation/DocBook
 
 hostprogs-$(CONFIG_KALLSYMS)     += kallsyms
 hostprogs-$(CONFIG_LOGO)         += pnmtologo
@@ -16,12 +17,14 @@ hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
 always         := $(hostprogs-y) $(hostprogs-m)
 
 # The following hostprogs-y programs are only build on demand
-hostprogs-y += unifdef
+hostprogs-y += unifdef docproc
 
-# This target is used internally to avoid "is up to date" messages
+# These targets are used internally to avoid "is up to date" messages
 PHONY += build_unifdef
 build_unifdef: scripts/unifdef FORCE
        @:
+build_docproc: scripts/docproc FORCE
+       @:
 
 subdir-$(CONFIG_MODVERSIONS) += genksyms
 subdir-y                     += mod
diff --git a/scripts/Makefile.asm-generic b/scripts/Makefile.asm-generic
new file mode 100644 (file)
index 0000000..40caf3c
--- /dev/null
@@ -0,0 +1,24 @@
+# include/asm-generic contains a lot of files that are used
+# verbatim by several architectures.
+#
+# This Makefile reads the file arch/$(SRCARCH)/include/asm/Kbuild
+# and for each file listed in this file with generic-y creates
+# a small wrapper file in $(obj) (arch/$(SRCARCH)/include/generated/asm)
+
+kbuild-file := $(srctree)/arch/$(SRCARCH)/include/asm/Kbuild
+-include $(kbuild-file)
+
+include scripts/Kbuild.include
+
+# Create output directory if not already present
+_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj))
+
+quiet_cmd_wrap = WRAP    $@
+cmd_wrap = echo "\#include <asm-generic/$*.h>" >$@
+
+all: $(patsubst %, $(obj)/%, $(generic-y))
+       @:
+
+$(obj)/%.h:
+       $(call cmd,wrap)
+
index 6165622c3e29ae4cb395a1182045a905b603d7f4..a0fd5029cfe78c8d082409b3228a59998b15eaa2 100644 (file)
@@ -51,36 +51,52 @@ ifeq ($(KBUILD_NOPEDANTIC),)
 endif
 
 #
-# make W=1 settings
+# make W=... settings
 #
-# $(call cc-option... ) handles gcc -W.. options which
+# W=1 - warnings that may be relevant and does not occur too often
+# W=2 - warnings that occur quite often but may still be relevant
+# W=3 - the more obscure warnings, can most likely be ignored
+#
+# $(call cc-option, -W...) handles gcc -W.. options which
 # are not supported by all versions of the compiler
 ifdef KBUILD_ENABLE_EXTRA_GCC_CHECKS
-KBUILD_EXTRA_WARNINGS := -Wextra
-KBUILD_EXTRA_WARNINGS += -Wunused -Wno-unused-parameter
-KBUILD_EXTRA_WARNINGS += -Waggregate-return
-KBUILD_EXTRA_WARNINGS += -Wbad-function-cast
-KBUILD_EXTRA_WARNINGS += -Wcast-qual
-KBUILD_EXTRA_WARNINGS += -Wcast-align
-KBUILD_EXTRA_WARNINGS += -Wconversion
-KBUILD_EXTRA_WARNINGS += -Wdisabled-optimization
-KBUILD_EXTRA_WARNINGS += -Wlogical-op
-KBUILD_EXTRA_WARNINGS += -Wmissing-declarations
-KBUILD_EXTRA_WARNINGS += -Wmissing-format-attribute
-KBUILD_EXTRA_WARNINGS += $(call cc-option, -Wmissing-include-dirs,)
-KBUILD_EXTRA_WARNINGS += -Wmissing-prototypes
-KBUILD_EXTRA_WARNINGS += -Wnested-externs
-KBUILD_EXTRA_WARNINGS += -Wold-style-definition
-KBUILD_EXTRA_WARNINGS += $(call cc-option, -Woverlength-strings,)
-KBUILD_EXTRA_WARNINGS += -Wpacked
-KBUILD_EXTRA_WARNINGS += -Wpacked-bitfield-compat
-KBUILD_EXTRA_WARNINGS += -Wpadded
-KBUILD_EXTRA_WARNINGS += -Wpointer-arith
-KBUILD_EXTRA_WARNINGS += -Wredundant-decls
-KBUILD_EXTRA_WARNINGS += -Wshadow
-KBUILD_EXTRA_WARNINGS += -Wswitch-default
-KBUILD_EXTRA_WARNINGS += $(call cc-option, -Wvla,)
-KBUILD_CFLAGS += $(KBUILD_EXTRA_WARNINGS)
+warning-  := $(empty)
+
+warning-1 := -Wextra -Wunused -Wno-unused-parameter
+warning-1 += -Wmissing-declarations
+warning-1 += -Wmissing-format-attribute
+warning-1 += -Wmissing-prototypes
+warning-1 += -Wold-style-definition
+warning-1 += $(call cc-option, -Wmissing-include-dirs)
+warning-1 += $(call cc-option, -Wunused-but-set-variable)
+
+warning-2 := -Waggregate-return
+warning-2 += -Wcast-align
+warning-2 += -Wdisabled-optimization
+warning-2 += -Wnested-externs
+warning-2 += -Wshadow
+warning-2 += $(call cc-option, -Wlogical-op)
+
+warning-3 := -Wbad-function-cast
+warning-3 += -Wcast-qual
+warning-3 += -Wconversion
+warning-3 += -Wpacked
+warning-3 += -Wpadded
+warning-3 += -Wpointer-arith
+warning-3 += -Wredundant-decls
+warning-3 += -Wswitch-default
+warning-3 += $(call cc-option, -Wpacked-bitfield-compat)
+warning-3 += $(call cc-option, -Wvla)
+
+warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
+warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
+warning += $(warning-$(findstring 3, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
+
+ifeq ("$(strip $(warning))","")
+        $(error W=$(KBUILD_ENABLE_EXTRA_GCC_CHECKS) is unknown)
+endif
+
+KBUILD_CFLAGS += $(warning)
 endif
 
 include scripts/Makefile.lib
@@ -351,7 +367,7 @@ quiet_cmd_link_o_target = LD      $@
 cmd_link_o_target = $(if $(strip $(obj-y)),\
                      $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
                      $(cmd_secanalysis),\
-                     rm -f $@; $(AR) rcs $@)
+                     rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@)
 
 $(builtin-target): $(obj-y) FORCE
        $(call if_changed,link_o_target)
@@ -377,7 +393,7 @@ $(modorder-target): $(subdir-ym) FORCE
 #
 ifdef lib-target
 quiet_cmd_link_l_target = AR      $@
-cmd_link_l_target = rm -f $@; $(AR) rcs $@ $(lib-y)
+cmd_link_l_target = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@ $(lib-y)
 
 $(lib-target): $(lib-y) FORCE
        $(call if_changed,link_l_target)
index f89cb87f5c018f24b56e13201530df261379c230..a57f5bd5a13d5b8f14a90b03bf23115e925b4a0a 100644 (file)
@@ -27,8 +27,13 @@ header-y      := $(filter-out %/, $(header-y))
 install-file  := $(install)/.install
 check-file    := $(install)/.check
 
+# generic-y list all files an architecture uses from asm-generic
+# Use this to build a list of headers which require a wrapper
+wrapper-files := $(filter $(header-y), $(generic-y))
+
 # all headers files for this dir
-all-files     := $(header-y) $(objhdr-y)
+header-y      := $(filter-out $(generic-y), $(header-y))
+all-files     := $(header-y) $(objhdr-y) $(wrapper-files)
 input-files   := $(addprefix $(srctree)/$(obj)/,$(header-y)) \
                  $(addprefix $(objtree)/$(obj)/,$(objhdr-y))
 output-files  := $(addprefix $(install)/, $(all-files))
@@ -47,6 +52,9 @@ quiet_cmd_install = INSTALL $(printdir) ($(words $(all-files))\
       cmd_install = \
         $(PERL) $< $(srctree)/$(obj) $(install) $(SRCARCH) $(header-y); \
         $(PERL) $< $(objtree)/$(obj) $(install) $(SRCARCH) $(objhdr-y); \
+        for F in $(wrapper-files); do                                   \
+                echo "\#include <asm-generic/$$F>" > $(install)/$$F;    \
+        done;                                                           \
         touch $@
 
 quiet_cmd_remove = REMOVE  $(unwanted)
index 1c702ca8aac81d853ac19c204d126c30dff639cb..93b2b5938a2e9e714590ca9728ec53a39763db06 100644 (file)
@@ -197,7 +197,7 @@ cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
 # ---------------------------------------------------------------------------
 
 quiet_cmd_gzip = GZIP    $@
-cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -f -9 > $@) || \
+cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \
        (rm -f $@ ; false)
 
 # DTC
index bf8b199ec598d591946f6cf070e3ccfd01ee5a52..a776371a350243330b14dc87b636146ba4ef2b16 100644 (file)
@@ -1,3 +1 @@
-hash
 fixdep
-docproc
index 4c324a1f1e0efb8668b4d64e05b56e8e0f64f25b..4fcef87bb8759894435a395224c7d92cd7a14214 100644 (file)
@@ -7,9 +7,8 @@
 # .config is included by main Makefile.
 # ---------------------------------------------------------------------------
 # fixdep:       Used to generate dependency information during build process
-# docproc:      Used in Documentation/DocBook
 
-hostprogs-y    := fixdep docproc
+hostprogs-y    := fixdep
 always         := $(hostprogs-y)
 
 # fixdep is needed to compile other host programs
index d8670810db65f664623a18f991a88a7a72a00d5b..b0aa2c680593d0c09857b9447d54ef933861ed3b 100755 (executable)
@@ -210,10 +210,10 @@ our $typeTypedefs = qr{(?x:
 
 our $logFunctions = qr{(?x:
        printk|
-       pr_(debug|dbg|vdbg|devel|info|warning|err|notice|alert|crit|emerg|cont)|
-       (dev|netdev|netif)_(printk|dbg|vdbg|info|warn|err|notice|alert|crit|emerg|WARN)|
+       [a-z]+_(emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)|
        WARN|
-       panic
+       panic|
+       MODULE_[A-Z_]+
 )};
 
 our @typeList = (
@@ -1462,7 +1462,7 @@ sub process {
 #80 column limit
                if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&
                    $rawline !~ /^.\s*\*\s*\@$Ident\s/ &&
-                   !($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?"[X\t]*"\s*(?:,|\)\s*;)\s*$/ ||
+                   !($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?"[X\t]*"\s*(?:|,|\)\s*;)\s*$/ ||
                    $line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/) &&
                    $length > 80)
                {
@@ -1943,6 +1943,11 @@ sub process {
                        WARN("LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr);
                }
 
+# check for uses of printk_ratelimit
+               if ($line =~ /\bprintk_ratelimit\s*\(/) {
+                       WARN("Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit\n" . $herecurr);
+               }
+
 # printk should use KERN_* levels.  Note that follow on printk's on the
 # same line do not need a level, so we use the current block context
 # to try and find and validate the current printk.  In summary the current
@@ -2748,6 +2753,11 @@ sub process {
                        WARN("sizeof(& should be avoided\n" . $herecurr);
                }
 
+# check for line continuations in quoted strings with odd counts of "
+               if ($rawline =~ /\\$/ && $rawline =~ tr/"/"/ % 2) {
+                       WARN("Avoid line continuations in quoted strings\n" . $herecurr);
+               }
+
 # check for new externs in .c files.
                if ($realfile =~ /\.c$/ && defined $stat &&
                    $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s)
index b444e89a0095dc16d207fb23a7600a148c67834b..5e490a8ceca5582e3003890cf34a21c33447969f 100755 (executable)
@@ -12,6 +12,7 @@ $| = 1;
 my $debugging;
 
 foreach my $file (@ARGV) {
+    next if $file =~ "include/linux/version\.h";
     # Open this file.
     open( my $f, '<', $file )
       or die "Can't open $file: $!\n";
diff --git a/scripts/depmod.sh b/scripts/depmod.sh
new file mode 100755 (executable)
index 0000000..3b029cb
--- /dev/null
@@ -0,0 +1,48 @@
+#!/bin/sh
+#
+# A depmod wrapper used by the toplevel Makefile
+
+if test $# -ne 2; then
+       echo "Usage: $0 /sbin/depmod <kernelrelease>" >&2
+       exit 1
+fi
+DEPMOD=$1
+KERNELRELEASE=$2
+
+if ! "$DEPMOD" -V 2>/dev/null | grep -q module-init-tools; then
+       echo "Warning: you may need to install module-init-tools" >&2
+       echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt" >&2
+       sleep 1
+fi
+
+if ! test -r System.map -a -x "$DEPMOD"; then
+       exit 0
+fi
+# older versions of depmod require the version string to start with three
+# numbers, so we cheat with a symlink here
+depmod_hack_needed=true
+mkdir -p .tmp_depmod/lib/modules/$KERNELRELEASE
+if "$DEPMOD" -b .tmp_depmod $KERNELRELEASE 2>/dev/null; then
+       if test -e .tmp_depmod/lib/modules/$KERNELRELEASE/modules.dep -o \
+               -e .tmp_depmod/lib/modules/$KERNELRELEASE/modules.dep.bin; then
+               depmod_hack_needed=false
+       fi
+fi
+if $depmod_hack_needed; then
+       symlink="$INSTALL_MOD_PATH/lib/modules/99.98.$KERNELRELEASE"
+       ln -s "$KERNELRELEASE" "$symlink"
+       KERNELRELEASE=99.98.$KERNELRELEASE
+fi
+
+set -- -ae -F System.map
+if test -n "$INSTALL_MOD_PATH"; then
+       set -- "$@" -b "$INSTALL_MOD_PATH"
+fi
+"$DEPMOD" "$@" "$KERNELRELEASE"
+ret=$?
+
+if $depmod_hack_needed; then
+       rm -f "$symlink"
+fi
+
+exit $ret
similarity index 100%
rename from scripts/basic/docproc.c
rename to scripts/docproc.c
index 04dce7c15f8328c71f3ce5f6bff4ef9ef0882eac..8f79b701de876a807ae76abd89ad077d65ef3390 100644 (file)
@@ -25,11 +25,12 @@ sub alphabetically {
 sub print_depends_on {
        my ($href) = @_;
        print "\n";
-       while (my ($mod, $list) = each %$href) {
+       for my $mod (sort keys %$href) {
+               my $list = $href->{$mod};
                print "\t$mod:\n";
                foreach my $sym (sort numerically @{$list}) {
                        my ($symbol, $no) = split /\s+/, $sym;
-                       printf("\t\t%-25s\t%-25d\n", $symbol, $no);
+                       printf("\t\t%-25s\n", $symbol);
                }
                print "\n";
        }
@@ -49,8 +50,14 @@ sub usage {
 }
 
 sub collectcfiles {
-    my @file
-       = `cat .tmp_versions/*.mod | grep '.*\.ko\$' | sed s/\.ko$/.mod.c/`;
+    my @file;
+    while (<.tmp_versions/*.mod>) {
+       open my $fh, '<', $_ or die "cannot open $_: $!\n";
+       push (@file,
+             grep s/\.ko/.mod.c/,      # change the suffix
+             grep m/.+\.ko/,           # find the .ko path
+             <$fh>);                   # lines in opened file
+    }
     chomp @file;
     return @file;
 }
@@ -95,6 +102,8 @@ close($module_symvers);
 #
 # collect the usage count of each symbol.
 #
+my $modversion_warnings = 0;
+
 foreach my $thismod (@allcfiles) {
        my $module;
 
@@ -125,7 +134,8 @@ foreach my $thismod (@allcfiles) {
                }
        }
        if ($state != 2) {
-               print "WARNING:$thismod is not built with CONFIG_MODVERSION enabled\n";
+               warn "WARNING:$thismod is not built with CONFIG_MODVERSIONS enabled\n";
+               $modversion_warnings++;
        }
        close($module);
 }
@@ -159,8 +169,12 @@ printf("SECTION 2:\n\tThis section reports export-symbol-usage of in-kernel
 modules. Each module lists the modules, and the symbols from that module that
 it uses.  Each listed symbol reports the number of modules using it\n");
 
+print "\nNOTE: Got $modversion_warnings CONFIG_MODVERSIONS warnings\n\n"
+    if $modversion_warnings;
+
 print "~"x80 , "\n";
-while (my ($thismod, $list) = each %MODULE) {
+for my $thismod (sort keys %MODULE) {
+       my $list = $MODULE{$thismod};
        my %depends;
        $thismod =~ s/\.mod\.c/.ko/;
        print "\t\t\t$thismod\n";
index e12b1a7525cf0b040c10252670cd98ae89566b42..b482f162a18af48e6e83f6097581a317d64b194f 100644 (file)
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 # Copyright (C) Martin Schlemmer <azarah@nosferatu.za.org>
 # Copyright (C) 2006 Sam Ravnborg <sam@ravnborg.org>
 #
@@ -105,9 +105,9 @@ list_parse() {
 # for links, devices etc the format differs. See gen_init_cpio for details
 parse() {
        local location="$1"
-       local name="${location/${srcdir}//}"
+       local name="/${location#${srcdir}}"
        # change '//' into '/'
-       name="${name//\/\///}"
+       name=$(echo "$name" | sed -e 's://*:/:g')
        local mode="$2"
        local uid="$3"
        local gid="$4"
@@ -117,8 +117,8 @@ parse() {
        [ "$root_gid" = "squash" ] && gid=0 || [ "$gid" -eq "$root_gid" ] && gid=0
        local str="${mode} ${uid} ${gid}"
 
-       [ "${ftype}" == "invalid" ] && return 0
-       [ "${location}" == "${srcdir}" ] && return 0
+       [ "${ftype}" = "invalid" ] && return 0
+       [ "${location}" = "${srcdir}" ] && return 0
 
        case "${ftype}" in
                "file")
@@ -192,7 +192,7 @@ input_file() {
        if [ -f "$1" ]; then
                ${dep_list}header "$1"
                is_cpio="$(echo "$1" | sed 's/^.*\.cpio\(\..*\)\?/cpio/')"
-               if [ $2 -eq 0 -a ${is_cpio} == "cpio" ]; then
+               if [ $2 -eq 0 -a ${is_cpio} = "cpio" ]; then
                        cpio_file=$1
                        echo "$1" | grep -q '^.*\.cpio\..*' && is_cpio_compressed="compressed"
                        [ ! -z ${dep_list} ] && echo "$1"
@@ -204,7 +204,7 @@ input_file() {
                else
                        echo "$1 \\"
                        cat "$1" | while read type dir file perm ; do
-                               if [ "$type" == "file" ]; then
+                               if [ "$type" = "file" ]; then
                                        echo "$file \\";
                                fi
                        done
@@ -226,7 +226,7 @@ cpio_list=
 output="/dev/stdout"
 output_file=""
 is_cpio_compressed=
-compr="gzip -9 -f"
+compr="gzip -n -9 -f"
 
 arg="$1"
 case "$arg" in
@@ -240,7 +240,7 @@ case "$arg" in
                output_file="$1"
                cpio_list="$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX)"
                output=${cpio_list}
-               echo "$output_file" | grep -q "\.gz$" && compr="gzip -9 -f"
+               echo "$output_file" | grep -q "\.gz$" && compr="gzip -n -9 -f"
                echo "$output_file" | grep -q "\.bz2$" && compr="bzip2 -9 -f"
                echo "$output_file" | grep -q "\.lzma$" && compr="lzma -9 -f"
                echo "$output_file" | grep -q "\.xz$" && \
@@ -287,8 +287,15 @@ done
 # we are careful to delete tmp files
 if [ ! -z ${output_file} ]; then
        if [ -z ${cpio_file} ]; then
+               timestamp=
+               if test -n "$KBUILD_BUILD_TIMESTAMP"; then
+                       timestamp="$(date -d"$KBUILD_BUILD_TIMESTAMP" +%s || :)"
+                       if test -n "$timestamp"; then
+                               timestamp="-t $timestamp"
+                       fi
+               fi
                cpio_tfile="$(mktemp ${TMPDIR:-/tmp}/cpiofile.XXXXXX)"
-               usr/gen_init_cpio ${cpio_list} > ${cpio_tfile}
+               usr/gen_init_cpio $timestamp ${cpio_list} > ${cpio_tfile}
        else
                cpio_tfile=${cpio_file}
        fi
index 60dd3eb9366e4c5404383285df6cee3886bfa699..487ac6f37ca23ce2d1e832fa177d74d4544386bf 100644 (file)
@@ -500,6 +500,8 @@ static void optimize_result(void)
 
                        /* find the token with the breates profit value */
                        best = find_best_token();
+                       if (token_profit[best] == 0)
+                               break;
 
                        /* place it in the "best" table */
                        best_table_len[i] = 2;
index 368ae306aee45a42fbcee26274b491af512afbf0..faa9a4701b6f27259b9f0094aa9ee3584f237fe4 100644 (file)
@@ -77,14 +77,15 @@ localyesconfig: $(obj)/streamline_config.pl $(obj)/conf
 # The symlink is used to repair a deficiency in arch/um
 update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
        $(Q)echo "  GEN config"
-       $(Q)xgettext --default-domain=linux              \
-           --add-comments --keyword=_ --keyword=N_      \
-           --from-code=UTF-8                            \
-           --files-from=scripts/kconfig/POTFILES.in     \
+       $(Q)xgettext --default-domain=linux                         \
+           --add-comments --keyword=_ --keyword=N_                 \
+           --from-code=UTF-8                                       \
+           --files-from=$(srctree)/scripts/kconfig/POTFILES.in     \
+           --directory=$(srctree) --directory=$(objtree)           \
            --output $(obj)/config.pot
        $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot
-       $(Q)ln -fs Kconfig.i386 arch/um/Kconfig.arch
-       $(Q)(for i in `ls arch/*/Kconfig`;               \
+       $(Q)ln -fs Kconfig.x86 arch/um/Kconfig
+       $(Q)(for i in `ls $(srctree)/arch/*/Kconfig`;    \
            do                                           \
                echo "  GEN $$i";                        \
                $(obj)/kxgettext $$i                     \
@@ -92,7 +93,7 @@ update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
            done )
        $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
            --output $(obj)/linux.pot
-       $(Q)rm -f arch/um/Kconfig.arch
+       $(Q)rm -f $(srctree)/arch/um/Kconfig
        $(Q)rm -f $(obj)/config.pot
 
 PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig
@@ -168,8 +169,11 @@ conf-objs  := conf.o  zconf.tab.o
 mconf-objs     := mconf.o zconf.tab.o $(lxdialog)
 nconf-objs     := nconf.o zconf.tab.o nconf.gui.o
 kxgettext-objs := kxgettext.o zconf.tab.o
+qconf-cxxobjs  := qconf.o
+qconf-objs     := kconfig_load.o zconf.tab.o
+gconf-objs     := gconf.o kconfig_load.o zconf.tab.o
 
-hostprogs-y := conf qconf gconf kxgettext
+hostprogs-y := conf
 
 ifeq ($(MAKECMDGOALS),nconfig)
        hostprogs-y += nconf
@@ -179,6 +183,10 @@ ifeq ($(MAKECMDGOALS),menuconfig)
        hostprogs-y += mconf
 endif
 
+ifeq ($(MAKECMDGOALS),update-po-config)
+       hostprogs-y += kxgettext
+endif
+
 ifeq ($(MAKECMDGOALS),xconfig)
        qconf-target := 1
 endif
@@ -188,16 +196,15 @@ endif
 
 
 ifeq ($(qconf-target),1)
-qconf-cxxobjs  := qconf.o
-qconf-objs     := kconfig_load.o zconf.tab.o
+       hostprogs-y += qconf
 endif
 
 ifeq ($(gconf-target),1)
-gconf-objs     := gconf.o kconfig_load.o zconf.tab.o
+       hostprogs-y += gconf
 endif
 
-clean-files    := lkc_defs.h qconf.moc .tmp_qtcheck \
-                  .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h
+clean-files    := lkc_defs.h qconf.moc .tmp_qtcheck .tmp_gtkcheck
+clean-files    += zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h
 clean-files     += mconf qconf gconf nconf
 clean-files     += config.pot linux.pot
 
@@ -321,11 +328,12 @@ $(obj)/%.moc: $(src)/%.h
        $(KC_QT_MOC) -i $< -o $@
 
 $(obj)/lkc_defs.h: $(src)/lkc_proto.h
-       sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
+       $(Q)sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
 
 # Extract gconf menu items for I18N support
 $(obj)/gconf.glade.h: $(obj)/gconf.glade
-       intltool-extract --type=gettext/glade $(obj)/gconf.glade
+       $(Q)intltool-extract --type=gettext/glade --srcdir=$(srctree) \
+       $(obj)/gconf.glade
 
 ###
 # The following requires flex/bison/gperf
index 61c35bf2d9cb93d690a40eafb0227006bec46151..2bafd9a7c8daa0c7f80edb0294f5686995832c9f 100644 (file)
@@ -560,8 +560,6 @@ int conf_write(const char *name)
        const char *basename;
        const char *str;
        char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1];
-       time_t now;
-       int use_timestamp = 1;
        char *env;
 
        dirname[0] = 0;
@@ -598,19 +596,11 @@ int conf_write(const char *name)
        if (!out)
                return 1;
 
-       time(&now);
-       env = getenv("KCONFIG_NOTIMESTAMP");
-       if (env && *env)
-               use_timestamp = 0;
-
        fprintf(out, _("#\n"
                       "# Automatically generated make config: don't edit\n"
                       "# %s\n"
-                      "%s%s"
                       "#\n"),
-                    rootmenu.prompt->text,
-                    use_timestamp ? "# " : "",
-                    use_timestamp ? ctime(&now) : "");
+                    rootmenu.prompt->text);
 
        if (!conf_get_changed())
                sym_clear_all_valid();
@@ -784,7 +774,6 @@ int conf_write_autoconf(void)
        const char *str;
        const char *name;
        FILE *out, *tristate, *out_h;
-       time_t now;
        int i;
 
        sym_clear_all_valid();
@@ -811,22 +800,19 @@ int conf_write_autoconf(void)
                return 1;
        }
 
-       time(&now);
        fprintf(out, "#\n"
                     "# Automatically generated make config: don't edit\n"
                     "# %s\n"
-                    "# %s"
                     "#\n",
-                    rootmenu.prompt->text, ctime(&now));
+                    rootmenu.prompt->text);
        fprintf(tristate, "#\n"
                          "# Automatically generated - do not edit\n"
                          "\n");
        fprintf(out_h, "/*\n"
                       " * Automatically generated C config: don't edit\n"
                       " * %s\n"
-                      " * %s"
                       " */\n",
-                      rootmenu.prompt->text, ctime(&now));
+                      rootmenu.prompt->text);
 
        for_all_symbols(i, sym) {
                sym_calc_value(sym);
index 3d238db4976405fee6aa122c3582e4a717a25315..16bfae2d321742bd5bf06e0a17e3e6377b47ef71 100644 (file)
@@ -20,12 +20,8 @@ struct file {
        struct file *parent;
        const char *name;
        int lineno;
-       int flags;
 };
 
-#define FILE_BUSY              0x0001
-#define FILE_SCANNED           0x0002
-
 typedef enum tristate {
        no, mod, yes
 } tristate;
index 455896164d72ccdbe327b2b5914b9561bece6c17..a11d5f7b9eeb1f793514fb8548b646a7414ca321 100644 (file)
@@ -253,7 +253,7 @@ void init_left_tree(void)
 
        gtk_tree_view_set_model(view, model1);
        gtk_tree_view_set_headers_visible(view, TRUE);
-       gtk_tree_view_set_rules_hint(view, FALSE);
+       gtk_tree_view_set_rules_hint(view, TRUE);
 
        column = gtk_tree_view_column_new();
        gtk_tree_view_append_column(view, column);
@@ -298,7 +298,7 @@ void init_right_tree(void)
 
        gtk_tree_view_set_model(view, model2);
        gtk_tree_view_set_headers_visible(view, TRUE);
-       gtk_tree_view_set_rules_hint(view, FALSE);
+       gtk_tree_view_set_rules_hint(view, TRUE);
 
        column = gtk_tree_view_column_new();
        gtk_tree_view_append_column(view, column);
@@ -756,7 +756,6 @@ void on_load_clicked(GtkButton * button, gpointer user_data)
 void on_single_clicked(GtkButton * button, gpointer user_data)
 {
        view_mode = SINGLE_VIEW;
-       gtk_paned_set_position(GTK_PANED(hpaned), 0);
        gtk_widget_hide(tree1_w);
        current = &rootmenu;
        display_tree_part();
@@ -782,7 +781,6 @@ void on_split_clicked(GtkButton * button, gpointer user_data)
 void on_full_clicked(GtkButton * button, gpointer user_data)
 {
        view_mode = FULL_VIEW;
-       gtk_paned_set_position(GTK_PANED(hpaned), 0);
        gtk_widget_hide(tree1_w);
        if (tree2)
                gtk_tree_store_clear(tree2);
@@ -1444,6 +1442,12 @@ static void display_tree(struct menu *menu)
                 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
                    || (view_mode == FULL_VIEW)
                    || (view_mode == SPLIT_VIEW))*/
+
+               /* Change paned position if the view is not in 'split mode' */
+               if (view_mode == SINGLE_VIEW || view_mode == FULL_VIEW) {
+                       gtk_paned_set_position(GTK_PANED(hpaned), 0);
+               }
+
                if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
                    || (view_mode == FULL_VIEW)
                    || (view_mode == SPLIT_VIEW)) {
index 6eb039718259a38838268c7df29a2212cb265bed..d9182916f72494d3138a93a352f24a11ee3f06e7 100644 (file)
@@ -2363,11 +2363,11 @@ void zconf_initscan(const char *name)
 
        current_file = file_lookup(name);
        current_file->lineno = 1;
-       current_file->flags = FILE_BUSY;
 }
 
 void zconf_nextfile(const char *name)
 {
+       struct file *iter;
        struct file *file = file_lookup(name);
        struct buffer *buf = malloc(sizeof(*buf));
        memset(buf, 0, sizeof(*buf));
@@ -2383,18 +2383,25 @@ void zconf_nextfile(const char *name)
        buf->parent = current_buf;
        current_buf = buf;
 
-       if (file->flags & FILE_BUSY) {
-               printf("%s:%d: do not source '%s' from itself\n",
-                      zconf_curname(), zconf_lineno(), name);
-               exit(1);
-       }
-       if (file->flags & FILE_SCANNED) {
-               printf("%s:%d: file '%s' is already sourced from '%s'\n",
-                      zconf_curname(), zconf_lineno(), name,
-                      file->parent->name);
-               exit(1);
+       for (iter = current_file->parent; iter; iter = iter->parent ) {
+               if (!strcmp(current_file->name,iter->name) ) {
+                       printf("%s:%d: recursive inclusion detected. "
+                              "Inclusion path:\n  current file : '%s'\n",
+                              zconf_curname(), zconf_lineno(),
+                              zconf_curname());
+                       iter = current_file->parent;
+                       while (iter && \
+                              strcmp(iter->name,current_file->name)) {
+                               printf("  included from: '%s:%d'\n",
+                                      iter->name, iter->lineno-1);
+                               iter = iter->parent;
+                       }
+                       if (iter)
+                               printf("  included from: '%s:%d'\n",
+                                      iter->name, iter->lineno+1);
+                       exit(1);
+               }
        }
-       file->flags |= FILE_BUSY;
        file->lineno = 1;
        file->parent = current_file;
        current_file = file;
@@ -2404,8 +2411,6 @@ static void zconf_endfile(void)
 {
        struct buffer *parent;
 
-       current_file->flags |= FILE_SCANNED;
-       current_file->flags &= ~FILE_BUSY;
        current_file = current_file->parent;
 
        parent = current_buf->parent;
index db56377393d7922229562fa1ea767f3288424e25..488dd741078747132b08dc9afb33001f4a03db5a 100644 (file)
@@ -373,18 +373,18 @@ static void print_function_line(void)
        const int skip = 1;
 
        for (i = 0; i < function_keys_num; i++) {
-               wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
+               (void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
                mvwprintw(main_window, LINES-3, offset,
                                "%s",
                                function_keys[i].key_str);
-               wattrset(main_window, attributes[FUNCTION_TEXT]);
+               (void) wattrset(main_window, attributes[FUNCTION_TEXT]);
                offset += strlen(function_keys[i].key_str);
                mvwprintw(main_window, LINES-3,
                                offset, "%s",
                                function_keys[i].func);
                offset += strlen(function_keys[i].func) + skip;
        }
-       wattrset(main_window, attributes[NORMAL]);
+       (void) wattrset(main_window, attributes[NORMAL]);
 }
 
 /* help */
@@ -953,16 +953,16 @@ static void show_menu(const char *prompt, const char *instructions,
        current_instructions = instructions;
 
        clear();
-       wattrset(main_window, attributes[NORMAL]);
+       (void) wattrset(main_window, attributes[NORMAL]);
        print_in_middle(stdscr, 1, 0, COLS,
                        menu_backtitle,
                        attributes[MAIN_HEADING]);
 
-       wattrset(main_window, attributes[MAIN_MENU_BOX]);
+       (void) wattrset(main_window, attributes[MAIN_MENU_BOX]);
        box(main_window, 0, 0);
-       wattrset(main_window, attributes[MAIN_MENU_HEADING]);
+       (void) wattrset(main_window, attributes[MAIN_MENU_HEADING]);
        mvwprintw(main_window, 0, 3, " %s ", prompt);
-       wattrset(main_window, attributes[NORMAL]);
+       (void) wattrset(main_window, attributes[NORMAL]);
 
        set_menu_items(curses_menu, curses_menu_items);
 
index 06dd2e33581de5de81863bd1b74b2fb7100af5ed..c2796b866f8f14a37453f409429b900e1f11ba44 100644 (file)
@@ -1489,8 +1489,7 @@ void ConfigMainWindow::saveConfigAs(void)
        QString s = Q3FileDialog::getSaveFileName(conf_get_configname(), NULL, this);
        if (s.isNull())
                return;
-       if (conf_write(QFile::encodeName(s)))
-               QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+       saveConfig();
 }
 
 void ConfigMainWindow::searchConfig(void)
@@ -1643,7 +1642,7 @@ void ConfigMainWindow::closeEvent(QCloseEvent* e)
        mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
        switch (mb.exec()) {
        case QMessageBox::Yes:
-               conf_write(NULL);
+               saveConfig();
        case QMessageBox::No:
                e->accept();
                break;
index 3dbaec185cc486d183ed5ba87cfe848635e4b968..b22f884f90221650ed46ef4cf509bf6a3b33170e 100644 (file)
@@ -294,11 +294,11 @@ void zconf_initscan(const char *name)
 
        current_file = file_lookup(name);
        current_file->lineno = 1;
-       current_file->flags = FILE_BUSY;
 }
 
 void zconf_nextfile(const char *name)
 {
+       struct file *iter;
        struct file *file = file_lookup(name);
        struct buffer *buf = malloc(sizeof(*buf));
        memset(buf, 0, sizeof(*buf));
@@ -314,18 +314,25 @@ void zconf_nextfile(const char *name)
        buf->parent = current_buf;
        current_buf = buf;
 
-       if (file->flags & FILE_BUSY) {
-               printf("%s:%d: do not source '%s' from itself\n",
-                      zconf_curname(), zconf_lineno(), name);
-               exit(1);
-       }
-       if (file->flags & FILE_SCANNED) {
-               printf("%s:%d: file '%s' is already sourced from '%s'\n",
-                      zconf_curname(), zconf_lineno(), name,
-                      file->parent->name);
-               exit(1);
+       for (iter = current_file->parent; iter; iter = iter->parent ) {
+               if (!strcmp(current_file->name,iter->name) ) {
+                       printf("%s:%d: recursive inclusion detected. "
+                              "Inclusion path:\n  current file : '%s'\n",
+                              zconf_curname(), zconf_lineno(),
+                              zconf_curname());
+                       iter = current_file->parent;
+                       while (iter && \
+                              strcmp(iter->name,current_file->name)) {
+                               printf("  included from: '%s:%d'\n",
+                                      iter->name, iter->lineno-1);
+                               iter = iter->parent;
+                       }
+                       if (iter)
+                               printf("  included from: '%s:%d'\n",
+                                      iter->name, iter->lineno+1);
+                       exit(1);
+               }
        }
-       file->flags |= FILE_BUSY;
        file->lineno = 1;
        file->parent = current_file;
        current_file = file;
@@ -335,8 +342,6 @@ static void zconf_endfile(void)
 {
        struct buffer *parent;
 
-       current_file->flags |= FILE_SCANNED;
-       current_file->flags &= ~FILE_BUSY;
        current_file = current_file->parent;
 
        parent = current_buf->parent;
index 50ad317a4bf9b41bc62d074ee8bd19a9864ffda6..f221ddf69080402a60ad612a4ce63f05be671a6e 100755 (executable)
@@ -42,6 +42,16 @@ if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then
 else
        TIMESTAMP=$KBUILD_BUILD_TIMESTAMP
 fi
+if test -z "$KBUILD_BUILD_USER"; then
+       LINUX_COMPILE_BY=$(whoami | sed 's/\\/\\\\/')
+else
+       LINUX_COMPILE_BY=$KBUILD_BUILD_USER
+fi
+if test -z "$KBUILD_BUILD_HOST"; then
+       LINUX_COMPILE_HOST=`hostname`
+else
+       LINUX_COMPILE_HOST=$KBUILD_BUILD_HOST
+fi
 
 UTS_VERSION="#$VERSION"
 CONFIG_FLAGS=""
@@ -63,20 +73,8 @@ UTS_TRUNCATE="cut -b -$UTS_LEN"
 
   echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\"
 
-  echo \#define LINUX_COMPILE_TIME \"`date +%T`\"
-  echo \#define LINUX_COMPILE_BY \"`whoami`\"
-  echo \#define LINUX_COMPILE_HOST \"`hostname | $UTS_TRUNCATE`\"
-
-  domain=`dnsdomainname 2> /dev/null`
-  if [ -z "$domain" ]; then
-    domain=`domainname 2> /dev/null`
-  fi
-
-  if [ -n "$domain" ]; then
-    echo \#define LINUX_COMPILE_DOMAIN \"`echo $domain | $UTS_TRUNCATE`\"
-  else
-    echo \#define LINUX_COMPILE_DOMAIN
-  fi
+  echo \#define LINUX_COMPILE_BY \"`echo $LINUX_COMPILE_BY | $UTS_TRUNCATE`\"
+  echo \#define LINUX_COMPILE_HOST \"`echo $LINUX_COMPILE_HOST | $UTS_TRUNCATE`\"
 
   echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | tail -n 1`\"
 ) > .tmpcompile
@@ -91,8 +89,8 @@ UTS_TRUNCATE="cut -b -$UTS_LEN"
 # first line.
 
 if [ -r $TARGET ] && \
-      grep -v 'UTS_VERSION\|LINUX_COMPILE_TIME' $TARGET > .tmpver.1 && \
-      grep -v 'UTS_VERSION\|LINUX_COMPILE_TIME' .tmpcompile > .tmpver.2 && \
+      grep -v 'UTS_VERSION' $TARGET > .tmpver.1 && \
+      grep -v 'UTS_VERSION' .tmpcompile > .tmpver.2 && \
       cmp -s .tmpver.1 .tmpver.2; then
    rm -f .tmpcompile
 else
index a834b935f5363d80ab56b15a1acf3cb477f21e42..006960ebbce927adbb1761ecc1275858db00a62c 100644 (file)
@@ -26,9 +26,9 @@ RPM := $(shell if [ -x "/usr/bin/rpmbuild" ]; then echo rpmbuild; \
                   else echo rpm; fi)
 
 # Remove hyphens since they have special meaning in RPM filenames
-KERNELPATH := kernel-$(subst -,,$(KERNELRELEASE))
+KERNELPATH := kernel-$(subst -,_,$(KERNELRELEASE))
 MKSPEC     := $(srctree)/scripts/package/mkspec
-PREV       := set -e; cd ..;
+PREV       := set -e; cd -P ..;
 
 # rpm-pkg
 # ---------------------------------------------------------------------------
index e1c1d5b8ca70842e426d653fa508f9ed89601f8a..4bf17ddf7c7ff732f4ed0a9a851bfd759ad03772 100755 (executable)
@@ -22,7 +22,7 @@ if [ "`grep CONFIG_DRM=y .config | cut -f2 -d\=`" = "y" ]; then
 fi
 
 PROVIDES="$PROVIDES kernel-$KERNELRELEASE"
-__KERNELRELEASE=`echo $KERNELRELEASE | sed -e "s/-//g"`
+__KERNELRELEASE=`echo $KERNELRELEASE | sed -e "s/-/_/g"`
 
 echo "Name: kernel"
 echo "Summary: The Linux Kernel"
@@ -47,6 +47,18 @@ echo ""
 echo "%description"
 echo "The Linux Kernel, the operating system core itself"
 echo ""
+echo "%package headers"
+echo "Summary: Header files for the Linux kernel for use by glibc"
+echo "Group: Development/System"
+echo "Obsoletes: kernel-headers"
+echo "Provides: kernel-headers = %{version}"
+echo "%description headers"
+echo "Kernel-headers includes the C header files that specify the interface"
+echo "between the Linux kernel and userspace libraries and programs.  The"
+echo "header files define structures and constants that are needed for"
+echo "building most standard programs and are also needed for rebuilding the"
+echo "glibc package."
+echo ""
 
 if ! $PREBUILT; then
 echo "%prep"
@@ -83,6 +95,7 @@ echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/vmlinuz-$KERNELRELEASE"
 echo "%endif"
 echo "%endif"
 
+echo 'make %{?_smp_mflags} INSTALL_HDR_PATH=$RPM_BUILD_ROOT/usr headers_install'
 echo 'cp System.map $RPM_BUILD_ROOT'"/boot/System.map-$KERNELRELEASE"
 
 echo 'cp .config $RPM_BUILD_ROOT'"/boot/config-$KERNELRELEASE"
@@ -105,3 +118,7 @@ echo "/lib/modules/$KERNELRELEASE"
 echo "/lib/firmware"
 echo "/boot/*"
 echo ""
+echo "%files headers"
+echo '%defattr (-, root, root)'
+echo "/usr/include"
+echo ""
index 46a59cae3a0a6d52840483ab10212ef93fb6f3c3..20fb25c2338299f33a8954d6b046ce17f7b466fe 100755 (executable)
@@ -250,7 +250,7 @@ while :                             # incrementing SUBLEVEL (s in v.p.s)
 do
     CURRENTFULLVERSION="$VERSION.$PATCHLEVEL.$SUBLEVEL"
     EXTRAVER=
-    if [ $STOPFULLVERSION = $CURRENTFULLVERSION ]; then
+    if [ x$STOPFULLVERSION = x$CURRENTFULLVERSION ]; then
         echo "Stopping at $CURRENTFULLVERSION base as requested."
         break
     fi
index 4be60364a40509eac1269eafc97393aadc1ac5e8..f40a6af6bf40068f2a074bf6bff86d68b2a05440 100644 (file)
@@ -43,6 +43,7 @@
 #undef ELF_R_INFO
 #undef Elf_r_info
 #undef ELF_ST_BIND
+#undef ELF_ST_TYPE
 #undef fn_ELF_R_SYM
 #undef fn_ELF_R_INFO
 #undef uint_t
@@ -76,6 +77,7 @@
 # define ELF_R_INFO            ELF64_R_INFO
 # define Elf_r_info            Elf64_r_info
 # define ELF_ST_BIND           ELF64_ST_BIND
+# define ELF_ST_TYPE           ELF64_ST_TYPE
 # define fn_ELF_R_SYM          fn_ELF64_R_SYM
 # define fn_ELF_R_INFO         fn_ELF64_R_INFO
 # define uint_t                        uint64_t
 # define ELF_R_INFO            ELF32_R_INFO
 # define Elf_r_info            Elf32_r_info
 # define ELF_ST_BIND           ELF32_ST_BIND
+# define ELF_ST_TYPE           ELF32_ST_TYPE
 # define fn_ELF_R_SYM          fn_ELF32_R_SYM
 # define fn_ELF_R_INFO         fn_ELF32_R_INFO
 # define uint_t                        uint32_t
@@ -427,6 +430,11 @@ static unsigned find_secsym_ndx(unsigned const txtndx,
                if (txtndx == w2(symp->st_shndx)
                        /* avoid STB_WEAK */
                    && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) {
+                       /* function symbols on ARM have quirks, avoid them */
+                       if (w2(ehdr->e_machine) == EM_ARM
+                           && ELF_ST_TYPE(symp->st_info) == STT_FUNC)
+                               continue;
+
                        *recvalp = _w(symp->st_value);
                        return symp - sym0;
                }
index a936315ba2c87340f3a38d38c68bc599907a47d0..4d020ecb75242db1372be5cf09df4d705b6c7592 100644 (file)
@@ -1,2 +1,2 @@
-Please see Documentation/SELinux.txt for information on
+Please see Documentation/security/SELinux.txt for information on
 installing a dummy SELinux policy.
index bd6185d529cff980e8516429abdc9f3ca2646391..75c5d24f1993ae009aedf2b12bd33f7dd9360b25 100755 (executable)
@@ -132,7 +132,7 @@ exuberant()
        --regex-asm='/^ENTRY\(([^)]*)\).*/\1/'                  \
        --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' \
        --regex-c++='/^TRACE_EVENT\(([^,)]*).*/trace_\1/'               \
-       --regex-c++='/^DEFINE_EVENT\(([^,)]*).*/trace_\1/'
+       --regex-c++='/^DEFINE_EVENT\([^,)]*, *([^,)]*).*/trace_\1/'
 
        all_kconfigs | xargs $1 -a                              \
        --langdef=kconfig --language-force=kconfig              \
@@ -152,7 +152,9 @@ emacs()
 {
        all_sources | xargs $1 -a                               \
        --regex='/^ENTRY(\([^)]*\)).*/\1/'                      \
-       --regex='/^SYSCALL_DEFINE[0-9]?(\([^,)]*\).*/sys_\1/'
+       --regex='/^SYSCALL_DEFINE[0-9]?(\([^,)]*\).*/sys_\1/'   \
+       --regex='/^TRACE_EVENT(\([^,)]*\).*/trace_\1/'          \
+       --regex='/^DEFINE_EVENT([^,)]*, *\([^,)]*\).*/trace_\1/'
 
        all_kconfigs | xargs $1 -a                              \
        --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/'
index 95accd442d55eeb5c81f6bcd39b63fc12e5a6f25..e0f08b52e4ab440933c9f72120092b8bcd527b46 100644 (file)
@@ -167,6 +167,7 @@ config INTEL_TXT
 config LSM_MMAP_MIN_ADDR
        int "Low address space for LSM to protect from user allocation"
        depends on SECURITY && SECURITY_SELINUX
+       default 32768 if ARM
        default 65536
        help
          This is the portion of low virtual memory which should be protected
index ae3a698415e63603d9b159814b45c58b0f83eee0..3d2fd141dff76f078d171e2abf28fd4e97b5378c 100644 (file)
@@ -593,7 +593,8 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
                        sa.aad.op = OP_SETPROCATTR;
                        sa.aad.info = name;
                        sa.aad.error = -EINVAL;
-                       return aa_audit(AUDIT_APPARMOR_DENIED, NULL, GFP_KERNEL,
+                       return aa_audit(AUDIT_APPARMOR_DENIED,
+                                       __aa_current_profile(), GFP_KERNEL,
                                        &sa, NULL);
                }
        } else if (strcmp(name, "exec") == 0) {
@@ -611,7 +612,7 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
 static int apparmor_task_setrlimit(struct task_struct *task,
                unsigned int resource, struct rlimit *new_rlim)
 {
-       struct aa_profile *profile = aa_current_profile();
+       struct aa_profile *profile = __aa_current_profile();
        int error = 0;
 
        if (!unconfined(profile))
index 06d764ccbbe5533f3e77a7d6b00a6bb3c7d3614b..94de6b4907c8af064ed20743148f40b7d946b12e 100644 (file)
@@ -194,7 +194,7 @@ void aa_dfa_free_kref(struct kref *kref)
  * @flags: flags controlling what type of accept tables are acceptable
  *
  * Unpack a dfa that has been serialized.  To find information on the dfa
- * format look in Documentation/apparmor.txt
+ * format look in Documentation/security/apparmor.txt
  * Assumes the dfa @blob stream has been aligned on a 8 byte boundary
  *
  * Returns: an unpacked dfa ready for matching or ERR_PTR on failure
index e33aaf7e5744fcec9fd65d0e5974d13303fff506..d6d9a57b56525e5c7ca9df569f19d3da7d84feba 100644 (file)
@@ -12,8 +12,8 @@
  * published by the Free Software Foundation, version 2 of the
  * License.
  *
- * AppArmor uses a serialized binary format for loading policy.
- * To find policy format documentation look in Documentation/apparmor.txt
+ * AppArmor uses a serialized binary format for loading policy. To find
+ * policy format documentation look in Documentation/security/apparmor.txt
  * All policy is validated before it is used.
  */
 
index f20e984ccfb459c141222f51791f4b5a3fcab6a9..a93b3b73307991c69738bc0dab712e56330ba932 100644 (file)
@@ -529,15 +529,10 @@ skip:
        new->suid = new->fsuid = new->euid;
        new->sgid = new->fsgid = new->egid;
 
-       /* For init, we want to retain the capabilities set in the initial
-        * task.  Thus we skip the usual capability rules
-        */
-       if (!is_global_init(current)) {
-               if (effective)
-                       new->cap_effective = new->cap_permitted;
-               else
-                       cap_clear(new->cap_effective);
-       }
+       if (effective)
+               new->cap_effective = new->cap_permitted;
+       else
+               cap_clear(new->cap_effective);
        bprm->cap_effective = effective;
 
        /*
index 8d9c48f13774b8d35d7bbb8444aafb4681c2d394..1be68269e1c2a2c55e2db2cc46d206539c5f79f3 100644 (file)
@@ -62,8 +62,7 @@ static inline struct dev_cgroup *task_devcgroup(struct task_struct *task)
 struct cgroup_subsys devices_subsys;
 
 static int devcgroup_can_attach(struct cgroup_subsys *ss,
-               struct cgroup *new_cgroup, struct task_struct *task,
-               bool threadgroup)
+               struct cgroup *new_cgroup, struct task_struct *task)
 {
        if (current != task && !capable(CAP_SYS_ADMIN))
                        return -EPERM;
@@ -475,17 +474,11 @@ struct cgroup_subsys devices_subsys = {
        .subsys_id = devices_subsys_id,
 };
 
-int devcgroup_inode_permission(struct inode *inode, int mask)
+int __devcgroup_inode_permission(struct inode *inode, int mask)
 {
        struct dev_cgroup *dev_cgroup;
        struct dev_whitelist_item *wh;
 
-       dev_t device = inode->i_rdev;
-       if (!device)
-               return 0;
-       if (!S_ISBLK(inode->i_mode) && !S_ISCHR(inode->i_mode))
-               return 0;
-
        rcu_read_lock();
 
        dev_cgroup = task_devcgroup(current);
index 69907a58a6837d038675e55b6abede4176b92daf..b1cba5bf0a5e3d092b57318a242014e915af04ff 100644 (file)
@@ -8,7 +8,7 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, version 2 of the License.
  *
- * See Documentation/keys-trusted-encrypted.txt
+ * See Documentation/security/keys-trusted-encrypted.txt
  */
 
 #include <linux/uaccess.h>
index 07a025f8190233faf66a384816dea03754ee770a..f375152a2500b1d747d7128517430d2401f3a4ce 100644 (file)
@@ -109,11 +109,13 @@ extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
                                    const struct cred *cred,
                                    struct key_type *type,
                                    const void *description,
-                                   key_match_func_t match);
+                                   key_match_func_t match,
+                                   bool no_state_check);
 
 extern key_ref_t search_my_process_keyrings(struct key_type *type,
                                            const void *description,
                                            key_match_func_t match,
+                                           bool no_state_check,
                                            const struct cred *cred);
 extern key_ref_t search_process_keyrings(struct key_type *type,
                                         const void *description,
index 427fddcaeb19b78049b3e1028349cb6b731ed8f9..eca51918c951d3a28db16bf0f61c749722b6ac64 100644 (file)
@@ -206,8 +206,14 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
                goto error5;
        }
 
+       /* wait for the key to finish being constructed */
+       ret = wait_for_key_construction(key, 1);
+       if (ret < 0)
+               goto error6;
+
        ret = key->serial;
 
+error6:
        key_put(key);
 error5:
        key_type_put(ktype);
index cdd2f3f88c8879280a7607c1be655d5487d652c4..a06ffab38568809f5187970261888d6a9e673f18 100644 (file)
@@ -176,13 +176,15 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m)
        else
                seq_puts(m, "[anon]");
 
-       rcu_read_lock();
-       klist = rcu_dereference(keyring->payload.subscriptions);
-       if (klist)
-               seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys);
-       else
-               seq_puts(m, ": empty");
-       rcu_read_unlock();
+       if (key_is_instantiated(keyring)) {
+               rcu_read_lock();
+               klist = rcu_dereference(keyring->payload.subscriptions);
+               if (klist)
+                       seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys);
+               else
+                       seq_puts(m, ": empty");
+               rcu_read_unlock();
+       }
 }
 
 /*
@@ -271,6 +273,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
  * @type: The type of key to search for.
  * @description: Parameter for @match.
  * @match: Function to rule on whether or not a key is the one required.
+ * @no_state_check: Don't check if a matching key is bad
  *
  * Search the supplied keyring tree for a key that matches the criteria given.
  * The root keyring and any linked keyrings must grant Search permission to the
@@ -303,7 +306,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
                             const struct cred *cred,
                             struct key_type *type,
                             const void *description,
-                            key_match_func_t match)
+                            key_match_func_t match,
+                            bool no_state_check)
 {
        struct {
                struct keyring_list *keylist;
@@ -345,6 +349,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
        kflags = keyring->flags;
        if (keyring->type == type && match(keyring, description)) {
                key = keyring;
+               if (no_state_check)
+                       goto found;
 
                /* check it isn't negative and hasn't expired or been
                 * revoked */
@@ -384,11 +390,13 @@ descend:
                        continue;
 
                /* skip revoked keys and expired keys */
-               if (kflags & (1 << KEY_FLAG_REVOKED))
-                       continue;
+               if (!no_state_check) {
+                       if (kflags & (1 << KEY_FLAG_REVOKED))
+                               continue;
 
-               if (key->expiry && now.tv_sec >= key->expiry)
-                       continue;
+                       if (key->expiry && now.tv_sec >= key->expiry)
+                               continue;
+               }
 
                /* keys that don't match */
                if (!match(key, description))
@@ -399,6 +407,9 @@ descend:
                                        cred, KEY_SEARCH) < 0)
                        continue;
 
+               if (no_state_check)
+                       goto found;
+
                /* we set a different error code if we pass a negative key */
                if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
                        err = key->type_data.reject_error;
@@ -478,7 +489,7 @@ key_ref_t keyring_search(key_ref_t keyring,
                return ERR_PTR(-ENOKEY);
 
        return keyring_search_aux(keyring, current->cred,
-                                 type, description, type->match);
+                                 type, description, type->match, false);
 }
 EXPORT_SYMBOL(keyring_search);
 
index 525cf8a29cdde86c5c58557fd73ceb49e9c73dec..49bbc97943ad8b804e22ff69150083a0f891ffd5 100644 (file)
@@ -199,7 +199,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
        if (key->perm & KEY_POS_VIEW) {
                skey_ref = search_my_process_keyrings(key->type, key,
                                                      lookup_user_key_possessed,
-                                                     cred);
+                                                     true, cred);
                if (!IS_ERR(skey_ref)) {
                        key_ref_put(skey_ref);
                        key_ref = make_key_ref(key, 1);
index 930634e4514973ac0f79acc7037138acb576a2c3..a3063eb3dc232a16eab45161e28f0c88fc642841 100644 (file)
@@ -331,6 +331,7 @@ void key_fsgid_changed(struct task_struct *tsk)
 key_ref_t search_my_process_keyrings(struct key_type *type,
                                     const void *description,
                                     key_match_func_t match,
+                                    bool no_state_check,
                                     const struct cred *cred)
 {
        key_ref_t key_ref, ret, err;
@@ -350,7 +351,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
        if (cred->thread_keyring) {
                key_ref = keyring_search_aux(
                        make_key_ref(cred->thread_keyring, 1),
-                       cred, type, description, match);
+                       cred, type, description, match, no_state_check);
                if (!IS_ERR(key_ref))
                        goto found;
 
@@ -371,7 +372,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
        if (cred->tgcred->process_keyring) {
                key_ref = keyring_search_aux(
                        make_key_ref(cred->tgcred->process_keyring, 1),
-                       cred, type, description, match);
+                       cred, type, description, match, no_state_check);
                if (!IS_ERR(key_ref))
                        goto found;
 
@@ -395,7 +396,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
                        make_key_ref(rcu_dereference(
                                             cred->tgcred->session_keyring),
                                     1),
-                       cred, type, description, match);
+                       cred, type, description, match, no_state_check);
                rcu_read_unlock();
 
                if (!IS_ERR(key_ref))
@@ -417,7 +418,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
        else if (cred->user->session_keyring) {
                key_ref = keyring_search_aux(
                        make_key_ref(cred->user->session_keyring, 1),
-                       cred, type, description, match);
+                       cred, type, description, match, no_state_check);
                if (!IS_ERR(key_ref))
                        goto found;
 
@@ -459,7 +460,8 @@ key_ref_t search_process_keyrings(struct key_type *type,
 
        might_sleep();
 
-       key_ref = search_my_process_keyrings(type, description, match, cred);
+       key_ref = search_my_process_keyrings(type, description, match,
+                                            false, cred);
        if (!IS_ERR(key_ref))
                goto found;
        err = key_ref;
@@ -845,6 +847,7 @@ void key_replace_session_keyring(void)
        new-> sgid      = old-> sgid;
        new->fsgid      = old->fsgid;
        new->user       = get_uid(old->user);
+       new->user_ns    = new->user->user_ns;
        new->group_info = get_group_info(old->group_info);
 
        new->securebits = old->securebits;
index df3c0417ee4062ffebac5cb6f3ad30d84fc66a6b..82465328c39b94b5264fb65ba27399f6cdf4d68f 100644 (file)
@@ -8,7 +8,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  *
- * See Documentation/keys-request-key.txt
+ * See Documentation/security/keys-request-key.txt
  */
 
 #include <linux/module.h>
@@ -71,9 +71,8 @@ EXPORT_SYMBOL(complete_request_key);
  * This is called in context of freshly forked kthread before kernel_execve(),
  * so we can simply install the desired session_keyring at this point.
  */
-static int umh_keys_init(struct subprocess_info *info)
+static int umh_keys_init(struct subprocess_info *info, struct cred *cred)
 {
-       struct cred *cred = (struct cred*)current_cred();
        struct key *keyring = info->data;
 
        return install_session_keyring_to_cred(cred, keyring);
@@ -470,7 +469,7 @@ static struct key *construct_key_and_link(struct key_type *type,
        } else if (ret == -EINPROGRESS) {
                ret = 0;
        } else {
-               key = ERR_PTR(ret);
+               goto couldnt_alloc_key;
        }
 
        key_put(dest_keyring);
@@ -480,6 +479,7 @@ static struct key *construct_key_and_link(struct key_type *type,
 construction_failed:
        key_negate_and_link(key, key_negative_timeout, NULL, NULL);
        key_put(key);
+couldnt_alloc_key:
        key_put(dest_keyring);
        kleave(" = %d", ret);
        return ERR_PTR(ret);
@@ -530,8 +530,7 @@ struct key *request_key_and_link(struct key_type *type,
               dest_keyring, flags);
 
        /* search all the process keyrings for a key */
-       key_ref = search_process_keyrings(type, description, type->match,
-                                         cred);
+       key_ref = search_process_keyrings(type, description, type->match, cred);
 
        if (!IS_ERR(key_ref)) {
                key = key_ref_to_ptr(key_ref);
index 68164031a74e0bc225844037ceedd45a40fc94cb..6cff37529b80210c3bc2b789c44662bb56a33f52 100644 (file)
@@ -8,7 +8,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  *
- * See Documentation/keys-request-key.txt
+ * See Documentation/security/keys-request-key.txt
  */
 
 #include <linux/module.h>
@@ -59,7 +59,8 @@ static void request_key_auth_describe(const struct key *key,
 
        seq_puts(m, "key:");
        seq_puts(m, key->description);
-       seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
+       if (key_is_instantiated(key))
+               seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
 }
 
 /*
index c99b9368368c3d6e2193e81abaf5ab417d34557b..0c33e2ea1f3c34879d44ca57044822fefc657695 100644 (file)
@@ -8,7 +8,7 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, version 2 of the License.
  *
- * See Documentation/keys-trusted-encrypted.txt
+ * See Documentation/security/keys-trusted-encrypted.txt
  */
 
 #include <linux/uaccess.h>
index f66baf44f32d16344756635321fffb98b34f0034..5b366d7af3c4dc17b595c67af3dbe99d5fd69df1 100644 (file)
@@ -157,8 +157,8 @@ EXPORT_SYMBOL_GPL(user_destroy);
 void user_describe(const struct key *key, struct seq_file *m)
 {
        seq_puts(m, key->description);
-
-       seq_printf(m, ": %u", key->datalen);
+       if (key_is_instantiated(key))
+               seq_printf(m, ": %u", key->datalen);
 }
 
 EXPORT_SYMBOL_GPL(user_describe);
index 908aa712816ac25bcb73fe22e6e704bd669d7566..893af8a2fa1e994c518b7649ddc9d29b61c8681a 100644 (file)
@@ -210,7 +210,6 @@ static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr,
 static void dump_common_audit_data(struct audit_buffer *ab,
                                   struct common_audit_data *a)
 {
-       struct inode *inode = NULL;
        struct task_struct *tsk = current;
 
        if (a->tsk)
@@ -229,33 +228,47 @@ static void dump_common_audit_data(struct audit_buffer *ab,
        case LSM_AUDIT_DATA_CAP:
                audit_log_format(ab, " capability=%d ", a->u.cap);
                break;
-       case LSM_AUDIT_DATA_FS:
-               if (a->u.fs.path.dentry) {
-                       struct dentry *dentry = a->u.fs.path.dentry;
-                       if (a->u.fs.path.mnt) {
-                               audit_log_d_path(ab, "path=", &a->u.fs.path);
-                       } else {
-                               audit_log_format(ab, " name=");
-                               audit_log_untrustedstring(ab,
-                                                dentry->d_name.name);
-                       }
-                       inode = dentry->d_inode;
-               } else if (a->u.fs.inode) {
-                       struct dentry *dentry;
-                       inode = a->u.fs.inode;
-                       dentry = d_find_alias(inode);
-                       if (dentry) {
-                               audit_log_format(ab, " name=");
-                               audit_log_untrustedstring(ab,
-                                                dentry->d_name.name);
-                               dput(dentry);
-                       }
-               }
+       case LSM_AUDIT_DATA_PATH: {
+               struct inode *inode;
+
+               audit_log_d_path(ab, "path=", &a->u.path);
+
+               inode = a->u.path.dentry->d_inode;
                if (inode)
                        audit_log_format(ab, " dev=%s ino=%lu",
                                        inode->i_sb->s_id,
                                        inode->i_ino);
                break;
+       }
+       case LSM_AUDIT_DATA_DENTRY: {
+               struct inode *inode;
+
+               audit_log_format(ab, " name=");
+               audit_log_untrustedstring(ab, a->u.dentry->d_name.name);
+
+               inode = a->u.dentry->d_inode;
+               if (inode)
+                       audit_log_format(ab, " dev=%s ino=%lu",
+                                       inode->i_sb->s_id,
+                                       inode->i_ino);
+               break;
+       }
+       case LSM_AUDIT_DATA_INODE: {
+               struct dentry *dentry;
+               struct inode *inode;
+
+               inode = a->u.inode;
+               dentry = d_find_alias(inode);
+               if (dentry) {
+                       audit_log_format(ab, " name=");
+                       audit_log_untrustedstring(ab,
+                                        dentry->d_name.name);
+                       dput(dentry);
+               }
+               audit_log_format(ab, " dev=%s ino=%lu", inode->i_sb->s_id,
+                                inode->i_ino);
+               break;
+       }
        case LSM_AUDIT_DATA_TASK:
                tsk = a->u.tsk;
                if (tsk && tsk->pid) {
index 3d2715fd35ea4c8dc11b580a7ee1fb946b9c4257..d515b2128a4ef6f631f4113cf0fcf3575fea3e6d 100644 (file)
@@ -526,7 +526,7 @@ int avc_audit(u32 ssid, u32 tsid,
         * during retry. However this is logically just as if the operation
         * happened a little later.
         */
-       if ((a->type == LSM_AUDIT_DATA_FS) &&
+       if ((a->type == LSM_AUDIT_DATA_INODE) &&
            (flags & IPERM_FLAG_RCU))
                return -ECHILD;
 
@@ -752,10 +752,9 @@ int avc_ss_reset(u32 seqno)
 int avc_has_perm_noaudit(u32 ssid, u32 tsid,
                         u16 tclass, u32 requested,
                         unsigned flags,
-                        struct av_decision *in_avd)
+                        struct av_decision *avd)
 {
        struct avc_node *node;
-       struct av_decision avd_entry, *avd;
        int rc = 0;
        u32 denied;
 
@@ -766,18 +765,11 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
        node = avc_lookup(ssid, tsid, tclass);
        if (unlikely(!node)) {
                rcu_read_unlock();
-
-               if (in_avd)
-                       avd = in_avd;
-               else
-                       avd = &avd_entry;
-
                security_compute_av(ssid, tsid, tclass, avd);
                rcu_read_lock();
                node = avc_insert(ssid, tsid, tclass, avd);
        } else {
-               if (in_avd)
-                       memcpy(in_avd, &node->ae.avd, sizeof(*in_avd));
+               memcpy(avd, &node->ae.avd, sizeof(*avd));
                avd = &node->ae.avd;
        }
 
index 8fb248843009de5e6b71a01cae7b884cd597ba36..20219ef5439ac69d63b61445a97403524e51c69b 100644 (file)
@@ -990,6 +990,7 @@ static void selinux_write_opts(struct seq_file *m,
                        continue;
                default:
                        BUG();
+                       return;
                };
                /* we need a comma before each option */
                seq_putc(m, ',');
@@ -1443,6 +1444,7 @@ static int task_has_capability(struct task_struct *tsk,
                printk(KERN_ERR
                       "SELinux:  out of range capability %d\n", cap);
                BUG();
+               return -EINVAL;
        }
 
        rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
@@ -1474,7 +1476,6 @@ static int inode_has_perm(const struct cred *cred,
                          unsigned flags)
 {
        struct inode_security_struct *isec;
-       struct common_audit_data ad;
        u32 sid;
 
        validate_creds(cred);
@@ -1485,29 +1486,48 @@ static int inode_has_perm(const struct cred *cred,
        sid = cred_sid(cred);
        isec = inode->i_security;
 
-       if (!adp) {
-               adp = &ad;
-               COMMON_AUDIT_DATA_INIT(&ad, FS);
-               ad.u.fs.inode = inode;
-       }
-
        return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
 }
 
+static int inode_has_perm_noadp(const struct cred *cred,
+                               struct inode *inode,
+                               u32 perms,
+                               unsigned flags)
+{
+       struct common_audit_data ad;
+
+       COMMON_AUDIT_DATA_INIT(&ad, INODE);
+       ad.u.inode = inode;
+       return inode_has_perm(cred, inode, perms, &ad, flags);
+}
+
 /* Same as inode_has_perm, but pass explicit audit data containing
    the dentry to help the auditing code to more easily generate the
    pathname if needed. */
 static inline int dentry_has_perm(const struct cred *cred,
-                                 struct vfsmount *mnt,
                                  struct dentry *dentry,
                                  u32 av)
 {
        struct inode *inode = dentry->d_inode;
        struct common_audit_data ad;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.mnt = mnt;
-       ad.u.fs.path.dentry = dentry;
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = dentry;
+       return inode_has_perm(cred, inode, av, &ad, 0);
+}
+
+/* Same as inode_has_perm, but pass explicit audit data containing
+   the path to help the auditing code to more easily generate the
+   pathname if needed. */
+static inline int path_has_perm(const struct cred *cred,
+                               struct path *path,
+                               u32 av)
+{
+       struct inode *inode = path->dentry->d_inode;
+       struct common_audit_data ad;
+
+       COMMON_AUDIT_DATA_INIT(&ad, PATH);
+       ad.u.path = *path;
        return inode_has_perm(cred, inode, av, &ad, 0);
 }
 
@@ -1529,8 +1549,8 @@ static int file_has_perm(const struct cred *cred,
        u32 sid = cred_sid(cred);
        int rc;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path = file->f_path;
+       COMMON_AUDIT_DATA_INIT(&ad, PATH);
+       ad.u.path = file->f_path;
 
        if (sid != fsec->sid) {
                rc = avc_has_perm(sid, fsec->sid,
@@ -1568,8 +1588,8 @@ static int may_create(struct inode *dir,
        sid = tsec->sid;
        newsid = tsec->create_sid;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.dentry = dentry;
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = dentry;
 
        rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
                          DIR__ADD_NAME | DIR__SEARCH,
@@ -1621,8 +1641,8 @@ static int may_link(struct inode *dir,
        dsec = dir->i_security;
        isec = dentry->d_inode->i_security;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.dentry = dentry;
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = dentry;
 
        av = DIR__SEARCH;
        av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
@@ -1667,9 +1687,9 @@ static inline int may_rename(struct inode *old_dir,
        old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
        new_dsec = new_dir->i_security;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
 
-       ad.u.fs.path.dentry = old_dentry;
+       ad.u.dentry = old_dentry;
        rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
                          DIR__REMOVE_NAME | DIR__SEARCH, &ad);
        if (rc)
@@ -1685,7 +1705,7 @@ static inline int may_rename(struct inode *old_dir,
                        return rc;
        }
 
-       ad.u.fs.path.dentry = new_dentry;
+       ad.u.dentry = new_dentry;
        av = DIR__ADD_NAME | DIR__SEARCH;
        if (new_dentry->d_inode)
                av |= DIR__REMOVE_NAME;
@@ -1895,7 +1915,7 @@ static int selinux_quota_on(struct dentry *dentry)
 {
        const struct cred *cred = current_cred();
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
+       return dentry_has_perm(cred, dentry, FILE__QUOTAON);
 }
 
 static int selinux_syslog(int type)
@@ -1992,8 +2012,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
                        return rc;
        }
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path = bprm->file->f_path;
+       COMMON_AUDIT_DATA_INIT(&ad, PATH);
+       ad.u.path = bprm->file->f_path;
 
        if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
                new_tsec->sid = old_tsec->sid;
@@ -2107,8 +2127,8 @@ static inline void flush_unauthorized_files(const struct cred *cred,
                                                struct tty_file_private, list);
                        file = file_priv->file;
                        inode = file->f_path.dentry->d_inode;
-                       if (inode_has_perm(cred, inode,
-                                          FILE__READ | FILE__WRITE, NULL, 0)) {
+                       if (inode_has_perm_noadp(cred, inode,
+                                          FILE__READ | FILE__WRITE, 0)) {
                                drop_tty = 1;
                        }
                }
@@ -2121,7 +2141,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
 
        /* Revalidate access to inherited open files. */
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, INODE);
 
        spin_lock(&files->file_lock);
        for (;;) {
@@ -2469,8 +2489,8 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
        if (flags & MS_KERNMOUNT)
                return 0;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.dentry = sb->s_root;
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = sb->s_root;
        return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
 }
 
@@ -2479,8 +2499,8 @@ static int selinux_sb_statfs(struct dentry *dentry)
        const struct cred *cred = current_cred();
        struct common_audit_data ad;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.dentry = dentry->d_sb->s_root;
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = dentry->d_sb->s_root;
        return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
 }
 
@@ -2496,8 +2516,7 @@ static int selinux_mount(char *dev_name,
                return superblock_has_perm(cred, path->mnt->mnt_sb,
                                           FILESYSTEM__REMOUNT, NULL);
        else
-               return dentry_has_perm(cred, path->mnt, path->dentry,
-                                      FILE__MOUNTON);
+               return path_has_perm(cred, path, FILE__MOUNTON);
 }
 
 static int selinux_umount(struct vfsmount *mnt, int flags)
@@ -2630,14 +2649,14 @@ static int selinux_inode_readlink(struct dentry *dentry)
 {
        const struct cred *cred = current_cred();
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__READ);
+       return dentry_has_perm(cred, dentry, FILE__READ);
 }
 
 static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
 {
        const struct cred *cred = current_cred();
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__READ);
+       return dentry_has_perm(cred, dentry, FILE__READ);
 }
 
 static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags)
@@ -2654,8 +2673,8 @@ static int selinux_inode_permission(struct inode *inode, int mask, unsigned flag
        if (!mask)
                return 0;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.inode = inode;
+       COMMON_AUDIT_DATA_INIT(&ad, INODE);
+       ad.u.inode = inode;
 
        if (from_access)
                ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS;
@@ -2680,16 +2699,20 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 
        if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
                        ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
-               return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
+               return dentry_has_perm(cred, dentry, FILE__SETATTR);
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__WRITE);
+       return dentry_has_perm(cred, dentry, FILE__WRITE);
 }
 
 static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
 {
        const struct cred *cred = current_cred();
+       struct path path;
+
+       path.dentry = dentry;
+       path.mnt = mnt;
 
-       return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR);
+       return path_has_perm(cred, &path, FILE__GETATTR);
 }
 
 static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
@@ -2710,7 +2733,7 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
 
        /* Not an attribute we recognize, so just check the
           ordinary setattr permission. */
-       return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
+       return dentry_has_perm(cred, dentry, FILE__SETATTR);
 }
 
 static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
@@ -2733,8 +2756,8 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
        if (!inode_owner_or_capable(inode))
                return -EPERM;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.dentry = dentry;
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = dentry;
 
        rc = avc_has_perm(sid, isec->sid, isec->sclass,
                          FILE__RELABELFROM, &ad);
@@ -2797,14 +2820,14 @@ static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
 {
        const struct cred *cred = current_cred();
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
+       return dentry_has_perm(cred, dentry, FILE__GETATTR);
 }
 
 static int selinux_inode_listxattr(struct dentry *dentry)
 {
        const struct cred *cred = current_cred();
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
+       return dentry_has_perm(cred, dentry, FILE__GETATTR);
 }
 
 static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
@@ -3210,7 +3233,7 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred)
         * new inode label or new policy.
         * This check is not redundant - do not remove.
         */
-       return inode_has_perm(cred, inode, open_file_to_av(file), NULL, 0);
+       return inode_has_perm_noadp(cred, inode, open_file_to_av(file), 0);
 }
 
 /* task security operations */
index 348eb00cb6685fadfef59c5864157f909b092274..3ba4feba048a0158230620b83ca91d29c2e8ff26 100644 (file)
 #define POLICYDB_VERSION_PERMISSIVE    23
 #define POLICYDB_VERSION_BOUNDARY      24
 #define POLICYDB_VERSION_FILENAME_TRANS        25
+#define POLICYDB_VERSION_ROLETRANS     26
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN   POLICYDB_VERSION_BASE
 #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
 #define POLICYDB_VERSION_MAX   CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
 #else
-#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_FILENAME_TRANS
+#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_ROLETRANS
 #endif
 
 /* Mask for just the mount related flags */
@@ -85,7 +86,7 @@ extern int selinux_policycap_openperm;
 int security_mls_enabled(void);
 
 int security_load_policy(void *data, size_t len);
-int security_read_policy(void **data, ssize_t *len);
+int security_read_policy(void **data, size_t *len);
 size_t security_policydb_len(void);
 
 int security_policycap_supported(unsigned int req_cap);
@@ -111,8 +112,8 @@ void security_compute_av_user(u32 ssid, u32 tsid,
 int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
                            const struct qstr *qstr, u32 *out_sid);
 
-int security_transition_sid_user(u32 ssid, u32 tsid,
-                                u16 tclass, u32 *out_sid);
+int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
+                                const char *objname, u32 *out_sid);
 
 int security_member_sid(u32 ssid, u32 tsid,
        u16 tclass, u32 *out_sid);
index 65ebfe954f85395f490ce74d694d73a859b523ac..3618251d0fdb4435dfb96be2c845c0727deca04d 100644 (file)
@@ -141,6 +141,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
                break;
        default:
                BUG();
+               return NULL;
        }
 
        list_for_each_entry_rcu(node, &sel_netnode_hash[idx].list, list)
index 2d3373b2e256b5a8a61e69ddf8f03597eee2baff..35459340019e44399775c2f96aa9b5871f8d566c 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/percpu.h>
 #include <linux/audit.h>
 #include <linux/uaccess.h>
+#include <linux/kobject.h>
+#include <linux/ctype.h>
 
 /* selinuxfs pseudo filesystem for exporting the security policy API.
    Based on the proc code and the fs/nfsd/nfsctl.c code. */
@@ -750,14 +752,24 @@ out:
        return length;
 }
 
+static inline int hexcode_to_int(int code) {
+       if (code == '\0' || !isxdigit(code))
+               return -1;
+       if (isdigit(code))
+               return code - '0';
+       return tolower(code) - 'a' + 10;
+}
+
 static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
 {
        char *scon = NULL, *tcon = NULL;
+       char *namebuf = NULL, *objname = NULL;
        u32 ssid, tsid, newsid;
        u16 tclass;
        ssize_t length;
        char *newcon = NULL;
        u32 len;
+       int nargs;
 
        length = task_has_security(current, SECURITY__COMPUTE_CREATE);
        if (length)
@@ -773,10 +785,44 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
        if (!tcon)
                goto out;
 
-       length = -EINVAL;
-       if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
+       length = -ENOMEM;
+       namebuf = kzalloc(size + 1, GFP_KERNEL);
+       if (!namebuf)
                goto out;
 
+       length = -EINVAL;
+       nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf);
+       if (nargs < 3 || nargs > 4)
+               goto out;
+       if (nargs == 4) {
+               /*
+                * If and when the name of new object to be queried contains
+                * either whitespace or multibyte characters, they shall be
+                * encoded based on the percentage-encoding rule.
+                * If not encoded, the sscanf logic picks up only left-half
+                * of the supplied name; splitted by a whitespace unexpectedly.
+                */
+               char   *r, *w;
+               int     c1, c2;
+
+               r = w = namebuf;
+               do {
+                       c1 = *r++;
+                       if (c1 == '+')
+                               c1 = ' ';
+                       else if (c1 == '%') {
+                               if ((c1 = hexcode_to_int(*r++)) < 0)
+                                       goto out;
+                               if ((c2 = hexcode_to_int(*r++)) < 0)
+                                       goto out;
+                               c1 = (c1 << 4) | c2;
+                       }
+                       *w++ = c1;
+               } while (c1 != '\0');
+
+               objname = namebuf;
+       }
+
        length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
        if (length)
                goto out;
@@ -785,7 +831,8 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
        if (length)
                goto out;
 
-       length = security_transition_sid_user(ssid, tsid, tclass, &newsid);
+       length = security_transition_sid_user(ssid, tsid, tclass,
+                                             objname, &newsid);
        if (length)
                goto out;
 
@@ -804,6 +851,7 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
        length = len;
 out:
        kfree(newcon);
+       kfree(namebuf);
        kfree(tcon);
        kfree(scon);
        return length;
@@ -1901,6 +1949,7 @@ static struct file_system_type sel_fs_type = {
 };
 
 struct vfsmount *selinuxfs_mount;
+static struct kobject *selinuxfs_kobj;
 
 static int __init init_sel_fs(void)
 {
@@ -1908,9 +1957,16 @@ static int __init init_sel_fs(void)
 
        if (!selinux_enabled)
                return 0;
+
+       selinuxfs_kobj = kobject_create_and_add("selinux", fs_kobj);
+       if (!selinuxfs_kobj)
+               return -ENOMEM;
+
        err = register_filesystem(&sel_fs_type);
-       if (err)
+       if (err) {
+               kobject_put(selinuxfs_kobj);
                return err;
+       }
 
        selinuxfs_mount = kern_mount(&sel_fs_type);
        if (IS_ERR(selinuxfs_mount)) {
@@ -1927,6 +1983,7 @@ __initcall(init_sel_fs);
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
 void exit_sel_fs(void)
 {
+       kobject_put(selinuxfs_kobj);
        unregister_filesystem(&sel_fs_type);
 }
 #endif
index 7102457661d645cd499d770819ad92e3970f6831..d246aca3f4fbd43563bf01d20d78e28feb826ad8 100644 (file)
@@ -128,6 +128,11 @@ static struct policydb_compat_info policydb_compat[] = {
                .sym_num        = SYM_NUM,
                .ocon_num       = OCON_NUM,
        },
+       {
+               .version        = POLICYDB_VERSION_ROLETRANS,
+               .sym_num        = SYM_NUM,
+               .ocon_num       = OCON_NUM,
+       },
 };
 
 static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -179,6 +184,43 @@ out:
        return rc;
 }
 
+static u32 filenametr_hash(struct hashtab *h, const void *k)
+{
+       const struct filename_trans *ft = k;
+       unsigned long hash;
+       unsigned int byte_num;
+       unsigned char focus;
+
+       hash = ft->stype ^ ft->ttype ^ ft->tclass;
+
+       byte_num = 0;
+       while ((focus = ft->name[byte_num++]))
+               hash = partial_name_hash(focus, hash);
+       return hash & (h->size - 1);
+}
+
+static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2)
+{
+       const struct filename_trans *ft1 = k1;
+       const struct filename_trans *ft2 = k2;
+       int v;
+
+       v = ft1->stype - ft2->stype;
+       if (v)
+               return v;
+
+       v = ft1->ttype - ft2->ttype;
+       if (v)
+               return v;
+
+       v = ft1->tclass - ft2->tclass;
+       if (v)
+               return v;
+
+       return strcmp(ft1->name, ft2->name);
+
+}
+
 static u32 rangetr_hash(struct hashtab *h, const void *k)
 {
        const struct range_trans *key = k;
@@ -231,15 +273,22 @@ static int policydb_init(struct policydb *p)
        if (rc)
                goto out;
 
+       p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10));
+       if (!p->filename_trans)
+               goto out;
+
        p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
        if (!p->range_tr)
                goto out;
 
+       ebitmap_init(&p->filename_trans_ttypes);
        ebitmap_init(&p->policycaps);
        ebitmap_init(&p->permissive_map);
 
        return 0;
 out:
+       hashtab_destroy(p->filename_trans);
+       hashtab_destroy(p->range_tr);
        for (i = 0; i < SYM_NUM; i++)
                hashtab_destroy(p->symtab[i].table);
        return rc;
@@ -417,32 +466,26 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
 };
 
 #ifdef DEBUG_HASHES
-static void symtab_hash_eval(struct symtab *s)
+static void hash_eval(struct hashtab *h, const char *hash_name)
 {
-       int i;
-
-       for (i = 0; i < SYM_NUM; i++) {
-               struct hashtab *h = s[i].table;
-               struct hashtab_info info;
+       struct hashtab_info info;
 
-               hashtab_stat(h, &info);
-               printk(KERN_DEBUG "SELinux: %s:  %d entries and %d/%d buckets used, "
-                      "longest chain length %d\n", symtab_name[i], h->nel,
-                      info.slots_used, h->size, info.max_chain_len);
-       }
+       hashtab_stat(h, &info);
+       printk(KERN_DEBUG "SELinux: %s:  %d entries and %d/%d buckets used, "
+              "longest chain length %d\n", hash_name, h->nel,
+              info.slots_used, h->size, info.max_chain_len);
 }
 
-static void rangetr_hash_eval(struct hashtab *h)
+static void symtab_hash_eval(struct symtab *s)
 {
-       struct hashtab_info info;
+       int i;
 
-       hashtab_stat(h, &info);
-       printk(KERN_DEBUG "SELinux: rangetr:  %d entries and %d/%d buckets used, "
-              "longest chain length %d\n", h->nel,
-              info.slots_used, h->size, info.max_chain_len);
+       for (i = 0; i < SYM_NUM; i++)
+               hash_eval(s[i].table, symtab_name[i]);
 }
+
 #else
-static inline void rangetr_hash_eval(struct hashtab *h)
+static inline void hash_eval(struct hashtab *h, char *hash_name)
 {
 }
 #endif
@@ -675,6 +718,16 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
        cat_destroy,
 };
 
+static int filenametr_destroy(void *key, void *datum, void *p)
+{
+       struct filename_trans *ft = key;
+       kfree(ft->name);
+       kfree(key);
+       kfree(datum);
+       cond_resched();
+       return 0;
+}
+
 static int range_tr_destroy(void *key, void *datum, void *p)
 {
        struct mls_range *rt = datum;
@@ -709,7 +762,6 @@ void policydb_destroy(struct policydb *p)
        int i;
        struct role_allow *ra, *lra = NULL;
        struct role_trans *tr, *ltr = NULL;
-       struct filename_trans *ft, *nft;
 
        for (i = 0; i < SYM_NUM; i++) {
                cond_resched();
@@ -773,6 +825,9 @@ void policydb_destroy(struct policydb *p)
        }
        kfree(lra);
 
+       hashtab_map(p->filename_trans, filenametr_destroy, NULL);
+       hashtab_destroy(p->filename_trans);
+
        hashtab_map(p->range_tr, range_tr_destroy, NULL);
        hashtab_destroy(p->range_tr);
 
@@ -788,14 +843,7 @@ void policydb_destroy(struct policydb *p)
                flex_array_free(p->type_attr_map_array);
        }
 
-       ft = p->filename_trans;
-       while (ft) {
-               nft = ft->next;
-               kfree(ft->name);
-               kfree(ft);
-               ft = nft;
-       }
-
+       ebitmap_destroy(&p->filename_trans_ttypes);
        ebitmap_destroy(&p->policycaps);
        ebitmap_destroy(&p->permissive_map);
 
@@ -1795,7 +1843,7 @@ static int range_read(struct policydb *p, void *fp)
                rt = NULL;
                r = NULL;
        }
-       rangetr_hash_eval(p->range_tr);
+       hash_eval(p->range_tr, "rangetr");
        rc = 0;
 out:
        kfree(rt);
@@ -1805,9 +1853,10 @@ out:
 
 static int filename_trans_read(struct policydb *p, void *fp)
 {
-       struct filename_trans *ft, *last;
-       u32 nel, len;
+       struct filename_trans *ft;
+       struct filename_trans_datum *otype;
        char *name;
+       u32 nel, len;
        __le32 buf[4];
        int rc, i;
 
@@ -1816,25 +1865,23 @@ static int filename_trans_read(struct policydb *p, void *fp)
 
        rc = next_entry(buf, fp, sizeof(u32));
        if (rc)
-               goto out;
+               return rc;
        nel = le32_to_cpu(buf[0]);
 
-       last = p->filename_trans;
-       while (last && last->next)
-               last = last->next;
-
        for (i = 0; i < nel; i++) {
+               ft = NULL;
+               otype = NULL;
+               name = NULL;
+
                rc = -ENOMEM;
                ft = kzalloc(sizeof(*ft), GFP_KERNEL);
                if (!ft)
                        goto out;
 
-               /* add it to the tail of the list */
-               if (!last)
-                       p->filename_trans = ft;
-               else
-                       last->next = ft;
-               last = ft;
+               rc = -ENOMEM;
+               otype = kmalloc(sizeof(*otype), GFP_KERNEL);
+               if (!otype)
+                       goto out;
 
                /* length of the path component string */
                rc = next_entry(buf, fp, sizeof(u32));
@@ -1862,10 +1909,22 @@ static int filename_trans_read(struct policydb *p, void *fp)
                ft->stype = le32_to_cpu(buf[0]);
                ft->ttype = le32_to_cpu(buf[1]);
                ft->tclass = le32_to_cpu(buf[2]);
-               ft->otype = le32_to_cpu(buf[3]);
+
+               otype->otype = le32_to_cpu(buf[3]);
+
+               rc = ebitmap_set_bit(&p->filename_trans_ttypes, ft->ttype, 1);
+               if (rc)
+                       goto out;
+
+               hashtab_insert(p->filename_trans, ft, otype);
        }
-       rc = 0;
+       hash_eval(p->filename_trans, "filenametr");
+       return 0;
 out:
+       kfree(ft);
+       kfree(name);
+       kfree(otype);
+
        return rc;
 }
 
@@ -2266,6 +2325,11 @@ int policydb_read(struct policydb *p, void *fp)
                p->symtab[i].nprim = nprim;
        }
 
+       rc = -EINVAL;
+       p->process_class = string_to_security_class(p, "process");
+       if (!p->process_class)
+               goto bad;
+
        rc = avtab_read(&p->te_avtab, fp, p);
        if (rc)
                goto bad;
@@ -2298,8 +2362,17 @@ int policydb_read(struct policydb *p, void *fp)
                tr->role = le32_to_cpu(buf[0]);
                tr->type = le32_to_cpu(buf[1]);
                tr->new_role = le32_to_cpu(buf[2]);
+               if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
+                       rc = next_entry(buf, fp, sizeof(u32));
+                       if (rc)
+                               goto bad;
+                       tr->tclass = le32_to_cpu(buf[0]);
+               } else
+                       tr->tclass = p->process_class;
+
                if (!policydb_role_isvalid(p, tr->role) ||
                    !policydb_type_isvalid(p, tr->type) ||
+                   !policydb_class_isvalid(p, tr->tclass) ||
                    !policydb_role_isvalid(p, tr->new_role))
                        goto bad;
                ltr = tr;
@@ -2340,11 +2413,6 @@ int policydb_read(struct policydb *p, void *fp)
        if (rc)
                goto bad;
 
-       rc = -EINVAL;
-       p->process_class = string_to_security_class(p, "process");
-       if (!p->process_class)
-               goto bad;
-
        rc = -EINVAL;
        p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition");
        p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition");
@@ -2517,8 +2585,9 @@ static int cat_write(void *vkey, void *datum, void *ptr)
        return 0;
 }
 
-static int role_trans_write(struct role_trans *r, void *fp)
+static int role_trans_write(struct policydb *p, void *fp)
 {
+       struct role_trans *r = p->role_tr;
        struct role_trans *tr;
        u32 buf[3];
        size_t nel;
@@ -2538,6 +2607,12 @@ static int role_trans_write(struct role_trans *r, void *fp)
                rc = put_entry(buf, sizeof(u32), 3, fp);
                if (rc)
                        return rc;
+               if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
+                       buf[0] = cpu_to_le32(tr->tclass);
+                       rc = put_entry(buf, sizeof(u32), 1, fp);
+                       if (rc)
+                               return rc;
+               }
        }
 
        return 0;
@@ -3045,7 +3120,7 @@ static int genfs_write(struct policydb *p, void *fp)
        return 0;
 }
 
-static int range_count(void *key, void *data, void *ptr)
+static int hashtab_cnt(void *key, void *data, void *ptr)
 {
        int *cnt = ptr;
        *cnt = *cnt + 1;
@@ -3093,7 +3168,7 @@ static int range_write(struct policydb *p, void *fp)
 
        /* count the number of entries in the hashtab */
        nel = 0;
-       rc = hashtab_map(p->range_tr, range_count, &nel);
+       rc = hashtab_map(p->range_tr, hashtab_cnt, &nel);
        if (rc)
                return rc;
 
@@ -3110,43 +3185,63 @@ static int range_write(struct policydb *p, void *fp)
        return 0;
 }
 
-static int filename_trans_write(struct policydb *p, void *fp)
+static int filename_write_helper(void *key, void *data, void *ptr)
 {
-       struct filename_trans *ft;
-       u32 len, nel = 0;
        __le32 buf[4];
+       struct filename_trans *ft = key;
+       struct filename_trans_datum *otype = data;
+       void *fp = ptr;
        int rc;
+       u32 len;
 
-       for (ft = p->filename_trans; ft; ft = ft->next)
-               nel++;
-
-       buf[0] = cpu_to_le32(nel);
+       len = strlen(ft->name);
+       buf[0] = cpu_to_le32(len);
        rc = put_entry(buf, sizeof(u32), 1, fp);
        if (rc)
                return rc;
 
-       for (ft = p->filename_trans; ft; ft = ft->next) {
-               len = strlen(ft->name);
-               buf[0] = cpu_to_le32(len);
-               rc = put_entry(buf, sizeof(u32), 1, fp);
-               if (rc)
-                       return rc;
+       rc = put_entry(ft->name, sizeof(char), len, fp);
+       if (rc)
+               return rc;
 
-               rc = put_entry(ft->name, sizeof(char), len, fp);
-               if (rc)
-                       return rc;
+       buf[0] = ft->stype;
+       buf[1] = ft->ttype;
+       buf[2] = ft->tclass;
+       buf[3] = otype->otype;
 
-               buf[0] = ft->stype;
-               buf[1] = ft->ttype;
-               buf[2] = ft->tclass;
-               buf[3] = ft->otype;
+       rc = put_entry(buf, sizeof(u32), 4, fp);
+       if (rc)
+               return rc;
 
-               rc = put_entry(buf, sizeof(u32), 4, fp);
-               if (rc)
-                       return rc;
-       }
        return 0;
 }
+
+static int filename_trans_write(struct policydb *p, void *fp)
+{
+       u32 nel;
+       __le32 buf[1];
+       int rc;
+
+       if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
+               return 0;
+
+       nel = 0;
+       rc = hashtab_map(p->filename_trans, hashtab_cnt, &nel);
+       if (rc)
+               return rc;
+
+       buf[0] = cpu_to_le32(nel);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+
+       rc = hashtab_map(p->filename_trans, filename_write_helper, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
 /*
  * Write the configuration data in a policy database
  * structure to a policy database binary representation
@@ -3249,7 +3344,7 @@ int policydb_write(struct policydb *p, void *fp)
        if (rc)
                return rc;
 
-       rc = role_trans_write(p->role_tr, fp);
+       rc = role_trans_write(p, fp);
        if (rc)
                return rc;
 
index 732ea4a686821d048e7b09442b3f7f747c016732..b846c0387180942e2f50d31edc2982594f3dde2e 100644 (file)
@@ -72,17 +72,20 @@ struct role_datum {
 
 struct role_trans {
        u32 role;               /* current role */
-       u32 type;               /* program executable type */
+       u32 type;               /* program executable type, or new object type */
+       u32 tclass;             /* process class, or new object class */
        u32 new_role;           /* new role */
        struct role_trans *next;
 };
 
 struct filename_trans {
-       struct filename_trans *next;
        u32 stype;              /* current process */
        u32 ttype;              /* parent dir context */
        u16 tclass;             /* class of new object */
        const char *name;       /* last path component */
+};
+
+struct filename_trans_datum {
        u32 otype;              /* expected of new object */
 };
 
@@ -227,7 +230,10 @@ struct policydb {
        struct role_trans *role_tr;
 
        /* file transitions with the last path component */
-       struct filename_trans *filename_trans;
+       /* quickly exclude lookups when parent ttype has no rules */
+       struct ebitmap filename_trans_ttypes;
+       /* actual set of filename_trans rules */
+       struct hashtab *filename_trans;
 
        /* bools indexed by (value - 1) */
        struct cond_bool_datum **bool_val_to_struct;
index 6ef4af47dac497be5b8b2cc2ed64aeab4c3ee936..973e00e34fa9f18ff95d7920a18edbeb5987a5ba 100644 (file)
@@ -1359,26 +1359,35 @@ out:
 }
 
 static void filename_compute_type(struct policydb *p, struct context *newcontext,
-                                 u32 scon, u32 tcon, u16 tclass,
-                                 const struct qstr *qstr)
-{
-       struct filename_trans *ft;
-       for (ft = p->filename_trans; ft; ft = ft->next) {
-               if (ft->stype == scon &&
-                   ft->ttype == tcon &&
-                   ft->tclass == tclass &&
-                   !strcmp(ft->name, qstr->name)) {
-                       newcontext->type = ft->otype;
-                       return;
-               }
-       }
+                                 u32 stype, u32 ttype, u16 tclass,
+                                 const char *objname)
+{
+       struct filename_trans ft;
+       struct filename_trans_datum *otype;
+
+       /*
+        * Most filename trans rules are going to live in specific directories
+        * like /dev or /var/run.  This bitmap will quickly skip rule searches
+        * if the ttype does not contain any rules.
+        */
+       if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype))
+               return;
+
+       ft.stype = stype;
+       ft.ttype = ttype;
+       ft.tclass = tclass;
+       ft.name = objname;
+
+       otype = hashtab_search(p->filename_trans, &ft);
+       if (otype)
+               newcontext->type = otype->otype;
 }
 
 static int security_compute_sid(u32 ssid,
                                u32 tsid,
                                u16 orig_tclass,
                                u32 specified,
-                               const struct qstr *qstr,
+                               const char *objname,
                                u32 *out_sid,
                                bool kern)
 {
@@ -1478,23 +1487,21 @@ static int security_compute_sid(u32 ssid,
                newcontext.type = avdatum->data;
        }
 
-       /* if we have a qstr this is a file trans check so check those rules */
-       if (qstr)
+       /* if we have a objname this is a file trans check so check those rules */
+       if (objname)
                filename_compute_type(&policydb, &newcontext, scontext->type,
-                                     tcontext->type, tclass, qstr);
+                                     tcontext->type, tclass, objname);
 
        /* Check for class-specific changes. */
-       if  (tclass == policydb.process_class) {
-               if (specified & AVTAB_TRANSITION) {
-                       /* Look for a role transition rule. */
-                       for (roletr = policydb.role_tr; roletr;
-                            roletr = roletr->next) {
-                               if (roletr->role == scontext->role &&
-                                   roletr->type == tcontext->type) {
-                                       /* Use the role transition rule. */
-                                       newcontext.role = roletr->new_role;
-                                       break;
-                               }
+       if (specified & AVTAB_TRANSITION) {
+               /* Look for a role transition rule. */
+               for (roletr = policydb.role_tr; roletr; roletr = roletr->next) {
+                       if ((roletr->role == scontext->role) &&
+                           (roletr->type == tcontext->type) &&
+                           (roletr->tclass == tclass)) {
+                               /* Use the role transition rule. */
+                               newcontext.role = roletr->new_role;
+                               break;
                        }
                }
        }
@@ -1541,13 +1548,14 @@ int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
                            const struct qstr *qstr, u32 *out_sid)
 {
        return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
-                                   qstr, out_sid, true);
+                                   qstr ? qstr->name : NULL, out_sid, true);
 }
 
-int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid)
+int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
+                                const char *objname, u32 *out_sid)
 {
        return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
-                                   NULL, out_sid, false);
+                                   objname, out_sid, false);
 }
 
 /**
@@ -2209,10 +2217,11 @@ out_unlock:
                goto out;
        }
        for (i = 0, j = 0; i < mynel; i++) {
+               struct av_decision dummy_avd;
                rc = avc_has_perm_noaudit(fromsid, mysids[i],
                                          SECCLASS_PROCESS, /* kernel value */
                                          PROCESS__TRANSITION, AVC_STRICT,
-                                         NULL);
+                                         &dummy_avd);
                if (!rc)
                        mysids2[j++] = mysids[i];
                cond_resched();
@@ -3190,7 +3199,7 @@ out:
  * @len: length of data in bytes
  *
  */
-int security_read_policy(void **data, ssize_t *len)
+int security_read_policy(void **data, size_t *len)
 {
        int rc;
        struct policy_file fp;
index b449cfdad21c2a983ccc4ab2d2c981fe889cde1b..2b6c6a516123d65fea012f83fef9b43feb1b8b6d 100644 (file)
@@ -316,22 +316,17 @@ static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a,
 static inline void smk_ad_setfield_u_fs_path_dentry(struct smk_audit_info *a,
                                                    struct dentry *d)
 {
-       a->a.u.fs.path.dentry = d;
-}
-static inline void smk_ad_setfield_u_fs_path_mnt(struct smk_audit_info *a,
-                                                struct vfsmount *m)
-{
-       a->a.u.fs.path.mnt = m;
+       a->a.u.dentry = d;
 }
 static inline void smk_ad_setfield_u_fs_inode(struct smk_audit_info *a,
                                              struct inode *i)
 {
-       a->a.u.fs.inode = i;
+       a->a.u.inode = i;
 }
 static inline void smk_ad_setfield_u_fs_path(struct smk_audit_info *a,
                                             struct path p)
 {
-       a->a.u.fs.path = p;
+       a->a.u.path = p;
 }
 static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a,
                                            struct sock *sk)
index 400a5d5cde6183c9bc3c6d348f58b623e2821b46..9831a39c11f6f5d7196de2a5d154e75cb4bfc7c3 100644 (file)
@@ -383,7 +383,7 @@ static int smack_sb_statfs(struct dentry *dentry)
        int rc;
        struct smk_audit_info ad;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
        rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad);
@@ -407,7 +407,7 @@ static int smack_sb_mount(char *dev_name, struct path *path,
        struct superblock_smack *sbp = path->mnt->mnt_sb->s_security;
        struct smk_audit_info ad;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, *path);
 
        return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad);
@@ -425,10 +425,13 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags)
 {
        struct superblock_smack *sbp;
        struct smk_audit_info ad;
+       struct path path;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
-       smk_ad_setfield_u_fs_path_dentry(&ad, mnt->mnt_root);
-       smk_ad_setfield_u_fs_path_mnt(&ad, mnt);
+       path.dentry = mnt->mnt_root;
+       path.mnt = mnt;
+
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
+       smk_ad_setfield_u_fs_path(&ad, path);
 
        sbp = mnt->mnt_sb->s_security;
        return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad);
@@ -563,7 +566,7 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
        struct smk_audit_info ad;
        int rc;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
 
        isp = smk_of_inode(old_dentry->d_inode);
@@ -592,7 +595,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
        struct smk_audit_info ad;
        int rc;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
        /*
@@ -623,7 +626,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
        struct smk_audit_info ad;
        int rc;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
        /*
@@ -663,7 +666,7 @@ static int smack_inode_rename(struct inode *old_inode,
        char *isp;
        struct smk_audit_info ad;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
 
        isp = smk_of_inode(old_dentry->d_inode);
@@ -700,7 +703,7 @@ static int smack_inode_permission(struct inode *inode, int mask, unsigned flags)
        /* May be droppable after audit */
        if (flags & IPERM_FLAG_RCU)
                return -ECHILD;
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
        smk_ad_setfield_u_fs_inode(&ad, inode);
        return smk_curacc(smk_of_inode(inode), mask, &ad);
 }
@@ -720,7 +723,7 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
         */
        if (iattr->ia_valid & ATTR_FORCE)
                return 0;
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
        return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
@@ -736,10 +739,13 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
 {
        struct smk_audit_info ad;
+       struct path path;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
-       smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
-       smk_ad_setfield_u_fs_path_mnt(&ad, mnt);
+       path.dentry = dentry;
+       path.mnt = mnt;
+
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
+       smk_ad_setfield_u_fs_path(&ad, path);
        return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
 }
 
@@ -784,7 +790,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
        } else
                rc = cap_inode_setxattr(dentry, name, value, size, flags);
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
        if (rc == 0)
@@ -845,7 +851,7 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name)
 {
        struct smk_audit_info ad;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
        return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
@@ -877,7 +883,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
        } else
                rc = cap_inode_removexattr(dentry, name);
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
        if (rc == 0)
                rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
@@ -1047,7 +1053,7 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
        int rc = 0;
        struct smk_audit_info ad;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, file->f_path);
 
        if (_IOC_DIR(cmd) & _IOC_WRITE)
@@ -1070,8 +1076,8 @@ static int smack_file_lock(struct file *file, unsigned int cmd)
 {
        struct smk_audit_info ad;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
-       smk_ad_setfield_u_fs_path_dentry(&ad, file->f_path.dentry);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
+       smk_ad_setfield_u_fs_path(&ad, file->f_path);
        return smk_curacc(file->f_security, MAY_WRITE, &ad);
 }
 
@@ -1089,7 +1095,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
        struct smk_audit_info ad;
        int rc;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, file->f_path);
 
        switch (cmd) {
index 7556315c197823e0baedcf15d0f0930c74345429..a0d09e56874b6a3b7bf23d48631cfede23a105c7 100644 (file)
@@ -108,10 +108,9 @@ static bool tomoyo_flush(struct tomoyo_io_buffer *head)
                        head->read_user_buf += len;
                        w += len;
                }
-               if (*w) {
-                       head->r.w[0] = w;
+               head->r.w[0] = w;
+               if (*w)
                        return false;
-               }
                /* Add '\0' for query. */
                if (head->poll) {
                        if (!head->read_user_buf_avail ||
@@ -459,8 +458,16 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
        if (profile == &tomoyo_default_profile)
                return -EINVAL;
        if (!strcmp(data, "COMMENT")) {
-               const struct tomoyo_path_info *old_comment = profile->comment;
-               profile->comment = tomoyo_get_name(cp);
+               static DEFINE_SPINLOCK(lock);
+               const struct tomoyo_path_info *new_comment
+                       = tomoyo_get_name(cp);
+               const struct tomoyo_path_info *old_comment;
+               if (!new_comment)
+                       return -ENOMEM;
+               spin_lock(&lock);
+               old_comment = profile->comment;
+               profile->comment = new_comment;
+               spin_unlock(&lock);
                tomoyo_put_name(old_comment);
                return 0;
        }
index cb09f1fce910959f62dd6d249bc495bf6fa5d432..d64e8ecb6fb3e7cbb923cbf80e8cbb993872279b 100644 (file)
@@ -1011,7 +1011,6 @@ int tomoyo_path_perm(const u8 operation, struct path *path)
                break;
        case TOMOYO_TYPE_RMDIR:
        case TOMOYO_TYPE_CHROOT:
-       case TOMOYO_TYPE_UMOUNT:
                tomoyo_add_slash(&buf);
                break;
        }
index 297612669c74d244051662d8e1d4bd96d3040a11..42a7b1ba8cbf221ceeaa188c2089fa2a99e01a94 100644 (file)
@@ -75,6 +75,7 @@ void *tomoyo_commit_ok(void *data, const unsigned int size)
                memset(data, 0, size);
                return ptr;
        }
+       kfree(ptr);
        return NULL;
 }
 
index 82bf8c2390bc7c1b0d376ba22817b688447819cc..9fc2e15841c96f54edbefb24a96c40405d06bedd 100644 (file)
@@ -138,11 +138,12 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name,
        }
        if (need_dev) {
                /* Get mount point or device file. */
-               if (kern_path(dev_name, LOOKUP_FOLLOW, &path)) {
+               if (!dev_name || kern_path(dev_name, LOOKUP_FOLLOW, &path)) {
                        error = -ENOENT;
                        goto out;
                }
                requested_dev_name = tomoyo_realpath_from_path(&path);
+               path_put(&path);
                if (!requested_dev_name) {
                        error = -ENOENT;
                        goto out;
index 9bfc1ee8222ddf6c9edadb48067e5384f0598e8c..6d5393204d951ef0bdd2d7306ff8648bdf141078 100644 (file)
@@ -390,7 +390,7 @@ bool tomoyo_correct_domain(const unsigned char *domainname)
                if (!cp)
                        break;
                if (*domainname != '/' ||
-                   !tomoyo_correct_word2(domainname, cp - domainname - 1))
+                   !tomoyo_correct_word2(domainname, cp - domainname))
                        goto out;
                domainname = cp + 1;
        }
index 5d98194bcad55b6963037d95d35743909517018a..f8c5be46451058ba5a7f25d9a81195fd02643f92 100644 (file)
@@ -704,13 +704,12 @@ static int snd_ctl_elem_list(struct snd_card *card,
        struct snd_ctl_elem_list list;
        struct snd_kcontrol *kctl;
        struct snd_ctl_elem_id *dst, *id;
-       unsigned int offset, space, first, jidx;
+       unsigned int offset, space, jidx;
        
        if (copy_from_user(&list, _list, sizeof(list)))
                return -EFAULT;
        offset = list.offset;
        space = list.space;
-       first = 0;
        /* try limit maximum space */
        if (space > 16384)
                return -ENOMEM;
index 30ecad41403c1becb741f7312ca247eb96054b8c..2c041bb36ab3c177e032e16e39ee47777dce7f48 100644 (file)
@@ -342,7 +342,6 @@ static const struct file_operations snd_shutdown_f_ops =
 int snd_card_disconnect(struct snd_card *card)
 {
        struct snd_monitor_file *mfile;
-       struct file *file;
        int err;
 
        if (!card)
@@ -366,8 +365,6 @@ int snd_card_disconnect(struct snd_card *card)
        
        spin_lock(&card->files_lock);
        list_for_each_entry(mfile, &card->files_list, list) {
-               file = mfile->file;
-
                /* it's critical part, use endless loop */
                /* we have no room to fail */
                mfile->disconnected_f_op = mfile->file->f_op;
index 2c41825c836ec028c4725c2e038eb3937723c543..eb9fe2e1d291850f62a0db393535a3f394d4e9a0 100644 (file)
@@ -58,26 +58,6 @@ static const char *sanity_file_name(const char *path)
        else
                return path;
 }
-
-/* print file and line with a certain printk prefix */
-static int print_snd_pfx(unsigned int level, const char *path, int line,
-                        const char *format)
-{
-       const char *file = sanity_file_name(path);
-       char tmp[] = "<0>";
-       const char *pfx = level ? KERN_DEBUG : KERN_DEFAULT;
-       int ret = 0;
-
-       if (format[0] == '<' && format[2] == '>') {
-               tmp[1] = format[1];
-               pfx = tmp;
-               ret = 1;
-       }
-       printk("%sALSA %s:%d: ", pfx, file, line);
-       return ret;
-}
-#else
-#define print_snd_pfx(level, path, line, format)       0
 #endif
 
 #if defined(CONFIG_SND_DEBUG) || defined(CONFIG_SND_VERBOSE_PRINTK)
@@ -85,15 +65,29 @@ void __snd_printk(unsigned int level, const char *path, int line,
                  const char *format, ...)
 {
        va_list args;
-       
+#ifdef CONFIG_SND_VERBOSE_PRINTK
+       struct va_format vaf;
+       char verbose_fmt[] = KERN_DEFAULT "ALSA %s:%d %pV";
+#endif
+
 #ifdef CONFIG_SND_DEBUG        
        if (debug < level)
                return;
 #endif
+
        va_start(args, format);
-       if (print_snd_pfx(level, path, line, format))
-               format += 3; /* skip the printk level-prefix */
+#ifdef CONFIG_SND_VERBOSE_PRINTK
+       vaf.fmt = format;
+       vaf.va = &args;
+       if (format[0] == '<' && format[2] == '>') {
+               memcpy(verbose_fmt, format, 3);
+               vaf.fmt = format + 3;
+       } else if (level)
+               memcpy(verbose_fmt, KERN_DEBUG, 3);
+       printk(verbose_fmt, sanity_file_name(path), line, &vaf);
+#else
        vprintk(format, args);
+#endif
        va_end(args);
 }
 EXPORT_SYMBOL_GPL(__snd_printk);
index 13b3f6f49fae3c8624b8d47e44b24268be211b3c..2045697f449d3f5ebe347572dc2dfba66b64568a 100644 (file)
@@ -90,11 +90,8 @@ static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin,
                               struct snd_pcm_plugin_channel *dst_channels,
                               snd_pcm_uframes_t frames)
 {
-       struct linear_priv *data;
-
        if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
                return -ENXIO;
-       data = (struct linear_priv *)plugin->extra_data;
        if (frames == 0)
                return 0;
 #ifdef CONFIG_SND_DEBUG
index abfeff1611ce271eabe0bd98a1b75f613d626f96..f1341308bedaa585311896d3b62dcca8b86395cb 100644 (file)
@@ -1756,8 +1756,18 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
        wait_queue_t wait;
        int err = 0;
        snd_pcm_uframes_t avail = 0;
-       long tout;
-
+       long wait_time, tout;
+
+       if (runtime->no_period_wakeup)
+               wait_time = MAX_SCHEDULE_TIMEOUT;
+       else {
+               wait_time = 10;
+               if (runtime->rate) {
+                       long t = runtime->period_size * 2 / runtime->rate;
+                       wait_time = max(t, wait_time);
+               }
+               wait_time = msecs_to_jiffies(wait_time * 1000);
+       }
        init_waitqueue_entry(&wait, current);
        add_wait_queue(&runtime->tsleep, &wait);
        for (;;) {
@@ -1765,9 +1775,8 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
                        err = -ERESTARTSYS;
                        break;
                }
-               set_current_state(TASK_INTERRUPTIBLE);
                snd_pcm_stream_unlock_irq(substream);
-               tout = schedule_timeout(msecs_to_jiffies(10000));
+               tout = schedule_timeout_interruptible(wait_time);
                snd_pcm_stream_lock_irq(substream);
                switch (runtime->status->state) {
                case SNDRV_PCM_STATE_SUSPENDED:
index 1a07750f3836ae93826fa20d5c5f7a56511bb3c3..1c6be91dfb9887ea1b3634735858e27757c42e21 100644 (file)
@@ -1481,11 +1481,20 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
                        break; /* all drained */
                init_waitqueue_entry(&wait, current);
                add_wait_queue(&to_check->sleep, &wait);
-               set_current_state(TASK_INTERRUPTIBLE);
                snd_pcm_stream_unlock_irq(substream);
                up_read(&snd_pcm_link_rwsem);
                snd_power_unlock(card);
-               tout = schedule_timeout(10 * HZ);
+               if (runtime->no_period_wakeup)
+                       tout = MAX_SCHEDULE_TIMEOUT;
+               else {
+                       tout = 10;
+                       if (runtime->rate) {
+                               long t = runtime->period_size * 2 / runtime->rate;
+                               tout = max(t, tout);
+                       }
+                       tout = msecs_to_jiffies(tout * 1000);
+               }
+               tout = schedule_timeout_interruptible(tout);
                snd_power_lock(card);
                down_read(&snd_pcm_link_rwsem);
                snd_pcm_stream_lock_irq(substream);
@@ -1518,13 +1527,11 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
 static int snd_pcm_drop(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime;
-       struct snd_card *card;
        int result = 0;
        
        if (PCM_RUNTIME_CHECK(substream))
                return -ENXIO;
        runtime = substream->runtime;
-       card = substream->pcm->card;
 
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||
            runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED ||
@@ -2056,7 +2063,6 @@ static int snd_pcm_open_file(struct file *file,
 {
        struct snd_pcm_file *pcm_file;
        struct snd_pcm_substream *substream;
-       struct snd_pcm_str *str;
        int err;
 
        if (rpcm_file)
@@ -2073,7 +2079,6 @@ static int snd_pcm_open_file(struct file *file,
        }
        pcm_file->substream = substream;
        if (substream->ref_count == 1) {
-               str = substream->pstr;
                substream->file = pcm_file;
                substream->pcm_release = pcm_release_private;
        }
@@ -3015,11 +3020,9 @@ static const struct vm_operations_struct snd_pcm_vm_ops_status =
 static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file,
                               struct vm_area_struct *area)
 {
-       struct snd_pcm_runtime *runtime;
        long size;
        if (!(area->vm_flags & VM_READ))
                return -EINVAL;
-       runtime = substream->runtime;
        size = area->vm_end - area->vm_start;
        if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)))
                return -EINVAL;
@@ -3054,11 +3057,9 @@ static const struct vm_operations_struct snd_pcm_vm_ops_control =
 static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file,
                                struct vm_area_struct *area)
 {
-       struct snd_pcm_runtime *runtime;
        long size;
        if (!(area->vm_flags & VM_READ))
                return -EINVAL;
-       runtime = substream->runtime;
        size = area->vm_end - area->vm_start;
        if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)))
                return -EINVAL;
index e7a8e9e4edb2063760607f11afcd6187f94a92b4..f9077361c119d1a4a5eed6135a3d2e4042c812e5 100644 (file)
@@ -467,13 +467,11 @@ int snd_seq_queue_timer_open(int queueid)
 int snd_seq_queue_timer_close(int queueid)
 {
        struct snd_seq_queue *queue;
-       struct snd_seq_timer *tmr;
        int result = 0;
 
        queue = queueptr(queueid);
        if (queue == NULL)
                return -EINVAL;
-       tmr = queue->timer;
        snd_seq_timer_close(queue);
        queuefree(queue);
        return result;
index 86ee16ca365e6fc612a4ad25baf6ecbf9fbc6893..440030818db70c88c582d0047790baed074297c9 100644 (file)
@@ -209,6 +209,7 @@ static void isight_packet(struct fw_iso_context *context, u32 cycle,
                isight->packet_index = -1;
                return;
        }
+       fw_iso_context_queue_flush(isight->context);
 
        if (++index >= QUEUE_LENGTH)
                index = 0;
index 2ca6f4f85b412a18502ac0f6370d19cc604d7d56..e3569bdd3b64e704f82c9e621110abe8e0853f8d 100644 (file)
@@ -27,7 +27,6 @@
 #include "hpioctl.h"
 
 #include <linux/pci.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/jiffies.h>
 #include <linux/slab.h>
index fb311d8c05bff2365776260b089f878c7cb02ac6..5c6ea113d219cc2566a75d05d0d1e9b7f8272f2e 100644 (file)
@@ -60,7 +60,7 @@ struct code_header {
            HPI_VER_MINOR(HPI_VER) * 100 + HPI_VER_RELEASE(HPI_VER)))
 
 /***********************************************************************/
-#include "linux/pci.h"
+#include <linux/pci.h>
 /*-------------------------------------------------------------------*/
 short hpi_dsp_code_open(u32 adapter, struct dsp_code *ps_dsp_code,
        u32 *pos_error_code)
index 5e619a84da061295fa4758e313935e89aea8009d..15f0161ce4a2342f9eb9b5eca86392a9481eacc2 100644 (file)
@@ -1440,6 +1440,14 @@ static struct snd_emu_chip_details emu_chip_details[] = {
         .ca0102_chip = 1,
         .spk71 = 1,
         .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */
+       /* EMU0404 PCIe */
+       {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40051102,
+        .driver = "Audigy2", .name = "E-mu 0404 PCIe [MAEM8984]",
+        .id = "EMU0404",
+        .emu10k2_chip = 1,
+        .ca0108_chip = 1,
+        .spk71 = 1,
+        .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 PCIe ver_03 */
        /* Note that all E-mu cards require kernel 2.6 or newer. */
        {.vendor = 0x1102, .device = 0x0008,
         .driver = "Audigy2", .name = "SB Audigy 2 Value [Unknown]",
index eacd4901a308d8b0b3c6a269ccd8c38bbf4f4f67..a7ec7030cf87e9773a1ce1f58ee318ace075498a 100644 (file)
@@ -1234,9 +1234,12 @@ static int __devinit snd_fm801_create(struct snd_card *card,
        sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
        if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
            (tea575x_tuner & TUNER_TYPE_MASK) < 4) {
-               if (snd_tea575x_init(&chip->tea))
+               if (snd_tea575x_init(&chip->tea)) {
                        snd_printk(KERN_ERR "TEA575x radio not found\n");
-       } else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0)
+                       snd_fm801_free(chip);
+                       return -ENODEV;
+               }
+       } else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0) {
                /* autodetect tuner connection */
                for (tea575x_tuner = 1; tea575x_tuner <= 3; tea575x_tuner++) {
                        chip->tea575x_tuner = tea575x_tuner;
@@ -1246,6 +1249,12 @@ static int __devinit snd_fm801_create(struct snd_card *card,
                                break;
                        }
                }
+               if (tea575x_tuner == 4) {
+                       snd_printk(KERN_ERR "TEA575x radio not found\n");
+                       snd_fm801_free(chip);
+                       return -ENODEV;
+               }
+       }
        strlcpy(chip->tea.card, snd_fm801_tea575x_gpios[(tea575x_tuner & TUNER_TYPE_MASK) - 1].name, sizeof(chip->tea.card));
 #endif
 
index f1de1bac042c260e5612a2f55f9ff13e79a30406..55f0647458c70aebb79028d3131e6f520d63eb19 100644 (file)
@@ -50,7 +50,12 @@ int snd_hda_enable_beep_device(struct hda_codec *codec, int enable);
 int snd_hda_attach_beep_device(struct hda_codec *codec, int nid);
 void snd_hda_detach_beep_device(struct hda_codec *codec);
 #else
-#define snd_hda_attach_beep_device(...)                0
-#define snd_hda_detach_beep_device(...)
+static inline int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
+{
+       return 0;
+}
+static inline void snd_hda_detach_beep_device(struct hda_codec *codec)
+{
+}
 #endif
 #endif
index 8edd998509f72057143a75715ce19c17e4896354..45b4a8d70e085a36849f32d971e0d987b6ded638 100644 (file)
@@ -4719,7 +4719,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                           cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
        snd_printd("   inputs:");
        for (i = 0; i < cfg->num_inputs; i++) {
-               snd_printdd(" %s=0x%x",
+               snd_printd(" %s=0x%x",
                            hda_get_autocfg_input_label(codec, cfg, i),
                            cfg->inputs[i].pin);
        }
index 74b0560289c00630aca0ba952d8c80a0316e7fd8..b05f7be9dc1b154017838b4fda19486014ad6f47 100644 (file)
@@ -312,23 +312,6 @@ out_fail:
        return -EINVAL;
 }
 
-static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid)
-{
-       int eldv;
-       int present;
-
-       present = snd_hda_pin_sense(codec, nid);
-       eldv    = (present & AC_PINSENSE_ELDV);
-       present = (present & AC_PINSENSE_PRESENCE);
-
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-       printk(KERN_INFO "HDMI: sink_present = %d, eld_valid = %d\n",
-                       !!present, !!eldv);
-#endif
-
-       return eldv && present;
-}
-
 int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
 {
        return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
@@ -343,7 +326,7 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
        int size;
        unsigned char *buf;
 
-       if (!hdmi_eld_valid(codec, nid))
+       if (!eld->eld_valid)
                return -ENOENT;
 
        size = snd_hdmi_get_eld_size(codec, nid);
@@ -477,6 +460,8 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry,
 
        snd_iprintf(buffer, "monitor_present\t\t%d\n", e->monitor_present);
        snd_iprintf(buffer, "eld_valid\t\t%d\n", e->eld_valid);
+       if (!e->eld_valid)
+               return;
        snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name);
        snd_iprintf(buffer, "connection_type\t\t%s\n",
                                eld_connection_type_names[e->conn_type]);
index 43a036716d259af107b0b8b7cad7eb05768117aa..486f6deb3eee952ab810750ecee652c23acc2b11 100644 (file)
@@ -391,6 +391,7 @@ struct azx {
 
        /* chip type specific */
        int driver_type;
+       unsigned int driver_caps;
        int playback_streams;
        int playback_index_offset;
        int capture_streams;
@@ -464,6 +465,34 @@ enum {
        AZX_NUM_DRIVERS, /* keep this as last entry */
 };
 
+/* driver quirks (capabilities) */
+/* bits 0-7 are used for indicating driver type */
+#define AZX_DCAPS_NO_TCSEL     (1 << 8)        /* No Intel TCSEL bit */
+#define AZX_DCAPS_NO_MSI       (1 << 9)        /* No MSI support */
+#define AZX_DCAPS_ATI_SNOOP    (1 << 10)       /* ATI snoop enable */
+#define AZX_DCAPS_NVIDIA_SNOOP (1 << 11)       /* Nvidia snoop enable */
+#define AZX_DCAPS_SCH_SNOOP    (1 << 12)       /* SCH/PCH snoop enable */
+#define AZX_DCAPS_RIRB_DELAY   (1 << 13)       /* Long delay in read loop */
+#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14)     /* Put a delay before read */
+#define AZX_DCAPS_CTX_WORKAROUND (1 << 15)     /* X-Fi workaround */
+#define AZX_DCAPS_POSFIX_LPIB  (1 << 16)       /* Use LPIB as default */
+#define AZX_DCAPS_POSFIX_VIA   (1 << 17)       /* Use VIACOMBO as default */
+#define AZX_DCAPS_NO_64BIT     (1 << 18)       /* No 64bit address */
+#define AZX_DCAPS_SYNC_WRITE   (1 << 19)       /* sync each cmd write */
+
+/* quirks for ATI SB / AMD Hudson */
+#define AZX_DCAPS_PRESET_ATI_SB \
+       (AZX_DCAPS_ATI_SNOOP | AZX_DCAPS_NO_TCSEL | \
+        AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB)
+
+/* quirks for ATI/AMD HDMI */
+#define AZX_DCAPS_PRESET_ATI_HDMI \
+       (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB)
+
+/* quirks for Nvidia */
+#define AZX_DCAPS_PRESET_NVIDIA \
+       (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI)
+
 static char *driver_short_names[] __devinitdata = {
        [AZX_DRIVER_ICH] = "HDA Intel",
        [AZX_DRIVER_PCH] = "HDA Intel PCH",
@@ -566,7 +595,7 @@ static void azx_init_cmd_io(struct azx *chip)
        /* reset the rirb hw write pointer */
        azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
        /* set N=1, get RIRB response interrupt for new entry */
-       if (chip->driver_type == AZX_DRIVER_CTX)
+       if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
                azx_writew(chip, RINTCNT, 0xc0);
        else
                azx_writew(chip, RINTCNT, 1);
@@ -1056,19 +1085,24 @@ static void azx_init_pci(struct azx *chip)
         * codecs.
         * The PCI register TCSEL is defined in the Intel manuals.
         */
-       if (chip->driver_type != AZX_DRIVER_ATI &&
-           chip->driver_type != AZX_DRIVER_ATIHDMI)
+       if (!(chip->driver_caps & AZX_DCAPS_NO_TCSEL)) {
+               snd_printdd(SFX "Clearing TCSEL\n");
                update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0);
+       }
 
-       switch (chip->driver_type) {
-       case AZX_DRIVER_ATI:
-               /* For ATI SB450 azalia HD audio, we need to enable snoop */
+       /* For ATI SB450/600/700/800/900 and AMD Hudson azalia HD audio,
+        * we need to enable snoop.
+        */
+       if (chip->driver_caps & AZX_DCAPS_ATI_SNOOP) {
+               snd_printdd(SFX "Enabling ATI snoop\n");
                update_pci_byte(chip->pci,
                                ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 
                                0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP);
-               break;
-       case AZX_DRIVER_NVIDIA:
-               /* For NVIDIA HDA, enable snoop */
+       }
+
+       /* For NVIDIA HDA, enable snoop */
+       if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) {
+               snd_printdd(SFX "Enabling Nvidia snoop\n");
                update_pci_byte(chip->pci,
                                NVIDIA_HDA_TRANSREG_ADDR,
                                0x0f, NVIDIA_HDA_ENABLE_COHBITS);
@@ -1078,9 +1112,10 @@ static void azx_init_pci(struct azx *chip)
                update_pci_byte(chip->pci,
                                NVIDIA_HDA_OSTRM_COH,
                                0x01, NVIDIA_HDA_ENABLE_COHBIT);
-               break;
-       case AZX_DRIVER_SCH:
-       case AZX_DRIVER_PCH:
+       }
+
+       /* Enable SCH/PCH snoop if needed */
+       if (chip->driver_caps & AZX_DCAPS_SCH_SNOOP) {
                pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
                if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) {
                        pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC,
@@ -1091,14 +1126,6 @@ static void azx_init_pci(struct azx *chip)
                                (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)
                                ? "Failed" : "OK");
                }
-               break;
-       default:
-               /* AMD Hudson needs the similar snoop, as it seems... */
-               if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
-                       update_pci_byte(chip->pci,
-                               ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR,
-                               0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP);
-               break;
         }
 }
 
@@ -1152,7 +1179,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
        status = azx_readb(chip, RIRBSTS);
        if (status & RIRB_INT_MASK) {
                if (status & RIRB_INT_RESPONSE) {
-                       if (chip->driver_type == AZX_DRIVER_CTX)
+                       if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY)
                                udelay(80);
                        azx_update_rirb(chip);
                }
@@ -1421,8 +1448,10 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
        if (err < 0)
                return err;
 
-       if (chip->driver_type == AZX_DRIVER_NVIDIA)
+       if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) {
+               snd_printd(SFX "Enable delay in RIRB handling\n");
                chip->bus->needs_damn_long_delay = 1;
+       }
 
        codecs = 0;
        max_slots = azx_max_codecs[chip->driver_type];
@@ -1457,9 +1486,8 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
         * sequence like the pin-detection.  It seems that forcing the synced
         * access works around the stall.  Grrr...
         */
-       if (chip->pci->vendor == PCI_VENDOR_ID_AMD ||
-           chip->pci->vendor == PCI_VENDOR_ID_ATI) {
-               snd_printk(KERN_INFO SFX "Enable sync_write for AMD chipset\n");
+       if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) {
+               snd_printd(SFX "Enable sync_write for stable communication\n");
                chip->bus->sync_write = 1;
                chip->bus->allow_bus_reset = 1;
        }
@@ -1720,7 +1748,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
 
        stream_tag = azx_dev->stream_tag;
        /* CA-IBG chips need the playback stream starting from 1 */
-       if (chip->driver_type == AZX_DRIVER_CTX &&
+       if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) &&
            stream_tag > chip->capture_streams)
                stream_tag -= chip->capture_streams;
        return snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
@@ -2365,20 +2393,14 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
        }
 
        /* Check VIA/ATI HD Audio Controller exist */
-       switch (chip->driver_type) {
-       case AZX_DRIVER_VIA:
-               /* Use link position directly, avoid any transfer problem. */
+       if (chip->driver_caps & AZX_DCAPS_POSFIX_VIA) {
+               snd_printd(SFX "Using VIACOMBO position fix\n");
                return POS_FIX_VIACOMBO;
-       case AZX_DRIVER_ATI:
-               /* ATI chipsets don't work well with position-buffer */
+       }
+       if (chip->driver_caps & AZX_DCAPS_POSFIX_LPIB) {
+               snd_printd(SFX "Using LPIB position fix\n");
                return POS_FIX_LPIB;
-       case AZX_DRIVER_GENERIC:
-               /* AMD chipsets also don't work with position-buffer */
-               if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
-                       return POS_FIX_LPIB;
-               break;
        }
-
        return POS_FIX_AUTO;
 }
 
@@ -2460,8 +2482,8 @@ static void __devinit check_msi(struct azx *chip)
        }
 
        /* NVidia chipsets seem to cause troubles with MSI */
-       if (chip->driver_type == AZX_DRIVER_NVIDIA) {
-               printk(KERN_INFO "hda_intel: Disable MSI for Nvidia chipset\n");
+       if (chip->driver_caps & AZX_DCAPS_NO_MSI) {
+               printk(KERN_INFO "hda_intel: Disabling MSI\n");
                chip->msi = 0;
        }
 }
@@ -2471,7 +2493,7 @@ static void __devinit check_msi(struct azx *chip)
  * constructor
  */
 static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
-                               int dev, int driver_type,
+                               int dev, unsigned int driver_caps,
                                struct azx **rchip)
 {
        struct azx *chip;
@@ -2499,7 +2521,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        chip->card = card;
        chip->pci = pci;
        chip->irq = -1;
-       chip->driver_type = driver_type;
+       chip->driver_caps = driver_caps;
+       chip->driver_type = driver_caps & 0xff;
        check_msi(chip);
        chip->dev_index = dev;
        INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
@@ -2563,8 +2586,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap);
 
        /* disable SB600 64bit support for safety */
-       if ((chip->driver_type == AZX_DRIVER_ATI) ||
-           (chip->driver_type == AZX_DRIVER_ATIHDMI)) {
+       if (chip->pci->vendor == PCI_VENDOR_ID_ATI) {
                struct pci_dev *p_smbus;
                p_smbus = pci_get_device(PCI_VENDOR_ID_ATI,
                                         PCI_DEVICE_ID_ATI_SBX00_SMBUS,
@@ -2574,19 +2596,13 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
                                gcap &= ~ICH6_GCAP_64OK;
                        pci_dev_put(p_smbus);
                }
-       } else {
-               /* FIXME: not sure whether this is really needed, but
-                * Hudson isn't stable enough for allowing everything...
-                * let's check later again.
-                */
-               if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
-                       gcap &= ~ICH6_GCAP_64OK;
        }
 
-       /* disable 64bit DMA address for Teradici */
-       /* it does not work with device 6549:1200 subsys e4a2:040b */
-       if (chip->driver_type == AZX_DRIVER_TERA)
+       /* disable 64bit DMA address on some devices */
+       if (chip->driver_caps & AZX_DCAPS_NO_64BIT) {
+               snd_printd(SFX "Disabling 64bit DMA\n");
                gcap &= ~ICH6_GCAP_64OK;
+       }
 
        /* allow 64bit DMA address if supported by H/W */
        if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
@@ -2788,38 +2804,62 @@ static void __devexit azx_remove(struct pci_dev *pci)
 /* PCI IDs */
 static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        /* CPT */
-       { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
+       { PCI_DEVICE(0x8086, 0x1c20),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
        /* PBG */
-       { PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH },
+       { PCI_DEVICE(0x8086, 0x1d20),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
        /* Panther Point */
-       { PCI_DEVICE(0x8086, 0x1e20), .driver_data = AZX_DRIVER_PCH },
+       { PCI_DEVICE(0x8086, 0x1e20),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
        /* SCH */
-       { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
+       { PCI_DEVICE(0x8086, 0x811b),
+         .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP },
        /* Generic Intel */
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
          .driver_data = AZX_DRIVER_ICH },
-       /* ATI SB 450/600 */
-       { PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI },
-       { PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI },
+       /* ATI SB 450/600/700/800/900 */
+       { PCI_DEVICE(0x1002, 0x437b),
+         .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
+       { PCI_DEVICE(0x1002, 0x4383),
+         .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
+       /* AMD Hudson */
+       { PCI_DEVICE(0x1022, 0x780d),
+         .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
        /* ATI HDMI */
-       { PCI_DEVICE(0x1002, 0x793b), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0x7919), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0x960f), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0x970f), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa00), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa08), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa10), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa18), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa20), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa28), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa30), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa38), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa40), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa48), .driver_data = AZX_DRIVER_ATIHDMI },
+       { PCI_DEVICE(0x1002, 0x793b),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0x7919),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0x960f),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0x970f),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa00),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa08),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa10),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa18),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa20),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa28),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa30),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa38),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa40),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa48),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
        /* VIA VT8251/VT8237A */
-       { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA },
+       { PCI_DEVICE(0x1106, 0x3288),
+         .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA },
        /* SIS966 */
        { PCI_DEVICE(0x1039, 0x7502), .driver_data = AZX_DRIVER_SIS },
        /* ULI M5461 */
@@ -2828,9 +2868,10 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
-         .driver_data = AZX_DRIVER_NVIDIA },
+         .driver_data = AZX_DRIVER_NVIDIA | AZX_DCAPS_PRESET_NVIDIA },
        /* Teradici */
-       { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
+       { PCI_DEVICE(0x6549, 0x1200),
+         .driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT },
        /* Creative X-Fi (CA0110-IBG) */
 #if !defined(CONFIG_SND_CTXFI) && !defined(CONFIG_SND_CTXFI_MODULE)
        /* the following entry conflicts with snd-ctxfi driver,
@@ -2840,10 +2881,13 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
-         .driver_data = AZX_DRIVER_CTX },
+         .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
+         AZX_DCAPS_RIRB_PRE_DELAY },
 #else
        /* this entry seems still valid -- i.e. without emu20kx chip */
-       { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_CTX },
+       { PCI_DEVICE(0x1102, 0x0009),
+         .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
+         AZX_DCAPS_RIRB_PRE_DELAY },
 #endif
        /* Vortex86MX */
        { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
@@ -2853,11 +2897,11 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
-         .driver_data = AZX_DRIVER_GENERIC },
+         .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
-         .driver_data = AZX_DRIVER_GENERIC },
+         .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);
index f1b3875c57dff4a73a27ad7b97817eaa1c119af1..d694e9d4921d85eef34f6588386c0235c9913e10 100644 (file)
@@ -506,9 +506,11 @@ static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
                                hda_nid_t hp)
 {
        struct ad198x_spec *spec = codec->spec;
-       snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
+       if (snd_hda_query_pin_caps(codec, front) & AC_PINCAP_EAPD)
+               snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
                            !spec->inv_eapd ? 0x00 : 0x02);
-       snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
+       if (snd_hda_query_pin_caps(codec, hp) & AC_PINCAP_EAPD)
+               snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
                            !spec->inv_eapd ? 0x00 : 0x02);
 }
 
@@ -524,6 +526,10 @@ static void ad198x_power_eapd(struct hda_codec *codec)
        case 0x11d4184a:
        case 0x11d4194a:
        case 0x11d4194b:
+       case 0x11d41988:
+       case 0x11d4198b:
+       case 0x11d4989a:
+       case 0x11d4989b:
                ad198x_power_eapd_write(codec, 0x12, 0x11);
                break;
        case 0x11d41981:
@@ -533,12 +539,6 @@ static void ad198x_power_eapd(struct hda_codec *codec)
        case 0x11d41986:
                ad198x_power_eapd_write(codec, 0x1b, 0x1a);
                break;
-       case 0x11d41988:
-       case 0x11d4198b:
-       case 0x11d4989a:
-       case 0x11d4989b:
-               ad198x_power_eapd_write(codec, 0x29, 0x22);
-               break;
        }
 }
 
@@ -3159,6 +3159,7 @@ static const struct snd_pci_quirk ad1988_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
        SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
        SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
+       SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG),
        SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
        {}
 };
index 4f37477d3c71b5238b049275987cca2656df0107..694b9daf691f74208b88a069623586af1ef92c0b 100644 (file)
@@ -3098,8 +3098,11 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS),
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS),
+       SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G565", CXT5066_AUTO),
        SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */
+       SND_PCI_QUIRK(0x1b0a, 0x2092, "CyberpowerPC Gamer Xplorer N57001", CXT5066_AUTO),
        {}
 };
 
@@ -3433,7 +3436,9 @@ static void cx_auto_parse_output(struct hda_codec *codec)
                        break;
                }
        }
-       if (spec->auto_mute && cfg->line_out_pins[0] &&
+       if (spec->auto_mute &&
+           cfg->line_out_pins[0] &&
+           cfg->line_out_type != AUTO_PIN_SPEAKER_OUT &&
            cfg->line_out_pins[0] != cfg->hp_pins[0] &&
            cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
                for (i = 0; i < cfg->line_outs; i++) {
@@ -3481,25 +3486,32 @@ static void cx_auto_update_speakers(struct hda_codec *codec)
 {
        struct conexant_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
-       int on;
+       int on = 1;
 
-       if (!spec->auto_mute)
-               on = 0;
-       else
-               on = spec->hp_present | spec->line_present;
+       /* turn on HP EAPD when HP jacks are present */
+       if (spec->auto_mute)
+               on = spec->hp_present;
        cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on);
-       do_automute(codec, cfg->speaker_outs, cfg->speaker_pins, !on);
+       /* mute speakers in auto-mode if HP or LO jacks are plugged */
+       if (spec->auto_mute)
+               on = !(spec->hp_present ||
+                      (spec->detect_line && spec->line_present));
+       do_automute(codec, cfg->speaker_outs, cfg->speaker_pins, on);
 
        /* toggle line-out mutes if needed, too */
        /* if LO is a copy of either HP or Speaker, don't need to handle it */
        if (cfg->line_out_pins[0] == cfg->hp_pins[0] ||
            cfg->line_out_pins[0] == cfg->speaker_pins[0])
                return;
-       if (!spec->automute_lines || !spec->auto_mute)
-               on = 0;
-       else
-               on = spec->hp_present;
-       do_automute(codec, cfg->line_outs, cfg->line_out_pins, !on);
+       if (spec->auto_mute) {
+               /* mute LO in auto-mode when HP jack is present */
+               if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ||
+                   spec->automute_lines)
+                       on = !spec->hp_present;
+               else
+                       on = 1;
+       }
+       do_automute(codec, cfg->line_outs, cfg->line_out_pins, on);
 }
 
 static void cx_auto_hp_automute(struct hda_codec *codec)
@@ -3696,13 +3708,14 @@ static int cx_auto_mux_enum_update(struct hda_codec *codec,
 {
        struct conexant_spec *spec = codec->spec;
        hda_nid_t adc;
+       int changed = 1;
 
        if (!imux->num_items)
                return 0;
        if (idx >= imux->num_items)
                idx = imux->num_items - 1;
        if (spec->cur_mux[0] == idx)
-               return 0;
+               changed = 0;
        adc = spec->imux_info[idx].adc;
        select_input_connection(codec, spec->imux_info[idx].adc,
                                spec->imux_info[idx].pin);
@@ -3715,7 +3728,7 @@ static int cx_auto_mux_enum_update(struct hda_codec *codec,
                                           spec->cur_adc_format);
        }
        spec->cur_mux[0] = idx;
-       return 1;
+       return changed;
 }
 
 static int cx_auto_mux_enum_put(struct snd_kcontrol *kcontrol,
@@ -3789,7 +3802,7 @@ static void cx_auto_check_auto_mic(struct hda_codec *codec)
        int pset[INPUT_PIN_ATTR_NORMAL + 1];
        int i;
 
-       for (i = 0; i < INPUT_PIN_ATTR_NORMAL; i++)
+       for (i = 0; i < ARRAY_SIZE(pset); i++)
                pset[i] = -1;
        for (i = 0; i < spec->private_imux.num_items; i++) {
                hda_nid_t pin = spec->imux_info[i].pin;
index 322901873222c446f6570c8139671697fd291e23..bd0ae697f9c4118ae5947e1f6015d41cff3638ea 100644 (file)
@@ -48,8 +48,8 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
  *
  * The HDA correspondence of pipes/ports are converter/pin nodes.
  */
-#define MAX_HDMI_CVTS  3
-#define MAX_HDMI_PINS  3
+#define MAX_HDMI_CVTS  4
+#define MAX_HDMI_PINS  4
 
 struct hdmi_spec {
        int num_cvts;
@@ -78,10 +78,6 @@ struct hdmi_spec {
         */
        struct hda_multi_out multiout;
        const struct hda_pcm_stream *pcm_playback;
-
-       /* misc flags */
-       /* PD bit indicates only the update, not the current state */
-       unsigned int old_pin_detect:1;
 };
 
 
@@ -300,13 +296,6 @@ static int hda_node_index(hda_nid_t *nids, hda_nid_t nid)
        return -EINVAL;
 }
 
-static void hdmi_get_show_eld(struct hda_codec *codec, hda_nid_t pin_nid,
-                             struct hdmi_eld *eld)
-{
-       if (!snd_hdmi_get_eld(eld, codec, pin_nid))
-               snd_hdmi_show_eld(eld);
-}
-
 #ifdef BE_PARANOID
 static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
                                int *packet_index, int *byte_index)
@@ -694,35 +683,20 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
 static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 {
        struct hdmi_spec *spec = codec->spec;
-       int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
-       int pind = !!(res & AC_UNSOL_RES_PD);
+       int pin_nid = res >> AC_UNSOL_RES_TAG_SHIFT;
+       int pd = !!(res & AC_UNSOL_RES_PD);
        int eldv = !!(res & AC_UNSOL_RES_ELDV);
        int index;
 
        printk(KERN_INFO
                "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
-               tag, pind, eldv);
+               pin_nid, pd, eldv);
 
-       index = hda_node_index(spec->pin, tag);
+       index = hda_node_index(spec->pin, pin_nid);
        if (index < 0)
                return;
 
-       if (spec->old_pin_detect) {
-               if (pind)
-                       hdmi_present_sense(codec, tag, &spec->sink_eld[index]);
-               pind = spec->sink_eld[index].monitor_present;
-       }
-
-       spec->sink_eld[index].monitor_present = pind;
-       spec->sink_eld[index].eld_valid = eldv;
-
-       if (pind && eldv) {
-               hdmi_get_show_eld(codec, spec->pin[index],
-                                 &spec->sink_eld[index]);
-               /* TODO: do real things about ELD */
-       }
-
-       snd_hda_input_jack_report(codec, tag);
+       hdmi_present_sense(codec, pin_nid, &spec->sink_eld[index]);
 }
 
 static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -903,13 +877,33 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid)
 static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
                               struct hdmi_eld *eld)
 {
+       /*
+        * Always execute a GetPinSense verb here, even when called from
+        * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited
+        * response's PD bit is not the real PD value, but indicates that
+        * the real PD value changed. An older version of the HD-audio
+        * specification worked this way. Hence, we just ignore the data in
+        * the unsolicited response to avoid custom WARs.
+        */
        int present = snd_hda_pin_sense(codec, pin_nid);
 
+       memset(eld, 0, sizeof(*eld));
+
        eld->monitor_present    = !!(present & AC_PINSENSE_PRESENCE);
-       eld->eld_valid          = !!(present & AC_PINSENSE_ELDV);
+       if (eld->monitor_present)
+               eld->eld_valid  = !!(present & AC_PINSENSE_ELDV);
+       else
+               eld->eld_valid  = 0;
 
-       if (present & AC_PINSENSE_ELDV)
-               hdmi_get_show_eld(codec, pin_nid, eld);
+       printk(KERN_INFO
+               "HDMI status: Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
+               pin_nid, eld->monitor_present, eld->eld_valid);
+
+       if (eld->eld_valid)
+               if (!snd_hdmi_get_eld(eld, codec, pin_nid))
+                       snd_hdmi_show_eld(eld);
+
+       snd_hda_input_jack_report(codec, pin_nid);
 }
 
 static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
@@ -927,7 +921,6 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
                                     SND_JACK_VIDEOOUT, NULL);
        if (err < 0)
                return err;
-       snd_hda_input_jack_report(codec, pin_nid);
 
        hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]);
 
@@ -1034,6 +1027,7 @@ static char *generic_hdmi_pcm_names[MAX_HDMI_CVTS] = {
        "HDMI 0",
        "HDMI 1",
        "HDMI 2",
+       "HDMI 3",
 };
 
 /*
@@ -1490,18 +1484,6 @@ static const struct hda_codec_ops nvhdmi_patch_ops_2ch = {
        .free = generic_hdmi_free,
 };
 
-static int patch_nvhdmi_8ch_89(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-       int err = patch_generic_hdmi(codec);
-
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-       spec->old_pin_detect = 1;
-       return 0;
-}
-
 static int patch_nvhdmi_2ch(struct hda_codec *codec)
 {
        struct hdmi_spec *spec;
@@ -1515,7 +1497,6 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec)
        spec->multiout.num_dacs = 0;  /* no analog */
        spec->multiout.max_channels = 2;
        spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
-       spec->old_pin_detect = 1;
        spec->num_cvts = 1;
        spec->cvt[0] = nvhdmi_master_con_nid_7x;
        spec->pcm_playback = &nvhdmi_pcm_playback_2ch;
@@ -1658,28 +1639,28 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
 { .id = 0x10de0005, .name = "MCP77/78 HDMI",   .patch = patch_nvhdmi_8ch_7x },
 { .id = 0x10de0006, .name = "MCP77/78 HDMI",   .patch = patch_nvhdmi_8ch_7x },
 { .id = 0x10de0007, .name = "MCP79/7A HDMI",   .patch = patch_nvhdmi_8ch_7x },
-{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de000c, .name = "MCP89 HDMI",      .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de000c, .name = "MCP89 HDMI",      .patch = patch_generic_hdmi },
+{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP",  .patch = patch_generic_hdmi },
 /* 17 is known to be absent */
-{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
-{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP",  .patch = patch_generic_hdmi },
+{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP",  .patch = patch_generic_hdmi },
 { .id = 0x10de0067, .name = "MCP67 HDMI",      .patch = patch_nvhdmi_2ch },
 { .id = 0x10de8001, .name = "MCP73 HDMI",      .patch = patch_nvhdmi_2ch },
 { .id = 0x80860054, .name = "IbexPeak HDMI",   .patch = patch_generic_hdmi },
index 7a4e10002f56dcb5b2bf299c81bcc72b57a77cd2..d21191dcfe8809e27d8fe9da883b796b20d18322 100644 (file)
@@ -1141,6 +1141,13 @@ static void update_speakers(struct hda_codec *codec)
        struct alc_spec *spec = codec->spec;
        int on;
 
+       /* Control HP pins/amps depending on master_mute state;
+        * in general, HP pins/amps control should be enabled in all cases,
+        * but currently set only for master_mute, just to be safe
+        */
+       do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
+                   spec->autocfg.hp_pins, spec->master_mute, true);
+
        if (!spec->automute)
                on = 0;
        else
@@ -4876,7 +4883,6 @@ static const struct snd_pci_quirk alc880_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
        SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
        SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
-       SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
        SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
        SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
        SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
@@ -6201,11 +6207,6 @@ static const struct snd_kcontrol_new alc260_input_mixer[] = {
 /* update HP, line and mono out pins according to the master switch */
 static void alc260_hp_master_update(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-
-       /* change HP pins */
-       do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
-                   spec->autocfg.hp_pins, spec->master_mute, true);
        update_speakers(codec);
 }
 
@@ -11924,7 +11925,7 @@ static const struct hda_verb alc262_nec_verbs[] = {
  *  0x1b = port replicator headphone out
  */
 
-#define ALC_HP_EVENT   0x37
+#define ALC_HP_EVENT   ALC880_HP_EVENT
 
 static const struct hda_verb alc262_fujitsu_unsol_verbs[] = {
        {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
@@ -12598,6 +12599,7 @@ static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
  */
 enum {
        PINFIX_FSC_H270,
+       PINFIX_HP_Z200,
 };
 
 static const struct alc_fixup alc262_fixups[] = {
@@ -12610,9 +12612,17 @@ static const struct alc_fixup alc262_fixups[] = {
                        { }
                }
        },
+       [PINFIX_HP_Z200] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x16, 0x99130120 }, /* internal speaker */
+                       { }
+               }
+       },
 };
 
 static const struct snd_pci_quirk alc262_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", PINFIX_HP_Z200),
        SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
        {}
 };
@@ -12729,6 +12739,8 @@ static const struct snd_pci_quirk alc262_cfg_tbl[] = {
                           ALC262_HP_BPC),
        SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series",
                           ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200",
+                          ALC262_AUTO),
        SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
                           ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
@@ -13314,9 +13326,8 @@ static void alc268_acer_lc_setup(struct hda_codec *codec)
        struct alc_spec *spec = codec->spec;
        spec->autocfg.hp_pins[0] = 0x15;
        spec->autocfg.speaker_pins[0] = 0x14;
-       spec->automute_mixer_nid[0] = 0x0f;
        spec->automute = 1;
-       spec->automute_mode = ALC_AUTOMUTE_MIXER;
+       spec->automute_mode = ALC_AUTOMUTE_AMP;
        spec->ext_mic.pin = 0x18;
        spec->ext_mic.mux_idx = 0;
        spec->int_mic.pin = 0x12;
@@ -13860,6 +13871,7 @@ static const struct snd_pci_quirk alc268_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
                                                ALC268_ACER_ASPIRE_ONE),
        SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
+       SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron 910", ALC268_AUTO),
        SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
                        "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
        /* almost compatible with toshiba but with optional digital outs;
@@ -13870,7 +13882,6 @@ static const struct snd_pci_quirk alc268_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
        SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
        SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
-       SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
        SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
        {}
 };
index 605c99e1e520de5d205a76046764d7e5f0f5a852..f43bb0eaed8b8e3c6f75ca08c7179267937c3be1 100644 (file)
@@ -745,12 +745,23 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
        struct via_spec *spec = codec->spec;
        hda_nid_t nid = kcontrol->private_value;
        unsigned int pinsel = ucontrol->value.enumerated.item[0];
+       unsigned int parm0, parm1;
        /* Get Independent Mode index of headphone pin widget */
        spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel
                ? 1 : 0;
-       if (spec->codec_type == VT1718S)
+       if (spec->codec_type == VT1718S) {
                snd_hda_codec_write(codec, nid, 0,
                                    AC_VERB_SET_CONNECT_SEL, pinsel ? 2 : 0);
+               /* Set correct mute switch for MW3 */
+               parm0 = spec->hp_independent_mode ?
+                              AMP_IN_UNMUTE(0) : AMP_IN_MUTE(0);
+               parm1 = spec->hp_independent_mode ?
+                              AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1);
+               snd_hda_codec_write(codec, 0x1b, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, parm0);
+               snd_hda_codec_write(codec, 0x1b, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, parm1);
+       }
        else
                snd_hda_codec_write(codec, nid, 0,
                                    AC_VERB_SET_CONNECT_SEL, pinsel);
@@ -832,10 +843,13 @@ static int via_hp_build(struct hda_codec *codec)
        knew->subdevice = HDA_SUBDEV_NID_FLAG | nid;
        knew->private_value = nid;
 
-       knew = via_clone_control(spec, &via_hp_mixer[1]);
-       if (knew == NULL)
-               return -ENOMEM;
-       knew->subdevice = side_mute_channel(spec);
+       nid = side_mute_channel(spec);
+       if (nid) {
+               knew = via_clone_control(spec, &via_hp_mixer[1]);
+               if (knew == NULL)
+                       return -ENOMEM;
+               knew->subdevice = nid;
+       }
 
        return 0;
 }
@@ -4280,9 +4294,6 @@ static const struct hda_verb vt1718S_volume_init_verbs[] = {
        {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
        {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
        {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
-
-       /* Setup default input of Front HP to MW9 */
-       {0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
        /* PW9 PW10 Output enable */
        {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
        {0x2e, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
@@ -4291,10 +4302,10 @@ static const struct hda_verb vt1718S_volume_init_verbs[] = {
        /* Enable Boost Volume backdoor */
        {0x1, 0xf88, 0x8},
        /* MW0/1/2/3/4: un-mute index 0 (AOWx), mute index 1 (MW9) */
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
@@ -4304,8 +4315,6 @@ static const struct hda_verb vt1718S_volume_init_verbs[] = {
        /* set MUX1 = 2 (AOW4), MUX2 = 1 (AOW3) */
        {0x34, AC_VERB_SET_CONNECT_SEL, 0x2},
        {0x35, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* Unmute MW4's index 0 */
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { }
 };
 
@@ -4453,6 +4462,19 @@ static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec,
                        if (err < 0)
                                return err;
                } else if (i == AUTO_SEQ_FRONT) {
+                       /* add control to mixer index 0 */
+                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                                             "Master Front Playback Volume",
+                                             HDA_COMPOSE_AMP_VAL(0x21, 3, 5,
+                                                                 HDA_INPUT));
+                       if (err < 0)
+                               return err;
+                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                                             "Master Front Playback Switch",
+                                             HDA_COMPOSE_AMP_VAL(0x21, 3, 5,
+                                                                 HDA_INPUT));
+                       if (err < 0)
+                               return err;
                        /* Front */
                        sprintf(name, "%s Playback Volume", chname[i]);
                        err = via_add_control(
index 34b24286d279d542e3d24e80a3531e8cf95bc8f5..2692e5ae5f2daa53822242c864a4f1b5ddf6a8ff 100644 (file)
@@ -445,7 +445,7 @@ static void lola_reset_setups(struct lola *chip)
        lola_setup_all_analog_gains(chip, PLAY, false); /* output, update */
 }
 
-static int lola_parse_tree(struct lola *chip)
+static int __devinit lola_parse_tree(struct lola *chip)
 {
        unsigned int val;
        int nid, err;
index 949691a876d3635798c6000da1b651d13684b1a6..3f08afc0f0d382b5b509c924abc2eb8532f4c822 100644 (file)
@@ -521,6 +521,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 #define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024)
 
 /* revisions >= 230 indicate AES32 card */
+#define HDSPM_MADI_OLD_REV     207
 #define HDSPM_MADI_REV         210
 #define HDSPM_RAYDAT_REV       211
 #define HDSPM_AIO_REV          212
@@ -1143,7 +1144,7 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
 
                /* if wordclock has synced freq and wordclock is valid */
                if ((status2 & HDSPM_wcLock) != 0 &&
-                               (status & HDSPM_SelSyncRef0) == 0) {
+                               (status2 & HDSPM_SelSyncRef0) == 0) {
 
                        rate_bits = status2 & HDSPM_wcFreqMask;
 
@@ -1639,12 +1640,14 @@ static int snd_hdspm_midi_input_read (struct hdspm_midi *hmidi)
                }
        }
        hmidi->pending = 0;
+       spin_unlock_irqrestore(&hmidi->lock, flags);
 
+       spin_lock_irqsave(&hmidi->hdspm->lock, flags);
        hmidi->hdspm->control_register |= hmidi->ie;
        hdspm_write(hmidi->hdspm, HDSPM_controlRegister,
                    hmidi->hdspm->control_register);
+       spin_unlock_irqrestore(&hmidi->hdspm->lock, flags);
 
-       spin_unlock_irqrestore (&hmidi->lock, flags);
        return snd_hdspm_midi_output_write (hmidi);
 }
 
@@ -6377,6 +6380,7 @@ static int __devinit snd_hdspm_create(struct snd_card *card,
 
        switch (hdspm->firmware_rev) {
        case HDSPM_MADI_REV:
+       case HDSPM_MADI_OLD_REV:
                hdspm->io_type = MADI;
                hdspm->card_name = "RME MADI";
                hdspm->midiPorts = 3;
index 8cc4733698a0f02d7de84de2cf4aec3b8c683584..ce33be0e4e9841f5864d95b4e091cdb4cf69df43 100644 (file)
@@ -278,7 +278,7 @@ static int pdacf_resume(struct pcmcia_device *link)
 /*
  * Module entry points
  */
-static struct pcmcia_device_id snd_pdacf_ids[] = {
+static const struct pcmcia_device_id snd_pdacf_ids[] = {
        /* this is too general PCMCIA_DEVICE_MANF_CARD(0x015d, 0x4c45), */
        PCMCIA_DEVICE_PROD_ID12("Core Sound","PDAudio-CF",0x396d19d2,0x71717b49),
        PCMCIA_DEVICE_NULL
index 80000d631f88366deeeaae70588dec5d3c960830..d9ef21d8fa7321fff082401301adcfc60fb102d1 100644 (file)
@@ -350,7 +350,7 @@ static void vxpocket_detach(struct pcmcia_device *link)
  * Module entry points
  */
 
-static struct pcmcia_device_id vxp_ids[] = {
+static const struct pcmcia_device_id vxp_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x01f1, 0x0100),
        PCMCIA_DEVICE_NULL
 };
index 7fbfa051f6e1fb013b8a739cfc2ebe074e0c586b..eda955b158343c527548ea77bff97edc1e530425 100644 (file)
@@ -848,9 +848,10 @@ int atmel_ssc_set_audio(int ssc_id)
        if (IS_ERR(ssc))
                pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n",
                        PTR_ERR(ssc));
-       else
+       else {
                ssc_pdev->dev.parent = &(ssc->pdev->dev);
-       ssc_free(ssc);
+               ssc_free(ssc);
+       }
 
        ret = platform_device_add(ssc_pdev);
        if (ret < 0)
index 28afbbf69ce00d30c76754eb6f8bb0c5adea519e..95572d290c2740a1aa146d053327028ca598d371 100644 (file)
@@ -146,7 +146,7 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
                        "at91sam9g20ek_wm8731 "
                        ": at91sam9g20ek_wm8731_init() called\n");
 
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_MCLK,
                MCLK_RATE, SND_SOC_CLOCK_IN);
        if (ret < 0) {
                printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret);
index ea4951cf5526d5871af7441430d583d81fd3749c..f79d1655e035d845fc0d8118366df2cd2f397989 100644 (file)
@@ -75,7 +75,7 @@ static struct snd_soc_dai_link bf5xx_ad1836_dai[] = {
                .cpu_dai_name = "bfin-tdm.0",
                .codec_dai_name = "ad1836-hifi",
                .platform_name = "bfin-tdm-pcm-audio",
-               .codec_name = "ad1836.0",
+               .codec_name = "spi0.4",
                .ops = &bf5xx_ad1836_ops,
        },
        {
@@ -84,7 +84,7 @@ static struct snd_soc_dai_link bf5xx_ad1836_dai[] = {
                .cpu_dai_name = "bfin-tdm.1",
                .codec_dai_name = "ad1836-hifi",
                .platform_name = "bfin-tdm-pcm-audio",
-               .codec_name = "ad1836.0",
+               .codec_name = "spi0.4",
                .ops = &bf5xx_ad1836_ops,
        },
 };
index ab63d52e36e147d9759f81afa0fdf9fbb21741b9..754c496412bdd0ec1440b4c2b9175251d6158670 100644 (file)
@@ -145,22 +145,22 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
        /* bit size */
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
-               word_len = 3;
+               word_len = AD1836_WORD_LEN_16;
                break;
        case SNDRV_PCM_FORMAT_S20_3LE:
-               word_len = 1;
+               word_len = AD1836_WORD_LEN_20;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
        case SNDRV_PCM_FORMAT_S32_LE:
-               word_len = 0;
+               word_len = AD1836_WORD_LEN_24;
                break;
        }
 
-       snd_soc_update_bits(codec, AD1836_DAC_CTRL1,
-               AD1836_DAC_WORD_LEN_MASK, word_len);
+       snd_soc_update_bits(codec, AD1836_DAC_CTRL1, AD1836_DAC_WORD_LEN_MASK,
+               word_len << AD1836_DAC_WORD_LEN_OFFSET);
 
-       snd_soc_update_bits(codec, AD1836_ADC_CTRL2,
-               AD1836_ADC_WORD_LEN_MASK, word_len);
+       snd_soc_update_bits(codec, AD1836_ADC_CTRL2, AD1836_ADC_WORD_LEN_MASK,
+               word_len << AD1836_ADC_WORD_OFFSET);
 
        return 0;
 }
index 845596717fdf522d2de2d83d37e123825a36cade..9d6a3f8f8aafa29ada5b25408d0470efbd738186 100644 (file)
@@ -25,6 +25,7 @@
 #define AD1836_DAC_SERFMT_PCK256       (0x4 << 5)
 #define AD1836_DAC_SERFMT_PCK128       (0x5 << 5)
 #define AD1836_DAC_WORD_LEN_MASK       0x18
+#define AD1836_DAC_WORD_LEN_OFFSET     3
 
 #define AD1836_DAC_CTRL2               1
 #define AD1836_DACL1_MUTE              0
@@ -51,6 +52,7 @@
 #define AD1836_ADCL2_MUTE              2
 #define AD1836_ADCR2_MUTE              3
 #define AD1836_ADC_WORD_LEN_MASK       0x30
+#define AD1836_ADC_WORD_OFFSET         5
 #define AD1836_ADC_SERFMT_MASK        (7 << 6)
 #define AD1836_ADC_SERFMT_PCK256       (0x4 << 6)
 #define AD1836_ADC_SERFMT_PCK128       (0x5 << 6)
@@ -60,4 +62,8 @@
 
 #define AD1836_NUM_REGS                16
 
+#define AD1836_WORD_LEN_24 0x0
+#define AD1836_WORD_LEN_20 0x1
+#define AD1836_WORD_LEN_16 0x2
+
 #endif
index b8066ef10bb0ae65dcf3b49582fe89329e17f09c..46dbfd067f79647b7fca338eb85addd177eda966 100644 (file)
@@ -153,8 +153,7 @@ static int cq93vc_resume(struct snd_soc_codec *codec)
 
 static int cq93vc_probe(struct snd_soc_codec *codec)
 {
-       struct davinci_vc *davinci_vc =
-                       mfd_get_data(to_platform_device(codec->dev));
+       struct davinci_vc *davinci_vc = codec->dev->platform_data;
 
        davinci_vc->cq93vc.codec = codec;
        codec->control_data = davinci_vc;
index f8c663dcff027d9d10083a41d0a6f5cd3b082e20..d68ea532cc7f59a52e46be1a89ccf4d0c35ad518 100644 (file)
@@ -262,14 +262,14 @@ static int v253_hangup(struct tty_struct *tty)
 }
 
 /* Line discipline .receive_buf() */
-static unsigned int v253_receive(struct tty_struct *tty,
-                                const unsigned char *cp, char *fp, int count)
+static void v253_receive(struct tty_struct *tty,
+                               const unsigned char *cp, char *fp, int count)
 {
        struct snd_soc_codec *codec = tty->disc_data;
        struct cx20442_priv *cx20442;
 
        if (!codec)
-               return count;
+               return;
 
        cx20442 = snd_soc_codec_get_drvdata(codec);
 
@@ -281,8 +281,6 @@ static unsigned int v253_receive(struct tty_struct *tty,
                codec->hw_write = (hw_write_t)tty->ops->write;
                codec->card->pop_time = 1;
        }
-
-       return count;
 }
 
 /* Line discipline .write_wakeup() */
index 575238d68e5eb0b8afbace12f51a14923f1d5f3b..bec788b12613add7ea8927762c23bb0572105b1a 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/i2c/twl.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -733,8 +732,7 @@ static int aif_event(struct snd_soc_dapm_widget *w,
 
 static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 {
-       struct twl4030_codec_audio_data *pdata =
-                       mfd_get_data(to_platform_device(codec->dev));
+       struct twl4030_codec_audio_data *pdata = codec->dev->platform_data;
        unsigned char hs_gain, hs_pop;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        /* Base values for ramp delay calculation: 2^19 - 2^26 */
@@ -2299,7 +2297,7 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
 
 static int __devinit twl4030_codec_probe(struct platform_device *pdev)
 {
-       struct twl4030_codec_audio_data *pdata = mfd_get_data(pdev);
+       struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data;
 
        if (!pdata) {
                dev_err(&pdev->dev, "platform_data is missing\n");
index c8a874d0d4cae5d9a0a66974ff3ac5b4887d492a..5836201834d97dcc769347ab98827841fce013ca 100644 (file)
@@ -441,8 +441,7 @@ EXPORT_SYMBOL_GPL(wl1273_get_format);
 
 static int wl1273_probe(struct snd_soc_codec *codec)
 {
-       struct wl1273_core **core =
-                       mfd_get_data(to_platform_device(codec->dev));
+       struct wl1273_core **core = codec->dev->platform_data;
        struct wl1273_priv *wl1273;
        int r;
 
index 14d0716bf0093b2a5d5b34ff5c8088302255b5dc..bcc208967917f149956985e7c8f5c290a1506aad 100644 (file)
@@ -22,7 +22,7 @@ SND_SOC_DAPM_ADC("ADC", "wm1250-ev1 Capture", SND_SOC_NOPM, 0, 0),
 SND_SOC_DAPM_DAC("DAC", "wm1250-ev1 Playback", SND_SOC_NOPM, 0, 0),
 
 SND_SOC_DAPM_INPUT("WM1250 Input"),
-SND_SOC_DAPM_INPUT("WM1250 Output"),
+SND_SOC_DAPM_OUTPUT("WM1250 Output"),
 };
 
 static const struct snd_soc_dapm_route wm1250_ev1_dapm_routes[] = {
index 736b785e375606435ab0e181f8d48634966242ff..fbee556cbf35adaba1bbca26e6659cb199590c07 100644 (file)
@@ -1378,7 +1378,7 @@ static void wm8400_probe_deferred(struct work_struct *work)
 
 static int wm8400_codec_probe(struct snd_soc_codec *codec)
 {
-       struct wm8400 *wm8400 = mfd_get_data(to_platform_device(codec->dev));
+       struct wm8400 *wm8400 = dev_get_platdata(codec->dev);
        struct wm8400_priv *priv;
        int ret;
        u16 reg;
index 6dec7cee2cb4bd5fcd0cda18c7b325284a2ae039..2dc964b55e4fa15ce23fec72fbc7c7925f8fbc1e 100644 (file)
@@ -198,7 +198,7 @@ static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
 {
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec);
 
-       return wm8731->sysclk_type == WM8731_SYSCLK_MCLK;
+       return wm8731->sysclk_type == WM8731_SYSCLK_XTAL;
 }
 
 static const struct snd_soc_dapm_route wm8731_intercon[] = {
index 6785688f88069ad9b56fed4a28933d34c8751ebc..9a5e67c5a6bdf9f2cc7fc5a23b49a8c76a0f462e 100644 (file)
@@ -680,20 +680,25 @@ static struct snd_soc_dai_ops wm8804_dai_ops = {
 #define WM8804_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
                        SNDRV_PCM_FMTBIT_S24_LE)
 
+#define WM8804_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+                     SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \
+                     SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
+                     SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
+
 static struct snd_soc_dai_driver wm8804_dai = {
        .name = "wm8804-spdif",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
                .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_192000,
+               .rates = WM8804_RATES,
                .formats = WM8804_FORMATS,
        },
        .capture = {
                .stream_name = "Capture",
                .channels_min = 2,
                .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_192000,
+               .rates = WM8804_RATES,
                .formats = WM8804_FORMATS,
        },
        .ops = &wm8804_dai_ops,
index ccc9bd8327948ecbc33290d17ee21d9717ba203d..e2ab4fac28199130a69ce3421ffb722de75b3c97 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/gcd.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
-#include <linux/delay.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
@@ -1840,7 +1839,7 @@ static int wm8915_set_sysclk(struct snd_soc_dai *dai,
        int old;
 
        /* Disable SYSCLK while we reconfigure */
-       old = snd_soc_read(codec, WM8915_AIF_CLOCKING_1);
+       old = snd_soc_read(codec, WM8915_AIF_CLOCKING_1) & WM8915_SYSCLK_ENA;
        snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
                            WM8915_SYSCLK_ENA, 0);
 
@@ -2039,6 +2038,7 @@ static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
                break;
        case WM8915_FLL_MCLK2:
                reg = 1;
+               break;
        case WM8915_FLL_DACLRCLK1:
                reg = 2;
                break;
index f90ae427242b4a26c87b9aff56fe23cc09303645..5e05eed96c381c9730b31d65ea1b786b459ec41e 100644 (file)
@@ -1999,12 +1999,12 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
                return 0;
 
        /* If the left PGA is enabled hit that VU bit... */
-       if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_HPOUTL_PGA_ENA)
+       if (snd_soc_read(codec, WM8962_PWR_MGMT_2) & WM8962_HPOUTL_PGA_ENA)
                return snd_soc_write(codec, WM8962_HPOUTL_VOLUME,
                                     reg_cache[WM8962_HPOUTL_VOLUME]);
 
        /* ...otherwise the right.  The VU is stereo. */
-       if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_HPOUTR_PGA_ENA)
+       if (snd_soc_read(codec, WM8962_PWR_MGMT_2) & WM8962_HPOUTR_PGA_ENA)
                return snd_soc_write(codec, WM8962_HPOUTR_VOLUME,
                                     reg_cache[WM8962_HPOUTR_VOLUME]);
 
index 3c2ee1bb73cdb8c85d21372b41d3598cf7b4bcad..6af23d06870f8a03d1a8a1910577d6a13fef67a3 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
index e55b298c14a06e249f54453829295c880c39998a..9e370d14ad88f2bce72ccd0ce1204eb01bd854fa 100644 (file)
@@ -215,23 +215,23 @@ static const struct snd_kcontrol_new analogue_snd_controls[] = {
 SOC_SINGLE_TLV("IN1L Volume", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
               inpga_tlv),
 SOC_SINGLE("IN1L Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
-SOC_SINGLE("IN1L ZC Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 0),
+SOC_SINGLE("IN1L ZC Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 6, 1, 0),
 
 SOC_SINGLE_TLV("IN1R Volume", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
               inpga_tlv),
 SOC_SINGLE("IN1R Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
-SOC_SINGLE("IN1R ZC Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 0),
+SOC_SINGLE("IN1R ZC Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 6, 1, 0),
 
 
 SOC_SINGLE_TLV("IN2L Volume", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
               inpga_tlv),
 SOC_SINGLE("IN2L Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
-SOC_SINGLE("IN2L ZC Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 0),
+SOC_SINGLE("IN2L ZC Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 6, 1, 0),
 
 SOC_SINGLE_TLV("IN2R Volume", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
               inpga_tlv),
 SOC_SINGLE("IN2R Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
-SOC_SINGLE("IN2R ZC Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 0),
+SOC_SINGLE("IN2R ZC Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 6, 1, 0),
 
 SOC_SINGLE_TLV("MIXINL IN2L Volume", WM8993_INPUT_MIXER3, 7, 1, 0,
               inmix_sw_tlv),
index 13e05a302a92edf15aa1f464298f7ae81a2e7579..9259f1f348999cd5963817402023e7b8d805768e 100644 (file)
@@ -205,7 +205,7 @@ static struct snd_soc_dai_driver davinci_vcif_dai = {
 
 static int davinci_vcif_probe(struct platform_device *pdev)
 {
-       struct davinci_vc *davinci_vc = mfd_get_data(pdev);
+       struct davinci_vc *davinci_vc = pdev->dev.platform_data;
        struct davinci_vcif_dev *davinci_vcif_dev;
        int ret;
 
index 15dac0f20cd8aa9a37221acc3367fa269142fc5a..6680c0b4d2038cf569940df97d7f363b6b317a74 100644 (file)
@@ -310,7 +310,7 @@ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
         * should allocate a DMA buffer only for the streams that are valid.
         */
 
-       if (dai->driver->playback.channels_min) {
+       if (pcm->streams[0].substream) {
                ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
                        fsl_dma_hardware.buffer_bytes_max,
                        &pcm->streams[0].substream->dma_buffer);
@@ -320,13 +320,13 @@ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
                }
        }
 
-       if (dai->driver->capture.channels_min) {
+       if (pcm->streams[1].substream) {
                ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
                        fsl_dma_hardware.buffer_bytes_max,
                        &pcm->streams[1].substream->dma_buffer);
                if (ret) {
-                       snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
                        dev_err(card->dev, "can't alloc capture dma buffer\n");
+                       snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
                        return ret;
                }
        }
@@ -449,7 +449,8 @@ static int fsl_dma_open(struct snd_pcm_substream *substream)
        dma_private->ld_buf_phys = ld_buf_phys;
        dma_private->dma_buf_phys = substream->dma_buffer.addr;
 
-       ret = request_irq(dma_private->irq, fsl_dma_isr, 0, "DMA", dma_private);
+       ret = request_irq(dma_private->irq, fsl_dma_isr, 0, "fsldma-audio",
+                         dma_private);
        if (ret) {
                dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
                        dma_private->irq, ret);
index d8f130d39dd904c341d539fbe5457fe976b285b1..bb699bb55a502c041b9d47fff2f5c396c8c431c8 100644 (file)
@@ -11,9 +11,6 @@ menuconfig SND_IMX_SOC
 
 if SND_IMX_SOC
 
-config SND_MXC_SOC_SSI
-       tristate
-
 config SND_MXC_SOC_FIQ
        tristate
 
@@ -24,7 +21,6 @@ config SND_MXC_SOC_WM1133_EV1
        tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted"
        depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
        select SND_SOC_WM8350
-       select SND_MXC_SOC_SSI
        select SND_MXC_SOC_FIQ
        help
          Enable support for audio on the i.MX31ADS with the WM1133-EV1
@@ -34,7 +30,6 @@ config SND_SOC_MX27VIS_AIC32X4
        tristate "SoC audio support for Visstrim M10 boards"
        depends on MACH_IMX27_VISSTRIM_M10
        select SND_SOC_TVL320AIC32X4
-       select SND_MXC_SOC_SSI
        select SND_MXC_SOC_MX2
        help
          Say Y if you want to add support for SoC audio on Visstrim SM10
@@ -44,7 +39,6 @@ config SND_SOC_PHYCORE_AC97
        tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
        depends on MACH_PCM043 || MACH_PCA100
        select SND_SOC_WM9712
-       select SND_MXC_SOC_SSI
        select SND_MXC_SOC_FIQ
        help
          Say Y if you want to add support for SoC audio on Phytec phyCORE
@@ -57,7 +51,6 @@ config SND_SOC_EUKREA_TLV320
                || MACH_EUKREA_MBIMXSD35_BASEBOARD \
                || MACH_EUKREA_MBIMXSD51_BASEBOARD
        select SND_SOC_TLV320AIC23
-       select SND_MXC_SOC_SSI
        select SND_MXC_SOC_FIQ
        help
          Enable I2S based access to the TLV320AIC23B codec attached
index aab7765f401a0904397c9c22a801fc10670b73f4..4173b3d87f979d2757f1498bd503f15b07195542 100644 (file)
@@ -337,3 +337,5 @@ static void __exit snd_imx_pcm_exit(void)
        platform_driver_unregister(&imx_pcm_driver);
 }
 module_exit(snd_imx_pcm_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-pcm-audio");
index 5b13feca753732a6664969308e0794b161936aa8..61fceb09cdb5bbbf426270696bbf48b058f4d658 100644 (file)
@@ -774,4 +774,4 @@ module_exit(imx_ssi_exit);
 MODULE_AUTHOR("Sascha Hauer, <s.hauer@pengutronix.de>");
 MODULE_DESCRIPTION("i.MX I2S/ac97 SoC Interface");
 MODULE_LICENSE("GPL");
-
+MODULE_ALIAS("platform:imx-ssi");
index b5922984eac667008184a1475f1d5dc983f44e1a..99054cf1f68fe69febec8dd06528b121c8e6d9bd 100644 (file)
@@ -65,14 +65,6 @@ config SND_OMAP_SOC_OVERO
          Say Y if you want to add support for SoC audio on the
          Gumstix Overo or CompuLab CM-T35
 
-config SND_OMAP_SOC_OMAP2EVM
-       tristate "SoC Audio support for OMAP2EVM board"
-       depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP2EVM
-       select SND_OMAP_SOC_MCBSP
-       select SND_SOC_TWL4030
-       help
-         Say Y if you want to add support for SoC audio on the omap2evm board.
-
 config SND_OMAP_SOC_OMAP3EVM
        tristate "SoC Audio support for OMAP3EVM board"
        depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3EVM
index ba9fc650db28a1e9b06641ad8ff2adb04647f87d..6c2c87eed5bb7bd39d79c41bc4596b7ec4a48417 100644 (file)
@@ -13,7 +13,6 @@ snd-soc-rx51-objs := rx51.o
 snd-soc-ams-delta-objs := ams-delta.o
 snd-soc-osk5912-objs := osk5912.o
 snd-soc-overo-objs := overo.o
-snd-soc-omap2evm-objs := omap2evm.o
 snd-soc-omap3evm-objs := omap3evm.o
 snd-soc-am3517evm-objs := am3517evm.o
 snd-soc-sdp3430-objs := sdp3430.o
diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c
deleted file mode 100644 (file)
index 29b60d6..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * omap2evm.c  --  SoC audio machine driver for omap2evm board
- *
- * Author: Arun KS <arunks@mistralsolutions.com>
- *
- * Based on sound/soc/omap/overo.c by Steve Sakoman
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <plat/mcbsp.h>
-
-#include "omap-mcbsp.h"
-#include "omap-pcm.h"
-
-static int omap2evm_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int ret;
-
-       /* Set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai,
-                                 SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0) {
-               printk(KERN_ERR "can't set codec DAI configuration\n");
-               return ret;
-       }
-
-       /* Set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai,
-                                 SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0) {
-               printk(KERN_ERR "can't set cpu DAI configuration\n");
-               return ret;
-       }
-
-       /* Set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
-                                           SND_SOC_CLOCK_IN);
-       if (ret < 0) {
-               printk(KERN_ERR "can't set codec system clock\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-static struct snd_soc_ops omap2evm_ops = {
-       .hw_params = omap2evm_hw_params,
-};
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link omap2evm_dai = {
-       .name = "TWL4030",
-       .stream_name = "TWL4030",
-       .cpu_dai_name = "omap-mcbsp-dai.1",
-       .codec_dai_name = "twl4030-hifi",
-       .platform_name = "omap-pcm-audio",
-       .codec_name = "twl4030-codec",
-       .ops = &omap2evm_ops,
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_omap2evm = {
-       .name = "omap2evm",
-       .dai_link = &omap2evm_dai,
-       .num_links = 1,
-};
-
-static struct platform_device *omap2evm_snd_device;
-
-static int __init omap2evm_soc_init(void)
-{
-       int ret;
-
-       if (!machine_is_omap2evm())
-               return -ENODEV;
-       printk(KERN_INFO "omap2evm SoC init\n");
-
-       omap2evm_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!omap2evm_snd_device) {
-               printk(KERN_ERR "Platform device allocation failed\n");
-               return -ENOMEM;
-       }
-
-       platform_set_drvdata(omap2evm_snd_device, &snd_soc_omap2evm);
-
-       ret = platform_device_add(omap2evm_snd_device);
-       if (ret)
-               goto err1;
-
-       return 0;
-
-err1:
-       printk(KERN_ERR "Unable to add platform device\n");
-       platform_device_put(omap2evm_snd_device);
-
-       return ret;
-}
-module_init(omap2evm_soc_init);
-
-static void __exit omap2evm_soc_exit(void)
-{
-       platform_device_unregister(omap2evm_snd_device);
-}
-module_exit(omap2evm_soc_exit);
-
-MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
-MODULE_DESCRIPTION("ALSA SoC omap2evm");
-MODULE_LICENSE("GPL");
index 2ce0b2d891d5081df50ed6c677ef835eab845b94..fab20a54e86340f1b5d2536cc9e3002613ef1c7d 100644 (file)
@@ -95,14 +95,14 @@ static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (dai->driver->playback.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
                ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->driver->capture.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
                ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
index 2afabaf59491ed71ae331f827d40d04545e6b1b3..1a591f1ebfbd9431f89559be28421d8defde585c 100644 (file)
@@ -151,13 +151,13 @@ static struct snd_soc_ops raumfeld_cs4270_ops = {
        .hw_params = raumfeld_cs4270_hw_params,
 };
 
-static int raumfeld_line_suspend(struct snd_soc_card *card)
+static int raumfeld_analog_suspend(struct snd_soc_card *card)
 {
        raumfeld_enable_audio(false);
        return 0;
 }
 
-static int raumfeld_line_resume(struct snd_soc_card *card)
+static int raumfeld_analog_resume(struct snd_soc_card *card)
 {
        raumfeld_enable_audio(true);
        return 0;
@@ -225,32 +225,53 @@ static struct snd_soc_ops raumfeld_ak4104_ops = {
        .hw_params = raumfeld_ak4104_hw_params,
 };
 
-static struct snd_soc_dai_link raumfeld_dai[] = {
+#define DAI_LINK_CS4270                \
+{                                                      \
+       .name           = "CS4270",                     \
+       .stream_name    = "CS4270",                     \
+       .cpu_dai_name   = "pxa-ssp-dai.0",              \
+       .platform_name  = "pxa-pcm-audio",              \
+       .codec_dai_name = "cs4270-hifi",                \
+       .codec_name     = "cs4270-codec.0-0048",        \
+       .ops            = &raumfeld_cs4270_ops,         \
+}
+
+#define DAI_LINK_AK4104                \
+{                                                      \
+       .name           = "ak4104",                     \
+       .stream_name    = "Playback",                   \
+       .cpu_dai_name   = "pxa-ssp-dai.1",              \
+       .codec_dai_name = "ak4104-hifi",                \
+       .platform_name  = "pxa-pcm-audio",              \
+       .ops            = &raumfeld_ak4104_ops,         \
+       .codec_name     = "spi0.0",                     \
+}
+
+static struct snd_soc_dai_link snd_soc_raumfeld_connector_dai[] =
 {
-       .name           = "ak4104",
-       .stream_name    = "Playback",
-       .cpu_dai_name   = "pxa-ssp-dai.1",
-       .codec_dai_name = "ak4104-hifi",
-       .platform_name  = "pxa-pcm-audio",
-       .ops            = &raumfeld_ak4104_ops,
-       .codec_name     = "ak4104-codec.0",
-},
+       DAI_LINK_CS4270,
+       DAI_LINK_AK4104,
+};
+
+static struct snd_soc_dai_link snd_soc_raumfeld_speaker_dai[] =
 {
-       .name           = "CS4270",
-       .stream_name    = "CS4270",
-       .cpu_dai_name   = "pxa-ssp-dai.0",
-       .platform_name  = "pxa-pcm-audio",
-       .codec_dai_name = "cs4270-hifi",
-       .codec_name     = "cs4270-codec.0-0048",
-       .ops            = &raumfeld_cs4270_ops,
-},};
-
-static struct snd_soc_card snd_soc_raumfeld = {
-       .name           = "Raumfeld",
-       .dai_link       = raumfeld_dai,
-       .suspend_post   = raumfeld_line_suspend,
-       .resume_pre     = raumfeld_line_resume,
-       .num_links      = ARRAY_SIZE(raumfeld_dai),
+       DAI_LINK_CS4270,
+};
+
+static struct snd_soc_card snd_soc_raumfeld_connector = {
+       .name           = "Raumfeld Connector",
+       .dai_link       = snd_soc_raumfeld_connector_dai,
+       .num_links      = ARRAY_SIZE(snd_soc_raumfeld_connector_dai),
+       .suspend_post   = raumfeld_analog_suspend,
+       .resume_pre     = raumfeld_analog_resume,
+};
+
+static struct snd_soc_card snd_soc_raumfeld_speaker = {
+       .name           = "Raumfeld Speaker",
+       .dai_link       = snd_soc_raumfeld_speaker_dai,
+       .num_links      = ARRAY_SIZE(snd_soc_raumfeld_speaker_dai),
+       .suspend_post   = raumfeld_analog_suspend,
+       .resume_pre     = raumfeld_analog_resume,
 };
 
 static struct platform_device *raumfeld_audio_device;
@@ -271,22 +292,25 @@ static int __init raumfeld_audio_init(void)
 
        set_max9485_clk(MAX9485_MCLK_FREQ_122880);
 
-       /* Register LINE and SPDIF */
+       /* Register analog device */
        raumfeld_audio_device = platform_device_alloc("soc-audio", 0);
        if (!raumfeld_audio_device)
                return -ENOMEM;
 
-       platform_set_drvdata(raumfeld_audio_device,
-                            &snd_soc_raumfeld);
-       ret = platform_device_add(raumfeld_audio_device);
-
-       /* no S/PDIF on Speakers */
        if (machine_is_raumfeld_speaker())
+               platform_set_drvdata(raumfeld_audio_device,
+                                    &snd_soc_raumfeld_speaker);
+
+       if (machine_is_raumfeld_connector())
+               platform_set_drvdata(raumfeld_audio_device,
+                                    &snd_soc_raumfeld_connector);
+
+       ret = platform_device_add(raumfeld_audio_device);
+       if (ret < 0)
                return ret;
 
        raumfeld_enable_audio(true);
-
-       return ret;
+       return 0;
 }
 
 static void __exit raumfeld_audio_exit(void)
index 459566bfcd3527cd8f142001645b3f8bfff8c1c3..d155cbb58e1c8f2562ec3a963c11528b446cc0f6 100644 (file)
@@ -1,6 +1,6 @@
 config SND_SOC_SAMSUNG
        tristate "ASoC support for Samsung"
-       depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_S5P6442 || ARCH_EXYNOS4
+       depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_EXYNOS4
        select S3C64XX_DMA if ARCH_S3C64XX
        select S3C2410_DMA if ARCH_S3C2410
        help
@@ -55,7 +55,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750
 
 config SND_SOC_SAMSUNG_SMDK_WM8580
        tristate "SoC I2S Audio support for WM8580 on SMDK"
-       depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDK6440 || MACH_SMDK6450 || MACH_SMDK6442 || MACH_SMDKV210 || MACH_SMDKC110)
+       depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDK6440 || MACH_SMDK6450 || MACH_SMDKV210 || MACH_SMDKC110)
        select SND_SOC_WM8580
        select SND_SAMSUNG_I2S
        help
index ffa09b3b2caaeedf98568331ec0825888829e5eb..992a732b5211bccb5385256eaf37ff887259ee0a 100644 (file)
@@ -191,7 +191,7 @@ static inline bool tx_active(struct i2s_dai *i2s)
        if (!i2s)
                return false;
 
-       active = readl(i2s->addr + I2SMOD);
+       active = readl(i2s->addr + I2SCON);
 
        if (is_secondary(i2s))
                active &= CON_TXSDMA_ACTIVE;
@@ -223,7 +223,7 @@ static inline bool rx_active(struct i2s_dai *i2s)
        if (!i2s)
                return false;
 
-       active = readl(i2s->addr + I2SMOD) & CON_RXDMA_ACTIVE;
+       active = readl(i2s->addr + I2SCON) & CON_RXDMA_ACTIVE;
 
        return active ? true : false;
 }
index 8aacf23d6f3a19c1c67e49723da113a9fbb2a283..3d26f6607aa47aa97cc6798ac0d10cb14276a0ae 100644 (file)
@@ -249,7 +249,7 @@ static int __init smdk_audio_init(void)
        int ret;
        char *str;
 
-       if (machine_is_smdkc100() || machine_is_smdk6442()
+       if (machine_is_smdkc100()
                        || machine_is_smdkv210() || machine_is_smdkc110()) {
                smdk.num_links = 3;
                /* Secondary is at offset SAMSUNG_I2S_SECOFF from Primary */
index 06b7b81a16016f714b9bb2597dc705c0bab20ffb..039b9532b270cb8c1bb300efd0d1a7f385d95aa4 100644 (file)
@@ -409,9 +409,6 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
        codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
 
        switch (control) {
-       case SND_SOC_CUSTOM:
-               break;
-
        case SND_SOC_I2C:
 #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
                codec->hw_write = (hw_write_t)i2c_master_send;
@@ -466,6 +463,9 @@ static bool snd_soc_set_cache_val(void *base, unsigned int idx,
 static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
                unsigned int word_size)
 {
+       if (!base)
+               return -1;
+
        switch (word_size) {
        case 1: {
                const u8 *cache = base;
index bb7cd58129459cbd9f0fb729ad61d4ed7070ee18..d75043ed7fc0551f66881675df110dede0d5ccf0 100644 (file)
@@ -1306,10 +1306,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
        /* no, then find CPU DAI from registered DAIs*/
        list_for_each_entry(cpu_dai, &dai_list, list) {
                if (!strcmp(cpu_dai->name, dai_link->cpu_dai_name)) {
-
-                       if (!try_module_get(cpu_dai->dev->driver->owner))
-                               return -ENODEV;
-
                        rtd->cpu_dai = cpu_dai;
                        goto find_codec;
                }
@@ -1622,11 +1618,15 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
 
        /* probe the cpu_dai */
        if (!cpu_dai->probed) {
+               if (!try_module_get(cpu_dai->dev->driver->owner))
+                       return -ENODEV;
+
                if (cpu_dai->driver->probe) {
                        ret = cpu_dai->driver->probe(cpu_dai);
                        if (ret < 0) {
                                printk(KERN_ERR "asoc: failed to probe CPU DAI %s\n",
                                                cpu_dai->name);
+                               module_put(cpu_dai->dev->driver->owner);
                                return ret;
                        }
                }
index 456617e63789893c7d90f547cbc00f3c7ba168d5..32ab7fc4579ac18ee7155aa4891e709c76173bf1 100644 (file)
@@ -325,6 +325,7 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
 }
 
 static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
+       struct snd_soc_dapm_widget *kcontrolw,
        const struct snd_kcontrol_new *kcontrol_new,
        struct snd_kcontrol **kcontrol)
 {
@@ -334,6 +335,8 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
        *kcontrol = NULL;
 
        list_for_each_entry(w, &dapm->card->widgets, list) {
+               if (w == kcontrolw || w->dapm != kcontrolw->dapm)
+                       continue;
                for (i = 0; i < w->num_kcontrols; i++) {
                        if (&w->kcontrol_news[i] == kcontrol_new) {
                                if (w->kcontrols)
@@ -347,9 +350,9 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
 }
 
 /* create new dapm mixer control */
-static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
-       struct snd_soc_dapm_widget *w)
+static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
 {
+       struct snd_soc_dapm_context *dapm = w->dapm;
        int i, ret = 0;
        size_t name_len, prefix_len;
        struct snd_soc_dapm_path *path;
@@ -447,9 +450,9 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
 }
 
 /* create new dapm mux control */
-static int dapm_new_mux(struct snd_soc_dapm_context *dapm,
-       struct snd_soc_dapm_widget *w)
+static int dapm_new_mux(struct snd_soc_dapm_widget *w)
 {
+       struct snd_soc_dapm_context *dapm = w->dapm;
        struct snd_soc_dapm_path *path = NULL;
        struct snd_kcontrol *kcontrol;
        struct snd_card *card = dapm->card->snd_card;
@@ -468,7 +471,7 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm,
                return -EINVAL;
        }
 
-       shared = dapm_is_shared_kcontrol(dapm, &w->kcontrol_news[0],
+       shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[0],
                                         &kcontrol);
        if (kcontrol) {
                wlist = kcontrol->private_data;
@@ -532,8 +535,7 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm,
 }
 
 /* create new dapm volume control */
-static int dapm_new_pga(struct snd_soc_dapm_context *dapm,
-       struct snd_soc_dapm_widget *w)
+static int dapm_new_pga(struct snd_soc_dapm_widget *w)
 {
        if (w->num_kcontrols)
                dev_err(w->dapm->dev,
@@ -1110,7 +1112,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
        trace_snd_soc_dapm_start(card);
 
        list_for_each_entry(d, &card->dapm_list, list)
-               if (d->n_widgets)
+               if (d->n_widgets || d->codec == NULL)
                        d->dev_power = 0;
 
        /* Check which widgets we need to power and store them in
@@ -1823,13 +1825,13 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
                case snd_soc_dapm_mixer:
                case snd_soc_dapm_mixer_named_ctl:
                        w->power_check = dapm_generic_check_power;
-                       dapm_new_mixer(dapm, w);
+                       dapm_new_mixer(w);
                        break;
                case snd_soc_dapm_mux:
                case snd_soc_dapm_virt_mux:
                case snd_soc_dapm_value_mux:
                        w->power_check = dapm_generic_check_power;
-                       dapm_new_mux(dapm, w);
+                       dapm_new_mux(w);
                        break;
                case snd_soc_dapm_adc:
                case snd_soc_dapm_aif_out:
@@ -1842,7 +1844,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
                case snd_soc_dapm_pga:
                case snd_soc_dapm_out_drv:
                        w->power_check = dapm_generic_check_power;
-                       dapm_new_pga(dapm, w);
+                       dapm_new_pga(w);
                        break;
                case snd_soc_dapm_input:
                case snd_soc_dapm_output:
index d47beffedb0ff5b4be36bab35a1014e5bd5aa22f..1e3ae3327dd3a65431b4a517ab5b340dac2ee6f7 100644 (file)
@@ -227,6 +227,7 @@ static int usb6fire_fw_ezusb_upload(
        ret = usb6fire_fw_ihex_init(fw, rec);
        if (ret < 0) {
                kfree(rec);
+               release_firmware(fw);
                snd_printk(KERN_ERR PREFIX "error validating ezusb "
                                "firmware %s.\n", fwname);
                return ret;
@@ -269,7 +270,6 @@ static int usb6fire_fw_ezusb_upload(
        data = 0x00; /* resume ezusb cpu */
        ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
        if (ret < 0) {
-               release_firmware(fw);
                snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
                                "firmware %s: end message.\n", fwname);
                return ret;
index b137b25865cc986cc8f6bc8d21ca482e34b987cd..d144cdb2f15909acefec2f0c45ea0cd1ff523030 100644 (file)
@@ -395,12 +395,12 @@ static int usb6fire_pcm_open(struct snd_pcm_substream *alsa_sub)
        alsa_rt->hw = pcm_hw;
 
        if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               if (rt->rate >= 0)
+               if (rt->rate < ARRAY_SIZE(rates))
                        alsa_rt->hw.rates = rates_alsaid[rt->rate];
                alsa_rt->hw.channels_max = OUT_N_CHANNELS;
                sub = &rt->playback;
        } else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE) {
-               if (rt->rate >= 0)
+               if (rt->rate < ARRAY_SIZE(rates))
                        alsa_rt->hw.rates = rates_alsaid[rt->rate];
                alsa_rt->hw.channels_max = IN_N_CHANNELS;
                sub = &rt->capture;
index a90662af2d6bbd7b2df46d17cb1da01ee849d29c..220c6167dd86d5ed2164db0c73b97afac1ba6ec5 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/usb/audio.h>
 #include <linux/usb/audio-v2.h>
 
+#include <sound/control.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/pcm.h>
@@ -492,14 +493,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
                }
        }
 
-       chip->txfr_quirk = 0;
-       err = 1; /* continue */
-       if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) {
-               /* need some special handlings */
-               if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0)
-                       goto __error;
-       }
-
        /*
         * For devices with more than one control interface, we assume the
         * first contains the audio controls. We might need a more specific
@@ -508,6 +501,14 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
        if (!chip->ctrl_intf)
                chip->ctrl_intf = alts;
 
+       chip->txfr_quirk = 0;
+       err = 1; /* continue */
+       if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) {
+               /* need some special handlings */
+               if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0)
+                       goto __error;
+       }
+
        if (err > 0) {
                /* create normal USB audio interfaces */
                if (snd_usb_create_streams(chip, ifnum) < 0 ||
index eab06edcc9b73f8a56f0ec2bac616f3a8d535073..c22fa76e363ae5699e9885cc548fdc28d25607b3 100644 (file)
@@ -86,16 +86,6 @@ struct mixer_build {
        const struct usbmix_selector_map *selector_map;
 };
 
-enum {
-       USB_MIXER_BOOLEAN,
-       USB_MIXER_INV_BOOLEAN,
-       USB_MIXER_S8,
-       USB_MIXER_U8,
-       USB_MIXER_S16,
-       USB_MIXER_U16,
-};
-
-
 /*E-mu 0202/0404/0204 eXtension Unit(XU) control*/
 enum {
        USB_XU_CLOCK_RATE               = 0xe301,
@@ -535,20 +525,21 @@ static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_ou
  * if failed, give up and free the control instance.
  */
 
-static int add_control_to_empty(struct mixer_build *state, struct snd_kcontrol *kctl)
+int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
+                             struct snd_kcontrol *kctl)
 {
        struct usb_mixer_elem_info *cval = kctl->private_data;
        int err;
 
-       while (snd_ctl_find_id(state->chip->card, &kctl->id))
+       while (snd_ctl_find_id(mixer->chip->card, &kctl->id))
                kctl->id.index++;
-       if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) {
+       if ((err = snd_ctl_add(mixer->chip->card, kctl)) < 0) {
                snd_printd(KERN_ERR "cannot add control (err = %d)\n", err);
                return err;
        }
        cval->elem_id = &kctl->id;
-       cval->next_id_elem = state->mixer->id_elems[cval->id];
-       state->mixer->id_elems[cval->id] = cval;
+       cval->next_id_elem = mixer->id_elems[cval->id];
+       mixer->id_elems[cval->id] = cval;
        return 0;
 }
 
@@ -984,6 +975,9 @@ static struct snd_kcontrol_new usb_feature_unit_ctl_ro = {
        .put = NULL,
 };
 
+/* This symbol is exported in order to allow the mixer quirks to
+ * hook up to the standard feature unit control mechanism */
+struct snd_kcontrol_new *snd_usb_feature_unit_ctl = &usb_feature_unit_ctl;
 
 /*
  * build a feature control
@@ -1176,7 +1170,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
 
        snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
                    cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res);
-       add_control_to_empty(state, kctl);
+       snd_usb_mixer_add_control(state->mixer, kctl);
 }
 
 
@@ -1340,7 +1334,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
 
        snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n",
                    cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
-       add_control_to_empty(state, kctl);
+       snd_usb_mixer_add_control(state->mixer, kctl);
 }
 
 
@@ -1641,7 +1635,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw
 
                snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n",
                            cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
-               if ((err = add_control_to_empty(state, kctl)) < 0)
+               if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0)
                        return err;
        }
        return 0;
@@ -1858,7 +1852,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
 
        snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n",
                    cval->id, kctl->id.name, desc->bNrInPins);
-       if ((err = add_control_to_empty(state, kctl)) < 0)
+       if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0)
                return err;
 
        return 0;
index b4a2c8165e4b2b6e7870fda7b0f3a490e17e97e8..ae1a14dcfe82cf51753da7265bcdaf6ce95969f4 100644 (file)
@@ -24,7 +24,16 @@ struct usb_mixer_interface {
        u8 xonar_u1_status;
 };
 
-#define MAX_CHANNELS   10      /* max logical channels */
+#define MAX_CHANNELS   16      /* max logical channels */
+
+enum {
+       USB_MIXER_BOOLEAN,
+       USB_MIXER_INV_BOOLEAN,
+       USB_MIXER_S8,
+       USB_MIXER_U8,
+       USB_MIXER_S16,
+       USB_MIXER_U16,
+};
 
 struct usb_mixer_elem_info {
        struct usb_mixer_interface *mixer;
@@ -55,4 +64,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
 void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer);
 int snd_usb_mixer_activate(struct usb_mixer_interface *mixer);
 
+int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
+                             struct snd_kcontrol *kctl);
+
 #endif /* __USBMIXER_H */
index 9146cffa6ede3096b24eae718935226880530a25..3d0f4873112b17d9f5d7bfec90a87fbab2053ae6 100644 (file)
@@ -40,6 +40,8 @@
 #include "mixer_quirks.h"
 #include "helper.h"
 
+extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
+
 /*
  * Sound Blaster remote control configuration
  *
@@ -492,6 +494,69 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
        return err;
 }
 
+/* M-Audio FastTrack Ultra quirks */
+
+/* private_free callback */
+static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
+{
+       kfree(kctl->private_data);
+       kctl->private_data = NULL;
+}
+
+static int snd_maudio_ftu_create_ctl(struct usb_mixer_interface *mixer,
+                                    int in, int out, const char *name)
+{
+       struct usb_mixer_elem_info *cval;
+       struct snd_kcontrol *kctl;
+
+       cval = kzalloc(sizeof(*cval), GFP_KERNEL);
+       if (!cval)
+               return -ENOMEM;
+
+       cval->id = 5;
+       cval->mixer = mixer;
+       cval->val_type = USB_MIXER_S16;
+       cval->channels = 1;
+       cval->control = out + 1;
+       cval->cmask = 1 << in;
+
+       kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval);
+       if (!kctl) {
+               kfree(cval);
+               return -ENOMEM;
+       }
+
+       snprintf(kctl->id.name, sizeof(kctl->id.name), name);
+       kctl->private_free = usb_mixer_elem_free;
+       return snd_usb_mixer_add_control(mixer, kctl);
+}
+
+static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer)
+{
+       char name[64];
+       int in, out, err;
+
+       for (out = 0; out < 8; out++) {
+               for (in = 0; in < 8; in++) {
+                       snprintf(name, sizeof(name),
+                                "AIn%d - Out%d Capture Volume", in  + 1, out + 1);
+                       err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+                       if (err < 0)
+                               return err;
+               }
+
+               for (in = 8; in < 16; in++) {
+                       snprintf(name, sizeof(name),
+                                "DIn%d - Out%d Playback Volume", in - 7, out + 1);
+                       err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       return 0;
+}
+
 void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
                               unsigned char samplerate_id)
 {
@@ -533,6 +598,11 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
                                              snd_audigy2nx_proc_read);
                break;
 
+       case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */
+       case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
+               err = snd_maudio_ftu_create_mixer(mixer);
+               break;
+
        case USB_ID(0x0b05, 0x1739):
        case USB_ID(0x0b05, 0x1743):
                err = snd_xonar_u1_controls_create(mixer);
index 78792a8900c3c575904f9d712e0bb96b224ac2a1..0b2ae8e1c02d6e62a3671de37915f69f7db482b4 100644 (file)
@@ -1988,7 +1988,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                .data = & (const struct snd_usb_audio_quirk[]) {
                        {
                                .ifnum = 0,
-                               .type = QUIRK_IGNORE_INTERFACE
+                               .type = QUIRK_AUDIO_STANDARD_MIXER,
                        },
                        {
                                .ifnum = 1,
@@ -2055,7 +2055,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                .data = & (const struct snd_usb_audio_quirk[]) {
                        {
                                .ifnum = 0,
-                               .type = QUIRK_IGNORE_INTERFACE
+                               .type = QUIRK_AUDIO_STANDARD_MIXER,
                        },
                        {
                                .ifnum = 1,
index bd13d7257240528f97cc2a0caf5b134a0b9d58ac..090e1930dfdcc6b37c68b7731e0862cb703a7689 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/usb.h>
 #include <linux/usb/audio.h>
 
+#include <sound/control.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/pcm.h>
@@ -262,6 +263,20 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
        return 0;
 }
 
+/*
+ * Create a standard mixer for the specified interface.
+ */
+static int create_standard_mixer_quirk(struct snd_usb_audio *chip,
+                                      struct usb_interface *iface,
+                                      struct usb_driver *driver,
+                                      const struct snd_usb_audio_quirk *quirk)
+{
+       if (quirk->ifnum < 0)
+               return 0;
+
+       return snd_usb_create_mixer(chip, quirk->ifnum, 0);
+}
+
 /*
  * audio-interface quirks
  *
@@ -294,7 +309,8 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
                [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
                [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
                [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
-               [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk
+               [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk,
+               [QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_quirk,
        };
 
        if (quirk->type < QUIRK_TYPE_COUNT) {
@@ -387,7 +403,7 @@ static int snd_usb_cm106_boot_quirk(struct usb_device *dev)
 static int snd_usb_cm6206_boot_quirk(struct usb_device *dev)
 {
        int err, reg;
-       int val[] = {0x200c, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000};
+       int val[] = {0x2004, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000};
 
        for (reg = 0; reg < ARRAY_SIZE(val); reg++) {
                err = snd_usb_cm106_write_int_reg(dev, reg, val[reg]);
index 32f2a97f2f14f7494d07d5c4e84f1230aa283797..1e79986b577749ca0ebea31aa7b5c7c46ac750b1 100644 (file)
@@ -84,6 +84,7 @@ enum quirk_type {
        QUIRK_AUDIO_FIXED_ENDPOINT,
        QUIRK_AUDIO_EDIROL_UAXX,
        QUIRK_AUDIO_ALIGN_TRANSFER,
+       QUIRK_AUDIO_STANDARD_MIXER,
 
        QUIRK_TYPE_COUNT
 };
index 1455413ec7a74ed5ebea22c70863fb8dc1545d3c..940257b5774ec209d09e3b2d4fbee647ff86dd71 100644 (file)
@@ -215,11 +215,13 @@ LIB_FILE=$(OUTPUT)libperf.a
 LIB_H += ../../include/linux/perf_event.h
 LIB_H += ../../include/linux/rbtree.h
 LIB_H += ../../include/linux/list.h
+LIB_H += ../../include/linux/const.h
 LIB_H += ../../include/linux/hash.h
 LIB_H += ../../include/linux/stringify.h
 LIB_H += util/include/linux/bitmap.h
 LIB_H += util/include/linux/bitops.h
 LIB_H += util/include/linux/compiler.h
+LIB_H += util/include/linux/const.h
 LIB_H += util/include/linux/ctype.h
 LIB_H += util/include/linux/kernel.h
 LIB_H += util/include/linux/list.h
@@ -631,7 +633,7 @@ prefix_SQ = $(subst ','\'',$(prefix))
 
 SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
 
-LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive $(EXTLIBS)
+LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group
 
 ALL_CFLAGS += $(BASIC_CFLAGS)
 ALL_CFLAGS += $(ARCH_CFLAGS)
index e18eb7ed30ae3b00af785c6bef248b4714bf34f4..7b139e1e7e869f9c11070012ac21bf13534d1d50 100644 (file)
@@ -7,8 +7,6 @@
  */
 #include "builtin.h"
 
-#include "util/util.h"
-
 #include "util/util.h"
 #include "util/color.h"
 #include <linux/list.h>
index 0974f957b8fa2634409ff46e8de915b1380e87a8..8e2c85798185c58068783f2b392e00f305f492e1 100644 (file)
@@ -823,6 +823,16 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
 
        symbol__init();
 
+       if (symbol_conf.kptr_restrict)
+               pr_warning(
+"WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
+"check /proc/sys/kernel/kptr_restrict.\n\n"
+"Samples in kernel functions may not be resolved if a suitable vmlinux\n"
+"file is not found in the buildid cache or in the vmlinux path.\n\n"
+"Samples in kernel modules won't be resolved at all.\n\n"
+"If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
+"even with a suitable vmlinux or kallsyms file.\n\n");
+
        if (no_buildid_cache || no_buildid)
                disable_buildid_cache();
 
index 498c6f70a74784ecd249ccd0c9cc495651f1047d..287a173523a7fa4d39c0c6635cbbaf94a0ac181a 100644 (file)
@@ -116,6 +116,9 @@ static int process_sample_event(union perf_event *event,
        if (al.filtered || (hide_unresolved && al.sym == NULL))
                return 0;
 
+       if (al.map != NULL)
+               al.map->dso->hit = 1;
+
        if (perf_session__add_hist_entry(session, &al, sample, evsel)) {
                pr_debug("problem incrementing symbol period, skipping event\n");
                return -1;
@@ -249,6 +252,8 @@ static int __cmd_report(void)
        u64 nr_samples;
        struct perf_session *session;
        struct perf_evsel *pos;
+       struct map *kernel_map;
+       struct kmap *kernel_kmap;
        const char *help = "For a higher level overview, try: perf report --sort comm,dso";
 
        signal(SIGINT, sig_handler);
@@ -268,6 +273,24 @@ static int __cmd_report(void)
        if (ret)
                goto out_delete;
 
+       kernel_map = session->host_machine.vmlinux_maps[MAP__FUNCTION];
+       kernel_kmap = map__kmap(kernel_map);
+       if (kernel_map == NULL ||
+           (kernel_map->dso->hit &&
+            (kernel_kmap->ref_reloc_sym == NULL ||
+             kernel_kmap->ref_reloc_sym->addr == 0))) {
+               const struct dso *kdso = kernel_map->dso;
+
+               ui__warning(
+"Kernel address maps (/proc/{kallsyms,modules}) were restricted.\n\n"
+"Check /proc/sys/kernel/kptr_restrict before running 'perf record'.\n\n%s\n\n"
+"Samples in kernel modules can't be resolved as well.\n\n",
+                           RB_EMPTY_ROOT(&kdso->symbols[MAP__FUNCTION]) ?
+"As no suitable kallsyms nor vmlinux was found, kernel samples\n"
+"can't be resolved." :
+"If some relocation was applied (e.g. kexec) symbols may be misresolved.");
+       }
+
        if (dump_trace) {
                perf_session__fprintf_nr_events(session, stdout);
                goto out_delete;
index 974f6d3f4e53544b5e408aa64d70f4274ed56845..22747de7234b548cd1fadac1c53d9884849df935 100644 (file)
@@ -10,7 +10,6 @@
 #include "util/symbol.h"
 #include "util/thread.h"
 #include "util/trace-event.h"
-#include "util/parse-options.h"
 #include "util/util.h"
 #include "util/evlist.h"
 #include "util/evsel.h"
index b67186228c8916747042db705e9781d131171897..2da9162262b05a189fb969440f8816d90e55b99a 100644 (file)
@@ -474,7 +474,7 @@ static int test__basic_mmap(void)
        unsigned int nr_events[nsyscalls],
                     expected_nr_events[nsyscalls], i, j;
        struct perf_evsel *evsels[nsyscalls], *evsel;
-       int sample_size = perf_sample_size(attr.sample_type);
+       int sample_size = __perf_evsel__sample_size(attr.sample_type);
 
        for (i = 0; i < nsyscalls; ++i) {
                char name[64];
index 2d7934e9de380da65b3c5f8e3a9ad5684d1af1a6..f2f3f4937aa245142eda2082274b7b200e41db4e 100644 (file)
@@ -62,8 +62,6 @@
 #include <linux/unistd.h>
 #include <linux/types.h>
 
-#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
-
 static struct perf_top top = {
        .count_filter           = 5,
        .delay_secs             = 2,
@@ -82,6 +80,8 @@ static bool                   use_tui, use_stdio;
 
 static int                     default_interval                =      0;
 
+static bool                    kptr_restrict_warned;
+static bool                    vmlinux_warned;
 static bool                    inherit                         =  false;
 static int                     realtime_prio                   =      0;
 static bool                    group                           =  false;
@@ -740,7 +740,22 @@ static void perf_event__process_sample(const union perf_event *event,
            al.filtered)
                return;
 
+       if (!kptr_restrict_warned &&
+           symbol_conf.kptr_restrict &&
+           al.cpumode == PERF_RECORD_MISC_KERNEL) {
+               ui__warning(
+"Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
+"Check /proc/sys/kernel/kptr_restrict.\n\n"
+"Kernel%s samples will not be resolved.\n",
+                         !RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION]) ?
+                         " modules" : "");
+               if (use_browser <= 0)
+                       sleep(5);
+               kptr_restrict_warned = true;
+       }
+
        if (al.sym == NULL) {
+               const char *msg = "Kernel samples will not be resolved.\n";
                /*
                 * As we do lazy loading of symtabs we only will know if the
                 * specified vmlinux file is invalid when we actually have a
@@ -752,12 +767,20 @@ static void perf_event__process_sample(const union perf_event *event,
                 * --hide-kernel-symbols, even if the user specifies an
                 * invalid --vmlinux ;-)
                 */
-               if (al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
+               if (!kptr_restrict_warned && !vmlinux_warned &&
+                   al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
                    RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
-                       ui__warning("The %s file can't be used\n",
-                                   symbol_conf.vmlinux_name);
-                       exit_browser(0);
-                       exit(1);
+                       if (symbol_conf.vmlinux_name) {
+                               ui__warning("The %s file can't be used.\n%s",
+                                           symbol_conf.vmlinux_name, msg);
+                       } else {
+                               ui__warning("A vmlinux file was not found.\n%s",
+                                           msg);
+                       }
+
+                       if (use_browser <= 0)
+                               sleep(5);
+                       vmlinux_warned = true;
                }
 
                return;
index 26d4d3fd6deb2e1285ca44c9a710e7cadffd374d..ad73300f7bac6d1b11e4db0f1e121e0e26b0fb0c 100755 (executable)
@@ -23,12 +23,7 @@ if test -d ../../.git -o -f ../../.git &&
 then
        VN=$(echo "$VN" | sed -e 's/-/./g');
 else
-       eval $(grep '^VERSION[[:space:]]*=' ../../Makefile|tr -d ' ')
-       eval $(grep '^PATCHLEVEL[[:space:]]*=' ../../Makefile|tr -d ' ')
-       eval $(grep '^SUBLEVEL[[:space:]]*=' ../../Makefile|tr -d ' ')
-       eval $(grep '^EXTRAVERSION[[:space:]]*=' ../../Makefile|tr -d ' ')
-
-       VN="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
+       VN=$(MAKEFLAGS= make -sC ../.. kernelversion)
 fi
 
 VN=$(expr "$VN" : v*'\(.*\)')
index 6635fcd11ca558e1831d331a500474c8908a58d1..3c1b8a6321017efdb75fde50cbe5d1d520a62153 100644 (file)
@@ -35,22 +35,6 @@ const char *perf_event__name(unsigned int id)
        return perf_event__names[id];
 }
 
-int perf_sample_size(u64 sample_type)
-{
-       u64 mask = sample_type & PERF_SAMPLE_MASK;
-       int size = 0;
-       int i;
-
-       for (i = 0; i < 64; i++) {
-               if (mask & (1ULL << i))
-                       size++;
-       }
-
-       size *= sizeof(u64);
-
-       return size;
-}
-
 static struct perf_sample synth_sample = {
        .pid       = -1,
        .tid       = -1,
@@ -553,9 +537,18 @@ static int perf_event__process_kernel_mmap(union perf_event *event,
                        goto out_problem;
 
                perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps);
-               perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
-                                                        symbol_name,
-                                                        event->mmap.pgoff);
+
+               /*
+                * Avoid using a zero address (kptr_restrict) for the ref reloc
+                * symbol. Effectively having zero here means that at record
+                * time /proc/sys/kernel/kptr_restrict was non zero.
+                */
+               if (event->mmap.pgoff != 0) {
+                       perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
+                                                                symbol_name,
+                                                                event->mmap.pgoff);
+               }
+
                if (machine__is_default_guest(machine)) {
                        /*
                         * preload dso of guest kernel and modules
index c083328714082503b7927ee1401d699f1afc8efc..1d7f66488a885456ab4dac49bcc3ecaadad904c2 100644 (file)
@@ -82,8 +82,6 @@ struct perf_sample {
        struct ip_callchain *callchain;
 };
 
-int perf_sample_size(u64 sample_type);
-
 #define BUILD_ID_SIZE 20
 
 struct build_id_event {
index 50aa34879c33dbaee76fa8230ec2ecacc82e40f3..b021ea9265c3e39b9f18fb9e65f731516b49642d 100644 (file)
@@ -12,7 +12,6 @@
 #include "evlist.h"
 #include "evsel.h"
 #include "util.h"
-#include "debug.h"
 
 #include <sys/mman.h>
 
@@ -257,19 +256,15 @@ int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
        return evlist->mmap != NULL ? 0 : -ENOMEM;
 }
 
-static int __perf_evlist__mmap(struct perf_evlist *evlist, struct perf_evsel *evsel,
+static int __perf_evlist__mmap(struct perf_evlist *evlist,
                               int idx, int prot, int mask, int fd)
 {
        evlist->mmap[idx].prev = 0;
        evlist->mmap[idx].mask = mask;
        evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
                                      MAP_SHARED, fd, 0);
-       if (evlist->mmap[idx].base == MAP_FAILED) {
-               if (evlist->cpus->map[idx] == -1 && evsel->attr.inherit)
-                       ui__warning("Inherit is not allowed on per-task "
-                                   "events using mmap.\n");
+       if (evlist->mmap[idx].base == MAP_FAILED)
                return -1;
-       }
 
        perf_evlist__add_pollfd(evlist, fd);
        return 0;
@@ -289,7 +284,7 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
 
                                if (output == -1) {
                                        output = fd;
-                                       if (__perf_evlist__mmap(evlist, evsel, cpu,
+                                       if (__perf_evlist__mmap(evlist, cpu,
                                                                prot, mask, output) < 0)
                                                goto out_unmap;
                                } else {
@@ -329,7 +324,7 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
 
                        if (output == -1) {
                                output = fd;
-                               if (__perf_evlist__mmap(evlist, evsel, thread,
+                               if (__perf_evlist__mmap(evlist, thread,
                                                        prot, mask, output) < 0)
                                        goto out_unmap;
                        } else {
@@ -460,33 +455,46 @@ int perf_evlist__set_filters(struct perf_evlist *evlist)
        return 0;
 }
 
-u64 perf_evlist__sample_type(struct perf_evlist *evlist)
+bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist)
 {
-       struct perf_evsel *pos;
-       u64 type = 0;
-
-       list_for_each_entry(pos, &evlist->entries, node) {
-               if (!type)
-                       type = pos->attr.sample_type;
-               else if (type != pos->attr.sample_type)
-                       die("non matching sample_type");
+       struct perf_evsel *pos, *first;
+
+       pos = first = list_entry(evlist->entries.next, struct perf_evsel, node);
+
+       list_for_each_entry_continue(pos, &evlist->entries, node) {
+               if (first->attr.sample_type != pos->attr.sample_type)
+                       return false;
        }
 
-       return type;
+       return true;
 }
 
-bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
+u64 perf_evlist__sample_type(const struct perf_evlist *evlist)
+{
+       struct perf_evsel *first;
+
+       first = list_entry(evlist->entries.next, struct perf_evsel, node);
+       return first->attr.sample_type;
+}
+
+bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist)
 {
-       bool value = false, first = true;
-       struct perf_evsel *pos;
-
-       list_for_each_entry(pos, &evlist->entries, node) {
-               if (first) {
-                       value = pos->attr.sample_id_all;
-                       first = false;
-               } else if (value != pos->attr.sample_id_all)
-                       die("non matching sample_id_all");
+       struct perf_evsel *pos, *first;
+
+       pos = first = list_entry(evlist->entries.next, struct perf_evsel, node);
+
+       list_for_each_entry_continue(pos, &evlist->entries, node) {
+               if (first->attr.sample_id_all != pos->attr.sample_id_all)
+                       return false;
        }
 
-       return value;
+       return true;
+}
+
+bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
+{
+       struct perf_evsel *first;
+
+       first = list_entry(evlist->entries.next, struct perf_evsel, node);
+       return first->attr.sample_id_all;
 }
index 0a1ef1f051f0cb0db67c86df9b4e3fe12acfc472..b2b862374f371d363bc19ed3cc684fde1de9f6d3 100644 (file)
@@ -66,7 +66,9 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
 void perf_evlist__delete_maps(struct perf_evlist *evlist);
 int perf_evlist__set_filters(struct perf_evlist *evlist);
 
-u64 perf_evlist__sample_type(struct perf_evlist *evlist);
-bool perf_evlist__sample_id_all(const struct perf_evlist *evlist);
+u64 perf_evlist__sample_type(const struct perf_evlist *evlist);
+bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist);
 
+bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
+bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
 #endif /* __PERF_EVLIST_H */
index ee0fe0dffa7122e1936925b91fcbcf47de7739a1..0239eb87b2321ea9e4fe208605020e83b1d7c718 100644 (file)
 
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 
+int __perf_evsel__sample_size(u64 sample_type)
+{
+       u64 mask = sample_type & PERF_SAMPLE_MASK;
+       int size = 0;
+       int i;
+
+       for (i = 0; i < 64; i++) {
+               if (mask & (1ULL << i))
+                       size++;
+       }
+
+       size *= sizeof(u64);
+
+       return size;
+}
+
 void perf_evsel__init(struct perf_evsel *evsel,
                      struct perf_event_attr *attr, int idx)
 {
@@ -35,7 +51,17 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
 
 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
+       int cpu, thread;
        evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
+
+       if (evsel->fd) {
+               for (cpu = 0; cpu < ncpus; cpu++) {
+                       for (thread = 0; thread < nthreads; thread++) {
+                               FD(evsel, cpu, thread) = -1;
+                       }
+               }
+       }
+
        return evsel->fd != NULL ? 0 : -ENOMEM;
 }
 
index f79bb2c09a6cbea510e31d260a1fabb778e13950..7e9366e4490b532bce4facc7b92e38a83c9c68e4 100644 (file)
@@ -149,4 +149,11 @@ static inline int perf_evsel__read_scaled(struct perf_evsel *evsel,
        return __perf_evsel__read(evsel, ncpus, nthreads, true);
 }
 
+int __perf_evsel__sample_size(u64 sample_type);
+
+static inline int perf_evsel__sample_size(struct perf_evsel *evsel)
+{
+       return __perf_evsel__sample_size(evsel->attr.sample_type);
+}
+
 #endif /* __PERF_EVSEL_H */
index 0717bebc76494d24cfc68bec984aba404058438c..afb0849fe530e5f4a06937457bb98644acf681df 100644 (file)
@@ -193,9 +193,13 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
             *linkname = malloc(size), *targetname;
        int len, err = -1;
 
-       if (is_kallsyms)
+       if (is_kallsyms) {
+               if (symbol_conf.kptr_restrict) {
+                       pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
+                       return 0;
+               }
                realname = (char *)name;
-       else
+       else
                realname = realpath(name, NULL);
 
        if (realname == NULL || filename == NULL || linkname == NULL)
diff --git a/tools/perf/util/include/linux/const.h b/tools/perf/util/include/linux/const.h
new file mode 100644 (file)
index 0000000..1b476c9
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../include/linux/const.h"
index 69436b3200a45d20a27a2e0481da3b2bbcd7535c..a9ac0504aabd25f3dc4a528f5e86d291eed4da05 100644 (file)
@@ -674,7 +674,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
        struct perf_evlist *evlist = &pevlist->evlist;
        union perf_event *event;
        int sample_id_all = 1, cpu;
-       static char *kwlist[] = {"sample_id_all", NULL, NULL};
+       static char *kwlist[] = {"cpu", "sample_id_all", NULL, NULL};
        int err;
 
        if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist,
@@ -692,16 +692,14 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
 
                first = list_entry(evlist->entries.next, struct perf_evsel, node);
                err = perf_event__parse_sample(event, first->attr.sample_type,
-                                              perf_sample_size(first->attr.sample_type),
+                                              perf_evsel__sample_size(first),
                                               sample_id_all, &pevent->sample);
-               if (err) {
-                       pr_err("Can't parse sample, err = %d\n", err);
-                       goto end;
-               }
-
+               if (err)
+                       return PyErr_Format(PyExc_OSError,
+                                           "perf: can't parse sample, err=%d", err);
                return pyevent;
        }
-end:
+
        Py_INCREF(Py_None);
        return Py_None;
 }
index 64500fc787997e700a556f80531440926dfcf0c1..f5a8fbdd3f76b51f9b5abf0bd551c964c3d301ed 100644 (file)
@@ -58,6 +58,16 @@ static int perf_session__open(struct perf_session *self, bool force)
                goto out_close;
        }
 
+       if (!perf_evlist__valid_sample_type(self->evlist)) {
+               pr_err("non matching sample_type");
+               goto out_close;
+       }
+
+       if (!perf_evlist__valid_sample_id_all(self->evlist)) {
+               pr_err("non matching sample_id_all");
+               goto out_close;
+       }
+
        self->size = input_stat.st_size;
        return 0;
 
@@ -97,7 +107,7 @@ out:
 void perf_session__update_sample_type(struct perf_session *self)
 {
        self->sample_type = perf_evlist__sample_type(self->evlist);
-       self->sample_size = perf_sample_size(self->sample_type);
+       self->sample_size = __perf_evsel__sample_size(self->sample_type);
        self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
        perf_session__id_header_size(self);
 }
index 516876dfbe5280af9bd52179c07d99b16ed43233..eec196329fd92c2e0567c8af5535ae1a99fcc4b1 100644 (file)
@@ -676,9 +676,30 @@ discard_symbol:            rb_erase(&pos->rb_node, root);
        return count + moved;
 }
 
+static bool symbol__restricted_filename(const char *filename,
+                                       const char *restricted_filename)
+{
+       bool restricted = false;
+
+       if (symbol_conf.kptr_restrict) {
+               char *r = realpath(filename, NULL);
+
+               if (r != NULL) {
+                       restricted = strcmp(r, restricted_filename) == 0;
+                       free(r);
+                       return restricted;
+               }
+       }
+
+       return restricted;
+}
+
 int dso__load_kallsyms(struct dso *dso, const char *filename,
                       struct map *map, symbol_filter_t filter)
 {
+       if (symbol__restricted_filename(filename, "/proc/kallsyms"))
+               return -1;
+
        if (dso__load_all_kallsyms(dso, filename, map) < 0)
                return -1;
 
@@ -1790,6 +1811,9 @@ static int machine__create_modules(struct machine *machine)
                modules = path;
        }
 
+       if (symbol__restricted_filename(path, "/proc/modules"))
+               return -1;
+
        file = fopen(modules, "r");
        if (file == NULL)
                return -1;
@@ -2239,6 +2263,9 @@ static u64 machine__get_kernel_start_addr(struct machine *machine)
                }
        }
 
+       if (symbol__restricted_filename(filename, "/proc/kallsyms"))
+               return 0;
+
        if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
                return 0;
 
@@ -2410,6 +2437,25 @@ static int setup_list(struct strlist **list, const char *list_str,
        return 0;
 }
 
+static bool symbol__read_kptr_restrict(void)
+{
+       bool value = false;
+
+       if (geteuid() != 0) {
+               FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
+               if (fp != NULL) {
+                       char line[8];
+
+                       if (fgets(line, sizeof(line), fp) != NULL)
+                               value = atoi(line) != 0;
+
+                       fclose(fp);
+               }
+       }
+
+       return value;
+}
+
 int symbol__init(void)
 {
        const char *symfs;
@@ -2456,6 +2502,8 @@ int symbol__init(void)
        if (symfs != symbol_conf.symfs)
                free((void *)symfs);
 
+       symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
+
        symbol_conf.initialized = true;
        return 0;
 
index 242de0101a868f99d38c0fbf7348590556f8187f..325ee36a9d29d63d82973d262816f91a064813f2 100644 (file)
@@ -75,7 +75,8 @@ struct symbol_conf {
                        use_callchain,
                        exclude_other,
                        show_cpu_utilization,
-                       initialized;
+                       initialized,
+                       kptr_restrict;
        const char      *vmlinux_name,
                        *kallsyms_name,
                        *source_prefix,
index 1e88485c16a04b755e68bb14510c3fd5cf368769..0a7ed5b5e281c88b321de87ced66a3d29ebb003d 100644 (file)
@@ -2187,6 +2187,7 @@ static const struct flag flags[] = {
        { "TASKLET_SOFTIRQ", 6 },
        { "SCHED_SOFTIRQ", 7 },
        { "HRTIMER_SOFTIRQ", 8 },
+       { "RCU_SOFTIRQ", 9 },
 
        { "HRTIMER_NORESTART", 0 },
        { "HRTIMER_RESTART", 1 },
index 1fd29b2daa9204fff6e345c8871799dcb0e04e5e..cef28e6632b98cd4e82426f45805f676c2fc0543 100755 (executable)
@@ -788,7 +788,7 @@ sub wait_for_input
 
 sub reboot_to {
     if ($reboot_type eq "grub") {
-       run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'";
+       run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch && reboot)'";
        return;
     }
 
@@ -1480,7 +1480,7 @@ sub process_config_ignore {
        or dodie "Failed to read $config";
 
     while (<IN>) {
-       if (/^(.*?(CONFIG\S*)(=.*| is not set))/) {
+       if (/^((CONFIG\S*)=.*)/) {
            $config_ignore{$2} = $1;
        }
     }
@@ -1638,7 +1638,7 @@ sub run_config_bisect {
        if (!$found) {
            # try the other half
            doprint "Top half produced no set configs, trying bottom half\n";
-           @tophalf = @start_list[$half .. $#start_list];
+           @tophalf = @start_list[$half + 1 .. $#start_list];
            create_config @tophalf;
            read_current_config \%current_config;
            foreach my $config (@tophalf) {
@@ -1690,7 +1690,7 @@ sub run_config_bisect {
        # remove half the configs we are looking at and see if
        # they are good.
        $half = int($#start_list / 2);
-    } while ($half > 0);
+    } while ($#start_list > 0);
 
     # we found a single config, try it again unless we are running manually
 
index df0c6d2c386098cb4a23ed963af885f6a7945cc1..74d3331bdaf992b10bdf38d630d0dca00cc08360 100644 (file)
@@ -197,6 +197,14 @@ const struct option longopts[] = {
                .name = "help",
                .val = 'h',
        },
+       {
+               .name = "event-idx",
+               .val = 'E',
+       },
+       {
+               .name = "no-event-idx",
+               .val = 'e',
+       },
        {
                .name = "indirect",
                .val = 'I',
@@ -211,13 +219,17 @@ const struct option longopts[] = {
 
 static void help()
 {
-       fprintf(stderr, "Usage: virtio_test [--help] [--no-indirect]\n");
+       fprintf(stderr, "Usage: virtio_test [--help]"
+               " [--no-indirect]"
+               " [--no-event-idx]"
+               "\n");
 }
 
 int main(int argc, char **argv)
 {
        struct vdev_info dev;
-       unsigned long long features = 1ULL << VIRTIO_RING_F_INDIRECT_DESC;
+       unsigned long long features = (1ULL << VIRTIO_RING_F_INDIRECT_DESC) |
+               (1ULL << VIRTIO_RING_F_EVENT_IDX);
        int o;
 
        for (;;) {
@@ -228,6 +240,9 @@ int main(int argc, char **argv)
                case '?':
                        help();
                        exit(2);
+               case 'e':
+                       features &= ~(1ULL << VIRTIO_RING_F_EVENT_IDX);
+                       break;
                case 'h':
                        help();
                        goto done;
index 7f06884ecd41b588d829064a53ac964395b0ae1e..af0f22fb1ef71e6dc94c620873bc3241c2883430 100644 (file)
@@ -22,6 +22,7 @@
 
 static unsigned int offset;
 static unsigned int ino = 721;
+static time_t default_mtime;
 
 struct file_handler {
        const char *type;
@@ -102,7 +103,6 @@ static int cpio_mkslink(const char *name, const char *target,
                         unsigned int mode, uid_t uid, gid_t gid)
 {
        char s[256];
-       time_t mtime = time(NULL);
 
        if (name[0] == '/')
                name++;
@@ -114,7 +114,7 @@ static int cpio_mkslink(const char *name, const char *target,
                (long) uid,             /* uid */
                (long) gid,             /* gid */
                1,                      /* nlink */
-               (long) mtime,           /* mtime */
+               (long) default_mtime,   /* mtime */
                (unsigned)strlen(target)+1, /* filesize */
                3,                      /* major */
                1,                      /* minor */
@@ -152,7 +152,6 @@ static int cpio_mkgeneric(const char *name, unsigned int mode,
                       uid_t uid, gid_t gid)
 {
        char s[256];
-       time_t mtime = time(NULL);
 
        if (name[0] == '/')
                name++;
@@ -164,7 +163,7 @@ static int cpio_mkgeneric(const char *name, unsigned int mode,
                (long) uid,             /* uid */
                (long) gid,             /* gid */
                2,                      /* nlink */
-               (long) mtime,           /* mtime */
+               (long) default_mtime,   /* mtime */
                0,                      /* filesize */
                3,                      /* major */
                1,                      /* minor */
@@ -242,7 +241,6 @@ static int cpio_mknod(const char *name, unsigned int mode,
                       unsigned int maj, unsigned int min)
 {
        char s[256];
-       time_t mtime = time(NULL);
 
        if (dev_type == 'b')
                mode |= S_IFBLK;
@@ -259,7 +257,7 @@ static int cpio_mknod(const char *name, unsigned int mode,
                (long) uid,             /* uid */
                (long) gid,             /* gid */
                1,                      /* nlink */
-               (long) mtime,           /* mtime */
+               (long) default_mtime,   /* mtime */
                0,                      /* filesize */
                3,                      /* major */
                1,                      /* minor */
@@ -460,7 +458,7 @@ static int cpio_mkfile_line(const char *line)
 static void usage(const char *prog)
 {
        fprintf(stderr, "Usage:\n"
-               "\t%s <cpio_list>\n"
+               "\t%s [-t <timestamp>] <cpio_list>\n"
                "\n"
                "<cpio_list> is a file containing newline separated entries that\n"
                "describe the files to be included in the initramfs archive:\n"
@@ -491,7 +489,11 @@ static void usage(const char *prog)
                "nod /dev/console 0600 0 0 c 5 1\n"
                "dir /root 0700 0 0\n"
                "dir /sbin 0755 0 0\n"
-               "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n",
+               "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
+               "\n"
+               "<timestamp> is time in seconds since Epoch that will be used\n"
+               "as mtime for symlinks, special files and directories. The default\n"
+               "is to use the current time for these entries.\n",
                prog);
 }
 
@@ -529,17 +531,42 @@ int main (int argc, char *argv[])
        char *args, *type;
        int ec = 0;
        int line_nr = 0;
+       const char *filename;
+
+       default_mtime = time(NULL);
+       while (1) {
+               int opt = getopt(argc, argv, "t:h");
+               char *invalid;
 
-       if (2 != argc) {
+               if (opt == -1)
+                       break;
+               switch (opt) {
+               case 't':
+                       default_mtime = strtol(optarg, &invalid, 10);
+                       if (!*optarg || *invalid) {
+                               fprintf(stderr, "Invalid timestamp: %s\n",
+                                               optarg);
+                               usage(argv[0]);
+                               exit(1);
+                       }
+                       break;
+               case 'h':
+               case '?':
+                       usage(argv[0]);
+                       exit(opt == 'h' ? 0 : 1);
+               }
+       }
+
+       if (argc - optind != 1) {
                usage(argv[0]);
                exit(1);
        }
-
-       if (!strcmp(argv[1], "-"))
+       filename = argv[optind];
+       if (!strcmp(filename, "-"))
                cpio_list = stdin;
-       else if (! (cpio_list = fopen(argv[1], "r"))) {
+       else if (!(cpio_list = fopen(filename, "r"))) {
                fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
-                       argv[1], strerror(errno));
+                       filename, strerror(errno));
                usage(argv[0]);
                exit(1);
        }
index 22cdb960660a61cd6c142278b08ed175b3d9110b..96ebc0679415baeff88d7764b1c0e956820adad2 100644 (file)
@@ -467,12 +467,8 @@ static struct kvm *kvm_create_vm(void)
                if (!kvm->buses[i])
                        goto out_err;
        }
-       spin_lock_init(&kvm->mmu_lock);
-
-       r = kvm_init_mmu_notifier(kvm);
-       if (r)
-               goto out_err;
 
+       spin_lock_init(&kvm->mmu_lock);
        kvm->mm = current->mm;
        atomic_inc(&kvm->mm->mm_count);
        kvm_eventfd_init(kvm);
@@ -480,6 +476,11 @@ static struct kvm *kvm_create_vm(void)
        mutex_init(&kvm->irq_lock);
        mutex_init(&kvm->slots_lock);
        atomic_set(&kvm->users_count, 1);
+
+       r = kvm_init_mmu_notifier(kvm);
+       if (r)
+               goto out_err;
+
        raw_spin_lock(&kvm_lock);
        list_add(&kvm->vm_list, &vm_list);
        raw_spin_unlock(&kvm_lock);
@@ -651,7 +652,9 @@ int __kvm_set_memory_region(struct kvm *kvm,
        /* We can read the guest memory with __xxx_user() later on. */
        if (user_alloc &&
            ((mem->userspace_addr & (PAGE_SIZE - 1)) ||
-            !access_ok(VERIFY_WRITE, mem->userspace_addr, mem->memory_size)))
+            !access_ok(VERIFY_WRITE,
+                       (void __user *)(unsigned long)mem->userspace_addr,
+                       mem->memory_size)))
                goto out;
        if (mem->slot >= KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS)
                goto out;